From: Apple Date: Mon, 11 Aug 2003 21:39:07 +0000 (+0000) Subject: xnu-344.tar.gz X-Git-Tag: mac-os-x-102^0 X-Git-Url: https://git.saurik.com/apple/xnu.git/commitdiff_plain/9bccf70c0258c7cac2dcb80011b2a964d884c552 xnu-344.tar.gz --- diff --git a/Makefile b/Makefile index 00fd1ce02..5adbd70ba 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,18 @@ ifndef VERSDIR export VERSDIR=$(shell /bin/pwd) endif +ifndef SRCROOT +export SRCROOT=$(shell /bin/pwd) +endif +ifndef OBJROOT +export OBJROOT=$(SRCROOT)/BUILD/obj +endif +ifndef DSTROOT +export DSTROOT=$(SRCROOT)/BUILD/dst +endif +ifndef SYMROOT +export SYMROOT=$(SRCROOT)/BUILD/sym +endif export MakeInc_cmd=${VERSDIR}/makedefs/MakeInc.cmd export MakeInc_def=${VERSDIR}/makedefs/MakeInc.def @@ -46,5 +58,8 @@ INSTALL_FILE_LIST= \ INSTALL_FILE_DIR= \ / +INSTMAN_SUBDIRS = \ + bsd + include $(MakeInc_rule) include $(MakeInc_dir) diff --git a/PB.project b/PB.project deleted file mode 100644 index 28014d5c7..000000000 --- a/PB.project +++ /dev/null @@ -1,15 +0,0 @@ -{ - FILESTABLE = {}; - LANGUAGE = English; - NEXTSTEP_BUILDTOOL = /bin/gnumake; - NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; - NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; - PDO_UNIX_BUILDTOOL = /bin/gnumake; - PDO_UNIX_JAVA_COMPILER = "$(JDKBINDIR)/javac"; - PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; - PROJECTNAME = xnu; - PROJECTTYPE = Legacy; - PROJECTVERSION = 2.8; - WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; - WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; -} diff --git a/README b/README index 690dd7893..0d4d3285a 100644 --- a/README +++ b/README @@ -1,45 +1,6 @@ How to build XNU: -1) Setup your environment: - - Create and go to your sandbox directory - - $ cd - - Extract the xnu project from cvs: - - $ cvs co -r xnu - - where must be replaced by the matching xnu tag for - the xnu project level. - - Go to the top directory in your XNU project. - - $ cd /xnu - - If you are using a sh-style shell, run the following command: - $ . SETUP/setup.sh - - If you are using a csh-style shell, run the following command: - % source SETUP/setup.csh - - This will define the following environmental variables: - SRCROOT, OBJROOT, DSTROOT, SYMROOT - -2) Export the Component Header Files - - From the top directory, run: - - $ make exporthdrs - - This exports the component header files in the $OBJROOT/EXPORT_HDRS - directory. - -3) Build all the Components - - From the top directory. run: - - $ make all +1) Type: "make" This builds all the components for all architectures defined in ARCH_CONFIGS and for all kernel configurations defined in KERNEL_CONFIGS. @@ -52,7 +13,18 @@ How to build XNU: $(OBJROOT)/RELEASE_PPC/osfmk/RELEASE/osfmk.o: pre-linked object for osfmk component $(OBJROOT)/RELEASE_PPC/mach_kernel: bootable image -4) Building a Component +2) Building a Component + + Go to the top directory in your XNU project. + + If you are using a sh-style shell, run the following command: + $ . SETUP/setup.sh + + If you are using a csh-style shell, run the following command: + % source SETUP/setup.csh + + This will define the following environmental variables: + SRCROOT, OBJROOT, DSTROOT, SYMROOT From a component top directory: @@ -63,9 +35,6 @@ How to build XNU: By default, ARCH_CONFIGS contains one architecture, the build machine architecture, and KERNEL_CONFIGS is set to build for RELEASE . - WARNING: If a component header file has been modified, you will have to do - the above procedures 3 and 4. - Example: $(OBJROOT)/RELEASE_PPC/osfmk/RELEASE/osfmk.o: pre-linked object for osfmk component @@ -76,7 +45,10 @@ How to build XNU: This includes your component in the bootable image, mach_kernel, and in the kernel binary with symbols, mach_kernel.sys. -5) Building DEBUG + WARNING: If a component header file has been modified, you will have to do + the above procedure 1. + +3) Building DEBUG Define KERNEL_CONFIGS to DEBUG in your environment or when running a make command. Then, apply procedures 4, 5 @@ -92,7 +64,7 @@ How to build XNU: $(OBJROOT)/DEBUG_PPC/osfmk/DEBUG/osfmk.o: pre-linked object for osfmk component $(OBJROOT)/DEBUG_PPC/mach_kernel: bootable image -6) Building fat +4) Building fat Define ARCH_CONFIGS in your environment or when running a make command. Apply procedures 3, 4, 5 @@ -104,13 +76,13 @@ How to build XNU: $ export ARCH_CONFIGS="PPC I386" $ make exporthdrs all -7) Build check before integration +5) Build check before integration From the top directory, run: $ ~rc/bin/buildit . -arch ppc -arch i386 -noinstallsrc -nosum -8) Creating tags and cscope +6) Creating tags and cscope Set up your build environment as per instructions in 2a diff --git a/bsd/Makefile b/bsd/Makefile index 4c16828e0..86c7e4164 100644 --- a/bsd/Makefile +++ b/bsd/Makefile @@ -11,19 +11,15 @@ INSTINC_SUBDIRS = \ crypto \ dev \ hfs \ - include \ isofs \ libkern \ machine \ miscfs \ net \ netat \ - netccitt \ netinet \ netinet6 \ - netiso \ netkey \ - netns \ nfs \ sys \ ufs \ @@ -39,19 +35,15 @@ EXPINC_SUBDIRS = \ crypto \ dev \ hfs \ - include \ isofs \ libkern \ machine \ miscfs \ net \ netat \ - netccitt \ netinet \ netinet6 \ - netiso \ netkey \ - netns \ nfs \ sys \ ufs \ @@ -72,6 +64,8 @@ COMP_SUBDIRS = \ INST_SUBDIRS = \ +INSTMAN_SUBDIRS = \ + man include $(MakeInc_rule) include $(MakeInc_dir) diff --git a/bsd/conf/MASTER b/bsd/conf/MASTER index f434bfba1..aa6d7ff53 100644 --- a/bsd/conf/MASTER +++ b/bsd/conf/MASTER @@ -140,6 +140,10 @@ options IPFIREWALL_FORWARD #Transparent proxy # options IPFIREWALL_DEFAULT_TO_ACCEPT # allow everything by default # options IPFIREWALL_KEXT # Kernel extension # options MULTICAST # Internet Protocol Class-D $ +options TCPDEBUG # TCP debug # +options RANDOM_IP_ID # random (not sequential) ip ids # +options TCP_DROP_SYNFIN # Drop TCP packets with SYN+FIN set # +options ICMP_BANDLIM # ICMP bandwidth limiting sysctl # @@ -154,9 +158,7 @@ options KTRACE # ktrace support # # options FFS # Fast Filesystem Support # options HFS # HFS/HFS+ support # -options HFS_HARDLINKS # HFS+ hardlink support # options FIFO # fifo support # -options PORTAL # portal_fs support # options UNION # union_fs support # options FDESC # fdesc_fs support # options CD9660 # ISO 9660 CD-ROM support # @@ -186,20 +188,27 @@ options OBJCTEST # Objc internal test # options KERNEL_STACK # MI kernel stack support # profile # build a profiling kernel # +# +# Point-to-Point Protocol support +# +pseudo-device ppp 2 # + # -# IPv6 (Kame Stable 20000425) Support +# IPv6 Support # options "INET6" # kernel IPv6 Support # -options MAPPED_ADDR_ENABLED # enable IPv4, on IPv6 socket # options IPSEC # IP security # options IPSEC_ESP # IP security # options "IPV6FIREWALL" # IPv6 Firewall Feature # options "IPV6FIREWALL_DEFAULT_TO_ACCEPT" #IPv6 Firewall Feature # options "IPV6FIREWALL_VERBOSE" #IPv6 Firewall Feature # -options NATPT # KAME/IPv6 NAT feature # -pseudo-device gif 2 # + +pseudo-device gif 1 # pseudo-device dummy 2 # pseudo-device faith 1 # +pseudo-device stf 1 # + +options crypto # makeoptions LIBDRIVER = "libDriver_kern.o" # makeoptions LIBOBJC = "libkobjc.o" # @@ -231,7 +240,13 @@ pseudo-device loop # # UCB pseudo terminal service # -pseudo-device pty 32 init pty_init +pseudo-device pty 128 init pty_init + +# +# vnode device +pseudo-device vndevice 4 init vndevice_init + +# # # packet filter device # diff --git a/bsd/conf/MASTER.i386 b/bsd/conf/MASTER.i386 index 7bcd2f6c1..c2ab5b9cf 100644 --- a/bsd/conf/MASTER.i386 +++ b/bsd/conf/MASTER.i386 @@ -45,9 +45,9 @@ # Standard Apple Research Configurations: # -------- ----- -------- --------------- # -# RELEASE = [intel pc mach medium event vol pst gdb kernobjc libdriver fixpri simple_clock mdebug kernserv driverkit uxpr kernstack ipc_compat ipc_debug nfsclient nfsserver quota fifo fdesc union ffs cd9660 compat_43 devfs revfs hfs mrouting ipdivert ipfirewall] +# RELEASE = [intel pc mach medium event vol pst gdb kernobjc libdriver fixpri simple_clock mdebug kernserv driverkit uxpr kernstack ipc_compat ipc_debug nfsclient nfsserver quota fifo fdesc union ffs cd9660 compat_43 volfs devfs synthfs revfs hfs mrouting ipdivert ipfirewall inet6 ipsec gif tcpdrop_synfin ktrace stf] # PROFILE = [RELEASE profile] -# DEBUG = [intel pc mach medium event vol pst gdb kernobjc libdriver_g fixpri debug simple_clock mdebug kernserv driverkit xpr_debug uxpr kernstack ipc_compat ipc_debug nfsclient nfsserver quota fifo fdesc union ffs cd9660 compat_43 revfs hfs devfs mach_assert mrouting ipdivert ipfirewall] +# DEBUG = [intel pc mach medium event vol pst gdb kernobjc libdriver_g fixpri debug simple_clock mdebug kernserv driverkit xpr_debug uxpr kernstack ipc_compat ipc_debug nfsclient nfsserver quota fifo fdesc union ffs cd9660 compat_43 revfs hfs volfs devfs synthfs mach_assert mrouting ipdivert ipfirewall inet6 ipsec gif tcpdrop_synfin ktrace stf] # ###################################################################### # @@ -85,7 +85,3 @@ pseudo-device nfsmeas # # pseudo-device vol # -# -# Point-to-Point Protocol support -# -pseudo-device ppp 2 # diff --git a/bsd/conf/MASTER.ppc b/bsd/conf/MASTER.ppc index ddcf51100..46cb6811a 100644 --- a/bsd/conf/MASTER.ppc +++ b/bsd/conf/MASTER.ppc @@ -45,10 +45,10 @@ # Standard Apple Research Configurations: # -------- ----- -------- --------------- # -# RELEASE = [ppc mach medium vol pst gdb simple_clock kernstack nfsclient nfsserver quota fifo fdesc union ffs cd9660 compat_43 revfs noprofiling hfs volfs devfs synthfs netat mrouting ipdivert ipfirewall] +# RELEASE = [ppc mach medium vol pst gdb simple_clock kernstack nfsclient nfsserver quota fifo fdesc union ffs cd9660 compat_43 revfs noprofiling hfs volfs devfs synthfs netat mrouting ipdivert ipfirewall ktrace inet6 ipsec tcpdrop_synfin gif stf] # RELEASE_TRACE = [RELEASE kdebug] -# PROFILE = [ppc mach medium vol pst gdb debug simple_clock kernstack nfsclient nfsserver quota fifo fdesc union ffs cd9660 compat_43 revfs profile hfs volfs devfs synthfs netat mrouting ipdivert ipfirewall] -# DEBUG = [ppc mach medium vol pst gdb debug simple_clock kernstack nfsclient nfsserver quota fifo fdesc union ffs cd9660 compat_43 revfs profiling hfs volfs devfs synthfs netat mrouting mach_assert ipdivert ipfirewall] +# PROFILE = [ppc mach medium vol pst gdb debug simple_clock kernstack nfsclient nfsserver quota fifo fdesc union ffs cd9660 compat_43 revfs profile hfs volfs devfs synthfs netat mrouting ipdivert ipfirewall ktrace inet6 ipsec tcpdrop_synfin gif stf] +# DEBUG = [ppc mach medium vol pst gdb debug simple_clock kernstack nfsclient nfsserver quota fifo fdesc union ffs cd9660 compat_43 revfs profiling hfs volfs devfs synthfs netat mrouting mach_assert ipdivert ipfirewall ktrace inet6 ipsec tcpdrop_synfin gif stf] # DEBUG_TRACE = [DEBUG kdebug] # ###################################################################### @@ -81,7 +81,3 @@ pseudo-device nfsmeas # # pseudo-device vol # -# -# Point-to-Point Protocol support -# -pseudo-device ppp 2 # diff --git a/bsd/conf/Makefile b/bsd/conf/Makefile index c2e1c4abc..fee0600ae 100644 --- a/bsd/conf/Makefile +++ b/bsd/conf/Makefile @@ -47,14 +47,13 @@ do_setup_conf: $(OBJROOT)/$(KERNEL_CONFIG)_$(ARCH_CONFIG)/$(COMPONENT)/doconf \ do_all: do_setup_conf @echo "[ $(SOURCE) ] Starting do_all $(COMPONENT) $(BSD_KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)"; \ - (cd $(COMPOBJROOT)/$(BSD_KERNEL_CONFIG); \ next_source=$(subst conf/,,$(SOURCE)); \ - ${MAKE} MAKEFILES=$(TARGET)/$(BSD_KERNEL_CONFIG)/Makefile \ + ${MAKE} -C $(COMPOBJROOT)/$(BSD_KERNEL_CONFIG) \ + MAKEFILES=$(TARGET)/$(BSD_KERNEL_CONFIG)/Makefile \ SOURCE=$${next_source} \ TARGET=$(TARGET) \ INCL_MAKEDEP=FALSE \ - build_all \ - ); \ + build_all; \ echo "[ $(SOURCE) ] Returning do_all $(COMPONENT) $(BSD_KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)"; do_build_all: do_all diff --git a/bsd/conf/Makefile.template b/bsd/conf/Makefile.template index 235b7663f..c209ca49e 100644 --- a/bsd/conf/Makefile.template +++ b/bsd/conf/Makefile.template @@ -10,11 +10,6 @@ # export IDENT -# -# XXX: INCFLAGS -# -INCFLAGS_MAKEFILE= -I$(SOURCE) -I$(SOURCE)include -I$(SOURCE)netat -I$(SOURCE)netat/h -I$(SOURCE)netat/at -I$(SOURCE_DIR) - export MakeInc_cmd=${SRCROOT}/makedefs/MakeInc.cmd export MakeInc_def=${SRCROOT}/makedefs/MakeInc.def export MakeInc_rule=${SRCROOT}/makedefs/MakeInc.rule @@ -26,7 +21,10 @@ include $(MakeInc_def) # # XXX: CFLAGS # -CFLAGS+= -imacros meta_features.h -DARCH_PRIVATE -DKERNEL -DDRIVER_PRIVATE -D_KERNEL_BUILD -DKERNEL_BUILD -DMACH_KERNEL -DBSD_BUILD -DNCPUS=1 -Wno-four-char-constants -fpascal-strings -D__APPLE__ -I. +CFLAGS+= -imacros meta_features.h -DARCH_PRIVATE -DKERNEL -DDRIVER_PRIVATE \ + -D_KERNEL_BUILD -DKERNEL_BUILD -DMACH_KERNEL -DBSD_BUILD \ + -DBSD_KERNEL_PRIVATE -DNCPUS=1 -Wno-four-char-constants -fpascal-strings \ + -D__APPLE__ -I. # XXX: ld flags for bsd.o export LDFLAGS_COMPONENT += -keep_private_externs diff --git a/bsd/conf/files b/bsd/conf/files index bc6001350..7012205fa 100644 --- a/bsd/conf/files +++ b/bsd/conf/files @@ -59,6 +59,7 @@ OPTIONS/compat_43 optional compat_43 OPTIONS/diagnostic optional diagnostic OPTIONS/ktrace optional ktrace OPTIONS/profiling optional profiling +OPTIONS/vndevice optional vndevice # # Network options @@ -71,9 +72,6 @@ OPTIONS/tpip optional tpip OPTIONS/ns optional ns OPTIONS/iso optional iso OPTIONS/tuba optional tuba -OPTIONS/ccitt optional ccitt -OPTIONS/hdlc optional hdlc -OPTIONS/llc optional llc OPTIONS/gateway optional gateway OPTIONS/ipx optional ipx OPTIONS/tun optional tun @@ -101,15 +99,10 @@ OPTIONS/netat optional netat # OPTIONS/ffs optional ffs OPTIONS/hfs optional hfs -OPTIONS/hfs_hardlinks optional hfs OPTIONS/mfs optional mfs OPTIONS/fdesc optional fdesc OPTIONS/fifo optional fifo -OPTIONS/kernfs optional kernfs OPTIONS/nullfs optional nullfs -OPTIONS/portal optional portal -OPTIONS/procfs optional procfs -OPTIONS/umapfs optional umapfs OPTIONS/union optional union OPTIONS/cd9660 optional cd9660 OPTIONS/volfs optional volfs @@ -122,6 +115,8 @@ bsd/dev/random/YarrowCoreLib/src/comp.c standard bsd/dev/random/YarrowCoreLib/src/prng.c standard bsd/dev/random/YarrowCoreLib/src/sha1mod.c standard bsd/dev/random/YarrowCoreLib/src/yarrowUtils.c standard +bsd/dev/vn/vn.c optional vndevice +bsd/dev/vn/shadow.c optional vndevice bsd/libkern/random.c standard bsd/libkern/scanc.c standard @@ -135,6 +130,7 @@ bsd/vfs/vfs_cluster.c standard bsd/vfs/vfs_conf.c standard bsd/vfs/vfs_init.c standard bsd/vfs/vfs_lookup.c standard +bsd/vfs/vfs_quota.c standard bsd/vfs/vfs_subr.c standard bsd/vfs/vfs_syscalls.c standard bsd/vfs/vfs_support.c standard @@ -146,26 +142,10 @@ bsd/miscfs/deadfs/dead_vnops.c standard bsd/miscfs/fdesc/fdesc_vfsops.c optional fdesc bsd/miscfs/fdesc/fdesc_vnops.c optional fdesc bsd/miscfs/fifofs/fifo_vnops.c optional fifo -bsd/miscfs/kernfs/kernfs_vfsops.c optional kernfs -bsd/miscfs/kernfs/kernfs_vnops.c optional kernfs bsd/miscfs/nullfs/null_subr.c optional nullfs bsd/miscfs/nullfs/null_vfsops.c optional nullfs bsd/miscfs/nullfs/null_vnops.c optional nullfs -bsd/miscfs/portal/portal_vfsops.c optional portal -bsd/miscfs/portal/portal_vnops.c optional portal -bsd/miscfs/procfs/procfs_subr.c optional procfs -bsd/miscfs/procfs/procfs_vnops.c optional procfs -bsd/miscfs/procfs/procfs_vfsops.c optional procfs -bsd/miscfs/procfs/procfs_note.c optional procfs -bsd/miscfs/procfs/procfs_mem.c optional procfs -bsd/miscfs/procfs/procfs_ctl.c optional procfs -bsd/miscfs/procfs/procfs_status.c optional procfs -bsd/miscfs/procfs/procfs_regs.c optional procfs -bsd/miscfs/procfs/procfs_fpregs.c optional procfs bsd/miscfs/specfs/spec_vnops.c standard -bsd/miscfs/umapfs/umap_subr.c optional umapfs -bsd/miscfs/umapfs/umap_vfsops.c optional umapfs -bsd/miscfs/umapfs/umap_vnops.c optional umapfs bsd/miscfs/union/union_subr.c optional union bsd/miscfs/union/union_vfsops.c optional union bsd/miscfs/union/union_vnops.c optional union @@ -189,7 +169,6 @@ bsd/isofs/cd9660/cd9660_util.c optional cd9660 bsd/isofs/cd9660/cd9660_vfsops.c optional cd9660 bsd/isofs/cd9660/cd9660_vnops.c optional cd9660 -bsd/net/if_spppsubr.c optional sppp bsd/net/slcompress.c optional i4bipr bsd/net/bpf.c optional bpfilter bsd/net/bpf_filter.c optional bpfilter @@ -204,12 +183,10 @@ bsd/net/ether_at_pr_module.c optional ether bsd/net/ether_inet_pr_module.c optional ether bsd/net/ether_inet6_pr_module.c optional ether inet6 bsd/net/if_ethersubr.c optional ether -bsd/net/if_fddisubr.c optional fddi bsd/net/if_loop.c optional loop bsd/net/if_media.c standard bsd/net/if_mib.c standard bsd/net/if_sl.c optional sl -bsd/net/if_spppsubr.c optional sppp bsd/net/if_tun.c optional tun bsd/net/if_vlan.c optional vlan bsd/net/kext_net.c standard @@ -227,45 +204,27 @@ bsd/net/netisr.c standard bsd/net/zlib.c optional ipsec bsd/net/if_dummy.c optional dummy bsd/net/if_gif.c optional gif +bsd/net/if_stf.c optional stf #bsd/net/radish.c standard bsd/net/if_faith.c optional faith bsd/net/net_osdep.c optional ipsec bsd/net/net_osdep.c optional inet6 -bsd/netccitt//ccitt_proto.c optional ccitt -bsd/netccitt/hd_debug.c optional hdlc -bsd/netccitt/hd_input.c optional hdlc -bsd/netccitt/hd_output.c optional hdlc -bsd/netccitt/hd_subr.c optional hdlc -bsd/netccitt/hd_timer.c optional hdlc -bsd/netccitt/if_x25subr.c optional ccitt -bsd/netccitt/llc_input.c optional llc -bsd/netccitt/llc_output.c optional llc -bsd/netccitt/llc_subr.c optional llc -bsd/netccitt/llc_timer.c optional llc -bsd/netccitt/pk_acct.c optional ccitt -bsd/netccitt/pk_debug.c optional ccitt -bsd/netccitt/pk_input.c optional ccitt -bsd/netccitt/pk_llcsubr.c optional llc hdlc -bsd/netccitt/pk_output.c optional ccitt -bsd/netccitt/pk_subr.c optional ccitt -bsd/netccitt/pk_timer.c optional ccitt -bsd/netccitt/pk_usrreq.c optional ccitt - bsd/netinet/if_atm.c optional atm bsd/netinet/if_ether.c optional ether bsd/netinet/igmp.c standard bsd/netinet/in.c standard bsd/netinet/in_bootp.c standard +bsd/netinet/dhcp_options.c standard bsd/netinet/in_pcb.c standard bsd/netinet/in_proto.c standard bsd/netinet/in_rmx.c standard bsd/netinet/ip_divert.c optional ipdivert bsd/netinet/ip_dummynet.c optional dummynet bsd/netinet/ip_flow.c standard -bsd/netinet/ip_fw.c optional ipfirewall bsd/netinet/ip_icmp.c standard +bsd/netinet/ip_id.c optional randomipid bsd/netinet/ip_input.c standard bsd/netinet/ip_mroute.c standard bsd/netinet/ip_output.c standard @@ -280,75 +239,62 @@ bsd/netinet/udp_usrreq.c standard bsd/netinet/in_gif.c optional gif inet bsd/netinet/ip_ecn.c optional inet inet6 bsd/netinet/ip_ecn.c optional inet ipsec -bsd/netinet/ip_encap.c optional inet inet6 -bsd/netinet/ip_encap.c optional inet ipsec - -bsd/netinet6/in6.c optional inet6 -bsd/netinet6/in6_gif.c optional gif inet6 -bsd/netinet6/in6_ifattach.c optional inet6 -bsd/netinet6/in6_cksum.c optional inet6 -bsd/netinet6/in6_pcb.c optional inet6 -bsd/netinet6/in6_src.c optional inet6 -#bsd/netinet6/in6_pcbsubr.c optional inet6 -bsd/netinet6/in6_proto.c optional inet6 -bsd/netinet6/in6_rmx.c optional inet6 -bsd/netinet6/in6_prefix.c optional inet6 -bsd/netinet6/dest6.c optional inet6 -bsd/netinet6/frag6.c optional inet6 -bsd/netinet6/icmp6.c optional inet6 -bsd/netinet6/ip6_input.c optional inet6 -bsd/netinet6/ip6_forward.c optional inet6 -bsd/netinet6/ip6_mroute.c optional inet6 -bsd/netinet6/ip6_output.c optional inet6 -bsd/netinet6/route6.c optional inet6 -bsd/netinet6/mld6.c optional inet6 -bsd/netinet6/nd6.c optional inet6 -bsd/netinet6/nd6_nbr.c optional inet6 -bsd/netinet6/nd6_rtr.c optional inet6 -bsd/netinet6/raw_ip6.c optional inet6 -bsd/netinet6/udp6_usrreq.c optional inet6 -bsd/netinet6/ah_core.c optional ipsec -bsd/netinet6/esp_core.c optional ipsec -bsd/netinet6/ipsec.c optional ipsec -bsd/netinet6/ah_output.c optional ipsec -bsd/netinet6/ah_input.c optional ipsec -bsd/netinet6/esp_output.c optional ipsec -bsd/netinet6/esp_input.c optional ipsec +bsd/netinet/ip_encap.c optional inet +bsd/netinet6/ah_core.c optional ipsec +bsd/netinet6/ah_input.c optional ipsec +bsd/netinet6/ah_output.c optional ipsec +bsd/netinet6/esp_core.c optional ipsec ipsec_esp +bsd/netinet6/esp_input.c optional ipsec ipsec_esp +bsd/netinet6/esp_output.c optional ipsec ipsec_esp +bsd/netinet6/esp_rijndael.c optional ipsec ipsec_esp +bsd/netinet6/ipsec.c optional ipsec +bsd/netinet6/dest6.c optional inet6 +bsd/netinet6/frag6.c optional inet6 +bsd/netinet6/icmp6.c optional inet6 +bsd/netinet6/in6.c optional inet6 +bsd/netinet6/in6_cksum.c optional inet6 +bsd/netinet6/in6_gif.c optional gif inet6 +bsd/netinet6/ip6_forward.c optional inet6 +bsd/netinet6/in6_ifattach.c optional inet6 +bsd/netinet6/ip6_input.c optional inet6 +bsd/netinet6/ip6_mroute.c optional inet6 +bsd/netinet6/ip6_output.c optional inet6 +bsd/netinet6/in6_src.c optional inet6 bsd/netinet6/ipcomp_core.c optional ipsec -bsd/netinet6/ipcomp_input.c optional ipsec -bsd/netinet6/ipcomp_output.c optional ipsec -bsd/netinet6/ip6_fw.c optional ipv6firewall -bsd/netinet6/natpt_dispatch.c optional inet6 natpt -bsd/netinet6/natpt_list.c optional inet6 natpt -bsd/netinet6/natpt_log.c optional inet6 natpt -bsd/netinet6/natpt_rule.c optional inet6 natpt -bsd/netinet6/natpt_trans.c optional inet6 natpt -bsd/netinet6/natpt_tslot.c optional inet6 natpt -bsd/netinet6/natpt_usrreq.c optional inet6 natpt +bsd/netinet6/ipcomp_input.c optional ipsec +bsd/netinet6/ipcomp_output.c optional ipsec +bsd/netinet6/in6_pcb.c optional inet6 +bsd/netinet6/in6_prefix.c optional inet6 +bsd/netinet6/in6_proto.c optional inet6 +bsd/netinet6/in6_rmx.c optional inet6 +bsd/netinet6/mld6.c optional inet6 +bsd/netinet6/nd6.c optional inet6 +bsd/netinet6/nd6_nbr.c optional inet6 +bsd/netinet6/nd6_rtr.c optional inet6 +bsd/netinet6/raw_ip6.c optional inet6 +bsd/netinet6/route6.c optional inet6 +bsd/netinet6/scope6.c optional inet6 +bsd/netinet6/udp6_output.c optional inet6 +bsd/netinet6/udp6_usrreq.c optional inet6 bsd/netkey/key.c optional ipsec bsd/netkey/key_debug.c optional ipsec bsd/netkey/keysock.c optional ipsec bsd/netkey/keydb.c optional ipsec +bsd/kern/md5c.c optional inet bsd/kern/md5c.c optional inet6 -bsd/kern/md5c.c optional ipsec -#bsd/crypto/md5.c optional ipsec -#bsd/crypto/hmac_md5.c optional ipsec -bsd/crypto/sha1.c optional ipsec -bsd/crypto/des/des_cbc.c optional ipsec -bsd/crypto/des/des_ecb.c optional ipsec -bsd/crypto/des/des_setkey.c optional ipsec -bsd/crypto/des/des_3cbc.c optional ipsec -bsd/crypto/blowfish/bf_cbc.c optional ipsec -bsd/crypto/blowfish/bf_cbc_m.c optional ipsec -bsd/crypto/blowfish/bf_enc.c optional ipsec -bsd/crypto/blowfish/bf_skey.c optional ipsec -bsd/crypto/cast128/cast128.c optional ipsec -bsd/crypto/cast128/cast128_cbc.c optional ipsec -bsd/crypto/rc5/rc5.c optional ipsec -bsd/crypto/rc5/rc5_cbc.c optional ipsec - +bsd/kern/md5c.c optional crypto +bsd/crypto/sha1.c optional crypto +bsd/crypto/sha2/sha2.c optional crypto +bsd/crypto/des/des_ecb.c optional crypto +bsd/crypto/des/des_setkey.c optional crypto +bsd/crypto/blowfish/bf_enc.c optional crypto +bsd/crypto/blowfish/bf_skey.c optional crypto +bsd/crypto/cast128/cast128.c optional crypto +bsd/crypto/rijndael/rijndael-alg-fst.c optional crypto +bsd/crypto/rijndael/rijndael-api-fst.c optional crypto +bsd/crypto/rc4/rc4.c optional crypto #bsd/netpm/pm_aTT.c optional pm #bsd/netpm/pm_ams.c optional pm @@ -362,18 +308,6 @@ bsd/crypto/rc5/rc5_cbc.c optional ipsec #bsd/netpm/pm_usrreq.c optional pm - -bsd/netns/idp_usrreq.c optional ns -bsd/netns/ns.c optional ns -bsd/netns/ns_error.c optional ns -bsd/netns/ns_input.c optional ns -bsd/netns/ns_ip.c optional ns -bsd/netns/ns_output.c optional ns -bsd/netns/ns_pcb.c optional ns -bsd/netns/ns_proto.c optional ns -bsd/netns/spp_debug.c optional ns -bsd/netns/spp_usrreq.c optional ns - bsd/netat/at.c optional netat bsd/netat/at_proto.c optional netat bsd/netat/at_pcb.c optional netat @@ -446,6 +380,8 @@ bsd/nfs/nfs_syscalls.c optional nfsclient nfsserver bsd/nfs/nfs_vfsops.c optional nfsclient bsd/nfs/nfs_vnops.c optional nfsclient +bsd/kern/netboot.c optional nfsclient + bsd/ufs/ffs/ffs_alloc.c standard bsd/ufs/ffs/ffs_balloc.c standard bsd/ufs/ffs/ffs_inode.c standard @@ -465,19 +401,23 @@ bsd/ufs/ufs/ufs_quota.c optional quota bsd/ufs/ufs/ufs_vfsops.c standard bsd/ufs/ufs/ufs_vnops.c standard +bsd/hfs/hfs_attrlist.c optional hfs bsd/hfs/hfs_btreeio.c optional hfs +bsd/hfs/hfs_catalog.c optional hfs +bsd/hfs/hfs_chash.c optional hfs +bsd/hfs/hfs_cnode.c optional hfs bsd/hfs/hfs_encodinghint.c optional hfs bsd/hfs/hfs_encodings.c optional hfs bsd/hfs/hfs_endian.c optional hfs bsd/hfs/hfs_link.c optional hfs bsd/hfs/hfs_lockf.c optional hfs bsd/hfs/hfs_lookup.c optional hfs +bsd/hfs/hfs_quota.c optional quota bsd/hfs/hfs_readwrite.c optional hfs bsd/hfs/hfs_search.c optional hfs bsd/hfs/hfs_vfsops.c optional hfs bsd/hfs/hfs_vfsutils.c optional hfs -bsd/hfs/hfs_vhash.c optional hfs -bsd/hfs/hfs_vnodeops.c optional hfs +bsd/hfs/hfs_vnops.c optional hfs bsd/hfs/MacOSStubs.c optional hfs bsd/hfs/rangelist.c optional hfs bsd/hfs/hfscommon/BTree/BTree.c optional hfs @@ -492,9 +432,7 @@ bsd/hfs/hfscommon/Catalog/CatalogUtilities.c optional hfs bsd/hfs/hfscommon/Catalog/FileIDsServices.c optional hfs bsd/hfs/hfscommon/Misc/BTreeWrapper.c optional hfs bsd/hfs/hfscommon/Misc/FileExtentMapping.c optional hfs -bsd/hfs/hfscommon/Misc/GenericMRUCache.c optional hfs bsd/hfs/hfscommon/Misc/VolumeAllocation.c optional hfs -bsd/hfs/hfscommon/Misc/VolumeRequests.c optional hfs bsd/hfs/hfscommon/Unicode/UnicodeWrappers.c optional hfs bsd/kern/bsd_init.c standard @@ -505,14 +443,16 @@ bsd/kern/kern_clock.c standard bsd/kern/kern_core.c standard bsd/kern/kern_symfile.c standard bsd/kern/kern_descrip.c standard -bsd/kern/kern_event.c standard +bsd/kern/kern_event.c standard +bsd/kern/kern_control.c standard bsd/kern/kern_exec.c standard bsd/kern/kern_exit.c standard bsd/kern/kern_fork.c standard -bsd/kern/kern_ktrace.c optional ktrace +bsd/kern/kern_ktrace.c standard bsd/kern/kern_lock.c optional cpus bsd/kern/kern_malloc.c standard bsd/kern/kern_mman.c standard +bsd/kern/kern_panicinfo.c standard bsd/kern/kern_physio.c standard bsd/kern/kern_proc.c standard bsd/kern/kern_prot.c standard @@ -547,8 +487,7 @@ bsd/kern/tty_tty.c standard bsd/kern/ubc_subr.c standard bsd/kern/uipc_domain.c standard bsd/kern/uipc_mbuf.c standard -bsd/kern/uipc_mbuf2.c optional inet6 -bsd/kern/uipc_mbuf2.c optional ipsec +bsd/kern/uipc_mbuf2.c standard bsd/kern/uipc_proto.c standard bsd/kern/uipc_socket.c standard bsd/kern/uipc_socket2.c standard @@ -556,6 +495,7 @@ bsd/kern/uipc_syscalls.c standard bsd/kern/uipc_usrreq.c standard bsd/kern/sysv_ipc.c standard bsd/kern/sysv_shm.c standard +bsd/kern/sysv_sem.c standard bsd/kern/mach_fat.c standard bsd/kern/mach_header.c standard bsd/kern/mach_loader.c standard diff --git a/bsd/conf/files.ppc b/bsd/conf/files.ppc index 9b4564717..1cfa5685c 100644 --- a/bsd/conf/files.ppc +++ b/bsd/conf/files.ppc @@ -14,6 +14,7 @@ bsd/dev/ppc/memmove.c standard bsd/dev/ppc/machdep.c standard bsd/dev/ppc/kern_machdep.c standard bsd/dev/ppc/stubs.c standard +bsd/dev/ppc/systemcalls.c standard bsd/dev/ppc/km.c standard bsd/dev/ppc/xsumas.s standard diff --git a/bsd/conf/param.c b/bsd/conf/param.c index 2cb4f2d29..9de9d895c 100644 --- a/bsd/conf/param.c +++ b/bsd/conf/param.c @@ -70,7 +70,7 @@ #include #include #include -#include +#include #include #include #include @@ -95,32 +95,6 @@ int nport = NPROC / 2; #define MAXSOCKETS NMBCLUSTERS int maxsockets = MAXSOCKETS; -#define SHMMAXPGS 1024 /* XXX until we have more kmap space */ - -#ifndef SHMMAX -#define SHMMAX (SHMMAXPGS * 4096) -#endif -#ifndef SHMMIN -#define SHMMIN 1 -#endif -#ifndef SHMMNI -#define SHMMNI 32 /* <= SHMMMNI in shm.h */ -#endif -#ifndef SHMSEG -#define SHMSEG 8 -#endif -#ifndef SHMALL -#define SHMALL (SHMMAXPGS) -#endif - -struct shminfo shminfo = { - SHMMAX, - SHMMIN, - SHMMNI, - SHMSEG, - SHMALL -}; - /* * These have to be allocated somewhere; allocating * them here forces loader errors if this file is omitted @@ -132,3 +106,4 @@ struct cblock *cfreelist = 0; int cfreecount = 0; struct buf *buf; struct domain *domains; + diff --git a/bsd/conf/tools/doconf/doconf.csh b/bsd/conf/tools/doconf/doconf.csh index 43388c11c..ae5ab908b 100755 --- a/bsd/conf/tools/doconf/doconf.csh +++ b/bsd/conf/tools/doconf/doconf.csh @@ -287,7 +287,7 @@ part != 0 {\ # kernel binaries are put). # echo 'builddir "."' >> $SYSCONF.new - set OBJRELDIR=`relpath $OBJROOT $OBJDIR` + set OBJRELDIR=`$RELPATH $OBJROOT $OBJDIR` echo 'objectdir "'$OBJROOT'/'$OBJRELDIR'"' >> $SYSCONF.new set SRCDIR=`dirname $SOURCE` echo 'sourcedir "'$SRCROOT'"' >> $SYSCONF.new diff --git a/bsd/conf/version.major b/bsd/conf/version.major index 7ed6ff82d..1e8b31496 100644 --- a/bsd/conf/version.major +++ b/bsd/conf/version.major @@ -1 +1 @@ -5 +6 diff --git a/bsd/conf/version.minor b/bsd/conf/version.minor index 7ed6ff82d..573541ac9 100644 --- a/bsd/conf/version.minor +++ b/bsd/conf/version.minor @@ -1 +1 @@ -5 +0 diff --git a/bsd/conf/version.variant b/bsd/conf/version.variant index 8b1378917..e69de29bb 100644 --- a/bsd/conf/version.variant +++ b/bsd/conf/version.variant @@ -1 +0,0 @@ - diff --git a/bsd/crypto/Makefile b/bsd/crypto/Makefile index d191e76d1..4e0880559 100644 --- a/bsd/crypto/Makefile +++ b/bsd/crypto/Makefile @@ -8,37 +8,32 @@ include $(MakeInc_cmd) include $(MakeInc_def) INSTINC_SUBDIRS = \ + blowfish \ cast128 \ des \ - blowfish \ - rc5 + rc4 \ + rijndael \ + sha2 INSTINC_SUBDIRS_PPC = \ INSTINC_SUBDIRS_I386 = \ -EXPINC_SUBDIRS = \ - cast128 \ - des \ - blowfish \ - rc5 +EXPINC_SUBDIRS = ${INSTINC_SUBDIRS} EXPINC_SUBDIRS_PPC = \ EXPINC_SUBDIRS_I386 = \ -DATAFILES = \ - sha1.h - -INSTALL_MI_LIST = ${DATAFILES} +PRIVATE_DATAFILES = \ + sha1.h md5.h INSTALL_MI_DIR = crypto -EXPORT_MI_LIST = ${DATAFILES} - -EXPORT_MI_DIR = crypto +EXPORT_MI_DIR = ${INSTALL_MI_DIR} +INSTALL_MI_LCL_KERN_LIST = ${PRIVATE_DATAFILES} include $(MakeInc_rule) include $(MakeInc_dir) diff --git a/bsd/crypto/blowfish/Makefile b/bsd/crypto/blowfish/Makefile index 73b43dc7f..e4885864b 100644 --- a/bsd/crypto/blowfish/Makefile +++ b/bsd/crypto/blowfish/Makefile @@ -19,19 +19,14 @@ EXPINC_SUBDIRS_PPC = \ EXPINC_SUBDIRS_I386 = \ -DATAFILES = \ - bf_locl.h bf_pi.h blowfish.h - -INSTALL_MI_LIST = ${DATAFILES} +PRIVATE_DATAFILES = \ + blowfish.h INSTALL_MI_DIR = crypto -EXPORT_MI_LIST = ${DATAFILES} - -EXPORT_MI_DIR = crypto +EXPORT_MI_DIR = ${INSTALL_MI_DIR} +INSTALL_MI_LCL_KERN_LIST = ${PRIVATE_DATAFILES} include $(MakeInc_rule) include $(MakeInc_dir) - - diff --git a/bsd/crypto/blowfish/bf_cbc.c b/bsd/crypto/blowfish/bf_cbc.c deleted file mode 100644 index e382fa993..000000000 --- a/bsd/crypto/blowfish/bf_cbc.c +++ /dev/null @@ -1,148 +0,0 @@ -/* crypto/bf/bf_cbc.c */ -/* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@mincom.oz.au). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@mincom.oz.au). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@mincom.oz.au)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@mincom.oz.au)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ - -#include -#include - -void BF_cbc_encrypt(in, out, length, ks, iv, encrypt) -unsigned char *in; -unsigned char *out; -long length; -BF_KEY *ks; -unsigned char *iv; -int encrypt; - { - register BF_LONG tin0,tin1; - register BF_LONG tout0,tout1,xor0,xor1; - register long l=length; - BF_LONG tin[2]; - - if (encrypt) - { - n2l(iv,tout0); - n2l(iv,tout1); - iv-=8; - for (l-=8; l>=0; l-=8) - { - n2l(in,tin0); - n2l(in,tin1); - tin0^=tout0; - tin1^=tout1; - tin[0]=tin0; - tin[1]=tin1; - BF_encrypt(tin,ks,BF_ENCRYPT); - tout0=tin[0]; - tout1=tin[1]; - l2n(tout0,out); - l2n(tout1,out); - } - if (l != -8) - { - n2ln(in,tin0,tin1,l+8); - tin0^=tout0; - tin1^=tout1; - tin[0]=tin0; - tin[1]=tin1; - BF_encrypt(tin,ks,BF_ENCRYPT); - tout0=tin[0]; - tout1=tin[1]; - l2n(tout0,out); - l2n(tout1,out); - } - l2n(tout0,iv); - l2n(tout1,iv); - } - else - { - n2l(iv,xor0); - n2l(iv,xor1); - iv-=8; - for (l-=8; l>=0; l-=8) - { - n2l(in,tin0); - n2l(in,tin1); - tin[0]=tin0; - tin[1]=tin1; - BF_encrypt(tin,ks,BF_DECRYPT); - tout0=tin[0]^xor0; - tout1=tin[1]^xor1; - l2n(tout0,out); - l2n(tout1,out); - xor0=tin0; - xor1=tin1; - } - if (l != -8) - { - n2l(in,tin0); - n2l(in,tin1); - tin[0]=tin0; - tin[1]=tin1; - BF_encrypt(tin,ks,BF_DECRYPT); - tout0=tin[0]^xor0; - tout1=tin[1]^xor1; - l2nn(tout0,tout1,out,l+8); - xor0=tin0; - xor1=tin1; - } - l2n(xor0,iv); - l2n(xor1,iv); - } - tin0=tin1=tout0=tout1=xor0=xor1=0; - tin[0]=tin[1]=0; - } - diff --git a/bsd/crypto/blowfish/bf_cbc_m.c b/bsd/crypto/blowfish/bf_cbc_m.c deleted file mode 100644 index c7a56d904..000000000 --- a/bsd/crypto/blowfish/bf_cbc_m.c +++ /dev/null @@ -1,339 +0,0 @@ -/* - * heavily modified to accept mbuf, by Jun-ichiro itojun Itoh - * , 1997. - */ -/* crypto/bf/bf_cbc.c */ -/* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@mincom.oz.au). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@mincom.oz.au). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@mincom.oz.au)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@mincom.oz.au)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ - -#include -#include -#include -#include - -#include -#include - -#define panic(x) {printf(x); return;} - -void BF_cbc_encrypt_m(m0, skip, length, key, iv, mode) - struct mbuf *m0; - int skip; - int length; - BF_KEY *key; - unsigned char *iv; - int mode; -{ - u_int8_t inbuf[8], outbuf[8]; - struct mbuf *m; - size_t off; - register BF_LONG tin0, tin1; - register BF_LONG tout0, tout1; - BF_LONG tin[2]; - - /* sanity checks */ - if (m0->m_pkthdr.len < skip) { - printf("mbuf length < skip\n"); - return; - } - if (m0->m_pkthdr.len < length) { - printf("mbuf length < encrypt length\n"); - return; - } - if (m0->m_pkthdr.len < skip + length) { - printf("mbuf length < skip + encrypt length\n"); - return; - } - if (length % 8) { - printf("length is not multiple of 8\n"); - return; - } - - m = m0; - off = 0; - - /* skip over the header */ - while (skip) { - if (!m) - panic("mbuf chain?\n"); - if (m->m_len <= skip) { - skip -= m->m_len; - m = m->m_next; - off = 0; - } else { - off = skip; - skip = 0; - } - } - - /* initialize */ - tin0 = tin1 = tout0 = tout1 = 0; - tin[0] = tin[1] = 0; - - if (mode == BF_ENCRYPT) { - u_int8_t *in, *out; - - n2l(iv, tout0); - n2l(iv, tout1); - - while (0 < length) { - if (!m) - panic("mbuf chain?\n"); - - /* - * copy the source into input buffer. - * don't update off or m, since we need to use them * later. - */ - if (off + 8 <= m->m_len) - bcopy(mtod(m, u_int8_t *) + off, &inbuf[0], 8); - else { - struct mbuf *n; - size_t noff; - u_int8_t *p; - u_int8_t *in; - - n = m; - noff = off; - p = mtod(n, u_int8_t *) + noff; - - in = &inbuf[0]; - while (in - &inbuf[0] < 8) { - if (!p) - panic("mbuf chain?\n"); - - *in++ = *p++; - noff++; - if (noff < n->m_len) - continue; - do { - n = n->m_next; - } while (n && ! n->m_len); - noff = 0; - if (n) - p = mtod(n, u_int8_t *) + noff; - else - p = NULL; - } - } - - in = &inbuf[0]; - out = &outbuf[0]; - n2l(in, tin0); - n2l(in, tin1); - - tin0 ^= tout0; tin[0] = tin0; - tin1 ^= tout1; tin[1] = tin1; - BF_encrypt(tin, key, BF_ENCRYPT); - tout0 = tin[0]; l2n(tout0, out); - tout1 = tin[1]; l2n(tout1, out); - - /* - * copy the output buffer into the result. - * need to update off and m. - */ - if (off + 8 < m->m_len) { - bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); - off += 8; - } else if (off + 8 == m->m_len) { - bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); - do { - m = m->m_next; - } while (m && ! m->m_len); - off = 0; - } else { - struct mbuf *n; - size_t noff; - u_int8_t *p; - u_int8_t *out; - - n = m; - noff = off; - p = mtod(n, u_int8_t *) + noff; - - out = &outbuf[0]; - while (out - &outbuf[0] < 8) { - if (!p) - panic("mbuf chain?"); - *p++ = *out++; - noff++; - if (noff < n->m_len) - continue; - do { - n = n->m_next; - } while (n && ! n->m_len); - noff = 0; - if (n) - p = mtod(n, u_int8_t *) + noff; - else - p = NULL; - } - - m = n; - off = noff; - } - - length -= 8; - } - } else if (mode == BF_DECRYPT) { - register BF_LONG xor0, xor1; - u_int8_t *in, *out; - - xor0 = xor1 = 0; - n2l(iv, xor0); - n2l(iv, xor1); - - while (0 < length) { - if (!m) - panic("mbuf chain?\n"); - - /* - * copy the source into input buffer. - * don't update off or m, since we need to use them * later. - */ - if (off + 8 <= m->m_len) - bcopy(mtod(m, u_int8_t *) + off, &inbuf[0], 8); - else { - struct mbuf *n; - size_t noff; - u_int8_t *p; - u_int8_t *in; - - n = m; - noff = off; - p = mtod(n, u_int8_t *) + noff; - - in = &inbuf[0]; - while (in - &inbuf[0] < 8) { - if (!p) - panic("mbuf chain?\n"); - *in++ = *p++; - noff++; - if (noff < n->m_len) - continue; - do { - n = n->m_next; - } while (n && ! n->m_len); - noff = 0; - if (n) - p = mtod(n, u_int8_t *) + noff; - else - p = NULL; - } - } - - in = &inbuf[0]; - out = &outbuf[0]; - n2l(in, tin0); tin[0] = tin0; - n2l(in, tin1); tin[1] = tin1; - BF_encrypt(tin, key, BF_DECRYPT); - tout0 = tin[0] ^ xor0; - tout1 = tin[1] ^ xor1; - l2n(tout0, out); - l2n(tout1, out); - xor0 = tin0; - xor1 = tin1; - - - /* - * copy the output buffer into the result. - * need to update off and m. - */ - if (off + 8 < m->m_len) { - bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); - off += 8; - } else if (off + 8 == m->m_len) { - bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); - do { - m = m->m_next; - } while (m && ! m->m_len); - off = 0; - } else { - struct mbuf *n; - size_t noff; - u_int8_t *p; - u_int8_t *out; - - n = m; - noff = off; - p = mtod(n, u_int8_t *) + noff; - - out = &outbuf[0]; - while (out - &outbuf[0] < 8) { - if (!p) - panic("mbuf chain?\n"); - *p++ = *out++; - noff++; - if (noff < n->m_len) - continue; - do { - n = n->m_next; - } while (n && ! n->m_len); - noff = 0; - if (n) - p = mtod(n, u_int8_t *) + noff; - else - p = NULL; - } - - m = n; - off = noff; - } - - length -= 8; - } - } -} diff --git a/bsd/crypto/blowfish/bf_enc.c b/bsd/crypto/blowfish/bf_enc.c index 41d302a51..afdc9cf4c 100644 --- a/bsd/crypto/blowfish/bf_enc.c +++ b/bsd/crypto/blowfish/bf_enc.c @@ -1,3 +1,6 @@ +/* $FreeBSD: src/sys/crypto/blowfish/bf_enc.c,v 1.1.2.2 2001/07/03 11:01:28 ume Exp $ */ +/* $KAME: bf_enc.c,v 1.5 2000/09/18 21:21:19 itojun Exp $ */ + /* crypto/bf/bf_enc.c */ /* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au) * All rights reserved. @@ -56,6 +59,7 @@ * [including the GNU Public Licence.] */ +#include #include #include @@ -69,72 +73,71 @@ If you set BF_ROUNDS to some value other than 16 or 20, you will have to modify the code. #endif -void BF_encrypt(data,key,encrypt) -BF_LONG *data; -BF_KEY *key; -int encrypt; - { - register BF_LONG l,r,*p,*s; +/* XXX "data" is host endian */ +void +BF_encrypt(data, key, encrypt) + BF_LONG *data; + BF_KEY *key; + int encrypt; +{ + register BF_LONG l, r, *p, *s; - p=key->P; - s= &(key->S[0]); - l=data[0]; - r=data[1]; + p = key->P; + s= &key->S[0]; + l = data[0]; + r = data[1]; - if (encrypt) - { + if (encrypt) { l^=p[0]; - BF_ENC(r,l,s,p[ 1]); - BF_ENC(l,r,s,p[ 2]); - BF_ENC(r,l,s,p[ 3]); - BF_ENC(l,r,s,p[ 4]); - BF_ENC(r,l,s,p[ 5]); - BF_ENC(l,r,s,p[ 6]); - BF_ENC(r,l,s,p[ 7]); - BF_ENC(l,r,s,p[ 8]); - BF_ENC(r,l,s,p[ 9]); - BF_ENC(l,r,s,p[10]); - BF_ENC(r,l,s,p[11]); - BF_ENC(l,r,s,p[12]); - BF_ENC(r,l,s,p[13]); - BF_ENC(l,r,s,p[14]); - BF_ENC(r,l,s,p[15]); - BF_ENC(l,r,s,p[16]); + BF_ENC(r, l, s, p[ 1]); + BF_ENC(l, r, s, p[ 2]); + BF_ENC(r, l, s, p[ 3]); + BF_ENC(l, r, s, p[ 4]); + BF_ENC(r, l, s, p[ 5]); + BF_ENC(l, r, s, p[ 6]); + BF_ENC(r, l, s, p[ 7]); + BF_ENC(l, r, s, p[ 8]); + BF_ENC(r, l, s, p[ 9]); + BF_ENC(l, r, s, p[10]); + BF_ENC(r, l, s, p[11]); + BF_ENC(l, r, s, p[12]); + BF_ENC(r, l, s, p[13]); + BF_ENC(l, r, s, p[14]); + BF_ENC(r, l, s, p[15]); + BF_ENC(l, r, s, p[16]); #if BF_ROUNDS == 20 - BF_ENC(r,l,s,p[17]); - BF_ENC(l,r,s,p[18]); - BF_ENC(r,l,s,p[19]); - BF_ENC(l,r,s,p[20]); + BF_ENC(r, l, s, p[17]); + BF_ENC(l, r, s, p[18]); + BF_ENC(r, l, s, p[19]); + BF_ENC(l, r, s, p[20]); #endif - r^=p[BF_ROUNDS+1]; - } - else - { - l^=p[BF_ROUNDS+1]; + r ^= p[BF_ROUNDS + 1]; + } else { + l ^= p[BF_ROUNDS + 1]; #if BF_ROUNDS == 20 - BF_ENC(r,l,s,p[20]); - BF_ENC(l,r,s,p[19]); - BF_ENC(r,l,s,p[18]); - BF_ENC(l,r,s,p[17]); + BF_ENC(r, l, s, p[20]); + BF_ENC(l, r, s, p[19]); + BF_ENC(r, l, s, p[18]); + BF_ENC(l, r, s, p[17]); #endif - BF_ENC(r,l,s,p[16]); - BF_ENC(l,r,s,p[15]); - BF_ENC(r,l,s,p[14]); - BF_ENC(l,r,s,p[13]); - BF_ENC(r,l,s,p[12]); - BF_ENC(l,r,s,p[11]); - BF_ENC(r,l,s,p[10]); - BF_ENC(l,r,s,p[ 9]); - BF_ENC(r,l,s,p[ 8]); - BF_ENC(l,r,s,p[ 7]); - BF_ENC(r,l,s,p[ 6]); - BF_ENC(l,r,s,p[ 5]); - BF_ENC(r,l,s,p[ 4]); - BF_ENC(l,r,s,p[ 3]); - BF_ENC(r,l,s,p[ 2]); - BF_ENC(l,r,s,p[ 1]); - r^=p[0]; - } - data[1]=l&0xffffffff; - data[0]=r&0xffffffff; + BF_ENC(r, l, s, p[16]); + BF_ENC(l, r, s, p[15]); + BF_ENC(r, l, s, p[14]); + BF_ENC(l, r, s, p[13]); + BF_ENC(r, l, s, p[12]); + BF_ENC(l, r, s, p[11]); + BF_ENC(r, l, s, p[10]); + BF_ENC(l, r, s, p[ 9]); + BF_ENC(r, l, s, p[ 8]); + BF_ENC(l, r, s, p[ 7]); + BF_ENC(r, l, s, p[ 6]); + BF_ENC(l, r, s, p[ 5]); + BF_ENC(r, l, s, p[ 4]); + BF_ENC(l, r, s, p[ 3]); + BF_ENC(r, l, s, p[ 2]); + BF_ENC(l, r, s, p[ 1]); + r ^= p[0]; } + data[1] = l & 0xffffffff; + data[0] = r & 0xffffffff; +} diff --git a/bsd/crypto/blowfish/bf_locl.h b/bsd/crypto/blowfish/bf_locl.h index fbf8d9814..c3fa929e0 100644 --- a/bsd/crypto/blowfish/bf_locl.h +++ b/bsd/crypto/blowfish/bf_locl.h @@ -1,3 +1,6 @@ +/* $FreeBSD: src/sys/crypto/blowfish/bf_locl.h,v 1.1.2.2 2001/07/03 11:01:28 ume Exp $ */ +/* $KAME: bf_locl.h,v 1.5 2000/08/31 06:03:48 itojun Exp $ */ + /* crypto/bf/bf_local.h */ /* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au) * All rights reserved. @@ -64,10 +67,10 @@ */ #undef c2l -#define c2l(c,l) (l =((unsigned long)(*((c)++))) , \ - l|=((unsigned long)(*((c)++)))<< 8L, \ - l|=((unsigned long)(*((c)++)))<<16L, \ - l|=((unsigned long)(*((c)++)))<<24L) +#define c2l(c,l) (l =((BF_LONG)(*((c)++))) , \ + l|=((BF_LONG)(*((c)++)))<< 8L, \ + l|=((BF_LONG)(*((c)++)))<<16L, \ + l|=((BF_LONG)(*((c)++)))<<24L) /* NOTE - c is not incremented as per c2l */ #undef c2ln @@ -75,14 +78,14 @@ c+=n; \ l1=l2=0; \ switch (n) { \ - case 8: l2 =((unsigned long)(*(--(c))))<<24L; \ - case 7: l2|=((unsigned long)(*(--(c))))<<16L; \ - case 6: l2|=((unsigned long)(*(--(c))))<< 8L; \ - case 5: l2|=((unsigned long)(*(--(c)))); \ - case 4: l1 =((unsigned long)(*(--(c))))<<24L; \ - case 3: l1|=((unsigned long)(*(--(c))))<<16L; \ - case 2: l1|=((unsigned long)(*(--(c))))<< 8L; \ - case 1: l1|=((unsigned long)(*(--(c)))); \ + case 8: l2 =((BF_LONG)(*(--(c))))<<24L; \ + case 7: l2|=((BF_LONG)(*(--(c))))<<16L; \ + case 6: l2|=((BF_LONG)(*(--(c))))<< 8L; \ + case 5: l2|=((BF_LONG)(*(--(c)))); \ + case 4: l1 =((BF_LONG)(*(--(c))))<<24L; \ + case 3: l1|=((BF_LONG)(*(--(c))))<<16L; \ + case 2: l1|=((BF_LONG)(*(--(c))))<< 8L; \ + case 1: l1|=((BF_LONG)(*(--(c)))); \ } \ } @@ -113,14 +116,14 @@ c+=n; \ l1=l2=0; \ switch (n) { \ - case 8: l2 =((unsigned long)(*(--(c)))) ; \ - case 7: l2|=((unsigned long)(*(--(c))))<< 8; \ - case 6: l2|=((unsigned long)(*(--(c))))<<16; \ - case 5: l2|=((unsigned long)(*(--(c))))<<24; \ - case 4: l1 =((unsigned long)(*(--(c)))) ; \ - case 3: l1|=((unsigned long)(*(--(c))))<< 8; \ - case 2: l1|=((unsigned long)(*(--(c))))<<16; \ - case 1: l1|=((unsigned long)(*(--(c))))<<24; \ + case 8: l2 =((BF_LONG)(*(--(c)))) ; \ + case 7: l2|=((BF_LONG)(*(--(c))))<< 8; \ + case 6: l2|=((BF_LONG)(*(--(c))))<<16; \ + case 5: l2|=((BF_LONG)(*(--(c))))<<24; \ + case 4: l1 =((BF_LONG)(*(--(c)))) ; \ + case 3: l1|=((BF_LONG)(*(--(c))))<< 8; \ + case 2: l1|=((BF_LONG)(*(--(c))))<<16; \ + case 1: l1|=((BF_LONG)(*(--(c))))<<24; \ } \ } @@ -140,10 +143,10 @@ } #undef n2l -#define n2l(c,l) (l =((unsigned long)(*((c)++)))<<24L, \ - l|=((unsigned long)(*((c)++)))<<16L, \ - l|=((unsigned long)(*((c)++)))<< 8L, \ - l|=((unsigned long)(*((c)++)))) +#define n2l(c,l) (l =((BF_LONG)(*((c)++)))<<24L, \ + l|=((BF_LONG)(*((c)++)))<<16L, \ + l|=((BF_LONG)(*((c)++)))<< 8L, \ + l|=((BF_LONG)(*((c)++)))) #undef l2n #define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>24L)&0xff), \ @@ -158,9 +161,17 @@ * BF_PTR for sparc and MIPS/SGI * use nothing for Alpha and HP. */ -#if !defined(BF_PTR) && !defined(BF_PTR2) -#undef BF_PTR +#undef BF_PTR +#undef BF_PTR2 +#ifdef __NetBSD__ +#ifdef __i386__ +#define BF_PTR2 +#else +#ifdef __mips__ +#define BF_PTR +#endif #endif +#endif /*NetBSD*/ #define BF_M 0x3fc #define BF_0 22L diff --git a/bsd/crypto/blowfish/bf_pi.h b/bsd/crypto/blowfish/bf_pi.h index 560dd1ee8..ae5d7803b 100644 --- a/bsd/crypto/blowfish/bf_pi.h +++ b/bsd/crypto/blowfish/bf_pi.h @@ -1,3 +1,6 @@ +/* $FreeBSD: src/sys/crypto/blowfish/bf_pi.h,v 1.1.2.1 2000/07/15 07:14:18 kris Exp $ */ +/* $KAME: bf_pi.h,v 1.3 2000/03/27 04:36:26 sumikawa Exp $ */ + /* crypto/bf/bf_pi.h */ /* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au) * All rights reserved. diff --git a/bsd/crypto/blowfish/bf_skey.c b/bsd/crypto/blowfish/bf_skey.c index 4515b8454..4dc8e934b 100644 --- a/bsd/crypto/blowfish/bf_skey.c +++ b/bsd/crypto/blowfish/bf_skey.c @@ -1,3 +1,6 @@ +/* $FreeBSD: src/sys/crypto/blowfish/bf_skey.c,v 1.1.2.2 2001/07/03 11:01:28 ume Exp $ */ +/* $KAME: bf_skey.c,v 1.5 2000/11/06 13:58:08 itojun Exp $ */ + /* crypto/bf/bf_skey.c */ /* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au) * All rights reserved. @@ -63,58 +66,55 @@ #include #include -void BF_set_key(key,len,data) -BF_KEY *key; -int len; -unsigned char *data; - { +void +BF_set_key(key, len, data) + BF_KEY *key; + int len; + unsigned char *data; +{ int i; - BF_LONG *p,ri,in[2]; - unsigned char *d,*end; - + BF_LONG *p, ri, in[2]; + unsigned char *d, *end; - memcpy((char *)key,(char *)&bf_init,sizeof(BF_KEY)); - p=key->P; + memcpy((char *)key, (char *)&bf_init, sizeof(BF_KEY)); + p = key->P; - if (len > ((BF_ROUNDS+2)*4)) len=(BF_ROUNDS+2)*4; + if (len > ((BF_ROUNDS + 2) * 4)) + len = (BF_ROUNDS + 2) * 4; - d=data; + d = data; end= &(data[len]); - for (i=0; i<(BF_ROUNDS+2); i++) - { - ri= *(d++); - if (d >= end) d=data; - - ri<<=8; - ri|= *(d++); - if (d >= end) d=data; + for (i = 0; i < BF_ROUNDS + 2; i++) { + ri = *(d++); + if (d >= end) d = data; - ri<<=8; - ri|= *(d++); - if (d >= end) d=data; + ri <<= 8; + ri |= *(d++); + if (d >= end) d = data; - ri<<=8; - ri|= *(d++); - if (d >= end) d=data; + ri <<= 8; + ri |= *(d++); + if (d >= end) d = data; - p[i]^=ri; - } + ri <<= 8; + ri |= *(d++); + if (d >= end) d = data; - in[0]=0L; - in[1]=0L; - for (i=0; i<(BF_ROUNDS+2); i+=2) - { - BF_encrypt(in,key,BF_ENCRYPT); - p[i ]=in[0]; - p[i+1]=in[1]; - } + p[i] ^= ri; + } - p=key->S; - for (i=0; i<4*256; i+=2) - { - BF_encrypt(in,key,BF_ENCRYPT); - p[i ]=in[0]; - p[i+1]=in[1]; - } + in[0] = 0L; + in[1] = 0L; + for (i = 0; i < BF_ROUNDS + 2; i += 2) { + BF_encrypt(in, key, BF_ENCRYPT); + p[i ] = in[0]; + p[i+1] = in[1]; } + p = key->S; + for (i = 0; i < 4 * 256; i += 2) { + BF_encrypt(in, key, BF_ENCRYPT); + p[i ] = in[0]; + p[i+1] = in[1]; + } +} diff --git a/bsd/crypto/blowfish/blowfish.h b/bsd/crypto/blowfish/blowfish.h index 0e5b989e4..fdfd34121 100644 --- a/bsd/crypto/blowfish/blowfish.h +++ b/bsd/crypto/blowfish/blowfish.h @@ -1,3 +1,6 @@ +/* $FreeBSD: src/sys/crypto/blowfish/blowfish.h,v 1.1.2.2 2001/07/03 11:01:28 ume Exp $ */ +/* $KAME: blowfish.h,v 1.10 2000/09/18 21:21:20 itojun Exp $ */ + /* crypto/bf/blowfish.h */ /* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au) * All rights reserved. @@ -66,55 +69,19 @@ extern "C" { #define BF_ENCRYPT 1 #define BF_DECRYPT 0 -/* If you make this 'unsigned int' the pointer variants will work on - * the Alpha, otherwise they will not. Strangly using the '8 byte' - * BF_LONG and the default 'non-pointer' inner loop is the best configuration - * for the Alpha */ -#define BF_LONG unsigned long +/* must be 32bit quantity */ +#define BF_LONG u_int32_t #define BF_ROUNDS 16 #define BF_BLOCK 8 -typedef struct bf_key_st - { +typedef struct bf_key_st { BF_LONG P[BF_ROUNDS+2]; BF_LONG S[4*256]; - } BF_KEY; - -#ifndef NOPROTO - -void BF_set_key(BF_KEY *key, int len, unsigned char *data); -void BF_ecb_encrypt(unsigned char *in,unsigned char *out,BF_KEY *key, - int encrypt); -void BF_encrypt(BF_LONG *data,BF_KEY *key,int encrypt); -void BF_cbc_encrypt(unsigned char *in, unsigned char *out, long length, - BF_KEY *ks, unsigned char *iv, int encrypt); -void BF_cfb64_encrypt(unsigned char *in, unsigned char *out, long length, - BF_KEY *schedule, unsigned char *ivec, int *num, int encrypt); -void BF_ofb64_encrypt(unsigned char *in, unsigned char *out, long length, - BF_KEY *schedule, unsigned char *ivec, int *num); -char *BF_options(void); - -/* added by itojun */ -struct mbuf; -void BF_cbc_encrypt_m(struct mbuf *, int, int, BF_KEY *, - unsigned char *, int); - -#else - -void BF_set_key(); -void BF_ecb_encrypt(); -void BF_encrypt(); -void BF_cbc_encrypt(); -void BF_cfb64_encrypt(); -void BF_ofb64_encrypt(); -char *BF_options(); - -/* added by itojun */ -void BF_cbc_encrypt_m(); - -#endif +} BF_KEY; +void BF_set_key __P((BF_KEY *, int, unsigned char *)); +void BF_encrypt __P((BF_LONG *, BF_KEY *, int)); #ifdef __cplusplus } #endif diff --git a/bsd/crypto/cast128/Makefile b/bsd/crypto/cast128/Makefile index 98869f4e0..d67b89e11 100644 --- a/bsd/crypto/cast128/Makefile +++ b/bsd/crypto/cast128/Makefile @@ -19,17 +19,14 @@ EXPINC_SUBDIRS_PPC = \ EXPINC_SUBDIRS_I386 = \ -DATAFILES = \ - cast128.h cast128_subkey.h - -INSTALL_MI_LIST = ${DATAFILES} +PRIVATE_DATAFILES = \ + cast128.h INSTALL_MI_DIR = crypto -EXPORT_MI_LIST = ${DATAFILES} - -EXPORT_MI_DIR = crypto +EXPORT_MI_DIR = ${INSTALL_MI_DIR} +INSTALL_MI_LCL_KERN_LIST = ${PRIVATE_DATAFILES} include $(MakeInc_rule) include $(MakeInc_dir) diff --git a/bsd/crypto/cast128/cast128.c b/bsd/crypto/cast128/cast128.c index 0d9661f47..84d40ba0b 100644 --- a/bsd/crypto/cast128/cast128.c +++ b/bsd/crypto/cast128/cast128.c @@ -1,3 +1,6 @@ +/* $FreeBSD: src/sys/crypto/cast128/cast128.c,v 1.1.2.3 2001/12/05 05:54:57 ume Exp $ */ +/* $KAME: cast128.c,v 1.5 2001/11/27 09:47:32 sakane Exp $ */ + /* * heavily modified by Tomomi Suzuki */ @@ -52,9 +55,22 @@ static u_int32_t S8[]; /* * Step 1 */ -void set_cast128_subkey(u_int32_t *subkey, u_int8_t *key) +void set_cast128_subkey(u_int32_t *subkey, u_int8_t *key0, int keylen) { u_int32_t buf[8]; /* for x0x1x2x3, x4x5x6x7 ..., z0z1z2z3, ... */ + u_int32_t key[16]; + int i; + + /* + * the key has to be initilized. should it be logged when the key + * length is more than 16 bytes ? anyway, ignore it at this moment. + */ + if (keylen > 16) + keylen = 16; + for (i = 0; i < keylen; i++) + key[i] = key0[i]; + while (i < 16) + key[i++] = 0; buf[0] = (key[ 0] << 24) | (key[ 1] << 16) | (key[ 2] << 8) | key[ 3]; diff --git a/bsd/crypto/cast128/cast128.h b/bsd/crypto/cast128/cast128.h index d05af15ba..2dc90d318 100644 --- a/bsd/crypto/cast128/cast128.h +++ b/bsd/crypto/cast128/cast128.h @@ -1,3 +1,6 @@ +/* $FreeBSD: src/sys/crypto/cast128/cast128.h,v 1.1.2.3 2001/12/05 05:54:57 ume Exp $ */ +/* $KAME: cast128.h,v 1.7 2001/11/27 09:47:32 sakane Exp $ */ + /* * heavily modified by Tomomi Suzuki */ @@ -37,14 +40,13 @@ #define RFC2144_CAST_128_H #include -#include #define CAST128_ENCRYPT 1 #define CAST128_DECRYPT 0 -extern void set_cast128_subkey __P((u_int32_t *, u_int8_t *)); +extern void set_cast128_subkey __P((u_int32_t *, u_int8_t *, int)); extern void cast128_encrypt_round16 __P((u_int8_t *, const u_int8_t *, u_int32_t *)); extern void cast128_decrypt_round16 __P((u_int8_t *, const u_int8_t *, @@ -53,8 +55,5 @@ extern void cast128_encrypt_round12 __P((u_int8_t *, const u_int8_t *, u_int32_t *)); extern void cast128_decrypt_round12 __P((u_int8_t *, const u_int8_t *, u_int32_t *)); -extern void cast128_cbc_process __P((struct mbuf *, size_t, size_t, - u_int32_t *, u_int8_t *, size_t, int)); - #endif diff --git a/bsd/crypto/cast128/cast128_cbc.c b/bsd/crypto/cast128/cast128_cbc.c deleted file mode 100644 index e2d2f6c1c..000000000 --- a/bsd/crypto/cast128/cast128_cbc.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -/* - * based on sys/crypto/des/des_cbc.c, rewrote by Tomomi Suzuki - */ - -#include -#include -#include -#include - - -void -cast128_cbc_process(m0, skip, length, subkey, iv, keylen, mode) - struct mbuf *m0; - size_t skip; - size_t length; - u_int32_t *subkey; - u_int8_t *iv; - size_t keylen; - int mode; -{ - struct mbuf *m; - u_int8_t inbuf[8], outbuf[8]; - size_t off; - - /* sanity check */ - if (m0->m_pkthdr.len < skip) { - printf("cast128_cbc_process: mbuf length < skip\n"); - return; - } - if (m0->m_pkthdr.len < length) { - printf("cast128_cbc_process: mbuf length < encrypt length\n"); - return; - } - if (m0->m_pkthdr.len < skip + length) { - printf("cast128_cbc_process: " - "mbuf length < skip + encrypt length\n"); - return; - } - if (length % 8) { - printf("cast128_cbc_process: length is not multiple of 8\n"); - return; - } - - m = m0; - off = 0; - - /* skip over the header */ - while (skip) { - if (!m) - panic("cast128_cbc_process: mbuf chain?\n"); - if (m->m_len <= skip) { - skip -= m->m_len; - m = m->m_next; - off = 0; - } else { - off = skip; - skip = 0; - } - } - - /* copy iv into outbuf for XOR (encrypt) */ - bcopy(iv, outbuf, 8); - - /* - * encrypt/decrypt packet - */ - while (length > 0) { - int i; - - if (!m) - panic("cast128_cbc_process: mbuf chain?\n"); - - /* - * copy the source into input buffer. - * don't update off or m, since we need to use them - * later. - */ - if (off + 8 <= m->m_len) - bcopy(mtod(m, u_int8_t *)+off, inbuf, 8); - else { - struct mbuf *n; - size_t noff; - u_int8_t *p, *in; - - n = m; - noff = off; - p = mtod(n, u_int8_t *) + noff; - - in = inbuf; - while (in - inbuf < 8) { - if (!p) { - panic("cast128_cbc_process: " - "mbuf chain?\n"); - } - *in++ = *p++; - noff++; - if (noff < n->m_len) - continue; - do { - n = n->m_next; - } while (n && !n->m_len); - noff = 0; - if (n) - p = mtod(n, u_int8_t *); - else - p = NULL; - } - } - - /* encrypt/decrypt */ - switch (mode) { - case CAST128_ENCRYPT: - /* XOR */ - for (i = 0; i < 8; i++) - inbuf[i] ^= outbuf[i]; - - /* encrypt */ - if (keylen <= 80/8) - cast128_encrypt_round12(outbuf, inbuf, subkey); - else - cast128_encrypt_round16(outbuf, inbuf, subkey); - break; - - case CAST128_DECRYPT: - /* decrypt */ - if (keylen <= 80/8) - cast128_decrypt_round12(outbuf, inbuf, subkey); - else - cast128_decrypt_round16(outbuf, inbuf, subkey); - - /* XOR */ - for (i = 0; i < 8; i++) - outbuf[i] ^= iv[i]; - - /* copy inbuf into iv for next XOR */ - bcopy(inbuf, iv, 8); - break; - } - - /* - * copy the output buffer into the result. - * need to update off and m. - */ - if (off + 8 < m->m_len) { - bcopy(outbuf, mtod(m, u_int8_t *) + off, 8); - off += 8; - } else if (off + 8 == m->m_len) { - bcopy(outbuf, mtod(m, u_int8_t *) + off, 8); - do { - m = m->m_next; - } while (m && !m->m_len); - off = 0; - } else { - struct mbuf *n; - size_t noff; - u_int8_t *p, *out; - - n = m; - noff = off; - p = mtod(n, u_int8_t *) + noff; - - out = outbuf; - while (out - outbuf < 8) { - if (!p) { - panic("cast128_cbc_process: " - "mbuf chain?\n"); - } - *p++ = *out++; - noff++; - if (noff < n->m_len) - continue; - do { - n = n->m_next; - } while (n && !n->m_len); - noff = 0; - if (n) - p = mtod(n, u_int8_t *); - else - p = NULL; - } - - m = n; - off = noff; - } - - length -= 8; - } -} - diff --git a/bsd/crypto/cast128/cast128_subkey.h b/bsd/crypto/cast128/cast128_subkey.h index 5f52be30a..d30980385 100644 --- a/bsd/crypto/cast128/cast128_subkey.h +++ b/bsd/crypto/cast128/cast128_subkey.h @@ -1,3 +1,6 @@ +/* $FreeBSD: src/sys/crypto/cast128/cast128_subkey.h,v 1.1.2.1 2000/07/15 07:14:21 kris Exp $ */ +/* $KAME: cast128_subkey.h,v 1.3 2000/03/27 04:36:30 sumikawa Exp $ */ + /* * heavily modified by Tomomi Suzuki */ diff --git a/bsd/crypto/des/Makefile b/bsd/crypto/des/Makefile index 42d04844a..58c13ed5f 100644 --- a/bsd/crypto/des/Makefile +++ b/bsd/crypto/des/Makefile @@ -19,17 +19,14 @@ EXPINC_SUBDIRS_PPC = \ EXPINC_SUBDIRS_I386 = \ -DATAFILES = \ - des.h des_locl.h podd.h sk.h spr.h - -INSTALL_MI_LIST = ${DATAFILES} +PRIVATE_DATAFILES = \ + des.h INSTALL_MI_DIR = crypto -EXPORT_MI_LIST = ${DATAFILES} - -EXPORT_MI_DIR = crypto +EXPORT_MI_DIR = ${INSTALL_MI_DIR} +INSTALL_MI_LCL_KERN_LIST = ${PRIVATE_DATAFILES} include $(MakeInc_rule) include $(MakeInc_dir) diff --git a/bsd/crypto/des/des.h b/bsd/crypto/des/des.h index 144a61e5e..88a4fdc57 100644 --- a/bsd/crypto/des/des.h +++ b/bsd/crypto/des/des.h @@ -1,3 +1,6 @@ +/* $FreeBSD: src/sys/crypto/des/des.h,v 1.1.2.2 2001/07/03 11:01:31 ume Exp $ */ +/* $KAME: des.h,v 1.7 2000/09/18 20:59:21 itojun Exp $ */ + /* lib/des/des.h */ /* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) * All rights reserved. @@ -52,11 +55,8 @@ extern "C" { #endif -/* If this is set to 'unsigned int' on a DEC Alpha, this gives about a - * %20 speed up (longs are 8 bytes, int's are 4). */ -#ifndef DES_LONG -#define DES_LONG unsigned long -#endif +/* must be 32bit quantity */ +#define DES_LONG u_int32_t typedef unsigned char des_cblock[8]; typedef struct des_ks_struct @@ -80,196 +80,18 @@ typedef struct des_ks_struct #define DES_CBC_MODE 0 #define DES_PCBC_MODE 1 -#define des_ecb2_encrypt(i,o,k1,k2,e) \ - des_ecb3_encrypt((i),(o),(k1),(k2),(k1),(e)) - -#define des_ede2_cbc_encrypt(i,o,l,k1,k2,iv,e) \ - des_ede3_cbc_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(e)) - -#define des_ede2_cfb64_encrypt(i,o,l,k1,k2,iv,n,e) \ - des_ede3_cfb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n),(e)) - -#define des_ede2_ofb64_encrypt(i,o,l,k1,k2,iv,n) \ - des_ede3_ofb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n)) - -#define C_Block des_cblock -#define Key_schedule des_key_schedule -#ifdef KERBEROS -#define ENCRYPT DES_ENCRYPT -#define DECRYPT DES_DECRYPT -#endif -#define KEY_SZ DES_KEY_SZ -#define string_to_key des_string_to_key -#define read_pw_string des_read_pw_string -#define random_key des_random_key -#define pcbc_encrypt des_pcbc_encrypt -#define set_key des_set_key -#define key_sched des_key_sched -#define ecb_encrypt des_ecb_encrypt -#define cbc_encrypt des_cbc_encrypt -#define ncbc_encrypt des_ncbc_encrypt -#define xcbc_encrypt des_xcbc_encrypt -#define cbc_cksum des_cbc_cksum -#define quad_cksum des_quad_cksum - -/* For compatibility with the MIT lib - eay 20/05/92 */ -typedef des_key_schedule bit_64; -#define des_fixup_key_parity des_set_odd_parity -#define des_check_key_parity check_parity - extern int des_check_key; /* defaults to false */ -extern int des_rw_mode; /* defaults to DES_PCBC_MODE */ - -/* The next line is used to disable full ANSI prototypes, if your - * compiler has problems with the prototypes, make sure this line always - * evaluates to true :-) */ -#if defined(MSDOS) || defined(__STDC__) -#undef NOPROTO -#endif -#ifndef NOPROTO -char *des_options(void); -void des_ecb3_encrypt(des_cblock *input,des_cblock *output, - des_key_schedule ks1,des_key_schedule ks2, - des_key_schedule ks3, int enc); -DES_LONG des_cbc_cksum(des_cblock *input,des_cblock *output, - long length,des_key_schedule schedule,des_cblock *ivec); -/* -void des_cbc_encrypt(des_cblock *input,des_cblock *output,long length, - des_key_schedule schedule,des_cblock *ivec,int enc); -*/ -void des_cbc_encrypt(struct mbuf *, size_t, size_t, - des_key_schedule schedule,des_cblock *ivec, int enc); -void des_ncbc_encrypt(des_cblock *input,des_cblock *output,long length, - des_key_schedule schedule,des_cblock *ivec,int enc); -void des_xcbc_encrypt(des_cblock *input,des_cblock *output,long length, - des_key_schedule schedule,des_cblock *ivec, - des_cblock *inw,des_cblock *outw,int enc); -void des_3cbc_encrypt(des_cblock *input,des_cblock *output,long length, - des_key_schedule sk1,des_key_schedule sk2, - des_cblock *ivec1,des_cblock *ivec2,int enc); -extern void des_3cbc_process(struct mbuf *, size_t, size_t, - des_key_schedule *schedule, des_cblock *ivec, int mode); -void des_cfb_encrypt(unsigned char *in,unsigned char *out,int numbits, - long length,des_key_schedule schedule,des_cblock *ivec,int enc); -void des_ecb_encrypt(des_cblock *input,des_cblock *output, - des_key_schedule ks,int enc); -void des_encrypt(DES_LONG *data,des_key_schedule ks, int enc); -void des_encrypt2(DES_LONG *data,des_key_schedule ks, int enc); -void des_ede3_cbc_encrypt(des_cblock *input, des_cblock *output, - long length, des_key_schedule ks1, des_key_schedule ks2, - des_key_schedule ks3, des_cblock *ivec, int enc); -void des_ede3_cfb64_encrypt(unsigned char *in, unsigned char *out, - long length, des_key_schedule ks1, des_key_schedule ks2, - des_key_schedule ks3, des_cblock *ivec, int *num, int encrypt); -void des_ede3_ofb64_encrypt(unsigned char *in, unsigned char *out, - long length, des_key_schedule ks1, des_key_schedule ks2, - des_key_schedule ks3, des_cblock *ivec, int *num); - -int des_enc_read(int fd,char *buf,int len,des_key_schedule sched, - des_cblock *iv); -int des_enc_write(int fd,char *buf,int len,des_key_schedule sched, - des_cblock *iv); -#ifdef PERL5 -char *des_crypt(const char *buf,const char *salt); -#else -/* some stupid compilers complain because I have declared char instead - * of const char */ -#if 1 -char *crypt(const char *buf,const char *salt); -#else -char *crypt(); -#endif -#endif -void des_ofb_encrypt(unsigned char *in,unsigned char *out, - int numbits,long length,des_key_schedule schedule,des_cblock *ivec); -void des_pcbc_encrypt(des_cblock *input,des_cblock *output,long length, - des_key_schedule schedule,des_cblock *ivec,int enc); -DES_LONG des_quad_cksum(des_cblock *input,des_cblock *output, - long length,int out_count,des_cblock *seed); -void des_random_seed(des_cblock key); -void des_random_key(des_cblock ret); -int des_read_password(des_cblock *key,char *prompt,int verify); -int des_read_2passwords(des_cblock *key1,des_cblock *key2, - char *prompt,int verify); -int des_read_pw_string(char *buf,int length,char *prompt,int verify); -void des_set_odd_parity(des_cblock *key); -int des_is_weak_key(des_cblock *key); -int des_set_key(des_cblock *key,des_key_schedule schedule); -int des_key_sched(des_cblock *key,des_key_schedule schedule); -void des_string_to_key(char *str,des_cblock *key); -void des_string_to_2keys(char *str,des_cblock *key1,des_cblock *key2); -void des_cfb64_encrypt(unsigned char *in, unsigned char *out, long length, - des_key_schedule schedule, des_cblock *ivec, int *num, int enc); -void des_ofb64_encrypt(unsigned char *in, unsigned char *out, long length, - des_key_schedule schedule, des_cblock *ivec, int *num); - -/* Extra functions from Mark Murray */ -/* -void des_cblock_print_file(des_cblock *cb, FILE *fp); -*/ -/* The following functions are not in the normal unix build or the - * SSLeay build. When using the SSLeay build, use RAND_seed() - * and RAND_bytes() instead. */ -int des_new_random_key(des_cblock *key); -void des_init_random_number_generator(des_cblock *key); -void des_set_random_generator_seed(des_cblock *key); -void des_set_sequence_number(des_cblock new_sequence_number); -void des_generate_random_block(des_cblock *block); -#else +char *des_options __P((void)); +void des_ecb_encrypt __P((des_cblock *, des_cblock *, + des_key_schedule, int)); +void des_encrypt __P((DES_LONG *, des_key_schedule, int)); +void des_encrypt2 __P((DES_LONG *, des_key_schedule, int)); -char *des_options(); -void des_ecb3_encrypt(); -DES_LONG des_cbc_cksum(); -void des_cbc_encrypt(); -void des_ncbc_encrypt(); -void des_xcbc_encrypt(); -void des_3cbc_encrypt(); -void des_cfb_encrypt(); -void des_ede3_cfb64_encrypt(); -void des_ede3_ofb64_encrypt(); -void des_ecb_encrypt(); -void des_encrypt(); -void des_encrypt2(); -void des_ede3_cbc_encrypt(); -int des_enc_read(); -int des_enc_write(); -#ifdef PERL5 -char *des_crypt(); -#else -char *crypt(); -#endif -void des_ofb_encrypt(); -void des_pcbc_encrypt(); -DES_LONG des_quad_cksum(); -void des_random_seed(); -void des_random_key(); -int des_read_password(); -int des_read_2passwords(); -int des_read_pw_string(); -void des_set_odd_parity(); -int des_is_weak_key(); -int des_set_key(); -int des_key_sched(); -void des_string_to_key(); -void des_string_to_2keys(); -void des_cfb64_encrypt(); -void des_ofb64_encrypt(); - -/* Extra functions from Mark Murray */ -void des_cblock_print_file(); -/* The following functions are not in the normal unix build or the - * SSLeay build. When using the SSLeay build, use RAND_seed() - * and RAND_bytes() instead. */ -#ifdef FreeBSD -int des_new_random_key(); -void des_init_random_number_generator(); -void des_set_random_generator_seed(); -void des_set_sequence_number(); -void des_generate_random_block(); -#endif - -#endif +void des_set_odd_parity __P((des_cblock *)); +int des_is_weak_key __P((des_cblock *)); +int des_set_key __P((des_cblock *, des_key_schedule)); +int des_key_sched __P((des_cblock *, des_key_schedule)); #ifdef __cplusplus } diff --git a/bsd/crypto/des/des_3cbc.c b/bsd/crypto/des/des_3cbc.c deleted file mode 100644 index 9d63a63de..000000000 --- a/bsd/crypto/des/des_3cbc.c +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -/* - * based on sys/crypto/des/des_cbc.c, rewrote by Tomomi Suzuki - */ -#include - - -void des_3cbc_process(m0, skip, length, schedule, ivec, mode) - struct mbuf *m0; - size_t skip; - size_t length; - des_key_schedule *schedule; - des_cblock (*ivec); - int mode; -{ - u_int8_t inbuf[8], outbuf[8]; - struct mbuf *m; - size_t off; - DES_LONG tin0, tin1; - DES_LONG tout0, tout1; - DES_LONG tin[2]; - DES_LONG xor0 = 0, xor1 = 0; - u_int8_t *iv; - u_int8_t *in, *out; - - /* sanity check */ - if (m0->m_pkthdr.len < skip) { - printf("des_3cbc_process: mbuf length < skip\n"); - return; - } - if (m0->m_pkthdr.len < length) { - printf("des_3cbc_process: mbuf length < encrypt length\n"); - return; - } - if (m0->m_pkthdr.len < skip + length) { - printf("des_3cbc_process: mbuf length < " - "skip + encrypt length\n"); - return; - } - if (length % 8) { - printf("des_3cbc_process: length(%lu) is not multiple of 8\n", - (u_long)length); - return; - } - - m = m0; - off = 0; - - /* skip over the header */ - while (skip) { - if (!m) - panic("des_3cbc_process: mbuf chain?\n"); - if (m->m_len <= skip) { - skip -= m->m_len; - m = m->m_next; - off = 0; - } else { - off = skip; - skip = 0; - } - } - - /* initialize */ - tin0 = tin1 = tout0 = tout1 = 0; - tin[0] = tin[1] = 0; - - switch (mode) { - case DES_ENCRYPT: - iv = (u_int8_t *)ivec; - c2l(iv, tout0); - c2l(iv, tout1); - break; - case DES_DECRYPT: - xor0 = xor1 = 0; - iv = (u_int8_t *)ivec; - c2l(iv, xor0); - c2l(iv, xor1); - break; - } - - /* - * encrypt/decrypt packet - */ - while (length > 0) { - if (!m) - panic("des_3cbc_process: mbuf chain?\n"); - - /* - * copy the source into input buffer. - * don't update off or m, since we need to use them - * later. - */ - if (off + 8 <= m->m_len) - bcopy(mtod(m, u_int8_t *) + off, &inbuf[0], 8); - else { - struct mbuf *n; - size_t noff; - u_int8_t *p; - u_int8_t *in; - - n = m; - noff = off; - p = mtod(n, u_int8_t *) + noff; - - in = &inbuf[0]; - while (in - &inbuf[0] < 8) { - if (!p) { - panic("des_3cbc_process: " - "mbuf chain?\n"); - } - *in++ = *p++; - noff++; - if (noff < n->m_len) - continue; - do { - n = n->m_next; - } while (n && !n->m_len); - noff = 0; - if (n) - p = mtod(n, u_int8_t *) + noff; - else - p = NULL; - } - } - - /* encrypt/decrypt */ - switch (mode) { - case DES_ENCRYPT: - in = &inbuf[0]; - out = &outbuf[0]; - c2l(in, tin0); - c2l(in, tin1); - - /* XOR */ - tin0 ^= tout0; tin[0] = tin0; - tin1 ^= tout1; tin[1] = tin1; - - des_encrypt((DES_LONG *)tin, schedule[0], DES_ENCRYPT); - des_encrypt((DES_LONG *)tin, schedule[1], DES_DECRYPT); - des_encrypt((DES_LONG *)tin, schedule[2], DES_ENCRYPT); - - tout0 = tin[0]; l2c(tout0, out); - tout1 = tin[1]; l2c(tout1, out); - break; - case DES_DECRYPT: - in = &inbuf[0]; - out = &outbuf[0]; - c2l(in, tin0); tin[0] = tin0; - c2l(in, tin1); tin[1] = tin1; - - des_encrypt((DES_LONG *)tin, schedule[2], DES_DECRYPT); - des_encrypt((DES_LONG *)tin, schedule[1], DES_ENCRYPT); - des_encrypt((DES_LONG *)tin, schedule[0], DES_DECRYPT); - - /* XOR */ - tout0 = tin[0] ^ xor0; - tout1 = tin[1] ^ xor1; - l2c(tout0, out); - l2c(tout1, out); - - /* for next iv */ - xor0 = tin0; - xor1 = tin1; - break; - } - - /* - * copy the output buffer int the result. - * need to update off and m. - */ - if (off + 8 < m->m_len) { - bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); - off += 8; - } else if (off + 8 == m->m_len) { - bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); - do { - m = m->m_next; - } while (m && !m->m_len); - off = 0; - } else { - struct mbuf *n; - size_t noff; - u_int8_t *p; - u_int8_t *out; - - n = m; - noff = off; - p = mtod(n, u_int8_t *) + noff; - - out = &outbuf[0]; - while (out - &outbuf[0] < 8) { - if (!p) { - panic("des_3cbc_process: " - "mbuf chain?\n"); - } - *p++ = *out++; - noff++; - if (noff < n->m_len) - continue; - do { - n = n->m_next; - } while (n && !n->m_len); - noff = 0; - if (n) - p = mtod(n, u_int8_t *) + noff; - else - p = NULL; - } - - m = n; - off = noff; - } - - length -= 8; - } -} - diff --git a/bsd/crypto/des/des_cbc.c b/bsd/crypto/des/des_cbc.c deleted file mode 100644 index 657cf4bd9..000000000 --- a/bsd/crypto/des/des_cbc.c +++ /dev/null @@ -1,326 +0,0 @@ -/* - * heavily modified by Yoshifumi Nishida . - * then, completely rewrote by Jun-ichiro itojun Itoh , - * 1997. - */ -/* crypto/des/cbc_enc.c */ -/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) - * All rights reserved. - * - * This file is part of an SSL implementation written - * by Eric Young (eay@mincom.oz.au). - * The implementation was written so as to conform with Netscapes SSL - * specification. This library and applications are - * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE - * as long as the following conditions are aheared to. - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. If this code is used in a product, - * Eric Young should be given attribution as the author of the parts used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Eric Young (eay@mincom.oz.au) - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ - -#include - -#define panic(x) {printf(x); return;} - -void des_cbc_encrypt(m0, skip, length, schedule, ivec, mode) - struct mbuf *m0; - size_t skip; - size_t length; - des_key_schedule schedule; - des_cblock (*ivec); - int mode; -{ - u_int8_t inbuf[8], outbuf[8]; - struct mbuf *m; - size_t off; - register DES_LONG tin0, tin1; - register DES_LONG tout0, tout1; - DES_LONG tin[2]; - u_int8_t *iv; - - /* sanity checks */ - if (m0->m_pkthdr.len < skip) { - printf("mbuf length < skip\n"); - return; - } - if (m0->m_pkthdr.len < length) { - printf("mbuf length < encrypt length\n"); - return; - } - if (m0->m_pkthdr.len < skip + length) { - printf("mbuf length < skip + encrypt length\n"); - return; - } - if (length % 8) { - printf("length is not multiple of 8\n"); - return; - } - - m = m0; - off = 0; - - /* skip over the header */ - while (skip) { - if (!m) - panic("mbuf chain?\n"); - if (m->m_len <= skip) { - skip -= m->m_len; - m = m->m_next; - off = 0; - } else { - off = skip; - skip = 0; - } - } - - /* initialize */ - tin0 = tin1 = tout0 = tout1 = 0; - tin[0] = tin[1] = 0; - - if (mode == DES_ENCRYPT) { - u_int8_t *in, *out; - - iv = (u_int8_t *)ivec; - c2l(iv, tout0); - c2l(iv, tout1); - - while (0 < length) { - if (!m) - panic("mbuf chain?\n"); - - /* - * copy the source into input buffer. - * don't update off or m, since we need to use them * later. - */ - if (off + 8 <= m->m_len) - bcopy(mtod(m, u_int8_t *) + off, &inbuf[0], 8); - else { - struct mbuf *n; - size_t noff; - u_int8_t *p; - u_int8_t *in; - - n = m; - noff = off; - p = mtod(n, u_int8_t *) + noff; - - in = &inbuf[0]; - while (in - &inbuf[0] < 8) { - if (!p) - panic("mbuf chain?\n"); - - *in++ = *p++; - noff++; - if (noff < n->m_len) - continue; - do { - n = n->m_next; - } while (n && ! n->m_len); - noff = 0; - if (n) - p = mtod(n, u_int8_t *) + noff; - else - p = NULL; - } - } - - in = &inbuf[0]; - out = &outbuf[0]; - c2l(in, tin0); - c2l(in, tin1); - - tin0 ^= tout0; tin[0] = tin0; - tin1 ^= tout1; tin[1] = tin1; - des_encrypt((DES_LONG *)tin, schedule, DES_ENCRYPT); - tout0 = tin[0]; l2c(tout0, out); - tout1 = tin[1]; l2c(tout1, out); - - /* - * copy the output buffer into the result. - * need to update off and m. - */ - if (off + 8 < m->m_len) { - bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); - off += 8; - } else if (off + 8 == m->m_len) { - bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); - do { - m = m->m_next; - } while (m && ! m->m_len); - off = 0; - } else { - struct mbuf *n; - size_t noff; - u_int8_t *p; - u_int8_t *out; - - n = m; - noff = off; - p = mtod(n, u_int8_t *) + noff; - - out = &outbuf[0]; - while (out - &outbuf[0] < 8) { - if (!p) - panic("mbuf chain?"); - *p++ = *out++; - noff++; - if (noff < n->m_len) - continue; - do { - n = n->m_next; - } while (n && ! n->m_len); - noff = 0; - if (n) - p = mtod(n, u_int8_t *) + noff; - else - p = NULL; - } - - m = n; - off = noff; - } - - length -= 8; - } - } else if (mode == DES_DECRYPT) { - register DES_LONG xor0, xor1; - u_int8_t *in, *out; - - xor0 = xor1 = 0; - iv = (u_int8_t *)ivec; - c2l(iv, xor0); - c2l(iv, xor1); - - while (0 < length) { - if (!m) - panic("mbuf chain?\n"); - - /* - * copy the source into input buffer. - * don't update off or m, since we need to use them * later. - */ - if (off + 8 <= m->m_len) - bcopy(mtod(m, u_int8_t *) + off, &inbuf[0], 8); - else { - struct mbuf *n; - size_t noff; - u_int8_t *p; - u_int8_t *in; - - n = m; - noff = off; - p = mtod(n, u_int8_t *) + noff; - - in = &inbuf[0]; - while (in - &inbuf[0] < 8) { - if (!p) - panic("mbuf chain?\n"); - *in++ = *p++; - noff++; - if (noff < n->m_len) - continue; - do { - n = n->m_next; - } while (n && ! n->m_len); - noff = 0; - if (n) - p = mtod(n, u_int8_t *) + noff; - else - p = NULL; - } - } - - in = &inbuf[0]; - out = &outbuf[0]; - c2l(in, tin0); tin[0] = tin0; - c2l(in, tin1); tin[1] = tin1; - des_encrypt((DES_LONG *)tin, schedule, DES_DECRYPT); - tout0 = tin[0] ^ xor0; - tout1 = tin[1] ^ xor1; - l2c(tout0, out); - l2c(tout1, out); - xor0 = tin0; - xor1 = tin1; - - - /* - * copy the output buffer into the result. - * need to update off and m. - */ - if (off + 8 < m->m_len) { - bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); - off += 8; - } else if (off + 8 == m->m_len) { - bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); - do { - m = m->m_next; - } while (m && ! m->m_len); - off = 0; - } else { - struct mbuf *n; - size_t noff; - u_int8_t *p; - u_int8_t *out; - - n = m; - noff = off; - p = mtod(n, u_int8_t *) + noff; - - out = &outbuf[0]; - while (out - &outbuf[0] < 8) { - if (!p) - panic("mbuf chain?\n"); - *p++ = *out++; - noff++; - if (noff < n->m_len) - continue; - do { - n = n->m_next; - } while (n && ! n->m_len); - noff = 0; - if (n) - p = mtod(n, u_int8_t *) + noff; - else - p = NULL; - } - - m = n; - off = noff; - } - - length -= 8; - } - } -} diff --git a/bsd/crypto/des/des_ecb.c b/bsd/crypto/des/des_ecb.c index b0c239ac8..2ff242ebf 100644 --- a/bsd/crypto/des/des_ecb.c +++ b/bsd/crypto/des/des_ecb.c @@ -1,3 +1,6 @@ +/* $FreeBSD: src/sys/crypto/des/des_ecb.c,v 1.1.2.2 2001/07/03 11:01:31 ume Exp $ */ +/* $KAME: des_ecb.c,v 1.5 2000/11/06 13:58:08 itojun Exp $ */ + /* crypto/des/ecb_enc.c */ /* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) * All rights reserved. @@ -45,6 +48,8 @@ * [including the GNU Public Licence.] */ +#include +#include #include #include diff --git a/bsd/crypto/des/des_locl.h b/bsd/crypto/des/des_locl.h index 8f33ab7a1..2f8ed9275 100644 --- a/bsd/crypto/des/des_locl.h +++ b/bsd/crypto/des/des_locl.h @@ -1,3 +1,6 @@ +/* $FreeBSD: src/sys/crypto/des/des_locl.h,v 1.2.2.2 2001/07/03 11:01:31 ume Exp $ */ +/* $KAME: des_locl.h,v 1.6 2000/11/06 13:58:09 itojun Exp $ */ + /* lib/des/des_locl.h */ /* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) * All rights reserved. @@ -52,77 +55,17 @@ * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING */ -#include -#include -#include -#include - #ifndef HEADER_DES_LOCL_H #define HEADER_DES_LOCL_H -#if defined(WIN32) || defined(WIN16) -#ifndef MSDOS -#define MSDOS -#endif -#endif - -/* -#include -#include -#ifndef MSDOS -#include -#endif -*/ #include -/* the following is tweaked from a config script, that is why it is a - * protected undef/define */ -#ifndef DES_PTR #undef DES_PTR -#endif - -#ifdef MSDOS /* Visual C++ 2.1 (Windows NT/95) */ -#include -#include -#include -#include -#ifndef RAND -#define RAND -#endif -#undef NOPROTO -#endif - -#if !defined(KERNEL) && (defined(__STDC__) || defined(VMS) || defined(M_XENIX) || defined(MSDOS)) -#include -#endif - -#ifndef RAND -#define RAND -#endif - -#ifdef linux -#undef RAND -#endif - -#ifdef MSDOS -#define getpid() 2 -#define RAND -#undef NOPROTO -#endif - -#if defined(NOCONST) -#define const -#endif #ifdef __STDC__ #undef NOPROTO #endif -#ifdef RAND -#define srandom(s) srand(s) -#define random rand -#endif - #define ITERATIONS 16 #define HALF_ITERATIONS 8 @@ -185,11 +128,7 @@ } \ } -#if defined(WIN32) -#define ROTATE(a,n) (_lrotr(a,n)) -#else #define ROTATE(a,n) (((a)>>(n))+((a)<<(32-(n)))) -#endif /* The changes to this macro may help or hinder, depending on the * compiler and the achitecture. gcc2 always seems to do well :-). @@ -304,36 +243,3 @@ PERM_OP(l,r,tt, 4,0x0f0f0f0fL); \ } #endif - - -/* -#define mbuf2char(i_mbuf, i_index, in) \ - { \ - register int i; \ - struct mbuf *m; \ - char *buf; \ - m = i_mbuf; \ - for (i = 0; i < 8; i ++){ \ - if (i_index + i == m->m_len){ \ - m = m->m_next; \ - } \ - buf = mtod(m, char *); \ - in[i] = *(buf + i); \ - } - - -#define char2mbuf(o_mbuf, o_index, out) \ - { \ - register int i; \ - struct mbuf *m; \ - char *buf; \ - m = o_mbuf; \ - for (i = 0; i < 8; i ++){ \ - if (i_index + i == m->m_len){ \ - m = m->m_next; \ - } \ - buf = mtod(m, char *); \ - *(buf + i) = out[i]; \ - } -*/ - diff --git a/bsd/crypto/des/des_setkey.c b/bsd/crypto/des/des_setkey.c index 4656c960f..72b4d1a48 100644 --- a/bsd/crypto/des/des_setkey.c +++ b/bsd/crypto/des/des_setkey.c @@ -1,3 +1,6 @@ +/* $FreeBSD: src/sys/crypto/des/des_setkey.c,v 1.1.2.3 2001/07/10 09:46:35 ume Exp $ */ +/* $KAME: des_setkey.c,v 1.6 2001/07/03 14:27:53 itojun Exp $ */ + /* crypto/des/set_key.c */ /* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) * All rights reserved. @@ -52,15 +55,13 @@ * 1.1 added norm_expand_bits * 1.0 First working version */ +#include +#include #include #include #include -#ifndef NOPROTO -static int check_parity(des_cblock (*key)); -#else -static int check_parity(); -#endif +static int check_parity __P((des_cblock (*))); int des_check_key=0; @@ -126,10 +127,7 @@ des_cblock (*key); * this section very often :-(, thanks to * engineering@MorningStar.Com for the fix * eay 93/06/29 */ -/* - if (memcmp(weak_keys[i],key,sizeof(key)) == 0) return(1); -*/ - if (bcmp(weak_keys[i],key,sizeof(key)) == 0) return(1); + if (bcmp(weak_keys[i],key,sizeof(*key)) == 0) return(1); return(0); } diff --git a/bsd/crypto/des/podd.h b/bsd/crypto/des/podd.h index 5093bc6bb..61646cc4b 100644 --- a/bsd/crypto/des/podd.h +++ b/bsd/crypto/des/podd.h @@ -1,3 +1,6 @@ +/* $FreeBSD: src/sys/crypto/des/podd.h,v 1.1.2.1 2000/07/15 07:14:21 kris Exp $ */ +/* $KAME: podd.h,v 1.3 2000/03/27 04:36:34 sumikawa Exp $ */ + /* crypto/des/podd.h */ /* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) * All rights reserved. diff --git a/bsd/crypto/des/sk.h b/bsd/crypto/des/sk.h index db354ce9d..6009c114a 100644 --- a/bsd/crypto/des/sk.h +++ b/bsd/crypto/des/sk.h @@ -1,3 +1,6 @@ +/* $FreeBSD: src/sys/crypto/des/sk.h,v 1.1.2.1 2000/07/15 07:14:21 kris Exp $ */ +/* $KAME: sk.h,v 1.3 2000/03/27 04:36:34 sumikawa Exp $ */ + /* crypto/des/sk.h */ /* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) * All rights reserved. diff --git a/bsd/crypto/des/spr.h b/bsd/crypto/des/spr.h index ebe9007f2..21dea800c 100644 --- a/bsd/crypto/des/spr.h +++ b/bsd/crypto/des/spr.h @@ -1,3 +1,6 @@ +/* $FreeBSD: src/sys/crypto/des/spr.h,v 1.1.2.1 2000/07/15 07:14:22 kris Exp $ */ +/* $KAME: spr.h,v 1.3 2000/03/27 04:36:35 sumikawa Exp $ */ + /* crypto/des/spr.h */ /* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) * All rights reserved. diff --git a/bsd/crypto/md5.c b/bsd/crypto/md5.c new file mode 100644 index 000000000..6fd600bd9 --- /dev/null +++ b/bsd/crypto/md5.c @@ -0,0 +1,308 @@ +/* $FreeBSD: src/sys/crypto/md5.c,v 1.1.2.2 2001/07/03 11:01:27 ume Exp $ */ +/* $KAME: md5.c,v 1.5 2000/11/08 06:13:08 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#define SHIFT(X, s) (((X) << (s)) | ((X) >> (32 - (s)))) + +#define F(X, Y, Z) (((X) & (Y)) | ((~X) & (Z))) +#define G(X, Y, Z) (((X) & (Z)) | ((Y) & (~Z))) +#define H(X, Y, Z) ((X) ^ (Y) ^ (Z)) +#define I(X, Y, Z) ((Y) ^ ((X) | (~Z))) + +#define ROUND1(a, b, c, d, k, s, i) { \ + (a) = (a) + F((b), (c), (d)) + X[(k)] + T[(i)]; \ + (a) = SHIFT((a), (s)); \ + (a) = (b) + (a); \ +} + +#define ROUND2(a, b, c, d, k, s, i) { \ + (a) = (a) + G((b), (c), (d)) + X[(k)] + T[(i)]; \ + (a) = SHIFT((a), (s)); \ + (a) = (b) + (a); \ +} + +#define ROUND3(a, b, c, d, k, s, i) { \ + (a) = (a) + H((b), (c), (d)) + X[(k)] + T[(i)]; \ + (a) = SHIFT((a), (s)); \ + (a) = (b) + (a); \ +} + +#define ROUND4(a, b, c, d, k, s, i) { \ + (a) = (a) + I((b), (c), (d)) + X[(k)] + T[(i)]; \ + (a) = SHIFT((a), (s)); \ + (a) = (b) + (a); \ +} + +#define Sa 7 +#define Sb 12 +#define Sc 17 +#define Sd 22 + +#define Se 5 +#define Sf 9 +#define Sg 14 +#define Sh 20 + +#define Si 4 +#define Sj 11 +#define Sk 16 +#define Sl 23 + +#define Sm 6 +#define Sn 10 +#define So 15 +#define Sp 21 + +#define MD5_A0 0x67452301 +#define MD5_B0 0xefcdab89 +#define MD5_C0 0x98badcfe +#define MD5_D0 0x10325476 + +/* Integer part of 4294967296 times abs(sin(i)), where i is in radians. */ +static const u_int32_t T[65] = { + 0, + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, +}; + +static const u_int8_t md5_paddat[MD5_BUFLEN] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static void md5_calc __P((u_int8_t *, md5_ctxt *)); + +void md5_init(ctxt) + md5_ctxt *ctxt; +{ + ctxt->md5_n = 0; + ctxt->md5_i = 0; + ctxt->md5_sta = MD5_A0; + ctxt->md5_stb = MD5_B0; + ctxt->md5_stc = MD5_C0; + ctxt->md5_std = MD5_D0; + bzero(ctxt->md5_buf, sizeof(ctxt->md5_buf)); +} + +void md5_loop(ctxt, input, len) + md5_ctxt *ctxt; + u_int8_t *input; + u_int len; /* number of bytes */ +{ + u_int gap, i; + + ctxt->md5_n += len * 8; /* byte to bit */ + gap = MD5_BUFLEN - ctxt->md5_i; + + if (len >= gap) { + bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i), + gap); + md5_calc(ctxt->md5_buf, ctxt); + + for (i = gap; i + MD5_BUFLEN <= len; i += MD5_BUFLEN) { + md5_calc((u_int8_t *)(input + i), ctxt); + } + + ctxt->md5_i = len - i; + bcopy((void *)(input + i), (void *)ctxt->md5_buf, ctxt->md5_i); + } else { + bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i), + len); + ctxt->md5_i += len; + } +} + +void md5_pad(ctxt) + md5_ctxt *ctxt; +{ + u_int gap; + + /* Don't count up padding. Keep md5_n. */ + gap = MD5_BUFLEN - ctxt->md5_i; + if (gap > 8) { + bcopy((void *)md5_paddat, + (void *)(ctxt->md5_buf + ctxt->md5_i), + gap - sizeof(ctxt->md5_n)); + } else { + /* including gap == 8 */ + bcopy((void *)md5_paddat, (void *)(ctxt->md5_buf + ctxt->md5_i), + gap); + md5_calc(ctxt->md5_buf, ctxt); + bcopy((void *)(md5_paddat + gap), + (void *)ctxt->md5_buf, + MD5_BUFLEN - sizeof(ctxt->md5_n)); + } + + /* 8 byte word */ +#if BYTE_ORDER == LITTLE_ENDIAN + bcopy(&ctxt->md5_n8[0], &ctxt->md5_buf[56], 8); +#endif +#if BYTE_ORDER == BIG_ENDIAN + ctxt->md5_buf[56] = ctxt->md5_n8[7]; + ctxt->md5_buf[57] = ctxt->md5_n8[6]; + ctxt->md5_buf[58] = ctxt->md5_n8[5]; + ctxt->md5_buf[59] = ctxt->md5_n8[4]; + ctxt->md5_buf[60] = ctxt->md5_n8[3]; + ctxt->md5_buf[61] = ctxt->md5_n8[2]; + ctxt->md5_buf[62] = ctxt->md5_n8[1]; + ctxt->md5_buf[63] = ctxt->md5_n8[0]; +#endif + + md5_calc(ctxt->md5_buf, ctxt); +} + +void md5_result(digest, ctxt) + u_int8_t *digest; + md5_ctxt *ctxt; +{ + /* 4 byte words */ +#if BYTE_ORDER == LITTLE_ENDIAN + bcopy(&ctxt->md5_st8[0], digest, 16); +#endif +#if BYTE_ORDER == BIG_ENDIAN + digest[ 0] = ctxt->md5_st8[ 3]; digest[ 1] = ctxt->md5_st8[ 2]; + digest[ 2] = ctxt->md5_st8[ 1]; digest[ 3] = ctxt->md5_st8[ 0]; + digest[ 4] = ctxt->md5_st8[ 7]; digest[ 5] = ctxt->md5_st8[ 6]; + digest[ 6] = ctxt->md5_st8[ 5]; digest[ 7] = ctxt->md5_st8[ 4]; + digest[ 8] = ctxt->md5_st8[11]; digest[ 9] = ctxt->md5_st8[10]; + digest[10] = ctxt->md5_st8[ 9]; digest[11] = ctxt->md5_st8[ 8]; + digest[12] = ctxt->md5_st8[15]; digest[13] = ctxt->md5_st8[14]; + digest[14] = ctxt->md5_st8[13]; digest[15] = ctxt->md5_st8[12]; +#endif +} + +#if BYTE_ORDER == BIG_ENDIAN +u_int32_t X[16]; +#endif + +static void md5_calc(b64, ctxt) + u_int8_t *b64; + md5_ctxt *ctxt; +{ + u_int32_t A = ctxt->md5_sta; + u_int32_t B = ctxt->md5_stb; + u_int32_t C = ctxt->md5_stc; + u_int32_t D = ctxt->md5_std; +#if BYTE_ORDER == LITTLE_ENDIAN + u_int32_t *X = (u_int32_t *)b64; +#endif +#if BYTE_ORDER == BIG_ENDIAN + /* 4 byte words */ + /* what a brute force but fast! */ + u_int8_t *y = (u_int8_t *)X; + y[ 0] = b64[ 3]; y[ 1] = b64[ 2]; y[ 2] = b64[ 1]; y[ 3] = b64[ 0]; + y[ 4] = b64[ 7]; y[ 5] = b64[ 6]; y[ 6] = b64[ 5]; y[ 7] = b64[ 4]; + y[ 8] = b64[11]; y[ 9] = b64[10]; y[10] = b64[ 9]; y[11] = b64[ 8]; + y[12] = b64[15]; y[13] = b64[14]; y[14] = b64[13]; y[15] = b64[12]; + y[16] = b64[19]; y[17] = b64[18]; y[18] = b64[17]; y[19] = b64[16]; + y[20] = b64[23]; y[21] = b64[22]; y[22] = b64[21]; y[23] = b64[20]; + y[24] = b64[27]; y[25] = b64[26]; y[26] = b64[25]; y[27] = b64[24]; + y[28] = b64[31]; y[29] = b64[30]; y[30] = b64[29]; y[31] = b64[28]; + y[32] = b64[35]; y[33] = b64[34]; y[34] = b64[33]; y[35] = b64[32]; + y[36] = b64[39]; y[37] = b64[38]; y[38] = b64[37]; y[39] = b64[36]; + y[40] = b64[43]; y[41] = b64[42]; y[42] = b64[41]; y[43] = b64[40]; + y[44] = b64[47]; y[45] = b64[46]; y[46] = b64[45]; y[47] = b64[44]; + y[48] = b64[51]; y[49] = b64[50]; y[50] = b64[49]; y[51] = b64[48]; + y[52] = b64[55]; y[53] = b64[54]; y[54] = b64[53]; y[55] = b64[52]; + y[56] = b64[59]; y[57] = b64[58]; y[58] = b64[57]; y[59] = b64[56]; + y[60] = b64[63]; y[61] = b64[62]; y[62] = b64[61]; y[63] = b64[60]; +#endif + + ROUND1(A, B, C, D, 0, Sa, 1); ROUND1(D, A, B, C, 1, Sb, 2); + ROUND1(C, D, A, B, 2, Sc, 3); ROUND1(B, C, D, A, 3, Sd, 4); + ROUND1(A, B, C, D, 4, Sa, 5); ROUND1(D, A, B, C, 5, Sb, 6); + ROUND1(C, D, A, B, 6, Sc, 7); ROUND1(B, C, D, A, 7, Sd, 8); + ROUND1(A, B, C, D, 8, Sa, 9); ROUND1(D, A, B, C, 9, Sb, 10); + ROUND1(C, D, A, B, 10, Sc, 11); ROUND1(B, C, D, A, 11, Sd, 12); + ROUND1(A, B, C, D, 12, Sa, 13); ROUND1(D, A, B, C, 13, Sb, 14); + ROUND1(C, D, A, B, 14, Sc, 15); ROUND1(B, C, D, A, 15, Sd, 16); + + ROUND2(A, B, C, D, 1, Se, 17); ROUND2(D, A, B, C, 6, Sf, 18); + ROUND2(C, D, A, B, 11, Sg, 19); ROUND2(B, C, D, A, 0, Sh, 20); + ROUND2(A, B, C, D, 5, Se, 21); ROUND2(D, A, B, C, 10, Sf, 22); + ROUND2(C, D, A, B, 15, Sg, 23); ROUND2(B, C, D, A, 4, Sh, 24); + ROUND2(A, B, C, D, 9, Se, 25); ROUND2(D, A, B, C, 14, Sf, 26); + ROUND2(C, D, A, B, 3, Sg, 27); ROUND2(B, C, D, A, 8, Sh, 28); + ROUND2(A, B, C, D, 13, Se, 29); ROUND2(D, A, B, C, 2, Sf, 30); + ROUND2(C, D, A, B, 7, Sg, 31); ROUND2(B, C, D, A, 12, Sh, 32); + + ROUND3(A, B, C, D, 5, Si, 33); ROUND3(D, A, B, C, 8, Sj, 34); + ROUND3(C, D, A, B, 11, Sk, 35); ROUND3(B, C, D, A, 14, Sl, 36); + ROUND3(A, B, C, D, 1, Si, 37); ROUND3(D, A, B, C, 4, Sj, 38); + ROUND3(C, D, A, B, 7, Sk, 39); ROUND3(B, C, D, A, 10, Sl, 40); + ROUND3(A, B, C, D, 13, Si, 41); ROUND3(D, A, B, C, 0, Sj, 42); + ROUND3(C, D, A, B, 3, Sk, 43); ROUND3(B, C, D, A, 6, Sl, 44); + ROUND3(A, B, C, D, 9, Si, 45); ROUND3(D, A, B, C, 12, Sj, 46); + ROUND3(C, D, A, B, 15, Sk, 47); ROUND3(B, C, D, A, 2, Sl, 48); + + ROUND4(A, B, C, D, 0, Sm, 49); ROUND4(D, A, B, C, 7, Sn, 50); + ROUND4(C, D, A, B, 14, So, 51); ROUND4(B, C, D, A, 5, Sp, 52); + ROUND4(A, B, C, D, 12, Sm, 53); ROUND4(D, A, B, C, 3, Sn, 54); + ROUND4(C, D, A, B, 10, So, 55); ROUND4(B, C, D, A, 1, Sp, 56); + ROUND4(A, B, C, D, 8, Sm, 57); ROUND4(D, A, B, C, 15, Sn, 58); + ROUND4(C, D, A, B, 6, So, 59); ROUND4(B, C, D, A, 13, Sp, 60); + ROUND4(A, B, C, D, 4, Sm, 61); ROUND4(D, A, B, C, 11, Sn, 62); + ROUND4(C, D, A, B, 2, So, 63); ROUND4(B, C, D, A, 9, Sp, 64); + + ctxt->md5_sta += A; + ctxt->md5_stb += B; + ctxt->md5_stc += C; + ctxt->md5_std += D; +} diff --git a/bsd/crypto/md5.h b/bsd/crypto/md5.h new file mode 100644 index 000000000..3d02afe6b --- /dev/null +++ b/bsd/crypto/md5.h @@ -0,0 +1,76 @@ +/* $FreeBSD: src/sys/crypto/md5.h,v 1.1.2.1 2000/07/15 07:14:18 kris Exp $ */ +/* $KAME: md5.h,v 1.4 2000/03/27 04:36:22 sumikawa Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _NETINET6_MD5_H_ +#define _NETINET6_MD5_H_ + +#define MD5_BUFLEN 64 + +typedef struct { + union { + u_int32_t md5_state32[4]; + u_int8_t md5_state8[16]; + } md5_st; + +#define md5_sta md5_st.md5_state32[0] +#define md5_stb md5_st.md5_state32[1] +#define md5_stc md5_st.md5_state32[2] +#define md5_std md5_st.md5_state32[3] +#define md5_st8 md5_st.md5_state8 + + union { + u_int64_t md5_count64; + u_int8_t md5_count8[8]; + } md5_count; +#define md5_n md5_count.md5_count64 +#define md5_n8 md5_count.md5_count8 + + u_int md5_i; + u_int8_t md5_buf[MD5_BUFLEN]; +} md5_ctxt; + +extern void md5_init __P((md5_ctxt *)); +extern void md5_loop __P((md5_ctxt *, u_int8_t *, u_int)); +extern void md5_pad __P((md5_ctxt *)); +extern void md5_result __P((u_int8_t *, md5_ctxt *)); + +/* compatibility */ +#define MD5_CTX md5_ctxt +#define MD5Init(x) md5_init((x)) +#define MD5Update(x, y, z) md5_loop((x), (y), (z)) +#define MD5Final(x, y) \ +do { \ + md5_pad((y)); \ + md5_result((x), (y)); \ +} while (0) + +#endif /* ! _NETINET6_MD5_H_*/ diff --git a/bsd/crypto/rc4/Makefile b/bsd/crypto/rc4/Makefile new file mode 100644 index 000000000..09d432842 --- /dev/null +++ b/bsd/crypto/rc4/Makefile @@ -0,0 +1,34 @@ +export MakeInc_cmd=${SRCROOT}/makedefs/MakeInc.cmd +export MakeInc_def=${SRCROOT}/makedefs/MakeInc.def +export MakeInc_rule=${SRCROOT}/makedefs/MakeInc.rule +export MakeInc_dir=${SRCROOT}/makedefs/MakeInc.dir + + +include $(MakeInc_cmd) +include $(MakeInc_def) + +INSTINC_SUBDIRS = \ + +INSTINC_SUBDIRS_PPC = \ + +INSTINC_SUBDIRS_I386 = \ + +EXPINC_SUBDIRS = \ + +EXPINC_SUBDIRS_PPC = \ + +EXPINC_SUBDIRS_I386 = \ + +PRIVATE_DATAFILES = \ + rc4.h + +INSTALL_MI_DIR = crypto + +EXPORT_MI_DIR = ${INSTALL_MI_DIR} + +INSTALL_MI_LCL_KERN_LIST = ${PRIVATE_DATAFILES} + +include $(MakeInc_rule) +include $(MakeInc_dir) + + diff --git a/bsd/crypto/rc4/rc4.c b/bsd/crypto/rc4/rc4.c new file mode 100644 index 000000000..2154cc404 --- /dev/null +++ b/bsd/crypto/rc4/rc4.c @@ -0,0 +1,104 @@ + +/* + * rc4.c + * + * Copyright (c) 1996-2000 Whistle Communications, Inc. + * All rights reserved. + * + * Subject to the following obligations and disclaimer of warranty, use and + * redistribution of this software, in source or object code forms, with or + * without modifications are expressly permitted by Whistle Communications; + * provided, however, that: + * 1. Any and all reproductions of the source or object code must include the + * copyright notice above and the following disclaimer of warranties; and + * 2. No rights are granted, in any manner or form, to use Whistle + * Communications, Inc. trademarks, including the mark "WHISTLE + * COMMUNICATIONS" on advertising, endorsements, or otherwise except as + * such appears in the above copyright notice or in the software. + * + * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND + * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO + * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, + * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. + * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY + * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS + * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. + * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES + * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING + * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * $FreeBSD: src/sys/crypto/rc4/rc4.c,v 1.2.2.1 2000/04/18 04:48:31 archie Exp $ + */ + +#include +#include + +static __inline void +swap_bytes(u_char *a, u_char *b) +{ + u_char temp; + + temp = *a; + *a = *b; + *b = temp; +} + +/* + * Initialize an RC4 state buffer using the supplied key, + * which can have arbitrary length. + */ +void +rc4_init(struct rc4_state *const state, const u_char *key, int keylen) +{ + u_char j; + int i; + + /* Initialize state with identity permutation */ + for (i = 0; i < 256; i++) + state->perm[i] = (u_char)i; + state->index1 = 0; + state->index2 = 0; + + /* Randomize the permutation using key data */ + for (j = i = 0; i < 256; i++) { + j += state->perm[i] + key[i % keylen]; + swap_bytes(&state->perm[i], &state->perm[j]); + } +} + +/* + * Encrypt some data using the supplied RC4 state buffer. + * The input and output buffers may be the same buffer. + * Since RC4 is a stream cypher, this function is used + * for both encryption and decryption. + */ +void +rc4_crypt(struct rc4_state *const state, + const u_char *inbuf, u_char *outbuf, int buflen) +{ + int i; + u_char j; + + for (i = 0; i < buflen; i++) { + + /* Update modification indicies */ + state->index1++; + state->index2 += state->perm[state->index1]; + + /* Modify permutation */ + swap_bytes(&state->perm[state->index1], + &state->perm[state->index2]); + + /* Encrypt/decrypt next byte */ + j = state->perm[state->index1] + state->perm[state->index2]; + outbuf[i] = inbuf[i] ^ state->perm[j]; + } +} + diff --git a/bsd/crypto/rc4/rc4.h b/bsd/crypto/rc4/rc4.h new file mode 100644 index 000000000..45971adbf --- /dev/null +++ b/bsd/crypto/rc4/rc4.h @@ -0,0 +1,54 @@ + +/* + * rc4.h + * + * Copyright (c) 1996-2000 Whistle Communications, Inc. + * All rights reserved. + * + * Subject to the following obligations and disclaimer of warranty, use and + * redistribution of this software, in source or object code forms, with or + * without modifications are expressly permitted by Whistle Communications; + * provided, however, that: + * 1. Any and all reproductions of the source or object code must include the + * copyright notice above and the following disclaimer of warranties; and + * 2. No rights are granted, in any manner or form, to use Whistle + * Communications, Inc. trademarks, including the mark "WHISTLE + * COMMUNICATIONS" on advertising, endorsements, or otherwise except as + * such appears in the above copyright notice or in the software. + * + * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND + * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO + * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, + * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. + * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY + * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS + * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. + * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES + * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING + * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * $FreeBSD: src/sys/crypto/rc4/rc4.h,v 1.2.2.1 2000/04/18 04:48:32 archie Exp $ + */ + +#ifndef _SYS_CRYPTO_RC4_RC4_H_ +#define _SYS_CRYPTO_RC4_RC4_H_ + +struct rc4_state { + u_char perm[256]; + u_char index1; + u_char index2; +}; + +extern void rc4_init(struct rc4_state *state, const u_char *key, int keylen); +extern void rc4_crypt(struct rc4_state *state, + const u_char *inbuf, u_char *outbuf, int buflen); + +#endif + diff --git a/bsd/crypto/rc5/Makefile b/bsd/crypto/rc5/Makefile deleted file mode 100644 index f901bbe6a..000000000 --- a/bsd/crypto/rc5/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -export MakeInc_cmd=${SRCROOT}/makedefs/MakeInc.cmd -export MakeInc_def=${SRCROOT}/makedefs/MakeInc.def -export MakeInc_rule=${SRCROOT}/makedefs/MakeInc.rule -export MakeInc_dir=${SRCROOT}/makedefs/MakeInc.dir - - -include $(MakeInc_cmd) -include $(MakeInc_def) - -INSTINC_SUBDIRS = \ - -INSTINC_SUBDIRS_PPC = \ - -INSTINC_SUBDIRS_I386 = \ - -EXPINC_SUBDIRS = \ - -EXPINC_SUBDIRS_PPC = \ - -EXPINC_SUBDIRS_I386 = \ - -DATAFILES = \ - rc5.h - -INSTALL_MI_LIST = ${DATAFILES} - -INSTALL_MI_DIR = crypto - -EXPORT_MI_LIST = ${DATAFILES} - -EXPORT_MI_DIR = crypto - - -include $(MakeInc_rule) -include $(MakeInc_dir) - - diff --git a/bsd/crypto/rc5/rc5.c b/bsd/crypto/rc5/rc5.c deleted file mode 100644 index 10eb5fe17..000000000 --- a/bsd/crypto/rc5/rc5.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include - - -void -set_rc5_expandkey(e_key, key, keylen, rounds) - RC5_WORD *e_key; - u_int8_t *key; - size_t keylen; - int rounds; -{ - int i, j, k, LL, t, T; - RC5_WORD L[256/WW]; - RC5_WORD A, B; - - LL = (keylen + WW - 1) / WW; - - bzero(L, sizeof(RC5_WORD)*LL); - - for (i = 0; i < keylen; i++) { - t = (key[i] & 0xff) << (8*(i%4)); - L[i/WW] = L[i/WW] + t; - } - - T = 2 * (rounds + 1); - e_key[0] = Pw; - for (i = 1; i < T; i++) - e_key[i] = e_key[i-1] + Qw; - - i = j = 0; - A = B = 0; - if (LL > T) - k = 3 * LL; - else - k = 3 * T; - - for (; k > 0; k--) { - A = ROTL(e_key[i]+A+B, 3, W); - e_key[i] = A; - B = ROTL(L[j]+A+B, A+B, W); - L[j] = B; - - i = (i + 1) % T; - j = (j + 1) % LL; - } -} - - -/* - * - */ -void -rc5_encrypt_round16(out, in, e_key) - u_int8_t *out; - const u_int8_t *in; - const RC5_WORD *e_key; -{ - RC5_WORD A, B; - const RC5_WORD *e_keyA, *e_keyB; - - A = in[0] & 0xff; - A += (in[1] & 0xff) << 8; - A += (in[2] & 0xff) << 16; - A += (in[3] & 0xff) << 24; - B = in[4] & 0xff; - B += (in[5] & 0xff) << 8; - B += (in[6] & 0xff) << 16; - B += (in[7] & 0xff) << 24; - - e_keyA = e_key; - e_keyB = e_key + 1; - - A += *e_keyA; e_keyA += 2; - B += *e_keyB; e_keyB += 2; - - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; /* round 4 */ - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; /* round 8 */ - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; /* round 12 */ - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; - A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; - B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; /* round 16 */ - - out[0] = A & 0xff; - out[1] = (A >> 8) & 0xff; - out[2] = (A >> 16) & 0xff; - out[3] = (A >> 24) & 0xff; - out[4] = B & 0xff; - out[5] = (B >> 8) & 0xff; - out[6] = (B >> 16) & 0xff; - out[7] = (B >> 24) & 0xff; -} - - -/* - * - */ -void -rc5_decrypt_round16(out, in, e_key) - u_int8_t *out; - const u_int8_t *in; - const RC5_WORD *e_key; -{ - RC5_WORD A, B; - const RC5_WORD *e_keyA, *e_keyB; - - A = in[0] & 0xff; - A += (in[1] & 0xff) << 8; - A += (in[2] & 0xff) << 16; - A += (in[3] & 0xff) << 24; - B = in[4] & 0xff; - B += (in[5] & 0xff) << 8; - B += (in[6] & 0xff) << 16; - B += (in[7] & 0xff) << 24; - - e_keyA = e_key + 2*16; - e_keyB = e_key + 2*16 + 1; - - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; /* round 4 */ - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; /* round 8 */ - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; /* round 12 */ - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; - B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; - A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; /* round 16 */ - - B = B - *e_keyB; - A = A - *e_keyA; - - out[0] = A & 0xff; - out[1] = (A >> 8) & 0xff; - out[2] = (A >> 16) & 0xff; - out[3] = (A >> 24) & 0xff; - out[4] = B & 0xff; - out[5] = (B >> 8) & 0xff; - out[6] = (B >> 16) & 0xff; - out[7] = (B >> 24) & 0xff; -} - diff --git a/bsd/crypto/rc5/rc5.h b/bsd/crypto/rc5/rc5.h deleted file mode 100644 index bc6d80bba..000000000 --- a/bsd/crypto/rc5/rc5.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _RFC2040_RC5_H_ -#define _RFC2040_RC5_H_ - -#include -#include -#include - -/* - * if RC5_WORD change, W also may be changed. - */ -typedef u_int32_t RC5_WORD; - -#define W (32) -#define WW (W / 8) -#define ROT_MASK (W - 1) -#define BB ((2 * W) / 8) - -#define SHLL(x, s) ((RC5_WORD)((x) << ((s)&ROT_MASK))) -#define SHLR(x, s, w) ((RC5_WORD)((x) >> ((w)-((s)&ROT_MASK)))) -#define SHRL(x, s, w) ((RC5_WORD)((x) << ((w)-((s)&ROT_MASK)))) -#define SHRR(x, s) ((RC5_WORD)((x) >> ((s)&ROT_MASK))) - -#define ROTL(x, s, w) ((RC5_WORD)(SHLL((x), (s))|SHLR((x), (s), (w)))) -#define ROTR(x, s, w) ((RC5_WORD)(SHRL((x), (s), (w))|SHRR((x), (s)))) - -#define P16 0xb7e1 -#define Q16 0x9e37 -#define P32 0xb7e15163 -#define Q32 0x9e3779b9 -#define P64 0xb7e151628aed2a6b -#define Q64 0x9e3779b97f4a7c15 - -#if W == 16 -#define Pw P16 -#define Qw Q16 -#elif W == 32 -#define Pw P32 -#define Qw Q32 -#elif W == 64 -#define Pw P64 -#define Qw Q64 -#endif - -#define RC5_ENCRYPT 1 -#define RC5_DECRYPT 0 - -extern void set_rc5_expandkey __P((RC5_WORD *, u_int8_t *, size_t, int)); -extern void rc5_encrypt_round16 __P((u_int8_t *, const u_int8_t *, - const RC5_WORD *)); -extern void rc5_decrypt_round16 __P((u_int8_t *, const u_int8_t *, - const RC5_WORD *)); -extern void rc5_cbc_process __P((struct mbuf *, size_t, size_t, RC5_WORD *, - u_int8_t *, int)); - -#endif diff --git a/bsd/crypto/rc5/rc5_cbc.c b/bsd/crypto/rc5/rc5_cbc.c deleted file mode 100644 index c3d094d24..000000000 --- a/bsd/crypto/rc5/rc5_cbc.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -/* - * based on sys/crypto/des/des_cbc.c, rewrote by Tomomi Suzuki - */ -#include - - -void -rc5_cbc_process(m0, skip, length, e_key, iv, mode) - struct mbuf *m0; - size_t skip; - size_t length; - RC5_WORD *e_key; - u_int8_t *iv; - int mode; -{ - u_int8_t inbuf[8], outbuf[8]; - struct mbuf *m; - size_t off; - - /* sanity check */ - if (m0->m_pkthdr.len < skip) { - printf("rc5_cbc_process: mbuf length < skip\n"); - return; - } - if (m0->m_pkthdr.len < length) { - printf("rc5_cbc_process: mbuf length < encrypt length\n"); - return; - } - if (m0->m_pkthdr.len < skip + length) { - printf("rc5_cbc_process: mbuf length < " - "skip + encrypt length\n"); - return; - } - if (length % 8) { - printf("rc5_cbc_process: length(%lu)is not multipleof 8\n", - (u_long)length); - return; - } - - m = m0; - off = 0; - - /* skip over the header */ - while (skip) { - if (!m) - panic("rc5_cbc_process: mbuf chain?\n"); - if (m->m_len <= skip) { - skip -= m->m_len; - m = m->m_next; - off = 0; - } else { - off = skip; - skip = 0; - } - } - - /* copy iv into outbuf for XOR (encrypt) */ - bcopy(iv, outbuf, 8); - - /* - * encrypt/decrypt packet - */ - while (length > 0) { - int i; - - if (!m) - panic("rc5_cbc_process: mbuf chain?\n"); - - /* - * copy the source into input buffer. - * don't update off or m, since we need to use them - * later. - */ - if (off + 8 <= m->m_len) - bcopy(mtod(m, u_int8_t *) + off, &inbuf[0], 8); - else { - struct mbuf *n; - size_t noff; - u_int8_t *p; - u_int8_t *in; - - n = m; - noff = off; - p = mtod(n, u_int8_t *) + noff; - - in = &inbuf[0]; - while (in - &inbuf[0] < 8) { - if (!p) { - panic("rc5_cbc_process: " - "mbuf chain?\n"); - } - *in++ = *p++; - noff++; - if (noff < n->m_len) - continue; - do { - n = n->m_next; - } while (n && !n->m_len); - noff = 0; - if (n) - p = mtod(n, u_int8_t *) + noff; - else - p = NULL; - } - } - - /* encrypt/decrypt */ - switch (mode) { - case RC5_ENCRYPT: - /* XOR */ - for (i = 0; i < 8; i++) - inbuf[i] ^= outbuf[i]; - - /* encrypt */ - rc5_encrypt_round16(outbuf, inbuf, e_key); - break; - - case RC5_DECRYPT: - /* decrypt */ - rc5_decrypt_round16(outbuf, inbuf, e_key); - - /* XOR */ - for (i = 0; i < 8; i++) - outbuf[i] ^= iv[i]; - - /* copy inbuf into iv for next XOR */ - bcopy(inbuf, iv, 8); - break; - } - - /* - * copy the output buffer into the result. - * need to update off and m. - */ - if (off + 8 < m->m_len) { - bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); - off += 8; - } else if (off + 8 == m->m_len) { - bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); - do { - m = m->m_next; - } while (m && !m->m_len); - off = 0; - } else { - struct mbuf *n; - size_t noff; - u_int8_t *p; - u_int8_t *out; - - n = m; - noff = off; - p = mtod(n, u_int8_t *) + noff; - - out = &outbuf[0]; - while (out - &outbuf[0] < 8) { - if (!p) { - panic("rc5_cbc_process: " - "mbuf chain?\n"); - } - *p++ = *out++; - noff++; - if (noff < n->m_len) - continue; - do { - n = n->m_next; - } while (n && !n->m_len); - noff = 0; - if (n) - p = mtod(n, u_int8_t *) + noff; - else - p = NULL; - } - - m = n; - off = noff; - } - - length -= 8; - } -} - diff --git a/bsd/crypto/rijndael/Makefile b/bsd/crypto/rijndael/Makefile new file mode 100644 index 000000000..92d360eb6 --- /dev/null +++ b/bsd/crypto/rijndael/Makefile @@ -0,0 +1,34 @@ +export MakeInc_cmd=${SRCROOT}/makedefs/MakeInc.cmd +export MakeInc_def=${SRCROOT}/makedefs/MakeInc.def +export MakeInc_rule=${SRCROOT}/makedefs/MakeInc.rule +export MakeInc_dir=${SRCROOT}/makedefs/MakeInc.dir + + +include $(MakeInc_cmd) +include $(MakeInc_def) + +INSTINC_SUBDIRS = \ + +INSTINC_SUBDIRS_PPC = \ + +INSTINC_SUBDIRS_I386 = \ + +EXPINC_SUBDIRS = \ + +EXPINC_SUBDIRS_PPC = \ + +EXPINC_SUBDIRS_I386 = \ + +PRIVATE_DATAFILES = \ + rijndael-alg-fst.h rijndael-api-fst.h rijndael.h + +INSTALL_MI_DIR = crypto + +EXPORT_MI_DIR = ${INSTALL_MI_DIR} + +INSTALL_MI_LCL_KERN_LIST = ${PRIVATE_DATAFILES} + +include $(MakeInc_rule) +include $(MakeInc_dir) + + diff --git a/bsd/crypto/rijndael/boxes-fst.dat b/bsd/crypto/rijndael/boxes-fst.dat new file mode 100644 index 000000000..8b9e26c33 --- /dev/null +++ b/bsd/crypto/rijndael/boxes-fst.dat @@ -0,0 +1,958 @@ +/* $FreeBSD: src/sys/crypto/rijndael/boxes-fst.dat,v 1.2.2.1 2001/07/03 11:01:35 ume Exp $ */ +/* $KAME: boxes-fst.dat,v 1.6 2001/05/27 00:23:22 itojun Exp $ */ + +const word8 S[256] = { + 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, +202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, +183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, + 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, + 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, + 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, +208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, + 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, +205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, + 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, +224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, +231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, +186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, +112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, +225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, +140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22 +}; + +#ifdef INTERMEDIATE_VALUE_KAT +static const word8 Si[256] = { + 82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251, +124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203, + 84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66, 250, 195, 78, + 8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73, 109, 139, 209, 37, +114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92, 204, 93, 101, 182, 146, +108, 112, 72, 80, 253, 237, 185, 218, 94, 21, 70, 87, 167, 141, 157, 132, +144, 216, 171, 0, 140, 188, 211, 10, 247, 228, 88, 5, 184, 179, 69, 6, +208, 44, 30, 143, 202, 63, 15, 2, 193, 175, 189, 3, 1, 19, 138, 107, + 58, 145, 17, 65, 79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 115, +150, 172, 116, 34, 231, 173, 53, 133, 226, 249, 55, 232, 28, 117, 223, 110, + 71, 241, 26, 113, 29, 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27, +252, 86, 62, 75, 198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244, + 31, 221, 168, 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95, + 96, 81, 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239, +160, 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97, + 23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12, 125 +}; +#endif /* INTERMEDIATE_VALUE_KAT */ + +union xtab { + word32 xt32[256]; + word8 xt8[256][4]; +}; + +static const union xtab xT1 = { + .xt8 = { +{0xc6,0x63,0x63,0xa5}, {0xf8,0x7c,0x7c,0x84}, {0xee,0x77,0x77,0x99}, {0xf6,0x7b,0x7b,0x8d}, +{0xff,0xf2,0xf2,0x0d}, {0xd6,0x6b,0x6b,0xbd}, {0xde,0x6f,0x6f,0xb1}, {0x91,0xc5,0xc5,0x54}, +{0x60,0x30,0x30,0x50}, {0x02,0x01,0x01,0x03}, {0xce,0x67,0x67,0xa9}, {0x56,0x2b,0x2b,0x7d}, +{0xe7,0xfe,0xfe,0x19}, {0xb5,0xd7,0xd7,0x62}, {0x4d,0xab,0xab,0xe6}, {0xec,0x76,0x76,0x9a}, +{0x8f,0xca,0xca,0x45}, {0x1f,0x82,0x82,0x9d}, {0x89,0xc9,0xc9,0x40}, {0xfa,0x7d,0x7d,0x87}, +{0xef,0xfa,0xfa,0x15}, {0xb2,0x59,0x59,0xeb}, {0x8e,0x47,0x47,0xc9}, {0xfb,0xf0,0xf0,0x0b}, +{0x41,0xad,0xad,0xec}, {0xb3,0xd4,0xd4,0x67}, {0x5f,0xa2,0xa2,0xfd}, {0x45,0xaf,0xaf,0xea}, +{0x23,0x9c,0x9c,0xbf}, {0x53,0xa4,0xa4,0xf7}, {0xe4,0x72,0x72,0x96}, {0x9b,0xc0,0xc0,0x5b}, +{0x75,0xb7,0xb7,0xc2}, {0xe1,0xfd,0xfd,0x1c}, {0x3d,0x93,0x93,0xae}, {0x4c,0x26,0x26,0x6a}, +{0x6c,0x36,0x36,0x5a}, {0x7e,0x3f,0x3f,0x41}, {0xf5,0xf7,0xf7,0x02}, {0x83,0xcc,0xcc,0x4f}, +{0x68,0x34,0x34,0x5c}, {0x51,0xa5,0xa5,0xf4}, {0xd1,0xe5,0xe5,0x34}, {0xf9,0xf1,0xf1,0x08}, +{0xe2,0x71,0x71,0x93}, {0xab,0xd8,0xd8,0x73}, {0x62,0x31,0x31,0x53}, {0x2a,0x15,0x15,0x3f}, +{0x08,0x04,0x04,0x0c}, {0x95,0xc7,0xc7,0x52}, {0x46,0x23,0x23,0x65}, {0x9d,0xc3,0xc3,0x5e}, +{0x30,0x18,0x18,0x28}, {0x37,0x96,0x96,0xa1}, {0x0a,0x05,0x05,0x0f}, {0x2f,0x9a,0x9a,0xb5}, +{0x0e,0x07,0x07,0x09}, {0x24,0x12,0x12,0x36}, {0x1b,0x80,0x80,0x9b}, {0xdf,0xe2,0xe2,0x3d}, +{0xcd,0xeb,0xeb,0x26}, {0x4e,0x27,0x27,0x69}, {0x7f,0xb2,0xb2,0xcd}, {0xea,0x75,0x75,0x9f}, +{0x12,0x09,0x09,0x1b}, {0x1d,0x83,0x83,0x9e}, {0x58,0x2c,0x2c,0x74}, {0x34,0x1a,0x1a,0x2e}, +{0x36,0x1b,0x1b,0x2d}, {0xdc,0x6e,0x6e,0xb2}, {0xb4,0x5a,0x5a,0xee}, {0x5b,0xa0,0xa0,0xfb}, +{0xa4,0x52,0x52,0xf6}, {0x76,0x3b,0x3b,0x4d}, {0xb7,0xd6,0xd6,0x61}, {0x7d,0xb3,0xb3,0xce}, +{0x52,0x29,0x29,0x7b}, {0xdd,0xe3,0xe3,0x3e}, {0x5e,0x2f,0x2f,0x71}, {0x13,0x84,0x84,0x97}, +{0xa6,0x53,0x53,0xf5}, {0xb9,0xd1,0xd1,0x68}, {0x00,0x00,0x00,0x00}, {0xc1,0xed,0xed,0x2c}, +{0x40,0x20,0x20,0x60}, {0xe3,0xfc,0xfc,0x1f}, {0x79,0xb1,0xb1,0xc8}, {0xb6,0x5b,0x5b,0xed}, +{0xd4,0x6a,0x6a,0xbe}, {0x8d,0xcb,0xcb,0x46}, {0x67,0xbe,0xbe,0xd9}, {0x72,0x39,0x39,0x4b}, +{0x94,0x4a,0x4a,0xde}, {0x98,0x4c,0x4c,0xd4}, {0xb0,0x58,0x58,0xe8}, {0x85,0xcf,0xcf,0x4a}, +{0xbb,0xd0,0xd0,0x6b}, {0xc5,0xef,0xef,0x2a}, {0x4f,0xaa,0xaa,0xe5}, {0xed,0xfb,0xfb,0x16}, +{0x86,0x43,0x43,0xc5}, {0x9a,0x4d,0x4d,0xd7}, {0x66,0x33,0x33,0x55}, {0x11,0x85,0x85,0x94}, +{0x8a,0x45,0x45,0xcf}, {0xe9,0xf9,0xf9,0x10}, {0x04,0x02,0x02,0x06}, {0xfe,0x7f,0x7f,0x81}, +{0xa0,0x50,0x50,0xf0}, {0x78,0x3c,0x3c,0x44}, {0x25,0x9f,0x9f,0xba}, {0x4b,0xa8,0xa8,0xe3}, +{0xa2,0x51,0x51,0xf3}, {0x5d,0xa3,0xa3,0xfe}, {0x80,0x40,0x40,0xc0}, {0x05,0x8f,0x8f,0x8a}, +{0x3f,0x92,0x92,0xad}, {0x21,0x9d,0x9d,0xbc}, {0x70,0x38,0x38,0x48}, {0xf1,0xf5,0xf5,0x04}, +{0x63,0xbc,0xbc,0xdf}, {0x77,0xb6,0xb6,0xc1}, {0xaf,0xda,0xda,0x75}, {0x42,0x21,0x21,0x63}, +{0x20,0x10,0x10,0x30}, {0xe5,0xff,0xff,0x1a}, {0xfd,0xf3,0xf3,0x0e}, {0xbf,0xd2,0xd2,0x6d}, +{0x81,0xcd,0xcd,0x4c}, {0x18,0x0c,0x0c,0x14}, {0x26,0x13,0x13,0x35}, {0xc3,0xec,0xec,0x2f}, +{0xbe,0x5f,0x5f,0xe1}, {0x35,0x97,0x97,0xa2}, {0x88,0x44,0x44,0xcc}, {0x2e,0x17,0x17,0x39}, +{0x93,0xc4,0xc4,0x57}, {0x55,0xa7,0xa7,0xf2}, {0xfc,0x7e,0x7e,0x82}, {0x7a,0x3d,0x3d,0x47}, +{0xc8,0x64,0x64,0xac}, {0xba,0x5d,0x5d,0xe7}, {0x32,0x19,0x19,0x2b}, {0xe6,0x73,0x73,0x95}, +{0xc0,0x60,0x60,0xa0}, {0x19,0x81,0x81,0x98}, {0x9e,0x4f,0x4f,0xd1}, {0xa3,0xdc,0xdc,0x7f}, +{0x44,0x22,0x22,0x66}, {0x54,0x2a,0x2a,0x7e}, {0x3b,0x90,0x90,0xab}, {0x0b,0x88,0x88,0x83}, +{0x8c,0x46,0x46,0xca}, {0xc7,0xee,0xee,0x29}, {0x6b,0xb8,0xb8,0xd3}, {0x28,0x14,0x14,0x3c}, +{0xa7,0xde,0xde,0x79}, {0xbc,0x5e,0x5e,0xe2}, {0x16,0x0b,0x0b,0x1d}, {0xad,0xdb,0xdb,0x76}, +{0xdb,0xe0,0xe0,0x3b}, {0x64,0x32,0x32,0x56}, {0x74,0x3a,0x3a,0x4e}, {0x14,0x0a,0x0a,0x1e}, +{0x92,0x49,0x49,0xdb}, {0x0c,0x06,0x06,0x0a}, {0x48,0x24,0x24,0x6c}, {0xb8,0x5c,0x5c,0xe4}, +{0x9f,0xc2,0xc2,0x5d}, {0xbd,0xd3,0xd3,0x6e}, {0x43,0xac,0xac,0xef}, {0xc4,0x62,0x62,0xa6}, +{0x39,0x91,0x91,0xa8}, {0x31,0x95,0x95,0xa4}, {0xd3,0xe4,0xe4,0x37}, {0xf2,0x79,0x79,0x8b}, +{0xd5,0xe7,0xe7,0x32}, {0x8b,0xc8,0xc8,0x43}, {0x6e,0x37,0x37,0x59}, {0xda,0x6d,0x6d,0xb7}, +{0x01,0x8d,0x8d,0x8c}, {0xb1,0xd5,0xd5,0x64}, {0x9c,0x4e,0x4e,0xd2}, {0x49,0xa9,0xa9,0xe0}, +{0xd8,0x6c,0x6c,0xb4}, {0xac,0x56,0x56,0xfa}, {0xf3,0xf4,0xf4,0x07}, {0xcf,0xea,0xea,0x25}, +{0xca,0x65,0x65,0xaf}, {0xf4,0x7a,0x7a,0x8e}, {0x47,0xae,0xae,0xe9}, {0x10,0x08,0x08,0x18}, +{0x6f,0xba,0xba,0xd5}, {0xf0,0x78,0x78,0x88}, {0x4a,0x25,0x25,0x6f}, {0x5c,0x2e,0x2e,0x72}, +{0x38,0x1c,0x1c,0x24}, {0x57,0xa6,0xa6,0xf1}, {0x73,0xb4,0xb4,0xc7}, {0x97,0xc6,0xc6,0x51}, +{0xcb,0xe8,0xe8,0x23}, {0xa1,0xdd,0xdd,0x7c}, {0xe8,0x74,0x74,0x9c}, {0x3e,0x1f,0x1f,0x21}, +{0x96,0x4b,0x4b,0xdd}, {0x61,0xbd,0xbd,0xdc}, {0x0d,0x8b,0x8b,0x86}, {0x0f,0x8a,0x8a,0x85}, +{0xe0,0x70,0x70,0x90}, {0x7c,0x3e,0x3e,0x42}, {0x71,0xb5,0xb5,0xc4}, {0xcc,0x66,0x66,0xaa}, +{0x90,0x48,0x48,0xd8}, {0x06,0x03,0x03,0x05}, {0xf7,0xf6,0xf6,0x01}, {0x1c,0x0e,0x0e,0x12}, +{0xc2,0x61,0x61,0xa3}, {0x6a,0x35,0x35,0x5f}, {0xae,0x57,0x57,0xf9}, {0x69,0xb9,0xb9,0xd0}, +{0x17,0x86,0x86,0x91}, {0x99,0xc1,0xc1,0x58}, {0x3a,0x1d,0x1d,0x27}, {0x27,0x9e,0x9e,0xb9}, +{0xd9,0xe1,0xe1,0x38}, {0xeb,0xf8,0xf8,0x13}, {0x2b,0x98,0x98,0xb3}, {0x22,0x11,0x11,0x33}, +{0xd2,0x69,0x69,0xbb}, {0xa9,0xd9,0xd9,0x70}, {0x07,0x8e,0x8e,0x89}, {0x33,0x94,0x94,0xa7}, +{0x2d,0x9b,0x9b,0xb6}, {0x3c,0x1e,0x1e,0x22}, {0x15,0x87,0x87,0x92}, {0xc9,0xe9,0xe9,0x20}, +{0x87,0xce,0xce,0x49}, {0xaa,0x55,0x55,0xff}, {0x50,0x28,0x28,0x78}, {0xa5,0xdf,0xdf,0x7a}, +{0x03,0x8c,0x8c,0x8f}, {0x59,0xa1,0xa1,0xf8}, {0x09,0x89,0x89,0x80}, {0x1a,0x0d,0x0d,0x17}, +{0x65,0xbf,0xbf,0xda}, {0xd7,0xe6,0xe6,0x31}, {0x84,0x42,0x42,0xc6}, {0xd0,0x68,0x68,0xb8}, +{0x82,0x41,0x41,0xc3}, {0x29,0x99,0x99,0xb0}, {0x5a,0x2d,0x2d,0x77}, {0x1e,0x0f,0x0f,0x11}, +{0x7b,0xb0,0xb0,0xcb}, {0xa8,0x54,0x54,0xfc}, {0x6d,0xbb,0xbb,0xd6}, {0x2c,0x16,0x16,0x3a} + } +}; +#define T1 xT1.xt8 + +static const union xtab xT2 = { + .xt8 = { +{0xa5,0xc6,0x63,0x63}, {0x84,0xf8,0x7c,0x7c}, {0x99,0xee,0x77,0x77}, {0x8d,0xf6,0x7b,0x7b}, +{0x0d,0xff,0xf2,0xf2}, {0xbd,0xd6,0x6b,0x6b}, {0xb1,0xde,0x6f,0x6f}, {0x54,0x91,0xc5,0xc5}, +{0x50,0x60,0x30,0x30}, {0x03,0x02,0x01,0x01}, {0xa9,0xce,0x67,0x67}, {0x7d,0x56,0x2b,0x2b}, +{0x19,0xe7,0xfe,0xfe}, {0x62,0xb5,0xd7,0xd7}, {0xe6,0x4d,0xab,0xab}, {0x9a,0xec,0x76,0x76}, +{0x45,0x8f,0xca,0xca}, {0x9d,0x1f,0x82,0x82}, {0x40,0x89,0xc9,0xc9}, {0x87,0xfa,0x7d,0x7d}, +{0x15,0xef,0xfa,0xfa}, {0xeb,0xb2,0x59,0x59}, {0xc9,0x8e,0x47,0x47}, {0x0b,0xfb,0xf0,0xf0}, +{0xec,0x41,0xad,0xad}, {0x67,0xb3,0xd4,0xd4}, {0xfd,0x5f,0xa2,0xa2}, {0xea,0x45,0xaf,0xaf}, +{0xbf,0x23,0x9c,0x9c}, {0xf7,0x53,0xa4,0xa4}, {0x96,0xe4,0x72,0x72}, {0x5b,0x9b,0xc0,0xc0}, +{0xc2,0x75,0xb7,0xb7}, {0x1c,0xe1,0xfd,0xfd}, {0xae,0x3d,0x93,0x93}, {0x6a,0x4c,0x26,0x26}, +{0x5a,0x6c,0x36,0x36}, {0x41,0x7e,0x3f,0x3f}, {0x02,0xf5,0xf7,0xf7}, {0x4f,0x83,0xcc,0xcc}, +{0x5c,0x68,0x34,0x34}, {0xf4,0x51,0xa5,0xa5}, {0x34,0xd1,0xe5,0xe5}, {0x08,0xf9,0xf1,0xf1}, +{0x93,0xe2,0x71,0x71}, {0x73,0xab,0xd8,0xd8}, {0x53,0x62,0x31,0x31}, {0x3f,0x2a,0x15,0x15}, +{0x0c,0x08,0x04,0x04}, {0x52,0x95,0xc7,0xc7}, {0x65,0x46,0x23,0x23}, {0x5e,0x9d,0xc3,0xc3}, +{0x28,0x30,0x18,0x18}, {0xa1,0x37,0x96,0x96}, {0x0f,0x0a,0x05,0x05}, {0xb5,0x2f,0x9a,0x9a}, +{0x09,0x0e,0x07,0x07}, {0x36,0x24,0x12,0x12}, {0x9b,0x1b,0x80,0x80}, {0x3d,0xdf,0xe2,0xe2}, +{0x26,0xcd,0xeb,0xeb}, {0x69,0x4e,0x27,0x27}, {0xcd,0x7f,0xb2,0xb2}, {0x9f,0xea,0x75,0x75}, +{0x1b,0x12,0x09,0x09}, {0x9e,0x1d,0x83,0x83}, {0x74,0x58,0x2c,0x2c}, {0x2e,0x34,0x1a,0x1a}, +{0x2d,0x36,0x1b,0x1b}, {0xb2,0xdc,0x6e,0x6e}, {0xee,0xb4,0x5a,0x5a}, {0xfb,0x5b,0xa0,0xa0}, +{0xf6,0xa4,0x52,0x52}, {0x4d,0x76,0x3b,0x3b}, {0x61,0xb7,0xd6,0xd6}, {0xce,0x7d,0xb3,0xb3}, +{0x7b,0x52,0x29,0x29}, {0x3e,0xdd,0xe3,0xe3}, {0x71,0x5e,0x2f,0x2f}, {0x97,0x13,0x84,0x84}, +{0xf5,0xa6,0x53,0x53}, {0x68,0xb9,0xd1,0xd1}, {0x00,0x00,0x00,0x00}, {0x2c,0xc1,0xed,0xed}, +{0x60,0x40,0x20,0x20}, {0x1f,0xe3,0xfc,0xfc}, {0xc8,0x79,0xb1,0xb1}, {0xed,0xb6,0x5b,0x5b}, +{0xbe,0xd4,0x6a,0x6a}, {0x46,0x8d,0xcb,0xcb}, {0xd9,0x67,0xbe,0xbe}, {0x4b,0x72,0x39,0x39}, +{0xde,0x94,0x4a,0x4a}, {0xd4,0x98,0x4c,0x4c}, {0xe8,0xb0,0x58,0x58}, {0x4a,0x85,0xcf,0xcf}, +{0x6b,0xbb,0xd0,0xd0}, {0x2a,0xc5,0xef,0xef}, {0xe5,0x4f,0xaa,0xaa}, {0x16,0xed,0xfb,0xfb}, +{0xc5,0x86,0x43,0x43}, {0xd7,0x9a,0x4d,0x4d}, {0x55,0x66,0x33,0x33}, {0x94,0x11,0x85,0x85}, +{0xcf,0x8a,0x45,0x45}, {0x10,0xe9,0xf9,0xf9}, {0x06,0x04,0x02,0x02}, {0x81,0xfe,0x7f,0x7f}, +{0xf0,0xa0,0x50,0x50}, {0x44,0x78,0x3c,0x3c}, {0xba,0x25,0x9f,0x9f}, {0xe3,0x4b,0xa8,0xa8}, +{0xf3,0xa2,0x51,0x51}, {0xfe,0x5d,0xa3,0xa3}, {0xc0,0x80,0x40,0x40}, {0x8a,0x05,0x8f,0x8f}, +{0xad,0x3f,0x92,0x92}, {0xbc,0x21,0x9d,0x9d}, {0x48,0x70,0x38,0x38}, {0x04,0xf1,0xf5,0xf5}, +{0xdf,0x63,0xbc,0xbc}, {0xc1,0x77,0xb6,0xb6}, {0x75,0xaf,0xda,0xda}, {0x63,0x42,0x21,0x21}, +{0x30,0x20,0x10,0x10}, {0x1a,0xe5,0xff,0xff}, {0x0e,0xfd,0xf3,0xf3}, {0x6d,0xbf,0xd2,0xd2}, +{0x4c,0x81,0xcd,0xcd}, {0x14,0x18,0x0c,0x0c}, {0x35,0x26,0x13,0x13}, {0x2f,0xc3,0xec,0xec}, +{0xe1,0xbe,0x5f,0x5f}, {0xa2,0x35,0x97,0x97}, {0xcc,0x88,0x44,0x44}, {0x39,0x2e,0x17,0x17}, +{0x57,0x93,0xc4,0xc4}, {0xf2,0x55,0xa7,0xa7}, {0x82,0xfc,0x7e,0x7e}, {0x47,0x7a,0x3d,0x3d}, +{0xac,0xc8,0x64,0x64}, {0xe7,0xba,0x5d,0x5d}, {0x2b,0x32,0x19,0x19}, {0x95,0xe6,0x73,0x73}, +{0xa0,0xc0,0x60,0x60}, {0x98,0x19,0x81,0x81}, {0xd1,0x9e,0x4f,0x4f}, {0x7f,0xa3,0xdc,0xdc}, +{0x66,0x44,0x22,0x22}, {0x7e,0x54,0x2a,0x2a}, {0xab,0x3b,0x90,0x90}, {0x83,0x0b,0x88,0x88}, +{0xca,0x8c,0x46,0x46}, {0x29,0xc7,0xee,0xee}, {0xd3,0x6b,0xb8,0xb8}, {0x3c,0x28,0x14,0x14}, +{0x79,0xa7,0xde,0xde}, {0xe2,0xbc,0x5e,0x5e}, {0x1d,0x16,0x0b,0x0b}, {0x76,0xad,0xdb,0xdb}, +{0x3b,0xdb,0xe0,0xe0}, {0x56,0x64,0x32,0x32}, {0x4e,0x74,0x3a,0x3a}, {0x1e,0x14,0x0a,0x0a}, +{0xdb,0x92,0x49,0x49}, {0x0a,0x0c,0x06,0x06}, {0x6c,0x48,0x24,0x24}, {0xe4,0xb8,0x5c,0x5c}, +{0x5d,0x9f,0xc2,0xc2}, {0x6e,0xbd,0xd3,0xd3}, {0xef,0x43,0xac,0xac}, {0xa6,0xc4,0x62,0x62}, +{0xa8,0x39,0x91,0x91}, {0xa4,0x31,0x95,0x95}, {0x37,0xd3,0xe4,0xe4}, {0x8b,0xf2,0x79,0x79}, +{0x32,0xd5,0xe7,0xe7}, {0x43,0x8b,0xc8,0xc8}, {0x59,0x6e,0x37,0x37}, {0xb7,0xda,0x6d,0x6d}, +{0x8c,0x01,0x8d,0x8d}, {0x64,0xb1,0xd5,0xd5}, {0xd2,0x9c,0x4e,0x4e}, {0xe0,0x49,0xa9,0xa9}, +{0xb4,0xd8,0x6c,0x6c}, {0xfa,0xac,0x56,0x56}, {0x07,0xf3,0xf4,0xf4}, {0x25,0xcf,0xea,0xea}, +{0xaf,0xca,0x65,0x65}, {0x8e,0xf4,0x7a,0x7a}, {0xe9,0x47,0xae,0xae}, {0x18,0x10,0x08,0x08}, +{0xd5,0x6f,0xba,0xba}, {0x88,0xf0,0x78,0x78}, {0x6f,0x4a,0x25,0x25}, {0x72,0x5c,0x2e,0x2e}, +{0x24,0x38,0x1c,0x1c}, {0xf1,0x57,0xa6,0xa6}, {0xc7,0x73,0xb4,0xb4}, {0x51,0x97,0xc6,0xc6}, +{0x23,0xcb,0xe8,0xe8}, {0x7c,0xa1,0xdd,0xdd}, {0x9c,0xe8,0x74,0x74}, {0x21,0x3e,0x1f,0x1f}, +{0xdd,0x96,0x4b,0x4b}, {0xdc,0x61,0xbd,0xbd}, {0x86,0x0d,0x8b,0x8b}, {0x85,0x0f,0x8a,0x8a}, +{0x90,0xe0,0x70,0x70}, {0x42,0x7c,0x3e,0x3e}, {0xc4,0x71,0xb5,0xb5}, {0xaa,0xcc,0x66,0x66}, +{0xd8,0x90,0x48,0x48}, {0x05,0x06,0x03,0x03}, {0x01,0xf7,0xf6,0xf6}, {0x12,0x1c,0x0e,0x0e}, +{0xa3,0xc2,0x61,0x61}, {0x5f,0x6a,0x35,0x35}, {0xf9,0xae,0x57,0x57}, {0xd0,0x69,0xb9,0xb9}, +{0x91,0x17,0x86,0x86}, {0x58,0x99,0xc1,0xc1}, {0x27,0x3a,0x1d,0x1d}, {0xb9,0x27,0x9e,0x9e}, +{0x38,0xd9,0xe1,0xe1}, {0x13,0xeb,0xf8,0xf8}, {0xb3,0x2b,0x98,0x98}, {0x33,0x22,0x11,0x11}, +{0xbb,0xd2,0x69,0x69}, {0x70,0xa9,0xd9,0xd9}, {0x89,0x07,0x8e,0x8e}, {0xa7,0x33,0x94,0x94}, +{0xb6,0x2d,0x9b,0x9b}, {0x22,0x3c,0x1e,0x1e}, {0x92,0x15,0x87,0x87}, {0x20,0xc9,0xe9,0xe9}, +{0x49,0x87,0xce,0xce}, {0xff,0xaa,0x55,0x55}, {0x78,0x50,0x28,0x28}, {0x7a,0xa5,0xdf,0xdf}, +{0x8f,0x03,0x8c,0x8c}, {0xf8,0x59,0xa1,0xa1}, {0x80,0x09,0x89,0x89}, {0x17,0x1a,0x0d,0x0d}, +{0xda,0x65,0xbf,0xbf}, {0x31,0xd7,0xe6,0xe6}, {0xc6,0x84,0x42,0x42}, {0xb8,0xd0,0x68,0x68}, +{0xc3,0x82,0x41,0x41}, {0xb0,0x29,0x99,0x99}, {0x77,0x5a,0x2d,0x2d}, {0x11,0x1e,0x0f,0x0f}, +{0xcb,0x7b,0xb0,0xb0}, {0xfc,0xa8,0x54,0x54}, {0xd6,0x6d,0xbb,0xbb}, {0x3a,0x2c,0x16,0x16} + } +}; +#define T2 xT2.xt8 + +static const union xtab xT3 = { + .xt8 = { +{0x63,0xa5,0xc6,0x63}, {0x7c,0x84,0xf8,0x7c}, {0x77,0x99,0xee,0x77}, {0x7b,0x8d,0xf6,0x7b}, +{0xf2,0x0d,0xff,0xf2}, {0x6b,0xbd,0xd6,0x6b}, {0x6f,0xb1,0xde,0x6f}, {0xc5,0x54,0x91,0xc5}, +{0x30,0x50,0x60,0x30}, {0x01,0x03,0x02,0x01}, {0x67,0xa9,0xce,0x67}, {0x2b,0x7d,0x56,0x2b}, +{0xfe,0x19,0xe7,0xfe}, {0xd7,0x62,0xb5,0xd7}, {0xab,0xe6,0x4d,0xab}, {0x76,0x9a,0xec,0x76}, +{0xca,0x45,0x8f,0xca}, {0x82,0x9d,0x1f,0x82}, {0xc9,0x40,0x89,0xc9}, {0x7d,0x87,0xfa,0x7d}, +{0xfa,0x15,0xef,0xfa}, {0x59,0xeb,0xb2,0x59}, {0x47,0xc9,0x8e,0x47}, {0xf0,0x0b,0xfb,0xf0}, +{0xad,0xec,0x41,0xad}, {0xd4,0x67,0xb3,0xd4}, {0xa2,0xfd,0x5f,0xa2}, {0xaf,0xea,0x45,0xaf}, +{0x9c,0xbf,0x23,0x9c}, {0xa4,0xf7,0x53,0xa4}, {0x72,0x96,0xe4,0x72}, {0xc0,0x5b,0x9b,0xc0}, +{0xb7,0xc2,0x75,0xb7}, {0xfd,0x1c,0xe1,0xfd}, {0x93,0xae,0x3d,0x93}, {0x26,0x6a,0x4c,0x26}, +{0x36,0x5a,0x6c,0x36}, {0x3f,0x41,0x7e,0x3f}, {0xf7,0x02,0xf5,0xf7}, {0xcc,0x4f,0x83,0xcc}, +{0x34,0x5c,0x68,0x34}, {0xa5,0xf4,0x51,0xa5}, {0xe5,0x34,0xd1,0xe5}, {0xf1,0x08,0xf9,0xf1}, +{0x71,0x93,0xe2,0x71}, {0xd8,0x73,0xab,0xd8}, {0x31,0x53,0x62,0x31}, {0x15,0x3f,0x2a,0x15}, +{0x04,0x0c,0x08,0x04}, {0xc7,0x52,0x95,0xc7}, {0x23,0x65,0x46,0x23}, {0xc3,0x5e,0x9d,0xc3}, +{0x18,0x28,0x30,0x18}, {0x96,0xa1,0x37,0x96}, {0x05,0x0f,0x0a,0x05}, {0x9a,0xb5,0x2f,0x9a}, +{0x07,0x09,0x0e,0x07}, {0x12,0x36,0x24,0x12}, {0x80,0x9b,0x1b,0x80}, {0xe2,0x3d,0xdf,0xe2}, +{0xeb,0x26,0xcd,0xeb}, {0x27,0x69,0x4e,0x27}, {0xb2,0xcd,0x7f,0xb2}, {0x75,0x9f,0xea,0x75}, +{0x09,0x1b,0x12,0x09}, {0x83,0x9e,0x1d,0x83}, {0x2c,0x74,0x58,0x2c}, {0x1a,0x2e,0x34,0x1a}, +{0x1b,0x2d,0x36,0x1b}, {0x6e,0xb2,0xdc,0x6e}, {0x5a,0xee,0xb4,0x5a}, {0xa0,0xfb,0x5b,0xa0}, +{0x52,0xf6,0xa4,0x52}, {0x3b,0x4d,0x76,0x3b}, {0xd6,0x61,0xb7,0xd6}, {0xb3,0xce,0x7d,0xb3}, +{0x29,0x7b,0x52,0x29}, {0xe3,0x3e,0xdd,0xe3}, {0x2f,0x71,0x5e,0x2f}, {0x84,0x97,0x13,0x84}, +{0x53,0xf5,0xa6,0x53}, {0xd1,0x68,0xb9,0xd1}, {0x00,0x00,0x00,0x00}, {0xed,0x2c,0xc1,0xed}, +{0x20,0x60,0x40,0x20}, {0xfc,0x1f,0xe3,0xfc}, {0xb1,0xc8,0x79,0xb1}, {0x5b,0xed,0xb6,0x5b}, +{0x6a,0xbe,0xd4,0x6a}, {0xcb,0x46,0x8d,0xcb}, {0xbe,0xd9,0x67,0xbe}, {0x39,0x4b,0x72,0x39}, +{0x4a,0xde,0x94,0x4a}, {0x4c,0xd4,0x98,0x4c}, {0x58,0xe8,0xb0,0x58}, {0xcf,0x4a,0x85,0xcf}, +{0xd0,0x6b,0xbb,0xd0}, {0xef,0x2a,0xc5,0xef}, {0xaa,0xe5,0x4f,0xaa}, {0xfb,0x16,0xed,0xfb}, +{0x43,0xc5,0x86,0x43}, {0x4d,0xd7,0x9a,0x4d}, {0x33,0x55,0x66,0x33}, {0x85,0x94,0x11,0x85}, +{0x45,0xcf,0x8a,0x45}, {0xf9,0x10,0xe9,0xf9}, {0x02,0x06,0x04,0x02}, {0x7f,0x81,0xfe,0x7f}, +{0x50,0xf0,0xa0,0x50}, {0x3c,0x44,0x78,0x3c}, {0x9f,0xba,0x25,0x9f}, {0xa8,0xe3,0x4b,0xa8}, +{0x51,0xf3,0xa2,0x51}, {0xa3,0xfe,0x5d,0xa3}, {0x40,0xc0,0x80,0x40}, {0x8f,0x8a,0x05,0x8f}, +{0x92,0xad,0x3f,0x92}, {0x9d,0xbc,0x21,0x9d}, {0x38,0x48,0x70,0x38}, {0xf5,0x04,0xf1,0xf5}, +{0xbc,0xdf,0x63,0xbc}, {0xb6,0xc1,0x77,0xb6}, {0xda,0x75,0xaf,0xda}, {0x21,0x63,0x42,0x21}, +{0x10,0x30,0x20,0x10}, {0xff,0x1a,0xe5,0xff}, {0xf3,0x0e,0xfd,0xf3}, {0xd2,0x6d,0xbf,0xd2}, +{0xcd,0x4c,0x81,0xcd}, {0x0c,0x14,0x18,0x0c}, {0x13,0x35,0x26,0x13}, {0xec,0x2f,0xc3,0xec}, +{0x5f,0xe1,0xbe,0x5f}, {0x97,0xa2,0x35,0x97}, {0x44,0xcc,0x88,0x44}, {0x17,0x39,0x2e,0x17}, +{0xc4,0x57,0x93,0xc4}, {0xa7,0xf2,0x55,0xa7}, {0x7e,0x82,0xfc,0x7e}, {0x3d,0x47,0x7a,0x3d}, +{0x64,0xac,0xc8,0x64}, {0x5d,0xe7,0xba,0x5d}, {0x19,0x2b,0x32,0x19}, {0x73,0x95,0xe6,0x73}, +{0x60,0xa0,0xc0,0x60}, {0x81,0x98,0x19,0x81}, {0x4f,0xd1,0x9e,0x4f}, {0xdc,0x7f,0xa3,0xdc}, +{0x22,0x66,0x44,0x22}, {0x2a,0x7e,0x54,0x2a}, {0x90,0xab,0x3b,0x90}, {0x88,0x83,0x0b,0x88}, +{0x46,0xca,0x8c,0x46}, {0xee,0x29,0xc7,0xee}, {0xb8,0xd3,0x6b,0xb8}, {0x14,0x3c,0x28,0x14}, +{0xde,0x79,0xa7,0xde}, {0x5e,0xe2,0xbc,0x5e}, {0x0b,0x1d,0x16,0x0b}, {0xdb,0x76,0xad,0xdb}, +{0xe0,0x3b,0xdb,0xe0}, {0x32,0x56,0x64,0x32}, {0x3a,0x4e,0x74,0x3a}, {0x0a,0x1e,0x14,0x0a}, +{0x49,0xdb,0x92,0x49}, {0x06,0x0a,0x0c,0x06}, {0x24,0x6c,0x48,0x24}, {0x5c,0xe4,0xb8,0x5c}, +{0xc2,0x5d,0x9f,0xc2}, {0xd3,0x6e,0xbd,0xd3}, {0xac,0xef,0x43,0xac}, {0x62,0xa6,0xc4,0x62}, +{0x91,0xa8,0x39,0x91}, {0x95,0xa4,0x31,0x95}, {0xe4,0x37,0xd3,0xe4}, {0x79,0x8b,0xf2,0x79}, +{0xe7,0x32,0xd5,0xe7}, {0xc8,0x43,0x8b,0xc8}, {0x37,0x59,0x6e,0x37}, {0x6d,0xb7,0xda,0x6d}, +{0x8d,0x8c,0x01,0x8d}, {0xd5,0x64,0xb1,0xd5}, {0x4e,0xd2,0x9c,0x4e}, {0xa9,0xe0,0x49,0xa9}, +{0x6c,0xb4,0xd8,0x6c}, {0x56,0xfa,0xac,0x56}, {0xf4,0x07,0xf3,0xf4}, {0xea,0x25,0xcf,0xea}, +{0x65,0xaf,0xca,0x65}, {0x7a,0x8e,0xf4,0x7a}, {0xae,0xe9,0x47,0xae}, {0x08,0x18,0x10,0x08}, +{0xba,0xd5,0x6f,0xba}, {0x78,0x88,0xf0,0x78}, {0x25,0x6f,0x4a,0x25}, {0x2e,0x72,0x5c,0x2e}, +{0x1c,0x24,0x38,0x1c}, {0xa6,0xf1,0x57,0xa6}, {0xb4,0xc7,0x73,0xb4}, {0xc6,0x51,0x97,0xc6}, +{0xe8,0x23,0xcb,0xe8}, {0xdd,0x7c,0xa1,0xdd}, {0x74,0x9c,0xe8,0x74}, {0x1f,0x21,0x3e,0x1f}, +{0x4b,0xdd,0x96,0x4b}, {0xbd,0xdc,0x61,0xbd}, {0x8b,0x86,0x0d,0x8b}, {0x8a,0x85,0x0f,0x8a}, +{0x70,0x90,0xe0,0x70}, {0x3e,0x42,0x7c,0x3e}, {0xb5,0xc4,0x71,0xb5}, {0x66,0xaa,0xcc,0x66}, +{0x48,0xd8,0x90,0x48}, {0x03,0x05,0x06,0x03}, {0xf6,0x01,0xf7,0xf6}, {0x0e,0x12,0x1c,0x0e}, +{0x61,0xa3,0xc2,0x61}, {0x35,0x5f,0x6a,0x35}, {0x57,0xf9,0xae,0x57}, {0xb9,0xd0,0x69,0xb9}, +{0x86,0x91,0x17,0x86}, {0xc1,0x58,0x99,0xc1}, {0x1d,0x27,0x3a,0x1d}, {0x9e,0xb9,0x27,0x9e}, +{0xe1,0x38,0xd9,0xe1}, {0xf8,0x13,0xeb,0xf8}, {0x98,0xb3,0x2b,0x98}, {0x11,0x33,0x22,0x11}, +{0x69,0xbb,0xd2,0x69}, {0xd9,0x70,0xa9,0xd9}, {0x8e,0x89,0x07,0x8e}, {0x94,0xa7,0x33,0x94}, +{0x9b,0xb6,0x2d,0x9b}, {0x1e,0x22,0x3c,0x1e}, {0x87,0x92,0x15,0x87}, {0xe9,0x20,0xc9,0xe9}, +{0xce,0x49,0x87,0xce}, {0x55,0xff,0xaa,0x55}, {0x28,0x78,0x50,0x28}, {0xdf,0x7a,0xa5,0xdf}, +{0x8c,0x8f,0x03,0x8c}, {0xa1,0xf8,0x59,0xa1}, {0x89,0x80,0x09,0x89}, {0x0d,0x17,0x1a,0x0d}, +{0xbf,0xda,0x65,0xbf}, {0xe6,0x31,0xd7,0xe6}, {0x42,0xc6,0x84,0x42}, {0x68,0xb8,0xd0,0x68}, +{0x41,0xc3,0x82,0x41}, {0x99,0xb0,0x29,0x99}, {0x2d,0x77,0x5a,0x2d}, {0x0f,0x11,0x1e,0x0f}, +{0xb0,0xcb,0x7b,0xb0}, {0x54,0xfc,0xa8,0x54}, {0xbb,0xd6,0x6d,0xbb}, {0x16,0x3a,0x2c,0x16} + } +}; +#define T3 xT3.xt8 + +static const union xtab xT4 = { + .xt8 = { +{0x63,0x63,0xa5,0xc6}, {0x7c,0x7c,0x84,0xf8}, {0x77,0x77,0x99,0xee}, {0x7b,0x7b,0x8d,0xf6}, +{0xf2,0xf2,0x0d,0xff}, {0x6b,0x6b,0xbd,0xd6}, {0x6f,0x6f,0xb1,0xde}, {0xc5,0xc5,0x54,0x91}, +{0x30,0x30,0x50,0x60}, {0x01,0x01,0x03,0x02}, {0x67,0x67,0xa9,0xce}, {0x2b,0x2b,0x7d,0x56}, +{0xfe,0xfe,0x19,0xe7}, {0xd7,0xd7,0x62,0xb5}, {0xab,0xab,0xe6,0x4d}, {0x76,0x76,0x9a,0xec}, +{0xca,0xca,0x45,0x8f}, {0x82,0x82,0x9d,0x1f}, {0xc9,0xc9,0x40,0x89}, {0x7d,0x7d,0x87,0xfa}, +{0xfa,0xfa,0x15,0xef}, {0x59,0x59,0xeb,0xb2}, {0x47,0x47,0xc9,0x8e}, {0xf0,0xf0,0x0b,0xfb}, +{0xad,0xad,0xec,0x41}, {0xd4,0xd4,0x67,0xb3}, {0xa2,0xa2,0xfd,0x5f}, {0xaf,0xaf,0xea,0x45}, +{0x9c,0x9c,0xbf,0x23}, {0xa4,0xa4,0xf7,0x53}, {0x72,0x72,0x96,0xe4}, {0xc0,0xc0,0x5b,0x9b}, +{0xb7,0xb7,0xc2,0x75}, {0xfd,0xfd,0x1c,0xe1}, {0x93,0x93,0xae,0x3d}, {0x26,0x26,0x6a,0x4c}, +{0x36,0x36,0x5a,0x6c}, {0x3f,0x3f,0x41,0x7e}, {0xf7,0xf7,0x02,0xf5}, {0xcc,0xcc,0x4f,0x83}, +{0x34,0x34,0x5c,0x68}, {0xa5,0xa5,0xf4,0x51}, {0xe5,0xe5,0x34,0xd1}, {0xf1,0xf1,0x08,0xf9}, +{0x71,0x71,0x93,0xe2}, {0xd8,0xd8,0x73,0xab}, {0x31,0x31,0x53,0x62}, {0x15,0x15,0x3f,0x2a}, +{0x04,0x04,0x0c,0x08}, {0xc7,0xc7,0x52,0x95}, {0x23,0x23,0x65,0x46}, {0xc3,0xc3,0x5e,0x9d}, +{0x18,0x18,0x28,0x30}, {0x96,0x96,0xa1,0x37}, {0x05,0x05,0x0f,0x0a}, {0x9a,0x9a,0xb5,0x2f}, +{0x07,0x07,0x09,0x0e}, {0x12,0x12,0x36,0x24}, {0x80,0x80,0x9b,0x1b}, {0xe2,0xe2,0x3d,0xdf}, +{0xeb,0xeb,0x26,0xcd}, {0x27,0x27,0x69,0x4e}, {0xb2,0xb2,0xcd,0x7f}, {0x75,0x75,0x9f,0xea}, +{0x09,0x09,0x1b,0x12}, {0x83,0x83,0x9e,0x1d}, {0x2c,0x2c,0x74,0x58}, {0x1a,0x1a,0x2e,0x34}, +{0x1b,0x1b,0x2d,0x36}, {0x6e,0x6e,0xb2,0xdc}, {0x5a,0x5a,0xee,0xb4}, {0xa0,0xa0,0xfb,0x5b}, +{0x52,0x52,0xf6,0xa4}, {0x3b,0x3b,0x4d,0x76}, {0xd6,0xd6,0x61,0xb7}, {0xb3,0xb3,0xce,0x7d}, +{0x29,0x29,0x7b,0x52}, {0xe3,0xe3,0x3e,0xdd}, {0x2f,0x2f,0x71,0x5e}, {0x84,0x84,0x97,0x13}, +{0x53,0x53,0xf5,0xa6}, {0xd1,0xd1,0x68,0xb9}, {0x00,0x00,0x00,0x00}, {0xed,0xed,0x2c,0xc1}, +{0x20,0x20,0x60,0x40}, {0xfc,0xfc,0x1f,0xe3}, {0xb1,0xb1,0xc8,0x79}, {0x5b,0x5b,0xed,0xb6}, +{0x6a,0x6a,0xbe,0xd4}, {0xcb,0xcb,0x46,0x8d}, {0xbe,0xbe,0xd9,0x67}, {0x39,0x39,0x4b,0x72}, +{0x4a,0x4a,0xde,0x94}, {0x4c,0x4c,0xd4,0x98}, {0x58,0x58,0xe8,0xb0}, {0xcf,0xcf,0x4a,0x85}, +{0xd0,0xd0,0x6b,0xbb}, {0xef,0xef,0x2a,0xc5}, {0xaa,0xaa,0xe5,0x4f}, {0xfb,0xfb,0x16,0xed}, +{0x43,0x43,0xc5,0x86}, {0x4d,0x4d,0xd7,0x9a}, {0x33,0x33,0x55,0x66}, {0x85,0x85,0x94,0x11}, +{0x45,0x45,0xcf,0x8a}, {0xf9,0xf9,0x10,0xe9}, {0x02,0x02,0x06,0x04}, {0x7f,0x7f,0x81,0xfe}, +{0x50,0x50,0xf0,0xa0}, {0x3c,0x3c,0x44,0x78}, {0x9f,0x9f,0xba,0x25}, {0xa8,0xa8,0xe3,0x4b}, +{0x51,0x51,0xf3,0xa2}, {0xa3,0xa3,0xfe,0x5d}, {0x40,0x40,0xc0,0x80}, {0x8f,0x8f,0x8a,0x05}, +{0x92,0x92,0xad,0x3f}, {0x9d,0x9d,0xbc,0x21}, {0x38,0x38,0x48,0x70}, {0xf5,0xf5,0x04,0xf1}, +{0xbc,0xbc,0xdf,0x63}, {0xb6,0xb6,0xc1,0x77}, {0xda,0xda,0x75,0xaf}, {0x21,0x21,0x63,0x42}, +{0x10,0x10,0x30,0x20}, {0xff,0xff,0x1a,0xe5}, {0xf3,0xf3,0x0e,0xfd}, {0xd2,0xd2,0x6d,0xbf}, +{0xcd,0xcd,0x4c,0x81}, {0x0c,0x0c,0x14,0x18}, {0x13,0x13,0x35,0x26}, {0xec,0xec,0x2f,0xc3}, +{0x5f,0x5f,0xe1,0xbe}, {0x97,0x97,0xa2,0x35}, {0x44,0x44,0xcc,0x88}, {0x17,0x17,0x39,0x2e}, +{0xc4,0xc4,0x57,0x93}, {0xa7,0xa7,0xf2,0x55}, {0x7e,0x7e,0x82,0xfc}, {0x3d,0x3d,0x47,0x7a}, +{0x64,0x64,0xac,0xc8}, {0x5d,0x5d,0xe7,0xba}, {0x19,0x19,0x2b,0x32}, {0x73,0x73,0x95,0xe6}, +{0x60,0x60,0xa0,0xc0}, {0x81,0x81,0x98,0x19}, {0x4f,0x4f,0xd1,0x9e}, {0xdc,0xdc,0x7f,0xa3}, +{0x22,0x22,0x66,0x44}, {0x2a,0x2a,0x7e,0x54}, {0x90,0x90,0xab,0x3b}, {0x88,0x88,0x83,0x0b}, +{0x46,0x46,0xca,0x8c}, {0xee,0xee,0x29,0xc7}, {0xb8,0xb8,0xd3,0x6b}, {0x14,0x14,0x3c,0x28}, +{0xde,0xde,0x79,0xa7}, {0x5e,0x5e,0xe2,0xbc}, {0x0b,0x0b,0x1d,0x16}, {0xdb,0xdb,0x76,0xad}, +{0xe0,0xe0,0x3b,0xdb}, {0x32,0x32,0x56,0x64}, {0x3a,0x3a,0x4e,0x74}, {0x0a,0x0a,0x1e,0x14}, +{0x49,0x49,0xdb,0x92}, {0x06,0x06,0x0a,0x0c}, {0x24,0x24,0x6c,0x48}, {0x5c,0x5c,0xe4,0xb8}, +{0xc2,0xc2,0x5d,0x9f}, {0xd3,0xd3,0x6e,0xbd}, {0xac,0xac,0xef,0x43}, {0x62,0x62,0xa6,0xc4}, +{0x91,0x91,0xa8,0x39}, {0x95,0x95,0xa4,0x31}, {0xe4,0xe4,0x37,0xd3}, {0x79,0x79,0x8b,0xf2}, +{0xe7,0xe7,0x32,0xd5}, {0xc8,0xc8,0x43,0x8b}, {0x37,0x37,0x59,0x6e}, {0x6d,0x6d,0xb7,0xda}, +{0x8d,0x8d,0x8c,0x01}, {0xd5,0xd5,0x64,0xb1}, {0x4e,0x4e,0xd2,0x9c}, {0xa9,0xa9,0xe0,0x49}, +{0x6c,0x6c,0xb4,0xd8}, {0x56,0x56,0xfa,0xac}, {0xf4,0xf4,0x07,0xf3}, {0xea,0xea,0x25,0xcf}, +{0x65,0x65,0xaf,0xca}, {0x7a,0x7a,0x8e,0xf4}, {0xae,0xae,0xe9,0x47}, {0x08,0x08,0x18,0x10}, +{0xba,0xba,0xd5,0x6f}, {0x78,0x78,0x88,0xf0}, {0x25,0x25,0x6f,0x4a}, {0x2e,0x2e,0x72,0x5c}, +{0x1c,0x1c,0x24,0x38}, {0xa6,0xa6,0xf1,0x57}, {0xb4,0xb4,0xc7,0x73}, {0xc6,0xc6,0x51,0x97}, +{0xe8,0xe8,0x23,0xcb}, {0xdd,0xdd,0x7c,0xa1}, {0x74,0x74,0x9c,0xe8}, {0x1f,0x1f,0x21,0x3e}, +{0x4b,0x4b,0xdd,0x96}, {0xbd,0xbd,0xdc,0x61}, {0x8b,0x8b,0x86,0x0d}, {0x8a,0x8a,0x85,0x0f}, +{0x70,0x70,0x90,0xe0}, {0x3e,0x3e,0x42,0x7c}, {0xb5,0xb5,0xc4,0x71}, {0x66,0x66,0xaa,0xcc}, +{0x48,0x48,0xd8,0x90}, {0x03,0x03,0x05,0x06}, {0xf6,0xf6,0x01,0xf7}, {0x0e,0x0e,0x12,0x1c}, +{0x61,0x61,0xa3,0xc2}, {0x35,0x35,0x5f,0x6a}, {0x57,0x57,0xf9,0xae}, {0xb9,0xb9,0xd0,0x69}, +{0x86,0x86,0x91,0x17}, {0xc1,0xc1,0x58,0x99}, {0x1d,0x1d,0x27,0x3a}, {0x9e,0x9e,0xb9,0x27}, +{0xe1,0xe1,0x38,0xd9}, {0xf8,0xf8,0x13,0xeb}, {0x98,0x98,0xb3,0x2b}, {0x11,0x11,0x33,0x22}, +{0x69,0x69,0xbb,0xd2}, {0xd9,0xd9,0x70,0xa9}, {0x8e,0x8e,0x89,0x07}, {0x94,0x94,0xa7,0x33}, +{0x9b,0x9b,0xb6,0x2d}, {0x1e,0x1e,0x22,0x3c}, {0x87,0x87,0x92,0x15}, {0xe9,0xe9,0x20,0xc9}, +{0xce,0xce,0x49,0x87}, {0x55,0x55,0xff,0xaa}, {0x28,0x28,0x78,0x50}, {0xdf,0xdf,0x7a,0xa5}, +{0x8c,0x8c,0x8f,0x03}, {0xa1,0xa1,0xf8,0x59}, {0x89,0x89,0x80,0x09}, {0x0d,0x0d,0x17,0x1a}, +{0xbf,0xbf,0xda,0x65}, {0xe6,0xe6,0x31,0xd7}, {0x42,0x42,0xc6,0x84}, {0x68,0x68,0xb8,0xd0}, +{0x41,0x41,0xc3,0x82}, {0x99,0x99,0xb0,0x29}, {0x2d,0x2d,0x77,0x5a}, {0x0f,0x0f,0x11,0x1e}, +{0xb0,0xb0,0xcb,0x7b}, {0x54,0x54,0xfc,0xa8}, {0xbb,0xbb,0xd6,0x6d}, {0x16,0x16,0x3a,0x2c} + } +}; +#define T4 xT4.xt8 + +static const union xtab xT5 = { + .xt8 = { +{0x51,0xf4,0xa7,0x50}, {0x7e,0x41,0x65,0x53}, {0x1a,0x17,0xa4,0xc3}, {0x3a,0x27,0x5e,0x96}, +{0x3b,0xab,0x6b,0xcb}, {0x1f,0x9d,0x45,0xf1}, {0xac,0xfa,0x58,0xab}, {0x4b,0xe3,0x03,0x93}, +{0x20,0x30,0xfa,0x55}, {0xad,0x76,0x6d,0xf6}, {0x88,0xcc,0x76,0x91}, {0xf5,0x02,0x4c,0x25}, +{0x4f,0xe5,0xd7,0xfc}, {0xc5,0x2a,0xcb,0xd7}, {0x26,0x35,0x44,0x80}, {0xb5,0x62,0xa3,0x8f}, +{0xde,0xb1,0x5a,0x49}, {0x25,0xba,0x1b,0x67}, {0x45,0xea,0x0e,0x98}, {0x5d,0xfe,0xc0,0xe1}, +{0xc3,0x2f,0x75,0x02}, {0x81,0x4c,0xf0,0x12}, {0x8d,0x46,0x97,0xa3}, {0x6b,0xd3,0xf9,0xc6}, +{0x03,0x8f,0x5f,0xe7}, {0x15,0x92,0x9c,0x95}, {0xbf,0x6d,0x7a,0xeb}, {0x95,0x52,0x59,0xda}, +{0xd4,0xbe,0x83,0x2d}, {0x58,0x74,0x21,0xd3}, {0x49,0xe0,0x69,0x29}, {0x8e,0xc9,0xc8,0x44}, +{0x75,0xc2,0x89,0x6a}, {0xf4,0x8e,0x79,0x78}, {0x99,0x58,0x3e,0x6b}, {0x27,0xb9,0x71,0xdd}, +{0xbe,0xe1,0x4f,0xb6}, {0xf0,0x88,0xad,0x17}, {0xc9,0x20,0xac,0x66}, {0x7d,0xce,0x3a,0xb4}, +{0x63,0xdf,0x4a,0x18}, {0xe5,0x1a,0x31,0x82}, {0x97,0x51,0x33,0x60}, {0x62,0x53,0x7f,0x45}, +{0xb1,0x64,0x77,0xe0}, {0xbb,0x6b,0xae,0x84}, {0xfe,0x81,0xa0,0x1c}, {0xf9,0x08,0x2b,0x94}, +{0x70,0x48,0x68,0x58}, {0x8f,0x45,0xfd,0x19}, {0x94,0xde,0x6c,0x87}, {0x52,0x7b,0xf8,0xb7}, +{0xab,0x73,0xd3,0x23}, {0x72,0x4b,0x02,0xe2}, {0xe3,0x1f,0x8f,0x57}, {0x66,0x55,0xab,0x2a}, +{0xb2,0xeb,0x28,0x07}, {0x2f,0xb5,0xc2,0x03}, {0x86,0xc5,0x7b,0x9a}, {0xd3,0x37,0x08,0xa5}, +{0x30,0x28,0x87,0xf2}, {0x23,0xbf,0xa5,0xb2}, {0x02,0x03,0x6a,0xba}, {0xed,0x16,0x82,0x5c}, +{0x8a,0xcf,0x1c,0x2b}, {0xa7,0x79,0xb4,0x92}, {0xf3,0x07,0xf2,0xf0}, {0x4e,0x69,0xe2,0xa1}, +{0x65,0xda,0xf4,0xcd}, {0x06,0x05,0xbe,0xd5}, {0xd1,0x34,0x62,0x1f}, {0xc4,0xa6,0xfe,0x8a}, +{0x34,0x2e,0x53,0x9d}, {0xa2,0xf3,0x55,0xa0}, {0x05,0x8a,0xe1,0x32}, {0xa4,0xf6,0xeb,0x75}, +{0x0b,0x83,0xec,0x39}, {0x40,0x60,0xef,0xaa}, {0x5e,0x71,0x9f,0x06}, {0xbd,0x6e,0x10,0x51}, +{0x3e,0x21,0x8a,0xf9}, {0x96,0xdd,0x06,0x3d}, {0xdd,0x3e,0x05,0xae}, {0x4d,0xe6,0xbd,0x46}, +{0x91,0x54,0x8d,0xb5}, {0x71,0xc4,0x5d,0x05}, {0x04,0x06,0xd4,0x6f}, {0x60,0x50,0x15,0xff}, +{0x19,0x98,0xfb,0x24}, {0xd6,0xbd,0xe9,0x97}, {0x89,0x40,0x43,0xcc}, {0x67,0xd9,0x9e,0x77}, +{0xb0,0xe8,0x42,0xbd}, {0x07,0x89,0x8b,0x88}, {0xe7,0x19,0x5b,0x38}, {0x79,0xc8,0xee,0xdb}, +{0xa1,0x7c,0x0a,0x47}, {0x7c,0x42,0x0f,0xe9}, {0xf8,0x84,0x1e,0xc9}, {0x00,0x00,0x00,0x00}, +{0x09,0x80,0x86,0x83}, {0x32,0x2b,0xed,0x48}, {0x1e,0x11,0x70,0xac}, {0x6c,0x5a,0x72,0x4e}, +{0xfd,0x0e,0xff,0xfb}, {0x0f,0x85,0x38,0x56}, {0x3d,0xae,0xd5,0x1e}, {0x36,0x2d,0x39,0x27}, +{0x0a,0x0f,0xd9,0x64}, {0x68,0x5c,0xa6,0x21}, {0x9b,0x5b,0x54,0xd1}, {0x24,0x36,0x2e,0x3a}, +{0x0c,0x0a,0x67,0xb1}, {0x93,0x57,0xe7,0x0f}, {0xb4,0xee,0x96,0xd2}, {0x1b,0x9b,0x91,0x9e}, +{0x80,0xc0,0xc5,0x4f}, {0x61,0xdc,0x20,0xa2}, {0x5a,0x77,0x4b,0x69}, {0x1c,0x12,0x1a,0x16}, +{0xe2,0x93,0xba,0x0a}, {0xc0,0xa0,0x2a,0xe5}, {0x3c,0x22,0xe0,0x43}, {0x12,0x1b,0x17,0x1d}, +{0x0e,0x09,0x0d,0x0b}, {0xf2,0x8b,0xc7,0xad}, {0x2d,0xb6,0xa8,0xb9}, {0x14,0x1e,0xa9,0xc8}, +{0x57,0xf1,0x19,0x85}, {0xaf,0x75,0x07,0x4c}, {0xee,0x99,0xdd,0xbb}, {0xa3,0x7f,0x60,0xfd}, +{0xf7,0x01,0x26,0x9f}, {0x5c,0x72,0xf5,0xbc}, {0x44,0x66,0x3b,0xc5}, {0x5b,0xfb,0x7e,0x34}, +{0x8b,0x43,0x29,0x76}, {0xcb,0x23,0xc6,0xdc}, {0xb6,0xed,0xfc,0x68}, {0xb8,0xe4,0xf1,0x63}, +{0xd7,0x31,0xdc,0xca}, {0x42,0x63,0x85,0x10}, {0x13,0x97,0x22,0x40}, {0x84,0xc6,0x11,0x20}, +{0x85,0x4a,0x24,0x7d}, {0xd2,0xbb,0x3d,0xf8}, {0xae,0xf9,0x32,0x11}, {0xc7,0x29,0xa1,0x6d}, +{0x1d,0x9e,0x2f,0x4b}, {0xdc,0xb2,0x30,0xf3}, {0x0d,0x86,0x52,0xec}, {0x77,0xc1,0xe3,0xd0}, +{0x2b,0xb3,0x16,0x6c}, {0xa9,0x70,0xb9,0x99}, {0x11,0x94,0x48,0xfa}, {0x47,0xe9,0x64,0x22}, +{0xa8,0xfc,0x8c,0xc4}, {0xa0,0xf0,0x3f,0x1a}, {0x56,0x7d,0x2c,0xd8}, {0x22,0x33,0x90,0xef}, +{0x87,0x49,0x4e,0xc7}, {0xd9,0x38,0xd1,0xc1}, {0x8c,0xca,0xa2,0xfe}, {0x98,0xd4,0x0b,0x36}, +{0xa6,0xf5,0x81,0xcf}, {0xa5,0x7a,0xde,0x28}, {0xda,0xb7,0x8e,0x26}, {0x3f,0xad,0xbf,0xa4}, +{0x2c,0x3a,0x9d,0xe4}, {0x50,0x78,0x92,0x0d}, {0x6a,0x5f,0xcc,0x9b}, {0x54,0x7e,0x46,0x62}, +{0xf6,0x8d,0x13,0xc2}, {0x90,0xd8,0xb8,0xe8}, {0x2e,0x39,0xf7,0x5e}, {0x82,0xc3,0xaf,0xf5}, +{0x9f,0x5d,0x80,0xbe}, {0x69,0xd0,0x93,0x7c}, {0x6f,0xd5,0x2d,0xa9}, {0xcf,0x25,0x12,0xb3}, +{0xc8,0xac,0x99,0x3b}, {0x10,0x18,0x7d,0xa7}, {0xe8,0x9c,0x63,0x6e}, {0xdb,0x3b,0xbb,0x7b}, +{0xcd,0x26,0x78,0x09}, {0x6e,0x59,0x18,0xf4}, {0xec,0x9a,0xb7,0x01}, {0x83,0x4f,0x9a,0xa8}, +{0xe6,0x95,0x6e,0x65}, {0xaa,0xff,0xe6,0x7e}, {0x21,0xbc,0xcf,0x08}, {0xef,0x15,0xe8,0xe6}, +{0xba,0xe7,0x9b,0xd9}, {0x4a,0x6f,0x36,0xce}, {0xea,0x9f,0x09,0xd4}, {0x29,0xb0,0x7c,0xd6}, +{0x31,0xa4,0xb2,0xaf}, {0x2a,0x3f,0x23,0x31}, {0xc6,0xa5,0x94,0x30}, {0x35,0xa2,0x66,0xc0}, +{0x74,0x4e,0xbc,0x37}, {0xfc,0x82,0xca,0xa6}, {0xe0,0x90,0xd0,0xb0}, {0x33,0xa7,0xd8,0x15}, +{0xf1,0x04,0x98,0x4a}, {0x41,0xec,0xda,0xf7}, {0x7f,0xcd,0x50,0x0e}, {0x17,0x91,0xf6,0x2f}, +{0x76,0x4d,0xd6,0x8d}, {0x43,0xef,0xb0,0x4d}, {0xcc,0xaa,0x4d,0x54}, {0xe4,0x96,0x04,0xdf}, +{0x9e,0xd1,0xb5,0xe3}, {0x4c,0x6a,0x88,0x1b}, {0xc1,0x2c,0x1f,0xb8}, {0x46,0x65,0x51,0x7f}, +{0x9d,0x5e,0xea,0x04}, {0x01,0x8c,0x35,0x5d}, {0xfa,0x87,0x74,0x73}, {0xfb,0x0b,0x41,0x2e}, +{0xb3,0x67,0x1d,0x5a}, {0x92,0xdb,0xd2,0x52}, {0xe9,0x10,0x56,0x33}, {0x6d,0xd6,0x47,0x13}, +{0x9a,0xd7,0x61,0x8c}, {0x37,0xa1,0x0c,0x7a}, {0x59,0xf8,0x14,0x8e}, {0xeb,0x13,0x3c,0x89}, +{0xce,0xa9,0x27,0xee}, {0xb7,0x61,0xc9,0x35}, {0xe1,0x1c,0xe5,0xed}, {0x7a,0x47,0xb1,0x3c}, +{0x9c,0xd2,0xdf,0x59}, {0x55,0xf2,0x73,0x3f}, {0x18,0x14,0xce,0x79}, {0x73,0xc7,0x37,0xbf}, +{0x53,0xf7,0xcd,0xea}, {0x5f,0xfd,0xaa,0x5b}, {0xdf,0x3d,0x6f,0x14}, {0x78,0x44,0xdb,0x86}, +{0xca,0xaf,0xf3,0x81}, {0xb9,0x68,0xc4,0x3e}, {0x38,0x24,0x34,0x2c}, {0xc2,0xa3,0x40,0x5f}, +{0x16,0x1d,0xc3,0x72}, {0xbc,0xe2,0x25,0x0c}, {0x28,0x3c,0x49,0x8b}, {0xff,0x0d,0x95,0x41}, +{0x39,0xa8,0x01,0x71}, {0x08,0x0c,0xb3,0xde}, {0xd8,0xb4,0xe4,0x9c}, {0x64,0x56,0xc1,0x90}, +{0x7b,0xcb,0x84,0x61}, {0xd5,0x32,0xb6,0x70}, {0x48,0x6c,0x5c,0x74}, {0xd0,0xb8,0x57,0x42} + } +}; +#define T5 xT5.xt8 + +static const union xtab xT6 = { + .xt8 = { +{0x50,0x51,0xf4,0xa7}, {0x53,0x7e,0x41,0x65}, {0xc3,0x1a,0x17,0xa4}, {0x96,0x3a,0x27,0x5e}, +{0xcb,0x3b,0xab,0x6b}, {0xf1,0x1f,0x9d,0x45}, {0xab,0xac,0xfa,0x58}, {0x93,0x4b,0xe3,0x03}, +{0x55,0x20,0x30,0xfa}, {0xf6,0xad,0x76,0x6d}, {0x91,0x88,0xcc,0x76}, {0x25,0xf5,0x02,0x4c}, +{0xfc,0x4f,0xe5,0xd7}, {0xd7,0xc5,0x2a,0xcb}, {0x80,0x26,0x35,0x44}, {0x8f,0xb5,0x62,0xa3}, +{0x49,0xde,0xb1,0x5a}, {0x67,0x25,0xba,0x1b}, {0x98,0x45,0xea,0x0e}, {0xe1,0x5d,0xfe,0xc0}, +{0x02,0xc3,0x2f,0x75}, {0x12,0x81,0x4c,0xf0}, {0xa3,0x8d,0x46,0x97}, {0xc6,0x6b,0xd3,0xf9}, +{0xe7,0x03,0x8f,0x5f}, {0x95,0x15,0x92,0x9c}, {0xeb,0xbf,0x6d,0x7a}, {0xda,0x95,0x52,0x59}, +{0x2d,0xd4,0xbe,0x83}, {0xd3,0x58,0x74,0x21}, {0x29,0x49,0xe0,0x69}, {0x44,0x8e,0xc9,0xc8}, +{0x6a,0x75,0xc2,0x89}, {0x78,0xf4,0x8e,0x79}, {0x6b,0x99,0x58,0x3e}, {0xdd,0x27,0xb9,0x71}, +{0xb6,0xbe,0xe1,0x4f}, {0x17,0xf0,0x88,0xad}, {0x66,0xc9,0x20,0xac}, {0xb4,0x7d,0xce,0x3a}, +{0x18,0x63,0xdf,0x4a}, {0x82,0xe5,0x1a,0x31}, {0x60,0x97,0x51,0x33}, {0x45,0x62,0x53,0x7f}, +{0xe0,0xb1,0x64,0x77}, {0x84,0xbb,0x6b,0xae}, {0x1c,0xfe,0x81,0xa0}, {0x94,0xf9,0x08,0x2b}, +{0x58,0x70,0x48,0x68}, {0x19,0x8f,0x45,0xfd}, {0x87,0x94,0xde,0x6c}, {0xb7,0x52,0x7b,0xf8}, +{0x23,0xab,0x73,0xd3}, {0xe2,0x72,0x4b,0x02}, {0x57,0xe3,0x1f,0x8f}, {0x2a,0x66,0x55,0xab}, +{0x07,0xb2,0xeb,0x28}, {0x03,0x2f,0xb5,0xc2}, {0x9a,0x86,0xc5,0x7b}, {0xa5,0xd3,0x37,0x08}, +{0xf2,0x30,0x28,0x87}, {0xb2,0x23,0xbf,0xa5}, {0xba,0x02,0x03,0x6a}, {0x5c,0xed,0x16,0x82}, +{0x2b,0x8a,0xcf,0x1c}, {0x92,0xa7,0x79,0xb4}, {0xf0,0xf3,0x07,0xf2}, {0xa1,0x4e,0x69,0xe2}, +{0xcd,0x65,0xda,0xf4}, {0xd5,0x06,0x05,0xbe}, {0x1f,0xd1,0x34,0x62}, {0x8a,0xc4,0xa6,0xfe}, +{0x9d,0x34,0x2e,0x53}, {0xa0,0xa2,0xf3,0x55}, {0x32,0x05,0x8a,0xe1}, {0x75,0xa4,0xf6,0xeb}, +{0x39,0x0b,0x83,0xec}, {0xaa,0x40,0x60,0xef}, {0x06,0x5e,0x71,0x9f}, {0x51,0xbd,0x6e,0x10}, +{0xf9,0x3e,0x21,0x8a}, {0x3d,0x96,0xdd,0x06}, {0xae,0xdd,0x3e,0x05}, {0x46,0x4d,0xe6,0xbd}, +{0xb5,0x91,0x54,0x8d}, {0x05,0x71,0xc4,0x5d}, {0x6f,0x04,0x06,0xd4}, {0xff,0x60,0x50,0x15}, +{0x24,0x19,0x98,0xfb}, {0x97,0xd6,0xbd,0xe9}, {0xcc,0x89,0x40,0x43}, {0x77,0x67,0xd9,0x9e}, +{0xbd,0xb0,0xe8,0x42}, {0x88,0x07,0x89,0x8b}, {0x38,0xe7,0x19,0x5b}, {0xdb,0x79,0xc8,0xee}, +{0x47,0xa1,0x7c,0x0a}, {0xe9,0x7c,0x42,0x0f}, {0xc9,0xf8,0x84,0x1e}, {0x00,0x00,0x00,0x00}, +{0x83,0x09,0x80,0x86}, {0x48,0x32,0x2b,0xed}, {0xac,0x1e,0x11,0x70}, {0x4e,0x6c,0x5a,0x72}, +{0xfb,0xfd,0x0e,0xff}, {0x56,0x0f,0x85,0x38}, {0x1e,0x3d,0xae,0xd5}, {0x27,0x36,0x2d,0x39}, +{0x64,0x0a,0x0f,0xd9}, {0x21,0x68,0x5c,0xa6}, {0xd1,0x9b,0x5b,0x54}, {0x3a,0x24,0x36,0x2e}, +{0xb1,0x0c,0x0a,0x67}, {0x0f,0x93,0x57,0xe7}, {0xd2,0xb4,0xee,0x96}, {0x9e,0x1b,0x9b,0x91}, +{0x4f,0x80,0xc0,0xc5}, {0xa2,0x61,0xdc,0x20}, {0x69,0x5a,0x77,0x4b}, {0x16,0x1c,0x12,0x1a}, +{0x0a,0xe2,0x93,0xba}, {0xe5,0xc0,0xa0,0x2a}, {0x43,0x3c,0x22,0xe0}, {0x1d,0x12,0x1b,0x17}, +{0x0b,0x0e,0x09,0x0d}, {0xad,0xf2,0x8b,0xc7}, {0xb9,0x2d,0xb6,0xa8}, {0xc8,0x14,0x1e,0xa9}, +{0x85,0x57,0xf1,0x19}, {0x4c,0xaf,0x75,0x07}, {0xbb,0xee,0x99,0xdd}, {0xfd,0xa3,0x7f,0x60}, +{0x9f,0xf7,0x01,0x26}, {0xbc,0x5c,0x72,0xf5}, {0xc5,0x44,0x66,0x3b}, {0x34,0x5b,0xfb,0x7e}, +{0x76,0x8b,0x43,0x29}, {0xdc,0xcb,0x23,0xc6}, {0x68,0xb6,0xed,0xfc}, {0x63,0xb8,0xe4,0xf1}, +{0xca,0xd7,0x31,0xdc}, {0x10,0x42,0x63,0x85}, {0x40,0x13,0x97,0x22}, {0x20,0x84,0xc6,0x11}, +{0x7d,0x85,0x4a,0x24}, {0xf8,0xd2,0xbb,0x3d}, {0x11,0xae,0xf9,0x32}, {0x6d,0xc7,0x29,0xa1}, +{0x4b,0x1d,0x9e,0x2f}, {0xf3,0xdc,0xb2,0x30}, {0xec,0x0d,0x86,0x52}, {0xd0,0x77,0xc1,0xe3}, +{0x6c,0x2b,0xb3,0x16}, {0x99,0xa9,0x70,0xb9}, {0xfa,0x11,0x94,0x48}, {0x22,0x47,0xe9,0x64}, +{0xc4,0xa8,0xfc,0x8c}, {0x1a,0xa0,0xf0,0x3f}, {0xd8,0x56,0x7d,0x2c}, {0xef,0x22,0x33,0x90}, +{0xc7,0x87,0x49,0x4e}, {0xc1,0xd9,0x38,0xd1}, {0xfe,0x8c,0xca,0xa2}, {0x36,0x98,0xd4,0x0b}, +{0xcf,0xa6,0xf5,0x81}, {0x28,0xa5,0x7a,0xde}, {0x26,0xda,0xb7,0x8e}, {0xa4,0x3f,0xad,0xbf}, +{0xe4,0x2c,0x3a,0x9d}, {0x0d,0x50,0x78,0x92}, {0x9b,0x6a,0x5f,0xcc}, {0x62,0x54,0x7e,0x46}, +{0xc2,0xf6,0x8d,0x13}, {0xe8,0x90,0xd8,0xb8}, {0x5e,0x2e,0x39,0xf7}, {0xf5,0x82,0xc3,0xaf}, +{0xbe,0x9f,0x5d,0x80}, {0x7c,0x69,0xd0,0x93}, {0xa9,0x6f,0xd5,0x2d}, {0xb3,0xcf,0x25,0x12}, +{0x3b,0xc8,0xac,0x99}, {0xa7,0x10,0x18,0x7d}, {0x6e,0xe8,0x9c,0x63}, {0x7b,0xdb,0x3b,0xbb}, +{0x09,0xcd,0x26,0x78}, {0xf4,0x6e,0x59,0x18}, {0x01,0xec,0x9a,0xb7}, {0xa8,0x83,0x4f,0x9a}, +{0x65,0xe6,0x95,0x6e}, {0x7e,0xaa,0xff,0xe6}, {0x08,0x21,0xbc,0xcf}, {0xe6,0xef,0x15,0xe8}, +{0xd9,0xba,0xe7,0x9b}, {0xce,0x4a,0x6f,0x36}, {0xd4,0xea,0x9f,0x09}, {0xd6,0x29,0xb0,0x7c}, +{0xaf,0x31,0xa4,0xb2}, {0x31,0x2a,0x3f,0x23}, {0x30,0xc6,0xa5,0x94}, {0xc0,0x35,0xa2,0x66}, +{0x37,0x74,0x4e,0xbc}, {0xa6,0xfc,0x82,0xca}, {0xb0,0xe0,0x90,0xd0}, {0x15,0x33,0xa7,0xd8}, +{0x4a,0xf1,0x04,0x98}, {0xf7,0x41,0xec,0xda}, {0x0e,0x7f,0xcd,0x50}, {0x2f,0x17,0x91,0xf6}, +{0x8d,0x76,0x4d,0xd6}, {0x4d,0x43,0xef,0xb0}, {0x54,0xcc,0xaa,0x4d}, {0xdf,0xe4,0x96,0x04}, +{0xe3,0x9e,0xd1,0xb5}, {0x1b,0x4c,0x6a,0x88}, {0xb8,0xc1,0x2c,0x1f}, {0x7f,0x46,0x65,0x51}, +{0x04,0x9d,0x5e,0xea}, {0x5d,0x01,0x8c,0x35}, {0x73,0xfa,0x87,0x74}, {0x2e,0xfb,0x0b,0x41}, +{0x5a,0xb3,0x67,0x1d}, {0x52,0x92,0xdb,0xd2}, {0x33,0xe9,0x10,0x56}, {0x13,0x6d,0xd6,0x47}, +{0x8c,0x9a,0xd7,0x61}, {0x7a,0x37,0xa1,0x0c}, {0x8e,0x59,0xf8,0x14}, {0x89,0xeb,0x13,0x3c}, +{0xee,0xce,0xa9,0x27}, {0x35,0xb7,0x61,0xc9}, {0xed,0xe1,0x1c,0xe5}, {0x3c,0x7a,0x47,0xb1}, +{0x59,0x9c,0xd2,0xdf}, {0x3f,0x55,0xf2,0x73}, {0x79,0x18,0x14,0xce}, {0xbf,0x73,0xc7,0x37}, +{0xea,0x53,0xf7,0xcd}, {0x5b,0x5f,0xfd,0xaa}, {0x14,0xdf,0x3d,0x6f}, {0x86,0x78,0x44,0xdb}, +{0x81,0xca,0xaf,0xf3}, {0x3e,0xb9,0x68,0xc4}, {0x2c,0x38,0x24,0x34}, {0x5f,0xc2,0xa3,0x40}, +{0x72,0x16,0x1d,0xc3}, {0x0c,0xbc,0xe2,0x25}, {0x8b,0x28,0x3c,0x49}, {0x41,0xff,0x0d,0x95}, +{0x71,0x39,0xa8,0x01}, {0xde,0x08,0x0c,0xb3}, {0x9c,0xd8,0xb4,0xe4}, {0x90,0x64,0x56,0xc1}, +{0x61,0x7b,0xcb,0x84}, {0x70,0xd5,0x32,0xb6}, {0x74,0x48,0x6c,0x5c}, {0x42,0xd0,0xb8,0x57} + } +}; +#define T6 xT6.xt8 + +static const union xtab xT7 = { + .xt8 = { +{0xa7,0x50,0x51,0xf4}, {0x65,0x53,0x7e,0x41}, {0xa4,0xc3,0x1a,0x17}, {0x5e,0x96,0x3a,0x27}, +{0x6b,0xcb,0x3b,0xab}, {0x45,0xf1,0x1f,0x9d}, {0x58,0xab,0xac,0xfa}, {0x03,0x93,0x4b,0xe3}, +{0xfa,0x55,0x20,0x30}, {0x6d,0xf6,0xad,0x76}, {0x76,0x91,0x88,0xcc}, {0x4c,0x25,0xf5,0x02}, +{0xd7,0xfc,0x4f,0xe5}, {0xcb,0xd7,0xc5,0x2a}, {0x44,0x80,0x26,0x35}, {0xa3,0x8f,0xb5,0x62}, +{0x5a,0x49,0xde,0xb1}, {0x1b,0x67,0x25,0xba}, {0x0e,0x98,0x45,0xea}, {0xc0,0xe1,0x5d,0xfe}, +{0x75,0x02,0xc3,0x2f}, {0xf0,0x12,0x81,0x4c}, {0x97,0xa3,0x8d,0x46}, {0xf9,0xc6,0x6b,0xd3}, +{0x5f,0xe7,0x03,0x8f}, {0x9c,0x95,0x15,0x92}, {0x7a,0xeb,0xbf,0x6d}, {0x59,0xda,0x95,0x52}, +{0x83,0x2d,0xd4,0xbe}, {0x21,0xd3,0x58,0x74}, {0x69,0x29,0x49,0xe0}, {0xc8,0x44,0x8e,0xc9}, +{0x89,0x6a,0x75,0xc2}, {0x79,0x78,0xf4,0x8e}, {0x3e,0x6b,0x99,0x58}, {0x71,0xdd,0x27,0xb9}, +{0x4f,0xb6,0xbe,0xe1}, {0xad,0x17,0xf0,0x88}, {0xac,0x66,0xc9,0x20}, {0x3a,0xb4,0x7d,0xce}, +{0x4a,0x18,0x63,0xdf}, {0x31,0x82,0xe5,0x1a}, {0x33,0x60,0x97,0x51}, {0x7f,0x45,0x62,0x53}, +{0x77,0xe0,0xb1,0x64}, {0xae,0x84,0xbb,0x6b}, {0xa0,0x1c,0xfe,0x81}, {0x2b,0x94,0xf9,0x08}, +{0x68,0x58,0x70,0x48}, {0xfd,0x19,0x8f,0x45}, {0x6c,0x87,0x94,0xde}, {0xf8,0xb7,0x52,0x7b}, +{0xd3,0x23,0xab,0x73}, {0x02,0xe2,0x72,0x4b}, {0x8f,0x57,0xe3,0x1f}, {0xab,0x2a,0x66,0x55}, +{0x28,0x07,0xb2,0xeb}, {0xc2,0x03,0x2f,0xb5}, {0x7b,0x9a,0x86,0xc5}, {0x08,0xa5,0xd3,0x37}, +{0x87,0xf2,0x30,0x28}, {0xa5,0xb2,0x23,0xbf}, {0x6a,0xba,0x02,0x03}, {0x82,0x5c,0xed,0x16}, +{0x1c,0x2b,0x8a,0xcf}, {0xb4,0x92,0xa7,0x79}, {0xf2,0xf0,0xf3,0x07}, {0xe2,0xa1,0x4e,0x69}, +{0xf4,0xcd,0x65,0xda}, {0xbe,0xd5,0x06,0x05}, {0x62,0x1f,0xd1,0x34}, {0xfe,0x8a,0xc4,0xa6}, +{0x53,0x9d,0x34,0x2e}, {0x55,0xa0,0xa2,0xf3}, {0xe1,0x32,0x05,0x8a}, {0xeb,0x75,0xa4,0xf6}, +{0xec,0x39,0x0b,0x83}, {0xef,0xaa,0x40,0x60}, {0x9f,0x06,0x5e,0x71}, {0x10,0x51,0xbd,0x6e}, +{0x8a,0xf9,0x3e,0x21}, {0x06,0x3d,0x96,0xdd}, {0x05,0xae,0xdd,0x3e}, {0xbd,0x46,0x4d,0xe6}, +{0x8d,0xb5,0x91,0x54}, {0x5d,0x05,0x71,0xc4}, {0xd4,0x6f,0x04,0x06}, {0x15,0xff,0x60,0x50}, +{0xfb,0x24,0x19,0x98}, {0xe9,0x97,0xd6,0xbd}, {0x43,0xcc,0x89,0x40}, {0x9e,0x77,0x67,0xd9}, +{0x42,0xbd,0xb0,0xe8}, {0x8b,0x88,0x07,0x89}, {0x5b,0x38,0xe7,0x19}, {0xee,0xdb,0x79,0xc8}, +{0x0a,0x47,0xa1,0x7c}, {0x0f,0xe9,0x7c,0x42}, {0x1e,0xc9,0xf8,0x84}, {0x00,0x00,0x00,0x00}, +{0x86,0x83,0x09,0x80}, {0xed,0x48,0x32,0x2b}, {0x70,0xac,0x1e,0x11}, {0x72,0x4e,0x6c,0x5a}, +{0xff,0xfb,0xfd,0x0e}, {0x38,0x56,0x0f,0x85}, {0xd5,0x1e,0x3d,0xae}, {0x39,0x27,0x36,0x2d}, +{0xd9,0x64,0x0a,0x0f}, {0xa6,0x21,0x68,0x5c}, {0x54,0xd1,0x9b,0x5b}, {0x2e,0x3a,0x24,0x36}, +{0x67,0xb1,0x0c,0x0a}, {0xe7,0x0f,0x93,0x57}, {0x96,0xd2,0xb4,0xee}, {0x91,0x9e,0x1b,0x9b}, +{0xc5,0x4f,0x80,0xc0}, {0x20,0xa2,0x61,0xdc}, {0x4b,0x69,0x5a,0x77}, {0x1a,0x16,0x1c,0x12}, +{0xba,0x0a,0xe2,0x93}, {0x2a,0xe5,0xc0,0xa0}, {0xe0,0x43,0x3c,0x22}, {0x17,0x1d,0x12,0x1b}, +{0x0d,0x0b,0x0e,0x09}, {0xc7,0xad,0xf2,0x8b}, {0xa8,0xb9,0x2d,0xb6}, {0xa9,0xc8,0x14,0x1e}, +{0x19,0x85,0x57,0xf1}, {0x07,0x4c,0xaf,0x75}, {0xdd,0xbb,0xee,0x99}, {0x60,0xfd,0xa3,0x7f}, +{0x26,0x9f,0xf7,0x01}, {0xf5,0xbc,0x5c,0x72}, {0x3b,0xc5,0x44,0x66}, {0x7e,0x34,0x5b,0xfb}, +{0x29,0x76,0x8b,0x43}, {0xc6,0xdc,0xcb,0x23}, {0xfc,0x68,0xb6,0xed}, {0xf1,0x63,0xb8,0xe4}, +{0xdc,0xca,0xd7,0x31}, {0x85,0x10,0x42,0x63}, {0x22,0x40,0x13,0x97}, {0x11,0x20,0x84,0xc6}, +{0x24,0x7d,0x85,0x4a}, {0x3d,0xf8,0xd2,0xbb}, {0x32,0x11,0xae,0xf9}, {0xa1,0x6d,0xc7,0x29}, +{0x2f,0x4b,0x1d,0x9e}, {0x30,0xf3,0xdc,0xb2}, {0x52,0xec,0x0d,0x86}, {0xe3,0xd0,0x77,0xc1}, +{0x16,0x6c,0x2b,0xb3}, {0xb9,0x99,0xa9,0x70}, {0x48,0xfa,0x11,0x94}, {0x64,0x22,0x47,0xe9}, +{0x8c,0xc4,0xa8,0xfc}, {0x3f,0x1a,0xa0,0xf0}, {0x2c,0xd8,0x56,0x7d}, {0x90,0xef,0x22,0x33}, +{0x4e,0xc7,0x87,0x49}, {0xd1,0xc1,0xd9,0x38}, {0xa2,0xfe,0x8c,0xca}, {0x0b,0x36,0x98,0xd4}, +{0x81,0xcf,0xa6,0xf5}, {0xde,0x28,0xa5,0x7a}, {0x8e,0x26,0xda,0xb7}, {0xbf,0xa4,0x3f,0xad}, +{0x9d,0xe4,0x2c,0x3a}, {0x92,0x0d,0x50,0x78}, {0xcc,0x9b,0x6a,0x5f}, {0x46,0x62,0x54,0x7e}, +{0x13,0xc2,0xf6,0x8d}, {0xb8,0xe8,0x90,0xd8}, {0xf7,0x5e,0x2e,0x39}, {0xaf,0xf5,0x82,0xc3}, +{0x80,0xbe,0x9f,0x5d}, {0x93,0x7c,0x69,0xd0}, {0x2d,0xa9,0x6f,0xd5}, {0x12,0xb3,0xcf,0x25}, +{0x99,0x3b,0xc8,0xac}, {0x7d,0xa7,0x10,0x18}, {0x63,0x6e,0xe8,0x9c}, {0xbb,0x7b,0xdb,0x3b}, +{0x78,0x09,0xcd,0x26}, {0x18,0xf4,0x6e,0x59}, {0xb7,0x01,0xec,0x9a}, {0x9a,0xa8,0x83,0x4f}, +{0x6e,0x65,0xe6,0x95}, {0xe6,0x7e,0xaa,0xff}, {0xcf,0x08,0x21,0xbc}, {0xe8,0xe6,0xef,0x15}, +{0x9b,0xd9,0xba,0xe7}, {0x36,0xce,0x4a,0x6f}, {0x09,0xd4,0xea,0x9f}, {0x7c,0xd6,0x29,0xb0}, +{0xb2,0xaf,0x31,0xa4}, {0x23,0x31,0x2a,0x3f}, {0x94,0x30,0xc6,0xa5}, {0x66,0xc0,0x35,0xa2}, +{0xbc,0x37,0x74,0x4e}, {0xca,0xa6,0xfc,0x82}, {0xd0,0xb0,0xe0,0x90}, {0xd8,0x15,0x33,0xa7}, +{0x98,0x4a,0xf1,0x04}, {0xda,0xf7,0x41,0xec}, {0x50,0x0e,0x7f,0xcd}, {0xf6,0x2f,0x17,0x91}, +{0xd6,0x8d,0x76,0x4d}, {0xb0,0x4d,0x43,0xef}, {0x4d,0x54,0xcc,0xaa}, {0x04,0xdf,0xe4,0x96}, +{0xb5,0xe3,0x9e,0xd1}, {0x88,0x1b,0x4c,0x6a}, {0x1f,0xb8,0xc1,0x2c}, {0x51,0x7f,0x46,0x65}, +{0xea,0x04,0x9d,0x5e}, {0x35,0x5d,0x01,0x8c}, {0x74,0x73,0xfa,0x87}, {0x41,0x2e,0xfb,0x0b}, +{0x1d,0x5a,0xb3,0x67}, {0xd2,0x52,0x92,0xdb}, {0x56,0x33,0xe9,0x10}, {0x47,0x13,0x6d,0xd6}, +{0x61,0x8c,0x9a,0xd7}, {0x0c,0x7a,0x37,0xa1}, {0x14,0x8e,0x59,0xf8}, {0x3c,0x89,0xeb,0x13}, +{0x27,0xee,0xce,0xa9}, {0xc9,0x35,0xb7,0x61}, {0xe5,0xed,0xe1,0x1c}, {0xb1,0x3c,0x7a,0x47}, +{0xdf,0x59,0x9c,0xd2}, {0x73,0x3f,0x55,0xf2}, {0xce,0x79,0x18,0x14}, {0x37,0xbf,0x73,0xc7}, +{0xcd,0xea,0x53,0xf7}, {0xaa,0x5b,0x5f,0xfd}, {0x6f,0x14,0xdf,0x3d}, {0xdb,0x86,0x78,0x44}, +{0xf3,0x81,0xca,0xaf}, {0xc4,0x3e,0xb9,0x68}, {0x34,0x2c,0x38,0x24}, {0x40,0x5f,0xc2,0xa3}, +{0xc3,0x72,0x16,0x1d}, {0x25,0x0c,0xbc,0xe2}, {0x49,0x8b,0x28,0x3c}, {0x95,0x41,0xff,0x0d}, +{0x01,0x71,0x39,0xa8}, {0xb3,0xde,0x08,0x0c}, {0xe4,0x9c,0xd8,0xb4}, {0xc1,0x90,0x64,0x56}, +{0x84,0x61,0x7b,0xcb}, {0xb6,0x70,0xd5,0x32}, {0x5c,0x74,0x48,0x6c}, {0x57,0x42,0xd0,0xb8} + } +}; +#define T7 xT7.xt8 + +static const union xtab xT8 = { + .xt8 = { +{0xf4,0xa7,0x50,0x51}, {0x41,0x65,0x53,0x7e}, {0x17,0xa4,0xc3,0x1a}, {0x27,0x5e,0x96,0x3a}, +{0xab,0x6b,0xcb,0x3b}, {0x9d,0x45,0xf1,0x1f}, {0xfa,0x58,0xab,0xac}, {0xe3,0x03,0x93,0x4b}, +{0x30,0xfa,0x55,0x20}, {0x76,0x6d,0xf6,0xad}, {0xcc,0x76,0x91,0x88}, {0x02,0x4c,0x25,0xf5}, +{0xe5,0xd7,0xfc,0x4f}, {0x2a,0xcb,0xd7,0xc5}, {0x35,0x44,0x80,0x26}, {0x62,0xa3,0x8f,0xb5}, +{0xb1,0x5a,0x49,0xde}, {0xba,0x1b,0x67,0x25}, {0xea,0x0e,0x98,0x45}, {0xfe,0xc0,0xe1,0x5d}, +{0x2f,0x75,0x02,0xc3}, {0x4c,0xf0,0x12,0x81}, {0x46,0x97,0xa3,0x8d}, {0xd3,0xf9,0xc6,0x6b}, +{0x8f,0x5f,0xe7,0x03}, {0x92,0x9c,0x95,0x15}, {0x6d,0x7a,0xeb,0xbf}, {0x52,0x59,0xda,0x95}, +{0xbe,0x83,0x2d,0xd4}, {0x74,0x21,0xd3,0x58}, {0xe0,0x69,0x29,0x49}, {0xc9,0xc8,0x44,0x8e}, +{0xc2,0x89,0x6a,0x75}, {0x8e,0x79,0x78,0xf4}, {0x58,0x3e,0x6b,0x99}, {0xb9,0x71,0xdd,0x27}, +{0xe1,0x4f,0xb6,0xbe}, {0x88,0xad,0x17,0xf0}, {0x20,0xac,0x66,0xc9}, {0xce,0x3a,0xb4,0x7d}, +{0xdf,0x4a,0x18,0x63}, {0x1a,0x31,0x82,0xe5}, {0x51,0x33,0x60,0x97}, {0x53,0x7f,0x45,0x62}, +{0x64,0x77,0xe0,0xb1}, {0x6b,0xae,0x84,0xbb}, {0x81,0xa0,0x1c,0xfe}, {0x08,0x2b,0x94,0xf9}, +{0x48,0x68,0x58,0x70}, {0x45,0xfd,0x19,0x8f}, {0xde,0x6c,0x87,0x94}, {0x7b,0xf8,0xb7,0x52}, +{0x73,0xd3,0x23,0xab}, {0x4b,0x02,0xe2,0x72}, {0x1f,0x8f,0x57,0xe3}, {0x55,0xab,0x2a,0x66}, +{0xeb,0x28,0x07,0xb2}, {0xb5,0xc2,0x03,0x2f}, {0xc5,0x7b,0x9a,0x86}, {0x37,0x08,0xa5,0xd3}, +{0x28,0x87,0xf2,0x30}, {0xbf,0xa5,0xb2,0x23}, {0x03,0x6a,0xba,0x02}, {0x16,0x82,0x5c,0xed}, +{0xcf,0x1c,0x2b,0x8a}, {0x79,0xb4,0x92,0xa7}, {0x07,0xf2,0xf0,0xf3}, {0x69,0xe2,0xa1,0x4e}, +{0xda,0xf4,0xcd,0x65}, {0x05,0xbe,0xd5,0x06}, {0x34,0x62,0x1f,0xd1}, {0xa6,0xfe,0x8a,0xc4}, +{0x2e,0x53,0x9d,0x34}, {0xf3,0x55,0xa0,0xa2}, {0x8a,0xe1,0x32,0x05}, {0xf6,0xeb,0x75,0xa4}, +{0x83,0xec,0x39,0x0b}, {0x60,0xef,0xaa,0x40}, {0x71,0x9f,0x06,0x5e}, {0x6e,0x10,0x51,0xbd}, +{0x21,0x8a,0xf9,0x3e}, {0xdd,0x06,0x3d,0x96}, {0x3e,0x05,0xae,0xdd}, {0xe6,0xbd,0x46,0x4d}, +{0x54,0x8d,0xb5,0x91}, {0xc4,0x5d,0x05,0x71}, {0x06,0xd4,0x6f,0x04}, {0x50,0x15,0xff,0x60}, +{0x98,0xfb,0x24,0x19}, {0xbd,0xe9,0x97,0xd6}, {0x40,0x43,0xcc,0x89}, {0xd9,0x9e,0x77,0x67}, +{0xe8,0x42,0xbd,0xb0}, {0x89,0x8b,0x88,0x07}, {0x19,0x5b,0x38,0xe7}, {0xc8,0xee,0xdb,0x79}, +{0x7c,0x0a,0x47,0xa1}, {0x42,0x0f,0xe9,0x7c}, {0x84,0x1e,0xc9,0xf8}, {0x00,0x00,0x00,0x00}, +{0x80,0x86,0x83,0x09}, {0x2b,0xed,0x48,0x32}, {0x11,0x70,0xac,0x1e}, {0x5a,0x72,0x4e,0x6c}, +{0x0e,0xff,0xfb,0xfd}, {0x85,0x38,0x56,0x0f}, {0xae,0xd5,0x1e,0x3d}, {0x2d,0x39,0x27,0x36}, +{0x0f,0xd9,0x64,0x0a}, {0x5c,0xa6,0x21,0x68}, {0x5b,0x54,0xd1,0x9b}, {0x36,0x2e,0x3a,0x24}, +{0x0a,0x67,0xb1,0x0c}, {0x57,0xe7,0x0f,0x93}, {0xee,0x96,0xd2,0xb4}, {0x9b,0x91,0x9e,0x1b}, +{0xc0,0xc5,0x4f,0x80}, {0xdc,0x20,0xa2,0x61}, {0x77,0x4b,0x69,0x5a}, {0x12,0x1a,0x16,0x1c}, +{0x93,0xba,0x0a,0xe2}, {0xa0,0x2a,0xe5,0xc0}, {0x22,0xe0,0x43,0x3c}, {0x1b,0x17,0x1d,0x12}, +{0x09,0x0d,0x0b,0x0e}, {0x8b,0xc7,0xad,0xf2}, {0xb6,0xa8,0xb9,0x2d}, {0x1e,0xa9,0xc8,0x14}, +{0xf1,0x19,0x85,0x57}, {0x75,0x07,0x4c,0xaf}, {0x99,0xdd,0xbb,0xee}, {0x7f,0x60,0xfd,0xa3}, +{0x01,0x26,0x9f,0xf7}, {0x72,0xf5,0xbc,0x5c}, {0x66,0x3b,0xc5,0x44}, {0xfb,0x7e,0x34,0x5b}, +{0x43,0x29,0x76,0x8b}, {0x23,0xc6,0xdc,0xcb}, {0xed,0xfc,0x68,0xb6}, {0xe4,0xf1,0x63,0xb8}, +{0x31,0xdc,0xca,0xd7}, {0x63,0x85,0x10,0x42}, {0x97,0x22,0x40,0x13}, {0xc6,0x11,0x20,0x84}, +{0x4a,0x24,0x7d,0x85}, {0xbb,0x3d,0xf8,0xd2}, {0xf9,0x32,0x11,0xae}, {0x29,0xa1,0x6d,0xc7}, +{0x9e,0x2f,0x4b,0x1d}, {0xb2,0x30,0xf3,0xdc}, {0x86,0x52,0xec,0x0d}, {0xc1,0xe3,0xd0,0x77}, +{0xb3,0x16,0x6c,0x2b}, {0x70,0xb9,0x99,0xa9}, {0x94,0x48,0xfa,0x11}, {0xe9,0x64,0x22,0x47}, +{0xfc,0x8c,0xc4,0xa8}, {0xf0,0x3f,0x1a,0xa0}, {0x7d,0x2c,0xd8,0x56}, {0x33,0x90,0xef,0x22}, +{0x49,0x4e,0xc7,0x87}, {0x38,0xd1,0xc1,0xd9}, {0xca,0xa2,0xfe,0x8c}, {0xd4,0x0b,0x36,0x98}, +{0xf5,0x81,0xcf,0xa6}, {0x7a,0xde,0x28,0xa5}, {0xb7,0x8e,0x26,0xda}, {0xad,0xbf,0xa4,0x3f}, +{0x3a,0x9d,0xe4,0x2c}, {0x78,0x92,0x0d,0x50}, {0x5f,0xcc,0x9b,0x6a}, {0x7e,0x46,0x62,0x54}, +{0x8d,0x13,0xc2,0xf6}, {0xd8,0xb8,0xe8,0x90}, {0x39,0xf7,0x5e,0x2e}, {0xc3,0xaf,0xf5,0x82}, +{0x5d,0x80,0xbe,0x9f}, {0xd0,0x93,0x7c,0x69}, {0xd5,0x2d,0xa9,0x6f}, {0x25,0x12,0xb3,0xcf}, +{0xac,0x99,0x3b,0xc8}, {0x18,0x7d,0xa7,0x10}, {0x9c,0x63,0x6e,0xe8}, {0x3b,0xbb,0x7b,0xdb}, +{0x26,0x78,0x09,0xcd}, {0x59,0x18,0xf4,0x6e}, {0x9a,0xb7,0x01,0xec}, {0x4f,0x9a,0xa8,0x83}, +{0x95,0x6e,0x65,0xe6}, {0xff,0xe6,0x7e,0xaa}, {0xbc,0xcf,0x08,0x21}, {0x15,0xe8,0xe6,0xef}, +{0xe7,0x9b,0xd9,0xba}, {0x6f,0x36,0xce,0x4a}, {0x9f,0x09,0xd4,0xea}, {0xb0,0x7c,0xd6,0x29}, +{0xa4,0xb2,0xaf,0x31}, {0x3f,0x23,0x31,0x2a}, {0xa5,0x94,0x30,0xc6}, {0xa2,0x66,0xc0,0x35}, +{0x4e,0xbc,0x37,0x74}, {0x82,0xca,0xa6,0xfc}, {0x90,0xd0,0xb0,0xe0}, {0xa7,0xd8,0x15,0x33}, +{0x04,0x98,0x4a,0xf1}, {0xec,0xda,0xf7,0x41}, {0xcd,0x50,0x0e,0x7f}, {0x91,0xf6,0x2f,0x17}, +{0x4d,0xd6,0x8d,0x76}, {0xef,0xb0,0x4d,0x43}, {0xaa,0x4d,0x54,0xcc}, {0x96,0x04,0xdf,0xe4}, +{0xd1,0xb5,0xe3,0x9e}, {0x6a,0x88,0x1b,0x4c}, {0x2c,0x1f,0xb8,0xc1}, {0x65,0x51,0x7f,0x46}, +{0x5e,0xea,0x04,0x9d}, {0x8c,0x35,0x5d,0x01}, {0x87,0x74,0x73,0xfa}, {0x0b,0x41,0x2e,0xfb}, +{0x67,0x1d,0x5a,0xb3}, {0xdb,0xd2,0x52,0x92}, {0x10,0x56,0x33,0xe9}, {0xd6,0x47,0x13,0x6d}, +{0xd7,0x61,0x8c,0x9a}, {0xa1,0x0c,0x7a,0x37}, {0xf8,0x14,0x8e,0x59}, {0x13,0x3c,0x89,0xeb}, +{0xa9,0x27,0xee,0xce}, {0x61,0xc9,0x35,0xb7}, {0x1c,0xe5,0xed,0xe1}, {0x47,0xb1,0x3c,0x7a}, +{0xd2,0xdf,0x59,0x9c}, {0xf2,0x73,0x3f,0x55}, {0x14,0xce,0x79,0x18}, {0xc7,0x37,0xbf,0x73}, +{0xf7,0xcd,0xea,0x53}, {0xfd,0xaa,0x5b,0x5f}, {0x3d,0x6f,0x14,0xdf}, {0x44,0xdb,0x86,0x78}, +{0xaf,0xf3,0x81,0xca}, {0x68,0xc4,0x3e,0xb9}, {0x24,0x34,0x2c,0x38}, {0xa3,0x40,0x5f,0xc2}, +{0x1d,0xc3,0x72,0x16}, {0xe2,0x25,0x0c,0xbc}, {0x3c,0x49,0x8b,0x28}, {0x0d,0x95,0x41,0xff}, +{0xa8,0x01,0x71,0x39}, {0x0c,0xb3,0xde,0x08}, {0xb4,0xe4,0x9c,0xd8}, {0x56,0xc1,0x90,0x64}, +{0xcb,0x84,0x61,0x7b}, {0x32,0xb6,0x70,0xd5}, {0x6c,0x5c,0x74,0x48}, {0xb8,0x57,0x42,0xd0} + } +}; +#define T8 xT8.xt8 + +static const word8 S5[256] = { +0x52,0x09,0x6a,0xd5, +0x30,0x36,0xa5,0x38, +0xbf,0x40,0xa3,0x9e, +0x81,0xf3,0xd7,0xfb, +0x7c,0xe3,0x39,0x82, +0x9b,0x2f,0xff,0x87, +0x34,0x8e,0x43,0x44, +0xc4,0xde,0xe9,0xcb, +0x54,0x7b,0x94,0x32, +0xa6,0xc2,0x23,0x3d, +0xee,0x4c,0x95,0x0b, +0x42,0xfa,0xc3,0x4e, +0x08,0x2e,0xa1,0x66, +0x28,0xd9,0x24,0xb2, +0x76,0x5b,0xa2,0x49, +0x6d,0x8b,0xd1,0x25, +0x72,0xf8,0xf6,0x64, +0x86,0x68,0x98,0x16, +0xd4,0xa4,0x5c,0xcc, +0x5d,0x65,0xb6,0x92, +0x6c,0x70,0x48,0x50, +0xfd,0xed,0xb9,0xda, +0x5e,0x15,0x46,0x57, +0xa7,0x8d,0x9d,0x84, +0x90,0xd8,0xab,0x00, +0x8c,0xbc,0xd3,0x0a, +0xf7,0xe4,0x58,0x05, +0xb8,0xb3,0x45,0x06, +0xd0,0x2c,0x1e,0x8f, +0xca,0x3f,0x0f,0x02, +0xc1,0xaf,0xbd,0x03, +0x01,0x13,0x8a,0x6b, +0x3a,0x91,0x11,0x41, +0x4f,0x67,0xdc,0xea, +0x97,0xf2,0xcf,0xce, +0xf0,0xb4,0xe6,0x73, +0x96,0xac,0x74,0x22, +0xe7,0xad,0x35,0x85, +0xe2,0xf9,0x37,0xe8, +0x1c,0x75,0xdf,0x6e, +0x47,0xf1,0x1a,0x71, +0x1d,0x29,0xc5,0x89, +0x6f,0xb7,0x62,0x0e, +0xaa,0x18,0xbe,0x1b, +0xfc,0x56,0x3e,0x4b, +0xc6,0xd2,0x79,0x20, +0x9a,0xdb,0xc0,0xfe, +0x78,0xcd,0x5a,0xf4, +0x1f,0xdd,0xa8,0x33, +0x88,0x07,0xc7,0x31, +0xb1,0x12,0x10,0x59, +0x27,0x80,0xec,0x5f, +0x60,0x51,0x7f,0xa9, +0x19,0xb5,0x4a,0x0d, +0x2d,0xe5,0x7a,0x9f, +0x93,0xc9,0x9c,0xef, +0xa0,0xe0,0x3b,0x4d, +0xae,0x2a,0xf5,0xb0, +0xc8,0xeb,0xbb,0x3c, +0x83,0x53,0x99,0x61, +0x17,0x2b,0x04,0x7e, +0xba,0x77,0xd6,0x26, +0xe1,0x69,0x14,0x63, +0x55,0x21,0x0c,0x7d +}; + +static const union xtab xU1 = { + .xt8 = { +{0x00,0x00,0x00,0x00}, {0x0e,0x09,0x0d,0x0b}, {0x1c,0x12,0x1a,0x16}, {0x12,0x1b,0x17,0x1d}, +{0x38,0x24,0x34,0x2c}, {0x36,0x2d,0x39,0x27}, {0x24,0x36,0x2e,0x3a}, {0x2a,0x3f,0x23,0x31}, +{0x70,0x48,0x68,0x58}, {0x7e,0x41,0x65,0x53}, {0x6c,0x5a,0x72,0x4e}, {0x62,0x53,0x7f,0x45}, +{0x48,0x6c,0x5c,0x74}, {0x46,0x65,0x51,0x7f}, {0x54,0x7e,0x46,0x62}, {0x5a,0x77,0x4b,0x69}, +{0xe0,0x90,0xd0,0xb0}, {0xee,0x99,0xdd,0xbb}, {0xfc,0x82,0xca,0xa6}, {0xf2,0x8b,0xc7,0xad}, +{0xd8,0xb4,0xe4,0x9c}, {0xd6,0xbd,0xe9,0x97}, {0xc4,0xa6,0xfe,0x8a}, {0xca,0xaf,0xf3,0x81}, +{0x90,0xd8,0xb8,0xe8}, {0x9e,0xd1,0xb5,0xe3}, {0x8c,0xca,0xa2,0xfe}, {0x82,0xc3,0xaf,0xf5}, +{0xa8,0xfc,0x8c,0xc4}, {0xa6,0xf5,0x81,0xcf}, {0xb4,0xee,0x96,0xd2}, {0xba,0xe7,0x9b,0xd9}, +{0xdb,0x3b,0xbb,0x7b}, {0xd5,0x32,0xb6,0x70}, {0xc7,0x29,0xa1,0x6d}, {0xc9,0x20,0xac,0x66}, +{0xe3,0x1f,0x8f,0x57}, {0xed,0x16,0x82,0x5c}, {0xff,0x0d,0x95,0x41}, {0xf1,0x04,0x98,0x4a}, +{0xab,0x73,0xd3,0x23}, {0xa5,0x7a,0xde,0x28}, {0xb7,0x61,0xc9,0x35}, {0xb9,0x68,0xc4,0x3e}, +{0x93,0x57,0xe7,0x0f}, {0x9d,0x5e,0xea,0x04}, {0x8f,0x45,0xfd,0x19}, {0x81,0x4c,0xf0,0x12}, +{0x3b,0xab,0x6b,0xcb}, {0x35,0xa2,0x66,0xc0}, {0x27,0xb9,0x71,0xdd}, {0x29,0xb0,0x7c,0xd6}, +{0x03,0x8f,0x5f,0xe7}, {0x0d,0x86,0x52,0xec}, {0x1f,0x9d,0x45,0xf1}, {0x11,0x94,0x48,0xfa}, +{0x4b,0xe3,0x03,0x93}, {0x45,0xea,0x0e,0x98}, {0x57,0xf1,0x19,0x85}, {0x59,0xf8,0x14,0x8e}, +{0x73,0xc7,0x37,0xbf}, {0x7d,0xce,0x3a,0xb4}, {0x6f,0xd5,0x2d,0xa9}, {0x61,0xdc,0x20,0xa2}, +{0xad,0x76,0x6d,0xf6}, {0xa3,0x7f,0x60,0xfd}, {0xb1,0x64,0x77,0xe0}, {0xbf,0x6d,0x7a,0xeb}, +{0x95,0x52,0x59,0xda}, {0x9b,0x5b,0x54,0xd1}, {0x89,0x40,0x43,0xcc}, {0x87,0x49,0x4e,0xc7}, +{0xdd,0x3e,0x05,0xae}, {0xd3,0x37,0x08,0xa5}, {0xc1,0x2c,0x1f,0xb8}, {0xcf,0x25,0x12,0xb3}, +{0xe5,0x1a,0x31,0x82}, {0xeb,0x13,0x3c,0x89}, {0xf9,0x08,0x2b,0x94}, {0xf7,0x01,0x26,0x9f}, +{0x4d,0xe6,0xbd,0x46}, {0x43,0xef,0xb0,0x4d}, {0x51,0xf4,0xa7,0x50}, {0x5f,0xfd,0xaa,0x5b}, +{0x75,0xc2,0x89,0x6a}, {0x7b,0xcb,0x84,0x61}, {0x69,0xd0,0x93,0x7c}, {0x67,0xd9,0x9e,0x77}, +{0x3d,0xae,0xd5,0x1e}, {0x33,0xa7,0xd8,0x15}, {0x21,0xbc,0xcf,0x08}, {0x2f,0xb5,0xc2,0x03}, +{0x05,0x8a,0xe1,0x32}, {0x0b,0x83,0xec,0x39}, {0x19,0x98,0xfb,0x24}, {0x17,0x91,0xf6,0x2f}, +{0x76,0x4d,0xd6,0x8d}, {0x78,0x44,0xdb,0x86}, {0x6a,0x5f,0xcc,0x9b}, {0x64,0x56,0xc1,0x90}, +{0x4e,0x69,0xe2,0xa1}, {0x40,0x60,0xef,0xaa}, {0x52,0x7b,0xf8,0xb7}, {0x5c,0x72,0xf5,0xbc}, +{0x06,0x05,0xbe,0xd5}, {0x08,0x0c,0xb3,0xde}, {0x1a,0x17,0xa4,0xc3}, {0x14,0x1e,0xa9,0xc8}, +{0x3e,0x21,0x8a,0xf9}, {0x30,0x28,0x87,0xf2}, {0x22,0x33,0x90,0xef}, {0x2c,0x3a,0x9d,0xe4}, +{0x96,0xdd,0x06,0x3d}, {0x98,0xd4,0x0b,0x36}, {0x8a,0xcf,0x1c,0x2b}, {0x84,0xc6,0x11,0x20}, +{0xae,0xf9,0x32,0x11}, {0xa0,0xf0,0x3f,0x1a}, {0xb2,0xeb,0x28,0x07}, {0xbc,0xe2,0x25,0x0c}, +{0xe6,0x95,0x6e,0x65}, {0xe8,0x9c,0x63,0x6e}, {0xfa,0x87,0x74,0x73}, {0xf4,0x8e,0x79,0x78}, +{0xde,0xb1,0x5a,0x49}, {0xd0,0xb8,0x57,0x42}, {0xc2,0xa3,0x40,0x5f}, {0xcc,0xaa,0x4d,0x54}, +{0x41,0xec,0xda,0xf7}, {0x4f,0xe5,0xd7,0xfc}, {0x5d,0xfe,0xc0,0xe1}, {0x53,0xf7,0xcd,0xea}, +{0x79,0xc8,0xee,0xdb}, {0x77,0xc1,0xe3,0xd0}, {0x65,0xda,0xf4,0xcd}, {0x6b,0xd3,0xf9,0xc6}, +{0x31,0xa4,0xb2,0xaf}, {0x3f,0xad,0xbf,0xa4}, {0x2d,0xb6,0xa8,0xb9}, {0x23,0xbf,0xa5,0xb2}, +{0x09,0x80,0x86,0x83}, {0x07,0x89,0x8b,0x88}, {0x15,0x92,0x9c,0x95}, {0x1b,0x9b,0x91,0x9e}, +{0xa1,0x7c,0x0a,0x47}, {0xaf,0x75,0x07,0x4c}, {0xbd,0x6e,0x10,0x51}, {0xb3,0x67,0x1d,0x5a}, +{0x99,0x58,0x3e,0x6b}, {0x97,0x51,0x33,0x60}, {0x85,0x4a,0x24,0x7d}, {0x8b,0x43,0x29,0x76}, +{0xd1,0x34,0x62,0x1f}, {0xdf,0x3d,0x6f,0x14}, {0xcd,0x26,0x78,0x09}, {0xc3,0x2f,0x75,0x02}, +{0xe9,0x10,0x56,0x33}, {0xe7,0x19,0x5b,0x38}, {0xf5,0x02,0x4c,0x25}, {0xfb,0x0b,0x41,0x2e}, +{0x9a,0xd7,0x61,0x8c}, {0x94,0xde,0x6c,0x87}, {0x86,0xc5,0x7b,0x9a}, {0x88,0xcc,0x76,0x91}, +{0xa2,0xf3,0x55,0xa0}, {0xac,0xfa,0x58,0xab}, {0xbe,0xe1,0x4f,0xb6}, {0xb0,0xe8,0x42,0xbd}, +{0xea,0x9f,0x09,0xd4}, {0xe4,0x96,0x04,0xdf}, {0xf6,0x8d,0x13,0xc2}, {0xf8,0x84,0x1e,0xc9}, +{0xd2,0xbb,0x3d,0xf8}, {0xdc,0xb2,0x30,0xf3}, {0xce,0xa9,0x27,0xee}, {0xc0,0xa0,0x2a,0xe5}, +{0x7a,0x47,0xb1,0x3c}, {0x74,0x4e,0xbc,0x37}, {0x66,0x55,0xab,0x2a}, {0x68,0x5c,0xa6,0x21}, +{0x42,0x63,0x85,0x10}, {0x4c,0x6a,0x88,0x1b}, {0x5e,0x71,0x9f,0x06}, {0x50,0x78,0x92,0x0d}, +{0x0a,0x0f,0xd9,0x64}, {0x04,0x06,0xd4,0x6f}, {0x16,0x1d,0xc3,0x72}, {0x18,0x14,0xce,0x79}, +{0x32,0x2b,0xed,0x48}, {0x3c,0x22,0xe0,0x43}, {0x2e,0x39,0xf7,0x5e}, {0x20,0x30,0xfa,0x55}, +{0xec,0x9a,0xb7,0x01}, {0xe2,0x93,0xba,0x0a}, {0xf0,0x88,0xad,0x17}, {0xfe,0x81,0xa0,0x1c}, +{0xd4,0xbe,0x83,0x2d}, {0xda,0xb7,0x8e,0x26}, {0xc8,0xac,0x99,0x3b}, {0xc6,0xa5,0x94,0x30}, +{0x9c,0xd2,0xdf,0x59}, {0x92,0xdb,0xd2,0x52}, {0x80,0xc0,0xc5,0x4f}, {0x8e,0xc9,0xc8,0x44}, +{0xa4,0xf6,0xeb,0x75}, {0xaa,0xff,0xe6,0x7e}, {0xb8,0xe4,0xf1,0x63}, {0xb6,0xed,0xfc,0x68}, +{0x0c,0x0a,0x67,0xb1}, {0x02,0x03,0x6a,0xba}, {0x10,0x18,0x7d,0xa7}, {0x1e,0x11,0x70,0xac}, +{0x34,0x2e,0x53,0x9d}, {0x3a,0x27,0x5e,0x96}, {0x28,0x3c,0x49,0x8b}, {0x26,0x35,0x44,0x80}, +{0x7c,0x42,0x0f,0xe9}, {0x72,0x4b,0x02,0xe2}, {0x60,0x50,0x15,0xff}, {0x6e,0x59,0x18,0xf4}, +{0x44,0x66,0x3b,0xc5}, {0x4a,0x6f,0x36,0xce}, {0x58,0x74,0x21,0xd3}, {0x56,0x7d,0x2c,0xd8}, +{0x37,0xa1,0x0c,0x7a}, {0x39,0xa8,0x01,0x71}, {0x2b,0xb3,0x16,0x6c}, {0x25,0xba,0x1b,0x67}, +{0x0f,0x85,0x38,0x56}, {0x01,0x8c,0x35,0x5d}, {0x13,0x97,0x22,0x40}, {0x1d,0x9e,0x2f,0x4b}, +{0x47,0xe9,0x64,0x22}, {0x49,0xe0,0x69,0x29}, {0x5b,0xfb,0x7e,0x34}, {0x55,0xf2,0x73,0x3f}, +{0x7f,0xcd,0x50,0x0e}, {0x71,0xc4,0x5d,0x05}, {0x63,0xdf,0x4a,0x18}, {0x6d,0xd6,0x47,0x13}, +{0xd7,0x31,0xdc,0xca}, {0xd9,0x38,0xd1,0xc1}, {0xcb,0x23,0xc6,0xdc}, {0xc5,0x2a,0xcb,0xd7}, +{0xef,0x15,0xe8,0xe6}, {0xe1,0x1c,0xe5,0xed}, {0xf3,0x07,0xf2,0xf0}, {0xfd,0x0e,0xff,0xfb}, +{0xa7,0x79,0xb4,0x92}, {0xa9,0x70,0xb9,0x99}, {0xbb,0x6b,0xae,0x84}, {0xb5,0x62,0xa3,0x8f}, +{0x9f,0x5d,0x80,0xbe}, {0x91,0x54,0x8d,0xb5}, {0x83,0x4f,0x9a,0xa8}, {0x8d,0x46,0x97,0xa3} + } +}; +#define U1 xU1.xt8 + +static const union xtab xU2 = { + .xt8 = { +{0x00,0x00,0x00,0x00}, {0x0b,0x0e,0x09,0x0d}, {0x16,0x1c,0x12,0x1a}, {0x1d,0x12,0x1b,0x17}, +{0x2c,0x38,0x24,0x34}, {0x27,0x36,0x2d,0x39}, {0x3a,0x24,0x36,0x2e}, {0x31,0x2a,0x3f,0x23}, +{0x58,0x70,0x48,0x68}, {0x53,0x7e,0x41,0x65}, {0x4e,0x6c,0x5a,0x72}, {0x45,0x62,0x53,0x7f}, +{0x74,0x48,0x6c,0x5c}, {0x7f,0x46,0x65,0x51}, {0x62,0x54,0x7e,0x46}, {0x69,0x5a,0x77,0x4b}, +{0xb0,0xe0,0x90,0xd0}, {0xbb,0xee,0x99,0xdd}, {0xa6,0xfc,0x82,0xca}, {0xad,0xf2,0x8b,0xc7}, +{0x9c,0xd8,0xb4,0xe4}, {0x97,0xd6,0xbd,0xe9}, {0x8a,0xc4,0xa6,0xfe}, {0x81,0xca,0xaf,0xf3}, +{0xe8,0x90,0xd8,0xb8}, {0xe3,0x9e,0xd1,0xb5}, {0xfe,0x8c,0xca,0xa2}, {0xf5,0x82,0xc3,0xaf}, +{0xc4,0xa8,0xfc,0x8c}, {0xcf,0xa6,0xf5,0x81}, {0xd2,0xb4,0xee,0x96}, {0xd9,0xba,0xe7,0x9b}, +{0x7b,0xdb,0x3b,0xbb}, {0x70,0xd5,0x32,0xb6}, {0x6d,0xc7,0x29,0xa1}, {0x66,0xc9,0x20,0xac}, +{0x57,0xe3,0x1f,0x8f}, {0x5c,0xed,0x16,0x82}, {0x41,0xff,0x0d,0x95}, {0x4a,0xf1,0x04,0x98}, +{0x23,0xab,0x73,0xd3}, {0x28,0xa5,0x7a,0xde}, {0x35,0xb7,0x61,0xc9}, {0x3e,0xb9,0x68,0xc4}, +{0x0f,0x93,0x57,0xe7}, {0x04,0x9d,0x5e,0xea}, {0x19,0x8f,0x45,0xfd}, {0x12,0x81,0x4c,0xf0}, +{0xcb,0x3b,0xab,0x6b}, {0xc0,0x35,0xa2,0x66}, {0xdd,0x27,0xb9,0x71}, {0xd6,0x29,0xb0,0x7c}, +{0xe7,0x03,0x8f,0x5f}, {0xec,0x0d,0x86,0x52}, {0xf1,0x1f,0x9d,0x45}, {0xfa,0x11,0x94,0x48}, +{0x93,0x4b,0xe3,0x03}, {0x98,0x45,0xea,0x0e}, {0x85,0x57,0xf1,0x19}, {0x8e,0x59,0xf8,0x14}, +{0xbf,0x73,0xc7,0x37}, {0xb4,0x7d,0xce,0x3a}, {0xa9,0x6f,0xd5,0x2d}, {0xa2,0x61,0xdc,0x20}, +{0xf6,0xad,0x76,0x6d}, {0xfd,0xa3,0x7f,0x60}, {0xe0,0xb1,0x64,0x77}, {0xeb,0xbf,0x6d,0x7a}, +{0xda,0x95,0x52,0x59}, {0xd1,0x9b,0x5b,0x54}, {0xcc,0x89,0x40,0x43}, {0xc7,0x87,0x49,0x4e}, +{0xae,0xdd,0x3e,0x05}, {0xa5,0xd3,0x37,0x08}, {0xb8,0xc1,0x2c,0x1f}, {0xb3,0xcf,0x25,0x12}, +{0x82,0xe5,0x1a,0x31}, {0x89,0xeb,0x13,0x3c}, {0x94,0xf9,0x08,0x2b}, {0x9f,0xf7,0x01,0x26}, +{0x46,0x4d,0xe6,0xbd}, {0x4d,0x43,0xef,0xb0}, {0x50,0x51,0xf4,0xa7}, {0x5b,0x5f,0xfd,0xaa}, +{0x6a,0x75,0xc2,0x89}, {0x61,0x7b,0xcb,0x84}, {0x7c,0x69,0xd0,0x93}, {0x77,0x67,0xd9,0x9e}, +{0x1e,0x3d,0xae,0xd5}, {0x15,0x33,0xa7,0xd8}, {0x08,0x21,0xbc,0xcf}, {0x03,0x2f,0xb5,0xc2}, +{0x32,0x05,0x8a,0xe1}, {0x39,0x0b,0x83,0xec}, {0x24,0x19,0x98,0xfb}, {0x2f,0x17,0x91,0xf6}, +{0x8d,0x76,0x4d,0xd6}, {0x86,0x78,0x44,0xdb}, {0x9b,0x6a,0x5f,0xcc}, {0x90,0x64,0x56,0xc1}, +{0xa1,0x4e,0x69,0xe2}, {0xaa,0x40,0x60,0xef}, {0xb7,0x52,0x7b,0xf8}, {0xbc,0x5c,0x72,0xf5}, +{0xd5,0x06,0x05,0xbe}, {0xde,0x08,0x0c,0xb3}, {0xc3,0x1a,0x17,0xa4}, {0xc8,0x14,0x1e,0xa9}, +{0xf9,0x3e,0x21,0x8a}, {0xf2,0x30,0x28,0x87}, {0xef,0x22,0x33,0x90}, {0xe4,0x2c,0x3a,0x9d}, +{0x3d,0x96,0xdd,0x06}, {0x36,0x98,0xd4,0x0b}, {0x2b,0x8a,0xcf,0x1c}, {0x20,0x84,0xc6,0x11}, +{0x11,0xae,0xf9,0x32}, {0x1a,0xa0,0xf0,0x3f}, {0x07,0xb2,0xeb,0x28}, {0x0c,0xbc,0xe2,0x25}, +{0x65,0xe6,0x95,0x6e}, {0x6e,0xe8,0x9c,0x63}, {0x73,0xfa,0x87,0x74}, {0x78,0xf4,0x8e,0x79}, +{0x49,0xde,0xb1,0x5a}, {0x42,0xd0,0xb8,0x57}, {0x5f,0xc2,0xa3,0x40}, {0x54,0xcc,0xaa,0x4d}, +{0xf7,0x41,0xec,0xda}, {0xfc,0x4f,0xe5,0xd7}, {0xe1,0x5d,0xfe,0xc0}, {0xea,0x53,0xf7,0xcd}, +{0xdb,0x79,0xc8,0xee}, {0xd0,0x77,0xc1,0xe3}, {0xcd,0x65,0xda,0xf4}, {0xc6,0x6b,0xd3,0xf9}, +{0xaf,0x31,0xa4,0xb2}, {0xa4,0x3f,0xad,0xbf}, {0xb9,0x2d,0xb6,0xa8}, {0xb2,0x23,0xbf,0xa5}, +{0x83,0x09,0x80,0x86}, {0x88,0x07,0x89,0x8b}, {0x95,0x15,0x92,0x9c}, {0x9e,0x1b,0x9b,0x91}, +{0x47,0xa1,0x7c,0x0a}, {0x4c,0xaf,0x75,0x07}, {0x51,0xbd,0x6e,0x10}, {0x5a,0xb3,0x67,0x1d}, +{0x6b,0x99,0x58,0x3e}, {0x60,0x97,0x51,0x33}, {0x7d,0x85,0x4a,0x24}, {0x76,0x8b,0x43,0x29}, +{0x1f,0xd1,0x34,0x62}, {0x14,0xdf,0x3d,0x6f}, {0x09,0xcd,0x26,0x78}, {0x02,0xc3,0x2f,0x75}, +{0x33,0xe9,0x10,0x56}, {0x38,0xe7,0x19,0x5b}, {0x25,0xf5,0x02,0x4c}, {0x2e,0xfb,0x0b,0x41}, +{0x8c,0x9a,0xd7,0x61}, {0x87,0x94,0xde,0x6c}, {0x9a,0x86,0xc5,0x7b}, {0x91,0x88,0xcc,0x76}, +{0xa0,0xa2,0xf3,0x55}, {0xab,0xac,0xfa,0x58}, {0xb6,0xbe,0xe1,0x4f}, {0xbd,0xb0,0xe8,0x42}, +{0xd4,0xea,0x9f,0x09}, {0xdf,0xe4,0x96,0x04}, {0xc2,0xf6,0x8d,0x13}, {0xc9,0xf8,0x84,0x1e}, +{0xf8,0xd2,0xbb,0x3d}, {0xf3,0xdc,0xb2,0x30}, {0xee,0xce,0xa9,0x27}, {0xe5,0xc0,0xa0,0x2a}, +{0x3c,0x7a,0x47,0xb1}, {0x37,0x74,0x4e,0xbc}, {0x2a,0x66,0x55,0xab}, {0x21,0x68,0x5c,0xa6}, +{0x10,0x42,0x63,0x85}, {0x1b,0x4c,0x6a,0x88}, {0x06,0x5e,0x71,0x9f}, {0x0d,0x50,0x78,0x92}, +{0x64,0x0a,0x0f,0xd9}, {0x6f,0x04,0x06,0xd4}, {0x72,0x16,0x1d,0xc3}, {0x79,0x18,0x14,0xce}, +{0x48,0x32,0x2b,0xed}, {0x43,0x3c,0x22,0xe0}, {0x5e,0x2e,0x39,0xf7}, {0x55,0x20,0x30,0xfa}, +{0x01,0xec,0x9a,0xb7}, {0x0a,0xe2,0x93,0xba}, {0x17,0xf0,0x88,0xad}, {0x1c,0xfe,0x81,0xa0}, +{0x2d,0xd4,0xbe,0x83}, {0x26,0xda,0xb7,0x8e}, {0x3b,0xc8,0xac,0x99}, {0x30,0xc6,0xa5,0x94}, +{0x59,0x9c,0xd2,0xdf}, {0x52,0x92,0xdb,0xd2}, {0x4f,0x80,0xc0,0xc5}, {0x44,0x8e,0xc9,0xc8}, +{0x75,0xa4,0xf6,0xeb}, {0x7e,0xaa,0xff,0xe6}, {0x63,0xb8,0xe4,0xf1}, {0x68,0xb6,0xed,0xfc}, +{0xb1,0x0c,0x0a,0x67}, {0xba,0x02,0x03,0x6a}, {0xa7,0x10,0x18,0x7d}, {0xac,0x1e,0x11,0x70}, +{0x9d,0x34,0x2e,0x53}, {0x96,0x3a,0x27,0x5e}, {0x8b,0x28,0x3c,0x49}, {0x80,0x26,0x35,0x44}, +{0xe9,0x7c,0x42,0x0f}, {0xe2,0x72,0x4b,0x02}, {0xff,0x60,0x50,0x15}, {0xf4,0x6e,0x59,0x18}, +{0xc5,0x44,0x66,0x3b}, {0xce,0x4a,0x6f,0x36}, {0xd3,0x58,0x74,0x21}, {0xd8,0x56,0x7d,0x2c}, +{0x7a,0x37,0xa1,0x0c}, {0x71,0x39,0xa8,0x01}, {0x6c,0x2b,0xb3,0x16}, {0x67,0x25,0xba,0x1b}, +{0x56,0x0f,0x85,0x38}, {0x5d,0x01,0x8c,0x35}, {0x40,0x13,0x97,0x22}, {0x4b,0x1d,0x9e,0x2f}, +{0x22,0x47,0xe9,0x64}, {0x29,0x49,0xe0,0x69}, {0x34,0x5b,0xfb,0x7e}, {0x3f,0x55,0xf2,0x73}, +{0x0e,0x7f,0xcd,0x50}, {0x05,0x71,0xc4,0x5d}, {0x18,0x63,0xdf,0x4a}, {0x13,0x6d,0xd6,0x47}, +{0xca,0xd7,0x31,0xdc}, {0xc1,0xd9,0x38,0xd1}, {0xdc,0xcb,0x23,0xc6}, {0xd7,0xc5,0x2a,0xcb}, +{0xe6,0xef,0x15,0xe8}, {0xed,0xe1,0x1c,0xe5}, {0xf0,0xf3,0x07,0xf2}, {0xfb,0xfd,0x0e,0xff}, +{0x92,0xa7,0x79,0xb4}, {0x99,0xa9,0x70,0xb9}, {0x84,0xbb,0x6b,0xae}, {0x8f,0xb5,0x62,0xa3}, +{0xbe,0x9f,0x5d,0x80}, {0xb5,0x91,0x54,0x8d}, {0xa8,0x83,0x4f,0x9a}, {0xa3,0x8d,0x46,0x97} + } +}; +#define U2 xU2.xt8 + +static const union xtab xU3 = { + .xt8 = { +{0x00,0x00,0x00,0x00}, {0x0d,0x0b,0x0e,0x09}, {0x1a,0x16,0x1c,0x12}, {0x17,0x1d,0x12,0x1b}, +{0x34,0x2c,0x38,0x24}, {0x39,0x27,0x36,0x2d}, {0x2e,0x3a,0x24,0x36}, {0x23,0x31,0x2a,0x3f}, +{0x68,0x58,0x70,0x48}, {0x65,0x53,0x7e,0x41}, {0x72,0x4e,0x6c,0x5a}, {0x7f,0x45,0x62,0x53}, +{0x5c,0x74,0x48,0x6c}, {0x51,0x7f,0x46,0x65}, {0x46,0x62,0x54,0x7e}, {0x4b,0x69,0x5a,0x77}, +{0xd0,0xb0,0xe0,0x90}, {0xdd,0xbb,0xee,0x99}, {0xca,0xa6,0xfc,0x82}, {0xc7,0xad,0xf2,0x8b}, +{0xe4,0x9c,0xd8,0xb4}, {0xe9,0x97,0xd6,0xbd}, {0xfe,0x8a,0xc4,0xa6}, {0xf3,0x81,0xca,0xaf}, +{0xb8,0xe8,0x90,0xd8}, {0xb5,0xe3,0x9e,0xd1}, {0xa2,0xfe,0x8c,0xca}, {0xaf,0xf5,0x82,0xc3}, +{0x8c,0xc4,0xa8,0xfc}, {0x81,0xcf,0xa6,0xf5}, {0x96,0xd2,0xb4,0xee}, {0x9b,0xd9,0xba,0xe7}, +{0xbb,0x7b,0xdb,0x3b}, {0xb6,0x70,0xd5,0x32}, {0xa1,0x6d,0xc7,0x29}, {0xac,0x66,0xc9,0x20}, +{0x8f,0x57,0xe3,0x1f}, {0x82,0x5c,0xed,0x16}, {0x95,0x41,0xff,0x0d}, {0x98,0x4a,0xf1,0x04}, +{0xd3,0x23,0xab,0x73}, {0xde,0x28,0xa5,0x7a}, {0xc9,0x35,0xb7,0x61}, {0xc4,0x3e,0xb9,0x68}, +{0xe7,0x0f,0x93,0x57}, {0xea,0x04,0x9d,0x5e}, {0xfd,0x19,0x8f,0x45}, {0xf0,0x12,0x81,0x4c}, +{0x6b,0xcb,0x3b,0xab}, {0x66,0xc0,0x35,0xa2}, {0x71,0xdd,0x27,0xb9}, {0x7c,0xd6,0x29,0xb0}, +{0x5f,0xe7,0x03,0x8f}, {0x52,0xec,0x0d,0x86}, {0x45,0xf1,0x1f,0x9d}, {0x48,0xfa,0x11,0x94}, +{0x03,0x93,0x4b,0xe3}, {0x0e,0x98,0x45,0xea}, {0x19,0x85,0x57,0xf1}, {0x14,0x8e,0x59,0xf8}, +{0x37,0xbf,0x73,0xc7}, {0x3a,0xb4,0x7d,0xce}, {0x2d,0xa9,0x6f,0xd5}, {0x20,0xa2,0x61,0xdc}, +{0x6d,0xf6,0xad,0x76}, {0x60,0xfd,0xa3,0x7f}, {0x77,0xe0,0xb1,0x64}, {0x7a,0xeb,0xbf,0x6d}, +{0x59,0xda,0x95,0x52}, {0x54,0xd1,0x9b,0x5b}, {0x43,0xcc,0x89,0x40}, {0x4e,0xc7,0x87,0x49}, +{0x05,0xae,0xdd,0x3e}, {0x08,0xa5,0xd3,0x37}, {0x1f,0xb8,0xc1,0x2c}, {0x12,0xb3,0xcf,0x25}, +{0x31,0x82,0xe5,0x1a}, {0x3c,0x89,0xeb,0x13}, {0x2b,0x94,0xf9,0x08}, {0x26,0x9f,0xf7,0x01}, +{0xbd,0x46,0x4d,0xe6}, {0xb0,0x4d,0x43,0xef}, {0xa7,0x50,0x51,0xf4}, {0xaa,0x5b,0x5f,0xfd}, +{0x89,0x6a,0x75,0xc2}, {0x84,0x61,0x7b,0xcb}, {0x93,0x7c,0x69,0xd0}, {0x9e,0x77,0x67,0xd9}, +{0xd5,0x1e,0x3d,0xae}, {0xd8,0x15,0x33,0xa7}, {0xcf,0x08,0x21,0xbc}, {0xc2,0x03,0x2f,0xb5}, +{0xe1,0x32,0x05,0x8a}, {0xec,0x39,0x0b,0x83}, {0xfb,0x24,0x19,0x98}, {0xf6,0x2f,0x17,0x91}, +{0xd6,0x8d,0x76,0x4d}, {0xdb,0x86,0x78,0x44}, {0xcc,0x9b,0x6a,0x5f}, {0xc1,0x90,0x64,0x56}, +{0xe2,0xa1,0x4e,0x69}, {0xef,0xaa,0x40,0x60}, {0xf8,0xb7,0x52,0x7b}, {0xf5,0xbc,0x5c,0x72}, +{0xbe,0xd5,0x06,0x05}, {0xb3,0xde,0x08,0x0c}, {0xa4,0xc3,0x1a,0x17}, {0xa9,0xc8,0x14,0x1e}, +{0x8a,0xf9,0x3e,0x21}, {0x87,0xf2,0x30,0x28}, {0x90,0xef,0x22,0x33}, {0x9d,0xe4,0x2c,0x3a}, +{0x06,0x3d,0x96,0xdd}, {0x0b,0x36,0x98,0xd4}, {0x1c,0x2b,0x8a,0xcf}, {0x11,0x20,0x84,0xc6}, +{0x32,0x11,0xae,0xf9}, {0x3f,0x1a,0xa0,0xf0}, {0x28,0x07,0xb2,0xeb}, {0x25,0x0c,0xbc,0xe2}, +{0x6e,0x65,0xe6,0x95}, {0x63,0x6e,0xe8,0x9c}, {0x74,0x73,0xfa,0x87}, {0x79,0x78,0xf4,0x8e}, +{0x5a,0x49,0xde,0xb1}, {0x57,0x42,0xd0,0xb8}, {0x40,0x5f,0xc2,0xa3}, {0x4d,0x54,0xcc,0xaa}, +{0xda,0xf7,0x41,0xec}, {0xd7,0xfc,0x4f,0xe5}, {0xc0,0xe1,0x5d,0xfe}, {0xcd,0xea,0x53,0xf7}, +{0xee,0xdb,0x79,0xc8}, {0xe3,0xd0,0x77,0xc1}, {0xf4,0xcd,0x65,0xda}, {0xf9,0xc6,0x6b,0xd3}, +{0xb2,0xaf,0x31,0xa4}, {0xbf,0xa4,0x3f,0xad}, {0xa8,0xb9,0x2d,0xb6}, {0xa5,0xb2,0x23,0xbf}, +{0x86,0x83,0x09,0x80}, {0x8b,0x88,0x07,0x89}, {0x9c,0x95,0x15,0x92}, {0x91,0x9e,0x1b,0x9b}, +{0x0a,0x47,0xa1,0x7c}, {0x07,0x4c,0xaf,0x75}, {0x10,0x51,0xbd,0x6e}, {0x1d,0x5a,0xb3,0x67}, +{0x3e,0x6b,0x99,0x58}, {0x33,0x60,0x97,0x51}, {0x24,0x7d,0x85,0x4a}, {0x29,0x76,0x8b,0x43}, +{0x62,0x1f,0xd1,0x34}, {0x6f,0x14,0xdf,0x3d}, {0x78,0x09,0xcd,0x26}, {0x75,0x02,0xc3,0x2f}, +{0x56,0x33,0xe9,0x10}, {0x5b,0x38,0xe7,0x19}, {0x4c,0x25,0xf5,0x02}, {0x41,0x2e,0xfb,0x0b}, +{0x61,0x8c,0x9a,0xd7}, {0x6c,0x87,0x94,0xde}, {0x7b,0x9a,0x86,0xc5}, {0x76,0x91,0x88,0xcc}, +{0x55,0xa0,0xa2,0xf3}, {0x58,0xab,0xac,0xfa}, {0x4f,0xb6,0xbe,0xe1}, {0x42,0xbd,0xb0,0xe8}, +{0x09,0xd4,0xea,0x9f}, {0x04,0xdf,0xe4,0x96}, {0x13,0xc2,0xf6,0x8d}, {0x1e,0xc9,0xf8,0x84}, +{0x3d,0xf8,0xd2,0xbb}, {0x30,0xf3,0xdc,0xb2}, {0x27,0xee,0xce,0xa9}, {0x2a,0xe5,0xc0,0xa0}, +{0xb1,0x3c,0x7a,0x47}, {0xbc,0x37,0x74,0x4e}, {0xab,0x2a,0x66,0x55}, {0xa6,0x21,0x68,0x5c}, +{0x85,0x10,0x42,0x63}, {0x88,0x1b,0x4c,0x6a}, {0x9f,0x06,0x5e,0x71}, {0x92,0x0d,0x50,0x78}, +{0xd9,0x64,0x0a,0x0f}, {0xd4,0x6f,0x04,0x06}, {0xc3,0x72,0x16,0x1d}, {0xce,0x79,0x18,0x14}, +{0xed,0x48,0x32,0x2b}, {0xe0,0x43,0x3c,0x22}, {0xf7,0x5e,0x2e,0x39}, {0xfa,0x55,0x20,0x30}, +{0xb7,0x01,0xec,0x9a}, {0xba,0x0a,0xe2,0x93}, {0xad,0x17,0xf0,0x88}, {0xa0,0x1c,0xfe,0x81}, +{0x83,0x2d,0xd4,0xbe}, {0x8e,0x26,0xda,0xb7}, {0x99,0x3b,0xc8,0xac}, {0x94,0x30,0xc6,0xa5}, +{0xdf,0x59,0x9c,0xd2}, {0xd2,0x52,0x92,0xdb}, {0xc5,0x4f,0x80,0xc0}, {0xc8,0x44,0x8e,0xc9}, +{0xeb,0x75,0xa4,0xf6}, {0xe6,0x7e,0xaa,0xff}, {0xf1,0x63,0xb8,0xe4}, {0xfc,0x68,0xb6,0xed}, +{0x67,0xb1,0x0c,0x0a}, {0x6a,0xba,0x02,0x03}, {0x7d,0xa7,0x10,0x18}, {0x70,0xac,0x1e,0x11}, +{0x53,0x9d,0x34,0x2e}, {0x5e,0x96,0x3a,0x27}, {0x49,0x8b,0x28,0x3c}, {0x44,0x80,0x26,0x35}, +{0x0f,0xe9,0x7c,0x42}, {0x02,0xe2,0x72,0x4b}, {0x15,0xff,0x60,0x50}, {0x18,0xf4,0x6e,0x59}, +{0x3b,0xc5,0x44,0x66}, {0x36,0xce,0x4a,0x6f}, {0x21,0xd3,0x58,0x74}, {0x2c,0xd8,0x56,0x7d}, +{0x0c,0x7a,0x37,0xa1}, {0x01,0x71,0x39,0xa8}, {0x16,0x6c,0x2b,0xb3}, {0x1b,0x67,0x25,0xba}, +{0x38,0x56,0x0f,0x85}, {0x35,0x5d,0x01,0x8c}, {0x22,0x40,0x13,0x97}, {0x2f,0x4b,0x1d,0x9e}, +{0x64,0x22,0x47,0xe9}, {0x69,0x29,0x49,0xe0}, {0x7e,0x34,0x5b,0xfb}, {0x73,0x3f,0x55,0xf2}, +{0x50,0x0e,0x7f,0xcd}, {0x5d,0x05,0x71,0xc4}, {0x4a,0x18,0x63,0xdf}, {0x47,0x13,0x6d,0xd6}, +{0xdc,0xca,0xd7,0x31}, {0xd1,0xc1,0xd9,0x38}, {0xc6,0xdc,0xcb,0x23}, {0xcb,0xd7,0xc5,0x2a}, +{0xe8,0xe6,0xef,0x15}, {0xe5,0xed,0xe1,0x1c}, {0xf2,0xf0,0xf3,0x07}, {0xff,0xfb,0xfd,0x0e}, +{0xb4,0x92,0xa7,0x79}, {0xb9,0x99,0xa9,0x70}, {0xae,0x84,0xbb,0x6b}, {0xa3,0x8f,0xb5,0x62}, +{0x80,0xbe,0x9f,0x5d}, {0x8d,0xb5,0x91,0x54}, {0x9a,0xa8,0x83,0x4f}, {0x97,0xa3,0x8d,0x46} + } +}; +#define U3 xU3.xt8 + +static const union xtab xU4 = { + .xt8 = { +{0x00,0x00,0x00,0x00}, {0x09,0x0d,0x0b,0x0e}, {0x12,0x1a,0x16,0x1c}, {0x1b,0x17,0x1d,0x12}, +{0x24,0x34,0x2c,0x38}, {0x2d,0x39,0x27,0x36}, {0x36,0x2e,0x3a,0x24}, {0x3f,0x23,0x31,0x2a}, +{0x48,0x68,0x58,0x70}, {0x41,0x65,0x53,0x7e}, {0x5a,0x72,0x4e,0x6c}, {0x53,0x7f,0x45,0x62}, +{0x6c,0x5c,0x74,0x48}, {0x65,0x51,0x7f,0x46}, {0x7e,0x46,0x62,0x54}, {0x77,0x4b,0x69,0x5a}, +{0x90,0xd0,0xb0,0xe0}, {0x99,0xdd,0xbb,0xee}, {0x82,0xca,0xa6,0xfc}, {0x8b,0xc7,0xad,0xf2}, +{0xb4,0xe4,0x9c,0xd8}, {0xbd,0xe9,0x97,0xd6}, {0xa6,0xfe,0x8a,0xc4}, {0xaf,0xf3,0x81,0xca}, +{0xd8,0xb8,0xe8,0x90}, {0xd1,0xb5,0xe3,0x9e}, {0xca,0xa2,0xfe,0x8c}, {0xc3,0xaf,0xf5,0x82}, +{0xfc,0x8c,0xc4,0xa8}, {0xf5,0x81,0xcf,0xa6}, {0xee,0x96,0xd2,0xb4}, {0xe7,0x9b,0xd9,0xba}, +{0x3b,0xbb,0x7b,0xdb}, {0x32,0xb6,0x70,0xd5}, {0x29,0xa1,0x6d,0xc7}, {0x20,0xac,0x66,0xc9}, +{0x1f,0x8f,0x57,0xe3}, {0x16,0x82,0x5c,0xed}, {0x0d,0x95,0x41,0xff}, {0x04,0x98,0x4a,0xf1}, +{0x73,0xd3,0x23,0xab}, {0x7a,0xde,0x28,0xa5}, {0x61,0xc9,0x35,0xb7}, {0x68,0xc4,0x3e,0xb9}, +{0x57,0xe7,0x0f,0x93}, {0x5e,0xea,0x04,0x9d}, {0x45,0xfd,0x19,0x8f}, {0x4c,0xf0,0x12,0x81}, +{0xab,0x6b,0xcb,0x3b}, {0xa2,0x66,0xc0,0x35}, {0xb9,0x71,0xdd,0x27}, {0xb0,0x7c,0xd6,0x29}, +{0x8f,0x5f,0xe7,0x03}, {0x86,0x52,0xec,0x0d}, {0x9d,0x45,0xf1,0x1f}, {0x94,0x48,0xfa,0x11}, +{0xe3,0x03,0x93,0x4b}, {0xea,0x0e,0x98,0x45}, {0xf1,0x19,0x85,0x57}, {0xf8,0x14,0x8e,0x59}, +{0xc7,0x37,0xbf,0x73}, {0xce,0x3a,0xb4,0x7d}, {0xd5,0x2d,0xa9,0x6f}, {0xdc,0x20,0xa2,0x61}, +{0x76,0x6d,0xf6,0xad}, {0x7f,0x60,0xfd,0xa3}, {0x64,0x77,0xe0,0xb1}, {0x6d,0x7a,0xeb,0xbf}, +{0x52,0x59,0xda,0x95}, {0x5b,0x54,0xd1,0x9b}, {0x40,0x43,0xcc,0x89}, {0x49,0x4e,0xc7,0x87}, +{0x3e,0x05,0xae,0xdd}, {0x37,0x08,0xa5,0xd3}, {0x2c,0x1f,0xb8,0xc1}, {0x25,0x12,0xb3,0xcf}, +{0x1a,0x31,0x82,0xe5}, {0x13,0x3c,0x89,0xeb}, {0x08,0x2b,0x94,0xf9}, {0x01,0x26,0x9f,0xf7}, +{0xe6,0xbd,0x46,0x4d}, {0xef,0xb0,0x4d,0x43}, {0xf4,0xa7,0x50,0x51}, {0xfd,0xaa,0x5b,0x5f}, +{0xc2,0x89,0x6a,0x75}, {0xcb,0x84,0x61,0x7b}, {0xd0,0x93,0x7c,0x69}, {0xd9,0x9e,0x77,0x67}, +{0xae,0xd5,0x1e,0x3d}, {0xa7,0xd8,0x15,0x33}, {0xbc,0xcf,0x08,0x21}, {0xb5,0xc2,0x03,0x2f}, +{0x8a,0xe1,0x32,0x05}, {0x83,0xec,0x39,0x0b}, {0x98,0xfb,0x24,0x19}, {0x91,0xf6,0x2f,0x17}, +{0x4d,0xd6,0x8d,0x76}, {0x44,0xdb,0x86,0x78}, {0x5f,0xcc,0x9b,0x6a}, {0x56,0xc1,0x90,0x64}, +{0x69,0xe2,0xa1,0x4e}, {0x60,0xef,0xaa,0x40}, {0x7b,0xf8,0xb7,0x52}, {0x72,0xf5,0xbc,0x5c}, +{0x05,0xbe,0xd5,0x06}, {0x0c,0xb3,0xde,0x08}, {0x17,0xa4,0xc3,0x1a}, {0x1e,0xa9,0xc8,0x14}, +{0x21,0x8a,0xf9,0x3e}, {0x28,0x87,0xf2,0x30}, {0x33,0x90,0xef,0x22}, {0x3a,0x9d,0xe4,0x2c}, +{0xdd,0x06,0x3d,0x96}, {0xd4,0x0b,0x36,0x98}, {0xcf,0x1c,0x2b,0x8a}, {0xc6,0x11,0x20,0x84}, +{0xf9,0x32,0x11,0xae}, {0xf0,0x3f,0x1a,0xa0}, {0xeb,0x28,0x07,0xb2}, {0xe2,0x25,0x0c,0xbc}, +{0x95,0x6e,0x65,0xe6}, {0x9c,0x63,0x6e,0xe8}, {0x87,0x74,0x73,0xfa}, {0x8e,0x79,0x78,0xf4}, +{0xb1,0x5a,0x49,0xde}, {0xb8,0x57,0x42,0xd0}, {0xa3,0x40,0x5f,0xc2}, {0xaa,0x4d,0x54,0xcc}, +{0xec,0xda,0xf7,0x41}, {0xe5,0xd7,0xfc,0x4f}, {0xfe,0xc0,0xe1,0x5d}, {0xf7,0xcd,0xea,0x53}, +{0xc8,0xee,0xdb,0x79}, {0xc1,0xe3,0xd0,0x77}, {0xda,0xf4,0xcd,0x65}, {0xd3,0xf9,0xc6,0x6b}, +{0xa4,0xb2,0xaf,0x31}, {0xad,0xbf,0xa4,0x3f}, {0xb6,0xa8,0xb9,0x2d}, {0xbf,0xa5,0xb2,0x23}, +{0x80,0x86,0x83,0x09}, {0x89,0x8b,0x88,0x07}, {0x92,0x9c,0x95,0x15}, {0x9b,0x91,0x9e,0x1b}, +{0x7c,0x0a,0x47,0xa1}, {0x75,0x07,0x4c,0xaf}, {0x6e,0x10,0x51,0xbd}, {0x67,0x1d,0x5a,0xb3}, +{0x58,0x3e,0x6b,0x99}, {0x51,0x33,0x60,0x97}, {0x4a,0x24,0x7d,0x85}, {0x43,0x29,0x76,0x8b}, +{0x34,0x62,0x1f,0xd1}, {0x3d,0x6f,0x14,0xdf}, {0x26,0x78,0x09,0xcd}, {0x2f,0x75,0x02,0xc3}, +{0x10,0x56,0x33,0xe9}, {0x19,0x5b,0x38,0xe7}, {0x02,0x4c,0x25,0xf5}, {0x0b,0x41,0x2e,0xfb}, +{0xd7,0x61,0x8c,0x9a}, {0xde,0x6c,0x87,0x94}, {0xc5,0x7b,0x9a,0x86}, {0xcc,0x76,0x91,0x88}, +{0xf3,0x55,0xa0,0xa2}, {0xfa,0x58,0xab,0xac}, {0xe1,0x4f,0xb6,0xbe}, {0xe8,0x42,0xbd,0xb0}, +{0x9f,0x09,0xd4,0xea}, {0x96,0x04,0xdf,0xe4}, {0x8d,0x13,0xc2,0xf6}, {0x84,0x1e,0xc9,0xf8}, +{0xbb,0x3d,0xf8,0xd2}, {0xb2,0x30,0xf3,0xdc}, {0xa9,0x27,0xee,0xce}, {0xa0,0x2a,0xe5,0xc0}, +{0x47,0xb1,0x3c,0x7a}, {0x4e,0xbc,0x37,0x74}, {0x55,0xab,0x2a,0x66}, {0x5c,0xa6,0x21,0x68}, +{0x63,0x85,0x10,0x42}, {0x6a,0x88,0x1b,0x4c}, {0x71,0x9f,0x06,0x5e}, {0x78,0x92,0x0d,0x50}, +{0x0f,0xd9,0x64,0x0a}, {0x06,0xd4,0x6f,0x04}, {0x1d,0xc3,0x72,0x16}, {0x14,0xce,0x79,0x18}, +{0x2b,0xed,0x48,0x32}, {0x22,0xe0,0x43,0x3c}, {0x39,0xf7,0x5e,0x2e}, {0x30,0xfa,0x55,0x20}, +{0x9a,0xb7,0x01,0xec}, {0x93,0xba,0x0a,0xe2}, {0x88,0xad,0x17,0xf0}, {0x81,0xa0,0x1c,0xfe}, +{0xbe,0x83,0x2d,0xd4}, {0xb7,0x8e,0x26,0xda}, {0xac,0x99,0x3b,0xc8}, {0xa5,0x94,0x30,0xc6}, +{0xd2,0xdf,0x59,0x9c}, {0xdb,0xd2,0x52,0x92}, {0xc0,0xc5,0x4f,0x80}, {0xc9,0xc8,0x44,0x8e}, +{0xf6,0xeb,0x75,0xa4}, {0xff,0xe6,0x7e,0xaa}, {0xe4,0xf1,0x63,0xb8}, {0xed,0xfc,0x68,0xb6}, +{0x0a,0x67,0xb1,0x0c}, {0x03,0x6a,0xba,0x02}, {0x18,0x7d,0xa7,0x10}, {0x11,0x70,0xac,0x1e}, +{0x2e,0x53,0x9d,0x34}, {0x27,0x5e,0x96,0x3a}, {0x3c,0x49,0x8b,0x28}, {0x35,0x44,0x80,0x26}, +{0x42,0x0f,0xe9,0x7c}, {0x4b,0x02,0xe2,0x72}, {0x50,0x15,0xff,0x60}, {0x59,0x18,0xf4,0x6e}, +{0x66,0x3b,0xc5,0x44}, {0x6f,0x36,0xce,0x4a}, {0x74,0x21,0xd3,0x58}, {0x7d,0x2c,0xd8,0x56}, +{0xa1,0x0c,0x7a,0x37}, {0xa8,0x01,0x71,0x39}, {0xb3,0x16,0x6c,0x2b}, {0xba,0x1b,0x67,0x25}, +{0x85,0x38,0x56,0x0f}, {0x8c,0x35,0x5d,0x01}, {0x97,0x22,0x40,0x13}, {0x9e,0x2f,0x4b,0x1d}, +{0xe9,0x64,0x22,0x47}, {0xe0,0x69,0x29,0x49}, {0xfb,0x7e,0x34,0x5b}, {0xf2,0x73,0x3f,0x55}, +{0xcd,0x50,0x0e,0x7f}, {0xc4,0x5d,0x05,0x71}, {0xdf,0x4a,0x18,0x63}, {0xd6,0x47,0x13,0x6d}, +{0x31,0xdc,0xca,0xd7}, {0x38,0xd1,0xc1,0xd9}, {0x23,0xc6,0xdc,0xcb}, {0x2a,0xcb,0xd7,0xc5}, +{0x15,0xe8,0xe6,0xef}, {0x1c,0xe5,0xed,0xe1}, {0x07,0xf2,0xf0,0xf3}, {0x0e,0xff,0xfb,0xfd}, +{0x79,0xb4,0x92,0xa7}, {0x70,0xb9,0x99,0xa9}, {0x6b,0xae,0x84,0xbb}, {0x62,0xa3,0x8f,0xb5}, +{0x5d,0x80,0xbe,0x9f}, {0x54,0x8d,0xb5,0x91}, {0x4f,0x9a,0xa8,0x83}, {0x46,0x97,0xa3,0x8d} + } +}; +#define U4 xU4.xt8 + +static const word32 rcon[30] = { + 0x01,0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 +}; diff --git a/bsd/crypto/rijndael/rijndael-alg-fst.c b/bsd/crypto/rijndael/rijndael-alg-fst.c new file mode 100644 index 000000000..5cd4857e4 --- /dev/null +++ b/bsd/crypto/rijndael/rijndael-alg-fst.c @@ -0,0 +1,488 @@ +/* $FreeBSD: src/sys/crypto/rijndael/rijndael-alg-fst.c,v 1.3.2.1 2001/07/03 11:01:35 ume Exp $ */ +/* $KAME: rijndael-alg-fst.c,v 1.7 2001/05/27 00:23:23 itojun Exp $ */ + +/* + * rijndael-alg-fst.c v2.3 April '2000 + * + * Optimised ANSI C code + * + * authors: v1.0: Antoon Bosselaers + * v2.0: Vincent Rijmen + * v2.3: Paulo Barreto + * + * This code is placed in the public domain. + */ + +#include +#include +#ifdef KERNEL +#include +#else +#include +#endif +#include +#include + +#include + +int rijndaelKeySched(word8 k[MAXKC][4], word8 W[MAXROUNDS+1][4][4], int ROUNDS) { + /* Calculate the necessary round keys + * The number of calculations depends on keyBits and blockBits + */ + int j, r, t, rconpointer = 0; + union { + word8 x8[MAXKC][4]; + word32 x32[MAXKC]; + } xtk; +#define tk xtk.x8 + int KC = ROUNDS - 6; + + for (j = KC-1; j >= 0; j--) { + *((word32*)tk[j]) = *((word32*)k[j]); + } + r = 0; + t = 0; + /* copy values into round key array */ + for (j = 0; (j < KC) && (r < ROUNDS + 1); ) { + for (; (j < KC) && (t < 4); j++, t++) { + *((word32*)W[r][t]) = *((word32*)tk[j]); + } + if (t == 4) { + r++; + t = 0; + } + } + + while (r < ROUNDS + 1) { /* while not enough round key material calculated */ + /* calculate new values */ + tk[0][0] ^= S[tk[KC-1][1]]; + tk[0][1] ^= S[tk[KC-1][2]]; + tk[0][2] ^= S[tk[KC-1][3]]; + tk[0][3] ^= S[tk[KC-1][0]]; + tk[0][0] ^= rcon[rconpointer++]; + + if (KC != 8) { + for (j = 1; j < KC; j++) { + *((word32*)tk[j]) ^= *((word32*)tk[j-1]); + } + } else { + for (j = 1; j < KC/2; j++) { + *((word32*)tk[j]) ^= *((word32*)tk[j-1]); + } + tk[KC/2][0] ^= S[tk[KC/2 - 1][0]]; + tk[KC/2][1] ^= S[tk[KC/2 - 1][1]]; + tk[KC/2][2] ^= S[tk[KC/2 - 1][2]]; + tk[KC/2][3] ^= S[tk[KC/2 - 1][3]]; + for (j = KC/2 + 1; j < KC; j++) { + *((word32*)tk[j]) ^= *((word32*)tk[j-1]); + } + } + /* copy values into round key array */ + for (j = 0; (j < KC) && (r < ROUNDS + 1); ) { + for (; (j < KC) && (t < 4); j++, t++) { + *((word32*)W[r][t]) = *((word32*)tk[j]); + } + if (t == 4) { + r++; + t = 0; + } + } + } + return 0; +#undef tk +} + +int rijndaelKeyEncToDec(word8 W[MAXROUNDS+1][4][4], int ROUNDS) { + int r; + word8 *w; + + for (r = 1; r < ROUNDS; r++) { + w = W[r][0]; + *((word32*)w) = + *((const word32*)U1[w[0]]) + ^ *((const word32*)U2[w[1]]) + ^ *((const word32*)U3[w[2]]) + ^ *((const word32*)U4[w[3]]); + + w = W[r][1]; + *((word32*)w) = + *((const word32*)U1[w[0]]) + ^ *((const word32*)U2[w[1]]) + ^ *((const word32*)U3[w[2]]) + ^ *((const word32*)U4[w[3]]); + + w = W[r][2]; + *((word32*)w) = + *((const word32*)U1[w[0]]) + ^ *((const word32*)U2[w[1]]) + ^ *((const word32*)U3[w[2]]) + ^ *((const word32*)U4[w[3]]); + + w = W[r][3]; + *((word32*)w) = + *((const word32*)U1[w[0]]) + ^ *((const word32*)U2[w[1]]) + ^ *((const word32*)U3[w[2]]) + ^ *((const word32*)U4[w[3]]); + } + return 0; +} + +/** + * Encrypt a single block. + */ +int rijndaelEncrypt(word8 in[16], word8 out[16], word8 rk[MAXROUNDS+1][4][4], int ROUNDS) { + int r; + union { + word8 x8[16]; + word32 x32[4]; + } xa, xb; +#define a xa.x8 +#define b xb.x8 + union { + word8 x8[4][4]; + word32 x32[4]; + } xtemp; +#define temp xtemp.x8 + + memcpy(a, in, sizeof a); + + *((word32*)temp[0]) = *((word32*)(a )) ^ *((word32*)rk[0][0]); + *((word32*)temp[1]) = *((word32*)(a+ 4)) ^ *((word32*)rk[0][1]); + *((word32*)temp[2]) = *((word32*)(a+ 8)) ^ *((word32*)rk[0][2]); + *((word32*)temp[3]) = *((word32*)(a+12)) ^ *((word32*)rk[0][3]); + *((word32*)(b )) = *((const word32*)T1[temp[0][0]]) + ^ *((const word32*)T2[temp[1][1]]) + ^ *((const word32*)T3[temp[2][2]]) + ^ *((const word32*)T4[temp[3][3]]); + *((word32*)(b + 4)) = *((const word32*)T1[temp[1][0]]) + ^ *((const word32*)T2[temp[2][1]]) + ^ *((const word32*)T3[temp[3][2]]) + ^ *((const word32*)T4[temp[0][3]]); + *((word32*)(b + 8)) = *((const word32*)T1[temp[2][0]]) + ^ *((const word32*)T2[temp[3][1]]) + ^ *((const word32*)T3[temp[0][2]]) + ^ *((const word32*)T4[temp[1][3]]); + *((word32*)(b +12)) = *((const word32*)T1[temp[3][0]]) + ^ *((const word32*)T2[temp[0][1]]) + ^ *((const word32*)T3[temp[1][2]]) + ^ *((const word32*)T4[temp[2][3]]); + for (r = 1; r < ROUNDS-1; r++) { + *((word32*)temp[0]) = *((word32*)(b )) ^ *((word32*)rk[r][0]); + *((word32*)temp[1]) = *((word32*)(b+ 4)) ^ *((word32*)rk[r][1]); + *((word32*)temp[2]) = *((word32*)(b+ 8)) ^ *((word32*)rk[r][2]); + *((word32*)temp[3]) = *((word32*)(b+12)) ^ *((word32*)rk[r][3]); + + *((word32*)(b )) = *((const word32*)T1[temp[0][0]]) + ^ *((const word32*)T2[temp[1][1]]) + ^ *((const word32*)T3[temp[2][2]]) + ^ *((const word32*)T4[temp[3][3]]); + *((word32*)(b + 4)) = *((const word32*)T1[temp[1][0]]) + ^ *((const word32*)T2[temp[2][1]]) + ^ *((const word32*)T3[temp[3][2]]) + ^ *((const word32*)T4[temp[0][3]]); + *((word32*)(b + 8)) = *((const word32*)T1[temp[2][0]]) + ^ *((const word32*)T2[temp[3][1]]) + ^ *((const word32*)T3[temp[0][2]]) + ^ *((const word32*)T4[temp[1][3]]); + *((word32*)(b +12)) = *((const word32*)T1[temp[3][0]]) + ^ *((const word32*)T2[temp[0][1]]) + ^ *((const word32*)T3[temp[1][2]]) + ^ *((const word32*)T4[temp[2][3]]); + } + /* last round is special */ + *((word32*)temp[0]) = *((word32*)(b )) ^ *((word32*)rk[ROUNDS-1][0]); + *((word32*)temp[1]) = *((word32*)(b+ 4)) ^ *((word32*)rk[ROUNDS-1][1]); + *((word32*)temp[2]) = *((word32*)(b+ 8)) ^ *((word32*)rk[ROUNDS-1][2]); + *((word32*)temp[3]) = *((word32*)(b+12)) ^ *((word32*)rk[ROUNDS-1][3]); + b[ 0] = T1[temp[0][0]][1]; + b[ 1] = T1[temp[1][1]][1]; + b[ 2] = T1[temp[2][2]][1]; + b[ 3] = T1[temp[3][3]][1]; + b[ 4] = T1[temp[1][0]][1]; + b[ 5] = T1[temp[2][1]][1]; + b[ 6] = T1[temp[3][2]][1]; + b[ 7] = T1[temp[0][3]][1]; + b[ 8] = T1[temp[2][0]][1]; + b[ 9] = T1[temp[3][1]][1]; + b[10] = T1[temp[0][2]][1]; + b[11] = T1[temp[1][3]][1]; + b[12] = T1[temp[3][0]][1]; + b[13] = T1[temp[0][1]][1]; + b[14] = T1[temp[1][2]][1]; + b[15] = T1[temp[2][3]][1]; + *((word32*)(b )) ^= *((word32*)rk[ROUNDS][0]); + *((word32*)(b+ 4)) ^= *((word32*)rk[ROUNDS][1]); + *((word32*)(b+ 8)) ^= *((word32*)rk[ROUNDS][2]); + *((word32*)(b+12)) ^= *((word32*)rk[ROUNDS][3]); + + memcpy(out, b, sizeof b /* XXX out */); + + return 0; +#undef a +#undef b +#undef temp +} + +#ifdef INTERMEDIATE_VALUE_KAT +/** + * Encrypt only a certain number of rounds. + * Only used in the Intermediate Value Known Answer Test. + */ +int rijndaelEncryptRound(word8 a[4][4], word8 rk[MAXROUNDS+1][4][4], int ROUNDS, int rounds) { + int r; + word8 temp[4][4]; + + /* make number of rounds sane */ + if (rounds > ROUNDS) { + rounds = ROUNDS; + } + + *((word32*)a[0]) = *((word32*)a[0]) ^ *((word32*)rk[0][0]); + *((word32*)a[1]) = *((word32*)a[1]) ^ *((word32*)rk[0][1]); + *((word32*)a[2]) = *((word32*)a[2]) ^ *((word32*)rk[0][2]); + *((word32*)a[3]) = *((word32*)a[3]) ^ *((word32*)rk[0][3]); + + for (r = 1; (r <= rounds) && (r < ROUNDS); r++) { + *((word32*)temp[0]) = *((word32*)T1[a[0][0]]) + ^ *((word32*)T2[a[1][1]]) + ^ *((word32*)T3[a[2][2]]) + ^ *((word32*)T4[a[3][3]]); + *((word32*)temp[1]) = *((word32*)T1[a[1][0]]) + ^ *((word32*)T2[a[2][1]]) + ^ *((word32*)T3[a[3][2]]) + ^ *((word32*)T4[a[0][3]]); + *((word32*)temp[2]) = *((word32*)T1[a[2][0]]) + ^ *((word32*)T2[a[3][1]]) + ^ *((word32*)T3[a[0][2]]) + ^ *((word32*)T4[a[1][3]]); + *((word32*)temp[3]) = *((word32*)T1[a[3][0]]) + ^ *((word32*)T2[a[0][1]]) + ^ *((word32*)T3[a[1][2]]) + ^ *((word32*)T4[a[2][3]]); + *((word32*)a[0]) = *((word32*)temp[0]) ^ *((word32*)rk[r][0]); + *((word32*)a[1]) = *((word32*)temp[1]) ^ *((word32*)rk[r][1]); + *((word32*)a[2]) = *((word32*)temp[2]) ^ *((word32*)rk[r][2]); + *((word32*)a[3]) = *((word32*)temp[3]) ^ *((word32*)rk[r][3]); + } + if (rounds == ROUNDS) { + /* last round is special */ + temp[0][0] = T1[a[0][0]][1]; + temp[0][1] = T1[a[1][1]][1]; + temp[0][2] = T1[a[2][2]][1]; + temp[0][3] = T1[a[3][3]][1]; + temp[1][0] = T1[a[1][0]][1]; + temp[1][1] = T1[a[2][1]][1]; + temp[1][2] = T1[a[3][2]][1]; + temp[1][3] = T1[a[0][3]][1]; + temp[2][0] = T1[a[2][0]][1]; + temp[2][1] = T1[a[3][1]][1]; + temp[2][2] = T1[a[0][2]][1]; + temp[2][3] = T1[a[1][3]][1]; + temp[3][0] = T1[a[3][0]][1]; + temp[3][1] = T1[a[0][1]][1]; + temp[3][2] = T1[a[1][2]][1]; + temp[3][3] = T1[a[2][3]][1]; + *((word32*)a[0]) = *((word32*)temp[0]) ^ *((word32*)rk[ROUNDS][0]); + *((word32*)a[1]) = *((word32*)temp[1]) ^ *((word32*)rk[ROUNDS][1]); + *((word32*)a[2]) = *((word32*)temp[2]) ^ *((word32*)rk[ROUNDS][2]); + *((word32*)a[3]) = *((word32*)temp[3]) ^ *((word32*)rk[ROUNDS][3]); + } + + return 0; +} +#endif /* INTERMEDIATE_VALUE_KAT */ + +/** + * Decrypt a single block. + */ +int rijndaelDecrypt(word8 in[16], word8 out[16], word8 rk[MAXROUNDS+1][4][4], int ROUNDS) { + int r; + union { + word8 x8[16]; + word32 x32[4]; + } xa, xb; +#define a xa.x8 +#define b xb.x8 + union { + word8 x8[4][4]; + word32 x32[4]; + } xtemp; +#define temp xtemp.x8 + + memcpy(a, in, sizeof a); + + *((word32*)temp[0]) = *((word32*)(a )) ^ *((word32*)rk[ROUNDS][0]); + *((word32*)temp[1]) = *((word32*)(a+ 4)) ^ *((word32*)rk[ROUNDS][1]); + *((word32*)temp[2]) = *((word32*)(a+ 8)) ^ *((word32*)rk[ROUNDS][2]); + *((word32*)temp[3]) = *((word32*)(a+12)) ^ *((word32*)rk[ROUNDS][3]); + + *((word32*)(b )) = *((const word32*)T5[temp[0][0]]) + ^ *((const word32*)T6[temp[3][1]]) + ^ *((const word32*)T7[temp[2][2]]) + ^ *((const word32*)T8[temp[1][3]]); + *((word32*)(b+ 4)) = *((const word32*)T5[temp[1][0]]) + ^ *((const word32*)T6[temp[0][1]]) + ^ *((const word32*)T7[temp[3][2]]) + ^ *((const word32*)T8[temp[2][3]]); + *((word32*)(b+ 8)) = *((const word32*)T5[temp[2][0]]) + ^ *((const word32*)T6[temp[1][1]]) + ^ *((const word32*)T7[temp[0][2]]) + ^ *((const word32*)T8[temp[3][3]]); + *((word32*)(b+12)) = *((const word32*)T5[temp[3][0]]) + ^ *((const word32*)T6[temp[2][1]]) + ^ *((const word32*)T7[temp[1][2]]) + ^ *((const word32*)T8[temp[0][3]]); + for (r = ROUNDS-1; r > 1; r--) { + *((word32*)temp[0]) = *((word32*)(b )) ^ *((word32*)rk[r][0]); + *((word32*)temp[1]) = *((word32*)(b+ 4)) ^ *((word32*)rk[r][1]); + *((word32*)temp[2]) = *((word32*)(b+ 8)) ^ *((word32*)rk[r][2]); + *((word32*)temp[3]) = *((word32*)(b+12)) ^ *((word32*)rk[r][3]); + *((word32*)(b )) = *((const word32*)T5[temp[0][0]]) + ^ *((const word32*)T6[temp[3][1]]) + ^ *((const word32*)T7[temp[2][2]]) + ^ *((const word32*)T8[temp[1][3]]); + *((word32*)(b+ 4)) = *((const word32*)T5[temp[1][0]]) + ^ *((const word32*)T6[temp[0][1]]) + ^ *((const word32*)T7[temp[3][2]]) + ^ *((const word32*)T8[temp[2][3]]); + *((word32*)(b+ 8)) = *((const word32*)T5[temp[2][0]]) + ^ *((const word32*)T6[temp[1][1]]) + ^ *((const word32*)T7[temp[0][2]]) + ^ *((const word32*)T8[temp[3][3]]); + *((word32*)(b+12)) = *((const word32*)T5[temp[3][0]]) + ^ *((const word32*)T6[temp[2][1]]) + ^ *((const word32*)T7[temp[1][2]]) + ^ *((const word32*)T8[temp[0][3]]); + } + /* last round is special */ + *((word32*)temp[0]) = *((word32*)(b )) ^ *((word32*)rk[1][0]); + *((word32*)temp[1]) = *((word32*)(b+ 4)) ^ *((word32*)rk[1][1]); + *((word32*)temp[2]) = *((word32*)(b+ 8)) ^ *((word32*)rk[1][2]); + *((word32*)temp[3]) = *((word32*)(b+12)) ^ *((word32*)rk[1][3]); + b[ 0] = S5[temp[0][0]]; + b[ 1] = S5[temp[3][1]]; + b[ 2] = S5[temp[2][2]]; + b[ 3] = S5[temp[1][3]]; + b[ 4] = S5[temp[1][0]]; + b[ 5] = S5[temp[0][1]]; + b[ 6] = S5[temp[3][2]]; + b[ 7] = S5[temp[2][3]]; + b[ 8] = S5[temp[2][0]]; + b[ 9] = S5[temp[1][1]]; + b[10] = S5[temp[0][2]]; + b[11] = S5[temp[3][3]]; + b[12] = S5[temp[3][0]]; + b[13] = S5[temp[2][1]]; + b[14] = S5[temp[1][2]]; + b[15] = S5[temp[0][3]]; + *((word32*)(b )) ^= *((word32*)rk[0][0]); + *((word32*)(b+ 4)) ^= *((word32*)rk[0][1]); + *((word32*)(b+ 8)) ^= *((word32*)rk[0][2]); + *((word32*)(b+12)) ^= *((word32*)rk[0][3]); + + memcpy(out, b, sizeof b /* XXX out */); + + return 0; +#undef a +#undef b +#undef temp +} + + +#ifdef INTERMEDIATE_VALUE_KAT +/** + * Decrypt only a certain number of rounds. + * Only used in the Intermediate Value Known Answer Test. + * Operations rearranged such that the intermediate values + * of decryption correspond with the intermediate values + * of encryption. + */ +int rijndaelDecryptRound(word8 a[4][4], word8 rk[MAXROUNDS+1][4][4], int ROUNDS, int rounds) { + int r, i; + word8 temp[4], shift; + + /* make number of rounds sane */ + if (rounds > ROUNDS) { + rounds = ROUNDS; + } + /* first round is special: */ + *(word32 *)a[0] ^= *(word32 *)rk[ROUNDS][0]; + *(word32 *)a[1] ^= *(word32 *)rk[ROUNDS][1]; + *(word32 *)a[2] ^= *(word32 *)rk[ROUNDS][2]; + *(word32 *)a[3] ^= *(word32 *)rk[ROUNDS][3]; + for (i = 0; i < 4; i++) { + a[i][0] = Si[a[i][0]]; + a[i][1] = Si[a[i][1]]; + a[i][2] = Si[a[i][2]]; + a[i][3] = Si[a[i][3]]; + } + for (i = 1; i < 4; i++) { + shift = (4 - i) & 3; + temp[0] = a[(0 + shift) & 3][i]; + temp[1] = a[(1 + shift) & 3][i]; + temp[2] = a[(2 + shift) & 3][i]; + temp[3] = a[(3 + shift) & 3][i]; + a[0][i] = temp[0]; + a[1][i] = temp[1]; + a[2][i] = temp[2]; + a[3][i] = temp[3]; + } + /* ROUNDS-1 ordinary rounds */ + for (r = ROUNDS-1; r > rounds; r--) { + *(word32 *)a[0] ^= *(word32 *)rk[r][0]; + *(word32 *)a[1] ^= *(word32 *)rk[r][1]; + *(word32 *)a[2] ^= *(word32 *)rk[r][2]; + *(word32 *)a[3] ^= *(word32 *)rk[r][3]; + + *((word32*)a[0]) = + *((word32*)U1[a[0][0]]) + ^ *((word32*)U2[a[0][1]]) + ^ *((word32*)U3[a[0][2]]) + ^ *((word32*)U4[a[0][3]]); + + *((word32*)a[1]) = + *((word32*)U1[a[1][0]]) + ^ *((word32*)U2[a[1][1]]) + ^ *((word32*)U3[a[1][2]]) + ^ *((word32*)U4[a[1][3]]); + + *((word32*)a[2]) = + *((word32*)U1[a[2][0]]) + ^ *((word32*)U2[a[2][1]]) + ^ *((word32*)U3[a[2][2]]) + ^ *((word32*)U4[a[2][3]]); + + *((word32*)a[3]) = + *((word32*)U1[a[3][0]]) + ^ *((word32*)U2[a[3][1]]) + ^ *((word32*)U3[a[3][2]]) + ^ *((word32*)U4[a[3][3]]); + for (i = 0; i < 4; i++) { + a[i][0] = Si[a[i][0]]; + a[i][1] = Si[a[i][1]]; + a[i][2] = Si[a[i][2]]; + a[i][3] = Si[a[i][3]]; + } + for (i = 1; i < 4; i++) { + shift = (4 - i) & 3; + temp[0] = a[(0 + shift) & 3][i]; + temp[1] = a[(1 + shift) & 3][i]; + temp[2] = a[(2 + shift) & 3][i]; + temp[3] = a[(3 + shift) & 3][i]; + a[0][i] = temp[0]; + a[1][i] = temp[1]; + a[2][i] = temp[2]; + a[3][i] = temp[3]; + } + } + if (rounds == 0) { + /* End with the extra key addition */ + *(word32 *)a[0] ^= *(word32 *)rk[0][0]; + *(word32 *)a[1] ^= *(word32 *)rk[0][1]; + *(word32 *)a[2] ^= *(word32 *)rk[0][2]; + *(word32 *)a[3] ^= *(word32 *)rk[0][3]; + } + return 0; +} +#endif /* INTERMEDIATE_VALUE_KAT */ diff --git a/bsd/crypto/rijndael/rijndael-alg-fst.h b/bsd/crypto/rijndael/rijndael-alg-fst.h new file mode 100644 index 000000000..811ce60d1 --- /dev/null +++ b/bsd/crypto/rijndael/rijndael-alg-fst.h @@ -0,0 +1,34 @@ +/* $FreeBSD: src/sys/crypto/rijndael/rijndael-alg-fst.h,v 1.2.2.1 2001/07/03 11:01:35 ume Exp $ */ +/* $KAME: rijndael-alg-fst.h,v 1.4 2000/10/02 17:14:26 itojun Exp $ */ + +/* + * rijndael-alg-fst.h v2.3 April '2000 + * + * Optimised ANSI C code + * + * #define INTERMEDIATE_VALUE_KAT to generate the Intermediate Value Known Answer Test. + */ + +#ifndef __RIJNDAEL_ALG_FST_H +#define __RIJNDAEL_ALG_FST_H + +#define RIJNDAEL_MAXKC (256/32) +#define RIJNDAEL_MAXROUNDS 14 + +int rijndaelKeySched(u_int8_t k[RIJNDAEL_MAXKC][4], u_int8_t rk[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS); + +int rijndaelKeyEncToDec(u_int8_t W[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS); + +int rijndaelEncrypt(u_int8_t a[16], u_int8_t b[16], u_int8_t rk[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS); + +#ifdef INTERMEDIATE_VALUE_KAT +int rijndaelEncryptRound(u_int8_t a[4][4], u_int8_t rk[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS, int rounds); +#endif /* INTERMEDIATE_VALUE_KAT */ + +int rijndaelDecrypt(u_int8_t a[16], u_int8_t b[16], u_int8_t rk[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS); + +#ifdef INTERMEDIATE_VALUE_KAT +int rijndaelDecryptRound(u_int8_t a[4][4], u_int8_t rk[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS, int rounds); +#endif /* INTERMEDIATE_VALUE_KAT */ + +#endif /* __RIJNDAEL_ALG_FST_H */ diff --git a/bsd/crypto/rijndael/rijndael-api-fst.c b/bsd/crypto/rijndael/rijndael-api-fst.c new file mode 100644 index 000000000..295bab387 --- /dev/null +++ b/bsd/crypto/rijndael/rijndael-api-fst.c @@ -0,0 +1,484 @@ +/* $FreeBSD: src/sys/crypto/rijndael/rijndael-api-fst.c,v 1.2.2.1 2001/07/03 11:01:35 ume Exp $ */ +/* $KAME: rijndael-api-fst.c,v 1.10 2001/05/27 09:34:18 itojun Exp $ */ + +/* + * rijndael-api-fst.c v2.3 April '2000 + * + * Optimised ANSI C code + * + * authors: v1.0: Antoon Bosselaers + * v2.0: Vincent Rijmen + * v2.1: Vincent Rijmen + * v2.2: Vincent Rijmen + * v2.3: Paulo Barreto + * v2.4: Vincent Rijmen + * + * This code is placed in the public domain. + */ + +#include +#include +#ifdef KERNEL +#include +#else +#include +#endif +#include +#include +#include + +int rijndael_makeKey(keyInstance *key, BYTE direction, int keyLen, char *keyMaterial) { + word8 k[MAXKC][4]; + int i; + char *keyMat; + + if (key == NULL) { + return BAD_KEY_INSTANCE; + } + + if ((direction == DIR_ENCRYPT) || (direction == DIR_DECRYPT)) { + key->direction = direction; + } else { + return BAD_KEY_DIR; + } + + if ((keyLen == 128) || (keyLen == 192) || (keyLen == 256)) { + key->keyLen = keyLen; + } else { + return BAD_KEY_MAT; + } + + if (keyMaterial != NULL) { + bcopy(keyMaterial, key->keyMaterial, keyLen/8); + } + + key->ROUNDS = keyLen/32 + 6; + + /* initialize key schedule: */ + keyMat = key->keyMaterial; + for (i = 0; i < key->keyLen/8; i++) { + k[i >> 2][i & 3] = (word8)keyMat[i]; + } + rijndaelKeySched(k, key->keySched, key->ROUNDS); + if (direction == DIR_DECRYPT) { + rijndaelKeyEncToDec(key->keySched, key->ROUNDS); + } + + return TRUE; +} + +int rijndael_cipherInit(cipherInstance *cipher, BYTE mode, char *IV) { + if ((mode == MODE_ECB) || (mode == MODE_CBC) || (mode == MODE_CFB1)) { + cipher->mode = mode; + } else { + return BAD_CIPHER_MODE; + } + if (IV != NULL) { + bcopy(IV, cipher->IV, MAX_IV_SIZE); + } else { + bzero(cipher->IV, MAX_IV_SIZE); + } + return TRUE; +} + +int rijndael_blockEncrypt(cipherInstance *cipher, keyInstance *key, + BYTE *input, int inputLen, BYTE *outBuffer) { + int i, k, numBlocks; + word8 block[16], iv[4][4]; + + if (cipher == NULL || + key == NULL || + key->direction == DIR_DECRYPT) { + return BAD_CIPHER_STATE; + } + if (input == NULL || inputLen <= 0) { + return 0; /* nothing to do */ + } + + numBlocks = inputLen/128; + + switch (cipher->mode) { + case MODE_ECB: + for (i = numBlocks; i > 0; i--) { + rijndaelEncrypt(input, outBuffer, key->keySched, key->ROUNDS); + input += 16; + outBuffer += 16; + } + break; + + case MODE_CBC: +#if 1 /*STRICT_ALIGN*/ + bcopy(cipher->IV, block, 16); + bcopy(input, iv, 16); + ((word32*)block)[0] ^= ((word32*)iv)[0]; + ((word32*)block)[1] ^= ((word32*)iv)[1]; + ((word32*)block)[2] ^= ((word32*)iv)[2]; + ((word32*)block)[3] ^= ((word32*)iv)[3]; +#else + ((word32*)block)[0] = ((word32*)cipher->IV)[0] ^ ((word32*)input)[0]; + ((word32*)block)[1] = ((word32*)cipher->IV)[1] ^ ((word32*)input)[1]; + ((word32*)block)[2] = ((word32*)cipher->IV)[2] ^ ((word32*)input)[2]; + ((word32*)block)[3] = ((word32*)cipher->IV)[3] ^ ((word32*)input)[3]; +#endif + rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS); + input += 16; + for (i = numBlocks - 1; i > 0; i--) { +#if 1 /*STRICT_ALIGN*/ + bcopy(outBuffer, block, 16); + ((word32*)block)[0] ^= ((word32*)iv)[0]; + ((word32*)block)[1] ^= ((word32*)iv)[1]; + ((word32*)block)[2] ^= ((word32*)iv)[2]; + ((word32*)block)[3] ^= ((word32*)iv)[3]; +#else + ((word32*)block)[0] = ((word32*)outBuffer)[0] ^ ((word32*)input)[0]; + ((word32*)block)[1] = ((word32*)outBuffer)[1] ^ ((word32*)input)[1]; + ((word32*)block)[2] = ((word32*)outBuffer)[2] ^ ((word32*)input)[2]; + ((word32*)block)[3] = ((word32*)outBuffer)[3] ^ ((word32*)input)[3]; +#endif + outBuffer += 16; + rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS); + input += 16; + } + break; + + case MODE_CFB1: +#if 1 /*STRICT_ALIGN*/ + bcopy(cipher->IV, iv, 16); +#else /* !STRICT_ALIGN */ + *((word32*)iv[0]) = *((word32*)(cipher->IV )); + *((word32*)iv[1]) = *((word32*)(cipher->IV+ 4)); + *((word32*)iv[2]) = *((word32*)(cipher->IV+ 8)); + *((word32*)iv[3]) = *((word32*)(cipher->IV+12)); +#endif /* ?STRICT_ALIGN */ + for (i = numBlocks; i > 0; i--) { + for (k = 0; k < 128; k++) { + *((word32*) block ) = *((word32*)iv[0]); + *((word32*)(block+ 4)) = *((word32*)iv[1]); + *((word32*)(block+ 8)) = *((word32*)iv[2]); + *((word32*)(block+12)) = *((word32*)iv[3]); + rijndaelEncrypt(block, block, key->keySched, key->ROUNDS); + outBuffer[k/8] ^= (block[0] & 0x80) >> (k & 7); + iv[0][0] = (iv[0][0] << 1) | (iv[0][1] >> 7); + iv[0][1] = (iv[0][1] << 1) | (iv[0][2] >> 7); + iv[0][2] = (iv[0][2] << 1) | (iv[0][3] >> 7); + iv[0][3] = (iv[0][3] << 1) | (iv[1][0] >> 7); + iv[1][0] = (iv[1][0] << 1) | (iv[1][1] >> 7); + iv[1][1] = (iv[1][1] << 1) | (iv[1][2] >> 7); + iv[1][2] = (iv[1][2] << 1) | (iv[1][3] >> 7); + iv[1][3] = (iv[1][3] << 1) | (iv[2][0] >> 7); + iv[2][0] = (iv[2][0] << 1) | (iv[2][1] >> 7); + iv[2][1] = (iv[2][1] << 1) | (iv[2][2] >> 7); + iv[2][2] = (iv[2][2] << 1) | (iv[2][3] >> 7); + iv[2][3] = (iv[2][3] << 1) | (iv[3][0] >> 7); + iv[3][0] = (iv[3][0] << 1) | (iv[3][1] >> 7); + iv[3][1] = (iv[3][1] << 1) | (iv[3][2] >> 7); + iv[3][2] = (iv[3][2] << 1) | (iv[3][3] >> 7); + iv[3][3] = (iv[3][3] << 1) | ((outBuffer[k/8] >> (7-(k&7))) & 1); + } + } + break; + + default: + return BAD_CIPHER_STATE; + } + + return 128*numBlocks; +} + +/** + * Encrypt data partitioned in octets, using RFC 2040-like padding. + * + * @param input data to be encrypted (octet sequence) + * @param inputOctets input length in octets (not bits) + * @param outBuffer encrypted output data + * + * @return length in octets (not bits) of the encrypted output buffer. + */ +int rijndael_padEncrypt(cipherInstance *cipher, keyInstance *key, + BYTE *input, int inputOctets, BYTE *outBuffer) { + int i, numBlocks, padLen; + word8 block[16], *iv, *cp; + + if (cipher == NULL || + key == NULL || + key->direction == DIR_DECRYPT) { + return BAD_CIPHER_STATE; + } + if (input == NULL || inputOctets <= 0) { + return 0; /* nothing to do */ + } + + numBlocks = inputOctets/16; + + switch (cipher->mode) { + case MODE_ECB: + for (i = numBlocks; i > 0; i--) { + rijndaelEncrypt(input, outBuffer, key->keySched, key->ROUNDS); + input += 16; + outBuffer += 16; + } + padLen = 16 - (inputOctets - 16*numBlocks); + if (padLen > 0 && padLen <= 16) + panic("rijndael_padEncrypt(ECB)"); + bcopy(input, block, 16 - padLen); + for (cp = block + 16 - padLen; cp < block + 16; cp++) + *cp = padLen; + rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS); + break; + + case MODE_CBC: + iv = cipher->IV; + for (i = numBlocks; i > 0; i--) { + ((word32*)block)[0] = ((word32*)input)[0] ^ ((word32*)iv)[0]; + ((word32*)block)[1] = ((word32*)input)[1] ^ ((word32*)iv)[1]; + ((word32*)block)[2] = ((word32*)input)[2] ^ ((word32*)iv)[2]; + ((word32*)block)[3] = ((word32*)input)[3] ^ ((word32*)iv)[3]; + rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS); + iv = outBuffer; + input += 16; + outBuffer += 16; + } + padLen = 16 - (inputOctets - 16*numBlocks); + if (padLen > 0 && padLen <= 16) + panic("rijndael_padEncrypt(CBC)"); + for (i = 0; i < 16 - padLen; i++) { + block[i] = input[i] ^ iv[i]; + } + for (i = 16 - padLen; i < 16; i++) { + block[i] = (BYTE)padLen ^ iv[i]; + } + rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS); + break; + + default: + return BAD_CIPHER_STATE; + } + + return 16*(numBlocks + 1); +} + +int rijndael_blockDecrypt(cipherInstance *cipher, keyInstance *key, + BYTE *input, int inputLen, BYTE *outBuffer) { + int i, k, numBlocks; + word8 block[16], iv[4][4]; + + if (cipher == NULL || + key == NULL || + (cipher->mode != MODE_CFB1 && key->direction == DIR_ENCRYPT)) { + return BAD_CIPHER_STATE; + } + if (input == NULL || inputLen <= 0) { + return 0; /* nothing to do */ + } + + numBlocks = inputLen/128; + + switch (cipher->mode) { + case MODE_ECB: + for (i = numBlocks; i > 0; i--) { + rijndaelDecrypt(input, outBuffer, key->keySched, key->ROUNDS); + input += 16; + outBuffer += 16; + } + break; + + case MODE_CBC: +#if 1 /*STRICT_ALIGN */ + bcopy(cipher->IV, iv, 16); +#else + *((word32*)iv[0]) = *((word32*)(cipher->IV )); + *((word32*)iv[1]) = *((word32*)(cipher->IV+ 4)); + *((word32*)iv[2]) = *((word32*)(cipher->IV+ 8)); + *((word32*)iv[3]) = *((word32*)(cipher->IV+12)); +#endif + for (i = numBlocks; i > 0; i--) { + rijndaelDecrypt(input, block, key->keySched, key->ROUNDS); + ((word32*)block)[0] ^= *((word32*)iv[0]); + ((word32*)block)[1] ^= *((word32*)iv[1]); + ((word32*)block)[2] ^= *((word32*)iv[2]); + ((word32*)block)[3] ^= *((word32*)iv[3]); +#if 1 /*STRICT_ALIGN*/ + bcopy(input, iv, 16); + bcopy(block, outBuffer, 16); +#else + *((word32*)iv[0]) = ((word32*)input)[0]; ((word32*)outBuffer)[0] = ((word32*)block)[0]; + *((word32*)iv[1]) = ((word32*)input)[1]; ((word32*)outBuffer)[1] = ((word32*)block)[1]; + *((word32*)iv[2]) = ((word32*)input)[2]; ((word32*)outBuffer)[2] = ((word32*)block)[2]; + *((word32*)iv[3]) = ((word32*)input)[3]; ((word32*)outBuffer)[3] = ((word32*)block)[3]; +#endif + input += 16; + outBuffer += 16; + } + break; + + case MODE_CFB1: +#if 1 /*STRICT_ALIGN */ + bcopy(cipher->IV, iv, 16); +#else + *((word32*)iv[0]) = *((word32*)(cipher->IV)); + *((word32*)iv[1]) = *((word32*)(cipher->IV+ 4)); + *((word32*)iv[2]) = *((word32*)(cipher->IV+ 8)); + *((word32*)iv[3]) = *((word32*)(cipher->IV+12)); +#endif + for (i = numBlocks; i > 0; i--) { + for (k = 0; k < 128; k++) { + *((word32*) block ) = *((word32*)iv[0]); + *((word32*)(block+ 4)) = *((word32*)iv[1]); + *((word32*)(block+ 8)) = *((word32*)iv[2]); + *((word32*)(block+12)) = *((word32*)iv[3]); + rijndaelEncrypt(block, block, key->keySched, key->ROUNDS); + iv[0][0] = (iv[0][0] << 1) | (iv[0][1] >> 7); + iv[0][1] = (iv[0][1] << 1) | (iv[0][2] >> 7); + iv[0][2] = (iv[0][2] << 1) | (iv[0][3] >> 7); + iv[0][3] = (iv[0][3] << 1) | (iv[1][0] >> 7); + iv[1][0] = (iv[1][0] << 1) | (iv[1][1] >> 7); + iv[1][1] = (iv[1][1] << 1) | (iv[1][2] >> 7); + iv[1][2] = (iv[1][2] << 1) | (iv[1][3] >> 7); + iv[1][3] = (iv[1][3] << 1) | (iv[2][0] >> 7); + iv[2][0] = (iv[2][0] << 1) | (iv[2][1] >> 7); + iv[2][1] = (iv[2][1] << 1) | (iv[2][2] >> 7); + iv[2][2] = (iv[2][2] << 1) | (iv[2][3] >> 7); + iv[2][3] = (iv[2][3] << 1) | (iv[3][0] >> 7); + iv[3][0] = (iv[3][0] << 1) | (iv[3][1] >> 7); + iv[3][1] = (iv[3][1] << 1) | (iv[3][2] >> 7); + iv[3][2] = (iv[3][2] << 1) | (iv[3][3] >> 7); + iv[3][3] = (iv[3][3] << 1) | ((input[k/8] >> (7-(k&7))) & 1); + outBuffer[k/8] ^= (block[0] & 0x80) >> (k & 7); + } + } + break; + + default: + return BAD_CIPHER_STATE; + } + + return 128*numBlocks; +} + +int rijndael_padDecrypt(cipherInstance *cipher, keyInstance *key, + BYTE *input, int inputOctets, BYTE *outBuffer) { + int i, numBlocks, padLen; + word8 block[16]; + word32 iv[4]; + + if (cipher == NULL || + key == NULL || + key->direction == DIR_ENCRYPT) { + return BAD_CIPHER_STATE; + } + if (input == NULL || inputOctets <= 0) { + return 0; /* nothing to do */ + } + if (inputOctets % 16 != 0) { + return BAD_DATA; + } + + numBlocks = inputOctets/16; + + switch (cipher->mode) { + case MODE_ECB: + /* all blocks but last */ + for (i = numBlocks - 1; i > 0; i--) { + rijndaelDecrypt(input, outBuffer, key->keySched, key->ROUNDS); + input += 16; + outBuffer += 16; + } + /* last block */ + rijndaelDecrypt(input, block, key->keySched, key->ROUNDS); + padLen = block[15]; + if (padLen >= 16) { + return BAD_DATA; + } + for (i = 16 - padLen; i < 16; i++) { + if (block[i] != padLen) { + return BAD_DATA; + } + } + bcopy(block, outBuffer, 16 - padLen); + break; + + case MODE_CBC: + bcopy(cipher->IV, iv, 16); + /* all blocks but last */ + for (i = numBlocks - 1; i > 0; i--) { + rijndaelDecrypt(input, block, key->keySched, key->ROUNDS); + ((word32*)block)[0] ^= iv[0]; + ((word32*)block)[1] ^= iv[1]; + ((word32*)block)[2] ^= iv[2]; + ((word32*)block)[3] ^= iv[3]; + bcopy(input, iv, 16); + bcopy(block, outBuffer, 16); + input += 16; + outBuffer += 16; + } + /* last block */ + rijndaelDecrypt(input, block, key->keySched, key->ROUNDS); + ((word32*)block)[0] ^= iv[0]; + ((word32*)block)[1] ^= iv[1]; + ((word32*)block)[2] ^= iv[2]; + ((word32*)block)[3] ^= iv[3]; + padLen = block[15]; + if (padLen <= 0 || padLen > 16) { + return BAD_DATA; + } + for (i = 16 - padLen; i < 16; i++) { + if (block[i] != padLen) { + return BAD_DATA; + } + } + bcopy(block, outBuffer, 16 - padLen); + break; + + default: + return BAD_CIPHER_STATE; + } + + return 16*numBlocks - padLen; +} + +#ifdef INTERMEDIATE_VALUE_KAT +/** + * cipherUpdateRounds: + * + * Encrypts/Decrypts exactly one full block a specified number of rounds. + * Only used in the Intermediate Value Known Answer Test. + * + * Returns: + * TRUE - on success + * BAD_CIPHER_STATE - cipher in bad state (e.g., not initialized) + */ +int rijndael_cipherUpdateRounds(cipherInstance *cipher, keyInstance *key, + BYTE *input, int inputLen, BYTE *outBuffer, int rounds) { + int j; + word8 block[4][4]; + + if (cipher == NULL || key == NULL) { + return BAD_CIPHER_STATE; + } + + for (j = 3; j >= 0; j--) { + /* parse input stream into rectangular array */ + *((word32*)block[j]) = *((word32*)(input+4*j)); + } + + switch (key->direction) { + case DIR_ENCRYPT: + rijndaelEncryptRound(block, key->keySched, key->ROUNDS, rounds); + break; + + case DIR_DECRYPT: + rijndaelDecryptRound(block, key->keySched, key->ROUNDS, rounds); + break; + + default: + return BAD_KEY_DIR; + } + + for (j = 3; j >= 0; j--) { + /* parse rectangular array into output ciphertext bytes */ + *((word32*)(outBuffer+4*j)) = *((word32*)block[j]); + } + + return TRUE; +} +#endif /* INTERMEDIATE_VALUE_KAT */ diff --git a/bsd/crypto/rijndael/rijndael-api-fst.h b/bsd/crypto/rijndael/rijndael-api-fst.h new file mode 100644 index 000000000..682f2da69 --- /dev/null +++ b/bsd/crypto/rijndael/rijndael-api-fst.h @@ -0,0 +1,104 @@ +/* $FreeBSD: src/sys/crypto/rijndael/rijndael-api-fst.h,v 1.2.2.1 2001/07/03 11:01:36 ume Exp $ */ +/* $KAME: rijndael-api-fst.h,v 1.6 2001/05/27 00:23:23 itojun Exp $ */ + +/* + * rijndael-api-fst.h v2.3 April '2000 + * + * Optimised ANSI C code + * + * #define INTERMEDIATE_VALUE_KAT to generate the Intermediate Value Known Answer Test. + */ + +#ifndef __RIJNDAEL_API_FST_H +#define __RIJNDAEL_API_FST_H + +#include + +/* Defines: + Add any additional defines you need +*/ + +#define DIR_ENCRYPT 0 /* Are we encrpyting? */ +#define DIR_DECRYPT 1 /* Are we decrpyting? */ +#define MODE_ECB 1 /* Are we ciphering in ECB mode? */ +#define MODE_CBC 2 /* Are we ciphering in CBC mode? */ +#define MODE_CFB1 3 /* Are we ciphering in 1-bit CFB mode? */ +#define TRUE 1 +#define FALSE 0 +#define BITSPERBLOCK 128 /* Default number of bits in a cipher block */ + +/* Error Codes - CHANGE POSSIBLE: inclusion of additional error codes */ +#define BAD_KEY_DIR -1 /* Key direction is invalid, e.g., unknown value */ +#define BAD_KEY_MAT -2 /* Key material not of correct length */ +#define BAD_KEY_INSTANCE -3 /* Key passed is not valid */ +#define BAD_CIPHER_MODE -4 /* Params struct passed to cipherInit invalid */ +#define BAD_CIPHER_STATE -5 /* Cipher in wrong state (e.g., not initialized) */ +#define BAD_BLOCK_LENGTH -6 +#define BAD_CIPHER_INSTANCE -7 +#define BAD_DATA -8 /* Data contents are invalid, e.g., invalid padding */ +#define BAD_OTHER -9 /* Unknown error */ + +/* CHANGE POSSIBLE: inclusion of algorithm specific defines */ +#define MAX_KEY_SIZE 64 /* # of ASCII char's needed to represent a key */ +#define MAX_IV_SIZE 16 /* # bytes needed to represent an IV */ + +/* Typedefs: + + Typedef'ed data storage elements. Add any algorithm specific +parameters at the bottom of the structs as appropriate. +*/ + +/* The structure for key information */ +typedef struct { + u_int8_t direction; /* Key used for encrypting or decrypting? */ + int keyLen; /* Length of the key */ + char keyMaterial[MAX_KEY_SIZE+1]; /* Raw key data in ASCII, e.g., user input or KAT values */ + /* The following parameters are algorithm dependent, replace or add as necessary */ + int ROUNDS; /* key-length-dependent number of rounds */ + int blockLen; /* block length */ + union { + u_int8_t xkS8[RIJNDAEL_MAXROUNDS+1][4][4]; /* key schedule */ + u_int32_t xkS32[RIJNDAEL_MAXROUNDS+1][4]; /* key schedule */ + } xKeySched; +#define keySched xKeySched.xkS8 +} keyInstance; + +/* The structure for cipher information */ +typedef struct { /* changed order of the components */ + u_int8_t mode; /* MODE_ECB, MODE_CBC, or MODE_CFB1 */ + u_int8_t IV[MAX_IV_SIZE]; /* A possible Initialization Vector for ciphering */ + /* Add any algorithm specific parameters needed here */ + int blockLen; /* Sample: Handles non-128 bit block sizes (if available) */ +} cipherInstance; + +/* Function prototypes */ +/* CHANGED: nothing + TODO: implement the following extensions to setup 192-bit and 256-bit block lengths: + makeKeyEx(): parameter blockLen added + -- this parameter is absolutely necessary if you want to + setup the round keys in a variable block length setting + cipherInitEx(): parameter blockLen added (for obvious reasons) + */ + +int rijndael_makeKey(keyInstance *key, u_int8_t direction, int keyLen, char *keyMaterial); + +int rijndael_cipherInit(cipherInstance *cipher, u_int8_t mode, char *IV); + +int rijndael_blockEncrypt(cipherInstance *cipher, keyInstance *key, + u_int8_t *input, int inputLen, u_int8_t *outBuffer); + +int rijndael_padEncrypt(cipherInstance *cipher, keyInstance *key, + u_int8_t *input, int inputOctets, u_int8_t *outBuffer); + +int rijndael_blockDecrypt(cipherInstance *cipher, keyInstance *key, + u_int8_t *input, int inputLen, u_int8_t *outBuffer); + +int rijndael_padDecrypt(cipherInstance *cipher, keyInstance *key, + u_int8_t *input, int inputOctets, u_int8_t *outBuffer); + +#ifdef INTERMEDIATE_VALUE_KAT +int rijndael_cipherUpdateRounds(cipherInstance *cipher, keyInstance *key, + u_int8_t *input, int inputLen, u_int8_t *outBuffer, int Rounds); +#endif /* INTERMEDIATE_VALUE_KAT */ + +#endif /* __RIJNDAEL_API_FST_H */ diff --git a/bsd/crypto/rijndael/rijndael.h b/bsd/crypto/rijndael/rijndael.h new file mode 100644 index 000000000..8dafa3b71 --- /dev/null +++ b/bsd/crypto/rijndael/rijndael.h @@ -0,0 +1,4 @@ +/* $KAME: rijndael.h,v 1.2 2000/10/02 17:14:27 itojun Exp $ */ +/* $FreeBSD: src/sys/crypto/rijndael/rijndael.h,v 1.1.1.1.2.1 2001/07/03 11:01:36 ume Exp $ */ + +#include diff --git a/bsd/crypto/rijndael/rijndael_local.h b/bsd/crypto/rijndael/rijndael_local.h new file mode 100644 index 000000000..81e79604a --- /dev/null +++ b/bsd/crypto/rijndael/rijndael_local.h @@ -0,0 +1,11 @@ +/* $KAME: rijndael_local.h,v 1.3 2000/10/02 17:14:27 itojun Exp $ */ +/* $FreeBSD: src/sys/crypto/rijndael/rijndael_local.h,v 1.3.2.1 2001/07/03 11:01:36 ume Exp $ */ + +/* the file should not be used from outside */ +typedef u_int8_t BYTE; +typedef u_int8_t word8; +typedef u_int16_t word16; +typedef u_int32_t word32; + +#define MAXKC RIJNDAEL_MAXKC +#define MAXROUNDS RIJNDAEL_MAXROUNDS diff --git a/bsd/crypto/sha1.c b/bsd/crypto/sha1.c index fd74b3c8a..c5c7b27cd 100644 --- a/bsd/crypto/sha1.c +++ b/bsd/crypto/sha1.c @@ -1,3 +1,6 @@ +/* $FreeBSD: src/sys/crypto/sha1.c,v 1.2.2.4 2001/07/03 11:01:27 ume Exp $ */ +/* $KAME: sha1.c,v 1.5 2000/11/08 06:13:08 itojun Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. @@ -216,18 +219,16 @@ sha1_pad(ctxt) } void -sha1_loop(ctxt, input0, len) +sha1_loop(ctxt, input, len) struct sha1_ctxt *ctxt; - const caddr_t input0; + const u_int8_t *input; size_t len; { - const u_int8_t *input; size_t gaplen; size_t gapstart; size_t off; size_t copysiz; - input = (const u_int8_t *)input0; off = 0; while (off < len) { diff --git a/bsd/crypto/sha1.h b/bsd/crypto/sha1.h index 430792443..a3ee2d834 100644 --- a/bsd/crypto/sha1.h +++ b/bsd/crypto/sha1.h @@ -1,3 +1,6 @@ +/* $FreeBSD: src/sys/crypto/sha1.h,v 1.3.2.3 2000/10/12 18:59:31 archie Exp $ */ +/* $KAME: sha1.h,v 1.5 2000/03/27 04:36:23 sumikawa Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. @@ -51,10 +54,10 @@ struct sha1_ctxt { u_int8_t count; }; -#if defined(KERNEL) || defined(_KERNEL) +#ifdef KERNEL extern void sha1_init __P((struct sha1_ctxt *)); extern void sha1_pad __P((struct sha1_ctxt *)); -extern void sha1_loop __P((struct sha1_ctxt *, const caddr_t, size_t)); +extern void sha1_loop __P((struct sha1_ctxt *, const u_int8_t *, size_t)); extern void sha1_result __P((struct sha1_ctxt *, caddr_t)); /* compatibilty with other SHA1 source codes */ @@ -62,7 +65,7 @@ typedef struct sha1_ctxt SHA1_CTX; #define SHA1Init(x) sha1_init((x)) #define SHA1Update(x, y, z) sha1_loop((x), (y), (z)) #define SHA1Final(x, y) sha1_result((y), (x)) -#endif +#endif /* KERNEL */ #define SHA1_RESULTLEN (160/8) diff --git a/bsd/crypto/sha2/Makefile b/bsd/crypto/sha2/Makefile new file mode 100644 index 000000000..95aff4dee --- /dev/null +++ b/bsd/crypto/sha2/Makefile @@ -0,0 +1,32 @@ +export MakeInc_cmd=${SRCROOT}/makedefs/MakeInc.cmd +export MakeInc_def=${SRCROOT}/makedefs/MakeInc.def +export MakeInc_rule=${SRCROOT}/makedefs/MakeInc.rule +export MakeInc_dir=${SRCROOT}/makedefs/MakeInc.dir + + +include $(MakeInc_cmd) +include $(MakeInc_def) + +INSTINC_SUBDIRS = \ + +INSTINC_SUBDIRS_PPC = \ + +INSTINC_SUBDIRS_I386 = \ + +EXPINC_SUBDIRS = \ + +EXPINC_SUBDIRS_PPC = \ + +EXPINC_SUBDIRS_I386 = \ + +PRIVATE_DATAFILES = \ + sha2.h + +INSTALL_MI_DIR = crypto + +EXPORT_MI_DIR = ${INSTALL_MI_DIR} + +INSTALL_MI_LCL_KERN_LIST = ${PRIVATE_DATAFILES} + +include $(MakeInc_rule) +include $(MakeInc_dir) diff --git a/bsd/crypto/sha2/sha2.c b/bsd/crypto/sha2/sha2.c new file mode 100644 index 000000000..9ea6f468b --- /dev/null +++ b/bsd/crypto/sha2/sha2.c @@ -0,0 +1,1047 @@ +/* $FreeBSD: src/sys/crypto/sha2/sha2.c,v 1.2.2.1 2001/07/03 11:01:36 ume Exp $ */ +/* $KAME: sha2.c,v 1.6 2001/03/12 11:31:04 itojun Exp $ */ + +/* + * sha2.c + * + * Version 1.0.0beta1 + * + * Written by Aaron D. Gifford + * + * Copyright 2000 Aaron D. Gifford. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTOR(S) ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + + +#include +#include +#include +#include +#include + +/* + * ASSERT NOTE: + * Some sanity checking code is included using assert(). On my FreeBSD + * system, this additional code can be removed by compiling with NDEBUG + * defined. Check your own systems manpage on assert() to see how to + * compile WITHOUT the sanity checking code on your system. + * + * UNROLLED TRANSFORM LOOP NOTE: + * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform + * loop version for the hash transform rounds (defined using macros + * later in this file). Either define on the command line, for example: + * + * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c + * + * or define below: + * + * #define SHA2_UNROLL_TRANSFORM + * + */ + +#ifndef assert(x) +#define assert(x) +#endif + +/*** SHA-256/384/512 Machine Architecture Definitions *****************/ +/* + * BYTE_ORDER NOTE: + * + * Please make sure that your system defines BYTE_ORDER. If your + * architecture is little-endian, make sure it also defines + * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are + * equivilent. + * + * If your system does not define the above, then you can do so by + * hand like this: + * + * #define LITTLE_ENDIAN 1234 + * #define BIG_ENDIAN 4321 + * + * And for little-endian machines, add: + * + * #define BYTE_ORDER LITTLE_ENDIAN + * + * Or for big-endian machines: + * + * #define BYTE_ORDER BIG_ENDIAN + * + * The FreeBSD machine this was written on defines BYTE_ORDER + * appropriately by including (which in turn includes + * where the appropriate definitions are actually + * made). + */ +#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN) +#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN +#endif + +/* + * Define the followingsha2_* types to types of the correct length on + * the native archtecture. Most BSD systems and Linux define u_intXX_t + * types. Machines with very recent ANSI C headers, can use the + * uintXX_t definintions from inttypes.h by defining SHA2_USE_INTTYPES_H + * during compile or in the sha.h header file. + * + * Machines that support neither u_intXX_t nor inttypes.h's uintXX_t + * will need to define these three typedefs below (and the appropriate + * ones in sha.h too) by hand according to their system architecture. + * + * Thank you, Jun-ichiro itojun Hagino, for suggesting using u_intXX_t + * types and pointing out recent ANSI C support for uintXX_t in inttypes.h. + */ +#if 0 /*def SHA2_USE_INTTYPES_H*/ + +typedef uint8_t sha2_byte; /* Exactly 1 byte */ +typedef uint32_t sha2_word32; /* Exactly 4 bytes */ +typedef uint64_t sha2_word64; /* Exactly 8 bytes */ + +#else /* SHA2_USE_INTTYPES_H */ + +typedef u_int8_t sha2_byte; /* Exactly 1 byte */ +typedef u_int32_t sha2_word32; /* Exactly 4 bytes */ +typedef u_int64_t sha2_word64; /* Exactly 8 bytes */ + +#endif /* SHA2_USE_INTTYPES_H */ + + +/*** SHA-256/384/512 Various Length Definitions ***********************/ +/* NOTE: Most of these are in sha2.h */ +#define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8) +#define SHA384_SHORT_BLOCK_LENGTH (SHA384_BLOCK_LENGTH - 16) +#define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16) + + +/*** ENDIAN REVERSAL MACROS *******************************************/ +#if BYTE_ORDER == LITTLE_ENDIAN +#define REVERSE32(w,x) { \ + sha2_word32 tmp = (w); \ + tmp = (tmp >> 16) | (tmp << 16); \ + (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ +} +#define REVERSE64(w,x) { \ + sha2_word64 tmp = (w); \ + tmp = (tmp >> 32) | (tmp << 32); \ + tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \ + ((tmp & 0x00ff00ff00ff00ffULL) << 8); \ + (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \ + ((tmp & 0x0000ffff0000ffffULL) << 16); \ +} +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +/* + * Macro for incrementally adding the unsigned 64-bit integer n to the + * unsigned 128-bit integer (represented using a two-element array of + * 64-bit words): + */ +#define ADDINC128(w,n) { \ + (w)[0] += (sha2_word64)(n); \ + if ((w)[0] < (n)) { \ + (w)[1]++; \ + } \ +} + +/*** THE SIX LOGICAL FUNCTIONS ****************************************/ +/* + * Bit shifting and rotation (used by the six SHA-XYZ logical functions: + * + * NOTE: The naming of R and S appears backwards here (R is a SHIFT and + * S is a ROTATION) because the SHA-256/384/512 description document + * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this + * same "backwards" definition. + */ +/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */ +#define R(b,x) ((x) >> (b)) +/* 32-bit Rotate-right (used in SHA-256): */ +#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) +/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ +#define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) + +/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */ +#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) +#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + +/* Four of six logical functions used in SHA-256: */ +#define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x))) +#define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x))) +#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x))) +#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x))) + +/* Four of six logical functions used in SHA-384 and SHA-512: */ +#define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x))) +#define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x))) +#define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x))) +#define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x))) + +/*** INTERNAL FUNCTION PROTOTYPES *************************************/ +/* NOTE: These should not be accessed directly from outside this + * library -- they are intended for private internal visibility/use + * only. + */ +void SHA512_Last(SHA512_CTX*); +void SHA256_Transform(SHA256_CTX*, const sha2_word32*); +void SHA512_Transform(SHA512_CTX*, const sha2_word64*); + + +/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ +/* Hash constant words K for SHA-256: */ +const static sha2_word32 K256[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, + 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, + 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, + 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, + 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, + 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, + 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL +}; + +/* Initial hash value H for SHA-256: */ +const static sha2_word32 sha256_initial_hash_value[8] = { + 0x6a09e667UL, + 0xbb67ae85UL, + 0x3c6ef372UL, + 0xa54ff53aUL, + 0x510e527fUL, + 0x9b05688cUL, + 0x1f83d9abUL, + 0x5be0cd19UL +}; + +/* Hash constant words K for SHA-384 and SHA-512: */ +const static sha2_word64 K512[80] = { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, + 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, + 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, + 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, + 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, + 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, + 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, + 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, + 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, + 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, + 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, + 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, + 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, + 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, + 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, + 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, + 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, + 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, + 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, + 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, + 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, + 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, + 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, + 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, + 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL +}; + +/* Initial hash value H for SHA-384 */ +const static sha2_word64 sha384_initial_hash_value[8] = { + 0xcbbb9d5dc1059ed8ULL, + 0x629a292a367cd507ULL, + 0x9159015a3070dd17ULL, + 0x152fecd8f70e5939ULL, + 0x67332667ffc00b31ULL, + 0x8eb44a8768581511ULL, + 0xdb0c2e0d64f98fa7ULL, + 0x47b5481dbefa4fa4ULL +}; + +/* Initial hash value H for SHA-512 */ +const static sha2_word64 sha512_initial_hash_value[8] = { + 0x6a09e667f3bcc908ULL, + 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, + 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, + 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, + 0x5be0cd19137e2179ULL +}; + +/* + * Constant used by SHA256/384/512_End() functions for converting the + * digest to a readable hexadecimal character string: + */ +static const char *sha2_hex_digits = "0123456789abcdef"; + + +/*** SHA-256: *********************************************************/ +void SHA256_Init(SHA256_CTX* context) { + if (context == (SHA256_CTX*)0) { + return; + } + bcopy(sha256_initial_hash_value, context->state, SHA256_DIGEST_LENGTH); + bzero(context->buffer, SHA256_BLOCK_LENGTH); + context->bitcount = 0; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-256 round macros: */ + +#if BYTE_ORDER == LITTLE_ENDIAN + +#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ + REVERSE32(*data++, W256[j]); \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ + K256[j] + W256[j]; \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + + +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ + K256[j] + (W256[j] = *data++); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND256(a,b,c,d,e,f,g,h) \ + s0 = W256[(j+1)&0x0f]; \ + s0 = sigma0_256(s0); \ + s1 = W256[(j+14)&0x0f]; \ + s1 = sigma1_256(s1); \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \ + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + +void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { + sha2_word32 a, b, c, d, e, f, g, h, s0, s1; + sha2_word32 T1, *W256; + int j; + + W256 = (sha2_word32*)context->buffer; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { + /* Rounds 0 to 15 (unrolled): */ + ROUND256_0_TO_15(a,b,c,d,e,f,g,h); + ROUND256_0_TO_15(h,a,b,c,d,e,f,g); + ROUND256_0_TO_15(g,h,a,b,c,d,e,f); + ROUND256_0_TO_15(f,g,h,a,b,c,d,e); + ROUND256_0_TO_15(e,f,g,h,a,b,c,d); + ROUND256_0_TO_15(d,e,f,g,h,a,b,c); + ROUND256_0_TO_15(c,d,e,f,g,h,a,b); + ROUND256_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds to 64: */ + do { + ROUND256(a,b,c,d,e,f,g,h); + ROUND256(h,a,b,c,d,e,f,g); + ROUND256(g,h,a,b,c,d,e,f); + ROUND256(f,g,h,a,b,c,d,e); + ROUND256(e,f,g,h,a,b,c,d); + ROUND256(d,e,f,g,h,a,b,c); + ROUND256(c,d,e,f,g,h,a,b); + ROUND256(b,c,d,e,f,g,h,a); + } while (j < 64); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { + sha2_word32 a, b, c, d, e, f, g, h, s0, s1; + sha2_word32 T1, T2, *W256; + int j; + + W256 = (sha2_word32*)context->buffer; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { +#if BYTE_ORDER == LITTLE_ENDIAN + /* Copy data while converting to host byte order */ + REVERSE32(*data++,W256[j]); + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j]; +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + /* Apply the SHA-256 compression function to update a..h with copy */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++); +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W256[(j+1)&0x0f]; + s0 = sigma0_256(s0); + s1 = W256[(j+14)&0x0f]; + s1 = sigma1_256(s1); + + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 64); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void SHA256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { + unsigned int freespace, usedspace; + + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + assert(context != (SHA256_CTX*)0 && data != (sha2_byte*)0); + + usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA256_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + bcopy(data, &context->buffer[usedspace], freespace); + context->bitcount += freespace << 3; + len -= freespace; + data += freespace; + SHA256_Transform(context, (sha2_word32*)context->buffer); + } else { + /* The buffer is not yet full */ + bcopy(data, &context->buffer[usedspace], len); + context->bitcount += len << 3; + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= SHA256_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + SHA256_Transform(context, (const sha2_word32*)data); + context->bitcount += SHA256_BLOCK_LENGTH << 3; + len -= SHA256_BLOCK_LENGTH; + data += SHA256_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + bcopy(data, context->buffer, len); + context->bitcount += len << 3; + } + /* Clean up: */ + usedspace = freespace = 0; +} + +void SHA256_Final(sha2_byte digest[], SHA256_CTX* context) { + sha2_word32 *d = (sha2_word32*)digest; + unsigned int usedspace; + + /* Sanity check: */ + assert(context != (SHA256_CTX*)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + REVERSE64(context->bitcount,context->bitcount); +#endif + if (usedspace > 0) { + /* Begin padding with a 1 bit: */ + context->buffer[usedspace++] = 0x80; + + if (usedspace < SHA256_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + bzero(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace); + } else { + if (usedspace < SHA256_BLOCK_LENGTH) { + bzero(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace); + } + /* Do second-to-last transform: */ + SHA256_Transform(context, (sha2_word32*)context->buffer); + + /* And set-up for the last transform: */ + bzero(context->buffer, SHA256_SHORT_BLOCK_LENGTH); + } + } else { + /* Set-up for the last transform: */ + bzero(context->buffer, SHA256_SHORT_BLOCK_LENGTH); + + /* Begin padding with a 1 bit: */ + *context->buffer = 0x80; + } + /* Set the bit count: */ + *(sha2_word64*)&context->buffer[SHA256_SHORT_BLOCK_LENGTH] = context->bitcount; + + /* Final transform: */ + SHA256_Transform(context, (sha2_word32*)context->buffer); + +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 8; j++) { + REVERSE32(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + bcopy(context->state, d, SHA256_DIGEST_LENGTH); +#endif + } + + /* Clean up state data: */ + bzero(context, sizeof(context)); + usedspace = 0; +} + +char *SHA256_End(SHA256_CTX* context, char buffer[]) { + sha2_byte digest[SHA256_DIGEST_LENGTH], *d = digest; + int i; + + /* Sanity check: */ + assert(context != (SHA256_CTX*)0); + + if (buffer != (char*)0) { + SHA256_Final(digest, context); + + for (i = 0; i < SHA256_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + bzero(context, sizeof(context)); + } + bzero(digest, SHA256_DIGEST_LENGTH); + return buffer; +} + +char* SHA256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) { + SHA256_CTX context; + + SHA256_Init(&context); + SHA256_Update(&context, data, len); + return SHA256_End(&context, digest); +} + + +/*** SHA-512: *********************************************************/ +void SHA512_Init(SHA512_CTX* context) { + if (context == (SHA512_CTX*)0) { + return; + } + bcopy(sha512_initial_hash_value, context->state, SHA512_DIGEST_LENGTH); + bzero(context->buffer, SHA512_BLOCK_LENGTH); + context->bitcount[0] = context->bitcount[1] = 0; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-512 round macros: */ +#if BYTE_ORDER == LITTLE_ENDIAN + +#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ + REVERSE64(*data++, W512[j]); \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ + K512[j] + W512[j]; \ + (d) += T1, \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \ + j++ + + +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ + K512[j] + (W512[j] = *data++); \ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + j++ + +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND512(a,b,c,d,e,f,g,h) \ + s0 = W512[(j+1)&0x0f]; \ + s0 = sigma0_512(s0); \ + s1 = W512[(j+14)&0x0f]; \ + s1 = sigma1_512(s1); \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \ + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + j++ + +void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { + sha2_word64 a, b, c, d, e, f, g, h, s0, s1; + sha2_word64 T1, *W512 = (sha2_word64*)context->buffer; + int j; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { + ROUND512_0_TO_15(a,b,c,d,e,f,g,h); + ROUND512_0_TO_15(h,a,b,c,d,e,f,g); + ROUND512_0_TO_15(g,h,a,b,c,d,e,f); + ROUND512_0_TO_15(f,g,h,a,b,c,d,e); + ROUND512_0_TO_15(e,f,g,h,a,b,c,d); + ROUND512_0_TO_15(d,e,f,g,h,a,b,c); + ROUND512_0_TO_15(c,d,e,f,g,h,a,b); + ROUND512_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds up to 79: */ + do { + ROUND512(a,b,c,d,e,f,g,h); + ROUND512(h,a,b,c,d,e,f,g); + ROUND512(g,h,a,b,c,d,e,f); + ROUND512(f,g,h,a,b,c,d,e); + ROUND512(e,f,g,h,a,b,c,d); + ROUND512(d,e,f,g,h,a,b,c); + ROUND512(c,d,e,f,g,h,a,b); + ROUND512(b,c,d,e,f,g,h,a); + } while (j < 80); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { + sha2_word64 a, b, c, d, e, f, g, h, s0, s1; + sha2_word64 T1, T2, *W512 = (sha2_word64*)context->buffer; + int j; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + REVERSE64(*data++, W512[j]); + /* Apply the SHA-512 compression function to update a..h */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j]; +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + /* Apply the SHA-512 compression function to update a..h with copy */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++); +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W512[(j+1)&0x0f]; + s0 = sigma0_512(s0); + s1 = W512[(j+14)&0x0f]; + s1 = sigma1_512(s1); + + /* Apply the SHA-512 compression function to update a..h */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 80); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void SHA512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { + unsigned int freespace, usedspace; + + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + assert(context != (SHA512_CTX*)0 && data != (sha2_byte*)0); + + usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA512_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + bcopy(data, &context->buffer[usedspace], freespace); + ADDINC128(context->bitcount, freespace << 3); + len -= freespace; + data += freespace; + SHA512_Transform(context, (sha2_word64*)context->buffer); + } else { + /* The buffer is not yet full */ + bcopy(data, &context->buffer[usedspace], len); + ADDINC128(context->bitcount, len << 3); + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= SHA512_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + SHA512_Transform(context, (const sha2_word64*)data); + ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); + len -= SHA512_BLOCK_LENGTH; + data += SHA512_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + bcopy(data, context->buffer, len); + ADDINC128(context->bitcount, len << 3); + } + /* Clean up: */ + usedspace = freespace = 0; +} + +void SHA512_Last(SHA512_CTX* context) { + unsigned int usedspace; + + usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + REVERSE64(context->bitcount[0],context->bitcount[0]); + REVERSE64(context->bitcount[1],context->bitcount[1]); +#endif + if (usedspace > 0) { + /* Begin padding with a 1 bit: */ + context->buffer[usedspace++] = 0x80; + + if (usedspace < SHA512_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + bzero(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace); + } else { + if (usedspace < SHA512_BLOCK_LENGTH) { + bzero(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace); + } + /* Do second-to-last transform: */ + SHA512_Transform(context, (sha2_word64*)context->buffer); + + /* And set-up for the last transform: */ + bzero(context->buffer, SHA512_BLOCK_LENGTH - 2); + } + } else { + /* Prepare for final transform: */ + bzero(context->buffer, SHA512_SHORT_BLOCK_LENGTH); + + /* Begin padding with a 1 bit: */ + *context->buffer = 0x80; + } + /* Store the length of input data (in bits): */ + *(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1]; + *(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0]; + + /* Final transform: */ + SHA512_Transform(context, (sha2_word64*)context->buffer); +} + +void SHA512_Final(sha2_byte digest[], SHA512_CTX* context) { + sha2_word64 *d = (sha2_word64*)digest; + + /* Sanity check: */ + assert(context != (SHA512_CTX*)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + SHA512_Last(context); + + /* Save the hash data for output: */ +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 8; j++) { + REVERSE64(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + bcopy(context->state, d, SHA512_DIGEST_LENGTH); +#endif + } + + /* Zero out state data */ + bzero(context, sizeof(context)); +} + +char *SHA512_End(SHA512_CTX* context, char buffer[]) { + sha2_byte digest[SHA512_DIGEST_LENGTH], *d = digest; + int i; + + /* Sanity check: */ + assert(context != (SHA512_CTX*)0); + + if (buffer != (char*)0) { + SHA512_Final(digest, context); + + for (i = 0; i < SHA512_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + bzero(context, sizeof(context)); + } + bzero(digest, SHA512_DIGEST_LENGTH); + return buffer; +} + +char* SHA512_Data(const sha2_byte* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) { + SHA512_CTX context; + + SHA512_Init(&context); + SHA512_Update(&context, data, len); + return SHA512_End(&context, digest); +} + + +/*** SHA-384: *********************************************************/ +void SHA384_Init(SHA384_CTX* context) { + if (context == (SHA384_CTX*)0) { + return; + } + bcopy(sha384_initial_hash_value, context->state, SHA512_DIGEST_LENGTH); + bzero(context->buffer, SHA384_BLOCK_LENGTH); + context->bitcount[0] = context->bitcount[1] = 0; +} + +void SHA384_Update(SHA384_CTX* context, const sha2_byte* data, size_t len) { + SHA512_Update((SHA512_CTX*)context, data, len); +} + +void SHA384_Final(sha2_byte digest[], SHA384_CTX* context) { + sha2_word64 *d = (sha2_word64*)digest; + + /* Sanity check: */ + assert(context != (SHA384_CTX*)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + SHA512_Last((SHA512_CTX*)context); + + /* Save the hash data for output: */ +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 6; j++) { + REVERSE64(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + bcopy(context->state, d, SHA384_DIGEST_LENGTH); +#endif + } + + /* Zero out state data */ + bzero(context, sizeof(context)); +} + +char *SHA384_End(SHA384_CTX* context, char buffer[]) { + sha2_byte digest[SHA384_DIGEST_LENGTH], *d = digest; + int i; + + /* Sanity check: */ + assert(context != (SHA384_CTX*)0); + + if (buffer != (char*)0) { + SHA384_Final(digest, context); + + for (i = 0; i < SHA384_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + bzero(context, sizeof(context)); + } + bzero(digest, SHA384_DIGEST_LENGTH); + return buffer; +} + +char* SHA384_Data(const sha2_byte* data, size_t len, char digest[SHA384_DIGEST_STRING_LENGTH]) { + SHA384_CTX context; + + SHA384_Init(&context); + SHA384_Update(&context, data, len); + return SHA384_End(&context, digest); +} + diff --git a/bsd/crypto/sha2/sha2.h b/bsd/crypto/sha2/sha2.h new file mode 100644 index 000000000..1f063d26e --- /dev/null +++ b/bsd/crypto/sha2/sha2.h @@ -0,0 +1,141 @@ +/* $FreeBSD: src/sys/crypto/sha2/sha2.h,v 1.1.2.1 2001/07/03 11:01:36 ume Exp $ */ +/* $KAME: sha2.h,v 1.3 2001/03/12 08:27:48 itojun Exp $ */ + +/* + * sha2.h + * + * Version 1.0.0beta1 + * + * Written by Aaron D. Gifford + * + * Copyright 2000 Aaron D. Gifford. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTOR(S) ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef __SHA2_H__ +#define __SHA2_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + +/*** SHA-256/384/512 Various Length Definitions ***********************/ +#define SHA256_BLOCK_LENGTH 64 +#define SHA256_DIGEST_LENGTH 32 +#define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) +#define SHA384_BLOCK_LENGTH 128 +#define SHA384_DIGEST_LENGTH 48 +#define SHA384_DIGEST_STRING_LENGTH (SHA384_DIGEST_LENGTH * 2 + 1) +#define SHA512_BLOCK_LENGTH 128 +#define SHA512_DIGEST_LENGTH 64 +#define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) + + +/*** SHA-256/384/512 Context Structures *******************************/ +/* NOTE: If your architecture does not define either u_intXX_t types or + * uintXX_t (from inttypes.h), you may need to define things by hand + * for your system: + */ +#if 0 +typedef unsigned char u_int8_t; /* 1-byte (8-bits) */ +typedef unsigned int u_int32_t; /* 4-bytes (32-bits) */ +typedef unsigned long long u_int64_t; /* 8-bytes (64-bits) */ +#endif +/* + * Most BSD systems already define u_intXX_t types, as does Linux. + * Some systems, however, like Compaq's Tru64 Unix instead can use + * uintXX_t types defined by very recent ANSI C standards and included + * in the file: + * + * #include + * + * If you choose to use then please define: + * + * #define SHA2_USE_INTTYPES_H + * + * Or on the command line during compile: + * + * cc -DSHA2_USE_INTTYPES_H ... + */ +#if 0 /*def SHA2_USE_INTTYPES_H*/ + +typedef struct _SHA256_CTX { + uint32_t state[8]; + uint64_t bitcount; + uint8_t buffer[SHA256_BLOCK_LENGTH]; +} SHA256_CTX; +typedef struct _SHA512_CTX { + uint64_t state[8]; + uint64_t bitcount[2]; + uint8_t buffer[SHA512_BLOCK_LENGTH]; +} SHA512_CTX; + +#else /* SHA2_USE_INTTYPES_H */ + +typedef struct _SHA256_CTX { + u_int32_t state[8]; + u_int64_t bitcount; + u_int8_t buffer[SHA256_BLOCK_LENGTH]; +} SHA256_CTX; +typedef struct _SHA512_CTX { + u_int64_t state[8]; + u_int64_t bitcount[2]; + u_int8_t buffer[SHA512_BLOCK_LENGTH]; +} SHA512_CTX; + +#endif /* SHA2_USE_INTTYPES_H */ + +typedef SHA512_CTX SHA384_CTX; + + +/*** SHA-256/384/512 Function Prototypes ******************************/ + +void SHA256_Init __P((SHA256_CTX *)); +void SHA256_Update __P((SHA256_CTX*, const u_int8_t*, size_t)); +void SHA256_Final __P((u_int8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*)); +char* SHA256_End __P((SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH])); +char* SHA256_Data __P((const u_int8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH])); + +void SHA384_Init __P((SHA384_CTX*)); +void SHA384_Update __P((SHA384_CTX*, const u_int8_t*, size_t)); +void SHA384_Final __P((u_int8_t[SHA384_DIGEST_LENGTH], SHA384_CTX*)); +char* SHA384_End __P((SHA384_CTX*, char[SHA384_DIGEST_STRING_LENGTH])); +char* SHA384_Data __P((const u_int8_t*, size_t, char[SHA384_DIGEST_STRING_LENGTH])); + +void SHA512_Init __P((SHA512_CTX*)); +void SHA512_Update __P((SHA512_CTX*, const u_int8_t*, size_t)); +void SHA512_Final __P((u_int8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*)); +char* SHA512_End __P((SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH])); +char* SHA512_Data __P((const u_int8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH])); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __SHA2_H__ */ + diff --git a/bsd/dev/Makefile b/bsd/dev/Makefile index 8a11503da..8e8cf9321 100644 --- a/bsd/dev/Makefile +++ b/bsd/dev/Makefile @@ -8,7 +8,6 @@ include $(MakeInc_cmd) include $(MakeInc_def) INSTINC_SUBDIRS = \ - random INSTINC_SUBDIRS_PPC = \ diff --git a/bsd/dev/disk.h b/bsd/dev/disk.h index 6431ff276..f174e4ef1 100644 --- a/bsd/dev/disk.h +++ b/bsd/dev/disk.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,44 +21,12 @@ */ /* @(#)disk.h 1.0 08/29/87 (c) 1987 NeXT */ -/* - * HISTORY - * 28-Mar-92 Doug Mitchell - * Moved disk_label struct to . - * - * 22-May-91 Gregg Kellogg (gk) at NeXT - * Split out public interface. - * - * 20-Jul-90 Doug Mitchell - * Added DKIOCSFORMAT, DKIOCGFORMAT - * - * 16-Apr-90 Doug Mitchell at NeXT - * Added DKIOCPANELPRT. - * - * 25-Mar-90 John Seamons (jks) at NeXT - * Removed obsolete DKIOCNOTIFY and DKIOCINSERT. - * - * 23-Mar-90 Doug Mitchell - * Added DKIOCEJECT. - * - * 14-Feb-90 Doug Mitchell at NeXT - * Added DKIOCMNOTIFY. - * - * 16-Mar-88 John Seamons (jks) at NeXT - * Cleaned up to support standard disk label definitions. - * - * 24-Feb-88 Mike DeMoney (mike) at NeXT - * Added defines for dl_bootfile and dl_boot0_blkno. - * Reduced NBAD to allow for these entries in disktab. - * - * 29-Aug-87 John Seamons (jks) at NeXT - * Created. - * - */ - #ifndef _BSD_DEV_DISK_ #define _BSD_DEV_DISK_ +#ifndef _SYS_DISK_H_ +#define _SYS_DISK_H_ +#include #include #include #include @@ -66,6 +34,12 @@ #include #include +/* + * USE INSTEAD (NOTE: DKIOCGETBLOCKCOUNT -> DKIOCGETBLOCKCOUNT32) + */ + +#ifdef __APPLE_API_OBSOLETE + #define DR_CMDSIZE 32 #define DR_ERRSIZE 32 @@ -156,7 +130,8 @@ struct drive_location { #define DKIOCGLOCATION _IOR('d',28, struct drive_location) /* arch dependent location descrip */ #define DKIOCSETBLOCKSIZE _IOW('d', 24, int) /* set media's preferred sector size */ #define DKIOCGETBLOCKSIZE DKIOCBLKSIZE /* get media's preferred sector size */ -#define DKIOCGETBLOCKCOUNT DKIOCNUMBLKS /* get media's sector count */ +#define DKIOCGETBLOCKCOUNT32 DKIOCNUMBLKS /* get media's sector count */ +#define DKIOCGETBLOCKCOUNT64 _IOR('d', 25, u_int64_t) /* get media's sector count */ #define DKIOCGETLOCATION DKIOCGLOCATION /* get media's location description */ #define DKIOCISFORMATTED DKIOCGFORMAT /* is media formatted? */ #define DKIOCISWRITABLE _IOR('d', 29, int) /* is media writable? */ @@ -166,4 +141,7 @@ struct drive_location { #define DKIOCGETMAXSEGMENTCOUNTREAD _IOR('d', 66, u_int64_t) /* get device's maximum physical segment count for read buffers */ #define DKIOCGETMAXSEGMENTCOUNTWRITE _IOR('d', 67, u_int64_t) /* get device's maximum physical segment count for write buffers */ +#endif /* __APPLE_API_OBSOLETE */ + +#endif /* _SYS_DISK_H_ */ #endif /* _BSD_DEV_DISK_ */ diff --git a/bsd/dev/disk_label.h b/bsd/dev/disk_label.h index f177d1ffb..460b5bc9f 100644 --- a/bsd/dev/disk_label.h +++ b/bsd/dev/disk_label.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -23,16 +23,16 @@ * * File: bsd/dev/disk_label.h - NeXT disk label definition. * - * HISTORY - * 28-Mar-92 Doug Mitchell at NeXT - * Split out from . */ #ifndef _BSD_DEV_DISK_LABEL_ #define _BSD_DEV_DISK_LABEL_ +#include #include +#ifdef __APPLE_API_OBSOLETE + #define NLABELS 4 /* # of labels on a disk */ #define MAXLBLLEN 24 /* dl_label[] size */ #define NBAD 1670 /* sized to make label ~= 8KB */ @@ -103,5 +103,7 @@ typedef struct disk_label { #define dl_v3_checksum dl_un.DL_v3_checksum #define dl_bad dl_un.DL_bad +#endif /* __APPLE_API_OBSOLETE */ + #endif /* _BSD_DEV_DISK_LABEL_ */ diff --git a/bsd/dev/i386/conf.c b/bsd/dev/i386/conf.c index dfc84d209..f06b30fc6 100644 --- a/bsd/dev/i386/conf.c +++ b/bsd/dev/i386/conf.c @@ -254,17 +254,19 @@ isdisk(dev, type) dev_t dev; int type; { - switch (major(dev)) { - case 1: /* fd: floppy */ - case 6: /* sd: scsi disk */ - case 3: /* ide: */ - if (type == VBLK) - return(1); - break; - case 14: /* sd: scsi disk */ - case 41: /* fd: floppy */ - if (type == VCHR) - return(1); + dev_t maj = major(dev); + + switch (type) { + case VCHR: + maj = chrtoblk(maj); + if (maj == NODEV) { + break; + } + /* FALL THROUGH */ + case VBLK: + if (bdevsw[maj].d_type == D_DISK) { + return (1); + } break; } return(0); @@ -314,6 +316,17 @@ chrtoblk(dev) return(makedev(blkmaj, minor(dev))); } +int +chrtoblk_set(int cdev, int bdev) +{ + if (cdev >= nchrdev) + return (-1); + if (bdev != NODEV && bdev >= nblkdev) + return (-1); + chrtoblktab[cdev] = bdev; + return 0; +} + /* * Returns true if dev is /dev/mem or /dev/kmem. */ diff --git a/bsd/dev/i386/km.c b/bsd/dev/i386/km.c index ac1054724..ff1fa1978 100644 --- a/bsd/dev/i386/km.c +++ b/bsd/dev/i386/km.c @@ -314,7 +314,7 @@ kmtimeout( struct tty *tp) funnel_state = thread_funnel_set(kernel_flock, TRUE); kmoutput(tp); - (void) thread_funnel_set(kernel_flock, FALSE); + (void) thread_funnel_set(kernel_flock, funnel_state); } diff --git a/bsd/dev/i386/unix_signal.c b/bsd/dev/i386/unix_signal.c index 7ddf4acf3..0c06ff2fd 100644 --- a/bsd/dev/i386/unix_signal.c +++ b/bsd/dev/i386/unix_signal.c @@ -78,107 +78,115 @@ sendsig(p, catcher, sig, mask, code) int sig, mask; u_long code; { - struct sigframe { - int retaddr; - int sig; - int code; - struct sigcontext * scp; - } frame, *fp; - struct sigcontext context, *scp; + struct sigframe { + int retaddr; + sig_t catcher; + int sigstyle; + int sig; + int code; + struct sigcontext * scp; + } frame, *fp; + struct sigcontext context, *scp; struct sigacts *ps = p->p_sigacts; - int oonstack; - thread_t thread = current_thread(); - thread_act_t th_act = current_act(); - struct i386_saved_state * saved_state = get_user_regs(th_act); + int oonstack; + thread_t thread = current_thread(); + thread_act_t th_act = current_act(); + struct uthread * ut; + struct i386_saved_state * saved_state = get_user_regs(th_act); + sig_t trampact; + ut = get_bsdthread_info(th_act); oonstack = ps->ps_sigstk.ss_flags & SA_ONSTACK; - if ((ps->ps_flags & SAS_ALTSTACK) && !oonstack && + if ((ps->ps_flags & SAS_ALTSTACK) && !oonstack && (ps->ps_sigonstack & sigmask(sig))) { - scp = ((struct sigcontext *)ps->ps_sigstk.ss_sp) - 1; + scp = ((struct sigcontext *)ps->ps_sigstk.ss_sp) - 1; ps->ps_sigstk.ss_flags |= SA_ONSTACK; - } else - scp = ((struct sigcontext *)saved_state->uesp) - 1; - fp = ((struct sigframe *)scp) - 1; - - /* - * Build the argument list for the signal handler. - */ - - frame.retaddr = 0xffffffff; /* Handler should call sigreturn to get out of it */ - frame.sig = sig; - - if (sig == SIGILL || sig == SIGFPE) { - frame.code = code; - } else - frame.code = 0; - frame.scp = scp; - if (copyout((caddr_t)&frame, (caddr_t)fp, sizeof (frame))) - goto bad; + } else + scp = ((struct sigcontext *)saved_state->uesp) - 1; + fp = ((struct sigframe *)scp) - 1; + + /* + * Build the argument list for the signal handler. + */ + + trampact = ps->ps_trampact[sig]; + /* Handler should call sigreturn to get out of it */ + frame.retaddr = 0xffffffff; + frame.catcher = catcher; + frame.sigstyle = 1; + frame.sig = sig; + + if (sig == SIGILL || sig == SIGFPE) { + frame.code = code; + } else + frame.code = 0; + frame.scp = scp; + if (copyout((caddr_t)&frame, (caddr_t)fp, sizeof (frame))) + goto bad; #if PC_SUPPORT - { + { PCcontext_t context = threadPCContext(thread); if (context && context->running) { - oonstack |= 02; - context->running = FALSE; + oonstack |= 02; + context->running = FALSE; + } } - } #endif - /* - * Build the signal context to be used by sigreturn. - */ - context.sc_onstack = oonstack; - context.sc_mask = mask; - context.sc_eax = saved_state->eax; - context.sc_ebx = saved_state->ebx; - context.sc_ecx = saved_state->ecx; - context.sc_edx = saved_state->edx; - context.sc_edi = saved_state->edi; - context.sc_esi = saved_state->esi; - context.sc_ebp = saved_state->ebp; - context.sc_esp = saved_state->uesp; - context.sc_ss = saved_state->ss; - context.sc_eflags = saved_state->efl; - context.sc_eip = saved_state->eip; - context.sc_cs = saved_state->cs; - if (saved_state->efl & EFL_VM) { - context.sc_ds = saved_state->v86_segs.v86_ds; - context.sc_es = saved_state->v86_segs.v86_es; - context.sc_fs = saved_state->v86_segs.v86_fs; - context.sc_gs = saved_state->v86_segs.v86_gs; - - saved_state->efl &= ~EFL_VM; - } - else { - context.sc_ds = saved_state->ds; - context.sc_es = saved_state->es; - context.sc_fs = saved_state->fs; - context.sc_gs = saved_state->gs; - } - if (copyout((caddr_t)&context, (caddr_t)scp, sizeof (context))) - goto bad; + /* + * Build the signal context to be used by sigreturn. + */ + context.sc_onstack = oonstack; + context.sc_mask = mask; + context.sc_eax = saved_state->eax; + context.sc_ebx = saved_state->ebx; + context.sc_ecx = saved_state->ecx; + context.sc_edx = saved_state->edx; + context.sc_edi = saved_state->edi; + context.sc_esi = saved_state->esi; + context.sc_ebp = saved_state->ebp; + context.sc_esp = saved_state->uesp; + context.sc_ss = saved_state->ss; + context.sc_eflags = saved_state->efl; + context.sc_eip = saved_state->eip; + context.sc_cs = saved_state->cs; + if (saved_state->efl & EFL_VM) { + context.sc_ds = saved_state->v86_segs.v86_ds; + context.sc_es = saved_state->v86_segs.v86_es; + context.sc_fs = saved_state->v86_segs.v86_fs; + context.sc_gs = saved_state->v86_segs.v86_gs; + + saved_state->efl &= ~EFL_VM; + } else { + context.sc_ds = saved_state->ds; + context.sc_es = saved_state->es; + context.sc_fs = saved_state->fs; + context.sc_gs = saved_state->gs; + } + if (copyout((caddr_t)&context, (caddr_t)scp, sizeof (context))) + goto bad; - saved_state->eip = (unsigned int)catcher; - saved_state->cs = UCODE_SEL; + saved_state->eip = (unsigned int)trampact; + saved_state->cs = UCODE_SEL; - saved_state->uesp = (unsigned int)fp; - saved_state->ss = UDATA_SEL; + saved_state->uesp = (unsigned int)fp; + saved_state->ss = UDATA_SEL; - saved_state->ds = UDATA_SEL; - saved_state->es = UDATA_SEL; - saved_state->fs = NULL_SEG; - saved_state->gs = NULL_SEG; - return; + saved_state->ds = UDATA_SEL; + saved_state->es = UDATA_SEL; + saved_state->fs = NULL_SEG; + saved_state->gs = NULL_SEG; + return; bad: SIGACTION(p, SIGILL) = SIG_DFL; sig = sigmask(SIGILL); p->p_sigignore &= ~sig; p->p_sigcatch &= ~sig; - p->p_sigmask &= ~sig; + ut->uu_sigmask &= ~sig; /* sendsig is called with signal lock held */ - psignal_lock(p, SIGILL, 0, 1); + psignal_lock(p, SIGILL, 0); return; } @@ -207,6 +215,9 @@ sigreturn(p, uap, retval) thread_act_t th_act = current_act(); int error; struct i386_saved_state* saved_state = get_user_regs(th_act); + struct uthread * ut; + + if (saved_state == NULL) return EINVAL; @@ -214,24 +225,15 @@ sigreturn(p, uap, retval) if (error = copyin((caddr_t)uap->sigcntxp, (caddr_t)&context, sizeof (context))) return(error); - -#if 0 /*FIXME*/ - if ((context.sc_eflags & EFL_VM) == 0 && - (!valid_user_code_selector(context.sc_cs) || - !valid_user_data_selector(context.sc_ds) || - !valid_user_data_selector(context.sc_es) || - !valid_user_data_selector(context.sc_fs) || - !valid_user_data_selector(context.sc_gs) || - !valid_user_stack_selector(context.sc_ss)) - ) - return(EINVAL); -#endif + ut = (struct uthread *)get_bsdthread_info(th_act); if (context.sc_onstack & 01) p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK; else p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK; - p->p_sigmask = context.sc_mask &~ sigcantmask; + ut->uu_sigmask = context.sc_mask &~ sigcantmask; + if(ut->uu_siglist & ~ut->uu_sigmask) + signal_setast(current_act()); saved_state->eax = context.sc_eax; saved_state->ebx = context.sc_ebx; saved_state->ecx = context.sc_ecx; diff --git a/bsd/dev/i386/unix_startup.c b/bsd/dev/i386/unix_startup.c index c14e2807e..f341af01a 100644 --- a/bsd/dev/i386/unix_startup.c +++ b/bsd/dev/i386/unix_startup.c @@ -74,7 +74,7 @@ bsd_startupearly() nbuf = 256; if (niobuf == 0) - niobuf = nbuf / 2; + niobuf = (nbuf / 2) + 64; /* 64 reserved buffers */ if (niobuf > 4096) niobuf = 4096; if (niobuf < 128) @@ -111,8 +111,8 @@ bsd_startupearly() extern u_long tcp_recvspace; if ((nmbclusters = ncl) == 0) { - if ((nmbclusters = ((mem_size / 16) / MCLBYTES)) > 4096) - nmbclusters = 8192; + if ((nmbclusters = ((mem_size / 16) / MCLBYTES)) > 16384) + nmbclusters = 16384; } if ((scale = nmbclusters / NMBCLUSTERS) > 1) { tcp_sendspace *= scale; diff --git a/bsd/dev/ppc/conf.c b/bsd/dev/ppc/conf.c index 0030fe927..bfe8c9a0c 100644 --- a/bsd/dev/ppc/conf.c +++ b/bsd/dev/ppc/conf.c @@ -231,17 +231,19 @@ isdisk(dev, type) dev_t dev; int type; { - switch (major(dev)) { - case 1: /* fd: floppy */ - case 6: /* sd: scsi disk */ - case 3: /* ide: */ - if (type == VBLK) - return(1); - break; - case 14: /* sd: scsi disk */ - case 41: /* fd: floppy */ - if (type == VCHR) - return(1); + dev_t maj = major(dev); + + switch (type) { + case VCHR: + maj = chrtoblk(maj); + if (maj == NODEV) { + break; + } + /* FALL THROUGH */ + case VBLK: + if (bdevsw[maj].d_type == D_DISK) { + return (1); + } break; } return(0); @@ -291,6 +293,17 @@ chrtoblk(dev) return(makedev(blkmaj, minor(dev))); } +int +chrtoblk_set(int cdev, int bdev) +{ + if (cdev >= nchrdev) + return (NODEV); + if (bdev != NODEV && bdev >= nblkdev) + return (NODEV); + chrtoblktab[cdev] = bdev; + return 0; +} + /* * Returns true if dev is /dev/mem or /dev/kmem. */ diff --git a/bsd/dev/ppc/km.c b/bsd/dev/ppc/km.c index e04d3a636..9bf068b0b 100644 --- a/bsd/dev/ppc/km.c +++ b/bsd/dev/ppc/km.c @@ -314,7 +314,7 @@ kmtimeout( struct tty *tp) funnel_state = thread_funnel_set(kernel_flock, TRUE); kmoutput(tp); - (void) thread_funnel_set(kernel_flock, FALSE); + (void) thread_funnel_set(kernel_flock, funnel_state); } diff --git a/bsd/dev/ppc/mem.c b/bsd/dev/ppc/mem.c index 6af5aca37..ba9a0f800 100644 --- a/bsd/dev/ppc/mem.c +++ b/bsd/dev/ppc/mem.c @@ -81,8 +81,8 @@ #include #include -#include -#include +#include +#include static caddr_t devzerobuf; diff --git a/bsd/dev/ppc/systemcalls.c b/bsd/dev/ppc/systemcalls.c index 4bd050722..e84fd36dc 100644 --- a/bsd/dev/ppc/systemcalls.c +++ b/bsd/dev/ppc/systemcalls.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -19,150 +19,274 @@ * * @APPLE_LICENSE_HEADER_END@ */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void +unix_syscall( + struct savearea *regs +); + +extern struct savearea * +find_user_regs( + thread_act_t act); + +extern enter_funnel_section(funnel_t *funnel_lock); +extern exit_funnel_section(funnel_t *funnel_lock); + /* - * Copyright (c) 1997 Apple Computer, Inc. + * Function: unix_syscall * - * PowerPC Family: System Call handlers. + * Inputs: regs - pointer to Process Control Block * - * HISTORY - * 27-July-97 A. Ramesh - * Adopted for Common Core. + * Outputs: none */ - -#include -#include +void +unix_syscall( + struct savearea *regs +) +{ + thread_act_t thread_act; + struct uthread *uthread; + struct proc *proc; + struct sysent *callp; + int error; + unsigned short code; + boolean_t flavor; + int funnel_type; -#include -#include + thread_act = current_act(); + uthread = get_bsdthread_info(thread_act); -#include -#include -#include -#include -#include -#include + if (!(uthread->uu_flag & P_VFORK)) + proc = (struct proc *)get_bsdtask_info(current_task()); + else + proc = current_proc(); + flavor = (regs->save_r0 == NULL)? 1: 0; -#define ERESTART -1 /* restart syscall */ -#define EJUSTRETURN -2 /* don't modify regs, just return */ + uthread->uu_ar0 = (int *)regs; + if (flavor) + code = regs->save_r3; + else + code = regs->save_r0; -struct unix_syscallargs { - int flavor; - int r3; - int arg1, arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9; -}; -extern struct sysent { /* system call table */ - int16_t sy_narg; /* number of args */ - int16_t sy_parallel;/* can execute in parallel */ - int32_t (*sy_call)(); /* implementing function */ -} sysent[]; + callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; -/* -** Function: unix_syscall -** -** Inputs: pcb - pointer to Process Control Block -** arg1 - arguments to mach system calls -** arg2 -** arg3 -** arg4 -** arg5 -** arg6 -** arg7 -** -** Outputs: none -*/ -void -unix_syscall( - struct pcb * pcb, - int arg1, - int arg2, - int arg3, - int arg4, - int arg5, - int arg6, - int arg7 - ) -{ - struct ppc_saved_state *regs; - thread_t thread; - struct proc *p; - struct sysent *callp; - int nargs, error; - unsigned short code; - int rval[2]; - struct unix_syscallargs sarg; +#ifdef DEBUG + if (callp->sy_narg > 8) + panic("unix_syscall: max arg count exceeded"); +#endif + + if (callp->sy_narg != 0) { + if ( !flavor) { + uthread->uu_arg[0] = regs->save_r3; + uthread->uu_arg[1] = regs->save_r4; + uthread->uu_arg[2] = regs->save_r5; + uthread->uu_arg[3] = regs->save_r6; + uthread->uu_arg[4] = regs->save_r7; + uthread->uu_arg[5] = regs->save_r8; + uthread->uu_arg[6] = regs->save_r9; + uthread->uu_arg[7] = regs->save_r10; + } else { + uthread->uu_arg[0] = regs->save_r4; + uthread->uu_arg[1] = regs->save_r5; + uthread->uu_arg[2] = regs->save_r6; + uthread->uu_arg[3] = regs->save_r7; + uthread->uu_arg[4] = regs->save_r8; + uthread->uu_arg[5] = regs->save_r9; + uthread->uu_arg[7] = regs->save_r10; + } + } - if (!USERMODE(pcb->ss.srr1)) - panic("unix_syscall"); + callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; - regs = &pcb->ss; - thread = current_thread(); + if (kdebug_enable && (code != 180)) { + if (flavor) + KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START, + regs->save_r4, regs->save_r5, regs->save_r6, regs->save_r7, 0); + else + KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START, + regs->save_r3, regs->save_r4, regs->save_r5, regs->save_r6, 0); + } + funnel_type = (int)callp->sy_funnel; + if(funnel_type == KERNEL_FUNNEL) + enter_funnel_section(kernel_flock); + else if (funnel_type == NETWORK_FUNNEL) + enter_funnel_section(network_flock); + - /* - ** Get index into sysent table - */ - code = regs->r0; + uthread->uu_rval[0] = 0; - /* - ** Set up call pointer - */ - callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; + * r4 is volatile, if we set it to regs->save_r4 here the child + * will have parents r4 after execve + */ + uthread->uu_rval[1] = 0; - sarg. flavor = (callp == sysent): 1: 0; - sarg. r3 = regs->r3; - sarg. arg1 = arg1; - sarg. arg2 = arg2; - sarg. arg3 = arg3; - sarg. arg4 = arg4; - sarg. arg5 = arg5; - sarg. arg6 = arg6; - sarg. arg7 = arg7; + error = 0; - set_bsduthreadargs(thread,pcb,&sarg); + /* + * PPC runtime calls cerror after every unix system call, so + * assume no error and adjust the "pc" to skip this call. + * It will be set back to the cerror call if an error is detected. + */ + regs->save_srr0 += 4; + if (KTRPOINT(proc, KTR_SYSCALL)) + ktrsyscall(proc, code, callp->sy_narg, uthread->uu_arg, funnel_type); - if (callp->sy_narg > 8) - panic("unix_syscall: max arg count exceeded"); + error = (*(callp->sy_call))(proc, (void *)uthread->uu_arg, &(uthread->uu_rval[0])); + + regs = find_user_regs(thread_act); - rval[0] = 0; + if (error == ERESTART) { + regs->save_srr0 -= 8; + } else if (error != EJUSTRETURN) { + if (error) { + regs->save_r3 = error; + /* set the "pc" to execute cerror routine */ + regs->save_srr0 -= 4; + } else { /* (not error) */ + regs->save_r3 = uthread->uu_rval[0]; + regs->save_r4 = uthread->uu_rval[1]; + } + } + /* else (error == EJUSTRETURN) { nothing } */ - /* r4 is volatile, if we set it to regs->r4 here the child - * will have parents r4 after execve */ - rval[1] = 0; + if (KTRPOINT(proc, KTR_SYSRET)) + ktrsysret(proc, code, error, uthread->uu_rval[0], funnel_type); - error = 0; /* Start with a good value */ + if(funnel_type == KERNEL_FUNNEL) + exit_funnel_section(kernel_flock); + else if (funnel_type == NETWORK_FUNNEL) + exit_funnel_section(network_flock); + + if (kdebug_enable && (code != 180)) { + KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END, + error, uthread->uu_rval[0], uthread->uu_rval[1], 0, 0); + } + + thread_exception_return(); + /* NOTREACHED */ +} + +unix_syscall_return(error) +{ + thread_act_t thread_act; + struct uthread *uthread; + struct proc *proc; + struct savearea *regs; + unsigned short code; + struct sysent *callp; + int funnel_type; + + thread_act = current_act(); + proc = current_proc(); + uthread = get_bsdthread_info(thread_act); + + regs = find_user_regs(thread_act); /* - ** the PPC runtime calls cerror after every unix system call, so - ** assume no error and adjust the "pc" to skip this call. - ** It will be set back to the cerror call if an error is detected. - */ - regs->srr0 += 4; - vt = get_bsduthreadarg(thread); - p = ((struct proc *)get_bsdtask_info(current_task())); - error = (*(callp->sy_call))(p, (caddr_t)vt, rval); - - if (error == ERESTART) { - regs->srr0 -= 8; - } - else if (error != EJUSTRETURN) { - if (error) - { - regs->r3 = error; - /* set the "pc" to execute cerror routine */ - regs->srr0 -= 4; - } else { /* (not error) */ - regs->r3 = rval[0]; - regs->r4 = rval[1]; - } - } - /* else (error == EJUSTRETURN) { nothing } */ - - thread_exception_return(); - /* NOTREACHED */ + * Get index into sysent table + */ + if (error == ERESTART) { + regs->save_srr0 -= 8; + } else if (error != EJUSTRETURN) { + if (error) { + regs->save_r3 = error; + /* set the "pc" to execute cerror routine */ + regs->save_srr0 -= 4; + } else { /* (not error) */ + regs->save_r3 = uthread->uu_rval[0]; + regs->save_r4 = uthread->uu_rval[1]; + } + } + /* else (error == EJUSTRETURN) { nothing } */ + + if (regs->save_r0 != NULL) + code = regs->save_r0; + else + code = regs->save_r3; + + callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; + + funnel_type = (int)callp->sy_funnel; + + if (KTRPOINT(proc, KTR_SYSRET)) + ktrsysret(proc, code, error, uthread->uu_rval[0], funnel_type); + + if(funnel_type == KERNEL_FUNNEL) + exit_funnel_section(kernel_flock); + else if (funnel_type == NETWORK_FUNNEL) + exit_funnel_section(network_flock); + + if (kdebug_enable && (code != 180)) { + KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END, + error, uthread->uu_rval[0], uthread->uu_rval[1], 0, 0); + } + + thread_exception_return(); + /* NOTREACHED */ +} + +/* + * 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. + */ +struct gettimeofday_args{ + struct timeval *tp; + struct timezone *tzp; +}; +/* NOTE THIS implementation is for ppc architectures only */ +int +ppc_gettimeofday(p, uap, retval) + struct proc *p; + register struct gettimeofday_args *uap; + register_t *retval; +{ + struct timeval atv; + int error = 0; + struct timezone ltz; + //struct savearea *child_state; + extern simple_lock_data_t tz_slock; + + if (uap->tp) { + microtime(&atv); + retval[0] = atv.tv_sec; + retval[1] = atv.tv_usec; + } + if (uap->tzp) { + usimple_lock(&tz_slock); + ltz = tz; + usimple_unlock(&tz_slock); + error = copyout((caddr_t)<z, (caddr_t)uap->tzp, + sizeof (tz)); + } + + return(error); } diff --git a/bsd/dev/ppc/unix_signal.c b/bsd/dev/ppc/unix_signal.c index 894756641..bc2a1f20f 100644 --- a/bsd/dev/ppc/unix_signal.c +++ b/bsd/dev/ppc/unix_signal.c @@ -29,12 +29,17 @@ #include #include #include +#include #include #include +#include +#include #include #include #include +#define __ELF__ 0 +#include #define C_REDZONE_LEN 224 #define C_STK_ALIGN 16 @@ -46,12 +51,6 @@ * Arrange for this process to run a signal handler */ - -struct sigregs { - struct ppc_saved_state ss; - struct ppc_float_state fs; -}; - void sendsig(p, catcher, sig, mask, code) struct proc *p; @@ -59,90 +58,199 @@ sendsig(p, catcher, sig, mask, code) int sig, mask; u_long code; { - struct sigregs *p_regs; - struct sigcontext context, *p_context; + struct mcontext mctx, *p_mctx; + struct ucontext uctx, *p_uctx; + siginfo_t sinfo, *p_sinfo; struct sigacts *ps = p->p_sigacts; int framesize; int oonstack; unsigned long sp; - struct ppc_saved_state statep; - struct ppc_float_state fs; unsigned long state_count; - struct thread *thread; thread_act_t th_act; + struct uthread *ut; unsigned long paramp,linkp; + int infostyle = 1; + sig_t trampact; + int vec_used = 0; + int stack_size = 0; + int stack_flags = 0; - thread = current_thread(); th_act = current_act(); + ut = get_bsdthread_info(th_act); + state_count = PPC_EXCEPTION_STATE_COUNT; + if (act_machine_get_state(th_act, PPC_EXCEPTION_STATE, &mctx.es, &state_count) != KERN_SUCCESS) { + goto bad; + } state_count = PPC_THREAD_STATE_COUNT; - if (act_machine_get_state(th_act, PPC_THREAD_STATE, &statep, &state_count) != KERN_SUCCESS) { + if (act_machine_get_state(th_act, PPC_THREAD_STATE, &mctx.ss, &state_count) != KERN_SUCCESS) { goto bad; } state_count = PPC_FLOAT_STATE_COUNT; - if (act_machine_get_state(th_act, PPC_FLOAT_STATE, &fs, &state_count) != KERN_SUCCESS) { + if (act_machine_get_state(th_act, PPC_FLOAT_STATE, &mctx.fs, &state_count) != KERN_SUCCESS) { goto bad; } + vec_save(th_act); + if (find_user_vec(th_act)) { + vec_used = 1; + state_count = PPC_VECTOR_STATE_COUNT; + if (act_machine_get_state(th_act, PPC_VECTOR_STATE, &mctx.vs, &state_count) != KERN_SUCCESS) { + goto bad; + } + + } + + trampact = ps->ps_trampact[sig]; oonstack = ps->ps_sigstk.ss_flags & SA_ONSTACK; + if (p->p_sigacts->ps_siginfo & sigmask(sig)) + infostyle = 2; /* figure out where our new stack lives */ if ((ps->ps_flags & SAS_ALTSTACK) && !oonstack && (ps->ps_sigonstack & sigmask(sig))) { sp = (unsigned long)(ps->ps_sigstk.ss_sp); sp += ps->ps_sigstk.ss_size; + stack_size = ps->ps_sigstk.ss_size; ps->ps_sigstk.ss_flags |= SA_ONSTACK; } else - sp = statep.r1; + sp = mctx.ss.r1; - // preserve RED ZONE area + /* preserve RED ZONE area */ sp = TRUNC_DOWN(sp, C_REDZONE_LEN, C_STK_ALIGN); - // context goes first on stack - sp -= sizeof(*p_context); - p_context = (struct sigcontext *) sp; + /* context goes first on stack */ + sp -= sizeof(*p_uctx); + p_uctx = (struct ucontext *) sp; + + /* this is where siginfo goes on stack */ + sp -= sizeof(*p_sinfo); + p_sinfo = (siginfo_t *) sp; - // next are the saved registers - sp -= sizeof(*p_regs); - p_regs = (struct sigregs *)sp; + /* next are the saved registers */ + sp -= sizeof(*p_mctx); + p_mctx = (struct mcontext *)sp; - // C calling conventions, create param save and linkage - // areas + /* C calling conventions, create param save and linkage + * areas + */ sp = TRUNC_DOWN(sp, C_PARAMSAVE_LEN, C_STK_ALIGN); paramp = sp; sp -= C_LINKAGE_LEN; linkp = sp; - /* fill out sigcontext */ - context.sc_onstack = oonstack; - context.sc_mask = mask; - context.sc_ir = statep.srr0; - context.sc_psw = statep.srr1; - context.sc_regs = p_regs; + uctx.uc_onstack = oonstack; + uctx.uc_sigmask = mask; + uctx.uc_stack.ss_sp = (char *)sp; + uctx.uc_stack.ss_size = stack_size; + if (oonstack) + uctx.uc_stack.ss_flags |= SS_ONSTACK; + + uctx.uc_link = 0; + uctx.uc_mcsize = (size_t)((PPC_EXCEPTION_STATE_COUNT + PPC_THREAD_STATE_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int)); + if (vec_used) + uctx.uc_mcsize += (size_t)(PPC_VECTOR_STATE_COUNT * sizeof(int)); + uctx.uc_mcontext = p_mctx; + + /* setup siginfo */ + bzero((caddr_t)&sinfo, sizeof(siginfo_t)); + sinfo.si_signo = sig; + switch (sig) { + case SIGCHLD: + sinfo.si_pid = p->si_pid; + p->si_pid =0; + sinfo.si_status = p->si_status; + p->si_status = 0; + sinfo.si_uid = p->si_uid; + p->si_uid =0; + sinfo.si_code = p->si_code; + p->si_code = 0; + if (sinfo.si_code == CLD_EXITED) { + if (WIFEXITED(sinfo.si_status)) + sinfo.si_code = CLD_EXITED; + else if (WIFSIGNALED(sinfo.si_status)) { + if (WCOREDUMP(sinfo.si_status)) + sinfo.si_code = CLD_DUMPED; + else + sinfo.si_code = CLD_KILLED; + } + } + break; + case SIGILL: + sinfo.si_addr = (void *)mctx.ss.srr0; + if (mctx.ss.srr1 & (1 << (31 - SRR1_PRG_ILL_INS_BIT))) + sinfo.si_code = ILL_ILLOPC; + else if (mctx.ss.srr1 & (1 << (31 - SRR1_PRG_PRV_INS_BIT))) + sinfo.si_code = ILL_PRVOPC; + else if (mctx.ss.srr1 & (1 << (31 - SRR1_PRG_TRAP_BIT))) + sinfo.si_code = ILL_ILLTRP; + else + sinfo.si_code = ILL_NOOP; + break; + case SIGFPE: +#define FPSCR_VX 2 +#define FPSCR_OX 3 +#define FPSCR_UX 4 +#define FPSCR_ZX 5 +#define FPSCR_XX 6 + sinfo.si_addr = (void *)mctx.ss.srr0; + if (mctx.fs.fpscr & (1 << (31 - FPSCR_VX))) + sinfo.si_code = FPE_FLTINV; + else if (mctx.fs.fpscr & (1 << (31 - FPSCR_OX))) + sinfo.si_code = FPE_FLTOVF; + else if (mctx.fs.fpscr & (1 << (31 - FPSCR_UX))) + sinfo.si_code = FPE_FLTUND; + else if (mctx.fs.fpscr & (1 << (31 - FPSCR_ZX))) + sinfo.si_code = FPE_FLTDIV; + else if (mctx.fs.fpscr & (1 << (31 - FPSCR_XX))) + sinfo.si_code = FPE_FLTRES; + else + sinfo.si_code = FPE_NOOP; + break; + + case SIGBUS: + sinfo.si_addr = (void *)mctx.ss.srr0; + /* on ppc we generate only if EXC_PPC_UNALIGNED */ + sinfo.si_code = BUS_ADRALN; + break; + + case SIGSEGV: + sinfo.si_addr = (void *)mctx.ss.srr0; + /* First check in srr1 and then in dsisr */ + if (mctx.ss.srr1 & (1 << (31 - DSISR_PROT_BIT))) + sinfo.si_code = SEGV_ACCERR; + else if (mctx.es.dsisr & (1 << (31 - DSISR_PROT_BIT))) + sinfo.si_code = SEGV_ACCERR; + else + sinfo.si_code = SEGV_MAPERR; + break; + default: + break; + } /* copy info out to user space */ - if (copyout((caddr_t)&context, (caddr_t)p_context, sizeof(context))) + if (copyout((caddr_t)&uctx, (caddr_t)p_uctx, sizeof(struct ucontext))) goto bad; - if (copyout((caddr_t)&statep, (caddr_t)&p_regs->ss, - sizeof(struct ppc_saved_state))) + if (copyout((caddr_t)&sinfo, (caddr_t)p_sinfo, sizeof(siginfo_t))) goto bad; - if (copyout((caddr_t)&fs, (caddr_t)&p_regs->fs, - sizeof(struct ppc_float_state))) + if (copyout((caddr_t)&mctx, (caddr_t)p_mctx, uctx.uc_mcsize)) goto bad; /* Place our arguments in arg registers: rtm dependent */ - statep.r3 = (unsigned long)sig; - statep.r4 = (unsigned long)code; - statep.r5 = (unsigned long)p_context; + mctx.ss.r3 = (unsigned long)catcher; + mctx.ss.r4 = (unsigned long)infostyle; + mctx.ss.r5 = (unsigned long)sig; + mctx.ss.r6 = (unsigned long)p_sinfo; + mctx.ss.r7 = (unsigned long)p_uctx; - statep.srr0 = (unsigned long)catcher; - statep.srr1 = get_msr_exportmask(); /* MSR_EXPORT_MASK_SET */ - statep.r1 = sp; + mctx.ss.srr0 = (unsigned long)trampact; + mctx.ss.srr1 = get_msr_exportmask(); /* MSR_EXPORT_MASK_SET */ + mctx.ss.r1 = sp; state_count = PPC_THREAD_STATE_COUNT; - if (act_machine_set_state(th_act, PPC_THREAD_STATE, &statep, &state_count) != KERN_SUCCESS) { + if (act_machine_set_state(th_act, PPC_THREAD_STATE, &mctx.ss, &state_count) != KERN_SUCCESS) { goto bad; } @@ -153,9 +261,9 @@ bad: sig = sigmask(SIGILL); p->p_sigignore &= ~sig; p->p_sigcatch &= ~sig; - p->p_sigmask &= ~sig; + ut->uu_sigmask &= ~sig; /* sendsig is called with signal lock held */ - psignal_lock(p, SIGILL, 0, 1); + psignal_lock(p, SIGILL, 0); return; } @@ -170,7 +278,7 @@ bad: * a machine fault. */ struct sigreturn_args { - struct sigcontext *sigcntxp; + struct ucontext *uctx; }; /* ARGSUSED */ @@ -180,74 +288,78 @@ sigreturn(p, uap, retval) struct sigreturn_args *uap; int *retval; { - struct sigcontext context; - struct sigregs *p_regs; + struct ucontext uctx, *p_uctx; + struct mcontext mctx, *p_mctx; int error; - struct thread *thread; thread_act_t th_act; - struct ppc_saved_state statep; struct ppc_float_state fs; + struct ppc_exception_state es; + struct sigacts *ps = p->p_sigacts; + sigset_t mask; + register sig_t action; unsigned long state_count; unsigned int nbits, rbits; + struct uthread * ut; + int vec_used = 0; - thread = current_thread(); th_act = current_act(); - if (error = copyin(uap->sigcntxp, &context, sizeof(context))) { + ut = (struct uthread *)get_bsdthread_info(th_act); + if (error = copyin(uap->uctx, &uctx, sizeof(struct ucontext))) { return(error); } - state_count = PPC_THREAD_STATE_COUNT; - if (act_machine_get_state(th_act, PPC_THREAD_STATE, &statep, &state_count) != KERN_SUCCESS) { - return(EINVAL); - } - state_count = PPC_FLOAT_STATE_COUNT; - if (act_machine_get_state(th_act, PPC_FLOAT_STATE, &fs, &state_count) != KERN_SUCCESS) { - return(EINVAL); - } + if (error = copyin(uctx.uc_mcontext, &mctx, sizeof(struct mcontext))) { + return(error); + } + + if (uctx.uc_onstack & 01) + p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK; + else + p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK; + ut->uu_sigmask = uctx.uc_sigmask & ~sigcantmask; + + + if (ut->uu_siglist & ~ut->uu_sigmask) + signal_setast(current_act()); + nbits = get_msr_nbits(); rbits = get_msr_rbits(); /* adjust the critical fields */ /* make sure naughty bits are off */ - context.sc_psw &= ~(nbits); + mctx.ss.srr1 &= ~(nbits); /* make sure necessary bits are on */ - context.sc_psw |= (rbits); - -// /* we return from sigreturns as if we faulted in */ -// entry->es_flags = (entry->es_flags & ~ES_GATEWAY) | ES_TRAP; - - if (context.sc_regs) { - p_regs = (struct sigregs *)context.sc_regs; - if (error = copyin(&p_regs->ss, &statep, - sizeof(struct ppc_saved_state))) - return(error); + mctx.ss.srr1 |= (rbits); - if (error = copyin(&p_regs->fs, &fs, - sizeof(struct ppc_float_state))) - return(error); - - } - else { - statep.r1 = context.sc_sp; - } -// entry->es_general.saved.stack_pointer = context.sc_sp; + state_count = (size_t)((PPC_EXCEPTION_STATE_COUNT + PPC_THREAD_STATE_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int)); - if (context.sc_onstack & 01) - p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK; - else - p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK; - p->p_sigmask = context.sc_mask &~ sigcantmask; - statep.srr0 = context.sc_ir; - statep.srr1 = context.sc_psw; + if (uctx.uc_mcsize > state_count) + vec_used = 1; state_count = PPC_THREAD_STATE_COUNT; - if (act_machine_set_state(th_act, PPC_THREAD_STATE, &statep, &state_count) != KERN_SUCCESS) { + if (act_machine_set_state(th_act, PPC_THREAD_STATE, &mctx.ss, &state_count) != KERN_SUCCESS) { return(EINVAL); } state_count = PPC_FLOAT_STATE_COUNT; - if (act_machine_set_state(th_act, PPC_FLOAT_STATE, &fs, &state_count) != KERN_SUCCESS) { + if (act_machine_set_state(th_act, PPC_FLOAT_STATE, &mctx.fs, &state_count) != KERN_SUCCESS) { return(EINVAL); } + + mask = sigmask(SIGFPE); + if (((ut->uu_sigmask & mask) == 0) && (p->p_sigcatch & mask) && ((p->p_sigignore & mask) == 0)) { + action = ps->ps_sigact[SIGFPE]; + if((action != SIG_DFL) && (action != SIG_IGN)) { + thread_enable_fpe(th_act, 1); + } + } + + if (vec_used) { + state_count = PPC_VECTOR_STATE_COUNT; + if (act_machine_set_state(th_act, PPC_VECTOR_STATE, &mctx.vs, &state_count) != KERN_SUCCESS) { + return(EINVAL); + } + } + return (EJUSTRETURN); } diff --git a/bsd/dev/ppc/unix_startup.c b/bsd/dev/ppc/unix_startup.c index d8dcbece8..531a75a0b 100644 --- a/bsd/dev/ppc/unix_startup.c +++ b/bsd/dev/ppc/unix_startup.c @@ -72,7 +72,7 @@ bsd_startupearly() nbuf = 256; if (niobuf == 0) - niobuf = nbuf / 2; + niobuf = nbuf; if (niobuf > 4096) niobuf = 4096; if (niobuf < 128) @@ -109,8 +109,8 @@ bsd_startupearly() extern u_long tcp_recvspace; if ((nmbclusters = ncl) == 0) { - if ((nmbclusters = ((mem_size / 16) / MCLBYTES)) > 8192) - nmbclusters = 8192; + if ((nmbclusters = ((mem_size / 16) / MCLBYTES)) > 16384) + nmbclusters = 16384; } if ((scale = nmbclusters / NMBCLUSTERS) > 1) { tcp_sendspace *= scale; diff --git a/bsd/dev/random/Makefile b/bsd/dev/random/Makefile index a0b386718..778286e30 100644 --- a/bsd/dev/random/Makefile +++ b/bsd/dev/random/Makefile @@ -20,15 +20,14 @@ EXPINC_SUBDIRS_PPC = \ EXPINC_SUBDIRS_I386 = \ DATAFILES = \ - randomdev.h INSTALL_MI_LIST = ${DATAFILES} -INSTALL_MI_DIR = dev/random +INSTALL_MI_DIR = EXPORT_MI_LIST = ${DATAFILES} -EXPORT_MI_DIR = dev/random +EXPORT_MI_DIR = include $(MakeInc_rule) diff --git a/bsd/dev/random/YarrowCoreLib/include/WindowsTypesForMac.h b/bsd/dev/random/YarrowCoreLib/include/WindowsTypesForMac.h index e1c4d4f4e..bdab3ea8a 100644 --- a/bsd/dev/random/YarrowCoreLib/include/WindowsTypesForMac.h +++ b/bsd/dev/random/YarrowCoreLib/include/WindowsTypesForMac.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2000-2001 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1999, 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -38,24 +38,24 @@ #ifndef _WINDOWS_TYPES_FOR_MAC_H_ #define _WINDOWS_TYPES_FOR_MAC_H_ -#include +#include -typedef UInt8 UCHAR; -typedef SInt8 CHAR; -typedef UInt8 BYTE; +typedef u_int8_t UCHAR; +typedef int8_t CHAR; +typedef u_int8_t BYTE; typedef char TCHAR; -typedef SInt16 WORD; -typedef SInt32 DWORD; -typedef UInt16 USHORT; -typedef UInt32 ULONG; -typedef SInt32 LONG; -typedef UInt32 UINT; -typedef SInt64 LONGLONG; -typedef UInt8 *LPBYTE; -typedef SInt8 *LPSTR; -typedef SInt16 *LPWORD; -typedef SInt8 *LPCTSTR; /* ??? */ -typedef SInt8 *LPCSTR; /* ??? */ +typedef int16_t WORD; +typedef int32_t DWORD; +typedef u_int16_t USHORT; +typedef u_int32_t ULONG; +typedef int32_t LONG; +typedef u_int32_t UINT; +typedef int64_t LONGLONG; +typedef u_int8_t *LPBYTE; +typedef int8_t *LPSTR; +typedef int16_t *LPWORD; +typedef int8_t *LPCTSTR; /* ??? */ +typedef int8_t *LPCSTR; /* ??? */ typedef void *LPVOID; typedef void *HINSTANCE; typedef void *HANDLE; diff --git a/bsd/dev/random/YarrowCoreLib/include/macos_defs.h b/bsd/dev/random/YarrowCoreLib/include/macos_defs.h deleted file mode 100644 index 73aa2ddcd..000000000 --- a/bsd/dev/random/YarrowCoreLib/include/macos_defs.h +++ /dev/null @@ -1,1658 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - File: hfs_macos_types.h - - Contains: Basic Macintosh OS data types. - - Version: System 7.5 - - DRI: Nick Kledzik - - History: - 12-Aug-1999 Scott Roberts Created from ConditionalMacros.h, MacOSStubs.h, MacOSTypes.h - - - -*/ - - -#ifndef __hfs_macos_types__ -#define __hfs_macos_types__ - - -#include - #ifdef KERNEL - #include - #include - #endif - -#include -#include -#include -#include - -/****** START OF CONDITIONALMACROS *********/ - - #if defined(__ppc__) || defined(powerpc) || defined(ppc) - #define TARGET_CPU_PPC 1 - #define TARGET_CPU_68K 0 - #define TARGET_CPU_X86 0 - #define TARGET_CPU_MIPS 0 - #define TARGET_CPU_SPARC 0 - #define TARGET_CPU_ALPHA 0 - #define TARGET_RT_MAC_CFM 0 - #define TARGET_RT_MAC_MACHO 1 - #define TARGET_RT_MAC_68881 0 - #define TARGET_RT_LITTLE_ENDIAN 0 - #define TARGET_RT_BIG_ENDIAN 1 - #elif defined(m68k) - #define TARGET_CPU_PPC 0 - #define TARGET_CPU_68K 1 - #define TARGET_CPU_X86 0 - #define TARGET_CPU_MIPS 0 - #define TARGET_CPU_SPARC 0 - #define TARGET_CPU_ALPHA 0 - #define TARGET_RT_MAC_CFM 0 - #define TARGET_RT_MAC_MACHO 1 - #define TARGET_RT_MAC_68881 0 - #define TARGET_RT_LITTLE_ENDIAN 0 - #define TARGET_RT_BIG_ENDIAN 1 - #elif defined(sparc) - #define TARGET_CPU_PPC 0 - #define TARGET_CPU_68K 0 - #define TARGET_CPU_X86 0 - #define TARGET_CPU_MIPS 0 - #define TARGET_CPU_SPARC 1 - #define TARGET_CPU_ALPHA 0 - #define TARGET_RT_MAC_CFM 0 - #define TARGET_RT_MAC_MACHO 1 - #define TARGET_RT_MAC_68881 0 - #define TARGET_RT_LITTLE_ENDIAN 0 - #define TARGET_RT_BIG_ENDIAN 1 - #elif defined(__i386__) || defined(i386) || defined(intel) - #define TARGET_CPU_PPC 0 - #define TARGET_CPU_68K 0 - #define TARGET_CPU_X86 1 - #define TARGET_CPU_MIPS 0 - #define TARGET_CPU_SPARC 0 - #define TARGET_CPU_ALPHA 0 - #define TARGET_RT_MAC_CFM 0 - #define TARGET_RT_MAC_MACHO 1 - #define TARGET_RT_MAC_68881 0 - #define TARGET_RT_LITTLE_ENDIAN 1 - #define TARGET_RT_BIG_ENDIAN 0 - #else - #error unrecognized GNU C compiler - #endif - - - #define TARGET_OS_MAC 0 - #define TARGET_OS_WIN32 0 - #define TARGET_OS_UNIX 0 - - #define PRAGMA_IMPORT 0 - #define PRAGMA_STRUCT_ALIGN 1 - #define PRAGMA_ONCE 0 - #define PRAGMA_STRUCT_PACK 0 - #define PRAGMA_STRUCT_PACKPUSH 0 - #define PRAGMA_ENUM_PACK 0 - #define PRAGMA_ENUM_ALWAYSINT 0 - #define PRAGMA_ENUM_OPTIONS 0 - #define FOUR_CHAR_CODE(x) (x) - - #define TYPE_EXTENDED 0 - #if __GNUC__ >= 2 - #define TYPE_LONGLONG 1 - #else - #define TYPE_LONGLONG 0 - #endif - #ifdef __cplusplus - #define TYPE_BOOL 1 - #else - #define TYPE_BOOL 0 - #endif - - #define FUNCTION_PASCAL 0 - #define FUNCTION_DECLSPEC 0 - #define FUNCTION_WIN32CC 0 - - - #define EXTERN_API(_type) extern _type - #define EXTERN_API_C(_type) extern _type - #define EXTERN_API_STDCALL(_type) extern _type - #define EXTERN_API_C_STDCALL(_type) extern _type - - #define DEFINE_API(_type) _type - #define DEFINE_API_C(_type) _type - #define DEFINE_API_STDCALL(_type) _type - #define DEFINE_API_C_STDCALL(_type) _type - - #define CALLBACK_API(_type, _name) _type ( * _name) - #define CALLBACK_API_C(_type, _name) _type ( * _name) - #define CALLBACK_API_STDCALL(_type, _name) _type ( * _name) - #define CALLBACK_API_C_STDCALL(_type, _name) _type ( * _name) - - #define TARGET_API_MACOS_X 1 - #define TARGET_API_MAC_OS8 0 - #define TARGET_API_MAC_CARBON 0 - - #define ONEWORDINLINE(w1) - #define TWOWORDINLINE(w1,w2) - #define THREEWORDINLINE(w1,w2,w3) - #define FOURWORDINLINE(w1,w2,w3,w4) - #define FIVEWORDINLINE(w1,w2,w3,w4,w5) - #define SIXWORDINLINE(w1,w2,w3,w4,w5,w6) - #define SEVENWORDINLINE(w1,w2,w3,w4,w5,w6,w7) - #define EIGHTWORDINLINE(w1,w2,w3,w4,w5,w6,w7,w8) - #define NINEWORDINLINE(w1,w2,w3,w4,w5,w6,w7,w8,w9) - #define TENWORDINLINE(w1,w2,w3,w4,w5,w6,w7,w8,w9,w10) - #define ELEVENWORDINLINE(w1,w2,w3,w4,w5,w6,w7,w8,w9,w10,w11) - #define TWELVEWORDINLINE(w1,w2,w3,w4,w5,w6,w7,w8,w9,w10,w11,w12) - - -/****** START OF MACOSTYPES *********/ - - -/* - 4.4BSD's sys/types.h defines size_t without defining __size_t__: - Things are a lot clearer from here on if we define __size_t__ now. - */ -#define __size_t__ - -/* - Convert kernel's diagnostic flag to MacOS's -*/ -#if HFS_DIAGNOSTIC - #define DEBUG_BUILD 1 -#else - #define DEBUG_BUILD 0 -#endif /* DIAGNOSTIC */ - -/******************************************************************************** - - Special values in C - - NULL The C standard for an impossible pointer value - nil A carry over from pascal, NULL is prefered for C - -*********************************************************************************/ -#ifndef NULL - #define NULL 0 -#endif - -#ifndef nil - #define nil NULL -#endif - - -/******************************************************************************** - - Base integer types for all target OS's and CPU's - - UInt8 8-bit unsigned integer - SInt8 8-bit signed integer - UInt16 16-bit unsigned integer - SInt16 16-bit signed integer - UInt32 32-bit unsigned integer - SInt32 32-bit signed integer - UInt64 64-bit unsigned integer - SInt64 64-bit signed integer - -*********************************************************************************/ -typedef u_int8_t UInt8; -typedef int8_t SInt8; -typedef u_int16_t UInt16; -typedef int16_t SInt16; -typedef u_int32_t UInt32; -typedef int32_t SInt32; -typedef u_int64_t UInt64; -typedef int64_t SInt64; - - - -/******************************************************************************** - - Base floating point types - - Float32 32 bit IEEE float: 1 sign bit, 8 exponent bits, 23 fraction bits - Float64 64 bit IEEE float: 1 sign bit, 11 exponent bits, 52 fraction bits - Float80 80 bit MacOS float: 1 sign bit, 15 exponent bits, 1 integer bit, 63 fraction bits - Float96 96 bit 68881 float: 1 sign bit, 15 exponent bits, 16 pad bits, 1 integer bit, 63 fraction bits - - Note: These are fixed size floating point types, useful when writing a floating - point value to disk. If your compiler does not support a particular size - float, a struct is used instead. - Use of of the NCEG types (e.g. double_t) or an ANSI C type (e.g. double) if - you want a floating point representation that is natural for any given - compiler, but might be a different size on different compilers. - -*********************************************************************************/ -typedef float Float32; -typedef double Float64; - -struct Float80 { - SInt16 exp; - UInt16 man[4]; -}; -typedef struct Float80 Float80; - -struct Float96 { - SInt16 exp[2]; /* the second 16-bits is always zero */ - UInt16 man[4]; -}; -typedef struct Float96 Float96; - - - -/******************************************************************************** - - MacOS Memory Manager types - - Ptr Pointer to a non-relocatable block - Handle Pointer to a master pointer to a relocatable block - Size The number of bytes in a block (signed for historical reasons) - -*********************************************************************************/ -typedef char * Ptr; -typedef Ptr * Handle; -typedef long Size; -/******************************************************************************** - - Higher level basic types - - OSErr 16-bit result error code - OSStatus 32-bit result error code - LogicalAddress Address in the clients virtual address space - ConstLogicalAddress Address in the clients virtual address space that will only be read - PhysicalAddress Real address as used on the hardware bus - BytePtr Pointer to an array of bytes - ByteCount The size of an array of bytes - ByteOffset An offset into an array of bytes - ItemCount 32-bit iteration count - OptionBits Standard 32-bit set of bit flags - PBVersion ? - Duration 32-bit millisecond timer for drivers - AbsoluteTime 64-bit clock - ScriptCode The coarse features of a written language (e.g. Roman vs Cyrillic) - LangCode A particular language (e.g. English) - RegionCode A variation of a language (British vs American English) - FourCharCode A 32-bit value made by packing four 1 byte characters together - OSType A FourCharCode used in the OS and file system (e.g. creator) - ResType A FourCharCode used to tag resources (e.g. 'DLOG') - -*********************************************************************************/ -typedef SInt16 OSErr; -typedef SInt32 OSStatus; -typedef void * LogicalAddress; -typedef const void * ConstLogicalAddress; -typedef void * PhysicalAddress; -typedef UInt8 * BytePtr; -typedef UInt32 ByteCount; -typedef UInt32 ByteOffset; -typedef SInt32 Duration; -typedef UInt64 AbsoluteTime; -typedef UInt32 OptionBits; -typedef UInt32 ItemCount; -typedef UInt32 PBVersion; -typedef SInt16 ScriptCode; -typedef SInt16 LangCode; -typedef SInt16 RegionCode; -typedef unsigned long FourCharCode; -typedef FourCharCode OSType; -typedef FourCharCode ResType; -typedef OSType * OSTypePtr; -typedef ResType * ResTypePtr; - - -/******************************************************************************** - - Boolean types and values - - Boolean A one byte value, holds "false" (0) or "true" (1) - false The Boolean value of zero (0) - true The Boolean value of one (1) - -*********************************************************************************/ -/* - The identifiers "true" and "false" are becoming keywords in C++ - and work with the new built-in type "bool" - "Boolean" will remain an unsigned char for compatibility with source - code written before "bool" existed. -*/ -#if !TYPE_BOOL - -enum { - false = 0, - true = 1 -}; - -#endif /* !TYPE_BOOL */ - -typedef unsigned char Boolean; - - -/******************************************************************************** - - Function Pointer Types - - ProcPtr Generic pointer to a function - Register68kProcPtr Pointer to a 68K function that expects parameters in registers - UniversalProcPtr Pointer to classic 68K code or a RoutineDescriptor - - ProcHandle Pointer to a ProcPtr - UniversalProcHandle Pointer to a UniversalProcPtr - -*********************************************************************************/ -typedef long (*ProcPtr)(); -typedef void (*Register68kProcPtr)(); - -typedef ProcPtr UniversalProcPtr; - -typedef ProcPtr * ProcHandle; -typedef UniversalProcPtr * UniversalProcHandle; - -/******************************************************************************** - - Quickdraw Types - - Point 2D Quickdraw coordinate, range: -32K to +32K - Rect Rectangluar Quickdraw area - Style Quickdraw font rendering styles - StyleParameter Style when used as a parameter (historical 68K convention) - StyleField Style when used as a field (historical 68K convention) - CharParameter Char when used as a parameter (historical 68K convention) - - Note: The original Macintosh toolbox in 68K Pascal defined Style as a SET. - Both Style and CHAR occupy 8-bits in packed records or 16-bits when - used as fields in non-packed records or as parameters. - -*********************************************************************************/ -struct Point { - short v; - short h; -}; -typedef struct Point Point; - -typedef Point * PointPtr; -struct Rect { - short top; - short left; - short bottom; - short right; -}; -typedef struct Rect Rect; - -typedef Rect * RectPtr; -typedef short CharParameter; - -enum { - normal = 0, - bold = 1, - italic = 2, - underline = 4, - outline = 8, - shadow = 0x10, - condense = 0x20, - extend = 0x40 -}; - -typedef unsigned char Style; -typedef short StyleParameter; -typedef Style StyleField; - - -/******************************************************************************** - - Common Constants - - noErr OSErr: function performed properly - no error - kNilOptions OptionBits: all flags false - kInvalidID KernelID: NULL is for pointers as kInvalidID is for ID's - kVariableLengthArray array bounds: variable length array - - Note: kVariableLengthArray is used in array bounds to specify a variable length array. - It is ususally used in variable length structs when the last field is an array - of any size. Before ANSI C, we used zero as the bounds of variable length - array, but zero length array are illegal in ANSI C. Example usage: - - struct FooList - { - short listLength; - Foo elements[kVariableLengthArray]; - }; - -*********************************************************************************/ - -enum { - noErr = 0 -}; - - -enum { - kNilOptions = 0 -}; - -#define kInvalidID 0 - -enum { - kVariableLengthArray = 1 -}; - - - -/******************************************************************************** - - String Types - - UniChar A single UniCode character (16-bits) - - StrNNN Pascal string holding up to NNN bytes - StringPtr Pointer to a pascal string - StringHandle Pointer to a StringPtr - ConstStrNNNParam For function parameters only - means string is const - - CStringPtr Pointer to a C string (same as: char*) - ConstCStringPtr Pointer to a const C string (same as: const char*) - - Note: The length of a pascal string is stored in the first byte. - A pascal string does not have a termination byte and can be at most 255 bytes long. - The first character in a pascal string is offset one byte from the start of the string. - - A C string is terminated with a byte of value zero. - A C string has no length limitation. - The first character in a C string is the first byte of the string. - - -*********************************************************************************/ -typedef UInt16 UniChar; -typedef unsigned char Str255[256]; -typedef unsigned char Str63[64]; -typedef unsigned char Str32[33]; -typedef unsigned char Str31[32]; -typedef unsigned char Str27[28]; -typedef unsigned char Str15[16]; -/* - The type Str32 is used in many AppleTalk based data structures. - It holds up to 32 one byte chars. The problem is that with the - length byte it is 33 bytes long. This can cause weird alignment - problems in structures. To fix this the type "Str32Field" has - been created. It should only be used to hold 32 chars, but - it is 34 bytes long so that there are no alignment problems. -*/ -typedef unsigned char Str32Field[34]; -typedef unsigned char * StringPtr; -typedef StringPtr * StringHandle; -typedef const unsigned char * ConstStr255Param; -typedef const unsigned char * ConstStr63Param; -typedef const unsigned char * ConstStr32Param; -typedef const unsigned char * ConstStr31Param; -typedef const unsigned char * ConstStr27Param; -typedef const unsigned char * ConstStr15Param; -#ifdef __cplusplus -inline unsigned char StrLength(ConstStr255Param string) { return (*string); } -#else -#define StrLength(string) (*(unsigned char *)(string)) -#endif /* defined(__cplusplus) */ - -typedef const unsigned char * ConstUTF8Param; - -/********************************************************************************* - - Old names for types - -*********************************************************************************/ -typedef UInt8 Byte; -typedef SInt8 SignedByte; -typedef SInt64 * WidePtr; -typedef UInt64 * UnsignedWidePtr; -typedef Float80 extended80; -typedef Float96 extended96; -typedef SInt8 VHSelect; - - -EXTERN_API( void ) -DebugStr (ConstStr255Param debuggerMsg); - -/********************************************************************************* - - Added types for HFSPlus MacOS X functionality. Needs to be incorporated to - other places - -*********************************************************************************/ - - typedef struct vnode* FileReference; - #define kNoFileReference NULL - - -#define HFSInstrumentation 0 - - -/***** START OF MACOSSTUBS ********/ - - -/* - SizeTDef.h -- Common definitions - - size_t - this type is defined by several ANSI headers. -*/ -#if ! defined (__size_t__) - #define __size_t__ - #if defined (__xlc) || defined (__xlC) || defined (__xlC__) || defined (__MWERKS__) - typedef unsigned long size_t; - #else /* __xlC */ - typedef unsigned int size_t; - #endif /* __xlC */ -#endif /* __size_t__ */ - - -/* - StdDef.h -- Common definitions - -*/ - -#define offsetof(structure,field) ((size_t)&((structure *) 0)->field) - - - -/* - File: Errors.h - -*/ -enum { - paramErr = -50, /*error in user parameter list*/ - noHardwareErr = -200, /*Sound Manager Error Returns*/ - notEnoughHardwareErr = -201, /*Sound Manager Error Returns*/ - userCanceledErr = -128, - qErr = -1, /*queue element not found during deletion*/ - vTypErr = -2, /*invalid queue element*/ - corErr = -3, /*core routine number out of range*/ - unimpErr = -4, /*unimplemented core routine*/ - SlpTypeErr = -5, /*invalid queue element*/ - seNoDB = -8, /*no debugger installed to handle debugger command*/ - controlErr = -17, /*I/O System Errors*/ - statusErr = -18, /*I/O System Errors*/ - readErr = -19, /*I/O System Errors*/ - writErr = -20, /*I/O System Errors*/ - badUnitErr = -21, /*I/O System Errors*/ - unitEmptyErr = -22, /*I/O System Errors*/ - openErr = -23, /*I/O System Errors*/ - closErr = -24, /*I/O System Errors*/ - dRemovErr = -25, /*tried to remove an open driver*/ - dInstErr = -26 /*DrvrInstall couldn't find driver in resources*/ -}; - -enum { /* Printing Errors */ - iMemFullErr = -108, - iIOAbort = -27, /*Scrap Manager errors*/ - noScrapErr = -100, /*No scrap exists error*/ - noTypeErr = -102, /*No object of that type in scrap*/ - memROZWarn = -99, /*soft error in ROZ*/ - memROZError = -99, /*hard error in ROZ*/ - memROZErr = -99, /*hard error in ROZ*/ - memFullErr = -108, /*Not enough room in heap zone*/ - nilHandleErr = -109, /*Master Pointer was NIL in HandleZone or other*/ - memWZErr = -111, /*WhichZone failed (applied to free block)*/ - memPurErr = -112, /*trying to purge a locked or non-purgeable block*/ - memAdrErr = -110 /*address was odd; or out of range*/ -}; - - - -enum { - abortErr = -27, /*IO call aborted by KillIO*/ - iIOAbortErr = -27, /*IO abort error (Printing Manager)*/ - notOpenErr = -28, /*Couldn't rd/wr/ctl/sts cause driver not opened*/ - unitTblFullErr = -29, /*unit table has no more entries*/ - dceExtErr = -30, /*dce extension error*/ - slotNumErr = -360, /*invalid slot # error*/ - gcrOnMFMErr = -400, /*gcr format on high density media error*/ - dirFulErr = -33, /*Directory full*/ - dskFulErr = -34, /*disk full*/ - nsvErr = -35, /*no such volume*/ - ioErr = -36, /*I/O error (bummers)*/ - bdNamErr = -37, /*there may be no bad names in the final system!*/ - fnOpnErr = -38, /*File not open*/ - eofErr = -39, /*End of file*/ - posErr = -40, /*tried to position to before start of file (r/w)*/ - mFulErr = -41, /*memory full (open) or file won't fit (load)*/ - tmfoErr = -42, /*too many files open*/ - fnfErr = -43, /*File not found*/ - wPrErr = -44, /*diskette is write protected.*/ - fLckdErr = -45 /*file is locked*/ -}; - - -enum { - vLckdErr = -46, /*volume is locked*/ - fBsyErr = -47, /*File is busy (delete)*/ - dupFNErr = -48, /*duplicate filename (rename)*/ - opWrErr = -49, /*file already open with with write permission*/ - rfNumErr = -51, /*refnum error*/ - gfpErr = -52, /*get file position error*/ - volOffLinErr = -53, /*volume not on line error (was Ejected)*/ - permErr = -54, /*permissions error (on file open)*/ - volOnLinErr = -55, /*drive volume already on-line at MountVol*/ - nsDrvErr = -56, /*no such drive (tried to mount a bad drive num)*/ - noMacDskErr = -57, /*not a mac diskette (sig bytes are wrong)*/ - extFSErr = -58, /*volume in question belongs to an external fs*/ - fsRnErr = -59, /*file system internal error:during rename the old entry was deleted but could not be restored.*/ - badMDBErr = -60, /*bad master directory block*/ - wrPermErr = -61, /*write permissions error*/ - dirNFErr = -120, /*Directory not found*/ - tmwdoErr = -121, /*No free WDCB available*/ - badMovErr = -122, /*Move into offspring error*/ - wrgVolTypErr = -123, /*Wrong volume type error [operation not supported for MFS]*/ - volGoneErr = -124 /*Server volume has been disconnected.*/ -}; - -enum { - /*Dictionary Manager errors*/ - notBTree = -410, /*The file is not a dictionary.*/ - btNoSpace = -413, /*Can't allocate disk space.*/ - btDupRecErr = -414, /*Record already exists.*/ - btRecNotFnd = -415, /*Record cannot be found.*/ - btKeyLenErr = -416, /*Maximum key length is too long or equal to zero.*/ - btKeyAttrErr = -417, /*There is no such a key attribute.*/ - unknownInsertModeErr = -20000, /*There is no such an insert mode.*/ - recordDataTooBigErr = -20001, /*The record data is bigger than buffer size (1024 bytes).*/ - invalidIndexErr = -20002 /*The recordIndex parameter is not valid.*/ -}; - - -enum { - fidNotFound = -1300, /*no file thread exists.*/ - fidExists = -1301, /*file id already exists*/ - notAFileErr = -1302, /*directory specified*/ - diffVolErr = -1303, /*files on different volumes*/ - catChangedErr = -1304, /*the catalog has been modified*/ - desktopDamagedErr = -1305, /*desktop database files are corrupted*/ - sameFileErr = -1306, /*can't exchange a file with itself*/ - badFidErr = -1307, /*file id is dangling or doesn't match with the file number*/ - notARemountErr = -1308, /*when _Mount allows only remounts and doesn't get one*/ - fileBoundsErr = -1309, /*file's EOF, offset, mark or size is too big*/ - fsDataTooBigErr = -1310, /*file or volume is too big for system*/ - volVMBusyErr = -1311, /*can't eject because volume is in use by VM*/ - envNotPresent = -5500, /*returned by glue.*/ - envBadVers = -5501, /*Version non-positive*/ - envVersTooBig = -5502, /*Version bigger than call can handle*/ - fontDecError = -64, /*error during font declaration*/ - fontNotDeclared = -65, /*font not declared*/ - fontSubErr = -66, /*font substitution occured*/ - fontNotOutlineErr = -32615, /*bitmap font passed to routine that does outlines only*/ - firstDskErr = -84, /*I/O System Errors*/ - lastDskErr = -64, /*I/O System Errors*/ - noDriveErr = -64, /*drive not installed*/ - offLinErr = -65, /*r/w requested for an off-line drive*/ - noNybErr = -66 /*couldn't find 5 nybbles in 200 tries*/ -}; - -enum { - /* general text errors*/ - kTextUnsupportedEncodingErr = -8738, /* specified encoding not supported for this operation*/ - kTextMalformedInputErr = -8739, /* in DBCS, for example, high byte followed by invalid low byte*/ - kTextUndefinedElementErr = -8740, /* text conversion errors*/ - kTECMissingTableErr = -8745, - kTECTableChecksumErr = -8746, - kTECTableFormatErr = -8747, - kTECCorruptConverterErr = -8748, /* invalid converter object reference*/ - kTECNoConversionPathErr = -8749, - kTECBufferBelowMinimumSizeErr = -8750, /* output buffer too small to allow processing of first input text element*/ - kTECArrayFullErr = -8751, /* supplied name buffer or TextRun, TextEncoding, or UnicodeMapping array is too small*/ - kTECBadTextRunErr = -8752, - kTECPartialCharErr = -8753, /* input buffer ends in the middle of a multibyte character, conversion stopped*/ - kTECUnmappableElementErr = -8754, - kTECIncompleteElementErr = -8755, /* text element may be incomplete or is too long for internal buffers*/ - kTECDirectionErr = -8756, /* direction stack overflow, etc.*/ - kTECGlobalsUnavailableErr = -8770, /* globals have already been deallocated (premature TERM)*/ - kTECItemUnavailableErr = -8771, /* item (e.g. name) not available for specified region (& encoding if relevant)*/ - /* text conversion status codes*/ - kTECUsedFallbacksStatus = -8783, - kTECNeedFlushStatus = -8784, - kTECOutputBufferFullStatus = -8785, /* output buffer has no room for conversion of next input text element (partial conversion)*/ - /* deprecated error & status codes for low-level converter*/ - unicodeChecksumErr = -8769, - unicodeNoTableErr = -8768, - unicodeVariantErr = -8767, - unicodeFallbacksErr = -8766, - unicodePartConvertErr = -8765, - unicodeBufErr = -8764, - unicodeCharErr = -8763, - unicodeElementErr = -8762, - unicodeNotFoundErr = -8761, - unicodeTableFormatErr = -8760, - unicodeDirectionErr = -8759, - unicodeContextualErr = -8758, - unicodeTextEncodingDataErr = -8757 -}; - - -/* - File: MacMemory.h - - -*/ - - -/* - File: MixedMode.h - -*/ - -/* Calling Conventions */ -typedef unsigned short CallingConventionType; - -enum { - kPascalStackBased = 0, - kCStackBased = 1, - kRegisterBased = 2, - kD0DispatchedPascalStackBased = 8, - kD1DispatchedPascalStackBased = 12, - kD0DispatchedCStackBased = 9, - kStackDispatchedPascalStackBased = 14, - kThinkCStackBased = 5 -}; - - - #define STACK_UPP_TYPE(name) name - #define REGISTER_UPP_TYPE(name) name - - -/* - File: OSUtils.h - -*/ -typedef struct QElem QElem; - -typedef QElem * QElemPtr; -struct QHdr { - short qFlags; - QElemPtr qHead; - QElemPtr qTail; -}; -typedef struct QHdr QHdr; - -typedef QHdr * QHdrPtr; - -typedef CALLBACK_API( void , DeferredTaskProcPtr )(long dtParam); -/* - WARNING: DeferredTaskProcPtr uses register based parameters under classic 68k - and cannot be written in a high-level language without - the help of mixed mode or assembly glue. -*/ -typedef REGISTER_UPP_TYPE(DeferredTaskProcPtr) DeferredTaskUPP; -enum { uppDeferredTaskProcInfo = 0x0000B802 }; /* register no_return_value Func(4_bytes:A1) */ -#define NewDeferredTaskProc(userRoutine) (DeferredTaskUPP)NewRoutineDescriptor((ProcPtr)(userRoutine), uppDeferredTaskProcInfo, GetCurrentArchitecture()) -#define CallDeferredTaskProc(userRoutine, dtParam) CALL_ONE_PARAMETER_UPP((userRoutine), uppDeferredTaskProcInfo, (dtParam)) -struct DeferredTask { - QElemPtr qLink; - short qType; - short dtFlags; - DeferredTaskUPP dtAddr; - long dtParam; - long dtReserved; -}; -typedef struct DeferredTask DeferredTask; - -typedef DeferredTask * DeferredTaskPtr; - -/* - File: Finder.h - - -*/ - -/* - The following declerations used to be in Files.‰, - but are Finder specific and were moved here. -*/ - -enum { - /* Finder Flags */ - kIsOnDesk = 0x0001, - kColor = 0x000E, - kIsShared = 0x0040, /* bit 0x0080 is hasNoINITS */ - kHasBeenInited = 0x0100, /* bit 0x0200 was the letter bit for AOCE, but is now reserved for future use */ - kHasCustomIcon = 0x0400, - kIsStationery = 0x0800, - kNameLocked = 0x1000, - kHasBundle = 0x2000, - kIsInvisible = 0x4000, - kIsAlias = 0x8000 -}; - - -enum { - /* Finder Constants */ - fOnDesk = 1, - fHasBundle = 8192, - fTrash = -3, - fDesktop = -2, - fDisk = 0 -}; - -#if PRAGMA_STRUCT_ALIGN - #pragma options align=mac68k -#elif PRAGMA_STRUCT_PACKPUSH - #pragma pack(push, 2) -#elif PRAGMA_STRUCT_PACK - #pragma pack(2) -#endif - - -struct FInfo { - OSType fdType; /*the type of the file*/ - OSType fdCreator; /*file's creator*/ - unsigned short fdFlags; /*flags ex. hasbundle,invisible,locked, etc.*/ - Point fdLocation; /*file's location in folder*/ - short fdFldr; /*folder containing file*/ -}; -typedef struct FInfo FInfo; - -struct FXInfo { - short fdIconID; /*Icon ID*/ - short fdUnused[3]; /*unused but reserved 6 bytes*/ - SInt8 fdScript; /*Script flag and number*/ - SInt8 fdXFlags; /*More flag bits*/ - short fdComment; /*Comment ID*/ - long fdPutAway; /*Home Dir ID*/ -}; -typedef struct FXInfo FXInfo; - -struct DInfo { - Rect frRect; /*folder rect*/ - unsigned short frFlags; /*Flags*/ - Point frLocation; /*folder location*/ - short frView; /*folder view*/ -}; -typedef struct DInfo DInfo; - -struct DXInfo { - Point frScroll; /*scroll position*/ - long frOpenChain; /*DirID chain of open folders*/ - SInt8 frScript; /*Script flag and number*/ - SInt8 frXFlags; /*More flag bits*/ - short frComment; /*comment*/ - long frPutAway; /*DirID*/ -}; -typedef struct DXInfo DXInfo; - -#if PRAGMA_STRUCT_ALIGN - #pragma options align=reset -#elif PRAGMA_STRUCT_PACKPUSH - #pragma pack(pop) -#elif PRAGMA_STRUCT_PACK - #pragma pack() -#endif - - -enum { - fsRtParID = 1, - fsRtDirID = 2 -}; - - - -#if PRAGMA_STRUCT_ALIGN - #pragma options align=mac68k -#elif PRAGMA_STRUCT_PACKPUSH - #pragma pack(push, 2) -#elif PRAGMA_STRUCT_PACK - #pragma pack(2) -#endif - - -#if PRAGMA_STRUCT_ALIGN - #pragma options align=reset -#elif PRAGMA_STRUCT_PACKPUSH - #pragma pack(pop) -#elif PRAGMA_STRUCT_PACK - #pragma pack() -#endif - - -/* - * UTGetBlock options - */ - -enum { - gbDefault = 0, /* default value - read if not found */ - /* bits and masks */ - gbReadBit = 0, /* read block from disk (forced read) */ - gbReadMask = 0x0001, - gbExistBit = 1, /* get existing cache block */ - gbExistMask = 0x0002, - gbNoReadBit = 2, /* don't read block from disk if not found in cache */ - gbNoReadMask = 0x0004, - gbReleaseBit = 3, /* release block immediately after GetBlock */ - gbReleaseMask = 0x0008 -}; - - -/* - * UTReleaseBlock options - */ - -enum { - rbDefault = 0, /* default value - just mark the buffer not in-use */ - /* bits and masks */ - rbWriteBit = 0, /* force write buffer to disk */ - rbWriteMask = 0x0001, - rbTrashBit = 1, /* trash buffer contents after release */ - rbTrashMask = 0x0002, - rbDirtyBit = 2, /* mark buffer dirty */ - rbDirtyMask = 0x0004, - rbFreeBit = 3, /* free the buffer (save in the hash) */ - rbFreeMask = 0x000A /* rbFreeMask (rbFreeBit + rbTrashBit) works as rbTrash on < System 7.0 RamCache; on >= System 7.0, rbfreeMask overrides rbTrash */ -}; - -/* - * UTFlushCache options - */ - -enum { - fcDefault = 0, /* default value - pass this fcOption to just flush any dirty buffers */ - /* bits and masks */ - fcTrashBit = 0, /* (don't pass this as fcOption, use only for testing bit) */ - fcTrashMask = 0x0001, /* pass this fcOption value to flush and trash cache blocks */ - fcFreeBit = 1, /* (don't pass this as fcOption, use only for testing bit) */ - fcFreeMask = 0x0003 /* pass this fcOption to flush and free cache blocks (Note: both fcTrash and fcFree bits are set) */ -}; - - - -/* - * FCBRec.fcbFlags bits - */ - -enum { - fcbWriteBit = 0, /* Data can be written to this file */ - fcbWriteMask = 0x01, - fcbResourceBit = 1, /* This file is a resource fork */ - fcbResourceMask = 0x02, - fcbWriteLockedBit = 2, /* File has a locked byte range */ - fcbWriteLockedMask = 0x04, - fcbSharedWriteBit = 4, /* File is open for shared write access */ - fcbSharedWriteMask = 0x10, - fcbFileLockedBit = 5, /* File is locked (write-protected) */ - fcbFileLockedMask = 0x20, - fcbOwnClumpBit = 6, /* File has clump size specified in FCB */ - fcbOwnClumpMask = 0x40, - fcbModifiedBit = 7, /* File has changed since it was last flushed */ - fcbModifiedMask = 0x80 -}; - - -/* - File: TextCommon.h - -*/ - -/* LocaleIdentifier is an obsolete Copland typedef, will be removed soon*/ -typedef UInt32 LocaleIdentifier; -/* TextEncodingBase type & values */ -/* (values 0-32 correspond to the Script Codes defined in Inside Macintosh: Text pages 6-52 and 6-53 */ -typedef UInt32 TextEncodingBase; - -enum { - /* Mac OS encodings*/ - kTextEncodingMacRoman = 0L, - kTextEncodingMacJapanese = 1, - kTextEncodingMacChineseTrad = 2, - kTextEncodingMacKorean = 3, - kTextEncodingMacArabic = 4, - kTextEncodingMacHebrew = 5, - kTextEncodingMacGreek = 6, - kTextEncodingMacCyrillic = 7, - kTextEncodingMacDevanagari = 9, - kTextEncodingMacGurmukhi = 10, - kTextEncodingMacGujarati = 11, - kTextEncodingMacOriya = 12, - kTextEncodingMacBengali = 13, - kTextEncodingMacTamil = 14, - kTextEncodingMacTelugu = 15, - kTextEncodingMacKannada = 16, - kTextEncodingMacMalayalam = 17, - kTextEncodingMacSinhalese = 18, - kTextEncodingMacBurmese = 19, - kTextEncodingMacKhmer = 20, - kTextEncodingMacThai = 21, - kTextEncodingMacLaotian = 22, - kTextEncodingMacGeorgian = 23, - kTextEncodingMacArmenian = 24, - kTextEncodingMacChineseSimp = 25, - kTextEncodingMacTibetan = 26, - kTextEncodingMacMongolian = 27, - kTextEncodingMacEthiopic = 28, - kTextEncodingMacCentralEurRoman = 29, - kTextEncodingMacVietnamese = 30, - kTextEncodingMacExtArabic = 31, /* The following use script code 0, smRoman*/ - kTextEncodingMacSymbol = 33, - kTextEncodingMacDingbats = 34, - kTextEncodingMacTurkish = 35, - kTextEncodingMacCroatian = 36, - kTextEncodingMacIcelandic = 37, - kTextEncodingMacRomanian = 38, /* The following use script code 4, smArabic*/ - kTextEncodingMacFarsi = 0x8C, /* Like MacArabic but uses Farsi digits*/ - /* The following use script code 7, smCyrillic*/ - kTextEncodingMacUkrainian = 0x98, /* The following use script code 32, smUnimplemented*/ - kTextEncodingMacVT100 = 0xFC, /* VT100/102 font from Comm Toolbox: Latin-1 repertoire + box drawing etc*/ - /* Special Mac OS encodings*/ - kTextEncodingMacHFS = 0xFF, /* Meta-value, should never appear in a table.*/ - /* Unicode & ISO UCS encodings begin at 0x100*/ - kTextEncodingUnicodeDefault = 0x0100, /* Meta-value, should never appear in a table.*/ - kTextEncodingUnicodeV1_1 = 0x0101, - kTextEncodingISO10646_1993 = 0x0101, /* Code points identical to Unicode 1.1*/ - kTextEncodingUnicodeV2_0 = 0x0103, /* New location for Korean Hangul*/ - /* ISO 8-bit and 7-bit encodings begin at 0x200*/ - kTextEncodingISOLatin1 = 0x0201, /* ISO 8859-1*/ - kTextEncodingISOLatin2 = 0x0202, /* ISO 8859-2*/ - kTextEncodingISOLatinCyrillic = 0x0205, /* ISO 8859-5*/ - kTextEncodingISOLatinArabic = 0x0206, /* ISO 8859-6, = ASMO 708, =DOS CP 708*/ - kTextEncodingISOLatinGreek = 0x0207, /* ISO 8859-7*/ - kTextEncodingISOLatinHebrew = 0x0208, /* ISO 8859-8*/ - kTextEncodingISOLatin5 = 0x0209, /* ISO 8859-9*/ - /* MS-DOS & Windows encodings begin at 0x400*/ - kTextEncodingDOSLatinUS = 0x0400, /* code page 437*/ - kTextEncodingDOSGreek = 0x0405, /* code page 737 (formerly code page 437G)*/ - kTextEncodingDOSBalticRim = 0x0406, /* code page 775*/ - kTextEncodingDOSLatin1 = 0x0410, /* code page 850, "Multilingual"*/ - kTextEncodingDOSGreek1 = 0x0411, /* code page 851*/ - kTextEncodingDOSLatin2 = 0x0412, /* code page 852, Slavic*/ - kTextEncodingDOSCyrillic = 0x0413, /* code page 855, IBM Cyrillic*/ - kTextEncodingDOSTurkish = 0x0414, /* code page 857, IBM Turkish*/ - kTextEncodingDOSPortuguese = 0x0415, /* code page 860*/ - kTextEncodingDOSIcelandic = 0x0416, /* code page 861*/ - kTextEncodingDOSHebrew = 0x0417, /* code page 862*/ - kTextEncodingDOSCanadianFrench = 0x0418, /* code page 863*/ - kTextEncodingDOSArabic = 0x0419, /* code page 864*/ - kTextEncodingDOSNordic = 0x041A, /* code page 865*/ - kTextEncodingDOSRussian = 0x041B, /* code page 866*/ - kTextEncodingDOSGreek2 = 0x041C, /* code page 869, IBM Modern Greek*/ - kTextEncodingDOSThai = 0x041D, /* code page 874, also for Windows*/ - kTextEncodingDOSJapanese = 0x0420, /* code page 932, also for Windows*/ - kTextEncodingDOSChineseSimplif = 0x0421, /* code page 936, also for Windows*/ - kTextEncodingDOSKorean = 0x0422, /* code page 949, also for Windows; Unified Hangul Code*/ - kTextEncodingDOSChineseTrad = 0x0423, /* code page 950, also for Windows*/ - kTextEncodingWindowsLatin1 = 0x0500, /* code page 1252*/ - kTextEncodingWindowsANSI = 0x0500, /* code page 1252 (alternate name)*/ - kTextEncodingWindowsLatin2 = 0x0501, /* code page 1250, Central Europe*/ - kTextEncodingWindowsCyrillic = 0x0502, /* code page 1251, Slavic Cyrillic*/ - kTextEncodingWindowsGreek = 0x0503, /* code page 1253*/ - kTextEncodingWindowsLatin5 = 0x0504, /* code page 1254, Turkish*/ - kTextEncodingWindowsHebrew = 0x0505, /* code page 1255*/ - kTextEncodingWindowsArabic = 0x0506, /* code page 1256*/ - kTextEncodingWindowsBalticRim = 0x0507, /* code page 1257*/ - kTextEncodingWindowsKoreanJohab = 0x0510, /* code page 1361, for Windows NT*/ - /* Various national standards begin at 0x600*/ - kTextEncodingUS_ASCII = 0x0600, - kTextEncodingJIS_X0201_76 = 0x0620, - kTextEncodingJIS_X0208_83 = 0x0621, - kTextEncodingJIS_X0208_90 = 0x0622, - kTextEncodingJIS_X0212_90 = 0x0623, - kTextEncodingJIS_C6226_78 = 0x0624, - kTextEncodingGB_2312_80 = 0x0630, - kTextEncodingGBK_95 = 0x0631, /* annex to GB 13000-93; for Windows 95*/ - kTextEncodingKSC_5601_87 = 0x0640, /* same as KSC 5601-92 without Johab annex*/ - kTextEncodingKSC_5601_92_Johab = 0x0641, /* KSC 5601-92 Johab annex*/ - kTextEncodingCNS_11643_92_P1 = 0x0651, /* CNS 11643-1992 plane 1*/ - kTextEncodingCNS_11643_92_P2 = 0x0652, /* CNS 11643-1992 plane 2*/ - kTextEncodingCNS_11643_92_P3 = 0x0653, /* CNS 11643-1992 plane 3 (was plane 14 in 1986 version)*/ - /* ISO 2022 collections begin at 0x800*/ - kTextEncodingISO_2022_JP = 0x0820, - kTextEncodingISO_2022_JP_2 = 0x0821, - kTextEncodingISO_2022_CN = 0x0830, - kTextEncodingISO_2022_CN_EXT = 0x0831, - kTextEncodingISO_2022_KR = 0x0840, /* EUC collections begin at 0x900*/ - kTextEncodingEUC_JP = 0x0920, /* ISO 646, 1-byte katakana, JIS 208, JIS 212*/ - kTextEncodingEUC_CN = 0x0930, /* ISO 646, GB 2312-80*/ - kTextEncodingEUC_TW = 0x0931, /* ISO 646, CNS 11643-1992 Planes 1-16*/ - kTextEncodingEUC_KR = 0x0940, /* ISO 646, KS C 5601-1987*/ - /* Misc standards begin at 0xA00*/ - kTextEncodingShiftJIS = 0x0A01, /* plain Shift-JIS*/ - kTextEncodingKOI8_R = 0x0A02, /* Russian internet standard*/ - kTextEncodingBig5 = 0x0A03, /* Big-5 (has variants)*/ - kTextEncodingMacRomanLatin1 = 0x0A04, /* Mac OS Roman permuted to align with ISO Latin-1*/ - kTextEncodingHZ_GB_2312 = 0x0A05, /* HZ (RFC 1842, for Chinese mail & news)*/ - /* Other platform encodings*/ - kTextEncodingNextStepLatin = 0x0B01, /* NextStep encoding*/ - /* EBCDIC & IBM host encodings begin at 0xC00*/ - kTextEncodingEBCDIC_US = 0x0C01, /* basic EBCDIC-US*/ - kTextEncodingEBCDIC_CP037 = 0x0C02, /* code page 037, extended EBCDIC (Latin-1 set) for US,Canada...*/ - /* Special value*/ - kTextEncodingMultiRun = 0x0FFF, /* Multi-encoding text with external run info*/ - /* The following are older names for backward compatibility*/ - kTextEncodingMacTradChinese = 2, - kTextEncodingMacRSymbol = 8, - kTextEncodingMacSimpChinese = 25, - kTextEncodingMacGeez = 28, - kTextEncodingMacEastEurRoman = 29, - kTextEncodingMacUninterp = 32 -}; - -/* TextEncodingVariant type & values */ -typedef UInt32 TextEncodingVariant; - -enum { - /* Default TextEncodingVariant, for any TextEncodingBase*/ - kTextEncodingDefaultVariant = 0, /* Variants of kTextEncodingMacIcelandic */ - kMacIcelandicStandardVariant = 0, /* 0xBB & 0xBC are fem./masc. ordinal indicators*/ - kMacIcelandicTrueTypeVariant = 1, /* 0xBB & 0xBC are fi/fl ligatures*/ - /* Variants of kTextEncodingMacJapanese*/ - kMacJapaneseStandardVariant = 0, - kMacJapaneseStdNoVerticalsVariant = 1, - kMacJapaneseBasicVariant = 2, - kMacJapanesePostScriptScrnVariant = 3, - kMacJapanesePostScriptPrintVariant = 4, - kMacJapaneseVertAtKuPlusTenVariant = 5, /* Variant options for most Japanese encodings (MacJapanese, ShiftJIS, EUC-JP, ISO 2022-JP) */ - /* These can be OR-ed into the variant value in any combination*/ - kJapaneseNoOneByteKanaOption = 0x20, - kJapaneseUseAsciiBackslashOption = 0x40, /* Variants of kTextEncodingMacArabic*/ - kMacArabicStandardVariant = 0, /* 0xC0 is 8-spoke asterisk, 0x2A & 0xAA are asterisk (e.g. Cairo)*/ - kMacArabicTrueTypeVariant = 1, /* 0xC0 is asterisk, 0x2A & 0xAA are multiply signs (e.g. Baghdad)*/ - kMacArabicThuluthVariant = 2, /* 0xC0 is Arabic five-point star, 0x2A & 0xAA are multiply signs*/ - kMacArabicAlBayanVariant = 3, /* 8-spoke asterisk, multiply sign, Koranic ligatures & parens*/ - /* Variants of kTextEncodingMacFarsi*/ - kMacFarsiStandardVariant = 0, /* 0xC0 is 8-spoke asterisk, 0x2A & 0xAA are asterisk (e.g. Tehran)*/ - kMacFarsiTrueTypeVariant = 1, /* asterisk, multiply signs, Koranic ligatures, geometric shapes*/ - /* Variants of kTextEncodingMacHebrew*/ - kMacHebrewStandardVariant = 0, - kMacHebrewFigureSpaceVariant = 1, /* Variants of Unicode & ISO 10646 encodings*/ - kUnicodeNoSubset = 0, - kUnicodeNoCompatibilityVariant = 1, - kUnicodeMaxDecomposedVariant = 2, - kUnicodeNoComposedVariant = 3, - kUnicodeNoCorporateVariant = 4, /* Variants of Big-5 encoding*/ - kBig5_BasicVariant = 0, - kBig5_StandardVariant = 1, /* 0xC6A1-0xC7FC: kana, Cyrillic, enclosed numerics*/ - kBig5_ETenVariant = 2, /* adds kana, Cyrillic, radicals, etc with hi bytes C6-C8,F9*/ - /* The following are older names for backward compatibility*/ - kJapaneseStandardVariant = 0, - kJapaneseStdNoVerticalsVariant = 1, - kJapaneseBasicVariant = 2, - kJapanesePostScriptScrnVariant = 3, - kJapanesePostScriptPrintVariant = 4, - kJapaneseVertAtKuPlusTenVariant = 5, /* kJapaneseStdNoOneByteKanaVariant = 6, // replaced by kJapaneseNoOneByteKanaOption*/ - /* kJapaneseBasicNoOneByteKanaVariant = 7, // replaced by kJapaneseNoOneByteKanaOption */ - kHebrewStandardVariant = 0, - kHebrewFigureSpaceVariant = 1 -}; - -/* TextEncodingFormat type & values */ -typedef UInt32 TextEncodingFormat; - -enum { - /* Default TextEncodingFormat for any TextEncodingBase*/ - kTextEncodingDefaultFormat = 0, /* Formats for Unicode & ISO 10646*/ - kUnicode16BitFormat = 0, - kUnicodeUTF7Format = 1, - kUnicodeUTF8Format = 2, - kUnicode32BitFormat = 3 -}; - -/* TextEncoding type */ -typedef UInt32 TextEncoding; -/* name part selector for GetTextEncodingName*/ -typedef UInt32 TextEncodingNameSelector; - -enum { - kTextEncodingFullName = 0, - kTextEncodingBaseName = 1, - kTextEncodingVariantName = 2, - kTextEncodingFormatName = 3 -}; - -/* Types used in conversion */ -struct TextEncodingRun { - ByteOffset offset; - TextEncoding textEncoding; -}; -typedef struct TextEncodingRun TextEncodingRun; - -typedef TextEncodingRun * TextEncodingRunPtr; -typedef const TextEncodingRun * ConstTextEncodingRunPtr; -struct ScriptCodeRun { - ByteOffset offset; - ScriptCode script; -}; -typedef struct ScriptCodeRun ScriptCodeRun; - -typedef ScriptCodeRun * ScriptCodeRunPtr; -typedef const ScriptCodeRun * ConstScriptCodeRunPtr; -typedef UInt8 * TextPtr; -typedef const UInt8 * ConstTextPtr; -/* Basic types for Unicode characters and strings: */ -typedef UniChar * UniCharArrayPtr; -typedef const UniChar * ConstUniCharArrayPtr; -/* enums for TextEncoding Conversion routines*/ - -enum { - kTextScriptDontCare = -128, - kTextLanguageDontCare = -128, - kTextRegionDontCare = -128 -}; - - - -/* - File: UnicodeConverter.h - - -*/ - -/* Unicode conversion contexts: */ -typedef struct OpaqueTextToUnicodeInfo* TextToUnicodeInfo; -typedef struct OpaqueUnicodeToTextInfo* UnicodeToTextInfo; -typedef struct OpaqueUnicodeToTextRunInfo* UnicodeToTextRunInfo; -typedef const TextToUnicodeInfo ConstTextToUnicodeInfo; -typedef const UnicodeToTextInfo ConstUnicodeToTextInfo; -/* UnicodeMapVersion type & values */ -typedef SInt32 UnicodeMapVersion; - -enum { - kUnicodeUseLatestMapping = -1, - kUnicodeUseHFSPlusMapping = 4 -}; - -/* Types used in conversion */ -struct UnicodeMapping { - TextEncoding unicodeEncoding; - TextEncoding otherEncoding; - UnicodeMapVersion mappingVersion; -}; -typedef struct UnicodeMapping UnicodeMapping; - -typedef UnicodeMapping * UnicodeMappingPtr; -typedef const UnicodeMapping * ConstUnicodeMappingPtr; -/* Control flags for ConvertFromUnicodeToText and ConvertFromTextToUnicode */ - -enum { - kUnicodeUseFallbacksBit = 0, - kUnicodeKeepInfoBit = 1, - kUnicodeDirectionalityBits = 2, - kUnicodeVerticalFormBit = 4, - kUnicodeLooseMappingsBit = 5, - kUnicodeStringUnterminatedBit = 6, - kUnicodeTextRunBit = 7, - kUnicodeKeepSameEncodingBit = 8 -}; - - -enum { - kUnicodeUseFallbacksMask = 1L << kUnicodeUseFallbacksBit, - kUnicodeKeepInfoMask = 1L << kUnicodeKeepInfoBit, - kUnicodeDirectionalityMask = 3L << kUnicodeDirectionalityBits, - kUnicodeVerticalFormMask = 1L << kUnicodeVerticalFormBit, - kUnicodeLooseMappingsMask = 1L << kUnicodeLooseMappingsBit, - kUnicodeStringUnterminatedMask = 1L << kUnicodeStringUnterminatedBit, - kUnicodeTextRunMask = 1L << kUnicodeTextRunBit, - kUnicodeKeepSameEncodingMask = 1L << kUnicodeKeepSameEncodingBit -}; - -/* Values for kUnicodeDirectionality field */ - -enum { - kUnicodeDefaultDirection = 0, - kUnicodeLeftToRight = 1, - kUnicodeRightToLeft = 2 -}; - -/* Directionality masks for control flags */ - -enum { - kUnicodeDefaultDirectionMask = kUnicodeDefaultDirection << kUnicodeDirectionalityBits, - kUnicodeLeftToRightMask = kUnicodeLeftToRight << kUnicodeDirectionalityBits, - kUnicodeRightToLeftMask = kUnicodeRightToLeft << kUnicodeDirectionalityBits -}; - -/* Control flags for TruncateForUnicodeToText: */ -/* - Now TruncateForUnicodeToText uses control flags from the same set as used by - ConvertFromTextToUnicode, ConvertFromUnicodeToText, etc., but only - kUnicodeStringUnterminatedMask is meaningful for TruncateForUnicodeToText. - - Previously two special control flags were defined for TruncateForUnicodeToText: - kUnicodeTextElementSafeBit = 0 - kUnicodeRestartSafeBit = 1 - However, neither of these was implemented. - Instead of implementing kUnicodeTextElementSafeBit, we now use - kUnicodeStringUnterminatedMask since it accomplishes the same thing and avoids - having special flags just for TruncateForUnicodeToText - Also, kUnicodeRestartSafeBit is unnecessary, since restart-safeness is handled by - setting kUnicodeKeepInfoBit with ConvertFromUnicodeToText. - If TruncateForUnicodeToText is called with one or both of the old special control - flags set (bits 0 or 1), it will not generate a paramErr, but the old bits have no - effect on its operation. -*/ - -/* Filter bits for filter field in QueryUnicodeMappings and CountUnicodeMappings: */ - -enum { - kUnicodeMatchUnicodeBaseBit = 0, - kUnicodeMatchUnicodeVariantBit = 1, - kUnicodeMatchUnicodeFormatBit = 2, - kUnicodeMatchOtherBaseBit = 3, - kUnicodeMatchOtherVariantBit = 4, - kUnicodeMatchOtherFormatBit = 5 -}; - - -enum { - kUnicodeMatchUnicodeBaseMask = 1L << kUnicodeMatchUnicodeBaseBit, - kUnicodeMatchUnicodeVariantMask = 1L << kUnicodeMatchUnicodeVariantBit, - kUnicodeMatchUnicodeFormatMask = 1L << kUnicodeMatchUnicodeFormatBit, - kUnicodeMatchOtherBaseMask = 1L << kUnicodeMatchOtherBaseBit, - kUnicodeMatchOtherVariantMask = 1L << kUnicodeMatchOtherVariantBit, - kUnicodeMatchOtherFormatMask = 1L << kUnicodeMatchOtherFormatBit -}; - -/* Control flags for SetFallbackUnicodeToText */ - -enum { - kUnicodeFallbackSequencingBits = 0 -}; - - -enum { - kUnicodeFallbackSequencingMask = 3L << kUnicodeFallbackSequencingBits -}; - -/* values for kUnicodeFallbackSequencing field */ - -enum { - kUnicodeFallbackDefaultOnly = 0L, - kUnicodeFallbackCustomOnly = 1L, - kUnicodeFallbackDefaultFirst = 2L, - kUnicodeFallbackCustomFirst = 3L -}; - - - -/* - File: Timer.h - - -*/ - - -enum { - /* high bit of qType is set if task is active */ - kTMTaskActive = (1L << 15) -}; - -typedef struct TMTask TMTask; -typedef TMTask * TMTaskPtr; -typedef CALLBACK_API( void , TimerProcPtr )(TMTaskPtr tmTaskPtr); -/* - WARNING: TimerProcPtr uses register based parameters under classic 68k - and cannot be written in a high-level language without - the help of mixed mode or assembly glue. -*/ -typedef REGISTER_UPP_TYPE(TimerProcPtr) TimerUPP; -struct TMTask { - QElemPtr qLink; - short qType; - TimerUPP tmAddr; - long tmCount; - long tmWakeUp; - long tmReserved; -}; - - -/* - File: TextCommonPriv.h - - -*/ - - -/* - ----------------------------------------------------------------------------------------------------------- - TextEncoding creation & extraction macros. - Current packed format: - 31 30 29 26 25 16 15 0 - |pack| format | variant | base | - |vers| | | | - |2bit| 4 bits | 10 bits | 16 bits | - Unpacked elements - base 15 0 - | 0 | 16 bits | - variant 9 0 - | 0 | 10 bits | - format 3 0 - | 0 | 4 bits | - ----------------------------------------------------------------------------------------------------------- -*/ - -enum { - kTextEncodingVersion = 0 -}; - - -enum { - kTextEncodingBaseShiftBits = 0, /* <13>*/ - kTextEncodingVariantShiftBits = 16, /* <13>*/ - kTextEncodingFormatShiftBits = 26, /* <13><16>*/ - kTextEncodingVersionShiftBits = 30 -}; - - - -enum { - kTextEncodingBaseSourceMask = 0x0000FFFF, /* 16 bits <13>*/ - kTextEncodingVariantSourceMask = 0x000003FF, /* 10 bits <13><16>*/ - kTextEncodingFormatSourceMask = 0x0000000F, /* 4 bits <13><16>*/ - kTextEncodingVersionSourceMask = 0x00000003 /* 2 bits*/ -}; - - -enum { - kTextEncodingBaseMask = kTextEncodingBaseSourceMask << kTextEncodingBaseShiftBits, - kTextEncodingVariantMask = kTextEncodingVariantSourceMask << kTextEncodingVariantShiftBits, - kTextEncodingFormatMask = kTextEncodingFormatSourceMask << kTextEncodingFormatShiftBits, - kTextEncodingVersionMask = kTextEncodingVersionSourceMask << kTextEncodingVersionShiftBits -}; - - -enum { - kTextEncodingVersionShifted = (kTextEncodingVersion & kTextEncodingVersionSourceMask) << kTextEncodingVersionShiftBits -}; - - -#define CreateTextEncodingPriv(base,variant,format) \ - ( ((base & kTextEncodingBaseSourceMask) << kTextEncodingBaseShiftBits) \ - | ((variant & kTextEncodingVariantSourceMask) << kTextEncodingVariantShiftBits) \ - | ((format & kTextEncodingFormatSourceMask) << kTextEncodingFormatShiftBits) \ - | (kTextEncodingVersionShifted) ) -#define GetTextEncodingBasePriv(encoding) \ - ((encoding & kTextEncodingBaseMask) >> kTextEncodingBaseShiftBits) -#define GetTextEncodingVariantPriv(encoding) \ - ((encoding & kTextEncodingVariantMask) >> kTextEncodingVariantShiftBits) -#define GetTextEncodingFormatPriv(encoding) \ - ((encoding & kTextEncodingFormatMask) >> kTextEncodingFormatShiftBits) -#define IsMacTextEncoding(encoding) ((encoding & 0x0000FF00L) == 0x00000000L) -#define IsUnicodeTextEncoding(encoding) ((encoding & 0x0000FF00L) == 0x00000100L) -/* TextEncoding used by HFS*/ - -enum { - kMacHFSTextEncoding = 0x000000FF -}; - - -/* - File: Instrumentation.h - - -*/ -/*******************************************************************/ -/* Types */ -/*******************************************************************/ -/* Reference to an instrumentation class */ -typedef struct InstOpaqueClassRef* InstClassRef; - -/* Aliases to the generic instrumentation class for each type of class */ -typedef InstClassRef InstPathClassRef; -typedef InstClassRef InstTraceClassRef; -typedef InstClassRef InstHistogramClassRef; -typedef InstClassRef InstSplitHistogramClassRef; -typedef InstClassRef InstMagnitudeClassRef; -typedef InstClassRef InstGrowthClassRef; -typedef InstClassRef InstTallyClassRef; - -/* Reference to a data descriptor */ -typedef struct InstOpaqueDataDescriptorRef* InstDataDescriptorRef; - - -/*******************************************************************/ -/* Constant Definitions */ -/*******************************************************************/ - -/* Reference to the root of the class hierarchy */ -#define kInstRootClassRef ( (InstClassRef) -1) - -/* Options used for creating classes */ -typedef OptionBits InstClassOptions; - - -enum { - kInstDisableClassMask = 0x00, /* Create the class disabled */ - kInstEnableClassMask = 0x01, /* Create the class enabled */ - - kInstSummaryTraceClassMask = 0x20 /* Create a summary trace class instead of a regular one */ -}; - - - -EXTERN_API( Boolean ) -EqualString (ConstStr255Param str1, - ConstStr255Param str2, - Boolean caseSensitive, - Boolean diacSensitive); - - - - -/* - File: LowMemPriv.h - - -*/ - -/* The following replace storage used in low-mem on MacOS: */ -extern struct FSVarsRec * gFSMVars; - - -#define LMGetFSMVars() gFSMVars - - - -EXTERN_API( void ) -InsTime (QElemPtr tmTaskPtr); -EXTERN_API( void ) -PrimeTime (QElemPtr tmTaskPtr, - long count); -EXTERN_API( void ) -RmvTime (QElemPtr tmTaskPtr); - - - - -/* PROTOTYPES */ - -#if HFS_DIAGNOSTIC - extern void RequireFileLock(FileReference vp, int shareable); - #define REQUIRE_FILE_LOCK(vp,s) RequireFileLock((vp),(s)) -#else - #define REQUIRE_FILE_LOCK(vp,s) -#endif - - -EXTERN_API( void ) -BlockMove (const void * srcPtr, - void * destPtr, - Size byteCount); -EXTERN_API( void ) -BlockMoveData (const void * srcPtr, - void * destPtr, - Size byteCount); - -EXTERN_API_C( void ) -BlockMoveUncached (const void * srcPtr, - void * destPtr, - Size byteCount); - -EXTERN_API_C( void ) -BlockMoveDataUncached (const void * srcPtr, - void * destPtr, - Size byteCount); - -EXTERN_API_C( void ) -BlockZero (void * destPtr, - Size byteCount); - -EXTERN_API_C( void ) -BlockZeroUncached (void * destPtr, - Size byteCount); - -EXTERN_API( Ptr ) -NewPtr (Size byteCount); - -EXTERN_API( Ptr ) -NewPtrSys (Size byteCount); - -EXTERN_API( Ptr ) -NewPtrClear (Size byteCount); - -EXTERN_API( Ptr ) -NewPtrSysClear (Size byteCount); - -EXTERN_API( OSErr ) -MemError (void); - -EXTERN_API( void ) -DisposePtr (Ptr p); - -EXTERN_API( Size ) -GetPtrSize (Ptr p); - -EXTERN_API( void ) -SetPtrSize (Ptr p, - Size newSize); - -EXTERN_API( void ) -DisposeHandle (Handle h); - -EXTERN_API( void ) -SetHandleSize (Handle h, - Size newSize); - -/* - File: DateTimeUtils.h - - -*/ -EXTERN_API( void ) -GetDateTime (unsigned long * secs); - - - -#endif /* __hfs_macos_types__ */ diff --git a/bsd/dev/random/YarrowCoreLib/src/prng.c b/bsd/dev/random/YarrowCoreLib/src/prng.c index aa9c23d6d..fa4ab5fec 100644 --- a/bsd/dev/random/YarrowCoreLib/src/prng.c +++ b/bsd/dev/random/YarrowCoreLib/src/prng.c @@ -46,8 +46,6 @@ #if defined(macintosh) || defined(__APPLE__) /* FIXME - this file needs to be in a platform-independent place */ -#include - #include "macOnly.h" #endif /* macintosh */ #include "smf.h" diff --git a/bsd/dev/random/randomdev.c b/bsd/dev/random/randomdev.c index 642add668..f7830f40e 100644 --- a/bsd/dev/random/randomdev.c +++ b/bsd/dev/random/randomdev.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2000-2001 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1999, 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -29,8 +29,6 @@ #include #include #include -#include -#include #include #include diff --git a/bsd/dev/random/randomdev.h b/bsd/dev/random/randomdev.h index 906f620b1..efa6703e9 100644 --- a/bsd/dev/random/randomdev.h +++ b/bsd/dev/random/randomdev.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2000-2001 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1999, 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -23,13 +23,19 @@ #ifndef __DEV_RANDOMDEV_H__ #define __DEV_RANDOMDEV_H__ +#include + +#ifdef __APPLE_API_PRIVATE + +#include + int random_open(dev_t dev, int flags, int devtype, struct proc *pp); int random_close(dev_t dev, int flags, int mode, struct proc *pp); int random_read(dev_t dev, struct uio *uio, int ioflag); int random_write(dev_t dev, struct uio *uio, int ioflag); u_long RandomULong(); -void read_random(void* buffer, u_int numBytes); +#endif /* __APPLE_API_PRIVATE */ #endif /* __DEV_RANDOMDEV_H__ */ diff --git a/bsd/dev/vn/Makefile b/bsd/dev/vn/Makefile new file mode 100644 index 000000000..58a7c8500 --- /dev/null +++ b/bsd/dev/vn/Makefile @@ -0,0 +1,37 @@ +export MakeInc_cmd=${SRCROOT}/makedefs/MakeInc.cmd +export MakeInc_def=${SRCROOT}/makedefs/MakeInc.def +export MakeInc_rule=${SRCROOT}/makedefs/MakeInc.rule +export MakeInc_dir=${SRCROOT}/makedefs/MakeInc.dir + + +include $(MakeInc_cmd) +include $(MakeInc_def) + +INSTINC_SUBDIRS = \ + +INSTINC_SUBDIRS_PPC = \ + +INSTINC_SUBDIRS_I386 = \ + +EXPINC_SUBDIRS = \ + +EXPINC_SUBDIRS_PPC = \ + +EXPINC_SUBDIRS_I386 = \ + +DATAFILES = \ + vnioctl.h + +INSTALL_MI_LIST = ${DATAFILES} + +INSTALL_MI_DIR = sys + +EXPORT_MI_LIST = ${DATAFILES} + +EXPORT_MI_DIR = sys + + +include $(MakeInc_rule) +include $(MakeInc_dir) + + diff --git a/bsd/dev/vn/shadow.c b/bsd/dev/vn/shadow.c new file mode 100644 index 000000000..aef372aae --- /dev/null +++ b/bsd/dev/vn/shadow.c @@ -0,0 +1,726 @@ + +/* + * Copyright (c) 2001 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * shadow.c + * + * Implement copy-on-write shadow map to allow a disk image to be + * mounted read-only, yet be writable by transferring writes to a + * "shadow" file. Subsequent reads from blocks that have been + * written will then go the "shadow" file. + * + * The map has two parts: + * 1) a bit map to track which blocks have been written + * 2) a band map to map a "band" within the original file to a corresponding + * "band" in the shadow file. Each band has the same size. + * + * The band map is used to ensure that blocks that are contiguous in the + * original file will remain contiguous in the shadow file. + * + * For debugging purposes, this file can be compiled standalone using: + * cc -o shadow shadow.c -DTEST_SHADOW + */ + +/* + * Modification History + * + * December 21, 2001 Dieter Siegmund (dieter@apple.com) + * - initial revision + */ +#include +#include +#include + +#include + +#ifdef TEST_SHADOW +#include +#include +#define my_malloc(a) malloc(a) +#define my_free(a) free(a) +#else TEST_SHADOW +#include +#define my_malloc(a) _MALLOC(a, M_TEMP, M_WAITOK) +#define my_free(a) FREE(a, M_TEMP) +#endif TEST_SHADOW + +#include "shadow.h" + +#define ULONG_ALL_ONES ((u_long)(-1)) +#define USHORT_ALL_ONES ((u_short)(-1)) +#define UCHAR_ALL_ONES ((u_char)(-1)) + +#define my_trunc(value, divisor) ((value) / (divisor) * (divisor)) + +/* a band size of 128K can represent a file up to 8GB */ +#define BAND_SIZE_DEFAULT_POWER_2 17 +#define BAND_SIZE_DEFAULT (1 << BAND_SIZE_DEFAULT_POWER_2) + +typedef u_short band_number_t; +#define BAND_ZERO ((band_number_t)0) +#define BAND_MAX ((band_number_t)65535) + +struct shadow_map { + u_long blocks_per_band;/* size in blocks */ + u_long block_size; + u_char * block_bitmap; /* 1 bit per block; 1=written */ + band_number_t * bands; /* band map array */ + u_long file_size_blocks; /* size of file in bands */ + u_long shadow_size_bands; /* size of shadow in bands */ + u_long next_band; /* next free band */ + u_long zeroth_band; /* special-case 0th band */ +}; + + +typedef struct { + u_long byte; + u_long bit; +} bitmap_offset_t; + +static __inline__ u_char +bit(int b) +{ + return ((u_char)(1 << b)); +} + +/* + * Function: bits_lower + * Purpose: + * Return a byte value in which bits numbered lower than 'b' are set. + */ +static __inline__ u_char +bits_lower(int b) +{ + return ((u_char)(bit(b) - 1)); +} + +/* + * Function: byte_set_bits + * Purpose: + * Set the given range of bits within a byte. + */ +static __inline__ u_char +byte_set_bits(int start, int end) +{ + return ((u_char)((~bits_lower(start)) & (bits_lower(end) | bit(end)))); +} + +static __inline__ bitmap_offset_t +bitmap_offset(off_t where) +{ + bitmap_offset_t b; + + b.byte = where / NBBY; + b.bit = where % NBBY; + return (b); +} + +/* + * Function: bitmap_set + * + * Purpose: + * Set the given range of bits. + * + * This algorithm tries to set the extents using the biggest + * units, using longs, then a short, then a byte, then bits. + */ +static void +bitmap_set(u_char * map, u_long start_bit, u_long bit_count) +{ + bitmap_offset_t start; + bitmap_offset_t end; + + start = bitmap_offset(start_bit); + end = bitmap_offset(start_bit + bit_count); + if (start.byte < end.byte) { + u_long n_bytes; + + if (start.bit) { + map[start.byte] |= byte_set_bits(start.bit, NBBY - 1); + start.bit = 0; + start.byte++; + if (start.byte == end.byte) + goto end; + } + + n_bytes = end.byte - start.byte; + + while (n_bytes >= (sizeof(u_long))) { + *((u_long *)(map + start.byte)) = ULONG_ALL_ONES; + start.byte += sizeof(u_long); + n_bytes -= sizeof(u_long); + } + if (n_bytes >= sizeof(u_short)) { + *((u_short *)(map + start.byte)) = USHORT_ALL_ONES; + start.byte += sizeof(u_short); + n_bytes -= sizeof(u_short); + } + if (n_bytes == 1) { + map[start.byte] = UCHAR_ALL_ONES; + start.byte++; + n_bytes = 0; + } + } + + end: + if (end.bit > start.bit) { + map[start.byte] |= byte_set_bits(start.bit, end.bit - 1); + } + + return; +} + +/* + * Function: bitmap_get + * + * Purpose: + * Return the number of bits in the range that are the same e.g. + * 11101 returns 3 because the first 3 bits are the same (1's), whereas + * 001100 returns 2 because the first 2 bits are the same. + * This algorithm tries to count things in as big a chunk as possible, + * first aligning to a byte offset, then trying to count longs, a short, + * a byte, then any remaining bits to find the bit that is different. + */ + +static u_long +bitmap_get(u_char * map, u_long start_bit, u_long bit_count, + boolean_t * ret_is_set) +{ + u_long count; + int i; + boolean_t is_set; + bitmap_offset_t start; + bitmap_offset_t end; + + start = bitmap_offset(start_bit); + end = bitmap_offset(start_bit + bit_count); + + is_set = (map[start.byte] & bit(start.bit)) ? TRUE : FALSE; + count = 0; + + if (start.byte < end.byte) { + u_long n_bytes; + + if (start.bit) { /* try to align to a byte */ + for (i = start.bit; i < NBBY; i++) { + boolean_t this_is_set; + + this_is_set = (map[start.byte] & bit(i)) ? TRUE : FALSE; + if (this_is_set != is_set) { + goto done; /* found bit that was different, we're done */ + } + count++; + } + start.bit = 0; /* made it to the next byte */ + start.byte++; + if (start.byte == end.byte) + goto end; /* no more bytes, check for any leftover bits */ + } + /* calculate how many bytes are left in the range */ + n_bytes = end.byte - start.byte; + + /* check for 4 bytes of the same bits */ + while (n_bytes >= sizeof(u_long)) { + u_long * valPtr = (u_long *)(map + start.byte); + if ((is_set && *valPtr == ULONG_ALL_ONES) + || (!is_set && *valPtr == 0)) { + count += sizeof(*valPtr) * NBBY; + start.byte += sizeof(*valPtr); + n_bytes -= sizeof(*valPtr); + } + else + break; /* bits differ */ + + } + /* check for 2 bytes of the same bits */ + if (n_bytes >= sizeof(u_short)) { + u_short * valPtr = (u_short *)(map + start.byte); + + if ((is_set && *valPtr == USHORT_ALL_ONES) + || (!is_set && (*valPtr == 0))) { + count += sizeof(*valPtr) * NBBY; + start.byte += sizeof(*valPtr); + n_bytes -= sizeof(*valPtr); + } + } + + /* check for 1 byte of the same bits */ + if (n_bytes) { + if ((is_set && map[start.byte] == UCHAR_ALL_ONES) + || (!is_set && map[start.byte] == 0)) { + count += NBBY; + start.byte++; + n_bytes--; + } + /* we found bits that were different, find the first one */ + if (n_bytes) { + for (i = 0; i < NBBY; i++) { + boolean_t this_is_set; + + this_is_set = (map[start.byte] & bit(i)) ? TRUE : FALSE; + if (this_is_set != is_set) { + break; + } + count++; + } + goto done; + } + } + } + + end: + for (i = start.bit; i < end.bit; i++) { + boolean_t this_is_set = (map[start.byte] & bit(i)) ? TRUE : FALSE; + + if (this_is_set != is_set) { + break; + } + count++; + } + + done: + *ret_is_set = is_set; + return (count); +} + +static __inline__ band_number_t +shadow_map_block_to_band(shadow_map_t * map, unsigned long block) +{ + return (block / map->blocks_per_band); +} + +/* + * Function: shadow_map_mapped_band + * Purpose: + * Return the mapped band for the given band. + * If map_it is FALSE, and the band is not mapped, return FALSE. + * If map_it is TRUE, then this function will always return TRUE. + */ +static boolean_t +shadow_map_mapped_band(shadow_map_t * map, band_number_t band, + boolean_t map_it, band_number_t * mapped_band) +{ + boolean_t is_mapped = FALSE; + + if (band == map->zeroth_band) { + *mapped_band = BAND_ZERO; + is_mapped = TRUE; + } + else { + *mapped_band = map->bands[band]; + if (*mapped_band == BAND_ZERO) { + if (map_it) { + /* grow the file */ + if (map->next_band == 0) { + /* remember the zero'th band */ + map->zeroth_band = band; + } + *mapped_band = map->bands[band] = map->next_band++; + is_mapped = TRUE; + } + } + else { + is_mapped = TRUE; + } + } + return (is_mapped); +} + +/* + * Function: shadow_map_contiguous + * + * Purpose: + * Return the first offset within the range position..(position + count) + * that is not a contiguous mapped band. + * + * If called with is_write = TRUE, this function will map bands as it goes. + */ +static u_long +shadow_map_contiguous(shadow_map_t * map, u_long start_block, + u_long num_blocks, boolean_t is_write) +{ + band_number_t band = shadow_map_block_to_band(map, start_block); + u_long end_block = start_block + num_blocks; + boolean_t is_mapped; + band_number_t mapped_band; + u_long ret_end_block = end_block; + u_long p; + + is_mapped = shadow_map_mapped_band(map, band, is_write, &mapped_band); + if (is_write == FALSE && is_mapped == FALSE) { + static int happened = 0; + /* this can't happen */ + if (happened == 0) { + printf("shadow_map_contiguous: this can't happen!\n"); + happened = 1; + } + return (start_block); + } + for (p = my_trunc(start_block + map->blocks_per_band, + map->blocks_per_band); + p < end_block; p += map->blocks_per_band) { + band_number_t next_mapped_band; + + band++; + is_mapped = shadow_map_mapped_band(map, band, is_write, + &next_mapped_band); + if (is_write == FALSE && is_mapped == FALSE) { + return (p); + } + if ((mapped_band + 1) != next_mapped_band) { + /* not contiguous */ + ret_end_block = p; + break; + } + mapped_band = next_mapped_band; + } + return (ret_end_block); +} + + +/* + * Function: block_bitmap_size + * Purpose: + * The number of bytes required in a block bitmap to represent a file of size + * file_size. + * + * The bytes required is the number of blocks in the file, + * divided by the number of bits per byte. + * Note: + * An 8GB file requires (assuming 512 byte block): + * 2^33 / 2^9 / 2^3 = 2^21 = 2MB + * of bitmap space. This is a non-trival amount of memory, + * particularly since most of the bits will be zero. + * A sparse bitmap would really help in this case. + */ +static __inline__ u_long +block_bitmap_size(off_t file_size, u_long block_size) +{ + off_t blocks = howmany(file_size, block_size); + return (howmany(blocks, NBBY)); +} + +/* + * Function: shadow_map_read + * + * Purpose: + * Calculate the block offset within the shadow to read, and the number + * blocks to read. The input values (block_offset, block_count) refer + * to the original file. + * + * The output values (*incr_block_offset, *incr_block_count) refer to the + * shadow file if the return value is TRUE. They refer to the original + * file if the return value is FALSE. + + * Blocks within a band may or may not have been written, in addition, + * Bands are not necessarily contiguous, therefore: + * *incr_block_count <= block_count + * The caller must be prepared to call this function interatively + * to complete the whole i/o. + * Returns: + * TRUE if the shadow file should be read, FALSE if the original file + * should be read. + */ +boolean_t +shadow_map_read(shadow_map_t * map, u_long block_offset, u_long block_count, + u_long * incr_block_offset, u_long * incr_block_count) +{ + boolean_t written = FALSE; + u_long n_blocks; + + if (block_offset >= map->file_size_blocks + || (block_offset + block_count) > map->file_size_blocks) { + printf("shadow_map_read: request (%ld, %ld) exceeds file size %ld\n", + block_offset, block_count, map->file_size_blocks); + *incr_block_count = 0; + } + n_blocks = bitmap_get(map->block_bitmap, block_offset, block_count, + &written); + if (written == FALSE) { + *incr_block_count = n_blocks; + *incr_block_offset = block_offset; + } + else { /* start has been written, and therefore mapped */ + band_number_t mapped_band; + u_long band_limit; + + mapped_band = map->bands[shadow_map_block_to_band(map, block_offset)]; + *incr_block_offset = mapped_band * map->blocks_per_band + + (block_offset % map->blocks_per_band); + band_limit + = shadow_map_contiguous(map, block_offset, block_count, FALSE); + *incr_block_count = band_limit - block_offset; + if (*incr_block_count > n_blocks) { + *incr_block_count = n_blocks; + } + } + return (written); +} + +/* + * Function: shadow_map_write + * + * Purpose: + * Calculate the block offset within the shadow to write, and the number + * blocks to write. The input values (block_offset, block_count) refer + * to the original file. The output values + * (*incr_block_offset, *incr_block_count) refer to the shadow file. + * + * Bands are not necessarily contiguous, therefore: + * *incr_block_count <= block_count + * The caller must be prepared to call this function interatively + * to complete the whole i/o. + * Returns: + * TRUE if the shadow file was grown, FALSE otherwise. + */ +boolean_t +shadow_map_write(shadow_map_t * map, u_long block_offset, + u_long block_count, u_long * incr_block_offset, + u_long * incr_block_count) +{ + u_long band_limit; + band_number_t mapped_band; + boolean_t shadow_grew = FALSE; + + if (block_offset >= map->file_size_blocks + || (block_offset + block_count) > map->file_size_blocks) { + printf("shadow_map_write: request (%ld, %ld) exceeds file size %ld\n", + block_offset, block_count, map->file_size_blocks); + *incr_block_count = 0; + } + + band_limit = shadow_map_contiguous(map, block_offset, block_count, TRUE); + mapped_band = map->bands[shadow_map_block_to_band(map, block_offset)]; + *incr_block_offset = mapped_band * map->blocks_per_band + + (block_offset % map->blocks_per_band); + *incr_block_count = band_limit - block_offset; + + /* mark these blocks as written */ + bitmap_set(map->block_bitmap, block_offset, *incr_block_count); + + if (map->next_band > map->shadow_size_bands) { + map->shadow_size_bands = map->next_band; + shadow_grew = TRUE; + } + return (shadow_grew); +} + +/* + * Function: shadow_map_shadow_size + * + * Purpose: + * To return the size of the shadow file in blocks. + */ +u_long +shadow_map_shadow_size(shadow_map_t * map) +{ + return (map->shadow_size_bands * map->blocks_per_band); +} + +/* + * Function: shadow_map_create + * + * Purpose: + * Allocate the dynamic data for keeping track of the shadow dirty blocks + * and the band mapping table. + * Returns: + * NULL if an error occurred. + */ +shadow_map_t * +shadow_map_create(off_t file_size, off_t shadow_size, + u_long band_size, u_long block_size) +{ + void * block_bitmap = 0; + u_long bitmap_size; + band_number_t * bands = 0; + shadow_map_t * map; + u_long n_bands = 0; + + if (band_size == 0) { + band_size = BAND_SIZE_DEFAULT; + } + + n_bands = howmany(file_size, band_size); + if (n_bands > (BAND_MAX + 1)) { + printf("file is too big: %ld > %d\n", + n_bands, BAND_MAX); + goto failure; + } + + /* create a block bitmap, one bit per block */ + bitmap_size = block_bitmap_size(file_size, block_size); + block_bitmap = my_malloc(bitmap_size); + if (block_bitmap == NULL) { + printf("failed to allocate bitmap\n"); + goto failure; + } + bzero(block_bitmap, bitmap_size); + + /* get the band map */ + bands = (band_number_t *)my_malloc(n_bands * sizeof(band_number_t)); + if (bands == NULL) { + printf("failed to allocate bands\n"); + goto failure; + } + bzero(bands, n_bands * sizeof(band_number_t)); + + map = my_malloc(sizeof(*map)); + if (map == NULL) { + printf("failed to allocate map\n"); + goto failure; + } + map->blocks_per_band = band_size / block_size; + map->block_bitmap = block_bitmap; + map->bands = bands; + map->file_size_blocks = n_bands * map->blocks_per_band; + map->next_band = 0; + map->zeroth_band = -1; + map->shadow_size_bands = howmany(shadow_size, band_size); + map->block_size = block_size; + return (map); + + failure: + if (block_bitmap) + my_free(block_bitmap); + if (bands) + my_free(bands); + return (NULL); +} + +/* + * Function: shadow_map_free + * Purpose: + * Frees the data structure to deal with the shadow map. + */ +void +shadow_map_free(shadow_map_t * map) +{ + if (map->block_bitmap) + my_free(map->block_bitmap); + if (map->bands) + my_free(map->bands); + map->block_bitmap = 0; + map->bands = 0; + my_free(map); + return; +} + +#ifdef TEST_SHADOW +#define BAND_SIZE_BLOCKS (BAND_SIZE_DEFAULT / 512) + +enum { + ReadRequest, + WriteRequest, +}; + +typedef struct { + int type; + u_long offset; + u_long count; +} block_request_t; + +int +main() +{ + shadow_map_t * map; + int i; + block_request_t requests[] = { + { WriteRequest, BAND_SIZE_BLOCKS * 2, 1 }, + { ReadRequest, BAND_SIZE_BLOCKS / 2, BAND_SIZE_BLOCKS * 2 - 2 }, + { WriteRequest, BAND_SIZE_BLOCKS * 1, 5 * BAND_SIZE_BLOCKS + 3}, + { ReadRequest, 0, BAND_SIZE_BLOCKS * 10 }, + { WriteRequest, BAND_SIZE_BLOCKS * (BAND_MAX - 1), + BAND_SIZE_BLOCKS * 2}, + { 0, 0 }, + }; + + map = shadow_map_create(1024 * 1024 * 1024 * 8ULL, 0, 0, 512); + if (map == NULL) { + printf("shadow_map_create failed\n"); + exit(1); + } + for (i = 0; TRUE; i++) { + u_long offset; + u_long resid; + boolean_t shadow_grew; + boolean_t read_shadow; + + if (requests[i].count == 0) { + break; + } + offset = requests[i].offset; + resid = requests[i].count; + printf("\n%s REQUEST (%ld, %ld)\n", + requests[i].type == WriteRequest ? "WRITE" : "READ", + offset, resid); + switch (requests[i].type) { + case WriteRequest: + while (resid > 0) { + u_long this_offset; + u_long this_count; + + shadow_grew = shadow_map_write(map, offset, + resid, + &this_offset, + &this_count); + printf("\t(%ld, %ld) => (%ld, %ld)", + offset, resid, this_offset, this_count); + resid -= this_count; + offset += this_count; + if (shadow_grew) { + printf(" shadow grew to %ld", shadow_map_shadow_size(map)); + } + printf("\n"); + } + break; + case ReadRequest: + while (resid > 0) { + u_long this_offset; + u_long this_count; + + read_shadow = shadow_map_read(map, offset, + resid, + &this_offset, + &this_count); + printf("\t(%ld, %ld) => (%ld, %ld)%s\n", + offset, resid, this_offset, this_count, + read_shadow ? " from shadow" : ""); + if (this_count == 0) { + printf("this_count is 0, aborting\n"); + break; + } + resid -= this_count; + offset += this_count; + } + break; + default: + break; + } + } + if (map) { + shadow_map_free(map); + } + exit(0); + return (0); +} +#endif diff --git a/bsd/dev/vn/shadow.h b/bsd/dev/vn/shadow.h new file mode 100644 index 000000000..074ba9e4c --- /dev/null +++ b/bsd/dev/vn/shadow.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 1999, 2000-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#ifndef __VN_SHADOW_H__ +#define __VN_SHADOW_H__ + +#include + +#ifdef __APPLE_API_PRIVATE + +typedef struct shadow_map shadow_map_t; + +boolean_t +shadow_map_read(shadow_map_t * map, u_long block_offset, u_long block_count, + u_long * incr_block_offset, u_long * incr_block_count); +boolean_t +shadow_map_write(shadow_map_t * map, u_long block_offset, u_long block_count, + u_long * incr_block_offset, u_long * incr_block_count); +u_long +shadow_map_shadow_size(shadow_map_t * map); + +shadow_map_t * +shadow_map_create(off_t file_size, off_t shadow_size, + unsigned long band_size, unsigned long block_size); + +#endif /* __APPLE_API_PRIVATE */ +#endif /* __VN_SHADOW_H__ */ + + + diff --git a/bsd/dev/vn/vn.c b/bsd/dev/vn/vn.c new file mode 100644 index 000000000..0e29677cf --- /dev/null +++ b/bsd/dev/vn/vn.c @@ -0,0 +1,983 @@ + +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1990, 1993 + * 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: vn.c 1.13 94/04/02 + * + * from: @(#)vn.c 8.6 (Berkeley) 4/1/94 + * $FreeBSD: src/sys/dev/vn/vn.c,v 1.105.2.4 2001/11/18 07:11:00 dillon Exp $ + */ + +/* + * Vnode disk driver. + * + * Block/character interface to a vnode. Allows one to treat a file + * as a disk (e.g. build a filesystem in it, mount it, etc.). + * + * NOTE 1: This uses the VOP_BMAP/VOP_STRATEGY interface to the vnode + * instead of a simple VOP_RDWR. We do this to avoid distorting the + * local buffer cache. + * + * NOTE 2: There is a security issue involved with this driver. + * Once mounted all access to the contents of the "mapped" file via + * the special file is controlled by the permissions on the special + * file, the protection of the mapped file is ignored (effectively, + * by using root credentials in all transactions). + * + * NOTE 3: Doesn't interact with leases, should it? + */ + +#include "vndevice.h" + +#if NVNDEVICE > 0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +#include + +#include "shadow.h" + +static ioctl_fcn_t vnioctl_chr; +static ioctl_fcn_t vnioctl_blk; +static open_close_fcn_t vnopen; +static open_close_fcn_t vnclose; +static psize_fcn_t vnsize; +static strategy_fcn_t vnstrategy; +static read_write_fcn_t vnread; +static read_write_fcn_t vnwrite; + +static int vndevice_bdev_major; +static int vndevice_cdev_major; + +/* + * cdevsw + * D_DISK we want to look like a disk + * D_CANFREE We support B_FREEBUF + */ + +static struct bdevsw vn_bdevsw = { + /* open */ vnopen, + /* close */ vnclose, + /* strategy */ vnstrategy, + /* ioctl */ vnioctl_blk, + /* dump */ eno_dump, + /* psize */ vnsize, + /* flags */ D_DISK, +}; + +static struct cdevsw vn_cdevsw = { + /* open */ vnopen, + /* close */ vnclose, + /* read */ vnread, + /* write */ vnwrite, + /* ioctl */ vnioctl_chr, + /* stop */ eno_stop, + /* reset */ eno_reset, + /* ttys */ 0, + /* select */ eno_select, + /* mmap */ eno_mmap, + /* strategy */ eno_strat, + /* getc */ eno_getc, + /* putc */ eno_putc, + /* flags */ D_DISK, +}; + +struct vn_softc { + u_int64_t sc_fsize; /* file size in bytes */ + u_int64_t sc_size; /* size of vn, sc_secsize scale */ + int sc_flags; /* flags */ + int sc_secsize; /* sector size */ + struct vnode *sc_vp; /* vnode if not NULL */ + int sc_open_flags; + struct vnode *sc_shadow_vp; /* shadow vnode if not NULL */ + shadow_map_t * sc_shadow_map; /* shadow map if not NULL */ + struct ucred *sc_cred; /* credentials */ + u_long sc_options; /* options */ + void * sc_bdev; + void * sc_cdev; +} vn_table[NVNDEVICE]; + +#define ROOT_IMAGE_UNIT 0 + +/* sc_flags */ +#define VNF_INITED 0x01 +#define VNF_READONLY 0x02 + +static u_long vn_options; + +#define IFOPT(vn,opt) if (((vn)->sc_options|vn_options) & (opt)) +#define TESTOPT(vn,opt) (((vn)->sc_options|vn_options) & (opt)) + +static int vnsetcred (struct vn_softc *vn, struct proc *p); +static void vnclear (struct vn_softc *vn); + +static int +vniocattach_file(struct vn_softc *vn, + struct vn_ioctl *vio, + dev_t dev, + int in_kernel, + struct proc *p); +static int +vniocattach_shadow(struct vn_softc * vn, + struct vn_ioctl *vio, + dev_t dev, + int in_kernel, + struct proc *p); +static __inline__ +vnunit(dev_t dev) +{ + return (minor(dev)); +} + +static int +vnclose(dev_t dev, int flags, int devtype, struct proc *p) +{ + return (0); +} + +static int +vnopen(dev_t dev, int flags, int devtype, struct proc *p) +{ + struct vn_softc *vn; + int unit; + + unit = vnunit(dev); + if (vnunit(dev) >= NVNDEVICE) { + return (ENXIO); + } + vn = vn_table + unit; + if ((flags & FWRITE) && (vn->sc_flags & VNF_READONLY)) + return (EACCES); + + return(0); +} + +static int +vnread(dev_t dev, struct uio *uio, int ioflag) +{ + struct proc * p = current_proc(); + int status; + struct vn_softc * vn; + int unit; + + unit = vnunit(dev); + if (vnunit(dev) >= NVNDEVICE) { + return (ENXIO); + } + vn = vn_table + unit; + if ((vn->sc_flags & VNF_INITED) == 0) { + return (ENXIO); + } + if (vn->sc_shadow_vp != NULL) { + return (ENODEV); + } + vn_lock(vn->sc_vp, LK_EXCLUSIVE | LK_RETRY, p); + status = VOP_READ(vn->sc_vp, uio, ioflag, vn->sc_cred); + VOP_UNLOCK(vn->sc_vp, 0, p); + + return (status); +} + +static int +vnwrite(dev_t dev, struct uio *uio, int ioflag) +{ + struct proc * p = current_proc(); + int status; + struct vn_softc * vn; + int unit; + + unit = vnunit(dev); + if (vnunit(dev) >= NVNDEVICE) { + return (ENXIO); + } + vn = vn_table + unit; + if ((vn->sc_flags & VNF_INITED) == 0) { + return (ENXIO); + } + if (vn->sc_shadow_vp != NULL) { + return (ENODEV); + } + if (vn->sc_flags & VNF_READONLY) { + return (EROFS); + } + + vn_lock(vn->sc_vp, LK_EXCLUSIVE | LK_RETRY, p); + status = VOP_WRITE(vn->sc_vp, uio, ioflag, vn->sc_cred); + VOP_UNLOCK(vn->sc_vp, 0, p); + + return (status); +} + +static boolean_t +bp_is_mapped(struct buf * bp, vm_offset_t * vaddr) +{ + boolean_t is_mapped = FALSE; + + if (bp->b_flags & B_NEED_IODONE) { + struct buf * real_bp = (struct buf *)bp->b_real_bp; + + if (real_bp && real_bp->b_data) { + *vaddr = (vm_offset_t)real_bp->b_data; + is_mapped = TRUE; + } + } + return (is_mapped); +} + +static __inline__ int +file_io(struct vnode * vp, struct ucred * cred, + enum uio_rw op, char * base, off_t offset, long count, + struct proc * p, long * resid) +{ + struct uio auio; + struct iovec aiov; + int error; + + bzero(&auio, sizeof(auio)); + aiov.iov_base = base; + aiov.iov_len = count; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_offset = offset; + auio.uio_rw = op; + auio.uio_resid = count; + auio.uio_procp = p; + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + if (op == UIO_READ) + error = VOP_READ(vp, &auio, IO_SYNC, cred); + else + error = VOP_WRITE(vp, &auio, IO_SYNC, cred); + VOP_UNLOCK(vp, 0, p); + *resid = auio.uio_resid; + return (error); +} + +static int +shadow_read(struct vn_softc * vn, struct buf * bp, char * base, struct proc * p) +{ + int error = 0; + u_long offset; + boolean_t read_shadow; + u_long resid; + u_long start = 0; + + offset = bp->b_blkno; + resid = bp->b_bcount / vn->sc_secsize; + + while (resid > 0) { + u_long temp_resid; + u_long this_offset; + u_long this_resid; + struct vnode * vp; + + read_shadow = shadow_map_read(vn->sc_shadow_map, + offset, resid, + &this_offset, &this_resid); + if (read_shadow) { + vp = vn->sc_shadow_vp; + } + else { + vp = vn->sc_vp; + } + error = file_io(vp, vn->sc_cred, UIO_READ, base + start, + (off_t)this_offset * vn->sc_secsize, + this_resid * vn->sc_secsize, p, &temp_resid); + if (error) + break; + temp_resid = this_resid - temp_resid / vn->sc_secsize; + if (temp_resid == 0) { + static int printed = 0; + printf("vn device: shadow_write zero length read (printed %d)\n", printed); + printed++; + break; + } + resid -= temp_resid; + offset += temp_resid; + start += temp_resid * vn->sc_secsize;; + } + bp->b_resid = resid * vn->sc_secsize; + return (error); +} + +static int +shadow_write(struct vn_softc * vn, struct buf * bp, char * base, + struct proc * p) +{ + int error = 0; + u_long offset; + boolean_t shadow_grew; + u_long resid; + u_long start = 0; + + offset = bp->b_blkno; + resid = bp->b_bcount / vn->sc_secsize; + + while (resid > 0) { + u_long temp_resid; + u_long this_offset; + u_long this_resid; + struct vnode * vp; + + shadow_grew = shadow_map_write(vn->sc_shadow_map, + offset, resid, + &this_offset, &this_resid); + if (shadow_grew) { +#if 0 + off_t size; + /* truncate the file to its new length before write */ + size = (off_t)shadow_map_shadow_size(vn->sc_shadow_map) + * vn->sc_secsize; + vn_lock(vn->sc_shadow_vp, LK_EXCLUSIVE | LK_RETRY, p); + VOP_TRUNCATE(vn->sc_shadow_vp, size, + IO_SYNC, vn->sc_cred, p); + VOP_UNLOCK(vn->sc_shadow_vp, 0, p); +#endif 0 + } + error = file_io(vn->sc_shadow_vp, vn->sc_cred, UIO_WRITE, + base + start, + (off_t)this_offset * vn->sc_secsize, + this_resid * vn->sc_secsize, p, &temp_resid); + if (error) { + break; + } + temp_resid = this_resid - temp_resid / vn->sc_secsize; + if (temp_resid == 0) { + static int printed = 0; + printf("vn device: shadow_write zero length write (printed %d)\n", printed); + printed++; + break; + } + resid -= temp_resid; + offset += temp_resid; + start += temp_resid * vn->sc_secsize;; + } + bp->b_resid = resid * vn->sc_secsize; + return (error); +} + +static int +vn_readwrite_io(struct vn_softc * vn, struct buf * bp) +{ + int error = 0; + char * iov_base; + boolean_t need_unmap = FALSE; + struct proc * p = current_proc(); + vm_offset_t vaddr = NULL; + + if (bp->b_flags & B_VECTORLIST) { + if (bp_is_mapped(bp, &vaddr) == FALSE) { + if (ubc_upl_map(bp->b_pagelist, &vaddr) + != KERN_SUCCESS) { + panic("vn device: ubc_upl_map failed"); + } + else { + need_unmap = TRUE; + } + } + } + if (error) + return (error); + + if (vaddr != NULL) + iov_base = (caddr_t)(vaddr + bp->b_uploffset); + else + iov_base = bp->b_data; + if (vn->sc_shadow_vp == NULL) { + error = file_io(vn->sc_vp, vn->sc_cred, + bp->b_flags & B_READ ? UIO_READ : UIO_WRITE, + iov_base, (off_t)bp->b_blkno * vn->sc_secsize, + bp->b_bcount, p, &bp->b_resid); + } + else { + if (bp->b_flags & B_READ) + error = shadow_read(vn, bp, iov_base, p); + else + error = shadow_write(vn, bp, iov_base, p); + if (error == 0) + bp->b_resid = 0; + + } + if (need_unmap) { + ubc_upl_unmap(bp->b_pagelist); + } + return (error); +} + +static void +vnstrategy(struct buf *bp) +{ + struct vn_softc *vn; + int error = 0; + long sz; /* in sc_secsize chunks */ + + vn = vn_table + vnunit(bp->b_dev); + if ((vn->sc_flags & VNF_INITED) == 0) { + bp->b_error = ENXIO; + bp->b_flags |= B_ERROR; + biodone(bp); + return; + } + + bp->b_resid = bp->b_bcount; + /* + * Check for required alignment. Transfers must be a valid + * multiple of the sector size. + */ + if (bp->b_bcount % vn->sc_secsize != 0 || + bp->b_blkno % (vn->sc_secsize / DEV_BSIZE) != 0) { + bp->b_error = EINVAL; + bp->b_flags |= B_ERROR | B_INVAL; + biodone(bp); + return; + } + sz = howmany(bp->b_bcount, vn->sc_secsize); + + /* + * If out of bounds return an error. If at the EOF point, + * simply read or write less. + */ + if (bp->b_blkno >= vn->sc_size) { + bp->b_error = EINVAL; + bp->b_flags |= B_ERROR | B_INVAL; + biodone(bp); + return; + } + /* + * If the request crosses EOF, truncate the request. + */ + if ((bp->b_blkno + sz) > vn->sc_size) { + bp->b_bcount = (vn->sc_size - bp->b_blkno) * vn->sc_secsize; + bp->b_resid = bp->b_bcount; + } + + if (vn->sc_vp) { + error = vn_readwrite_io(vn, bp); + if (error) { + bp->b_error = error; + bp->b_flags |= B_ERROR; + } + biodone(bp); + } + else { + bp->b_flags |= B_ERROR; + bp->b_error = EINVAL; + biodone(bp); + } +} + +/* ARGSUSED */ +static int +vnioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p, + int is_char) +{ + struct vn_softc *vn; + struct vn_ioctl *vio; + int error; + u_long *f; + u_int64_t * o; + int unit; + + unit = vnunit(dev); + if (vnunit(dev) >= NVNDEVICE) { + return (ENXIO); + } + vn = vn_table + unit; + error = suser(p->p_ucred, &p->p_acflag); + if (error) + return (error); + + vio = (struct vn_ioctl *)data; + f = (u_long*)data; + o = (u_int64_t *)data; + switch (cmd) { + case VNIOCDETACH: + case DKIOCGETMAXBLOCKCOUNTREAD: + case DKIOCGETMAXBLOCKCOUNTWRITE: + case DKIOCGETMAXSEGMENTCOUNTREAD: + case DKIOCGETMAXSEGMENTCOUNTWRITE: + case DKIOCGETBLOCKCOUNT32: + if ((vn->sc_flags & VNF_INITED) == 0) { + return (ENXIO); + } + break; + default: + break; + } + switch (cmd) { + case DKIOCGETMAXBLOCKCOUNTREAD: + *o = vn->sc_vp->v_mount->mnt_maxreadcnt / vn->sc_secsize; + break; + case DKIOCGETMAXBLOCKCOUNTWRITE: + *o = vn->sc_vp->v_mount->mnt_maxwritecnt / vn->sc_secsize; + break; + case DKIOCGETMAXSEGMENTCOUNTREAD: + *o = vn->sc_vp->v_mount->mnt_segreadcnt; + break; + case DKIOCGETMAXSEGMENTCOUNTWRITE: + *o = vn->sc_vp->v_mount->mnt_segwritecnt; + break; + case DKIOCGETBLOCKSIZE: + *f = vn->sc_secsize; + break; + case DKIOCSETBLOCKSIZE: + if (is_char) { + /* can only set block size on block device */ + return (ENODEV); + } + if (vn->sc_shadow_vp != NULL) { + /* can't set the block size if already shadowing */ + return (EBUSY); + } + if (*f < DEV_BSIZE) { + return (EINVAL); + } + vn->sc_secsize = *f; + /* recompute the size in terms of the new blocksize */ + vn->sc_size = vn->sc_fsize / vn->sc_secsize; + break; + case DKIOCISWRITABLE: + *f = 1; + break; + case DKIOCGETBLOCKCOUNT32: + *f = vn->sc_size; + break; + case DKIOCGETBLOCKCOUNT64: + *o = vn->sc_size; + break; + case VNIOCSHADOW: + if (vn->sc_shadow_vp != NULL) { + return (EBUSY); + } + if (vn->sc_vp == NULL) { + /* much be attached before we can shadow */ + return (EINVAL); + } + if (vio->vn_file == NULL) { + return (EINVAL); + } + error = vniocattach_shadow(vn, vio, dev, 0, p); + break; + + case VNIOCATTACH: + if (is_char) { + /* attach only on block device */ + return (ENODEV); + } + if (vn->sc_flags & VNF_INITED) { + return (EBUSY); + } + if (vio->vn_file == NULL) { + return (EINVAL); + } + error = vniocattach_file(vn, vio, dev, 0, p); + break; + + case VNIOCDETACH: + if (is_char) { + /* detach only on block device */ + return (ENODEV); + } + /* Note: spec_open won't open a mounted block device */ + + /* + * XXX handle i/o in progress. Return EBUSY, or wait, or + * flush the i/o. + * XXX handle multiple opens of the device. Return EBUSY, + * or revoke the fd's. + * How are these problems handled for removable and failing + * hardware devices? (Hint: They are not) + */ + vnclear(vn); + break; + + case VNIOCGSET: + vn_options |= *f; + *f = vn_options; + break; + + case VNIOCGCLEAR: + vn_options &= ~(*f); + *f = vn_options; + break; + + case VNIOCUSET: + vn->sc_options |= *f; + *f = vn->sc_options; + break; + + case VNIOCUCLEAR: + vn->sc_options &= ~(*f); + *f = vn->sc_options; + break; + + default: + error = ENOTTY; + break; + } + return(error); +} + +static int +vnioctl_chr(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) +{ + return (vnioctl(dev, cmd, data, flag, p, TRUE)); +} + +static int +vnioctl_blk(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) +{ + return (vnioctl(dev, cmd, data, flag, p, FALSE)); +} + +/* + * vniocattach_file: + * + * Attach a file to a VN partition. Return the size in the vn_size + * field. + */ + +static int +vniocattach_file(struct vn_softc *vn, + struct vn_ioctl *vio, + dev_t dev, + int in_kernel, + struct proc *p) +{ + struct vattr vattr; + struct nameidata nd; + int error, flags; + + flags = FREAD|FWRITE; + if (in_kernel) { + NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, vio->vn_file, p); + } + else { + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, vio->vn_file, p); + } + error = vn_open(&nd, flags, 0); + if (error) { + if (error != EACCES && error != EPERM && error != EROFS) + return (error); + flags &= ~FWRITE; + if (in_kernel) { + NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, + vio->vn_file, p); + } + else { + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, + vio->vn_file, p); + } + error = vn_open(&nd, flags, 0); + if (error) + return (error); + } + if (nd.ni_vp->v_type != VREG) { + error = EINVAL; + } + else if (ubc_isinuse(nd.ni_vp, 1)) { + error = EBUSY; + } + else { + error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p); + } + if (error != 0) { + VOP_UNLOCK(nd.ni_vp, 0, p); + (void) vn_close(nd.ni_vp, flags, p->p_ucred, p); + return (error); + } + vn->sc_vp = nd.ni_vp; + vn->sc_vp->v_flag |= VNOCACHE_DATA; + VOP_UNLOCK(nd.ni_vp, 0, p); + + vn->sc_open_flags = flags; + + /* + * If the size is specified, override the file attributes. Note that + * the vn_size argument is in PAGE_SIZE sized blocks. + */ +#if 0 + if (vio->vn_size) + vn->sc_size = (quad_t)vio->vn_size * PAGE_SIZE / vn->sc_secsize; + else + vn->sc_size = vattr.va_size / vn->sc_secsize; +#endif 0 + vn->sc_secsize = DEV_BSIZE; + vn->sc_fsize = vattr.va_size; + vn->sc_size = vattr.va_size / vn->sc_secsize; + error = vnsetcred(vn, p); + if (error) { + (void) vn_close(nd.ni_vp, flags, p->p_ucred, p); + return(error); + } + { + dev_t cdev = makedev(vndevice_cdev_major, + minor(dev)); + vn->sc_cdev = devfs_make_node(cdev, DEVFS_CHAR, + UID_ROOT, GID_OPERATOR, + 0600, "rvn%d", + minor(dev)); + } + vn->sc_flags |= VNF_INITED; + if (flags == FREAD) + vn->sc_flags |= VNF_READONLY; + return(0); +} + +static int +vniocattach_shadow(vn, vio, dev, in_kernel, p) + struct vn_softc *vn; + struct vn_ioctl *vio; + dev_t dev; + int in_kernel; + struct proc *p; +{ + struct vattr vattr; + struct nameidata nd; + int error, flags; + shadow_map_t * map; + + flags = FREAD|FWRITE; + if (in_kernel) { + NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, vio->vn_file, p); + } + else { + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, vio->vn_file, p); + } + error = vn_open(&nd, flags, 0); + if (error) { + /* shadow MUST be writable! */ + return (error); + } + if (nd.ni_vp->v_type != VREG || + (error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p))) { + VOP_UNLOCK(nd.ni_vp, 0, p); + (void) vn_close(nd.ni_vp, flags, p->p_ucred, p); + return (error ? error : EINVAL); + } + vn->sc_shadow_vp = nd.ni_vp; + vn->sc_shadow_vp->v_flag |= VNOCACHE_DATA; + VOP_UNLOCK(nd.ni_vp, 0, p); + + map = shadow_map_create(vn->sc_fsize, vattr.va_size, + 0, vn->sc_secsize); + if (map == NULL) { + (void) vn_close(nd.ni_vp, flags, p->p_ucred, p); + vn->sc_shadow_vp = NULL; + return (ENOMEM); + } + vn->sc_shadow_map = map; + vn->sc_flags &= ~VNF_READONLY; /* we're now read/write */ + return(0); +} + +int +vndevice_root_image(char * path, char devname[], dev_t * dev_p) +{ + int error = 0; + int flags; + struct vn_softc * vn; + struct vn_ioctl vio; + + vio.vn_file = path; + vio.vn_size = 0; + + vn = vn_table + ROOT_IMAGE_UNIT; + *dev_p = makedev(vndevice_bdev_major, + ROOT_IMAGE_UNIT); + sprintf(devname, "vn%d", ROOT_IMAGE_UNIT); + error = vniocattach_file(vn, &vio, *dev_p, 1, current_proc()); + return (error); +} + +/* + * Duplicate the current processes' credentials. Since we are called only + * as the result of a SET ioctl and only root can do that, any future access + * to this "disk" is essentially as root. Note that credentials may change + * if some other uid can write directly to the mapped file (NFS). + */ +int +vnsetcred(struct vn_softc *vn, struct proc * p) +{ + char *tmpbuf; + int error = 0; + struct proc * current_proc(); + struct ucred * cred = p->p_ucred; + + /* + * Set credits in our softc + */ + + if (vn->sc_cred) + crfree(vn->sc_cred); + vn->sc_cred = crdup(cred); + + /* + * Horrible kludge to establish credentials for NFS XXX. + */ + + if (vn->sc_vp) { + struct uio auio; + struct iovec aiov; + + tmpbuf = _MALLOC(vn->sc_secsize, M_TEMP, M_WAITOK); + bzero(&auio, sizeof(auio)); + + aiov.iov_base = tmpbuf; + aiov.iov_len = vn->sc_secsize; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_offset = 0; + auio.uio_rw = UIO_READ; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_resid = aiov.iov_len; + vn_lock(vn->sc_vp, LK_EXCLUSIVE | LK_RETRY, p); + error = VOP_READ(vn->sc_vp, &auio, 0, vn->sc_cred); + VOP_UNLOCK(vn->sc_vp, 0, p); + FREE(tmpbuf, M_TEMP); + } + return (error); +} + +void +vnclear(struct vn_softc *vn) +{ + int flags; + struct proc * p = current_proc(); /* XXX */ + + if (vn->sc_vp != NULL) { + (void)vn_close(vn->sc_vp, vn->sc_open_flags, vn->sc_cred, p); + vn->sc_vp = NULL; + } + if (vn->sc_shadow_vp != NULL) { + (void)vn_close(vn->sc_shadow_vp, FREAD | FWRITE, + vn->sc_cred, p); + vn->sc_shadow_vp = NULL; + } + if (vn->sc_shadow_map != NULL) { + shadow_map_free(vn->sc_shadow_map); + vn->sc_shadow_map = NULL; + } + vn->sc_flags = ~(VNF_INITED | VNF_READONLY); + if (vn->sc_cred) { + crfree(vn->sc_cred); + vn->sc_cred = NULL; + } + vn->sc_size = 0; + vn->sc_fsize = 0; + if (vn->sc_cdev) { + devfs_remove(vn->sc_cdev); + vn->sc_cdev = NULL; + } +} + +static int +vnsize(dev_t dev) +{ + struct vn_softc *vn; + int unit; + + unit = vnunit(dev); + if (vnunit(dev) >= NVNDEVICE) { + return (ENXIO); + } + vn = vn_table + unit; + + if ((vn->sc_flags & VNF_INITED) == 0) + return(-1); + + return(vn->sc_secsize); +} + +#define CDEV_MAJOR -1 +#define BDEV_MAJOR -1 +static int vndevice_inited = 0; + +void +vndevice_init() +{ + int i; + + if (vndevice_inited) + return; + vndevice_bdev_major = bdevsw_add(BDEV_MAJOR, &vn_bdevsw); + + if (vndevice_bdev_major < 0) { + printf("vndevice_init: bdevsw_add() returned %d\n", + vndevice_bdev_major); + return; + } + vndevice_cdev_major = cdevsw_add_with_bdev(CDEV_MAJOR, &vn_cdevsw, + vndevice_bdev_major); + if (vndevice_cdev_major < 0) { + printf("vndevice_init: cdevsw_add() returned %d\n", + vndevice_cdev_major); + return; + } + for (i = 0; i < NVNDEVICE; i++) { + dev_t dev = makedev(vndevice_bdev_major, i); + vn_table[i].sc_bdev = devfs_make_node(dev, DEVFS_BLOCK, + UID_ROOT, GID_OPERATOR, + 0600, "vn%d", + i); + if (vn_table[i].sc_bdev == NULL) + printf("vninit: devfs_make_node failed!\n"); + } +} +#endif NVNDEVICE diff --git a/bsd/hfs/MacOSStubs.c b/bsd/hfs/MacOSStubs.c index e3ad04615..1dd6e6860 100644 --- a/bsd/hfs/MacOSStubs.c +++ b/bsd/hfs/MacOSStubs.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -19,53 +19,16 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* @(#)MacOSStubs.c 4.0 -* -* (c) 1997-1999 Apple Computer, Inc. All Rights Reserved -* -* MacOSStubs.c -- Contains routines called by MacOS code, that is not defined. -* -* HISTORY -* 9-9-99 Don Brady Don't use MNT_WAIT in C_FlushMDB. -* 9-Mar-1999 Don Brady Remove more obsolete routines, add ClearMemory(bzero). -* 20-Nov-1998 Don Brady Remove UFSToHFSStr and HFSToUFSStr routines (obsolete). -* 31-Aug-1998 Don Brady Move DST adjustments to GetTimeLocal (radar #2265075). -* 28-Jul-1998 Don Brady Add GetDiskBlocks routine (radar #2258148). -* 23-Jul-1998 Don Brady Use bdwrite instead of bwrite for default in RelBlock_glue (radar #2257225). -* 7-Jul-1998 Don Brady Remove character mappings from/to hfs (ufs_hfs and hfs_ufs tables). -* 22-Jun-1998 Pat Dirks Added the vice versa mappings in ufs_hfs and hfs_ufs to more -* thoroughly interchange ":" and "/" in name strings. -* 4-Jun-1998 Pat Dirks Changed to do all B*-Tree writes synchronously (FORCESYNCBTREEWRITES = 1) -* 4-jun-1998 Don Brady Use VPUT macro instead of vput. -* 6-may-1998 Don Brady Bump h_devvp refcount in GetInitializedVNode (radar #2232480). -* 27-apr-1998 Don Brady Change printf to kprintf. -* 23-Apr-1998 Pat Dirks Cleaned up GetBlock_glue to add brelse on I/O errors from bread. -* 23-apr-1998 Don Brady Add '/' to ':' mapping and vice versa to mapping tables. -* 21-apr-1998 Don Brady Clean up time/date conversion routines. -* 11-apr-1998 Don Brady Add RequireFileLock routine. -* 8-apr-1998 Don Brady C_FlushMDB now calls hfs_flushvolumeheader and hfs_flushMDB. -* 12-nov-1997 Scott Roberts -* Initially created file. -* -*/ #include #include #include -#include -#include #include -#include #include -#include -#include + #include "hfs.h" #include "hfs_dbg.h" - - #include "hfscommon/headers/FileMgrInternal.h" -extern int (**hfs_vnodeop_p)(void *); - /* * gTimeZone should only be used for HFS volumes! @@ -73,91 +36,6 @@ extern int (**hfs_vnodeop_p)(void *); */ struct timezone gTimeZone = {8*60,1}; - -/* */ -/* Creates a new vnode to hold a psuedo file like an extents tree file */ -/* */ - -OSStatus GetInitializedVNode(struct hfsmount *hfsmp, struct vnode **tmpvnode) -{ - - struct hfsnode *hp; - struct vnode *vp = NULL; - int rtn; - - DBG_ASSERT(hfsmp != NULL); - DBG_ASSERT(tmpvnode != NULL); - - /* Allocate a new hfsnode. */ - /* - * Must do malloc() before getnewvnode(), since malloc() can block - * and could cause other part of the system to access v_data - * which has not been initialized yet - */ - MALLOC_ZONE(hp, struct hfsnode *, sizeof(struct hfsnode), M_HFSNODE, M_WAITOK); - if(hp == NULL) { - rtn = ENOMEM; - goto Err_Exit; - } - bzero((caddr_t)hp, sizeof(struct hfsnode)); - lockinit(&hp->h_lock, PINOD, "hfsnode", 0, 0); - - MALLOC_ZONE(hp->h_meta, struct hfsfilemeta *, - sizeof(struct hfsfilemeta), M_HFSFMETA, M_WAITOK); - /* Allocate a new vnode. */ - if ((rtn = getnewvnode(VT_HFS, HFSTOVFS(hfsmp), hfs_vnodeop_p, &vp))) { - FREE_ZONE(hp->h_meta, sizeof(struct hfsfilemeta), M_HFSFMETA); - FREE_ZONE(hp, sizeof(struct hfsnode), M_HFSNODE); - goto Err_Exit; - } - - /* Init the structure */ - bzero(hp->h_meta, sizeof(struct hfsfilemeta)); - - hp->h_vp = vp; /* Make HFSTOV work */ - hp->h_meta->h_devvp = hfsmp->hfs_devvp; - hp->h_meta->h_dev = hfsmp->hfs_raw_dev; - hp->h_meta->h_usecount++; - hp->h_nodeflags |= IN_ACCESS | IN_CHANGE | IN_UPDATE; - rl_init(&hp->h_invalidranges); -#if HFS_DIAGNOSTIC - hp->h_valid = HFS_VNODE_MAGIC; -#endif - vp->v_data = hp; /* Make VTOH work */ - vp->v_type = VREG; - /* - * Metadata files are VREG but not available for IO - * through mapped IO as will as POSIX IO APIs. - * Hence we do not initialize UBC for those files - */ - vp->v_ubcinfo = UBC_NOINFO; - - *tmpvnode = vp; - - VREF(hp->h_meta->h_devvp); - - return noErr; - -Err_Exit: - - *tmpvnode = NULL; - - return rtn; -} - -OSErr C_FlushMDB( ExtendedVCB *volume) -{ - short err; - - if (volume->vcbSigWord == kHFSPlusSigWord) - err = hfs_flushvolumeheader(VCBTOHFS(volume), 0); - else - err = hfs_flushMDB(VCBTOHFS(volume), 0); - - return err; -} - - /* * GetTimeUTC - get the GMT Mac OS time (in seconds since 1/1/1904) * @@ -168,22 +46,6 @@ UInt32 GetTimeUTC(void) return (time.tv_sec + MAC_GMT_FACTOR); } -/* - * GetTimeLocal - get the local Mac OS time (in seconds since 1/1/1904) - * - * called by the Catalog Manager when creating/updating HFS records - */ -UInt32 GetTimeLocal(Boolean forHFS) -{ - UInt32 localTime; - - localTime = UTCToLocal(GetTimeUTC()); - - if (forHFS && gTimeZone.tz_dsttime) - localTime += 3600; - - return localTime; -} /* * LocalToUTC - convert from Mac OS local time to Mac OS GMT time. @@ -259,12 +121,6 @@ u_int32_t to_hfs_time(u_int32_t bsd_time) } -void BlockMoveData (const void *srcPtr, void *destPtr, Size byteCount) -{ - bcopy(srcPtr, destPtr, byteCount); -} - - Ptr NewPtrSysClear (Size byteCount) { Ptr tmptr; @@ -296,65 +152,3 @@ void DebugStr (ConstStr255Param debuggerMsg) DEBUG_BREAK; } -OSErr MemError (void) -{ - return 0; -} - - -void ClearMemory( void* start, UInt32 length ) -{ - bzero(start, (size_t)length); -} - - -/* - * RequireFileLock - * - * Check to see if a vnode is locked in the current context - * This is to be used for debugging purposes only!! - */ -#if HFS_DIAGNOSTIC -void RequireFileLock(FileReference vp, int shareable) -{ - struct lock__bsd__ *lkp; - int locked = false; - pid_t pid; - void * self; - - pid = current_proc()->p_pid; - self = (void *) current_thread(); - lkp = &VTOH(vp)->h_lock; - -return; - - simple_lock(&lkp->lk_interlock); - - if (shareable && (lkp->lk_sharecount > 0) && (lkp->lk_lockholder == LK_NOPROC)) - locked = true; - else if ((lkp->lk_exclusivecount > 0) && (lkp->lk_lockholder == pid) && (lkp->lk_lockthread == self)) - locked = true; - - simple_unlock(&lkp->lk_interlock); - - if (!locked) { - DBG_VFS((" # context... self=0x%0X, pid=0x%0X, proc=0x%0X\n", (int)self, pid, (int)current_proc())); - DBG_VFS((" # lock state... thread=0x%0X, holder=0x%0X, ex=%d, sh=%d\n", (int)lkp->lk_lockthread, lkp->lk_lockholder, lkp->lk_exclusivecount, lkp->lk_sharecount)); - - switch (H_FILEID(VTOH(vp))) { - case 3: - DEBUG_BREAK_MSG((" #\n # RequireFileLock: extent btree vnode not locked! v: 0x%08X\n #\n", (u_int)vp)); - break; - - case 4: - DEBUG_BREAK_MSG((" #\n # RequireFileLock: catalog btree vnode not locked! v: 0x%08X\n #\n", (u_int)vp)); - break; - - default: - DEBUG_BREAK_MSG((" #\n # RequireFileLock: file (%d) not locked! v: 0x%08X\n #\n", H_FILEID(VTOH(vp)), (u_int)vp)); - break; - } - } -} -#endif - diff --git a/bsd/hfs/Makefile b/bsd/hfs/Makefile index f628fa341..bea8d9526 100644 --- a/bsd/hfs/Makefile +++ b/bsd/hfs/Makefile @@ -8,14 +8,12 @@ include $(MakeInc_cmd) include $(MakeInc_def) INSTINC_SUBDIRS = \ - hfscommon INSTINC_SUBDIRS_PPC = \ INSTINC_SUBDIRS_I386 = \ EXPINC_SUBDIRS = \ - hfscommon EXPINC_SUBDIRS_PPC = \ @@ -25,7 +23,8 @@ DATAFILES = \ hfs_encodings.h hfs_format.h hfs_mount.h PRIVATE_DATAFILES = \ - hfs.h hfs_macos_defs.h rangelist.h + hfs.h hfs_attrlist.h hfs_catalog.h hfs_cnode.h hfs_endian.h \ + hfs_lockf.h hfs_macos_defs.h hfs_quota.h rangelist.h INSTALL_MI_LIST = ${DATAFILES} diff --git a/bsd/hfs/hfs.h b/bsd/hfs/hfs.h index c88467a1c..9086981b0 100644 --- a/bsd/hfs/hfs.h +++ b/bsd/hfs/hfs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -19,34 +19,32 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* @(#)hfs.h 3.0 -* -* (c) 1990, 1992 NeXT Computer, Inc. All Rights Reserved -* (c) 1997-1999 Apple Computer, Inc. All Rights Reserved -* -* hfs.h -- constants, structures, function declarations. etc. -* for Macintosh file system vfs. -* -*/ #ifndef __HFS__ #define __HFS__ +#include + +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE #include #include #include -#include - +#include +#include +#include +#include #include #include +#include +#include #include #include -#include -struct uio; // This is more effective than #include in case KERNEL is undefined... -struct hfslockf; // For advisory locking +struct uio; // This is more effective than #include in case KERNEL is undefined... +struct hfslockf; /* For advisory locking */ /* * Just reported via MIG interface. @@ -55,10 +53,8 @@ struct hfslockf; // For advisory locking #define HFS_LINK_MAX 32767 -/* - * Set to force READ_ONLY. - */ -#define FORCE_READONLY 0 +#define HFS_MAX_DEFERED_ALLOC (1024*1024) + enum { kMDBSize = 512 }; /* Size of I/O transfer to read entire MDB */ @@ -72,13 +68,9 @@ enum { }; enum { - kUndefinedFork = 0, kDataFork, kRsrcFork, - kDirectory, - kSysFile, - kDefault, - kAnyFork + kDirectory }; /* number of locked buffer caches to hold for b-tree meta data */ @@ -88,73 +80,74 @@ enum { * File type and creator for symbolic links */ enum { - kSymLinkFileType = 0x736C6E6B, /* 'slnk' */ - kSymLinkCreator = 0x72686170 /* 'rhap' */ + kSymLinkFileType = 0x736C6E6B, /* 'slnk' */ + kSymLinkCreator = 0x72686170 /* 'rhap' */ }; -#define BUFFERPTRLISTSIZE 25 - -extern char * gBufferAddress[BUFFERPTRLISTSIZE]; -extern struct buf *gBufferHeaderPtr[BUFFERPTRLISTSIZE]; -extern int gBufferListIndex; -extern simple_lock_data_t gBufferPtrListLock; extern struct timezone gTimeZone; -/* Flag values for bexpand: */ -#define RELEASE_BUFFER 0x00000001 - /* How many free extents to cache per volume */ #define kMaxFreeExtents 10 +/* + * HFS_MINFREE gives the minimum acceptable percentage + * of file system blocks which may be free (but this + * minimum will never exceed HFS_MAXRESERVE bytes). If + * the free block count drops below this level only the + * superuser may continue to allocate blocks. + */ +#define HFS_MINFREE 1 +#define HFS_MAXRESERVE (u_int64_t)(250*1024*1024) + /* Internal Data structures*/ struct vcb_t { u_int16_t vcbSigWord; int16_t vcbAtrb; - int16_t vcbFlags; - int16_t vcbVRefNum; + int16_t vcbFlags; + int16_t vcbspare; u_int32_t vcbCrDate; u_int32_t vcbLsMod; u_int32_t vcbVolBkUp; - u_int32_t checkedDate; /* time of last disk check */ int32_t vcbFilCnt; int32_t vcbDirCnt; - u_int32_t blockSize; /* size of allocation blocks */ - u_int32_t totalBlocks; /* total allocation blocks */ - u_int32_t freeBlocks; /* free allocation blocks */ - u_int32_t nextAllocation; /* start of next allocation search */ + u_int32_t blockSize; /* size of allocation blocks */ + u_int32_t totalBlocks; /* total allocation blocks */ + u_int32_t freeBlocks; /* free allocation blocks */ + u_int32_t nextAllocation; /* start of next allocation search */ int32_t vcbClpSiz; u_int32_t vcbNxtCNID; - u_int32_t vcbCNIDGen; - int32_t vcbWrCnt; + u_int32_t vcbCNIDGen; + int32_t vcbWrCnt; int32_t vcbFndrInfo[8]; u_int64_t encodingsBitmap; /* HFS Plus only */ - u_int16_t vcbNmFls; /* HFS only */ + u_int16_t vcbNmFls; /* HFS only */ u_int16_t vcbNmRtDirs; /* HFS only */ - int16_t vcbVBMSt; /* HFS only */ - int16_t vcbAlBlSt; /* HFS only */ + int16_t vcbVBMSt; /* HFS only */ + int16_t vcbAlBlSt; /* HFS only */ struct vnode * extentsRefNum; struct vnode * catalogRefNum; struct vnode * allocationsRefNum; - u_int8_t vcbVN[256]; /* volume name in UTF-8 */ + u_int8_t vcbVN[256]; /* volume name in UTF-8 */ u_int32_t volumeNameEncodingHint; - u_int32_t altIDSector; /* location of alternate MDB/VH */ - u_int32_t hfsPlusIOPosOffset; /* Disk block where HFS+ starts */ + u_int32_t hfsPlusIOPosOffset; /* Disk block where HFS+ starts */ u_int32_t vcbVBMIOSize; /* volume bitmap I/O size */ - char * hintCachePtr; /* volume heuristicHint cache */ - /* cache of largest known free extents */ - u_int32_t vcbFreeExtCnt; - HFSPlusExtentDescriptor vcbFreeExt[kMaxFreeExtents]; + /* cache of largest known free extents */ + u_int32_t vcbFreeExtCnt; + HFSPlusExtentDescriptor vcbFreeExt[kMaxFreeExtents]; + + u_int32_t reserveBlocks; /* free block reserve */ + u_int32_t loanedBlocks; /* blocks on loan for delayed allocations */ u_int32_t localCreateDate; /* creation times for HFS+ volumes are in local time */ simple_lock_data_t vcbSimpleLock; /* simple lock to allow concurrent access to vcb data */ @@ -162,10 +155,10 @@ struct vcb_t { typedef struct vcb_t ExtendedVCB; -/* vcbFlags */ -#define kHFS_DamagedVolume 0x1 /* This volume has errors, unmount dirty */ -#define MARK_VOLUMEDAMAGED(fcb) FCBTOVCB((fcb))->vcbFlags |= kHFS_DamagedVolume; +#define kHFS_DamagedVolume 0x1 /* This volume has errors, unmount dirty */ +/* XXX */ +#define MARK_VOLUMEDAMAGED(fcb) /* * NOTE: The code relies on being able to cast an ExtendedVCB* to a vfsVCB* in order @@ -184,10 +177,9 @@ typedef struct vfsVCB { /* This structure describes the HFS specific mount structure data. */ typedef struct hfsmount { - u_long hfs_mount_flags; - u_int8_t hfs_fs_clean; /* Whether contents have been flushed in clean state */ u_int8_t hfs_fs_ronly; /* Whether this was mounted as read-initially */ u_int8_t hfs_unknownpermissions; /* Whether this was mounted with MNT_UNKNOWNPERMISSIONS */ + u_int8_t hfs_media_writeable; /* Physical Description */ u_long hfs_phys_block_count; /* Num of PHYSICAL blocks of volume */ @@ -212,164 +204,26 @@ typedef struct hfsmount { /* HFS Specific */ struct vfsVCB hfs_vcb; - u_long hfs_private_metadata_dir; /* private/hidden directory for unlinked files */ + struct cat_desc hfs_privdir_desc; + struct cat_attr hfs_privdir_attr; u_int32_t hfs_metadata_createdate; hfs_to_unicode_func_t hfs_get_unicode; unicode_to_hfs_func_t hfs_get_hfsname; + + struct quotafile hfs_qfiles[MAXQUOTAS]; /* quota files */ } hfsmount_t; -#define HFSPLUS_PRIVATE_DIR \ - "\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80HFS+ Private Data" - - -/***************************************************************************** -* -* hfsnode structure -* -* -* -*****************************************************************************/ +#define hfs_private_metadata_dir hfs_privdir_desc.cd_cnid #define MAXHFSVNODELEN 31 -typedef u_char FileNameStr[MAXHFSVNODELEN+1]; -CIRCLEQ_HEAD(siblinghead, hfsnode) ; /* Head of the sibling list */ +typedef struct filefork FCB; -struct hfsnode { - LIST_ENTRY(hfsnode) h_hash; /* links on valid files */ - CIRCLEQ_ENTRY(hfsnode) h_sibling; /* links on siblings */ - struct lock__bsd__ h_lock; /* node lock. */ - union { - struct hfslockf *hu_lockf; /* Head of byte-level lock list. */ - void *hu_sysdata; /* private data for system files */ - char hu_symlinkdata[4]; /* symbolic link (4 chars or less) */ - char *hu_symlinkptr; /* symbolic link pathname */ - } h_un; - struct vnode * h_vp; /* vnode associated with this inode. */ - struct hfsfilemeta * h_meta; /* Ptr to file meta data */ - u_int16_t h_nodeflags; /* flags, see below */ - u_int8_t h_type; /* Type of info: dir, data, rsrc */ - int8_t fcbFlags; /* FCB flags */ - struct rl_head h_invalidranges;/* Areas of disk that should read back as zeroes */ - u_int64_t fcbEOF; /* Logical length or EOF in bytes */ - u_int64_t fcbPLen; /* Physical file length in bytes */ - u_int32_t fcbClmpSize; /* Number of bytes per clump */ - HFSPlusExtentRecord fcbExtents; /* Extents of file */ - -#if HFS_DIAGNOSTIC - u_int32_t h_valid; /* is the vnode reference valid */ -#endif -}; -#define h_lockf h_un.hu_lockf -#define fcbBTCBPtr h_un.hu_sysdata -#define h_symlinkptr h_un.hu_symlinkptr -#define h_symlinkdata h_un.hu_symlinkdata - -typedef struct hfsnode FCB; - - -typedef struct hfsfilemeta { - struct siblinghead h_siblinghead; /* Head of the sibling list */ - simple_lock_data_t h_siblinglock; /* sibling list lock. */ - u_int32_t h_metaflags; /* IN_LONGNAME, etc */ - struct vnode *h_devvp; /* vnode for block I/O. */ - - dev_t h_dev; /* Device associated with the inode. */ - u_int32_t h_nodeID; /* specific id of this node */ - u_int32_t h_dirID; /* Parent Directory ID */ - u_int32_t h_hint; /* Catalog hint */ - - off_t h_size; /* Total physical size of object */ - u_int16_t h_usecount; /* How many siblings */ - u_int16_t h_mode; /* IFMT, permissions; see below. */ - u_int32_t h_pflags; /* Permission flags (NODUMP, IMMUTABLE, APPEND etc.) */ - u_int32_t h_uid; /* File owner. */ - u_int32_t h_gid; /* File group. */ - union { - dev_t hu_rdev; /* Special device info for this node */ - u_int32_t hu_indnodeno; /* internal indirect node number (never exported) */ - } h_spun; - u_int32_t h_crtime; /* BSD-format creation date in secs. */ - u_int32_t h_atime; /* BSD-format access date in secs. */ - u_int32_t h_mtime; /* BSD-format mod date in seconds */ - u_int32_t h_ctime; /* BSD-format status change date */ - u_int32_t h_butime; /* BSD-format last backup date in secs. */ - u_int16_t h_nlink; /* link count (aprox. for dirs) */ - u_short h_namelen; /* Length of name string */ - char * h_namePtr; /* Points the name of the file */ - FileNameStr h_fileName; /* CName of file */ -} hfsfilemeta; -#define h_rdev h_spun.hu_rdev -#define h_indnodeno h_spun.hu_indnodeno - -#define H_EXTENDSIZE(VP,BYTES) ((VP)->h_meta->h_size += (BYTES)) -#define H_TRUNCSIZE(VP,BYTES) ((VP)->h_meta->h_size -= (BYTES)) #define MAKE_INODE_NAME(name,linkno) \ (void) sprintf((name), "%s%d", HFS_INODE_PREFIX, (linkno)) - -/* - * Macros for quick access to fields buried in the fcb inside an hfs node: - */ -#define H_FORKTYPE(HP) ((HP)->h_type) -#define H_FILEID(HP) ((HP)->h_meta->h_nodeID) -#define H_DIRID(HP) ((HP)->h_meta->h_dirID) -#define H_NAME(HP) ((HP)->h_meta->h_namePtr) -#define H_HINT(HP) ((HP)->h_meta->h_hint) -#define H_DEV(HP) ((HP)->h_meta->h_dev) - -#define H_ISBIGLINK(HP) ((HP)->fcbEOF > 4) -#define H_SYMLINK(HP) (H_ISBIGLINK((HP)) ? (HP)->h_symlinkptr : (HP)->h_symlinkdata) - -/* These flags are kept in flags. */ -#define IN_ACCESS 0x0001 /* Access time update request. */ -#define IN_CHANGE 0x0002 /* Change time update request. */ -#define IN_UPDATE 0x0004 /* Modification time update request. */ -#define IN_MODIFIED 0x0008 /* Node has been modified. */ -#define IN_RENAME 0x0010 /* Node is being renamed. */ -#define IN_SHLOCK 0x0020 /* File has shared lock. */ -#define IN_EXLOCK 0x0040 /* File has exclusive lock. */ -#define IN_BYCNID 0x0100 /* Dir was found by CNID */ -#define IN_ALLOCATING 0x1000 /* vnode is in transit, wait or ignore */ -#define IN_WANT 0x2000 /* Its being waited for */ - -/* These flags are kept in meta flags. */ -#define IN_LONGNAME 0x0400 /* File has long name buffer. */ -#define IN_UNSETACCESS 0x0200 /* File has unset access. */ -#define IN_DELETED 0x0800 /* File has been marked to be deleted */ -#define IN_NOEXISTS 0x1000 /* File has been deleted, catalog entry is gone */ -#if HFS_HARDLINKS -#define IN_DATANODE 0x2000 /* File is a data node (hard-linked) */ -#endif - - -/* File permissions stored in mode */ -#define IEXEC 0000100 /* Executable. */ -#define IWRITE 0000200 /* Writeable. */ -#define IREAD 0000400 /* Readable. */ -#define ISVTX 0001000 /* Sticky bit. */ -#define ISGID 0002000 /* Set-gid. */ -#define ISUID 0004000 /* Set-uid. */ - -/* File types */ -#define IFMT 0170000 /* Mask of file type. */ -#define IFIFO 0010000 /* Named pipe (fifo). */ -#define IFCHR 0020000 /* Character device. */ -#define IFDIR 0040000 /* Directory file. */ -#define IFBLK 0060000 /* Block device. */ -#define IFREG 0100000 /* Regular file. */ -#define IFLNK 0120000 /* Symbolic link. */ -#define IFSOCK 0140000 /* UNIX domain socket. */ -#define IFWHT 0160000 /* Whiteout. */ - -/* Value to make sure vnode is real and defined */ -#define HFS_VNODE_MAGIC 0x4846532b /* 'HFS+' */ - -/* To test wether the forkType is a sibling type */ -#define SIBLING_FORKTYPE(FORK) ((FORK==kDataFork) || (FORK==kRsrcFork)) - /* * Write check macro */ @@ -381,33 +235,6 @@ typedef struct hfsfilemeta { } \ } - -/* - * hfsmount locking and unlocking. - * - * mvl_lock_flags - */ -#define MVL_LOCKED 0x00000001 /* debug only */ - -#if HFS_DIAGNOSTIC -#define MVL_LOCK(mvip) { \ - (simple_lock(&(mvip)->mvl_lock)); \ - (mvip)->mvl_flags |= MVL_LOCKED; \ -} - -#define MVL_UNLOCK(mvip) { \ - if(((mvip)->mvl_flags & MVL_LOCKED) == 0) { \ - panic("MVL_UNLOCK - hfsnode not locked"); \ - } \ - (simple_unlock(&(mvip)->mvl_lock)); \ - (mvip)->mvl_flags &= ~MVL_LOCKED; \ -} -#else /* HFS_DIAGNOSTIC */ -#define MVL_LOCK(mvip) (simple_lock(&(mvip)->mvl_lock)) -#define MVL_UNLOCK(mvip) (simple_unlock(&(mvip)->mvl_lock)) -#endif /* HFS_DIAGNOSTIC */ - - /* structure to hold a "." or ".." directory entry (12 bytes) */ typedef struct hfsdotentry { u_int32_t d_fileno; /* unique file number */ @@ -417,45 +244,13 @@ typedef struct hfsdotentry { char d_name[4]; /* "." or ".." */ } hfsdotentry; -#define AVERAGE_HFSDIRENTRY_SIZE (8+22+4) +#define HFS_AVERAGE_NAME_SIZE 22 +#define AVERAGE_HFSDIRENTRY_SIZE (8+HFS_AVERAGE_NAME_SIZE+4) #define MAX_HFSDIRENTRY_SIZE sizeof(struct dirent) #define DIRENTRY_SIZE(namlen) \ ((sizeof(struct dirent) - (NAME_MAX+1)) + (((namlen)+1 + 3) &~ 3)) -enum { - kCatNameIsAllocated = 0x1, /* The name is malloc'd and is in cnm_nameptr */ - kCatNameIsMangled = 0x2, /* The name is mangled */ - kCatNameUsesReserved = 0x4, /* It overides the space reserved by cnm_namespace into cndu_extra, careful */ - kCatNameIsConsumed = 0x8, /* The name has been already processed, no freeing or work is needed */ - kCatNameNoCopyName = 0x10, /* Dont copy the name */ - kCatNameMangleName = 0x20 /* Mangle name if greater than passed in length */ -}; - -/* - * CatalogNameSpecifier is a structure that contains a name and possibly its form - * - * Special care needs to be taken with the flags, they can cause side effects. - */ -struct CatalogNameSpecifier { - u_int16_t cnm_flags; /* See above */ - u_int16_t cnm_length; /* Length of the name */ - u_int32_t cnm_parID; /* ID of the parent directory */ - unsigned char *cnm_nameptr; /* If allocated, a ptr to the space, else NULL */ - unsigned char cnm_namespace[MAXHFSVNODELEN+1]; /* Space where the name can be kept */ -}; -/* - * NOTE IT IS REQUIRED that KMaxMangleNameLen >= MAXHFSVNODELEN - * Also the total size of CatalogNameSpecifier should be less then cndu_extra, which - * currently it easily is, this is not a requirement, just a nicety. - * - * The rules to how to store a name: - * If its less than MAXHFSVNODELEN always store it in cnm_namespace. - * If we can get by doing mangling then cnm_namespace - * else allocate the space needed to cnm_nameptr. - * This reflects what is done at vnode creation. - */ - enum { kCatalogFolderNode = 1, @@ -469,11 +264,6 @@ enum { * The cnd_extra padding allows big hfs plus thread records (520 bytes max) * to be read onto this stucture during a cnid lookup. * - * IMPORTANT!!!!!! - * After declaring this structure, you must use the macro INIT_CATALOGDATA to prepare it - * and CLEAN_CATALOGDATA after using it, to clean any allocated structures. - * - * If you do not need to have the name, then pass in kCatNameNoCopyName for flags */ struct CatalogNodeData { int16_t cnd_type; @@ -503,7 +293,6 @@ struct CatalogNodeData { u_int32_t cnd_iNodeNumCopy; u_int32_t cnd_linkCNID; /* for hard links only */ u_int8_t cnd_extra[264]; /* make struct at least 520 bytes long */ - struct CatalogNameSpecifier cnd_namespecifier; }; typedef struct CatalogNodeData CatalogNodeData; @@ -511,127 +300,22 @@ typedef struct CatalogNodeData CatalogNodeData; #define cnd_linkCount cnd_un.cndu_linkCount #define cnd_rawDevice cnd_un.cndu_rawDevice -#define cnm_flags cnd_namespecifier.cnm_flags -#define cnm_length cnd_namespecifier.cnm_length -#define cnm_parID cnd_namespecifier.cnm_parID -#define cnm_nameptr cnd_namespecifier.cnm_nameptr -#define cnm_namespace cnd_namespecifier.cnm_namespace - -#define INIT_CATALOGDATA(C,F) do { bzero(&((C)->cnd_namespecifier), sizeof(struct CatalogNameSpecifier)); (C)->cnm_flags=(F);}while(0); -#if HFS_DIAGNOSTIC -extern void debug_check_catalogdata(struct CatalogNodeData *cat); -#define CLEAN_CATALOGDATA(C) do { debug_check_catalogdata(C); \ - if ((C)->cnm_flags & kCatNameIsAllocated) {\ - FREE((C)->cnm_nameptr, M_TEMP);\ - (C)->cnm_flags &= ~kCatNameIsAllocated;\ - (C)->cnm_nameptr = NULL;\ - }}while(0); -#else -#define CLEAN_CATALOGDATA(C) do { if ((C)->cnm_flags & kCatNameIsAllocated) {\ - FREE((C)->cnm_nameptr, M_TEMP);\ - (C)->cnm_flags &= ~kCatNameIsAllocated;\ - (C)->cnm_nameptr = NULL;\ - }}while(0); -#endif - -/* structure to hold a catalog record information */ -/* Of everything you wanted to know about a catalog entry, file and directory */ -typedef struct hfsCatalogInfo { - CatalogNodeData nodeData; - u_int32_t hint; -} hfsCatalogInfo; + enum { kHFSPlusMaxFileNameBytes = kHFSPlusMaxFileNameChars * 3 }; enum { kdirentMaxNameBytes = NAME_MAX }; -// structure definition of the searchfs system trap for the search criterea. -struct directoryInfoSpec -{ - u_long numFiles; -}; - -struct fileInfoSpec -{ - off_t dataLogicalLength; - off_t dataPhysicalLength; - off_t resourceLogicalLength; - off_t resourcePhysicalLength; -}; - -struct searchinfospec -{ - u_char name[kHFSPlusMaxFileNameBytes]; - u_long nameLength; - char attributes; // see IM:Files 2-100 - u_long nodeID; - u_long parentDirID; - struct timespec creationDate; - struct timespec modificationDate; - struct timespec changeDate; - struct timespec lastBackupDate; - u_long finderInfo[8]; - uid_t uid; - gid_t gid; - mode_t mask; - struct fileInfoSpec f; - struct directoryInfoSpec d; -}; -typedef struct searchinfospec searchinfospec_t; - -#define HFSTIMES(hp, t1, t2) { \ - if ((hp)->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) { \ - (hp)->h_nodeflags |= IN_MODIFIED; \ - if ((hp)->h_nodeflags & IN_ACCESS) { \ - (hp)->h_meta->h_atime = (t1)->tv_sec; \ - }; \ - if ((hp)->h_nodeflags & IN_UPDATE) { \ - (hp)->h_meta->h_mtime = (t2)->tv_sec; \ - } \ - if ((hp)->h_nodeflags & IN_CHANGE) { \ - (hp)->h_meta->h_ctime = time.tv_sec; \ - }; \ - (hp)->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE); \ - } \ -} - -/* This overlays the fid structure (see mount.h). */ -struct hfsfid { - u_int16_t hfsfid_len; /* Length of structure. */ - u_int16_t hfsfid_pad; /* Force 32-bit alignment. */ - /* The following data is filesystem-dependent, up to MAXFIDSZ (16) bytes: */ - u_int32_t hfsfid_cnid; /* Catalog node ID. */ - u_int32_t hfsfid_gen; /* Generation number (create date). */ -}; /* macro to determine if hfs or hfsplus */ #define ISHFSPLUS(VCB) ((VCB)->vcbSigWord == kHFSPlusSigWord) #define ISHFS(VCB) ((VCB)->vcbSigWord == kHFSSigWord) -/* - * Various ways to acquire a VNode pointer: - */ -#define HTOV(HP) ((HP)->h_vp) - -/* - * Various ways to acquire an HFS Node pointer: - */ -#define VTOH(VP) ((struct hfsnode *)((VP)->v_data)) -#define FCBTOH(FCB) ((struct hfsnode *)FCB) - -/* - * Various ways to acquire an FCB pointer: - */ -#define HTOFCB(HP) (HP) -#define VTOFCB(VP) ((FCB *)((VP)->v_data)) /* Should be the same as VTOH */ - /* * Various ways to acquire a VFS mount point pointer: */ #define VTOVFS(VP) ((VP)->v_mount) -#define HTOVFS(HP) ((HP)->h_vp->v_mount) -#define FCBTOVFS(FCB) ((FCB)->h_vp->v_mount) #define HFSTOVFS(HFSMP) ((HFSMP)->hfs_mp) #define VCBTOVFS(VCB) (((struct vfsVCB *)(VCB))->vcb_hfsmp->hfs_mp) @@ -639,8 +323,6 @@ struct hfsfid { * Various ways to acquire an HFS mount point pointer: */ #define VTOHFS(VP) ((struct hfsmount *)((VP)->v_mount->mnt_data)) -#define HTOHFS(HP) ((struct hfsmount *)(HP)->h_vp->v_mount->mnt_data) -#define FCBTOHFS(FCB) ((struct hfsmount *)(FCB)->h_vp->v_mount->mnt_data) #define VFSTOHFS(MP) ((struct hfsmount *)(MP)->mnt_data) #define VCBTOHFS(VCB) (((struct vfsVCB *)(VCB))->vcb_hfsmp) @@ -648,8 +330,6 @@ struct hfsfid { * Various ways to acquire a VCB pointer: */ #define VTOVCB(VP) (&(((struct hfsmount *)((VP)->v_mount->mnt_data))->hfs_vcb.vcb_vcb)) -#define HTOVCB(HP) (&(((struct hfsmount *)((HP)->h_vp->v_mount->mnt_data))->hfs_vcb.vcb_vcb)) -#define FCBTOVCB(FCB) (&(((struct hfsmount *)((FCB)->h_vp->v_mount->mnt_data))->hfs_vcb.vcb_vcb)) #define VFSTOVCB(MP) (&(((struct hfsmount *)(MP)->mnt_data)->hfs_vcb.vcb_vcb)) #define HFSTOVCB(HFSMP) (&(HFSMP)->hfs_vcb.vcb_vcb) @@ -657,32 +337,15 @@ struct hfsfid { #define E_NONE 0 #define kHFSBlockSize 512 -#define IOBLKNOFORBLK(STARTINGBLOCK, BLOCKSIZEINBYTES) ((daddr_t)((STARTINGBLOCK) / ((BLOCKSIZEINBYTES) >> 9))) -#define IOBLKCNTFORBLK(STARTINGBLOCK, BYTESTOTRANSFER, BLOCKSIZEINBYTES) \ - ((int)(IOBLKNOFORBYTE(((STARTINGBLOCK) * 512) + (BYTESTOTRANSFER) - 1, (BLOCKSIZEINBYTES)) - \ - IOBLKNOFORBLK((STARTINGBLOCK), (BLOCKSIZEINBYTES)) + 1)) -#define IOBYTECCNTFORBLK(STARTINGBLOCK, BYTESTOTRANSFER, BLOCKSIZEINBYTES) \ - (IOBLKCNTFORBLK((STARTINGBLOCK),(BYTESTOTRANSFER),(BLOCKSIZEINBYTES)) * (BLOCKSIZEINBYTES)) -#define IOBYTEOFFSETFORBLK(STARTINGBLOCK, BLOCKSIZEINBYTES) \ - (((STARTINGBLOCK) * 512) - \ - (IOBLKNOFORBLK((STARTINGBLOCK), (BLOCKSIZEINBYTES)) * (BLOCKSIZEINBYTES))) - -#define IOBLKNOFORBYTE(STARTINGBYTE, BLOCKSIZEINBYTES) ((daddr_t)((STARTINGBYTE) / (BLOCKSIZEINBYTES))) -#define IOBLKCNTFORBYTE(STARTINGBYTE, BYTESTOTRANSFER, BLOCKSIZEINBYTES) \ -((int)(IOBLKNOFORBYTE((STARTINGBYTE) + (BYTESTOTRANSFER) - 1, (BLOCKSIZEINBYTES)) - \ - IOBLKNOFORBYTE((STARTINGBYTE), (BLOCKSIZEINBYTES)) + 1)) -#define IOBYTECNTFORBYTE(STARTINGBYTE, BYTESTOTRANSFER, BLOCKSIZEINBYTES) \ - (IOBLKCNTFORBYTE((STARTINGBYTE),(BYTESTOTRANSFER),(BLOCKSIZEINBYTES)) * (BLOCKSIZEINBYTES)) -#define IOBYTEOFFSETFORBYTE(STARTINGBYTE, BLOCKSIZEINBYTES) ((STARTINGBYTE) - (IOBLKNOFORBYTE((STARTINGBYTE), (BLOCKSIZEINBYTES)) * (BLOCKSIZEINBYTES))) - - -#define HFS_PRI_SECTOR(blksize) (1024 / (blksize)) -#define HFS_PRI_OFFSET(blksize) ((blksize) > 1024 ? 1024 : 0) +/* + * Macros for getting the MDB/VH sector and offset + */ +#define HFS_PRI_SECTOR(blksize) (1024 / (blksize)) +#define HFS_PRI_OFFSET(blksize) ((blksize) > 1024 ? 1024 : 0) #define HFS_ALT_SECTOR(blksize, blkcnt) (((blkcnt) - 1) - (512 / (blksize))) #define HFS_ALT_OFFSET(blksize) ((blksize) > 1024 ? (blksize) - 1024 : 0) -#define MAKE_VREFNUM(x) ((int32_t)((x) & 0xffff)) /* * This is the straight GMT conversion constant: * 00:00:00 January 1, 1970 - 00:00:00 January 1, 1904 @@ -690,83 +353,45 @@ struct hfsfid { */ #define MAC_GMT_FACTOR 2082844800UL -#define HFS_ATTR_CMN_LOOKUPMASK (ATTR_CMN_SCRIPT | ATTR_CMN_FNDRINFO | ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST) -#define HFS_ATTR_DIR_LOOKUPMASK (ATTR_DIR_LINKCOUNT | ATTR_DIR_ENTRYCOUNT) -#define HFS_ATTR_FILE_LOOKUPMASK (ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | ATTR_FILE_ALLOCSIZE | \ - ATTR_FILE_DATALENGTH | ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_DATAEXTENTS | \ - ATTR_FILE_RSRCLENGTH | ATTR_FILE_RSRCALLOCSIZE | ATTR_FILE_RSRCEXTENTS) u_int32_t to_bsd_time(u_int32_t hfs_time); u_int32_t to_hfs_time(u_int32_t bsd_time); -int hfs_flushfiles(struct mount *mp, int flags); -short hfs_flushMDB(struct hfsmount *hfsmp, int waitfor); -short hfs_flushvolumeheader(struct hfsmount *hfsmp, int waitfor); +int hfs_flushfiles(struct mount *mp, int flags, struct proc *p); +int hfs_flushvolumeheader(struct hfsmount *hfsmp, int waitfor, int altflush); +#define HFS_ALTFLUSH 1 -short hfs_getcatalog (ExtendedVCB *vcb, u_int32_t dirID, char *name, short len, hfsCatalogInfo *catInfo); -short hfsMoveRename (ExtendedVCB *vcb, u_int32_t oldDirID, char *oldName, u_int32_t newDirID, char *newName, u_int32_t *hint); -short hfsCreate (ExtendedVCB *vcb, u_int32_t dirID, char *name, int mode, u_int32_t tehint); -short hfsCreateFileID (ExtendedVCB *vcb, u_int32_t parentDirID, StringPtr name, u_int32_t catalogHint, u_int32_t *fileIDPtr); -short hfs_vcreate (ExtendedVCB *vcb, hfsCatalogInfo *catInfo, u_int8_t forkType, struct vnode **vpp); -short hfsDelete (ExtendedVCB *vcb, u_int32_t parentDirID, StringPtr name, short isfile, u_int32_t catalogHint); short hfsUnmount(struct hfsmount *hfsmp, struct proc *p); + +extern int hfs_getcnode(struct hfsmount *hfsmp, cnid_t cnid, struct cat_desc *descp, + int wantrsrc, struct cat_attr *attrp, struct cat_fork *forkp, + struct vnode **vpp); + +extern int hfs_getnewvnode(struct hfsmount *hfsmp, struct cnode *cp, + struct cat_desc *descp, int wantrsrc, struct cat_attr *attrp, + struct cat_fork *forkp, struct vnode **vpp); + extern int hfs_metafilelocking(struct hfsmount *hfsmp, u_long fileID, u_int flags, struct proc *p); -extern int hasOverflowExtents(struct hfsnode *hp); -void hfs_set_metaname(char *, struct hfsfilemeta *, struct hfsmount *); +extern u_int32_t hfs_freeblks(struct hfsmount * hfsmp, int wantreserve); + short MacToVFSError(OSErr err); -int hfs_owner_rights(struct vnode *vp, struct ucred *cred, struct proc *p, Boolean invokesuperuserstatus); -void CopyVNodeToCatalogNode (struct vnode *vp, struct CatalogNodeData *nodeData); -void CopyCatalogToHFSNode(struct hfsCatalogInfo *catalogInfo, struct hfsnode *hp); +extern int hfs_owner_rights(struct hfsmount *hfsmp, uid_t cnode_uid, struct ucred *cred, + struct proc *p, int invokesuperuserstatus); + u_long FindMetaDataDirectory(ExtendedVCB *vcb); +#define kMaxSecsForFsync 5 +#define HFS_SYNCTRANS 1 + +extern int hfs_btsync(struct vnode *vp, int sync_transaction); short make_dir_entry(FCB **fileptr, char *name, u_int32_t fileID); -int AttributeBlockSize(struct attrlist *attrlist); -void PackCommonAttributeBlock(struct attrlist *alist, - struct vnode *vp, - struct hfsCatalogInfo *catInfo, - void **attrbufptrptr, - void **varbufptrptr); -void PackVolAttributeBlock(struct attrlist *alist, - struct vnode *vp, - struct hfsCatalogInfo *catInfo, - void **attrbufptrptr, - void **varbufptrptr); -void PackFileDirAttributeBlock(struct attrlist *alist, - struct vnode *vp, - struct hfsCatalogInfo *catInfo, - void **attrbufptrptr, - void **varbufptrptr); -void PackForkAttributeBlock(struct attrlist *alist, - struct vnode *vp, - struct hfsCatalogInfo *catInfo, - void **attrbufptrptr, - void **varbufptrptr); -void PackAttributeBlock(struct attrlist *alist, - struct vnode *vp, - struct hfsCatalogInfo *catInfo, - void **attrbufptrptr, - void **varbufptrptr); -void PackCatalogInfoAttributeBlock (struct attrlist *alist, - struct vnode * root_vp, - struct hfsCatalogInfo *catInfo, - void **attrbufptrptr, - void **varbufptrptr); -void UnpackCommonAttributeBlock(struct attrlist *alist, - struct vnode *vp, - struct hfsCatalogInfo *catInfo, - void **attrbufptrptr, - void **varbufptrptr); -void UnpackAttributeBlock(struct attrlist *alist, - struct vnode *vp, - struct hfsCatalogInfo *catInfo, - void **attrbufptrptr, - void **varbufptrptr); + unsigned long BestBlockSizeFit(unsigned long allocationBlockSize, unsigned long blockSizeLimit, unsigned long baseMultiple); @@ -774,8 +399,7 @@ unsigned long BestBlockSizeFit(unsigned long allocationBlockSize, OSErr hfs_MountHFSVolume(struct hfsmount *hfsmp, HFSMasterDirectoryBlock *mdb, struct proc *p); OSErr hfs_MountHFSPlusVolume(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp, - off_t embeddedOffset, off_t disksize, struct proc *p); -OSStatus GetInitializedVNode(struct hfsmount *hfsmp, struct vnode **tmpvnode); + off_t embeddedOffset, u_int64_t disksize, struct proc *p); int hfs_getconverter(u_int32_t encoding, hfs_to_unicode_func_t *get_unicode, unicode_to_hfs_func_t *get_hfsname); @@ -795,4 +419,15 @@ int utf8_to_mac_roman(ByteCount srcLen, const unsigned char* srcStr, Str31 dstSt u_int32_t hfs_pickencoding(const u_int16_t *src, int len); +enum volop {VOL_UPDATE, VOL_MKDIR, VOL_RMDIR, VOL_MKFILE, VOL_RMFILE}; + +extern int hfs_volupdate(struct hfsmount *hfsmp, enum volop op, int inroot); + +extern void hfs_setencodingbits(struct hfsmount *hfsmp, u_int32_t encoding); + + +extern void replace_desc(struct cnode *cp, struct cat_desc *cdp); + +#endif /* __APPLE_API_PRIVATE */ +#endif /* KERNEL */ #endif /* __HFS__ */ diff --git a/bsd/hfs/hfs_attrlist.c b/bsd/hfs/hfs_attrlist.c new file mode 100644 index 000000000..650d6fa4a --- /dev/null +++ b/bsd/hfs/hfs_attrlist.c @@ -0,0 +1,1839 @@ +/* + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * hfs_attrlist.c - HFS attribute list processing + * + * Copyright (c) 1998-2002, Apple Computer, Inc. All Rights Reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "hfs.h" +#include "hfs_cnode.h" +#include "hfs_mount.h" +#include "hfs_dbg.h" +#include "hfs_attrlist.h" + + + +extern uid_t console_user; + + +/* Routines that are shared by hfs_setattr: */ +extern int hfs_write_access(struct vnode *vp, struct ucred *cred, + struct proc *p, Boolean considerFlags); + +extern int hfs_chflags(struct vnode *vp, u_long flags, struct ucred *cred, + struct proc *p); + +extern int hfs_chmod(struct vnode *vp, int mode, struct ucred *cred, + struct proc *p); + +extern int hfs_chown(struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred, + struct proc *p); + +extern char * hfs_getnamehint(struct cnode *dcp, int index); + +extern void hfs_savenamehint(struct cnode *dcp, int index, const char * namehint); + +extern void hfs_relnamehint(struct cnode *dcp, int index); + +/* Packing routines: */ + + +static void packvolcommonattr(struct attrblock *abp, struct hfsmount *hfsmp, + struct vnode *vp); + +static void packvolattr(struct attrblock *abp, struct hfsmount *hfsmp, + struct vnode *vp); + +static void packcommonattr(struct attrblock *abp, struct hfsmount *hfsmp, + struct vnode *vp, struct cat_desc * cdp, + struct cat_attr * cap); + +static void packfileattr(struct attrblock *abp, struct hfsmount *hfsmp, + struct cat_attr *cattrp, struct cat_fork *datafork, + struct cat_fork *rsrcfork); + +static void packdirattr(struct attrblock *abp, struct hfsmount *hfsmp, + struct vnode *vp, struct cat_desc * descp, + struct cat_attr * cattrp); + +static void unpackattrblk(struct attrblock *abp, struct vnode *vp); + +static void unpackcommonattr(struct attrblock *abp, struct vnode *vp); + +static void unpackvolattr(struct attrblock *abp, struct hfsmount *hfsmp, + struct vnode *rootvp); + + +/* + +# +#% getattrlist vp = = = +# + vop_getattrlist { + IN struct vnode *vp; + IN struct attrlist *alist; + INOUT struct uio *uio; + IN struct ucred *cred; + IN struct proc *p; + }; + + */ +__private_extern__ +int +hfs_getattrlist(ap) + struct vop_getattrlist_args /* { + struct vnode *a_vp; + struct attrlist *a_alist + struct uio *a_uio; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); + struct hfsmount *hfsmp = VTOHFS(vp); + struct attrlist *alist = ap->a_alist; + struct timeval tv; + int fixedblocksize; + int attrblocksize; + int attrbufsize; + void *attrbufptr; + void *attrptr; + void *varptr; + struct attrblock attrblk; + struct cat_fork *datafp = NULL; + struct cat_fork *rsrcfp = NULL; + struct cat_fork rsrcfork = {0}; + int error = 0; + + if ((alist->bitmapcount != ATTR_BIT_MAP_COUNT) || + ((alist->commonattr & ~ATTR_CMN_VALIDMASK) != 0) || + ((alist->volattr & ~ATTR_VOL_VALIDMASK) != 0) || + ((alist->dirattr & ~ATTR_DIR_VALIDMASK) != 0) || + ((alist->fileattr & ~ATTR_FILE_VALIDMASK) != 0)) { + return (EINVAL); + } + + /* + * Requesting volume information requires setting the + * ATTR_VOL_INFO bit. Also, volume info requests are + * mutually exclusive with all other info requests. + */ + if ((alist->volattr != 0) && + (((alist->volattr & ATTR_VOL_INFO) == 0) || + (alist->dirattr != 0) || (alist->fileattr != 0))) { + return (EINVAL); + } + + /* Reject requests for unsupported options for now: */ + if ((alist->commonattr & (ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST)) || + (alist->fileattr & (ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | ATTR_FILE_FORKLIST))) { + return (EINVAL); + } + + /* Requesting volume information requires root vnode */ + if ((alist->volattr) && cp->c_fileid != kRootDirID) + return (EINVAL); + + /* Asking for data fork attributes from the rsrc fork is not supported */ + if (VNODE_IS_RSRC(vp) && (alist->fileattr & ATTR_DATAFORK_MASK)) + return (EINVAL); + + /* This file no longer exists! */ + if (cp->c_flag & (C_NOEXISTS | C_DELETED)) + return (ENOENT); + + /* This file doesn't have a name! */ + if ((cp->c_desc.cd_namelen == 0) && (alist->commonattr & ATTR_CMN_NAME)) + return (ENOENT); + + /* Update cnode times if needed */ + tv = time; + CTIMES(cp, &tv, &tv); + + /* + * If a File ID (ATTR_CMN_OBJPERMANENTID) is requested on + * an HFS volume we must be sure to create the thread + * record before returning it. (yikes) + */ + if ((vp->v_type == VREG) && + (alist->commonattr & ATTR_CMN_OBJPERMANENTID) && + (VTOVCB(vp)->vcbSigWord != kHFSPlusSigWord)) { + + if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) + return (EROFS); + if ((error = hfs_write_access(vp, ap->a_cred, ap->a_p, false)) != 0) + return (error); + + /* Lock catalog b-tree */ + error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_SHARED, ap->a_p); + if (error) + return (error); + + error = cat_insertfilethread(hfsmp, &cp->c_desc); + + /* Unlock catalog b-tree */ + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, ap->a_p); + if (error) + return (error); + } + + /* Establish known fork data */ + if (cp->c_datafork != NULL) { + datafp = &cp->c_datafork->ff_data; + if ((cp->c_rsrcfork == NULL) && + (cp->c_blocks == datafp->cf_blocks)) + rsrcfp = &rsrcfork; /* rsrc fork is empty */ + } + if (cp->c_rsrcfork != NULL) + rsrcfp = &cp->c_rsrcfork->ff_data; + + /* + * When resource fork data is requested and its not available + * in the cnode and the fork is not empty then it needs to be + * fetched from the catalog. + */ + if ((alist->fileattr & ATTR_RSRCFORK_MASK) && (rsrcfp == NULL)) { + /* Lock catalog b-tree */ + error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_SHARED, ap->a_p); + if (error) + return (error); + + /* Get resource fork data */ + error = cat_lookup(hfsmp, &cp->c_desc, 1, + (struct cat_desc *)0, (struct cat_attr *)0, &rsrcfork); + + /* Unlock the Catalog */ + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, ap->a_p); + if (error) + return (error); + + rsrcfp = &rsrcfork; + } + + fixedblocksize = hfs_attrblksize(alist); + attrblocksize = fixedblocksize + (sizeof(u_long)); /* u_long for length longword */ + if (alist->commonattr & ATTR_CMN_NAME) + attrblocksize += kHFSPlusMaxFileNameBytes + 1; + if (alist->volattr & ATTR_VOL_MOUNTPOINT) + attrblocksize += PATH_MAX; + if (alist->volattr & ATTR_VOL_NAME) + attrblocksize += kHFSPlusMaxFileNameBytes + 1; +#if 0 + if (alist->commonattr & ATTR_CMN_NAMEDATTRLIST) + attrblocksize += 0; + if (alist->fileattr & ATTR_FILE_FORKLIST) + attrblocksize += 0; +#endif + attrbufsize = MIN(ap->a_uio->uio_resid, attrblocksize); + MALLOC(attrbufptr, void *, attrblocksize, M_TEMP, M_WAITOK); + attrptr = attrbufptr; + *((u_long *)attrptr) = 0; /* Set buffer length in case of errors */ + ++((u_long *)attrptr); /* Reserve space for length field */ + varptr = ((char *)attrptr) + fixedblocksize; + + attrblk.ab_attrlist = alist; + attrblk.ab_attrbufpp = &attrptr; + attrblk.ab_varbufpp = &varptr; + attrblk.ab_flags = 0; + attrblk.ab_blocksize = attrblocksize; + + hfs_packattrblk(&attrblk, hfsmp, vp, &cp->c_desc, &cp->c_attr, + datafp, rsrcfp); + + /* Don't copy out more data than was generated */ + attrbufsize = MIN(attrbufsize, (u_int)varptr - (u_int)attrbufptr); + /* Set actual buffer length for return to caller */ + *((u_long *)attrbufptr) = attrbufsize; + error = uiomove((caddr_t)attrbufptr, attrbufsize, ap->a_uio); + + FREE(attrbufptr, M_TEMP); + return (error); +} + + +/* + +# +#% setattrlist vp L L L +# + vop_setattrlist { + IN struct vnode *vp; + IN struct attrlist *alist; + INOUT struct uio *uio; + IN struct ucred *cred; + IN struct proc *p; + }; + + */ +__private_extern__ +int +hfs_setattrlist(ap) + struct vop_setattrlist_args /* { + struct vnode *a_vp; + struct attrlist *a_alist + struct uio *a_uio; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); + struct hfsmount * hfsmp = VTOHFS(vp); + struct attrlist *alist = ap->a_alist; + struct ucred *cred = ap->a_cred; + struct proc *p = ap->a_p; + int attrblocksize; + void *attrbufptr = NULL; + void *attrptr; + void *varptr = NULL; + struct attrblock attrblk; + uid_t saved_uid; + gid_t saved_gid; + mode_t saved_mode; + u_long saved_flags; + int error = 0; + + if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) + return (EROFS); + if ((alist->bitmapcount != ATTR_BIT_MAP_COUNT) || + ((alist->commonattr & ~ATTR_CMN_SETMASK) != 0) || + ((alist->volattr & ~ATTR_VOL_SETMASK) != 0) || + ((alist->dirattr & ~ATTR_DIR_SETMASK) != 0) || + ((alist->fileattr & ~ATTR_FILE_SETMASK) != 0)) { + return (EINVAL); + } + /* + * When setting volume attributes make sure + * that ATTR_VOL_INFO is set and that all + * the attributes are valid. + */ + if ((alist->volattr != 0) && + (((alist->volattr & ATTR_VOL_INFO) == 0) || + (alist->commonattr & ~ATTR_CMN_VOLSETMASK) || + (cp->c_fileid != kRootDirID))) { + if ((alist->volattr & ATTR_VOL_INFO) == 0) + printf("hfs_setattrlist: you forgot to set ATTR_VOL_INFO bit!\n"); + else + printf("hfs_setattrlist: you cannot set bits 0x%08X!\n", + alist->commonattr & ~ATTR_CMN_VOLSETMASK); + return (EINVAL); + } + if (cp->c_flag & (C_NOEXISTS | C_DELETED)) + return (ENOENT); + /* + * Ownership of a file is required in one of two classes of calls: + * + * (a) When setting any ownership-requiring attribute other + * than ATTR_CMN_FLAGS, or + * (b) When setting ATTR_CMN_FLAGS on a volume that's not + * plain HFS (for which no real per-object ownership + * information is stored) + */ + if ((alist->commonattr & (ATTR_OWNERSHIP_SETMASK & ~ATTR_CMN_FLAGS)) || + ((alist->commonattr & ATTR_CMN_FLAGS) && + (VTOVCB(vp)->vcbSigWord != kHFSSigWord))) { + /* + * NOTE: The following isn't ENTIRELY complete: even if + * you're the superuser you cannot change the flags as + * long as SF_IMMUTABLE or SF_APPEND is set and the + * securelevel > 0. This is verified in hfs_chflags + * which gets invoked to do the actual flags field + * change so this check is sufficient for now. + */ + if ((error = hfs_owner_rights(hfsmp, cp->c_uid, cred, p, true)) != 0) + return (error); + } + /* + * For any other attributes, check to see if the user has + * write access to the cnode in question [unlike VOP_ACCESS, + * ignore IMMUTABLE here]: + */ + if (((alist->commonattr & ~ATTR_OWNERSHIP_SETMASK) != 0) || + (alist->volattr != 0) || (alist->dirattr != 0) || + (alist->fileattr != 0)) { + if ((error = hfs_write_access(vp, cred, p, false)) != 0) + return (error); + } + + /* + * Allocate the buffer now to minimize the time we might + * be blocked holding the catalog lock. + */ + attrblocksize = ap->a_uio->uio_resid; + if (attrblocksize < hfs_attrblksize(alist)) + return (EINVAL); + + MALLOC(attrbufptr, void *, attrblocksize, M_TEMP, M_WAITOK); + + error = uiomove((caddr_t)attrbufptr, attrblocksize, ap->a_uio); + if (error) + goto ErrorExit; + + /* Save original state so changes can be detected. */ + saved_uid = cp->c_uid; + saved_gid = cp->c_gid; + saved_mode = cp->c_mode; + saved_flags = cp->c_flags; + + attrptr = attrbufptr; + attrblk.ab_attrlist = alist; + attrblk.ab_attrbufpp = &attrptr; + attrblk.ab_varbufpp = &varptr; + attrblk.ab_flags = 0; + attrblk.ab_blocksize = attrblocksize; + unpackattrblk(&attrblk, vp); + + /* If unpacking changed the owner/group then call hfs_chown() */ + if ((saved_uid != cp->c_uid) || (saved_gid != cp->c_gid)) { + uid_t uid; + gid_t gid; + + uid = cp->c_uid; + cp->c_uid = saved_uid; + gid = cp->c_gid; + cp->c_gid = saved_gid; + if ((error = hfs_chown(vp, uid, gid, cred, p))) + goto ErrorExit; + } + /* If unpacking changed the mode then call hfs_chmod() */ + if (saved_mode != cp->c_mode) { + mode_t mode; + + mode = cp->c_mode; + cp->c_mode = saved_mode; + if ((error = hfs_chmod(vp, mode, cred, p))) + goto ErrorExit; + } + /* If unpacking changed the flags then call hfs_chflags() */ + if (saved_flags !=cp->c_flags) { + u_long flags; + + flags = cp->c_flags; + cp->c_flags = saved_flags; + if ((error = hfs_chflags(vp, flags, cred, p))) + goto ErrorExit; + } + /* + * If any cnode attributes changed then do an update. + */ + if (alist->volattr == 0) { + struct timeval atime, mtime; + + atime.tv_sec = cp->c_atime; + atime.tv_usec = 0; + mtime.tv_sec = cp->c_mtime; + mtime.tv_usec = cp->c_mtime_nsec / 1000; + cp->c_flag |= C_MODIFIED; + if ((error = VOP_UPDATE(vp, &atime, &mtime, 1))) + goto ErrorExit; + } + /* Volume Rename */ + if (alist->volattr & ATTR_VOL_NAME) { + ExtendedVCB *vcb = VTOVCB(vp); + + if (vcb->vcbVN[0] == 0) { + /* + * Ignore attempts to rename a volume to a zero-length name: + * restore the original name from the cnode. + */ + copystr(cp->c_desc.cd_nameptr, vcb->vcbVN, sizeof(vcb->vcbVN), NULL); + } else { + struct cat_desc to_desc = {0}; + struct cat_desc todir_desc = {0}; + struct cat_desc new_desc = {0}; + + todir_desc.cd_parentcnid = kRootParID; + todir_desc.cd_cnid = kRootParID; + todir_desc.cd_flags = CD_ISDIR; + + to_desc.cd_nameptr = vcb->vcbVN; + to_desc.cd_namelen = strlen(vcb->vcbVN); + to_desc.cd_parentcnid = kRootParID; + to_desc.cd_cnid = cp->c_cnid; + to_desc.cd_flags = CD_ISDIR; + + /* Lock catalog b-tree */ + error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p); + if (error) { + /* Restore the old name in the VCB */ + copystr(cp->c_desc.cd_nameptr, vcb->vcbVN, sizeof(vcb->vcbVN), NULL); + vcb->vcbFlags |= 0xFF00; + goto ErrorExit; + } + + error = cat_rename(hfsmp, &cp->c_desc, &todir_desc, &to_desc, &new_desc); + + /* Unlock the Catalog */ + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); + + if (error) { + /* Restore the old name in the VCB */ + copystr(cp->c_desc.cd_nameptr, vcb->vcbVN, sizeof(vcb->vcbVN), NULL); + vcb->vcbFlags |= 0xFF00; + goto ErrorExit; + } + /* Release old allocated name buffer */ + if (cp->c_desc.cd_flags & CD_HASBUF) { + char *name = cp->c_desc.cd_nameptr; + + cp->c_desc.cd_nameptr = 0; + cp->c_desc.cd_namelen = 0; + cp->c_desc.cd_flags &= ~CD_HASBUF; + FREE(name, M_TEMP); + } + /* Update cnode's catalog descriptor */ + replace_desc(cp, &new_desc); + vcb->volumeNameEncodingHint = new_desc.cd_encoding; + cp->c_flag |= C_CHANGE; + } + } + + /* + * When the volume name changes or the volume's finder info + * changes then force them to disk immediately. + */ + if ((alist->volattr & ATTR_VOL_INFO) && + ((alist->volattr & ATTR_VOL_NAME) || + (alist->commonattr & ATTR_CMN_FNDRINFO))) { + (void) hfs_flushvolumeheader(hfsmp, MNT_WAIT, 0); + } +ErrorExit: + if (attrbufptr) + FREE(attrbufptr, M_TEMP); + + return (error); +} + + +/* + * readdirattr operation will return attributes for the items in the + * directory specified. + * + * It does not do . and .. entries. The problem is if you are at the root of the + * hfs directory and go to .. you could be crossing a mountpoint into a + * different (ufs) file system. The attributes that apply for it may not + * apply for the file system you are doing the readdirattr on. To make life + * simpler, this call will only return entries in its directory, hfs like. + * TO DO LATER: + * 1. more than one for uiovcnt support. + * 2. put knohint (hints) in state for next call in + * 3. credentials checking when rest of hfs does it. + * 4. Do return permissions concatenation ??? + */ + +/* +# +#% readdirattr vp L L L +# +vop_readdirattr { + IN struct vnode *vp; + IN struct attrlist *alist; + INOUT struct uio *uio; + IN u_long maxcount: + IN u_long options; + OUT u_long *newstate; + OUT int *eofflag; + OUT u_long *actualCount; + OUT u_long **cookies; + IN struct ucred *cred; +}; +*/ +__private_extern__ +int +hfs_readdirattr(ap) + struct vop_readdirattr_args /* { + struct vnode *a_vp; + struct attrlist *a_alist; + struct uio *a_uio; + u_long a_maxcount; + u_long a_options; + u_long *a_newstate; + int *a_eofflag; + u_long *a_actualcount; + u_long **a_cookies; + struct ucred *a_cred; + } */ *ap; +{ + struct vnode *dvp = ap->a_vp; + struct cnode *dcp = VTOC(dvp); + struct hfsmount * hfsmp = VTOHFS(dvp); + struct attrlist *alist = ap->a_alist; + struct uio *uio = ap->a_uio; + int maxcount = ap->a_maxcount; + struct proc *p = current_proc(); + u_long fixedblocksize; + u_long maxattrblocksize; + u_long currattrbufsize; + void *attrbufptr = NULL; + void *attrptr; + void *varptr; + struct attrblock attrblk; + int error = 0; + int depleted = 0; + int index, startindex; + int i; + struct cat_desc *lastdescp = NULL; + struct cat_desc prevdesc; + char * prevnamebuf = NULL; + struct cat_entrylist *ce_list = NULL; + + *(ap->a_actualcount) = 0; + *(ap->a_eofflag) = 0; + + if (ap->a_cookies != NULL) { + printf("readdirattr: no cookies!\n"); + return (EINVAL); + } + + /* Check for invalid options and buffer space. */ + if (((ap->a_options & ~(FSOPT_NOINMEMUPDATE | FSOPT_NOFOLLOW)) != 0) + || (uio->uio_resid <= 0) || (uio->uio_iovcnt > 1) || (maxcount <= 0)) + return (EINVAL); + + /* This call doesn't take volume attributes. */ + if ((alist->bitmapcount != ATTR_BIT_MAP_COUNT) || + ((alist->commonattr & ~ATTR_CMN_VALIDMASK) != 0) || + (alist->volattr != 0) || + ((alist->dirattr & ~ATTR_DIR_VALIDMASK) != 0) || + ((alist->fileattr & ~ATTR_FILE_VALIDMASK) != 0)) + return (EINVAL); + + /* Reject requests for unsupported options. */ + if ((alist->commonattr & (ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST | + ATTR_CMN_OBJPERMANENTID)) || + (alist->fileattr & (ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | + ATTR_FILE_FORKLIST | ATTR_FILE_DATAEXTENTS | ATTR_FILE_RSRCEXTENTS))) { + printf("readdirattr: unsupported attributes! (%s)\n", dcp->c_desc.cd_nameptr); + return (EINVAL); + } + + /* Convert uio_offset into a directory index. */ + startindex = index = uio->uio_offset / sizeof(struct dirent); + if ((index + 1) > dcp->c_entries) { + *(ap->a_eofflag) = 1; + error = 0; + goto exit; + } + + /* Get a buffer to hold packed attributes. */ + fixedblocksize = (sizeof(u_long) + hfs_attrblksize(alist)); /* u_long for length */ + maxattrblocksize = fixedblocksize; + if (alist->commonattr & ATTR_CMN_NAME) + maxattrblocksize += kHFSPlusMaxFileNameBytes + 1; + MALLOC(attrbufptr, void *, maxattrblocksize, M_TEMP, M_WAITOK); + attrptr = attrbufptr; + varptr = (char *)attrbufptr + fixedblocksize; /* Point to variable-length storage */ + + /* Initialize a catalog entry list. */ + MALLOC(ce_list, struct cat_entrylist *, sizeof(*ce_list), M_TEMP, M_WAITOK); + bzero(ce_list, sizeof(*ce_list)); + ce_list->maxentries = MAXCATENTRIES; + + /* Initialize a starting descriptor. */ + bzero(&prevdesc, sizeof(prevdesc)); + prevdesc.cd_flags = CD_DECOMPOSED; + prevdesc.cd_hint = dcp->c_childhint; + prevdesc.cd_parentcnid = dcp->c_cnid; + prevdesc.cd_nameptr = hfs_getnamehint(dcp, index); + prevdesc.cd_namelen = prevdesc.cd_nameptr ? strlen(prevdesc.cd_nameptr) : 0; + + /* + * Obtain a list of catalog entries and pack their attributes until + * the output buffer is full or maxcount entries have been packed. + */ + while (!depleted) { + int maxentries; + + /* Constrain our list size. */ + maxentries = uio->uio_resid / (fixedblocksize + HFS_AVERAGE_NAME_SIZE); + maxentries = min(maxentries, dcp->c_entries - index); + maxentries = min(maxentries, maxcount); + ce_list->maxentries = min(maxentries, ce_list->maxentries); + lastdescp = NULL; + + /* Lock catalog b-tree. */ + error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_SHARED, p); + if (error) + goto exit; + + error = cat_getentriesattr(hfsmp, &prevdesc, index, ce_list); + /* Don't forget to release the descriptors later! */ + + /* Unlock catalog b-tree. */ + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); + + if (error == ENOENT) { + *(ap->a_eofflag) = TRUE; + error = 0; + depleted = 1; + } + if (error) + break; + + /* Process the catalog entries. */ + for (i = 0; i < ce_list->realentries; ++i) { + struct cnode *cp = NULL; + struct vnode *vp = NULL; + struct vnode *rvp = NULL; + struct cat_desc * cdescp; + struct cat_attr * cattrp; + struct cat_fork c_datafork = {0}; + struct cat_fork c_rsrcfork = {0}; + + cdescp = &ce_list->entry[i].ce_desc; + cattrp = &ce_list->entry[i].ce_attr; + c_datafork.cf_size = ce_list->entry[i].ce_datasize; + c_datafork.cf_blocks = ce_list->entry[i].ce_datablks; + c_rsrcfork.cf_size = ce_list->entry[i].ce_rsrcsize; + c_rsrcfork.cf_blocks = ce_list->entry[i].ce_rsrcblks; + /* + * Get in memory cnode data (if any). + */ + if (!(ap->a_options & FSOPT_NOINMEMUPDATE)) { + cp = hfs_chashget(dcp->c_dev, cattrp->ca_fileid, 0, &vp, &rvp); + if (cp != NULL) { + /* Only use cnode's decriptor for non-hardlinks */ + if (!(cp->c_flag & C_HARDLINK)) + cdescp = &cp->c_desc; + cattrp = &cp->c_attr; + if (cp->c_datafork) { + c_datafork.cf_size = cp->c_datafork->ff_data.cf_size; + c_datafork.cf_clump = cp->c_datafork->ff_data.cf_clump; + c_datafork.cf_blocks = cp->c_datafork->ff_data.cf_blocks; + } + if (cp->c_rsrcfork) { + c_rsrcfork.cf_size = cp->c_rsrcfork->ff_data.cf_size; + c_rsrcfork.cf_clump = cp->c_rsrcfork->ff_data.cf_clump; + c_rsrcfork.cf_blocks = cp->c_rsrcfork->ff_data.cf_blocks; + } + } + } + *((u_long *)attrptr)++ = 0; /* move it past length */ + attrblk.ab_attrlist = alist; + attrblk.ab_attrbufpp = &attrptr; + attrblk.ab_varbufpp = &varptr; + attrblk.ab_flags = 0; + attrblk.ab_blocksize = maxattrblocksize; + + /* Pack catalog entries into attribute buffer. */ + hfs_packattrblk(&attrblk, hfsmp, vp, cdescp, cattrp, + &c_datafork, &c_rsrcfork); + currattrbufsize = ((char *)varptr - (char *)attrbufptr); + + /* All done with cnode. */ + if (vp) { + vput(vp); + vp = NULL; + } else if (rvp) { + vput(rvp); + rvp = NULL; + } + cp = NULL; + + /* Make sure there's enough buffer space remaining. */ + if (currattrbufsize > uio->uio_resid) { + depleted = 1; + break; + } else { + *((u_long *)attrbufptr) = currattrbufsize; + error = uiomove((caddr_t)attrbufptr, currattrbufsize, ap->a_uio); + if (error != E_NONE) { + depleted = 1; + break; + } + attrptr = attrbufptr; + varptr = (char *)attrbufptr + fixedblocksize; /* Point to variable-length storage */ + /* Save the last valid catalog entry */ + lastdescp = &ce_list->entry[i].ce_desc; + index++; + *ap->a_actualcount += 1; + + /* Termination checks */ + if ((--maxcount <= 0) || + (uio->uio_resid < (fixedblocksize + HFS_AVERAGE_NAME_SIZE)) || + (index >= dcp->c_entries)) { + depleted = 1; + break; + } + } + } /* for each catalog entry */ + + /* If there are more entries then save the last name. */ + if (index < dcp->c_entries + && !(*(ap->a_eofflag)) + && lastdescp != NULL) { + if (prevnamebuf == NULL) + MALLOC(prevnamebuf, char *, kHFSPlusMaxFileNameBytes + 1, M_TEMP, M_WAITOK); + bcopy(lastdescp->cd_nameptr, prevnamebuf, lastdescp->cd_namelen + 1); + if (!depleted) { + prevdesc.cd_hint = lastdescp->cd_hint; + prevdesc.cd_nameptr = prevnamebuf; + prevdesc.cd_namelen = lastdescp->cd_namelen + 1; + } + } + + /* All done with the catalog descriptors. */ + for (i = 0; i < ce_list->realentries; ++i) + cat_releasedesc(&ce_list->entry[i].ce_desc); + ce_list->realentries = 0; + + } /* while not depleted */ + + *ap->a_newstate = dcp->c_mtime; + + /* All done with last name hint */ + hfs_relnamehint(dcp, startindex); + startindex = 0; + + /* Convert directory index into uio_offset. */ + uio->uio_offset = index * sizeof(struct dirent); + + /* Save a name hint if there are more entries */ + if ((error == 0) && prevnamebuf && (index + 1) < dcp->c_entries) + hfs_savenamehint(dcp, index, prevnamebuf); +exit: + if (startindex > 0) + hfs_relnamehint(dcp, startindex); + + if (attrbufptr) + FREE(attrbufptr, M_TEMP); + if (ce_list) + FREE(ce_list, M_TEMP); + if (prevnamebuf) + FREE(prevnamebuf, M_TEMP); + + return (error); +} + + +/*==================== Attribute list support routines ====================*/ + +/* + * Pack cnode attributes into an attribute block. + */ + __private_extern__ +void +hfs_packattrblk(struct attrblock *abp, + struct hfsmount *hfsmp, + struct vnode *vp, + struct cat_desc *descp, + struct cat_attr *attrp, + struct cat_fork *datafork, + struct cat_fork *rsrcfork) +{ + struct attrlist *attrlistp = abp->ab_attrlist; + + if (attrlistp->volattr) { + if (attrlistp->commonattr) + packvolcommonattr(abp, hfsmp, vp); + + if (attrlistp->volattr & ~ATTR_VOL_INFO) + packvolattr(abp, hfsmp, vp); + } else { + if (attrlistp->commonattr) + packcommonattr(abp, hfsmp, vp, descp, attrp); + + if (attrlistp->dirattr && S_ISDIR(attrp->ca_mode)) + packdirattr(abp, hfsmp, vp, descp,attrp); + + if (attrlistp->fileattr && !S_ISDIR(attrp->ca_mode)) + packfileattr(abp, hfsmp, attrp, datafork, rsrcfork); + } +} + + +static char* +mountpointname(struct mount *mp) +{ + size_t namelength = strlen(mp->mnt_stat.f_mntonname); + int foundchars = 0; + char *c; + + if (namelength == 0) + return (NULL); + + /* + * Look backwards through the name string, looking for + * the first slash encountered (which must precede the + * last part of the pathname). + */ + for (c = mp->mnt_stat.f_mntonname + namelength - 1; + namelength > 0; --c, --namelength) { + if (*c != '/') { + foundchars = 1; + } else if (foundchars) { + return (c + 1); + } + } + + return (mp->mnt_stat.f_mntonname); +} + + +static void +packnameattr( + struct attrblock *abp, + struct vnode *vp, + char *name, + int namelen) +{ + void *varbufptr; + struct attrreference * attr_refptr; + char *mpname; + size_t mpnamelen; + u_long attrlength; + char empty = 0; + + /* A cnode's name may be incorrect for the root of a mounted + * filesystem (it can be mounted on a different directory name + * than the name of the volume, such as "blah-1"). So for the + * root directory, it's best to return the last element of the + location where the volume's mounted: + */ + if ((vp != NULL) && (vp->v_flag & VROOT) && + (mpname = mountpointname(vp->v_mount))) { + mpnamelen = strlen(mpname); + + /* Trim off any trailing slashes: */ + while ((mpnamelen > 0) && (mpname[mpnamelen-1] == '/')) + --mpnamelen; + + /* If there's anything left, use it instead of the volume's name */ + if (mpnamelen > 0) { + name = mpname; + namelen = mpnamelen; + } + } + if (name == NULL) { + name = ∅ + namelen = 0; + } + + varbufptr = *abp->ab_varbufpp; + attr_refptr = (struct attrreference *)(*abp->ab_attrbufpp); + + attrlength = namelen + 1; + attr_refptr->attr_dataoffset = (char *)varbufptr - (char *)attr_refptr; + attr_refptr->attr_length = attrlength; + (void) strncpy((unsigned char *)varbufptr, name, attrlength); + /* + * Advance beyond the space just allocated and + * round up to the next 4-byte boundary: + */ + (char *)(varbufptr) += attrlength + ((4 - (attrlength & 3)) & 3); + ++attr_refptr; + + *abp->ab_attrbufpp = attr_refptr; + *abp->ab_varbufpp = varbufptr; +} + +/* + * Pack common volume attributes. + */ +static void +packvolcommonattr(struct attrblock *abp, struct hfsmount *hfsmp, struct vnode *vp) +{ + attrgroup_t attr; + void *attrbufptr = *abp->ab_attrbufpp; + void *varbufptr = *abp->ab_varbufpp; + struct cnode *cp = VTOC(vp); + struct mount *mp = VTOVFS(vp); + ExtendedVCB *vcb = HFSTOVCB(hfsmp); + u_long attrlength; + + attr = abp->ab_attrlist->commonattr; + + if (ATTR_CMN_NAME & attr) { + packnameattr(abp, vp, cp->c_desc.cd_nameptr, cp->c_desc.cd_namelen); + attrbufptr = *abp->ab_attrbufpp; + varbufptr = *abp->ab_varbufpp; + } + if (ATTR_CMN_DEVID & attr) { + *((dev_t *)attrbufptr)++ = hfsmp->hfs_raw_dev; + } + if (ATTR_CMN_FSID & attr) { + *((fsid_t *)attrbufptr) = mp->mnt_stat.f_fsid; + ++((fsid_t *)attrbufptr); + } + if (ATTR_CMN_OBJTYPE & attr) { + *((fsobj_type_t *)attrbufptr)++ = 0; + } + if (ATTR_CMN_OBJTAG & attr) { + *((fsobj_tag_t *)attrbufptr)++ = VT_HFS; + } + if (ATTR_CMN_OBJID & attr) { + ((fsobj_id_t *)attrbufptr)->fid_objno = 0; + ((fsobj_id_t *)attrbufptr)->fid_generation = 0; + ++((fsobj_id_t *)attrbufptr); + } + if (ATTR_CMN_OBJPERMANENTID & attr) { + ((fsobj_id_t *)attrbufptr)->fid_objno = 0; + ((fsobj_id_t *)attrbufptr)->fid_generation = 0; + ++((fsobj_id_t *)attrbufptr); + } + if (ATTR_CMN_PAROBJID & attr) { + ((fsobj_id_t *)attrbufptr)->fid_objno = 0; + ((fsobj_id_t *)attrbufptr)->fid_generation = 0; + ++((fsobj_id_t *)attrbufptr); + } + if (ATTR_CMN_SCRIPT & attr) { + u_long encoding; + + if (vcb->vcbSigWord == kHFSPlusSigWord) + encoding = vcb->volumeNameEncodingHint; + else + encoding = hfsmp->hfs_encoding; + *((text_encoding_t *)attrbufptr)++ = encoding; + } + if (ATTR_CMN_CRTIME & attr) { + ((struct timespec *)attrbufptr)->tv_sec = vcb->vcbCrDate; + ((struct timespec *)attrbufptr)->tv_nsec = 0; + ++((struct timespec *)attrbufptr); + } + if (ATTR_CMN_MODTIME & attr) { + ((struct timespec *)attrbufptr)->tv_sec = vcb->vcbLsMod; + ((struct timespec *)attrbufptr)->tv_nsec = 0; + ++((struct timespec *)attrbufptr); + } + if (ATTR_CMN_CHGTIME & attr) { + ((struct timespec *)attrbufptr)->tv_sec = vcb->vcbLsMod; + ((struct timespec *)attrbufptr)->tv_nsec = 0; + ++((struct timespec *)attrbufptr); + } + if (ATTR_CMN_ACCTIME & attr) { + ((struct timespec *)attrbufptr)->tv_sec = vcb->vcbLsMod; + ((struct timespec *)attrbufptr)->tv_nsec = 0; + ++((struct timespec *)attrbufptr); + } + if (ATTR_CMN_BKUPTIME & attr) { + ((struct timespec *)attrbufptr)->tv_sec = vcb->vcbVolBkUp; + ((struct timespec *)attrbufptr)->tv_nsec = 0; + ++((struct timespec *)attrbufptr); + } + if (ATTR_CMN_FNDRINFO & attr) { + bcopy (&vcb->vcbFndrInfo, attrbufptr, sizeof(vcb->vcbFndrInfo)); + (char *)attrbufptr += sizeof(vcb->vcbFndrInfo); + } + if (ATTR_CMN_OWNERID & attr) { + if (cp->c_uid == UNKNOWNUID) + *((uid_t *)attrbufptr)++ = console_user; + else + *((uid_t *)attrbufptr)++ = cp->c_uid; + } + if (ATTR_CMN_GRPID & attr) { + *((gid_t *)attrbufptr)++ = cp->c_gid; + } + if (ATTR_CMN_ACCESSMASK & attr) { + /* + * [2856576] Since we are dynamically changing the owner, also + * effectively turn off the set-user-id and set-group-id bits, + * just like chmod(2) would when changing ownership. This prevents + * a security hole where set-user-id programs run as whoever is + * logged on (or root if nobody is logged in yet!) + */ + *((u_long *)attrbufptr)++ = + (cp->c_uid == UNKNOWNUID) ? cp->c_mode & ~(S_ISUID | S_ISGID) : cp->c_mode; + } + if (ATTR_CMN_NAMEDATTRCOUNT & attr) { + *((u_long *)attrbufptr)++ = 0; /* XXX PPD TBC */ + } + if (ATTR_CMN_NAMEDATTRLIST & attr) { + attrlength = 0; + ((struct attrreference *)attrbufptr)->attr_dataoffset = 0; + ((struct attrreference *)attrbufptr)->attr_length = attrlength; + /* + * Advance beyond the space just allocated and + * round up to the next 4-byte boundary: + */ + (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3); + ++((struct attrreference *)attrbufptr); + } + if (ATTR_CMN_FLAGS & attr) { + *((u_long *)attrbufptr)++ = cp->c_flags; + } + if (ATTR_CMN_USERACCESS & attr) { + *((u_long *)attrbufptr)++ = + DerivePermissionSummary(cp->c_uid, cp->c_gid, cp->c_mode, + VTOVFS(vp), current_proc()->p_ucred, current_proc()); + } + + *abp->ab_attrbufpp = attrbufptr; + *abp->ab_varbufpp = varbufptr; +} + + +static void +packvolattr(struct attrblock *abp, struct hfsmount *hfsmp, struct vnode *vp) +{ + attrgroup_t attr; + void *attrbufptr = *abp->ab_attrbufpp; + void *varbufptr = *abp->ab_varbufpp; + struct cnode *cp = VTOC(vp); + struct mount *mp = VTOVFS(vp); + ExtendedVCB *vcb = HFSTOVCB(hfsmp); + u_long attrlength; + + attr = abp->ab_attrlist->volattr; + + if (ATTR_VOL_FSTYPE & attr) { + *((u_long *)attrbufptr)++ = (u_long)mp->mnt_vfc->vfc_typenum; + } + if (ATTR_VOL_SIGNATURE & attr) { + *((u_long *)attrbufptr)++ = (u_long)vcb->vcbSigWord; + } + if (ATTR_VOL_SIZE & attr) { + *((off_t *)attrbufptr)++ = + (off_t)vcb->totalBlocks * (off_t)vcb->blockSize; + } + if (ATTR_VOL_SPACEFREE & attr) { + *((off_t *)attrbufptr)++ = (off_t)hfs_freeblks(hfsmp, 0) * + (off_t)vcb->blockSize; + + } + if (ATTR_VOL_SPACEAVAIL & attr) { + *((off_t *)attrbufptr)++ = (off_t)hfs_freeblks(hfsmp, 1) * + (off_t)vcb->blockSize; + } + if (ATTR_VOL_MINALLOCATION & attr) { + *((off_t *)attrbufptr)++ = (off_t)vcb->blockSize; + } + if (ATTR_VOL_ALLOCATIONCLUMP & attr) { + *((off_t *)attrbufptr)++ = (off_t)(vcb->vcbClpSiz); + } + if (ATTR_VOL_IOBLOCKSIZE & attr) { + *((u_long *)attrbufptr)++ = (u_long)hfsmp->hfs_logBlockSize; + } + if (ATTR_VOL_OBJCOUNT & attr) { + *((u_long *)attrbufptr)++ = + (u_long)vcb->vcbFilCnt + (u_long)vcb->vcbDirCnt; + } + if (ATTR_VOL_FILECOUNT & attr) { + *((u_long *)attrbufptr)++ = (u_long)vcb->vcbFilCnt; + } + if (ATTR_VOL_DIRCOUNT & attr) { + *((u_long *)attrbufptr)++ = (u_long)vcb->vcbDirCnt; + } + if (ATTR_VOL_MAXOBJCOUNT & attr) { + *((u_long *)attrbufptr)++ = 0xFFFFFFFF; + } + if (ATTR_VOL_MOUNTPOINT & attr) { + ((struct attrreference *)attrbufptr)->attr_dataoffset = + (char *)varbufptr - (char *)attrbufptr; + ((struct attrreference *)attrbufptr)->attr_length = + strlen(mp->mnt_stat.f_mntonname) + 1; + attrlength = ((struct attrreference *)attrbufptr)->attr_length; + /* round up to the next 4-byte boundary: */ + attrlength = attrlength + ((4 - (attrlength & 3)) & 3); + (void) bcopy(mp->mnt_stat.f_mntonname, varbufptr, attrlength); + + /* Advance beyond the space just allocated: */ + (char *)varbufptr += attrlength; + ++((struct attrreference *)attrbufptr); + } + if (ATTR_VOL_NAME & attr) { + ((struct attrreference *)attrbufptr)->attr_dataoffset = + (char *)varbufptr - (char *)attrbufptr; + ((struct attrreference *)attrbufptr)->attr_length = + cp->c_desc.cd_namelen + 1; + attrlength = ((struct attrreference *)attrbufptr)->attr_length; + /* round up to the next 4-byte boundary: */ + attrlength = attrlength + ((4 - (attrlength & 3)) & 3); + /* XXX this could read off the end of cd_nameptr! */ + bcopy(cp->c_desc.cd_nameptr, varbufptr, attrlength); + + /* Advance beyond the space just allocated: */ + (char *)varbufptr += attrlength; + ++((struct attrreference *)attrbufptr); + } + if (ATTR_VOL_MOUNTFLAGS & attr) { + *((u_long *)attrbufptr)++ = (u_long)mp->mnt_flag; + } + if (ATTR_VOL_MOUNTEDDEVICE & attr) { + ((struct attrreference *)attrbufptr)->attr_dataoffset = + (char *)varbufptr - (char *)attrbufptr; + ((struct attrreference *)attrbufptr)->attr_length = + strlen(mp->mnt_stat.f_mntfromname) + 1; + attrlength = ((struct attrreference *)attrbufptr)->attr_length; + /* round up to the next 4-byte boundary: */ + attrlength = attrlength + ((4 - (attrlength & 3)) & 3); + (void) bcopy(mp->mnt_stat.f_mntfromname, varbufptr, attrlength); + + /* Advance beyond the space just allocated: */ + (char *)varbufptr += attrlength; + ++((struct attrreference *)attrbufptr); + } + if (ATTR_VOL_ENCODINGSUSED & attr) { + *((unsigned long long *)attrbufptr)++ = + (unsigned long long)vcb->encodingsBitmap; + } + if (ATTR_VOL_CAPABILITIES & attr) { + vol_capabilities_attr_t *vcapattrptr; + + vcapattrptr = (vol_capabilities_attr_t *)attrbufptr; + + if (vcb->vcbSigWord == kHFSPlusSigWord) { + vcapattrptr->capabilities[VOL_CAPABILITIES_FORMAT] = + VOL_CAP_FMT_PERSISTENTOBJECTIDS | + VOL_CAP_FMT_SYMBOLICLINKS | + VOL_CAP_FMT_HARDLINKS; + } else { /* Plain HFS */ + vcapattrptr->capabilities[VOL_CAPABILITIES_FORMAT] = + VOL_CAP_FMT_PERSISTENTOBJECTIDS; + } + vcapattrptr->capabilities[VOL_CAPABILITIES_INTERFACES] = + VOL_CAP_INT_SEARCHFS | + VOL_CAP_INT_ATTRLIST | + VOL_CAP_INT_NFSEXPORT | + VOL_CAP_INT_READDIRATTR ; + vcapattrptr->capabilities[VOL_CAPABILITIES_RESERVED1] = 0; + vcapattrptr->capabilities[VOL_CAPABILITIES_RESERVED2] = 0; + + vcapattrptr->valid[VOL_CAPABILITIES_FORMAT] = + VOL_CAP_FMT_PERSISTENTOBJECTIDS | + VOL_CAP_FMT_SYMBOLICLINKS | + VOL_CAP_FMT_HARDLINKS; + vcapattrptr->valid[VOL_CAPABILITIES_INTERFACES] = + VOL_CAP_INT_SEARCHFS | + VOL_CAP_INT_ATTRLIST | + VOL_CAP_INT_NFSEXPORT | + VOL_CAP_INT_READDIRATTR ; + vcapattrptr->valid[VOL_CAPABILITIES_RESERVED1] = 0; + vcapattrptr->valid[VOL_CAPABILITIES_RESERVED2] = 0; + + ++((vol_capabilities_attr_t *)attrbufptr); + } + if (ATTR_VOL_ATTRIBUTES & attr) { + vol_attributes_attr_t *volattrattrp; + + volattrattrp = (vol_attributes_attr_t *)attrbufptr; + volattrattrp->validattr.commonattr = ATTR_CMN_VALIDMASK; + volattrattrp->validattr.volattr = ATTR_VOL_VALIDMASK; + volattrattrp->validattr.dirattr = ATTR_DIR_VALIDMASK; + volattrattrp->validattr.fileattr = ATTR_FILE_VALIDMASK; + volattrattrp->validattr.forkattr = ATTR_FORK_VALIDMASK; + + volattrattrp->nativeattr.commonattr = ATTR_CMN_VALIDMASK; + volattrattrp->nativeattr.volattr = ATTR_VOL_VALIDMASK; + volattrattrp->nativeattr.dirattr = ATTR_DIR_VALIDMASK; + volattrattrp->nativeattr.fileattr = ATTR_FILE_VALIDMASK; + volattrattrp->nativeattr.forkattr = ATTR_FORK_VALIDMASK; + ++((vol_attributes_attr_t *)attrbufptr); + } + + *abp->ab_attrbufpp = attrbufptr; + *abp->ab_varbufpp = varbufptr; +} + + +static void +packcommonattr( + struct attrblock *abp, + struct hfsmount *hfsmp, + struct vnode *vp, + struct cat_desc * cdp, + struct cat_attr * cap) +{ + attrgroup_t attr = abp->ab_attrlist->commonattr; + struct mount *mp = HFSTOVFS(hfsmp); + void *attrbufptr = *abp->ab_attrbufpp; + void *varbufptr = *abp->ab_varbufpp; + u_long attrlength = 0; + + if (ATTR_CMN_NAME & attr) { + packnameattr(abp, vp, cdp->cd_nameptr, cdp->cd_namelen); + attrbufptr = *abp->ab_attrbufpp; + varbufptr = *abp->ab_varbufpp; + } + if (ATTR_CMN_DEVID & attr) { + *((dev_t *)attrbufptr)++ = hfsmp->hfs_raw_dev; + } + if (ATTR_CMN_FSID & attr) { + *((fsid_t *)attrbufptr) = mp->mnt_stat.f_fsid; + ++((fsid_t *)attrbufptr); + } + if (ATTR_CMN_OBJTYPE & attr) { + *((fsobj_type_t *)attrbufptr)++ = IFTOVT(cap->ca_mode); + } + if (ATTR_CMN_OBJTAG & attr) { + *((fsobj_tag_t *)attrbufptr)++ = VT_HFS; + } + /* + * Exporting file IDs from HFS Plus: + * + * For "normal" files the c_fileid is the same value as the + * c_cnid. But for hard link files, they are different - the + * c_cnid belongs to the active directory entry (ie the link) + * and the c_fileid is for the actual inode (ie the data file). + * + * The stat call (getattr) will always return the c_fileid + * and Carbon APIs, which are hardlink-ignorant, will always + * receive the c_cnid (from getattrlist). + */ + if (ATTR_CMN_OBJID & attr) { + ((fsobj_id_t *)attrbufptr)->fid_objno = cdp->cd_cnid; + ((fsobj_id_t *)attrbufptr)->fid_generation = 0; + ++((fsobj_id_t *)attrbufptr); + } + if (ATTR_CMN_OBJPERMANENTID & attr) { + ((fsobj_id_t *)attrbufptr)->fid_objno = cdp->cd_cnid; + ((fsobj_id_t *)attrbufptr)->fid_generation = 0; + ++((fsobj_id_t *)attrbufptr); + } + if (ATTR_CMN_PAROBJID & attr) { + ((fsobj_id_t *)attrbufptr)->fid_objno = cdp->cd_parentcnid; + ((fsobj_id_t *)attrbufptr)->fid_generation = 0; + ++((fsobj_id_t *)attrbufptr); + } + if (ATTR_CMN_SCRIPT & attr) { + *((text_encoding_t *)attrbufptr)++ = cdp->cd_encoding; + } + if (ATTR_CMN_CRTIME & attr) { + ((struct timespec *)attrbufptr)->tv_sec = cap->ca_itime; + ((struct timespec *)attrbufptr)->tv_nsec = 0; + ++((struct timespec *)attrbufptr); + } + if (ATTR_CMN_MODTIME & attr) { + ((struct timespec *)attrbufptr)->tv_sec = cap->ca_mtime; + ((struct timespec *)attrbufptr)->tv_nsec = 0; + ++((struct timespec *)attrbufptr); + } + if (ATTR_CMN_CHGTIME & attr) { + ((struct timespec *)attrbufptr)->tv_sec = cap->ca_ctime; + ((struct timespec *)attrbufptr)->tv_nsec = 0; + ++((struct timespec *)attrbufptr); + } + if (ATTR_CMN_ACCTIME & attr) { + ((struct timespec *)attrbufptr)->tv_sec = cap->ca_atime; + ((struct timespec *)attrbufptr)->tv_nsec = 0; + ++((struct timespec *)attrbufptr); + } + if (ATTR_CMN_BKUPTIME & attr) { + ((struct timespec *)attrbufptr)->tv_sec = cap->ca_btime; + ((struct timespec *)attrbufptr)->tv_nsec = 0; + ++((struct timespec *)attrbufptr); + } + if (ATTR_CMN_FNDRINFO & attr) { + bcopy(&cap->ca_finderinfo, attrbufptr, sizeof(u_int8_t) * 32); + (char *)attrbufptr += sizeof(u_int8_t) * 32; + } + if (ATTR_CMN_OWNERID & attr) { + *((uid_t *)attrbufptr)++ = + (cap->ca_uid == UNKNOWNUID) ? console_user : cap->ca_uid; + } + if (ATTR_CMN_GRPID & attr) { + *((gid_t *)attrbufptr)++ = cap->ca_gid; + } + if (ATTR_CMN_ACCESSMASK & attr) { + /* + * [2856576] Since we are dynamically changing the owner, also + * effectively turn off the set-user-id and set-group-id bits, + * just like chmod(2) would when changing ownership. This prevents + * a security hole where set-user-id programs run as whoever is + * logged on (or root if nobody is logged in yet!) + */ + *((u_long *)attrbufptr)++ = + (cap->ca_uid == UNKNOWNUID) ? cap->ca_mode & ~(S_ISUID | S_ISGID) : cap->ca_mode; + } + if (ATTR_CMN_NAMEDATTRCOUNT & attr) { + *((u_long *)attrbufptr)++ = 0; + } + if (ATTR_CMN_NAMEDATTRLIST & attr) { + attrlength = 0; + ((struct attrreference *)attrbufptr)->attr_dataoffset = 0; + ((struct attrreference *)attrbufptr)->attr_length = attrlength; + /* + * Advance beyond the space just allocated and + * round up to the next 4-byte boundary: + */ + (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3); + ++((struct attrreference *)attrbufptr); + } + if (ATTR_CMN_FLAGS & attr) { + *((u_long *)attrbufptr)++ = cap->ca_flags; + } + if (ATTR_CMN_USERACCESS & attr) { + *((u_long *)attrbufptr)++ = + DerivePermissionSummary(cap->ca_uid, cap->ca_gid, + cap->ca_mode, mp, current_proc()->p_ucred, + current_proc()); + } + + *abp->ab_attrbufpp = attrbufptr; + *abp->ab_varbufpp = varbufptr; +} + +static void +packdirattr( + struct attrblock *abp, + struct hfsmount *hfsmp, + struct vnode *vp, + struct cat_desc * descp, + struct cat_attr * cattrp) +{ + attrgroup_t attr = abp->ab_attrlist->dirattr; + void *attrbufptr = *abp->ab_attrbufpp; + + if (ATTR_DIR_LINKCOUNT & attr) + *((u_long *)attrbufptr)++ = cattrp->ca_nlink; + if (ATTR_DIR_ENTRYCOUNT & attr) { + u_long entries = cattrp->ca_entries; + + if ((descp->cd_parentcnid == kRootParID) && + (hfsmp->hfs_private_metadata_dir != 0)) + --entries; /* hide private dir */ + + *((u_long *)attrbufptr)++ = entries; + } + if (ATTR_DIR_MOUNTSTATUS & attr) { + if (vp != NULL && vp->v_mountedhere != NULL) + *((u_long *)attrbufptr)++ = DIR_MNTSTATUS_MNTPOINT; + else + *((u_long *)attrbufptr)++ = 0; + } + *abp->ab_attrbufpp = attrbufptr; +} + +static void +packfileattr( + struct attrblock *abp, + struct hfsmount *hfsmp, + struct cat_attr *cattrp, + struct cat_fork *datafork, + struct cat_fork *rsrcfork) +{ + attrgroup_t attr = abp->ab_attrlist->fileattr; + void *attrbufptr = *abp->ab_attrbufpp; + void *varbufptr = *abp->ab_varbufpp; + u_long attrlength; + u_long allocblksize; + + allocblksize = HFSTOVCB(hfsmp)->blockSize; + + if (ATTR_FILE_LINKCOUNT & attr) { + *((u_long *)attrbufptr)++ = cattrp->ca_nlink; + } + if (ATTR_FILE_TOTALSIZE & attr) { + *((off_t *)attrbufptr)++ = datafork->cf_size + rsrcfork->cf_size; + } + if (ATTR_FILE_ALLOCSIZE & attr) { + *((off_t *)attrbufptr)++ = + (off_t)cattrp->ca_blocks * (off_t)allocblksize; + } + if (ATTR_FILE_IOBLOCKSIZE & attr) { + *((u_long *)attrbufptr)++ = hfsmp->hfs_logBlockSize; + } + if (ATTR_FILE_CLUMPSIZE & attr) { + *((u_long *)attrbufptr)++ = datafork->cf_clump; /* XXX ambiguity */ + } + if (ATTR_FILE_DEVTYPE & attr) { + if (S_ISBLK(cattrp->ca_mode) || S_ISCHR(cattrp->ca_mode)) + *((u_long *)attrbufptr)++ = (u_long)cattrp->ca_rdev; + else + *((u_long *)attrbufptr)++ = 0; + } + if (ATTR_FILE_FILETYPE & attr) { + *((u_long *)attrbufptr)++ = 0; + } + if (ATTR_FILE_FORKCOUNT & attr) { + *((u_long *)attrbufptr)++ = 2; + } + if (ATTR_FILE_FORKLIST & attr) { + attrlength = 0; + ((struct attrreference *)attrbufptr)->attr_dataoffset = 0; + ((struct attrreference *)attrbufptr)->attr_length = attrlength; + /* + * Advance beyond the space just allocated and + * round up to the next 4-byte boundary: + */ + (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3); + ++((struct attrreference *)attrbufptr); + } + if (ATTR_FILE_DATALENGTH & attr) { + *((off_t *)attrbufptr)++ = datafork->cf_size; + } + if (ATTR_FILE_DATAALLOCSIZE & attr) { + *((off_t *)attrbufptr)++ = + (off_t)datafork->cf_blocks * (off_t)allocblksize; + } + if (ATTR_FILE_DATAEXTENTS & attr) { + bcopy(&datafork->cf_extents, attrbufptr, sizeof(extentrecord)); + (char *)attrbufptr += sizeof(extentrecord); + } + if (ATTR_FILE_RSRCLENGTH & attr) { + *((off_t *)attrbufptr)++ = rsrcfork->cf_size; + } + if (ATTR_FILE_RSRCALLOCSIZE & attr) { + *((off_t *)attrbufptr)++ = + (off_t)rsrcfork->cf_blocks * (off_t)allocblksize; + } + if (ATTR_FILE_RSRCEXTENTS & attr) { + bcopy(&rsrcfork->cf_extents, attrbufptr, sizeof(extentrecord)); + (char *)attrbufptr += sizeof(extentrecord); + } + *abp->ab_attrbufpp = attrbufptr; + *abp->ab_varbufpp = varbufptr; +} + + +static void +unpackattrblk(struct attrblock *abp, struct vnode *vp) +{ + struct attrlist *attrlistp = abp->ab_attrlist; + + if (attrlistp->volattr) + unpackvolattr(abp, VTOHFS(vp), vp); + else if (attrlistp->commonattr) + unpackcommonattr(abp, vp); +} + + +static void +unpackcommonattr( + struct attrblock *abp, + struct vnode *vp) +{ + attrgroup_t attr = abp->ab_attrlist->commonattr; + void *attrbufptr = *abp->ab_attrbufpp; + struct cnode *cp = VTOC(vp); + + if (ATTR_CMN_SCRIPT & attr) { + cp->c_encoding = (u_int32_t)*((text_encoding_t *)attrbufptr)++; + hfs_setencodingbits(VTOHFS(vp), cp->c_encoding); + } + if (ATTR_CMN_CRTIME & attr) { + cp->c_itime = ((struct timespec *)attrbufptr)->tv_sec; + ++((struct timespec *)attrbufptr); + } + if (ATTR_CMN_MODTIME & attr) { + cp->c_mtime = ((struct timespec *)attrbufptr)->tv_sec; + cp->c_mtime_nsec = ((struct timespec *)attrbufptr)->tv_nsec; + ++((struct timespec *)attrbufptr); + cp->c_flag &= ~C_UPDATE; + } + if (ATTR_CMN_CHGTIME & attr) { + cp->c_ctime = ((struct timespec *)attrbufptr)->tv_sec; + ++((struct timespec *)attrbufptr); + cp->c_flag &= ~C_CHANGE; + } + if (ATTR_CMN_ACCTIME & attr) { + cp->c_atime = ((struct timespec *)attrbufptr)->tv_sec; + ++((struct timespec *)attrbufptr); + cp->c_flag &= ~C_ACCESS; + } + if (ATTR_CMN_BKUPTIME & attr) { + cp->c_btime = ((struct timespec *)attrbufptr)->tv_sec; + ++((struct timespec *)attrbufptr); + } + if (ATTR_CMN_FNDRINFO & attr) { + bcopy(attrbufptr, &cp->c_attr.ca_finderinfo, + sizeof(cp->c_attr.ca_finderinfo)); + (char *)attrbufptr += sizeof(cp->c_attr.ca_finderinfo); + } + if (ATTR_CMN_OWNERID & attr) { + if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) { + u_int32_t uid = (u_int32_t)*((uid_t *)attrbufptr)++; + if (uid != (uid_t)VNOVAL) + cp->c_uid = uid; + } else { + ((uid_t *)attrbufptr)++; + } + } + if (ATTR_CMN_GRPID & attr) { + u_int32_t gid = (u_int32_t)*((gid_t *)attrbufptr)++; + if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) { + if (gid != (gid_t)VNOVAL) + cp->c_gid = gid; + } + } + if (ATTR_CMN_ACCESSMASK & attr) { + u_int16_t mode = (u_int16_t)*((u_long *)attrbufptr)++; + if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) { + if (mode != (mode_t)VNOVAL) { + cp->c_mode &= ~ALLPERMS; + cp->c_mode |= (mode & ALLPERMS); + } + } + } + if (ATTR_CMN_FLAGS & attr) { + u_long flags = *((u_long *)attrbufptr)++; + /* + * Flags are settable only on HFS+ volumes. A special + * exception is made for the IMMUTABLE flags + * (SF_IMMUTABLE and UF_IMMUTABLE), which can be set on + * HFS volumes as well: + */ + if ((VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) || + ((VTOVCB(vp)->vcbSigWord == kHFSSigWord) && + ((flags & ~IMMUTABLE) == 0))) { + if (flags != (u_long)VNOVAL) { + cp->c_flags = flags; + } + } + } + *abp->ab_attrbufpp = attrbufptr; +} + + +static void +unpackvolattr( + struct attrblock *abp, + struct hfsmount *hfsmp, + struct vnode *rootvp) +{ + void *attrbufptr = *abp->ab_attrbufpp; + ExtendedVCB *vcb = HFSTOVCB(hfsmp); + attrgroup_t attr; + + attr = abp->ab_attrlist->commonattr; + if (attr == 0) + goto volattr; + + if (ATTR_CMN_SCRIPT & attr) { + vcb->volumeNameEncodingHint = + (u_int32_t)*(((text_encoding_t *)attrbufptr)++); + } + if (ATTR_CMN_CRTIME & attr) { + vcb->vcbCrDate = ((struct timespec *)attrbufptr)->tv_sec; + ++((struct timespec *)attrbufptr); + + /* The volume's create date comes from the root directory */ + VTOC(rootvp)->c_itime = vcb->vcbCrDate; + VTOC(rootvp)->c_flag |= C_MODIFIED; + /* + * XXX Should we also do a relative change to the + * the volume header's create date in local time? + */ + } + if (ATTR_CMN_MODTIME & attr) { + vcb->vcbLsMod = ((struct timespec *)attrbufptr)->tv_sec; + ++((struct timespec *)attrbufptr); + } + if (ATTR_CMN_BKUPTIME & attr) { + vcb->vcbVolBkUp = ((struct timespec *)attrbufptr)->tv_sec; + ++((struct timespec *)attrbufptr); + } + if (ATTR_CMN_FNDRINFO & attr) { + bcopy(attrbufptr, &vcb->vcbFndrInfo, sizeof(vcb->vcbFndrInfo)); + (char *)attrbufptr += sizeof(vcb->vcbFndrInfo); + } + +volattr: + attr = abp->ab_attrlist->volattr & ~ATTR_VOL_INFO; + /* + * XXX - no validation is done on the name! + * It could be empty or garbage (bad UTF-8). + */ + if (ATTR_VOL_NAME & attr) { + copystr(((char *)attrbufptr) + *((u_long *)attrbufptr), + vcb->vcbVN, sizeof(vcb->vcbVN), NULL); + (char *)attrbufptr += sizeof(struct attrreference); + } + *abp->ab_attrbufpp = attrbufptr; + + vcb->vcbFlags |= 0xFF00; +} + +/* + * Calculate the total size of an attribute block. + */ + __private_extern__ +int +hfs_attrblksize(struct attrlist *attrlist) +{ + int size; + attrgroup_t a; + +#if ((ATTR_CMN_NAME | ATTR_CMN_DEVID | ATTR_CMN_FSID | ATTR_CMN_OBJTYPE | \ + ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | ATTR_CMN_OBJPERMANENTID | \ + ATTR_CMN_PAROBJID | ATTR_CMN_SCRIPT | ATTR_CMN_CRTIME | \ + ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | ATTR_CMN_ACCTIME | \ + ATTR_CMN_BKUPTIME | ATTR_CMN_FNDRINFO | ATTR_CMN_OWNERID | \ + ATTR_CMN_GRPID | ATTR_CMN_ACCESSMASK | ATTR_CMN_NAMEDATTRCOUNT | \ + ATTR_CMN_NAMEDATTRLIST | ATTR_CMN_FLAGS | ATTR_CMN_USERACCESS) \ + != ATTR_CMN_VALIDMASK) +#error hfs_attrblksize: Missing bits in common mask computation! +#endif + DBG_ASSERT((attrlist->commonattr & ~ATTR_CMN_VALIDMASK) == 0); + +#if ((ATTR_VOL_FSTYPE | ATTR_VOL_SIGNATURE | ATTR_VOL_SIZE | \ + ATTR_VOL_SPACEFREE | ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | \ + ATTR_VOL_ALLOCATIONCLUMP | ATTR_VOL_IOBLOCKSIZE | \ + ATTR_VOL_OBJCOUNT | ATTR_VOL_FILECOUNT | ATTR_VOL_DIRCOUNT | \ + ATTR_VOL_MAXOBJCOUNT | ATTR_VOL_MOUNTPOINT | ATTR_VOL_NAME | \ + ATTR_VOL_MOUNTFLAGS | ATTR_VOL_INFO | ATTR_VOL_MOUNTEDDEVICE | \ + ATTR_VOL_ENCODINGSUSED | ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES) \ + != ATTR_VOL_VALIDMASK) +#error hfs_attrblksize: Missing bits in volume mask computation! +#endif + DBG_ASSERT((attrlist->volattr & ~ATTR_VOL_VALIDMASK) == 0); + +#if ((ATTR_DIR_LINKCOUNT | ATTR_DIR_ENTRYCOUNT | ATTR_DIR_MOUNTSTATUS) \ + != ATTR_DIR_VALIDMASK) +#error hfs_attrblksize: Missing bits in directory mask computation! +#endif + DBG_ASSERT((attrlist->dirattr & ~ATTR_DIR_VALIDMASK) == 0); + +#if ((ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | ATTR_FILE_ALLOCSIZE | \ + ATTR_FILE_IOBLOCKSIZE | ATTR_FILE_CLUMPSIZE | ATTR_FILE_DEVTYPE | \ + ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | ATTR_FILE_FORKLIST | \ + ATTR_FILE_DATALENGTH | ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_DATAEXTENTS | \ + ATTR_FILE_RSRCLENGTH | ATTR_FILE_RSRCALLOCSIZE | ATTR_FILE_RSRCEXTENTS) \ + != ATTR_FILE_VALIDMASK) +#error hfs_attrblksize: Missing bits in file mask computation! +#endif + DBG_ASSERT((attrlist->fileattr & ~ATTR_FILE_VALIDMASK) == 0); + +#if ((ATTR_FORK_TOTALSIZE | ATTR_FORK_ALLOCSIZE) != ATTR_FORK_VALIDMASK) +#error hfs_attrblksize: Missing bits in fork mask computation! +#endif + DBG_ASSERT((attrlist->forkattr & ~ATTR_FORK_VALIDMASK) == 0); + + size = 0; + + if ((a = attrlist->commonattr) != 0) { + if (a & ATTR_CMN_NAME) size += sizeof(struct attrreference); + if (a & ATTR_CMN_DEVID) size += sizeof(dev_t); + if (a & ATTR_CMN_FSID) size += sizeof(fsid_t); + if (a & ATTR_CMN_OBJTYPE) size += sizeof(fsobj_type_t); + if (a & ATTR_CMN_OBJTAG) size += sizeof(fsobj_tag_t); + if (a & ATTR_CMN_OBJID) size += sizeof(fsobj_id_t); + if (a & ATTR_CMN_OBJPERMANENTID) size += sizeof(fsobj_id_t); + if (a & ATTR_CMN_PAROBJID) size += sizeof(fsobj_id_t); + if (a & ATTR_CMN_SCRIPT) size += sizeof(text_encoding_t); + if (a & ATTR_CMN_CRTIME) size += sizeof(struct timespec); + if (a & ATTR_CMN_MODTIME) size += sizeof(struct timespec); + if (a & ATTR_CMN_CHGTIME) size += sizeof(struct timespec); + if (a & ATTR_CMN_ACCTIME) size += sizeof(struct timespec); + if (a & ATTR_CMN_BKUPTIME) size += sizeof(struct timespec); + if (a & ATTR_CMN_FNDRINFO) size += 32 * sizeof(u_int8_t); + if (a & ATTR_CMN_OWNERID) size += sizeof(uid_t); + if (a & ATTR_CMN_GRPID) size += sizeof(gid_t); + if (a & ATTR_CMN_ACCESSMASK) size += sizeof(u_long); + if (a & ATTR_CMN_NAMEDATTRCOUNT) size += sizeof(u_long); + if (a & ATTR_CMN_NAMEDATTRLIST) size += sizeof(struct attrreference); + if (a & ATTR_CMN_FLAGS) size += sizeof(u_long); + if (a & ATTR_CMN_USERACCESS) size += sizeof(u_long); + }; + if ((a = attrlist->volattr) != 0) { + if (a & ATTR_VOL_FSTYPE) size += sizeof(u_long); + if (a & ATTR_VOL_SIGNATURE) size += sizeof(u_long); + if (a & ATTR_VOL_SIZE) size += sizeof(off_t); + if (a & ATTR_VOL_SPACEFREE) size += sizeof(off_t); + if (a & ATTR_VOL_SPACEAVAIL) size += sizeof(off_t); + if (a & ATTR_VOL_MINALLOCATION) size += sizeof(off_t); + if (a & ATTR_VOL_ALLOCATIONCLUMP) size += sizeof(off_t); + if (a & ATTR_VOL_IOBLOCKSIZE) size += sizeof(u_long); + if (a & ATTR_VOL_OBJCOUNT) size += sizeof(u_long); + if (a & ATTR_VOL_FILECOUNT) size += sizeof(u_long); + if (a & ATTR_VOL_DIRCOUNT) size += sizeof(u_long); + if (a & ATTR_VOL_MAXOBJCOUNT) size += sizeof(u_long); + if (a & ATTR_VOL_MOUNTPOINT) size += sizeof(struct attrreference); + if (a & ATTR_VOL_NAME) size += sizeof(struct attrreference); + if (a & ATTR_VOL_MOUNTFLAGS) size += sizeof(u_long); + if (a & ATTR_VOL_MOUNTEDDEVICE) size += sizeof(struct attrreference); + if (a & ATTR_VOL_ENCODINGSUSED) size += sizeof(unsigned long long); + if (a & ATTR_VOL_CAPABILITIES) size += sizeof(vol_capabilities_attr_t); + if (a & ATTR_VOL_ATTRIBUTES) size += sizeof(vol_attributes_attr_t); + }; + if ((a = attrlist->dirattr) != 0) { + if (a & ATTR_DIR_LINKCOUNT) size += sizeof(u_long); + if (a & ATTR_DIR_ENTRYCOUNT) size += sizeof(u_long); + if (a & ATTR_DIR_MOUNTSTATUS) size += sizeof(u_long); + }; + if ((a = attrlist->fileattr) != 0) { + if (a & ATTR_FILE_LINKCOUNT) size += sizeof(u_long); + if (a & ATTR_FILE_TOTALSIZE) size += sizeof(off_t); + if (a & ATTR_FILE_ALLOCSIZE) size += sizeof(off_t); + if (a & ATTR_FILE_IOBLOCKSIZE) size += sizeof(size_t); + if (a & ATTR_FILE_CLUMPSIZE) size += sizeof(off_t); + if (a & ATTR_FILE_DEVTYPE) size += sizeof(u_long); + if (a & ATTR_FILE_FILETYPE) size += sizeof(u_long); + if (a & ATTR_FILE_FORKCOUNT) size += sizeof(u_long); + if (a & ATTR_FILE_FORKLIST) size += sizeof(struct attrreference); + if (a & ATTR_FILE_DATALENGTH) size += sizeof(off_t); + if (a & ATTR_FILE_DATAALLOCSIZE) size += sizeof(off_t); + if (a & ATTR_FILE_DATAEXTENTS) size += sizeof(extentrecord); + if (a & ATTR_FILE_RSRCLENGTH) size += sizeof(off_t); + if (a & ATTR_FILE_RSRCALLOCSIZE) size += sizeof(off_t); + if (a & ATTR_FILE_RSRCEXTENTS) size += sizeof(extentrecord); + }; + if ((a = attrlist->forkattr) != 0) { + if (a & ATTR_FORK_TOTALSIZE) size += sizeof(off_t); + if (a & ATTR_FORK_ALLOCSIZE) size += sizeof(off_t); + }; + + return size; +} + + +__private_extern__ +unsigned long +DerivePermissionSummary(uid_t obj_uid, gid_t obj_gid, mode_t obj_mode, + struct mount *mp, struct ucred *cred, struct proc *p) +{ + register gid_t *gp; + unsigned long permissions; + int i; + + if (obj_uid == UNKNOWNUID) + obj_uid = console_user; + + /* User id 0 (root) always gets access. */ + if (cred->cr_uid == 0) { + permissions = R_OK | W_OK | X_OK; + goto Exit; + }; + + /* Otherwise, check the owner. */ + if (hfs_owner_rights(VFSTOHFS(mp), obj_uid, cred, p, false) == 0) { + permissions = ((unsigned long)obj_mode & S_IRWXU) >> 6; + goto Exit; + } + + /* Otherwise, check the groups. */ + if (! (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS)) { + for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++) { + if (obj_gid == *gp) { + permissions = ((unsigned long)obj_mode & S_IRWXG) >> 3; + goto Exit; + } + } + } + + /* Otherwise, settle for 'others' access. */ + permissions = (unsigned long)obj_mode & S_IRWXO; + +Exit: + return (permissions); +} + diff --git a/bsd/hfs/hfs_attrlist.h b/bsd/hfs/hfs_attrlist.h new file mode 100644 index 000000000..e5da460ee --- /dev/null +++ b/bsd/hfs/hfs_attrlist.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#ifndef _HFS_ATTRLIST_H_ +#define _HFS_ATTRLIST_H_ + +#include + +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE +#include +#include + +#include +#include + + +struct attrblock { + struct attrlist * ab_attrlist; + void ** ab_attrbufpp; + void ** ab_varbufpp; + int ab_flags; + int ab_blocksize; +}; + + +#define ATTR_OWNERSHIP_SETMASK (ATTR_CMN_OWNERID | ATTR_CMN_GRPID | \ + ATTR_CMN_ACCESSMASK | ATTR_CMN_FLAGS | ATTR_CMN_CRTIME | \ + ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | ATTR_CMN_ACCTIME) + +#define ATTR_DATAFORK_MASK (ATTR_FILE_TOTALSIZE | \ + ATTR_FILE_DATALENGTH | ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_DATAEXTENTS) + +#define ATTR_RSRCFORK_MASK (ATTR_FILE_TOTALSIZE | \ + ATTR_FILE_RSRCLENGTH | ATTR_FILE_RSRCALLOCSIZE | ATTR_FILE_RSRCEXTENTS) + + +extern int hfs_attrblksize(struct attrlist *attrlist); + +extern unsigned long DerivePermissionSummary(uid_t obj_uid, gid_t obj_gid, + mode_t obj_mode, struct mount *mp, + struct ucred *cred, struct proc *p); + +extern void hfs_packattrblk(struct attrblock *abp, struct hfsmount *hfsmp, + struct vnode *vp, struct cat_desc *descp, struct cat_attr *attrp, + struct cat_fork *datafork, struct cat_fork *rsrcfork); + +#endif /* __APPLE_API_PRIVATE */ +#endif /* KERNEL */ +#endif /* ! _HFS_ATTRLIST_H_ */ diff --git a/bsd/hfs/hfs_btreeio.c b/bsd/hfs/hfs_btreeio.c index 2bb3c7695..6947a695a 100644 --- a/bsd/hfs/hfs_btreeio.c +++ b/bsd/hfs/hfs_btreeio.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -19,32 +19,17 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* @(#)hfs_btreeio.c -* -* (c) 1998, 2000 Apple Computer, Inc. All Rights Reserved -* -* hfs_btreeio.c -- I/O Routines for the HFS B-tree files. -* -* HISTORY -* 15-Feb-2000 Don Brady Added ClearBTNodes. -* 16-Jul-1998 Don Brady In ExtendBtreeFile force all b-tree nodes to be contiguous on disk. -* 4-Jun-1998 Pat Dirks Changed to do all B*-Tree writes synchronously (FORCESYNCBTREEWRITES = 1) -* 18-apr-1998 Don Brady Call brelse on bread failure. -* 17-Apr-1998 Pat Dirks Fixed ReleaseBTreeBlock to not call brelse when bwrite or bdwrite is called. -* 13-apr-1998 Don Brady Add ExtendBTreeFile routine (from BTreeWrapper.c). -* 26-mar-1998 Don Brady SetBTreeBlockSize was incorrectly excluding 512 byte blockSize. -* 18-feb-1998 Don Brady Initially created file. -* -*/ #include #include #include +#include #include #include #include "hfs.h" +#include "hfs_cnode.h" #include "hfs_dbg.h" #include "hfs_endian.h" @@ -53,40 +38,37 @@ #define FORCESYNCBTREEWRITES 0 -static OSStatus FlushAlternate( ExtendedVCB *vcb ); static int ClearBTNodes(struct vnode *vp, long blksize, off_t offset, off_t amount); +__private_extern__ OSStatus SetBTreeBlockSize(FileReference vp, ByteCount blockSize, ItemCount minBlockCount) { BTreeControlBlockPtr bTreePtr; DBG_ASSERT(vp != NULL); - DBG_ASSERT(VTOFCB(vp) != NULL); - DBG_ASSERT(VTOFCB(vp)->fcbBTCBPtr != NULL); DBG_ASSERT(blockSize >= kMinNodeSize); if (blockSize > MAXBSIZE ) return (fsBTBadNodeSize); - DBG_TREE(("SetBlockSizeProc: blockSize=%ld for file %ld\n", blockSize, H_FILEID(VTOH(vp)))); - - bTreePtr = (BTreeControlBlockPtr)(VTOH(vp)->fcbBTCBPtr); + bTreePtr = (BTreeControlBlockPtr)VTOF(vp)->fcbBTCBPtr; bTreePtr->nodeSize = blockSize; return (E_NONE); } +__private_extern__ OSStatus GetBTreeBlock(FileReference vp, UInt32 blockNum, GetBlockOptions options, BlockDescriptor *block) { OSStatus retval = E_NONE; struct buf *bp = NULL; - if (options & kGetEmptyBlock) - bp = getblk(vp, blockNum, block->blockSize, 0, 0, BLK_META); - else - retval = meta_bread(vp, blockNum, block->blockSize, NOCRED, &bp); + if (options & kGetEmptyBlock) + bp = getblk(vp, blockNum, block->blockSize, 0, 0, BLK_META); + else + retval = meta_bread(vp, blockNum, block->blockSize, NOCRED, &bp); DBG_ASSERT(bp != NULL); DBG_ASSERT(bp->b_data != NULL); @@ -110,11 +92,11 @@ OSStatus GetBTreeBlock(FileReference vp, UInt32 blockNum, GetBlockOptions option (SWAP_BE16 (((BTHeaderRec *)((char *)block->buffer + 14))->nodeSize) != bp->b_bcount)) { /* Don't swap the descriptors at all, we don't care (this block will be invalidated) */ - SWAP_BT_NODE (block, ISHFSPLUS(VTOVCB(vp)), H_FILEID(VTOH(vp)), 3); + SWAP_BT_NODE (block, ISHFSPLUS(VTOVCB(vp)), VTOC(vp)->c_fileid, 3); /* The node needs swapping */ } else if (*((UInt16 *)((char *)block->buffer + (block->blockSize - sizeof (UInt16)))) == 0x0e00) { - SWAP_BT_NODE (block, ISHFSPLUS(VTOVCB(vp)), H_FILEID(VTOH(vp)), 0); + SWAP_BT_NODE (block, ISHFSPLUS(VTOVCB(vp)), VTOC(vp)->c_fileid, 0); #if 0 /* The node is not already in native byte order, hence corrupt */ } else if (*((UInt16 *)((char *)block->buffer + (block->blockSize - sizeof (UInt16)))) != 0x000e) { @@ -134,15 +116,16 @@ OSStatus GetBTreeBlock(FileReference vp, UInt32 blockNum, GetBlockOptions option } +__private_extern__ OSStatus ReleaseBTreeBlock(FileReference vp, BlockDescPtr blockPtr, ReleaseBlockOptions options) { + extern int bdwrite_internal(struct buf *, int); OSStatus retval = E_NONE; struct buf *bp = NULL; bp = (struct buf *) blockPtr->blockHeader; if (bp == NULL) { - DBG_TREE(("ReleaseBlockProc: blockHeader is zero!\n")); retval = -1; goto exit; } @@ -152,29 +135,41 @@ OSStatus ReleaseBTreeBlock(FileReference vp, BlockDescPtr blockPtr, ReleaseBlock brelse(bp); /* note: B-tree code will clear blockPtr->blockHeader and blockPtr->buffer */ } else { if (options & kForceWriteBlock) { - bp->b_flags |= B_DIRTY; retval = VOP_BWRITE(bp); } else if (options & kMarkBlockDirty) { - bp->b_flags |= B_DIRTY; #if FORCESYNCBTREEWRITES VOP_BWRITE(bp); #else - if (options & kLockTransaction) { - /* - * - * Set the B_LOCKED flag and unlock the buffer, causing brelse to move - * the buffer onto the LOCKED free list. This is necessary, otherwise - * getnewbuf() would try to reclaim the buffers using bawrite, which - * isn't going to work. - * - */ - extern int count_lock_queue __P((void)); - /* Don't hog all the buffers... */ - if (count_lock_queue() > kMaxLockedMetaBuffers) - hfs_fsync_transaction(vp); - bp->b_flags |= B_LOCKED; - }; - bdwrite(bp); + if (options & kLockTransaction) { + /* + * + * Set the B_LOCKED flag and unlock the buffer, causing brelse to move + * the buffer onto the LOCKED free list. This is necessary, otherwise + * getnewbuf() would try to reclaim the buffers using bawrite, which + * isn't going to work. + * + */ + extern int count_lock_queue __P((void)); + /* Don't hog all the buffers... */ + if (count_lock_queue() > kMaxLockedMetaBuffers) { + hfs_btsync(vp, HFS_SYNCTRANS); + /* Rollback sync time to cause a sync on lock release... */ + (void) BTSetLastSync(VTOF(vp), time.tv_sec - (kMaxSecsForFsync + 1)); + } + bp->b_flags |= B_LOCKED; + } + /* + * Delay-write this block. + * If the maximum delayed buffers has been exceeded then + * free up some buffers and fall back to an asynchronous write. + */ + if (bdwrite_internal(bp, 1) != 0) { + hfs_btsync(vp, 0); + /* Rollback sync time to cause a sync on lock release... */ + (void) BTSetLastSync(VTOF(vp), time.tv_sec - (kMaxSecsForFsync + 1)); + bp->b_flags &= ~B_LOCKED; + bawrite(bp); + } #endif } else { @@ -187,6 +182,7 @@ exit: } +__private_extern__ OSStatus ExtendBTreeFile(FileReference vp, FSSize minEOF, FSSize maxEOF) { #pragma unused (maxEOF) @@ -195,6 +191,8 @@ OSStatus ExtendBTreeFile(FileReference vp, FSSize minEOF, FSSize maxEOF) UInt64 actualBytesAdded; UInt64 bytesToAdd; UInt32 extendFlags; + u_int32_t startAllocation; + u_int32_t fileblocks; BTreeInfoRec btInfo; ExtendedVCB *vcb; FCB *filePtr; @@ -207,16 +205,15 @@ OSStatus ExtendBTreeFile(FileReference vp, FSSize minEOF, FSSize maxEOF) { bytesToAdd = minEOF - filePtr->fcbEOF; - if (bytesToAdd < filePtr->fcbClmpSize) - bytesToAdd = filePtr->fcbClmpSize; //XXX why not always be a mutiple of clump size? + if (bytesToAdd < filePtr->ff_clumpsize) + bytesToAdd = filePtr->ff_clumpsize; //XXX why not always be a mutiple of clump size? } else { - DBG_TREE((" ExtendBTreeFile: minEOF is smaller than current size!")); return -1; } - vcb = FCBTOVCB(filePtr); + vcb = VTOVCB(vp); /* * The Extents B-tree can't have overflow extents. ExtendFileC will @@ -224,7 +221,7 @@ OSStatus ExtendBTreeFile(FileReference vp, FSSize minEOF, FSSize maxEOF) * when the resident extents are exhausted. */ /* XXX warning - this can leave the volume bitmap unprotected during ExtendFileC call */ - if(H_FILEID(filePtr) != kHFSExtentsFileID) + if(VTOC(vp)->c_fileid != kHFSExtentsFileID) { p = current_proc(); /* lock extents b-tree (also protects volume bitmap) */ @@ -236,10 +233,10 @@ OSStatus ExtendBTreeFile(FileReference vp, FSSize minEOF, FSSize maxEOF) (void) BTGetInformation(filePtr, 0, &btInfo); /* - * The b-tree code expects nodes to be contiguous. So when + * The b-tree code expects nodes to be contiguous. So when * the allocation block size is less than the b-tree node - * size, we need to force disk allocations to be contiguous. - */ + * size, we need to force disk allocations to be contiguous. + */ if (vcb->blockSize >= btInfo.nodeSize) { extendFlags = 0; } else { @@ -247,18 +244,36 @@ OSStatus ExtendBTreeFile(FileReference vp, FSSize minEOF, FSSize maxEOF) extendFlags = kEFAllMask | kEFContigMask; } - retval = ExtendFileC(vcb, filePtr, bytesToAdd, 0, extendFlags, &actualBytesAdded); + fileblocks = filePtr->ff_blocks; + startAllocation = vcb->nextAllocation; - if(H_FILEID(filePtr) != kHFSExtentsFileID) - (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, p); + retval = ExtendFileC(vcb, filePtr, bytesToAdd, 0, extendFlags, &actualBytesAdded); + /* + * If a new extent was added then move the roving allocator + * reference forward by the current b-tree file size so + * there's plenty of room to grow. + */ + if ((retval == 0) && + (vcb->nextAllocation > startAllocation) && + ((vcb->nextAllocation + fileblocks) < vcb->totalBlocks)) { + vcb->nextAllocation += fileblocks; + } + + if(VTOC(vp)->c_fileid != kHFSExtentsFileID) { + /* + * Get any extents overflow b-tree changes to disk ASAP! + */ + if (retval == 0) { + (void) BTFlushPath(VTOF(vcb->extentsRefNum)); + (void) VOP_FSYNC(vcb->extentsRefNum, NOCRED, MNT_WAIT, p); + } + (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, p); + } if (retval) return (retval); - - if (actualBytesAdded < bytesToAdd) - DBG_TREE((" ExtendBTreeFile: actualBytesAdded < bytesToAdd!")); - filePtr->fcbEOF = filePtr->fcbPLen; + filePtr->fcbEOF = (u_int64_t)filePtr->ff_blocks * (u_int64_t)vcb->blockSize; retval = ClearBTNodes(vp, btInfo.nodeSize, filePtr->fcbEOF - actualBytesAdded, actualBytesAdded); if (retval) @@ -267,69 +282,18 @@ OSStatus ExtendBTreeFile(FileReference vp, FSSize minEOF, FSSize maxEOF) /* * Update the Alternate MDB or Alternate VolumeHeader */ - if ((H_FILEID(filePtr) == kHFSExtentsFileID) || - (H_FILEID(filePtr) == kHFSCatalogFileID) || - (H_FILEID(filePtr) == kHFSAttributesFileID) + if ((VTOC(vp)->c_fileid == kHFSExtentsFileID) || + (VTOC(vp)->c_fileid == kHFSCatalogFileID) || + (VTOC(vp)->c_fileid == kHFSAttributesFileID) ) { MarkVCBDirty( vcb ); - if (vcb->vcbSigWord == kHFSPlusSigWord) { - retval = hfs_flushvolumeheader(VCBTOHFS(vcb), 0); - } else { - retval = hfs_flushMDB(VCBTOHFS(vcb), 0); - } - if (retval == 0) { - retval = FlushAlternate(vcb); - } + retval = hfs_flushvolumeheader(VCBTOHFS(vcb), MNT_WAIT, HFS_ALTFLUSH); } return retval; } -static OSStatus -FlushAlternate( ExtendedVCB *vcb ) -{ - struct hfsmount *hfsmp = VCBTOHFS(vcb); - struct vnode *dev_vp = hfsmp->hfs_devvp; - struct buf *pri_bp = NULL; - struct buf *alt_bp = NULL; - int sectorsize; - u_long priIDSector; - u_long altIDSector; - int result; - - sectorsize = hfsmp->hfs_phys_block_size; - priIDSector = (vcb->hfsPlusIOPosOffset / sectorsize) + - HFS_PRI_SECTOR(sectorsize); - - altIDSector = (vcb->hfsPlusIOPosOffset / sectorsize) + - HFS_ALT_SECTOR(sectorsize, hfsmp->hfs_phys_block_count); - - /* Get the main MDB/VolumeHeader block */ - result = meta_bread(dev_vp, priIDSector, sectorsize, NOCRED, &pri_bp); - if (result) - goto exit; - - /* Get the alternate MDB/VolumeHeader block */ - result = meta_bread(dev_vp, altIDSector, sectorsize, NOCRED, &alt_bp); - if (result) - goto exit; - - bcopy(pri_bp->b_data + HFS_PRI_OFFSET(sectorsize), - alt_bp->b_data + HFS_ALT_OFFSET(sectorsize), kMDBSize); - - result = VOP_BWRITE(alt_bp); - alt_bp = NULL; -exit: - if (alt_bp) - brelse(alt_bp); - if (pri_bp) - brelse(pri_bp); - - return (result); -} - - /* * Clear out (zero) new b-tree nodes on disk. */ @@ -348,7 +312,7 @@ ClearBTNodes(struct vnode *vp, long blksize, off_t offset, off_t amount) if (bp == NULL) continue; bzero((char *)bp->b_data, blksize); - bp->b_flags |= (B_DIRTY | B_AGE); + bp->b_flags |= B_AGE; /* wait/yield every 32 blocks so we don't hog all the buffers */ if ((blk % 32) == 0) diff --git a/bsd/hfs/hfs_catalog.c b/bsd/hfs/hfs_catalog.c new file mode 100644 index 000000000..7d6999e65 --- /dev/null +++ b/bsd/hfs/hfs_catalog.c @@ -0,0 +1,2242 @@ +/* + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "hfs.h" +#include "hfs_catalog.h" +#include "hfs_format.h" +#include "hfs_endian.h" + +#include "hfscommon/headers/BTreesInternal.h" +#include "hfscommon/headers/CatalogPrivate.h" +#include "hfscommon/headers/HFSUnicodeWrappers.h" + +extern OSErr PositionIterator(CatalogIterator *cip, UInt32 offset, BTreeIterator *bip, UInt16 *op); + +/* + * Initialization of an FSBufferDescriptor structure. + */ +#define BDINIT(bd, addr) { \ + (bd).bufferAddress = (addr); \ + (bd).itemSize = sizeof(*(addr)); \ + (bd).itemCount = 1; \ +} + + +struct btobj { + BTreeIterator iterator; + HFSPlusCatalogKey key; + CatalogRecord data; +}; + +struct update_state { + struct cat_desc * s_desc; + struct cat_attr * s_attr; + struct cat_fork * s_datafork; + struct cat_fork * s_rsrcfork; + struct hfsmount * s_hfsmp; +}; + + +static int cat_lookupbykey(struct hfsmount *hfsmp, CatalogKey *keyp, u_long hint, int wantrsrc, + struct cat_desc *descp, struct cat_attr *attrp, struct cat_fork *forkp); + +static int cat_lookupmangled(struct hfsmount *hfsmp, struct cat_desc *descp, int wantrsrc, + struct cat_desc *outdescp, struct cat_attr *attrp, struct cat_fork *forkp); + +extern int mac_roman_to_unicode(const Str31 hfs_str, UniChar *uni_str, + UInt32 maxCharLen, UInt32 *unicodeChars); + +extern int unicode_to_hfs(ExtendedVCB *vcb, ByteCount srcLen, + const u_int16_t* srcStr, Str31 dstStr, int retry); + + +/* Internal catalog support routines */ + +int resolvelink(struct hfsmount *hfsmp, u_long linkref, struct HFSPlusCatalogFile *recp); + +static int getkey(struct hfsmount *hfsmp, cnid_t cnid, CatalogKey * key); + +static int buildkey(struct hfsmount *hfsmp, struct cat_desc *descp, + HFSPlusCatalogKey *key, int retry); + +static void buildthreadkey(HFSCatalogNodeID parentID, int std_hfs, CatalogKey *key); + +static void buildrecord(struct cat_attr *attrp, cnid_t cnid, int std_hfs, u_int32_t encoding, CatalogRecord *crp, int *recordSize); + +static int catrec_update(const CatalogKey *ckp, CatalogRecord *crp, u_int16_t reclen, struct update_state *state); + +static int builddesc(const HFSPlusCatalogKey *key, cnid_t cnid, u_long hint, u_long encoding, + int isdir, struct cat_desc *descp); + +static void getbsdattr(struct hfsmount *hfsmp, const struct HFSPlusCatalogFile *crp, struct cat_attr * attrp); + +static void promotekey(struct hfsmount *hfsmp, const HFSCatalogKey *hfskey, HFSPlusCatalogKey *keyp, u_long *encoding); +static void promotefork(struct hfsmount *hfsmp, const struct HFSCatalogFile *file, int resource, struct cat_fork * forkp); +static void promoteattr(struct hfsmount *hfsmp, const CatalogRecord *dataPtr, struct HFSPlusCatalogFile *crp); + +static cnid_t getcnid(const CatalogRecord *crp); +static u_long getencoding(const CatalogRecord *crp); +static cnid_t getparentcnid(const CatalogRecord *recp); + +static int isadir(const CatalogRecord *crp); + +static int buildthread(void *keyp, void *recp, int std_hfs, int directory); + + + + +void +cat_convertattr( + struct hfsmount *hfsmp, + CatalogRecord * recp, + struct cat_attr *attrp, + struct cat_fork *datafp, + struct cat_fork *rsrcfp) +{ + int std_hfs = HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord; + + if (std_hfs) { + struct HFSPlusCatalogFile cnoderec; + + promoteattr(hfsmp, recp, &cnoderec); + getbsdattr(hfsmp, &cnoderec, attrp); + } else { + getbsdattr(hfsmp, (struct HFSPlusCatalogFile *)recp, attrp); + } + + if (isadir(recp)) + bzero(datafp, sizeof(*datafp)); + else if (std_hfs) { + promotefork(hfsmp, (HFSCatalogFile *)&recp->hfsFile, 0, datafp); + promotefork(hfsmp, (HFSCatalogFile *)&recp->hfsFile, 1, rsrcfp); + } else { + bcopy(&recp->hfsPlusFile.dataFork, datafp, sizeof(*datafp)); + bcopy(&recp->hfsPlusFile.resourceFork, rsrcfp, sizeof(*rsrcfp)); + } +} + +int +cat_convertkey( + struct hfsmount *hfsmp, + CatalogKey *key, + CatalogRecord * recp, + struct cat_desc *descp) +{ + int std_hfs = HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord; + HFSPlusCatalogKey * pluskey = NULL; + u_long encoding; + + if (std_hfs) { + MALLOC(pluskey, HFSPlusCatalogKey *, sizeof(HFSPlusCatalogKey), M_TEMP, M_WAITOK); + promotekey(hfsmp, (HFSCatalogKey *)key, pluskey, &encoding); + + } else { + pluskey = (HFSPlusCatalogKey *)key; + encoding = getencoding(recp); + } + + builddesc(pluskey, getcnid(recp), 0, encoding, isadir(recp), descp); + if (std_hfs) { + FREE(pluskey, M_TEMP); + } + return (0); +} + + +/* + * cat_releasedesc + */ +void +cat_releasedesc(struct cat_desc *descp) +{ + char * name; + + if (descp == NULL) + return; + + if ((descp->cd_flags & CD_HASBUF) && + (descp->cd_nameptr != NULL)) { + name = descp->cd_nameptr; + descp->cd_nameptr = NULL; + descp->cd_namelen = 0; + descp->cd_flags &= ~CD_HASBUF; + FREE(name, M_TEMP); + } + descp->cd_nameptr = NULL; + descp->cd_namelen = 0; +} + +/* + * These Catalog functions allow access to the HFS Catalog (database). + * The catalog b-tree lock must be aquired before calling any of these routines. + */ + +/* + * cat_lookup - lookup a catalog node using a cnode decriptor + */ +int +cat_lookup(struct hfsmount *hfsmp, struct cat_desc *descp, int wantrsrc, + struct cat_desc *outdescp, struct cat_attr *attrp, + struct cat_fork *forkp) +{ + CatalogKey * keyp; + int std_hfs; + int result; + + std_hfs = (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord); + + MALLOC(keyp, CatalogKey *, sizeof(CatalogKey), M_TEMP, M_WAITOK); + + result = buildkey(hfsmp, descp, (HFSPlusCatalogKey *)keyp, 1); + if (result) + goto exit; + + result = cat_lookupbykey(hfsmp, keyp, descp->cd_hint, wantrsrc, outdescp, attrp, forkp); + + if (result == ENOENT) { + if (!std_hfs) { + result = cat_lookupmangled(hfsmp, descp, wantrsrc, outdescp, attrp, forkp); + } else if (hfsmp->hfs_encoding != kTextEncodingMacRoman) { + // make MacRoman key from utf-8 + // result = cat_lookupbykey(hfsmp, keyp, descp->cd_hint, attrp, forkp); + // update desc text encoding so that other catalog ops succeed + } + } +exit: + FREE(keyp, M_TEMP); + + return (result); +} + +int +cat_insertfilethread(struct hfsmount *hfsmp, struct cat_desc *descp) +{ + struct BTreeIterator *iterator; + struct FSBufferDescriptor file_data; + struct HFSCatalogFile file_rec; + UInt16 datasize; + FCB *fcb; + int result; + + if (HFSTOVCB(hfsmp)->vcbSigWord != kHFSSigWord) + return (EINVAL); + + fcb = GetFileControlBlock(HFSTOVCB(hfsmp)->catalogRefNum); + + MALLOC(iterator, BTreeIterator *, 2 * sizeof(*iterator), M_TEMP, M_WAITOK); + bzero(&iterator[0], 2* sizeof(*iterator)); + result = buildkey(hfsmp, descp, (HFSPlusCatalogKey *)&iterator[0].key, 0); + if (result) + goto exit; + + BDINIT(file_data, &file_rec); + result = BTSearchRecord(fcb, &iterator[0], &file_data, &datasize, &iterator[0]); + if (result) + goto exit; + + if (file_rec.recordType != kHFSFileRecord) { + result = EISDIR; + goto exit; + } + + if ((file_rec.flags & kHFSThreadExistsMask) == 0) { + struct FSBufferDescriptor thread_data; + struct HFSCatalogThread thread_rec; + + file_rec.flags |= kHFSThreadExistsMask; + BDINIT(thread_data, &thread_rec); + thread_data.itemSize = buildthread(&iterator[0].key, &thread_rec, 1, 0); + buildthreadkey(file_rec.fileID, 1, (CatalogKey *)&iterator[1].key); + + result = BTInsertRecord(fcb, &iterator[1], &thread_data, thread_data.itemSize); + if (result) + goto exit; + + (void) BTReplaceRecord(fcb, &iterator[0], &file_data, datasize); + (void) BTFlushPath(fcb); + } +exit: + FREE(iterator, M_TEMP); + + return MacToVFSError(result); +} + + +/* + * cat_idlookup - lookup a catalog node using a cnode id + */ +int +cat_idlookup(struct hfsmount *hfsmp, cnid_t cnid, struct cat_desc *outdescp, + struct cat_attr *attrp, struct cat_fork *forkp) +{ + struct BTreeIterator * iterator; + FSBufferDescriptor btdata; + UInt16 datasize; + CatalogKey * keyp; + CatalogRecord * recp; + int result; + int std_hfs; + + std_hfs = (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord); + + MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK); + bzero(iterator, sizeof(*iterator)); + buildthreadkey(cnid, std_hfs, (CatalogKey *)&iterator->key); + + MALLOC(recp, CatalogRecord *, sizeof(CatalogRecord), M_TEMP, M_WAITOK); + BDINIT(btdata, recp); + + result = BTSearchRecord(VTOF(HFSTOVCB(hfsmp)->catalogRefNum), iterator, + &btdata, &datasize, iterator); + if (result) + goto exit; + + /* Turn thread record into a cnode key (in place) */ + switch (recp->recordType) { + case kHFSFileThreadRecord: + case kHFSFolderThreadRecord: + keyp = (CatalogKey *)((char *)&recp->hfsThread.reserved + 6); + keyp->hfs.keyLength = kHFSCatalogKeyMinimumLength + keyp->hfs.nodeName[0]; + break; + + case kHFSPlusFileThreadRecord: + case kHFSPlusFolderThreadRecord: + keyp = (CatalogKey *)&recp->hfsPlusThread.reserved; + keyp->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength + + (keyp->hfsPlus.nodeName.length * 2); + break; + + default: + result = ENOENT; + goto exit; + } + + result = cat_lookupbykey(hfsmp, keyp, 0, 0, outdescp, attrp, forkp); +exit: + FREE(recp, M_TEMP); + FREE(iterator, M_TEMP); + + return MacToVFSError(result); +} + + +/* + * cat_lookupmangled - lookup a catalog node using a mangled name + */ +static int +cat_lookupmangled(struct hfsmount *hfsmp, struct cat_desc *descp, int wantrsrc, + struct cat_desc *outdescp, struct cat_attr *attrp, struct cat_fork *forkp) +{ + cnid_t fileID; + int prefixlen; + int result; + + if (wantrsrc) + return (ENOENT); + + fileID = GetEmbeddedFileID(descp->cd_nameptr, descp->cd_namelen, &prefixlen); + if (fileID < kHFSFirstUserCatalogNodeID) + return (ENOENT); + + result = cat_idlookup(hfsmp, fileID, outdescp, attrp, forkp); + if (result) + return (ENOENT); + + /* It must be in the correct directory */ + if (descp->cd_parentcnid != outdescp->cd_parentcnid) + goto falsematch; + + if ((outdescp->cd_namelen < prefixlen) || + bcmp(outdescp->cd_nameptr, descp->cd_nameptr, prefixlen-6) != 0) + goto falsematch; + + return (0); + +falsematch: + cat_releasedesc(outdescp); + return (ENOENT); +} + + +/* + * cat_lookupbykey - lookup a catalog node using a cnode key + */ +static int +cat_lookupbykey(struct hfsmount *hfsmp, CatalogKey *keyp, u_long hint, int wantrsrc, + struct cat_desc *descp, struct cat_attr *attrp, struct cat_fork *forkp) +{ + struct BTreeIterator * iterator; + FSBufferDescriptor btdata; + CatalogRecord * recp; + UInt16 datasize; + int result; + int std_hfs; + u_long ilink = 0; + cnid_t cnid = 0; + u_long encoding = 0; + + std_hfs = (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord); + + MALLOC(recp, CatalogRecord *, sizeof(CatalogRecord), M_TEMP, M_WAITOK); + BDINIT(btdata, recp); + MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK); + bzero(iterator, sizeof(*iterator)); + iterator->hint.nodeNum = hint; + bcopy(keyp, &iterator->key, sizeof(CatalogKey)); + + result = BTSearchRecord(VTOF(HFSTOVCB(hfsmp)->catalogRefNum), iterator, + &btdata, &datasize, iterator); + if (result) + goto exit; + + /* Save the cnid now in case there's a hard link */ + cnid = getcnid(recp); + encoding = getencoding(recp); + hint = iterator->hint.nodeNum; + + /* + * When a hardlink link is encountered, auto resolve it + */ + if (!std_hfs + && (attrp || forkp) + && (recp->recordType == kHFSPlusFileRecord) + && (SWAP_BE32(recp->hfsPlusFile.userInfo.fdType) == kHardLinkFileType) + && (SWAP_BE32(recp->hfsPlusFile.userInfo.fdCreator) == kHFSPlusCreator) + && ((to_bsd_time(recp->hfsPlusFile.createDate) == HFSTOVCB(hfsmp)->vcbCrDate) || + (to_bsd_time(recp->hfsPlusFile.createDate) == hfsmp->hfs_metadata_createdate))) { + + ilink = recp->hfsPlusFile.bsdInfo.special.iNodeNum; + + (void) resolvelink(hfsmp, ilink, (struct HFSPlusCatalogFile *)recp); + } + + if (attrp != NULL) { + if (std_hfs) { + struct HFSPlusCatalogFile cnoderec; + + promoteattr(hfsmp, recp, &cnoderec); + getbsdattr(hfsmp, &cnoderec, attrp); + } else { + getbsdattr(hfsmp, (struct HFSPlusCatalogFile *)recp, attrp); + if (ilink) + attrp->ca_rdev = ilink; + } + } + if (forkp != NULL) { + if (isadir(recp)) + bzero(forkp, sizeof(*forkp)); + else if (std_hfs) + promotefork(hfsmp, (HFSCatalogFile *)&recp->hfsFile, wantrsrc, forkp); + else if (wantrsrc) + bcopy(&recp->hfsPlusFile.resourceFork, forkp, sizeof(*forkp)); + else + bcopy(&recp->hfsPlusFile.dataFork, forkp, sizeof(*forkp)); + } + if (descp != NULL) { + HFSPlusCatalogKey * pluskey = NULL; + + if (std_hfs) { + MALLOC(pluskey, HFSPlusCatalogKey *, sizeof(HFSPlusCatalogKey), M_TEMP, M_WAITOK); + promotekey(hfsmp, (HFSCatalogKey *)&iterator->key, pluskey, &encoding); + + } else + pluskey = (HFSPlusCatalogKey *)&iterator->key; + + builddesc(pluskey, cnid, hint, encoding, isadir(recp), descp); + if (std_hfs) { + FREE(pluskey, M_TEMP); + } + } +exit: + FREE(iterator, M_TEMP); + FREE(recp, M_TEMP); + + return MacToVFSError(result); +} + + +/* + * cat_create - create a node in the catalog + */ +int +cat_create(struct hfsmount *hfsmp, struct cat_desc *descp, struct cat_attr *attrp, + struct cat_desc *out_descp) +{ + ExtendedVCB * vcb; + FCB * fcb; + struct btobj * bto; + FSBufferDescriptor btdata; + u_int32_t nextCNID; + u_int32_t datalen; + int std_hfs; + int result; + u_long encoding; + int modeformat; + + modeformat = attrp->ca_mode & S_IFMT; + + vcb = HFSTOVCB(hfsmp); + fcb = GetFileControlBlock(vcb->catalogRefNum); + nextCNID = vcb->vcbNxtCNID; + std_hfs = (vcb->vcbSigWord == kHFSSigWord); + + if (std_hfs && nextCNID == 0xFFFFFFFF) + return (ENOSPC); + + /* Get space for iterator, key and data */ + MALLOC(bto, struct btobj *, sizeof(struct btobj), M_TEMP, M_WAITOK); + bzero(bto, sizeof(struct btobj)); + + result = buildkey(hfsmp, descp, &bto->key, 0); + if (result) + goto exit; + + if (!std_hfs) { + encoding = hfs_pickencoding(bto->key.nodeName.unicode, + bto->key.nodeName.length); + hfs_setencodingbits(hfsmp, encoding); + } + + /* + * Insert the thread record first + */ + if (!std_hfs || (modeformat == S_IFDIR)) { + datalen = buildthread((void*)&bto->key, &bto->data, std_hfs, + S_ISDIR(attrp->ca_mode)); + btdata.bufferAddress = &bto->data; + btdata.itemSize = datalen; + btdata.itemCount = 1; + + for (;;) { + buildthreadkey(nextCNID, std_hfs, (CatalogKey *) &bto->iterator.key); + + result = BTInsertRecord(fcb, &bto->iterator, &btdata, datalen); + if (result == btExists && !std_hfs) { + /* + * Allow CNIDs on HFS Plus volumes to wrap around + */ + ++nextCNID; + if (nextCNID < kHFSFirstUserCatalogNodeID) { + vcb->vcbAtrb |= kHFSCatalogNodeIDsReusedMask; + vcb->vcbFlags |= 0xFF00; + nextCNID = kHFSFirstUserCatalogNodeID; + } + continue; + } + break; + } + if (result) goto exit; + } + + /* + * Now insert the file/directory record + */ + buildrecord(attrp, nextCNID, std_hfs, encoding, &bto->data, &datalen); + btdata.bufferAddress = &bto->data; + btdata.itemSize = datalen; + btdata.itemCount = 1; + + bcopy(&bto->key, &bto->iterator.key, sizeof(bto->key)); + + result = BTInsertRecord(fcb, &bto->iterator, &btdata, datalen); + if (result) { + if (result == btExists) + result = EEXIST; + + /* Back out the thread record */ + if (!std_hfs || S_ISDIR(attrp->ca_mode)) { + buildthreadkey(nextCNID, std_hfs, (CatalogKey *)&bto->iterator.key); + (void) BTDeleteRecord(fcb, &bto->iterator); + } + goto exit; + } + + /* + * Insert was Successfull, update name, parent and volume + */ + + + if (out_descp != NULL) { + HFSPlusCatalogKey * pluskey = NULL; + + if (std_hfs) { + MALLOC(pluskey, HFSPlusCatalogKey *, sizeof(HFSPlusCatalogKey), M_TEMP, M_WAITOK); + promotekey(hfsmp, (HFSCatalogKey *)&bto->iterator.key, pluskey, &encoding); + + } else + pluskey = (HFSPlusCatalogKey *)&bto->iterator.key; + + builddesc(pluskey, nextCNID, bto->iterator.hint.nodeNum, + encoding, S_ISDIR(attrp->ca_mode), out_descp); + if (std_hfs) { + FREE(pluskey, M_TEMP); + } + } + attrp->ca_fileid = nextCNID; + + /* Update parent stats */ + TrashCatalogIterator(vcb, descp->cd_parentcnid); + + /* Update volume stats */ + if (++nextCNID < kHFSFirstUserCatalogNodeID) { + vcb->vcbAtrb |= kHFSCatalogNodeIDsReusedMask; + nextCNID = kHFSFirstUserCatalogNodeID; + } + vcb->vcbNxtCNID = nextCNID; + vcb->vcbFlags |= 0xFF00; + + (void) BTFlushPath(fcb); + +exit: + FREE(bto, M_TEMP); + + return MacToVFSError(result); +} + + +/* + * cnode_rename - rename a catalog node + * + * Assumes that the target's directory exists. + * + * Order of B-tree operations: + * 1. BTSearchRecord(from_cnode, &data); + * 2. BTInsertRecord(to_cnode, &data); + * 3. BTDeleteRecord(from_cnode); + * 4. BTDeleteRecord(from_thread); + * 5. BTInsertRecord(to_thread); + */ +int +cat_rename ( + struct hfsmount * hfsmp, + struct cat_desc * from_cdp, + struct cat_desc * todir_cdp, + struct cat_desc * to_cdp, + struct cat_desc * out_cdp ) +{ + struct BTreeIterator * to_iterator = NULL; + struct BTreeIterator * from_iterator = NULL; + FSBufferDescriptor btdata; + CatalogRecord * recp = NULL; + HFSPlusCatalogKey * to_key; + ExtendedVCB * vcb; + FCB * fcb; + UInt16 datasize; + int result = 0; + int sourcegone = 0; + int skipthread = 0; + int directory = from_cdp->cd_flags & CD_ISDIR; + int std_hfs; + u_long encoding = 0; + + vcb = HFSTOVCB(hfsmp); + fcb = GetFileControlBlock(vcb->catalogRefNum); + std_hfs = (vcb->vcbSigWord == kHFSSigWord); + + if (from_cdp->cd_namelen == 0 || to_cdp->cd_namelen == 0) + return (EINVAL); + + MALLOC(from_iterator, BTreeIterator *, sizeof(*from_iterator), M_TEMP, M_WAITOK); + bzero(from_iterator, sizeof(*from_iterator)); + if ((result = buildkey(hfsmp, from_cdp, (HFSPlusCatalogKey *)&from_iterator->key, 0))) + goto exit; + + MALLOC(to_iterator, BTreeIterator *, sizeof(*to_iterator), M_TEMP, M_WAITOK); + bzero(to_iterator, sizeof(*to_iterator)); + if ((result = buildkey(hfsmp, to_cdp, (HFSPlusCatalogKey *)&to_iterator->key, 0))) + goto exit; + + to_key = (HFSPlusCatalogKey *)&to_iterator->key; + MALLOC(recp, CatalogRecord *, sizeof(CatalogRecord), M_TEMP, M_WAITOK); + BDINIT(btdata, recp); + + /* + * When moving a directory, make sure its a valid move. + */ + if (directory && (from_cdp->cd_parentcnid != to_cdp->cd_parentcnid)) { + struct BTreeIterator iterator = {0}; + cnid_t cnid = from_cdp->cd_cnid; + cnid_t pathcnid = todir_cdp->cd_parentcnid; + + /* First check the obvious ones */ + if (cnid == fsRtDirID || + cnid == to_cdp->cd_parentcnid || + cnid == pathcnid) { + result = EINVAL; + goto exit; + } + + /* + * Traverese destination path all the way back to the root + * making sure that source directory is not encountered. + * + */ + while (pathcnid > fsRtDirID) { + buildthreadkey(pathcnid, std_hfs, + (CatalogKey *)&iterator.key); + result = BTSearchRecord(fcb, &iterator, &btdata, + &datasize, NULL); + if (result) goto exit; + + pathcnid = getparentcnid(recp); + if (pathcnid == cnid) { + result = EINVAL; + goto exit; + } + } + } + + /* + * Step 1: Find cnode data at old location + */ + result = BTSearchRecord(fcb, from_iterator, &btdata, + &datasize, from_iterator); + if (result) + goto exit; + + /* Update the text encoding (on disk and in descriptor */ + if (!std_hfs) { + encoding = hfs_pickencoding(to_key->nodeName.unicode, + to_key->nodeName.length); + hfs_setencodingbits(hfsmp, encoding); + recp->hfsPlusFile.textEncoding = encoding; + if (out_cdp) + out_cdp->cd_encoding = encoding; + } + + if (std_hfs && !directory && + !(recp->hfsFile.flags & kHFSThreadExistsMask)) + skipthread = 1; +#if 0 + /* + * If the keys are identical then there's nothing left to do! + * + * update the hint and exit + * + */ + if (std_hfs && hfskeycompare(to_key, iter->key) == 0) + goto exit; + if (!std_hfs && hfspluskeycompare(to_key, iter->key) == 0) + goto exit; +#endif + + /* Trash the iterator caches */ + TrashCatalogIterator(vcb, from_cdp->cd_parentcnid); + if (from_cdp->cd_parentcnid != to_cdp->cd_parentcnid) + TrashCatalogIterator(vcb, to_cdp->cd_parentcnid); + + /* Step 2: Insert cnode at new location */ + result = BTInsertRecord(fcb, to_iterator, &btdata, datasize); + if (result == btExists) { + int fromtype = recp->recordType; + + if (from_cdp->cd_parentcnid != to_cdp->cd_parentcnid) + goto exit; /* EEXIST */ + + /* Find cnode data at new location */ + result = BTSearchRecord(fcb, to_iterator, &btdata, &datasize, NULL); + + if ((fromtype != recp->recordType) || + (from_cdp->cd_cnid != getcnid(recp))) + goto exit; /* EEXIST */ + + /* The old name is a case variant and must be removed */ + result = BTDeleteRecord(fcb, from_iterator); + if (result) + goto exit; + + /* Insert cnode (now that case duplicate is gone) */ + result = BTInsertRecord(fcb, to_iterator, &btdata, datasize); + if (result) { + /* Try and restore original before leaving */ + (void) BTInsertRecord(fcb, from_iterator, &btdata, datasize); + goto exit; + } + sourcegone = 1; + } + if (result) + goto exit; + + /* Step 3: Remove cnode from old location */ + if (!sourcegone) { + result = BTDeleteRecord(fcb, from_iterator); + if (result) { + /* Try and delete new record before leaving */ + (void) BTDeleteRecord(fcb, to_iterator); + goto exit; + } + } + + /* #### POINT OF NO RETURN #### */ + + /* + * Step 4: Remove cnode's old thread record + */ + buildthreadkey(from_cdp->cd_cnid, std_hfs, (CatalogKey *)&from_iterator->key); + (void) BTDeleteRecord(fcb, from_iterator); + + /* + * Step 5: Insert cnode's new thread record + * (optional for HFS files) + */ + if (!skipthread) { + datasize = buildthread(&to_iterator->key, recp, std_hfs, directory); + btdata.itemSize = datasize; + buildthreadkey(from_cdp->cd_cnid, std_hfs, (CatalogKey *)&from_iterator->key); + result = BTInsertRecord(fcb, from_iterator, &btdata, datasize); + } + + if (out_cdp) { + HFSPlusCatalogKey * pluskey = NULL; + + if (std_hfs) { + MALLOC(pluskey, HFSPlusCatalogKey *, sizeof(HFSPlusCatalogKey), M_TEMP, M_WAITOK); + promotekey(hfsmp, (HFSCatalogKey *)&to_iterator->key, pluskey, &encoding); + + } else + pluskey = (HFSPlusCatalogKey *)&to_iterator->key; + + builddesc(pluskey, from_cdp->cd_cnid, to_iterator->hint.nodeNum, + encoding, directory, out_cdp); + if (std_hfs) { + FREE(pluskey, M_TEMP); + } + } + (void) BTFlushPath(fcb); +exit: + if (from_iterator) + FREE(from_iterator, M_TEMP); + if (to_iterator) + FREE(to_iterator, M_TEMP); + if (recp) + FREE(recp, M_TEMP); + return MacToVFSError(result); +} + + +/* + * cat_delete - delete a node from the catalog + * + * Order of B-tree operations: + * 1. BTDeleteRecord(cnode); + * 2. BTDeleteRecord(thread); + * 3. BTUpdateRecord(parent); + */ +int +cat_delete(struct hfsmount *hfsmp, struct cat_desc *descp, struct cat_attr *attrp) +{ + ExtendedVCB * vcb; + FCB * fcb; + BTreeIterator *iterator; + cnid_t cnid; + int std_hfs; + int result; + + vcb = HFSTOVCB(hfsmp); + fcb = GetFileControlBlock(vcb->catalogRefNum); + std_hfs = (vcb->vcbSigWord == kHFSSigWord); + + /* Preflight check: + * + * The root directory cannot be deleted + * A directory must be empty + * A file must be zero length (no blocks) + */ + + if (descp->cd_cnid < kHFSFirstUserCatalogNodeID || + descp->cd_parentcnid == kRootParID) + return (EINVAL); + + /* XXX Preflight Missing */ + + /* Get space for iterator */ + MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK); + bzero(iterator, sizeof(*iterator)); + + /* + * Derive a key from either the file ID (for a virtual inode) + * or the descriptor. + */ + if (descp->cd_namelen == 0) { + result = getkey(hfsmp, attrp->ca_fileid, (CatalogKey *)&iterator->key); + cnid = attrp->ca_fileid; + } else { + result = buildkey(hfsmp, descp, (HFSPlusCatalogKey *)&iterator->key, 0); + cnid = descp->cd_cnid; + } + if (result) + goto exit; + + /* Delete record */ + result = BTDeleteRecord(fcb, iterator); + if (result) + goto exit; + + /* Delete thread record, ignore errors */ + buildthreadkey(cnid, std_hfs, (CatalogKey *)&iterator->key); + (void) BTDeleteRecord(fcb, iterator); + + TrashCatalogIterator(vcb, descp->cd_parentcnid); + + (void) BTFlushPath(fcb); +exit: + FREE(iterator, M_TEMP); + + return MacToVFSError(result); +} + + +/* + * cnode_update - update the catalog node described by descp + * using the data from attrp and forkp. + */ +int +cat_update(struct hfsmount *hfsmp, struct cat_desc *descp, struct cat_attr *attrp, + struct cat_fork *dataforkp, struct cat_fork *rsrcforkp) +{ + ExtendedVCB * vcb; + FCB * fcb; + BTreeIterator * iterator; + struct update_state state; + int std_hfs; + int result; + + vcb = HFSTOVCB(hfsmp); + fcb = GetFileControlBlock(vcb->catalogRefNum); + std_hfs = (vcb->vcbSigWord == kHFSSigWord); + + state.s_desc = descp; + state.s_attr = attrp; + state.s_datafork = dataforkp; + state.s_rsrcfork = rsrcforkp; + state.s_hfsmp = hfsmp; + + /* Get space for iterator */ + MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK); + bzero(iterator, sizeof(*iterator)); + + /* + * For open-deleted files we need to do a lookup by cnid + * (using thread rec). + * + * For hard links, the target of the update is the inode + * itself (not the link record) so a lookup by fileid + * (i.e. thread rec) is needed. + */ + if ((descp->cd_cnid != attrp->ca_fileid) || (descp->cd_namelen == 0)) + result = getkey(hfsmp, attrp->ca_fileid, (CatalogKey *)&iterator->key); + else + result = buildkey(hfsmp, descp, (HFSPlusCatalogKey *)&iterator->key, 0); + if (result) + goto exit; + + /* Pass a node hint */ + iterator->hint.nodeNum = descp->cd_hint; + + result = BTUpdateRecord(fcb, iterator, + (IterateCallBackProcPtr)catrec_update, &state); + if (result) + goto exit; + + /* Update the node hint. */ + descp->cd_hint = iterator->hint.nodeNum; + + (void) BTFlushPath(fcb); + +exit: + FREE(iterator, M_TEMP); + + return MacToVFSError(result); +} + +/* + * catrec_update - Update the fields of a catalog record + * This is called from within BTUpdateRecord. + */ +static int +catrec_update(const CatalogKey *ckp, CatalogRecord *crp, u_int16_t reclen, + struct update_state *state) +{ + struct cat_desc *descp; + struct cat_attr *attrp; + struct cat_fork *forkp; + struct hfsmount *hfsmp; + long blksize; + int i; + + descp = state->s_desc; + attrp = state->s_attr; + hfsmp = state->s_hfsmp; + blksize = HFSTOVCB(hfsmp)->blockSize; + + switch (crp->recordType) { + case kHFSFolderRecord: { + HFSCatalogFolder *dir; + + dir = (struct HFSCatalogFolder *)crp; + /* Do a quick sanity check */ + if ((ckp->hfs.parentID != descp->cd_parentcnid) || + (dir->folderID != descp->cd_cnid)) + return (btNotFound); + dir->valence = attrp->ca_entries; + dir->createDate = UTCToLocal(to_hfs_time(attrp->ca_itime)); + dir->modifyDate = UTCToLocal(to_hfs_time(attrp->ca_mtime)); + dir->backupDate = UTCToLocal(to_hfs_time(attrp->ca_btime)); + bcopy(&attrp->ca_finderinfo[0], &dir->userInfo, 16); + bcopy(&attrp->ca_finderinfo[16], &dir->finderInfo, 16); + break; + } + case kHFSFileRecord: { + HFSCatalogFile *file; + + file = (struct HFSCatalogFile *)crp; + /* Do a quick sanity check */ + if ((ckp->hfs.parentID != descp->cd_parentcnid) || + (file->fileID != attrp->ca_fileid)) + return (btNotFound); + file->createDate = UTCToLocal(to_hfs_time(attrp->ca_itime)); + file->modifyDate = UTCToLocal(to_hfs_time(attrp->ca_mtime)); + file->backupDate = UTCToLocal(to_hfs_time(attrp->ca_btime)); + bcopy(&attrp->ca_finderinfo[0], &file->userInfo, 16); + bcopy(&attrp->ca_finderinfo[16], &file->finderInfo, 16); + if (state->s_rsrcfork) { + forkp = state->s_rsrcfork; + file->rsrcLogicalSize = forkp->cf_size; + file->rsrcPhysicalSize = forkp->cf_blocks * blksize; + for (i = 0; i < kHFSExtentDensity; ++i) { + file->rsrcExtents[i].startBlock = + (u_int16_t)forkp->cf_extents[i].startBlock; + file->rsrcExtents[i].blockCount = + (u_int16_t)forkp->cf_extents[i].blockCount; + } + } + if (state->s_datafork) { + forkp = state->s_datafork; + file->dataLogicalSize = forkp->cf_size; + file->dataPhysicalSize = forkp->cf_blocks * blksize; + for (i = 0; i < kHFSExtentDensity; ++i) { + file->dataExtents[i].startBlock = + (u_int16_t)forkp->cf_extents[i].startBlock; + file->dataExtents[i].blockCount = + (u_int16_t)forkp->cf_extents[i].blockCount; + } + } + break; + } + case kHFSPlusFolderRecord: { + HFSPlusCatalogFolder *dir; + + dir = (struct HFSPlusCatalogFolder *)crp; + /* Do a quick sanity check */ + if ((ckp->hfsPlus.parentID != descp->cd_parentcnid) || + (dir->folderID != descp->cd_cnid)) + return (btNotFound); + dir->valence = attrp->ca_entries; + dir->createDate = to_hfs_time(attrp->ca_itime); + dir->contentModDate = to_hfs_time(attrp->ca_mtime); + dir->backupDate = to_hfs_time(attrp->ca_btime); + dir->accessDate = to_hfs_time(attrp->ca_atime); + dir->attributeModDate = to_hfs_time(attrp->ca_ctime); + dir->textEncoding = descp->cd_encoding; + bcopy(&attrp->ca_finderinfo[0], &dir->userInfo, 32); + /* + * Update the BSD Info if it was already initialized on + * disk or if the runtime values have been modified. + * + * If the BSD info was already initialized, but + * MNT_UNKNOWNPERMISSIONS is set, then the runtime IDs are + * probably different than what was on disk. We don't want + * to overwrite the on-disk values (so if we turn off + * MNT_UNKNOWNPERMISSIONS, the old IDs get used again). + * This way, we can still change fields like the mode or + * dates even when MNT_UNKNOWNPERMISSIONS is set. + * + * Note that if MNT_UNKNOWNPERMISSIONS is set, hfs_chown + * won't change the uid or gid from their defaults. So, if + * the BSD info wasn't set, and the runtime values are not + * default, then what changed was the mode or flags. We + * have to set the uid and gid to something, so use the + * supplied values (which will be default), which has the + * same effect as creating a new file while + * MNT_UNKNOWNPERMISSIONS is set. + */ + if ((dir->bsdInfo.fileMode != 0) || + (attrp->ca_flags != 0) || + (attrp->ca_uid != hfsmp->hfs_uid) || + (attrp->ca_gid != hfsmp->hfs_gid) || + ((attrp->ca_mode & ALLPERMS) != + (hfsmp->hfs_dir_mask & ACCESSPERMS))) { + if ((dir->bsdInfo.fileMode == 0) || + (HFSTOVFS(hfsmp)->mnt_flag & + MNT_UNKNOWNPERMISSIONS) == 0) { + dir->bsdInfo.ownerID = attrp->ca_uid; + dir->bsdInfo.groupID = attrp->ca_gid; + } + dir->bsdInfo.ownerFlags = attrp->ca_flags & 0x000000FF; + dir->bsdInfo.adminFlags = attrp->ca_flags >> 16; + dir->bsdInfo.fileMode = attrp->ca_mode; + } + break; + } + case kHFSPlusFileRecord: { + HFSPlusCatalogFile *file; + + file = (struct HFSPlusCatalogFile *)crp; + /* Do a quick sanity check */ + if (file->fileID != attrp->ca_fileid) + return (btNotFound); + file->createDate = to_hfs_time(attrp->ca_itime); + file->contentModDate = to_hfs_time(attrp->ca_mtime); + file->backupDate = to_hfs_time(attrp->ca_btime); + file->accessDate = to_hfs_time(attrp->ca_atime); + file->attributeModDate = to_hfs_time(attrp->ca_ctime); + file->textEncoding = descp->cd_encoding; + bcopy(&attrp->ca_finderinfo[0], &file->userInfo, 32); + /* + * Update the BSD Info if it was already initialized on + * disk or if the runtime values have been modified. + * + * If the BSD info was already initialized, but + * MNT_UNKNOWNPERMISSIONS is set, then the runtime IDs are + * probably different than what was on disk. We don't want + * to overwrite the on-disk values (so if we turn off + * MNT_UNKNOWNPERMISSIONS, the old IDs get used again). + * This way, we can still change fields like the mode or + * dates even when MNT_UNKNOWNPERMISSIONS is set. + * + * Note that if MNT_UNKNOWNPERMISSIONS is set, hfs_chown + * won't change the uid or gid from their defaults. So, if + * the BSD info wasn't set, and the runtime values are not + * default, then what changed was the mode or flags. We + * have to set the uid and gid to something, so use the + * supplied values (which will be default), which has the + * same effect as creating a new file while + * MNT_UNKNOWNPERMISSIONS is set. + */ + if ((file->bsdInfo.fileMode != 0) || + (attrp->ca_flags != 0) || + (attrp->ca_uid != hfsmp->hfs_uid) || + (attrp->ca_gid != hfsmp->hfs_gid) || + ((attrp->ca_mode & ALLPERMS) != + (hfsmp->hfs_file_mask & ACCESSPERMS))) { + if ((file->bsdInfo.fileMode == 0) || + (HFSTOVFS(hfsmp)->mnt_flag & + MNT_UNKNOWNPERMISSIONS) == 0) { + file->bsdInfo.ownerID = attrp->ca_uid; + file->bsdInfo.groupID = attrp->ca_gid; + } + file->bsdInfo.ownerFlags = attrp->ca_flags & 0x000000FF; + file->bsdInfo.adminFlags = attrp->ca_flags >> 16; + file->bsdInfo.fileMode = attrp->ca_mode; + } + if (state->s_rsrcfork) { + forkp = state->s_rsrcfork; + file->resourceFork.logicalSize = forkp->cf_size; + file->resourceFork.totalBlocks = forkp->cf_blocks; + bcopy(&forkp->cf_extents[0], &file->resourceFork.extents, + sizeof(HFSPlusExtentRecord)); + } + if (state->s_datafork) { + forkp = state->s_datafork; + file->dataFork.logicalSize = forkp->cf_size; + file->dataFork.totalBlocks = forkp->cf_blocks; + bcopy(&forkp->cf_extents[0], &file->dataFork.extents, + sizeof(HFSPlusExtentRecord)); + } + + if ((file->resourceFork.extents[0].startBlock != 0) && + (file->resourceFork.extents[0].startBlock == + file->dataFork.extents[0].startBlock)) + panic("catrec_update: rsrc fork == data fork"); + + /* Synchronize the lock state */ + if (attrp->ca_flags & (SF_IMMUTABLE | UF_IMMUTABLE)) + file->flags |= kHFSFileLockedMask; + else + file->flags &= ~kHFSFileLockedMask; + + /* Push out special field if necessary */ + if (S_ISBLK(attrp->ca_mode) || S_ISCHR(attrp->ca_mode)) + file->bsdInfo.special.rawDevice = attrp->ca_rdev; + else if (descp->cd_cnid != attrp->ca_fileid + || attrp->ca_nlink == 2) + file->bsdInfo.special.linkCount = attrp->ca_nlink; + break; + } + default: + return (btNotFound); + } + return (0); +} + +/* + * catrec_readattr - + * This is called from within BTIterateRecords. + */ +struct readattr_state { + struct hfsmount *hfsmp; + struct cat_entrylist *list; + cnid_t dir_cnid; + int stdhfs; + int error; +}; + +static int +catrec_readattr(const CatalogKey *key, const CatalogRecord *rec, + u_long node, struct readattr_state *state) +{ + struct cat_entrylist *list = state->list; + struct hfsmount *hfsmp = state->hfsmp; + struct cat_entry *cep; + cnid_t parentcnid; + + if (list->realentries >= list->maxentries) + return (0); /* stop */ + + parentcnid = state->stdhfs ? key->hfs.parentID : key->hfsPlus.parentID; + + switch(rec->recordType) { + case kHFSPlusFolderRecord: + case kHFSPlusFileRecord: + case kHFSFolderRecord: + case kHFSFileRecord: + if (parentcnid != state->dir_cnid) { + state->error = ENOENT; + return (0); /* stop */ + } + break; + default: + state->error = ENOENT; + return (0); /* stop */ + } + + /* Hide the private meta data directory. */ + if (parentcnid == kRootDirID && + rec->recordType == kHFSPlusFolderRecord && + rec->hfsPlusFolder.folderID == hfsmp->hfs_private_metadata_dir) { + return (1); /* continue */ + } + + cep = &list->entry[list->realentries++]; + + if (state->stdhfs) { + struct HFSPlusCatalogFile cnoderec; + HFSPlusCatalogKey * pluskey; + long encoding; + + promoteattr(hfsmp, rec, &cnoderec); + getbsdattr(hfsmp, &cnoderec, &cep->ce_attr); + + MALLOC(pluskey, HFSPlusCatalogKey *, sizeof(HFSPlusCatalogKey), M_TEMP, M_WAITOK); + promotekey(hfsmp, (HFSCatalogKey *)key, pluskey, &encoding); + builddesc(pluskey, getcnid(rec), node, encoding, isadir(rec), &cep->ce_desc); + FREE(pluskey, M_TEMP); + + if (rec->recordType == kHFSFileRecord) { + int blksize = HFSTOVCB(hfsmp)->blockSize; + + cep->ce_datasize = rec->hfsFile.dataLogicalSize; + cep->ce_datablks = rec->hfsFile.dataPhysicalSize / blksize; + cep->ce_rsrcsize = rec->hfsFile.rsrcLogicalSize; + cep->ce_rsrcblks = rec->hfsFile.rsrcPhysicalSize / blksize; + } + } else { + getbsdattr(hfsmp, (struct HFSPlusCatalogFile *)rec, &cep->ce_attr); + builddesc((HFSPlusCatalogKey *)key, getcnid(rec), node, getencoding(rec), + isadir(rec), &cep->ce_desc); + + if (rec->recordType == kHFSPlusFileRecord) { + cep->ce_datasize = rec->hfsPlusFile.dataFork.logicalSize; + cep->ce_datablks = rec->hfsPlusFile.dataFork.totalBlocks; + cep->ce_rsrcsize = rec->hfsPlusFile.resourceFork.logicalSize; + cep->ce_rsrcblks = rec->hfsPlusFile.resourceFork.totalBlocks; + + /* Save link reference for later processing. */ + if ((SWAP_BE32(rec->hfsPlusFile.userInfo.fdType) == kHardLinkFileType) + && (SWAP_BE32(rec->hfsPlusFile.userInfo.fdCreator) == kHFSPlusCreator)) + cep->ce_attr.ca_rdev = rec->hfsPlusFile.bsdInfo.special.iNodeNum; + } + } + + return (list->realentries < list->maxentries); +} + +/* + * Note: index is zero relative + */ +int +cat_getentriesattr(struct hfsmount *hfsmp, struct cat_desc *prevdesc, int index, + struct cat_entrylist *ce_list) +{ + FCB* fcb; + CatalogKey * key; + BTreeIterator * iterator; + struct readattr_state state; + cnid_t parentcnid; + int i; + int std_hfs; + int result = 0; + + ce_list->realentries = 0; + + fcb = GetFileControlBlock(HFSTOVCB(hfsmp)->catalogRefNum); + std_hfs = (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord); + parentcnid = prevdesc->cd_parentcnid; + + state.hfsmp = hfsmp; + state.list = ce_list; + state.dir_cnid = parentcnid; + state.stdhfs = std_hfs; + state.error = 0; + + MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK); + bzero(iterator, sizeof(*iterator)); + key = (CatalogKey *)&iterator->key; + iterator->hint.nodeNum = prevdesc->cd_hint; + + /* + * If the last entry wasn't cached then establish the iterator + */ + if ((index == 0) || + (prevdesc->cd_namelen == 0) || + (buildkey(hfsmp, prevdesc, (HFSPlusCatalogKey *)key, 0) != 0)) { + int i; + /* + * Position the iterator at the directory thread. + * (ie just before the first entry) + */ + buildthreadkey(parentcnid, std_hfs, key); + result = BTSearchRecord(fcb, iterator, NULL, NULL, iterator); + if (result) + goto exit; /* bad news */ + /* + * Iterate until we reach the entry just + * before the one we want to start with. + */ + for (i = 0; i < index; ++i) { + result = BTIterateRecord(fcb, kBTreeNextRecord, iterator, NULL, NULL); + if (result) + goto exit; /* bad news */ + } + } + + /* Fill list with entries. */ + result = BTIterateRecords(fcb, kBTreeNextRecord, iterator, + (IterateCallBackProcPtr)catrec_readattr, &state); + + if (state.error) + result = state.error; + else if (ce_list->realentries == 0) + result = ENOENT; + else + result = MacToVFSError(result); + + if (std_hfs) + goto exit; + + /* + * Resolve any hard links. + */ + for (i = 0; i < ce_list->realentries; ++i) { + struct FndrFileInfo *fip; + struct cat_entry *cep; + struct HFSPlusCatalogFile filerec; + + cep = &ce_list->entry[i]; + if (!S_ISREG(cep->ce_attr.ca_mode)) + continue; + + /* Note: Finder info is still in Big Endian */ + fip = (struct FndrFileInfo *)&cep->ce_attr.ca_finderinfo; + + /* Check for hard link signature. */ + if ((cep->ce_attr.ca_rdev != 0) + && (SWAP_BE32(fip->fdType) == kHardLinkFileType) + && (SWAP_BE32(fip->fdCreator) == kHFSPlusCreator) + && ((cep->ce_attr.ca_itime == HFSTOVCB(hfsmp)->vcbCrDate) || + (cep->ce_attr.ca_itime == hfsmp->hfs_metadata_createdate))) { + + if (resolvelink(hfsmp, cep->ce_attr.ca_rdev, &filerec) != 0) + continue; + /* Repack entry from inode record. */ + getbsdattr(hfsmp, &filerec, &cep->ce_attr); + cep->ce_datasize = filerec.dataFork.logicalSize; + cep->ce_datablks = filerec.dataFork.totalBlocks; + cep->ce_rsrcsize = filerec.resourceFork.logicalSize; + cep->ce_rsrcblks = filerec.resourceFork.totalBlocks; + } + } +exit: + FREE(iterator, M_TEMP); + + return MacToVFSError(result); +} + + +struct read_state { + u_int32_t cbs_parentID; + u_int32_t cbs_hiddenDirID; + off_t cbs_lastoffset; + struct uio * cbs_uio; + ExtendedVCB * cbs_vcb; + int16_t cbs_hfsPlus; + int16_t cbs_result; +}; + + +static int +catrec_read(const CatalogKey *ckp, const CatalogRecord *crp, + u_int16_t recordLen, struct read_state *state) +{ + CatalogName *cnp; + size_t utf8chars; + u_int32_t curID; + OSErr result; + struct dirent catent; + + if (state->cbs_hfsPlus) + curID = ckp->hfsPlus.parentID; + else + curID = ckp->hfs.parentID; + + /* We're done when parent directory changes */ + if (state->cbs_parentID != curID) { +lastitem: +/* + * The NSDirectoryList class chokes on empty records (it doesnt check d_reclen!) + * so remove padding for now... + */ +#if 0 + /* + * Pad the end of list with an empty record. + * This eliminates an extra call by readdir(3c). + */ + catent.d_fileno = 0; + catent.d_reclen = 0; + catent.d_type = 0; + catent.d_namlen = 0; + *(int32_t*)&catent.d_name[0] = 0; + + state->cbs_lastoffset = state->cbs_uio->uio_offset; + + state->cbs_result = uiomove((caddr_t) &catent, 12, state->cbs_uio); + if (state->cbs_result == 0) + state->cbs_result = ENOENT; +#else + state->cbs_lastoffset = state->cbs_uio->uio_offset; + state->cbs_result = ENOENT; +#endif + return (0); /* stop */ + } + + if (state->cbs_hfsPlus) { + switch(crp->recordType) { + case kHFSPlusFolderRecord: + catent.d_type = DT_DIR; + catent.d_fileno = crp->hfsPlusFolder.folderID; + break; + case kHFSPlusFileRecord: + catent.d_type = DT_REG; + catent.d_fileno = crp->hfsPlusFile.fileID; + break; + default: + return (0); /* stop */ + }; + + cnp = (CatalogName*) &ckp->hfsPlus.nodeName; + result = utf8_encodestr(cnp->ustr.unicode, cnp->ustr.length * sizeof(UniChar), + catent.d_name, &utf8chars, kdirentMaxNameBytes + 1, ':', 0); + if (result == ENAMETOOLONG) { + result = ConvertUnicodeToUTF8Mangled(cnp->ustr.length * sizeof(UniChar), + cnp->ustr.unicode, kdirentMaxNameBytes + 1, (ByteCount*)&utf8chars, catent.d_name, catent.d_fileno); + } + } else { /* hfs */ + switch(crp->recordType) { + case kHFSFolderRecord: + catent.d_type = DT_DIR; + catent.d_fileno = crp->hfsFolder.folderID; + break; + case kHFSFileRecord: + catent.d_type = DT_REG; + catent.d_fileno = crp->hfsFile.fileID; + break; + default: + return (0); /* stop */ + }; + + cnp = (CatalogName*) ckp->hfs.nodeName; + result = hfs_to_utf8(state->cbs_vcb, cnp->pstr, kdirentMaxNameBytes + 1, + (ByteCount *)&utf8chars, catent.d_name); + /* + * When an HFS name cannot be encoded with the current + * volume encoding we use MacRoman as a fallback. + */ + if (result) + result = mac_roman_to_utf8(cnp->pstr, kdirentMaxNameBytes + 1, + (ByteCount *)&utf8chars, catent.d_name); + } + + catent.d_namlen = utf8chars; + catent.d_reclen = DIRENTRY_SIZE(utf8chars); + + /* hide our private meta data directory */ + if (curID == kRootDirID && + catent.d_fileno == state->cbs_hiddenDirID && + catent.d_type == DT_DIR) + goto lastitem; + + state->cbs_lastoffset = state->cbs_uio->uio_offset; + + /* if this entry won't fit then we're done */ + if (catent.d_reclen > state->cbs_uio->uio_resid) + return (0); /* stop */ + + state->cbs_result = uiomove((caddr_t) &catent, catent.d_reclen, state->cbs_uio); + + /* continue iteration if there's room */ + return (state->cbs_result == 0 && + state->cbs_uio->uio_resid >= AVERAGE_HFSDIRENTRY_SIZE); +} + +/* + * + */ +int +cat_getdirentries(struct hfsmount *hfsmp, struct cat_desc *descp, + struct uio *uio, int *eofflag) +{ + ExtendedVCB *vcb = HFSTOVCB(hfsmp); + BTreeIterator * iterator; + CatalogIterator *cip; + u_int32_t diroffset; + u_int16_t op; + struct read_state state; + u_int32_t dirID = descp->cd_cnid; + int result; + + diroffset = uio->uio_offset; + *eofflag = 0; + + MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK); + bzero(iterator, sizeof(*iterator)); + + /* get an iterator and position it */ + cip = GetCatalogIterator(vcb, dirID, diroffset); + + result = PositionIterator(cip, diroffset, iterator, &op); + if (result == cmNotFound) { + *eofflag = 1; + result = 0; + AgeCatalogIterator(cip); + goto cleanup; + } else if ((result = MacToVFSError(result))) + goto cleanup; + + state.cbs_hiddenDirID = hfsmp->hfs_private_metadata_dir; + state.cbs_lastoffset = cip->currentOffset; + state.cbs_vcb = vcb; + state.cbs_uio = uio; + state.cbs_result = 0; + state.cbs_parentID = dirID; + + if (vcb->vcbSigWord == kHFSPlusSigWord) + state.cbs_hfsPlus = 1; + else + state.cbs_hfsPlus = 0; + + /* process as many entries as possible... */ + result = BTIterateRecords(GetFileControlBlock(vcb->catalogRefNum), op, + iterator, (IterateCallBackProcPtr)catrec_read, &state); + + if (state.cbs_result) + result = state.cbs_result; + else + result = MacToVFSError(result); + + if (result == ENOENT) { + *eofflag = 1; + result = 0; + } + + if (result == 0) { + cip->currentOffset = state.cbs_lastoffset; + cip->nextOffset = uio->uio_offset; + UpdateCatalogIterator(iterator, cip); + } + +cleanup: + if (result) { + cip->volume = 0; + cip->folderID = 0; + AgeCatalogIterator(cip); + } + + (void) ReleaseCatalogIterator(cip); + FREE(iterator, M_TEMP); + + return (result); +} + + +/* + * buildkey - build a Catalog b-tree key from a cnode descriptor + */ +static int +buildkey(struct hfsmount *hfsmp, struct cat_desc *descp, + HFSPlusCatalogKey *key, int retry) +{ + int utf8_flags = 0; + int result = 0; + size_t unicodeBytes = 0; + + if (descp->cd_namelen == 0 || descp->cd_nameptr[0] == '\0') + return (EINVAL); /* invalid name */ + + key->parentID = descp->cd_parentcnid; + key->nodeName.length = 0; + /* + * Convert filename from UTF-8 into Unicode + */ + + if ((descp->cd_flags & CD_DECOMPOSED) == 0) + utf8_flags |= UTF_DECOMPOSED; + result = utf8_decodestr(descp->cd_nameptr, descp->cd_namelen, + key->nodeName.unicode, &unicodeBytes, + sizeof(key->nodeName.unicode), ':', utf8_flags); + key->nodeName.length = unicodeBytes / sizeof(UniChar); + key->keyLength = kHFSPlusCatalogKeyMinimumLength + unicodeBytes; + if (result) { + if (result != ENAMETOOLONG) + result = EINVAL; /* name has invalid characters */ + return (result); + } + + /* + * For HFS volumes convert to an HFS compatible key + * + * XXX need to save the encoding that succeeded + */ + if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord) { + HFSCatalogKey hfskey; + + bzero(&hfskey, sizeof(hfskey)); + hfskey.keyLength = kHFSCatalogKeyMinimumLength; + hfskey.parentID = key->parentID; + hfskey.nodeName[0] = 0; + if (key->nodeName.length > 0) { + if (unicode_to_hfs(HFSTOVCB(hfsmp), + key->nodeName.length * 2, + key->nodeName.unicode, + &hfskey.nodeName[0], retry) != 0) { + return (EINVAL); + } + hfskey.keyLength += hfskey.nodeName[0]; + } + bcopy(&hfskey, key, sizeof(hfskey)); + } + return (0); + } + + +/* + * Resolve hard link reference to obtain the inode record. + */ +__private_extern__ +int +resolvelink(struct hfsmount *hfsmp, u_long linkref, struct HFSPlusCatalogFile *recp) +{ + FSBufferDescriptor btdata; + struct BTreeIterator *iterator; + struct cat_desc idesc; + char inodename[32]; + int result = 0; + + BDINIT(btdata, recp); + MAKE_INODE_NAME(inodename, linkref); + + /* Get space for iterator */ + MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK); + bzero(iterator, sizeof(*iterator)); + + /* Build a descriptor for private dir. */ + idesc.cd_parentcnid = hfsmp->hfs_private_metadata_dir; + idesc.cd_nameptr = inodename; + idesc.cd_namelen = strlen(inodename); + idesc.cd_flags = 0; + idesc.cd_hint = 0; + idesc.cd_encoding = 0; + (void) buildkey(hfsmp, &idesc, (HFSPlusCatalogKey *)&iterator->key, 0); + + result = BTSearchRecord(VTOF(HFSTOVCB(hfsmp)->catalogRefNum), iterator, + &btdata, NULL, NULL); + + if (result == 0) { + /* Make sure there's a reference */ + if (recp->bsdInfo.special.linkCount == 0) + recp->bsdInfo.special.linkCount = 2; + } else { + printf("HFS resolvelink: can't find %s\n", inodename); + } + + FREE(iterator, M_TEMP); + + return (result ? ENOENT : 0); +} + +/* + * getkey - get a key from id by doing a thread lookup + */ +static int +getkey(struct hfsmount *hfsmp, cnid_t cnid, CatalogKey * key) +{ + struct BTreeIterator * iterator; + FSBufferDescriptor btdata; + UInt16 datasize; + CatalogKey * keyp; + CatalogRecord * recp; + int result; + int std_hfs; + + std_hfs = (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord); + + MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK); + bzero(iterator, sizeof(*iterator)); + buildthreadkey(cnid, std_hfs, (CatalogKey *)&iterator->key); + + MALLOC(recp, CatalogRecord *, sizeof(CatalogRecord), M_TEMP, M_WAITOK); + BDINIT(btdata, recp); + + result = BTSearchRecord(VTOF(HFSTOVCB(hfsmp)->catalogRefNum), iterator, + &btdata, &datasize, iterator); + if (result) + goto exit; + + /* Turn thread record into a cnode key (in place) */ + switch (recp->recordType) { + case kHFSFileThreadRecord: + case kHFSFolderThreadRecord: + keyp = (CatalogKey *)((char *)&recp->hfsThread.reserved + 6); + keyp->hfs.keyLength = kHFSCatalogKeyMinimumLength + keyp->hfs.nodeName[0]; + bcopy(keyp, key, keyp->hfs.keyLength + 1); + break; + + case kHFSPlusFileThreadRecord: + case kHFSPlusFolderThreadRecord: + keyp = (CatalogKey *)&recp->hfsPlusThread.reserved; + keyp->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength + + (keyp->hfsPlus.nodeName.length * 2); + bcopy(keyp, key, keyp->hfsPlus.keyLength + 2); + break; + + default: + result = ENOENT; + break; + } + +exit: + FREE(iterator, M_TEMP); + FREE(recp, M_TEMP); + + return MacToVFSError(result); +} + + +/* + * buildrecord - build a default catalog directory or file record + */ +static void +buildrecord(struct cat_attr *attrp, cnid_t cnid, int std_hfs, u_int32_t encoding, + CatalogRecord *crp, int *recordSize) +{ + int type = attrp->ca_mode & S_IFMT; + u_int32_t createtime = to_hfs_time(attrp->ca_itime); + + if (std_hfs) { + createtime = UTCToLocal(createtime); + if (type == S_IFDIR) { + bzero(crp, sizeof(HFSCatalogFolder)); + crp->recordType = kHFSFolderRecord; + crp->hfsFolder.folderID = cnid; + crp->hfsFolder.createDate = createtime; + crp->hfsFolder.modifyDate = createtime; + bcopy(attrp->ca_finderinfo, &crp->hfsFolder.userInfo, 32); + *recordSize = sizeof(HFSCatalogFolder); + } else { + bzero(crp, sizeof(HFSCatalogFile)); + crp->recordType = kHFSFileRecord; + crp->hfsFile.fileID = cnid; + crp->hfsFile.createDate = createtime; + crp->hfsFile.modifyDate = createtime; + bcopy(attrp->ca_finderinfo, &crp->hfsFile.userInfo, 16); + bcopy(&attrp->ca_finderinfo[16], &crp->hfsFile.finderInfo, 16); + *recordSize = sizeof(HFSCatalogFile); + } + } else { + struct HFSPlusBSDInfo * bsdp = NULL; + struct FndrFileInfo * fip = NULL; + + if (type == S_IFDIR) { + bzero(crp, sizeof(HFSPlusCatalogFolder)); + crp->recordType = kHFSPlusFolderRecord; + crp->hfsPlusFolder.folderID = cnid; + crp->hfsPlusFolder.createDate = createtime; + crp->hfsPlusFolder.contentModDate = createtime; + crp->hfsPlusFolder.accessDate = createtime; + crp->hfsPlusFolder.attributeModDate = createtime; + crp->hfsPlusFolder.textEncoding = encoding; + bcopy(attrp->ca_finderinfo, &crp->hfsPlusFolder.userInfo, 32); + bsdp = &crp->hfsPlusFolder.bsdInfo; + *recordSize = sizeof(HFSPlusCatalogFolder); + } else { + bzero(crp, sizeof(HFSPlusCatalogFile)); + crp->recordType = kHFSPlusFileRecord; + crp->hfsPlusFile.fileID = cnid; + crp->hfsPlusFile.createDate = createtime; + crp->hfsPlusFile.contentModDate = createtime; + crp->hfsPlusFile.accessDate = createtime; + crp->hfsPlusFile.attributeModDate = createtime; + crp->hfsPlusFile.flags |= kHFSThreadExistsMask; + crp->hfsPlusFile.textEncoding = encoding; + bsdp = &crp->hfsPlusFile.bsdInfo; + switch(type) { + case S_IFBLK: + case S_IFCHR: + /* BLK/CHR need to save the device info */ + bsdp->special.rawDevice = attrp->ca_rdev; + break; + case S_IFREG: + /* Hardlink links need to save the linkref */ + fip = (FndrFileInfo *)&attrp->ca_finderinfo; + if ((SWAP_BE32(fip->fdType) == kHardLinkFileType) && + (SWAP_BE32(fip->fdCreator) == kHFSPlusCreator)) { + bsdp->special.iNodeNum = attrp->ca_rdev; + } + bcopy(attrp->ca_finderinfo, &crp->hfsPlusFile.userInfo, 32); + break; + case S_IFLNK: + /* Symlinks also have a type and creator */ + bcopy(attrp->ca_finderinfo, &crp->hfsPlusFile.userInfo, 32); + break; + } + *recordSize = sizeof(HFSPlusCatalogFile); + } + bsdp->ownerID = attrp->ca_uid; + bsdp->groupID = attrp->ca_gid; + bsdp->fileMode = attrp->ca_mode; + bsdp->adminFlags = attrp->ca_flags >> 16; + bsdp->ownerFlags = attrp->ca_flags & 0x000000FF; + } +} + + +/* + * builddesc - build a cnode descriptor from an HFS+ key + */ +static int +builddesc(const HFSPlusCatalogKey *key, cnid_t cnid, u_long hint, u_long encoding, + int isdir, struct cat_desc *descp) +{ + int result = 0; + char * nameptr; + long bufsize; + size_t utf8len; + + /* guess a size... */ + bufsize = (3 * key->nodeName.length) + 1; + MALLOC(nameptr, char *, bufsize, M_TEMP, M_WAITOK); + + result = utf8_encodestr(key->nodeName.unicode, + key->nodeName.length * sizeof(UniChar), + nameptr, (size_t *)&utf8len, + bufsize, ':', 0); + + if (result == ENAMETOOLONG) { + bufsize = 1 + utf8_encodelen(key->nodeName.unicode, + key->nodeName.length * sizeof(UniChar), + ':', 0); + FREE(nameptr, M_TEMP); + MALLOC(nameptr, char *, bufsize, M_TEMP, M_WAITOK); + + result = utf8_encodestr(key->nodeName.unicode, + key->nodeName.length * sizeof(UniChar), + nameptr, (size_t *)&utf8len, + bufsize, ':', 0); + } + descp->cd_parentcnid = key->parentID; + descp->cd_nameptr = nameptr; + descp->cd_namelen = utf8len; + descp->cd_cnid = cnid; + descp->cd_hint = hint; + descp->cd_flags = CD_DECOMPOSED | CD_HASBUF; + if (isdir) + descp->cd_flags |= CD_ISDIR; + descp->cd_encoding = encoding; + return result; +} + + +/* + * getbsdattr - get attributes in bsd format + * + */ +static void +getbsdattr(struct hfsmount *hfsmp, const struct HFSPlusCatalogFile *crp, struct cat_attr * attrp) +{ + int isDirectory = (crp->recordType == kHFSPlusFolderRecord); + const struct HFSPlusBSDInfo *bsd = &crp->bsdInfo; + + attrp->ca_nlink = 1; + attrp->ca_atime = to_bsd_time(crp->accessDate); + attrp->ca_mtime = to_bsd_time(crp->contentModDate); + attrp->ca_mtime_nsec = 0; + attrp->ca_ctime = to_bsd_time(crp->attributeModDate); + attrp->ca_itime = to_bsd_time(crp->createDate); + attrp->ca_btime = to_bsd_time(crp->backupDate); + + if ((bsd->fileMode & S_IFMT) == 0) { + attrp->ca_flags = 0; + attrp->ca_uid = hfsmp->hfs_uid; + attrp->ca_gid = hfsmp->hfs_gid; + if (isDirectory) + attrp->ca_mode = S_IFDIR | (hfsmp->hfs_dir_mask & ACCESSPERMS); + else + attrp->ca_mode = S_IFREG | (hfsmp->hfs_file_mask & ACCESSPERMS); + attrp->ca_rdev = 0; + } else { + attrp->ca_rdev = 0; + attrp->ca_uid = bsd->ownerID; + attrp->ca_gid = bsd->groupID; + attrp->ca_flags = bsd->ownerFlags | (bsd->adminFlags << 16); + attrp->ca_mode = (mode_t)bsd->fileMode; + switch (attrp->ca_mode & S_IFMT) { + case S_IFCHR: /* fall through */ + case S_IFBLK: + attrp->ca_rdev = bsd->special.rawDevice; + break; + case S_IFREG: + /* Pick up the hard link count */ + if (bsd->special.linkCount > 0) + attrp->ca_nlink = bsd->special.linkCount; + break; + } + + if (HFSTOVFS(hfsmp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) { + /* + * Override the permissions as determined by the mount auguments + * in ALMOST the same way unset permissions are treated but keep + * track of whether or not the file or folder is hfs locked + * by leaving the h_pflags field unchanged from what was unpacked + * out of the catalog. + */ + attrp->ca_uid = hfsmp->hfs_uid; + attrp->ca_gid = hfsmp->hfs_gid; + } + } + + if (isDirectory) { + if (!S_ISDIR(attrp->ca_mode)) { + attrp->ca_mode &= ~S_IFMT; + attrp->ca_mode |= S_IFDIR; + } + attrp->ca_nlink = 2 + ((HFSPlusCatalogFolder *)crp)->valence; + attrp->ca_entries = ((HFSPlusCatalogFolder *)crp)->valence; + } else { + /* Keep IMMUTABLE bits in sync with HFS locked flag */ + if (crp->flags & kHFSFileLockedMask) { + /* The file's supposed to be locked: + Make sure at least one of the IMMUTABLE bits is set: */ + if ((attrp->ca_flags & (SF_IMMUTABLE | UF_IMMUTABLE)) == 0) + attrp->ca_flags |= UF_IMMUTABLE; + } else { + /* The file's supposed to be unlocked: */ + attrp->ca_flags &= ~(SF_IMMUTABLE | UF_IMMUTABLE); + } + /* get total blocks (both forks) */ + attrp->ca_blocks = crp->dataFork.totalBlocks + crp->resourceFork.totalBlocks; + } + + attrp->ca_fileid = crp->fileID; + + bcopy(&crp->userInfo, attrp->ca_finderinfo, 32); +} + +/* + * promotekey - promote hfs key to hfs plus key + * + */ +static void +promotekey(struct hfsmount *hfsmp, const HFSCatalogKey *hfskey, + HFSPlusCatalogKey *keyp, u_long *encoding) +{ + hfs_to_unicode_func_t hfs_get_unicode = hfsmp->hfs_get_unicode; + UInt32 uniCount; + int error; + + *encoding = hfsmp->hfs_encoding; + + error = hfs_get_unicode(hfskey->nodeName, keyp->nodeName.unicode, + kHFSPlusMaxFileNameChars, &uniCount); + /* + * When an HFS name cannot be encoded with the current + * encoding use MacRoman as a fallback. + */ + if (error && hfsmp->hfs_encoding != kTextEncodingMacRoman) { + *encoding = 0; + (void) mac_roman_to_unicode(hfskey->nodeName, + keyp->nodeName.unicode, + kHFSPlusMaxFileNameChars, + &uniCount); + } + + keyp->nodeName.length = uniCount; + keyp->parentID = hfskey->parentID; +} + +/* + * promotefork - promote hfs fork info to hfs plus + * + */ +static void +promotefork(struct hfsmount *hfsmp, const struct HFSCatalogFile *filep, + int resource, struct cat_fork * forkp) +{ + struct HFSPlusExtentDescriptor *xp; + u_long blocksize = HFSTOVCB(hfsmp)->blockSize; + + bzero(forkp, sizeof(*forkp)); + xp = &forkp->cf_extents[0]; + if (resource) { + forkp->cf_size = filep->rsrcLogicalSize; + forkp->cf_blocks = filep->rsrcPhysicalSize / blocksize; + xp[0].startBlock = (u_int32_t)filep->rsrcExtents[0].startBlock; + xp[0].blockCount = (u_int32_t)filep->rsrcExtents[0].blockCount; + xp[1].startBlock = (u_int32_t)filep->rsrcExtents[1].startBlock; + xp[1].blockCount = (u_int32_t)filep->rsrcExtents[1].blockCount; + xp[2].startBlock = (u_int32_t)filep->rsrcExtents[2].startBlock; + xp[2].blockCount = (u_int32_t)filep->rsrcExtents[2].blockCount; + } else { + forkp->cf_size = filep->dataLogicalSize; + forkp->cf_blocks = filep->dataPhysicalSize / blocksize; + xp[0].startBlock = (u_int32_t)filep->dataExtents[0].startBlock; + xp[0].blockCount = (u_int32_t)filep->dataExtents[0].blockCount; + xp[1].startBlock = (u_int32_t)filep->dataExtents[1].startBlock; + xp[1].blockCount = (u_int32_t)filep->dataExtents[1].blockCount; + xp[2].startBlock = (u_int32_t)filep->dataExtents[2].startBlock; + xp[2].blockCount = (u_int32_t)filep->dataExtents[2].blockCount; + } +} + +/* + * promoteattr - promote hfs catalog attributes to hfs plus + * + */ +static void +promoteattr(struct hfsmount *hfsmp, const CatalogRecord *dataPtr, struct HFSPlusCatalogFile *crp) +{ + u_long blocksize = HFSTOVCB(hfsmp)->blockSize; + + if (dataPtr->recordType == kHFSFolderRecord) { + struct HFSCatalogFolder * folder; + + folder = (struct HFSCatalogFolder *) dataPtr; + crp->recordType = kHFSPlusFolderRecord; + crp->flags = folder->flags; + crp->fileID = folder->folderID; + crp->createDate = LocalToUTC(folder->createDate); + crp->contentModDate = LocalToUTC(folder->modifyDate); + crp->backupDate = LocalToUTC(folder->backupDate); + crp->reserved1 = folder->valence; + bcopy(&folder->userInfo, &crp->userInfo, 32); + } else /* file */ { + struct HFSCatalogFile * file; + + file = (struct HFSCatalogFile *) dataPtr; + crp->recordType = kHFSPlusFileRecord; + crp->flags = file->flags; + crp->fileID = file->fileID; + crp->createDate = LocalToUTC(file->createDate); + crp->contentModDate = LocalToUTC(file->modifyDate); + crp->backupDate = LocalToUTC(file->backupDate); + crp->reserved1 = 0; + bcopy(&file->userInfo, &crp->userInfo, 16); + bcopy(&file->finderInfo, &crp->finderInfo, 16); + crp->dataFork.totalBlocks = file->dataPhysicalSize / blocksize; + crp->resourceFork.totalBlocks = file->rsrcPhysicalSize / blocksize; + } + crp->textEncoding = 0; + crp->attributeModDate = crp->contentModDate; + crp->accessDate = crp->contentModDate; + bzero(&crp->bsdInfo, sizeof(HFSPlusBSDInfo)); + crp->reserved2 = 0; +} + +/* + * Build a catalog node thread record from a catalog key + * and return the size of the record. + */ +static int +buildthread(void *keyp, void *recp, int std_hfs, int directory) +{ + int size = 0; + + if (std_hfs) { + HFSCatalogKey *key = (HFSCatalogKey *)keyp; + HFSCatalogThread *rec = (HFSCatalogThread *)recp; + + size = sizeof(HFSCatalogThread); + bzero(rec, size); + if (directory) + rec->recordType = kHFSFolderThreadRecord; + else + rec->recordType = kHFSFileThreadRecord; + rec->parentID = key->parentID; + bcopy(key->nodeName, rec->nodeName, key->nodeName[0]+1); + + } else /* HFS+ */ { + HFSPlusCatalogKey *key = (HFSPlusCatalogKey *)keyp; + HFSPlusCatalogThread *rec = (HFSPlusCatalogThread *)recp; + + size = sizeof(HFSPlusCatalogThread); + if (directory) + rec->recordType = kHFSPlusFolderThreadRecord; + else + rec->recordType = kHFSPlusFileThreadRecord; + rec->reserved = 0; + rec->parentID = key->parentID; + bcopy(&key->nodeName, &rec->nodeName, + sizeof(UniChar) * (key->nodeName.length + 1)); + + /* HFS Plus has varaible sized thread records */ + size -= (sizeof(rec->nodeName.unicode) - + (rec->nodeName.length * sizeof(UniChar))); + } + + return (size); +} + +/* + * Build a catalog node thread key. + */ +static void +buildthreadkey(HFSCatalogNodeID parentID, int std_hfs, CatalogKey *key) +{ + if (std_hfs) { + key->hfs.keyLength = kHFSCatalogKeyMinimumLength; + key->hfs.reserved = 0; + key->hfs.parentID = parentID; + key->hfs.nodeName[0] = 0; + } else { + key->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength; + key->hfsPlus.parentID = parentID; + key->hfsPlus.nodeName.length = 0; + } +} + +/* + * Extract the text encoding from a catalog node record. + */ +static u_long +getencoding(const CatalogRecord *crp) +{ + u_long encoding; + + if (crp->recordType == kHFSPlusFolderRecord) + encoding = crp->hfsPlusFolder.textEncoding; + else if (crp->recordType == kHFSPlusFileRecord) + encoding = crp->hfsPlusFile.textEncoding; + else + encoding = 0; + + return (encoding); +} + +/* + * Extract the CNID from a catalog node record. + */ +static cnid_t +getcnid(const CatalogRecord *crp) +{ + cnid_t cnid = 0; + + switch (crp->recordType) { + case kHFSFolderRecord: + cnid = crp->hfsFolder.folderID; + break; + case kHFSFileRecord: + cnid = crp->hfsFile.fileID; + break; + case kHFSPlusFolderRecord: + cnid = crp->hfsPlusFolder.folderID; + break; + case kHFSPlusFileRecord: + cnid = crp->hfsPlusFile.fileID; + break; + } + return (cnid); +} + +/* + * Extract the parent ID from a catalog node record. + */ +static cnid_t +getparentcnid(const CatalogRecord *recp) +{ + cnid_t cnid = 0; + + switch (recp->recordType) { + case kHFSFileThreadRecord: + case kHFSFolderThreadRecord: + cnid = recp->hfsThread.parentID; + break; + + case kHFSPlusFileThreadRecord: + case kHFSPlusFolderThreadRecord: + cnid = recp->hfsPlusThread.parentID; + break; + } + return (cnid); +} + +/* + * Determine if a catalog node record is a directory. + */ +static int +isadir(const CatalogRecord *crp) +{ + return (crp->recordType == kHFSFolderRecord || + crp->recordType == kHFSPlusFolderRecord); +} + + diff --git a/bsd/hfs/hfs_catalog.h b/bsd/hfs/hfs_catalog.h new file mode 100644 index 000000000..da27320b1 --- /dev/null +++ b/bsd/hfs/hfs_catalog.h @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#ifndef __HFS_CATALOG__ +#define __HFS_CATALOG__ + +#include + +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE +#include +#include +#include + +#include + +/* HFS Catalog */ + + +/* + * Catalog ADTs + * + * The cat_desc, cat_attr, and cat_fork structures are + * use to import/export data to/from the Catalog file. + * The fields in these structures are always in BSD + * runtime format (e.g. dates and names). + */ + +typedef u_int32_t cnid_t; + +/* + * Catalog Node Descriptor (runtime) + */ +struct cat_desc { + u_int8_t cd_flags; /* see below (8 bits) */ + u_int8_t cd_encoding; /* name encoding */ + int16_t cd_namelen; /* length of cnode name */ + char * cd_nameptr; /* pointer to cnode name */ + cnid_t cd_parentcnid; /* parent directory CNID */ + u_long cd_hint; /* catalog file hint */ + cnid_t cd_cnid; /* cnode id (for getattrlist) */ +}; + +/* cd_flags */ +#define CD_HASBUF 0x01 /* allocated filename buffer */ +#define CD_DECOMPOSED 0x02 /* name is fully decomposed */ +#define CD_ISDIR 0x80 /* describes a directory */ + +/* + * Catalog Node Attributes (runtime) + */ +struct cat_attr { + cnid_t ca_fileid; /* inode number (for stat) normally == cnid */ + mode_t ca_mode; /* file access mode and type (16 bits) */ + nlink_t ca_nlink; /* file link count (16 bit integer) */ + uid_t ca_uid; /* file owner */ + gid_t ca_gid; /* file group */ + dev_t ca_rdev; /* device a special file represents */ + time_t ca_atime; /* last access time */ + time_t ca_mtime; /* last data modification time */ + int32_t ca_mtime_nsec; /* last data modification time nanosec */ + time_t ca_ctime; /* last file status change */ + time_t ca_itime; /* file initialization time */ + time_t ca_btime; /* last backup time */ + u_long ca_flags; /* status flags (chflags) */ + union { + u_int32_t cau_blocks; /* total file blocks used (rsrc + data) */ + u_int32_t cau_entries; /* total directory entries (valence) */ + } ca_union; + u_int8_t ca_finderinfo[32]; /* Opaque Finder information */ +}; +/* Aliases for common fields */ +#define ca_blocks ca_union.cau_blocks +#define ca_entries ca_union.cau_entries + +/* + * Catalog Node Fork (runtime + on disk) + */ +struct cat_fork { + u_int64_t cf_size; /* fork's logical size in bytes */ + u_int32_t cf_clump; /* fork's clump size in bytes */ + u_int32_t cf_blocks; /* total blocks used by this fork */ + struct HFSPlusExtentDescriptor cf_extents[8]; /* initial set of extents */ +}; + + +/* + * Catalog Node Entry + * + * A cat_entry is used for bulk enumerations (hfs_readdirattr). + */ +struct cat_entry { + struct cat_desc ce_desc; + struct cat_attr ce_attr; + off_t ce_datasize; + off_t ce_rsrcsize; + u_long ce_datablks; + u_long ce_rsrcblks; +}; + +#define MAXCATENTRIES 8 +/* + * Catalog Node Entry List + * + * A cat_entrylist is a list of Catalog Node Entries. + */ +struct cat_entrylist { + u_long maxentries; /* length of list */ + u_long realentries; /* valid entry count */ + struct cat_entry entry[MAXCATENTRIES]; /* array of entries */ +}; + +/* + * Catalog Interface + * + * These functions perform a catalog transactions. The + * catalog b-tree is abstracted through this interface. + * (please don't go around it) + */ + +struct hfsmount; + +extern void cat_releasedesc(struct cat_desc *descp); + +extern int cat_create ( struct hfsmount *hfsmp, + struct cat_desc *descp, + struct cat_attr *attrp, + struct cat_desc *out_descp); + +extern int cat_delete ( struct hfsmount *hfsmp, + struct cat_desc *descp, + struct cat_attr *attrp); + +extern int cat_lookup ( struct hfsmount *hfsmp, + struct cat_desc *descp, + int wantrsrc, + struct cat_desc *outdescp, + struct cat_attr *attrp, + struct cat_fork *forkp); + +extern int cat_idlookup (struct hfsmount *hfsmp, + cnid_t cnid, + struct cat_desc *outdescp, + struct cat_attr *attrp, + struct cat_fork *forkp); + +extern int cat_getentriesattr( + struct hfsmount *hfsmp, + struct cat_desc *prevdesc, + int index, + struct cat_entrylist *ce_list); + +extern int cat_rename ( struct hfsmount * hfsmp, + struct cat_desc * from_cdp, + struct cat_desc * todir_cdp, + struct cat_desc * to_cdp, + struct cat_desc * cdp); + +extern int cat_update ( struct hfsmount *hfsmp, + struct cat_desc *descp, + struct cat_attr *attrp, + struct cat_fork *dataforkp, + struct cat_fork *rsrcforkp); + +extern int cat_getdirentries( + struct hfsmount *hfsmp, + struct cat_desc *descp, + struct uio *uio, + int *eofflag); + +extern int cat_insertfilethread ( + struct hfsmount *hfsmp, + struct cat_desc *descp); + +#endif /* __APPLE_API_PRIVATE */ +#endif /* KERNEL */ +#endif /* __HFS_CATALOG__ */ diff --git a/bsd/hfs/hfs_chash.c b/bsd/hfs/hfs_chash.c new file mode 100644 index 000000000..5cc8d871d --- /dev/null +++ b/bsd/hfs/hfs_chash.c @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * Copyright (c) 1982, 1986, 1989, 1991, 1993, 1995 + * 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. + * + * @(#)hfs_chash.c + * derived from @(#)ufs_ihash.c 8.7 (Berkeley) 5/17/95 + */ + +#include +#include +#include +#include +#include +#include + +#include "hfs_cnode.h" + + +/* + * Structures associated with cnode caching. + */ +LIST_HEAD(cnodehashhead, cnode) *cnodehashtbl; +u_long cnodehash; /* size of hash table - 1 */ +#define CNODEHASH(device, inum) (&cnodehashtbl[((device) + (inum)) & cnodehash]) +struct slock hfs_chash_slock; + +/* + * Initialize cnode hash table. + */ +__private_extern__ +void +hfs_chashinit() +{ + cnodehashtbl = hashinit(desiredvnodes, M_HFSMNT, &cnodehash); + simple_lock_init(&hfs_chash_slock); +} + + +/* + * Use the device, inum pair to find the incore cnode. + * + * If it is in core, but locked, wait for it. + * + * If the requested vnode (fork) is not available, then + * take a reference on the other vnode (fork) so that + * the upcoming getnewvnode can not aquire it. + */ +__private_extern__ +struct cnode * +hfs_chashget(dev_t dev, ino_t inum, int wantrsrc, + struct vnode **vpp, struct vnode **rvpp) +{ + struct proc *p = current_proc(); + struct cnode *cp; + struct vnode *vp; + int error; + + *vpp = NULLVP; + *rvpp = NULLVP; + /* + * Go through the hash list + * If a cnode is in the process of being cleaned out or being + * allocated, wait for it to be finished and then try again. + */ +loop: + simple_lock(&hfs_chash_slock); + for (cp = CNODEHASH(dev, inum)->lh_first; cp; cp = cp->c_hash.le_next) { + if ((cp->c_fileid != inum) || (cp->c_dev != dev)) + continue; + if (ISSET(cp->c_flag, C_ALLOC)) { + /* + * cnode is being created. Wait for it to finish. + */ + SET(cp->c_flag, C_WALLOC); + simple_unlock(&hfs_chash_slock); + (void) tsleep((caddr_t)cp, PINOD, "hfs_chashget-1", 0); + goto loop; + } + if (ISSET(cp->c_flag, C_TRANSIT)) { + /* + * cnode is getting reclaimed wait for + * the operation to complete and return + * error + */ + SET(cp->c_flag, C_WTRANSIT); + simple_unlock(&hfs_chash_slock); + (void)tsleep((caddr_t)cp, PINOD, "hfs_chashget-2", 0); + goto loop; + } + if (cp->c_flag & C_NOEXISTS) + continue; + + /* + * Try getting the desired vnode first. If + * it isn't available then take a reference + * on the other vnode. + */ + vp = wantrsrc ? cp->c_rsrc_vp : cp->c_vp; + if (vp == NULLVP) + vp = wantrsrc ? cp->c_vp : cp->c_rsrc_vp; + if (vp == NULLVP) + panic("hfs_chashget: orphaned cnode in hash"); + + simple_lock(&vp->v_interlock); + simple_unlock(&hfs_chash_slock); + if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) + goto loop; + else if (cp->c_flag & C_NOEXISTS) { + /* + * While we were blocked the cnode got deleted. + */ + vput(vp); + goto loop; + } + + if (VNODE_IS_RSRC(vp)) + *rvpp = vp; + else + *vpp = vp; + /* + * Note that vget can block before aquiring the + * cnode lock. So we need to check if the vnode + * we wanted was created while we blocked. + */ + if (wantrsrc && *rvpp == NULL && cp->c_rsrc_vp) { + error = vget(cp->c_rsrc_vp, 0, p); + vput(*vpp); /* ref no longer needed */ + *vpp = NULL; + if (error) + goto loop; + *rvpp = cp->c_rsrc_vp; + + } else if (!wantrsrc && *vpp == NULL && cp->c_vp) { + error = vget(cp->c_vp, 0, p); + vput(*rvpp); /* ref no longer needed */ + *rvpp = NULL; + if (error) + goto loop; + *vpp = cp->c_vp; + } + return (cp); + } + simple_unlock(&hfs_chash_slock); + return (NULL); +} + + +/* + * Insert a cnode into the hash table. + */ +__private_extern__ +void +hfs_chashinsert(struct cnode *cp) +{ + if (cp->c_fileid == 0) + panic("hfs_chashinsert: trying to insert file id 0"); + simple_lock(&hfs_chash_slock); + LIST_INSERT_HEAD(CNODEHASH(cp->c_dev, cp->c_fileid), cp, c_hash); + simple_unlock(&hfs_chash_slock); +} + + +/* + * Remove a cnode from the hash table. + */ +__private_extern__ +void +hfs_chashremove(struct cnode *cp) +{ + simple_lock(&hfs_chash_slock); + LIST_REMOVE(cp, c_hash); + cp->c_hash.le_next = NULL; + cp->c_hash.le_prev = NULL; + simple_unlock(&hfs_chash_slock); +} + diff --git a/bsd/hfs/hfs_cnode.c b/bsd/hfs/hfs_cnode.c new file mode 100644 index 000000000..d59163ab5 --- /dev/null +++ b/bsd/hfs/hfs_cnode.c @@ -0,0 +1,650 @@ +/* + * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +extern int prtactive; + + +extern void hfs_relnamehints(struct cnode *dcp); + + +/* + * Last reference to an cnode. If necessary, write or delete it. + */ +__private_extern__ +int +hfs_inactive(ap) + struct vop_inactive_args /* { + struct vnode *a_vp; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); + struct hfsmount *hfsmp = VTOHFS(vp); + struct proc *p = ap->a_p; + struct timeval tv; + int error = 0; + int recycle = 0; + int forkcount = 0; + int truncated = 0; + + if (prtactive && vp->v_usecount != 0) + vprint("hfs_inactive: pushing active", vp); + + /* + * Ignore nodes related to stale file handles. + */ + if (cp->c_mode == 0) + goto out; + + if (vp->v_mount->mnt_flag & MNT_RDONLY) + goto out; + + if (cp->c_datafork) + ++forkcount; + if (cp->c_rsrcfork) + ++forkcount; + + /* If needed, get rid of any fork's data for a deleted file */ + if ((cp->c_flag & C_DELETED) && + vp->v_type == VREG && + (VTOF(vp)->ff_blocks != 0)) { + error = VOP_TRUNCATE(vp, (off_t)0, IO_NDELAY, NOCRED, p); + if (error) goto out; + truncated = 1; + recycle = 1; + } + + /* + * Check for a postponed deletion. + * (only delete cnode when the last fork goes inactive) + */ + if ((cp->c_flag & C_DELETED) && (forkcount <= 1)) { + /* + * Mark cnode in transit so that one can get this + * cnode from cnode hash. + */ + SET(cp->c_flag, C_TRANSIT); + cp->c_flag &= ~C_DELETED; + cp->c_rdev = 0; + + /* Lock catalog b-tree */ + error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p); + if (error) goto out; + + if (cp->c_blocks > 0) + printf("hfs_inactive: attempting to delete a non-empty file!"); + + /* + * The descriptor name may be zero, + * in which case the fileid is used. + */ + error = cat_delete(hfsmp, &cp->c_desc, &cp->c_attr); + + if (error && truncated && (error != ENXIO)) + printf("hfs_inactive: couldn't delete a truncated file!"); + + /* Update HFS Private Data dir */ + if (error == 0) { + hfsmp->hfs_privdir_attr.ca_entries--; + (void)cat_update(hfsmp, &hfsmp->hfs_privdir_desc, + &hfsmp->hfs_privdir_attr, NULL, NULL); + } + + /* Unlock catalog b-tree */ + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); + if (error) goto out; + +#if QUOTA + if (!hfs_getinoquota(cp)) + (void)hfs_chkiq(cp, -1, NOCRED, 0); +#endif /* QUOTA */ + + cp->c_mode = 0; + cp->c_flag |= C_NOEXISTS | C_CHANGE | C_UPDATE; + + if (error == 0) + hfs_volupdate(hfsmp, VOL_RMFILE, 0); + } + + /* Push any defered access times to disk */ + if (cp->c_flag & C_ATIMEMOD) { + cp->c_flag &= ~C_ATIMEMOD; + if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord) + cp->c_flag |= C_MODIFIED; + } + if (cp->c_flag & (C_ACCESS | C_CHANGE | C_MODIFIED | C_UPDATE)) { + tv = time; + VOP_UPDATE(vp, &tv, &tv, 0); + } +out: + VOP_UNLOCK(vp, 0, p); + /* + * If we are done with the vnode, reclaim it + * so that it can be reused immediately. + */ + if (cp->c_mode == 0 || recycle) + vrecycle(vp, (struct slock *)0, p); + + return (error); +} + + +/* + * Reclaim a cnode so that it can be used for other purposes. + */ +__private_extern__ +int +hfs_reclaim(ap) + struct vop_reclaim_args /* { + struct vnode *a_vp; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); + struct vnode *devvp = NULL; + struct filefork *fp = NULL; + struct filefork *altfp = NULL; + int i; + + if (prtactive && vp->v_usecount != 0) + vprint("hfs_reclaim(): pushing active", vp); + + devvp = cp->c_devvp; /* For later releasing */ + + /* + * Find file fork for this vnode (if any) + * Also check if another fork is active + */ + if ((fp = cp->c_datafork) && (cp->c_vp == vp)) { + cp->c_datafork = NULL; + cp->c_vp = NULL; + altfp = cp->c_rsrcfork; + } else if ((fp = cp->c_rsrcfork) && (cp->c_rsrc_vp == vp)) { + cp->c_rsrcfork = NULL; + cp->c_rsrc_vp = NULL; + altfp = cp->c_datafork; + } else { + cp->c_vp = NULL; + fp = NULL; + altfp = NULL; + } + + /* + * On the last fork, remove the cnode from its hash chain. + */ + if (altfp == NULL) + hfs_chashremove(cp); + + /* Release the file fork and related data (can block) */ + if (fp) { + fp->ff_cp = NULL; + /* Dump cached symlink data */ + if ((vp->v_type == VLNK) && (fp->ff_symlinkptr != NULL)) { + FREE(fp->ff_symlinkptr, M_TEMP); + fp->ff_symlinkptr = NULL; + } + FREE_ZONE(fp, sizeof(struct filefork), M_HFSFORK); + fp = NULL; + } + + /* + * Purge old data structures associated with the cnode. + */ + cache_purge(vp); + if (devvp && altfp == NULL) { + cp->c_devvp = NULL; + vrele(devvp); + } + + vp->v_data = NULL; + + /* + * If there was only one active fork then we can release the cnode. + */ + if (altfp == NULL) { +#if QUOTA + for (i = 0; i < MAXQUOTAS; i++) { + if (cp->c_dquot[i] != NODQUOT) { + dqrele(vp, cp->c_dquot[i]); + cp->c_dquot[i] = NODQUOT; + } + } +#endif /* QUOTA */ + /* + * Free any left over directory indices + */ + if (vp->v_type == VDIR) + hfs_relnamehints(cp); + + /* + * If the descriptor has a name then release it + */ + if (cp->c_desc.cd_flags & CD_HASBUF) { + char *nameptr; + + nameptr = cp->c_desc.cd_nameptr; + cp->c_desc.cd_nameptr = 0; + cp->c_desc.cd_flags &= ~CD_HASBUF; + cp->c_desc.cd_namelen = 0; + FREE(nameptr, M_TEMP); + } + CLR(cp->c_flag, (C_ALLOC | C_TRANSIT)); + if (ISSET(cp->c_flag, C_WALLOC) || ISSET(cp->c_flag, C_WTRANSIT)) + wakeup(cp); + FREE_ZONE(cp, sizeof(struct cnode), M_HFSNODE); + + } + + return (0); +} + + +/* + * get a cnode + * + * called by hfs_lookup and hfs_vget (descp == NULL) + * + * returns a locked vnode for cnode for given cnid/fileid + */ +__private_extern__ +int +hfs_getcnode(struct hfsmount *hfsmp, cnid_t cnid, struct cat_desc *descp, int wantrsrc, + struct cat_attr *attrp, struct cat_fork *forkp, struct vnode **vpp) +{ + dev_t dev = hfsmp->hfs_raw_dev; + struct vnode *vp = NULL; + struct vnode *rvp = NULL; + struct vnode *new_vp = NULL; + struct cnode *cp = NULL; + struct proc *p = current_proc(); + int retval = E_NONE; + + /* Check if unmount in progress */ + if (HFSTOVFS(hfsmp)->mnt_kern_flag & MNTK_UNMOUNT) { + *vpp = NULL; + return (EPERM); + } + + /* + * Check the hash for an active cnode + */ + cp = hfs_chashget(dev, cnid, wantrsrc, &vp, &rvp); + if (cp != NULL) { + /* hide open files that have been deleted */ + if ((hfsmp->hfs_private_metadata_dir != 0) + && (cp->c_parentcnid == hfsmp->hfs_private_metadata_dir) + && (cp->c_nlink == 0)) { + retval = ENOENT; + goto exit; + } + if (wantrsrc && rvp != NULL) { + vp = rvp; + rvp = NULL; + goto done; + } + if (!wantrsrc && vp != NULL) { + /* Hardlinks need an updated catalog descriptor */ + if (descp && cp->c_flag & C_HARDLINK) { + replace_desc(cp, descp); + } + /* We have a vnode so we're done. */ + goto done; + } + } + + /* + * There was no active vnode so get a new one. + * Use the existing cnode (if any). + */ + if (descp != NULL) { + /* + * hfs_lookup case, use descp, attrp and forkp + */ + retval = hfs_getnewvnode(hfsmp, cp, descp, wantrsrc, attrp, + forkp, &new_vp); + } else { + struct cat_desc cndesc = {0}; + struct cat_attr cnattr = {0}; + struct cat_fork cnfork = {0}; + + /* + * hfs_vget case, need to lookup entry (by file id) + */ + if (cnid == kRootParID) { + static char hfs_rootname[] = "/"; + + cndesc.cd_nameptr = &hfs_rootname[0]; + cndesc.cd_namelen = 1; + cndesc.cd_parentcnid = kRootParID; + cndesc.cd_cnid = kRootParID; + cndesc.cd_flags = CD_ISDIR; + + cnattr.ca_fileid = kRootParID; + cnattr.ca_nlink = 2; + cnattr.ca_mode = (S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO); + } else { + /* Lock catalog b-tree */ + retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_SHARED, p); + if (retval) + goto exit; + + retval = cat_idlookup(hfsmp, cnid, &cndesc, &cnattr, &cnfork); + + /* Unlock catalog b-tree */ + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); + if (retval) + goto exit; + + /* Hide open files that have been deleted */ + if ((hfsmp->hfs_private_metadata_dir != 0) && + (cndesc.cd_parentcnid == hfsmp->hfs_private_metadata_dir)) { + cat_releasedesc(&cndesc); + retval = ENOENT; + goto exit; + } + } + + retval = hfs_getnewvnode(hfsmp, cp, &cndesc, 0, &cnattr, &cnfork, &new_vp); + + /* Hardlinks may need an updated catalog descriptor */ + if (retval == 0 + && new_vp + && (VTOC(new_vp)->c_flag & C_HARDLINK) + && cndesc.cd_nameptr + && cndesc.cd_namelen > 0) { + replace_desc(VTOC(new_vp), &cndesc); + } + cat_releasedesc(&cndesc); + } +exit: + /* Release reference taken on opposite vnode (if any). */ + if (vp) + vput(vp); + else if (rvp) + vput(rvp); + + if (retval) { + *vpp = NULL; + return (retval); + } + vp = new_vp; +done: + /* The cnode's vnode should be in vp. */ + if (vp == NULL) + panic("hfs_getcnode: missing vp!"); + + UBCINFOCHECK("hfs_getcnode", vp); + *vpp = vp; + return (0); +} + + +/* + * hfs_getnewvnode - get new default vnode + * + * the vnode is returned locked + */ +extern int (**hfs_vnodeop_p) (void *); +extern int (**hfs_specop_p) (void *); +extern int (**hfs_fifoop_p) (void *); + +__private_extern__ +int +hfs_getnewvnode(struct hfsmount *hfsmp, struct cnode *cp, + struct cat_desc *descp, int wantrsrc, + struct cat_attr *attrp, struct cat_fork *forkp, + struct vnode **vpp) +{ + struct mount *mp = HFSTOVFS(hfsmp); + struct vnode *vp = NULL; + struct vnode *rvp = NULL; + struct vnode *new_vp = NULL; + struct cnode *cp2 = NULL; + struct filefork *fp = NULL; + int allocated = 0; + int i; + int retval; + dev_t dev; + struct proc *p = current_proc(); + + /* Bail when unmount is in progress */ + if (mp->mnt_kern_flag & MNTK_UNMOUNT) { + *vpp = NULL; + return (EPERM); + } + +#if !FIFO + if (IFTOVT(attrp->ca_mode) == VFIFO) { + *vpp = NULL; + return (EOPNOTSUPP); + } +#endif + dev = hfsmp->hfs_raw_dev; + + /* If no cnode was passed in then create one */ + if (cp == NULL) { + MALLOC_ZONE(cp2, struct cnode *, sizeof(struct cnode), + M_HFSNODE, M_WAITOK); + bzero(cp2, sizeof(struct cnode)); + allocated = 1; + SET(cp2->c_flag, C_ALLOC); + cp2->c_cnid = descp->cd_cnid; + cp2->c_fileid = attrp->ca_fileid; + cp2->c_dev = dev; + lockinit(&cp2->c_lock, PINOD, "cnode", 0, 0); + (void) lockmgr(&cp2->c_lock, LK_EXCLUSIVE, (struct slock *)0, p); + /* + * There were several blocking points since we first + * checked the hash. Now that we're through blocking, + * check the hash again in case we're racing for the + * same cnode. + */ + cp = hfs_chashget(dev, attrp->ca_fileid, wantrsrc, &vp, &rvp); + if (cp != NULL) { + /* We lost the race - use the winner's cnode */ + FREE_ZONE(cp2, sizeof(struct cnode), M_HFSNODE); + allocated = 0; + if (wantrsrc && rvp != NULL) { + *vpp = rvp; + return (0); + } + if (!wantrsrc && vp != NULL) { + *vpp = vp; + return (0); + } + } else /* allocated */ { + cp = cp2; + hfs_chashinsert(cp); + } + } + + /* Allocate a new vnode. If unsuccesful, leave after freeing memory */ + if ((retval = getnewvnode(VT_HFS, mp, hfs_vnodeop_p, &new_vp))) { + if (allocated) { + hfs_chashremove(cp); + if (ISSET(cp->c_flag, C_WALLOC)) { + CLR(cp->c_flag, C_WALLOC); + wakeup(cp); + } + FREE_ZONE(cp2, sizeof(struct cnode), M_HFSNODE); + allocated = 0; + } else if (rvp) { + vput(rvp); + } else if (vp) { + vput(vp); + } + *vpp = NULL; + return (retval); + } + if (allocated) { + bcopy(attrp, &cp->c_attr, sizeof(struct cat_attr)); + bcopy(descp, &cp->c_desc, sizeof(struct cat_desc)); + } + new_vp->v_data = cp; + if (wantrsrc && S_ISREG(cp->c_mode)) + cp->c_rsrc_vp = new_vp; + else + cp->c_vp = new_vp; + + /* Release reference taken on opposite vnode (if any). */ + if (rvp) + vput(rvp); + if (vp) + vput(vp); + + vp = new_vp; + vp->v_ubcinfo = UBC_NOINFO; + + /* + * If this is a new cnode then initialize it using descp and attrp... + */ + if (allocated) { + /* The name was inherited so clear descriptor state... */ + descp->cd_namelen = 0; + descp->cd_nameptr = NULL; + descp->cd_flags &= ~CD_HASBUF; + + /* Tag hardlinks */ + if (IFTOVT(cp->c_mode) == VREG && + (descp->cd_cnid != attrp->ca_fileid)) { + cp->c_flag |= C_HARDLINK; + } + + /* Take one dev reference for each non-directory cnode */ + if (IFTOVT(cp->c_mode) != VDIR) { + cp->c_devvp = hfsmp->hfs_devvp; + VREF(cp->c_devvp); + } +#if QUOTA + for (i = 0; i < MAXQUOTAS; i++) + cp->c_dquot[i] = NODQUOT; +#endif /* QUOTA */ + } + + if (IFTOVT(cp->c_mode) != VDIR) { + if (forkp && attrp->ca_blocks < forkp->cf_blocks) + panic("hfs_getnewvnode: bad ca_blocks (too small)"); + /* + * Allocate and initialize a file fork... + */ + MALLOC_ZONE(fp, struct filefork *, sizeof(struct filefork), + M_HFSFORK, M_WAITOK); + bzero(fp, sizeof(struct filefork)); + fp->ff_cp = cp; + if (forkp) + bcopy(forkp, &fp->ff_data, sizeof(HFSPlusForkData)); + if (fp->ff_clumpsize == 0) + fp->ff_clumpsize = HFSTOVCB(hfsmp)->vcbClpSiz; + rl_init(&fp->ff_invalidranges); + if (wantrsrc) { + if (cp->c_rsrcfork != NULL) + panic("stale rsrc fork"); + cp->c_rsrcfork = fp; + } else { + if (cp->c_datafork != NULL) + panic("stale data fork"); + cp->c_datafork = fp; + } + } + + /* + * Finish vnode initialization. + * Setting the v_type 'stamps' the vnode as 'complete', + * so should be done almost last. + * + * At this point the vnode should be locked and fully + * allocated. And ready to be used or accessed. (though + * having it locked prevents most of this, it can still + * be accessed through lists and hashes). + */ + vp->v_type = IFTOVT(cp->c_mode); + + /* Tag system files */ + if ((descp->cd_cnid < kHFSFirstUserCatalogNodeID) && (vp->v_type == VREG)) + vp->v_flag |= VSYSTEM; + /* Tag root directory */ + if (cp->c_cnid == kRootDirID) + vp->v_flag |= VROOT; + + if ((vp->v_type == VREG) && !(vp->v_flag & VSYSTEM) + && (UBCINFOMISSING(vp) || UBCINFORECLAIMED(vp))) { + ubc_info_init(vp); + } else { + vp->v_ubcinfo = UBC_NOINFO; + } + + if (vp->v_type == VCHR || vp->v_type == VBLK) { + struct vnode *nvp; + + vp->v_op = hfs_specop_p; + if ((nvp = checkalias(vp, cp->c_rdev, mp))) { + /* + * Discard unneeded vnode, but save its cnode. + * Note that the lock is carried over in the + * cnode to the replacement vnode. + */ + nvp->v_data = vp->v_data; + vp->v_data = NULL; + vp->v_op = spec_vnodeop_p; + vrele(vp); + vgone(vp); + /* + * Reinitialize aliased cnode. + * Assume its not a resource fork. + */ + cp->c_vp = nvp; + vp = nvp; + } + } else if (vp->v_type == VFIFO) { +#if FIFO + vp->v_op = hfs_fifoop_p; +#endif + } + + /* Vnode is now initialized - see if anyone was waiting for it. */ + CLR(cp->c_flag, C_ALLOC); + if (ISSET(cp->c_flag, C_WALLOC)) { + CLR(cp->c_flag, C_WALLOC); + wakeup((caddr_t)cp); + } + + *vpp = vp; + return (0); +} + diff --git a/bsd/hfs/hfs_cnode.h b/bsd/hfs/hfs_cnode.h new file mode 100644 index 000000000..998514360 --- /dev/null +++ b/bsd/hfs/hfs_cnode.h @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#ifndef _HFS_CNODE_H_ +#define _HFS_CNODE_H_ + +#include + +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* + * The filefork is used to represent an HFS file fork (data or resource). + * Reading or writing any of these fields requires holding cnode lock. + */ +struct filefork { + struct cnode *ff_cp; /* cnode associated with this fork */ + struct rl_head ff_invalidranges; /* Areas of disk that should read back as zeroes */ + union { + struct hfslockf *ffu_lockf; /* Head of byte-level lock list. */ + void *ffu_sysdata; /* private data for system files */ + char *ffu_symlinkptr; /* symbolic link pathname */ + } ff_un; + struct cat_fork ff_data; + u_int32_t ff_unallocblocks; /* unallocated blocks (until cmap) */ +}; + +/* Aliases for common fields */ +#define ff_size ff_data.cf_size +#define ff_clumpsize ff_data.cf_clump +#define ff_blocks ff_data.cf_blocks +#define ff_extents ff_data.cf_extents +#define ff_symlinkptr ff_un.ffu_symlinkptr +#define ff_lockf ff_un.ffu_lockf + + +/* The btree code still needs these... */ +#define fcbEOF ff_size +#define fcbClmpSize ff_clumpsize +#define fcbExtents ff_extents +#define fcbBTCBPtr ff_un.ffu_sysdata + + +/* + * Directory index entry + */ +struct hfs_index { + SLIST_ENTRY(hfs_index) hi_link; + int hi_index; + void *hi_thread; /* thread that created index entry */ + char hi_name[1]; +}; + +/* + * The cnode is used to represent each active (or recently active) + * file or directory in the HFS filesystem. + * + * Reading or writing any of these fields requires holding c_lock. + */ +struct cnode { + struct lock__bsd__ c_lock; /* cnode's lock */ + LIST_ENTRY(cnode) c_hash; /* cnode's hash chain */ + u_int32_t c_flag; /* cnode's runtime flags */ + struct vnode *c_vp; /* vnode for data fork or dir */ + struct vnode *c_rsrc_vp; /* vnode for resource fork */ + struct vnode *c_devvp; /* vnode for block I/O */ + dev_t c_dev; /* cnode's device */ + struct dquot *c_dquot[MAXQUOTAS]; /* cnode's quota info */ + cnid_t c_childhint; /* catalog hint for children */ + struct cat_desc c_desc; /* cnode's descriptor */ + struct cat_attr c_attr; /* cnode's attributes */ + SLIST_HEAD(hfs_indexhead, hfs_index) c_indexlist; /* directory index list */ + struct filefork *c_datafork; /* cnode's data fork */ + struct filefork *c_rsrcfork; /* cnode's rsrc fork */ +}; + +/* Aliases for common cnode fields */ +#define c_cnid c_desc.cd_cnid +#define c_hint c_desc.cd_hint +#define c_parentcnid c_desc.cd_parentcnid +#define c_encoding c_desc.cd_encoding + +#define c_fileid c_attr.ca_fileid +#define c_mode c_attr.ca_mode +#define c_nlink c_attr.ca_nlink +#define c_uid c_attr.ca_uid +#define c_gid c_attr.ca_gid +#define c_rdev c_attr.ca_rdev +#define c_atime c_attr.ca_atime +#define c_mtime c_attr.ca_mtime +#define c_mtime_nsec c_attr.ca_mtime_nsec +#define c_ctime c_attr.ca_ctime +#define c_itime c_attr.ca_itime +#define c_btime c_attr.ca_btime +#define c_flags c_attr.ca_flags +#define c_finderinfo c_attr.ca_finderinfo +#define c_blocks c_attr.ca_blocks +#define c_entries c_attr.ca_entries +#define c_zftimeout c_childhint + + +/* Runtime cnode flags (kept in c_flag) */ +#define C_ACCESS 0x0001 /* Access time update request */ +#define C_CHANGE 0x0002 /* Change time update request */ +#define C_UPDATE 0x0004 /* Modification time update request */ +#define C_MODIFIED 0x0008 /* CNode has been modified */ +#define C_ATIMEMOD 0x0010 /* Access time has been modified */ + +#define C_NOEXISTS 0x0020 /* CNode has been deleted, catalog entry is gone */ +#define C_DELETED 0x0040 /* CNode has been marked to be deleted */ +#define C_HARDLINK 0x0080 /* CNode is a hard link */ + +#define C_ALLOC 0x0100 /* CNode is being allocated */ +#define C_WALLOC 0x0200 /* Waiting for allocation to finish */ +#define C_TRANSIT 0x0400 /* CNode is getting recycled */ +#define C_WTRANSIT 0x0800 /* Waiting for cnode getting recycled */ + +#define C_RENAME 0x1000 /* CNode is being renamed */ +#define C_ZFWANTSYNC 0x2000 /* fsync requested and file has holes */ + + +#define ZFTIMELIMIT (5 * 60) + +/* + * Convert between cnode pointers and vnode pointers + */ +#define VTOC(vp) ((struct cnode *)(vp)->v_data) + +#define CTOV(cp,rsrc) (((rsrc) && S_ISREG((cp)->c_mode)) ? \ + (cp)->c_rsrc_vp : (cp)->c_vp) + +/* + * Convert between vnode pointers and file forks + * + * Note: no CTOF since that is ambiguous + */ + +#define FTOC(fp) ((fp)->ff_cp) + +#define VTOF(vp) ((vp) == VTOC((vp))->c_rsrc_vp ? \ + VTOC((vp))->c_rsrcfork : \ + VTOC((vp))->c_datafork) + +#define FTOV(fp) ((fp) == FTOC(fp)->c_rsrcfork ? \ + FTOC(fp)->c_rsrc_vp : \ + FTOC(fp)->c_vp) + +/* + * Test for a resource fork + */ +#define FORK_IS_RSRC(fp) ((fp) == FTOC(fp)->c_rsrcfork) + +#define VNODE_IS_RSRC(vp) ((vp) == VTOC((vp))->c_rsrc_vp) + + +/* + * CTIMES should be an inline function... + */ +#define C_TIMEMASK (C_ACCESS | C_CHANGE | C_UPDATE) + +#define ATIME_ACCURACY 60 + +#define CTIMES(cp, t1, t2) { \ + if ((cp)->c_flag & C_TIMEMASK) { \ + /* \ + * If only the access time is changing then defer \ + * updating it on-disk util later (in hfs_inactive). \ + * If it was recently updated then skip the update. \ + */ \ + if (((cp)->c_flag & (C_TIMEMASK | C_MODIFIED)) == C_ACCESS) { \ + if (((cp)->c_flag & C_ATIMEMOD) || \ + (t1)->tv_sec > ((cp)->c_atime + ATIME_ACCURACY)) { \ + (cp)->c_atime = (t1)->tv_sec; \ + (cp)->c_flag |= C_ATIMEMOD; \ + } \ + (cp)->c_flag &= ~C_ACCESS; \ + } else { \ + if ((cp)->c_flag & C_ACCESS) { \ + (cp)->c_atime = (t1)->tv_sec; \ + } \ + if ((cp)->c_flag & C_UPDATE) { \ + (cp)->c_mtime = (t2)->tv_sec; \ + (cp)->c_mtime_nsec = (t2)->tv_usec * 1000; \ + } \ + if ((cp)->c_flag & C_CHANGE) { \ + (cp)->c_ctime = time.tv_sec; \ + } \ + (cp)->c_flag |= C_MODIFIED; \ + (cp)->c_flag &= ~C_TIMEMASK; \ + } \ + } \ +} + +/* This overlays the fid structure (see mount.h). */ +struct hfsfid { + u_int16_t hfsfid_len; /* Length of structure. */ + u_int16_t hfsfid_pad; /* Force 32-bit alignment. */ + /* The following data is filesystem-dependent, up to MAXFIDSZ (16) bytes: */ + u_int32_t hfsfid_cnid; /* Catalog node ID. */ + u_int32_t hfsfid_gen; /* Generation number (create date). */ +}; + + +/* + * HFS cnode hash functions. + */ +extern void hfs_chashinit(void); +extern void hfs_chashinsert(struct cnode *cp); +extern void hfs_chashremove(struct cnode *cp); +extern struct cnode * hfs_chashget(dev_t dev, ino_t inum, int wantrsrc, + struct vnode **vpp, struct vnode **rvpp); + +#endif /* __APPLE_API_PRIVATE */ +#endif /* KERNEL */ + +#endif /* ! _HFS_CNODE_H_ */ diff --git a/bsd/hfs/hfs_dbg.h b/bsd/hfs/hfs_dbg.h index 9033f82ad..0b4942f36 100644 --- a/bsd/hfs/hfs_dbg.h +++ b/bsd/hfs/hfs_dbg.h @@ -81,16 +81,7 @@ struct componentname; */ #if HFS_DIAGNOSTIC extern int hfs_dbg_all; -extern int hfs_dbg_vfs; -extern int hfs_dbg_vop; -extern int hfs_dbg_load; -extern int hfs_dbg_io; -extern int hfs_dbg_utils; -extern int hfs_dbg_rw; -extern int hfs_dbg_lookup; -extern int hfs_dbg_tree; extern int hfs_dbg_err; -extern int hfs_dbg_test; #ifdef KERNEL #if (HFS_DEBUG_STAGE == 4) @@ -105,75 +96,6 @@ extern int hfs_dbg_test; #define DBG_ASSERT(a) assert(a) #endif /* KERNEL */ -//#define DBG_VFS if (hfs_dbg_all || hfs_dbg_vfs) PRINTIT -#define DBG_VFS(x) { \ - if(hfs_dbg_all || hfs_dbg_vfs) { \ - PRINTIT("%X: ", current_proc()->p_pid); \ - PRINTIT x; \ - PRINT_DELAY; \ - }; \ -} -#define DBG_VFS_CONT(x) { \ - if(hfs_dbg_all || hfs_dbg_vfs) { \ - PRINTIT x; \ - PRINT_DELAY; \ - }; \ -} -#define DBG_VOP(x) { \ - if(hfs_dbg_all || hfs_dbg_vop) { \ - PRINTIT("%X: ", current_proc()->p_pid); \ - PRINTIT x; \ - PRINT_DELAY; \ - }; \ -} -#define DBG_VOP_CONT(x) { \ - if(hfs_dbg_all || hfs_dbg_vop) { \ - PRINTIT x; \ - PRINT_DELAY; \ - }; \ -} -#define DBG_LOAD(x) { \ - if(hfs_dbg_all || hfs_dbg_load) { \ - PRINTIT("%X: ", current_proc()->p_pid); \ - PRINTIT x; \ - PRINT_DELAY; \ - }; \ -} -#define DBG_IO(x) { \ - if(hfs_dbg_all || hfs_dbg_io) { \ - PRINTIT("%X: ", current_proc()->p_pid); \ - PRINTIT x; \ - PRINT_DELAY; \ - }; \ -} -#define DBG_UTILS(x) { \ - if(hfs_dbg_all || hfs_dbg_utils) { \ - PRINTIT("%X: ", current_proc()->p_pid); \ - PRINTIT x; \ - PRINT_DELAY; \ - }; \ -} -#define DBG_RW(x) { \ - if(hfs_dbg_all || hfs_dbg_rw) { \ - PRINTIT("%X: ", current_proc()->p_pid); \ - PRINTIT x; \ - PRINT_DELAY; \ - }; \ -} -#define DBG_LOOKUP(x) { \ - if(hfs_dbg_all || hfs_dbg_lookup) { \ - PRINTIT("%X: ", current_proc()->p_pid); \ - PRINTIT x; \ - PRINT_DELAY; \ - }; \ -} -#define DBG_TREE(x) { \ - if(hfs_dbg_all || hfs_dbg_tree) { \ - PRINTIT("%X: ", current_proc()->p_pid); \ - PRINTIT x; \ - PRINT_DELAY; \ - }; \ -} #define DBG_ERR(x) { \ if(hfs_dbg_all || hfs_dbg_err) { \ PRINTIT("%X: ", current_proc()->p_pid); \ @@ -182,156 +104,11 @@ extern int hfs_dbg_test; PRINT_DELAY; \ }; \ } -#define DBG_TEST(x) { \ - if(hfs_dbg_all || hfs_dbg_test) { \ - PRINTIT("%X: ", current_proc()->p_pid); \ - PRINTIT x; \ - PRINT_DELAY; \ - }; \ -} -#else // HFS_DIAGNOSTIC -#define DBG_ASSERT(a) -#define DBG_VFS(x) -#define DBG_VFS_CONT(x) -#define DBG_VOP(x) -#define DBG_VOP_CONT(x) -#define DBG_LOAD(x) -#define DBG_IO(x) -#define DBG_UTILS(x) -#define DBG_RW(x) -#define DBG_LOOKUP(x) -#define DBG_TREE(x) -#define DBG_ERR(x) -#define DBG_TEST(x) -#endif // HFS_DIAGNOSTIC - - -/* Used to help print commone values in the vnode ops */ -#if HFS_DIAGNOSTIC - extern void debug_vn_status (char* introStr, struct vnode *vn); - extern void debug_vn_print (char* introStr, struct vnode *vn); - extern void debug_check_vnode(struct vnode *vp, int stage); - - #define DBG_VN_STATUS (introStr, vn) debug_vn_status (introStr, vn) - #define DBG_VN_PRINT (introStr, vn) debug_vn_print (introStr, vn) - #define DBG_FUNC_NAME(FSTR) static char *funcname = FSTR - #define DBG_PRINT_FUNC_NAME() DBG_VFS(("%s: ", funcname)); - #define DBG_VOP_PRINT_FUNCNAME() DBG_VOP(("%s: ", funcname)); - - - /* This checks to make sure the passed in node is valid and HFS */ - #define DBG_HFS_NODE_CHECK(VP) { \ - if ((VP) == NULL || VTOH((VP))->h_valid != HFS_VNODE_MAGIC) { \ - DBG_VOP_CONT(("%s: INVALID VNODE: ", funcname)); \ - DBG_VOP_PRINT_VNODE_INFO(VP); \ - DBG_VOP_CONT(("\n")); \ - return (EINVAL); \ - } \ - } - - #define DBG_VOP_PRINT_VNODE_INFO(VP) { if (VP && VTOH((VP))->h_valid == HFS_VNODE_MAGIC) { \ - DBG_VOP_CONT(("\tn: %s, p: %d, id: %d, f: %d, u: %d, v: 0x%x ",H_NAME(VTOH(VP)), \ - H_DIRID(VTOH(VP)), H_FILEID(VTOH(VP)), H_FORKTYPE(VTOH(VP)), (VP)->v_usecount, (u_int)(VP))); \ - } else { \ - DBG_VOP_CONT(("\tBAD MACNODE"));}} - - #define DBG_VOP_PRINT_CPN_INFO(CN) DBG_VOP_CONT(("name: %s",(CN)->cn_nameptr)); - -#else /* HFS_DIAGNOSTIC */ - - #define DBG_VN_PRINT(introStr,vn) - #define DBG_VN_STATUS(introStr,vn) - #define DBG_FUNC_NAME(FSTR) - #define DBG_PRINT_FUNC_NAME() - #define DBG_HFS_NODE_CHECK(VP) - #define DBG_VOP_PRINT_FUNCNAME() - #define DBG_VOP_PRINT_VNODE_INFO(VP) - #define DBG_VOP_PRINT_CPN_INFO(CN) - -#endif /* HFS_DIAGNOSTIC */ - - -#if HFS_DIAGNOSTIC -#define DBG_VOP_TEST_LOCKS 1 -#else /* HFS_DIAGNOSTIC */ -#undef DBG_VOP_TEST_LOCKS -#endif /* HFS_DIAGNOSTIC */ - - - -#if DBG_VOP_TEST_LOCKS - -typedef struct VopDbgStoreRec { - short id; - struct vnode *vp; - short inState; - short outState; - short errState; - int inValue; - int outValue; - } VopDbgStoreRec; - -void DbgVopTest (int max, int error, VopDbgStoreRec *VopDbgStore, char *funcname); -void DbgLookupTest(char *funcname, struct componentname *cnp, struct vnode *dvp, struct vnode *vp); +#else /* HFS_DIAGNOSTIC */ -#define VOPDBG_IGNORE 0 -#define VOPDBG_LOCKED 1 -#define VOPDBG_UNLOCKED -1 -#define VOPDBG_LOCKNOTNIL 2 -#define VOPDBG_SAME 3 - -#define VOPDBG_ZERO 0 -#define VOPDBG_POS 1 - -/* This sets up the test for the lock state of vnodes. The entry paramaters are: - * I = index of paramater - * VP = pointer to a vnode - * ENTRYSTATE = the inState of the lock - * EXITSTATE = the outState of the lock - * ERRORSTATE = the error state of the lock - * It initializes the structure, does some preliminary validity checks, but does nothing - * if the instate is set to be ignored. - */ - - -#define DBG_VOP_LOCKS_DECL(I) VopDbgStoreRec VopDbgStore[I];short numOfLockSlots=I -#define DBG_VOP_LOCKS_INIT(I,VP,ENTRYSTATE,EXITSTATE,ERRORSTATE,CHECKFLAG) \ - if (I >= numOfLockSlots) { \ - DEBUG_BREAK_MSG(("%s: DBG_VOP_LOCKS_INIT: Entry #%d greater than allocated slots!\n", funcname, I)); \ - }; \ - VopDbgStore[I].id = I; \ - VopDbgStore[I].vp = VP; \ - VopDbgStore[I].inState = ENTRYSTATE; \ - VopDbgStore[I].outState = EXITSTATE; \ - VopDbgStore[I].errState = ERRORSTATE; \ - VopDbgStore[I].inValue = 0; \ - VopDbgStore[I].outValue = 0; \ - if ((VopDbgStore[I].inState != VOPDBG_IGNORE)) { \ - if ((VP) == NULL) \ - PRINTIT ("%X: %s: DBG_VOP_LOCK on start: Null vnode ptr\n", current_proc()->p_pid, funcname); \ - else \ - VopDbgStore[I].inValue = lockstatus (&(VTOH(VP))->h_lock); \ - } \ - if ((VP) != NULL) \ - { \ - if (CHECKFLAG==VOPDBG_POS && (VP)->v_usecount <= 0) \ - PRINTIT("%X: %s: BAD USECOUNT OF %d !!!!\n", current_proc()->p_pid, funcname, (VP)->v_usecount); \ - else if ((VP)->v_usecount < 0) \ - PRINTIT("%X: %s: BAD USECOUNT OF %d !!!!\n", current_proc()->p_pid, funcname, (VP)->v_usecount); \ - } - - #define DBG_VOP_UPDATE_VP(I, VP) \ - VopDbgStore[I].vp = VP; - - #define DBG_VOP_LOCKS_TEST(status) DbgVopTest (numOfLockSlots, status, VopDbgStore, funcname); - #define DBG_VOP_LOOKUP_TEST(funcname, cnp, dvp, vp) DbgLookupTest (funcname, cnp, dvp, vp); +#define DBG_ASSERT(a) +#define DBG_ERR(x) -#else /* DBG_VOP_TEST_LOCKS */ +#endif /* HFS_DIAGNOSTIC */ - #define DBG_VOP_LOCKS_DECL(A) - #define DBG_VOP_LOCKS_INIT(A,B,C,D,E,F) - #define DBG_VOP_LOCKS_TEST(a) - #define DBG_VOP_LOOKUP_TEST(funcname, cnp, dvp, vp) - #define DBG_VOP_UPDATE_VP(I, VP) -#endif /* DBG_VOP_TEST_LOCKS */ diff --git a/bsd/hfs/hfs_encodinghint.c b/bsd/hfs/hfs_encodinghint.c index 776f2b361..c82f1a148 100644 --- a/bsd/hfs/hfs_encodinghint.c +++ b/bsd/hfs/hfs_encodinghint.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2001-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -35,9 +35,12 @@ #define CJK_KATAKANA (CJK_JAPAN | CJK_CHINESE_SIMP | CJK_KOREAN) -/* Remeber the las unique CJK bit */ +/* Remember the last unique CJK bit */ u_int8_t cjk_lastunique = 0; +/* CJK encoding bias */ +u_int32_t hfs_encodingbias = 0; + /* Map CJK bits to Mac encoding */ u_int8_t cjk_encoding[] = { @@ -808,7 +811,33 @@ hfs_pickencoding(const u_int16_t *src, int len) if (cjkstate) { if (powerof2(cjkstate)) { cjk_lastunique = cjkstate; - } else if (cjk_lastunique) { + return ((u_int32_t)cjk_encoding[cjkstate]); + } + if (hfs_encodingbias != 0) { + switch(hfs_encodingbias) { + case kTextEncodingMacJapanese: + if (cjkstate & CJK_JAPAN) + return (kTextEncodingMacJapanese); + break; + case kTextEncodingMacKorean: + if (cjkstate & CJK_KOREAN) + return (kTextEncodingMacKorean); + break; + case kTextEncodingMacChineseTrad: + if (cjkstate & CJK_CHINESE_TRAD) + return (kTextEncodingMacChineseTrad); + if (cjkstate & CJK_CHINESE_SIMP) + return (kTextEncodingMacChineseSimp); + break; + case kTextEncodingMacChineseSimp: + if (cjkstate & CJK_CHINESE_SIMP) + return (kTextEncodingMacChineseSimp); + if (cjkstate & CJK_CHINESE_TRAD) + return (kTextEncodingMacChineseTrad); + break; + } + } + if (cjk_lastunique) { if (cjkstate & cjk_lastunique) cjkstate = cjk_lastunique; else diff --git a/bsd/hfs/hfs_encodings.c b/bsd/hfs/hfs_encodings.c index e85de58dc..185e14503 100644 --- a/bsd/hfs/hfs_encodings.c +++ b/bsd/hfs/hfs_encodings.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -52,7 +52,7 @@ extern struct host realhost; #define MAX_HFS_UNICODE_CHARS (15*5) -static int mac_roman_to_unicode(Str31 hfs_str, UniChar *uni_str, UInt32 maxCharLen, UInt32 *usedCharLen); +int mac_roman_to_unicode(Str31 hfs_str, UniChar *uni_str, UInt32 maxCharLen, UInt32 *usedCharLen); static int unicode_to_mac_roman(UniChar *uni_str, UInt32 unicodeChars, Str31 hfs_str); @@ -272,6 +272,25 @@ mac_roman_to_utf8(Str31 hfs_str, ByteCount maxDstLen, ByteCount *actualDstLen, u } +/* + * Convert Unicode string into HFS encoding + * + * ':' chars are converted to '/' + * Assumes input represents fully decomposed Unicode + */ +int +unicode_to_hfs(ExtendedVCB *vcb, ByteCount srcLen, u_int16_t* srcStr, Str31 dstStr, int retry) +{ + int error; + unicode_to_hfs_func_t hfs_get_hfsname = VCBTOHFS(vcb)->hfs_get_hfsname; + + error = hfs_get_hfsname(srcStr, srcLen/sizeof(UniChar), dstStr); + if (error && retry) { + error = unicode_to_mac_roman(srcStr, srcLen/sizeof(UniChar), dstStr); + } + return error; +} + /* * Convert UTF-8 string into HFS encoding * @@ -279,16 +298,15 @@ mac_roman_to_utf8(Str31 hfs_str, ByteCount maxDstLen, ByteCount *actualDstLen, u * Assumes input represents fully decomposed Unicode */ int -utf8_to_hfs(ExtendedVCB *vcb, ByteCount srcLen, const unsigned char* srcStr, Str31 dstStr) +utf8_to_hfs(ExtendedVCB *vcb, ByteCount srcLen, const unsigned char* srcStr, Str31 dstStr/*, int retry*/) { int error; UniChar uniStr[MAX_HFS_UNICODE_CHARS]; size_t ucslen; - unicode_to_hfs_func_t hfs_get_hfsname = VCBTOHFS(vcb)->hfs_get_hfsname; error = utf8_decodestr(srcStr, srcLen, uniStr, &ucslen, sizeof(uniStr), ':', 0); if (error == 0) - error = hfs_get_hfsname(uniStr, ucslen/sizeof(UniChar), dstStr); + error = unicode_to_hfs(vcb, ucslen, uniStr, dstStr, 1); return error; } @@ -592,7 +610,8 @@ static UniChar gHiBitCombUnicode[128] = { * * Unicode output is fully decomposed */ -static int mac_roman_to_unicode(Str31 hfs_str, UniChar *uni_str, +int +mac_roman_to_unicode(Str31 hfs_str, UniChar *uni_str, UInt32 maxCharLen, UInt32 *unicodeChars) { const UInt8 *p; diff --git a/bsd/hfs/hfs_encodings.h b/bsd/hfs/hfs_encodings.h index 7d4e7bbc1..233af5ba7 100644 --- a/bsd/hfs/hfs_encodings.h +++ b/bsd/hfs/hfs_encodings.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -26,6 +26,19 @@ #ifndef _HFS_ENCODINGS_H_ #define _HFS_ENCODINGS_H_ +#include + +#ifdef __APPLE_API_UNSTABLE +/* + * Sysctl value for HFS Unicode encoding matching. + */ +#define HFS_ENCODINGBIAS 1 /* encoding matching CJK bias */ + +#define CTL_HFS_NAMES { \ + { 0, 0 }, \ + { "encodingbias", CTLTYPE_INT }, \ +} + /* * HFS Filename Encoding Converters Interface * @@ -46,10 +59,12 @@ typedef int (* unicode_to_hfs_func_t)(UniChar *uni_str, UInt32 unicodeChars, Str31 hfs_str); -int hfs_addconverter(int kmod_id, UInt32 encoding, hfs_to_unicode_func_t get_unicode, - unicode_to_hfs_func_t get_hfsname); +int hfs_addconverter(int kmod_id, UInt32 encoding, + hfs_to_unicode_func_t get_unicode, + unicode_to_hfs_func_t get_hfsname); int hfs_remconverter(int kmod_id, UInt32 encoding); +#endif /* __APPLE_API_UNSTABLE */ #endif /* ! _HFS_ENCODINGS_H_ */ diff --git a/bsd/hfs/hfs_endian.c b/bsd/hfs/hfs_endian.c index d01635c4e..89809b608 100644 --- a/bsd/hfs/hfs_endian.c +++ b/bsd/hfs/hfs_endian.c @@ -50,9 +50,6 @@ hfs_swap_HFSPlusForkData ( { int i; - DBG_FUNC_NAME("hfs_swap_HFSPlusForkData"); - DBG_PRINT_FUNC_NAME(); - src->logicalSize = SWAP_BE64 (src->logicalSize); src->clumpSize = SWAP_BE32 (src->clumpSize); @@ -84,8 +81,6 @@ hfs_swap_BTNode ( UInt32 i; int error = 0; - DBG_FUNC_NAME("hfs_swap_BTNode"); - DBG_PRINT_FUNC_NAME(); #ifdef ENDIAN_DEBUG if (unswap == 0) { @@ -218,9 +213,6 @@ hfs_swap_HFSPlusBTInternalNode ( UInt32 i; UInt32 j; - DBG_FUNC_NAME("hfs_swap_HFSPlusBTInternalNode"); - DBG_PRINT_FUNC_NAME(); - if (fileID == kHFSExtentsFileID) { HFSPlusExtentKey *srcKey; HFSPlusExtentDescriptor *srcRec; @@ -383,9 +375,6 @@ hfs_swap_HFSBTInternalNode ( UInt32 i; UInt32 j; - DBG_FUNC_NAME("hfs_swap_HFSBTInternalNode"); - DBG_PRINT_FUNC_NAME(); - if (fileID == kHFSExtentsFileID) { HFSExtentKey *srcKey; HFSExtentDescriptor *srcRec; diff --git a/bsd/hfs/hfs_endian.h b/bsd/hfs/hfs_endian.h index f20851d99..a1b91fdf9 100644 --- a/bsd/hfs/hfs_endian.h +++ b/bsd/hfs/hfs_endian.h @@ -22,6 +22,10 @@ #ifndef __HFS_ENDIAN_H__ #define __HFS_ENDIAN_H__ +#include + +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE /* * hfs_endian.h * @@ -75,4 +79,6 @@ int hfs_swap_BTNode (BlockDescriptor *src, int isHFSPlus, HFSCatalogNodeID file } #endif +#endif /* __APPLE_API_PRIVATE */ +#endif /* KERNEL */ #endif /* __HFS_FORMAT__ */ diff --git a/bsd/hfs/hfs_format.h b/bsd/hfs/hfs_format.h index c9840f64f..ffbef0fb9 100644 --- a/bsd/hfs/hfs_format.h +++ b/bsd/hfs/hfs_format.h @@ -22,6 +22,8 @@ #ifndef __HFS_FORMAT__ #define __HFS_FORMAT__ +#include + /* * hfs_format.c * @@ -49,6 +51,7 @@ enum { }; +#ifdef __APPLE_API_PRIVATE /* * Mac OS X has a special directory for linked and unlinked files (HFS Plus only). * This directory and its contents are never exported from the filesystem under @@ -70,6 +73,8 @@ enum { #define HFS_INODE_PREFIX "iNode" #define HFS_DELETE_PREFIX "temp" +#endif /* __APPLE_API_PRIVATE */ + /* * Indirect link files (hard links) have the following type/creator. */ @@ -363,7 +368,7 @@ struct HFSPlusCatalogThread { }; typedef struct HFSPlusCatalogThread HFSPlusCatalogThread; - +#ifdef __APPLE_API_UNSTABLE /* These are the types of records in the attribute B-tree. The values were chosen so that they wouldn't conflict with the catalog record types. @@ -436,7 +441,7 @@ enum { kHFSPlusExtentMinNodeSize = 512, kHFSPlusAttrMinNodeSize = 4096 }; - +#endif /* __APPLE_API_UNSTABLE */ /* HFS and HFS Plus volume attribute bits */ enum { diff --git a/bsd/hfs/hfs_link.c b/bsd/hfs/hfs_link.c index f31f86495..6a78cd752 100644 --- a/bsd/hfs/hfs_link.c +++ b/bsd/hfs/hfs_link.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -20,11 +20,11 @@ * @APPLE_LICENSE_HEADER_END@ */ -#if HFS_HARDLINKS #include #include #include +#include #include #include #include @@ -32,157 +32,155 @@ #include #include "hfs.h" -#include "hfscommon/headers/FileMgrInternal.h" +#include "hfs_catalog.h" +#include "hfs_format.h" +#include "hfs_endian.h" /* * Create a new indirect link * - * An indirect link is a reference to a data node. The only useable fields in the - * link are the parentID, name and text encoding. All other catalog fields - * are ignored. + * An indirect link is a reference to a data node. The only useable + * fields in the link are the link number, parentID, name and text + * encoding. All other catalog fields are ignored. */ static int -createindirectlink(struct hfsnode *dnhp, UInt32 linkPID, char *linkName) +createindirectlink(struct hfsmount *hfsmp, u_int32_t linknum, + u_int32_t linkparid, char *linkName, cnid_t *linkcnid) { - struct hfsCatalogInfo catInfo; - struct FInfo *fip; - ExtendedVCB *vcb; + struct FndrFileInfo *fip; + struct cat_desc desc; + struct cat_attr attr; int result; - vcb = HTOVCB(dnhp); + /* Setup the descriptor */ + bzero(&desc, sizeof(desc)); + desc.cd_nameptr = linkName; + desc.cd_namelen = strlen(linkName); + desc.cd_parentcnid = linkparid; - /* Create the indirect link directly in the catalog */ - result = hfsCreate(vcb, linkPID, linkName, IFREG, 0); - if (result) return (result); - - /* - * XXX SER Here is a good example where hfsCreate should pass in a catinfo and return - * things like the hint and file ID there should be no reason to call lookup here - */ - catInfo.hint = 0; - INIT_CATALOGDATA(&catInfo.nodeData, kCatNameNoCopyName); - - result = hfs_getcatalog(vcb, linkPID, linkName, -1, &catInfo); - if (result) goto errExit; - - fip = (struct FInfo *)&catInfo.nodeData.cnd_finderInfo; - fip->fdType = kHardLinkFileType; /* 'hlnk' */ - fip->fdCreator = kHFSPlusCreator; /* 'hfs+' */ - fip->fdFlags |= kHasBeenInited; - - /* links are matched to data nodes by nodeID and to volumes by create date */ - catInfo.nodeData.cnd_iNodeNum = dnhp->h_meta->h_indnodeno; - catInfo.nodeData.cnd_createDate = vcb->vcbCrDate; - - result = UpdateCatalogNode(vcb, linkPID, linkName, catInfo.hint, &catInfo.nodeData); - if (result) goto errExit; + /* Setup the default attributes */ + bzero(&attr, sizeof(attr)); + + /* links are matched to data nodes by link ID and to volumes by create date */ + attr.ca_rdev = linknum; /* note: cat backend overloads ca_rdev to be the linknum when nlink = 0 */ + attr.ca_itime = HFSTOVCB(hfsmp)->vcbCrDate; + attr.ca_mode = S_IFREG; - CLEAN_CATALOGDATA(&catInfo.nodeData); - return (0); + fip = (struct FndrFileInfo *)&attr.ca_finderinfo; + fip->fdType = SWAP_BE32 (kHardLinkFileType); /* 'hlnk' */ + fip->fdCreator = SWAP_BE32 (kHFSPlusCreator); /* 'hfs+' */ + fip->fdFlags = SWAP_BE16 (kHasBeenInited); -errExit: - CLEAN_CATALOGDATA(&catInfo.nodeData); + /* Create the indirect link directly in the catalog */ + result = cat_create(hfsmp, &desc, &attr, NULL); - /* get rid of link node */ - (void) hfsDelete(vcb, linkPID, linkName, TRUE, 0); + if (linkcnid != NULL) + *linkcnid = attr.ca_fileid; return (result); } /* - * 2 locks are needed (dvp and hp) + * 2 locks are needed (dvp and vp) * also need catalog lock * * caller's responsibility: * componentname cleanup - * unlocking dvp and hp + * unlocking dvp and vp */ static int -hfs_makelink(hp, dvp, cnp) - struct hfsnode *hp; - struct vnode *dvp; - register struct componentname *cnp; +hfs_makelink(struct hfsmount *hfsmp, struct cnode *cp, struct cnode *dcp, + struct componentname *cnp) { struct proc *p = cnp->cn_proc; - struct hfsnode *dhp = VTOH(dvp); - u_int32_t ldirID; /* directory ID of linked nodes directory */ - ExtendedVCB *vcb = VTOVCB(dvp); - u_int32_t hint; u_int32_t indnodeno = 0; char inodename[32]; + struct cat_desc to_desc; + int newlink = 0; int retval; - ldirID = VTOHFS(dvp)->hfs_private_metadata_dir; /* We don't allow link nodes in our Private Meta Data folder! */ - if ( H_FILEID(dhp) == ldirID) + if (dcp->c_fileid == hfsmp->hfs_privdir_desc.cd_cnid) return (EPERM); - if (vcb->freeBlocks == 0) + if (hfs_freeblks(hfsmp, 0) == 0) return (ENOSPC); - /* lock catalog b-tree */ - retval = hfs_metafilelocking(VTOHFS(dvp), kHFSCatalogFileID, LK_EXCLUSIVE, p); - if (retval != E_NONE) + /* Lock catalog b-tree */ + retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p); + if (retval) return retval; /* * If this is a new hardlink then we need to create the data * node (inode) and replace the original file with a link node. */ - if (hp->h_meta->h_nlink == 1) { + if (cp->c_nlink == 2 && (cp->c_flag & C_HARDLINK) == 0) { + newlink = 1; + bzero(&to_desc, sizeof(to_desc)); + to_desc.cd_parentcnid = hfsmp->hfs_privdir_desc.cd_cnid; + to_desc.cd_cnid = cp->c_fileid; do { /* get a unique indirect node number */ indnodeno = ((random() & 0x3fffffff) + 100); MAKE_INODE_NAME(inodename, indnodeno); /* move source file to data node directory */ - hint = 0; - retval = hfsMoveRename(vcb, H_DIRID(hp), H_NAME(hp), ldirID, inodename, &hint); - } while (retval == cmExists); + to_desc.cd_nameptr = inodename; + to_desc.cd_namelen = strlen(inodename); + + retval = cat_rename(hfsmp, &cp->c_desc, &hfsmp->hfs_privdir_desc, + &to_desc, NULL); - if (retval) goto out; + } while (retval == EEXIST); + if (retval) + goto out; - hp->h_meta->h_indnodeno = indnodeno; - - /* replace source file with link node */ - retval = createindirectlink(hp, H_DIRID(hp), H_NAME(hp)); + /* Replace source file with link node */ + retval = createindirectlink(hfsmp, indnodeno, cp->c_parentcnid, + cp->c_desc.cd_nameptr, &cp->c_desc.cd_cnid); if (retval) { /* put it source file back */ - hint = 0; - (void) hfsMoveRename(vcb, ldirID, inodename, H_DIRID(hp), H_NAME(hp), &hint); + (void) cat_rename(hfsmp, &to_desc, &dcp->c_desc, &cp->c_desc, NULL); goto out; } - } + cp->c_rdev = indnodeno; + } else { + indnodeno = cp->c_rdev; + } /* * Create a catalog entry for the new link (parentID + name). */ - retval = createindirectlink(hp, H_FILEID(dhp), cnp->cn_nameptr); - if (retval && hp->h_meta->h_nlink == 1) { - /* get rid of new link */ - (void) hfsDelete(vcb, H_DIRID(hp), H_NAME(hp), TRUE, 0); - - /* put it source file back */ - hint = 0; - (void) hfsMoveRename(vcb, ldirID, inodename, H_DIRID(hp), H_NAME(hp), &hint); + retval = createindirectlink(hfsmp, indnodeno, dcp->c_fileid, cnp->cn_nameptr, NULL); + if (retval && newlink) { + /* Get rid of new link */ + (void) cat_delete(hfsmp, &cp->c_desc, &cp->c_attr); + + /* Put the source file back */ + (void) cat_rename(hfsmp, &to_desc, &dcp->c_desc, &cp->c_desc, NULL); goto out; } /* - * Finally, if this is a new hardlink then we need to mark the hfs node + * Finally, if this is a new hardlink then: + * - update HFS Private Data dir + * - mark the cnode as a hard link */ - if (hp->h_meta->h_nlink == 1) { - hp->h_meta->h_nlink++; - hp->h_nodeflags |= IN_CHANGE; - hp->h_meta->h_metaflags |= IN_DATANODE; + if (newlink) { + hfsmp->hfs_privdir_attr.ca_entries++; + (void)cat_update(hfsmp, &hfsmp->hfs_privdir_desc, + &hfsmp->hfs_privdir_attr, NULL, NULL); + hfs_volupdate(hfsmp, VOL_MKFILE, 0); + cp->c_flag |= (C_CHANGE | C_HARDLINK); } out: - /* unlock catalog b-tree */ - (void) hfs_metafilelocking(VTOHFS(dvp), kHFSCatalogFileID, LK_RELEASE, p); + /* Unlock catalog b-tree */ + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); return (retval); } @@ -201,17 +199,18 @@ out: */ int hfs_link(ap) -struct vop_link_args /* { - struct vnode *a_vp; - struct vnode *a_tdvp; - struct componentname *a_cnp; -} */ *ap; + struct vop_link_args /* { + struct vnode *a_vp; + struct vnode *a_tdvp; + struct componentname *a_cnp; + } */ *ap; { struct vnode *vp = ap->a_vp; struct vnode *tdvp = ap->a_tdvp; struct componentname *cnp = ap->a_cnp; struct proc *p = cnp->cn_proc; - struct hfsnode *hp; + struct cnode *cp; + struct cnode *tdcp; struct timeval tv; int error; @@ -234,13 +233,15 @@ struct vop_link_args /* { VOP_ABORTOP(tdvp, cnp); goto out2; } - hp = VTOH(vp); - if (hp->h_meta->h_nlink >= HFS_LINK_MAX) { + cp = VTOC(vp); + tdcp = VTOC(tdvp); + + if (cp->c_nlink >= HFS_LINK_MAX) { VOP_ABORTOP(tdvp, cnp); error = EMLINK; goto out1; } - if (hp->h_meta->h_pflags & (IMMUTABLE | APPEND)) { + if (cp->c_flags & (IMMUTABLE | APPEND)) { VOP_ABORTOP(tdvp, cnp); error = EPERM; goto out1; @@ -251,15 +252,24 @@ struct vop_link_args /* { goto out1; } - hp->h_meta->h_nlink++; - hp->h_nodeflags |= IN_CHANGE; + cp->c_nlink++; + cp->c_flag |= C_CHANGE; tv = time; error = VOP_UPDATE(vp, &tv, &tv, 1); if (!error) - error = hfs_makelink(hp, tdvp, cnp); + error = hfs_makelink(VTOHFS(vp), cp, tdcp, cnp); if (error) { - hp->h_meta->h_nlink--; - hp->h_nodeflags |= IN_CHANGE; + cp->c_nlink--; + cp->c_flag |= C_CHANGE; + } else { + /* Update the target directory and volume stats */ + tdcp->c_nlink++; + tdcp->c_entries++; + tdcp->c_flag |= C_CHANGE | C_UPDATE; + tv = time; + (void) VOP_UPDATE(tdvp, &tv, &tv, 0); + hfs_volupdate(VTOHFS(vp), VOL_MKFILE, + (tdcp->c_cnid == kHFSRootFolderID)); } FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI); out1: @@ -269,5 +279,3 @@ out2: vput(tdvp); return (error); } - -#endif diff --git a/bsd/hfs/hfs_lockf.c b/bsd/hfs/hfs_lockf.c index 2f4237734..63c1c0cb4 100644 --- a/bsd/hfs/hfs_lockf.c +++ b/bsd/hfs/hfs_lockf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1999,2001-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -20,7 +20,7 @@ * @APPLE_LICENSE_HEADER_END@ */ -/* (c) 1997-1998 Apple Computer, Inc. All Rights Reserved */ +/* (c) 1997-1998,2001 Apple Computer, Inc. All Rights Reserved */ /* * Copyright (c) 1982, 1986, 1989, 1993 * The Regents of the University of California. All rights reserved. @@ -69,8 +69,8 @@ #include #include +#include "hfs_cnode.h" #include "hfs_lockf.h" -#include "hfs.h" /* * This variable controls the maximum number of processes that will @@ -97,7 +97,7 @@ hfs_setlock(lock) register struct hfslockf *lock; { register struct hfslockf *block; - struct hfsnode *hp = lock->lf_hfsnode; + struct filefork *fork = lock->lf_fork; struct hfslockf **prev, *overlap, *ltmp; static char lockstr[] = "hfslockf"; int ovcase, priority, needtolink, error; @@ -205,8 +205,8 @@ hfs_setlock(lock) * Skip over locks owned by other processes. * Handle any locks that overlap and are owned by ourselves. */ - prev = &hp->h_lockf; - block = hp->h_lockf; + prev = &fork->ff_lockf; + block = fork->ff_lockf; needtolink = 1; for (;;) { if ((ovcase = hfs_findoverlap(block, lock, SELF, &prev, &overlap))) @@ -324,7 +324,7 @@ hfs_setlock(lock) } /* - * Remove a byte-range lock on an hfsnode. + * Remove a file fork's byte-range lock. * * Generally, find the lock (or an overlap to that lock) * and remove it (or shrink it), then wakeup anyone we can. @@ -333,8 +333,8 @@ int hfs_clearlock(unlock) register struct hfslockf *unlock; { - struct hfsnode *hp = unlock->lf_hfsnode; - register struct hfslockf *lf = hp->h_lockf; + struct filefork *fork = unlock->lf_fork; + register struct hfslockf *lf = fork->ff_lockf; struct hfslockf *overlap, **prev; int ovcase; @@ -346,7 +346,7 @@ hfs_clearlock(unlock) if (lockf_debug & 1) hfs_lprint("hfs_clearlock", unlock); #endif /* LOCKF_DEBUG */ - prev = &hp->h_lockf; + prev = &fork->ff_lockf; while ((ovcase = hfs_findoverlap(lf, unlock, SELF, &prev, &overlap))) { /* * Wakeup the list of locks to be retried. @@ -429,17 +429,17 @@ hfs_getlock(lock, fl) } /* - * Walk the list of locks for an hfsnode and + * Walk a file fork's list of locks and * return the first blocking lock. */ struct hfslockf * hfs_getblock(lock) register struct hfslockf *lock; { - struct hfslockf **prev, *overlap, *lf = lock->lf_hfsnode->h_lockf; + struct hfslockf **prev, *overlap, *lf = lock->lf_fork->ff_lockf; int ovcase; - prev = &lock->lf_hfsnode->h_lockf; + prev = &lock->lf_fork->ff_lockf; while ((ovcase = hfs_findoverlap(lf, lock, OTHERS, &prev, &overlap))) { /* * We've found an overlap, see if it blocks us @@ -456,7 +456,7 @@ hfs_getblock(lock) } /* - * Walk the list of locks for an hfsnode to + * Walk a file fork's list of locks to * find an overlapping lock (if any). * * NOTE: this returns only the FIRST overlapping lock. There @@ -651,9 +651,9 @@ hfs_lprint(tag, lock) else printf("id 0x%x", lock->lf_id); printf(" in ino %d on dev <%d, %d>, %s, start %d, end %d", - lock->lf_hfsnode->i_number, - major(lock->lf_hfsnode->h_dev), - minor(lock->lf_hfsnode->h_dev), + FTOC(lock->lf_fork)->c_fileid, + major(FTOC(lock->lf_fork)->c_dev), + minor(FTOC(lock->lf_fork)->c_dev), lock->lf_type == F_RDLCK ? "shared" : lock->lf_type == F_WRLCK ? "exclusive" : lock->lf_type == F_UNLCK ? "unlock" : @@ -671,10 +671,10 @@ hfs_lprintlist(tag, lock) register struct hfslockf *lf, *blk; printf("%s: Lock list for ino %d on dev <%d, %d>:\n", - tag, lock->lf_hfsnode->i_number, - major(lock->lf_hfsnode->h_dev), - minor(lock->lf_hfsnode->h_dev)); - for (lf = lock->lf_hfsnode->h_lockf; lf; lf = lf->lf_next) { + tag, FTOC(lock->lf_fork)->i_number, + major(FTOC(lock->lf_fork)->c_dev), + minor(FTOC(lock->lf_fork)->c_dev)); + for (lf = lock->lf_fork->ff_lockf; lf; lf = lf->lf_next) { printf("\tlock 0x%lx for ", lf); if (lf->lf_flags & F_POSIX) printf("proc %d", ((struct proc *)(lf->lf_id))->p_pid); diff --git a/bsd/hfs/hfs_lockf.h b/bsd/hfs/hfs_lockf.h index b3ad07eac..0ae8db758 100644 --- a/bsd/hfs/hfs_lockf.h +++ b/bsd/hfs/hfs_lockf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1999,2001-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -20,7 +20,7 @@ * @APPLE_LICENSE_HEADER_END@ */ -/* (c) 1997-1998 Apple Computer, Inc. All Rights Reserved */ +/* (c) 1997-1998,2001 Apple Computer, Inc. All Rights Reserved */ /* * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. @@ -61,10 +61,17 @@ * derived from @(#)lockf.h 8.2 (Berkeley) 10/26/94 */ +#ifndef __HFS_LOCKF__ +#define __HFS_LOCKF__ + +#include + +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE /* * The hfslockf structure is a kernel structure which contains the information * associated with a byte range lock. The hfslockf structures are linked into - * the inode structure. Locks are sorted by the starting byte of the lock for + * a cnode's file fork. Locks are sorted by the starting byte of the lock for * efficiency. */ TAILQ_HEAD(locklist, hfslockf); @@ -75,8 +82,8 @@ struct hfslockf { off_t lf_start; /* Byte # of the start of the lock */ off_t lf_end; /* Byte # of the end of the lock (-1=EOF) */ caddr_t lf_id; /* Id of the resource holding the lock */ - struct hfsnode *lf_hfsnode; /* Back pointer to the inode */ - struct hfslockf *lf_next; /* Pointer to the next lock on this inode */ + struct filefork *lf_fork; /* Back pointer to the file fork */ + struct hfslockf *lf_next; /* Pointer to the next lock on this fork */ struct locklist lf_blkhd; /* List of requests blocked on this lock */ TAILQ_ENTRY(hfslockf) lf_block;/* A request waiting for a lock */ }; @@ -104,4 +111,7 @@ __BEGIN_DECLS void hfs_lprint __P((char *, struct hfslockf *)); void hfs_lprintlist __P((char *, struct hfslockf *)); __END_DECLS -#endif +#endif /* LOCKF_DEBUG */ +#endif /* __APPLE_API_PRIVATE */ +#endif /* KERNEL */ +#endif /* __HFS_LOCKF__ */ diff --git a/bsd/hfs/hfs_lookup.c b/bsd/hfs/hfs_lookup.c index 821bd1b66..824f615dc 100644 --- a/bsd/hfs/hfs_lookup.c +++ b/bsd/hfs/hfs_lookup.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -64,58 +64,34 @@ * * * hfs_lookup.c -- code to handle directory traversal on HFS/HFS+ volume - * - * MODIFICATION HISTORY: - * 21-May-1999 Don Brady Add support for HFS rooting. - * 25-Feb-1999 Clark Warner Fixed the error case of VFS_VGGET when - * processing DotDot (..) to relock parent - * 23-Feb-1999 Pat Dirks Finish cleanup around Don's last fix in "." and ".." handling. - * 11-Nov-1998 Don Brady Take out VFS_VGET that got added as part of previous fix. - * 14-Oct-1998 Don Brady Fix locking policy volation in hfs_lookup for ".." case - * (radar #2279902). - * 4-Jun-1998 Pat Dirks Split off from hfs_vnodeops.c */ +#define LEGACY_FORK_NAMES 0 #include -#include #include #include #include #include +#include #include #include -#include "hfs.h" -#include "hfs_dbg.h" -#include "hfscommon/headers/FileMgrInternal.h" +#include "hfs.h" +#include "hfs_catalog.h" +#include "hfs_cnode.h" -u_int16_t GetForkFromName(struct componentname *cnp); -int hfs_vget_sibling(struct vnode *vdp, u_int16_t forkType, struct vnode **vpp); -int hfs_vget_catinfo(struct vnode *parent_vp, struct hfsCatalogInfo *catInfo, u_int32_t forkType, struct vnode **target_vpp); -/* - * XXX SER fork strings. - * Put these someplace better - */ -#define gHFSForkIdentStr "/" -#define gDataForkNameStr "data" -#define gRsrcForkNameStr "rsrc" +static int forkcomponent(struct componentname *cnp, int *rsrcfork); +#define _PATH_DATAFORKSPEC "/..namedfork/data" -#if DBG_VOP_TEST_LOCKS -extern void DbgVopTest(int maxSlots, int retval, VopDbgStoreRec *VopDbgStore, char *funcname); +#ifdef LEGACY_FORK_NAMES +#define LEGACY_RSRCFORKSPEC "/rsrc" #endif -/***************************************************************************** -* -* Operations on vnodes -* -*****************************************************************************/ - - /* * FROM FREEBSD 3.1 - * Convert a component of a pathname into a pointer to a locked hfsnode. + * Convert a component of a pathname into a pointer to a locked cnode. * This is a very central and rather complicated routine. * If the file system is not maintained in a strict tree hierarchy, * this can result in a deadlock situation (see comments in code below). @@ -139,7 +115,7 @@ extern void DbgVopTest(int maxSlots, int retval, VopDbgStoreRec *VopDbgStore, ch * routine wants to access the parent of the target, locked or unlocked. * * Keeping the parent locked as long as possible protects from other processes - * looking up the same item, so it has to be locked until the hfsnode is totally finished + * looking up the same item, so it has to be locked until the cnode is totally finished * * This routine is actually used as VOP_CACHEDLOOKUP method, and the * filesystem employs the generic hfs_cache_lookup() as VOP_LOOKUP @@ -166,7 +142,7 @@ extern void DbgVopTest(int maxSlots, int retval, VopDbgStoreRec *VopDbgStore, ch * found: * if at end of path and deleting, return information to allow delete * if at end of path and rewriting (RENAME and LOCKPARENT), lock target - * inode and return info to allow rewrite + * cnode and return info to allow rewrite * if not at end, add name to cache; if at end and neither creating * nor deleting, add name to cache */ @@ -174,18 +150,20 @@ extern void DbgVopTest(int maxSlots, int retval, VopDbgStoreRec *VopDbgStore, ch /* * Lookup *nm in directory *pvp, return it in *a_vpp. * **a_vpp is held on exit. - * We create a hfsnode for the file, but we do NOT open the file here. + * We create a cnode for the file, but we do NOT open the file here. #% lookup dvp L ? ? #% lookup vpp - L - IN struct vnode *dvp - Parent node of file; - INOUT struct vnode **vpp - node of target file, its a new node if the target vnode did not exist; + INOUT struct vnode **vpp - node of target file, its a new node if + the target vnode did not exist; IN struct componentname *cnp - Name of file; * When should we lock parent_hp in here ?? */ +__private_extern__ int hfs_lookup(ap) struct vop_cachedlookup_args /* { @@ -194,397 +172,288 @@ hfs_lookup(ap) struct componentname *a_cnp; } */ *ap; { - struct vnode *parent_vp; - struct vnode *target_vp; - struct vnode *tparent_vp; - struct hfsnode *parent_hp; /* parent */ - struct componentname *cnp; - struct ucred *cred; - struct proc *p; - struct hfsCatalogInfo catInfo; - u_int32_t parent_id; - u_int32_t nodeID; - u_int16_t targetLen; - u_int16_t forkType; - int flags; - int lockparent; /* !0 => lockparent flag is set */ - int wantparent; /* !0 => wantparent or lockparent flag */ - int nameiop; - int retval; - u_char isDot, isDotDot, found; - DBG_FUNC_NAME("lookup"); - DBG_VOP_LOCKS_DECL(2); - DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_POS); - DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_POS); - DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("\n")); - DBG_HFS_NODE_CHECK(ap->a_dvp); - - - /* - * Do initial setup - */ - INIT_CATALOGDATA(&catInfo.nodeData, 0); - parent_vp = ap->a_dvp; - cnp = ap->a_cnp; - parent_hp = VTOH(parent_vp); /* parent */ - target_vp = NULL; - targetLen = cnp->cn_namelen; - nameiop = cnp->cn_nameiop; - cred = cnp->cn_cred; - p = cnp->cn_proc; - lockparent = cnp->cn_flags & LOCKPARENT; - wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT); - flags = cnp->cn_flags; - parent_id = H_FILEID(parent_hp); - nodeID = kUnknownID; - found = FALSE; - isDot = FALSE; - isDotDot = FALSE; - retval = E_NONE; - forkType = kUndefinedFork; - - - /* - * We now have a segment name to search for, and a directory to search. - * - */ + struct vnode *dvp; /* vnode for directory being searched */ + struct cnode *dcp; /* cnode for directory being searched */ + struct vnode *tvp; /* target vnode */ + struct hfsmount *hfsmp; + struct componentname *cnp; + struct ucred *cred; + struct proc *p; + int wantrsrc = 0; + int forknamelen = 0; + int flags; + int wantparent; + int nameiop; + int retval = 0; + int isDot; + struct cat_desc desc = {0}; + struct cat_desc cndesc; + struct cat_attr attr; + struct cat_fork fork; + struct vnode **vpp; + + vpp = ap->a_vpp; + cnp = ap->a_cnp; + dvp = ap->a_dvp; + dcp = VTOC(dvp); + hfsmp = VTOHFS(dvp); + *vpp = NULL; + isDot = FALSE; + tvp = NULL; + nameiop = cnp->cn_nameiop; + cred = cnp->cn_cred; + p = cnp->cn_proc; + flags = cnp->cn_flags; + wantparent = flags & (LOCKPARENT|WANTPARENT); /* * First check to see if it is a . or .., else look it up. */ - - if (flags & ISDOTDOT) { /* Wanting the parent */ - isDotDot = TRUE; - found = TRUE; /* .. is always defined */ - nodeID = H_DIRID(parent_hp); - } /* Wanting ourselves */ - else if ((cnp->cn_nameptr[0] == '.') && (targetLen == 1)) { + if (flags & ISDOTDOT) { /* Wanting the parent */ + goto found; /* .. is always defined */ + } else if ((cnp->cn_nameptr[0] == '.') && (cnp->cn_namelen == 1)) { isDot = TRUE; - found = TRUE; /* We always know who we are */ - } - else { /* Wanting something else */ - catInfo.hint = kNoHint; - - /* lock catalog b-tree */ - retval = hfs_metafilelocking(VTOHFS(parent_vp), kHFSCatalogFileID, LK_SHARED, p); - if (retval) - goto Err_Exit; - - retval = hfs_getcatalog (VTOVCB(parent_vp), parent_id, cnp->cn_nameptr, targetLen, &catInfo); - - /* unlock catalog b-tree */ - (void) hfs_metafilelocking(VTOHFS(parent_vp), kHFSCatalogFileID, LK_RELEASE, p); - - if (retval == E_NONE) - found = TRUE; - }; - + goto found; /* We always know who we are */ + } else { + /* Check fork suffix to see if we want the resource fork */ + forknamelen = forkcomponent(cnp, &wantrsrc); - /* - * At this point we know IF we have a valid dir/name. - */ + /* No need to go to catalog if there are no children */ + if (dcp->c_entries == 0) + goto notfound; + bzero(&cndesc, sizeof(cndesc)); + cndesc.cd_nameptr = cnp->cn_nameptr; + cndesc.cd_namelen = cnp->cn_namelen; + cndesc.cd_parentcnid = dcp->c_cnid; + cndesc.cd_hint = dcp->c_childhint; - retval = E_NONE; - if (! found) { - /* - * This is a non-existing entry - * - * If creating, and at end of pathname and current - * directory has not been removed, then can consider - * allowing file to be created. - */ - if ((nameiop == CREATE || nameiop == RENAME || - (nameiop == DELETE && - (ap->a_cnp->cn_flags & DOWHITEOUT) && - (ap->a_cnp->cn_flags & ISWHITEOUT))) && - (flags & ISLASTCN)) { - /* - * Access for write is interpreted as allowing - * creation of files in the directory. - */ - retval = VOP_ACCESS(parent_vp, VWRITE, cred, cnp->cn_proc); + /* Lock catalog b-tree */ + retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_SHARED, p); if (retval) - return (retval); + goto exit; + retval = cat_lookup(hfsmp, &cndesc, wantrsrc, &desc, &attr, &fork); + + if (retval == 0 && S_ISREG(attr.ca_mode) && attr.ca_blocks < fork.cf_blocks) + panic("hfs_lookup: bad ca_blocks (too small)"); - cnp->cn_flags |= SAVENAME; - if (!lockparent) - VOP_UNLOCK(parent_vp, 0, p); - retval = EJUSTRETURN; - goto Err_Exit; + /* Unlock catalog b-tree */ + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); + if (retval == 0) { + dcp->c_childhint = desc.cd_hint; + goto found; + } +notfound: + /* + * This is a non-existing entry + * + * If creating, and at end of pathname and current + * directory has not been removed, then can consider + * allowing file to be created. + */ + if ((nameiop == CREATE || nameiop == RENAME || + (nameiop == DELETE && + (ap->a_cnp->cn_flags & DOWHITEOUT) && + (ap->a_cnp->cn_flags & ISWHITEOUT))) && + (flags & ISLASTCN)) { + /* + * Access for write is interpreted as allowing + * creation of files in the directory. + */ + retval = VOP_ACCESS(dvp, VWRITE, cred, cnp->cn_proc); + if (retval) + goto exit; + + cnp->cn_flags |= SAVENAME; + if (!(flags & LOCKPARENT)) + VOP_UNLOCK(dvp, 0, p); + retval = EJUSTRETURN; + goto exit; } /* * Insert name into cache (as non-existent) if appropriate. + * + * Disable negative caching since HFS is case-insensitive. */ - - /* - * XXX SER - Here we would store the name in cache as non-existant if not trying to create it, but, - * the name cache IS case-sensitive, thus maybe showing a negative hit, when the name - * is only different by case. So hfs does not support negative caching. Something to look at. - * (See radar 2293594 for a failed example) +#if 0 if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE) - cache_enter(parent_vp, *vpp, cnp); - */ - + cache_enter(dvp, *vpp, cnp); +#endif retval = ENOENT; + goto exit; } - else { - /* - * We have found an entry - * - * Here we have to decide what type of vnode to create. - * There are 3 type of objects that are given: - * 1. '.': return the same dp - * 2. '..' return the parent of dp, always a VDIR - * 3. catinfo rec: return depending on type: - * A. VDIR, nodeType is kCatalogFolderNode - * B. VLINK nodeType is kCatalogFileNode, the mode is IFLNK (esp. if it is a link to a directory e.g. bar/link/foo) - * C. VREG, nodeType is kCatalogFileNode, forkType at this point is unknown - * To determine the forkType, we can use this algorithm (\0 in the strings mean the NULL character): - * a. forkType is kDataType iff ISLASTCN is set (as in the case of the default fork e.g. data/foo). - * b. forkType is kDataType iff ISLASTCN is not set and the namePtr is followed by "/?AppleHFSFork/data\0" - * c. forkType is kRsrcType iff ISLASTCN is not set and the namePtr is followed by "/?AppleHFSFork/rsrc\0" - * If the latter two are correct, then we 'consume' the remaining of the name buffer - * and set the cnp as appropriate. - * Anything else returns an retval - */ - +found: + /* + * Process any fork specifiers + */ + if (forknamelen && S_ISREG(attr.ca_mode)) { + /* fork names are only for lookups */ + if ((nameiop != LOOKUP) && (nameiop != CREATE)) { + retval = EPERM; + goto exit; + } + cnp->cn_consume = forknamelen; + flags |= ISLASTCN; + } else { + wantrsrc = 0; + forknamelen = 0; + } + + /* + * If deleting, and at end of pathname, return + * parameters which can be used to remove file. + */ + if (nameiop == DELETE && (flags & ISLASTCN)) { /* - * If deleting, and at end of pathname, return - * parameters which can be used to remove file. - * If the wantparent flag isn't set, we return only - * the directory (in ndp->ndvp), otherwise we go - * on and lock the hfsnode, being careful with ".". - * - * Forks cannot be deleted so scan-ahead is illegal, so just return the default fork - */ - if (nameiop == DELETE && (flags & ISLASTCN)) { - /* - * Write access to directory required to delete files. - */ - retval = VOP_ACCESS(parent_vp, VWRITE, cred, cnp->cn_proc); + * Write access to directory required to delete files. + */ + if ((retval = VOP_ACCESS(dvp, VWRITE, cred, cnp->cn_proc))) + goto exit; + + if (isDot) { /* Want to return ourselves */ + VREF(dvp); + *vpp = dvp; + goto exit; + } else if (flags & ISDOTDOT) { + retval = hfs_getcnode(hfsmp, dcp->c_parentcnid, + NULL, 0, NULL, NULL, &tvp); if (retval) - goto Err_Exit; - - if (isDot) { /* Want to return ourselves */ - VREF(parent_vp); - target_vp = parent_vp; - goto Err_Exit; - } - else if (isDotDot) { - retval = VFS_VGET(parent_vp->v_mount, &nodeID, &target_vp); - if (retval) - goto Err_Exit; - } - else { - retval = hfs_vget_catinfo(parent_vp, &catInfo, kDefault, &target_vp); - if (retval) - goto Err_Exit; - CLEAN_CATALOGDATA(&catInfo.nodeData); - }; - + goto exit; + } else { + retval = hfs_getcnode(hfsmp, attr.ca_fileid, + &desc, wantrsrc, &attr, &fork, &tvp); + if (retval) + goto exit; + } - /* - * If directory is "sticky", then user must own - * the directory, or the file in it, else she - * may not delete it (unless she's root). This - * implements append-only directories. - */ - if ((parent_hp->h_meta->h_mode & ISVTX) && - (cred->cr_uid != 0) && - (cred->cr_uid != parent_hp->h_meta->h_uid) && - (target_vp->v_type != VLNK) && - (hfs_owner_rights(target_vp, cred, p, false))) { - vput(target_vp); - retval = EPERM; - goto Err_Exit; - } -#if HFS_HARDLINKS - /* - * If this is a link node then we need to save the name - * (of the link) so we can delete it from the catalog b-tree. - * In this case, hfs_remove will then free the component name. - */ - if (target_vp && (VTOH(target_vp)->h_meta->h_metaflags & IN_DATANODE)) - cnp->cn_flags |= SAVENAME; -#endif - - if (!lockparent) - VOP_UNLOCK(parent_vp, 0, p); - goto Err_Exit; - }; - /* - * If rewriting 'RENAME', return the hfsnode and the - * information required to rewrite the present directory + * If directory is "sticky", then user must own + * the directory, or the file in it, else she + * may not delete it (unless she's root). This + * implements append-only directories. */ - if (nameiop == RENAME && wantparent && (cnp->cn_flags & ISLASTCN)) { - - if ((retval = VOP_ACCESS(parent_vp, VWRITE, cred, cnp->cn_proc)) != 0) - goto Err_Exit; + if ((dcp->c_mode & S_ISTXT) && + (cred->cr_uid != 0) && + (cred->cr_uid != dcp->c_uid) && + (tvp->v_type != VLNK) && + (hfs_owner_rights(hfsmp, VTOC(tvp)->c_uid, cred, p, false))) { + vput(tvp); + retval = EPERM; + goto exit; + } - /* - * Careful about locking second inode. - * This can only occur if the target is ".". like 'mv foo/bar foo/.' - */ - if (isDot) { - retval = EISDIR; - goto Err_Exit; - } - else if (isDotDot) { - retval = VFS_VGET(parent_vp->v_mount, &nodeID, &target_vp); - if (retval) - goto Err_Exit; - } - else { - - retval = hfs_vget_catinfo(parent_vp, &catInfo, kDefault, &target_vp); - if (retval) - goto Err_Exit; - - CLEAN_CATALOGDATA(&catInfo.nodeData); /* Should do nothing */ - }; - + /* + * If this is a link node then we need to save the name + * (of the link) so we can delete it from the catalog b-tree. + * In this case, hfs_remove will then free the component name. + * + * DJB - IS THIS STILL NEEDED???? + */ + if (tvp && (VTOC(tvp)->c_flag & C_HARDLINK)) cnp->cn_flags |= SAVENAME; - if (!lockparent) - VOP_UNLOCK(parent_vp, 0, p); - - goto Err_Exit; - /* Finished...all is well, goto the end */ - }; + + if (!(flags & LOCKPARENT)) + VOP_UNLOCK(dvp, 0, p); + *vpp = tvp; + goto exit; + } + /* + * If renaming, return the cnode and save the current name. + */ + if (nameiop == RENAME && wantparent && (flags & ISLASTCN)) { + if ((retval = VOP_ACCESS(dvp, VWRITE, cred, cnp->cn_proc)) != 0) + goto exit; /* - * Step through the translation in the name. We do not `vput' the - * directory because we may need it again if a symbolic link - * is relative to the current directory. Instead we save it - * unlocked as "tparent_vp". We must get the target hfsnode before unlocking - * the directory to insure that the hfsnode will not be removed - * before we get it. We prevent deadlock by always fetching - * inodes from the root, moving down the directory tree. Thus - * when following backward pointers ".." we must unlock the - * parent directory before getting the requested directory. - * There is a potential race condition here if both the current - * and parent directories are removed before the VFS_VGET for the - * hfsnode associated with ".." returns. We hope that this occurs - * infrequently since we cannot avoid this race condition without - * implementing a sophisticated deadlock detection algorithm. - * Note also that this simple deadlock detection scheme will not - * work if the file system has any hard links other than ".." - * that point backwards in the directory structure. + * Careful about locking second cnode. */ - - tparent_vp = parent_vp; - if (isDotDot) { - VOP_UNLOCK(tparent_vp, 0, p); /* race to get the inode */ - if ((retval = VFS_VGET(parent_vp->v_mount, &nodeID, &target_vp))) { - vn_lock(tparent_vp, LK_EXCLUSIVE | LK_RETRY, p); - goto Err_Exit; + if (isDot) { + retval = EISDIR; + goto exit; + } else if (flags & ISDOTDOT) { + retval = hfs_getcnode(hfsmp, dcp->c_parentcnid, + NULL, 0, NULL, NULL, &tvp); + if (retval) + goto exit; + } else { + retval = hfs_getcnode(hfsmp, attr.ca_fileid, + &desc, wantrsrc, &attr, &fork, &tvp); + if (retval) + goto exit; } - if (lockparent && (flags & ISLASTCN) && (tparent_vp != target_vp) && - (retval = vn_lock(tparent_vp, LK_EXCLUSIVE, p))) { - vput(target_vp); - goto Err_Exit; - } + cnp->cn_flags |= SAVENAME; + if (!(flags & LOCKPARENT)) + VOP_UNLOCK(dvp, 0, p); + *vpp = tvp; + goto exit; + } + + /* + * We must get the target cnode before unlocking + * the directory to insure that the cnode will not be removed + * before we get it. We prevent deadlock by always fetching + * cnodes from the root, moving down the directory tree. Thus + * when following backward pointers ".." we must unlock the + * parent directory before getting the requested directory. + * There is a potential race condition here if both the current + * and parent directories are removed before the VFS_VGET for the + * cnode associated with ".." returns. We hope that this occurs + * infrequently since we cannot avoid this race condition without + * implementing a sophisticated deadlock detection algorithm. + */ + if (flags & ISDOTDOT) { + VOP_UNLOCK(dvp, 0, p); /* race to get the cnode */ + retval = hfs_getcnode(hfsmp, dcp->c_parentcnid, + NULL, 0, NULL, NULL, &tvp); + if (retval) { + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); + goto exit; } - else if (isDot) { - VREF(parent_vp); /* we want ourself, ie "." */ - target_vp = parent_vp; + if ((flags & LOCKPARENT) && (flags & ISLASTCN) && (dvp != tvp) && + (retval = vn_lock(dvp, LK_EXCLUSIVE, p))) { + vput(tvp); + goto exit; } - else { - mode_t mode; - /* - * Determine what fork to get, currenty 3 scenarios are supported: - * 1. ./foo: if it is a dir, return a VDIR else return data fork - * 2. ./foo/.__Fork/data: return data fork - * 3. ./foo/.__Fork/rsrc: return resource fork - * So the algorithm is: - * If the object is a directory - * then return a VDIR vnode - * else if ISLASTCN is true - * then get the vnode with forkType=kDataFork - * else - * compare with the remaining cnp buffer with "/.__Fork/" - * if a match - * then compare string after that with either 'data' or 'rsrc' - * if match - * then - * 'consume' rest of cnp, setting appropriate values and flags - * return vnode depending on match - * else - * bad fork name - * else - * illegal path after a file object - */ + *vpp = tvp; + } else if (isDot) { + VREF(dvp); /* we want ourself, ie "." */ + *vpp = dvp; + } else { + int type = (attr.ca_mode & S_IFMT); - mode = (mode_t)(catInfo.nodeData.cnd_mode); - - if (catInfo.nodeData.cnd_type == kCatalogFolderNode) { - forkType = kDirectory; /* Really ignored */ - } - else if ((mode & IFMT) == IFLNK) { - forkType = kDataFork; - } /* After this point, nodeType should be a file */ - else if (flags & ISLASTCN) { /* Create a default fork */ - forkType = kDataFork; + if (!(flags & ISLASTCN) && type != S_IFDIR && type != S_IFLNK) { + retval = ENOTDIR; + goto exit; } - else { /* determine what fork was specified */ - forkType = GetForkFromName(cnp); - flags |= ISLASTCN; /* To know to unlock the parent if needed */ - }; /* else */ - - - /* If couldn't determine what type of fork, leave */ - if (forkType == kUndefinedFork) { - retval = ENOTDIR; - goto Err_Exit; - }; - - /* Get the vnode now that what type of fork is known */ - DBG_ASSERT((forkType==kDirectory) || (forkType==kDataFork) || (forkType==kRsrcFork)); - retval = hfs_vget_catinfo(tparent_vp, &catInfo, forkType, &target_vp); - if (retval != E_NONE) - goto Err_Exit; - - if (!lockparent || !(flags & ISLASTCN)) - VOP_UNLOCK(tparent_vp, 0, p); - - CLEAN_CATALOGDATA(&catInfo.nodeData); - }; /* else found */ - - - /* - * Insert name in cache if wanted. - * Names with composed chars are not put into the name cache. - * Resource forks are not entered in the name cache. This - * avoids deadlocks. - */ - if ((cnp->cn_flags & MAKEENTRY) - && (cnp->cn_namelen == catInfo.nodeData.cnm_length) - && ((H_FORKTYPE(VTOH(target_vp))) != kRsrcFork)) { - /* - * XXX SER - Might be good idea to bcopy(catInfo.nodeData.fsspec.name, cnp->cn_nameptr) - * to "normalize" the name cache. This will avoid polluting the name cache with - * names that are different in case, and allow negative caching - */ - cache_enter(parent_vp, target_vp, cnp); - } - - - - }; /* else found == TRUE */ - -Err_Exit: + retval = hfs_getcnode(hfsmp, attr.ca_fileid, + &desc, wantrsrc, &attr, &fork, &tvp); + if (retval) + goto exit; - CLEAN_CATALOGDATA(&catInfo.nodeData); /* Just to make sure */ - *ap->a_vpp = target_vp; + if (!(flags & LOCKPARENT) || !(flags & ISLASTCN)) + VOP_UNLOCK(dvp, 0, p); + *vpp = tvp; + } - DBG_VOP_UPDATE_VP(1, *ap->a_vpp); - //DBG_VOP_LOOKUP_TEST (funcname, cnp, parent_vp, target_vp); - //DBG_VOP_LOCKS_TEST(E_NONE); + /* + * Insert name in cache if appropriate. + * - "." and ".." are not cached. + * - Resource fork names are not cached. + * - Names with composed chars are not cached. + */ + if ((cnp->cn_flags & MAKEENTRY) + && !isDot + && !(flags & ISDOTDOT) + && !wantrsrc + && (cnp->cn_namelen == VTOC(*vpp)->c_desc.cd_namelen)) { + cache_enter(dvp, *vpp, cnp); + } +exit: + cat_releasedesc(&desc); return (retval); } @@ -608,14 +477,9 @@ Err_Exit: * is for DELETE, or NOCACHE is set (rewrite), and the * name is located in the cache, it will be dropped. * - * In hfs, since a name can represent multiple forks, it cannot - * be known what fork the name matches, so further checks have to be done. - * Currently a policy of first requested, is the one stored, is followed. - * - * SER XXX If this proves inadequate maybe we can munge the name to contain a fork reference - * like foo -> foo.d for the data fork. */ +__private_extern__ int hfs_cache_lookup(ap) struct vop_lookup_args /* { @@ -624,39 +488,31 @@ hfs_cache_lookup(ap) struct componentname *a_cnp; } */ *ap; { - struct vnode *vdp; - struct vnode *pdp; + struct vnode *dvp; + struct vnode *vp; + struct cnode *cp; int lockparent; int error; struct vnode **vpp = ap->a_vpp; - struct componentname *cnp = ap->a_cnp; - struct ucred *cred = cnp->cn_cred; + struct componentname *cnp = ap->a_cnp; + struct ucred *cred = cnp->cn_cred; int flags = cnp->cn_flags; - struct proc *p = cnp->cn_proc; - struct hfsnode *hp; - u_int32_t vpid; /* capability number of vnode */ - DBG_FUNC_NAME("cache_lookup"); - DBG_VOP_LOCKS_DECL(2); - DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_POS); - DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_POS); - DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("\n")); - DBG_VOP_CONT(("\tTarget: "));DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n")); - DBG_HFS_NODE_CHECK(ap->a_dvp); + struct proc *p = cnp->cn_proc; + u_long vpid; /* capability number of vnode */ *vpp = NULL; - vdp = ap->a_dvp; + dvp = ap->a_dvp; lockparent = flags & LOCKPARENT; - if (vdp->v_type != VDIR) + /* + * Check accessiblity of directory. + */ + if (dvp->v_type != VDIR) return (ENOTDIR); - - if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) && - (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) + if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) && + (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) return (EROFS); - - error = VOP_ACCESS(vdp, VEXEC, cred, cnp->cn_proc); - - if (error) + if ((error = VOP_ACCESS(dvp, VEXEC, cred, cnp->cn_proc))) return (error); /* @@ -666,54 +522,46 @@ hfs_cache_lookup(ap) * (negative cacheing), a status of ENOENT is returned. If the lookup * fails, a status of zero is returned. */ - error = cache_lookup(vdp, vpp, cnp); - + error = cache_lookup(dvp, vpp, cnp); if (error == 0) { /* Unsuccessfull */ - DBG_VOP(("\tWas not in name cache\n")); error = hfs_lookup(ap); -#if HFS_HARDLINKS - if (error) - return (error); - /* - * If this is a hard-link vnode then we need to update - * the name (of the link) and update the parent ID. This - * enables getattrlist calls to return correct link info. - */ - hp = VTOH(*ap->a_vpp); - if ((flags & ISLASTCN) && (hp->h_meta->h_metaflags & IN_DATANODE)) { - H_DIRID(hp) = H_FILEID(VTOH(ap->a_dvp)); - hfs_set_metaname(cnp->cn_nameptr, hp->h_meta, HTOHFS(hp)); - } -#endif return (error); - }; + } - DBG_VOP(("\tName was found in the name cache")); - if (error == ENOENT) { - DBG_VOP_CONT((" though it was a NEGATIVE HIT\n")); + if (error == ENOENT) return (error); - }; - DBG_VOP_CONT(("\n")); -#if HFS_HARDLINKS + /* We have a name that matched */ + vp = *vpp; + vpid = vp->v_id; + /* * If this is a hard-link vnode then we need to update - * the name (of the link) and update the parent ID. This - * enables getattrlist calls to return correct link info. + * the name (of the link), the parent ID, the cnid, the + * text encoding and the catalog hint. This enables + * getattrlist calls to return the correct link info. */ - hp = VTOH(*vpp); - if ((flags & ISLASTCN) && (hp->h_meta->h_metaflags & IN_DATANODE)) { - H_DIRID(hp) = H_FILEID(VTOH(vdp)); - hfs_set_metaname(cnp->cn_nameptr, hp->h_meta, HTOHFS(hp)); + cp = VTOC(vp); + if ((flags & ISLASTCN) && (cp->c_flag & C_HARDLINK) && + ((cp->c_parentcnid != VTOC(ap->a_dvp)->c_cnid) || + (bcmp(cnp->cn_nameptr, cp->c_desc.cd_nameptr, cp->c_desc.cd_namelen) != 0))) { + + struct cat_desc desc; + + /* + * Get an updated descriptor + */ + bzero(&desc, sizeof(desc)); + desc.cd_nameptr = cnp->cn_nameptr; + desc.cd_namelen = cnp->cn_namelen; + desc.cd_parentcnid = VTOC(ap->a_dvp)->c_cnid; + desc.cd_hint = VTOC(ap->a_dvp)->c_childhint; + if (cat_lookup(VTOHFS(vp), &desc, 0, &desc, NULL, NULL) == 0) + replace_desc(cp, &desc); } -#endif - /* We have a name that matched */ - pdp = vdp; - vdp = *vpp; - vpid = vdp->v_id; - if (pdp == vdp) { /* lookup on "." */ - VREF(vdp); + if (dvp == vp) { /* lookup on "." */ + VREF(vp); error = 0; } else if (flags & ISDOTDOT) { /* @@ -722,128 +570,85 @@ hfs_cache_lookup(ap) * to release lock on child before trying to lock parent * then regain lock if needed */ - VOP_UNLOCK(pdp, 0, p); - error = vget(vdp, LK_EXCLUSIVE, p); + VOP_UNLOCK(dvp, 0, p); + error = vget(vp, LK_EXCLUSIVE, p); if (!error && lockparent && (flags & ISLASTCN)) - error = vn_lock(pdp, LK_EXCLUSIVE, p); - } else if ((! (flags & ISLASTCN)) && (vdp->v_type == VREG) && - (GetForkFromName(cnp) != kDataFork)) { - /* - * We only store data forks in the name cache. - */ - goto finished; + error = vn_lock(dvp, LK_EXCLUSIVE, p); } else { - error = vget(vdp, LK_EXCLUSIVE, p); + if ((flags & ISLASTCN) == 0 && vp->v_type == VREG) { + int wantrsrc = 0; + + cnp->cn_consume = forkcomponent(cnp, &wantrsrc); + + /* Fork names are only for lookups */ + if (cnp->cn_consume && + (cnp->cn_nameiop != LOOKUP && cnp->cn_nameiop != CREATE)) + return (EPERM); + /* + * We only store data forks in the name cache. + */ + if (wantrsrc) + return (hfs_lookup(ap)); + } + error = vget(vp, LK_EXCLUSIVE, p); if (!lockparent || error || !(flags & ISLASTCN)) - VOP_UNLOCK(pdp, 0, p); + VOP_UNLOCK(dvp, 0, p); } /* * Check that the capability number did not change * while we were waiting for the lock. */ if (!error) { - if (vpid == vdp->v_id) - return (0); /* HERE IS THE NORMAL EXIT FOR CACHE LOOKUP!!!! */ + if (vpid == vp->v_id) + return (0); /* * The above is the NORMAL exit, after this point is an error * condition. */ - vput(vdp); - if (lockparent && pdp != vdp && (flags & ISLASTCN)) - VOP_UNLOCK(pdp, 0, p); + vput(vp); + if (lockparent && (dvp != vp) && (flags & ISLASTCN)) + VOP_UNLOCK(dvp, 0, p); } - error = vn_lock(pdp, LK_EXCLUSIVE, p); - if (error) - return (error); -finished: + if ((error = vn_lock(dvp, LK_EXCLUSIVE, p))) + return (error); return (hfs_lookup(ap)); } + /* - * Parses a componentname and sees if the remaining path - * contains a hfs named fork specifier. If it does set the - * componentname to consume the rest of the path, and - * return the forkType + * forkcomponent - look for a fork suffix in the component name + * */ - -u_int16_t GetForkFromName(struct componentname *cnp) +static int +forkcomponent(struct componentname *cnp, int *rsrcfork) { - u_int16_t forkType = kUndefinedFork; - char *tcp = cnp->cn_nameptr + cnp->cn_namelen; - - if (bcmp(tcp, _PATH_FORKSPECIFIER, sizeof(_PATH_FORKSPECIFIER) - 1) == 0) { - /* Its a HFS fork, so far */ - tcp += (sizeof(_PATH_FORKSPECIFIER) - 1); - if (bcmp(tcp, _PATH_DATANAME, sizeof(_PATH_DATANAME)) == 0) { - forkType = kDataFork; - cnp->cn_consume = sizeof(_PATH_FORKSPECIFIER) + sizeof(_PATH_DATANAME) - 2; - } - else if (bcmp(tcp, _PATH_RSRCNAME, sizeof(_PATH_RSRCNAME)) == 0) { - forkType = kRsrcFork; - cnp->cn_consume = sizeof(_PATH_FORKSPECIFIER) + sizeof(_PATH_RSRCNAME) - 2; - }; /* else if */ - }; /* if bcmp */ - - - /* XXX SER For backwards compatability...keep it */ - if (forkType == kUndefinedFork) { - tcp = cnp->cn_nameptr + cnp->cn_namelen; - if (bcmp(tcp, gHFSForkIdentStr, sizeof(gHFSForkIdentStr) - 1) == 0) { - /* Its a HFS fork, so far */ - tcp += (sizeof(gHFSForkIdentStr) - 1); - if (bcmp(tcp, gDataForkNameStr, sizeof(gDataForkNameStr)) == 0) { - forkType = kDataFork; - cnp->cn_consume = sizeof(gHFSForkIdentStr) + sizeof(gDataForkNameStr) - 2; - } - else if (bcmp(tcp, gRsrcForkNameStr, sizeof(gRsrcForkNameStr)) == 0) { - forkType = kRsrcFork; - cnp->cn_consume = sizeof(gHFSForkIdentStr) + sizeof(gRsrcForkNameStr) - 2; - }; /* else if */ - }; /* if bcmp */ - }; - - return forkType; -} - -#if DBG_VOP_TEST_LOCKS + char *suffix = cnp->cn_nameptr + cnp->cn_namelen; + int consume = 0; -void DbgLookupTest( char *funcname, struct componentname *cnp, struct vnode *dvp, struct vnode *vp) -{ - if (! (hfs_dbg_lookup || hfs_dbg_all)) - return; - - - if (dvp) { - if (lockstatus(&VTOH(dvp)->h_lock)) { - DBG_LOOKUP (("%s: Parent vnode exited LOCKED", funcname)); - } - else { - DBG_LOOKUP (("%s: Parent vnode exited UNLOCKED", funcname)); - } + *rsrcfork = 0; + if (*suffix == '\0') + return (0); + /* + * There are only 3 valid fork suffixes: + * "/..namedfork/rsrc" + * "/..namedfork/data" + * "/rsrc" (legacy) + */ + if (bcmp(suffix, _PATH_RSRCFORKSPEC, sizeof(_PATH_RSRCFORKSPEC)) == 0) { + consume = sizeof(_PATH_RSRCFORKSPEC) - 1; + *rsrcfork = 1; + } else if (bcmp(suffix, _PATH_DATAFORKSPEC, sizeof(_PATH_DATAFORKSPEC)) == 0) { + consume = sizeof(_PATH_DATAFORKSPEC) - 1; } - if (vp) { - if (vp==dvp) - { - DBG_LOOKUP (("%s: Target and Parent are the same", funcname)); - } - else { - if (lockstatus(&VTOH(vp)->h_lock)) { - DBG_LOOKUP (("%s: Found vnode exited LOCKED", funcname)); - } - else { - DBG_LOOKUP (("%s: Found vnode exited LOCKED", funcname)); - } - } - DBG_LOOKUP (("%s: Found vnode 0x%x has vtype of %d\n ", funcname, (u_int)vp, vp->v_type)); +#ifdef LEGACY_FORK_NAMES + else if (bcmp(suffix, LEGACY_RSRCFORKSPEC, sizeof(LEGACY_RSRCFORKSPEC)) == 0) { + consume = sizeof(LEGACY_RSRCFORKSPEC) - 1; + *rsrcfork = 1; } - else - DBG_LOOKUP (("%s: Found vnode exited NULL\n", funcname)); - - +#endif + return (consume); } -#endif /* DBG_VOP_TEST_LOCKS */ - diff --git a/bsd/hfs/hfs_macos_defs.h b/bsd/hfs/hfs_macos_defs.h index 917613810..33461cc17 100644 --- a/bsd/hfs/hfs_macos_defs.h +++ b/bsd/hfs/hfs_macos_defs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -19,21 +19,14 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* - File: hfs_macos_types.h - - Contains: Basic Macintosh OS data types. - - Version: System 7.5 - - DRI: Nick Kledzik - -*/ +#ifndef __HFS_MACOS_TYPES__ +#define __HFS_MACOS_TYPES__ -#ifndef __hfs_macos_types__ -#define __hfs_macos_types__ +#include +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE #include #ifdef KERNEL @@ -46,123 +39,37 @@ #include #include -/****** START OF CONDITIONALMACROS *********/ - - #if defined(__ppc__) || defined(powerpc) || defined(ppc) - #define TARGET_CPU_PPC 1 - #define TARGET_CPU_68K 0 - #define TARGET_CPU_X86 0 - #define TARGET_CPU_MIPS 0 - #define TARGET_CPU_SPARC 0 - #define TARGET_CPU_ALPHA 0 - #define TARGET_RT_MAC_CFM 0 - #define TARGET_RT_MAC_MACHO 1 - #define TARGET_RT_MAC_68881 0 - #define TARGET_RT_LITTLE_ENDIAN 0 - #define TARGET_RT_BIG_ENDIAN 1 - #elif defined(m68k) - #define TARGET_CPU_PPC 0 - #define TARGET_CPU_68K 1 - #define TARGET_CPU_X86 0 - #define TARGET_CPU_MIPS 0 - #define TARGET_CPU_SPARC 0 - #define TARGET_CPU_ALPHA 0 - #define TARGET_RT_MAC_CFM 0 - #define TARGET_RT_MAC_MACHO 1 - #define TARGET_RT_MAC_68881 0 - #define TARGET_RT_LITTLE_ENDIAN 0 - #define TARGET_RT_BIG_ENDIAN 1 - #elif defined(sparc) - #define TARGET_CPU_PPC 0 - #define TARGET_CPU_68K 0 - #define TARGET_CPU_X86 0 - #define TARGET_CPU_MIPS 0 - #define TARGET_CPU_SPARC 1 - #define TARGET_CPU_ALPHA 0 - #define TARGET_RT_MAC_CFM 0 - #define TARGET_RT_MAC_MACHO 1 - #define TARGET_RT_MAC_68881 0 - #define TARGET_RT_LITTLE_ENDIAN 0 - #define TARGET_RT_BIG_ENDIAN 1 - #elif defined(__i386__) || defined(i386) || defined(intel) - #define TARGET_CPU_PPC 0 - #define TARGET_CPU_68K 0 - #define TARGET_CPU_X86 1 - #define TARGET_CPU_MIPS 0 - #define TARGET_CPU_SPARC 0 - #define TARGET_CPU_ALPHA 0 - #define TARGET_RT_MAC_CFM 0 - #define TARGET_RT_MAC_MACHO 1 - #define TARGET_RT_MAC_68881 0 - #define TARGET_RT_LITTLE_ENDIAN 1 - #define TARGET_RT_BIG_ENDIAN 0 - #else - #error unrecognized GNU C compiler - #endif +#define TARGET_OS_MAC 0 +#define TARGET_OS_WIN32 0 +#define TARGET_OS_UNIX 0 - #define TARGET_OS_MAC 0 - #define TARGET_OS_WIN32 0 - #define TARGET_OS_UNIX 0 - - #define PRAGMA_IMPORT 0 - #define PRAGMA_STRUCT_ALIGN 1 - #define PRAGMA_ONCE 0 - #define PRAGMA_STRUCT_PACK 0 - #define PRAGMA_STRUCT_PACKPUSH 0 - #define PRAGMA_ENUM_PACK 0 - #define PRAGMA_ENUM_ALWAYSINT 0 - #define PRAGMA_ENUM_OPTIONS 0 - #define FOUR_CHAR_CODE(x) (x) - - #define TYPE_EXTENDED 0 - #if __GNUC__ >= 2 - #define TYPE_LONGLONG 1 - #else - #define TYPE_LONGLONG 0 - #endif - #ifdef __cplusplus - #define TYPE_BOOL 1 - #else - #define TYPE_BOOL 0 - #endif - - #define FUNCTION_PASCAL 0 - #define FUNCTION_DECLSPEC 0 - #define FUNCTION_WIN32CC 0 +#define PRAGMA_IMPORT 0 +#define PRAGMA_STRUCT_ALIGN 1 +#define PRAGMA_ONCE 0 +#define PRAGMA_STRUCT_PACK 0 +#define PRAGMA_STRUCT_PACKPUSH 0 + +#if __GNUC__ >= 2 + #define TYPE_LONGLONG 1 +#else + #define TYPE_LONGLONG 0 +#endif +#ifdef __cplusplus + #define TYPE_BOOL 1 +#else + #define TYPE_BOOL 0 +#endif +#define EXTERN_API(_type) extern _type +#define EXTERN_API_C(_type) extern _type - #define EXTERN_API(_type) extern _type - #define EXTERN_API_C(_type) extern _type - #define EXTERN_API_STDCALL(_type) extern _type - #define EXTERN_API_C_STDCALL(_type) extern _type - - #define DEFINE_API(_type) _type - #define DEFINE_API_C(_type) _type - #define DEFINE_API_STDCALL(_type) _type - #define DEFINE_API_C_STDCALL(_type) _type - - #define CALLBACK_API(_type, _name) _type ( * _name) - #define CALLBACK_API_C(_type, _name) _type ( * _name) - #define CALLBACK_API_STDCALL(_type, _name) _type ( * _name) - #define CALLBACK_API_C_STDCALL(_type, _name) _type ( * _name) - - #define TARGET_API_MACOS_X 1 - #define TARGET_API_MAC_OS8 0 - #define TARGET_API_MAC_CARBON 0 +#define CALLBACK_API_C(_type, _name) _type ( * _name) + +#define TARGET_API_MACOS_X 1 +#define TARGET_API_MAC_OS8 0 +#define TARGET_API_MAC_CARBON 0 - #define ONEWORDINLINE(w1) - #define TWOWORDINLINE(w1,w2) - #define THREEWORDINLINE(w1,w2,w3) - #define FOURWORDINLINE(w1,w2,w3,w4) - #define FIVEWORDINLINE(w1,w2,w3,w4,w5) - #define SIXWORDINLINE(w1,w2,w3,w4,w5,w6) - #define SEVENWORDINLINE(w1,w2,w3,w4,w5,w6,w7) - #define EIGHTWORDINLINE(w1,w2,w3,w4,w5,w6,w7,w8) - #define NINEWORDINLINE(w1,w2,w3,w4,w5,w6,w7,w8,w9) - #define TENWORDINLINE(w1,w2,w3,w4,w5,w6,w7,w8,w9,w10) - #define ELEVENWORDINLINE(w1,w2,w3,w4,w5,w6,w7,w8,w9,w10,w11) - #define TWELVEWORDINLINE(w1,w2,w3,w4,w5,w6,w7,w8,w9,w10,w11,w12) /****** START OF MACOSTYPES *********/ @@ -200,123 +107,42 @@ #endif -/******************************************************************************** - - Base integer types for all target OS's and CPU's - - UInt8 8-bit unsigned integer - SInt8 8-bit signed integer - UInt16 16-bit unsigned integer - SInt16 16-bit signed integer - UInt32 32-bit unsigned integer - SInt32 32-bit signed integer - UInt64 64-bit unsigned integer - SInt64 64-bit signed integer - -*********************************************************************************/ -typedef u_int8_t UInt8; -typedef int8_t SInt8; -typedef u_int16_t UInt16; -typedef int16_t SInt16; -typedef u_int32_t UInt32; -typedef int32_t SInt32; -typedef u_int64_t UInt64; -typedef int64_t SInt64; - - - -/******************************************************************************** - - Base floating point types - - Float32 32 bit IEEE float: 1 sign bit, 8 exponent bits, 23 fraction bits - Float64 64 bit IEEE float: 1 sign bit, 11 exponent bits, 52 fraction bits - Float80 80 bit MacOS float: 1 sign bit, 15 exponent bits, 1 integer bit, 63 fraction bits - Float96 96 bit 68881 float: 1 sign bit, 15 exponent bits, 16 pad bits, 1 integer bit, 63 fraction bits - - Note: These are fixed size floating point types, useful when writing a floating - point value to disk. If your compiler does not support a particular size - float, a struct is used instead. - Use of of the NCEG types (e.g. double_t) or an ANSI C type (e.g. double) if - you want a floating point representation that is natural for any given - compiler, but might be a different size on different compilers. - -*********************************************************************************/ -typedef float Float32; -typedef double Float64; - -struct Float80 { - SInt16 exp; - UInt16 man[4]; -}; -typedef struct Float80 Float80; - -struct Float96 { - SInt16 exp[2]; /* the second 16-bits is always zero */ - UInt16 man[4]; -}; -typedef struct Float96 Float96; - - - -/******************************************************************************** - - MacOS Memory Manager types - - Ptr Pointer to a non-relocatable block - Handle Pointer to a master pointer to a relocatable block - Size The number of bytes in a block (signed for historical reasons) - -*********************************************************************************/ -typedef char * Ptr; -typedef Ptr * Handle; -typedef long Size; -/******************************************************************************** - - Higher level basic types - - OSErr 16-bit result error code - OSStatus 32-bit result error code - LogicalAddress Address in the clients virtual address space - ConstLogicalAddress Address in the clients virtual address space that will only be read - PhysicalAddress Real address as used on the hardware bus - BytePtr Pointer to an array of bytes - ByteCount The size of an array of bytes - ByteOffset An offset into an array of bytes - ItemCount 32-bit iteration count - OptionBits Standard 32-bit set of bit flags - PBVersion ? - Duration 32-bit millisecond timer for drivers - AbsoluteTime 64-bit clock - ScriptCode The coarse features of a written language (e.g. Roman vs Cyrillic) - LangCode A particular language (e.g. English) - RegionCode A variation of a language (British vs American English) - FourCharCode A 32-bit value made by packing four 1 byte characters together - OSType A FourCharCode used in the OS and file system (e.g. creator) - ResType A FourCharCode used to tag resources (e.g. 'DLOG') - -*********************************************************************************/ -typedef SInt16 OSErr; -typedef SInt32 OSStatus; -typedef void * LogicalAddress; -typedef const void * ConstLogicalAddress; -typedef void * PhysicalAddress; -typedef UInt8 * BytePtr; -typedef UInt32 ByteCount; -typedef UInt32 ByteOffset; -typedef SInt32 Duration; -typedef UInt64 AbsoluteTime; -typedef UInt32 OptionBits; -typedef UInt32 ItemCount; -typedef UInt32 PBVersion; -typedef SInt16 ScriptCode; -typedef SInt16 LangCode; -typedef SInt16 RegionCode; -typedef unsigned long FourCharCode; -typedef FourCharCode OSType; -typedef FourCharCode ResType; -typedef OSType * OSTypePtr; -typedef ResType * ResTypePtr; +typedef u_int8_t UInt8; +typedef int8_t SInt8; +typedef u_int16_t UInt16; +typedef int16_t SInt16; +typedef u_int32_t UInt32; +typedef int32_t SInt32; +typedef u_int64_t UInt64; +typedef int64_t SInt64; + +typedef char * Ptr; +typedef long Size; + +typedef SInt16 OSErr; +typedef SInt32 OSStatus; +typedef UInt32 ItemCount; +typedef void * LogicalAddress; +typedef UInt32 ByteCount; +typedef UInt8 * BytePtr; +typedef UInt32 ByteOffset; +typedef UInt32 OptionBits; +typedef unsigned long FourCharCode; +typedef FourCharCode OSType; + +typedef UInt16 UniChar; +typedef unsigned char Str255[256]; +typedef unsigned char Str31[32]; +typedef unsigned char * StringPtr; +typedef const unsigned char * ConstStr255Param; +typedef const unsigned char * ConstStr31Param; +typedef const unsigned char * ConstUTF8Param; + +typedef UInt8 Byte; + +typedef UInt32 TextEncoding; +typedef UniChar * UniCharArrayPtr; +typedef const UniChar * ConstUniCharArrayPtr; /******************************************************************************** @@ -343,190 +169,12 @@ enum { #endif /* !TYPE_BOOL */ -typedef unsigned char Boolean; +typedef unsigned char Boolean; -/******************************************************************************** - - Function Pointer Types - - ProcPtr Generic pointer to a function - Register68kProcPtr Pointer to a 68K function that expects parameters in registers - UniversalProcPtr Pointer to classic 68K code or a RoutineDescriptor - - ProcHandle Pointer to a ProcPtr - UniversalProcHandle Pointer to a UniversalProcPtr - -*********************************************************************************/ -typedef long (*ProcPtr)(); -typedef void (*Register68kProcPtr)(); - -typedef ProcPtr UniversalProcPtr; - -typedef ProcPtr * ProcHandle; -typedef UniversalProcPtr * UniversalProcHandle; - -/******************************************************************************** - - Quickdraw Types - - Point 2D Quickdraw coordinate, range: -32K to +32K - Rect Rectangluar Quickdraw area - Style Quickdraw font rendering styles - StyleParameter Style when used as a parameter (historical 68K convention) - StyleField Style when used as a field (historical 68K convention) - CharParameter Char when used as a parameter (historical 68K convention) - - Note: The original Macintosh toolbox in 68K Pascal defined Style as a SET. - Both Style and CHAR occupy 8-bits in packed records or 16-bits when - used as fields in non-packed records or as parameters. - -*********************************************************************************/ -struct Point { - short v; - short h; -}; -typedef struct Point Point; - -typedef Point * PointPtr; -struct Rect { - short top; - short left; - short bottom; - short right; -}; -typedef struct Rect Rect; - -typedef Rect * RectPtr; -typedef short CharParameter; - -enum { - normal = 0, - bold = 1, - italic = 2, - underline = 4, - outline = 8, - shadow = 0x10, - condense = 0x20, - extend = 0x40 -}; - -typedef unsigned char Style; -typedef short StyleParameter; -typedef Style StyleField; -/******************************************************************************** - - Common Constants - - noErr OSErr: function performed properly - no error - kNilOptions OptionBits: all flags false - kInvalidID KernelID: NULL is for pointers as kInvalidID is for ID's - kVariableLengthArray array bounds: variable length array - - Note: kVariableLengthArray is used in array bounds to specify a variable length array. - It is ususally used in variable length structs when the last field is an array - of any size. Before ANSI C, we used zero as the bounds of variable length - array, but zero length array are illegal in ANSI C. Example usage: - - struct FooList - { - short listLength; - Foo elements[kVariableLengthArray]; - }; - -*********************************************************************************/ - -enum { - noErr = 0 -}; - - -enum { - kNilOptions = 0 -}; - -#define kInvalidID 0 - -enum { - kVariableLengthArray = 1 -}; - - - -/******************************************************************************** - - String Types - - UniChar A single UniCode character (16-bits) - - StrNNN Pascal string holding up to NNN bytes - StringPtr Pointer to a pascal string - StringHandle Pointer to a StringPtr - ConstStrNNNParam For function parameters only - means string is const - - CStringPtr Pointer to a C string (same as: char*) - ConstCStringPtr Pointer to a const C string (same as: const char*) - - Note: The length of a pascal string is stored in the first byte. - A pascal string does not have a termination byte and can be at most 255 bytes long. - The first character in a pascal string is offset one byte from the start of the string. - - A C string is terminated with a byte of value zero. - A C string has no length limitation. - The first character in a C string is the first byte of the string. - - -*********************************************************************************/ -typedef UInt16 UniChar; -typedef unsigned char Str255[256]; -typedef unsigned char Str63[64]; -typedef unsigned char Str32[33]; -typedef unsigned char Str31[32]; -typedef unsigned char Str27[28]; -typedef unsigned char Str15[16]; -/* - The type Str32 is used in many AppleTalk based data structures. - It holds up to 32 one byte chars. The problem is that with the - length byte it is 33 bytes long. This can cause weird alignment - problems in structures. To fix this the type "Str32Field" has - been created. It should only be used to hold 32 chars, but - it is 34 bytes long so that there are no alignment problems. -*/ -typedef unsigned char Str32Field[34]; -typedef unsigned char * StringPtr; -typedef StringPtr * StringHandle; -typedef const unsigned char * ConstStr255Param; -typedef const unsigned char * ConstStr63Param; -typedef const unsigned char * ConstStr32Param; -typedef const unsigned char * ConstStr31Param; -typedef const unsigned char * ConstStr27Param; -typedef const unsigned char * ConstStr15Param; -#ifdef __cplusplus -inline unsigned char StrLength(ConstStr255Param string) { return (*string); } -#else -#define StrLength(string) (*(unsigned char *)(string)) -#endif /* defined(__cplusplus) */ - -typedef const unsigned char * ConstUTF8Param; - -/********************************************************************************* - - Old names for types - -*********************************************************************************/ -typedef UInt8 Byte; -typedef SInt8 SignedByte; -typedef SInt64 * WidePtr; -typedef UInt64 * UnsignedWidePtr; -typedef Float80 extended80; -typedef Float96 extended96; -typedef SInt8 VHSelect; - - -EXTERN_API( void ) -DebugStr (ConstStr255Param debuggerMsg); +EXTERN_API( void ) DebugStr(ConstStr255Param debuggerMsg); /********************************************************************************* @@ -535,11 +183,7 @@ DebugStr (ConstStr255Param debuggerMsg); *********************************************************************************/ - typedef struct vnode* FileReference; - #define kNoFileReference NULL - - -#define HFSInstrumentation 0 +typedef struct vnode* FileReference; /***** START OF MACOSSTUBS ********/ @@ -560,456 +204,41 @@ DebugStr (ConstStr255Param debuggerMsg); #endif /* __size_t__ */ -/* - StdDef.h -- Common definitions - -*/ - -#define offsetof(structure,field) ((size_t)&((structure *) 0)->field) - - - /* File: Errors.h */ enum { - paramErr = -50, /*error in user parameter list*/ - noHardwareErr = -200, /*Sound Manager Error Returns*/ - notEnoughHardwareErr = -201, /*Sound Manager Error Returns*/ - userCanceledErr = -128, - qErr = -1, /*queue element not found during deletion*/ - vTypErr = -2, /*invalid queue element*/ - corErr = -3, /*core routine number out of range*/ - unimpErr = -4, /*unimplemented core routine*/ - SlpTypeErr = -5, /*invalid queue element*/ - seNoDB = -8, /*no debugger installed to handle debugger command*/ - controlErr = -17, /*I/O System Errors*/ - statusErr = -18, /*I/O System Errors*/ - readErr = -19, /*I/O System Errors*/ - writErr = -20, /*I/O System Errors*/ - badUnitErr = -21, /*I/O System Errors*/ - unitEmptyErr = -22, /*I/O System Errors*/ - openErr = -23, /*I/O System Errors*/ - closErr = -24, /*I/O System Errors*/ - dRemovErr = -25, /*tried to remove an open driver*/ - dInstErr = -26 /*DrvrInstall couldn't find driver in resources*/ -}; - -enum { /* Printing Errors */ - iMemFullErr = -108, - iIOAbort = -27, /*Scrap Manager errors*/ - noScrapErr = -100, /*No scrap exists error*/ - noTypeErr = -102, /*No object of that type in scrap*/ - memROZWarn = -99, /*soft error in ROZ*/ - memROZError = -99, /*hard error in ROZ*/ - memROZErr = -99, /*hard error in ROZ*/ - memFullErr = -108, /*Not enough room in heap zone*/ - nilHandleErr = -109, /*Master Pointer was NIL in HandleZone or other*/ - memWZErr = -111, /*WhichZone failed (applied to free block)*/ - memPurErr = -112, /*trying to purge a locked or non-purgeable block*/ - memAdrErr = -110 /*address was odd; or out of range*/ -}; - - - -enum { - abortErr = -27, /*IO call aborted by KillIO*/ - iIOAbortErr = -27, /*IO abort error (Printing Manager)*/ - notOpenErr = -28, /*Couldn't rd/wr/ctl/sts cause driver not opened*/ - unitTblFullErr = -29, /*unit table has no more entries*/ - dceExtErr = -30, /*dce extension error*/ - slotNumErr = -360, /*invalid slot # error*/ - gcrOnMFMErr = -400, /*gcr format on high density media error*/ - dirFulErr = -33, /*Directory full*/ - dskFulErr = -34, /*disk full*/ - nsvErr = -35, /*no such volume*/ - ioErr = -36, /*I/O error (bummers)*/ - bdNamErr = -37, /*there may be no bad names in the final system!*/ - fnOpnErr = -38, /*File not open*/ - eofErr = -39, /*End of file*/ - posErr = -40, /*tried to position to before start of file (r/w)*/ - mFulErr = -41, /*memory full (open) or file won't fit (load)*/ - tmfoErr = -42, /*too many files open*/ - fnfErr = -43, /*File not found*/ - wPrErr = -44, /*diskette is write protected.*/ - fLckdErr = -45 /*file is locked*/ -}; - - -enum { - vLckdErr = -46, /*volume is locked*/ - fBsyErr = -47, /*File is busy (delete)*/ - dupFNErr = -48, /*duplicate filename (rename)*/ - opWrErr = -49, /*file already open with with write permission*/ - rfNumErr = -51, /*refnum error*/ - gfpErr = -52, /*get file position error*/ - volOffLinErr = -53, /*volume not on line error (was Ejected)*/ - permErr = -54, /*permissions error (on file open)*/ - volOnLinErr = -55, /*drive volume already on-line at MountVol*/ - nsDrvErr = -56, /*no such drive (tried to mount a bad drive num)*/ - noMacDskErr = -57, /*not a mac diskette (sig bytes are wrong)*/ - extFSErr = -58, /*volume in question belongs to an external fs*/ - fsRnErr = -59, /*file system internal error:during rename the old entry was deleted but could not be restored.*/ - badMDBErr = -60, /*bad master directory block*/ - wrPermErr = -61, /*write permissions error*/ - dirNFErr = -120, /*Directory not found*/ - tmwdoErr = -121, /*No free WDCB available*/ - badMovErr = -122, /*Move into offspring error*/ - wrgVolTypErr = -123, /*Wrong volume type error [operation not supported for MFS]*/ - volGoneErr = -124 /*Server volume has been disconnected.*/ -}; - -enum { - /*Dictionary Manager errors*/ - notBTree = -410, /*The file is not a dictionary.*/ - btNoSpace = -413, /*Can't allocate disk space.*/ - btDupRecErr = -414, /*Record already exists.*/ - btRecNotFnd = -415, /*Record cannot be found.*/ - btKeyLenErr = -416, /*Maximum key length is too long or equal to zero.*/ - btKeyAttrErr = -417, /*There is no such a key attribute.*/ - unknownInsertModeErr = -20000, /*There is no such an insert mode.*/ - recordDataTooBigErr = -20001, /*The record data is bigger than buffer size (1024 bytes).*/ - invalidIndexErr = -20002 /*The recordIndex parameter is not valid.*/ -}; - - -enum { - fidNotFound = -1300, /*no file thread exists.*/ - fidExists = -1301, /*file id already exists*/ - notAFileErr = -1302, /*directory specified*/ - diffVolErr = -1303, /*files on different volumes*/ - catChangedErr = -1304, /*the catalog has been modified*/ - desktopDamagedErr = -1305, /*desktop database files are corrupted*/ - sameFileErr = -1306, /*can't exchange a file with itself*/ - badFidErr = -1307, /*file id is dangling or doesn't match with the file number*/ - notARemountErr = -1308, /*when _Mount allows only remounts and doesn't get one*/ - fileBoundsErr = -1309, /*file's EOF, offset, mark or size is too big*/ - fsDataTooBigErr = -1310, /*file or volume is too big for system*/ - volVMBusyErr = -1311, /*can't eject because volume is in use by VM*/ - envNotPresent = -5500, /*returned by glue.*/ - envBadVers = -5501, /*Version non-positive*/ - envVersTooBig = -5502, /*Version bigger than call can handle*/ - fontDecError = -64, /*error during font declaration*/ - fontNotDeclared = -65, /*font not declared*/ - fontSubErr = -66, /*font substitution occured*/ - fontNotOutlineErr = -32615, /*bitmap font passed to routine that does outlines only*/ - firstDskErr = -84, /*I/O System Errors*/ - lastDskErr = -64, /*I/O System Errors*/ - noDriveErr = -64, /*drive not installed*/ - offLinErr = -65, /*r/w requested for an off-line drive*/ - noNybErr = -66 /*couldn't find 5 nybbles in 200 tries*/ -}; - -enum { - /* general text errors*/ - kTextUnsupportedEncodingErr = -8738, /* specified encoding not supported for this operation*/ - kTextMalformedInputErr = -8739, /* in DBCS, for example, high byte followed by invalid low byte*/ - kTextUndefinedElementErr = -8740, /* text conversion errors*/ - kTECMissingTableErr = -8745, - kTECTableChecksumErr = -8746, - kTECTableFormatErr = -8747, - kTECCorruptConverterErr = -8748, /* invalid converter object reference*/ - kTECNoConversionPathErr = -8749, - kTECBufferBelowMinimumSizeErr = -8750, /* output buffer too small to allow processing of first input text element*/ - kTECArrayFullErr = -8751, /* supplied name buffer or TextRun, TextEncoding, or UnicodeMapping array is too small*/ - kTECBadTextRunErr = -8752, - kTECPartialCharErr = -8753, /* input buffer ends in the middle of a multibyte character, conversion stopped*/ - kTECUnmappableElementErr = -8754, - kTECIncompleteElementErr = -8755, /* text element may be incomplete or is too long for internal buffers*/ - kTECDirectionErr = -8756, /* direction stack overflow, etc.*/ - kTECGlobalsUnavailableErr = -8770, /* globals have already been deallocated (premature TERM)*/ - kTECItemUnavailableErr = -8771, /* item (e.g. name) not available for specified region (& encoding if relevant)*/ - /* text conversion status codes*/ - kTECUsedFallbacksStatus = -8783, - kTECNeedFlushStatus = -8784, - kTECOutputBufferFullStatus = -8785, /* output buffer has no room for conversion of next input text element (partial conversion)*/ - /* deprecated error & status codes for low-level converter*/ - unicodeChecksumErr = -8769, - unicodeNoTableErr = -8768, - unicodeVariantErr = -8767, - unicodeFallbacksErr = -8766, - unicodePartConvertErr = -8765, - unicodeBufErr = -8764, - unicodeCharErr = -8763, - unicodeElementErr = -8762, - unicodeNotFoundErr = -8761, - unicodeTableFormatErr = -8760, - unicodeDirectionErr = -8759, - unicodeContextualErr = -8758, - unicodeTextEncodingDataErr = -8757 -}; - - -/* - File: MacMemory.h - - -*/ - - -/* - File: MixedMode.h - -*/ - -/* Calling Conventions */ -typedef unsigned short CallingConventionType; - -enum { - kPascalStackBased = 0, - kCStackBased = 1, - kRegisterBased = 2, - kD0DispatchedPascalStackBased = 8, - kD1DispatchedPascalStackBased = 12, - kD0DispatchedCStackBased = 9, - kStackDispatchedPascalStackBased = 14, - kThinkCStackBased = 5 -}; - - - #define STACK_UPP_TYPE(name) name - #define REGISTER_UPP_TYPE(name) name - - -/* - File: OSUtils.h - -*/ -typedef struct QElem QElem; - -typedef QElem * QElemPtr; -struct QHdr { - short qFlags; - QElemPtr qHead; - QElemPtr qTail; -}; -typedef struct QHdr QHdr; - -typedef QHdr * QHdrPtr; + noErr = 0, + dskFulErr = -34, /*disk full*/ + bdNamErr = -37, /*there may be no bad names in the final system!*/ + paramErr = -50, /*error in user parameter list*/ + memFullErr = -108, /*Not enough room in heap zone*/ + fileBoundsErr = -1309, /*file's EOF, offset, mark or size is too big*/ + kTECUsedFallbacksStatus = -8783, -typedef CALLBACK_API( void , DeferredTaskProcPtr )(long dtParam); -/* - WARNING: DeferredTaskProcPtr uses register based parameters under classic 68k - and cannot be written in a high-level language without - the help of mixed mode or assembly glue. -*/ -typedef REGISTER_UPP_TYPE(DeferredTaskProcPtr) DeferredTaskUPP; -enum { uppDeferredTaskProcInfo = 0x0000B802 }; /* register no_return_value Func(4_bytes:A1) */ -#define NewDeferredTaskProc(userRoutine) (DeferredTaskUPP)NewRoutineDescriptor((ProcPtr)(userRoutine), uppDeferredTaskProcInfo, GetCurrentArchitecture()) -#define CallDeferredTaskProc(userRoutine, dtParam) CALL_ONE_PARAMETER_UPP((userRoutine), uppDeferredTaskProcInfo, (dtParam)) -struct DeferredTask { - QElemPtr qLink; - short qType; - short dtFlags; - DeferredTaskUPP dtAddr; - long dtParam; - long dtReserved; }; -typedef struct DeferredTask DeferredTask; -typedef DeferredTask * DeferredTaskPtr; - -/* - File: Finder.h - - -*/ - -/* - The following declerations used to be in Files.‰, - but are Finder specific and were moved here. -*/ enum { - /* Finder Flags */ - kIsOnDesk = 0x0001, - kColor = 0x000E, - kIsShared = 0x0040, /* bit 0x0080 is hasNoINITS */ - kHasBeenInited = 0x0100, /* bit 0x0200 was the letter bit for AOCE, but is now reserved for future use */ - kHasCustomIcon = 0x0400, - kIsStationery = 0x0800, - kNameLocked = 0x1000, - kHasBundle = 0x2000, - kIsInvisible = 0x4000, - kIsAlias = 0x8000 + /* Finder Flags */ + kHasBeenInited = 0x0100, + kHasCustomIcon = 0x0400, + kIsStationery = 0x0800, + kNameLocked = 0x1000, + kHasBundle = 0x2000, + kIsInvisible = 0x4000, + kIsAlias = 0x8000 }; - enum { - /* Finder Constants */ - fOnDesk = 1, - fHasBundle = 8192, - fTrash = -3, - fDesktop = -2, - fDisk = 0 + fsRtParID = 1, + fsRtDirID = 2 }; -#if PRAGMA_STRUCT_ALIGN - #pragma options align=mac68k -#elif PRAGMA_STRUCT_PACKPUSH - #pragma pack(push, 2) -#elif PRAGMA_STRUCT_PACK - #pragma pack(2) -#endif - - -struct FInfo { - OSType fdType; /*the type of the file*/ - OSType fdCreator; /*file's creator*/ - unsigned short fdFlags; /*flags ex. hasbundle,invisible,locked, etc.*/ - Point fdLocation; /*file's location in folder*/ - short fdFldr; /*folder containing file*/ -}; -typedef struct FInfo FInfo; - -struct FXInfo { - short fdIconID; /*Icon ID*/ - short fdUnused[3]; /*unused but reserved 6 bytes*/ - SInt8 fdScript; /*Script flag and number*/ - SInt8 fdXFlags; /*More flag bits*/ - short fdComment; /*Comment ID*/ - long fdPutAway; /*Home Dir ID*/ -}; -typedef struct FXInfo FXInfo; - -struct DInfo { - Rect frRect; /*folder rect*/ - unsigned short frFlags; /*Flags*/ - Point frLocation; /*folder location*/ - short frView; /*folder view*/ -}; -typedef struct DInfo DInfo; - -struct DXInfo { - Point frScroll; /*scroll position*/ - long frOpenChain; /*DirID chain of open folders*/ - SInt8 frScript; /*Script flag and number*/ - SInt8 frXFlags; /*More flag bits*/ - short frComment; /*comment*/ - long frPutAway; /*DirID*/ -}; -typedef struct DXInfo DXInfo; - -#if PRAGMA_STRUCT_ALIGN - #pragma options align=reset -#elif PRAGMA_STRUCT_PACKPUSH - #pragma pack(pop) -#elif PRAGMA_STRUCT_PACK - #pragma pack() -#endif - enum { - fsRtParID = 1, - fsRtDirID = 2 -}; - - - -#if PRAGMA_STRUCT_ALIGN - #pragma options align=mac68k -#elif PRAGMA_STRUCT_PACKPUSH - #pragma pack(push, 2) -#elif PRAGMA_STRUCT_PACK - #pragma pack(2) -#endif - - -#if PRAGMA_STRUCT_ALIGN - #pragma options align=reset -#elif PRAGMA_STRUCT_PACKPUSH - #pragma pack(pop) -#elif PRAGMA_STRUCT_PACK - #pragma pack() -#endif - - -/* - * UTGetBlock options - */ - -enum { - gbDefault = 0, /* default value - read if not found */ - /* bits and masks */ - gbReadBit = 0, /* read block from disk (forced read) */ - gbReadMask = 0x0001, - gbExistBit = 1, /* get existing cache block */ - gbExistMask = 0x0002, - gbNoReadBit = 2, /* don't read block from disk if not found in cache */ - gbNoReadMask = 0x0004, - gbReleaseBit = 3, /* release block immediately after GetBlock */ - gbReleaseMask = 0x0008 -}; - - -/* - * UTReleaseBlock options - */ - -enum { - rbDefault = 0, /* default value - just mark the buffer not in-use */ - /* bits and masks */ - rbWriteBit = 0, /* force write buffer to disk */ - rbWriteMask = 0x0001, - rbTrashBit = 1, /* trash buffer contents after release */ - rbTrashMask = 0x0002, - rbDirtyBit = 2, /* mark buffer dirty */ - rbDirtyMask = 0x0004, - rbFreeBit = 3, /* free the buffer (save in the hash) */ - rbFreeMask = 0x000A /* rbFreeMask (rbFreeBit + rbTrashBit) works as rbTrash on < System 7.0 RamCache; on >= System 7.0, rbfreeMask overrides rbTrash */ -}; - -/* - * UTFlushCache options - */ - -enum { - fcDefault = 0, /* default value - pass this fcOption to just flush any dirty buffers */ - /* bits and masks */ - fcTrashBit = 0, /* (don't pass this as fcOption, use only for testing bit) */ - fcTrashMask = 0x0001, /* pass this fcOption value to flush and trash cache blocks */ - fcFreeBit = 1, /* (don't pass this as fcOption, use only for testing bit) */ - fcFreeMask = 0x0003 /* pass this fcOption to flush and free cache blocks (Note: both fcTrash and fcFree bits are set) */ -}; - - - -/* - * FCBRec.fcbFlags bits - */ - -enum { - fcbWriteBit = 0, /* Data can be written to this file */ - fcbWriteMask = 0x01, - fcbResourceBit = 1, /* This file is a resource fork */ - fcbResourceMask = 0x02, - fcbWriteLockedBit = 2, /* File has a locked byte range */ - fcbWriteLockedMask = 0x04, - fcbSharedWriteBit = 4, /* File is open for shared write access */ - fcbSharedWriteMask = 0x10, - fcbFileLockedBit = 5, /* File is locked (write-protected) */ - fcbFileLockedMask = 0x20, - fcbOwnClumpBit = 6, /* File has clump size specified in FCB */ - fcbOwnClumpMask = 0x40, - fcbModifiedBit = 7, /* File has changed since it was last flushed */ - fcbModifiedMask = 0x80 -}; - - -/* - File: TextCommon.h - -*/ - -/* LocaleIdentifier is an obsolete Copland typedef, will be removed soon*/ -typedef UInt32 LocaleIdentifier; -/* TextEncodingBase type & values */ -/* (values 0-32 correspond to the Script Codes defined in Inside Macintosh: Text pages 6-52 and 6-53 */ -typedef UInt32 TextEncodingBase; - -enum { - /* Mac OS encodings*/ + /* Mac OS encodings*/ kTextEncodingMacRoman = 0L, kTextEncodingMacJapanese = 1, kTextEncodingMacChineseTrad = 2, @@ -1040,7 +269,7 @@ enum { kTextEncodingMacEthiopic = 28, kTextEncodingMacCentralEurRoman = 29, kTextEncodingMacVietnamese = 30, - kTextEncodingMacExtArabic = 31, /* The following use script code 0, smRoman*/ + kTextEncodingMacExtArabic = 31, /* The following use script code 0, smRoman*/ kTextEncodingMacSymbol = 33, kTextEncodingMacDingbats = 34, kTextEncodingMacTurkish = 35, @@ -1048,523 +277,11 @@ enum { kTextEncodingMacIcelandic = 37, kTextEncodingMacRomanian = 38, kTextEncodingMacUnicode = 0x7E, - /* The following use script code 4, smArabic */ - kTextEncodingMacFarsi = 0x8C, /* Like MacArabic but uses Farsi digits */ - /* The following use script code 7, smCyrillic */ - kTextEncodingMacUkrainian = 0x98, /* The following use script code 32, smUnimplemented */ - kTextEncodingMacVT100 = 0xFC, /* VT100/102 font from Comm Toolbox: Latin-1 repertoire + box drawing etc*/ - /* Special Mac OS encodings*/ - kTextEncodingMacHFS = 0xFF, /* Meta-value, should never appear in a table.*/ - /* Unicode & ISO UCS encodings begin at 0x100*/ - kTextEncodingUnicodeDefault = 0x0100, /* Meta-value, should never appear in a table.*/ - kTextEncodingUnicodeV1_1 = 0x0101, - kTextEncodingISO10646_1993 = 0x0101, /* Code points identical to Unicode 1.1*/ - kTextEncodingUnicodeV2_0 = 0x0103, /* New location for Korean Hangul*/ - /* ISO 8-bit and 7-bit encodings begin at 0x200*/ - kTextEncodingISOLatin1 = 0x0201, /* ISO 8859-1*/ - kTextEncodingISOLatin2 = 0x0202, /* ISO 8859-2*/ - kTextEncodingISOLatinCyrillic = 0x0205, /* ISO 8859-5*/ - kTextEncodingISOLatinArabic = 0x0206, /* ISO 8859-6, = ASMO 708, =DOS CP 708*/ - kTextEncodingISOLatinGreek = 0x0207, /* ISO 8859-7*/ - kTextEncodingISOLatinHebrew = 0x0208, /* ISO 8859-8*/ - kTextEncodingISOLatin5 = 0x0209, /* ISO 8859-9*/ - /* MS-DOS & Windows encodings begin at 0x400*/ - kTextEncodingDOSLatinUS = 0x0400, /* code page 437*/ - kTextEncodingDOSGreek = 0x0405, /* code page 737 (formerly code page 437G)*/ - kTextEncodingDOSBalticRim = 0x0406, /* code page 775*/ - kTextEncodingDOSLatin1 = 0x0410, /* code page 850, "Multilingual"*/ - kTextEncodingDOSGreek1 = 0x0411, /* code page 851*/ - kTextEncodingDOSLatin2 = 0x0412, /* code page 852, Slavic*/ - kTextEncodingDOSCyrillic = 0x0413, /* code page 855, IBM Cyrillic*/ - kTextEncodingDOSTurkish = 0x0414, /* code page 857, IBM Turkish*/ - kTextEncodingDOSPortuguese = 0x0415, /* code page 860*/ - kTextEncodingDOSIcelandic = 0x0416, /* code page 861*/ - kTextEncodingDOSHebrew = 0x0417, /* code page 862*/ - kTextEncodingDOSCanadianFrench = 0x0418, /* code page 863*/ - kTextEncodingDOSArabic = 0x0419, /* code page 864*/ - kTextEncodingDOSNordic = 0x041A, /* code page 865*/ - kTextEncodingDOSRussian = 0x041B, /* code page 866*/ - kTextEncodingDOSGreek2 = 0x041C, /* code page 869, IBM Modern Greek*/ - kTextEncodingDOSThai = 0x041D, /* code page 874, also for Windows*/ - kTextEncodingDOSJapanese = 0x0420, /* code page 932, also for Windows*/ - kTextEncodingDOSChineseSimplif = 0x0421, /* code page 936, also for Windows*/ - kTextEncodingDOSKorean = 0x0422, /* code page 949, also for Windows; Unified Hangul Code*/ - kTextEncodingDOSChineseTrad = 0x0423, /* code page 950, also for Windows*/ - kTextEncodingWindowsLatin1 = 0x0500, /* code page 1252*/ - kTextEncodingWindowsANSI = 0x0500, /* code page 1252 (alternate name)*/ - kTextEncodingWindowsLatin2 = 0x0501, /* code page 1250, Central Europe*/ - kTextEncodingWindowsCyrillic = 0x0502, /* code page 1251, Slavic Cyrillic*/ - kTextEncodingWindowsGreek = 0x0503, /* code page 1253*/ - kTextEncodingWindowsLatin5 = 0x0504, /* code page 1254, Turkish*/ - kTextEncodingWindowsHebrew = 0x0505, /* code page 1255*/ - kTextEncodingWindowsArabic = 0x0506, /* code page 1256*/ - kTextEncodingWindowsBalticRim = 0x0507, /* code page 1257*/ - kTextEncodingWindowsKoreanJohab = 0x0510, /* code page 1361, for Windows NT*/ - /* Various national standards begin at 0x600*/ - kTextEncodingUS_ASCII = 0x0600, - kTextEncodingJIS_X0201_76 = 0x0620, - kTextEncodingJIS_X0208_83 = 0x0621, - kTextEncodingJIS_X0208_90 = 0x0622, - kTextEncodingJIS_X0212_90 = 0x0623, - kTextEncodingJIS_C6226_78 = 0x0624, - kTextEncodingGB_2312_80 = 0x0630, - kTextEncodingGBK_95 = 0x0631, /* annex to GB 13000-93; for Windows 95*/ - kTextEncodingKSC_5601_87 = 0x0640, /* same as KSC 5601-92 without Johab annex*/ - kTextEncodingKSC_5601_92_Johab = 0x0641, /* KSC 5601-92 Johab annex*/ - kTextEncodingCNS_11643_92_P1 = 0x0651, /* CNS 11643-1992 plane 1*/ - kTextEncodingCNS_11643_92_P2 = 0x0652, /* CNS 11643-1992 plane 2*/ - kTextEncodingCNS_11643_92_P3 = 0x0653, /* CNS 11643-1992 plane 3 (was plane 14 in 1986 version)*/ - /* ISO 2022 collections begin at 0x800*/ - kTextEncodingISO_2022_JP = 0x0820, - kTextEncodingISO_2022_JP_2 = 0x0821, - kTextEncodingISO_2022_CN = 0x0830, - kTextEncodingISO_2022_CN_EXT = 0x0831, - kTextEncodingISO_2022_KR = 0x0840, /* EUC collections begin at 0x900*/ - kTextEncodingEUC_JP = 0x0920, /* ISO 646, 1-byte katakana, JIS 208, JIS 212*/ - kTextEncodingEUC_CN = 0x0930, /* ISO 646, GB 2312-80*/ - kTextEncodingEUC_TW = 0x0931, /* ISO 646, CNS 11643-1992 Planes 1-16*/ - kTextEncodingEUC_KR = 0x0940, /* ISO 646, KS C 5601-1987*/ - /* Misc standards begin at 0xA00*/ - kTextEncodingShiftJIS = 0x0A01, /* plain Shift-JIS*/ - kTextEncodingKOI8_R = 0x0A02, /* Russian internet standard*/ - kTextEncodingBig5 = 0x0A03, /* Big-5 (has variants)*/ - kTextEncodingMacRomanLatin1 = 0x0A04, /* Mac OS Roman permuted to align with ISO Latin-1*/ - kTextEncodingHZ_GB_2312 = 0x0A05, /* HZ (RFC 1842, for Chinese mail & news)*/ - /* Other platform encodings*/ - kTextEncodingNextStepLatin = 0x0B01, /* NextStep encoding*/ - /* EBCDIC & IBM host encodings begin at 0xC00*/ - kTextEncodingEBCDIC_US = 0x0C01, /* basic EBCDIC-US*/ - kTextEncodingEBCDIC_CP037 = 0x0C02, /* code page 037, extended EBCDIC (Latin-1 set) for US,Canada...*/ - /* Special value*/ - kTextEncodingMultiRun = 0x0FFF, /* Multi-encoding text with external run info*/ - /* The following are older names for backward compatibility*/ - kTextEncodingMacTradChinese = 2, - kTextEncodingMacRSymbol = 8, - kTextEncodingMacSimpChinese = 25, - kTextEncodingMacGeez = 28, - kTextEncodingMacEastEurRoman = 29, - kTextEncodingMacUninterp = 32 -}; - -/* TextEncodingVariant type & values */ -typedef UInt32 TextEncodingVariant; - -enum { - /* Default TextEncodingVariant, for any TextEncodingBase*/ - kTextEncodingDefaultVariant = 0, /* Variants of kTextEncodingMacIcelandic */ - kMacIcelandicStandardVariant = 0, /* 0xBB & 0xBC are fem./masc. ordinal indicators*/ - kMacIcelandicTrueTypeVariant = 1, /* 0xBB & 0xBC are fi/fl ligatures*/ - /* Variants of kTextEncodingMacJapanese*/ - kMacJapaneseStandardVariant = 0, - kMacJapaneseStdNoVerticalsVariant = 1, - kMacJapaneseBasicVariant = 2, - kMacJapanesePostScriptScrnVariant = 3, - kMacJapanesePostScriptPrintVariant = 4, - kMacJapaneseVertAtKuPlusTenVariant = 5, /* Variant options for most Japanese encodings (MacJapanese, ShiftJIS, EUC-JP, ISO 2022-JP) */ - /* These can be OR-ed into the variant value in any combination*/ - kJapaneseNoOneByteKanaOption = 0x20, - kJapaneseUseAsciiBackslashOption = 0x40, /* Variants of kTextEncodingMacArabic*/ - kMacArabicStandardVariant = 0, /* 0xC0 is 8-spoke asterisk, 0x2A & 0xAA are asterisk (e.g. Cairo)*/ - kMacArabicTrueTypeVariant = 1, /* 0xC0 is asterisk, 0x2A & 0xAA are multiply signs (e.g. Baghdad)*/ - kMacArabicThuluthVariant = 2, /* 0xC0 is Arabic five-point star, 0x2A & 0xAA are multiply signs*/ - kMacArabicAlBayanVariant = 3, /* 8-spoke asterisk, multiply sign, Koranic ligatures & parens*/ - /* Variants of kTextEncodingMacFarsi*/ - kMacFarsiStandardVariant = 0, /* 0xC0 is 8-spoke asterisk, 0x2A & 0xAA are asterisk (e.g. Tehran)*/ - kMacFarsiTrueTypeVariant = 1, /* asterisk, multiply signs, Koranic ligatures, geometric shapes*/ - /* Variants of kTextEncodingMacHebrew*/ - kMacHebrewStandardVariant = 0, - kMacHebrewFigureSpaceVariant = 1, /* Variants of Unicode & ISO 10646 encodings*/ - kUnicodeNoSubset = 0, - kUnicodeNoCompatibilityVariant = 1, - kUnicodeMaxDecomposedVariant = 2, - kUnicodeNoComposedVariant = 3, - kUnicodeNoCorporateVariant = 4, /* Variants of Big-5 encoding*/ - kBig5_BasicVariant = 0, - kBig5_StandardVariant = 1, /* 0xC6A1-0xC7FC: kana, Cyrillic, enclosed numerics*/ - kBig5_ETenVariant = 2, /* adds kana, Cyrillic, radicals, etc with hi bytes C6-C8,F9*/ - /* The following are older names for backward compatibility*/ - kJapaneseStandardVariant = 0, - kJapaneseStdNoVerticalsVariant = 1, - kJapaneseBasicVariant = 2, - kJapanesePostScriptScrnVariant = 3, - kJapanesePostScriptPrintVariant = 4, - kJapaneseVertAtKuPlusTenVariant = 5, /* kJapaneseStdNoOneByteKanaVariant = 6, // replaced by kJapaneseNoOneByteKanaOption*/ - /* kJapaneseBasicNoOneByteKanaVariant = 7, // replaced by kJapaneseNoOneByteKanaOption */ - kHebrewStandardVariant = 0, - kHebrewFigureSpaceVariant = 1 -}; - -/* TextEncodingFormat type & values */ -typedef UInt32 TextEncodingFormat; - -enum { - /* Default TextEncodingFormat for any TextEncodingBase*/ - kTextEncodingDefaultFormat = 0, /* Formats for Unicode & ISO 10646*/ - kUnicode16BitFormat = 0, - kUnicodeUTF7Format = 1, - kUnicodeUTF8Format = 2, - kUnicode32BitFormat = 3 -}; - -/* TextEncoding type */ -typedef UInt32 TextEncoding; -/* name part selector for GetTextEncodingName*/ -typedef UInt32 TextEncodingNameSelector; - -enum { - kTextEncodingFullName = 0, - kTextEncodingBaseName = 1, - kTextEncodingVariantName = 2, - kTextEncodingFormatName = 3 -}; - -/* Types used in conversion */ -struct TextEncodingRun { - ByteOffset offset; - TextEncoding textEncoding; -}; -typedef struct TextEncodingRun TextEncodingRun; - -typedef TextEncodingRun * TextEncodingRunPtr; -typedef const TextEncodingRun * ConstTextEncodingRunPtr; -struct ScriptCodeRun { - ByteOffset offset; - ScriptCode script; -}; -typedef struct ScriptCodeRun ScriptCodeRun; - -typedef ScriptCodeRun * ScriptCodeRunPtr; -typedef const ScriptCodeRun * ConstScriptCodeRunPtr; -typedef UInt8 * TextPtr; -typedef const UInt8 * ConstTextPtr; -/* Basic types for Unicode characters and strings: */ -typedef UniChar * UniCharArrayPtr; -typedef const UniChar * ConstUniCharArrayPtr; -/* enums for TextEncoding Conversion routines*/ - -enum { - kTextScriptDontCare = -128, - kTextLanguageDontCare = -128, - kTextRegionDontCare = -128 -}; - - - -/* - File: UnicodeConverter.h - - -*/ - -/* Unicode conversion contexts: */ -typedef struct OpaqueTextToUnicodeInfo* TextToUnicodeInfo; -typedef struct OpaqueUnicodeToTextInfo* UnicodeToTextInfo; -typedef struct OpaqueUnicodeToTextRunInfo* UnicodeToTextRunInfo; -typedef const TextToUnicodeInfo ConstTextToUnicodeInfo; -typedef const UnicodeToTextInfo ConstUnicodeToTextInfo; -/* UnicodeMapVersion type & values */ -typedef SInt32 UnicodeMapVersion; - -enum { - kUnicodeUseLatestMapping = -1, - kUnicodeUseHFSPlusMapping = 4 -}; - -/* Types used in conversion */ -struct UnicodeMapping { - TextEncoding unicodeEncoding; - TextEncoding otherEncoding; - UnicodeMapVersion mappingVersion; -}; -typedef struct UnicodeMapping UnicodeMapping; - -typedef UnicodeMapping * UnicodeMappingPtr; -typedef const UnicodeMapping * ConstUnicodeMappingPtr; -/* Control flags for ConvertFromUnicodeToText and ConvertFromTextToUnicode */ - -enum { - kUnicodeUseFallbacksBit = 0, - kUnicodeKeepInfoBit = 1, - kUnicodeDirectionalityBits = 2, - kUnicodeVerticalFormBit = 4, - kUnicodeLooseMappingsBit = 5, - kUnicodeStringUnterminatedBit = 6, - kUnicodeTextRunBit = 7, - kUnicodeKeepSameEncodingBit = 8 -}; - - -enum { - kUnicodeUseFallbacksMask = 1L << kUnicodeUseFallbacksBit, - kUnicodeKeepInfoMask = 1L << kUnicodeKeepInfoBit, - kUnicodeDirectionalityMask = 3L << kUnicodeDirectionalityBits, - kUnicodeVerticalFormMask = 1L << kUnicodeVerticalFormBit, - kUnicodeLooseMappingsMask = 1L << kUnicodeLooseMappingsBit, - kUnicodeStringUnterminatedMask = 1L << kUnicodeStringUnterminatedBit, - kUnicodeTextRunMask = 1L << kUnicodeTextRunBit, - kUnicodeKeepSameEncodingMask = 1L << kUnicodeKeepSameEncodingBit -}; - -/* Values for kUnicodeDirectionality field */ - -enum { - kUnicodeDefaultDirection = 0, - kUnicodeLeftToRight = 1, - kUnicodeRightToLeft = 2 -}; - -/* Directionality masks for control flags */ - -enum { - kUnicodeDefaultDirectionMask = kUnicodeDefaultDirection << kUnicodeDirectionalityBits, - kUnicodeLeftToRightMask = kUnicodeLeftToRight << kUnicodeDirectionalityBits, - kUnicodeRightToLeftMask = kUnicodeRightToLeft << kUnicodeDirectionalityBits -}; - -/* Control flags for TruncateForUnicodeToText: */ -/* - Now TruncateForUnicodeToText uses control flags from the same set as used by - ConvertFromTextToUnicode, ConvertFromUnicodeToText, etc., but only - kUnicodeStringUnterminatedMask is meaningful for TruncateForUnicodeToText. - - Previously two special control flags were defined for TruncateForUnicodeToText: - kUnicodeTextElementSafeBit = 0 - kUnicodeRestartSafeBit = 1 - However, neither of these was implemented. - Instead of implementing kUnicodeTextElementSafeBit, we now use - kUnicodeStringUnterminatedMask since it accomplishes the same thing and avoids - having special flags just for TruncateForUnicodeToText - Also, kUnicodeRestartSafeBit is unnecessary, since restart-safeness is handled by - setting kUnicodeKeepInfoBit with ConvertFromUnicodeToText. - If TruncateForUnicodeToText is called with one or both of the old special control - flags set (bits 0 or 1), it will not generate a paramErr, but the old bits have no - effect on its operation. -*/ - -/* Filter bits for filter field in QueryUnicodeMappings and CountUnicodeMappings: */ - -enum { - kUnicodeMatchUnicodeBaseBit = 0, - kUnicodeMatchUnicodeVariantBit = 1, - kUnicodeMatchUnicodeFormatBit = 2, - kUnicodeMatchOtherBaseBit = 3, - kUnicodeMatchOtherVariantBit = 4, - kUnicodeMatchOtherFormatBit = 5 -}; - - -enum { - kUnicodeMatchUnicodeBaseMask = 1L << kUnicodeMatchUnicodeBaseBit, - kUnicodeMatchUnicodeVariantMask = 1L << kUnicodeMatchUnicodeVariantBit, - kUnicodeMatchUnicodeFormatMask = 1L << kUnicodeMatchUnicodeFormatBit, - kUnicodeMatchOtherBaseMask = 1L << kUnicodeMatchOtherBaseBit, - kUnicodeMatchOtherVariantMask = 1L << kUnicodeMatchOtherVariantBit, - kUnicodeMatchOtherFormatMask = 1L << kUnicodeMatchOtherFormatBit -}; - -/* Control flags for SetFallbackUnicodeToText */ - -enum { - kUnicodeFallbackSequencingBits = 0 -}; - - -enum { - kUnicodeFallbackSequencingMask = 3L << kUnicodeFallbackSequencingBits -}; - -/* values for kUnicodeFallbackSequencing field */ - -enum { - kUnicodeFallbackDefaultOnly = 0L, - kUnicodeFallbackCustomOnly = 1L, - kUnicodeFallbackDefaultFirst = 2L, - kUnicodeFallbackCustomFirst = 3L -}; - - -/* - File: Timer.h - - -*/ - - -enum { - /* high bit of qType is set if task is active */ - kTMTaskActive = (1L << 15) -}; - -typedef struct TMTask TMTask; -typedef TMTask * TMTaskPtr; -typedef CALLBACK_API( void , TimerProcPtr )(TMTaskPtr tmTaskPtr); -/* - WARNING: TimerProcPtr uses register based parameters under classic 68k - and cannot be written in a high-level language without - the help of mixed mode or assembly glue. -*/ -typedef REGISTER_UPP_TYPE(TimerProcPtr) TimerUPP; -struct TMTask { - QElemPtr qLink; - short qType; - TimerUPP tmAddr; - long tmCount; - long tmWakeUp; - long tmReserved; -}; - - -/* - File: TextCommonPriv.h - - -*/ - - -/* - ----------------------------------------------------------------------------------------------------------- - TextEncoding creation & extraction macros. - Current packed format: - 31 30 29 26 25 16 15 0 - |pack| format | variant | base | - |vers| | | | - |2bit| 4 bits | 10 bits | 16 bits | - Unpacked elements - base 15 0 - | 0 | 16 bits | - variant 9 0 - | 0 | 10 bits | - format 3 0 - | 0 | 4 bits | - ----------------------------------------------------------------------------------------------------------- -*/ - -enum { - kTextEncodingVersion = 0 -}; - - -enum { - kTextEncodingBaseShiftBits = 0, /* <13>*/ - kTextEncodingVariantShiftBits = 16, /* <13>*/ - kTextEncodingFormatShiftBits = 26, /* <13><16>*/ - kTextEncodingVersionShiftBits = 30 -}; - - - -enum { - kTextEncodingBaseSourceMask = 0x0000FFFF, /* 16 bits <13>*/ - kTextEncodingVariantSourceMask = 0x000003FF, /* 10 bits <13><16>*/ - kTextEncodingFormatSourceMask = 0x0000000F, /* 4 bits <13><16>*/ - kTextEncodingVersionSourceMask = 0x00000003 /* 2 bits*/ -}; - - -enum { - kTextEncodingBaseMask = kTextEncodingBaseSourceMask << kTextEncodingBaseShiftBits, - kTextEncodingVariantMask = kTextEncodingVariantSourceMask << kTextEncodingVariantShiftBits, - kTextEncodingFormatMask = kTextEncodingFormatSourceMask << kTextEncodingFormatShiftBits, - kTextEncodingVersionMask = kTextEncodingVersionSourceMask << kTextEncodingVersionShiftBits -}; - - -enum { - kTextEncodingVersionShifted = (kTextEncodingVersion & kTextEncodingVersionSourceMask) << kTextEncodingVersionShiftBits -}; - - -#define CreateTextEncodingPriv(base,variant,format) \ - ( ((base & kTextEncodingBaseSourceMask) << kTextEncodingBaseShiftBits) \ - | ((variant & kTextEncodingVariantSourceMask) << kTextEncodingVariantShiftBits) \ - | ((format & kTextEncodingFormatSourceMask) << kTextEncodingFormatShiftBits) \ - | (kTextEncodingVersionShifted) ) -#define GetTextEncodingBasePriv(encoding) \ - ((encoding & kTextEncodingBaseMask) >> kTextEncodingBaseShiftBits) -#define GetTextEncodingVariantPriv(encoding) \ - ((encoding & kTextEncodingVariantMask) >> kTextEncodingVariantShiftBits) -#define GetTextEncodingFormatPriv(encoding) \ - ((encoding & kTextEncodingFormatMask) >> kTextEncodingFormatShiftBits) -#define IsMacTextEncoding(encoding) ((encoding & 0x0000FF00L) == 0x00000000L) -#define IsUnicodeTextEncoding(encoding) ((encoding & 0x0000FF00L) == 0x00000100L) -/* TextEncoding used by HFS*/ - -enum { - kMacHFSTextEncoding = 0x000000FF -}; - - -/* - File: Instrumentation.h - - -*/ -/*******************************************************************/ -/* Types */ -/*******************************************************************/ -/* Reference to an instrumentation class */ -typedef struct InstOpaqueClassRef* InstClassRef; - -/* Aliases to the generic instrumentation class for each type of class */ -typedef InstClassRef InstPathClassRef; -typedef InstClassRef InstTraceClassRef; -typedef InstClassRef InstHistogramClassRef; -typedef InstClassRef InstSplitHistogramClassRef; -typedef InstClassRef InstMagnitudeClassRef; -typedef InstClassRef InstGrowthClassRef; -typedef InstClassRef InstTallyClassRef; - -/* Reference to a data descriptor */ -typedef struct InstOpaqueDataDescriptorRef* InstDataDescriptorRef; - - -/*******************************************************************/ -/* Constant Definitions */ -/*******************************************************************/ - -/* Reference to the root of the class hierarchy */ -#define kInstRootClassRef ( (InstClassRef) -1) - -/* Options used for creating classes */ -typedef OptionBits InstClassOptions; - - -enum { - kInstDisableClassMask = 0x00, /* Create the class disabled */ - kInstEnableClassMask = 0x01, /* Create the class enabled */ - - kInstSummaryTraceClassMask = 0x20 /* Create a summary trace class instead of a regular one */ + kTextEncodingMacFarsi = 0x8C, /* Like MacArabic but uses Farsi digits */ /* The following use script code 7, smCyrillic */ + kTextEncodingMacUkrainian = 0x98, /* The following use script code 32, smUnimplemented */ }; - - -EXTERN_API( Boolean ) -EqualString (ConstStr255Param str1, - ConstStr255Param str2, - Boolean caseSensitive, - Boolean diacSensitive); - - - - -/* - File: LowMemPriv.h - - -*/ - - -EXTERN_API( void ) -InsTime (QElemPtr tmTaskPtr); -EXTERN_API( void ) -PrimeTime (QElemPtr tmTaskPtr, - long count); -EXTERN_API( void ) -RmvTime (QElemPtr tmTaskPtr); - - - /* PROTOTYPES */ @@ -1577,72 +294,25 @@ RmvTime (QElemPtr tmTaskPtr); EXTERN_API( void ) -BlockMove (const void * srcPtr, - void * destPtr, - Size byteCount); -EXTERN_API( void ) -BlockMoveData (const void * srcPtr, - void * destPtr, - Size byteCount); +BlockMoveData(const void * srcPtr, void * destPtr, Size byteCount); -EXTERN_API_C( void ) -BlockMoveUncached (const void * srcPtr, - void * destPtr, - Size byteCount); +#define BlockMoveData(src, dest, len) bcopy((src), (dest), (len)) EXTERN_API_C( void ) -BlockMoveDataUncached (const void * srcPtr, - void * destPtr, - Size byteCount); +ClearMemory(void * start, UInt32 length); -EXTERN_API_C( void ) -BlockZero (void * destPtr, - Size byteCount); +#define ClearMemory(start, length) bzero((start), (size_t)(length)); -EXTERN_API_C( void ) -BlockZeroUncached (void * destPtr, - Size byteCount); EXTERN_API( Ptr ) -NewPtr (Size byteCount); +NewPtr(Size byteCount); EXTERN_API( Ptr ) -NewPtrSys (Size byteCount); - -EXTERN_API( Ptr ) -NewPtrClear (Size byteCount); - -EXTERN_API( Ptr ) -NewPtrSysClear (Size byteCount); - -EXTERN_API( OSErr ) -MemError (void); +NewPtrSysClear(Size byteCount); EXTERN_API( void ) -DisposePtr (Ptr p); - -EXTERN_API( Size ) -GetPtrSize (Ptr p); - -EXTERN_API( void ) -SetPtrSize (Ptr p, - Size newSize); - -EXTERN_API( void ) -DisposeHandle (Handle h); - -EXTERN_API( void ) -SetHandleSize (Handle h, - Size newSize); - -/* - File: DateTimeUtils.h - - -*/ -EXTERN_API( void ) -GetDateTime (unsigned long * secs); - - +DisposePtr(Ptr p); -#endif /* __hfs_macos_types__ */ +#endif /* __APPLE_API_PRIVATE */ +#endif /* KERNEL */ +#endif /* __HFS_MACOS_TYPES__ */ diff --git a/bsd/hfs/hfs_mount.h b/bsd/hfs/hfs_mount.h index b7c191ecb..06afe6df8 100644 --- a/bsd/hfs/hfs_mount.h +++ b/bsd/hfs/hfs_mount.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -20,13 +20,15 @@ * @APPLE_LICENSE_HEADER_END@ */ /* - * Copyright (c) 1997-2000 Apple Computer, Inc. All Rights Reserved + * Copyright (c) 1997-2002 Apple Computer, Inc. All Rights Reserved * */ #ifndef _HFS_MOUNT_H_ #define _HFS_MOUNT_H_ +#include + #include #include @@ -40,6 +42,7 @@ #define UNKNOWNGID ((gid_t)99) #define UNKNOWNPERMISSIONS (S_IRWXU | S_IROTH | S_IXOTH) /* 705 */ +#ifdef __APPLE_API_UNSTABLE struct hfs_mount_args { char *fspec; /* block special device to mount */ struct export_args export; /* network export information */ @@ -52,5 +55,7 @@ struct hfs_mount_args { }; #define HFSFSMNT_NOXONFILES 0x1 /* disable execute permissions for files */ +#define HFSFSMNT_WRAPPER 0x2 /* mount HFS wrapper (if it exists) */ +#endif /* __APPLE_API_UNSTABLE */ #endif /* ! _HFS_MOUNT_H_ */ diff --git a/bsd/hfs/hfs_quota.c b/bsd/hfs/hfs_quota.c new file mode 100644 index 000000000..61b0b83cd --- /dev/null +++ b/bsd/hfs/hfs_quota.c @@ -0,0 +1,730 @@ +/* + * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Copyright (c) 1982, 1986, 1990, 1993, 1995 + * The 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. + * + * @(#)hfs_quota.c + * derived from @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * Quota name to error message mapping. + */ +static char *quotatypes[] = INITQFNAMES; + +/* + * Set up the quotas for a cnode. + * + * 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. + */ +int +hfs_getinoquota(cp) + register struct cnode *cp; +{ + struct hfsmount *hfsmp; + struct vnode *vp; + int error; + + vp = cp->c_vp ? cp->c_vp : cp->c_rsrc_vp; + hfsmp = VFSTOHFS(vp->v_mount); + /* + * Set up the user quota based on file uid. + * EINVAL means that quotas are not enabled. + */ + if (cp->c_dquot[USRQUOTA] == NODQUOT && + (error = + dqget(vp, cp->c_uid, &hfsmp->hfs_qfiles[USRQUOTA], USRQUOTA, &cp->c_dquot[USRQUOTA])) && + error != EINVAL) + return (error); + /* + * Set up the group quota based on file gid. + * EINVAL means that quotas are not enabled. + */ + if (cp->c_dquot[GRPQUOTA] == NODQUOT && + (error = + dqget(vp, cp->c_gid, &hfsmp->hfs_qfiles[GRPQUOTA], GRPQUOTA, &cp->c_dquot[GRPQUOTA])) && + error != EINVAL) + return (error); + return (0); +} + +/* + * Update disk usage, and take corrective action. + */ +int +hfs_chkdq(cp, change, cred, flags) + register struct cnode *cp; + int64_t change; + struct ucred *cred; + int flags; +{ + register struct dquot *dq; + register int i; + int64_t ncurbytes; + int error; + struct proc *p; + +#if DIAGNOSTIC + if ((flags & CHOWN) == 0) + hfs_chkdquot(cp); +#endif + if (change == 0) + return (0); + if (change < 0) { + for (i = 0; i < MAXQUOTAS; i++) { + if ((dq = cp->c_dquot[i]) == NODQUOT) + continue; + while (dq->dq_flags & DQ_LOCK) { + dq->dq_flags |= DQ_WANT; + sleep((caddr_t)dq, PINOD+1); + } + ncurbytes = dq->dq_curbytes + change; + if (ncurbytes >= 0) + dq->dq_curbytes = ncurbytes; + else + dq->dq_curbytes = 0; + dq->dq_flags &= ~DQ_BLKS; + dq->dq_flags |= DQ_MOD; + } + return (0); + } + p = current_proc(); + if (cred == NOCRED) + cred = kernproc->p_ucred; + if ((flags & FORCE) == 0 && ((cred->cr_uid != 0) || (p->p_flag & P_FORCEQUOTA))) { + for (i = 0; i < MAXQUOTAS; i++) { + if ((dq = cp->c_dquot[i]) == NODQUOT) + continue; + if (error = hfs_chkdqchg(cp, change, cred, i)) + return (error); + } + } + for (i = 0; i < MAXQUOTAS; i++) { + if ((dq = cp->c_dquot[i]) == NODQUOT) + continue; + while (dq->dq_flags & DQ_LOCK) { + dq->dq_flags |= DQ_WANT; + sleep((caddr_t)dq, PINOD+1); + } + dq->dq_curbytes += change; + dq->dq_flags |= DQ_MOD; + } + return (0); +} + +/* + * Check for a valid change to a users allocation. + * Issue an error message if appropriate. + */ +int +hfs_chkdqchg(cp, change, cred, type) + struct cnode *cp; + int64_t change; + struct ucred *cred; + int type; +{ + register struct dquot *dq = cp->c_dquot[type]; + u_int64_t ncurbytes = dq->dq_curbytes + change; + struct vnode *vp = cp->c_vp ? cp->c_vp : cp->c_rsrc_vp; + + /* + * If user would exceed their hard limit, disallow space allocation. + */ + if (ncurbytes >= dq->dq_bhardlimit && dq->dq_bhardlimit) { + if ((dq->dq_flags & DQ_BLKS) == 0 && + cp->c_uid == cred->cr_uid) { +#if 1 + printf("\n%s: write failed, %s disk limit reached\n", + vp->v_mount->mnt_stat.f_mntonname, + quotatypes[type]); +#endif + 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 (ncurbytes >= dq->dq_bsoftlimit && dq->dq_bsoftlimit) { + if (dq->dq_curbytes < dq->dq_bsoftlimit) { + dq->dq_btime = time.tv_sec + + VFSTOHFS(vp->v_mount)->hfs_qfiles[type].qf_btime; +#if 1 + if (cp->c_uid == cred->cr_uid) + printf("\n%s: warning, %s %s\n", + vp->v_mount->mnt_stat.f_mntonname, + quotatypes[type], "disk quota exceeded"); +#endif + return (0); + } + if (time.tv_sec > dq->dq_btime) { + if ((dq->dq_flags & DQ_BLKS) == 0 && + cp->c_uid == cred->cr_uid) { +#if 1 + printf("\n%s: write failed, %s %s\n", + vp->v_mount->mnt_stat.f_mntonname, + quotatypes[type], + "disk quota exceeded for too long"); +#endif + dq->dq_flags |= DQ_BLKS; + } + return (EDQUOT); + } + } + return (0); +} + +/* + * Check the inode limit, applying corrective action. + */ +int +hfs_chkiq(cp, change, cred, flags) + register struct cnode *cp; + long change; + struct ucred *cred; + int flags; +{ + register struct dquot *dq; + register int i; + int ncurinodes, error; + struct proc *p; + +#if DIAGNOSTIC + if ((flags & CHOWN) == 0) + hfs_chkdquot(cp); +#endif + if (change == 0) + return (0); + if (change < 0) { + for (i = 0; i < MAXQUOTAS; i++) { + if ((dq = cp->c_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); + } + p = current_proc(); + if (cred == NOCRED) + cred = kernproc->p_ucred; + if ((flags & FORCE) == 0 && ((cred->cr_uid != 0) || (p->p_flag & P_FORCEQUOTA))) { + for (i = 0; i < MAXQUOTAS; i++) { + if ((dq = cp->c_dquot[i]) == NODQUOT) + continue; + if (error = hfs_chkiqchg(cp, change, cred, i)) + return (error); + } + } + for (i = 0; i < MAXQUOTAS; i++) { + if ((dq = cp->c_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. + */ +int +hfs_chkiqchg(cp, change, cred, type) + struct cnode *cp; + long change; + struct ucred *cred; + int type; +{ + register struct dquot *dq = cp->c_dquot[type]; + long ncurinodes = dq->dq_curinodes + change; + struct vnode *vp = cp->c_vp ? cp->c_vp : cp->c_rsrc_vp; + + /* + * If user would exceed their hard limit, disallow cnode allocation. + */ + if (ncurinodes >= dq->dq_ihardlimit && dq->dq_ihardlimit) { + if ((dq->dq_flags & DQ_INODS) == 0 && + cp->c_uid == cred->cr_uid) { +#if 1 + printf("\n%s: write failed, %s cnode limit reached\n", + vp->v_mount->mnt_stat.f_mntonname, + quotatypes[type]); +#endif + dq->dq_flags |= DQ_INODS; + } + return (EDQUOT); + } + /* + * If user is over their soft limit for too long, disallow cnode + * 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 + + VFSTOHFS(vp->v_mount)->hfs_qfiles[type].qf_itime; +#if 1 + if (cp->c_uid == cred->cr_uid) + printf("\n%s: warning, %s %s\n", + vp->v_mount->mnt_stat.f_mntonname, + quotatypes[type], "cnode quota exceeded"); +#endif + return (0); + } + if (time.tv_sec > dq->dq_itime) { + if ((dq->dq_flags & DQ_INODS) == 0 && + cp->c_uid == cred->cr_uid) { +#if 1 + printf("\n%s: write failed, %s %s\n", + vp->v_mount->mnt_stat.f_mntonname, + quotatypes[type], + "cnode quota exceeded for too long"); +#endif + dq->dq_flags |= DQ_INODS; + } + return (EDQUOT); + } + } + return (0); +} + +#if 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. + */ +void +hfs_chkdquot(cp) + register struct cnode *cp; +{ + struct vnode *vp = cp->c_vp ? cp->c_vp : cp->c_rsrc_vp; + struct hfsmount *hfsmp = VFSTOHFS(vp->v_mount); + register int i; + + for (i = 0; i < MAXQUOTAS; i++) { + if (hfsmp->hfs_qfiles[i].qf_vp == NULLVP || + (hfsmp->hfs_qfiles[i].qf_qflags & (QTF_OPENING|QTF_CLOSING))) + continue; + if (cp->c_dquot[i] == NODQUOT) { + vprint("chkdquot: missing dquot", vp); + panic("missing dquot"); + } + } +} +#endif + +/* + * Code to process quotactl commands. + */ + +/* + * Q_QUOTAON - set up a quota file for a particular file system. + */ +int +hfs_quotaon(p, mp, type, fname, segflg) + struct proc *p; + struct mount *mp; + register int type; + caddr_t fname; + enum uio_seg segflg; +{ + struct hfsmount *hfsmp = VFSTOHFS(mp); + struct vnode *vp, **vpp; + struct vnode *nextvp; + struct dquot *dq; + int error; + struct nameidata nd; + + vpp = &hfsmp->hfs_qfiles[type].qf_vp; + NDINIT(&nd, LOOKUP, FOLLOW, segflg, fname, p); + if (error = vn_open(&nd, FREAD|FWRITE, 0)) + return (error); + vp = nd.ni_vp; + VOP_UNLOCK(vp, 0, p); + if (vp->v_type != VREG) { + (void) vn_close(vp, FREAD|FWRITE, p->p_ucred, p); + return (EACCES); + } + if (*vpp != vp) + hfs_quotaoff(p, mp, type); + hfsmp->hfs_qfiles[type].qf_qflags |= QTF_OPENING; + mp->mnt_flag |= MNT_QUOTA; + vp->v_flag |= VNOFLUSH; + *vpp = vp; + /* + * Save the credential of the process that turned on quotas. + */ + crhold(p->p_ucred); + hfsmp->hfs_qfiles[type].qf_cred = p->p_ucred; + /* Finish initializing the quota file */ + if (error = dqfileopen(&hfsmp->hfs_qfiles[type], type)) + goto exit; + /* + * Search vnodes associated with this mount point, + * adding references to quota file being opened. + * NB: only need to add dquot's for cnodes being modified. + */ +again: + for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nextvp) { + nextvp = vp->v_mntvnodes.le_next; + if (vp->v_writecount == 0) + continue; + if (vget(vp, LK_EXCLUSIVE, p)) + goto again; + if (error = hfs_getinoquota(VTOC(vp))) { + vput(vp); + break; + } + vput(vp); + if (vp->v_mntvnodes.le_next != nextvp || vp->v_mount != mp) + goto again; + } +exit: + hfsmp->hfs_qfiles[type].qf_qflags &= ~QTF_OPENING; + if (error) + hfs_quotaoff(p, mp, type); + return (error); +} + +/* + * Q_QUOTAOFF - turn off disk quotas for a filesystem. + */ +int +hfs_quotaoff(p, mp, type) + struct proc *p; + struct mount *mp; + register int type; +{ + struct vnode *vp; + struct vnode *qvp, *nextvp; + struct hfsmount *hfsmp = VFSTOHFS(mp); + struct dquot *dq; + struct cnode *cp; + int error; + struct ucred *cred; + + if ((qvp = hfsmp->hfs_qfiles[type].qf_vp) == NULLVP) + return (0); + hfsmp->hfs_qfiles[type].qf_qflags |= QTF_CLOSING; + /* + * Search vnodes associated with this mount point, + * deleting any references to quota file being closed. + */ +again: + for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nextvp) { + nextvp = vp->v_mntvnodes.le_next; + if (vget(vp, LK_EXCLUSIVE, p)) + goto again; + cp = VTOC(vp); + dq = cp->c_dquot[type]; + cp->c_dquot[type] = NODQUOT; + dqrele(vp, dq); + vput(vp); + if (vp->v_mntvnodes.le_next != nextvp || vp->v_mount != mp) + goto again; + } + dqflush(qvp); + /* Finish tearing down the quota file */ + dqfileclose(&hfsmp->hfs_qfiles[type], type); + qvp->v_flag &= ~VNOFLUSH; + error = vn_close(qvp, FREAD|FWRITE, p->p_ucred, p); + hfsmp->hfs_qfiles[type].qf_vp = NULLVP; + cred = hfsmp->hfs_qfiles[type].qf_cred; + if (cred != NOCRED) { + hfsmp->hfs_qfiles[type].qf_cred = NOCRED; + crfree(cred); + } + hfsmp->hfs_qfiles[type].qf_qflags &= ~QTF_CLOSING; + for (type = 0; type < MAXQUOTAS; type++) + if (hfsmp->hfs_qfiles[type].qf_vp != NULLVP) + break; + if (type == MAXQUOTAS) + mp->mnt_flag &= ~MNT_QUOTA; + return (error); +} + +/* + * Q_GETQUOTA - return current values in a dqblk structure. + */ +int +hfs_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, &VFSTOHFS(mp)->hfs_qfiles[type], 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. + */ +int +hfs_setquota(mp, id, type, addr) + struct mount *mp; + u_long id; + int type; + caddr_t addr; +{ + register struct dquot *dq; + struct dquot *ndq; + struct hfsmount *hfsmp = VFSTOHFS(mp); + struct dqblk newlim; + int error; + + if (error = copyin(addr, (caddr_t)&newlim, sizeof (struct dqblk))) + return (error); + if (error = dqget(NULLVP, id, &hfsmp->hfs_qfiles[type], 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_curbytes = dq->dq_curbytes; + 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_curbytes >= newlim.dqb_bsoftlimit && + (dq->dq_bsoftlimit == 0 || dq->dq_curbytes < dq->dq_bsoftlimit)) + newlim.dqb_btime = time.tv_sec + hfsmp->hfs_qfiles[type].qf_btime; + 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 + hfsmp->hfs_qfiles[type].qf_itime; + dq->dq_dqb = newlim; + if (dq->dq_curbytes < 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 cnode and byte usage. + */ +int +hfs_setuse(mp, id, type, addr) + struct mount *mp; + u_long id; + int type; + caddr_t addr; +{ + register struct dquot *dq; + struct hfsmount *hfsmp = VFSTOHFS(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, &hfsmp->hfs_qfiles[type], 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_curbytes < dq->dq_bsoftlimit && + usage.dqb_curbytes >= dq->dq_bsoftlimit) + dq->dq_btime = time.tv_sec + hfsmp->hfs_qfiles[type].qf_btime; + if (dq->dq_isoftlimit && dq->dq_curinodes < dq->dq_isoftlimit && + usage.dqb_curinodes >= dq->dq_isoftlimit) + dq->dq_itime = time.tv_sec + hfsmp->hfs_qfiles[type].qf_itime; + dq->dq_curbytes = usage.dqb_curbytes; + dq->dq_curinodes = usage.dqb_curinodes; + if (dq->dq_curbytes < 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. + */ +int +hfs_qsync(mp) + struct mount *mp; +{ + struct hfsmount *hfsmp = VFSTOHFS(mp); + struct proc *p = current_proc(); /* XXX */ + struct vnode *vp, *nextvp; + struct dquot *dq; + int i, error; + + /* + * Check if the mount point has any quotas. + * If not, simply return. + */ + for (i = 0; i < MAXQUOTAS; i++) + if (hfsmp->hfs_qfiles[i].qf_vp != NULLVP) + break; + if (i == MAXQUOTAS) + return (0); + /* + * Search vnodes associated with this mount point, + * synchronizing any modified dquot structures. + */ + simple_lock(&mntvnode_slock); +again: + for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nextvp) { + if (vp->v_mount != mp) + goto again; + nextvp = vp->v_mntvnodes.le_next; + simple_lock(&vp->v_interlock); + simple_unlock(&mntvnode_slock); + error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p); + if (error) { + simple_lock(&mntvnode_slock); + if (error == ENOENT) + goto again; + continue; + } + for (i = 0; i < MAXQUOTAS; i++) { + dq = VTOC(vp)->c_dquot[i]; + if (dq != NODQUOT && (dq->dq_flags & DQ_MOD)) + dqsync(vp, dq); + } + vput(vp); + simple_lock(&mntvnode_slock); + if (vp->v_mntvnodes.le_next != nextvp) + goto again; + } + simple_unlock(&mntvnode_slock); + return (0); +} + +/* + * Q_QUOTASTAT - get quota on/off status + */ +int +hfs_quotastat(mp, type, addr) + struct mount *mp; + register int type; + caddr_t addr; +{ + struct hfsmount *hfsmp = VFSTOHFS(mp); + int error = 0; + int qstat; + + if ((mp->mnt_flag & MNT_QUOTA) && (hfsmp->hfs_qfiles[type].qf_vp != NULLVP)) + qstat = 1; /* quotas are on for this type */ + else + qstat = 0; /* quotas are off for this type */ + + error = copyout ((caddr_t)&qstat, addr, sizeof(qstat)); + return (error); +} + diff --git a/bsd/hfs/hfs_quota.h b/bsd/hfs/hfs_quota.h new file mode 100644 index 000000000..2b4ded302 --- /dev/null +++ b/bsd/hfs/hfs_quota.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Copyright (c) 1982, 1986, 1993 + * The 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. + * + * @(#)hfs_quota.h + * derived from @(#)quota.h 8.3 (Berkeley) 8/19/94 + */ + +#ifndef _HFS_QUOTA_H_ +#define _HFS_QUOTA_H_ + +#include + +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE +#include + +#include + +struct cnode; +struct mount; +struct proc; +struct ucred; +__BEGIN_DECLS +int hfs_chkdq __P((struct cnode *, int64_t, struct ucred *, int)); +int hfs_chkdqchg __P((struct cnode *, int64_t, struct ucred *, int)); +int hfs_chkiq __P((struct cnode *, long, struct ucred *, int)); +int hfs_chkiqchg __P((struct cnode *, long, struct ucred *, int)); +int hfs_getinoquota __P((struct cnode *)); +int hfs_getquota __P((struct mount *, u_long, int, caddr_t)); +int hfs_qsync __P((struct mount *mp)); +int hfs_quotaoff __P((struct proc *, struct mount *, int)); +int hfs_quotaon __P((struct proc *, struct mount *, int, caddr_t, enum uio_seg)); +int hfs_setquota __P((struct mount *, u_long, int, caddr_t)); +int hfs_setuse __P((struct mount *, u_long, int, caddr_t)); +int hfs_quotactl __P((struct mount *, int, uid_t, caddr_t, struct proc *)); +__END_DECLS + +#if DIAGNOSTIC +__BEGIN_DECLS +void hfs_chkdquot __P((struct cnode *)); +__END_DECLS +#endif +#endif /* __APPLE_API_PRIVATE */ +#endif /* KERNEL */ + +#endif /* ! _HFS_QUOTA_H_ */ diff --git a/bsd/hfs/hfs_readwrite.c b/bsd/hfs/hfs_readwrite.c index 825ec1ca5..4544a7685 100644 --- a/bsd/hfs/hfs_readwrite.c +++ b/bsd/hfs/hfs_readwrite.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,36 +21,10 @@ */ /* @(#)hfs_readwrite.c 1.0 * - * (c) 1990, 1992 NeXT Computer, Inc. All Rights Reserved - * (c) 1998 Apple Computer, Inc. All Rights Reserved + * (c) 1998-2001 Apple Computer, Inc. All Rights Reserved * - * * hfs_readwrite.c -- vnode operations to deal with reading and writing files. * - * MODIFICATION HISTORY: - * 9-Nov-1999 Scott Roberts hfs_allocate now returns sizes based on allocation block boundaries (#2398794) - * 3-Feb-1999 Pat Dirks Merged in Joe's change to hfs_truncate to skip vinvalbuf if LEOF isn't changing (#2302796) - * Removed superfluous (and potentially dangerous) second call to vinvalbuf() in hfs_truncate. - * 2-Dec-1998 Pat Dirks Added support for read/write bootstrap ioctls. - * 10-Nov-1998 Pat Dirks Changed read/write/truncate logic to optimize block sizes for first extents of a file. - * Changed hfs_strategy to correct I/O sizes from cluser code I/O requests in light of - * different block sizing. Changed bexpand to handle RELEASE_BUFFER flag. - * 22-Sep-1998 Don Brady Changed truncate zero-fill to use bwrite after several bawrites have been queued. - * 11-Sep-1998 Pat Dirks Fixed buffering logic to not rely on B_CACHE, which is set for empty buffers that - * have been pre-read by cluster_read (use b_validend > 0 instead). - * 27-Aug-1998 Pat Dirks Changed hfs_truncate to use cluster_write in place of bawrite where possible. - * 25-Aug-1998 Pat Dirks Changed hfs_write to do small device-block aligned writes into buffers without doing - * read-ahead of the buffer. Added bexpand to deal with incomplete [dirty] buffers. - * Fixed can_cluster macro to use MAXPHYSIO instead of MAXBSIZE. - * 19-Aug-1998 Don Brady Remove optimization in hfs_truncate that prevented extra physical blocks from - * being truncated (radar #2265750). Also set fcb->fcbEOF before calling vinvalbuf. - * 7-Jul-1998 Pat Dirks Added code to honor IO_NOZEROFILL in hfs_truncate. - * 16-Jul-1998 Don Brady In hfs_bmap use MAXPHYSIO instead of MAXBSIZE when calling MapFileBlockC (radar #2263753). - * 16-Jul-1998 Don Brady Fix error handling in hfs_allocate (radar #2252265). - * 04-Jul-1998 chw Synchronized options in hfs_allocate with flags in call to ExtendFileC - * 25-Jun-1998 Don Brady Add missing blockNo incrementing to zero fill loop in hfs_truncate. - * 22-Jun-1998 Don Brady Add bp = NULL assignment after brelse in hfs_read. - * 4-Jun-1998 Pat Dirks Split off from hfs_vnodeops.c */ #include @@ -61,7 +35,6 @@ #include #include #include -//#include #include #include @@ -73,11 +46,14 @@ #include #include "hfs.h" -#include "hfs_dbg.h" #include "hfs_endian.h" +#include "hfs_quota.h" #include "hfscommon/headers/FileMgrInternal.h" #include "hfscommon/headers/BTreesInternal.h" +#include "hfs_cnode.h" +#include "hfs_dbg.h" +extern int overflow_extents(struct filefork *fp); #define can_cluster(size) ((((size & (4096-1))) == 0) && (size <= (MAXPHYSIO/2))) @@ -87,13 +63,6 @@ enum { extern u_int32_t GetLogicalBlockSize(struct vnode *vp); -#if DBG_VOP_TEST_LOCKS -extern void DbgVopTest(int maxSlots, int retval, VopDbgStoreRec *VopDbgStore, char *funcname); -#endif - -#if HFS_DIAGNOSTIC -void debug_check_blocksizes(struct vnode *vp); -#endif /***************************************************************************** * @@ -114,123 +83,83 @@ void debug_check_blocksizes(struct vnode *vp); int hfs_read(ap) -struct vop_read_args /* { - struct vnode *a_vp; - struct uio *a_uio; - int a_ioflag; - struct ucred *a_cred; -} */ *ap; + struct vop_read_args /* { + struct vnode *a_vp; + struct uio *a_uio; + int a_ioflag; + struct ucred *a_cred; + } */ *ap; { - register struct vnode *vp; - struct hfsnode *hp; - register struct uio *uio; - struct buf *bp; - daddr_t logBlockNo; - u_long fragSize, moveSize, startOffset, ioxfersize; - int devBlockSize = 0; - off_t bytesRemaining; - int retval; - u_short mode; - FCB *fcb; - - DBG_FUNC_NAME("hfs_read"); - DBG_VOP_LOCKS_DECL(1); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); - DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS); - - vp = ap->a_vp; - hp = VTOH(vp); - fcb = HTOFCB(hp); - mode = hp->h_meta->h_mode; - uio = ap->a_uio; - -#if HFS_DIAGNOSTIC - if (uio->uio_rw != UIO_READ) - panic("%s: mode", funcname); -#endif - - /* Can only read files */ - if (ap->a_vp->v_type != VREG && ap->a_vp->v_type != VLNK) { - DBG_VOP_LOCKS_TEST(EISDIR); - return (EISDIR); - } - DBG_RW(("\tfile size Ox%X\n", (u_int)fcb->fcbEOF)); - DBG_RW(("\tstarting at offset Ox%X of file, length Ox%X\n", (u_int)uio->uio_offset, (u_int)uio->uio_resid)); - -#if HFS_DIAGNOSTIC - debug_check_blocksizes(vp); -#endif - - /* - * If they didn't ask for any data, then we are done. - */ - if (uio->uio_resid == 0) { - DBG_VOP_LOCKS_TEST(E_NONE); - return (E_NONE); - } - - /* cant read from a negative offset */ - if (uio->uio_offset < 0) { - DBG_VOP_LOCKS_TEST(EINVAL); - return (EINVAL); - } - - if (uio->uio_offset > fcb->fcbEOF) { - if ( (!ISHFSPLUS(VTOVCB(vp))) && (uio->uio_offset > (off_t)MAXHFSFILESIZE)) - retval = EFBIG; - else - retval = E_NONE; - - DBG_VOP_LOCKS_TEST(retval); - return (retval); - } + register struct uio *uio = ap->a_uio; + register struct vnode *vp = ap->a_vp; + struct cnode *cp; + struct filefork *fp; + struct buf *bp; + daddr_t logBlockNo; + u_long fragSize, moveSize, startOffset, ioxfersize; + int devBlockSize = 0; + off_t bytesRemaining; + int retval = 0; + off_t filesize; + off_t filebytes; + + /* Preflight checks */ + if (vp->v_type != VREG && vp->v_type != VLNK) + return (EISDIR); /* HFS can only read files */ + if (uio->uio_resid == 0) + return (0); /* Nothing left to do */ + if (uio->uio_offset < 0) + return (EINVAL); /* cant read from a negative offset */ + + cp = VTOC(vp); + fp = VTOF(vp); + filesize = fp->ff_size; + filebytes = (off_t)fp->ff_blocks * (off_t)VTOVCB(vp)->blockSize; + if (uio->uio_offset > filesize) { + if ((!ISHFSPLUS(VTOVCB(vp))) && (uio->uio_offset > (off_t)MAXHFSFILESIZE)) + return (EFBIG); + else + return (0); + } - VOP_DEVBLOCKSIZE(hp->h_meta->h_devvp, &devBlockSize); + VOP_DEVBLOCKSIZE(cp->c_devvp, &devBlockSize); - KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_START, - (int)uio->uio_offset, uio->uio_resid, (int)fcb->fcbEOF, (int)fcb->fcbPLen, 0); + KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_START, + (int)uio->uio_offset, uio->uio_resid, (int)filesize, (int)filebytes, 0); - if (UBCISVALID(vp)) - retval = cluster_read(vp, uio, (off_t)fcb->fcbEOF, devBlockSize, 0); - else { + if (UBCISVALID(vp)) { + retval = cluster_read(vp, uio, filesize, devBlockSize, 0); + } else { - for (retval = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) { + for (retval = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) { - if ((bytesRemaining = (fcb->fcbEOF - uio->uio_offset)) <= 0) + if ((bytesRemaining = (filesize - uio->uio_offset)) <= 0) break; logBlockNo = (daddr_t)(uio->uio_offset / PAGE_SIZE_64); startOffset = (u_long) (uio->uio_offset & PAGE_MASK_64); fragSize = PAGE_SIZE; - if (((logBlockNo * PAGE_SIZE) + fragSize) < fcb->fcbEOF) + if (((logBlockNo * PAGE_SIZE) + fragSize) < filesize) ioxfersize = fragSize; else { - ioxfersize = fcb->fcbEOF - (logBlockNo * PAGE_SIZE); + ioxfersize = filesize - (logBlockNo * PAGE_SIZE); ioxfersize = (ioxfersize + (devBlockSize - 1)) & ~(devBlockSize - 1); } - DBG_RW(("\tat logBlockNo Ox%X, with Ox%lX left to read\n", logBlockNo, (UInt32)uio->uio_resid)); - moveSize = ioxfersize; - DBG_RW(("\tmoveSize = Ox%lX; ioxfersize = Ox%lX; startOffset = Ox%lX.\n", - moveSize, ioxfersize, startOffset)); - DBG_ASSERT(moveSize >= startOffset); - moveSize -= startOffset; + moveSize = ioxfersize; + moveSize -= startOffset; if (bytesRemaining < moveSize) moveSize = bytesRemaining; if (uio->uio_resid < moveSize) { moveSize = uio->uio_resid; - DBG_RW(("\treducing moveSize to Ox%lX (uio->uio_resid).\n", moveSize)); }; if (moveSize == 0) { break; }; - DBG_RW(("\tat logBlockNo Ox%X, extent of Ox%lX, xfer of Ox%lX; moveSize = Ox%lX\n", logBlockNo, fragSize, ioxfersize, moveSize)); - - if (( uio->uio_offset + fragSize) >= fcb->fcbEOF) { + if (( uio->uio_offset + fragSize) >= filesize) { retval = bread(vp, logBlockNo, ioxfersize, NOCRED, &bp); } else if (logBlockNo - 1 == vp->v_lastr && !(vp->v_flag & VRAOFF)) { @@ -238,10 +167,10 @@ struct vop_read_args /* { int nextsize; if (((nextLogBlockNo * PAGE_SIZE) + - (daddr_t)fragSize) < fcb->fcbEOF) + (daddr_t)fragSize) < filesize) nextsize = fragSize; else { - nextsize = fcb->fcbEOF - (nextLogBlockNo * PAGE_SIZE); + nextsize = filesize - (nextLogBlockNo * PAGE_SIZE); nextsize = (nextsize + (devBlockSize - 1)) & ~(devBlockSize - 1); } retval = breadn(vp, logBlockNo, ioxfersize, &nextLogBlockNo, &nextsize, 1, NOCRED, &bp); @@ -275,41 +204,29 @@ struct vop_read_args /* { if ((startOffset + moveSize) > bp->b_bcount) panic("hfs_read: bad startOffset or moveSize\n"); - DBG_RW(("\tcopying Ox%lX bytes from %lX; resid = Ox%lX...\n", moveSize, (char *)bp->b_data + startOffset, bp->b_resid)); - if ((retval = uiomove((caddr_t)bp->b_data + startOffset, (int)moveSize, uio))) break; - if (S_ISREG(mode) && - (((startOffset + moveSize) == fragSize) || (uio->uio_offset == fcb->fcbEOF))) { + if (S_ISREG(cp->c_mode) && + (((startOffset + moveSize) == fragSize) || (uio->uio_offset == filesize))) { bp->b_flags |= B_AGE; }; - DBG_ASSERT(bp->b_bcount == bp->b_validend); - brelse(bp); /* Start of loop resets bp to NULL before reaching outside this block... */ } - if (bp != NULL) { - DBG_ASSERT(bp->b_bcount == bp->b_validend); - brelse(bp); - }; - } - - if (HTOVCB(hp)->vcbSigWord == kHFSPlusSigWord) - hp->h_nodeflags |= IN_ACCESS; - - DBG_VOP_LOCKS_TEST(retval); + if (bp != NULL) { + brelse(bp); + } + } - #if HFS_DIAGNOSTIC - debug_check_blocksizes(vp); - #endif + cp->c_flag |= C_ACCESS; - KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_END, - (int)uio->uio_offset, uio->uio_resid, (int)fcb->fcbEOF, (int)fcb->fcbPLen, 0); + KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_END, + (int)uio->uio_offset, uio->uio_resid, (int)filesize, (int)filebytes, 0); - return (retval); + return (retval); } /* @@ -325,144 +242,127 @@ struct vop_read_args /* { */ int hfs_write(ap) -struct vop_write_args /* { - struct vnode *a_vp; - struct uio *a_uio; - int a_ioflag; - struct ucred *a_cred; -} */ *ap; + struct vop_write_args /* { + struct vnode *a_vp; + struct uio *a_uio; + int a_ioflag; + struct ucred *a_cred; + } */ *ap; { - struct hfsnode *hp = VTOH(ap->a_vp); - struct uio *uio = ap->a_uio; - struct vnode *vp = ap->a_vp ; - struct vnode *dev; - struct buf *bp; - struct proc *p, *cp; - struct timeval tv; - FCB *fcb = HTOFCB(hp); - ExtendedVCB *vcb = HTOVCB(hp); + struct vnode *vp = ap->a_vp; + struct uio *uio = ap->a_uio; + struct cnode *cp; + struct filefork *fp; + struct buf *bp; + struct proc *p; + struct timeval tv; + ExtendedVCB *vcb; int devBlockSize = 0; daddr_t logBlockNo; long fragSize; off_t origFileSize, currOffset, writelimit, bytesToAdd; off_t actualBytesAdded; u_long blkoffset, resid, xfersize, clearSize; - int flags, ioflag; + int eflags, ioflag; int retval; - DBG_FUNC_NAME("hfs_write"); - DBG_VOP_LOCKS_DECL(1); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); - DBG_RW(("\thfsnode 0x%x (%s)\n", (u_int)hp, H_NAME(hp))); - DBG_RW(("\tstarting at offset Ox%lX of file, length Ox%lX\n", (UInt32)uio->uio_offset, (UInt32)uio->uio_resid)); - - DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS); - - dev = hp->h_meta->h_devvp; - -#if HFS_DIAGNOSTIC - debug_check_blocksizes(vp); -#endif - - if (uio->uio_offset < 0) { - DBG_VOP_LOCKS_TEST(EINVAL); - return (EINVAL); - } + off_t filebytes; + u_long fileblocks; - if (uio->uio_resid == 0) { - DBG_VOP_LOCKS_TEST(E_NONE); - return (E_NONE); - } + ioflag = ap->a_ioflag; - if (ap->a_vp->v_type != VREG && ap->a_vp->v_type != VLNK) { /* Can only write files */ - DBG_VOP_LOCKS_TEST(EISDIR); - return (EISDIR); - }; - -#if HFS_DIAGNOSTIC - if (uio->uio_rw != UIO_WRITE) - panic("%s: mode", funcname); -#endif - - ioflag = ap->a_ioflag; - uio = ap->a_uio; - vp = ap->a_vp; - - if (ioflag & IO_APPEND) uio->uio_offset = fcb->fcbEOF; - if ((hp->h_meta->h_pflags & APPEND) && uio->uio_offset != fcb->fcbEOF) - return (EPERM); + if (uio->uio_offset < 0) + return (EINVAL); + if (uio->uio_resid == 0) + return (E_NONE); + if (vp->v_type != VREG && vp->v_type != VLNK) + return (EISDIR); /* Can only write files */ + + cp = VTOC(vp); + fp = VTOF(vp); + vcb = VTOVCB(vp); + fileblocks = fp->ff_blocks; + filebytes = (off_t)fileblocks * (off_t)vcb->blockSize; + + if (ioflag & IO_APPEND) + uio->uio_offset = fp->ff_size; + if ((cp->c_flags & APPEND) && uio->uio_offset != fp->ff_size) + return (EPERM); writelimit = uio->uio_offset + uio->uio_resid; - /* - * Maybe this should be above the vnode op call, but so long as - * file servers have no limits, I don't think it matters. - */ - p = uio->uio_procp; - if (vp->v_type == VREG && p && - writelimit > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { - psignal(p, SIGXFSZ); - return (EFBIG); - }; - VOP_DEVBLOCKSIZE(hp->h_meta->h_devvp, &devBlockSize); - - resid = uio->uio_resid; - origFileSize = fcb->fcbEOF; - flags = ioflag & IO_SYNC ? B_SYNC : 0; - - DBG_RW(("\tLEOF is 0x%lX, PEOF is 0x%lX.\n", fcb->fcbEOF, fcb->fcbPLen)); + /* + * Maybe this should be above the vnode op call, but so long as + * file servers have no limits, I don't think it matters. + */ + p = uio->uio_procp; + if (vp->v_type == VREG && p && + writelimit > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { + psignal(p, SIGXFSZ); + return (EFBIG); + } + p = current_proc(); - /* - NOTE: In the following loop there are two positions tracked: - currOffset is the current I/O starting offset. currOffset is never >LEOF; the - LEOF is nudged along with currOffset as data is zeroed or written. - uio->uio_offset is the start of the current I/O operation. It may be arbitrarily - beyond currOffset. + VOP_DEVBLOCKSIZE(cp->c_devvp, &devBlockSize); - The following is true at all times: + resid = uio->uio_resid; + origFileSize = fp->ff_size; + eflags = kEFDeferMask; /* defer file block allocations */ + filebytes = (off_t)fp->ff_blocks * (off_t)vcb->blockSize; - currOffset <= LEOF <= uio->uio_offset <= writelimit - */ - currOffset = MIN(uio->uio_offset, fcb->fcbEOF); + /* + * NOTE: In the following loop there are two positions tracked: + * currOffset is the current I/O starting offset. currOffset + * is never >LEOF; the LEOF is nudged along with currOffset as + * data is zeroed or written. uio->uio_offset is the start of + * the current I/O operation. It may be arbitrarily beyond + * currOffset. + * + * The following is true at all times: + * currOffset <= LEOF <= uio->uio_offset <= writelimit + */ + currOffset = MIN(uio->uio_offset, fp->ff_size); - DBG_RW(("\tstarting I/O loop at 0x%lX.\n", (u_long)currOffset)); + KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 0)) | DBG_FUNC_START, + (int)uio->uio_offset, uio->uio_resid, (int)fp->ff_size, (int)filebytes, 0); + retval = 0; - cp = current_proc(); + /* Now test if we need to extend the file */ + /* Doing so will adjust the filebytes for us */ - KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 0)) | DBG_FUNC_START, - (int)uio->uio_offset, uio->uio_resid, (int)fcb->fcbEOF, (int)fcb->fcbPLen, 0); - retval = 0; +#if QUOTA + if(writelimit > filebytes) { + bytesToAdd = writelimit - filebytes; - /* Now test if we need to extend the file */ - /* Doing so will adjust the fcbPLen for us */ + retval = hfs_chkdq(cp, (int64_t)(roundup(bytesToAdd, fp->ff_clumpsize)), + ap->a_cred, 0); + if (retval) + return (retval); + } +#endif /* QUOTA */ - while (writelimit > (off_t)fcb->fcbPLen) { + while (writelimit > filebytes) { - bytesToAdd = writelimit - fcb->fcbPLen; - DBG_RW(("\textending file by 0x%lX bytes; 0x%lX blocks free", - (unsigned long)bytesToAdd, (unsigned long)vcb->freeBlocks)); - - /* lock extents b-tree (also protects volume bitmap) */ - retval = hfs_metafilelocking(HTOHFS(hp), kHFSExtentsFileID, LK_EXCLUSIVE, cp); - if (retval != E_NONE) - break; - - retval = MacToVFSError( - ExtendFileC (vcb, - fcb, - bytesToAdd, - 0, - kEFContigBit, - &actualBytesAdded)); - - (void) hfs_metafilelocking(HTOHFS(hp), kHFSExtentsFileID, LK_RELEASE, cp); - DBG_VOP_CONT(("\tactual bytes added = 0x%lX bytes, retval = %d...\n", actualBytesAdded, retval)); - if ((actualBytesAdded == 0) && (retval == E_NONE)) retval = ENOSPC; - if (retval != E_NONE) break; - - KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 0)) | DBG_FUNC_NONE, - (int)uio->uio_offset, uio->uio_resid, (int)fcb->fcbEOF, (int)fcb->fcbPLen, 0); - }; + bytesToAdd = writelimit - filebytes; + if (suser(ap->a_cred, NULL) != 0) + eflags |= kEFReserveMask; + + /* lock extents b-tree (also protects volume bitmap) */ + retval = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_EXCLUSIVE, current_proc()); + if (retval != E_NONE) + break; + + retval = MacToVFSError(ExtendFileC (vcb, (FCB*)fp, bytesToAdd, + 0, eflags, &actualBytesAdded)); + + (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, p); + if ((actualBytesAdded == 0) && (retval == E_NONE)) + retval = ENOSPC; + if (retval != E_NONE) + break; + filebytes = (off_t)fp->ff_blocks * (off_t)vcb->blockSize; + KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 0)) | DBG_FUNC_NONE, + (int)uio->uio_offset, uio->uio_resid, (int)fp->ff_size, (int)filebytes, 0); + } if (UBCISVALID(vp) && retval == E_NONE) { off_t filesize; @@ -474,27 +374,26 @@ struct vop_write_args /* { int lflag; struct rl_entry *invalid_range; - if (writelimit > fcb->fcbEOF) + if (writelimit > fp->ff_size) filesize = writelimit; else - filesize = fcb->fcbEOF; + filesize = fp->ff_size; lflag = (ioflag & IO_SYNC); - if (uio->uio_offset <= fcb->fcbEOF) { + if (uio->uio_offset <= fp->ff_size) { zero_off = uio->uio_offset & ~PAGE_MASK_64; /* Check to see whether the area between the zero_offset and the start of the transfer to see whether is invalid and should be zero-filled as part of the transfer: */ - if (rl_scan(&hp->h_invalidranges, zero_off, uio->uio_offset - 1, &invalid_range) != RL_NOOVERLAP) { + if (rl_scan(&fp->ff_invalidranges, zero_off, uio->uio_offset - 1, &invalid_range) != RL_NOOVERLAP) lflag |= IO_HEADZEROFILL; - }; } else { - off_t eof_page_base = fcb->fcbEOF & ~PAGE_MASK_64; + off_t eof_page_base = fp->ff_size & ~PAGE_MASK_64; - /* The bytes between fcb->fcbEOF and uio->uio_offset must never be + /* The bytes between fp->ff_size and uio->uio_offset must never be read without being zeroed. The current last block is filled with zeroes if it holds valid data but in all cases merely do a little bookkeeping to track the area from the end of the current last page to the start of @@ -506,14 +405,14 @@ struct vop_write_args /* { may be past the start of the write, in which case the zeroing will be handled by the cluser_write of the actual data. */ - inval_start = (fcb->fcbEOF + (PAGE_SIZE_64 - 1)) & ~PAGE_MASK_64; + inval_start = (fp->ff_size + (PAGE_SIZE_64 - 1)) & ~PAGE_MASK_64; inval_end = uio->uio_offset & ~PAGE_MASK_64; - zero_off = fcb->fcbEOF; + zero_off = fp->ff_size; - if ((fcb->fcbEOF & PAGE_MASK_64) && - (rl_scan(&hp->h_invalidranges, + if ((fp->ff_size & PAGE_MASK_64) && + (rl_scan(&fp->ff_invalidranges, eof_page_base, - fcb->fcbEOF - 1, + fp->ff_size - 1, &invalid_range) != RL_NOOVERLAP)) { /* The page containing the EOF is not valid, so the entire page must be made inaccessible now. If the write @@ -538,14 +437,17 @@ struct vop_write_args /* { and the actual write will start on a page past inval_end. Now's the last chance to zero-fill the page containing the EOF: */ - retval = cluster_write(vp, (struct uio *) 0, fcb->fcbEOF, inval_start, - zero_off, (off_t)0, devBlockSize, lflag | IO_HEADZEROFILL); + retval = cluster_write(vp, (struct uio *) 0, + fp->ff_size, inval_start, + zero_off, (off_t)0, devBlockSize, + lflag | IO_HEADZEROFILL | IO_NOZERODIRTY); if (retval) goto ioerr_exit; }; /* Mark the remaining area of the newly allocated space as invalid: */ - rl_add(inval_start, inval_end - 1 , &hp->h_invalidranges); - zero_off = fcb->fcbEOF = inval_end; + rl_add(inval_start, inval_end - 1 , &fp->ff_invalidranges); + cp->c_zftimeout = time.tv_sec + ZFTIMELIMIT; + zero_off = fp->ff_size = inval_end; }; if (uio->uio_offset > zero_off) lflag |= IO_HEADZEROFILL; @@ -557,7 +459,7 @@ struct vop_write_args /* { tail_off = (writelimit + (PAGE_SIZE_64 - 1)) & ~PAGE_MASK_64; if (tail_off > filesize) tail_off = filesize; if (tail_off > writelimit) { - if (rl_scan(&hp->h_invalidranges, writelimit, tail_off - 1, &invalid_range) != RL_NOOVERLAP) { + if (rl_scan(&fp->ff_invalidranges, writelimit, tail_off - 1, &invalid_range) != RL_NOOVERLAP) { lflag |= IO_TAILZEROFILL; }; }; @@ -574,164 +476,144 @@ struct vop_write_args /* { */ io_start = (lflag & IO_HEADZEROFILL) ? zero_off : uio->uio_offset; io_end = (lflag & IO_TAILZEROFILL) ? tail_off : writelimit; - if (io_start < fcb->fcbEOF) { - rl_remove(io_start, io_end - 1, &hp->h_invalidranges); + if (io_start < fp->ff_size) { + rl_remove(io_start, io_end - 1, &fp->ff_invalidranges); }; - retval = cluster_write(vp, uio, fcb->fcbEOF, filesize, zero_off, tail_off, devBlockSize, lflag); + retval = cluster_write(vp, uio, fp->ff_size, filesize, zero_off, + tail_off, devBlockSize, lflag | IO_NOZERODIRTY); - if (uio->uio_offset > fcb->fcbEOF) { - fcb->fcbEOF = uio->uio_offset; + if (uio->uio_offset > fp->ff_size) { + fp->ff_size = uio->uio_offset; - ubc_setsize(vp, (off_t)fcb->fcbEOF); /* XXX check errors */ + ubc_setsize(vp, fp->ff_size); /* XXX check errors */ } - if (resid > uio->uio_resid) hp->h_nodeflags |= IN_CHANGE | IN_UPDATE; - - } else { - - while (retval == E_NONE && uio->uio_resid > 0) { - logBlockNo = currOffset / PAGE_SIZE; - blkoffset = currOffset & PAGE_MASK; - - if (((off_t)(fcb->fcbPLen) - currOffset) < PAGE_SIZE_64) - fragSize = (off_t)(fcb->fcbPLen) - ((off_t)logBlockNo * PAGE_SIZE_64); - else - fragSize = PAGE_SIZE; - xfersize = fragSize - blkoffset; - - DBG_RW(("\tcurrOffset = Ox%lX, logBlockNo = Ox%X, blkoffset = Ox%lX, xfersize = Ox%lX, fragSize = Ox%lX.\n", - (unsigned long)currOffset, logBlockNo, blkoffset, xfersize, fragSize)); - - /* Make any adjustments for boundary conditions */ - if (currOffset + (off_t)xfersize > writelimit) { - xfersize = writelimit - currOffset; - DBG_RW(("\ttrimming xfersize to 0x%lX to match writelimit (uio_resid)...\n", xfersize)); - }; - - /* - * There is no need to read into bp if: - * We start on a block boundary and will overwrite the whole block - * - * OR - */ - if ((blkoffset == 0) && (xfersize >= fragSize)) { - DBG_RW(("\tRequesting %ld-byte block Ox%lX w/o read...\n", fragSize, (long)logBlockNo)); - - bp = getblk(vp, logBlockNo, fragSize, 0, 0, BLK_READ); - retval = 0; - - if (bp->b_blkno == -1) { - brelse(bp); - retval = EIO; /* XXX */ - break; - } - } else { - - if (currOffset == fcb->fcbEOF && blkoffset == 0) { - bp = getblk(vp, logBlockNo, fragSize, 0, 0, BLK_READ); - retval = 0; - - if (bp->b_blkno == -1) { - brelse(bp); - retval = EIO; /* XXX */ - break; - } - - } else { - /* - * This I/O transfer is not sufficiently aligned, so read the affected block into a buffer: - */ - DBG_VOP(("\tRequesting block Ox%X, size = 0x%08lX...\n", logBlockNo, fragSize)); - retval = bread(vp, logBlockNo, fragSize, ap->a_cred, &bp); - - if (retval != E_NONE) { - if (bp) - brelse(bp); - break; - } - } - } - - /* See if we are starting to write within file boundaries: - If not, then we need to present a "hole" for the area between - the current EOF and the start of the current I/O operation: - - Note that currOffset is only less than uio_offset if uio_offset > LEOF... - */ - if (uio->uio_offset > currOffset) { - clearSize = MIN(uio->uio_offset - currOffset, xfersize); - DBG_RW(("\tzeroing Ox%lX bytes Ox%lX bytes into block Ox%X...\n", clearSize, blkoffset, logBlockNo)); - bzero(bp->b_data + blkoffset, clearSize); - currOffset += clearSize; - blkoffset += clearSize; - xfersize -= clearSize; - }; - - if (xfersize > 0) { - DBG_RW(("\tCopying Ox%lX bytes Ox%lX bytes into block Ox%X... ioflag == 0x%X\n", - xfersize, blkoffset, logBlockNo, ioflag)); - retval = uiomove((caddr_t)bp->b_data + blkoffset, (int)xfersize, uio); - currOffset += xfersize; - }; - DBG_ASSERT((bp->b_bcount % devBlockSize) == 0); - - if (ioflag & IO_SYNC) { - (void)VOP_BWRITE(bp); - //DBG_RW(("\tissuing bwrite\n")); - } else if ((xfersize + blkoffset) == fragSize) { - //DBG_RW(("\tissuing bawrite\n")); - bp->b_flags |= B_AGE; - bawrite(bp); - } else { - //DBG_RW(("\tissuing bdwrite\n")); - bdwrite(bp); - }; - - /* Update the EOF if we just extended the file - (the PEOF has already been moved out and the block mapping table has been updated): */ - if (currOffset > fcb->fcbEOF) { - DBG_VOP(("\textending EOF to 0x%lX...\n", (UInt32)fcb->fcbEOF)); - fcb->fcbEOF = currOffset; - - if (UBCISVALID(vp)) - ubc_setsize(vp, (off_t)fcb->fcbEOF); /* XXX check errors */ - }; - - if (retval || (resid == 0)) - break; - hp->h_nodeflags |= IN_CHANGE | IN_UPDATE; - }; - }; + if (resid > uio->uio_resid) + cp->c_flag |= C_CHANGE | C_UPDATE; + } else { + while (retval == E_NONE && uio->uio_resid > 0) { + logBlockNo = currOffset / PAGE_SIZE; + blkoffset = currOffset & PAGE_MASK; + + if ((filebytes - currOffset) < PAGE_SIZE_64) + fragSize = filebytes - ((off_t)logBlockNo * PAGE_SIZE_64); + else + fragSize = PAGE_SIZE; + xfersize = fragSize - blkoffset; + + /* Make any adjustments for boundary conditions */ + if (currOffset + (off_t)xfersize > writelimit) + xfersize = writelimit - currOffset; + + /* + * There is no need to read into bp if: + * We start on a block boundary and will overwrite the whole block + * + * OR + */ + if ((blkoffset == 0) && (xfersize >= fragSize)) { + bp = getblk(vp, logBlockNo, fragSize, 0, 0, BLK_READ); + retval = 0; + + if (bp->b_blkno == -1) { + brelse(bp); + retval = EIO; /* XXX */ + break; + } + } else { + + if (currOffset == fp->ff_size && blkoffset == 0) { + bp = getblk(vp, logBlockNo, fragSize, 0, 0, BLK_READ); + retval = 0; + if (bp->b_blkno == -1) { + brelse(bp); + retval = EIO; /* XXX */ + break; + } + } else { + /* + * This I/O transfer is not sufficiently aligned, + * so read the affected block into a buffer: + */ + retval = bread(vp, logBlockNo, fragSize, ap->a_cred, &bp); + if (retval != E_NONE) { + if (bp) + brelse(bp); + break; + } + } + } + + /* See if we are starting to write within file boundaries: + * If not, then we need to present a "hole" for the area + * between the current EOF and the start of the current + * I/O operation: + * + * Note that currOffset is only less than uio_offset if + * uio_offset > LEOF... + */ + if (uio->uio_offset > currOffset) { + clearSize = MIN(uio->uio_offset - currOffset, xfersize); + bzero(bp->b_data + blkoffset, clearSize); + currOffset += clearSize; + blkoffset += clearSize; + xfersize -= clearSize; + } + + if (xfersize > 0) { + retval = uiomove((caddr_t)bp->b_data + blkoffset, (int)xfersize, uio); + currOffset += xfersize; + } + + if (ioflag & IO_SYNC) { + (void)VOP_BWRITE(bp); + } else if ((xfersize + blkoffset) == fragSize) { + bp->b_flags |= B_AGE; + bawrite(bp); + } else { + bdwrite(bp); + } + + /* Update the EOF if we just extended the file + * (the PEOF has already been moved out and the + * block mapping table has been updated): + */ + if (currOffset > fp->ff_size) { + fp->ff_size = currOffset; + if (UBCISVALID(vp)) + ubc_setsize(vp, fp->ff_size); /* XXX check errors */ + } + if (retval || (resid == 0)) + break; + cp->c_flag |= C_CHANGE | C_UPDATE; + } /* endwhile */ + } ioerr_exit: - /* + /* * If we successfully wrote any data, and we are not the superuser - * we clear the setuid and setgid bits as a precaution against - * tampering. - */ - if (resid > uio->uio_resid && ap->a_cred && ap->a_cred->cr_uid != 0) - hp->h_meta->h_mode &= ~(ISUID | ISGID); - - if (retval) { - if (ioflag & IO_UNIT) { - (void)VOP_TRUNCATE(vp, origFileSize, - ioflag & IO_SYNC, ap->a_cred, uio->uio_procp); - uio->uio_offset -= resid - uio->uio_resid; - uio->uio_resid = resid; - } - } else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) { - tv = time; - retval = VOP_UPDATE(vp, &tv, &tv, 1); - } - - #if HFS_DIAGNOSTIC - debug_check_blocksizes(vp); - #endif + * we clear the setuid and setgid bits as a precaution against + * tampering. + */ + if (resid > uio->uio_resid && ap->a_cred && ap->a_cred->cr_uid != 0) + cp->c_mode &= ~(S_ISUID | S_ISGID); + + if (retval) { + if (ioflag & IO_UNIT) { + (void)VOP_TRUNCATE(vp, origFileSize, + ioflag & IO_SYNC, ap->a_cred, uio->uio_procp); + uio->uio_offset -= resid - uio->uio_resid; + uio->uio_resid = resid; + filebytes = (off_t)fp->ff_blocks * (off_t)vcb->blockSize; + } + } else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) { + tv = time; + retval = VOP_UPDATE(vp, &tv, &tv, 1); + } - KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 0)) | DBG_FUNC_END, - (int)uio->uio_offset, uio->uio_resid, (int)fcb->fcbEOF, (int)fcb->fcbPLen, 0); + KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 0)) | DBG_FUNC_END, + (int)uio->uio_offset, uio->uio_resid, (int)fp->ff_size, (int)filebytes, 0); - DBG_VOP_LOCKS_TEST(retval); - return (retval); + return (retval); } @@ -753,61 +635,55 @@ ioerr_exit: /* ARGSUSED */ int hfs_ioctl(ap) -struct vop_ioctl_args /* { - struct vnode *a_vp; - int a_command; - caddr_t a_data; - int a_fflag; - struct ucred *a_cred; - struct proc *a_p; -} */ *ap; + struct vop_ioctl_args /* { + struct vnode *a_vp; + int a_command; + caddr_t a_data; + int a_fflag; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; { - DBG_FUNC_NAME("hfs_ioctl"); - DBG_VOP_LOCKS_DECL(1); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); - - DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); - - switch (ap->a_command) { - - case 1: - { register struct hfsnode *hp; - register struct vnode *vp; - register struct radvisory *ra; - FCB *fcb; - int devBlockSize = 0; - int error; - - vp = ap->a_vp; - - VOP_LEASE(vp, ap->a_p, ap->a_cred, LEASE_READ); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, ap->a_p); - - ra = (struct radvisory *)(ap->a_data); - hp = VTOH(vp); + switch (ap->a_command) { + case 1: { + register struct cnode *cp; + register struct vnode *vp; + register struct radvisory *ra; + struct filefork *fp; + int devBlockSize = 0; + int error; + + vp = ap->a_vp; + + if (vp->v_type != VREG) + return EINVAL; + + VOP_LEASE(vp, ap->a_p, ap->a_cred, LEASE_READ); + error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, ap->a_p); + if (error) + return (error); + + ra = (struct radvisory *)(ap->a_data); + cp = VTOC(vp); + fp = VTOF(vp); + + if (ra->ra_offset >= fp->ff_size) { + VOP_UNLOCK(vp, 0, ap->a_p); + return (EFBIG); + } + VOP_DEVBLOCKSIZE(cp->c_devvp, &devBlockSize); - fcb = HTOFCB(hp); + error = advisory_read(vp, fp->ff_size, ra->ra_offset, ra->ra_count, devBlockSize); + VOP_UNLOCK(vp, 0, ap->a_p); - if (ra->ra_offset >= fcb->fcbEOF) { - VOP_UNLOCK(vp, 0, ap->a_p); - DBG_VOP_LOCKS_TEST(EFBIG); - return (EFBIG); + return (error); } - VOP_DEVBLOCKSIZE(hp->h_meta->h_devvp, &devBlockSize); - - error = advisory_read(vp, fcb->fcbEOF, ra->ra_offset, ra->ra_count, devBlockSize); - VOP_UNLOCK(vp, 0, ap->a_p); - - DBG_VOP_LOCKS_TEST(error); - return (error); - } case 2: /* F_READBOOTBLOCKS */ case 3: /* F_WRITEBOOTBLOCKS */ { struct vnode *vp = ap->a_vp; - struct hfsnode *hp = VTOH(vp); + struct vnode *devvp = NULL; struct fbootstraptransfer *btd = (struct fbootstraptransfer *)ap->a_data; int devBlockSize; int error; @@ -821,6 +697,7 @@ struct vop_ioctl_args /* { if ((vp->v_flag & VROOT) == 0) return EINVAL; if (btd->fbt_offset + btd->fbt_length > 1024) return EINVAL; + devvp = VTOHFS(vp)->hfs_devvp; aiov.iov_base = btd->fbt_buffer; aiov.iov_len = btd->fbt_length; @@ -832,11 +709,11 @@ struct vop_ioctl_args /* { auio.uio_rw = (ap->a_command == 3) ? UIO_WRITE : UIO_READ; /* F_WRITEBOOTSTRAP / F_READBOOTSTRAP */ auio.uio_procp = ap->a_p; - VOP_DEVBLOCKSIZE(hp->h_meta->h_devvp, &devBlockSize); + VOP_DEVBLOCKSIZE(devvp, &devBlockSize); while (auio.uio_resid > 0) { blockNumber = auio.uio_offset / devBlockSize; - error = bread(hp->h_meta->h_devvp, blockNumber, devBlockSize, ap->a_cred, &bp); + error = bread(devvp, blockNumber, devBlockSize, ap->a_cred, &bp); if (error) { if (bp) brelse(bp); return error; @@ -866,7 +743,6 @@ struct vop_ioctl_args /* { } default: - DBG_VOP_LOCKS_TEST(ENOTTY); return (ENOTTY); } @@ -877,104 +753,21 @@ struct vop_ioctl_args /* { /* ARGSUSED */ int hfs_select(ap) -struct vop_select_args /* { - struct vnode *a_vp; - int a_which; - int a_fflags; - struct ucred *a_cred; - void *a_wql; - struct proc *a_p; -} */ *ap; -{ - DBG_FUNC_NAME("hfs_select"); - DBG_VOP_LOCKS_DECL(1); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); - - DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_POS); - - /* - * We should really check to see if I/O is possible. - */ - DBG_VOP_LOCKS_TEST(1); - return (1); -} - - - -/* - * Mmap a file - * - * NB Currently unsupported. -# XXX - not used -# - vop_mmap { - IN struct vnode *vp; - IN int fflags; - IN struct ucred *cred; - IN struct proc *p; - - */ - -/* ARGSUSED */ - -int -hfs_mmap(ap) -struct vop_mmap_args /* { - struct vnode *a_vp; - int a_fflags; - struct ucred *a_cred; - struct proc *a_p; -} */ *ap; -{ - DBG_FUNC_NAME("hfs_mmap"); - DBG_VOP_LOCKS_DECL(1); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); - - DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_POS); - - DBG_VOP_LOCKS_TEST(EINVAL); - return (EINVAL); -} - - - -/* - * Seek on a file - * - * Nothing to do, so just return. -# XXX - not used -# Needs work: Is newoff right? What's it mean? -# - vop_seek { - IN struct vnode *vp; - IN off_t oldoff; - IN off_t newoff; - IN struct ucred *cred; - */ -/* ARGSUSED */ -int -hfs_seek(ap) -struct vop_seek_args /* { - struct vnode *a_vp; - off_t a_oldoff; - off_t a_newoff; - struct ucred *a_cred; -} */ *ap; + struct vop_select_args /* { + struct vnode *a_vp; + int a_which; + int a_fflags; + struct ucred *a_cred; + void *a_wql; + struct proc *a_p; + } */ *ap; { - DBG_FUNC_NAME("hfs_seek"); - DBG_VOP_LOCKS_DECL(1); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); - - DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_POS); - - DBG_VOP_LOCKS_TEST(E_NONE); - return (E_NONE); + /* + * We should really check to see if I/O is possible. + */ + return (1); } - /* * Bmap converts a the logical block number of a file to its physical block * number on the disk. @@ -1005,17 +798,19 @@ struct vop_seek_args /* { int hfs_bmap(ap) -struct vop_bmap_args /* { - struct vnode *a_vp; - daddr_t a_bn; - struct vnode **a_vpp; - daddr_t *a_bnp; - int *a_runp; -} */ *ap; + struct vop_bmap_args /* { + struct vnode *a_vp; + daddr_t a_bn; + struct vnode **a_vpp; + daddr_t *a_bnp; + int *a_runp; + } */ *ap; { - struct hfsnode *hp = VTOH(ap->a_vp); - struct hfsmount *hfsmp = VTOHFS(ap->a_vp); - int retval = E_NONE; + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); + struct filefork *fp = VTOF(vp); + struct hfsmount *hfsmp = VTOHFS(vp); + int retval = E_NONE; daddr_t logBlockSize; size_t bytesContAvail = 0; off_t blockposition; @@ -1024,46 +819,33 @@ struct vop_bmap_args /* { struct rl_entry *invalid_range; enum rl_overlaptype overlaptype; -#define DEBUG_BMAP 0 -#if DEBUG_BMAP - DBG_FUNC_NAME("hfs_bmap"); - DBG_VOP_LOCKS_DECL(2); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_PRINT_VNODE_INFO(ap->a_vp); - - DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS); - if (ap->a_vpp != NULL) { - DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_UNLOCKED, VOPDBG_IGNORE, VOPDBG_POS); - } else { - DBG_VOP_LOCKS_INIT(1,NULL, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_POS); - }; -#endif - - DBG_IO(("\tMapped blk %d --> ", ap->a_bn)); - /* - * Check for underlying vnode requests and ensure that logical - * to physical mapping is requested. - */ - if (ap->a_vpp != NULL) - *ap->a_vpp = VTOH(ap->a_vp)->h_meta->h_devvp; - if (ap->a_bnp == NULL) - return (0); - - logBlockSize = GetLogicalBlockSize(ap->a_vp); - blockposition = (off_t)(ap->a_bn * logBlockSize); - - lockExtBtree = hasOverflowExtents(hp); - if (lockExtBtree) - { - p = current_proc(); - retval = hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE | LK_CANRECURSE, p); - if (retval) - return (retval); - } + /* + * Check for underlying vnode requests and ensure that logical + * to physical mapping is requested. + */ + if (ap->a_vpp != NULL) + *ap->a_vpp = cp->c_devvp; + if (ap->a_bnp == NULL) + return (0); + + /* Only clustered I/O should have delayed allocations. */ + DBG_ASSERT(fp->ff_unallocblocks == 0); + + logBlockSize = GetLogicalBlockSize(vp); + blockposition = (off_t)ap->a_bn * (off_t)logBlockSize; + + lockExtBtree = overflow_extents(fp); + if (lockExtBtree) { + p = current_proc(); + retval = hfs_metafilelocking(hfsmp, kHFSExtentsFileID, + LK_EXCLUSIVE | LK_CANRECURSE, p); + if (retval) + return (retval); + } - retval = MacToVFSError( + retval = MacToVFSError( MapFileBlockC (HFSTOVCB(hfsmp), - HTOFCB(hp), + (FCB*)fp, MAXPHYSIO, blockposition, ap->a_bnp, @@ -1073,7 +855,7 @@ struct vop_bmap_args /* { if (retval == E_NONE) { /* Adjust the mapping information for invalid file ranges: */ - overlaptype = rl_scan(&hp->h_invalidranges, + overlaptype = rl_scan(&fp->ff_invalidranges, blockposition, blockposition + MAXPHYSIO - 1, &invalid_range); @@ -1093,7 +875,7 @@ struct vop_bmap_args /* { if (invalid_range->rl_start == blockposition) { /* There's actually no valid information to be had starting here: */ *ap->a_bnp = (daddr_t)-1; - if ((HTOFCB(hp)->fcbEOF > (invalid_range->rl_end + 1)) && + if ((fp->ff_size > (invalid_range->rl_end + 1)) && (invalid_range->rl_end + 1 - blockposition < bytesContAvail)) { bytesContAvail = invalid_range->rl_end + 1 - blockposition; }; @@ -1116,21 +898,6 @@ struct vop_bmap_args /* { }; }; - DBG_IO(("%d:%d.\n", *ap->a_bnp, (bytesContAvail < logBlockSize) ? 0 : (bytesContAvail / logBlockSize) - 1)); - -#if DEBUG_BMAP - - DBG_VOP_LOCKS_TEST(retval); -#endif - - if (ap->a_runp) { - DBG_ASSERT((*ap->a_runp * logBlockSize) < bytesContAvail); /* At least *ap->a_runp blocks left and ... */ - if (can_cluster(logBlockSize)) { - DBG_ASSERT(bytesContAvail - (*ap->a_runp * logBlockSize) < (2*logBlockSize)); /* ... at most 1 logical block accounted for by current block */ - /* ... plus some sub-logical block sized piece */ - }; - }; - return (retval); } @@ -1138,11 +905,11 @@ struct vop_bmap_args /* { int hfs_blktooff(ap) -struct vop_blktooff_args /* { - struct vnode *a_vp; - daddr_t a_lblkno; - off_t *a_offset; -} */ *ap; + struct vop_blktooff_args /* { + struct vnode *a_vp; + daddr_t a_lblkno; + off_t *a_offset; + } */ *ap; { if (ap->a_vp == NULL) return (EINVAL); @@ -1153,14 +920,12 @@ struct vop_blktooff_args /* { int hfs_offtoblk(ap) -struct vop_offtoblk_args /* { - struct vnode *a_vp; - off_t a_offset; - daddr_t *a_lblkno; -} */ *ap; + struct vop_offtoblk_args /* { + struct vnode *a_vp; + off_t a_offset; + daddr_t *a_lblkno; + } */ *ap; { - long lbsize, boff; - if (ap->a_vp == NULL) return (EINVAL); *ap->a_lblkno = ap->a_offset / PAGE_SIZE_64; @@ -1170,65 +935,98 @@ struct vop_offtoblk_args /* { int hfs_cmap(ap) -struct vop_cmap_args /* { - struct vnode *a_vp; - off_t a_foffset; - size_t a_size; - daddr_t *a_bpn; - size_t *a_run; - void *a_poff; -} */ *ap; + struct vop_cmap_args /* { + struct vnode *a_vp; + off_t a_foffset; + size_t a_size; + daddr_t *a_bpn; + size_t *a_run; + void *a_poff; + } */ *ap; { - struct hfsnode *hp = VTOH(ap->a_vp); - struct hfsmount *hfsmp = VTOHFS(ap->a_vp); - FCB *fcb = HTOFCB(hp); + struct hfsmount *hfsmp = VTOHFS(ap->a_vp); + struct filefork *fp = VTOF(ap->a_vp); size_t bytesContAvail = 0; int retval = E_NONE; - int lockExtBtree; + int lockExtBtree = 0; struct proc *p = NULL; struct rl_entry *invalid_range; enum rl_overlaptype overlaptype; - off_t limit; -#define DEBUG_CMAP 0 -#if DEBUG_CMAP - DBG_FUNC_NAME("hfs_cmap"); - DBG_VOP_LOCKS_DECL(2); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_PRINT_VNODE_INFO(ap->a_vp); + /* + * Check for underlying vnode requests and ensure that logical + * to physical mapping is requested. + */ + if (ap->a_bpn == NULL) + return (0); + + if (overflow_extents(fp) || fp->ff_unallocblocks) { + lockExtBtree = 1; + p = current_proc(); + if (retval = hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE | LK_CANRECURSE, p)) { + return (retval); + } + } - DBG_VOP_LOCKS_INIT(0, ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS); -#endif + /* + * Check for any delayed allocations. + */ + if (fp->ff_unallocblocks) { + SInt64 reqbytes, actbytes; - DBG_IO(("\tMapped offset %qx --> ", ap->a_foffset)); - /* - * Check for underlying vnode requests and ensure that logical - * to physical mapping is requested. - */ - if (ap->a_bpn == NULL) { - return (0); - }; + reqbytes = (SInt64)fp->ff_unallocblocks * + (SInt64)HFSTOVCB(hfsmp)->blockSize; + /* + * Release the blocks on loan and aquire some real ones. + * Note that we can race someone else for these blocks + * (and lose) so cmap needs to handle a failure here. + * Currently this race can't occur because all allocations + * are protected by an exclusive lock on the Extents + * Overflow file. + */ + HFSTOVCB(hfsmp)->loanedBlocks -= fp->ff_unallocblocks; + FTOC(fp)->c_blocks -= fp->ff_unallocblocks; + fp->ff_blocks -= fp->ff_unallocblocks; + fp->ff_unallocblocks = 0; + + while (retval == 0 && reqbytes > 0) { + retval = MacToVFSError(ExtendFileC(HFSTOVCB(hfsmp), + (FCB*)fp, reqbytes, 0, + kEFAllMask | kEFNoClumpMask, &actbytes)); + if (retval == 0 && actbytes == 0) + retval = ENOSPC; + + if (retval) { + fp->ff_unallocblocks = + reqbytes / HFSTOVCB(hfsmp)->blockSize; + HFSTOVCB(hfsmp)->loanedBlocks += fp->ff_unallocblocks; + FTOC(fp)->c_blocks += fp->ff_unallocblocks; + fp->ff_blocks += fp->ff_unallocblocks; + } + reqbytes -= actbytes; + } - if (lockExtBtree = hasOverflowExtents(hp)) - { - p = current_proc(); - if (retval = hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE | LK_CANRECURSE, p)) { - return (retval); - }; - } - retval = MacToVFSError( + if (retval) { + (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, p); + return (retval); + } + VTOC(ap->a_vp)->c_flag |= C_MODIFIED; + } + + retval = MacToVFSError( MapFileBlockC (HFSTOVCB(hfsmp), - fcb, + (FCB *)fp, ap->a_size, ap->a_foffset, ap->a_bpn, &bytesContAvail)); - if (lockExtBtree) (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, p); + if (lockExtBtree) + (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, p); if (retval == E_NONE) { /* Adjust the mapping information for invalid file ranges: */ - overlaptype = rl_scan(&hp->h_invalidranges, + overlaptype = rl_scan(&fp->ff_invalidranges, ap->a_foffset, ap->a_foffset + (off_t)bytesContAvail - 1, &invalid_range); @@ -1245,7 +1043,7 @@ struct vop_cmap_args /* { (i.e. there's no valid bytes between the end of this range and the file's EOF): */ - if ((fcb->fcbEOF > (invalid_range->rl_end + 1)) && + if ((fp->ff_size > (invalid_range->rl_end + 1)) && (invalid_range->rl_end + 1 - ap->a_foffset < bytesContAvail)) { bytesContAvail = invalid_range->rl_end + 1 - ap->a_foffset; }; @@ -1257,7 +1055,7 @@ struct vop_cmap_args /* { if (invalid_range->rl_start == ap->a_foffset) { /* There's actually no valid information to be had starting here: */ *ap->a_bpn = (daddr_t)-1; - if ((fcb->fcbEOF > (invalid_range->rl_end + 1)) && + if ((fp->ff_size > (invalid_range->rl_end + 1)) && (invalid_range->rl_end + 1 - ap->a_foffset < bytesContAvail)) { bytesContAvail = invalid_range->rl_end + 1 - ap->a_foffset; }; @@ -1272,19 +1070,100 @@ struct vop_cmap_args /* { if (ap->a_run) *ap->a_run = bytesContAvail; }; - if (ap->a_poff) *(int *)ap->a_poff = 0; - - DBG_IO(("%d:%d.\n", *ap->a_bpn, bytesContAvail)); + if (ap->a_poff) + *(int *)ap->a_poff = 0; -#if DEBUG_BMAP + return (retval); +} - DBG_VOP_LOCKS_TEST(retval); -#endif - return (retval); +/* + * Read or write a buffer that is not contiguous on disk. We loop over + * each device block, copying to or from caller's buffer. + * + * We could be a bit more efficient by transferring as much data as is + * contiguous. But since this routine should rarely be called, and that + * would be more complicated; best to keep it simple. + */ +static int +hfs_strategy_fragmented(struct buf *bp) +{ + register struct vnode *vp = bp->b_vp; + register struct cnode *cp = VTOC(vp); + register struct vnode *devvp = cp->c_devvp; + caddr_t ioaddr; /* Address of fragment within bp */ + struct buf *frag = NULL; /* For reading or writing a single block */ + int retval = 0; + long remaining; /* Bytes (in bp) left to transfer */ + off_t offset; /* Logical offset of current fragment in vp */ + u_long block_size; /* Size of one device block (and one I/O) */ + + /* Make sure we redo this mapping for the next I/O */ + bp->b_blkno = bp->b_lblkno; + + /* Set up the logical position and number of bytes to read/write */ + offset = (off_t) bp->b_lblkno * (off_t) GetLogicalBlockSize(vp); + block_size = VTOHFS(vp)->hfs_phys_block_size; + + /* Get an empty buffer to do the deblocking */ + frag = geteblk(block_size); + if (ISSET(bp->b_flags, B_READ)) + SET(frag->b_flags, B_READ); + + for (ioaddr = bp->b_data, remaining = bp->b_bcount; remaining != 0; + ioaddr += block_size, offset += block_size, + remaining -= block_size) { + frag->b_resid = frag->b_bcount; + CLR(frag->b_flags, B_DONE); + + /* Map the current position to a physical block number */ + retval = VOP_CMAP(vp, offset, block_size, &frag->b_lblkno, + NULL, NULL); + if (retval != 0) + break; + /* + * Did we try to read a hole? + * (Should never happen for metadata!) + */ + if ((long)frag->b_lblkno == -1) { + bzero(ioaddr, block_size); + continue; + } + + /* If writing, copy before I/O */ + if (!ISSET(bp->b_flags, B_READ)) + bcopy(ioaddr, frag->b_data, block_size); + + /* Call the device to do the I/O and wait for it */ + frag->b_blkno = frag->b_lblkno; + frag->b_vp = devvp; /* Used to dispatch via VOP_STRATEGY */ + frag->b_dev = devvp->v_rdev; + retval = VOP_STRATEGY(frag); + frag->b_vp = NULL; + if (retval != 0) + break; + retval = biowait(frag); + if (retval != 0) + break; + + /* If reading, copy after the I/O */ + if (ISSET(bp->b_flags, B_READ)) + bcopy(frag->b_data, ioaddr, block_size); + } + + frag->b_vp = NULL; + SET(frag->b_flags, B_INVAL); + brelse(frag); + + if ((bp->b_error = retval) != 0) + SET(bp->b_flags, B_ERROR); + + biodone(bp); /* This I/O is now complete */ + return retval; } + /* * Calculate the logical to physical mapping if not done already, * then call the device strategy routine. @@ -1294,106 +1173,89 @@ struct vop_cmap_args /* { */ int hfs_strategy(ap) -struct vop_strategy_args /* { - struct buf *a_bp; -} */ *ap; + struct vop_strategy_args /* { + struct buf *a_bp; + } */ *ap; { - register struct buf *bp = ap->a_bp; - register struct vnode *vp = bp->b_vp; - register struct hfsnode *hp; - int retval = 0; - - DBG_FUNC_NAME("hfs_strategy"); - -// DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("\n")); - - hp = VTOH(vp); - - if ( !(bp->b_flags & B_VECTORLIST)) { - - if (vp->v_type == VBLK || vp->v_type == VCHR) - panic("hfs_strategy: device vnode passed!"); + register struct buf *bp = ap->a_bp; + register struct vnode *vp = bp->b_vp; + register struct cnode *cp = VTOC(vp); + int retval = 0; + off_t offset; + size_t bytes_contig; + + if ( !(bp->b_flags & B_VECTORLIST)) { + if (vp->v_type == VBLK || vp->v_type == VCHR) + panic("hfs_strategy: device vnode passed!"); - if (bp->b_flags & B_PAGELIST) { - /* - * if we have a page list associated with this bp, - * then go through cluster_bp since it knows how to - * deal with a page request that might span non-contiguous - * physical blocks on the disk... - */ - retval = cluster_bp(bp); - vp = hp->h_meta->h_devvp; - bp->b_dev = vp->v_rdev; + if (bp->b_flags & B_PAGELIST) { + /* + * If we have a page list associated with this bp, + * then go through cluster_bp since it knows how to + * deal with a page request that might span non- + * contiguous physical blocks on the disk... + */ + retval = cluster_bp(bp); + vp = cp->c_devvp; + bp->b_dev = vp->v_rdev; - return (retval); - } - /* - * If we don't already know the filesystem relative block number - * then get it using VOP_BMAP(). If VOP_BMAP() returns the block - * number as -1 then we've got a hole in the file. Although HFS - * filesystems don't create files with holes, invalidating of - * subranges of the file (lazy zero filling) may create such a - * situation. - */ - if (bp->b_blkno == bp->b_lblkno) { - if ((retval = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL))) { - bp->b_error = retval; - bp->b_flags |= B_ERROR; - biodone(bp); - return (retval); - } - if ((long)bp->b_blkno == -1) - clrbuf(bp); - } - if ((long)bp->b_blkno == -1) { - biodone(bp); - return (0); + return (retval); + } + + /* + * If we don't already know the filesystem relative block + * number then get it using VOP_BMAP(). If VOP_BMAP() + * returns the block number as -1 then we've got a hole in + * the file. Although HFS filesystems don't create files with + * holes, invalidating of subranges of the file (lazy zero + * filling) may create such a situation. + */ + if (bp->b_blkno == bp->b_lblkno) { + offset = (off_t) bp->b_lblkno * + (off_t) GetLogicalBlockSize(vp); + + if ((retval = VOP_CMAP(vp, offset, bp->b_bcount, + &bp->b_blkno, &bytes_contig, NULL))) { + bp->b_error = retval; + bp->b_flags |= B_ERROR; + biodone(bp); + return (retval); + } + if (bytes_contig < bp->b_bcount) + { + /* + * We were asked to read a block that wasn't + * contiguous, so we have to read each of the + * pieces and copy them into the buffer. + * Since ordinary file I/O goes through + * cluster_io (which won't ask us for + * discontiguous data), this is probably an + * attempt to read or write metadata. + */ + return hfs_strategy_fragmented(bp); + } + if ((long)bp->b_blkno == -1) + clrbuf(bp); + } + if ((long)bp->b_blkno == -1) { + biodone(bp); + return (0); + } + if (bp->b_validend == 0) { + /* + * Record the exact size of the I/O transfer about to + * be made: + */ + bp->b_validend = bp->b_bcount; + } } - if (bp->b_validend == 0) { - /* Record the exact size of the I/O transfer about to be made: */ - DBG_ASSERT(bp->b_validoff == 0); - bp->b_validend = bp->b_bcount; - DBG_ASSERT(bp->b_dirtyoff == 0); - }; - } - vp = hp->h_meta->h_devvp; - bp->b_dev = vp->v_rdev; - DBG_IO(("\t\t>>>%s: continuing w/ vp: 0x%x with logBlk Ox%X and phyBlk Ox%X\n", funcname, (u_int)vp, bp->b_lblkno, bp->b_blkno)); - - return VOCALL (vp->v_op, VOFFSET(vop_strategy), ap); -} - - -/* -#% reallocblks vp L L L -# - vop_reallocblks { - IN struct vnode *vp; - IN struct cluster_save *buflist; - - */ - -int -hfs_reallocblks(ap) -struct vop_reallocblks_args /* { - struct vnode *a_vp; - struct cluster_save *a_buflist; -} */ *ap; -{ - DBG_FUNC_NAME("hfs_reallocblks"); - DBG_VOP_LOCKS_DECL(1); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); - - DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS); + vp = cp->c_devvp; + bp->b_dev = vp->v_rdev; - /* Currently no support for clustering */ /* XXX */ - DBG_VOP_LOCKS_TEST(ENOSPC); - return (ENOSPC); + return VOCALL (vp->v_op, VOFFSET(vop_strategy), ap); } - /* # #% truncate vp L L L @@ -1405,275 +1267,259 @@ vop_truncate { IN struct ucred *cred; IN struct proc *p; }; - * Truncate the hfsnode hp to at most length size, freeing (or adding) the + * Truncate a cnode to at most length size, freeing (or adding) the * disk blocks. */ int hfs_truncate(ap) - struct vop_truncate_args /* { - struct vnode *a_vp; - off_t a_length; - int a_flags; - struct ucred *a_cred; - struct proc *a_p; - } */ *ap; + struct vop_truncate_args /* { + struct vnode *a_vp; + off_t a_length; + int a_flags; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; { - register struct vnode *vp = ap->a_vp; - register struct hfsnode *hp = VTOH(vp); - off_t length = ap->a_length; - long vflags; - struct timeval tv; - int retval; - FCB *fcb; - off_t bytesToAdd; - off_t actualBytesAdded; - DBG_FUNC_NAME("hfs_truncate"); - DBG_VOP_LOCKS_DECL(1); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); - DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS); - -#if HFS_DIAGNOSTIC - debug_check_blocksizes(ap->a_vp); -#endif + register struct vnode *vp = ap->a_vp; + register struct cnode *cp = VTOC(vp); + struct filefork *fp = VTOF(vp); + off_t length; + long vflags; + struct timeval tv; + int retval; + off_t bytesToAdd; + off_t actualBytesAdded; + off_t filebytes; + u_long fileblocks; + int blksize; + + if (vp->v_type != VREG && vp->v_type != VLNK) + return (EISDIR); /* cannot truncate an HFS directory! */ + + length = ap->a_length; + blksize = VTOVCB(vp)->blockSize; + fileblocks = fp->ff_blocks; + filebytes = (off_t)fileblocks * (off_t)blksize; + + KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 7)) | DBG_FUNC_START, + (int)length, (int)fp->ff_size, (int)filebytes, 0, 0); + + if (length < 0) + return (EINVAL); - fcb = HTOFCB(hp); + if ((!ISHFSPLUS(VTOVCB(vp))) && (length > (off_t)MAXHFSFILESIZE)) + return (EFBIG); - KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 7)) | DBG_FUNC_START, - (int)length, fcb->fcbEOF, fcb->fcbPLen, 0, 0); - if (length < 0) { - DBG_VOP_LOCKS_TEST(EINVAL); - return (EINVAL); - } + tv = time; + retval = E_NONE; - if ((!ISHFSPLUS(VTOVCB(vp))) && (length > (off_t)MAXHFSFILESIZE)) { - DBG_VOP_LOCKS_TEST(EFBIG); - return (EFBIG); - } + /* + * We cannot just check if fp->ff_size == length (as an optimization) + * since there may be extra physical blocks that also need truncation. + */ +#if QUOTA + if (retval = hfs_getinoquota(cp)) + return(retval); +#endif /* QUOTA */ - if (vp->v_type != VREG && vp->v_type != VLNK) { - DBG_VOP_LOCKS_TEST(EISDIR); - return (EISDIR); /* hfs doesn't support truncating of directories */ - } + /* + * Lengthen the size of the file. We must ensure that the + * last byte of the file is allocated. Since the smallest + * value of ff_size is 0, length will be at least 1. + */ + if (length > fp->ff_size) { +#if QUOTA + retval = hfs_chkdq(cp, (int64_t)(roundup(length - filebytes, fp->ff_clumpsize)), + ap->a_cred, 0); + if (retval) + goto Err_Exit; +#endif /* QUOTA */ + /* + * If we don't have enough physical space then + * we need to extend the physical size. + */ + if (length > filebytes) { + int eflags; - tv = time; - retval = E_NONE; - - DBG_RW(("%s: truncate from Ox%lX to Ox%X bytes\n", funcname, fcb->fcbPLen, length)); + /* All or nothing and don't round up to clumpsize. */ + eflags = kEFAllMask | kEFNoClumpMask; - /* - * we cannot just check if fcb->fcbEOF == length (as an optimization) - * since there may be extra physical blocks that also need truncation - */ + if (suser(ap->a_cred, NULL) != 0) + eflags |= kEFReserveMask; /* keep a reserve */ - /* - * Lengthen the size of the file. We must ensure that the - * last byte of the file is allocated. Since the smallest - * value of fcbEOF is 0, length will be at least 1. - */ - if (length > fcb->fcbEOF) { - off_t filePosition; - daddr_t logBlockNo; - long logBlockSize; - long blkOffset; - off_t bytestoclear; - int blockZeroCount; - struct buf *bp=NULL; + /* lock extents b-tree (also protects volume bitmap) */ + retval = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p); + if (retval) + goto Err_Exit; - /* - * If we don't have enough physical space then - * we need to extend the physical size. - */ - if (length > fcb->fcbPLen) { - /* lock extents b-tree (also protects volume bitmap) */ - retval = hfs_metafilelocking(HTOHFS(hp), kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p); - if (retval) - goto Err_Exit; - - while ((length > fcb->fcbPLen) && (retval == E_NONE)) { - bytesToAdd = length - fcb->fcbPLen; - retval = MacToVFSError( - ExtendFileC (HTOVCB(hp), - fcb, + while ((length > filebytes) && (retval == E_NONE)) { + bytesToAdd = length - filebytes; + retval = MacToVFSError(ExtendFileC(VTOVCB(vp), + (FCB*)fp, bytesToAdd, 0, - kEFAllMask, /* allocate all requested bytes or none */ + eflags, &actualBytesAdded)); - if (actualBytesAdded == 0 && retval == E_NONE) { - if (length > fcb->fcbPLen) - length = fcb->fcbPLen; - break; + filebytes = (off_t)fp->ff_blocks * (off_t)blksize; + if (actualBytesAdded == 0 && retval == E_NONE) { + if (length > filebytes) + length = filebytes; + break; + } + } /* endwhile */ + (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, ap->a_p); + if (retval) + goto Err_Exit; + + KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 7)) | DBG_FUNC_NONE, + (int)length, (int)fp->ff_size, (int)filebytes, 0, 0); } - } - (void) hfs_metafilelocking(HTOHFS(hp), kHFSExtentsFileID, LK_RELEASE, ap->a_p); - if (retval) - goto Err_Exit; - - DBG_ASSERT(length <= fcb->fcbPLen); - KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 7)) | DBG_FUNC_NONE, - (int)length, fcb->fcbEOF, fcb->fcbPLen, 0, 0); - } - if (! (ap->a_flags & IO_NOZEROFILL)) { - - if (UBCISVALID(vp) && retval == E_NONE) { - struct rl_entry *invalid_range; - int devBlockSize; - off_t zero_limit; + if (!(ap->a_flags & IO_NOZEROFILL)) { + if (UBCINFOEXISTS(vp) && retval == E_NONE) { + struct rl_entry *invalid_range; + int devBlockSize; + off_t zero_limit; - zero_limit = (fcb->fcbEOF + (PAGE_SIZE_64 - 1)) & ~PAGE_MASK_64; - if (length < zero_limit) zero_limit = length; - - if (length > fcb->fcbEOF) { - /* Extending the file: time to fill out the current last page w. zeroes? */ - if ((fcb->fcbEOF & PAGE_MASK_64) && - (rl_scan(&hp->h_invalidranges, - fcb->fcbEOF & ~PAGE_MASK_64, - fcb->fcbEOF - 1, - &invalid_range) == RL_NOOVERLAP)) { + zero_limit = (fp->ff_size + (PAGE_SIZE_64 - 1)) & ~PAGE_MASK_64; + if (length < zero_limit) zero_limit = length; + + if (length > fp->ff_size) { + /* Extending the file: time to fill out the current last page w. zeroes? */ + if ((fp->ff_size & PAGE_MASK_64) && + (rl_scan(&fp->ff_invalidranges, fp->ff_size & ~PAGE_MASK_64, + fp->ff_size - 1, &invalid_range) == RL_NOOVERLAP)) { /* There's some valid data at the start of the (current) last page of the file, so zero out the remainder of that page to ensure the entire page contains valid data. Since there is no invalid range possible past the (current) eof, there's no need to remove anything from the invalid range list before calling cluster_write(): */ - VOP_DEVBLOCKSIZE(hp->h_meta->h_devvp, &devBlockSize); - retval = cluster_write(vp, (struct uio *) 0, fcb->fcbEOF, zero_limit, - fcb->fcbEOF, (off_t)0, devBlockSize, (ap->a_flags & IO_SYNC) | IO_HEADZEROFILL); + VOP_DEVBLOCKSIZE(cp->c_devvp, &devBlockSize); + retval = cluster_write(vp, (struct uio *) 0, fp->ff_size, zero_limit, + fp->ff_size, (off_t)0, devBlockSize, + (ap->a_flags & IO_SYNC) | IO_HEADZEROFILL | IO_NOZERODIRTY); if (retval) goto Err_Exit; /* Merely invalidate the remaining area, if necessary: */ - if (length > zero_limit) rl_add(zero_limit, length - 1, &hp->h_invalidranges); - } else { + if (length > zero_limit) { + rl_add(zero_limit, length - 1, &fp->ff_invalidranges); + cp->c_zftimeout = time.tv_sec + ZFTIMELIMIT; + } + } else { /* The page containing the (current) eof is invalid: just add the remainder of the page to the invalid list, along with the area being newly allocated: */ - rl_add(fcb->fcbEOF, length - 1, &hp->h_invalidranges); - }; - } - } else { - -#if 0 - /* - * zero out any new logical space... - */ - bytestoclear = length - fcb->fcbEOF; - filePosition = fcb->fcbEOF; + rl_add(fp->ff_size, length - 1, &fp->ff_invalidranges); + cp->c_zftimeout = time.tv_sec + ZFTIMELIMIT; + }; + } + } else { + panic("hfs_truncate: invoked on non-UBC object?!"); + }; + } + cp->c_flag |= C_UPDATE; + fp->ff_size = length; - while (bytestoclear > 0) { - logBlockNo = (daddr_t)(filePosition / PAGE_SIZE_64); - blkOffset = (long)(filePosition & PAGE_MASK_64); + if (UBCISVALID(vp)) + ubc_setsize(vp, fp->ff_size); /* XXX check errors */ - if (((off_t)(fcb->fcbPLen) - ((off_t)logBlockNo * (off_t)PAGE_SIZE)) < PAGE_SIZE_64) - logBlockSize = (off_t)(fcb->fcbPLen) - ((off_t)logBlockNo * PAGE_SIZE_64); - else - logBlockSize = PAGE_SIZE; - - if (logBlockSize < blkOffset) - panic("hfs_truncate: bad logBlockSize computed\n"); - - blockZeroCount = MIN(bytestoclear, logBlockSize - blkOffset); + } else { /* Shorten the size of the file */ - if (blkOffset == 0 && ((bytestoclear >= logBlockSize) || filePosition >= fcb->fcbEOF)) { - bp = getblk(vp, logBlockNo, logBlockSize, 0, 0, BLK_WRITE); - retval = 0; - - } else { - retval = bread(vp, logBlockNo, logBlockSize, ap->a_cred, &bp); - if (retval) { - brelse(bp); - goto Err_Exit; - } - } - bzero((char *)bp->b_data + blkOffset, blockZeroCount); - - bp->b_flags |= B_DIRTY | B_AGE; - - if (ap->a_flags & IO_SYNC) - VOP_BWRITE(bp); - else if (logBlockNo % 32) - bawrite(bp); - else - VOP_BWRITE(bp); /* wait after we issue 32 requests */ + if (fp->ff_size > length) { + /* + * Any buffers that are past the truncation point need to be + * invalidated (to maintain buffer cache consistency). For + * simplicity, we invalidate all the buffers by calling vinvalbuf. + */ + if (UBCISVALID(vp)) + ubc_setsize(vp, length); /* XXX check errors */ - bytestoclear -= blockZeroCount; - filePosition += blockZeroCount; - } -#else - panic("hfs_truncate: invoked on non-UBC object?!"); -#endif - }; - } - fcb->fcbEOF = length; + vflags = ((length > 0) ? V_SAVE : 0) | V_SAVEMETA; + retval = vinvalbuf(vp, vflags, ap->a_cred, ap->a_p, 0, 0); + + /* Any space previously marked as invalid is now irrelevant: */ + rl_remove(length, fp->ff_size - 1, &fp->ff_invalidranges); + } - if (UBCISVALID(vp)) - ubc_setsize(vp, (off_t)fcb->fcbEOF); /* XXX check errors */ + /* + * Account for any unmapped blocks. Note that the new + * file length can still end up with unmapped blocks. + */ + if (fp->ff_unallocblocks > 0) { + u_int32_t finalblks; - } else { /* Shorten the size of the file */ + /* lock extents b-tree */ + retval = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, + LK_EXCLUSIVE, ap->a_p); + if (retval) + goto Err_Exit; - if (fcb->fcbEOF > length) { - /* - * Any buffers that are past the truncation point need to be - * invalidated (to maintain buffer cache consistency). For - * simplicity, we invalidate all the buffers by calling vinvalbuf. - */ - if (UBCISVALID(vp)) - ubc_setsize(vp, (off_t)length); /* XXX check errors */ + VTOVCB(vp)->loanedBlocks -= fp->ff_unallocblocks; + cp->c_blocks -= fp->ff_unallocblocks; + fp->ff_blocks -= fp->ff_unallocblocks; + fp->ff_unallocblocks = 0; + + finalblks = (length + blksize - 1) / blksize; + if (finalblks > fp->ff_blocks) { + /* calculate required unmapped blocks */ + fp->ff_unallocblocks = finalblks - fp->ff_blocks; + VTOVCB(vp)->loanedBlocks += fp->ff_unallocblocks; + cp->c_blocks += fp->ff_unallocblocks; + fp->ff_blocks += fp->ff_unallocblocks; + } + (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, + LK_RELEASE, ap->a_p); + } - vflags = ((length > 0) ? V_SAVE : 0) | V_SAVEMETA; - retval = vinvalbuf(vp, vflags, ap->a_cred, ap->a_p, 0, 0); - - /* Any space previously marked as invalid is now irrelevant: */ - rl_remove(length, fcb->fcbEOF - 1, &hp->h_invalidranges); - } + /* + * For a TBE process the deallocation of the file blocks is + * delayed until the file is closed. And hfs_close calls + * truncate with the IO_NDELAY flag set. So when IO_NDELAY + * isn't set, we make sure this isn't a TBE process. + */ + if ((ap->a_flags & IO_NDELAY) || (!ISSET(ap->a_p->p_flag, P_TBE))) { +#if QUOTA + off_t savedbytes = ((off_t)fp->ff_blocks * (off_t)blksize); +#endif /* QUOTA */ + /* lock extents b-tree (also protects volume bitmap) */ + retval = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p); + if (retval) + goto Err_Exit; + + if (fp->ff_unallocblocks == 0) + retval = MacToVFSError(TruncateFileC(VTOVCB(vp), + (FCB*)fp, length, false)); - /* - * For a TBE process the deallocation of the file blocks is - * delayed until the file is closed. And hfs_close calls - * truncate with the IO_NDELAY flag set. So when IO_NDELAY - * isn't set, we make sure this isn't a TBE process. - */ - if ((ap->a_flags & IO_NDELAY) || (!ISSET(ap->a_p->p_flag, P_TBE))) { - - /* lock extents b-tree (also protects volume bitmap) */ - retval = hfs_metafilelocking(HTOHFS(hp), kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p); - if (retval) - goto Err_Exit; - retval = MacToVFSError( - TruncateFileC( - HTOVCB(hp), - fcb, - length, - false)); - (void) hfs_metafilelocking(HTOHFS(hp), kHFSExtentsFileID, LK_RELEASE, ap->a_p); - if (retval) - goto Err_Exit; + (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, ap->a_p); + filebytes = (off_t)fp->ff_blocks * (off_t)blksize; + if (retval) + goto Err_Exit; +#if QUOTA + /* These are bytesreleased */ + (void) hfs_chkdq(cp, (int64_t)-(savedbytes - filebytes), NOCRED, 0); +#endif /* QUOTA */ + } + /* Only set update flag if the logical length changes */ + if (fp->ff_size != length) + cp->c_flag |= C_UPDATE; + fp->ff_size = length; } - fcb->fcbEOF = length; - - if (fcb->fcbFlags & fcbModifiedMask) - hp->h_nodeflags |= IN_MODIFIED; - } - hp->h_nodeflags |= IN_CHANGE | IN_UPDATE; - retval = VOP_UPDATE(vp, &tv, &tv, MNT_WAIT); - if (retval) { - DBG_ERR(("Could not update truncate")); + cp->c_flag |= C_CHANGE; + retval = VOP_UPDATE(vp, &tv, &tv, MNT_WAIT); + if (retval) { KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 7)) | DBG_FUNC_NONE, -1, -1, -1, retval, 0); - } -Err_Exit:; + } -#if HFS_DIAGNOSTIC - debug_check_blocksizes(ap->a_vp); -#endif +Err_Exit: - KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 7)) | DBG_FUNC_END, - (int)length, fcb->fcbEOF, fcb->fcbPLen, retval, 0); + KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 7)) | DBG_FUNC_END, + (int)length, (int)fp->ff_size, (int)filebytes, retval, 0); - DBG_VOP_LOCKS_TEST(retval); - return (retval); + return (retval); } @@ -1691,131 +1537,121 @@ vop_allocate { IN struct ucred *cred; IN struct proc *p; }; - * allocate the hfsnode hp to at most length size + * allocate a cnode to at most length size */ int hfs_allocate(ap) - struct vop_allocate_args /* { - struct vnode *a_vp; - off_t a_length; - u_int32_t a_flags; - off_t *a_bytesallocated; - off_t a_offset; - struct ucred *a_cred; - struct proc *a_p; - } */ *ap; + struct vop_allocate_args /* { + struct vnode *a_vp; + off_t a_length; + u_int32_t a_flags; + off_t *a_bytesallocated; + off_t a_offset; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; { - register struct vnode *vp = ap->a_vp; - register struct hfsnode *hp = VTOH(vp); - off_t length = ap->a_length; - off_t startingPEOF; - off_t moreBytesRequested; - off_t actualBytesAdded; - long vflags; - struct timeval tv; - int retval, retval2; - FCB *fcb; - UInt32 blockHint; - UInt32 extendFlags =0; /* For call to ExtendFileC */ - DBG_FUNC_NAME("hfs_allocate"); - DBG_VOP_LOCKS_DECL(1); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); - DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS); - - /* Set the number of bytes allocated to 0 so that the caller will know that we - did nothing. ExtendFileC will fill this in for us if we actually allocate space */ - - *(ap->a_bytesallocated) = 0; - fcb = HTOFCB(hp); - - /* Now for some error checking */ - - if (length < (off_t)0) { - DBG_VOP_LOCKS_TEST(EINVAL); - return (EINVAL); - } - - if (vp->v_type != VREG && vp->v_type != VLNK) { - DBG_VOP_LOCKS_TEST(EISDIR); - return (EISDIR); /* hfs doesn't support truncating of directories */ - } - - if ((ap->a_flags & ALLOCATEFROMVOL) && (length <= fcb->fcbPLen)) - return (EINVAL); + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); + struct filefork *fp = VTOF(vp); + off_t length = ap->a_length; + off_t startingPEOF; + off_t moreBytesRequested; + off_t actualBytesAdded; + off_t filebytes; + u_long fileblocks; + long vflags; + struct timeval tv; + int retval, retval2; + UInt32 blockHint; + UInt32 extendFlags =0; /* For call to ExtendFileC */ + + *(ap->a_bytesallocated) = 0; + fileblocks = fp->ff_blocks; + filebytes = (off_t)fileblocks * (off_t)VTOVCB(vp)->blockSize; + + if (length < (off_t)0) + return (EINVAL); + if (vp->v_type != VREG && vp->v_type != VLNK) + return (EISDIR); + if ((ap->a_flags & ALLOCATEFROMVOL) && (length <= filebytes)) + return (EINVAL); - /* Fill in the flags word for the call to Extend the file */ + /* Fill in the flags word for the call to Extend the file */ - if (ap->a_flags & ALLOCATECONTIG) { + if (ap->a_flags & ALLOCATECONTIG) extendFlags |= kEFContigMask; - } - if (ap->a_flags & ALLOCATEALL) { + if (ap->a_flags & ALLOCATEALL) extendFlags |= kEFAllMask; - } - tv = time; - retval = E_NONE; - blockHint = 0; - startingPEOF = fcb->fcbPLen; + if (suser(ap->a_cred, NULL) != 0) + extendFlags |= kEFReserveMask; - if (ap->a_flags & ALLOCATEFROMPEOF) { - length += fcb->fcbPLen; - } + tv = time; + retval = E_NONE; + blockHint = 0; + startingPEOF = filebytes; - if (ap->a_flags & ALLOCATEFROMVOL) - blockHint = ap->a_offset / HTOVCB(hp)->blockSize; + if (ap->a_flags & ALLOCATEFROMPEOF) + length += filebytes; + else if (ap->a_flags & ALLOCATEFROMVOL) + blockHint = ap->a_offset / VTOVCB(vp)->blockSize; - /* If no changes are necesary, then we're done */ - if (fcb->fcbPLen == length) - goto Std_Exit; + /* If no changes are necesary, then we're done */ + if (filebytes == length) + goto Std_Exit; - /* - * Lengthen the size of the file. We must ensure that the - * last byte of the file is allocated. Since the smallest - * value of fcbPLen is 0, length will be at least 1. - */ - if (length > fcb->fcbPLen) { - moreBytesRequested = length - fcb->fcbPLen; + /* + * Lengthen the size of the file. We must ensure that the + * last byte of the file is allocated. Since the smallest + * value of filebytes is 0, length will be at least 1. + */ + if (length > filebytes) { + moreBytesRequested = length - filebytes; +#if QUOTA + retval = hfs_chkdq(cp, (int64_t)(roundup(moreBytesRequested, fp->ff_clumpsize)), + ap->a_cred, 0); + if (retval) + return (retval); + +#endif /* QUOTA */ /* lock extents b-tree (also protects volume bitmap) */ - retval = hfs_metafilelocking(HTOHFS(hp), kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p); + retval = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p); if (retval) goto Err_Exit; - retval = MacToVFSError( - ExtendFileC(HTOVCB(hp), - fcb, - moreBytesRequested, - blockHint, - extendFlags, - &actualBytesAdded)); + retval = MacToVFSError(ExtendFileC(VTOVCB(vp), + (FCB*)fp, + moreBytesRequested, + blockHint, + extendFlags, + &actualBytesAdded)); *(ap->a_bytesallocated) = actualBytesAdded; - - (void) hfs_metafilelocking(HTOHFS(hp), kHFSExtentsFileID, LK_RELEASE, ap->a_p); - - DBG_ASSERT(length <= fcb->fcbPLen); + filebytes = (off_t)fp->ff_blocks * (off_t)VTOVCB(vp)->blockSize; + (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, ap->a_p); /* * if we get an error and no changes were made then exit * otherwise we must do the VOP_UPDATE to reflect the changes */ - if (retval && (startingPEOF == fcb->fcbPLen)) goto Err_Exit; + if (retval && (startingPEOF == filebytes)) + goto Err_Exit; - /* - * Adjust actualBytesAdded to be allocation block aligned, not - * clump size aligned. - * NOTE: So what we are reporting does not affect reality - * until the file is closed, when we truncate the file to allocation - * block size. - */ - + /* + * Adjust actualBytesAdded to be allocation block aligned, not + * clump size aligned. + * NOTE: So what we are reporting does not affect reality + * until the file is closed, when we truncate the file to allocation + * block size. + */ if ((actualBytesAdded != 0) && (moreBytesRequested < actualBytesAdded)) *(ap->a_bytesallocated) = roundup(moreBytesRequested, (off_t)VTOVCB(vp)->blockSize); - } else { /* Shorten the size of the file */ + } else { /* Shorten the size of the file */ - if (fcb->fcbEOF > length) { + if (fp->ff_size > length) { /* * Any buffers that are past the truncation point need to be * invalidated (to maintain buffer cache consistency). For @@ -1825,51 +1661,50 @@ int hfs_allocate(ap) (void) vinvalbuf(vp, vflags, ap->a_cred, ap->a_p, 0, 0); } - /* lock extents b-tree (also protects volume bitmap) */ - retval = hfs_metafilelocking(HTOHFS(hp), kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p); - if (retval) goto Err_Exit; + /* lock extents b-tree (also protects volume bitmap) */ + retval = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p); + if (retval) goto Err_Exit; - retval = MacToVFSError( + retval = MacToVFSError( TruncateFileC( - HTOVCB(hp), - fcb, + VTOVCB(vp), + (FCB*)fp, length, false)); - (void) hfs_metafilelocking(HTOHFS(hp), kHFSExtentsFileID, LK_RELEASE, ap->a_p); - + (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, ap->a_p); + filebytes = (off_t)fp->ff_blocks * (off_t)VTOVCB(vp)->blockSize; /* * if we get an error and no changes were made then exit * otherwise we must do the VOP_UPDATE to reflect the changes */ - if (retval && (startingPEOF == fcb->fcbPLen)) goto Err_Exit; - if (fcb->fcbFlags & fcbModifiedMask) - hp->h_nodeflags |= IN_MODIFIED; - - DBG_ASSERT(length <= fcb->fcbPLen) // DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG + if (retval && (startingPEOF == filebytes)) goto Err_Exit; +#if QUOTA + /* These are bytesreleased */ + (void) hfs_chkdq(cp, (int64_t)-((startingPEOF - filebytes)), NOCRED,0); +#endif /* QUOTA */ - if (fcb->fcbEOF > fcb->fcbPLen) { - fcb->fcbEOF = fcb->fcbPLen; + if (fp->ff_size > filebytes) { + fp->ff_size = filebytes; if (UBCISVALID(vp)) - ubc_setsize(vp, (off_t)fcb->fcbEOF); /* XXX check errors */ - } - } + ubc_setsize(vp, fp->ff_size); /* XXX check errors */ + } + } Std_Exit: - hp->h_nodeflags |= IN_CHANGE | IN_UPDATE; + cp->c_flag |= C_CHANGE | C_UPDATE; retval2 = VOP_UPDATE(vp, &tv, &tv, MNT_WAIT); - if (retval == 0) retval = retval2; - + if (retval == 0) + retval = retval2; Err_Exit: - DBG_VOP_LOCKS_TEST(retval); - return (retval); + return (retval); } - - -/* pagein for HFS filesystem, similar to hfs_read(), but without cluster_read() */ +/* + * pagein for HFS filesystem + */ int hfs_pagein(ap) struct vop_pagein_args /* { @@ -1882,44 +1717,19 @@ hfs_pagein(ap) int a_flags } */ *ap; { - register struct vnode *vp; - struct hfsnode *hp; - FCB *fcb; - int devBlockSize = 0; - int retval; - - DBG_FUNC_NAME("hfs_pagein"); - DBG_VOP_LOCKS_DECL(1); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_PRINT_VNODE_INFO(vp);DBG_VOP_CONT(("\n")); - DBG_VOP_LOCKS_INIT(0,vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS); - - vp = ap->a_vp; - hp = VTOH(vp); - fcb = HTOFCB(hp); - - if (vp->v_type != VREG && vp->v_type != VLNK) - panic("hfs_pagein: vp not UBC type\n"); - - DBG_VOP(("\tfile size Ox%X\n", (u_int)fcb->fcbEOF)); - DBG_VOP(("\tstarting at offset Ox%X of file, length Ox%X\n", (u_int)ap->a_f_offset, (u_int)ap->a_size)); - -#if HFS_DIAGNOSTIC - debug_check_blocksizes(vp); -#endif - - VOP_DEVBLOCKSIZE(hp->h_meta->h_devvp, &devBlockSize); + register struct vnode *vp = ap->a_vp; + int devBlockSize = 0; + int error; - retval = cluster_pagein(vp, ap->a_pl, ap->a_pl_offset, ap->a_f_offset, - ap->a_size, (off_t)fcb->fcbEOF, devBlockSize, - ap->a_flags); + if (vp->v_type != VREG && vp->v_type != VLNK) + panic("hfs_pagein: vp not UBC type\n"); -#if HFS_DIAGNOSTIC - debug_check_blocksizes(vp); -#endif - DBG_VOP_LOCKS_TEST(retval); + VOP_DEVBLOCKSIZE(VTOC(vp)->c_devvp, &devBlockSize); - return (retval); + error = cluster_pagein(vp, ap->a_pl, ap->a_pl_offset, ap->a_f_offset, + ap->a_size, (off_t)VTOF(vp)->ff_size, devBlockSize, + ap->a_flags); + return (error); } /* @@ -1937,43 +1747,28 @@ hfs_pageout(ap) int a_flags } */ *ap; { - struct vnode *vp = ap->a_vp; - struct hfsnode *hp = VTOH(vp); - FCB *fcb = HTOFCB(hp); - int retval; - int devBlockSize = 0; - off_t end_of_range; - - DBG_FUNC_NAME("hfs_pageout"); - DBG_VOP_LOCKS_DECL(1); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_PRINT_VNODE_INFO(vp);DBG_VOP_CONT(("\n")); - DBG_VOP(("\thfsnode 0x%x (%s)\n", (u_int)hp, H_NAME(hp))); - DBG_VOP(("\tstarting at offset Ox%lX of file, length Ox%lX\n", - (UInt32)ap->a_f_offset, (UInt32)ap->a_size)); - - DBG_VOP_LOCKS_INIT(0, vp, VOPDBG_LOCKED, - VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS); - -#if HFS_DIAGNOSTIC - debug_check_blocksizes(vp); -#endif + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); + struct filefork *fp = VTOF(vp); + int retval; + int devBlockSize = 0; + off_t end_of_range; + off_t filesize; if (UBCINVALID(vp)) panic("hfs_pageout: Not a VREG: vp=%x", vp); - VOP_DEVBLOCKSIZE(hp->h_meta->h_devvp, &devBlockSize); - + VOP_DEVBLOCKSIZE(cp->c_devvp, &devBlockSize); + filesize = fp->ff_size; end_of_range = ap->a_f_offset + ap->a_size - 1; - if (end_of_range >= (off_t)fcb->fcbEOF) - end_of_range = (off_t)(fcb->fcbEOF - 1); - - if (ap->a_f_offset < (off_t)fcb->fcbEOF) - rl_remove(ap->a_f_offset, end_of_range, &hp->h_invalidranges); + if (end_of_range >= filesize) + end_of_range = (off_t)(filesize - 1); + if (ap->a_f_offset < filesize) + rl_remove(ap->a_f_offset, end_of_range, &fp->ff_invalidranges); retval = cluster_pageout(vp, ap->a_pl, ap->a_pl_offset, ap->a_f_offset, ap->a_size, - (off_t)fcb->fcbEOF, devBlockSize, ap->a_flags); + filesize, devBlockSize, ap->a_flags); /* * If we successfully wrote any data, and we are not the superuser @@ -1981,13 +1776,8 @@ hfs_pageout(ap) * tampering. */ if (retval == 0 && ap->a_cred && ap->a_cred->cr_uid != 0) - hp->h_meta->h_mode &= ~(ISUID | ISGID); + cp->c_mode &= ~(S_ISUID | S_ISGID); -#if HFS_DIAGNOSTIC - debug_check_blocksizes(vp); -#endif - - DBG_VOP_LOCKS_TEST(retval); return (retval); } @@ -1999,39 +1789,42 @@ hfs_pageout(ap) */ int hfs_bwrite(ap) -struct vop_bwrite_args /* { - struct buf *a_bp; -} */ *ap; + struct vop_bwrite_args /* { + struct buf *a_bp; + } */ *ap; { - register struct buf *bp = ap->a_bp; - register struct vnode *vp = bp->b_vp; - BlockDescriptor block; - int retval = 0; - - DBG_FUNC_NAME("hfs_bwrite"); - + int retval = 0; #if BYTE_ORDER == LITTLE_ENDIAN - /* Trap B-Tree writes */ - if ((H_FILEID(VTOH(vp)) == kHFSExtentsFileID) || - (H_FILEID(VTOH(vp)) == kHFSCatalogFileID)) { - - /* Swap if the B-Tree node is in native byte order */ - if (((UInt16 *)((char *)bp->b_data + bp->b_bcount - 2))[0] == 0x000e) { - /* Prepare the block pointer */ - block.blockHeader = bp; - block.buffer = bp->b_data; - block.blockReadFromDisk = (bp->b_flags & B_CACHE) == 0; /* not found in cache ==> came from disk */ - block.blockSize = bp->b_bcount; + register struct buf *bp = ap->a_bp; + register struct vnode *vp = bp->b_vp; + BlockDescriptor block; + + /* Trap B-Tree writes */ + if ((VTOC(vp)->c_fileid == kHFSExtentsFileID) || + (VTOC(vp)->c_fileid == kHFSCatalogFileID)) { + + /* Swap if the B-Tree node is in native byte order */ + if (((UInt16 *)((char *)bp->b_data + bp->b_bcount - 2))[0] == 0x000e) { + /* Prepare the block pointer */ + block.blockHeader = bp; + block.buffer = bp->b_data; + /* not found in cache ==> came from disk */ + block.blockReadFromDisk = (bp->b_flags & B_CACHE) == 0; + block.blockSize = bp->b_bcount; - /* Endian un-swap B-Tree node */ - SWAP_BT_NODE (&block, ISHFSPLUS (VTOVCB(vp)), H_FILEID(VTOH(vp)), 1); - } + /* Endian un-swap B-Tree node */ + SWAP_BT_NODE (&block, ISHFSPLUS (VTOVCB(vp)), VTOC(vp)->c_fileid, 1); + } - /* We don't check to make sure that it's 0x0e00 because it could be all zeros */ - } + /* We don't check to make sure that it's 0x0e00 because it could be all zeros */ + } #endif + /* This buffer shouldn't be locked anymore but if it is clear it */ + if (ISSET(ap->a_bp->b_flags, B_LOCKED)) { + CLR(ap->a_bp->b_flags, B_LOCKED); + printf("hfs_bwrite: called with lock bit set\n"); + } + retval = vn_bwrite (ap); - retval = vn_bwrite (ap); - - return (retval); + return (retval); } diff --git a/bsd/hfs/hfs_search.c b/bsd/hfs/hfs_search.c index 979e52414..0c7638fbe 100644 --- a/bsd/hfs/hfs_search.c +++ b/bsd/hfs/hfs_search.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1997-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -18,14 +18,8 @@ * under the License. * * @APPLE_LICENSE_HEADER_END@ - */ -/* @(#)hfs_search.c - * - * (c) 1997-2000 Apple Computer, Inc. All Rights Reserved - * * - * MODIFICATION HISTORY: - * 04-May-1999 Don Brady Split off from hfs_vnodeops.c. + * @(#)hfs_search.c */ #include @@ -44,6 +38,10 @@ #include "hfs.h" #include "hfs_dbg.h" +#include "hfs_catalog.h" +#include "hfs_attrlist.h" +#include "hfs_endian.h" + #include "hfscommon/headers/FileMgrInternal.h" #include "hfscommon/headers/CatalogPrivate.h" #include "hfscommon/headers/HFSUnicodeWrappers.h" @@ -51,20 +49,59 @@ #include "hfscommon/headers/BTreeScanner.h" -static int UnpackSearchAttributeBlock(struct vnode *vp, struct attrlist *alist, searchinfospec_t *searchInfo, void *attributeBuffer); +/* Search criterea. */ +struct directoryInfoSpec +{ + u_long numFiles; +}; + +struct fileInfoSpec +{ + off_t dataLogicalLength; + off_t dataPhysicalLength; + off_t resourceLogicalLength; + off_t resourcePhysicalLength; +}; + +struct searchinfospec +{ + u_char name[kHFSPlusMaxFileNameBytes]; + u_long nameLength; + char attributes; // see IM:Files 2-100 + u_long nodeID; + u_long parentDirID; + struct timespec creationDate; + struct timespec modificationDate; + struct timespec changeDate; + struct timespec accessDate; + struct timespec lastBackupDate; + u_long finderInfo[8]; + uid_t uid; + gid_t gid; + mode_t mask; + struct fileInfoSpec f; + struct directoryInfoSpec d; +}; +typedef struct searchinfospec searchinfospec_t; -Boolean CheckCriteria( ExtendedVCB *vcb, - u_long searchBits, - struct attrlist *attrList, - CatalogNodeData *cnp, - CatalogKey *key, - searchinfospec_t *searchInfo1, - searchinfospec_t *searchInfo2, - Boolean lookForDup); +static void ResolveHardlink(ExtendedVCB *vcb, HFSPlusCatalogFile *recp); -static int CheckAccess(CatalogNodeData *cnp, CatalogKey *key, struct proc *p); -static int InsertMatch(struct vnode *vp, struct uio *a_uio, CatalogNodeData *cnp, +static int UnpackSearchAttributeBlock(struct vnode *vp, struct attrlist *alist, + searchinfospec_t *searchInfo, void *attributeBuffer); + +static int CheckCriteria( ExtendedVCB *vcb, + u_long searchBits, + struct attrlist *attrList, + CatalogRecord *rec, + CatalogKey *key, + searchinfospec_t *searchInfo1, + searchinfospec_t *searchInfo2, + Boolean lookForDup ); + +static int CheckAccess(ExtendedVCB *vcb, CatalogKey *key, struct proc *p); + +static int InsertMatch(struct vnode *vp, struct uio *a_uio, CatalogRecord *rec, CatalogKey *key, struct attrlist *returnAttrList, void *attributesBuffer, void *variableBuffer, u_long bufferSize, u_long * nummatches ); @@ -82,12 +119,29 @@ static Boolean CompareWideRange( u_int64_t val, u_int64_t low, u_int64_t high ) return( (val >= low) && (val <= high) ); } //#define CompareRange(val, low, high) ((val >= low) && (val <= high)) - + +#if 1 // Installer workaround (2940423) static Boolean IsTargetName( searchinfospec_t * searchInfoPtr, Boolean isHFSPlus ); +#endif // Installer workaround + +extern int cat_convertkey( + struct hfsmount *hfsmp, + CatalogKey *key, + CatalogRecord * recp, + struct cat_desc *descp); + +extern void cat_convertattr( + struct hfsmount *hfsmp, + CatalogRecord * recp, + struct cat_attr *attrp, + struct cat_fork *datafp, + struct cat_fork *rsrcfp); +extern int resolvelink(struct hfsmount *hfsmp, u_long linkref, + struct HFSPlusCatalogFile *recp); /************************************************************************/ -/* Entry for searchfs() */ +/* Entry for searchfs() */ /************************************************************************/ #define errSearchBufferFull 101 /* Internal search errors */ @@ -106,51 +160,46 @@ vop_searchfs { int hfs_search( ap ) -struct vop_searchfs_args *ap; /* - struct vnodeop_desc *a_desc; - struct vnode *a_vp; - void *a_searchparams1; - void *a_searchparams2; - struct attrlist *a_searchattrs; - u_long a_maxmatches; - struct timeval *a_timelimit; - struct attrlist *a_returnattrs; - u_long *a_nummatches; - u_long a_scriptcode; - u_long a_options; - struct uio *a_uio; - struct searchstate *a_searchstate; -*/ + struct vop_searchfs_args *ap; /* + struct vnodeop_desc *a_desc; + struct vnode *a_vp; + void *a_searchparams1; + void *a_searchparams2; + struct attrlist *a_searchattrs; + u_long a_maxmatches; + struct timeval *a_timelimit; + struct attrlist *a_returnattrs; + u_long *a_nummatches; + u_long a_scriptcode; + u_long a_options; + struct uio *a_uio; + struct searchstate *a_searchstate; + */ { - FCB* catalogFCB; - searchinfospec_t searchInfo1; - searchinfospec_t searchInfo2; - void *attributesBuffer; - void *variableBuffer; - short recordSize; - short operation; - u_long fixedBlockSize; - u_long eachReturnBufferSize; - struct proc *p = current_proc(); - CatalogNodeData myCNodeData; - CatalogNodeData * myCNodeDataPtr; - CatalogKey * myCurrentKeyPtr; - CatalogRecord * myCurrentDataPtr; - CatPosition * myCatPositionPtr; - BTScanState myBTScanState; - Boolean timerExpired = false; - Boolean doQuickExit = false; - u_long lastNodeNum = 0XFFFFFFFF; - ExtendedVCB *vcb = VTOVCB(ap->a_vp); - int err = E_NONE; - int isHFSPlus; + ExtendedVCB *vcb = VTOVCB(ap->a_vp); + FCB * catalogFCB; + searchinfospec_t searchInfo1; + searchinfospec_t searchInfo2; + void *attributesBuffer; + void *variableBuffer; + u_long fixedBlockSize; + u_long eachReturnBufferSize; + struct proc *p = current_proc(); + int err = E_NONE; + int isHFSPlus; + int timerExpired = false; + int doQuickExit = false; + CatalogKey * myCurrentKeyPtr; + CatalogRecord * myCurrentDataPtr; + CatPosition * myCatPositionPtr; + BTScanState myBTScanState; /* XXX Parameter check a_searchattrs? */ *(ap->a_nummatches) = 0; - if ( ap->a_options & ~SRCHFS_VALIDOPTIONSMASK ) - return( EINVAL ); + if (ap->a_options & ~SRCHFS_VALIDOPTIONSMASK) + return (EINVAL); if (ap->a_uio->uio_resid <= 0) return (EINVAL); @@ -158,14 +207,16 @@ struct vop_searchfs_args *ap; /* isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord); /* UnPack the search boundries, searchInfo1, searchInfo2 */ - err = UnpackSearchAttributeBlock( ap->a_vp, ap->a_searchattrs, &searchInfo1, ap->a_searchparams1 ); + err = UnpackSearchAttributeBlock(ap->a_vp, ap->a_searchattrs, + &searchInfo1, ap->a_searchparams1); if (err) return err; - err = UnpackSearchAttributeBlock( ap->a_vp, ap->a_searchattrs, &searchInfo2, ap->a_searchparams2 ); + err = UnpackSearchAttributeBlock(ap->a_vp, ap->a_searchattrs, + &searchInfo2, ap->a_searchparams2); if (err) return err; - fixedBlockSize = sizeof(u_long) + AttributeBlockSize( ap->a_returnattrs ); /* u_long for length longword */ + fixedBlockSize = sizeof(u_long) + hfs_attrblksize(ap->a_returnattrs); /* u_long for length longword */ eachReturnBufferSize = fixedBlockSize; - + if ( ap->a_returnattrs->commonattr & ATTR_CMN_NAME ) /* XXX should be more robust! */ eachReturnBufferSize += kHFSPlusMaxFileNameBytes + 1; @@ -173,25 +224,24 @@ struct vop_searchfs_args *ap; /* variableBuffer = (void*)((char*) attributesBuffer + fixedBlockSize); /* Lock catalog b-tree */ - err = hfs_metafilelocking( VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_SHARED, p ); - if ( err != E_NONE ) { + err = hfs_metafilelocking(VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_SHARED, p); + if (err) goto ExitThisRoutine; - }; - catalogFCB = VTOFCB( vcb->catalogRefNum ); + catalogFCB = GetFileControlBlock(vcb->catalogRefNum); myCurrentKeyPtr = NULL; myCurrentDataPtr = NULL; myCatPositionPtr = (CatPosition *)ap->a_searchstate; if (ap->a_options & SRCHFS_START) { /* Starting a new search. */ - /* make sure our meta data is synced up */ - err = VOP_FSYNC(vcb->catalogRefNum, NOCRED, MNT_WAIT, p); + /* Make sure the on-disk Catalog file is current */ + (void) VOP_FSYNC(vcb->catalogRefNum, NOCRED, MNT_WAIT, p); ap->a_options &= ~SRCHFS_START; bzero( (caddr_t)myCatPositionPtr, sizeof( *myCatPositionPtr ) ); err = BTScanInitialize(catalogFCB, 0, 0, 0, kCatSearchBufferSize, &myBTScanState); - -#if 1 // Installer workaround + +#if 1 // Installer workaround (2940423) // hack to get around installer problems when the installer expects search results // to be in key order. At this point the problem appears to be limited to // searches for "Library". The idea here is to go get the "Library" at root @@ -216,23 +266,13 @@ struct vop_searchfs_args *ap; /* btrec.itemCount = 1; btrec.itemSize = sizeof( rec ); - result = BTSearchRecord( catalogFCB, &iterator, kInvalidMRUCacheKey, - &btrec, &reclen, &iterator ); + result = BTSearchRecord( catalogFCB, &iterator, &btrec, &reclen, &iterator ); if ( result == E_NONE ) { - if ( isHFSPlus ) { - // HFSPlus vols have CatalogRecords that map exactly to CatalogNodeData so there is no need - // to copy. - myCNodeDataPtr = (CatalogNodeData *) &rec; - } else { - CopyCatalogNodeData( vcb, &rec, &myCNodeData ); - myCNodeDataPtr = &myCNodeData; - } - - if (CheckCriteria(vcb, ap->a_options, ap->a_searchattrs, myCNodeDataPtr, + if (CheckCriteria(vcb, ap->a_options, ap->a_searchattrs, &rec, keyp, &searchInfo1, &searchInfo2, false) && - CheckAccess(myCNodeDataPtr, keyp, ap->a_uio->uio_procp)) { + CheckAccess(vcb, keyp, ap->a_uio->uio_procp)) { - result = InsertMatch(ap->a_vp, ap->a_uio, myCNodeDataPtr, + result = InsertMatch(ap->a_vp, ap->a_uio, &rec, keyp, ap->a_returnattrs, attributesBuffer, variableBuffer, eachReturnBufferSize, ap->a_nummatches); @@ -249,22 +289,23 @@ struct vop_searchfs_args *ap; /* myCatPositionPtr->recordsFound, kCatSearchBufferSize, &myBTScanState); -#if 0 /* Make sure Catalog hasn't changed. */ if (err == 0 && myCatPositionPtr->writeCount != myBTScanState.btcb->writeCount) { myCatPositionPtr->writeCount = myBTScanState.btcb->writeCount; err = EBUSY; /* catChangedErr */ } -#endif } /* Unlock catalog b-tree */ (void) hfs_metafilelocking(VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_RELEASE, p); if (err) goto ExitThisRoutine; +#if 1 // Installer workaround (2940423) if ( doQuickExit ) goto QuickExit; +#endif // Installer workaround + /* * Check all the catalog btree records... * return the attributes for matching items @@ -279,23 +320,17 @@ struct vop_searchfs_args *ap; /* if (err) break; - if ( isHFSPlus ) { - // HFSPlus vols have CatalogRecords that map exactly to CatalogNodeData so there is no need - // to copy. - myCNodeDataPtr = (CatalogNodeData *) myCurrentDataPtr; - } else { - CopyCatalogNodeData( vcb, myCurrentDataPtr, &myCNodeData ); - myCNodeDataPtr = &myCNodeData; - } - - if (CheckCriteria(vcb, ap->a_options, ap->a_searchattrs, myCNodeDataPtr, - myCurrentKeyPtr, &searchInfo1, &searchInfo2, true) && - CheckAccess(myCNodeDataPtr, myCurrentKeyPtr, ap->a_uio->uio_procp)) { - - err = InsertMatch(ap->a_vp, ap->a_uio, myCNodeDataPtr, - myCurrentKeyPtr, ap->a_returnattrs, - attributesBuffer, variableBuffer, - eachReturnBufferSize, ap->a_nummatches); + /* Resolve any hardlinks */ + if (isHFSPlus) + ResolveHardlink(vcb, (HFSPlusCatalogFile *) myCurrentDataPtr); + + if (CheckCriteria( vcb, ap->a_options, ap->a_searchattrs, myCurrentDataPtr, + myCurrentKeyPtr, &searchInfo1, &searchInfo2, true ) + && CheckAccess(vcb, myCurrentKeyPtr, ap->a_uio->uio_procp)) { + err = InsertMatch(ap->a_vp, ap->a_uio, myCurrentDataPtr, + myCurrentKeyPtr, ap->a_returnattrs, + attributesBuffer, variableBuffer, + eachReturnBufferSize, ap->a_nummatches); if (err) { /* * The last match didn't fit so come back @@ -305,6 +340,7 @@ struct vop_searchfs_args *ap; /* --myBTScanState.recordNum; break; } + if (*(ap->a_nummatches) >= ap->a_maxmatches) break; } @@ -322,13 +358,14 @@ struct vop_searchfs_args *ap; /* timerExpired = true; } } + QuickExit: /* Update catalog position */ myCatPositionPtr->writeCount = myBTScanState.btcb->writeCount; - BTScanTerminate(&myBTScanState, &myCatPositionPtr->nextNode, - &myCatPositionPtr->nextRecord, - &myCatPositionPtr->recordsFound); + BTScanTerminate(&myBTScanState, &myCatPositionPtr->nextNode, + &myCatPositionPtr->nextRecord, + &myCatPositionPtr->recordsFound); if ( err == E_NONE ) { err = EAGAIN; /* signal to the user to call searchfs again */ @@ -350,9 +387,22 @@ ExitThisRoutine: } +static void +ResolveHardlink(ExtendedVCB *vcb, HFSPlusCatalogFile *recp) +{ + if ((recp->recordType == kHFSPlusFileRecord) + && (SWAP_BE32(recp->userInfo.fdType) == kHardLinkFileType) + && (SWAP_BE32(recp->userInfo.fdCreator) == kHFSPlusCreator) + && ((to_bsd_time(recp->createDate) == vcb->vcbCrDate) || + (to_bsd_time(recp->createDate) == VCBTOHFS(vcb)->hfs_metadata_createdate))) { + (void) resolvelink(VCBTOHFS(vcb), recp->bsdInfo.special.iNodeNum, recp); + } +} + + static Boolean CompareMasked(const UInt32 *thisValue, const UInt32 *compareData, - const UInt32 *compareMask, UInt32 count) + const UInt32 *compareMask, UInt32 count) { Boolean matched; UInt32 i; @@ -414,37 +464,94 @@ ComparePartialPascalName ( register ConstStr31Param str, register ConstStr31Para /* * Check to see if caller has access rights to this item */ + static int -CheckAccess(CatalogNodeData *cnp, CatalogKey *key, struct proc *p) +CheckAccess(ExtendedVCB *theVCBPtr, CatalogKey *theKeyPtr, struct proc *theProcPtr) { - return (1); + Boolean isHFSPlus; + int myErr; + int myResult; + HFSCatalogNodeID myNodeID; + unsigned long myPerms; + hfsmount_t * my_hfsmountPtr; + struct cat_desc my_cat_desc; + struct cat_attr my_cat_attr; + + myResult = 0; /* default to "no access" */ + my_cat_desc.cd_nameptr = NULL; + my_cat_desc.cd_namelen = 0; + + if ( theProcPtr->p_ucred->cr_uid == 0 ) { + myResult = 1; /* allow access */ + goto ExitThisRoutine; /* root always has access */ + } + + my_hfsmountPtr = VCBTOHFS( theVCBPtr ); + isHFSPlus = ( theVCBPtr->vcbSigWord == kHFSPlusSigWord ); + if ( isHFSPlus ) + myNodeID = theKeyPtr->hfsPlus.parentID; + else + myNodeID = theKeyPtr->hfs.parentID; + + while ( myNodeID >= kRootDirID ) { + /* now go get catalog data for this directory */ + myErr = hfs_metafilelocking( my_hfsmountPtr, kHFSCatalogFileID, LK_SHARED, theProcPtr ); + if ( myErr ) + goto ExitThisRoutine; /* no access */ + + myErr = cat_idlookup( my_hfsmountPtr, myNodeID, &my_cat_desc, &my_cat_attr, NULL ); + (void) hfs_metafilelocking( my_hfsmountPtr, kHFSCatalogFileID, LK_RELEASE, theProcPtr ); + if ( myErr ) + goto ExitThisRoutine; /* no access */ + + myNodeID = my_cat_desc.cd_parentcnid; /* move up the hierarchy */ + myPerms = DerivePermissionSummary(my_cat_attr.ca_uid, my_cat_attr.ca_gid, + my_cat_attr.ca_mode, my_hfsmountPtr->hfs_mp, + theProcPtr->p_ucred, theProcPtr ); + cat_releasedesc( &my_cat_desc ); + + if ( (myPerms & X_OK) == 0 ) + goto ExitThisRoutine; /* no access */ + } + + myResult = 1; /* allow access */ + +ExitThisRoutine: + cat_releasedesc( &my_cat_desc ); + return ( myResult ); + } -Boolean -CheckCriteria( ExtendedVCB *vcb, - u_long searchBits, - struct attrlist *attrList, - CatalogNodeData *cnp, +static int +CheckCriteria( ExtendedVCB *vcb, + u_long searchBits, + struct attrlist *attrList, + CatalogRecord *rec, CatalogKey *key, - searchinfospec_t *searchInfo1, + searchinfospec_t *searchInfo1, searchinfospec_t *searchInfo2, Boolean lookForDup ) { Boolean matched, atleastone; Boolean isHFSPlus; attrgroup_t searchAttributes; + struct cat_attr c_attr = {0}; + struct cat_fork datafork; + struct cat_fork rsrcfork; isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord); - switch (cnp->cnd_type) { - case kCatalogFolderNode: + switch (rec->recordType) { + case kHFSFolderRecord: + case kHFSPlusFolderRecord: if ( (searchBits & SRCHFS_MATCHDIRS) == 0 ) { /* If we are NOT searching folders */ matched = false; goto TestDone; } break; - case kCatalogFileNode: + case kHFSFileRecord: + case kHFSPlusFileRecord: if ( (searchBits & SRCHFS_MATCHFILES) == 0 ) { /* If we are NOT searching files */ matched = false; goto TestDone; @@ -483,7 +590,7 @@ CheckCriteria( ExtendedVCB *vcb, matched = (FastRelString(key->hfs.nodeName, (u_char*)searchInfo1->name) == 0); } -#if 1 // Installer workaround +#if 1 // Installer workaround (2940423) if ( lookForDup ) { HFSCatalogNodeID parentID; if (isHFSPlus) @@ -496,15 +603,19 @@ CheckCriteria( ExtendedVCB *vcb, matched = false; } #endif // Installer workaround - + if ( matched == false || (searchBits & ~SRCHFS_MATCHPARTIALNAMES) == 0 ) goto TestDone; /* no match, or nothing more to compare */ atleastone = true; } + + /* Convert catalog record into cat_attr format. */ + cat_convertattr(VCBTOHFS(vcb), rec, &c_attr, &datafork, &rsrcfork); /* Now that we have a record worth searching, see if it matches the search attributes */ - if (cnp->cnd_type == kCatalogFileNode) { + if (rec->recordType == kHFSFileRecord || + rec->recordType == kHFSPlusFileRecord) { if ((attrList->fileattr & ~ATTR_FILE_VALIDMASK) != 0) { /* attr we do know about */ matched = false; goto TestDone; @@ -515,7 +626,7 @@ CheckCriteria( ExtendedVCB *vcb, /* File logical length (data fork) */ if ( searchAttributes & ATTR_FILE_DATALENGTH ) { matched = CompareWideRange( - cnp->cnd_datafork.logicalSize, + datafork.cf_size, searchInfo1->f.dataLogicalLength, searchInfo2->f.dataLogicalLength); if (matched == false) goto TestDone; @@ -525,7 +636,7 @@ CheckCriteria( ExtendedVCB *vcb, /* File physical length (data fork) */ if ( searchAttributes & ATTR_FILE_DATAALLOCSIZE ) { matched = CompareWideRange( - cnp->cnd_datafork.totalBlocks * vcb->blockSize, + (u_int64_t)datafork.cf_blocks * (u_int64_t)vcb->blockSize, searchInfo1->f.dataPhysicalLength, searchInfo2->f.dataPhysicalLength); if (matched == false) goto TestDone; @@ -535,7 +646,7 @@ CheckCriteria( ExtendedVCB *vcb, /* File logical length (resource fork) */ if ( searchAttributes & ATTR_FILE_RSRCLENGTH ) { matched = CompareWideRange( - cnp->cnd_rsrcfork.logicalSize, + rsrcfork.cf_size, searchInfo1->f.resourceLogicalLength, searchInfo2->f.resourceLogicalLength); if (matched == false) goto TestDone; @@ -545,7 +656,7 @@ CheckCriteria( ExtendedVCB *vcb, /* File physical length (resource fork) */ if ( searchAttributes & ATTR_FILE_RSRCALLOCSIZE ) { matched = CompareWideRange( - cnp->cnd_rsrcfork.totalBlocks * vcb->blockSize, + (u_int64_t)rsrcfork.cf_blocks * (u_int64_t)vcb->blockSize, searchInfo1->f.resourcePhysicalLength, searchInfo2->f.resourcePhysicalLength); if (matched == false) goto TestDone; @@ -553,13 +664,14 @@ CheckCriteria( ExtendedVCB *vcb, } } else { - atleastone = true; /* to match SRCHFS_MATCHDIRS */ + atleastone = true; /* to match SRCHFS_MATCHFILES */ } } /* * Check the directory attributes */ - else if (cnp->cnd_type == kCatalogFolderNode) { + else if (rec->recordType == kHFSFolderRecord || + rec->recordType == kHFSPlusFolderRecord) { if ((attrList->dirattr & ~ATTR_DIR_VALIDMASK) != 0) { /* attr we do know about */ matched = false; goto TestDone; @@ -569,7 +681,9 @@ CheckCriteria( ExtendedVCB *vcb, /* Directory valence */ if ( searchAttributes & ATTR_DIR_ENTRYCOUNT ) { - matched = CompareRange(cnp->cnd_valence, searchInfo1->d.numFiles, searchInfo2->d.numFiles ); + matched = CompareRange(c_attr.ca_entries, + searchInfo1->d.numFiles, + searchInfo2->d.numFiles ); if (matched == false) goto TestDone; atleastone = true; } @@ -584,10 +698,11 @@ CheckCriteria( ExtendedVCB *vcb, */ searchAttributes = attrList->commonattr; if ( (searchAttributes & ATTR_CMN_VALIDMASK) != 0 ) { - /* node ID */ if ( searchAttributes & ATTR_CMN_OBJID ) { - matched = CompareRange( cnp->cnd_nodeID, searchInfo1->nodeID, searchInfo2->nodeID ); + matched = CompareRange(c_attr.ca_fileid, + searchInfo1->nodeID, + searchInfo2->nodeID ); if (matched == false) goto TestDone; atleastone = true; } @@ -601,7 +716,8 @@ CheckCriteria( ExtendedVCB *vcb, else parentID = key->hfs.parentID; - matched = CompareRange( parentID, searchInfo1->parentDirID, searchInfo2->parentDirID ); + matched = CompareRange(parentID, searchInfo1->parentDirID, + searchInfo2->parentDirID ); if (matched == false) goto TestDone; atleastone = true; } @@ -609,72 +725,88 @@ CheckCriteria( ExtendedVCB *vcb, /* Finder Info & Extended Finder Info where extFinderInfo is last 32 bytes */ if ( searchAttributes & ATTR_CMN_FNDRINFO ) { UInt32 *thisValue; - thisValue = (UInt32 *) &cnp->cnd_finderInfo; + thisValue = (UInt32 *) &c_attr.ca_finderinfo; /* * Note: ioFlFndrInfo and ioDrUsrWds have the same offset in search info, so * no need to test the object type here. */ - matched = CompareMasked( thisValue, (UInt32 *) &searchInfo1->finderInfo, - (UInt32 *) &searchInfo2->finderInfo, 8 ); /* 8 * UInt32 */ + matched = CompareMasked(thisValue, + (UInt32 *)&searchInfo1->finderInfo, + (UInt32 *) &searchInfo2->finderInfo, 8); if (matched == false) goto TestDone; atleastone = true; } /* Create date */ if ( searchAttributes & ATTR_CMN_CRTIME ) { - matched = CompareRange(to_bsd_time(cnp->cnd_createDate), - searchInfo1->creationDate.tv_sec, searchInfo2->creationDate.tv_sec ); + matched = CompareRange(c_attr.ca_itime, + searchInfo1->creationDate.tv_sec, + searchInfo2->creationDate.tv_sec); if (matched == false) goto TestDone; atleastone = true; } /* Mod date */ if ( searchAttributes & ATTR_CMN_MODTIME ) { - matched = CompareRange(to_bsd_time(cnp->cnd_contentModDate), - searchInfo1->modificationDate.tv_sec, searchInfo2->modificationDate.tv_sec ); + matched = CompareRange(c_attr.ca_mtime, + searchInfo1->modificationDate.tv_sec, + searchInfo2->modificationDate.tv_sec); if (matched == false) goto TestDone; atleastone = true; } /* Change Time */ if ( searchAttributes & ATTR_CMN_CHGTIME ) { - matched = CompareRange(to_bsd_time(cnp->cnd_attributeModDate), - searchInfo1->changeDate.tv_sec, searchInfo2->changeDate.tv_sec ); + matched = CompareRange(c_attr.ca_ctime, + searchInfo1->changeDate.tv_sec, + searchInfo2->changeDate.tv_sec); if (matched == false) goto TestDone; atleastone = true; } + /* Access date */ + if ( searchAttributes & ATTR_CMN_ACCTIME ) { + matched = CompareRange(c_attr.ca_atime, + searchInfo1->accessDate.tv_sec, + searchInfo2->accessDate.tv_sec); + if (matched == false) goto TestDone; + atleastone = true; + } + /* Backup date */ if ( searchAttributes & ATTR_CMN_BKUPTIME ) { - matched = CompareRange(to_bsd_time(cnp->cnd_backupDate), - searchInfo1->lastBackupDate.tv_sec, searchInfo2->lastBackupDate.tv_sec ); + matched = CompareRange(c_attr.ca_btime, + searchInfo1->lastBackupDate.tv_sec, + searchInfo2->lastBackupDate.tv_sec); if (matched == false) goto TestDone; atleastone = true; } /* User ID */ if ( searchAttributes & ATTR_CMN_OWNERID ) { - matched = CompareRange( cnp->cnd_ownerID, searchInfo1->uid, searchInfo2->uid ); + matched = CompareRange(c_attr.ca_uid, + searchInfo1->uid, searchInfo2->uid); if (matched == false) goto TestDone; atleastone = true; } /* Group ID */ if ( searchAttributes & ATTR_CMN_GRPID ) { - matched = CompareRange( cnp->cnd_groupID, searchInfo1->gid, searchInfo2->gid ); + matched = CompareRange(c_attr.ca_gid, + searchInfo1->gid, searchInfo2->gid); if (matched == false) goto TestDone; atleastone = true; } /* mode */ if ( searchAttributes & ATTR_CMN_ACCESSMASK ) { - matched = CompareRange( (u_long)cnp->cnd_mode, - (u_long)searchInfo1->mask, (u_long)searchInfo2->mask ); + matched = CompareRange((u_long)c_attr.ca_mode, + (u_long)searchInfo1->mask, + (u_long)searchInfo2->mask); if (matched == false) goto TestDone; atleastone = true; } - } /* If we got here w/o matching any, then set to false */ @@ -697,99 +829,58 @@ TestDone: * Adds another record to the packed array for output */ static int -InsertMatch( struct vnode *root_vp, struct uio *a_uio, CatalogNodeData *cnp, +InsertMatch( struct vnode *root_vp, struct uio *a_uio, CatalogRecord *rec, CatalogKey *key, struct attrlist *returnAttrList, void *attributesBuffer, void *variableBuffer, u_long bufferSize, u_long * nummatches ) { int err; void *rovingAttributesBuffer; void *rovingVariableBuffer; - struct hfsCatalogInfo catalogInfo; u_long packedBufferSize; ExtendedVCB *vcb = VTOVCB(root_vp); Boolean isHFSPlus = vcb->vcbSigWord == kHFSPlusSigWord; u_long privateDir = VTOHFS(root_vp)->hfs_private_metadata_dir; + struct attrblock attrblk; + struct cat_desc c_desc = {0}; + struct cat_attr c_attr = {0}; + struct cat_fork datafork; + struct cat_fork rsrcfork; rovingAttributesBuffer = (char*)attributesBuffer + sizeof(u_long); /* Reserve space for length field */ rovingVariableBuffer = variableBuffer; - - INIT_CATALOGDATA(&catalogInfo.nodeData, 0); - catalogInfo.nodeData.cnd_iNodeNumCopy = 0; - /* The packing call below expects a struct hfsCatalogInfo */ - bcopy(cnp, &catalogInfo.nodeData, (cnp->cnd_type == kCatalogFileNode) ? - sizeof(HFSPlusCatalogFile) : sizeof(HFSPlusCatalogFolder)); + /* Convert catalog record into cat_attr format. */ + cat_convertattr(VTOHFS(root_vp), rec, &c_attr, &datafork, &rsrcfork); - catalogInfo.nodeData.cnm_parID = isHFSPlus ? key->hfsPlus.parentID : key->hfs.parentID; + /* hide our private meta data directory */ + if ((privateDir != 0) && (c_attr.ca_fileid == privateDir)) { + err = 0; + goto exit; + } - /* hide open files that have been deleted */ - if ((privateDir != 0) && (catalogInfo.nodeData.cnm_parID == privateDir)) - return (0); + if (returnAttrList->commonattr & ATTR_CMN_NAME) { + cat_convertkey(VTOHFS(root_vp), key, rec, &c_desc); + } else { + c_desc.cd_cnid = c_attr.ca_fileid; + if (isHFSPlus) + c_desc.cd_parentcnid = key->hfsPlus.parentID; + else + c_desc.cd_parentcnid = key->hfs.parentID; + } - /* hide our private meta data directory */ - if ((privateDir != 0) && (catalogInfo.nodeData.cnd_nodeID == privateDir)) - return (0); - - if ( returnAttrList->commonattr & ATTR_CMN_NAME ) { - size_t utf8len = 0; - - catalogInfo.nodeData.cnm_nameptr = catalogInfo.nodeData.cnm_namespace; - - /* Return result in UTF-8 */ - if ( isHFSPlus ) { - err = utf8_encodestr(key->hfsPlus.nodeName.unicode, - key->hfsPlus.nodeName.length * sizeof(UniChar), - catalogInfo.nodeData.cnm_namespace, - &utf8len, - MAXHFSVNODELEN + 1, ':', 0); - if (err == ENAMETOOLONG) { - utf8len = utf8_encodelen(key->hfsPlus.nodeName.unicode, - key->hfsPlus.nodeName.length * sizeof(UniChar), ':', 0); - MALLOC(catalogInfo.nodeData.cnm_nameptr, char *, utf8len+1, M_TEMP, M_WAITOK); - catalogInfo.nodeData.cnm_flags |= kCatNameIsAllocated; - err = utf8_encodestr(key->hfsPlus.nodeName.unicode, - key->hfsPlus.nodeName.length * sizeof(UniChar), - catalogInfo.nodeData.cnm_nameptr, - &utf8len, - utf8len + 1, ':', 0); - } - } else { - err = hfs_to_utf8(vcb, - key->hfs.nodeName, - MAXHFSVNODELEN + 1, - (ByteCount*) &utf8len, - catalogInfo.nodeData.cnm_namespace); - if (err == ENAMETOOLONG) { - MALLOC(catalogInfo.nodeData.cnm_nameptr, char *, utf8len+1, M_TEMP, M_WAITOK); - catalogInfo.nodeData.cnm_flags |= kCatNameIsAllocated; - err = hfs_to_utf8(vcb, - key->hfs.nodeName, - utf8len + 1, - (ByteCount*) &utf8len, - catalogInfo.nodeData.cnm_nameptr); - } else if (err) { - /* - * When an HFS name cannot be encoded with the current - * volume encoding we use MacRoman as a fallback. - */ - err = mac_roman_to_utf8(key->hfs.nodeName, MAXHFSVNODELEN + 1, - (ByteCount*) &utf8len, - catalogInfo.nodeData.cnm_namespace); - } - } - catalogInfo.nodeData.cnm_length = utf8len; - if (err && (catalogInfo.nodeData.cnm_flags & kCatNameIsAllocated)) - { - DisposePtr(catalogInfo.nodeData.cnm_nameptr); - catalogInfo.nodeData.cnm_flags &= ~kCatNameIsAllocated; - catalogInfo.nodeData.cnm_nameptr = catalogInfo.nodeData.cnm_namespace; - catalogInfo.nodeData.cnm_namespace[0] = 0; - } + /* hide open files that have been deleted */ + if ((privateDir != 0) && (c_desc.cd_parentcnid == privateDir)) { + err = 0; + goto exit; } - PackCatalogInfoAttributeBlock( returnAttrList,root_vp, &catalogInfo, &rovingAttributesBuffer, &rovingVariableBuffer ); + attrblk.ab_attrlist = returnAttrList; + attrblk.ab_attrbufpp = &rovingAttributesBuffer; + attrblk.ab_varbufpp = &rovingVariableBuffer; + attrblk.ab_flags = 0; + attrblk.ab_blocksize = 0; - CLEAN_CATALOGDATA(&catalogInfo.nodeData); + hfs_packattrblk(&attrblk, VTOHFS(root_vp), NULL, &c_desc, &c_attr, &datafork, &rsrcfork); packedBufferSize = (char*)rovingVariableBuffer - (char*)attributesBuffer; @@ -801,6 +892,8 @@ InsertMatch( struct vnode *root_vp, struct uio *a_uio, CatalogNodeData *cnp, *((u_long *)attributesBuffer) = packedBufferSize; /* Store length of fixed + var block */ err = uiomove( (caddr_t)attributesBuffer, packedBufferSize, a_uio ); /* XXX should be packedBufferSize */ +exit: + cat_releasedesc(&c_desc); return( err ); } @@ -881,6 +974,10 @@ UnpackSearchAttributeBlock( struct vnode *vp, struct attrlist *alist, searchinfo searchInfo->changeDate = *((struct timespec *)attributeBuffer); ++((struct timespec *)attributeBuffer); } + if ( a & ATTR_CMN_ACCTIME ) { + searchInfo->accessDate = *((struct timespec *)attributeBuffer); + ++((struct timespec *)attributeBuffer); + } if ( a & ATTR_CMN_BKUPTIME ) { searchInfo->lastBackupDate = *((struct timespec *)attributeBuffer); ++((struct timespec *)attributeBuffer); @@ -939,6 +1036,7 @@ UnpackSearchAttributeBlock( struct vnode *vp, struct attrlist *alist, searchinfo } +#if 1 // Installer workaround (2940423) /* this routine was added as part of the work around where some installers would fail */ /* because they incorrectly assumed search results were in some kind of order. */ /* This routine is used to indentify the problematic target. At this point we */ @@ -972,5 +1070,5 @@ static Boolean IsTargetName( searchinfospec_t * searchInfoPtr, Boolean isHFSPlus return( false ); } /* IsTargetName */ - +#endif // Installer workaround diff --git a/bsd/hfs/hfs_vfsops.c b/bsd/hfs/hfs_vfsops.c index 395b4b1e1..c92af136d 100644 --- a/bsd/hfs/hfs_vfsops.c +++ b/bsd/hfs/hfs_vfsops.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -59,46 +59,10 @@ * hfs_vfsops.c * derived from @(#)ufs_vfsops.c 8.8 (Berkeley) 5/20/95 * - * (c) Copyright 1997-1998 Apple Computer, Inc. All rights reserved. + * (c) Copyright 1997-2002 Apple Computer, Inc. All rights reserved. * * hfs_vfsops.c -- VFS layer for loadable HFS file system. * - * HISTORY - * 9-Nov-1999 Don Brady Fix error handling in hfs_unmount [2399157]. - * 9-Sep-1999 Don Brady Clear system file fcbModified flags in hfs_flushvolumeheader/hfs_flushMDB. - * 5-Aug-1999 Pat Dirks Moved special HFS flag from f_fsid.val[0][0] to mount flags (#2293117). - * 23-Jul-1999 Pat Dirks Added special-case code for root's parent directory in hfs_vget (#2263664). - * 9-Jun-1999 Don Brady Fix hfs_mount for reload and read-only downgrade cases. - * 2-Jun-1999 Don Brady Fix hfs_statfs to return correct f_files value. - * 4-May-1999 Don Brady Remove obsolete loadable module code. - * 22-Mar-1999 Don Brady Hide our private meta data in hfs_vget. - * 18-May-1999 Don Brady Add hfs_mountroot for HFS Plus rooting. - * 22-Mar-1999 Don Brady Hide our private meta data in hfs_vget. - * 12-Nov-1998 Pat Dirks Changed hfs_statfs to return volume's actual log. block size (#2286198). - * 22-Aug-1998 Scott Roberts Assign uid,gid, and mask for default on objects. - * 29-Jul-1998 Pat Dirks Fixed changed hfs_vget() to release complex node when retrying for data fork node. - * 27-Jul-1998 Scott Roberts Changes hfs_vget() to return data forks instead of complex. - * 14-Jul-1998 CHW Added check for use count of device node in hfs_mountfs - * 1-Jul-1998 Don Brady Always set kHFSVolumeUnmountedMask bit of vcb->vcbAtrb in hfs_unmount. - * 30-Jun-1998 Don Brady Removed hard-coded EINVAL error in hfs_mountfs (for radar #2249539). - * 24-Jun-1998 Don Brady Added setting of timezone to hfs_mount (radar #2226387). - * 4-Jun-1998 Don Brady Use VPUT/VRELE macros instead of vput/vrele. - * 6-May-1998 Scott Roberts Updated hfs_vget with kernel changes. - * 29-Apr-1998 Don Brady Update hfs_statfs to actually fill in statfs fields (radar #2227092). - * 23-Apr-1998 Pat Dirks Cleaned up code to call brelse() on errors from bread(). - * 4/20/1998 Don Brady Remove course-grained hfs metadata locking. - * 4/18/1998 Don Brady Add VCB locking. - * 4/16/1998 Don Brady hfs_unmount now flushes the volume bitmap. Add b-tree locking to hfs_vget. - * 4/8/1998 Don Brady Replace hfs_mdbupdate with hfs_flushvolumeheader and hfs_flushMDB. - * 4/8/1998 Don Brady In hfs_unmount call hfs_mdbupdate before trashing metafiles! - * 4/3/1998 Don Brady Call InitCatalogCache instead of PostInitFS. - * 4/1/1998 Don Brady Get rid of gHFSFlags, gReqstVol and gFlushOnlyFlag globals (not used). - * 3/30/1998 Don Brady In hfs_unmount use SKIPSYSTEM option on first vflush. - * 3/26/1998 Don Brady Changed hfs_unmount to call vflush before calling hfsUnmount. - * In hfs_mountfs don't mount hfs-wrapper. - * 3/19/1998 Pat Dirks Fixed bug in hfs_mount where device vnode was being - * released on way out. - * 11/14/1997 Pat Dirks Derived from hfs_vfsops.c */ #include #include @@ -110,75 +74,44 @@ #include #include #include +#include +#include + #include #include #include "hfs.h" +#include "hfs_catalog.h" +#include "hfs_cnode.h" #include "hfs_dbg.h" #include "hfs_endian.h" +#include "hfs_quota.h" #include "hfscommon/headers/FileMgrInternal.h" #include "hfscommon/headers/BTreesInternal.h" + #if HFS_DIAGNOSTIC int hfs_dbg_all = 0; -int hfs_dbg_vfs = 0; -int hfs_dbg_vop = 0; -int hfs_dbg_load = 0; -int hfs_dbg_io = 0; -int hfs_dbg_utils = 0; -int hfs_dbg_rw = 0; -int hfs_dbg_lookup = 0; -int hfs_dbg_tree = 0; int hfs_dbg_err = 0; -int hfs_dbg_test = 0; #endif -/* - * These come from IOKit/storage/IOMediaBSDClient.h - */ -#define DKIOCGETBLOCKSIZE _IOR('d', 24, u_int32_t) -#define DKIOCSETBLOCKSIZE _IOW('d', 24, u_int32_t) -#define DKIOCGETBLOCKCOUNT _IOR('d', 25, u_int64_t) - -/* - * HFS File System globals: - */ -Ptr gBufferAddress[BUFFERPTRLISTSIZE]; -struct buf *gBufferHeaderPtr[BUFFERPTRLISTSIZE]; -int gBufferListIndex; -simple_lock_data_t gBufferPtrListLock; - -//static char hfs_fs_name[MFSNAMELEN] = "hfs"; - - -/* - * Global variables defined in other modules: - */ extern struct vnodeopv_desc hfs_vnodeop_opv_desc; -extern struct vnode *hfs_vhashget(dev_t dev, UInt32 nodeID, UInt8 forkType); - -extern OSErr HFSPlusToHFSExtents( const HFSPlusExtentRecord oldExtents, HFSExtentRecord newExtents); - +extern void hfs_converterinit(void); extern void inittodr( time_t base); -extern OSErr GetVolumeNameFromCatalog(ExtendedVCB *vcb); -extern void CopyCatalogToObjectMeta(struct hfsCatalogInfo *catInfo, struct vnode *vp, struct hfsfilemeta *fm); -extern void CopyCatalogToFCB(struct hfsCatalogInfo *catInfo, struct vnode *vp); -extern void hfs_name_CatToMeta(CatalogNodeData *nodeData, struct hfsfilemeta *fm); -int hfs_changefs(struct mount *mp, struct hfs_mount_args *args, struct proc *p); -int hfs_reload(struct mount *mp, struct ucred *cred, struct proc *p); -int hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, struct hfs_mount_args *args); -int hfs_vget(struct mount *mp, void *objID, struct vnode **vpp); -void hfs_vhashinit(); -void hfs_converterinit(void); +static int hfs_changefs __P((struct mount *mp, struct hfs_mount_args *args, + struct proc *p)); +static int hfs_reload __P((struct mount *mp, struct ucred *cred, struct proc *p)); - -static int hfs_statfs(); +static int hfs_mountfs __P((struct vnode *devvp, struct mount *mp, struct proc *p, + struct hfs_mount_args *args)); +static int hfs_statfs __P((struct mount *mp, register struct statfs *sbp, + struct proc *p)); /* @@ -191,6 +124,7 @@ hfs_mountroot() struct mount *mp; struct proc *p = current_proc(); /* XXX */ struct hfsmount *hfsmp; + ExtendedVCB *vcb; int error; /* @@ -200,11 +134,14 @@ hfs_mountroot() printf("hfs_mountroot: can't setup bdevvp"); return (error); } - if ((error = vfs_rootmountalloc("hfs", "root_device", &mp))) + if ((error = vfs_rootmountalloc("hfs", "root_device", &mp))) { + vrele(rootvp); /* release the reference from bdevvp() */ return (error); + } if ((error = hfs_mountfs(rootvp, mp, p, NULL))) { mp->mnt_vfc->vfc_refcount--; vfs_unbusy(mp, p); + vrele(rootvp); /* release the reference from bdevvp() */ _FREE_ZONE(mp, sizeof (struct mount), M_MOUNT); return (error); } @@ -220,10 +157,15 @@ hfs_mountroot() hfsmp->hfs_dir_mask = (S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH); /* 0755 */ hfsmp->hfs_file_mask = (S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH); /* 0755 */ + /* Establish the free block reserve. */ + vcb = HFSTOVCB(hfsmp); + vcb->reserveBlocks = ((u_int64_t)vcb->totalBlocks * HFS_MINFREE) / 100; + vcb->reserveBlocks = MIN(vcb->reserveBlocks, HFS_MAXRESERVE / vcb->blockSize); + (void)hfs_statfs(mp, &mp->mnt_stat, p); vfs_unbusy(mp, p); - inittodr(to_bsd_time(HFSTOVCB(hfsmp)->vcbLsMod)); + inittodr(HFSTOVCB(hfsmp)->vcbLsMod); return (0); } @@ -234,8 +176,8 @@ hfs_mountroot() * mount system call */ -int -hfs_mount (mp, path, data, ndp, p) +static int +hfs_mount(mp, path, data, ndp, p) register struct mount *mp; char *path; caddr_t data; @@ -249,7 +191,6 @@ hfs_mount (mp, path, data, ndp, p) int retval = E_NONE; int flags; mode_t accessmode; - int loadconv = 0; if ((retval = copyin(data, (caddr_t)&args, sizeof(args)))) goto error_exit; @@ -272,21 +213,16 @@ hfs_mount (mp, path, data, ndp, p) if (mp->mnt_flag & MNT_FORCE) flags |= FORCECLOSE; - if ((retval = hfs_flushfiles(mp, flags))) + if ((retval = hfs_flushfiles(mp, flags, p))) goto error_exit; - hfsmp->hfs_fs_clean = 1; hfsmp->hfs_fs_ronly = 1; - if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord) - retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT); - else - retval = hfs_flushMDB(hfsmp, MNT_WAIT); + retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT, 0); /* also get the volume bitmap blocks */ if (!retval) retval = VOP_FSYNC(hfsmp->hfs_devvp, NOCRED, MNT_WAIT, p); if (retval) { - hfsmp->hfs_fs_clean = 0; hfsmp->hfs_fs_ronly = 0; goto error_exit; } @@ -310,17 +246,13 @@ hfs_mount (mp, path, data, ndp, p) } VOP_UNLOCK(devvp, 0, p); } - if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord) - retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT); - else - retval = hfs_flushMDB(hfsmp, MNT_WAIT); + retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT, 0); if (retval != E_NONE) goto error_exit; /* only change hfs_fs_ronly after a successfull write */ hfsmp->hfs_fs_ronly = 0; - hfsmp->hfs_fs_clean = 0; } if ((hfsmp->hfs_fs_ronly == 0) && @@ -413,23 +345,24 @@ error_exit: } -/* change fs mount parameters */ -int +/* Change fs mount parameters */ +static int hfs_changefs(mp, args, p) struct mount *mp; struct hfs_mount_args *args; struct proc *p; { - int retval; + int retval = 0; int namefix, permfix, permswitch; struct hfsmount *hfsmp; - struct hfsnode *hp; - mode_t hfs_file_mask; + struct cnode *cp; ExtendedVCB *vcb; - hfsCatalogInfo catInfo; register struct vnode *vp, *nvp; hfs_to_unicode_func_t get_unicode_func; unicode_to_hfs_func_t get_hfsname_func; + struct cat_desc cndesc; + struct cat_attr cnattr; + u_long old_encoding; hfsmp = VFSTOHFS(mp); vcb = HFSTOVCB(hfsmp); @@ -443,19 +376,21 @@ hfs_changefs(mp, args, p) hfsmp->hfs_unknownpermissions = ((mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) != 0); namefix = permfix = 0; - /* change the timezone (Note: this affects all hfs volumes and hfs+ volume create dates) */ + /* Change the timezone (Note: this affects all hfs volumes and hfs+ volume create dates) */ if (args->hfs_timezone.tz_minuteswest != VNOVAL) { gTimeZone = args->hfs_timezone; } - /* change the default uid, gid and/or mask */ + /* Change the default uid, gid and/or mask */ if ((args->hfs_uid != (uid_t)VNOVAL) && (hfsmp->hfs_uid != args->hfs_uid)) { hfsmp->hfs_uid = args->hfs_uid; - ++permfix; + if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord) + ++permfix; } if ((args->hfs_gid != (gid_t)VNOVAL) && (hfsmp->hfs_gid != args->hfs_gid)) { hfsmp->hfs_gid = args->hfs_gid; - ++permfix; + if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord) + ++permfix; } if (args->hfs_mask != (mode_t)VNOVAL) { if (hfsmp->hfs_dir_mask != (args->hfs_mask & ALLPERMS)) { @@ -463,17 +398,19 @@ hfs_changefs(mp, args, p) hfsmp->hfs_file_mask = args->hfs_mask & ALLPERMS; if ((args->flags != VNOVAL) && (args->flags & HFSFSMNT_NOXONFILES)) hfsmp->hfs_file_mask = (args->hfs_mask & DEFFILEMODE); - ++permfix; + if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord) + ++permfix; } } - /* change the hfs encoding value (hfs only) */ + /* Change the hfs encoding value (hfs only) */ if ((HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord) && (hfsmp->hfs_encoding != (u_long)VNOVAL) && (hfsmp->hfs_encoding != args->hfs_encoding)) { retval = hfs_getconverter(args->hfs_encoding, &get_unicode_func, &get_hfsname_func); - if (retval) goto error_exit; + if (retval) + goto exit; /* * Connect the new hfs_get_unicode converter but leave @@ -486,11 +423,13 @@ hfs_changefs(mp, args, p) * in the old converters. */ hfsmp->hfs_get_unicode = get_unicode_func; + old_encoding = hfsmp->hfs_encoding; + hfsmp->hfs_encoding = args->hfs_encoding; ++namefix; } - - if (!(namefix || permfix || permswitch)) goto exit; + if (!(namefix || permfix || permswitch)) + goto exit; /* * For each active vnode fix things that changed @@ -523,12 +462,9 @@ loop: continue; } - hp = VTOH(vp); + cp = VTOC(vp); - INIT_CATALOGDATA(&catInfo.nodeData, 0); - - catInfo.hint = kNoHint; - retval = hfs_getcatalog(vcb, H_DIRID(hp), H_NAME(hp), hp->h_meta->h_namelen, &catInfo); + retval = cat_lookup(hfsmp, &cp->c_desc, 0, &cndesc, &cnattr, NULL); /* If we couldn't find this guy skip to the next one */ if (retval) { if (namefix) @@ -538,45 +474,11 @@ loop: continue; } - H_HINT(hp) = catInfo.hint; - if (permswitch || (permfix && (hp->h_meta->h_metaflags & IN_UNSETACCESS))) { - if ((vcb->vcbSigWord == kHFSPlusSigWord) && (catInfo.nodeData.cnd_mode & IFMT)) { - if (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) { - /* - * Override the permissions as determined by the mount auguments - * in ALMOST the same way unset permissions are treated but keep - * track of whether or not the file or folder is hfs locked - * by leaving the h_pflags field unchanged from what was unpacked - * out of the catalog. - */ - hp->h_meta->h_metaflags |= IN_UNSETACCESS; - hp->h_meta->h_uid = VTOHFS(vp)->hfs_uid; - hp->h_meta->h_gid = VTOHFS(vp)->hfs_gid; - } else { - hp->h_meta->h_uid = catInfo.nodeData.cnd_ownerID; - hp->h_meta->h_gid = catInfo.nodeData.cnd_groupID; - }; - hp->h_meta->h_mode = (mode_t)catInfo.nodeData.cnd_mode; - } else { - /* - * Set the permissions as determined by the mount auguments - * but keep in account if the file or folder is hfs locked - */ - hp->h_meta->h_metaflags |= IN_UNSETACCESS; - hp->h_meta->h_uid = VTOHFS(vp)->hfs_uid; - hp->h_meta->h_gid = VTOHFS(vp)->hfs_gid; - - /* Default access is full read/write/execute: */ - hp->h_meta->h_mode &= IFMT; - hp->h_meta->h_mode |= ACCESSPERMS; /* 0777: rwxrwxrwx */ - /* ... but no more than that permitted by the mount point's: */ - if ((hp->h_meta->h_mode & IFMT) == IFDIR) { - hp->h_meta->h_mode &= IFMT | VTOHFS(vp)->hfs_dir_mask; - } else { - hp->h_meta->h_mode &= IFMT | VTOHFS(vp)->hfs_file_mask; - } - }; - }; + if (permswitch || permfix) { + cp->c_uid = cnattr.ca_uid; + cp->c_gid = cnattr.ca_gid; + cp->c_mode = cnattr.ca_mode; + } /* * If we're switching name converters then... @@ -585,41 +487,31 @@ loop: */ if (namefix) { cache_purge(vp); - hfs_name_CatToMeta(&catInfo.nodeData, hp->h_meta); + replace_desc(cp, &cndesc); - if (catInfo.nodeData.cnd_nodeID == kHFSRootFolderID) - strncpy(vcb->vcbVN, H_NAME(hp), NAME_MAX); + if (cndesc.cd_cnid == kHFSRootFolderID) { + strncpy(vcb->vcbVN, cp->c_desc.cd_nameptr, NAME_MAX); + cp->c_desc.cd_encoding = hfsmp->hfs_encoding; + } + } else { + cat_releasedesc(&cndesc); } - - CLEAN_CATALOGDATA(&catInfo.nodeData); - vput(vp); simple_lock(&mntvnode_slock); - } /* end for (vp...) */ - simple_unlock(&mntvnode_slock); - - -exit: + } /* end for (vp...) */ + simple_unlock(&mntvnode_slock); /* * If we're switching name converters we can now * connect the new hfs_get_hfsname converter and * release our interest in the old converters. */ if (namefix) { - u_long old_encoding = hfsmp->hfs_encoding; - hfsmp->hfs_get_hfsname = get_hfsname_func; - hfsmp->hfs_encoding = args->hfs_encoding; vcb->volumeNameEncodingHint = args->hfs_encoding; - (void) hfs_relconverter(old_encoding); } - - return (0); - -error_exit: - +exit: return (retval); } @@ -630,29 +522,30 @@ error_exit: * be mounted read-only. * * Things to do to update the mount: - * 1) invalidate all cached meta-data. - * 2) re-read volume header from disk. - * 3) re-load meta-file info (extents, file size). - * 4) re-load B-tree header data. - * 5) invalidate all inactive vnodes. - * 6) invalidate all cached file data. - * 7) re-read hfsnode data for all active vnodes. + * invalidate all cached meta-data. + * invalidate all inactive vnodes. + * invalidate all cached file data. + * re-read volume header from disk. + * re-load meta-file info (extents, file size). + * re-load B-tree header data. + * re-read cnode data for all active vnodes. */ -int +static int hfs_reload(mountp, cred, p) register struct mount *mountp; struct ucred *cred; struct proc *p; { register struct vnode *vp, *nvp, *devvp; - struct hfsnode *hp; + struct cnode *cp; struct buf *bp; int sectorsize; int error, i; struct hfsmount *hfsmp; struct HFSPlusVolumeHeader *vhp; ExtendedVCB *vcb; - FCB *fcb; + struct filefork *forkp; + struct cat_desc cndesc; if ((mountp->mnt_flag & MNT_RDONLY) == 0) return (EINVAL); @@ -671,6 +564,57 @@ hfs_reload(mountp, cred, p) panic("hfs_reload: dirty1"); InvalidateCatalogCache(vcb); +loop: + simple_lock(&mntvnode_slock); + for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { + if (vp->v_mount != mountp) { + simple_unlock(&mntvnode_slock); + goto loop; + } + nvp = vp->v_mntvnodes.le_next; + + /* + * Invalidate all inactive vnodes. + */ + if (vrecycle(vp, &mntvnode_slock, p)) + goto loop; + + /* + * Invalidate all cached file data. + */ + simple_lock(&vp->v_interlock); + simple_unlock(&mntvnode_slock); + if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) { + goto loop; + } + if (vinvalbuf(vp, 0, cred, p, 0, 0)) + panic("hfs_reload: dirty2"); + + /* + * Re-read cnode data for all active vnodes (non-metadata files). + */ + cp = VTOC(vp); + if ((vp->v_flag & VSYSTEM) == 0 && !VNODE_IS_RSRC(vp)) { + struct cat_fork *datafork; + struct cat_desc desc; + + datafork = cp->c_datafork ? &cp->c_datafork->ff_data : NULL; + + /* lookup by fileID since name could have changed */ + if ((error = cat_idlookup(hfsmp, cp->c_fileid, &desc, &cp->c_attr, datafork))) { + vput(vp); + return (error); + } + + + /* update cnode's catalog descriptor */ + (void) replace_desc(cp, &desc); + } + vput(vp); + simple_lock(&mntvnode_slock); + } + simple_unlock(&mntvnode_slock); + /* * Re-read VolumeHeader from disk. */ @@ -687,23 +631,25 @@ hfs_reload(mountp, cred, p) vhp = (HFSPlusVolumeHeader *) (bp->b_data + HFS_PRI_OFFSET(sectorsize)); - if ((ValidVolumeHeader(vhp) != 0) || (vcb->blockSize != SWAP_BE32 (vhp->blockSize))) { + /* Do a quick sanity check */ + if (SWAP_BE16(vhp->signature) != kHFSPlusSigWord || + SWAP_BE16(vhp->version) != kHFSPlusVersion || + SWAP_BE32(vhp->blockSize) != vcb->blockSize) { brelse(bp); - return (EIO); /* XXX needs translation */ + return (EIO); } - vcb->vcbLsMod = SWAP_BE32 (vhp->modifyDate); - vcb->vcbAtrb = (UInt16) SWAP_BE32 (vhp->attributes); /* VCB only uses lower 16 bits */ - vcb->vcbClpSiz = SWAP_BE32 (vhp->rsrcClumpSize); - vcb->vcbNxtCNID = SWAP_BE32 (vhp->nextCatalogID); - vcb->vcbVolBkUp = SWAP_BE32 (vhp->backupDate); - vcb->vcbWrCnt = SWAP_BE32 (vhp->writeCount); - vcb->vcbFilCnt = SWAP_BE32 (vhp->fileCount); - vcb->vcbDirCnt = SWAP_BE32 (vhp->folderCount); + vcb->vcbLsMod = to_bsd_time(SWAP_BE32(vhp->modifyDate)); + vcb->vcbAtrb = (UInt16) SWAP_BE32 (vhp->attributes); /* VCB only uses lower 16 bits */ + vcb->vcbClpSiz = SWAP_BE32 (vhp->rsrcClumpSize); + vcb->vcbNxtCNID = SWAP_BE32 (vhp->nextCatalogID); + vcb->vcbVolBkUp = to_bsd_time(SWAP_BE32(vhp->backupDate)); + vcb->vcbWrCnt = SWAP_BE32 (vhp->writeCount); + vcb->vcbFilCnt = SWAP_BE32 (vhp->fileCount); + vcb->vcbDirCnt = SWAP_BE32 (vhp->folderCount); vcb->nextAllocation = SWAP_BE32 (vhp->nextAllocation); - vcb->totalBlocks = SWAP_BE32 (vhp->totalBlocks); - vcb->freeBlocks = SWAP_BE32 (vhp->freeBlocks); - vcb->checkedDate = SWAP_BE32 (vhp->checkedDate); + vcb->totalBlocks = SWAP_BE32 (vhp->totalBlocks); + vcb->freeBlocks = SWAP_BE32 (vhp->freeBlocks); vcb->encodingsBitmap = SWAP_BE64 (vhp->encodingsBitmap); bcopy(vhp->finderInfo, vcb->vcbFndrInfo, sizeof(vhp->finderInfo)); vcb->localCreateDate = SWAP_BE32 (vhp->createDate); /* hfs+ create date is in local time */ @@ -711,35 +657,40 @@ hfs_reload(mountp, cred, p) /* * Re-load meta-file vnode data (extent info, file size, etc). */ - fcb = VTOFCB((struct vnode *)vcb->extentsRefNum); - /* bcopy(vhp->extentsFile.extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); */ - for (i = 0; i < kHFSPlusExtentDensity; i++) { - fcb->fcbExtents[i].startBlock = SWAP_BE32 (vhp->extentsFile.extents[i].startBlock); - fcb->fcbExtents[i].blockCount = SWAP_BE32 (vhp->extentsFile.extents[i].blockCount); - } - fcb->fcbEOF = SWAP_BE64 (vhp->extentsFile.logicalSize); - fcb->fcbPLen = SWAP_BE32 (vhp->extentsFile.totalBlocks) * vcb->blockSize; - fcb->fcbClmpSize = SWAP_BE32 (vhp->extentsFile.clumpSize); - - fcb = VTOFCB((struct vnode *)vcb->catalogRefNum); - /* bcopy(vhp->catalogFile.extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); */ - for (i = 0; i < kHFSPlusExtentDensity; i++) { - fcb->fcbExtents[i].startBlock = SWAP_BE32 (vhp->catalogFile.extents[i].startBlock); - fcb->fcbExtents[i].blockCount = SWAP_BE32 (vhp->catalogFile.extents[i].blockCount); - } - fcb->fcbPLen = SWAP_BE64 (vhp->catalogFile.logicalSize); - fcb->fcbPLen = SWAP_BE32 (vhp->catalogFile.totalBlocks) * vcb->blockSize; - fcb->fcbClmpSize = SWAP_BE32 (vhp->catalogFile.clumpSize); - - fcb = VTOFCB((struct vnode *)vcb->allocationsRefNum); - /* bcopy(vhp->allocationFile.extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); */ - for (i = 0; i < kHFSPlusExtentDensity; i++) { - fcb->fcbExtents[i].startBlock = SWAP_BE32 (vhp->allocationFile.extents[i].startBlock); - fcb->fcbExtents[i].blockCount = SWAP_BE32 (vhp->allocationFile.extents[i].blockCount); - } - fcb->fcbEOF = SWAP_BE64 (vhp->allocationFile.logicalSize); - fcb->fcbPLen = SWAP_BE32 (vhp->allocationFile.totalBlocks) * vcb->blockSize; - fcb->fcbClmpSize = SWAP_BE32 (vhp->allocationFile.clumpSize); + forkp = VTOF((struct vnode *)vcb->extentsRefNum); + for (i = 0; i < kHFSPlusExtentDensity; i++) { + forkp->ff_extents[i].startBlock = + SWAP_BE32 (vhp->extentsFile.extents[i].startBlock); + forkp->ff_extents[i].blockCount = + SWAP_BE32 (vhp->extentsFile.extents[i].blockCount); + } + forkp->ff_size = SWAP_BE64 (vhp->extentsFile.logicalSize); + forkp->ff_blocks = SWAP_BE32 (vhp->extentsFile.totalBlocks); + forkp->ff_clumpsize = SWAP_BE32 (vhp->extentsFile.clumpSize); + + + forkp = VTOF((struct vnode *)vcb->catalogRefNum); + for (i = 0; i < kHFSPlusExtentDensity; i++) { + forkp->ff_extents[i].startBlock = + SWAP_BE32 (vhp->catalogFile.extents[i].startBlock); + forkp->ff_extents[i].blockCount = + SWAP_BE32 (vhp->catalogFile.extents[i].blockCount); + } + forkp->ff_size = SWAP_BE64 (vhp->catalogFile.logicalSize); + forkp->ff_blocks = SWAP_BE32 (vhp->catalogFile.totalBlocks); + forkp->ff_clumpsize = SWAP_BE32 (vhp->catalogFile.clumpSize); + + + forkp = VTOF((struct vnode *)vcb->allocationsRefNum); + for (i = 0; i < kHFSPlusExtentDensity; i++) { + forkp->ff_extents[i].startBlock = + SWAP_BE32 (vhp->allocationFile.extents[i].startBlock); + forkp->ff_extents[i].blockCount = + SWAP_BE32 (vhp->allocationFile.extents[i].blockCount); + } + forkp->ff_size = SWAP_BE64 (vhp->allocationFile.logicalSize); + forkp->ff_blocks = SWAP_BE32 (vhp->allocationFile.totalBlocks); + forkp->ff_clumpsize = SWAP_BE32 (vhp->allocationFile.clumpSize); brelse(bp); vhp = NULL; @@ -747,81 +698,24 @@ hfs_reload(mountp, cred, p) /* * Re-load B-tree header data */ - fcb = VTOFCB((struct vnode *)vcb->extentsRefNum); - if (error = MacToVFSError( BTReloadData(fcb) )) + forkp = VTOF((struct vnode *)vcb->extentsRefNum); + if (error = MacToVFSError( BTReloadData((FCB*)forkp) )) return (error); - fcb = VTOFCB((struct vnode *)vcb->catalogRefNum); - if (error = MacToVFSError( BTReloadData(fcb) )) + forkp = VTOF((struct vnode *)vcb->catalogRefNum); + if (error = MacToVFSError( BTReloadData((FCB*)forkp) )) return (error); - /* Now that the catalog is ready, get the volume name */ - /* also picks up the create date in GMT */ - if ((error = MacToVFSError( GetVolumeNameFromCatalog(vcb) ))) + /* Reload the volume name */ + if ((error = cat_idlookup(hfsmp, kHFSRootFolderID, &cndesc, NULL, NULL))) return (error); + vcb->volumeNameEncodingHint = cndesc.cd_encoding; + bcopy(cndesc.cd_nameptr, vcb->vcbVN, min(255, cndesc.cd_namelen)); + cat_releasedesc(&cndesc); /* Re-establish private/hidden directory for unlinked files */ hfsmp->hfs_private_metadata_dir = FindMetaDataDirectory(vcb); -loop: - simple_lock(&mntvnode_slock); - for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { - if (vp->v_mount != mountp) { - simple_unlock(&mntvnode_slock); - goto loop; - } - nvp = vp->v_mntvnodes.le_next; - - /* - * Invalidate all inactive vnodes. - */ - if (vrecycle(vp, &mntvnode_slock, p)) - goto loop; - - /* - * Invalidate all cached file data. - */ - simple_lock(&vp->v_interlock); - simple_unlock(&mntvnode_slock); - if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) { - goto loop; - } - if (vinvalbuf(vp, 0, cred, p, 0, 0)) - panic("hfs_reload: dirty2"); - - /* - * Re-read hfsnode data for all active vnodes (non-metadata files). - */ - hp = VTOH(vp); - if ((vp->v_flag & VSYSTEM) == 0) { - hfsCatalogInfo catInfo; - - /* lookup by fileID since name could have changed */ - catInfo.hint = kNoHint; - INIT_CATALOGDATA(&catInfo.nodeData, 0); - - if ((error = hfs_getcatalog(vcb, H_FILEID(hp), NULL, -1, &catInfo))) { - vput(vp); - CLEAN_CATALOGDATA(&catInfo.nodeData); - return (error); - } - - H_HINT(hp) = catInfo.hint; - if (hp->h_meta->h_metaflags & IN_LONGNAME) - FREE(H_NAME(hp), M_TEMP); - H_NAME(hp) = NULL; - hp->h_meta->h_namelen = 0; - CopyCatalogToObjectMeta(&catInfo, vp, hp->h_meta); - CopyCatalogToFCB(&catInfo, vp); - - CLEAN_CATALOGDATA(&catInfo.nodeData); - } - - vput(vp); - simple_lock(&mntvnode_slock); - } - simple_unlock(&mntvnode_slock); - return (0); } @@ -829,24 +723,28 @@ loop: /* * Common code for mount and mountroot */ -int -hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, struct hfs_mount_args *args) +static int +hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, + struct hfs_mount_args *args) { - int retval = E_NONE; - register struct hfsmount *hfsmp; - struct buf *bp; - dev_t dev; - HFSMasterDirectoryBlock *mdbp; - int ronly; - struct ucred *cred; + int retval = E_NONE; + struct hfsmount *hfsmp; + struct buf *bp; + dev_t dev; + HFSMasterDirectoryBlock *mdbp; + int ronly; + int i; + int mntwrapper; + struct ucred *cred; u_int64_t disksize; u_int64_t blkcnt; u_int32_t blksize; u_int32_t minblksize; - DBG_VFS(("hfs_mountfs: mp = 0x%lX\n", (u_long)mp)); + u_int32_t iswritable; - dev = devvp->v_rdev; - cred = p ? p->p_ucred : NOCRED; + dev = devvp->v_rdev; + cred = p ? p->p_ucred : NOCRED; + mntwrapper = 0; /* * Disallow multiple mounts of the same device. * Disallow mounting of a device that is currently in use @@ -861,12 +759,12 @@ hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, struct hfs_mo return (retval); ronly = (mp->mnt_flag & MNT_RDONLY) != 0; - DBG_VFS(("hfs_mountfs: opening device...\n")); if ((retval = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p))) return (retval); bp = NULL; hfsmp = NULL; + mdbp = NULL; minblksize = kHFSBlockSize; /* Get the real physical block size. */ @@ -892,12 +790,13 @@ hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, struct hfs_mo disksize = blkcnt * (u_int64_t)512; /* - * For large volumes use a 4K physical block size. + * There are only 31 bits worth of block count in + * the buffer cache. So for large volumes a 4K + * physical block size is needed. */ if (blkcnt > (u_int64_t)0x000000007fffffff) { minblksize = blksize = 4096; } - /* Now switch to our prefered physical block size. */ if (blksize > 512) { if (VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, (caddr_t)&blksize, FWRITE, cred, p)) { @@ -917,7 +816,6 @@ hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, struct hfs_mo * blksize has our prefered physical block size * blkcnt has the total number of physical blocks */ - devvp->v_specsize = blksize; /* cache the IO attributes */ @@ -930,25 +828,32 @@ hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, struct hfs_mo if ((retval = meta_bread(devvp, HFS_PRI_SECTOR(blksize), blksize, cred, &bp))) { goto error_exit; } - mdbp = (HFSMasterDirectoryBlock*) (bp->b_data + HFS_PRI_OFFSET(blksize)); + MALLOC(mdbp, HFSMasterDirectoryBlock *, kMDBSize, M_TEMP, M_WAITOK); + bcopy(bp->b_data + HFS_PRI_OFFSET(blksize), mdbp, kMDBSize); + brelse(bp); + bp = NULL; MALLOC(hfsmp, struct hfsmount *, sizeof(struct hfsmount), M_HFSMNT, M_WAITOK); bzero(hfsmp, sizeof(struct hfsmount)); simple_lock_init(&hfsmp->hfs_renamelock); - /* - * Init the volume information structure - */ - mp->mnt_data = (qaddr_t)hfsmp; - hfsmp->hfs_mp = mp; /* Make VFSTOHFS work */ - hfsmp->hfs_vcb.vcb_hfsmp = hfsmp; /* Make VCBTOHFS work */ - hfsmp->hfs_raw_dev = devvp->v_rdev; - hfsmp->hfs_devvp = devvp; - hfsmp->hfs_phys_block_size = blksize; - hfsmp->hfs_phys_block_count = blkcnt; - hfsmp->hfs_fs_ronly = ronly; - hfsmp->hfs_unknownpermissions = ((mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) != 0); + /* + * Init the volume information structure + */ + mp->mnt_data = (qaddr_t)hfsmp; + hfsmp->hfs_mp = mp; /* Make VFSTOHFS work */ + hfsmp->hfs_vcb.vcb_hfsmp = hfsmp; /* Make VCBTOHFS work */ + hfsmp->hfs_raw_dev = devvp->v_rdev; + hfsmp->hfs_devvp = devvp; + hfsmp->hfs_phys_block_size = blksize; + hfsmp->hfs_phys_block_count = blkcnt; + hfsmp->hfs_media_writeable = 1; + hfsmp->hfs_fs_ronly = ronly; + hfsmp->hfs_unknownpermissions = ((mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) != 0); + for (i = 0; i < MAXQUOTAS; i++) + hfsmp->hfs_qfiles[i].qf_vp = NULLVP; + if (args) { hfsmp->hfs_uid = (args->hfs_uid == (uid_t)VNOVAL) ? UNKNOWNUID : args->hfs_uid; if (hfsmp->hfs_uid == 0xfffffffd) hfsmp->hfs_uid = UNKNOWNUID; @@ -964,7 +869,9 @@ hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, struct hfs_mo } else { hfsmp->hfs_dir_mask = UNKNOWNPERMISSIONS & ALLPERMS; /* 0777: rwx---rwx */ hfsmp->hfs_file_mask = UNKNOWNPERMISSIONS & DEFFILEMODE; /* 0666: no --x by default? */ - }; + } + if ((args->flags != (int)VNOVAL) && (args->flags & HFSFSMNT_WRAPPER)) + mntwrapper = 1; } else { /* Even w/o explicit mount arguments, MNT_UNKNOWNPERMISSIONS requires setting up uid, gid, and mask: */ if (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) { @@ -972,12 +879,20 @@ hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, struct hfs_mo hfsmp->hfs_gid = UNKNOWNGID; hfsmp->hfs_dir_mask = UNKNOWNPERMISSIONS & ALLPERMS; /* 0777: rwx---rwx */ hfsmp->hfs_file_mask = UNKNOWNPERMISSIONS & DEFFILEMODE; /* 0666: no --x by default? */ - }; - }; + } + } + + /* Find out if disk media is writable. */ + if (VOP_IOCTL(devvp, DKIOCISWRITABLE, (caddr_t)&iswritable, 0, cred, p) == 0) { + if (iswritable) + hfsmp->hfs_media_writeable = 1; + else + hfsmp->hfs_media_writeable = 0; + } /* Mount a standard HFS disk */ if ((SWAP_BE16(mdbp->drSigWord) == kHFSSigWord) && - (SWAP_BE16(mdbp->drEmbedSigWord) != kHFSPlusSigWord)) { + (mntwrapper || (SWAP_BE16(mdbp->drEmbedSigWord) != kHFSPlusSigWord))) { if (devvp == rootvp) { retval = EINVAL; /* Cannot root from HFS standard disks */ goto error_exit; @@ -993,7 +908,6 @@ hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, struct hfs_mo retval = ENXIO; goto error_exit; } - /* XXX do we need to call vfs_init_io_attributes again ? */ devvp->v_specsize = blksize; hfsmp->hfs_phys_block_size = blksize; hfsmp->hfs_phys_block_count = blkcnt; @@ -1006,7 +920,8 @@ hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, struct hfs_mo gTimeZone = args->hfs_timezone; } - retval = hfs_getconverter(hfsmp->hfs_encoding, &hfsmp->hfs_get_unicode, &hfsmp->hfs_get_hfsname); + retval = hfs_getconverter(hfsmp->hfs_encoding, &hfsmp->hfs_get_unicode, + &hfsmp->hfs_get_hfsname); if (retval) goto error_exit; @@ -1024,15 +939,6 @@ hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, struct hfs_mo embeddedOffset += (u_int64_t)SWAP_BE16(mdbp->drEmbedExtent.startBlock) * (u_int64_t)SWAP_BE32(mdbp->drAlBlkSiz); - disksize = (u_int64_t)SWAP_BE16(mdbp->drEmbedExtent.blockCount) * - (u_int64_t)SWAP_BE32(mdbp->drAlBlkSiz); - - hfsmp->hfs_phys_block_count = disksize / blksize; - - brelse(bp); - bp = NULL; - mdbp = NULL; - /* * If the embedded volume doesn't start on a block * boundary, then switch the device to a 512-byte @@ -1062,11 +968,19 @@ hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, struct hfs_mo hfsmp->hfs_phys_block_size = blksize; } - retval = meta_bread(devvp, (embeddedOffset / blksize) + HFS_PRI_SECTOR(blksize), - blksize, cred, &bp); + disksize = (u_int64_t)SWAP_BE16(mdbp->drEmbedExtent.blockCount) * + (u_int64_t)SWAP_BE32(mdbp->drAlBlkSiz); + + hfsmp->hfs_phys_block_count = disksize / blksize; + + retval = meta_bread(devvp, (embeddedOffset / blksize) + + HFS_PRI_SECTOR(blksize), blksize, cred, &bp); if (retval) goto error_exit; - vhp = (HFSPlusVolumeHeader*) (bp->b_data + HFS_PRI_OFFSET(blksize)); + bcopy(bp->b_data + HFS_PRI_OFFSET(blksize), mdbp, 512); + brelse(bp); + bp = NULL; + vhp = (HFSPlusVolumeHeader*) mdbp; } else /* pure HFS+ */ { embeddedOffset = 0; @@ -1092,7 +1006,6 @@ hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, struct hfs_mo retval = ENXIO; goto error_exit; } - /* XXX do we need to call vfs_init_io_attributes again ? */ devvp->v_specsize = blksize; /* Note: relative block count adjustment (in case this is an embedded volume). */ hfsmp->hfs_phys_block_count *= hfsmp->hfs_phys_block_size / blksize; @@ -1109,35 +1022,27 @@ hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, struct hfs_mo goto error_exit; } - brelse(bp); - bp = NULL; - - mp->mnt_stat.f_fsid.val[0] = (long)dev; - mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; - mp->mnt_maxsymlinklen = 0; - devvp->v_specflags |= SI_MOUNTEDON; - - if (ronly == 0) { - hfsmp->hfs_fs_clean = 0; - if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord) - (void) hfs_flushvolumeheader(hfsmp, MNT_WAIT); - else - (void) hfs_flushMDB(hfsmp, MNT_WAIT); - } - goto std_exit; + mp->mnt_stat.f_fsid.val[0] = (long)dev; + mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; + mp->mnt_maxsymlinklen = 0; + devvp->v_specflags |= SI_MOUNTEDON; -error_exit: - DBG_VFS(("hfs_mountfs: exiting with error %d...\n", retval)); - - if (bp) - brelse(bp); - (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p); - if (hfsmp) { - FREE(hfsmp, M_HFSMNT); - mp->mnt_data = (qaddr_t)0; - } + if (ronly == 0) { + (void) hfs_flushvolumeheader(hfsmp, MNT_WAIT, 0); + } + FREE(mdbp, M_TEMP); + return (0); -std_exit: +error_exit: + if (bp) + brelse(bp); + if (mdbp) + FREE(mdbp, M_TEMP); + (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p); + if (hfsmp) { + FREE(hfsmp, M_HFSMNT); + mp->mnt_data = (qaddr_t)0; + } return (retval); } @@ -1147,22 +1052,20 @@ std_exit: * Nothing to do at the moment. */ /* ARGSUSED */ -int hfs_start(mp, flags, p) -struct mount *mp; -int flags; -struct proc *p; +static int +hfs_start(mp, flags, p) + struct mount *mp; + int flags; + struct proc *p; { - DBG_FUNC_NAME("hfs_start"); - DBG_PRINT_FUNC_NAME(); - - return (0); + return (0); } /* * unmount system call */ -int +static int hfs_unmount(mp, mntflags, p) struct mount *mp; int mntflags; @@ -1171,12 +1074,16 @@ hfs_unmount(mp, mntflags, p) struct hfsmount *hfsmp = VFSTOHFS(mp); int retval = E_NONE; int flags; + int force; flags = 0; - if (mntflags & MNT_FORCE) + force = 0; + if (mntflags & MNT_FORCE) { flags |= FORCECLOSE; + force = 1; + } - if ((retval = hfs_flushfiles(mp, flags))) + if ((retval = hfs_flushfiles(mp, flags, p)) && !force) return (retval); /* @@ -1184,35 +1091,29 @@ hfs_unmount(mp, mntflags, p) */ if (hfsmp->hfs_fs_ronly == 0) { retval = VOP_FSYNC(HFSTOVCB(hfsmp)->catalogRefNum, NOCRED, MNT_WAIT, p); - if (retval && ((mntflags & MNT_FORCE) == 0)) + if (retval && !force) return (retval); retval = VOP_FSYNC(HFSTOVCB(hfsmp)->extentsRefNum, NOCRED, MNT_WAIT, p); - if (retval && ((mntflags & MNT_FORCE) == 0)) + if (retval && !force) return (retval); if (retval = VOP_FSYNC(hfsmp->hfs_devvp, NOCRED, MNT_WAIT, p)) { - if ((mntflags & MNT_FORCE) == 0) + if (!force) return (retval); } /* See if this volume is damaged, is so do not unmount cleanly */ if (HFSTOVCB(hfsmp)->vcbFlags & kHFS_DamagedVolume) { - hfsmp->hfs_fs_clean = 0; HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeUnmountedMask; } else { - hfsmp->hfs_fs_clean = 1; - HFSTOVCB(hfsmp)->vcbAtrb |= kHFSVolumeUnmountedMask; + HFSTOVCB(hfsmp)->vcbAtrb |= kHFSVolumeUnmountedMask; } - if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord) - retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT); - else - retval = hfs_flushMDB(hfsmp, MNT_WAIT); - + + retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT, 0); if (retval) { - hfsmp->hfs_fs_clean = 0; HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeUnmountedMask; - if ((mntflags & MNT_FORCE) == 0) + if (!force) return (retval); /* could not flush everything */ } } @@ -1226,14 +1127,16 @@ hfs_unmount(mp, mntflags, p) (void) hfs_relconverter(hfsmp->hfs_encoding); hfsmp->hfs_devvp->v_specflags &= ~SI_MOUNTEDON; - retval = VOP_CLOSE(hfsmp->hfs_devvp, hfsmp->hfs_fs_ronly ? FREAD : FREAD|FWRITE, - NOCRED, p); - vrele(hfsmp->hfs_devvp); + retval = VOP_CLOSE(hfsmp->hfs_devvp, + hfsmp->hfs_fs_ronly ? FREAD : FREAD|FWRITE, + NOCRED, p); + if (retval && !force) + return(retval); + vrele(hfsmp->hfs_devvp); FREE(hfsmp, M_HFSMNT); mp->mnt_data = (qaddr_t)0; - - return (retval); + return (0); } @@ -1242,39 +1145,99 @@ hfs_unmount(mp, mntflags, p) * * OUT - vpp, should be locked and vget()'d (to increment usecount and lock) */ -int hfs_root(mp, vpp) -struct mount *mp; -struct vnode **vpp; +static int +hfs_root(mp, vpp) + struct mount *mp; + struct vnode **vpp; { - struct vnode *nvp; - int retval; - UInt32 rootObjID = kRootDirID; - - DBG_FUNC_NAME("hfs_root"); - DBG_PRINT_FUNC_NAME(); + struct vnode *nvp; + int retval; + UInt32 rootObjID = kRootDirID; - if ((retval = VFS_VGET(mp, &rootObjID, &nvp))) - return (retval); + if ((retval = VFS_VGET(mp, &rootObjID, &nvp))) + return (retval); - *vpp = nvp; - return (0); + *vpp = nvp; + return (0); } /* * Do operations associated with quotas */ -int hfs_quotactl(mp, cmds, uid, arg, p) -struct mount *mp; -int cmds; -uid_t uid; -caddr_t arg; -struct proc *p; +int +hfs_quotactl(mp, cmds, uid, arg, p) + struct mount *mp; + int cmds; + uid_t uid; + caddr_t arg; + struct proc *p; { - DBG_FUNC_NAME("hfs_quotactl"); - DBG_PRINT_FUNC_NAME(); + int cmd, type, error; + +#if !QUOTA + return (EOPNOTSUPP); +#else + if (uid == -1) + uid = p->p_cred->p_ruid; + cmd = cmds >> SUBCMDSHIFT; + + switch (cmd) { + case Q_SYNC: + case Q_QUOTASTAT: + break; + case Q_GETQUOTA: + if (uid == p->p_cred->p_ruid) + break; + /* fall through */ + default: + if (error = suser(p->p_ucred, &p->p_acflag)) + return (error); + } + + type = cmds & SUBCMDMASK; + if ((u_int)type >= MAXQUOTAS) + return (EINVAL); + if (vfs_busy(mp, LK_NOWAIT, 0, p)) + return (0); + + switch (cmd) { - return (EOPNOTSUPP); + case Q_QUOTAON: + error = hfs_quotaon(p, mp, type, arg, UIO_USERSPACE); + break; + + case Q_QUOTAOFF: + error = hfs_quotaoff(p, mp, type); + break; + + case Q_SETQUOTA: + error = hfs_setquota(mp, uid, type, arg); + break; + + case Q_SETUSE: + error = hfs_setuse(mp, uid, type, arg); + break; + + case Q_GETQUOTA: + error = hfs_getquota(mp, uid, type, arg); + break; + + case Q_SYNC: + error = hfs_qsync(mp); + break; + + case Q_QUOTASTAT: + error = hfs_quotastat(mp, type, arg); + break; + + default: + error = EINVAL; + break; + } + vfs_unbusy(mp, p); + return (error); +#endif /* QUOTA */ } @@ -1291,18 +1254,15 @@ hfs_statfs(mp, sbp, p) struct hfsmount *hfsmp = VFSTOHFS(mp); u_long freeCNIDs; - DBG_FUNC_NAME("hfs_statfs"); - DBG_PRINT_FUNC_NAME(); - freeCNIDs = (u_long)0xFFFFFFFF - (u_long)vcb->vcbNxtCNID; sbp->f_bsize = vcb->blockSize; sbp->f_iosize = hfsmp->hfs_logBlockSize; sbp->f_blocks = vcb->totalBlocks; - sbp->f_bfree = vcb->freeBlocks; - sbp->f_bavail = vcb->freeBlocks; + sbp->f_bfree = hfs_freeblks(hfsmp, 0); + sbp->f_bavail = hfs_freeblks(hfsmp, 1); sbp->f_files = vcb->totalBlocks - 2; /* max files is constrained by total blocks */ - sbp->f_ffree = MIN(freeCNIDs, vcb->freeBlocks); + sbp->f_ffree = MIN(freeCNIDs, sbp->f_bavail); sbp->f_type = 0; if (sbp != &mp->mnt_stat) { @@ -1323,22 +1283,20 @@ hfs_statfs(mp, sbp, p) * * Note: we are always called with the filesystem marked `MPBUSY'. */ -static int hfs_sync(mp, waitfor, cred, p) -struct mount *mp; -int waitfor; -struct ucred *cred; -struct proc *p; +static int +hfs_sync(mp, waitfor, cred, p) + struct mount *mp; + int waitfor; + struct ucred *cred; + struct proc *p; { - struct vnode *nvp, *vp; - struct hfsnode *hp; - struct hfsmount *hfsmp = VFSTOHFS(mp); - ExtendedVCB *vcb; - struct vnode *meta_vp[3]; - int i; - int error, allerror = 0; - - DBG_FUNC_NAME("hfs_sync"); - DBG_PRINT_FUNC_NAME(); + struct vnode *nvp, *vp; + struct cnode *cp; + struct hfsmount *hfsmp; + ExtendedVCB *vcb; + struct vnode *meta_vp[3]; + int i; + int error, allerror = 0; /* * During MNT_UPDATE hfs_changefs might be manipulating @@ -1347,121 +1305,116 @@ struct proc *p; if (mp->mnt_flag & MNT_UPDATE) return (0); - hfsmp = VFSTOHFS(mp); - if (hfsmp->hfs_fs_ronly != 0) { - panic("update: rofs mod"); - }; + hfsmp = VFSTOHFS(mp); + if (hfsmp->hfs_fs_ronly != 0) { + panic("update: rofs mod"); + }; - /* - * Write back each 'modified' vnode - */ + /* + * Write back each 'modified' vnode + */ -loop:; - simple_lock(&mntvnode_slock); - for (vp = mp->mnt_vnodelist.lh_first; - vp != NULL; - vp = nvp) { +loop: + simple_lock(&mntvnode_slock); + for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { int didhold; - /* - * If the vnode that we are about to sync is no longer - * associated with this mount point, start over. - */ - if (vp->v_mount != mp) { - simple_unlock(&mntvnode_slock); - goto loop; - } - simple_lock(&vp->v_interlock); - nvp = vp->v_mntvnodes.le_next; - hp = VTOH(vp); - - if ((vp->v_flag & VSYSTEM) || (vp->v_type == VNON) || - (((hp->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0) && - (vp->v_dirtyblkhd.lh_first == NULL) && !(vp->v_flag & VHASDIRTY))) { - simple_unlock(&vp->v_interlock); - simple_unlock(&mntvnode_slock); - simple_lock(&mntvnode_slock); - continue; - } - - simple_unlock(&mntvnode_slock); - error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p); - if (error) { - if (error == ENOENT) - goto loop; - simple_lock(&mntvnode_slock); - continue; - } + /* + * If the vnode that we are about to sync is no longer + * associated with this mount point, start over. + */ + if (vp->v_mount != mp) { + simple_unlock(&mntvnode_slock); + goto loop; + } + simple_lock(&vp->v_interlock); + nvp = vp->v_mntvnodes.le_next; + cp = VTOC(vp); + + if ((vp->v_flag & VSYSTEM) || (vp->v_type == VNON) || + (((cp->c_flag & (C_ACCESS | C_CHANGE | C_MODIFIED | C_UPDATE)) == 0) && + (vp->v_dirtyblkhd.lh_first == NULL) && !(vp->v_flag & VHASDIRTY))) { + simple_unlock(&vp->v_interlock); + simple_unlock(&mntvnode_slock); + simple_lock(&mntvnode_slock); + continue; + } + + simple_unlock(&mntvnode_slock); + error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p); + if (error) { + if (error == ENOENT) + goto loop; + simple_lock(&mntvnode_slock); + continue; + } didhold = ubc_hold(vp); - if ((error = VOP_FSYNC(vp, cred, waitfor, p))) { - DBG_ERR(("hfs_sync: error %d calling fsync on vnode 0x%X.\n", error, (u_int)vp)); - allerror = error; - }; - DBG_ASSERT(*((volatile int *)(&(vp)->v_interlock))==0); - VOP_UNLOCK(vp, 0, p); + if ((error = VOP_FSYNC(vp, cred, waitfor, p))) { + allerror = error; + }; + VOP_UNLOCK(vp, 0, p); if (didhold) ubc_rele(vp); - vrele(vp); - simple_lock(&mntvnode_slock); - }; - - vcb = HFSTOVCB(hfsmp); - meta_vp[0] = vcb->extentsRefNum; - meta_vp[1] = vcb->catalogRefNum; - meta_vp[2] = vcb->allocationsRefNum; /* This is NULL for standard HFS */ - - /* Now sync our three metadata files */ - for (i = 0; i < 3; ++i) { - struct vnode *btvp; - - btvp = meta_vp[i]; - - if ((btvp==0) || (btvp->v_type == VNON) || (btvp->v_mount != mp)) - continue; - simple_lock(&btvp->v_interlock); - hp = VTOH(btvp); - if (((hp->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0) && - (btvp->v_dirtyblkhd.lh_first == NULL) && !(btvp->v_flag & VHASDIRTY)) { - simple_unlock(&btvp->v_interlock); - continue; - } - simple_unlock(&mntvnode_slock); - error = vget(btvp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p); - if (error) { - simple_lock(&mntvnode_slock); - continue; - } - if ((error = VOP_FSYNC(btvp, cred, waitfor, p))) - allerror = error; - VOP_UNLOCK(btvp, 0, p); - vrele(btvp); - simple_lock(&mntvnode_slock); - }; - - simple_unlock(&mntvnode_slock); + vrele(vp); + simple_lock(&mntvnode_slock); + }; - /* - * Force stale file system control information to be flushed. - */ - if (vcb->vcbSigWord == kHFSSigWord) { - if ((error = VOP_FSYNC(hfsmp->hfs_devvp, cred, waitfor, p))) - allerror = error; - } - /* - * Write back modified superblock. - */ + vcb = HFSTOVCB(hfsmp); + + meta_vp[0] = vcb->extentsRefNum; + meta_vp[1] = vcb->catalogRefNum; + meta_vp[2] = vcb->allocationsRefNum; /* This is NULL for standard HFS */ + + /* Now sync our three metadata files */ + for (i = 0; i < 3; ++i) { + struct vnode *btvp; + + btvp = btvp = meta_vp[i];; + if ((btvp==0) || (btvp->v_type == VNON) || (btvp->v_mount != mp)) + continue; + simple_lock(&btvp->v_interlock); + cp = VTOC(btvp); + if (((cp->c_flag & (C_ACCESS | C_CHANGE | C_MODIFIED | C_UPDATE)) == 0) && + (btvp->v_dirtyblkhd.lh_first == NULL) && !(btvp->v_flag & VHASDIRTY)) { + simple_unlock(&btvp->v_interlock); + continue; + } + simple_unlock(&mntvnode_slock); + error = vget(btvp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p); + if (error) { + simple_lock(&mntvnode_slock); + continue; + } + if ((error = VOP_FSYNC(btvp, cred, waitfor, p))) + allerror = error; + VOP_UNLOCK(btvp, 0, p); + vrele(btvp); + simple_lock(&mntvnode_slock); + }; + + simple_unlock(&mntvnode_slock); + + /* + * Force stale file system control information to be flushed. + */ + if (vcb->vcbSigWord == kHFSSigWord) { + if ((error = VOP_FSYNC(hfsmp->hfs_devvp, cred, waitfor, p))) + allerror = error; + } +#if QUOTA + hfs_qsync(mp); +#endif /* QUOTA */ + /* + * Write back modified superblock. + */ + + if (IsVCBDirty(vcb)) { + error = hfs_flushvolumeheader(hfsmp, waitfor, 0); + if (error) + allerror = error; + } - if (IsVCBDirty(vcb)) { - if (vcb->vcbSigWord == kHFSPlusSigWord) - error = hfs_flushvolumeheader(hfsmp, waitfor); - else - error = hfs_flushMDB(hfsmp, waitfor); - - if (error) - allerror = error; - }; - - return (allerror); + return (allerror); } @@ -1469,27 +1422,25 @@ loop:; * File handle to vnode * * Have to be really careful about stale file handles: - * - check that the hfsnode number is valid - * - call hfs_vget() to get the locked hfsnode - * - check for an unallocated hfsnode (i_mode == 0) + * - check that the cnode id is valid + * - call hfs_vget() to get the locked cnode + * - check for an unallocated cnode (i_mode == 0) * - check that the given client host has export rights and return * those rights via. exflagsp and credanonp */ -int +static int hfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) -register struct mount *mp; -struct fid *fhp; -struct mbuf *nam; -struct vnode **vpp; -int *exflagsp; -struct ucred **credanonp; + register struct mount *mp; + struct fid *fhp; + struct mbuf *nam; + struct vnode **vpp; + int *exflagsp; + struct ucred **credanonp; { struct hfsfid *hfsfhp; struct vnode *nvp; int result; struct netcred *np; - DBG_FUNC_NAME("hfs_fhtovp"); - DBG_PRINT_FUNC_NAME(); *vpp = NULL; hfsfhp = (struct hfsfid *)fhp; @@ -1517,16 +1468,16 @@ struct ucred **credanonp; * error prone. Future, would be change the "wrap bit" to a unique * wrap number and use that for generation number. For now do this. */ - if ((hfsfhp->hfsfid_gen < VTOH(nvp)->h_meta->h_crtime)) { + if ((hfsfhp->hfsfid_gen < VTOC(nvp)->c_itime)) { vput(nvp); - return ESTALE; + return (ESTALE); }; *vpp = nvp; *exflagsp = np->netc_exflags; *credanonp = &np->netc_anon; - return 0; + return (0); } @@ -1534,251 +1485,242 @@ struct ucred **credanonp; * Vnode pointer to File handle */ /* ARGSUSED */ -static int hfs_vptofh(vp, fhp) -struct vnode *vp; -struct fid *fhp; +static int +hfs_vptofh(vp, fhp) + struct vnode *vp; + struct fid *fhp; { - struct hfsnode *hp; + struct cnode *cp; struct hfsfid *hfsfhp; - struct proc *p = current_proc(); - int result; - u_int32_t fileID; - DBG_FUNC_NAME("hfs_vptofh"); - DBG_PRINT_FUNC_NAME(); - hp = VTOH(vp); - hfsfhp = (struct hfsfid *)fhp; - - /* If a file handle is requested for a file on an HFS volume we must be sure - to create the thread record before returning the object id in the filehandle - to make sure the file can be retrieved by fileid if necessary: - */ - if ((vp->v_type == VREG) && ISHFS(VTOVCB(vp))) { - /* Create a thread record and return the FileID [which is the file's fileNumber] */ - /* lock catalog b-tree */ - if ((result = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_EXCLUSIVE, p)) != 0) return result; - result = hfsCreateFileID(VTOVCB(vp), H_DIRID(hp), H_NAME(hp), H_HINT(hp), &fileID); - (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, p); - if (result) { - DBG_ERR(("hfs_vptofh: error %d on CreateFileIDRef.\n", result)); - return result; - }; - DBG_ASSERT(fileID == H_FILEID(hp)); - }; + if (ISHFS(VTOVCB(vp))) + return (EOPNOTSUPP); /* hfs standard is not exportable */ + cp = VTOC(vp); + hfsfhp = (struct hfsfid *)fhp; hfsfhp->hfsfid_len = sizeof(struct hfsfid); hfsfhp->hfsfid_pad = 0; - hfsfhp->hfsfid_cnid = H_FILEID(hp); - hfsfhp->hfsfid_gen = hp->h_meta->h_crtime; + hfsfhp->hfsfid_cnid = cp->c_cnid; + hfsfhp->hfsfid_gen = cp->c_itime; - return 0; + return (0); } /* * Initial HFS filesystems, done only once. */ -int +static int hfs_init(vfsp) -struct vfsconf *vfsp; + struct vfsconf *vfsp; { - int i; - static int done = 0; - OSErr err; - - DBG_FUNC_NAME("hfs_init"); - DBG_PRINT_FUNC_NAME(); - - if (done) - return (0); - done = 1; - hfs_vhashinit(); - hfs_converterinit(); + static int done = 0; - simple_lock_init (&gBufferPtrListLock); - - for (i = BUFFERPTRLISTSIZE - 1; i >= 0; --i) { - gBufferAddress[i] = NULL; - gBufferHeaderPtr[i] = NULL; - }; - gBufferListIndex = 0; + if (done) + return (0); + done = 1; + hfs_chashinit(); + hfs_converterinit(); +#if QUOTA + dqinit(); +#endif /* QUOTA */ /* * Allocate Catalog Iterator cache... */ - err = InitCatalogCache(); + (void) InitCatalogCache(); - return E_NONE; + return (0); } /* - * fast filesystem related variables. + * HFS filesystem related variables. */ -static int hfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) -int *name; -u_int namelen; -void *oldp; -size_t *oldlenp; -void *newp; -size_t newlen; -struct proc *p; +static int +hfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) + int *name; + u_int namelen; + void *oldp; + size_t *oldlenp; + void *newp; + size_t newlen; + struct proc *p; { - DBG_FUNC_NAME("hfs_sysctl"); - DBG_PRINT_FUNC_NAME(); + extern u_int32_t hfs_encodingbias; + + /* all sysctl names at this level are terminal */ + if (namelen != 1) + return (ENOTDIR); /* overloaded */ - return (EOPNOTSUPP); + if (name[0] == HFS_ENCODINGBIAS) + return (sysctl_int(oldp, oldlenp, newp, newlen, + &hfs_encodingbias)); + + return (EOPNOTSUPP); } /* This will return a vnode of either a directory or a data vnode based on an object id. If * it is a file id, its data fork will be returned. */ +static int +hfs_vget(mp, ino, vpp) + struct mount *mp; + void *ino; + struct vnode **vpp; +{ + cnid_t cnid = *(cnid_t *)ino; + + /* Check for cnids that should't be exported. */ + if ((cnid < kHFSFirstUserCatalogNodeID) + && (cnid != kHFSRootFolderID && cnid != kHFSRootParentID)) + return (ENOENT); + /* Don't export HFS Private Data dir. */ + if (cnid == VFSTOHFS(mp)->hfs_privdir_desc.cd_cnid) + return (ENOENT); + + return (hfs_getcnode(VFSTOHFS(mp), cnid, NULL, 0, NULL, NULL, vpp)); +} + +/* + * Flush out all the files in a filesystem. + */ int -hfs_vget(struct mount *mp, - void *ino, - struct vnode **vpp) +hfs_flushfiles(struct mount *mp, int flags, struct proc *p) { - struct hfsmount *hfsmp; - dev_t dev; - int retval = E_NONE; + register struct hfsmount *hfsmp; + int i; + int error; - DBG_VFS(("hfs_vget: ino = %ld\n", *(UInt32 *)ino)); +#if QUOTA + hfsmp = VFSTOHFS(mp); - /* Check if unmount in progress */ - if (mp->mnt_kern_flag & MNTK_UNMOUNT) { - *vpp = NULL; - return (EPERM); + if (mp->mnt_flag & MNT_QUOTA) { + if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags)) + return (error); + for (i = 0; i < MAXQUOTAS; i++) { + if (hfsmp->hfs_qfiles[i].qf_vp == NULLVP) + continue; + hfs_quotaoff(p, mp, i); + } + /* + * Here we fall through to vflush again to ensure + * that we have gotten rid of all the system vnodes. + */ } +#endif /* QUOTA */ - hfsmp = VFSTOHFS(mp); - dev = hfsmp->hfs_raw_dev; - - /* First check to see if it is in the cache */ - *vpp = hfs_vhashget(dev, *(UInt32 *)ino, kDefault); - - /* hide open files that have been deleted */ - if (*vpp != NULL) { - if ((VTOH(*vpp)->h_meta->h_metaflags & IN_NOEXISTS) || - (hfsmp->hfs_private_metadata_dir != 0) && - (H_DIRID(VTOH(*vpp)) == hfsmp->hfs_private_metadata_dir)) { - vput(*vpp); - retval = ENOENT; - goto Err_Exit; - } - } - - /* The vnode is not in the cache, so lets make it */ - if (*vpp == NULL) - { - hfsCatalogInfo catInfo; - struct proc *p = current_proc(); - UInt8 forkType; - - INIT_CATALOGDATA(&catInfo.nodeData, 0); - catInfo.hint = kNoHint; - /* Special-case the root's parent directory (DirID = 1) because - it doesn't actually exist in the catalog: */ - if ((*vpp == NULL) && (*(UInt32 *)ino == kRootParID)) { - bzero(&catInfo, sizeof(catInfo)); - catInfo.nodeData.cnd_type = kCatalogFolderNode; - catInfo.nodeData.cnm_nameptr = catInfo.nodeData.cnm_namespace; - catInfo.nodeData.cnm_namespace[0] = '/'; - catInfo.nodeData.cnm_length = 1; - catInfo.nodeData.cnd_nodeID = kRootParID; - catInfo.nodeData.cnm_parID = kRootParID; - catInfo.nodeData.cnd_valence = 1; - catInfo.nodeData.cnd_ownerID = 0; - catInfo.nodeData.cnd_groupID = 0; - catInfo.nodeData.cnd_mode = (S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO); - } else { - - /* lock catalog b-tree */ - retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_SHARED, p); - if (retval != E_NONE) goto Lookup_Err_Exit; - - retval = hfs_getcatalog(VFSTOVCB(mp), *(UInt32 *)ino, NULL, -1, &catInfo); - - /* unlock catalog b-tree */ - (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); - - if (retval != E_NONE) goto Lookup_Err_Exit; - - /* hide open files that have been deleted */ - if ((hfsmp->hfs_private_metadata_dir != 0) && - (catInfo.nodeData.cnm_parID == hfsmp->hfs_private_metadata_dir)) { - retval = ENOENT; - goto Lookup_Err_Exit; - }; - }; - - forkType = (catInfo.nodeData.cnd_type == kCatalogFolderNode) ? kDirectory : kDataFork; - retval = hfs_vcreate(VFSTOVCB(mp), &catInfo, forkType, vpp); - -Lookup_Err_Exit: - CLEAN_CATALOGDATA(&catInfo.nodeData); - }; - - UBCINFOCHECK("hfs_vget", *vpp); - -Err_Exit: + error = vflush(mp, NULLVP, (SKIPSYSTEM | SKIPSWAP | flags)); + error = vflush(mp, NULLVP, (SKIPSYSTEM | flags)); - /* rember if a parent directory was looked up by CNID */ - if (retval == 0 && ((*vpp)->v_type == VDIR) - && lockstatus(&mp->mnt_lock) != LK_SHARED) - VTOH(*vpp)->h_nodeflags |= IN_BYCNID; + return (error); +} - return (retval); +/* + * Update volume encoding bitmap (HFS Plus only) + */ +__private_extern__ +void +hfs_setencodingbits(struct hfsmount *hfsmp, u_int32_t encoding) +{ +#define kIndexMacUkrainian 48 /* MacUkrainian encoding is 152 */ +#define kIndexMacFarsi 49 /* MacFarsi encoding is 140 */ + + UInt32 index; + + switch (encoding) { + case kTextEncodingMacUkrainian: + index = kIndexMacUkrainian; + break; + case kTextEncodingMacFarsi: + index = kIndexMacFarsi; + break; + default: + index = encoding; + break; + } + if (index < 128) { + HFSTOVCB(hfsmp)->encodingsBitmap |= (1 << index); + HFSTOVCB(hfsmp)->vcbFlags |= 0xFF00; + } } /* - * Flush out all the files in a filesystem. + * Update volume stats */ +__private_extern__ int -hfs_flushfiles(struct mount *mp, int flags) +hfs_volupdate(struct hfsmount *hfsmp, enum volop op, int inroot) { - int error; - - error = vflush(mp, NULLVP, (SKIPSYSTEM | SKIPSWAP | flags)); - error = vflush(mp, NULLVP, (SKIPSYSTEM | flags)); + ExtendedVCB *vcb; - return (error); + vcb = HFSTOVCB(hfsmp); + vcb->vcbFlags |= 0xFF00; + vcb->vcbLsMod = time.tv_sec; + + switch (op) { + case VOL_UPDATE: + break; + case VOL_MKDIR: + if (vcb->vcbDirCnt != 0xFFFFFFFF) + ++vcb->vcbDirCnt; + if (inroot && vcb->vcbNmRtDirs != 0xFFFF) + ++vcb->vcbNmRtDirs; + break; + case VOL_RMDIR: + if (vcb->vcbDirCnt != 0) + --vcb->vcbDirCnt; + if (inroot && vcb->vcbNmRtDirs != 0xFFFF) + --vcb->vcbNmRtDirs; + break; + case VOL_MKFILE: + if (vcb->vcbFilCnt != 0xFFFFFFFF) + ++vcb->vcbFilCnt; + if (inroot && vcb->vcbNmFls != 0xFFFF) + ++vcb->vcbNmFls; + break; + case VOL_RMFILE: + if (vcb->vcbFilCnt != 0) + --vcb->vcbFilCnt; + if (inroot && vcb->vcbNmFls != 0xFFFF) + --vcb->vcbNmFls; + break; + } + return (0); } -short hfs_flushMDB(struct hfsmount *hfsmp, int waitfor) + +static int +hfs_flushMDB(struct hfsmount *hfsmp, int waitfor, int altflush) { - ExtendedVCB *vcb = HFSTOVCB(hfsmp); - FCB *fcb; + ExtendedVCB *vcb = HFSTOVCB(hfsmp); + struct filefork *fp; HFSMasterDirectoryBlock *mdb; - struct buf *bp; - int retval; - int size = kMDBSize; /* 512 */ - ByteCount namelen; - - if (vcb->vcbSigWord != kHFSSigWord) - return EINVAL; + struct buf *bp = NULL; + int retval; + int sectorsize; + ByteCount namelen; - DBG_ASSERT(hfsmp->hfs_devvp != NULL); + sectorsize = hfsmp->hfs_phys_block_size; - retval = bread(hfsmp->hfs_devvp, IOBLKNOFORBLK(kMasterDirectoryBlock, size), - IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, size), NOCRED, &bp); + retval = bread(hfsmp->hfs_devvp, HFS_PRI_SECTOR(sectorsize), sectorsize, NOCRED, &bp); if (retval) { - DBG_VFS((" hfs_flushMDB bread return error! (%d)\n", retval)); - if (bp) brelse(bp); + if (bp) + brelse(bp); return retval; } - DBG_ASSERT(bp != NULL); - DBG_ASSERT(bp->b_data != NULL); - DBG_ASSERT(bp->b_bcount == size); + DBG_ASSERT(bp != NULL); + DBG_ASSERT(bp->b_data != NULL); + DBG_ASSERT(bp->b_bcount == size); - mdb = (HFSMasterDirectoryBlock *)((char *)bp->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, size)); + mdb = (HFSMasterDirectoryBlock *)(bp->b_data + HFS_PRI_OFFSET(sectorsize)); - VCB_LOCK(vcb); - mdb->drCrDate = SWAP_BE32 (UTCToLocal(vcb->vcbCrDate)); - mdb->drLsMod = SWAP_BE32 (UTCToLocal(vcb->vcbLsMod)); - mdb->drAtrb = SWAP_BE16 (vcb->vcbAtrb); + mdb->drCrDate = SWAP_BE32 (UTCToLocal(to_hfs_time(vcb->vcbCrDate))); + mdb->drLsMod = SWAP_BE32 (UTCToLocal(to_hfs_time(vcb->vcbLsMod))); + mdb->drAtrb = SWAP_BE16 (vcb->vcbAtrb); mdb->drNmFls = SWAP_BE16 (vcb->vcbNmFls); mdb->drAllocPtr = SWAP_BE16 (vcb->nextAllocation); mdb->drClpSiz = SWAP_BE32 (vcb->vcbClpSiz); @@ -1791,7 +1733,7 @@ short hfs_flushMDB(struct hfsmount *hfsmp, int waitfor) if (retval) retval = utf8_to_mac_roman(namelen, vcb->vcbVN, mdb->drVN); - mdb->drVolBkUp = SWAP_BE32 (UTCToLocal(vcb->vcbVolBkUp)); + mdb->drVolBkUp = SWAP_BE32 (UTCToLocal(to_hfs_time(vcb->vcbVolBkUp))); mdb->drWrCnt = SWAP_BE32 (vcb->vcbWrCnt); mdb->drNmRtDirs = SWAP_BE16 (vcb->vcbNmRtDirs); mdb->drFilCnt = SWAP_BE32 (vcb->vcbFilCnt); @@ -1799,34 +1741,43 @@ short hfs_flushMDB(struct hfsmount *hfsmp, int waitfor) bcopy(vcb->vcbFndrInfo, mdb->drFndrInfo, sizeof(mdb->drFndrInfo)); - fcb = VTOFCB(vcb->extentsRefNum); - /* HFSPlusToHFSExtents(fcb->fcbExtents, mdb->drXTExtRec); */ - mdb->drXTExtRec[0].startBlock = SWAP_BE16 (fcb->fcbExtents[0].startBlock); - mdb->drXTExtRec[0].blockCount = SWAP_BE16 (fcb->fcbExtents[0].blockCount); - mdb->drXTExtRec[1].startBlock = SWAP_BE16 (fcb->fcbExtents[1].startBlock); - mdb->drXTExtRec[1].blockCount = SWAP_BE16 (fcb->fcbExtents[1].blockCount); - mdb->drXTExtRec[2].startBlock = SWAP_BE16 (fcb->fcbExtents[2].startBlock); - mdb->drXTExtRec[2].blockCount = SWAP_BE16 (fcb->fcbExtents[2].blockCount); - - mdb->drXTFlSize = SWAP_BE32 (fcb->fcbPLen); - mdb->drXTClpSiz = SWAP_BE32 (fcb->fcbClmpSize); + fp = VTOF(vcb->extentsRefNum); + mdb->drXTExtRec[0].startBlock = SWAP_BE16 (fp->ff_extents[0].startBlock); + mdb->drXTExtRec[0].blockCount = SWAP_BE16 (fp->ff_extents[0].blockCount); + mdb->drXTExtRec[1].startBlock = SWAP_BE16 (fp->ff_extents[1].startBlock); + mdb->drXTExtRec[1].blockCount = SWAP_BE16 (fp->ff_extents[1].blockCount); + mdb->drXTExtRec[2].startBlock = SWAP_BE16 (fp->ff_extents[2].startBlock); + mdb->drXTExtRec[2].blockCount = SWAP_BE16 (fp->ff_extents[2].blockCount); + mdb->drXTFlSize = SWAP_BE32 (fp->ff_blocks * vcb->blockSize); + mdb->drXTClpSiz = SWAP_BE32 (fp->ff_clumpsize); - fcb = VTOFCB(vcb->catalogRefNum); - /* HFSPlusToHFSExtents(fcb->fcbExtents, mdb->drCTExtRec); */ - mdb->drCTExtRec[0].startBlock = SWAP_BE16 (fcb->fcbExtents[0].startBlock); - mdb->drCTExtRec[0].blockCount = SWAP_BE16 (fcb->fcbExtents[0].blockCount); - mdb->drCTExtRec[1].startBlock = SWAP_BE16 (fcb->fcbExtents[1].startBlock); - mdb->drCTExtRec[1].blockCount = SWAP_BE16 (fcb->fcbExtents[1].blockCount); - mdb->drCTExtRec[2].startBlock = SWAP_BE16 (fcb->fcbExtents[2].startBlock); - mdb->drCTExtRec[2].blockCount = SWAP_BE16 (fcb->fcbExtents[2].blockCount); - - mdb->drCTFlSize = SWAP_BE32 (fcb->fcbPLen); - mdb->drCTClpSiz = SWAP_BE32 (fcb->fcbClmpSize); - VCB_UNLOCK(vcb); + fp = VTOF(vcb->catalogRefNum); + mdb->drCTExtRec[0].startBlock = SWAP_BE16 (fp->ff_extents[0].startBlock); + mdb->drCTExtRec[0].blockCount = SWAP_BE16 (fp->ff_extents[0].blockCount); + mdb->drCTExtRec[1].startBlock = SWAP_BE16 (fp->ff_extents[1].startBlock); + mdb->drCTExtRec[1].blockCount = SWAP_BE16 (fp->ff_extents[1].blockCount); + mdb->drCTExtRec[2].startBlock = SWAP_BE16 (fp->ff_extents[2].startBlock); + mdb->drCTExtRec[2].blockCount = SWAP_BE16 (fp->ff_extents[2].blockCount); + mdb->drCTFlSize = SWAP_BE32 (fp->ff_blocks * vcb->blockSize); + mdb->drCTClpSiz = SWAP_BE32 (fp->ff_clumpsize); + + /* If requested, flush out the alternate MDB */ + if (altflush) { + struct buf *alt_bp = NULL; + u_long altIDSector; + + altIDSector = HFS_ALT_SECTOR(sectorsize, hfsmp->hfs_phys_block_count); + + if (meta_bread(hfsmp->hfs_devvp, altIDSector, sectorsize, NOCRED, &alt_bp) == 0) { + bcopy(mdb, alt_bp->b_data + HFS_ALT_OFFSET(sectorsize), kMDBSize); + (void) VOP_BWRITE(alt_bp); + } else if (alt_bp) + brelse(alt_bp); + } - if (waitfor != MNT_WAIT) + if (waitfor != MNT_WAIT) bawrite(bp); - else + else retval = VOP_BWRITE(bp); MarkVCBClean( vcb ); @@ -1835,51 +1786,56 @@ short hfs_flushMDB(struct hfsmount *hfsmp, int waitfor) } -short hfs_flushvolumeheader(struct hfsmount *hfsmp, int waitfor) +__private_extern__ +int +hfs_flushvolumeheader(struct hfsmount *hfsmp, int waitfor, int altflush) { - ExtendedVCB *vcb = HFSTOVCB(hfsmp); - FCB *fcb; - HFSPlusVolumeHeader *volumeHeader; - int retval; - struct buf *bp; - int i; + ExtendedVCB *vcb = HFSTOVCB(hfsmp); + struct filefork *fp; + HFSPlusVolumeHeader *volumeHeader; + int retval; + struct buf *bp; + int i; int sectorsize; int priIDSector; + int critical = 0; - if (vcb->vcbSigWord != kHFSPlusSigWord) - return EINVAL; + if (vcb->vcbSigWord == kHFSSigWord) + return hfs_flushMDB(hfsmp, waitfor, altflush); + if (altflush) + critical = 1; sectorsize = hfsmp->hfs_phys_block_size; priIDSector = (vcb->hfsPlusIOPosOffset / sectorsize) + HFS_PRI_SECTOR(sectorsize); retval = meta_bread(hfsmp->hfs_devvp, priIDSector, sectorsize, NOCRED, &bp); if (retval) { - DBG_VFS((" hfs_flushvolumeheader bread return error! (%d)\n", retval)); - if (bp) brelse(bp); - return retval; + if (bp) + brelse(bp); + return (retval); } - DBG_ASSERT(bp != NULL); - DBG_ASSERT(bp->b_data != NULL); - DBG_ASSERT(bp->b_bcount == size); - volumeHeader = (HFSPlusVolumeHeader *)((char *)bp->b_data + HFS_PRI_OFFSET(sectorsize)); /* * For embedded HFS+ volumes, update create date if it changed * (ie from a setattrlist call) */ - if ((vcb->hfsPlusIOPosOffset != 0) && (SWAP_BE32 (volumeHeader->createDate) != vcb->localCreateDate)) - { - struct buf *bp2; + if ((vcb->hfsPlusIOPosOffset != 0) && + (SWAP_BE32 (volumeHeader->createDate) != vcb->localCreateDate)) { + struct buf *bp2; HFSMasterDirectoryBlock *mdb; - retval = meta_bread(hfsmp->hfs_devvp, HFS_PRI_SECTOR(sectorsize), sectorsize, NOCRED, &bp2); - if (retval != E_NONE) { - if (bp2) brelse(bp2); + retval = meta_bread(hfsmp->hfs_devvp, HFS_PRI_SECTOR(sectorsize), + sectorsize, NOCRED, &bp2); + if (retval) { + if (bp2) + brelse(bp2); + retval = 0; } else { - mdb = (HFSMasterDirectoryBlock *)(bp2->b_data + HFS_PRI_OFFSET(sectorsize)); + mdb = (HFSMasterDirectoryBlock *)(bp2->b_data + + HFS_PRI_OFFSET(sectorsize)); if ( SWAP_BE32 (mdb->drCrDate) != vcb->localCreateDate ) { @@ -1892,95 +1848,112 @@ short hfs_flushvolumeheader(struct hfsmount *hfsmp, int waitfor) brelse(bp2); /* just release it */ } } - } + } - VCB_LOCK(vcb); /* Note: only update the lower 16 bits worth of attributes */ - volumeHeader->attributes = SWAP_BE32 ((SWAP_BE32 (volumeHeader->attributes) & 0xFFFF0000) + (UInt16) vcb->vcbAtrb); - volumeHeader->lastMountedVersion = SWAP_BE32 (kHFSPlusMountVersion); - volumeHeader->createDate = SWAP_BE32 (vcb->localCreateDate); /* volume create date is in local time */ - volumeHeader->modifyDate = SWAP_BE32 (vcb->vcbLsMod); - volumeHeader->backupDate = SWAP_BE32 (vcb->vcbVolBkUp); - volumeHeader->checkedDate = SWAP_BE32 (vcb->checkedDate); - volumeHeader->fileCount = SWAP_BE32 (vcb->vcbFilCnt); - volumeHeader->folderCount = SWAP_BE32 (vcb->vcbDirCnt); - volumeHeader->freeBlocks = SWAP_BE32 (vcb->freeBlocks); - volumeHeader->nextAllocation = SWAP_BE32 (vcb->nextAllocation); - volumeHeader->rsrcClumpSize = SWAP_BE32 (vcb->vcbClpSiz); - volumeHeader->dataClumpSize = SWAP_BE32 (vcb->vcbClpSiz); - volumeHeader->nextCatalogID = SWAP_BE32 (vcb->vcbNxtCNID); - volumeHeader->writeCount = SWAP_BE32 (vcb->vcbWrCnt); - volumeHeader->encodingsBitmap = SWAP_BE64 (vcb->encodingsBitmap); - - bcopy( vcb->vcbFndrInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo) ); - - VCB_UNLOCK(vcb); - - fcb = VTOFCB(vcb->extentsRefNum); - /* bcopy( fcb->fcbExtents, volumeHeader->extentsFile.extents, sizeof(HFSPlusExtentRecord) ); */ - for (i = 0; i < kHFSPlusExtentDensity; i++) { - volumeHeader->extentsFile.extents[i].startBlock = SWAP_BE32 (fcb->fcbExtents[i].startBlock); - volumeHeader->extentsFile.extents[i].blockCount = SWAP_BE32 (fcb->fcbExtents[i].blockCount); - } - - fcb->fcbFlags &= ~fcbModifiedMask; - volumeHeader->extentsFile.logicalSize = SWAP_BE64 (fcb->fcbEOF); - volumeHeader->extentsFile.totalBlocks = SWAP_BE32 (fcb->fcbPLen / vcb->blockSize); - volumeHeader->extentsFile.clumpSize = SWAP_BE32 (fcb->fcbClmpSize); - - fcb = VTOFCB(vcb->catalogRefNum); - /* bcopy( fcb->fcbExtents, volumeHeader->catalogFile.extents, sizeof(HFSPlusExtentRecord) ); */ - for (i = 0; i < kHFSPlusExtentDensity; i++) { - volumeHeader->catalogFile.extents[i].startBlock = SWAP_BE32 (fcb->fcbExtents[i].startBlock); - volumeHeader->catalogFile.extents[i].blockCount = SWAP_BE32 (fcb->fcbExtents[i].blockCount); - } - - fcb->fcbFlags &= ~fcbModifiedMask; - volumeHeader->catalogFile.logicalSize = SWAP_BE64 (fcb->fcbEOF); - volumeHeader->catalogFile.totalBlocks = SWAP_BE32 (fcb->fcbPLen / vcb->blockSize); - volumeHeader->catalogFile.clumpSize = SWAP_BE32 (fcb->fcbClmpSize); - - fcb = VTOFCB(vcb->allocationsRefNum); - /* bcopy( fcb->fcbExtents, volumeHeader->allocationFile.extents, sizeof(HFSPlusExtentRecord) ); */ - for (i = 0; i < kHFSPlusExtentDensity; i++) { - volumeHeader->allocationFile.extents[i].startBlock = SWAP_BE32 (fcb->fcbExtents[i].startBlock); - volumeHeader->allocationFile.extents[i].blockCount = SWAP_BE32 (fcb->fcbExtents[i].blockCount); - } - - fcb->fcbFlags &= ~fcbModifiedMask; - volumeHeader->allocationFile.logicalSize = SWAP_BE64 (fcb->fcbEOF); - volumeHeader->allocationFile.totalBlocks = SWAP_BE32 (fcb->fcbPLen / vcb->blockSize); - volumeHeader->allocationFile.clumpSize = SWAP_BE32 (fcb->fcbClmpSize); - - if (waitfor != MNT_WAIT) - bawrite(bp); - else + volumeHeader->attributes = SWAP_BE32 ((SWAP_BE32 (volumeHeader->attributes) & 0xFFFF0000) + (UInt16) vcb->vcbAtrb); + volumeHeader->lastMountedVersion = SWAP_BE32 (kHFSPlusMountVersion); + volumeHeader->createDate = SWAP_BE32 (vcb->localCreateDate); /* volume create date is in local time */ + volumeHeader->modifyDate = SWAP_BE32 (to_hfs_time(vcb->vcbLsMod)); + volumeHeader->backupDate = SWAP_BE32 (to_hfs_time(vcb->vcbVolBkUp)); + volumeHeader->fileCount = SWAP_BE32 (vcb->vcbFilCnt); + volumeHeader->folderCount = SWAP_BE32 (vcb->vcbDirCnt); + volumeHeader->freeBlocks = SWAP_BE32 (vcb->freeBlocks); + volumeHeader->nextAllocation = SWAP_BE32 (vcb->nextAllocation); + volumeHeader->rsrcClumpSize = SWAP_BE32 (vcb->vcbClpSiz); + volumeHeader->dataClumpSize = SWAP_BE32 (vcb->vcbClpSiz); + volumeHeader->nextCatalogID = SWAP_BE32 (vcb->vcbNxtCNID); + volumeHeader->writeCount = SWAP_BE32 (vcb->vcbWrCnt); + volumeHeader->encodingsBitmap = SWAP_BE64 (vcb->encodingsBitmap); + + if (bcmp(vcb->vcbFndrInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo)) != 0) + critical = 1; + bcopy(vcb->vcbFndrInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo)); + + /* Sync Extents over-flow file meta data */ + fp = VTOF(vcb->extentsRefNum); + for (i = 0; i < kHFSPlusExtentDensity; i++) { + volumeHeader->extentsFile.extents[i].startBlock = + SWAP_BE32 (fp->ff_extents[i].startBlock); + volumeHeader->extentsFile.extents[i].blockCount = + SWAP_BE32 (fp->ff_extents[i].blockCount); + } + FTOC(fp)->c_flag &= ~C_MODIFIED; + volumeHeader->extentsFile.logicalSize = SWAP_BE64 (fp->ff_size); + volumeHeader->extentsFile.totalBlocks = SWAP_BE32 (fp->ff_blocks); + volumeHeader->extentsFile.clumpSize = SWAP_BE32 (fp->ff_clumpsize); + + /* Sync Catalog file meta data */ + fp = VTOF(vcb->catalogRefNum); + for (i = 0; i < kHFSPlusExtentDensity; i++) { + volumeHeader->catalogFile.extents[i].startBlock = + SWAP_BE32 (fp->ff_extents[i].startBlock); + volumeHeader->catalogFile.extents[i].blockCount = + SWAP_BE32 (fp->ff_extents[i].blockCount); + } + FTOC(fp)->c_flag &= ~C_MODIFIED; + volumeHeader->catalogFile.logicalSize = SWAP_BE64 (fp->ff_size); + volumeHeader->catalogFile.totalBlocks = SWAP_BE32 (fp->ff_blocks); + volumeHeader->catalogFile.clumpSize = SWAP_BE32 (fp->ff_clumpsize); + + /* Sync Allocation file meta data */ + fp = VTOF(vcb->allocationsRefNum); + for (i = 0; i < kHFSPlusExtentDensity; i++) { + volumeHeader->allocationFile.extents[i].startBlock = + SWAP_BE32 (fp->ff_extents[i].startBlock); + volumeHeader->allocationFile.extents[i].blockCount = + SWAP_BE32 (fp->ff_extents[i].blockCount); + } + FTOC(fp)->c_flag &= ~C_MODIFIED; + volumeHeader->allocationFile.logicalSize = SWAP_BE64 (fp->ff_size); + volumeHeader->allocationFile.totalBlocks = SWAP_BE32 (fp->ff_blocks); + volumeHeader->allocationFile.clumpSize = SWAP_BE32 (fp->ff_clumpsize); + + /* If requested, flush out the alternate volume header */ + if (altflush) { + struct buf *alt_bp = NULL; + u_long altIDSector; + + altIDSector = (vcb->hfsPlusIOPosOffset / sectorsize) + + HFS_ALT_SECTOR(sectorsize, hfsmp->hfs_phys_block_count); + + if (meta_bread(hfsmp->hfs_devvp, altIDSector, sectorsize, NOCRED, &alt_bp) == 0) { + bcopy(volumeHeader, alt_bp->b_data + HFS_ALT_OFFSET(sectorsize), kMDBSize); + (void) VOP_BWRITE(alt_bp); + } else if (alt_bp) + brelse(alt_bp); + } + + if (waitfor != MNT_WAIT) + bawrite(bp); + else { retval = VOP_BWRITE(bp); + /* When critical data changes, flush the device cache */ + if (critical && (retval == 0)) { + (void) VOP_IOCTL(hfsmp->hfs_devvp, DKIOCSYNCHRONIZECACHE, + NULL, FWRITE, NOCRED, current_proc()); + } + } - MarkVCBClean( vcb ); - + vcb->vcbFlags &= 0x00FF; return (retval); } -/* - * Moved here to avoid having to define prototypes - */ - /* * hfs vfs operations. */ struct vfsops hfs_vfsops = { - hfs_mount, - hfs_start, - hfs_unmount, - hfs_root, - hfs_quotactl, - hfs_statfs, - hfs_sync, - hfs_vget, - hfs_fhtovp, - hfs_vptofh, - hfs_init, - hfs_sysctl + hfs_mount, + hfs_start, + hfs_unmount, + hfs_root, + hfs_quotactl, + hfs_statfs, + hfs_sync, + hfs_vget, + hfs_fhtovp, + hfs_vptofh, + hfs_init, + hfs_sysctl }; diff --git a/bsd/hfs/hfs_vfsutils.c b/bsd/hfs/hfs_vfsutils.c index e69c2e046..c45f8a898 100644 --- a/bsd/hfs/hfs_vfsutils.c +++ b/bsd/hfs/hfs_vfsutils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,145 +21,41 @@ */ /* @(#)hfs_vfsutils.c 4.0 * -* (c) 1997-2000 Apple Computer, Inc. All Rights Reserved +* (c) 1997-2002 Apple Computer, Inc. All Rights Reserved * * hfs_vfsutils.c -- Routines that go between the HFS layer and the VFS. * -* Change History (most recent first): -* -* 22-Jan-2000 Don Brady Remove calls to MountCheck. -* 7-Sep-1999 Don Brady Add HFS Plus hard-link support. -* 25-Aug-1999 Don Brady Dont't use vcbAlBlSt for HFS plus volumes (2350009). -* 9-Aug-1999 Pat Dirks Added support for ATTR_VOL_ENCODINGSUSED [#2357367]. -* 16-Jul-1999 Pat Dirks Fixed PackCommonCatalogInfoAttributeBlock to return full range of possible vnode types [#2317604] -* 15-Jun-1999 Pat Dirks Added support for return of mounted device in hfs_getattrlist [#2345297]. -* 9-Jun-1999 Don Brady Cleanup vcb accesses in hfs_MountHFSVolume. -* 3-Jun-1999 Don Brady Remove references to unused/legacy vcb fields (eg vcbXTClpSiz). -* 21-May-1999 Don Brady Add call to hfs_vinit in hfsGet to support mknod. -* 6-Apr-1999 Don Brady Fixed de-reference of NULL dvp in hfsGet. -* 22-Mar-1999 Don Brady Add support for UFS delete semantics. -* 1-Mar-1999 Scott Roberts Dont double MALLOC on long names. -* 23-Feb-1999 Pat Dirks Change incrementing of meta refcount to be done BEFORE lock is acquired. -* 2-Feb-1999 Pat Dirks For volume ATTR_CMN_SCRIPT use vcb->volumeNameEncodingHint instead of 0. -* 10-Mar-1999 Don Brady Removing obsolete code. -* 2-Feb-1999 Don Brady For volume ATTR_CMN_SCRIPT use vcb->volumeNameEncodingHint instead of 0. -* 18-Jan-1999 Pat Dirks Changed CopyCatalogToHFSNode to start with ACCESSPERMS instead of adding -* write access only for unlocked files (now handled via IMMUTABLE setting) -* 7-Dec-1998 Pat Dirks Changed PackCatalogInfoFileAttributeBlock to return proper I/O block size. -* 7-Dec-1998 Don Brady Pack the real text encoding instead of zero. -* 16-Dec-1998 Don Brady Use the root's crtime intead of vcb create time for getattrlist. -* 16-Dec-1998 Don Brady Use the root's crtime intead of vcb create time for getattrlist. -* 2-Dec-1998 Scott Roberts Copy the mdbVN correctly into the vcb. -* 3-Dec-1998 Pat Dirks Added support for ATTR_VOL_MOUNTFLAGS. -* 20-Nov-1998 Don Brady Add support for UTF-8 names. -* 18-Nov-1998 Pat Dirks Changed UnpackCommonAttributeBlock to call wait for hfs_chflags to update catalog entry when changing flags -* 13-Nov-1998 Pat Dirks Changed BestBlockSizeFit to try PAGE_SIZE only and skip check for MAXBSIZE. -* 10-Nov-1998 Pat Dirks Changed CopyCatalogToHFSNode to ensure consistency between lock flag and IMMUTABLE bits. -* 10-Nov-1998 Pat Dirks Added MapFileOffset(), LogicalBlockSize() and UpdateBlockMappingTable() routines. -* 18-Nov-1998 Pat Dirks Changed PackVolAttributeBlock to return proper logical block size -* for ATTR_VOL_IOBLOCKSIZE attribute. -* 3-Nov-1998 Umesh Vaishampayan Changes to deal with "struct timespec" -* change in the kernel. -* 23-Sep-1998 Don Brady In UnpackCommonAttributeBlock simplified setting of gid, uid and mode. -* 10-Nov-1998 Pat Dirks Added MapFileOffset(), LogicalBlockSize() and UpdateBlockMappingTable() routines. -* 17-Sep-1998 Pat Dirks Changed BestBlockSizeFit to try MAXBSIZE and PAGE_SIZE first. -* 8-Sep-1998 Don Brady Fix CopyVNodeToCatalogNode to use h_mtime for contentModDate (instead of h_ctime). -* 4-Sep-1998 Pat Dirks Added BestBlockSizeFit routine. -* 18-Aug-1998 Don Brady Change DEBUG_BREAK_MSG to a DBG_UTILS in MacToVFSError (radar #2262802). -* 30-Jun-1998 Don Brady Add calls to MacToVFSError to hfs/hfsplus mount routines (for radar #2249539). -* 22-Jun-1998 Don Brady Add more error cases to MacToVFSError; all HFS Common errors are negative. -* Changed hfsDelete to call DeleteFile for files. -* 4-Jun-1998 Pat Dirks Changed incorrect references to 'vcbAlBlkSize' to 'blockSize'; -* Added hfsCreateFileID. -* 4-Jun-1998 Don Brady Add hfsMoveRename to replace hfsMove and hfsRename. Use VPUT/VRELE macros -* instead of vput/vrele to catch bad ref counts. -* 28-May-1998 Pat Dirks Adjusted for change in definition of ATTR_CMN_NAME and removed ATTR_CMN_RAWDEVICE. -* 7-May-1998 Don Brady Added check for NULL vp to hfs_metafilelocking (radar #2233832). -* 24-Apr-1998 Pat Dirks Fixed AttributeBlockSize to return only length of variable attribute block. -* 4/21/1998 Don Brady Add SUPPORTS_MAC_ALIASES conditional (for radar #2225419). -* 4/21/1998 Don Brady Map cmNotEmpty errors to ENOTEMPTY (radar #2229259). -* 4/21/1998 Don Brady Fix up time/date conversions. -* 4/20/1998 Don Brady Remove course-grained hfs metadata locking. -* 4/18/1998 Don Brady Add VCB locking. -* 4/17/1998 Pat Dirks Fixed PackFileAttributeBlock to return more up-to-date EOF/PEOF info from vnode. -* 4/15/1998 Don Brady Add hasOverflowExtents and hfs_metafilelocking. Use ExtendBTreeFile instead -* of SetEndOfForkProc. Set forktype for system files. -* 4/14/1998 Deric Horn PackCatalogInfoAttributeBlock(), and related packing routines to -* pack attribute data given hfsCatalogInfo, without the objects vnode; -* 4/14/1998 Scott Roberts Add execute priviledges to all hfs objects. -* 4/9/1998 Don Brady Add MDB/VolumeHeader flushing to hfsUnmount; -* 4/8/1998 Don Brady Make sure vcbVRefNum field gets initialized (use MAKE_VREFNUM). -* 4/6/1998 Don Brady Removed calls to CreateVolumeCatalogCache (obsolete). -* 4/06/1998 Scott Roberts Added complex file support. -* 4/02/1998 Don Brady UpdateCatalogNode now takes parID and name as input. -* 3/31/1998 Don Brady Sync up with final HFSVolumes.h header file. -* 3/31/1998 Don Brady Check result from UFSToHFSStr to make sure hfs/hfs+ names are not greater -* than 31 characters. -* 3/30/1998 Don Brady In InitMetaFileVNode set VSYSTEM bit in vnode's v_flag. -* 3/26/1998 Don Brady Cleaned up hfs_MountXXX routines. Removed CloseBtreeFile and OpenBTreeFile. -* Simplified hfsUnmount (removed MacOS specific code). -* 3/17/1998 Don Brady AttributeBlockSize calculation did not account for the size field (4bytes). -* PackVolCommonAttributes and PackCommonAttributeBlock for ATTR_CMN_NAME -* were not setting up the name correctly. -* 3/17/1998 Don Brady Changed CreateCatalogNode interface to take kCatalogFolderNode and -* kCatalogFileNode as type input. Also, force MountCheck to always run. -* 12-nov-1997 Scott Roberts Initially created file. -* 17-Mar-98 ser Broke out and created CopyCatalogToHFSNode() -* */ #include #include #include #include #include -#include #include +#include #include #include #include #include #include "hfs.h" +#include "hfs_catalog.h" #include "hfs_dbg.h" #include "hfs_mount.h" #include "hfs_endian.h" +#include "hfs_cnode.h" #include "hfscommon/headers/FileMgrInternal.h" #include "hfscommon/headers/BTreesInternal.h" #include "hfscommon/headers/HFSUnicodeWrappers.h" -#define SUPPORTS_MAC_ALIASES 0 -#define kMaxSecsForFsync 5 -#define BYPASSBLOCKINGOPTIMIZATION 0 - -extern int (**hfs_vnodeop_p)(void *); -extern int (**hfs_specop_p)(void *); -extern int (**hfs_fifoop_p)(void *); extern int count_lock_queue __P((void)); extern uid_t console_user; -OSErr ValidMasterDirectoryBlock( HFSMasterDirectoryBlock *mdb ); - -/* Externs from vhash */ -extern void hfs_vhashins_sibling(dev_t dev, UInt32 nodeID, struct hfsnode *hp, struct hfsfilemeta **fm); -extern void hfs_vhashins(dev_t dev, UInt32 nodeID,struct hfsnode *hp); -extern struct vnode *hfs_vhashget(dev_t dev, UInt32 nodeID, UInt8 forkType); - -extern int hfs_vinit( struct mount *mntp, int (**specops)(void *), int (**fifoops)(), struct vnode **vpp); - -extern OSErr GetVolumeNameFromCatalog(ExtendedVCB *vcb); - -static int InitMetaFileVNode(struct vnode *vp, off_t eof, u_long clumpSize, const HFSPlusExtentRecord extents, - HFSCatalogNodeID fileID, void * keyCompareProc); static void ReleaseMetaFileVNode(struct vnode *vp); -static void RemovedMetaDataDirectory(ExtendedVCB *vcb); - -void CopyCatalogToObjectMeta(struct hfsCatalogInfo *catalogInfo, struct vnode *vp, struct hfsfilemeta *fm); -void CopyCatalogToFCB(struct hfsCatalogInfo *catalogInfo, struct vnode *vp); -void hfs_name_CatToMeta(CatalogNodeData *nodeData, struct hfsfilemeta *fm); u_int32_t GetLogicalBlockSize(struct vnode *vp); /* BTree accessor routines */ @@ -179,27 +75,30 @@ extern OSStatus ReleaseBTreeBlock(FileReference vp, BlockDescPtr blockPtr, Relea // // //******************************************************************************* +char hfs_catname[] = "Catalog B-tree"; +char hfs_extname[] = "Extents B-tree"; +char hfs_vbmname[] = "Volume Bitmap"; + +char hfs_privdirname[] = + "\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80HFS+ Private Data"; OSErr hfs_MountHFSVolume(struct hfsmount *hfsmp, HFSMasterDirectoryBlock *mdb, struct proc *p) { - ExtendedVCB *vcb = HFSTOVCB(hfsmp); - struct vnode *tmpvnode; - OSErr err; - HFSPlusExtentRecord extents; + ExtendedVCB *vcb = HFSTOVCB(hfsmp); + int error; ByteCount utf8chars; - DBG_FUNC_NAME("hfs_MountHFSVolume"); - DBG_PRINT_FUNC_NAME(); + struct cat_desc cndesc; + struct cat_attr cnattr; + struct cat_fork fork; - if (hfsmp == nil || mdb == nil) /* exit if bad paramater */ + /* Block size must be a multiple of 512 */ + if (SWAP_BE32(mdb->drAlBlkSiz) == 0 || + (SWAP_BE32(mdb->drAlBlkSiz) & 0x01FF) != 0) return (EINVAL); - err = ValidMasterDirectoryBlock( mdb ); /* make sure this is an HFS disk */ - if (err) - return MacToVFSError(err); - /* don't mount a writeable volume if its dirty, it must be cleaned by fsck_hfs */ - if ((hfsmp->hfs_fs_ronly == 0) && ((SWAP_BE16 (mdb->drAtrb) & kHFSVolumeUnmountedMask) == 0)) + if ((hfsmp->hfs_fs_ronly == 0) && ((SWAP_BE16(mdb->drAtrb) & kHFSVolumeUnmountedMask) == 0)) return (EINVAL); /* @@ -207,104 +106,122 @@ OSErr hfs_MountHFSVolume(struct hfsmount *hfsmp, HFSMasterDirectoryBlock *mdb, * Note - the VCB starts out clear (all zeros) * */ - vcb->vcbVRefNum = MAKE_VREFNUM(hfsmp->hfs_raw_dev); - - vcb->vcbSigWord = SWAP_BE16 (mdb->drSigWord); - vcb->vcbCrDate = LocalToUTC (SWAP_BE32 (mdb->drCrDate)); + vcb->vcbSigWord = SWAP_BE16 (mdb->drSigWord); + vcb->vcbCrDate = to_bsd_time(LocalToUTC(SWAP_BE32(mdb->drCrDate))); vcb->localCreateDate = SWAP_BE32 (mdb->drCrDate); - vcb->vcbLsMod = LocalToUTC (SWAP_BE32 (mdb->drLsMod)); - vcb->vcbAtrb = SWAP_BE16 (mdb->drAtrb); - vcb->vcbNmFls = SWAP_BE16 (mdb->drNmFls); - vcb->vcbVBMSt = SWAP_BE16 (mdb->drVBMSt); - vcb->nextAllocation = SWAP_BE16 (mdb->drAllocPtr); - vcb->totalBlocks = SWAP_BE16 (mdb->drNmAlBlks); - vcb->blockSize = SWAP_BE32 (mdb->drAlBlkSiz); - vcb->vcbClpSiz = SWAP_BE32 (mdb->drClpSiz); - vcb->vcbAlBlSt = SWAP_BE16 (mdb->drAlBlSt); - vcb->vcbNxtCNID = SWAP_BE32 (mdb->drNxtCNID); - vcb->freeBlocks = SWAP_BE16 (mdb->drFreeBks); - vcb->vcbVolBkUp = LocalToUTC (SWAP_BE32 (mdb->drVolBkUp)); - vcb->vcbWrCnt = SWAP_BE32 (mdb->drWrCnt); - vcb->vcbNmRtDirs = SWAP_BE16 (mdb->drNmRtDirs); - vcb->vcbFilCnt = SWAP_BE32 (mdb->drFilCnt); - vcb->vcbDirCnt = SWAP_BE32 (mdb->drDirCnt); + vcb->vcbLsMod = to_bsd_time(LocalToUTC(SWAP_BE32(mdb->drLsMod))); + vcb->vcbAtrb = SWAP_BE16 (mdb->drAtrb); + vcb->vcbNmFls = SWAP_BE16 (mdb->drNmFls); + vcb->vcbVBMSt = SWAP_BE16 (mdb->drVBMSt); + vcb->nextAllocation = SWAP_BE16 (mdb->drAllocPtr); + vcb->totalBlocks = SWAP_BE16 (mdb->drNmAlBlks); + vcb->blockSize = SWAP_BE32 (mdb->drAlBlkSiz); + vcb->vcbClpSiz = SWAP_BE32 (mdb->drClpSiz); + vcb->vcbAlBlSt = SWAP_BE16 (mdb->drAlBlSt); + vcb->vcbNxtCNID = SWAP_BE32 (mdb->drNxtCNID); + vcb->freeBlocks = SWAP_BE16 (mdb->drFreeBks); + vcb->vcbVolBkUp = to_bsd_time(LocalToUTC(SWAP_BE32(mdb->drVolBkUp))); + vcb->vcbWrCnt = SWAP_BE32 (mdb->drWrCnt); + vcb->vcbNmRtDirs = SWAP_BE16 (mdb->drNmRtDirs); + vcb->vcbFilCnt = SWAP_BE32 (mdb->drFilCnt); + vcb->vcbDirCnt = SWAP_BE32 (mdb->drDirCnt); bcopy(mdb->drFndrInfo, vcb->vcbFndrInfo, sizeof(vcb->vcbFndrInfo)); - vcb->nextAllocation = SWAP_BE16 ( mdb->drAllocPtr); /* Duplicate?!?!?! */ - vcb->encodingsBitmap = 0; - vcb->vcbWrCnt++; /* Compensate for write of MDB on last flush */ - /* - * Copy the drVN field, which is a Pascal String to the vcb, which is a cstring - */ + if (!hfsmp->hfs_fs_ronly) + vcb->vcbWrCnt++; /* Compensate for write of MDB on last flush */ /* convert hfs encoded name into UTF-8 string */ - err = hfs_to_utf8(vcb, mdb->drVN, NAME_MAX, &utf8chars, vcb->vcbVN); + error = hfs_to_utf8(vcb, mdb->drVN, NAME_MAX, &utf8chars, vcb->vcbVN); /* * When an HFS name cannot be encoded with the current * volume encoding we use MacRoman as a fallback. */ - if (err || (utf8chars == 0)) + if (error || (utf8chars == 0)) (void) mac_roman_to_utf8(mdb->drVN, NAME_MAX, &utf8chars, vcb->vcbVN); - // Initialize our dirID/nodePtr cache associated with this volume. - err = InitMRUCache( sizeof(UInt32), kDefaultNumMRUCacheBlocks, &(vcb->hintCachePtr) ); - ReturnIfError( err ); - - hfsmp->hfs_logBlockSize = BestBlockSizeFit(vcb->blockSize, MAXBSIZE, hfsmp->hfs_phys_block_size); + hfsmp->hfs_logBlockSize = BestBlockSizeFit(vcb->blockSize, MAXBSIZE, hfsmp->hfs_phys_block_size); vcb->vcbVBMIOSize = kHFSBlockSize; - // XXX PPD: Should check here for hardware lock flag and set flags in VCB/MP appropriately VCB_LOCK_INIT(vcb); + bzero(&cndesc, sizeof(cndesc)); + cndesc.cd_parentcnid = kRootParID; + bzero(&cnattr, sizeof(cnattr)); + cnattr.ca_nlink = 1; + cnattr.ca_mode = S_IFREG; + bzero(&fork, sizeof(fork)); + /* - * Set up Extents B-tree vnode... - */ - err = GetInitializedVNode(hfsmp, &tmpvnode); - if (err) goto MtVolErr; - /* HFSToHFSPlusExtents(mdb->drXTExtRec, extents); */ /* ASDFADSFSD */ - extents[0].startBlock = SWAP_BE16 (mdb->drXTExtRec[0].startBlock); - extents[0].blockCount = SWAP_BE16 (mdb->drXTExtRec[0].blockCount); - extents[1].startBlock = SWAP_BE16 (mdb->drXTExtRec[1].startBlock); - extents[1].blockCount = SWAP_BE16 (mdb->drXTExtRec[1].blockCount); - extents[2].startBlock = SWAP_BE16 (mdb->drXTExtRec[2].startBlock); - extents[2].blockCount = SWAP_BE16 (mdb->drXTExtRec[2].blockCount); - - err = InitMetaFileVNode(tmpvnode, SWAP_BE32 (mdb->drXTFlSize), SWAP_BE32 (mdb->drXTClpSiz), extents, - kHFSExtentsFileID, CompareExtentKeys); - if (err) goto MtVolErr; + * Set up Extents B-tree vnode + */ + cndesc.cd_nameptr = hfs_extname; + cndesc.cd_namelen = strlen(hfs_extname); + cndesc.cd_cnid = cnattr.ca_fileid = kHFSExtentsFileID; + fork.cf_size = SWAP_BE32(mdb->drXTFlSize); + fork.cf_blocks = fork.cf_size / vcb->blockSize; + fork.cf_clump = SWAP_BE32(mdb->drXTClpSiz); + fork.cf_extents[0].startBlock = SWAP_BE16(mdb->drXTExtRec[0].startBlock); + fork.cf_extents[0].blockCount = SWAP_BE16(mdb->drXTExtRec[0].blockCount); + fork.cf_extents[1].startBlock = SWAP_BE16(mdb->drXTExtRec[1].startBlock); + fork.cf_extents[1].blockCount = SWAP_BE16(mdb->drXTExtRec[1].blockCount); + fork.cf_extents[2].startBlock = SWAP_BE16(mdb->drXTExtRec[2].startBlock); + fork.cf_extents[2].blockCount = SWAP_BE16(mdb->drXTExtRec[2].blockCount); + cnattr.ca_blocks = fork.cf_blocks; + + error = hfs_getnewvnode(hfsmp, NULL, &cndesc, 0, &cnattr, &fork, + &vcb->extentsRefNum); + if (error) goto MtVolErr; + error = MacToVFSError(BTOpenPath(VTOF(vcb->extentsRefNum), + (KeyCompareProcPtr)CompareExtentKeys, + GetBTreeBlock, ReleaseBTreeBlock, + ExtendBTreeFile, SetBTreeBlockSize)); + if (error) { + VOP_UNLOCK(vcb->extentsRefNum, 0, p); + goto MtVolErr; + } /* * Set up Catalog B-tree vnode... */ - err = GetInitializedVNode(hfsmp, &tmpvnode); - if (err) goto MtVolErr; - /* HFSToHFSPlusExtents(mdb->drCTExtRec, extents); */ - extents[0].startBlock = SWAP_BE16 (mdb->drCTExtRec[0].startBlock); - extents[0].blockCount = SWAP_BE16 (mdb->drCTExtRec[0].blockCount); - extents[1].startBlock = SWAP_BE16 (mdb->drCTExtRec[1].startBlock); - extents[1].blockCount = SWAP_BE16 (mdb->drCTExtRec[1].blockCount); - extents[2].startBlock = SWAP_BE16 (mdb->drCTExtRec[2].startBlock); - extents[2].blockCount = SWAP_BE16 (mdb->drCTExtRec[2].blockCount); - - err = InitMetaFileVNode(tmpvnode, SWAP_BE32 (mdb->drCTFlSize), SWAP_BE32 (mdb->drCTClpSiz), extents, - kHFSCatalogFileID, CompareCatalogKeys); - if (err) goto MtVolErr; + cndesc.cd_nameptr = hfs_catname; + cndesc.cd_namelen = strlen(hfs_catname); + cndesc.cd_cnid = cnattr.ca_fileid = kHFSCatalogFileID; + fork.cf_size = SWAP_BE32(mdb->drCTFlSize); + fork.cf_blocks = fork.cf_size / vcb->blockSize; + fork.cf_clump = SWAP_BE32(mdb->drCTClpSiz); + fork.cf_extents[0].startBlock = SWAP_BE16(mdb->drCTExtRec[0].startBlock); + fork.cf_extents[0].blockCount = SWAP_BE16(mdb->drCTExtRec[0].blockCount); + fork.cf_extents[1].startBlock = SWAP_BE16(mdb->drCTExtRec[1].startBlock); + fork.cf_extents[1].blockCount = SWAP_BE16(mdb->drCTExtRec[1].blockCount); + fork.cf_extents[2].startBlock = SWAP_BE16(mdb->drCTExtRec[2].startBlock); + fork.cf_extents[2].blockCount = SWAP_BE16(mdb->drCTExtRec[2].blockCount); + cnattr.ca_blocks = fork.cf_blocks; + + error = hfs_getnewvnode(hfsmp, NULL, &cndesc, 0, &cnattr, &fork, + &vcb->catalogRefNum); + if (error) { + VOP_UNLOCK(vcb->extentsRefNum, 0, p); + goto MtVolErr; + } + error = MacToVFSError(BTOpenPath(VTOF(vcb->catalogRefNum), + (KeyCompareProcPtr)CompareCatalogKeys, + GetBTreeBlock, ReleaseBTreeBlock, + ExtendBTreeFile, SetBTreeBlockSize)); + if (error) { + VOP_UNLOCK(vcb->catalogRefNum, 0, p); + VOP_UNLOCK(vcb->extentsRefNum, 0, p); + goto MtVolErr; + } /* mark the volume dirty (clear clean unmount bit) */ vcb->vcbAtrb &= ~kHFSVolumeUnmountedMask; - /* Remove any MetaDataDirectory from hfs disks */ - if (hfsmp->hfs_fs_ronly == 0) - RemovedMetaDataDirectory(vcb); - /* * all done with b-trees so we can unlock now... */ - VOP_UNLOCK(vcb->catalogRefNum, 0, p); - VOP_UNLOCK(vcb->extentsRefNum, 0, p); - - err = noErr; + VOP_UNLOCK(vcb->catalogRefNum, 0, p); + VOP_UNLOCK(vcb->extentsRefNum, 0, p); - if ( err == noErr ) + if ( error == noErr ) { if ( !(vcb->vcbAtrb & kHFSVolumeHardwareLockMask) ) // if the disk is not write protected { @@ -314,12 +231,12 @@ OSErr hfs_MountHFSVolume(struct hfsmount *hfsmp, HFSMasterDirectoryBlock *mdb, goto CmdDone; //-- Release any resources allocated so far before exiting with an error: -MtVolErr:; +MtVolErr: ReleaseMetaFileVNode(vcb->catalogRefNum); ReleaseMetaFileVNode(vcb->extentsRefNum); -CmdDone:; - return( err ); +CmdDone: + return (error); } //******************************************************************************* @@ -329,27 +246,25 @@ CmdDone:; //******************************************************************************* OSErr hfs_MountHFSPlusVolume(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp, - off_t embeddedOffset, off_t disksize, struct proc *p) + off_t embeddedOffset, u_int64_t disksize, struct proc *p) { - register ExtendedVCB *vcb; - HFSPlusForkData *fdp; - struct vnode *tmpvnode; - OSErr retval; - - if (hfsmp == nil || vhp == nil) /* exit if bad paramater */ - return (EINVAL); + register ExtendedVCB *vcb; + struct cat_desc cndesc; + struct cat_attr cnattr; + UInt32 blockSize; + OSErr retval; - DBG_VFS(("hfs_MountHFSPlusVolume: signature=0x%x, version=%d, blockSize=%ld\n", - SWAP_BE16 (vhp->signature), - SWAP_BE16 (vhp->version), - SWAP_BE32 (vhp->blockSize))); + if (SWAP_BE16(vhp->signature) != kHFSPlusSigWord || + SWAP_BE16(vhp->version) != kHFSPlusVersion) + return (EINVAL); - retval = ValidVolumeHeader(vhp); /* make sure this is an HFS Plus disk */ - if (retval) - return MacToVFSError(retval); + /* Block size must be at least 512 and a power of 2 */ + blockSize = SWAP_BE32(vhp->blockSize); + if (blockSize < 512 || (blockSize & (blockSize-1)) != 0) + return (EINVAL); /* don't mount a writable volume if its dirty, it must be cleaned by fsck_hfs */ - if (hfsmp->hfs_fs_ronly == 0 && (SWAP_BE32 (vhp->attributes) & kHFSVolumeUnmountedMask) == 0) + if (hfsmp->hfs_fs_ronly == 0 && (SWAP_BE32(vhp->attributes) & kHFSVolumeUnmountedMask) == 0) return (EINVAL); /* Make sure we can live with the physical block size. */ @@ -358,105 +273,147 @@ OSErr hfs_MountHFSPlusVolume(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp, (SWAP_BE32(vhp->blockSize) < hfsmp->hfs_phys_block_size)) { return (ENXIO); } - /* * The VolumeHeader seems OK: transfer info from it into VCB * Note - the VCB starts out clear (all zeros) */ vcb = HFSTOVCB(hfsmp); - //DBG_ASSERT((hfsmp->hfs_raw_dev & 0xFFFF0000) == 0); - vcb->vcbVRefNum = MAKE_VREFNUM(hfsmp->hfs_raw_dev); - vcb->vcbSigWord = SWAP_BE16 (vhp->signature); - vcb->vcbLsMod = SWAP_BE32 (vhp->modifyDate); - vcb->vcbAtrb = (UInt16) SWAP_BE32 (vhp->attributes); // VCB only uses lower 16 bits - vcb->vcbClpSiz = SWAP_BE32 (vhp->rsrcClumpSize); - vcb->vcbNxtCNID = SWAP_BE32 (vhp->nextCatalogID); - vcb->vcbVolBkUp = SWAP_BE32 (vhp->backupDate); - vcb->vcbWrCnt = SWAP_BE32 (vhp->writeCount); - vcb->vcbFilCnt = SWAP_BE32 (vhp->fileCount); - vcb->vcbDirCnt = SWAP_BE32 (vhp->folderCount); + vcb->vcbSigWord = SWAP_BE16(vhp->signature); + vcb->vcbLsMod = to_bsd_time(SWAP_BE32(vhp->modifyDate)); + vcb->vcbAtrb = (UInt16)SWAP_BE32(vhp->attributes); + vcb->vcbClpSiz = SWAP_BE32(vhp->rsrcClumpSize); + vcb->vcbNxtCNID = SWAP_BE32(vhp->nextCatalogID); + vcb->vcbVolBkUp = to_bsd_time(SWAP_BE32(vhp->backupDate)); + vcb->vcbWrCnt = SWAP_BE32(vhp->writeCount); + vcb->vcbFilCnt = SWAP_BE32(vhp->fileCount); + vcb->vcbDirCnt = SWAP_BE32(vhp->folderCount); /* copy 32 bytes of Finder info */ bcopy(vhp->finderInfo, vcb->vcbFndrInfo, sizeof(vhp->finderInfo)); vcb->vcbAlBlSt = 0; /* hfs+ allocation blocks start at first block of volume */ - vcb->vcbWrCnt++; /* compensate for write of Volume Header on last flush */ + if (!hfsmp->hfs_fs_ronly) + vcb->vcbWrCnt++; /* compensate for write of Volume Header on last flush */ VCB_LOCK_INIT(vcb); - /* Now fill in the Extended VCB info */ - vcb->nextAllocation = SWAP_BE32 (vhp->nextAllocation); - vcb->totalBlocks = SWAP_BE32 (vhp->totalBlocks); - vcb->freeBlocks = SWAP_BE32 (vhp->freeBlocks); - vcb->blockSize = SWAP_BE32 (vhp->blockSize); - vcb->checkedDate = SWAP_BE32 (vhp->checkedDate); - vcb->encodingsBitmap = SWAP_BE64 (vhp->encodingsBitmap); + /* Now fill in the Extended VCB info */ + vcb->nextAllocation = SWAP_BE32(vhp->nextAllocation); + vcb->totalBlocks = SWAP_BE32(vhp->totalBlocks); + vcb->freeBlocks = SWAP_BE32(vhp->freeBlocks); + vcb->blockSize = SWAP_BE32(vhp->blockSize); + vcb->encodingsBitmap = SWAP_BE64(vhp->encodingsBitmap); + vcb->localCreateDate = SWAP_BE32(vhp->createDate); - vcb->hfsPlusIOPosOffset = embeddedOffset; + vcb->hfsPlusIOPosOffset = embeddedOffset; - vcb->localCreateDate = SWAP_BE32 (vhp->createDate); /* in local time, not GMT! */ + /* Default to no free block reserve */ + vcb->reserveBlocks = 0; - /* Update the logical block size in the mount struct (currently set up from the wrapper MDB) - using the new blocksize value: */ - hfsmp->hfs_logBlockSize = BestBlockSizeFit(vcb->blockSize, MAXBSIZE, hfsmp->hfs_phys_block_size); + /* + * Update the logical block size in the mount struct + * (currently set up from the wrapper MDB) using the + * new blocksize value: + */ + hfsmp->hfs_logBlockSize = BestBlockSizeFit(vcb->blockSize, MAXBSIZE, hfsmp->hfs_phys_block_size); vcb->vcbVBMIOSize = min(vcb->blockSize, MAXPHYSIO); - // XXX PPD: Should check here for hardware lock flag and set flags in VCB/MP appropriately - // vcb->vcbAtrb |= kVolumeHardwareLockMask; // XXX this line for debugging only!!!! - - // Initialize our dirID/nodePtr cache associated with this volume. - retval = InitMRUCache( sizeof(UInt32), kDefaultNumMRUCacheBlocks, &(vcb->hintCachePtr) ); - if (retval != noErr) goto ErrorExit; + bzero(&cndesc, sizeof(cndesc)); + cndesc.cd_parentcnid = kRootParID; + bzero(&cnattr, sizeof(cnattr)); + cnattr.ca_nlink = 1; + cnattr.ca_mode = S_IFREG; /* - * Set up Extents B-tree vnode... - */ - retval = GetInitializedVNode(hfsmp, &tmpvnode); + * Set up Extents B-tree vnode + */ + cndesc.cd_nameptr = hfs_extname; + cndesc.cd_namelen = strlen(hfs_extname); + cndesc.cd_cnid = cnattr.ca_fileid = kHFSExtentsFileID; + + SWAP_HFS_PLUS_FORK_DATA (&vhp->extentsFile); + cnattr.ca_blocks = vhp->extentsFile.totalBlocks; + + retval = hfs_getnewvnode(hfsmp, NULL, &cndesc, 0, &cnattr, + (struct cat_fork *)&vhp->extentsFile, + &vcb->extentsRefNum); + SWAP_HFS_PLUS_FORK_DATA (&vhp->extentsFile); + if (retval) goto ErrorExit; - fdp = &vhp->extentsFile; - SWAP_HFS_PLUS_FORK_DATA (fdp); - retval = InitMetaFileVNode(tmpvnode, fdp->logicalSize, fdp->clumpSize, fdp->extents, - kHFSExtentsFileID, CompareExtentKeysPlus); - SWAP_HFS_PLUS_FORK_DATA (fdp); - if (retval) goto ErrorExit; + retval = MacToVFSError(BTOpenPath(VTOF(vcb->extentsRefNum), + (KeyCompareProcPtr) CompareExtentKeysPlus, + GetBTreeBlock, ReleaseBTreeBlock, + ExtendBTreeFile, SetBTreeBlockSize)); + if (retval) { + VOP_UNLOCK(vcb->extentsRefNum, 0, p); + goto ErrorExit; + } /* - * Set up Catalog B-tree vnode... + * Set up Catalog B-tree vnode */ - retval = GetInitializedVNode(hfsmp, &tmpvnode); - if (retval) goto ErrorExit; - fdp = &vhp->catalogFile; - SWAP_HFS_PLUS_FORK_DATA (fdp); - retval = InitMetaFileVNode(tmpvnode, fdp->logicalSize, fdp->clumpSize, fdp->extents, - kHFSCatalogFileID, CompareExtendedCatalogKeys); - SWAP_HFS_PLUS_FORK_DATA (fdp); - if (retval) goto ErrorExit; + cndesc.cd_nameptr = hfs_catname; + cndesc.cd_namelen = strlen(hfs_catname); + cndesc.cd_cnid = cnattr.ca_fileid = kHFSCatalogFileID; + + SWAP_HFS_PLUS_FORK_DATA(&vhp->catalogFile); + cnattr.ca_blocks = vhp->catalogFile.totalBlocks; + + retval = hfs_getnewvnode(hfsmp, NULL, &cndesc, 0, &cnattr, + (struct cat_fork *)&vhp->catalogFile, + &vcb->catalogRefNum); + SWAP_HFS_PLUS_FORK_DATA(&vhp->catalogFile); + if (retval) { + VOP_UNLOCK(vcb->extentsRefNum, 0, p); + goto ErrorExit; + } + retval = MacToVFSError(BTOpenPath(VTOF(vcb->catalogRefNum), + (KeyCompareProcPtr) CompareExtendedCatalogKeys, + GetBTreeBlock, ReleaseBTreeBlock, + ExtendBTreeFile, SetBTreeBlockSize)); + if (retval) { + VOP_UNLOCK(vcb->catalogRefNum, 0, p); + VOP_UNLOCK(vcb->extentsRefNum, 0, p); + goto ErrorExit; + } /* - * Set up Allocation file vnode... + * Set up Allocation file vnode */ - retval = GetInitializedVNode(hfsmp, &tmpvnode); - if (retval) goto ErrorExit; - fdp = &vhp->allocationFile; - SWAP_HFS_PLUS_FORK_DATA (fdp); - retval = InitMetaFileVNode(tmpvnode, fdp->logicalSize, fdp->clumpSize, fdp->extents, - kHFSAllocationFileID, NULL); - SWAP_HFS_PLUS_FORK_DATA (fdp); - if (retval) goto ErrorExit; - - /* - * Now that Catalog file is open get the volume name from the catalog - */ - retval = MacToVFSError( GetVolumeNameFromCatalog(vcb) ); - if (retval != noErr) goto ErrorExit; + cndesc.cd_nameptr = hfs_vbmname; + cndesc.cd_namelen = strlen(hfs_vbmname); + cndesc.cd_cnid = cnattr.ca_fileid = kHFSAllocationFileID; + + SWAP_HFS_PLUS_FORK_DATA(&vhp->allocationFile); + cnattr.ca_blocks = vhp->allocationFile.totalBlocks; + + retval = hfs_getnewvnode(hfsmp, NULL, &cndesc, 0, &cnattr, + (struct cat_fork *)&vhp->allocationFile, + &vcb->allocationsRefNum); + SWAP_HFS_PLUS_FORK_DATA(&vhp->allocationFile); + if (retval) { + VOP_UNLOCK(vcb->catalogRefNum, 0, p); + VOP_UNLOCK(vcb->extentsRefNum, 0, p); + goto ErrorExit; + } + + /* Pick up volume name and create date */ + retval = cat_idlookup(hfsmp, kHFSRootFolderID, &cndesc, &cnattr, NULL); + if (retval) { + VOP_UNLOCK(vcb->allocationsRefNum, 0, p); + VOP_UNLOCK(vcb->catalogRefNum, 0, p); + VOP_UNLOCK(vcb->extentsRefNum, 0, p); + goto ErrorExit; + } + vcb->vcbCrDate = cnattr.ca_itime; + vcb->volumeNameEncodingHint = cndesc.cd_encoding; + bcopy(cndesc.cd_nameptr, vcb->vcbVN, min(255, cndesc.cd_namelen)); + cat_releasedesc(&cndesc); /* mark the volume dirty (clear clean unmount bit) */ vcb->vcbAtrb &= ~kHFSVolumeUnmountedMask; - /* setup private/hidden directory for unlinked files */ - hfsmp->hfs_private_metadata_dir = FindMetaDataDirectory(vcb); - /* * all done with metadata files so we can unlock now... */ @@ -464,26 +421,23 @@ OSErr hfs_MountHFSPlusVolume(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp, VOP_UNLOCK(vcb->catalogRefNum, 0, p); VOP_UNLOCK(vcb->extentsRefNum, 0, p); - if ( !(vcb->vcbAtrb & kHFSVolumeHardwareLockMask) ) // if the disk is not write protected + /* setup private/hidden directory for unlinked files */ + hfsmp->hfs_private_metadata_dir = FindMetaDataDirectory(vcb); + + if ( !(vcb->vcbAtrb & kHFSVolumeHardwareLockMask) ) // if the disk is not write protected { - MarkVCBDirty( vcb ); // mark VCB dirty so it will be written + MarkVCBDirty( vcb ); // mark VCB dirty so it will be written } - - DBG_VFS(("hfs_MountHFSPlusVolume: returning (%d)\n", retval)); return (0); - ErrorExit: /* * A fatal error occured and the volume cannot be mounted * release any resources that we aquired... */ - DBG_VFS(("hfs_MountHFSPlusVolume: fatal error (%d)\n", retval)); - - InvalidateCatalogCache(vcb); - + InvalidateCatalogCache(vcb); ReleaseMetaFileVNode(vcb->allocationsRefNum); ReleaseMetaFileVNode(vcb->catalogRefNum); ReleaseMetaFileVNode(vcb->extentsRefNum); @@ -499,90 +453,16 @@ ErrorExit: */ static void ReleaseMetaFileVNode(struct vnode *vp) { - if (vp) - { - FCB *fcb = VTOFCB(vp); + struct filefork *fp; - if (fcb->fcbBTCBPtr != NULL) - (void) BTClosePath(fcb); /* ignore errors since there is only one path open */ + if (vp && (fp = VTOF(vp))) { + if (fp->fcbBTCBPtr != NULL) + (void) BTClosePath(fp); /* release the node even if BTClosePath fails */ - if (VOP_ISLOCKED(vp)) - vput(vp); - else - vrele(vp); - } -} - - -/* - * InitMetaFileVNode - * - * vp U L L - */ -static int InitMetaFileVNode(struct vnode *vp, off_t eof, u_long clumpSize, const HFSPlusExtentRecord extents, - HFSCatalogNodeID fileID, void * keyCompareProc) -{ - FCB *fcb; - ExtendedVCB *vcb; - int result = 0; - - DBG_ASSERT(vp != NULL); - DBG_ASSERT(vp->v_data != NULL); - - vcb = VTOVCB(vp); - fcb = VTOFCB(vp); - - switch (fileID) - { - case kHFSExtentsFileID: - vcb->extentsRefNum = vp; - break; - - case kHFSCatalogFileID: - vcb->catalogRefNum = vp; - break; - - case kHFSAllocationFileID: - vcb->allocationsRefNum = vp; - break; - - default: - panic("InitMetaFileVNode: invalid fileID!"); + vrele(vp); + vgone(vp); } - - fcb->fcbEOF = eof; - fcb->fcbPLen = eof; - fcb->fcbClmpSize = clumpSize; - H_FILEID(VTOH(vp)) = fileID; - H_DIRID(VTOH(vp)) = kHFSRootParentID; - H_FORKTYPE(VTOH(vp)) = kSysFile; - - bcopy(extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); - - /* - * Lock the hfsnode and insert the hfsnode into the hash queue: - */ - hfs_vhashins(H_DEV(VTOH(vp)), fileID, VTOH(vp)); - vp->v_flag |= VSYSTEM; /* tag our metadata files (used by vflush call) */ - - /* As the vnode is a system vnode we don't need UBC */ - if(UBCINFOEXISTS(vp)) { - /* So something is wrong if the it exists */ - panic("ubc exists for system vnode"); - } - - if (keyCompareProc != NULL) { - result = BTOpenPath(fcb, - (KeyCompareProcPtr) keyCompareProc, - GetBTreeBlock, - ReleaseBTreeBlock, - ExtendBTreeFile, - SetBTreeBlockSize); - result = MacToVFSError(result); - } - - return (result); } @@ -595,15 +475,10 @@ static int InitMetaFileVNode(struct vnode *vp, off_t eof, u_long clumpSize, cons short hfsUnmount( register struct hfsmount *hfsmp, struct proc *p) { - ExtendedVCB *vcb = HFSTOVCB(hfsmp); - int retval = E_NONE; + ExtendedVCB *vcb = HFSTOVCB(hfsmp); + int retval = E_NONE; - (void) DisposeMRUCache(vcb->hintCachePtr); InvalidateCatalogCache( vcb ); - // XXX PPD: Should dispose of any allocated volume cache here: call DisposeVolumeCacheBlocks( vcb )? - - (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p); - (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE, p); if (vcb->vcbSigWord == kHFSPlusSigWord) ReleaseMetaFileVNode(vcb->allocationsRefNum); @@ -616,2632 +491,321 @@ short hfsUnmount( register struct hfsmount *hfsmp, struct proc *p) /* - * hfs_resolvelink - auto resolve HFS+ hardlinks - * - * Used after calling GetCatalogNode or GetCatalogOffspring + * Some 3rd party kexts link against hfs_getcatalog so keep a stub for now. */ -void hfs_resolvelink(ExtendedVCB *vcb, CatalogNodeData *cndp) +short +hfs_getcatalog(void *p1, u_long p2, void *p3, short p4, void *p5) { - struct FInfo *fip; - char iNodeName[32]; - UInt32 hint; - UInt32 indlinkno; - UInt32 linkparid, linkcnid; - OSErr result; - - fip = (struct FInfo *) &cndp->cnd_finderInfo; - - /* - * if this is an indirect link (hardlink) then auto resolve it... - */ - if ((vcb->vcbSigWord == kHFSPlusSigWord) - && (cndp->cnd_type == kCatalogFileNode) - && (fip->fdType == kHardLinkFileType) - && (fip->fdCreator == kHFSPlusCreator) - && ((cndp->cnd_createDate == vcb->vcbCrDate) || - (cndp->cnd_createDate == VCBTOHFS(vcb)->hfs_metadata_createdate))) { - - indlinkno = cndp->cnd_iNodeNum; - MAKE_INODE_NAME(iNodeName, indlinkno); - /* - * Get nodeData from the data node file. - * Flag the node data to NOT copy the name (ie preserve the original) - * Also preserve the parent directory ID. - */ - linkparid = cndp->cnm_parID; - linkcnid = cndp->cnd_nodeID; - cndp->cnm_flags |= kCatNameNoCopyName; - result = GetCatalogNode(vcb, VCBTOHFS(vcb)->hfs_private_metadata_dir, - iNodeName, 0, 0, cndp, &hint); - cndp->cnm_flags &= ~kCatNameNoCopyName; - - /* Make sure there's a reference */ - if (result == 0) { - if (cndp->cnd_linkCount == 0) cndp->cnd_linkCount = 2; - - /* Keep a copy of iNodeNum to put into h_indnodeno */ - cndp->cnd_iNodeNumCopy = indlinkno; - cndp->cnm_parID = linkparid; - cndp->cnd_linkCNID = linkcnid; - } - } + return ENOENT; } -/* - * Performs a lookup on the given dirID, name. Returns the catalog info - * - * If len is -1, then it is a null terminated string, pass it along to MacOS as kUndefinedStrLen - */ - -short hfs_getcatalog (ExtendedVCB *vcb, UInt32 parentDirID, char *name, short len, hfsCatalogInfo *catInfo) +int overflow_extents(struct filefork *fp) { - OSErr result; - UInt32 length; - - if (len == -1 ) { /* Convert it to MacOS terms */ - if (name) - length = strlen(name); - else - length = kUndefinedStrLen; - } - else - length = len; - - result = GetCatalogNode(vcb, parentDirID, name, length, catInfo->hint, &catInfo->nodeData, &catInfo->hint); - -#if HFS_DIAGNOSTICS - if (catInfo->nodeData.cnm_nameptr) { - DBG_ASSERT(strlen(catInfo->nodeData.cnm_nameptr) == catInfo->nodeData.cnm_length); - } -#endif + u_long blocks; - if (result == 0) - hfs_resolvelink(vcb, &catInfo->nodeData); + if (VTOVCB(FTOV(fp))->vcbSigWord == kHFSPlusSigWord) { + if (fp->ff_extents[7].blockCount == 0) + return (0); - return MacToVFSError(result); -} + blocks = fp->ff_extents[0].blockCount + + fp->ff_extents[1].blockCount + + fp->ff_extents[2].blockCount + + fp->ff_extents[3].blockCount + + fp->ff_extents[4].blockCount + + fp->ff_extents[5].blockCount + + fp->ff_extents[6].blockCount + + fp->ff_extents[7].blockCount; + } else { + if (fp->ff_extents[2].blockCount == 0) + return false; + + blocks = fp->ff_extents[0].blockCount + + fp->ff_extents[1].blockCount + + fp->ff_extents[2].blockCount; + } + return (fp->ff_blocks > blocks); +} -short hfsDelete (ExtendedVCB *vcb, UInt32 parentDirID, StringPtr name, short isfile, UInt32 catalogHint) +/* __private_extern__ */ +int +hfs_metafilelocking(struct hfsmount *hfsmp, u_long fileID, u_int flags, struct proc *p) { - OSErr result = noErr; - - /* XXX have all the file's blocks been flushed/trashed? */ + ExtendedVCB *vcb; + struct vnode *vp = NULL; + int numOfLockedBuffs; + int retval = 0; - /* - * DeleteFile will delete the catalog node and then - * free up any disk space used by the file. - */ - if (isfile) - result = DeleteFile(vcb, parentDirID, name, catalogHint); - else /* is a directory */ - result = DeleteCatalogNode(vcb, parentDirID, name, catalogHint); + vcb = HFSTOVCB(hfsmp); + + switch (fileID) { + case kHFSExtentsFileID: + vp = vcb->extentsRefNum; + break; + + case kHFSCatalogFileID: + vp = vcb->catalogRefNum; + break; + + case kHFSAllocationFileID: + /* bitmap is covered by Extents B-tree locking */ + /* FALL THROUGH */ + default: + panic("hfs_lockmetafile: invalid fileID"); + } - if (result) - DBG_ERR(("on Delete, DeleteFile returned: %d: dirid: %ld name: %s\n", result, parentDirID, name)); + /* Release, if necesary any locked buffer caches */ + if ((flags & LK_TYPE_MASK) == LK_RELEASE) { + struct timeval tv = time; + u_int32_t lastfsync = tv.tv_sec; - return MacToVFSError(result); -} + (void) BTGetLastSync((FCB*)VTOF(vp), &lastfsync); + + numOfLockedBuffs = count_lock_queue(); + if ((numOfLockedBuffs > kMaxLockedMetaBuffers) || ((numOfLockedBuffs>1) && ((tv.tv_sec - lastfsync) > kMaxSecsForFsync))) { + hfs_btsync(vp, HFS_SYNCTRANS); + } + } else { + flags |= LK_RETRY; + } + + retval = lockmgr(&VTOC(vp)->c_lock, flags, &vp->v_interlock, p); + return (retval); +} -short hfsMoveRename (ExtendedVCB *vcb, UInt32 oldDirID, char *oldName, UInt32 newDirID, char *newName, UInt32 *hint) +/* + * RequireFileLock + * + * Check to see if a vnode is locked in the current context + * This is to be used for debugging purposes only!! + */ +#if HFS_DIAGNOSTIC +void RequireFileLock(FileReference vp, int shareable) { - OSErr result = noErr; + struct lock__bsd__ *lkp; + int locked = false; + pid_t pid; + void * self; - result = MoveRenameCatalogNode(vcb, oldDirID,oldName, *hint, newDirID, newName, hint, 0); + pid = current_proc()->p_pid; + self = (void *) current_thread(); + lkp = &VTOC(vp)->c_lock; - if (result) - DBG_ERR(("on hfsMoveRename, MoveRenameCatalogNode returned: %d: newdirid: %ld newname: %s\n", result, newDirID, newName)); - - - return MacToVFSError(result); -} + simple_lock(&lkp->lk_interlock); + + if (shareable && (lkp->lk_sharecount > 0) && (lkp->lk_lockholder == LK_NOPROC)) + locked = true; + else if ((lkp->lk_exclusivecount > 0) && (lkp->lk_lockholder == pid) && (lkp->lk_lockthread == self)) + locked = true; -/* XXX SER pass back the hint so other people can use it */ + simple_unlock(&lkp->lk_interlock); + + if (!locked) { + switch (VTOC(vp)->c_fileid) { + case 3: + DEBUG_BREAK_MSG((" #\n # RequireFileLock: extent btree vnode not locked! v: 0x%08X\n #\n", (u_int)vp)); + break; + case 4: + DEBUG_BREAK_MSG((" #\n # RequireFileLock: catalog btree vnode not locked! v: 0x%08X\n #\n", (u_int)vp)); + break; -short hfsCreate(ExtendedVCB *vcb, UInt32 dirID, char *name, int mode, UInt32 tehint) -{ - OSErr result = noErr; - HFSCatalogNodeID catalogNodeID; - UInt32 catalogHint; - UInt32 type; - - /* just test for directories, the default is to create a file (like symlinks) */ - if ((mode & IFMT) == IFDIR) - type = kCatalogFolderNode; - else - type = kCatalogFileNode; - - result = CreateCatalogNode (vcb, dirID, name, type, &catalogNodeID, &catalogHint, tehint); - - return MacToVFSError(result); + default: + DEBUG_BREAK_MSG((" #\n # RequireFileLock: file (%d) not locked! v: 0x%08X\n #\n", VTOC(vp)->c_fileid, (u_int)vp)); + break; + } + } } +#endif -short hfsCreateFileID (ExtendedVCB *vcb, UInt32 parentDirID, StringPtr name, UInt32 catalogHint, UInt32 *fileIDPtr) -{ - return MacToVFSError(CreateFileIDRef(vcb, parentDirID, name, catalogHint, fileIDPtr)); +/* + * There are three ways to qualify for ownership rights on an object: + * + * 1. (a) Your UID matches the cnode's UID. + * (b) The object in question is owned by "unknown" and + * your UID matches the console user's UID. + * 2. (a) Permissions on the filesystem are being ignored and + * your UID matches the replacement UID. + * (b) Permissions on the filesystem are being ignored and + * the replacement UID is "unknown" and + * your UID matches the console user UID. + * 3. You are root. + * + */ +int +hfs_owner_rights(struct hfsmount *hfsmp, uid_t cnode_uid, struct ucred *cred, + struct proc *p, int invokesuperuserstatus) +{ + if ((cred->cr_uid == cnode_uid) || /* [1a] */ + ((cnode_uid == UNKNOWNUID) && (cred->cr_uid == console_user)) || /* [1b] */ + ((HFSTOVFS(hfsmp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) && /* [2] */ + ((cred->cr_uid == hfsmp->hfs_uid) || /* [2a] */ + ((hfsmp->hfs_uid == UNKNOWNUID) && /* [2b] */ + (cred->cr_uid == console_user)))) || + (invokesuperuserstatus && (suser(cred, &p->p_acflag) == 0))) { /* [3] */ + return (0); + } else { + return (EPERM); + } } -/********************************************************************************/ -/* */ -/* hfs_vget_catinfo - Returns a vnode derived from a hfs catInfo struct */ -/* */ -/********************************************************************************/ +unsigned long BestBlockSizeFit(unsigned long allocationBlockSize, + unsigned long blockSizeLimit, + unsigned long baseMultiple) { + /* + Compute the optimal (largest) block size (no larger than allocationBlockSize) that is less than the + specified limit but still an even multiple of the baseMultiple. + */ + int baseBlockCount, blockCount; + unsigned long trialBlockSize; -int hfs_vget_catinfo(struct vnode *parent_vp, struct hfsCatalogInfo *catInfo, u_int32_t forkType, struct vnode **target_vp) -{ - int retval = E_NONE; - - if (forkType == kDefault) { - if (catInfo->nodeData.cnd_type == kCatalogFolderNode) - forkType = kDirectory; - else - forkType = kDataFork; - } - - *target_vp = hfs_vhashget(H_DEV(VTOH(parent_vp)), catInfo->nodeData.cnd_nodeID, forkType); + if (allocationBlockSize % baseMultiple != 0) { + /* + Whoops: the allocation blocks aren't even multiples of the specified base: + no amount of dividing them into even parts will be a multiple, either then! + */ + return 512; /* Hope for the best */ + }; - if (*target_vp == NULL) - retval = hfs_vcreate( VTOVCB(parent_vp), catInfo, forkType, target_vp); + /* Try the obvious winner first, to prevent 12K allocation blocks, for instance, + from being handled as two 6K logical blocks instead of 3 4K logical blocks. + Even though the former (the result of the loop below) is the larger allocation + block size, the latter is more efficient: */ + if (allocationBlockSize % PAGE_SIZE == 0) return PAGE_SIZE; - return (retval); -} + /* No clear winner exists: pick the largest even fraction <= MAXBSIZE: */ + baseBlockCount = allocationBlockSize / baseMultiple; /* Now guaranteed to be an even multiple */ + for (blockCount = baseBlockCount; blockCount > 0; --blockCount) { + trialBlockSize = blockCount * baseMultiple; + if (allocationBlockSize % trialBlockSize == 0) { /* An even multiple? */ + if ((trialBlockSize <= blockSizeLimit) && + (trialBlockSize % baseMultiple == 0)) { + return trialBlockSize; + }; + }; + }; + /* Note: we should never get here, since blockCount = 1 should always work, + but this is nice and safe and makes the compiler happy, too ... */ + return 512; +} -/************************************************************************/ -/* hfs_vcreate - Returns a vnode derived from hfs */ -/* */ -/* When creating the vnode, care must be made to set the */ -/* correct fields in the correct order. Calls to malloc() */ -/* and other subroutines, can cause a context switch, */ -/* and the fields must be ready for the possibility */ -/* */ -/* */ -/************************************************************************/ -short hfs_vcreate(ExtendedVCB *vcb, hfsCatalogInfo *catInfo, UInt8 forkType, struct vnode **vpp) +/* + * To make the HFS Plus filesystem follow UFS unlink semantics, a remove + * of an active vnode is translated to a move/rename so the file appears + * deleted. The destination folder for these move/renames is setup here + * and a reference to it is place in hfsmp->hfs_private_metadata_dir. + */ +u_long +FindMetaDataDirectory(ExtendedVCB *vcb) { - struct hfsnode *hp; - struct vnode *vp; - struct hfsmount *hfsmp; - struct hfsfilemeta *fm; - struct mount *mp; - struct vfsFCB *xfcb; - dev_t dev; - short retval; - - hfsmp = VCBTOHFS(vcb); - mp = HFSTOVFS(hfsmp); - dev = hfsmp->hfs_raw_dev; - - /* Check if unmount in progress */ - if (mp->mnt_kern_flag & MNTK_UNMOUNT) { - *vpp = NULL; - return (EPERM); - } - - /* - * If this is a hard link then check if the - * data node already exists in our hash. - */ - if ((forkType == kDataFork) - && (catInfo->nodeData.cnd_type == kCatalogFileNode) - && ((catInfo->nodeData.cnd_mode & IFMT) == IFREG) - && (catInfo->nodeData.cnd_linkCount > 0)) { - vp = hfs_vhashget(dev, catInfo->nodeData.cnd_nodeID, kDataFork); - if (vp != NULL) { - /* Use the name of the link and it's parent ID. */ - hp = VTOH(vp); - H_DIRID(hp) = catInfo->nodeData.cnm_parID; - hfs_set_metaname(catInfo->nodeData.cnm_nameptr, hp->h_meta, hfsmp); - *vpp = vp; - return (0); - } - } - - MALLOC_ZONE(hp, struct hfsnode *, sizeof(struct hfsnode), M_HFSNODE, M_WAITOK); - bzero((caddr_t)hp, sizeof(struct hfsnode)); - hp->h_nodeflags |= IN_ALLOCATING; - lockinit(&hp->h_lock, PINOD, "hfsnode", 0, 0); - H_FORKTYPE(hp) = forkType; - rl_init(&hp->h_invalidranges); - - /* - * There were several blocking points since we first - * checked the hash. Now that we're through blocking, - * check the hash again in case we're racing for the - * same hnode. - */ - vp = hfs_vhashget(dev, catInfo->nodeData.cnd_nodeID, forkType); - if (vp != NULL) { - /* We lost the race, use the winner's vnode */ - FREE_ZONE(hp, sizeof(struct hfsnode), M_HFSNODE); - *vpp = vp; - UBCINFOCHECK("hfs_vcreate", vp); + struct hfsmount * hfsmp; + struct vnode * dvp = NULL; + struct cnode * dcp = NULL; + struct FndrDirInfo * fndrinfo; + struct cat_desc out_desc = {0}; + struct timeval tv; + int error; + + if (vcb->vcbSigWord != kHFSPlusSigWord) return (0); - } - /* - * Insert the hfsnode into the hash queue, also if meta exists - * add to sibling list and return the meta address - */ - fm = NULL; - if (SIBLING_FORKTYPE(forkType)) - hfs_vhashins_sibling(dev, catInfo->nodeData.cnd_nodeID, hp, &fm); - else - hfs_vhashins(dev, catInfo->nodeData.cnd_nodeID, hp); - - /* Allocate a new vnode. If unsuccesful, leave after freeing memory */ - if ((retval = getnewvnode(VT_HFS, mp, hfs_vnodeop_p, &vp))) { - hfs_vhashrem(hp); - if (hp->h_nodeflags & IN_WANT) { - hp->h_nodeflags &= ~IN_WANT; - wakeup(hp); - } - FREE_ZONE(hp, sizeof(struct hfsnode), M_HFSNODE); - *vpp = NULL; - return (retval); - } - hp->h_vp = vp; - vp->v_data = hp; + hfsmp = VCBTOHFS(vcb); - hp->h_nodeflags &= ~IN_ALLOCATING; - if (hp->h_nodeflags & IN_WANT) { - hp->h_nodeflags &= ~IN_WANT; - wakeup((caddr_t)hp); + if (hfsmp->hfs_privdir_desc.cd_parentcnid == 0) { + hfsmp->hfs_privdir_desc.cd_parentcnid = kRootDirID; + hfsmp->hfs_privdir_desc.cd_nameptr = hfs_privdirname; + hfsmp->hfs_privdir_desc.cd_namelen = strlen(hfs_privdirname); + hfsmp->hfs_privdir_desc.cd_flags = CD_ISDIR; } - /* - * If needed allocate and init the object meta data: - */ - if (fm == NULL) { - /* Allocate it....remember we can do a context switch here */ - MALLOC_ZONE(fm, struct hfsfilemeta *, sizeof(struct hfsfilemeta), M_HFSFMETA, M_WAITOK); - bzero(fm, sizeof(struct hfsfilemeta)); - - /* Fill it in */ - /* - * NOTICE: XXX Even though we have added the vnode to the hash so it is alive on TWO - * accessable lists, we do not assign it until later, - * this helps to make sure we do not use a half initiated meta - */ - - /* Init the sibling list if needed */ - if (SIBLING_FORKTYPE(forkType)) { - simple_lock_init(&fm->h_siblinglock); - CIRCLEQ_INIT(&fm->h_siblinghead); - CIRCLEQ_INSERT_HEAD(&fm->h_siblinghead, hp, h_sibling); - }; - - fm->h_dev = dev; - CopyCatalogToObjectMeta(catInfo, vp, fm); - - /* - * the vnode is finally alive, with the exception of the FCB below, - * It is finally locked and ready for its debutante ball - */ - hp->h_meta = fm; - }; - fm->h_usecount++; - - /* - * Init the File Control Block. - */ - CopyCatalogToFCB(catInfo, vp); + /* Lock catalog b-tree */ + error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, current_proc()); + if (error) + return (0); - /* - * Finish vnode initialization. - * Setting the v_type 'stamps' the vnode as 'complete', so should be done almost last. - * - * At this point the vnode should be locked and fully allocated. And ready to be used - * or accessed. (though having it locked prevents most of this, it - * can still be accessed through lists and hashs). - */ - vp->v_type = IFTOVT(hp->h_meta->h_mode); - if ((vp->v_type == VREG) - && (UBCINFOMISSING(vp) || UBCINFORECLAIMED(vp))) { - ubc_info_init(vp); + error = cat_lookup(hfsmp, &hfsmp->hfs_privdir_desc, 0, NULL, + &hfsmp->hfs_privdir_attr, NULL); + + if (error == 0) { + /* Unlock catalog b-tree */ + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, current_proc()); + hfsmp->hfs_metadata_createdate = hfsmp->hfs_privdir_attr.ca_itime; + return (hfsmp->hfs_privdir_attr.ca_fileid); + } else if (hfsmp->hfs_fs_ronly) { + /* Unlock catalog b-tree */ + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, current_proc()); + return (0); } + + /* Setup the default attributes */ + bzero(&hfsmp->hfs_privdir_attr, sizeof(struct cat_attr)); + hfsmp->hfs_privdir_attr.ca_mode = S_IFDIR; + hfsmp->hfs_privdir_attr.ca_flags = SF_IMMUTABLE; + hfsmp->hfs_privdir_attr.ca_nlink = 2; + hfsmp->hfs_privdir_attr.ca_itime = vcb->vcbCrDate; + hfsmp->hfs_privdir_attr.ca_mtime = time.tv_sec; + + /* hidden and off the desktop view */ + fndrinfo = (struct FndrDirInfo *)&hfsmp->hfs_privdir_attr.ca_finderinfo; + fndrinfo->frLocation.v = SWAP_BE16 (22460); + fndrinfo->frLocation.h = SWAP_BE16 (22460); + fndrinfo->frFlags |= SWAP_BE16 (kIsInvisible + kNameLocked); + + error = cat_create(hfsmp, &hfsmp->hfs_privdir_desc, + &hfsmp->hfs_privdir_attr, &out_desc); + + /* Unlock catalog b-tree */ + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, current_proc()); + if (error) + return (0); - /* - * Initialize the vnode from the inode, check for aliases, sets the VROOT flag. - * Note that the underlying vnode may have changed. - */ - if ((retval = hfs_vinit(mp, hfs_specop_p, hfs_fifoop_p, &vp))) { - vput(vp); - *vpp = NULL; - return (retval); + hfsmp->hfs_privdir_desc.cd_hint = out_desc.cd_hint; + hfsmp->hfs_privdir_desc.cd_cnid = out_desc.cd_cnid; + hfsmp->hfs_privdir_attr.ca_fileid = out_desc.cd_cnid; + hfsmp->hfs_metadata_createdate = vcb->vcbCrDate; + + if (VFS_ROOT(HFSTOVFS(hfsmp), &dvp) == 0) { + dcp = VTOC(dvp); + dcp->c_childhint = out_desc.cd_hint; + dcp->c_nlink++; + dcp->c_entries++; + dcp->c_flag |= C_CHANGE | C_UPDATE; + tv = time; + (void) VOP_UPDATE(dvp, &tv, &tv, 0); + vput(dvp); } + hfs_volupdate(hfsmp, VOL_MKDIR, 1); + cat_releasedesc(&out_desc); - /* - * Finish inode initialization now that aliasing has been resolved. - */ - hp->h_meta->h_devvp = hfsmp->hfs_devvp; - VREF(hp->h_meta->h_devvp); - - *vpp = vp; - return 0; + return (out_desc.cd_cnid); } -void CopyCatalogToObjectMeta(struct hfsCatalogInfo *catalogInfo, struct vnode *vp, struct hfsfilemeta *fm) + +/* + * This will return the correct logical block size for a given vnode. + * For most files, it is the allocation block size, for meta data like + * BTrees, this is kept as part of the BTree private nodeSize + */ +u_int32_t +GetLogicalBlockSize(struct vnode *vp) { - ExtendedVCB *vcb = VTOVCB(vp); - struct mount *mp = VTOVFS(vp); - Boolean isHFSPlus, isDirectory; - ushort finderFlags; - ushort filetype; - - DBG_ASSERT (fm != NULL); - DBG_ASSERT (fm->h_namelen == 0); - DBG_ASSERT (fm->h_namePtr == 0); +u_int32_t logBlockSize; - DBG_UTILS(("\tCopying to file's meta data: name:%s, nodeid:%ld\n", catalogInfo->nodeData.cnm_nameptr, catalogInfo->nodeData.cnd_nodeID)); + DBG_ASSERT(vp != NULL); - isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord); - isDirectory = (catalogInfo->nodeData.cnd_type == kCatalogFolderNode); - finderFlags = SWAP_BE16 (((struct FInfo *)(&catalogInfo->nodeData.cnd_finderInfo))->fdFlags); - - /* Copy over the dirid, and hint */ - fm->h_nodeID = catalogInfo->nodeData.cnd_nodeID; - fm->h_dirID = catalogInfo->nodeData.cnm_parID; - fm->h_hint = catalogInfo->hint; - - /* Copy over the name */ - hfs_name_CatToMeta(&catalogInfo->nodeData, fm); - - - /* get dates in BSD format */ - fm->h_mtime = to_bsd_time(catalogInfo->nodeData.cnd_contentModDate); - fm->h_crtime = to_bsd_time(catalogInfo->nodeData.cnd_createDate); - fm->h_butime = to_bsd_time(catalogInfo->nodeData.cnd_backupDate); - if (isHFSPlus) { - fm->h_atime = to_bsd_time(catalogInfo->nodeData.cnd_accessDate); - fm->h_ctime = to_bsd_time(catalogInfo->nodeData.cnd_attributeModDate); - } - else { - fm->h_atime = to_bsd_time(catalogInfo->nodeData.cnd_contentModDate); - fm->h_ctime = to_bsd_time(catalogInfo->nodeData.cnd_contentModDate); - } - - /* Now the rest */ - if (isHFSPlus && (catalogInfo->nodeData.cnd_mode & IFMT)) { - fm->h_uid = catalogInfo->nodeData.cnd_ownerID; - fm->h_gid = catalogInfo->nodeData.cnd_groupID; - fm->h_pflags = catalogInfo->nodeData.cnd_ownerFlags | - (catalogInfo->nodeData.cnd_adminFlags << 16); - fm->h_mode = (mode_t)catalogInfo->nodeData.cnd_mode; -#if 1 - if (fm->h_uid == 0xFFFFFFFD) { /* 0xfffffffd = 4294967293, the old "unknown" */ - fm->h_uid = UNKNOWNUID; - fm->h_metaflags |= IN_CHANGE; - vcb->vcbFlags |= kHFS_DamagedVolume; /* Trigger fsck on next mount */ - }; - if (fm->h_gid == 0xFFFFFFFD) { /* 0xfffffffd = 4294967293, the old "unknown" */ - fm->h_gid = UNKNOWNGID; - fm->h_metaflags |= IN_CHANGE; - vcb->vcbFlags |= kHFS_DamagedVolume; /* Trigger fsck on next mount */ - }; -#endif - filetype = fm->h_mode & IFMT; - if (filetype == IFCHR || filetype == IFBLK) - fm->h_rdev = catalogInfo->nodeData.cnd_rawDevice; - else { - fm->h_rdev = 0; -#if HFS_HARDLINKS - if (catalogInfo->nodeData.cnd_type == kCatalogFileNode && - catalogInfo->nodeData.cnd_linkCount > 0) { - fm->h_nlink = catalogInfo->nodeData.cnd_linkCount; - fm->h_indnodeno = catalogInfo->nodeData.cnd_iNodeNumCopy; - fm->h_metaflags |= IN_DATANODE; - } -#endif - } - - if (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) { - /* - * Override the permissions as determined by the mount auguments - * in ALMOST the same way unset permissions are treated but keep - * track of whether or not the file or folder is hfs locked - * by leaving the h_pflags field unchanged from what was unpacked - * out of the catalog. - */ - fm->h_metaflags |= IN_UNSETACCESS; - fm->h_uid = VTOHFS(vp)->hfs_uid; - fm->h_gid = VTOHFS(vp)->hfs_gid; -#if OVERRIDE_UNKNOWN_PERMISSIONS - /* Default access is full read/write/execute: */ - /* XXX won't this smash IFCHR, IFBLK and IFLNK (for no-follow lookups)? */ - fm->h_mode = ACCESSPERMS; /* 0777: rwxrwxrwx */ - fm->h_rdev = 0; - - /* ... but no more than that permitted by the mount point's: */ - if (isDirectory) { - fm->h_mode &= VTOHFS(vp)->hfs_dir_mask; - } - else { - fm->h_mode &= VTOHFS(vp)->hfs_file_mask; - } - - if(isDirectory) - fm->h_mode |= IFDIR; - else if (SUPPORTS_MAC_ALIASES && (finderFlags & kIsAlias)) /* aliases will be symlinks in the future */ - fm->h_mode |= IFLNK; - else - fm->h_mode |= IFREG; -#endif - }; - } else { - /* - * Set the permissions as determined by the mount auguments - * but keep in account if the file or folder is hfs locked - */ - fm->h_metaflags |= IN_UNSETACCESS; - fm->h_uid = VTOHFS(vp)->hfs_uid; - fm->h_gid = VTOHFS(vp)->hfs_gid; - fm->h_pflags = 0; /* No valid pflags on disk (IMMUTABLE is synced from lock flag later) */ - fm->h_rdev = 0; /* No valid rdev on disk */ - /* Default access is full read/write/execute: */ - fm->h_mode = ACCESSPERMS; /* 0777: rwxrwxrwx */ - - /* ... but no more than that permitted by the mount point's: */ - if (isDirectory) { - fm->h_mode &= VTOHFS(vp)->hfs_dir_mask; - } - else { - fm->h_mode &= VTOHFS(vp)->hfs_file_mask; - } - - if(isDirectory) - fm->h_mode |= IFDIR; - else if (SUPPORTS_MAC_ALIASES && (finderFlags & kIsAlias)) /* aliases will be symlinks in the future */ - fm->h_mode |= IFLNK; - else - fm->h_mode |= IFREG; - }; - - /* Make sure that there is no nodeType/mode mismatch */ - if (isDirectory && ((fm->h_mode & IFMT) != IFDIR)) { - fm->h_mode &= ~IFMT; /* Clear the bad bits */ - fm->h_mode |= IFDIR; /* Set the proper one */ - }; - - /* Make sure the IMMUTABLE bits are in sync with the locked flag in the catalog: */ - if (!isDirectory) { - if (catalogInfo->nodeData.cnd_flags & kHFSFileLockedMask) { - /* The file's supposed to be locked: - Make sure at least one of the IMMUTABLE bits is set: */ - if ((fm->h_pflags & (SF_IMMUTABLE | UF_IMMUTABLE)) == 0) { - fm->h_pflags |= UF_IMMUTABLE; /* Set the user-changable IMMUTABLE bit */ - }; - } else { - /* The file's supposed to be unlocked: */ - fm->h_pflags &= ~(SF_IMMUTABLE | UF_IMMUTABLE); - }; - }; - - if (isDirectory) { - fm->h_nlink = 2 + catalogInfo->nodeData.cnd_valence; - fm->h_size = (2 * sizeof(hfsdotentry)) + - (catalogInfo->nodeData.cnd_valence * AVERAGE_HFSDIRENTRY_SIZE); - if (fm->h_size < MAX_HFSDIRENTRY_SIZE) - fm->h_size = MAX_HFSDIRENTRY_SIZE; - } else { - fm->h_size = (off_t)vcb->blockSize * - (off_t)(catalogInfo->nodeData.cnd_rsrcfork.totalBlocks + - catalogInfo->nodeData.cnd_datafork.totalBlocks); - } -} - - -void CopyCatalogToFCB(struct hfsCatalogInfo *catalogInfo, struct vnode *vp) -{ - FCB *fcb = VTOFCB(vp); - ExtendedVCB *vcb = VTOVCB(vp); - Boolean isHFSPlus, isDirectory, isResource; - HFSPlusExtentDescriptor *extents; - UInt8 forkType; - - DBG_ASSERT (vp != NULL); - DBG_ASSERT (fcb != NULL); - DBG_ASSERT (vcb != NULL); - DBG_ASSERT (VTOH(vp) != NULL); - - forkType = H_FORKTYPE(VTOH(vp)); - isResource = (forkType == kRsrcFork); - isDirectory = (catalogInfo->nodeData.cnd_type == kCatalogFolderNode); - isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord); - - /* Init the fcb */ - fcb->fcbFlags = catalogInfo->nodeData.cnd_flags; - - if (forkType != kDirectory) { - fcb->fcbFlags &= kHFSFileLockedMask; /* Clear resource, dirty bits */ - if (fcb->fcbFlags != 0) /* if clear, its not locked, then.. */ - fcb->fcbFlags = fcbFileLockedMask; /* duplicate the bit for later use */ - - fcb->fcbClmpSize = vcb->vcbClpSiz; /*XXX why not use the one in catalogInfo? */ - - if (isResource) - extents = catalogInfo->nodeData.cnd_rsrcfork.extents; - else - extents = catalogInfo->nodeData.cnd_datafork.extents; - - /* Copy the extents to their correct location: */ - bcopy (extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); - - if (isResource) { - fcb->fcbEOF = catalogInfo->nodeData.cnd_rsrcfork.logicalSize; - fcb->fcbPLen = (off_t)((off_t)catalogInfo->nodeData.cnd_rsrcfork.totalBlocks * (off_t)vcb->blockSize); - fcb->fcbFlags |= fcbResourceMask; - } else { - fcb->fcbEOF = catalogInfo->nodeData.cnd_datafork.logicalSize; - fcb->fcbPLen = (off_t)((off_t)catalogInfo->nodeData.cnd_datafork.totalBlocks * (off_t)vcb->blockSize); - }; - }; - - -} - -int hasOverflowExtents(struct hfsnode *hp) -{ - ExtendedVCB *vcb = HTOVCB(hp); - FCB *fcb = HTOFCB(hp); - u_long blocks; - - if (vcb->vcbSigWord == kHFSPlusSigWord) - { - - if (fcb->fcbExtents[7].blockCount == 0) - return false; - - blocks = fcb->fcbExtents[0].blockCount + - fcb->fcbExtents[1].blockCount + - fcb->fcbExtents[2].blockCount + - fcb->fcbExtents[3].blockCount + - fcb->fcbExtents[4].blockCount + - fcb->fcbExtents[5].blockCount + - fcb->fcbExtents[6].blockCount + - fcb->fcbExtents[7].blockCount; - } - else - { - if (fcb->fcbExtents[2].blockCount == 0) - return false; - - blocks = fcb->fcbExtents[0].blockCount + - fcb->fcbExtents[1].blockCount + - fcb->fcbExtents[2].blockCount; - } - - return ((fcb->fcbPLen / vcb->blockSize) > blocks); -} - - -int hfs_metafilelocking(struct hfsmount *hfsmp, u_long fileID, u_int flags, struct proc *p) -{ - ExtendedVCB *vcb; - struct vnode *vp = NULL; - int numOfLockedBuffs; - int retval = 0; - - vcb = HFSTOVCB(hfsmp); - - DBG_UTILS(("hfs_metafilelocking: vol: %d, file: %d %s%s%s\n", vcb->vcbVRefNum, fileID, - ((flags & LK_TYPE_MASK) == LK_RELEASE ? "RELEASE" : ""), - ((flags & LK_TYPE_MASK) == LK_EXCLUSIVE ? "EXCLUSIVE" : ""), - ((flags & LK_TYPE_MASK) == LK_SHARED ? "SHARED" : "") )); - - - switch (fileID) - { - case kHFSExtentsFileID: - vp = vcb->extentsRefNum; - break; - - case kHFSCatalogFileID: - vp = vcb->catalogRefNum; - break; - - case kHFSAllocationFileID: - /* bitmap is covered by Extents B-tree locking */ - /* FALL THROUGH */ - default: - panic("hfs_lockmetafile: invalid fileID"); - } - - if (vp != NULL) { - - /* Release, if necesary any locked buffer caches */ - if ((flags & LK_TYPE_MASK) == LK_RELEASE) { - struct timeval tv = time; - u_int32_t lastfsync = tv.tv_sec; - - (void) BTGetLastSync(VTOFCB(vp), &lastfsync); - - numOfLockedBuffs = count_lock_queue(); - if ((numOfLockedBuffs > kMaxLockedMetaBuffers) || ((numOfLockedBuffs>1) && ((tv.tv_sec - lastfsync) > kMaxSecsForFsync))) { - DBG_UTILS(("Synching meta deta: %d... # locked buffers = %d, fsync gap = %ld\n", H_FILEID(VTOH(vp)), - numOfLockedBuffs, (tv.tv_sec - lastfsync))); - hfs_fsync_transaction(vp); - }; - }; - - retval = lockmgr(&VTOH(vp)->h_lock, flags, &vp->v_interlock, p); - }; - - return retval; -} - - -/* - * There are three ways to qualify for ownership rights on an object: - * - * 1. (a) Your UID matches the UID of the vnode - * (b) The object in question is owned by "unknown" and your UID matches the console user's UID - * 2. (a) Permissions on the filesystem are being ignored and your UID matches the replacement UID - * (b) Permissions on the filesystem are being ignored and the replacement UID is "unknown" and - * your UID matches the console user UID - * 3. You are root - * - */ -int hfs_owner_rights(struct vnode *vp, struct ucred *cred, struct proc *p, Boolean invokesuperuserstatus) { - return ((cred->cr_uid == VTOH(vp)->h_meta->h_uid) || /* [1a] */ - ((VTOH(vp)->h_meta->h_uid == UNKNOWNUID) && (cred->cr_uid == console_user)) || /* [1b] */ - ((VTOVFS(vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) && /* [2] */ - ((cred->cr_uid == VTOHFS(vp)->hfs_uid) || /* [2a] */ - ((VTOHFS(vp)->hfs_uid == UNKNOWNUID) && (cred->cr_uid == console_user)))) || /* [2b] */ - (invokesuperuserstatus && (suser(cred, &p->p_acflag) == 0))) ? 0 : EPERM; -} - - - -int hfs_catalogentry_owner_rights(uid_t obj_uid, struct mount *mp, struct ucred *cred, struct proc *p, Boolean invokesuperuserstatus) { - return ((cred->cr_uid == obj_uid) || /* [1a] */ - ((obj_uid == UNKNOWNUID) && (cred->cr_uid == console_user)) || /* [1b] */ - ((mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) && /* [2] */ - ((cred->cr_uid == VFSTOHFS(mp)->hfs_uid) || /* [2a] */ - ((VFSTOHFS(mp)->hfs_uid == UNKNOWNUID) && (cred->cr_uid == console_user)))) || /* [2b] */ - (invokesuperuserstatus && (suser(cred, &p->p_acflag) == 0))) ? 0 : EPERM; -} - - - -void CopyVNodeToCatalogNode (struct vnode *vp, struct CatalogNodeData *nodeData) -{ - ExtendedVCB *vcb; - FCB *fcb; - struct hfsnode *hp; - Boolean isHFSPlus, isResource; - HFSPlusExtentDescriptor *extents; - off_t fileReadLimit; - - hp = VTOH(vp); - vcb = HTOVCB(hp); - fcb = HTOFCB(hp); - isResource = (H_FORKTYPE(hp) == kRsrcFork); - isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord); - - /* date and time of last fork modification */ - if (hp->h_meta->h_mtime != 0) - nodeData->cnd_contentModDate = to_hfs_time(hp->h_meta->h_mtime); - - if (isHFSPlus) { - /* Make sure that there is no nodeType/mode mismatch */ - if ((nodeData->cnd_type == kCatalogFolderNode) - && ((hp->h_meta->h_mode & IFMT) != IFDIR)) { - - DBG_ASSERT((hp->h_meta->h_mode & IFMT) == IFDIR); - hp->h_meta->h_mode &= ~IFMT; /* Clear the bad bits */ - hp->h_meta->h_mode |= IFDIR; /* Set the proper one */ - }; - /* date and time of last modification (any kind) */ - if (hp->h_meta->h_ctime != 0) - nodeData->cnd_attributeModDate = to_hfs_time(hp->h_meta->h_ctime); - /* date and time of last access (MacOS X only) */ - if (hp->h_meta->h_atime != 0) - nodeData->cnd_accessDate = to_hfs_time(hp->h_meta->h_atime); - /* hfs_setattr can change the create date */ - if (hp->h_meta->h_crtime != 0) - nodeData->cnd_createDate = to_hfs_time(hp->h_meta->h_crtime); - if (! (hp->h_meta->h_metaflags & IN_UNSETACCESS)) { - nodeData->cnd_adminFlags = hp->h_meta->h_pflags >> 16; - nodeData->cnd_ownerFlags = hp->h_meta->h_pflags & 0x000000FF; - nodeData->cnd_mode = hp->h_meta->h_mode; - nodeData->cnd_ownerID = hp->h_meta->h_uid; - nodeData->cnd_groupID = hp->h_meta->h_gid; - } - }; - - /* the rest only applies to files */ - if (nodeData->cnd_type == kCatalogFileNode) { - if (hp->h_meta->h_pflags & (SF_IMMUTABLE | UF_IMMUTABLE)) { - /* The file is locked: set the locked bit in the catalog. */ - nodeData->cnd_flags |= kHFSFileLockedMask; - } else { - /* The file is unlocked: make sure the locked bit in the catalog is clear. */ - nodeData->cnd_flags &= ~kHFSFileLockedMask; - }; - if (CIRCLEQ_EMPTY(&hp->h_invalidranges)) { - fileReadLimit = fcb->fcbEOF; - } else { - fileReadLimit = CIRCLEQ_FIRST(&hp->h_invalidranges)->rl_start; - }; - if (isResource) { - extents = nodeData->cnd_rsrcfork.extents; - nodeData->cnd_rsrcfork.logicalSize = fileReadLimit; - nodeData->cnd_rsrcfork.totalBlocks = fcb->fcbPLen / vcb->blockSize; - } else { - extents = nodeData->cnd_datafork.extents; - nodeData->cnd_datafork.logicalSize = fileReadLimit; - nodeData->cnd_datafork.totalBlocks = fcb->fcbPLen / vcb->blockSize; - }; - - bcopy ( fcb->fcbExtents, extents, sizeof(HFSPlusExtentRecord)); - - if ((vp->v_type == VBLK) || (vp->v_type == VCHR)) - nodeData->cnd_rawDevice = hp->h_meta->h_rdev; - else if (hp->h_meta->h_metaflags & IN_DATANODE) - nodeData->cnd_linkCount = hp->h_meta->h_nlink; - - if (vp->v_type == VLNK) { - ((struct FInfo *)(&nodeData->cnd_finderInfo))->fdType = SWAP_BE32 (kSymLinkFileType); - ((struct FInfo *)(&nodeData->cnd_finderInfo))->fdCreator = SWAP_BE32 (kSymLinkCreator); - - /* Set this up as an alias */ - #if SUPPORTS_MAC_ALIASES - ((struct FInfo *)(&nodeData->cnd_finderInfo))->fdFlags |= SWAP_BE16 (kIsAlias); - #endif - } - } - } - - -/********************************************************************* - - Sets the name in the filemeta structure - - XXX Does not preflight if changing from one size to another - XXX Currently not protected from context switching - -*********************************************************************/ - -void hfs_set_metaname(char *name, struct hfsfilemeta *fm, struct hfsmount *hfsmp) -{ -int namelen = strlen(name); -char *tname, *fname; - -#if HFS_DIAGNOSTIC - DBG_ASSERT(name != NULL); - DBG_ASSERT(fm != NULL); - if (fm->h_namePtr) { - DBG_ASSERT(fm->h_namelen == strlen(fm->h_namePtr)); - if (strlen(fm->h_namePtr) > MAXHFSVNODELEN) - DBG_ASSERT(fm->h_metaflags & IN_LONGNAME); - }; - if (fm->h_metaflags & IN_LONGNAME) { - DBG_ASSERT(fm->h_namePtr != (char *)fm->h_fileName); - DBG_ASSERT(fm->h_namePtr != NULL); - }; -#endif //HFS_DIAGNOSTIC - - /* - * Details that have to be dealt with: - * 1. No name is allocated. fm->h_namePtr should be NULL - * 2. A name is being changed and: - * a. it was in static space and now cannot fit - * b. It was malloc'd and now will fit in the static - * c. It did and will fit in the static - * This could be a little smarter: - * - Dont re'malloc if the new name is smaller (but then wasting memory) - * - If its a longname but the same size, we still free and malloc - * - - */ - - - /* Allocate the new memory */ - if (namelen > MAXHFSVNODELEN) { - /* - * Notice the we ALWAYS allocate, even if the new is less then the old, - * or even if they are the SAME - */ - MALLOC(tname, char *, namelen+1, M_TEMP, M_WAITOK); - } - else - tname = fm->h_fileName; - - simple_lock(&hfsmp->hfs_renamelock); - - /* Check to see if there is something to free, if yes, remember it */ - if (fm->h_metaflags & IN_LONGNAME) - fname = fm->h_namePtr; - else - fname = NULL; - - /* Set the flag */ - if (namelen > MAXHFSVNODELEN) { - fm->h_metaflags |= IN_LONGNAME; - } - else { - fm->h_metaflags &= ~IN_LONGNAME; - }; - - /* Now copy it over */ - bcopy(name, tname, namelen+1); - - fm->h_namePtr = tname; - fm->h_namelen = namelen; - - simple_unlock(&hfsmp->hfs_renamelock); - - /* Lastly, free the old, if set */ - if (fname != NULL) - FREE(fname, M_TEMP); - -} - -void hfs_name_CatToMeta(CatalogNodeData *nodeData, struct hfsfilemeta *fm) -{ -char *fname; - -#if HFS_DIAGNOSTIC - DBG_ASSERT(nodeData != NULL); - DBG_ASSERT(fm != NULL); - if (fm->h_namePtr) { - DBG_ASSERT(fm->h_namelen == strlen(fm->h_namePtr)); - if (strlen(fm->h_namePtr) > MAXHFSVNODELEN) - DBG_ASSERT(fm->h_metaflags & IN_LONGNAME); - }; - if (fm->h_metaflags & IN_LONGNAME) { - DBG_ASSERT(fm->h_namePtr != (char *)fm->h_fileName); - DBG_ASSERT(fm->h_namePtr != NULL); - }; - - DBG_ASSERT(nodeData->cnm_nameptr != NULL); - - if (nodeData->cnm_length) { - DBG_ASSERT(strlen(nodeData->cnm_nameptr) == nodeData->cnm_length); - } - - if (nodeData->cnm_length > MAXHFSVNODELEN) - { DBG_ASSERT(nodeData->cnm_nameptr != nodeData->cnm_namespace); } - else if (nodeData->cnm_nameptr) - { DBG_ASSERT(nodeData->cnm_nameptr == nodeData->cnm_namespace); } - -#endif //HFS_DIAGNOSTIC - - - /* Check to see if there is something to free, if yes, remember it */ - if (fm->h_metaflags & IN_LONGNAME) - fname = fm->h_namePtr; - else - fname = NULL; - - /* Set the flag */ - if (nodeData->cnm_length > MAXHFSVNODELEN) { - fm->h_metaflags |= IN_LONGNAME; - } else { - fm->h_metaflags &= ~IN_LONGNAME; - }; - - /* Copy over the name */ - if (nodeData->cnm_nameptr == nodeData->cnm_namespace) { - bcopy(nodeData->cnm_namespace, fm->h_fileName, nodeData->cnm_length+1); - fm->h_namePtr = fm->h_fileName; - } - else { - fm->h_namePtr = nodeData->cnm_nameptr; - } - - fm->h_namelen = nodeData->cnm_length; - - nodeData->cnm_flags |= kCatNameIsConsumed; - nodeData->cnm_flags &= ~kCatNameIsAllocated; - nodeData->cnm_length = 0; - nodeData->cnm_nameptr = (char *)0; - nodeData->cnm_namespace[0] = 0; - - /* Lastly, free the old, if set */ - if (fname != NULL) - FREE(fname, M_TEMP); -} - - - -unsigned long DerivePermissionSummary(uid_t obj_uid, gid_t obj_gid, mode_t obj_mode, struct mount *mp, struct ucred *cred, struct proc *p) { - register gid_t *gp; - unsigned long permissions; - int i; - - /* User id 0 (root) always gets access. */ - if (cred->cr_uid == 0) { - permissions = R_OK | W_OK | X_OK; - goto Exit; - }; - - /* Otherwise, check the owner. */ - if (hfs_catalogentry_owner_rights(obj_uid, mp, cred, p, false) == 0) { - permissions = ((unsigned long)obj_mode & S_IRWXU) >> 6; - goto Exit; - } - - /* Otherwise, check the groups. */ - if (! (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS)) { - for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++) { - if (obj_gid == *gp) { - permissions = ((unsigned long)obj_mode & S_IRWXG) >> 3; - goto Exit; - } - }; - }; - - /* Otherwise, settle for 'others' access. */ - permissions = (unsigned long)obj_mode & S_IRWXO; - -Exit: - return permissions; -} - - - -int AttributeBlockSize(struct attrlist *attrlist) { - int size; - attrgroup_t a; - -#if ((ATTR_CMN_NAME | ATTR_CMN_DEVID | ATTR_CMN_FSID | ATTR_CMN_OBJTYPE | \ - ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | ATTR_CMN_OBJPERMANENTID | ATTR_CMN_PAROBJID | \ - ATTR_CMN_SCRIPT | ATTR_CMN_CRTIME | ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | \ - ATTR_CMN_ACCTIME | ATTR_CMN_BKUPTIME | ATTR_CMN_FNDRINFO | ATTR_CMN_OWNERID | \ - ATTR_CMN_GRPID | ATTR_CMN_ACCESSMASK | ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST| \ - ATTR_CMN_FLAGS | ATTR_CMN_USERACCESS) != ATTR_CMN_VALIDMASK) -#error AttributeBlockSize: Missing bits in common mask computation! -#endif - DBG_ASSERT((attrlist->commonattr & ~ATTR_CMN_VALIDMASK) == 0); - -#if ((ATTR_VOL_FSTYPE | ATTR_VOL_SIGNATURE | ATTR_VOL_SIZE | ATTR_VOL_SPACEFREE | \ - ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | ATTR_VOL_ALLOCATIONCLUMP | ATTR_VOL_IOBLOCKSIZE | \ - ATTR_VOL_OBJCOUNT | ATTR_VOL_FILECOUNT | ATTR_VOL_DIRCOUNT | ATTR_VOL_MAXOBJCOUNT | \ - ATTR_VOL_MOUNTPOINT | ATTR_VOL_NAME | ATTR_VOL_MOUNTFLAGS | ATTR_VOL_INFO | \ - ATTR_VOL_MOUNTEDDEVICE| ATTR_VOL_ENCODINGSUSED | ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES) != ATTR_VOL_VALIDMASK) -#error AttributeBlockSize: Missing bits in volume mask computation! -#endif - DBG_ASSERT((attrlist->volattr & ~ATTR_VOL_VALIDMASK) == 0); - -#if ((ATTR_DIR_LINKCOUNT | ATTR_DIR_ENTRYCOUNT | ATTR_DIR_MOUNTSTATUS) != ATTR_DIR_VALIDMASK) -#error AttributeBlockSize: Missing bits in directory mask computation! -#endif - DBG_ASSERT((attrlist->dirattr & ~ATTR_DIR_VALIDMASK) == 0); -#if ((ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | ATTR_FILE_ALLOCSIZE | ATTR_FILE_IOBLOCKSIZE | \ - ATTR_FILE_CLUMPSIZE | ATTR_FILE_DEVTYPE | ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | \ - ATTR_FILE_FORKLIST | ATTR_FILE_DATALENGTH | ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_DATAEXTENTS | \ - ATTR_FILE_RSRCLENGTH | ATTR_FILE_RSRCALLOCSIZE | ATTR_FILE_RSRCEXTENTS) != ATTR_FILE_VALIDMASK) -#error AttributeBlockSize: Missing bits in file mask computation! -#endif - DBG_ASSERT((attrlist->fileattr & ~ATTR_FILE_VALIDMASK) == 0); - -#if ((ATTR_FORK_TOTALSIZE | ATTR_FORK_ALLOCSIZE) != ATTR_FORK_VALIDMASK) -#error AttributeBlockSize: Missing bits in fork mask computation! -#endif - DBG_ASSERT((attrlist->forkattr & ~ATTR_FORK_VALIDMASK) == 0); - - size = 0; - - if ((a = attrlist->commonattr) != 0) { - if (a & ATTR_CMN_NAME) size += sizeof(struct attrreference); - if (a & ATTR_CMN_DEVID) size += sizeof(dev_t); - if (a & ATTR_CMN_FSID) size += sizeof(fsid_t); - if (a & ATTR_CMN_OBJTYPE) size += sizeof(fsobj_type_t); - if (a & ATTR_CMN_OBJTAG) size += sizeof(fsobj_tag_t); - if (a & ATTR_CMN_OBJID) size += sizeof(fsobj_id_t); - if (a & ATTR_CMN_OBJPERMANENTID) size += sizeof(fsobj_id_t); - if (a & ATTR_CMN_PAROBJID) size += sizeof(fsobj_id_t); - if (a & ATTR_CMN_SCRIPT) size += sizeof(text_encoding_t); - if (a & ATTR_CMN_CRTIME) size += sizeof(struct timespec); - if (a & ATTR_CMN_MODTIME) size += sizeof(struct timespec); - if (a & ATTR_CMN_CHGTIME) size += sizeof(struct timespec); - if (a & ATTR_CMN_ACCTIME) size += sizeof(struct timespec); - if (a & ATTR_CMN_BKUPTIME) size += sizeof(struct timespec); - if (a & ATTR_CMN_FNDRINFO) size += 32 * sizeof(UInt8); - if (a & ATTR_CMN_OWNERID) size += sizeof(uid_t); - if (a & ATTR_CMN_GRPID) size += sizeof(gid_t); - if (a & ATTR_CMN_ACCESSMASK) size += sizeof(u_long); - if (a & ATTR_CMN_NAMEDATTRCOUNT) size += sizeof(u_long); - if (a & ATTR_CMN_NAMEDATTRLIST) size += sizeof(struct attrreference); - if (a & ATTR_CMN_FLAGS) size += sizeof(u_long); - if (a & ATTR_CMN_USERACCESS) size += sizeof(u_long); - }; - if ((a = attrlist->volattr) != 0) { - if (a & ATTR_VOL_FSTYPE) size += sizeof(u_long); - if (a & ATTR_VOL_SIGNATURE) size += sizeof(u_long); - if (a & ATTR_VOL_SIZE) size += sizeof(off_t); - if (a & ATTR_VOL_SPACEFREE) size += sizeof(off_t); - if (a & ATTR_VOL_SPACEAVAIL) size += sizeof(off_t); - if (a & ATTR_VOL_MINALLOCATION) size += sizeof(off_t); - if (a & ATTR_VOL_ALLOCATIONCLUMP) size += sizeof(off_t); - if (a & ATTR_VOL_IOBLOCKSIZE) size += sizeof(u_long); - if (a & ATTR_VOL_OBJCOUNT) size += sizeof(u_long); - if (a & ATTR_VOL_FILECOUNT) size += sizeof(u_long); - if (a & ATTR_VOL_DIRCOUNT) size += sizeof(u_long); - if (a & ATTR_VOL_MAXOBJCOUNT) size += sizeof(u_long); - if (a & ATTR_VOL_MOUNTPOINT) size += sizeof(struct attrreference); - if (a & ATTR_VOL_NAME) size += sizeof(struct attrreference); - if (a & ATTR_VOL_MOUNTFLAGS) size += sizeof(u_long); - if (a & ATTR_VOL_MOUNTEDDEVICE) size += sizeof(struct attrreference); - if (a & ATTR_VOL_ENCODINGSUSED) size += sizeof(unsigned long long); - if (a & ATTR_VOL_CAPABILITIES) size += sizeof(vol_capabilities_attr_t); - if (a & ATTR_VOL_ATTRIBUTES) size += sizeof(vol_attributes_attr_t); - }; - if ((a = attrlist->dirattr) != 0) { - if (a & ATTR_DIR_LINKCOUNT) size += sizeof(u_long); - if (a & ATTR_DIR_ENTRYCOUNT) size += sizeof(u_long); - if (a & ATTR_DIR_MOUNTSTATUS) size += sizeof(u_long); - }; - if ((a = attrlist->fileattr) != 0) { - if (a & ATTR_FILE_LINKCOUNT) size += sizeof(u_long); - if (a & ATTR_FILE_TOTALSIZE) size += sizeof(off_t); - if (a & ATTR_FILE_ALLOCSIZE) size += sizeof(off_t); - if (a & ATTR_FILE_IOBLOCKSIZE) size += sizeof(size_t); - if (a & ATTR_FILE_CLUMPSIZE) size += sizeof(off_t); - if (a & ATTR_FILE_DEVTYPE) size += sizeof(u_long); - if (a & ATTR_FILE_FILETYPE) size += sizeof(u_long); - if (a & ATTR_FILE_FORKCOUNT) size += sizeof(u_long); - if (a & ATTR_FILE_FORKLIST) size += sizeof(struct attrreference); - if (a & ATTR_FILE_DATALENGTH) size += sizeof(off_t); - if (a & ATTR_FILE_DATAALLOCSIZE) size += sizeof(off_t); - if (a & ATTR_FILE_DATAEXTENTS) size += sizeof(extentrecord); - if (a & ATTR_FILE_RSRCLENGTH) size += sizeof(off_t); - if (a & ATTR_FILE_RSRCALLOCSIZE) size += sizeof(off_t); - if (a & ATTR_FILE_RSRCEXTENTS) size += sizeof(extentrecord); - }; - if ((a = attrlist->forkattr) != 0) { - if (a & ATTR_FORK_TOTALSIZE) size += sizeof(off_t); - if (a & ATTR_FORK_ALLOCSIZE) size += sizeof(off_t); - }; - - return size; -} - - - -char* FindMountpointName(struct mount *mp) { - size_t namelength = strlen(mp->mnt_stat.f_mntonname); - int foundchars = 0; - char *c; - - if (namelength == 0) return NULL; - - /* Look backwards through the name string, looking for the first slash - encountered (which must precede the last part of the pathname) - */ - for (c = mp->mnt_stat.f_mntonname + namelength - 1; namelength > 0; --c, --namelength) { - if (*c != '/') { - foundchars = 1; - } else if (foundchars) { - return (c + 1); - }; - }; - - return mp->mnt_stat.f_mntonname; -} - - - -void PackObjectName(struct vnode *vp, - char *name, - size_t namelen, - void **attrbufptrptr, - void **varbufptrptr) { - char *mpname; - size_t mpnamelen; - u_long attrlength; - - /* The name of an object may be incorrect for the root of a mounted filesystem - because it may be mounted on a different directory name than the name of the - volume (such as "blah-1". For the root directory, it's best to return the - last element of the location where the volume's mounted: - */ - if ((vp->v_flag & VROOT) && (mpname = FindMountpointName(vp->v_mount))) { - mpnamelen = strlen(mpname); - - /* Trim off any trailing slashes: */ - while ((mpnamelen > 0) && (mpname[mpnamelen-1] == '/')) { - --mpnamelen; - }; - - /* If there's anything left, use it instead of the volume's name */ - if (mpnamelen > 0) { - name = mpname; - namelen = mpnamelen; - }; - }; - - attrlength = namelen + 1; - ((struct attrreference *)(*attrbufptrptr))->attr_dataoffset = (char *)(*varbufptrptr) - (char *)(*attrbufptrptr); - ((struct attrreference *)(*attrbufptrptr))->attr_length = attrlength; - (void) strncpy((unsigned char *)(*varbufptrptr), name, attrlength); - - /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */ - (char *)(*varbufptrptr) += attrlength + ((4 - (attrlength & 3)) & 3); - ++((struct attrreference *)(*attrbufptrptr)); -} - - - -void PackVolCommonAttributes(struct attrlist *alist, - struct vnode *root_vp, - struct hfsCatalogInfo *root_catInfo, - void **attrbufptrptr, - void **varbufptrptr) { - void *attrbufptr; - void *varbufptr; - attrgroup_t a; - struct hfsnode *root_hp = VTOH(root_vp); - struct mount *mp = VTOVFS(root_vp); - struct hfsmount *hfsmp = VTOHFS(root_vp); - ExtendedVCB *vcb = HFSTOVCB(hfsmp); - u_long attrlength; - - attrbufptr = *attrbufptrptr; - varbufptr = *varbufptrptr; - - if ((a = alist->commonattr) != 0) { - if (a & ATTR_CMN_NAME) { - PackObjectName(root_vp, H_NAME(root_hp), root_hp->h_meta->h_namelen, &attrbufptr, &varbufptr); - }; - if (a & ATTR_CMN_DEVID) *((dev_t *)attrbufptr)++ = hfsmp->hfs_raw_dev; - if (a & ATTR_CMN_FSID) { - *((fsid_t *)attrbufptr) = mp->mnt_stat.f_fsid; - ++((fsid_t *)attrbufptr); - }; - if (a & ATTR_CMN_OBJTYPE) *((fsobj_type_t *)attrbufptr)++ = 0; - if (a & ATTR_CMN_OBJTAG) *((fsobj_tag_t *)attrbufptr)++ = VT_HFS; - if (a & ATTR_CMN_OBJID) { - ((fsobj_id_t *)attrbufptr)->fid_objno = 0; - ((fsobj_id_t *)attrbufptr)->fid_generation = 0; - ++((fsobj_id_t *)attrbufptr); - }; - if (a & ATTR_CMN_OBJPERMANENTID) { - ((fsobj_id_t *)attrbufptr)->fid_objno = 0; - ((fsobj_id_t *)attrbufptr)->fid_generation = 0; - ++((fsobj_id_t *)attrbufptr); - }; - if (a & ATTR_CMN_PAROBJID) { - ((fsobj_id_t *)attrbufptr)->fid_objno = 0; - ((fsobj_id_t *)attrbufptr)->fid_generation = 0; - ++((fsobj_id_t *)attrbufptr); - }; - VCB_LOCK(vcb); - if (a & ATTR_CMN_SCRIPT) *((text_encoding_t *)attrbufptr)++ = vcb->volumeNameEncodingHint; - /* NOTE: all VCB dates are in Mac OS time */ - if (a & ATTR_CMN_CRTIME) { - ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(vcb->vcbCrDate); - ((struct timespec *)attrbufptr)->tv_nsec = 0; - ++((struct timespec *)attrbufptr); - }; - if (a & ATTR_CMN_MODTIME) { - ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(vcb->vcbLsMod); - ((struct timespec *)attrbufptr)->tv_nsec = 0; - ++((struct timespec *)attrbufptr); - }; - if (a & ATTR_CMN_CHGTIME) { - ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(vcb->vcbLsMod); - ((struct timespec *)attrbufptr)->tv_nsec = 0; - ++((struct timespec *)attrbufptr); - }; - if (a & ATTR_CMN_ACCTIME) { - ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(vcb->vcbLsMod); - ((struct timespec *)attrbufptr)->tv_nsec = 0; - ++((struct timespec *)attrbufptr); - }; - if (a & ATTR_CMN_BKUPTIME) { - ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(vcb->vcbVolBkUp); - ((struct timespec *)attrbufptr)->tv_nsec = 0; - ++((struct timespec *)attrbufptr); - }; - if (a & ATTR_CMN_FNDRINFO) { - bcopy (&vcb->vcbFndrInfo, attrbufptr, sizeof(vcb->vcbFndrInfo)); - (char *)attrbufptr += sizeof(vcb->vcbFndrInfo); - }; - VCB_UNLOCK(vcb); - if (a & ATTR_CMN_OWNERID) { - if (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) { - *((uid_t *)attrbufptr)++ = - (VTOHFS(root_vp)->hfs_uid == UNKNOWNUID) ? console_user : VTOHFS(root_vp)->hfs_uid; - } else { - *((uid_t *)attrbufptr)++ = - (root_hp->h_meta->h_uid == UNKNOWNUID) ? console_user : root_hp->h_meta->h_uid; - }; - }; - if (a & ATTR_CMN_GRPID) { - if (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) { - *((gid_t *)attrbufptr)++ = VTOHFS(root_vp)->hfs_gid; - } else { - *((gid_t *)attrbufptr)++ = root_hp->h_meta->h_gid; - }; - }; - if (a & ATTR_CMN_ACCESSMASK) *((u_long *)attrbufptr)++ = (u_long)root_hp->h_meta->h_mode; - if (a & ATTR_CMN_NAMEDATTRCOUNT) *((u_long *)attrbufptr)++ = 0; /* XXX PPD TBC */ - if (a & ATTR_CMN_NAMEDATTRLIST) { - attrlength = 0; - ((struct attrreference *)attrbufptr)->attr_dataoffset = 0; - ((struct attrreference *)attrbufptr)->attr_length = attrlength; - - /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */ - (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3); - ++((struct attrreference *)attrbufptr); - }; - if (a & ATTR_CMN_FLAGS) *((u_long *)attrbufptr)++ = root_hp->h_meta->h_pflags; - if (a & ATTR_CMN_USERACCESS) { - if (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) { - *((u_long *)attrbufptr)++ = - DerivePermissionSummary((VTOHFS(root_vp)->hfs_uid == UNKNOWNUID) ? console_user : VTOHFS(root_vp)->hfs_uid, - VTOHFS(root_vp)->hfs_gid, - root_hp->h_meta->h_mode, - VTOVFS(root_vp), - current_proc()->p_ucred, - current_proc()); - } else { - *((u_long *)attrbufptr)++ = - DerivePermissionSummary((root_hp->h_meta->h_uid == UNKNOWNUID) ? console_user : root_hp->h_meta->h_uid, - root_hp->h_meta->h_gid, - root_hp->h_meta->h_mode, - VTOVFS(root_vp), - current_proc()->p_ucred, - current_proc()); - }; - }; - }; - - *attrbufptrptr = attrbufptr; - *varbufptrptr = varbufptr; -} - - - -void PackVolAttributeBlock(struct attrlist *alist, - struct vnode *root_vp, - struct hfsCatalogInfo *root_catInfo, - void **attrbufptrptr, - void **varbufptrptr) { - void *attrbufptr; - void *varbufptr; - attrgroup_t a; - struct mount *mp = VTOVFS(root_vp); - struct hfsmount *hfsmp = VTOHFS(root_vp); - ExtendedVCB *vcb = HFSTOVCB(hfsmp); - u_long attrlength; - - attrbufptr = *attrbufptrptr; - varbufptr = *varbufptrptr; - - if ((a = alist->volattr) != 0) { - VCB_LOCK(vcb); - if (a & ATTR_VOL_FSTYPE) *((u_long *)attrbufptr)++ = (u_long)mp->mnt_vfc->vfc_typenum; - if (a & ATTR_VOL_SIGNATURE) *((u_long *)attrbufptr)++ = (u_long)vcb->vcbSigWord; - if (a & ATTR_VOL_SIZE) *((off_t *)attrbufptr)++ = (off_t)vcb->totalBlocks * (off_t)vcb->blockSize; - if (a & ATTR_VOL_SPACEFREE) *((off_t *)attrbufptr)++ = (off_t)vcb->freeBlocks * (off_t)vcb->blockSize; - if (a & ATTR_VOL_SPACEAVAIL) *((off_t *)attrbufptr)++ = (off_t)vcb->freeBlocks * (off_t)vcb->blockSize; - if (a & ATTR_VOL_MINALLOCATION) *((off_t *)attrbufptr)++ = (off_t)vcb->blockSize; - if (a & ATTR_VOL_ALLOCATIONCLUMP) *((off_t *)attrbufptr)++ = (off_t)(vcb->vcbClpSiz); - if (a & ATTR_VOL_IOBLOCKSIZE) *((u_long *)attrbufptr)++ = (u_long)hfsmp->hfs_logBlockSize; - if (a & ATTR_VOL_OBJCOUNT) *((u_long *)attrbufptr)++ = (u_long)vcb->vcbFilCnt + (u_long)vcb->vcbDirCnt; - if (a & ATTR_VOL_FILECOUNT) *((u_long *)attrbufptr)++ = (u_long)vcb->vcbFilCnt; - if (a & ATTR_VOL_DIRCOUNT) *((u_long *)attrbufptr)++ = (u_long)vcb->vcbDirCnt; - if (a & ATTR_VOL_MAXOBJCOUNT) *((u_long *)attrbufptr)++ = 0xFFFFFFFF; - if (a & ATTR_VOL_MOUNTPOINT) { - ((struct attrreference *)attrbufptr)->attr_dataoffset = (char *)varbufptr - (char *)attrbufptr; - ((struct attrreference *)attrbufptr)->attr_length = strlen(mp->mnt_stat.f_mntonname) + 1; - attrlength = ((struct attrreference *)attrbufptr)->attr_length; - attrlength = attrlength + ((4 - (attrlength & 3)) & 3); /* round up to the next 4-byte boundary: */ - (void) bcopy(mp->mnt_stat.f_mntonname, varbufptr, attrlength); - - /* Advance beyond the space just allocated: */ - (char *)varbufptr += attrlength; - ++((struct attrreference *)attrbufptr); - }; - if (a & ATTR_VOL_NAME) { - ((struct attrreference *)attrbufptr)->attr_dataoffset = (char *)varbufptr - (char *)attrbufptr; - ((struct attrreference *)attrbufptr)->attr_length = VTOH(root_vp)->h_meta->h_namelen + 1; - attrlength = ((struct attrreference *)attrbufptr)->attr_length; - attrlength = attrlength + ((4 - (attrlength & 3)) & 3); /* round up to the next 4-byte boundary: */ - bcopy(H_NAME(VTOH(root_vp)), varbufptr, attrlength); - - /* Advance beyond the space just allocated: */ - (char *)varbufptr += attrlength; - ++((struct attrreference *)attrbufptr); - }; - if (a & ATTR_VOL_MOUNTFLAGS) *((u_long *)attrbufptr)++ = (u_long)mp->mnt_flag; - if (a & ATTR_VOL_MOUNTEDDEVICE) { - ((struct attrreference *)attrbufptr)->attr_dataoffset = (char *)varbufptr - (char *)attrbufptr; - ((struct attrreference *)attrbufptr)->attr_length = strlen(mp->mnt_stat.f_mntfromname) + 1; - attrlength = ((struct attrreference *)attrbufptr)->attr_length; - attrlength = attrlength + ((4 - (attrlength & 3)) & 3); /* round up to the next 4-byte boundary: */ - (void) bcopy(mp->mnt_stat.f_mntfromname, varbufptr, attrlength); - - /* Advance beyond the space just allocated: */ - (char *)varbufptr += attrlength; - ++((struct attrreference *)attrbufptr); - }; - if (a & ATTR_VOL_ENCODINGSUSED) *((unsigned long long *)attrbufptr)++ = (unsigned long long)vcb->encodingsBitmap; - if (a & ATTR_VOL_CAPABILITIES) { - if (vcb->vcbSigWord == kHFSPlusSigWord) { - ((vol_capabilities_attr_t *)attrbufptr)->capabilities[VOL_CAPABILITIES_FORMAT] = - VOL_CAP_FMT_PERSISTENTOBJECTIDS | VOL_CAP_FMT_SYMBOLICLINKS | VOL_CAP_FMT_HARDLINKS; - } else { /* Plain HFS */ - ((vol_capabilities_attr_t *)attrbufptr)->capabilities[VOL_CAPABILITIES_FORMAT] = - VOL_CAP_FMT_PERSISTENTOBJECTIDS; - } - ((vol_capabilities_attr_t *)attrbufptr)->capabilities[VOL_CAPABILITIES_INTERFACES] = - VOL_CAP_INT_SEARCHFS | VOL_CAP_INT_ATTRLIST | VOL_CAP_INT_NFSEXPORT | VOL_CAP_INT_READDIRATTR; - ((vol_capabilities_attr_t *)attrbufptr)->capabilities[VOL_CAPABILITIES_RESERVED1] = 0; - ((vol_capabilities_attr_t *)attrbufptr)->capabilities[VOL_CAPABILITIES_RESERVED2] = 0; - - ((vol_capabilities_attr_t *)attrbufptr)->valid[VOL_CAPABILITIES_FORMAT] = - VOL_CAP_FMT_PERSISTENTOBJECTIDS | VOL_CAP_FMT_SYMBOLICLINKS | VOL_CAP_FMT_HARDLINKS; - ((vol_capabilities_attr_t *)attrbufptr)->valid[VOL_CAPABILITIES_INTERFACES] = - VOL_CAP_INT_SEARCHFS | VOL_CAP_INT_ATTRLIST | VOL_CAP_INT_NFSEXPORT | VOL_CAP_INT_READDIRATTR; - ((vol_capabilities_attr_t *)attrbufptr)->valid[VOL_CAPABILITIES_RESERVED1] = 0; - ((vol_capabilities_attr_t *)attrbufptr)->valid[VOL_CAPABILITIES_RESERVED2] = 0; - - ++((vol_capabilities_attr_t *)attrbufptr); - }; - if (a & ATTR_VOL_ATTRIBUTES) { - ((vol_attributes_attr_t *)attrbufptr)->validattr.commonattr = ATTR_CMN_VALIDMASK; - ((vol_attributes_attr_t *)attrbufptr)->validattr.volattr = ATTR_VOL_VALIDMASK; - ((vol_attributes_attr_t *)attrbufptr)->validattr.dirattr = ATTR_DIR_VALIDMASK; - ((vol_attributes_attr_t *)attrbufptr)->validattr.fileattr = ATTR_FILE_VALIDMASK; - ((vol_attributes_attr_t *)attrbufptr)->validattr.forkattr = ATTR_FORK_VALIDMASK; - - ((vol_attributes_attr_t *)attrbufptr)->nativeattr.commonattr = ATTR_CMN_VALIDMASK; - ((vol_attributes_attr_t *)attrbufptr)->nativeattr.volattr = ATTR_VOL_VALIDMASK; - ((vol_attributes_attr_t *)attrbufptr)->nativeattr.dirattr = ATTR_DIR_VALIDMASK; - ((vol_attributes_attr_t *)attrbufptr)->nativeattr.fileattr = ATTR_FILE_VALIDMASK; - ((vol_attributes_attr_t *)attrbufptr)->nativeattr.forkattr = ATTR_FORK_VALIDMASK; - - ++((vol_attributes_attr_t *)attrbufptr); - }; - VCB_UNLOCK(vcb); - }; - - *attrbufptrptr = attrbufptr; - *varbufptrptr = varbufptr; -} - - - - -void PackVolumeInfo(struct attrlist *alist, - struct vnode *root_vp, - struct hfsCatalogInfo *root_catinfo, - void **attrbufptrptr, - void **varbufptrptr) { - - PackVolCommonAttributes(alist, root_vp, root_catinfo, attrbufptrptr, varbufptrptr); - PackVolAttributeBlock(alist, root_vp, root_catinfo, attrbufptrptr, varbufptrptr); -}; - -// Pack the common attribute contents of an objects hfsCatalogInfo -void PackCommonCatalogInfoAttributeBlock(struct attrlist *alist, - struct vnode *root_vp, - struct hfsCatalogInfo *catalogInfo, - void **attrbufptrptr, - void **varbufptrptr ) -{ - struct hfsnode *hp; - void *attrbufptr; - void *varbufptr; - attrgroup_t a; - u_long attrlength; - Boolean isHFSPlus; - - hp = VTOH(root_vp); - attrbufptr = *attrbufptrptr; - varbufptr = *varbufptrptr; - isHFSPlus = (VTOVCB(root_vp)->vcbSigWord == kHFSPlusSigWord); - - if ((a = alist->commonattr) != 0) - { - if (a & ATTR_CMN_NAME) - { - attrlength = strlen(catalogInfo->nodeData.cnm_nameptr) + 1; - ((struct attrreference *)attrbufptr)->attr_dataoffset = (char *)varbufptr - (char *)attrbufptr; - ((struct attrreference *)attrbufptr)->attr_length = attrlength; - (void) strncpy((unsigned char *)varbufptr, - catalogInfo->nodeData.cnm_nameptr, attrlength); - - /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */ - (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3); - ++((struct attrreference *)attrbufptr); - }; - if (a & ATTR_CMN_DEVID) *((dev_t *)attrbufptr)++ = H_DEV(hp); - if (a & ATTR_CMN_FSID) { - *((fsid_t *)attrbufptr) = VTOVFS(root_vp)->mnt_stat.f_fsid; - ++((fsid_t *)attrbufptr); - }; - if (a & ATTR_CMN_OBJTYPE) - { - switch (catalogInfo->nodeData.cnd_type) { - case kCatalogFolderNode: - *((fsobj_type_t *)attrbufptr)++ = VDIR; - break; - - case kCatalogFileNode: - /* Files in an HFS+ catalog can represent many things (regular files, symlinks, block/character devices, ...) */ - if ((HTOVCB(hp)->vcbSigWord == kHFSPlusSigWord) && - (catalogInfo->nodeData.cnd_mode & IFMT)) { - *((fsobj_type_t *)attrbufptr)++ = - IFTOVT((mode_t)catalogInfo->nodeData.cnd_mode); - } else { - *((fsobj_type_t *)attrbufptr)++ = VREG; - }; - break; - - default: - *((fsobj_type_t *)attrbufptr)++ = VNON; - break; - }; - } - if (a & ATTR_CMN_OBJTAG) *((fsobj_tag_t *)attrbufptr)++ = root_vp->v_tag; - if (a & ATTR_CMN_OBJID) { - u_int32_t cnid; - - /* For hard links use the link's cnid */ - if (catalogInfo->nodeData.cnd_iNodeNumCopy != 0) - cnid = catalogInfo->nodeData.cnd_linkCNID; - else - cnid = catalogInfo->nodeData.cnd_nodeID; - ((fsobj_id_t *)attrbufptr)->fid_objno = cnid; - ((fsobj_id_t *)attrbufptr)->fid_generation = 0; - ++((fsobj_id_t *)attrbufptr); - }; - if (a & ATTR_CMN_OBJPERMANENTID) { - u_int32_t cnid; - - /* For hard links use the link's cnid */ - if (catalogInfo->nodeData.cnd_iNodeNumCopy != 0) - cnid = catalogInfo->nodeData.cnd_linkCNID; - else - cnid = catalogInfo->nodeData.cnd_nodeID; - ((fsobj_id_t *)attrbufptr)->fid_objno = cnid; - ((fsobj_id_t *)attrbufptr)->fid_generation = 0; - ++((fsobj_id_t *)attrbufptr); - }; - if (a & ATTR_CMN_PAROBJID) - { - ((fsobj_id_t *)attrbufptr)->fid_objno = catalogInfo->nodeData.cnm_parID; - ((fsobj_id_t *)attrbufptr)->fid_generation = 0; - ++((fsobj_id_t *)attrbufptr); - }; - if (a & ATTR_CMN_SCRIPT) - { - if (HTOVCB(hp)->vcbSigWord == kHFSPlusSigWord) { - *((text_encoding_t *)attrbufptr)++ = catalogInfo->nodeData.cnd_textEncoding; - } else { - *((text_encoding_t *)attrbufptr)++ = VTOHFS(root_vp)->hfs_encoding; - } - }; - if (a & ATTR_CMN_CRTIME) - { - ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(catalogInfo->nodeData.cnd_createDate); - ((struct timespec *)attrbufptr)->tv_nsec = 0; - ++((struct timespec *)attrbufptr); - }; - if (a & ATTR_CMN_MODTIME) - { - ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(catalogInfo->nodeData.cnd_contentModDate); - ((struct timespec *)attrbufptr)->tv_nsec = 0; - ++((struct timespec *)attrbufptr); - }; - if (a & ATTR_CMN_CHGTIME) - { - ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(catalogInfo->nodeData.cnd_attributeModDate); - ((struct timespec *)attrbufptr)->tv_nsec = 0; - ++((struct timespec *)attrbufptr); - }; - if (a & ATTR_CMN_ACCTIME) - { - ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(catalogInfo->nodeData.cnd_accessDate); - ((struct timespec *)attrbufptr)->tv_nsec = 0; - ++((struct timespec *)attrbufptr); - }; - if (a & ATTR_CMN_BKUPTIME) - { - ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(catalogInfo->nodeData.cnd_backupDate); - ((struct timespec *)attrbufptr)->tv_nsec = 0; - ++((struct timespec *)attrbufptr); - }; - if (a & ATTR_CMN_FNDRINFO) - { - bcopy (&catalogInfo->nodeData.cnd_finderInfo, attrbufptr, sizeof(catalogInfo->nodeData.cnd_finderInfo)); - (char *)attrbufptr += sizeof(catalogInfo->nodeData.cnd_finderInfo); - }; - if (a & ATTR_CMN_OWNERID) { - if ((VTOVFS(root_vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) || - ((catalogInfo->nodeData.cnd_mode & IFMT) == 0)) { - *((uid_t *)attrbufptr)++ = - (VTOHFS(root_vp)->hfs_uid == UNKNOWNUID) ? console_user : VTOHFS(root_vp)->hfs_uid; - } else { - *((uid_t *)attrbufptr)++ = - (catalogInfo->nodeData.cnd_ownerID == UNKNOWNUID) ? console_user : catalogInfo->nodeData.cnd_ownerID; - }; - } - if (a & ATTR_CMN_GRPID) { - if ((VTOVFS(root_vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) || - ((catalogInfo->nodeData.cnd_mode & IFMT) == 0)) { - *((gid_t *)attrbufptr)++ = VTOHFS(root_vp)->hfs_gid; - } else { - *((gid_t *)attrbufptr)++ = catalogInfo->nodeData.cnd_groupID; - }; - } - if (a & ATTR_CMN_ACCESSMASK) { - if (((catalogInfo->nodeData.cnd_mode & IFMT) == 0) -#if OVERRIDE_UNKNOWN_PERMISSIONS - || (VTOVFS(root_vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) -#endif - ) { - switch (catalogInfo->nodeData.cnd_type) { - case kCatalogFileNode: - /* Files in an HFS+ catalog can represent many things (regular files, symlinks, block/character devices, ...) */ - *((u_long *)attrbufptr)++ = (u_long)(IFREG | (ACCESSPERMS & (u_long)(VTOHFS(root_vp)->hfs_file_mask))); - break; - - case kCatalogFolderNode: - *((u_long *)attrbufptr)++ = (u_long)(IFDIR | (ACCESSPERMS & (u_long)(VTOHFS(root_vp)->hfs_dir_mask))); - break; - - default: - *((u_long *)attrbufptr)++ = (u_long)((catalogInfo->nodeData.cnd_mode & IFMT) | - VTOHFS(root_vp)->hfs_dir_mask); - }; - } else { - *((u_long *)attrbufptr)++ = - (u_long)catalogInfo->nodeData.cnd_mode; - }; - } - if (a & ATTR_CMN_NAMEDATTRCOUNT) *((u_long *)attrbufptr)++ = 0; /* XXX PPD TBC */ - if (a & ATTR_CMN_NAMEDATTRLIST) - { - attrlength = 0; - ((struct attrreference *)attrbufptr)->attr_dataoffset = 0; - ((struct attrreference *)attrbufptr)->attr_length = attrlength; - - /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */ - (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3); - ++((struct attrreference *)attrbufptr); - }; - if (a & ATTR_CMN_FLAGS) { - u_long flags; - - if (catalogInfo->nodeData.cnd_mode & IFMT) - flags = catalogInfo->nodeData.cnd_ownerFlags | - catalogInfo->nodeData.cnd_adminFlags << 16; - else - flags = 0; - - if (catalogInfo->nodeData.cnd_type == kCatalogFileNode) { - if (catalogInfo->nodeData.cnd_flags & kHFSFileLockedMask) - flags |= UF_IMMUTABLE; - else - flags &= ~UF_IMMUTABLE; - }; - *((u_long *)attrbufptr)++ = flags; - }; - if (a & ATTR_CMN_USERACCESS) { - if ((VTOVFS(root_vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) || - ((catalogInfo->nodeData.cnd_mode & IFMT) == 0)) { - *((u_long *)attrbufptr)++ = - DerivePermissionSummary((VTOHFS(root_vp)->hfs_uid == UNKNOWNUID) ? console_user : VTOHFS(root_vp)->hfs_uid, - VTOHFS(root_vp)->hfs_gid, -#if OVERRIDE_UNKNOWN_PERMISSIONS - (catalogInfo->nodeData.cnd_type == kCatalogFileNode) ? VTOHFS(root_vp)->hfs_file_mask : VTOHFS(root_vp)->hfs_dir_mask, -#else - (catalogInfo->nodeData.cnd_mode & IFMT) ? - (u_long)catalogInfo->nodeData.cnd_mode : - ((catalogInfo->nodeData.cnd_type == kCatalogFileNode) ? - VTOHFS(root_vp)->hfs_file_mask : - VTOHFS(root_vp)->hfs_dir_mask), -#endif - VTOVFS(root_vp), - current_proc()->p_ucred, - current_proc()); - } else { - *((u_long *)attrbufptr)++ = - DerivePermissionSummary((catalogInfo->nodeData.cnd_ownerID == UNKNOWNUID) ? console_user : catalogInfo->nodeData.cnd_ownerID, - catalogInfo->nodeData.cnd_groupID, - (mode_t)catalogInfo->nodeData.cnd_mode, - VTOVFS(root_vp), - current_proc()->p_ucred, - current_proc()); - }; - }; - }; - - *attrbufptrptr = attrbufptr; - *varbufptrptr = varbufptr; -} - - -void PackCommonAttributeBlock(struct attrlist *alist, - struct vnode *vp, - struct hfsCatalogInfo *catInfo, - void **attrbufptrptr, - void **varbufptrptr) { - struct hfsnode *hp; - void *attrbufptr; - void *varbufptr; - attrgroup_t a; - u_long attrlength; - - hp = VTOH(vp); - - attrbufptr = *attrbufptrptr; - varbufptr = *varbufptrptr; - - if ((a = alist->commonattr) != 0) { - if (a & ATTR_CMN_NAME) { - PackObjectName(vp, H_NAME(hp), hp->h_meta->h_namelen, &attrbufptr, &varbufptr); - }; - if (a & ATTR_CMN_DEVID) *((dev_t *)attrbufptr)++ = H_DEV(hp); - if (a & ATTR_CMN_FSID) { - *((fsid_t *)attrbufptr) = VTOVFS(vp)->mnt_stat.f_fsid; - ++((fsid_t *)attrbufptr); - }; - if (a & ATTR_CMN_OBJTYPE) *((fsobj_type_t *)attrbufptr)++ = vp->v_type; - if (a & ATTR_CMN_OBJTAG) *((fsobj_tag_t *)attrbufptr)++ = vp->v_tag; - if (a & ATTR_CMN_OBJID) { - u_int32_t cnid; - - /* For hard links use the link's cnid */ - if (hp->h_meta->h_metaflags & IN_DATANODE) - cnid = catInfo->nodeData.cnd_linkCNID; - else - cnid = H_FILEID(hp); - ((fsobj_id_t *)attrbufptr)->fid_objno = cnid; - ((fsobj_id_t *)attrbufptr)->fid_generation = 0; - ++((fsobj_id_t *)attrbufptr); - }; - if (a & ATTR_CMN_OBJPERMANENTID) { - u_int32_t cnid; - - /* For hard links use the link's cnid */ - if (hp->h_meta->h_metaflags & IN_DATANODE) - cnid = catInfo->nodeData.cnd_linkCNID; - else - cnid = H_FILEID(hp); - ((fsobj_id_t *)attrbufptr)->fid_objno = cnid; - ((fsobj_id_t *)attrbufptr)->fid_generation = 0; - ++((fsobj_id_t *)attrbufptr); - }; - if (a & ATTR_CMN_PAROBJID) { - ((fsobj_id_t *)attrbufptr)->fid_objno = H_DIRID(hp); - ((fsobj_id_t *)attrbufptr)->fid_generation = 0; - ++((fsobj_id_t *)attrbufptr); - }; - if (a & ATTR_CMN_SCRIPT) - { - if (HTOVCB(hp)->vcbSigWord == kHFSPlusSigWord) { - *((text_encoding_t *)attrbufptr)++ = catInfo->nodeData.cnd_textEncoding; - } else { - *((text_encoding_t *)attrbufptr)++ = VTOHFS(vp)->hfs_encoding; - } - }; - if (a & ATTR_CMN_CRTIME) { - ((struct timespec *)attrbufptr)->tv_sec = hp->h_meta->h_crtime; - ((struct timespec *)attrbufptr)->tv_nsec = 0; - ++((struct timespec *)attrbufptr); - }; - if (a & ATTR_CMN_MODTIME) { - ((struct timespec *)attrbufptr)->tv_sec = hp->h_meta->h_mtime; - ((struct timespec *)attrbufptr)->tv_nsec = 0; - ++((struct timespec *)attrbufptr); - }; - if (a & ATTR_CMN_CHGTIME) { - ((struct timespec *)attrbufptr)->tv_sec = hp->h_meta->h_ctime; - ((struct timespec *)attrbufptr)->tv_nsec = 0; - ++((struct timespec *)attrbufptr); - }; - if (a & ATTR_CMN_ACCTIME) { - ((struct timespec *)attrbufptr)->tv_sec = hp->h_meta->h_atime; - ((struct timespec *)attrbufptr)->tv_nsec = 0; - ++((struct timespec *)attrbufptr); - }; - if (a & ATTR_CMN_BKUPTIME) { - ((struct timespec *)attrbufptr)->tv_sec = hp->h_meta->h_butime; - ((struct timespec *)attrbufptr)->tv_nsec = 0; - ++((struct timespec *)attrbufptr); - }; - if (a & ATTR_CMN_FNDRINFO) { - bcopy (&catInfo->nodeData.cnd_finderInfo, attrbufptr, sizeof(catInfo->nodeData.cnd_finderInfo)); - (char *)attrbufptr += sizeof(catInfo->nodeData.cnd_finderInfo); - }; - if (a & ATTR_CMN_OWNERID) { - if (VTOVFS(vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) { - *((uid_t *)attrbufptr)++ = - (VTOHFS(vp)->hfs_uid == UNKNOWNUID) ? console_user : VTOHFS(vp)->hfs_uid; - } else { - *((uid_t *)attrbufptr)++ = - (hp->h_meta->h_uid == UNKNOWNUID) ? console_user : hp->h_meta->h_uid; - } - }; - if (a & ATTR_CMN_GRPID) { - if (VTOVFS(vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) { - *((gid_t *)attrbufptr)++ = VTOHFS(vp)->hfs_gid; - } else { - *((gid_t *)attrbufptr)++ = hp->h_meta->h_gid; - }; - }; - if (a & ATTR_CMN_ACCESSMASK) *((u_long *)attrbufptr)++ = (u_long)hp->h_meta->h_mode; - if (a & ATTR_CMN_NAMEDATTRCOUNT) *((u_long *)attrbufptr)++ = 0; /* XXX PPD TBC */ - if (a & ATTR_CMN_NAMEDATTRLIST) { - attrlength = 0; - ((struct attrreference *)attrbufptr)->attr_dataoffset = 0; - ((struct attrreference *)attrbufptr)->attr_length = attrlength; - - /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */ - (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3); - ++((struct attrreference *)attrbufptr); - }; - if (a & ATTR_CMN_FLAGS) *((u_long *)attrbufptr)++ = hp->h_meta->h_pflags; - if (a & ATTR_CMN_USERACCESS) { - if (VTOVFS(vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) { - *((u_long *)attrbufptr)++ = - DerivePermissionSummary((VTOHFS(vp)->hfs_uid == UNKNOWNUID) ? console_user : VTOHFS(vp)->hfs_uid, - VTOHFS(vp)->hfs_gid, - hp->h_meta->h_mode, - VTOVFS(vp), - current_proc()->p_ucred, - current_proc()); - } else { - *((u_long *)attrbufptr)++ = - DerivePermissionSummary((hp->h_meta->h_uid == UNKNOWNUID) ? console_user : hp->h_meta->h_uid, - hp->h_meta->h_gid, - hp->h_meta->h_mode, - VTOVFS(vp), - current_proc()->p_ucred, - current_proc()); - }; - }; - }; - - *attrbufptrptr = attrbufptr; - *varbufptrptr = varbufptr; -} - - -// Pack the directory attributes given hfsCatalogInfo -void PackCatalogInfoDirAttributeBlock( struct attrlist *alist, struct vnode *vp, - struct hfsCatalogInfo *catInfo, void **attrbufptrptr, void **varbufptrptr ) -{ - void *attrbufptr; - attrgroup_t a; - u_long valence; - - attrbufptr = *attrbufptrptr; - a = alist->dirattr; - - if ( (catInfo->nodeData.cnd_type == kCatalogFolderNode) && (a != 0) ) { - valence = catInfo->nodeData.cnd_valence; - if ((catInfo->nodeData.cnm_parID == kRootParID) && - (VTOHFS(vp)->hfs_private_metadata_dir != 0)) { - --valence; /* hide private dir */ - } - /* The 'link count' is faked */ - if (a & ATTR_DIR_LINKCOUNT) - *((u_long *)attrbufptr)++ = 2 + valence; - if (a & ATTR_DIR_ENTRYCOUNT) - *((u_long *)attrbufptr)++ = valence; - if (a & ATTR_DIR_MOUNTSTATUS) - *((u_long *)attrbufptr)++ = 0; - }; - - *attrbufptrptr = attrbufptr; -} - - -void PackDirAttributeBlock(struct attrlist *alist, - struct vnode *vp, - struct hfsCatalogInfo *catInfo, - void **attrbufptrptr, - void **varbufptrptr) { - void *attrbufptr; - attrgroup_t a; - u_long valence; - - attrbufptr = *attrbufptrptr; - - a = alist->dirattr; - if ((vp->v_type == VDIR) && (a != 0)) { - valence = catInfo->nodeData.cnd_valence; - if ((catInfo->nodeData.cnm_parID == kRootParID) && - (VTOHFS(vp)->hfs_private_metadata_dir != 0)) { - --valence; /* hide private dir */ - } - - /* The 'link count' is faked */ - if (a & ATTR_DIR_LINKCOUNT) - *((u_long *)attrbufptr)++ = 2 + valence; - if (a & ATTR_DIR_ENTRYCOUNT) - *((u_long *)attrbufptr)++ = valence; - if (a & ATTR_DIR_MOUNTSTATUS) { - if (vp->v_mountedhere) { - *((u_long *)attrbufptr)++ = DIR_MNTSTATUS_MNTPOINT; - } else { - *((u_long *)attrbufptr)++ = 0; - }; - }; - }; - - *attrbufptrptr = attrbufptr; -} - - - -// Pack the file attributes from the hfsCatalogInfo for the file. -void PackCatalogInfoFileAttributeBlock( struct attrlist *alist, struct vnode *root_vp, struct hfsCatalogInfo *catInfo, void **attrbufptrptr, void **varbufptrptr ) -{ - void *attrbufptr; - void *varbufptr; - attrgroup_t a; - u_long attrlength; - ExtendedVCB *vcb = VTOVCB(root_vp); - - attrbufptr = *attrbufptrptr; - varbufptr = *varbufptrptr; - - a = alist->fileattr; - if ( (catInfo->nodeData.cnd_type == kCatalogFileNode) && (a != 0) ) - { -#if HFS_HARDLINKS - if (a & ATTR_FILE_LINKCOUNT) { - u_long linkcnt = catInfo->nodeData.cnd_linkCount; - - if (linkcnt < 1) - linkcnt = 1; - *((u_long *)attrbufptr)++ = linkcnt; - } -#else - if (a & ATTR_FILE_LINKCOUNT) *((u_long *)attrbufptr)++ = 1; -#endif - if (a & ATTR_FILE_TOTALSIZE) { - *((off_t *)attrbufptr)++ = - (off_t)catInfo->nodeData.cnd_datafork.logicalSize + - (off_t)catInfo->nodeData.cnd_rsrcfork.logicalSize; - } - if (a & ATTR_FILE_ALLOCSIZE) { - *((off_t *)attrbufptr)++ = - (off_t)((off_t)catInfo->nodeData.cnd_datafork.totalBlocks * (off_t)vcb->blockSize) + - (off_t)((off_t)catInfo->nodeData.cnd_rsrcfork.totalBlocks * (off_t)vcb->blockSize); - } - if (a & ATTR_FILE_IOBLOCKSIZE) { - *((u_long *)attrbufptr)++ = (u_long)(VTOHFS(root_vp)->hfs_logBlockSize); - } - if (a & ATTR_FILE_CLUMPSIZE) { - *((u_long *)attrbufptr)++ = vcb->vcbClpSiz; - } - if (a & ATTR_FILE_DEVTYPE) { - u_long rawdev; - u_short filetype; - - filetype = (catInfo->nodeData.cnd_mode & IFMT); - if (filetype == IFCHR || filetype == IFBLK) - rawdev = (u_long)catInfo->nodeData.cnd_rawDevice; - else - rawdev = 0; - - *((u_long *)attrbufptr)++ = rawdev; - } - if (a & ATTR_FILE_FILETYPE) { - *((u_long *)attrbufptr)++ = 0; /* XXX PPD */ - } - if (a & ATTR_FILE_FORKCOUNT) { - *((u_long *)attrbufptr)++ = 2; /* XXX PPD */ - } - if (a & ATTR_FILE_FORKLIST) { - attrlength = 0; - ((struct attrreference *)attrbufptr)->attr_dataoffset = 0; - ((struct attrreference *)attrbufptr)->attr_length = attrlength; - - /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */ - (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3); - ++((struct attrreference *)attrbufptr); - }; - if (a & ATTR_FILE_DATALENGTH) { - *((off_t *)attrbufptr)++ = - (off_t)catInfo->nodeData.cnd_datafork.logicalSize; - } - if (a & ATTR_FILE_DATAALLOCSIZE) { - *((off_t *)attrbufptr)++ = - (off_t)((off_t)catInfo->nodeData.cnd_datafork.totalBlocks * (off_t)vcb->blockSize); - } - if (a & ATTR_FILE_DATAEXTENTS) { - bcopy(&catInfo->nodeData.cnd_datafork.extents, attrbufptr, sizeof(extentrecord)); - (char *)attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3); - }; - if (a & ATTR_FILE_RSRCLENGTH) { - *((off_t *)attrbufptr)++ = - (off_t)catInfo->nodeData.cnd_rsrcfork.logicalSize; - } - if (a & ATTR_FILE_RSRCALLOCSIZE) { - *((off_t *)attrbufptr)++ = - (off_t)((off_t)catInfo->nodeData.cnd_rsrcfork.totalBlocks * (off_t)vcb->blockSize); - } - if (a & ATTR_FILE_RSRCEXTENTS) { - bcopy(&catInfo->nodeData.cnd_rsrcfork.extents, attrbufptr, sizeof(extentrecord)); - (char *)attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3); - }; - }; - - *attrbufptrptr = attrbufptr; - *varbufptrptr = varbufptr; -} - - -void PackFileAttributeBlock(struct attrlist *alist, - struct vnode *vp, - struct hfsCatalogInfo *catInfo, - void **attrbufptrptr, - void **varbufptrptr) { - struct hfsnode *hp = VTOH(vp); - FCB *fcb = HTOFCB(hp); - ExtendedVCB *vcb = HTOVCB(hp); - Boolean isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord); - void *attrbufptr = *attrbufptrptr; - void *varbufptr = *varbufptrptr; - attrgroup_t a = alist->fileattr; - u_long attrlength; - - if (a != 0) { -#if HFS_HARDLINKS - if (a & ATTR_FILE_LINKCOUNT) { - u_long linkcnt = catInfo->nodeData.cnd_linkCount; - - if (linkcnt < 1) - linkcnt = 1; - *((u_long *)attrbufptr)++ = linkcnt; - } -#else - if (a & ATTR_FILE_LINKCOUNT) *((u_long *)attrbufptr)++ = 1; -#endif - if (a & ATTR_FILE_TOTALSIZE) { - *((off_t *)attrbufptr)++ = - (off_t)catInfo->nodeData.cnd_datafork.logicalSize + - (off_t)catInfo->nodeData.cnd_rsrcfork.logicalSize; - } - if (a & ATTR_FILE_ALLOCSIZE) { - switch (H_FORKTYPE(hp)) { - case kDataFork: - *((off_t *)attrbufptr)++ = - (off_t)fcb->fcbPLen + - (off_t)((off_t)catInfo->nodeData.cnd_rsrcfork.totalBlocks * (off_t)vcb->blockSize); - break; - case kRsrcFork: - *((off_t *)attrbufptr)++ = - (off_t)fcb->fcbPLen + - (off_t)((off_t)catInfo->nodeData.cnd_datafork.totalBlocks * (off_t)vcb->blockSize); - break; - default: - *((off_t *)attrbufptr)++ = - (off_t)((off_t)catInfo->nodeData.cnd_datafork.totalBlocks * (off_t)vcb->blockSize) + - (off_t)((off_t)catInfo->nodeData.cnd_rsrcfork.totalBlocks * (off_t)vcb->blockSize); - }; - }; - if (a & ATTR_FILE_IOBLOCKSIZE) *((u_long *)attrbufptr)++ = GetLogicalBlockSize(vp); - if (a & ATTR_FILE_CLUMPSIZE) *((u_long *)attrbufptr)++ = fcb->fcbClmpSize; - if (a & ATTR_FILE_DEVTYPE) { - u_long rawdev; - - if ((vp->v_type == VBLK) || (vp->v_type == VCHR)) - rawdev = (u_long)catInfo->nodeData.cnd_rawDevice; - else - rawdev = 0; - *((u_long *)attrbufptr)++ = rawdev; - } - if (a & ATTR_FILE_FILETYPE) *((u_long *)attrbufptr)++ = 0; /* XXX PPD */ - if (a & ATTR_FILE_FORKCOUNT) *((u_long *)attrbufptr)++ = 2; /* XXX PPD */ - if (a & ATTR_FILE_FORKLIST) { - attrlength = 0; - ((struct attrreference *)attrbufptr)->attr_dataoffset = 0; - ((struct attrreference *)attrbufptr)->attr_length = attrlength; - - /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */ - (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3); - ++((struct attrreference *)attrbufptr); - }; - if (H_FORKTYPE(hp) == kDataFork) { - if (a & ATTR_FILE_DATALENGTH) - *((off_t *)attrbufptr)++ = fcb->fcbEOF; - if (a & ATTR_FILE_DATAALLOCSIZE) *((off_t *)attrbufptr)++ = fcb->fcbPLen; - if (a & ATTR_FILE_DATAEXTENTS) { - bcopy ( fcb->fcbExtents, attrbufptr, sizeof(extentrecord)); - (char *)attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3); - }; - } else { - if (a & ATTR_FILE_DATALENGTH) { - *((off_t *)attrbufptr)++ = - (off_t)catInfo->nodeData.cnd_datafork.logicalSize; - } - if (a & ATTR_FILE_DATAALLOCSIZE) { - *((off_t *)attrbufptr)++ = - (off_t)((off_t)catInfo->nodeData.cnd_datafork.totalBlocks * (off_t)vcb->blockSize); - } - if (a & ATTR_FILE_DATAEXTENTS) { - bcopy(&catInfo->nodeData.cnd_datafork.extents, attrbufptr, sizeof(extentrecord)); - (char *)attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3); - }; - }; - if (H_FORKTYPE(hp) == kRsrcFork) { - if (a & ATTR_FILE_RSRCLENGTH) - *((off_t *)attrbufptr)++ = fcb->fcbEOF; - if (a & ATTR_FILE_RSRCALLOCSIZE) *((off_t *)attrbufptr)++ = fcb->fcbPLen; - if (a & ATTR_FILE_RSRCEXTENTS) { - bcopy ( fcb->fcbExtents, attrbufptr, sizeof(extentrecord)); - (char *)attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3); - }; - } else { - if (a & ATTR_FILE_RSRCLENGTH) { - *((off_t *)attrbufptr)++ = - (off_t)catInfo->nodeData.cnd_rsrcfork.logicalSize; - } - if (a & ATTR_FILE_RSRCALLOCSIZE) { - *((off_t *)attrbufptr)++ = - (off_t)((off_t)catInfo->nodeData.cnd_rsrcfork.totalBlocks * (off_t)vcb->blockSize); - } - if (a & ATTR_FILE_RSRCEXTENTS) { - bcopy(&catInfo->nodeData.cnd_rsrcfork.extents, attrbufptr, sizeof(extentrecord)); - (char *)attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3); - }; - }; - }; - - *attrbufptrptr = attrbufptr; - *varbufptrptr = varbufptr; -} - -#if 0 -void PackForkAttributeBlock(struct attrlist *alist, - struct vnode *vp, - struct hfsCatalogInfo *catInfo, - void **attrbufptrptr, - void **varbufptrptr) { - /* XXX PPD TBC */ -} -#endif - - -// This routine takes catInfo, and alist, as inputs and packs it into an attribute block. -void PackCatalogInfoAttributeBlock ( struct attrlist *alist, struct vnode *root_vp, struct hfsCatalogInfo *catInfo, void **attrbufptrptr, void **varbufptrptr) -{ - //XXX Preflight that alist only contains bits with fields in catInfo - - PackCommonCatalogInfoAttributeBlock( alist, root_vp, catInfo, attrbufptrptr, varbufptrptr ); - - switch ( catInfo->nodeData.cnd_type ) - { - case kCatalogFolderNode: - PackCatalogInfoDirAttributeBlock( alist, root_vp, catInfo, attrbufptrptr, varbufptrptr ); - break; - - case kCatalogFileNode: - PackCatalogInfoFileAttributeBlock( alist, root_vp, catInfo, attrbufptrptr, varbufptrptr ); - break; - - default: /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR not being handled... */ - /* XXX PPD - Panic? */ - break; - } -} - - - -void PackAttributeBlock(struct attrlist *alist, - struct vnode *vp, - struct hfsCatalogInfo *catInfo, - void **attrbufptrptr, - void **varbufptrptr) -{ - if (alist->volattr != 0) { - DBG_ASSERT((vp->v_flag & VROOT) != 0); - PackVolumeInfo(alist,vp, catInfo, attrbufptrptr, varbufptrptr); - } else { - PackCommonAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr); - - switch (vp->v_type) { - case VDIR: - PackDirAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr); - break; - - case VREG: - case VLNK: - PackFileAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr); - break; - - /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR - not being handled... - */ - default: - /* XXX PPD - Panic? */ - break; - }; - }; -}; - - - -void UnpackVolumeAttributeBlock(struct attrlist *alist, - struct vnode *root_vp, - ExtendedVCB *vcb, - void **attrbufptrptr, - void **varbufptrptr) { - void *attrbufptr = *attrbufptrptr; - attrgroup_t a; - - if ((alist->commonattr == 0) && (alist->volattr == 0)) { - return; /* Get out without dirtying the VCB */ - }; - - VCB_LOCK(vcb); - - a = alist->commonattr; - - if (a & ATTR_CMN_SCRIPT) { - vcb->volumeNameEncodingHint = (u_int32_t)*(((text_encoding_t *)attrbufptr)++); -#if HFS_DIAGNOSTIC - a &= ~ATTR_CMN_SCRIPT; -#endif - }; - if (a & ATTR_CMN_CRTIME) { - vcb->vcbCrDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec); - /* Need to update the local time also */ - vcb->localCreateDate = UTCToLocal(vcb->vcbCrDate); - ++((struct timespec *)attrbufptr); -#if HFS_DIAGNOSTIC - a &= ~ATTR_CMN_CRTIME; -#endif - }; - if (a & ATTR_CMN_MODTIME) { - vcb->vcbLsMod = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec); - ++((struct timespec *)attrbufptr); -#if HFS_DIAGNOSTIC - a &= ~ATTR_CMN_MODTIME; -#endif - }; - if (a & ATTR_CMN_BKUPTIME) { - vcb->vcbVolBkUp = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec); - ++((struct timespec *)attrbufptr); -#if HFS_DIAGNOSTIC - a &= ~ATTR_CMN_BKUPTIME; -#endif - }; - if (a & ATTR_CMN_FNDRINFO) { - bcopy (attrbufptr, &vcb->vcbFndrInfo, sizeof(vcb->vcbFndrInfo)); - (char *)attrbufptr += sizeof(vcb->vcbFndrInfo); -#if HFS_DIAGNOSTIC - a &= ~ATTR_CMN_FNDRINFO; -#endif - }; - - DBG_ASSERT(a == 0); /* All common attributes for volumes must've been handled by now... */ - - a = alist->volattr & ~ATTR_VOL_INFO; - if (a & ATTR_VOL_NAME) { - copystr(((char *)attrbufptr) + *((u_long *)attrbufptr), vcb->vcbVN, sizeof(vcb->vcbVN), NULL); - (char *)attrbufptr += sizeof(struct attrreference); -#if HFS_DIAGNOSTIC - a &= ~ATTR_VOL_NAME; -#endif - }; - - DBG_ASSERT(a == 0); /* All common attributes for volumes must've been handled by now... */ - - vcb->vcbFlags |= 0xFF00; // Mark the VCB dirty - - VCB_UNLOCK(vcb); -} - - -void UnpackCommonAttributeBlock(struct attrlist *alist, - struct vnode *vp, - struct hfsCatalogInfo *catInfo, - void **attrbufptrptr, - void **varbufptrptr) { - struct hfsnode *hp = VTOH(vp); - void *attrbufptr; - attrgroup_t a; - - attrbufptr = *attrbufptrptr; - - DBG_ASSERT(catInfo != NULL); - - a = alist->commonattr; - if (a & ATTR_CMN_SCRIPT) { - catInfo->nodeData.cnd_textEncoding = (u_int32_t)*((text_encoding_t *)attrbufptr)++; - UpdateVolumeEncodings(VTOVCB(vp), catInfo->nodeData.cnd_textEncoding); /* Update the volume encoding */ -#if HFS_DIAGNOSTIC - a &= ~ATTR_CMN_SCRIPT; -#endif - }; - if (a & ATTR_CMN_CRTIME) { - catInfo->nodeData.cnd_createDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec); - VTOH(vp)->h_meta->h_crtime = (UInt32)((struct timespec *)attrbufptr)->tv_sec; - ++((struct timespec *)attrbufptr); -#if HFS_DIAGNOSTIC - a &= ~ATTR_CMN_CRTIME; -#endif - }; - if (a & ATTR_CMN_MODTIME) { - catInfo->nodeData.cnd_contentModDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec); - VTOH(vp)->h_meta->h_mtime = (UInt32)((struct timespec *)attrbufptr)->tv_sec; - ++((struct timespec *)attrbufptr); - hp->h_nodeflags &= ~IN_UPDATE; -#if HFS_DIAGNOSTIC - a &= ~ATTR_CMN_MODTIME; -#endif - }; - if (a & ATTR_CMN_CHGTIME) { - catInfo->nodeData.cnd_attributeModDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec); - VTOH(vp)->h_meta->h_ctime = (UInt32)((struct timespec *)attrbufptr)->tv_sec; - ++((struct timespec *)attrbufptr); - hp->h_nodeflags &= ~IN_CHANGE; -#if HFS_DIAGNOSTIC - a &= ~ATTR_CMN_CHGTIME; -#endif - }; - if (a & ATTR_CMN_ACCTIME) { - catInfo->nodeData.cnd_accessDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec); - VTOH(vp)->h_meta->h_atime = (UInt32)((struct timespec *)attrbufptr)->tv_sec; - ++((struct timespec *)attrbufptr); - hp->h_nodeflags &= ~IN_ACCESS; -#if HFS_DIAGNOSTIC - a &= ~ATTR_CMN_ACCTIME; -#endif - }; - if (a & ATTR_CMN_BKUPTIME) { - catInfo->nodeData.cnd_backupDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec); - VTOH(vp)->h_meta->h_butime = (UInt32)((struct timespec *)attrbufptr)->tv_sec; - ++((struct timespec *)attrbufptr); -#if HFS_DIAGNOSTIC - a &= ~ATTR_CMN_BKUPTIME; -#endif - }; - if (a & ATTR_CMN_FNDRINFO) { - bcopy (attrbufptr, &catInfo->nodeData.cnd_finderInfo, sizeof(catInfo->nodeData.cnd_finderInfo)); - (char *)attrbufptr += sizeof(catInfo->nodeData.cnd_finderInfo); -#if HFS_DIAGNOSTIC - a &= ~ATTR_CMN_FNDRINFO; -#endif - }; - if (a & ATTR_CMN_OWNERID) { - if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) { - u_int32_t uid = (u_int32_t)*((uid_t *)attrbufptr)++; - if (uid != (uid_t)VNOVAL) - hp->h_meta->h_uid = uid; /* catalog will get updated by hfs_chown() */ - } - else { - ((uid_t *)attrbufptr)++; - } -#if HFS_DIAGNOSTIC - a &= ~ATTR_CMN_OWNERID; -#endif - }; - if (a & ATTR_CMN_GRPID) { - u_int32_t gid = (u_int32_t)*((gid_t *)attrbufptr)++; - if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) { - if (gid != (gid_t)VNOVAL) - hp->h_meta->h_gid = gid; /* catalog will get updated by hfs_chown() */ - }; -#if HFS_DIAGNOSTIC - a &= ~ATTR_CMN_GRPID; -#endif - }; - if (a & ATTR_CMN_ACCESSMASK) { - u_int16_t mode = (u_int16_t)*((u_long *)attrbufptr)++; - if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) { - if (mode != (mode_t)VNOVAL) { - hp->h_meta->h_mode &= ~ALLPERMS; - hp->h_meta->h_mode |= (mode & ALLPERMS); /* catalog will get updated by hfs_chmod() */ - } - }; -#if HFS_DIAGNOSTIC - a &= ~ATTR_CMN_ACCESSMASK; -#endif - }; - if (a & ATTR_CMN_FLAGS) { - u_long flags = *((u_long *)attrbufptr)++; - /* Flags are settable only on HFS+ volumes. A special exception is made for the IMMUTABLE - flags (SF_IMMUTABLE and UF_IMMUTABLE), which can be set on HFS volumes as well: */ - if ((VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) || - ((VTOVCB(vp)->vcbSigWord == kHFSSigWord) && ((flags & ~IMMUTABLE) == 0))) { - if (flags != (u_long)VNOVAL) { - hp->h_meta->h_pflags = flags; /* catalog will get updated by hfs_chflags */ - }; - }; -#if HFS_DIAGNOSTIC - a &= ~ATTR_CMN_FLAGS; -#endif - }; - -#if HFS_DIAGNOSTIC - if (a != 0) { - DEBUG_BREAK_MSG(("UnpackCommonAttributes: unhandled bit: 0x%08X\n", a)); - }; -#endif - - *attrbufptrptr = attrbufptr; -// *varbufptrptr = varbufptr; -} - - - -#if 0 -void UnpackDirAttributeBlock(struct attrlist *alist, - struct vnode *vp, - struct hfsCatalogInfo *catInfo, - void **attrbufptrptr, - void **varbufptrptr) { - void *attrbufptr; - void *varbufptr; - attrgroup_t a; - u_long attrlength; - - attrbufptr = *attrbufptrptr; - varbufptr = *varbufptrptr; - - /* XXX PPD TBC */ - - *attrbufptrptr = attrbufptr; - *varbufptrptr = varbufptr; -} -#endif - - - -#if 0 -void UnpackFileAttributeBlock(struct attrlist *alist, - struct vnode *vp, - struct hfsCatalogInfo *catInfo, - void **attrbufptrptr, - void **varbufptrptr) { - void *attrbufptr; - void *varbufptr; - attrgroup_t a; - u_long attrlength; - - attrbufptr = *attrbufptrptr; - varbufptr = *varbufptrptr; - - /* XXX PPD TBC */ - - *attrbufptrptr = attrbufptr; - *varbufptrptr = varbufptr; -} -#endif - - - -#if 0 -void UnpackForkAttributeBlock(struct attrlist *alist, - struct vnode *vp, - struct hfsCatalogInfo *catInfo, - void **attrbufptrptr, - void **varbufptrptr) { - void *attrbufptr; - void *varbufptr; - attrgroup_t a; - u_long attrlength; - - attrbufptr = *attrbufptrptr; - varbufptr = *varbufptrptr; - - /* XXX PPD TBC */ - - *attrbufptrptr = attrbufptr; - *varbufptrptr = varbufptr; -} -#endif - - - -void UnpackAttributeBlock(struct attrlist *alist, - struct vnode *vp, - struct hfsCatalogInfo *catInfo, - void **attrbufptrptr, - void **varbufptrptr) { - - - if (alist->volattr != 0) { - UnpackVolumeAttributeBlock(alist, vp, VTOVCB(vp), attrbufptrptr, varbufptrptr); - return; - }; - - /* We're dealing with a vnode object here: */ - UnpackCommonAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr); - -#if 0 - switch (vp->v_type) { - case VDIR: - UnpackDirAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr); - break; - - case VREG: - /* case VCPLX: */ /* XXX PPD TBC */ - UnpackFileAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr); - break; - - case VFORK: - UnpackForkAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr); - break; - - /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR - not being handled... - */ - default: - /* XXX PPD - Panic? */ - break; - }; -#endif - -}; - - -unsigned long BestBlockSizeFit(unsigned long allocationBlockSize, - unsigned long blockSizeLimit, - unsigned long baseMultiple) { - /* - Compute the optimal (largest) block size (no larger than allocationBlockSize) that is less than the - specified limit but still an even multiple of the baseMultiple. - */ - int baseBlockCount, blockCount; - unsigned long trialBlockSize; - - if (allocationBlockSize % baseMultiple != 0) { - /* - Whoops: the allocation blocks aren't even multiples of the specified base: - no amount of dividing them into even parts will be a multiple, either then! - */ - return 512; /* Hope for the best */ - }; - - /* Try the obvious winner first, to prevent 12K allocation blocks, for instance, - from being handled as two 6K logical blocks instead of 3 4K logical blocks. - Even though the former (the result of the loop below) is the larger allocation - block size, the latter is more efficient: */ - if (allocationBlockSize % PAGE_SIZE == 0) return PAGE_SIZE; - - /* No clear winner exists: pick the largest even fraction <= MAXBSIZE: */ - baseBlockCount = allocationBlockSize / baseMultiple; /* Now guaranteed to be an even multiple */ - - for (blockCount = baseBlockCount; blockCount > 0; --blockCount) { - trialBlockSize = blockCount * baseMultiple; - if (allocationBlockSize % trialBlockSize == 0) { /* An even multiple? */ - if ((trialBlockSize <= blockSizeLimit) && - (trialBlockSize % baseMultiple == 0)) { - return trialBlockSize; - }; - }; - }; - - /* Note: we should never get here, since blockCount = 1 should always work, - but this is nice and safe and makes the compiler happy, too ... */ - return 512; -} - - -/* - * To make the HFS Plus filesystem follow UFS unlink semantics, a remove - * of an active vnode is translated to a move/rename so the file appears - * deleted. The destination folder for these move/renames is setup here - * and a reference to it is place in hfsmp->hfs_private_metadata_dir. - */ -u_long -FindMetaDataDirectory(ExtendedVCB *vcb) -{ - char namep[32]; - hfsCatalogInfo catInfo; - HFSCatalogNodeID dirID; - u_int32_t metadata_createdate; - int retval; - - if (vcb->vcbSigWord != kHFSPlusSigWord) - return (0); - - dirID = 0; - metadata_createdate = 0; - strncpy(namep, HFSPLUS_PRIVATE_DIR, sizeof(namep)); - INIT_CATALOGDATA(&catInfo.nodeData, kCatNameNoCopyName); - catInfo.hint = kNoHint; - - /* lock catalog b-tree */ - retval = hfs_metafilelocking(VCBTOHFS(vcb), kHFSCatalogFileID, LK_SHARED, current_proc()); - if (retval) goto Err_Exit; - - if (hfs_getcatalog(vcb, kRootDirID, namep, -1, &catInfo) == 0) { - dirID = catInfo.nodeData.cnd_nodeID; - metadata_createdate = catInfo.nodeData.cnd_createDate; - } else if (VCBTOHFS(vcb)->hfs_fs_ronly == 0) { - if (CreateCatalogNode(vcb, kRootDirID, namep, kCatalogFolderNode, &dirID, &catInfo.hint, 0) == 0) { - catInfo.hint = kNoHint; - if (hfs_getcatalog(vcb, kRootDirID, namep, -1, &catInfo) == 0) { - - /* create date is later used for validation */ - catInfo.nodeData.cnd_createDate = vcb->vcbCrDate; - metadata_createdate = catInfo.nodeData.cnd_createDate; - - /* directory with no permissions owned by root */ - catInfo.nodeData.cnd_mode = IFDIR; - catInfo.nodeData.cnd_adminFlags = (SF_IMMUTABLE >> 16); - - /* hidden and off the desktop view */ - ((struct DInfo *)(&catInfo.nodeData.cnd_finderInfo))->frLocation.v = SWAP_BE16 (22460); - ((struct DInfo *)(&catInfo.nodeData.cnd_finderInfo))->frLocation.h = SWAP_BE16 (22460); - ((struct DInfo *)(&catInfo.nodeData.cnd_finderInfo))->frFlags |= SWAP_BE16 (kIsInvisible + kNameLocked); - - (void) UpdateCatalogNode(vcb, kRootDirID, namep, catInfo.hint, &catInfo.nodeData); - } - } - } - - /* unlock catalog b-tree */ - (void) hfs_metafilelocking(VCBTOHFS(vcb), kHFSCatalogFileID, LK_RELEASE, current_proc()); - - VCBTOHFS(vcb)->hfs_metadata_createdate = metadata_createdate; -Err_Exit: - CLEAN_CATALOGDATA(&catInfo.nodeData); - - return dirID; -} - - -static void -RemovedMetaDataDirectory(ExtendedVCB *vcb) -{ - char name[32]; - hfsCatalogInfo catInfo; - int retval; - - strncpy(name, HFSPLUS_PRIVATE_DIR, sizeof(name)); - INIT_CATALOGDATA(&catInfo.nodeData, kCatNameNoCopyName); - - /* lock catalog b-tree */ - retval = hfs_metafilelocking(VCBTOHFS(vcb), kHFSCatalogFileID, LK_SHARED, current_proc()); - if (retval) goto Err_Exit; - - /* If the HFSPLUSMETADATAFOLDER exists then delete it. */ - retval = GetCatalogNode(vcb, kRootDirID, name, strlen(name), kNoHint, - &catInfo.nodeData, &catInfo.hint); - if (retval == 0 && (catInfo.nodeData.cnd_type == kCatalogFolderNode)) { - (void) DeleteCatalogNode(vcb, kRootDirID, name, catInfo.hint); - printf("hfs_mount: removed \"%s\" from hfs volume \"%s\"\n", name, vcb->vcbVN); - } - - /* unlock catalog b-tree */ - (void) hfs_metafilelocking(VCBTOHFS(vcb), kHFSCatalogFileID, LK_RELEASE, current_proc()); - -Err_Exit: - CLEAN_CATALOGDATA(&catInfo.nodeData); -} - -/* - * This will return the correct logical block size for a given vnode. - * For most files, it is the allocation block size, for meta data like - * BTrees, this is kept as part of the BTree private nodeSize - */ -u_int32_t -GetLogicalBlockSize(struct vnode *vp) -{ -u_int32_t logBlockSize; - - DBG_ASSERT(vp != NULL); - - /* start with default */ - logBlockSize = VTOHFS(vp)->hfs_logBlockSize; + /* start with default */ + logBlockSize = VTOHFS(vp)->hfs_logBlockSize; if (vp->v_flag & VSYSTEM) { - if (VTOH(vp)->fcbBTCBPtr != NULL) { + if (VTOF(vp)->fcbBTCBPtr != NULL) { BTreeInfoRec bTreeInfo; /* @@ -3252,11 +816,11 @@ u_int32_t logBlockSize; * it in the first place?? */ - (void) BTGetInformation (VTOFCB(vp), kBTreeInfoVersion, &bTreeInfo); + (void) BTGetInformation (VTOF(vp), kBTreeInfoVersion, &bTreeInfo); logBlockSize = bTreeInfo.nodeSize; - } else if (H_FILEID(VTOH(vp)) == kHFSAllocationFileID) { + } else if (VTOC(vp)->c_fileid == kHFSAllocationFileID) { logBlockSize = VTOVCB(vp)->vcbVBMIOSize; } } @@ -3266,468 +830,169 @@ u_int32_t logBlockSize; return logBlockSize; } +__private_extern__ +u_int32_t +hfs_freeblks(struct hfsmount * hfsmp, int wantreserve) +{ + struct vcb_t *vcb = HFSTOVCB(hfsmp); + u_int32_t freeblks; + + freeblks = vcb->freeBlocks; + if (wantreserve) { + if (freeblks > vcb->reserveBlocks) + freeblks -= vcb->reserveBlocks; + else + freeblks = 0; + } + + freeblks -= vcb->loanedBlocks; + return (freeblks); +} + /* * Map HFS Common errors (negative) to BSD error codes (positive). * Positive errors (ie BSD errors) are passed through unchanged. */ short MacToVFSError(OSErr err) { - if (err >= 0) { - if (err > 0) { - DBG_ERR(("MacToVFSError: passing error #%d unchanged...\n", err)); - }; - return err; - }; + if (err >= 0) + return err; - if (err != 0) { - DBG_ERR(("MacToVFSError: mapping error code %d...\n", err)); - }; - switch (err) { - case dirFulErr: /* -33 */ - case dskFulErr: /* -34 */ - case btNoSpaceAvail: /* -32733 */ - case fxOvFlErr: /* -32750 */ - return ENOSPC; /* +28 */ - - case btBadNode: /* -32731 */ - case ioErr: /* -36 */ - return EIO; /* +5 */ - - case mFulErr: /* -41 */ - case memFullErr: /* -108 */ - return ENOMEM; /* +12 */ - - case tmfoErr: /* -42 */ - /* Consider EMFILE (Too many open files, 24)? */ - return ENFILE; /* +23 */ - - case nsvErr: /* -35 */ - case fnfErr: /* -43 */ - case dirNFErr: /* -120 */ - case fidNotFound: /* -1300 */ - return ENOENT; /* +2 */ - - case wPrErr: /* -44 */ - case vLckdErr: /* -46 */ - case fsDSIntErr: /* -127 */ - return EROFS; /* +30 */ - - case opWrErr: /* -49 */ - case fLckdErr: /* -45 */ - return EACCES; /* +13 */ - - case permErr: /* -54 */ - case wrPermErr: /* -61 */ - return EPERM; /* +1 */ - - case fBsyErr: /* -47 */ - return EBUSY; /* +16 */ - - case dupFNErr: /* -48 */ - case fidExists: /* -1301 */ - case cmExists: /* -32718 */ - case btExists: /* -32734 */ - return EEXIST; /* +17 */ - - case rfNumErr: /* -51 */ - return EBADF; /* +9 */ - - case notAFileErr: /* -1302 */ - return EISDIR; /* +21 */ - - case cmNotFound: /* -32719 */ - case btNotFound: /* -32735 */ - return ENOENT; /* 28 */ - - case cmNotEmpty: /* -32717 */ - return ENOTEMPTY; /* 66 */ - - case cmFThdDirErr: /* -32714 */ - return EISDIR; /* 21 */ - - case fxRangeErr: /* -32751 */ - return EIO; /* 5 */ - - case bdNamErr: /* -37 */ - return ENAMETOOLONG; /* 63 */ - - case fnOpnErr: /* -38 */ - case eofErr: /* -39 */ - case posErr: /* -40 */ - case paramErr: /* -50 */ - case badMDBErr: /* -60 */ - case badMovErr: /* -122 */ - case sameFileErr: /* -1306 */ - case badFidErr: /* -1307 */ - case fileBoundsErr: /* -1309 */ - return EINVAL; /* +22 */ - - case fsBTBadNodeSize: + case dskFulErr: /* -34 */ + case btNoSpaceAvail: /* -32733 */ + case fxOvFlErr: /* -32750 */ + return ENOSPC; /* +28 */ + + case btBadNode: /* -32731 */ + return EIO; /* +5 */ + + case memFullErr: /* -108 */ + return ENOMEM; /* +12 */ + + case cmExists: /* -32718 */ + case btExists: /* -32734 */ + return EEXIST; /* +17 */ + + case cmNotFound: /* -32719 */ + case btNotFound: /* -32735 */ + return ENOENT; /* 28 */ + + case cmNotEmpty: /* -32717 */ + return ENOTEMPTY; /* 66 */ + + case cmFThdDirErr: /* -32714 */ + return EISDIR; /* 21 */ + + case fxRangeErr: /* -32751 */ + return EIO; /* 5 */ + + case bdNamErr: /* -37 */ + return ENAMETOOLONG; /* 63 */ + + case paramErr: /* -50 */ + case fileBoundsErr: /* -1309 */ + return EINVAL; /* +22 */ + + case fsBTBadNodeSize: return ENXIO; - default: - DBG_UTILS(("Unmapped MacOS error: %d\n", err)); - return EIO; /* +5 */ + + default: + return EIO; /* +5 */ } } /* - * All of our debugging functions + * Get the directory entry name hint for a given index. + * The directory cnode (dcp) must be locked. */ - -#if HFS_DIAGNOSTIC - -void debug_vn_status (char* introStr, struct vnode *vn) -{ - DBG_VOP(("%s:\t",introStr)); - if (vn != NULL) - { - if (vn->v_tag != VT_HFS) - { - DBG_VOP(("NON-HFS VNODE Ox%08lX\n", (unsigned long)vn)); - } - else if(vn->v_tag==VT_HFS && (vn->v_data==NULL || VTOH((vn))->h_valid != HFS_VNODE_MAGIC)) - { - DBG_VOP(("BAD VNODE PRIVATE DATA!!!!\n")); - } - else - { - DBG_VOP(("r: %d & ", vn->v_usecount)); - if (lockstatus(&VTOH(vn)->h_lock)) - { - DBG_VOP_CONT(("is L\n")); - } - else - { - DBG_VOP_CONT(("is U\n")); - } - } - } - else - { - DBG_VOP(("vnode is NULL\n")); - }; -} - -void debug_vn_print (char* introStr, struct vnode *vn) -{ -// DBG_FUNC_NAME("DBG_VN_PRINT"); - DBG_ASSERT (vn != NULL); - DBG_VFS(("%s: ",introStr)); - DBG_VFS_CONT(("vnode: 0x%x is a ", (uint)vn)); - switch (vn->v_tag) - { - case VT_UFS: - DBG_VFS_CONT(("%s","UFS")); - break; - case VT_HFS: - DBG_VFS_CONT(("%s","HFS")); - break; - default: - DBG_VFS_CONT(("%s","UNKNOWN")); - break; - } - - DBG_VFS_CONT((" vnode\n")); - if (vn->v_tag==VT_HFS) - { - if (vn->v_data==NULL) - { - DBG_VFS(("BAD VNODE PRIVATE DATA!!!!\n")); - } - else - { - DBG_VFS((" Name: %s Id: %ld ",H_NAME(VTOH(vn)), H_FILEID(VTOH(vn)))); - } - } - else - DBG_VFS((" ")); - - DBG_VFS_CONT(("Refcount: %d\n", vn->v_usecount)); - if (VOP_ISLOCKED(vn)) - { - DBG_VFS((" The vnode is locked\n")); - } - else - { - DBG_VFS((" The vnode is not locked\n")); - } -} - -void debug_rename_test_locks (char* introStr, - struct vnode *fvp, - struct vnode *fdvp, - struct vnode *tvp, - struct vnode *tdvp, - int fstatus, - int fdstatus, - int tstatus, - int tdstatus -) +__private_extern__ +char * +hfs_getnamehint(struct cnode *dcp, int index) { - DBG_VOP(("\t%s: ", introStr)); - if (fvp) {if(lockstatus(&VTOH(fvp)->h_lock)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));}; - if (fdvp) {if(lockstatus(&VTOH(fdvp)->h_lock)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));}; - if (tvp) {if(lockstatus(&VTOH(tvp)->h_lock)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));}; - if (tdvp) {if(lockstatus(&VTOH(tdvp)->h_lock)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));}; - DBG_VFS_CONT(("\n")); - - if (fvp) { - if (lockstatus(&VTOH(fvp)->h_lock)) { - if (fstatus==VOPDBG_UNLOCKED) { - DBG_VOP(("\tfvp should be NOT LOCKED and it is\n")); - } - } else if (fstatus == VOPDBG_LOCKED) { - DBG_VOP(("\tfvp should be LOCKED and it isnt\n")); - } - } - - if (fdvp) { - if (lockstatus(&VTOH(fdvp)->h_lock)) { - if (fdstatus==VOPDBG_UNLOCKED) { - DBG_VOP(("\tfdvp should be NOT LOCKED and it is\n")); - } - } else if (fdstatus == VOPDBG_LOCKED) { - DBG_VOP(("\tfdvp should be LOCKED and it isnt\n")); - } - } - - if (tvp) { - if (lockstatus(&VTOH(tvp)->h_lock)) { - if (tstatus==VOPDBG_UNLOCKED) { - DBG_VOP(("\ttvp should be NOT LOCKED and it is\n")); - } - } else if (tstatus == VOPDBG_LOCKED) { - DBG_VOP(("\ttvp should be LOCKED and it isnt\n")); - } - } - - if (tdvp) { - if (lockstatus(&VTOH(tdvp)->h_lock)) { - if (tdstatus==VOPDBG_UNLOCKED) { - DBG_VOP(("\ttdvp should be NOT LOCKED and it is\n")); - } - } else if (tdstatus == VOPDBG_LOCKED) { - DBG_VOP(("\ttdvp should be LOCKED and it isnt\n")); - - } - } - -} -#endif /* HFS_DIAGNOSTIC */ + struct hfs_index *entry; + void *self; + if (index > 0) { + self = current_thread(); + SLIST_FOREACH(entry, &dcp->c_indexlist, hi_link) { + if ((entry->hi_index == index) + && (entry->hi_thread == self)) + return (entry->hi_name); + } + } -#if HFS_DIAGNOSTIC -void debug_check_buffersizes(struct vnode *vp, struct hfsnode *hp, struct buf *bp) { - DBG_ASSERT(bp->b_validoff == 0); - DBG_ASSERT(bp->b_dirtyoff == 0); - DBG_ASSERT((bp->b_bcount == HTOHFS(hp)->hfs_logBlockSize) || - ((bp->b_bcount % 512 == 0) && - (bp->b_validend > 0) && - (bp->b_dirtyend > 0) && - (bp->b_bcount < HTOHFS(hp)->hfs_logBlockSize))); - - if (bp->b_validend == 0) { - DBG_ASSERT(bp->b_dirtyend == 0); - } else { - DBG_ASSERT(bp->b_validend == bp->b_bcount); - DBG_ASSERT(bp->b_dirtyend <= bp->b_bcount); - }; + return (NULL); } - -void debug_check_blocksizes(struct vnode *vp) { - struct hfsnode *hp = VTOH(vp); - struct buf *bp; - - if (vp->v_flag & VSYSTEM) return; - - for (bp = vp->v_cleanblkhd.lh_first; bp != NULL; bp = bp->b_vnbufs.le_next) { - debug_check_buffersizes(vp, hp, bp); - }; - - for (bp = vp->v_dirtyblkhd.lh_first; bp != NULL; bp = bp->b_vnbufs.le_next) { - debug_check_buffersizes(vp, hp, bp); - }; +/* + * Save a directory entry name hint for a given index. + * The directory cnode (dcp) must be locked. + */ +__private_extern__ +void +hfs_savenamehint(struct cnode *dcp, int index, const char * namehint) +{ + struct hfs_index *entry; + int len; + + if (index > 0) { + len = strlen(namehint); + MALLOC(entry, struct hfs_index *, len + sizeof(struct hfs_index), + M_TEMP, M_WAITOK); + entry->hi_index = index; + entry->hi_thread = current_thread(); + bcopy(namehint, entry->hi_name, len + 1); + SLIST_INSERT_HEAD(&dcp->c_indexlist, entry, hi_link); + } } -void debug_check_catalogdata(struct CatalogNodeData *cat) { - - if (cat->cnm_nameptr == NULL) { - DBG_ASSERT((cat->cnm_flags & kCatNameIsAllocated) == 0); - } - else if (cat->cnm_nameptr == cat->cnm_namespace) { - DBG_ASSERT((cat->cnm_flags & kCatNameIsAllocated) == 0); - } - else { - DBG_ASSERT((cat->cnm_flags & kCatNameIsAllocated) == kCatNameIsAllocated); - } - - if (cat->cnm_nameptr) { - DBG_ASSERT(strlen(cat->cnm_nameptr) == cat->cnm_length); +/* + * Release the directory entry name hint for a given index. + * The directory cnode (dcp) must be locked. + */ +__private_extern__ +void +hfs_relnamehint(struct cnode *dcp, int index) +{ + struct hfs_index *entry; + void *self; + + if (index > 0) { + self = current_thread(); + SLIST_FOREACH(entry, &dcp->c_indexlist, hi_link) { + if ((entry->hi_index == index) + && (entry->hi_thread == self)) { + SLIST_REMOVE(&dcp->c_indexlist, entry, hfs_index, + hi_link); + FREE(entry, M_TEMP); + break; + } + } } - - if (cat->cnm_flags & kCatNameIsConsumed) { - DBG_ASSERT((cat->cnm_flags & kCatNameIsAllocated) == 0); - } - - if (cat->cnm_flags & kCatNameNoCopyName) { - DBG_ASSERT((cat->cnm_flags & (kCatNameIsAllocated|kCatNameIsConsumed|kCatNameIsMangled)) == 0); - DBG_ASSERT(cat->cnm_length == 0); - DBG_ASSERT(cat->cnm_nameptr == 0); - DBG_ASSERT(strlen(cat->cnm_namespace) == 0); - } - } -extern void hfs_vhash_dbg(struct hfsnode *hp); - -/* Checks the valicity of a hfs vnode */ -void debug_check_vnode(struct vnode *vp, int stage) { - struct hfsnode *hp; - u_long size; - int i; - - /* vcb stuff */ - if (VTOHFS(vp)->hfs_mount_flags & kHFSBootVolumeInconsistentMask) - DEBUG_BREAK_MSG(("Volume is damaged!")); - - /* vnode stuff */ - if (vp==NULL) - DEBUG_BREAK_MSG(("Null vnode")); - if (vp->v_tag != VT_HFS) - DEBUG_BREAK_MSG(("Not a HFS vnode, it is a %d", vp->v_tag)); - if (vp->v_data==NULL) - DEBUG_BREAK_MSG(("v_data is NULL")); - - /* hfsnode stuff */ - hp = VTOH(vp); - if (hp->h_valid != HFS_VNODE_MAGIC) - DEBUG_BREAK_MSG(("Bad Formed HFS node")); - if (hp->h_vp==NULL || hp->h_vp!=vp) - DEBUG_BREAK_MSG(("Bad hfsnode vnode pte")); - if (hp->h_meta == NULL) - DEBUG_BREAK_MSG(("Bad hfsnode meta ptr")); - switch (H_FORKTYPE(hp)) { - case kDataFork: - case kRsrcFork: - if ((hp->h_meta->h_siblinghead.cqh_first == NULL) || (hp->h_meta->h_siblinghead.cqh_last == NULL)) - DEBUG_BREAK_MSG(("Null sibling header")); - if ((hp->h_sibling.cqe_next==NULL) || (hp->h_sibling.cqe_prev==NULL)) - DEBUG_BREAK_MSG(("Null sibling list")); - if (hp->h_meta->h_usecount<1 || hp->h_meta->h_usecount>2) - DEBUG_BREAK_MSG(("Bad sibling usecount")); - break; - case kDirectory: - case kSysFile: - if ((hp->h_meta->h_siblinghead.cqh_first != NULL) || (hp->h_meta->h_siblinghead.cqh_last != NULL)) - DEBUG_BREAK_MSG(("Non Null sibling header")); - if ((hp->h_sibling.cqe_next!=NULL) || (hp->h_sibling.cqe_prev!=NULL)) - DEBUG_BREAK_MSG(("Null sibling list")); - if (hp->h_meta->h_usecount!=1) - DEBUG_BREAK_MSG(("Bad usecount")); - - break; - default: - DEBUG_BREAK_MSG(("Bad hfsnode fork type")); - } - - /* hfsmeta stuff */ - if (hp->h_meta->h_devvp == NULL) - DEBUG_BREAK_MSG(("Bad hfsnode dev vnode")); - if (H_DEV(hp) == 0) - DEBUG_BREAK_MSG(("Bad dev id")); - if (H_FILEID(hp) == 0) - DEBUG_BREAK_MSG(("Bad file id")); - - if (((hp->h_meta->h_metaflags & IN_DATANODE)==0) && (H_DIRID(hp) == 0) && (H_FILEID(hp) != 1)) - DEBUG_BREAK_MSG(("Bad dir id")); - - if (hp->h_meta->h_namePtr == NULL && hp->h_meta->h_namelen!=0) - DEBUG_BREAK_MSG(("hfs meta h_namelen is not 0")); - if (hp->h_meta->h_namePtr != NULL && strlen(hp->h_meta->h_namePtr) != hp->h_meta->h_namelen) - DEBUG_BREAK_MSG(("Bad hfs meta h_namelen")); - - /* Check the hash */ - hfs_vhash_dbg(hp); - - /* Check to see if we want to compare with the disk */ - if (stage > 200) { - int retval; - hfsCatalogInfo catInfo; - - INIT_CATALOGDATA(&catInfo.nodeData, 0); - catInfo.hint = 0; - - if (hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_SHARED, current_proc())) - return; - - if (hfs_getcatalog(VTOVCB(vp), H_DIRID(hp), hp->h_meta->h_namePtr, hp->h_meta->h_namelen, &catInfo)) - DEBUG_BREAK_MSG(("Could not find hfsnode Catalog record")); - - (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, current_proc()); - - if (H_FILEID(hp) != catInfo.nodeData.cnd_nodeID) - DEBUG_BREAK_MSG(("hfsnode catalog node id mismatch")); - if (H_DIRID(hp) != catInfo.nodeData.cnm_parID) - DEBUG_BREAK_MSG(("hfsnode catalog dir id mismatch")); - if (strcmp(hp->h_meta->h_namePtr, catInfo.nodeData.cnm_nameptr) != 0) - DEBUG_BREAK_MSG(("hfsnode catalog name mismatch")); - /* Check dates too??? */ - - CLEAN_CATALOGDATA(&catInfo.nodeData); +/* + * Release all directory entry name hints. + */ +__private_extern__ +void +hfs_relnamehints(struct cnode *dcp) +{ + struct hfs_index *entry; + struct hfs_index *next; + if (!SLIST_EMPTY(&dcp->c_indexlist)) { + for(entry = SLIST_FIRST(&dcp->c_indexlist); + entry != NULL; + entry = next) { + next = SLIST_NEXT(entry, hi_link); + SLIST_REMOVE(&dcp->c_indexlist, entry, hfs_index, hi_link); + FREE(entry, M_TEMP); } - - - /* Check Extents */ - { - for(i = 0, size = 0; i < kHFSPlusExtentDensity; i++) - { - size += hp->fcbExtents[i].blockCount; - } - - if (hp->fcbEOF > hp->fcbPLen) - DEBUG_BREAK_MSG(("fcbPLen is smaller than fcbEOF")); - - if (hp->fcbExtents[kHFSPlusExtentDensity-1].blockCount == 0) { - if ((off_t)size * (off_t)VTOVCB(vp)->blockSize != hp->fcbPLen) - DEBUG_BREAK_MSG(("fcbPLen does not match extents")); - } else { - if ( hp->fcbPLen < (off_t)size * (off_t)VTOVCB(vp)->blockSize) - DEBUG_BREAK_MSG(("fcbPLen is smaller than extents")); - } - for(i = 0; i < kHFSPlusExtentDensity; i++) - { - if (hp->fcbExtents[i].blockCount == 0 || hp->fcbExtents[i].startBlock == 0) - break; - } - if ((VTOVCB(vp)->vcbSigWord == kHFSSigWord) && i > kHFSExtentDensity) - DEBUG_BREAK_MSG(("Illegal value in extents for ordinary HFS")); - if (i > kHFSPlusExtentDensity) { - for(; i < kHFSPlusExtentDensity; i++) - { - if (hp->fcbExtents[i].blockCount != 0 || hp->fcbExtents[i].startBlock != 0) - DEBUG_BREAK_MSG(("Illegal value in extents")); - } - } } +} - - /* BTree stuff */ - if (0 && vp->v_flag & VSYSTEM) { - BTreeInfoRec info; - - BTGetInformation(hp, 0, &info); - if (hp->fcbBTCBPtr == NULL) - DEBUG_BREAK_MSG(("Null fcbBTCBPtr")); - if (H_HINT(hp) == 0) - DEBUG_BREAK_MSG(("hint is 0")); - if (H_HINT(hp) > info.numNodes) - DEBUG_BREAK_MSG(("hint > numNodes")); - } -} -#endif /* HFS_DIAGNOSTIC */ diff --git a/bsd/hfs/hfs_vhash.c b/bsd/hfs/hfs_vhash.c deleted file mode 100644 index 8e403895f..000000000 --- a/bsd/hfs/hfs_vhash.c +++ /dev/null @@ -1,393 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* Copyright (c) 1998 Apple Computer, Inc. All Rights Reserved */ -/* - * Copyright (c) 1982, 1986, 1989, 1991, 1993, 1995 - * 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. - * - * @(#)hfs_vhash.c - * derived from @(#)ufs_ihash.c 8.7 (Berkeley) 5/17/95 - */ - -#include -#include -#include -#include -#include -#include - -#include "hfs.h" -#include "hfs_dbg.h" - - -/* - * Structures associated with hfsnode cacheing. - */ -LIST_HEAD(vhashhead, hfsnode) *vhashtbl; -u_long vhash; /* size of hash table - 1 */ -#define HFSNODEHASH(device, nodeID) (&vhashtbl[((device) + (nodeID)) & vhash]) -struct slock hfs_vhash_slock; - -/* - * Initialize hfsnode hash table. - */ -void -hfs_vhashinit() -{ - - vhashtbl = hashinit(desiredvnodes, M_HFSMNT, &vhash); - simple_lock_init(&hfs_vhash_slock); -} - -/* - * Use the device/dirID/forkType tuple to find the incore hfsnode, and return a pointer - * to it. If it is in core, but locked, wait for it. - * - * Acceptable forkTypes are kData, kRsrcFork, kDirectory, or kDefault which translates to either - * kDataFork or kDirectory - * - * While traversing the hash, expext that a hfsnode is in the midst of being allocated, if so, - * then sleep and try again - */ -struct vnode * -hfs_vhashget(dev, nodeID, forkType) - dev_t dev; - UInt32 nodeID; - UInt8 forkType; -{ - struct proc *p = current_proc(); - struct hfsnode *hp; - struct vnode *vp; - - /* - * Go through the hash list - * If a vnode is in the process of being cleaned out or being - * allocated, wait for it to be finished and then try again - */ -loop: - simple_lock(&hfs_vhash_slock); - for (hp = HFSNODEHASH(dev, nodeID)->lh_first; hp; hp = hp->h_hash.le_next) { - if (hp->h_nodeflags & IN_ALLOCATING) { - /* - * vnode is being created. Wait for it to finish... - */ - hp->h_nodeflags |= IN_WANT; - simple_unlock(&hfs_vhash_slock); - tsleep((caddr_t)hp, PINOD, "hfs_vhashget", 0); - goto loop; - } - if ((H_FILEID(hp) != nodeID) || (H_DEV(hp) != dev) || - (hp->h_meta->h_metaflags & IN_NOEXISTS)) - continue; - - /* SER XXX kDefault of meta data (ksysfile) is not assumed here */ - if ( (forkType == kAnyFork) || - (H_FORKTYPE(hp) == forkType) || - ((forkType == kDefault) && ((H_FORKTYPE(hp) == kDirectory) - || (H_FORKTYPE(hp) == kDataFork)))) { - vp = HTOV(hp); - simple_lock(&vp->v_interlock); - simple_unlock(&hfs_vhash_slock); - if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) - goto loop; - return (vp); - } - } - simple_unlock(&hfs_vhash_slock); - return (NULL); -} - - - - -/* - * Lock the hfsnode and insert the hfsnode into the hash table, and return it locked. - * Returns the sibling meta data if it exists, elses return NULL - */ -void -hfs_vhashins_sibling(dev, nodeID, hp, fm) - dev_t dev; - UInt32 nodeID; - struct hfsnode *hp; - struct hfsfilemeta **fm; -{ - struct vhashhead *ipp; - struct hfsnode *thp; - struct hfsfilemeta *tfm; - - tfm = NULL; - lockmgr(&hp->h_lock, LK_EXCLUSIVE, (struct slock *)0, current_proc()); - - /* - * Go through the hash list to see if a sibling exists - * If it does, store it to return - * If a vnode is in the process of being cleaned out or being - * allocated, wait for it to be finished and then try again - */ - - ipp = HFSNODEHASH(dev, nodeID); - -loop: - simple_lock(&hfs_vhash_slock); - for (thp = ipp->lh_first; thp; thp = thp->h_hash.le_next) { - if (thp->h_nodeflags & IN_ALLOCATING) { - /* - * vnode is being created. Wait for it to finish... - */ - thp->h_nodeflags |= IN_WANT; - simple_unlock(&hfs_vhash_slock); - tsleep((caddr_t)thp, PINOD, "hfs_vhashins_sibling", 0); - goto loop; - } - if ((H_FILEID(thp) == nodeID) && (H_DEV(thp) == dev)) { - tfm = hp->h_meta = thp->h_meta; - break; - } - } - - /* Add to sibling list..if it can have them */ - if (tfm && (H_FORKTYPE(hp)==kDataFork || H_FORKTYPE(hp)==kRsrcFork)) { - simple_lock(&tfm->h_siblinglock); - CIRCLEQ_INSERT_HEAD(&tfm->h_siblinghead, hp, h_sibling); - simple_unlock(&tfm->h_siblinglock); - }; - - LIST_INSERT_HEAD(ipp, hp, h_hash); - simple_unlock(&hfs_vhash_slock); - *fm = tfm; -} - - - -/* -* Lock the hfsnode and insert the hfsnode into the hash table, and return it locked. - */ -void -hfs_vhashins(dev, nodeID, hp) - dev_t dev; - UInt32 nodeID; - struct hfsnode *hp; -{ - struct vhashhead *ipp; - - DBG_ASSERT(hp != NULL); - DBG_ASSERT(nodeID != 0); - - lockmgr(&hp->h_lock, LK_EXCLUSIVE, (struct slock *)0, current_proc()); - - simple_lock(&hfs_vhash_slock); - ipp = HFSNODEHASH(dev, nodeID); - LIST_INSERT_HEAD(ipp, hp, h_hash); - simple_unlock(&hfs_vhash_slock); -} - - -/* - * Remove the hfsnode from the hash table and then checks to see if another forks exists. - */ -void -hfs_vhashrem(hp) - struct hfsnode *hp; -{ - - DBG_ASSERT(hp != NULL); - DBG_ASSERT(hp->h_meta != NULL); - - simple_lock(&hfs_vhash_slock); - - /* Test to see if there are siblings, should only apply to forks */ - if (hp->h_meta != NULL && hp->h_meta->h_siblinghead.cqh_first != NULL) { - simple_lock(&hp->h_meta->h_siblinglock); - CIRCLEQ_REMOVE(&hp->h_meta->h_siblinghead, hp, h_sibling); - simple_unlock(&hp->h_meta->h_siblinglock); - }; - - LIST_REMOVE(hp, h_hash); - -#if HFS_DIAGNOSTIC - hp->h_hash.le_next = NULL; - hp->h_hash.le_prev = NULL; -#endif - - - simple_unlock(&hfs_vhash_slock); - - -} - - -/* - * Moves the entries from one bucket to another - * nodeID is the old bucket id - */ -void -hfs_vhashmove(hp, oldNodeID) - struct hfsnode *hp; - UInt32 oldNodeID; -{ - struct vhashhead *oldHeadIndex, *newHeadIndex; - struct hfsnode *thp, *nextNode; - UInt32 newNodeID; - - newNodeID = H_FILEID(hp); - oldHeadIndex = HFSNODEHASH(H_DEV(hp), oldNodeID); - newHeadIndex = HFSNODEHASH(H_DEV(hp), newNodeID); - - /* If it is moving to the same bucket...then we are done */ - if (oldHeadIndex == newHeadIndex) - return; - -loop: - /* - * Go through the old hash list - * If there is a nodeid mismatch, or the nodeid doesnt match the current bucket - * remove it and add it to the right bucket. - * If a vnode is in the process of being cleaned out or being - * allocated, wait for it to be finished and then try again - */ - simple_lock(&hfs_vhash_slock); - for (nextNode = oldHeadIndex->lh_first; nextNode; ) { - if (nextNode->h_nodeflags & IN_ALLOCATING) { - /* - * vnode is being created. Wait for it to finish... - */ - nextNode->h_nodeflags |= IN_WANT; - simple_unlock(&hfs_vhash_slock); - tsleep((caddr_t)nextNode, PINOD, "hfs_vhashmove", 0); - goto loop; - } - - thp = nextNode; - nextNode = nextNode->h_hash.le_next; - if (newNodeID == H_FILEID(thp)) { - LIST_REMOVE(thp, h_hash); - thp->h_hash.le_next = NULL; - thp->h_hash.le_next = NULL; - LIST_INSERT_HEAD(newHeadIndex, thp, h_hash); - } - } - - simple_unlock(&hfs_vhash_slock); -} - -#if HFS_DIAGNOSTIC -/* - * This will test the hash entry for a given hfsnode - * It will test: - * 1. The uniqei existance of the node - * 2. All other nodes, proper membership to the hash - * 3. Proper termination of the hash - * 4. All members have a non-null h_meta - */ -void hfs_vhash_dbg(hp) - struct hfsnode *hp; -{ - struct proc *p = current_proc(); /* XXX */ - struct vnode *vp; - struct hfsnode *thp, *tthp; - int maxsiblings = 1; - int wasFound = false; - struct vhashhead *ipp, *jpp; - dev_t dev = H_DEV(hp); - UInt32 nodeID = H_FILEID(hp); - UInt8 forkType = H_FORKTYPE(hp); - u_long forksfound = 0; - - if (forkType==kDataFork || forkType==kRsrcFork) - maxsiblings++; - - if (hp == NULL) - DEBUG_BREAK_MSG(("hash_dgh: Null hfsnode")); - /* - * Go through the hash list - * If a vnode is in the process of being cleaned out or being - * allocated, wait for it to be finished and then try again - */ - ipp = HFSNODEHASH(dev, nodeID); - -loop: - simple_lock(&hfs_vhash_slock); - for (thp = ipp->lh_first; thp; thp = thp->h_hash.le_next) { - if (thp->h_nodeflags & IN_ALLOCATING) { /* Its in the process of being allocated */ - simple_unlock(&hfs_vhash_slock); - tsleep((caddr_t)thp, PINOD, "hfs_vhash_ins_meta", 0); - goto loop; - }; - - if (thp->h_meta == NULL) - DEBUG_BREAK_MSG(("hash_dgh: Null hfs_meta")); - jpp = (HFSNODEHASH(H_DEV(thp), H_FILEID(thp))); - if (ipp != jpp) - DEBUG_BREAK_MSG(("hash_dgh: Member on wrong hash")); - - if ((H_FILEID(thp) == nodeID) && (H_DEV(thp) == dev)) { - maxsiblings--; - if (maxsiblings < 0) - DEBUG_BREAK_MSG(("hash_dgh: Too many siblings")); - if ((1<uio_iovcnt == 1 is violated - * and cleaned up call to uiomove to check space available first. - * 2-Jul-1999 Pat Dirks Fixed hfs_setattrlist to ignore attempts to set null volume name (#2331829). - * 18-May-1999 Don Brady Add support for rooting from HFS Plus. - * 4-May-1999 Don Brady Split off hfs_search.c - * 15-Apr-1999 Don Brady Change va_nlink back to 1 for directories in hfs_getattr. - * 6-Apr-1999 Don Brady Fix deference of NULL h_sibling in hfs_chid. - * 29-Mar-1999 Scott Roberts Put in the correct . and .. entries for readdir - * 22-Mar-1999 Don Brady Add UFS delete semantic support to hfs_remove. - * 1-Mar-1999 Scott Roberts h_meta is now released when the complex vnode is relesed - * 26-Feb-1999 Pat Dirks (copied by Chw) Fixed hfs_lookup to check for - * error return on vget. - * 25-Feb-1999 Pat Dirks Fixed hfs_remove to use a local copy of the h_sibling pointer around vnode_uncache. - * 3-Feb-1999 Pat Dirks Changed to stop updating wrapper volume name in MDB since wrapper volume's - * catalog isn't updated and this inconsistency trips Disk First Aid's checks. - * 22-Jan-1999 Pat Dirks Changed hfs_rename, hfs_remove, and hfs_rmdir to call cache_purge. - * 22-Jan-1999 Don Brady After calling hfsMoveRename call hfs_getcatalog to get new name. - * 12-Jan-1999 Don Brady Fixed the size of ATTR_CMN_NAME buffer to NAME_MAX + 1. - * 8-Jan-1999 Pat Dirks Added hfs_writepermission and change hfs_setattrlist to use it instead of - * including an incorrect derivative of hfs_access in-line. - * 15-Dec-1998 Pat Dirks Changed setattrlist to do permission checking as appropriate (Radar #2290212). - * 17-Nov-1998 Scott Roberts Added support for long volume names in SetAttrList(). - * 6-Nov-1998 Don Brady Add support for UTF-8 names. - * 3-Nov-1998 Umesh Vaishampayan Changes to deal with "struct timespec" - * change in the kernel. - * 21-Oct-1998 Scott Roberts Added support for advisory locking (Radar #2237914). - * 25-Sep-1998 Don Brady Changed hfs_exchange to call hfs_chid after updating catalog (radar #2276605). - * 23-Sep-1998 Don Brady hfs_setattrlist now calls hfs_chown and hfs_chmod to change values. - * 15-Sep-1998 Pat Dirks Cleaned up vnode unlocking on various error exit paths and changed - * to use new error stub routines in place of hfs_mknod and hfs_link. - * 16-Sep-1998 Don Brady When renaming a volume in hfs_setattrlist, also update hfs+ wrapper name (radar #2272925). - * 1-Sep-1998 Don Brady Fix uninitiazed time variable in hfs_makenode (radar #2270372). - * 31-Aug-1998 Don Brady Adjust change time for DST in hfs_update (radar #2265075). - * 12-Aug-1998 Don Brady Update complex node name in hfs_rename (radar #2262111). - * 5-Aug-1998 Don Brady In hfs_setattrlist call MacToVFSError after calling UpdateCatalogNode (radar #2261247). - * 21-Jul-1998 Don Brady Fixed broken preflight in hfs_getattrlist. - * 17-Jul-1998 Clark Warner Fixed the one left out case of freeing M_NAMEI in hfs_abort - * 13-Jul-1998 Don Brady Add uio_resid preflight check to hfs_search (radar #2251855). - * 30-Jun-1998 Scott Roberts Changed hfs_makenode and its callers to free M_NAMEI. - * 29-Jun-1998 Don Brady Fix unpacking order in UnpackSearchAttributeBlock (radar #2249248). - * 13-Jun-1998 Scott Roberts Integrated changes to hfs_lock (radar #2237243). - * 4-Jun-1998 Pat Dirks Split off hfs_lookup.c and hfs_readwrite.c - * 3-Jun-1998 Don Brady Fix hfs_rename bugs (radar #2229259, #2239823, 2231108 and #2237380). - * Removed extra vputs in hfs_rmdir (radar #2240309). - * 28-May-1998 Don Brady Fix hfs_truncate to correctly extend files (radar #2237242). - * 20-May-1998 Don Brady In hfs_close shrink the peof to the smallest size neccessary (radar #2230094). - * 5-May-1998 Don Brady Fixed typo in hfs_rename (apply H_FILEID macro to VTOH result). - * 29-Apr-1998 Joe Sokol Don't do cluster I/O when logical block size is not 4K multiple. - * 28-Apr-1998 Pat Dirks Cleaned up unused variable physBlockNo in hfs_write. - * 28-Apr-1998 Joe Sokol Touched up support for cluster_read/cluster_write and enabled it. - * 27-Apr-1998 Don Brady Remove some DEBUG_BREAK calls in DbgVopTest. - * 24-Apr-1998 Pat Dirks Fixed read logic to read-ahead only ONE block, and of only logBlockSize instead of 64K... - * Added calls to brelse() on errors from bread[n](). - * Changed logic to add overall length field to AttrBlockSize only on attribute return operations. - * 23-Apr-1998 Don Brady The hfs_symlink call is only supported on HFS Plus disks. - * 23-Apr-1998 Deric Horn Fixed hfs_search bug where matches were skipped when buffer was full. - * 22-Apr-1998 Scott Roberts Return on error if catalog mgr returns an error in truncate. - * 21-Apr-1998 Don Brady Fix up time/date conversions. - * 20-Apr-1998 Don Brady Remove course-grained hfs metadata locking. - * 17-Apr-1998 Pat Dirks Officially enabled searchfs in vops table. - * 17-Apr-1998 Deric Horn Bug fixes to hfs_search, reenabled searchfs trap for upcoming kernel build. - * 15-Apr-1998 Don Brady Add locking for HFS B-trees. Don't lock file meta lock for VSYSTEM files. - * Don't call VOP_UPDATE for system files. Roll set_time into hfs_update. - * 14-Apr-1998 Pat Dirks Cleaned up fsync to skip complex nodes and not hit sibling nodes. - * 14-Apr-1998 Deric Horn Added hfs_search() and related routines for searchfs() support. - * 14-Apr-1998 Scott Roberts Fixed paramaters to ExchangeFileIDs() - * 13-Apr-1998 Pat Dirks Changed to update H_HINT whenever hfs_getcatalog was called. - * 8-Apr-1998 Pat Dirks Added page-in and page-out passthrough routines to keep MapFS happy. - * 6-Apr-1998 Pat Dirks Changed hfs_write to clean up code and fix bug that caused - * zeroes to be interspersed in data. Added debug printf to hfs_read. - * 6-Apr-1998 Scott Roberts Added complex file support. - * 02-apr-1998 Don Brady UpdateCatalogNode now takes parID and name as input. - * 31-mar-1998 Don Brady Sync up with final HFSVolumes.h header file. - * 27-mar-1998 Don Brady Check result from UFSToHFSStr to make sure hfs/hfs+ names are not greater than 31 characters. - * 27-mar-1998 chw minor link fixes. - * 19-Mar-1998 ser Added hfs_readdirattr. - * 17-Mar-1998 ser Removed CheckUserAccess. Added code to implement ExchangeFileIDs - * 16-Mar-1998 Pat Dirks Fixed logic in hfs_read to properly account for space - * remaining past selected offset and avoid premature panic. - * 16-jun-1997 Scott Roberts - * Dec-1991 Kevin Wells at NeXT: - * Significantly modified for Macintosh file system. - * Added support for NFS exportability. - * 25-Jun-1990 Doug Mitchell at NeXT: - * Created (for DOS file system). - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include "hfs.h" -#include "hfs_lockf.h" -#include "hfs_dbg.h" -#include "hfs_mount.h" - -#include "hfscommon/headers/CatalogPrivate.h" -#include "hfscommon/headers/BTreesInternal.h" -#include "hfscommon/headers/FileMgrInternal.h" -#include "hfscommon/headers/HFSUnicodeWrappers.h" - -#define OWNERSHIP_ONLY_ATTRS (ATTR_CMN_OWNERID | ATTR_CMN_GRPID | ATTR_CMN_ACCESSMASK | ATTR_CMN_FLAGS) - -#define MAKE_DELETED_NAME(NAME,FID) \ - (void) sprintf((NAME), "%s%d", HFS_DELETE_PREFIX, (FID)) - - -extern uid_t console_user; - -/* Global vfs data structures for hfs */ -int (**hfs_vnodeop_p)(void *); - -/* external routines defined in hfs_vhash.c */ -extern void hfs_vhashrem(struct hfsnode *hp); -extern int vinvalbuf_vhash(register struct vnode *vp, int flags, struct ucred *cred, struct proc *p); -extern void hfs_vhashmove( struct hfsnode *hp,UInt32 nodeID); -extern struct vnode * hfs_vhashget(dev_t dev, UInt32 nodeID, UInt8 forkType); - -extern OSErr PositionIterator(CatalogIterator *cip, UInt32 offset, BTreeIterator *bip, UInt16 *op); - -extern void hfs_name_CatToMeta(CatalogNodeData *nodeData, struct hfsfilemeta *fm); - -extern groupmember(gid_t gid, struct ucred *cred); - -extern void hfs_resolvelink(ExtendedVCB *vcb, CatalogNodeData *cndp); - -static int hfs_makenode( int mode, - dev_t rawdev, struct vnode *dvp, struct vnode **vpp, - struct componentname *cnp, struct proc *p); - -static void hfs_chid(struct hfsnode *hp, u_int32_t fid, u_int32_t pid, char* name); - -static int hfs_write_access(struct vnode *vp, struct ucred *cred, struct proc *p, Boolean considerFlags); - -static int hfs_chown( struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred, struct proc *p); -static int hfs_chmod( struct vnode *vp, int mode, struct ucred *cred, struct proc *p); -static int hfs_chflags( struct vnode *vp, u_long flags, struct ucred *cred, struct proc *p); - - -int hfs_cache_lookup(); /* in hfs_lookup.c */ -int hfs_lookup(); /* in hfs_lookup.c */ -int hfs_read(); /* in hfs_readwrite.c */ -int hfs_write(); /* in hfs_readwrite.c */ -int hfs_ioctl(); /* in hfs_readwrite.c */ -int hfs_select(); /* in hfs_readwrite.c */ -int hfs_mmap(); /* in hfs_readwrite.c */ -int hfs_seek(); /* in hfs_readwrite.c */ -int hfs_bmap(); /* in hfs_readwrite.c */ -int hfs_strategy(); /* in hfs_readwrite.c */ -int hfs_reallocblks(); /* in hfs_readwrite.c */ -int hfs_truncate(); /* in hfs_readwrite.c */ -int hfs_allocate(); /* in hfs_readwrite.c */ -int hfs_pagein(); /* in hfs_readwrite.c */ -int hfs_pageout(); /* in hfs_readwrite.c */ -int hfs_search(); /* in hfs_search.c */ -int hfs_bwrite(); /* in hfs_readwrite.c */ -int hfs_link(); /* in hfs_link.c */ -int hfs_blktooff(); /* in hfs_readwrite.c */ -int hfs_offtoblk(); /* in hfs_readwrite.c */ -int hfs_cmap(); /* in hfs_readwrite.c */ - -/***************************************************************************** -* -* Operations on vnodes -* -*****************************************************************************/ - -/* - * Create a regular file -#% create dvp L U U -#% create vpp - L - -# - vop_create { - IN WILLRELE struct vnode *dvp; - OUT struct vnode **vpp; - IN struct componentname *cnp; - IN struct vattr *vap; - - We are responsible for freeing the namei buffer, - it is done in hfs_makenode() -*/ - -static int -hfs_create(ap) -struct vop_create_args /* { - struct vnode *a_dvp; - struct vnode **a_vpp; - struct componentname *a_cnp; - struct vattr *a_vap; -} */ *ap; -{ - struct proc *p = current_proc(); - int retval; - int mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode); - DBG_FUNC_NAME("create"); - DBG_VOP_LOCKS_DECL(2); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_PRINT_VNODE_INFO(ap->a_dvp); - DBG_VOP_PRINT_CPN_INFO(ap->a_cnp); - - DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); - DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_POS); - DBG_VOP_CONT(("\tva_type %d va_mode 0x%x\n", - ap->a_vap->va_type, ap->a_vap->va_mode)); - -#if HFS_DIAGNOSTIC - DBG_HFS_NODE_CHECK(ap->a_dvp); - DBG_ASSERT(ap->a_dvp->v_type == VDIR); - if(ap->a_vap == NULL) { - panic("NULL attr on create"); - } - - switch(ap->a_vap->va_type) { - case VDIR: - VOP_ABORTOP(ap->a_dvp, ap->a_cnp); - vput(ap->a_dvp); - DBG_VOP_LOCKS_TEST(EISDIR); - return (EISDIR); /* use hfs_mkdir instead */ - case VREG: - case VLNK: - break; - default: - DBG_ERR(("%s: INVALID va_type: %d, %s, %s\n", funcname, ap->a_vap->va_type, H_NAME(VTOH(ap->a_dvp)), ap->a_cnp->cn_nameptr)); - VOP_ABORTOP(ap->a_dvp, ap->a_cnp); - vput(ap->a_dvp); - DBG_VOP_LOCKS_TEST(EINVAL); - return (EINVAL); - } -// if(ap->a_vap->va_mode & (VSUID | VSGID | VSVTX)) { -// DBG_ERR(("%s: INVALID va_mode (%o): %s, %s\n", funcname, ap->a_vap->va_mode, H_NAME(VTOH(ap->a_dvp)), ap->a_cnp->cn_nameptr)); -// DBG_VOP_LOCKS_TEST(EINVAL); -// VOP_ABORTOP(ap->a_dvp, ap->a_cnp); -// vput(ap->a_dvp); -// return (EINVAL); /* Can't do these */ -// }; -#endif - - /* Create the vnode */ - retval = hfs_makenode(mode, 0, ap->a_dvp, ap->a_vpp, ap->a_cnp, p); - DBG_VOP_UPDATE_VP(1, *ap->a_vpp); - - if (retval != E_NONE) { - DBG_ERR(("%s: hfs_makenode FAILED: %s, %s\n", funcname, ap->a_cnp->cn_nameptr, H_NAME(VTOH(ap->a_dvp)))); - } - DBG_VOP_LOCKS_TEST(retval); - return (retval); -} - - -/* - * Mknod vnode call - -#% mknod dvp L U U -#% mknod vpp - X - -# - vop_mknod { - IN WILLRELE struct vnode *dvp; - OUT WILLRELE struct vnode **vpp; - IN struct componentname *cnp; - IN struct vattr *vap; - */ -/* ARGSUSED */ - -static int -hfs_mknod(ap) -struct vop_mknod_args /* { - struct vnode *a_dvp; - struct vnode **a_vpp; - struct componentname *a_cnp; - struct vattr *a_vap; -} */ *ap; -{ - struct vattr *vap = ap->a_vap; - struct vnode **vpp = ap->a_vpp; - struct proc *p = current_proc(); - dev_t rawdev = 0; - int error; - - if (VTOVCB(ap->a_dvp)->vcbSigWord != kHFSPlusSigWord) { - VOP_ABORTOP(ap->a_dvp, ap->a_cnp); - vput(ap->a_dvp); - return (EOPNOTSUPP); - } - - if (vap->va_rdev != VNOVAL) { - /* - * Want to be able to use this to make badblock - * inodes, so don't truncate the dev number. - */ - rawdev = vap->va_rdev; - } - - /* Create the vnode */ - error = hfs_makenode(MAKEIMODE(vap->va_type, vap->va_mode), - rawdev, ap->a_dvp, vpp, ap->a_cnp, p); - - if (error != E_NONE) { - return (error); - } - - /* - * Remove inode so that it will be reloaded by lookup and - * checked to see if it is an alias of an existing vnode. - * Note: unlike UFS, we don't bash v_type here. - */ - vput(*vpp); - vgone(*vpp); - *vpp = 0; - return (0); -} - - -/* - * mkcomplex vnode call - * - -#% mkcomplex dvp L U U -#% mkcomplex vpp - L - -# -vop_mkcomplex { - IN WILLRELE struct vnode *dvp; - OUT struct vnode **vpp; - IN struct componentname *cnp; - IN struct vattr *vap; - IN u_long type; -} - - */ - -static int -hfs_mkcomplex(ap) -struct vop_mkcomplex_args /* { - struct vnode *a_dvp; - struct vnode **a_vpp; - struct componentname *a_cnp; - struct vattr *a_vap; - u_long a_type; -} */ *ap; -{ - int retval = E_NONE; - DBG_FUNC_NAME("make_complex"); - DBG_VOP_LOCKS_DECL(2); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_PRINT_VNODE_INFO(ap->a_dvp); - DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n")); - - DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); - DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_POS); - - retval = VOP_CREATE(ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap); - - DBG_VOP_LOCKS_TEST(retval); - return retval; -} - - -/* - * Open called. -#% open vp L L L -# - vop_open { - IN struct vnode *vp; - IN int mode; - IN struct ucred *cred; - IN struct proc *p; - */ - - -static int -hfs_open(ap) -struct vop_open_args /* { - struct vnode *a_vp; - int a_mode; - struct ucred *a_cred; - struct proc *a_p; -} */ *ap; -{ - struct hfsnode *hp = VTOH(ap->a_vp); - int retval = E_NONE; - DBG_FUNC_NAME("open"); - DBG_VOP_LOCKS_DECL(1); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_CONT((" "));DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); - DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS); - - if (ap->a_vp->v_type == VREG) /* Only files */ - { - /* - * Files marked append-only must be opened for appending. - */ - if ((hp->h_meta->h_pflags & APPEND) && - (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE) - retval = EPERM; - } - - - DBG_VOP_LOCKS_TEST(retval); - return (retval); -} - -/* - * Close called. - * - * Update the times on the hfsnode. -#% close vp U U U -# - vop_close { - IN struct vnode *vp; - IN int fflag; - IN struct ucred *cred; - IN struct proc *p; - */ - - -static int -hfs_close(ap) -struct vop_close_args /* { - struct vnode *a_vp; - int a_fflag; - struct ucred *a_cred; - struct proc *a_p; -} */ *ap; -{ - register struct vnode *vp = ap->a_vp; - struct hfsnode *hp = VTOH(vp); - struct proc *p = ap->a_p; - FCB *fcb; - struct timeval tv; - off_t leof; - u_long blks, blocksize; - int retval = E_NONE; - int devBlockSize; - int forceUpdate = 0; - - DBG_FUNC_NAME("close"); - DBG_VOP_LOCKS_DECL(1); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_CONT((" "));DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); - DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); - - simple_lock(&vp->v_interlock); - if (vp->v_usecount > (UBCINFOEXISTS(vp) ? 2 : 1)) { - tv = time; - HFSTIMES(hp, &tv, &tv); - } - simple_unlock(&vp->v_interlock); - - /* - * VOP_CLOSE can be called with vp locked (from vclean). - * We check for this case using VOP_ISLOCKED and bail. - * - * also, ignore complex nodes; there's no data associated with them. - */ - if (H_FORKTYPE(hp) == kDirectory || VOP_ISLOCKED(vp)) { - DBG_VOP_LOCKS_TEST(E_NONE); - return E_NONE; - }; - - fcb = HTOFCB(hp); - leof = fcb->fcbEOF; - - if (leof != 0) { - enum vtype our_type = vp->v_type; - u_long our_id = vp->v_id; - - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - /* - * Since we can context switch in vn_lock our vnode - * could get recycled (eg umount -f). Double check - * that its still ours. - */ - if (vp->v_type != our_type || vp->v_id != our_id) { - VOP_UNLOCK(vp, 0, p); - DBG_VOP_LOCKS_TEST(E_NONE); - return(E_NONE); - } - - /* Last chance to explicitly zero out the areas that are currently marked invalid: */ - VOP_DEVBLOCKSIZE(hp->h_meta->h_devvp, &devBlockSize); - while (!CIRCLEQ_EMPTY(&hp->h_invalidranges)) { - struct rl_entry *invalid_range = CIRCLEQ_FIRST(&hp->h_invalidranges); - off_t start = invalid_range->rl_start; - off_t end = invalid_range->rl_end; - - /* The range about to be written must be validated first, so that - VOP_CMAP() will return the appropriate mapping for the cluster code: */ - rl_remove(start, end, &hp->h_invalidranges); - - retval = cluster_write(vp, (struct uio *) 0, fcb->fcbEOF, invalid_range->rl_end + 1, invalid_range->rl_start, - (off_t)0, devBlockSize, IO_HEADZEROFILL | 0x8000); - - forceUpdate = 1; - }; - /* Make sure the EOF gets written out at least once more - now that all invalid ranges have been zero-filled and validated: */ - if (forceUpdate) hp->h_nodeflags |= IN_MODIFIED; - - blocksize = HTOVCB(hp)->blockSize; - blks = leof / blocksize; - if (((off_t)blks * (off_t)blocksize) != leof) - blks++; - - /* - * Shrink the peof to the smallest size neccessary to contain the leof. - */ - if (((off_t)blks * (off_t)blocksize) < fcb->fcbPLen) { - retval = VOP_TRUNCATE(vp, leof, IO_NDELAY, ap->a_cred, p); - } - cluster_push(vp); - - /* If the VOP_TRUNCATE didn't happen to flush the vnode's information out to - disk, force it to be updated now that all invalid ranges have been zero-filled - and validated: - */ - if (hp->h_nodeflags & IN_MODIFIED) VOP_UPDATE(vp, &time, &time, 0); - - VOP_UNLOCK(vp, 0, p); - } - - DBG_VOP_LOCKS_TEST(retval); - return (retval); -} - -/* -#% access vp L L L -# - vop_access { - IN struct vnode *vp; - IN int mode; - IN struct ucred *cred; - IN struct proc *p; - - */ - -static int -hfs_access(ap) -struct vop_access_args /* { - struct vnode *a_vp; - int a_mode; - struct ucred *a_cred; - struct proc *a_p; -} */ *ap; -{ - struct vnode *vp = ap->a_vp; - struct ucred *cred = ap->a_cred; - struct hfsnode *hp = VTOH(vp); - ExtendedVCB *vcb = HTOVCB(hp); - register gid_t *gp; - mode_t mask, mode; - Boolean isHFSPlus; - int retval = E_NONE; - int i; - DBG_FUNC_NAME("access"); - DBG_VOP_LOCKS_DECL(1); -// DBG_VOP_PRINT_FUNCNAME(); -// DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); - - DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS); - - mode = ap->a_mode; - isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord ); - - /* - * Disallow write attempts on read-only file systems; - * unless the file is a socket, fifo, or a block or - * character device resident on the file system. - */ - if (mode & VWRITE) { - switch (vp->v_type) { - case VDIR: - case VLNK: - case VREG: - if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) - return (EROFS); - break; - default: - break; - } - } - - /* If immutable bit set, nobody gets to write it. */ - if ((mode & VWRITE) && (hp->h_meta->h_pflags & IMMUTABLE)) - return (EPERM); - - /* Otherwise, user id 0 always gets access. */ - if (ap->a_cred->cr_uid == 0) { - retval = 0; - goto Exit; - }; - - mask = 0; - - /* Otherwise, check the owner. */ - if (hfs_owner_rights(vp, cred, ap->a_p, false) == 0) { - if (mode & VEXEC) - mask |= S_IXUSR; - if (mode & VREAD) - mask |= S_IRUSR; - if (mode & VWRITE) - mask |= S_IWUSR; - retval = ((hp->h_meta->h_mode & mask) == mask ? 0 : EACCES); - goto Exit; - } - - /* Otherwise, check the groups. */ - if (! (VTOVFS(vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS)) { - for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++) { - if (hp->h_meta->h_gid == *gp) { - if (mode & VEXEC) - mask |= S_IXGRP; - if (mode & VREAD) - mask |= S_IRGRP; - if (mode & VWRITE) - mask |= S_IWGRP; - retval = ((hp->h_meta->h_mode & mask) == mask ? 0 : EACCES); - goto Exit; - } - }; - }; - - /* Otherwise, check everyone else. */ - if (mode & VEXEC) - mask |= S_IXOTH; - if (mode & VREAD) - mask |= S_IROTH; - if (mode & VWRITE) - mask |= S_IWOTH; - retval = ((hp->h_meta->h_mode & mask) == mask ? 0 : EACCES); - -Exit: - DBG_VOP_LOCKS_TEST(retval); - return (retval); -} - - - -/* -#% getattr vp = = = -# - vop_getattr { - IN struct vnode *vp; - IN struct vattr *vap; - IN struct ucred *cred; - IN struct proc *p; - - */ - - -/* ARGSUSED */ -static int -hfs_getattr(ap) -struct vop_getattr_args /* { - struct vnode *a_vp; - struct vattr *a_vap; - struct ucred *a_cred; - struct proc *a_p; -} */ *ap; -{ - register struct vnode *vp = ap->a_vp; - register struct hfsnode *hp = VTOH(vp); - register struct vattr *vap = ap->a_vap; - struct timeval tv; - DBG_FUNC_NAME("getattr"); - DBG_VOP_LOCKS_DECL(1); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); - - DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_POS); - - DBG_HFS_NODE_CHECK(ap->a_vp); - - tv = time; - HFSTIMES(hp, &tv, &tv); - - vap->va_fsid = H_DEV(hp); - vap->va_fileid = H_FILEID(hp); - vap->va_mode = hp->h_meta->h_mode; - if (VTOVFS(vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) { - vap->va_uid = (VTOHFS(vp)->hfs_uid == UNKNOWNUID) ? console_user : VTOHFS(vp)->hfs_uid; - } else { - vap->va_uid = (hp->h_meta->h_uid == UNKNOWNUID) ? console_user : hp->h_meta->h_uid; - }; - vap->va_gid = hp->h_meta->h_gid; - if (vp->v_type == VDIR) { - vap->va_size = hp->h_meta->h_size; - vap->va_bytes = 0; - vap->va_rdev = 0; - vap->va_nlink = hp->h_meta->h_nlink; - /* - * account for hidden data nodes directory - */ - if ((H_FILEID(hp) == kRootDirID) && - (VTOHFS(vp)->hfs_private_metadata_dir != 0)) { - vap->va_size -= AVERAGE_HFSDIRENTRY_SIZE; - vap->va_nlink--; - } - } - else { - vap->va_size = hp->fcbEOF; - vap->va_bytes = hp->h_meta->h_size; - - if (vp->v_type == VBLK || vp->v_type == VCHR) - vap->va_rdev = hp->h_meta->h_rdev; - else - vap->va_rdev = 0; - - if (hp->h_meta->h_metaflags & IN_DELETED) - vap->va_nlink = 0; -#if HFS_HARDLINKS - else if ((hp->h_meta->h_metaflags & IN_DATANODE) && - (hp->h_meta->h_nlink > 0)) - vap->va_nlink = hp->h_meta->h_nlink; -#endif - else - vap->va_nlink = 1; - - } - - vap->va_atime.tv_nsec = 0; - vap->va_atime.tv_sec = hp->h_meta->h_atime; - vap->va_mtime.tv_nsec = 0; - vap->va_mtime.tv_sec = hp->h_meta->h_mtime; - vap->va_ctime.tv_nsec = 0; - vap->va_ctime.tv_sec = hp->h_meta->h_ctime; - vap->va_flags = hp->h_meta->h_pflags; - vap->va_gen = 0; - /* this doesn't belong here */ - if (vp->v_type == VBLK) - vap->va_blocksize = BLKDEV_IOSIZE; - else if (vp->v_type == VCHR) - vap->va_blocksize = MAXPHYSIO; - else - vap->va_blocksize = VTOVFS(vp)->mnt_stat.f_iosize; - vap->va_type = vp->v_type; - vap->va_filerev = 0; - - DBG_VOP_LOCKS_TEST(E_NONE); - return (E_NONE); -} - -/* - * Set attribute vnode op. called from several syscalls -#% setattr vp L L L -# - vop_setattr { - IN struct vnode *vp; - IN struct vattr *vap; - IN struct ucred *cred; - IN struct proc *p; - - */ - -static int -hfs_setattr(ap) -struct vop_setattr_args /* { -struct vnode *a_vp; -struct vattr *a_vap; -struct ucred *a_cred; -struct proc *a_p; -} */ *ap; -{ - struct vnode *vp = ap->a_vp; - struct hfsnode *hp = VTOH(vp); - struct vattr *vap = ap->a_vap; - struct ucred *cred = ap->a_cred; - struct proc *p = ap->a_p; - struct timeval atimeval, mtimeval; - int retval; - DBG_FUNC_NAME("setattr"); - DBG_VOP_LOCKS_DECL(1); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); - DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS); - WRITE_CK(vp, funcname); - DBG_HFS_NODE_CHECK(ap->a_vp); - - /* - * Check for unsettable 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)) { - retval = EINVAL; - goto ErrorExit; - } - - if (vap->va_flags != VNOVAL) { - if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) { - retval = EROFS; - goto ErrorExit; - }; - if ((retval = hfs_chflags(vp, vap->va_flags, cred, p))) { - goto ErrorExit; - }; - if (vap->va_flags & (IMMUTABLE | APPEND)) { - retval = 0; - goto ErrorExit; - }; - } - - if (hp->h_meta->h_pflags & (IMMUTABLE | APPEND)) { - retval = EPERM; - goto ErrorExit; - }; - /* - * Go through the fields and update iff not VNOVAL. - */ - if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { - if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) { - retval = EROFS; - goto ErrorExit; - }; - if ((retval = hfs_chown(vp, vap->va_uid, vap->va_gid, cred, p))) { - goto ErrorExit; - }; - } - if (vap->va_size != VNOVAL) { - /* - * Disallow write attempts on read-only file systems; - * unless the file is a socket, fifo, or a block or - * character device resident on the file system. - */ - switch (vp->v_type) { - case VDIR: - retval = EISDIR; - goto ErrorExit; - case VLNK: - case VREG: - if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) { - retval = EROFS; - goto ErrorExit; - }; - break; - default: - break; - } - if ((retval = VOP_TRUNCATE(vp, vap->va_size, 0, cred, p))) { - goto ErrorExit; - }; - } - hp = VTOH(vp); - if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { - if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) { - retval = EROFS; - goto ErrorExit; - }; - if (((retval = hfs_owner_rights(vp, cred, p, true)) != 0) && - ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || - (retval = VOP_ACCESS(vp, VWRITE, cred, p)))) { - goto ErrorExit; - }; - if (vap->va_atime.tv_sec != VNOVAL) - hp->h_nodeflags |= IN_ACCESS; - if (vap->va_mtime.tv_sec != VNOVAL) { - hp->h_nodeflags |= IN_CHANGE | IN_UPDATE; - /* - * The utimes system call can reset the modification time - * but it doesn't know about the HFS+ create time. So we - * need to insure that the creation time is always at least - * as old as the modification time. - */ - if (( VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord ) && - ( H_FILEID(hp) != kRootDirID ) && - ( vap->va_mtime.tv_sec < hp->h_meta->h_crtime )) - hp->h_meta->h_crtime = vap->va_mtime.tv_sec; - } - atimeval.tv_sec = vap->va_atime.tv_sec; - atimeval.tv_usec = 0; - mtimeval.tv_sec = vap->va_mtime.tv_sec; - mtimeval.tv_usec = 0; - if ((retval = VOP_UPDATE(vp, &atimeval, &mtimeval, 1))) { - goto ErrorExit; - }; - } - retval = 0; - if (vap->va_mode != (mode_t)VNOVAL) { - if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) { - retval = EROFS; - goto ErrorExit; - }; - retval = hfs_chmod(vp, (int)vap->va_mode, cred, p); - }; - -ErrorExit: ; - - DBG_VOP(("hfs_setattr: returning %d...\n", retval)); - DBG_VOP_LOCKS_TEST(retval); - return (retval); -} - - -/* - -# -#% getattrlist vp = = = -# - vop_getattrlist { - IN struct vnode *vp; - IN struct attrlist *alist; - INOUT struct uio *uio; - IN struct ucred *cred; - IN struct proc *p; - }; - - */ - -static int -hfs_getattrlist(ap) -struct vop_getattrlist_args /* { -struct vnode *a_vp; -struct attrlist *a_alist -struct uio *a_uio; -struct ucred *a_cred; -struct proc *a_p; -} */ *ap; -{ - struct vnode *vp = ap->a_vp; - struct hfsnode *hp = VTOH(vp); - struct attrlist *alist = ap->a_alist; - int error = 0; - struct hfsCatalogInfo catInfo; - struct hfsCatalogInfo *catInfoPtr = NULL; - struct timeval tv; - int fixedblocksize; - int attrblocksize; - int attrbufsize; - void *attrbufptr; - void *attrptr; - void *varptr; - u_int32_t fileID; - DBG_FUNC_NAME("getattrlist"); - DBG_VOP_LOCKS_DECL(1); - - DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_POS); - DBG_HFS_NODE_CHECK(ap->a_vp); - DBG_VOP(("%s: Common attr:0x%lx, buff size Ox%lX,\n",funcname, (u_long)alist->commonattr,(u_long)ap->a_uio->uio_resid)); - - DBG_ASSERT(ap->a_uio->uio_rw == UIO_READ); - - if ((alist->bitmapcount != ATTR_BIT_MAP_COUNT) || - ((alist->commonattr & ~ATTR_CMN_VALIDMASK) != 0) || - ((alist->volattr & ~ATTR_VOL_VALIDMASK) != 0) || - ((alist->dirattr & ~ATTR_DIR_VALIDMASK) != 0) || - ((alist->fileattr & ~ATTR_FILE_VALIDMASK) != 0) || - ((alist->forkattr & ~ATTR_FORK_VALIDMASK) != 0)) { - DBG_ERR(("%s: bad attrlist\n", funcname)); - DBG_VOP_LOCKS_TEST(EINVAL); - return EINVAL; - }; - - /* Requesting volume information requires setting the ATTR_VOL_INFO bit and - volume info requests are mutually exclusive with all other info requests: */ - if ((alist->volattr != 0) && (((alist->volattr & ATTR_VOL_INFO) == 0) || - (alist->dirattr != 0) || (alist->fileattr != 0) || (alist->forkattr != 0) - )) { - DBG_ERR(("%s: conflicting information requested\n", funcname)); - DBG_VOP_LOCKS_TEST(EINVAL); - return EINVAL; - }; - - /* Reject requests for unsupported options for now: */ - if ((alist->commonattr & (ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST)) || - (alist->fileattr & (ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | ATTR_FILE_FORKLIST))) { - DBG_ERR(("%s: illegal bits in attlist\n", funcname)); - DBG_VOP_LOCKS_TEST(EINVAL); - return EINVAL; - }; - - /* Requesting volume information requires root vnode */ - if ((alist->volattr) && (H_FILEID(hp) != kRootDirID)) { - DBG_ERR(("%s: not root vnode\n", funcname)); - DBG_VOP_LOCKS_TEST(EINVAL); - return EINVAL; - }; - - - /* Update times if needed */ - tv = time; - HFSTIMES(hp, &tv, &tv); - - /* If a FileID (ATTR_CMN_OBJPERMANENTID) is requested on an HFS volume we must be sure - to create the thread record before returning it: - */ - if ((vp->v_type == VREG) && - (alist->commonattr & ATTR_CMN_OBJPERMANENTID)) { - /* Only HFS-Plus volumes are guaranteed to have a thread record in place already: */ - if (VTOVCB(vp)->vcbSigWord != kHFSPlusSigWord) { - /* Create a thread record and return the FileID [which is the file's fileNumber] */ - /* lock catalog b-tree */ - error = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_EXCLUSIVE, ap->a_p); - error = hfsCreateFileID(VTOVCB(vp), H_DIRID(hp), H_NAME(hp), H_HINT(hp), &fileID); - (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, ap->a_p); - if (error) { - DBG_VOP_LOCKS_TEST(error); - DBG_ERR(("hfs_getattrlist: error %d on CreateFileIDRef.\n", error)); - return error; - }; - DBG_ASSERT(fileID == H_FILEID(hp)); - }; - }; - - /* Asking for data fork attributes from the rsrc fork is not supported */ - if ((H_FORKTYPE(hp) == kRsrcFork) && (alist->fileattr & HFS_ATTR_FILE_LOOKUPMASK)) { - return (EINVAL); - } - - /* - * Avoid unnecessary catalog lookups for volume info which is available directly - * in the VCB and root vnode, or can be synthesized. - */ - INIT_CATALOGDATA(&catInfo.nodeData, 0); - catInfo.hint = kNoHint; - - if (((alist->volattr == 0) && ((alist->commonattr & HFS_ATTR_CMN_LOOKUPMASK) != 0)) || - ((alist->dirattr & HFS_ATTR_DIR_LOOKUPMASK) != 0) || - ((alist->fileattr & HFS_ATTR_FILE_LOOKUPMASK) != 0) || - ((alist->commonattr & (ATTR_CMN_OBJID | ATTR_CMN_OBJPERMANENTID)) - && (hp->h_meta->h_metaflags & IN_DATANODE))) { - - /* lock catalog b-tree */ - error = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_SHARED, ap->a_p); - if (error) goto GetCatalogErr_Exit; - - if (alist->volattr != 0) { - /* Look up the root info, regardless of the vnode provided */ - error = hfs_getcatalog(VTOVCB(vp), 2, NULL, -1, &catInfo); - } else { - error = hfs_getcatalog(VTOVCB(vp), H_DIRID(hp), H_NAME(hp), -1, &catInfo); - if (error == 0) H_HINT(hp) = catInfo.hint; /* Remember the last valid hint */ - }; - - /* unlock catalog b-tree */ - (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, ap->a_p); - - /* - * If a data fork has an active sibling and we need - * rsrc fork attributes then we need to lock the - * sibling and make a copy of its attributes. - */ - if ((hp->h_meta->h_usecount > 1) && - (H_FORKTYPE(hp) == kDataFork) && - (alist->fileattr & HFS_ATTR_FILE_LOOKUPMASK)) { - struct vnode *sib_vp = NULL; - struct hfsnode *nhp; - struct proc *p = current_proc(); - - DBG_ASSERT(hp->h_meta->h_siblinghead.cqh_first && - (hp->h_meta->h_siblinghead.cqh_first != hp->h_meta->h_siblinghead.cqh_last)); - DBG_ASSERT(H_FORKTYPE(hp)==kDataFork || H_FORKTYPE(hp)==kRsrcFork); - - /* Loop through all siblings, skipping ourselves */ - simple_lock(&hp->h_meta->h_siblinglock); - CIRCLEQ_FOREACH(nhp, &hp->h_meta->h_siblinghead, h_sibling) { - if (nhp == hp) /* skip ourselves */ - continue; - sib_vp = HTOV(nhp); - }; - simple_unlock(&hp->h_meta->h_siblinglock); - - /* The only error that vget returns is when the vnode is going away, so ignore the vnode */ - if (vget(sib_vp, LK_EXCLUSIVE | LK_RETRY, p) == 0) { - if (VTOH(sib_vp)->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) { - /* XXX SER No need to copy the whole thing over, just copy the fork info */ - CopyVNodeToCatalogNode (sib_vp, &catInfo.nodeData); - }; - - vput(sib_vp); - }; /* vget() */ - }; /* h_use_count > 1 */ - - /* Update to the in-memory state, if it has been modified...just to make sure */ - if (VTOH(vp)->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) { - /* XXX SER No need to copy the whole thing over, just copy the fork info */ - CopyVNodeToCatalogNode (vp, &catInfo.nodeData); - }; - - /* XXX What if hfs_getcatalog fails...we just continue??? */ - catInfoPtr = &catInfo; - - }; - - fixedblocksize = AttributeBlockSize(alist); - attrblocksize = fixedblocksize + (sizeof(u_long)); /* u_long for length longword */ - if (alist->commonattr & ATTR_CMN_NAME) attrblocksize += kHFSPlusMaxFileNameBytes + 1; - if (alist->commonattr & ATTR_CMN_NAMEDATTRLIST) attrblocksize += 0; /* XXX PPD */ - if (alist->volattr & ATTR_VOL_MOUNTPOINT) attrblocksize += PATH_MAX; - if (alist->volattr & ATTR_VOL_NAME) attrblocksize += kHFSPlusMaxFileNameBytes + 1; - if (alist->fileattr & ATTR_FILE_FORKLIST) attrblocksize += 0; /* XXX PPD */ - - attrbufsize = MIN(ap->a_uio->uio_resid, attrblocksize); - DBG_VOP(("hfs_getattrlist: allocating Ox%X byte buffer (Ox%X + Ox%X) for attributes...\n", - attrblocksize, - fixedblocksize, - attrblocksize - fixedblocksize)); - MALLOC(attrbufptr, void *, attrblocksize, M_TEMP, M_WAITOK); - attrptr = attrbufptr; - *((u_long *)attrptr) = 0; /* Set buffer length in case of errors */ - ++((u_long *)attrptr); /* Reserve space for length field */ - varptr = ((char *)attrptr) + fixedblocksize; /* Point to variable-length storage */ - DBG_VOP(("hfs_getattrlist: attrptr = 0x%08X, varptr = 0x%08X...\n", (u_int)attrptr, (u_int)varptr)); - - PackAttributeBlock(alist, vp, catInfoPtr, &attrptr, &varptr); - attrbufsize = MIN(attrbufsize, (u_int)varptr - (u_int)attrbufptr); /* Don't copy out more data than was generated */ - *((u_long *)attrbufptr) = attrbufsize; /* Set actual buffer length for return to caller */ - DBG_VOP(("hfs_getattrlist: copying Ox%X bytes to user address 0x%08X.\n", attrbufsize, (u_int)ap->a_uio->uio_iov->iov_base)); - error = uiomove((caddr_t)attrbufptr, attrbufsize, ap->a_uio); - if (error != E_NONE) { - DBG_ERR(("hfs_getattrlist: error %d on uiomove.\n", error)); - }; - - FREE(attrbufptr, M_TEMP); - - -GetCatalogErr_Exit: - CLEAN_CATALOGDATA(&catInfo.nodeData); - DBG_VOP_LOCKS_TEST(error); - return error; -} - - - -/* - -# -#% setattrlist vp L L L -# - vop_setattrlist { - IN struct vnode *vp; - IN struct attrlist *alist; - INOUT struct uio *uio; - IN struct ucred *cred; - IN struct proc *p; - }; - - */ - -static int -hfs_setattrlist(ap) -struct vop_setattrlist_args /* { -struct vnode *a_vp; -struct attrlist *a_alist -struct uio *a_uio; -struct ucred *a_cred; -struct proc *a_p; -} */ *ap; -{ - struct vnode *vp = ap->a_vp; - struct hfsnode *hp = VTOH(vp); - struct attrlist *alist = ap->a_alist; - struct ucred *cred = ap->a_cred; - struct proc *p = ap->a_p; - int error; - struct hfsCatalogInfo catInfo; - int attrblocksize; - void *attrbufptr = NULL; - void *attrptr; - void *varptr = NULL; - uid_t saved_uid; - gid_t saved_gid; - mode_t saved_mode; - u_long saved_flags; - char * filename; - char iNodeName[32]; - u_int32_t pid; - int retval = 0; - - DBG_FUNC_NAME("setattrlist"); - DBG_VOP_LOCKS_DECL(1); - - DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_POS); - DBG_HFS_NODE_CHECK(ap->a_vp); - DBG_VOP(("%s: Common attr:0x%x, buff size Ox%X,\n",funcname, (u_int)alist->commonattr,(u_int)ap->a_uio->uio_resid)); - - DBG_ASSERT(ap->a_uio->uio_rw == UIO_WRITE); - - if ((alist->bitmapcount != ATTR_BIT_MAP_COUNT) || - ((alist->commonattr & ~ATTR_CMN_SETMASK) != 0) || - ((alist->volattr & ~ATTR_VOL_SETMASK) != 0) || - ((alist->dirattr & ~ATTR_DIR_SETMASK) != 0) || - ((alist->fileattr & ~ATTR_FILE_SETMASK) != 0) || - ((alist->forkattr & ~ATTR_FORK_SETMASK) != 0)) { - DBG_ERR(("%s: Bad attrlist\n", funcname)); - DBG_VOP_LOCKS_TEST(EINVAL); - return EINVAL; - }; - - if ((alist->volattr != 0) && /* Setting volume info */ - (((alist->volattr & ATTR_VOL_INFO) == 0) || /* Not explicitly indicating this or ... */ - (alist->commonattr & ~ATTR_CMN_VOLSETMASK))) /* ... setting invalid attributes for volume */ - { - DBG_ERR(("%s: Bad attrlist\n", funcname)); - DBG_VOP_LOCKS_TEST(EINVAL); - return EINVAL; - }; - - if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) { - DBG_VOP_LOCKS_TEST(EROFS); - return EROFS; - }; - - /* - Ownership of the file (in addition to write access, checked below, - is required in one of two classes of calls: - - (a) When setting any ownership-requiring attribute other than ATTR_CMN_FLAGS, or - (b) When setting ATTR_CMN_FLAGS on a volume that's not plain HFS (for which no - real per-object ownership information is stored): - */ - if ((alist->commonattr & (OWNERSHIP_ONLY_ATTRS & ~ATTR_CMN_FLAGS)) || - ((alist->commonattr & ATTR_CMN_FLAGS) && (VTOVCB(vp)->vcbSigWord != kHFSSigWord))) { - /* NOTE: The following isn't ENTIRELY complete: even if you're the superuser - you cannot change the flags as long as SF_IMMUTABLE or SF_APPEND is - set and securelevel > 0. This is verified in hfs_chflags which gets - invoked to do the actual flags field change so this check is sufficient - for now. - */ - /* Check to see if the user owns the object [or is superuser]: */ - if ((retval = hfs_owner_rights(vp, cred, p, true)) != 0) { - DBG_VOP_LOCKS_TEST(retval); - return retval; - }; - } else { - DBG_ASSERT(((alist->commonattr & OWNERSHIP_ONLY_ATTRS) == 0) || - (((alist->commonattr & OWNERSHIP_ONLY_ATTRS) == ATTR_CMN_FLAGS) && - (VTOVCB(vp)->vcbSigWord == kHFSSigWord))); - /* No ownership access is required: mere write access (checked below) will do... */ - }; - - /* For any other attributes, check to see if the user has write access to - the object in question [unlike VOP_ACCESS, ignore IMMUTABLE here]: */ - - if ((((alist->commonattr & ~(OWNERSHIP_ONLY_ATTRS)) != 0) || - (alist->volattr != 0) || - (alist->dirattr != 0) || - (alist->fileattr != 0) || - (alist->forkattr != 0)) && - ((retval = hfs_write_access(vp, cred, p, false)) != 0)) { - DBG_VOP_LOCKS_TEST(retval); - return retval; - }; /* end of if ownership attr */ - - /* Allocate the buffer now to minimize the time we might be blocked holding the catalog lock */ - attrblocksize = ap->a_uio->uio_resid; - if (attrblocksize < AttributeBlockSize(alist)) { - DBG_ERR(("%s: bad attrblocksize\n", funcname)); - DBG_VOP_LOCKS_TEST(EINVAL); - return EINVAL; - }; - - MALLOC(attrbufptr, void *, attrblocksize, M_TEMP, M_WAITOK); - - INIT_CATALOGDATA(&catInfo.nodeData, kCatNameNoCopyName); - catInfo.hint = kNoHint; - - filename = H_NAME(hp); - pid = H_DIRID(hp); - -#if HFS_HARDLINKS - /* - * Force an update of the indirect node instead of the link - * by using the name and parent of the indirect node. - */ - if (hp->h_meta->h_metaflags & IN_DATANODE) { - MAKE_INODE_NAME(iNodeName, hp->h_meta->h_indnodeno); - filename = iNodeName; - pid = VTOHFS(vp)->hfs_private_metadata_dir; - } -#endif - - /* lock catalog b-tree */ - error = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_EXCLUSIVE, p); - if (error != E_NONE) - goto ErrorExit; - - error = hfs_getcatalog(VTOVCB(vp), pid, filename, -1, &catInfo); - - /* unlock catalog b-tree */ - (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, p); - if (error != E_NONE) - goto ErrorExit; - - H_HINT(hp) = catInfo.hint; /* Remember the last valid hint */ - - error = uiomove((caddr_t)attrbufptr, attrblocksize, ap->a_uio); - if (error) goto ErrorExit; - - if ((alist->volattr) && (H_FILEID(hp) != kRootDirID)) { - error = EINVAL; - goto ErrorExit; - }; - - /* - * If we are going to change the times: - * 1. do we have permission to change the dates? - * 2. Is there another fork? If so then clear any flags associated with the times - */ - if (alist->commonattr & (ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | ATTR_CMN_ACCTIME)) { - if (alist->commonattr & (ATTR_CMN_CHGTIME | ATTR_CMN_ACCTIME)) { - if ((error = hfs_owner_rights(vp, cred, p, true)) != 0) - goto ErrorExit; - } - - /* If there is another fork, clear the flags */ - if ((hp->h_meta->h_usecount > 1) && (H_FORKTYPE(hp) == kDataFork)) { - struct vnode *sib_vp = NULL; - struct hfsnode *nhp; - - /* Loop through all siblings, skipping ourselves */ - simple_lock(&hp->h_meta->h_siblinglock); - CIRCLEQ_FOREACH(nhp, &hp->h_meta->h_siblinghead, h_sibling) { - if (nhp == hp) /* skip ourselves */ - continue; - sib_vp = HTOV(nhp); - } - simple_unlock(&hp->h_meta->h_siblinglock); - - /* - * The only error that vget returns is when the vnode is going away, - * so ignore the vnode - */ - if (sib_vp && vget(sib_vp, LK_EXCLUSIVE | LK_RETRY, p) == 0) { - if ((sib_vp->v_tag == VT_HFS) - && VTOH(sib_vp)->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) { - if (alist->commonattr & ATTR_CMN_MODTIME) - VTOH(sib_vp)->h_nodeflags &= ~IN_UPDATE; - if (alist->commonattr & ATTR_CMN_CHGTIME) - VTOH(sib_vp)->h_nodeflags &= ~IN_CHANGE; - if (alist->commonattr & ATTR_CMN_ACCTIME) - VTOH(sib_vp)->h_nodeflags &= ~IN_ACCESS; - } - vput(sib_vp); - } - } - } - - /* save these in case hfs_chown() or hfs_chmod() fail */ - saved_uid = hp->h_meta->h_uid; - saved_gid = hp->h_meta->h_gid; - saved_mode = hp->h_meta->h_mode; - saved_flags = hp->h_meta->h_pflags; - - attrptr = attrbufptr; - UnpackAttributeBlock(alist, vp, &catInfo, &attrptr, &varptr); - - /* if unpacking changed the owner or group then call hfs_chown() */ - if (saved_uid != hp->h_meta->h_uid || saved_gid != hp->h_meta->h_gid) { - uid_t uid; - gid_t gid; - - uid = hp->h_meta->h_uid; - hp->h_meta->h_uid = saved_uid; - gid = hp->h_meta->h_gid; - hp->h_meta->h_gid = saved_gid; - if ((error = hfs_chown(vp, uid, gid, cred, p))) - goto ErrorExit; - } - - /* if unpacking changed the mode then call hfs_chmod() */ - if (saved_mode != hp->h_meta->h_mode) { - mode_t mode; - - mode = hp->h_meta->h_mode; - hp->h_meta->h_mode = saved_mode; - if ((error = hfs_chmod(vp, mode, cred, p))) - goto ErrorExit; - }; - - /* if unpacking changed the flags then call hfs_chflags */ - if (saved_flags != hp->h_meta->h_pflags) { - u_long flags; - - flags = hp->h_meta->h_pflags; - hp->h_meta->h_pflags = saved_flags; - if ((error = hfs_chflags(vp, flags, cred, p))) - goto ErrorExit; - }; - - - /* lock catalog b-tree */ - error = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_EXCLUSIVE, p); - if (error != E_NONE) - goto ErrorExit; - - /* Update Catalog Tree */ - if (alist->volattr == 0) { - error = MacToVFSError( UpdateCatalogNode(HTOVCB(hp), pid, filename, H_HINT(hp), &catInfo.nodeData)); - } - - /* Volume Rename */ - if (alist->volattr & ATTR_VOL_NAME) { - ExtendedVCB *vcb = VTOVCB(vp); - int namelen = strlen(vcb->vcbVN); - - if (vcb->vcbVN[0] == 0) { - /* - * Ignore attempts to rename a volume to a zero-length name: - * restore the original name from the metadata. - */ - copystr(H_NAME(hp), vcb->vcbVN, sizeof(vcb->vcbVN), NULL); - } else { - UInt32 tehint = 0; - - /* - * Force Carbon renames to have MacUnicode encoding - */ - if ((hp->h_nodeflags & IN_BYCNID) && (!ISSET(p->p_flag, P_TBE))) { - tehint = kTextEncodingMacUnicode; - } - - error = MoveRenameCatalogNode(vcb, kRootParID, H_NAME(hp), H_HINT(hp), - kRootParID, vcb->vcbVN, &H_HINT(hp), tehint); - if (error) { - VCB_LOCK(vcb); - copystr(H_NAME(hp), vcb->vcbVN, sizeof(vcb->vcbVN), NULL); /* Restore the old name in the VCB */ - vcb->vcbFlags |= 0xFF00; // Mark the VCB dirty - VCB_UNLOCK(vcb); - goto UnlockExit; - }; - - hfs_set_metaname(vcb->vcbVN, hp->h_meta, HTOHFS(hp)); - hp->h_nodeflags |= IN_CHANGE; - - } /* vcb->vcbVN[0] == 0 ... else ... */ - } /* alist->volattr & ATTR_VOL_NAME */ - -UnlockExit: - /* unlock catalog b-tree */ - (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, p); - -ErrorExit: - - CLEAN_CATALOGDATA(&catInfo.nodeData); - - if (attrbufptr) FREE(attrbufptr, M_TEMP); - - DBG_VOP_LOCKS_TEST(error); - return error; -} - -/* - * Change the mode on a file. - * Inode must be locked before calling. - */ -static int -hfs_chmod(vp, mode, cred, p) -register struct vnode *vp; -register int mode; -register struct ucred *cred; -struct proc *p; -{ - register struct hfsnode *hp = VTOH(vp); - int retval; - - if (VTOVCB(vp)->vcbSigWord != kHFSPlusSigWord) - return E_NONE; - -#if OVERRIDE_UNKNOWN_PERMISSIONS - if (VTOVFS(vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) { - return E_NONE; - }; -#endif - - if ((retval = hfs_owner_rights(vp, cred, p, true)) != 0) - return (retval); - if (cred->cr_uid) { - if (vp->v_type != VDIR && (mode & S_ISTXT)) - return (EFTYPE); - if (!groupmember(hp->h_meta->h_gid, cred) && (mode & ISGID)) - return (EPERM); - } - hp->h_meta->h_mode &= ~ALLPERMS; - hp->h_meta->h_mode |= (mode & ALLPERMS); - hp->h_meta->h_metaflags &= ~IN_UNSETACCESS; - hp->h_nodeflags |= IN_CHANGE; - return (0); -} - - -static int -hfs_write_access(struct vnode *vp, struct ucred *cred, struct proc *p, Boolean considerFlags) -{ - struct hfsnode *hp = VTOH(vp); - ExtendedVCB *vcb = HTOVCB(hp); - gid_t *gp; - Boolean isHFSPlus; - int retval = E_NONE; - int i; - - isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord ); - - /* - * Disallow write attempts on read-only file systems; - * unless the file is a socket, fifo, or a block or - * character device resident on the file system. - */ - switch (vp->v_type) { - case VDIR: - case VLNK: - case VREG: - if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) - return (EROFS); - break; - default: - break; - } - - /* If immutable bit set, nobody gets to write it. */ - if (considerFlags && (hp->h_meta->h_pflags & IMMUTABLE)) - return (EPERM); - - /* Otherwise, user id 0 always gets access. */ - if (cred->cr_uid == 0) { - retval = 0; - goto Exit; - }; - - /* Otherwise, check the owner. */ - if ((retval = hfs_owner_rights(vp, cred, p, false)) == 0) { - retval = ((hp->h_meta->h_mode & S_IWUSR) == S_IWUSR ? 0 : EACCES); - goto Exit; - } - - /* Otherwise, check the groups. */ - for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++) - if (hp->h_meta->h_gid == *gp) { - retval = ((hp->h_meta->h_mode & S_IWGRP) == S_IWGRP ? 0 : EACCES); - goto Exit; - } - - /* Otherwise, check everyone else. */ - retval = ((hp->h_meta->h_mode & S_IWOTH) == S_IWOTH ? 0 : EACCES); - -Exit: - return (retval); -} - - - -/* - * Change the flags on a file or directory. - * Inode must be locked before calling. - */ -static int -hfs_chflags(vp, flags, cred, p) -register struct vnode *vp; -register u_long flags; -register struct ucred *cred; -struct proc *p; -{ - register struct hfsnode *hp = VTOH(vp); - int retval; - - if (VTOVCB(vp)->vcbSigWord == kHFSSigWord) { - if ((retval = hfs_write_access(vp, cred, p, false)) != 0) { - return retval; - }; - } else if ((retval = hfs_owner_rights(vp, cred, p, true)) != 0) { - return retval; - }; - - if (cred->cr_uid == 0) { - if ((hp->h_meta->h_pflags & (SF_IMMUTABLE | SF_APPEND)) && - securelevel > 0) { - return EPERM; - }; - hp->h_meta->h_pflags = flags; - } else { - if (hp->h_meta->h_pflags & (SF_IMMUTABLE | SF_APPEND) || - (flags & UF_SETTABLE) != flags) { - return EPERM; - }; - hp->h_meta->h_pflags &= SF_SETTABLE; - hp->h_meta->h_pflags |= (flags & UF_SETTABLE); - } - hp->h_meta->h_metaflags &= ~IN_UNSETACCESS; - hp->h_nodeflags |= IN_CHANGE; - - return 0; -} - - -/* - * Perform chown operation on hfsnode hp; - * hfsnode must be locked prior to call. - */ -static int -hfs_chown(vp, uid, gid, cred, p) -register struct vnode *vp; -uid_t uid; -gid_t gid; -struct ucred *cred; -struct proc *p; -{ - register struct hfsnode *hp = VTOH(vp); - uid_t ouid; - gid_t ogid; - int retval = 0; - - if (VTOVCB(vp)->vcbSigWord != kHFSPlusSigWord) - return EOPNOTSUPP; - - if (VTOVFS(vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) { - return E_NONE; - }; - - if (uid == (uid_t)VNOVAL) - uid = hp->h_meta->h_uid; - if (gid == (gid_t)VNOVAL) - gid = hp->h_meta->h_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 != hp->h_meta->h_uid || uid != hp->h_meta->h_uid || - (gid != hp->h_meta->h_gid && !groupmember((gid_t)gid, cred))) && - (retval = suser(cred, &p->p_acflag))) - return (retval); - - ogid = hp->h_meta->h_gid; - ouid = hp->h_meta->h_uid; - - hp->h_meta->h_gid = gid; - hp->h_meta->h_uid = uid; - - hp->h_meta->h_metaflags &= ~IN_UNSETACCESS; - if (ouid != uid || ogid != gid) - hp->h_nodeflags |= IN_CHANGE; - if (ouid != uid && cred->cr_uid != 0) - hp->h_meta->h_mode &= ~ISUID; - if (ogid != gid && cred->cr_uid != 0) - hp->h_meta->h_mode &= ~ISGID; - return (0); -} - - - -/* -# -#% exchange fvp L L L -#% exchange tvp L L L -# - vop_exchange { - IN struct vnode *fvp; - IN struct vnode *tvp; - IN struct ucred *cred; - IN struct proc *p; - }; - - */ - /* - * exchange is a very tricky routine, because we might have to unlock the - * passed in vnode, and then retry locking it and all its siblings, and then - * unlocking them in reverse. - * Also the sibling list lock must be kept during the whole operation to - * make sure nothing changes underneath us. - * Also it depends on behavior of the sibling list and hash, so - * careful if you change anything. - */ - -static int -hfs_exchange(ap) -struct vop_exchange_args /* { -struct vnode *a_fvp; -struct vnode *a_tvp; -struct ucred *a_cred; -struct proc *a_p; -} */ *ap; -{ - struct hfsnode *from_hp, *to_hp, *nhp; - struct hfsnode *fromFirst, *fromSecond, *toFirst, *toSecond; - struct vnode *from_vp, *to_vp; - struct hfsmount *hfsmp; - u_char tmp_name[kHFSPlusMaxFileNameBytes+1]; /* 766 bytes! */ - ExtendedVCB *vcb; - u_int32_t fromFileID, toFileID; - u_int32_t fromParID; - u_int32_t tmpLong; - int retval = E_NONE; - DBG_FUNC_NAME("exchange"); - DBG_VOP_LOCKS_DECL(2); - DBG_VOP_LOCKS_INIT(0,ap->a_fvp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS); - DBG_VOP_LOCKS_INIT(1,ap->a_tvp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS); - - /* Set up variables and checks */ - from_vp = ap->a_fvp; - to_vp = ap->a_tvp; - from_hp = VTOH(from_vp); - to_hp = VTOH(to_vp); - hfsmp = VTOHFS(from_vp); - vcb = HTOVCB(from_hp); - toFileID = H_FILEID(to_hp); - fromFileID = H_FILEID(from_hp); - fromParID = H_DIRID(from_hp); - - if (from_vp->v_mount != to_vp->v_mount) { - DBG_VOP_LOCKS_TEST(EXDEV); - return EXDEV; - } - - /* Can only exchange file objects */ - if (from_vp->v_type != VREG || to_vp->v_type != VREG) { - DBG_VOP_LOCKS_TEST(EINVAL); - return EINVAL; - } - - /* - * Lock the siblink list - * Check for multiple forks - * If there are, we would need to: - * 1. Unlock ourselves - * 3. Traverse the list in a forward order...locking all vnodes - * 4. Flush all buffers - * 5. Perform the exchange - * 6. Traverse the list in a reverse order...unlocking all vnodes, except orignal - * Notice that the sibling lock is kept during the whole operation. This quarentees - * that no new forks are taken off or put on - */ - DBG_ASSERT(H_FORKTYPE(from_hp)==kDataFork && H_FORKTYPE(to_hp)==kDataFork); - fromFirst = fromSecond = toFirst = toSecond = NULL; - - if (from_hp->h_meta->h_usecount > 1) { - /* - * This has siblings, so remember the passed-in vnode, - * unlock it if it is not the 'first' sibling, - * and then lock the rest of the vnodes by sibling order. - * Notice that the passed-in vnode is not vrele(), this - * keeps the usecount>0, so it wont go away. - */ - simple_lock(&from_hp->h_meta->h_siblinglock); - fromFirst = from_hp->h_meta->h_siblinghead.cqh_first; - fromSecond = fromFirst->h_sibling.cqe_next; - simple_unlock(&from_hp->h_meta->h_siblinglock); - - if (fromFirst == from_hp) { - if (vget(HTOV(fromSecond), LK_EXCLUSIVE | LK_RETRY, ap->a_p)) - fromSecond = NULL; /* its going away */ - } else { - VOP_UNLOCK(HTOV(from_hp), 0, ap->a_p); - if (vget(HTOV(fromFirst), LK_EXCLUSIVE | LK_RETRY, ap->a_p)) - fromFirst = NULL; /* its going away */ - if (vget(HTOV(fromSecond), LK_EXCLUSIVE | LK_RETRY, ap->a_p)) - fromSecond = NULL; /* its going away */ - }; - - } else { - fromFirst = from_hp; - }; - - if (to_hp->h_meta->h_usecount > 1) { - - simple_lock(&to_hp->h_meta->h_siblinglock); - toFirst = to_hp->h_meta->h_siblinghead.cqh_first; - toSecond = toFirst->h_sibling.cqe_next; - simple_unlock(&to_hp->h_meta->h_siblinglock); - - if (toFirst == to_hp) { - if (vget(HTOV(toSecond), LK_EXCLUSIVE | LK_RETRY, ap->a_p)) - toSecond = NULL; /* its going away */ - } else { - VOP_UNLOCK(HTOV(to_hp), 0, ap->a_p); - if (vget(HTOV(toFirst), LK_EXCLUSIVE | LK_RETRY, ap->a_p)) - toFirst = NULL; /* its going away */ - if (vget(HTOV(toSecond), LK_EXCLUSIVE | LK_RETRY, ap->a_p)) - toSecond = NULL; /* its going away */ - }; - - } else { - toFirst = to_hp; - }; - - - /* Ignore any errors, we are doing a 'best effort' on flushing */ - if (fromFirst) - (void) vinvalbuf(HTOV(fromFirst), V_SAVE, ap->a_cred, ap->a_p, 0, 0); - if (fromSecond) - (void) vinvalbuf(HTOV(fromSecond), V_SAVE, ap->a_cred, ap->a_p, 0, 0); - if (toFirst) - (void) vinvalbuf(HTOV(toFirst), V_SAVE, ap->a_cred, ap->a_p, 0, 0); - if (toSecond) - (void) vinvalbuf(HTOV(toSecond), V_SAVE, ap->a_cred, ap->a_p, 0, 0); - - - /* lock catalog b-tree */ - retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, ap->a_p); - if (retval) goto Err_Exit; - - /* lock extents b-tree iff there are overflow extents */ - /* XXX SER ExchangeFileIDs() always tries to delete the virtual extent id for exchanging files - so we neeed the tree to be always locked. - */ - retval = hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p); - if (retval) goto Err_Exit_Relse; - - /* Do the exchange */ - retval = MacToVFSError( ExchangeFileIDs(vcb, H_NAME(from_hp), H_NAME(to_hp), H_DIRID(from_hp), H_DIRID(to_hp), H_HINT(from_hp), H_HINT(to_hp) )); - - (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, ap->a_p); - - if (retval != E_NONE) { - DBG_ERR(("/tError trying to exchange: %d\n", retval)); - goto Err_Exit_Relse; - } - - - /* Purge the vnodes from the name */ - if (fromFirst) - cache_purge(HTOV(fromFirst)); - if (fromSecond) - cache_purge(HTOV(fromSecond)); - if (toFirst) - cache_purge(HTOV(toFirst)); - if (toSecond) - cache_purge(HTOV(toSecond)); - - /* Now exchange fileID, parID, name for the vnode itself */ - copystr(H_NAME(from_hp), (char*) tmp_name, strlen(H_NAME(from_hp))+1, NULL); - hfs_chid(from_hp, toFileID, H_DIRID(to_hp), H_NAME(to_hp)); - hfs_chid(to_hp, fromFileID, fromParID, (char*) tmp_name); - - /* copy rest */ - tmpLong = HTOFCB(from_hp)->fcbFlags; - HTOFCB(from_hp)->fcbFlags = HTOFCB(to_hp)->fcbFlags; - HTOFCB(to_hp)->fcbFlags = tmpLong; - - tmpLong = from_hp->h_meta->h_crtime; - from_hp->h_meta->h_crtime = to_hp->h_meta->h_crtime; - to_hp->h_meta->h_crtime = tmpLong; - - tmpLong = from_hp->h_meta->h_butime; - from_hp->h_meta->h_butime = to_hp->h_meta->h_butime; - to_hp->h_meta->h_butime = tmpLong; - - tmpLong = from_hp->h_meta->h_atime; - from_hp->h_meta->h_atime = to_hp->h_meta->h_atime; - to_hp->h_meta->h_atime = tmpLong; - - tmpLong = from_hp->h_meta->h_ctime; - from_hp->h_meta->h_ctime = to_hp->h_meta->h_ctime; - to_hp->h_meta->h_ctime = tmpLong; - - tmpLong = from_hp->h_meta->h_gid; - from_hp->h_meta->h_gid = to_hp->h_meta->h_gid; - to_hp->h_meta->h_gid = tmpLong; - - tmpLong = from_hp->h_meta->h_uid; - from_hp->h_meta->h_uid = to_hp->h_meta->h_uid; - to_hp->h_meta->h_uid = tmpLong; - - tmpLong = from_hp->h_meta->h_pflags; - from_hp->h_meta->h_pflags = to_hp->h_meta->h_pflags; - to_hp->h_meta->h_pflags = tmpLong; - - tmpLong = from_hp->h_meta->h_mode; - from_hp->h_meta->h_mode = to_hp->h_meta->h_mode; - to_hp->h_meta->h_mode = tmpLong; - - tmpLong = from_hp->h_meta->h_rdev; - from_hp->h_meta->h_rdev = to_hp->h_meta->h_rdev; - to_hp->h_meta->h_rdev = tmpLong; - - tmpLong = from_hp->h_meta->h_size; - from_hp->h_meta->h_size = to_hp->h_meta->h_size; - to_hp->h_meta->h_size = tmpLong; - - - -Err_Exit_Relse: - - /* unlock catalog b-tree */ - (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, ap->a_p); - - -Err_Exit: - - - /* XXX SER - * At this point, the vnodes' data is switched, but are on the old hash list. - * so move them to the right bucket. This couldnt be done until now, because the h_siblinglock - * was being held. - * Scenario: - * A fork is trying to be added while exchanging...It got the hash lock, - * but is waiting for the h_siblinglock. So we cannot try get the hash lock - * until we release h_siblinglock, so it could continue, so it adds to the sibling list - * and at the old place, so hfs_vhashmove has to move all vnodes with the old file id. - * Not very pretty, becarefull that this works ok - * Scenario 2: - * Same as the above, but before the move is made (like at this very spot), the new vnode - * is added and a vget is requested for that new vnode, it would have old data - * WE MIGHT NEED TO LOCK THE HASH BECAUSE OF THIS !!! - * Scenario 3: - * Hey! Same as above, but it is added after all the moving - * So now there is a vnode with the old data, on the old hash...it will become - * lost next time that a vget() is done - * - * XXX SER A solution might be to NOT move the hash, but the data (extents) or the - * opposite that we are doing now - */ - hfs_vhashmove(from_hp, fromFileID); - hfs_vhashmove(to_hp, toFileID); - - -#if HFS_DIAGNOSTIC - if (fromFirst) - debug_check_vnode(HTOV(fromFirst), 0); - if (fromSecond) - debug_check_vnode(HTOV(fromSecond), 0); - if (toFirst) - debug_check_vnode(HTOV(toFirst), 0); - if (toSecond) - debug_check_vnode(HTOV(toSecond), 0); -#endif - - - /* Unlock any forks, and the sibling list */ - if (to_hp->h_meta->h_usecount > 1) { - if (to_hp == toFirst) { - if (toSecond) - vput(HTOV(toSecond)); - } else { - if (toSecond) - vrele(HTOV(toSecond)); /* decrement, return it locked */ - if (toFirst) - vput(HTOV(toFirst)); - } - } - if (from_hp->h_meta->h_usecount > 1) { - if (from_hp == fromFirst) { - if (fromSecond) - vput(HTOV(fromSecond)); - } else { - if (fromSecond) - vrele(HTOV(fromSecond)); /* decrement, return it locked */ - if (fromFirst) - vput(HTOV(fromFirst)); - } - } - - DBG_VOP_LOCKS_TEST(retval); - return (retval); -} - - -/* - * Change a vnode's file id, parent id and name - * - * Assumes the vnode is locked and is of type VREG - */ -static void -hfs_chid(struct hfsnode *hp, u_int32_t fid, u_int32_t pid, char* name) -{ - DBG_ASSERT(HTOV(hp)->v_type == VREG); - - H_HINT(hp) = 0; - H_FILEID(hp) = fid; /* change h_nodeID */ - H_DIRID(hp) = pid; - - hfs_set_metaname(name, hp->h_meta, HTOHFS(hp)); - - -} - - -/* - -#% fsync vp L L L -# - vop_fsync { - IN struct vnode *vp; - IN struct ucred *cred; - IN int waitfor; - IN struct proc *p; - - */ - - -static int -hfs_fsync(ap) -struct vop_fsync_args /* { - struct vnode *a_vp; - struct ucred *a_cred; - int a_waitfor; - struct proc *a_p; -} */ *ap; -{ - struct vnode *vp = ap->a_vp ; - struct hfsnode *hp = VTOH(vp); - int retval = 0; - register struct buf *bp; - struct timeval tv; - struct buf *nbp; - int s; - - DBG_FUNC_NAME("fsync"); - DBG_VOP_LOCKS_DECL(1); - DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT((" ")); - DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); - DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_ZERO); - DBG_HFS_NODE_CHECK(ap->a_vp); - -#if HFS_DIAGNOSTIC - DBG_ASSERT(*((int*)&vp->v_interlock) == 0); -#endif - - - /* - * First of all, write out any clusters. - */ - cluster_push(vp); - - /* - * Flush all dirty buffers associated with a vnode. - */ -loop: - s = splbio(); - for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) { - nbp = bp->b_vnbufs.le_next; - if ((bp->b_flags & B_BUSY)) - continue; - if ((bp->b_flags & B_DELWRI) == 0) - panic("hfs_fsync: not dirty"); - bremfree(bp); - bp->b_flags |= B_BUSY; - bp->b_flags &= ~B_LOCKED; /* Clear flag, should only be set on meta files */ - splx(s); - /* - * Wait for I/O associated with indirect blocks to complete, - * since there is no way to quickly wait for them below. - */ - DBG_VOP(("\t\t\tFlushing out phys block %d == log block %d\n", bp->b_blkno, bp->b_lblkno)); - if (bp->b_vp == vp || ap->a_waitfor == MNT_NOWAIT) { - (void) bawrite(bp); - } else { - (void) VOP_BWRITE(bp); - } - goto loop; - } - if (vp->v_flag & VHASDIRTY) - ubc_pushdirty(vp); - - if (ap->a_waitfor == MNT_WAIT) { - while (vp->v_numoutput) { - vp->v_flag |= VBWAIT; - tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "hfs_fsync", 0); - } - - /* I have seen this happen for swapfile. So it is safer to - * check for dirty buffers again. --Umesh - */ - if (vp->v_dirtyblkhd.lh_first || (vp->v_flag & VHASDIRTY)) { - vprint("hfs_fsync: dirty", vp); - splx(s); - goto loop; - } - } - splx(s); - -#if HFS_DIAGNOSTIC - DBG_ASSERT(*((int*)&vp->v_interlock) == 0); -#endif - - tv = time; - if ((vp->v_flag & VSYSTEM) && (hp->fcbBTCBPtr!=NULL)) - BTSetLastSync(HTOFCB(hp), tv.tv_sec); - - if (H_FORKTYPE(hp) != kSysFile) { - retval = VOP_UPDATE(ap->a_vp, &tv, &tv, ap->a_waitfor == MNT_WAIT); - - if (retval != E_NONE) { - DBG_ERR(("%s: FLUSH FAILED: %s\n", funcname, H_NAME(hp))); - } - } - else - hp->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE); - - if (ap->a_waitfor == MNT_WAIT) { - DBG_ASSERT(vp->v_dirtyblkhd.lh_first == NULL); - }; - DBG_VOP_LOCKS_TEST(retval); - DBG_ASSERT(*((int*)&vp->v_interlock) == 0); - return (retval); -} - - -int -hfs_fsync_transaction(struct vnode *vp) -{ - struct hfsnode *hp = VTOH(vp); - register struct buf *bp; - struct timeval tv; - struct buf *nbp; - int s; - - /* - * Flush all dirty buffers associated with a vnode. - */ -loop: - s = splbio(); - - for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) { - nbp = bp->b_vnbufs.le_next; - if ((bp->b_flags & B_BUSY)) - continue; - if ((bp->b_flags & B_DELWRI) == 0) - panic("hfs_fsync: not dirty"); - if ( !(bp->b_flags & B_LOCKED)) - continue; - - bremfree(bp); - bp->b_flags |= B_BUSY; - bp->b_flags &= ~B_LOCKED; /* Clear flag, should only be set on meta files */ - splx(s); - - (void) bawrite(bp); - - goto loop; - } - splx(s); - - tv = time; - if ((vp->v_flag & VSYSTEM) && (hp->fcbBTCBPtr!=NULL)) - (void) BTSetLastSync(VTOFCB(vp), tv.tv_sec); - hp->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE); - - return 0; -} - -/* - -#% remove dvp L U U -#% remove vp L U U -# - vop_remove { - IN WILLRELE struct vnode *dvp; - IN WILLRELE struct vnode *vp; - IN struct componentname *cnp; - - */ - -int -hfs_remove(ap) -struct vop_remove_args /* { - struct vnode *a_dvp; - struct vnode *a_vp; - struct componentname *a_cnp; -} */ *ap; -{ - struct vnode *vp = ap->a_vp; - struct vnode *dvp = ap->a_dvp; - struct hfsnode *hp = VTOH(ap->a_vp); - struct hfsmount *hfsmp = HTOHFS(hp); - struct proc *p = current_proc(); - struct timeval tv; - int retval, use_count; - int filebusy = 0; - int uncache = 0; - DBG_FUNC_NAME("remove"); - DBG_VOP_LOCKS_DECL(2); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_PRINT_VNODE_INFO(ap->a_vp); - DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n")); - DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); - DBG_VOP_LOCKS_INIT(1,ap->a_vp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); - - retval = E_NONE; - - if ((hp->h_meta->h_pflags & (IMMUTABLE | APPEND)) || - (VTOH(dvp)->h_meta->h_pflags & APPEND)) { - retval = EPERM; - goto out; - } - - if (vp->v_usecount > 1) { - /* - * the namei done for the rename took a reference on the - * vnode. Hence set 1 in the tookref parameter - * of ubc_isinuse(). - */ - if(UBCISVALID(vp) && !ubc_isinuse(vp, 1)) - goto hfs_nobusy; - if ((ap->a_cnp->cn_flags & NODELETEBUSY) - || (hfsmp->hfs_private_metadata_dir == 0)) { - /* Carbon semantics prohibits deleting busy files */ - retval = EBUSY; - goto out; - } else - filebusy = 1; - } - -hfs_nobusy: - - tv = time; /* Done here, so all times are the same */ - - /* Check other siblings for in use also */ - /* Uncache everything and make sure no other usecount */ - /* - * This assumes the presence of the most 1 sibling - * - * a. loop through the siblings looking for another - * b. If we find ourselves...skip it - * If there was a sibling: - * a. Check for a positve usecount - * b. uncache any pages - * c. Write out and memory changes - * The idea is to keep the h_siblinglock as little as possible - */ - if (hp->h_meta->h_usecount > 1) { - struct vnode *sib_vp = NULL; - struct hfsnode *nhp; - - DBG_ASSERT(hp->h_meta->h_siblinghead.cqh_first && - (hp->h_meta->h_siblinghead.cqh_first != hp->h_meta->h_siblinghead.cqh_last)); - DBG_ASSERT(H_FORKTYPE(hp)==kDataFork || H_FORKTYPE(hp)==kRsrcFork); - - /* Loop through all siblings, skipping ourselves */ - simple_lock(&hp->h_meta->h_siblinglock); - CIRCLEQ_FOREACH(nhp, &hp->h_meta->h_siblinghead, h_sibling) { - if (nhp == hp) /* skip ourselves */ - continue; - sib_vp = HTOV(nhp); - }; - simple_unlock(&hp->h_meta->h_siblinglock); - - /* Check to see if the other fork is in use */ - DBG_ASSERT(sib_vp != NULL); - simple_lock(&sib_vp->v_interlock); - use_count = sib_vp->v_usecount; - simple_unlock(&sib_vp->v_interlock); - if (use_count > 0) { - /* - * This is a sibling vnode and we did not take - * a reference on it. - * Hence set 0 in the tookref parameter - * of ubc_isinuse(). - */ - if(UBCISVALID(sib_vp) && !ubc_isinuse(sib_vp, 0)) - goto hfs_nobusy2; - if ((ap->a_cnp->cn_flags & NODELETEBUSY) - || (hfsmp->hfs_private_metadata_dir == 0)) { - /* Carbon semantics prohibits deleting busy files */ - retval = EBUSY; - goto out; - } else - filebusy = 1; - } /* use_count > 0 */ - -hfs_nobusy2: - - /* The only error that vget returns is when the vnode is going away, so ignore the vnode */ - if (vget(sib_vp, LK_EXCLUSIVE | LK_RETRY, p) == 0) { - /* - * XXX SER An intelligient person would ask, why flush out changes - * that are going to be deleted? See the next comment. - */ - if ((VTOH(sib_vp)->h_nodeflags & IN_MODIFIED) || (VTOFCB(sib_vp)->fcbFlags - & fcbModifiedMask)) { - DBG_ASSERT((VTOH(sib_vp)->h_nodeflags & IN_MODIFIED) != 0); - VOP_UPDATE(sib_vp, &tv, &tv, 0); - }; - - /* Invalidate the buffers, ignore the results */ - (void) vinvalbuf(sib_vp, 0, NOCRED, p, 0, 0); - - vput(sib_vp); - }; /* vget() */ - }; /* h_use_count > 1 */ - - /* - * remove the entry from the namei cache: - * We do it early before any linking/busy file wierdness, make sure the - * original is gone - */ - cache_purge(vp); - - /* Flush out any catalog changes */ - /* XXX SER: This is a hack, becasue hfsDelete reads the data from the disk - * and not from memory which is more correct - */ - if ((hp->h_nodeflags & IN_MODIFIED) || (HTOFCB(hp)->fcbFlags & fcbModifiedMask)) - { - DBG_ASSERT((hp->h_nodeflags & IN_MODIFIED) != 0); - VOP_UPDATE(vp, &tv, &tv, 0); - } - - /* lock catalog b-tree */ - retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p); - if (retval != E_NONE) { - retval = EBUSY; - goto out; - } - - /* - * After this point, any errors must goto out2, so the Catalog Tree gets unlocked - */ - -#if HFS_HARDLINKS - /* - * Multi-linked files just need their link node deleted from the catalog - */ - if (hp->h_meta->h_metaflags & IN_DATANODE) { - - if ((ap->a_cnp->cn_flags & HASBUF) == 0 || - ap->a_cnp->cn_nameptr[0] == '\0') { - retval = ENOENT; /* name missing */ - goto out2; - } - - /* lock extents b-tree (also protects volume bitmap) */ - retval = hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE, p); - if (retval != E_NONE) { - retval = EBUSY; - goto out2; /* unlock catalog b-tree on the way out */ - } - - retval = hfsDelete (HTOVCB(hp), H_FILEID(VTOH(dvp)), - ap->a_cnp->cn_nameptr, TRUE, H_HINT(hp)); - - (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, p); - - if (retval != 0) - goto out2; - - hp->h_meta->h_metaflags |= IN_NOEXISTS; - hp->h_nodeflags |= IN_CHANGE; - if (--hp->h_meta->h_nlink < 1) - hp->h_meta->h_metaflags |= IN_DELETED; - - /* name and parent fields are no longer valid so invalidate them */ - H_DIRID(hp) = kUnknownID; - hfs_set_metaname("\0", hp->h_meta, HTOHFS(hp)); - - if ((ap->a_cnp->cn_flags & (HASBUF | SAVENAME)) == (HASBUF | SAVENAME)) - FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI); - /* - * This is a deleted file no new clients - * would be able to look it up. Maked the VM object - * not cachable so that it dies as soon as the last - * mapping disappears. This will reclaim the disk - * space as soon as possible. - */ - uncache = 1; - goto out2; /* link deleted, all done */ - } -#endif - - /* - * To make the HFS filesystem follow UFS unlink semantics, a remove of - * an active vnode is translated to a move/rename so the file appears - * deleted. Later, the file is removed by hfs_inactive on the hfsnode. - */ - if (filebusy) { - UInt32 hint = H_HINT(hp); - char nodeName[32]; - - MAKE_DELETED_NAME(nodeName, H_FILEID(hp)); - - retval = hfsMoveRename (HTOVCB(hp), H_DIRID(hp), H_NAME(hp), - hfsmp->hfs_private_metadata_dir, nodeName, &hint); - if (retval) goto out2; - - hp->h_meta->h_metaflags |= IN_DELETED; - hp->h_nodeflags |= IN_CHANGE; - - /* update name so Catalog lookups succeed */ - H_HINT(hp) = hint; - H_DIRID(hp) = hfsmp->hfs_private_metadata_dir; - hfs_set_metaname(nodeName, hp->h_meta, HTOHFS(hp)); - - /* - * This is an open deleted file no new clients - * would be able to look it up. Maked the VM object - * not cachable so that it dies as soon as the last - * mapping disappears. This will reclaim the disk - * space as soon as possible. - */ - uncache = 1; - goto out2; /* all done, unlock the catalog */ - } - - /* unlock the Catalog */ - (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); - - /* Invalidate the buffers */ - if ((retval= vinvalbuf(vp, 0, NOCRED, p, 0, 0))) - goto out; - - if(UBCINFOEXISTS(vp)) - (void)ubc_setsize(vp, (off_t)0); - - - /* lock catalog b-tree */ - retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p); - if (retval != E_NONE) { - retval = EBUSY; - goto out; - } - /* lock extents b-tree (also protects volume bitmap) */ - retval = hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE, p); - if (retval != E_NONE) { - retval = EBUSY; - goto out2; /* unlock catalog b-tree on the way out */ - } - - /* remove entry from catalog and free any blocks used */ - retval = hfsDelete (HTOVCB(hp), H_DIRID(hp), H_NAME(hp), TRUE, H_HINT(hp)); - - /* Clean up */ - (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, p); - (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); - - if (retval != 0) - goto out; - - hp->h_meta->h_metaflags |= IN_NOEXISTS; - hp->h_meta->h_mode = 0; /* Makes the node go away...see inactive */ - /* clear the block mappings */ - hp->fcbPLen = (u_int64_t)0; - bzero(&hp->fcbExtents, sizeof(HFSPlusExtentRecord)); - - VTOH(dvp)->h_nodeflags |= IN_CHANGE | IN_UPDATE; - - uncache = 1; - goto done; - -out2: - (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); - -out: - - if (! retval) - VTOH(dvp)->h_nodeflags |= IN_CHANGE | IN_UPDATE; - -done: - if (dvp != vp) - VOP_UNLOCK(vp, 0, p); - - if (uncache) - ubc_uncache(vp); - - vrele(vp); - vput(dvp); - - DBG_VOP_LOCKS_TEST(retval); - return (retval); -} - - -/* - -#% rename sourcePar_vp U U U -#% rename source_vp U U U -#% rename targetPar_vp L U U -#% rename target_vp X U U -# - vop_rename { - IN WILLRELE struct vnode *sourcePar_vp; - IN WILLRELE struct vnode *source_vp; - IN struct componentname *source_cnp; - IN WILLRELE struct vnode *targetPar_vp; - IN WILLRELE struct vnode *target_vp; - IN struct componentname *target_cnp; - - - */ -/* -* On entry: -* source's parent directory is unlocked -* source file or directory is unlocked -* destination's parent directory is locked -* destination file or directory is locked if it exists -* -* On exit: -* all denodes should be released -* -*/ - -static int -hfs_rename(ap) -struct vop_rename_args /* { - struct vnode *a_fdvp; - struct vnode *a_fvp; - struct componentname *a_fcnp; - struct vnode *a_tdvp; - struct vnode *a_tvp; - struct componentname *a_tcnp; -} */ *ap; -{ - struct vnode *target_vp = ap->a_tvp; - struct vnode *targetPar_vp = ap->a_tdvp; - struct vnode *source_vp = ap->a_fvp; - struct vnode *sourcePar_vp = ap->a_fdvp; - struct componentname *target_cnp = ap->a_tcnp; - struct componentname *source_cnp = ap->a_fcnp; - struct proc *p = source_cnp->cn_proc; - struct hfsnode *target_hp, *targetPar_hp, *source_hp, *sourcePar_hp; - u_int32_t oldparent = 0, newparent = 0; - int doingdirectory = 0; - int retval = 0; - struct timeval tv; - struct hfsCatalogInfo catInfo; - u_int32_t tehint = 0; - DBG_VOP_LOCKS_DECL(4); - - DBG_FUNC_NAME("rename");DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("\n")); - DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("Source:\t"));DBG_VOP_PRINT_VNODE_INFO(ap->a_fvp);DBG_VOP_CONT(("\n")); - DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("SourcePar: "));DBG_VOP_PRINT_VNODE_INFO(ap->a_fdvp);DBG_VOP_CONT(("\n")); - DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("Target:\t"));DBG_VOP_PRINT_VNODE_INFO(ap->a_tvp);DBG_VOP_CONT(("\n")); - DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("TargetPar: "));DBG_VOP_PRINT_VNODE_INFO(ap->a_tdvp);DBG_VOP_CONT(("\n")); - DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("SourceName:\t"));DBG_VOP_PRINT_CPN_INFO(ap->a_fcnp);DBG_VOP_CONT(("\n")); - DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("TargetName:\t"));DBG_VOP_PRINT_CPN_INFO(ap->a_tcnp);DBG_VOP_CONT(("\n")); - DBG_VOP_LOCKS_INIT(0,ap->a_fdvp, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); - DBG_VOP_LOCKS_INIT(1,ap->a_fvp, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); - DBG_VOP_LOCKS_INIT(2,ap->a_tdvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); - DBG_VOP_LOCKS_INIT(3,ap->a_tvp, VOPDBG_LOCKNOTNIL, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); - WRITE_CK(ap->a_fdvp, funcname); - DBG_HFS_NODE_CHECK(ap->a_fdvp); - DBG_HFS_NODE_CHECK(ap->a_tdvp); - -#if HFS_DIAGNOSTIC - if ((target_cnp->cn_flags & HASBUF) == 0 || - (source_cnp->cn_flags & HASBUF) == 0) - panic("hfs_rename: no name"); -#endif - - DBG_ASSERT((ap->a_fdvp->v_type == VDIR) && (ap->a_tdvp->v_type == VDIR)); - target_hp = targetPar_hp = source_hp = sourcePar_hp = 0; - - /* If fvp is the same as tvp...then we are just changing case, ignore target_vp */ - /* - * This must be done now, since the value of target_vp is used to - * determine wether to unlock it (for instance, goto abortit). - * In this case, target_vp comes in unlocked - */ - if (source_vp == target_vp) - target_vp = NULL; - - /* - * Check for cross-device rename. - */ - if ((source_vp->v_mount != targetPar_vp->v_mount) || - (target_vp && (source_vp->v_mount != target_vp->v_mount))) { - retval = EXDEV; - goto abortit; - } - - /* - * Check for access permissions - */ - if (target_vp && ((VTOH(target_vp)->h_meta->h_pflags & (IMMUTABLE | APPEND)) || - (VTOH(targetPar_vp)->h_meta->h_pflags & APPEND))) { - retval = EPERM; - goto abortit; - } - - /* - * Force Carbon renames to have MacUnicode encoding - */ - if ((VTOH(targetPar_vp)->h_nodeflags & IN_BYCNID) && (!ISSET(p->p_flag, P_TBE))) { - tehint = kTextEncodingMacUnicode; - } - - if ((retval = vn_lock(source_vp, LK_EXCLUSIVE, p))) - goto abortit; - - sourcePar_hp = VTOH(sourcePar_vp); - source_hp = VTOH(source_vp); - oldparent = H_FILEID(sourcePar_hp); - if ((source_hp->h_meta->h_pflags & (IMMUTABLE | APPEND)) || (sourcePar_hp->h_meta->h_pflags & APPEND)) { - VOP_UNLOCK(source_vp, 0, p); - retval = EPERM; - goto abortit; - } - - /* - * Be sure we are not renaming ".", "..", or an alias of ".". This - * leads to a crippled directory tree. It's pretty tough to do a - * "ls" or "pwd" with the "." directory entry missing, and "cd .." - * doesn't work if the ".." entry is missing. - */ - if ((source_hp->h_meta->h_mode & IFMT) == IFDIR) { - if ((source_cnp->cn_namelen == 1 && source_cnp->cn_nameptr[0] == '.') - || sourcePar_hp == source_hp - || (source_cnp->cn_flags&ISDOTDOT) - || (source_hp->h_nodeflags & IN_RENAME)) { - VOP_UNLOCK(source_vp, 0, p); - retval = EINVAL; - goto abortit; - } - source_hp->h_nodeflags |= IN_RENAME; - doingdirectory = TRUE; - } - - /* - * - * >>>> Transit between abort and bad <<<< - * - */ - - targetPar_hp = VTOH(targetPar_vp); - if (target_vp) - target_hp = VTOH(target_vp); - else - DBG_ASSERT(target_hp == NULL); - - newparent = H_FILEID(targetPar_hp); - - /* Test to make sure we are not crossing devices */ - /* XXX SER Is this necesary, does catalog manager take care of this? */ - if (target_vp) { - if (H_DEV(target_hp) != H_DEV(targetPar_hp) || H_DEV(target_hp) != H_DEV(source_hp)) - panic("rename: EXDEV"); - } - else { - if (H_DEV(targetPar_hp) != H_DEV(source_hp)) - panic("rename: EXDEV"); - }; - - retval = VOP_ACCESS(source_vp, VWRITE, target_cnp->cn_cred, target_cnp->cn_proc); - if (doingdirectory && (newparent != oldparent)) { - if (retval) /* write access check above */ - goto bad; - } - retval = 0; /* Reset value from above, we dont care about it anymore */ - - /* - * If the destination exists, then be sure its type (file or dir) - * matches that of the source. And, if it is a directory make sure - * it is empty. Then delete the destination. - */ - if (target_vp) { - - /* - * 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 ((targetPar_hp->h_meta->h_mode & S_ISTXT) && (target_cnp->cn_cred->cr_uid != 0) && - target_cnp->cn_cred->cr_uid != targetPar_hp->h_meta->h_uid && - target_cnp->cn_cred->cr_uid != target_hp->h_meta->h_uid) { - retval = EPERM; - goto bad; - } - - /* - * VOP_REMOVE will vput targetPar_vp so we better bump - * its ref count and relockit, always set target_vp to - * NULL afterwards to indicate that were done with it. - */ - VREF(targetPar_vp); - - cache_purge(target_vp); - -#if HFS_HARDLINKS - target_cnp->cn_flags &= ~SAVENAME; -#endif - - retval = VOP_REMOVE(targetPar_vp, target_vp, target_cnp); - (void) vn_lock(targetPar_vp, LK_EXCLUSIVE | LK_RETRY, p); - - target_vp = NULL; - target_hp = NULL; - - if (retval) goto bad; - - }; - - - if (newparent != oldparent) - vn_lock(sourcePar_vp, LK_EXCLUSIVE | LK_RETRY, p); - - /* remove the existing entry from the namei cache: */ - cache_purge(source_vp); - - INIT_CATALOGDATA(&catInfo.nodeData, 0); - - /* lock catalog b-tree */ - retval = hfs_metafilelocking(VTOHFS(source_vp), kHFSCatalogFileID, LK_EXCLUSIVE, p); - if (retval) { - if (newparent != oldparent) /* unlock the lock we just got */ - VOP_UNLOCK(sourcePar_vp, 0, p); - goto bad; - }; - - /* use source_cnp instead of H_NAME(source_hp) in case source is a hard link */ - retval = MoveRenameCatalogNode(HTOVCB(source_hp), H_DIRID(source_hp), - source_cnp->cn_nameptr, H_HINT(source_hp), - H_FILEID(VTOH(targetPar_vp)), - target_cnp->cn_nameptr, &H_HINT(source_hp), tehint); - retval = MacToVFSError(retval); - - if (retval == 0) { - /* Look up the catalog entry just renamed since it might have been auto-decomposed */ - catInfo.hint = H_HINT(source_hp); - retval = hfs_getcatalog(HTOVCB(source_hp), H_FILEID(targetPar_hp), target_cnp->cn_nameptr, target_cnp->cn_namelen, &catInfo); - } - - /* unlock catalog b-tree */ - (void) hfs_metafilelocking(VTOHFS(source_vp), kHFSCatalogFileID, LK_RELEASE, p); - - if (newparent != oldparent) - VOP_UNLOCK(sourcePar_vp, 0, p); - - if (retval) goto bad; - - H_DIRID(source_hp) = H_FILEID(targetPar_hp); - - hfs_name_CatToMeta(&catInfo.nodeData, source_hp->h_meta); - - CLEAN_CATALOGDATA(&catInfo.nodeData); - - source_hp->h_nodeflags &= ~IN_RENAME; - - - /* - * Timestamp both parent directories. - * Note that if this is a rename within the same directory, - * (where targetPar_hp == sourcePar_hp) - * the code below is still safe and correct. - */ - targetPar_hp->h_nodeflags |= IN_UPDATE; - sourcePar_hp->h_nodeflags |= IN_UPDATE; - tv = time; - HFSTIMES(targetPar_hp, &tv, &tv); - HFSTIMES(sourcePar_hp, &tv, &tv); - - vput(targetPar_vp); - vrele(sourcePar_vp); - vput(source_vp); - - DBG_VOP_LOCKS_TEST(retval); - if (retval != E_NONE) { - DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("\tReturning with error %d\n",retval)); - } - return (retval); - -bad:; - if (retval && doingdirectory) - source_hp->h_nodeflags &= ~IN_RENAME; - - if (targetPar_vp == target_vp) - vrele(targetPar_vp); - else - vput(targetPar_vp); - - if (target_vp) - vput(target_vp); - - vrele(sourcePar_vp); - - if (VOP_ISLOCKED(source_vp)) - vput(source_vp); - else - vrele(source_vp); - - DBG_VOP_LOCKS_TEST(retval); - if (retval != E_NONE) { - DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("\tReturning with error %d\n",retval)); - } - return (retval); - -abortit:; - - VOP_ABORTOP(targetPar_vp, target_cnp); /* XXX, why not in NFS? */ - - if (targetPar_vp == target_vp) - vrele(targetPar_vp); - else - vput(targetPar_vp); - - if (target_vp) - vput(target_vp); - - VOP_ABORTOP(sourcePar_vp, source_cnp); /* XXX, why not in NFS? */ - - vrele(sourcePar_vp); - vrele(source_vp); - - DBG_VOP_LOCKS_TEST(retval); - if (retval != E_NONE) { - DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("\tReturning with error %d\n",retval)); - } - return (retval); -} - - - -/* - * Mkdir system call -#% mkdir dvp L U U -#% mkdir vpp - L - -# - vop_mkdir { - IN WILLRELE struct vnode *dvp; - OUT struct vnode **vpp; - IN struct componentname *cnp; - IN struct vattr *vap; - - We are responsible for freeing the namei buffer, - it is done in hfs_makenode() -*/ - -int -hfs_mkdir(ap) -struct vop_mkdir_args /* { - struct vnode *a_dvp; - struct vnode **a_vpp; - struct componentname *a_cnp; - struct vattr *a_vap; -} */ *ap; -{ - struct proc *p = current_proc(); - int retval; - int mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode); - - DBG_FUNC_NAME("mkdir"); - DBG_VOP_LOCKS_DECL(2); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_PRINT_VNODE_INFO(ap->a_dvp); - DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n")); - - DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); - DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_POS); - - DBG_VOP(("%s: parent 0x%x (%s) ap->a_cnp->cn_nameptr %s\n", funcname, (u_int)VTOH(ap->a_dvp), H_NAME(VTOH(ap->a_dvp)), ap->a_cnp->cn_nameptr)); - WRITE_CK( ap->a_dvp, funcname); - DBG_HFS_NODE_CHECK(ap->a_dvp); - DBG_ASSERT(ap->a_dvp->v_type == VDIR); - - /* Create the vnode */ - DBG_ASSERT((ap->a_cnp->cn_flags & SAVESTART) == 0); - retval = hfs_makenode(mode, 0, ap->a_dvp, ap->a_vpp, ap->a_cnp, p); - DBG_VOP_UPDATE_VP(1, *ap->a_vpp); - - if (retval != E_NONE) { - DBG_ERR(("%s: hfs_makenode FAILED: %s, %s\n", funcname, ap->a_cnp->cn_nameptr, H_NAME(VTOH(ap->a_dvp)))); - DBG_VOP_LOCKS_TEST(retval); - return (retval); - } - - DBG_VOP_LOCKS_TEST(E_NONE); - return (E_NONE); -} - -/* - * Rmdir system call. -#% rmdir dvp L U U -#% rmdir vp L U U -# - vop_rmdir { - IN WILLRELE struct vnode *dvp; - IN WILLRELE struct vnode *vp; - IN struct componentname *cnp; - - */ - -int -hfs_rmdir(ap) -struct vop_rmdir_args /* { - struct vnode *a_dvp; - struct vnode *a_vp; - struct componentname *a_cnp; -} */ *ap; -{ - struct vnode *vp = ap->a_vp; - struct vnode *dvp = ap->a_dvp; - struct hfsnode *hp = VTOH(vp); - struct proc *p = current_proc(); - int retval; - DBG_FUNC_NAME("rmdir"); - DBG_VOP_LOCKS_DECL(2); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP(("\tParent: "));DBG_VOP_PRINT_VNODE_INFO(ap->a_dvp);DBG_VOP_CONT(("\n")); - DBG_VOP(("\tTarget: "));DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); - DBG_VOP(("\tTarget Name: "));DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n")); - - DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); - DBG_VOP_LOCKS_INIT(1,ap->a_vp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); - - if (dvp == vp) { - vrele(vp); - vput(vp); - DBG_VOP_LOCKS_TEST(EINVAL); - return (EINVAL); - } - - /* - * HFS differs from UFS here in that we don't allow removing - * a directory that in use by others - even if its empty. - * - * In the future we might want to allow this just like we do - * for files (by renaming the busy directory). - */ -#if 0 - if (vp->v_usecount > 1) { - DBG_ERR(("%s: dir is busy, usecount is %d\n", funcname, vp->v_usecount )); - retval = EBUSY; - goto Err_Exit; - } -#endif - /* remove the entry from the namei cache: */ - cache_purge(vp); - - /* lock catalog b-tree */ - retval = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_EXCLUSIVE, p); - if (retval != E_NONE) { - goto Err_Exit; - } - - /* remove entry from catalog */ - retval = hfsDelete (HTOVCB(hp), H_DIRID(hp), H_NAME(hp), FALSE, H_HINT(hp)); - - /* unlock catalog b-tree */ - (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, p); - - if (! retval) { - VTOH(dvp)->h_nodeflags |= IN_CHANGE | IN_UPDATE; /* Set the parent to be updated */ - hp->h_meta->h_mode = 0; /* Makes the vnode go away...see inactive */ - hp->h_meta->h_metaflags |= IN_NOEXISTS; - } - -Err_Exit:; - if (dvp != 0) - vput(dvp); - vput(vp); - - DBG_VOP_LOCKS_TEST(retval); - return (retval); -} - -/* - * symlink -- make a symbolic link -#% symlink dvp L U U -#% symlink vpp - U - -# -# XXX - note that the return vnode has already been VRELE'ed -# by the filesystem layer. To use it you must use vget, -# possibly with a further namei. -# - vop_symlink { - IN WILLRELE struct vnode *dvp; - OUT WILLRELE struct vnode **vpp; - IN struct componentname *cnp; - IN struct vattr *vap; - IN char *target; - - We are responsible for freeing the namei buffer, - it is done in hfs_makenode(). - -*/ - -int -hfs_symlink(ap) - struct vop_symlink_args /* { - struct vnode *a_dvp; - struct vnode **a_vpp; - struct componentname *a_cnp; - struct vattr *a_vap; - char *a_target; - } */ *ap; -{ - register struct vnode *vp, **vpp = ap->a_vpp; - struct proc *p = current_proc(); - struct hfsnode *hp; - int len, retval; - struct buf *bp = NULL; - - /* HFS standard disks don't support symbolic links */ - if (VTOVCB(ap->a_dvp)->vcbSigWord != kHFSPlusSigWord) { - VOP_ABORTOP(ap->a_dvp, ap->a_cnp); - vput(ap->a_dvp); - return (EOPNOTSUPP); - } - - /* Check for empty target name */ - if (ap->a_target[0] == 0) { - VOP_ABORTOP(ap->a_dvp, ap->a_cnp); - vput(ap->a_dvp); - return (EINVAL); - } - - /* Create the vnode */ - retval = hfs_makenode(IFLNK | ap->a_vap->va_mode, 0, ap->a_dvp, - vpp, ap->a_cnp, p); - DBG_VOP_UPDATE_VP(1, *ap->a_vpp); - - if (retval != E_NONE) { - return (retval); - } - - vp = *vpp; - len = strlen(ap->a_target); - hp = VTOH(vp); - hp->fcbClmpSize = VTOVCB(vp)->blockSize; - - /* Allocate space for the link */ - retval = VOP_TRUNCATE(vp, len, IO_NOZEROFILL, - ap->a_cnp->cn_cred, ap->a_cnp->cn_proc); - if (retval) - goto out; - - /* Write the link to disk */ - bp = getblk(vp, 0, roundup((int)hp->fcbEOF, VTOHFS(vp)->hfs_phys_block_size), 0, 0, BLK_META); - bzero(bp->b_data, bp->b_bufsize); - bcopy(ap->a_target, bp->b_data, len); - bp->b_flags |= B_DIRTY; - bawrite(bp); - -out: - vput(vp); - return (retval); -} - - -/* - * Dummy dirents to simulate the "." and ".." entries of the directory - * in a hfs filesystem. HFS doesn't provide these on disk. Note that - * the size of these entries is the smallest needed to represent them - * (only 12 byte each). - */ -static hfsdotentry rootdots[2] = { - { - 1, /* d_fileno */ - sizeof(struct hfsdotentry), /* d_reclen */ - DT_DIR, /* d_type */ - 1, /* d_namlen */ - "." /* d_name */ - }, - { - 1, /* d_fileno */ - sizeof(struct hfsdotentry), /* d_reclen */ - DT_DIR, /* d_type */ - 2, /* d_namlen */ - ".." /* d_name */ - } -}; - -static hfsdotentry emptyentry = { 0 }; - -/* 4.3 Note: -* There is some confusion as to what the semantics of uio_offset are. -* In ufs, it represents the actual byte offset within the directory -* "file." HFS, however, just uses it as an entry counter - essentially -* assuming that it has no meaning except to the hfs_readdir function. -* This approach would be more efficient here, but some callers may -* assume the uio_offset acts like a byte offset. NFS in fact -* monkeys around with the offset field a lot between readdir calls. -* -* The use of the resid uiop->uio_resid and uiop->uio_iov->iov_len -* fields is a mess as well. The libc function readdir() returns -* NULL (indicating the end of a directory) when either -* the getdirentries() syscall (which calls this and returns -* the size of the buffer passed in less the value of uiop->uio_resid) -* returns 0, or a direct record with a d_reclen of zero. -* nfs_server.c:rfs_readdir(), on the other hand, checks for the end -* of the directory by testing uiop->uio_resid == 0. The solution -* is to pad the size of the last struct direct in a given -* block to fill the block if we are not at the end of the directory. -*/ - -struct callbackstate { - u_int32_t cbs_parentID; - u_int32_t cbs_hiddenDirID; - off_t cbs_lastoffset; - struct uio * cbs_uio; - ExtendedVCB * cbs_vcb; - int16_t cbs_hfsPlus; - int16_t cbs_result; -}; - - -SInt32 -ProcessCatalogEntry(const CatalogKey *ckp, const CatalogRecord *crp, - u_int16_t recordLen, struct callbackstate *state) -{ - CatalogName *cnp; - size_t utf8chars; - u_int32_t curID; - OSErr result; - struct dirent catent; - - if (state->cbs_hfsPlus) - curID = ckp->hfsPlus.parentID; - else - curID = ckp->hfs.parentID; - - /* We're done when parent directory changes */ - if (state->cbs_parentID != curID) { -lastitem: -/* - * The NSDirectoryList class chokes on empty records (it doesnt check d_reclen!) - * so remove padding for now... - */ -#if 0 - /* - * Pad the end of list with an empty record. - * This eliminates an extra call by readdir(3c). - */ - catent.d_fileno = 0; - catent.d_reclen = 0; - catent.d_type = 0; - catent.d_namlen = 0; - *(int32_t*)&catent.d_name[0] = 0; - - state->cbs_lastoffset = state->cbs_uio->uio_offset; - - state->cbs_result = uiomove((caddr_t) &catent, 12, state->cbs_uio); - if (state->cbs_result == 0) - state->cbs_result = ENOENT; -#else - state->cbs_lastoffset = state->cbs_uio->uio_offset; - state->cbs_result = ENOENT; -#endif - return (0); /* stop */ - } - - if (state->cbs_hfsPlus) { - switch(crp->recordType) { - case kHFSPlusFolderRecord: - catent.d_type = DT_DIR; - catent.d_fileno = crp->hfsPlusFolder.folderID; - break; - case kHFSPlusFileRecord: - catent.d_type = DT_REG; - catent.d_fileno = crp->hfsPlusFile.fileID; - break; - default: - return (0); /* stop */ - }; - - cnp = (CatalogName*) &ckp->hfsPlus.nodeName; - result = utf8_encodestr(cnp->ustr.unicode, cnp->ustr.length * sizeof(UniChar), - catent.d_name, &utf8chars, kdirentMaxNameBytes + 1, ':', 0); - if (result == ENAMETOOLONG) { - result = ConvertUnicodeToUTF8Mangled(cnp->ustr.length * sizeof(UniChar), - cnp->ustr.unicode, kdirentMaxNameBytes + 1, (ByteCount*)&utf8chars, catent.d_name, catent.d_fileno); - } - } else { /* hfs */ - switch(crp->recordType) { - case kHFSFolderRecord: - catent.d_type = DT_DIR; - catent.d_fileno = crp->hfsFolder.folderID; - break; - case kHFSFileRecord: - catent.d_type = DT_REG; - catent.d_fileno = crp->hfsFile.fileID; - break; - default: - return (0); /* stop */ - }; - - cnp = (CatalogName*) ckp->hfs.nodeName; - result = hfs_to_utf8(state->cbs_vcb, cnp->pstr, kdirentMaxNameBytes + 1, - (ByteCount *)&utf8chars, catent.d_name); - /* - * When an HFS name cannot be encoded with the current - * volume encoding we use MacRoman as a fallback. - */ - if (result) - result = mac_roman_to_utf8(cnp->pstr, kdirentMaxNameBytes + 1, - (ByteCount *)&utf8chars, catent.d_name); - } - - catent.d_namlen = utf8chars; - catent.d_reclen = DIRENTRY_SIZE(utf8chars); - - /* hide our private meta data directory */ - if (curID == kRootDirID && - catent.d_fileno == state->cbs_hiddenDirID && - catent.d_type == DT_DIR) - goto lastitem; - - state->cbs_lastoffset = state->cbs_uio->uio_offset; - - /* if this entry won't fit then we're done */ - if (catent.d_reclen > state->cbs_uio->uio_resid) - return (0); /* stop */ - - state->cbs_result = uiomove((caddr_t) &catent, catent.d_reclen, state->cbs_uio); - - /* continue iteration if there's room */ - return (state->cbs_result == 0 && - state->cbs_uio->uio_resid >= AVERAGE_HFSDIRENTRY_SIZE); -} - -/* - * NOTE: We require a minimal buffer size of DIRBLKSIZ for two reasons. One, it is the same value - * returned be stat() call as the block size. This is mentioned in the man page for getdirentries(): - * "Nbytes must be greater than or equal to the block size associated with the file, - * see stat(2)". Might as well settle on the same size of ufs. Second, this makes sure there is enough - * room for the . and .. entries that have to added manually. - */ - -/* -#% readdir vp L L L -# -vop_readdir { - IN struct vnode *vp; - INOUT struct uio *uio; - IN struct ucred *cred; - INOUT int *eofflag; - OUT int *ncookies; - INOUT u_long **cookies; - */ -static int -hfs_readdir(ap) -struct vop_readdir_args /* { - struct vnode *vp; - struct uio *uio; - struct ucred *cred; - int *eofflag; - int *ncookies; - u_long **cookies; -} */ *ap; -{ - register struct uio *uio = ap->a_uio; - struct hfsnode *hp = VTOH(ap->a_vp); - struct proc *p = current_proc(); - ExtendedVCB *vcb = HTOVCB(hp); - off_t off = uio->uio_offset; - u_int32_t dirID = H_FILEID(hp); - int retval = 0; - OSErr result = noErr; - u_int32_t diroffset; - BTreeIterator bi; - CatalogIterator *cip; - u_int16_t op; - struct callbackstate state; - int eofflag = 0; - - DBG_FUNC_NAME("readdir"); - DBG_VOP_LOCKS_DECL(1); - - DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); - DBG_HFS_NODE_CHECK(ap->a_vp); - - /* We assume it's all one big buffer... */ - if (uio->uio_iovcnt > 1 || uio->uio_resid < AVERAGE_HFSDIRENTRY_SIZE) { - return EINVAL; - }; - - /* Create the entries for . and .. */ - if (uio->uio_offset < sizeof(rootdots)) { - caddr_t dep; - size_t dotsize; - - rootdots[0].d_fileno = dirID; - rootdots[1].d_fileno = H_DIRID(hp); - - if (uio->uio_offset == 0) { - dep = (caddr_t) &rootdots[0]; - dotsize = 2* sizeof(struct hfsdotentry); - } else if (uio->uio_offset == sizeof(struct hfsdotentry)) { - dep = (caddr_t) &rootdots[1]; - dotsize = sizeof(struct hfsdotentry); - } else { - retval = EINVAL; - goto Exit; - } - - retval = uiomove(dep, dotsize, uio); - if (retval != 0) - goto Exit; - } - - diroffset = uio->uio_offset; - - /* lock catalog b-tree */ - retval = hfs_metafilelocking(VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_SHARED, p); - if (retval != E_NONE) - goto Exit; - - /* get an iterator and position it */ - cip = GetCatalogIterator(vcb, dirID, diroffset); - - result = PositionIterator(cip, diroffset, &bi, &op); - if (result == cmNotFound) { - eofflag = 1; - retval = 0; - AgeCatalogIterator(cip); - goto cleanup; - } else if ((retval = MacToVFSError(result))) - goto cleanup; - - state.cbs_hiddenDirID = VCBTOHFS(vcb)->hfs_private_metadata_dir; - state.cbs_lastoffset = cip->currentOffset; - state.cbs_vcb = vcb; - state.cbs_uio = uio; - state.cbs_result = 0; - state.cbs_parentID = dirID; - - if (vcb->vcbSigWord == kHFSPlusSigWord) - state.cbs_hfsPlus = 1; - else - state.cbs_hfsPlus = 0; - - /* process as many entries as possible... */ - result = BTIterateRecords(GetFileControlBlock(vcb->catalogRefNum), op, &bi, - (IterateCallBackProcPtr)ProcessCatalogEntry, &state); - - if (state.cbs_result) - retval = state.cbs_result; - else - retval = MacToVFSError(result); - - if (retval == ENOENT) { - eofflag = 1; - retval = 0; - } - - if (retval == 0) { - cip->currentOffset = state.cbs_lastoffset; - cip->nextOffset = uio->uio_offset; - UpdateCatalogIterator(&bi, cip); - } - -cleanup: - if (retval) { - cip->volume = 0; - cip->folderID = 0; - AgeCatalogIterator(cip); - } - - (void) ReleaseCatalogIterator(cip); - - /* unlock catalog b-tree */ - (void) hfs_metafilelocking(VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_RELEASE, p); - - if (retval != E_NONE) { - DBG_ERR(("%s: retval %d when trying to read directory %ld: %s\n",funcname, retval, - H_FILEID(hp), H_NAME(hp))); - goto Exit; - - } - - /* were we already past eof ? */ - if (uio->uio_offset == off) { - retval = E_NONE; - goto Exit; - } - - if (vcb->vcbSigWord == kHFSPlusSigWord) - hp->h_nodeflags |= IN_ACCESS; - - /* Bake any cookies */ - if (!retval && ap->a_ncookies != NULL) { - struct dirent* dpStart; - struct dirent* dpEnd; - struct dirent* dp; - int ncookies; - u_long *cookies; - u_long *cookiep; - - /* - * Only the NFS server uses cookies, and it loads the - * directory block into system space, so we can just look at - * it directly. - */ - if (uio->uio_segflg != UIO_SYSSPACE) - panic("hfs_readdir: unexpected uio from NFS server"); - dpStart = (struct dirent *)(uio->uio_iov->iov_base - (uio->uio_offset - off)); - dpEnd = (struct dirent *) uio->uio_iov->iov_base; - for (dp = dpStart, ncookies = 0; - dp < dpEnd && dp->d_reclen != 0; - dp = (struct dirent *)((caddr_t)dp + dp->d_reclen)) - ncookies++; - MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP, M_WAITOK); - for (dp = dpStart, cookiep = cookies; - dp < dpEnd; - dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) { - off += dp->d_reclen; - *cookiep++ = (u_long) off; - } - *ap->a_ncookies = ncookies; - *ap->a_cookies = cookies; - } - -Exit:; - - if (ap->a_eofflag) - *ap->a_eofflag = eofflag; - - DBG_VOP_LOCKS_TEST(retval); - return (retval); -} - - -/* - * readdirattr operation will return attributes for the items in the - * directory specified. - * - * It does not do . and .. entries. The problem is if you are at the root of the - * hfs directory and go to .. you could be crossing a mountpoint into a - * different (ufs) file system. The attributes that apply for it may not - * apply for the file system you are doing the readdirattr on. To make life - * simpler, this call will only return entries in its directory, hfs like. - * TO DO LATER: - * 1.getattrlist creates a thread record if the objpermanentid attribute - * is requested. Just do EINVAL for now and fix later. - * 2. more than one for uiovcnt support. - * 3. put knohint (hints) in state for next call in - * 4. credentials checking when rest of hfs does it. - * 5. Do return permissions concatenation ??? - */ - -/* -# -#% readdirattr vp L L L -# -vop_readdirattr { - IN struct vnode *vp; - IN struct attrlist *alist; - INOUT struct uio *uio; - IN u_long maxcount: - IN u_long options; - OUT u_long *newstate; - OUT int *eofflag; - OUT u_long *actualCount; - OUT u_long **cookies; - IN struct ucred *cred; -}; -*/ -static int -hfs_readdirattr(ap) -struct vop_readdirattr_args /* { - struct vnode *vp; - struct attrlist *alist; - struct uio *uio; - u_long maxcount: - u_long options; - int *newstate; - int *eofflag; - u_long *actualcount; - u_long **cookies; - struct ucred *cred; -} */ *ap; -{ - struct vnode *vp = ap->a_vp; - struct attrlist *alist = ap->a_alist; - register struct uio *uio = ap->a_uio; - u_long maxcount = ap->a_maxcount; - u_long ncookies; - ExtendedVCB *vcb = HTOVCB(VTOH(vp)); - UInt32 dirID = H_FILEID(VTOH(vp)); - struct proc *proc = current_proc(); /* could get this out of uio */ - off_t startoffset = uio->uio_offset; - struct hfsCatalogInfo catInfo; - UInt32 index; - int retval = 0; - u_long fixedblocksize; - u_long maxattrblocksize; - u_long currattrbufsize; - void *attrbufptr = NULL; - void *attrptr; - void *varptr; - - *(ap->a_actualcount) = 0; - *(ap->a_eofflag) = 0; - - /* check for invalid options, check vnode, and buffer space */ - if (((ap->a_options & ~FSOPT_NOINMEMUPDATE) != 0) || - (vp == NULL) || - (uio->uio_resid <= 0) || (uio->uio_iovcnt > 1)) - return EINVAL; - - /* this call doesn't take volume attributes */ - if ((alist->bitmapcount != ATTR_BIT_MAP_COUNT) || - ((alist->commonattr & ~ATTR_CMN_VALIDMASK) != 0) || - (alist->volattr != 0) || - ((alist->dirattr & ~ATTR_DIR_VALIDMASK) != 0) || - ((alist->fileattr & ~ATTR_FILE_VALIDMASK) != 0) || - ((alist->forkattr & ~ATTR_FORK_VALIDMASK) != 0)) - return EINVAL; - - /* Reject requests for unsupported options for now: */ - if ((alist->commonattr & (ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST)) || - (alist->fileattr & (ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | ATTR_FILE_FORKLIST)) || - (alist->commonattr & ATTR_CMN_OBJPERMANENTID) ) - return EINVAL; - - /* getattrlist and searchfs use a secondary buffer to malloc and then use - * uiomove afterwards. It's an extra copy, but for now leave it alone - */ - fixedblocksize = (sizeof(u_long) + AttributeBlockSize(alist)); /* u_long for length */ - maxattrblocksize = fixedblocksize; - if (alist->commonattr & ATTR_CMN_NAME) - maxattrblocksize += kHFSPlusMaxFileNameBytes + 1; - MALLOC(attrbufptr, void *, maxattrblocksize, M_TEMP, M_WAITOK); - attrptr = attrbufptr; - varptr = (char *)attrbufptr + fixedblocksize; /* Point to variable-length storage */ - - /* Since attributes passed back can contain variable ones (name), we can't just use - * uio_offset as is. We thus force it to represent fixed size of hfsdirentries - * as hfs_readdir was originally doing. If this all we need to represent the current - * state, then ap->a_state is not needed at all. - */ - /* index = ap->a_state; should not be less than 1 */ - index = (uio->uio_offset / sizeof(struct dirent)) + 1; - INIT_CATALOGDATA(&catInfo.nodeData, 0); - - - /* HFS Catalog does not have a bulk directory enumeration call. Do it one at - * time, using hints. GetCatalogOffspring takes care of hfsplus and name issues - * for us, so that's a win. Later, implement GetCatalogOffspringBulk. - */ - catInfo.hint = kNoHint; /* note, we may want to save the latest in state */ - while ((uio->uio_resid >= 0) && (maxcount !=0 )) { - /* better to check uio_resid against max or fixedblocksize, but won't work. - * Depending on if dir or file, the attributes returned will be different. - * Thus fixedblocksize is too large in some cases.Also, the variable - * part (like name) could be between fixedblocksize and the max. - */ - OSErr result; - - /* Lock catalog b-tree */ - if ((retval = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_SHARED, proc)) != E_NONE) - goto exit; - - catInfo.nodeData.cnd_iNodeNumCopy = 0; - result = GetCatalogOffspring(vcb, dirID, index, &catInfo.nodeData, NULL, NULL); - if (result == 0) - hfs_resolvelink(vcb, &catInfo.nodeData); - - /* Unlock catalog b-tree, unconditionally . Ties up the everything during enumeration */ - (void) hfs_metafilelocking( VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_RELEASE, proc ); - - if (result != noErr) { - if (result == cmNotFound) { - *(ap->a_eofflag) = TRUE; - retval = E_NONE; - } - else retval = MacToVFSError(result); - break; - } - - /* hide our private meta data directory as does hfs_readdir */ - if ((dirID == kRootDirID) && - catInfo.nodeData.cnd_nodeID == VCBTOHFS(vcb)->hfs_private_metadata_dir && - catInfo.nodeData.cnd_type == kCatalogFolderNode) { - - ++index; - CLEAN_CATALOGDATA(&catInfo.nodeData); - continue; - } - - *((u_long *)attrptr)++ = 0; /* move it past length */ - - /* - * Don't use data from cached vnodes when FSOPT_NOINMEMUPDATE - * option is active or if this entry is a hard link. - */ - if ((ap->a_options & FSOPT_NOINMEMUPDATE) - || (catInfo.nodeData.cnd_iNodeNumCopy != 0)) { - /* vp okay to use instead of root vp */ - PackCatalogInfoAttributeBlock(alist, vp, &catInfo, &attrptr, &varptr); - } else { - struct vnode *entry_vp = NULL; - struct vnode *rsrc_vp = NULL; - int nodetype; - UInt32 nodeid; - - /* - * Flush out any in-memory state to the catalog record. - * - * In the HFS locking hierarchy, the data fork vnode must - * be acquired before the resource fork vnode. - */ - nodeid = catInfo.nodeData.cnd_nodeID; - if (catInfo.nodeData.cnd_type == kCatalogFolderNode) - nodetype = kDirectory; - else - nodetype = kDataFork; - - /* Check for this entry's cached vnode: */ - entry_vp = hfs_vhashget(H_DEV(VTOH(vp)), nodeid, nodetype); - - /* Also check for a cached resource fork vnode: */ - if (nodetype == kDataFork) { - rsrc_vp = hfs_vhashget(H_DEV(VTOH(vp)), nodeid, kRsrcFork); - if ((rsrc_vp != NULL) - && (VTOH(rsrc_vp)->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE))) { - /* Pick up resource fork info */ - CopyVNodeToCatalogNode(rsrc_vp, &catInfo.nodeData); - } - } - - if (entry_vp != NULL) - PackAttributeBlock(alist, entry_vp, &catInfo, &attrptr, &varptr); - else if (rsrc_vp != NULL) - PackAttributeBlock(alist, rsrc_vp, &catInfo, &attrptr, &varptr); - else - PackCatalogInfoAttributeBlock(alist, vp, &catInfo, &attrptr, &varptr); - - if (rsrc_vp) - vput(rsrc_vp); - if (entry_vp) - vput(entry_vp); - } - currattrbufsize = *((u_long *)attrbufptr) = ((char *)varptr - (char *)attrbufptr); - - /* now check if we can't fit in the buffer space remaining */ - if (currattrbufsize > uio->uio_resid) - break; - else { - retval = uiomove((caddr_t)attrbufptr, currattrbufsize, ap->a_uio); - if (retval != E_NONE) - break; - attrptr = attrbufptr; - varptr = (char *)attrbufptr + fixedblocksize; /* Point to variable-length storage */ - index++; - *ap->a_actualcount += 1; - maxcount--; - } - /* Clean for the next loop */ - CLEAN_CATALOGDATA(&catInfo.nodeData); - }; - *ap->a_newstate = VTOH(vp)->h_meta->h_mtime;/* before we unlock, know the mod date */ - - CLEAN_CATALOGDATA(&catInfo.nodeData); - - if (!retval && ap->a_cookies != NULL) { /* CHECK THAT 0 wasn't passed in */ - void* dpStart; - void* dpEnd; - void* dp; - u_long *cookies; - u_long *cookiep; - - /* Only the NFS server uses cookies, and it loads the - * directory block into system space, so we can just look at - * it directly. - */ - if (uio->uio_segflg != UIO_SYSSPACE) /* || uio->uio_iovcnt != 1 checked earlier */ - panic("hfs_readdirattr: unexpected uio from NFS server"); - dpStart = uio->uio_iov->iov_base - (uio->uio_offset - startoffset); - dpEnd = uio->uio_iov->iov_base; - MALLOC(cookies, u_long *, (*ap->a_actualcount)*sizeof(u_long), M_TEMP, M_WAITOK); - for (dp = dpStart, cookiep = cookies; - dp < dpEnd; - dp = ((caddr_t) dp + *((u_long *)dp))) { - *cookiep++ = (u_long)((caddr_t)dp + sizeof(u_long)); - } - *ap->a_cookies = cookies; - } - - uio->uio_offset = startoffset + (*ap->a_actualcount)*sizeof(struct dirent); - -exit: - if (attrbufptr != NULL) - FREE(attrbufptr, M_TEMP); - return (retval); -} - - -/* - * Return target name of a symbolic link -#% readlink vp L L L -# - vop_readlink { - IN struct vnode *vp; - INOUT struct uio *uio; - IN struct ucred *cred; - */ - -int -hfs_readlink(ap) -struct vop_readlink_args /* { -struct vnode *a_vp; -struct uio *a_uio; -struct ucred *a_cred; -} */ *ap; -{ - int retval; - struct vnode *vp = ap->a_vp; - struct hfsnode *hp = VTOH(vp); - - if (vp->v_type != VLNK) - return (EINVAL); - - /* Zero length sym links are not allowed */ - if (hp->fcbEOF == 0) { - VTOVCB(vp)->vcbFlags |= kHFS_DamagedVolume; - return (EINVAL); - } - - /* Cache the path so we don't waste buffer cache resources */ - if (hp->h_symlinkptr == NULL) { - struct buf *bp = NULL; - - if (H_ISBIGLINK(hp)) - MALLOC(hp->h_symlinkptr, char *, hp->fcbEOF, M_TEMP, M_WAITOK); - - retval = meta_bread(vp, 0, roundup((int)hp->fcbEOF, VTOHFS(vp)->hfs_phys_block_size), - ap->a_cred, &bp); - if (retval) { - if (bp) - brelse(bp); - if (hp->h_symlinkptr) { - FREE(hp->h_symlinkptr, M_TEMP); - hp->h_symlinkptr = NULL; - } - return (retval); - } - - bcopy(bp->b_data, H_SYMLINK(hp), (size_t)hp->fcbEOF); - - if (bp) { - bp->b_flags |= B_INVAL; /* data no longer needed */ - brelse(bp); - } - } - - retval = uiomove((caddr_t)H_SYMLINK(hp), (int)hp->fcbEOF, ap->a_uio); - - return (retval); -} - - -/* - * hfs 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. -#% abortop dvp = = = -# - vop_abortop { - IN struct vnode *dvp; - IN struct componentname *cnp; - - */ - -/* ARGSUSED */ - -static int -hfs_abortop(ap) -struct vop_abortop_args /* { - struct vnode *a_dvp; - struct componentname *a_cnp; -} */ *ap; -{ - DBG_FUNC_NAME("abortop"); - DBG_VOP_LOCKS_DECL(1); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_PRINT_VNODE_INFO(ap->a_dvp); - DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n")); - - - DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_POS); - - if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) { - FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI); - } - DBG_VOP_LOCKS_TEST(E_NONE); - return (E_NONE); -} - -// int prthfsactive = 0; /* 1 => print out reclaim of active vnodes */ - -/* -#% inactive vp L U U -# - vop_inactive { - IN struct vnode *vp; - IN struct proc *p; - -*/ - -static int -hfs_inactive(ap) -struct vop_inactive_args /* { - struct vnode *a_vp; -} */ *ap; -{ - struct vnode *vp = ap->a_vp; - struct hfsnode *hp = VTOH(vp); - struct proc *p = ap->a_p; - struct timeval tv; - int error = 0; - extern int prtactive; - - DBG_FUNC_NAME("inactive"); - DBG_VOP_LOCKS_DECL(1); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); - - DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_ZERO); - - - if (prtactive && vp->v_usecount <= 0) - vprint("hfs_inactive: pushing active", vp); - - if (vp->v_usecount != 0) - DBG_VOP(("%s: bad usecount = %d\n",funcname,vp->v_usecount )); - - /* - * Ignore nodes related to stale file handles. - */ - if (hp->h_meta->h_mode == 0) - goto out; - - /* - * Check for a postponed deletion - */ - if (hp->h_meta->h_metaflags & IN_DELETED) { - hp->h_meta->h_metaflags &= ~IN_DELETED; - - error = vinvalbuf(vp, 0, NOCRED, p, 0, 0); - if (error) goto out; - - if(UBCINFOEXISTS(vp)) - (void)ubc_setsize(vp, (off_t)0); - - /* Lock both trees - * Note: we do not need a lock on the private metadata directory - * since it never has a vnode associated with it. - */ - error = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_EXCLUSIVE | LK_CANRECURSE, p); - if (error) goto out; - error = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_EXCLUSIVE | LK_CANRECURSE, p); - if (error) { - (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, p); - goto out; - } - - if (hp->h_meta->h_metaflags & IN_DATANODE) { - char iNodeName[32]; - - MAKE_INODE_NAME(iNodeName, hp->h_meta->h_indnodeno); - error = hfsDelete(HTOVCB(hp), VTOHFS(vp)->hfs_private_metadata_dir, iNodeName, TRUE, H_HINT(hp)); - } else { - /* XXX can we leave orphaned sibling? */ - error = hfsDelete(HTOVCB(hp), H_DIRID(hp), H_NAME(hp), TRUE, H_HINT(hp)); - if (error == ENOENT) { - /* try by fileID as a backup */ - error = hfsDelete(HTOVCB(hp), H_FILEID(hp), NULL, TRUE, H_HINT(hp)); - } - } - - (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, p); - (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, p); - if (error) goto out; - - hp->h_meta->h_metaflags |= IN_NOEXISTS; - hp->h_meta->h_mode = 0; - /* clear the block mappings */ - hp->fcbPLen = (u_int64_t)0; - bzero(&hp->fcbExtents, sizeof(HFSPlusExtentRecord)); - - hp->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE); - } - - if (hp->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) { - tv = time; - VOP_UPDATE(vp, &tv, &tv, 0); - } - -out: - VOP_UNLOCK(vp, 0, p); - /* - * If we are done with the inode, reclaim it - * so that it can be reused immediately. - */ - if (hp->h_meta->h_mode == 0) - vrecycle(vp, (struct slock *)0, p); - - /* XXX SER Here we might want to get rid of any other forks - * The problem is that if we call vrecycle(), our structure - * disappear from under us, we would need to remember, and expect - * things to go to null or to disappear - * But it stillw would be a good thing to remove vnodes - * referencing stale data - */ - - DBG_VOP_LOCKS_TEST(E_NONE); - return (E_NONE); -} - -/* - Ignored since the locks are gone...... -#% reclaim vp U I I -# - vop_reclaim { - IN struct vnode *vp; - IN struct proc *p; - - */ - -static int -hfs_reclaim(ap) -struct vop_reclaim_args /* { - struct vnode *a_vp; -} */ *ap; -{ - struct vnode *vp = ap->a_vp; - struct hfsnode *hp = VTOH(vp); - void *tdata = vp->v_data; - char *tname; - Boolean freeMeta = true; - struct vnode *devvp = NULL; - - extern int prtactive; - DBG_FUNC_NAME("reclaim"); - DBG_VOP_LOCKS_DECL(1); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); - - DBG_VOP_LOCKS_INIT(0, ap->a_vp, VOPDBG_UNLOCKED, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_ZERO); - - /* - NOTE: XXX vnodes need careful handling because fork vnodes that failed to be - created in their entirity could be getting cleaned up here. - */ - - if (prtactive && vp->v_usecount != 0) - vprint("hfs_reclaim(): pushing active", vp); - - hp->h_nodeflags |= IN_ALLOCATING; /* Mark this as being incomplete */ - /* - * This will remove the entry from the hash AND the sibling list - * This will make sure everything is in a stable state to see if we can remove the meta - * i.e. if this is the only fork...the sibling list will be empty - */ - hfs_vhashrem(hp); - - DBG_ASSERT(tdata != NULL); - DBG_ASSERT(hp->h_meta != NULL); - - devvp = hp->h_meta->h_devvp; /* For later releasing */ - hp->h_meta->h_usecount--; - - /* release the file meta if this is the last fork */ - if (H_FORKTYPE(hp)==kDataFork || H_FORKTYPE(hp)==kRsrcFork) { - if (hp->h_meta->h_siblinghead.cqh_first != (void *) &hp->h_meta->h_siblinghead) - freeMeta = false; - }; - - if (freeMeta) { - DBG_ASSERT(hp->h_meta->h_usecount == 0); - if (hp->h_meta->h_metaflags & IN_LONGNAME) { - tname = H_NAME(hp); - DBG_ASSERT(tname != NULL); - FREE(tname, M_TEMP); - } - FREE_ZONE(hp->h_meta, sizeof(struct hfsfilemeta), M_HFSFMETA); - hp->h_meta = NULL; - } - else - DBG_ASSERT(hp->h_meta->h_usecount == 1); - - /* Dump cached symlink data */ - if ((vp->v_type == VLNK) && (hp->h_symlinkptr != NULL)) { - if (H_ISBIGLINK(hp)) - FREE(hp->h_symlinkptr, M_TEMP); - hp->h_symlinkptr = NULL; - } - - /* - * Purge old data structures associated with the inode. - */ - cache_purge(vp); - if (devvp) { - vrele(devvp); - }; - - /* Free our data structs */ - FREE_ZONE(tdata, sizeof(struct hfsnode), M_HFSNODE); - vp->v_data = NULL; - - DBG_VOP_LOCKS_TEST(E_NONE); - return (E_NONE); -} - - -/* - * Lock an hfsnode. If its already locked, set the WANT bit and sleep. -#% lock vp U L U -# - vop_lock { - IN struct vnode *vp; - IN int flags; - IN struct proc *p; - */ - -static int -hfs_lock(ap) -struct vop_lock_args /* { - struct vnode *a_vp; - int a_flags; - struct proc *a_p; -} */ *ap; -{ - struct vnode * vp = ap->a_vp; - struct hfsnode *hp = VTOH(ap->a_vp); - int retval; - - DBG_FUNC_NAME("lock"); - DBG_VOP_LOCKS_DECL(1); - DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT((" ")); - DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT((" flags = 0x%08X.\n", ap->a_flags)); - DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_UNLOCKED, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_ZERO); - - retval = lockmgr(&hp->h_lock, ap->a_flags, &vp->v_interlock, ap->a_p); - if (retval != E_NONE) { - if ((ap->a_flags & LK_NOWAIT) == 0) - DBG_ERR(("hfs_lock: error %d trying to lock vnode (flags = 0x%08X).\n", retval, ap->a_flags)); - goto Err_Exit; - }; - - if (vp->v_type == VDIR) - hp->h_nodeflags &= ~IN_BYCNID; - -Err_Exit:; - DBG_ASSERT(*((int*)&vp->v_interlock) == 0); - DBG_VOP_LOCKS_TEST(retval); - return (retval); -} - -/* - * Unlock an hfsnode. -#% unlock vp L U L -# - vop_unlock { - IN struct vnode *vp; - IN int flags; - IN struct proc *p; - - */ -int -hfs_unlock(ap) -struct vop_unlock_args /* { - struct vnode *a_vp; - int a_flags; - struct proc *a_p; -} */ *ap; -{ - struct hfsnode *hp = VTOH(ap->a_vp); - struct vnode *vp = ap->a_vp; - int retval = E_NONE; - - DBG_FUNC_NAME("unlock"); - DBG_VOP_LOCKS_DECL(1); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_PRINT_VNODE_INFO(vp);DBG_VOP_CONT((" flags = 0x%08X.\n", ap->a_flags)); - DBG_VOP_LOCKS_INIT(0,vp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_LOCKED, VOPDBG_ZERO); - - if (vp->v_type == VDIR) - hp->h_nodeflags &= ~IN_BYCNID; - - DBG_ASSERT((ap->a_flags & (LK_EXCLUSIVE|LK_SHARED)) == 0); - retval = lockmgr(&hp->h_lock, ap->a_flags | LK_RELEASE, &vp->v_interlock, ap->a_p); - if (retval != E_NONE) { - DEBUG_BREAK_MSG(("hfs_unlock: error %d trying to unlock vnode (forktype = %d).\n", retval, H_FORKTYPE(hp))); - }; - - DBG_ASSERT(*((int*)&vp->v_interlock) == 0); - DBG_VOP_LOCKS_TEST(retval); - return (retval); -} - - -/* - * Print out the contents of an hfsnode. -#% print vp = = = -# - vop_print { - IN struct vnode *vp; - */ -int -hfs_print(ap) -struct vop_print_args /* { - struct vnode *a_vp; -} */ *ap; -{ - register struct vnode * vp = ap->a_vp; - register struct hfsnode *hp = VTOH( vp); - DBG_FUNC_NAME("print"); - DBG_VOP_LOCKS_DECL(1); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_PRINT_VNODE_INFO(ap->a_vp); - - DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_POS); - - printf("tag VT_HFS, dirID %d, on dev %d, %d", H_DIRID(hp), - major(H_DEV(hp)), minor(H_DEV(hp))); - /* lockmgr_printinfo(&hp->h_lock); */ - printf("\n"); - DBG_VOP_LOCKS_TEST(E_NONE); - return (E_NONE); -} - - -/* - * Check for a locked hfsnode. -#% islocked vp = = = -# - vop_islocked { - IN struct vnode *vp; - - */ -int -hfs_islocked(ap) -struct vop_islocked_args /* { - struct vnode *a_vp; -} */ *ap; -{ - int lockStatus; - //DBG_FUNC_NAME("islocked"); - //DBG_VOP_LOCKS_DECL(1); - //DBG_VOP_PRINT_FUNCNAME(); - //DBG_VOP_PRINT_VNODE_INFO(ap->a_vp); - - //DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_ZERO); - - lockStatus = lockstatus(&VTOH( ap->a_vp)->h_lock); - //DBG_VOP_LOCKS_TEST(E_NONE); - return (lockStatus); -} - -/* - -#% pathconf vp L L L -# - vop_pathconf { - IN struct vnode *vp; - IN int name; - OUT register_t *retval; - - */ -static int -hfs_pathconf(ap) -struct vop_pathconf_args /* { - struct vnode *a_vp; - int a_name; - int *a_retval; -} */ *ap; -{ - int retval = E_NONE; - DBG_FUNC_NAME("pathconf"); - DBG_VOP_LOCKS_DECL(1); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_PRINT_VNODE_INFO(ap->a_vp); - - DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS); - - DBG_HFS_NODE_CHECK (ap->a_vp); - - switch (ap->a_name) { - case _PC_LINK_MAX: -#if HFS_HARDLINKS - if (VTOVCB(ap->a_vp)->vcbSigWord == kHFSPlusSigWord) - *ap->a_retval = HFS_LINK_MAX; - else - *ap->a_retval = 1; -#else - *ap->a_retval = 1; -#endif - break; - case _PC_NAME_MAX: - *ap->a_retval = kHFSPlusMaxFileNameBytes; /* max # of characters x max utf8 representation */ - break; - case _PC_PATH_MAX: - *ap->a_retval = PATH_MAX; /* 1024 */ - break; - case _PC_CHOWN_RESTRICTED: - *ap->a_retval = 1; - break; - case _PC_NO_TRUNC: - *ap->a_retval = 0; - break; - case _PC_NAME_CHARS_MAX: - *ap->a_retval = kHFSPlusMaxFileNameChars; - break; - case _PC_CASE_SENSITIVE: - *ap->a_retval = 0; - break; - case _PC_CASE_PRESERVING: - *ap->a_retval = 1; - break; - default: - retval = EINVAL; - } - - DBG_VOP_LOCKS_TEST(retval); - return (retval); -} - - - - - -/* - * Advisory record locking support -#% advlock vp U U U -# - vop_advlock { - IN struct vnode *vp; - IN caddr_t id; - IN int op; - IN struct flock *fl; - IN int flags; - - */ -int -hfs_advlock(ap) -struct vop_advlock_args /* { - struct vnode *a_vp; - caddr_t a_id; - int a_op; - struct flock *a_fl; - int a_flags; -} */ *ap; -{ - register struct hfsnode *hp = VTOH(ap->a_vp); - register struct flock *fl = ap->a_fl; - register struct hfslockf *lock; - off_t start, end; - int retval; - DBG_FUNC_NAME("advlock"); - DBG_VOP_LOCKS_DECL(1); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP(("\n")); - DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); - /* - * Avoid the common case of unlocking when inode has no locks. - */ - if (hp->h_lockf == (struct hfslockf *)0) { - if (ap->a_op != F_SETLK) { - fl->l_type = F_UNLCK; - return (0); - } - } - /* - * Convert the flock structure into a start and end. - */ - start = 0; - 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 = HTOFCB(hp)->fcbEOF + 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 hfslockf structure - */ - MALLOC(lock, struct hfslockf *, sizeof *lock, M_LOCKF, M_WAITOK); - lock->lf_start = start; - lock->lf_end = end; - lock->lf_id = ap->a_id; - lock->lf_hfsnode = hp; - lock->lf_type = fl->l_type; - lock->lf_next = (struct hfslockf *)0; - TAILQ_INIT(&lock->lf_blkhd); - lock->lf_flags = ap->a_flags; - /* - * Do the requested operation. - */ - switch(ap->a_op) { - case F_SETLK: - retval = hfs_setlock(lock); - break; - - case F_UNLCK: - retval = hfs_clearlock(lock); - FREE(lock, M_LOCKF); - break; - - case F_GETLK: - retval = hfs_getlock(lock, fl); - FREE(lock, M_LOCKF); - break; - - default: - retval = EINVAL; - _FREE(lock, M_LOCKF); - break; - } - - DBG_VOP_LOCKS_TEST(retval); - return (retval); -} - - - -/* - * Update the access, modified, and node change times as specified by the - * IACCESS, IUPDATE, and ICHANGE flags respectively. The IMODIFIED flag is - * used to specify that the node 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 node change time is always taken from the current - * time. If waitfor is set, then wait for the disk write of the node to - * complete. - */ -/* -#% update vp L L L - IN struct vnode *vp; - IN struct timeval *access; - IN struct timeval *modify; - IN int waitfor; -*/ - -int -hfs_update(ap) - struct vop_update_args /* { - struct vnode *a_vp; - struct timeval *a_access; - struct timeval *a_modify; - int a_waitfor; - } */ *ap; -{ - struct hfsnode *hp; - struct proc *p; - hfsCatalogInfo catInfo; - char *filename; - char iNodeName[32]; - u_int32_t pid; - int retval; - ExtendedVCB *vcb; - DBG_FUNC_NAME("update"); - DBG_VOP_LOCKS_DECL(1); - DBG_VOP_PRINT_FUNCNAME(); - DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); - DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_ZERO); - - hp = VTOH(ap->a_vp); - - DBG_ASSERT(hp && hp->h_meta); - DBG_ASSERT(*((int*)&ap->a_vp->v_interlock) == 0); - - if ((H_FORKTYPE(hp) == kSysFile) || - (VTOVFS(ap->a_vp)->mnt_flag & MNT_RDONLY) || - (hp->h_meta->h_mode == 0)) { - hp->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE); - DBG_VOP_LOCKS_TEST(0); - return (0); - } - - if (H_FORKTYPE(hp) == kSysFile) { - hp->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE); - DBG_VOP_LOCKS_TEST(0); - return (0); - } - - if (VTOVFS(ap->a_vp)->mnt_flag & MNT_RDONLY) { - hp->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE); - DBG_VOP_LOCKS_TEST(0); - return (0); - } - - /* Check to see if MacOS set the fcb to be dirty, if so, translate it to IN_MODIFIED */ - if (HTOFCB(hp)->fcbFlags &fcbModifiedMask) - hp->h_nodeflags |= IN_MODIFIED; - - if ((hp->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0) { - DBG_VOP_LOCKS_TEST(0); - return (0); - }; - - if (hp->h_nodeflags & IN_ACCESS) - hp->h_meta->h_atime = ap->a_access->tv_sec; - if (hp->h_nodeflags & IN_UPDATE) - hp->h_meta->h_mtime = ap->a_modify->tv_sec; - if (hp->h_nodeflags & IN_CHANGE) { - hp->h_meta->h_ctime = time.tv_sec; - /* - * HFS dates that WE set must be adjusted for DST - */ - if ((HTOVCB(hp)->vcbSigWord == kHFSSigWord) && gTimeZone.tz_dsttime) { - hp->h_meta->h_ctime += 3600; - hp->h_meta->h_mtime = hp->h_meta->h_ctime; - } - } - - p = current_proc(); - filename = H_NAME(hp); - pid = H_DIRID(hp); - vcb = HTOVCB(hp); - catInfo.hint = H_HINT(hp); - -#if HFS_HARDLINKS - /* - * Force an update of the indirect node instead of the link - * by using the name and parent of the indirect node. - */ - if (hp->h_meta->h_metaflags & IN_DATANODE) { - MAKE_INODE_NAME(iNodeName, hp->h_meta->h_indnodeno); - filename = iNodeName; - pid = VCBTOHFS(vcb)->hfs_private_metadata_dir; - } -#endif - - INIT_CATALOGDATA(&catInfo.nodeData, kCatNameNoCopyName); - - /* - * Since VOP_UPDATE can be called from withing another VOP (eg VOP_RENAME), - * the Catalog b-tree may aready be locked by the current thread. So we - * allow recursive locking of the Catalog from within VOP_UPDATE. - */ - /* Lock the Catalog b-tree file */ - retval = hfs_metafilelocking(HTOHFS(hp), kHFSCatalogFileID, LK_EXCLUSIVE | LK_CANRECURSE, p); - if (retval) { - DBG_VOP_LOCKS_TEST(retval); - return (retval); - }; - - retval = hfs_getcatalog(vcb, pid, filename, -1, &catInfo); - if (retval != noErr) { - (void) hfs_metafilelocking(HTOHFS(hp), kHFSCatalogFileID, LK_RELEASE, p); - retval = MacToVFSError(retval); - goto Err_Exit; - }; - - H_HINT(hp) = catInfo.hint; - CopyVNodeToCatalogNode (HTOV(hp), &catInfo.nodeData); - - retval = UpdateCatalogNode(vcb, pid, filename, H_HINT(hp), &catInfo.nodeData); - - /* unlock the Catalog b-tree file */ - (void) hfs_metafilelocking(HTOHFS(hp), kHFSCatalogFileID, LK_RELEASE, p); - - if (retval != noErr) { /* from UpdateCatalogNode() */ - retval = MacToVFSError(retval); - goto Err_Exit; - }; - - /* After the updates are finished, clear the flags */ - hp->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE); - HTOFCB(hp)->fcbFlags &= ~fcbModifiedMask; - - /* Update general data */ - if (ap->a_vp->v_type == VDIR) { - hp->h_meta->h_nlink = 2 + catInfo.nodeData.cnd_valence; - hp->h_meta->h_size = sizeof(rootdots) + - (catInfo.nodeData.cnd_valence * AVERAGE_HFSDIRENTRY_SIZE); - if (hp->h_meta->h_size < MAX_HFSDIRENTRY_SIZE) - hp->h_meta->h_size < MAX_HFSDIRENTRY_SIZE; - } else { - hp->h_meta->h_size = (off_t)vcb->blockSize * - (off_t)(catInfo.nodeData.cnd_rsrcfork.totalBlocks + - catInfo.nodeData.cnd_datafork.totalBlocks); - } - - -Err_Exit: - - CLEAN_CATALOGDATA(&catInfo.nodeData); - - DBG_VOP_LOCKS_TEST(retval); - return (retval); -} - - -/* - * Initialize the vnode associated with a new hfsnode, - * handle aliased vnodes. - */ -int -hfs_vinit(mntp, specops, fifoops, vpp) - struct mount *mntp; - int (**specops)(void *); - int (**fifoops)(void *); - struct vnode **vpp; -{ - struct hfsnode *hp; - struct vnode *vp, *nvp; - - vp = *vpp; - hp = VTOH(vp); - /* vp->v_type set in CopyCatalogToHFSNode */ - switch(vp->v_type) { - case VCHR: - case VBLK: - vp->v_op = specops; - if ((nvp = checkalias(vp, hp->h_meta->h_rdev, mntp))) { - /* - * Discard unneeded vnode, but save its hfsnode. - * Note that the lock is carried over in the hfsnode - * to the replacement vnode. - */ - nvp->v_data = vp->v_data; - vp->v_data = NULL; - vp->v_op = spec_vnodeop_p; - vrele(vp); - vgone(vp); - /* - * Reinitialize aliased hfsnode. - */ - - hp->h_vp = nvp; - vp = nvp; - } - break; - case VFIFO: -#if FIFO - vp->v_op = fifoops; - break; -#else - return (EOPNOTSUPP); -#endif - default: - break; - } - if (H_FILEID(hp) == kRootDirID) - vp->v_flag |= VROOT; - - *vpp = vp; - return (0); -} - -/* - * Allocate a new node - * - * Upon leaving, namei buffer must be freed. - * - */ -static int -hfs_makenode(mode, rawdev, dvp, vpp, cnp, p) - int mode; - dev_t rawdev; - struct vnode *dvp; - struct vnode **vpp; - struct componentname *cnp; - struct proc *p; -{ - register struct hfsnode *hp, *parhp; - struct timeval tv; - struct vnode *tvp; - struct hfsCatalogInfo catInfo; - ExtendedVCB *vcb; - UInt8 forkType; - int retval; - int hasmetalock = 0; - u_int32_t tehint = 0; - DBG_FUNC_NAME("makenode"); - - parhp = VTOH(dvp); - vcb = HTOVCB(parhp); - *vpp = NULL; - tvp = NULL; - if ((mode & IFMT) == 0) - mode |= IFREG; - -#if HFS_DIAGNOSTIC - if ((cnp->cn_flags & HASBUF) == 0) - panic("hfs_makenode: no name"); -#endif - - /* lock catalog b-tree */ - retval = hfs_metafilelocking(VTOHFS(dvp), - kHFSCatalogFileID, LK_EXCLUSIVE, p); - if (retval != E_NONE) - goto bad1; - else - hasmetalock = 1; - - /* - * Force Carbon creates to have MacUnicode encoding - */ - if ((parhp->h_nodeflags & IN_BYCNID) && (!ISSET(p->p_flag, P_TBE))) { - tehint = kTextEncodingMacUnicode; - } - - /* Create the Catalog B*-Tree entry */ - retval = hfsCreate(vcb, H_FILEID(parhp), cnp->cn_nameptr, mode, tehint); - if (retval != E_NONE) { - DBG_ERR(("%s: hfsCreate FAILED: %s, %s\n", funcname, cnp->cn_nameptr, H_NAME(parhp))); - goto bad1; - } - - /* Look up the catalog entry just created: */ - INIT_CATALOGDATA(&catInfo.nodeData, 0); - catInfo.hint = kNoHint; - - retval = hfs_getcatalog(vcb, H_FILEID(parhp), cnp->cn_nameptr, cnp->cn_namelen, &catInfo); - if (retval != E_NONE) { - DBG_ERR(("%s: hfs_getcatalog FAILED: %s, %s\n", funcname, cnp->cn_nameptr, H_NAME(parhp))); - goto bad1; - } - - /* unlock catalog b-tree */ - hasmetalock = 0; - (void) hfs_metafilelocking(VTOHFS(dvp), - kHFSCatalogFileID, LK_RELEASE, p); - - /* hfs plus has additional metadata to initialize */ - if (vcb->vcbSigWord == kHFSPlusSigWord) { - u_int32_t pflags; - int catmode; - - if (VTOVFS(dvp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) { - catInfo.nodeData.cnd_ownerID = VTOHFS(dvp)->hfs_uid; - catInfo.nodeData.cnd_groupID = VTOHFS(dvp)->hfs_gid; - catmode = mode; - } else { - catInfo.nodeData.cnd_ownerID = cnp->cn_cred->cr_uid; - catInfo.nodeData.cnd_groupID = parhp->h_meta->h_gid; - catmode = mode; - } - - switch (catmode & IFMT) { - case IFLNK: - catInfo.nodeData.cnd_ownerID = parhp->h_meta->h_uid; - break; - - case IFCHR: - case IFBLK: - /* XXX should we move this to post hfsGet? */ - catInfo.nodeData.cnd_rawDevice = rawdev; - /* - * Don't tag as a special file (BLK or CHR) until *after* - * hfsGet is called. This insures that the checkalias call - * is defered until hfs_mknod completes. - */ - catmode = (catmode & ~IFMT) | IFREG; - break; - } - - if ((catmode & ISGID) && !groupmember(parhp->h_meta->h_gid, cnp->cn_cred) && - suser(cnp->cn_cred, NULL)) - catmode &= ~ISGID; - - if (cnp->cn_flags & ISWHITEOUT) - pflags = UF_OPAQUE; - else - pflags = 0; - - /* - * The 32-bit pflags field has two bytes of significance which - * are stored separately as admin and owner flags. - * - * +------------------------------------+ - * pflags: |XXXXXXXX| SF |XXXXXXXX| UF | - * +------------------------------------+ - */ - catInfo.nodeData.cnd_adminFlags = (pflags >> 16) & 0x00FF; - catInfo.nodeData.cnd_ownerFlags = pflags & 0x00FF; - catInfo.nodeData.cnd_mode = catmode; - } - - /* Create a vnode for the object just created: */ - forkType = (catInfo.nodeData.cnd_type == kCatalogFolderNode) ? kDirectory : kDataFork; - retval = hfs_vcreate(vcb, &catInfo, forkType, &tvp); - - CLEAN_CATALOGDATA(&catInfo.nodeData); /* Should do nothing */ - - if (retval) goto bad1; /* from hfs_vcreate() */ - - /* flush out pflags, mode, gid, uid and rdev */ - tv = time; - if (vcb->vcbSigWord == kHFSPlusSigWord) { - hp = VTOH(tvp); - /* reset mode and v_type in case it was BLK/CHR */ - hp->h_meta->h_mode = mode; - tvp->v_type = IFTOVT(mode); - hp->h_meta->h_metaflags &= ~IN_UNSETACCESS; - hp->h_nodeflags |= IN_ACCESS | IN_CHANGE | IN_UPDATE; - if ((retval = VOP_UPDATE(tvp, &tv, &tv, 1))) - goto bad2; - } - - VTOH(dvp)->h_nodeflags |= IN_CHANGE | IN_UPDATE; - if ((retval = VOP_UPDATE(dvp, &tv, &tv, 1))) - goto bad2; - - if ((cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) { - FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI); - }; - vput(dvp); - if (UBCINFOMISSING(tvp) || UBCINFORECLAIMED(tvp)) - ubc_info_init(tvp); - - *vpp = tvp; - return (0); - -bad2: - /* - * Write retval occurred trying to update the node - * or the directory so must deallocate the node. - */ - /* XXX SER In the future maybe set *vpp to 0xdeadbeef for testing */ - vput(tvp); - -bad1: - if (hasmetalock) { - /* unlock catalog b-tree */ - hasmetalock = 0; - (void) hfs_metafilelocking(VTOHFS(dvp), - kHFSCatalogFileID, LK_RELEASE, p); - } - if ((cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) { - FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI); - }; - vput(dvp); - - return (retval); -} - - -#if DBG_VOP_TEST_LOCKS - -/* XXX SER Add passing in the flags...might not be a serious error if locked */ - -void DbgVopTest( int maxSlots, - int retval, - VopDbgStoreRec *VopDbgStore, - char *funcname) -{ - int index; - - for (index = 0; index < maxSlots; index++) - { - if (VopDbgStore[index].id != index) { - DEBUG_BREAK_MSG(("%s: DBG_VOP_LOCK: invalid id field (%d) in target entry (#%d).\n", funcname, VopDbgStore[index].id, index)); - }; - - if ((VopDbgStore[index].vp != NULL) && - ((VopDbgStore[index].vp->v_data==NULL) || (VTOH(VopDbgStore[index].vp)->h_valid != HFS_VNODE_MAGIC))) - continue; - - if (VopDbgStore[index].vp != NULL) - debug_check_vnode(VopDbgStore[index].vp, 0); - - switch (VopDbgStore[index].inState) - { - case VOPDBG_IGNORE: - case VOPDBG_SAME: - /* Do Nothing !!! */ - break; - case VOPDBG_LOCKED: - case VOPDBG_UNLOCKED: - case VOPDBG_LOCKNOTNIL: - { - if (VopDbgStore[index].vp == NULL && (VopDbgStore[index].inState != VOPDBG_LOCKNOTNIL)) { - DBG_ERR (("%s: InState check: Null vnode ptr in entry #%d\n", funcname, index)); - } else if (VopDbgStore[index].vp != NULL) { - switch (VopDbgStore[index].inState) - { - case VOPDBG_LOCKED: - case VOPDBG_LOCKNOTNIL: - if (VopDbgStore[index].inValue == 0) - { - DBG_ERR (("%s: Entry: not LOCKED:", funcname)); - DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp); - DBG_ERR (("\n")); - } - break; - case VOPDBG_UNLOCKED: - if (VopDbgStore[index].inValue != 0) - { - DBG_ERR (("%s: Entry: not UNLOCKED:", funcname)); - DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp); - DBG_ERR (("\n")); - } - break; - } - } - break; - } - default: - DBG_ERR (("%s: DBG_VOP_LOCK on entry: bad lock test value: %d\n", funcname, VopDbgStore[index].errState)); - } - - - if (retval != 0) - { - switch (VopDbgStore[index].errState) - { - case VOPDBG_IGNORE: - /* Do Nothing !!! */ - break; - case VOPDBG_LOCKED: - case VOPDBG_UNLOCKED: - case VOPDBG_SAME: - { - if (VopDbgStore[index].vp == NULL) { - DBG_ERR (("%s: ErrState check: Null vnode ptr in entry #%d\n", funcname, index)); - } else { - VopDbgStore[index].outValue = lockstatus(&VTOH(VopDbgStore[index].vp)->h_lock); - switch (VopDbgStore[index].errState) - { - case VOPDBG_LOCKED: - if (VopDbgStore[index].outValue == 0) - { - DBG_ERR (("%s: Error: not LOCKED:", funcname)); - DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp); - DBG_ERR(("\n")); - } - break; - case VOPDBG_UNLOCKED: - if (VopDbgStore[index].outValue != 0) - { - DBG_ERR (("%s: Error: not UNLOCKED:", funcname)); - DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp); - DBG_ERR(("\n")); - } - break; - case VOPDBG_SAME: - if (VopDbgStore[index].outValue != VopDbgStore[index].inValue) - DBG_ERR (("%s: Error: In/Out locks are DIFFERENT: 0x%x, inis %d and out is %d\n", funcname, (u_int)VopDbgStore[index].vp, VopDbgStore[index].inValue, VopDbgStore[index].outValue)); - break; - } - } - break; - } - case VOPDBG_LOCKNOTNIL: - if (VopDbgStore[index].vp != NULL) { - VopDbgStore[index].outValue = lockstatus(&VTOH(VopDbgStore[index].vp)->h_lock); - if (VopDbgStore[index].outValue == 0) - DBG_ERR (("%s: Error: Not LOCKED: 0x%x\n", funcname, (u_int)VopDbgStore[index].vp)); - } - break; - default: - DBG_ERR (("%s: Error: bad lock test value: %d\n", funcname, VopDbgStore[index].errState)); - } - } - else - { - switch (VopDbgStore[index].outState) - { - case VOPDBG_IGNORE: - /* Do Nothing !!! */ - break; - case VOPDBG_LOCKED: - case VOPDBG_UNLOCKED: - case VOPDBG_SAME: - if (VopDbgStore[index].vp == NULL) { - DBG_ERR (("%s: OutState: Null vnode ptr in entry #%d\n", funcname, index)); - }; - if (VopDbgStore[index].vp != NULL) - { - VopDbgStore[index].outValue = lockstatus(&VTOH(VopDbgStore[index].vp)->h_lock); - switch (VopDbgStore[index].outState) - { - case VOPDBG_LOCKED: - if (VopDbgStore[index].outValue == 0) - { - DBG_ERR (("%s: Out: not LOCKED:", funcname)); - DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp); - DBG_ERR (("\n")); - } - break; - case VOPDBG_UNLOCKED: - if (VopDbgStore[index].outValue != 0) - { - DBG_ERR (("%s: Out: not UNLOCKED:", funcname)); - DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp); - DBG_ERR (("\n")); - } - break; - case VOPDBG_SAME: - if (VopDbgStore[index].outValue != VopDbgStore[index].inValue) - DBG_ERR (("%s: Out: In/Out locks are DIFFERENT: 0x%x, in is %d and out is %d\n", funcname, (u_int)VopDbgStore[index].vp, VopDbgStore[index].inValue, VopDbgStore[index].outValue)); - break; - } - } - break; - case VOPDBG_LOCKNOTNIL: - if (VopDbgStore[index].vp != NULL) { - if (&VTOH(VopDbgStore[index].vp)->h_lock == NULL) { - DBG_ERR (("%s: DBG_VOP_LOCK on out: Null lock on vnode 0x%x\n", funcname, (u_int)VopDbgStore[index].vp)); - } - else { - VopDbgStore[index].outValue = lockstatus(&VTOH(VopDbgStore[index].vp)->h_lock); - if (VopDbgStore[index].outValue == 0) - { - DBG_ERR (("%s: DBG_VOP_LOCK on out: Should be LOCKED:", funcname)); - DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp); DBG_ERR (("\n")); - } - } - } - break; - default: - DBG_ERR (("%s: DBG_VOP_LOCK on out: bad lock test value: %d\n", funcname, VopDbgStore[index].outState)); - } - } - - VopDbgStore[index].id = -1; /* Invalidate the entry to allow panic-free re-use */ - } -} - -#endif /* DBG_VOP_TEST_LOCKS */ - -/* - * Wrapper for special device reads - */ -int -hfsspec_read(ap) - struct vop_read_args /* { - struct vnode *a_vp; - struct uio *a_uio; - int a_ioflag; - struct ucred *a_cred; - } */ *ap; -{ - - /* - * Set access flag. - */ - VTOH(ap->a_vp)->h_nodeflags |= IN_ACCESS; - return (VOCALL (spec_vnodeop_p, VOFFSET(vop_read), ap)); -} - -/* - * Wrapper for special device writes - */ -int -hfsspec_write(ap) - struct vop_write_args /* { - struct vnode *a_vp; - struct uio *a_uio; - int a_ioflag; - struct ucred *a_cred; - } */ *ap; -{ - - /* - * Set update and change flags. - */ - VTOH(ap->a_vp)->h_nodeflags |= IN_CHANGE | IN_UPDATE; - return (VOCALL (spec_vnodeop_p, VOFFSET(vop_write), ap)); -} - -/* - * Wrapper for special device close - * - * Update the times on the hfsnode then do device close. - */ -int -hfsspec_close(ap) - struct vop_close_args /* { - struct vnode *a_vp; - int a_fflag; - struct ucred *a_cred; - struct proc *a_p; - } */ *ap; -{ - struct vnode *vp = ap->a_vp; - struct hfsnode *hp = VTOH(vp); - - simple_lock(&vp->v_interlock); - if (ap->a_vp->v_usecount > 1) - HFSTIMES(hp, &time, &time); - simple_unlock(&vp->v_interlock); - return (VOCALL (spec_vnodeop_p, VOFFSET(vop_close), ap)); -} - -#if FIFO -/* - * Wrapper for fifo reads - */ -int -hfsfifo_read(ap) - struct vop_read_args /* { - struct vnode *a_vp; - struct uio *a_uio; - int a_ioflag; - struct ucred *a_cred; - } */ *ap; -{ - extern int (**fifo_vnodeop_p)(void *); - - /* - * Set access flag. - */ - VTOH(ap->a_vp)->h_nodeflags |= IN_ACCESS; - return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_read), ap)); -} - -/* - * Wrapper for fifo writes - */ -int -hfsfifo_write(ap) - struct vop_write_args /* { - struct vnode *a_vp; - struct uio *a_uio; - int a_ioflag; - struct ucred *a_cred; - } */ *ap; -{ - extern int (**fifo_vnodeop_p)(void *); - - /* - * Set update and change flags. - */ - VTOH(ap->a_vp)->h_nodeflags |= IN_CHANGE | IN_UPDATE; - return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_write), ap)); -} - -/* - * Wrapper for fifo close - * - * Update the times on the hfsnode then do device close. - */ -int -hfsfifo_close(ap) - struct vop_close_args /* { - struct vnode *a_vp; - int a_fflag; - struct ucred *a_cred; - struct proc *a_p; - } */ *ap; -{ - extern int (**fifo_vnodeop_p)(void *); - struct vnode *vp = ap->a_vp; - struct hfsnode *hp = VTOH(vp); - - simple_lock(&vp->v_interlock); - if (ap->a_vp->v_usecount > 1) - HFSTIMES(hp, &time, &time); - simple_unlock(&vp->v_interlock); - return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_close), ap)); -} -#endif /* FIFO */ - - -/***************************************************************************** -* -* VOP Tables -* -*****************************************************************************/ - -#define VOPFUNC int (*)(void *) - -struct vnodeopv_entry_desc hfs_vnodeop_entries[] = { - { &vop_default_desc, (VOPFUNC)vn_default_error }, - { &vop_lookup_desc, (VOPFUNC)hfs_cache_lookup }, /* lookup */ - { &vop_create_desc, (VOPFUNC)hfs_create }, /* create */ - { &vop_mknod_desc, (VOPFUNC)hfs_mknod }, /* mknod */ - { &vop_open_desc, (VOPFUNC)hfs_open }, /* open */ - { &vop_close_desc, (VOPFUNC)hfs_close }, /* close */ - { &vop_access_desc, (VOPFUNC)hfs_access }, /* access */ - { &vop_getattr_desc, (VOPFUNC)hfs_getattr }, /* getattr */ - { &vop_setattr_desc, (VOPFUNC)hfs_setattr }, /* setattr */ - { &vop_read_desc, (VOPFUNC)hfs_read }, /* read */ - { &vop_write_desc, (VOPFUNC)hfs_write }, /* write */ - { &vop_ioctl_desc, (VOPFUNC)hfs_ioctl }, /* ioctl */ - { &vop_select_desc, (VOPFUNC)hfs_select }, /* select */ - { &vop_exchange_desc, (VOPFUNC)hfs_exchange }, /* exchange */ - { &vop_mmap_desc, (VOPFUNC)hfs_mmap }, /* mmap */ - { &vop_fsync_desc, (VOPFUNC)hfs_fsync }, /* fsync */ - { &vop_seek_desc, (VOPFUNC)hfs_seek }, /* seek */ - { &vop_remove_desc, (VOPFUNC)hfs_remove }, /* remove */ -#if HFS_HARDLINKS - { &vop_link_desc, (VOPFUNC)hfs_link }, /* link */ -#else - { &vop_link_desc, (VOPFUNC)err_link }, /* link (NOT SUPPORTED) */ -#endif - { &vop_rename_desc, (VOPFUNC)hfs_rename }, /* rename */ - { &vop_mkdir_desc, (VOPFUNC)hfs_mkdir }, /* mkdir */ - { &vop_rmdir_desc, (VOPFUNC)hfs_rmdir }, /* rmdir */ - { &vop_mkcomplex_desc, (VOPFUNC)hfs_mkcomplex }, /* mkcomplex */ - { &vop_getattrlist_desc, (VOPFUNC)hfs_getattrlist }, /* getattrlist */ - { &vop_setattrlist_desc, (VOPFUNC)hfs_setattrlist }, /* setattrlist */ - { &vop_symlink_desc, (VOPFUNC)hfs_symlink }, /* symlink */ - { &vop_readdir_desc, (VOPFUNC)hfs_readdir }, /* readdir */ - { &vop_readdirattr_desc, (VOPFUNC)hfs_readdirattr }, /* readdirattr */ - { &vop_readlink_desc, (VOPFUNC)hfs_readlink }, /* readlink */ - { &vop_abortop_desc, (VOPFUNC)hfs_abortop }, /* abortop */ - { &vop_inactive_desc, (VOPFUNC)hfs_inactive }, /* inactive */ - { &vop_reclaim_desc, (VOPFUNC)hfs_reclaim }, /* reclaim */ - { &vop_lock_desc, (VOPFUNC)hfs_lock }, /* lock */ - { &vop_unlock_desc, (VOPFUNC)hfs_unlock }, /* unlock */ - { &vop_bmap_desc, (VOPFUNC)hfs_bmap }, /* bmap */ - { &vop_strategy_desc, (VOPFUNC)hfs_strategy }, /* strategy */ - { &vop_print_desc, (VOPFUNC)hfs_print }, /* print */ - { &vop_islocked_desc, (VOPFUNC)hfs_islocked }, /* islocked */ - { &vop_pathconf_desc, (VOPFUNC)hfs_pathconf }, /* pathconf */ - { &vop_advlock_desc, (VOPFUNC)hfs_advlock }, /* advlock */ - { &vop_reallocblks_desc, (VOPFUNC)hfs_reallocblks }, /* reallocblks */ - { &vop_truncate_desc, (VOPFUNC)hfs_truncate }, /* truncate */ - { &vop_allocate_desc, (VOPFUNC)hfs_allocate }, /* allocate */ - { &vop_update_desc, (VOPFUNC)hfs_update }, /* update */ - { &vop_searchfs_desc, (VOPFUNC)hfs_search }, /* search fs */ - { &vop_bwrite_desc, (VOPFUNC)hfs_bwrite }, /* bwrite */ - { &vop_pagein_desc, (VOPFUNC)hfs_pagein }, /* pagein */ - { &vop_pageout_desc,(VOPFUNC) hfs_pageout }, /* pageout */ - { &vop_copyfile_desc, (VOPFUNC)err_copyfile }, /* copyfile */ - { &vop_blktooff_desc, (VOPFUNC)hfs_blktooff }, /* blktooff */ - { &vop_offtoblk_desc, (VOPFUNC)hfs_offtoblk }, /* offtoblk */ - { &vop_cmap_desc, (VOPFUNC)hfs_cmap }, /* cmap */ - { NULL, (VOPFUNC)NULL } -}; - -struct vnodeopv_desc hfs_vnodeop_opv_desc = -{ &hfs_vnodeop_p, hfs_vnodeop_entries }; - -int (**hfs_specop_p)(void *); -struct vnodeopv_entry_desc hfs_specop_entries[] = { - { &vop_default_desc, (VOPFUNC)vn_default_error }, - { &vop_lookup_desc, (VOPFUNC)spec_lookup }, /* lookup */ - { &vop_create_desc, (VOPFUNC)spec_create }, /* create */ - { &vop_mknod_desc, (VOPFUNC)spec_mknod }, /* mknod */ - { &vop_open_desc, (VOPFUNC)spec_open }, /* open */ - { &vop_close_desc, (VOPFUNC)hfsspec_close }, /* close */ - { &vop_access_desc, (VOPFUNC)hfs_access }, /* access */ - { &vop_getattr_desc, (VOPFUNC)hfs_getattr }, /* getattr */ - { &vop_setattr_desc, (VOPFUNC)hfs_setattr }, /* setattr */ - { &vop_read_desc, (VOPFUNC)hfsspec_read }, /* read */ - { &vop_write_desc, (VOPFUNC)hfsspec_write }, /* write */ - { &vop_lease_desc, (VOPFUNC)spec_lease_check }, /* lease */ - { &vop_ioctl_desc, (VOPFUNC)spec_ioctl }, /* ioctl */ - { &vop_select_desc, (VOPFUNC)spec_select }, /* select */ - { &vop_revoke_desc, (VOPFUNC)spec_revoke }, /* revoke */ - { &vop_mmap_desc, (VOPFUNC)spec_mmap }, /* mmap */ - { &vop_fsync_desc, (VOPFUNC)hfs_fsync }, /* fsync */ - { &vop_seek_desc, (VOPFUNC)spec_seek }, /* seek */ - { &vop_remove_desc, (VOPFUNC)spec_remove }, /* remove */ - { &vop_link_desc, (VOPFUNC)spec_link }, /* link */ - { &vop_rename_desc, (VOPFUNC)spec_rename }, /* rename */ - { &vop_mkdir_desc, (VOPFUNC)spec_mkdir }, /* mkdir */ - { &vop_rmdir_desc, (VOPFUNC)spec_rmdir }, /* rmdir */ - { &vop_symlink_desc, (VOPFUNC)spec_symlink }, /* symlink */ - { &vop_readdir_desc, (VOPFUNC)spec_readdir }, /* readdir */ - { &vop_readlink_desc, (VOPFUNC)spec_readlink }, /* readlink */ - { &vop_abortop_desc, (VOPFUNC)spec_abortop }, /* abortop */ - { &vop_inactive_desc, (VOPFUNC)hfs_inactive }, /* inactive */ - { &vop_reclaim_desc, (VOPFUNC)hfs_reclaim }, /* reclaim */ - { &vop_lock_desc, (VOPFUNC)hfs_lock }, /* lock */ - { &vop_unlock_desc, (VOPFUNC)hfs_unlock }, /* unlock */ - { &vop_bmap_desc, (VOPFUNC)spec_bmap }, /* bmap */ - { &vop_strategy_desc, (VOPFUNC)spec_strategy }, /* strategy */ - { &vop_print_desc, (VOPFUNC)hfs_print }, /* print */ - { &vop_islocked_desc, (VOPFUNC)hfs_islocked }, /* islocked */ - { &vop_pathconf_desc, (VOPFUNC)spec_pathconf }, /* pathconf */ - { &vop_advlock_desc, (VOPFUNC)spec_advlock }, /* advlock */ - { &vop_blkatoff_desc, (VOPFUNC)spec_blkatoff }, /* blkatoff */ - { &vop_valloc_desc, (VOPFUNC)spec_valloc }, /* valloc */ - { &vop_reallocblks_desc, (VOPFUNC)spec_reallocblks }, /* reallocblks */ - { &vop_vfree_desc, (VOPFUNC)err_vfree }, /* vfree */ - { &vop_truncate_desc, (VOPFUNC)spec_truncate }, /* truncate */ - { &vop_update_desc, (VOPFUNC)hfs_update }, /* update */ - { &vop_bwrite_desc, (VOPFUNC)hfs_bwrite }, - { &vop_devblocksize_desc, (VOPFUNC)spec_devblocksize }, /* devblocksize */ - { &vop_pagein_desc, (VOPFUNC)hfs_pagein }, /* Pagein */ - { &vop_pageout_desc, (VOPFUNC)hfs_pageout }, /* Pageout */ - { &vop_copyfile_desc, (VOPFUNC)err_copyfile }, /* copyfile */ - { &vop_blktooff_desc, (VOPFUNC)hfs_blktooff }, /* blktooff */ - { &vop_offtoblk_desc, (VOPFUNC)hfs_offtoblk }, /* offtoblk */ - { (struct vnodeop_desc*)NULL, (VOPFUNC)NULL } -}; -struct vnodeopv_desc hfs_specop_opv_desc = - { &hfs_specop_p, hfs_specop_entries }; - -#if FIFO -int (**hfs_fifoop_p)(void *); -struct vnodeopv_entry_desc hfs_fifoop_entries[] = { - { &vop_default_desc, (VOPFUNC)vn_default_error }, - { &vop_lookup_desc, (VOPFUNC)fifo_lookup }, /* lookup */ - { &vop_create_desc, (VOPFUNC)fifo_create }, /* create */ - { &vop_mknod_desc, (VOPFUNC)fifo_mknod }, /* mknod */ - { &vop_open_desc, (VOPFUNC)fifo_open }, /* open */ - { &vop_close_desc, (VOPFUNC)hfsfifo_close }, /* close */ - { &vop_access_desc, (VOPFUNC)hfs_access }, /* access */ - { &vop_getattr_desc, (VOPFUNC)hfs_getattr }, /* getattr */ - { &vop_setattr_desc, (VOPFUNC)hfs_setattr }, /* setattr */ - { &vop_read_desc, (VOPFUNC)hfsfifo_read }, /* read */ - { &vop_write_desc, (VOPFUNC)hfsfifo_write }, /* write */ - { &vop_lease_desc, (VOPFUNC)fifo_lease_check }, /* lease */ - { &vop_ioctl_desc, (VOPFUNC)fifo_ioctl }, /* ioctl */ - { &vop_select_desc, (VOPFUNC)fifo_select }, /* select */ - { &vop_revoke_desc, (VOPFUNC)fifo_revoke }, /* revoke */ - { &vop_mmap_desc, (VOPFUNC)fifo_mmap }, /* mmap */ - { &vop_fsync_desc, (VOPFUNC)hfs_fsync }, /* fsync */ - { &vop_seek_desc, (VOPFUNC)fifo_seek }, /* seek */ - { &vop_remove_desc, (VOPFUNC)fifo_remove }, /* remove */ - { &vop_link_desc, (VOPFUNC)fifo_link }, /* link */ - { &vop_rename_desc, (VOPFUNC)fifo_rename }, /* rename */ - { &vop_mkdir_desc, (VOPFUNC)fifo_mkdir }, /* mkdir */ - { &vop_rmdir_desc, (VOPFUNC)fifo_rmdir }, /* rmdir */ - { &vop_symlink_desc, (VOPFUNC)fifo_symlink }, /* symlink */ - { &vop_readdir_desc, (VOPFUNC)fifo_readdir }, /* readdir */ - { &vop_readlink_desc, (VOPFUNC)fifo_readlink }, /* readlink */ - { &vop_abortop_desc, (VOPFUNC)fifo_abortop }, /* abortop */ - { &vop_inactive_desc, (VOPFUNC)hfs_inactive }, /* inactive */ - { &vop_reclaim_desc, (VOPFUNC)hfs_reclaim }, /* reclaim */ - { &vop_lock_desc, (VOPFUNC)hfs_lock }, /* lock */ - { &vop_unlock_desc, (VOPFUNC)hfs_unlock }, /* unlock */ - { &vop_bmap_desc, (VOPFUNC)fifo_bmap }, /* bmap */ - { &vop_strategy_desc, (VOPFUNC)fifo_strategy }, /* strategy */ - { &vop_print_desc, (VOPFUNC)hfs_print }, /* print */ - { &vop_islocked_desc, (VOPFUNC)hfs_islocked }, /* islocked */ - { &vop_pathconf_desc, (VOPFUNC)fifo_pathconf }, /* pathconf */ - { &vop_advlock_desc, (VOPFUNC)fifo_advlock }, /* advlock */ - { &vop_blkatoff_desc, (VOPFUNC)fifo_blkatoff }, /* blkatoff */ - { &vop_valloc_desc, (VOPFUNC)fifo_valloc }, /* valloc */ - { &vop_reallocblks_desc, (VOPFUNC)fifo_reallocblks }, /* reallocblks */ - { &vop_vfree_desc, (VOPFUNC)err_vfree }, /* vfree */ - { &vop_truncate_desc, (VOPFUNC)fifo_truncate }, /* truncate */ - { &vop_update_desc, (VOPFUNC)hfs_update }, /* update */ - { &vop_bwrite_desc, (VOPFUNC)hfs_bwrite }, - { &vop_pagein_desc, (VOPFUNC)hfs_pagein }, /* Pagein */ - { &vop_pageout_desc, (VOPFUNC)hfs_pageout }, /* Pageout */ - { &vop_copyfile_desc, (VOPFUNC)err_copyfile }, /* copyfile */ - { &vop_blktooff_desc, (VOPFUNC)hfs_blktooff }, /* blktooff */ - { &vop_offtoblk_desc, (VOPFUNC)hfs_offtoblk }, /* offtoblk */ - { &vop_cmap_desc, (VOPFUNC)hfs_cmap }, /* cmap */ - { (struct vnodeop_desc*)NULL, (VOPFUNC)NULL } -}; -struct vnodeopv_desc hfs_fifoop_opv_desc = - { &hfs_fifoop_p, hfs_fifoop_entries }; -#endif /* FIFO */ - - - diff --git a/bsd/hfs/hfs_vnops.c b/bsd/hfs/hfs_vnops.c new file mode 100644 index 000000000..19006da0e --- /dev/null +++ b/bsd/hfs/hfs_vnops.c @@ -0,0 +1,3368 @@ +/* + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "hfs.h" +#include "hfs_catalog.h" +#include "hfs_cnode.h" +#include "hfs_lockf.h" +#include "hfs_dbg.h" +#include "hfs_mount.h" +#include "hfs_quota.h" +#include "hfs_endian.h" + +#include "hfscommon/headers/BTreesInternal.h" +#include "hfscommon/headers/FileMgrInternal.h" + +#define MAKE_DELETED_NAME(NAME,FID) \ + (void) sprintf((NAME), "%s%d", HFS_DELETE_PREFIX, (FID)) + + +extern uid_t console_user; + +/* Global vfs data structures for hfs */ + + +extern int groupmember(gid_t gid, struct ucred *cred); + +static int hfs_makenode(int mode, struct vnode *dvp, struct vnode **vpp, + struct componentname *cnp); + +static int hfs_vgetrsrc(struct hfsmount *hfsmp, struct vnode *vp, + struct vnode **rvpp, struct proc *p); + +static int hfs_metasync(struct hfsmount *hfsmp, daddr_t node, struct proc *p); + +int hfs_write_access(struct vnode *vp, struct ucred *cred, struct proc *p, Boolean considerFlags); + +int hfs_chflags(struct vnode *vp, u_long flags, struct ucred *cred, + struct proc *p); +int hfs_chmod(struct vnode *vp, int mode, struct ucred *cred, + struct proc *p); +int hfs_chown(struct vnode *vp, uid_t uid, gid_t gid, + struct ucred *cred, struct proc *p); + +/***************************************************************************** +* +* Common Operations on vnodes +* +*****************************************************************************/ + +/* + * Create a regular file +#% create dvp L U U +#% create vpp - L - +# + vop_create { + IN WILLRELE struct vnode *dvp; + OUT struct vnode **vpp; + IN struct componentname *cnp; + IN struct vattr *vap; + + We are responsible for freeing the namei buffer, + it is done in hfs_makenode() +*/ + +static int +hfs_create(ap) + struct vop_create_args /* { + struct vnode *a_dvp; + struct vnode **a_vpp; + struct componentname *a_cnp; + struct vattr *a_vap; + } */ *ap; +{ + struct vattr *vap = ap->a_vap; + + return (hfs_makenode(MAKEIMODE(vap->va_type, vap->va_mode), + ap->a_dvp, ap->a_vpp, ap->a_cnp)); +} + + +/* + * Mknod vnode call + +#% mknod dvp L U U +#% mknod vpp - X - +# + vop_mknod { + IN WILLRELE struct vnode *dvp; + OUT WILLRELE struct vnode **vpp; + IN struct componentname *cnp; + IN struct vattr *vap; + */ +/* ARGSUSED */ + +static int +hfs_mknod(ap) + struct vop_mknod_args /* { + struct vnode *a_dvp; + struct vnode **a_vpp; + struct componentname *a_cnp; + struct vattr *a_vap; + } */ *ap; +{ + struct vattr *vap = ap->a_vap; + struct vnode **vpp = ap->a_vpp; + struct cnode *cp; + int error; + + if (VTOVCB(ap->a_dvp)->vcbSigWord != kHFSPlusSigWord) { + VOP_ABORTOP(ap->a_dvp, ap->a_cnp); + vput(ap->a_dvp); + return (EOPNOTSUPP); + } + + /* Create the vnode */ + error = hfs_makenode(MAKEIMODE(vap->va_type, vap->va_mode), + ap->a_dvp, vpp, ap->a_cnp); + if (error) + return (error); + cp = VTOC(*vpp); + cp->c_flag |= C_ACCESS | C_CHANGE | C_UPDATE; + if ((vap->va_rdev != VNOVAL) && + (vap->va_type == VBLK || vap->va_type == VCHR)) + cp->c_rdev = vap->va_rdev; + /* + * Remove cnode so that it will be reloaded by lookup and + * checked to see if it is an alias of an existing vnode. + * Note: unlike UFS, we don't bash v_type here. + */ + vput(*vpp); + vgone(*vpp); + *vpp = 0; + return (0); +} + + +/* + * Open called. +#% open vp L L L +# + vop_open { + IN struct vnode *vp; + IN int mode; + IN struct ucred *cred; + IN struct proc *p; + */ + + +static int +hfs_open(ap) + struct vop_open_args /* { + struct vnode *a_vp; + int a_mode; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + + /* + * Files marked append-only must be opened for appending. + */ + if ((vp->v_type != VDIR) && (VTOC(vp)->c_flags & APPEND) && + (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE) + return (EPERM); + + return (0); +} + +/* + * Close called. + * + * Update the times on the cnode. +#% close vp U U U +# + vop_close { + IN struct vnode *vp; + IN int fflag; + IN struct ucred *cred; + IN struct proc *p; + */ + + +static int +hfs_close(ap) + struct vop_close_args /* { + struct vnode *a_vp; + int a_fflag; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; +{ + register struct vnode *vp = ap->a_vp; + register struct cnode *cp = VTOC(vp); + register struct filefork *fp = VTOF(vp); + struct proc *p = ap->a_p; + struct timeval tv; + off_t leof; + u_long blks, blocksize; + int devBlockSize; + int error; + + simple_lock(&vp->v_interlock); + if ((!UBCISVALID(vp) && vp->v_usecount > 1) + || (UBCISVALID(vp) && ubc_isinuse(vp, 1))) { + tv = time; + CTIMES(cp, &tv, &tv); + } + simple_unlock(&vp->v_interlock); + + /* + * VOP_CLOSE can be called with vp locked (from vclean). + * We check for this case using VOP_ISLOCKED and bail. + * + * XXX During a force unmount we won't do the cleanup below! + */ + if (vp->v_type == VDIR || VOP_ISLOCKED(vp)) + return (0); + + leof = fp->ff_size; + + if ((fp->ff_blocks > 0) && !ISSET(cp->c_flag, C_DELETED)) { + enum vtype our_type = vp->v_type; + u_long our_id = vp->v_id; + int was_nocache = ISSET(vp->v_flag, VNOCACHE_DATA); + + error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + if (error) + return (0); + /* + * Since we can context switch in vn_lock our vnode + * could get recycled (eg umount -f). Double check + * that its still ours. + */ + if (vp->v_type != our_type || vp->v_id != our_id + || cp != VTOC(vp) || !UBCINFOEXISTS(vp)) { + VOP_UNLOCK(vp, 0, p); + return (0); + } + + /* + * Last chance to explicitly zero out the areas + * that are currently marked invalid: + */ + VOP_DEVBLOCKSIZE(cp->c_devvp, &devBlockSize); + (void) cluster_push(vp); + SET(vp->v_flag, VNOCACHE_DATA); /* Don't cache zeros */ + while (!CIRCLEQ_EMPTY(&fp->ff_invalidranges)) { + struct rl_entry *invalid_range = CIRCLEQ_FIRST(&fp->ff_invalidranges); + off_t start = invalid_range->rl_start; + off_t end = invalid_range->rl_end; + + /* The range about to be written must be validated + * first, so that VOP_CMAP() will return the + * appropriate mapping for the cluster code: + */ + rl_remove(start, end, &fp->ff_invalidranges); + + (void) cluster_write(vp, (struct uio *) 0, leof, + invalid_range->rl_end + 1, invalid_range->rl_start, + (off_t)0, devBlockSize, IO_HEADZEROFILL | IO_NOZERODIRTY); + + if (ISSET(vp->v_flag, VHASDIRTY)) + (void) cluster_push(vp); + + cp->c_flag |= C_MODIFIED; + } + cp->c_flag &= ~C_ZFWANTSYNC; + cp->c_zftimeout = 0; + blocksize = VTOVCB(vp)->blockSize; + blks = leof / blocksize; + if (((off_t)blks * (off_t)blocksize) != leof) + blks++; + /* + * Shrink the peof to the smallest size neccessary to contain the leof. + */ + if (blks < fp->ff_blocks) + (void) VOP_TRUNCATE(vp, leof, IO_NDELAY, ap->a_cred, p); + (void) cluster_push(vp); + + if (!was_nocache) + CLR(vp->v_flag, VNOCACHE_DATA); + + /* + * If the VOP_TRUNCATE didn't happen to flush the vnode's + * information out to disk, force it to be updated now that + * all invalid ranges have been zero-filled and validated: + */ + if (cp->c_flag & C_MODIFIED) { + tv = time; + VOP_UPDATE(vp, &tv, &tv, 0); + } + VOP_UNLOCK(vp, 0, p); + } + return (0); +} + +/* +#% access vp L L L +# + vop_access { + IN struct vnode *vp; + IN int mode; + IN struct ucred *cred; + IN struct proc *p; + + */ + +static int +hfs_access(ap) + struct vop_access_args /* { + struct vnode *a_vp; + int a_mode; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); + struct ucred *cred = ap->a_cred; + register gid_t *gp; + mode_t mode = ap->a_mode; + mode_t mask = 0; + int i; + int error; + + /* + * Disallow write attempts on read-only file systems; + * unless the file is a socket, fifo, or a block or + * character device resident on the file system. + */ + if (mode & VWRITE) { + switch (vp->v_type) { + case VDIR: + case VLNK: + case VREG: + if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) + return (EROFS); +#if QUOTA + if ((error = hfs_getinoquota(cp))) + return (error); +#endif /* QUOTA */ + break; + } + } + + /* If immutable bit set, nobody gets to write it. */ + if ((mode & VWRITE) && (cp->c_flags & IMMUTABLE)) + return (EPERM); + + /* Otherwise, user id 0 always gets access. */ + if (ap->a_cred->cr_uid == 0) + return (0); + + mask = 0; + + /* Otherwise, check the owner. */ + if (hfs_owner_rights(VTOHFS(vp), cp->c_uid, cred, ap->a_p, false) == 0) { + if (mode & VEXEC) + mask |= S_IXUSR; + if (mode & VREAD) + mask |= S_IRUSR; + if (mode & VWRITE) + mask |= S_IWUSR; + return ((cp->c_mode & mask) == mask ? 0 : EACCES); + } + + /* Otherwise, check the groups. */ + if (! (VTOVFS(vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS)) { + for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++) + if (cp->c_gid == *gp) { + if (mode & VEXEC) + mask |= S_IXGRP; + if (mode & VREAD) + mask |= S_IRGRP; + if (mode & VWRITE) + mask |= S_IWGRP; + return ((cp->c_mode & mask) == mask ? 0 : EACCES); + } + } + + /* Otherwise, check everyone else. */ + if (mode & VEXEC) + mask |= S_IXOTH; + if (mode & VREAD) + mask |= S_IROTH; + if (mode & VWRITE) + mask |= S_IWOTH; + return ((cp->c_mode & mask) == mask ? 0 : EACCES); +} + + + +/* +#% getattr vp = = = +# + vop_getattr { + IN struct vnode *vp; + IN struct vattr *vap; + IN struct ucred *cred; + IN struct proc *p; + + */ + + +/* ARGSUSED */ +static int +hfs_getattr(ap) + struct vop_getattr_args /* { + struct vnode *a_vp; + struct vattr *a_vap; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); + struct vattr *vap = ap->a_vap; + struct timeval tv; + + tv = time; + CTIMES(cp, &tv, &tv); + + vap->va_type = vp->v_type; + /* + * [2856576] Since we are dynamically changing the owner, also + * effectively turn off the set-user-id and set-group-id bits, + * just like chmod(2) would when changing ownership. This prevents + * a security hole where set-user-id programs run as whoever is + * logged on (or root if nobody is logged in yet!) + */ + vap->va_mode = (cp->c_uid == UNKNOWNUID) ? cp->c_mode & ~(S_ISUID | S_ISGID) : cp->c_mode; + vap->va_nlink = cp->c_nlink; + vap->va_uid = (cp->c_uid == UNKNOWNUID) ? console_user : cp->c_uid; + vap->va_gid = cp->c_gid; + vap->va_fsid = cp->c_dev; + /* + * Exporting file IDs from HFS Plus: + * + * For "normal" files the c_fileid is the same value as the + * c_cnid. But for hard link files, they are different - the + * c_cnid belongs to the active directory entry (ie the link) + * and the c_fileid is for the actual inode (ie the data file). + * + * The stat call (getattr) will always return the c_fileid + * and Carbon APIs, which are hardlink-ignorant, will always + * receive the c_cnid (from getattrlist). + */ + vap->va_fileid = cp->c_fileid; + vap->va_atime.tv_sec = cp->c_atime; + vap->va_atime.tv_nsec = 0; + vap->va_mtime.tv_sec = cp->c_mtime; + vap->va_mtime.tv_nsec = cp->c_mtime_nsec; + vap->va_ctime.tv_sec = cp->c_ctime; + vap->va_ctime.tv_nsec = 0; + vap->va_gen = 0; + vap->va_flags = cp->c_flags; + vap->va_rdev = 0; + vap->va_blocksize = VTOVFS(vp)->mnt_stat.f_iosize; + vap->va_filerev = 0; + vap->va_spare = 0; + if (vp->v_type == VDIR) { + vap->va_size = cp->c_nlink * AVERAGE_HFSDIRENTRY_SIZE; + vap->va_bytes = 0; + } else { + vap->va_size = VTOF(vp)->ff_size; + vap->va_bytes = (u_quad_t)cp->c_blocks * + (u_quad_t)VTOVCB(vp)->blockSize; + if (vp->v_type == VBLK || vp->v_type == VCHR) + vap->va_rdev = cp->c_rdev; + } + return (0); +} + +/* + * Set attribute vnode op. called from several syscalls +#% setattr vp L L L +# + vop_setattr { + IN struct vnode *vp; + IN struct vattr *vap; + IN struct ucred *cred; + IN struct proc *p; + + */ + +static int +hfs_setattr(ap) + struct vop_setattr_args /* { + struct vnode *a_vp; + struct vattr *a_vap; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; +{ + struct vattr *vap = ap->a_vap; + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); + struct ucred *cred = ap->a_cred; + struct proc *p = ap->a_p; + struct timeval atimeval, mtimeval; + int error; + + /* + * Check for unsettable 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); + } + + if (vap->va_flags != VNOVAL) { + if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) + return (EROFS); + if ((error = hfs_chflags(vp, vap->va_flags, cred, p))) + return (error); + if (vap->va_flags & (IMMUTABLE | APPEND)) + return (0); + } + + if (cp->c_flags & (IMMUTABLE | APPEND)) + return (EPERM); + /* + * Go through the fields and update iff not VNOVAL. + */ + if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { + if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) + return (EROFS); + if ((error = hfs_chown(vp, vap->va_uid, vap->va_gid, cred, p))) + return (error); + } + if (vap->va_size != VNOVAL) { + /* + * Disallow write attempts on read-only file systems; + * unless the file is a socket, fifo, or a block or + * character device resident on the file system. + */ + switch (vp->v_type) { + case VDIR: + return (EISDIR); + case VLNK: + case VREG: + if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) + return (EROFS); + break; + default: + break; + } + if ((error = VOP_TRUNCATE(vp, vap->va_size, 0, cred, p))) + return (error); + } + cp = VTOC(vp); + if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { + if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) + return (EROFS); + if (((error = hfs_owner_rights(VTOHFS(vp), cp->c_uid, cred, p, true)) != 0) && + ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || + (error = VOP_ACCESS(vp, VWRITE, cred, p)))) { + return (error); + } + if (vap->va_atime.tv_sec != VNOVAL) + cp->c_flag |= C_ACCESS; + if (vap->va_mtime.tv_sec != VNOVAL) { + cp->c_flag |= C_CHANGE | C_UPDATE; + /* + * The utimes system call can reset the modification + * time but it doesn't know about HFS create times. + * So we need to insure that the creation time is + * always at least as old as the modification time. + */ + if ((VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) && + (cp->c_cnid != kRootDirID) && + (vap->va_mtime.tv_sec < cp->c_itime)) { + cp->c_itime = vap->va_mtime.tv_sec; + } + } + atimeval.tv_sec = vap->va_atime.tv_sec; + atimeval.tv_usec = 0; + mtimeval.tv_sec = vap->va_mtime.tv_sec; + mtimeval.tv_usec = 0; + if ((error = VOP_UPDATE(vp, &atimeval, &mtimeval, 1))) + return (error); + } + error = 0; + if (vap->va_mode != (mode_t)VNOVAL) { + if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) + return (EROFS); + error = hfs_chmod(vp, (int)vap->va_mode, cred, p); + } + return (error); +} + + +/* + * Change the mode on a file. + * cnode must be locked before calling. + */ +int +hfs_chmod(vp, mode, cred, p) + register struct vnode *vp; + register int mode; + register struct ucred *cred; + struct proc *p; +{ + register struct cnode *cp = VTOC(vp); + int error; + + if (VTOVCB(vp)->vcbSigWord != kHFSPlusSigWord) + return (0); + +#if OVERRIDE_UNKNOWN_PERMISSIONS + if (VTOVFS(vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) { + return (0); + }; +#endif + if ((error = hfs_owner_rights(VTOHFS(vp), cp->c_uid, cred, p, true)) != 0) + return (error); + if (cred->cr_uid) { + if (vp->v_type != VDIR && (mode & S_ISTXT)) + return (EFTYPE); + if (!groupmember(cp->c_gid, cred) && (mode & S_ISGID)) + return (EPERM); + } + cp->c_mode &= ~ALLPERMS; + cp->c_mode |= (mode & ALLPERMS); + cp->c_flag |= C_CHANGE; + return (0); +} + + +int +hfs_write_access(struct vnode *vp, struct ucred *cred, struct proc *p, Boolean considerFlags) +{ + struct cnode *cp = VTOC(vp); + gid_t *gp; + int retval = 0; + int i; + + /* + * Disallow write attempts on read-only file systems; + * unless the file is a socket, fifo, or a block or + * character device resident on the file system. + */ + switch (vp->v_type) { + case VDIR: + case VLNK: + case VREG: + if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) + return (EROFS); + break; + default: + break; + } + + /* If immutable bit set, nobody gets to write it. */ + if (considerFlags && (cp->c_flags & IMMUTABLE)) + return (EPERM); + + /* Otherwise, user id 0 always gets access. */ + if (cred->cr_uid == 0) + return (0); + + /* Otherwise, check the owner. */ + if ((retval = hfs_owner_rights(VTOHFS(vp), cp->c_uid, cred, p, false)) == 0) + return ((cp->c_mode & S_IWUSR) == S_IWUSR ? 0 : EACCES); + + /* Otherwise, check the groups. */ + for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++) { + if (cp->c_gid == *gp) + return ((cp->c_mode & S_IWGRP) == S_IWGRP ? 0 : EACCES); + } + + /* Otherwise, check everyone else. */ + return ((cp->c_mode & S_IWOTH) == S_IWOTH ? 0 : EACCES); +} + + + +/* + * Change the flags on a file or directory. + * cnode must be locked before calling. + */ +int +hfs_chflags(vp, flags, cred, p) + register struct vnode *vp; + register u_long flags; + register struct ucred *cred; + struct proc *p; +{ + register struct cnode *cp = VTOC(vp); + int retval; + + if (VTOVCB(vp)->vcbSigWord == kHFSSigWord) { + if ((retval = hfs_write_access(vp, cred, p, false)) != 0) { + return retval; + }; + } else if ((retval = hfs_owner_rights(VTOHFS(vp), cp->c_uid, cred, p, true)) != 0) { + return retval; + }; + + if (cred->cr_uid == 0) { + if ((cp->c_flags & (SF_IMMUTABLE | SF_APPEND)) && + securelevel > 0) { + return EPERM; + }; + cp->c_flags = flags; + } else { + if (cp->c_flags & (SF_IMMUTABLE | SF_APPEND) || + (flags & UF_SETTABLE) != flags) { + return EPERM; + }; + cp->c_flags &= SF_SETTABLE; + cp->c_flags |= (flags & UF_SETTABLE); + } + cp->c_flag |= C_CHANGE; + + return (0); +} + + +/* + * Perform chown operation on cnode cp; + * code must be locked prior to call. + */ +int +hfs_chown(vp, uid, gid, cred, p) + register struct vnode *vp; + uid_t uid; + gid_t gid; + struct ucred *cred; + struct proc *p; +{ + register struct cnode *cp = VTOC(vp); + uid_t ouid; + gid_t ogid; + int error = 0; +#if QUOTA + register int i; + int64_t change; +#endif /* QUOTA */ + + if (VTOVCB(vp)->vcbSigWord != kHFSPlusSigWord) + return (EOPNOTSUPP); + + if (VTOVFS(vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) + return (0); + + if (uid == (uid_t)VNOVAL) + uid = cp->c_uid; + if (gid == (gid_t)VNOVAL) + gid = cp->c_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 != cp->c_uid || uid != cp->c_uid || + (gid != cp->c_gid && !groupmember((gid_t)gid, cred))) && + (error = suser(cred, &p->p_acflag))) + return (error); + + ogid = cp->c_gid; + ouid = cp->c_uid; +#if QUOTA + if ((error = hfs_getinoquota(cp))) + return (error); + if (ouid == uid) { + dqrele(vp, cp->c_dquot[USRQUOTA]); + cp->c_dquot[USRQUOTA] = NODQUOT; + } + if (ogid == gid) { + dqrele(vp, cp->c_dquot[GRPQUOTA]); + cp->c_dquot[GRPQUOTA] = NODQUOT; + } + + /* + * Eventually need to account for (fake) a block per directory + *if (vp->v_type == VDIR) + *change = VTOVCB(vp)->blockSize; + *else + */ + + change = (int64_t)(cp->c_blocks) * (int64_t)VTOVCB(vp)->blockSize; + (void) hfs_chkdq(cp, -change, cred, CHOWN); + (void) hfs_chkiq(cp, -1, cred, CHOWN); + for (i = 0; i < MAXQUOTAS; i++) { + dqrele(vp, cp->c_dquot[i]); + cp->c_dquot[i] = NODQUOT; + } +#endif /* QUOTA */ + cp->c_gid = gid; + cp->c_uid = uid; +#if QUOTA + if ((error = hfs_getinoquota(cp)) == 0) { + if (ouid == uid) { + dqrele(vp, cp->c_dquot[USRQUOTA]); + cp->c_dquot[USRQUOTA] = NODQUOT; + } + if (ogid == gid) { + dqrele(vp, cp->c_dquot[GRPQUOTA]); + cp->c_dquot[GRPQUOTA] = NODQUOT; + } + if ((error = hfs_chkdq(cp, change, cred, CHOWN)) == 0) { + if ((error = hfs_chkiq(cp, 1, cred, CHOWN)) == 0) + goto good; + else + (void) hfs_chkdq(cp, -change, cred, CHOWN|FORCE); + } + for (i = 0; i < MAXQUOTAS; i++) { + dqrele(vp, cp->c_dquot[i]); + cp->c_dquot[i] = NODQUOT; + } + } + cp->c_gid = ogid; + cp->c_uid = ouid; + if (hfs_getinoquota(cp) == 0) { + if (ouid == uid) { + dqrele(vp, cp->c_dquot[USRQUOTA]); + cp->c_dquot[USRQUOTA] = NODQUOT; + } + if (ogid == gid) { + dqrele(vp, cp->c_dquot[GRPQUOTA]); + cp->c_dquot[GRPQUOTA] = NODQUOT; + } + (void) hfs_chkdq(cp, change, cred, FORCE|CHOWN); + (void) hfs_chkiq(cp, 1, cred, FORCE|CHOWN); + (void) hfs_getinoquota(cp); + } + return (error); +good: + if (hfs_getinoquota(cp)) + panic("hfs_chown: lost quota"); +#endif /* QUOTA */ + + if (ouid != uid || ogid != gid) + cp->c_flag |= C_CHANGE; + if (ouid != uid && cred->cr_uid != 0) + cp->c_mode &= ~S_ISUID; + if (ogid != gid && cred->cr_uid != 0) + cp->c_mode &= ~S_ISGID; + return (0); +} + + +/* +# +#% exchange fvp L L L +#% exchange tvp L L L +# + */ + /* + * The hfs_exchange routine swaps the fork data in two files by + * exchanging some of the information in the cnode. It is used + * to preserve the file ID when updating an existing file, in + * case the file is being tracked through its file ID. Typically + * its used after creating a new file during a safe-save. + */ + +static int +hfs_exchange(ap) + struct vop_exchange_args /* { + struct vnode *a_fvp; + struct vnode *a_tvp; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; +{ + struct vnode *from_vp = ap->a_fvp; + struct vnode *to_vp = ap->a_tvp; + struct vnode *from_rvp = NULL; + struct vnode *to_rvp = NULL; + struct cnode *from_cp = VTOC(from_vp); + struct cnode *to_cp = VTOC(to_vp); + struct hfsmount *hfsmp = VTOHFS(from_vp); + struct cat_desc tempdesc; + struct cat_attr tempattr; + int error = 0; + + /* The files must be on the same volume. */ + if (from_vp->v_mount != to_vp->v_mount) + return (EXDEV); + + /* Only normal files can be exchanged. */ + if ((from_vp->v_type != VREG) || (to_vp->v_type != VREG) || + (from_cp->c_flag & C_HARDLINK) || (to_cp->c_flag & C_HARDLINK) || + VNODE_IS_RSRC(from_vp) || VNODE_IS_RSRC(to_vp)) + return (EINVAL); + + from_rvp = from_cp->c_rsrc_vp; + to_rvp = to_cp->c_rsrc_vp; + + /* If one of the resource forks is open then get the other one. */ + if (from_rvp || to_rvp) { + error = hfs_vgetrsrc(hfsmp, from_vp, &from_rvp, ap->a_p); + if (error) + return (error); + error = hfs_vgetrsrc(hfsmp, to_vp, &to_rvp, ap->a_p); + if (error) { + vrele(from_rvp); + return (error); + } + } + + /* Ignore any errors, we are doing a 'best effort' on flushing */ + if (from_vp) + (void) vinvalbuf(from_vp, V_SAVE, ap->a_cred, ap->a_p, 0, 0); + if (to_vp) + (void) vinvalbuf(to_vp, V_SAVE, ap->a_cred, ap->a_p, 0, 0); + if (from_rvp) + (void) vinvalbuf(from_rvp, V_SAVE, ap->a_cred, ap->a_p, 0, 0); + if (to_rvp) + (void) vinvalbuf(to_rvp, V_SAVE, ap->a_cred, ap->a_p, 0, 0); + + /* Lock catalog b-tree */ + error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, ap->a_p); + if (error) goto Err_Exit; + + /* The backend code always tries to delete the virtual + * extent id for exchanging files so we neeed to lock + * the extents b-tree. + */ + error = hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p); + if (error) { + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, ap->a_p); + goto Err_Exit; + } + + /* Do the exchange */ + error = MacToVFSError(ExchangeFileIDs(HFSTOVCB(hfsmp), + from_cp->c_desc.cd_nameptr, to_cp->c_desc.cd_nameptr, + from_cp->c_parentcnid, to_cp->c_parentcnid, + from_cp->c_hint, to_cp->c_hint)); + + (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, ap->a_p); + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, ap->a_p); + + if (error != E_NONE) { + goto Err_Exit; + } + + /* Purge the vnodes from the name cache */ + if (from_vp) + cache_purge(from_vp); + if (to_vp) + cache_purge(to_vp); + + /* Save a copy of from attributes before swapping. */ + bcopy(&from_cp->c_desc, &tempdesc, sizeof(struct cat_desc)); + bcopy(&from_cp->c_attr, &tempattr, sizeof(struct cat_attr)); + + /* + * Swap the descriptors and all non-fork related attributes. + * (except the modify date) + */ + bcopy(&to_cp->c_desc, &from_cp->c_desc, sizeof(struct cat_desc)); + from_cp->c_hint = 0; + from_cp->c_fileid = from_cp->c_cnid; + from_cp->c_itime = to_cp->c_itime; + from_cp->c_btime = to_cp->c_btime; + from_cp->c_atime = to_cp->c_atime; + from_cp->c_ctime = to_cp->c_ctime; + from_cp->c_gid = to_cp->c_gid; + from_cp->c_uid = to_cp->c_uid; + from_cp->c_flags = to_cp->c_flags; + from_cp->c_mode = to_cp->c_mode; + bcopy(to_cp->c_finderinfo, from_cp->c_finderinfo, 32); + + bcopy(&tempdesc, &to_cp->c_desc, sizeof(struct cat_desc)); + to_cp->c_hint = 0; + to_cp->c_fileid = to_cp->c_cnid; + to_cp->c_itime = tempattr.ca_itime; + to_cp->c_btime = tempattr.ca_btime; + to_cp->c_atime = tempattr.ca_atime; + to_cp->c_ctime = tempattr.ca_ctime; + to_cp->c_gid = tempattr.ca_gid; + to_cp->c_uid = tempattr.ca_uid; + to_cp->c_flags = tempattr.ca_flags; + to_cp->c_mode = tempattr.ca_mode; + bcopy(tempattr.ca_finderinfo, to_cp->c_finderinfo, 32); + + /* Reinsert into the cnode hash under new file IDs*/ + hfs_chashremove(from_cp); + hfs_chashremove(to_cp); + + hfs_chashinsert(from_cp); + hfs_chashinsert(to_cp); +Err_Exit: + if (to_rvp) + vrele(to_rvp); + if (from_rvp) + vrele(from_rvp); + + return (error); +} + + +/* + +#% fsync vp L L L +# + vop_fsync { + IN struct vnode *vp; + IN struct ucred *cred; + IN int waitfor; + IN struct proc *p; + + */ + +static int +hfs_fsync(ap) + struct vop_fsync_args /* { + struct vnode *a_vp; + struct ucred *a_cred; + int a_waitfor; + struct proc *a_p; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); + struct filefork *fp = NULL; + int retval = 0; + register struct buf *bp; + struct timeval tv; + struct buf *nbp; + int s; + int wait; + int retry = 0; + + wait = (ap->a_waitfor == MNT_WAIT); + + /* HFS directories don't have any data blocks. */ + if (vp->v_type == VDIR) + goto metasync; + + /* + * For system files flush the B-tree header and + * for regular files write out any clusters + */ + if (vp->v_flag & VSYSTEM) { + if (VTOF(vp)->fcbBTCBPtr != NULL) + BTFlushPath(VTOF(vp)); + } else if (UBCINFOEXISTS(vp)) + (void) cluster_push(vp); + + /* + * When MNT_WAIT is requested and the zero fill timeout + * has expired then we must explicitly zero out any areas + * that are currently marked invalid (holes). + */ + if ((wait || (cp->c_flag & C_ZFWANTSYNC)) && + UBCINFOEXISTS(vp) && (fp = VTOF(vp)) && + cp->c_zftimeout != 0) { + int devblksize; + int was_nocache; + + if (time.tv_sec < cp->c_zftimeout) { + /* Remember that a force sync was requested. */ + cp->c_flag |= C_ZFWANTSYNC; + goto loop; + } + VOP_DEVBLOCKSIZE(cp->c_devvp, &devblksize); + was_nocache = ISSET(vp->v_flag, VNOCACHE_DATA); + SET(vp->v_flag, VNOCACHE_DATA); /* Don't cache zeros */ + + while (!CIRCLEQ_EMPTY(&fp->ff_invalidranges)) { + struct rl_entry *invalid_range = CIRCLEQ_FIRST(&fp->ff_invalidranges); + off_t start = invalid_range->rl_start; + off_t end = invalid_range->rl_end; + + /* The range about to be written must be validated + * first, so that VOP_CMAP() will return the + * appropriate mapping for the cluster code: + */ + rl_remove(start, end, &fp->ff_invalidranges); + + (void) cluster_write(vp, (struct uio *) 0, + fp->ff_size, + invalid_range->rl_end + 1, + invalid_range->rl_start, + (off_t)0, devblksize, + IO_HEADZEROFILL | IO_NOZERODIRTY); + cp->c_flag |= C_MODIFIED; + } + (void) cluster_push(vp); + if (!was_nocache) + CLR(vp->v_flag, VNOCACHE_DATA); + cp->c_flag &= ~C_ZFWANTSYNC; + cp->c_zftimeout = 0; + } + + /* + * Flush all dirty buffers associated with a vnode. + */ +loop: + s = splbio(); + for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) { + nbp = bp->b_vnbufs.le_next; + if ((bp->b_flags & B_BUSY)) + continue; + if ((bp->b_flags & B_DELWRI) == 0) + panic("hfs_fsync: not dirty"); + bremfree(bp); + bp->b_flags |= B_BUSY; + /* Clear B_LOCKED, should only be set on meta files */ + bp->b_flags &= ~B_LOCKED; + splx(s); + /* + * Wait for I/O associated with indirect blocks to complete, + * since there is no way to quickly wait for them below. + */ + if (bp->b_vp == vp || ap->a_waitfor == MNT_NOWAIT) + (void) bawrite(bp); + else + (void) VOP_BWRITE(bp); + goto loop; + } + + if (wait) { + while (vp->v_numoutput) { + vp->v_flag |= VBWAIT; + tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "hfs_fsync", 0); + } + + if (vp->v_dirtyblkhd.lh_first) { + /* still have some dirty buffers */ + if (retry++ > 10) { + vprint("hfs_fsync: dirty", vp); + splx(s); + /* + * Looks like the requests are not + * getting queued to the driver. + * Retrying here causes a cpu bound loop. + * Yield to the other threads and hope + * for the best. + */ + (void)tsleep((caddr_t)&vp->v_numoutput, + PRIBIO + 1, "hfs_fsync", hz/10); + retry = 0; + } else { + splx(s); + } + /* try again */ + goto loop; + } + } + splx(s); + +metasync: + tv = time; + if (vp->v_flag & VSYSTEM) { + if (VTOF(vp)->fcbBTCBPtr != NULL) + BTSetLastSync(VTOF(vp), tv.tv_sec); + cp->c_flag &= ~(C_ACCESS | C_CHANGE | C_MODIFIED | C_UPDATE); + } else /* User file */ { + retval = VOP_UPDATE(ap->a_vp, &tv, &tv, wait); + + /* When MNT_WAIT is requested push out any delayed meta data */ + if ((retval == 0) && wait && cp->c_hint && + !ISSET(cp->c_flag, C_DELETED | C_NOEXISTS)) { + hfs_metasync(VTOHFS(vp), cp->c_hint, ap->a_p); + } + } + + return (retval); +} + +/* Sync an hfs catalog b-tree node */ +static int +hfs_metasync(struct hfsmount *hfsmp, daddr_t node, struct proc *p) +{ + struct vnode *vp; + struct buf *bp; + struct buf *nbp; + int s; + + vp = HFSTOVCB(hfsmp)->catalogRefNum; + + if (hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p) != 0) + return (0); + + /* + * Look for a matching node that has been delayed + * but is not part of a set (B_LOCKED). + */ + s = splbio(); + for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) { + nbp = bp->b_vnbufs.le_next; + if (bp->b_flags & B_BUSY) + continue; + if (bp->b_lblkno == node) { + if (bp->b_flags & B_LOCKED) + break; + + bremfree(bp); + bp->b_flags |= B_BUSY; + splx(s); + (void) VOP_BWRITE(bp); + goto exit; + } + } + splx(s); +exit: + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); + + return (0); +} + +__private_extern__ +int +hfs_btsync(struct vnode *vp, int sync_transaction) +{ + struct cnode *cp = VTOC(vp); + register struct buf *bp; + struct timeval tv; + struct buf *nbp; + int s; + + /* + * Flush all dirty buffers associated with b-tree. + */ +loop: + s = splbio(); + + for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) { + nbp = bp->b_vnbufs.le_next; + if ((bp->b_flags & B_BUSY)) + continue; + if ((bp->b_flags & B_DELWRI) == 0) + panic("hfs_fsync: not dirty"); + if (sync_transaction && !(bp->b_flags & B_LOCKED)) + continue; + + bremfree(bp); + bp->b_flags |= B_BUSY; + bp->b_flags &= ~B_LOCKED; + splx(s); + + (void) bawrite(bp); + + goto loop; + } + splx(s); + + tv = time; + if ((vp->v_flag & VSYSTEM) && (VTOF(vp)->fcbBTCBPtr != NULL)) + (void) BTSetLastSync(VTOF(vp), tv.tv_sec); + cp->c_flag &= ~(C_ACCESS | C_CHANGE | C_MODIFIED | C_UPDATE); + + return 0; +} + +/* + * Rmdir system call. +#% rmdir dvp L U U +#% rmdir vp L U U +# + vop_rmdir { + IN WILLRELE struct vnode *dvp; + IN WILLRELE struct vnode *vp; + IN struct componentname *cnp; + + */ +static int +hfs_rmdir(ap) + struct vop_rmdir_args /* { + struct vnode *a_dvp; + struct vnode *a_vp; + struct componentname *a_cnp; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct vnode *dvp = ap->a_dvp; + struct proc *p = ap->a_cnp->cn_proc; + struct cnode *cp; + struct cnode *dcp; + struct hfsmount * hfsmp; + struct timeval tv; + int error = 0; + + cp = VTOC(vp); + dcp = VTOC(dvp); + hfsmp = VTOHFS(vp); + + if (dcp == cp) { + vrele(dvp); + vput(vp); + return (EINVAL); /* cannot remove "." */ + } + /* + * 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 (cp->c_entries != 0) { + error = ENOTEMPTY; + goto out; + } + if ((dcp->c_flags & APPEND) || (cp->c_flags & (IMMUTABLE | APPEND))) { + error = EPERM; + goto out; + } + + /* Remove the entry from the namei cache: */ + cache_purge(vp); + + /* Lock catalog b-tree */ + error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p); + if (error) goto out; + + if (cp->c_entries > 0) + panic("hfs_rmdir: attempting to delete a non-empty directory!"); + /* Remove entry from catalog */ + error = cat_delete(hfsmp, &cp->c_desc, &cp->c_attr); + + /* Unlock catalog b-tree */ + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); + if (error) goto out; + +#if QUOTA + if (!hfs_getinoquota(cp)) + (void)hfs_chkiq(cp, -1, NOCRED, 0); +#endif /* QUOTA */ + + /* The parent lost a child */ + if (dcp->c_entries > 0) + dcp->c_entries--; + if (dcp->c_nlink > 0) + dcp->c_nlink--; + dcp->c_flag |= C_CHANGE | C_UPDATE; + tv = time; + (void) VOP_UPDATE(dvp, &tv, &tv, 0); + hfs_volupdate(hfsmp, VOL_RMDIR, (dcp->c_cnid == kHFSRootFolderID)); + + cp->c_mode = 0; /* Makes the vnode go away...see inactive */ + cp->c_flag |= C_NOEXISTS; +out: + if (dvp) + vput(dvp); + vput(vp); + return (error); +} + +/* + +#% remove dvp L U U +#% remove vp L U U +# + vop_remove { + IN WILLRELE struct vnode *dvp; + IN WILLRELE struct vnode *vp; + IN struct componentname *cnp; + + */ + +static int +hfs_remove(ap) + struct vop_remove_args /* { + struct vnode *a_dvp; + struct vnode *a_vp; + struct componentname *a_cnp; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct vnode *dvp = ap->a_dvp; + struct vnode *rvp = NULL; + struct cnode *cp; + struct cnode *dcp; + struct hfsmount *hfsmp; + struct proc *p = current_proc(); + int dataforkbusy = 0; + int rsrcforkbusy = 0; + int truncated = 0; + struct timeval tv; + int error = 0; + + /* Redirect directories to rmdir */ + if (vp->v_type == VDIR) + return (hfs_rmdir(ap)); + + cp = VTOC(vp); + dcp = VTOC(dvp); + hfsmp = VTOHFS(vp); + + if (cp->c_parentcnid != dcp->c_cnid) { + error = EINVAL; + goto out; + } + + /* Make sure a remove is permitted */ + if ((cp->c_flags & (IMMUTABLE | APPEND)) || + (VTOC(dvp)->c_flags & APPEND) || + VNODE_IS_RSRC(vp)) { + error = EPERM; + goto out; + } + + /* + * Aquire a vnode for a non-empty resource fork. + * (needed for VOP_TRUNCATE) + */ + if (cp->c_blocks - VTOF(vp)->ff_blocks) { + error = hfs_vgetrsrc(hfsmp, vp, &rvp, p); + if (error) + goto out; + } + + /* + * Check if this file is being used. + * + * The namei done for the remove took a reference on the + * vnode (vp). And we took a ref on the resource vnode (rvp). + * Hence set 1 in the tookref parameter of ubc_isinuse(). + */ + if (UBCISVALID(vp) && ubc_isinuse(vp, 1)) + dataforkbusy = 1; + if (rvp && UBCISVALID(rvp) && ubc_isinuse(rvp, 1)) + rsrcforkbusy = 1; + + /* + * Carbon semantics prohibit deleting busy files. + * (enforced when NODELETEBUSY is requested) + */ + if ((dataforkbusy || rsrcforkbusy) && + ((ap->a_cnp->cn_flags & NODELETEBUSY) || + (hfsmp->hfs_private_metadata_dir == 0))) { + error = EBUSY; + goto out; + } + + /* Remove our entry from the namei cache. */ + cache_purge(vp); + + /* + * Truncate any non-busy forks. Busy forks will + * get trucated when their vnode goes inactive. + * + * (Note: hard links are truncated in VOP_INACTIVE) + */ + if ((cp->c_flag & C_HARDLINK) == 0) { + int mode = cp->c_mode; + + if (!dataforkbusy && cp->c_datafork->ff_blocks != 0) { + cp->c_mode = 0; /* Suppress VOP_UPDATES */ + error = VOP_TRUNCATE(vp, (off_t)0, IO_NDELAY, NOCRED, p); + cp->c_mode = mode; + if (error) + goto out; + truncated = 1; + } + if (!rsrcforkbusy && rvp) { + cp->c_mode = 0; /* Suppress VOP_UPDATES */ + error = VOP_TRUNCATE(rvp, (off_t)0, IO_NDELAY, NOCRED, p); + cp->c_mode = mode; + if (error && !dataforkbusy) + goto out; + else { + /* + * XXX could also force an update on vp + * and fail the remove. + */ + error = 0; + } + truncated = 1; + } + } + /* + * There are 3 remove cases to consider: + * 1. File is a hardlink ==> remove the link + * 2. File is busy (in use) ==> move/rename the file + * 3. File is not in use ==> remove the file + */ + + if (cp->c_flag & C_HARDLINK) { + struct cat_desc desc; + + if ((ap->a_cnp->cn_flags & HASBUF) == 0 || + ap->a_cnp->cn_nameptr[0] == '\0') { + error = ENOENT; /* name missing! */ + goto out; + } + + /* Setup a descriptor for the link */ + bzero(&desc, sizeof(desc)); + desc.cd_nameptr = ap->a_cnp->cn_nameptr; + desc.cd_namelen = ap->a_cnp->cn_namelen; + desc.cd_parentcnid = dcp->c_cnid; + /* XXX - if cnid is out of sync then the wrong thread rec will get deleted. */ + desc.cd_cnid = cp->c_cnid; + + /* Lock catalog b-tree */ + error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p); + if (error) + goto out; + + error = cat_delete(hfsmp, &desc, &cp->c_attr); + + /* Unlock the Catalog */ + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); + + /* All done with component name... */ + if ((ap->a_cnp->cn_flags & (HASBUF | SAVENAME)) == (HASBUF | SAVENAME)) + FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI); + + if (error != 0) + goto out; + + cp->c_flag |= C_CHANGE; + if (--cp->c_nlink < 1) + cp->c_flag |= C_DELETED; + hfs_volupdate(hfsmp, VOL_RMFILE, (dcp->c_cnid == kHFSRootFolderID)); + + } else if (dataforkbusy || rsrcforkbusy) { + char delname[32]; + struct cat_desc to_desc; + struct cat_desc todir_desc; + + /* + * Orphan this file (move to hidden directory). + */ + bzero(&todir_desc, sizeof(todir_desc)); + todir_desc.cd_parentcnid = 2; + + MAKE_DELETED_NAME(delname, cp->c_fileid); + bzero(&to_desc, sizeof(to_desc)); + to_desc.cd_nameptr = delname; + to_desc.cd_namelen = strlen(delname); + to_desc.cd_parentcnid = hfsmp->hfs_private_metadata_dir; + to_desc.cd_flags = 0; + to_desc.cd_cnid = cp->c_cnid; + + /* Lock catalog b-tree */ + error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p); + if (error) goto out; + + error = cat_rename(hfsmp, &cp->c_desc, &todir_desc, + &to_desc, (struct cat_desc *)NULL); + + hfsmp->hfs_privdir_attr.ca_entries++; + (void)cat_update(hfsmp, &hfsmp->hfs_privdir_desc, + &hfsmp->hfs_privdir_attr, NULL, NULL); + + /* Unlock the Catalog */ + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); + if (error) goto out; + + cp->c_flag |= C_CHANGE | C_DELETED | C_NOEXISTS; + --cp->c_nlink; + + } else /* Not busy */ { + + /* Lock catalog b-tree */ + error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p); + if (error) goto out; + + if (vp->v_type == VDIR && cp->c_entries > 0) + panic("hfs_remove: attempting to delete a non-empty directory!"); + if (vp->v_type != VDIR && cp->c_blocks > 0) + panic("hfs_remove: attempting to delete a non-empty file!"); + + error = cat_delete(hfsmp, &cp->c_desc, &cp->c_attr); + + if (error && truncated) + panic("hfs_remove: couldn't delete a truncated file!"); + + /* Unlock the Catalog */ + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); + if (error) goto out; + +#if QUOTA + if (!hfs_getinoquota(cp)) + (void)hfs_chkiq(cp, -1, NOCRED, 0); +#endif /* QUOTA */ + + cp->c_mode = 0; + cp->c_flag |= C_CHANGE | C_NOEXISTS; + --cp->c_nlink; + hfs_volupdate(hfsmp, VOL_RMFILE, (dcp->c_cnid == kHFSRootFolderID)); + } + + /* + * All done with this cnode's descriptor... + * + * Note: all future catalog calls for this cnode must be + * by fileid only. This is OK for HFS (which doesn't have + * file thread records) since HFS doesn't support hard + * links or the removal of busy files. + */ + cat_releasedesc(&cp->c_desc); + + /* In all three cases the parent lost a child */ + if (dcp->c_entries > 0) + dcp->c_entries--; + if (dcp->c_nlink > 0) + dcp->c_nlink--; + dcp->c_flag |= C_CHANGE | C_UPDATE; + tv = time; + (void) VOP_UPDATE(dvp, &tv, &tv, 0); + + if (rvp) + vrele(rvp); + VOP_UNLOCK(vp, 0, p); + (void) ubc_uncache(vp); + vrele(vp); + vput(dvp); + return (0); +out: + if (rvp) + vrele(rvp); + + /* Commit the truncation to the catalog record */ + if (truncated) { + cp->c_flag |= C_CHANGE | C_UPDATE; + tv = time; + (void) VOP_UPDATE(vp, &tv, &tv, 0); + } + vput(vp); + vput(dvp); + return (error); +} + + +__private_extern__ void +replace_desc(struct cnode *cp, struct cat_desc *cdp) +{ + /* First release allocated name buffer */ + if (cp->c_desc.cd_flags & CD_HASBUF && cp->c_desc.cd_nameptr != 0) { + char *name = cp->c_desc.cd_nameptr; + + cp->c_desc.cd_nameptr = 0; + cp->c_desc.cd_namelen = 0; + cp->c_desc.cd_flags &= ~CD_HASBUF; + FREE(name, M_TEMP); + } + bcopy(cdp, &cp->c_desc, sizeof(cp->c_desc)); + + /* Cnode now owns the name buffer */ + cdp->cd_nameptr = 0; + cdp->cd_namelen = 0; + cdp->cd_flags &= ~CD_HASBUF; +} + + +/* +# +#% rename fdvp U U U +#% rename fvp U U U +#% rename tdvp L U U +#% rename tvp X U U +# + vop_rename { + IN WILLRELE struct vnode *fdvp; + IN WILLRELE struct vnode *fvp; + IN struct componentname *fcnp; + IN WILLRELE struct vnode *tdvp; + IN WILLRELE struct vnode *tvp; + IN struct componentname *tcnp; + }; +*/ +/* + * Rename a cnode. + * + * The VFS layer guarantees that source and destination will + * either both be directories, or both not be directories. + * + * When the target is a directory, hfs_rename must ensure + * that it is empty. + */ + +static int +hfs_rename(ap) + struct vop_rename_args /* { + struct vnode *a_fdvp; + struct vnode *a_fvp; + struct componentname *a_fcnp; + struct vnode *a_tdvp; + struct vnode *a_tvp; + struct componentname *a_tcnp; + } */ *ap; +{ + struct vnode *tvp = ap->a_tvp; + struct vnode *tdvp = ap->a_tdvp; + struct vnode *fvp = ap->a_fvp; + struct vnode *fdvp = ap->a_fdvp; + struct componentname *tcnp = ap->a_tcnp; + struct componentname *fcnp = ap->a_fcnp; + struct cnode *fcp = NULL; + struct cnode *fdcp = NULL; + struct cnode *tdcp = NULL; + struct cnode *tcp = NULL; + struct cat_desc from_desc; + struct cat_desc to_desc; + struct cat_desc out_desc; + struct hfsmount *hfsmp; + struct proc *p = fcnp->cn_proc; + struct timeval tv; + int retval = 0; + cnid_t oldparent = 0; + cnid_t newparent = 0; + +#if HFS_DIAGNOSTIC + if ((tcnp->cn_flags & HASBUF) == 0 || + (fcnp->cn_flags & HASBUF) == 0) + panic("hfs_rename: no name"); +#endif + /* + * When fvp matches tvp they must be case variants + * or hard links, and if they are in the same directory then + * tvp really doesn't exist (see VFS rename). + * XXX Hard link rename is still broken/ignored. If they are + * in different directories then we must have hard links. + * Comments further down describe behaviour of hard links in same dir. + * Note case insensitivity was and still is presumed. + */ + if (fvp == tvp) { + if (fdvp != tdvp) { + retval = 0; + goto abortop; + } + tvp = NULL; + } + + /* + * Check for cross-device rename. + */ + if ((fvp->v_mount != tdvp->v_mount) || + (tvp && (fvp->v_mount != tvp->v_mount))) { + retval = EXDEV; + goto abortop; + } + + /* + * Make sure a remove of "to" vnode is permitted. + */ + if (tvp && ((VTOC(tvp)->c_flags & (IMMUTABLE | APPEND)) || + (VTOC(tdvp)->c_flags & APPEND))) { + retval = EPERM; + goto abortop; + } + + if ((retval = vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p))) + goto abortop; + + /* + * Make sure "from" vnode and its parent are changeable. + */ + fdcp = VTOC(fdvp); + fcp = VTOC(fvp); + oldparent = fdcp->c_cnid; + if ((fcp->c_flags & (IMMUTABLE | APPEND)) || (fdcp->c_flags & APPEND)) { + VOP_UNLOCK(fvp, 0, p); + retval = EPERM; + goto abortop; + } + + if (fcp->c_parentcnid != fdcp->c_cnid) { + VOP_UNLOCK(fvp, 0, p); + retval = EINVAL; + goto abortop; + } + + /* + * Check if names already match... + * XXX The name being checked is from fcp rather than fcnp! If + * there are hard links, fcp yields the name which was + * most recently looked up (yes that design is vulnerable to races) + * and the name most recently looked up was the target, so they + * compare equal and we ignore the rename. XXX + */ + if (fvp == ap->a_tvp && + (bcmp(fcp->c_desc.cd_nameptr, tcnp->cn_nameptr, + fcp->c_desc.cd_namelen) == 0)) { + VOP_UNLOCK(fvp, 0, p); + retval = 0; + goto abortop; + } + + /* XXX This doesn't make sense for HFS... + * + * Be sure we are not renaming ".", "..", or an alias of ".". This + * leads to a crippled directory tree. It's pretty tough to do a + * "ls" or "pwd" with the "." directory entry missing, and "cd .." + * doesn't work if the ".." entry is missing. + */ + if (fvp->v_type == VDIR) { + if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') + || fdcp == fcp + || (fcnp->cn_flags&ISDOTDOT) + || (fcp->c_flag & C_RENAME)) { + VOP_UNLOCK(fvp, 0, p); + retval = EINVAL; + goto abortop; + } + fcp->c_flag |= C_RENAME; + } + + /* XXX UFS does vrele(fdvp) here */ + + /* From now on use bad instead of abort to exit */ + + tdcp = VTOC(tdvp); + if (tvp) + tcp = VTOC(tvp); + + newparent = tdcp->c_cnid; + + retval = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc); + if ((fvp->v_type == VDIR) && (newparent != oldparent)) { + if (retval) /* write access check above */ + goto bad; + } + retval = 0; /* Reset value from above, we dont care about it anymore */ + + /* + * If the destination exists, then be sure its type (file or dir) + * matches that of the source. And, if it is a directory make sure + * it is empty. Then delete the destination. + */ + if (tvp) { + /* + * 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 ((tdcp->c_mode & S_ISTXT) && (tcnp->cn_cred->cr_uid != 0) && + tcnp->cn_cred->cr_uid != tdcp->c_uid && + tcnp->cn_cred->cr_uid != tcp->c_uid) { + retval = EPERM; + goto bad; + } + + /* + * Target must be empty if a directory. + */ + if (S_ISDIR(tcp->c_mode) && (tcp->c_nlink > 2)) { + retval = ENOTEMPTY; + goto bad; + } + + /* + * VOP_REMOVE will vput tdvp so we better bump + * its ref count and relockit, always set tvp to + * NULL afterwards to indicate that were done with it. + */ + VREF(tdvp); + + cache_purge(tvp); + + tcnp->cn_flags &= ~SAVENAME; + + if (tvp->v_type == VDIR) + retval = VOP_RMDIR(tdvp, tvp, tcnp); + else + retval = VOP_REMOVE(tdvp, tvp, tcnp); + + (void) vn_lock(tdvp, LK_EXCLUSIVE | LK_RETRY, p); + tvp = NULL; + tcp = NULL; + if (retval) + goto bad; + + } + + /* XXX + * Prevent lock heirarchy violation (deadlock): + * + * If fdvp is the parent of tdvp then we must drop + * tdvp lock before aquiring the lock for fdvp. + */ + if (newparent != oldparent) + vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY, p); + + /* remove the existing entry from the namei cache: */ + cache_purge(fvp); + + hfsmp = VTOHFS(fvp); + bzero(&from_desc, sizeof(from_desc)); + from_desc.cd_nameptr = fcnp->cn_nameptr; + from_desc.cd_namelen = fcnp->cn_namelen; + from_desc.cd_parentcnid = fdcp->c_cnid; + from_desc.cd_flags = fcp->c_desc.cd_flags & ~(CD_HASBUF | CD_DECOMPOSED); + from_desc.cd_cnid = fcp->c_cnid; + bzero(&to_desc, sizeof(to_desc)); + to_desc.cd_nameptr = tcnp->cn_nameptr; + to_desc.cd_namelen = tcnp->cn_namelen; + to_desc.cd_parentcnid = tdcp->c_cnid; + to_desc.cd_flags = fcp->c_desc.cd_flags & ~(CD_HASBUF | CD_DECOMPOSED); + to_desc.cd_cnid = fcp->c_cnid; + + /* Lock catalog b-tree */ + retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p); + if (retval) { + if (newparent != oldparent) /* unlock the lock we just got */ + VOP_UNLOCK(fdvp, 0, p); + goto bad; + } + retval = cat_rename(hfsmp, &from_desc, &tdcp->c_desc, + &to_desc, &out_desc); + + /* Unlock catalog b-tree */ + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); + + if (newparent != oldparent) + VOP_UNLOCK(fdvp, 0, p); + + if (retval) goto bad; + + /* update cnode's catalog descriptor */ + replace_desc(fcp, &out_desc); + + fcp->c_flag &= ~C_RENAME; + + /* + * Time stamp both parent directories. + * Note that if this is a rename within the same directory, + * (where tdcp == fdcp) + * the code below is still safe and correct. + */ + if (fdcp->c_nlink > 0) + fdcp->c_nlink--; + if (fdcp->c_entries > 0) + fdcp->c_entries--; + tdcp->c_nlink++; + tdcp->c_entries++; + fdcp->c_flag |= C_UPDATE; + tdcp->c_flag |= C_UPDATE; + tv = time; + CTIMES(fdcp, &tv, &tv); + CTIMES(tdcp, &tv, &tv); + tdcp->c_childhint = out_desc.cd_hint; /* Cache directory's location */ + + hfs_volupdate(hfsmp, fvp->v_type == VDIR ? VOL_RMDIR : VOL_RMFILE, + (fdcp->c_cnid == kHFSRootFolderID)); + hfs_volupdate(hfsmp, fvp->v_type == VDIR ? VOL_MKDIR : VOL_MKFILE, + (tdcp->c_cnid == kHFSRootFolderID)); + + vput(tdvp); + vrele(fdvp); + vput(fvp); + return (0); + +bad: + if (fcp) + fcp->c_flag &= ~C_RENAME; + if (tdvp == tvp) + vrele(tdvp); + else + vput(tdvp); + if (tvp) + vput(tvp); + vrele(fdvp); + + if (VOP_ISLOCKED(fvp)) + vput(fvp); + else + vrele(fvp); + return (retval); + +abortop: + + VOP_ABORTOP(tdvp, tcnp); + if (tdvp == tvp) + vrele(tdvp); + else + vput(tdvp); + if (tvp) + vput(tvp); + VOP_ABORTOP(fdvp, fcnp); + vrele(fdvp); + vrele(fvp); + return (retval); +} + + + +/* + * Mkdir system call +#% mkdir dvp L U U +#% mkdir vpp - L - +# + vop_mkdir { + IN WILLRELE struct vnode *dvp; + OUT struct vnode **vpp; + IN struct componentname *cnp; + IN struct vattr *vap; + + We are responsible for freeing the namei buffer, + it is done in hfs_makenode() +*/ + +static int +hfs_mkdir(ap) + struct vop_mkdir_args /* { + struct vnode *a_dvp; + struct vnode **a_vpp; + struct componentname *a_cnp; + struct vattr *a_vap; + } */ *ap; +{ + struct vattr *vap = ap->a_vap; + + return (hfs_makenode(MAKEIMODE(vap->va_type, vap->va_mode), + ap->a_dvp, ap->a_vpp, ap->a_cnp)); +} + + +/* + * symlink -- make a symbolic link +#% symlink dvp L U U +#% symlink vpp - U - +# +# XXX - note that the return vnode has already been VRELE'ed +# by the filesystem layer. To use it you must use vget, +# possibly with a further namei. +# + vop_symlink { + IN WILLRELE struct vnode *dvp; + OUT WILLRELE struct vnode **vpp; + IN struct componentname *cnp; + IN struct vattr *vap; + IN char *target; + + We are responsible for freeing the namei buffer, + it is done in hfs_makenode(). + +*/ + +static int +hfs_symlink(ap) + struct vop_symlink_args /* { + struct vnode *a_dvp; + struct vnode **a_vpp; + struct componentname *a_cnp; + struct vattr *a_vap; + char *a_target; + } */ *ap; +{ + register struct vnode *vp, **vpp = ap->a_vpp; + struct filefork *fp; + int len, error; + struct buf *bp = NULL; + + /* HFS standard disks don't support symbolic links */ + if (VTOVCB(ap->a_dvp)->vcbSigWord != kHFSPlusSigWord) { + VOP_ABORTOP(ap->a_dvp, ap->a_cnp); + vput(ap->a_dvp); + return (EOPNOTSUPP); + } + + /* Check for empty target name */ + if (ap->a_target[0] == 0) { + VOP_ABORTOP(ap->a_dvp, ap->a_cnp); + vput(ap->a_dvp); + return (EINVAL); + } + + /* Create the vnode */ + if ((error = hfs_makenode(S_IFLNK | ap->a_vap->va_mode, + ap->a_dvp, vpp, ap->a_cnp))) + return (error); + + vp = *vpp; + len = strlen(ap->a_target); + fp = VTOF(vp); + fp->ff_clumpsize = VTOVCB(vp)->blockSize; + + /* Allocate space for the link */ + error = VOP_TRUNCATE(vp, len, IO_NOZEROFILL, + ap->a_cnp->cn_cred, ap->a_cnp->cn_proc); + if (error) + goto out; /* XXX need to remove link */ + + /* Write the link to disk */ + bp = getblk(vp, 0, roundup((int)fp->ff_size, VTOHFS(vp)->hfs_phys_block_size), + 0, 0, BLK_META); + bzero(bp->b_data, bp->b_bufsize); + bcopy(ap->a_target, bp->b_data, len); + bawrite(bp); +out: + vput(vp); + return (error); +} + + +/* + * Dummy dirents to simulate the "." and ".." entries of the directory + * in a hfs filesystem. HFS doesn't provide these on disk. Note that + * the size of these entries is the smallest needed to represent them + * (only 12 byte each). + */ +static hfsdotentry rootdots[2] = { + { + 1, /* d_fileno */ + sizeof(struct hfsdotentry), /* d_reclen */ + DT_DIR, /* d_type */ + 1, /* d_namlen */ + "." /* d_name */ + }, + { + 1, /* d_fileno */ + sizeof(struct hfsdotentry), /* d_reclen */ + DT_DIR, /* d_type */ + 2, /* d_namlen */ + ".." /* d_name */ + } +}; + +/* 4.3 Note: +* There is some confusion as to what the semantics of uio_offset are. +* In ufs, it represents the actual byte offset within the directory +* "file." HFS, however, just uses it as an entry counter - essentially +* assuming that it has no meaning except to the hfs_readdir function. +* This approach would be more efficient here, but some callers may +* assume the uio_offset acts like a byte offset. NFS in fact +* monkeys around with the offset field a lot between readdir calls. +* +* The use of the resid uiop->uio_resid and uiop->uio_iov->iov_len +* fields is a mess as well. The libc function readdir() returns +* NULL (indicating the end of a directory) when either +* the getdirentries() syscall (which calls this and returns +* the size of the buffer passed in less the value of uiop->uio_resid) +* returns 0, or a direct record with a d_reclen of zero. +* nfs_server.c:rfs_readdir(), on the other hand, checks for the end +* of the directory by testing uiop->uio_resid == 0. The solution +* is to pad the size of the last struct direct in a given +* block to fill the block if we are not at the end of the directory. +*/ + + +/* + * NOTE: We require a minimal buffer size of DIRBLKSIZ for two reasons. One, it is the same value + * returned be stat() call as the block size. This is mentioned in the man page for getdirentries(): + * "Nbytes must be greater than or equal to the block size associated with the file, + * see stat(2)". Might as well settle on the same size of ufs. Second, this makes sure there is enough + * room for the . and .. entries that have to added manually. + */ + +/* +#% readdir vp L L L +# +vop_readdir { + IN struct vnode *vp; + INOUT struct uio *uio; + IN struct ucred *cred; + INOUT int *eofflag; + OUT int *ncookies; + INOUT u_long **cookies; + */ +static int +hfs_readdir(ap) + struct vop_readdir_args /* { + struct vnode *vp; + struct uio *uio; + struct ucred *cred; + int *eofflag; + int *ncookies; + u_long **cookies; + } */ *ap; +{ + register struct uio *uio = ap->a_uio; + struct cnode *cp = VTOC(ap->a_vp); + struct hfsmount *hfsmp = VTOHFS(ap->a_vp); + struct proc *p = current_proc(); + off_t off = uio->uio_offset; + int retval = 0; + int eofflag = 0; + + /* We assume it's all one big buffer... */ + if (uio->uio_iovcnt > 1 || uio->uio_resid < AVERAGE_HFSDIRENTRY_SIZE) + return EINVAL; + + /* Create the entries for . and .. */ + if (uio->uio_offset < sizeof(rootdots)) { + caddr_t dep; + size_t dotsize; + + rootdots[0].d_fileno = cp->c_cnid; + rootdots[1].d_fileno = cp->c_parentcnid; + + if (uio->uio_offset == 0) { + dep = (caddr_t) &rootdots[0]; + dotsize = 2* sizeof(struct hfsdotentry); + } else if (uio->uio_offset == sizeof(struct hfsdotentry)) { + dep = (caddr_t) &rootdots[1]; + dotsize = sizeof(struct hfsdotentry); + } else { + retval = EINVAL; + goto Exit; + } + + retval = uiomove(dep, dotsize, uio); + if (retval != 0) + goto Exit; + } + + /* If there are no children then we're done */ + if (cp->c_entries == 0) { + eofflag = 1; + retval = 0; + goto Exit; + } + + /* Lock catalog b-tree */ + retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_SHARED, p); + if (retval) goto Exit; + + retval = cat_getdirentries(hfsmp, &cp->c_desc, uio, &eofflag); + + /* Unlock catalog b-tree */ + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); + + if (retval != E_NONE) { + goto Exit; + } + + /* were we already past eof ? */ + if (uio->uio_offset == off) { + retval = E_NONE; + goto Exit; + } + + cp->c_flag |= C_ACCESS; + /* Bake any cookies */ + if (!retval && ap->a_ncookies != NULL) { + struct dirent* dpStart; + struct dirent* dpEnd; + struct dirent* dp; + int ncookies; + u_long *cookies; + u_long *cookiep; + + /* + * Only the NFS server uses cookies, and it loads the + * directory block into system space, so we can just look at + * it directly. + */ + if (uio->uio_segflg != UIO_SYSSPACE) + panic("hfs_readdir: unexpected uio from NFS server"); + dpStart = (struct dirent *)(uio->uio_iov->iov_base - (uio->uio_offset - off)); + dpEnd = (struct dirent *) uio->uio_iov->iov_base; + for (dp = dpStart, ncookies = 0; + dp < dpEnd && dp->d_reclen != 0; + dp = (struct dirent *)((caddr_t)dp + dp->d_reclen)) + ncookies++; + MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP, M_WAITOK); + for (dp = dpStart, cookiep = cookies; + dp < dpEnd; + dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) { + off += dp->d_reclen; + *cookiep++ = (u_long) off; + } + *ap->a_ncookies = ncookies; + *ap->a_cookies = cookies; + } + +Exit:; + if (ap->a_eofflag) + *ap->a_eofflag = eofflag; + + return (retval); +} + + +/* + * Return target name of a symbolic link +#% readlink vp L L L +# + vop_readlink { + IN struct vnode *vp; + INOUT struct uio *uio; + IN struct ucred *cred; + */ + +static int +hfs_readlink(ap) + struct vop_readlink_args /* { + struct vnode *a_vp; + struct uio *a_uio; + struct ucred *a_cred; + } */ *ap; +{ + int retval; + struct vnode *vp = ap->a_vp; + struct cnode *cp; + struct filefork *fp; + + if (vp->v_type != VLNK) + return (EINVAL); + + cp = VTOC(vp); + fp = VTOF(vp); + + /* Zero length sym links are not allowed */ + if (fp->ff_size == 0 || fp->ff_size > MAXPATHLEN) { + VTOVCB(vp)->vcbFlags |= kHFS_DamagedVolume; + return (EINVAL); + } + + /* Cache the path so we don't waste buffer cache resources */ + if (fp->ff_symlinkptr == NULL) { + struct buf *bp = NULL; + + MALLOC(fp->ff_symlinkptr, char *, fp->ff_size, M_TEMP, M_WAITOK); + retval = meta_bread(vp, 0, + roundup((int)fp->ff_size, + VTOHFS(vp)->hfs_phys_block_size), + ap->a_cred, &bp); + if (retval) { + if (bp) + brelse(bp); + if (fp->ff_symlinkptr) { + FREE(fp->ff_symlinkptr, M_TEMP); + fp->ff_symlinkptr = NULL; + } + return (retval); + } + bcopy(bp->b_data, fp->ff_symlinkptr, (size_t)fp->ff_size); + if (bp) { + bp->b_flags |= B_INVAL; /* data no longer needed */ + brelse(bp); + } + } + retval = uiomove((caddr_t)fp->ff_symlinkptr, (int)fp->ff_size, ap->a_uio); + + return (retval); +} + + +/* + * hfs 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. +#% abortop dvp = = = +# + vop_abortop { + IN struct vnode *dvp; + IN struct componentname *cnp; + + */ + +/* ARGSUSED */ + +static int +hfs_abortop(ap) + struct vop_abortop_args /* { + struct vnode *a_dvp; + struct componentname *a_cnp; + } */ *ap; +{ + if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) + FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI); + + return (0); +} + + +/* + * Lock an cnode. If its already locked, set the WANT bit and sleep. +#% lock vp U L U +# + vop_lock { + IN struct vnode *vp; + IN int flags; + IN struct proc *p; + */ + +static int +hfs_lock(ap) + struct vop_lock_args /* { + struct vnode *a_vp; + int a_flags; + struct proc *a_p; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); + + if (cp == NULL) + panic("hfs_lock: cnode in vnode is null\n"); + + return (lockmgr(&cp->c_lock, ap->a_flags, &vp->v_interlock, ap->a_p)); +} + +/* + * Unlock an cnode. +#% unlock vp L U L +# + vop_unlock { + IN struct vnode *vp; + IN int flags; + IN struct proc *p; + + */ +static int +hfs_unlock(ap) + struct vop_unlock_args /* { + struct vnode *a_vp; + int a_flags; + struct proc *a_p; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); + + if (cp == NULL) + panic("hfs_unlock: cnode in vnode is null\n"); + + return (lockmgr(&cp->c_lock, ap->a_flags | LK_RELEASE, + &vp->v_interlock, ap->a_p)); +} + + +/* + * Print out the contents of a cnode. +#% print vp = = = +# + vop_print { + IN struct vnode *vp; + */ +static int +hfs_print(ap) + struct vop_print_args /* { + struct vnode *a_vp; + } */ *ap; +{ + struct vnode * vp = ap->a_vp; + struct cnode *cp = VTOC(vp); + + printf("tag VT_HFS, cnid %d, on dev %d, %d", cp->c_cnid, + major(cp->c_dev), minor(cp->c_dev)); +#if FIFO + if (vp->v_type == VFIFO) + fifo_printinfo(vp); +#endif /* FIFO */ + lockmgr_printinfo(&cp->c_lock); + printf("\n"); + return (0); +} + + +/* + * Check for a locked cnode. +#% islocked vp = = = +# + vop_islocked { + IN struct vnode *vp; + + */ +static int +hfs_islocked(ap) + struct vop_islocked_args /* { + struct vnode *a_vp; + } */ *ap; +{ + return (lockstatus(&VTOC(ap->a_vp)->c_lock)); +} + +/* + +#% pathconf vp L L L +# + vop_pathconf { + IN struct vnode *vp; + IN int name; + OUT register_t *retval; + + */ +static int +hfs_pathconf(ap) + struct vop_pathconf_args /* { + struct vnode *a_vp; + int a_name; + int *a_retval; + } */ *ap; +{ + int retval = 0; + + switch (ap->a_name) { + case _PC_LINK_MAX: + if (VTOVCB(ap->a_vp)->vcbSigWord == kHFSPlusSigWord) + *ap->a_retval = HFS_LINK_MAX; + else + *ap->a_retval = 1; + break; + case _PC_NAME_MAX: + *ap->a_retval = kHFSPlusMaxFileNameBytes; /* max # of characters x max utf8 representation */ + break; + case _PC_PATH_MAX: + *ap->a_retval = PATH_MAX; /* 1024 */ + break; + case _PC_CHOWN_RESTRICTED: + *ap->a_retval = 1; + break; + case _PC_NO_TRUNC: + *ap->a_retval = 0; + break; + case _PC_NAME_CHARS_MAX: + *ap->a_retval = kHFSPlusMaxFileNameChars; + break; + case _PC_CASE_SENSITIVE: + *ap->a_retval = 0; + break; + case _PC_CASE_PRESERVING: + *ap->a_retval = 1; + break; + default: + retval = EINVAL; + } + + return (retval); +} + + +/* + * Advisory record locking support +#% advlock vp U U U +# + vop_advlock { + IN struct vnode *vp; + IN caddr_t id; + IN int op; + IN struct flock *fl; + IN int flags; + + */ +static int +hfs_advlock(ap) + struct vop_advlock_args /* { + struct vnode *a_vp; + caddr_t a_id; + int a_op; + struct flock *a_fl; + int a_flags; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct flock *fl = ap->a_fl; + struct hfslockf *lock; + struct filefork *fork; + off_t start, end; + int retval; + + /* Only regular files can have locks */ + if (vp->v_type != VREG) + return (EISDIR); + + fork = VTOF(ap->a_vp); + /* + * Avoid the common case of unlocking when cnode has no locks. + */ + if (fork->ff_lockf == (struct hfslockf *)0) { + if (ap->a_op != F_SETLK) { + fl->l_type = F_UNLCK; + return (0); + } + } + /* + * Convert the flock structure into a start and end. + */ + start = 0; + 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 = fork->ff_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 hfslockf structure + */ + MALLOC(lock, struct hfslockf *, sizeof *lock, M_LOCKF, M_WAITOK); + lock->lf_start = start; + lock->lf_end = end; + lock->lf_id = ap->a_id; + lock->lf_fork = fork; + lock->lf_type = fl->l_type; + lock->lf_next = (struct hfslockf *)0; + TAILQ_INIT(&lock->lf_blkhd); + lock->lf_flags = ap->a_flags; + /* + * Do the requested operation. + */ + switch(ap->a_op) { + case F_SETLK: + retval = hfs_setlock(lock); + break; + case F_UNLCK: + retval = hfs_clearlock(lock); + FREE(lock, M_LOCKF); + break; + case F_GETLK: + retval = hfs_getlock(lock, fl); + FREE(lock, M_LOCKF); + break; + default: + retval = EINVAL; + _FREE(lock, M_LOCKF); + break; + } + + return (retval); +} + + + +/* + * Update the access, modified, and node change times as specified + * by the C_ACCESS, C_UPDATE, and C_CHANGE flags respectively. The + * C_MODIFIED flag is used to specify that the node needs to be + * updated but that the times have already been set. The access and + * modified times are input parameters but the node change time is + * always taken from the current time. If waitfor is set, then wait + * for the disk write of the node to complete. + */ +/* +#% update vp L L L + IN struct vnode *vp; + IN struct timeval *access; + IN struct timeval *modify; + IN int waitfor; +*/ +static int +hfs_update(ap) + struct vop_update_args /* { + struct vnode *a_vp; + struct timeval *a_access; + struct timeval *a_modify; + int a_waitfor; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(ap->a_vp); + struct proc *p; + struct cat_fork *dataforkp = NULL; + struct cat_fork *rsrcforkp = NULL; + struct cat_fork datafork; + int updateflag; + int error; + + /* XXX do we really want to clear the sytem cnode flags here???? */ + if ((vp->v_flag & VSYSTEM) || + (VTOVFS(vp)->mnt_flag & MNT_RDONLY) || + (cp->c_mode == 0)) { + cp->c_flag &= ~(C_ACCESS | C_CHANGE | C_MODIFIED | C_UPDATE); + return (0); + } + + updateflag = cp->c_flag & (C_ACCESS | C_CHANGE | C_MODIFIED | C_UPDATE); + + /* Nothing to update. */ + if (updateflag == 0) + return (0); + /* HFS standard doesn't have access times. */ + if ((updateflag == C_ACCESS) && (VTOVCB(vp)->vcbSigWord == kHFSSigWord)) + return (0); + if (updateflag & C_ACCESS) { + /* + * If only the access time is changing then defer + * updating it on-disk util later (in hfs_inactive). + * If it was recently updated then skip the update. + */ + if (updateflag == C_ACCESS) { + cp->c_flag &= ~C_ACCESS; + + /* Its going to disk or its sufficiently newer... */ + if ((cp->c_flag & C_ATIMEMOD) || + (ap->a_access->tv_sec > (cp->c_atime + ATIME_ACCURACY))) { + cp->c_atime = ap->a_access->tv_sec; + cp->c_flag |= C_ATIMEMOD; + } + return (0); + } else { + cp->c_atime = ap->a_access->tv_sec; + } + } + if (updateflag & C_UPDATE) { + cp->c_mtime = ap->a_modify->tv_sec; + cp->c_mtime_nsec = ap->a_modify->tv_usec * 1000; + } + if (updateflag & C_CHANGE) { + cp->c_ctime = time.tv_sec; + /* + * HFS dates that WE set must be adjusted for DST + */ + if ((VTOVCB(vp)->vcbSigWord == kHFSSigWord) && gTimeZone.tz_dsttime) { + cp->c_ctime += 3600; + cp->c_mtime = cp->c_ctime; + } + } + + if (cp->c_datafork) + dataforkp = &cp->c_datafork->ff_data; + if (cp->c_rsrcfork) + rsrcforkp = &cp->c_rsrcfork->ff_data; + + p = current_proc(); + + /* + * For delayed allocations updates are + * postponed until an fsync or the file + * gets written to disk. + * + * Deleted files can defer meta data updates until inactive. + */ + if (ISSET(cp->c_flag, C_DELETED) || + (dataforkp && cp->c_datafork->ff_unallocblocks) || + (rsrcforkp && cp->c_rsrcfork->ff_unallocblocks)) { + if (updateflag & (C_CHANGE | C_UPDATE)) + hfs_volupdate(VTOHFS(vp), VOL_UPDATE, 0); + cp->c_flag &= ~(C_ACCESS | C_CHANGE | C_UPDATE); + cp->c_flag |= C_MODIFIED; + return (0); + } + + /* + * For files with invalid ranges (holes) the on-disk + * field representing the size of the file (cf_size) + * must be no larger than the start of the first hole. + */ + if (dataforkp && !CIRCLEQ_EMPTY(&cp->c_datafork->ff_invalidranges)) { + bcopy(dataforkp, &datafork, sizeof(datafork)); + datafork.cf_size = CIRCLEQ_FIRST(&cp->c_datafork->ff_invalidranges)->rl_start; + dataforkp = &datafork; + } + + /* + * Lock the Catalog b-tree file. + * A shared lock is sufficient since an update doesn't change + * the tree and the lock on vp protects the cnode. + */ + error = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_SHARED, p); + if (error) + return (error); + + /* XXX - waitfor is not enforced */ + error = cat_update(VTOHFS(vp), &cp->c_desc, &cp->c_attr, dataforkp, rsrcforkp); + + /* Unlock the Catalog b-tree file. */ + (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, p); + + if (updateflag & (C_CHANGE | C_UPDATE)) + hfs_volupdate(VTOHFS(vp), VOL_UPDATE, 0); + + /* After the updates are finished, clear the flags */ + cp->c_flag &= ~(C_ACCESS | C_CHANGE | C_MODIFIED | C_UPDATE | C_ATIMEMOD); + + return (error); +} + +/* + * Allocate a new node + * + * Upon leaving, namei buffer must be freed. + * + */ +static int +hfs_makenode(mode, dvp, vpp, cnp) + int mode; + struct vnode *dvp; + struct vnode **vpp; + struct componentname *cnp; +{ + struct cnode *cp; + struct cnode *dcp; + struct vnode *tvp; + struct hfsmount *hfsmp; + struct timeval tv; + struct proc *p; + struct cat_desc in_desc, out_desc; + struct cat_attr attr; + int error; + enum vtype vnodetype; + + p = cnp->cn_proc; + dcp = VTOC(dvp); + hfsmp = VTOHFS(dvp); + *vpp = NULL; + tvp = NULL; + bzero(&out_desc, sizeof(out_desc)); + + if ((mode & S_IFMT) == 0) + mode |= S_IFREG; + vnodetype = IFTOVT(mode); + + /* Check if unmount in progress */ + if (VTOVFS(dvp)->mnt_kern_flag & MNTK_UNMOUNT) { + error = EPERM; + goto exit; + } + /* Check if were out of usable disk space. */ + if ((suser(cnp->cn_cred, NULL) != 0) && (hfs_freeblks(hfsmp, 1) <= 0)) { + error = ENOSPC; + goto exit; + } + + /* Setup the default attributes */ + bzero(&attr, sizeof(attr)); + attr.ca_mode = mode; + attr.ca_nlink = vnodetype == VDIR ? 2 : 1; + attr.ca_mtime = time.tv_sec; + attr.ca_mtime_nsec = time.tv_usec * 1000; + if ((VTOVCB(dvp)->vcbSigWord == kHFSSigWord) && gTimeZone.tz_dsttime) { + attr.ca_mtime += 3600; /* Same as what hfs_update does */ + } + attr.ca_atime = attr.ca_ctime = attr.ca_itime = attr.ca_mtime; + if (VTOVFS(dvp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) { + attr.ca_uid = hfsmp->hfs_uid; + attr.ca_gid = hfsmp->hfs_gid; + } else { + if (vnodetype == VLNK) + attr.ca_uid = dcp->c_uid; + else + attr.ca_uid = cnp->cn_cred->cr_uid; + attr.ca_gid = dcp->c_gid; + } + /* + * Don't tag as a special file (BLK or CHR) until *after* + * hfs_getnewvnode is called. This insures that any + * alias checking is defered until hfs_mknod completes. + */ + if (vnodetype == VBLK || vnodetype == VCHR) + attr.ca_mode = (attr.ca_mode & ~S_IFMT) | S_IFREG; + + /* Tag symlinks with a type and creator. */ + if (vnodetype == VLNK) { + struct FndrFileInfo *fip; + + fip = (struct FndrFileInfo *)&attr.ca_finderinfo; + fip->fdType = SWAP_BE32(kSymLinkFileType); + fip->fdCreator = SWAP_BE32(kSymLinkCreator); + } + if ((attr.ca_mode & S_ISGID) && + !groupmember(dcp->c_gid, cnp->cn_cred) && + suser(cnp->cn_cred, NULL)) { + attr.ca_mode &= ~S_ISGID; + } + if (cnp->cn_flags & ISWHITEOUT) + attr.ca_flags |= UF_OPAQUE; + + /* Setup the descriptor */ + bzero(&in_desc, sizeof(in_desc)); + in_desc.cd_nameptr = cnp->cn_nameptr; + in_desc.cd_namelen = cnp->cn_namelen; + in_desc.cd_parentcnid = dcp->c_cnid; + in_desc.cd_flags = S_ISDIR(mode) ? CD_ISDIR : 0; + + /* Lock catalog b-tree */ + error = hfs_metafilelocking(VTOHFS(dvp), kHFSCatalogFileID, LK_EXCLUSIVE, p); + if (error) + goto exit; + + error = cat_create(hfsmp, &in_desc, &attr, &out_desc); + + /* Unlock catalog b-tree */ + (void) hfs_metafilelocking(VTOHFS(dvp), kHFSCatalogFileID, LK_RELEASE, p); + if (error) + goto exit; + + /* Update the parent directory */ + dcp->c_childhint = out_desc.cd_hint; /* Cache directory's location */ + dcp->c_nlink++; + dcp->c_entries++; + dcp->c_flag |= C_CHANGE | C_UPDATE; + tv = time; + (void) VOP_UPDATE(dvp, &tv, &tv, 0); + hfs_volupdate(hfsmp, vnodetype == VDIR ? VOL_MKDIR : VOL_MKFILE, + (dcp->c_cnid == kHFSRootFolderID)); + + /* Create a vnode for the object just created: */ + error = hfs_getnewvnode(hfsmp, NULL, &out_desc, 0, &attr, NULL, &tvp); + if (error) + goto exit; + +#if QUOTA + cp = VTOC(tvp); + /* + * We call hfs_chkiq with FORCE flag so that if we + * fall through to the rmdir we actually have + * accounted for the inode + */ + if ((error = hfs_getinoquota(cp)) || + (error = hfs_chkiq(cp, 1, cnp->cn_cred, FORCE))) { + if ((cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) { + FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI); + } + if (tvp->v_type == VDIR) + VOP_RMDIR(dvp,tvp, cnp); + else + VOP_REMOVE(dvp,tvp, cnp); + return (error); + } +#endif /* QUOTA */ + + /* + * restore vtype and mode for VBLK and VCHR + */ + if (vnodetype == VBLK || vnodetype == VCHR) { + struct cnode *cp; + + cp = VTOC(tvp); + cp->c_mode = mode; + tvp->v_type = IFTOVT(mode); + cp->c_flag |= C_CHANGE; + tv = time; + if ((error = VOP_UPDATE(tvp, &tv, &tv, 1))) { + vput(tvp); + goto exit; + } + } + + *vpp = tvp; +exit: + cat_releasedesc(&out_desc); + + if ((cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) + FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI); + vput(dvp); + + return (error); +} + + +static int +hfs_vgetrsrc(struct hfsmount *hfsmp, struct vnode *vp, struct vnode **rvpp, struct proc *p) +{ + struct vnode *rvp; + struct cnode *cp = VTOC(vp); + int error; + + if ((rvp = cp->c_rsrc_vp)) { + /* Use exising vnode */ + error = vget(rvp, 0, p); + if (error) { + char * name = VTOC(vp)->c_desc.cd_nameptr; + + if (name) + printf("hfs_vgetrsrc: couldn't get" + " resource fork for %s\n", name); + return (error); + } + } else { + struct cat_fork rsrcfork; + + /* Lock catalog b-tree */ + error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_SHARED, p); + if (error) + return (error); + + /* Get resource fork data */ + error = cat_lookup(hfsmp, &cp->c_desc, 1, (struct cat_desc *)0, + (struct cat_attr *)0, &rsrcfork); + + /* Unlock the Catalog */ + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); + if (error) + return (error); + + error = hfs_getnewvnode(hfsmp, cp, &cp->c_desc, 1, &cp->c_attr, + &rsrcfork, &rvp); + if (error) + return (error); + } + + *rvpp = rvp; + return (0); +} + + +/* + * Wrapper for special device reads + */ +static int +hfsspec_read(ap) + struct vop_read_args /* { + struct vnode *a_vp; + struct uio *a_uio; + int a_ioflag; + struct ucred *a_cred; + } */ *ap; +{ + /* + * Set access flag. + */ + VTOC(ap->a_vp)->c_flag |= C_ACCESS; + return (VOCALL (spec_vnodeop_p, VOFFSET(vop_read), ap)); +} + +/* + * Wrapper for special device writes + */ +static int +hfsspec_write(ap) + struct vop_write_args /* { + struct vnode *a_vp; + struct uio *a_uio; + int a_ioflag; + struct ucred *a_cred; + } */ *ap; +{ + /* + * Set update and change flags. + */ + VTOC(ap->a_vp)->c_flag |= C_CHANGE | C_UPDATE; + return (VOCALL (spec_vnodeop_p, VOFFSET(vop_write), ap)); +} + +/* + * Wrapper for special device close + * + * Update the times on the cnode then do device close. + */ +static int +hfsspec_close(ap) + struct vop_close_args /* { + struct vnode *a_vp; + int a_fflag; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); + + simple_lock(&vp->v_interlock); + if (ap->a_vp->v_usecount > 1) + CTIMES(cp, &time, &time); + simple_unlock(&vp->v_interlock); + return (VOCALL (spec_vnodeop_p, VOFFSET(vop_close), ap)); +} + +#if FIFO +/* + * Wrapper for fifo reads + */ +static int +hfsfifo_read(ap) + struct vop_read_args /* { + struct vnode *a_vp; + struct uio *a_uio; + int a_ioflag; + struct ucred *a_cred; + } */ *ap; +{ + extern int (**fifo_vnodeop_p)(void *); + + /* + * Set access flag. + */ + VTOC(ap->a_vp)->c_flag |= C_ACCESS; + return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_read), ap)); +} + +/* + * Wrapper for fifo writes + */ +static int +hfsfifo_write(ap) + struct vop_write_args /* { + struct vnode *a_vp; + struct uio *a_uio; + int a_ioflag; + struct ucred *a_cred; + } */ *ap; +{ + extern int (**fifo_vnodeop_p)(void *); + + /* + * Set update and change flags. + */ + VTOC(ap->a_vp)->c_flag |= C_CHANGE | C_UPDATE; + return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_write), ap)); +} + +/* + * Wrapper for fifo close + * + * Update the times on the cnode then do device close. + */ +static int +hfsfifo_close(ap) + struct vop_close_args /* { + struct vnode *a_vp; + int a_fflag; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; +{ + extern int (**fifo_vnodeop_p)(void *); + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); + + simple_lock(&vp->v_interlock); + if (ap->a_vp->v_usecount > 1) + CTIMES(cp, &time, &time); + simple_unlock(&vp->v_interlock); + return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_close), ap)); +} +#endif /* FIFO */ + + +/***************************************************************************** +* +* VOP Tables +* +*****************************************************************************/ +int hfs_cache_lookup(); /* in hfs_lookup.c */ +int hfs_lookup(); /* in hfs_lookup.c */ +int hfs_read(); /* in hfs_readwrite.c */ +int hfs_write(); /* in hfs_readwrite.c */ +int hfs_ioctl(); /* in hfs_readwrite.c */ +int hfs_select(); /* in hfs_readwrite.c */ +int hfs_bmap(); /* in hfs_readwrite.c */ +int hfs_strategy(); /* in hfs_readwrite.c */ +int hfs_truncate(); /* in hfs_readwrite.c */ +int hfs_allocate(); /* in hfs_readwrite.c */ +int hfs_pagein(); /* in hfs_readwrite.c */ +int hfs_pageout(); /* in hfs_readwrite.c */ +int hfs_search(); /* in hfs_search.c */ +int hfs_bwrite(); /* in hfs_readwrite.c */ +int hfs_link(); /* in hfs_link.c */ +int hfs_blktooff(); /* in hfs_readwrite.c */ +int hfs_offtoblk(); /* in hfs_readwrite.c */ +int hfs_cmap(); /* in hfs_readwrite.c */ +int hfs_getattrlist(); /* in hfs_attrlist.c */ +int hfs_setattrlist(); /* in hfs_attrlist.c */ +int hfs_readdirattr(); /* in hfs_attrlist.c */ +int hfs_inactive(); /* in hfs_cnode.c */ +int hfs_reclaim(); /* in hfs_cnode.c */ + +int (**hfs_vnodeop_p)(void *); + +#define VOPFUNC int (*)(void *) + +struct vnodeopv_entry_desc hfs_vnodeop_entries[] = { + { &vop_default_desc, (VOPFUNC)vn_default_error }, + { &vop_lookup_desc, (VOPFUNC)hfs_cache_lookup }, /* lookup */ + { &vop_create_desc, (VOPFUNC)hfs_create }, /* create */ + { &vop_mknod_desc, (VOPFUNC)hfs_mknod }, /* mknod */ + { &vop_open_desc, (VOPFUNC)hfs_open }, /* open */ + { &vop_close_desc, (VOPFUNC)hfs_close }, /* close */ + { &vop_access_desc, (VOPFUNC)hfs_access }, /* access */ + { &vop_getattr_desc, (VOPFUNC)hfs_getattr }, /* getattr */ + { &vop_setattr_desc, (VOPFUNC)hfs_setattr }, /* setattr */ + { &vop_read_desc, (VOPFUNC)hfs_read }, /* read */ + { &vop_write_desc, (VOPFUNC)hfs_write }, /* write */ + { &vop_ioctl_desc, (VOPFUNC)hfs_ioctl }, /* ioctl */ + { &vop_select_desc, (VOPFUNC)hfs_select }, /* select */ + { &vop_exchange_desc, (VOPFUNC)hfs_exchange }, /* exchange */ + { &vop_mmap_desc, (VOPFUNC)err_mmap }, /* mmap */ + { &vop_fsync_desc, (VOPFUNC)hfs_fsync }, /* fsync */ + { &vop_seek_desc, (VOPFUNC)nop_seek }, /* seek */ + { &vop_remove_desc, (VOPFUNC)hfs_remove }, /* remove */ + { &vop_link_desc, (VOPFUNC)hfs_link }, /* link */ + { &vop_rename_desc, (VOPFUNC)hfs_rename }, /* rename */ + { &vop_mkdir_desc, (VOPFUNC)hfs_mkdir }, /* mkdir */ + { &vop_rmdir_desc, (VOPFUNC)hfs_rmdir }, /* rmdir */ + { &vop_mkcomplex_desc, (VOPFUNC)err_mkcomplex }, /* mkcomplex */ + { &vop_getattrlist_desc, (VOPFUNC)hfs_getattrlist }, /* getattrlist */ + { &vop_setattrlist_desc, (VOPFUNC)hfs_setattrlist }, /* setattrlist */ + { &vop_symlink_desc, (VOPFUNC)hfs_symlink }, /* symlink */ + { &vop_readdir_desc, (VOPFUNC)hfs_readdir }, /* readdir */ + { &vop_readdirattr_desc, (VOPFUNC)hfs_readdirattr }, /* readdirattr */ + { &vop_readlink_desc, (VOPFUNC)hfs_readlink }, /* readlink */ + { &vop_abortop_desc, (VOPFUNC)hfs_abortop }, /* abortop */ + { &vop_inactive_desc, (VOPFUNC)hfs_inactive }, /* inactive */ + { &vop_reclaim_desc, (VOPFUNC)hfs_reclaim }, /* reclaim */ + { &vop_lock_desc, (VOPFUNC)hfs_lock }, /* lock */ + { &vop_unlock_desc, (VOPFUNC)hfs_unlock }, /* unlock */ + { &vop_bmap_desc, (VOPFUNC)hfs_bmap }, /* bmap */ + { &vop_strategy_desc, (VOPFUNC)hfs_strategy }, /* strategy */ + { &vop_print_desc, (VOPFUNC)hfs_print }, /* print */ + { &vop_islocked_desc, (VOPFUNC)hfs_islocked }, /* islocked */ + { &vop_pathconf_desc, (VOPFUNC)hfs_pathconf }, /* pathconf */ + { &vop_advlock_desc, (VOPFUNC)hfs_advlock }, /* advlock */ + { &vop_reallocblks_desc, (VOPFUNC)err_reallocblks }, /* reallocblks */ + { &vop_truncate_desc, (VOPFUNC)hfs_truncate }, /* truncate */ + { &vop_allocate_desc, (VOPFUNC)hfs_allocate }, /* allocate */ + { &vop_update_desc, (VOPFUNC)hfs_update }, /* update */ + { &vop_searchfs_desc, (VOPFUNC)hfs_search }, /* search fs */ + { &vop_bwrite_desc, (VOPFUNC)hfs_bwrite }, /* bwrite */ + { &vop_pagein_desc, (VOPFUNC)hfs_pagein }, /* pagein */ + { &vop_pageout_desc,(VOPFUNC) hfs_pageout }, /* pageout */ + { &vop_copyfile_desc, (VOPFUNC)err_copyfile }, /* copyfile */ + { &vop_blktooff_desc, (VOPFUNC)hfs_blktooff }, /* blktooff */ + { &vop_offtoblk_desc, (VOPFUNC)hfs_offtoblk }, /* offtoblk */ + { &vop_cmap_desc, (VOPFUNC)hfs_cmap }, /* cmap */ + { NULL, (VOPFUNC)NULL } +}; + +struct vnodeopv_desc hfs_vnodeop_opv_desc = +{ &hfs_vnodeop_p, hfs_vnodeop_entries }; + +int (**hfs_specop_p)(void *); +struct vnodeopv_entry_desc hfs_specop_entries[] = { + { &vop_default_desc, (VOPFUNC)vn_default_error }, + { &vop_lookup_desc, (VOPFUNC)spec_lookup }, /* lookup */ + { &vop_create_desc, (VOPFUNC)spec_create }, /* create */ + { &vop_mknod_desc, (VOPFUNC)spec_mknod }, /* mknod */ + { &vop_open_desc, (VOPFUNC)spec_open }, /* open */ + { &vop_close_desc, (VOPFUNC)hfsspec_close }, /* close */ + { &vop_access_desc, (VOPFUNC)hfs_access }, /* access */ + { &vop_getattr_desc, (VOPFUNC)hfs_getattr }, /* getattr */ + { &vop_setattr_desc, (VOPFUNC)hfs_setattr }, /* setattr */ + { &vop_read_desc, (VOPFUNC)hfsspec_read }, /* read */ + { &vop_write_desc, (VOPFUNC)hfsspec_write }, /* write */ + { &vop_lease_desc, (VOPFUNC)spec_lease_check }, /* lease */ + { &vop_ioctl_desc, (VOPFUNC)spec_ioctl }, /* ioctl */ + { &vop_select_desc, (VOPFUNC)spec_select }, /* select */ + { &vop_revoke_desc, (VOPFUNC)spec_revoke }, /* revoke */ + { &vop_mmap_desc, (VOPFUNC)spec_mmap }, /* mmap */ + { &vop_fsync_desc, (VOPFUNC)hfs_fsync }, /* fsync */ + { &vop_seek_desc, (VOPFUNC)spec_seek }, /* seek */ + { &vop_remove_desc, (VOPFUNC)spec_remove }, /* remove */ + { &vop_link_desc, (VOPFUNC)spec_link }, /* link */ + { &vop_rename_desc, (VOPFUNC)spec_rename }, /* rename */ + { &vop_mkdir_desc, (VOPFUNC)spec_mkdir }, /* mkdir */ + { &vop_rmdir_desc, (VOPFUNC)spec_rmdir }, /* rmdir */ + { &vop_symlink_desc, (VOPFUNC)spec_symlink }, /* symlink */ + { &vop_readdir_desc, (VOPFUNC)spec_readdir }, /* readdir */ + { &vop_readlink_desc, (VOPFUNC)spec_readlink }, /* readlink */ + { &vop_abortop_desc, (VOPFUNC)spec_abortop }, /* abortop */ + { &vop_inactive_desc, (VOPFUNC)hfs_inactive }, /* inactive */ + { &vop_reclaim_desc, (VOPFUNC)hfs_reclaim }, /* reclaim */ + { &vop_lock_desc, (VOPFUNC)hfs_lock }, /* lock */ + { &vop_unlock_desc, (VOPFUNC)hfs_unlock }, /* unlock */ + { &vop_bmap_desc, (VOPFUNC)spec_bmap }, /* bmap */ + { &vop_strategy_desc, (VOPFUNC)spec_strategy }, /* strategy */ + { &vop_print_desc, (VOPFUNC)hfs_print }, /* print */ + { &vop_islocked_desc, (VOPFUNC)hfs_islocked }, /* islocked */ + { &vop_pathconf_desc, (VOPFUNC)spec_pathconf }, /* pathconf */ + { &vop_advlock_desc, (VOPFUNC)spec_advlock }, /* advlock */ + { &vop_blkatoff_desc, (VOPFUNC)spec_blkatoff }, /* blkatoff */ + { &vop_valloc_desc, (VOPFUNC)spec_valloc }, /* valloc */ + { &vop_reallocblks_desc, (VOPFUNC)spec_reallocblks }, /* reallocblks */ + { &vop_vfree_desc, (VOPFUNC)err_vfree }, /* vfree */ + { &vop_truncate_desc, (VOPFUNC)spec_truncate }, /* truncate */ + { &vop_update_desc, (VOPFUNC)hfs_update }, /* update */ + { &vop_bwrite_desc, (VOPFUNC)hfs_bwrite }, + { &vop_devblocksize_desc, (VOPFUNC)spec_devblocksize }, /* devblocksize */ + { &vop_pagein_desc, (VOPFUNC)hfs_pagein }, /* Pagein */ + { &vop_pageout_desc, (VOPFUNC)hfs_pageout }, /* Pageout */ + { &vop_copyfile_desc, (VOPFUNC)err_copyfile }, /* copyfile */ + { &vop_blktooff_desc, (VOPFUNC)hfs_blktooff }, /* blktooff */ + { &vop_offtoblk_desc, (VOPFUNC)hfs_offtoblk }, /* offtoblk */ + { (struct vnodeop_desc*)NULL, (VOPFUNC)NULL } +}; +struct vnodeopv_desc hfs_specop_opv_desc = + { &hfs_specop_p, hfs_specop_entries }; + +#if FIFO +int (**hfs_fifoop_p)(void *); +struct vnodeopv_entry_desc hfs_fifoop_entries[] = { + { &vop_default_desc, (VOPFUNC)vn_default_error }, + { &vop_lookup_desc, (VOPFUNC)fifo_lookup }, /* lookup */ + { &vop_create_desc, (VOPFUNC)fifo_create }, /* create */ + { &vop_mknod_desc, (VOPFUNC)fifo_mknod }, /* mknod */ + { &vop_open_desc, (VOPFUNC)fifo_open }, /* open */ + { &vop_close_desc, (VOPFUNC)hfsfifo_close }, /* close */ + { &vop_access_desc, (VOPFUNC)hfs_access }, /* access */ + { &vop_getattr_desc, (VOPFUNC)hfs_getattr }, /* getattr */ + { &vop_setattr_desc, (VOPFUNC)hfs_setattr }, /* setattr */ + { &vop_read_desc, (VOPFUNC)hfsfifo_read }, /* read */ + { &vop_write_desc, (VOPFUNC)hfsfifo_write }, /* write */ + { &vop_lease_desc, (VOPFUNC)fifo_lease_check }, /* lease */ + { &vop_ioctl_desc, (VOPFUNC)fifo_ioctl }, /* ioctl */ + { &vop_select_desc, (VOPFUNC)fifo_select }, /* select */ + { &vop_revoke_desc, (VOPFUNC)fifo_revoke }, /* revoke */ + { &vop_mmap_desc, (VOPFUNC)fifo_mmap }, /* mmap */ + { &vop_fsync_desc, (VOPFUNC)hfs_fsync }, /* fsync */ + { &vop_seek_desc, (VOPFUNC)fifo_seek }, /* seek */ + { &vop_remove_desc, (VOPFUNC)fifo_remove }, /* remove */ + { &vop_link_desc, (VOPFUNC)fifo_link }, /* link */ + { &vop_rename_desc, (VOPFUNC)fifo_rename }, /* rename */ + { &vop_mkdir_desc, (VOPFUNC)fifo_mkdir }, /* mkdir */ + { &vop_rmdir_desc, (VOPFUNC)fifo_rmdir }, /* rmdir */ + { &vop_symlink_desc, (VOPFUNC)fifo_symlink }, /* symlink */ + { &vop_readdir_desc, (VOPFUNC)fifo_readdir }, /* readdir */ + { &vop_readlink_desc, (VOPFUNC)fifo_readlink }, /* readlink */ + { &vop_abortop_desc, (VOPFUNC)fifo_abortop }, /* abortop */ + { &vop_inactive_desc, (VOPFUNC)hfs_inactive }, /* inactive */ + { &vop_reclaim_desc, (VOPFUNC)hfs_reclaim }, /* reclaim */ + { &vop_lock_desc, (VOPFUNC)hfs_lock }, /* lock */ + { &vop_unlock_desc, (VOPFUNC)hfs_unlock }, /* unlock */ + { &vop_bmap_desc, (VOPFUNC)fifo_bmap }, /* bmap */ + { &vop_strategy_desc, (VOPFUNC)fifo_strategy }, /* strategy */ + { &vop_print_desc, (VOPFUNC)hfs_print }, /* print */ + { &vop_islocked_desc, (VOPFUNC)hfs_islocked }, /* islocked */ + { &vop_pathconf_desc, (VOPFUNC)fifo_pathconf }, /* pathconf */ + { &vop_advlock_desc, (VOPFUNC)fifo_advlock }, /* advlock */ + { &vop_blkatoff_desc, (VOPFUNC)fifo_blkatoff }, /* blkatoff */ + { &vop_valloc_desc, (VOPFUNC)fifo_valloc }, /* valloc */ + { &vop_reallocblks_desc, (VOPFUNC)fifo_reallocblks }, /* reallocblks */ + { &vop_vfree_desc, (VOPFUNC)err_vfree }, /* vfree */ + { &vop_truncate_desc, (VOPFUNC)fifo_truncate }, /* truncate */ + { &vop_update_desc, (VOPFUNC)hfs_update }, /* update */ + { &vop_bwrite_desc, (VOPFUNC)hfs_bwrite }, + { &vop_pagein_desc, (VOPFUNC)hfs_pagein }, /* Pagein */ + { &vop_pageout_desc, (VOPFUNC)hfs_pageout }, /* Pageout */ + { &vop_copyfile_desc, (VOPFUNC)err_copyfile }, /* copyfile */ + { &vop_blktooff_desc, (VOPFUNC)hfs_blktooff }, /* blktooff */ + { &vop_offtoblk_desc, (VOPFUNC)hfs_offtoblk }, /* offtoblk */ + { &vop_cmap_desc, (VOPFUNC)hfs_cmap }, /* cmap */ + { (struct vnodeop_desc*)NULL, (VOPFUNC)NULL } +}; +struct vnodeopv_desc hfs_fifoop_opv_desc = + { &hfs_fifoop_p, hfs_fifoop_entries }; +#endif /* FIFO */ + + + diff --git a/bsd/hfs/hfscommon/BTree/BTree.c b/bsd/hfs/hfscommon/BTree/BTree.c index 1cd262eef..12c2680af 100644 --- a/bsd/hfs/hfscommon/BTree/BTree.c +++ b/bsd/hfs/hfscommon/BTree/BTree.c @@ -146,8 +146,6 @@ #include "../headers/BTreesPrivate.h" -#include "../headers/HFSInstrumentation.h" - /* * The amount that the BTree header leaf count can be wrong before we assume * it is in an infinite loop. @@ -193,8 +191,6 @@ OSStatus BTOpenPath (FCB *filePtr, BTHeaderRec *header; NodeRec nodeRec; - LogStartTime(kTraceOpenBTree); - ////////////////////// Preliminary Error Checking /////////////////////////// if ( filePtr == nil || @@ -256,7 +252,7 @@ OSStatus BTOpenPath (FCB *filePtr, Panic("\pBTOpen: getNodeProc returned error getting header node."); goto ErrorExit; } - + ++btreePtr->numGetNodes; header = (BTHeaderRec*) ((u_long)nodeRec.buffer + sizeof(BTNodeDescriptor)); @@ -293,20 +289,26 @@ OSStatus BTOpenPath (FCB *filePtr, btreePtr->flags = 0; btreePtr->writeCount = 1; - btreePtr->numGetNodes = 1; // for earlier call to getNodeProc - /////////////////////////// Check Header Node /////////////////////////////// - //€€ set kBadClose attribute bit, and UpdateNode - - // if nodeSize matches then we don't need to release, just CheckNode + // set kBadClose attribute bit, and UpdateNode /* b-tree node size must be at least as big as the physical block size */ - if (btreePtr->nodeSize < nodeRec.blockSize) { - err = fsBTBadNodeSize; - goto ErrorExit; + if (btreePtr->nodeSize < nodeRec.blockSize) + { + /* + * If this tree has any records or the media is writeable then + * we cannot mount using the current physical block size. + */ + if (btreePtr->leafRecords > 0 || + VTOHFS(btreePtr->fileRefNum)->hfs_media_writeable) + { + err = fsBTBadNodeSize; + goto ErrorExit; + } } + // if nodeSize Matches then we don't need to release, just CheckNode if ( btreePtr->nodeSize == nodeRec.blockSize ) { err = CheckNode (btreePtr, nodeRec.buffer); @@ -324,6 +326,7 @@ OSStatus BTOpenPath (FCB *filePtr, * buffer cache to read the entire node */ err = releaseBlockProc(btreePtr->fileRefNum, &nodeRec, kTrashBlock); + ++btreePtr->numReleaseNodes; M_ExitOnError (err); err = GetNode (btreePtr, kHeaderNodeNum, &nodeRec ); // calls CheckNode... @@ -336,19 +339,10 @@ OSStatus BTOpenPath (FCB *filePtr, err = ReleaseNode (btreePtr, &nodeRec); M_ExitOnError (err); - /* - * Under Mac OS, b-tree nodes can be non-contiguous on disk when the - * allocation block size is smaller than the b-tree node size. - */ - if ( !NodesAreContiguous(FCBTOVCB(filePtr), filePtr, btreePtr->nodeSize) ) - return fsBTInvalidNodeErr; - //////////////////////////////// Success //////////////////////////////////// //€€ align LEOF to multiple of node size? - just on close - LogEndTime(kTraceOpenBTree, noErr); - return noErr; @@ -360,8 +354,6 @@ ErrorExit: (void) ReleaseNode (btreePtr, &nodeRec); DisposePtr( (Ptr) btreePtr ); - LogEndTime(kTraceOpenBTree, err); - return err; } @@ -387,8 +379,6 @@ OSStatus BTClosePath (FCB *filePtr) OSStatus err; BTreeControlBlockPtr btreePtr; - LogStartTime(kTraceCloseBTree); - btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr; if (btreePtr == nil) @@ -405,16 +395,12 @@ OSStatus BTClosePath (FCB *filePtr) DisposePtr( (Ptr) btreePtr ); filePtr->fcbBTCBPtr = nil; - LogEndTime(kTraceCloseBTree, noErr); - return noErr; /////////////////////// Error - Clean Up and Exit /////////////////////////// ErrorExit: - LogEndTime(kTraceCloseBTree, err); - return err; } @@ -451,7 +437,6 @@ Result: noErr - success, record contains copy of record found OSStatus BTSearchRecord (FCB *filePtr, BTreeIterator *searchIterator, - UInt32 heuristicHint, FSBufferDescriptor *record, UInt16 *recordLen, BTreeIterator *resultIterator ) @@ -468,9 +453,6 @@ OSStatus BTSearchRecord (FCB *filePtr, Boolean foundRecord; Boolean validHint; - - LogStartTime(kTraceSearchBTree); - if (filePtr == nil) return paramErr; if (searchIterator == nil) return paramErr; @@ -516,30 +498,6 @@ OSStatus BTSearchRecord (FCB *filePtr, (void) BTInvalidateHint( searchIterator ); } - ////////////////////////////// Try the heuristicHint ////////////////////////////////// - - if ( (foundRecord == false) && (heuristicHint != kInvalidMRUCacheKey) && (nodeNum != heuristicHint) ) - { - LogStartTime(kHeuristicHint); - nodeNum = heuristicHint; - - err = GetNode (btreePtr, nodeNum, &node); - if( err == noErr ) - { - if ( ((BTNodeDescriptor*) node.buffer)->kind == kBTLeafNode && - ((BTNodeDescriptor*) node.buffer)->numRecords > 0 ) - { - foundRecord = SearchNode (btreePtr, node.buffer, &searchIterator->key, &index); - } - - if (foundRecord == false) - { - err = ReleaseNode (btreePtr, &node); - M_ExitOnError (err); - } - } - LogEndTime(kHeuristicHint, (foundRecord == false)); - } //////////////////////////// Search The Tree //////////////////////////////// @@ -600,8 +558,6 @@ OSStatus BTSearchRecord (FCB *filePtr, err = ReleaseNode (btreePtr, &node); M_ExitOnError (err); - LogEndTime(kTraceSearchBTree, (foundRecord == false)); - if (foundRecord == false) return fsBTRecordNotFoundErr; else return noErr; @@ -629,8 +585,6 @@ ErrorExit: if ( err == fsBTEmptyErr ) err = fsBTRecordNotFoundErr; - LogEndTime(kTraceSearchBTree, err); - return err; } @@ -673,8 +627,6 @@ OSStatus BTIterateRecord (FCB *filePtr, UInt16 index; - LogStartTime(kTraceGetBTreeRecord); - ////////////////////////// Priliminary Checks /////////////////////////////// left.buffer = nil; @@ -909,8 +861,6 @@ CopyData: M_ExitOnError (err); } - LogEndTime(kTraceGetBTreeRecord, noErr); - return noErr; /////////////////////// Error - Clean Up and Exit /////////////////////////// @@ -940,8 +890,6 @@ ErrorExit: if ( err == fsBTEmptyErr || err == fsBTEndOfIterationErr ) err = fsBTRecordNotFoundErr; - LogEndTime(kTraceGetBTreeRecord, err); - return err; } @@ -1039,6 +987,8 @@ BTIterateRecords(FCB *filePtr, BTreeIterationOperation operation, BTreeIterator err = FindIteratorPosition(btreePtr, iterator, &left, &node, &right, &nodeNum, &index, &foundRecord); + if (err == fsBTRecordNotFoundErr) + err = 0; M_ExitOnError(err); @@ -1134,6 +1084,10 @@ BTIterateRecords(FCB *filePtr, BTreeIterationOperation operation, BTreeIterator ProcessData: err = GetRecordByIndex(btreePtr, node.buffer, index, &keyPtr, &recordPtr, &len); + if (err) { + err = btBadNode; + goto ErrorExit; + } while (err == 0) { if (callBackProc(keyPtr, recordPtr, len, callBackState) == 0) @@ -1166,6 +1120,10 @@ ProcessData: } err = GetRecordByIndex(btreePtr, node.buffer, index, &keyPtr, &recordPtr, &len); + if (err) { + err = btBadNode; + goto ErrorExit; + } } @@ -1252,8 +1210,6 @@ OSStatus BTInsertRecord (FCB *filePtr, if (err != noErr) return err; - LogStartTime(kTraceInsertBTreeRecord); - btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr; REQUIRE_FILE_LOCK(btreePtr->fileRefNum, false); @@ -1360,8 +1316,6 @@ Success: iterator->hint.reserved1 = 0; iterator->hint.reserved2 = 0; - LogEndTime(kTraceInsertBTreeRecord, noErr); - return noErr; @@ -1380,8 +1334,6 @@ ErrorExit: if (err == fsBTEmptyErr) err = fsBTRecordNotFoundErr; - LogEndTime(kTraceInsertBTreeRecord, err); - return err; } @@ -1412,8 +1364,6 @@ OSStatus BTReplaceRecord (FCB *filePtr, if (err != noErr) return err; - LogStartTime(kTraceReplaceBTreeRecord); - btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr; REQUIRE_FILE_LOCK(btreePtr->fileRefNum, false); @@ -1507,8 +1457,6 @@ Success: iterator->hint.reserved1 = 0; iterator->hint.reserved2 = 0; - LogEndTime(kTraceReplaceBTreeRecord, noErr); - return noErr; @@ -1524,9 +1472,113 @@ ErrorExit: iterator->hint.reserved1 = 0; iterator->hint.reserved2 = 0; + return err; +} + + + +//////////////////////////////// BTUpdateRecord //////////////////////////////// + +OSStatus +BTUpdateRecord(FCB *filePtr, BTreeIterator *iterator, + IterateCallBackProcPtr callBackProc, void * callBackState) +{ + OSStatus err; + BTreeControlBlockPtr btreePtr; + TreePathTable treePathTable; + BlockDescriptor nodeRec; + RecordPtr recordPtr; + BTreeKeyPtr keyPtr; + UInt32 insertNodeNum; + UInt16 recordLen; + UInt16 index; + Boolean validHint; + + + ////////////////////////// Priliminary Checks /////////////////////////////// + + nodeRec.buffer = nil; // so we can call ReleaseNode + + btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr; + + REQUIRE_FILE_LOCK(btreePtr->fileRefNum, false); + + ////////////////////////////// Take A Hint ////////////////////////////////// + + err = IsItAHint (btreePtr, iterator, &validHint); + M_ExitOnError (err); + + if (validHint) + { + insertNodeNum = iterator->hint.nodeNum; + + err = GetNode (btreePtr, insertNodeNum, &nodeRec); + if (err == noErr) + { + if (((NodeDescPtr)nodeRec.buffer)->kind == kBTLeafNode && + SearchNode (btreePtr, nodeRec.buffer, &iterator->key, &index)) + { + err = GetRecordByIndex(btreePtr, nodeRec.buffer, index, &keyPtr, &recordPtr, &recordLen); + M_ExitOnError (err); + + err = callBackProc(keyPtr, recordPtr, recordLen, callBackState); + M_ExitOnError (err); + + err = UpdateNode (btreePtr, &nodeRec, 0, 0); + M_ExitOnError (err); + + ++btreePtr->numValidHints; + + goto Success; + } + else + { + (void) BTInvalidateHint( iterator ); + } + + err = ReleaseNode (btreePtr, &nodeRec); + M_ExitOnError (err); + } + else + { + (void) BTInvalidateHint( iterator ); + } + } + + ////////////////////////////// Get A Clue /////////////////////////////////// + + err = SearchTree (btreePtr, &iterator->key, treePathTable, &insertNodeNum, &nodeRec, &index); + M_ExitOnError (err); + + err = GetRecordByIndex(btreePtr, nodeRec.buffer, index, &keyPtr, &recordPtr, &recordLen); + M_ExitOnError (err); + + err = callBackProc(keyPtr, recordPtr, recordLen, callBackState); + M_ExitOnError (err); + + err = UpdateNode (btreePtr, &nodeRec, 0, 0); + M_ExitOnError (err); + +Success: + // create hint + iterator->hint.writeCount = btreePtr->writeCount; + iterator->hint.nodeNum = insertNodeNum; + iterator->hint.index = 0; + iterator->hint.reserved1 = 0; + iterator->hint.reserved2 = 0; + return noErr; + + ////////////////////////////// Error Exit /////////////////////////////////// - LogEndTime(kTraceReplaceBTreeRecord, err); +ErrorExit: + + (void) ReleaseNode (btreePtr, &nodeRec); + iterator->hint.writeCount = 0; + iterator->hint.nodeNum = 0; + iterator->hint.index = 0; + iterator->hint.reserved1 = 0; + iterator->hint.reserved2 = 0; return err; } @@ -1544,7 +1596,6 @@ OSStatus BTDeleteRecord (FCB *filePtr, UInt32 nodeNum; UInt16 index; - LogStartTime(kTraceDeleteBTreeRecord); ////////////////////////// Priliminary Checks /////////////////////////////// @@ -1582,8 +1633,6 @@ OSStatus BTDeleteRecord (FCB *filePtr, iterator->hint.nodeNum = 0; - LogEndTime(kTraceDeleteBTreeRecord, noErr); - return noErr; ////////////////////////////// Error Exit /////////////////////////////////// @@ -1591,8 +1640,6 @@ OSStatus BTDeleteRecord (FCB *filePtr, ErrorExit: (void) ReleaseNode (btreePtr, &nodeRec); - LogEndTime(kTraceDeleteBTreeRecord, err); - return err; } @@ -1657,8 +1704,6 @@ OSStatus BTFlushPath (FCB *filePtr) BTreeControlBlockPtr btreePtr; - LogStartTime(kTraceFlushBTree); - M_ReturnErrorIf (filePtr == nil, paramErr); btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr; @@ -1669,8 +1714,6 @@ OSStatus BTFlushPath (FCB *filePtr) err = UpdateHeader (btreePtr, false); - LogEndTime(kTraceFlushBTree, err); - return err; } diff --git a/bsd/hfs/hfscommon/BTree/BTreeAllocate.c b/bsd/hfs/hfscommon/BTree/BTreeAllocate.c index 46d23cecb..60cfa0635 100644 --- a/bsd/hfs/hfscommon/BTree/BTreeAllocate.c +++ b/bsd/hfs/hfscommon/BTree/BTreeAllocate.c @@ -323,8 +323,6 @@ OSStatus ExtendBTree (BTreeControlBlockPtr btreePtr, mapNodeRecSize = nodeSize - sizeof(BTNodeDescriptor) - 6; // 2 bytes of free space (see note) - // update for proper 64 bit arithmetic!! - //////////////////////// Count Bits In Node Map ///////////////////////////// @@ -344,13 +342,10 @@ OSStatus ExtendBTree (BTreeControlBlockPtr btreePtr, /////////////////////// Extend LEOF If Necessary //////////////////////////// - minEOF = newTotalNodes * nodeSize; + minEOF = (UInt64)newTotalNodes * (UInt64)nodeSize; if ( filePtr->fcbEOF < minEOF ) { - // - // ???? Does this B*Tree pack stop working when LEOF > 2^32-1? - // - maxEOF = ((UInt32)0xFFFFFFFFL); + maxEOF = (UInt64)0x7fffffffLL * (UInt64)nodeSize; err = btreePtr->setEndOfForkProc (btreePtr->fileRefNum, minEOF, maxEOF); M_ExitOnError (err); @@ -471,6 +466,9 @@ Success: btreePtr->freeNodes += (newTotalNodes - oldTotalNodes) - newMapNodes; btreePtr->flags |= kBTHeaderDirty; //€€ how about a macro for this + + /* Force the b-tree header changes to disk */ + (void) UpdateHeader (btreePtr, true); return noErr; diff --git a/bsd/hfs/hfscommon/BTree/BTreeMiscOps.c b/bsd/hfs/hfscommon/BTree/BTreeMiscOps.c index 93828720a..c71fab021 100644 --- a/bsd/hfs/hfscommon/BTree/BTreeMiscOps.c +++ b/bsd/hfs/hfscommon/BTree/BTreeMiscOps.c @@ -153,7 +153,7 @@ Result: noErr - success OSStatus VerifyHeader (FCB *filePtr, BTHeaderRec *header ) { - UInt32 forkSize; + UInt64 forkSize; UInt32 totalNodes; @@ -171,7 +171,7 @@ OSStatus VerifyHeader (FCB *filePtr, totalNodes = header->totalNodes; - forkSize = totalNodes * header->nodeSize; + forkSize = (UInt64)totalNodes * (UInt64)header->nodeSize; if ( forkSize != filePtr->fcbEOF ) return fsBTInvalidHeaderErr; diff --git a/bsd/hfs/hfscommon/BTree/BTreeNodeOps.c b/bsd/hfs/hfscommon/BTree/BTreeNodeOps.c index e80c07ec5..fe9b141df 100644 --- a/bsd/hfs/hfscommon/BTree/BTreeNodeOps.c +++ b/bsd/hfs/hfscommon/BTree/BTreeNodeOps.c @@ -101,7 +101,6 @@ */ #include "../headers/BTreesPrivate.h" -#include "../headers/HFSInstrumentation.h" @@ -193,8 +192,6 @@ OSStatus GetNode (BTreeControlBlockPtr btreePtr, GetBlockProcPtr getNodeProc; - LogStartTime(kTraceGetNode); - //€€ is nodeNum within proper range? if( nodeNum >= btreePtr->totalNodes ) { @@ -271,15 +268,11 @@ OSStatus GetNode (BTreeControlBlockPtr btreePtr, } } - LogEndTime(kTraceGetNode, noErr); - return noErr; ErrorExit: nodePtr->buffer = nil; nodePtr->blockHeader = nil; - - LogEndTime(kTraceGetNode, err); return err; } @@ -364,9 +357,7 @@ OSStatus ReleaseNode (BTreeControlBlockPtr btreePtr, { OSStatus err; ReleaseBlockProcPtr releaseNodeProc; - - - LogStartTime(kTraceReleaseNode); + err = noErr; @@ -382,8 +373,6 @@ OSStatus ReleaseNode (BTreeControlBlockPtr btreePtr, nodePtr->buffer = nil; nodePtr->blockHeader = nil; - - LogEndTime(kTraceReleaseNode, err); return err; } @@ -411,8 +400,6 @@ OSStatus TrashNode (BTreeControlBlockPtr btreePtr, OSStatus err; ReleaseBlockProcPtr releaseNodeProc; - - LogStartTime(kTraceReleaseNode); err = noErr; @@ -429,8 +416,6 @@ OSStatus TrashNode (BTreeControlBlockPtr btreePtr, nodePtr->buffer = nil; nodePtr->blockHeader = nil; - LogEndTime(kTraceReleaseNode, err); - return err; } @@ -473,17 +458,12 @@ OSStatus UpdateNode (BTreeControlBlockPtr btreePtr, (void) CheckNode (btreePtr, nodePtr->buffer); } - LogStartTime(kTraceReleaseNode); - releaseNodeProc = btreePtr->releaseBlockProc; err = releaseNodeProc (btreePtr->fileRefNum, nodePtr, flags | kMarkBlockDirty ); - - LogEndTime(kTraceReleaseNode, err); - - M_ExitOnError (err); ++btreePtr->numUpdateNodes; + M_ExitOnError (err); } nodePtr->buffer = nil; @@ -547,8 +527,8 @@ OSStatus CheckNode (BTreeControlBlockPtr btreePtr, NodeDescPtr node ) //XXX can we calculate a more accurate minimum record size? maxRecords = ( nodeSize - sizeof (BTNodeDescriptor) ) >> 3; - - if (node->numRecords > maxRecords) + + if (node->numRecords == 0 || node->numRecords > maxRecords) return fsBTInvalidNodeErr; ////////////////////////// check record offsets ///////////////////////////// diff --git a/bsd/hfs/hfscommon/BTree/BTreeTreeOps.c b/bsd/hfs/hfscommon/BTree/BTreeTreeOps.c index 19e831329..2de280321 100644 --- a/bsd/hfs/hfscommon/BTree/BTreeTreeOps.c +++ b/bsd/hfs/hfscommon/BTree/BTreeTreeOps.c @@ -194,63 +194,123 @@ OSStatus SearchTree (BTreeControlBlockPtr btreePtr, UInt16 *returnIndex ) { OSStatus err; - SInt16 level; - UInt32 curNodeNum; + SInt16 level; // Expected depth of current node + UInt32 curNodeNum; // Current node we're searching NodeRec nodeRec; UInt16 index; Boolean keyFound; + SInt8 nodeKind; // Kind of current node (index/leaf) KeyPtr keyPtr; UInt8 * dataPtr; UInt16 dataSize; - if (btreePtr->treeDepth == 0) // is the tree empty? + curNodeNum = btreePtr->rootNode; + level = btreePtr->treeDepth; + + if (level == 0) // is the tree empty? { err = fsBTEmptyErr; goto ErrorExit; } - curNodeNum = btreePtr->rootNode; - //€€ for debugging... treePathTable [0].node = 0; treePathTable [0].index = 0; while (true) { - PanicIf(curNodeNum == 0, "\pSearchTree: curNodeNum is zero!"); - - err = GetNode (btreePtr, curNodeNum, &nodeRec); - if (err != noErr) - { - goto ErrorExit; - } + // + // [2550929] Node number 0 is the header node. It is never a valid + // index or leaf node. If we're ever asked to search through node 0, + // something has gone wrong (typically a bad child node number, or + // we found a node full of zeroes that we thought was an index node). + // + if (curNodeNum == 0) + { +// Panic("\pSearchTree: curNodeNum is zero!"); + err = btBadNode; + goto ErrorExit; + } + + err = GetNode (btreePtr, curNodeNum, &nodeRec); + if (err != noErr) + { + goto ErrorExit; + } - keyFound = SearchNode (btreePtr, nodeRec.buffer, searchKey, &index); - - level = ((BTNodeDescriptor*)nodeRec.buffer)->height; //€€ or --level; - - - treePathTable [level].node = curNodeNum; - - if ( ((BTNodeDescriptor*)nodeRec.buffer)->kind == kBTLeafNode) - { - treePathTable [level].index = index; - break; // were done... - } - - if ( (keyFound != true) && (index != 0)) - --index; - - treePathTable [level].index = index; - - GetRecordByIndex (btreePtr, nodeRec.buffer, index, &keyPtr, &dataPtr, &dataSize); - curNodeNum = *(UInt32 *)dataPtr; - err = ReleaseNode (btreePtr, &nodeRec); - if (err != noErr) - { - goto ErrorExit; - } + // + // [2550929] Sanity check the node height and node type. We expect + // particular values at each iteration in the search. This checking + // quickly finds bad pointers, loops, and other damage to the + // hierarchy of the B-tree. + // + if (((BTNodeDescriptor*)nodeRec.buffer)->height != level) + { +// Panic("\pIncorrect node height"); + err = btBadNode; + goto ReleaseAndExit; + } + nodeKind = ((BTNodeDescriptor*)nodeRec.buffer)->kind; + if (level == 1) + { + // Nodes at level 1 must be leaves, by definition + if (nodeKind != kBTLeafNode) + { + // Panic("\pIncorrect node type: expected leaf"); + err = btBadNode; + goto ReleaseAndExit; + } + } + else + { + // A node at any other depth must be an index node + if (nodeKind != kBTIndexNode) + { +// Panic("\pIncorrect node type: expected index"); + err = btBadNode; + goto ReleaseAndExit; + } + } + + keyFound = SearchNode (btreePtr, nodeRec.buffer, searchKey, &index); + + treePathTable [level].node = curNodeNum; + + if (nodeKind == kBTLeafNode) + { + treePathTable [level].index = index; + break; // were done... + } + + if ( (keyFound != true) && (index != 0)) + --index; + + treePathTable [level].index = index; + + err = GetRecordByIndex (btreePtr, nodeRec.buffer, index, &keyPtr, &dataPtr, &dataSize); + if (err != noErr) + { + // [2550929] If we got an error, it is probably because the index was bad + // (typically a corrupt node that confused SearchNode). Invalidate the node + // so we won't accidentally use the corrupted contents. NOTE: the Mac OS 9 + // sources call this InvalidateNode. + + (void) TrashNode(btreePtr, &nodeRec); + goto ErrorExit; + } + + // Get the child pointer out of this index node. We're now done with the current + // node and can continue the search with the child node. + curNodeNum = *(UInt32 *)dataPtr; + err = ReleaseNode (btreePtr, &nodeRec); + if (err != noErr) + { + goto ErrorExit; + } + + // The child node should be at a level one less than the parent. + --level; } *nodeNum = curNodeNum; @@ -262,6 +322,10 @@ OSStatus SearchTree (BTreeControlBlockPtr btreePtr, else return fsBTRecordNotFoundErr; // searchKey not found, index identifies insert point +ReleaseAndExit: + (void) ReleaseNode(btreePtr, &nodeRec); + // fall into ErrorExit + ErrorExit: *nodeNum = 0; @@ -325,6 +389,7 @@ OSStatus InsertLevel (BTreeControlBlockPtr btreePtr, Boolean insertParent; Boolean updateParent; Boolean newRoot; + InsertKey insertKey; #if defined(applec) && !defined(__SC__) PanicIf ((level == 1) && (((NodeDescPtr)targetNode->buffer)->kind != kBTLeafNode), "\P InsertLevel: non-leaf at level 1! "); @@ -425,7 +490,6 @@ OSStatus InsertLevel (BTreeControlBlockPtr btreePtr, if ( insertParent ) { InsertKey *insertKeyPtr; - InsertKey insertKey; if ( updateParent ) { diff --git a/bsd/hfs/hfscommon/Catalog/Catalog.c b/bsd/hfs/hfscommon/Catalog/Catalog.c index 63950007d..e7134028f 100644 --- a/bsd/hfs/hfscommon/Catalog/Catalog.c +++ b/bsd/hfs/hfscommon/Catalog/Catalog.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -19,141 +19,6 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* - File: Catalog.c - - Contains: Catalog Manager Implementation - - Version: HFS Plus 1.0 - - Copyright: © 1996-2000 by Apple Computer, Inc., all rights reserved. - - File Ownership: - - DRI: Don Brady - - Other Contact: Mark Day - - Technology: xxx put technology here xxx - - Writers: - - (msd) Mark Day - (DSH) Deric Horn - (djb) Don Brady - - Change History (most recent first): - 2/2/99 djb Fix CreateFileIDRef to copy entire name when creating thread record. - 1/7/99 djb Use a max bytes of 256 in calls to ConvertUnicodeToUTF8. - 12/9/98 djb UpdateCatalogNode only updates vcbLsMod if contentModDate changes. - 11/5/98 djb Add support for UTF-8 names. - 8/31/98 djb GetTimeLocal now takes an input. - 7/8/98 ser Added accessDate and AttributeModDate init. to create routine. - 6/5/98 djb Added CreateFileIDRef routine. - 6/3/98 djb Merge MoveCatalogRecord and RenameCatalogRecord into one routine. - 4/17/98 djb Add VCB locking. - 4/6/98 djb Catalog iterators now need to be released. - 4/6/98 djb Removed CreateVolumeCatalogCache and DisposeVolumeCatalogCache (obsolete). - 3/31/98 djb Make UpdateCatalogNode interface thread-safe. - 3/31/98 djb Sync up with final HFSVolumes.h header file. - 3/17/98 djb Fixed CreateCatalogNode interface to take kCatalogFolderNode and - kCatalogFileNode as type input. - - 12/10/97 DSH 2201501, UpdateCatalogNode to only update CatalogRecords which - are under 2 Gig by checking the overloaded valence field. - 11/20/97 djb Radar #2002357. Fixing retry mechanism. - 11/17/97 djb PrepareInputName routine now returns an error. - 11/13/97 djb Radar #1683572. Add new GetCatalogOffspringFile routine for - PBGetFileInfo calls (support used to be in HFSPathnameCalls.a). - 11/7/97 msd Change calls to the wrapper routine CompareUnicodeNames() to use - the underlying routine FastUnicodeCompare() instead. - 10/19/97 msd Bug 1684586. GetCatInfo and SetCatInfo use only contentModDate. - 10/17/97 djb Change Catalog Create/Rename to use ConvertInputNameToUnicode. - 10/13/97 djb Update volumeNameEncodingHint when changing volume name. Change - name of GetSystemTextEncoding to GetDefaultTextEncoding. - 10/1/97 djb Add new catalog iterators and node cache to improve performance. - 9/12/97 msd In CreateCatalogNode, make sure parent is a folder, not a file. - 9/10/97 msd In RenameCatalogNodeUnicode, remove HFS-only code and make sure - the conversion context is set up and marked in the volume's - bitmap. - 9/9/97 DSH Added RelString_Glue to avoid having to link DFAEngine with - Interface.o - 9/8/97 msd Make sure a folder's modifyDate is set whenever its - contentModDate is set. In UpdateCatalogNode, make sure the - modifyDate is greater or equal to contentModDate; do a DebugStr - only for debug builds. - 9/7/97 djb Make some DebuStrs HFS_DIAGNOSTIC only. - 9/4/97 djb Add more Catalog Iterators, Instrument RelString. - 9/4/97 msd Remove call to PropertyDeleteObject. - 8/18/97 DSH Use RelString instead of FastRelString in DFA to avoid loading - branch island instead of table. - 8/14/97 djb Remove hard link support. Switch over to FastRelString. - 8/8/97 djb Fixed bugs in LinkCatalogNode. - 8/5/97 djb Don't restore vcbNxtCNID if thread exists (radar #1670614). - 7/25/97 DSH Pass heuristicHint to BTSearchRecord from GetCatalogOffspring. - 7/18/97 msd Include LowMemPriv.h. In LinkCatalogNode, now sets the - kInsertedFileThread2 flag correctly; should only affect error - recovery code. - 7/16/97 DSH FilesInternal.i renamed FileMgrInternal.i to avoid name - collision - 7/8/97 DSH Loading PrecompiledHeaders from define passed in on C line - 6/27/97 msd Add PBLongRename SPI. Added RenameCatalogNodeUnicode call, which - takes Unicode names for HFS Plus volumes. Removed calls to - Attributes module when creating, renaming or moving nodes. - 6/24/97 djb Validate the mangled name matches in - LocateCatalogNodeByMangledName. - 6/24/97 djb Add hard link support. - 6/20/97 msd Use contentModDate and attributeModDate fields instead of - modifyDate. Made CopyCatalogNodeData public. - 6/18/97 djb Add routines LocateCatalogNodeWithRetry & UpdateVolumeEncodings. - Add mangled name retry to DeleteCatalogNode, MoveCatalogNode and - RenameCatalogNode. - 6/13/97 djb Major changes for longname support and multiple scripts. - 6/9/97 msd Instead of calling GetDateTime, call GetTimeUTC or GetTimeLocal. - Dates on an HFS Plus volume need to be converted to/from UTC. - 6/4/97 djb Set textEncoding hint in Rename and Create. TrashCatalogIterator - was not always called with the correct folder ID. - 5/21/97 djb Turn off recursive iterators. - 5/19/97 djb Add support for B-tree iterators to GetCatalogOffspring. - 5/9/97 djb Get in sync with FilesInternal.i. - 4/24/97 djb First checked into Common System Project. - 4/11/97 DSH Use extended VCB fields catalogRefNum, and extentsRefNum. - 4/4/97 djb Get in sync with volume format changes. - 3/31/97 djb Additional HFS Plus optimization added to GetCatalogNode. - 3/28/97 djb Add Optimization to GetCatalogNode. - 3/27/97 djb Unicode conversion routines now use byte counts. - 3/17/97 DSH Casting to compile with SC, GetRecordSize -> - GetCatalogRecordSize, moved some prototypes to extern. - 3/5/97 msd Add calls to Property Manager when catalog entries are created, - deleted, moved, renamed. - 2/19/97 djb HFS Plus catalog keys no longer have a pad word. - 1/24/97 DSH (djb) GetCatalogOffSpring() fix volume->vcbDirIDM = 0 - 1/23/97 DSH Truncate name to CMMaxCName characters in PrepareInputName(). - 1/14/97 djb Fixed RenameCatalogNode for case when just a cnid is passed. - 1/13/97 djb Added support for varaible sized thread records in HFS+. - 1/11/97 DSH Moving PrepareInputName() declaration fo FilesInternal.h - 1/10/97 djb CopyCatalogNodeData was trashing the resource extents on HFS+. - 1/10/97 djb CopyCatalogNodeData was trashing dataLogicalSize on HFS+ disks. - 1/9/97 djb Get in sync with new HFSVolumesPriv.i. - 1/6/97 djb Added name length checking to CompareExtendedCatalogKeys. Fixed - GetCatalogOffspring - it was not correctly passing the HFS+ flag - to PrepareOutputName. Fixed BuildKey for HFS+ keys. - 1/3/97 djb Fixed termination bug in GetCatalogOffspring. Added support for - large keys. Integrated latest HFSVolumesPriv.h changes. - 12/19/96 DSH Changed call from C_FlushMDB to HFS+ savy - FlushVolumeControlBlock() - 12/19/96 djb Add new B-tree manager... - 12/13/96 djb Fixing bugs for HFS+. Switch to HFSUnicodeWrappers routines. - 12/12/96 djb Changed the SPI for GetCatalogNode, GetCatalogOffspring, and - UpdateCatalogNode. - 12/12/96 DSH Removed static function declarations for functions used by - FileIDServices.c. - 11/11/96 djb Added support for HFS+ Unicode names. Major changes throughout. - 11/4/96 djb Added FSSpec output to GetCatalogNode and GetCatalogOffspring - routines. - 10/29/96 djb first checked in - -*/ #pragma segment Catalog @@ -166,632 +31,20 @@ #include "../headers/BTreesInternal.h" #include "../headers/CatalogPrivate.h" #include "../headers/HFSUnicodeWrappers.h" -#include "../headers/HFSInstrumentation.h" // External routines extern SInt32 FastRelString( ConstStr255Param str1, ConstStr255Param str2 ); -extern SInt16 RelString_Glue(StringPtr pStr1, StringPtr pStr2); - - -// Internal routines - -static OSErr IterateCatalogNode(ExtendedVCB *volume, CatalogIterator *catalogIterator, - UInt16 index, CatalogNodeData *nodeData, - HFSCatalogNodeID *nodeID, SInt16 *nodeType); - -void InitCatalogThreadRecord(ExtendedVCB *volume, UInt32 nodeType, CatalogKey *nodeKey, - CatalogRecord *record, UInt32 *threadSize); - -void InitCatalogRecord(ExtendedVCB *volume, UInt32 nodeType, UInt32 textEncoding, - CatalogRecord *record, UInt32 *recordSize, HFSCatalogNodeID catalogNodeID); - -#if HFS_DIAGNOSTIC - #include - #define PRINTIT(A) kprintf A; -#else - #define PRINTIT(A) -#endif /* HFS_DIAGNOSTIC */ //_________________________________________________________________________________ // Exported Routines // -// CreateCatalogNode - Creates a new folder or file CNode. -// DeleteCatalogNode - Deletes an existing folder or file CNode. -// GetCatalogNode - Locates an existing folder or file CNode. -// GetCatalogOffspringFile - Gets an offspring file record from a folder. -// GetCatalogOffspring - Gets an offspring record from a folder. -// MoveRenameCatalogNode - Moves/Renames an existing folder or file CNode. -// UpdateCatalogNode - Marks a Catalog BTree node as 'dirty'. -// CreateFileIDRef - Creates a file thread record for hfs file node -// CompareCatalogKeys - Compares two catalog keys. -// -//_________________________________________________________________________________ - - -//_________________________________________________________________________________ -// -// About date/time values: -// -// Date/time values stored in control blocks and generic structures (such as -// CatalogNodeData) are always stored in local time. Values stored in HFS volume -// format structures (such as B-tree records) are also stored in local time. -// Values stored in HFS Plus format structures are stored in UTC. -//_________________________________________________________________________________ - - -// Implementation - - -//_________________________________________________________________________________ -// Routine: CreateCatalogNode -// -// Function: Creates a new folder or file CNode. A new folder or file -// record is added to the catalog BTree. If a folder CNode is -// being created, a new thread record is also added. -// -//_________________________________________________________________________________ - -OSErr -CreateCatalogNode ( ExtendedVCB *volume, HFSCatalogNodeID parentID, ConstUTF8Param name, - UInt32 nodeType, HFSCatalogNodeID *catalogNodeID, UInt32 *catalogHint, - UInt32 teHint) -{ - CatalogKey *nodeKey; - CatalogRecord nodeData; // 520 bytes - UInt32 nodeDataSize; - CatalogRecord parentThreadData; // 520 bytes - HFSCatalogNodeID parentsParentID; - CatalogName *parentNamePtr; - UInt32 tempHint; - UInt32 textEncoding; - UInt16 tempSize; - OSErr result; - Boolean isHFSPlus = (volume->vcbSigWord == kHFSPlusSigWord); - FCB *fcb; - FSBufferDescriptor btRecord; - BTreeIterator iterator; - BTreeIterator threadIter; - HFSCatalogNodeID nextCNID; - - if (nodeType != kCatalogFolderNode && nodeType != kCatalogFileNode) - return paramErr; - - fcb = GetFileControlBlock(volume->catalogRefNum); - nodeKey = (CatalogKey *) &iterator.key; - - //--- make sure parent exists (by locating the parent's thread record) - - result = LocateCatalogThread(volume, parentID, &parentThreadData, &tempSize, &tempHint); - ReturnIfError(result); - - TrashCatalogIterator(volume, parentID); // invalidate any iterators for this parentID - - // save copy of parent's parentID and name. - - if (isHFSPlus) - { - if (parentThreadData.recordType != kHFSPlusFolderThreadRecord) - return dirNFErr; - - parentsParentID = parentThreadData.hfsPlusThread.parentID; - parentNamePtr = (CatalogName*) &parentThreadData.hfsPlusThread.nodeName; - } - else - { - if (parentThreadData.recordType != kHFSFolderThreadRecord) - return dirNFErr; - - parentsParentID = parentThreadData.hfsThread.parentID; - parentNamePtr = (CatalogName*) &parentThreadData.hfsThread.nodeName; - } - - // invalidate cache for parent since its about to change - InvalidateCatalogNodeCache(volume, parentsParentID); - - //--- build key for new catalog node - textEncoding = teHint; - result = BuildCatalogKeyUTF8(volume, parentID, name, kUndefinedStrLen, nodeKey, &textEncoding); - ReturnIfError(result); - - /* make sure it doesn't exist */ - result = BTSearchRecord(fcb, &iterator, kInvalidMRUCacheKey, NULL, NULL, &iterator); - if (result != btNotFound) - return (cmExists); - - nextCNID = volume->vcbNxtCNID; - if (!isHFSPlus && nextCNID == 0xFFFFFFFF) - return (dskFulErr); - - //--- build thread record for new CNode - if (isHFSPlus || nodeType == kCatalogFolderNode) - { - CatalogRecord threadData; // 520 bytes - UInt32 threadSize; - - btRecord.bufferAddress = &threadData; - btRecord.itemSize = threadSize; - btRecord.itemCount = 1; - InitCatalogThreadRecord(volume, nodeType, nodeKey, &threadData, &threadSize); -TryNextID: - BuildCatalogKey(nextCNID, NULL, isHFSPlus, (CatalogKey*) &threadIter.key); - result = BTInsertRecord(fcb, &threadIter, &btRecord, threadSize); - if (result == btExists && isHFSPlus) - { - /* - * Allow CNIDs on HFS Plus volumes to wrap around - */ - ++nextCNID; - if (nextCNID < kHFSFirstUserCatalogNodeID) - { - volume->vcbAtrb |= kHFSCatalogNodeIDsReusedMask; - volume->vcbFlags |= 0xFF00; - nextCNID = kHFSFirstUserCatalogNodeID; - } - goto TryNextID; - } - ReturnIfError(result); - } - - //--- initialize catalog data record (for folder or file) - btRecord.bufferAddress = &nodeData; - btRecord.itemSize = nodeDataSize; - btRecord.itemCount = 1; - InitCatalogRecord(volume, nodeType, textEncoding, &nodeData, &nodeDataSize, nextCNID); - - //--- add new folder/file record to catalog BTree - result = BTInsertRecord(fcb, &iterator, &btRecord, nodeDataSize ); - if (result) - { - if (result == btExists) - result = cmExists; - - if (isHFSPlus || nodeType == kCatalogFolderNode) - (void) BTDeleteRecord(fcb, &threadIter); - - return result; - } - - /* - * Return the CNID actually used. Update the volume's next ID. - */ - *catalogNodeID = nextCNID; - if (++nextCNID < kHFSFirstUserCatalogNodeID) - { - volume->vcbAtrb |= kHFSCatalogNodeIDsReusedMask; - volume->vcbFlags |= 0xFF00; - nextCNID = kHFSFirstUserCatalogNodeID; - } - volume->vcbNxtCNID = nextCNID; - - //--- update counters... - - result = UpdateFolderCount( volume, parentsParentID, parentNamePtr, nodeData.recordType, kNoHint, +1); - ReturnIfError(result); /* XXX what about cleanup ??? */ - - AdjustVolumeCounts(volume, nodeData.recordType, +1); - - result = FlushCatalog(volume); - - return result; - -} // end CreateCatalogNode - - -/* - * initialize catalog data record (for folder or file) - */ -void InitCatalogRecord(ExtendedVCB *volume, UInt32 nodeType, UInt32 textEncoding, CatalogRecord *record, UInt32 *recordSize, HFSCatalogNodeID nodeID) -{ - UInt32 timeStamp; - - ClearMemory(record, sizeof(CatalogRecord)); // first clear the record - - if (volume->vcbSigWord == kHFSPlusSigWord) - { - timeStamp = GetTimeUTC(); // get current date/time (universal) - - UpdateVolumeEncodings(volume, textEncoding); - - if (nodeType == kCatalogFolderNode ) - { - record->recordType = kHFSPlusFolderRecord; - record->hfsPlusFolder.folderID = nodeID; - record->hfsPlusFolder.createDate = timeStamp; - record->hfsPlusFolder.contentModDate = timeStamp; - record->hfsPlusFolder.accessDate = timeStamp; - record->hfsPlusFolder.attributeModDate = timeStamp; - record->hfsPlusFolder.textEncoding = textEncoding; - *recordSize = sizeof(HFSPlusCatalogFolder); - // threadType = kHFSPlusFolderThreadRecord; - } - else if (nodeType == kCatalogFileNode ) - { - record->recordType = kHFSPlusFileRecord; - record->hfsPlusFile.fileID = nodeID; - record->hfsPlusFile.createDate = timeStamp; - record->hfsPlusFile.contentModDate = timeStamp; - record->hfsPlusFile.accessDate = timeStamp; - record->hfsPlusFile.attributeModDate = timeStamp; - record->hfsPlusFile.flags |= kHFSThreadExistsMask; - record->hfsPlusFile.textEncoding = textEncoding; - *recordSize = sizeof(HFSPlusCatalogFile); - // threadType = kHFSPlusFileThreadRecord; - } - } - else /* standard hfs */ - { - timeStamp = GetTimeLocal(true); // get current local date/time - - if (nodeType == kCatalogFolderNode ) - { - record->recordType = kHFSFolderRecord; - record->hfsFolder.folderID = nodeID; - record->hfsFolder.createDate = timeStamp; - record->hfsFolder.modifyDate = timeStamp; - *recordSize = sizeof(HFSCatalogFolder); - // threadType = kHFSFolderThreadRecord; - } - else if (nodeType == kCatalogFileNode ) - { - record->recordType = kHFSFileRecord; - record->hfsFile.fileID = nodeID; - record->hfsFile.createDate = timeStamp; - record->hfsFile.modifyDate = timeStamp; - *recordSize = sizeof(HFSCatalogFile); - } - } -} - - -void InitCatalogThreadRecord(ExtendedVCB *volume, UInt32 nodeType, CatalogKey *nodeKey, - CatalogRecord *record, UInt32 *threadSize) -{ - ClearMemory(record, sizeof(CatalogRecord) ); // first clear the record - - if (volume->vcbSigWord == kHFSPlusSigWord) - { - if (nodeType == kCatalogFolderNode) - record->recordType = kHFSPlusFolderThreadRecord; - else - record->recordType = kHFSPlusFileThreadRecord; - record->hfsPlusThread.parentID = nodeKey->hfsPlus.parentID; - *threadSize = sizeof(record->hfsPlusThread); - - // HFS Plus has varaible sized threads so adjust to actual length - *threadSize -= ( sizeof(record->hfsPlusThread.nodeName.unicode) - - (nodeKey->hfsPlus.nodeName.length * sizeof(UniChar)) ); - BlockMoveData(&nodeKey->hfsPlus.nodeName, &record->hfsPlusThread.nodeName, - sizeof(UniChar) * (nodeKey->hfsPlus.nodeName.length + 1)); - } - else // classic HFS - { - if (nodeType == kCatalogFolderNode) - record->recordType = kHFSFolderThreadRecord; - else - record->recordType = kHFSFileThreadRecord; - record->hfsThread.parentID = nodeKey->hfs.parentID; - *threadSize = sizeof(record->hfsThread); - BlockMoveData(&nodeKey->hfs.nodeName, &record->hfsThread.nodeName, - nodeKey->hfs.nodeName[0] + 1); - } -} - - -//_________________________________________________________________________________ -// Routine: DeleteCatalogNode -// -// Function: Deletes an existing folder or file CNode. The thread record -// is also deleted for directories and files that have thread -// records. -// -// The valence for a folder must be zero before it can be deleted. -// The rootfolder cannot be deleted. -// -//_________________________________________________________________________________ - -OSErr -DeleteCatalogNode(ExtendedVCB *volume, HFSCatalogNodeID parentID, ConstUTF8Param name, UInt32 hint) -{ - CatalogKey key; // 518 bytes - CatalogRecord data; // 520 bytes - UInt32 nodeHint; - HFSCatalogNodeID nodeID; - HFSCatalogNodeID nodeParentID; - UInt16 nodeType; - OSErr result; - Boolean isHFSPlus = (volume->vcbSigWord == kHFSPlusSigWord); - - //--- locate subject catalog node - - result = BuildCatalogKeyUTF8(volume, parentID, name, kUndefinedStrLen, &key, NULL); - ReturnIfError(result); - - result = LocateCatalogNodeByKey(volume, hint, &key, &data, &nodeHint); - - // if we did not find it by name, then look for an embedded file ID in a mangled name - if ( (result == cmNotFound) && isHFSPlus ) - result = LocateCatalogNodeByMangledName(volume, parentID, name, kUndefinedStrLen, &key, &data, &nodeHint); - - /* - * In Mac OS X there can also be HFS filenames that - * could not be encoded using the default encoding. - */ - if (result == cmNotFound && !isHFSPlus && VCBTOHFS(volume)->hfs_encoding != 0) { - Str31 hfsName; - - utf8_to_mac_roman(strlen(name), name, hfsName); - result = LocateCatalogNode(volume, parentID, (CatalogName*)hfsName, - 0, &key, &data, &nodeHint); - } - ReturnIfError(result); - - nodeParentID = isHFSPlus ? key.hfsPlus.parentID : key.hfs.parentID; // establish real parent cnid - nodeType = data.recordType; // establish cnode type - nodeID = 0; - - switch (nodeType) - { - case kHFSFolderRecord: - if (data.hfsFolder.valence != 0) // is it empty? - return cmNotEmpty; - - nodeID = data.hfsFolder.folderID; - break; - - case kHFSPlusFolderRecord: - if (data.hfsPlusFolder.valence != 0) // is it empty? - return cmNotEmpty; - - nodeID = data.hfsPlusFolder.folderID; - break; - - case kHFSFileRecord: - if (data.hfsFile.flags & kHFSThreadExistsMask) - nodeID = data.hfsFile.fileID; - break; - - case kHFSPlusFileRecord: - nodeID = data.hfsPlusFile.fileID; // note: HFS Plus files always have a thread - break; - - default: - return cmNotFound; - } - - - if (nodeID == fsRtDirID) // is this the root folder? - return cmRootCN; // sorry, you can't delete the root! - - TrashCatalogIterator(volume, nodeParentID); // invalidate any iterators for this parentID - InvalidateCatalogNodeCache(volume, nodeParentID); // and invalidate node cache - - //--- delete catalog records for CNode and file threads if they exist - - result = DeleteBTreeRecord(volume->catalogRefNum, &key); - ReturnIfError(result); - - if ( nodeID ) - { - CatalogKey threadKey; // 518 bytes - - BuildCatalogKey(nodeID, NULL, isHFSPlus, &threadKey); - - (void) DeleteBTreeRecord(volume->catalogRefNum, &threadKey); // ignore errors for thread deletes - } - - //--- update counters... - - result = UpdateFolderCount(volume, nodeParentID, NULL, nodeType, kNoHint, -1); - ReturnIfError(result); - - AdjustVolumeCounts(volume, nodeType, -1); // all done with this file or folder - - result = FlushCatalog(volume); - - return result; - -} // end DeleteCatalogNode - - -//_________________________________________________________________________________ -// Routine: GetCatalogNode -// -// Function: Locates an existing folder or file CNode and pointer to the CNode data record. +// CompareCatalogKeys - Compares two catalog keys. // //_________________________________________________________________________________ -OSErr -GetCatalogNode( ExtendedVCB *volume, HFSCatalogNodeID parentID, ConstUTF8Param name, UInt32 nameLen, UInt32 hint, - CatalogNodeData *nodeData, UInt32 *newHint) -{ - CatalogKey *key; - CatalogRecord *record; - BTreeIterator searchIterator; - FSBufferDescriptor btRecord; - ByteCount utf8len; - UInt32 heuristicHint; - UInt32 *cachedHint; - FCB *fcb; - OSErr result = noErr; - UInt16 dataSize; - Boolean isHFSPlus = (volume->vcbSigWord == kHFSPlusSigWord); - - if (isHFSPlus) { - btRecord.bufferAddress = nodeData; - btRecord.itemSize = sizeof(CatalogNodeData); - } else { - btRecord.bufferAddress = &nodeData->cnd_extra; - btRecord.itemSize = sizeof(HFSCatalogFile); - } - - btRecord.itemCount = 1; - record = (CatalogRecord *) btRecord.bufferAddress; - key = (CatalogKey *) &searchIterator.key; - - if (name && nameLen == kUndefinedStrLen) - nameLen = strlen(name); - - result = BuildCatalogKeyUTF8(volume, parentID, name, nameLen, key, NULL); - ReturnIfError(result); - - fcb = GetFileControlBlock(volume->catalogRefNum); - searchIterator.hint.nodeNum = *newHint; - searchIterator.hint.index = 0; - - /* - * We pass a 2nd hint/guess into BTSearchRecord. The heuristicHint - * is a mapping of dirID and nodeNumber, in hopes that the current - * search will be in the same node as the last search with the same - * parentID. - */ - if (name != NULL && GetMRUCacheBlock(parentID, volume->hintCachePtr, (Ptr *)&cachedHint) == 0) - heuristicHint = *cachedHint; - else - heuristicHint = kInvalidMRUCacheKey; - - result = BTSearchRecord(fcb, &searchIterator, heuristicHint, &btRecord, &dataSize, &searchIterator); - if (result == btNotFound) - result = cmNotFound; - - if (name != NULL && result == noErr) - InsertMRUCacheBlock(volume->hintCachePtr, parentID, (Ptr) &(searchIterator.hint.nodeNum)); - - if (result == noErr) { - CatalogName *nodeName = NULL; - HFSCatalogNodeID threadParentID; - - /* if we got a thread record, then go look up real record */ - switch (record->recordType) { - - case kHFSFileThreadRecord: - case kHFSFolderThreadRecord: - threadParentID = record->hfsThread.parentID; - nodeName = (CatalogName *) &record->hfsThread.nodeName; - break; - - case kHFSPlusFileThreadRecord: - case kHFSPlusFolderThreadRecord: - threadParentID = record->hfsPlusThread.parentID; - nodeName = (CatalogName *) &record->hfsPlusThread.nodeName; - break; - - default: - threadParentID = 0; - *newHint = searchIterator.hint.nodeNum; - break; - } - if (threadParentID) { - BuildCatalogKey(threadParentID, nodeName, isHFSPlus, key); - searchIterator.hint.nodeNum = kNoHint; - searchIterator.hint.index = 0; - - result = BTSearchRecord(fcb, &searchIterator, kInvalidMRUCacheKey, &btRecord, &dataSize, &searchIterator); - if (result == btNotFound) - result = cmNotFound; - if (result == noErr) - *newHint = searchIterator.hint.nodeNum; - } - } - - /* - * If we did not find it by name, then look for an embedded - * file ID in a mangled name. - */ - if ( result == cmNotFound && isHFSPlus) - result = LocateCatalogNodeByMangledName(volume, parentID, name, nameLen, - key, record, newHint); - - /* - * In Mac OS X there can also be HFS filenames that - * could not be encoded using the default encoding. - * In which case they were encoded as MacRoman. - */ - if (result == cmNotFound && !isHFSPlus && VCBTOHFS(volume)->hfs_encoding != 0) { - Str31 hfsName; - - utf8_to_mac_roman(nameLen, name, hfsName); - result = LocateCatalogNode(volume, parentID, (CatalogName*)hfsName, - 0, key, record, newHint); - } - ReturnIfError(result); - - nodeData->cnm_parID = isHFSPlus ? key->hfsPlus.parentID : key->hfs.parentID; - - if (nodeData->cnm_flags & kCatNameNoCopyName) { - if (! isHFSPlus) { - if (record->recordType == kHFSFolderRecord || record->recordType == kHFSFileRecord) - CopyCatalogNodeData(volume, record, nodeData); - else - result = cmNotFound; - } - } - else { - nodeData->cnm_nameptr = nodeData->cnm_namespace; - if ( isHFSPlus ) { - result = utf8_encodestr(key->hfsPlus.nodeName.unicode, - key->hfsPlus.nodeName.length * sizeof(UniChar), - nodeData->cnm_namespace, (size_t *)&utf8len, - MAXHFSVNODELEN + 1, ':', 0); - - /* Need to allocate buffer large enough */ - if (result == ENAMETOOLONG) { - utf8len = utf8_encodelen(key->hfsPlus.nodeName.unicode, - key->hfsPlus.nodeName.length * sizeof(UniChar), - ':', 0); - nodeData->cnm_nameptr = NewPtr(utf8len + 1); - nodeData->cnm_flags |= kCatNameIsAllocated; - result = utf8_encodestr(key->hfsPlus.nodeName.unicode, - key->hfsPlus.nodeName.length * sizeof(UniChar), - nodeData->cnm_nameptr, (size_t *)&utf8len, - utf8len + 1, ':', 0); - } - } - else { // classic HFS - - /* convert data to HFS Plus format */ - if (record->recordType == kHFSFolderRecord || record->recordType == kHFSFileRecord) { - CopyCatalogNodeData(volume, record, nodeData); - result = hfs_to_utf8(volume, key->hfs.nodeName, MAXHFSVNODELEN + 1, - &utf8len, nodeData->cnm_namespace); - /* Need to allocate buffer large enough */ - if (result == ENAMETOOLONG) { - nodeData->cnm_nameptr = NewPtr(utf8len + 1); - nodeData->cnm_flags |= kCatNameIsAllocated; - result = hfs_to_utf8(volume, key->hfs.nodeName, utf8len + 1, - &utf8len, nodeData->cnm_nameptr); - } else if (result) { - /* - * When an HFS name cannot be encoded with the current - * volume encoding we use MacRoman as a fallback. - */ - result = mac_roman_to_utf8(key->hfs.nodeName, MAXHFSVNODELEN + 1, - &utf8len, nodeData->cnm_namespace); - } - } else - result = cmNotFound; - } - - nodeData->cnm_length = utf8len; - if (result && (nodeData->cnm_flags & kCatNameIsAllocated)) - { - DisposePtr(nodeData->cnm_nameptr); - nodeData->cnm_flags &= ~kCatNameIsAllocated; - nodeData->cnm_nameptr = 0; /* Just to be clean */ - } - } - - - #if DEBUG_BUILD - if ( nodeData->cnd_nodeID > volume->vcbNxtCNID || nodeData->cnd_nodeID == 0) - DebugStr("\pGetCatalogNode bad file ID found!"); - #endif - - return result; - -} // end GetCatalogNode UInt32 @@ -859,26 +112,12 @@ PositionIterator(CatalogIterator *cip, UInt32 offset, BTreeIterator *bip, UInt16 *op = kBTreeNextRecord; } else { /* start from beginning */ - UInt32 heuristicHint; - UInt32 *cachedHint; - *op = kBTreeNextRecord; - /* - * We pass a 2nd hint/guess into BTSearchRecord. The heuristicHint - * is a mapping of dirID and nodeNumber, in hopes that the current - * search will be in the same node as the last search with the same - * parentID. - */ - result = GetMRUCacheBlock( cip->folderID, vol->hintCachePtr, (Ptr *)&cachedHint ); - heuristicHint = (result == noErr) ? *cachedHint : kInvalidMRUCacheKey; - /* Position iterator at the folder's thread record */ - result = BTSearchRecord(fcb, bip, heuristicHint, NULL, NULL, bip); + result = BTSearchRecord(fcb, bip, NULL, NULL, bip); if (result) goto exit; - - InsertMRUCacheBlock( vol->hintCachePtr, cip->folderID, (Ptr) &bip->hint.nodeNum ); /* find offset (note: n^2 / 2) */ if (offset > CAT_START_OFFSET) { @@ -935,907 +174,6 @@ exit: } /* end PositionIterator */ -//_________________________________________________________________________________ -// Routine: GetCatalogOffspring -// -// Function: Gets an offspring record from a specified folder. The folder -// is identified by it's folderID. The desired offspring CNode is -// indicated by the value of the offspring index (1 = 1st offspring -// CNode, 2 = 2nd offspring CNode, etc.). -// -//_________________________________________________________________________________ - -OSErr -GetCatalogOffspring(ExtendedVCB *volume, HFSCatalogNodeID folderID, UInt16 index, - CatalogNodeData *nodeData, - HFSCatalogNodeID *nodeID, SInt16 *nodeType) -{ - CatalogIterator * catalogIterator; - OSErr result; - - - if ( folderID == 0 ) - return cmNotFound; - - /* - * return cmNotFound for index 32767, to prevent overflowing - * the index into negative numbers. - */ - if ( index == 32767 ) - return cmNotFound; - - // get best catalog iterator... - catalogIterator = oGetCatalogIterator(volume, folderID, index); - - result = IterateCatalogNode(volume, catalogIterator, index, - nodeData, nodeID, nodeType); - - (void) ReleaseCatalogIterator(catalogIterator); - - return result; - -} // end GetCatalogOffspring - - -//_________________________________________________________________________________ -// Routine: IterateCatalogNode -// -// Function: Gets an offspring record from a specified folder. The folder -// is identified by it's folderID. The desired offspring CNode is -// indicated by the value of the offspring index (1 = 1st offspring -// CNode, 2 = 2nd offspring CNode, etc.). -// -//_________________________________________________________________________________ - -static OSErr -IterateCatalogNode( ExtendedVCB *volume, CatalogIterator *catalogIterator, UInt16 index, - CatalogNodeData *nodeData, HFSCatalogNodeID *nodeID, - SInt16 *nodeType ) -{ - HFSCatalogNodeID offspringParentID; - CatalogKey * offspringKey; - CatalogName * offspringName; - BTreeIterator btreeIterator; - FSBufferDescriptor btRecord; - CatalogRecord * record; - UInt8 databuf[32]; /* space for partial record */ - FCB * fcb; - SInt16 selectionIndex; - UInt16 tempSize; - UInt16 operation; - OSErr result; - Boolean isHFSPlus; - ByteCount utf8len; - - - isHFSPlus = (volume->vcbSigWord == kHFSPlusSigWord); - fcb = GetFileControlBlock(volume->catalogRefNum); - - // make a btree iterator from catalog iterator - UpdateBtreeIterator(catalogIterator, &btreeIterator); - - /* if client doesn't want data (ie readdir), just get type and id */ - if (nodeData == NULL) { - /* data buf has space to cover all type/id offsets */ - btRecord.bufferAddress = databuf; - btRecord.itemSize = sizeof(databuf); - } else if (isHFSPlus) { - btRecord.bufferAddress = nodeData; - btRecord.itemSize = sizeof(CatalogNodeData); - } else { - btRecord.bufferAddress = &nodeData->cnd_extra; - btRecord.itemSize = sizeof(HFSCatalogFile); - } - btRecord.itemCount = 1; - - //--- if neccessary position the iterator at the thread record for the specified folder - - if ( catalogIterator->currentIndex == 0 ) // is this a new iterator? - { - UInt32 heuristicHint; - UInt32 *cachedHint; - - // We pass a 2nd hint/guess into BTSearchRecord. The heuristicHint is a mapping of - // dirID and nodeNumber, in hopes that the current search will be in the same node - // as the last search with the same parentID. - result = GetMRUCacheBlock( catalogIterator->folderID, volume->hintCachePtr, (Ptr *)&cachedHint ); - heuristicHint = (result == noErr) ? *cachedHint : kInvalidMRUCacheKey; - - result = BTSearchRecord( fcb, &btreeIterator, heuristicHint, &btRecord, &tempSize, &btreeIterator ); - ExitOnError(result); - - UpdateCatalogIterator(&btreeIterator, catalogIterator); // update btree hint and key - - InsertMRUCacheBlock( volume->hintCachePtr, catalogIterator->folderID, (Ptr) &btreeIterator.hint.nodeNum ); - } - - //--- get offspring record (relative to catalogIterator's position) - - selectionIndex = index - catalogIterator->currentIndex; - - // now we have to map index into next/prev operations... - if (selectionIndex == 1) - { - operation = kBTreeNextRecord; - } - else if (selectionIndex == -1) - { - operation = kBTreePrevRecord; - } - else if (selectionIndex == 0) - { - operation = kBTreeCurrentRecord; - } - else if (selectionIndex > 1) - { - UInt32 i; - - for (i = 1; i < selectionIndex; ++i) - { - result = BTIterateRecord( fcb, kBTreeNextRecord, &btreeIterator, &btRecord, &tempSize ); - ExitOnError(result); - } - operation = kBTreeNextRecord; - } - else // (selectionIndex < -1) - { - SInt32 i; - - for (i = -1; i > selectionIndex; --i) - { - result = BTIterateRecord( fcb, kBTreePrevRecord, &btreeIterator, &btRecord, &tempSize ); - ExitOnError(result); - } - operation = kBTreePrevRecord; - } - - result = BTIterateRecord( fcb, operation, &btreeIterator, &btRecord, &tempSize ); - ExitOnError(result); - - offspringKey = (CatalogKey*) &btreeIterator.key; - - if (isHFSPlus) - { - offspringParentID = offspringKey->hfsPlus.parentID; - offspringName = (CatalogName*) &offspringKey->hfsPlus.nodeName; - } - else - { - offspringParentID = offspringKey->hfs.parentID; - offspringName = (CatalogName*) offspringKey->hfs.nodeName; - } - - if (offspringParentID != catalogIterator->folderID) // different parent? - { - AgeCatalogIterator(catalogIterator); // we reached the end, so don't hog the cache! - - result = cmNotFound; // must be done with this folder - goto ErrorExit; - } - - UpdateCatalogIterator(&btreeIterator, catalogIterator); // update btree hint and key - catalogIterator->currentIndex = index; // update the offspring index marker - - record = (CatalogRecord *) btRecord.bufferAddress; - - if (nodeData == NULL) { /* Just copy the id and type...not name */ - if (isHFSPlus) - { - *nodeType = record->recordType; - *nodeID = record->hfsPlusFolder.folderID; - } - else /* hfs name */ - { - - if (record->recordType == kHFSFileRecord) { - *nodeType = kCatalogFileNode; - *nodeID = record->hfsFile.fileID; - } else if (record->recordType == kHFSFolderRecord) { - *nodeType = kCatalogFolderNode; - *nodeID = record->hfsFolder.folderID; - } else - result = cmNotFound; - } - } else { - nodeData->cnm_parID = isHFSPlus ? offspringKey->hfsPlus.parentID : offspringKey->hfs.parentID; - nodeData->cnm_nameptr = nodeData->cnm_namespace; - if (isHFSPlus) - { - result = utf8_encodestr(offspringName->ustr.unicode, - offspringName->ustr.length * sizeof(UniChar), - nodeData->cnm_namespace, (size_t *)&utf8len, - MAXHFSVNODELEN + 1, ':', 0); - - /* Need to allocate buffer large enough */ - if (result == ENAMETOOLONG) { - utf8len = utf8_encodelen(offspringName->ustr.unicode, - offspringName->ustr.length * sizeof(UniChar), - ':', 0); - nodeData->cnm_nameptr = NewPtr(utf8len + 1); - nodeData->cnm_flags |= kCatNameIsAllocated; - result = utf8_encodestr(offspringName->ustr.unicode, - offspringName->ustr.length * sizeof(UniChar), - nodeData->cnm_nameptr, (size_t *)&utf8len, - utf8len + 1, ':', 0); - } - } - else /* hfs name */ - { - if (record->recordType == kHFSFolderRecord || record->recordType == kHFSFileRecord) { - - CopyCatalogNodeData(volume, record, nodeData); - result = hfs_to_utf8(volume, offspringName->pstr, MAXHFSVNODELEN + 1, &utf8len, nodeData->cnm_namespace); - if (result == ENAMETOOLONG) { /* Need to allocate buffer large enough */ - nodeData->cnm_nameptr = NewPtr(utf8len+1); - nodeData->cnm_flags |= kCatNameIsAllocated; - result = hfs_to_utf8(volume, offspringName->pstr, utf8len + 1, &utf8len, nodeData->cnm_nameptr); - } else if (result) { - /* - * When an HFS name cannot be encoded with the current - * volume encoding we use MacRoman as a fallback. - */ - result = mac_roman_to_utf8(offspringName->pstr, MAXHFSVNODELEN + 1, - &utf8len, nodeData->cnm_namespace); - } - - } else { - result = cmNotFound; - } - } - } - - return result; - -ErrorExit: - - if ( result == btNotFound ) - result = cmNotFound; - - return result; - -} // end IterateCatalogNode - - -//_________________________________________________________________________________ -// Routine: MoveRenameCatalogNode -// -// Function: Moves and/or rename an existing folder or file CNode. -// Note that when moving a folder, all decendants (its offspring, -// their offspring, etc.) are also moved. -// -// Assumes srcHint contains a text encoding that was set by a GetCatalogNode call -//_________________________________________________________________________________ - -OSErr -MoveRenameCatalogNode(ExtendedVCB *volume, HFSCatalogNodeID srcParentID, ConstUTF8Param srcName, - UInt32 srcHint, HFSCatalogNodeID dstParentID, ConstUTF8Param dstName, - UInt32 *newHint, UInt32 teHint) -{ - CatalogKey srcKey; // 518 bytes - CatalogRecord srcRecord; // 520 bytes - CatalogKey dstKey; // 518 bytes - CatalogKey dstFolderKey; // 518 bytes - HFSCatalogNodeID dstFolderParentID = 0; - UInt32 dstFolderHint; - CatalogName *dstFolderNamePtr = NULL; - CatalogRecord tmpRecord; // 520 bytes - HFSCatalogNodeID threadID; - UInt32 textEncoding; - OSErr result; - Boolean isNewName; - Boolean isHFSPlus = (volume->vcbSigWord == kHFSPlusSigWord); - Boolean isOrigDeleted = false; - short srcNameLen; - short dstNameLen; - - textEncoding = teHint; - result = BuildCatalogKeyUTF8(volume, srcParentID, srcName, kUndefinedStrLen, &srcKey, &textEncoding); - ReturnIfError(result); - - /* XXX can strlen and bcmp handle NULL pointers? */ - - srcNameLen = strlen(srcName); - dstNameLen = strlen(dstName); - - //--- check if names match - - if ((srcNameLen == dstNameLen) && (bcmp(srcName, dstName, srcNameLen) == 0)) - { - isNewName = false; - dstKey = srcKey; - if ( isHFSPlus ) { - dstKey.hfsPlus.parentID = dstParentID; // set parent ID - } - else { - dstKey.hfs.parentID = dstParentID; // set parent ID - } - } - else /* names are different */ - { - isNewName = true; - result = BuildCatalogKeyUTF8(volume, dstParentID, dstName, kUndefinedStrLen, &dstKey, &textEncoding); - ReturnIfError(result); - } - - //--- make sure source record exists - - result = LocateCatalogNodeByKey(volume, srcHint, &srcKey, &srcRecord, &srcHint); - - // if we did not find it by name, then look for an embedded file ID in a mangled name - if ( (result == cmNotFound) && isHFSPlus ) - result = LocateCatalogNodeByMangledName(volume, srcParentID, srcName, kUndefinedStrLen, &srcKey, &srcRecord, &srcHint); - /* - * In Mac OS X there can also be HFS filenames that - * could not be encoded using the default encoding. - */ - if (result == cmNotFound && !isHFSPlus && VCBTOHFS(volume)->hfs_encoding != 0) { - Str31 hfsName; - - utf8_to_mac_roman(strlen(srcName), srcName, hfsName); - result = LocateCatalogNode(volume, srcParentID, (CatalogName*)hfsName, - 0, &srcKey, &srcRecord, &srcHint); - } - ReturnIfError(result); - - srcParentID = (isHFSPlus ? srcKey.hfsPlus.parentID : srcKey.hfs.parentID); - - // if we're moving then do some additional preflighting... - - if (srcParentID != dstParentID) - { - //--- make sure destination folder exists - - result = LocateCatalogNode(volume, dstParentID, NULL, kNoHint, &dstFolderKey, &tmpRecord, &dstFolderHint); - ReturnIfError(result); - - if (tmpRecord.recordType == kHFSPlusFolderRecord) - { - dstParentID = tmpRecord.hfsPlusFolder.folderID; - dstFolderParentID = dstFolderKey.hfsPlus.parentID; - dstFolderNamePtr = (CatalogName*) &dstFolderKey.hfsPlus.nodeName; - } - else if (tmpRecord.recordType == kHFSFolderRecord) - { - dstParentID = tmpRecord.hfsFolder.folderID; - dstFolderParentID = dstFolderKey.hfs.parentID; - dstFolderNamePtr = (CatalogName*) &dstFolderKey.hfs.nodeName; - } - else - { - return badMovErr; - } - - //--- if source is a folder, make sure its a proper move - - if (srcRecord.recordType == kHFSPlusFolderRecord || srcRecord.recordType == kHFSFolderRecord) - { - HFSCatalogNodeID srcFolderID; - HFSCatalogNodeID ancestorParentID; - CatalogKey tempKey; // 518 bytes - UInt32 tempHint; - - if (isHFSPlus) - { - srcFolderID = srcRecord.hfsPlusFolder.folderID; - ancestorParentID = dstFolderKey.hfsPlus.parentID; - } - else - { - srcFolderID = srcRecord.hfsFolder.folderID; - ancestorParentID = dstFolderKey.hfs.parentID; - } - - if ( srcFolderID == fsRtDirID || // source == root? - srcFolderID == dstParentID || // source == destination? - srcFolderID == ancestorParentID ) // source == destination's parent? - { - return badMovErr; - } - - while (ancestorParentID > fsRtDirID) // loop until we reach the root folder - { - // locate next folder up the tree... - result = LocateCatalogNode(volume, ancestorParentID, NULL, kNoHint, &tempKey, &tmpRecord, &tempHint); - ReturnIfError(result); - - ancestorParentID = isHFSPlus ? tempKey.hfsPlus.parentID : tempKey.hfs.parentID; - - if (srcFolderID == ancestorParentID) // source = destination ancestor? - return badMovErr; - } - } - - TrashCatalogIterator(volume, dstParentID); // invalidate any iterators for destination parentID - } - else /* (srcParentID == dstParentID) */ - { - if ( !isNewName ) - { - *newHint = srcHint; // they match, so we're all done! - return noErr; - } - } - - TrashCatalogIterator(volume, srcParentID); // invalidate any iterators for source's parentID - InvalidateCatalogNodeCache(volume, srcParentID); // invalidate node cache since parent changed - - if (isNewName && isHFSPlus) - { - // update textEncoding hint (works for folders and files) - srcRecord.hfsPlusFolder.textEncoding = textEncoding; - - UpdateVolumeEncodings(volume, textEncoding); - } - - //--- insert source CNode record in BTree with new key (a new parent id and/or new name) - - result = InsertBTreeRecord(volume->catalogRefNum, &dstKey, &srcRecord, GetCatalogRecordSize(&srcRecord), newHint); - - if (result == btExists) - { - UInt16 dataSize; - - /* XXX what about the case: move id1,foo to id2,FOO ?? */ - if (srcParentID != dstParentID || isNewName == false) - return cmExists; - - //--- new CNode name already exists in the same folder, locate the existing one - result = SearchBTreeRecord(volume->catalogRefNum, &dstKey, srcHint, - &dstFolderKey, &tmpRecord, &dataSize, newHint); - - if (result == btNotFound) - result = cmNotFound; - ReturnIfError(result); - - //--- check if its the same CNode (same name but different upper/lower case) - - if (srcRecord.recordType != tmpRecord.recordType) - return cmExists; - - switch (srcRecord.recordType) - { - case kHFSPlusFileRecord: /* HFS Plus records share same cnid location */ - case kHFSPlusFolderRecord: - if (srcRecord.hfsPlusFolder.folderID != tmpRecord.hfsPlusFolder.folderID) - return cmExists; - break; - - case kHFSFolderRecord: - if (srcRecord.hfsFolder.folderID != tmpRecord.hfsFolder.folderID) - return cmExists; - break; - - case kHFSFileRecord: - if (srcRecord.hfsFile.fileID != tmpRecord.hfsFile.fileID) - return cmExists; - break; - - default: - return cmExists; - } - - //--- same name but different case, so delete old and insert with new name... - - result = DeleteBTreeRecord(volume->catalogRefNum, &srcKey); - ReturnIfError(result); - isOrigDeleted = true; // So we dont delete it again down below - - result = InsertBTreeRecord(volume->catalogRefNum, &dstKey, &srcRecord, dataSize, newHint); - } - ReturnIfError(result); - - // - // from this point on we need to cleanup (ie delete the new record) if we encounter errors! - // - - //--- update thread record for node (if it exists) - - switch (srcRecord.recordType) - { - case kHFSPlusFileRecord: - case kHFSPlusFolderRecord: - threadID = srcRecord.hfsPlusFolder.folderID; - break; - - case kHFSFolderRecord: - threadID = srcRecord.hfsFolder.folderID; - break; - - case kHFSFileRecord: - if (srcRecord.hfsFile.flags & kHFSThreadExistsMask) - { - threadID = srcRecord.hfsFile.fileID; - break; - } - /* fall through if no thread... */ - - default: - threadID = 0; - } - - if (threadID) - { - UInt32 threadHint; - CatalogKey threadKey; // 518 bytes - CatalogRecord threadRecord; // 520 bytes - UInt16 threadSize; - - result = LocateCatalogRecord(volume, threadID, NULL, kNoHint, &threadKey, &threadRecord, &threadHint); - if (result != noErr) goto Exit_Delete; - - if (isHFSPlus) - { - if (srcParentID != dstParentID) - threadRecord.hfsPlusThread.parentID = dstParentID; - if (isNewName) - CopyCatalogName((CatalogName *)&dstKey.hfsPlus.nodeName, (CatalogName *) &threadRecord.hfsPlusThread.nodeName, isHFSPlus); - - threadSize = sizeof(threadRecord.hfsPlusThread); - // HFS Plus has varaible sized threads so adjust to actual length - threadSize -= ( sizeof(threadRecord.hfsPlusThread.nodeName.unicode) - (threadRecord.hfsPlusThread.nodeName.length * sizeof(UniChar)) ); - } - else - { - if (srcParentID != dstParentID) - threadRecord.hfsThread.parentID = dstParentID; - if (isNewName) - CopyCatalogName((CatalogName *)&dstKey.hfs.nodeName,(CatalogName *) threadRecord.hfsThread.nodeName, isHFSPlus); - - threadSize = sizeof(threadRecord.hfsThread); - } - - result = DeleteBTreeRecord(volume->catalogRefNum, &threadKey); - if (result != noErr) goto Exit_Delete; - - result = InsertBTreeRecord(volume->catalogRefNum, &threadKey, &threadRecord, threadSize, &threadHint); - if (result != noErr) goto Exit_Delete; //XXX exiting with a missing thread! - } - - //--- we successfully added the new node so delete the old source CNode record - - if (! isOrigDeleted) { - result = DeleteBTreeRecord(volume->catalogRefNum, &srcKey); - if (result) - { - // uh oh, we could not delete the original - // so we better get rid of the new node... - - (void) DeleteBTreeRecord(volume->catalogRefNum, &dstKey); - - //XXX also need to fix up the thread... - - return result; - } - } - - if (srcParentID != dstParentID) - { - result = UpdateFolderCount(volume, srcParentID, NULL, srcRecord.recordType, kNoHint, -1); - result = UpdateFolderCount(volume, dstFolderParentID, dstFolderNamePtr, srcRecord.recordType, dstFolderHint, +1); - } - - //--- make sure changes get flushed out - VCB_LOCK(volume); - volume->vcbFlags |= 0xFF00; // Mark the VCB dirty - volume->vcbLsMod = GetTimeUTC(); // update last modified date - VCB_UNLOCK(volume); - - (void) FlushCatalog(volume); - - return result; - - -Exit_Delete: - (void) DeleteBTreeRecord(volume->catalogRefNum, &dstKey); - - return result; - -} // end MoveRenameCatalogNode - - -//_________________________________________________________________________________ -// Routine: UpdateCatalogNode -// -// Function: Marks the Catalog BTree node identified by the given catalog hint -// as 'dirty'. -// -//_________________________________________________________________________________ - - -OSErr -UpdateCatalogNode(ExtendedVCB *volume, HFSCatalogNodeID parentID, ConstUTF8Param name, - UInt32 catalogHint, const CatalogNodeData *nodeData) -{ - CatalogKey *key; - CatalogRecord *record; - UInt32 hint; - UInt16 recordSize; - OSErr result; - CatalogKey catalogKey; // 518 bytes - CatalogRecord catalogRecord; // 520 bytes - Boolean isHFSPlus = volume->vcbSigWord == kHFSPlusSigWord; - - /* XXX no reason to have ptrs to local variables... */ - key = &catalogKey; - record = &catalogRecord; - - result = BuildCatalogKeyUTF8(volume, parentID, name, kUndefinedStrLen, key, NULL); - ReturnIfError(result); - - //--- locate subject catalog node - - result = LocateCatalogNodeByKey(volume, catalogHint, key, record, &hint); - - // if we did not find it by name, then look for an embedded file ID in a mangled name - if ( (result == cmNotFound) && isHFSPlus ) - result = LocateCatalogNodeByMangledName(volume, parentID, name, kUndefinedStrLen, key, record, &hint); - - /* - * In Mac OS X there can also be HFS filenames that - * could not be encoded using the default encoding. - */ - if (result == cmNotFound && !isHFSPlus && VCBTOHFS(volume)->hfs_encoding != 0) { - Str31 hfsName; - - utf8_to_mac_roman(strlen(name), name, hfsName); - result = LocateCatalogNode(volume, parentID, (CatalogName*)hfsName, - 0, key, record, &hint); - } - if (result == btNotFound) - result = cmNotFound; - - if (catalogHint != hint) - PRINTIT(("UpdateCatalogNode: catalogHint does not match (in: %ld, out: %ld)\n", catalogHint, hint)); - ReturnIfError(result); - - // update user modifiable fields in the catalog node record... - - switch (record->recordType) - { - case kHFSFolderRecord: - { - #if DEBUG_BUILD - if (nodeData->cnd_type != kCatalogFolderNode) - DebugStr("\p UpdateCatalogNode: folder/file mismatch!"); - #endif - - record->hfsFolder.createDate = UTCToLocal(nodeData->cnd_createDate); - record->hfsFolder.modifyDate = UTCToLocal(nodeData->cnd_contentModDate); - record->hfsFolder.backupDate = UTCToLocal(nodeData->cnd_backupDate); - - *(DInfo*) &record->hfsFolder.userInfo = *(DInfo*) &nodeData->cnd_finderInfo; - *(DXInfo*) &record->hfsFolder.finderInfo = *(DXInfo*) ((UInt32)&nodeData->cnd_finderInfo + 16); - - recordSize = sizeof(HFSCatalogFolder); - break; - } - - case kHFSFileRecord: - { - UInt32 i; - - #if DEBUG_BUILD - if (nodeData->cnd_type != kCatalogFileNode) - DebugStr("UpdateCatalogNode: folder/file mismatch!"); - if ((nodeData->cnd_datafork.totalBlocks > (0x7FFFFFFF/volume->blockSize)) || - (nodeData->cnd_rsrcfork.totalBlocks > (0x7FFFFFFF/volume->blockSize))) - DebugStr("HFS file size is larger than 2Gig"); - #endif - - record->hfsFile.flags = (UInt8) nodeData->cnd_flags; - record->hfsFile.createDate = UTCToLocal(nodeData->cnd_createDate); - record->hfsFile.modifyDate = UTCToLocal(nodeData->cnd_contentModDate); - record->hfsFile.backupDate = UTCToLocal(nodeData->cnd_backupDate); - - record->hfsFile.dataLogicalSize = nodeData->cnd_datafork.logicalSize; - record->hfsFile.dataPhysicalSize = nodeData->cnd_datafork.totalBlocks * volume->blockSize; - record->hfsFile.rsrcLogicalSize = nodeData->cnd_rsrcfork.logicalSize; - record->hfsFile.rsrcPhysicalSize = nodeData->cnd_rsrcfork.totalBlocks * volume->blockSize; - - *(FInfo*) &record->hfsFile.userInfo = *(FInfo*) &nodeData->cnd_finderInfo; - *(FXInfo*) &record->hfsFile.finderInfo = *(FXInfo*) ((UInt32)&nodeData->cnd_finderInfo + 16); - - // copy extent info - for (i = 0; i < kHFSExtentDensity; ++i) - { - record->hfsFile.dataExtents[i].startBlock = - (UInt16) nodeData->cnd_datafork.extents[i].startBlock; - record->hfsFile.dataExtents[i].blockCount = - (UInt16) nodeData->cnd_datafork.extents[i].blockCount; - record->hfsFile.rsrcExtents[i].startBlock = - (UInt16) nodeData->cnd_rsrcfork.extents[i].startBlock; - record->hfsFile.rsrcExtents[i].blockCount = - (UInt16) nodeData->cnd_rsrcfork.extents[i].blockCount; - } - - recordSize = sizeof(HFSCatalogFile); - break; - } - - case kHFSPlusFolderRecord: - { - record->hfsPlusFolder.createDate = nodeData->cnd_createDate; - record->hfsPlusFolder.contentModDate = nodeData->cnd_contentModDate; - record->hfsPlusFolder.backupDate = nodeData->cnd_backupDate; - record->hfsPlusFolder.accessDate = nodeData->cnd_accessDate; - record->hfsPlusFolder.attributeModDate = nodeData->cnd_attributeModDate; - record->hfsPlusFolder.bsdInfo.ownerID = nodeData->cnd_ownerID; - record->hfsPlusFolder.bsdInfo.groupID = nodeData->cnd_groupID; - record->hfsPlusFolder.bsdInfo.ownerFlags = nodeData->cnd_ownerFlags; - record->hfsPlusFolder.bsdInfo.adminFlags = nodeData->cnd_adminFlags; - record->hfsPlusFolder.bsdInfo.fileMode = nodeData->cnd_mode; - record->hfsPlusFolder.textEncoding = nodeData->cnd_textEncoding; - - BlockMoveData(&nodeData->cnd_finderInfo, &record->hfsPlusFolder.userInfo, 32); - - recordSize = sizeof(HFSPlusCatalogFolder); - break; - } - - case kHFSPlusFileRecord: - { - record->hfsPlusFile.flags = nodeData->cnd_flags; - record->hfsPlusFile.createDate = nodeData->cnd_createDate; - record->hfsPlusFile.contentModDate = nodeData->cnd_contentModDate; - record->hfsPlusFile.backupDate = nodeData->cnd_backupDate; - record->hfsPlusFile.accessDate = nodeData->cnd_accessDate; - record->hfsPlusFile.attributeModDate = nodeData->cnd_attributeModDate; - record->hfsPlusFile.bsdInfo.ownerID = nodeData->cnd_ownerID; - record->hfsPlusFile.bsdInfo.groupID = nodeData->cnd_groupID; - record->hfsPlusFile.bsdInfo.ownerFlags = nodeData->cnd_ownerFlags; - record->hfsPlusFile.bsdInfo.adminFlags = nodeData->cnd_adminFlags; - record->hfsPlusFile.bsdInfo.fileMode = nodeData->cnd_mode; - /* get special value (iNodeNum, linkCount or rawDevice) */ - record->hfsPlusFile.bsdInfo.special.rawDevice = nodeData->cnd_rawDevice; - record->hfsPlusFile.textEncoding = nodeData->cnd_textEncoding; - - record->hfsPlusFile.dataFork.logicalSize = nodeData->cnd_datafork.logicalSize; - record->hfsPlusFile.dataFork.totalBlocks = nodeData->cnd_datafork.totalBlocks; - BlockMoveData(&nodeData->cnd_datafork.extents, - &record->hfsPlusFile.dataFork.extents, sizeof(HFSPlusExtentRecord)); - - record->hfsPlusFile.resourceFork.logicalSize = nodeData->cnd_rsrcfork.logicalSize; - record->hfsPlusFile.resourceFork.totalBlocks = nodeData->cnd_rsrcfork.totalBlocks; - BlockMoveData(&nodeData->cnd_rsrcfork.extents, - &record->hfsPlusFile.resourceFork.extents, sizeof(HFSPlusExtentRecord)); - - BlockMoveData(&nodeData->cnd_finderInfo, &record->hfsPlusFile.userInfo, 32); - -#if HFS_HARDLINKS && DEBUG_BUILD - /* Must swap opaque finder data */ - if (SWAP_BE32 (record->hfsPlusFile.userInfo.fdType) == kHardLinkFileType && - SWAP_BE32 (record->hfsPlusFile.userInfo.fdCreator) == kHardLinkCreator) { - if (record->hfsPlusFile.dataFork.logicalSize != 0) - DebugStr("UpdateCatalogNode: link has data fork!"); - } -#endif - recordSize = sizeof(HFSPlusCatalogFile); - break; - } - - default: - return cmNotFound; - } - - result = ReplaceBTreeRecord(volume->catalogRefNum, key, catalogHint, record, recordSize, &hint); - - if ( result == btNotFound ) - { - result = cmNotFound; - } - else if ( result == noErr ) - { - /* if we're just updating the accessDate then no need to change volume mod date */ - if (nodeData->cnd_contentModDate > volume->vcbLsMod || - (isHFSPlus && nodeData->cnd_attributeModDate > volume->vcbLsMod)) - { - VCB_LOCK(volume); - volume->vcbFlags |= 0xFF00; // Mark the VCB dirty - volume->vcbLsMod = GetTimeUTC(); // update last modified date - VCB_UNLOCK(volume); - } - - result = FlushCatalog(volume); // flush the catalog - } - - return result; -} - - -//_________________________________________________________________________________ -// Routine: CreateFileIDRef -// -// Function: Creates a file thread record for hfs file node -// -//_________________________________________________________________________________ - -OSErr -CreateFileIDRef(ExtendedVCB *volume, HFSCatalogNodeID parentID, ConstUTF8Param name, UInt32 hint, HFSCatalogNodeID *threadID) -{ - CatalogKey nodeKey; // 518 bytes - CatalogRecord nodeData; // 520 bytes - HFSCatalogKey threadKey; - HFSCatalogThread threadData; - UInt32 nodeHint; - UInt32 tempHint; - OSErr result; - Boolean isHFSPlus = (volume->vcbSigWord == kHFSPlusSigWord); - - *threadID = 0; - - result = BuildCatalogKeyUTF8(volume, parentID, name, kUndefinedStrLen, &nodeKey, NULL); - ReturnIfError(result); - - //--- locate subject catalog node - - result = LocateCatalogNodeByKey(volume, hint, &nodeKey, &nodeData, &nodeHint); - - // if we did not find it by name, then look for an embedded file ID in a mangled name - if ( (result == cmNotFound) && isHFSPlus ) - result = LocateCatalogNodeByMangledName(volume, parentID, name, kUndefinedStrLen, &nodeKey, &nodeData, &nodeHint); - /* - * In Mac OS X there can also be HFS filenames that - * could not be encoded using the default encoding. - */ - if ((result == cmNotFound) && !isHFSPlus && VCBTOHFS(volume)->hfs_encoding != 0) { - Str31 hfsName; - - utf8_to_mac_roman(strlen(name), name, hfsName); - result = LocateCatalogNode(volume, parentID, (CatalogName*)hfsName, - 0, &nodeKey, &nodeData, &nodeHint); - } - ReturnIfError(result); - - if (nodeData.recordType == kHFSPlusFileRecord) - { - *threadID = nodeData.hfsPlusFile.fileID; - return noErr; // already have one - } - - if (nodeData.recordType != kHFSFileRecord) - { - return notAFileErr; - } - - - if (nodeData.hfsFile.flags & kHFSThreadExistsMask) - { - *threadID = nodeData.hfsFile.fileID; - return noErr; // already have one - } - - result = VolumeWritable( volume ); - if ( result != noErr ) return result; - - // - // need to insert a thread record - // - BuildCatalogKey(nodeData.hfsFile.fileID, NULL, false, (CatalogKey *)&threadKey); - - ClearMemory(&threadData, sizeof(HFSCatalogThread)); - threadData.recordType = kHFSFileThreadRecord; - threadData.parentID = nodeKey.hfs.parentID; - BlockMoveData(&nodeKey.hfs.nodeName, &threadData.nodeName, nodeKey.hfs.nodeName[0] + 1); - - result = InsertBTreeRecord(volume->catalogRefNum, &threadKey, &threadData, sizeof(HFSCatalogThread), &tempHint); - if (result == btExists) result = noErr; //XXX could return cmExists or fidExists - ReturnIfError(result); - - // - // Finally, set the flag in the file record to say this file has a thread record. - // - nodeData.hfsFile.flags |= kHFSThreadExistsMask; - result = ReplaceBTreeRecord(volume->catalogRefNum, &nodeKey, nodeHint, &nodeData, sizeof(HFSCatalogFile), &nodeHint ); - - if (result == noErr) { - (void) FlushCatalog(volume); - *threadID = nodeData.hfsFile.fileID; - } - - return result; -} - - //_________________________________________________________________________________ // Routine: CompareCatalogKeys // @@ -1860,18 +198,8 @@ CompareCatalogKeys(HFSCatalogKey *searchKey, HFSCatalogKey *trialKey) else if ( searchParentID < trialParentID ) result = -1; else // parent dirID's are equal, compare names - { - #if ( ! FORDISKFIRSTAID ) - LogStartTime(kTraceRelString); - result = FastRelString(searchKey->nodeName, trialKey->nodeName); - LogEndTime(kTraceRelString, noErr); - #else - result = (SInt32) RelString_Glue(searchKey->nodeName, trialKey->nodeName); - #endif - } - return result; } diff --git a/bsd/hfs/hfscommon/Catalog/CatalogIterators.c b/bsd/hfs/hfscommon/Catalog/CatalogIterators.c index 596b812bb..56751bc4b 100644 --- a/bsd/hfs/hfscommon/Catalog/CatalogIterators.c +++ b/bsd/hfs/hfscommon/Catalog/CatalogIterators.c @@ -63,7 +63,6 @@ #include "../headers/FileMgrInternal.h" #include "../headers/BTreesInternal.h" #include "../headers/CatalogPrivate.h" -#include "../headers/HFSInstrumentation.h" #include @@ -134,10 +133,6 @@ InitCatalogCache(void) cacheSize = sizeof(CatalogCacheGlobals) + ( kCatalogIteratorCount * sizeof(CatalogIterator) ); cacheGlobals = (CatalogCacheGlobals *) NewPtrSysClear( cacheSize ); - err = MemError(); - if (err != noErr) - return err; - cacheGlobals->iteratorCount = kCatalogIteratorCount; lastIterator = kCatalogIteratorCount - 1; // last iterator number, since they start at 0 @@ -325,114 +320,6 @@ ReleaseCatalogIterator( CatalogIterator* catalogIterator) // be called to unlock it. // //_______________________________________________________________________________ -CatalogIterator* -oGetCatalogIterator( const ExtendedVCB *volume, HFSCatalogNodeID folderID, UInt16 index) -{ - CatalogCacheGlobals * cacheGlobals = GetCatalogCacheGlobals(); - CatalogIterator * iterator; - CatalogIterator * bestIterator; - UInt16 bestDelta; - Boolean newIterator = false; - - - LogStartTime(kGetCatalogIterator); - - bestDelta = 0xFFFF; // assume the best thing is to start from scratch - bestIterator = nil; - - CATALOG_ITER_LIST_LOCK(cacheGlobals); - - for ( iterator = cacheGlobals->mru ; iterator != nil ; iterator = iterator->nextMRU ) - { - UInt16 delta; - UInt16 iteratorIndex; - - // first make sure volume, folder id and type matches - if ( (iterator->volume != volume) || - (iterator->folderID != folderID) || - (iterator->currentIndex == 0xFFFFFFFF)) - { - continue; - } - - if ( CI_SLEEPLESS_LOCK(iterator) == EBUSY ) /* ignore busy iterators */ - { - //PRINTIT(" GetCatalogIterator: busy v=%d, d=%ld, i=%d\n", volume, folderID, iterator->currentIndex); - continue; - } - - iteratorIndex = iterator->currentIndex; - - // we matched volume, folder id and type, now check the index - if ( iteratorIndex == index ) - { - bestDelta = 0; - bestIterator = iterator; // we scored! - so get out of this loop - break; // break with iterator locked - } - - // calculate how far this iterator is from the requested index - if ( index > iteratorIndex ) - delta = index - iteratorIndex; - else - delta = iteratorIndex - index; - - - // remember the best iterator so far (there could be more than one) - if ( delta < bestDelta ) - { - bestDelta = delta; // we found a better one! - bestIterator = iterator; // so remember it - if ( delta == 1 ) // just one away is good enough! - break; // break with iterator locked - } - - (void) CI_UNLOCK(iterator); // unlock iterator before moving to the next one - - } // end for - - - // check if we didn't get one or if the one we got is too far away... - if ( (bestIterator == nil) || (index < bestDelta) ) - { - bestIterator = cacheGlobals->lru; // start over with a new iterator - - //PRINTIT(" GetCatalogIterator: recycle v=%d, d=%ld, i=%d\n", bestIterator->volRefNum, bestIterator->folderID, bestIterator->currentIndex); - (void) CI_LOCK_FROM_LIST(cacheGlobals, bestIterator); // XXX we should not eat the error! - - CATALOG_ITER_LIST_LOCK(cacheGlobals); // grab the lock again for MRU Insert below... - - bestIterator->volume = volume; // update the iterator's volume - bestIterator->folderID = folderID; // ... and folderID - bestIterator->currentIndex = 0; // ... and offspring index marker - - bestIterator->btreeNodeHint = 0; - bestIterator->btreeIndexHint = 0; - bestIterator->parentID = folderID; // set key to folderID + empty name - bestIterator->folderName.unicodeName.length = 0; // clear pascal/unicode name - - if ( volume->vcbSigWord == kHFSPlusSigWord ) - bestIterator->nameType = kShortUnicodeName; - else - bestIterator->nameType = kShortPascalName; - - newIterator = true; - } - else { - //PRINTIT(" GetCatalogIterator: found v=%d, d=%ld, i=%d\n", bestIterator->volRefNum, bestIterator->folderID, bestIterator->currentIndex); - } - - // put this iterator at the front of the list - InsertCatalogIteratorAsMRU( cacheGlobals, bestIterator ); - - CATALOG_ITER_LIST_UNLOCK(cacheGlobals); - - LogEndTime(kGetCatalogIterator, newIterator); - - return bestIterator; // return our best shot - -} // end oGetCatalogIterator - CatalogIterator* GetCatalogIterator(ExtendedVCB *volume, HFSCatalogNodeID folderID, UInt32 offset) diff --git a/bsd/hfs/hfscommon/Catalog/CatalogUtilities.c b/bsd/hfs/hfscommon/Catalog/CatalogUtilities.c index a966d7ab4..d1a43afb8 100644 --- a/bsd/hfs/hfscommon/Catalog/CatalogUtilities.c +++ b/bsd/hfs/hfscommon/Catalog/CatalogUtilities.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -19,74 +19,6 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* - File: CatalogUtilities.c - - Contains: Private Catalog Manager support routines. - - Version: HFS Plus 1.0 - - Copyright: © 1997-2000 by Apple Computer, Inc., all rights reserved. - - File Ownership: - - DRI: Don Brady - - Other Contact: Mark Day - - Technology: xxx put technology here xxx - - Writers: - - (DSH) Deric Horn - (msd) Mark Day - (djb) Don Brady - - Change History (most recent first): - 1/8/99 djb Fixing LocateCatalogNodeByMangledName... - 1/7/99 djb In BuildCatalogKeyUTF8 check name length against NAME_MAX. - 12/7/98 djb Add ExtractTextEncoding routine to get text encodings. - 11/20/98 djb Add support for UTF-8 names. - 8/31/98 djb GetTimeLocal now takes an input. - 4/17/98 djb Add VCB locking. - 4/3/98 djb Removed last name conversion cache from LocateCatalogNodeWithRetry. - 4/2/98 djb InvalidateCatalogNodeCache and TrashCatalogNodeCache are not used in MacOS X. - 03/31/98 djb Sync up with final HFSVolumes.h header file. - - 1/29/98 DSH Add TrashCatalogNodeCache for TrashAllFSCaches API support. - 12/15/97 djb Radar #2202860, In LocateCatalogNodeByMangledName remap - cmParentNotFound error code to cmNotFound. - 12/10/97 DSH 2201501, Pin the leof and peof to multiple of allocation blocks - under 2 Gig. - 12/9/97 DSH 2201501, Pin returned leof values to 2^31-1 (SInt32), instead of - 2^32-1 - 11/26/97 djb Radar #2005688, 2005461 - need to handle kTextMalformedInputErr. - 11/25/97 djb Radar #2002357 (again) fix new bug introduced in . - 11/17/97 djb PrepareInputName routine now returns an error. - 10/19/97 msd Bug 1684586. GetCatInfo and SetCatInfo use only contentModDate. - 10/17/97 djb Add ConvertInputNameToUnicode for Catalog Create/Rename. - 10/14/97 djb Fix LocateCatalogNode's MakeFSSpec optimization (radar #1683166) - 10/13/97 djb Copy text encoding in CopyCatalogNodeData. Fix cut/paste error - in VolumeHasEncodings macro. When accessing encoding bitmap use - the MapEncodingToIndex and MapIndexToEncoding macros. - 10/1/97 djb Remove old Catalog Iterator code... - 9/8/97 msd Make sure a folder's modifyDate is set whenever its - contentModDate is set. - 9/4/97 djb Add MakeFSSpec optimization. - 9/4/97 msd In CatalogNodeData, change attributeModDate to modifyDate. - 8/26/97 djb Back out (UpdateFolderCount must maintain vcbNmFls for HFS - Plus volumes too). - 8/14/97 djb Remove hard link support. - 7/18/97 msd Include LowMemPriv.h. - 7/16/97 DSH FilesInternal.i renamed FileMgrInternal.i to avoid name - collision - 7/8/97 DSH Loading PrecompiledHeaders from define passed in on C line - 6/27/97 msd UpdateFolderCount should update number of root files/folders for - HFS volumes, not HFS Plus. - 6/24/97 djb LocateCatalogNodeWithRetry did not always set result code. - 6/24/97 djb Add LocateCatalogNodeByMangledName routine - 6/24/97 djb first checked in -*/ #include #include #include @@ -156,13 +88,32 @@ LocateCatalogNodeByKey(const ExtendedVCB *volume, UInt32 hint, CatalogKey *keyPt CatalogRecord *dataPtr, UInt32 *newHint) { OSErr result; - CatalogName *nodeName = NULL; /* To ward off uninitialized use warnings from compiler */ + CatalogName *nodeName = NULL; HFSCatalogNodeID threadParentID; UInt16 tempSize; + FSBufferDescriptor btRecord; + BTreeIterator searchIterator = {0}; + FCB *fcb; + + fcb = GetFileControlBlock(volume->catalogRefNum); + btRecord.bufferAddress = dataPtr; + btRecord.itemCount = 1; + btRecord.itemSize = sizeof(CatalogRecord); + + searchIterator.hint.nodeNum = hint; + + bcopy(keyPtr, &searchIterator.key, sizeof(CatalogKey)); + + result = BTSearchRecord( fcb, &searchIterator, &btRecord, &tempSize, &searchIterator ); + + if (result == noErr) + { + *newHint = searchIterator.hint.nodeNum; + + BlockMoveData(&searchIterator.key, keyPtr, sizeof(CatalogKey)); + } - result = SearchBTreeRecord(volume->catalogRefNum, keyPtr, hint, keyPtr, - dataPtr, &tempSize, newHint); if (result == btNotFound) result = cmNotFound; ReturnIfError(result); @@ -194,193 +145,6 @@ LocateCatalogNodeByKey(const ExtendedVCB *volume, UInt32 hint, CatalogKey *keyPt } -#if 0 -//******************************************************************************* -// Routine: LocateCatalogNodeWithRetry -// -// Function: Locates the catalog record for an existing folder or file node. -// For HFS Plus volumes a retry is performed when a catalog node is -// not found and the volume contains more than one text encoding. -// -//ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ - -#define VolumeHasEncodings(v) \ - ( ((v)->encodingsBitmap != 0 ) - -#define EncodingInstalled(i) \ - ( (fsVars)->gConversionContext[(i)].toUnicode != 0 ) - -#define EncodingUsedByVolume(v,i) \ - ( ((v)->encodingsBitmap & (1 << (i))) ) - - -OSErr -LocateCatalogNodeWithRetry (const ExtendedVCB *volume, HFSCatalogNodeID folderID, ConstStr31Param pascalName, CatalogName *unicodeName, - UInt32 hint, CatalogKey *keyPtr, CatalogRecord *dataPtr, UInt32 *newHint) -{ - TextEncoding defaultEncoding; - TextEncoding encoding; - ItemCount encodingsToTry; - FSVarsRec *fsVars; - OSErr result = cmNotFound; - - fsVars = (FSVarsRec*) LMGetFSMVars(); // used by macros - - defaultEncoding = GetDefaultTextEncoding(); - encodingsToTry = CountInstalledEncodings(); - - // 1. Try finding file using default encoding (typical case) - - { - --encodingsToTry; - result = PrepareInputName(pascalName, true, defaultEncoding, unicodeName); - if (result == noErr) - result = LocateCatalogNode(volume, folderID, unicodeName, hint, keyPtr, dataPtr, newHint); - else - result = cmNotFound; - - if ( result != cmNotFound || encodingsToTry == 0) - return result; - } - - // - // XXX if the pascal string contains all 7-bit ascii then we don't need to do anymore retries - // - - // 2. Try finding file using Mac Roman (if not already tried above) - - if ( defaultEncoding != kTextEncodingMacRoman ) - { - --encodingsToTry; - result = PrepareInputName(pascalName, true, kTextEncodingMacRoman, unicodeName); - if (result == noErr) - result = LocateCatalogNode(volume, folderID, unicodeName, hint, keyPtr, dataPtr, newHint); - else - result = cmNotFound; - - if ( result != cmNotFound || encodingsToTry == 0 ) - return result; - } - - // 3. Try with encodings from disk (if any) - - if ( VolumeHasEncodings(volume) ) // any left to try? - { - UInt32 index; - - index = 0; // since we pre increment this will skip MacRoman (which was already tried above) - - while ( index < kMacBaseEncodingCount ) - { - ++index; - - encoding = MapIndexToEncoding(index); - - if ( encoding == defaultEncoding ) - continue; // we did this one already - - if ( EncodingInstalled(index) && EncodingUsedByVolume(volume, index) ) - { - --encodingsToTry; - result = PrepareInputName(pascalName, true, encoding, unicodeName); - if (result == noErr) - result = LocateCatalogNode(volume, folderID, unicodeName, hint, keyPtr, dataPtr, newHint); - else - result = cmNotFound; - - if ( result != cmNotFound || encodingsToTry == 0 ) - return result; - } - } - } - - // 4. Try any remaining encodings (if any) - - { - UInt32 index; - - index = 0; // since we pre increment this will skip MacRoman (which was already tried above) - - while ( (encodingsToTry > 0) && (index < kMacBaseEncodingCount) ) - { - ++index; - - encoding = MapIndexToEncoding(index); - - if ( encoding == defaultEncoding ) - continue; // we did this one already - - if ( EncodingInstalled(index) && EncodingUsedByVolume(volume, index) == false ) - { - --encodingsToTry; - result = PrepareInputName(pascalName, true, encoding, unicodeName); - if (result == noErr) - result = LocateCatalogNode(volume, folderID, unicodeName, hint, keyPtr, dataPtr, newHint); - else - result = cmNotFound; - - if ( result != cmNotFound || encodingsToTry == 0 ) - return result; - } - } - } - - return cmNotFound; -} -#endif - -//******************************************************************************* -// Routine: LocateCatalogNodeByMangledName -// -// Function: Locates the catalog record associated with a mangled name (if any) -// -//******************************************************************************* -#define kMaxCompareLen 64 /* If it compares this far...lets believe it */ - -OSErr -LocateCatalogNodeByMangledName( const ExtendedVCB *volume, HFSCatalogNodeID folderID, - const unsigned char * name, UInt32 length, CatalogKey *keyPtr, - CatalogRecord *dataPtr, UInt32 *hintPtr ) -{ - HFSCatalogNodeID fileID; - unsigned char nodeName[kMaxCompareLen+1]; - OSErr result; - size_t actualDstLen; - ByteCount prefixlen; - - - if (name == NULL || name[0] == '\0') - return cmNotFound; - - fileID = GetEmbeddedFileID(name, length, &prefixlen); - - if ( fileID < kHFSFirstUserCatalogNodeID ) - return cmNotFound; - - result = LocateCatalogNode(volume, fileID, NULL, kNoHint, keyPtr, dataPtr, hintPtr); - if ( result == cmParentNotFound ) // GetCatalogNode already handled cmParentNotFound case - result = cmNotFound; // so remap - ReturnIfError(result); - - // first make sure that the parents match - if ( folderID != keyPtr->hfsPlus.parentID ) - return cmNotFound; // not the same folder so this is a false match - - (void) utf8_encodestr(keyPtr->hfsPlus.nodeName.unicode, - keyPtr->hfsPlus.nodeName.length * sizeof (UniChar), - nodeName, &actualDstLen, kMaxCompareLen+1, ':', 0); - - prefixlen = min(prefixlen, kMaxCompareLen); - - if ((prefixlen - actualDstLen) < 6) - prefixlen = actualDstLen; /* To take into account UTF8 rounding */ - - if ( (actualDstLen < prefixlen) || bcmp(nodeName, name, prefixlen-6) != 0) - return cmNotFound; // mangled names didn't match so this is a false match - - return noErr; // we found it -} - //******************************************************************************* // Routine: LocateCatalogRecord @@ -408,32 +172,6 @@ LocateCatalogRecord(const ExtendedVCB *volume, HFSCatalogNodeID folderID, const } -//******************************************************************************* -// Routine: LocateCatalogThread -// -// Function: Locates a catalog thread record in the catalog BTree file and -// returns a pointer to the data record. -// -//******************************************************************************* - -OSErr -LocateCatalogThread(const ExtendedVCB *volume, HFSCatalogNodeID nodeID, CatalogRecord *threadData, UInt16 *threadSize, UInt32 *threadHint) -{ - CatalogKey threadKey; // 518 bytes - OSErr result; - - //--- build key record - - BuildCatalogKey(nodeID, NULL, (volume->vcbSigWord == kHFSPlusSigWord), &threadKey); - - //--- locate thread record in BTree - - result = SearchBTreeRecord( volume->catalogRefNum, &threadKey, kNoHint, &threadKey, - threadData, threadSize, threadHint); - - return (result == btNotFound ? cmNotFound : result); -} - /* * Routine: BuildCatalogKey @@ -551,14 +289,14 @@ FlushCatalog(ExtendedVCB *volume) { //--- check if catalog's fcb is dirty... - if ( fcb->fcbFlags & fcbModifiedMask ) + if ( 0 /*fcb->fcbFlags & fcbModifiedMask*/ ) { VCB_LOCK(volume); volume->vcbFlags |= 0xFF00; // Mark the VCB dirty volume->vcbLsMod = GetTimeUTC(); // update last modified date VCB_UNLOCK(volume); - result = FlushVolumeControlBlock(volume); + // result = FlushVolumeControlBlock(volume); } } @@ -586,251 +324,6 @@ UpdateCatalogName(ConstStr31Param srcName, Str31 destName) BlockMoveData(&srcName[1], &destName[1], length); } - -//******************************************************************************* -// Routine: AdjustVolumeCounts -// -// Function: Adjusts the folder and file counts in the VCB -// -//******************************************************************************* - -void -AdjustVolumeCounts(ExtendedVCB *volume, SInt16 type, SInt16 delta) -{ - //€€ also update extended VCB fields... - - VCB_LOCK(volume); - - if (type == kHFSFolderRecord || type == kHFSPlusFolderRecord) - volume->vcbDirCnt += delta; // adjust volume folder count, €€ worry about overflow? - else - volume->vcbFilCnt += delta; // adjust volume file count - - volume->vcbFlags |= 0xFF00; // Mark the VCB dirty - volume->vcbLsMod = GetTimeUTC(); // update last modified date - - VCB_UNLOCK(volume); -} - - -//******************************************************************************* - -void -UpdateVolumeEncodings(ExtendedVCB *volume, TextEncoding encoding) -{ - UInt32 index; - - encoding &= 0x7F; - - index = MapEncodingToIndex(encoding); - - VCB_LOCK(volume); - - volume->encodingsBitmap |= (1 << index); - - VCB_UNLOCK(volume); - - // vcb should already be marked dirty -} - - -//******************************************************************************* - -OSErr -UpdateFolderCount( ExtendedVCB *volume, HFSCatalogNodeID parentID, const CatalogName *name, SInt16 newType, - UInt32 hint, SInt16 valenceDelta) -{ - CatalogKey tempKey; // 518 bytes - CatalogRecord tempData; // 520 bytes - UInt32 tempHint; - HFSCatalogNodeID folderID; - UInt16 recordSize; - OSErr result; - -#if 0 - result = SearchBTreeRecord(volume->catalogRefNum, parentKey, hint, - &tempKey, &tempData, &recordSize, &tempHint); - if (result) - return (result == btNotFound ? cmNotFound : result); -#else - - result = LocateCatalogNode(volume, parentID, name, hint, &tempKey, &tempData, &tempHint); - ReturnIfError(result); -#endif - - if ( volume->vcbSigWord == kHFSPlusSigWord ) // HFS Plus - { - UInt32 timeStamp; - - if ( DEBUG_BUILD && tempData.recordType != kHFSPlusFolderRecord ) - DebugStr("\p UpdateFolder: found HFS folder on HFS+ volume!"); - - timeStamp = GetTimeUTC(); - /* adjust valence, but don't go negative */ - if (valenceDelta > 0) - tempData.hfsPlusFolder.valence += valenceDelta; - else if (tempData.hfsPlusFolder.valence != 0) - tempData.hfsPlusFolder.valence += valenceDelta; - else - volume->vcbFlags |= kHFS_DamagedVolume; - tempData.hfsPlusFolder.contentModDate = timeStamp; // set date/time last modified - folderID = tempData.hfsPlusFolder.folderID; - recordSize = sizeof(tempData.hfsPlusFolder); - } - else // classic HFS - { - if ( DEBUG_BUILD && tempData.recordType != kHFSFolderRecord ) - DebugStr("\p UpdateFolder: found HFS+ folder on HFS volume!"); - - /* adjust valence, but don't go negative */ - if (valenceDelta > 0) - tempData.hfsFolder.valence += valenceDelta; - else if (tempData.hfsFolder.valence != 0) - tempData.hfsFolder.valence += valenceDelta; - else - volume->vcbFlags |= kHFS_DamagedVolume; - tempData.hfsFolder.modifyDate = GetTimeLocal(true); // set date/time last modified - folderID = tempData.hfsFolder.folderID; - recordSize = sizeof(tempData.hfsFolder); - } - - result = ReplaceBTreeRecord(volume->catalogRefNum, &tempKey, tempHint, - &tempData, recordSize, &tempHint); - ReturnIfError(result); - - if ( folderID == kHFSRootFolderID ) - { - if (newType == kHFSFolderRecord || newType == kHFSPlusFolderRecord) - { - VCB_LOCK(volume); - volume->vcbNmRtDirs += valenceDelta; // adjust root folder count (undefined for HFS Plus) - VCB_UNLOCK(volume); - } - else - { - VCB_LOCK(volume); - volume->vcbNmFls += valenceDelta; // adjust root file count (used by GetVolInfo) - VCB_UNLOCK(volume); - } - } - - //XXX also update extended VCB fields... - - return result; -} - - -//******************************************************************************* - -UInt16 -GetCatalogRecordSize(const CatalogRecord *dataRecord) -{ - switch (dataRecord->recordType) - { - case kHFSFileRecord: - return sizeof(HFSCatalogFile); - - case kHFSFolderRecord: - return sizeof(HFSCatalogFolder); - - case kHFSPlusFileRecord: - return sizeof(HFSPlusCatalogFile); - - case kHFSPlusFolderRecord: - return sizeof(HFSPlusCatalogFolder); - - case kHFSFolderThreadRecord: - case kHFSFileThreadRecord: - return sizeof(HFSCatalogThread); - - case kHFSPlusFolderThreadRecord: - case kHFSPlusFileThreadRecord: - return sizeof(HFSPlusCatalogThread); - - default: - return 0; - } -} - - -//******************************************************************************* - -void -CopyCatalogNodeData(const ExtendedVCB *volume, const CatalogRecord *dataPtr, CatalogNodeData *nodeData) -{ - /* convert classic hfs records to hfs plus format */ - - if (dataPtr->recordType == kHFSFolderRecord) { - nodeData->cnd_type = kCatalogFolderNode; - nodeData->cnd_flags = dataPtr->hfsFolder.flags; - nodeData->cnd_nodeID = dataPtr->hfsFolder.folderID; - nodeData->cnd_createDate = LocalToUTC(dataPtr->hfsFolder.createDate); - nodeData->cnd_contentModDate = LocalToUTC(dataPtr->hfsFolder.modifyDate); - nodeData->cnd_attributeModDate = LocalToUTC(dataPtr->hfsFolder.modifyDate); - nodeData->cnd_accessDate = LocalToUTC(dataPtr->hfsFolder.modifyDate); - nodeData->cnd_backupDate = LocalToUTC(dataPtr->hfsFolder.backupDate); - nodeData->cnd_ownerID = VCBTOHFS(volume)->hfs_uid; - nodeData->cnd_groupID = VCBTOHFS(volume)->hfs_gid; - nodeData->cnd_adminFlags = 0; - nodeData->cnd_ownerFlags = 0; /* HFS directories cannot be locked */ - nodeData->cnd_mode = IFDIR | (ACCESSPERMS & VCBTOHFS(volume)->hfs_dir_mask); - nodeData->cnd_valence = dataPtr->hfsFolder.valence; - - BlockMoveData(&dataPtr->hfsFolder.userInfo, &nodeData->cnd_finderInfo, 32); - } else if (dataPtr->recordType == kHFSFileRecord) { - UInt32 i; - - nodeData->cnd_type = kCatalogFileNode; - nodeData->cnd_flags = dataPtr->hfsFile.flags; - nodeData->cnd_nodeID = dataPtr->hfsFile.fileID; - nodeData->cnd_createDate = LocalToUTC(dataPtr->hfsFile.createDate); - nodeData->cnd_contentModDate = LocalToUTC(dataPtr->hfsFile.modifyDate); - nodeData->cnd_attributeModDate = LocalToUTC(dataPtr->hfsFolder.modifyDate); - nodeData->cnd_accessDate = LocalToUTC(dataPtr->hfsFolder.modifyDate); - nodeData->cnd_backupDate = LocalToUTC(dataPtr->hfsFile.backupDate); - nodeData->cnd_ownerID = VCBTOHFS(volume)->hfs_uid; - nodeData->cnd_groupID = VCBTOHFS(volume)->hfs_gid; - nodeData->cnd_adminFlags = 0; - nodeData->cnd_ownerFlags = (nodeData->cnd_flags & kHFSFileLockedMask) ? UF_IMMUTABLE : 0; - nodeData->cnd_mode = IFREG | (ACCESSPERMS & VCBTOHFS(volume)->hfs_file_mask); - nodeData->cnd_linkCount = 0; - - BlockMoveData(&dataPtr->hfsFile.userInfo, &nodeData->cnd_finderInfo, 16); - BlockMoveData(&dataPtr->hfsFile.finderInfo, (void*)((UInt32)&nodeData->cnd_finderInfo + 16), 16); - - nodeData->cnd_datafork.logicalSize = dataPtr->hfsFile.dataLogicalSize; - nodeData->cnd_datafork.totalBlocks = - dataPtr->hfsFile.dataPhysicalSize / volume->blockSize; - - nodeData->cnd_rsrcfork.logicalSize = dataPtr->hfsFile.rsrcLogicalSize; - nodeData->cnd_rsrcfork.totalBlocks = - dataPtr->hfsFile.rsrcPhysicalSize / volume->blockSize; - - for (i = 0; i < kHFSExtentDensity; ++i) { - nodeData->cnd_datafork.extents[i].startBlock = - (UInt32) (dataPtr->hfsFile.dataExtents[i].startBlock); - - nodeData->cnd_datafork.extents[i].blockCount = - (UInt32) (dataPtr->hfsFile.dataExtents[i].blockCount); - - nodeData->cnd_rsrcfork.extents[i].startBlock = - (UInt32) (dataPtr->hfsFile.rsrcExtents[i].startBlock); - - nodeData->cnd_rsrcfork.extents[i].blockCount = - (UInt32) (dataPtr->hfsFile.rsrcExtents[i].blockCount); - } - for (i = kHFSExtentDensity; i < kHFSPlusExtentDensity; ++i) { - nodeData->cnd_datafork.extents[i].startBlock = 0; - nodeData->cnd_datafork.extents[i].blockCount = 0; - nodeData->cnd_rsrcfork.extents[i].startBlock = 0; - nodeData->cnd_rsrcfork.extents[i].blockCount = 0; - } - } else { - nodeData->cnd_type = 0; - } -} - - //_______________________________________________________________________ void @@ -856,16 +349,3 @@ CopyCatalogName(const CatalogName *srcName, CatalogName *dstName, Boolean isHFSP dstName->ustr.length = 0; // set length byte to zero (works for both unicode and pascal) } -//_______________________________________________________________________ - -UInt32 -CatalogNameLength(const CatalogName *name, Boolean isHFSPlus) -{ - if (isHFSPlus) - return name->ustr.length; - else - return name->pstr[0]; -} - - - diff --git a/bsd/hfs/hfscommon/Catalog/FileIDsServices.c b/bsd/hfs/hfscommon/Catalog/FileIDsServices.c index 43cdd2a22..923e90334 100644 --- a/bsd/hfs/hfscommon/Catalog/FileIDsServices.c +++ b/bsd/hfs/hfscommon/Catalog/FileIDsServices.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -19,106 +19,6 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* - File: FileIDServices.c - - Contains: File ID manipulating routines. - - Version: HFS Plus 1.0 - - Written by: Deric Horn - - Copyright: © 1996-1999 by Apple Computer, Inc., all rights reserved. - - File Ownership: - - DRI: Deric Horn - - Other Contact: xxx put other contact here xxx - - Technology: xxx put technology here xxx - - Writers: - - (JL) Jim Luther - (msd) Mark Day - (djb) Don Brady - (DSH) Deric Horn - - Change History (most recent first): - 3/2/98 djb Fix extents corruption bug in MoveExtents (radar #2309434). - 11/20/98 djb Add support for UTF-8 names. - 4/2/98 djb Switch over to real BTree interface in MoveExtents and DeleteExtents. - 3/31/98 djb Sync up with final HFSVolumes.h header file. - - 11/17/97 djb PrepareInputName routine now returns an error. - 11/13/97 djb Radar #2001699 ResolveFileID needs to use CMNotFound error. - 10/31/97 JL #2000184 - CreateFileThreadID and ExchangeFiles now return the - WDCBRecPtr or NULL for external file systems. ExchangeFiles no - longer returns length of FCB table to caller since that wasn't - ever needed. - <18> 10/23/97 DSH 1685058, Fix ExchangeFiles by invalidating the node cache before - switching the files. - 10/19/97 msd Bug 1684586. GetCatInfo and SetCatInfo use only contentModDate. - 10/16/97 DSH Return badFidErr in ResolveFileID if LocateCatalogThread fails - 10/15/97 DSH CreateFileThreadID(), remap btExists to fidExists. - 9/7/97 djb Turn off some DebugStr calls. - 9/4/97 msd Remove call to PropertyExchangeObjects. - 8/14/97 djb Remove hard link support. - 7/18/97 msd Include LowMemPriv.h. - 7/16/97 DSH FilesInternal.i renamed FileMgrInternal.i to avoid name - collision - 7/8/97 DSH Loading PrecompiledHeaders from define passed in on C line - 6/24/97 djb Add hard link support to ResolveFileID and CreateFileIDRef. - 6/20/97 msd Use contentModDate and attributeModDate fields instead of - modifyDate. - 6/13/97 djb Switch over from PrepareOutputName to ConvertUnicodeToHFSName. - PrepareInputName now takes an encoding. - 5/28/97 msd Move the declaration of FindFileName to FilesInternal.i. - 5/19/97 djb No longer need to invalidate vcbDirIDM field. - 5/16/97 msd In ExchangeFiles, change srcNamePtr from char * to StringPtr - (fixes warnings). - 4/28/97 djb (DSH) Added VolumeWritable check back into CreateFileIDThread. - 4/24/97 djb first checked in - 4/11/97 DSH Use extended VCB fields catalogRefNum, and extentsRefNum. - 4/9/97 msd Rewrite CreateFileThreadID so that it properly handles - pathnames, and doesn't overwrite the ioNamePtr. The data field - of FindFileNameGlueRec points to a CatalogNodeData, not - CatalogRecord. - 4/4/97 djb Get in sync with volume format changes. - 3/31/97 djb Change ClearMem to ClearMemory. - 3/17/97 DSH C_FlushCache prototype to FilesInternal.h - 3/5/97 msd ExchangeFiles needs to call PropertyExchangeObjects. - 2/13/97 msd Fix MoveExtents and DeleteExtents to work with HFS+ extent - records. - 1/31/97 msd In MoveExtents, when a record isn't found and you want the next - record in order, use the "next record" offset = 1 instead of - "current record" offset = 0. DeleteExtents would always exit - without doing anything because it was searching for an invalid - key. Removed several DebugStrs that were used as cheap code - coverage. - 1/15/97 DSH Resolve wasn't passing the name back for HFS - 1/13/97 djb LocateCatalogThread now passes back the thread record size. - 1/11/97 DSH HFS+, fixed some Unicode/Pascal strings related bugs for use on - HFS+ volumes. - 1/9/97 DSH Fix ExchangeFiles extents - 1/6/97 DSH pass VCB in CloseFile() routine. - 1/6/97 djb Fixed ResolveFileID - it was not returning a directory ID! - 1/3/97 msd Fix prototype for C_FlushCache. Fix prototype for - TrashFileBlocks. - 1/3/97 djb Integrate latest HFSVolumesPriv.h changes. - 1/2/97 DSH C port of ExchangeFileIDs - 12/20/96 djb Fixed bug in CreateFileID. - 12/19/96 DSH All refs to VCB are now refs to ExtendedVCB - 12/19/96 msd Use kFileThreadExistsMask (from HFSVolumesPriv.h) instead of - kFileThreadMask (from FilesInternal.h) since the latter was - incorrectly defined and has now been removed. - 12/19/96 djb Updated for new B-tree Manager interface. - 12/18/96 msd GetFileThreadID was using a bitwise-OR (|) instead of - bitwise-AND (&) to test for a bit being set. - 12/12/96 DSH first checked in - -*/ #include "../../hfs_macos_defs.h" #include "../../hfs_format.h" @@ -129,37 +29,32 @@ struct ExtentsRecBuffer { - ExtentKey extentKey; + ExtentKey extentKey; ExtentRecord extentData; }; typedef struct ExtentsRecBuffer ExtentsRecBuffer; -OSErr CreateFileID( ExtendedVCB *vcb, HFSCatalogNodeID fileID, CatalogName *name, HFSCatalogNodeID *threadID ); -OSErr GetFileThreadID( ExtendedVCB *vcb, HFSCatalogNodeID id, const CatalogName *name, Boolean isHFSPlus, UInt32 *threadID ); - UInt32 CheckExtents( void *extents, UInt32 blocks, Boolean isHFSPlus ); OSErr DeleteExtents( ExtendedVCB *vcb, UInt32 fileNumber, Boolean isHFSPlus ); OSErr MoveExtents( ExtendedVCB *vcb, UInt32 srcFileID, UInt32 destFileID, Boolean isHFSPlus ); void CopyCatalogNodeInfo( CatalogRecord *src, CatalogRecord *dest ); void CopyBigCatalogNodeInfo( CatalogRecord *src, CatalogRecord *dest ); - void CopyExtentInfo( ExtentKey *key, ExtentRecord *data, ExtentsRecBuffer *buffer, UInt16 bufferCount ); -extern void TrashFileBlocks( ExtendedVCB *vcb, UInt32 fileNumber ); OSErr ExchangeFileIDs( ExtendedVCB *vcb, ConstUTF8Param srcName, ConstUTF8Param destName, HFSCatalogNodeID srcID, HFSCatalogNodeID destID, UInt32 srcHint, UInt32 destHint ) { - CatalogKey srcKey; // 518 bytes + CatalogKey srcKey; // 518 bytes + CatalogKey destKey; // 518 bytes CatalogRecord srcData; // 520 bytes - CatalogKey destKey; // 518 bytes CatalogRecord destData; // 520 bytes CatalogRecord swapData; // 520 bytes - SInt16 numSrcExtentBlocks; - SInt16 numDestExtentBlocks; - OSErr err; - Boolean isHFSPlus = ( vcb->vcbSigWord == kHFSPlusSigWord ); + SInt16 numSrcExtentBlocks; + SInt16 numDestExtentBlocks; + OSErr err; + Boolean isHFSPlus = ( vcb->vcbSigWord == kHFSPlusSigWord ); TrashCatalogIterator(vcb, srcID); // invalidate any iterators for this parentID TrashCatalogIterator(vcb, destID); // invalidate any iterators for this parentID @@ -458,10 +353,8 @@ FlushAndReturn: void CopyCatalogNodeInfo( CatalogRecord *src, CatalogRecord *dest ) { -// dest->hfsFile.filStBlk = src->hfsFile.filStBlk; dest->hfsFile.dataLogicalSize = src->hfsFile.dataLogicalSize; dest->hfsFile.dataPhysicalSize = src->hfsFile.dataPhysicalSize; -// dest->hfsFile.filRStBlk = src->hfsFile.filRStBlk; dest->hfsFile.rsrcLogicalSize = src->hfsFile.rsrcLogicalSize; dest->hfsFile.rsrcPhysicalSize = src->hfsFile.rsrcPhysicalSize; dest->hfsFile.modifyDate = src->hfsFile.modifyDate; @@ -545,7 +438,7 @@ OSErr MoveExtents( ExtendedVCB *vcb, UInt32 srcFileID, UInt32 destFileID, Boolea // we found, so that BTIterateRecord would get the next one (the first we haven't processed). // - err = BTSearchRecord(fcb, &btIterator, kInvalidMRUCacheKey, &btRecord, &btRecordSize, &btIterator); + err = BTSearchRecord(fcb, &btIterator, &btRecord, &btRecordSize, &btIterator); // We expect a btNotFound here, since there shouldn't be an extent record with FABN = 0. if (err != btNotFound) @@ -682,7 +575,7 @@ OSErr DeleteExtents( ExtendedVCB *vcb, UInt32 fileID, Boolean isHFSPlus ) extentKeyPtr->hfs.startBlock = 0; } - err = BTSearchRecord(fcb, &btIterator, kInvalidMRUCacheKey, &btRecord, &btRecordSize, &btIterator); + err = BTSearchRecord(fcb, &btIterator, &btRecord, &btRecordSize, &btIterator); if ( err != btNotFound ) { if (err == noErr) { // Did we find a bogus extent record? diff --git a/bsd/hfs/hfscommon/Makefile b/bsd/hfs/hfscommon/Makefile deleted file mode 100644 index 87fa95d27..000000000 --- a/bsd/hfs/hfscommon/Makefile +++ /dev/null @@ -1,27 +0,0 @@ -export MakeInc_cmd=${SRCROOT}/makedefs/MakeInc.cmd -export MakeInc_def=${SRCROOT}/makedefs/MakeInc.def -export MakeInc_rule=${SRCROOT}/makedefs/MakeInc.rule -export MakeInc_dir=${SRCROOT}/makedefs/MakeInc.dir - - -include $(MakeInc_cmd) -include $(MakeInc_def) - -INSTINC_SUBDIRS = \ - headers - -INSTINC_SUBDIRS_PPC = \ - -INSTINC_SUBDIRS_I386 = \ - -EXPINC_SUBDIRS = \ - headers - -EXPINC_SUBDIRS_PPC = \ - -EXPINC_SUBDIRS_I386 = \ - -include $(MakeInc_rule) -include $(MakeInc_dir) - - diff --git a/bsd/hfs/hfscommon/Misc/BTreeWrapper.c b/bsd/hfs/hfscommon/Misc/BTreeWrapper.c index 86bbcd0b4..767e54bec 100644 --- a/bsd/hfs/hfscommon/Misc/BTreeWrapper.c +++ b/bsd/hfs/hfscommon/Misc/BTreeWrapper.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000,2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -19,102 +19,10 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* - File: BTreeWrapper.c - - Contains: Interface glue for new B-tree manager. - - Version: HFS Plus 1.0 - - Copyright: © 1996-1998 by Apple Computer, Inc., all rights reserved. - - File Ownership: - - DRI: Don Brady - - Other Contact: Mark Day - - Technology: xxx put technology here xxx - - Writers: - - (msd) Mark Day - (DSH) Deric Horn - (djb) Don Brady - - Change History (most recent first): - 8/10/98 djb Removed all references to btcb global iterator (lastIterator). - 04/02/98 djb GetBTreeRecord is only used for MacOS builds. - 03/31/98 djb Sync up with final HFSVolumes.h header file. - 9/4/97 msd Fix ValidHFSRecord to determine the type of B-tree by FileID, - not record size. Add better checking for attribute b-tree keys. - 8/22/97 djb Get blockReadFromDisk flag from GetCacheBlock call. - 8/14/97 djb Remove reserved field checks in ValidHFSRecord (radar #1649593). - Only call if ValidHFSRecord HFS_DIAGNOSTIC is true. - 8/11/97 djb Bug 1670441. In SetEndOfForkProc, don't DebugStr if the disk is - full. - 7/25/97 DSH Pass heuristicHint to BTSearchRecord from SearchBTreeRecord. - 7/24/97 djb CallBackProcs now take a file refNum instead of an FCB. - GetBlockProc now reports if block came from disk. - 7/22/97 djb Move all trace points to BTree.c file. - 7/21/97 djb LogEndTime now takes an error code. - 7/16/97 DSH FilesInternal.x -> FileMgrInternal.x to avoid name collision - 7/15/97 msd Bug #1664103. OpenBTree is not propagating errors from - BTOpenPath. - 7/9/97 djb Remove maxCNID check from ValidHFSRecord (radar #1649593). - 6/13/97 djb In ValidHFSRecord HFSPlus threads names can be > 31 chars. - 6/2/97 DSH Also flush AlternateVolumeHeader whenever Attributes or Startup - files change size. - 5/28/97 msd In ValidHFSRecord, check for attribute keys. - 5/19/97 djb Move summary traces from GetBTreeRecord to BTIterateRecord. - 5/9/97 djb Get in sync with new FilesInternal.i. - 5/7/97 djb Add summary traces to B-tree SPI. - 4/24/97 djb first checked in - 4/16/97 djb Always use new B-tree code. - 4/4/97 djb Remove clumpSize test from ValidHFSRecord. - 4/4/97 djb Get in sync with volume format changes. - 3/17/97 DSH Casting for SC, BlockProcs are now not static. - 3/3/97 djb Call trash block after closing btree! - 2/19/97 djb Add support for accessing bigger B-tree nodes. - 2/6/97 msd In CheckBTreeKey, remove test and DebugStr for parent ID being - too big. - 1/23/97 DSH SetEndOfForkProc now calls through to update the Alternate MDB - or VolumeHeader. - 1/16/97 djb Switched to dynamic lengths for BufferDescriptor length field in - SearchBTreeRecord and GetBTreeRecord. Round up to clump size in - SetEndOfForkProc. - 1/15/97 djb Don't return errors for bad file ids in key. - 1/13/97 djb Adding support for getting current record. ValidHFSRecord now - supports variable sized thread records. - 1/9/97 djb Call CheckBTreeKey before using key length in a BlockMoveData - call. - 1/6/97 djb Implement SetEndOfForkProc. - 1/6/97 djb Added HFS Plus support to CheckBTreeKey and ValidHFSRecord. - 1/3/97 djb Added support for large keys. Integrated latest HFSVolumesPriv.h - changes. - 12/23/96 djb Fixed problem in SearchBTreeRecord (dataSize is an output so it - was undefined). Added some debugging code. - 12/20/96 msd Fix OpenBTree to use the real data type for the key compare proc - pointer (not void *). Fixed problem in SearchBTreeRecord that - assigns a pointer to a buffer size field (forgot to dereference - the pointer). - 12/19/96 djb first checked in - -*/ #include "../headers/BTreesPrivate.h" - - -// B-tree callbacks... -#if TARGET_API_MAC_OS8 -OSStatus GetBlockProc ( FileReference fileRefNum, UInt32 blockNum, GetBlockOptions options, BlockDescriptor *block ); -OSStatus ReleaseBlockProc ( FileReference fileRefNum, BlockDescPtr blockPtr, ReleaseBlockOptions options ); -OSStatus SetBlockSizeProc ( FileReference fileRefNum, ByteCount blockSize, ItemCount minBlockCount ); -#endif - - // local routines static OSErr CheckBTreeKey(const BTreeKey *key, const BTreeControlBlock *btcb); static Boolean ValidHFSRecord(const void *record, const BTreeControlBlock *btcb, UInt16 recordSize); @@ -124,6 +32,9 @@ static Boolean ValidHFSRecord(const void *record, const BTreeControlBlock *btcb, OSErr SearchBTreeRecord(FileReference refNum, const void* key, UInt32 hint, void* foundKey, void* data, UInt16 *dataSize, UInt32 *newHint) { + panic("SearchBTreeRecord is dead code!"); + return (-1); +#if 0 FSBufferDescriptor btRecord; BTreeIterator searchIterator; FCB *fcb; @@ -155,27 +66,7 @@ OSErr SearchBTreeRecord(FileReference refNum, const void* key, UInt32 hint, void BlockMoveData(key, &searchIterator.key, CalcKeySize(btcb, (BTreeKey *) key)); //€€ should we range check against maxkeylen? - // We only optimize for catalog records - if( btRecord.itemSize == sizeof(CatalogRecord) ) - { - UInt32 heuristicHint; - UInt32 *cachedHint; - Ptr hintCachePtr = FCBTOVCB(fcb)->hintCachePtr; - - // We pass a 2nd hint/guess into BTSearchRecord. The heuristicHint is a mapping of - // dirID and nodeNumber, in hopes that the current search will be in the same node - // as the last search with the same parentID. - result = GetMRUCacheBlock( ((HFSCatalogKey *)key)->parentID, hintCachePtr, (Ptr *)&cachedHint ); - heuristicHint = (result == noErr) ? *cachedHint : kInvalidMRUCacheKey; - - result = BTSearchRecord( fcb, &searchIterator, heuristicHint, &btRecord, dataSize, &searchIterator ); - - InsertMRUCacheBlock( hintCachePtr, ((HFSCatalogKey *)key)->parentID, (Ptr) &(searchIterator.hint.nodeNum) ); - } - else - { - result = BTSearchRecord( fcb, &searchIterator, kInvalidMRUCacheKey, &btRecord, dataSize, &searchIterator ); - } + result = BTSearchRecord( fcb, &searchIterator, &btRecord, dataSize, &searchIterator ); if (result == noErr) { @@ -193,69 +84,7 @@ OSErr SearchBTreeRecord(FileReference refNum, const void* key, UInt32 hint, void ErrorExit: return result; -} - - - -OSErr InsertBTreeRecord(FileReference refNum, void* key, void* data, UInt16 dataSize, UInt32 *newHint) -{ - FSBufferDescriptor btRecord; - BTreeIterator iterator; - FCB *fcb; - BTreeControlBlock *btcb; - OSStatus result; - - - fcb = GetFileControlBlock(refNum); - btcb = (BTreeControlBlock*) fcb->fcbBTCBPtr; - - btRecord.bufferAddress = data; - btRecord.itemSize = dataSize; - btRecord.itemCount = 1; - - iterator.hint.nodeNum = 0; // no hint - - result = CheckBTreeKey((BTreeKey *) key, btcb); - ExitOnError(result); - - BlockMoveData(key, &iterator.key, CalcKeySize(btcb, (BTreeKey *) key)); //€€ should we range check against maxkeylen? - - if ( DEBUG_BUILD && !ValidHFSRecord(data, btcb, dataSize) ) - DebugStr("\pInsertBTreeRecord: bad record?"); - - result = BTInsertRecord( fcb, &iterator, &btRecord, dataSize ); - - *newHint = iterator.hint.nodeNum; - -ErrorExit: - - return result; -} - - -OSErr DeleteBTreeRecord(FileReference refNum, void* key) -{ - BTreeIterator iterator; - FCB *fcb; - BTreeControlBlock *btcb; - OSStatus result; - - - fcb = GetFileControlBlock(refNum); - btcb = (BTreeControlBlock*) fcb->fcbBTCBPtr; - - iterator.hint.nodeNum = 0; // no hint - - result = CheckBTreeKey((BTreeKey *) key, btcb); - ExitOnError(result); - - BlockMoveData(key, &iterator.key, CalcKeySize(btcb, (BTreeKey *) key)); //€€ should we range check against maxkeylen? - - result = BTDeleteRecord( fcb, &iterator ); - -ErrorExit: - - return result; +#endif } diff --git a/bsd/hfs/hfscommon/Misc/FileExtentMapping.c b/bsd/hfs/hfscommon/Misc/FileExtentMapping.c index d989e134a..b294edd9a 100644 --- a/bsd/hfs/hfscommon/Misc/FileExtentMapping.c +++ b/bsd/hfs/hfscommon/Misc/FileExtentMapping.c @@ -237,10 +237,10 @@ Internal Routines: and was in the extents file, then delete the record instead. */ +static const SInt64 kTwoGigabytes = 0x80000000LL; + enum { - kTwoGigabytes = (UInt32) 0x80000000, - kDataForkType = 0, kResourceForkType = 0xFF, @@ -367,7 +367,7 @@ OSErr FindExtentRecord( UInt32 *foundHint) { FCB * fcb; - BTreeIterator btIterator; + BTreeIterator *btIterator; FSBufferDescriptor btRecord; OSErr err; UInt16 btRecordSize; @@ -376,13 +376,14 @@ OSErr FindExtentRecord( *foundHint = 0; fcb = GetFileControlBlock(vcb->extentsRefNum); - (void) BTInvalidateHint(&btIterator); + MALLOC(btIterator, BTreeIterator *, sizeof(*btIterator), M_TEMP, M_WAITOK); + bzero(btIterator, sizeof(*btIterator)); if (vcb->vcbSigWord == kHFSSigWord) { HFSExtentKey * extentKeyPtr; HFSExtentRecord extentData; - extentKeyPtr = (HFSExtentKey*) &btIterator.key; + extentKeyPtr = (HFSExtentKey*) &btIterator->key; extentKeyPtr->keyLength = kHFSExtentKeyMaximumLength; extentKeyPtr->forkType = forkType; extentKeyPtr->fileID = fileID; @@ -392,10 +393,10 @@ OSErr FindExtentRecord( btRecord.itemSize = sizeof(HFSExtentRecord); btRecord.itemCount = 1; - err = BTSearchRecord(fcb, &btIterator, kInvalidMRUCacheKey, &btRecord, &btRecordSize, &btIterator); + err = BTSearchRecord(fcb, btIterator, &btRecord, &btRecordSize, btIterator); if (err == btNotFound && allowPrevious) { - err = BTIterateRecord(fcb, kBTreePrevRecord, &btIterator, &btRecord, &btRecordSize); + err = BTIterateRecord(fcb, kBTreePrevRecord, btIterator, &btRecord, &btRecordSize); // A previous record may not exist, so just return btNotFound (like we would if // it was for the wrong file/fork). @@ -438,7 +439,7 @@ OSErr FindExtentRecord( HFSPlusExtentKey * extentKeyPtr; HFSPlusExtentRecord extentData; - extentKeyPtr = (HFSPlusExtentKey*) &btIterator.key; + extentKeyPtr = (HFSPlusExtentKey*) &btIterator->key; extentKeyPtr->keyLength = kHFSPlusExtentKeyMaximumLength; extentKeyPtr->forkType = forkType; extentKeyPtr->pad = 0; @@ -449,10 +450,10 @@ OSErr FindExtentRecord( btRecord.itemSize = sizeof(HFSPlusExtentRecord); btRecord.itemCount = 1; - err = BTSearchRecord(fcb, &btIterator, kInvalidMRUCacheKey, &btRecord, &btRecordSize, &btIterator); + err = BTSearchRecord(fcb, btIterator, &btRecord, &btRecordSize, btIterator); if (err == btNotFound && allowPrevious) { - err = BTIterateRecord(fcb, kBTreePrevRecord, &btIterator, &btRecord, &btRecordSize); + err = BTIterateRecord(fcb, kBTreePrevRecord, btIterator, &btRecord, &btRecordSize); // A previous record may not exist, so just return btNotFound (like we would if // it was for the wrong file/fork). @@ -474,7 +475,8 @@ OSErr FindExtentRecord( } } - *foundHint = btIterator.hint.nodeNum; + *foundHint = btIterator->hint.nodeNum; + FREE(btIterator, M_TEMP); return err; } @@ -486,14 +488,15 @@ static OSErr CreateExtentRecord( HFSPlusExtentRecord extents, UInt32 *hint) { - BTreeIterator btIterator; + BTreeIterator * btIterator; FSBufferDescriptor btRecord; UInt16 btRecordSize; OSErr err; err = noErr; *hint = 0; - (void) BTInvalidateHint(&btIterator); + MALLOC(btIterator, BTreeIterator *, sizeof(*btIterator), M_TEMP, M_WAITOK); + bzero(btIterator, sizeof(*btIterator)); if (vcb->vcbSigWord == kHFSSigWord) { HFSExtentKey * keyPtr; @@ -504,7 +507,7 @@ static OSErr CreateExtentRecord( btRecord.itemSize = btRecordSize; btRecord.itemCount = 1; - keyPtr = (HFSExtentKey*) &btIterator.key; + keyPtr = (HFSExtentKey*) &btIterator->key; keyPtr->keyLength = kHFSExtentKeyMaximumLength; keyPtr->forkType = key->forkType; keyPtr->fileID = key->fileID; @@ -518,15 +521,16 @@ static OSErr CreateExtentRecord( btRecord.itemSize = btRecordSize; btRecord.itemCount = 1; - BlockMoveData(key, &btIterator.key, sizeof(HFSPlusExtentKey)); + BlockMoveData(key, &btIterator->key, sizeof(HFSPlusExtentKey)); } if (err == noErr) - err = BTInsertRecord(GetFileControlBlock(vcb->extentsRefNum), &btIterator, &btRecord, btRecordSize); + err = BTInsertRecord(GetFileControlBlock(vcb->extentsRefNum), btIterator, &btRecord, btRecordSize); if (err == noErr) - *hint = btIterator.hint.nodeNum; + *hint = btIterator->hint.nodeNum; + FREE(btIterator, M_TEMP); return err; } @@ -537,16 +541,17 @@ OSErr DeleteExtentRecord( UInt32 fileID, UInt32 startBlock) { - BTreeIterator btIterator; + BTreeIterator * btIterator; OSErr err; err = noErr; - (void) BTInvalidateHint(&btIterator); + MALLOC(btIterator, BTreeIterator *, sizeof(*btIterator), M_TEMP, M_WAITOK); + bzero(btIterator, sizeof(*btIterator)); if (vcb->vcbSigWord == kHFSSigWord) { HFSExtentKey * keyPtr; - keyPtr = (HFSExtentKey*) &btIterator.key; + keyPtr = (HFSExtentKey*) &btIterator->key; keyPtr->keyLength = kHFSExtentKeyMaximumLength; keyPtr->forkType = forkType; keyPtr->fileID = fileID; @@ -555,7 +560,7 @@ OSErr DeleteExtentRecord( else { // HFS Plus volume HFSPlusExtentKey * keyPtr; - keyPtr = (HFSPlusExtentKey*) &btIterator.key; + keyPtr = (HFSPlusExtentKey*) &btIterator->key; keyPtr->keyLength = kHFSPlusExtentKeyMaximumLength; keyPtr->forkType = forkType; keyPtr->pad = 0; @@ -563,8 +568,9 @@ OSErr DeleteExtentRecord( keyPtr->startBlock = startBlock; } - err = BTDeleteRecord(GetFileControlBlock(vcb->extentsRefNum), &btIterator); - + err = BTDeleteRecord(GetFileControlBlock(vcb->extentsRefNum), btIterator); + + FREE(btIterator, M_TEMP); return err; } @@ -633,25 +639,26 @@ OSErr MapFileBlockC ( // Determine the end of the available space. It will either be the end of the extent, // or the file's PEOF, whichever is smaller. // - dataEnd = (off_t)((off_t)(nextFABN) * (off_t)(allocBlockSize)); // Assume valid data through end of this extent - if (fcb->fcbPLen < dataEnd) // Is PEOF shorter? - dataEnd = fcb->fcbPLen; // Yes, so only map up to PEOF + dataEnd = (off_t)((off_t)(nextFABN) * (off_t)(allocBlockSize)); // Assume valid data through end of this extent + if (((off_t)fcb->ff_blocks * (off_t)allocBlockSize) < dataEnd) // Is PEOF shorter? + dataEnd = (off_t)fcb->ff_blocks * (off_t)allocBlockSize; // Yes, so only map up to PEOF // Compute the number of sectors in an allocation block sectorsPerBlock = allocBlockSize / sectorSize; // sectors per allocation block // // Compute the absolute sector number that contains the offset of the given file + // offset in sectors from start of the extent + + // offset in sectors from start of allocation block space // - - // offset in sectors from start of the extent temp = (daddr_t)((offset - (off_t)((off_t)(firstFABN) * (off_t)(allocBlockSize)))/sectorSize); - // offset in sectors from start of allocation block space - temp += startBlock * sectorsPerBlock; // offset in sectors from start of allocation block space + temp += startBlock * sectorsPerBlock; + + /* Add in any volume offsets */ if (vcb->vcbSigWord == kHFSPlusSigWord) - temp += vcb->hfsPlusIOPosOffset / sectorSize; /* offset inside wrapper */ + temp += vcb->hfsPlusIOPosOffset / sectorSize; else - temp += vcb->vcbAlBlSt; /* offset in sectors from start of volume */ + temp += vcb->vcbAlBlSt; // Return the desired sector for file position "offset" *startSector = temp; @@ -813,81 +820,16 @@ OSErr FlushExtentFile( ExtendedVCB *vcb ) { // If the FCB for the extent "file" is dirty, mark the VCB as dirty. - if ((fcb->fcbFlags & fcbModifiedMask) != 0) + if (FTOC(fcb)->c_flag & C_MODIFIED) { MarkVCBDirty( vcb ); - err = FlushVolumeControlBlock( vcb ); + // err = FlushVolumeControlBlock( vcb ); } } return( err ); } -//------------------------------------------------------------------------------- -// Routine: DeleteFile -// -// Function: De-allocates all disk space allocated to a specified file -// including the space used by the catalog (ie the catalog record). -// The space occupied by both forks is also deallocated. -// -//------------------------------------------------------------------------------- - -OSErr DeleteFile( ExtendedVCB *vcb, HFSCatalogNodeID parDirID, ConstUTF8Param catalogName, UInt32 catalogHint ) -{ - OSErr err; - OSErr errDF, errRF; - CatalogNodeData catalogData; - Boolean recordDeleted; - - recordDeleted = false; - - INIT_CATALOGDATA(&catalogData, kCatNameNoCopyName); - - // Find catalog data in catalog - err = GetCatalogNode( vcb, parDirID, catalogName, kUndefinedStrLen, catalogHint, &catalogData, &catalogHint); - if( err != noErr ) - goto Exit; - - - // Check to make sure record is for a file - if ( catalogData.cnd_type != kCatalogFileNode ) - { - err = notAFileErr; - goto Exit; - } - - // - // Always delete the Catalog record first (to minimize disk corruption) - // - err = DeleteCatalogNode(vcb, parDirID, catalogName, catalogHint); - if( err != noErr ) - goto Exit; - - // - // Note: we don't report errors from DeallocateFork since the - // file no longer exists (since DeleteCatalogNode succeeded). - // Any errors mean that there are possibly some orphaned disk - // blocks but from the clients perspective the file was deleted. - // - - // Deallocate data fork extents - errDF = DeallocateFork( vcb, catalogData.cnd_nodeID, kDataForkType, - catalogData.cnd_datafork.extents, &recordDeleted ); - - // Deallocate resource fork extents - errRF = DeallocateFork( vcb, catalogData.cnd_nodeID, kResourceForkType, - catalogData.cnd_rsrcfork.extents, &recordDeleted ); - - if (recordDeleted) - err = FlushExtentFile( vcb ); - - CLEAN_CATALOGDATA(&catalogData); - return (errDF ? errDF : (errRF ? errRF : err)); -Exit: - - CLEAN_CATALOGDATA(&catalogData); - return( err ); -} //‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ // Routine: CompareExtentKeys @@ -1067,7 +1009,7 @@ OSErr ExtendFileC ( UInt32 numExtentsPerRecord; SInt64 maximumBytes; SInt64 peof; - SInt64 previousPEOF; + UInt32 prevblocks; needsFlush = false; @@ -1075,7 +1017,7 @@ OSErr ExtendFileC ( volumeBlockSize = vcb->blockSize; allOrNothing = ((flags & kEFAllMask) != 0); forceContig = ((flags & kEFContigMask) != 0); - previousPEOF = fcb->fcbPLen; + prevblocks = fcb->ff_blocks; if (vcb->vcbSigWord == kHFSPlusSigWord) numExtentsPerRecord = kHFSPlusExtentDensity; @@ -1088,33 +1030,63 @@ OSErr ExtendFileC ( if (vcb->vcbSigWord == kHFSSigWord) { if (bytesToAdd >= kTwoGigabytes) goto Overflow; - if ((fcb->fcbPLen + bytesToAdd) >= kTwoGigabytes) + if ((((SInt64)fcb->ff_blocks * (SInt64)volumeBlockSize) + bytesToAdd) >= kTwoGigabytes) goto Overflow; - } + } // // Determine how many blocks need to be allocated. // Round up the number of desired bytes to add. // blocksToAdd = FileBytesToBlocks(bytesToAdd, volumeBlockSize); bytesToAdd = (SInt64)((SInt64)blocksToAdd * (SInt64)volumeBlockSize); - + + /* + * For deferred allocations just reserve the blocks. + */ + if ((flags & kEFDeferMask) + && (vcb->vcbSigWord == kHFSPlusSigWord) + && (bytesToAdd < (SInt64)HFS_MAX_DEFERED_ALLOC) + && (blocksToAdd < hfs_freeblks(VCBTOHFS(vcb), 1))) { + fcb->ff_unallocblocks += blocksToAdd; + vcb->loanedBlocks += blocksToAdd; + FTOC(fcb)->c_blocks += blocksToAdd; + fcb->ff_blocks += blocksToAdd; + + FTOC(fcb)->c_flag |= C_MODIFIED; + *actualBytesAdded = bytesToAdd; + return (0); + } + /* + * Give back any unallocated blocks before doing real allocations. + */ + if (fcb->ff_unallocblocks > 0) { + blocksToAdd += fcb->ff_unallocblocks; + bytesToAdd = (SInt64)blocksToAdd * (SInt64)volumeBlockSize; + + vcb->loanedBlocks -= fcb->ff_unallocblocks; + FTOC(fcb)->c_blocks -= fcb->ff_unallocblocks; + fcb->ff_blocks -= fcb->ff_unallocblocks; + fcb->ff_unallocblocks = 0; + } + // // If the file's clump size is larger than the allocation block size, // then set the maximum number of bytes to the requested number of bytes // rounded up to a multiple of the clump size. // - if (fcb->fcbClmpSize > volumeBlockSize) { + if ((fcb->fcbClmpSize > volumeBlockSize) + && (bytesToAdd < (SInt64)HFS_MAX_DEFERED_ALLOC) + && (flags & kEFNoClumpMask) == 0) { maximumBytes = (SInt64)FileBytesToBlocks(bytesToAdd, fcb->fcbClmpSize); maximumBytes *= fcb->fcbClmpSize; - } - else { + } else { maximumBytes = bytesToAdd; } // // Compute new physical EOF, rounded up to a multiple of a block. // - if ((vcb->vcbSigWord == kHFSSigWord) && ((fcb->fcbPLen + bytesToAdd) >= (SInt64) kTwoGigabytes)) // Too big? + if ((vcb->vcbSigWord == kHFSSigWord) && ((((SInt64)fcb->ff_blocks * (SInt64)volumeBlockSize) + bytesToAdd) >= kTwoGigabytes)) // Too big? if (allOrNothing) // Yes, must they have it all? goto Overflow; // Yes, can't have it else { @@ -1126,7 +1098,8 @@ OSErr ExtendFileC ( // If allocation is all-or-nothing, make sure there are // enough free blocks on the volume (quick test). // - if (allOrNothing && (blocksToAdd > (SInt64)vcb->freeBlocks)) { + if (allOrNothing && + (blocksToAdd > hfs_freeblks(VCBTOHFS(vcb), flags & kEFReserveMask))) { err = dskFulErr; goto ErrorExit; } @@ -1134,13 +1107,13 @@ OSErr ExtendFileC ( // // See if there are already enough blocks allocated to the file. // - peof = fcb->fcbPLen + bytesToAdd; // potential new PEOF + peof = ((SInt64)fcb->ff_blocks * (SInt64)volumeBlockSize) + bytesToAdd; // potential new PEOF err = SearchExtentFile(vcb, fcb, peof-1, &foundKey, foundData, &foundIndex, &hint, &nextBlock); if (err == noErr) { // Enough blocks are already allocated. Just update the FCB to reflect the new length. - fcb->fcbPLen = peof; - H_EXTENDSIZE(fcb, bytesToAdd); - fcb->fcbFlags |= fcbModifiedMask; + fcb->ff_blocks = peof / volumeBlockSize; + FTOC(fcb)->c_blocks += (bytesToAdd / volumeBlockSize); + FTOC(fcb)->c_flag |= C_MODIFIED; goto Exit; } if (err != fxRangeErr) // Any real error? @@ -1150,11 +1123,11 @@ OSErr ExtendFileC ( // Adjust the PEOF to the end of the last extent. // peof = (SInt64)((SInt64)nextBlock * (SInt64)volumeBlockSize); // currently allocated PEOF - bytesThisExtent = peof - fcb->fcbPLen; + bytesThisExtent = (SInt64)(nextBlock - fcb->ff_blocks) * (SInt64)volumeBlockSize; if (bytesThisExtent != 0) { - fcb->fcbPLen = peof; - H_EXTENDSIZE(fcb, bytesThisExtent); - fcb->fcbFlags |= fcbModifiedMask; + fcb->ff_blocks = nextBlock; + FTOC(fcb)->c_blocks += (bytesThisExtent / volumeBlockSize); + FTOC(fcb)->c_flag |= C_MODIFIED; bytesToAdd -= bytesThisExtent; } @@ -1173,7 +1146,36 @@ OSErr ExtendFileC ( startBlock = blockHint; else startBlock = foundData[foundIndex].startBlock + foundData[foundIndex].blockCount; - err = BlockAllocate(vcb, startBlock, bytesToAdd, maximumBytes, wantContig, &actualStartBlock, &actualNumBlocks); + + /* Force reserve checking if requested. */ + if (flags & kEFReserveMask) { + SInt64 availbytes; + + actualNumBlocks = 0; + actualStartBlock = 0; + + availbytes = (SInt64)hfs_freeblks(VCBTOHFS(vcb), 1) * + (SInt64)volumeBlockSize; + if (availbytes <= 0) { + err = dskFulErr; + } else { + if (wantContig && (availbytes < bytesToAdd)) + err = dskFulErr; + else { + err = BlockAllocate( + vcb, + startBlock, + MIN(bytesToAdd, availbytes), + MIN(maximumBytes, availbytes), + wantContig, + &actualStartBlock, + &actualNumBlocks); + } + } + } else { + err = BlockAllocate(vcb, startBlock, bytesToAdd, maximumBytes, + wantContig, &actualStartBlock, &actualNumBlocks); + } if (err == dskFulErr) { if (forceContig) break; // AllocContig failed because not enough contiguous space @@ -1202,19 +1204,19 @@ OSErr ExtendFileC ( ++foundIndex; // No, so use the next one. if (foundIndex == numExtentsPerRecord) { // This record is full. Need to create a new one. - if (H_FILEID(fcb) == kHFSExtentsFileID) { + if (FTOC(fcb)->c_fileid == kHFSExtentsFileID) { (void) BlockDeallocate(vcb, actualStartBlock, actualNumBlocks); err = dskFulErr; // Oops. Can't extend extents file past first record. break; } foundKey.keyLength = kHFSPlusExtentKeyMaximumLength; - if (fcb->fcbFlags & fcbResourceMask) + if (FORK_IS_RSRC(fcb)) foundKey.forkType = kResourceForkType; else foundKey.forkType = kDataForkType; foundKey.pad = 0; - foundKey.fileID = H_FILEID(fcb); + foundKey.fileID = FTOC(fcb)->c_fileid; foundKey.startBlock = nextBlock; foundData[0].startBlock = actualStartBlock; @@ -1262,9 +1264,9 @@ OSErr ExtendFileC ( bytesToAdd -= bytesThisExtent; maximumBytes -= bytesThisExtent; } - fcb->fcbPLen += bytesThisExtent; - H_EXTENDSIZE(fcb, bytesThisExtent); - fcb->fcbFlags |= fcbModifiedMask; + fcb->ff_blocks += (bytesThisExtent / volumeBlockSize); + FTOC(fcb)->c_blocks += (bytesThisExtent / volumeBlockSize); + FTOC(fcb)->c_flag |= C_MODIFIED; // If contiguous allocation was requested, then we've already got one contiguous // chunk. If we didn't get all we wanted, then adjust the error to disk full. @@ -1278,7 +1280,7 @@ OSErr ExtendFileC ( ErrorExit: Exit: - *actualBytesAdded = fcb->fcbPLen - previousPEOF; + *actualBytesAdded = (SInt64)(fcb->ff_blocks - prevblocks) * (SInt64)volumeBlockSize; if (needsFlush) (void) FlushExtentFile(vcb); @@ -1345,12 +1347,12 @@ OSErr TruncateFileC ( else numExtentsPerRecord = kHFSExtentDensity; - if (fcb->fcbFlags & fcbResourceMask) + if (FORK_IS_RSRC(fcb)) forkType = kResourceForkType; else forkType = kDataForkType; - temp64 = fcb->fcbPLen / (SInt64)vcb->blockSize; // number of allocation blocks currently in file + temp64 = fcb->ff_blocks; physNumBlocks = (UInt32)temp64; // @@ -1360,7 +1362,7 @@ OSErr TruncateFileC ( // nextBlock = FileBytesToBlocks(peof, vcb->blockSize); // number of allocation blocks to remain in file peof = (SInt64)((SInt64)nextBlock * (SInt64)vcb->blockSize); // number of bytes in those blocks - if ((vcb->vcbSigWord == kHFSSigWord) && (peof >= (UInt32) kTwoGigabytes)) { + if ((vcb->vcbSigWord == kHFSSigWord) && (peof >= kTwoGigabytes)) { #if DEBUG_BUILD DebugStr("\pHFS: Trying to truncate a file to 2GB or more"); #endif @@ -1371,9 +1373,10 @@ OSErr TruncateFileC ( // // Update FCB's length // - H_TRUNCSIZE(fcb, fcb->fcbPLen - peof); - fcb->fcbPLen = peof; - fcb->fcbFlags |= fcbModifiedMask; + numBlocks = peof / vcb->blockSize; + FTOC(fcb)->c_blocks -= (fcb->ff_blocks - numBlocks); + fcb->ff_blocks = numBlocks; + FTOC(fcb)->c_flag |= C_MODIFIED; // // If the new PEOF is 0, then truncateToExtent has no meaning (we should always deallocate @@ -1383,7 +1386,7 @@ OSErr TruncateFileC ( int i; // Deallocate all the extents for this fork - err = DeallocateFork(vcb, H_FILEID(fcb), forkType, fcb->fcbExtents, &recordDeleted); + err = DeallocateFork(vcb, FTOC(fcb)->c_fileid, forkType, fcb->fcbExtents, &recordDeleted); if (err != noErr) goto ErrorExit; // got some error, so return it // Update the catalog extent record (making sure it's zeroed out) @@ -1469,7 +1472,7 @@ OSErr TruncateFileC ( // blocks. // if (nextBlock < physNumBlocks) - err = TruncateExtents(vcb, forkType, H_FILEID(fcb), nextBlock, &recordDeleted); + err = TruncateExtents(vcb, forkType, FTOC(fcb)->c_fileid, nextBlock, &recordDeleted); Done: ErrorExit: @@ -1651,8 +1654,8 @@ static OSErr SearchExtentFile( // // Find the desired record, or the previous record if it is the same fork // - err = FindExtentRecord(vcb, (fcb->fcbFlags & fcbResourceMask) ? kResourceForkType : kDataForkType, - H_FILEID(fcb), filePositionBlock, true, foundExtentKey, foundExtentData, extentBTreeHint); + err = FindExtentRecord(vcb, FORK_IS_RSRC(fcb) ? kResourceForkType : kDataForkType, + FTOC(fcb)->c_fileid, filePositionBlock, true, foundExtentKey, foundExtentData, extentBTreeHint); if (err == btNotFound) { // @@ -1711,68 +1714,70 @@ static OSErr UpdateExtentRecord ( const HFSPlusExtentRecord extentData, UInt32 extentBTreeHint) { - BTreeIterator btIterator; - FSBufferDescriptor btRecord; - UInt16 btRecordSize; - FCB * btFCB; - OSErr err = noErr; + OSErr err = noErr; if (extentFileKey->keyLength == 0) { // keyLength == 0 means the FCB's extent record BlockMoveData(extentData, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); - fcb->fcbFlags |= fcbModifiedMask; + FTOC(fcb)->c_flag |= C_MODIFIED; } else { + BTreeIterator * btIterator; + FSBufferDescriptor btRecord; + UInt16 btRecordSize; + FCB * btFCB; + // // Need to find and change a record in Extents BTree // btFCB = GetFileControlBlock(vcb->extentsRefNum); + MALLOC(btIterator, BTreeIterator *, sizeof(*btIterator), M_TEMP, M_WAITOK); + bzero(btIterator, sizeof(*btIterator)); if (vcb->vcbSigWord == kHFSSigWord) { HFSExtentKey * key; // Actual extent key used on disk in HFS HFSExtentRecord foundData; // The extent data actually found - key = (HFSExtentKey*) &btIterator.key; + key = (HFSExtentKey*) &btIterator->key; key->keyLength = kHFSExtentKeyMaximumLength; key->forkType = extentFileKey->forkType; key->fileID = extentFileKey->fileID; key->startBlock = extentFileKey->startBlock; - btIterator.hint.index = 0; - btIterator.hint.nodeNum = extentBTreeHint; + btIterator->hint.index = 0; + btIterator->hint.nodeNum = extentBTreeHint; btRecord.bufferAddress = &foundData; btRecord.itemSize = sizeof(HFSExtentRecord); btRecord.itemCount = 1; - err = BTSearchRecord(btFCB, &btIterator, kInvalidMRUCacheKey, &btRecord, - &btRecordSize, &btIterator); + err = BTSearchRecord(btFCB, btIterator, &btRecord, &btRecordSize, btIterator); if (err == noErr) err = HFSPlusToHFSExtents(extentData, (HFSExtentDescriptor *)&foundData); if (err == noErr) - err = BTReplaceRecord(btFCB, &btIterator, &btRecord, btRecordSize); + err = BTReplaceRecord(btFCB, btIterator, &btRecord, btRecordSize); } else { // HFS Plus volume HFSPlusExtentRecord foundData; // The extent data actually found - BlockMoveData(extentFileKey, &btIterator.key, sizeof(HFSPlusExtentKey)); + BlockMoveData(extentFileKey, &btIterator->key, sizeof(HFSPlusExtentKey)); - btIterator.hint.index = 0; - btIterator.hint.nodeNum = extentBTreeHint; + btIterator->hint.index = 0; + btIterator->hint.nodeNum = extentBTreeHint; btRecord.bufferAddress = &foundData; btRecord.itemSize = sizeof(HFSPlusExtentRecord); btRecord.itemCount = 1; - err = BTSearchRecord(btFCB, &btIterator, kInvalidMRUCacheKey, &btRecord, - &btRecordSize, &btIterator); + err = BTSearchRecord(btFCB, btIterator, &btRecord, &btRecordSize, btIterator); if (err == noErr) { BlockMoveData(extentData, &foundData, sizeof(HFSPlusExtentRecord)); - err = BTReplaceRecord(btFCB, &btIterator, &btRecord, btRecordSize); + err = BTReplaceRecord(btFCB, btIterator, &btRecord, btRecordSize); } } + FREE(btIterator, M_TEMP); } return err; @@ -1882,58 +1887,3 @@ static Boolean ExtentsAreIntegral( return true; } - - -//_________________________________________________________________________________ -// -// Routine: NodesAreContiguous -// -// Purpose: Ensure that all b-tree nodes are contiguous on disk -// Called by BTOpenPath during volume mount -//_________________________________________________________________________________ - -Boolean NodesAreContiguous( - ExtendedVCB *vcb, - FCB *fcb, - UInt32 nodeSize) -{ - UInt32 mask; - UInt32 startBlock; - UInt32 blocksChecked; - UInt32 hint; - HFSPlusExtentKey key; - HFSPlusExtentRecord extents; - OSErr result; - Boolean lastExtentReached; - - - if (vcb->blockSize >= nodeSize) - return TRUE; - - mask = (nodeSize / vcb->blockSize) - 1; - - // check the local extents - (void) GetFCBExtentRecord(fcb, extents); - if ( !ExtentsAreIntegral(extents, mask, &blocksChecked, &lastExtentReached) ) - return FALSE; - - if (lastExtentReached || (SInt64)((SInt64)blocksChecked * (SInt64)vcb->blockSize) >= fcb->fcbPLen) - return TRUE; - - startBlock = blocksChecked; - - // check the overflow extents (if any) - while ( !lastExtentReached ) - { - result = FindExtentRecord(vcb, kDataForkType, H_FILEID(fcb), startBlock, FALSE, &key, extents, &hint); - if (result) break; - - if ( !ExtentsAreIntegral(extents, mask, &blocksChecked, &lastExtentReached) ) - return FALSE; - - startBlock += blocksChecked; - } - - return TRUE; -} - diff --git a/bsd/hfs/hfscommon/Misc/GenericMRUCache.c b/bsd/hfs/hfscommon/Misc/GenericMRUCache.c deleted file mode 100644 index 1ba7db973..000000000 --- a/bsd/hfs/hfscommon/Misc/GenericMRUCache.c +++ /dev/null @@ -1,333 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - File: GenericMRUCache.c - - Contains: Contains cache accessor routines based on MRU / LRU ordering. - - Version: HFS+ 1.0 - - Copyright: © 1997-1998 by Apple Computer, Inc., all rights reserved. - - File Ownership: - - DRI: Deric Horn - - Other Contact: Don Brady - - Technology: HFS+ - - Writers: - - (DSH) Deric Horn - - Change History (most recent first): - - 1/29/98 DSH Add TrashMRUCache for TrashAllFSCaches API support. - 7/25/97 DSH first checked in -*/ - -#include "../../hfs_macos_defs.h" -#include "../headers/FileMgrInternal.h" - -enum { - // error codes - errNotInCache = -123, - errInvalidKey = -124 -}; - - -struct CacheBlock { - struct CacheBlock *nextMRU; // next node in MRU order - struct CacheBlock *nextLRU; // next node in LRU order - UInt32 flags; // status flags - UInt32 key; // comparrison Key - char buffer[1]; // user defineable data -}; -typedef struct CacheBlock CacheBlock; - -struct CacheGlobals { - UInt32 cacheBlockSize; // Size of CacheBlock structure including the buffer - UInt32 cacheBufferSize; // Size of cache buffer - UInt32 numCacheBlocks; // Number of blocks in cache - CacheBlock *mru; - CacheBlock *lru; -}; -typedef struct CacheGlobals CacheGlobals; - - -// -// Internal routines -// -static void InsertAsMRU ( CacheGlobals *cacheGlobals, CacheBlock *cacheBlock ); -static void InsertAsLRU ( CacheGlobals *cacheGlobals, CacheBlock *cacheBlock ); - - -// -// Diagram of Cache structures -// -// _______ ________ ________ ________ -// |data | | buff | | buff | | buff | -// | mru |-----> | nMRU |-----> | nMRU |--> °°° --->| nMRU |-->€ -// | lru |-\ €<-| nLRU | <-----| nLRU |<-- °°° <---| nLRU | -// ------- \ -------- -------- -------- -// \ | -// \-----------------------------------------/ -// CacheGlobals CacheBlock's - - - - -//‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ -// Routine: InitMRUCache -// -// Function: Allocates cache, and initializes all the cache structures. -// -//‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ -OSErr InitMRUCache( UInt32 bufferSize, UInt32 numCacheBlocks, Ptr *cachePtr ) -{ - OSErr err; - short i, lastBuffer; - CacheBlock *cacheBlock; - CacheGlobals *cacheGlobals; - UInt32 cacheBlockSize = offsetof( CacheBlock, buffer ) + bufferSize; - - cacheGlobals = (CacheGlobals *) NewPtrSysClear( sizeof( CacheGlobals ) + ( numCacheBlocks * cacheBlockSize ) ); - err = MemError(); - - if ( err == noErr ) - { - cacheGlobals->cacheBlockSize = cacheBlockSize; - cacheGlobals->cacheBufferSize = bufferSize; - cacheGlobals->numCacheBlocks = numCacheBlocks; - - lastBuffer = numCacheBlocks - 1; // last buffer number, since they start at 0 - - // Initialize the LRU order for the cache - cacheGlobals->lru = (CacheBlock *)((Ptr)cacheGlobals + sizeof( CacheGlobals ) + (lastBuffer * cacheBlockSize)); - cacheGlobals->lru->nextMRU = nil; - - // Initialize the MRU order for the cache - cacheGlobals->mru = (CacheBlock *)( (Ptr)cacheGlobals + sizeof( CacheGlobals ) ); // points to 1st cache block - cacheGlobals->mru->nextLRU = nil; - - // Traverse nodes, setting initial mru, lru, and default values - for ( i=0, cacheBlock=cacheGlobals->mru; ikey = kInvalidMRUCacheKey; // initialize key to illegal while we're at it - cacheBlock->flags = 0; - cacheBlock->nextMRU = (CacheBlock *) ( (Ptr)cacheBlock + cacheBlockSize ); - cacheBlock = cacheBlock->nextMRU; - } - // And the last Block - cacheGlobals->lru->key = kInvalidMRUCacheKey; - cacheBlock->flags = 0; - - for ( i=0, cacheBlock=cacheGlobals->lru; inextLRU = (CacheBlock *) ( (Ptr)cacheBlock - cacheBlockSize ); - cacheBlock = cacheBlock->nextLRU; - } - - *cachePtr = (Ptr) cacheGlobals; // return cacheGlobals to user - } - else - { - *cachePtr = nil; - } - - return( err ); -} - - -//‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ -// Routine: DisposeMRUCache -// -// Function: Dispose of all memory allocated by the cache -// -//‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ -OSErr DisposeMRUCache( Ptr cachePtr ) -{ - OSErr err; - - DisposePtr( cachePtr ); - err = MemError(); - - return( err ); -} - - -//ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ -// Routine: TrashMRUCache -// -// Function: Invalidates all entries in the MRU cache pointed to by cachePtr. -// -//ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ -void TrashMRUCache( Ptr cachePtr ) -{ - CacheGlobals *cacheGlobals = (CacheGlobals *) cachePtr; - CacheBlock *cacheBlock; - - for ( cacheBlock = cacheGlobals->mru ; cacheBlock != nil ; cacheBlock = cacheBlock->nextMRU ) - { - cacheBlock->flags = 0; // Clear the flags - cacheBlock->key = kInvalidMRUCacheKey; // Make it an illegal value - } -} - - -//ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ -// Routine: GetMRUCacheBlock -// -// Function: Return buffer associated with the passed in key. -// Search the cache in MRU order -// € We can insert the found cache block at the head of mru automatically -// -//‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ -OSErr GetMRUCacheBlock( UInt32 key, Ptr cachePtr, Ptr *buffer ) -{ - CacheBlock *cacheBlock; - CacheGlobals *cacheGlobals = (CacheGlobals *) cachePtr; - -// if ( key == kInvalidMRUCacheKey ) // removed for performance -// return( errInvalidKey ); - - for ( cacheBlock = cacheGlobals->mru ; (cacheBlock != nil) && (cacheBlock->key != kInvalidMRUCacheKey) ; cacheBlock = cacheBlock->nextMRU ) - { - if ( cacheBlock->key == key ) - { - InsertAsMRU( cacheGlobals, cacheBlock ); - *buffer = (Ptr) cacheBlock->buffer; - return( noErr ); - } - } - - return( errNotInCache ); -} - - - -//‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ -// Routine: InvalidateMRUCacheBlock -// -// Function: Place the cache block at the head of the lru queue and mark it invalid -// -//‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ -void InvalidateMRUCacheBlock( Ptr cachePtr, Ptr buffer ) -{ - CacheGlobals *cacheGlobals = (CacheGlobals *) cachePtr; - CacheBlock *cacheBlock; - - cacheBlock = (CacheBlock *) (buffer - offsetof( CacheBlock, buffer )); - cacheBlock->flags = 0; // Clear the flags - cacheBlock->key = kInvalidMRUCacheKey; // Make it an illegal value - InsertAsLRU( cacheGlobals, cacheBlock ); -} - - -//‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ -// Routine: InsertMRUCacheBlock -// -// Function: Place the CacheBlock associated with the passed in key at the -// head of the mru queue and replace the buffer with the passed in buffer -// -//‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ -void InsertMRUCacheBlock( Ptr cachePtr, UInt32 key, Ptr buffer ) -{ - CacheBlock *cacheBlock = NULL; - Ptr cacheBuffer; - OSErr err; - CacheGlobals *cacheGlobals = (CacheGlobals *) cachePtr; - UInt32 cacheBufferSize; - - err = GetMRUCacheBlock( key, cachePtr, &cacheBuffer ); - if ( err == errNotInCache ) - cacheBlock = cacheGlobals->lru; - else if ( err == noErr ) - cacheBlock = (CacheBlock *) (cacheBuffer - offsetof( CacheBlock, buffer )); - - cacheBufferSize = cacheGlobals->cacheBufferSize; - if ( cacheBufferSize == sizeof(UInt32) ) - *(UInt32*)cacheBlock->buffer = *(UInt32*)buffer; - else - BlockMoveData( buffer, cacheBlock->buffer, cacheBufferSize ); - InsertAsMRU( cacheGlobals, cacheBlock ); - - cacheBlock->flags = 0; - cacheBlock->key = key; -} - - - - -//‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ -// Routine: InsertMRUCacheBlock -// -// Function: Moves cache block to head of mru order in double linked list of cached blocks -// -//‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ -static void InsertAsMRU ( CacheGlobals *cacheGlobals, CacheBlock *cacheBlock ) -{ - CacheBlock *swapBlock; - - if ( cacheGlobals->mru != cacheBlock ) // if it's not already the mru cacheBlock - { - swapBlock = cacheGlobals->mru; // put it in the front of the double queue - cacheGlobals->mru = cacheBlock; - cacheBlock->nextLRU->nextMRU = cacheBlock->nextMRU; - if ( cacheBlock->nextMRU != nil ) - cacheBlock->nextMRU->nextLRU = cacheBlock->nextLRU; - else - cacheGlobals->lru= cacheBlock->nextLRU; - cacheBlock->nextMRU = swapBlock; - cacheBlock->nextLRU = nil; - swapBlock->nextLRU = cacheBlock; - } -} - - -//‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ -// Routine: InsertMRUCacheBlock -// -// Function: Moves cache block to head of lru order in double linked list of cached blocks -// -//‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ -static void InsertAsLRU ( CacheGlobals *cacheGlobals, CacheBlock *cacheBlock ) -{ - CacheBlock *swapBlock; - - if ( cacheGlobals->lru != cacheBlock ) - { - swapBlock = cacheGlobals->lru; - cacheGlobals->lru = cacheBlock; - cacheBlock->nextMRU->nextLRU = cacheBlock->nextLRU; - if ( cacheBlock->nextLRU != nil ) - cacheBlock->nextLRU->nextMRU = cacheBlock->nextMRU; - else - cacheGlobals->mru= cacheBlock->nextMRU; - cacheBlock->nextLRU = swapBlock; - cacheBlock->nextMRU = nil; - swapBlock->nextMRU = cacheBlock; - } -} - - diff --git a/bsd/hfs/hfscommon/Misc/VolumeAllocation.c b/bsd/hfs/hfscommon/Misc/VolumeAllocation.c index 8f074d0b1..ae4fccf6f 100644 --- a/bsd/hfs/hfscommon/Misc/VolumeAllocation.c +++ b/bsd/hfs/hfscommon/Misc/VolumeAllocation.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -230,11 +230,11 @@ OSErr BlockAllocate ( // // If the disk is already full, don't bother. // - if (vcb->freeBlocks == 0) { + if (hfs_freeblks(VCBTOHFS(vcb), 0) == 0) { err = dskFulErr; goto Exit; } - if (forceContiguous && vcb->freeBlocks < minBlocks) { + if (forceContiguous && hfs_freeblks(VCBTOHFS(vcb), 0) < minBlocks) { err = dskFulErr; goto Exit; } @@ -256,6 +256,12 @@ OSErr BlockAllocate ( // if (forceContiguous) { err = BlockAllocateContig(vcb, startingBlock, minBlocks, maxBlocks, actualStartBlock, actualNumBlocks); + /* + * If we allocated from a new position then + * also update the roving allocatior. + */ + if ((err == noErr) && (*actualStartBlock > startingBlock)) + vcb->nextAllocation = *actualStartBlock; } else { /* * Scan the bitmap once, gather the N largest free extents, then @@ -347,6 +353,8 @@ OSErr BlockDeallocate ( // VCB_LOCK(vcb); vcb->freeBlocks += numBlocks; + if (vcb->nextAllocation == (firstBlock + numBlocks)) + vcb->nextAllocation -= numBlocks; VCB_UNLOCK(vcb); MarkVCBDirty(vcb); @@ -468,7 +476,6 @@ static OSErr ReleaseBitmapBlock( if (bp) { if (dirty) { - bp->b_flags |= B_DIRTY; bdwrite(bp); } else { brelse(bp); @@ -1165,6 +1172,7 @@ static OSErr BlockFindContiguous( stopBlock = endingBlock - minBlocks + 1; currentBlock = startingBlock; + firstBlock = 0; // // Pre-read the first bitmap block. @@ -1195,7 +1203,7 @@ static OSErr BlockFindContiguous( bitMask = currentBlock & kBitsWithinWordMask; if (bitMask) { - tempWord = *currentWord; // Fetch the current word only once + tempWord = SWAP_BE32(*currentWord); // Fetch the current word only once bitMask = kHighBitInWordMask >> bitMask; while (tempWord & bitMask) { @@ -1232,7 +1240,7 @@ static OSErr BlockFindContiguous( } // See if any of the bits are clear - if ((tempWord=*currentWord) + 1) // non-zero if any bits were clear + if ((tempWord = SWAP_BE32(*currentWord)) + 1) // non-zero if any bits were clear { // Figure out which bit is clear bitMask = kHighBitInWordMask; @@ -1271,7 +1279,7 @@ FoundUnused: bitMask = currentBlock & kBitsWithinWordMask; if (bitMask) { - tempWord = *currentWord; // Fetch the current word only once + tempWord = SWAP_BE32(*currentWord); // Fetch the current word only once bitMask = kHighBitInWordMask >> bitMask; while (bitMask && !(tempWord & bitMask)) { @@ -1308,7 +1316,7 @@ FoundUnused: } // See if any of the bits are set - if ((tempWord=*currentWord) != 0) + if ((tempWord = SWAP_BE32(*currentWord)) != 0) { // Figure out which bit is set bitMask = kHighBitInWordMask; diff --git a/bsd/hfs/hfscommon/Misc/VolumeRequests.c b/bsd/hfs/hfscommon/Misc/VolumeRequests.c deleted file mode 100644 index 18c6eb6b4..000000000 --- a/bsd/hfs/hfscommon/Misc/VolumeRequests.c +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - File: VolumeRequests.c - - Contains: MountVolume and related utility routines for HFS & HFS Plus - - Version: HFS Plus 1.0 - - Written by: Deric Horn - - Copyright: © 1996-1998 by Apple Computer, Inc., all rights reserved. - - File Ownership: - - DRI: Deric Horn - - Other Contacts: Mark Day, Don Brady - - Technology: File Systems - - Writers: - - (JL) Jim Luther - (msd) Mark Day - (DSH) Deric Horn - (djb) Don Brady - - Change History (most recent first): - 7/28/98 djb GetDiskBlocks is now implemented in MacOSStubs.c (radar #2258148). - 4/3/98 djb Conditionally remove FSVars reference from GetVolumeNameFromCatalog. - 3/31/98 djb Sync up with final HFSVolumes.h header file. - 1/29/98 DSH TrashAllFSCaches is responsible for trashing all file system and - disk caches. Called from FlushVol when the HFS bit is set. - 12/12/97 DSH 2003877, when vcbAllocPtr was copied to nextAllocation it was - getting sign extended. - 11/26/97 DSH 2003459, fcbs was not being initialized if volume was offline - and we are executing an unconditional unmount. - 11/24/97 DSH 2005507, FlushVolumeControlBlock() keeps MDB drCrDate in sync - with VolumeHeader createDate. - 11/11/97 DSH 1685873, RemountWrappedVolumes was only remounting the first - HFS+ volume in the queue, causing HFS wrappers to be mounted if - multiple volumes had been mounted before InitHFSPlus. - 11/4/97 DSH Clear FCB when getting a new one. - 11/3/97 JL #2001483 - Removed unneeded parameters from MountVolume, - MountHFSVolume, MountHFSPlusVolume, GetVolumeInformation, - GetXVolumeInformation and AddVCB (and added local variables as - needed). Return WDCBRecPtr from UnMountVolume. Set wdcb - parameter to NULL in GetXVolumeInformation if working directory - was not specified. - 10/31/97 DSH Added consistencyStatus parameter to MountCheck - 10/23/97 msd Bug 1685113. The VolumeHeader's createDate should be in local - time (not GMT) and identical to the MDB's drCrDate (and VCB's - vcbCrDate). When checking for a remount of an offline HFS Plus - volume, compare write counts instead of mod dates (which could - be fooled by the user changing time zones). Force MountCheck to - run if the volume was last mounted by Bride 1.0b2 or earlier. - 10/17/97 msd Conditionalize DebugStrs. - 10/13/97 djb Update volumeNameEncodingHint when updating the volume name. - 10/10/97 msd Bug 1683571. The dates in the volume header are in GMT, so be - sure to convert them when mounting a volume or flushing the - volume header. - 10/2/97 DSH In UnmountVolume() check that the drive is on line before - determining if wrapper volume needs to be renamed causing IO. - 10/1/97 DSH Run on disk version of MountCheck instead of ROM version for - boot volumes1682475. - 10/1/97 djb Add calls to InvalidateCatalogCache (part of radar #1678833). - 9/26/97 DSH Removed debugging code: support for 'W' key wrapper mounting. - 9/17/97 DSH hfsPlusIOPosOffset was uninitialized for Wrapperless volumes. - 9/5/97 djb In MountVol initialize Catalog cache before calling Catalog! - 9/4/97 msd PropertyCloseVolume renamed to AttributesCloseVolume. Remove - call to AttributesOpenVolume (it no longer exists). - 9/2/97 DSH VolumeHeader is now 3rd sector in partition, altVH is 2nd to - last cor compatability. Initial support for wrapperless - volumes. - 8/26/97 djb Only call CountRootFiles during MountVol. - 8/20/97 msd If the HFS Plus volume version doesn't match, mount the wrapper - instead. - 8/19/97 djb Add error handling to RenameWrapperVolume. - 8/15/97 msd Bug 1673999. In MakeVCBsExtendedVCBs, copy old VCB's vcbAllocPtr - to new VCB's nextAllocation field. - 8/12/97 djb Fixed GetXVolInfo to only use extended vcb fields for local - volumes (radar# 1673177) - 8/11/97 DSH vcbNmAlBlks is now taken from the embededExtent.blockCount - (1669121). - 8/11/97 djb Return actual count of files in root directory for HFS Plus - volumes (Radar #1669118). Added local CountRootFiles routine. - 8/5/97 msd Make sure version field in VolumeHeader is exactly - kHFSPlusVersion. 8/1/97 djb GetXVolumeInformation now returns - extFSErr when FSID is nonzero (Radar #1649503). - 7/25/97 DSH Init and Dispose of GenericMRUCache within ExtendedVCB. - 7/16/97 DSH FilesInternal.x -> FileMgrInternal.x to avoid name collision - 7/15/97 DSH Remount Wrapper volumes mounted before HFS+ initialization - (166729) - 7/15/97 djb Remove ioXVersion checking in GetXVolInfo (radar #1666217). - 7/8/97 DSH Loading PrecompiledHeaders from define passed in on C line - 7/7/97 djb Add GetVolumeNameFromCatalog routine. - 7/7/97 DSH GetNewVRefNum now get's a recycled vRefNum. Bug 1664445 in - Installer was cacheing the vRefNum while CheckDisk unmounts and - remounts disk. - 6/30/97 DSH shadowing values obsoleteVCBXTRef, and obsoleteVCBCTRef when - HFS+ volume is mounted. - 6/26/97 DSH GetVolInfo returns HFS signature for HFS+ volumes, GetXVolInfo - returns real signature. - 6/24/97 DSH MakeVCBsExtendedVCBs was using wdcb->count as count not byte - count. - 6/18/97 djb Set/get volume encodingsBitmap. - 6/16/97 msd Include String.h and Disks.h. - 6/12/97 djb Get in sync with HFS Plus format changes. - 6/11/97 msd Make GetXVolumeInformation return true allocation block size. It - now checks the ioXVersion field. - 5/28/97 msd When flushing the volume header, write out the allocation file's - clump size (from the FCB). When mounting an HFS Plus volume, - zero the entire FCB extent record, not just the first extent, - for the various volume control files. - 5/19/97 djb Add calls to CreateVolumeCatalogCache, - DisposeVolumeCatalogCache. - 5/9/97 djb Get in sync with new FilesInternal.i - 5/8/97 DSH Only mount HFS+ volumes with version < 2.0 in the VolumeHeader. - Return wrgVolTypErr if too new. - 5/2/97 djb Disable Manual Eject code since its buggy! - 4/25/97 djb first checked in - - 4/11/97 DSH MountHFSPlusVolume gets volume name from catalog, and - UnmountVolume shadows the name back to the wrapper partition. - 4/8/97 msd Once volume is mounted, call AttributesOpenVolume to allow a - buffer to be allocated. - 4/7/97 msd In FlushVolumeControlBlock, don't update the attributes BTree - fields in the Volume Header unless an attributes BTree was - already open. - 4/7/97 msd In SetupFCB, add case for attributes BTree. Add code to set up - the attributes BTree. Remove call to PropertyOpenVolume. In - FlushVolumeControlBlock, write out any changes to the attributes - BTree. - 4/4/97 djb Get in sync with volume format changes. - 3/31/97 djb Added catalogDataCache to VCB; Remove ClearMem routine. - 3/18/97 msd In MountHFSPlusVolume, the free blocks calculation can overflow, - setting vcbFreeBks to a too-small value. - 3/17/97 DSH Added some utility functions AddVCB, GetParallelFCBFromRefNum, - casting for SC, and made some functions extern for DFA. - 3/5/97 msd Add calls to Property Manager to open and close the volume. When - unmounting an HFS+ volume, the allocation (bitmap) file now gets - closed. - 2/19/97 djb Update to 16-bit HFS Plus signature. - 2/12/97 msd In GetXVolumeInformation, the result code could be - uninitialized. - 1/23/97 DSH UpdateAlternateVoumeControlBlock() - 1/15/97 djb Remove MountCheckStub. Add file names to fcbs for debugging. - 1/13/97 DSH Use ExtendedVCB nextAllocation instead of vcbAllocPtr through - all code. - 1/9/97 djb Get in sync with new VolumeHeader and Extended VCB. - 1/6/97 djb Changed API to ParallelFCBFromRefnum (pragma parameter was - broken). - 1/6/97 msd Set only the defined bits in the MDB drAtrb field (when copying - from VCB vcbAtrb field). - 1/6/97 DSH CloseFile requires VCB to be passed in. - 1/6/97 djb FlushVolumeControlBlock was writing to absolute block 0 instead - of to block zero of the embedded volume. - 12/20/96 msd A comparison was using "=" instead of "=="; might have caused - the wrong volume to be set as the default. - 12/19/96 DSH Setting up ExtendedVCBs - 12/19/96 djb Updated for new B-tree Manager interface. - 12/18/96 msd Change GetVCBRefNum so it can actually return a VCB pointer. - 12/12/96 djb Use new SPI for GetCatalogNode. - 12/12/96 msd Fix a bunch of errors (mostly type mismatch) when compiling with - Metrowerks. - 12/12/96 DSH adding some util functions - 12/10/96 msd Check PRAGMA_LOAD_SUPPORTED before loading precompiled headers. - 12/4/96 DSH Ported GetVolumeInformation & GetXVolumeInformation. - <3*> 11/20/96 DSH HFS Plus support to MountVolume - 11/20/96 DSH Added UnmountVol and related routines, also backed out <2> - because C_FXMKeyCmp is passed as a parameter from C but called - from Asm in BTOpen so we need a Case ON Asm entry point. - 11/20/96 msd Use CompareExtentKeys() instead of CFXMKeyCmp(). - 11/19/96 DSH first checked in - <1> 11/19/96 DSH first checked in - -*/ -#include -#include -#include -#include -#include - -#include "../../hfs.h" -#include "../../hfs_endian.h" - -#include "../headers/FileMgrInternal.h" - - -OSErr ValidMasterDirectoryBlock( HFSMasterDirectoryBlock *mdb ); - -OSErr GetVolumeNameFromCatalog(ExtendedVCB *vcb); - -// External routines - -extern OSErr C_FlushMDB( ExtendedVCB *volume ); - - -//‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ -// Routine: VolumeWritable Asm: CVFlgs -// -// Function: Check the volume's flags to see if modify requests are allowed. -// -//‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ -OSErr VolumeWritable( ExtendedVCB *vcb ) -{ - if ( !(vcb->vcbAtrb & 0x8000) ) // if the volume is not locked - { - if ( ! (*((Ptr)&(vcb->vcbAtrb) + 1) & kHFSVolumeHardwareLockMask) ) // if it's not write protected - return( noErr ); - else - return( wPrErr ); - } - else - { - return( vLckdErr ); - } -} - - -//‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ -// Routine: ValidMasterDirectoryBlock -// -// Function: Run some sanity checks to make sure the MDB is valid -// -// Result: error -//‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ -OSErr ValidMasterDirectoryBlock( HFSMasterDirectoryBlock *mdb ) -{ - OSErr err; - - if ( (SWAP_BE16 (mdb->drSigWord) == kHFSPlusSigWord) || (SWAP_BE16 (mdb->drSigWord) == kHFSSigWord) ) // if HFS or HFS Plus volume - { - if ( (SWAP_BE32 (mdb->drAlBlkSiz) != 0) && ((SWAP_BE32 (mdb->drAlBlkSiz) & 0x01FF) == 0) ) // non zero multiple of 512 - err = noErr; - else - err = badMDBErr; - } - else - { - err = noMacDskErr; - } - - return( err ); -} - - -//‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ -// Routine: ValidVolumeHeader -// -// Function: Run some sanity checks to make sure the VolumeHeader is valid -// -// Result: error -//‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ -OSErr ValidVolumeHeader( HFSPlusVolumeHeader *volumeHeader ) -{ - OSErr err; - - if ( SWAP_BE16 (volumeHeader->signature) == kHFSPlusSigWord && SWAP_BE16 (volumeHeader->version) == kHFSPlusVersion ) - { - if ( (SWAP_BE32 (volumeHeader->blockSize) != 0) && ((SWAP_BE32 (volumeHeader->blockSize) & 0x01FF) == 0) ) // non zero multiple of 512 - err = noErr; - else - err = badMDBErr; //€€ I want badVolumeHeaderErr in Errors.i - } - else - { - err = noMacDskErr; - } - - return( err ); -} - - -//_______________________________________________________________________ -// -// Routine: FlushVolumeControlBlock -// Arguments: ExtendedVCB *vcb -// Output: OSErr err -// -// Function: Flush volume information to either the VolumeHeader of the Master Directory Block -//_______________________________________________________________________ - -OSErr FlushVolumeControlBlock( ExtendedVCB *vcb ) -{ - OSErr err; - - if ( ! IsVCBDirty( vcb ) ) // if it's not dirty - return( noErr ); - - if ( vcb->vcbSigWord == kHFSPlusSigWord ) - { - err = C_FlushMDB( vcb ); // Go flush the VCB info BEFORE close - } - else - { - // This routine doesn't really return an error!!! - // So for now, we will just return noErr - err = C_FlushMDB( vcb ); // Go flush the VCB info BEFORE close - return( noErr ); - } - - return( err ); -} - - -//‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ - -OSErr GetVolumeNameFromCatalog( ExtendedVCB *vcb ) -{ - CatalogNodeData nodeData; - UInt32 hint; - OSErr err; - - INIT_CATALOGDATA(&nodeData, 0); - - err = GetCatalogNode( vcb, kHFSRootFolderID, NULL, kUndefinedStrLen, kNoHint, &nodeData, &hint ); - - if ( err == noErr ) - { - BlockMoveData( nodeData.cnm_nameptr, vcb->vcbVN, min(255, nodeData.cnm_length)); - vcb->volumeNameEncodingHint = nodeData.cnd_textEncoding; - - /* HFS+ uses the root directory's create date since its in GMT */ - if (vcb->vcbSigWord == kHFSPlusSigWord) - vcb->vcbCrDate = nodeData.cnd_createDate; - } - - CLEAN_CATALOGDATA(&nodeData); - - return err; -} diff --git a/bsd/hfs/hfscommon/Unicode/UCStringCompareData.h b/bsd/hfs/hfscommon/Unicode/UCStringCompareData.h index b7b7deaf1..b975465d3 100644 --- a/bsd/hfs/hfscommon/Unicode/UCStringCompareData.h +++ b/bsd/hfs/hfscommon/Unicode/UCStringCompareData.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -55,6 +55,13 @@ 2/27/97 msd first checked in */ +#ifndef _UCSTRINGCOMPAREDATA_ +#define _UCSTRINGCOMPAREDATA_ + +#include + +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE /* * For better performance, the case folding table for basic latin * is seperate from the others. This eliminates the extra lookup @@ -311,3 +318,6 @@ unsigned short gCompareTable[] = { /* F */ 0xF000, 0xF100, 0xF200, 0xF300, 0xF400, 0xF500, 0xF600, 0xF700, 0xF800, 0xF900, 0xFA00, 0xFB00, 0xFC00, 0xFD00, 0xFE00, 0xFF00, }; +#endif /* __APPLE_API_PRIVATE */ +#endif /* KERNEL */ +#endif /* _UCSTRINGCOMPAREDATA_ */ diff --git a/bsd/hfs/hfscommon/Unicode/UnicodeWrappers.c b/bsd/hfs/hfscommon/Unicode/UnicodeWrappers.c index 90c08d466..1e02d0932 100644 --- a/bsd/hfs/hfscommon/Unicode/UnicodeWrappers.c +++ b/bsd/hfs/hfscommon/Unicode/UnicodeWrappers.c @@ -148,9 +148,6 @@ CountFilenameExtensionChars( const unsigned char * filename, UInt32 length ) UInt16 maxExtChars; Boolean foundExtension; - if (length == kUndefinedStrLen) - length = strlen(filename); - if ( length < 3 ) return 0; /* "x.y" is smallest possible extension */ @@ -199,9 +196,6 @@ GetEmbeddedFileID(const unsigned char * filename, UInt32 length, UInt32 *prefixL if ( filename == NULL ) return 0; - if (length == kUndefinedStrLen) - length = strlen(filename); - if ( length < 28 ) return 0; /* too small to have been mangled */ @@ -274,8 +268,6 @@ HexStringToInteger(UInt32 length, const UInt8 *hexStr) * return 0 if equal * */ -extern unsigned short gCompareTable[]; - SInt32 FastRelString( ConstStr255Param str1, ConstStr255Param str2 ) { UInt16* compareTable; @@ -390,9 +382,6 @@ SInt32 FastRelString( ConstStr255Param str1, ConstStr255Param str2 ) // return 1; // -extern UInt16 gLowerCaseTable[]; -extern UInt16 gLatinCaseFold[]; - SInt32 FastUnicodeCompare ( register ConstUniCharArrayPtr str1, register ItemCount length1, register ConstUniCharArrayPtr str2, register ItemCount length2) { diff --git a/bsd/hfs/hfscommon/headers/BTreeScanner.h b/bsd/hfs/hfscommon/headers/BTreeScanner.h index b537bccfd..ce9cf3002 100644 --- a/bsd/hfs/hfscommon/headers/BTreeScanner.h +++ b/bsd/hfs/hfscommon/headers/BTreeScanner.h @@ -25,6 +25,10 @@ #ifndef _BTREESCANNER_H_ #define _BTREESCANNER_H_ +#include + +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE #include #include "FileMgrInternal.h" @@ -108,4 +112,6 @@ int BTScanTerminate( BTScanState * scanState, u_int32_t * startingRecord, u_int32_t * recordsFound ); +#endif /* __APPLE_API_PRIVATE */ +#endif /* KERNEL */ #endif /* !_BTREESCANNER_H_ */ diff --git a/bsd/hfs/hfscommon/headers/BTreesInternal.h b/bsd/hfs/hfscommon/headers/BTreesInternal.h index d692e1a52..a473cfceb 100644 --- a/bsd/hfs/hfscommon/headers/BTreesInternal.h +++ b/bsd/hfs/hfscommon/headers/BTreesInternal.h @@ -71,6 +71,11 @@ #ifndef __BTREESINTERNAL__ #define __BTREESINTERNAL__ +#include + +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE + #ifndef __FILEMGRINTERNAL__ #include "FileMgrInternal.h" #endif @@ -117,9 +122,9 @@ typedef BlockDescriptor *BlockDescPtr; struct FSBufferDescriptor { - LogicalAddress bufferAddress; - ByteCount itemSize; - ItemCount itemCount; + void * bufferAddress; + ByteCount itemSize; + ItemCount itemCount; }; typedef struct FSBufferDescriptor FSBufferDescriptor; @@ -148,7 +153,7 @@ enum { }; typedef OptionBits ReleaseBlockOptions; -typedef UInt32 FSSize; +typedef UInt64 FSSize; typedef UInt32 ForkBlockNumber; /*============================================================================ @@ -285,7 +290,6 @@ extern OSStatus BTClosePath (FCB *filePtr ); extern OSStatus BTSearchRecord (FCB *filePtr, BTreeIterator *searchIterator, - UInt32 heuristicHint, FSBufferDescriptor *btRecord, UInt16 *recordLen, BTreeIterator *resultIterator ); @@ -310,6 +314,10 @@ extern OSStatus BTReplaceRecord (FCB *filePtr, FSBufferDescriptor *btRecord, UInt16 recordLen ); +extern OSStatus BTUpdateRecord (FCB *filePtr, + BTreeIterator *iterator, + IterateCallBackProcPtr callBackProc, + void *callBackState ); extern OSStatus BTDeleteRecord (FCB *filePtr, BTreeIterator *iterator ); @@ -330,4 +338,6 @@ extern OSStatus BTGetLastSync (FCB *filePtr, extern OSStatus BTSetLastSync (FCB *filePtr, UInt32 lastfsync ); +#endif /* __APPLE_API_PRIVATE */ +#endif /* KERNEL */ #endif // __BTREESINTERNAL__ diff --git a/bsd/hfs/hfscommon/headers/BTreesPrivate.h b/bsd/hfs/hfscommon/headers/BTreesPrivate.h index 4fce7de21..4721f13a5 100644 --- a/bsd/hfs/hfscommon/headers/BTreesPrivate.h +++ b/bsd/hfs/hfscommon/headers/BTreesPrivate.h @@ -111,6 +111,11 @@ #ifndef __BTREESPRIVATE__ #define __BTREESPRIVATE__ +#include + +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE + #include "../../hfs_macos_defs.h" #ifndef __FILEMGRINTERNAL__ @@ -489,4 +494,6 @@ OSStatus DeleteTree (BTreeControlBlockPtr btreePtr, UInt16 index, UInt16 level ); +#endif /* __APPLE_API_PRIVATE */ +#endif /* KERNEL */ #endif //__BTREESPRIVATE__ diff --git a/bsd/hfs/hfscommon/headers/CatalogPrivate.h b/bsd/hfs/hfscommon/headers/CatalogPrivate.h index 96d0a3aa7..4fce1168a 100644 --- a/bsd/hfs/hfscommon/headers/CatalogPrivate.h +++ b/bsd/hfs/hfscommon/headers/CatalogPrivate.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000, 2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -69,6 +69,11 @@ #ifndef __CATALOGPRIVATE__ #define __CATALOGPRIVATE__ +#include + +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE + #include "../../hfs_format.h" #include "FileMgrInternal.h" @@ -145,8 +150,6 @@ typedef struct CatalogCacheGlobals CatalogCacheGlobals; // Private Catalog Manager Routines (for use only by Catalog Manager, CatSearch and FileID Services) // -extern OSErr LocateCatalogThread( const ExtendedVCB *volume, HFSCatalogNodeID nodeID, CatalogRecord *threadData, - UInt16 *threadSize, UInt32 *threadHint); extern OSErr LocateCatalogNode( const ExtendedVCB *volume, HFSCatalogNodeID folderID, const CatalogName *name, UInt32 hint, CatalogKey *key, CatalogRecord *data, UInt32 *newHint); @@ -160,19 +163,8 @@ extern OSErr LocateCatalogRecord( const ExtendedVCB *volume, HFSCatalogNodeID fo extern OSErr LocateCatalogNodeWithRetry ( const ExtendedVCB *volume, HFSCatalogNodeID folderID, ConstStr31Param pascalName, CatalogName *unicodeName, UInt32 hint, CatalogKey *keyPtr, CatalogRecord *dataPtr, UInt32 *newHint ); - -extern OSErr LocateCatalogNodeByMangledName( const ExtendedVCB *volume, HFSCatalogNodeID folderID, - ConstStr31Param name, UInt32 length, - CatalogKey *keyPtr, CatalogRecord *dataPtr, UInt32 *hintPtr ); - extern OSErr FlushCatalog( ExtendedVCB *volume); -#define InvalidateCatalogNodeCache(v, pid) - -extern OSErr UpdateFolderCount( ExtendedVCB *volume, HFSCatalogNodeID parentID, const CatalogName *name, SInt16 newType, - UInt32 hint, SInt16 valenceDelta); - -extern UInt16 GetCatalogRecordSize( const CatalogRecord *dataRecord); extern void ConvertInputNameToUnicode(ConstStr31Param name, TextEncoding encodingHint, TextEncoding *actualEncoding, CatalogName *catalogName); @@ -183,10 +175,6 @@ extern void BuildCatalogKey( HFSCatalogNodeID parentID, const CatalogName *name, extern OSErr BuildCatalogKeyUTF8(ExtendedVCB *volume, HFSCatalogNodeID parentID, const char *name, UInt32 length, CatalogKey *key, UInt32 *textEncoding); -extern void UpdateCatalogName( ConstStr31Param srcName, Str31 destName); - -extern UInt32 CatalogNameLength( const CatalogName *name, Boolean isHFSPlus); - extern void CopyCatalogName( const CatalogName *srcName, CatalogName *dstName, Boolean isHFSPLus); extern OSErr ResolveFileID( ExtendedVCB *vcb, HFSCatalogNodeID fileID, HFSCatalogNodeID *parentID, Str31 name ); @@ -197,16 +185,9 @@ extern OSErr CreateFileThreadID( FIDParam *filePB, WDCBRecPtr *wdcbPtr ); extern OSErr ExchangeFiles( FIDParam *filePB, WDCBRecPtr *wdcbPtr ); #endif -extern void CopyCatalogNodeData( const ExtendedVCB *volume, const CatalogRecord *dataPtr, CatalogNodeData *nodeData); - -extern void UpdateVolumeEncodings( ExtendedVCB *volume, TextEncoding encoding); - -extern void AdjustVolumeCounts( ExtendedVCB *volume, SInt16 type, SInt16 delta ); - // Catalog Iterator Routines -extern CatalogIterator* oGetCatalogIterator( const ExtendedVCB *volume, HFSCatalogNodeID folderID, UInt16 index); extern CatalogIterator* GetCatalogIterator(ExtendedVCB *volume, HFSCatalogNodeID folderID, UInt32 offset); extern OSErr ReleaseCatalogIterator( CatalogIterator *catalogIterator ); @@ -220,4 +201,6 @@ extern void UpdateBtreeIterator( const CatalogIterator *catalogIterator, BTreeI extern void UpdateCatalogIterator( const BTreeIterator *btreeIterator, CatalogIterator *catalogIterator ); +#endif /* __APPLE_API_PRIVATE */ +#endif /* KERNEL */ #endif //__CATALOGPRIVATE__ diff --git a/bsd/hfs/hfscommon/headers/FileMgrInternal.h b/bsd/hfs/hfscommon/headers/FileMgrInternal.h index ed67a4cf1..519cd4965 100644 --- a/bsd/hfs/hfscommon/headers/FileMgrInternal.h +++ b/bsd/hfs/hfscommon/headers/FileMgrInternal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -32,12 +32,18 @@ #ifndef __FILEMGRINTERNAL__ #define __FILEMGRINTERNAL__ +#include + +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE + #include #include #include "../../hfs.h" #include "../../hfs_macos_defs.h" #include "../../hfs_format.h" +#include "../../hfs_cnode.h" #if PRAGMA_ONCE @@ -104,10 +110,12 @@ enum { /* internal flags*/ enum { - kEFContigBit = 1, /* force contiguous allocation*/ - kEFContigMask = 0x02, - kEFAllBit = 0, /* allocate all requested bytes or none*/ - kEFAllMask = 0x01, /* TruncateFile option flags*/ + kEFAllMask = 0x01, /* allocate all requested bytes or none */ + kEFContigMask = 0x02, /* force contiguous allocation */ + kEFReserveMask = 0x04, /* keep block reserve */ + kEFDeferMask = 0x08, /* defer file block allocations */ + kEFNoClumpMask = 0x10, /* don't round up to clump size */ + kTFTrunExtBit = 0, /* truncate to the extent containing new PEOF*/ kTFTrunExtMask = 1 }; @@ -121,12 +129,6 @@ enum { }; -enum { - kInvalidMRUCacheKey = -1L, /* flag to denote current MRU cache key is invalid*/ - kDefaultNumMRUCacheBlocks = 16 /* default number of blocks in each cache*/ -}; - - /* Universal Extent Key */ union ExtentKey { @@ -174,16 +176,6 @@ enum { }; -enum { - vcbMaxNam = 27, /* volumes currently have a 27 byte max name length*/ - /* VCB flags*/ - vcbManualEjectMask = 0x0001, /* bit 0 manual-eject bit: set if volume is in a manual-eject drive*/ - vcbFlushCriticalInfoMask = 0x0002, /* bit 1 critical info bit: set if critical MDB information needs to flush*/ - /* IoParam->ioVAtrb*/ - kDefaultVolumeMask = 0x0020, - kFilesOpenMask = 0x0040 -}; - /* Universal catalog name*/ @@ -197,8 +189,8 @@ typedef union CatalogName CatalogName; /* * MacOS accessor routines */ -#define GetFileControlBlock(fref) ((FCB *)((fref)->v_data)) -#define GetFileRefNumFromFCB(filePtr) ((filePtr)->h_vp) +#define GetFileControlBlock(fref) VTOF((fref)) +#define GetFileRefNumFromFCB(fcb) FTOV((fcb)) /* The following macro marks a VCB as dirty by setting the upper 8 bits of the flags*/ @@ -216,8 +208,8 @@ IsVCBDirty (ExtendedVCB *vcb); #define VCB_LOCK(vcb) simple_lock(&vcb->vcbSimpleLock) #define VCB_UNLOCK(vcb) simple_unlock(&vcb->vcbSimpleLock) -#define MarkVCBDirty(vcb) { VCB_LOCK((vcb)); ((vcb)->vcbFlags |= 0xFF00); VCB_UNLOCK((vcb)); } -#define MarkVCBClean(vcb) { VCB_LOCK((vcb)); ((vcb)->vcbFlags &= 0x00FF); VCB_UNLOCK((vcb)); } +#define MarkVCBDirty(vcb) { ((vcb)->vcbFlags |= 0xFF00); } +#define MarkVCBClean(vcb) { ((vcb)->vcbFlags &= 0x00FF); } #define IsVCBDirty(vcb) ((Boolean) ((vcb->vcbFlags & 0xFF00) != 0)) @@ -242,62 +234,6 @@ ExitOnError (OSErr result); /* Catalog Manager Routines (IPI)*/ -EXTERN_API_C( OSErr ) -CreateCatalogNode (ExtendedVCB * volume, - HFSCatalogNodeID parentID, - ConstUTF8Param name, - UInt32 nodeType, - HFSCatalogNodeID * catalogNodeID, - UInt32 * catalogHint, - UInt32 teHint); - -EXTERN_API_C( OSErr ) -DeleteCatalogNode (ExtendedVCB * volume, - HFSCatalogNodeID parentID, - ConstUTF8Param name, - UInt32 hint); - -EXTERN_API_C( OSErr ) -GetCatalogNode (ExtendedVCB * volume, - HFSCatalogNodeID parentID, - ConstUTF8Param name, - UInt32 length, - UInt32 hint, - CatalogNodeData * nodeData, - UInt32 * newHint); - -EXTERN_API_C( OSErr ) -GetCatalogOffspring (ExtendedVCB * volume, - HFSCatalogNodeID folderID, - UInt16 index, - CatalogNodeData * nodeData, - HFSCatalogNodeID * nodeID, - SInt16 * nodeType); - -EXTERN_API_C( OSErr ) -MoveRenameCatalogNode (ExtendedVCB * volume, - HFSCatalogNodeID srcParentID, - ConstUTF8Param srcName, - UInt32 srcHint, - HFSCatalogNodeID dstParentID, - ConstUTF8Param dstName, - UInt32 * newHint, - UInt32 teHint); - -EXTERN_API_C( OSErr ) -UpdateCatalogNode (ExtendedVCB * volume, - HFSCatalogNodeID parentID, - ConstUTF8Param name, - UInt32 catalogHint, - const CatalogNodeData * nodeData); - -EXTERN_API_C( OSErr ) -CreateFileIDRef (ExtendedVCB * volume, - HFSCatalogNodeID parentID, - ConstUTF8Param name, - UInt32 hint, - HFSCatalogNodeID * threadID); - EXTERN_API_C( OSErr ) ExchangeFileIDs (ExtendedVCB * volume, ConstUTF8Param srcName, @@ -307,13 +243,6 @@ ExchangeFileIDs (ExtendedVCB * volume, UInt32 srcHint, UInt32 destHint ); -EXTERN_API_C( OSErr ) -LinkCatalogNode (ExtendedVCB * volume, - HFSCatalogNodeID parentID, - ConstUTF8Param name, - HFSCatalogNodeID linkParentID, - ConstUTF8Param linkName); - EXTERN_API_C( SInt32 ) CompareCatalogKeys (HFSCatalogKey * searchKey, HFSCatalogKey * trialKey); @@ -329,31 +258,6 @@ EXTERN_API_C( void ) InvalidateCatalogCache (ExtendedVCB * volume); -/* GenericMRUCache Routines*/ -EXTERN_API_C( OSErr ) -InitMRUCache (UInt32 bufferSize, - UInt32 numCacheBlocks, - Ptr * cachePtr); - -EXTERN_API_C( OSErr ) -DisposeMRUCache (Ptr cachePtr); - -EXTERN_API_C( void ) -TrashMRUCache (Ptr cachePtr); - -EXTERN_API_C( OSErr ) -GetMRUCacheBlock (UInt32 key, - Ptr cachePtr, - Ptr * buffer); - -EXTERN_API_C( void ) -InvalidateMRUCacheBlock (Ptr cachePtr, - Ptr buffer); - -EXTERN_API_C( void ) -InsertMRUCacheBlock (Ptr cachePtr, - UInt32 key, - Ptr buffer); /* BTree Manager Routines*/ @@ -369,17 +273,6 @@ SearchBTreeRecord (FileReference refNum, UInt16 * dataSize, UInt32 * newHint); -EXTERN_API_C( OSErr ) -InsertBTreeRecord (FileReference refNum, - void * key, - void * data, - UInt16 dataSize, - UInt32 * newHint); - -EXTERN_API_C( OSErr ) -DeleteBTreeRecord (FileReference refNum, - void * key); - EXTERN_API_C( OSErr ) ReplaceBTreeRecord (FileReference refNum, const void * key, @@ -420,12 +313,6 @@ EXTERN_API_C( SInt32 ) CompareExtentKeysPlus (const HFSPlusExtentKey *searchKey, const HFSPlusExtentKey *trialKey); -EXTERN_API_C( OSErr ) -DeleteFile (ExtendedVCB * vcb, - HFSCatalogNodeID parDirID, - ConstUTF8Param catalogName, - UInt32 catalogHint); - EXTERN_API_C( OSErr ) TruncateFileC (ExtendedVCB * vcb, FCB * fcb, @@ -457,10 +344,6 @@ NodesAreContiguous (ExtendedVCB * vcb, /* Utility routines*/ -EXTERN_API_C( void ) -ClearMemory (void * start, - UInt32 length); - EXTERN_API_C( OSErr ) VolumeWritable (ExtendedVCB * vcb); @@ -469,10 +352,6 @@ VolumeWritable (ExtendedVCB * vcb); EXTERN_API_C( UInt32 ) GetTimeUTC (void); -/* Get the current local time*/ -EXTERN_API_C( UInt32 ) -GetTimeLocal (Boolean forHFS); - EXTERN_API_C( UInt32 ) LocalToUTC (UInt32 localTime); @@ -480,14 +359,6 @@ EXTERN_API_C( UInt32 ) UTCToLocal (UInt32 utcTime); -/* Volumes routines*/ -EXTERN_API_C( OSErr ) -FlushVolumeControlBlock (ExtendedVCB * vcb); - -EXTERN_API_C( OSErr ) -ValidVolumeHeader (HFSPlusVolumeHeader * volumeHeader); - - #if PRAGMA_STRUCT_ALIGN #pragma options align=reset #elif PRAGMA_STRUCT_PACKPUSH @@ -506,5 +377,7 @@ ValidVolumeHeader (HFSPlusVolumeHeader * volumeHeader); } #endif +#endif /* __APPLE_API_PRIVATE */ +#endif /* KERNEL */ #endif /* __FILEMGRINTERNAL__ */ diff --git a/bsd/hfs/hfscommon/headers/HFSInstrumentation.h b/bsd/hfs/hfscommon/headers/HFSInstrumentation.h deleted file mode 100644 index 5cdc2de20..000000000 --- a/bsd/hfs/hfscommon/headers/HFSInstrumentation.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - File: HFSInstrumentation.h - - Contains: xxx put contents here xxx - - Version: xxx put version here xxx - - Copyright: © 1997 by Apple Computer, Inc., all rights reserved. - - File Ownership: - - DRI: xxx put dri here xxx - - Other Contact: xxx put other contact here xxx - - Technology: xxx put technology here xxx - - Writers: - - (DSH) Deric Horn - (djb) Don Brady - - Change History (most recent first): - - 10/1/97 djb Add kGetCatalogIterator - 9/4/97 djb Add kTraceRelString, kHeuristicHint. - 7/24/97 djb Add summary traces for GetNode, RelNode, and BasicIO. - 7/21/97 djb Redefine LogStartTime/LogEndTime macros. - 7/16/97 DSH FilesInternal.i renamed FileMgrInternal.i to avoid name - collision - 5/9/97 djb first checked in -*/ - -#include "../../hfs_macos_defs.h" -#include "FileMgrInternal.h" - - -// -// Instrumentation summary trace indicies -// -enum { - // Unicode routines - kTraceUnicodeToPString, - kTracePStringToUnicode, - kTraceUnicodeCompare, - - kTraceRelString, - - // B-tree routines - kTraceOpenBTree, - kTraceCloseBTree, - kTraceFlushBTree, - kTraceSearchBTree, - kTraceGetBTreeRecord, - kTraceInsertBTreeRecord, - kTraceDeleteBTreeRecord, - kTraceReplaceBTreeRecord, - - // Misc routines - kTraceMapFileBlock, - kTraceBlockAllocate, - - kTraceGetNode, - kTraceReleaseNode, - kTraceBasicIO, - kTraceFSRead, - kHeuristicHint, - kGetCatalogIterator, - - - kSummaryTraceRefs // number of summary trace references -}; - - -void STLogStartTime(UInt32 selector); -void STLogEndTime(UInt32 selector, OSErr error); - - -/* -MACRO - LogStartTime(selector) - -DESCRIPTION - If summary traces are enabled then LogStartTime will record the starting time for - the routine associated with the selector. Otherwise LogStartTime does nothing. - -*/ - -#if hasSummaryTraces - -#define LogStartTime(selector) STLogStartTime( (selector) ) - -#else - -#define LogStartTime(selector) ((void) 0) - -#endif - - - -/* -MACRO - LogEndTime(selector, error) - -DESCRIPTION - If summary traces are enabled then InsLogEndTime will record the ending time for - the routine associated with the selector. Otherwise LogEndTime does nothing. - -*/ - -#if hasSummaryTraces - -#define LogEndTime(selector,error) STLogEndTime( (selector), (error) ) - -#else - -#define LogEndTime(selector,error) ((void) 0) - -#endif diff --git a/bsd/hfs/hfscommon/headers/HFSUnicodeWrappers.h b/bsd/hfs/hfscommon/headers/HFSUnicodeWrappers.h index f32f517ea..56a7e4bdd 100644 --- a/bsd/hfs/hfscommon/headers/HFSUnicodeWrappers.h +++ b/bsd/hfs/hfscommon/headers/HFSUnicodeWrappers.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -65,29 +65,16 @@ 12/12/96 msd first checked in */ +#ifndef _HFSUNICODEWRAPPERS_ +#define _HFSUNICODEWRAPPERS_ -#include "../../hfs_macos_defs.h" -#include "../../hfs_format.h" - -// Encoding vs. Index -// -// For runtime table lookups and for the volume encoding bitmap we -// need to map some encodings to keep them in a reasonable range. -// - -enum { - kIndexMacUkrainian = 48, // MacUkrainian encoding is 152 - kIndexMacFarsi = 49 // MacFarsi encoding is 140 -}; +#include -#define MapEncodingToIndex(e) \ - ( (e) < 48 ? (e) : ( (e) == kTextEncodingMacUkrainian ? kIndexMacUkrainian : ( (e) == kTextEncodingMacFarsi ? kIndexMacFarsi : kTextEncodingMacRoman) ) ) +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE -#define MapIndexToEncoding(i) \ - ( (i) == kIndexMacFarsi ? kTextEncodingMacFarsi : ( (i) == kIndexMacUkrainian ? kTextEncodingMacUkrainian : (i) ) ) - -#define ValidMacEncoding(e) \ - ( ((e) < 39) || ((e) == kTextEncodingMacFarsi) || ((e) == kTextEncodingMacUkrainian) ) +#include "../../hfs_macos_defs.h" +#include "../../hfs_format.h" extern OSErr ConvertUnicodeToUTF8Mangled ( ByteCount srcLen, @@ -119,3 +106,6 @@ extern SInt32 FastRelString( ConstStr255Param str1, ConstStr255Param str2 ); extern HFSCatalogNodeID GetEmbeddedFileID( ConstStr31Param filename, UInt32 length, UInt32 *prefixLength ); +#endif /* __APPLE_API_PRIVATE */ +#endif /* KERNEL */ +#endif /* _HFSUNICODEWRAPPERS_ */ diff --git a/bsd/hfs/hfscommon/headers/Makefile b/bsd/hfs/hfscommon/headers/Makefile deleted file mode 100644 index 81ad2b9cb..000000000 --- a/bsd/hfs/hfscommon/headers/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -export MakeInc_cmd=${SRCROOT}/makedefs/MakeInc.cmd -export MakeInc_def=${SRCROOT}/makedefs/MakeInc.def -export MakeInc_rule=${SRCROOT}/makedefs/MakeInc.rule -export MakeInc_dir=${SRCROOT}/makedefs/MakeInc.dir - - -include $(MakeInc_cmd) -include $(MakeInc_def) - -INSTINC_SUBDIRS = \ - -INSTINC_SUBDIRS_PPC = \ - -INSTINC_SUBDIRS_I386 = \ - -EXPINC_SUBDIRS = \ - -EXPINC_SUBDIRS_PPC = \ - -EXPINC_SUBDIRS_I386 = \ - -DATAFILES = \ - BTreesInternal.h BTreesPrivate.h CatalogPrivate.h \ - FileMgrInternal.h - -INSTALL_MI_LIST = ${DATAFILES} - -INSTALL_MI_DIR = hfs/hfscommon/headers - -EXPORT_MI_LIST = \ - -EXPORT_MI_DIR = \ - - -include $(MakeInc_rule) -include $(MakeInc_dir) - - diff --git a/bsd/hfs/rangelist.h b/bsd/hfs/rangelist.h index f7c31ecf1..86b4c0c06 100644 --- a/bsd/hfs/rangelist.h +++ b/bsd/hfs/rangelist.h @@ -19,7 +19,13 @@ * * @APPLE_LICENSE_HEADER_END@ */ +#ifndef _HFS_RANGELIST_H_ +#define _HFS_RANGELIST_H_ +#include + +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE #include #include @@ -51,3 +57,7 @@ enum rl_overlaptype rl_scan(struct rl_head *rangelist, off_t end, struct rl_entry **overlap); __END_DECLS + +#endif /* __APPLE_API_PRIVATE */ +#endif /* KERNEL */ +#endif /* ! _HFS_RANGELIST_H_ */ diff --git a/bsd/i386/Makefile b/bsd/i386/Makefile index b300ae639..e3f4901de 100644 --- a/bsd/i386/Makefile +++ b/bsd/i386/Makefile @@ -10,7 +10,7 @@ include $(MakeInc_def) DATAFILES = \ cpu.h disklabel.h endian.h exec.h label_t.h param.h \ profile.h psl.h ptrace.h reboot.h setjmp.h signal.h \ - spl.h table.h types.h user.h vmparam.h + spl.h table.h types.h ucontext.h user.h vmparam.h INSTALL_MD_LIST = ${DATAFILES} diff --git a/bsd/i386/cpu.h b/bsd/i386/cpu.h index 65270f0ae..fbace41fc 100644 --- a/bsd/i386/cpu.h +++ b/bsd/i386/cpu.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -27,6 +27,10 @@ #ifndef _BSD_I386_CPU_H_ #define _BSD_I386_CPU_H_ +#include + +#ifdef __APPLE_API_OBSOLETE #define cpu_number() (0) +#endif /* __APPLE_API_OBSOLETE */ #endif /* _BSD_I386_CPU_H_ */ diff --git a/bsd/i386/disklabel.h b/bsd/i386/disklabel.h index e01222824..97cab07c3 100644 --- a/bsd/i386/disklabel.h +++ b/bsd/i386/disklabel.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,6 +22,9 @@ #ifndef _MACHINE_DISKLABEL_H_ #define _MACHINE_DISKLABEL_H_ +#include + +#ifdef __APPLE_API_OBSOLETE #define LABELSECTOR (1024 / DEV_BSIZE) /* sector containing label */ #define LABELOFFSET 0 /* offset of label in sector */ #define MAXPARTITIONS 8 /* number of partitions */ @@ -31,5 +34,6 @@ struct cpu_disklabel { int cd_dummy; /* must have one element. */ }; +#endif /* __APPLE_API_OBSOLETE */ #endif /* _MACHINE_DISKLABEL_H_ */ diff --git a/bsd/i386/endian.h b/bsd/i386/endian.h index 1403d717b..2d9a1d3a1 100644 --- a/bsd/i386/endian.h +++ b/bsd/i386/endian.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * diff --git a/bsd/i386/exec.h b/bsd/i386/exec.h index 677ee5d80..237ecd5fc 100644 --- a/bsd/i386/exec.h +++ b/bsd/i386/exec.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -54,6 +54,13 @@ * @(#)exec.h 8.1 (Berkeley) 6/11/93 */ +#ifndef _BSD_I386_EXEC_H_ +#define _BSD_I386_EXEC_H_ + + +#include + +#ifdef __APPLE_API_OBSOLETE /* Size of a page in an object file. */ #define __LDPGSZ 4096 @@ -109,3 +116,6 @@ struct exec { */ #define PS_STRINGS \ ((struct ps_strings *)(USRSTACK - sizeof(struct ps_strings))) +#endif /* __APPLE_API_OBSOLETE */ + +#endif /* _BSD_I386_EXEC_H_ */ diff --git a/bsd/i386/label_t.h b/bsd/i386/label_t.h index b33aa29ef..f47065aff 100644 --- a/bsd/i386/label_t.h +++ b/bsd/i386/label_t.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -24,17 +24,17 @@ * * Intel386 Family: For setjmp/longjmp (kernel version). * - * HISTORY - * - * 20 April 1992 ? at NeXT - * Created. */ #ifndef _BSD_I386_LABEL_T_H_ #define _BSD_I386_LABEL_T_H_ +#include + +#ifdef __APPLE_API_OBSOLETE typedef struct label_t { int val[14]; } label_t; +#endif /* __APPLE_API_OBSOLETE */ #endif /* _BSD_I386_LABEL_T_H_ */ diff --git a/bsd/i386/param.h b/bsd/i386/param.h index 32ead8a3e..f5e43d3f6 100644 --- a/bsd/i386/param.h +++ b/bsd/i386/param.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * diff --git a/bsd/i386/profile.h b/bsd/i386/profile.h index 68370a2eb..c3dd8dea3 100644 --- a/bsd/i386/profile.h +++ b/bsd/i386/profile.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,15 +22,16 @@ /* * Copyright (c) 1997, Apple Computer, Inc. All rights reserved. * - * History : - * 29-Sep-1997 Umesh Vaishampayan - * Created. */ #ifndef _BSD_I386_PROFILE_H_ #define _BSD_I386_PROFILE_H_ +#include + #ifdef KERNEL +#ifdef __APPLE_API_UNSTABLE + /* * Block interrupts during mcount so that those interrupts can also be * counted (as soon as we get done with the current counting). On the @@ -42,6 +43,8 @@ #define MCOUNT_INIT #define MCOUNT_ENTER /* s = splhigh(); */ /* XXX TODO */ #define MCOUNT_EXIT /* (void) splx(s); */ /* XXX TODO */ + +#endif /* __APPLE_API_UNSTABLE */ #endif /* KERNEL */ #endif /* _BSD_I386_PROFILE_H_ */ diff --git a/bsd/i386/psl.h b/bsd/i386/psl.h index 57ad9145f..bea431e18 100644 --- a/bsd/i386/psl.h +++ b/bsd/i386/psl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -24,10 +24,6 @@ * * Intel386 Family: Definition of eflags register. * - * HISTORY - * - * 7 April 1992 ? at NeXT - * Created. */ #if KERNEL_PRIVATE diff --git a/bsd/i386/ptrace.h b/bsd/i386/ptrace.h index c27381154..32cbfbbb4 100644 --- a/bsd/i386/ptrace.h +++ b/bsd/i386/ptrace.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * diff --git a/bsd/i386/reboot.h b/bsd/i386/reboot.h index 53088b120..dad563257 100644 --- a/bsd/i386/reboot.h +++ b/bsd/i386/reboot.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -19,19 +19,6 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* - * File: next/reboot.h - * Author: Avadis Tevanian, Jr. - * - * NeXT specific reboot flags. - * - * HISTORY - * 28-Feb-90 John Seamons (jks) at NeXT - * Added RB_COMMAND flag that allows a specific reboot command to be used. - * - * 06-Jul-88 Avadis Tevanian (avie) at NeXT, Inc. - * Created. - */ #ifndef _BSD_I386_REBOOT_H_ #define _BSD_I386_REBOOT_H_ @@ -40,7 +27,10 @@ * Empty file (publicly) */ +#include + #ifdef KERNEL_PRIVATE +#ifdef __APPLE_API_PRIVATE /* * Use most significant 16 bits to avoid collisions with @@ -56,6 +46,7 @@ #define RB_BOOTDOS 0x00800000 /* reboot into DOS */ #define RB_PRETTY 0x01000000 /* shutdown with pretty graphics */ +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL_PRIVATE */ #endif /* _BSD_I386_REBOOT_H_ */ diff --git a/bsd/i386/reg.h b/bsd/i386/reg.h index aea69bfca..35bb1130d 100644 --- a/bsd/i386/reg.h +++ b/bsd/i386/reg.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -24,10 +24,6 @@ * * Intel386 Family: User registers for U**X. * - * HISTORY - * - * 20 April 1992 ? at NeXT - * Created. */ #ifdef KERNEL_PRIVATE diff --git a/bsd/i386/setjmp.h b/bsd/i386/setjmp.h index 2ce10d1cb..b2584eb47 100644 --- a/bsd/i386/setjmp.h +++ b/bsd/i386/setjmp.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * diff --git a/bsd/i386/signal.h b/bsd/i386/signal.h index 6f079937b..3c73b16a9 100644 --- a/bsd/i386/signal.h +++ b/bsd/i386/signal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,15 +22,14 @@ /* * Copyright (c) 1992 NeXT Computer, Inc. * - * HISTORY - * - * 8 April 1992 ? at NeXT - * Created. */ #ifndef _i386_SIGNAL_ #define _i386_SIGNAL_ 1 +#include + +#ifdef __APPLE_API_OBSOLETE typedef int sig_atomic_t; /* @@ -61,4 +60,7 @@ struct sigcontext { unsigned int sc_gs; }; +#endif /* __APPLE_API_OBSOLETE */ + #endif /* _i386_SIGNAL_ */ + diff --git a/bsd/i386/spl.h b/bsd/i386/spl.h index 3a01fb94f..0f6be5565 100644 --- a/bsd/i386/spl.h +++ b/bsd/i386/spl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * diff --git a/bsd/i386/table.h b/bsd/i386/table.h index eb3e811b5..f55484ddc 100644 --- a/bsd/i386/table.h +++ b/bsd/i386/table.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * diff --git a/bsd/i386/types.h b/bsd/i386/types.h index 10a5646ad..f370e9bf1 100644 --- a/bsd/i386/types.h +++ b/bsd/i386/types.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -79,5 +79,8 @@ typedef int32_t register_t; typedef long int intptr_t; typedef unsigned long int uintptr_t; + +#define __offsetof(type, field) ((size_t)(&((type *)0)->field)) + #endif /* __ASSEMBLER__ */ #endif /* _MACHTYPES_H_ */ diff --git a/bsd/i386/ucontext.h b/bsd/i386/ucontext.h new file mode 100644 index 000000000..0256c0f53 --- /dev/null +++ b/bsd/i386/ucontext.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#ifndef _I386_UCONTEXT_H_ +#define _I386_UCONTEXT_H_ + + +#include +#include +#include + + +#ifdef __APPLE_API_UNSTABLE +/* WARNING: THIS WILL CHANGE; DO NOT COUNT ON THIS */ +/* Needs to be finalized as to what it should contain */ +struct mcontext { + struct sigcontext sc; +}; + +#define I386_MCONTEXT_SIZE sizeof(struct mcontext) + +typedef struct mcontext * mcontext_t; + +#endif /* __APPLE_API_UNSTABLE */ + +#endif /* _I386_UCONTEXT_H_ */ diff --git a/bsd/i386/user.h b/bsd/i386/user.h index 3152f5cbc..edc737230 100644 --- a/bsd/i386/user.h +++ b/bsd/i386/user.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * diff --git a/bsd/i386/vmparam.h b/bsd/i386/vmparam.h index 8c3c919c1..a1c9daeec 100644 --- a/bsd/i386/vmparam.h +++ b/bsd/i386/vmparam.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -19,21 +19,6 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* - * HISTORY - * 16-Jan-98 Wilfredo Sanchez (wsanchez@apple.com) - * Remove #ifdef KERNEL_PRiVATE around USRSTACK to match ppc version. - * Sendmail needs it. - * - * 05-Sep-97 Umesh Vaishampayan (umeshv@apple.com) - * Made MAXSSIZ a finite value. - * - * 05-Mar-89 Avadis Tevanian, Jr. (avie) at NeXT - * Make MAXDSIZ infinity. - * - * 12-Aug-87 John Seamons (jks) at NeXT - * Ported to NeXT. - */ #ifndef _BSD_I386_VMPARAM_H_ #define _BSD_I386_VMPARAM_H_ 1 diff --git a/bsd/include/Makefile b/bsd/include/Makefile deleted file mode 100644 index ca571a43d..000000000 --- a/bsd/include/Makefile +++ /dev/null @@ -1,44 +0,0 @@ -export MakeInc_cmd=${SRCROOT}/makedefs/MakeInc.cmd -export MakeInc_def=${SRCROOT}/makedefs/MakeInc.def -export MakeInc_rule=${SRCROOT}/makedefs/MakeInc.rule -export MakeInc_dir=${SRCROOT}/makedefs/MakeInc.dir - - -include $(MakeInc_cmd) -include $(MakeInc_def) - -INSTINC_SUBDIRS = \ - arpa \ - protocols - -INSTINC_SUBDIRS_PPC = \ - -INSTINC_SUBDIRS_I386 = \ - -EXPINC_SUBDIRS = \ - -EXPINC_SUBDIRS_PPC = \ - -EXPINC_SUBDIRS_I386 = \ - -DATAFILES = \ - ar.h bitstring.h c.h ctype.h db.h dirent.h disktab.h err.h errno.h \ - fcntl.h fnmatch.h fsproperties.h fstab.h fts.h glob.h grp.h kvm.h limits.h locale.h \ - math.h memory.h mpool.h ndbm.h netdb.h nlist.h paths.h pwd.h ranlib.h \ - regex.h regexp.h rune.h runetype.h setjmp.h semaphore.h sgtty.h signal.h stab.h \ - stddef.h stdio.h stdlib.h string.h strings.h struct.h sysexits.h syslog.h \ - tar.h termios.h time.h ttyent.h tzfile.h unistd.h util.h utime.h utmp.h vis.h - -INSTALL_MI_LIST = ${DATAFILES} - -INSTALL_MI_DIR = - -EXPORT_MI_LIST = stddef.h - -EXPORT_MI_DIR = - - -include $(MakeInc_rule) -include $(MakeInc_dir) - - diff --git a/bsd/include/ar.h b/bsd/include/ar.h deleted file mode 100644 index def1c4320..000000000 --- a/bsd/include/ar.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, Inc. - * - * This code is derived from software contributed to Berkeley by - * Hugh Smith 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. - * - * @(#)ar.h 8.2 (Berkeley) 1/21/94 - */ - -#ifndef _AR_H_ -#define _AR_H_ - -/* Pre-4BSD archives had these magic numbers in them. */ -#define OARMAG1 0177555 -#define OARMAG2 0177545 - -#define ARMAG "!\n" /* ar "magic number" */ -#define SARMAG 8 /* strlen(ARMAG); */ - -#define AR_EFMT1 "#1/" /* extended format #1 */ - -struct ar_hdr { - char ar_name[16]; /* name */ - char ar_date[12]; /* modification time */ - char ar_uid[6]; /* user id */ - char ar_gid[6]; /* group id */ - char ar_mode[8]; /* octal file permissions */ - char ar_size[10]; /* size in bytes */ -#define ARFMAG "`\n" - char ar_fmag[2]; /* consistency check */ -}; - -#endif /* !_AR_H_ */ diff --git a/bsd/include/arpa/Makefile b/bsd/include/arpa/Makefile deleted file mode 100644 index 473ffe8ec..000000000 --- a/bsd/include/arpa/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -export MakeInc_cmd=${SRCROOT}/makedefs/MakeInc.cmd -export MakeInc_def=${SRCROOT}/makedefs/MakeInc.def -export MakeInc_rule=${SRCROOT}/makedefs/MakeInc.rule -export MakeInc_dir=${SRCROOT}/makedefs/MakeInc.dir - - -include $(MakeInc_cmd) -include $(MakeInc_def) - -INSTINC_SUBDIRS = \ - -INSTINC_SUBDIRS_PPC = \ - -INSTINC_SUBDIRS_I386 = \ - -EXPINC_SUBDIRS = \ - -EXPINC_SUBDIRS_PPC = \ - -EXPINC_SUBDIRS_I386 = \ - -DATAFILES = \ - ftp.h inet.h telnet.h tftp.h - -INSTALL_MI_LIST = ${DATAFILES} - -INSTALL_MI_DIR = arpa - -EXPORT_MI_LIST = - -EXPORT_MI_DIR = - - -include $(MakeInc_rule) -include $(MakeInc_dir) - - diff --git a/bsd/include/arpa/ftp.h b/bsd/include/arpa/ftp.h deleted file mode 100644 index 90b425b79..000000000 --- a/bsd/include/arpa/ftp.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1983, 1989, 1993 - * 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. - * - * @(#)ftp.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _FTP_H_ -#define _FTP_H_ - -/* Definitions for FTP; see RFC-765. */ - -/* - * Reply codes. - */ -#define PRELIM 1 /* positive preliminary */ -#define COMPLETE 2 /* positive completion */ -#define CONTINUE 3 /* positive intermediate */ -#define TRANSIENT 4 /* transient negative completion */ -#define ERROR 5 /* permanent negative completion */ - -/* - * Type codes - */ -#define TYPE_A 1 /* ASCII */ -#define TYPE_E 2 /* EBCDIC */ -#define TYPE_I 3 /* image */ -#define TYPE_L 4 /* local byte size */ - -#ifdef FTP_NAMES -char *typenames[] = {"0", "ASCII", "EBCDIC", "Image", "Local" }; -#endif - -/* - * Form codes - */ -#define FORM_N 1 /* non-print */ -#define FORM_T 2 /* telnet format effectors */ -#define FORM_C 3 /* carriage control (ASA) */ -#ifdef FTP_NAMES -char *formnames[] = {"0", "Nonprint", "Telnet", "Carriage-control" }; -#endif - -/* - * Structure codes - */ -#define STRU_F 1 /* file (no record structure) */ -#define STRU_R 2 /* record structure */ -#define STRU_P 3 /* page structure */ -#ifdef FTP_NAMES -char *strunames[] = {"0", "File", "Record", "Page" }; -#endif - -/* - * Mode types - */ -#define MODE_S 1 /* stream */ -#define MODE_B 2 /* block */ -#define MODE_C 3 /* compressed */ -#ifdef FTP_NAMES -char *modenames[] = {"0", "Stream", "Block", "Compressed" }; -#endif - -/* - * Record Tokens - */ -#define REC_ESC '\377' /* Record-mode Escape */ -#define REC_EOR '\001' /* Record-mode End-of-Record */ -#define REC_EOF '\002' /* Record-mode End-of-File */ - -/* - * Block Header - */ -#define BLK_EOR 0x80 /* Block is End-of-Record */ -#define BLK_EOF 0x40 /* Block is End-of-File */ -#define BLK_ERRORS 0x20 /* Block is suspected of containing errors */ -#define BLK_RESTART 0x10 /* Block is Restart Marker */ - -#define BLK_BYTECOUNT 2 /* Bytes in this block */ - -#endif /* !_FTP_H_ */ diff --git a/bsd/include/arpa/inet.h b/bsd/include/arpa/inet.h deleted file mode 100644 index 48e2754de..000000000 --- a/bsd/include/arpa/inet.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1983, 1993 - * 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. - * - * @(#)inet.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _INET_H_ -#define _INET_H_ - -/* External definitions for functions in inet(3) */ - -#include - -__BEGIN_DECLS -unsigned long inet_addr __P((const char *)); -int inet_aton __P((const char *, struct in_addr *)); -unsigned long inet_lnaof __P((struct in_addr)); -struct in_addr inet_makeaddr __P((u_long , u_long)); -unsigned long inet_netof __P((struct in_addr)); -unsigned long inet_network __P((const char *)); -char *inet_ntoa __P((struct in_addr)); -__END_DECLS - -#endif /* !_INET_H_ */ diff --git a/bsd/include/arpa/nameser.h b/bsd/include/arpa/nameser.h deleted file mode 100644 index 97d292155..000000000 --- a/bsd/include/arpa/nameser.h +++ /dev/null @@ -1,448 +0,0 @@ -/* - * Copyright (c) 1983, 1989, 1993 - * 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. - */ - -/* - * Copyright (c) 1996 by Internet Software Consortium. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS - * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE - * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - */ - -/* - * From: Id: nameser.h,v 8.16 1998/02/06 00:35:58 halley Exp - * $FreeBSD: src/include/arpa/nameser.h,v 1.12.2.1 1999/08/29 14:39:00 peter Exp $ - */ - -#ifndef _ARPA_NAMESER_H_ -#define _ARPA_NAMESER_H_ - -#define BIND_4_COMPAT - -#include -#include - -/* - * revision information. this is the release date in YYYYMMDD format. - * it can change every day so the right thing to do with it is use it - * in preprocessor commands such as "#if (__NAMESER > 19931104)". do not - * compare for equality; rather, use it to determine whether your libnameser.a - * is new enough to contain a certain feature. - */ - -/* XXXRTH I made this bigger than __BIND in 4.9.5 T6B */ -#define __NAMESER 19961001 /* New interface version stamp. */ - -/* - * Define constants based on RFC 883, RFC 1034, RFC 1035 - */ -#define NS_PACKETSZ 512 /* maximum packet size */ -#define NS_MAXDNAME 1025 /* maximum domain name */ -#define NS_MAXCDNAME 255 /* maximum compressed domain name */ -#define NS_MAXLABEL 63 /* maximum length of domain label */ -#define NS_HFIXEDSZ 12 /* #/bytes of fixed data in header */ -#define NS_QFIXEDSZ 4 /* #/bytes of fixed data in query */ -#define NS_RRFIXEDSZ 10 /* #/bytes of fixed data in r record */ -#define NS_INT32SZ 4 /* #/bytes of data in a u_int32_t */ -#define NS_INT16SZ 2 /* #/bytes of data in a u_int16_t */ -#define NS_INT8SZ 1 /* #/bytes of data in a u_int8_t */ -#define NS_INADDRSZ 4 /* IPv4 T_A */ -#define NS_IN6ADDRSZ 16 /* IPv6 T_AAAA */ -#define NS_CMPRSFLGS 0xc0 /* Flag bits indicating name compression. */ -#define NS_DEFAULTPORT 53 /* For both TCP and UDP. */ - -/* - * These can be expanded with synonyms, just keep ns_parse.c:ns_parserecord() - * in synch with it. - */ -typedef enum __ns_sect { - ns_s_qd = 0, /* Query: Question. */ - ns_s_zn = 0, /* Update: Zone. */ - ns_s_an = 1, /* Query: Answer. */ - ns_s_pr = 1, /* Update: Prerequisites. */ - ns_s_ns = 2, /* Query: Name servers. */ - ns_s_ud = 2, /* Update: Update. */ - ns_s_ar = 3, /* Query|Update: Additional records. */ - ns_s_max = 4 -} ns_sect; - -/* - * This is a message handle. It is caller allocated and has no dynamic data. - * This structure is intended to be opaque to all but ns_parse.c, thus the - * leading _'s on the member names. Use the accessor functions, not the _'s. - */ -typedef struct __ns_msg { - const u_char *_msg, *_eom; - u_int16_t _id, _flags, _counts[ns_s_max]; - const u_char *_sections[ns_s_max]; - ns_sect _sect; - int _rrnum; - const u_char *_ptr; -} ns_msg; - -/* Private data structure - do not use from outside library. */ -struct _ns_flagdata { int mask, shift; }; -extern struct _ns_flagdata _ns_flagdata[]; - -/* Accessor macros - this is part of the public interface. */ -#define ns_msg_getflag(handle, flag) ( \ - ((handle)._flags & _ns_flagdata[flag].mask) \ - >> _ns_flagdata[flag].shift \ - ) -#define ns_msg_id(handle) ((handle)._id + 0) -#define ns_msg_base(handle) ((handle)._msg + 0) -#define ns_msg_end(handle) ((handle)._eom + 0) -#define ns_msg_size(handle) ((handle)._eom - (handle)._msg) -#define ns_msg_count(handle, section) ((handle)._counts[section] + 0) - -/* - * This is a parsed record. It is caller allocated and has no dynamic data. - */ -typedef struct __ns_rr { - char name[NS_MAXDNAME]; /* XXX need to malloc */ - u_int16_t type; - u_int16_t class; - u_int32_t ttl; - u_int16_t rdlength; - const u_char *rdata; -} ns_rr; - -/* Accessor macros - this is part of the public interface. */ -#define ns_rr_name(rr) (((rr).name[0] != '\0') ? (rr).name : ".") -#define ns_rr_type(rr) ((rr).type + 0) -#define ns_rr_class(rr) ((rr).class + 0) -#define ns_rr_ttl(rr) ((rr).ttl + 0) -#define ns_rr_rdlen(rr) ((rr).rdlength + 0) -#define ns_rr_rdata(rr) ((rr).rdata + 0) - -/* - * These don't have to be in the same order as in the packet flags word, - * and they can even overlap in some cases, but they will need to be kept - * in synch with ns_parse.c:ns_flagdata[]. - */ -typedef enum __ns_flag { - ns_f_qr, /* Question/Response. */ - ns_f_opcode, /* Operation code. */ - ns_f_aa, /* Authoritative Answer. */ - ns_f_tc, /* Truncation occurred. */ - ns_f_rd, /* Recursion Desired. */ - ns_f_ra, /* Recursion Available. */ - ns_f_z, /* MBZ. */ - ns_f_ad, /* Authentic Data (DNSSEC). */ - ns_f_cd, /* Checking Disabled (DNSSEC). */ - ns_f_rcode, /* Response code. */ - ns_f_max -} ns_flag; - -/* - * Currently defined opcodes. - */ -typedef enum __ns_opcode { - ns_o_query = 0, /* Standard query. */ - ns_o_iquery = 1, /* Inverse query (deprecated/unsupported). */ - ns_o_status = 2, /* Name server status query (unsupported). */ - /* Opcode 3 is undefined/reserved. */ - ns_o_notify = 4, /* Zone change notification. */ - ns_o_update = 5, /* Zone update message. */ - ns_o_max = 6 -} ns_opcode; - -/* - * Currently defined response codes. - */ -typedef enum __ns_rcode { - ns_r_noerror = 0, /* No error occurred. */ - ns_r_formerr = 1, /* Format error. */ - ns_r_servfail = 2, /* Server failure. */ - ns_r_nxdomain = 3, /* Name error. */ - ns_r_notimpl = 4, /* Unimplemented. */ - ns_r_refused = 5, /* Operation refused. */ - /* these are for BIND_UPDATE */ - ns_r_yxdomain = 6, /* Name exists */ - ns_r_yxrrset = 7, /* RRset exists */ - ns_r_nxrrset = 8, /* RRset does not exist */ - ns_r_notauth = 9, /* Not authoritative for zone */ - ns_r_notzone = 10, /* Zone of record different from zone section */ - ns_r_max = 11 -} ns_rcode; - -/* BIND_UPDATE */ -typedef enum __ns_update_operation { - ns_uop_delete = 0, - ns_uop_add = 1, - ns_uop_max = 2 -} ns_update_operation; - -/* - * This RR-like structure is particular to UPDATE. - */ -struct ns_updrec { - struct ns_updrec *r_prev; /* prev record */ - struct ns_updrec *r_next; /* next record */ - u_int8_t r_section; /* ZONE/PREREQUISITE/UPDATE */ - char * r_dname; /* owner of the RR */ - u_int16_t r_class; /* class number */ - u_int16_t r_type; /* type number */ - u_int32_t r_ttl; /* time to live */ - u_char * r_data; /* rdata fields as text string */ - u_int16_t r_size; /* size of r_data field */ - int r_opcode; /* type of operation */ - /* following fields for private use by the resolver/server routines */ - struct ns_updrec *r_grpnext; /* next record when grouped */ - struct databuf *r_dp; /* databuf to process */ - struct databuf *r_deldp; /* databuf's deleted/overwritten */ - u_int16_t r_zone; /* zone number on server */ -}; -typedef struct ns_updrec ns_updrec; - -/* - * Currently defined type values for resources and queries. - */ -typedef enum __ns_type { - ns_t_a = 1, /* Host address. */ - ns_t_ns = 2, /* Authoritative server. */ - ns_t_md = 3, /* Mail destination. */ - ns_t_mf = 4, /* Mail forwarder. */ - ns_t_cname = 5, /* Canonical name. */ - ns_t_soa = 6, /* Start of authority zone. */ - ns_t_mb = 7, /* Mailbox domain name. */ - ns_t_mg = 8, /* Mail group member. */ - ns_t_mr = 9, /* Mail rename name. */ - ns_t_null = 10, /* Null resource record. */ - ns_t_wks = 11, /* Well known service. */ - ns_t_ptr = 12, /* Domain name pointer. */ - ns_t_hinfo = 13, /* Host information. */ - ns_t_minfo = 14, /* Mailbox information. */ - ns_t_mx = 15, /* Mail routing information. */ - ns_t_txt = 16, /* Text strings. */ - ns_t_rp = 17, /* Responsible person. */ - ns_t_afsdb = 18, /* AFS cell database. */ - ns_t_x25 = 19, /* X_25 calling address. */ - ns_t_isdn = 20, /* ISDN calling address. */ - ns_t_rt = 21, /* Router. */ - ns_t_nsap = 22, /* NSAP address. */ - ns_t_nsap_ptr = 23, /* Reverse NSAP lookup (deprecated). */ - ns_t_sig = 24, /* Security signature. */ - ns_t_key = 25, /* Security key. */ - ns_t_px = 26, /* X.400 mail mapping. */ - ns_t_gpos = 27, /* Geographical position (withdrawn). */ - ns_t_aaaa = 28, /* Ip6 Address. */ - ns_t_loc = 29, /* Location Information. */ - ns_t_nxt = 30, /* Next domain (security). */ - ns_t_eid = 31, /* Endpoint identifier. */ - ns_t_nimloc = 32, /* Nimrod Locator. */ - ns_t_srv = 33, /* Server Selection. */ - ns_t_atma = 34, /* ATM Address */ - ns_t_naptr = 35, /* Naming Authority PoinTeR */ - /* Query type values which do not appear in resource records. */ - ns_t_ixfr = 251, /* Incremental zone transfer. */ - ns_t_axfr = 252, /* Transfer zone of authority. */ - ns_t_mailb = 253, /* Transfer mailbox records. */ - ns_t_maila = 254, /* Transfer mail agent records. */ - ns_t_any = 255, /* Wildcard match. */ - ns_t_max = 65536 -} ns_type; - -/* - * Values for class field - */ -typedef enum __ns_class { - ns_c_in = 1, /* Internet. */ - /* Class 2 unallocated/unsupported. */ - ns_c_chaos = 3, /* MIT Chaos-net. */ - ns_c_hs = 4, /* MIT Hesiod. */ - /* Query class values which do not appear in resource records */ - ns_c_none = 254, /* for prereq. sections in update requests */ - ns_c_any = 255, /* Wildcard match. */ - ns_c_max = 65536 -} ns_class; - -/* - * Flags field of the KEY RR rdata - */ -#define NS_KEY_TYPEMASK 0xC000 /* Mask for "type" bits */ -#define NS_KEY_TYPE_AUTH_CONF 0x0000 /* Key usable for both */ -#define NS_KEY_TYPE_CONF_ONLY 0x8000 /* Key usable for confidentiality */ -#define NS_KEY_TYPE_AUTH_ONLY 0x4000 /* Key usable for authentication */ -#define NS_KEY_TYPE_NO_KEY 0xC000 /* No key usable for either; no key */ -/* The type bits can also be interpreted independently, as single bits: */ -#define NS_KEY_NO_AUTH 0x8000 /* Key unusable for authentication */ -#define NS_KEY_NO_CONF 0x4000 /* Key unusable for confidentiality */ -#define NS_KEY_EXPERIMENTAL 0x2000 /* Security is *mandatory* if bit=0 */ -#define NS_KEY_RESERVED3 0x1000 /* reserved - must be zero */ -#define NS_KEY_RESERVED4 0x0800 /* reserved - must be zero */ -#define NS_KEY_USERACCOUNT 0x0400 /* key is assoc. with a user acct */ -#define NS_KEY_ENTITY 0x0200 /* key is assoc. with entity eg host */ -#define NS_KEY_ZONEKEY 0x0100 /* key is zone key */ -#define NS_KEY_IPSEC 0x0080 /* key is for IPSEC (host or user)*/ -#define NS_KEY_EMAIL 0x0040 /* key is for email (MIME security) */ -#define NS_KEY_RESERVED10 0x0020 /* reserved - must be zero */ -#define NS_KEY_RESERVED11 0x0010 /* reserved - must be zero */ -#define NS_KEY_SIGNATORYMASK 0x000F /* key can sign RR's of same name */ - -#define NS_KEY_RESERVED_BITMASK ( NS_KEY_RESERVED3 | \ - NS_KEY_RESERVED4 | \ - NS_KEY_RESERVED10 | \ - NS_KEY_RESERVED11 ) - -/* The Algorithm field of the KEY and SIG RR's is an integer, {1..254} */ -#define NS_ALG_MD5RSA 1 /* MD5 with RSA */ -#define NS_ALG_EXPIRE_ONLY 253 /* No alg, no security */ -#define NS_ALG_PRIVATE_OID 254 /* Key begins with OID giving alg */ - -/* Signatures */ -#define NS_MD5RSA_MIN_BITS 512 /* Size of a mod or exp in bits */ -#define NS_MD5RSA_MAX_BITS 2552 - /* Total of binary mod and exp */ -#define NS_MD5RSA_MAX_BYTES ((NS_MD5RSA_MAX_BITS+7/8)*2+3) - /* Max length of text sig block */ -#define NS_MD5RSA_MAX_BASE64 (((NS_MD5RSA_MAX_BYTES+2)/3)*4) - -/* Offsets into SIG record rdata to find various values */ -#define NS_SIG_TYPE 0 /* Type flags */ -#define NS_SIG_ALG 2 /* Algorithm */ -#define NS_SIG_LABELS 3 /* How many labels in name */ -#define NS_SIG_OTTL 4 /* Original TTL */ -#define NS_SIG_EXPIR 8 /* Expiration time */ -#define NS_SIG_SIGNED 12 /* Signature time */ -#define NS_SIG_FOOT 16 /* Key footprint */ -#define NS_SIG_SIGNER 18 /* Domain name of who signed it */ - -/* How RR types are represented as bit-flags in NXT records */ -#define NS_NXT_BITS 8 -#define NS_NXT_BIT_SET( n,p) (p[(n)/NS_NXT_BITS] |= (0x80>>((n)%NS_NXT_BITS))) -#define NS_NXT_BIT_CLEAR(n,p) (p[(n)/NS_NXT_BITS] &= ~(0x80>>((n)%NS_NXT_BITS))) -#define NS_NXT_BIT_ISSET(n,p) (p[(n)/NS_NXT_BITS] & (0x80>>((n)%NS_NXT_BITS))) - - -/* - * Inline versions of get/put short/long. Pointer is advanced. - */ -#define NS_GET16(s, cp) { \ - register u_char *t_cp = (u_char *)(cp); \ - (s) = ((u_int16_t)t_cp[0] << 8) \ - | ((u_int16_t)t_cp[1]) \ - ; \ - (cp) += NS_INT16SZ; \ -} - -#define NS_GET32(l, cp) { \ - register u_char *t_cp = (u_char *)(cp); \ - (l) = ((u_int32_t)t_cp[0] << 24) \ - | ((u_int32_t)t_cp[1] << 16) \ - | ((u_int32_t)t_cp[2] << 8) \ - | ((u_int32_t)t_cp[3]) \ - ; \ - (cp) += NS_INT32SZ; \ -} - -#define NS_PUT16(s, cp) { \ - register u_int16_t t_s = (u_int16_t)(s); \ - register u_char *t_cp = (u_char *)(cp); \ - *t_cp++ = t_s >> 8; \ - *t_cp = t_s; \ - (cp) += NS_INT16SZ; \ -} - -#define NS_PUT32(l, cp) { \ - register u_int32_t t_l = (u_int32_t)(l); \ - register u_char *t_cp = (u_char *)(cp); \ - *t_cp++ = t_l >> 24; \ - *t_cp++ = t_l >> 16; \ - *t_cp++ = t_l >> 8; \ - *t_cp = t_l; \ - (cp) += NS_INT32SZ; \ -} - -/* - * ANSI C identifier hiding. - */ -#define ns_get16 __ns_get16 -#define ns_get32 __ns_get32 -#define ns_put16 __ns_put16 -#define ns_put32 __ns_put32 -#define ns_initparse __ns_initparse -#define ns_parserr __ns_parserr -#define ns_sprintrr __ns_sprintrr -#define ns_sprintrrf __ns_sprintrrf -#define ns_format_ttl __ns_format_ttl -#define ns_parse_ttl __ns_parse_ttl -#define ns_name_ntop __ns_name_ntop -#define ns_name_pton __ns_name_pton -#define ns_name_unpack __ns_name_unpack -#define ns_name_pack __ns_name_pack -#define ns_name_compress __ns_name_compress -#define ns_name_uncompress __ns_name_uncompress - -__BEGIN_DECLS -u_int ns_get16 __P((const u_char *)); -u_long ns_get32 __P((const u_char *)); -void ns_put16 __P((u_int, u_char *)); -void ns_put32 __P((u_long, u_char *)); -int ns_initparse __P((const u_char *, int, ns_msg *)); -int ns_parserr __P((ns_msg *, ns_sect, int, ns_rr *)); -int ns_sprintrr __P((const ns_msg *, const ns_rr *, - const char *, const char *, char *, size_t)); -int ns_sprintrrf __P((const u_char *, size_t, const char *, - ns_class, ns_type, u_long, const u_char *, - size_t, const char *, const char *, - char *, size_t)); -int ns_format_ttl __P((u_long, char *, size_t)); -int ns_parse_ttl __P((const char *, u_long *)); -int ns_name_ntop __P((const u_char *, char *, size_t)); -int ns_name_pton __P((const char *, u_char *, size_t)); -int ns_name_unpack __P((const u_char *, const u_char *, - const u_char *, u_char *, size_t)); -int ns_name_pack __P((const u_char *, u_char *, int, - const u_char **, const u_char **)); -int ns_name_uncompress __P((const u_char *, const u_char *, - const u_char *, char *, size_t)); -int ns_name_compress __P((const char *, u_char *, size_t, - const u_char **, const u_char **)); -int ns_name_skip __P((const u_char **, const u_char *)); -__END_DECLS - -#ifdef BIND_4_COMPAT -#include -#endif - -#endif /* !_ARPA_NAMESER_H_ */ diff --git a/bsd/include/arpa/nameser_compat.h b/bsd/include/arpa/nameser_compat.h deleted file mode 100644 index 33c96acfd..000000000 --- a/bsd/include/arpa/nameser_compat.h +++ /dev/null @@ -1,194 +0,0 @@ -/* Copyright (c) 1983, 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. - */ - -/* - * from nameser.h 8.1 (Berkeley) 6/2/93 - * From: Id: nameser_compat.h,v 8.9 1998/03/20 23:25:10 halley Exp - * $FreeBSD: src/include/arpa/nameser_compat.h,v 1.1.2.1 1999/08/29 14:39:01 peter Exp $ - */ - -#ifndef _ARPA_NAMESER_COMPAT_ -#define _ARPA_NAMESER_COMPAT_ - -#define __BIND 19950621 /* (DEAD) interface version stamp. */ - -#include - -#if !defined(BYTE_ORDER) || \ - (BYTE_ORDER != BIG_ENDIAN && BYTE_ORDER != LITTLE_ENDIAN && \ - BYTE_ORDER != PDP_ENDIAN) - /* you must determine what the correct bit order is for - * your compiler - the next line is an intentional error - * which will force your compiles to bomb until you fix - * the above macros. - */ - error "Undefined or invalid BYTE_ORDER"; -#endif - -/* - * Structure for query header. The order of the fields is machine- and - * compiler-dependent, depending on the byte/bit order and the layout - * of bit fields. We use bit fields only in int variables, as this - * is all ANSI requires. This requires a somewhat confusing rearrangement. - */ - -typedef struct { - unsigned id :16; /* query identification number */ -#if BYTE_ORDER == BIG_ENDIAN - /* fields in third byte */ - unsigned qr: 1; /* response flag */ - unsigned opcode: 4; /* purpose of message */ - unsigned aa: 1; /* authoritive answer */ - unsigned tc: 1; /* truncated message */ - unsigned rd: 1; /* recursion desired */ - /* fields in fourth byte */ - unsigned ra: 1; /* recursion available */ - unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */ - unsigned ad: 1; /* authentic data from named */ - unsigned cd: 1; /* checking disabled by resolver */ - unsigned rcode :4; /* response code */ -#endif -#if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN - /* fields in third byte */ - unsigned rd :1; /* recursion desired */ - unsigned tc :1; /* truncated message */ - unsigned aa :1; /* authoritive answer */ - unsigned opcode :4; /* purpose of message */ - unsigned qr :1; /* response flag */ - /* fields in fourth byte */ - unsigned rcode :4; /* response code */ - unsigned cd: 1; /* checking disabled by resolver */ - unsigned ad: 1; /* authentic data from named */ - unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */ - unsigned ra :1; /* recursion available */ -#endif - /* remaining bytes */ - unsigned qdcount :16; /* number of question entries */ - unsigned ancount :16; /* number of answer entries */ - unsigned nscount :16; /* number of authority entries */ - unsigned arcount :16; /* number of resource entries */ -} HEADER; - -#define PACKETSZ NS_PACKETSZ -#define MAXDNAME NS_MAXDNAME -#define MAXCDNAME NS_MAXCDNAME -#define MAXLABEL NS_MAXLABEL -#define HFIXEDSZ NS_HFIXEDSZ -#define QFIXEDSZ NS_QFIXEDSZ -#define RRFIXEDSZ NS_RRFIXEDSZ -#define INT32SZ NS_INT32SZ -#define INT16SZ NS_INT16SZ -#define INADDRSZ NS_INADDRSZ -#define IN6ADDRSZ NS_IN6ADDRSZ -#define INDIR_MASK NS_CMPRSFLGS -#define NAMESERVER_PORT NS_DEFAULTPORT - -#define S_ZONE ns_s_zn -#define S_PREREQ ns_s_pr -#define S_UPDATE ns_s_ud -#define S_ADDT ns_s_ar - -#define QUERY ns_o_query -#define IQUERY ns_o_iquery -#define STATUS ns_o_status -#define NS_NOTIFY_OP ns_o_notify -#define NS_UPDATE_OP ns_o_update - -#define NOERROR ns_r_noerror -#define FORMERR ns_r_formerr -#define SERVFAIL ns_r_servfail -#define NXDOMAIN ns_r_nxdomain -#define NOTIMP ns_r_notimpl -#define REFUSED ns_r_refused -#define YXDOMAIN ns_r_yxdomain -#define YXRRSET ns_r_yxrrset -#define NXRRSET ns_r_nxrrset -#define NOTAUTH ns_r_notauth -#define NOTZONE ns_r_notzone - -#define DELETE ns_uop_delete -#define ADD ns_uop_add - -#define T_A ns_t_a -#define T_NS ns_t_ns -#define T_MD ns_t_md -#define T_MF ns_t_mf -#define T_CNAME ns_t_cname -#define T_SOA ns_t_soa -#define T_MB ns_t_mb -#define T_MG ns_t_mg -#define T_MR ns_t_mr -#define T_NULL ns_t_null -#define T_WKS ns_t_wks -#define T_PTR ns_t_ptr -#define T_HINFO ns_t_hinfo -#define T_MINFO ns_t_minfo -#define T_MX ns_t_mx -#define T_TXT ns_t_txt -#define T_RP ns_t_rp -#define T_AFSDB ns_t_afsdb -#define T_X25 ns_t_x25 -#define T_ISDN ns_t_isdn -#define T_RT ns_t_rt -#define T_NSAP ns_t_nsap -#define T_NSAP_PTR ns_t_nsap_ptr -#define T_SIG ns_t_sig -#define T_KEY ns_t_key -#define T_PX ns_t_px -#define T_GPOS ns_t_gpos -#define T_AAAA ns_t_aaaa -#define T_LOC ns_t_loc -#define T_NXT ns_t_nxt -#define T_EID ns_t_eid -#define T_NIMLOC ns_t_nimloc -#define T_SRV ns_t_srv -#define T_ATMA ns_t_atma -#define T_NAPTR ns_t_naptr -#define T_IXFR ns_t_ixfr -#define T_AXFR ns_t_axfr -#define T_MAILB ns_t_mailb -#define T_MAILA ns_t_maila -#define T_ANY ns_t_any - -#define C_IN ns_c_in -#define C_CHAOS ns_c_chaos -#define C_HS ns_c_hs -/* BIND_UPDATE */ -#define C_NONE ns_c_none -#define C_ANY ns_c_any - -#define GETSHORT NS_GET16 -#define GETLONG NS_GET32 -#define PUTSHORT NS_PUT16 -#define PUTLONG NS_PUT32 - -#endif /* _ARPA_NAMESER_COMPAT_ */ diff --git a/bsd/include/arpa/telnet.h b/bsd/include/arpa/telnet.h deleted file mode 100644 index 8126ce9af..000000000 --- a/bsd/include/arpa/telnet.h +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1983, 1993 - * 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. - * - * @(#)telnet.h 8.2 (Berkeley) 12/15/93 - */ - -#ifndef _TELNET_H_ -#define _TELNET_H_ - -/* - * Definitions for the TELNET protocol. - */ -#define IAC 255 /* interpret as command: */ -#define DONT 254 /* you are not to use option */ -#define DO 253 /* please, you use option */ -#define WONT 252 /* I won't use option */ -#define WILL 251 /* I will use option */ -#define SB 250 /* interpret as subnegotiation */ -#define GA 249 /* you may reverse the line */ -#define EL 248 /* erase the current line */ -#define EC 247 /* erase the current character */ -#define AYT 246 /* are you there */ -#define AO 245 /* abort output--but let prog finish */ -#define IP 244 /* interrupt process--permanently */ -#define BREAK 243 /* break */ -#define DM 242 /* data mark--for connect. cleaning */ -#define NOP 241 /* nop */ -#define SE 240 /* end sub negotiation */ -#define EOR 239 /* end of record (transparent mode) */ -#define ABORT 238 /* Abort process */ -#define SUSP 237 /* Suspend process */ -#define xEOF 236 /* End of file: EOF is already used... */ - -#define SYNCH 242 /* for telfunc calls */ - -#ifdef TELCMDS -char *telcmds[] = { - "EOF", "SUSP", "ABORT", "EOR", - "SE", "NOP", "DMARK", "BRK", "IP", "AO", "AYT", "EC", - "EL", "GA", "SB", "WILL", "WONT", "DO", "DONT", "IAC", 0, -}; -#else -extern char *telcmds[]; -#endif - -#define TELCMD_FIRST xEOF -#define TELCMD_LAST IAC -#define TELCMD_OK(x) ((unsigned int)(x) <= TELCMD_LAST && \ - (unsigned int)(x) >= TELCMD_FIRST) -#define TELCMD(x) telcmds[(x)-TELCMD_FIRST] - -/* telnet options */ -#define TELOPT_BINARY 0 /* 8-bit data path */ -#define TELOPT_ECHO 1 /* echo */ -#define TELOPT_RCP 2 /* prepare to reconnect */ -#define TELOPT_SGA 3 /* suppress go ahead */ -#define TELOPT_NAMS 4 /* approximate message size */ -#define TELOPT_STATUS 5 /* give status */ -#define TELOPT_TM 6 /* timing mark */ -#define TELOPT_RCTE 7 /* remote controlled transmission and echo */ -#define TELOPT_NAOL 8 /* negotiate about output line width */ -#define TELOPT_NAOP 9 /* negotiate about output page size */ -#define TELOPT_NAOCRD 10 /* negotiate about CR disposition */ -#define TELOPT_NAOHTS 11 /* negotiate about horizontal tabstops */ -#define TELOPT_NAOHTD 12 /* negotiate about horizontal tab disposition */ -#define TELOPT_NAOFFD 13 /* negotiate about formfeed disposition */ -#define TELOPT_NAOVTS 14 /* negotiate about vertical tab stops */ -#define TELOPT_NAOVTD 15 /* negotiate about vertical tab disposition */ -#define TELOPT_NAOLFD 16 /* negotiate about output LF disposition */ -#define TELOPT_XASCII 17 /* extended ascic character set */ -#define TELOPT_LOGOUT 18 /* force logout */ -#define TELOPT_BM 19 /* byte macro */ -#define TELOPT_DET 20 /* data entry terminal */ -#define TELOPT_SUPDUP 21 /* supdup protocol */ -#define TELOPT_SUPDUPOUTPUT 22 /* supdup output */ -#define TELOPT_SNDLOC 23 /* send location */ -#define TELOPT_TTYPE 24 /* terminal type */ -#define TELOPT_EOR 25 /* end or record */ -#define TELOPT_TUID 26 /* TACACS user identification */ -#define TELOPT_OUTMRK 27 /* output marking */ -#define TELOPT_TTYLOC 28 /* terminal location number */ -#define TELOPT_3270REGIME 29 /* 3270 regime */ -#define TELOPT_X3PAD 30 /* X.3 PAD */ -#define TELOPT_NAWS 31 /* window size */ -#define TELOPT_TSPEED 32 /* terminal speed */ -#define TELOPT_LFLOW 33 /* remote flow control */ -#define TELOPT_LINEMODE 34 /* Linemode option */ -#define TELOPT_XDISPLOC 35 /* X Display Location */ -#define TELOPT_OLD_ENVIRON 36 /* Old - Environment variables */ -#define TELOPT_AUTHENTICATION 37/* Authenticate */ -#define TELOPT_ENCRYPT 38 /* Encryption option */ -#define TELOPT_NEW_ENVIRON 39 /* New - Environment variables */ -#define TELOPT_EXOPL 255 /* extended-options-list */ - - -#define NTELOPTS (1+TELOPT_NEW_ENVIRON) -#ifdef TELOPTS -char *telopts[NTELOPTS+1] = { - "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME", - "STATUS", "TIMING MARK", "RCTE", "NAOL", "NAOP", - "NAOCRD", "NAOHTS", "NAOHTD", "NAOFFD", "NAOVTS", - "NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO", - "DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT", - "SEND LOCATION", "TERMINAL TYPE", "END OF RECORD", - "TACACS UID", "OUTPUT MARKING", "TTYLOC", - "3270 REGIME", "X.3 PAD", "NAWS", "TSPEED", "LFLOW", - "LINEMODE", "XDISPLOC", "OLD-ENVIRON", "AUTHENTICATION", - "ENCRYPT", "NEW-ENVIRON", - 0, -}; -#define TELOPT_FIRST TELOPT_BINARY -#define TELOPT_LAST TELOPT_NEW_ENVIRON -#define TELOPT_OK(x) ((unsigned int)(x) <= TELOPT_LAST) -#define TELOPT(x) telopts[(x)-TELOPT_FIRST] -#endif - -/* sub-option qualifiers */ -#define TELQUAL_IS 0 /* option is... */ -#define TELQUAL_SEND 1 /* send option */ -#define TELQUAL_INFO 2 /* ENVIRON: informational version of IS */ -#define TELQUAL_REPLY 2 /* AUTHENTICATION: client version of IS */ -#define TELQUAL_NAME 3 /* AUTHENTICATION: client version of IS */ - -#define LFLOW_OFF 0 /* Disable remote flow control */ -#define LFLOW_ON 1 /* Enable remote flow control */ -#define LFLOW_RESTART_ANY 2 /* Restart output on any char */ -#define LFLOW_RESTART_XON 3 /* Restart output only on XON */ - -/* - * LINEMODE suboptions - */ - -#define LM_MODE 1 -#define LM_FORWARDMASK 2 -#define LM_SLC 3 - -#define MODE_EDIT 0x01 -#define MODE_TRAPSIG 0x02 -#define MODE_ACK 0x04 -#define MODE_SOFT_TAB 0x08 -#define MODE_LIT_ECHO 0x10 - -#define MODE_MASK 0x1f - -/* Not part of protocol, but needed to simplify things... */ -#define MODE_FLOW 0x0100 -#define MODE_ECHO 0x0200 -#define MODE_INBIN 0x0400 -#define MODE_OUTBIN 0x0800 -#define MODE_FORCE 0x1000 - -#define SLC_SYNCH 1 -#define SLC_BRK 2 -#define SLC_IP 3 -#define SLC_AO 4 -#define SLC_AYT 5 -#define SLC_EOR 6 -#define SLC_ABORT 7 -#define SLC_EOF 8 -#define SLC_SUSP 9 -#define SLC_EC 10 -#define SLC_EL 11 -#define SLC_EW 12 -#define SLC_RP 13 -#define SLC_LNEXT 14 -#define SLC_XON 15 -#define SLC_XOFF 16 -#define SLC_FORW1 17 -#define SLC_FORW2 18 - -#define NSLC 18 - -/* - * For backwards compatability, we define SLC_NAMES to be the - * list of names if SLC_NAMES is not defined. - */ -#define SLC_NAMELIST "0", "SYNCH", "BRK", "IP", "AO", "AYT", "EOR", \ - "ABORT", "EOF", "SUSP", "EC", "EL", "EW", "RP", \ - "LNEXT", "XON", "XOFF", "FORW1", "FORW2", 0, -#ifdef SLC_NAMES -char *slc_names[] = { - SLC_NAMELIST -}; -#else -extern char *slc_names[]; -#define SLC_NAMES SLC_NAMELIST -#endif - -#define SLC_NAME_OK(x) ((unsigned int)(x) <= NSLC) -#define SLC_NAME(x) slc_names[x] - -#define SLC_NOSUPPORT 0 -#define SLC_CANTCHANGE 1 -#define SLC_VARIABLE 2 -#define SLC_DEFAULT 3 -#define SLC_LEVELBITS 0x03 - -#define SLC_FUNC 0 -#define SLC_FLAGS 1 -#define SLC_VALUE 2 - -#define SLC_ACK 0x80 -#define SLC_FLUSHIN 0x40 -#define SLC_FLUSHOUT 0x20 - -#define OLD_ENV_VAR 1 -#define OLD_ENV_VALUE 0 -#define NEW_ENV_VAR 0 -#define NEW_ENV_VALUE 1 -#define ENV_ESC 2 -#define ENV_USERVAR 3 - -/* - * AUTHENTICATION suboptions - */ - -/* - * Who is authenticating who ... - */ -#define AUTH_WHO_CLIENT 0 /* Client authenticating server */ -#define AUTH_WHO_SERVER 1 /* Server authenticating client */ -#define AUTH_WHO_MASK 1 - -/* - * amount of authentication done - */ -#define AUTH_HOW_ONE_WAY 0 -#define AUTH_HOW_MUTUAL 2 -#define AUTH_HOW_MASK 2 - -#define AUTHTYPE_NULL 0 -#define AUTHTYPE_KERBEROS_V4 1 -#define AUTHTYPE_KERBEROS_V5 2 -#define AUTHTYPE_SPX 3 -#define AUTHTYPE_MINK 4 -#define AUTHTYPE_CNT 5 - -#define AUTHTYPE_TEST 99 - -#ifdef AUTH_NAMES -char *authtype_names[] = { - "NULL", "KERBEROS_V4", "KERBEROS_V5", "SPX", "MINK", 0, -}; -#else -extern char *authtype_names[]; -#endif - -#define AUTHTYPE_NAME_OK(x) ((unsigned int)(x) < AUTHTYPE_CNT) -#define AUTHTYPE_NAME(x) authtype_names[x] - -/* - * ENCRYPTion suboptions - */ -#define ENCRYPT_IS 0 /* I pick encryption type ... */ -#define ENCRYPT_SUPPORT 1 /* I support encryption types ... */ -#define ENCRYPT_REPLY 2 /* Initial setup response */ -#define ENCRYPT_START 3 /* Am starting to send encrypted */ -#define ENCRYPT_END 4 /* Am ending encrypted */ -#define ENCRYPT_REQSTART 5 /* Request you start encrypting */ -#define ENCRYPT_REQEND 6 /* Request you send encrypting */ -#define ENCRYPT_ENC_KEYID 7 -#define ENCRYPT_DEC_KEYID 8 -#define ENCRYPT_CNT 9 - -#define ENCTYPE_ANY 0 -#define ENCTYPE_DES_CFB64 1 -#define ENCTYPE_DES_OFB64 2 -#define ENCTYPE_CNT 3 - -#ifdef ENCRYPT_NAMES -char *encrypt_names[] = { - "IS", "SUPPORT", "REPLY", "START", "END", - "REQUEST-START", "REQUEST-END", "ENC-KEYID", "DEC-KEYID", - 0, -}; -char *enctype_names[] = { - "ANY", "DES_CFB64", "DES_OFB64", 0, -}; -#else -extern char *encrypt_names[]; -extern char *enctype_names[]; -#endif - - -#define ENCRYPT_NAME_OK(x) ((unsigned int)(x) < ENCRYPT_CNT) -#define ENCRYPT_NAME(x) encrypt_names[x] - -#define ENCTYPE_NAME_OK(x) ((unsigned int)(x) < ENCTYPE_CNT) -#define ENCTYPE_NAME(x) enctype_names[x] - -#endif /* !_TELNET_H_ */ diff --git a/bsd/include/arpa/tftp.h b/bsd/include/arpa/tftp.h deleted file mode 100644 index 1e7324f01..000000000 --- a/bsd/include/arpa/tftp.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1983, 1993 - * 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. - * - * @(#)tftp.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _TFTP_H_ -#define _TFTP_H_ - -/* - * Trivial File Transfer Protocol (IEN-133) - */ -#define SEGSIZE 512 /* data segment size */ - -/* - * Packet types. - */ -#define RRQ 01 /* read request */ -#define WRQ 02 /* write request */ -#define DATA 03 /* data packet */ -#define ACK 04 /* acknowledgement */ -#define ERROR 05 /* error code */ - -struct tftphdr { - short th_opcode; /* packet type */ - union { - short tu_block; /* block # */ - short tu_code; /* error code */ - char tu_stuff[1]; /* request packet stuff */ - } th_u; - char th_data[1]; /* data or error string */ -}; - -#define th_block th_u.tu_block -#define th_code th_u.tu_code -#define th_stuff th_u.tu_stuff -#define th_msg th_data - -/* - * Error codes. - */ -#define EUNDEF 0 /* not defined */ -#define ENOTFOUND 1 /* file not found */ -#define EACCESS 2 /* access violation */ -#define ENOSPACE 3 /* disk full or allocation exceeded */ -#define EBADOP 4 /* illegal TFTP operation */ -#define EBADID 5 /* unknown transfer ID */ -#define EEXISTS 6 /* file already exists */ -#define ENOUSER 7 /* no such user */ - -#endif /* !_TFTP_H_ */ diff --git a/bsd/include/bitstring.h b/bsd/include/bitstring.h deleted file mode 100644 index 92dec9e96..000000000 --- a/bsd/include/bitstring.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Paul Vixie. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)bitstring.h 8.1 (Berkeley) 7/19/93 - */ - -#ifndef _BITSTRING_H_ -#define _BITSTRING_H_ - -typedef unsigned char bitstr_t; - -/* internal macros */ - /* byte of the bitstring bit is in */ -#define _bit_byte(bit) \ - ((bit) >> 3) - - /* mask for the bit within its byte */ -#define _bit_mask(bit) \ - (1 << ((bit)&0x7)) - -/* external macros */ - /* bytes in a bitstring of nbits bits */ -#define bitstr_size(nbits) \ - ((((nbits) - 1) >> 3) + 1) - - /* allocate a bitstring */ -#define bit_alloc(nbits) \ - (bitstr_t *)calloc(1, \ - (unsigned int)bitstr_size(nbits) * sizeof(bitstr_t)) - - /* allocate a bitstring on the stack */ -#define bit_decl(name, nbits) \ - (name)[bitstr_size(nbits)] - - /* is bit N of bitstring name set? */ -#define bit_test(name, bit) \ - ((name)[_bit_byte(bit)] & _bit_mask(bit)) - - /* set bit N of bitstring name */ -#define bit_set(name, bit) \ - (name)[_bit_byte(bit)] |= _bit_mask(bit) - - /* clear bit N of bitstring name */ -#define bit_clear(name, bit) \ - (name)[_bit_byte(bit)] &= ~_bit_mask(bit) - - /* clear bits start ... stop in bitstring */ -#define bit_nclear(name, start, stop) { \ - register bitstr_t *_name = name; \ - register int _start = start, _stop = stop; \ - register int _startbyte = _bit_byte(_start); \ - register int _stopbyte = _bit_byte(_stop); \ - if (_startbyte == _stopbyte) { \ - _name[_startbyte] &= ((0xff >> (8 - (_start&0x7))) | \ - (0xff << ((_stop&0x7) + 1))); \ - } else { \ - _name[_startbyte] &= 0xff >> (8 - (_start&0x7)); \ - while (++_startbyte < _stopbyte) \ - _name[_startbyte] = 0; \ - _name[_stopbyte] &= 0xff << ((_stop&0x7) + 1); \ - } \ -} - - /* set bits start ... stop in bitstring */ -#define bit_nset(name, start, stop) { \ - register bitstr_t *_name = name; \ - register int _start = start, _stop = stop; \ - register int _startbyte = _bit_byte(_start); \ - register int _stopbyte = _bit_byte(_stop); \ - if (_startbyte == _stopbyte) { \ - _name[_startbyte] |= ((0xff << (_start&0x7)) & \ - (0xff >> (7 - (_stop&0x7)))); \ - } else { \ - _name[_startbyte] |= 0xff << ((_start)&0x7); \ - while (++_startbyte < _stopbyte) \ - _name[_startbyte] = 0xff; \ - _name[_stopbyte] |= 0xff >> (7 - (_stop&0x7)); \ - } \ -} - - /* find first bit clear in name */ -#define bit_ffc(name, nbits, value) { \ - register bitstr_t *_name = name; \ - register int _byte, _nbits = nbits; \ - register int _stopbyte = _bit_byte(_nbits), _value = -1; \ - for (_byte = 0; _byte <= _stopbyte; ++_byte) \ - if (_name[_byte] != 0xff) { \ - _value = _byte << 3; \ - for (_stopbyte = _name[_byte]; (_stopbyte&0x1); \ - ++_value, _stopbyte >>= 1); \ - break; \ - } \ - *(value) = _value; \ -} - - /* find first bit set in name */ -#define bit_ffs(name, nbits, value) { \ - register bitstr_t *_name = name; \ - register int _byte, _nbits = nbits; \ - register int _stopbyte = _bit_byte(_nbits), _value = -1; \ - for (_byte = 0; _byte <= _stopbyte; ++_byte) \ - if (_name[_byte]) { \ - _value = _byte << 3; \ - for (_stopbyte = _name[_byte]; !(_stopbyte&0x1); \ - ++_value, _stopbyte >>= 1); \ - break; \ - } \ - *(value) = _value; \ -} - -#endif /* !_BITSTRING_H_ */ diff --git a/bsd/include/c.h b/bsd/include/c.h deleted file mode 100644 index 905d271fa..000000000 --- a/bsd/include/c.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Standard C macros - * - ********************************************************************** - * HISTORY - * 02-Feb-86 Glenn Marcy (gm0w) at Carnegie-Mellon University - * Added check to allow multiple or recursive inclusion of this - * file. Added bool enum from machine/types.h for regular users - * that want a real boolean type. - * - * 29-Dec-85 Glenn Marcy (gm0w) at Carnegie-Mellon University - * Also change spacing of MAX and MIN to coincide with that of - * sys/param.h. - * - * 19-Nov-85 Glenn Marcy (gm0w) at Carnegie-Mellon University - * Changed the number of tabs between TRUE, FALSE and their - * respective values to match those in sys/types.h. - * - * 17-Dec-84 Glenn Marcy (gm0w) at Carnegie-Mellon University - * Only define TRUE and FALSE if not defined. Added caseE macro - * for using enumerated types in switch statements. - * - * 23-Apr-81 Mike Accetta (mja) at Carnegie-Mellon University - * Added "sizeofS" and "sizeofA" macros which expand to the size - * of a string constant and array respectively. - * - ********************************************************************** - */ - -#ifndef _C_INCLUDE_ -#define _C_INCLUDE_ - -#ifndef ABS -#define ABS(x) ((x)>=0?(x):-(x)) -#endif /* ABS */ -#ifndef MIN -#define MIN(a,b) (((a)<(b))?(a):(b)) -#endif /* MIN */ -#ifndef MAX -#define MAX(a,b) (((a)>(b))?(a):(b)) -#endif /* MAX */ - -#ifndef FALSE -#define FALSE 0 -#endif /* FALSE */ -#ifndef TRUE -#define TRUE 1 -#endif /* TRUE */ - -#define CERROR (-1) - -#ifndef bool -typedef enum { false = 0, true = 1 } bool; -#endif /* bool */ - -#define sizeofS(string) (sizeof(string) - 1) -#define sizeofA(array) (sizeof(array)/sizeof(array[0])) - -#define caseE(enum_type) case (int)(enum_type) - -#endif /* _C_INCLUDE_ */ diff --git a/bsd/include/ctype.h b/bsd/include/ctype.h deleted file mode 100644 index bd5d05a9a..000000000 --- a/bsd/include/ctype.h +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, Inc. - * - * This code is derived from software contributed to Berkeley by - * Paul Borman at Krystal Technologies. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)ctype.h 8.4 (Berkeley) 1/21/94 - */ - -#ifndef _CTYPE_H_ -#define _CTYPE_H_ - -#include - -#define _A 0x00000100L /* Alpha */ -#define _C 0x00000200L /* Control */ -#define _D 0x00000400L /* Digit */ -#define _G 0x00000800L /* Graph */ -#define _L 0x00001000L /* Lower */ -#define _P 0x00002000L /* Punct */ -#define _S 0x00004000L /* Space */ -#define _U 0x00008000L /* Upper */ -#define _X 0x00010000L /* X digit */ -#define _B 0x00020000L /* Blank */ -#define _R 0x00040000L /* Print */ -#define _I 0x00080000L /* Ideogram */ -#define _T 0x00100000L /* Special */ -#define _Q 0x00200000L /* Phonogram */ - -#define isalnum(c) __istype((c), (_A|_D)) -#define isalpha(c) __istype((c), _A) -#define iscntrl(c) __istype((c), _C) -#define isdigit(c) __isctype((c), _D) /* ANSI -- locale independent */ -#define isgraph(c) __istype((c), _G) -#define islower(c) __istype((c), _L) -#define isprint(c) __istype((c), _R) -#define ispunct(c) __istype((c), _P) -#define isspace(c) __istype((c), _S) -#define isupper(c) __istype((c), _U) -#define isxdigit(c) __isctype((c), _X) /* ANSI -- locale independent */ - -#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE) -#define isascii(c) ((c & ~0x7F) == 0) -#define toascii(c) ((c) & 0x7F) -#define digittoint(c) __istype((c), 0xFF) -#define isideogram(c) __istype((c), _I) -#define isphonogram(c) __istype((c), _T) -#define isspecial(c) __istype((c), _Q) -#define isblank(c) __istype((c), _B) -#define isrune(c) __istype((c), 0xFFFFFF00L) -#define isnumber(c) __istype((c), _D) -#define ishexnumber(c) __istype((c), _X) -#endif - -/* See comments in about _BSD_RUNE_T_. */ -__BEGIN_DECLS -unsigned long ___runetype __P((_BSD_RUNE_T_)); -_BSD_RUNE_T_ ___tolower __P((_BSD_RUNE_T_)); -_BSD_RUNE_T_ ___toupper __P((_BSD_RUNE_T_)); -__END_DECLS - -/* - * If your compiler supports prototypes and inline functions, - * #define _USE_CTYPE_INLINE_. Otherwise, use the C library - * functions. - */ -#if !defined(_USE_CTYPE_CLIBRARY_) && defined(__GNUC__) || defined(__cplusplus) -#define _USE_CTYPE_INLINE_ 1 -#endif - -#if defined(_USE_CTYPE_INLINE_) -static __inline int -__istype(_BSD_RUNE_T_ c, unsigned long f) -{ - return((((c & _CRMASK) ? ___runetype(c) : - _CurrentRuneLocale->runetype[c]) & f) ? 1 : 0); -} - -static __inline int -__isctype(_BSD_RUNE_T_ c, unsigned long f) -{ - return((((c & _CRMASK) ? 0 : - _DefaultRuneLocale.runetype[c]) & f) ? 1 : 0); -} - -/* _ANSI_LIBRARY is defined by lib/libc/gen/isctype.c. */ -#if !defined(_ANSI_LIBRARY) -static __inline _BSD_RUNE_T_ -toupper(_BSD_RUNE_T_ c) -{ - return((c & _CRMASK) ? - ___toupper(c) : _CurrentRuneLocale->mapupper[c]); -} - -static __inline _BSD_RUNE_T_ -tolower(_BSD_RUNE_T_ c) -{ - return((c & _CRMASK) ? - ___tolower(c) : _CurrentRuneLocale->maplower[c]); -} -#endif /* !_ANSI_LIBRARY */ - -#else /* !_USE_CTYPE_INLINE_ */ - -__BEGIN_DECLS -int __istype __P((_BSD_RUNE_T_, unsigned long)); -int __isctype __P((_BSD_RUNE_T_, unsigned long)); -_BSD_RUNE_T_ toupper __P((_BSD_RUNE_T_)); -_BSD_RUNE_T_ tolower __P((_BSD_RUNE_T_)); -__END_DECLS -#endif /* _USE_CTYPE_INLINE_ */ - -#endif /* !_CTYPE_H_ */ diff --git a/bsd/include/db.h b/bsd/include/db.h deleted file mode 100644 index 1e4cce86c..000000000 --- a/bsd/include/db.h +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1990, 1993 - * 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. - * - * @(#)db.h 8.4 (Berkeley) 2/21/94 - */ - -#ifndef _DB_H_ -#define _DB_H_ - -#include -#include - -#include - -#define RET_ERROR -1 /* Return values. */ -#define RET_SUCCESS 0 -#define RET_SPECIAL 1 - -#define MAX_PAGE_NUMBER 0xffffffff /* >= # of pages in a file */ -typedef u_int32_t pgno_t; -#define MAX_PAGE_OFFSET 65535 /* >= # of bytes in a page */ -typedef u_int16_t indx_t; -#define MAX_REC_NUMBER 0xffffffff /* >= # of records in a tree */ -typedef u_int32_t recno_t; - -/* Key/data structure -- a Data-Base Thang. */ -typedef struct { - void *data; /* data */ - size_t size; /* data length */ -} DBT; - -/* Routine flags. */ -#define R_CURSOR 1 /* del, put, seq */ -#define __R_UNUSED 2 /* UNUSED */ -#define R_FIRST 3 /* seq */ -#define R_IAFTER 4 /* put (RECNO) */ -#define R_IBEFORE 5 /* put (RECNO) */ -#define R_LAST 6 /* seq (BTREE, RECNO) */ -#define R_NEXT 7 /* seq */ -#define R_NOOVERWRITE 8 /* put */ -#define R_PREV 9 /* seq (BTREE, RECNO) */ -#define R_SETCURSOR 10 /* put (RECNO) */ -#define R_RECNOSYNC 11 /* sync (RECNO) */ - -typedef enum { DB_BTREE, DB_HASH, DB_RECNO } DBTYPE; - -/* - * !!! - * The following flags are included in the dbopen(3) call as part of the - * open(2) flags. In order to avoid conflicts with the open flags, start - * at the top of the 16 or 32-bit number space and work our way down. If - * the open flags were significantly expanded in the future, it could be - * a problem. Wish I'd left another flags word in the dbopen call. - * - * !!! - * None of this stuff is implemented yet. The only reason that it's here - * is so that the access methods can skip copying the key/data pair when - * the DB_LOCK flag isn't set. - */ -#if UINT_MAX > 65535 -#define DB_LOCK 0x20000000 /* Do locking. */ -#define DB_SHMEM 0x40000000 /* Use shared memory. */ -#define DB_TXN 0x80000000 /* Do transactions. */ -#else -#define DB_LOCK 0x2000 /* Do locking. */ -#define DB_SHMEM 0x4000 /* Use shared memory. */ -#define DB_TXN 0x8000 /* Do transactions. */ -#endif - -/* Access method description structure. */ -typedef struct __db { - DBTYPE type; /* Underlying db type. */ - int (*close) __P((struct __db *)); - int (*del) __P((const struct __db *, const DBT *, u_int)); - int (*get) __P((const struct __db *, const DBT *, DBT *, u_int)); - int (*put) __P((const struct __db *, DBT *, const DBT *, u_int)); - int (*seq) __P((const struct __db *, DBT *, DBT *, u_int)); - int (*sync) __P((const struct __db *, u_int)); - void *internal; /* Access method private. */ - int (*fd) __P((const struct __db *)); -} DB; - -#define BTREEMAGIC 0x053162 -#define BTREEVERSION 3 - -/* Structure used to pass parameters to the btree routines. */ -typedef struct { -#define R_DUP 0x01 /* duplicate keys */ - u_long flags; - u_int cachesize; /* bytes to cache */ - int maxkeypage; /* maximum keys per page */ - int minkeypage; /* minimum keys per page */ - u_int psize; /* page size */ - int (*compare) /* comparison function */ - __P((const DBT *, const DBT *)); - size_t (*prefix) /* prefix function */ - __P((const DBT *, const DBT *)); - int lorder; /* byte order */ -} BTREEINFO; - -#define HASHMAGIC 0x061561 -#define HASHVERSION 2 - -/* Structure used to pass parameters to the hashing routines. */ -typedef struct { - u_int bsize; /* bucket size */ - u_int ffactor; /* fill factor */ - u_int nelem; /* number of elements */ - u_int cachesize; /* bytes to cache */ - u_int32_t /* hash function */ - (*hash) __P((const void *, size_t)); - int lorder; /* byte order */ -} HASHINFO; - -/* Structure used to pass parameters to the record routines. */ -typedef struct { -#define R_FIXEDLEN 0x01 /* fixed-length records */ -#define R_NOKEY 0x02 /* key not required */ -#define R_SNAPSHOT 0x04 /* snapshot the input */ - u_long flags; - u_int cachesize; /* bytes to cache */ - u_int psize; /* page size */ - int lorder; /* byte order */ - size_t reclen; /* record length (fixed-length records) */ - u_char bval; /* delimiting byte (variable-length records */ - char *bfname; /* btree file name */ -} RECNOINFO; - -#ifdef __DBINTERFACE_PRIVATE -/* - * Little endian <==> big endian 32-bit swap macros. - * M_32_SWAP swap a memory location - * P_32_SWAP swap a referenced memory location - * P_32_COPY swap from one location to another - */ -#define M_32_SWAP(a) { \ - u_int32_t _tmp = a; \ - ((char *)&a)[0] = ((char *)&_tmp)[3]; \ - ((char *)&a)[1] = ((char *)&_tmp)[2]; \ - ((char *)&a)[2] = ((char *)&_tmp)[1]; \ - ((char *)&a)[3] = ((char *)&_tmp)[0]; \ -} -#define P_32_SWAP(a) { \ - u_int32_t _tmp = *(u_int32_t *)a; \ - ((char *)a)[0] = ((char *)&_tmp)[3]; \ - ((char *)a)[1] = ((char *)&_tmp)[2]; \ - ((char *)a)[2] = ((char *)&_tmp)[1]; \ - ((char *)a)[3] = ((char *)&_tmp)[0]; \ -} -#define P_32_COPY(a, b) { \ - ((char *)&(b))[0] = ((char *)&(a))[3]; \ - ((char *)&(b))[1] = ((char *)&(a))[2]; \ - ((char *)&(b))[2] = ((char *)&(a))[1]; \ - ((char *)&(b))[3] = ((char *)&(a))[0]; \ -} - -/* - * Little endian <==> big endian 16-bit swap macros. - * M_16_SWAP swap a memory location - * P_16_SWAP swap a referenced memory location - * P_16_COPY swap from one location to another - */ -#define M_16_SWAP(a) { \ - u_int16_t _tmp = a; \ - ((char *)&a)[0] = ((char *)&_tmp)[1]; \ - ((char *)&a)[1] = ((char *)&_tmp)[0]; \ -} -#define P_16_SWAP(a) { \ - u_int16_t _tmp = *(u_int16_t *)a; \ - ((char *)a)[0] = ((char *)&_tmp)[1]; \ - ((char *)a)[1] = ((char *)&_tmp)[0]; \ -} -#define P_16_COPY(a, b) { \ - ((char *)&(b))[0] = ((char *)&(a))[1]; \ - ((char *)&(b))[1] = ((char *)&(a))[0]; \ -} -#endif - -__BEGIN_DECLS -DB *dbopen __P((const char *, int, int, DBTYPE, const void *)); - -#ifdef __DBINTERFACE_PRIVATE -DB *__bt_open __P((const char *, int, int, const BTREEINFO *, int)); -DB *__hash_open __P((const char *, int, int, const HASHINFO *, int)); -DB *__rec_open __P((const char *, int, int, const RECNOINFO *, int)); -void __dbpanic __P((DB *dbp)); -#endif -__END_DECLS -#endif /* !_DB_H_ */ diff --git a/bsd/include/dirent.h b/bsd/include/dirent.h deleted file mode 100644 index 5e2447f1d..000000000 --- a/bsd/include/dirent.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1989, 1993 - * 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. - * - * @(#)dirent.h 8.2 (Berkeley) 7/28/94 - */ - -#ifndef _DIRENT_H_ -#define _DIRENT_H_ - -/* - * The kernel defines the format of directory entries returned by - * the getdirentries(2) system call. - */ -#include - -#ifdef _POSIX_SOURCE -typedef void * DIR; -#else - -#define d_ino d_fileno /* backward compatibility */ - -/* definitions for library routines operating on directories. */ -#define DIRBLKSIZ 1024 - -/* structure describing an open directory. */ -typedef struct _dirdesc { - int dd_fd; /* file descriptor associated with directory */ - long dd_loc; /* offset in current buffer */ - long dd_size; /* amount of data returned by getdirentries */ - char *dd_buf; /* data buffer */ - int dd_len; /* size of data buffer */ - long dd_seek; /* magic cookie returned by getdirentries */ - long dd_rewind; /* magic cookie for rewinding */ - int dd_flags; /* flags for readdir */ -} DIR; - -#define dirfd(dirp) ((dirp)->dd_fd) - -/* flags for opendir2 */ -#define DTF_HIDEW 0x0001 /* hide whiteout entries */ -#define DTF_NODUP 0x0002 /* don't return duplicate names */ -#define DTF_REWIND 0x0004 /* rewind after reading union stack */ -#define __DTF_READALL 0x0008 /* everything has been read */ - -#ifndef NULL -#define NULL 0 -#endif - -#endif /* _POSIX_SOURCE */ - -#ifndef KERNEL - -#include - -__BEGIN_DECLS -DIR *opendir __P((const char *)); -struct dirent *readdir __P((DIR *)); -void rewinddir __P((DIR *)); -int closedir __P((DIR *)); -#ifndef _POSIX_SOURCE -DIR *__opendir2 __P((const char *, int)); -long telldir __P((const DIR *)); -void seekdir __P((DIR *, long)); -int scandir __P((const char *, struct dirent ***, - int (*)(struct dirent *), int (*)(const void *, const void *))); -int alphasort __P((const void *, const void *)); -int getdirentries __P((int, char *, int, long *)); -#endif /* not POSIX */ -__END_DECLS - -#endif /* !KERNEL */ - -#endif /* !_DIRENT_H_ */ diff --git a/bsd/include/disktab.h b/bsd/include/disktab.h deleted file mode 100644 index 386cb640b..000000000 --- a/bsd/include/disktab.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1983, 1993 - * 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. - * - * @(#)disktab.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _DISKTAB_H_ -#define _DISKTAB_H_ - -/* - * Disk description table, see disktab(5) - */ -#define DISKTAB "/etc/disktab" - -struct disktab { - char *d_name; /* drive name */ - char *d_type; /* drive type */ - int d_secsize; /* sector size in bytes */ - int d_ntracks; /* # tracks/cylinder */ - int d_nsectors; /* # sectors/track */ - int d_ncylinders; /* # cylinders */ - int d_rpm; /* revolutions/minute */ - int d_badsectforw; /* supports DEC bad144 std */ - int d_sectoffset; /* use sect rather than cyl offsets */ - struct partition { - int p_size; /* #sectors in partition */ - short p_bsize; /* block size in bytes */ - short p_fsize; /* frag size in bytes */ - } d_partitions[8]; -}; - -#endif /* !_DISKTAB_H_ */ diff --git a/bsd/include/err.h b/bsd/include/err.h deleted file mode 100644 index 59e6d224b..000000000 --- a/bsd/include/err.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1993 - * 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. - * - * @(#)err.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _ERR_H_ -#define _ERR_H_ - -/* - * Don't use va_list in the err/warn prototypes. Va_list is typedef'd in two - * places ( and ), so if we include one - * of them here we may collide with the utility's includes. It's unreasonable - * for utilities to have to include one of them to include err.h, so we get - * _BSD_VA_LIST_ from and use it. - */ -#include -#include - -__BEGIN_DECLS -__dead void err __P((int, const char *, ...)) __attribute__((__noreturn__)); -__dead void verr __P((int, const char *, _BSD_VA_LIST_)) __attribute__((__noreturn__)); -__dead void errx __P((int, const char *, ...)) __attribute__((__noreturn__)); -__dead void verrx __P((int, const char *, _BSD_VA_LIST_)) __attribute__((__noreturn__)); -void warn __P((const char *, ...)); -void vwarn __P((const char *, _BSD_VA_LIST_)); -void warnx __P((const char *, ...)); -void vwarnx __P((const char *, _BSD_VA_LIST_)); -__END_DECLS - -#endif /* !_ERR_H_ */ diff --git a/bsd/include/errno.h b/bsd/include/errno.h deleted file mode 100644 index 57f2f7b66..000000000 --- a/bsd/include/errno.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -#include - diff --git a/bsd/include/fcntl.h b/bsd/include/fcntl.h deleted file mode 100644 index d936d7062..000000000 --- a/bsd/include/fcntl.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -#include diff --git a/bsd/include/fnmatch.h b/bsd/include/fnmatch.h deleted file mode 100644 index f60424db6..000000000 --- a/bsd/include/fnmatch.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1992, 1993 - * 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. - * - * @(#)fnmatch.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _FNMATCH_H_ -#define _FNMATCH_H_ - -#define FNM_NOMATCH 1 /* Match failed. */ - -#define FNM_NOESCAPE 0x01 /* Disable backslash escaping. */ -#define FNM_PATHNAME 0x02 /* Slash must be matched by slash. */ -#define FNM_PERIOD 0x04 /* Period must be matched by period. */ - -#include - -__BEGIN_DECLS -#ifndef _POSIX_SOURCE -int fnmatch __P((const char *, const char *, int)); -#endif -__END_DECLS - -#endif /* !_FNMATCH_H_ */ diff --git a/bsd/include/fsproperties.h b/bsd/include/fsproperties.h deleted file mode 100644 index 15db66039..000000000 --- a/bsd/include/fsproperties.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#ifndef _FSPROPERTIES_H_ -#define _FSPROPERTIES_H_ - -/* Info plist keys */ -#define kFSMediaTypesKey "FSMediaTypes" -#define kFSPersonalitiesKey "FSPersonalities" - -/* Sub-keys for FSMediaTypes dictionaries */ -#define kFSMediaPropertiesKey "FSMediaProperties" -#define kFSProbeArgumentsKey "FSProbeArguments" -#define kFSProbeExecutableKey "FSProbeExecutable" -#define kFSProbeOrderKey "FSProbeOrder" - -/* Sub-keys for FSPersonalities dictionaries */ -#define kFSFormatArgumentsKey "FSFormatArguments" -#define kFSFormatContentMaskKey "FSFormatContentMask" -#define kFSFormatExecutableKey "FSFormatExecutable" -#define kFSFormatMinimumSizeKey "FSFormatMinimumSize" -#define kFSMountArgumentsKey "FSMountArguments" -#define kFSMountExecutableKey "FSMountExecutable" -#define kFSNameKey "FSName" -#define kFSRepairArgumentsKey "FSRepairArguments" -#define kFSRepairExecutableKey "FSRepairExecutable" -#define kFSVerificationArgumentsKey "FSVerificationArguments" -#define kFSVerificationExecutableKey "FSVerificationExecutable" - -#endif /* _FSPROPERTIES_H_ */ diff --git a/bsd/include/fstab.h b/bsd/include/fstab.h deleted file mode 100644 index 5427d3468..000000000 --- a/bsd/include/fstab.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1980, 1993 - * 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. - * - * @(#)fstab.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _FSTAB_H_ -#define _FSTAB_H_ - -/* - * File system table, see fstab(5). - * - * Used by dump, mount, umount, swapon, fsck, df, ... - * - * For ufs fs_spec field is the block special name. Programs that want to - * use the character special name must create that name by prepending a 'r' - * after the right most slash. Quota files are always named "quotas", so - * if type is "rq", then use concatenation of fs_file and "quotas" to locate - * quota file. - */ -#define _PATH_FSTAB "/etc/fstab" -#define FSTAB "/etc/fstab" /* deprecated */ - -#define FSTAB_RW "rw" /* read/write device */ -#define FSTAB_RQ "rq" /* read/write with quotas */ -#define FSTAB_RO "ro" /* read-only device */ -#define FSTAB_SW "sw" /* swap device */ -#define FSTAB_XX "xx" /* ignore totally */ - -struct fstab { - char *fs_spec; /* block special device name */ - char *fs_file; /* file system path prefix */ - char *fs_vfstype; /* File system type, ufs, nfs */ - char *fs_mntops; /* Mount options ala -o */ - char *fs_type; /* FSTAB_* from fs_mntops */ - int fs_freq; /* dump frequency, in days */ - int fs_passno; /* pass number on parallel dump */ -}; - -#include - -__BEGIN_DECLS -struct fstab *getfsent __P((void)); -struct fstab *getfsspec __P((const char *)); -struct fstab *getfsfile __P((const char *)); -int setfsent __P((void)); -void endfsent __P((void)); -__END_DECLS - -#endif /* !_FSTAB_H_ */ diff --git a/bsd/include/fts.h b/bsd/include/fts.h deleted file mode 100644 index 3311bd3b8..000000000 --- a/bsd/include/fts.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1989, 1993 - * 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. - * - * @(#)fts.h 8.3 (Berkeley) 8/14/94 - */ - -#ifndef _FTS_H_ -#define _FTS_H_ - -typedef struct { - struct _ftsent *fts_cur; /* current node */ - struct _ftsent *fts_child; /* linked list of children */ - struct _ftsent **fts_array; /* sort array */ - dev_t fts_dev; /* starting device # */ - char *fts_path; /* path for this descent */ - int fts_rfd; /* fd for root */ - int fts_pathlen; /* sizeof(path) */ - int fts_nitems; /* elements in the sort array */ - int (*fts_compar)(); /* compare function */ - -#define FTS_COMFOLLOW 0x001 /* follow command line symlinks */ -#define FTS_LOGICAL 0x002 /* logical walk */ -#define FTS_NOCHDIR 0x004 /* don't change directories */ -#define FTS_NOSTAT 0x008 /* don't get stat info */ -#define FTS_PHYSICAL 0x010 /* physical walk */ -#define FTS_SEEDOT 0x020 /* return dot and dot-dot */ -#define FTS_XDEV 0x040 /* don't cross devices */ -#define FTS_WHITEOUT 0x080 /* return whiteout information */ -#define FTS_OPTIONMASK 0x0ff /* valid user option mask */ - -#define FTS_NAMEONLY 0x100 /* (private) child names only */ -#define FTS_STOP 0x200 /* (private) unrecoverable error */ - int fts_options; /* fts_open options, global flags */ -} FTS; - -typedef struct _ftsent { - struct _ftsent *fts_cycle; /* cycle node */ - struct _ftsent *fts_parent; /* parent directory */ - struct _ftsent *fts_link; /* next file in directory */ - long fts_number; /* local numeric value */ - void *fts_pointer; /* local address value */ - char *fts_accpath; /* access path */ - char *fts_path; /* root path */ - int fts_errno; /* errno for this node */ - int fts_symfd; /* fd for symlink */ - u_short fts_pathlen; /* strlen(fts_path) */ - u_short fts_namelen; /* strlen(fts_name) */ - - ino_t fts_ino; /* inode */ - dev_t fts_dev; /* device */ - nlink_t fts_nlink; /* link count */ - -#define FTS_ROOTPARENTLEVEL -1 -#define FTS_ROOTLEVEL 0 - short fts_level; /* depth (-1 to N) */ - -#define FTS_D 1 /* preorder directory */ -#define FTS_DC 2 /* directory that causes cycles */ -#define FTS_DEFAULT 3 /* none of the above */ -#define FTS_DNR 4 /* unreadable directory */ -#define FTS_DOT 5 /* dot or dot-dot */ -#define FTS_DP 6 /* postorder directory */ -#define FTS_ERR 7 /* error; errno is set */ -#define FTS_F 8 /* regular file */ -#define FTS_INIT 9 /* initialized only */ -#define FTS_NS 10 /* stat(2) failed */ -#define FTS_NSOK 11 /* no stat(2) requested */ -#define FTS_SL 12 /* symbolic link */ -#define FTS_SLNONE 13 /* symbolic link without target */ -#define FTS_W 14 /* whiteout object */ - u_short fts_info; /* user flags for FTSENT structure */ - -#define FTS_DONTCHDIR 0x01 /* don't chdir .. to the parent */ -#define FTS_SYMFOLLOW 0x02 /* followed a symlink to get here */ -#define FTS_ISW 0x04 /* this is a whiteout object */ - u_short fts_flags; /* private flags for FTSENT structure */ - -#define FTS_AGAIN 1 /* read node again */ -#define FTS_FOLLOW 2 /* follow symbolic link */ -#define FTS_NOINSTR 3 /* no instructions */ -#define FTS_SKIP 4 /* discard node */ - u_short fts_instr; /* fts_set() instructions */ - - struct stat *fts_statp; /* stat(2) information */ - char fts_name[1]; /* file name */ -} FTSENT; - -#include - -__BEGIN_DECLS -FTSENT *fts_children __P((FTS *, int)); -int fts_close __P((FTS *)); -FTS *fts_open __P((char * const *, int, - int (*)(const FTSENT **, const FTSENT **))); -FTSENT *fts_read __P((FTS *)); -int fts_set __P((FTS *, FTSENT *, int)); -__END_DECLS - -#endif /* !_FTS_H_ */ diff --git a/bsd/include/glob.h b/bsd/include/glob.h deleted file mode 100644 index 9a6d1f028..000000000 --- a/bsd/include/glob.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Guido van Rossum. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)glob.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _GLOB_H_ -#define _GLOB_H_ - -#include - -struct stat; -typedef struct { - int gl_pathc; /* Count of total paths so far. */ - int gl_matchc; /* Count of paths matching pattern. */ - int gl_offs; /* Reserved at beginning of gl_pathv. */ - int gl_flags; /* Copy of flags parameter to glob. */ - char **gl_pathv; /* List of paths matching pattern. */ - /* Copy of errfunc parameter to glob. */ - int (*gl_errfunc) __P((const char *, int)); - - /* - * Alternate filesystem access methods for glob; replacement - * versions of closedir(3), readdir(3), opendir(3), stat(2) - * and lstat(2). - */ - void (*gl_closedir) __P((void *)); - struct dirent *(*gl_readdir) __P((void *)); - void *(*gl_opendir) __P((const char *)); - int (*gl_lstat) __P((const char *, struct stat *)); - int (*gl_stat) __P((const char *, struct stat *)); -} glob_t; - -#define GLOB_APPEND 0x0001 /* Append to output from previous call. */ -#define GLOB_DOOFFS 0x0002 /* Use gl_offs. */ -#define GLOB_ERR 0x0004 /* Return on error. */ -#define GLOB_MARK 0x0008 /* Append / to matching directories. */ -#define GLOB_NOCHECK 0x0010 /* Return pattern itself if nothing matches. */ -#define GLOB_NOSORT 0x0020 /* Don't sort. */ - -#ifndef _POSIX_SOURCE -#define GLOB_ALTDIRFUNC 0x0040 /* Use alternately specified directory funcs. */ -#define GLOB_BRACE 0x0080 /* Expand braces ala csh. */ -#define GLOB_MAGCHAR 0x0100 /* Pattern had globbing characters. */ -#define GLOB_NOMAGIC 0x0200 /* GLOB_NOCHECK without magic chars (csh). */ -#define GLOB_QUOTE 0x0400 /* Quote special chars with \. */ -#define GLOB_TILDE 0x0800 /* Expand tilde names from the passwd file. */ -#endif - -#define GLOB_NOSPACE (-1) /* Malloc call failed. */ -#define GLOB_ABEND (-2) /* Unignored error. */ - -__BEGIN_DECLS -int glob __P((const char *, int, int (*)(const char *, int), glob_t *)); -void globfree __P((glob_t *)); -__END_DECLS - -#endif /* !_GLOB_H_ */ diff --git a/bsd/include/grp.h b/bsd/include/grp.h deleted file mode 100644 index 54828e8ec..000000000 --- a/bsd/include/grp.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, 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. - * - * @(#)grp.h 8.2 (Berkeley) 1/21/94 - */ - -#ifndef _GRP_H_ -#define _GRP_H_ - -#ifndef _POSIX_SOURCE -#define _PATH_GROUP "/etc/group" -#endif - -struct group { - char *gr_name; /* group name */ - char *gr_passwd; /* group password */ - int gr_gid; /* group id */ - char **gr_mem; /* group members */ -}; - -#include - -__BEGIN_DECLS -struct group *getgrgid __P((gid_t)); -struct group *getgrnam __P((const char *)); -#ifndef _POSIX_SOURCE -struct group *getgrent __P((void)); -int setgrent __P((void)); -void endgrent __P((void)); -void setgrfile __P((const char *)); -int setgroupent __P((int)); -#endif -__END_DECLS - -#endif /* !_GRP_H_ */ diff --git a/bsd/include/kvm.h b/bsd/include/kvm.h deleted file mode 100644 index f513cb681..000000000 --- a/bsd/include/kvm.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1989, 1993 - * 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. - * - * @(#)kvm.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _KVM_H_ -#define _KVM_H_ - -/* Default version symbol. */ -#define VRS_SYM "_version" -#define VRS_KEY "VERSION" - -#include -#include - -__BEGIN_DECLS - -typedef struct __kvm kvm_t; - -struct kinfo_proc; -int kvm_close __P((kvm_t *)); -char **kvm_getargv __P((kvm_t *, const struct kinfo_proc *, int)); -char **kvm_getenvv __P((kvm_t *, const struct kinfo_proc *, int)); -char *kvm_geterr __P((kvm_t *)); -int kvm_getloadavg __P((kvm_t *, double [], int)); -char *kvm_getfiles __P((kvm_t *, int, int, int *)); -struct kinfo_proc * - kvm_getprocs __P((kvm_t *, int, int, int *)); -int kvm_nlist __P((kvm_t *, struct nlist *)); -kvm_t *kvm_open - __P((const char *, const char *, const char *, int, const char *)); -kvm_t *kvm_openfiles - __P((const char *, const char *, const char *, int, char *)); -int kvm_read __P((kvm_t *, unsigned long, void *, unsigned int)); -int kvm_write __P((kvm_t *, unsigned long, const void *, unsigned int)); - -__END_DECLS - -#endif /* !_KVM_H_ */ diff --git a/bsd/include/limits.h b/bsd/include/limits.h deleted file mode 100644 index d2879c312..000000000 --- a/bsd/include/limits.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* $NetBSD: limits.h,v 1.8 1996/10/21 05:10:50 jtc Exp $ */ - -/* - * Copyright (c) 1988, 1993 - * 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. - * - * @(#)limits.h 8.2 (Berkeley) 1/4/94 - */ - -#ifndef _LIMITS_H_ -#define _LIMITS_H_ - -#include -#include - -#if !defined(_ANSI_SOURCE) -#define _POSIX_ARG_MAX 4096 -#define _POSIX_CHILD_MAX 6 -#define _POSIX_LINK_MAX 8 -#define _POSIX_MAX_CANON 255 -#define _POSIX_MAX_INPUT 255 -#define _POSIX_NAME_MAX 14 -#define _POSIX_NGROUPS_MAX 0 -#define _POSIX_OPEN_MAX 16 -#define _POSIX_PATH_MAX 255 -#define _POSIX_PIPE_BUF 512 -#define _POSIX_SSIZE_MAX 32767 -#define _POSIX_STREAM_MAX 8 -#define _POSIX_TZNAME_MAX 3 - -#define _POSIX2_BC_BASE_MAX 99 -#define _POSIX2_BC_DIM_MAX 2048 -#define _POSIX2_BC_SCALE_MAX 99 -#define _POSIX2_BC_STRING_MAX 1000 -#define _POSIX2_COLL_WEIGHTS_MAX 2 -#define _POSIX2_EQUIV_CLASS_MAX 2 -#define _POSIX2_EXPR_NEST_MAX 32 -#define _POSIX2_LINE_MAX 2048 -#define _POSIX2_RE_DUP_MAX 255 - -#define PTHREAD_STACK_MIN 8192 -#define PTHREAD_DESTRUCTOR_ITERATIONS 4 -#define PTHREAD_KEYS_MAX 128 - -#endif /* !_ANSI_SOURCE */ - -#if ( !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE) ) || defined(_XOPEN_SOURCE) -#define PASS_MAX 128 - -#define NL_ARGMAX 9 -#define NL_LANGMAX 14 -#define NL_MSGMAX 32767 -#define NL_NMAX 1 -#define NL_SETMAX 255 -#define NL_TEXTMAX 255 -#endif - - -#endif /* !_LIMITS_H_ */ diff --git a/bsd/include/locale.h b/bsd/include/locale.h deleted file mode 100644 index be3a8bdc1..000000000 --- a/bsd/include/locale.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)locale.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _LOCALE_H_ -#define _LOCALE_H_ - -struct lconv { - char *decimal_point; - char *thousands_sep; - char *grouping; - char *int_curr_symbol; - char *currency_symbol; - char *mon_decimal_point; - char *mon_thousands_sep; - char *mon_grouping; - char *positive_sign; - char *negative_sign; - char int_frac_digits; - char frac_digits; - char p_cs_precedes; - char p_sep_by_space; - char n_cs_precedes; - char n_sep_by_space; - char p_sign_posn; - char n_sign_posn; -}; - -#ifndef NULL -#define NULL 0 -#endif - -#define LC_ALL 0 -#define LC_COLLATE 1 -#define LC_CTYPE 2 -#define LC_MONETARY 3 -#define LC_NUMERIC 4 -#define LC_TIME 5 - -#define _LC_LAST 6 /* marks end */ - -#include - -__BEGIN_DECLS -struct lconv *localeconv __P((void)); -char *setlocale __P((int, const char *)); -__END_DECLS - -#endif /* _LOCALE_H_ */ diff --git a/bsd/include/math.h b/bsd/include/math.h deleted file mode 100644 index 8cc72772f..000000000 --- a/bsd/include/math.h +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* Copyright (c) 1995 by NeXT Computer, Inc. All rights reserved. */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -#ifndef _MATH_H_ -#define _MATH_H_ - -/* - * ANSI/POSIX - */ -#define HUGE_VAL 1e500 /* IEEE: positive infinity */ - -/* - * XOPEN/SVID - */ -#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE) -#define M_E 2.7182818284590452354 /* e */ -#define M_LOG2E 1.4426950408889634074 /* log 2e */ -#define M_LOG10E 0.43429448190325182765 /* log 10e */ -#define M_LN2 0.69314718055994530942 /* log e2 */ -#define M_LN10 2.30258509299404568402 /* log e10 */ -#define M_PI 3.14159265358979323846 /* pi */ -#define M_PI_2 1.57079632679489661923 /* pi/2 */ -#define M_PI_4 0.78539816339744830962 /* pi/4 */ -#define M_1_PI 0.31830988618379067154 /* 1/pi */ -#define M_2_PI 0.63661977236758134308 /* 2/pi */ -#define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */ -#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */ -#define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */ - -#define MAXFLOAT ((float)3.40282346638528860e+38) -extern int signgam; - -#if !defined(_XOPEN_SOURCE) -enum fdversion {fdlibm_ieee = -1, fdlibm_svid, fdlibm_xopen, fdlibm_posix}; - -#define _LIB_VERSION_TYPE enum fdversion -#define _LIB_VERSION _fdlib_version - -/* if global variable _LIB_VERSION is not desirable, one may - * change the following to be a constant by: - * #define _LIB_VERSION_TYPE const enum version - * In that case, after one initializes the value _LIB_VERSION (see - * s_lib_version.c) during compile time, it cannot be modified - * in the middle of a program - */ -extern _LIB_VERSION_TYPE _LIB_VERSION; - -#define _IEEE_ fdlibm_ieee -#define _SVID_ fdlibm_svid -#define _XOPEN_ fdlibm_xopen -#define _POSIX_ fdlibm_posix - -#if !defined(__cplusplus) -struct exception { - int type; - char *name; - double arg1; - double arg2; - double retval; -}; -#endif - -#define HUGE MAXFLOAT - -/* - * set X_TLOSS = pi*2**52, which is possibly defined in - * (one may replace the following line by "#include ") - */ - -#define X_TLOSS 1.41484755040568800000e+16 - -#define DOMAIN 1 -#define SING 2 -#define OVERFLOW 3 -#define UNDERFLOW 4 -#define TLOSS 5 -#define PLOSS 6 - -#endif /* !_XOPEN_SOURCE */ -#endif /* !_ANSI_SOURCE && !_POSIX_SOURCE */ - - -#include -__BEGIN_DECLS -/* - * ANSI/POSIX - */ -extern __pure double acos __P((double)); -extern __pure double asin __P((double)); -extern __pure double atan __P((double)); -extern __pure double atan2 __P((double, double)); -extern __pure double cos __P((double)); -extern __pure double sin __P((double)); -extern __pure double tan __P((double)); - -extern __pure double cosh __P((double)); -extern __pure double sinh __P((double)); -extern __pure double tanh __P((double)); - -extern __pure double exp __P((double)); -extern double frexp __P((double, int *)); -extern __pure double ldexp __P((double, int)); -extern __pure double log __P((double)); -extern __pure double log10 __P((double)); -extern double modf __P((double, double *)); - -extern __pure double pow __P((double, double)); -extern __pure double sqrt __P((double)); - -extern __pure double ceil __P((double)); -extern __pure double fabs __P((double)); -extern __pure double floor __P((double)); -extern __pure double fmod __P((double, double)); - -#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE) -extern __pure double erf __P((double)); -extern __pure double erfc __P((double)); -extern double gamma __P((double)); -extern __pure double hypot __P((double, double)); -extern __pure int isinf __P((double)); -extern __pure int isnan __P((double)); -extern __pure int finite __P((double)); -extern __pure double j0 __P((double)); -extern __pure double j1 __P((double)); -extern __pure double jn __P((int, double)); -extern double lgamma __P((double)); -extern __pure double y0 __P((double)); -extern __pure double y1 __P((double)); -extern __pure double yn __P((int, double)); - -#if !defined(_XOPEN_SOURCE) -extern __pure double acosh __P((double)); -extern __pure double asinh __P((double)); -extern __pure double atanh __P((double)); -extern __pure double cbrt __P((double)); -extern __pure double logb __P((double)); -extern __pure double nextafter __P((double, double)); -extern __pure double remainder __P((double, double)); -extern __pure double scalb __P((double, int)); - -#ifndef __cplusplus -extern int matherr __P((struct exception *)); -#endif - -/* - * IEEE Test Vector - */ -extern __pure double significand __P((double)); - -/* - * Functions callable from C, intended to support IEEE arithmetic. - */ -extern __pure double copysign __P((double, double)); -extern __pure int ilogb __P((double)); -extern __pure double rint __P((double)); -extern __pure double scalbn __P((double, int)); - -/* - * BSD math library entry points - */ -extern double cabs(); -extern __pure double drem __P((double, double)); -extern __pure double expm1 __P((double)); -extern __pure double log1p __P((double)); - -/* - * Reentrant version of gamma & lgamma; passes signgam back by reference - * as the second argument; user must allocate space for signgam. - */ -#ifdef _REENTRANT -extern double gamma_r __P((double, int *)); -extern double lgamma_r __P((double, int *)); -#endif /* _REENTRANT */ -#endif /* !_XOPEN_SOURCE */ -#endif /* !_ANSI_SOURCE && !_POSIX_SOURCE */ -__END_DECLS - -#endif /* _MATH_H_ */ diff --git a/bsd/include/memory.h b/bsd/include/memory.h deleted file mode 100644 index 49f8bd0a5..000000000 --- a/bsd/include/memory.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1988, 1993 - * 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. - * - * @(#)memory.h 8.1 (Berkeley) 6/2/93 - */ - -#include diff --git a/bsd/include/mpool.h b/bsd/include/mpool.h deleted file mode 100644 index 13f955171..000000000 --- a/bsd/include/mpool.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)mpool.h 8.1 (Berkeley) 6/2/93 - */ - -/* - * The memory pool scheme is a simple one. Each in memory page is referenced - * by a bucket which is threaded in three ways. All active pages are threaded - * on a hash chain (hashed by the page number) and an lru chain. Inactive - * pages are threaded on a free chain. Each reference to a memory pool is - * handed an MPOOL which is the opaque cookie passed to all of the memory - * routines. - */ -#define HASHSIZE 128 -#define HASHKEY(pgno) ((pgno - 1) % HASHSIZE) - -/* The BKT structures are the elements of the lists. */ -typedef struct BKT { - struct BKT *hnext; /* next hash bucket */ - struct BKT *hprev; /* previous hash bucket */ - struct BKT *cnext; /* next free/lru bucket */ - struct BKT *cprev; /* previous free/lru bucket */ - void *page; /* page */ - pgno_t pgno; /* page number */ - -#define MPOOL_DIRTY 0x01 /* page needs to be written */ -#define MPOOL_PINNED 0x02 /* page is pinned into memory */ - unsigned long flags; /* flags */ -} BKT; - -/* The BKTHDR structures are the heads of the lists. */ -typedef struct BKTHDR { - struct BKT *hnext; /* next hash bucket */ - struct BKT *hprev; /* previous hash bucket */ - struct BKT *cnext; /* next free/lru bucket */ - struct BKT *cprev; /* previous free/lru bucket */ -} BKTHDR; - -typedef struct MPOOL { - BKTHDR free; /* The free list. */ - BKTHDR lru; /* The LRU list. */ - BKTHDR hashtable[HASHSIZE]; /* Hashed list by page number. */ - pgno_t curcache; /* Current number of cached pages. */ - pgno_t maxcache; /* Max number of cached pages. */ - pgno_t npages; /* Number of pages in the file. */ - u_long pagesize; /* File page size. */ - int fd; /* File descriptor. */ - /* Page in conversion routine. */ - void (*pgin) __P((void *, pgno_t, void *)); - /* Page out conversion routine. */ - void (*pgout) __P((void *, pgno_t, void *)); - void *pgcookie; /* Cookie for page in/out routines. */ -#ifdef STATISTICS - unsigned long cachehit; - unsigned long cachemiss; - unsigned long pagealloc; - unsigned long pageflush; - unsigned long pageget; - unsigned long pagenew; - unsigned long pageput; - unsigned long pageread; - unsigned long pagewrite; -#endif -} MPOOL; - -#ifdef __MPOOLINTERFACE_PRIVATE -/* Macros to insert/delete into/from hash chain. */ -#define rmhash(bp) { \ - (bp)->hprev->hnext = (bp)->hnext; \ - (bp)->hnext->hprev = (bp)->hprev; \ -} -#define inshash(bp, pg) { \ - hp = &mp->hashtable[HASHKEY(pg)]; \ - (bp)->hnext = hp->hnext; \ - (bp)->hprev = (struct BKT *)hp; \ - hp->hnext->hprev = (bp); \ - hp->hnext = (bp); \ -} - -/* Macros to insert/delete into/from lru and free chains. */ -#define rmchain(bp) { \ - (bp)->cprev->cnext = (bp)->cnext; \ - (bp)->cnext->cprev = (bp)->cprev; \ -} -#define inschain(bp, dp) { \ - (bp)->cnext = (dp)->cnext; \ - (bp)->cprev = (struct BKT *)(dp); \ - (dp)->cnext->cprev = (bp); \ - (dp)->cnext = (bp); \ -} -#endif - -__BEGIN_DECLS -MPOOL *mpool_open __P((DBT *, int, pgno_t, pgno_t)); -void mpool_filter __P((MPOOL *, void (*)(void *, pgno_t, void *), - void (*)(void *, pgno_t, void *), void *)); -void *mpool_new __P((MPOOL *, pgno_t *)); -void *mpool_get __P((MPOOL *, pgno_t, u_int)); -int mpool_put __P((MPOOL *, void *, u_int)); -int mpool_sync __P((MPOOL *)); -int mpool_close __P((MPOOL *)); -#ifdef STATISTICS -void mpool_stat __P((MPOOL *)); -#endif -__END_DECLS diff --git a/bsd/include/ndbm.h b/bsd/include/ndbm.h deleted file mode 100644 index 033a6ea63..000000000 --- a/bsd/include/ndbm.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Margo Seltzer. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)ndbm.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _NDBM_H_ -#define _NDBM_H_ - -#include - -/* Map dbm interface onto db(3). */ -#define DBM_RDONLY O_RDONLY - -/* Flags to dbm_store(). */ -#define DBM_INSERT 0 -#define DBM_REPLACE 1 - -/* - * The db(3) support for ndbm(3) always appends this suffix to the - * file name to avoid overwriting the user's original database. - */ -#define DBM_SUFFIX ".db" - -typedef struct { - char *dptr; - int dsize; -} datum; - -typedef DB DBM; -#define dbm_pagfno(a) DBM_PAGFNO_NOT_AVAILABLE - -__BEGIN_DECLS -void dbm_close __P((DBM *)); -int dbm_delete __P((DBM *, datum)); -datum dbm_fetch __P((DBM *, datum)); -datum dbm_firstkey __P((DBM *)); -long dbm_forder __P((DBM *, datum)); -datum dbm_nextkey __P((DBM *)); -DBM *dbm_open __P((const char *, int, int)); -int dbm_store __P((DBM *, datum, datum, int)); -int dbm_dirfno __P((DBM *)); -__END_DECLS - -#endif /* !_NDBM_H_ */ diff --git a/bsd/include/netdb.h b/bsd/include/netdb.h deleted file mode 100644 index bad5ac4d9..000000000 --- a/bsd/include/netdb.h +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * ++Copyright++ 1980, 1983, 1988, 1993 - * - - * Copyright (c) 1980, 1983, 1988, 1993 - * 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. - * - - * Portions Copyright (c) 1993 by Digital Equipment Corporation. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies, and that - * the name of Digital Equipment Corporation not be used in advertising or - * publicity pertaining to distribution of the document or software without - * specific, written prior permission. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT - * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - * - - * --Copyright-- - */ - -/* - * @(#)netdb.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _NETDB_H_ -#define _NETDB_H_ - -#include -#include - -#define _PATH_HEQUIV "/etc/hosts.equiv" -#define _PATH_HOSTS "/etc/hosts" -#define _PATH_NETWORKS "/etc/networks" -#define _PATH_PROTOCOLS "/etc/protocols" -#define _PATH_SERVICES "/etc/services" - -extern int h_errno; - -/* - * Structures returned by network data base library. All addresses are - * supplied in host order, and returned in network order (suitable for - * use in system calls). - */ -struct hostent { - char *h_name; /* official name of host */ - char **h_aliases; /* alias list */ - int h_addrtype; /* host address type */ - int h_length; /* length of address */ - char **h_addr_list; /* list of addresses from name server */ -#define h_addr h_addr_list[0] /* address, for backward compatiblity */ -}; - -/* - * Assumption here is that a network number - * fits in an unsigned long -- probably a poor one. - */ -struct netent { - char *n_name; /* official name of net */ - char **n_aliases; /* alias list */ - int n_addrtype; /* net address type */ - unsigned long n_net; /* network # */ -}; - -struct servent { - char *s_name; /* official service name */ - char **s_aliases; /* alias list */ - int s_port; /* port # */ - char *s_proto; /* protocol to use */ -}; - -struct protoent { - char *p_name; /* official protocol name */ - char **p_aliases; /* alias list */ - int p_proto; /* protocol # */ -}; - -struct addrinfo { - int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */ - int ai_family; /* PF_xxx */ - int ai_socktype; /* SOCK_xxx */ - int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ - size_t ai_addrlen; /* length of ai_addr */ - char *ai_canonname; /* canonical name for hostname */ - struct sockaddr *ai_addr; /* binary address */ - struct addrinfo *ai_next; /* next structure in linked list */ -}; - -struct rpcent { - char *r_name; /* name of server for this rpc program */ - char **r_aliases; /* alias list */ - int r_number; /* rpc program number */ -}; - -/* - * Error return codes from gethostbyname() and gethostbyaddr() - * (left in extern int h_errno). - */ - -#define NETDB_INTERNAL -1 /* see errno */ -#define NETDB_SUCCESS 0 /* no problem */ -#define HOST_NOT_FOUND 1 /* Authoritative Answer Host not found */ -#define TRY_AGAIN 2 /* Non-Authoritative Host not found, or SERVERFAIL */ -#define NO_RECOVERY 3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */ -#define NO_DATA 4 /* Valid name, no data record of requested type */ -#define NO_ADDRESS NO_DATA /* no address, look for MX record */ - -/* - * Error return codes from getaddrinfo() - */ -#define EAI_ADDRFAMILY 1 /* address family for hostname not supported */ -#define EAI_AGAIN 2 /* temporary failure in name resolution */ -#define EAI_BADFLAGS 3 /* invalid value for ai_flags */ -#define EAI_FAIL 4 /* non-recoverable failure in name resolution */ -#define EAI_FAMILY 5 /* ai_family not supported */ -#define EAI_MEMORY 6 /* memory allocation failure */ -#define EAI_NODATA 7 /* no address associated with hostname */ -#define EAI_NONAME 8 /* hostname nor servname provided, or not known */ -#define EAI_SERVICE 9 /* servname not supported for ai_socktype */ -#define EAI_SOCKTYPE 10 /* ai_socktype not supported */ -#define EAI_SYSTEM 11 /* system error returned in errno */ -#define EAI_BADHINTS 12 -#define EAI_PROTOCOL 13 -#define EAI_MAX 14 - -/* - * Flag values for getaddrinfo() - */ -#define AI_PASSIVE 0x00000001 /* get address to use bind() */ -#define AI_CANONNAME 0x00000002 /* fill ai_canonname */ -#define AI_NUMERICHOST 0x00000004 /* prevent name resolution */ -/* valid flags for addrinfo */ -#define AI_MASK (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST) - -#define AI_ALL 0x00000100 /* IPv6 and IPv4-mapped (with AI_V4MAPPED) */ -#define AI_V4MAPPED_CFG 0x00000200 /* accept IPv4-mapped if kernel supports */ -#define AI_ADDRCONFIG 0x00000400 /* only if any address is assigned */ -#define AI_V4MAPPED 0x00000800 /* accept IPv4-mapped IPv6 address */ -/* special recommended flags for getipnodebyname */ -#define AI_DEFAULT (AI_V4MAPPED_CFG | AI_ADDRCONFIG) - -/* - * Constants for getnameinfo() - */ -#define NI_MAXHOST 1025 -#define NI_MAXSERV 32 - -/* - * Flag values for getnameinfo() - */ -#define NI_NOFQDN 0x00000001 -#define NI_NUMERICHOST 0x00000002 -#define NI_NAMEREQD 0x00000004 -#define NI_NUMERICSERV 0x00000008 -#define NI_DGRAM 0x00000010 -#define NI_WITHSCOPEID 0x00000020 - -/* - * Scope delimit character - */ -#define SCOPE_DELIMITER '@' - -__BEGIN_DECLS -void endhostent __P((void)); -void endnetent __P((void)); -void endprotoent __P((void)); -void endservent __P((void)); -void freehostent __P((struct hostent *)); -struct hostent *gethostbyaddr __P((const char *, int, int)); -struct hostent *gethostbyname __P((const char *)); -struct hostent *gethostbyname2 __P((const char *, int)); -struct hostent *gethostent __P((void)); -struct hostent *getipnodebyaddr __P((const void *, size_t, int, int *)); -struct hostent *getipnodebyname __P((const char *, int, int, int *)); -struct netent *getnetbyaddr __P((long, int)); -struct netent *getnetbyname __P((const char *)); -struct netent *getnetent __P((void)); -struct protoent *getprotobyname __P((const char *)); -struct protoent *getprotobynumber __P((int)); -struct protoent *getprotoent __P((void)); -struct servent *getservbyname __P((const char *, const char *)); -struct servent *getservbyport __P((int, const char *)); -struct servent *getservent __P((void)); -struct rpcent *getrpcbyname __P((const char *name)); -struct rpcent *getrpcbynumber __P((long number)); -struct rpcent *getrpcent __P((void)); -void setrpcent __P((int stayopen)); -void endrpcent __P((void)); - -void herror __P((const char *)); -char *hstrerror __P((int)); -void sethostent __P((int)); -/* void sethostfile __P((const char *)); */ -void setnetent __P((int)); -void setprotoent __P((int)); -void setservent __P((int)); - -char *gai_strerror __P((int)); -void freeaddrinfo __P((struct addrinfo *)); -int getaddrinfo __P((const char *, const char *, const struct addrinfo *, struct addrinfo **)); -__END_DECLS - -#endif /* !_NETDB_H_ */ diff --git a/bsd/include/nlist.h b/bsd/include/nlist.h deleted file mode 100644 index 828b4a733..000000000 --- a/bsd/include/nlist.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, 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. - * - * @(#)nlist.h 8.2 (Berkeley) 1/21/94 - */ - -#ifndef _NLIST_H_ -#define _NLIST_H_ - -/* - * Symbol table entry format. The #ifdef's are so that programs including - * nlist.h can initialize nlist structures statically. - */ -struct nlist { -#ifdef _AOUT_INCLUDE_ - union { - char *n_name; /* symbol name (in memory) */ - long n_strx; /* file string table offset (on disk) */ - } n_un; -#else - char *n_name; /* symbol name (in memory) */ -#endif - -#define N_UNDF 0x00 /* undefined */ -#define N_ABS 0x02 /* absolute address */ -#define N_TEXT 0x04 /* text segment */ -#define N_DATA 0x06 /* data segment */ -#define N_BSS 0x08 /* bss segment */ -#define N_COMM 0x12 /* common reference */ -#define N_FN 0x1e /* file name */ - -#define N_EXT 0x01 /* external (global) bit, OR'ed in */ -#define N_TYPE 0x1e /* mask for all the type bits */ - unsigned char n_type; /* type defines */ - - char n_other; /* spare */ -#define n_hash n_desc /* used internally by ld(1); XXX */ - short n_desc; /* used by stab entries */ - unsigned long n_value; /* address/value of the symbol */ -}; - -#define N_FORMAT "%08x" /* namelist value format; XXX */ -#define N_STAB 0x0e0 /* mask for debugger symbols -- stab(5) */ - -#include - -__BEGIN_DECLS -int nlist __P((const char *, struct nlist *)); -__END_DECLS - -#endif /* !_NLIST_H_ */ diff --git a/bsd/include/paths.h b/bsd/include/paths.h deleted file mode 100644 index 45a47aa33..000000000 --- a/bsd/include/paths.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* $OpenBSD: paths.h,v 1.10 1997/11/09 00:29:02 bri Exp $ */ -/* $NetBSD: paths.h,v 1.10 1997/04/23 09:41:38 lukem Exp $ */ - -/* - * Copyright (c) 1989, 1993 - * 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. - * - * @(#)paths.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _PATHS_H_ -#define _PATHS_H_ - -/* Default search path. */ -#define _PATH_DEFPATH "/usr/bin:/bin" -/* All standard utilities path. */ -#define _PATH_STDPATH "/usr/bin:/bin:/usr/sbin:/sbin" - -#define _PATH_BSHELL "/bin/sh" -#define _PATH_CONSOLE "/dev/console" -#define _PATH_CSHELL "/bin/csh" -#define _PATH_DEFTAPE "/dev/nrst0" -#define _PATH_DEVDB "/var/run/dev.db" -#define _PATH_DEVNULL "/dev/null" -#define _PATH_DRUM "/dev/drum" -#define _PATH_FSIRAND "/sbin/fsirand" -#define _PATH_KMEM "/dev/kmem" -#define _PATH_KVMDB "/var/db/kvm.db" -#define _PATH_LOCALE "/usr/share/locale" -#define _PATH_MAILDIR "/var/mail" -#define _PATH_MAN "/usr/share/man" -#define _PATH_MEM "/dev/mem" -#define _PATH_NOLOGIN "/etc/nologin" -#define _PATH_RSH "/usr/bin/rsh" -#define _PATH_SENDMAIL "/usr/sbin/sendmail" -#define _PATH_SHELLS "/etc/shells" -#define _PATH_TTY "/dev/tty" -#define _PATH_UNIX "/mach" -#define _PATH_VI "/usr/bin/vi" - -/* Provide trailing slash, since mostly used for building pathnames. */ -#define _PATH_DEV "/dev/" -#define _PATH_TMP "/tmp/" -#define _PATH_UUCPLOCK "/var/spool/lock/" -#define _PATH_VARDB "/var/db/" -#define _PATH_VARRUN "/var/run/" -#define _PATH_VARTMP "/var/tmp/" - -#include - -#endif /* !_PATHS_H_ */ diff --git a/bsd/include/protocols/Makefile b/bsd/include/protocols/Makefile deleted file mode 100644 index 81f0a9363..000000000 --- a/bsd/include/protocols/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -export MakeInc_cmd=${SRCROOT}/makedefs/MakeInc.cmd -export MakeInc_def=${SRCROOT}/makedefs/MakeInc.def -export MakeInc_rule=${SRCROOT}/makedefs/MakeInc.rule -export MakeInc_dir=${SRCROOT}/makedefs/MakeInc.dir - - -include $(MakeInc_cmd) -include $(MakeInc_def) - -INSTINC_SUBDIRS = \ - -INSTINC_SUBDIRS_PPC = \ - -INSTINC_SUBDIRS_I386 = \ - -EXPINC_SUBDIRS = \ - -EXPINC_SUBDIRS_PPC = \ - -EXPINC_SUBDIRS_I386 = \ - -DATAFILES = \ - dumprestore.h routed.h rwhod.h talkd.h timed.h - -INSTALL_MI_LIST = ${DATAFILES} - -INSTALL_MI_DIR = protocols - -EXPORT_MI_LIST = - -EXPORT_MI_DIR = - - -include $(MakeInc_rule) -include $(MakeInc_dir) - - diff --git a/bsd/include/protocols/dumprestore.h b/bsd/include/protocols/dumprestore.h deleted file mode 100644 index 0912e7d66..000000000 --- a/bsd/include/protocols/dumprestore.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1980, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, 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. - * - * @(#)dumprestore.h 8.2 (Berkeley) 1/21/94 - */ - -#ifndef _DUMPRESTORE_H_ -#define _DUMPRESTORE_H_ - -/* - * TP_BSIZE is the size of file blocks on the dump tapes. - * Note that TP_BSIZE must be a multiple of DEV_BSIZE. - * - * NTREC is the number of TP_BSIZE blocks that are written - * in each tape record. HIGHDENSITYTREC is the number of - * TP_BSIZE blocks that are written in each tape record on - * 6250 BPI or higher density tapes. - * - * TP_NINDIR is the number of indirect pointers in a TS_INODE - * or TS_ADDR record. Note that it must be a power of two. - */ -#define TP_BSIZE 1024 -#define NTREC 10 -#define HIGHDENSITYTREC 32 -#define TP_NINDIR (TP_BSIZE/2) -#define LBLSIZE 16 -#define NAMELEN 64 - -#define OFS_MAGIC (int)60011 -#define NFS_MAGIC (int)60012 -#define CHECKSUM (int)84446 - -union u_spcl { - char dummy[TP_BSIZE]; - struct s_spcl { - long c_type; /* record type (see below) */ - time_t c_date; /* date of this dump */ - time_t c_ddate; /* date of previous dump */ - long c_volume; /* dump volume number */ - daddr_t c_tapea; /* logical block of this record */ - ino_t c_inumber; /* number of inode */ - long c_magic; /* magic number (see above) */ - long c_checksum; /* record checksum */ - struct dinode c_dinode; /* ownership and mode of inode */ - long c_count; /* number of valid c_addr entries */ - char c_addr[TP_NINDIR]; /* 1 => data; 0 => hole in inode */ - char c_label[LBLSIZE]; /* dump label */ - long c_level; /* level of this dump */ - char c_filesys[NAMELEN]; /* name of dumpped file system */ - char c_dev[NAMELEN]; /* name of dumpped device */ - char c_host[NAMELEN]; /* name of dumpped host */ - long c_flags; /* additional information */ - long c_firstrec; /* first record on volume */ - long c_spare[32]; /* reserved for future uses */ - } s_spcl; -}; - -/* - * special record types - */ -#define TS_TAPE 1 /* dump tape header */ -#define TS_INODE 2 /* beginning of file record */ -#define TS_ADDR 4 /* continuation of file record */ -#define TS_BITS 3 /* map of inodes on tape */ -#define TS_CLRI 6 /* map of inodes deleted since last dump */ -#define TS_END 5 /* end of volume marker */ - -/* - * flag values - */ -#define DR_NEWHEADER 0x0001 /* new format tape header */ -#define DR_NEWINODEFMT 0x0002 /* new format inodes on tape */ - -#define DUMPOUTFMT "%-16s %c %s" /* for printf */ - /* name, level, ctime(date) */ -#define DUMPINFMT "%16s %c %[^\n]\n" /* inverse for scanf */ - -#endif /* !_DUMPRESTORE_H_ */ diff --git a/bsd/include/protocols/routed.h b/bsd/include/protocols/routed.h deleted file mode 100644 index 95533f387..000000000 --- a/bsd/include/protocols/routed.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1983, 1989, 1993 - * 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. - * - * @(#)routed.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _ROUTED_H_ -#define _ROUTED_H_ - -/* - * Routing Information Protocol - * - * Derived from Xerox NS Routing Information Protocol - * by changing 32-bit net numbers to sockaddr's and - * padding stuff to 32-bit boundaries. - */ -#define RIPVERSION 1 - -struct netinfo { - struct sockaddr rip_dst; /* destination net/host */ - int rip_metric; /* cost of route */ -}; - -struct rip { - u_char rip_cmd; /* request/response */ - u_char rip_vers; /* protocol version # */ - u_char rip_res1[2]; /* pad to 32-bit boundary */ - union { - struct netinfo ru_nets[1]; /* variable length... */ - char ru_tracefile[1]; /* ditto ... */ - } ripun; -#define rip_nets ripun.ru_nets -#define rip_tracefile ripun.ru_tracefile -}; - -/* - * Packet types. - */ -#define RIPCMD_REQUEST 1 /* want info */ -#define RIPCMD_RESPONSE 2 /* responding to request */ -#define RIPCMD_TRACEON 3 /* turn tracing on */ -#define RIPCMD_TRACEOFF 4 /* turn it off */ - -#define RIPCMD_MAX 5 -#ifdef RIPCMDS -char *ripcmds[RIPCMD_MAX] = - { "#0", "REQUEST", "RESPONSE", "TRACEON", "TRACEOFF" }; -#endif - -#define HOPCNT_INFINITY 16 /* per Xerox NS */ -#define MAXPACKETSIZE 512 /* max broadcast size */ - -/* - * Timer values used in managing the routing table. - * Complete tables are broadcast every SUPPLY_INTERVAL seconds. - * If changes occur between updates, dynamic updates containing only changes - * may be sent. When these are sent, a timer is set for a random value - * between MIN_WAITTIME and MAX_WAITTIME, and no additional dynamic updates - * are sent until the timer expires. - * - * Every update of a routing entry forces an entry's timer to be reset. - * After EXPIRE_TIME without updates, the entry is marked invalid, - * but held onto until GARBAGE_TIME so that others may - * see it "be deleted". - */ -#define TIMER_RATE 30 /* alarm clocks every 30 seconds */ - -#define SUPPLY_INTERVAL 30 /* time to supply tables */ -#define MIN_WAITTIME 2 /* min. interval to broadcast changes */ -#define MAX_WAITTIME 5 /* max. time to delay changes */ - -#define EXPIRE_TIME 180 /* time to mark entry invalid */ -#define GARBAGE_TIME 240 /* time to garbage collect */ - -#endif /* !_ROUTED_H_ */ diff --git a/bsd/include/protocols/rwhod.h b/bsd/include/protocols/rwhod.h deleted file mode 100644 index c054e63ef..000000000 --- a/bsd/include/protocols/rwhod.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1983, 1993 - * 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. - * - * @(#)rwhod.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _RWHOD_H_ -#define _RWHOD_H_ - -/* - * rwho protocol packet format. - */ -struct outmp { - char out_line[8]; /* tty name */ - char out_name[8]; /* user id */ - long out_time; /* time on */ -}; - -struct whod { - char wd_vers; /* protocol version # */ - char wd_type; /* packet type, see below */ - char wd_pad[2]; - int wd_sendtime; /* time stamp by sender */ - int wd_recvtime; /* time stamp applied by receiver */ - char wd_hostname[32]; /* hosts's name */ - int wd_loadav[3]; /* load average as in uptime */ - int wd_boottime; /* time system booted */ - struct whoent { - struct outmp we_utmp; /* active tty info */ - int we_idle; /* tty idle time */ - } wd_we[1024 / sizeof (struct whoent)]; -}; - -#define WHODVERSION 1 -#define WHODTYPE_STATUS 1 /* host status */ - -#define _PATH_RWHODIR "/var/rwho" - -#endif /* !_RWHOD_H_ */ diff --git a/bsd/include/protocols/talkd.h b/bsd/include/protocols/talkd.h deleted file mode 100644 index b8a2b97b6..000000000 --- a/bsd/include/protocols/talkd.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1983, 1993 - * 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. - * - * @(#)talkd.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _TALKD_H_ -#define _TALKD_H_ - -/* - * This describes the protocol used by the talk server and clients. - * - * The talk server acts a repository of invitations, responding to - * requests by clients wishing to rendezvous for the purpose of - * holding a conversation. In normal operation, a client, the caller, - * initiates a rendezvous by sending a CTL_MSG to the server of - * type LOOK_UP. This causes the server to search its invitation - * tables to check if an invitation currently exists for the caller - * (to speak to the callee specified in the message). If the lookup - * fails, the caller then sends an ANNOUNCE message causing the server - * to broadcast an announcement on the callee's login ports requesting - * contact. When the callee responds, the local server uses the - * recorded invitation to respond with the appropriate rendezvous - * address and the caller and callee client programs establish a - * stream connection through which the conversation takes place. - */ - -/* - * Client->server request message format. - */ -typedef struct { - u_char vers; /* protocol version */ - u_char type; /* request type, see below */ - u_char answer; /* not used */ - u_char pad; - u_long id_num; /* message id */ - struct osockaddr addr; /* old (4.3) style */ - struct osockaddr ctl_addr; /* old (4.3) style */ - long pid; /* caller's process id */ -#define NAME_SIZE 12 - char l_name[NAME_SIZE];/* caller's name */ - char r_name[NAME_SIZE];/* callee's name */ -#define TTY_SIZE 16 - char r_tty[TTY_SIZE];/* callee's tty name */ -} CTL_MSG; - -/* - * Server->client response message format. - */ -typedef struct { - u_char vers; /* protocol version */ - u_char type; /* type of request message, see below */ - u_char answer; /* respose to request message, see below */ - u_char pad; - u_long id_num; /* message id */ - struct osockaddr addr; /* address for establishing conversation */ -} CTL_RESPONSE; - -#define TALK_VERSION 1 /* protocol version */ - -/* message type values */ -#define LEAVE_INVITE 0 /* leave invitation with server */ -#define LOOK_UP 1 /* check for invitation by callee */ -#define DELETE 2 /* delete invitation by caller */ -#define ANNOUNCE 3 /* announce invitation by caller */ - -/* answer values */ -#define SUCCESS 0 /* operation completed properly */ -#define NOT_HERE 1 /* callee not logged in */ -#define FAILED 2 /* operation failed for unexplained reason */ -#define MACHINE_UNKNOWN 3 /* caller's machine name unknown */ -#define PERMISSION_DENIED 4 /* callee's tty doesn't permit announce */ -#define UNKNOWN_REQUEST 5 /* request has invalid type value */ -#define BADVERSION 6 /* request has invalid protocol version */ -#define BADADDR 7 /* request has invalid addr value */ -#define BADCTLADDR 8 /* request has invalid ctl_addr value */ - -/* - * Operational parameters. - */ -#define MAX_LIFE 60 /* max time daemon saves invitations */ -/* RING_WAIT should be 10's of seconds less than MAX_LIFE */ -#define RING_WAIT 30 /* time to wait before resending invitation */ - -#endif /* !_TALKD_H_ */ diff --git a/bsd/include/protocols/timed.h b/bsd/include/protocols/timed.h deleted file mode 100644 index e3e62639c..000000000 --- a/bsd/include/protocols/timed.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1983, 1993 - * 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. - * - * @(#)timed.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _TIMED_H_ -#define _TIMED_H_ - -/* - * Time Synchronization Protocol - */ - -#define TSPVERSION 1 -#define ANYADDR NULL - -struct tsp { - u_char tsp_type; - u_char tsp_vers; - u_short tsp_seq; - union { - struct timeval tspu_time; - char tspu_hopcnt; - } tsp_u; - char tsp_name[MAXHOSTNAMELEN]; -}; - -#define tsp_time tsp_u.tspu_time -#define tsp_hopcnt tsp_u.tspu_hopcnt - -/* - * Command types. - */ -#define TSP_ANY 0 /* match any types */ -#define TSP_ADJTIME 1 /* send adjtime */ -#define TSP_ACK 2 /* generic acknowledgement */ -#define TSP_MASTERREQ 3 /* ask for master's name */ -#define TSP_MASTERACK 4 /* acknowledge master request */ -#define TSP_SETTIME 5 /* send network time */ -#define TSP_MASTERUP 6 /* inform slaves that master is up */ -#define TSP_SLAVEUP 7 /* slave is up but not polled */ -#define TSP_ELECTION 8 /* advance candidature for master */ -#define TSP_ACCEPT 9 /* support candidature of master */ -#define TSP_REFUSE 10 /* reject candidature of master */ -#define TSP_CONFLICT 11 /* two or more masters present */ -#define TSP_RESOLVE 12 /* masters' conflict resolution */ -#define TSP_QUIT 13 /* reject candidature if master is up */ -#define TSP_DATE 14 /* reset the time (date command) */ -#define TSP_DATEREQ 15 /* remote request to reset the time */ -#define TSP_DATEACK 16 /* acknowledge time setting */ -#define TSP_TRACEON 17 /* turn tracing on */ -#define TSP_TRACEOFF 18 /* turn tracing off */ -#define TSP_MSITE 19 /* find out master's site */ -#define TSP_MSITEREQ 20 /* remote master's site request */ -#define TSP_TEST 21 /* for testing election algo */ -#define TSP_SETDATE 22 /* New from date command */ -#define TSP_SETDATEREQ 23 /* New remote for above */ -#define TSP_LOOP 24 /* loop detection packet */ - -#define TSPTYPENUMBER 25 - -#ifdef TSPTYPES -char *tsptype[TSPTYPENUMBER] = - { "ANY", "ADJTIME", "ACK", "MASTERREQ", "MASTERACK", "SETTIME", "MASTERUP", - "SLAVEUP", "ELECTION", "ACCEPT", "REFUSE", "CONFLICT", "RESOLVE", "QUIT", - "DATE", "DATEREQ", "DATEACK", "TRACEON", "TRACEOFF", "MSITE", "MSITEREQ", - "TEST", "SETDATE", "SETDATEREQ", "LOOP" }; -#endif - -#endif /* !_TIMED_H_ */ diff --git a/bsd/include/pwd.h b/bsd/include/pwd.h deleted file mode 100644 index 5423e3864..000000000 --- a/bsd/include/pwd.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* $NetBSD: pwd.h,v 1.11 1997/08/16 13:47:21 lukem Exp $ */ - -/*- - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, Inc. - * Portions Copyright(C) 1995, Jason Downs. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)pwd.h 8.2 (Berkeley) 1/21/94 - */ - -#ifndef _PWD_H_ -#define _PWD_H_ - -#include - -#ifndef _POSIX_SOURCE -#define _PATH_PASSWD "/etc/passwd" -#define _PATH_MASTERPASSWD "/etc/master.passwd" -#define _PATH_MASTERPASSWD_LOCK "/etc/ptmp" - -#define _PATH_MP_DB "/etc/pwd.db" -#define _PATH_SMP_DB "/etc/spwd.db" - -#define _PATH_PWD_MKDB "/usr/sbin/pwd_mkdb" - -#define _PW_KEYBYNAME '1' /* stored by name */ -#define _PW_KEYBYNUM '2' /* stored by entry in the "file" */ -#define _PW_KEYBYUID '3' /* stored by uid */ - -#define _PASSWORD_EFMT1 '_' /* extended encryption format */ - -#define _PASSWORD_LEN 128 /* max length, not counting NULL */ - -#define _PASSWORD_NOUID 0x01 /* flag for no specified uid. */ -#define _PASSWORD_NOGID 0x02 /* flag for no specified gid. */ -#define _PASSWORD_NOCHG 0x04 /* flag for no specified change. */ -#define _PASSWORD_NOEXP 0x08 /* flag for no specified expire. */ - -#define _PASSWORD_WARNDAYS 14 /* days to warn about expiry */ -#define _PASSWORD_CHGNOW -1 /* special day to force password - * change at next login */ -#endif - -struct passwd { - char *pw_name; /* user name */ - char *pw_passwd; /* encrypted password */ - uid_t pw_uid; /* user uid */ - gid_t pw_gid; /* user gid */ - time_t pw_change; /* password change time */ - char *pw_class; /* user access class */ - char *pw_gecos; /* Honeywell login info */ - char *pw_dir; /* home directory */ - char *pw_shell; /* default shell */ - time_t pw_expire; /* account expiration */ -}; - -#include - -__BEGIN_DECLS -struct passwd *getpwuid __P((uid_t)); -struct passwd *getpwnam __P((const char *)); -#ifndef _POSIX_SOURCE -struct passwd *getpwent __P((void)); -#ifndef _XOPEN_SOURCE -int setpassent __P((int)); -#endif -int setpwent __P((void)); -void endpwent __P((void)); -#endif -__END_DECLS - -#endif /* !_PWD_H_ */ diff --git a/bsd/include/ranlib.h b/bsd/include/ranlib.h deleted file mode 100644 index 543b89abc..000000000 --- a/bsd/include/ranlib.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ -/* - * Copyright (c) 1990, 1982, 1985, 1986, 1988, 1993, 1994 - * 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. - * - * @(#)ranlib.h 8.1 (Berkeley) 6/2/93 - */ -#ifndef _RANLIB_H_ -#define _RANLIB_H_ - -#include /* off_t */ - -/* - * There are two known orders of table of contents for archives. The first is - * the order ranlib(1) originally produced and still produces without any - * options. This table of contents has the archive member name "__.SYMDEF" - * This order has the ranlib structures in the order the objects appear in the - * archive and the symbol names of those objects in the order of symbol table. - * The second know order is sorted by symbol name and is produced with the -s - * option to ranlib(1). This table of contents has the archive member name - * "__.SYMDEF SORTED" and many programs (notably the 1.0 version of ld(1) can't - * tell the difference between names because of the imbedded blank in the name - * and works with either table of contents). This second order is used by the - * post 1.0 link editor to produce faster linking. The original 1.0 version of - * ranlib(1) gets confused when it is run on a archive with the second type of - * table of contents because it and ar(1) which it uses use different ways to - * determined the member name (ar(1) treats all blanks in the name as - * significant and ranlib(1) only checks for the first one). - */ -#define SYMDEF "__.SYMDEF" -#define SYMDEF_SORTED "__.SYMDEF SORTED" - -#define RANLIBMAG "__.SYMDEF" /* archive file name */ -#define RANLIBSKEW 3 /* creation time offset */ - -/* - * Structure of the __.SYMDEF table of contents for an archive. - * __.SYMDEF begins with a long giving the size in bytes of the ranlib - * structures which immediately follow, and then continues with a string - * table consisting of a long giving the number of bytes of strings which - * follow and then the strings themselves. The ran_strx fields index the - * string table whose first byte is numbered 0. - */ -struct ranlib { - union { - off_t ran_strx; /* string table index of */ - char *ran_name; /* symbol defined by */ - } ran_un; - off_t ran_off; /* library member at this offset */ -}; -#endif /* ! _RANLIB_H_ */ diff --git a/bsd/include/regex.h b/bsd/include/regex.h deleted file mode 100644 index ad48247f3..000000000 --- a/bsd/include/regex.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1992 Henry Spencer. - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Henry Spencer of the University of Toronto. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)regex.h 8.2 (Berkeley) 1/3/94 - */ - -#ifndef _REGEX_H_ -#define _REGEX_H_ - -#include - -/* types */ -typedef off_t regoff_t; - -typedef struct { - int re_magic; - size_t re_nsub; /* number of parenthesized subexpressions */ - __const char *re_endp; /* end pointer for REG_PEND */ - struct re_guts *re_g; /* none of your business :-) */ -} regex_t; - -typedef struct { - regoff_t rm_so; /* start of match */ - regoff_t rm_eo; /* end of match */ -} regmatch_t; - -/* regcomp() flags */ -#define REG_BASIC 0000 -#define REG_EXTENDED 0001 -#define REG_ICASE 0002 -#define REG_NOSUB 0004 -#define REG_NEWLINE 0010 -#define REG_NOSPEC 0020 -#define REG_PEND 0040 -#define REG_DUMP 0200 - -/* regerror() flags */ -#define REG_NOMATCH 1 -#define REG_BADPAT 2 -#define REG_ECOLLATE 3 -#define REG_ECTYPE 4 -#define REG_EESCAPE 5 -#define REG_ESUBREG 6 -#define REG_EBRACK 7 -#define REG_EPAREN 8 -#define REG_EBRACE 9 -#define REG_BADBR 10 -#define REG_ERANGE 11 -#define REG_ESPACE 12 -#define REG_BADRPT 13 -#define REG_EMPTY 14 -#define REG_ASSERT 15 -#define REG_INVARG 16 -#define REG_ATOI 255 /* convert name to number (!) */ -#define REG_ITOA 0400 /* convert number to name (!) */ - -/* regexec() flags */ -#define REG_NOTBOL 00001 -#define REG_NOTEOL 00002 -#define REG_STARTEND 00004 -#define REG_TRACE 00400 /* tracing of execution */ -#define REG_LARGE 01000 /* force large representation */ -#define REG_BACKR 02000 /* force use of backref code */ - -__BEGIN_DECLS -int regcomp __P((regex_t *, const char *, int)); -size_t regerror __P((int, const regex_t *, char *, size_t)); -int regexec __P((const regex_t *, - const char *, size_t, regmatch_t [], int)); -void regfree __P((regex_t *)); -__END_DECLS - -#endif /* !_REGEX_H_ */ diff --git a/bsd/include/regexp.h b/bsd/include/regexp.h deleted file mode 100644 index 97ce7e4b8..000000000 --- a/bsd/include/regexp.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1986 by University of Toronto. - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley - * by Henry Spencer. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)regexp.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _REGEXP_H_ -#define _REGEXP_H_ - -/* - * Definitions etc. for regexp(3) routines. - * - * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof], - * not the System V one. - */ -#define NSUBEXP 10 -typedef struct regexp { - char *startp[NSUBEXP]; - char *endp[NSUBEXP]; - char regstart; /* Internal use only. */ - char reganch; /* Internal use only. */ - char *regmust; /* Internal use only. */ - int regmlen; /* Internal use only. */ - char program[1]; /* Unwarranted chumminess with compiler. */ -} regexp; - -#include - -__BEGIN_DECLS -regexp *regcomp __P((const char *)); -int regexec __P((const regexp *, const char *)); -void regsub __P((const regexp *, const char *, char *)); -void regerror __P((const char *)); -__END_DECLS - -#endif /* !_REGEXP_H_ */ diff --git a/bsd/include/resolv.h.kame b/bsd/include/resolv.h.kame deleted file mode 100644 index 25135c01a..000000000 --- a/bsd/include/resolv.h.kame +++ /dev/null @@ -1,356 +0,0 @@ -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/*- - * Copyright (c) 1983, 1987, 1989, 1993 - * 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. - */ - -/* - * Portions Copyright (c) 1996 by Internet Software Consortium. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS - * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE - * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - */ - -/* - * @(#)resolv.h 8.1 (Berkeley) 6/2/93 - * From Id: resolv.h,v 8.12 1998/04/28 19:36:46 halley Exp $ - * $FreeBSD: src/include/resolv.h,v 1.17.2.1 1999/08/29 14:38:55 peter Exp $ - */ - -#ifndef _RESOLV_H_ -#define _RESOLV_H_ - -#include -#include -#include -#include -#include - -/* - * Revision information. This is the release date in YYYYMMDD format. - * It can change every day so the right thing to do with it is use it - * in preprocessor commands such as "#if (__RES > 19931104)". Do not - * compare for equality; rather, use it to determine whether your resolver - * is new enough to contain a certain feature. - */ - -#define __RES 19960801 - -/* - * Resolver configuration file. - * Normally not present, but may contain the address of the - * inital name server(s) to query and the domain search list. - */ - -#ifndef _PATH_RESCONF -#define _PATH_RESCONF "/etc/resolv.conf" -#endif - -/* - * Global defines and variables for resolver stub. - */ -#define MAXNS 3 /* max # name servers we'll track */ -#define MAXDFLSRCH 3 /* # default domain levels to try */ -#define MAXDNSRCH 6 /* max # domains in search path */ -#define LOCALDOMAINPARTS 2 /* min levels in name that is "local" */ -#ifdef __NetBSD__ -#define MAXDNSLUS 4 /* min # of host lookup types */ -#endif - -#define RES_TIMEOUT 5 /* min. seconds between retries */ -#define MAXRESOLVSORT 10 /* number of net to sort on */ -#define RES_MAXNDOTS 15 /* should reflect bit field size */ - -struct __res_state { - int retrans; /* retransmition time interval */ - int retry; /* number of times to retransmit */ - u_long options; /* option flags - see below. */ - int nscount; /* number of name servers */ - struct sockaddr_in - nsaddr_list[MAXNS]; /* address of name server */ -#define nsaddr nsaddr_list[0] /* for backward compatibility */ - u_short id; /* current message id */ - char *dnsrch[MAXDNSRCH+1]; /* components of domain to search */ - char defdname[256]; /* default domain (deprecated) */ - u_long pfcode; /* RES_PRF_ flags - see below. */ - unsigned ndots:4; /* threshold for initial abs. query */ - unsigned nsort:4; /* number of elements in sort_list[] */ - char unused[3]; - struct { - struct in_addr addr; - u_int32_t mask; - } sort_list[MAXRESOLVSORT]; -#ifdef __NetBSD__ - char lookups[MAXDNSLUS]; -#else - char pad[72]; /* on an i386 this means 512b total */ -#endif -}; - -#if 1 /* INET6 */ -/* - * replacement of __res_state, separated to keep binary compatibility. - */ -struct __res_state_ext { - struct sockaddr_storage nsaddr_list[MAXNS]; - struct { - int af; /* address family for addr, mask */ - union { - struct in_addr ina; - struct in6_addr in6a; - } addr, mask; - } sort_list[MAXRESOLVSORT]; -}; -#endif - -/* - * Resolver options (keep these in synch with res_debug.c, please) - */ -#define RES_INIT 0x00000001 /* address initialized */ -#define RES_DEBUG 0x00000002 /* print debug messages */ -#define RES_AAONLY 0x00000004 /* authoritative answers only (!IMPL)*/ -#define RES_USEVC 0x00000008 /* use virtual circuit */ -#define RES_PRIMARY 0x00000010 /* query primary server only (!IMPL) */ -#define RES_IGNTC 0x00000020 /* ignore truncation errors */ -#define RES_RECURSE 0x00000040 /* recursion desired */ -#define RES_DEFNAMES 0x00000080 /* use default domain name */ -#define RES_STAYOPEN 0x00000100 /* Keep TCP socket open */ -#define RES_DNSRCH 0x00000200 /* search up local domain tree */ -#define RES_INSECURE1 0x00000400 /* type 1 security disabled */ -#define RES_INSECURE2 0x00000800 /* type 2 security disabled */ -#define RES_NOALIASES 0x00001000 /* shuts off HOSTALIASES feature */ -#define RES_USE_INET6 0x00002000 /* use/map IPv6 in gethostbyname() */ -#define RES_NOTLDQUERY 0x00004000 /* Don't query TLD names */ - -#define RES_DEFAULT (RES_RECURSE | RES_DEFNAMES | RES_DNSRCH) - -/* - * Resolver "pfcode" values. Used by dig. - */ -#define RES_PRF_STATS 0x00000001 -#define RES_PRF_UPDATE 0x00000002 -#define RES_PRF_CLASS 0x00000004 -#define RES_PRF_CMD 0x00000008 -#define RES_PRF_QUES 0x00000010 -#define RES_PRF_ANS 0x00000020 -#define RES_PRF_AUTH 0x00000040 -#define RES_PRF_ADD 0x00000080 -#define RES_PRF_HEAD1 0x00000100 -#define RES_PRF_HEAD2 0x00000200 -#define RES_PRF_TTLID 0x00000400 -#define RES_PRF_HEADX 0x00000800 -#define RES_PRF_QUERY 0x00001000 -#define RES_PRF_REPLY 0x00002000 -#define RES_PRF_INIT 0x00004000 -/* 0x00008000 */ - -typedef enum { res_goahead, res_nextns, res_modified, res_done, res_error } - res_sendhookact; - -typedef res_sendhookact (*res_send_qhook)__P((struct sockaddr_in * const *ns, - const u_char **query, - int *querylen, - u_char *ans, - int anssiz, - int *resplen)); - -typedef res_sendhookact (*res_send_rhook)__P((const struct sockaddr_in *ns, - const u_char *query, - int querylen, - u_char *ans, - int anssiz, - int *resplen)); - -struct res_sym { - int number; /* Identifying number, like T_MX */ - char * name; /* Its symbolic name, like "MX" */ - char * humanname; /* Its fun name, like "mail exchanger" */ -}; - -extern struct __res_state _res; -#if 1 /* INET6 */ -extern struct __res_state_ext _res_ext; -#endif -extern const struct res_sym __p_class_syms[]; -extern const struct res_sym __p_type_syms[]; - -/* Private routines shared between libc/net, named, nslookup and others. */ -#define res_hnok __res_hnok -#define res_ownok __res_ownok -#define res_mailok __res_mailok -#define res_dnok __res_dnok -#define sym_ston __sym_ston -#define sym_ntos __sym_ntos -#define sym_ntop __sym_ntop -#define b64_ntop __b64_ntop -#define b64_pton __b64_pton -#define loc_ntoa __loc_ntoa -#define loc_aton __loc_aton -#define fp_resstat __fp_resstat -#define p_query __p_query -#define dn_skipname __dn_skipname -#define fp_resstat __fp_resstat -#define fp_query __fp_query -#define fp_nquery __fp_nquery -#define hostalias __hostalias -#define putlong __putlong -#define putshort __putshort -#define p_class __p_class -#define p_time __p_time -#define p_type __p_type -#define p_query __p_query -#define p_cdnname __p_cdnname -#define p_section __p_section -#define p_cdname __p_cdname -#define p_fqnname __p_fqnname -#define p_fqname __p_fqname -#define p_rr __p_rr /* XXX: from FreeBSD2.2.7 */ -#define p_option __p_option -#define p_secstodate __p_secstodate -#define dn_count_labels __dn_count_labels -#define dn_comp __dn_comp -#define dn_expand __dn_expand -#define res_init __res_init -#define res_randomid __res_randomid -#define res_query __res_query -#define res_search __res_search -#define res_querydomain __res_querydomain -#define res_mkquery __res_mkquery -#define res_send __res_send -#define res_isourserver __res_isourserver -#define res_nameinquery __res_nameinquery -#define res_queriesmatch __res_queriesmatch -#define res_close __res_close -#define res_mkupdate __res_mkupdate -#define res_mkupdrec __res_mkupdrec -#define res_freeupdrec __res_freeupdrec - -__BEGIN_DECLS -int res_hnok __P((const char *)); -int res_ownok __P((const char *)); -int res_mailok __P((const char *)); -int res_dnok __P((const char *)); -int sym_ston __P((const struct res_sym *, const char *, int *)); -const char * sym_ntos __P((const struct res_sym *, int, int *)); -const char * sym_ntop __P((const struct res_sym *, int, int *)); -int b64_ntop __P((u_char const *, size_t, char *, size_t)); -int b64_pton __P((char const *, u_char *, size_t)); -int loc_aton __P((const char *, u_char *)); -const char * loc_ntoa __P((const u_char *, char *)); -int dn_skipname __P((const u_char *, const u_char *)); -void fp_resstat __P((struct __res_state *, FILE *)); -void fp_query __P((const u_char *, FILE *)); -void fp_nquery __P((const u_char *, int, FILE *)); -const char * hostalias __P((const char *)); -void putlong __P((u_int32_t, u_char *)); -void putshort __P((u_int16_t, u_char *)); -const char * p_class __P((int)); -const char * p_time __P((u_int32_t)); -const char * p_type __P((int)); -void p_query __P((const u_char *)); -const u_char * p_cdnname __P((const u_char *, const u_char *, int, FILE *)); -const u_char * p_cdname __P((const u_char *, const u_char *, FILE *)); -const u_char * p_fqnname __P((const u_char *, const u_char *, - int, char *, int)); -const u_char * p_fqname __P((const u_char *, const u_char *, FILE *)); -/* XXX: from FreeBSD2.2.7 */ -const u_char * p_rr __P((const u_char *, const u_char *, FILE *)); -const char * p_option __P((u_long)); -char * p_secstodate __P((u_long)); -int dn_count_labels __P((const char *)); -int dn_comp __P((const char *, u_char *, int, - u_char **, u_char **)); -int dn_expand __P((const u_char *, const u_char *, const u_char *, - char *, int)); -int res_init __P((void)); -u_int res_randomid __P((void)); -int res_query __P((const char *, int, int, u_char *, int)); -int res_search __P((const char *, int, int, u_char *, int)); -int res_querydomain __P((const char *, const char *, int, int, - u_char *, int)); -int res_mkquery __P((int, const char *, int, int, const u_char *, - int, const u_char *, u_char *, int)); -int res_send __P((const u_char *, int, u_char *, int)); -int res_isourserver __P((const struct sockaddr_in *)); -int res_nameinquery __P((const char *, int, int, - const u_char *, const u_char *)); -int res_queriesmatch __P((const u_char *, const u_char *, - const u_char *, const u_char *)); -void res_close __P((void)); -const char * p_section __P((int, int)); -/* XXX The following depend on the ns_updrec typedef in arpa/nameser.h */ -#ifdef _ARPA_NAMESER_H_ -int res_update __P((ns_updrec *)); -int res_mkupdate __P((ns_updrec *, u_char *, int)); -ns_updrec * res_mkupdrec __P((int, const char *, u_int, u_int, u_long)); -void res_freeupdrec __P((ns_updrec *)); -#endif -__END_DECLS - -#endif /* !_RESOLV_H_ */ diff --git a/bsd/include/rune.h b/bsd/include/rune.h deleted file mode 100644 index 123a638dc..000000000 --- a/bsd/include/rune.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Paul Borman at Krystal Technologies. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)rune.h 8.1 (Berkeley) 6/27/93 - */ - -#ifndef _RUNE_H_ -#define _RUNE_H_ - -#include -#include - -#define _PATH_LOCALE "/usr/share/locale" - -#define _INVALID_RUNE _CurrentRuneLocale->invalid_rune - -#define __sgetrune _CurrentRuneLocale->sgetrune -#define __sputrune _CurrentRuneLocale->sputrune - -#define sgetrune(s, n, r) (*__sgetrune)((s), (n), (r)) -#define sputrune(c, s, n, r) (*__sputrune)((c), (s), (n), (r)) - -__BEGIN_DECLS -char *mbrune __P((const char *, rune_t)); -char *mbrrune __P((const char *, rune_t)); -char *mbmb __P((const char *, char *)); -long fgetrune __P((FILE *)); -int fputrune __P((rune_t, FILE *)); -int fungetrune __P((rune_t, FILE *)); -int setrunelocale __P((char *)); -void setinvalidrune __P((rune_t)); -__END_DECLS - -#endif /*! _RUNE_H_ */ diff --git a/bsd/include/runetype.h b/bsd/include/runetype.h deleted file mode 100644 index eb0f2c132..000000000 --- a/bsd/include/runetype.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Paul Borman at Krystal Technologies. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)runetype.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _RUNETYPE_H_ -#define _RUNETYPE_H_ - -#include -#include - -#ifndef _BSD_WCHAR_T_DEFINED_ -#define _BSD_WCHAR_T_DEFINED_ -#ifndef _ANSI_SOURCE -typedef _BSD_WCHAR_T_ rune_t; -#endif -typedef _BSD_WCHAR_T_ wchar_t; -#endif - -#define _CACHED_RUNES (1 <<8 ) /* Must be a power of 2 */ -#define _CRMASK (~(_CACHED_RUNES - 1)) - -/* - * The lower 8 bits of runetype[] contain the digit value of the rune. - */ -typedef struct { - rune_t min; /* First rune of the range */ - rune_t max; /* Last rune (inclusive) of the range */ - rune_t map; /* What first maps to in maps */ - unsigned long *types; /* Array of types in range */ -} _RuneEntry; - -typedef struct { - int nranges; /* Number of ranges stored */ - _RuneEntry *ranges; /* Pointer to the ranges */ -} _RuneRange; - -typedef struct { - char magic[8]; /* Magic saying what version we are */ - char encoding[32]; /* ASCII name of this encoding */ - - rune_t (*sgetrune) - __P((const char *, unsigned int, char const **)); - int (*sputrune) - __P((rune_t, char *, unsigned int, char **)); - rune_t invalid_rune; - - unsigned long runetype[_CACHED_RUNES]; - rune_t maplower[_CACHED_RUNES]; - rune_t mapupper[_CACHED_RUNES]; - - /* - * The following are to deal with Runes larger than _CACHED_RUNES - 1. - * Their data is actually contiguous with this structure so as to make - * it easier to read/write from/to disk. - */ - _RuneRange runetype_ext; - _RuneRange maplower_ext; - _RuneRange mapupper_ext; - - void *variable; /* Data which depends on the encoding */ - int variable_len; /* how long that data is */ -} _RuneLocale; - -#define _RUNE_MAGIC_1 "RuneMagi" /* Indicates version 0 of RuneLocale */ - -extern _RuneLocale _DefaultRuneLocale; -extern _RuneLocale *_CurrentRuneLocale; - -#endif /* !_RUNETYPE_H_ */ diff --git a/bsd/include/semaphore.h b/bsd/include/semaphore.h deleted file mode 100644 index bde387f52..000000000 --- a/bsd/include/semaphore.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -#ifndef _BSD_SEMAPHORE_H -#define _BSD_SEMAPHORE_H - -#include -#include - -#include - -#endif /* _BSD_SEMAPHORE_H */ diff --git a/bsd/include/setjmp.h b/bsd/include/setjmp.h deleted file mode 100644 index 51c8fd879..000000000 --- a/bsd/include/setjmp.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -#ifndef _BSD_SETJMP_H -#define _BSD_SETJMP_H - -#include - -#endif /* _BSD_SETJMP_H */ diff --git a/bsd/include/sgtty.h b/bsd/include/sgtty.h deleted file mode 100644 index 59081aa90..000000000 --- a/bsd/include/sgtty.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1985, 1993 - * 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. - * - * @(#)sgtty.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef USE_OLD_TTY -#define USE_OLD_TTY -#endif -#include diff --git a/bsd/include/signal.h b/bsd/include/signal.h deleted file mode 100644 index e89323ff4..000000000 --- a/bsd/include/signal.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)signal.h 8.3 (Berkeley) 3/30/94 - */ - -#ifndef _USER_SIGNAL_H -#define _USER_SIGNAL_H - -#include -#include -#include - -#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE) -extern __const char *__const sys_signame[NSIG]; -extern __const char *__const sys_siglist[NSIG]; -#endif - -__BEGIN_DECLS -int raise __P((int)); -#ifndef _ANSI_SOURCE -int kill __P((pid_t, int)); -int sigaction __P((int, const struct sigaction *, struct sigaction *)); -int sigaddset __P((sigset_t *, int)); -int sigdelset __P((sigset_t *, int)); -int sigemptyset __P((sigset_t *)); -int sigfillset __P((sigset_t *)); -int sigismember __P((const sigset_t *, int)); -int sigpending __P((sigset_t *)); -int sigprocmask __P((int, const sigset_t *, sigset_t *)); -int sigsuspend __P((const sigset_t *)); -#ifndef _POSIX_SOURCE -int killpg __P((pid_t, int)); -int sigblock __P((int)); -int siginterrupt __P((int, int)); -int sigpause __P((int)); -int sigreturn __P((struct sigcontext *)); -int sigsetmask __P((int)); -int sigvec __P((int, struct sigvec *, struct sigvec *)); -void psignal __P((unsigned int, const char *)); -#endif /* !_POSIX_SOURCE */ -#endif /* !_ANSI_SOURCE */ -__END_DECLS - -/* List definitions after function declarations, or Reiser cpp gets upset. */ -#define sigaddset(set, signo) (*(set) |= 1 << ((signo) - 1), 0) -#define sigdelset(set, signo) (*(set) &= ~(1 << ((signo) - 1)), 0) -#define sigemptyset(set) (*(set) = 0, 0) -#define sigfillset(set) (*(set) = ~(sigset_t)0, 0) -#define sigismember(set, signo) ((*(set) & (1 << ((signo) - 1))) != 0) - -#endif /* !_USER_SIGNAL_H */ diff --git a/bsd/include/stab.h b/bsd/include/stab.h deleted file mode 100644 index e4ee83e46..000000000 --- a/bsd/include/stab.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)stab.h 8.1 (Berkeley) 6/2/93 - */ - -/* - * The following are symbols used by various debuggers and by the Pascal - * compiler. Each of them must have one (or more) of the bits defined by - * the N_STAB mask set. - */ - -#define N_GSYM 0x20 /* global symbol */ -#define N_FNAME 0x22 /* F77 function name */ -#define N_FUN 0x24 /* procedure name */ -#define N_STSYM 0x26 /* data segment variable */ -#define N_LCSYM 0x28 /* bss segment variable */ -#define N_MAIN 0x2a /* main function name */ -#define N_PC 0x30 /* global Pascal symbol */ -#define N_RSYM 0x40 /* register variable */ -#define N_SLINE 0x44 /* text segment line number */ -#define N_DSLINE 0x46 /* data segment line number */ -#define N_BSLINE 0x48 /* bss segment line number */ -#define N_SSYM 0x60 /* structure/union element */ -#define N_SO 0x64 /* main source file name */ -#define N_LSYM 0x80 /* stack variable */ -#define N_BINCL 0x82 /* include file beginning */ -#define N_SOL 0x84 /* included source file name */ -#define N_PSYM 0xa0 /* parameter variable */ -#define N_EINCL 0xa2 /* include file end */ -#define N_ENTRY 0xa4 /* alternate entry point */ -#define N_LBRAC 0xc0 /* left bracket */ -#define N_EXCL 0xc2 /* deleted include file */ -#define N_RBRAC 0xe0 /* right bracket */ -#define N_BCOMM 0xe2 /* begin common */ -#define N_ECOMM 0xe4 /* end common */ -#define N_ECOML 0xe8 /* end common (local name) */ -#define N_LENG 0xfe /* length of preceding entry */ diff --git a/bsd/include/stddef.h b/bsd/include/stddef.h deleted file mode 100644 index dceacd35f..000000000 --- a/bsd/include/stddef.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* $OpenBSD: stddef.h,v 1.2 1997/09/21 10:45:52 niklas Exp $ */ -/* $NetBSD: stddef.h,v 1.4 1994/10/26 00:56:26 cgd Exp $ */ - -/*- - * 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. - * - * @(#)stddef.h 5.5 (Berkeley) 4/3/91 - */ - -#ifndef __STDDEF_H__ -#define __STDDEF_H__ - -#include - -typedef _BSD_PTRDIFF_T_ ptrdiff_t; - -#ifndef _BSD_SIZE_T_DEFINED_ -#define _BSD_SIZE_T_DEFINED_ -typedef _BSD_SIZE_T_ size_t; -#endif - -#ifndef _BSD_WCHAR_T_DEFINED_ -#define _BSD_WCHAR_T_DEFINED_ -typedef _BSD_WCHAR_T_ wchar_t; -#ifndef _ANSI_SOURCE -typedef _BSD_RUNE_T_ rune_t; -#endif -#endif - -#ifndef NULL -#define NULL 0 -#endif - -#define offsetof(type, member) ((size_t)(&((type *)0)->member)) - -#endif /* __STDDEF_H__ */ diff --git a/bsd/include/stdio.h b/bsd/include/stdio.h deleted file mode 100644 index 2013f49a6..000000000 --- a/bsd/include/stdio.h +++ /dev/null @@ -1,401 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Chris Torek. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)stdio.h 8.5 (Berkeley) 4/29/95 - */ - -#ifndef _STDIO_H_ -#define _STDIO_H_ - -#if !defined(_ANSI_SOURCE) && !defined(__STRICT_ANSI__) -#include -#endif - -#include - -#include -#ifndef _BSD_SIZE_T_DEFINED_ -#define _BSD_SIZE_T_DEFINED_ -typedef _BSD_SIZE_T_ size_t; -#endif - -#ifndef NULL -#define NULL 0 -#endif - -/* - * This is fairly grotesque, but pure ANSI code must not inspect the - * innards of an fpos_t anyway. The library internally uses off_t, - * which we assume is exactly as big as eight chars. (When we switch - * to gcc 2.4 we will use __attribute__ here.) - * - * WARNING: the alignment constraints on an off_t and the struct below - * differ on (e.g.) the SPARC. Hence, the placement of an fpos_t object - * in a structure will change if fpos_t's are not aligned on 8-byte - * boundaries. THIS IS A CROCK, but for now there is no way around it. - */ -#if !defined(_ANSI_SOURCE) && !defined(__STRICT_ANSI__) -typedef off_t fpos_t; -#else -typedef struct __sfpos { - char _pos[8]; -} fpos_t; -#endif - -#define _FSTDIO /* Define for new stdio with functions. */ - -/* - * NB: to fit things in six character monocase externals, the stdio - * code uses the prefix `__s' for stdio objects, typically followed - * by a three-character attempt at a mnemonic. - */ - -/* stdio buffers */ -struct __sbuf { - unsigned char *_base; - int _size; -}; - -/* - * stdio state variables. - * - * The following always hold: - * - * if (_flags&(__SLBF|__SWR)) == (__SLBF|__SWR), - * _lbfsize is -_bf._size, else _lbfsize is 0 - * if _flags&__SRD, _w is 0 - * if _flags&__SWR, _r is 0 - * - * This ensures that the getc and putc macros (or inline functions) never - * try to write or read from a file that is in `read' or `write' mode. - * (Moreover, they can, and do, automatically switch from read mode to - * write mode, and back, on "r+" and "w+" files.) - * - * _lbfsize is used only to make the inline line-buffered output stream - * code as compact as possible. - * - * _ub, _up, and _ur are used when ungetc() pushes back more characters - * than fit in the current _bf, or when ungetc() pushes back a character - * that does not match the previous one in _bf. When this happens, - * _ub._base becomes non-nil (i.e., a stream has ungetc() data iff - * _ub._base!=NULL) and _up and _ur save the current values of _p and _r. - * - * NB: see WARNING above before changing the layout of this structure! - */ -typedef struct __sFILE { - unsigned char *_p; /* current position in (some) buffer */ - int _r; /* read space left for getc() */ - int _w; /* write space left for putc() */ - short _flags; /* flags, below; this FILE is free if 0 */ - short _file; /* fileno, if Unix descriptor, else -1 */ - struct __sbuf _bf; /* the buffer (at least 1 byte, if !NULL) */ - int _lbfsize; /* 0 or -_bf._size, for inline putc */ - - /* operations */ - void *_cookie; /* cookie passed to io functions */ - int (*_close) __P((void *)); - int (*_read) __P((void *, char *, int)); - fpos_t (*_seek) __P((void *, fpos_t, int)); - int (*_write) __P((void *, const char *, int)); - - /* separate buffer for long sequences of ungetc() */ - struct __sbuf _ub; /* ungetc buffer */ - unsigned char *_up; /* saved _p when _p is doing ungetc data */ - int _ur; /* saved _r when _r is counting ungetc data */ - - /* tricks to meet minimum requirements even when malloc() fails */ - unsigned char _ubuf[3]; /* guarantee an ungetc() buffer */ - unsigned char _nbuf[1]; /* guarantee a getc() buffer */ - - /* separate buffer for fgetln() when line crosses buffer boundary */ - struct __sbuf _lb; /* buffer for fgetln() */ - - /* Unix stdio files get aligned to block boundaries on fseek() */ - int _blksize; /* stat.st_blksize (may be != _bf._size) */ - fpos_t _offset; /* current lseek offset (see WARNING) */ -} FILE; - -__BEGIN_DECLS -extern FILE __sF[]; -__END_DECLS - -#define __SLBF 0x0001 /* line buffered */ -#define __SNBF 0x0002 /* unbuffered */ -#define __SRD 0x0004 /* OK to read */ -#define __SWR 0x0008 /* OK to write */ - /* RD and WR are never simultaneously asserted */ -#define __SRW 0x0010 /* open for reading & writing */ -#define __SEOF 0x0020 /* found EOF */ -#define __SERR 0x0040 /* found error */ -#define __SMBF 0x0080 /* _buf is from malloc */ -#define __SAPP 0x0100 /* fdopen()ed in append mode */ -#define __SSTR 0x0200 /* this is an sprintf/snprintf string */ -#define __SOPT 0x0400 /* do fseek() optimisation */ -#define __SNPT 0x0800 /* do not do fseek() optimisation */ -#define __SOFF 0x1000 /* set iff _offset is in fact correct */ -#define __SMOD 0x2000 /* true => fgetln modified _p text */ - -/* - * The following three definitions are for ANSI C, which took them - * from System V, which brilliantly took internal interface macros and - * made them official arguments to setvbuf(), without renaming them. - * Hence, these ugly _IOxxx names are *supposed* to appear in user code. - * - * Although numbered as their counterparts above, the implementation - * does not rely on this. - */ -#define _IOFBF 0 /* setvbuf should set fully buffered */ -#define _IOLBF 1 /* setvbuf should set line buffered */ -#define _IONBF 2 /* setvbuf should set unbuffered */ - -#define BUFSIZ 1024 /* size of buffer used by setbuf */ -#define EOF (-1) - -/* - * FOPEN_MAX is a minimum maximum, and is the number of streams that - * stdio can provide without attempting to allocate further resources - * (which could fail). Do not use this for anything. - */ - /* must be == _POSIX_STREAM_MAX */ -#define FOPEN_MAX 20 /* must be <= OPEN_MAX */ -#define FILENAME_MAX 1024 /* must be <= PATH_MAX */ - -/* System V/ANSI C; this is the wrong way to do this, do *not* use these. */ -#ifndef _ANSI_SOURCE -#define P_tmpdir "/var/tmp/" -#endif -#define L_tmpnam 1024 /* XXX must be == PATH_MAX */ -#define TMP_MAX 308915776 - -#ifndef SEEK_SET -#define SEEK_SET 0 /* set file offset to offset */ -#endif -#ifndef SEEK_CUR -#define SEEK_CUR 1 /* set file offset to current plus offset */ -#endif -#ifndef SEEK_END -#define SEEK_END 2 /* set file offset to EOF plus offset */ -#endif - -#define stdin (&__sF[0]) -#define stdout (&__sF[1]) -#define stderr (&__sF[2]) - -/* - * Functions defined in ANSI C standard. - */ -__BEGIN_DECLS -void clearerr __P((FILE *)); -int fclose __P((FILE *)); -int feof __P((FILE *)); -int ferror __P((FILE *)); -int fflush __P((FILE *)); -int fgetc __P((FILE *)); -int fgetpos __P((FILE *, fpos_t *)); -char *fgets __P((char *, size_t, FILE *)); -FILE *fopen __P((const char *, const char *)); -int fprintf __P((FILE *, const char *, ...)); -int fputc __P((int, FILE *)); -int fputs __P((const char *, FILE *)); -size_t fread __P((void *, size_t, size_t, FILE *)); -FILE *freopen __P((const char *, const char *, FILE *)); -int fscanf __P((FILE *, const char *, ...)); -int fseek __P((FILE *, long, int)); -int fsetpos __P((FILE *, const fpos_t *)); -long ftell __P((FILE *)); -size_t fwrite __P((const void *, size_t, size_t, FILE *)); -int getc __P((FILE *)); -int getchar __P((void)); -char *gets __P((char *)); -#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE) -extern int sys_nerr; /* perror(3) external variables */ -extern __const char *__const sys_errlist[]; -#endif -void perror __P((const char *)); -int printf __P((const char *, ...)); -int putc __P((int, FILE *)); -int putchar __P((int)); -int puts __P((const char *)); -int remove __P((const char *)); -int rename __P((const char *, const char *)); -void rewind __P((FILE *)); -int scanf __P((const char *, ...)); -void setbuf __P((FILE *, char *)); -int setvbuf __P((FILE *, char *, int, size_t)); -int sprintf __P((char *, const char *, ...)); -int sscanf __P((const char *, const char *, ...)); -FILE *tmpfile __P((void)); -char *tmpnam __P((char *)); -int ungetc __P((int, FILE *)); -int vfprintf __P((FILE *, const char *, _BSD_VA_LIST_)); -int vprintf __P((const char *, _BSD_VA_LIST_)); -int vsprintf __P((char *, const char *, _BSD_VA_LIST_)); -__END_DECLS - -/* - * Functions defined in POSIX 1003.1. - */ -#ifndef _ANSI_SOURCE -#define L_cuserid 9 /* size for cuserid(); UT_NAMESIZE + 1 */ -#define L_ctermid 1024 /* size for ctermid(); PATH_MAX */ - -__BEGIN_DECLS -char *ctermid __P((char *)); -FILE *fdopen __P((int, const char *)); -int fileno __P((FILE *)); -__END_DECLS -#endif /* not ANSI */ - -/* - * Routines that are purely local. - */ -#if !defined (_ANSI_SOURCE) && !defined(_POSIX_SOURCE) -__BEGIN_DECLS -char *fgetln __P((FILE *, size_t *)); -int fpurge __P((FILE *)); -int fseeko __P((FILE *, fpos_t, int)); -fpos_t ftello __P((FILE *)); -int getw __P((FILE *)); -int pclose __P((FILE *)); -FILE *popen __P((const char *, const char *)); -int putw __P((int, FILE *)); -void setbuffer __P((FILE *, char *, int)); -int setlinebuf __P((FILE *)); -char *tempnam __P((const char *, const char *)); -int snprintf __P((char *, size_t, const char *, ...)); -int vsnprintf __P((char *, size_t, const char *, _BSD_VA_LIST_)); -int vscanf __P((const char *, _BSD_VA_LIST_)); -int vsscanf __P((const char *, const char *, _BSD_VA_LIST_)); -FILE *zopen __P((const char *, const char *, int)); -__END_DECLS - -/* - * This is a #define because the function is used internally and - * (unlike vfscanf) the name __svfscanf is guaranteed not to collide - * with a user function when _ANSI_SOURCE or _POSIX_SOURCE is defined. - */ -#define vfscanf __svfscanf - -/* - * Stdio function-access interface. - */ -__BEGIN_DECLS -FILE *funopen __P((const void *, - int (*)(void *, char *, int), - int (*)(void *, const char *, int), - fpos_t (*)(void *, fpos_t, int), - int (*)(void *))); -__END_DECLS -#define fropen(cookie, fn) funopen(cookie, fn, 0, 0, 0) -#define fwopen(cookie, fn) funopen(cookie, 0, fn, 0, 0) -#endif /* !_ANSI_SOURCE && !_POSIX_SOURCE */ - -/* - * Functions internal to the implementation. - */ -__BEGIN_DECLS -int __srget __P((FILE *)); -int __svfscanf __P((FILE *, const char *, _BSD_VA_LIST_)); -int __swbuf __P((int, FILE *)); -__END_DECLS - -/* - * The __sfoo macros are here so that we can - * define function versions in the C library. - */ -#define __sgetc(p) (--(p)->_r < 0 ? __srget(p) : (int)(*(p)->_p++)) -#if defined(__GNUC__) && defined(__STDC__) -static __inline int __sputc(int _c, FILE *_p) { - if (--_p->_w >= 0 || (_p->_w >= _p->_lbfsize && (char)_c != '\n')) - return (*_p->_p++ = _c); - else - return (__swbuf(_c, _p)); -} -#else -/* - * This has been tuned to generate reasonable code on the vax using pcc. - */ -#define __sputc(c, p) \ - (--(p)->_w < 0 ? \ - (p)->_w >= (p)->_lbfsize ? \ - (*(p)->_p = (c)), *(p)->_p != '\n' ? \ - (int)*(p)->_p++ : \ - __swbuf('\n', p) : \ - __swbuf((int)(c), p) : \ - (*(p)->_p = (c), (int)*(p)->_p++)) -#endif - -#define __sfeof(p) (((p)->_flags & __SEOF) != 0) -#define __sferror(p) (((p)->_flags & __SERR) != 0) -#define __sclearerr(p) ((void)((p)->_flags &= ~(__SERR|__SEOF))) -#define __sfileno(p) ((p)->_file) - -#define feof(p) __sfeof(p) -#define ferror(p) __sferror(p) -#define clearerr(p) __sclearerr(p) - -#ifndef _ANSI_SOURCE -#define fileno(p) __sfileno(p) -#endif - -#ifndef lint -#define getc(fp) __sgetc(fp) -#define putc(x, fp) __sputc(x, fp) -#endif /* lint */ - -#define getchar() getc(stdin) -#define putchar(x) putc(x, stdout) -#endif /* _STDIO_H_ */ diff --git a/bsd/include/stdlib.h b/bsd/include/stdlib.h deleted file mode 100644 index b08b58730..000000000 --- a/bsd/include/stdlib.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1990, 1993 - * 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. - * - * @(#)stdlib.h 8.5 (Berkeley) 5/19/95 - */ - -#ifndef _STDLIB_H_ -#define _STDLIB_H_ - -#include - -#ifndef _BSD_SIZE_T_DEFINED_ -#define _BSD_SIZE_T_DEFINED_ -typedef _BSD_SIZE_T_ size_t; -#endif - -#ifndef _BSD_WCHAR_T_DEFINED_ -#define _BSD_WCHAR_T_DEFINED_ -#ifndef _ANSI_SOURCE -typedef _BSD_WCHAR_T_ rune_t; -#endif -typedef _BSD_WCHAR_T_ wchar_t; -#endif - -typedef struct { - int quot; /* quotient */ - int rem; /* remainder */ -} div_t; - -typedef struct { - long quot; /* quotient */ - long rem; /* remainder */ -} ldiv_t; - -#ifndef NULL -#define NULL 0 -#endif - -#define EXIT_FAILURE 1 -#define EXIT_SUCCESS 0 - -#define RAND_MAX 0x7fffffff - -extern int __mb_cur_max; -#define MB_CUR_MAX __mb_cur_max - -#include - -__BEGIN_DECLS -__dead void - abort __P((void)); -__pure int - abs __P((int)); -int atexit __P((void (*)(void))); -double atof __P((const char *)); -int atoi __P((const char *)); -long atol __P((const char *)); -void *bsearch __P((const void *, const void *, size_t, - size_t, int (*)(const void *, const void *))); -void *calloc __P((size_t, size_t)); -__pure div_t - div __P((int, int)); -__dead void - exit __P((int)); -void free __P((void *)); -char *getenv __P((const char *)); -__pure long - labs __P((long)); -__pure ldiv_t - ldiv __P((long, long)); -void *malloc __P((size_t)); -void qsort __P((void *, size_t, size_t, - int (*)(const void *, const void *))); -int rand __P((void)); -void *realloc __P((void *, size_t)); -void srand __P((unsigned)); -double strtod __P((const char *, char **)); -long strtol __P((const char *, char **, int)); -unsigned long - strtoul __P((const char *, char **, int)); -int system __P((const char *)); - -/* These are currently just stubs. */ -int mblen __P((const char *, size_t)); -size_t mbstowcs __P((wchar_t *, const char *, size_t)); -int wctomb __P((char *, wchar_t)); -int mbtowc __P((wchar_t *, const char *, size_t)); -size_t wcstombs __P((char *, const wchar_t *, size_t)); - -#ifndef _ANSI_SOURCE -int putenv __P((const char *)); -int setenv __P((const char *, const char *, int)); -#endif - -#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE) -void *alloca __P((size_t)); /* built-in for gcc */ - /* getcap(3) functions */ -char *getbsize __P((int *, long *)); -char *cgetcap __P((char *, char *, int)); -int cgetclose __P((void)); -int cgetent __P((char **, char **, char *)); -int cgetfirst __P((char **, char **)); -int cgetmatch __P((char *, char *)); -int cgetnext __P((char **, char **)); -int cgetnum __P((char *, char *, long *)); -int cgetset __P((char *)); -int cgetstr __P((char *, char *, char **)); -int cgetustr __P((char *, char *, char **)); - -int daemon __P((int, int)); -char *devname __P((int, int)); -int getloadavg __P((double [], int)); - -char *group_from_gid __P((unsigned long, int)); -int heapsort __P((void *, size_t, size_t, - int (*)(const void *, const void *))); -char *initstate __P((unsigned long, char *, long)); -int mergesort __P((void *, size_t, size_t, - int (*)(const void *, const void *))); -int radixsort __P((const unsigned char **, int, const unsigned char *, - unsigned)); -int sradixsort __P((const unsigned char **, int, const unsigned char *, - unsigned)); -long random __P((void)); -char *realpath __P((const char *, char resolved_path[])); -char *setstate __P((char *)); -void srandom __P((unsigned long)); -char *user_from_uid __P((unsigned long, int)); -#ifndef __STRICT_ANSI__ -long long - strtoq __P((const char *, char **, int)); -unsigned long long - strtouq __P((const char *, char **, int)); -#endif -void unsetenv __P((const char *)); -#endif -__END_DECLS - -#endif /* _STDLIB_H_ */ diff --git a/bsd/include/string.h b/bsd/include/string.h deleted file mode 100644 index 285a6dd80..000000000 --- a/bsd/include/string.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1990, 1993 - * 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. - * - * @(#)string.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _STRING_H_ -#define _STRING_H_ -#include - -#ifndef _BSD_SIZE_T_DEFINED_ -#define _BSD_SIZE_T_DEFINED_ -typedef _BSD_SIZE_T_ size_t; -#endif - -#ifndef NULL -#define NULL 0 -#endif - -#include - -__BEGIN_DECLS -void *memchr __P((const void *, int, size_t)); -int memcmp __P((const void *, const void *, size_t)); -void *memcpy __P((void *, const void *, size_t)); -void *memmove __P((void *, const void *, size_t)); -void *memset __P((void *, int, size_t)); -char *strcat __P((char *, const char *)); -char *strchr __P((const char *, int)); -int strcmp __P((const char *, const char *)); -int strcoll __P((const char *, const char *)); -char *strcpy __P((char *, const char *)); -size_t strcspn __P((const char *, const char *)); -char *strerror __P((int)); -size_t strlen __P((const char *)); -char *strncat __P((char *, const char *, size_t)); -int strncmp __P((const char *, const char *, size_t)); -char *strncpy __P((char *, const char *, size_t)); -char *strpbrk __P((const char *, const char *)); -char *strrchr __P((const char *, int)); -size_t strspn __P((const char *, const char *)); -char *strstr __P((const char *, const char *)); -char *strtok __P((char *, const char *)); -size_t strxfrm __P((char *, const char *, size_t)); - -/* Nonstandard routines */ -#ifndef _ANSI_SOURCE -int bcmp __P((const void *, const void *, size_t)); -void bcopy __P((const void *, void *, size_t)); -void bzero __P((void *, size_t)); -int ffs __P((int)); -char *index __P((const char *, int)); -void *memccpy __P((void *, const void *, int, size_t)); -char *rindex __P((const char *, int)); -int strcasecmp __P((const char *, const char *)); -char *strdup __P((const char *)); -void strmode __P((int, char *)); -int strncasecmp __P((const char *, const char *, size_t)); -char *strsep __P((char **, const char *)); -void swab __P((const void *, void *, size_t)); -#endif -__END_DECLS - -#endif /* _STRING_H_ */ diff --git a/bsd/include/strings.h b/bsd/include/strings.h deleted file mode 100644 index 56c3ae4a6..000000000 --- a/bsd/include/strings.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1990, 1993 - * 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. - * - * @(#)strings.h 8.1 (Berkeley) 6/2/93 - */ - -#include diff --git a/bsd/include/struct.h b/bsd/include/struct.h deleted file mode 100644 index ba8ac59be..000000000 --- a/bsd/include/struct.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1983, 1993 - * 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. - * - * @(#)struct.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _STRUCT_H_ -#define _STRUCT_H_ - -/* Offset of the field in the structure. */ -#define fldoff(name, field) \ - ((int)&(((struct name *)0)->field)) - -/* Size of the field in the structure. */ -#define fldsiz(name, field) \ - (sizeof(((struct name *)0)->field)) - -/* Address of the structure from a field. */ -#define strbase(name, addr, field) \ - ((struct name *)((char *)(addr) - fldoff(name, field))) - -#endif /* !_STRUCT_H_ */ diff --git a/bsd/include/sysexits.h b/bsd/include/sysexits.h deleted file mode 100644 index 0a960a06e..000000000 --- a/bsd/include/sysexits.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1987, 1993 - * 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. - * - * @(#)sysexits.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _SYSEXITS_H_ -#define _SYSEXITS_H_ - -/* - * SYSEXITS.H -- Exit status codes for system programs. - * - * This include file attempts to categorize possible error - * exit statuses for system programs, notably delivermail - * and the Berkeley network. - * - * Error numbers begin at EX__BASE to reduce the possibility of - * clashing with other exit statuses that random programs may - * already return. The meaning of the codes is approximately - * as follows: - * - * EX_USAGE -- The command was used incorrectly, e.g., with - * the wrong number of arguments, a bad flag, a bad - * syntax in a parameter, or whatever. - * EX_DATAERR -- The input data was incorrect in some way. - * This should only be used for user's data & not - * system files. - * EX_NOINPUT -- An input file (not a system file) did not - * exist or was not readable. This could also include - * errors like "No message" to a mailer (if it cared - * to catch it). - * EX_NOUSER -- The user specified did not exist. This might - * be used for mail addresses or remote logins. - * EX_NOHOST -- The host specified did not exist. This is used - * in mail addresses or network requests. - * EX_UNAVAILABLE -- A service is unavailable. This can occur - * if a support program or file does not exist. This - * can also be used as a catchall message when something - * you wanted to do doesn't work, but you don't know - * why. - * EX_SOFTWARE -- An internal software error has been detected. - * This should be limited to non-operating system related - * errors as possible. - * EX_OSERR -- An operating system error has been detected. - * This is intended to be used for such things as "cannot - * fork", "cannot create pipe", or the like. It includes - * things like getuid returning a user that does not - * exist in the passwd file. - * EX_OSFILE -- Some system file (e.g., /etc/passwd, /etc/utmp, - * etc.) does not exist, cannot be opened, or has some - * sort of error (e.g., syntax error). - * EX_CANTCREAT -- A (user specified) output file cannot be - * created. - * EX_IOERR -- An error occurred while doing I/O on some file. - * EX_TEMPFAIL -- temporary failure, indicating something that - * is not really an error. In sendmail, this means - * that a mailer (e.g.) could not create a connection, - * and the request should be reattempted later. - * EX_PROTOCOL -- the remote system returned something that - * was "not possible" during a protocol exchange. - * EX_NOPERM -- You did not have sufficient permission to - * perform the operation. This is not intended for - * file system problems, which should use NOINPUT or - * CANTCREAT, but rather for higher level permissions. - */ - -#define EX_OK 0 /* successful termination */ - -#define EX__BASE 64 /* base value for error messages */ - -#define EX_USAGE 64 /* command line usage error */ -#define EX_DATAERR 65 /* data format error */ -#define EX_NOINPUT 66 /* cannot open input */ -#define EX_NOUSER 67 /* addressee unknown */ -#define EX_NOHOST 68 /* host name unknown */ -#define EX_UNAVAILABLE 69 /* service unavailable */ -#define EX_SOFTWARE 70 /* internal software error */ -#define EX_OSERR 71 /* system error (e.g., can't fork) */ -#define EX_OSFILE 72 /* critical OS file missing */ -#define EX_CANTCREAT 73 /* can't create (user) output file */ -#define EX_IOERR 74 /* input/output error */ -#define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */ -#define EX_PROTOCOL 76 /* remote error in protocol */ -#define EX_NOPERM 77 /* permission denied */ -#define EX_CONFIG 78 /* configuration error */ - -#define EX__MAX 78 /* maximum listed value */ - -#endif /* !_SYSEXITS_H_ */ diff --git a/bsd/include/syslog.h b/bsd/include/syslog.h deleted file mode 100644 index 455fe67ce..000000000 --- a/bsd/include/syslog.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -#include - diff --git a/bsd/include/tar.h b/bsd/include/tar.h deleted file mode 100644 index 37d0edc28..000000000 --- a/bsd/include/tar.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1994 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Chuck Karish of Mindcraft, 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. - * - * @(#)tar.h 8.2 (Berkeley) 1/4/94 - */ - -#ifndef _TAR_H -#define _TAR_H - -#define TMAGIC "ustar" /* ustar and a null */ -#define TMAGLEN 6 -#define TVERSION "00" /* 00 and no null */ -#define TVERSLEN 2 - -/* Values used in typeflag field */ -#define REGTYPE '0' /* Regular file */ -#define AREGTYPE '\0' /* Regular file */ -#define LNKTYPE '1' /* Link */ -#define SYMTYPE '2' /* Reserved */ -#define CHRTYPE '3' /* Character special */ -#define BLKTYPE '4' /* Block special */ -#define DIRTYPE '5' /* Directory */ -#define FIFOTYPE '6' /* FIFO special */ -#define CONTTYPE '7' /* Reserved */ - -/* Bits used in the mode field - values in octal */ -#define TSUID 04000 /* Set UID on execution */ -#define TSGID 02000 /* Set GID on execution */ -#define TSVTX 01000 /* Reserved */ - /* File permissions */ -#define TUREAD 00400 /* Read by owner */ -#define TUWRITE 00200 /* Write by owner */ -#define TUEXEC 00100 /* Execute/Search by owner */ -#define TGREAD 00040 /* Read by group */ -#define TGWRITE 00020 /* Write by group */ -#define TGEXEC 00010 /* Execute/Search by group */ -#define TOREAD 00004 /* Read by other */ -#define TOWRITE 00002 /* Write by other */ -#define TOEXEC 00001 /* Execute/Search by other */ - -#endif diff --git a/bsd/include/termios.h b/bsd/include/termios.h deleted file mode 100644 index 7ab55fe45..000000000 --- a/bsd/include/termios.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -#include - diff --git a/bsd/include/time.h b/bsd/include/time.h deleted file mode 100644 index d5552cb67..000000000 --- a/bsd/include/time.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, 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. - * - * @(#)time.h 8.3 (Berkeley) 1/21/94 - */ - -#ifndef _TIME_H_ -#define _TIME_H_ - -#include - -#ifndef NULL -#define NULL 0 -#endif - -#ifndef _BSD_CLOCK_T_DEFINED_ -#define _BSD_CLOCK_T_DEFINED_ -typedef _BSD_CLOCK_T_ clock_t; -#endif - -#ifndef _BSD_TIME_T_DEFINED_ -#define _BSD_TIME_T_DEFINED_ -typedef _BSD_TIME_T_ time_t; -#endif - -#ifndef _BSD_SIZE_T_DEFINED_ -#define _BSD_SIZE_T_DEFINED_ -typedef _BSD_SIZE_T_ size_t; -#endif - -struct tm { - int tm_sec; /* seconds after the minute [0-60] */ - int tm_min; /* minutes after the hour [0-59] */ - int tm_hour; /* hours since midnight [0-23] */ - int tm_mday; /* day of the month [1-31] */ - int tm_mon; /* months since January [0-11] */ - int tm_year; /* years since 1900 */ - int tm_wday; /* days since Sunday [0-6] */ - int tm_yday; /* days since January 1 [0-365] */ - int tm_isdst; /* Daylight Savings Time flag */ - long tm_gmtoff; /* offset from CUT in seconds */ - char *tm_zone; /* timezone abbreviation */ -}; - -#include /* Include file containing CLK_TCK. */ - -#define CLOCKS_PER_SEC (CLK_TCK) - -#include - -__BEGIN_DECLS -char *asctime __P((const struct tm *)); -clock_t clock __P((void)); -char *ctime __P((const time_t *)); -double difftime __P((time_t, time_t)); -struct tm *gmtime __P((const time_t *)); -struct tm *localtime __P((const time_t *)); -time_t mktime __P((struct tm *)); -size_t strftime __P((char *, size_t, const char *, const struct tm *)); -time_t time __P((time_t *)); - -#ifndef _ANSI_SOURCE -void tzset __P((void)); -#endif /* not ANSI */ - -#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE) -char *timezone __P((int, int)); -void tzsetwall __P((void)); -#endif /* neither ANSI nor POSIX */ -__END_DECLS - -#endif /* !_TIME_H_ */ diff --git a/bsd/include/ttyent.h b/bsd/include/ttyent.h deleted file mode 100644 index 25ace7f44..000000000 --- a/bsd/include/ttyent.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1989, 1993 - * 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. - * - * @(#)ttyent.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _TTYENT_H_ -#define _TTYENT_H_ - -#define _PATH_TTYS "/etc/ttys" - -#define _TTYS_OFF "off" -#define _TTYS_ON "on" -#define _TTYS_SECURE "secure" -#define _TTYS_WINDOW "window" -#define _TTYS_ONERROR "onerror" -#define _TTYS_ONOPTION "onoption" - -struct ttyent { - char *ty_name; /* terminal device name */ - char *ty_getty; /* command to execute, usually getty */ - char *ty_type; /* terminal type for termcap */ -#define TTY_ON 0x01 /* enable logins (start ty_getty program) */ -#define TTY_SECURE 0x02 /* allow uid of 0 to login */ - int ty_status; /* status flags */ - char *ty_window; /* command to start up window manager */ - char *ty_onerror; /* command to execute after getty failure */ - char *ty_onoption; /* command to execute after console login */ - char *ty_comment; /* comment field */ -}; - -#include - -__BEGIN_DECLS -struct ttyent *getttyent __P((void)); -struct ttyent *getttynam __P((const char *)); -int setttyent __P((void)); -int endttyent __P((void)); -__END_DECLS - -#endif /* !_TTYENT_H_ */ diff --git a/bsd/include/tzfile.h b/bsd/include/tzfile.h deleted file mode 100644 index 53bc18087..000000000 --- a/bsd/include/tzfile.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Arthur David Olson of the National Cancer Institute. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)tzfile.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _TZFILE_H_ -#define _TZFILE_H_ - -/* - * Information about time zone files. - */ - /* Time zone object file directory */ -#define TZDIR "/usr/share/zoneinfo" -#define TZDEFAULT "/etc/localtime" -#define TZDEFRULES "posixrules" - -/* -** Each file begins with. . . -*/ - -struct tzhead { - char tzh_reserved[24]; /* reserved for future use */ - char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */ - char tzh_leapcnt[4]; /* coded number of leap seconds */ - char tzh_timecnt[4]; /* coded number of transition times */ - char tzh_typecnt[4]; /* coded number of local time types */ - char tzh_charcnt[4]; /* coded number of abbr. chars */ -}; - -/* -** . . .followed by. . . -** -** tzh_timecnt (char [4])s coded transition times a la time(2) -** tzh_timecnt (unsigned char)s types of local time starting at above -** tzh_typecnt repetitions of -** one (char [4]) coded GMT offset in seconds -** one (unsigned char) used to set tm_isdst -** one (unsigned char) that's an abbreviation list index -** tzh_charcnt (char)s '\0'-terminated zone abbreviations -** tzh_leapcnt repetitions of -** one (char [4]) coded leap second transition times -** one (char [4]) total correction after above -** tzh_ttisstdcnt (char)s indexed by type; if TRUE, transition -** time is standard time, if FALSE, -** transition time is wall clock time -** if absent, transition times are -** assumed to be wall clock time -*/ - -/* -** In the current implementation, "tzset()" refuses to deal with files that -** exceed any of the limits below. -*/ - -/* -** The TZ_MAX_TIMES value below is enough to handle a bit more than a -** year's worth of solar time (corrected daily to the nearest second) or -** 138 years of Pacific Presidential Election time -** (where there are three time zone transitions every fourth year). -*/ -#define TZ_MAX_TIMES 370 - -#define NOSOLAR /* 4BSD doesn't currently handle solar time */ - -#ifndef NOSOLAR -#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */ -#else -#define TZ_MAX_TYPES 20 /* Maximum number of local time types */ -#endif - -#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */ - -#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */ - -#define SECSPERMIN 60 -#define MINSPERHOUR 60 -#define HOURSPERDAY 24 -#define DAYSPERWEEK 7 -#define DAYSPERNYEAR 365 -#define DAYSPERLYEAR 366 -#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) -#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY) -#define MONSPERYEAR 12 - -#define TM_SUNDAY 0 -#define TM_MONDAY 1 -#define TM_TUESDAY 2 -#define TM_WEDNESDAY 3 -#define TM_THURSDAY 4 -#define TM_FRIDAY 5 -#define TM_SATURDAY 6 - -#define TM_JANUARY 0 -#define TM_FEBRUARY 1 -#define TM_MARCH 2 -#define TM_APRIL 3 -#define TM_MAY 4 -#define TM_JUNE 5 -#define TM_JULY 6 -#define TM_AUGUST 7 -#define TM_SEPTEMBER 8 -#define TM_OCTOBER 9 -#define TM_NOVEMBER 10 -#define TM_DECEMBER 11 - -#define TM_YEAR_BASE 1900 - -#define EPOCH_YEAR 1970 -#define EPOCH_WDAY TM_THURSDAY - -/* -** Accurate only for the past couple of centuries; -** that will probably do. -*/ - -#define isleap(y) (((y) % 4) == 0 && ((y) % 100) != 0 || ((y) % 400) == 0) - -#endif /* !_TZFILE_H_ */ diff --git a/bsd/include/unistd.h b/bsd/include/unistd.h deleted file mode 100644 index fb2766835..000000000 --- a/bsd/include/unistd.h +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1998-1999 Apple Computer, Inc. All Rights Reserved - * Copyright (c) 1991, 1993, 1994 - * 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 8.12 (Berkeley) 4/27/95 - * - * Copyright (c) 1998 Apple Compter, Inc. - * All Rights Reserved - */ - -/* History: - 7/14/99 EKN at Apple fixed getdirentriesattr from getdirentryattr - 3/26/98 CHW at Apple added real interface to searchfs call - 3/5/98 CHW at Apple added hfs semantic system calls headers -*/ - -#ifndef _UNISTD_H_ -#define _UNISTD_H_ - -#include -#include -#include - -#define STDIN_FILENO 0 /* standard input file descriptor */ -#define STDOUT_FILENO 1 /* standard output file descriptor */ -#define STDERR_FILENO 2 /* standard error file descriptor */ - -#ifndef NULL -#define NULL 0 /* null pointer constant */ -#endif - -#define _POSIX_THREADS /* We support pthreads */ - -__BEGIN_DECLS -__dead void - _exit __P((int)); -int access __P((const char *, int)); -unsigned int alarm __P((unsigned int)); -int chdir __P((const char *)); -int chown __P((const char *, uid_t, gid_t)); -int close __P((int)); -size_t confstr __P((int, char *, size_t)); -int dup __P((int)); -int dup2 __P((int, int)); -int execl __P((const char *, const char *, ...)); -int execle __P((const char *, const char *, ...)); -int execlp __P((const char *, const char *, ...)); -int execv __P((const char *, char * const *)); -int execve __P((const char *, char * const *, char * const *)); -int execvp __P((const char *, char * const *)); -pid_t fork __P((void)); -long fpathconf __P((int, int)); -char *getcwd __P((char *, size_t)); -gid_t getegid __P((void)); -uid_t geteuid __P((void)); -gid_t getgid __P((void)); -int getgroups __P((int, gid_t [])); -char *getlogin __P((void)); -pid_t getpgrp __P((void)); -pid_t getpid __P((void)); -pid_t getppid __P((void)); -uid_t getuid __P((void)); -int isatty __P((int)); -int link __P((const char *, const char *)); -off_t lseek __P((int, off_t, int)); -long pathconf __P((const char *, int)); -int pause __P((void)); -int pipe __P((int *)); -ssize_t read __P((int, void *, size_t)); -int rmdir __P((const char *)); -int setgid __P((gid_t)); -int setpgid __P((pid_t, pid_t)); -pid_t setsid __P((void)); -int setuid __P((uid_t)); -unsigned int sleep __P((unsigned int)); -long sysconf __P((int)); -pid_t tcgetpgrp __P((int)); -int tcsetpgrp __P((int, pid_t)); -char *ttyname __P((int)); -int unlink __P((const char *)); -ssize_t write __P((int, const void *, size_t)); - -extern char *optarg; /* getopt(3) external variables */ -extern int optind, opterr, optopt, optreset; -int getopt __P((int, char * const [], const char *)); - -#ifndef _POSIX_SOURCE -#ifdef __STDC__ -struct timeval; /* select(2) */ -#endif -int acct __P((const char *)); -int async_daemon __P((void)); -char *brk __P((const char *)); -int chroot __P((const char *)); -char *crypt __P((const char *, const char *)); -int des_cipher __P((const char *, char *, long, int)); -int des_setkey __P((const char *key)); -int encrypt __P((char *, int)); -void endusershell __P((void)); -int exect __P((const char *, char * const *, char * const *)); -int fchdir __P((int)); -int fchown __P((int, int, int)); -int fsync __P((int)); -int ftruncate __P((int, off_t)); -int getdtablesize __P((void)); -int getgrouplist __P((const char *, int, int *, int *)); -long gethostid __P((void)); -int gethostname __P((char *, int)); -mode_t getmode __P((const void *, mode_t)); -__pure int - getpagesize __P((void)); -char *getpass __P((const char *)); -char *getusershell __P((void)); -char *getwd __P((char *)); /* obsoleted by getcwd() */ -int initgroups __P((const char *, int)); -int iruserok __P((unsigned long, int, const char *, const char *)); -int mknod __P((const char *, mode_t, dev_t)); -int mkstemp __P((char *)); -char *mktemp __P((char *)); -int nfssvc __P((int, void *)); -int nice __P((int)); -#if 0 -void psignal __P((unsigned int, const char *)); -extern __const char *__const sys_siglist[]; -#else -#include -#endif -int profil __P((char *, int, int, int)); -int rcmd __P((char **, int, const char *, - const char *, const char *, int *)); -char *re_comp __P((const char *)); -int re_exec __P((const char *)); -int readlink __P((const char *, char *, int)); -int reboot __P((int)); -int revoke __P((const char *)); -int rresvport __P((int *)); -int ruserok __P((const char *, int, const char *, const char *)); -char *sbrk __P((int)); -int select __P((int, fd_set *, fd_set *, fd_set *, struct timeval *)); -int setegid __P((gid_t)); -int seteuid __P((uid_t)); -int setgroups __P((int, const gid_t *)); -void sethostid __P((long)); -int sethostname __P((const char *, int)); -int setkey __P((const char *)); -int setlogin __P((const char *)); -void *setmode __P((const char *)); -int setpgrp __P((pid_t pid, pid_t pgrp)); /* obsoleted by setpgid() */ -int setregid __P((gid_t, gid_t)); -int setreuid __P((uid_t, uid_t)); -int setrgid __P((gid_t)); -int setruid __P((uid_t)); -void setusershell __P((void)); -int swapon __P((const char *)); -int symlink __P((const char *, const char *)); -void sync __P((void)); -int syscall __P((int, ...)); -int truncate __P((const char *, off_t)); -int ttyslot __P((void)); -unsigned int ualarm __P((unsigned int, unsigned int)); -int unwhiteout __P((const char *)); -void usleep __P((unsigned int)); -void *valloc __P((size_t)); /* obsoleted by malloc() */ -pid_t vfork __P((void)); - -extern char *suboptarg; /* getsubopt(3) external variable */ -int getsubopt __P((char **, char * const *, char **)); - -/* HFS & HFS Plus semantics system calls go here */ -int getattrlist __P((const char*,void*,void*,size_t,unsigned long)); -int setattrlist __P((const char*,void*,void*,size_t,unsigned long)); -int exchangedata __P((const char*,const char*,unsigned long)); -int checkuseraccess __P((const char*,uid_t,gid_t*,int,int,unsigned long)); -int getdirentriesattr __P((int,void*,void*,size_t,unsigned long*,unsigned long*,unsigned long*,unsigned long)); -int searchfs __P((const char*,void*,void*,unsigned long,unsigned long,void*)); - -int fsctl __P((const char *,unsigned long,void*,unsigned long)); - - -#endif /* !_POSIX_SOURCE */ -__END_DECLS - -#endif /* !_UNISTD_H_ */ diff --git a/bsd/include/util.h b/bsd/include/util.h deleted file mode 100644 index 42dbdabfa..000000000 --- a/bsd/include/util.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* $NetBSD: util.h,v 1.10 1997/12/01 02:25:46 lukem Exp $ */ - -/*- - * Copyright (c) 1995 - * 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. - */ - -#ifndef _UTIL_H_ -#define _UTIL_H_ - -#include -#include -#include -#include -#include -#include -#include - -#define PIDLOCK_NONBLOCK 1 -#define PIDLOCK_USEHOSTNAME 2 - -#define FPARSELN_UNESCESC 0x01 -#define FPARSELN_UNESCCONT 0x02 -#define FPARSELN_UNESCCOMM 0x04 -#define FPARSELN_UNESCREST 0x08 -#define FPARSELN_UNESCALL 0x0f - -__BEGIN_DECLS -void login __P((struct utmp *)); -int login_tty __P((int)); -int logout __P((const char *)); -void logwtmp __P((const char *, const char *, const char *)); -int pw_lock __P((int retries)); -int pw_mkdb __P((void)); -int pw_abort __P((void)); -void pw_init __P((void)); -void pw_edit __P((int notsetuid, const char *filename)); -void pw_prompt __P((void)); -void pw_copy __P((int ffd, int tfd, struct passwd *pw, - struct passwd *old_pw)); -int pw_scan __P((char *bp, struct passwd *pw, int *flags)); -void pw_error __P((const char *name, int err, int eval)); -int openpty __P((int *, int *, char *, struct termios *, - struct winsize *)); -char *fparseln __P((FILE *, size_t *, size_t *, const char[3], int)); -pid_t forkpty __P((int *, char *, struct termios *, struct winsize *)); -int getmaxpartitions __P((void)); -int getrawpartition __P((void)); -int opendisk __P((const char *, int, char *, size_t, int)); -int pidlock __P((const char *, int, pid_t *, const char *)); -int ttylock __P((const char *, int, pid_t *)); -int ttyunlock __P((const char *)); -int ttyaction __P((char *tty, char *act, char *user)); -struct iovec; -char *ttymsg __P((struct iovec *, int, const char *, int)); -__END_DECLS - -#endif /* !_UTIL_H_ */ diff --git a/bsd/include/utime.h b/bsd/include/utime.h deleted file mode 100644 index 2326c06cc..000000000 --- a/bsd/include/utime.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1990, 1993 - * 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. - * - * @(#)utime.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _UTIME_H_ -#define _UTIME_H_ - -struct utimbuf { - time_t actime; /* Access time */ - time_t modtime; /* Modification time */ -}; - -#include - -__BEGIN_DECLS -int utime __P((const char *, const struct utimbuf *)); -__END_DECLS - -#endif /* !_UTIME_H_ */ diff --git a/bsd/include/utmp.h b/bsd/include/utmp.h deleted file mode 100644 index 0778052a7..000000000 --- a/bsd/include/utmp.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1988, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, 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. - * - * @(#)utmp.h 8.2 (Berkeley) 1/21/94 - */ - -#ifndef _UTMP_H_ -#define _UTMP_H_ - -#define _PATH_UTMP "/var/run/utmp" -#define _PATH_WTMP "/var/log/wtmp" -#define _PATH_LASTLOG "/var/log/lastlog" - -#define UT_NAMESIZE 8 -#define UT_LINESIZE 8 -#define UT_HOSTSIZE 16 - -struct lastlog { - time_t ll_time; - char ll_line[UT_LINESIZE]; - char ll_host[UT_HOSTSIZE]; -}; - -struct utmp { - char ut_line[UT_LINESIZE]; - char ut_name[UT_NAMESIZE]; - char ut_host[UT_HOSTSIZE]; - long ut_time; -}; - -#endif /* !_UTMP_H_ */ diff --git a/bsd/include/vis.h b/bsd/include/vis.h deleted file mode 100644 index b9debf747..000000000 --- a/bsd/include/vis.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1990, 1993 - * 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. - * - * @(#)vis.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _VIS_H_ -#define _VIS_H_ - -/* - * to select alternate encoding format - */ -#define VIS_OCTAL 0x01 /* use octal \ddd format */ -#define VIS_CSTYLE 0x02 /* use \[nrft0..] where appropiate */ - -/* - * to alter set of characters encoded (default is to encode all - * non-graphic except space, tab, and newline). - */ -#define VIS_SP 0x04 /* also encode space */ -#define VIS_TAB 0x08 /* also encode tab */ -#define VIS_NL 0x10 /* also encode newline */ -#define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL) -#define VIS_SAFE 0x20 /* only encode "unsafe" characters */ - -/* - * other - */ -#define VIS_NOSLASH 0x40 /* inhibit printing '\' */ - -/* - * unvis return codes - */ -#define UNVIS_VALID 1 /* character valid */ -#define UNVIS_VALIDPUSH 2 /* character valid, push back passed char */ -#define UNVIS_NOCHAR 3 /* valid sequence, no character produced */ -#define UNVIS_SYNBAD -1 /* unrecognized escape sequence */ -#define UNVIS_ERROR -2 /* decoder in unknown state (unrecoverable) */ - -/* - * unvis flags - */ -#define UNVIS_END 1 /* no more characters */ - -#include - -__BEGIN_DECLS -char *vis __P((char *, int, int, int)); -int strvis __P((char *, const char *, int)); -int strvisx __P((char *, const char *, size_t, int)); -int strunvis __P((char *, const char *)); -int unvis __P((char *, int, int *, int)); -__END_DECLS - -#endif /* !_VIS_H_ */ diff --git a/bsd/isofs/cd9660/cd9660_mount.h b/bsd/isofs/cd9660/cd9660_mount.h index 9fbf38172..caa7e5c85 100644 --- a/bsd/isofs/cd9660/cd9660_mount.h +++ b/bsd/isofs/cd9660/cd9660_mount.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -59,6 +59,12 @@ * @(#)cd9660_mount.h 8.1 (Berkeley) 5/24/95 */ +#ifndef __ISOFS_CD9660_CD9660_MOUNT_H__ +#define __ISOFS_CD9660_CD9660_MOUNT_H__ + +#include + +#ifdef __APPLE_API_UNSTABLE /* * Arguments to mount ISO 9660 filesystems. */ @@ -72,3 +78,6 @@ struct iso_args { #define ISOFSMNT_GENS 0x00000002 /* enable generation numbers */ #define ISOFSMNT_EXTATT 0x00000004 /* enable extended attributes */ #define ISOFSMNT_NOJOLIET 0x00000008 /* disable Joliet Ext.*/ + +#endif /* __APPLE_API_UNSTABLE */ +#endif /* __ISOFS_CD9660_CD9660_MOUNT_H__ */ diff --git a/bsd/isofs/cd9660/cd9660_node.h b/bsd/isofs/cd9660/cd9660_node.h index 79c64af76..78f1239c3 100644 --- a/bsd/isofs/cd9660/cd9660_node.h +++ b/bsd/isofs/cd9660/cd9660_node.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -63,6 +63,9 @@ #ifndef _CD9660_NODE_H_ #define _CD9660_NODE_H_ +#include + +#ifdef __APPLE_API_PRIVATE /* * Theoretically, directories can be more than 2Gb in length, * however, in practice this seems unlikely. So, we define @@ -189,4 +192,5 @@ struct iso_dnode *iso_dmap __P((dev_t, ino_t, int)); void iso_dunmap __P((dev_t)); #endif +#endif /* __APPLE_API_PRIVATE */ #endif /* ! _CD9660_NODE_H_ */ diff --git a/bsd/isofs/cd9660/cd9660_rrip.h b/bsd/isofs/cd9660/cd9660_rrip.h index 4e62dc4e7..4a3c17192 100644 --- a/bsd/isofs/cd9660/cd9660_rrip.h +++ b/bsd/isofs/cd9660/cd9660_rrip.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -60,7 +60,12 @@ * * @(#)cd9660_rrip.h 8.2 (Berkeley) 12/5/94 */ +#ifndef __ISOFS_CD9660_CD9660_RRIP_H__ +#define __ISOFS_CD9660_CD9660_RRIP_H__ +#include + +#ifdef __APPLE_API_PRIVATE typedef struct { char type [ISODCL ( 0, 1)]; u_char length [ISODCL ( 2, 2)]; /* 711 */ @@ -161,3 +166,6 @@ typedef struct { char offset [ISODCL ( 12, 19)]; char length [ISODCL ( 20, 27)]; } ISO_RRIP_CONT; + +#endif /* __APPLE_API_PRIVATE */ +#endif /* __ISOFS_CD9660_CD9660_RRIP_H__ */ diff --git a/bsd/isofs/cd9660/cd9660_vfsops.c b/bsd/isofs/cd9660/cd9660_vfsops.c index ea7221a15..b053db39e 100644 --- a/bsd/isofs/cd9660/cd9660_vfsops.c +++ b/bsd/isofs/cd9660/cd9660_vfsops.c @@ -160,6 +160,7 @@ cd9660_mountroot() args.flags = ISOFSMNT_ROOT; args.ssector = 0; if ((error = iso_mountfs(rootvp, mp, p, &args))) { + vrele(rootvp); /* release the reference from bdevvp() */ FREE_ZONE(mp, sizeof (struct mount), M_MOUNT); return (error); } @@ -603,11 +604,14 @@ cd9660_unmount(mp, mntflags, p) { register struct iso_mnt *isomp; int error, flags = 0; + int force = 0; - if ( (mntflags & MNT_FORCE) ) + if ( (mntflags & MNT_FORCE) ) { flags |= FORCECLOSE; + force = 1; + } - if ( (error = vflush(mp, NULLVP, flags)) ) + if ( (error = vflush(mp, NULLVP, flags)) && !force ) return (error); isomp = VFSTOISOFS(mp); @@ -619,12 +623,14 @@ cd9660_unmount(mp, mntflags, p) isomp->im_devvp->v_specflags &= ~SI_MOUNTEDON; error = VOP_CLOSE(isomp->im_devvp, FREAD, NOCRED, p); + if (error && !force ) + return(error); + vrele(isomp->im_devvp); FREE((caddr_t)isomp, M_ISOFSMNT); mp->mnt_data = (qaddr_t)0; mp->mnt_flag &= ~MNT_LOCAL; - - return (error); + return (0); } /* diff --git a/bsd/isofs/cd9660/iso.h b/bsd/isofs/cd9660/iso.h index 55fca26c0..1b69d791c 100644 --- a/bsd/isofs/cd9660/iso.h +++ b/bsd/isofs/cd9660/iso.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -63,6 +63,9 @@ #ifndef _ISO_H_ #define _ISO_H_ +#include + +#ifdef __APPLE_API_PRIVATE #define ISODCL(from, to) (to - from + 1) struct iso_volume_descriptor { @@ -396,4 +399,5 @@ void packattrblk __P((struct attrlist *alist, struct vnode *vp, */ #define ASSOCCHAR '=' +#endif /* __APPLE_API_PRIVATE */ #endif /* ! _ISO_H_ */ diff --git a/bsd/isofs/cd9660/iso_rrip.h b/bsd/isofs/cd9660/iso_rrip.h index 08e9f4ec6..5081d1bdc 100644 --- a/bsd/isofs/cd9660/iso_rrip.h +++ b/bsd/isofs/cd9660/iso_rrip.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -60,8 +60,13 @@ * * @(#)iso_rrip.h 8.2 (Berkeley) 1/23/94 */ +#ifndef __ISOFS_CD9660_ISO_RRIP_H__ +#define __ISOFS_CD9660_ISO_RRIP_H__ +#include + +#ifdef __APPLE_API_PRIVATE /* * Analyze function flag (similar to RR field bits) */ @@ -104,3 +109,5 @@ int cd9660_rrip_getsymname __P((struct iso_directory_record *isodir, struct iso_mnt *imp)); int cd9660_rrip_offset __P((struct iso_directory_record *isodir, struct iso_mnt *imp)); +#endif /* __APPLE_API_PRIVATE */ +#endif /* __ISOFS_CD9660_ISO_RRIP_H__ */ diff --git a/bsd/kern/ast.h b/bsd/kern/ast.h index 1ebbe2c1c..f2b6aa07e 100644 --- a/bsd/kern/ast.h +++ b/bsd/kern/ast.h @@ -36,12 +36,8 @@ extern thread_apc_handler_t bsd_ast; #else /* !BSD_USE_APC */ -#define AST_NONE 0 -#define AST_BSD 0x80 -#define AST_BSD_INIT 0x100 - -extern void ast_on(int); -extern thread_ast_set(thread_act_t, int); +extern void astbsd_on(void); +extern void act_set_astbsd(thread_act_t); extern void bsd_ast(thread_act_t); #endif /* !BSD_USE_APC */ diff --git a/bsd/kern/bsd_init.c b/bsd/kern/bsd_init.c index 6a055af65..1b81ced7b 100644 --- a/bsd/kern/bsd_init.c +++ b/bsd/kern/bsd_init.c @@ -114,7 +114,11 @@ #include #include +#include +#include + extern shared_region_mapping_t system_shared_region; +extern int app_profile; /* on/off switch for pre-heat cache */ char copyright[] = "Copyright (c) 1982, 1986, 1989, 1991, 1993\n\tThe Regents of the University of California. All rights reserved.\n\n"; @@ -132,18 +136,6 @@ struct pstats pstats0; struct sigacts sigacts0; struct proc *kernproc, *initproc; - -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]; -long dk_bps[DK_NDRIVE]; - -int dk_busy; -int dk_ndrive; - long tk_cancc; long tk_nin; long tk_nout; @@ -166,9 +158,6 @@ int domainnamelen; char rootdevice[16]; /* hfs device names have at least 9 chars */ struct timeval boottime; /* GRODY! This has to go... */ -#if FIXME /* [ */ -struct timeval time; -#endif /* FIXME ] */ #ifdef KMEMSTATS struct kmemstats kmemstats[M_LAST]; @@ -187,8 +176,9 @@ int cmask = CMASK; int parse_bsd_args(void); extern int bsd_hardclockinit; -extern vm_address_t bsd_init_task; +extern task_t bsd_init_task; extern char init_task_failure_data[]; +extern void time_zone_slock_init(void); funnel_t * kernel_flock; funnel_t * network_flock; @@ -225,7 +215,6 @@ proc_name(s, p) length + 1); } - /* To allow these values to be patched, they're globals here */ #include struct rlimit vm_initial_limit_stack = { DFLSSIZ, MAXSSIZ }; @@ -233,15 +222,13 @@ struct rlimit vm_initial_limit_data = { DFLDSIZ, MAXDSIZ }; struct rlimit vm_initial_limit_core = { DFLCSIZ, MAXCSIZ }; extern thread_t first_thread; +extern thread_act_t cloneproc(struct proc *, int); +extern int (*mountroot) __P((void)); +extern int netboot_mountroot(); /* netboot.c */ +extern int netboot_setup(struct proc * p); -#define SPL_DEBUG 0 -#if SPL_DEBUG -#define dprintf(x) printf x -#else SPL_DEBUG -#define dprintf(x) -#endif /* SPL_DEBUG */ - -extern thread_t cloneproc(struct proc *, int); +/* hook called after root is mounted XXX temporary hack */ +void (*mountroot_post_hook)(void); void bsd_init() @@ -251,13 +238,11 @@ bsd_init() register int i; int s; thread_t th; - extern void bsdinit_task(); void lightning_bolt(void ); kern_return_t ret; boolean_t funnel_state; extern void uthread_zone_init(); - extern int (*mountroot) __P((void)); #if 1 @@ -275,22 +260,20 @@ bsd_init() kernel_flock = funnel_alloc(KERNEL_FUNNEL); if (kernel_flock == (funnel_t *)0 ) { - panic("bsd_init: Fail to allocate kernel mutex lock"); + panic("bsd_init: Failed to allocate kernel funnel"); } - funnel_state = thread_funnel_set(kernel_flock, TRUE); if (!disable_funnel) { network_flock = funnel_alloc(NETWORK_FUNNEL); if (network_flock == (funnel_t *)0 ) { - panic("bds_init: Fail to allocate network mutex lock"); + panic("bsd_init: Failed to allocate network funnel"); } } else { network_flock = kernel_flock; } - printf(copyright); kmeminit(); @@ -312,14 +295,15 @@ bsd_init() p = kernproc; /* kernel_task->proc = kernproc; */ - set_bsdtask_info(kernel_task,(void *)kernproc); + set_bsdtask_info(kernel_task,(void *)p); p->p_pid = 0; /* give kernproc a name */ proc_name("kernel_task", p); if (current_task() != kernel_task) - printf("We are in for problem, current task in not kernel task\n"); + printf("bsd_init: We have a problem, " + "current task is not kernel task\n"); /* * Create process 0. @@ -341,6 +325,7 @@ bsd_init() p->p_nice = NZERO; p->p_pptr = p; lockinit(&p->signal_lock, PVM, "signal", 0, 0); + TAILQ_INIT(&p->p_uthlist); p->sigwait = FALSE; p->sigwait_thread = THREAD_NULL; p->exit_thread = THREAD_NULL; @@ -377,7 +362,6 @@ bsd_init() */ (void)chgproccnt(0, 1); - /* * Allocate a kernel submap for pageable memory * for temporary copying (execve()). @@ -391,22 +375,15 @@ bsd_init() TRUE, TRUE, &bsd_pageable_map); - if (ret != KERN_SUCCESS) - panic("bsd_init: Failed to allocare bsd pageable map"); + if (ret != KERN_SUCCESS) + panic("bsd_init: Failed to allocate bsd pageable map"); } /* Initialize the execve() semaphore */ - { - kern_return_t kret; - int value; - - value = BSD_PAGABLE_MAP_SIZE / NCARGS; - - kret = semaphore_create(kernel_task, &execve_semaphore, - SYNC_POLICY_FIFO, value); - if (kret != KERN_SUCCESS) - panic("bsd_init: Failed to create execve semaphore"); - } + ret = semaphore_create(kernel_task, &execve_semaphore, + SYNC_POLICY_FIFO, (BSD_PAGABLE_MAP_SIZE / NCARGS)); + if (ret != KERN_SUCCESS) + panic("bsd_init: Failed to create execve semaphore"); /* * Initialize the calendar. @@ -424,13 +401,11 @@ bsd_init() /* Initialize syslog */ log_init(); - /* Initialize SysV shm */ - shminit(); + /* POSIX Shm and Sem */ + pshm_cache_init(); + psem_cache_init(); + time_zone_slock_init(); - /* POSIX Shm and Sem */ - pshm_cache_init(); - psem_cache_init(); - /* * Initialize protocols. Block reception of incoming packets * until everything is ready. @@ -442,15 +417,9 @@ bsd_init() domaininit(); splx(s); - /* - * Create kernel idle cpu processes. This must be done - * before a context switch can occur (and hence I/O can - * happen in the binit() call). - */ p->p_fd->fd_cdir = NULL; p->p_fd->fd_rdir = NULL; - #ifdef GPROF /* Initialize kernel profiling. */ kmstartup(); @@ -471,6 +440,9 @@ bsd_init() #if NLOOP > 0 loopattach(); /* XXX */ #endif + + /* Register the built-in dlil ethernet interface family */ + ether_family_init(); vnode_pager_bootstrap(); @@ -485,8 +457,16 @@ bsd_init() */ microtime(&time); + bsd_hardclockinit = -1; /* start ticking */ + if (0 == (err = vfs_mountroot())) break; + if (mountroot == netboot_mountroot) { + printf("cannot mount network root, errno = %d\n", err); + mountroot = NULL; + if (0 == (err = vfs_mountroot())) + break; + } printf("cannot mount root, errno = %d\n", err); boothowto |= RB_ASKNAME; } @@ -499,6 +479,14 @@ bsd_init() VREF(rootvnode); filedesc0.fd_cdir = rootvnode; VOP_UNLOCK(rootvnode, 0, p); + + if (mountroot == netboot_mountroot) { + int err; + /* post mount setup */ + if (err = netboot_setup(p)) { + panic("bsd_init: NetBoot could not find root, %d", err); + } + } /* @@ -509,7 +497,7 @@ bsd_init() p->p_stats->p_start = boottime = time; p->p_rtime.tv_sec = p->p_rtime.tv_usec = 0; -#ifdef DEVFS +#if DEVFS { extern void devfs_kernel_mount(char * str); @@ -524,48 +512,25 @@ bsd_init() bsd_utaskbootstrap(); - (void) thread_funnel_set(kernel_flock, FALSE); + /* invoke post-root-mount hook */ + if (mountroot_post_hook != NULL) + mountroot_post_hook(); + + (void) thread_funnel_set(kernel_flock, funnel_state); } +/* Called with kernel funnel held */ void -bsdinit_task() +bsdinit_task(void) { struct proc *p = current_proc(); struct uthread *ut; kern_return_t kr; thread_act_t th_act; - boolean_t funnel_state; - - funnel_state = thread_funnel_set(kernel_flock, TRUE); - -#if FIXME /* [ */ - - ipc_port_t master_bootstrap_port; - task_t bootstrap_task; - thread_act_t bootstrap_thr_act; - ipc_port_t root_device_port; - - master_bootstrap_port = ipc_port_alloc_kernel(); - if (master_bootstrap_port == IP_NULL) - panic("can't allocate master bootstrap port"); - printf("setting bootstrap port \n"); - task_set_special_port(bootstrap_task, - TASK_BOOTSTRAP_PORT, - ipc_port_make_send(master_bootstrap_port)); - - printf("Setting exception port for the init task\n"); - (void) task_set_exception_ports(get_threadtask(th), - EXC_MASK_ALL & - ~(EXC_MASK_SYSCALL | - EXC_MASK_MACH_SYSCALL | EXC_MASK_RPC_ALERT), - ux_exception_port, - EXCEPTION_DEFAULT, 0); -#endif /* FIXME ] */ proc_name("init", p); ux_handler_init(); - /* port_reference(ux_exception_port);*/ th_act = current_act(); (void) host_set_exception_ports(host_priv_self(), @@ -591,11 +556,11 @@ bsdinit_task() bsd_hardclockinit = 1; /* Start bsd hardclock */ bsd_init_task = get_threadtask(th_act); init_task_failure_data[0] = 0; + shared_region_mapping_ref(system_shared_region); vm_set_shared_region(get_threadtask(th_act), system_shared_region); load_init_program(p); - - (void) thread_funnel_set(kernel_flock, FALSE); - + /* turn on app-profiling i.e. pre-heating */ + app_profile = 1; } void @@ -613,8 +578,9 @@ lightning_bolt() (void) thread_funnel_set(kernel_flock, FALSE); } -bsd_autoconf(){ - extern kern_return_t IOKitBSDInit( void ); +bsd_autoconf() +{ + extern kern_return_t IOKitBSDInit( void ); kminit(); @@ -628,7 +594,7 @@ bsd_autoconf(){ (*pi->ps_func) (pi->ps_count); } - return( IOKitBSDInit()); + return( IOKitBSDInit()); } @@ -638,10 +604,6 @@ setconf() { extern kern_return_t IOFindBSDRoot( char * rootName, dev_t * root, u_int32_t * flags ); - - extern int (*mountroot) __P((void)); - extern int nfs_mountroot(); /* nfs_vfsops.c */ - u_int32_t flags; kern_return_t err; @@ -661,10 +623,9 @@ setconf() flags = 0; } - /* if network device then force nfs root */ if( flags & 1 ) { - printf("mounting nfs root\n"); - mountroot = nfs_mountroot; + /* network device */ + mountroot = netboot_mountroot; } else { /* otherwise have vfs determine root filesystem */ mountroot = NULL; @@ -675,12 +636,18 @@ setconf() bsd_utaskbootstrap() { thread_act_t th_act; + struct uthread *ut; - th_act = (thread_act_t)cloneproc(kernproc, 0); + th_act = cloneproc(kernproc, 0); initproc = pfind(1); + /* Set the launch time for init */ + initproc->p_stats->p_start = time; + + ut = (struct uthread *)get_bsdthread_info(th_act); + ut->uu_sigmask = 0; thread_hold(th_act); - (void) thread_stop_wait(getshuttle_thread(th_act)); - thread_ast_set(th_act,AST_BSD_INIT); + (void)thread_stop(getshuttle_thread(th_act)); + act_set_astbsd(th_act); thread_release(th_act); thread_unstop(getshuttle_thread(th_act)); (void) thread_resume(th_act); @@ -766,13 +733,11 @@ thread_funnel_switch( panic("thread_funnel_switch: can't switch to same funnel"); } - if ((oldfnl != NETWORK_FUNNEL) && (oldfnl != KERNEL_FUNNEL)) - { + if ((oldfnl != NETWORK_FUNNEL) && (oldfnl != KERNEL_FUNNEL)) { panic("thread_funnel_switch: invalid oldfunnel"); } - if ((newfnl != NETWORK_FUNNEL) && (newfnl != KERNEL_FUNNEL)) - { - panic("thread_funnel_switch: invalid oldfunnel"); + if ((newfnl != NETWORK_FUNNEL) && (newfnl != KERNEL_FUNNEL)) { + panic("thread_funnel_switch: invalid newfunnel"); } if((curflock = thread_funnel_get()) == THR_FUNNEL_NULL) { @@ -785,7 +750,7 @@ thread_funnel_switch( panic("thread_funnel_switch: network funnel not held"); if ((oldfnl == KERNEL_FUNNEL) && (curflock != kernel_flock)) - panic("thread_funnel_switch: network funnel not held"); + panic("thread_funnel_switch: kernel funnel not held"); if(oldfnl == NETWORK_FUNNEL) { oldflock = network_flock; diff --git a/bsd/kern/bsd_stubs.c b/bsd/kern/bsd_stubs.c index 07966f77d..bfe0a85c4 100644 --- a/bsd/kern/bsd_stubs.c +++ b/bsd/kern/bsd_stubs.c @@ -47,8 +47,6 @@ kmem_mb_alloc(vm_map_t mbmap, int size) } pcb_synch() {} -unix_master() {} -unix_release() {} struct proc * current_proc(void) @@ -123,7 +121,8 @@ bdevsw_add(int index, struct bdevsw * bsw) if (index == -1) { devsw = bdevsw; - for(index=0; index < nblkdev; index++, devsw++) { + /* yes, start at 1 to avoid collision with volfs (Radar 2842228) */ + for(index=1; index < nblkdev; index++, devsw++) { if(memcmp((char *)devsw, (char *)&nobdev, sizeof(struct bdevsw)) == 0) @@ -238,7 +237,28 @@ cdevsw_remove(int index, struct cdevsw * csw) return(index); } -int +static int +cdev_set_bdev(int cdev, int bdev) +{ + extern int chrtoblk_add(int cdev, int bdev); + + return (chrtoblk_set(cdev, bdev)); +} + +int +cdevsw_add_with_bdev(int index, struct cdevsw * csw, int bdev) +{ + index = cdevsw_add(index, csw); + if (index < 0) { + return (index); + } + if (cdev_set_bdev(index, bdev) < 0) { + cdevsw_remove(index, csw); + return (-1); + } + return (index); +} + issingleuser(void) { char namep[16]; diff --git a/bsd/kern/init_sysent.c b/bsd/kern/init_sysent.c index efcdf87c8..b6fc75287 100644 --- a/bsd/kern/init_sysent.c +++ b/bsd/kern/init_sysent.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1995-1999, 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -19,22 +19,8 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* Copyright (c) 1995-1999 Apple Computer, Inc. All Rights Reserved */ -/* - * HISTORY - * 12-Feb-00 Clark Warner (warner_c) at Apple - * Added copyfile system call - * 26-Jul-99 Earsh Nandkeshwar (earsh) at Apple - * Changed getdirentryattr to getdirentriesattr - * 22-Jan-98 Clark Warner (warner_c) at Apple - * Created new system calls for supporting HFS/HFS Plus file system semantics - * - * 04-Jun-95 Mac Gillon (mgillon) at NeXT - * Created new version based on NS3.3 and 4.4BSD - * - */ - +#include #include #include #include @@ -45,6 +31,8 @@ #define sysp(fn,no) {no, 1, KERNEL_FUNNEL, fn} #define sysnets(fn,no) {no, 0, NETWORK_FUNNEL, fn} #define sysnetp(fn,no) {no, 1, NETWORK_FUNNEL, fn} +#define sysnofnl(fn,no) {no, 0, NO_FUNNEL, fn} + /* * definitions */ @@ -93,10 +81,8 @@ int getegid(); int profil(); int load_shared_file(); int reset_shared_file(); -#if KTRACE +int new_system_shared_regions(); int ktrace(); -#else -#endif int sigaction(); int getgid(); int sigprocmask(); @@ -148,6 +134,9 @@ int vtrace(); #else #endif int gettimeofday(); +#ifdef __ppc__ +int ppc_gettimeofday(); +#endif int getrusage(); int getsockopt(); int readv(); @@ -164,6 +153,7 @@ int socketpair(); int mkdir(); int rmdir(); int utimes(); +int futimes(); int adjtime(); int setsid(); int quotactl(); @@ -174,13 +164,6 @@ int getfh(); int setgid(); int setegid(); int seteuid(); -#if LFS -int lfs_bmapv(); -int lfs_markv(); -int lfs_segclean(); -int lfs_segwait(); -#else -#endif int stat(); int fstat(); int lstat(); @@ -198,9 +181,6 @@ int __sysctl(); int undelete(); int setprivexec(); int add_profil(); -#ifdef NOTEVER -int table(); -#endif /* NOTEVER */ int kdebug_trace(); @@ -219,9 +199,6 @@ int ocreat(); int olseek(); int ostat(); int olstat(); -#if KTRACE -#else -#endif int ofstat(); int ogetkerninfo(); int osmmap(); @@ -239,9 +216,6 @@ int osigsetmask(); int osigstack(); int orecvmsg(); int osendmsg(); -#if TRACE -#else -#endif int orecvfrom(); int osetreuid(); int osetregid(); @@ -258,16 +232,7 @@ int ogetsockname(); int ogetdomainname(); int osetdomainname(); int owait3(); -#if NFS -#else -#endif int ogetdirentries(); -#if NFS -#else -#endif -#if LFS -#else -#endif #if NETAT int ATsocket(); @@ -293,7 +258,7 @@ int checkuseraccess(); int searchfs(); int delete(); int copyfile(); - + /* end of HFS calls */ #else /* COMPAT_43 */ @@ -334,11 +299,21 @@ int sem_getvalue(); int sem_init(); int sem_destroy(); -int issetugid(); +int issetugid(); +int utrace(); +int pread(); +int pwrite(); +int getsid(); +int getpgid(); + +int __pthread_kill(); +int sigwait(); +int pthread_sigmask(); +int __disable_threadsignal(); + /* * System call switch table. */ - struct sysent sysent[] = { syss(nosys,0), /* 0 = indir */ @@ -386,22 +361,18 @@ struct sysent sysent[] = { compat(stat,2), /* 38 = old stat */ sysp(getppid,0), /* 39 = getppid */ compat(lstat,2), /* 40 = old lstat */ - syss(dup,2), /* 41 = dup */ + syss(dup,1), /* 41 = dup */ syss(pipe,0), /* 42 = pipe */ sysp(getegid,0), /* 43 = getegid */ syss(profil,4), /* 44 = profil */ -#if KTRACE syss(ktrace,4), /* 45 = ktrace */ -#else - syss(nosys,0), /* 45 = nosys */ -#endif syss(sigaction,3), /* 46 = sigaction */ sysp(getgid,0), /* 47 = getgid */ - syss(sigprocmask,2), /* 48 = sigprocmask */ + syss(sigprocmask,3), /* 48 = sigprocmask */ syss(getlogin,2), /* 49 = getlogin */ syss(setlogin,1), /* 50 = setlogin */ syss(acct,1), /* 51 = turn acct off/on */ - syss(sigpending,0), /* 52 = sigpending */ + syss(sigpending,1), /* 52 = sigpending */ syss(sigaltstack,2), /* 53 = sigaltstack */ syss(ioctl,3), /* 54 = ioctl */ syss(reboot,2), /* 55 = reboot */ @@ -446,28 +417,32 @@ struct sysent sysent[] = { syss(nosys,0), /* 94 was obsolete setdopt */ syss(fsync,1), /* 95 = fsync */ sysp(setpriority,3), /* 96 = setpriority */ - sysnets(socket,3), /* 97 = socket */ + sysnets(socket,3), /* 97 = socket */ sysnets(connect,3), /* 98 = connect */ comaptnet(accept,3), /* 99 = accept */ sysp(getpriority,2), /* 100 = getpriority */ comaptnet(send,4), /* 101 = old send */ comaptnet(recv,4), /* 102 = old recv */ syss(sigreturn,1), /* 103 = sigreturn */ - sysnets(bind,3), /* 104 = bind */ - sysnets(setsockopt,5), /* 105 = setsockopt */ - sysnets(listen,2), /* 106 = listen */ + sysnets(bind,3), /* 104 = bind */ + sysnets(setsockopt,5), /* 105 = setsockopt */ + sysnets(listen,2), /* 106 = listen */ syss(nosys,0), /* 107 was vtimes */ compat(sigvec,3), /* 108 = sigvec */ compat(sigblock,1), /* 109 = sigblock */ compat(sigsetmask,1), /* 110 = sigsetmask */ syss(sigsuspend,1), /* 111 = sigpause */ - compat(sigstack,2), /* 112 = sigstack */ + compat(sigstack,2), /* 112 = sigstack */ comaptnet(recvmsg,3), /* 113 = recvmsg */ comaptnet(sendmsg,3), /* 114 = sendmsg */ syss(nosys,0), /* 115 = old vtrace */ - syss(gettimeofday,2), /* 116 = gettimeofday */ +#ifdef __ppc__ + sysnofnl(ppc_gettimeofday,2), /* 116 = gettimeofday */ +#else + sysnofnl(gettimeofday,2), /* 116 = gettimeofday */ +#endif sysp(getrusage,2), /* 117 = getrusage */ - sysnets(getsockopt,5), /* 118 = getsockopt */ + sysnets(getsockopt,5), /* 118 = getsockopt */ syss(nosys,0), /* 119 = old resuba */ sysp(readv,3), /* 120 = readv */ sysp(writev,3), /* 121 = writev */ @@ -475,20 +450,20 @@ struct sysent sysent[] = { syss(fchown,3), /* 123 = fchown */ syss(fchmod,2), /* 124 = fchmod */ comaptnet(recvfrom,6), /* 125 = recvfrom */ - compat(setreuid,2), /* 126 = setreuid */ - compat(setregid,2), /* 127 = setregid */ + compat(setreuid,2), /* 126 = setreuid */ + compat(setregid,2), /* 127 = setregid */ syss(rename,2), /* 128 = rename */ - compat(truncate,2), /* 129 = old truncate */ + compat(truncate,2), /* 129 = old truncate */ compat(ftruncate,2), /* 130 = ftruncate */ syss(flock,2), /* 131 = flock */ - syss(mkfifo,2), /* 132 = nosys */ + syss(mkfifo,2), /* 132 = mkfifo */ sysnets(sendto,6), /* 133 = sendto */ - sysnets(shutdown,2), /* 134 = shutdown */ - sysnets(socketpair,5), /* 135 = socketpair */ + sysnets(shutdown,2), /* 134 = shutdown */ + sysnets(socketpair,4), /* 135 = socketpair */ syss(mkdir,2), /* 136 = mkdir */ syss(rmdir,1), /* 137 = rmdir */ syss(utimes,2), /* 138 = utimes */ - syss(nosys,0), /* 139 = used internally */ + syss(futimes,2), /* 139 = futimes */ syss(adjtime,2), /* 140 = adjtime */ comaptnet(getpeername,3),/* 141 = getpeername */ compat(gethostid,0), /* 142 = old gethostid */ @@ -500,15 +475,15 @@ struct sysent sysent[] = { syss(nosys,0), /* 148 was setquota */ syss(nosys,0), /* 149 was qquota */ comaptnet(getsockname,3),/* 150 = getsockname */ - /* - * Syscalls 151-183 inclusive are reserved for vendor-specific - * system calls. (This includes various calls added for compatibity - * with other Unix variants.) - */ - syss(nosys,0), /* 151 was m68k specific machparam */ + syss(getpgid,1), /* 151 = getpgid */ sysp(setprivexec,1),/* 152 = setprivexec */ - syss(nosys,0), /* 153 */ - syss(nosys,0), /* 154 */ +#ifdef DOUBLE_ALIGN_PARAMS + syss(pread,5), /* 153 = pread */ + syss(pwrite,5), /* 154 = pwrite */ +#else + syss(pread,4), /* 153 = pread */ + syss(pwrite,4), /* 154 = pwrite */ +#endif syss(nfssvc,2), /* 155 = nfs_svc */ compat(getdirentries,4), /* 156 = old getdirentries */ syss(statfs, 2), /* 157 = statfs */ @@ -516,7 +491,6 @@ struct sysent sysent[] = { syss(unmount, 2), /* 159 = unmount */ syss(nosys,0), /* 160 was async_daemon */ syss(getfh,2), /* 161 = get file handle */ - /*?????*/ compat(getdomainname,2), /* 162 = getdomainname */ compat(setdomainname,2), /* 163 = setdomainname */ syss(nosys,0), /* 164 */ @@ -539,28 +513,21 @@ struct sysent sysent[] = { syss(nosys,0), /* 177 */ syss(nosys,0), /* 178 */ syss(nosys,0), /* 179 */ - syss(kdebug_trace,0), /* 180 */ + syss(kdebug_trace,6), /* 180 */ syss(setgid,1), /* 181 */ syss(setegid,1), /* 182 */ - syss(seteuid,1), /* 183 */ -#if LFS - syss(lfs_bmapv,3), /* 184 = lfs_bmapv */ - syss(lfs_markv,3), /* 185 = lfs_markv */ - syss(lfs_segclean,2), /* 186 = lfs_segclean */ - syss(lfs_segwait,2), /* 187 = lfs_segwait */ -#else + syss(seteuid,1), /* 183 */ syss(nosys,0), /* 184 = nosys */ syss(nosys,0), /* 185 = nosys */ syss(nosys,0), /* 186 = nosys */ syss(nosys,0), /* 187 = nosys */ -#endif syss(stat,2), /* 188 = stat */ syss(fstat,2), /* 189 = fstat */ syss(lstat,2), /* 190 = lstat */ syss(pathconf,2), /* 191 = pathconf */ syss(fpathconf,2), /* 192 = fpathconf */ #if COMPAT_GETFSSTAT - syss(getfsstat,0), /* 193 = getfsstat */ + syss(getfsstat,3), /* 193 = getfsstat */ #else syss(nosys,0), /* 193 is unused */ #endif @@ -573,30 +540,34 @@ struct sysent sysent[] = { syss(mmap,7), /* 197 = mmap */ #endif syss(nosys,0), /* 198 = __syscall */ +#ifdef DOUBLE_ALIGN_PARAMS syss(lseek,5), /* 199 = lseek */ +#else + syss(lseek,4), /* 199 = lseek */ +#endif +#ifdef DOUBLE_ALIGN_PARAMS syss(truncate,4), /* 200 = truncate */ syss(ftruncate,4), /* 201 = ftruncate */ +#else + syss(truncate,3), /* 200 = truncate */ + syss(ftruncate,3), /* 201 = ftruncate */ +#endif syss(__sysctl,6), /* 202 = __sysctl */ sysp(mlock, 2), /* 203 = mlock */ syss(munlock, 2), /* 204 = munlock */ -#if NETAT syss(undelete,1), /* 205 = undelete */ - sysnets(ATsocket,1), /* 206 = AppleTalk ATsocket */ - sysnets(ATgetmsg,4), /* 207 = AppleTalk ATgetmsg*/ - sysnets(ATputmsg,4), /* 208 = AppleTalk ATputmsg*/ - sysnets(ATPsndreq,4), /* 209 = AppleTalk ATPsndreq*/ - sysnets(ATPsndrsp,4), /* 210 = AppleTalk ATPsndrsp*/ - sysnets(ATPgetreq,3), /* 211 = AppleTalk ATPgetreq*/ - sysnets(ATPgetrsp,2), /* 212 = AppleTalk ATPgetrsp*/ - syss(nosys,0), /* 213 = Reserved for AT expansion */ - syss(nosys,0), /* 214 = Reserved for AT expansion */ - syss(nosys,0), /* 215 = Reserved for AT expansion */ +#if NETAT + sysnets(ATsocket,1), /* 206 = ATsocket */ + sysnets(ATgetmsg,4), /* 207 = ATgetmsg*/ + sysnets(ATputmsg,4), /* 208 = ATputmsg*/ + sysnets(ATPsndreq,4), /* 209 = ATPsndreq*/ + sysnets(ATPsndrsp,4), /* 210 = ATPsndrsp*/ + sysnets(ATPgetreq,3), /* 211 = ATPgetreq*/ + sysnets(ATPgetrsp,2), /* 212 = ATPgetrsp*/ + syss(nosys,0), /* 213 = Reserved for AppleTalk */ + syss(nosys,0), /* 214 = Reserved for AppleTalk */ + syss(nosys,0), /* 215 = Reserved for AppleTalk */ #else - syss(undelete,1), /* 205 = undelete */ - -/* System calls 205 - 215 are reserved to allow HFS and AT to coexist */ -/* CHW 1/22/98 */ - syss(nosys,0), /* 206 = Reserved for AppleTalk */ syss(nosys,0), /* 207 = Reserved for AppleTalk */ syss(nosys,0), /* 208 = Reserved for AppleTalk */ @@ -626,10 +597,14 @@ struct sysent sysent[] = { syss(setattrlist,5), /* 221 = HFS setattrlist set attribute list */ syss(getdirentriesattr,8), /* 222 = HFS getdirentriesattr get directory attributes */ syss(exchangedata,3), /* 223 = HFS exchangedata exchange file contents */ +#ifdef __APPLE_API_OBSOLETE syss(checkuseraccess,6),/* 224 = HFS checkuseraccess check access to a file */ +#else + syss(nosys,6),/* 224 = HFS checkuseraccess check access to a file */ +#endif /* __APPLE_API_OBSOLETE */ syss(searchfs,6), /* 225 = HFS searchfs to implement catalog searching */ - syss(delete,1), /* 226 = private HFS delete (with Mac OS semantics) */ - syss(copyfile,4), /* 227 = Copyfile for orignally for AFP */ + syss(delete,1), /* 226 = private delete (Carbon semantics) */ + syss(copyfile,4), /* 227 = copyfile - orignally for AFP */ syss(nosys,0), /* 228 */ syss(nosys,0), /* 229 */ syss(nosys,0), /* 230 */ @@ -644,7 +619,7 @@ struct sysent sysent[] = { syss(nosys,0), /* 239 */ syss(nosys,0), /* 240 */ syss(nosys,0), /* 241 */ - syss(fsctl,0), /* 242 */ + syss(fsctl,4), /* 242 = fsctl */ syss(nosys,0), /* 243 */ syss(nosys,0), /* 244 */ syss(nosys,0), /* 245 */ @@ -652,7 +627,7 @@ struct sysent sysent[] = { syss(nosys,0), /* 247 */ syss(nosys,0), /* 248 */ syss(nosys,0), /* 249 */ - syss(minherit,3), /* 250 */ + syss(minherit,3), /* 250 = minherit */ syss(semsys,5), /* 251 = semsys */ syss(msgsys,6), /* 252 = msgsys */ syss(shmsys,4), /* 253 = shmsys */ @@ -698,9 +673,9 @@ struct sysent sysent[] = { syss(nosys,0), /* 293 */ syss(nosys,0), /* 294 */ syss(nosys,0), /* 295 */ - syss(load_shared_file,7), /* 296 */ - syss(reset_shared_file,3), /* 297 */ - syss(nosys,0), /* 298 */ + syss(load_shared_file,7), /* 296 = load_shared_file */ + syss(reset_shared_file,3), /* 297 = reset_shared_file */ + syss(new_system_shared_regions,0), /* 298 = new_system_shared_regions */ syss(nosys,0), /* 299 */ syss(nosys,0), /* 300 */ syss(nosys,0), /* 301 */ @@ -712,7 +687,7 @@ struct sysent sysent[] = { syss(nosys,0), /* 307 */ syss(nosys,0), /* 308 */ syss(nosys,0), /* 309 */ - syss(nosys,0), /* 310 */ + syss(getsid,1), /* 310 = getsid */ syss(nosys,0), /* 311 */ syss(nosys,0), /* 312 */ syss(nosys,0), /* 313 */ @@ -726,18 +701,18 @@ struct sysent sysent[] = { syss(nosys,0), /* 321 */ syss(nosys,0), /* 322 */ syss(nosys,0), /* 323 */ - syss(mlockall,1), /* 324 */ - syss(munlockall,1), /* 325 */ + syss(mlockall,1), /* 324 = mlockall*/ + syss(munlockall,1), /* 325 = munlockall*/ syss(nosys,0), /* 326 */ sysp(issetugid,0), /* 327 = issetugid */ - syss(nosys,0), /* 328 */ - syss(nosys,0), /* 329 */ - syss(nosys,0), /* 330 */ - syss(nosys,0), /* 331 */ + syss(__pthread_kill,2), /* 328 */ + syss(pthread_sigmask,3), /* 329 */ + syss(sigwait,2), /* 330 */ + syss(__disable_threadsignal,1), /* 331 */ syss(nosys,0), /* 332 */ syss(nosys,0), /* 333 */ syss(nosys,0), /* 334 */ - syss(nosys,0), /* 335 */ + syss(utrace,2), /* 335 = utrace */ syss(nosys,0), /* 336 */ syss(nosys,0), /* 337 */ syss(nosys,0), /* 338 */ diff --git a/bsd/kern/kdebug.c b/bsd/kern/kdebug.c index c0b81b4b5..82c594c8b 100644 --- a/bsd/kern/kdebug.c +++ b/bsd/kern/kdebug.c @@ -39,6 +39,16 @@ #include #include +/* trace enable status */ +unsigned int kdebug_enable = 0; + +/* track timestamps for security server's entropy needs */ +mach_timespec_t * kd_entropy_buffer = 0; +unsigned int kd_entropy_bufsize = 0; +unsigned int kd_entropy_count = 0; +unsigned int kd_entropy_indx = 0; +unsigned int kd_entropy_buftomem = 0; + /* kd_buf kd_buffer[kd_bufsize/sizeof(kd_buf)]; */ kd_buf * kd_bufptr; unsigned int kd_buftomem=0; @@ -48,7 +58,6 @@ kd_buf * kd_readlast; unsigned int nkdbufs = 8192; unsigned int kd_bufsize = 0; unsigned int kdebug_flags = 0; -unsigned int kdebug_enable=0; unsigned int kdebug_nolog=1; unsigned int kdlog_beg=0; unsigned int kdlog_end=0; @@ -82,16 +91,32 @@ struct kdebug_args { int arg5; }; +/* task to string structure */ +struct tts +{ + task_t *task; + char task_comm[20]; /* from procs p_comm */ +}; + +typedef struct tts tts_t; + struct krt { kd_threadmap *map; /* pointer to the map buffer */ int count; int maxcount; - struct proc *p; + struct tts *atts; }; typedef struct krt krt_t; +/* This is for the CHUD toolkit call */ +typedef void (*kd_chudhook_fn) (unsigned int debugid, unsigned int arg1, + unsigned int arg2, unsigned int arg3, + unsigned int arg4, unsigned int arg5); + +kd_chudhook_fn kdebug_chudhook = 0; /* pointer to CHUD toolkit function */ + /* Support syscall SYS_kdebug_trace */ kdebug_trace(p, uap, retval) struct proc *p; @@ -116,8 +141,32 @@ unsigned int debugid, arg1, arg2, arg3, arg4, arg5; unsigned long long now; mach_timespec_t *tsp; + if (kdebug_enable & KDEBUG_ENABLE_CHUD) { + if (kdebug_chudhook) + kdebug_chudhook(debugid, arg1, arg2, arg3, arg4, arg5); + + if (!((kdebug_enable & KDEBUG_ENABLE_ENTROPY) || + (kdebug_enable & KDEBUG_ENABLE_TRACE))) + return; + } + s = ml_set_interrupts_enabled(FALSE); + if (kdebug_enable & KDEBUG_ENABLE_ENTROPY) + { + if (kd_entropy_indx < kd_entropy_count) + { + ml_get_timebase((unsigned long long *) &kd_entropy_buffer [ kd_entropy_indx]); + kd_entropy_indx++; + } + + if (kd_entropy_indx == kd_entropy_count) + { + /* Disable entropy collection */ + kdebug_enable &= ~KDEBUG_ENABLE_ENTROPY; + } + } + if (kdebug_nolog) { ml_set_interrupts_enabled(s); @@ -227,6 +276,15 @@ unsigned int debugid, arg1, arg2, arg3, arg4, arg5; unsigned long long now; mach_timespec_t *tsp; + if (kdebug_enable & KDEBUG_ENABLE_CHUD) { + if (kdebug_chudhook) + (void)kdebug_chudhook(debugid, arg1, arg2, arg3, arg4, arg5); + + if (!((kdebug_enable & KDEBUG_ENABLE_ENTROPY) || + (kdebug_enable & KDEBUG_ENABLE_TRACE))) + return; + } + s = ml_set_interrupts_enabled(FALSE); if (kdebug_nolog) @@ -355,7 +413,8 @@ kdbg_reinit() int x; int ret=0; - kdebug_enable = 0; + /* Disable trace collecting */ + kdebug_enable &= ~KDEBUG_ENABLE_TRACE; kdebug_nolog = 1; if ((kdebug_flags & KDBG_INIT) && (kdebug_flags & KDBG_BUFINIT) && kd_bufsize && kd_buffer) @@ -424,9 +483,9 @@ kdbg_resolve_map(thread_act_t th_act, krt_t *t) mapptr=&t->map[t->count]; mapptr->thread = (unsigned int)getshuttle_thread(th_act); mapptr->valid = 1; - (void) strncpy (mapptr->command, t->p->p_comm, - sizeof(t->p->p_comm)-1); - mapptr->command[sizeof(t->p->p_comm)-1] = '\0'; + (void) strncpy (mapptr->command, t->atts->task_comm, + sizeof(t->atts->task_comm)-1); + mapptr->command[sizeof(t->atts->task_comm)-1] = '\0'; t->count++; } } @@ -435,17 +494,33 @@ void kdbg_mapinit() { struct proc *p; struct krt akrt; + int tts_count; /* number of task-to-string structures */ + struct tts *tts_mapptr; + unsigned int tts_mapsize = 0; + unsigned int tts_maptomem=0; + int i; + if (kdebug_flags & KDBG_MAPINIT) return; - /* Calculate size of thread map buffer */ - for (p = allproc.lh_first, kd_mapcount=0; p; + /* Calculate the sizes of map buffers*/ + for (p = allproc.lh_first, kd_mapcount=0, tts_count=0; p; p = p->p_list.le_next) { kd_mapcount += get_task_numacts((task_t)p->task); + tts_count++; } + /* + * The proc count could change during buffer allocation, + * so introduce a small fudge factor to bump up the + * buffer sizes. This gives new tasks some chance of + * making into the tables. Bump up by 10%. + */ + kd_mapcount += kd_mapcount/10; + tts_count += tts_count/10; + kd_mapsize = kd_mapcount * sizeof(kd_threadmap); if((kmem_alloc(kernel_map, & kd_maptomem, (vm_size_t)kd_mapsize) == KERN_SUCCESS)) @@ -453,7 +528,37 @@ void kdbg_mapinit() else kd_mapptr = (kd_threadmap *) 0; - if (kd_mapptr) + tts_mapsize = tts_count * sizeof(struct tts); + if((kmem_alloc(kernel_map, & tts_maptomem, + (vm_size_t)tts_mapsize) == KERN_SUCCESS)) + tts_mapptr = (struct tts *) tts_maptomem; + else + tts_mapptr = (struct tts *) 0; + + + /* + * We need to save the procs command string + * and take a reference for each task associated + * with a valid process + */ + + if (tts_mapptr) { + for (p = allproc.lh_first, i=0; p && i < tts_count; + p = p->p_list.le_next) { + if (p->p_flag & P_WEXIT) + continue; + + if (task_reference_try(p->task)) { + tts_mapptr[i].task = p->task; + (void)strncpy(&tts_mapptr[i].task_comm, p->p_comm, sizeof(tts_mapptr[i].task_comm) - 1); + i++; + } + } + tts_count = i; + } + + + if (kd_mapptr && tts_mapptr) { kdebug_flags |= KDBG_MAPINIT; /* Initialize thread map data */ @@ -461,11 +566,13 @@ void kdbg_mapinit() akrt.count = 0; akrt.maxcount = kd_mapcount; - for (p = allproc.lh_first; p; p = p->p_list.le_next) + for (i=0; i < tts_count; i++) { - akrt.p = p; - task_act_iterate_wth_args((task_t)p->task, kdbg_resolve_map, &akrt); - } + akrt.atts = &tts_mapptr[i]; + task_act_iterate_wth_args(tts_mapptr[i].task, kdbg_resolve_map, &akrt); + task_deallocate(tts_mapptr[i].task); + } + kmem_free(kernel_map, (char *)tts_mapptr, tts_mapsize); } } @@ -475,7 +582,7 @@ int x; /* Clean up the trace buffer */ global_state_pid = -1; - kdebug_enable = 0; + kdebug_enable &= ~KDEBUG_ENABLE_TRACE; kdebug_nolog = 1; kdebug_flags &= ~KDBG_BUFINIT; kdebug_flags &= (unsigned int)~KDBG_CKTYPES; @@ -719,7 +826,92 @@ kdbg_readmap(kd_threadmap *buffer, size_t *number) return(ret); } +kdbg_getentropy (mach_timespec_t * buffer, size_t *number, int ms_timeout) +{ + int avail = *number; + int ret = 0; + int count = 0; /* The number of timestamp entries that will fill buffer */ + + if (kd_entropy_buffer) + return(EBUSY); + + kd_entropy_count = avail/sizeof(mach_timespec_t); + kd_entropy_bufsize = kd_entropy_count * sizeof(mach_timespec_t); + kd_entropy_indx = 0; + + /* Enforce maximum entropy entries here if needed */ + + /* allocate entropy buffer */ + if (kmem_alloc(kernel_map, &kd_entropy_buftomem, + (vm_size_t)kd_entropy_bufsize) == KERN_SUCCESS) + { + kd_entropy_buffer = (mach_timespec_t *)kd_entropy_buftomem; + } + else + { + kd_entropy_buffer = (mach_timespec_t *) 0; + kd_entropy_count = 0; + kd_entropy_indx = 0; + return (EINVAL); + } + + if (ms_timeout < 10) + ms_timeout = 10; + + /* Enable entropy sampling */ + kdebug_enable |= KDEBUG_ENABLE_ENTROPY; + + ret = tsleep (kdbg_getentropy, PRIBIO | PCATCH, "kd_entropy", (ms_timeout/(1000/HZ))); + + /* Disable entropy sampling */ + kdebug_enable &= ~KDEBUG_ENABLE_ENTROPY; + + *number = 0; + ret = 0; + + if (kd_entropy_indx > 0) + { + /* copyout the buffer */ + if (copyout(kd_entropy_buffer, buffer, kd_entropy_indx * sizeof(mach_timespec_t))) + ret = EINVAL; + else + *number = kd_entropy_indx; + } + + /* Always cleanup */ + kd_entropy_count = 0; + kd_entropy_indx = 0; + kd_entropy_buftomem = 0; + kmem_free(kernel_map, (char *)kd_entropy_buffer, kd_entropy_bufsize); + kd_entropy_buffer = (mach_timespec_t *) 0; + return(ret); +} + + +/* + * This function is provided for the CHUD toolkit only. + * int val: + * zero disables kdebug_chudhook function call + * non-zero enables kdebug_chudhook function call + * char *fn: + * address of the enabled kdebug_chudhook function +*/ + +void kdbg_control_chud(int val, void *fn) +{ + if (val) { + /* enable chudhook */ + kdebug_enable |= KDEBUG_ENABLE_CHUD; + kdebug_chudhook = fn; + } + else { + /* disable chudhook */ + kdebug_enable &= ~KDEBUG_ENABLE_CHUD; + kdebug_chudhook = 0; + } +} + kdbg_control(name, namelen, where, sizep) int *name; u_int namelen; @@ -736,6 +928,48 @@ kbufinfo_t kd_bufinfo; pid_t curpid; struct proc *p, *curproc; + if (name[0] == KERN_KDGETBUF) { + /* + Does not alter the global_state_pid + This is a passive request. + */ + if (size < sizeof(kd_bufinfo.nkdbufs)) { + /* + There is not enough room to return even + the first element of the info structure. + */ + return(EINVAL); + } + + kd_bufinfo.nkdbufs = nkdbufs; + kd_bufinfo.nkdthreads = kd_mapsize / sizeof(kd_threadmap); + kd_bufinfo.nolog = kdebug_nolog; + kd_bufinfo.flags = kdebug_flags; + kd_bufinfo.bufid = global_state_pid; + + if(size >= sizeof(kbufinfo_t)) { + /* Provide all the info we have */ + if(copyout (&kd_bufinfo, where, sizeof(kbufinfo_t))) + return(EINVAL); + } + else { + /* + For backwards compatibility, only provide + as much info as there is room for. + */ + if(copyout (&kd_bufinfo, where, size)) + return(EINVAL); + } + return(0); + } + else if (name[0] == KERN_KDGETENTROPY) { + if (kd_entropy_buffer) + return(EBUSY); + else + ret = kdbg_getentropy((mach_timespec_t *)where, sizep, value); + return (ret); + } + if(curproc = current_proc()) curpid = curproc->p_pid; else @@ -776,9 +1010,15 @@ struct proc *p, *curproc; break; } } - kdebug_enable=(value)?1:0; + + if (value) + kdebug_enable |= KDEBUG_ENABLE_TRACE; + else + kdebug_enable &= ~KDEBUG_ENABLE_TRACE; + kdebug_nolog = (value)?0:1; - if (kdebug_enable) + + if (kdebug_enable & KDEBUG_ENABLE_TRACE) kdbg_mapinit(); break; case KERN_KDSETBUF: @@ -790,19 +1030,6 @@ struct proc *p, *curproc; else nkdbufs = max_entries; break; - case KERN_KDGETBUF: - if(size < sizeof(kbufinfo_t)) { - ret=EINVAL; - break; - } - kd_bufinfo.nkdbufs = nkdbufs; - kd_bufinfo.nkdthreads = kd_mapsize / sizeof(kd_threadmap); - kd_bufinfo.nolog = kdebug_nolog; - kd_bufinfo.flags = kdebug_flags; - if(copyout (&kd_bufinfo, where, sizeof(kbufinfo_t))) { - ret=EINVAL; - } - break; case KERN_KDSETUP: ret=kdbg_reinit(); break; diff --git a/bsd/kern/kern_clock.c b/bsd/kern/kern_clock.c index 649b0a6d4..a1b35394e 100644 --- a/bsd/kern/kern_clock.c +++ b/bsd/kern/kern_clock.c @@ -68,7 +68,6 @@ #include #include #include -#include #include #include #include @@ -117,18 +116,22 @@ bsd_hardclock(usermode, pc, numticks) int numticks; { register struct proc *p; - register int s; - int ticks = numticks; - extern int tickdelta; - extern long timedelta; register thread_t thread; int nusecs = numticks * tick; if (!bsd_hardclockinit) return; - thread = current_thread(); + /* + * Increment the time-of-day. + */ + microtime(&time); + if (bsd_hardclockinit < 0) { + return; + } + + thread = current_thread(); /* * Charge the time out based on the mode the cpu is in. * Here again we fudge for the lack of proper interval timers @@ -137,159 +140,95 @@ bsd_hardclock(usermode, pc, numticks) */ p = (struct proc *)current_proc(); if (p && ((p->p_flag & P_WEXIT) == NULL)) { - if (usermode) { - if (p) { + if (usermode) { if (p->p_stats && p->p_stats->p_prof.pr_scale) { p->p_flag |= P_OWEUPC; - ast_on(AST_BSD); + astbsd_on(); + } + + /* + * CPU was in user state. Increment + * user time counter, and process process-virtual time + * interval timer. + */ + if (p->p_stats && + timerisset(&p->p_stats->p_timer[ITIMER_VIRTUAL].it_value) && + !itimerdecr(&p->p_stats->p_timer[ITIMER_VIRTUAL], nusecs)) { + extern void psignal_vtalarm(struct proc *); + + /* does psignal(p, SIGVTALRM) in a thread context */ + thread_call_func(psignal_vtalarm, p, FALSE); } } /* - * CPU was in user state. Increment - * user time counter, and process process-virtual time - * interval timer. + * If the cpu is currently scheduled to a process, then + * charge it with resource utilization for a tick, updating + * statistics which run in (user+system) virtual time, + * such as the cpu time limit and profiling timers. + * This assumes that the current process has been running + * the entire last tick. */ - if (p->p_stats && - timerisset(&p->p_stats->p_timer[ITIMER_VIRTUAL].it_value) && - itimerdecr(&p->p_stats->p_timer[ITIMER_VIRTUAL], nusecs) == 0) { - extern void psignal_vtalarm(struct proc *); + if (!is_thread_idle(thread)) { + if (p->p_limit && + p->p_limit->pl_rlimit[RLIMIT_CPU].rlim_cur != RLIM_INFINITY) { + time_value_t sys_time, user_time; + + thread_read_times(thread, &user_time, &sys_time); + if ((sys_time.seconds + user_time.seconds + 1) > + p->p_limit->pl_rlimit[RLIMIT_CPU].rlim_cur) { + extern void psignal_xcpu(struct proc *); - /* does psignal(p, SIGVTALRM) in a thread context */ - thread_call_func((thread_call_func_t)psignal_vtalarm, p, FALSE); - } - } + /* does psignal(p, SIGXCPU) in a thread context */ + thread_call_func(psignal_xcpu, p, FALSE); - /* - * If the cpu is currently scheduled to a process, then - * charge it with resource utilization for a tick, updating - * statistics which run in (user+system) virtual time, - * such as the cpu time limit and profiling timers. - * This assumes that the current process has been running - * the entire last tick. - */ - if (p && !(is_thread_idle(thread))) - { - if (p->p_limit && (p->p_limit->pl_rlimit[RLIMIT_CPU].rlim_cur != RLIM_INFINITY)) { - time_value_t sys_time, user_time; - - thread_read_times(thread, &user_time, &sys_time); - if ((sys_time.seconds + user_time.seconds + 1) > - p->p_limit->pl_rlimit[RLIMIT_CPU].rlim_cur) { - extern void psignal_xcpu(struct proc *); + if (p->p_limit->pl_rlimit[RLIMIT_CPU].rlim_cur < + p->p_limit->pl_rlimit[RLIMIT_CPU].rlim_max) + p->p_limit->pl_rlimit[RLIMIT_CPU].rlim_cur += 5; + } + } + if (timerisset(&p->p_stats->p_timer[ITIMER_PROF].it_value) && + !itimerdecr(&p->p_stats->p_timer[ITIMER_PROF], nusecs)) { + extern void psignal_sigprof(struct proc *); - /* does psignal(p, SIGXCPU) in a thread context */ - thread_call_func((thread_call_func_t)psignal_xcpu, p, FALSE); - - if (p->p_limit->pl_rlimit[RLIMIT_CPU].rlim_cur < - p->p_limit->pl_rlimit[RLIMIT_CPU].rlim_max) - p->p_limit->pl_rlimit[RLIMIT_CPU].rlim_cur += 5; + /* does psignal(p, SIGPROF) in a thread context */ + thread_call_func(psignal_sigprof, p, FALSE); } } - if (timerisset(&p->p_stats->p_timer[ITIMER_PROF].it_value) && - itimerdecr(&p->p_stats->p_timer[ITIMER_PROF], nusecs) == 0) { - extern void psignal_sigprof(struct proc *); - - /* does psignal(p, SIGPROF) in a thread context */ - thread_call_func((thread_call_func_t)psignal_sigprof, p, FALSE); - } } +#ifdef GPROF /* - * Increment the time-of-day, and schedule - * processing of the callouts at a very low cpu priority, - * so we don't keep the relatively high clock interrupt - * priority any longer than necessary. - */ - - /* - * Gather the statistics. + * Gather some statistics. */ gatherstats(usermode, pc); - - } - if (timedelta != 0) { - register delta; - clock_res_t nsdelta = tickdelta * NSEC_PER_USEC; - - if (timedelta < 0) { - delta = ticks - tickdelta; - timedelta += tickdelta; - nsdelta = -nsdelta; - } else { - delta = ticks + tickdelta; - timedelta -= tickdelta; - } - clock_adjust_calendar(nsdelta); - } - microtime(&time); +#endif } /* - * Gather statistics on resource utilization. - * - * We make a gross assumption: that the system has been in the - * state it is in (user state, kernel state, interrupt state, - * or idle state) for the entire last time interval, and - * update statistics accordingly. + * Gather some statistics. */ /*ARGSUSED*/ void -gatherstats(usermode, pc) - boolean_t usermode; - caddr_t pc; +gatherstats( + boolean_t usermode, + caddr_t pc) { - register int cpstate, s; - struct proc *proc =current_proc(); #ifdef GPROF - struct gmonparam *p = &_gmonparam; -#endif + if (!usermode) { + struct gmonparam *p = &_gmonparam; - /* - * Determine what state the cpu is in. - */ - if (usermode) { - /* - * CPU was in user state. - */ - if (proc->p_nice > NZERO) - cpstate = CP_NICE; - else - cpstate = CP_USER; - } else { - /* - * CPU was in system state. If profiling kernel - * increment a counter. If no process is running - * then this is a system tick if we were running - * at a non-zero IPL (in a driver). If a process is running, - * then we charge it with system time even if we were - * at a non-zero IPL, since the system often runs - * this way during processing of system calls. - * This is approximate, but the lack of true interval - * timers makes doing anything else difficult. - */ - cpstate = CP_SYS; - if (is_thread_idle(current_thread())) - cpstate = CP_IDLE; -#ifdef GPROF if (p->state == GMON_PROF_ON) { + register int s; + s = pc - p->lowpc; if (s < p->textsize) { s /= (HISTFRACTION * sizeof(*p->kcount)); p->kcount[s]++; } } -#endif } - /* - * We maintain statistics shown by user-level statistics - * programs: the amount of time in each cpu state, and - * the amount of time each of DK_NDRIVE ``drives'' is busy. - */ - cp_time[cpstate]++; - for (s = 0; s < DK_NDRIVE; s++) - if (dk_busy & (1 << s)) - dk_time[s]++; +#endif } @@ -337,10 +276,11 @@ untimeout( hzto(tv) struct timeval *tv; { + struct timeval now; register long ticks; register long sec; - int s = splhigh(); - + + microtime(&now); /* * If number of milliseconds will fit in 32 bit arithmetic, * then compute number of milliseconds to time and scale to @@ -350,32 +290,18 @@ hzto(tv) * Delta times less than 25 days can be computed ``exactly''. * Maximum value for any timeout in 10ms ticks is 250 days. */ - sec = tv->tv_sec - time.tv_sec; + sec = tv->tv_sec - now.tv_sec; if (sec <= 0x7fffffff / 1000 - 1000) - ticks = ((tv->tv_sec - time.tv_sec) * 1000 + - (tv->tv_usec - time.tv_usec) / 1000) + ticks = ((tv->tv_sec - now.tv_sec) * 1000 + + (tv->tv_usec - now.tv_usec) / 1000) / (tick / 1000); else if (sec <= 0x7fffffff / hz) ticks = sec * hz; else ticks = 0x7fffffff; - splx(s); - return (ticks); -} -#if 0 /* [ */ -/* - * Convert ticks to a timeval - */ -ticks_to_timeval(ticks, tvp) - register long ticks; - struct timeval *tvp; -{ - tvp->tv_sec = ticks/hz; - tvp->tv_usec = (ticks%hz) * tick; - asert(tvp->tv_usec < 1000000); + return (ticks); } -#endif /* ] */ /* * Return information about system clocks. diff --git a/bsd/kern/kern_control.c b/bsd/kern/kern_control.c new file mode 100644 index 000000000..6e3288a6a --- /dev/null +++ b/bsd/kern/kern_control.c @@ -0,0 +1,466 @@ +/* + * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* Copyright (C) 1999 Apple Computer, Inc. */ + +/* + * NKE management domain - allows control connections to + * an NKE and to read/write data. + * + * Christophe Allie, 010928 + * Justin C. Walker, 990319 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + + +/* + * Definitions and vars for we support + */ + +#define CTL_SENDSIZE (2 * 1024) /* default buffer size */ +#define CTL_RECVSIZE (8 * 1024) /* default buffer size */ + +/* + internal structure maintained for each register controller +*/ +struct ctl +{ + TAILQ_ENTRY(ctl) next; /* controller chain */ + struct socket *skt; /* current controlling socket */ + + /* controller information provided when registering */ + u_int32_t id; /* unique nke identifier, provided by DTS */ + u_int32_t unit; /* unit number for use by the nke */ + void *userdata; /* for private use by nke */ + + /* misc communication information */ + u_int32_t flags; /* support flags */ + u_int32_t recvbufsize; /* request more than the default buffer size */ + u_int32_t sendbufsize; /* request more than the default buffer size */ + + /* Dispatch functions */ + int (*connect)(kern_ctl_ref, void *); /* Make contact */ + void (*disconnect)(kern_ctl_ref, void *); /* Break contact */ + int (*write) (kern_ctl_ref, void *, struct mbuf *); /* Send data to nke */ + int (*set)(kern_ctl_ref, void *, int, void *, size_t ); /* set ctl configuration */ + int (*get)(kern_ctl_ref, void *, int, void *, size_t *); /* get ctl configuration */ +}; + + +/* all the controllers are chained */ +TAILQ_HEAD(, ctl) ctl_head; + +int ctl_attach(struct socket *, int, struct proc *); +int ctl_connect(struct socket *, struct sockaddr *, struct proc *); +int ctl_disconnect(struct socket *); +int ctl_ioctl(struct socket *so, u_long cmd, caddr_t data, + struct ifnet *ifp, struct proc *p); +int ctl_send(struct socket *, int, struct mbuf *, + struct sockaddr *, struct mbuf *, struct proc *); +int ctl_ctloutput(struct socket *, struct sockopt *); + +struct ctl *ctl_find(u_int32_t, u_int32_t unit); +void ctl_post_msg(u_long event_code, u_int32_t id, u_int32_t unit); + + +struct pr_usrreqs ctl_usrreqs = +{ + pru_abort_notsupp, pru_accept_notsupp, ctl_attach, pru_bind_notsupp, + ctl_connect, pru_connect2_notsupp, ctl_ioctl, pru_detach_notsupp, + ctl_disconnect, pru_listen_notsupp, pru_peeraddr_notsupp, + pru_rcvd_notsupp, pru_rcvoob_notsupp, ctl_send, + pru_sense_null, pru_shutdown_notsupp, pru_sockaddr_notsupp, + sosend, soreceive, sopoll +}; + +struct protosw ctlsw = +{ + SOCK_DGRAM, &systemdomain, SYSPROTO_CONTROL, PR_ATOMIC|PR_CONNREQUIRED, + NULL, NULL, NULL, ctl_ctloutput, + NULL, NULL, + NULL, NULL, NULL, NULL, &ctl_usrreqs +}; + +/* + * Install the protosw's for the NKE manager. + */ +int +kern_control_init(void) +{ + int retval; + + retval = net_add_proto(&ctlsw, &systemdomain); + if (retval) { + log(LOG_WARNING, "Can't install Kernel Controller Manager (%d)\n", retval); + return retval; + } + + TAILQ_INIT(&ctl_head); + + return(KERN_SUCCESS); +} + + +/* + * Kernel Controller user-request functions + */ +int +ctl_attach (struct socket *so, int proto, struct proc *p) +{ + /* + * attach function must exist and succeed + * detach not necessary since we use + * connect/disconnect to handle so_pcb + */ + + return 0; +} + +int +ctl_connect(struct socket *so, struct sockaddr *nam, struct proc *p) +{ + struct ctl *ctl; + int error = 0; + struct sockaddr_ctl *sa = (struct sockaddr_ctl *)nam; + + ctl = ctl_find(sa->sc_id, sa->sc_unit); + if (ctl == NULL) + return(EADDRNOTAVAIL); + + if (ctl->skt != NULL) + return(EBUSY); + + error = soreserve(so, + ctl->sendbufsize ? ctl->sendbufsize : CTL_SENDSIZE, + ctl->recvbufsize ? ctl->recvbufsize : CTL_RECVSIZE); + if (error) + return error; + + ctl->skt = so; + + if (ctl->flags & CTL_FLAG_PRIVILEGED) { + if (p == 0) + return(EPERM); + if (error = suser(p->p_ucred, &p->p_acflag)) + return error; + } + + if (ctl->connect) + error = (*ctl->connect)(ctl, ctl->userdata); + if (error) { + ctl->skt = NULL; + return error; + } + + so->so_pcb = (caddr_t)ctl; + soisconnected(so); + + return error; +} + +int +ctl_disconnect(struct socket *so) +{ + struct ctl *ctl; + + if ((ctl = (struct ctl *)so->so_pcb)) + { + if (ctl->disconnect) + (*ctl->disconnect)(ctl, ctl->userdata); + ctl->skt = NULL; + so->so_pcb = NULL; + soisdisconnected(so); + } + return 0; +} + +int +ctl_send(struct socket *so, int flags, struct mbuf *m, + struct sockaddr *addr, struct mbuf *control, + struct proc *p) +{ + struct ctl *ctl = (struct ctl *)so->so_pcb; + int error = 0; + + if (ctl == NULL) + return(ENOTCONN); + + if (ctl->write) + error = (*ctl->write)(ctl, ctl->userdata, m); + + return error; +} + +int +ctl_enqueuembuf(void *ctlref, struct mbuf *m, u_int32_t flags) +{ + struct ctl *ctl = (struct ctl *)ctlref; + struct socket *so = (struct socket *)ctl->skt; + + if (ctl == NULL) /* sanity check */ + return(EINVAL); + + if (so == NULL) + return(ENOTCONN); + + if (sbspace(&so->so_rcv) < m->m_pkthdr.len) + return(ENOBUFS); + + sbappend(&so->so_rcv, m); + if ((flags & CTL_DATA_NOWAKEUP) == 0) + sorwakeup(so); + return 0; +} + +int +ctl_enqueuedata(void *ctlref, void *data, size_t len, u_int32_t flags) +{ + struct ctl *ctl = (struct ctl *)ctlref; + struct socket *so = (struct socket *)ctl->skt; + struct mbuf *m; + + if (ctl == NULL) /* sanity check */ + return(EINVAL); + + if (so == NULL) + return(ENOTCONN); + + if (len > MCLBYTES) + return(EMSGSIZE); + + if (sbspace(&so->so_rcv) < len) + return(ENOBUFS); + + if ((m = m_gethdr(M_NOWAIT, MT_DATA)) == NULL) + return (ENOBUFS); + + if (len > MHLEN) { + MCLGET(m, M_NOWAIT); + if (!(m->m_flags & M_EXT)) { + m_freem(m); + return(ENOBUFS); + } + } + + bcopy(data, mtod(m, void *), len); + + sbappend(&so->so_rcv, m); + if ((flags & CTL_DATA_NOWAKEUP) == 0) + sorwakeup(so); + return 0; +} + +int +ctl_ctloutput(struct socket *so, struct sockopt *sopt) +{ + struct ctl *ctl = (struct ctl *)so->so_pcb; + int error = 0, s; + void *data; + size_t len; + + if (sopt->sopt_level != SYSPROTO_CONTROL) { + return(EINVAL); + } + + if (ctl == NULL) + return(ENOTCONN); + + switch (sopt->sopt_dir) { + case SOPT_SET: + if (ctl->set == NULL) + return(ENOTSUP); + MALLOC(data, void *, sopt->sopt_valsize, M_TEMP, M_WAITOK); + if (data == NULL) + return(ENOMEM); + error = sooptcopyin(sopt, data, sopt->sopt_valsize, sopt->sopt_valsize); + if (error == 0) + error = (*ctl->set)(ctl, ctl->userdata, sopt->sopt_name, data, sopt->sopt_valsize); + FREE(data, M_TEMP); + break; + + case SOPT_GET: + if (ctl->get == NULL) + return(ENOTSUP); + data = NULL; + if (sopt->sopt_valsize && sopt->sopt_val) { + MALLOC(data, void *, sopt->sopt_valsize, M_TEMP, M_WAITOK); + if (data == NULL) + return(ENOMEM); + } + len = sopt->sopt_valsize; + error = (*ctl->get)(ctl, ctl->userdata, sopt->sopt_name, data, &len); + if (error == 0) { + if (data != NULL) + error = sooptcopyout(sopt, data, len); + else + sopt->sopt_valsize = len; + } + if (data != NULL) + FREE(data, M_TEMP); + break; + } + return error; +} + +int ctl_ioctl(struct socket *so, u_long cmd, caddr_t data, + struct ifnet *ifp, struct proc *p) +{ + int error = ENOTSUP, s, n; + struct ctl *ctl = (struct ctl *)so->so_pcb; + + switch (cmd) { + /* get the number of controllers */ + case CTLIOCGCOUNT: + n = 0; + TAILQ_FOREACH(ctl, &ctl_head, next) + n++; + *(u_int32_t *)data = n; + error = 0; + break; + + + /* add controls to get list of NKEs */ + + } + + return error; +} + +/* + * Register/unregister a NKE + */ +int +ctl_register(struct kern_ctl_reg *userctl, void *userdata, kern_ctl_ref *ctlref) +{ + struct ctl *ctl; + + if (userctl == NULL) /* sanity check */ + return(EINVAL); + + ctl = ctl_find(userctl->ctl_id, userctl->ctl_unit); + if (ctl != NULL) + return(EEXIST); + + MALLOC(ctl, struct ctl *, sizeof(*ctl), M_TEMP, M_WAITOK); + if (ctl == NULL) + return(ENOMEM); + + bzero((char *)ctl, sizeof(*ctl)); + + ctl->id = userctl->ctl_id; + ctl->unit = userctl->ctl_unit; + ctl->flags = userctl->ctl_flags; + ctl->sendbufsize = userctl->ctl_sendsize; + ctl->recvbufsize = userctl->ctl_recvsize; + ctl->userdata = userdata; + ctl->connect = userctl->ctl_connect; + ctl->disconnect = userctl->ctl_disconnect; + ctl->write = userctl->ctl_write; + ctl->set = userctl->ctl_set; + ctl->get = userctl->ctl_get; + + TAILQ_INSERT_TAIL(&ctl_head, ctl, next); + + *ctlref = ctl; + + ctl_post_msg(KEV_CTL_REGISTERED, ctl->id, ctl->unit); + return(0); +} + +int +ctl_deregister(void *ctlref) +{ + struct ctl *ctl = (struct ctl *)ctlref; + struct socket *so; + + if (ctl == NULL) /* sanity check */ + return(EINVAL); + + TAILQ_REMOVE(&ctl_head, ctl, next); + + if (ctl->skt) { + ctl->skt->so_pcb = 0; + soisdisconnected(ctl->skt); + } + + ctl_post_msg(KEV_CTL_DEREGISTERED, ctl->id, ctl->unit); + FREE(ctl, M_TEMP); + return(0); +} + +/* + * Locate a NKE + */ +struct ctl * +ctl_find(u_int32_t id, u_int32_t unit) +{ + struct ctl *ctl; + + TAILQ_FOREACH(ctl, &ctl_head, next) + if ((ctl->id == id) && (ctl->unit == unit)) + return ctl; + + return NULL; +} + +void ctl_post_msg(u_long event_code, u_int32_t id, u_int32_t unit) +{ + struct ctl_event_data ctl_ev_data; + struct kev_msg ev_msg; + + ev_msg.vendor_code = KEV_VENDOR_APPLE; + + ev_msg.kev_class = KEV_SYSTEM_CLASS; + ev_msg.kev_subclass = KEV_CTL_SUBCLASS; + ev_msg.event_code = event_code; + + /* common nke subclass data */ + bzero(&ctl_ev_data, sizeof(ctl_ev_data)); + ctl_ev_data.ctl_id = id; + ctl_ev_data.ctl_unit = unit; + ev_msg.dv[0].data_ptr = &ctl_ev_data; + ev_msg.dv[0].data_length = sizeof(ctl_ev_data); + + ev_msg.dv[1].data_length = 0; + + kev_post_msg(&ev_msg); +} + diff --git a/bsd/kern/kern_core.c b/bsd/kern/kern_core.c index 144331f7d..ebab0fa6e 100644 --- a/bsd/kern/kern_core.c +++ b/bsd/kern/kern_core.c @@ -168,7 +168,7 @@ coredump(p) int vbrcount=0; tir_t tir1; struct vnode * vp; - + extern boolean_t coredumpok(vm_map_t map, vm_offset_t va); /* temp fix */ if (pcred->p_svuid != pcred->p_ruid || pcred->p_svgid != pcred->p_rgid) return (EFAULT); @@ -181,14 +181,6 @@ coredump(p) return (EFAULT); (void) task_suspend(task); - /* - * Make sure all registers, etc. are in pcb so they get - * into core file. - */ -#if defined (__ppc__) - fpu_save(current_act()); - vec_save(current_act()); -#endif sprintf(core_name, "/cores/core.%d", p->p_pid); NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, core_name, p); if(error = vn_open(&nd, O_CREAT | FWRITE, S_IRUSR )) @@ -297,6 +289,7 @@ coredump(p) sc->cmd = LC_SEGMENT; sc->cmdsize = sizeof(struct segment_command); /* segment name is zerod by kmem_alloc */ + sc->segname[0] = 0; sc->vmaddr = vmoffset; sc->vmsize = size; sc->fileoff = foffset; @@ -318,7 +311,7 @@ coredump(p) * Note: if we can't read, then we end up with * a hole in the file. */ - if ((maxprot & VM_PROT_READ) == VM_PROT_READ && vbr.user_tag != VM_MEMORY_IOKIT) { + if ((maxprot & VM_PROT_READ) == VM_PROT_READ && vbr.user_tag != VM_MEMORY_IOKIT && coredumpok(map,vmoffset)) { error = vn_rdwr(UIO_WRITE, vp, (caddr_t)vmoffset, size, foffset, UIO_USERSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *) 0, p); } diff --git a/bsd/kern/kern_descrip.c b/bsd/kern/kern_descrip.c index c592c4140..0b8a16e32 100644 --- a/bsd/kern/kern_descrip.c +++ b/bsd/kern/kern_descrip.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -85,6 +85,8 @@ struct filelist filehead; /* head of list of open files */ int nfiles; /* actual number of open files */ +static int frele_internal(struct file *); + /* * System calls on descriptors. */ @@ -232,13 +234,13 @@ fcntl(p, uap, retval) struct vnode *vp, *devvp; int i, tmp, error, error2, flg = F_POSIX; struct flock fl; - fstore_t alloc_struct; /* structure for allocate command */ + fstore_t alloc_struct; /* structure for allocate command */ u_int32_t alloc_flags = 0; off_t offset; /* used for F_SETSIZE */ int newmin; struct radvisory ra_struct; fbootstraptransfer_t fbt_struct; /* for F_READBOOTSTRAP and F_WRITEBOOTSTRAP */ - struct log2phys l2p_struct; /* structure for allocate command */ + struct log2phys l2p_struct; /* structure for allocate command */ daddr_t lbn, bn; int devBlockSize = 0; @@ -275,16 +277,16 @@ fcntl(p, uap, retval) fp->f_flag &= ~FCNTLFLAGS; fp->f_flag |= FFLAGS((long)uap->arg) & FCNTLFLAGS; tmp = fp->f_flag & FNONBLOCK; - error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p); + error = fo_ioctl(fp, FIONBIO, (caddr_t)&tmp, p); if (error) return (error); tmp = fp->f_flag & FASYNC; - error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p); + error = fo_ioctl(fp, FIOASYNC, (caddr_t)&tmp, p); if (!error) return (0); fp->f_flag &= ~FNONBLOCK; tmp = 0; - (void) (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p); + (void)fo_ioctl(fp, FIONBIO, (caddr_t)&tmp, p); return (error); case F_GETOWN: @@ -292,8 +294,7 @@ fcntl(p, uap, retval) *retval = ((struct socket *)fp->f_data)->so_pgid; return (0); } - error = (*fp->f_ops->fo_ioctl) - (fp, (int)TIOCGPGRP, (caddr_t)retval, p); + error = fo_ioctl(fp, (int)TIOCGPGRP, (caddr_t)retval, p); *retval = -*retval; return (error); @@ -311,8 +312,7 @@ fcntl(p, uap, retval) return (ESRCH); uap->arg = (void *)(long)p1->p_pgrp->pg_id; } - return ((*fp->f_ops->fo_ioctl) - (fp, (int)TIOCSPGRP, (caddr_t)&uap->arg, p)); + return (fo_ioctl(fp, (int)TIOCSPGRP, (caddr_t)&uap->arg, p)); case F_SETLKW: flg |= F_WAIT; @@ -367,55 +367,44 @@ fcntl(p, uap, retval) return (copyout((caddr_t)&fl, (caddr_t)uap->arg, sizeof (fl))); - case F_PREALLOCATE: - - /* Copy in the structure */ + case F_PREALLOCATE: + if (fp->f_type != DTYPE_VNODE) + return (EBADF); + + /* make sure that we have write permission */ + if ((fp->f_flag & FWRITE) == 0) + return (EBADF); error = copyin((caddr_t)uap->arg, (caddr_t)&alloc_struct, sizeof (alloc_struct)); - if (error) return (error); - /* now set the space allocated to 0 and pass it out in - case we get a parameter checking error */ - + /* now set the space allocated to 0 */ alloc_struct.fst_bytesalloc = 0; - error = copyout((caddr_t)&alloc_struct, (caddr_t)uap->arg, - sizeof (alloc_struct)); - - if (error) - return(error); - - /* First make sure that we have write permission */ - - if ((fp->f_flag & FWRITE) == 0) - return (EBADF); - - - /* Do some simple parameter checking */ - + /* + * Do some simple parameter checking + */ /* set up the flags */ alloc_flags |= PREALLOCATE; - if (alloc_struct.fst_flags & F_ALLOCATECONTIG) { + if (alloc_struct.fst_flags & F_ALLOCATECONTIG) alloc_flags |= ALLOCATECONTIG; - } - if (alloc_struct.fst_flags & F_ALLOCATEALL) { - alloc_flags |= ALLOCATEALL; - } + if (alloc_struct.fst_flags & F_ALLOCATEALL) + alloc_flags |= ALLOCATEALL; - /* Do any position mode specific stuff. The only */ - /* position mode supported now is PEOFPOSMODE */ + /* + * Do any position mode specific stuff. The only + * position mode supported now is PEOFPOSMODE + */ switch (alloc_struct.fst_posmode) { case F_PEOFPOSMODE: - if (alloc_struct.fst_offset != 0) return (EINVAL); @@ -423,7 +412,6 @@ fcntl(p, uap, retval) break; case F_VOLPOSMODE: - if (alloc_struct.fst_offset <= 0) return (EINVAL); @@ -431,131 +419,134 @@ fcntl(p, uap, retval) break; default: - return(EINVAL); - } - /* Now lock the vnode and call allocate to get the space */ - - vp = (struct vnode *)fp->f_data; + vp = (struct vnode *)fp->f_data; - VOP_LOCK(vp,LK_EXCLUSIVE,p); + /* lock the vnode and call allocate to get the space */ + error = vn_lock(vp, LK_EXCLUSIVE|LK_RETRY, p); + if (error) + return (error); error = VOP_ALLOCATE(vp,alloc_struct.fst_length,alloc_flags, &alloc_struct.fst_bytesalloc, alloc_struct.fst_offset, fp->f_cred, p); - VOP_UNLOCK(vp,0,p); + VOP_UNLOCK(vp, 0, p); - if (error2 = (copyout((caddr_t)&alloc_struct, (caddr_t)uap->arg, - sizeof (alloc_struct)))) { - if (error) { + if (error2 = copyout((caddr_t)&alloc_struct, + (caddr_t)uap->arg, + sizeof (alloc_struct))) { + if (error) return(error); - } else { + else return(error2); - } } - return(error); - case F_SETSIZE: + case F_SETSIZE: + if (fp->f_type != DTYPE_VNODE) + return (EBADF); - /* Copy in the structure */ - error = copyin((caddr_t)uap->arg, (caddr_t)&offset, - sizeof (off_t)); - + sizeof (off_t)); if (error) return (error); + /* + * Make sure that we are root. Growing a file + * without zero filling the data is a security hole + * root would have access anyway so we'll allow it + */ - /* First make sure that we are root. Growing a file */ - /* without zero filling the data is a security hole */ - /* root would have access anyway so we'll allow it */ - - if (!is_suser()) { + if (!is_suser()) return (EACCES); - } - - /* Now lock the vnode and call allocate to get the space */ - vp = (struct vnode *)fp->f_data; + vp = (struct vnode *)fp->f_data; - VOP_LOCK(vp,LK_EXCLUSIVE,p); + /* lock the vnode and call allocate to get the space */ + error = vn_lock(vp, LK_EXCLUSIVE|LK_RETRY, p); + if (error) + return (error); error = VOP_TRUNCATE(vp,offset,IO_NOZEROFILL,fp->f_cred,p); VOP_UNLOCK(vp,0,p); - return(error); - - case F_RDAHEAD: - vp = (struct vnode *)fp->f_data; - + + case F_RDAHEAD: + if (fp->f_type != DTYPE_VNODE) + return (EBADF); + vp = (struct vnode *)fp->f_data; + simple_lock(&vp->v_interlock); if (uap->arg) - vp->v_flag &= ~VRAOFF; + vp->v_flag &= ~VRAOFF; else - vp->v_flag |= VRAOFF; + vp->v_flag |= VRAOFF; simple_unlock(&vp->v_interlock); - return (0); - case F_NOCACHE: - vp = (struct vnode *)fp->f_data; - + case F_NOCACHE: + if (fp->f_type != DTYPE_VNODE) + return (EBADF); + vp = (struct vnode *)fp->f_data; + simple_lock(&vp->v_interlock); if (uap->arg) - vp->v_flag |= VNOCACHE_DATA; + vp->v_flag |= VNOCACHE_DATA; else - vp->v_flag &= ~VNOCACHE_DATA; + vp->v_flag &= ~VNOCACHE_DATA; simple_unlock(&vp->v_interlock); - return (0); case F_RDADVISE: - vp = (struct vnode *)fp->f_data; + if (fp->f_type != DTYPE_VNODE) + return (EBADF); + vp = (struct vnode *)fp->f_data; - if (error = copyin((caddr_t)uap->arg, (caddr_t)&ra_struct, sizeof (ra_struct))) - return(error); + if (error = copyin((caddr_t)uap->arg, + (caddr_t)&ra_struct, sizeof (ra_struct))) + return(error); return (VOP_IOCTL(vp, 1, &ra_struct, 0, fp->f_cred, p)); - + case F_READBOOTSTRAP: case F_WRITEBOOTSTRAP: - - /* Copy in the structure */ + if (fp->f_type != DTYPE_VNODE) + return (EBADF); error = copyin((caddr_t)uap->arg, (caddr_t)&fbt_struct, - sizeof (fbt_struct)); - + sizeof (fbt_struct)); if (error) return (error); - if (uap->cmd == F_WRITEBOOTSTRAP) { - /* First make sure that we are root. Updating the */ - /* bootstrap on a disk could be a security hole */ - - if (!is_suser()) { - return (EACCES); - } - }; - - /* Now lock the vnode and call VOP_IOCTL to handle the I/O: */ - - vp = (struct vnode *)fp->f_data; - if (vp->v_tag != VT_HFS) { - error = EINVAL; - } else { - VOP_LOCK(vp,LK_EXCLUSIVE,p); - error = VOP_IOCTL(vp, (uap->cmd == F_WRITEBOOTSTRAP) ? 3 : 2, &fbt_struct, 0, fp->f_cred, p); - VOP_UNLOCK(vp,0,p); - }; + /* + * Make sure that we are root. Updating the + * bootstrap on a disk could be a security hole + */ + if (!is_suser()) + return (EACCES); + } + vp = (struct vnode *)fp->f_data; + if (vp->v_tag != VT_HFS) /* XXX */ + error = EINVAL; + else { + /* lock the vnode and call VOP_IOCTL to handle the I/O */ + error = vn_lock(vp, LK_EXCLUSIVE|LK_RETRY, p); + if (error) + return (error); + error = VOP_IOCTL(vp, (uap->cmd == F_WRITEBOOTSTRAP) ? 3 : 2, + &fbt_struct, 0, fp->f_cred, p); + VOP_UNLOCK(vp,0,p); + } return(error); - - case F_LOG2PHYS: + + case F_LOG2PHYS: if (fp->f_type != DTYPE_VNODE) return (EBADF); vp = (struct vnode *)fp->f_data; - VOP_LOCK(vp, LK_EXCLUSIVE, p); + error = vn_lock(vp, LK_EXCLUSIVE|LK_RETRY, p); + if (error) + return (error); if (VOP_OFFTOBLK(vp, fp->f_offset, &lbn)) panic("fcntl LOG2PHYS OFFTOBLK"); if (VOP_BLKTOOFF(vp, lbn, &offset)) @@ -574,7 +565,6 @@ fcntl(p, uap, retval) } return (error); - default: return (EINVAL); } @@ -1094,6 +1084,31 @@ fdfree(p) FREE_ZONE(fdp, sizeof *fdp, M_FILEDESC); } +static int +closef_finish(fp, p) + register struct file *fp; + register struct proc *p; +{ + struct vnode *vp; + struct flock lf; + int error; + + if ((fp->f_flag & FHASLOCK) && fp->f_type == DTYPE_VNODE) { + lf.l_whence = SEEK_SET; + lf.l_start = 0; + lf.l_len = 0; + lf.l_type = F_UNLCK; + vp = (struct vnode *)fp->f_data; + (void) VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK); + } + if (fp->f_ops) + error = fo_close(fp, p); + else + error = 0; + ffree(fp); + return (error); +} + /* * Internal form of close. * Decrement reference count on file structure. @@ -1127,22 +1142,9 @@ closef(fp, p) vp = (struct vnode *)fp->f_data; (void) VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_POSIX); } - if (frele(fp) > 0) + if (frele_internal(fp) > 0) return (0); - if ((fp->f_flag & FHASLOCK) && fp->f_type == DTYPE_VNODE) { - lf.l_whence = SEEK_SET; - lf.l_start = 0; - lf.l_len = 0; - lf.l_type = F_UNLCK; - vp = (struct vnode *)fp->f_data; - (void) VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK); - } - if (fp->f_ops) - error = (*fp->f_ops->fo_close)(fp, p); - else - error = 0; - ffree(fp); - return (error); + return(closef_finish(fp, p)); } /* @@ -1304,14 +1306,41 @@ fref(struct file *fp) return ((int)fp->f_count); } -int -frele(struct file *fp) +static int +frele_internal(struct file *fp) { if (--fp->f_count < 0) panic("frele: count < 0"); return ((int)fp->f_count); } + +int +frele(struct file *fp) +{ + int count; + funnel_t * fnl; + extern int disable_funnel; + + fnl = thread_funnel_get(); + /* + * If the funnels are merged then atleast a funnel should be held + * else frele should come in with kernel funnel only + */ + if (!disable_funnel && (fnl != kernel_flock)) { + panic("frele: kernel funnel not held"); + + } else if (fnl == THR_FUNNEL_NULL) { + panic("frele: no funnel held"); + } + + if ((count = frele_internal(fp)) == 0) { + /* some one closed the fd while we were blocked */ + (void)closef_finish(fp, current_proc()); + } + return(count); +} + int fcount(struct file *fp) { diff --git a/bsd/kern/kern_event.c b/bsd/kern/kern_event.c index a431f36b2..aa0d6326f 100644 --- a/bsd/kern/kern_event.c +++ b/bsd/kern/kern_event.c @@ -31,10 +31,8 @@ #include #include #include - - -extern struct domain systemdomain; - +#include +#include int raw_usrreq(); @@ -55,6 +53,22 @@ struct kern_event_head kern_event_head; static u_long static_event_id = 0; +/* + * Install the protosw's for the NKE manager. Invoked at + * extension load time + */ +int +kern_event_init(void) +{ + int retval; + + if ((retval = net_add_proto(eventsw, &systemdomain)) == 0) + return(KERN_SUCCESS); + + log(LOG_WARNING, "Can't install kernel events protocol (%d)\n", retval); + return(retval); +} + int kev_attach(struct socket *so, int proto, struct proc *p) { int error; @@ -126,7 +140,6 @@ int kev_post_msg(struct kev_msg *event_msg) ev->event_code = event_msg->event_code; m->m_len = total_size; - ev_pcb = LIST_FIRST(&kern_event_head); for (ev_pcb = LIST_FIRST(&kern_event_head); ev_pcb; ev_pcb = LIST_NEXT(ev_pcb, ev_link)) { diff --git a/bsd/kern/kern_exec.c b/bsd/kern/kern_exec.c index 88348db3f..6eb6ebe8f 100644 --- a/bsd/kern/kern_exec.c +++ b/bsd/kern/kern_exec.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -94,6 +94,7 @@ #include #include +#include #include #include @@ -103,6 +104,11 @@ #include #include #include +#if KTRACE +#include +#endif + +int app_profile = 0; extern vm_map_t bsd_pageable_map; @@ -160,6 +166,7 @@ execve(p, uap, retval) vm_map_t old_map; vm_map_t map; int i; + boolean_t new_shared_regions = FALSE; union { /* #! and name of interpreter */ char ex_shell[SHSIZE]; @@ -181,6 +188,7 @@ execve(p, uap, retval) int vfexec=0; unsigned long arch_offset =0; unsigned long arch_size = 0; + char *ws_cache_name = NULL; /* used for pre-heat */ task = current_task(); thr_act = current_act(); @@ -214,7 +222,7 @@ execve(p, uap, retval) * We have to do this before namei() because in case of * symbolic links, namei() would overwrite the original "path". * In case the last symbolic link resolved was a relative pathname - * we would loose the original "path", which could be an + * we would lose the original "path", which could be an * absolute pathname. This might be unacceptable for dyld. */ /* XXX We could optimize to avoid copyinstr in the namei() */ @@ -226,6 +234,22 @@ execve(p, uap, retval) * copyinstr will put in savedpathlen, the count of * characters (including NULL) in the path. */ + + if(app_profile != 0) { + + /* grab the name of the file out of its path */ + /* we will need this for lookup within the */ + /* name file */ + ws_cache_name = savedpath + savedpathlen; + while (ws_cache_name[0] != '/') { + if(ws_cache_name == savedpath) { + ws_cache_name--; + break; + } + ws_cache_name--; + } + ws_cache_name++; + } /* Save the name aside for future use */ execargsp = (vm_offset_t *)((char *)(execargs) + savedpathlen); @@ -489,6 +513,8 @@ again: printf("execve: task_create failed. Code: 0x%x\n", result); p->task = new_task; set_bsdtask_info(new_task, p); + if (p->p_nice != 0) + resetpriority(p); task = new_task; map = get_task_map(new_task); result = thread_create(new_task, &thr_act); @@ -504,6 +530,23 @@ again: * Load the Mach-O file. */ VOP_UNLOCK(vp, 0, p); + if(ws_cache_name) { + tws_handle_startup_file(task, cred->cr_uid, + ws_cache_name, vp, &new_shared_regions); + } + if (new_shared_regions) { + shared_region_mapping_t new_shared_region; + shared_region_mapping_t old_shared_region; + + if (shared_file_create_system_region(&new_shared_region)) + panic("couldn't create system_shared_region\n"); + + vm_get_shared_region(task, &old_shared_region); + vm_set_shared_region(task, new_shared_region); + + shared_region_mapping_dealloc(old_shared_region); + } + lret = load_machfile(vp, mach_header, arch_offset, arch_size, &load_result, thr_act, map); @@ -580,10 +623,8 @@ again: p->p_cred->p_svuid = p->p_ucred->cr_uid; p->p_cred->p_svgid = p->p_ucred->cr_gid; - if (!vfexec && (p->p_flag & P_TRACED)) { + if (!vfexec && (p->p_flag & P_TRACED)) psignal(p, SIGTRAP); - ast_on(AST_BSD); - } if (error) { goto badtoolate; @@ -647,7 +688,11 @@ again: * and NBPW for the NULL after pointer to path. */ ap = ucp - na*NBPW - 3*NBPW - savedpathlen - 2*NBPW; +#if defined(ppc) + thread_setuserstack(thr_act, ap); /* Set the stack */ +#else uthread->uu_ar0[SP] = ap; +#endif (void) suword((caddr_t)ap, na-ne); /* argc */ nc = 0; cc = 0; @@ -682,14 +727,20 @@ again: } if (load_result.dynlinker) { +#if defined(ppc) + ap = thread_adjuserstack(thr_act, -4); /* Adjust the stack */ +#else ap = uthread->uu_ar0[SP] -= 4; +#endif (void) suword((caddr_t)ap, load_result.mach_header); } if (vfexec) { vm_map_switch(old_map); } -#if defined(i386) || defined(ppc) +#if defined(ppc) + thread_setentrypoint(thr_act, load_result.entry_point); /* Set the entry point */ +#elif defined(i386) uthread->uu_ar0[PC] = load_result.entry_point; #else #error architecture not implemented! @@ -701,7 +752,7 @@ again: /* * Reset signal state. */ - execsigs(p); + execsigs(p, thr_act); /* * Close file descriptors @@ -709,8 +760,10 @@ again: */ fdexec(p); /* FIXME: Till vmspace inherit is fixed: */ - if (p->vm_shm) + if (!vfexec && p->vm_shm) shmexit(p); + /* Clean up the semaphores */ + semexit(p); /* * Remember file name for accounting. @@ -753,7 +806,6 @@ again: badtoolate: if (vfexec) { - (void) thread_resume(thr_act); task_deallocate(new_task); act_deallocate(thr_act); if (error) @@ -768,6 +820,7 @@ bad1: execargs_free(execargs); if (!error && vfexec) { vfork_return(current_act(), p->p_pptr, p, retval); + (void) thread_resume(thr_act); return(0); } return(error); @@ -816,8 +869,6 @@ load_init_program(p) register_t retval[2]; struct uthread * ut; - unix_master(); - error = 0; /* init_args are copied in string form directly from bootstrap */ @@ -910,8 +961,6 @@ load_init_program(p) error = execve(p,&init_exec_args,retval); } while (error); - - unix_release(); } /* diff --git a/bsd/kern/kern_exit.c b/bsd/kern/kern_exit.c index f588872ac..3f6aa7236 100644 --- a/bsd/kern/kern_exit.c +++ b/bsd/kern/kern_exit.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -86,7 +86,11 @@ #include #include #include +#include #include +#if KTRACE +#include +#endif extern char init_task_failure_data[]; int exit1 __P((struct proc *, int, int *)); @@ -106,12 +110,12 @@ exit(p, uap, retval) { exit1(p, W_EXITCODE(uap->rval, 0), retval); - /* drop funnel befewo we return */ + /* drop funnel before we return */ thread_funnel_set(kernel_flock, FALSE); thread_exception_return(); /* NOTREACHED */ while (TRUE) - thread_block(0); + thread_block(THREAD_CONTINUE_NULL); /* NOTREACHED */ } @@ -141,7 +145,7 @@ exit1(p, rv, retval) ut = get_bsdthread_info(th_act_self); if (ut->uu_flag & P_VFORK) { - vfork_exit(p, rv); + (void)vfork_exit(p, rv); vfork_return(th_act_self, p->p_pptr, p , retval); unix_syscall_return(0); /* NOT REACHED */ @@ -172,7 +176,7 @@ exit1(p, rv, retval) s = splsched(); p->p_flag |= P_WEXIT; splx(s); - proc_prepareexit(p); + (void)proc_prepareexit(p); p->p_xstat = rv; /* task terminate will call proc_terminate and that cleans it up */ @@ -224,14 +228,14 @@ proc_prepareexit(struct proc *p) p->p_sigignore = ~0; p->p_siglist = 0; ut = get_bsdthread_info(th_act_self); - ut->uu_sig = 0; - untimeout(realitexpire, (caddr_t)p); + ut->uu_siglist = 0; + untimeout(realitexpire, (caddr_t)p->p_pid); } void proc_exit(struct proc *p) { - register struct proc *q, *nq; + register struct proc *q, *nq, *pp; thread_t self = current_thread(); thread_act_t th_act_self = current_act(); struct task *task = p->task; @@ -262,6 +266,8 @@ proc_exit(struct proc *p) /* Close ref SYSV Shared memory*/ if (p->vm_shm) shmexit(p); + /* Release SYSV semaphores */ + semexit(p); if (SESS_LEADER(p)) { register struct session *sp = p->p_session; @@ -301,6 +307,8 @@ proc_exit(struct proc *p) fixjobc(p, p->p_pgrp, 0); p->p_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; + (void)acct_process(p); + #if KTRACE /* * release trace file @@ -313,7 +321,6 @@ proc_exit(struct proc *p) } #endif - q = p->p_children.lh_first; if (q) /* only need this if any child is S_ZOMB */ wakeup((caddr_t) initproc); @@ -327,7 +334,9 @@ proc_exit(struct proc *p) if (q->p_flag & P_TRACED) { q->p_flag &= ~P_TRACED; if (q->sigwait_thread) { - thread_t sig_shuttle = getshuttle_thread(q->sigwait_thread); + thread_t sig_shuttle; + + sig_shuttle = (thread_t)getshuttle_thread((thread_act_t)q->sigwait_thread); /* * The sigwait_thread could be stopped at a * breakpoint. Wake it up to kill. @@ -335,9 +344,9 @@ proc_exit(struct proc *p) * the first thread in the task. So any attempts to kill * the process would result into a deadlock on q->sigwait. */ - thread_resume((struct thread *)q->sigwait_thread); + thread_resume((thread_act_t)q->sigwait_thread); clear_wait(sig_shuttle, THREAD_INTERRUPTED); - threadsignal(q->sigwait_thread, SIGKILL, 0); + threadsignal((thread_act_t)q->sigwait_thread, SIGKILL, 0); } psignal(q, SIGKILL); } @@ -421,7 +430,24 @@ proc_exit(struct proc *p) /* * Notify parent that we're gone. */ - psignal(p->p_pptr, SIGCHLD); + if (p->p_pptr->p_flag & P_NOCLDWAIT) { + struct proc * pp = p->p_pptr; + + proc_reparent(p, initproc); + /* If there are no more children wakeup parent */ + if (LIST_EMPTY(&pp->p_children)) + wakeup((caddr_t)pp); + } + /* should be fine as parent proc would be initproc */ + pp = p->p_pptr; + if (pp != initproc) { + pp->si_pid = p->p_pid; + pp->si_status = p->p_xstat; + pp->si_code = CLD_EXITED; + pp->si_uid = p->p_cred->p_ruid; + } + psignal(pp, SIGCHLD); + /* Place onto zombproc. */ LIST_INSERT_HEAD(&zombproc, p, p_list); @@ -509,8 +535,8 @@ wait1continue(result) p = current_proc(); thread = current_act(); - vt = get_bsduthreadarg(thread); - retval = get_bsduthreadrval(thread); + vt = (void *)get_bsduthreadarg(thread); + retval = (int *)get_bsduthreadrval(thread); wait1((struct proc *)p, (struct wait4_args *)vt, retval, 0); } @@ -578,6 +604,12 @@ loop: if (p->p_oppid && (t = pfind(p->p_oppid))) { p->p_oppid = 0; proc_reparent(p, t); + if (t != initproc) { + t->si_pid = p->p_pid; + t->si_status = p->p_xstat; + t->si_code = CLD_CONTINUED; + t->si_uid = p->p_cred->p_ruid; + } psignal(t, SIGCHLD); wakeup((caddr_t)t); p->p_flag &= ~P_WAITING; @@ -738,7 +770,7 @@ process_terminate_self(void) void vfork_exit(p, rv) - register struct proc *p; + struct proc *p; int rv; { register struct proc *q, *nq; @@ -798,18 +830,18 @@ panic("init died\nState at Last Exception:\n\n%s", init_task_failure_data); p->p_sigignore = ~0; p->p_siglist = 0; - ut->uu_sig = 0; - untimeout(realitexpire, (caddr_t)p); + ut->uu_siglist = 0; + untimeout(realitexpire, (caddr_t)p->p_pid); p->p_xstat = rv; - vproc_exit(p); + (void)vproc_exit(p); } void vproc_exit(struct proc *p) { - register struct proc *q, *nq; + register struct proc *q, *nq, *pp; thread_t self = current_thread(); thread_act_t th_act_self = current_act(); struct task *task = p->task; @@ -825,10 +857,6 @@ vproc_exit(struct proc *p) */ fdfree(p); - /* Close ref SYSV Shared memory*/ - if (p->vm_shm) - shmexit(p); - if (SESS_LEADER(p)) { register struct session *sp = p->p_session; @@ -867,6 +895,7 @@ vproc_exit(struct proc *p) fixjobc(p, p->p_pgrp, 0); p->p_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; + #if KTRACE /* * release trace file @@ -892,7 +921,9 @@ vproc_exit(struct proc *p) if (q->p_flag & P_TRACED) { q->p_flag &= ~P_TRACED; if (q->sigwait_thread) { - thread_t sig_shuttle = getshuttle_thread(q->sigwait_thread); + thread_t sig_shuttle; + + sig_shuttle = (thread_t) getshuttle_thread((thread_act_t)q->sigwait_thread); /* * The sigwait_thread could be stopped at a * breakpoint. Wake it up to kill. @@ -900,9 +931,9 @@ vproc_exit(struct proc *p) * the first thread in the task. So any attempts to kill * the process would result into a deadlock on q->sigwait. */ - thread_resume((struct thread *)q->sigwait_thread); + thread_resume((thread_act_t)q->sigwait_thread); clear_wait(sig_shuttle, THREAD_INTERRUPTED); - threadsignal(q->sigwait_thread, SIGKILL, 0); + threadsignal((thread_act_t)q->sigwait_thread, SIGKILL, 0); } psignal(q, SIGKILL); } @@ -986,6 +1017,13 @@ vproc_exit(struct proc *p) /* * Notify parent that we're gone. */ + pp = p->p_pptr; + if (pp != initproc) { + pp->si_pid = p->p_pid; + pp->si_status = p->p_xstat; + pp->si_code = CLD_EXITED; + pp->si_uid = p->p_cred->p_ruid; + } psignal(p->p_pptr, SIGCHLD); /* Place onto zombproc. */ diff --git a/bsd/kern/kern_fork.c b/bsd/kern/kern_fork.c index 58aa6ecf4..c34b51b31 100644 --- a/bsd/kern/kern_fork.c +++ b/bsd/kern/kern_fork.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -71,16 +71,18 @@ #include #include #include +#if KTRACE #include +#endif #include #include #include -thread_t cloneproc(struct proc *, int); +thread_act_t cloneproc(struct proc *, int); struct proc * forkproc(struct proc *, int); -thread_t procdup(); +thread_act_t procdup(); #define DOFORK 0x1 /* fork() system call */ #define DOVFORK 0x2 /* vfork() system call */ @@ -164,6 +166,7 @@ vfork(p, uap, retval) ut->uu_flag |= P_VFORK; ut->uu_proc = newproc; ut->uu_userstate = (void *)act_thread_csave(); + ut->uu_vforkmask = ut->uu_sigmask; thread_set_child(cur_act, newproc->p_pid); @@ -217,6 +220,7 @@ vfork_return(th_act, p, p2, retval) ut->uu_userstate = 0; ut->uu_flag &= ~P_VFORK; ut->uu_proc = 0; + ut->uu_sigmask = ut->uu_vforkmask; p2->p_flag &= ~P_INVFORK; p2->p_vforkact = (void *)0; @@ -230,12 +234,12 @@ vfork_return(th_act, p, p2, retval) return; } -thread_t +thread_act_t procdup( struct proc *child, struct proc *parent) { - thread_t thread; + thread_act_t thread; task_t task; kern_return_t result; extern task_t kernel_task; @@ -267,7 +271,7 @@ fork1(p1, flags, retval) { register struct proc *p2; register uid_t uid; - thread_t newth, self = current_thread(); + thread_act_t newth; int s, count; task_t t; @@ -297,7 +301,7 @@ fork1(p1, flags, retval) /* The newly created process comes with signal lock held */ newth = cloneproc(p1, 1); - thread_dup(current_act(), newth); + thread_dup(newth); /* p2 = newth->task->proc; */ p2 = (struct proc *)(get_bsdtask_info(get_threadtask(newth))); @@ -344,15 +348,17 @@ fork1(p1, flags, retval) * lock set. fork() code needs to explicity remove this lock * before signals can be delivered */ -thread_t +thread_act_t cloneproc(p1, lock) register struct proc *p1; register int lock; { register struct proc *p2; - thread_t th; + thread_act_t th; p2 = (struct proc *)forkproc(p1,lock); + + th = procdup(p2, p1); /* child, parent */ LIST_INSERT_AFTER(p1, p2, p_pglist); @@ -417,7 +423,8 @@ retry: again: for (; p2 != 0; p2 = p2->p_list.le_next) { while (p2->p_pid == nextpid || - p2->p_pgrp->pg_id == nextpid) { + p2->p_pgrp->pg_id == nextpid || + p2->p_session->s_sid == nextpid) { nextpid++; if (nextpid >= pidchecked) goto retry; @@ -427,6 +434,9 @@ again: if (p2->p_pgrp && p2->p_pgrp->pg_id > nextpid && pidchecked > p2->p_pgrp->pg_id) pidchecked = p2->p_pgrp->pg_id; + if (p2->p_session->s_sid > nextpid && + pidchecked > p2->p_session->s_sid) + pidchecked = p2->p_session->s_sid; } if (!doingzomb) { doingzomb = 1; @@ -464,7 +474,7 @@ again: crhold(p1->p_ucred); lockinit(&p2->p_cred->pc_lock, PLOCK, "proc cred", 0, 0); - /* bump references to the text vnode (for procfs) */ + /* bump references to the text vnode */ p2->p_textvp = p1->p_textvp; if (p2->p_textvp) VREF(p2->p_textvp); @@ -514,9 +524,10 @@ again: p2->sigwait_thread = NULL; p2->exit_thread = NULL; p2->user_stack = p1->user_stack; - p2->p_sigpending = 0; + p2->p_xxxsigpending = 0; p2->p_vforkcnt = 0; p2->p_vforkact = 0; + TAILQ_INIT(&p2->p_uthlist); #if KTRACE /* @@ -551,25 +562,53 @@ uthread_zone_init() } void * -uthread_alloc(void) +uthread_alloc(task_t task, thread_act_t thr_act ) { + struct proc *p; + struct uthread *uth, *uth_parent; void *ut; + extern task_t kernel_task; + boolean_t funnel_state; if (!uthread_zone_inited) uthread_zone_init(); ut = (void *)zalloc(uthread_zone); bzero(ut, sizeof(struct uthread)); + + if (task != kernel_task) { + uth = (struct uthread *)ut; + p = get_bsdtask_info(task); + + funnel_state = thread_funnel_set(kernel_flock, TRUE); + uth_parent = (struct uthread *)get_bsdthread_info(current_act()); + if (uth_parent) { + if (uth_parent->uu_flag & USAS_OLDMASK) + uth->uu_sigmask = uth_parent->uu_oldmask; + else + uth->uu_sigmask = uth_parent->uu_sigmask; + } + uth->uu_act = thr_act; + //signal_lock(p); + if (p) + TAILQ_INSERT_TAIL(&p->p_uthlist, uth, uu_list); + //signal_unlock(p); + (void)thread_funnel_set(kernel_flock, funnel_state); + } + return (ut); } void -uthread_free(void *uthread) +uthread_free(task_t task, void *uthread, void * bsd_info) { struct _select *sel; struct uthread *uth = (struct uthread *)uthread; + struct proc * p = (struct proc *)bsd_info; + extern task_t kernel_task; int size; + boolean_t funnel_state; sel = &uth->uu_state.ss_select; /* cleanup the select bit space */ @@ -586,6 +625,13 @@ uthread_free(void *uthread) sel->wql = 0; } + if ((task != kernel_task) && p) { + funnel_state = thread_funnel_set(kernel_flock, TRUE); + //signal_lock(p); + TAILQ_REMOVE(&p->p_uthlist, uth, uu_list); + //signal_unlock(p); + (void)thread_funnel_set(kernel_flock, funnel_state); + } /* and free the uthread itself */ zfree(uthread_zone, (vm_offset_t)uthread); } diff --git a/bsd/kern/kern_ktrace.c b/bsd/kern/kern_ktrace.c index c88bbf81a..a4ccca92a 100644 --- a/bsd/kern/kern_ktrace.c +++ b/bsd/kern/kern_ktrace.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -53,80 +53,106 @@ * SUCH DAMAGE. * * @(#)kern_ktrace.c 8.2 (Berkeley) 9/23/93 + * $FreeBSD: src/sys/kern/kern_ktrace.c,v 1.35.2.4 2001/03/05 13:09:01 obrien Exp $ */ #include #include +#include #include #include #include #include +#if KTRACE #include +#endif #include #include -#include - #if KTRACE +static struct ktr_header *ktrgetheader __P((int type)); +static void ktrwrite __P((struct vnode *, struct ktr_header *, + struct uio *, int)); +static int ktrcanset __P((struct proc *,struct proc *)); +static int ktrsetchildren __P((struct proc *,struct proc *, + int, int, struct vnode *)); +static int ktrops __P((struct proc *,struct proc *,int,int,struct vnode *)); -struct ktr_header * + +static struct ktr_header * ktrgetheader(type) int type; { register struct ktr_header *kth; struct proc *p = current_proc(); /* XXX */ - MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header), - M_TEMP, M_WAITOK); + MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header), + M_KTRACE, 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); } +#endif void -ktrsyscall(vp, code, argsize, args) - struct vnode *vp; - register_t code; - size_t argsize; +ktrsyscall(p, code, narg, args, funnel_type) + struct proc *p; + int code, narg; register_t args[]; + int funnel_type; { +#if KTRACE + struct vnode *vp; struct ktr_header *kth; struct ktr_syscall *ktp; - register len = sizeof(struct ktr_syscall) + argsize; - struct proc *p = current_proc(); /* XXX */ + register int len; register_t *argp; int i; + if (!KTRPOINT(p, KTR_SYSCALL)) + return; + + vp = p->p_tracep; + len = __offsetof(struct ktr_syscall, ktr_args) + + (narg * sizeof(register_t)); p->p_traceflag |= KTRFAC_ACTIVE; kth = ktrgetheader(KTR_SYSCALL); - MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK); + MALLOC(ktp, struct ktr_syscall *, len, M_KTRACE, M_WAITOK); ktp->ktr_code = code; - ktp->ktr_argsize = argsize; - argp = (register_t *)((char *)ktp + sizeof(struct ktr_syscall)); - for (i = 0; i < (argsize / sizeof *argp); i++) + ktp->ktr_narg = narg; + argp = &ktp->ktr_args[0]; + 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); + ktrwrite(vp, kth, NULL, funnel_type); + FREE(ktp, M_KTRACE); + FREE(kth, M_KTRACE); p->p_traceflag &= ~KTRFAC_ACTIVE; +#else + return; +#endif } - + void -ktrsysret(vp, code, error, retval) - struct vnode *vp; - register_t code; - int error; +ktrsysret(p, code, error, retval, funnel_type) + struct proc *p; + int code, error; register_t retval; + int funnel_type; { +#if KTRACE + struct vnode *vp; struct ktr_header *kth; struct ktr_sysret ktp; - struct proc *p = current_proc(); /* XXX */ + if (!KTRPOINT(p, KTR_SYSRET)) + return; + + vp = p->p_tracep; p->p_traceflag |= KTRFAC_ACTIVE; kth = ktrgetheader(KTR_SYSRET); ktp.ktr_code = code; @@ -136,11 +162,15 @@ ktrsysret(vp, code, error, retval) kth->ktr_buf = (caddr_t)&ktp; kth->ktr_len = sizeof(struct ktr_sysret); - ktrwrite(vp, kth); - FREE(kth, M_TEMP); + ktrwrite(vp, kth, NULL, funnel_type); + FREE(kth, M_KTRACE); p->p_traceflag &= ~KTRFAC_ACTIVE; +#else + return; +#endif } +#if KTRACE void ktrnamei(vp, path) struct vnode *vp; @@ -154,59 +184,49 @@ ktrnamei(vp, path) kth->ktr_len = strlen(path); kth->ktr_buf = path; - ktrwrite(vp, kth); - FREE(kth, M_TEMP); + ktrwrite(vp, kth, NULL, KERNEL_FUNNEL); + FREE(kth, M_KTRACE); p->p_traceflag &= ~KTRFAC_ACTIVE; } void -ktrgenio(vp, fd, rw, iov, len, error) +ktrgenio(vp, fd, rw, uio, error, funnel_type) struct vnode *vp; int fd; enum uio_rw rw; - register struct iovec *iov; - int len, error; + struct uio *uio; + int error; + int funnel_type; { struct ktr_header *kth; - register struct ktr_genio *ktp; - register caddr_t cp; - register int resid = len, cnt; + struct ktr_genio ktg; struct proc *p = current_proc(); /* XXX */ - + if (error) return; + p->p_traceflag |= KTRFAC_ACTIVE; kth = ktrgetheader(KTR_GENIO); - 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); + ktg.ktr_fd = fd; + ktg.ktr_rw = rw; + kth->ktr_buf = (caddr_t)&ktg; + kth->ktr_len = sizeof(struct ktr_genio); + uio->uio_offset = 0; + uio->uio_rw = UIO_WRITE; + + ktrwrite(vp, kth, uio, funnel_type); + FREE(kth, M_KTRACE); p->p_traceflag &= ~KTRFAC_ACTIVE; } void -ktrpsig(vp, sig, action, mask, code) +ktrpsig(vp, sig, action, mask, code, funnel_type) struct vnode *vp; int sig; sig_t action; - int mask, code; + sigset_t *mask; + int code; + int funnel_type; { struct ktr_header *kth; struct ktr_psig kp; @@ -216,20 +236,21 @@ ktrpsig(vp, sig, action, mask, code) kth = ktrgetheader(KTR_PSIG); kp.signo = (char)sig; kp.action = action; - kp.mask = mask; + 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); + ktrwrite(vp, kth, NULL, funnel_type); + FREE(kth, M_KTRACE); p->p_traceflag &= ~KTRFAC_ACTIVE; } void -ktrcsw(vp, out, user) +ktrcsw(vp, out, user, funnel_type) struct vnode *vp; int out, user; + int funnel_type; { struct ktr_header *kth; struct ktr_csw kc; @@ -242,10 +263,11 @@ ktrcsw(vp, out, user) kth->ktr_buf = (caddr_t)&kc; kth->ktr_len = sizeof (struct ktr_csw); - ktrwrite(vp, kth); - FREE(kth, M_TEMP); + ktrwrite(vp, kth, NULL, funnel_type); + FREE(kth, M_KTRACE); p->p_traceflag &= ~KTRFAC_ACTIVE; } +#endif /* KTRACE */ /* Interface and common routines */ @@ -253,10 +275,10 @@ ktrcsw(vp, out, user) * ktrace system call */ struct ktrace_args { - char * fname; - int ops; - int facs; - int pid; + char *fname; + int ops; + int facs; + int pid; }; /* ARGSUSED */ int @@ -265,12 +287,13 @@ ktrace(curp, uap, retval) register struct ktrace_args *uap; register_t *retval; { +#if KTRACE register struct vnode *vp = NULL; register struct proc *p; struct pgrp *pg; - int facs = SCARG(uap, facs) & ~KTRFAC_ROOT; - int ops = KTROP(SCARG(uap, ops)); - int descend = SCARG(uap, ops) & KTRFLAG_DESCEND; + 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; @@ -280,14 +303,14 @@ ktrace(curp, uap, retval) /* * an operation which requires a file argument. */ - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, fname), - curp); - if (error = vn_open(&nd, FREAD|FWRITE, 0)) { + NDINIT(&nd, LOOKUP, (NOFOLLOW|LOCKLEAF), UIO_USERSPACE, uap->fname, curp); + error = vn_open(&nd, FREAD|FWRITE|O_NOFOLLOW, 0); + if (error) { curp->p_traceflag &= ~KTRFAC_ACTIVE; return (error); } vp = nd.ni_vp; - VOP_UNLOCK(vp, 0, p); + VOP_UNLOCK(vp, 0, curp); if (vp->v_type != VREG) { (void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp); curp->p_traceflag &= ~KTRFAC_ACTIVE; @@ -298,19 +321,23 @@ ktrace(curp, uap, retval) * Clear all uses of the tracefile */ if (ops == KTROP_CLEARFILE) { - for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) { + LIST_FOREACH(p, &allproc, p_list) { if (p->p_tracep == vp) { if (ktrcanset(curp, p)) { - p->p_tracep = NULL; + struct vnode *tvp = p->p_tracep; + /* no more tracing */ p->p_traceflag = 0; - (void) vn_close(vp, FREAD|FWRITE, - p->p_ucred, p); + if (tvp != NULL) { + p->p_tracep = NULL; + vrele(tvp); + } } else error = EPERM; } } goto done; } + /* * need something to (un)trace (XXX - why is this here?) */ @@ -318,29 +345,29 @@ ktrace(curp, uap, retval) error = EINVAL; goto done; } - /* + /* * do it */ - if (SCARG(uap, pid) < 0) { + if (uap->pid < 0) { /* * by process group */ - pg = pgfind(-SCARG(uap, pid)); + pg = pgfind(-uap->pid); if (pg == NULL) { error = ESRCH; goto done; } - for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) + LIST_FOREACH(p, &pg->pg_members, p_pglist) if (descend) ret |= ktrsetchildren(curp, p, ops, facs, vp); - else + else ret |= ktrops(curp, p, ops, facs, vp); - + } else { /* * by pid */ - p = pfind(SCARG(uap, pid)); + p = pfind(uap->pid); if (p == NULL) { error = ESRCH; goto done; @@ -357,38 +384,87 @@ done: (void) vn_close(vp, FWRITE, curp->p_ucred, curp); curp->p_traceflag &= ~KTRFAC_ACTIVE; return (error); +#else + return ENOSYS; +#endif } +/* + * utrace system call + */ +struct utrace_args { + const void * addr; + size_t len; +}; + +/* ARGSUSED */ int +utrace(curp, uap, retval) + struct proc *curp; + register struct utrace_args *uap; + register_t *retval; +{ +#if KTRACE + struct ktr_header *kth; + struct proc *p = current_proc(); /* XXX */ + register caddr_t cp; + + if (!KTRPOINT(p, KTR_USER)) + return (0); + if (uap->len > KTR_USER_MAXLEN) + return (EINVAL); + p->p_traceflag |= KTRFAC_ACTIVE; + kth = ktrgetheader(KTR_USER); + MALLOC(cp, caddr_t, uap->len, M_KTRACE, M_WAITOK); + if (!copyin(uap->addr, cp, uap->len)) { + kth->ktr_buf = cp; + kth->ktr_len = uap->len; + ktrwrite(p->p_tracep, kth, NULL, KERNEL_FUNNEL); + } + FREE(kth, M_KTRACE); + FREE(cp, M_KTRACE); + p->p_traceflag &= ~KTRFAC_ACTIVE; + + return (0); +#else + return (ENOSYS); +#endif +} + +#if KTRACE +static int ktrops(curp, p, ops, facs, vp) struct proc *p, *curp; int ops, facs; struct vnode *vp; { + struct vnode *tvp; if (!ktrcanset(curp, p)) return (0); if (ops == KTROP_SET) { - if (p->p_tracep != vp) { + if (p->p_tracep != vp) { /* * if trace file already in use, relinquish */ - if (p->p_tracep != NULL) - vrele(p->p_tracep); + tvp = p->p_tracep; VREF(vp); p->p_tracep = vp; + if (tvp != NULL) + vrele(tvp); } p->p_traceflag |= facs; if (curp->p_ucred->cr_uid == 0) p->p_traceflag |= KTRFAC_ROOT; - } else { + } else { /* KTROP_CLEAR */ if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) { /* no more tracing */ + tvp = p->p_tracep; p->p_traceflag = 0; - if (p->p_tracep != NULL) { - vrele(p->p_tracep); + if (tvp != NULL) { p->p_tracep = NULL; + vrele(tvp); } } } @@ -396,6 +472,7 @@ ktrops(curp, p, ops, facs, vp) return (1); } +static int ktrsetchildren(curp, top, ops, facs, vp) struct proc *curp, *top; int ops, facs; @@ -412,13 +489,13 @@ ktrsetchildren(curp, top, ops, facs, vp) * otherwise do any siblings, and if done with this level, * follow back up the tree (but not past top). */ - if (p->p_children.lh_first) - p = p->p_children.lh_first; + if (!LIST_EMPTY(&p->p_children)) + p = LIST_FIRST(&p->p_children); else for (;;) { if (p == top) return (ret); - if (p->p_sibling.le_next) { - p = p->p_sibling.le_next; + if (LIST_NEXT(p, p_sibling)) { + p = LIST_NEXT(p, p_sibling); break; } p = p->p_pptr; @@ -427,9 +504,11 @@ ktrsetchildren(curp, top, ops, facs, vp) /*NOTREACHED*/ } -ktrwrite(vp, kth) +static void +ktrwrite(vp, kth, uio, funnel_type) struct vnode *vp; register struct ktr_header *kth; + struct uio *uio; { struct uio auio; struct iovec aiov[2]; @@ -438,6 +517,30 @@ ktrwrite(vp, kth) if (vp == NULL) return; + + if (funnel_type == -1) { + funnel_t *f = thread_funnel_get(); + if(f == THR_FUNNEL_NULL) + funnel_type = NO_FUNNEL; + else if (f == (funnel_t *)network_flock) + funnel_type = NETWORK_FUNNEL; + else if (f == (funnel_t *)kernel_flock) + funnel_type = KERNEL_FUNNEL; + } + + switch (funnel_type) { + case KERNEL_FUNNEL: + /* Nothing more to do */ + break; + case NETWORK_FUNNEL: + thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); + break; + case NO_FUNNEL: + (void) thread_funnel_set(kernel_flock, TRUE); + break; + default: + panic("Invalid funnel (%)", funnel_type); + } auio.uio_iov = &aiov[0]; auio.uio_offset = 0; auio.uio_segflg = UIO_SYSSPACE; @@ -446,47 +549,91 @@ ktrwrite(vp, 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; + auio.uio_procp = current_proc(); 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; + if (uio != NULL) + kth->ktr_len += uio->uio_resid; + } + error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + if (error) + goto bad; + (void)VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + error = VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, p->p_ucred); + if (error == 0 && uio != NULL) { + (void)VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + error = VOP_WRITE(vp, uio, IO_UNIT | IO_APPEND, p->p_ucred); } - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, p->p_ucred); VOP_UNLOCK(vp, 0, p); - if (!error) + if (!error) { + switch (funnel_type) { + case KERNEL_FUNNEL: + /* Nothing more to do */ + break; + case NETWORK_FUNNEL: + thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); + /* switch funnel to NETWORK_FUNNEL */ + break; + case NO_FUNNEL: + (void) thread_funnel_set(kernel_flock, FALSE); + break; + default: + panic("Invalid funnel (%)", funnel_type); + } return; + } + +bad: /* * If error encountered, give up tracing on this vnode. */ log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n", error); - for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) { + LIST_FOREACH(p, &allproc, p_list) { if (p->p_tracep == vp) { p->p_tracep = NULL; p->p_traceflag = 0; vrele(vp); } } + + switch (funnel_type) { + case KERNEL_FUNNEL: + /* Nothing more to do */ + break; + case NETWORK_FUNNEL: + thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); + /* switch funnel to NETWORK_FUNNEL */ + break; + case NO_FUNNEL: + (void) thread_funnel_set(kernel_flock, FALSE); + break; + default: + panic("Invalid funnel (%)", funnel_type); + } } /* * 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 + * 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. */ +static int ktrcanset(callp, targetp) struct proc *callp, *targetp; { register struct pcred *caller = callp->p_cred; register struct pcred *target = targetp->p_cred; + if (!PRISON_CHECK(callp, targetp)) + return (0); if ((caller->pc_ucred->cr_uid == target->p_ruid && target->p_ruid == target->p_svuid && caller->p_rgid == target->p_rgid && /* XXX */ @@ -498,4 +645,4 @@ ktrcanset(callp, targetp) return (0); } -#endif +#endif /* KTRACE */ diff --git a/bsd/kern/kern_malloc.c b/bsd/kern/kern_malloc.c index 24086441b..cf158f9b2 100644 --- a/bsd/kern/kern_malloc.c +++ b/bsd/kern/kern_malloc.c @@ -75,11 +75,11 @@ #include #include #include +#include -#include #include -#include +#include #include #include @@ -190,8 +190,8 @@ struct kmzones { KMZ_CREATEZONE, /* 73 M_OFILETABL */ MCLBYTES, KMZ_CREATEZONE, /* 74 M_MCLUST */ SOX(hfsmount), KMZ_LOOKUPZONE, /* 75 M_HFSMNT */ - SOS(hfsnode), KMZ_CREATEZONE, /* 76 M_HFSNODE */ - SOS(hfsfilemeta), KMZ_CREATEZONE, /* 77 M_HFSFMETA */ + SOS(cnode), KMZ_CREATEZONE, /* 76 M_HFSNODE */ + SOS(filefork), KMZ_CREATEZONE, /* 77 M_HFSFORK */ SOX(volfs_mntdata), KMZ_LOOKUPZONE, /* 78 M_VOLFSMNT */ SOS(volfs_vndata), KMZ_CREATEZONE, /* 79 M_VOLFSNODE */ 0, KMZ_MALLOC, /* 80 M_TEMP */ @@ -202,7 +202,9 @@ struct kmzones { 0, KMZ_MALLOC, /* 85 M_UDFMOUNT */ 0, KMZ_MALLOC, /* 86 M_IP6NDP */ 0, KMZ_MALLOC, /* 87 M_IP6OPT */ - 0, KMZ_MALLOC, /* 88 M_NATPT */ + 0, KMZ_MALLOC, /* 88 M_IP6MISC */ + 0, KMZ_MALLOC, /* 89 M_TSEGQ */ + 0, KMZ_MALLOC, /* 90 M_IGMP */ #undef SOS #undef SOX @@ -264,6 +266,8 @@ struct _mhead { char dat[0]; }; +#define ZEROSIZETOKEN 0xFADEDFAD + void *_MALLOC( size_t size, int type, @@ -275,8 +279,12 @@ void *_MALLOC( if (type >= M_LAST) panic("_malloc TYPE"); + /* + * On zero request we do not return zero as that + * could be mistaken for ENOMEM. + */ if (size == 0) - return (0); + return (ZEROSIZETOKEN); if (flags & M_NOWAIT) { mem = (void *)kalloc_noblock(memsize); @@ -300,8 +308,10 @@ void _FREE( if (type >= M_LAST) panic("_free TYPE"); - if (!addr) + if (addr == (void *)ZEROSIZETOKEN) return; + if (!addr) + return; /* correct (convenient bsd kernel legacy) */ hdr = addr; hdr--; kfree((vm_offset_t)hdr, hdr->mlen); diff --git a/bsd/kern/kern_mman.c b/bsd/kern/kern_mman.c index 25c48f396..ed614c238 100644 --- a/bsd/kern/kern_mman.c +++ b/bsd/kern/kern_mman.c @@ -733,12 +733,12 @@ madvise(p, uap, retval) */ if (VM_MAX_ADDRESS > 0 && ((vm_offset_t) uap->addr + uap->len) > VM_MAX_ADDRESS) - return (EINVAL); + return (ENOMEM); if (VM_MIN_ADDRESS > 0 && uap->addr < VM_MIN_ADDRESS) - return (EINVAL); + return (ENOMEM); if (((vm_offset_t) uap->addr + uap->len) < (vm_offset_t) uap->addr) - return (EINVAL); + return (ENOMEM); /* * Since this routine is only advisory, we default to conservative @@ -752,14 +752,24 @@ madvise(p, uap, retval) switch (uap->behav) { case MADV_RANDOM: new_behavior = VM_BEHAVIOR_RANDOM; + break; case MADV_SEQUENTIAL: new_behavior = VM_BEHAVIOR_SEQUENTIAL; + break; case MADV_NORMAL: - default: new_behavior = VM_BEHAVIOR_DEFAULT; + break; + case MADV_WILLNEED: + new_behavior = VM_BEHAVIOR_WILLNEED; + break; + case MADV_DONTNEED: + new_behavior = VM_BEHAVIOR_DONTNEED; + break; + default: + return(EINVAL); } - result = vm_behavior_set(user_map, start, end, uap->behav); + result = vm_behavior_set(user_map, start, end, new_behavior); switch (result) { case KERN_SUCCESS: return (0); @@ -923,7 +933,7 @@ mlock(p, uap, retval) user_map = current_map(); /* vm_wire */ - result = vm_wire(host_priv_self(), user_map, addr, size, VM_PROT_ALL); + result = vm_map_wire(user_map, addr, (vm_offset_t)(addr+size), VM_PROT_NONE, TRUE); return (result == KERN_SUCCESS ? 0 : ENOMEM); } @@ -1082,7 +1092,7 @@ kern_return_t map_fd_funneled( return (KERN_INVALID_ARGUMENT); if (offset & PAGE_MASK_64) { - printf("map_fd: file offset not page aligned(%d : %s\)n",p->p_pid, p->p_comm); + printf("map_fd: file offset not page aligned(%d : %s)\n",p->p_pid, p->p_comm); return (KERN_INVALID_ARGUMENT); } map_size = round_page(size); diff --git a/bsd/kern/kern_newsysctl.c b/bsd/kern/kern_newsysctl.c index d24a34b51..399bbdb92 100644 --- a/bsd/kern/kern_newsysctl.c +++ b/bsd/kern/kern_newsysctl.c @@ -644,7 +644,7 @@ sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l) if (i > req->oldlen - req->oldidx) i = req->oldlen - req->oldidx; if (i > 0) { - error = copyout(p, (char *)req->oldptr + req->oldidx, i); + error = copyout((void*)p, (char *)req->oldptr + req->oldidx, i); if (error) return error; } @@ -742,7 +742,7 @@ sysctl_old_user(struct sysctl_req *req, const void *p, size_t l) if (i > req->oldlen - req->oldidx) i = req->oldlen - req->oldidx; if (i > 0) - error = copyout(p, (char *)req->oldptr + req->oldidx, + error = copyout((void*)p, (char *)req->oldptr + req->oldidx, i); } req->oldidx += l; diff --git a/bsd/kern/kern_panicinfo.c b/bsd/kern/kern_panicinfo.c new file mode 100644 index 000000000..62f79dafe --- /dev/null +++ b/bsd/kern/kern_panicinfo.c @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* prototypes not exported by osfmk. */ +extern void kmem_free(vm_map_t, vm_offset_t, vm_size_t); +extern kern_return_t kmem_alloc_wired(vm_map_t, vm_offset_t *, vm_size_t); + + +/* Globals */ +static off_t imagesizelimit = (4 * 4096); + +/* Information about the current panic image */ +static int image_bits = 32; /* Bitdepth */ + +static char *image_pathname = NULL; /* path to it */ +static size_t image_pathlen = 0; /* and the length of the pathname */ + +static vm_offset_t image_ptr = NULL; /* the image itself */ +static off_t image_size = 0; /* and the imagesize */ + + +__private_extern__ void +get_panicimage(vm_offset_t *imageptr, vm_size_t *imagesize, int *imagebits) +{ + *imageptr = image_ptr; + *imagesize = image_size; + *imagebits = image_bits; +} + +static int +panicimage_from_file( + char *imname, + off_t sizelimit, + vm_offset_t *image, + off_t *filesize, + struct proc *p) +{ + int error = 0; + int error1 = 0; + int aresid; + struct nameidata nd; + struct vattr vattr; + struct vnode * vp; + kern_return_t kret; + struct pcred *pcred = p->p_cred; + struct ucred *cred = pcred->pc_ucred; + vm_offset_t iobuf; + + /* Open the file */ + NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, imname, p); + error = vn_open(&nd, FREAD, S_IRUSR); + if (error) + return (error); + vp = nd.ni_vp; + + if (vp->v_type != VREG) { + error = EFAULT; + goto out; + } + + /* get the file size */ + error = VOP_GETATTR(vp, &vattr, cred, p); + if (error) + goto out; + + /* validate the file size */ + if (vattr.va_size > sizelimit) { + error = EFBIG; + goto out; + } + + /* allocate kernel wired memory */ + kret = kmem_alloc_wired(kernel_map, &iobuf, + (vm_size_t)vattr.va_size); + if (kret != KERN_SUCCESS) { + switch (kret) { + default: + error = EINVAL; + break; + case KERN_NO_SPACE: + case KERN_RESOURCE_SHORTAGE: + error = ENOMEM; + break; + case KERN_PROTECTION_FAILURE: + error = EPERM; + break; + } + goto out; + } + + /* read the file in the kernel buffer */ + error = vn_rdwr(UIO_READ, vp, (caddr_t)iobuf, (int)vattr.va_size, + (off_t)0, UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, + cred, &aresid, p); + if (error) { + (void)kmem_free(kernel_map, iobuf, (vm_size_t)vattr.va_size); + goto out; + } + + /* + * return the image to the caller + * freeing this memory is callers responsibility + */ + *image = iobuf; + *filesize = (off_t)vattr.va_size; + +out: + VOP_UNLOCK(vp, 0, p); + error1 = vn_close(vp, FREAD, cred, p); + if (error == 0) + error = error1; + return (error); +} + +__private_extern__ int +sysctl_dopanicinfo(name, namelen, oldp, oldlenp, newp, newlen, p) + int *name; + u_int namelen; + void *oldp; + size_t *oldlenp; + void *newp; + size_t newlen; + struct proc *p; +{ + int error = 0; + int bitdepth = 32; /* default is 32 bits */ + char *imname; + + /* all sysctl names at this level are terminal */ + if (namelen != 1) + return (ENOTDIR); /* overloaded */ + + switch (name[0]) { + default: + return (EOPNOTSUPP); + case KERN_PANICINFO_MAXSIZE: + if (newp != NULL && (error = suser(p->p_ucred, &p->p_acflag))) + return (error); + error = sysctl_quad(oldp, oldlenp, newp, newlen, &imagesizelimit); + return (error); + + case KERN_PANICINFO_IMAGE16: + bitdepth = 16; + /* and fall through */ + case KERN_PANICINFO_IMAGE32: + /* allocate a buffer for the image pathname */ + MALLOC_ZONE(imname, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); + + if (!newp) { + bcopy(image_pathname, imname, image_pathlen); + imname[image_pathlen] = '\0'; + } else + imname[0] = '\0'; + error = sysctl_string(oldp, oldlenp, newp, newlen, + imname, MAXPATHLEN); + if (newp && !error) { + char *tmpstr, *oldstr; + off_t filesize = 0; + size_t len; + vm_offset_t image; + vm_offset_t oimage; + vm_size_t osize; + + len = strlen(imname); + oldstr = image_pathname; + + error = panicimage_from_file(imname, imagesizelimit, + &image, &filesize, p); + if (error) + goto errout; + + /* release the old image */ + if (image_ptr) { + oimage = image_ptr; + osize = image_size; + } + + /* remember the new one */ + image_ptr = image; + image_bits = bitdepth; /* new bith depth */ + image_size = filesize; /* new imagesize */ + + if (oimage) + kmem_free(kernel_map, oimage, osize); + + /* save the new name */ + MALLOC(tmpstr, char *, len+1, M_TEMP, M_WAITOK); + bcopy(imname, tmpstr, len); + tmpstr[len] = '\0'; + + image_pathname = tmpstr; /* new pathname */ + image_pathlen = len; /* new pathname length */ + + /* free the old name */ + FREE(oldstr, M_TEMP); + } +errout: + FREE_ZONE(imname, MAXPATHLEN, M_NAMEI); + return (error); + } +} diff --git a/bsd/kern/kern_proc.c b/bsd/kern/kern_proc.c index e040cd76e..97f98cc1d 100644 --- a/bsd/kern/kern_proc.c +++ b/bsd/kern/kern_proc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -167,6 +167,23 @@ inferior(p) return (0); return (1); } +/* + * Is p an inferior of t ? + */ +int +isinferior(p, t) + register struct proc *p; + register struct proc *t; +{ + + /* if p==t they are not inferior */ + if (p == t) + return(0); + for (; p != t; p = p->p_pptr) + if (p->p_pid == 0) + return (0); + return (1); +} /* * Locate a process by number @@ -231,8 +248,10 @@ enterpgrp(p, pgid, mksess) #endif MALLOC_ZONE(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, M_WAITOK); - if ((np = pfind(savepid)) == NULL || np != p) + if ((np = pfind(savepid)) == NULL || np != p) { + FREE_ZONE(pgrp, sizeof(struct pgrp), M_PGRP); return (ESRCH); + } if (mksess) { register struct session *sess; @@ -242,6 +261,7 @@ enterpgrp(p, pgid, mksess) MALLOC_ZONE(sess, struct session *, sizeof(struct session), M_SESSION, M_WAITOK); sess->s_leader = p; + sess->s_sid = p->p_pid; sess->s_count = 1; sess->s_ttyvp = NULL; sess->s_ttyp = NULL; diff --git a/bsd/kern/kern_prot.c b/bsd/kern/kern_prot.c index 5882e93cf..66c98a137 100644 --- a/bsd/kern/kern_prot.c +++ b/bsd/kern/kern_prot.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -75,6 +75,8 @@ #include #include +#include + #include /* @@ -131,6 +133,56 @@ getpgrp(p, uap, retval) return (0); } +/* Get an arbitary pid's process group id */ +struct getpgid_args { + pid_t pid; +}; + +int +getpgid(p, uap, retval) + struct proc *p; + struct getpgid_args *uap; + register_t *retval; +{ + struct proc *pt; + + pt = p; + if (uap->pid == 0) + goto found; + + if ((pt = pfind(uap->pid)) == 0) + return (ESRCH); +found: + *retval = pt->p_pgrp->pg_id; + return (0); +} + +/* + * Get an arbitary pid's session id. + */ +struct getsid_args { + pid_t pid; +}; + +int +getsid(p, uap, retval) + struct proc *p; + struct getsid_args *uap; + register_t *retval; +{ + struct proc *pt; + + pt = p; + if (uap->pid == 0) + goto found; + + if ((pt = pfind(uap->pid)) == 0) + return (ESRCH); +found: + *retval = pt->p_session->s_sid; + return (0); +} + /* ARGSUSED */ getuid(p, uap, retval) struct proc *p; @@ -322,6 +374,9 @@ setuid(p, uap, retval) * Transfer proc count to new user. * Copy credentials so other references do not see our changes. */ + + /* prepare app access profile files */ + prepare_profile_database(uap->uid); pcred_writelock(p); (void)chgproccnt(pc->p_ruid, -1); (void)chgproccnt(uid, 1); @@ -712,14 +767,14 @@ setlogin(p, uap, retval) /* Set the secrity token of the task with current euid and eguid */ -void +kern_return_t set_security_token(struct proc * p) { security_token_t sec_token; sec_token.val[0] = p->p_ucred->cr_uid; sec_token.val[1] = p->p_ucred->cr_gid; - (void)host_security_set_task_token(host_security_self(), + return host_security_set_task_token(host_security_self(), p->task, sec_token, (sec_token.val[0]) ? diff --git a/bsd/kern/kern_shutdown.c b/bsd/kern/kern_shutdown.c index fcd80032e..45697a58d 100644 --- a/bsd/kern/kern_shutdown.c +++ b/bsd/kern/kern_shutdown.c @@ -45,7 +45,7 @@ #include #include #include -#include +#include #include #if NCPUS > 1 #include @@ -171,13 +171,6 @@ proc_shutdown() if (p && p != self) task_suspend(p->task); /* stop init */ - /* - * Suspend mach_init - */ - p = pfind(2); - if (p && p != self) - task_suspend(p->task); /* stop mach_init */ - printf("Killing all processes "); /* @@ -251,7 +244,8 @@ proc_shutdown() * XXX */ if (p->exit_thread) { /* someone already doing it */ - thread_block(0);/* give him a chance */ + /* give him a chance */ + thread_block(THREAD_CONTINUE_NULL); } else { p->exit_thread = current_thread(); diff --git a/bsd/kern/kern_sig.c b/bsd/kern/kern_sig.c index a849370ca..21c9358d9 100644 --- a/bsd/kern/kern_sig.c +++ b/bsd/kern/kern_sig.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -62,7 +62,6 @@ #define SIGPROP /* include signal properties table */ #include -#include #include #include #include @@ -75,10 +74,14 @@ #include #include #include +#include +#if KTRACE #include +#endif #include #include #include +#include #include @@ -88,19 +91,24 @@ #include /* for coredump */ #include /* for APC support */ #include +#include #include +#include + +extern void doexception(int exc, int code, int sub); void stop __P((struct proc *p)); int cansignal __P((struct proc *, struct pcred *, struct proc *, int)); int killpg1 __P((struct proc *, int, int, int)); void sigexit_locked __P((struct proc *, int)); -void setsigvec __P((struct proc *, int, struct sigaction *)); +int setsigvec __P((struct proc *, int, struct __sigaction *)); void exit1 __P((struct proc *, int, int *)); int signal_lock __P((struct proc *)); int signal_unlock __P((struct proc *)); -void signal_setast __P((thread_act_t *)); -void signal_clearast __P((thread_act_t *)); -void psignal_lock __P((struct proc *, int, int, int)); +void signal_setast __P((thread_act_t)); +void psignal_lock __P((struct proc *, int, int)); +void psignal_uthread __P((thread_act_t, int)); +kern_return_t do_bsdexception(int, int, int); #if SIGNAL_DEBUG void ram_printf __P((int)); @@ -112,12 +120,13 @@ ram_printf(int x) printf("x is %d",x); } - #endif /* SIGNAL_DEBUG */ + int signal_lock(struct proc *p) { int error = 0; +#if DIAGNOSTIC #if SIGNAL_DEBUG #ifdef __ppc__ { @@ -135,9 +144,11 @@ int error = 0; } #endif /* __ppc__ */ #endif /* SIGNAL_DEBUG */ +#endif /* DIAGNOSTIC */ siglock_retry: - error = lockmgr(&p->signal_lock, LK_EXCLUSIVE, 0, (struct proc *)0); + /* TBD: check p last arg */ + error = lockmgr(&p->signal_lock, LK_EXCLUSIVE, 0, (struct proc *)p); if (error == EINTR) goto siglock_retry; return(error); @@ -146,6 +157,7 @@ siglock_retry: int signal_unlock(struct proc *p) { +#if DIAGNOSTIC #if SIGNAL_DEBUG #ifdef __ppc__ { @@ -163,26 +175,17 @@ signal_unlock(struct proc *p) } #endif /* __ppc__ */ #endif /* SIGNAL_DEBUG */ +#endif /* DIAGNOSTIC */ - return(lockmgr(&p->signal_lock, LK_RELEASE, (simple_lock_t)0, (struct proc *)0)); + /* TBD: check p last arg */ + return(lockmgr(&p->signal_lock, LK_RELEASE, (simple_lock_t)0, (struct proc *)p)); } void signal_setast(sig_actthread) -thread_act_t *sig_actthread; -{ - thread_ast_set(sig_actthread, AST_BSD); - if ((thread_act_t *)current_act() == sig_actthread) - ast_on(AST_BSD); -} - -void -signal_clearast(sig_actthread) -thread_act_t *sig_actthread; +thread_act_t sig_actthread; { - thread_ast_clear(sig_actthread, AST_BSD); - if ((thread_act_t *)current_act() == sig_actthread) - ast_off(AST_BSD); + act_set_astbsd(sig_actthread); } /* @@ -195,6 +198,10 @@ cansignal(p, pc, q, signum) struct proc *q; int signum; { + /* you can signal yourself */ + if (p == q) + return(1); + if (pc->pc_ucred->cr_uid == 0) return (1); /* root can always signal */ @@ -243,7 +250,7 @@ cansignal(p, pc, q, signum) struct sigaction_args { int signum; - struct sigaction *nsa; + struct __sigaction *nsa; struct sigaction *osa; }; @@ -255,10 +262,12 @@ sigaction(p, uap, retval) register_t *retval; { struct sigaction vec; + struct __sigaction __vec; + register struct sigaction *sa; register struct sigacts *ps = p->p_sigacts; register int signum; - int bit, error; + int bit, error=0; signum = uap->signum; if (signum <= 0 || signum >= NSIG || @@ -274,57 +283,153 @@ sigaction(p, uap, retval) sa->sa_flags |= SA_ONSTACK; if ((ps->ps_sigintr & bit) == 0) sa->sa_flags |= SA_RESTART; - if (p->p_flag & P_NOCLDSTOP) + if (ps->ps_siginfo & bit) + sa->sa_flags |= SA_SIGINFO; + if (ps->ps_signodefer & bit) + sa->sa_flags |= SA_NODEFER; + if ((signum == SIGCHLD) && (p->p_flag & P_NOCLDSTOP)) sa->sa_flags |= SA_NOCLDSTOP; + if ((signum == SIGCHLD) && (p->p_flag & P_NOCLDWAIT)) + sa->sa_flags |= SA_NOCLDWAIT; if (error = copyout((caddr_t)sa, (caddr_t)uap->osa, sizeof (vec))) return (error); } if (uap->nsa) { - if (error = copyin((caddr_t)uap->nsa, (caddr_t)sa, - sizeof (vec))) + if (error = copyin((caddr_t)uap->nsa, (caddr_t)&__vec, + sizeof (__vec))) return (error); - setsigvec(p, signum, sa); + error = setsigvec(p, signum, &__vec); } - return (0); + return (error); +} + +/* Routines to manipulate bits on all threads */ +int +clear_procsiglist(struct proc *p, int bit) +{ + struct uthread * uth; + thread_act_t thact; + + signal_lock(p); + + if ((p->p_flag & P_INVFORK) && p->p_vforkact) { + thact = p->p_vforkact; + uth = (struct uthread *)get_bsdthread_info(thact); + if (uth) { + uth->uu_siglist &= ~bit; + } + p->p_siglist &= ~bit; + signal_unlock(p); + return(0); + } + + TAILQ_FOREACH(uth, &p->p_uthlist, uu_list) { + uth->uu_siglist &= ~bit; + } + p->p_siglist &= ~bit; + signal_unlock(p); + return(0); } -static int -reset_sigbits(thread_act_t th_act, int bit) +int +unblock_procsigmask(struct proc *p, int bit) { -struct uthread *ut; - ut = get_bsdthread_info(th_act); - if (ut) { - ut->uu_sig &= ~bit; + struct uthread * uth; + thread_act_t thact; + + signal_lock(p); + if ((p->p_flag & P_INVFORK) && p->p_vforkact) { + thact = p->p_vforkact; + uth = (struct uthread *)get_bsdthread_info(thact); + if (uth) { + uth->uu_sigmask &= ~bit; + } + p->p_sigmask &= ~bit; + signal_unlock(p); + return(0); + } + TAILQ_FOREACH(uth, &p->p_uthlist, uu_list) { + uth->uu_sigmask &= ~bit; } + p->p_sigmask &= ~bit; + signal_unlock(p); + return(0); } + int -clear_sigbits (struct proc *p, int bit) +block_procsigmask(struct proc *p, int bit) { -task_t task = p->task; + struct uthread * uth; + thread_act_t thact; - p->p_siglist &= ~(bit); - task_act_iterate_wth_args(task, reset_sigbits, bit); + signal_lock(p); + if ((p->p_flag & P_INVFORK) && p->p_vforkact) { + thact = p->p_vforkact; + uth = (struct uthread *)get_bsdthread_info(thact); + if (uth) { + uth->uu_sigmask |= bit; + } + p->p_sigmask |= bit; + signal_unlock(p); + return(0); + } + TAILQ_FOREACH(uth, &p->p_uthlist, uu_list) { + uth->uu_sigmask |= bit; + } + p->p_sigmask |= bit; + signal_unlock(p); return(0); } +int +set_procsigmask(struct proc *p, int bit) +{ + struct uthread * uth; + thread_act_t thact; + signal_lock(p); + if ((p->p_flag & P_INVFORK) && p->p_vforkact) { + thact = p->p_vforkact; + uth = (struct uthread *)get_bsdthread_info(thact); + if (uth) { + uth->uu_sigmask = bit; + } + p->p_sigmask = bit; + signal_unlock(p); + return(0); + } + TAILQ_FOREACH(uth, &p->p_uthlist, uu_list) { + uth->uu_sigmask = bit; + } + p->p_sigmask = bit; + signal_unlock(p); + return(0); +} -void +int setsigvec(p, signum, sa) register struct proc *p; int signum; - register struct sigaction *sa; + register struct __sigaction *sa; { register struct sigacts *ps = p->p_sigacts; register int bit; + if ((signum == SIGKILL || signum == SIGSTOP) && + sa->sa_handler != SIG_DFL) + return(EINVAL); bit = sigmask(signum); /* * Change setting atomically. */ ps->ps_sigact[signum] = sa->sa_handler; + ps->ps_trampact[signum] = sa->sa_tramp; ps->ps_catchmask[signum] = sa->sa_mask &~ sigcantmask; + if (sa->sa_flags & SA_SIGINFO) + ps->ps_siginfo |= bit; + else + ps->ps_siginfo &= ~bit; if ((sa->sa_flags & SA_RESTART) == 0) ps->ps_sigintr |= bit; else @@ -337,12 +442,33 @@ setsigvec(p, signum, sa) ps->ps_usertramp |= bit; else ps->ps_usertramp &= ~bit; + if (sa->sa_flags & SA_RESETHAND) + ps->ps_sigreset |= bit; + else + ps->ps_sigreset &= ~bit; + if (sa->sa_flags & SA_NODEFER) + ps->ps_signodefer |= bit; + else + ps->ps_signodefer &= ~bit; if (signum == SIGCHLD) { if (sa->sa_flags & SA_NOCLDSTOP) p->p_flag |= P_NOCLDSTOP; else p->p_flag &= ~P_NOCLDSTOP; + if ((sa->sa_flags & SA_NOCLDWAIT) || (sa->sa_handler == SIG_IGN)) + p->p_flag |= P_NOCLDWAIT; + else + p->p_flag &= ~P_NOCLDWAIT; } + +#ifdef __ppc__ + if (signum == SIGFPE) { + if (sa->sa_handler == SIG_DFL || sa->sa_handler == SIG_IGN) + thread_enable_fpe(current_act(), 0); + else + thread_enable_fpe(current_act(), 1); + } +#endif /* __ppc__ */ /* * Set bit in p_sigignore for signals that are set to SIG_IGN, * and for signals set to SIG_DFL where the default is to ignore. @@ -351,16 +477,8 @@ setsigvec(p, signum, sa) */ if (sa->sa_handler == SIG_IGN || (sigprop[signum] & SA_IGNORE && sa->sa_handler == SIG_DFL)) { - p->p_siglist &= ~bit; /* never to be seen again */ - /* - * If this is a thread signal, clean out the - * threads as well. - */ - if (bit & threadmask) { - register task_t task = p->task; - task_act_iterate_wth_args(task, reset_sigbits, bit); - } + clear_procsiglist(p, bit); if (signum != SIGCONT) p->p_sigignore |= bit; /* easier in psignal */ p->p_sigcatch &= ~bit; @@ -371,6 +489,7 @@ setsigvec(p, signum, sa) else p->p_sigcatch |= bit; } + return(0); } /* @@ -392,11 +511,13 @@ siginit(p) * Reset signals for an exec of the specified process. */ void -execsigs(p) +execsigs(p, thr_act) register struct proc *p; + register thread_act_t thr_act; { register struct sigacts *ps = p->p_sigacts; register int nc, mask; + struct uthread *ut; /* * Reset caught signals. Held signals remain held @@ -410,7 +531,12 @@ execsigs(p) if (sigprop[nc] & SA_IGNORE) { if (nc != SIGCONT) p->p_sigignore |= mask; - p->p_siglist &= ~mask; + if (thr_act){ + ut = (struct uthread *)get_bsdthread_info(thr_act); + ut->uu_siglist &= ~mask; + p->p_siglist &= ~mask; + } else + clear_procsiglist(p, mask); } ps->ps_sigact[nc] = SIG_DFL; } @@ -432,7 +558,8 @@ execsigs(p) */ struct sigprocmask_args { int how; - sigset_t mask; + sigset_t *mask; + sigset_t * omask; }; int sigprocmask(p, uap, retval) @@ -441,21 +568,34 @@ sigprocmask(p, uap, retval) register_t *retval; { int error = 0; + sigset_t oldmask, nmask; + sigset_t * omask = uap->omask; + struct uthread *ut; - *retval = p->p_sigmask; + ut = (struct uthread *)get_bsdthread_info(current_act()); + oldmask = ut->uu_sigmask; + + if (uap->mask == (sigset_t *)0) { + /* just want old mask */ + goto out; + } + error = copyin((caddr_t)uap->mask, &nmask, sizeof(sigset_t)); + if (error) + goto out; switch (uap->how) { case SIG_BLOCK: - p->p_sigmask |= uap->mask &~ sigcantmask; + block_procsigmask(p, (nmask & ~sigcantmask)); + signal_setast(current_act()); break; case SIG_UNBLOCK: - p->p_sigmask &= ~(uap->mask); + unblock_procsigmask(p, (nmask & ~sigcantmask)); signal_setast(current_act()); break; case SIG_SETMASK: - p->p_sigmask = uap->mask &~ sigcantmask; + set_procsigmask(p, (nmask & ~sigcantmask)); signal_setast(current_act()); break; @@ -463,19 +603,30 @@ sigprocmask(p, uap, retval) error = EINVAL; break; } +out: + if (!error && omask) + copyout(&oldmask, omask, sizeof(sigset_t)); return (error); } -/* ARGSUSED */ +struct sigpending_args { + struct sigvec *osv; +}; int sigpending(p, uap, retval) struct proc *p; - void *uap; + register struct sigpending_args *uap; register_t *retval; { + struct uthread *ut; + sigset_t pendlist; - *retval = p->p_siglist; - return (0); + ut = (struct uthread *)get_bsdthread_info(current_act()); + pendlist = ut->uu_siglist; + + if (uap->osv) + copyout(&pendlist, uap->osv, sizeof(sigset_t)); + return(0); } #if COMPAT_43 @@ -494,12 +645,15 @@ osigvec(p, uap, retval) register struct osigvec_args *uap; register_t *retval; { + struct sigvec __vec; struct sigvec vec; register struct sigacts *ps = p->p_sigacts; register struct sigvec *sv; register int signum; - int bit, error; + int bit, error=0; + panic("osigvec: notsupp"); +#if 0 signum = uap->signum; if (signum <= 0 || signum >= NSIG || signum == SIGKILL || signum == SIGSTOP) @@ -525,9 +679,10 @@ osigvec(p, uap, retval) sizeof (vec))) return (error); sv->sv_flags ^= SA_RESTART; /* opposite of SV_INTERRUPT */ - setsigvec(p, signum, (struct sigaction *)sv); + error = setsigvec(p, signum, (struct sigaction *)sv); } - return (0); +#endif + return (error); } struct osigblock_args { @@ -539,9 +694,10 @@ osigblock(p, uap, retval) struct osigblock_args *uap; register_t *retval; { + struct uthread * uth = get_bsdthread_info(current_act()); - *retval = p->p_sigmask; - p->p_sigmask |= uap->mask &~ sigcantmask; + *retval = uth->uu_sigmask; + uth->uu_sigmask |= (uap->mask & ~sigcantmask); return (0); } @@ -554,9 +710,10 @@ osigsetmask(p, uap, retval) struct osigsetmask_args *uap; register_t *retval; { + struct uthread * uth = get_bsdthread_info(current_act()); - *retval = p->p_sigmask; - p->p_sigmask = uap->mask &~ sigcantmask; + *retval = uth->uu_sigmask; + uth->uu_sigmask = (uap->mask & ~sigcantmask); return (0); } #endif /* COMPAT_43 */ @@ -570,11 +727,12 @@ osigsetmask(p, uap, retval) int sigcontinue(error) { + struct uthread *ut = get_bsdthread_info(current_act()); unix_syscall_return(EINTR); } struct sigsuspend_args { - int mask; + sigset_t mask; }; /* ARGSUSED */ @@ -585,6 +743,9 @@ sigsuspend(p, uap, retval) register_t *retval; { register struct sigacts *ps = p->p_sigacts; + struct uthread *ut; + + ut = (struct uthread *)get_bsdthread_info(current_act()); /* * When returning from sigpause, we want @@ -593,19 +754,232 @@ sigsuspend(p, uap, retval) * save it here and mark the sigacts structure * to indicate this. */ - ps->ps_oldmask = p->p_sigmask; - ps->ps_flags |= SAS_OLDMASK; - p->p_sigmask = uap->mask &~ sigcantmask; + ut->uu_oldmask = ut->uu_sigmask; + ut->uu_flag |= USAS_OLDMASK; + ut->uu_sigmask = (uap->mask & ~sigcantmask); (void) tsleep0((caddr_t) p, PPAUSE|PCATCH, "pause", 0, sigcontinue); /* always return EINTR rather than ERESTART... */ return (EINTR); } +struct __disable_thsignal_args { + int value; +}; + +int +__disable_threadsignal(p, uap, retval) + struct proc *p; + register struct __disable_thsignal_args *uap; + register_t *retval; +{ + struct uthread *uth; + + uth = (struct uthread *)get_bsdthread_info(current_act()); + + /* No longer valid to have any signal delivered */ + signal_lock(p); + uth->uu_flag |= UNO_SIGMASK; + signal_unlock(p); + + return(0); + +} + +struct pthread_kill_args { + void * thread_port; + int sig; +}; + +int +__pthread_kill(p, uap, retval) + struct proc *p; + register struct pthread_kill_args *uap; + register_t *retval; +{ + thread_act_t target_act; + int error = 0; + int signum = uap->sig; + struct uthread *uth; + + target_act = (thread_act_t)port_name_to_act(uap->thread_port); + + if (target_act == THR_ACT_NULL) + return (ESRCH); + if ((u_int)signum >= NSIG) { + error = EINVAL; + goto out; + } + + uth = (struct uthread *)get_bsdthread_info(target_act); + { void *tht = getshuttle_thread(target_act); +} + if (uth->uu_flag & UNO_SIGMASK) { + error = ESRCH; + goto out; + } + + if (signum) + psignal_uthread(target_act, signum); +out: + act_deallocate(target_act); + return (error); +} + + +struct pthread_sigmask_args { + int how; + const sigset_t *set; + sigset_t * oset; +}; +int +pthread_sigmask(p, uap, retval) + register struct proc *p; + register struct pthread_sigmask_args *uap; + register_t *retval; +{ + int how = uap->how; + const sigset_t *set = uap->set; + sigset_t * oset = uap->oset; + const sigset_t nset; + int error = 0; + struct uthread *ut; + sigset_t oldset; + + ut = (struct uthread *)get_bsdthread_info(current_act()); + oldset = ut->uu_sigmask; + + if (set == (sigset_t *) 0) { + /* need only old mask */ + goto out; + } + + error = copyin((caddr_t)set, (caddr_t)&nset, sizeof(sigset_t)); + if (error) + goto out; + + switch (uap->how) { + case SIG_BLOCK: + ut->uu_sigmask |= (nset & ~sigcantmask); + break; + + case SIG_UNBLOCK: + ut->uu_sigmask &= ~(nset); + signal_setast(current_act()); + break; + + case SIG_SETMASK: + ut->uu_sigmask = (nset & ~sigcantmask); + signal_setast(current_act()); + break; + + default: + error = EINVAL; + + } +out: + if (!error && oset) + copyout((caddr_t)&oldset, (caddr_t)oset, sizeof(sigset_t)); + + return(error); +} + + +struct sigwait_args { + const sigset_t *set; + int *sig; +}; + +int +sigwait(p, uap, retval) + register struct proc *p; + register struct sigwait_args *uap; + register_t *retval; +{ + register struct sigacts *ps = p->p_sigacts; + struct uthread *ut; + struct uthread *uth; + thread_act_t thact; + int error = 0; + sigset_t mask; + sigset_t siglist; + sigset_t sigw=0; + int signum; + + ut = (struct uthread *)get_bsdthread_info(current_act()); + + if (uap->set == (const sigset_t *)0) + return(EINVAL); + + error = copyin((caddr_t)uap->set, (caddr_t)&mask, sizeof(sigset_t)); + if (error) + return(error); + + siglist = (mask & ~sigcantmask); + + if (siglist == 0) + return(EINVAL); + + signal_lock(p); + if ((p->p_flag & P_INVFORK) && p->p_vforkact) { + signal_unlock(p); + return(EINVAL); + } else { + TAILQ_FOREACH(uth, &p->p_uthlist, uu_list) { + if (sigw = uth->uu_siglist & siglist) { + break; + } + } + } + signal_unlock(p); + if (sigw) { + /* The signal was pending on a thread */ + goto sigwait1; + } + /* + * When returning from sigwait, we want + * the old mask to be restored after the + * signal handler has finished. Thus, we + * save it here and mark the sigacts structure + * to indicate this. + */ + ut->uu_oldmask = ut->uu_sigmask; + ut->uu_flag |= USAS_OLDMASK; + if (siglist == (sigset_t)0) + return(EINVAL); + /* SIGKILL and SIGSTOP are not maskable as well */ + ut->uu_sigmask = ~(siglist|sigcantmask); + ut->uu_sigwait = siglist; + /* No Continuations for now */ + error = tsleep((caddr_t)&ut->uu_sigwait, PPAUSE|PCATCH, "pause", 0); + + if ((error == EINTR) || (error == ERESTART)) + error = 0; + + sigw = (ut->uu_sigwait & siglist); + ut->uu_sigmask = ut->uu_oldmask; + ut->uu_oldmask = 0; + ut->uu_flag &= ~USAS_OLDMASK; +sigwait1: + ut->uu_sigwait = 0; + if (!error) { + signum = ffs((unsigned int)sigw); + if (!signum) + panic("sigwait with no signal wakeup"); + ut->uu_siglist &= ~(sigmask(signum)); + if (uap->sig) + error = copyout(&signum, uap->sig, sizeof(int)); + } + + return(error); + +} + #if COMPAT_43 struct osigstack_args { struct sigstack *nss; struct sigstack *oss; }; + /* ARGSUSED */ int osigstack(p, uap, retval) @@ -660,6 +1034,10 @@ sigaltstack(p, uap, retval) if (error = copyin((caddr_t)uap->nss, (caddr_t)&ss, sizeof (ss))) return (error); + if ((ss.ss_flags & ~SA_DISABLE) != 0) { + return(EINVAL); + } + if (ss.ss_flags & SA_DISABLE) { if (psp->ps_sigstk.ss_flags & SA_ONSTACK) return (EINVAL); @@ -812,12 +1190,33 @@ pgsignal(pgrp, signum, checkctty) psignal(p, signum); } +/* + * Send signal to a backgrounded process blocked due to tty access + * In FreeBSD, the backgrounded process wakes up every second and + * discovers whether it is foregounded or not. In our case, we block + * the thread in tsleep as we want to avoid storm of processes as well + * as the suspend is only at AST level + */ +void +tty_pgsignal(pgrp, signum) + struct pgrp *pgrp; + int signum; +{ + register struct proc *p; + + if (pgrp) + for (p = pgrp->pg_members.lh_first; p != 0; + p = p->p_pglist.le_next) + if ((p->p_flag & P_TTYSLEEP) && (p->p_flag & P_CONTROLT)) + psignal(p, signum); +} + /* * Send a signal caused by a trap to a specific thread. */ void threadsignal(sig_actthread, signum, code) - register thread_act_t *sig_actthread; + register thread_act_t sig_actthread; register int signum; u_long code; { @@ -842,55 +1241,22 @@ threadsignal(sig_actthread, signum, code) if (!(p->p_flag & P_TRACED) && (p->p_sigignore & mask)) return; - uth->uu_sig |= mask; + uth->uu_siglist |= mask; + p->p_siglist |= mask; /* just for lame ones looking here */ uth->uu_code = code; /* mark on process as well */ - p->p_siglist |= mask; signal_setast(sig_actthread); } -void -psignal_pend(p) - register struct proc *p; -{ - boolean_t funnel_state; - register int sigbits, mask, signum; - - thread_funnel_set(kernel_flock, TRUE); - - if (p->p_sigpending == 0) - return; - - - signal_lock(p); - - for (;;) { - sigbits = p->p_sigpending; - if (sigbits == 0) - goto out; - signum = ffs((long)sigbits); - mask = sigmask(signum); - p->p_sigpending &= ~mask; - - psignal_lock(p, signum, 0, 0); - - } -out: - p->p_flag &= ~P_SIGTHR; - signal_unlock(p); - thread_funnel_set(kernel_flock, FALSE); -} - void psignal(p, signum) register struct proc *p; register int signum; { - psignal_lock(p, signum, 1, 1); + psignal_lock(p, signum, 1); } - void psignal_vfork(p, new_task, thr_act, signum) register struct proc *p; @@ -904,6 +1270,7 @@ psignal_vfork(p, new_task, thr_act, signum) register sig_t action; int mask; kern_return_t kret; + struct uthread *uth; if ((u_int)signum >= NSIG || signum == 0) panic("psignal signal number"); @@ -920,6 +1287,7 @@ psignal_vfork(p, new_task, thr_act, signum) return; + uth = get_bsdthread_info(thr_act); signal_lock(p); /* @@ -931,8 +1299,10 @@ psignal_vfork(p, new_task, thr_act, signum) (p->p_flag & P_TRACED) == 0) p->p_nice = NZERO; - if (prop & SA_CONT) + if (prop & SA_CONT) { p->p_siglist &= ~stopsigmask; + uth->uu_siglist &= ~stopsigmask; + } if (prop & SA_STOP) { /* @@ -944,12 +1314,14 @@ psignal_vfork(p, new_task, thr_act, signum) if (prop & SA_TTYSTOP && p->p_pgrp->pg_jobc == 0 && action == SIG_DFL) goto psigout; + uth->uu_siglist &= ~contsigmask; p->p_siglist &= ~contsigmask; } - p->p_siglist |= mask; + uth->uu_siglist |= mask; + p->p_siglist |= mask; /* just for lame ones looking here */ - /* Deliver signal to the activation passed in */ - thread_ast_set(thr_act, AST_BSD); + /* Deliver signal to the activation passed in */ + act_set_astbsd(thr_act); /* * SIGKILL priority twiddling moved here from above because @@ -959,12 +1331,6 @@ psignal_vfork(p, new_task, thr_act, signum) */ if ((signum == SIGKILL) && (p->p_nice > NZERO)) { p->p_nice = NZERO; -#if XXX - /* - * we need to make changes here to get nice to work - * reset priority to BASEPRI_USER - */ -#endif } /* @@ -984,8 +1350,10 @@ run: * while we were stopped), check for a signal from the debugger. */ if (p->p_stat == SSTOP) { - if ((p->p_flag & P_TRACED) != 0 && p->p_xstat != 0) - p->p_siglist |= sigmask(p->p_xstat); + if ((p->p_flag & P_TRACED) != 0 && p->p_xstat != 0) { + uth->uu_siglist |= sigmask(p->p_xstat); + p->p_siglist |= mask; /* just for lame ones looking here */ + } } /* @@ -997,6 +1365,40 @@ psigout: signal_unlock(p); } +thread_act_t +get_signalthread(struct proc *p, int signum) +{ + struct uthread *uth; + thread_act_t thr_act; + sigset_t mask = sigmask(signum); + thread_act_t sig_thread_act; + struct task * sig_task = p->task; + thread_t sig_thread; + kern_return_t kret; + + if ((p->p_flag & P_INVFORK) && p->p_vforkact) { + sig_thread_act = p->p_vforkact; + kret = check_actforsig(sig_task, sig_thread_act, &sig_thread, 1); + if (kret == KERN_SUCCESS) + return(sig_thread_act); + else + return(THR_ACT_NULL); + } + + TAILQ_FOREACH(uth, &p->p_uthlist, uu_list) { + if(((uth->uu_flag & UNO_SIGMASK)== 0) && + (((uth->uu_sigmask & mask) == 0) || (uth->uu_sigwait & mask))) { + if (check_actforsig(p->task, uth->uu_act, NULL, 1) == KERN_SUCCESS) + return(uth->uu_act); + } + } + if (get_signalact(p->task, &thr_act, NULL, 1) == KERN_SUCCESS) { + return(thr_act); + } + + return(THR_ACT_NULL); +} + /* * Send the signal to the process. If the signal has an action, the action * is usually performed by the target process rather than the caller; we add @@ -1011,11 +1413,10 @@ psigout: * Other ignored signals are discarded immediately. */ void -psignal_lock(p, signum, withlock, pend) +psignal_lock(p, signum, withlock) register struct proc *p; register int signum; register int withlock; - register int pend; { register int s, prop; register sig_t action; @@ -1023,8 +1424,9 @@ psignal_lock(p, signum, withlock, pend) thread_t sig_thread; register task_t sig_task; register thread_t cur_thread; - thread_act_t *cur_act; + thread_act_t cur_act; int mask; + struct uthread *uth; kern_return_t kret; int sw_funnel = 0; @@ -1065,26 +1467,40 @@ psignal_lock(p, signum, withlock, pend) return; } - /* - * if the traced process is blocked waiting for - * gdb then do not block the caller just pend - * the signal. Setup a callout to process the - * pended signal if not alreadu set + if (withlock) + signal_lock(p); + + /* + * Deliver the signal to the first thread in the task. This + * allows single threaded applications which use signals to + * be able to be linked with multithreaded libraries. We have + * an implicit reference to the current_thread, but need + * an explicit one otherwise. The thread reference keeps + * the corresponding task data structures around too. This + * reference is released by thread_deallocate. */ - if (pend && (p->p_flag & P_TRACED) && p->sigwait) { - p->p_sigpending |= mask; - if (!(p->p_flag & P_SIGTHR)) { - p->p_flag |= P_SIGTHR; - thread_call_func((thread_call_func_t)psignal_pend, p, - FALSE); - } - if (sw_funnel) - thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); - return; + + if (((p->p_flag & P_TRACED) == 0) && (p->p_sigignore & mask)) + goto psigout; + + cur_thread = current_thread(); /* this is a shuttle */ + cur_act = current_act(); + + /* If successful return with ast set */ + sig_thread_act = get_signalthread(p, signum); + + if (sig_thread_act == THR_ACT_NULL) { + /* XXXX FIXME + /* if it is sigkill, may be we should + * inject a thread to terminate + */ +#if SIGNAL_DEBUG + ram_printf(1); +#endif /* SIGNAL_DEBUG */ + goto psigout; } - if (withlock) - signal_lock(p); + uth = get_bsdthread_info(sig_thread_act); /* * If proc is traced, always give parent a chance. @@ -1101,7 +1517,9 @@ psignal_lock(p, signum, withlock, pend) */ if (p->p_sigignore & mask) goto psigout; - if (p->p_sigmask & mask) + if (uth->uu_sigwait & mask) + action = SIG_WAIT; + if (uth->uu_sigmask & mask) action = SIG_HOLD; else if (p->p_sigcatch & mask) action = SIG_CATCH; @@ -1113,8 +1531,10 @@ psignal_lock(p, signum, withlock, pend) (p->p_flag & P_TRACED) == 0) p->p_nice = NZERO; - if (prop & SA_CONT) + if (prop & SA_CONT) { + uth->uu_siglist &= ~stopsigmask; p->p_siglist &= ~stopsigmask; + } if (prop & SA_STOP) { /* @@ -1126,17 +1546,225 @@ psignal_lock(p, signum, withlock, pend) if (prop & SA_TTYSTOP && p->p_pgrp->pg_jobc == 0 && action == SIG_DFL) goto psigout; + uth->uu_siglist &= ~contsigmask; p->p_siglist &= ~contsigmask; } - p->p_siglist |= mask; + uth->uu_siglist |= mask; + p->p_siglist |= mask; /* just for lame ones looking here */ + /* * Defer further processing for signals which are held, * except that stopped processes must be continued by SIGCONT. */ - if (action == SIG_HOLD && ((prop & SA_CONT) == 0 || p->p_stat != SSTOP)) + if (action == SIG_HOLD && ((prop & SA_CONT) == 0 || p->p_stat != SSTOP)) { goto psigout; - + } + /* + * SIGKILL priority twiddling moved here from above because + * it needs sig_thread. Could merge it into large switch + * below if we didn't care about priority for tracing + * as SIGKILL's action is always SIG_DFL. + */ + if ((signum == SIGKILL) && (p->p_nice > NZERO)) { + p->p_nice = NZERO; + } + + /* + * Process is traced - wake it up (if not already + * stopped) so that it can discover the signal in + * issig() and stop for the parent. + */ + if (p->p_flag & P_TRACED) { + if (p->p_stat != SSTOP) + goto run; + else + goto psigout; + } + + if (action == SIG_WAIT) { + uth->uu_sigwait = mask; + uth->uu_siglist &= ~mask; + p->p_siglist &= ~mask; + wakeup(&uth->uu_sigwait); + /* if it is SIGCONT resume whole process */ + if (prop & SA_CONT) + (void) task_resume(sig_task); + goto psigout; + } + + if (action != SIG_DFL) { + /* + * User wants to catch the signal. + * Wake up the thread, but don't un-suspend it + * (except for SIGCONT). + */ + if (prop & SA_CONT) + (void) task_resume(sig_task); + goto run; + } else { + /* Default action - varies */ + if (mask & stopsigmask) { + /* + * These are the signals which by default + * stop a process. + * + * Don't clog system with children of init + * stopped from the keyboard. + */ + if (!(prop & SA_STOP) && p->p_pptr == initproc) { + psignal_lock(p, SIGKILL, 0); + uth->uu_siglist &= ~mask; + p->p_siglist &= ~mask; + goto psigout; + } + + /* + * Stop the task + * if task hasn't already been stopped by + * a signal. + */ + uth->uu_siglist &= ~mask; + p->p_siglist &= ~mask; + if (p->p_stat != SSTOP) { + p->p_xstat = signum; + stop(p); + if ((p->p_pptr->p_flag & P_NOCLDSTOP) == 0) { + struct proc *pp = p->p_pptr; + + pp->si_pid = p->p_pid; + pp->si_status = p->p_xstat; + pp->si_code = CLD_STOPPED; + pp->si_uid = p->p_cred->p_ruid; + psignal(pp, SIGCHLD); + } + } + goto psigout; + } + + switch (signum) { + /* + * Signals ignored by default have been dealt + * with already, since their bits are on in + * p_sigignore. + */ + + case SIGKILL: + /* + * Kill signal always sets process running and + * unsuspends it. + */ + /* + * Process will be running after 'run' + */ + p->p_stat = SRUN; + + thread_abort(sig_thread_act); + + goto psigout; + + case SIGCONT: + /* + * Let the process run. If it's sleeping on an + * event, it remains so. + */ + if (p->p_flag & P_TTYSLEEP) { + p->p_flag &= ~P_TTYSLEEP; + wakeup(&p->p_siglist); + } else { + (void) task_resume(sig_task); + } + uth->uu_siglist &= ~mask; + p->p_siglist &= ~mask; + p->p_stat = SRUN; + + goto psigout; + + default: + /* + * All other signals wake up the process, but don't + * resume it. + */ + goto run; + } + } + /*NOTREACHED*/ +run: + /* + * If we're being traced (possibly because someone attached us + * while we were stopped), check for a signal from the debugger. + */ + if (p->p_stat == SSTOP) { + if ((p->p_flag & P_TRACED) != 0 && p->p_xstat != 0) + uth->uu_siglist |= sigmask(p->p_xstat); + } else { + /* + * setrunnable(p) in BSD and + * Wake up the thread if it is interruptible. + */ + p->p_stat = SRUN; + thread_abort_safely(sig_thread_act); + } +psigout: + if (withlock) + signal_unlock(p); + if (sw_funnel) + thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); +} + + +/* psignal_lock(p, signum, withlock ) */ +void +psignal_uthread(thr_act, signum) + thread_act_t thr_act; + int signum; +{ + struct proc *p; + register int s, prop; + register sig_t action; + thread_act_t sig_thread_act; + thread_t sig_thread; + register task_t sig_task; + register thread_t cur_thread; + thread_act_t cur_act; + int mask; + struct uthread *uth; + kern_return_t kret; + int error = 0; + + p = (struct proc *)get_bsdtask_info(get_threadtask(thr_act)); + if ((u_int)signum >= NSIG || signum == 0) + panic("Invalid signal number in psignal_uthread"); + mask = sigmask(signum); + prop = sigprop[signum]; + +#if SIGNAL_DEBUG + if(rdebug_proc && (p == rdebug_proc)) { + ram_printf(3); + } +#endif /* SIGNAL_DEBUG */ + + /* + * We will need the task pointer later. Grab it now to + * check for a zombie process. Also don't send signals + * to kernel internal tasks. + */ + if (((sig_task = p->task) == TASK_NULL) || is_kerneltask(sig_task)) { + return; + } + + sig_thread_act = thr_act; + /* + * do not send signals to the process that has the thread + * doing a reboot(). Not doing so will mark that thread aborted + * and can cause IO failures wich will cause data loss. + */ + if (ISSET(p->p_flag, P_REBOOT)) { + return; + } + + signal_lock(p); + /* * Deliver the signal to the first thread in the task. This * allows single threaded applications which use signals to @@ -1147,47 +1775,79 @@ psignal_lock(p, signum, withlock, pend) * reference is released by thread_deallocate. */ + if (((p->p_flag & P_TRACED) == 0) && (p->p_sigignore & mask)) + goto puthout; + cur_thread = current_thread(); /* this is a shuttle */ cur_act = current_act(); - if ((p->p_flag & P_INVFORK) && p->p_vforkact) { - sig_thread_act = p->p_vforkact; + kret = check_actforsig(sig_task, sig_thread_act, &sig_thread, 1); - kret = check_actforsig(sig_task, sig_thread_act, &sig_thread, 1); - if (kret == KERN_SUCCESS) { - goto psig_foundthread; - } - } + if (kret != KERN_SUCCESS) { + error = EINVAL; + goto puthout; + } - /* If successful return with ast set */ - kret = (kern_return_t)get_signalact(sig_task, - &sig_thread_act, &sig_thread, 1); - if ((kret != KERN_SUCCESS) || (sig_thread_act == THREAD_NULL)) { - /* XXXX FIXME - /* if it is sigkill, may be we should - * inject a thread to terminate - */ -#if DIAGNOSTIC - printf("WARNING: no activation in psignal\n"); -#endif -#if SIGNAL_DEBUG - ram_printf(1); -#endif /* SIGNAL_DEBUG */ - goto psigout; - } + uth = get_bsdthread_info(sig_thread_act); -psig_foundthread: - if (sig_thread == THREAD_NULL) { -#if DIAGNOSTIC - printf("WARNING: valid act; but no shutte in psignal\n"); -#endif -#if 0 - /* FIXME : NO VALID SHUTTLE */ - goto psigout; -#endif + /* + * If proc is traced, always give parent a chance. + */ + if (p->p_flag & P_TRACED) + action = SIG_DFL; + else { + /* + * If the signal is being ignored, + * then we forget about it immediately. + * (Note: we don't set SIGCONT in p_sigignore, + * and if it is set to SIG_IGN, + * action will be SIG_DFL here.) + */ + if (p->p_sigignore & mask) + goto puthout; + if (uth->uu_sigwait & mask) + action = SIG_WAIT; + if (uth->uu_sigmask & mask) + action = SIG_HOLD; + else if (p->p_sigcatch & mask) + action = SIG_CATCH; + else + action = SIG_DFL; } + if (p->p_nice > NZERO && action == SIG_DFL && (prop & SA_KILL) && + (p->p_flag & P_TRACED) == 0) + p->p_nice = NZERO; + + if (prop & SA_CONT) { + uth->uu_siglist &= ~stopsigmask; + p->p_siglist &= ~stopsigmask; + } + + if (prop & SA_STOP) { + /* + * If sending a tty stop signal to a member of an orphaned + * process group, discard the signal here if the action + * is default; don't stop the process below if sleeping, + * and don't clear any pending SIGCONT. + */ + if (prop & SA_TTYSTOP && p->p_pgrp->pg_jobc == 0 && + action == SIG_DFL) + goto puthout; + uth->uu_siglist &= ~contsigmask; + p->p_siglist &= ~contsigmask; + } + uth->uu_siglist |= mask; + p->p_siglist |= mask; /* just for lame ones looking here */ + + /* + * Defer further processing for signals which are held, + * except that stopped processes must be continued by SIGCONT. + */ + if (action == SIG_HOLD && ((prop & SA_CONT) == 0 || p->p_stat != SSTOP)) + goto puthout; + /* * SIGKILL priority twiddling moved here from above because * it needs sig_thread. Could merge it into large switch @@ -1196,12 +1856,6 @@ psig_foundthread: */ if ((signum == SIGKILL) && (p->p_nice > NZERO)) { p->p_nice = NZERO; -#if XXX - /* - * we need to make changes here to get nice to work - * reset priority to BASEPRI_USER - */ -#endif } /* @@ -1211,9 +1865,20 @@ psig_foundthread: */ if (p->p_flag & P_TRACED) { if (p->p_stat != SSTOP) - goto run; + goto psurun; else - goto psigout; + goto puthout; + } + + if (action == SIG_WAIT) { + uth->uu_sigwait = mask; + uth->uu_siglist &= ~mask; + p->p_siglist &= ~mask; + wakeup(&uth->uu_sigwait); + /* if it is SIGCONT resume whole process */ + if (prop & SA_CONT) + (void) task_resume(sig_task); + goto puthout; } if (action != SIG_DFL) { @@ -1224,7 +1889,7 @@ psig_foundthread: */ if (prop & SA_CONT) (void) task_resume(sig_task); - goto run; + goto psurun; } else { /* Default action - varies */ if (mask & stopsigmask) { @@ -1236,44 +1901,33 @@ psig_foundthread: * stopped from the keyboard. */ if (!(prop & SA_STOP) && p->p_pptr == initproc) { - psignal_lock(p, SIGKILL, 0, 1); + psignal_lock(p, SIGKILL, 0); + uth->uu_siglist &= ~mask; p->p_siglist &= ~mask; - goto psigout; + goto puthout; } /* - * Stop the task. + * Stop the task + * if task hasn't already been stopped by + * a signal. */ - if (!is_thread_running(sig_thread)) { - /* Thread is not running - * If task hasn't already been stopped by - * a signal, stop it. - */ - p->p_siglist &= ~mask; - if (get_task_userstop(sig_task) == 0) { - /* - * p_cursig must not be set, because - * it will be psig()'d if it is not - * zero, and the signal is being - * handled here. But save the signal - * in p_stopsig so WUNTRACED - * option to wait can find it. - */ - p->p_xstat = signum; - if ((p->p_pptr->p_flag & P_NOCLDSTOP) == 0) - psignal(p->p_pptr, SIGCHLD); - stop(p); + uth->uu_siglist &= ~mask; + p->p_siglist &= ~mask; + if (p->p_stat != SSTOP) { + p->p_xstat = signum; + if ((p->p_pptr->p_flag & P_NOCLDSTOP) == 0) { + struct proc *pp = p->p_pptr; + + pp->si_pid = p->p_pid; + pp->si_status = p->p_xstat; + pp->si_code = CLD_STOPPED; + pp->si_uid = p->p_cred->p_ruid; + psignal(pp, SIGCHLD); } -#if 0 - /* unconditional check is bad */ - signal_clearast(sig_thread_act); -#endif - goto psigout; - } else { - if (p->p_stat != SZOMB) - signal_setast(cur_act); - goto psigout; + stop(p); } + goto puthout; } switch (signum) { @@ -1295,7 +1949,7 @@ psig_foundthread: thread_abort(sig_thread_act); - goto psigout; + goto puthout; case SIGCONT: /* @@ -1308,52 +1962,44 @@ psig_foundthread: } else { (void) task_resume(sig_task); } + uth->uu_siglist &= ~mask; p->p_siglist &= ~mask; p->p_stat = SRUN; -#if 0 - /* do not clear AST as tcsh is sendig SIGTERM followed by - * SIGCONT and the ast was getting cleared unconditinally - * This is not right. - */ - signal_clearast(sig_thread_act); -#endif - goto psigout; + goto puthout; default: /* * All other signals wake up the process, but don't * resume it. */ - goto run; + goto psurun; } } /*NOTREACHED*/ -run: +psurun: /* * If we're being traced (possibly because someone attached us * while we were stopped), check for a signal from the debugger. */ if (p->p_stat == SSTOP) { - if ((p->p_flag & P_TRACED) != 0 && p->p_xstat != 0) + if ((p->p_flag & P_TRACED) != 0 && p->p_xstat != 0) { + uth->uu_siglist |= sigmask(p->p_xstat); p->p_siglist |= sigmask(p->p_xstat); + } + } else { + /* + * setrunnable(p) in BSD and + * Wake up the thread if it is interruptible. + */ + p->p_stat = SRUN; + thread_abort_safely(sig_thread_act); } - /* - * setrunnable(p) in BSD - */ - p->p_stat = SRUN; - - /* - * Wake up the thread if it is interruptible. - */ - thread_abort_safely(sig_thread_act); -psigout: - if (withlock) +puthout: signal_unlock(p); - if (sw_funnel) - thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); } + __inline__ void sig_lock_to_exit( struct proc *p) @@ -1385,7 +2031,7 @@ sig_try_locked( (THREAD_INTERRUPTIBLE)); } signal_unlock(p); - thread_block(0); + thread_block(THREAD_CONTINUE_NULL); signal_lock(p); if (thread_should_abort(self)) { /* @@ -1420,13 +2066,18 @@ issignal(p) int s; struct uthread * ut; kern_return_t kret; + struct proc *pp; cur_thread = current_thread(); cur_act = current_act(); +#if SIGNAL_DEBUG + if(rdebug_proc && (p == rdebug_proc)) { + ram_printf(3); + } +#endif /* SIGNAL_DEBUG */ signal_lock(p); - /* * Try to grab the signal lock. */ @@ -1437,7 +2088,7 @@ issignal(p) ut = get_bsdthread_info(cur_act); for(;;) { - sigbits = (ut->uu_sig |p->p_siglist) & ~p->p_sigmask; + sigbits = ut->uu_siglist & ~ut->uu_sigmask; if (p->p_flag & P_PPWAIT) sigbits &= ~stopsigmask; @@ -1449,20 +2100,16 @@ issignal(p) mask = sigmask(signum); prop = sigprop[signum]; - if (mask & threadmask) { - /* we can take this signal */ - ut->uu_sig &= ~mask; - } - /* * We should see pending but ignored signals * only if P_TRACED was on when they were posted. */ if (mask & p->p_sigignore && (p->p_flag & P_TRACED) == 0) { + ut->uu_siglist &= ~mask; /* take the signal! */ p->p_siglist &= ~mask; /* take the signal! */ continue; } - if (p->p_flag & P_TRACED && (p->p_flag & P_PPWAIT) == 0) { + if (p->p_flag & P_TRACED && (p->p_flag & P_PPWAIT) == 0) { register int hold; register task_t task; /* @@ -1471,25 +2118,46 @@ issignal(p) */ /* ptrace debugging */ p->p_xstat = signum; - psignal(p->p_pptr, SIGCHLD); - /* - * XXX Have to really stop for debuggers; - * XXX stop() doesn't do the right thing. - * XXX Inline the task_suspend because we - * XXX have to diddle Unix state in the - * XXX middle of it. - */ - task = p->task; - task_hold(task); - p->sigwait = TRUE; - p->sigwait_thread = cur_act; - p->p_stat = SSTOP; - p->p_flag &= ~P_WAITED; - p->p_siglist &= ~mask; /* clear the old signal */ - - wakeup((caddr_t)p->p_pptr); - assert_wait((caddr_t)&p->sigwait, (THREAD_INTERRUPTIBLE)); - thread_block(0); + pp = p->p_pptr; + if (p->p_flag & P_SIGEXC) { + p->sigwait = TRUE; + p->sigwait_thread = cur_act; + p->p_stat = SSTOP; + p->p_flag &= ~P_WAITED; + ut->uu_siglist &= ~mask; /* clear the old signal */ + p->p_siglist &= ~mask; /* clear the old signal */ + signal_unlock(p); + do_bsdexception(EXC_SOFTWARE, EXC_SOFT_SIGNAL, signum); + signal_lock(p); + } else { + pp->si_pid = p->p_pid; + pp->si_status = p->p_xstat; + pp->si_code = CLD_TRAPPED; + pp->si_uid = p->p_cred->p_ruid; + psignal(pp, SIGCHLD); + /* + * XXX Have to really stop for debuggers; + * XXX stop() doesn't do the right thing. + * XXX Inline the task_suspend because we + * XXX have to diddle Unix state in the + * XXX middle of it. + */ + task = p->task; + task_hold(task); + p->sigwait = TRUE; + p->sigwait_thread = cur_act; + p->p_stat = SSTOP; + p->p_flag &= ~P_WAITED; + ut->uu_siglist &= ~mask; /* clear the old signal */ + p->p_siglist &= ~mask; /* clear the old signal */ + + wakeup((caddr_t)p->p_pptr); + signal_unlock(p); + assert_wait((caddr_t)&p->sigwait, (THREAD_INTERRUPTIBLE)); + thread_block(THREAD_CONTINUE_NULL); + signal_lock(p); + } + p->sigwait = FALSE; p->sigwait_thread = NULL; wakeup((caddr_t)&p->sigwait_thread); @@ -1500,7 +2168,7 @@ issignal(p) * pgsignal would get the SIGKILL to traced program * That's what we are trying to see (I hope) */ - if (p->p_siglist & sigmask(SIGKILL)) { + if (ut->uu_siglist & sigmask(SIGKILL)) { /* * Wait event may still be outstanding; * clear it, since sig_lock_to_exit will @@ -1540,11 +2208,9 @@ issignal(p) * signal is being masked, look for other signals. */ mask = sigmask(signum); - if (mask & threadmask) - ut->uu_sig |= mask; - else - p->p_siglist |= mask; - if (p->p_sigmask & mask) + ut->uu_siglist |= mask; + p->p_siglist |= mask; /* just for lame ones looking here */ + if (ut->uu_sigmask & mask) continue; } @@ -1584,17 +2250,17 @@ issignal(p) (p->p_pgrp->pg_jobc == 0 && prop & SA_TTYSTOP)) break; /* == ignore */ - p->p_xstat = signum; - stop(p); - if ((p->p_pptr->p_flag & P_NOCLDSTOP) == 0) - psignal(p->p_pptr, SIGCHLD); - thread_block(0); - /* - * We may have to quit - */ - if (thread_should_abort(current_thread())) { - signal_unlock(p); - return(0); + if (p->p_stat != SSTOP) { + p->p_xstat = signum; + stop(p); + if ((p->p_pptr->p_flag & P_NOCLDSTOP) == 0) { + pp = p->p_pptr; + pp->si_pid = p->p_pid; + pp->si_status = p->p_xstat; + pp->si_code = CLD_STOPPED; + pp->si_uid = p->p_cred->p_ruid; + psignal(pp, SIGCHLD); + } } break; } else if (prop & SA_IGNORE) { @@ -1604,8 +2270,8 @@ issignal(p) */ break; /* == ignore */ } else { - p->p_siglist &= ~mask; /* take the signal! */ - p->p_sigpending &= ~mask; /* take the pending signal */ + ut->uu_siglist &= ~mask; /* take the signal! */ + p->p_siglist &= ~mask; /* take the signal! */ signal_unlock(p); return (signum); } @@ -1627,13 +2293,13 @@ issignal(p) * This signal has an action, let * postsig() process it. */ + ut->uu_siglist &= ~mask; /* take the signal! */ p->p_siglist &= ~mask; /* take the signal! */ - p->p_sigpending &= ~mask; /* take the pending signal */ signal_unlock(p); return (signum); } + ut->uu_siglist &= ~mask; /* take the signal! */ p->p_siglist &= ~mask; /* take the signal! */ - p->p_sigpending &= ~mask; /* take the pending signal */ } /* NOTREACHED */ } @@ -1651,18 +2317,19 @@ CURSIG(p) struct uthread * ut; int retnum = 0; - if (p->p_siglist == 0) - return (0); - - if (((p->p_siglist & ~p->p_sigmask) == 0) && ((p->p_flag & P_TRACED) == 0)) - return (0); cur_thread = current_thread(); cur_act = current_act(); ut = get_bsdthread_info(cur_act); - sigbits = (ut->uu_sig | p->p_siglist) & ~p->p_sigmask; + if (ut->uu_siglist == 0) + return (0); + + if (((ut->uu_siglist & ~ut->uu_sigmask) == 0) && ((p->p_flag & P_TRACED) == 0)) + return (0); + + sigbits = ut->uu_siglist & ~ut->uu_sigmask; for(;;) { if (p->p_flag & P_PPWAIT) @@ -1688,7 +2355,7 @@ CURSIG(p) * signal is being masked, look for other signals. */ mask = sigmask(signum); - if (p->p_sigmask & mask) + if (ut->uu_sigmask & mask) continue; return(signum); } @@ -1793,6 +2460,7 @@ postsig(signum) register sig_t action; u_long code; int mask, returnmask; + struct uthread * ut; #if DIAGNOSTIC if (signum == 0) @@ -1809,18 +2477,20 @@ postsig(signum) * Try to grab the signal lock. */ if (sig_try_locked(p) <= 0) { - signal_unlock(p); + signal_unlock(p); return; } + ut = (struct uthread *)get_bsdthread_info(current_act()); mask = sigmask(signum); + ut->uu_siglist &= ~mask; p->p_siglist &= ~mask; action = ps->ps_sigact[signum]; #if KTRACE if (KTRPOINT(p, KTR_PSIG)) ktrpsig(p->p_tracep, - signum, action, ps->ps_flags & SAS_OLDMASK ? - ps->ps_oldmask : p->p_sigmask, 0); + signum, action, ut->uu_flag & USAS_OLDMASK ? + &ut->uu_oldmask : &ut->uu_sigmask, 0, -1); #endif if (action == SIG_DFL) { /* @@ -1836,7 +2506,7 @@ postsig(signum) * If we get here, the signal must be caught. */ #if DIAGNOSTIC - if (action == SIG_IGN || (p->p_sigmask & mask)) + if (action == SIG_IGN || (ut->uu_sigmask & mask)) log(LOG_WARNING, "postsig: processing masked or ignored signal\n"); #endif @@ -1849,12 +2519,29 @@ postsig(signum) * mask from before the sigpause is what we want * restored after the signal processing is completed. */ - if (ps->ps_flags & SAS_OLDMASK) { - returnmask = ps->ps_oldmask; - ps->ps_flags &= ~SAS_OLDMASK; + if (ut->uu_flag & USAS_OLDMASK) { + returnmask = ut->uu_oldmask; + ut->uu_flag &= ~USAS_OLDMASK; + ut->uu_oldmask = 0; } else - returnmask = p->p_sigmask; - p->p_sigmask |= ps->ps_catchmask[signum] | mask; + returnmask = ut->uu_sigmask; + ut->uu_sigmask |= ps->ps_catchmask[signum]; + if ((ps->ps_signodefer & mask) == 0) + ut->uu_sigmask |= mask; + if ((signum != SIGILL) && (signum != SIGTRAP) && (ps->ps_sigreset & mask)) { + if ((signum != SIGCONT) && (sigprop[signum] & SA_IGNORE)) + p->p_sigignore |= mask; + ps->ps_sigact[signum] = SIG_DFL; + ps->ps_siginfo &= ~mask; + ps->ps_signodefer &= ~mask; + } +#ifdef __ppc__ + /* Needs to disable to run in user mode */ + if (signum == SIGFPE) { + thread_enable_fpe(current_act(), 0); + } +#endif /* __ppc__ */ + if (ps->ps_sig != signum) { code = 0; } else { @@ -1902,6 +2589,7 @@ bsd_ast(thread_act_t thr_act) int signum; unsigned int pc; boolean_t funnel_state; + static bsd_init_done = 0; if (p == NULL) return; @@ -1918,7 +2606,12 @@ bsd_ast(thread_act_t thr_act) while (signum = issignal(p)) postsig(signum); } - ast_off(AST_BSD); + if (!bsd_init_done) { + extern void bsdinit_task(void); + + bsd_init_done = 1; + bsdinit_task(); + } (void) thread_funnel_set(kernel_flock, FALSE); } @@ -1935,7 +2628,7 @@ psignal_vtalarm(struct proc *p) if (p == NULL) return; funnel_state = thread_funnel_set(kernel_flock, TRUE); - psignal_lock(p, SIGVTALRM, 1, 1); + psignal_lock(p, SIGVTALRM, 1); (void) thread_funnel_set(kernel_flock, FALSE); } @@ -1947,7 +2640,7 @@ psignal_xcpu(struct proc *p) if (p == NULL) return; funnel_state = thread_funnel_set(kernel_flock, TRUE); - psignal_lock(p, SIGXCPU, 1, 1); + psignal_lock(p, SIGXCPU, 1); (void) thread_funnel_set(kernel_flock, FALSE); } @@ -1959,7 +2652,7 @@ psignal_sigprof(struct proc *p) if (p == NULL) return; funnel_state = thread_funnel_set(kernel_flock, TRUE); - psignal_lock(p, SIGPROF, 1, 1); + psignal_lock(p, SIGPROF, 1); (void) thread_funnel_set(kernel_flock, FALSE); } @@ -1979,3 +2672,18 @@ task_t task; } } } + +kern_return_t +do_bsdexception( + int exc, + int code, + int sub) +{ + exception_data_type_t codes[EXCEPTION_CODE_MAX]; + extern kern_return_t bsd_exception(int, exception_data_type_t codes[], int); + + codes[0] = code; + codes[1] = sub; + return(bsd_exception(exc, codes, 2)); +} + diff --git a/bsd/kern/kern_subr.c b/bsd/kern/kern_subr.c index 7cd4f6770..be0f738ff 100644 --- a/bsd/kern/kern_subr.c +++ b/bsd/kern/kern_subr.c @@ -136,7 +136,7 @@ uiomove(cp, n, uio) error = copywithin(iov->iov_base, (caddr_t)cp, cnt); break; -#ifdef ppc + case UIO_PHYS_USERSPACE: if (uio->uio_rw == UIO_READ) { @@ -162,7 +162,6 @@ uiomove(cp, n, uio) if (error) return (error); break; -#endif } iov->iov_base += cnt; iov->iov_len -= cnt; diff --git a/bsd/kern/kern_synch.c b/bsd/kern/kern_synch.c index 657657490..f7d68435f 100644 --- a/bsd/kern/kern_synch.c +++ b/bsd/kern/kern_synch.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -48,7 +49,13 @@ #include #include -_sleep_continue() +#if KTRACE +#include +#include +#endif + +static void +_sleep_continue(void) { register struct proc *p; register thread_t thread = current_thread(); @@ -80,7 +87,6 @@ _sleep_continue() /* else fall through */ case THREAD_INTERRUPTED: if (catch) { - unix_master(); if (thread_should_abort(current_thread())) { error = EINTR; } else if (SHOULDissignal(p,ut)) { @@ -94,19 +100,22 @@ _sleep_continue() error = EINTR; } } - unix_release(); } else error = EINTR; break; } - if ((error == EINTR) || (error == ERESTART)) { - thread_ast_set(th_act, AST_BSD); - ast_on(AST_BSD); - } + if (error == EINTR || error == ERESTART) + act_set_astbsd(th_act); + if (ut->uu_timo) thread_cancel_timer(); +#if KTRACE + if (KTRPOINT(p, KTR_CSW)) + ktrcsw(p->p_tracep, 0, 0, -1); +#endif + unix_syscall_return((*ut->uu_continuation)(error)); } @@ -124,17 +133,13 @@ _sleep_continue() * sleeping has gone away. */ -#if FIXME -static __inline__ -#endif -int -_sleep(chan, pri, wmsg, timo, continuation, preassert) - caddr_t chan; - int pri; - char *wmsg; - int timo; - int (*continuation)(); - int preassert; +static int +_sleep( + caddr_t chan, + int pri, + char *wmsg, + u_int64_t abstime, + int (*continuation)(int)) { register struct proc *p; register thread_t thread = current_thread(); @@ -142,6 +147,7 @@ _sleep(chan, pri, wmsg, timo, continuation, preassert) struct uthread * ut; int sig, catch = pri & PCATCH; int sigttblock = pri & PTTYBLOCK; + int wait_result; int error = 0; spl_t s; @@ -153,18 +159,16 @@ _sleep(chan, pri, wmsg, timo, continuation, preassert) p = current_proc(); #if KTRACE if (KTRPOINT(p, KTR_CSW)) - ktrcsw(p->p_tracep, 1, 0); + ktrcsw(p->p_tracep, 1, 0, -1); #endif p->p_priority = pri & PRIMASK; - if (!preassert) { - /* it is already pre asserted */ - if (chan) - assert_wait(chan, (catch) ? THREAD_ABORTSAFE : THREAD_UNINT); - - } - if (timo) - thread_set_timer(timo, NSEC_PER_SEC / hz); + if (chan) + wait_result = assert_wait(chan, + (catch) ? THREAD_ABORTSAFE : THREAD_UNINT); + + if (abstime) + thread_set_timer_deadline(abstime); /* * We start our timeout @@ -176,7 +180,6 @@ _sleep(chan, pri, wmsg, timo, continuation, preassert) * stopped, p->p_wchan will be 0 upon return from CURSIG. */ if (catch) { - unix_master(); if (SHOULDissignal(p,ut)) { if (sig = CURSIG(p)) { clear_wait(thread, THREAD_INTERRUPTED); @@ -184,11 +187,11 @@ _sleep(chan, pri, wmsg, timo, continuation, preassert) if (sigttblock && ((sig == SIGTTOU) || (sig == SIGTTIN))) { p->p_flag |= P_TTYSLEEP; /* reset signal bits */ - clear_sigbits(p, sig); + clear_procsiglist(p, sig); assert_wait(&p->p_siglist, THREAD_ABORTSAFE); /* assert wait can block and SIGCONT should be checked */ if (p->p_flag & P_TTYSLEEP) - thread_block(0); + thread_block(THREAD_CONTINUE_NULL); /* return with success */ error = 0; goto out; @@ -197,21 +200,18 @@ _sleep(chan, pri, wmsg, timo, continuation, preassert) error = EINTR; else error = ERESTART; - unix_release(); goto out; } } if (thread_should_abort(current_thread())) { clear_wait(thread, THREAD_INTERRUPTED); error = EINTR; - unix_release(); goto out; } - if (get_thread_waitevent(thread) == 0) { /*already happened */ - unix_release(); + if (get_thread_waitresult(thread) != THREAD_WAITING) { + /*already happened */ goto out; } - unix_release(); } #if FIXME /* [ */ @@ -220,20 +220,20 @@ _sleep(chan, pri, wmsg, timo, continuation, preassert) splx(s); p->p_stats->p_ru.ru_nvcsw++; - if (continuation != (int (*)()) 0 ) { + if (continuation != THREAD_CONTINUE_NULL ) { ut->uu_continuation = continuation; ut->uu_pri = pri; - ut->uu_timo = timo; - thread_block(_sleep_continue); + ut->uu_timo = abstime? 1: 0; + (void) thread_block(_sleep_continue); /* NOTREACHED */ } - thread_block(0); + wait_result = thread_block(THREAD_CONTINUE_NULL); #if FIXME /* [ */ thread->wait_mesg = NULL; #endif /* FIXME ] */ - switch (get_thread_waitresult(thread)) { + switch (wait_result) { case THREAD_TIMED_OUT: error = EWOULDBLOCK; break; @@ -248,7 +248,6 @@ _sleep(chan, pri, wmsg, timo, continuation, preassert) /* else fall through */ case THREAD_INTERRUPTED: if (catch) { - unix_master(); if (thread_should_abort(current_thread())) { error = EINTR; } else if (SHOULDissignal(p,ut)) { @@ -262,67 +261,69 @@ _sleep(chan, pri, wmsg, timo, continuation, preassert) error = EINTR; } } - unix_release(); } else error = EINTR; break; } out: - if ((error == EINTR) || (error == ERESTART)) { - thread_ast_set(th_act, AST_BSD); - ast_on(AST_BSD); - } - if (timo) + if (error == EINTR || error == ERESTART) + act_set_astbsd(th_act); + if (abstime) thread_cancel_timer(); (void) splx(s); +#if KTRACE + if (KTRPOINT(p, KTR_CSW)) + ktrcsw(p->p_tracep, 0, 0, -1); +#endif return (error); } -int sleep(chan, pri) - void *chan; - int pri; +int +sleep( + void *chan, + int pri) { - - return (_sleep((caddr_t)chan, pri, (char *)NULL, 0, (void (*)())0, 0)); - + return _sleep((caddr_t)chan, pri, (char *)NULL, 0, (int (*)(int))0); } -int tsleep(chan, pri, wmsg, timo) - void *chan; - int pri; - char * wmsg; - int timo; -{ - return(_sleep((caddr_t)chan, pri, wmsg, timo, (void (*)())0, 0)); +int +tsleep( + void *chan, + int pri, + char *wmsg, + int timo) +{ + u_int64_t abstime = 0; + + if (timo) + clock_interval_to_deadline(timo, NSEC_PER_SEC / hz, &abstime); + return _sleep((caddr_t)chan, pri, wmsg, abstime, (int (*)(int))0); } -int tsleep0(chan, pri, wmsg, timo, continuation) - void *chan; - int pri; - char * wmsg; - int timo; - int (*continuation)(); +int +tsleep0( + void *chan, + int pri, + char *wmsg, + int timo, + int (*continuation)(int)) { -#if defined (__i386__) - return(_sleep((caddr_t)chan, pri, wmsg, timo, (void (*)())0, 0)); -#else - return(_sleep((caddr_t)chan, pri, wmsg, timo, continuation, 0)); -#endif + u_int64_t abstime = 0; + + if (timo) + clock_interval_to_deadline(timo, NSEC_PER_SEC / hz, &abstime); + return _sleep((caddr_t)chan, pri, wmsg, abstime, continuation); } -/* tsleeps without assertwait or thread block */ -int tsleep1(chan, pri, wmsg, timo, continuation) - void *chan; - int pri; - char * wmsg; - int timo; - int (*continuation)(); +int +tsleep1( + void *chan, + int pri, + char *wmsg, + u_int64_t abstime, + int (*continuation)(int)) { -#if defined (__i386__) - return(_sleep((caddr_t)chan, pri, wmsg, timo, (void (*)())0, 1)); -#else - return(_sleep((caddr_t)chan, pri, wmsg, timo, continuation, 1)); -#endif + return _sleep((caddr_t)chan, pri, wmsg, abstime, continuation); } /* @@ -332,7 +333,7 @@ void wakeup(chan) register void *chan; { - thread_wakeup_prim((caddr_t)chan,FALSE, THREAD_AWAKENED); + thread_wakeup_prim((caddr_t)chan, FALSE, THREAD_AWAKENED); } /* @@ -341,6 +342,7 @@ wakeup(chan) * Be very sure that the first process is really * the right one to wakeup. */ +void wakeup_one(chan) register caddr_t chan; { @@ -358,3 +360,27 @@ resetpriority(p) { (void)task_importance(p->task, -p->p_nice); } + +struct loadavg averunnable = + { {0, 0, 0}, FSCALE }; /* load average, of runnable procs */ +/* + * Constants for averages over 1, 5, and 15 minutes + * when sampling at 5 second intervals. + */ +static fixpt_t cexp[3] = { + (fixpt_t)(0.9200444146293232 * FSCALE), /* exp(-1/12) */ + (fixpt_t)(0.9834714538216174 * FSCALE), /* exp(-1/60) */ + (fixpt_t)(0.9944598480048967 * FSCALE), /* exp(-1/180) */ +}; + +void +compute_averunnable( + register int nrun) +{ + register int i; + struct loadavg *avg = &averunnable; + + for (i = 0; i < 3; i++) + avg->ldavg[i] = (cexp[i] * avg->ldavg[i] + + nrun * FSCALE * (FSCALE - cexp[i])) >> FSHIFT; +} diff --git a/bsd/kern/kern_sysctl.c b/bsd/kern/kern_sysctl.c index 41091784d..6aefc6796 100644 --- a/bsd/kern/kern_sysctl.c +++ b/bsd/kern/kern_sysctl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -76,6 +76,7 @@ #include #include #include +#include #include #include #include @@ -92,7 +93,7 @@ extern vm_map_t bsd_pageable_map; #include #if __ppc__ -#include +#include #endif sysctlfn kern_sysctl; @@ -121,6 +122,7 @@ fill_externproc(struct proc *p, struct extern_proc *exp); /* * temporary location for vm_sysctl. This should be machine independant */ +int vm_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) int *name; u_int namelen; @@ -130,26 +132,20 @@ vm_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) size_t newlen; struct proc *p; { - int error, level, inthostid; - extern long avenrun[3], mach_factor[3]; + extern uint32_t mach_factor[3]; struct loadavg loadinfo; - //if (namelen != 1 && !(name[0] == VM_LOADAVG)) - //return (ENOTDIR); /* overloaded */ - switch (name[0]) { case VM_LOADAVG: - loadinfo.ldavg[0] = avenrun[0]; - loadinfo.ldavg[1] = avenrun[1]; - loadinfo.ldavg[2] = avenrun[2]; - loadinfo.fscale = LSCALE; - return (sysctl_struct(oldp, oldlenp, newp, newlen, &loadinfo, sizeof(struct loadavg))); + return (sysctl_struct(oldp, oldlenp, newp, newlen, + &averunnable, sizeof(struct loadavg))); case VM_MACHFACTOR: loadinfo.ldavg[0] = mach_factor[0]; loadinfo.ldavg[1] = mach_factor[1]; loadinfo.ldavg[2] = mach_factor[2]; loadinfo.fscale = LSCALE; - return (sysctl_struct(oldp, oldlenp, newp, newlen, &loadinfo, sizeof(struct loadavg))); + return (sysctl_struct(oldp, oldlenp, newp, newlen, + &loadinfo, sizeof(struct loadavg))); case VM_METER: return (EOPNOTSUPP); case VM_MAXID: @@ -201,11 +197,13 @@ __sysctl(p, uap, retval) return (error); /* CTL_UNSPEC is used to get oid to AUTO_OID */ - if (uap->new != NULL && - (((name[0] == CTL_KERN) && (name[1] != KERN_IPC)) || - (name[0] == CTL_HW) || (name[0] == CTL_VM) || - (name[0] == CTL_VFS)) && - (error = suser(p->p_ucred, &p->p_acflag))) + if (uap->new != NULL + && ((name[0] == CTL_KERN + && !(name[1] == KERN_IPC || name[1] == KERN_PANICINFO)) + || (name[0] == CTL_HW) + || (name[0] == CTL_VM) + || (name[0] == CTL_VFS)) + && (error = suser(p->p_ucred, &p->p_acflag))) return (error); switch (name[0]) { @@ -225,11 +223,6 @@ __sysctl(p, uap, retval) case CTL_VFS: fn = vfs_sysctl; break; -#if FIXME /* [ */ - case CTL_MACHDEP: - fn = cpu_sysctl; - break; -#endif /* FIXME ] */ #ifdef DEBUG case CTL_DEBUG: fn = debug_sysctl; @@ -248,7 +241,8 @@ __sysctl(p, uap, retval) return (EFAULT); /* The pc sampling mechanism does not need to take this lock */ - if (name[1] != KERN_PCSAMPLES) { + if ((name[1] != KERN_PCSAMPLES) && + (!((name[1] == KERN_KDEBUG) && (name[2] == KERN_KDGETENTROPY)))) { while (memlock.sl_lock) { memlock.sl_want = 1; sleep((caddr_t)&memlock, PRIBIO+1); @@ -258,7 +252,8 @@ __sysctl(p, uap, retval) } if (dolock && oldlen && (error = vslock(uap->old, oldlen))) { - if (name[1] != KERN_PCSAMPLES) { + if ((name[1] != KERN_PCSAMPLES) && + (! ((name[1] == KERN_KDEBUG) && (name[2] == KERN_KDGETENTROPY)))) { memlock.sl_lock = 0; if (memlock.sl_want) { memlock.sl_want = 0; @@ -321,11 +316,14 @@ int securelevel = -1; int securelevel; #endif -int get_kernel_symfile( struct proc *p, char **symfile ); +extern int get_kernel_symfile( struct proc *, char **); +extern int sysctl_dopanicinfo(int *, u_int, void *, size_t *, + void *, size_t, struct proc *); /* * kernel related system variables. */ +int kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) int *name; u_int namelen; @@ -337,15 +335,21 @@ kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) { int error, level, inthostid; unsigned int oldval=0; + char *str; extern char ostype[], osrelease[], version[]; - - /* all sysctl names at this level are terminal */ - if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF - || name[0] == KERN_KDEBUG - || name[0] == KERN_PROCARGS - || name[0] == KERN_PCSAMPLES - || name[0] == KERN_IPC - )) + extern int netboot_root(); + + /* all sysctl names not listed below are terminal at this level */ + if (namelen != 1 + && !(name[0] == KERN_PROC + || name[0] == KERN_PROF + || name[0] == KERN_KDEBUG + || name[0] == KERN_PROCARGS + || name[0] == KERN_PCSAMPLES + || name[0] == KERN_IPC + || name[0] == KERN_SYSV + || name[0] == KERN_PANICINFO) + ) return (ENOTDIR); /* overloaded */ switch (name[0]) { @@ -423,24 +427,23 @@ kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) #else return (sysctl_rdint(oldp, oldlenp, newp, 0)); #endif -#if FIXME /* [ */ - case KERN_MAXPARTITIONS: - return (sysctl_rdint(oldp, oldlenp, newp, MAXPARTITIONS)); -#endif /* FIXME ] */ case KERN_KDEBUG: return (kdebug_ops(name + 1, namelen - 1, oldp, oldlenp, p)); case KERN_PCSAMPLES: return (pcsamples_ops(name + 1, namelen - 1, oldp, oldlenp, p)); case KERN_PROCARGS: /* new one as it does not use kinfo_proc */ - return (sysctl_procargs(name + 1, namelen - 1, oldp, oldlenp)); - case KERN_SYMFILE: - { - char *str; - error = get_kernel_symfile( p, &str ); - if ( error ) return error; - return (sysctl_rdstring(oldp, oldlenp, newp, str)); - } + return (sysctl_procargs(name + 1, namelen - 1, oldp, oldlenp, p)); + case KERN_SYMFILE: + error = get_kernel_symfile( p, &str ); + if ( error ) + return error; + return (sysctl_rdstring(oldp, oldlenp, newp, str)); + case KERN_NETBOOT: + return (sysctl_rdint(oldp, oldlenp, newp, netboot_root())); + case KERN_PANICINFO: + return(sysctl_dopanicinfo(name + 1, namelen - 1, oldp, oldlenp, + newp, newlen, p)); default: return (EOPNOTSUPP); } @@ -481,7 +484,8 @@ hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) if(!PEGetModelName(dummy,64)) return(EINVAL); return (sysctl_rdstring(oldp, oldlenp, newp, dummy)); - case HW_NCPU: { + case HW_NCPU: + { int numcpus=1; host_basic_info_data_t hinfo; kern_return_t kret; @@ -592,6 +596,7 @@ debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) * Validate parameters and get old / set new parameters * for an integer-valued sysctl function. */ +int sysctl_int(oldp, oldlenp, newp, newlen, valp) void *oldp; size_t *oldlenp; @@ -616,6 +621,7 @@ sysctl_int(oldp, oldlenp, newp, newlen, valp) /* * As above, but read-only. */ +int sysctl_rdint(oldp, oldlenp, newp, val) void *oldp; size_t *oldlenp; @@ -634,10 +640,59 @@ sysctl_rdint(oldp, oldlenp, newp, val) return (error); } +/* + * Validate parameters and get old / set new parameters + * for an quad(64bit)-valued sysctl function. + */ +int +sysctl_quad(oldp, oldlenp, newp, newlen, valp) + void *oldp; + size_t *oldlenp; + void *newp; + size_t newlen; + quad_t *valp; +{ + int error = 0; + + if (oldp && *oldlenp < sizeof(quad_t)) + return (ENOMEM); + if (newp && newlen != sizeof(quad_t)) + return (EINVAL); + *oldlenp = sizeof(quad_t); + if (oldp) + error = copyout(valp, oldp, sizeof(quad_t)); + if (error == 0 && newp) + error = copyin(newp, valp, sizeof(quad_t)); + return (error); +} + +/* + * As above, but read-only. + */ +int +sysctl_rdquad(oldp, oldlenp, newp, val) + void *oldp; + size_t *oldlenp; + void *newp; + quad_t val; +{ + int error = 0; + + if (oldp && *oldlenp < sizeof(quad_t)) + return (ENOMEM); + if (newp) + return (EPERM); + *oldlenp = sizeof(quad_t); + if (oldp) + error = copyout((caddr_t)&val, oldp, sizeof(quad_t)); + return (error); +} + /* * Validate parameters and get old / set new parameters * for a string-valued sysctl function. */ +int sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen) void *oldp; size_t *oldlenp; @@ -653,8 +708,8 @@ sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen) return (ENOMEM); if (newp && newlen >= maxlen) return (EINVAL); + *oldlenp = len -1; /* deal with NULL strings correctly */ if (oldp) { - *oldlenp = len; error = copyout(str, oldp, len); } if (error == 0 && newp) { @@ -667,6 +722,7 @@ sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen) /* * As above, but read-only. */ +int sysctl_rdstring(oldp, oldlenp, newp, str) void *oldp; size_t *oldlenp; @@ -690,6 +746,7 @@ sysctl_rdstring(oldp, oldlenp, newp, str) * Validate parameters and get old / set new parameters * for a structure oriented sysctl function. */ +int sysctl_struct(oldp, oldlenp, newp, newlen, sp, len) void *oldp; size_t *oldlenp; @@ -717,6 +774,7 @@ sysctl_struct(oldp, oldlenp, newp, newlen, sp, len) * Validate parameters and get old parameters * for a structure oriented sysctl function. */ +int sysctl_rdstruct(oldp, oldlenp, newp, sp, len) void *oldp; size_t *oldlenp; @@ -738,6 +796,7 @@ sysctl_rdstruct(oldp, oldlenp, newp, sp, len) /* * Get file structures. */ +int sysctl_file(where, sizep) char *where; size_t *sizep; @@ -789,6 +848,7 @@ sysctl_file(where, sizep) */ #define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc)) +int sysctl_doproc(name, namelen, where, sizep) int *name; u_int namelen; @@ -907,23 +967,11 @@ fill_eproc(p, ep) ep->e_pcred = *p->p_cred; ep->e_ucred = *p->p_ucred; if (p->p_stat == SIDL || p->p_stat == SZOMB) { - ep->e_vm.vm_rssize = 0; ep->e_vm.vm_tsize = 0; ep->e_vm.vm_dsize = 0; ep->e_vm.vm_ssize = 0; - /* ep->e_vm.vm_pmap = XXX; */ - } else { -#if FIXME /* [ */ - register vm_map_t vm = ((task_t)p->task)->map; - - ep->e_vm.vm_rssize = pmap_resident_count(vm->pmap); /*XXX*/ -// ep->e_vm.vm_tsize = vm->vm_tsize; -// ep->e_vm.vm_dsize = vm->vm_dsize; -// ep->e_vm.vm_ssize = vm->vm_ssize; -#else /* FIXME ][ */ - ep->e_vm.vm_rssize = 0; /*XXX*/ -#endif /* FIXME ] */ } + ep->e_vm.vm_rssize = 0; if (p->p_pptr) ep->e_ppid = p->p_pptr->p_pid; else @@ -954,6 +1002,8 @@ fill_externproc(p, exp) register struct extern_proc *exp; { exp->p_forw = exp->p_back = NULL; + if (p->p_stats) + exp->p_starttime = p->p_stats->p_start; exp->p_vmspace = NULL; exp->p_sigacts = p->p_sigacts; exp->p_flag = p->p_flag; @@ -981,10 +1031,10 @@ fill_externproc(p, exp) exp->p_iticks = p->p_iticks ; exp->p_traceflag = p->p_traceflag ; exp->p_tracep = p->p_tracep ; - exp->p_siglist = p->p_siglist ; + exp->p_siglist = 0 ; /* No longer relevant */ exp->p_textvp = p->p_textvp ; exp->p_holdcnt = 0 ; - exp->p_sigmask = p->p_sigmask ; + exp->p_sigmask = 0 ; /* no longer avaialable */ exp->p_sigignore = p->p_sigignore ; exp->p_sigcatch = p->p_sigcatch ; exp->p_priority = p->p_priority ; @@ -999,6 +1049,7 @@ fill_externproc(p, exp) exp->p_ru = p->p_ru ; } +int kdebug_ops(name, namelen, where, sizep, p) int *name; u_int namelen; @@ -1006,12 +1057,13 @@ char *where; size_t *sizep; struct proc *p; { -int size=*sizep; -int ret=0; -extern int kdbg_control(int *name, u_int namelen, char * where,size_t * sizep); + int size=*sizep; + int ret=0; + extern int kdbg_control(int *name, u_int namelen, + char * where,size_t * sizep); - if (ret = suser(p->p_ucred, &p->p_acflag)) - return(ret); + if (ret = suser(p->p_ucred, &p->p_acflag)) + return(ret); switch(name[0]) { case KERN_KDEFLAGS: @@ -1028,6 +1080,7 @@ extern int kdbg_control(int *name, u_int namelen, char * where,size_t * sizep); case KERN_KDPIDEX: case KERN_KDSETRTCDEC: case KERN_KDSETBUF: + case KERN_KDGETENTROPY: ret = kdbg_control(name, namelen, where, sizep); break; default: @@ -1037,6 +1090,7 @@ extern int kdbg_control(int *name, u_int namelen, char * where,size_t * sizep); return(ret); } +int pcsamples_ops(name, namelen, where, sizep, p) int *name; u_int namelen; @@ -1044,11 +1098,12 @@ char *where; size_t *sizep; struct proc *p; { -int ret=0; -extern int pcsamples_control(int *name, u_int namelen, char * where,size_t * sizep); + int ret=0; + extern int pcsamples_control(int *name, u_int namelen, + char * where,size_t * sizep); - if (ret = suser(p->p_ucred, &p->p_acflag)) - return(ret); + if (ret = suser(p->p_ucred, &p->p_acflag)) + return(ret); switch(name[0]) { case KERN_PCDISABLE: @@ -1074,11 +1129,13 @@ extern int pcsamples_control(int *name, u_int namelen, char * where,size_t * siz * zeroed for security reasons. * Odd data structure is for compatibility. */ -sysctl_procargs(name, namelen, where, sizep) +int +sysctl_procargs(name, namelen, where, sizep, cur_proc) int *name; u_int namelen; char *where; size_t *sizep; + struct proc *cur_proc; { register struct proc *p; register int needed = 0; @@ -1128,6 +1185,9 @@ sysctl_procargs(name, namelen, where, sizep) if (!p->user_stack) return(EINVAL); + if ((p->p_ucred->cr_uid != cur_proc->p_ucred->cr_uid) + && suser(cur_proc->p_ucred, &cur_proc->p_acflag)) + return (EINVAL); arg_addr = (vm_offset_t)(p->user_stack - arg_size); diff --git a/bsd/kern/kern_time.c b/bsd/kern/kern_time.c index f7eeeb639..d41be2383 100644 --- a/bsd/kern/kern_time.c +++ b/bsd/kern/kern_time.c @@ -64,14 +64,13 @@ #include -#include - #include #define HZ 100 /* XXX */ -struct timeval time; - +volatile struct timeval time; +/* simple lock used to access timezone, tz structure */ +decl_simple_lock_data(, tz_slock); /* * Time of day and interval timer support. * @@ -94,6 +93,10 @@ gettimeofday(p, uap, retval) { struct timeval atv; int error = 0; + extern simple_lock_data_t tz_slock; + struct timezone ltz; /* local copy */ + +/* NOTE THIS implementation is for non ppc architectures only */ if (uap->tp) { microtime(&atv); @@ -102,9 +105,13 @@ gettimeofday(p, uap, retval) return(error); } - if (uap->tzp) - error = copyout((caddr_t)&tz, (caddr_t)uap->tzp, + if (uap->tzp) { + usimple_lock(&tz_slock); + ltz = tz; + usimple_unlock(&tz_slock); + error = copyout((caddr_t)<z, (caddr_t)uap->tzp, sizeof (tz)); + } return(error); } @@ -123,6 +130,7 @@ settimeofday(p, uap, retval) struct timeval atv; struct timezone atz; int error, s; + extern simple_lock_data_t tz_slock; if (error = suser(p->p_ucred, &p->p_acflag)) return (error); @@ -135,36 +143,32 @@ settimeofday(p, uap, retval) return (error); if (uap->tv) setthetime(&atv); - if (uap->tzp) + if (uap->tzp) { + usimple_lock(&tz_slock); tz = atz; + usimple_unlock(&tz_slock); + } return (0); } setthetime(tv) struct timeval *tv; { + long delta = tv->tv_sec - time.tv_sec; mach_timespec_t now; - long delta; - int s; now.tv_sec = tv->tv_sec; now.tv_nsec = tv->tv_usec * NSEC_PER_USEC; clock_set_calendar_value(now); - delta = tv->tv_sec - time.tv_sec; boottime.tv_sec += delta; #if NFSCLIENT || NFSSERVER lease_updatetime(delta); #endif - s = splhigh(); - microtime(&time); - splx(s); } -int tickadj = 240000 / (60 * HZ); /* "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. */ +#define tickadj (40 * NSEC_PER_USEC) /* "standard" skew, ns / 10 ms */ +#define bigadj (1 * NSEC_PER_SEC) /* use 10x skew above bigadj ns */ struct adjtime_args { struct timeval *delta; @@ -177,43 +181,38 @@ adjtime(p, uap, retval) register struct adjtime_args *uap; register_t *retval; { - struct timeval atv, oatv; - register long ndelta; - int s, error; + struct timeval atv; + int64_t total; + uint32_t delta; + int 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); + 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 / tickdelta * tickdelta; + /* + * Compute the total correction and the rate at which to apply it. + */ + total = (int64_t)atv.tv_sec * NSEC_PER_SEC + atv.tv_usec * NSEC_PER_USEC; + if (total > bigadj || total < -bigadj) + delta = 10 * tickadj; + else + delta = tickadj; + + total = clock_set_calendar_adjtime(total, delta); - s = splclock(); if (uap->olddelta) { - oatv.tv_sec = timedelta / 1000000; - oatv.tv_usec = timedelta % 1000000; + atv.tv_sec = total / NSEC_PER_SEC; + atv.tv_usec = (total / NSEC_PER_USEC) % USEC_PER_SEC; + (void) copyout((caddr_t)&atv, + (caddr_t)uap->olddelta, sizeof (struct timeval)); } - timedelta = ndelta; - splx(s); - if (uap->olddelta) - (void) copyout((caddr_t)&oatv, (caddr_t)uap->olddelta, - sizeof (struct timeval)); - return(0); + return (0); } -#define SECDAY ((unsigned)(24*60*60)) /* seconds per day */ -#define SECYR ((unsigned)(365*SECDAY)) /* per common year */ -#define YRREF 70 /* UNIX time referenced to 1970 */ - /* * Initialze the time of day register. * Trust the RTC except for the case where it is set before @@ -258,26 +257,37 @@ inittodr(base) return; } +void timevaladd( + struct timeval *t1, + struct timeval *t2); +void timevalsub( + struct timeval *t1, + struct timeval *t2); +void timevalfix( + struct timeval *t1); + +uint64_t + tvtoabstime( + struct timeval *tvp); + /* * Get value of an interval timer. The process virtual and - * profiling virtual time timers are kept in the u. area, since - * they can be swapped out. These are kept internally in the + * profiling virtual time timers 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. + * The real time interval timer expiration time (p_rtime) + * 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. + * kern_clock.c. The real time timer is processed by a callout + * routine. Since a callout may be delayed in real time due to + * other processing in the system, it is possible for the real + * time callout 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 time .it_value from the + * real time .it_interval. Rather, we compute the next time in + * absolute time when the timer should go off. */ struct getitimer_args { @@ -292,30 +302,35 @@ getitimer(p, uap, retval) register_t *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. + * 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, <)) + if (timerisset(&p->p_rtime)) { + struct timeval now; + + microuptime(&now); + if (timercmp(&p->p_rtime, &now, <)) 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))); + else { + aitv.it_value = p->p_rtime; + timevalsub(&aitv.it_value, &now); + } + } + else + timerclear(&aitv.it_value); + } + else + aitv = p->p_stats->p_timer[uap->which]; + + return (copyout((caddr_t)&aitv, + (caddr_t)uap->itv, sizeof (struct itimerval))); } struct setitimer_args { @@ -332,33 +347,38 @@ setitimer(p, uap, retval) { struct itimerval aitv; register struct itimerval *itvp; - int s, error; + int 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 (EINVAL); + if ((itvp = uap->itv) && + (error = copyin((caddr_t)itvp, + (caddr_t)&aitv, sizeof (struct itimerval)))) return (error); - if ((uap->itv = uap->oitv) && - (error = getitimer(p, uap, retval))) + 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); + thread_call_func_cancel(realitexpire, (void *)p->p_pid, FALSE); if (timerisset(&aitv.it_value)) { - timevaladd(&aitv.it_value, &time); - timeout(realitexpire, (caddr_t)p, hzto(&aitv.it_value)); + microuptime(&p->p_rtime); + timevaladd(&p->p_rtime, &aitv.it_value); + thread_call_func_delayed( + realitexpire, (void *)p->p_pid, + tvtoabstime(&p->p_rtime)); } + else + timerclear(&p->p_rtime); + p->p_realtimer = aitv; - } else + } + else p->p_stats->p_timer[uap->which] = aitv; - splx(s); - return(0); /* To insure good return value on success */ + + return (0); } /* @@ -370,53 +390,47 @@ setitimer(p, uap, retval) * SIGALRM calls to be compressed into one. */ void -realitexpire(arg) - void *arg; +realitexpire( + void *pid) { register struct proc *p; - int s; - boolean_t funnel_state; + struct timeval now; + boolean_t funnel_state = thread_funnel_set(kernel_flock, TRUE); - funnel_state = thread_funnel_set(kernel_flock,TRUE); - - p = (struct proc *)arg; - psignal(p, SIGALRM); - if (!timerisset(&p->p_realtimer.it_interval)) { - timerclear(&p->p_realtimer.it_value); - (void) thread_funnel_set(kernel_flock, FALSE); + p = pfind((pid_t)pid); + if (p == NULL) { + (void) thread_funnel_set(kernel_flock, FALSE); return; } - - /* - * If the time's way off, don't try to compensate by getting - * there incrementally. - */ - s = splclock(); - if (p->p_realtimer.it_value.tv_sec < time.tv_sec - 10) { - p->p_realtimer.it_value = time; - timeout(realitexpire, (caddr_t)p, - hzto(&p->p_realtimer.it_value)); - splx(s); - (void) thread_funnel_set(kernel_flock, FALSE); + + if (!timerisset(&p->p_realtimer.it_interval)) { + timerclear(&p->p_rtime); + psignal(p, SIGALRM); + + (void) thread_funnel_set(kernel_flock, FALSE); return; - } - splx(s); - - 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); - (void) thread_funnel_set(kernel_flock, FALSE); - return; + + microuptime(&now); + timevaladd(&p->p_rtime, &p->p_realtimer.it_interval); + if (timercmp(&p->p_rtime, &now, <=)) { + if ((p->p_rtime.tv_sec + 2) >= now.tv_sec) { + for (;;) { + timevaladd(&p->p_rtime, &p->p_realtimer.it_interval); + if (timercmp(&p->p_rtime, &now, >)) + break; + } + } + else { + p->p_rtime = p->p_realtimer.it_interval; + timevaladd(&p->p_rtime, &now); } - splx(s); } - + + thread_call_func_delayed(realitexpire, pid, tvtoabstime(&p->p_rtime)); + + psignal(p, SIGALRM); + (void) thread_funnel_set(kernel_flock, FALSE); } @@ -490,8 +504,9 @@ expire: * Caveat emptor. */ void -timevaladd(t1, t2) - struct timeval *t1, *t2; +timevaladd( + struct timeval *t1, + struct timeval *t2) { t1->tv_sec += t2->tv_sec; @@ -499,8 +514,9 @@ timevaladd(t1, t2) timevalfix(t1); } void -timevalsub(t1, t2) - struct timeval *t1, *t2; +timevalsub( + struct timeval *t1, + struct timeval *t2) { t1->tv_sec -= t2->tv_sec; @@ -508,8 +524,8 @@ timevalsub(t1, t2) timevalfix(t1); } void -timevalfix(t1) - struct timeval *t1; +timevalfix( + struct timeval *t1) { if (t1->tv_usec < 0) { @@ -527,10 +543,67 @@ timevalfix(t1) * to which tvp points. */ void -microtime(struct timeval * tvp) +microtime( + struct timeval *tvp) { mach_timespec_t now = clock_get_calendar_value(); tvp->tv_sec = now.tv_sec; tvp->tv_usec = now.tv_nsec / NSEC_PER_USEC; } + +void +microuptime( + struct timeval *tvp) +{ + mach_timespec_t now = clock_get_system_value(); + + tvp->tv_sec = now.tv_sec; + tvp->tv_usec = now.tv_nsec / NSEC_PER_USEC; +} + +/* + * Ditto for timespec. + */ +void +nanotime( + struct timespec *tsp) +{ + mach_timespec_t now = clock_get_calendar_value(); + + tsp->tv_sec = now.tv_sec; + tsp->tv_nsec = now.tv_nsec; +} + +void +nanouptime( + struct timespec *tsp) +{ + mach_timespec_t now = clock_get_system_value(); + + tsp->tv_sec = now.tv_sec; + tsp->tv_nsec = now.tv_nsec; +} + +uint64_t +tvtoabstime( + struct timeval *tvp) +{ + uint64_t result, usresult; + + clock_interval_to_absolutetime_interval( + tvp->tv_sec, NSEC_PER_SEC, &result); + clock_interval_to_absolutetime_interval( + tvp->tv_usec, NSEC_PER_USEC, &usresult); + + return (result + usresult); +} +void +time_zone_slock_init(void) +{ + extern simple_lock_data_t tz_slock; + + simple_lock_init(&tz_slock); + + +} diff --git a/bsd/kern/mach_loader.c b/bsd/kern/mach_loader.c index ea6eda046..0a9956125 100644 --- a/bsd/kern/mach_loader.c +++ b/bsd/kern/mach_loader.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -54,9 +54,13 @@ #include #include #include -#include #include +#include +#include + +#include + /* * Prototypes of static functions. */ @@ -403,20 +407,18 @@ RedoLookup: &(map_info.alternate_next), &(map_info.flags), &next); - if((map_info.flags & SHARED_REGION_FULL) && + if((map_info.self != (vm_offset_t)system_shared_region) && (map_info.flags & SHARED_REGION_SYSTEM)) { - if(map_info.self != (vm_offset_t)system_shared_region) { - shared_region_mapping_ref(system_shared_region); - vm_set_shared_region(task, - system_shared_region); - shared_region_mapping_dealloc( + shared_region_mapping_ref(system_shared_region); + vm_set_shared_region(task, system_shared_region); + shared_region_mapping_dealloc( (shared_region_mapping_t)map_info.self); - goto RedoLookup; - } + goto RedoLookup; } if (dylink_test) { + p->p_flag |= P_NOSHLIB; /* no shlibs in use */ addr = map_info.client_base; vm_map(map, &addr, map_info.text_size, 0, (VM_MEMORY_SHARED_PMAP << 24) @@ -723,17 +725,15 @@ load_threadstack( unsigned long size; int flavor; - /* - * Set the thread state. - */ - *user_stack = 0; while (total_size > 0) { flavor = *ts++; size = *ts++; total_size -= (size+2)*sizeof(unsigned long); if (total_size < 0) return(LOAD_BADMACHO); - ret = thread_userstack(thread, flavor, ts, size, user_stack, customstack); + *user_stack = USRSTACK; + ret = thread_userstack(thread, flavor, ts, size, + user_stack, customstack); if (ret != KERN_SUCCESS) return(LOAD_FAILURE); ts += size; /* ts is a (unsigned long *) */ diff --git a/bsd/kern/mach_process.c b/bsd/kern/mach_process.c index db317e75a..e7df848de 100644 --- a/bsd/kern/mach_process.c +++ b/bsd/kern/mach_process.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -59,12 +59,6 @@ * * from: @(#)sys_process.c 8.1 (Berkeley) 6/10/93 */ -/* - * HISTORY - * - * 10-Jun-97 Umesh Vaishampayan (umeshv@apple.com) - * Ported to PPC. Cleaned up the architecture specific code. - */ #include #include @@ -90,7 +84,9 @@ #define CLR(t, f) (t) &= ~(f) #define ISSET(t, f) ((t) & (f)) -void psignal_lock __P((struct proc *, int, int, int)); +void psignal_lock __P((struct proc *, int, int)); +int isinferior __P((struct proc *, struct proc *)); + /* * sys-trace system call. */ @@ -100,6 +96,7 @@ struct ptrace_args { caddr_t addr; int data; }; + int ptrace(p, uap, retval) struct proc *p; @@ -110,7 +107,6 @@ ptrace(p, uap, retval) vm_offset_t start_addr, end_addr, kern_addr, offset; vm_size_t size; - boolean_t change_protection; task_t task; thread_t thread; thread_act_t th_act; @@ -118,19 +114,20 @@ ptrace(p, uap, retval) int *locr0; int error = 0; #if defined(ppc) - struct ppc_saved_state statep; + struct ppc_thread_state statep; #elif defined(i386) struct i386_saved_state statep; #else #error architecture not supported #endif unsigned long state_count; + int tr_sigexc = 0; if (uap->req == PT_DENY_ATTACH) { if (ISSET(p->p_flag, P_TRACED)) { exit1(p, W_EXITCODE(ENOTSUP, 0), retval); - /* drop funnel befewo we return */ + /* drop funnel before we return */ thread_funnel_set(kernel_flock, FALSE); thread_exception_return(); /* NOTREACHED */ @@ -140,6 +137,14 @@ ptrace(p, uap, retval) return(0); } + if (uap->req == PT_FORCEQUOTA) { + if (is_suser()) { + SET(t->p_flag, P_FORCEQUOTA); + return (0); + } else + return (EPERM); + } + /* * Intercept and deal with "please trace me" request. */ @@ -149,6 +154,13 @@ ptrace(p, uap, retval) t->p_oppid = t->p_pptr->p_pid; return(0); } + if (uap->req == PT_SIGEXC) { + if (ISSET(p->p_flag, P_TRACED)) { + SET(p->p_flag, P_SIGEXC); + return(0); + } else + return(EINVAL); + } /* * Locate victim, and make sure it is traceable. @@ -164,6 +176,10 @@ ptrace(p, uap, retval) return (EPERM); task = t->task; + if (uap->req == PT_ATTACHEXC) { + uap->req = PT_ATTACH; + tr_sigexc = 1; + } if (uap->req == PT_ATTACH) { /* @@ -188,11 +204,17 @@ ptrace(p, uap, retval) (error = suser(p->p_ucred, &p->p_acflag)) != 0) return (error); + if ((p->p_flag & P_TRACED) && isinferior(p, t)) + return(EPERM); + if (ISSET(t->p_flag, P_NOATTACH)) { psignal(p, SIGSEGV); return (EBUSY); } SET(t->p_flag, P_TRACED); + if (tr_sigexc) + SET(t->p_flag, P_SIGEXC); + t->p_oppid = t->p_pptr->p_pid; if (t->p_pptr != p) proc_reparent(t, p); @@ -242,6 +264,7 @@ ptrace(p, uap, retval) t->p_oppid = 0; CLR(t->p_flag, P_TRACED); + CLR(t->p_flag, P_SIGEXC); goto resume; case PT_KILL: @@ -249,24 +272,24 @@ ptrace(p, uap, retval) * Tell child process to kill itself after it * is resumed by adding NSIG to p_cursig. [see issig] */ - psignal_lock(t, SIGKILL, 0, 0); + psignal_lock(t, SIGKILL, 0); goto resume; case PT_STEP: /* single step the child */ case PT_CONTINUE: /* continue the child */ th_act = (thread_act_t)get_firstthread(task); - if (th_act == THREAD_NULL) + if (th_act == THR_ACT_NULL) goto errorLabel; ut = (uthread_t)get_bsdthread_info(th_act); locr0 = ut->uu_ar0; #if defined(i386) state_count = i386_NEW_THREAD_STATE_COUNT; - if (act_machine_get_state(th_act, i386_NEW_THREAD_STATE, &statep, &state_count) != KERN_SUCCESS) { + if (thread_getstatus(th_act, i386_NEW_THREAD_STATE, &statep, &state_count) != KERN_SUCCESS) { goto errorLabel; } #elif defined(ppc) state_count = PPC_THREAD_STATE_COUNT; - if (act_machine_get_state(th_act, PPC_THREAD_STATE, &statep, &state_count) != KERN_SUCCESS) { + if (thread_getstatus(th_act, PPC_THREAD_STATE, &statep, &state_count) != KERN_SUCCESS) { goto errorLabel; } #else @@ -282,7 +305,7 @@ ptrace(p, uap, retval) statep.srr0 = (int)uap->addr; state_count = PPC_THREAD_STATE_COUNT; - if (act_machine_set_state(th_act, PPC_THREAD_STATE, &statep, &state_count) != KERN_SUCCESS) { + if (thread_setstatus(th_act, PPC_THREAD_STATE, &statep, &state_count) != KERN_SUCCESS) { goto errorLabel; } #undef ALIGNED @@ -295,11 +318,11 @@ ptrace(p, uap, retval) goto errorLabel; if (uap->data != 0) { - psignal_lock(t, uap->data, 0, 1); + psignal_lock(t, uap->data, 0); } #if defined(ppc) state_count = PPC_THREAD_STATE_COUNT; - if (act_machine_get_state(th_act, PPC_THREAD_STATE, &statep, &state_count) != KERN_SUCCESS) { + if (thread_getstatus(th_act, PPC_THREAD_STATE, &statep, &state_count) != KERN_SUCCESS) { goto errorLabel; } #endif @@ -324,7 +347,7 @@ ptrace(p, uap, retval) } #if defined (ppc) state_count = PPC_THREAD_STATE_COUNT; - if (act_machine_set_state(th_act, PPC_THREAD_STATE, &statep, &state_count) != KERN_SUCCESS) { + if (thread_setstatus(th_act, PPC_THREAD_STATE, &statep, &state_count) != KERN_SUCCESS) { goto errorLabel; } #endif @@ -337,10 +360,28 @@ ptrace(p, uap, retval) } break; + case PT_THUPDATE: { + thread_act_t target_act; + + if ((unsigned)uap->data >= NSIG) + goto errorLabel; + th_act = (thread_act_t)port_name_to_act((void *)uap->addr); + if (th_act == THR_ACT_NULL) + return (ESRCH); + ut = (uthread_t)get_bsdthread_info(th_act); + if (uap->data) + ut->uu_siglist |= sigmask(uap->data); + t->p_xstat = uap->data; + t->p_stat = SRUN; + act_deallocate(th_act); + return(0); + } + break; +errorLabel: default: - errorLabel: return(EINVAL); } + return(0); } diff --git a/bsd/kern/netboot.c b/bsd/kern/netboot.c new file mode 100644 index 000000000..4043bc9d3 --- /dev/null +++ b/bsd/kern/netboot.c @@ -0,0 +1,754 @@ +/* + * Copyright (c) 2001 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * History: + * 14 December, 2001 Dieter Siegmund (dieter@apple.com) + * - created + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +//#include + +extern dev_t rootdev; /* device of the root */ +extern struct filedesc filedesc0; + +extern char * strchr(const char *str, int ch); + +extern int nfs_mountroot(); /* nfs_vfsops.c */ +extern int (*mountroot)(void); + +extern unsigned char rootdevice[]; + +static int S_netboot = 0; +static struct netboot_info * S_netboot_info_p; + +void * +IOBSDRegistryEntryForDeviceTree(char * path); + +void +IOBSDRegistryEntryRelease(void * entry); + +const void * +IOBSDRegistryEntryGetData(void * entry, char * property_name, + int * packet_length); + +extern int vndevice_root_image(const char * path, char devname[], + dev_t * dev_p); +extern int di_root_image(const char *path, char devname[], dev_t *dev_p); + + +static boolean_t path_getfile __P((char * image_path, + struct sockaddr_in * sin_p, + char * serv_name, char * pathname)); + +#define BOOTP_RESPONSE "bootp-response" +#define BSDP_RESPONSE "bsdp-response" +#define DHCP_RESPONSE "dhcp-response" + +extern int +bootp(struct ifnet * ifp, struct in_addr * iaddr_p, int max_retry, + struct in_addr * netmask_p, struct in_addr * router_p, + struct proc * procp); + +#define IP_FORMAT "%d.%d.%d.%d" +#define IP_CH(ip) ((u_char *)ip) +#define IP_LIST(ip) IP_CH(ip)[0],IP_CH(ip)[1],IP_CH(ip)[2],IP_CH(ip)[3] + +#define kNetBootRootPathPrefixNFS "nfs:" +#define kNetBootRootPathPrefixHTTP "http:" + +typedef enum { + kNetBootImageTypeUnknown = 0, + kNetBootImageTypeNFS = 1, + kNetBootImageTypeHTTP = 2, +} NetBootImageType; + +struct netboot_info { + struct in_addr client_ip; + struct in_addr server_ip; + char * server_name; + int server_name_length; + char * mount_point; + int mount_point_length; + char * image_path; + int image_path_length; + NetBootImageType image_type; + boolean_t use_hdix; +}; + +int +inet_aton(char * cp, struct in_addr * pin) +{ + u_char * b = (char *)pin; + int i; + char * p; + + for (p = cp, i = 0; i < 4; i++) { + u_long l = strtoul(p, 0, 0); + if (l > 255) + return (FALSE); + b[i] = l; + p = strchr(p, '.'); + if (i < 3 && p == NULL) + return (FALSE); + p++; + } + return (TRUE); +} + +/* + * Function: parse_booter_path + * Purpose: + * Parse a string of the form: + * "::[:]" + * into the given ip address, host, mount point, and optionally, image_path. + * + * Note: + * The passed in string is modified i.e. ':' is replaced by '\0'. + * Example: + * "17.202.16.17:seaport:/release/.images/Image9/CurrentHera" + */ +static __inline__ boolean_t +parse_booter_path(char * path, struct in_addr * iaddr_p, char * * host, + char * * mount_dir, char * * image_path) +{ + char * start; + char * colon; + + /* IP address */ + start = path; + colon = strchr(start, ':'); + if (colon == NULL) { + return (FALSE); + } + *colon = '\0'; + if (inet_aton(start, iaddr_p) != 1) { + return (FALSE); + } + + /* host */ + start = colon + 1; + colon = strchr(start, ':'); + if (colon == NULL) { + return (FALSE); + } + *colon = '\0'; + *host = start; + + /* mount */ + start = colon + 1; + colon = strchr(start, ':'); + *mount_dir = start; + if (colon == NULL) { + *image_path = NULL; + } + else { + /* image path */ + *colon = '\0'; + start = colon + 1; + *image_path = start; + } + return (TRUE); +} + +/* + * Function: find_colon + * Purpose: + * Find the next unescaped instance of the colon character. + * If a colon is escaped (preceded by a backslash '\' character), + * shift the string over by one character to overwrite the backslash. + */ +static __inline__ char * +find_colon(char * str) +{ + char * start = str; + char * colon; + + while ((colon = strchr(start, ':')) != NULL) { + char * dst; + char * src; + + if (colon == start) { + break; + } + if (colon[-1] != '\\') + break; + for (dst = colon - 1, src = colon; *dst != '\0'; dst++, src++) { + *dst = *src; + } + start = colon; + } + return (colon); +} + +/* + * Function: parse_netboot_path + * Purpose: + * Parse a string of the form: + * "nfs::[:]" + * into the given ip address, host, mount point, and optionally, image_path. + * Notes: + * - the passed in string is modified i.e. ':' is replaced by '\0' + * - literal colons must be escaped with a backslash + * + * Examples: + * nfs:17.202.42.112:/Library/NetBoot/NetBootSP0:Jaguar/Jaguar.dmg + * nfs:17.202.42.112:/Volumes/Foo\:/Library/NetBoot/NetBootSP0:Jaguar/Jaguar.dmg + */ +static __inline__ boolean_t +parse_netboot_path(char * path, struct in_addr * iaddr_p, char * * host, + char * * mount_dir, char * * image_path) +{ + char * start; + char * colon; + + if (strncmp(path, kNetBootRootPathPrefixNFS, + strlen(kNetBootRootPathPrefixNFS)) != 0) { + return (FALSE); + } + + /* IP address */ + start = path + strlen(kNetBootRootPathPrefixNFS); + colon = strchr(start, ':'); + if (colon == NULL) { + return (FALSE); + } + *colon = '\0'; + if (inet_aton(start, iaddr_p) != 1) { + return (FALSE); + } + + /* mount point */ + start = colon + 1; + colon = find_colon(start); + *mount_dir = start; + if (colon == NULL) { + *image_path = NULL; + } + else { + /* image path */ + *colon = '\0'; + start = colon + 1; + (void)find_colon(start); + *image_path = start; + } + *host = inet_ntoa(*iaddr_p); + return (TRUE); +} + +static boolean_t +parse_image_path(char * path, struct in_addr * iaddr_p, char * * host, + char * * mount_dir, char * * image_path) +{ + if (path[0] >= '0' && path[0] <= '9') { + return (parse_booter_path(path, iaddr_p, host, mount_dir, + image_path)); + } + return (parse_netboot_path(path, iaddr_p, host, mount_dir, + image_path)); +} + +static boolean_t +get_root_path(char * root_path) +{ + void * entry; + boolean_t found = FALSE; + const void * pkt; + int pkt_len; + + entry = IOBSDRegistryEntryForDeviceTree("/chosen"); + if (entry == NULL) { + return (FALSE); + } + pkt = IOBSDRegistryEntryGetData(entry, BSDP_RESPONSE, &pkt_len); + if (pkt != NULL && pkt_len >= sizeof(struct dhcp)) { + printf("netboot: retrieving root path from BSDP response\n"); + } + else { + pkt = IOBSDRegistryEntryGetData(entry, BOOTP_RESPONSE, + &pkt_len); + if (pkt != NULL && pkt_len >= sizeof(struct dhcp)) { + printf("netboot: retrieving root path from BOOTP response\n"); + } + } + if (pkt != NULL) { + int len; + dhcpol_t options; + char * path; + struct dhcp * reply; + + reply = (struct dhcp *)pkt; + (void)dhcpol_parse_packet(&options, reply, pkt_len, NULL); + + path = (char *)dhcpol_find(&options, + dhcptag_root_path_e, &len, NULL); + if (path) { + bcopy(path, root_path, len); + root_path[len] = '\0'; + found = TRUE; + } + } + IOBSDRegistryEntryRelease(entry); + return (found); + +} + +static struct netboot_info * +netboot_info_init(struct in_addr iaddr) +{ + struct netboot_info * info; + char * root_path = NULL; + boolean_t use_hdix = TRUE; + char * vndevice = NULL; + + MALLOC_ZONE(vndevice, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK); + if (PE_parse_boot_arg("vndevice", vndevice) == TRUE) { + use_hdix = FALSE; + } + _FREE_ZONE(vndevice, MAXPATHLEN, M_NAMEI); + + info = (struct netboot_info *)kalloc(sizeof(*info)); + bzero(info, sizeof(*info)); + info->client_ip = iaddr; + info->image_type = kNetBootImageTypeUnknown; + info->use_hdix = use_hdix; + + /* check for a booter-specified path then a NetBoot path */ + MALLOC_ZONE(root_path, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK); + if (PE_parse_boot_arg("rp", root_path) == TRUE + || PE_parse_boot_arg("rootpath", root_path) == TRUE + || get_root_path(root_path) == TRUE) { + char * server_name = NULL; + char * mount_point = NULL; + char * image_path = NULL; + struct in_addr server_ip; + + if (parse_image_path(root_path, &server_ip, &server_name, + &mount_point, &image_path)) { + info->image_type = kNetBootImageTypeNFS; + info->server_ip = server_ip; + info->server_name_length = strlen(server_name) + 1; + info->server_name = (char *)kalloc(info->server_name_length); + info->mount_point_length = strlen(mount_point) + 1; + info->mount_point = (char *)kalloc(info->mount_point_length); + strcpy(info->server_name, server_name); + strcpy(info->mount_point, mount_point); + + printf("Server %s Mount %s", + server_name, info->mount_point); + if (image_path != NULL) { + boolean_t needs_slash; + + info->image_path_length = strlen(image_path) + 1; + if (image_path[0] != '/') { + needs_slash = TRUE; + info->image_path_length++; + } + info->image_path = (char *)kalloc(info->image_path_length); + if (needs_slash) { + info->image_path[0] = '/'; + strcpy(info->image_path + 1, image_path); + } + else { + strcpy(info->image_path, image_path); + } + printf(" Image %s", info->image_path); + } + printf("\n"); + } + else if (strncmp(root_path, kNetBootRootPathPrefixHTTP, + strlen(kNetBootRootPathPrefixHTTP)) == 0) { + /* only HDIX supports HTTP */ + info->image_type = kNetBootImageTypeHTTP; + info->use_hdix = TRUE; + info->image_path_length = strlen(root_path) + 1; + info->image_path = (char *)kalloc(info->image_path_length); + strcpy(info->image_path, root_path); + } + else { + printf("netboot: root path uses unrecognized format\n"); + } + } + _FREE_ZONE(root_path, MAXPATHLEN, M_NAMEI); + return (info); +} + +static void +netboot_info_free(struct netboot_info * * info_p) +{ + struct netboot_info * info = *info_p; + + if (info) { + if (info->mount_point) { + kfree(info->mount_point, info->mount_point_length); + } + if (info->server_name) { + kfree(info->server_name, info->server_name_length); + } + if (info->image_path) { + kfree(info->image_path, info->image_path_length); + } + kfree(info, sizeof(*info)); + } + *info_p = NULL; + return; +} + +boolean_t +netboot_iaddr(struct in_addr * iaddr_p) +{ + if (S_netboot_info_p == NULL) + return (FALSE); + + *iaddr_p = S_netboot_info_p->client_ip; + return (TRUE); +} + +boolean_t +netboot_rootpath(struct in_addr * server_ip, + char * name, int name_len, + char * path, int path_len) +{ + if (S_netboot_info_p == NULL) + return (FALSE); + + name[0] = '\0'; + path[0] = '\0'; + + if (S_netboot_info_p->mount_point_length == 0) { + return (FALSE); + } + if (path_len < S_netboot_info_p->mount_point_length) { + printf("netboot: path too small %d < %d\n", + path_len, S_netboot_info_p->mount_point_length); + return (FALSE); + } + strcpy(path, S_netboot_info_p->mount_point); + strncpy(name, S_netboot_info_p->server_name, name_len); + *server_ip = S_netboot_info_p->server_ip; + return (TRUE); +} + + +static boolean_t +get_ip_parameters(struct in_addr * iaddr_p, struct in_addr * netmask_p, + struct in_addr * router_p) +{ + void * entry; + const void * pkt; + int pkt_len; + + + entry = IOBSDRegistryEntryForDeviceTree("/chosen"); + if (entry == NULL) { + return (FALSE); + } + pkt = IOBSDRegistryEntryGetData(entry, DHCP_RESPONSE, &pkt_len); + if (pkt != NULL && pkt_len >= sizeof(struct dhcp)) { + printf("netboot: retrieving IP information from DHCP response\n"); + } + else { + pkt = IOBSDRegistryEntryGetData(entry, BOOTP_RESPONSE, &pkt_len); + if (pkt != NULL && pkt_len >= sizeof(struct dhcp)) { + printf("netboot: retrieving IP information from BOOTP response\n"); + } + } + if (pkt != NULL) { + struct in_addr * ip; + int len; + dhcpol_t options; + struct dhcp * reply; + + reply = (struct dhcp *)pkt; + (void)dhcpol_parse_packet(&options, reply, pkt_len, NULL); + *iaddr_p = reply->dp_yiaddr; + ip = (struct in_addr *) + dhcpol_find(&options, + dhcptag_subnet_mask_e, &len, NULL); + if (ip) { + *netmask_p = *ip; + } + ip = (struct in_addr *) + dhcpol_find(&options, dhcptag_router_e, &len, NULL); + if (ip) { + *router_p = *ip; + } + } + IOBSDRegistryEntryRelease(entry); + return (pkt != NULL); +} + +static int +inet_aifaddr(struct socket * so, char * name, const struct in_addr * addr, + const struct in_addr * mask, + const struct in_addr * broadcast) +{ + struct sockaddr blank_sin = { sizeof(blank_sin), AF_INET }; + struct ifaliasreq ifra; + + bzero(&ifra, sizeof(ifra)); + strncpy(ifra.ifra_name, name, sizeof(ifra.ifra_name)); + if (addr) { + ifra.ifra_addr = blank_sin; + ((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr = *addr; + } + if (mask) { + ifra.ifra_mask = blank_sin; + ((struct sockaddr_in *)&ifra.ifra_mask)->sin_addr = *mask; + } + if (broadcast) { + ifra.ifra_broadaddr = blank_sin; + ((struct sockaddr_in *)&ifra.ifra_broadaddr)->sin_addr = *broadcast; + } + return (ifioctl(so, SIOCAIFADDR, (caddr_t)&ifra, current_proc())); +} + +static int +default_route_add(struct in_addr router, boolean_t proxy_arp) +{ + struct sockaddr_in dst; + u_long flags = RTF_UP | RTF_STATIC; + struct sockaddr_in gw; + struct sockaddr_in mask; + + if (proxy_arp == FALSE) { + flags |= RTF_GATEWAY; + } + + /* dest 0.0.0.0 */ + bzero((caddr_t)&dst, sizeof(dst)); + dst.sin_len = sizeof(dst); + dst.sin_family = AF_INET; + + /* gateway */ + bzero((caddr_t)&gw, sizeof(gw)); + gw.sin_len = sizeof(gw); + gw.sin_family = AF_INET; + gw.sin_addr = router; + + /* mask 0.0.0.0 */ + bzero(&mask, sizeof(mask)); + mask.sin_len = sizeof(mask); + mask.sin_family = AF_INET; + + printf("netboot: adding default route " IP_FORMAT "\n", + IP_LIST(&router)); + + return (rtrequest(RTM_ADD, (struct sockaddr *)&dst, (struct sockaddr *)&gw, + (struct sockaddr *)&mask, flags, NULL)); +} + +static struct ifnet * +find_interface() +{ + struct ifnet * ifp = NULL; + + if (rootdevice[0]) { + ifp = ifunit(rootdevice); + } + if (ifp == NULL) { + TAILQ_FOREACH(ifp, &ifnet, if_link) + if ((ifp->if_flags & + (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0) + break; + } + return (ifp); +} + +int +netboot_mountroot() +{ + int error = 0; + struct in_addr iaddr = { 0 }; + struct ifreq ifr; + struct ifnet * ifp; + struct in_addr netmask = { 0 }; + struct proc * procp = current_proc(); + struct in_addr router = { 0 }; + struct socket * so = NULL; + + bzero(&ifr, sizeof(ifr)); + + thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); + + /* find the interface */ + ifp = find_interface(); + if (ifp == NULL) { + printf("netboot: no suitable interface\n"); + error = ENXIO; + goto failed; + } + sprintf(ifr.ifr_name, "%s%d", ifp->if_name, ifp->if_unit); + printf("netboot: using network interface '%s'\n", ifr.ifr_name); + + /* bring it up */ + if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0)) != 0) { + printf("netboot: socreate, error=%d\n", error); + goto failed; + } + ifr.ifr_flags = ifp->if_flags | IFF_UP; + error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)&ifr, procp); + if (error) { + printf("netboot: SIFFLAGS, error=%d\n", error); + goto failed; + } + + /* grab information from the registry */ + if (get_ip_parameters(&iaddr, &netmask, &router) == FALSE) { + /* use BOOTP to retrieve IP address, netmask and router */ + error = bootp(ifp, &iaddr, 32, &netmask, &router, procp); + if (error) { + printf("netboot: BOOTP failed %d\n", error); + goto failed; + } + } + printf("netboot: IP address " IP_FORMAT, IP_LIST(&iaddr)); + if (netmask.s_addr) { + printf(" netmask " IP_FORMAT, IP_LIST(&netmask)); + } + if (router.s_addr) { + printf(" router " IP_FORMAT, IP_LIST(&router)); + } + printf("\n"); + error = inet_aifaddr(so, ifr.ifr_name, &iaddr, &netmask, NULL); + if (error) { + printf("netboot: inet_aifaddr failed, %d\n", error); + goto failed; + } + if (router.s_addr == 0) { + /* enable proxy arp if we don't have a router */ + router.s_addr = iaddr.s_addr; + } + error = default_route_add(router, router.s_addr == iaddr.s_addr); + if (error) { + printf("netboot: default_route_add failed %d\n", error); + } + + soclose(so); + thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); + + S_netboot_info_p = netboot_info_init(iaddr); + switch (S_netboot_info_p->image_type) { + default: + case kNetBootImageTypeNFS: + error = nfs_mountroot(); + break; + case kNetBootImageTypeHTTP: + error = netboot_setup(procp); + break; + } + if (error == 0) { + S_netboot = 1; + } + else { + S_netboot = 0; + } + return (error); +failed: + if (so != NULL) { + soclose(so); + } + thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); + return (error); +} + +int +netboot_setup(struct proc * p) +{ + dev_t dev; + int error = 0; + + if (S_netboot_info_p == NULL + || S_netboot_info_p->image_path == NULL) { + goto done; + } + if (S_netboot_info_p->use_hdix) { + printf("netboot_setup: calling di_root_image\n"); + error = di_root_image(S_netboot_info_p->image_path, + rootdevice, &dev); + if (error) { + printf("netboot_setup: di_root_image: failed %d\n", error); + goto done; + } + } + else { + printf("netboot_setup: calling vndevice_root_image\n"); + error = vndevice_root_image(S_netboot_info_p->image_path, + rootdevice, &dev); + if (error) { + printf("netboot_setup: vndevice_root_image: failed %d\n", error); + goto done; + } + } + rootdev = dev; + mountroot = NULL; + printf("netboot: root device 0x%x\n", rootdev); + error = vfs_mountroot(); + if (error == 0 && rootvnode != NULL) { + struct vnode *tvp; + struct vnode *newdp; + + /* Get the vnode for '/'. Set fdp->fd_fd.fd_cdir to reference it. */ + if (VFS_ROOT(mountlist.cqh_last, &newdp)) + panic("netboot_setup: cannot find root vnode"); + VREF(newdp); + tvp = rootvnode; + vrele(tvp); + filedesc0.fd_cdir = newdp; + rootvnode = newdp; + simple_lock(&mountlist_slock); + CIRCLEQ_REMOVE(&mountlist, CIRCLEQ_FIRST(&mountlist), mnt_list); + simple_unlock(&mountlist_slock); + VOP_UNLOCK(rootvnode, 0, p); + mountlist.cqh_first->mnt_flag |= MNT_ROOTFS; + } + done: + netboot_info_free(&S_netboot_info_p); + return (error); +} + +int +netboot_root() +{ + return (S_netboot); +} diff --git a/bsd/kern/parallel.c b/bsd/kern/parallel.c deleted file mode 100644 index 2d93edd97..000000000 --- a/bsd/kern/parallel.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Mach Operating System - * Copyright (c) 1989 Carnegie-Mellon University - * Copyright (c) 1988 Carnegie-Mellon University - * Copyright (c) 1987 Carnegie-Mellon University - * All rights reserved. The CMU software License Agreement specifies - * the terms and conditions for use and redistribution. - */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:06:13 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.1.1.1 1997/09/30 02:44:39 wsanchez - * Import of kernel from umeshv/kernel - * - * Revision 2.4 89/12/22 15:52:48 rpd - * MACH_HOST support: when releasing master, context switch away - * immediately if thread is not assigned to default processor set. - * [89/11/16 dlb] - * - * Revision 2.3 89/10/11 14:19:20 dlb - * Processor logic - explicitly record bound processor in thread - * instead of changing whichq pointer. - * [88/09/30 dlb] - * - * Revision 2.2 89/02/25 18:07:24 gm0w - * Changes for cleanup. - * - * 15-Oct-87 David Golub (dbg) at Carnegie-Mellon University - * Use thread_bind (inline version) to bind thread to master cpu - * while holding unix-lock. - * - * 9-Oct-87 Robert Baron (rvb) at Carnegie-Mellon University - * Define unix_reset for longjmp/setjmp reset. - * - * 25-Sep-87 Robert Baron (rvb) at Carnegie-Mellon University - * Clean out some debugging code. - * - * 21-Sep-87 Robert Baron (rvb) at Carnegie-Mellon University - * Created. - * - */ - - -#include -#include - -#if NCPUS > 1 - -#include -#include -#include -#include - -void unix_master() -{ - register thread_t t = current_thread(); - - if (! (++( t->unix_lock ))) { - - /* thread_bind(t, master_processor); */ - t->bound_processor = master_processor; - - if (cpu_number() != master_cpu) { - t->interruptible = FALSE; - thread_block(0); - } - } -} - -void unix_release() -{ - register thread_t t = current_thread(); - - t->unix_lock--; - if (t->unix_lock < 0) { - /* thread_bind(t, PROCESSOR_NULL); */ - t->bound_processor = PROCESSOR_NULL; -#if MACH_HOST - if (t->processor_set != &default_pset) - thread_block(0); -#endif MACH_HOST - } -} - -void unix_reset() -{ - register thread_t t = current_thread(); - - if (t->unix_lock != -1) - t->unix_lock = 0; -} - -#endif NCPUS > 1 diff --git a/bsd/kern/parallel.h b/bsd/kern/parallel.h deleted file mode 100644 index 0538a4630..000000000 --- a/bsd/kern/parallel.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Mach Operating System - * Copyright (c) 1989 Carnegie-Mellon University - * Copyright (c) 1988 Carnegie-Mellon University - * Copyright (c) 1987 Carnegie-Mellon University - * All rights reserved. The CMU software License Agreement specifies - * the terms and conditions for use and redistribution. - */ -/* - * HISTORY - * Revision 1.1.1.1 1997/09/30 02:44:35 wsanchez - * Import of kernel from umeshv/kernel - * - * Revision 2.3 89/03/09 20:14:51 rpd - * More cleanup. - * - * Revision 2.2 89/02/25 18:07:31 gm0w - * Kernel code cleanup. - * Put entire file under #indef KERNEL. - * [89/02/15 mrt] - * - * 9-Oct-87 Robert Baron (rvb) at Carnegie-Mellon University - * Define unix_reset for longjmp/setjmp reset. - * - * 21-Sep-87 Robert Baron (rvb) at Carnegie-Mellon University - * Created. - * - */ - -#ifndef _KERN_PARALLEL_H_ -#define _KERN_PARALLEL_H_ - - -#define unix_master() -#define unix_release() -#define unix_reset() - - -#endif /* _KERN_PARALLEL_H_ */ diff --git a/bsd/kern/posix_sem.c b/bsd/kern/posix_sem.c index 3905e5299..05f946900 100644 --- a/bsd/kern/posix_sem.c +++ b/bsd/kern/posix_sem.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -24,7 +24,7 @@ * All Rights Reserved. */ /* - * posix_shm.c : Support for POSIX semaphore apis + * posix_shm.c : Support for POSIX semaphore APIs * * File: posix_sem.c * Author: Ananthakrishna Ramesh @@ -59,7 +59,6 @@ #include #include - #define PSEMNAMLEN 31 /* maximum name segment length we bother with */ struct pseminfo { @@ -123,17 +122,18 @@ u_long psemhash; /* size of hash table - 1 */ long psemnument; /* number of cache entries allocated */ struct psemstats psemstats; /* cache effectiveness statistics */ -int psem_cache_search __P((struct pseminfo **, struct psemname *, struct psemcache **)); +static int psem_cache_search __P((struct pseminfo **, + struct psemname *, struct psemcache **)); -int psem_read __P((struct file *fp, struct uio *uio, - struct ucred *cred)); -int psem_write __P((struct file *fp, struct uio *uio, - struct ucred *cred)); -int psem_ioctl __P((struct file *fp, u_long com, - caddr_t data, struct proc *p)); -int psem_select __P((struct file *fp, int which, - struct proc *p)); -int psem_closefile __P((struct file *fp, struct proc *p)); +static int psem_read __P((struct file *fp, struct uio *uio, + struct ucred *cred, int flags, struct proc *p)); +static int psem_write __P((struct file *fp, struct uio *uio, + struct ucred *cred, int flags, struct proc *p)); +static int psem_ioctl __P((struct file *fp, u_long com, + caddr_t data, struct proc *p)); +static int psem_select __P((struct file *fp, int which, void *wql, + struct proc *p)); +static int psem_closefile __P((struct file *fp, struct proc *p)); struct fileops psemops = { psem_read, psem_write, psem_ioctl, psem_select, psem_closefile }; @@ -148,7 +148,7 @@ struct fileops psemops = * fails, a status of zero is returned. */ -int +static int psem_cache_search(psemp, pnp, pcache) struct pseminfo **psemp; struct psemname *pnp; @@ -195,7 +195,7 @@ psem_cache_search(psemp, pnp, pcache) /* * Add an entry to the cache. */ -int +static int psem_cache_add(psemp, pnp) struct pseminfo *psemp; struct psemname *pnp; @@ -256,6 +256,21 @@ psem_cache_init() psemhashtbl = hashinit(desiredvnodes, M_SHM, &psemhash); } +static void +psem_cache_delete(pcp) + struct psemcache *pcp; +{ +#if DIAGNOSTIC + if (pcp->psem_hash.le_prev == 0) + panic("psem namecache purge le_prev"); + if (pcp->psem_hash.le_next == pcp) + panic("namecache purge le_next"); +#endif /* DIAGNOSTIC */ + LIST_REMOVE(pcp, psem_hash); + pcp->psem_hash.le_prev = 0; + psemnument--; +} + /* * Invalidate a all entries to particular vnode. * @@ -276,33 +291,18 @@ psem_cache_purge(void) } } -psem_cache_delete(pcp) - struct psemcache *pcp; -{ -#if DIAGNOSTIC - if (pcp->psem_hash.le_prev == 0) - panic("psem namecache purge le_prev"); - if (pcp->psem_hash.le_next == pcp) - panic("namecache purge le_next"); -#endif /* DIAGNOSTIC */ - LIST_REMOVE(pcp, psem_hash); - pcp->psem_hash.le_prev = 0; - psemnument--; -} - - struct sem_open_args { -const char *name; -int oflag; -int mode; -int value; + const char *name; + int oflag; + int mode; + int value; }; int sem_open(p, uap, retval) -struct proc *p; -register struct sem_open_args *uap; -register_t *retval; + struct proc *p; + register struct sem_open_args *uap; + register_t *retval; { register struct filedesc *fdp = p->p_fd; register struct file *fp; @@ -341,7 +341,6 @@ register_t *retval; goto bad; } - #ifdef PSXSEM_NAME_RESTRICT nameptr = pnbuf; if (*nameptr == '/') { @@ -475,10 +474,12 @@ bad: return (error); } - - int -psem_access(struct pseminfo *pinfo, int mode, struct ucred *cred, struct proc *p) +psem_access(pinfo, mode, cred, p) + struct pseminfo *pinfo; + int mode; + struct ucred *cred; + struct proc *p; { mode_t mask; register gid_t *gp; @@ -517,18 +518,15 @@ psem_access(struct pseminfo *pinfo, int mode, struct ucred *cred, struct proc *p return ((pinfo->psem_mode & mask) == mask ? 0 : EACCES); } - - - struct sem_unlink_args { -const char *name; + const char *name; }; int sem_unlink(p, uap, retval) -struct proc *p; -register struct sem_unlink_args *uap; -register_t *retval; + struct proc *p; + register struct sem_unlink_args *uap; + register_t *retval; { register struct filedesc *fdp = p->p_fd; register struct file *fp; @@ -628,7 +626,7 @@ bad: } struct sem_close_args { -sem_t *sem; + sem_t *sem; }; int @@ -651,12 +649,10 @@ sem_close(p, uap, retval) if( error = closef(fp, p)) return(error); return(0); - - } struct sem_wait_args { -sem_t *sem; + sem_t *sem; }; int @@ -699,17 +695,16 @@ sem_wait(p, uap, retval) default: return (EINVAL); } - } struct sem_trywait_args { -sem_t *sem; + sem_t *sem; }; int sem_trywait(p, uap, retval) struct proc *p; - struct sem_wait_args *uap; + struct sem_trywait_args *uap; register_t *retval; { int fd = (int)uap->sem; @@ -751,17 +746,16 @@ sem_trywait(p, uap, retval) default: return (EINVAL); } - } struct sem_post_args { -sem_t *sem; + sem_t *sem; }; int sem_post(p, uap, retval) struct proc *p; - struct sem_wait_args *uap; + struct sem_post_args *uap; register_t *retval; { int fd = (int)uap->sem; @@ -798,13 +792,12 @@ sem_post(p, uap, retval) default: return (EINVAL); } - } struct sem_init_args { -sem_t *sem; -int phsared; -unsigned int value; + sem_t *sem; + int phsared; + unsigned int value; }; int @@ -817,7 +810,7 @@ sem_init(p, uap, retval) } struct sem_destroy_args { -sem_t *sem; + sem_t *sem; }; int @@ -830,8 +823,8 @@ sem_destroy(p, uap, retval) } struct sem_getvalue_args { -sem_t *sem; -int * sval; + sem_t *sem; + int * sval; }; int @@ -843,18 +836,7 @@ sem_getvalue(p, uap, retval) return(ENOSYS); } -int -psem_closefile(fp, p) - struct file *fp; - struct proc *p; -{ - - return (psem_close(((struct psemnode *)fp->f_data), fp->f_flag, - fp->f_cred, p)); -} - - -int +static int psem_close(pnode, flags, cred, p) register struct psemnode *pnode; int flags; @@ -886,6 +868,16 @@ psem_close(pnode, flags, cred, p) return (error); } +static int +psem_closefile(fp, p) + struct file *fp; + struct proc *p; +{ + + return (psem_close(((struct psemnode *)fp->f_data), fp->f_flag, + fp->f_cred, p)); +} + int psem_delete(struct pseminfo * pinfo) { @@ -905,27 +897,46 @@ psem_delete(struct pseminfo * pinfo) default: return (EINVAL); } - } - -int -psem_read(struct file *fp, struct uio *uio, struct ucred *cred) +static int +psem_read(fp, uio, cred, flags, p) + struct file *fp; + struct uio *uio; + struct ucred *cred; + int flags; + struct proc *p; { return(EOPNOTSUPP); } -int -psem_write(struct file *fp, struct uio *uio, struct ucred *cred) + +static int +psem_write(fp, uio, cred, flags, p) + struct file *fp; + struct uio *uio; + struct ucred *cred; + int flags; + struct proc *p; { return(EOPNOTSUPP); } -int -psem_ioctl(struct file *fp, u_long com, caddr_t data, struct proc *p) + +static int +psem_ioctl(fp, com, data, p) + struct file *fp; + u_long com; + caddr_t data; + struct proc *p; { return(EOPNOTSUPP); } -int -psem_select(struct file *fp, int which, struct proc *p) + +static int +psem_select(fp, which, wql, p) + struct file *fp; + int which; + void *wql; + struct proc *p; { return(EOPNOTSUPP); } diff --git a/bsd/kern/posix_shm.c b/bsd/kern/posix_shm.c index c011cb3e5..1b25d26ac 100644 --- a/bsd/kern/posix_shm.c +++ b/bsd/kern/posix_shm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -24,7 +24,7 @@ * All Rights Reserved. */ /* - * posix_shm.c : Support for POSIX shared memory apis + * posix_shm.c : Support for POSIX shared memory APIs * * File: posix_shm.c * Author: Ananthakrishna Ramesh @@ -130,21 +130,19 @@ u_long pshmhash; /* size of hash table - 1 */ long pshmnument; /* number of cache entries allocated */ struct pshmstats pshmstats; /* cache effectiveness statistics */ -int pshm_read __P((struct file *fp, struct uio *uio, - struct ucred *cred)); -int pshm_write __P((struct file *fp, struct uio *uio, - struct ucred *cred)); -int pshm_ioctl __P((struct file *fp, u_long com, - caddr_t data, struct proc *p)); -int pshm_select __P((struct file *fp, int which, - struct proc *p)); -int pshm_closefile __P((struct file *fp, struct proc *p)); +static int pshm_read __P((struct file *fp, struct uio *uio, + struct ucred *cred, int flags, struct proc *p)); +static int pshm_write __P((struct file *fp, struct uio *uio, + struct ucred *cred, int flags, struct proc *p)); +static int pshm_ioctl __P((struct file *fp, u_long com, + caddr_t data, struct proc *p)); +static int pshm_select __P((struct file *fp, int which, void *wql, + struct proc *p)); +static int pshm_closefile __P((struct file *fp, struct proc *p)); struct fileops pshmops = { pshm_read, pshm_write, pshm_ioctl, pshm_select, pshm_closefile }; - - /* * Lookup an entry in the cache * @@ -299,16 +297,16 @@ pshm_cache_delete(pcp) struct shm_open_args { -const char *name; -int oflag; -int mode; + const char *name; + int oflag; + int mode; }; int shm_open(p, uap, retval) -struct proc *p; -register struct shm_open_args *uap; -register_t *retval; + struct proc *p; + register struct shm_open_args *uap; + register_t *retval; { register struct filedesc *fdp = p->p_fd; register struct file *fp; @@ -328,6 +326,7 @@ register_t *retval; int incache = 0; struct pshmnode * pnode = PSHMNODE_NULL; struct pshmcache * pcache = PSHMCACHE_NULL; + int pinfo_alloc=0; pinfo = PSHMINFO_NULL; @@ -399,12 +398,13 @@ register_t *retval; } #endif error = EEXIST; - goto bad; + goto bad1; } if (!incache) { /* create a new one */ pinfo = (struct pshminfo *)_MALLOC(sizeof(struct pshminfo), M_SHM, M_WAITOK); bzero(pinfo, sizeof(struct pshminfo)); + pinfo_alloc = 1; pinfo->pshm_flags = PSHM_DEFINED | PSHM_INCREATE; pinfo->pshm_usecount = 1; pinfo->pshm_mode = cmode; @@ -414,27 +414,27 @@ register_t *retval; /* already exists */ if( pinfo->pshm_flags & PSHM_INDELETE) { error = ENOENT; - goto bad; + goto bad1; } if (error = pshm_access(pinfo, fmode, p->p_ucred, p)) - goto bad; + goto bad1; } } else { if (!incache) { /* O_CREAT is not set and the shm obecj does not exist */ error = ENOENT; - goto bad; + goto bad1; } if( pinfo->pshm_flags & PSHM_INDELETE) { error = ENOENT; - goto bad; + goto bad1; } if (error = pshm_access(pinfo, fmode, p->p_ucred, p)) - goto bad; + goto bad1; } if (fmode & O_TRUNC) { error = EINVAL; - goto bad1; + goto bad2; } #if DIAGNOSTIC if (fmode & FWRITE) @@ -447,7 +447,7 @@ register_t *retval; if (!incache) { if (error = pshm_cache_add(pinfo, &nd)) { - goto bad2; + goto bad3; } } pinfo->pshm_flags &= ~PSHM_INCREATE; @@ -461,12 +461,15 @@ register_t *retval; *retval = indx; _FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI); return (0); -bad2: +bad3: _FREE(pnode, M_SHM); +bad2: + if (pinfo_alloc) + _FREE(pinfo, M_SHM); bad1: - _FREE(pinfo, M_SHM); - + fdrelse(p, indx); + ffree(nfp); bad: _FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI); return (error); @@ -594,6 +597,7 @@ pshm_access(struct pshminfo *pinfo, int mode, struct ucred *cred, struct proc *p mask |= S_IWOTH; return ((pinfo->pshm_mode & mask) == mask ? 0 : EACCES); } + struct mmap_args { caddr_t addr; size_t len; @@ -700,14 +704,14 @@ out: } struct shm_unlink_args { -const char *name; + const char *name; }; int shm_unlink(p, uap, retval) -struct proc *p; -register struct shm_unlink_args *uap; -register_t *retval; + struct proc *p; + register struct shm_unlink_args *uap; + register_t *retval; { register struct filedesc *fdp = p->p_fd; register struct file *fp; @@ -812,15 +816,6 @@ out: return (EINVAL); } } -int -pshm_closefile(fp, p) - struct file *fp; - struct proc *p; -{ - - return (pshm_close(((struct pshmnode *)fp->f_data), fp->f_flag, - fp->f_cred, p)); -} int pshm_close(pnode, flags, cred, p) @@ -852,23 +847,54 @@ pshm_close(pnode, flags, cred, p) _FREE(pnode, M_SHM); return (error); } -int -pshm_read(struct file *fp, struct uio *uio, struct ucred *cred) + +static int +pshm_closefile(fp, p) + struct file *fp; + struct proc *p; +{ + return (pshm_close(((struct pshmnode *)fp->f_data), fp->f_flag, + fp->f_cred, p)); +} + +static int +pshm_read(fp, uio, cred, flags, p) + struct file *fp; + struct uio *uio; + struct ucred *cred; + int flags; + struct proc *p; { return(EOPNOTSUPP); } -int -pshm_write(struct file *fp, struct uio *uio, struct ucred *cred) + +static int +pshm_write(fp, uio, cred, flags, p) + struct file *fp; + struct uio *uio; + struct ucred *cred; + int flags; + struct proc *p; { return(EOPNOTSUPP); } -int -pshm_ioctl(struct file *fp, u_long com, caddr_t data, struct proc *p) + +static int +pshm_ioctl(fp, com, data, p) + struct file *fp; + u_long com; + caddr_t data; + struct proc *p; { return(EOPNOTSUPP); } -int -pshm_select(struct file *fp, int which, struct proc *p) + +static int +pshm_select(fp, which, wql, p) + struct file *fp; + int which; + void *wql; + struct proc *p; { return(EOPNOTSUPP); } diff --git a/bsd/kern/subr_disk.c b/bsd/kern/subr_disk.c deleted file mode 100644 index d40c94295..000000000 --- a/bsd/kern/subr_disk.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ -/* - * Copyright (c) 1982, 1986, 1988, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, 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. - * - * @(#)ufs_disksubr.c 8.5 (Berkeley) 1/21/94 - */ - -#include -#include -#include -#include -#include - -/* - * Seek sort for disks. We depend on the driver which calls us using b_resid - * as the current cylinder number. - * - * The argument ap structure holds a b_actf activity chain pointer on which we - * keep two queues, sorted in ascending cylinder order. The first queue holds - * those requests which are positioned after the current cylinder (in the first - * request); the second holds requests which came in after their cylinder number - * was passed. Thus we implement a one way scan, retracting after reaching the - * end of the drive to the first request on the second queue, at which time it - * becomes the first queue. - * - * A one-way scan is natural because of the way UNIX read-ahead blocks are - * allocated. - */ - -/* - * For portability with historic industry practice, the - * cylinder number has to be maintained in the `b_resid' - * field. - */ -#define b_cylinder b_resid - -void -disksort(ap, bp) - register struct buf *ap, *bp; -{ - register struct buf *bq; - - /* If the queue is empty, then it's easy. */ - if (ap->b_actf == NULL) { - bp->b_actf = NULL; - ap->b_actf = bp; - return; - } - - /* - * If we lie after the first (currently active) request, then we - * must locate the second request list and add ourselves to it. - */ - bq = ap->b_actf; - if (bp->b_cylinder < bq->b_cylinder) { - while (bq->b_actf) { - /* - * Check for an ``inversion'' in the normally ascending - * cylinder numbers, indicating the start of the second - * request list. - */ - if (bq->b_actf->b_cylinder < bq->b_cylinder) { - /* - * Search the second request list for the first - * request at a larger cylinder number. We go - * before that; if there is no such request, we - * go at end. - */ - do { - if (bp->b_cylinder < - bq->b_actf->b_cylinder) - goto insert; - if (bp->b_cylinder == - bq->b_actf->b_cylinder && - bp->b_blkno < bq->b_actf->b_blkno) - goto insert; - bq = bq->b_actf; - } while (bq->b_actf); - goto insert; /* after last */ - } - bq = bq->b_actf; - } - /* - * No inversions... we will go after the last, and - * be the first request in the second request list. - */ - goto insert; - } - /* - * Request is at/after the current request... - * sort in the first request list. - */ - while (bq->b_actf) { - /* - * We want to go after the current request if there is an - * inversion after it (i.e. it is the end of the first - * request list), or if the next request is a larger cylinder - * than our request. - */ - if (bq->b_actf->b_cylinder < bq->b_cylinder || - bp->b_cylinder < bq->b_actf->b_cylinder || - (bp->b_cylinder == bq->b_actf->b_cylinder && - bp->b_blkno < bq->b_actf->b_blkno)) - goto insert; - bq = bq->b_actf; - } - /* - * Neither a second list nor a larger request... we go at the end of - * the first list, which is the same as the end of the whole schebang. - */ -insert: bp->b_actf = bq->b_actf; - bq->b_actf = bp; -} - -/* encoding of disk minor numbers, should be elsewhere... */ -#define dkunit(dev) (minor(dev) >> 3) -#define dkpart(dev) (minor(dev) & 07) -#define dkminor(unit, part) (((unit) << 3) | (part)) - -/* - * Compute checksum for disk label. - */ -u_int -dkcksum(lp) - register struct disklabel *lp; -{ - register u_short *start, *end; - register u_short sum = 0; - - start = (u_short *)lp; - end = (u_short *)&lp->d_partitions[lp->d_npartitions]; - while (start < end) - sum ^= *start++; - return (sum); -} - -/* - * Disk error is the preface to plaintive error messages - * about failing disk transfers. It prints messages of the form - -hp0g: hard error reading fsbn 12345 of 12344-12347 (hp0 bn %d cn %d tn %d sn %d) - - * if the offset of the error in the transfer and a disk label - * are both available. blkdone should be -1 if the position of the error - * is unknown; the disklabel pointer may be null from drivers that have not - * been converted to use them. The message is printed with printf - * if pri is LOG_PRINTF, otherwise it uses log at the specified priority. - * The message should be completed (with at least a newline) with printf - * or addlog, respectively. There is no trailing space. - */ -void -diskerr(bp, dname, what, pri, blkdone, lp) - register struct buf *bp; - char *dname, *what; - int pri, blkdone; - register struct disklabel *lp; -{ - int unit = dkunit(bp->b_dev), part = dkpart(bp->b_dev); - register void (*pr) __P((const char *, ...)); - char partname = 'a' + part; - int sn; - - if (pri != LOG_PRINTF) { - log(pri, ""); - pr = addlog; - } else - pr = printf; - (*pr)("%s%d%c: %s %sing fsbn ", dname, unit, partname, what, - bp->b_flags & B_READ ? "read" : "writ"); - sn = bp->b_blkno; - if (bp->b_bcount <= DEV_BSIZE) - (*pr)("%d", sn); - else { - if (blkdone >= 0) { - sn += blkdone; - (*pr)("%d of ", sn); - } - (*pr)("%d-%d", bp->b_blkno, - bp->b_blkno + (bp->b_bcount - 1) / DEV_BSIZE); - } - if (lp && (blkdone >= 0 || bp->b_bcount <= lp->d_secsize)) { -#ifdef tahoe - sn *= DEV_BSIZE / lp->d_secsize; /* XXX */ -#endif - sn += lp->d_partitions[part].p_offset; - (*pr)(" (%s%d bn %d; cn %d", dname, unit, sn, - sn / lp->d_secpercyl); - sn %= lp->d_secpercyl; - (*pr)(" tn %d sn %d)", sn / lp->d_nsectors, sn % lp->d_nsectors); - } -} diff --git a/bsd/kern/subr_log.c b/bsd/kern/subr_log.c index 6f78c5d10..4a4a9a06a 100644 --- a/bsd/kern/subr_log.c +++ b/bsd/kern/subr_log.c @@ -69,10 +69,6 @@ #include #include #include -#if 0 /* [ */ -#include -#include -#endif /* 0 ] */ #define LOG_RDPRI (PZERO + 1) @@ -107,11 +103,9 @@ logopen(dev, flags, mode, p) int flags, mode; struct proc *p; { - unix_master(); /* for pg_id, sigh */ LOG_LOCK(); if (log_open) { LOG_UNLOCK(); - unix_release(); return (EBUSY); } log_open = 1; @@ -130,7 +124,7 @@ logopen(dev, flags, mode, p) msgbufp->msg_bufc[i] = 0; } LOG_UNLOCK(); - unix_release(); + return (0); } @@ -235,7 +229,6 @@ logwakeup() funnel_state = thread_funnel_set(kernel_flock, TRUE); selwakeup(&logsoftc.sc_selp); if (logsoftc.sc_state & LOG_ASYNC) { - unix_master(); LOG_LOCK(); pgid = logsoftc.sc_pgid; LOG_UNLOCK(); @@ -243,7 +236,6 @@ logwakeup() gsignal(-pgid, SIGIO); else if (p = pfind(pgid)) psignal(p, SIGIO); - unix_release(); } if (logsoftc.sc_state & LOG_RDWAIT) { wakeup((caddr_t)msgbufp); diff --git a/bsd/kern/subr_prf.c b/bsd/kern/subr_prf.c index 814ac7056..68867e8ea 100644 --- a/bsd/kern/subr_prf.c +++ b/bsd/kern/subr_prf.c @@ -90,7 +90,6 @@ #include #include #include -#include #include #include /* for cpu_number() */ @@ -115,6 +114,11 @@ int (*v_putc)() = cnputc; /* routine to putc on virtual console */ extern struct tty cons; /* standard console tty */ extern struct tty *constty; /* pointer to console "window" tty */ +extern int __doprnt(const char *fmt, + va_list *argp, + void (*putc)(int, void *arg), + void *arg, + int radix); /* * Record cpu that panic'd and lock around panic data @@ -132,11 +136,16 @@ boolean_t new_printf_cpu_number; /* do we need to output who we are */ extern void logwakeup(); extern void halt_cpu(); extern boot(); -int putchar(); + static void snprintf_func(int ch, void *arg); +struct putchar_args { + int flags; + struct tty *tty; +}; +static void putchar(int c, void *arg); /* @@ -148,28 +157,27 @@ void uprintf(const char *fmt, ...) { register struct proc *p = current_proc(); + struct putchar_args pca; va_list ap; + + pca.flags = TOTTY; + pca.tty = (struct tty *)p->p_session->s_ttyp; - unix_master(); /* sessions, sigh */ if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) { va_start(ap, fmt); - prf(fmt, ap, TOTTY, (struct tty *)p->p_session->s_ttyvp); + __doprnt(fmt, &ap, putchar, &pca, 10); va_end(ap); } - unix_release(); } tpr_t tprintf_open(p) register struct proc *p; { - unix_master(); /* sessions, sigh */ if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) { SESSHOLD(p->p_session); - unix_release(); return ((tpr_t) p->p_session); } - unix_release(); return ((tpr_t) NULL); } @@ -177,10 +185,8 @@ void tprintf_close(sess) tpr_t sess; { - unix_master(); /* sessions, sigh */ if (sess) SESSRELE((struct session *) sess); - unix_release(); } /* @@ -194,19 +200,21 @@ tprintf(tpr_t tpr, const char *fmt, ...) struct tty *tp = NULL; int flags = TOLOG; va_list ap; + struct putchar_args pca; logpri(LOG_INFO); - unix_master(); /* sessions, sigh */ if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) { flags |= TOTTY; tp = sess->s_ttyp; } if (tp != NULL) { + pca.flags = TOTTY; + pca.tty = tp; + va_start(ap, fmt); - prf(fmt, ap, TOTTY, tp); + __doprnt(fmt, &ap, putchar, &pca, 10); va_end(ap); } - unix_release(); logwakeup(); } @@ -221,8 +229,12 @@ ttyprintf(struct tty *tp, const char *fmt, ...) va_list ap; if (tp != NULL) { + struct putchar_args pca; + pca.flags = TOTTY; + pca.tty = tp; + va_start(ap, fmt); - prf(fmt, ap, TOTTY, tp); + __doprnt(fmt, &ap, putchar, &pca, 10); va_end(ap); } } @@ -234,10 +246,13 @@ void logpri(level) int level; { - - putchar('<', TOLOG, (struct tty *)0); + struct putchar_args pca; + pca.flags = TOLOG; + pca.tty = NULL; + + putchar('<', &pca); printn((u_long)level, 10, TOLOG, (struct tty *)0, 0, 0); - putchar('>', TOLOG, (struct tty *)0); + putchar('>', &pca); } void @@ -245,256 +260,82 @@ addlog(const char *fmt, ...) { register s = splhigh(); va_list ap; + struct putchar_args pca; + + pca.flags = TOLOG; + pca.tty = NULL; va_start(ap, fmt); - prf(fmt, ap, TOLOG, (struct tty *)0); + __doprnt(fmt, &ap, putchar, &pca, 10); + splx(s); - if (!log_open) - prf(fmt, ap, TOCONS, (struct tty *)0); + if (!log_open) { + pca.flags = TOCONS; + __doprnt(fmt, &ap, putchar, &pca, 10); + } va_end(ap); logwakeup(); } void _printf(int flags, struct tty *ttyp, const char *format, ...) { va_list ap; + struct putchar_args pca; + + pca.flags = flags; + pca.tty = ttyp; va_start(ap, format); - prf(format, ap, flags, ttyp); + __doprnt(format, &ap, putchar, &pca, 10); va_end(ap); } int prf(const char *fmt, va_list ap, int flags, struct tty *ttyp) { - register int b, c, i; - char *s; - int any; - int zf = 0, fld_size; - -#if NCPUS > 1 - int cpun = cpu_number(); + struct putchar_args pca; - if(ttyp == 0) { - simple_lock(&printf_lock); + pca.flags = flags; + pca.tty = ttyp; + +#if NCPUS > 1 + int cpun = cpu_number(); + + if(ttyp == 0) { + simple_lock(&printf_lock); } else TTY_LOCK(ttyp); - + if (cpun != master_cpu) - new_printf_cpu_number = TRUE; + new_printf_cpu_number = TRUE; if (new_printf_cpu_number) { putchar('{', flags, ttyp); printn((u_long)cpun, 10, flags, ttyp, 0, 0); putchar('}', flags, ttyp); } -#endif /* NCPUS > 1 */ -loop: - while ((c = *fmt++) != '%') { - if (c == '\0') { -#if NCPUS > 1 - if(ttyp == 0) { - simple_unlock(&printf_lock); - } else - TTY_UNLOCK(ttyp); -#endif - return 0; - } - putchar(c, flags, ttyp); - } -again: - zf = 0; - fld_size = 0; - c = *fmt++; - if (c == '0') - zf = '0'; - fld_size = 0; - for (;c <= '9' && c >= '0'; c = *fmt++) - fld_size = fld_size * 10 + c - '0'; - - /* THIS CODE IS VAX DEPENDENT IN HANDLING %l? AND %c */ - switch (c) { - - case 'l': - goto again; - case 'x': case 'X': - b = 16; - goto number; - case 'd': case 'D': - case 'u': /* what a joke */ - b = 10; - goto number; - case 'o': case 'O': - b = 8; -number: - printn(va_arg(ap, unsigned), b, flags, ttyp, zf, fld_size); - break; - case 'c': - b = va_arg(ap, unsigned); -#if BYTE_ORDER == LITTLE_ENDIAN - for (i = 24; i >= 0; i -= 8) - if (c = (b >> i) & 0x7f) - putchar(c, flags, ttyp); -#endif -#if BYTE_ORDER == BIG_ENDIAN - if ((c = (b & 0x7f))) - putchar(c, flags, ttyp); -#endif - break; - case 'b': - b = va_arg(ap, unsigned); - s = va_arg(ap, char *); - printn((u_long)b, *s++, flags, ttyp, 0, 0); - any = 0; - if (b) { - while ((i = *s++)) { - if (*s <= 32) { - register int j; - - if (any++) - putchar(',', flags, ttyp); - j = *s++ ; - for (; (c = *s) > 32 ; s++) - putchar(c, flags, ttyp); - printn( (u_long)( (b >> (j-1)) & - ( (2 << (i-j)) -1)), - 8, flags, ttyp, 0, 0); - } else if (b & (1 << (i-1))) { - putchar(any? ',' : '<', flags, ttyp); - any = 1; - for (; (c = *s) > 32; s++) - putchar(c, flags, ttyp); - } else - for (; *s > 32; s++) - ; - } - putchar('>', flags, ttyp); - } - break; - - case 's': - s = va_arg(ap, char *); -#ifdef DEBUG - if (fld_size) { - while (fld_size-- > 0) - putchar((c = *s++)? c : '_', flags, ttyp); - } else { - while ((c = *s++)) - putchar(c, flags, ttyp); - } -#else - while (c = *s++) - putchar(c, flags, ttyp); -#endif - break; - - case '%': - putchar('%', flags, ttyp); - goto loop; - case 'C': - b = va_arg(ap, unsigned); -#if BYTE_ORDER == LITTLE_ENDIAN - for (i = 24; i >= 0; i -= 8) - if (c = (b >> i) & 0x7f) - putchar(c, flags, ttyp); -#endif -#if BYTE_ORDER == BIG_ENDIAN - if ((c = (b & 0x7f))) - putchar(c, flags, ttyp); -#endif +#endif /* NCPUS > 1 */ + + __doprnt(fmt, &ap, putchar, &pca, 10); - case 'r': - case 'R': - b = va_arg(ap, unsigned); - s = va_arg(ap, char *); - if (c == 'R') { - puts("0x", flags, ttyp); - printn((u_long)b, 16, flags, ttyp, 0, 0); - } - any = 0; - if (c == 'r' || b) { - register struct reg_desc *rd; - register struct reg_values *rv; - unsigned field; - - putchar('<', flags, ttyp); - for (rd = (struct reg_desc *)s; rd->rd_mask; rd++) { - field = b & rd->rd_mask; - field = (rd->rd_shift > 0) - ? field << rd->rd_shift - : field >> -rd->rd_shift; - if (any && - (rd->rd_format || rd->rd_values - || (rd->rd_name && field) - ) - ) - putchar(',', flags, ttyp); - if (rd->rd_name) { - if (rd->rd_format || rd->rd_values - || field) { - puts(rd->rd_name, flags, ttyp); - any = 1; - } - if (rd->rd_format || rd->rd_values) { - putchar('=', flags, ttyp); - any = 1; - } - } - if (rd->rd_format) { - _printf(flags, ttyp, rd->rd_format, - field); - any = 1; - if (rd->rd_values) - putchar(':', flags, ttyp); - } - if (rd->rd_values) { - any = 1; - for (rv = rd->rd_values; - rv->rv_name; - rv++) { - if (field == rv->rv_value) { - puts(rv->rv_name, flags, - ttyp); - break; - } - } - if (rv->rv_name == NULL) - puts("???", flags, ttyp); - } - } - putchar('>', flags, ttyp); - } - break; - - case 'n': - case 'N': - { - register struct reg_values *rv; - - b = va_arg(ap, unsigned); - s = va_arg(ap,char *); - for (rv = (struct reg_values *)s; rv->rv_name; rv++) { - if (b == rv->rv_value) { - puts(rv->rv_name, flags, ttyp); - break; - } - } - if (rv->rv_name == NULL) - puts("???", flags, ttyp); - if (c == 'N' || rv->rv_name == NULL) { - putchar(':', flags, ttyp); - printn((u_long)b, 10, flags, ttyp, 0, 0); - } - } - break; - } - goto loop; +#if NCPUS > 1 + if(ttyp == 0) { + simple_unlock(&printf_lock); + } else + TTY_UNLOCK(ttyp); +#endif + + return 0; } static void puts(const char *s, int flags, struct tty *ttyp) { register char c; + struct putchar_args pca; + + pca.flags = flags; + pca.tty = ttyp; while ((c = *s++)) - putchar(c, flags, ttyp); + putchar(c, &pca); } /* @@ -505,9 +346,13 @@ static void printn(u_long n, int b, int flags, struct tty *ttyp, int zf, int fld { char prbuf[11]; register char *cp; + struct putchar_args pca; + + pca.flags = flags; + pca.tty = ttyp; if (b == 10 && (int)n < 0) { - putchar('-', flags, ttyp); + putchar('-', &pca); n = (unsigned)(-(int)n); } cp = prbuf; @@ -518,12 +363,12 @@ static void printn(u_long n, int b, int flags, struct tty *ttyp, int zf, int fld if (fld_size) { for (fld_size -= cp - prbuf; fld_size > 0; fld_size--) if (zf) - putchar('0', flags, ttyp); + putchar('0', &pca); else - putchar(' ', flags, ttyp); + putchar(' ', &pca); } do - putchar(*--cp, flags, ttyp); + putchar(*--cp, &pca); while (cp > prbuf); } @@ -543,32 +388,30 @@ void tablefull(const char *tab) * are saved in msgbuf for inspection later. */ /*ARGSUSED*/ -int -putchar(c, flags, tp) - register int c; - struct tty *tp; +void +putchar(int c, void *arg) { + struct putchar_args *pca = arg; register struct msgbuf *mbp; - char **sp = (char**) tp; + char **sp = (char**) pca->tty; if (panicstr) constty = 0; - if ((flags & TOCONS) && tp == NULL && constty) { - tp = constty; - flags |= TOTTY; + if ((pca->flags & TOCONS) && pca->tty == NULL && constty) { + pca->tty = constty; + pca->flags |= TOTTY; } - if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 && - (flags & TOCONS) && tp == constty) + if ((pca->flags & TOTTY) && pca->tty && tputchar(c, pca->tty) < 0 && + (pca->flags & TOCONS) && pca->tty == constty) constty = 0; - if ((flags & TOLOG) && c != '\0' && c != '\r' && c != 0177) + if ((pca->flags & TOLOG) && c != '\0' && c != '\r' && c != 0177) log_putc(c); - if ((flags & TOCONS) && constty == 0 && c != '\0') + if ((pca->flags & TOCONS) && constty == 0 && c != '\0') (*v_putc)(c); - if (flags & TOSTR) { + if (pca->flags & TOSTR) { **sp = c; (*sp)++; } - return 0; } @@ -580,10 +423,16 @@ int vsprintf(char *buf, const char *cfmt, va_list ap) { int retval; + struct snprintf_arg info; - retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); - buf[retval] = '\0'; - return retval; + info.str = buf; + info.remain = 999999; + + retval = __doprnt(cfmt, &ap, snprintf_func, &info, 10); + if (info.remain >= 1) { + *info.str++ = '\0'; + } + return 0; } /* @@ -612,7 +461,7 @@ vsnprintf(char *str, size_t size, const char *format, va_list ap) info.str = str; info.remain = size; - retval = kvprintf(format, snprintf_func, &info, 10, ap); + retval = __doprnt(format, &ap, snprintf_func, &info, 10); if (info.remain >= 1) *info.str++ = '\0'; return retval; @@ -629,274 +478,10 @@ snprintf_func(int ch, void *arg) } } -/* - * Put a number (base <= 16) in a buffer in reverse order; return an - * optional length and a pointer to the NULL terminated (preceded?) - * buffer. - */ -static char * -ksprintn(ul, base, lenp) - register u_long ul; - register int base, *lenp; -{ /* A long in base 8, plus NULL. */ - static char buf[sizeof(long) * NBBY / 3 + 2]; - register char *p; - - p = buf; - do { - *++p = hex2ascii(ul % base); - } while (ul /= base); - if (lenp) - *lenp = p - buf; - return (p); -} - -/* - * Scaled down version of printf(3). - * - * Two additional formats: - * - * The format %b is supported to decode error registers. - * Its usage is: - * - * printf("reg=%b\n", regval, "*"); - * - * where is the output base expressed as a control character, e.g. - * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, - * the first of which gives the bit number to be inspected (origin 1), and - * the next characters (up to a control character, i.e. a character <= 32), - * give the name of the register. Thus: - * - * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); - * - * would produce output: - * - * reg=3 - * - * XXX: %D -- Hexdump, takes pointer and separator string: - * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX - * ("%*D", len, ptr, " " -> XX XX XX XX ... - */ int kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap) { -#define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; } - char *p, *q, *d; - u_char *up; - int ch, n; - u_long ul; - int base, lflag, tmp, width, ladjust, sharpflag, neg, sign, dot; - int dwidth; - char padc; - int retval = 0; - - if (!func) - d = (char *) arg; - else - d = NULL; - - if (fmt == NULL) - fmt = "(fmt null)\n"; - - if (radix < 2 || radix > 36) - radix = 10; - - for (;;) { - padc = ' '; - width = 0; - while ((ch = (u_char)*fmt++) != '%') { - if (ch == '\0') - return retval; - PCHAR(ch); - } - lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; - sign = 0; dot = 0; dwidth = 0; -reswitch: switch (ch = (u_char)*fmt++) { - case '.': - dot = 1; - goto reswitch; - case '#': - sharpflag = 1; - goto reswitch; - case '+': - sign = 1; - goto reswitch; - case '-': - ladjust = 1; - goto reswitch; - case '%': - PCHAR(ch); - break; - case '*': - if (!dot) { - width = va_arg(ap, int); - if (width < 0) { - ladjust = !ladjust; - width = -width; - } - } else { - dwidth = va_arg(ap, int); - } - goto reswitch; - case '0': - if (!dot) { - padc = '0'; - goto reswitch; - } - case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - for (n = 0;; ++fmt) { - n = n * 10 + ch - '0'; - ch = *fmt; - if (ch < '0' || ch > '9') - break; - } - if (dot) - dwidth = n; - else - width = n; - goto reswitch; - case 'b': - ul = va_arg(ap, int); - p = va_arg(ap, char *); - for (q = ksprintn(ul, *p++, NULL); *q;) - PCHAR(*q--); - - if (!ul) - break; - - for (tmp = 0; *p;) { - n = *p++; - if (ul & (1 << (n - 1))) { - PCHAR(tmp ? ',' : '<'); - for (; (n = *p) > ' '; ++p) - PCHAR(n); - tmp = 1; - } else - for (; *p > ' '; ++p) - continue; - } - if (tmp) - PCHAR('>'); - break; - case 'c': - PCHAR(va_arg(ap, int)); - break; - case 'D': - up = va_arg(ap, u_char *); - p = va_arg(ap, char *); - if (!width) - width = 16; - while(width--) { - PCHAR(hex2ascii(*up >> 4)); - PCHAR(hex2ascii(*up & 0x0f)); - up++; - if (width) - for (q=p;*q;q++) - PCHAR(*q); - } - break; - case 'd': - ul = lflag ? va_arg(ap, long) : va_arg(ap, int); - sign = 1; - base = 10; - goto number; - case 'l': - lflag = 1; - goto reswitch; - case 'o': - ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); - base = 8; - goto nosign; - case 'p': - ul = (uintptr_t)va_arg(ap, void *); - base = 16; - sharpflag = (width == 0); - goto nosign; - case 'n': - case 'r': - ul = lflag ? va_arg(ap, u_long) : - sign ? (u_long)va_arg(ap, int) : va_arg(ap, u_int); - base = radix; - goto number; - case 's': - p = va_arg(ap, char *); - if (p == NULL) - p = "(null)"; - if (!dot) - n = strlen (p); - else - for (n = 0; n < dwidth && p[n]; n++) - continue; - - width -= n; - - if (!ladjust && width > 0) - while (width--) - PCHAR(padc); - while (n--) - PCHAR(*p++); - if (ladjust && width > 0) - while (width--) - PCHAR(padc); - break; - case 'u': - ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); - base = 10; - goto nosign; - case 'x': - ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); - base = 16; - goto nosign; - case 'z': - ul = lflag ? va_arg(ap, u_long) : - sign ? (u_long)va_arg(ap, int) : va_arg(ap, u_int); - base = 16; - goto number; -nosign: sign = 0; -number: if (sign && (long)ul < 0L) { - neg = 1; - ul = -(long)ul; - } - p = ksprintn(ul, base, &tmp); - if (sharpflag && ul != 0) { - if (base == 8) - tmp++; - else if (base == 16) - tmp += 2; - } - if (neg) - tmp++; - - if (!ladjust && width && (width -= tmp) > 0) - while (width--) - PCHAR(padc); - if (neg) - PCHAR('-'); - if (sharpflag && ul != 0) { - if (base == 8) { - PCHAR('0'); - } else if (base == 16) { - PCHAR('0'); - PCHAR('x'); - } - } - - while (*p) - PCHAR(*p--); - - if (ladjust && width && (width -= tmp) > 0) - while (width--) - PCHAR(padc); - - break; - default: - PCHAR('%'); - if (lflag) - PCHAR('l'); - PCHAR(ch); - break; - } - } -#undef PCHAR + __doprnt(fmt, &ap, func, arg, radix); + return 0; } + diff --git a/bsd/kern/subr_prof.c b/bsd/kern/subr_prof.c index ed0455eeb..2fcd135c7 100644 --- a/bsd/kern/subr_prof.c +++ b/bsd/kern/subr_prof.c @@ -123,7 +123,8 @@ kmstartup() /* * Return kernel profiling information. */ -sysctl_doprof(name, namelen, oldp, oldlenp, newp, newlen, p) +int +sysctl_doprof(name, namelen, oldp, oldlenp, newp, newlen) int *name; u_int namelen; void *oldp; diff --git a/bsd/kern/sys_domain.c b/bsd/kern/sys_domain.c index 1f6cd83af..ab3f62847 100644 --- a/bsd/kern/sys_domain.c +++ b/bsd/kern/sys_domain.c @@ -29,10 +29,21 @@ #include #include #include +#include -extern struct protosw eventsw; +/* domain init function */ +void systemdomain_init(); + struct domain systemdomain = - { PF_SYSTEM, "system", 0, 0, 0, - &eventsw}; + { PF_SYSTEM, "system", systemdomain_init, 0, 0, 0}; + + +void systemdomain_init() +{ + /* add system domain built in protocol initializers here */ + + kern_event_init(); + kern_control_init(); +} diff --git a/bsd/kern/sys_generic.c b/bsd/kern/sys_generic.c index ad99a98d0..e02a30b86 100644 --- a/bsd/kern/sys_generic.c +++ b/bsd/kern/sys_generic.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -72,10 +72,6 @@ #include #include -#if KTRACE -#include -#endif - #include #include #include @@ -107,37 +103,167 @@ #include /* for wait queue based select */ #include +#if KTRACE +#include +#endif + +static int dofileread __P((struct proc *, struct file *, int, void *, + size_t, off_t, int, int*)); +static int dofilewrite __P((struct proc *, struct file *, int, + const void *, size_t, off_t, int, int*)); + +static struct file* +holdfp(fdp, fd, flag) + struct filedesc* fdp; + int fd, flag; +{ + struct file* fp; + + if (((u_int)fd) >= fdp->fd_nfiles || + (fp = fdp->fd_ofiles[fd]) == NULL || + (fp->f_flag & flag) == 0) { + return (NULL); + } + fref(fp); + return (fp); +} /* * Read system call. */ +#ifndef _SYS_SYSPROTO_H_ struct read_args { int fd; char *cbuf; u_int nbyte; }; -/* ARGSUSED */ +#endif +int read(p, uap, retval) struct proc *p; register struct read_args *uap; register_t *retval; +{ + register struct file *fp; + int error; + + if ((fp = holdfp(p->p_fd, uap->fd, FREAD)) == NULL) + return (EBADF); + error = dofileread(p, fp, uap->fd, uap->cbuf, uap->nbyte, + (off_t)-1, 0, retval); + frele(fp); + return(error); +} + +/* + * Pread system call + */ +#ifndef _SYS_SYSPROTO_H_ +struct pread_args { + int fd; + void *buf; + size_t nbyte; +#ifdef DOUBLE_ALIGN_PARAMS + int pad; +#endif + off_t offset; +}; +#endif +int +pread(p, uap, retval) + struct proc *p; + register struct pread_args *uap; + int *retval; +{ + register struct file *fp; + int error; + + if ((fp = holdfp(p->p_fd, uap->fd, FREAD)) == NULL) + return (EBADF); + if (fp->f_type != DTYPE_VNODE) { + error = ESPIPE; + } else { + error = dofileread(p, fp, uap->fd, uap->buf, uap->nbyte, + uap->offset, FOF_OFFSET, retval); + } + frele(fp); + return(error); +} + +/* + * Code common for read and pread + */ +int +dofileread(p, fp, fd, buf, nbyte, offset, flags, retval) + struct proc *p; + struct file *fp; + int fd, flags; + void *buf; + size_t nbyte; + off_t offset; + int *retval; { struct uio auio; struct iovec aiov; + long cnt, error = 0; +#if KTRACE + struct iovec ktriov; + struct uio ktruio; + int didktr = 0; +#endif - aiov.iov_base = (caddr_t)uap->cbuf; - aiov.iov_len = uap->nbyte; + aiov.iov_base = (caddr_t)buf; + aiov.iov_len = nbyte; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; + auio.uio_offset = offset; + if (nbyte > INT_MAX) + return (EINVAL); + auio.uio_resid = nbyte; auio.uio_rw = UIO_READ; - return (rwuio(p, uap->fd, &auio, UIO_READ, retval)); + auio.uio_segflg = UIO_USERSPACE; + auio.uio_procp = p; +#if KTRACE + /* + * if tracing, save a copy of iovec + */ + if (KTRPOINT(p, KTR_GENIO)) { + ktriov = aiov; + ktruio = auio; + didktr = 1; + } +#endif + cnt = nbyte; + + if ((error = fo_read(fp, &auio, fp->f_cred, flags, p))) { + if (auio.uio_resid != cnt && (error == ERESTART || + error == EINTR || error == EWOULDBLOCK)) + error = 0; + } + cnt -= auio.uio_resid; +#if KTRACE + if (didktr && error == 0) { + ktruio.uio_iov = &ktriov; + ktruio.uio_resid = cnt; + ktrgenio(p->p_tracep, fd, UIO_READ, &ktruio, error, + KERNEL_FUNNEL); + } +#endif + *retval = cnt; + return (error); } +/* + * Scatter read system call. + */ +#ifndef _SYS_SYSPROTO_H_ struct readv_args { int fd; struct iovec *iovp; u_int iovcnt; }; +#endif +int readv(p, uap, retval) struct proc *p; register struct readv_args *uap; @@ -171,32 +297,139 @@ readv(p, uap, retval) /* * Write system call */ +#ifndef _SYS_SYSPROTO_H_ struct write_args { int fd; char *cbuf; u_int nbyte; }; +#endif +int write(p, uap, retval) struct proc *p; register struct write_args *uap; int *retval; { + register struct file *fp; + int error; + + if ((fp = holdfp(p->p_fd, uap->fd, FWRITE)) == NULL) + return (EBADF); + error = dofilewrite(p, fp, uap->fd, uap->cbuf, uap->nbyte, + (off_t)-1, 0, retval); + frele(fp); + return(error); +} + +/* + * Pwrite system call + */ +#ifndef _SYS_SYSPROTO_H_ +struct pwrite_args { + int fd; + const void *buf; + size_t nbyte; +#ifdef DOUBLE_ALIGN_PARAMS + int pad; +#endif + off_t offset; +}; +#endif +int +pwrite(p, uap, retval) + struct proc *p; + register struct pwrite_args *uap; + int *retval; +{ + register struct file *fp; + int error; + + if ((fp = holdfp(p->p_fd, uap->fd, FWRITE)) == NULL) + return (EBADF); + if (fp->f_type != DTYPE_VNODE) { + error = ESPIPE; + } else { + error = dofilewrite(p, fp, uap->fd, uap->buf, uap->nbyte, + uap->offset, FOF_OFFSET, retval); + } + frele(fp); + return(error); +} + +static int +dofilewrite(p, fp, fd, buf, nbyte, offset, flags, retval) + struct proc *p; + struct file *fp; + int fd, flags; + const void *buf; + size_t nbyte; + off_t offset; + int *retval; +{ struct uio auio; struct iovec aiov; - - aiov.iov_base = uap->cbuf; - aiov.iov_len = uap->nbyte; + long cnt, error = 0; +#if KTRACE + struct iovec ktriov; + struct uio ktruio; + int didktr = 0; +#endif + + aiov.iov_base = (void *)(uintptr_t)buf; + aiov.iov_len = nbyte; auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; + auio.uio_iovcnt = 1; + auio.uio_offset = offset; + if (nbyte > INT_MAX) + return (EINVAL); + auio.uio_resid = nbyte; auio.uio_rw = UIO_WRITE; - return (rwuio(p, uap->fd, &auio, UIO_WRITE, retval)); + auio.uio_segflg = UIO_USERSPACE; + auio.uio_procp = p; +#if KTRACE + /* + * if tracing, save a copy of iovec and uio + */ + if (KTRPOINT(p, KTR_GENIO)) { + ktriov = aiov; + ktruio = auio; + didktr = 1; + } +#endif + cnt = nbyte; + if (fp->f_type == DTYPE_VNODE) + bwillwrite(); + if ((error = fo_write(fp, &auio, fp->f_cred, flags, p))) { + if (auio.uio_resid != cnt && (error == ERESTART || + error == EINTR || error == EWOULDBLOCK)) + error = 0; + if (error == EPIPE) + psignal(p, SIGPIPE); + } + cnt -= auio.uio_resid; +#if KTRACE + if (didktr && error == 0) { + ktruio.uio_iov = &ktriov; + ktruio.uio_resid = cnt; + ktrgenio(p->p_tracep, fd, UIO_WRITE, &ktruio, error, + KERNEL_FUNNEL); + } +#endif + *retval = cnt; + return (error); } - + +/* + * Gather write system call + */ +#ifndef _SYS_SYSPROTO_H_ struct writev_args { int fd; struct iovec *iovp; u_int iovcnt; }; +#endif +int writev(p, uap, retval) struct proc *p; register struct writev_args *uap; @@ -227,6 +460,7 @@ writev(p, uap, retval) return (error); } +int rwuio(p, fdes, uio, rw, retval) struct proc *p; int fdes; @@ -237,6 +471,12 @@ rwuio(p, fdes, uio, rw, retval) struct file *fp; register struct iovec *iov; int i, count, flag, error; +#if KTRACE + struct iovec *ktriov; + struct uio ktruio; + int didktr = 0; + u_int iovlen; +#endif if (error = fdgetf(p, fdes, &fp)) return (error); @@ -259,33 +499,65 @@ rwuio(p, fdes, uio, rw, retval) iov++; } count = uio->uio_resid; +#if KTRACE + /* + * if tracing, save a copy of iovec + */ + if (KTRPOINT(p, KTR_GENIO)) { + iovlen = uio->uio_iovcnt * sizeof (struct iovec); + MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); + bcopy((caddr_t)uio->uio_iov, (caddr_t)ktriov, iovlen); + ktruio = *uio; + didktr = 1; + } +#endif + if (rw == UIO_READ) { - if (error = (*fp->f_ops->fo_read)(fp, uio, fp->f_cred)) - if (uio->uio_resid != count && (error == ERESTART || - error == EINTR || error == EWOULDBLOCK)) - error = 0; + if (error = fo_read(fp, uio, fp->f_cred, 0, p)) + if (uio->uio_resid != count && (error == ERESTART || + error == EINTR || error == EWOULDBLOCK)) + error = 0; } else { - if (error = (*fp->f_ops->fo_write)(fp, uio, fp->f_cred)) { + if (fp->f_type == DTYPE_VNODE) + bwillwrite(); + if (error = fo_write(fp, uio, fp->f_cred, 0, p)) { if (uio->uio_resid != count && (error == ERESTART || - error == EINTR || error == EWOULDBLOCK)) + error == EINTR || error == EWOULDBLOCK)) error = 0; - if (error == EPIPE) + /* The socket layer handles SIGPIPE */ + if (error == EPIPE && fp->f_type != DTYPE_SOCKET) psignal(p, SIGPIPE); } } + *retval = count - uio->uio_resid; + +#if KTRACE + if (didktr) { + if (error == 0) { + ktruio.uio_iov = ktriov; + ktruio.uio_resid = *retval; + ktrgenio(p->p_tracep, fdes, rw, &ktruio, error, + KERNEL_FUNNEL); + } + FREE(ktriov, M_TEMP); + } +#endif + return(error); } /* * Ioctl system call */ +#ifndef _SYS_SYSPROTO_H_ struct ioctl_args { int fd; u_long com; caddr_t data; }; -/* ARGSUSED */ +#endif +int ioctl(p, uap, retval) struct proc *p; register struct ioctl_args *uap; @@ -306,10 +578,11 @@ ioctl(p, uap, retval) if ((fp->f_flag & (FREAD | FWRITE)) == 0) return (EBADF); - /*### LD 6/11/97 Hack Alert: this is to get AppleTalk to work +#if NETAT + /* + * ### LD 6/11/97 Hack Alert: this is to get AppleTalk to work * while implementing an ATioctl system call */ -#if NETAT { extern int appletalk_inited; @@ -317,7 +590,7 @@ ioctl(p, uap, retval) #ifdef APPLETALK_DEBUG kprintf("ioctl: special AppleTalk \n"); #endif - error = (*fp->f_ops->fo_ioctl)(fp, uap->com, uap->data, p); + error = fo_ioctl(fp, uap->com, uap->data, p); return(error); } } @@ -374,7 +647,7 @@ ioctl(p, uap, retval) fp->f_flag |= FNONBLOCK; else fp->f_flag &= ~FNONBLOCK; - error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p); + error = fo_ioctl(fp, FIONBIO, (caddr_t)&tmp, p); break; case FIOASYNC: @@ -382,7 +655,7 @@ ioctl(p, uap, retval) fp->f_flag |= FASYNC; else fp->f_flag &= ~FASYNC; - error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p); + error = fo_ioctl(fp, FIOASYNC, (caddr_t)&tmp, p); break; case FIOSETOWN: @@ -402,8 +675,7 @@ ioctl(p, uap, retval) } tmp = p1->p_pgrp->pg_id; } - error = (*fp->f_ops->fo_ioctl) - (fp, (int)TIOCSPGRP, (caddr_t)&tmp, p); + error = fo_ioctl(fp, (int)TIOCSPGRP, (caddr_t)&tmp, p); break; case FIOGETOWN: @@ -412,12 +684,12 @@ ioctl(p, uap, retval) *(int *)data = ((struct socket *)fp->f_data)->so_pgid; break; } - error = (*fp->f_ops->fo_ioctl)(fp, TIOCGPGRP, data, p); + error = fo_ioctl(fp, TIOCGPGRP, data, p); *(int *)data = -*(int *)data; break; default: - error = (*fp->f_ops->fo_ioctl)(fp, com, data, p); + error = fo_ioctl(fp, com, data, p); /* * Copy any data to user, size was * already set and checked above. @@ -431,14 +703,21 @@ ioctl(p, uap, retval) return (error); } - int selwait, nselcoll; #define SEL_FIRSTPASS 1 #define SEL_SECONDPASS 2 +extern int selcontinue(int error); +extern int selprocess(int error, int sel_pass); +static int selscan(struct proc *p, struct _select * sel, + int nfd, register_t *retval, int sel_pass); +static int selcount(struct proc *p, u_int32_t *ibits, u_int32_t *obits, + int nfd, int * count, int * nfcount); +extern uint64_t tvtoabstime(struct timeval *tvp); /* * Select system call. */ +#ifndef _SYS_SYSPROTO_H_ struct select_args { int nd; u_int32_t *in; @@ -446,20 +725,14 @@ struct select_args { u_int32_t *ex; struct timeval *tv; }; - -extern int selcontinue(int error); -extern int selprocess(int error, int sel_pass); -static int selscan( struct proc *p, struct _select * sel, - int nfd, register_t *retval, int sel_pass); -static int selcount(struct proc *p, u_int32_t *ibits, u_int32_t *obits, - int nfd, int * count, int * nfcount); - +#endif +int select(p, uap, retval) register struct proc *p; register struct select_args *uap; register_t *retval; { - int s, error = 0, timo; + int error = 0; u_int ni, nw, size; thread_act_t th_act; struct uthread *uth; @@ -534,20 +807,22 @@ select(p, uap, retval) #undef getbits if (uap->tv) { - error = copyin((caddr_t)uap->tv, (caddr_t)&sel->atv, - sizeof (sel->atv)); + struct timeval atv; + + error = copyin((caddr_t)uap->tv, (caddr_t)&atv, sizeof (atv)); if (error) goto continuation; - if (itimerfix(&sel->atv)) { + if (itimerfix(&atv)) { error = EINVAL; goto continuation; } - timeradd(&sel->atv, &time, &sel->atv); - timo = hzto(&sel->atv); - } else - timo = 0; - sel->poll = timo; + clock_absolutetime_interval_to_deadline( + tvtoabstime(&atv), &sel->abstime); + } + else + sel->abstime = 0; + sel->nfcount = 0; if (error = selcount(p, sel->ibits, sel->obits, uap->nd, &count, &nfcount)) { goto continuation; @@ -580,19 +855,19 @@ select(p, uap, retval) wait_queue_sub_init(uth->uu_wqsub, (SYNC_POLICY_FIFO | SYNC_POLICY_PREPOST)); continuation: - selprocess(error, SEL_FIRSTPASS); + return selprocess(error, SEL_FIRSTPASS); } int selcontinue(int error) { - selprocess(error, SEL_SECONDPASS); + return selprocess(error, SEL_SECONDPASS); } int selprocess(error, sel_pass) { - int s, ncoll, timo; + int ncoll; u_int ni, nw; thread_act_t th_act; struct uthread *uth; @@ -601,9 +876,10 @@ selprocess(error, sel_pass) int *retval; struct _select *sel; int unwind = 1; - int prepost =0; + int prepost = 0; int somewakeup = 0; int doretry = 0; + wait_result_t wait_result; p = current_proc(); th_act = current_act(); @@ -646,10 +922,12 @@ retry: } } - /* this should be timercmp(&time, &atv, >=) */ - if (uap->tv && (time.tv_sec > sel->atv.tv_sec || - time.tv_sec == sel->atv.tv_sec && time.tv_usec >= sel->atv.tv_usec)) { - goto done; + if (uap->tv) { + uint64_t now; + + clock_get_uptime(&now); + if (now >= sel->abstime) + goto done; } if (doretry) { @@ -663,9 +941,7 @@ retry: * To effect a poll, the timeout argument should be * non-nil, pointing to a zero-valued timeval structure. */ - timo = sel->poll; - - if (uap->tv && (timo == 0)) { + if (uap->tv && sel->abstime == 0) { goto done; } @@ -682,9 +958,12 @@ retry: panic("selprocess: 2nd pass assertwaiting"); /* Wait Queue Subordinate has waitqueue as first element */ - if (wait_queue_assert_wait(uth->uu_wqsub, &selwait, THREAD_ABORTSAFE)) { - /* If it is true then there are no preposted events */ - error = tsleep1((caddr_t)&selwait, PSOCK | PCATCH, "select", timo, selcontinue); + wait_result = wait_queue_assert_wait((wait_queue_t)uth->uu_wqsub, + &selwait, THREAD_ABORTSAFE); + if (wait_result != THREAD_AWAKENED) { + /* there are no preposted events */ + error = tsleep1(NULL, PSOCK | PCATCH, + "select", sel->abstime, selcontinue); } else { prepost = 1; error = 0; @@ -723,12 +1002,7 @@ done: putbits(ex, 2); #undef putbits } - -#if defined (__i386__) return(error); -#else - unix_syscall_return(error); -#endif } static int @@ -795,7 +1069,7 @@ selscan(p, sel, nfd, retval, sel_pass) else wql_ptr = (wql+ nc * SIZEOF_WAITQUEUE_LINK); if (fp->f_ops && (fp->f_type != DTYPE_SOCKET) - && (*fp->f_ops->fo_select)(fp, flag[msk], wql_ptr, p)) { + && fo_select(fp, flag[msk], wql_ptr, p)) { optr[fd/NFDBITS] |= (1 << (fd % NFDBITS)); n++; } @@ -820,6 +1094,7 @@ selscan(p, sel, nfd, retval, sel_pass) fp = fdp->fd_ofiles[fd]; if (fp == NULL || (fdp->fd_ofileflags[fd] & UF_RESERVED)) { + thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); return(EBADF); } if (sel_pass == SEL_SECONDPASS) @@ -827,7 +1102,7 @@ selscan(p, sel, nfd, retval, sel_pass) else wql_ptr = (wql+ nc * SIZEOF_WAITQUEUE_LINK); if (fp->f_ops && (fp->f_type == DTYPE_SOCKET) && - (*fp->f_ops->fo_select)(fp, flag[msk], wql_ptr, p)) { + fo_select(fp, flag[msk], wql_ptr, p)) { optr[fd/NFDBITS] |= (1 << (fd % NFDBITS)); n++; } @@ -843,6 +1118,7 @@ selscan(p, sel, nfd, retval, sel_pass) } /*ARGSUSED*/ +int seltrue(dev, flag, p) dev_t dev; int flag; @@ -997,6 +1273,7 @@ extern struct eventqelt *evprocdeque(struct proc *p, struct eventqelt *eqp); * called upon socket close. deque and free all events for * the socket */ +void evsofree(struct socket *sp) { struct eventqelt *eqp, *next; @@ -1035,6 +1312,7 @@ evsofree(struct socket *sp) * enque this event if it's not already queued. wakeup the proc if we do queue this event to it. */ +void evprocenque(struct eventqelt *eqp) { struct proc *p; @@ -1058,6 +1336,7 @@ evprocenque(struct eventqelt *eqp) * given either a sockbuf or a socket run down the * event list and queue ready events found */ +void postevent(struct socket *sp, struct sockbuf *sb, int event) { int mask; @@ -1317,66 +1596,69 @@ struct evwait_args { */ int waitevent(p, uap, retval) - struct proc *p; - struct evwait_args *uap; - register_t *retval; + struct proc *p; + struct evwait_args *uap; + register_t *retval; { - int error = 0; - struct eventqelt *eqp; - int timo; - struct timeval atv; - int s; + int error = 0; + struct eventqelt *eqp; + uint64_t abstime, interval; if (uap->tv) { - error = copyin((caddr_t)uap->tv, (caddr_t)&atv, - sizeof (atv)); + struct timeval atv; + + error = copyin((caddr_t)uap->tv, (caddr_t)&atv, sizeof (atv)); if (error) - return(error); + return(error); if (itimerfix(&atv)) { error = EINVAL; return(error); } - s = splhigh(); - timeradd(&atv, &time, &atv); - timo = hzto(&atv); - splx(s); - } else - timo = 0; - KERNEL_DEBUG(DBG_MISC_WAIT|DBG_FUNC_START, 0,0,0,0,0); + interval = tvtoabstime(&atv); + } + else + abstime = interval = 0; + + KERNEL_DEBUG(DBG_MISC_WAIT|DBG_FUNC_START, 0,0,0,0,0); retry: - s = splhigh(); - if ((eqp = evprocdeque(p,NULL)) != NULL) { - splx(s); - error = copyout((caddr_t)&eqp->ee_req, (caddr_t)uap->u_req, - sizeof(struct eventreq)); - KERNEL_DEBUG(DBG_MISC_WAIT|DBG_FUNC_END, error, - eqp->ee_req.er_handle,eqp->ee_req.er_eventbits,eqp,0); - return(error); - } else { - if (uap->tv && (timo == 0)) { - splx(s); - *retval = 1; // poll failed - KERNEL_DEBUG(DBG_MISC_WAIT|DBG_FUNC_END, error,0,0,0,0); - return(error); - } + if ((eqp = evprocdeque(p,NULL)) != NULL) { + error = copyout((caddr_t)&eqp->ee_req, + (caddr_t)uap->u_req, sizeof(struct eventreq)); + KERNEL_DEBUG(DBG_MISC_WAIT|DBG_FUNC_END, error, + eqp->ee_req.er_handle,eqp->ee_req.er_eventbits,eqp,0); - KERNEL_DEBUG(DBG_MISC_WAIT, 1,&p->p_evlist,0,0,0); - error = tsleep(&p->p_evlist, PSOCK | PCATCH, "waitevent", timo); - KERNEL_DEBUG(DBG_MISC_WAIT, 2,&p->p_evlist,0,0,0); - splx(s); - if (error == 0) - goto retry; - if (error == ERESTART) - error = EINTR; - if (error == EWOULDBLOCK) { - *retval = 1; - error = 0; - } - } - KERNEL_DEBUG(DBG_MISC_WAIT|DBG_FUNC_END, 0,0,0,0,0); - return(error); + return (error); + } + else { + if (uap->tv && interval == 0) { + *retval = 1; // poll failed + KERNEL_DEBUG(DBG_MISC_WAIT|DBG_FUNC_END, error,0,0,0,0); + + return (error); + } + + if (interval != 0) + clock_absolutetime_interval_to_deadline(interval, &abstime) + + KERNEL_DEBUG(DBG_MISC_WAIT, 1,&p->p_evlist,0,0,0); + error = tsleep1(&p->p_evlist, PSOCK | PCATCH, + "waitevent", abstime, (int (*)(int))0); + KERNEL_DEBUG(DBG_MISC_WAIT, 2,&p->p_evlist,0,0,0); + if (error == 0) + goto retry; + if (error == ERESTART) + error = EINTR; + if (error == EWOULDBLOCK) { + *retval = 1; + error = 0; + } + } + + KERNEL_DEBUG(DBG_MISC_WAIT|DBG_FUNC_END, 0,0,0,0,0); + + return (error); } struct modwatch_args { diff --git a/bsd/kern/sys_socket.c b/bsd/kern/sys_socket.c index c6ae049cc..c276ed036 100644 --- a/bsd/kern/sys_socket.c +++ b/bsd/kern/sys_socket.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -70,9 +70,9 @@ #include int soo_read __P((struct file *fp, struct uio *uio, - struct ucred *cred)); + struct ucred *cred, int flags, struct proc *p)); int soo_write __P((struct file *fp, struct uio *uio, - struct ucred *cred)); + struct ucred *cred, int flags, struct proc *p)); int soo_close __P((struct file *fp, struct proc *p)); int soo_select __P((struct file *fp, int which, void * wql, struct proc *p)); @@ -82,12 +82,14 @@ struct fileops socketops = /* ARGSUSED */ int -soo_read(fp, uio, cred) +soo_read(fp, uio, cred, flags, p) struct file *fp; struct uio *uio; struct ucred *cred; + int flags; + struct proc *p; { - struct socket *so = (struct socket *)fp->f_data; + struct socket *so; struct kextcb *kp; int stat; int (*fsoreceive) __P((struct socket *so, @@ -98,6 +100,12 @@ soo_read(fp, uio, cred) thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); + if ((so = (struct socket *)fp->f_data) == NULL) { + /* This is not a valid open file descriptor */ + thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); + return (EBADF); + } + fsoreceive = so->so_proto->pr_usrreqs->pru_soreceive; if (fsoreceive != soreceive) { kp = sotokextcb(so); @@ -117,12 +125,14 @@ soo_read(fp, uio, cred) /* ARGSUSED */ int -soo_write(fp, uio, cred) +soo_write(fp, uio, cred, flags, p) struct file *fp; struct uio *uio; struct ucred *cred; + int flags; + struct proc *p; { - struct socket *so = (struct socket *)fp->f_data; + struct socket *so; int (*fsosend) __P((struct socket *so, struct sockaddr *addr, struct uio *uio, struct mbuf *top, struct mbuf *control, int flags)); @@ -130,6 +140,13 @@ soo_write(fp, uio, cred) int stat; thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); + + if ((so = (struct socket *)fp->f_data) == NULL) { + /* This is not a valid open file descriptor */ + thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); + return (EBADF); + } + fsosend = so->so_proto->pr_usrreqs->pru_sosend; if (fsosend != sosend) { kp = sotokextcb(so); @@ -143,7 +160,12 @@ soo_write(fp, uio, cred) stat = (*fsosend)(so, 0, uio, 0, 0, 0); thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); - return stat; + + /* Generation of SIGPIPE can be controlled per socket */ + if (stat == EPIPE && uio->uio_procp && !(so->so_flags & SOF_NOSIGPIPE)) + psignal(uio->uio_procp, SIGPIPE); + + return stat; } int @@ -153,19 +175,24 @@ soo_ioctl(fp, cmd, data, p) register caddr_t data; struct proc *p; { - register struct socket *so = (struct socket *)fp->f_data; - + register struct socket *so; struct sockopt sopt; struct kextcb *kp; int error = 0; - kp = sotokextcb(so); - sopt.sopt_level = cmd; - sopt.sopt_name = (int)data; - sopt.sopt_p = p; - thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); + if ((so = (struct socket *)fp->f_data) == NULL) { + /* This is not a valid open file descriptor */ + thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); + return (EBADF); + } + + kp = sotokextcb(so); + sopt.sopt_level = cmd; + sopt.sopt_name = (int)data; + sopt.sopt_p = p; + while (kp) { if (kp->e_soif && kp->e_soif->sf_socontrol) (*kp->e_soif->sf_socontrol)(so, &sopt, kp); @@ -240,6 +267,7 @@ soo_ioctl(fp, cmd, data, p) fp->f_flag |= FNONBLOCK; so->so_state |= SS_NBIO; so->so_options |= SO_DONTTRUNC | SO_WANTMORE; + so->so_flags |= SOF_NOSIGPIPE; if (cloned_so && so != cloned_so) { /* Flags options */ @@ -362,8 +390,12 @@ soo_stat(so, ub) register struct socket *so; register struct stat *ub; { - int stat; + int stat; + /* + * DANGER: by the time we get the network funnel the socket + * may have been closed + */ thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); bzero((caddr_t)ub, sizeof (*ub)); ub->st_mode = S_IFSOCK; @@ -380,11 +412,12 @@ soo_close(fp, p) { int error = 0; - if (fp->f_data) { - thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); + thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); + + if (fp->f_data) error = soclose((struct socket *)fp->f_data); - thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); - } + + thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); fp->f_data = 0; return (error); diff --git a/bsd/kern/syscalls.c b/bsd/kern/syscalls.c index d5b0b8bd9..27d915a0a 100644 --- a/bsd/kern/syscalls.c +++ b/bsd/kern/syscalls.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -20,19 +20,6 @@ * @APPLE_LICENSE_HEADER_END@ */ /* Copyright (c) 1992,1995-1999 Apple Computer, Inc. All rights resereved. */ -/* - * HISTORY - * - * 02-10-99 Clark Warner (warner_c) ta Apple - * Chaned call 227 to copyfile - * 07-14-99 Earsh Nandkeshwar (earsh) at Apple - * Renamed getdirentryattr to getdirentriesattr - * 01-22-98 Clark Warner (warner_c) at Apple - * Created new HFS style Systemcalls - * 25-May-95 Mac Gillon (mgillon) at NeXT - * Created from NS 3.3 and 4.4BSD - * - */ char *syscallnames[] = { "syscall", /* 0 = syscall */ @@ -43,7 +30,7 @@ char *syscallnames[] = { "open", /* 5 = open */ "close", /* 6 = close */ "wait4", /* 7 = wait4 */ - "old_creat", /* 8 = old creat */ + "obs_creat", /* 8 = old creat */ "link", /* 9 = link */ "unlink", /* 10 = unlink */ "obs_execv", /* 11 = obsolete execv */ @@ -52,8 +39,8 @@ char *syscallnames[] = { "mknod", /* 14 = mknod */ "chmod", /* 15 = chmod */ "chown", /* 16 = chown */ - "sbreak", /* 17 = obsolete sbreak */ - "obs_stat", /* 18 = obsolete stat */ + "obs_break", /* 17 = obsolete break */ + "obs_getfsstat", /* 18 = obsolete getfsstat */ "old_lseek", /* 19 = old lseek */ "getpid", /* 20 = getpid */ "obs_mount", /* 21 = obsolete mount */ @@ -73,9 +60,9 @@ char *syscallnames[] = { "fchflags", /* 35 = fchflags */ "sync", /* 36 = sync */ "kill", /* 37 = kill */ - "old_stat", /* 38 = old stat */ + "obs_stat", /* 38 = old stat */ "getppid", /* 39 = getppid */ - "old_lstat", /* 40 = old lstat */ + "obs_lstat", /* 40 = old lstat */ "dup", /* 41 = dup */ "pipe", /* 42 = pipe */ "getegid", /* 43 = getegid */ @@ -97,22 +84,22 @@ char *syscallnames[] = { "execve", /* 59 = execve */ "umask", /* 60 = umask */ "chroot", /* 61 = chroot */ - "old_fstat", /* 62 = old fstat */ - "old_getkerninfo", /* 63 = old getkerninfo */ - "old_getpagesize", /* 64 = old getpagesize */ + "obs_fstat", /* 62 = old fstat */ + "#63", /* 63 = reserved */ + "obs_getpagesize", /* 64 = old getpagesize */ "msync", /* 65 = msync */ "vfork", /* 66 = vfork */ "obs_vread", /* 67 = obsolete vread */ "obs_vwrite", /* 68 = obsolete vwrite */ "sbrk", /* 69 = sbrk */ "sstk", /* 70 = sstk */ - "old_mmap", /* 71 = old mmap */ + "obs_mmap", /* 71 = old mmap */ "obs_vadvise", /* 72 = obsolete vadvise */ "munmap", /* 73 = munmap */ "mprotect", /* 74 = mprotect */ "madvise", /* 75 = madvise */ - "obs_vhangup", /* 76 = obsolete vhangup */ - "obs_vlimit", /* 77 = obsolete vlimit */ + "#76", /* 76 = obsolete vhangup */ + "#77", /* 77 = obsolete vlimit */ "mincore", /* 78 = mincore */ "getgroups", /* 79 = getgroups */ "setgroups", /* 80 = setgroups */ @@ -120,10 +107,10 @@ char *syscallnames[] = { "setpgid", /* 82 = setpgid */ "setitimer", /* 83 = setitimer */ "old_wait", /* 84 = old wait */ - "swapon", /* 85 = swapon */ + "obs_swapon", /* 85 = swapon */ "getitimer", /* 86 = getitimer */ - "old_gethostname", /* 87 = old gethostname */ - "old_sethostname", /* 88 = old sethostname */ + "obs_gethostname", /* 87 = old gethostname */ + "obs_sethostname", /* 88 = old sethostname */ "getdtablesize", /* 89 = getdtablesize */ "dup2", /* 90 = dup2 */ "#91", /* 91 = getdopt */ @@ -134,7 +121,7 @@ char *syscallnames[] = { "setpriority", /* 96 = setpriority */ "socket", /* 97 = socket */ "connect", /* 98 = connect */ - "old_accept", /* 99 = old accept */ + "obs_accept", /* 99 = old accept */ "getpriority", /* 100 = getpriority */ "old_send", /* 101 = old send */ "old_recv", /* 102 = old recv */ @@ -142,15 +129,15 @@ char *syscallnames[] = { "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 */ + "#107", /* 107 = obsolete vtimes */ + "obs_sigvec", /* 108 = old sigvec */ + "obs_sigblock", /* 109 = old sigblock */ + "obs_sigsetmask", /* 110 = old sigsetmask */ "sigsuspend", /* 111 = sigsuspend */ - "old_sigstack", /* 112 = old sigstack */ - "old_recvmsg", /* 113 = old recvmsg */ - "old_sendmsg", /* 114 = old sendmsg */ - "obs_vtrace", /* 115 = obsolete vtrace */ + "obs_sigstack", /* 112 = old sigstack */ + "obs_recvmsg", /* 113 = old recvmsg */ + "obs_sendmsg", /* 114 = old sendmsg */ + "#115", /* 115 = obsolete vtrace */ "gettimeofday", /* 116 = gettimeofday */ "getrusage", /* 117 = getrusage */ "getsockopt", /* 118 = getsockopt */ @@ -160,12 +147,12 @@ char *syscallnames[] = { "settimeofday", /* 122 = settimeofday */ "fchown", /* 123 = fchown */ "fchmod", /* 124 = fchmod */ - "old_recvfrom", /* 125 = old recvfrom */ - "old_setreuid", /* 126 = old setreuid */ - "old_setregid", /* 127 = old setregid */ + "obs_recvfrom", /* 125 = old recvfrom */ + "obs_setreuid", /* 126 = old setreuid */ + "obs_setregid", /* 127 = old setregid */ "rename", /* 128 = rename */ - "old_truncate", /* 129 = old truncate */ - "old_ftruncate", /* 130 = old ftruncate */ + "obs_truncate", /* 129 = old truncate */ + "obs_ftruncate", /* 130 = old ftruncate */ "flock", /* 131 = flock */ "mkfifo", /* 132 = mkfifo */ "sendto", /* 133 = sendto */ @@ -174,211 +161,215 @@ char *syscallnames[] = { "mkdir", /* 136 = mkdir */ "rmdir", /* 137 = rmdir */ "utimes", /* 138 = utimes */ - "#139", /* 139 = nosys */ + "futimes", /* 139 = futimes */ "adjtime", /* 140 = adjtime */ - "old_getpeername", /* 141 = old getpeername */ - "old_gethostid", /* 142 = old gethostid */ - "old_sethostid", /* 143 = old sethostid */ - "old_getrlimit", /* 144 = old getrlimit */ - "old_setrlimit", /* 145 = old setrlimit */ - "old_killpg", /* 146 = old killpg */ + "obs_getpeername", /* 141 = old getpeername */ + "obs_gethostid", /* 142 = old gethostid */ + "#143", /* 143 = old sethostid */ + "obs_getrlimit", /* 144 = old getrlimit */ + "obs_setrlimit", /* 145 = old setrlimit */ + "obs_killpg", /* 146 = old killpg */ "setsid", /* 147 = setsid */ - "obs_setquota", /* 148 = obsolete setquota */ - "obs_quota", /* 149 = obsolete quota */ - "old_getsockname", /* 150 = old getsockname */ - "#151", /* 151 = nosys */ + "#148", /* 148 = obsolete setquota */ + "#149", /* 149 = obsolete qquota */ + "obs_getsockname", /* 150 = old getsockname */ + "getpgid", /* 151 = getpgid */ "setprivexec", /* 152 = setprivexec */ - "#153", /* 153 = nosys */ - "#154", /* 154 = nosys */ + "pread", /* 153 = pread */ + "pwrite", /* 154 = pwrite */ "nfssvc", /* 155 = nfssvc */ "getdirentries", /* 156 =getdirentries */ "statfs", /* 157 = statfs */ "fstatfs", /* 158 = fstatfs */ "unmount", /* 159 = unmount */ - "obs_async_daemon", /* 160 = obsolete async_daemon */ + "#160", /* 160 = obsolete async_daemon */ "getfh", /* 161 = getfh */ - "old_getdomainname",/* 162 = old getdomainname */ - "old_setdomainname",/* 163 = old setdomainname */ - "obs_pcfs_mount", /* 164 = obsolete pcfs_mount */ + "obs_getdomainname",/* 162 = old getdomainname */ + "obs_setdomainname",/* 163 = old setdomainname */ + "#164", /* 164 */ "quotactl", /* 165 = quotactl */ - "obs_exportfs", /* 166 = obsolete exportfs */ + "#166", /* 166 = obsolete exportfs */ "mount", /* 167 = mount */ - "obs_ustat", /* 168 = obsolete ustat */ + "#168", /* 168 = obsolete ustat */ "#169", /* 169 = nosys */ - "obs_table", /* 170 = obsolete table */ - "old_wait_3", /* 171 = old wait_3 */ - "obs_rpause", /* 172 = obsolete rpause */ + "#170", /* 170 = obsolete table */ + "obs_wait3", /* 171 = old wait3 */ + "#172", /* 172 = obsolete rpause */ "#173", /* 173 = nosys */ - "obs_getdents", /* 174 = obsolete getdents */ + "#174", /* 174 = obsolete getdents */ "#175", /* 175 = nosys */ "add_profil", /* 176 = add_profil */ /* NeXT */ "#177", /* 177 = nosys */ "#178", /* 178 = nosys */ "#179", /* 179 = nosys */ - "kdebug_trace", /* 180 = kdebug_trace */ + "kdebug_trace", /* 180 = kdebug_trace */ "setgid", /* 181 = setgid */ "setegid", /* 182 = setegid */ "seteuid", /* 183 = seteuid */ -#ifdef LFS - "lfs_bmapv", /* 184 = lfs_bmapv */ - "lfs_markv", /* 185 = lfs_markv */ - "lfs_segclean", /* 186 = lfs_segclean */ - "lfs_segwait", /* 187 = lfs_segwait */ -#else "#184", /* 184 = nosys */ "#185", /* 185 = nosys */ "#186", /* 186 = nosys */ "#187", /* 187 = nosys */ -#endif "stat", /* 188 = stat */ "fstat", /* 189 = fstat */ "lstat", /* 190 = lstat */ "pathconf", /* 191 = pathconf */ "fpathconf", /* 192 = fpathconf */ - "#193", /* 193 = nosys */ + "obs_getfsstat", /* 193 = old getfsstat */ "getrlimit", /* 194 = getrlimit */ "setrlimit", /* 195 = setrlimit */ - "#196", /* 196 = unused */ + "getdirentries", /* 196 = getdirentries */ "mmap", /* 197 = mmap */ - "__syscall", /* 198 = __syscall */ + "#198", /* 198 = __syscall */ "lseek", /* 199 = lseek */ "truncate", /* 200 = truncate */ "ftruncate", /* 201 = ftruncate */ "__sysctl", /* 202 = __sysctl */ "mlock", /* 203 = mlock */ "munlock", /* 204 = munlock */ - "#205", /* 205 = nosys */ - - /* - * 206 - 215 are all reserved for AppleTalk. - * When AppleTalk is defined some of them are in use - */ - - "#206", /* 206 = nosys */ - "#207", /* 207 = nosys */ - "#208", /* 208 = nosys */ - "#209", /* 209 = nosys */ - "#210", /* 210 = nosys */ - "#211", /* 205 = nosys */ - "#212", /* 206 = nosys */ - "#213", /* 207 = nosys */ - "#214", /* 208 = nosys */ - "#215", /* 209 = nosys */ - "mkcomplex", /* 216 = mkcomplex */ - "statv", /* 217 = stav */ - "lstatv", /* 218 = lstav */ - "fstatv", /* 219 = fstav */ - "getattrlist", /* 220 = getattrlist */ - "setattrlist", /* 221 = setattrlist */ - "getdirentriesattr", /* 222 = getdirentriesattr*/ - "exchangedata", /* 223 = exchangedata */ - "checkuseraccess", /* 224 - checkuseraccess*/ - "searchfs", /* 225 = searchfs */ - "#226", /* 226 = private delete call */ - "#227", /* 227 = copyfile */ - "#228", /* 228 = nosys */ - "#229", /* 229 = nosys */ - "#230", /* 230 = reserved for AFS */ - - /* - * 216 - 230 are all reserved for suppoorting HFS/AFP File System - * Semantics. 225-230 are reserved for future use. - */ + "undelete", /* 205 = undelete */ + "ATsocket", /* 206 = ATsocket */ + "ATgetmsg", /* 207 = ATgetmsg */ + "ATputmsg", /* 208 = ATputmsg */ + "ATPsndreq", /* 209 = ATPsndreq */ + "ATPsndrsp", /* 210 = ATPsndrsp */ + "ATPgetreq", /* 211 = ATPgetreq */ + "ATPgetrsp", /* 212 = ATPgetrsp */ + "#213", /* 213 = Reserved for AppleTalk */ + "#214", /* 214 = Reserved for AppleTalk */ + "#215", /* 215 = Reserved for AppleTalk */ + "#216", /* 216 = Reserved */ + "#217", /* 217 = Reserved */ + "#218", /* 218 = Reserved */ + "#219", /* 219 = Reserved */ + "getattrlist", /* 220 = getattrlist */ + "setattrlist", /* 221 = setattrlist */ + "getdirentriesattr", /* 222 = getdirentriesattr */ + "exchangedata", /* 223 = exchangedata */ + "checkuseraccess", /* 224 - checkuseraccess */ + "searchfs", /* 225 = searchfs */ + "delete", /* 226 = private delete call */ + "copyfile", /* 227 = copyfile */ + "#228", /* 228 = nosys */ + "#229", /* 229 = nosys */ + "#230", /* 230 = reserved for AFS */ "watchevent", /* 231 = watchevent */ "waitevent", /* 232 = waitevent */ - "modwatch", /* 233 = modwatch */ - "#234", /* 234 = nosys */ - "#235", /* 235 = nosys */ - "#236", /* 236 = nosys */ - "#237", /* 237 = nosys */ - "#238", /* 238 = nosys */ - "#239", /* 239 = nosys */ - "#240", /* 240 = nosys */ - "#241", /* 241 = nosys */ - "#242", /* 242 = nosys */ - "#243", /* 243 = nosys */ - "#244", /* 244 = nosys */ - "#245", /* 245 = nosys */ - "#246", /* 246 = nosys */ - "#247", /* 247 = nosys */ - "#248", /* 248 = nosys */ - "#249", /* 249 = nosys */ - "minherit", /* 250 = minherit */ - "semsys", /* 251 = semsys */ - "msgsys", /* 252 = msgsys */ - "shmsys", /* 253 = shmsys */ - "semctl", /* 254 = semctl */ - "semget", /* 255 = semget */ - "semop", /* 256 = semop */ + "modwatch", /* 233 = modwatch */ + "#234", /* 234 = nosys */ + "#235", /* 235 = nosys */ + "#236", /* 236 = nosys */ + "#237", /* 237 = nosys */ + "#238", /* 238 = nosys */ + "#239", /* 239 = nosys */ + "#240", /* 240 = nosys */ + "#241", /* 241 = nosys */ + "fsctl", /* 242 = fsctl */ + "#243", /* 243 = nosys */ + "#244", /* 244 = nosys */ + "#245", /* 245 = nosys */ + "#246", /* 246 = nosys */ + "#247", /* 247 = nosys */ + "#248", /* 248 = nosys */ + "#249", /* 249 = nosys */ + "minherit", /* 250 = minherit */ + "semsys", /* 251 = semsys */ + "msgsys", /* 252 = msgsys */ + "shmsys", /* 253 = shmsys */ + "semctl", /* 254 = semctl */ + "semget", /* 255 = semget */ + "semop", /* 256 = semop */ "semconfig", /* 257 = semconfig */ - "msgctl", /* 258 = msgctl */ - "msgget", /* 259 = msgget */ - "msgsnd", /* 260 = msgsnd */ - "msgrcv", /* 261 = msgrcv */ - "shmat", /* 262 = shmat */ - "shmctl", /* 263 = shmctl */ - "shmdt", /* 264 = shmdt */ - "shmget", /* 265 = shmget */ - "shm_open", /* 266 = shm_open */ + "msgctl", /* 258 = msgctl */ + "msgget", /* 259 = msgget */ + "msgsnd", /* 260 = msgsnd */ + "msgrcv", /* 261 = msgrcv */ + "shmat", /* 262 = shmat */ + "shmctl", /* 263 = shmctl */ + "shmdt", /* 264 = shmdt */ + "shmget", /* 265 = shmget */ + "shm_open", /* 266 = shm_open */ "shm_unlink", /* 267 = shm_unlink */ - "sem_open", /* 268 = sem_open */ + "sem_open", /* 268 = sem_open */ "sem_close", /* 269 = sem_close */ "sem_unlink", /* 270 = sem_unlink */ - "sem_wait", /* 271 = sem_wait */ + "sem_wait", /* 271 = sem_wait */ "sem_trywait", /* 272 = sem_trywait */ - "sem_post", /* 273 = sem_post */ + "sem_post", /* 273 = sem_post */ "sem_getvalue", /* 274 = sem_getvalue */ - "sem_init", /* 275 = sem_init */ + "sem_init", /* 275 = sem_init */ "sem_destroy", /* 276 = sem_destroy */ - "#277", /* 277 = nosys */ - "#278", /* 278 = nosys */ - "#279", /* 279 = nosys */ - "#280", /* 280 = nosys */ - "#281", /* 281 = nosys */ - "#282", /* 282 = nosys */ - "#283", /* 283 = nosys */ - "#284", /* 284 = nosys */ - "#285", /* 285 = nosys */ - "#286", /* 286 = nosys */ - "#287", /* 287 = nosys */ - "#288", /* 288 = nosys */ - "#289", /* 289 = nosys */ - "#290", /* 290 = nosys */ - "#291", /* 291 = nosys */ - "#292", /* 292 = nosys */ - "#293", /* 293 = nosys */ - "#294", /* 294 = nosys */ - "#295", /* 295 = nosys */ + "#277", /* 277 = nosys */ + "#278", /* 278 = nosys */ + "#279", /* 279 = nosys */ + "#280", /* 280 = nosys */ + "#281", /* 281 = nosys */ + "#282", /* 282 = nosys */ + "#283", /* 283 = nosys */ + "#284", /* 284 = nosys */ + "#285", /* 285 = nosys */ + "#286", /* 286 = nosys */ + "#287", /* 287 = nosys */ + "#288", /* 288 = nosys */ + "#289", /* 289 = nosys */ + "#290", /* 290 = nosys */ + "#291", /* 291 = nosys */ + "#292", /* 292 = nosys */ + "#293", /* 293 = nosys */ + "#294", /* 294 = nosys */ + "#295", /* 295 = nosys */ "load_shared_file", /* 296 = load_shared_file */ "reset_shared_file", /* 297 = reset_shared_file */ - "#298", /* 298 = nosys */ - "#299", /* 299 = nosys */ - "#300", /* 300 = modnext */ - "#301", /* 301 = modstat */ - "#302", /* 302 = modfnext */ - "#303", /* 303 = modfind */ - "#304", /* 304 = kldload */ - "#305", /* 305 = kldunload */ - "#306", /* 306 = kldfind */ - "#307", /* 307 = kldnext */ - "#308", /* 308 = kldstat */ - "#309", /* 309 = kldfirstmod */ - "#310", /* 310 = getsid */ - "#311", /* 311 = setresuid */ - "#312", /* 312 = setresgid */ - "#313", /* 313 = obsolete signanosleep */ - "#314", /* 314 = aio_return */ - "#315", /* 315 = aio_suspend */ - "#316", /* 316 = aio_cancel */ - "#317", /* 317 = aio_error */ - "#318", /* 318 = aio_read */ - "#319", /* 319 = aio_write */ - "#320", /* 320 = lio_listio */ - "#321", /* 321 = yield */ - "#322", /* 322 = thr_sleep */ - "#323", /* 323 = thr_wakeup */ - "mlockall", /* 324 = mlockall */ - "munlockall", /* 325 = munlockall */ - "#326", /* 326 */ - "issetugid" /* 327 = issetugid */ + "new_system_shared_regions", /* 298 = new_system_shared_regions */ + "#299", /* 299 = nosys */ + "#300", /* 300 = modnext */ + "#301", /* 301 = modstat */ + "#302", /* 302 = modfnext */ + "#303", /* 303 = modfind */ + "#304", /* 304 = kldload */ + "#305", /* 305 = kldunload */ + "#306", /* 306 = kldfind */ + "#307", /* 307 = kldnext */ + "#308", /* 308 = kldstat */ + "#309", /* 309 = kldfirstmod */ + "getsid", /* 310 = getsid */ + "#311", /* 311 = setresuid */ + "#312", /* 312 = setresgid */ + "#313", /* 313 = obsolete signanosleep */ + "#314", /* 314 = aio_return */ + "#315", /* 315 = aio_suspend */ + "#316", /* 316 = aio_cancel */ + "#317", /* 317 = aio_error */ + "#318", /* 318 = aio_read */ + "#319", /* 319 = aio_write */ + "#320", /* 320 = lio_listio */ + "#321", /* 321 = yield */ + "#322", /* 322 = thr_sleep */ + "#323", /* 323 = thr_wakeup */ + "mlockall", /* 324 = mlockall */ + "munlockall", /* 325 = munlockall */ + "#326", /* 326 */ + "issetugid", /* 327 = issetugid */ + "__pthread_kill", /* 328 = __pthread_kill */ + "pthread_sigmask", /* 329 = pthread_sigmask */ + "sigwait", /* 330 = sigwait */ + "#331", /* 331 */ + "#332", /* 332 */ + "#333", /* 333 */ + "#334", /* 334 */ + "utrace", /* 335 = utrace */ + "#336", /* 336 */ + "#337", /* 337 */ + "#338", /* 338 */ + "#339", /* 339 */ + "#340", /* 340 */ + "#341", /* 341 */ + "#342", /* 342 */ + "#343", /* 343 */ + "#344", /* 344 */ + "#345", /* 345 */ + "#346", /* 346 */ + "#347", /* 347 */ + "#348", /* 348 */ + "#349" /* 349 */ }; diff --git a/bsd/kern/sysctl_init.c b/bsd/kern/sysctl_init.c index 18b840051..3b659c97e 100644 --- a/bsd/kern/sysctl_init.c +++ b/bsd/kern/sysctl_init.c @@ -26,6 +26,7 @@ #include extern struct sysctl_oid sysctl__debug_bpf_bufsize; +extern struct sysctl_oid sysctl__debug_bpf_maxbufsize; #if TUN extern struct sysctl_oid sysctl__debug_if_tun_debug; @@ -37,6 +38,12 @@ extern struct sysctl_oid sysctl__debug_ttydebug; #endif #endif +extern struct sysctl_oid sysctl__kern_sysv_shmmax; +extern struct sysctl_oid sysctl__kern_sysv_shmmin; +extern struct sysctl_oid sysctl__kern_sysv_shmmni; +extern struct sysctl_oid sysctl__kern_sysv_shmseg; +extern struct sysctl_oid sysctl__kern_sysv_shmall; + extern struct sysctl_oid sysctl__kern_dummy; extern struct sysctl_oid sysctl__kern_ipc_maxsockbuf; extern struct sysctl_oid sysctl__kern_ipc_nmbclusters; @@ -47,6 +54,8 @@ extern struct sysctl_oid sysctl__kern_ipc_maxsockets; extern struct sysctl_oid sysctl__net_inet_icmp_icmplim; extern struct sysctl_oid sysctl__net_inet_icmp_maskrepl; extern struct sysctl_oid sysctl__net_inet_icmp_bmcastecho; +extern struct sysctl_oid sysctl__net_inet_icmp_log_redirect; +extern struct sysctl_oid sysctl__net_inet_icmp_drop_redirect; extern struct sysctl_oid sysctl__net_inet_ip_accept_sourceroute; #if IPCTL_DEFMTU @@ -65,6 +74,9 @@ extern struct sysctl_oid sysctl__net_inet_ip_redirect; extern struct sysctl_oid sysctl__net_inet_ip_sourceroute; extern struct sysctl_oid sysctl__net_inet_ip_subnets_are_local; extern struct sysctl_oid sysctl__net_inet_ip_keepfaith; +extern struct sysctl_oid sysctl__net_inet_ip_maxfragpackets; +extern struct sysctl_oid sysctl__net_inet_ip_check_interface; +extern struct sysctl_oid sysctl__net_inet_ip_check_route_selfref; #if NGIF > 0 extern struct sysctl_oid sysctl__net_inet_ip_gifttl; #endif @@ -84,6 +96,11 @@ extern struct sysctl_oid sysctl__net_inet_ip_fw_one_pass; extern struct sysctl_oid sysctl__net_inet_ip_fw; #endif +extern struct sysctl_oid sysctl__net_inet_ip_linklocal; +extern struct sysctl_oid sysctl__net_inet_ip_linklocal_stat; +extern struct sysctl_oid sysctl__net_inet_ip_linklocal_in; +extern struct sysctl_oid sysctl__net_inet_ip_linklocal_in_allowbadttl; + extern struct sysctl_oid sysctl__net_inet_raw_maxdgram; extern struct sysctl_oid sysctl__net_inet_raw_recvspace; extern struct sysctl_oid sysctl__net_inet_tcp_always_keepalive; @@ -97,13 +114,31 @@ extern struct sysctl_oid sysctl__net_inet_tcp_keepinit; extern struct sysctl_oid sysctl__net_inet_tcp_keepintvl; extern struct sysctl_oid sysctl__net_inet_tcp_mssdflt; extern struct sysctl_oid sysctl__net_inet_tcp_recvspace; -extern struct sysctl_oid sysctl__net_inet_tcp_rttdflt; extern struct sysctl_oid sysctl__net_inet_tcp_sendspace; -extern struct sysctl_oid sysctl__net_inet_tcp_v6mssdflt; +extern struct sysctl_oid sysctl__net_inet_tcp_blackhole; +extern struct sysctl_oid sysctl__net_inet_tcp_tcp_lq_overflow; +extern struct sysctl_oid sysctl__net_inet_tcp_path_mtu_discovery; +extern struct sysctl_oid sysctl__net_inet_tcp_slowstart_flightsize; +extern struct sysctl_oid sysctl__net_inet_tcp_local_slowstart_flightsize; +extern struct sysctl_oid sysctl__net_inet_tcp_newreno; +extern struct sysctl_oid sysctl__net_inet_tcp_tcbhashsize; +extern struct sysctl_oid sysctl__net_inet_tcp_do_tcpdrain; +extern struct sysctl_oid sysctl__net_inet_tcp_icmp_may_rst; +extern struct sysctl_oid sysctl__net_inet_tcp_strict_rfc1948; +extern struct sysctl_oid sysctl__net_inet_tcp_delacktime; +extern struct sysctl_oid sysctl__net_inet_tcp_isn_reseed_interval; +extern struct sysctl_oid sysctl__net_inet_tcp_msl; +#if TCP_DROP_SYNFIN +extern struct sysctl_oid sysctl__net_inet_tcp_drop_synfin; +#endif +#if TCPDEBUG +extern struct sysctl_oid sysctl__net_inet_tcp_tcpconsdebug; +#endif extern struct sysctl_oid sysctl__net_inet_udp_log_in_vain; extern struct sysctl_oid sysctl__net_inet_udp_checksum; extern struct sysctl_oid sysctl__net_inet_udp_maxdgram; extern struct sysctl_oid sysctl__net_inet_udp_recvspace; +extern struct sysctl_oid sysctl__net_inet_udp_blackhole; #if NETAT extern struct sysctl_oid sysctl__net_appletalk_debug; @@ -126,6 +161,7 @@ extern struct sysctl_oid sysctl__net_link_ether_inet_maxtries; extern struct sysctl_oid sysctl__net_link_ether_inet_proxyall; extern struct sysctl_oid sysctl__net_link_ether_inet_prune_intvl; extern struct sysctl_oid sysctl__net_link_ether_inet_useloopback; +extern struct sysctl_oid sysctl__net_link_ether_inet_log_arp_wrong_iface; extern struct sysctl_oid sysctl__net_link_ether_inet_apple_hwcksum_tx; extern struct sysctl_oid sysctl__net_link_ether_inet_apple_hwcksum_rx; @@ -165,6 +201,8 @@ extern struct sysctl_oid sysctl__vfs_nfs_nfsstats; #endif extern struct sysctl_oid sysctl__kern_ipc; +extern struct sysctl_oid sysctl__kern_sysv; + extern struct sysctl_oid sysctl__net_inet; #if NETAT @@ -222,8 +260,10 @@ extern struct sysctl_oid sysctl__vfs; extern struct sysctl_oid sysctl__sysctl; #if INET6 +extern struct sysctl_oid sysctl__net_inet_tcp_v6mssdflt; extern struct sysctl_oid sysctl__net_inet6; extern struct sysctl_oid sysctl__net_inet6_ip6; +extern struct sysctl_oid sysctl__net_inet6_ip6_stats; extern struct sysctl_oid sysctl__net_inet6_icmp6; extern struct sysctl_oid sysctl__net_inet6_ip6_forwarding; extern struct sysctl_oid sysctl__net_inet6_ip6_redirect; @@ -240,9 +280,16 @@ extern struct sysctl_oid sysctl__net_inet6_ip6_gifhlim; extern struct sysctl_oid sysctl__net_inet6_ip6_kame_version; extern struct sysctl_oid sysctl__net_inet6_ip6_use_deprecated; extern struct sysctl_oid sysctl__net_inet6_ip6_rr_prune; -#if MAPPED_ADDR_ENABLED -extern struct sysctl_oid sysctl__net_inet6_ip6_mapped_addr; -#endif +extern struct sysctl_oid sysctl__net_inet6_ip6_use_tempaddr; +extern struct sysctl_oid sysctl__net_inet6_ip6_v6only; +extern struct sysctl_oid sysctl__net_inet6_ip6_auto_linklocal; +extern struct sysctl_oid sysctl__net_inet6_ip6_rip6stats; +extern struct sysctl_oid sysctl__net_inet6_ip6_rtexpire; +extern struct sysctl_oid sysctl__net_inet6_ip6_rtminexpire; +extern struct sysctl_oid sysctl__net_inet6_ip6_rtmaxcache; +extern struct sysctl_oid sysctl__net_inet6_ip6_temppltime; +extern struct sysctl_oid sysctl__net_inet6_ip6_tempvltime; +extern struct sysctl_oid sysctl__net_inet6_ip6_auto_on; #if IPV6FIREWALL extern struct sysctl_oid sysctl__net_inet6_ip6_fw; extern struct sysctl_oid sysctl__net_inet6_ip6_fw_debug; @@ -251,7 +298,11 @@ extern struct sysctl_oid sysctl__net_inet6_ip6_fw_verbose_limit; #endif extern struct sysctl_oid sysctl__net_inet6_icmp6_rediraccept; extern struct sysctl_oid sysctl__net_inet6_icmp6_redirtimeout; -extern struct sysctl_oid sysctl__net_inet6_icmp6_errratelimit; +extern struct sysctl_oid sysctl__net_inet6_icmp6_stats; +extern struct sysctl_oid sysctl__net_inet6_icmp6_nodeinfo; +extern struct sysctl_oid sysctl__net_inet6_icmp6_errppslimit; +extern struct sysctl_oid sysctl__net_inet6_icmp6_nd6_maxnudhint; +extern struct sysctl_oid sysctl__net_inet6_icmp6_nd6_debug; extern struct sysctl_oid sysctl__net_inet6_icmp6_nd6_prune; extern struct sysctl_oid sysctl__net_inet6_icmp6_nd6_delay; extern struct sysctl_oid sysctl__net_inet6_icmp6_nd6_umaxtries; @@ -260,29 +311,32 @@ extern struct sysctl_oid sysctl__net_inet6_icmp6_nd6_useloopback; extern struct sysctl_oid sysctl__net_inet6_icmp6_nodeinfo; #if IPSEC extern struct sysctl_oid sysctl__net_inet6_ipsec6; +extern struct sysctl_oid sysctl__net_inet6_ipsec6_stats; extern struct sysctl_oid sysctl__net_inet6_ipsec6_def_policy; extern struct sysctl_oid sysctl__net_inet6_ipsec6_esp_trans_deflev; extern struct sysctl_oid sysctl__net_inet6_ipsec6_esp_net_deflev; extern struct sysctl_oid sysctl__net_inet6_ipsec6_ah_trans_deflev; extern struct sysctl_oid sysctl__net_inet6_ipsec6_ah_net_deflev; -extern struct sysctl_oid sysctl__net_inet6_ipsec6_inbound_call_ike; extern struct sysctl_oid sysctl__net_inet6_ipsec6_ecn; extern struct sysctl_oid sysctl__net_inet6_ipsec6_debug; +extern struct sysctl_oid sysctl__net_inet6_ipsec6_esp_randpad; #endif #endif #if IPSEC extern struct sysctl_oid sysctl__net_inet_ipsec; +extern struct sysctl_oid sysctl__net_inet_ipsec_bypass; extern struct sysctl_oid sysctl__net_inet_ipsec_def_policy; +extern struct sysctl_oid sysctl__net_inet_ipsec_esp_randpad; extern struct sysctl_oid sysctl__net_inet_ipsec_esp_trans_deflev; extern struct sysctl_oid sysctl__net_inet_ipsec_esp_net_deflev; extern struct sysctl_oid sysctl__net_inet_ipsec_ah_trans_deflev; extern struct sysctl_oid sysctl__net_inet_ipsec_ah_net_deflev; -extern struct sysctl_oid sysctl__net_inet_ipsec_inbound_call_ike; extern struct sysctl_oid sysctl__net_inet_ipsec_ah_cleartos; extern struct sysctl_oid sysctl__net_inet_ipsec_ah_offsetmask; extern struct sysctl_oid sysctl__net_inet_ipsec_dfbit; extern struct sysctl_oid sysctl__net_inet_ipsec_ecn; extern struct sysctl_oid sysctl__net_inet_ipsec_debug; +extern struct sysctl_oid sysctl__net_inet_ipsec_stats; extern struct sysctl_oid sysctl__net_key; extern struct sysctl_oid sysctl__net_key_debug; extern struct sysctl_oid sysctl__net_key_spi_trycnt; @@ -292,6 +346,8 @@ extern struct sysctl_oid sysctl__net_key_int_random; extern struct sysctl_oid sysctl__net_key_larval_lifetime; extern struct sysctl_oid sysctl__net_key_blockacq_count; extern struct sysctl_oid sysctl__net_key_blockacq_lifetime; +extern struct sysctl_oid sysctl__net_key_esp_keymin; +extern struct sysctl_oid sysctl__net_key_ah_keymin; #endif @@ -303,7 +359,8 @@ struct sysctl_oid *newsysctl_list[] = &sysctl__debug, &sysctl__vfs, &sysctl__sysctl, - &sysctl__debug_bpf_bufsize + &sysctl__debug_bpf_bufsize, + &sysctl__debug_bpf_maxbufsize #if TUN ,&sysctl__debug_if_tun_debug #endif @@ -314,6 +371,11 @@ struct sysctl_oid *newsysctl_list[] = #endif #endif + ,&sysctl__kern_sysv_shmmax + ,&sysctl__kern_sysv_shmmin + ,&sysctl__kern_sysv_shmmni + ,&sysctl__kern_sysv_shmseg + ,&sysctl__kern_sysv_shmall ,&sysctl__kern_dummy ,&sysctl__kern_ipc_maxsockbuf ,&sysctl__kern_ipc_nmbclusters @@ -324,6 +386,8 @@ struct sysctl_oid *newsysctl_list[] = ,&sysctl__net_inet_icmp_icmplim ,&sysctl__net_inet_icmp_maskrepl ,&sysctl__net_inet_icmp_bmcastecho + ,&sysctl__net_inet_icmp_drop_redirect + ,&sysctl__net_inet_icmp_log_redirect ,&sysctl__net_inet_ip_accept_sourceroute #if IPCTL_DEFMTU ,&sysctl__net_inet_ip_mtu @@ -340,6 +404,9 @@ struct sysctl_oid *newsysctl_list[] = ,&sysctl__net_inet_ip_sourceroute ,&sysctl__net_inet_ip_subnets_are_local ,&sysctl__net_inet_ip_keepfaith + ,&sysctl__net_inet_ip_maxfragpackets + ,&sysctl__net_inet_ip_check_interface + ,&sysctl__net_inet_ip_check_route_selfref #if NGIF > 0 ,&sysctl__net_inet_ip_gifttl #endif @@ -357,6 +424,10 @@ struct sysctl_oid *newsysctl_list[] = ,&sysctl__net_inet_ip_fw_one_pass ,&sysctl__net_inet_ip_fw #endif + ,&sysctl__net_inet_ip_linklocal + ,&sysctl__net_inet_ip_linklocal_stat + ,&sysctl__net_inet_ip_linklocal_in + ,&sysctl__net_inet_ip_linklocal_in_allowbadttl ,&sysctl__net_inet_raw_maxdgram ,&sysctl__net_inet_raw_recvspace ,&sysctl__net_inet_tcp_always_keepalive @@ -370,13 +441,31 @@ struct sysctl_oid *newsysctl_list[] = ,&sysctl__net_inet_tcp_keepintvl ,&sysctl__net_inet_tcp_mssdflt ,&sysctl__net_inet_tcp_recvspace - ,&sysctl__net_inet_tcp_rttdflt ,&sysctl__net_inet_tcp_sendspace - ,&sysctl__net_inet_tcp_v6mssdflt + ,&sysctl__net_inet_tcp_blackhole + ,&sysctl__net_inet_tcp_tcp_lq_overflow + ,&sysctl__net_inet_tcp_path_mtu_discovery + ,&sysctl__net_inet_tcp_slowstart_flightsize + ,&sysctl__net_inet_tcp_local_slowstart_flightsize + ,&sysctl__net_inet_tcp_newreno + ,&sysctl__net_inet_tcp_tcbhashsize + ,&sysctl__net_inet_tcp_do_tcpdrain + ,&sysctl__net_inet_tcp_icmp_may_rst + ,&sysctl__net_inet_tcp_strict_rfc1948 + ,&sysctl__net_inet_tcp_delacktime + ,&sysctl__net_inet_tcp_isn_reseed_interval + ,&sysctl__net_inet_tcp_msl +#if TCP_DROP_SYNFIN + ,&sysctl__net_inet_tcp_drop_synfin +#endif +#if TCPDEBUG + ,&sysctl__net_inet_tcp_tcpconsdebug +#endif ,&sysctl__net_inet_udp_log_in_vain ,&sysctl__net_inet_udp_checksum ,&sysctl__net_inet_udp_maxdgram ,&sysctl__net_inet_udp_recvspace + ,&sysctl__net_inet_udp_blackhole #if NETAT ,&sysctl__net_appletalk_debug @@ -400,6 +489,7 @@ struct sysctl_oid *newsysctl_list[] = ,&sysctl__net_link_ether_inet_proxyall ,&sysctl__net_link_ether_inet_prune_intvl ,&sysctl__net_link_ether_inet_useloopback + ,&sysctl__net_link_ether_inet_log_arp_wrong_iface ,&sysctl__net_link_ether_inet_apple_hwcksum_tx ,&sysctl__net_link_ether_inet_apple_hwcksum_rx #if NETMIBS @@ -436,6 +526,7 @@ struct sysctl_oid *newsysctl_list[] = ,&sysctl__vfs_nfs_nfsstats #endif ,&sysctl__kern_ipc + ,&sysctl__kern_sysv ,&sysctl__net_inet #if NETAT ,&sysctl__net_appletalk @@ -482,6 +573,7 @@ struct sysctl_oid *newsysctl_list[] = ,&sysctl__net_inet6 ,&sysctl__net_inet6_ip6 ,&sysctl__net_inet6_icmp6 + ,&sysctl__net_inet6_ip6_stats ,&sysctl__net_inet6_ip6_forwarding ,&sysctl__net_inet6_ip6_redirect ,&sysctl__net_inet6_ip6_hlim @@ -497,18 +589,29 @@ struct sysctl_oid *newsysctl_list[] = ,&sysctl__net_inet6_ip6_kame_version ,&sysctl__net_inet6_ip6_use_deprecated ,&sysctl__net_inet6_ip6_rr_prune -#if MAPPED_ADDR_ENABLED - ,&sysctl__net_inet6_ip6_mapped_addr -#endif + ,&sysctl__net_inet6_ip6_use_tempaddr + ,&sysctl__net_inet6_ip6_v6only + ,&sysctl__net_inet6_ip6_auto_linklocal + ,&sysctl__net_inet6_ip6_rip6stats + ,&sysctl__net_inet6_ip6_rtexpire + ,&sysctl__net_inet6_ip6_rtminexpire + ,&sysctl__net_inet6_ip6_rtmaxcache + ,&sysctl__net_inet6_ip6_temppltime + ,&sysctl__net_inet6_ip6_tempvltime + ,&sysctl__net_inet6_ip6_auto_on ,&sysctl__net_inet6_icmp6_rediraccept ,&sysctl__net_inet6_icmp6_redirtimeout - ,&sysctl__net_inet6_icmp6_errratelimit ,&sysctl__net_inet6_icmp6_nd6_prune ,&sysctl__net_inet6_icmp6_nd6_delay ,&sysctl__net_inet6_icmp6_nd6_umaxtries ,&sysctl__net_inet6_icmp6_nd6_mmaxtries ,&sysctl__net_inet6_icmp6_nd6_useloopback ,&sysctl__net_inet6_icmp6_nodeinfo + ,&sysctl__net_inet6_icmp6_stats + ,&sysctl__net_inet6_icmp6_errppslimit + ,&sysctl__net_inet6_icmp6_nd6_maxnudhint + ,&sysctl__net_inet6_icmp6_nd6_debug + ,&sysctl__net_inet_tcp_v6mssdflt #if IPV6FIREWALL ,&sysctl__net_inet6_ip6_fw ,&sysctl__net_inet6_ip6_fw_debug @@ -516,15 +619,16 @@ struct sysctl_oid *newsysctl_list[] = ,&sysctl__net_inet6_ip6_fw_verbose_limit #endif #if IPSEC - ,&sysctl__net_inet6_ipsec6 + ,&sysctl__net_inet6_ipsec6 + ,&sysctl__net_inet6_ipsec6_stats ,&sysctl__net_inet6_ipsec6_def_policy ,&sysctl__net_inet6_ipsec6_esp_trans_deflev ,&sysctl__net_inet6_ipsec6_esp_net_deflev ,&sysctl__net_inet6_ipsec6_ah_trans_deflev ,&sysctl__net_inet6_ipsec6_ah_net_deflev - ,&sysctl__net_inet6_ipsec6_inbound_call_ike ,&sysctl__net_inet6_ipsec6_ecn ,&sysctl__net_inet6_ipsec6_debug + ,&sysctl__net_inet6_ipsec6_esp_randpad #endif #endif #if IPSEC @@ -537,18 +641,22 @@ struct sysctl_oid *newsysctl_list[] = ,&sysctl__net_key_larval_lifetime ,&sysctl__net_key_blockacq_count ,&sysctl__net_key_blockacq_lifetime + ,&sysctl__net_key_esp_keymin + ,&sysctl__net_key_ah_keymin ,&sysctl__net_inet_ipsec + ,&sysctl__net_inet_ipsec_stats ,&sysctl__net_inet_ipsec_def_policy ,&sysctl__net_inet_ipsec_esp_trans_deflev ,&sysctl__net_inet_ipsec_esp_net_deflev ,&sysctl__net_inet_ipsec_ah_trans_deflev ,&sysctl__net_inet_ipsec_ah_net_deflev - ,&sysctl__net_inet_ipsec_inbound_call_ike ,&sysctl__net_inet_ipsec_ah_cleartos ,&sysctl__net_inet_ipsec_ah_offsetmask ,&sysctl__net_inet_ipsec_dfbit ,&sysctl__net_inet_ipsec_ecn ,&sysctl__net_inet_ipsec_debug + ,&sysctl__net_inet_ipsec_esp_randpad + ,&sysctl__net_inet_ipsec_bypass #endif ,(struct sysctl_oid *) 0 }; diff --git a/bsd/kern/sysv_ipc.c b/bsd/kern/sysv_ipc.c index 321125c84..e39505b70 100644 --- a/bsd/kern/sysv_ipc.c +++ b/bsd/kern/sysv_ipc.c @@ -71,7 +71,7 @@ ipcperm(cred, perm, mode) int mode; { - if (suser(cred, (u_short *)NULL)) + if (!suser(cred, (u_short *)NULL)) return (0); /* Check for user match. */ @@ -93,82 +93,6 @@ ipcperm(cred, perm, mode) - -/* - * SYSVSEM stubs - */ - -int -semsys(p, uap) - struct proc *p; -#if 0 - struct semsys_args *uap; -#else - void *uap; -#endif -{ - return(EOPNOTSUPP); -}; - -int -semconfig(p, uap) - struct proc *p; -#if 0 - struct semconfig_args *uap; -#else - void *uap; -#endif -{ - return(EOPNOTSUPP); -}; - -int -semctl(p, uap) - struct proc *p; -#if 0 - register struct semctl_args *uap; -#else - void *uap; -#endif -{ - return(EOPNOTSUPP); -}; - -int -semget(p, uap) - struct proc *p; -#if 0 - register struct semget_args *uap; -#else - void *uap; -#endif -{ - return(EOPNOTSUPP); -}; - -int -semop(p, uap) - struct proc *p; -#if 0 - register struct semop_args *uap; -#else - void *uap; -#endif -{ - return(EOPNOTSUPP); -}; - -/* called from kern_exit.c */ -void -semexit(p) - struct proc *p; -{ - return; -} - - - - /* * SYSVMSG stubs */ diff --git a/bsd/kern/sysv_sem.c b/bsd/kern/sysv_sem.c index b49976487..7061dadc1 100644 --- a/bsd/kern/sysv_sem.c +++ b/bsd/kern/sysv_sem.c @@ -26,92 +26,158 @@ * * This software is provided ``AS IS'' without any warranties of any kind. */ +/* + * John Bellardo modified the implementation for Darwin. 12/2000 + */ #include #include -#include #include #include #include -#include +#include +#include + +#include +#include + +/*#include */ +/*#include */ + +/* Uncomment this line to see the debugging output */ +/* #define SEM_DEBUG */ + +/* Macros to deal with the semaphore subsystem lock. The lock currently uses + * the semlock_holder static variable as a mutex. NULL means no lock, any + * value other than NULL means locked. semlock_holder is used because it was + * present in the code before the Darwin port, and for no other reason. + * When the time comes to relax the funnel requirements of the kernel only + * these macros should need to be changed. A spin lock would work well. + */ +/* Aquire the lock */ +#define SUBSYSTEM_LOCK_AQUIRE(p) { sysv_sem_aquiring_threads++; \ + while (semlock_holder != NULL) \ + (void) tsleep((caddr_t)&semlock_holder, (PZERO - 4), "sysvsem", 0); \ + semlock_holder = p; \ + sysv_sem_aquiring_threads--; } + +/* Release the lock */ +#define SUBSYSTEM_LOCK_RELEASE { semlock_holder = NULL; wakeup((caddr_t)&semlock_holder); } + +/* Release the lock and return a value */ +#define UNLOCK_AND_RETURN(ret) { SUBSYSTEM_LOCK_RELEASE; return(ret); } + +#define M_SYSVSEM M_SUBPROC +#if 0 static void seminit __P((void *)); SYSINIT(sysv_sem, SI_SUB_SYSV_SEM, SI_ORDER_FIRST, seminit, NULL) +#endif 0 -#ifndef _SYS_SYSPROTO_H_ -struct __semctl_args; -int __semctl __P((struct proc *p, struct __semctl_args *uap)); +/* Hard system limits to avoid resource starvation / DOS attacks. + * These are not needed if we can make the semaphore pages swappable. + */ +static struct seminfo limitseminfo = { + SEMMAP, /* # of entries in semaphore map */ + SEMMNI, /* # of semaphore identifiers */ + SEMMNS, /* # of semaphores in system */ + SEMMNU, /* # of undo structures in system */ + SEMMSL, /* max # of semaphores per id */ + SEMOPM, /* max # of operations per semop call */ + SEMUME, /* max # of undo entries per process */ + SEMUSZ, /* size in bytes of undo structure */ + SEMVMX, /* semaphore maximum value */ + SEMAEM /* adjust on exit max value */ +}; + +/* Current system allocations. We use this structure to track how many + * resources we have allocated so far. This way we can set large hard limits + * and not allocate the memory for them up front. + */ +struct seminfo seminfo = { + SEMMAP, /* Unused, # of entries in semaphore map */ + 0, /* # of semaphore identifiers */ + 0, /* # of semaphores in system */ + 0, /* # of undo entries in system */ + SEMMSL, /* max # of semaphores per id */ + SEMOPM, /* max # of operations per semop call */ + SEMUME, /* max # of undo entries per process */ + SEMUSZ, /* size in bytes of undo structure */ + SEMVMX, /* semaphore maximum value */ + SEMAEM /* adjust on exit max value */ +}; + +/* A counter so the module unload code knows when there are no more processes using + * the sysv_sem code */ +static long sysv_sem_sleeping_threads = 0; +static long sysv_sem_aquiring_threads = 0; + +struct semctl_args; +int semctl __P((struct proc *p, struct semctl_args *uap, int *)); struct semget_args; -int semget __P((struct proc *p, struct semget_args *uap)); +int semget __P((struct proc *p, struct semget_args *uap, int *)); struct semop_args; -int semop __P((struct proc *p, struct semop_args *uap)); +int semop __P((struct proc *p, struct semop_args *uap, int *)); struct semconfig_args; -int semconfig __P((struct proc *p, struct semconfig_args *uap)); -#endif +int semconfig __P((struct proc *p, struct semconfig_args *uap, int *)); + static struct sem_undo *semu_alloc __P((struct proc *p)); static int semundo_adjust __P((struct proc *p, struct sem_undo **supptr, int semid, int semnum, int adjval)); static void semundo_clear __P((int semid, int semnum)); +typedef int sy_call_t __P((struct proc *, void *, int *)); + /* XXX casting to (sy_call_t *) is bogus, as usual. */ static sy_call_t *semcalls[] = { - (sy_call_t *)__semctl, (sy_call_t *)semget, + (sy_call_t *)semctl, (sy_call_t *)semget, (sy_call_t *)semop, (sy_call_t *)semconfig }; -static int semtot = 0; -struct semid_ds *sema; /* semaphore id pool */ -struct sem *sem; /* semaphore pool */ -static struct sem_undo *semu_list; /* list of active undo structures */ -int *semu; /* undo structure pool */ +static int semtot = 0; /* # of used semaphores */ +struct semid_ds *sema = NULL; /* semaphore id pool */ +struct sem *sem = NULL; /* semaphore pool */ +static struct sem_undo *semu_list = NULL; /* list of active undo structures */ +struct sem_undo *semu = NULL; /* semaphore undo pool */ static struct proc *semlock_holder = NULL; +/* seminit no longer needed. The data structures are grown dynamically */ void -seminit(dummy) - void *dummy; +seminit() { - register int i; - - if (sema == NULL) - panic("sema is NULL"); - if (semu == NULL) - panic("semu is NULL"); - - for (i = 0; i < seminfo.semmni; i++) { - sema[i].sem_base = 0; - sema[i].sem_perm.mode = 0; - } - for (i = 0; i < seminfo.semmnu; i++) { - register struct sem_undo *suptr = SEMU(i); - suptr->un_proc = NULL; - } - semu_list = NULL; } /* * Entry point for all SEM calls + * + * In Darwin this is no longer the entry point. It will be removed after + * the code has been tested better. */ +struct semsys_args { + u_int which; + int a2; + int a3; + int a4; + int a5; +}; int -semsys(p, uap) +semsys(p, uap, retval) struct proc *p; /* XXX actually varargs. */ - struct semsys_args /* { - u_int which; - int a2; - int a3; - int a4; - int a5; - } */ *uap; + struct semsys_args *uap; + register_t *retval; { - while (semlock_holder != NULL && semlock_holder != p) + /* The individual calls handling the locking now */ + /*while (semlock_holder != NULL && semlock_holder != p) (void) tsleep((caddr_t)&semlock_holder, (PZERO - 4), "semsys", 0); + */ if (uap->which >= sizeof(semcalls)/sizeof(semcalls[0])) return (EINVAL); - return ((*semcalls[uap->which])(p, &uap->a2)); + return ((*semcalls[uap->which])(p, &uap->a2, retval)); } /* @@ -136,20 +202,20 @@ struct semconfig_args { #endif int -semconfig(p, uap) +semconfig(p, uap, retval) struct proc *p; struct semconfig_args *uap; + register_t *retval; { int eval = 0; switch (uap->flag) { case SEM_CONFIG_FREEZE: - semlock_holder = p; + SUBSYSTEM_LOCK_AQUIRE(p); break; case SEM_CONFIG_THAW: - semlock_holder = NULL; - wakeup((caddr_t)&semlock_holder); + SUBSYSTEM_LOCK_RELEASE; break; default: @@ -159,13 +225,215 @@ semconfig(p, uap) break; } - p->p_retval[0] = 0; + *retval = 0; return(eval); } +/* Expand the semu array to the given capacity. If the expansion fails + * return 0, otherwise return 1. + * + * Assumes we already have the subsystem lock. + */ +static int +grow_semu_array(newSize) + int newSize; +{ + register int i, j; + register struct sem_undo *newSemu; + if (newSize <= seminfo.semmnu) + return 0; + if (newSize > limitseminfo.semmnu) /* enforce hard limit */ + { +#ifdef SEM_DEBUG + printf("undo structure hard limit of %d reached, requested %d\n", + limitseminfo.semmnu, newSize); +#endif + return 0; + } + newSize = (newSize/SEMMNU_INC + 1) * SEMMNU_INC; + newSize = newSize > limitseminfo.semmnu ? limitseminfo.semmnu : newSize; + +#ifdef SEM_DEBUG + printf("growing semu[] from %d to %d\n", seminfo.semmnu, newSize); +#endif + MALLOC(newSemu, struct sem_undo*, sizeof(struct sem_undo)*newSize, + M_SYSVSEM, M_WAITOK); + if (NULL == newSemu) + { +#ifdef SEM_DEBUG + printf("allocation failed. no changes made.\n"); +#endif + return 0; + } + + /* Initialize our structure. */ + for (i = 0; i < seminfo.semmnu; i++) + { + newSemu[i] = semu[i]; + for(j = 0; j < SEMUME; j++) /* Is this really needed? */ + newSemu[i].un_ent[j] = semu[i].un_ent[j]; + } + for (i = seminfo.semmnu; i < newSize; i++) + { + newSemu[i].un_proc = NULL; + } + + /* Clean up the old array */ + if (semu) + FREE(semu, M_SYSVSEM); + + semu = newSemu; + seminfo.semmnu = newSize; +#ifdef SEM_DEBUG + printf("expansion successful\n"); +#endif + return 1; +} + +/* + * Expand the sema array to the given capacity. If the expansion fails + * we return 0, otherwise we return 1. + * + * Assumes we already have the subsystem lock. + */ +static int +grow_sema_array(newSize) + int newSize; +{ + register struct semid_ds *newSema; + register int i; + + if (newSize <= seminfo.semmni) + return 0; + if (newSize > limitseminfo.semmni) /* enforce hard limit */ + { +#ifdef SEM_DEBUG + printf("identifier hard limit of %d reached, requested %d\n", + limitseminfo.semmni, newSize); +#endif + return 0; + } + newSize = (newSize/SEMMNI_INC + 1) * SEMMNI_INC; + newSize = newSize > limitseminfo.semmni ? limitseminfo.semmni : newSize; + +#ifdef SEM_DEBUG + printf("growing sema[] from %d to %d\n", seminfo.semmni, newSize); +#endif + MALLOC(newSema, struct semid_ds*, sizeof(struct semid_ds)*newSize, + M_SYSVSEM, M_WAITOK); + if (NULL == newSema) + { +#ifdef SEM_DEBUG + printf("allocation failed. no changes made.\n"); +#endif + return 0; + } + + /* Initialize our new ids, and copy over the old ones */ + for (i = 0; i < seminfo.semmni; i++) + { + newSema[i] = sema[i]; + /* This is a hack. What we really want to be able to + * do is change the value a process is waiting on + * without waking it up, but I don't know how to do + * this with the existing code, so we wake up the + * process and let it do a lot of work to determine the + * semaphore set is really not available yet, and then + * sleep on the correct, reallocated semid_ds pointer. + */ + if (sema[i].sem_perm.mode & SEM_ALLOC) + wakeup((caddr_t)&sema[i]); + } + + for (i = seminfo.semmni; i < newSize; i++) + { + newSema[i].sem_base = 0; + newSema[i].sem_perm.mode = 0; + } + + /* Clean up the old array */ + if (sema) + FREE(sema, M_SYSVSEM); + + sema = newSema; + seminfo.semmni = newSize; +#ifdef SEM_DEBUG + printf("expansion successful\n"); +#endif + return 1; +} + +/* + * Expand the sem array to the given capacity. If the expansion fails + * we return 0 (fail), otherwise we return 1 (success). + * + * Assumes we already hold the subsystem lock. + */ +static int +grow_sem_array(newSize) + int newSize; +{ + register struct sem *newSem = NULL; + register int i; + + if (newSize < semtot) + return 0; + if (newSize > limitseminfo.semmns) /* enforce hard limit */ + { +#ifdef SEM_DEBUG + printf("semaphore hard limit of %d reached, requested %d\n", + limitseminfo.semmns, newSize); +#endif + return 0; + } + newSize = (newSize/SEMMNS_INC + 1) * SEMMNS_INC; + newSize = newSize > limitseminfo.semmns ? limitseminfo.semmns : newSize; + +#ifdef SEM_DEBUG + printf("growing sem array from %d to %d\n", seminfo.semmns, newSize); +#endif + MALLOC(newSem, struct sem*, sizeof(struct sem)*newSize, + M_SYSVSEM, M_WAITOK); + if (NULL == newSem) + { +#ifdef SEM_DEBUG + printf("allocation failed. no changes made.\n"); +#endif + return 0; + } + + /* We have our new memory, now copy the old contents over */ + if (sem) + for(i = 0; i < seminfo.semmns; i++) + newSem[i] = sem[i]; + + /* Update our id structures to point to the new semaphores */ + for(i = 0; i < seminfo.semmni; i++) + if (sema[i].sem_perm.mode & SEM_ALLOC) /* ID in use */ + { + if (newSem > sem) + sema[i].sem_base += newSem - sem; + else + sema[i].sem_base -= sem - newSem; + } + + /* clean up the old array */ + if (sem) + FREE(sem, M_SYSVSEM); + + sem = newSem; + seminfo.semmns = newSize; +#ifdef SEM_DEBUG + printf("expansion complete\n"); +#endif + return 1; +} + /* * Allocate a new sem_undo structure for a process * (returns ptr to structure or NULL if no more room) + * + * Assumes we already hold the subsystem lock. */ static struct sem_undo * @@ -219,9 +487,14 @@ semu_alloc(p) supptr = &(suptr->un_next); } - /* If we didn't free anything then just give-up */ + /* If we didn't free anything. Try expanding + * the semu[] array. If that doesn't work + * then fail. We expand last to get the + * most reuse out of existing resources. + */ if (!did_something) - return(NULL); + if (!grow_semu_array(seminfo.semmnu + 1)) + return(NULL); } else { /* * The second pass failed even though we freed @@ -236,6 +509,8 @@ semu_alloc(p) /* * Adjust a particular entry for a particular proc + * + * Assumes we already hold the subsystem lock. */ static int @@ -305,6 +580,8 @@ semundo_adjust(p, supptr, semid, semnum, adjval) return(0); } +/* Assumes we already hold the subsystem lock. + */ static void semundo_clear(semid, semnum) int semid, semnum; @@ -337,41 +614,48 @@ semundo_clear(semid, semnum) * Note that the user-mode half of this passes a union, not a pointer */ #ifndef _SYS_SYSPROTO_H_ -struct __semctl_args { +struct semctl_args { int semid; int semnum; int cmd; - union semun *arg; + union semun arg; }; #endif int -__semctl(p, uap) +semctl(p, uap, retval) struct proc *p; - register struct __semctl_args *uap; + register struct semctl_args *uap; + register_t *retval; { int semid = uap->semid; int semnum = uap->semnum; int cmd = uap->cmd; - union semun *arg = uap->arg; + union semun arg = uap->arg; union semun real_arg; struct ucred *cred = p->p_ucred; int i, rval, eval; struct semid_ds sbuf; register struct semid_ds *semaptr; + SUBSYSTEM_LOCK_AQUIRE(p); #ifdef SEM_DEBUG printf("call to semctl(%d, %d, %d, 0x%x)\n", semid, semnum, cmd, arg); #endif semid = IPCID_TO_IX(semid); if (semid < 0 || semid >= seminfo.semmsl) - return(EINVAL); +{ +#ifdef SEM_DEBUG + printf("Invalid semid\n"); +#endif + UNLOCK_AND_RETURN(EINVAL); +} semaptr = &sema[semid]; if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 || semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) - return(EINVAL); + UNLOCK_AND_RETURN(EINVAL); eval = 0; rval = 0; @@ -379,7 +663,7 @@ __semctl(p, uap) switch (cmd) { case IPC_RMID: if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_M))) - return(eval); + UNLOCK_AND_RETURN(eval); semaptr->sem_perm.cuid = cred->cr_uid; semaptr->sem_perm.uid = cred->cr_uid; semtot -= semaptr->sem_nsems; @@ -397,12 +681,12 @@ __semctl(p, uap) case IPC_SET: if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_M))) - return(eval); - if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0) - return(eval); - if ((eval = copyin(real_arg.buf, (caddr_t)&sbuf, + UNLOCK_AND_RETURN(eval); + /*if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0) + UNLOCK_AND_RETURN(eval);*/ + if ((eval = copyin(arg.buf, (caddr_t)&sbuf, sizeof(sbuf))) != 0) - return(eval); + UNLOCK_AND_RETURN(eval); semaptr->sem_perm.uid = sbuf.sem_perm.uid; semaptr->sem_perm.gid = sbuf.sem_perm.gid; semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777) | @@ -412,45 +696,45 @@ __semctl(p, uap) case IPC_STAT: if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R))) - return(eval); - if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0) - return(eval); - eval = copyout((caddr_t)semaptr, real_arg.buf, + UNLOCK_AND_RETURN(eval); + /*if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0) + UNLOCK_AND_RETURN(eval);*/ + eval = copyout((caddr_t)semaptr, arg.buf, sizeof(struct semid_ds)); break; case GETNCNT: if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R))) - return(eval); + UNLOCK_AND_RETURN(eval); if (semnum < 0 || semnum >= semaptr->sem_nsems) - return(EINVAL); + UNLOCK_AND_RETURN(EINVAL); rval = semaptr->sem_base[semnum].semncnt; break; case GETPID: if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R))) - return(eval); + UNLOCK_AND_RETURN(eval); if (semnum < 0 || semnum >= semaptr->sem_nsems) - return(EINVAL); + UNLOCK_AND_RETURN(EINVAL); rval = semaptr->sem_base[semnum].sempid; break; case GETVAL: if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R))) - return(eval); + UNLOCK_AND_RETURN(eval); if (semnum < 0 || semnum >= semaptr->sem_nsems) - return(EINVAL); + UNLOCK_AND_RETURN(EINVAL); rval = semaptr->sem_base[semnum].semval; break; case GETALL: if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R))) - return(eval); - if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0) - return(eval); + UNLOCK_AND_RETURN(eval); + /*if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0) + UNLOCK_AND_RETURN(eval);*/ for (i = 0; i < semaptr->sem_nsems; i++) { eval = copyout((caddr_t)&semaptr->sem_base[i].semval, - &real_arg.array[i], sizeof(real_arg.array[0])); + &arg.array[i], sizeof(arg.array[0])); if (eval != 0) break; } @@ -458,33 +742,48 @@ __semctl(p, uap) case GETZCNT: if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R))) - return(eval); + UNLOCK_AND_RETURN(eval); if (semnum < 0 || semnum >= semaptr->sem_nsems) - return(EINVAL); + UNLOCK_AND_RETURN(EINVAL); rval = semaptr->sem_base[semnum].semzcnt; break; case SETVAL: if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W))) - return(eval); + { +#ifdef SEM_DEBUG + printf("Invalid credentials for write\n"); +#endif + UNLOCK_AND_RETURN(eval); + } if (semnum < 0 || semnum >= semaptr->sem_nsems) - return(EINVAL); - if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0) - return(eval); - semaptr->sem_base[semnum].semval = real_arg.val; + { +#ifdef SEM_DEBUG + printf("Invalid number out of range for set\n"); +#endif + UNLOCK_AND_RETURN(EINVAL); + } + /*if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0) + { +#ifdef SEM_DEBUG + printf("Error during value copyin\n"); +#endif + UNLOCK_AND_RETURN(eval); + }*/ + semaptr->sem_base[semnum].semval = arg.val; semundo_clear(semid, semnum); wakeup((caddr_t)semaptr); break; case SETALL: if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W))) - return(eval); - if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0) - return(eval); + UNLOCK_AND_RETURN(eval); + /*if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0) + UNLOCK_AND_RETURN(eval);*/ for (i = 0; i < semaptr->sem_nsems; i++) { - eval = copyin(&real_arg.array[i], + eval = copyin(&arg.array[i], (caddr_t)&semaptr->sem_base[i].semval, - sizeof(real_arg.array[0])); + sizeof(arg.array[0])); if (eval != 0) break; } @@ -493,12 +792,12 @@ __semctl(p, uap) break; default: - return(EINVAL); + UNLOCK_AND_RETURN(EINVAL); } if (eval == 0) - p->p_retval[0] = rval; - return(eval); + *retval = rval; + UNLOCK_AND_RETURN(eval); } #ifndef _SYS_SYSPROTO_H_ @@ -510,9 +809,10 @@ struct semget_args { #endif int -semget(p, uap) +semget(p, uap, retval) struct proc *p; register struct semget_args *uap; + register_t *retval; { int semid, eval; int key = uap->key; @@ -520,10 +820,14 @@ semget(p, uap) int semflg = uap->semflg; struct ucred *cred = p->p_ucred; + SUBSYSTEM_LOCK_AQUIRE(p); #ifdef SEM_DEBUG - printf("semget(0x%x, %d, 0%o)\n", key, nsems, semflg); + if (key != IPC_PRIVATE) + printf("semget(0x%x, %d, 0%o)\n", key, nsems, semflg); + else + printf("semget(IPC_PRIVATE, %d, 0%o)\n", nsems, semflg); #endif - + if (key != IPC_PRIVATE) { for (semid = 0; semid < seminfo.semmni; semid++) { if ((sema[semid].sem_perm.mode & SEM_ALLOC) && @@ -536,25 +840,25 @@ semget(p, uap) #endif if ((eval = ipcperm(cred, &sema[semid].sem_perm, semflg & 0700))) - return(eval); + UNLOCK_AND_RETURN(eval); if (nsems > 0 && sema[semid].sem_nsems < nsems) { #ifdef SEM_DEBUG printf("too small\n"); #endif - return(EINVAL); + UNLOCK_AND_RETURN(EINVAL); } if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) { #ifdef SEM_DEBUG printf("not exclusive\n"); #endif - return(EEXIST); + UNLOCK_AND_RETURN(EEXIST); } goto found; } } #ifdef SEM_DEBUG - printf("need to allocate the semid_ds\n"); + printf("need to allocate an id for the request\n"); #endif if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) { if (nsems <= 0 || nsems > seminfo.semmsl) { @@ -562,14 +866,20 @@ semget(p, uap) printf("nsems out of range (0<%d<=%d)\n", nsems, seminfo.semmsl); #endif - return(EINVAL); + UNLOCK_AND_RETURN(EINVAL); } if (nsems > seminfo.semmns - semtot) { #ifdef SEM_DEBUG printf("not enough semaphores left (need %d, got %d)\n", nsems, seminfo.semmns - semtot); #endif - return(ENOSPC); + if (!grow_sem_array(semtot + nsems)) + { +#ifdef SEM_DEBUG + printf("failed to grow the sem array\n"); +#endif + UNLOCK_AND_RETURN(ENOSPC); + } } for (semid = 0; semid < seminfo.semmni; semid++) { if ((sema[semid].sem_perm.mode & SEM_ALLOC) == 0) @@ -577,9 +887,15 @@ semget(p, uap) } if (semid == seminfo.semmni) { #ifdef SEM_DEBUG - printf("no more semid_ds's available\n"); + printf("no more id's available\n"); #endif - return(ENOSPC); + if (!grow_sema_array(seminfo.semmni + 1)) + { +#ifdef SEM_DEBUG + printf("failed to grow sema array\n"); +#endif + UNLOCK_AND_RETURN(ENOSPC); + } } #ifdef SEM_DEBUG printf("semid %d is available\n", semid); @@ -607,11 +923,15 @@ semget(p, uap) #ifdef SEM_DEBUG printf("didn't find it and wasn't asked to create it\n"); #endif - return(ENOENT); + UNLOCK_AND_RETURN(ENOENT); } found: - p->p_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].sem_perm); + *retval = IXSEQ_TO_IPCID(semid, sema[semid].sem_perm); +#ifdef SEM_DEBUG + printf("semget is done, returning %d\n", *retval); +#endif + SUBSYSTEM_LOCK_RELEASE; return(0); } @@ -624,9 +944,10 @@ struct semop_args { #endif int -semop(p, uap) +semop(p, uap, retval) struct proc *p; register struct semop_args *uap; + register_t *retval; { int semid = uap->semid; int nsops = uap->nsops; @@ -639,6 +960,7 @@ semop(p, uap) int i, j, eval; int do_wakeup, do_undos; + SUBSYSTEM_LOCK_AQUIRE(p); #ifdef SEM_DEBUG printf("call to semop(%d, 0x%x, %d)\n", semid, sops, nsops); #endif @@ -646,34 +968,34 @@ semop(p, uap) semid = IPCID_TO_IX(semid); /* Convert back to zero origin */ if (semid < 0 || semid >= seminfo.semmsl) - return(EINVAL); + UNLOCK_AND_RETURN(EINVAL); semaptr = &sema[semid]; if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0) - return(EINVAL); + UNLOCK_AND_RETURN(EINVAL); if (semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) - return(EINVAL); + UNLOCK_AND_RETURN(EINVAL); if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W))) { #ifdef SEM_DEBUG printf("eval = %d from ipaccess\n", eval); #endif - return(eval); + UNLOCK_AND_RETURN(eval); } if (nsops > MAX_SOPS) { #ifdef SEM_DEBUG printf("too many sops (max=%d, nsops=%d)\n", MAX_SOPS, nsops); #endif - return(E2BIG); + UNLOCK_AND_RETURN(E2BIG); } if ((eval = copyin(uap->sops, &sops, nsops * sizeof(sops[0]))) != 0) { #ifdef SEM_DEBUG - printf("eval = %d from copyin(%08x, %08x, %d)\n", eval, + printf("eval = %d from copyin(%08x, %08x, %ld)\n", eval, uap->sops, &sops, nsops * sizeof(sops[0])); #endif - return(eval); + UNLOCK_AND_RETURN(eval); } /* @@ -694,7 +1016,7 @@ semop(p, uap) sopptr = &sops[i]; if (sopptr->sem_num >= semaptr->sem_nsems) - return(EFBIG); + UNLOCK_AND_RETURN(EFBIG); semptr = &semaptr->sem_base[sopptr->sem_num]; @@ -756,7 +1078,7 @@ semop(p, uap) * NOWAIT flag set then return with EAGAIN. */ if (sopptr->sem_flg & IPC_NOWAIT) - return(EAGAIN); + UNLOCK_AND_RETURN(EAGAIN); if (sopptr->sem_op == 0) semptr->semzcnt++; @@ -766,16 +1088,32 @@ semop(p, uap) #ifdef SEM_DEBUG printf("semop: good night!\n"); #endif + /* Release our lock on the semaphore subsystem so + * another thread can get at the semaphore we are + * waiting for. We will get the lock back after we + * wake up. + */ + SUBSYSTEM_LOCK_RELEASE; + sysv_sem_sleeping_threads++; eval = tsleep((caddr_t)semaptr, (PZERO - 4) | PCATCH, "semwait", 0); + sysv_sem_sleeping_threads--; + #ifdef SEM_DEBUG printf("semop: good morning (eval=%d)!\n", eval); #endif + /* There is no need to get the lock if we are just + * going to return without performing more semaphore + * operations. + */ + if (eval != 0) + return(EINTR); + SUBSYSTEM_LOCK_AQUIRE(p); /* Get it back */ suptr = NULL; /* sem_undo may have been reallocated */ + semaptr = &sema[semid]; /* sema may have been reallocated */ + - if (eval != 0) - return(EINTR); #ifdef SEM_DEBUG printf("semop: good morning!\n"); #endif @@ -788,16 +1126,19 @@ semop(p, uap) /* The man page says to return EIDRM. */ /* Unfortunately, BSD doesn't define that code! */ #ifdef EIDRM - return(EIDRM); + UNLOCK_AND_RETURN(EIDRM); #else - return(EINVAL); + UNLOCK_AND_RETURN(EINVAL); #endif } /* * The semaphore is still alive. Readjust the count of - * waiting processes. + * waiting processes. semptr needs to be recomputed + * because the sem[] may have been reallocated while + * we were sleeping, updating our sem_base pointer. */ + semptr = &semaptr->sem_base[sopptr->sem_num]; if (sopptr->sem_op == 0) semptr->semzcnt--; else @@ -853,7 +1194,7 @@ done: #ifdef SEM_DEBUG printf("eval = %d from semundo_adjust\n", eval); #endif - return(eval); + UNLOCK_AND_RETURN(eval); } /* loop through the sops */ } /* if (do_undos) */ @@ -864,7 +1205,16 @@ done: semptr->sempid = p->p_pid; } - /* Do a wakeup if any semaphore was up'd. */ + /* Do a wakeup if any semaphore was up'd. + * we will release our lock on the semaphore subsystem before + * we wakeup other processes to prevent a little thrashing. + * Note that this is fine because we are done using the + * semaphore structures at this point in time. We only use + * a local variable pointer value, and the retval + * parameter. + * Note 2: Future use of sem_wakeup may reqiure the lock. + */ + SUBSYSTEM_LOCK_RELEASE; if (do_wakeup) { #ifdef SEM_DEBUG printf("semop: doing wakeup\n"); @@ -881,7 +1231,7 @@ done: #ifdef SEM_DEBUG printf("semop: done\n"); #endif - p->p_retval[0] = 0; + *retval = 0; return(0); } @@ -897,17 +1247,16 @@ semexit(p) register struct sem_undo **supptr; int did_something; - /* - * If somebody else is holding the global semaphore facility lock - * then sleep until it is released. + /* If we have not allocated our semaphores yet there can't be + * anything to undo, but we need the lock to prevent + * dynamic memory race conditions. */ - while (semlock_holder != NULL && semlock_holder != p) { -#ifdef SEM_DEBUG - printf("semaphore facility locked - sleeping ...\n"); -#endif - (void) tsleep((caddr_t)&semlock_holder, (PZERO - 4), "semext", 0); + SUBSYSTEM_LOCK_AQUIRE(p); + if (!sem) + { + SUBSYSTEM_LOCK_RELEASE; + return; } - did_something = 0; /* @@ -964,6 +1313,14 @@ semexit(p) } else semaptr->sem_base[semnum].semval += adjval; + /* Maybe we should build a list of semaptr's to wake + * up, finish all access to data structures, release the + * subsystem lock, and wake all the processes. Something + * to think about. It wouldn't buy us anything unless + * wakeup had the potential to block, or the syscall + * funnel state was changed to allow multiple threads + * in the BSD code at once. + */ #ifdef SEM_WAKEUP sem_wakeup((caddr_t)semaptr); #else @@ -986,11 +1343,24 @@ semexit(p) unlock: /* - * If the exiting process is holding the global semaphore facility - * lock then release it. - */ - if (semlock_holder == p) { - semlock_holder = NULL; - wakeup((caddr_t)&semlock_holder); - } + * There is a semaphore leak (i.e. memory leak) in this code. + * We should be deleting the IPC_PRIVATE semaphores when they are + * no longer needed, and we dont. We would have to track which processes + * know about which IPC_PRIVATE semaphores, updating the list after + * every fork. We can't just delete them semaphore when the process + * that created it dies, because that process may well have forked + * some children. So we need to wait until all of it's children have + * died, and so on. Maybe we should tag each IPC_PRIVATE sempahore + * with the creating group ID, count the number of processes left in + * that group, and delete the semaphore when the group is gone. + * Until that code gets implemented we will leak IPC_PRIVATE semaphores. + * There is an upper bound on the size of our semaphore array, so + * leaking the semaphores should not work as a DOS attack. + * + * Please note that the original BSD code this file is based on had the + * same leaky semaphore problem. + */ + + SUBSYSTEM_LOCK_RELEASE; } + diff --git a/bsd/kern/sysv_shm.c b/bsd/kern/sysv_shm.c index dc25f2efc..c86c5d590 100644 --- a/bsd/kern/sysv_shm.c +++ b/bsd/kern/sysv_shm.c @@ -52,6 +52,7 @@ */ +#include #include #include #include @@ -60,6 +61,7 @@ #include #include #include +#include #include #include @@ -100,6 +102,7 @@ static sy_call_t *shmcalls[] = { static int shm_last_free, shm_nused, shm_committed; struct shmid_ds *shmsegs; +static int shm_inited = 0; struct shm_handle { /* vm_offset_t kva; */ @@ -116,6 +119,16 @@ static int shm_find_segment_by_key __P((key_t)); static struct shmid_ds *shm_find_segment_by_shmid __P((int)); static int shm_delete_mapping __P((struct proc *, struct shmmap_state *)); +#ifdef __APPLE_API_PRIVATE +struct shminfo shminfo = { + -1, /* SHMMAX 4096 *1024 */ + -1, /* SHMMIN = 1 */ + -1, /* SHMMNI = 1 */ + -1, /* SHMSEG = 8 */ + -1 /* SHMALL = 1024 */ +}; +#endif /* __APPLE_API_PRIVATE */ + static int shm_find_segment_by_key(key) key_t key; @@ -204,6 +217,8 @@ shmdt(p, uap, retval) struct shmmap_state *shmmap_s; int i; + if (!shm_inited) + return(EINVAL); shmmap_s = (struct shmmap_state *)p->vm_shm; if (shmmap_s == NULL) return EINVAL; @@ -240,6 +255,8 @@ shmat(p, uap, retval) vm_size_t size; kern_return_t rv; + if (!shm_inited) + return(EINVAL); shmmap_s = (struct shmmap_state *)p->vm_shm; if (shmmap_s == NULL) { size = shminfo.shmseg * sizeof(struct shmmap_state); @@ -341,6 +358,8 @@ oshmctl(p, uap, retval) struct shmid_ds *shmseg; struct oshmid_ds outbuf; + if (!shm_inited) + return(EINVAL); shmseg = shm_find_segment_by_shmid(uap->shmid); if (shmseg == NULL) return EINVAL; @@ -391,6 +410,8 @@ shmctl(p, uap, retval) struct shmid_ds inbuf; struct shmid_ds *shmseg; + if (!shm_inited) + return(EINVAL); shmseg = shm_find_segment_by_shmid(uap->shmid); if (shmseg == NULL) return EINVAL; @@ -580,6 +601,9 @@ shmget(p, uap, retval) { int segnum, mode, error; + if (!shm_inited) + return(EINVAL); + mode = uap->shmflg & ACCESSPERMS; if (uap->key != IPC_PRIVATE) { again: @@ -612,6 +636,9 @@ shmsys(p, uap, retval) register_t *retval; { + if (!shm_inited) + return(EINVAL); + if (uap->which >= sizeof(shmcalls)/sizeof(shmcalls[0])) return EINVAL; return ((*shmcalls[uap->which])(p, &uap->a2, retval)); @@ -625,6 +652,8 @@ shmfork(p1, p2) size_t size; int i; + if (!shm_inited) + return; size = shminfo.shmseg * sizeof(struct shmmap_state); shmmap_s = (struct shmmap_state *)_MALLOC(size, M_SHM, M_WAITOK); bcopy((caddr_t)p1->vm_shm, (caddr_t)shmmap_s, size); @@ -656,15 +685,71 @@ shminit(dummy) int i; int s; - s = sizeof(struct shmid_ds) * shminfo.shmmni; + if (!shm_inited) { + s = sizeof(struct shmid_ds) * shminfo.shmmni; + + MALLOC(shmsegs, struct shmid_ds *, s, + M_SHM, M_WAITOK); + for (i = 0; i < shminfo.shmmni; i++) { + shmsegs[i].shm_perm.mode = SHMSEG_FREE; + shmsegs[i].shm_perm.seq = 0; + } + shm_last_free = 0; + shm_nused = 0; + shm_committed = 0; + shm_inited = 1; + } +} + +/* (struct sysctl_oid *oidp, void *arg1, int arg2, \ + struct sysctl_req *req) */ +static int +sysctl_shminfo SYSCTL_HANDLER_ARGS +{ + int error = 0; + + error = SYSCTL_OUT(req, arg1, sizeof(int)); + if (error || !req->newptr) + return(error); - MALLOC(shmsegs, struct shmid_ds *, s, - M_SHM, M_WAITOK); - for (i = 0; i < shminfo.shmmni; i++) { - shmsegs[i].shm_perm.mode = SHMSEG_FREE; - shmsegs[i].shm_perm.seq = 0; + /* Set the values only if shared memory is not initialised */ + if (!shm_inited) { + if (error = SYSCTL_IN(req, arg1, sizeof(int))) + return(error); + if (arg1 == &shminfo.shmmax) { + if (shminfo.shmmax & PAGE_MASK) { + shminfo.shmmax = -1; + return(EINVAL); + } + } + + /* Initialize only when all values are set */ + if ((shminfo.shmmax != -1) && + (shminfo.shmmin != -1) && + (shminfo.shmmni != -1) && + (shminfo.shmseg != -1) && + (shminfo.shmall != -1)) { + shminit(); + } } - shm_last_free = 0; - shm_nused = 0; - shm_committed = 0; + return(0); } + +SYSCTL_NODE(_kern, KERN_SYSV, sysv, CTLFLAG_RW, 0, "SYSV"); + +SYSCTL_PROC(_kern_sysv, KSYSV_SHMMAX, shmmax, CTLTYPE_INT | CTLFLAG_RW, + &shminfo.shmmax, 0, &sysctl_shminfo ,"I","shmmax"); + +SYSCTL_PROC(_kern_sysv, KSYSV_SHMMIN, shmmin, CTLTYPE_INT | CTLFLAG_RW, + &shminfo.shmmin, 0, &sysctl_shminfo ,"I","shmmin"); + +SYSCTL_PROC(_kern_sysv, KSYSV_SHMMNI, shmmni, CTLTYPE_INT | CTLFLAG_RW, + &shminfo.shmmni, 0, &sysctl_shminfo ,"I","shmmni"); + +SYSCTL_PROC(_kern_sysv, KSYSV_SHMSEG, shmseg, CTLTYPE_INT | CTLFLAG_RW, + &shminfo.shmseg, 0, &sysctl_shminfo ,"I","shmseg"); + +SYSCTL_PROC(_kern_sysv, KSYSV_SHMALL, shmall, CTLTYPE_INT | CTLFLAG_RW, + &shminfo.shmall, 0, &sysctl_shminfo ,"I","shmall"); + + diff --git a/bsd/kern/tty.c b/bsd/kern/tty.c index fc84d6f5f..dee8138ff 100644 --- a/bsd/kern/tty.c +++ b/bsd/kern/tty.c @@ -106,6 +106,8 @@ #include #include #include +#include +#include #include #ifndef NeXT #include @@ -794,7 +796,9 @@ ttioctl(tp, cmd, data, flag, p) register struct proc *p = curproc; /* XXX */ #endif int s, error; + struct uthread *ut; + ut = (struct uthread *)get_bsdthread_info(current_act()); /* If the ioctl involves modification, hang if in the background. */ switch (cmd) { case TIOCFLUSH: @@ -821,7 +825,7 @@ ttioctl(tp, cmd, data, flag, p) while (isbackground(p, tp) && (p->p_flag & P_PPWAIT) == 0 && (p->p_sigignore & sigmask(SIGTTOU)) == 0 && - (p->p_sigmask & sigmask(SIGTTOU)) == 0) { + (ut->uu_sigmask & sigmask(SIGTTOU)) == 0) { if (p->p_pgrp->pg_jobc == 0) return (EIO); pgsignal(p->p_pgrp, SIGTTOU, 1); @@ -1096,6 +1100,10 @@ ttioctl(tp, cmd, data, flag, p) tp->t_pgrp = p->p_pgrp; p->p_session->s_ttyp = tp; p->p_flag |= P_CONTROLT; + /* The backgrounded process blocking on tty now + * could be foregound process. Wake such processes + */ + tty_pgsignal(tp->t_pgrp, SIGCONT); break; case TIOCSPGRP: { /* set pgrp of tty */ register struct pgrp *pgrp = pgfind(*(int *)data); @@ -1105,6 +1113,10 @@ ttioctl(tp, cmd, data, flag, p) else if (pgrp == NULL || pgrp->pg_session != p->p_session) return (EPERM); tp->t_pgrp = pgrp; + /* The backgrounded process blocking on tty now + * could be foregound process. Wake such processes + */ + tty_pgsignal(tp->t_pgrp, SIGCONT); break; } case TIOCSTAT: /* simulate control-T */ @@ -1573,8 +1585,12 @@ ttread(tp, uio, flag) int has_etime = 0, last_cc = 0; long slp = 0; /* XXX this should be renamed `timo'. */ boolean_t funnel_state; + struct uthread *ut; funnel_state = thread_funnel_set(kernel_flock, TRUE); + + ut = (struct uthread *)get_bsdthread_info(current_act()); + loop: s = spltty(); lflag = tp->t_lflag; @@ -1594,7 +1610,7 @@ loop: if (isbackground(p, tp)) { splx(s); if ((p->p_sigignore & sigmask(SIGTTIN)) || - (p->p_sigmask & sigmask(SIGTTIN)) || + (ut->uu_sigmask & sigmask(SIGTTIN)) || p->p_flag & P_PPWAIT || p->p_pgrp->pg_jobc == 0) { thread_funnel_set(kernel_flock, funnel_state); return (EIO); @@ -1880,16 +1896,19 @@ ttycheckoutq(tp, wait) int wait; { int hiwat, s, oldsig; + struct uthread *ut; + + ut = (struct uthread *)get_bsdthread_info(current_act()); hiwat = tp->t_hiwat; s = spltty(); - oldsig = wait ? current_proc()->p_siglist : 0; + oldsig = wait ? ut->uu_siglist : 0; if (tp->t_outq.c_cc > hiwat + OBUFSIZ + 100) while (tp->t_outq.c_cc > hiwat) { ttstart(tp); if (tp->t_outq.c_cc <= hiwat) break; - if (wait == 0 || current_proc()->p_siglist != oldsig) { + if (wait == 0 || ut->uu_siglist != oldsig) { splx(s); return (0); } @@ -1915,9 +1934,11 @@ ttwrite(tp, uio, flag) int i, hiwat, cnt, error, s; char obuf[OBUFSIZ]; boolean_t funnel_state; + struct uthread *ut; funnel_state = thread_funnel_set(kernel_flock, TRUE); + ut = (struct uthread *)get_bsdthread_info(current_act()); hiwat = tp->t_hiwat; cnt = uio->uio_resid; error = 0; @@ -1951,7 +1972,7 @@ loop: if (isbackground(p, tp) && ISSET(tp->t_lflag, TOSTOP) && (p->p_flag & P_PPWAIT) == 0 && (p->p_sigignore & sigmask(SIGTTOU)) == 0 && - (p->p_sigmask & sigmask(SIGTTOU)) == 0) { + (ut->uu_sigmask & sigmask(SIGTTOU)) == 0) { if (p->p_pgrp->pg_jobc == 0) { error = EIO; goto out; diff --git a/bsd/kern/tty_pty.c b/bsd/kern/tty_pty.c index 616d9e827..43386b2a6 100644 --- a/bsd/kern/tty_pty.c +++ b/bsd/kern/tty_pty.c @@ -71,6 +71,7 @@ #include #include #include +#include #include #ifndef NeXT @@ -316,12 +317,14 @@ ptsread(dev, uio, flag) register struct tty *tp = pt_tty[minor(dev)]; register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; int error = 0; + struct uthread *ut; + ut = (struct uthread *)get_bsdthread_info(current_act()); again: if (pti->pt_flags & PF_REMOTE) { while (isbackground(p, tp)) { if ((p->p_sigignore & sigmask(SIGTTIN)) || - (p->p_sigmask & sigmask(SIGTTIN)) || + (ut->uu_sigmask & sigmask(SIGTTIN)) || p->p_pgrp->pg_jobc == 0 || p->p_flag & P_PPWAIT) return (EIO); diff --git a/bsd/kern/ubc_subr.c b/bsd/kern/ubc_subr.c index c82fd94a2..955b6b638 100644 --- a/bsd/kern/ubc_subr.c +++ b/bsd/kern/ubc_subr.c @@ -55,7 +55,7 @@ #undef assert() #endif #define assert(cond) \ - if (!(cond)) panic("%s:%d (%s)", __FILE__, __LINE__, # cond) + ((void) ((cond) ? 0 : panic("%s:%d (%s)", __FILE__, __LINE__, # cond))) #else #include #endif /* DIAGNOSTIC */ @@ -1023,6 +1023,13 @@ ubc_isinuse(struct vnode *vp, int tookref) if (!UBCINFOEXISTS(vp)) return (0); + if (tookref == 0) { + printf("ubc_isinuse: called without a valid reference" + ": v_tag = %d\v", vp->v_tag); + vprint("ubc_isinuse", vp); + return (0); + } + if (vp->v_usecount > busycount) return (1); diff --git a/bsd/kern/uipc_domain.c b/bsd/kern/uipc_domain.c index fbd7a1116..efb0a3cd6 100644 --- a/bsd/kern/uipc_domain.c +++ b/bsd/kern/uipc_domain.c @@ -398,13 +398,24 @@ pfctlinput(cmd, sa) int cmd; struct sockaddr *sa; { - register struct domain *dp; - register struct protosw *pr; + pfctlinput2(cmd, sa, (void*)0); +} + +void +pfctlinput2(cmd, sa, ctlparam) + int cmd; + struct sockaddr *sa; + void *ctlparam; +{ + struct domain *dp; + struct protosw *pr; + if (!sa) + return; for (dp = domains; dp; dp = dp->dom_next) for (pr = dp->dom_protosw; pr; pr = pr->pr_next) if (pr->pr_ctlinput) - (*pr->pr_ctlinput)(cmd, sa, (caddr_t)0); + (*pr->pr_ctlinput)(cmd, sa, ctlparam); } void diff --git a/bsd/kern/uipc_mbuf.c b/bsd/kern/uipc_mbuf.c index 513cc8e53..0eed25410 100644 --- a/bsd/kern/uipc_mbuf.c +++ b/bsd/kern/uipc_mbuf.c @@ -76,6 +76,11 @@ #include #include +#include +#include + +#define _MCLREF(p) (++mclrefcnt[mtocl(p)]) +#define _MCLUNREF(p) (--mclrefcnt[mtocl(p)] == 0) extern kernel_pmap; /* The kernel's pmap */ @@ -108,6 +113,52 @@ extern int dlil_input_thread_wakeup; extern int dlil_expand_mcl; extern int dlil_initialized; +#if 0 +static int mfree_munge = 0; +#if 0 +#define _MFREE_MUNGE(m) { \ + if (mfree_munge) \ + { int i; \ + vm_offset_t *element = (vm_offset_t *)(m); \ + for (i = 0; \ + i < sizeof(struct mbuf)/sizeof(vm_offset_t); \ + i++) \ + (element)[i] = 0xdeadbeef; \ + } \ +} +#else +void +munge_mbuf(struct mbuf *m) +{ + int i; + vm_offset_t *element = (vm_offset_t *)(m); + for (i = 0; + i < sizeof(struct mbuf)/sizeof(vm_offset_t); + i++) + (element)[i] = 0xdeadbeef; +} +#define _MFREE_MUNGE(m) { \ + if (mfree_munge) \ + munge_mbuf(m); \ +} +#endif +#else +#define _MFREE_MUNGE(m) +#endif + + +#define _MINTGET(m, type) { \ + MBUF_LOCK(); \ + if (((m) = mfree) != 0) { \ + MCHECK(m); \ + ++mclrefcnt[mtocl(m)]; \ + mbstat.m_mtypes[MT_FREE]--; \ + mbstat.m_mtypes[(type)]++; \ + mfree = (m)->m_next; \ + } \ + MBUF_UNLOCK(); \ +} + void mbinit() @@ -250,6 +301,7 @@ m_expand(canwait) mbstat.m_mtypes[MT_FREE] += i; mbstat.m_mbufs += i; while (i--) { + _MFREE_MUNGE(m); m->m_type = MT_FREE; m->m_next = mfree; mfree = m++; @@ -271,7 +323,6 @@ struct mbuf * m_retry(canwait, type) int canwait, type; { -#define m_retry(h, t) 0 register struct mbuf *m; int wait, s; funnel_t * fnl; @@ -280,41 +331,42 @@ m_retry(canwait, type) for (;;) { (void) m_expand(canwait); - MGET(m, XXX, type); + _MINTGET(m, type); + if (m) { + (m)->m_next = (m)->m_nextpkt = 0; + (m)->m_type = (type); + (m)->m_data = (m)->m_dat; + (m)->m_flags = 0; + } if (m || canwait == M_DONTWAIT) break; MBUF_LOCK(); wait = m_want++; - dlil_expand_mcl = 1; + if (wait == 0) + mbstat.m_drain++; + else + mbstat.m_wait++; MBUF_UNLOCK(); if (dlil_initialized) wakeup((caddr_t)&dlil_input_thread_wakeup); - if (wait == 0) { - mbstat.m_drain++; - } - else { - assert_wait((caddr_t)&mfree, THREAD_UNINT); - mbstat.m_wait++; - } - /* * Grab network funnel because m_reclaim calls into the * socket domains and tsleep end-up calling splhigh */ fnl = thread_funnel_get(); - if (fnl && (fnl == kernel_flock)) { - fnl_switch = 1; - thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); - } else - funnel_state = thread_funnel_set(network_flock, TRUE); + if (fnl && (fnl == kernel_flock)) { + fnl_switch = 1; + thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); + } else + funnel_state = thread_funnel_set(network_flock, TRUE); if (wait == 0) { m_reclaim(); } else { /* Sleep with a small timeout as insurance */ - (void) tsleep((caddr_t)0, PZERO-1, "m_retry", hz); + (void) tsleep((caddr_t)&mfree, PZERO-1, "m_retry", hz); } if (fnl_switch) thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); @@ -322,7 +374,6 @@ m_retry(canwait, type) thread_funnel_set(network_flock, funnel_state); } return (m); -#undef m_retry } /* @@ -372,7 +423,15 @@ m_get(nowait, type) { register struct mbuf *m; - MGET(m, nowait, type); + _MINTGET(m, type); + if (m) { + m->m_next = m->m_nextpkt = 0; + m->m_type = type; + m->m_data = m->m_dat; + m->m_flags = 0; + } else + (m) = m_retry(nowait, type); + return (m); } @@ -382,8 +441,23 @@ m_gethdr(nowait, type) { register struct mbuf *m; - MGETHDR(m, nowait, type); - return (m); + _MINTGET(m, type); + if (m) { + m->m_next = m->m_nextpkt = 0; + m->m_type = type; + m->m_data = m->m_pktdat; + m->m_flags = M_PKTHDR; + m->m_pkthdr.rcvif = NULL; + m->m_pkthdr.header = NULL; + m->m_pkthdr.csum_flags = 0; + m->m_pkthdr.csum_data = 0; + m->m_pkthdr.aux = (struct mbuf *)NULL; + m->m_pkthdr.reserved1 = NULL; + m->m_pkthdr.reserved2 = NULL; + } else + m = m_retryhdr(nowait, type); + + return m; } struct mbuf * @@ -409,13 +483,20 @@ m_free(m) if (m->m_type == MT_FREE) panic("freeing free mbuf"); + /* Free the aux data if there is any */ + if ((m->m_flags & M_PKTHDR) && m->m_pkthdr.aux) + { + m_freem(m->m_pkthdr.aux); + } + MBUF_LOCK(); - if (m->m_flags & M_EXT) { + if ((m->m_flags & M_EXT)) + { if (MCLHASREFERENCE(m)) { remque((queue_t)&m->m_ext.ext_refs); } else if (m->m_ext.ext_free == NULL) { union mcluster *mcl= (union mcluster *)m->m_ext.ext_buf; - if (MCLUNREF(mcl)) { + if (_MCLUNREF(mcl)) { mcl->mcl_next = mclfree; mclfree = mcl; ++mbstat.m_clfree; @@ -434,7 +515,8 @@ m_free(m) } } mbstat.m_mtypes[m->m_type]--; - (void) MCLUNREF(m); + (void) _MCLUNREF(m); + _MFREE_MUNGE(m); m->m_type = MT_FREE; mbstat.m_mtypes[m->m_type]++; m->m_flags = 0; @@ -448,6 +530,77 @@ m_free(m) return (n); } +/* m_mclget() add an mbuf cluster to a normal mbuf */ +struct mbuf * +m_mclget(m, nowait) + struct mbuf *m; + int nowait; +{ + MCLALLOC(m->m_ext.ext_buf, nowait); + if (m->m_ext.ext_buf) { + m->m_data = m->m_ext.ext_buf; + m->m_flags |= M_EXT; + m->m_ext.ext_size = MCLBYTES; + m->m_ext.ext_free = 0; + m->m_ext.ext_refs.forward = m->m_ext.ext_refs.backward = + &m->m_ext.ext_refs; + } + + return m; +} + +/* m_mclalloc() allocate an mbuf cluster */ +caddr_t +m_mclalloc( nowait) + int nowait; +{ + caddr_t p; + + (void)m_clalloc(1, nowait); + if ((p = (caddr_t)mclfree)) { + ++mclrefcnt[mtocl(p)]; + mbstat.m_clfree--; + mclfree = ((union mcluster *)p)->mcl_next; + } + MBUF_UNLOCK(); + + return p; +} + +/* m_mclfree() releases a reference to a cluster allocated by MCLALLOC, + * freeing the cluster if the reference count has reached 0. */ +void +m_mclfree(p) + caddr_t p; +{ + MBUF_LOCK(); + if (--mclrefcnt[mtocl(p)] == 0) { + ((union mcluster *)(p))->mcl_next = mclfree; + mclfree = (union mcluster *)(p); + mbstat.m_clfree++; + } + MBUF_UNLOCK(); +} + +/* mcl_hasreference() checks if a cluster of an mbuf is referenced by another mbuf */ +int +m_mclhasreference(m) + struct mbuf *m; +{ + return (m->m_ext.ext_refs.forward != &(m->m_ext.ext_refs)); +} + +/* */ +void +m_copy_pkthdr(to, from) + struct mbuf *to, *from; +{ + to->m_pkthdr = from->m_pkthdr; + from->m_pkthdr.aux = (struct mbuf *)NULL; + to->m_flags = from->m_flags & M_COPYFLAGS; + to->m_data = (to)->m_pktdat; +} + /* Best effort to get a mbuf cluster + pkthdr under one lock. * If we don't have them avail, just bail out and use the regular * path. @@ -474,15 +627,15 @@ m_getpacket(void) m->m_type = MT_DATA; m->m_data = m->m_ext.ext_buf; m->m_flags = M_PKTHDR | M_EXT; - m->m_pkthdr.len = 0; - m->m_pkthdr.rcvif = NULL; + m->m_pkthdr.len = 0; + m->m_pkthdr.rcvif = NULL; m->m_pkthdr.header = NULL; m->m_pkthdr.csum_data = 0; m->m_pkthdr.csum_flags = 0; m->m_pkthdr.aux = (struct mbuf *)NULL; m->m_pkthdr.reserved1 = 0; m->m_pkthdr.reserved2 = 0; - m->m_ext.ext_free = 0; + m->m_ext.ext_free = 0; m->m_ext.ext_size = MCLBYTES; m->m_ext.ext_refs.forward = m->m_ext.ext_refs.backward = &m->m_ext.ext_refs; @@ -506,6 +659,14 @@ m_getpacket(void) } +/* + * return a list of mbuf hdrs that point to clusters... + * try for num_needed, if this can't be met, return whatever + * number were available... set up the first num_with_pkthdrs + * with mbuf hdrs configured as packet headers... these are + * chained on the m_nextpkt field... any packets requested beyond + * this are chained onto the last packet header's m_next field. + */ struct mbuf * m_getpackets(int num_needed, int num_with_pkthdrs, int how) { @@ -561,9 +722,7 @@ m_getpackets(int num_needed, int num_with_pkthdrs, int how) MGET(m, how, MT_DATA ); } else { MGETHDR(m, how, MT_DATA); - - if (m) - m->m_pkthdr.len = 0; + num_with_pkthdrs--; } if (m == 0) @@ -589,6 +748,10 @@ m_getpackets(int num_needed, int num_with_pkthdrs, int how) } +/* + * return a list of mbuf hdrs set up as packet hdrs + * chained together on the m_nextpkt field + */ struct mbuf * m_getpackethdrs(int num_needed, int how) { @@ -658,10 +821,28 @@ m_freem_list(m) nextpkt = m->m_nextpkt; /* chain of linked mbufs from driver */ else nextpkt = 0; + count++; while (m) { /* free the mbuf chain (like mfreem) */ - struct mbuf *n = m->m_next; + + struct mbuf *n; + + /* Free the aux data if there is any */ + if ((m->m_flags & M_PKTHDR) && m->m_pkthdr.aux) { + /* + * Treat the current m as the nextpkt and set m + * to the aux data. This lets us free the aux + * data in this loop without having to call + * m_freem recursively, which wouldn't work + * because we've still got the lock. + */ + nextpkt = m; + m = nextpkt->m_pkthdr.aux; + nextpkt->m_pkthdr.aux = NULL; + } + + n = m->m_next; if (n && n->m_nextpkt) panic("m_freem_list: m_nextpkt of m_next != NULL"); @@ -673,7 +854,7 @@ m_freem_list(m) remque((queue_t)&m->m_ext.ext_refs); } else if (m->m_ext.ext_free == NULL) { union mcluster *mcl= (union mcluster *)m->m_ext.ext_buf; - if (MCLUNREF(mcl)) { + if (_MCLUNREF(mcl)) { mcl->mcl_next = mclfree; mclfree = mcl; ++mbstat.m_clfree; @@ -684,7 +865,8 @@ m_freem_list(m) } } mbstat.m_mtypes[m->m_type]--; - (void) MCLUNREF(m); + (void) _MCLUNREF(m); + _MFREE_MUNGE(m); mbstat.m_mtypes[MT_FREE]++; m->m_type = MT_FREE; m->m_flags = 0; @@ -754,6 +936,7 @@ register struct mbuf *m; * Lesser-used path for M_PREPEND: * allocate new mbuf to prepend to chain, * copy junk along. + * Does not adjust packet header length. */ struct mbuf * m_prepend(m, len, how) @@ -779,6 +962,28 @@ m_prepend(m, len, how) return (m); } +/* + * Replacement for old M_PREPEND macro: + * allocate new mbuf to prepend to chain, + * copy junk along, and adjust length. + * + */ +struct mbuf * +m_prepend_2(m, len, how) + register struct mbuf *m; + int len, how; +{ + if (M_LEADINGSPACE(m) >= len) { + m->m_data -= len; + m->m_len += len; + } else { + m = m_prepend(m, len, how); + } + if ((m) && (m->m_flags & M_PKTHDR)) + m->m_pkthdr.len += len; + return (m); +} + /* * Make a copy of an mbuf chain starting "off0" bytes from the beginning, * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. @@ -888,7 +1093,13 @@ nospace: } - +/* + * equivilent to m_copym except that all necessary + * mbuf hdrs are allocated within this routine + * also, the last mbuf and offset accessed are passed + * out and can be passed back in to avoid having to + * rescan the entire mbuf list (normally hung off of the socket) + */ struct mbuf * m_copym_with_hdrs(m, off0, len, wait, m_last, m_off) register struct mbuf *m; @@ -1546,6 +1757,56 @@ m_dup(register struct mbuf *m, int how) return (0); } +int +m_mclref(struct mbuf *p) +{ + return (_MCLREF(p)); +} + +int +m_mclunref(struct mbuf *p) +{ + return (_MCLUNREF(p)); +} + +/* change mbuf to new type */ +void +m_mchtype(struct mbuf *m, int t) +{ + MBUF_LOCK(); + mbstat.m_mtypes[(m)->m_type]--; + mbstat.m_mtypes[t]++; + (m)->m_type = t; + MBUF_UNLOCK(); +} + +void *m_mtod(struct mbuf *m) +{ + return ((m)->m_data); +} + +struct mbuf *m_dtom(void *x) +{ + return ((struct mbuf *)((u_long)(x) & ~(MSIZE-1))); +} + +int m_mtocl(void *x) +{ + return (((char *)(x) - (char *)mbutl) / sizeof(union mcluster)); +} + +union mcluster *m_cltom(int x) +{ + return ((union mcluster *)(mbutl + (x))); +} + + +void m_mcheck(struct mbuf *m) +{ + if (m->m_type != MT_FREE) + panic("mget MCHECK: m_type=%x m=%x", m->m_type, m); +} + #if 0 #include diff --git a/bsd/kern/uipc_mbuf2.c b/bsd/kern/uipc_mbuf2.c index e395fc546..02b4f8f4b 100644 --- a/bsd/kern/uipc_mbuf2.c +++ b/bsd/kern/uipc_mbuf2.c @@ -85,14 +85,8 @@ * @(#)uipc_mbuf.c 8.4 (Berkeley) 2/14/95 */ -#define PULLDOWN_STAT -/*#define PULLDOWN_DEBUG*/ -#ifdef PULLDOWN_STAT -#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3) -#include "opt_inet.h" -#endif -#endif +/*#define PULLDOWN_DEBUG*/ #include #include diff --git a/bsd/kern/uipc_proto.c b/bsd/kern/uipc_proto.c index c6ce5216a..1d31b684a 100644 --- a/bsd/kern/uipc_proto.c +++ b/bsd/kern/uipc_proto.c @@ -87,7 +87,7 @@ static struct protosw localsw[] = { 0, &uipc_usrreqs }, { 0, 0, 0, 0, - raw_input, 0, raw_ctlinput, 0, + 0, 0, raw_ctlinput, 0, 0, raw_init, 0, 0, 0, 0, &raw_usrreqs diff --git a/bsd/kern/uipc_socket.c b/bsd/kern/uipc_socket.c index 3d19b403c..813dcf564 100644 --- a/bsd/kern/uipc_socket.c +++ b/bsd/kern/uipc_socket.c @@ -53,7 +53,8 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)uipc_socket.c 8.6 (Berkeley) 5/2/95 + * @(#)uipc_socket.c 8.3 (Berkeley) 4/15/94 + * $FreeBSD: src/sys/kern/uipc_socket.c,v 1.68.2.16 2001/06/14 20:46:06 ume Exp $ */ #include @@ -123,6 +124,8 @@ SYSCTL_INT(_kern_ipc, OID_AUTO, sosendminchain, CTLFLAG_RW, &sosendminchain, 0, ""); void so_cache_timer(); +struct mbuf *m_getpackets(int, int, int); + /* * Socket operation routines. @@ -132,6 +135,7 @@ void so_cache_timer(); * switching out to the protocol specific routines. */ +#ifdef __APPLE__ void socketinit() { vm_size_t str_size; @@ -313,7 +317,7 @@ void so_cache_timer() (void) thread_funnel_set(network_flock, FALSE); } - +#endif /* __APPLE__ */ /* * Get a socket structure from our zone, and initialize it. @@ -354,19 +358,29 @@ socreate(dom, aso, type, proto) struct socket **aso; register int type; int proto; - { struct proc *p = current_proc(); register struct protosw *prp; - struct socket *so; + register struct socket *so; register int error = 0; if (proto) prp = pffindproto(dom, proto, type); else prp = pffindtype(dom, type); + if (prp == 0 || prp->pr_usrreqs->pru_attach == 0) return (EPROTONOSUPPORT); +#ifndef __APPLE__ + + if (p->p_prison && jail_socket_unixiproute_only && + prp->pr_domain->dom_family != PF_LOCAL && + prp->pr_domain->dom_family != PF_INET && + prp->pr_domain->dom_family != PF_ROUTE) { + return (EPROTONOSUPPORT); + } + +#endif if (prp->pr_type != type) return (EPROTOTYPE); so = soalloc(p != 0, dom, type); @@ -377,28 +391,35 @@ socreate(dom, aso, type, proto) TAILQ_INIT(&so->so_comp); so->so_type = type; +#ifdef __APPLE__ if (p != 0) { if (p->p_ucred->cr_uid == 0) so->so_state = SS_PRIV; so->so_uid = p->p_ucred->cr_uid; } - +#else + so->so_cred = p->p_ucred; + crhold(so->so_cred); +#endif so->so_proto = prp; +#ifdef __APPLE__ so->so_rcv.sb_flags |= SB_RECV; /* XXX */ if (prp->pr_sfilter.tqh_first) error = sfilter_init(so); if (error == 0) +#endif error = (*prp->pr_usrreqs->pru_attach)(so, proto, p); - if (error) { so->so_state |= SS_NOFDREF; sofree(so); return (error); } +#ifdef __APPLE__ prp->pr_domain->dom_refs++; so->so_rcv.sb_so = so->so_snd.sb_so = so; TAILQ_INIT(&so->so_evlist); +#endif *aso = so; return (0); } @@ -415,14 +436,16 @@ sobind(so, nam) int s = splnet(); error = (*so->so_proto->pr_usrreqs->pru_bind)(so, nam, p); - if (error == 0) /* ??? */ - { kp = sotokextcb(so); - while (kp) - { if (kp->e_soif && kp->e_soif->sf_sobind) - { error = (*kp->e_soif->sf_sobind)(so, nam, kp); - if (error) - { if (error == EJUSTRETURN) + if (error == 0) { + kp = sotokextcb(so); + while (kp) { + if (kp->e_soif && kp->e_soif->sf_sobind) { + error = (*kp->e_soif->sf_sobind)(so, nam, kp); + if (error) { + if (error == EJUSTRETURN) { + error = 0; break; + } splx(s); return(error); } @@ -440,10 +463,32 @@ sodealloc(so) { so->so_gencnt = ++so_gencnt; +#ifndef __APPLE__ + if (so->so_rcv.sb_hiwat) + (void)chgsbsize(so->so_cred->cr_uidinfo, + &so->so_rcv.sb_hiwat, 0, RLIM_INFINITY); + if (so->so_snd.sb_hiwat) + (void)chgsbsize(so->so_cred->cr_uidinfo, + &so->so_snd.sb_hiwat, 0, RLIM_INFINITY); +#ifdef INET + if (so->so_accf != NULL) { + if (so->so_accf->so_accept_filter != NULL && + so->so_accf->so_accept_filter->accf_destroy != NULL) { + so->so_accf->so_accept_filter->accf_destroy(so); + } + if (so->so_accf->so_accept_filter_str != NULL) + FREE(so->so_accf->so_accept_filter_str, M_ACCF); + FREE(so->so_accf, M_ACCF); + } +#endif /* INET */ + crfree(so->so_cred); + zfreei(so->so_zone, so); +#else if (so->cached_in_sock_layer == 1) cached_sock_free(so); else _FREE_ZONE(so, sizeof(*so), so->so_zone); +#endif /* __APPLE__ */ } int @@ -468,13 +513,14 @@ solisten(so, backlog) backlog = somaxconn; so->so_qlimit = backlog; kp = sotokextcb(so); - while (kp) - { - if (kp->e_soif && kp->e_soif->sf_solisten) - { error = (*kp->e_soif->sf_solisten)(so, kp); - if (error) - { if (error == EJUSTRETURN) + while (kp) { + if (kp->e_soif && kp->e_soif->sf_solisten) { + error = (*kp->e_soif->sf_solisten)(so, kp); + if (error) { + if (error == EJUSTRETURN) { + error = 0; break; + } splx(s); return(error); } @@ -490,14 +536,15 @@ solisten(so, backlog) void sofree(so) register struct socket *so; -{ int error; +{ + int error; struct kextcb *kp; struct socket *head = so->so_head; kp = sotokextcb(so); - while (kp) - { if (kp->e_soif && kp->e_soif->sf_sofree) - { error = (*kp->e_soif->sf_sofree)(so, kp); + while (kp) { + if (kp->e_soif && kp->e_soif->sf_sofree) { + error = (*kp->e_soif->sf_sofree)(so, kp); if (error) { selthreadclear(&so->so_snd.sb_sel); selthreadclear(&so->so_rcv.sb_sel); @@ -508,34 +555,39 @@ sofree(so) } if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) { +#ifdef __APPLE__ selthreadclear(&so->so_snd.sb_sel); selthreadclear(&so->so_rcv.sb_sel); +#endif return; } - if (head != NULL) { - if (so->so_state & SS_INCOMP) { - TAILQ_REMOVE(&head->so_incomp, so, so_list); - head->so_incqlen--; - } else if (so->so_state & SS_COMP) { - /* - * We must not decommission a socket that's - * on the accept(2) queue. If we do, then - * accept(2) may hang after select(2) indicated - * that the listening socket was ready. - */ - selthreadclear(&so->so_snd.sb_sel); - selthreadclear(&so->so_rcv.sb_sel); - return; - } else { - panic("sofree: not queued"); - } + if (head != NULL) { + if (so->so_state & SS_INCOMP) { + TAILQ_REMOVE(&head->so_incomp, so, so_list); + head->so_incqlen--; + } else if (so->so_state & SS_COMP) { + /* + * We must not decommission a socket that's + * on the accept(2) queue. If we do, then + * accept(2) may hang after select(2) indicated + * that the listening socket was ready. + */ +#ifdef __APPLE__ + selthreadclear(&so->so_snd.sb_sel); + selthreadclear(&so->so_rcv.sb_sel); +#endif + return; + } else { + panic("sofree: not queued"); + } head->so_qlen--; - so->so_state &= ~(SS_INCOMP|SS_COMP); + so->so_state &= ~SS_INCOMP; so->so_head = NULL; } - +#ifdef __APPLE__ selthreadclear(&so->so_snd.sb_sel); sbrelease(&so->so_snd); +#endif sorflush(so); sfilter_term(so); sodealloc(so); @@ -554,15 +606,15 @@ soclose(so) int error = 0; struct kextcb *kp; -#if FB31SIG - funsetown(so->so_pgid); +#ifndef __APPLE__ + funsetown(so->so_sigio); #endif kp = sotokextcb(so); - while (kp) - { if (kp->e_soif && kp->e_soif->sf_soclose) - { error = (*kp->e_soif->sf_soclose)(so, kp); - if (error) - { splx(s); + while (kp) { + if (kp->e_soif && kp->e_soif->sf_soclose) { + error = (*kp->e_soif->sf_soclose)(so, kp); + if (error) { + splx(s); return((error == EJUSTRETURN) ? 0 : error); } } @@ -618,8 +670,10 @@ discard: if (so->so_pcb && so->so_state & SS_NOFDREF) panic("soclose: NOFDREF"); so->so_state |= SS_NOFDREF; +#ifdef __APPLE__ so->so_proto->pr_domain->dom_refs--; evsofree(so); +#endif sofree(so); splx(s); return (error); @@ -632,15 +686,22 @@ int soabort(so) struct socket *so; { + int error; - return (*so->so_proto->pr_usrreqs->pru_abort)(so); + error = (*so->so_proto->pr_usrreqs->pru_abort)(so); + if (error) { + sofree(so); + return error; + } + return (0); } int soaccept(so, nam) register struct socket *so; struct sockaddr **nam; -{ int s = splnet(); +{ + int s = splnet(); int error; struct kextcb *kp; @@ -648,14 +709,16 @@ soaccept(so, nam) panic("soaccept: !NOFDREF"); so->so_state &= ~SS_NOFDREF; error = (*so->so_proto->pr_usrreqs->pru_accept)(so, nam); - if (error == 0) - { kp = sotokextcb(so); + if (error == 0) { + kp = sotokextcb(so); while (kp) { - if (kp->e_soif && kp->e_soif->sf_soaccept) - { error = (*kp->e_soif->sf_soaccept)(so, nam, kp); - if (error) - { if (error == EJUSTRETURN) + if (kp->e_soif && kp->e_soif->sf_soaccept) { + error = (*kp->e_soif->sf_soaccept)(so, nam, kp); + if (error) { + if (error == EJUSTRETURN) { + error = 0; break; + } splx(s); return(error); } @@ -694,26 +757,27 @@ soconnect(so, nam) (error = sodisconnect(so)))) error = EISCONN; else { + /* + * Run connect filter before calling protocol: + * - non-blocking connect returns before completion; + * - allows filters to modify address. + */ + kp = sotokextcb(so); + while (kp) { + if (kp->e_soif && kp->e_soif->sf_soconnect) { + error = (*kp->e_soif->sf_soconnect)(so, nam, kp); + if (error) { + if (error == EJUSTRETURN) { + error = 0; + } + splx(s); + return(error); + } + } + kp = kp->e_next; + } error = (*so->so_proto->pr_usrreqs->pru_connect)(so, nam, p); - if (error == 0) - { - kp = sotokextcb(so); - while (kp) - { - if (kp->e_soif && kp->e_soif->sf_soconnect) - { error = (*kp->e_soif->sf_soconnect)(so, nam, kp); - if (error) - { if (error == EJUSTRETURN) - break; - splx(s); - return(error); - } - } - kp = kp->e_next; - } - } } - splx(s); return (error); } @@ -728,14 +792,16 @@ soconnect2(so1, so2) struct kextcb *kp; error = (*so1->so_proto->pr_usrreqs->pru_connect2)(so1, so2); - if (error == 0) - { kp = sotokextcb(so1); - while (kp) - { if (kp->e_soif && kp->e_soif->sf_soconnect2) - { error = (*kp->e_soif->sf_soconnect2)(so1, so2, kp); - if (error) - { if (error == EJUSTRETURN) + if (error == 0) { + kp = sotokextcb(so1); + while (kp) { + if (kp->e_soif && kp->e_soif->sf_soconnect2) { + error = (*kp->e_soif->sf_soconnect2)(so1, so2, kp); + if (error) { + if (error == EJUSTRETURN) { + return 0; break; + } splx(s); return(error); } @@ -764,15 +830,16 @@ sodisconnect(so) goto bad; } error = (*so->so_proto->pr_usrreqs->pru_disconnect)(so); - - if (error == 0) - { kp = sotokextcb(so); - while (kp) - { if (kp->e_soif && kp->e_soif->sf_sodisconnect) - { error = (*kp->e_soif->sf_sodisconnect)(so, kp); - if (error) - { if (error == EJUSTRETURN) + if (error == 0) { + kp = sotokextcb(so); + while (kp) { + if (kp->e_soif && kp->e_soif->sf_sodisconnect) { + error = (*kp->e_soif->sf_sodisconnect)(so, kp); + if (error) { + if (error == EJUSTRETURN) { + error = 0; break; + } splx(s); return(error); } @@ -940,6 +1007,14 @@ restart: do { if (bytes_to_copy >= MINCLSIZE) { + /* + * try to maintain a local cache of mbuf clusters needed to complete this write + * the list is further limited to the number that are currently needed to fill the socket + * this mechanism allows a large number of mbufs/clusters to be grabbed under a single + * mbuf lock... if we can't get any clusters, than fall back to trying for mbufs + * if we fail early (or miscalcluate the number needed) make sure to release any clusters + * we haven't yet consumed. + */ if ((m = freelist) == NULL) { int num_needed; int hdrs_needed = 0; @@ -1032,7 +1107,6 @@ getpackets_failed: if (dontroute) so->so_options |= SO_DONTROUTE; s = splnet(); /* XXX */ - kp = sotokextcb(so); /* Compute flags here, for pru_send and NKEs */ sendflags = (flags & MSG_OOB) ? PRUS_OOB : /* @@ -1046,17 +1120,18 @@ getpackets_failed: PRUS_EOF : /* If there is more to send set PRUS_MORETOCOME */ (resid > 0 && space > 0) ? PRUS_MORETOCOME : 0; + kp = sotokextcb(so); while (kp) - { if (kp->e_soif && kp->e_soif->sf_sosend) - { error = (*kp->e_soif->sf_sosend)(so, &addr, + { if (kp->e_soif && kp->e_soif->sf_sosend) { + error = (*kp->e_soif->sf_sosend)(so, &addr, &uio, &top, &control, &sendflags, kp); - if (error) - { splx(s); - if (error == EJUSTRETURN) - { sbunlock(&so->so_snd); + if (error) { + splx(s); + if (error == EJUSTRETURN) { + sbunlock(&so->so_snd); if (freelist) m_freem_list(freelist); @@ -1071,9 +1146,10 @@ getpackets_failed: error = (*so->so_proto->pr_usrreqs->pru_send)(so, sendflags, top, addr, control, p); splx(s); +#ifdef __APPLE__ if (flags & MSG_SEND) so->so_temp = NULL; - +#endif if (dontroute) so->so_options &= ~SO_DONTROUTE; clen = 0; @@ -1147,9 +1223,9 @@ soreceive(so, psa, uio, mp0, controlp, flagsp) so->so_rcv.sb_hiwat); kp = sotokextcb(so); - while (kp) - { if (kp->e_soif && kp->e_soif->sf_soreceive) - { error = (*kp->e_soif->sf_soreceive)(so, psa, &uio, + while (kp) { + if (kp->e_soif && kp->e_soif->sf_soreceive) { + error = (*kp->e_soif->sf_soreceive)(so, psa, &uio, mp0, controlp, flagsp, kp); if (error) @@ -1177,6 +1253,8 @@ soreceive(so, psa, uio, mp0, controlp, flagsp) (so->so_options & SO_OOBINLINE) == 0 && (so->so_oobmark || (so->so_state & SS_RCVATMARK)))) { m = m_get(M_WAIT, MT_DATA); + if (m == NULL) + return (ENOBUFS); error = (*pr->pr_usrreqs->pru_rcvoob)(so, m, flags & MSG_PEEK); if (error) goto bad; @@ -1188,19 +1266,21 @@ soreceive(so, psa, uio, mp0, controlp, flagsp) bad: if (m) m_freem(m); - if ((so->so_options & SO_WANTOOBFLAG) != 0) { - if (error == EWOULDBLOCK || error == EINVAL) { - /* - * Let's try to get normal data: - * EWOULDBLOCK: out-of-band data not receive yet; - * EINVAL: out-of-band data already read. - */ - error = 0; - goto nooob; - } else if (error == 0 && flagsp) - *flagsp |= MSG_OOB; - } +#ifdef __APPLE__ + if ((so->so_options & SO_WANTOOBFLAG) != 0) { + if (error == EWOULDBLOCK || error == EINVAL) { + /* + * Let's try to get normal data: + * EWOULDBLOCK: out-of-band data not receive yet; + * EINVAL: out-of-band data already read. + */ + error = 0; + goto nooob; + } else if (error == 0 && flagsp) + *flagsp |= MSG_OOB; + } KERNEL_DEBUG(DBG_FNC_SORECEIVE | DBG_FUNC_END, error,0,0,0,0); +#endif return (error); } nooob: @@ -1210,8 +1290,8 @@ nooob: (*pr->pr_usrreqs->pru_rcvd)(so, 0); restart: - if (error = sblock(&so->so_rcv, SBLOCKWAIT(flags))) - { + error = sblock(&so->so_rcv, SBLOCKWAIT(flags)); + if (error) { KERNEL_DEBUG(DBG_FNC_SORECEIVE | DBG_FUNC_END, error,0,0,0,0); return (error); } @@ -1272,15 +1352,14 @@ restart: if (socket_debug) printf("SORECEIVE - sbwait returned %d\n", error); splx(s); - if (error) - { + if (error) { KERNEL_DEBUG(DBG_FNC_SORECEIVE | DBG_FUNC_END, error,0,0,0,0); return (error); } goto restart; } dontblock: -#ifdef notyet /* XXXX */ +#ifndef __APPLE__ if (uio->uio_procp) uio->uio_procp->p_stats->p_ru.ru_msgrcv++; #endif @@ -1344,7 +1423,7 @@ dontblock: break; } else if (type == MT_OOBDATA) break; -#if 0 +#ifndef __APPLE__ /* * This assertion needs rework. The trouble is Appletalk is uses many * mbuf types (NOT listed in mbuf.h!) which will trigger this panic. @@ -1353,16 +1432,17 @@ dontblock: else KASSERT(m->m_type == MT_DATA || m->m_type == MT_HEADER, ("receive 3")); -#endif - /* - * Make sure to allways set MSG_OOB event when getting - * out of band data inline. - */ +#else + /* + * Make sure to allways set MSG_OOB event when getting + * out of band data inline. + */ if ((so->so_options & SO_WANTOOBFLAG) != 0 && - (so->so_options & SO_OOBINLINE) != 0 && - (so->so_state & SS_RCVATMARK) != 0) { - flags |= MSG_OOB; - } + (so->so_options & SO_OOBINLINE) != 0 && + (so->so_state & SS_RCVATMARK) != 0) { + flags |= MSG_OOB; + } +#endif so->so_state &= ~SS_RCVATMARK; len = uio->uio_resid; if (so->so_oobmark && len > so->so_oobmark - offset) @@ -1472,13 +1552,17 @@ dontblock: } if (m && pr->pr_flags & PR_ATOMIC) { +#ifdef __APPLE__ if (so->so_options & SO_DONTTRUNC) flags |= MSG_RCVMORE; - else - { flags |= MSG_TRUNC; + else { +#endif + flags |= MSG_TRUNC; if ((flags & MSG_PEEK) == 0) (void) sbdroprecord(&so->so_rcv); +#ifdef __APPLE__ } +#endif } if ((flags & MSG_PEEK) == 0) { if (m == 0) @@ -1486,8 +1570,10 @@ dontblock: if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) (*pr->pr_usrreqs->pru_rcvd)(so, flags); } +#ifdef __APPLE__ if ((so->so_options & SO_WANTMORE) && so->so_rcv.sb_cc > 0) flags |= MSG_HAVEMORE; +#endif if (orig_resid == uio->uio_resid && orig_resid && (flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) { sbunlock(&so->so_rcv); @@ -1523,21 +1609,20 @@ soshutdown(so, how) KERNEL_DEBUG(DBG_FNC_SOSHUTDOWN | DBG_FUNC_START, 0,0,0,0,0); kp = sotokextcb(so); - while (kp) - { if (kp->e_soif && kp->e_soif->sf_soshutdown) - { ret = (*kp->e_soif->sf_soshutdown)(so, how, kp); + while (kp) { + if (kp->e_soif && kp->e_soif->sf_soshutdown) { + ret = (*kp->e_soif->sf_soshutdown)(so, how, kp); if (ret) return((ret == EJUSTRETURN) ? 0 : ret); } kp = kp->e_next; } - how++; - if (how & FREAD) { + if (how != SHUT_WR) { sorflush(so); postevent(so, 0, EV_RCLOSED); } - if (how & FWRITE) { + if (how != SHUT_RD) { ret = ((*pr->pr_usrreqs->pru_shutdown)(so)); postevent(so, 0, EV_WCLOSED); KERNEL_DEBUG(DBG_FNC_SOSHUTDOWN | DBG_FUNC_END, 0,0,0,0,0); @@ -1559,9 +1644,9 @@ sorflush(so) struct kextcb *kp; kp = sotokextcb(so); - while (kp) - { if (kp->e_soif && kp->e_soif->sf_sorflush) - { if ((*kp->e_soif->sf_sorflush)(so, kp)) + while (kp) { + if (kp->e_soif && kp->e_soif->sf_sorflush) { + if ((*kp->e_soif->sf_sorflush)(so, kp)) return; } kp = kp->e_next; @@ -1572,12 +1657,21 @@ sorflush(so) s = splimp(); socantrcvmore(so); sbunlock(sb); +#ifdef __APPLE__ selthreadclear(&sb->sb_sel); +#endif asb = *sb; bzero((caddr_t)sb, sizeof (*sb)); +#ifndef __APPLE__ + if (asb.sb_flags & SB_KNOTE) { + sb->sb_sel.si_note = asb.sb_sel.si_note; + sb->sb_flags = SB_KNOTE; + } +#endif splx(s); if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) (*pr->pr_domain->dom_dispose)(asb.sb_mb); + sbrelease(&asb); } @@ -1626,10 +1720,14 @@ sosetopt(so, sopt) short val; struct kextcb *kp; + if (sopt->sopt_dir != SOPT_SET) { + sopt->sopt_dir = SOPT_SET; + } + kp = sotokextcb(so); - while (kp) - { if (kp->e_soif && kp->e_soif->sf_socontrol) - { error = (*kp->e_soif->sf_socontrol)(so, sopt, kp); + while (kp) { + if (kp->e_soif && kp->e_soif->sf_socontrol) { + error = (*kp->e_soif->sf_socontrol)(so, sopt, kp); if (error) return((error == EJUSTRETURN) ? 0 : error); } @@ -1665,9 +1763,11 @@ sosetopt(so, sopt) case SO_REUSEPORT: case SO_OOBINLINE: case SO_TIMESTAMP: +#ifdef __APPLE__ case SO_DONTTRUNC: case SO_WANTMORE: - case SO_WANTOOBFLAG: + case SO_WANTOOBFLAG: +#endif error = sooptcopyin(sopt, &optval, sizeof optval, sizeof optval); if (error) @@ -1731,11 +1831,22 @@ sosetopt(so, sopt) if (error) goto bad; - if (tv.tv_sec > SHRT_MAX / hz - hz) { + /* assert(hz > 0); */ + if (tv.tv_sec < 0 || tv.tv_sec > SHRT_MAX / hz || + tv.tv_usec < 0 || tv.tv_usec >= 1000000) { + error = EDOM; + goto bad; + } + /* assert(tick > 0); */ + /* assert(ULONG_MAX - SHRT_MAX >= 1000000); */ + { + long tmp = (u_long)(tv.tv_sec * hz) + tv.tv_usec / tick; + if (tmp > SHRT_MAX) { error = EDOM; goto bad; } - val = tv.tv_sec * hz + tv.tv_usec / tick; + val = tmp; + } switch (sopt->sopt_name) { case SO_SNDTIMEO: @@ -1748,11 +1859,12 @@ sosetopt(so, sopt) break; case SO_NKE: - { struct so_nke nke; + { + struct so_nke nke; struct NFDescriptor *nf1, *nf2 = NULL; - error = sooptcopyin(sopt, &nke, - sizeof nke, sizeof nke); + error = sooptcopyin(sopt, &nke, + sizeof nke, sizeof nke); if (error) goto bad; @@ -1760,6 +1872,18 @@ sosetopt(so, sopt) break; } + case SO_NOSIGPIPE: + error = sooptcopyin(sopt, &optval, sizeof optval, + sizeof optval); + if (error) + goto bad; + if (optval) + so->so_flags |= SOF_NOSIGPIPE; + else + so->so_flags &= ~SOF_NOSIGPIPE; + + break; + default: error = ENOPROTOOPT; break; @@ -1816,10 +1940,14 @@ sogetopt(so, sopt) struct mbuf *m; struct kextcb *kp; + if (sopt->sopt_dir != SOPT_GET) { + sopt->sopt_dir = SOPT_GET; + } + kp = sotokextcb(so); - while (kp) - { if (kp->e_soif && kp->e_soif->sf_socontrol) - { error = (*kp->e_soif->sf_socontrol)(so, sopt, kp); + while (kp) { + if (kp->e_soif && kp->e_soif->sf_socontrol) { + error = (*kp->e_soif->sf_socontrol)(so, sopt, kp); if (error) return((error == EJUSTRETURN) ? 0 : error); } @@ -1850,9 +1978,11 @@ sogetopt(so, sopt) case SO_BROADCAST: case SO_OOBINLINE: case SO_TIMESTAMP: +#ifdef __APPLE__ case SO_DONTTRUNC: case SO_WANTMORE: - case SO_WANTOOBFLAG: + case SO_WANTOOBFLAG: +#endif optval = so->so_options & sopt->sopt_name; integer: error = sooptcopyout(sopt, &optval, sizeof optval); @@ -1862,8 +1992,10 @@ integer: optval = so->so_type; goto integer; +#ifdef __APPLE__ case SO_NREAD: - { int pkt_total; + { + int pkt_total; struct mbuf *m1; pkt_total = 0; @@ -1873,8 +2005,8 @@ integer: #if 0 kprintf("SKT CC: %d\n", so->so_rcv.sb_cc); #endif - while (m1) - { if (m1->m_type == MT_DATA) + while (m1) { + if (m1->m_type == MT_DATA) pkt_total += m1->m_len; #if 0 kprintf("CNT: %d/%d\n", m1->m_len, pkt_total); @@ -1889,6 +2021,7 @@ integer: #endif goto integer; } +#endif case SO_ERROR: optval = so->so_error; so->so_error = 0; @@ -1920,6 +2053,10 @@ integer: error = sooptcopyout(sopt, &tv, sizeof tv); break; + case SO_NOSIGPIPE: + optval = (so->so_flags & SOF_NOSIGPIPE); + goto integer; + default: error = ENOPROTOOPT; break; @@ -1928,29 +2065,7 @@ integer: } } -void -sohasoutofband(so) - register struct socket *so; -{ - struct proc *p; - - struct kextcb *kp; - - kp = sotokextcb(so); - while (kp) - { if (kp->e_soif && kp->e_soif->sf_sohasoutofband) - { if ((*kp->e_soif->sf_sohasoutofband)(so, kp)) - return; - } - kp = kp->e_next; - } - 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); - selwakeup(&so->so_rcv.sb_sel); -} - +#ifdef __APPLE__ /* * Network filter support */ @@ -1987,7 +2102,6 @@ sfilter_init(register struct socket *so) return(0); } - /* * Run the list of filters, freeing extension control blocks * Assumes the soif/soutil blocks have been handled. @@ -2009,46 +2123,11 @@ sfilter_term(struct socket *so) } return(0); } +#endif __APPLE__ - +/* XXX; prepare mbuf for (__FreeBSD__ < 3) routines. */ int -sopoll(struct socket *so, int events, struct ucred *cred, void * wql) -{ - struct proc *p = current_proc(); - int revents = 0; - int s = splnet(); - - if (events & (POLLIN | POLLRDNORM)) - if (soreadable(so)) - revents |= events & (POLLIN | POLLRDNORM); - - if (events & (POLLOUT | POLLWRNORM)) - if (sowriteable(so)) - revents |= events & (POLLOUT | POLLWRNORM); - - if (events & (POLLPRI | POLLRDBAND)) - if (so->so_oobmark || (so->so_state & SS_RCVATMARK)) - revents |= events & (POLLPRI | POLLRDBAND); - - if (revents == 0) { - if (events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) { - so->so_rcv.sb_flags |= SB_SEL; - selrecord(p, &so->so_rcv.sb_sel, wql); - } - - if (events & (POLLOUT | POLLWRNORM)) { - so->so_snd.sb_flags |= SB_SEL; - selrecord(p, &so->so_snd.sb_sel, wql); - } - } - - splx(s); - return (revents); -} - -/*#### IPv6 Integration. Added new routines */ -int -sooptgetm(struct sockopt *sopt, struct mbuf **mp) +soopt_getm(struct sockopt *sopt, struct mbuf **mp) { struct mbuf *m, *m_prev; int sopt_size = sopt->sopt_valsize; @@ -2095,7 +2174,7 @@ sooptgetm(struct sockopt *sopt, struct mbuf **mp) /* XXX; copyin sopt data into mbuf chain for (__FreeBSD__ < 3) routines. */ int -sooptmcopyin(struct sockopt *sopt, struct mbuf *m) +soopt_mcopyin(struct sockopt *sopt, struct mbuf *m) { struct mbuf *m0 = m; @@ -2118,13 +2197,13 @@ sooptmcopyin(struct sockopt *sopt, struct mbuf *m) m = m->m_next; } if (m != NULL) /* should be allocated enoughly at ip6_sooptmcopyin() */ - panic("sooptmcopyin"); + panic("soopt_mcopyin"); return 0; } /* XXX; copyout mbuf chain data into soopt for (__FreeBSD__ < 3) routines. */ int -sooptmcopyout(struct sockopt *sopt, struct mbuf *m) +soopt_mcopyout(struct sockopt *sopt, struct mbuf *m) { struct mbuf *m0 = m; size_t valsize = 0; @@ -2157,3 +2236,61 @@ sooptmcopyout(struct sockopt *sopt, struct mbuf *m) return 0; } +void +sohasoutofband(so) + register struct socket *so; +{ + struct proc *p; + struct kextcb *kp; + + kp = sotokextcb(so); + while (kp) { + if (kp->e_soif && kp->e_soif->sf_sohasoutofband) { + if ((*kp->e_soif->sf_sohasoutofband)(so, kp)) + return; + } + kp = kp->e_next; + } + 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); + selwakeup(&so->so_rcv.sb_sel); +} + +int +sopoll(struct socket *so, int events, struct ucred *cred, void * wql) +{ + struct proc *p = current_proc(); + int revents = 0; + int s = splnet(); + + if (events & (POLLIN | POLLRDNORM)) + if (soreadable(so)) + revents |= events & (POLLIN | POLLRDNORM); + + if (events & (POLLOUT | POLLWRNORM)) + if (sowriteable(so)) + revents |= events & (POLLOUT | POLLWRNORM); + + if (events & (POLLPRI | POLLRDBAND)) + if (so->so_oobmark || (so->so_state & SS_RCVATMARK)) + revents |= events & (POLLPRI | POLLRDBAND); + + if (revents == 0) { + if (events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) { + /* Darwin sets the flag first, BSD calls selrecord first */ + so->so_rcv.sb_flags |= SB_SEL; + selrecord(p, &so->so_rcv.sb_sel, wql); + } + + if (events & (POLLOUT | POLLWRNORM)) { + /* Darwin sets the flag first, BSD calls selrecord first */ + so->so_snd.sb_flags |= SB_SEL; + selrecord(p, &so->so_snd.sb_sel, wql); + } + } + + splx(s); + return (revents); +} diff --git a/bsd/kern/uipc_socket2.c b/bsd/kern/uipc_socket2.c index 33d2ede3b..ae6a6cc9d 100644 --- a/bsd/kern/uipc_socket2.c +++ b/bsd/kern/uipc_socket2.c @@ -54,6 +54,7 @@ * SUCH DAMAGE. * * @(#)uipc_socket2.c 8.1 (Berkeley) 6/10/93 + * $FreeBSD: src/sys/kern/uipc_socket2.c,v 1.55.2.9 2001/07/26 18:53:02 peter Exp $ */ #include @@ -85,8 +86,6 @@ u_long sb_max = SB_MAX; /* XXX should be static */ static u_long sb_efficiency = 8; /* parameter for sbreserve() */ -char netcon[] = "netcon"; - /* * Procedures to manipulate state flags of socket * and do appropriate wakeups. Normal sequence from the @@ -94,7 +93,7 @@ char netcon[] = "netcon"; * 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, + * 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() @@ -104,14 +103,14 @@ char netcon[] = "netcon"; * From the passive side, a socket is created with * two queues of sockets: so_incomp for connections in progress * and so_comp for connections already made and awaiting user acceptance. - * As a protocol is preparing incoming connections, it creates a socket + * As a protocol is preparing incoming connections, it creates a socket * structure queued on so_incomp by calling sonewconn(). When the connection * is established, soisconnected() is called, and transfers the * socket structure to so_comp, making it available to accept(). * - * If a socket is closed with sockets on either + * If a socket is closed with sockets on either * so_incomp or so_comp, these sockets are dropped. - * + * * If higher level protocols are implemented in * the kernel, the wakeups done here will sometimes * cause software-interrupt process scheduling. @@ -128,14 +127,15 @@ soisconnecting(so) void soisconnected(so) - register struct socket *so; -{ register struct kextcb *kp; - register struct socket *head = so->so_head; + struct socket *so; +{ + struct socket *head = so->so_head; + struct kextcb *kp; kp = sotokextcb(so); - while (kp) - { if (kp->e_soif && kp->e_soif->sf_soisconnected) - { if ((*kp->e_soif->sf_soisconnected)(so, kp)) + while (kp) { + if (kp->e_soif && kp->e_soif->sf_soisconnected) { + if ((*kp->e_soif->sf_soisconnected)(so, kp)) return; } kp = kp->e_next; @@ -151,7 +151,7 @@ soisconnected(so) TAILQ_INSERT_TAIL(&head->so_comp, so, so_list); so->so_state |= SS_COMP; sorwakeup(head); - wakeup((caddr_t)&head->so_timeo); + wakeup_one(&head->so_timeo); } else { postevent(so,0,EV_WCONN); wakeup((caddr_t)&so->so_timeo); @@ -163,12 +163,13 @@ soisconnected(so) void soisdisconnecting(so) register struct socket *so; -{ register struct kextcb *kp; +{ + register struct kextcb *kp; kp = sotokextcb(so); - while (kp) - { if (kp->e_soif && kp->e_soif->sf_soisdisconnecting) - { if ((*kp->e_soif->sf_soisdisconnecting)(so, kp)) + while (kp) { + if (kp->e_soif && kp->e_soif->sf_soisdisconnecting) { + if ((*kp->e_soif->sf_soisdisconnecting)(so, kp)) return; } kp = kp->e_next; @@ -184,19 +185,20 @@ soisdisconnecting(so) void soisdisconnected(so) register struct socket *so; -{ register struct kextcb *kp; +{ + register struct kextcb *kp; kp = sotokextcb(so); - while (kp) - { if (kp->e_soif && kp->e_soif->sf_soisdisconnected) - { if ((*kp->e_soif->sf_soisdisconnected)(so, kp)) + while (kp) { + if (kp->e_soif && kp->e_soif->sf_soisdisconnected) { + if ((*kp->e_soif->sf_soisdisconnected)(so, kp)) return; } kp = kp->e_next; } so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING); - so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE); + so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE|SS_ISDISCONNECTED); wakeup((caddr_t)&so->so_timeo); sowwakeup(so); sorwakeup(so); @@ -258,7 +260,8 @@ struct socket * sonewconn(head, connstatus) register struct socket *head; int connstatus; -{ int error = 0; +{ + int error = 0; register struct socket *so; register struct kextcb *kp; @@ -267,14 +270,10 @@ sonewconn(head, connstatus) so = soalloc(1, head->so_proto->pr_domain->dom_family, head->so_type); if (so == NULL) return ((struct socket *)0); - - kp = sotokextcb(so); - while (kp) - { if (kp->e_soif && kp->e_soif->sf_sonewconn1) - { if ((*kp->e_soif->sf_sonewconn1)(so, connstatus, kp)) - return; - } - kp = kp->e_next; + /* check if head was closed during the soalloc */ + if (head->so_proto == NULL) { + sodealloc(so); + return ((struct socket *)0); } so->so_head = head; @@ -286,18 +285,39 @@ sonewconn(head, connstatus) so->so_timeo = head->so_timeo; so->so_pgid = head->so_pgid; so->so_uid = head->so_uid; - so->so_rcv.sb_flags |= SB_RECV; /* XXX */ - - (void) soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat); + /* Attach socket filters for this protocol */ if (so->so_proto->pr_sfilter.tqh_first) error = sfilter_init(so); - if (error == 0 && (*so->so_proto->pr_usrreqs->pru_attach)(so, 0, NULL)) { + if (error != 0) { + sodealloc(so); + return ((struct socket *)0); + } + + /* Call socket filters' sonewconn1 function if set */ + kp = sotokextcb(so); + while (kp) { + if (kp->e_soif && kp->e_soif->sf_sonewconn) { + error = (int)(*kp->e_soif->sf_sonewconn)(so, connstatus, kp); + if (error == EJUSTRETURN) { + return so; + } else if (error != 0) { + sodealloc(so); + return NULL; + } + } + kp = kp->e_next; + } + + if (soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat) || + (*so->so_proto->pr_usrreqs->pru_attach)(so, 0, NULL)) { sfilter_term(so); sodealloc(so); return ((struct socket *)0); } +#ifdef __APPLE__ so->so_proto->pr_domain->dom_refs++; +#endif if (connstatus) { TAILQ_INSERT_TAIL(&head->so_comp, so, so_list); @@ -313,8 +333,10 @@ sonewconn(head, connstatus) wakeup((caddr_t)&head->so_timeo); so->so_state |= connstatus; } +#ifdef __APPLE__ so->so_rcv.sb_so = so->so_snd.sb_so = so; TAILQ_INIT(&so->so_evlist); +#endif return (so); } @@ -331,12 +353,13 @@ sonewconn(head, connstatus) void socantsendmore(so) struct socket *so; -{ register struct kextcb *kp; - +{ + register struct kextcb *kp; + kp = sotokextcb(so); - while (kp) - { if (kp->e_soif && kp->e_soif->sf_socantsendmore) - { if ((*kp->e_soif->sf_socantsendmore)(so, kp)) + while (kp) { + if (kp->e_soif && kp->e_soif->sf_socantsendmore) { + if ((*kp->e_soif->sf_socantsendmore)(so, kp)) return; } kp = kp->e_next; @@ -350,12 +373,13 @@ socantsendmore(so) void socantrcvmore(so) struct socket *so; -{ register struct kextcb *kp; +{ + register struct kextcb *kp; kp = sotokextcb(so); - while (kp) - { if (kp->e_soif && kp->e_soif->sf_socantrcvmore) - { if ((*kp->e_soif->sf_socantrcvmore)(so, kp)) + while (kp) { + if (kp->e_soif && kp->e_soif->sf_socantrcvmore) { + if ((*kp->e_soif->sf_socantrcvmore)(so, kp)) return; } kp = kp->e_next; @@ -413,13 +437,10 @@ sowakeup(so, sb) register struct sockbuf *sb; { struct proc *p = current_proc(); - - - - + /* We clear the flag before calling selwakeup. */ + /* BSD calls selwakeup then sets the flag */ sb->sb_flags &= ~SB_SEL; selwakeup(&sb->sb_sel); - if (sb->sb_flags & SB_WAIT) { sb->sb_flags &= ~SB_WAIT; wakeup((caddr_t)&sb->sb_cc); @@ -430,7 +451,6 @@ sowakeup(so, sb) else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0) psignal(p, SIGIO); } - if (sb->sb_flags & SB_UPCALL) (*so->so_upcall)(so, so->so_upcallarg, M_DONTWAIT); } @@ -475,9 +495,9 @@ soreserve(so, sndcc, rcvcc) register struct kextcb *kp; kp = sotokextcb(so); - while (kp) - { if (kp->e_soif && kp->e_soif->sf_soreserve) - { if ((*kp->e_soif->sf_soreserve)(so, sndcc, rcvcc, kp)) + while (kp) { + if (kp->e_soif && kp->e_soif->sf_soreserve) { + if ((*kp->e_soif->sf_soreserve)(so, sndcc, rcvcc, kp)) return; } kp = kp->e_next; @@ -495,7 +515,9 @@ soreserve(so, sndcc, rcvcc) so->so_snd.sb_lowat = so->so_snd.sb_hiwat; return (0); bad2: +#ifdef __APPLE__ selthreadclear(&so->so_snd.sb_sel); +#endif sbrelease(&so->so_snd); bad: return (ENOBUFS); @@ -530,15 +552,9 @@ sbrelease(sb) { sbflush(sb); - sb->sb_hiwat = sb->sb_mbmax = 0; -#if 0 - /* this is getting called with bzeroed sb in sorflush */ - { - int oldpri = splimp(); - selthreadclear(&sb->sb_sel); - splx(oldpri); - } -#endif + sb->sb_hiwat = 0; + sb->sb_mbmax = 0; + } /* @@ -576,7 +592,8 @@ void sbappend(sb, m) struct sockbuf *sb; struct mbuf *m; -{ register struct kextcb *kp; +{ + struct kextcb *kp; register struct mbuf *n; @@ -585,15 +602,15 @@ sbappend(sb, m) if (m == 0) return; kp = sotokextcb(sbtoso(sb)); - while (kp) - { if (kp->e_sout && kp->e_sout->su_sbappend) - { if ((*kp->e_sout->su_sbappend)(sb, m, kp)) + while (kp) { + if (kp->e_sout && kp->e_sout->su_sbappend) { + if ((*kp->e_sout->su_sbappend)(sb, m, kp)) return; } kp = kp->e_next; } - - if (n = sb->sb_mb) { + n = sb->sb_mb; + if (n) { while (n->m_nextpkt) n = n->m_nextpkt; do { @@ -620,18 +637,24 @@ sbcheck(sb) for (m = sb->sb_mb; m; m = n) { n = m->m_nextpkt; for (; m; m = m->m_next) { - len += m->m_len; - mbcnt += MSIZE; - if (m->m_flags & M_EXT) /*XXX*/ /* pretty sure this is bogus */ - mbcnt += m->m_ext.ext_size; - if (m->m_nextpkt) - panic("sbcheck nextpkt"); - } - if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) { - printf("cc %ld != %ld || mbcnt %ld != %ld\n", len, sb->sb_cc, - mbcnt, sb->sb_mbcnt); - panic("sbcheck"); + len += m->m_len; + mbcnt += MSIZE; + if (m->m_flags & M_EXT) /*XXX*/ /* pretty sure this is bogus */ + mbcnt += m->m_ext.ext_size; + } } +#ifndef __APPLE__ + if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) { + printf("cc %ld != %ld || mbcnt %ld != %ld\n", len, sb->sb_cc, + mbcnt, sb->sb_mbcnt); + panic("sbcheck"); + } +#else + if (len != sb->sb_cc) + printf("sbcheck len %ld != sb_cc %ld\n", len, sb->sb_cc); + if (mbcnt != sb->sb_mbcnt) + printf("sbcheck mbcnt %ld != sb_mbcnt %ld\n", mbcnt, sb->sb_mbcnt); +#endif } #endif @@ -646,7 +669,7 @@ sbappendrecord(sb, m0) { register struct mbuf *m; register struct kextcb *kp; - + if (m0 == 0) return; @@ -867,8 +890,12 @@ sbcompress(sb, m, n) 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] && + if (n && (n->m_flags & M_EOR) == 0 && +#ifndef __APPLE__ + M_WRITABLE(n) && +#endif + m->m_len <= MCLBYTES / 4 && /* XXX: Don't copy too much */ + m->m_len <= M_TRAILINGSPACE(n) && n->m_type == m->m_type) { bcopy(mtod(m, caddr_t), mtod(n, caddr_t) + n->m_len, (unsigned)m->m_len); @@ -907,18 +934,25 @@ sbflush(sb) register struct kextcb *kp; kp = sotokextcb(sbtoso(sb)); - while (kp) - { if (kp->e_sout && kp->e_sout->su_sbflush) - { if ((*kp->e_sout->su_sbflush)(sb, kp)) + while (kp) { + if (kp->e_sout && kp->e_sout->su_sbflush) { + if ((*kp->e_sout->su_sbflush)(sb, kp)) return; } kp = kp->e_next; } if (sb->sb_flags & SB_LOCK) - panic("sbflush: locked"); - while (sb->sb_mbcnt && sb->sb_cc) + sb_lock(sb); + while (sb->sb_mbcnt) { + /* + * Don't call sbdrop(sb, 0) if the leading mbuf is non-empty: + * we would loop forever. Panic instead. + */ + if (!sb->sb_cc && (sb->sb_mb == NULL || sb->sb_mb->m_len)) + break; sbdrop(sb, (int)sb->sb_cc); + } if (sb->sb_cc || sb->sb_mb || sb->sb_mbcnt) panic("sbflush: cc %ld || mb %p || mbcnt %ld", sb->sb_cc, (void *)sb->sb_mb, sb->sb_mbcnt); postevent(0, sb, EV_RWBYTES); @@ -926,6 +960,14 @@ sbflush(sb) /* * Drop data from (the front of) a sockbuf. + * use m_freem_list to free the mbuf structures + * under a single lock... this is done by pruning + * the top of the tree from the body by keeping track + * of where we get to in the tree and then zeroing the + * two pertinent pointers m_nextpkt and m_next + * the socket buffer is then updated to point at the new + * top of the tree and the pruned area is released via + * m_freem_list. */ void sbdrop(sb, len) @@ -939,9 +981,9 @@ sbdrop(sb, len) KERNEL_DEBUG((DBG_FNC_SBDROP | DBG_FUNC_START), sb, len, 0, 0, 0); kp = sotokextcb(sbtoso(sb)); - while (kp) - { if (kp->e_sout && kp->e_sout->su_sbdrop) - { if ((*kp->e_sout->su_sbdrop)(sb, len, kp)) + while (kp) { + if (kp->e_sout && kp->e_sout->su_sbdrop) { + if ((*kp->e_sout->su_sbdrop)(sb, len, kp)) return; } kp = kp->e_next; @@ -952,11 +994,23 @@ sbdrop(sb, len) while (len > 0) { if (m == 0) { - if (next == 0) - panic("sbdrop"); - m = last = next; - next = m->m_nextpkt; - continue; + if (next == 0) { + /* temporarily replacing this panic with printf because + * it occurs occasionally when closing a socket when there + * is no harm in ignoring it. This problem will be investigated + * further. + */ + /* panic("sbdrop"); */ + printf("sbdrop - count not zero\n"); + len = 0; + /* zero the counts. if we have no mbufs, we have no data (PR-2986815) */ + sb->sb_cc = 0; + sb->sb_mbcnt = 0; + break; + } + m = last = next; + next = m->m_nextpkt; + continue; } if (m->m_len > len) { m->m_len -= len; @@ -1004,9 +1058,9 @@ sbdroprecord(sb) register struct kextcb *kp; kp = sotokextcb(sbtoso(sb)); - while (kp) - { if (kp->e_sout && kp->e_sout->su_sbdroprecord) - { if ((*kp->e_sout->su_sbdroprecord)(sb, kp)) + while (kp) { + if (kp->e_sout && kp->e_sout->su_sbdroprecord) { + if ((*kp->e_sout->su_sbdroprecord)(sb, kp)) return; } kp = kp->e_next; @@ -1018,7 +1072,8 @@ sbdroprecord(sb) do { sbfree(sb, m); MFREE(m, mn); - } while (m = mn); + m = mn; + } while (m); } postevent(0, sb, EV_RWBYTES); } @@ -1036,14 +1091,15 @@ sbcreatecontrol(p, size, type, level) register struct cmsghdr *cp; struct mbuf *m; + if (CMSG_SPACE((u_int)size) > MLEN) + return ((struct mbuf *) NULL); if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL) return ((struct mbuf *) NULL); cp = mtod(m, struct cmsghdr *); /* XXX check size? */ (void)memcpy(CMSG_DATA(cp), p, size); - size += sizeof(*cp); - m->m_len = size; - cp->cmsg_len = size; + m->m_len = CMSG_SPACE(size); + cp->cmsg_len = CMSG_LEN(size); cp->cmsg_level = level; cp->cmsg_type = type; return (m); @@ -1207,6 +1263,10 @@ int pru_sopoll_notsupp(struct socket *so, int events, } +#ifdef __APPLE__ +/* + * The following are macros on BSD and functions on Darwin + */ /* * Do we need to notify the other side when I/O is possible? @@ -1317,6 +1377,7 @@ sowwakeup(struct socket * so) if (sb_notify(&so->so_snd)) sowakeup(so, &so->so_snd); } +#endif __APPLE__ /* * Make a copy of a sockaddr in a malloced buffer of type M_SONAME. @@ -1389,16 +1450,16 @@ sbtoxsockbuf(struct sockbuf *sb, struct xsockbuf *xsb) * Here is the definition of some of the basic objects in the kern.ipc * branch of the MIB. */ - - SYSCTL_NODE(_kern, KERN_IPC, ipc, CTLFLAG_RW, 0, "IPC"); /* This takes the place of kern.maxsockbuf, which moved to kern.ipc. */ static int dummy; SYSCTL_INT(_kern, KERN_DUMMY, dummy, CTLFLAG_RW, &dummy, 0, ""); -SYSCTL_INT(_kern_ipc, KIPC_MAXSOCKBUF, maxsockbuf, CTLFLAG_RW, &sb_max, 0, ""); -SYSCTL_INT(_kern_ipc, OID_AUTO, maxsockets, CTLFLAG_RD, &maxsockets, 0, ""); +SYSCTL_INT(_kern_ipc, KIPC_MAXSOCKBUF, maxsockbuf, CTLFLAG_RW, + &sb_max, 0, "Maximum socket buffer size"); +SYSCTL_INT(_kern_ipc, OID_AUTO, maxsockets, CTLFLAG_RD, + &maxsockets, 0, "Maximum number of sockets avaliable"); SYSCTL_INT(_kern_ipc, KIPC_SOCKBUF_WASTE, sockbuf_waste_factor, CTLFLAG_RW, &sb_efficiency, 0, ""); SYSCTL_INT(_kern_ipc, KIPC_NMBCLUSTERS, nmbclusters, CTLFLAG_RD, &nmbclusters, 0, ""); diff --git a/bsd/kern/uipc_syscalls.c b/bsd/kern/uipc_syscalls.c index d6482c0a2..228d2d62a 100644 --- a/bsd/kern/uipc_syscalls.c +++ b/bsd/kern/uipc_syscalls.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -542,6 +542,7 @@ sendit(p, s, mp, flags, retsize) struct socket *so; #if KTRACE struct iovec *ktriov = NULL; + struct uio ktruio; #endif KERNEL_DEBUG(DBG_FNC_SENDIT | DBG_FUNC_START, 0,0,0,0,0); @@ -613,6 +614,15 @@ sendit(p, s, mp, flags, retsize) } else control = 0; +#if KTRACE + if (KTRPOINT(p, KTR_GENIO)) { + int iovlen = auio.uio_iovcnt * sizeof (struct iovec); + + MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); + bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen); + ktruio = auio; + } +#endif len = auio.uio_resid; so = (struct socket *)fp->f_data; error = so->so_proto->pr_usrreqs->pru_sosend(so, to, &auio, 0, control, @@ -621,16 +631,19 @@ sendit(p, s, mp, flags, retsize) if (auio.uio_resid != len && (error == ERESTART || error == EINTR || error == EWOULDBLOCK)) error = 0; - if (error == EPIPE) + /* Generation of SIGPIPE can be controlled per socket */ + if (error == EPIPE && !(so->so_flags & SOF_NOSIGPIPE)) psignal(p, SIGPIPE); } if (error == 0) *retsize = len - auio.uio_resid; #if KTRACE if (ktriov != NULL) { - if (error == 0) - ktrgenio(p->p_tracep, s, UIO_WRITE, - ktriov, *retsize, error); + if (error == 0) { + ktruio.uio_iov = ktriov; + ktruio.uio_resid = retsize[0]; + ktrgenio(p->p_tracep, s, UIO_WRITE, &ktruio, error, -1); + } FREE(ktriov, M_TEMP); } #endif @@ -833,6 +846,7 @@ recvit(p, s, mp, namelenp, retval) struct sockaddr *fromsa = 0; #if KTRACE struct iovec *ktriov = NULL; + struct uio ktruio; #endif KERNEL_DEBUG(DBG_FNC_RECVIT | DBG_FUNC_START, 0,0,0,0,0); @@ -862,6 +876,7 @@ recvit(p, s, mp, namelenp, retval) MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen); + ktruio = auio; } #endif len = auio.uio_resid; @@ -876,9 +891,11 @@ recvit(p, s, mp, namelenp, retval) } #if KTRACE if (ktriov != NULL) { - if (error == 0) - ktrgenio(p->p_tracep, s, UIO_WRITE, - ktriov, len - auio.uio_resid, error); + if (error == 0) { + ktruio.uio_iov = ktriov; + ktruio.uio_resid = len - auio.uio_resid; + ktrgenio(p->p_tracep, s, UIO_WRITE, &ktruio, error, -1); + } FREE(ktriov, M_TEMP); } #endif @@ -1033,15 +1050,17 @@ orecvfrom(p, uap, retval) #ifdef COMPAT_OLDSOCK +struct orecv_args { + int s; + caddr_t buf; + int len; + int flags; +}; + int orecv(p, uap, retval) struct proc *p; - register struct orecv_args { - int s; - caddr_t buf; - int len; - int flags; - } *uap; + struct orecv_args *uap; register_t *retval; { struct msghdr msg; @@ -1063,14 +1082,16 @@ orecv(p, uap, retval) * overlays the new one, missing only the flags, and with the (old) access * rights where the control fields are now. */ +struct orecvmsg_args { + int s; + struct omsghdr *msg; + int flags; +}; + int orecvmsg(p, uap, retval) struct proc *p; - register struct orecvmsg_args { - int s; - struct omsghdr *msg; - int flags; - } *uap; + struct orecvmsg_args *uap; register_t *retval; { struct msghdr msg; @@ -1107,14 +1128,16 @@ done: } #endif +struct recvmsg_args { + int s; + struct msghdr *msg; + int flags; +}; + int recvmsg(p, uap, retval) struct proc *p; - register struct recvmsg_args { - int s; - struct msghdr *msg; - int flags; - } *uap; + struct recvmsg_args *uap; register_t *retval; { struct msghdr msg; @@ -1163,13 +1186,15 @@ done: } /* ARGSUSED */ +struct shutdown_args { + int s; + int how; +}; + int shutdown(p, uap, retval) struct proc *p; - register struct shutdown_args { - int s; - int how; - } *uap; + struct shutdown_args *uap; register_t *retval; { struct file *fp; @@ -1186,16 +1211,18 @@ shutdown(p, uap, retval) /* ARGSUSED */ +struct setsockopt_args { + int s; + int level; + int name; + caddr_t val; + int valsize; +}; + int setsockopt(p, uap, retval) struct proc *p; - register struct setsockopt_args { - int s; - int level; - int name; - caddr_t val; - int valsize; - } *uap; + struct setsockopt_args *uap; register_t *retval; { struct file *fp; diff --git a/bsd/kern/uipc_usrreq.c b/bsd/kern/uipc_usrreq.c index 459a67a05..905652bee 100644 --- a/bsd/kern/uipc_usrreq.c +++ b/bsd/kern/uipc_usrreq.c @@ -502,7 +502,7 @@ unp_attach(so) if (error) return (error); } - unp = zalloc(unp_zone); + unp = (struct unpcb*)zalloc(unp_zone); if (unp == NULL) return (ENOBUFS); bzero(unp, sizeof *unp); @@ -550,7 +550,7 @@ unp_detach(unp) } if (unp->unp_addr) FREE(unp->unp_addr, M_SONAME); - zfree(unp_zone, unp); + zfree(unp_zone, (vm_offset_t)unp); } static int @@ -568,7 +568,6 @@ unp_bind(unp, nam, p) if (unp->unp_vnode != NULL) return (EINVAL); -#define offsetof(s, e) ((char *)&((s *)0)->e - (char *)((s *)0)) namelen = soun->sun_len - offsetof(struct sockaddr_un, sun_path); if (namelen <= 0) return EINVAL; @@ -884,7 +883,7 @@ unp_drop(unp, errno) so->so_pcb = (caddr_t) 0; if (unp->unp_addr) FREE(unp->unp_addr, M_SONAME); - zfree(unp_zone, unp); + zfree(unp_zone, (vm_offset_t)unp); sofree(so); } } diff --git a/bsd/libkern/libkern.h b/bsd/libkern/libkern.h index 25511e503..16c005525 100644 --- a/bsd/libkern/libkern.h +++ b/bsd/libkern/libkern.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -57,18 +57,24 @@ #ifndef _LIBKERN_LIBKERN_H_ #define _LIBKERN_LIBKERN_H_ +#include #include #include +#ifdef __APPLE_API_OBSOLETE /* BCD conversions. */ extern u_char const bcd2bin_data[]; extern u_char const bin2bcd_data[]; -extern char const hex2ascii_data[]; #define bcd2bin(bcd) (bcd2bin_data[bcd]) #define bin2bcd(bin) (bin2bcd_data[bin]) -#define hex2ascii(hex) (hex2ascii_data[hex]) +#endif /* __APPLE_API_OBSOLETE */ +#ifdef __APPLE_API_PRIVATE +extern char const hex2ascii_data[]; + +#define hex2ascii(hex) (hex2ascii_data[hex]) +#endif /* __APPLE_API_PRIVATE */ __BEGIN_DECLS static inline int diff --git a/bsd/machine/Makefile b/bsd/machine/Makefile index ee8dd6af2..86558ef33 100644 --- a/bsd/machine/Makefile +++ b/bsd/machine/Makefile @@ -12,7 +12,7 @@ DATAFILES = \ ansi.h byte_order.h cons.h cpu.h disklabel.h endian.h exec.h \ label_t.h param.h proc.h profile.h psl.h ptrace.h reboot.h \ reg.h setjmp.h signal.h spl.h table.h trap.h types.h unix_traps.h \ - user.h vmparam.h + ucontext.h user.h vmparam.h INSTALL_MI_LIST = ${DATAFILES} diff --git a/bsd/machine/ansi.h b/bsd/machine/ansi.h index 57cef4960..8f34cdd79 100644 --- a/bsd/machine/ansi.h +++ b/bsd/machine/ansi.h @@ -29,7 +29,6 @@ #ifndef _MACHINE_ANSI_H_ #define _MACHINE_ANSI_H_ - #if defined (__ppc__) #include "ppc/ansi.h" #elif defined (__i386__) @@ -38,5 +37,10 @@ #error architecture not supported #endif +#ifdef KERNEL +#ifndef offsetof +#define offsetof(type, member) ((size_t)(&((type *)0)->member)) +#endif /* offsetof */ +#endif /* KERNEL */ #endif /* _MACHINE_ANSI_H_ */ diff --git a/bsd/machine/ucontext.h b/bsd/machine/ucontext.h new file mode 100644 index 000000000..56cf8137d --- /dev/null +++ b/bsd/machine/ucontext.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#ifndef _MACHINE_UCONTEXT_H_ +#define _MACHINE_UCONTEXT_H_ + +#if defined (__ppc__) +#include "ppc/ucontext.h" +#elif defined (__i386__) +#include "i386/ucontext.h" +#else +#error architecture not supported +#endif + +#endif /* _MACHINE_UCONTEXT_H_ */ diff --git a/bsd/man/Makefile b/bsd/man/Makefile new file mode 100644 index 000000000..a287125bd --- /dev/null +++ b/bsd/man/Makefile @@ -0,0 +1,18 @@ +export MakeInc_cmd=${SRCROOT}/makedefs/MakeInc.cmd +export MakeInc_def=${SRCROOT}/makedefs/MakeInc.def +export MakeInc_rule=${SRCROOT}/makedefs/MakeInc.rule +export MakeInc_dir=${SRCROOT}/makedefs/MakeInc.dir + + +include $(MakeInc_cmd) +include $(MakeInc_def) + +INSTMAN_SUBDIRS = \ + man2 \ + man4 \ + man5 \ + man9 + +include $(MakeInc_rule) +include $(MakeInc_dir) + diff --git a/bsd/man/man2/Makefile b/bsd/man/man2/Makefile new file mode 100644 index 000000000..504f0f10a --- /dev/null +++ b/bsd/man/man2/Makefile @@ -0,0 +1,163 @@ +export MakeInc_cmd=${SRCROOT}/makedefs/MakeInc.cmd +export MakeInc_def=${SRCROOT}/makedefs/MakeInc.def +export MakeInc_rule=${SRCROOT}/makedefs/MakeInc.rule +export MakeInc_dir=${SRCROOT}/makedefs/MakeInc.dir + +include $(MakeInc_cmd) +include $(MakeInc_def) + +DATAFILES = \ + __syscall.2 \ + _exit.2 \ + accept.2 \ + access.2 \ + acct.2 \ + adjtime.2 \ + bind.2 \ + brk.2 \ + chdir.2 \ + chflags.2 \ + chmod.2 \ + chown.2 \ + chroot.2 \ + close.2 \ + connect.2 \ + dup.2 \ + dup2.2 \ + execve.2 \ + fchdir.2 \ + fchflags.2 \ + fchmod.2 \ + fchown.2 \ + fcntl.2 \ + flock.2 \ + fork.2 \ + fpathconf.2 \ + fstat.2 \ + fstatfs.2 \ + fsync.2 \ + ftruncate.2 \ + futimes.2 \ + getdirentries.2 \ + getegid.2 \ + geteuid.2 \ + getfh.2 \ + getfsstat.2 \ + getgid.2 \ + getgroups.2 \ + getitimer.2 \ + getlogin.2 \ + getpeername.2 \ + getpgrp.2 \ + getpgid.2 \ + getpid.2 \ + getppid.2 \ + getpriority.2 \ + getrlimit.2 \ + getrusage.2 \ + getsid.2 \ + getsockname.2 \ + getsockopt.2 \ + gettimeofday.2 \ + getuid.2 \ + intro.2 \ + ioctl.2 \ + issetugid.2 \ + kill.2 \ + ktrace.2 \ + lchown.2 \ + link.2 \ + listen.2 \ + lseek.2 \ + lstat.2 \ + madvise.2 \ + mincore.2 \ + minherit.2 \ + mkdir.2 \ + mkfifo.2 \ + mknod.2 \ + mlock.2 \ + mmap.2 \ + mount.2 \ + mprotect.2 \ + msync.2 \ + munlock.2 \ + munmap.2 \ + nfssvc.2 \ + open.2 \ + pathconf.2 \ + pipe.2 \ + posix_madvise.2 \ + pread.2 \ + profil.2 \ + ptrace.2 \ + pwrite.2 \ + quotactl.2 \ + read.2 \ + readlink.2 \ + readv.2 \ + reboot.2 \ + recv.2 \ + recvfrom.2 \ + recvmsg.2 \ + rename.2 \ + revoke.2 \ + rmdir.2 \ + sbrk.2 \ + select.2 \ + send.2 \ + sendmsg.2 \ + sendto.2 \ + setegid.2 \ + seteuid.2 \ + setgid.2 \ + setgroups.2 \ + setitimer.2 \ + setlogin.2 \ + setpgid.2 \ + setpgrp.2 \ + setpriority.2 \ + setrlimit.2 \ + setsid.2 \ + setsockopt.2 \ + settimeofday.2 \ + setuid.2 \ + shmat.2 \ + shmctl.2 \ + shmdt.2 \ + shmget.2 \ + shutdown.2 \ + sigaction.2 \ + sigaltstack.2 \ + sigpending.2 \ + sigprocmask.2 \ + sigreturn.2 \ + sigstack.2 \ + sigsuspend.2 \ + socket.2 \ + socketpair.2 \ + stat.2 \ + statfs.2 \ + symlink.2 \ + sync.2 \ + syscall.2 \ + truncate.2 \ + umask.2 \ + unlink.2 \ + unmount.2 \ + utimes.2 \ + vfork.2 \ + wait.2 \ + wait3.2 \ + wait4.2 \ + waitpid.2 \ + write.2 \ + writev.2 \ + +INSTALL_MAN_LIST = ${DATAFILES} + +INSTALL_MAN_DIR = man2 + +include $(MakeInc_rule) +include $(MakeInc_dir) + diff --git a/bsd/man/man2/__syscall.2 b/bsd/man/man2/__syscall.2 new file mode 100644 index 000000000..0bf5debf7 --- /dev/null +++ b/bsd/man/man2/__syscall.2 @@ -0,0 +1 @@ +.so man2/syscall.2 diff --git a/bsd/man/man2/_exit.2 b/bsd/man/man2/_exit.2 new file mode 100644 index 000000000..402de8fb9 --- /dev/null +++ b/bsd/man/man2/_exit.2 @@ -0,0 +1,114 @@ +.\" $NetBSD: _exit.2,v 1.6 1995/02/27 12:31:34 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1993 +.\" 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. +.\" +.\" @(#)_exit.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt EXIT 2 +.Os BSD 4 +.Sh NAME +.Nm _exit +.Nd terminate the calling process +.Sh SYNOPSIS +.Fd #include +.Ft void +.Fn _exit "int status" +.Sh DESCRIPTION +The +.Fn _exit +function +terminates a process with the following consequences: +.Bl -bullet +.It +All of the descriptors open in the calling process are closed. +This may entail delays, for example, waiting for output to drain; +a process in this state may not be killed, as it is already dying. +.It +If the parent process of the calling process has an outstanding +.Xr wait +call +or catches the +.Dv SIGCHLD +signal, +it is notified of the calling process's termination and +the +.Em status +is set as defined by +.Xr wait 2 . +.It +The parent process-ID of all of the calling process's existing child +processes are set to 1; the initialization process +(see the DEFINITIONS section of +.Xr intro 2 ) +inherits each of these processes. +.It +If the termination of the process causes any process group +to become orphaned (usually because the parents of all members +of the group have now exited; see +.Dq orphaned process group +in +.Xr intro 2 ) , +and if any member of the orphaned group is stopped, +the +.Dv SIGHUP +signal and the +.Dv SIGCONT +signal are sent to all members of the newly-orphaned process group. +.It +If the process is a controlling process (see +.Xr intro 2 ) , +the +.Dv SIGHUP +signal is sent to the foreground process group of the controlling terminal, +and all current access to the controlling terminal is revoked. +.El +.Pp +Most C programs call the library routine +.Xr exit 3 , +which flushes buffers, closes streams, unlinks temporary files, etc., +before +calling +.Fn _exit . +.Sh RETURN VALUE +.Fn _exit +can never return. +.Sh SEE ALSO +.Xr fork 2 , +.Xr sigaction 2 , +.Xr wait 2 , +.Xr exit 3 +.Sh STANDARDS +The +.Nm _exit +function is defined by +.St -p1003.1-88 . diff --git a/bsd/man/man2/accept.2 b/bsd/man/man2/accept.2 new file mode 100644 index 000000000..f62dbc3ba --- /dev/null +++ b/bsd/man/man2/accept.2 @@ -0,0 +1,172 @@ +.\" $NetBSD: accept.2,v 1.7 1996/01/31 20:14:42 mycroft Exp $ +.\" +.\" Copyright (c) 1983, 1990, 1991, 1993 +.\" 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. +.\" +.\" @(#)accept.2 8.2 (Berkeley) 12/11/93 +.\" +.Dd December 11, 1993 +.Dt ACCEPT 2 +.Os BSD 4.2 +.Sh NAME +.Nm accept +.Nd accept a connection on a socket +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn accept "int s" "struct sockaddr *addr" "int *addrlen" +.Sh DESCRIPTION +The argument +.Fa s +is a socket that has been created with +.Xr socket 2 , +bound to an address with +.Xr bind 2 , +and is listening for connections after a +.Xr listen 2 . +The +.Fn accept +argument +extracts the first connection request +on the queue of pending connections, creates +a new socket with the same properties of +.Fa s +and allocates a new file descriptor +for the socket. If no pending connections are +present on the queue, and the socket is not marked +as non-blocking, +.Fn accept +blocks the caller until a connection is present. +If the socket is marked non-blocking and no pending +connections are present on the queue, +.Fn accept +returns an error as described below. +The accepted socket +may not be used +to accept more connections. The original socket +.Fa s +remains open. +.Pp +The argument +.Fa addr +is a result parameter that is filled in with +the address of the connecting entity, +as known to the communications layer. +The exact format of the +.Fa addr +parameter is determined by the domain in which the communication +is occurring. +The +.Fa addrlen +is a value-result parameter; it should initially contain the +amount of space pointed to by +.Fa addr ; +on return it will contain the actual length (in bytes) of the +address returned. +This call +is used with connection-based socket types, currently with +.Dv SOCK_STREAM . +.Pp +It is possible to +.Xr select 2 +a socket for the purposes of doing an +.Fn accept +by selecting it for read. +.Pp +For certain protocols which require an explicit confirmation, +such as +.Tn ISO +or +.Tn DATAKIT , +.Fn accept +can be thought of +as merely dequeuing the next connection +request and not implying confirmation. +Confirmation can be implied by a normal read or write on the new +file descriptor, and rejection can be implied by closing the +new socket. +.Pp +One can obtain user connection request data without confirming +the connection by issuing a +.Xr recvmsg 2 +call with an +.Fa msg_iovlen +of 0 and a non-zero +.Fa msg_controllen , +or by issuing a +.Xr getsockopt 2 +request. +Similarly, one can provide user connection rejection information +by issuing a +.Xr sendmsg 2 +call with providing only the control information, +or by calling +.Xr setsockopt 2 . +.Sh RETURN VALUES +The call returns \-1 on error. If it succeeds, it returns a non-negative +integer that is a descriptor for the accepted socket. +.Sh ERRORS +The +.Fn accept +will fail if: +.Bl -tag -width Er +.It Bq Er EBADF +The descriptor is invalid. +.It Bq Er ENOTSOCK +The descriptor references a file, not a socket. +.It Bq Er EOPNOTSUPP +The referenced socket is not of type +.Dv SOCK_STREAM . +.It Bq Er EFAULT +The +.Fa addr +parameter is not in a writable part of the +user address space. +.It Bq Er EWOULDBLOCK +The socket is marked non-blocking and no connections +are present to be accepted. +.It Bq Er EMFILE +The per-process descriptor table is full. +.It Bq Er ENFILE +The system file table is full. +.El +.Sh SEE ALSO +.Xr bind 2 , +.Xr connect 2 , +.Xr listen 2 , +.Xr select 2 , +.Xr socket 2 +.Sh HISTORY +The +.Fn accept +function appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/access.2 b/bsd/man/man2/access.2 new file mode 100644 index 000000000..0d168d3c8 --- /dev/null +++ b/bsd/man/man2/access.2 @@ -0,0 +1,137 @@ +.\" $NetBSD: access.2,v 1.7 1995/02/27 12:31:44 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.\" @(#)access.2 8.2 (Berkeley) 4/1/94 +.\" +.Dd April 1, 1994 +.Dt ACCESS 2 +.Os BSD 4 +.Sh NAME +.Nm access +.Nd check access permissions of a file or pathname +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn access "const char *path" "int mode" +.Sh DESCRIPTION +The +.Fn access +function checks the accessibility of the +file named by +.Fa path +for the access permissions indicated by +.Fa mode . +The value of +.Fa mode +is the bitwise inclusive OR of the access permissions to be +checked +.Pf ( Dv R_OK +for read permission, +.Dv W_OK +for write permission and +.Dv X_OK +for execute/search permission) or the existence test, +.Dv F_OK . +All components of the pathname +.Fa path +are checked for access permissions (including +.Dv F_OK ) . +.Pp +The real user ID is used in place of the effective user ID +and the real group access list +(including the real group ID) are +used in place of the effective ID for verifying permission. +.Pp +Even if a process has appropriate privileges and indicates success for +.Dv X_OK , +the file may not actually have execute permission bits set. +Likewise for +.Dv R_OK +and +.Dv W_OK . +.Sh RETURN VALUES +If +.Fa path +cannot be found or if any of the desired access modes would +not be granted, then a -1 value is returned; otherwise +a 0 value is returned. +.Sh ERRORS +Access to the file is denied if: +.Bl -tag -width Er +.It Bq Er ENOTDIR +A component of the path prefix is not a directory. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded +.Dv {NAME_MAX} +characters, or an entire path name exceeded +.Dv {PATH_MAX} +characters. +.It Bq Er ENOENT +The named file does not exist. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating the pathname. +.It Bq Er EROFS +Write access is requested for a file on a read-only file system. +.It Bq Er ETXTBSY +Write access is requested for a pure procedure (shared text) +file presently being executed. +.It Bq Er EACCES +Permission bits of the file mode do not permit the requested +access, or search permission is denied on a component of the +path prefix. The owner of a file has permission checked with +respect to the ``owner'' read, write, and execute mode bits, +members of the file's group other than the owner have permission +checked with respect to the ``group'' mode bits, and all +others have permissions checked with respect to the ``other'' +mode bits. +.It Bq Er EFAULT +.Fa Path +points outside the process's allocated address space. +.It Bq Er EIO +An I/O error occurred while reading from or writing to the file system. +.It Bq Er EINVAL +An invalid value was specified for +.Ar mode . +.El +.Sh SEE ALSO +.Xr chmod 2 , +.Xr stat 2 +.Sh STANDARDS +The +.Fn access +function conforms to +.St -p1003.1-90 . +.Sh CAVEAT +.Fn Access +is a potential security hole and +should never be used. diff --git a/bsd/man/man2/acct.2 b/bsd/man/man2/acct.2 new file mode 100644 index 000000000..5c041ec7e --- /dev/null +++ b/bsd/man/man2/acct.2 @@ -0,0 +1,119 @@ +.\" $NetBSD: acct.2,v 1.6 1995/02/27 12:31:47 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt ACCT 2 +.Os BSD 4 +.Sh NAME +.Nm acct +.Nd enable or disable process accounting +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn acct "const char *file" +.Sh DESCRIPTION +The +.Fn acct +call enables or disables the collection of system accounting +records. +If the argument +.Fa file +is a nil pointer, accounting is disabled. +If +.Fa file +is an +.Em existing +pathname (null-terminated), record collection is enabled and for +every process initiated which terminates under normal +conditions an accounting record is appended to +.Fa file . +Abnormal conditions of termination are reboots +or other fatal system problems. +Records for processes which never terminate can not be +produced by +.Fn acct . +.Pp +For more information on the record structure used by +.Fn acct , +see +.Pa /usr/include/sys/acct.h +and +.Xr acct 5 . +.Pp +This call is permitted only to the super-user. +.Sh NOTES +Accounting is automatically disabled when the file system the +accounting file resides on runs out of space; it is enabled when +space once again becomes available. +.Sh RETURN VALUES +On error -1 is returned. +The file must exist and the call may be exercised only by the super-user. +.Sh ERRORS +.Fn Acct +will fail if one of the following is true: +.Bl -tag -width Er +.It Bq Er EPERM +The caller is not the super-user. +.It Bq Er ENOTDIR +A component of the path prefix is not a directory. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded +.Dv {NAME_MAX} +characters, or an entire path name exceeded +.Dv {PATH_MAX} +characters. +.It Bq Er ENOENT +The named file does not exist. +.It Bq Er EACCES +Search permission is denied for a component of the path prefix, +or the path name is not a regular file. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating the pathname. +.It Bq Er EROFS +The named file resides on a read-only file system. +.It Bq Er EFAULT +.Fa File +points outside the process's allocated address space. +.It Bq Er EIO +An I/O error occurred while reading from or writing to the file system. +.El +.Sh SEE ALSO +.Xr acct 5 , +.Xr sa 8 +.Sh HISTORY +An +.Fn acct +function call appeared in +.At v7 . diff --git a/bsd/man/man2/adjtime.2 b/bsd/man/man2/adjtime.2 new file mode 100644 index 000000000..30bf72b78 --- /dev/null +++ b/bsd/man/man2/adjtime.2 @@ -0,0 +1,113 @@ +.\" $NetBSD: adjtime.2,v 1.5 1995/10/12 15:40:44 jtc Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.\" @(#)adjtime.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt ADJTIME 2 +.Os BSD 4.3 +.Sh NAME +.Nm adjtime +.Nd "correct the time to allow synchronization of the system clock" +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn adjtime "const struct timeval *delta" "struct timeval *olddelta" +.Sh DESCRIPTION +.Fn Adjtime +makes small adjustments to the system time, as returned by +.Xr gettimeofday 2 , +advancing or retarding it +by the time specified by the timeval +.Fa delta . +If +.Fa delta +is negative, the clock is +slowed down by incrementing it more slowly than normal until +the correction is complete. +If +.Fa delta +is positive, a larger increment than normal +is used. +The skew used to perform the correction is generally a fraction of one percent. +Thus, the time is always +a monotonically increasing function. +A time correction from an earlier call to +.Fn adjtime +may not be finished when +.Fn adjtime +is called again. +If +.Fa olddelta +is non-nil, +the structure pointed to will contain, upon return, the +number of microseconds still to be corrected +from the earlier call. +.Pp +This call may be used by time servers that synchronize the clocks +of computers in a local area network. +Such time servers would slow down the clocks of some machines +and speed up the clocks of others to bring them to the average network time. +.Pp +The call +.Fn adjtime +is restricted to the super-user. +.Sh RETURN VALUES +A return value of 0 indicates that the call succeeded. +A return value of -1 indicates that an error occurred, and in this +case an error code is stored in the global variable +.Va errno . +.Sh ERRORS +.Fn Adjtime +will fail if: +.Bl -tag -width Er +.It Bq Er EFAULT +An argument points outside the process's allocated address space. +.It Bq Er EPERM +The process's effective user ID is not that of the super-user. +.El +.Sh SEE ALSO +.Xr date 1 , +.Xr gettimeofday 2 , +.Xr timed 8 , +.Xr timedc 8 , +.Rs +.%T "TSP: The Time Synchronization Protocol for UNIX 4.3BSD" +.%A R. Gusella +.%A S. Zatti +.Re +.Sh HISTORY +The +.Fn adjtime +function call appeared in +.Bx 4.3 . diff --git a/bsd/man/man2/bind.2 b/bsd/man/man2/bind.2 new file mode 100644 index 000000000..9c4404cdd --- /dev/null +++ b/bsd/man/man2/bind.2 @@ -0,0 +1,129 @@ +.\" $NetBSD: bind.2,v 1.8 1995/10/12 15:40:46 jtc Exp $ +.\" +.\" Copyright (c) 1983, 1993 +.\" 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. +.\" +.\" @(#)bind.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt BIND 2 +.Os BSD 4.2 +.Sh NAME +.Nm bind +.Nd bind a name to a socket +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn bind "int s" "const struct sockaddr *name" "int namelen" +.Sh DESCRIPTION +.Fn Bind +assigns a name to an unnamed socket. +When a socket is created +with +.Xr socket 2 +it exists in a name space (address family) +but has no name assigned. +.Fn Bind +requests that +.Fa name +be assigned to the socket. +.Sh NOTES +Binding a name in the UNIX domain creates a socket in the file +system that must be deleted by the caller when it is no longer +needed (using +.Xr unlink 2 ) . +.Pp +The rules used in name binding vary between communication domains. +Consult the manual entries in section 4 for detailed information. +.Sh RETURN VALUES +If the bind is successful, a 0 value is returned. +A return value of -1 indicates an error, which is +further specified in the global +.Va errno . +.Sh ERRORS +The +.Fn bind +call will fail if: +.Bl -tag -width Er +.It Bq Er EBADF +.Fa S +is not a valid descriptor. +.It Bq Er ENOTSOCK +.Fa S +is not a socket. +.It Bq Er EADDRNOTAVAIL +The specified address is not available from the local machine. +.It Bq Er EADDRINUSE +The specified address is already in use. +.It Bq Er EINVAL +The socket is already bound to an address. +.It Bq Er EACCES +The requested address is protected, and the current user +has inadequate permission to access it. +.It Bq Er EFAULT +The +.Fa name +parameter is not in a valid part of the user +address space. +.El +.Pp +The following errors are specific to binding names in the UNIX domain. +.Bl -tag -width Er +.It Bq Er ENOTDIR +A component of the path prefix is not a directory. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded +.Dv {NAME_MAX} +characters, or an entire path name exceeded +.Dv {PATH_MAX} +characters. +.It Bq Er ENOENT +A prefix component of the path name does not exist. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating the pathname. +.It Bq Er EIO +An I/O error occurred while making the directory entry or allocating the inode. +.It Bq Er EROFS +The name would reside on a read-only file system. +.It Bq Er EISDIR +An empty pathname was specified. +.El +.Sh SEE ALSO +.Xr connect 2 , +.Xr listen 2 , +.Xr socket 2 , +.Xr getsockname 2 +.Sh HISTORY +The +.Fn bind +function call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/brk.2 b/bsd/man/man2/brk.2 new file mode 100644 index 000000000..f580c15f6 --- /dev/null +++ b/bsd/man/man2/brk.2 @@ -0,0 +1,150 @@ +.\" $NetBSD: brk.2,v 1.7 1995/02/27 12:31:57 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.\" @(#)brk.2 8.2 (Berkeley) 12/11/93 +.\" +.Dd December 11, 1993 +.Dt BRK 2 +.Os BSD 4 +.Sh NAME +.Nm brk , +.Nm sbrk +.Nd change data segment size +.Sh SYNOPSIS +.Fd #include +.Ft char * +.Fn brk "const char *addr" +.Ft char * +.Fn sbrk "int incr" +.Sh DESCRIPTION +.Bf -symbolic +The brk and sbrk functions are historical curiosities +left over from earlier days before the advent of virtual memory management. +.Ef +The +.Fn brk +function +sets the break or lowest address +of a process's data segment (uninitialized data) to +.Fa addr +(immediately above bss). +Data addressing is restricted between +.Fa addr +and the lowest stack pointer to the stack segment. +Memory is allocated by +.Fa brk +in page size pieces; +if +.Fa addr +is not evenly divisible by the system page size, it is +increased to the next page boundary. +.Pp +.\" The +.\" .Nm sbrk +.\" function +.\" allocates chunks of +.\" .Fa incr +.\" bytes +.\" to the process's data space +.\" and returns an address pointer. +.\" The +.\" .Xr malloc 3 +.\" function utilizes +.\" .Nm sbrk . +.\" .Pp +The current value of the program break is reliably returned by +.Dq Li sbrk(0) +(see also +.Xr end 3 ) . +The +.Xr getrlimit 2 +system call may be used to determine +the maximum permissible size of the +.Em data +segment; +it will not be possible to set the break +beyond the +.Em rlim_max +value returned from a call to +.Xr getrlimit , +e.g. +.Dq qetext + rlp\(->rlim_max. +(see +.Xr end 3 +for the definition of +.Em etext ) . +.Sh RETURN VALUES +.Nm Brk +returns a pointer to the new end of memory if successful; +otherwise -1 with +.Va errno +set to indicate why the allocation failed. +The +.Nm sbrk +function returns a pointer to the base of the new storage if successful; +otherwise -1 with +.Va errno +set to indicate why the allocation failed. +.Sh ERRORS +.Xr Sbrk +will fail and no additional memory will be allocated if +one of the following are true: +.Bl -tag -width Er +.It Bq Er ENOMEM +The limit, as set by +.Xr setrlimit 2 , +was exceeded. +.It Bq Er ENOMEM +The maximum possible size of a data segment (compiled into the +system) was exceeded. +.It Bq Er ENOMEM +Insufficient space existed in the swap area +to support the expansion. +.El +.Sh SEE ALSO +.Xr execve 2 , +.Xr getrlimit 2 , +.Xr malloc 3 , +.Xr mmap 2 , +.Xr end 3 +.Sh BUGS +Setting the break may fail due to a temporary lack of +swap space. It is not possible to distinguish this +from a failure caused by exceeding the maximum size of +the data segment without consulting +.Xr getrlimit . +.Sh HISTORY +A +.Fn brk +function call appeared in +.At v7 . diff --git a/bsd/man/man2/chdir.2 b/bsd/man/man2/chdir.2 new file mode 100644 index 000000000..407f709e2 --- /dev/null +++ b/bsd/man/man2/chdir.2 @@ -0,0 +1,133 @@ +.\" $NetBSD: chdir.2,v 1.7 1995/02/27 12:32:00 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.\" @(#)chdir.2 8.2 (Berkeley) 12/11/93 +.\" +.Dd December 11, 1993 +.Dt CHDIR 2 +.Os BSD 4 +.Sh NAME +.Nm chdir , +.Nm fchdir +.Nd change current working directory +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn chdir "const char *path" +.Ft int +.Fn fchdir "int fd" +.Sh DESCRIPTION +The +.Fa path +argument points to the pathname of a directory. +The +.Fn chdir +function +causes the named directory +to become the current working directory, that is, +the starting point for path searches of pathnames not beginning with +a slash, +.Ql / . +.Pp +The +.Fn fchdir +function +causes the directory referenced by +.Fa fd +to become the current working directory, +the starting point for path searches of pathnames not beginning with +a slash, +.Ql / . +.Pp +In order for a directory to become the current directory, +a process must have execute (search) access to the directory. +.Sh RETURN VALUES +Upon successful completion, a value of 0 is returned. +Otherwise, a value of -1 is returned and +.Va errno +is set to indicate +the error. +.Sh ERRORS +.Fn Chdir +will fail and the current working directory will be unchanged if +one or more of the following are true: +.Bl -tag -width Er +.It Bq Er ENOTDIR +A component of the path prefix is not a directory. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded +.Dv {NAME_MAX} +characters, or an entire path name exceeded +.Dv {PATH_MAX} +characters. +.It Bq Er ENOENT +The named directory does not exist. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating the pathname. +.It Bq Er EACCES +Search permission is denied for any component of +the path name. +.It Bq Er EFAULT +.Fa Path +points outside the process's allocated address space. +.It Bq Er EIO +An I/O error occurred while reading from or writing to the file system. +.El +.Pp +.Fn Fchdir +will fail and the current working directory will be unchanged if +one or more of the following are true: +.Bl -tag -width Er +.It Bq Er EACCES +Search permission is denied for the directory referenced by the +file descriptor. +.It Bq Er ENOTDIR +The file descriptor does not reference a directory. +.It Bq Er EBADF +The argument +.Fa fd +is not a valid file descriptor. +.El +.Sh SEE ALSO +.Xr chroot 2 +.Sh STANDARDS +The +.Fn chdir +is expected to conform to +.St -p1003.1-88 . +.Sh HISTORY +The +.Fn fchdir +function call +appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/chflags.2 b/bsd/man/man2/chflags.2 new file mode 100644 index 000000000..48a949e8f --- /dev/null +++ b/bsd/man/man2/chflags.2 @@ -0,0 +1,157 @@ +.\" $NetBSD: chflags.2,v 1.6 1995/02/27 12:32:03 cgd Exp $ +.\" +.\" Copyright (c) 1989, 1993 +.\" 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. +.\" +.\" @(#)chflags.2 8.1 (Berkeley) 6/9/93 +.\" +.Dd June 9, 1993 +.Dt CHFLAGS 2 +.Os +.Sh NAME +.Nm chflags , +.Nm fchflags +.Nd set file flags +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn chflags "const char *path" "u_long flags" +.Ft int +.Fn fchflags "int fd" "u_long flags" +.Sh DESCRIPTION +The file whose name +is given by +.Fa path +or referenced by the descriptor +.Fa fd +has its flags changed to +.Fa flags . +.Pp +The flags specified are formed by +.Em or Ns 'ing +the following values +.Pp +.Bl -tag -width "SF_IMMUTABLE" -compact -offset indent +.It UF_NODUMP +Do not dump the file. +.It UF_IMMUTABLE +The file may not be changed. +.It UF_APPEND +The file may only be appended to. +.\".It ARCHIVED +.\"File is archived. +.It SF_IMMUTABLE +The file may not be changed. +.It SF_APPEND +The file may only be appended to. +.El +.Pp +The +.Dq UF_IMMUTABLE +and +.Dq UF_APPEND +flags may be set or unset by either the owner of a file or the super-user. +.Pp +The +.Dq SF_IMMUTABLE +and +.Dq SF_APPEND +flags may only be set or unset by the super-user. +They may be set at any time, but normally may only be unset when +the system is in single-user mode. +(See +.Xr init 8 +for details.) +.Sh RETURN VALUES +Upon successful completion, a value of 0 is returned. +Otherwise, -1 is returned and the global variable +.Va errno +is set to indicate the error. +.Sh ERRORS +.Fn Chflags +will fail it: +.Bl -tag -width Er +.It Bq Er ENOTDIR +A component of the path prefix is not a directory. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded +.Dv {NAME_MAX} +characters, or an entire path name exceeded +.Dv {PATH_MAX} +characters. +.It Bq Er ENOENT +The named file does not exist. +.It Bq Er EACCES +Search permission is denied for a component of the path prefix. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating the pathname. +.It Bq Er EPERM +The effective user ID does not match the owner of the file and +the effective user ID is not the super-user. +.It Bq Er EROFS +The named file resides on a read-only file system. +.It Bq Er EFAULT +.Fa Path +points outside the process's allocated address space. +.It Bq Er EIO +An +.Tn I/O +error occurred while reading from or writing to the file system. +.El +.Pp +.Fn Fchflags +will fail if: +.Bl -tag -width Er +.It Bq Er EBADF +The descriptor is not valid. +.It Bq Er EINVAL +.Fa Fd +refers to a socket, not to a file. +.It Bq Er EPERM +The effective user ID does not match the owner of the file and +the effective user ID is not the super-user. +.It Bq Er EROFS +The file resides on a read-only file system. +.It Bq Er EIO +An +.Tn I/O +error occurred while reading from or writing to the file system. +.El +.Sh SEE ALSO +.Xr chflags 1 , +.Xr init 8 +.Sh HISTORY +The +.Fn chflags +and +.Nm fchflags +functions first appeared in 4.4BSD. diff --git a/bsd/man/man2/chmod.2 b/bsd/man/man2/chmod.2 new file mode 100644 index 000000000..302be5974 --- /dev/null +++ b/bsd/man/man2/chmod.2 @@ -0,0 +1,187 @@ +.\" $NetBSD: chmod.2,v 1.7 1995/02/27 12:32:06 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.\" @(#)chmod.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt CHMOD 2 +.Os BSD 4 +.Sh NAME +.Nm chmod , +.Nm fchmod +.Nd change mode of file +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn chmod "const char *path" "mode_t mode" +.Ft int +.Fn fchmod "int fd" "mode_t mode" +.Sh DESCRIPTION +The function +.Fn chmod +sets the file permission bits +of the file +specified by the pathname +.Fa path +to +.Fa mode . +.Fn Fchmod +sets the permission bits of the specified +file descriptor +.Fa fd . +.Fn Chmod +verifies that the process owner (user) either owns +the file specified by +.Fa path +(or +.Fa fd ) , +or +is the super-user. +A mode is created from +.Em or'd +permission bit masks +defined in +.Aq Pa sys/stat.h : +.Bd -literal -offset indent -compact +#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 */ + +#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 */ + +#define S_ISUID 0004000 /* set user id on execution */ +#define S_ISGID 0002000 /* set group id on execution */ +#define S_ISVTX 0001000 /* save swapped text even after use */ +.Ed +.Pp +The +.Dv ISVTX +(the +.Em sticky bit ) +indicates to the system which executable files are shareable (the +default) and the system maintains the program text of the files +in the swap area. The sticky bit may only be set by the super user +on shareable executable files. +.Pp +If mode +.Dv ISVTX +(the `sticky bit') is set on a directory, +an unprivileged user may not delete or rename +files of other users in that directory. The sticky bit may be +set by any user on a directory which the user owns or has appropriate +permissions. +For more details of the properties of the sticky bit, see +.Xr sticky 8 . +.Pp +Writing or changing the owner of a file +turns off the set-user-id and set-group-id bits +unless the user is the super-user. +This makes the system somewhat more secure +by protecting set-user-id (set-group-id) files +from remaining set-user-id (set-group-id) if they are modified, +at the expense of a degree of compatibility. +.Sh RETURN VALUES +Upon successful completion, a value of 0 is returned. +Otherwise, a value of -1 is returned and +.Va errno +is set to indicate the error. +.Sh ERRORS +.Fn Chmod +will fail and the file mode will be unchanged if: +.Bl -tag -width Er +.It Bq Er ENOTDIR +A component of the path prefix is not a directory. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded +.Dv {NAME_MAX} +characters, or an entire path name exceeded +.Dv {PATH_MAX} +characters. +.It Bq Er ENOENT +The named file does not exist. +.It Bq Er EACCES +Search permission is denied for a component of the path prefix. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating the pathname. +.It Bq Er EPERM +The effective user ID does not match the owner of the file and +the effective user ID is not the super-user. +.It Bq Er EROFS +The named file resides on a read-only file system. +.It Bq Er EFAULT +.Fa Path +points outside the process's allocated address space. +.It Bq Er EIO +An I/O error occurred while reading from or writing to the file system. +.El +.Pp +.Fn Fchmod +will fail if: +.Bl -tag -width Er +.It Bq Er EBADF +The descriptor is not valid. +.It Bq Er EINVAL +.Fa Fd +refers to a socket, not to a file. +.It Bq Er EROFS +The file resides on a read-only file system. +.It Bq Er EIO +An I/O error occurred while reading from or writing to the file system. +.El +.Sh SEE ALSO +.Xr chmod 1 , +.Xr open 2 , +.Xr chown 2 , +.Xr stat 2 , +.Xr sticky 8 +.Sh STANDARDS +The +.Fn chmod +function is expected to conform to +.St -p1003.1-88 . +.Sh HISTORY +The +.Fn fchmod +function call +appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/chown.2 b/bsd/man/man2/chown.2 new file mode 100644 index 000000000..3e5f14801 --- /dev/null +++ b/bsd/man/man2/chown.2 @@ -0,0 +1,153 @@ +.\" $OpenBSD: chown.2,v 1.3 1997/01/26 05:10:33 downsj Exp $ +.\" $NetBSD: chown.2,v 1.10 1995/10/12 15:40:47 jtc Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993, 1994 +.\" 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. +.\" +.\" @(#)chown.2 8.4 (Berkeley) 4/19/94 +.\" +.Dd January 25, 1997 +.Dt CHOWN 2 +.Os +.Sh NAME +.Nm chown , +.Nm fchown +.Nd change owner and group of a file or link +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn chown "const char *path" "uid_t owner" "gid_t group" +.Ft int +.Fn fchown "int fd" "uid_t owner" "gid_t group" +.Sh DESCRIPTION +The owner ID and group ID of the file (or link) +named by +.Fa path +or referenced by +.Fa fd +is changed as specified by the arguments +.Fa owner +and +.Fa group . +The owner of a file may change the +.Fa group +to a group of which +he or she is a member, +but the change +.Fa owner +capability is restricted to the super-user. +.Pp +.Fn Chown +clears the set-user-id and set-group-id bits +on the file +to prevent accidental or mischievous creation of +set-user-id and set-group-id programs. +.Pp +.Fn Fchown +is particularly useful when used in conjunction +with the file locking primitives (see +.Xr flock 2 ) . +.Pp +One of the owner or group id's +may be left unchanged by specifying it as -1. +.Sh RETURN VALUES +Zero is returned if the operation was successful; +-1 is returned if an error occurs, with a more specific +error code being placed in the global variable +.Va errno . +.Sh ERRORS +.Fn Chown +will fail and the file or link will be unchanged if: +.Bl -tag -width Er +.It Bq Er ENOTDIR +A component of the path prefix is not a directory. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded +.Dv {NAME_MAX} +characters, or an entire path name exceeded +.Dv {PATH_MAX} +characters. +.It Bq Er ENOENT +The named file does not exist. +.It Bq Er EACCES +Search permission is denied for a component of the path prefix. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating the pathname. +.It Bq Er EPERM +The effective user ID is not the super-user. +.It Bq Er EROFS +The named file resides on a read-only file system. +.It Bq Er EFAULT +.Fa Path +points outside the process's allocated address space. +.It Bq Er EIO +An I/O error occurred while reading from or writing to the file system. +.El +.Pp +.Fn Fchown +will fail if: +.Bl -tag -width Er +.It Bq Er EBADF +.Fa Fd +does not refer to a valid descriptor. +.It Bq Er EINVAL +.Fa Fd +refers to a socket, not a file. +.It Bq Er EPERM +The effective user ID is not the super-user. +.It Bq Er EROFS +The named file resides on a read-only file system. +.It Bq Er EIO +An I/O error occurred while reading from or writing to the file system. +.El +.Sh SEE ALSO +.Xr chown 8 , +.Xr chgrp 1 , +.Xr chmod 2 , +.Xr flock 2 +.Sh STANDARDS +The +.Fn chown +function is expected to conform to +.St -p1003.1-88 . +.Sh HISTORY +The +.Fn fchown +function call appeared in +.Bx 4.2 . +.Pp +The +.Fn chown +and +.Fn fchown +functions were changed to follow symbolic links in +.Bx 4.4 . diff --git a/bsd/man/man2/chroot.2 b/bsd/man/man2/chroot.2 new file mode 100644 index 000000000..2bdb61d11 --- /dev/null +++ b/bsd/man/man2/chroot.2 @@ -0,0 +1,108 @@ +.\" $NetBSD: chroot.2,v 1.7 1995/02/27 12:32:12 cgd Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)chroot.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt CHROOT 2 +.Os BSD 4.2 +.Sh NAME +.Nm chroot +.Nd change root directory +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn chroot "const char *dirname" +.Sh DESCRIPTION +.Fa Dirname +is the address of the pathname of a directory, terminated by an ASCII NUL. +.Fn Chroot +causes +.Fa dirname +to become the root directory, +that is, the starting point for path searches of pathnames +beginning with +.Ql / . +.Pp +In order for a directory to become the root directory +a process must have execute (search) access for that directory. +.Pp +If the program is not currently running with an altered root directory, +it should be noted that +.Fn chroot +has no effect on the process's current directory. +.Pp +If the program is already running with an altered root directory, the +process's current directory is changed to the same new root directory. +This prevents the current directory from being further up the directory +tree than the altered root directory. +.Pp +This call is restricted to the super-user. +.Sh RETURN VALUES +Upon successful completion, a value of 0 is returned. Otherwise, +a value of -1 is returned and +.Va errno +is set to indicate an error. +.Sh ERRORS +.Fn Chroot +will fail and the root directory will be unchanged if: +.Bl -tag -width Er +.It Bq Er ENOTDIR +A component of the path name is not a directory. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded +.Dv {NAME_MAX} +characters, or an entire path name exceeded +.Dv {PATH_MAX} +characters. +.It Bq Er ENOENT +The named directory does not exist. +.It Bq Er EACCES +Search permission is denied for any component of the path name. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating the pathname. +.It Bq Er EFAULT +.Fa Path +points outside the process's allocated address space. +.It Bq Er EIO +An I/O error occurred while reading from or writing to the file system. +.El +.Sh SEE ALSO +.Xr chdir 2 +.Sh WARNINGS +There are ways for a root process to escape from the chroot jail. +.Sh HISTORY +The +.Fn chroot +function call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/close.2 b/bsd/man/man2/close.2 new file mode 100644 index 000000000..5cd4d18ec --- /dev/null +++ b/bsd/man/man2/close.2 @@ -0,0 +1,122 @@ +.\" $NetBSD: close.2,v 1.5 1995/02/27 12:32:14 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993, 1994 +.\" 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. +.\" +.\" @(#)close.2 8.2 (Berkeley) 4/19/94 +.\" +.Dd April 19, 1994 +.Dt CLOSE 2 +.Os BSD 4 +.Sh NAME +.Nm close +.Nd delete a descriptor +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn close "int d" +.Sh DESCRIPTION +The +.Fn close +call deletes a descriptor from the per-process object +reference table. +If this is the last reference to the underlying object, the +object will be deactivated. +For example, on the last close of a file +the current +.Em seek +pointer associated with the file is lost; +on the last close of a +.Xr socket 2 +associated naming information and queued data are discarded; +on the last close of a file holding an advisory lock +the lock is released (see further +.Xr flock 2 ) . +.Pp +When a process exits, +all associated file descriptors are freed, but since there is +a limit on active descriptors per processes, the +.Fn close +function call +is useful when a large quantity of file descriptors are being handled. +.Pp +When a process forks (see +.Xr fork 2 ) , +all descriptors for the new child process reference the same +objects as they did in the parent before the fork. +If a new process is then to be run using +.Xr execve 2 , +the process would normally inherit these descriptors. Most +of the descriptors can be rearranged with +.Xr dup2 2 +or deleted with +.Fn close +before the +.Xr execve +is attempted, but if some of these descriptors will still +be needed if the execve fails, it is necessary to arrange for them +to be closed if the execve succeeds. +For this reason, the call +.Dq Li fcntl(d, F_SETFD, 1) +is provided, +which arranges that a descriptor will be closed after a successful +execve; the call +.Dq Li fcntl(d, F_SETFD, 0) +restores the default, +which is to not close the descriptor. +.Sh RETURN VALUES +Upon successful completion, a value of 0 is returned. +Otherwise, a value of -1 is returned and the global integer variable +.Va errno +is set to indicate the error. +.Sh ERRORS +.Fn Close +will fail if: +.Bl -tag -width Er +.It Bq Er EBADF +.Fa D +is not an active descriptor. +.It Bq Er EINTR +An interrupt was received. +.El +.Sh SEE ALSO +.Xr accept 2 , +.Xr flock 2 , +.Xr open 2 , +.Xr pipe 2 , +.Xr socket 2 , +.Xr socketpair 2 , +.Xr execve 2 , +.Xr fcntl 2 +.Sh STANDARDS +.Fn Close +conforms to +.St -p1003.1-88 . diff --git a/bsd/man/man2/connect.2 b/bsd/man/man2/connect.2 new file mode 100644 index 000000000..6f8d8db18 --- /dev/null +++ b/bsd/man/man2/connect.2 @@ -0,0 +1,150 @@ +.\" $NetBSD: connect.2,v 1.8 1995/10/12 15:40:48 jtc Exp $ +.\" +.\" Copyright (c) 1983, 1993 +.\" 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. +.\" +.\" @(#)connect.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt CONNECT 2 +.Os BSD 4.2 +.Sh NAME +.Nm connect +.Nd initiate a connection on a socket +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn connect "int s" "const struct sockaddr *name" "int namelen" +.Sh DESCRIPTION +The parameter +.Fa s +is a socket. +If it is of type +.Dv SOCK_DGRAM , +this call specifies the peer with which the socket is to be associated; +this address is that to which datagrams are to be sent, +and the only address from which datagrams are to be received. +If the socket is of type +.Dv SOCK_STREAM , +this call attempts to make a connection to +another socket. +The other socket is specified by +.Fa name , +which is an address in the communications space of the socket. +Each communications space interprets the +.Fa name +parameter in its own way. +Generally, stream sockets may successfully +.Fn connect +only once; datagram sockets may use +.Fn connect +multiple times to change their association. +Datagram sockets may dissolve the association +by connecting to an invalid address, such as a null address. +.Sh RETURN VALUES +If the connection or binding succeeds, 0 is returned. +Otherwise a -1 is returned, and a more specific error +code is stored in +.Va errno . +.Sh ERRORS +The +.Fn connect +call fails if: +.Bl -tag -width Er +.It Bq Er EBADF +.Fa S +is not a valid descriptor. +.It Bq Er ENOTSOCK +.Fa S +is a descriptor for a file, not a socket. +.It Bq Er EADDRNOTAVAIL +The specified address is not available on this machine. +.It Bq Er EAFNOSUPPORT +Addresses in the specified address family cannot be used with this socket. +.It Bq Er EISCONN +The socket is already connected. +.It Bq Er ETIMEDOUT +Connection establishment timed out without establishing a connection. +.It Bq Er ECONNREFUSED +The attempt to connect was forcefully rejected. +.It Bq Er ENETUNREACH +The network isn't reachable from this host. +.It Bq Er EADDRINUSE +The address is already in use. +.It Bq Er EFAULT +The +.Fa name +parameter specifies an area outside +the process address space. +.It Bq Er EINPROGRESS +The socket is non-blocking +and the connection cannot +be completed immediately. +It is possible to +.Xr select 2 +for completion by selecting the socket for writing. +.It Bq Er EALREADY +The socket is non-blocking +and a previous connection attempt +has not yet been completed. +.El +.Pp +The following errors are specific to connecting names in the UNIX domain. +These errors may not apply in future versions of the UNIX IPC domain. +.Bl -tag -width Er +.It Bq Er ENOTDIR +A component of the path prefix is not a directory. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded +.Dv {NAME_MAX} +characters, or an entire path name exceeded +.Dv {PATH_MAX} +characters. +.It Bq Er ENOENT +The named socket does not exist. +.It Bq Er EACCES +Search permission is denied for a component of the path prefix. +.It Bq Er EACCES +Write access to the named socket is denied. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating the pathname. +.El +.Sh SEE ALSO +.Xr accept 2 , +.Xr select 2 , +.Xr socket 2 , +.Xr getsockname 2 +.Sh HISTORY +The +.Fn connect +function call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/dup.2 b/bsd/man/man2/dup.2 new file mode 100644 index 000000000..b9c0b1980 --- /dev/null +++ b/bsd/man/man2/dup.2 @@ -0,0 +1,133 @@ +.\" $NetBSD: dup.2,v 1.4 1995/02/27 12:32:21 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.\" @(#)dup.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt DUP 2 +.Os BSD 4 +.Sh NAME +.Nm dup , +.Nm dup2 +.Nd duplicate an existing file descriptor +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn dup "int oldd" +.Ft int +.Fn dup2 "int oldd" "int newd" +.Sh DESCRIPTION +.Fn Dup +duplicates an existing object descriptor and returns its value to +the calling process +.Fa ( newd += +.Fn dup oldd ) . +The argument +.Fa oldd +is a small non-negative integer index in +the per-process descriptor table. The value must be less +than the size of the table, which is returned by +.Xr getdtablesize 2 . +The new descriptor returned by the call +is the lowest numbered descriptor +currently not in use by the process. +.Pp +The object referenced by the descriptor does not distinguish +between +.Fa oldd +and +.Fa newd +in any way. +Thus if +.Fa newd +and +.Fa oldd +are duplicate references to an open +file, +.Xr read 2 , +.Xr write 2 +and +.Xr lseek 2 +calls all move a single pointer into the file, +and append mode, non-blocking I/O and asynchronous I/O options +are shared between the references. +If a separate pointer into the file is desired, a different +object reference to the file must be obtained by issuing an +additional +.Xr open 2 +call. +The close-on-exec flag on the new file descriptor is unset. +.Pp +In +.Fn dup2 , +the value of the new descriptor +.Fa newd +is specified. If this descriptor is already +in use, the descriptor is first deallocated as if a +.Xr close 2 +call had been done first. +.Sh RETURN VALUES +The value -1 is returned if an error occurs in either call. +The external variable +.Va errno +indicates the cause of the error. +.Sh ERRORS +.Fn Dup +and +.Fn dup2 +fail if: +.Bl -tag -width Er +.It Bq Er EBADF +.Fa Oldd +or +.Fa newd +is not a valid active descriptor +.It Bq Er EMFILE +Too many descriptors are active. +.El +.Sh SEE ALSO +.Xr accept 2 , +.Xr open 2 , +.Xr close 2 , +.Xr fcntl 2 , +.Xr pipe 2 , +.Xr socket 2 , +.Xr socketpair 2 , +.Xr getdtablesize 2 +.Sh STANDARDS +.Fn Dup +and +.Fn dup2 +are expected to conform to +.St -p1003.1-88 . diff --git a/bsd/man/man2/dup2.2 b/bsd/man/man2/dup2.2 new file mode 100644 index 000000000..49a65c65d --- /dev/null +++ b/bsd/man/man2/dup2.2 @@ -0,0 +1 @@ +.so man2/dup.2 diff --git a/bsd/man/man2/execve.2 b/bsd/man/man2/execve.2 new file mode 100644 index 000000000..c5c9838e6 --- /dev/null +++ b/bsd/man/man2/execve.2 @@ -0,0 +1,270 @@ +.\" $NetBSD: execve.2,v 1.9 1995/02/27 12:32:25 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.\" @(#)execve.2 8.3 (Berkeley) 1/24/94 +.\" +.Dd January 24, 1994 +.Dt EXECVE 2 +.Os BSD 4 +.Sh NAME +.Nm execve +.Nd execute a file +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn execve "const char *path" "char *const argv[]" "char *const envp[]" +.Sh DESCRIPTION +.Fn Execve +transforms the calling process into a new process. +The new process is constructed from an ordinary file, +whose name is pointed to by +.Fa path , +called the +.Em new process file . +This file is either an executable object file, +or a file of data for an interpreter. +An executable object file consists of an identifying header, +followed by pages of data representing the initial program (text) +and initialized data pages. Additional pages may be specified +by the header to be initialized with zero data; see +.Xr a.out 5 . +.Pp +An interpreter file begins with a line of the form: +.Pp +.Bd -filled -offset indent -compact +.Sy \&#! +.Em interpreter +.Bq Em arg +.Ed +.Pp +When an interpreter file is +.Fn execve Ap d , +the system +.Fn execve Ap s +runs the specified +.Em interpreter . +If the optional +.Em arg +is specified, it becomes the first argument to the +.Em interpreter , +and the name of the originally +.Fn execve Ap d +file becomes the second argument; +otherwise, the name of the originally +.Fn execve Ap d +file becomes the first argument. The original arguments are shifted over to +become the subsequent arguments. The zeroth argument, normally the name of the +.Fn execve Ap d +file, is left unchanged. +.Pp +The argument +.Fa argv +is a pointer to a null-terminated array of +character pointers to null-terminated character strings. +These strings construct the argument list to be made available to the new +process. At least one argument must be present in +the array; by custom, the first element should be +the name of the executed program (for example, the last component of +.Fa path ) . +.Pp +The argument +.Fa envp +is also a pointer to a null-terminated array of +character pointers to null-terminated strings. +A pointer to this array is normally stored in the global variable +.Va environ. +These strings pass information to the +new process that is not directly an argument to the command (see +.Xr environ 7 ) . +.Pp +File descriptors open in the calling process image remain open in +the new process image, except for those for which the close-on-exec +flag is set (see +.Xr close 2 +and +.Xr fcntl 2 ) . +Descriptors that remain open are unaffected by +.Fn execve . +.Pp +Signals set to be ignored in the calling process are set to be ignored in +the +new process. Signals which are set to be caught in the calling process image +are set to default action in the new process image. +Blocked signals remain blocked regardless of changes to the signal action. +The signal stack is reset to be undefined (see +.Xr sigaction 2 +for more information). +.Pp +If the set-user-ID mode bit of the new process image file is set +(see +.Xr chmod 2 ) , +the effective user ID of the new process image is set to the owner ID +of the new process image file. +If the set-group-ID mode bit of the new process image file is set, +the effective group ID of the new process image is set to the group ID +of the new process image file. +(The effective group ID is the first element of the group list.) +The real user ID, real group ID and +other group IDs of the new process image remain the same as the calling +process image. +After any set-user-ID and set-group-ID processing, +the effective user ID is recorded as the saved set-user-ID, +and the effective group ID is recorded as the saved set-group-ID. +These values may be used in changing the effective IDs later (see +.Xr setuid 2 ) . +.Pp +The new process also inherits the following attributes from +the calling process: +.Pp +.Bl -column parent_process_ID -offset indent -compact +.It process ID Ta see Xr getpid 2 +.It parent process ID Ta see Xr getppid 2 +.It process group ID Ta see Xr getpgrp 2 +.It access groups Ta see Xr getgroups 2 +.It working directory Ta see Xr chdir 2 +.It root directory Ta see Xr chroot 2 +.It control terminal Ta see Xr termios 4 +.It resource usages Ta see Xr getrusage 2 +.It interval timers Ta see Xr getitimer 2 +.It resource limits Ta see Xr getrlimit 2 +.It file mode mask Ta see Xr umask 2 +.It signal mask Ta see Xr sigaction 2 , +.Xr sigsetmask 2 +.El +.Pp +When a program is executed as a result of an +.Fn execve +call, it is entered as follows: +.Bd -literal -offset indent +main(argc, argv, envp) +int argc; +char **argv, **envp; +.Ed +.Pp +where +.Fa argc +is the number of elements in +.Fa argv +(the ``arg count'') +and +.Fa argv +points to the array of character pointers +to the arguments themselves. +.Sh RETURN VALUES +As the +.Fn execve +function overlays the current process image +with a new process image the successful call +has no process to return to. +If +.Fn execve +does return to the calling process an error has occurred; the +return value will be -1 and the global variable +.Va errno +is set to indicate the error. +.Sh ERRORS +.Fn Execve +will fail and return to the calling process if: +.Bl -tag -width Er +.It Bq Er ENOTDIR +A component of the path prefix is not a directory. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded +.Dv {NAME_MAX} +characters, or an entire path name exceeded +.Dv {PATH_MAX} +characters. +.It Bq Er ENOENT +The new process file does not exist. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating the pathname. +.It Bq Er EACCES +Search permission is denied for a component of the path prefix. +.It Bq Er EACCES +The new process file is not an ordinary file. +.It Bq Er EACCES +The new process file mode denies execute permission. +.It Bq Er EACCES +The new process file is on a filesystem mounted with execution +disabled +.Pf ( Dv MNT_NOEXEC +in +.Ao Pa sys/mount.h Ac ) . +.It Bq Er ENOEXEC +The new process file has the appropriate access +permission, but has an invalid magic number in its header. +.It Bq Er ETXTBSY +The new process file is a pure procedure (shared text) +file that is currently open for writing or reading by some process. +.It Bq Er ENOMEM +The new process requires more virtual memory than +is allowed by the imposed maximum +.Pq Xr getrlimit 2 . +.It Bq Er E2BIG +The number of bytes in the new process's argument list +is larger than the system-imposed limit. +The limit in the system as released is 20480 bytes +.Pf ( Dv NCARGS +in +.Ao Pa sys/param.h Ac ) . +.It Bq Er EFAULT +The new process file is not as long as indicated by +the size values in its header. +.It Bq Er EFAULT +.Fa Path , +.Fa argv , +or +.Fa envp +point +to an illegal address. +.It Bq Er EIO +An I/O error occurred while reading from the file system. +.El +.Sh CAVEAT +If a program is +.Em setuid +to a non-super-user, but is executed when +the real +.Em uid +is ``root'', then the program has some of the powers +of a super-user as well. +.Sh SEE ALSO +.Xr exit 2 , +.Xr fork 2 , +.Xr execl 3 , +.Xr environ 7 +.Sh HISTORY +The +.Fn execve +function call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/fchdir.2 b/bsd/man/man2/fchdir.2 new file mode 100644 index 000000000..60b9685da --- /dev/null +++ b/bsd/man/man2/fchdir.2 @@ -0,0 +1 @@ +.so man2/chdir.2 diff --git a/bsd/man/man2/fchflags.2 b/bsd/man/man2/fchflags.2 new file mode 100644 index 000000000..d039e6fc0 --- /dev/null +++ b/bsd/man/man2/fchflags.2 @@ -0,0 +1 @@ +.so man2/chflags.2 diff --git a/bsd/man/man2/fchmod.2 b/bsd/man/man2/fchmod.2 new file mode 100644 index 000000000..92647d2e3 --- /dev/null +++ b/bsd/man/man2/fchmod.2 @@ -0,0 +1 @@ +.so man2/chmod.2 diff --git a/bsd/man/man2/fchown.2 b/bsd/man/man2/fchown.2 new file mode 100644 index 000000000..f0a5635ae --- /dev/null +++ b/bsd/man/man2/fchown.2 @@ -0,0 +1 @@ +.so man2/chown.2 diff --git a/bsd/man/man2/fcntl.2 b/bsd/man/man2/fcntl.2 new file mode 100644 index 000000000..1916e0fdc --- /dev/null +++ b/bsd/man/man2/fcntl.2 @@ -0,0 +1,637 @@ +.\" $NetBSD: fcntl.2,v 1.6 1995/02/27 12:32:29 cgd Exp $ +.\" +.\" Copyright (c) 1983, 1993 +.\" 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.2 8.2 (Berkeley) 1/12/94 +.\" +.Dd January 12, 1994 +.Dt FCNTL 2 +.Os BSD 4.2 +.Sh NAME +.Nm fcntl +.Nd file control +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn fcntl "int fd" "int cmd" "int arg" +.Sh DESCRIPTION +.Fn Fcntl +provides for control over descriptors. +The argument +.Fa fd +is a descriptor to be operated on by +.Fa cmd +as follows: +.Bl -tag -width F_WRITEBOOTSTRAPX +.It Dv F_DUPFD +Return a new descriptor as follows: +.Pp +.Bl -bullet -compact -offset 4n +.It +Lowest numbered available descriptor greater than or equal to +.Fa arg . +.It +Same object references as the original descriptor. +.It +New descriptor shares the same file offset if the object +was a file. +.It +Same access mode (read, write or read/write). +.It +Same file status flags (i.e., both file descriptors +share the same file status flags). +.It +The close-on-exec flag associated with the new file descriptor +is set to remain open across +.Xr execv 2 +system calls. +.El +.It Dv F_GETFD +Get the close-on-exec flag associated with the file descriptor +.Fa fd . +If the low-order bit of the returned value is 0, +the file will remain open across +.Fn exec , +otherwise the file will be closed upon execution of +.Fn exec +.Fa ( arg +is ignored). +.It Dv F_SETFD +Set the close-on-exec flag associated with +.Fa fd +to the low order bit of +.Fa arg +(0 or 1 as above). +.It Dv F_GETFL +Get descriptor status flags, as described below +.Fa ( arg +is ignored). +.It Dv F_SETFL +Set descriptor status flags to +.Fa arg . +.It Dv F_GETOWN +Get the process ID or process group +currently receiving +.Dv SIGIO +and +.Dv SIGURG +signals; process groups are returned +as negative values +.Fa ( arg +is ignored). +.It Dv F_SETOWN +Set the process or process group +to receive +.Dv SIGIO +and +.Dv SIGURG +signals; +process groups are specified by supplying +.Fa arg +as negative, otherwise +.Fa arg +is interpreted as a process ID. +.It Dv F_PREALLOCATE +Preallocate file storage space. +.It Dv F_SETSIZE +Truncate a file without zeroing space. +The calling process must have root privileges. +.It Dv F_RDADVISE +Issue an advisory read async with no copy to user. +.It Dv F_RDAHEAD +Turn read ahead off/on. +A zero value in +.Fa arg +disables read ahead. +A non-zero value in +.Fa arg +turns read ahead on. +.It Dv F_READBOOTSTRAP +Read bootstrap from disk. +.It Dv F_WRITEBOOTSTRAP +Write bootstrap on disk. +The calling process must have root privileges. +.It Dv F_NOCACHE +Turns data caching off/on. A non-zero value in +.Fa arg +turns data caching off. +A value of zero in +.Fa arg +turns data caching on. +.It Dv F_LOG2PHYS +Get disk device information. +Currently this only includes the +disk device address that corresponds +to the current file offset. +.El +.Pp +The flags for the +.Dv F_GETFL +and +.Dv F_SETFL +commands are as follows: +.Bl -tag -width O_NONBLOCKX -offset indent +.It Dv O_NONBLOCK +Non-blocking I/O; if no data is available to a +.Xr read +call, or if a +.Xr write +operation would block, +the read or write call returns -1 with the error +.Er EAGAIN . +.It Dv O_APPEND +Force each write to append at the end of file; +corresponds to the +.Dv O_APPEND +flag of +.Xr open 2 . +.It Dv O_ASYNC +Enable the +.Dv SIGIO +signal to be sent to the process group +when I/O is possible, e.g., +upon availability of data to be read. +.El +.Pp +Several commands are available for doing advisory file locking; +they all operate on the following structure: +.ne 7v +.Bd -literal + struct flock { + off_t l_start; /* starting offset */ + off_t l_len; /* len = 0 means until end of file */ + pid_t l_pid; /* lock owner */ + short l_type; /* lock type: read/write, etc. */ + short l_whence; /* type of l_start */ + }; +.Ed +.Pp +The commands available for advisory record locking are as follows: +.Bl -tag -width F_SETLKWX +.It Dv F_GETLK +Get the first lock that blocks the lock description pointed to by the +third argument, +.Fa arg , +taken as a pointer to a +.Fa "struct flock" +(see above). +The information retrieved overwrites the information passed to +.Nm fcntl +in the +.Fa flock +structure. +If no lock is found that would prevent this lock from being created, +the structure is left unchanged by this function call except for the +lock type which is set to +.Dv F_UNLCK . +.It Dv F_SETLK +Set or clear a file segment lock according to the lock description +pointed to by the third argument, +.Fa arg , +taken as a pointer to a +.Fa "struct flock" +(see above). +.Dv F_SETLK +is used to establish shared (or read) locks +.Dv (F_RDLCK) +or exclusive (or write) locks, +.Dv (F_WRLCK) , +as well as remove either type of lock +.Dv (F_UNLCK) . +If a shared or exclusive lock cannot be set, +.Nm fcntl +returns immediately with +.Er EACCES . +.It Dv F_SETLKW +This command is the same as +.Dv F_SETLK +except that if a shared or exclusive lock is blocked by other locks, +the process waits until the request can be satisfied. +If a signal that is to be caught is received while +.Nm fcntl +is waiting for a region, the +.Nm fcntl +will be interrupted if the signal handler has not specified the +.Dv SA_RESTART +(see +.Xr sigaction 2 ) . +.El +.Pp +When a shared lock has been set on a segment of a file, +other processes can set shared locks on that segment +or a portion of it. +A shared lock prevents any other process from setting an exclusive +lock on any portion of the protected area. +A request for a shared lock fails if the file descriptor was not +opened with read access. +.Pp +An exclusive lock prevents any other process from setting a shared lock or +an exclusive lock on any portion of the protected area. +A request for an exclusive lock fails if the file was not +opened with write access. +.Pp +The value of +.Fa l_whence +is +.Dv SEEK_SET , +.Dv SEEK_CUR , +or +.Dv SEEK_END +to indicate that the relative offset, +.Fa l_start +bytes, will be measured from the start of the file, +current position, or end of the file, respectively. +The value of +.Fa l_len +is the number of consecutive bytes to be locked. +If +.Fa l_len +is negative, the result is undefined. +The +.Fa l_pid +field is only used with +.Dv F_GETLK +to return the process ID of the process holding a blocking lock. +After a successful +.Dv F_GETLK +request, the value of +.Fa l_whence +is +.Dv SEEK_SET . +.Pp +Locks may start and extend beyond the current end of a file, +but may not start or extend before the beginning of the file. +A lock is set to extend to the largest possible value of the +file offset for that file if +.Fa l_len +is set to zero. If +.Fa l_whence +and +.Fa l_start +point to the beginning of the file, and +.Fa l_len +is zero, the entire file is locked. +If an application wishes only to do entire file locking, the +.Xr flock 2 +system call is much more efficient. +.Pp +There is at most one type of lock set for each byte in the file. +Before a successful return from an +.Dv F_SETLK +or an +.Dv F_SETLKW +request when the calling process has previously existing locks +on bytes in the region specified by the request, +the previous lock type for each byte in the specified +region is replaced by the new lock type. +As specified above under the descriptions +of shared locks and exclusive locks, an +.Dv F_SETLK +or an +.Dv F_SETLKW +request fails or blocks respectively when another process has existing +locks on bytes in the specified region and the type of any of those +locks conflicts with the type specified in the request. +.Pp +This interface follows the completely stupid semantics of System V and +.St -p1003.1-88 +that require that all locks associated with a file for a given process are +removed when \fIany\fP file descriptor for that file is closed by that process. +This semantic means that applications must be aware of any files that +a subroutine library may access. +For example if an application for updating the password file locks the +password file database while making the update, and then calls +.Xr getpwname 3 +to retrieve a record, +the lock will be lost because +.Xr getpwname 3 +opens, reads, and closes the password database. +The database close will release all locks that the process has +associated with the database, even if the library routine never +requested a lock on the database. +Another minor semantic problem with this interface is that +locks are not inherited by a child process created using the +.Xr fork 2 +function. +The +.Xr flock 2 +interface has much more rational last close semantics and +allows locks to be inherited by child processes. +.Xr Flock 2 +is recommended for applications that want to ensure the integrity +of their locks when using library routines or wish to pass locks +to their children. +Note that +.Xr flock 2 +and +.Xr fcntl 2 +locks may be safely used concurrently. +.Pp +All locks associated with a file for a given process are +removed when the process terminates. +.Pp +A potential for deadlock occurs if a process controlling a locked region +is put to sleep by attempting to lock the locked region of another process. +This implementation detects that sleeping until a locked region is unlocked +would cause a deadlock and fails with an +.Er EDEADLK +error. +.Pp +The +.Dv F_PREALLOCATE +command operates on the following structure: +.ne 7v +.Bd -literal + typedef struct fstore { + u_int32_t fst_flags; /* IN: flags word */ + int fst_posmode; /* IN: indicates offset field */ + off_t fst_offset; /* IN: start of the region */ + off_t fst_length; /* IN: size of the region */ + off_t fst_bytesalloc; /* OUT: number of bytes allocated */ + } fstore_t; +.Ed +.Pp +The flags (fst_flags) for the +.Dv F_PREALLOCATE +command are as follows: +.Bl -tag -width F_ALLOCATECONTIGX -offset indent +.It Dv F_ALLOCATECONTIG +Allocate contiguous space. +.It Dv F_ALLOCATEALL +Allocate all requested space or no space at all. +.El +.Pp +The position modes (fst_posmode) for the +.Dv F_PREALLOCATE +command indicate how to use the offset field. +The modes are as follows: +.Bl -tag -width F_PEOFPOSMODEX -offset indent +.It Dv F_PEOFPOSMODE +Allocate from the physical end of file. +.It Dv F_VOLPOSMODE +Allocate from the volume offset. +.El +.Pp +The +.Dv F_RDADVISE +command operates on the following structure +which holds information passed from the +user to the system: +.ne 7v +.Bd -literal + struct radvisory { + off_t ra_offset; /* offset into the file */ + int ra_count; /* size of the read */ + }; +.Ed +.Pp +The +.Dv F_READBOOTSTRAP and F_WRITEBOOTSTRAP +commands operate on the following structure. +.ne 7v +.Bd -literal + typedef struct fbootstraptransfer { + off_t fbt_offset; /* IN: offset to start read/write */ + size_t fbt_length; /* IN: number of bytes to transfer */ + void *fbt_buffer; /* IN: buffer to be read/written */ + } fbootstraptransfer_t; +.Ed +.Pp +The +.Dv F_LOG2PHYS +command operates on the following structure. +.ne 7v +.Bd -literal + struct log2phys { + u_int32_t l2p_flags; /* unused so far */ + off_t l2p_contigbytes; /* unused so far */ + off_t l2p_devoffset; /* bytes into device */ + }; +.Ed +.Sh RETURN VALUES +Upon successful completion, the value returned depends on +.Fa cmd +as follows: +.Bl -tag -width F_GETOWNX -offset indent +.It Dv F_DUPFD +A new file descriptor. +.It Dv F_GETFD +Value of flag (only the low-order bit is defined). +.It Dv F_GETFL +Value of flags. +.It Dv F_GETOWN +Value of file descriptor owner. +.It other +Value other than -1. +.El +.Pp +Otherwise, a value of -1 is returned and +.Va errno +is set to indicate the error. +.Sh ERRORS +.Fn Fcntl +will fail if: +.Bl -tag -width Er +.It Bq Er EACCES +The argument +.Fa cmd +is +.Dv F_SETLK , +the type of lock +.Fa (l_type) +is a shared lock +.Dv (F_RDLCK) +or exclusive lock +.Dv (F_WRLCK) , +and the segment of a file to be locked is already +exclusive-locked by another process; +or the type is an exclusive lock and some portion of the +segment of a file to be locked is already shared-locked or +exclusive-locked by another process. +.Pp +The argument +.Fa cmd +is either +.Dv F_SETSIZE +or +.Dv F_WRITEBOOTSTRAP +and the calling process does not have root privileges. +.It Bq Er EBADF +.Fa Fildes +is not a valid open file descriptor. +.Pp +The argument +.Fa cmd +is +.Dv F_SETLK +or +.Dv F_SETLKW , +the type of lock +.Fa (l_type) +is a shared lock +.Dv (F_RDLCK) , +and +.Fa fildes +is not a valid file descriptor open for reading. +.Pp +The argument +.Fa cmd +is +.Dv F_SETLK +or +.Dv F_SETLKW , +the type of lock +.Fa (l_type) +is an exclusive lock +.Dv (F_WRLCK) , +and +.Fa fildes +is not a valid file descriptor open for writing. +.Pp +The argument +.Fa cmd +is +.Dv F_PREALLOCATE +and the calling process does not have +file write permission. +.Pp +The argument +.Fa cmd +is +.Dv F_LOG2PHYS +and +.Fa fildes +is not a valid file descriptor open for reading. +.It Bq Er EMFILE +.Fa Cmd +is +.Dv F_DUPFD +and the maximum allowed number of file descriptors are currently +open. +.It Bq Er EDEADLK +The argument +.Fa cmd +is +.Dv F_SETLKW , +and a deadlock condition was detected. +.It Bq Er EINTR +The argument +.Fa cmd +is +.Dv F_SETLKW , +and the function was interrupted by a signal. +.It Bq Er EINVAL +.Fa Cmd +is +.Dv F_DUPFD +and +.Fa arg +is negative or greater than the maximum allowable number +(see +.Xr getdtablesize 2 ) . +.Pp +The argument +.Fa cmd +is +.Dv F_GETLK , +.Dv F_SETLK , +or +.Dv F_SETLKW +and the data to which +.Fa arg +points is not valid, or +.Fa fildes +refers to a file that does not support locking. +.Pp +The argument +.Fa cmd +is +.Dv F_PREALLOCATE +and the +.Fa fst_posmode +is not a valid mode, +or when +.Dv F_PEOFPOSMODE +is set and +.Fa fst_offset +is a non-zero value, +or when +.Dv F_VOLPOSMODE +is set and +.Fa fst_offset +is a negative or zero value. +.Pp +The argument +.Fa cmd +is either +.Dv F_READBOOTSTRAP +or +.Dv F_WRITEBOOTSTRAP +and the operation was attempted on a non-HFS disk type. +.It Bq Er EMFILE +The argument +.Fa cmd +is +.Dv F_DUPED +and the maximum number of file descriptors permitted for the +process are already in use, +or no file descriptors greater than or equal to +.Fa arg +are available. +.It Bq Er ENOLCK +The argument +.Fa cmd +is +.Dv F_SETLK +or +.Dv F_SETLKW , +and satisfying the lock or unlock request would result in the +number of locked regions in the system exceeding a system-imposed limit. +.It Bq Er ESRCH +.Fa Cmd +is +.Dv F_SETOWN +and +the process ID given as argument is not in use. +.El +.Sh SEE ALSO +.Xr close 2 , +.Xr execve 2 , +.Xr flock 2 , +.Xr getdtablesize 2 , +.Xr open 2 , +.Xr sigaction 3 +.Sh HISTORY +The +.Fn fcntl +function call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/flock.2 b/bsd/man/man2/flock.2 new file mode 100644 index 000000000..e38879e58 --- /dev/null +++ b/bsd/man/man2/flock.2 @@ -0,0 +1,149 @@ +.\" $NetBSD: flock.2,v 1.5 1995/02/27 12:32:32 cgd Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)flock.2 8.2 (Berkeley) 12/11/93 +.\" +.Dd December 11, 1993 +.Dt FLOCK 2 +.Os BSD 4.2 +.Sh NAME +.Nm flock +.Nd "apply or remove an advisory lock on an open file" +.Sh SYNOPSIS +.Fd #include +.Fd #define LOCK_SH 1 /* shared lock */ +.Fd #define LOCK_EX 2 /* exclusive lock */ +.Fd #define LOCK_NB 4 /* don't block when locking */ +.Fd #define LOCK_UN 8 /* unlock */ +.Ft int +.Fn flock "int fd" "int operation" +.Sh DESCRIPTION +.Fn Flock +applies or removes an +.Em advisory +lock on the file associated with the file descriptor +.Fa fd . +A lock is applied by specifying an +.Fa operation +parameter that is one of +.Dv LOCK_SH +or +.Dv LOCK_EX +with the optional addition of +.Dv LOCK_NB . +To unlock +an existing lock +.Dv operation +should be +.Dv LOCK_UN . +.Pp +Advisory locks allow cooperating processes to perform +consistent operations on files, but do not guarantee +consistency (i.e., processes may still access files +without using advisory locks possibly resulting in +inconsistencies). +.Pp +The locking mechanism allows two types of locks: +.Em shared +locks and +.Em exclusive +locks. +At any time multiple shared locks may be applied to a file, +but at no time are multiple exclusive, or both shared and exclusive, +locks allowed simultaneously on a file. +.Pp +A shared lock may be +.Em upgraded +to an exclusive lock, and vice versa, simply by specifying +the appropriate lock type; this results in the previous +lock being released and the new lock applied (possibly +after other processes have gained and released the lock). +.Pp +Requesting a lock on an object that is already locked +normally causes the caller to be blocked until the lock may be +acquired. If +.Dv LOCK_NB +is included in +.Fa operation , +then this will not happen; instead the call will fail and +the error +.Er EWOULDBLOCK +will be returned. +.Sh NOTES +Locks are on files, not file descriptors. That is, file descriptors +duplicated through +.Xr dup 2 +or +.Xr fork 2 +do not result in multiple instances of a lock, but rather multiple +references to a single lock. If a process holding a lock on a file +forks and the child explicitly unlocks the file, the parent will +lose its lock. +.Pp +Processes blocked awaiting a lock may be awakened by signals. +.Sh RETURN VALUES +Zero is returned if the operation was successful; +on an error a -1 is returned and an error code is left in +the global location +.Va errno . +.Sh ERRORS +The +.Fn flock +call fails if: +.Bl -tag -width Er +.It Bq Er EWOULDBLOCK +The file is locked and the +.Dv LOCK_NB +option was specified. +.It Bq Er EBADF +The argument +.Fa fd +is an invalid descriptor. +.It Bq Er EINVAL +The argument +.Fa fd +refers to an object other than a file. +.It Bq Er EOPNOTSUPP +The referenced descriptor is not of the correct type. +.El +.Sh SEE ALSO +.Xr open 2 , +.Xr close 2 , +.Xr dup 2 , +.Xr execve 2 , +.Xr fork 2 +.Sh HISTORY +The +.Fn flock +function call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/fork.2 b/bsd/man/man2/fork.2 new file mode 100644 index 000000000..e9a810626 --- /dev/null +++ b/bsd/man/man2/fork.2 @@ -0,0 +1,111 @@ +.\" $NetBSD: fork.2,v 1.6 1995/02/27 12:32:36 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.\" @(#)fork.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt FORK 2 +.Os BSD 4 +.Sh NAME +.Nm fork +.Nd create a new process +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft pid_t +.Fn fork void +.Sh DESCRIPTION +.Fn Fork +causes creation of a new process. +The new process (child process) is an exact copy of the +calling process (parent process) except for the following: +.Bl -bullet -offset indent +.It +The child process has a unique process ID. +.It +The child process has a different parent +process ID (i.e., the process ID of the parent process). +.It +The child process has its own copy of the parent's descriptors. +These descriptors reference the same underlying objects, so that, +for instance, file pointers in file objects are shared between +the child and the parent, so that an +.Xr lseek 2 +on a descriptor in the child process can affect a subsequent +.Xr read +or +.Xr write +by the parent. +This descriptor copying is also used by the shell to +establish standard input and output for newly created processes +as well as to set up pipes. +.It +The child processes resource utilizations +are set to 0; see +.Xr setrlimit 2 . +.El +.Sh RETURN VALUES +Upon successful completion, +.Fn fork +returns a value +of 0 to the child process and returns the process ID of the child +process to the parent process. Otherwise, a value of -1 is returned +to the parent process, no child process is created, and the global +variable +.Va errno +is set to indicate the error. +.Sh ERRORS +.Fn Fork +will fail and no child process will be created if: +.Bl -tag -width Er +.It Bq Er EAGAIN +The system-imposed limit on the total +number of processes under execution would be exceeded. +This limit is configuration-dependent. +.It Bq Er EAGAIN +The system-imposed limit +.Dv MAXUPRC +.Pq Aq Pa sys/param.h +on the total number of +processes under execution by a single user would be exceeded. +.It Bq Er ENOMEM +There is insufficient swap space for the new process. +.El +.Sh SEE ALSO +.Xr execve 2 , +.Xr wait 2 +.Sh HISTORY +A +.Fn fork 2 +function call appeared in +.At v6 . diff --git a/bsd/man/man2/fpathconf.2 b/bsd/man/man2/fpathconf.2 new file mode 100644 index 000000000..c44760dfc --- /dev/null +++ b/bsd/man/man2/fpathconf.2 @@ -0,0 +1 @@ +.so man2/pathconf.2 diff --git a/bsd/man/man2/fstat.2 b/bsd/man/man2/fstat.2 new file mode 100644 index 000000000..b1a86c195 --- /dev/null +++ b/bsd/man/man2/fstat.2 @@ -0,0 +1 @@ +.so man2/stat.2 diff --git a/bsd/man/man2/fstatfs.2 b/bsd/man/man2/fstatfs.2 new file mode 100644 index 000000000..923d3c0cc --- /dev/null +++ b/bsd/man/man2/fstatfs.2 @@ -0,0 +1 @@ +.so man2/statfs.2 diff --git a/bsd/man/man2/fsync.2 b/bsd/man/man2/fsync.2 new file mode 100644 index 000000000..3f4b0d694 --- /dev/null +++ b/bsd/man/man2/fsync.2 @@ -0,0 +1,83 @@ +.\" $NetBSD: fsync.2,v 1.4 1995/02/27 12:32:38 cgd Exp $ +.\" +.\" Copyright (c) 1983, 1993 +.\" 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. +.\" +.\" @(#)fsync.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt FSYNC 2 +.Os BSD 4.2 +.Sh NAME +.Nm fsync +.Nd "synchronize a file's in-core state with that on disk" +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn fsync "int fd" +.Sh DESCRIPTION +.Fn Fsync +causes all modified data and attributes of +.Fa fd +to be moved to a permanent storage device. +This normally results in all in-core modified copies +of buffers for the associated file to be written to a disk. +.Pp +.Fn Fsync +should be used by programs that require a file to be +in a known state, for example, in building a simple transaction +facility. +.Sh RETURN VALUES +A 0 value is returned on success. A -1 value indicates +an error. +.Sh ERRORS +The +.Fn fsync +fails if: +.Bl -tag -width Er +.It Bq Er EBADF +.Fa Fd +is not a valid descriptor. +.It Bq Er EINVAL +.Fa Fd +refers to a socket, not to a file. +.It Bq Er EIO +An I/O error occurred while reading from or writing to the file system. +.El +.Sh SEE ALSO +.Xr sync 2 , +.Xr sync 8 , +.Xr update 8 +.Sh HISTORY +The +.Fn fsync +function call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/ftruncate.2 b/bsd/man/man2/ftruncate.2 new file mode 100644 index 000000000..2ed34f1ed --- /dev/null +++ b/bsd/man/man2/ftruncate.2 @@ -0,0 +1 @@ +.so man2/truncate.2 diff --git a/bsd/man/man2/futimes.2 b/bsd/man/man2/futimes.2 new file mode 100644 index 000000000..e7f93e1f0 --- /dev/null +++ b/bsd/man/man2/futimes.2 @@ -0,0 +1 @@ +.so man2/utimes.2 diff --git a/bsd/man/man2/getdirentries.2 b/bsd/man/man2/getdirentries.2 new file mode 100644 index 000000000..e6cc24a50 --- /dev/null +++ b/bsd/man/man2/getdirentries.2 @@ -0,0 +1,154 @@ +.\" $NetBSD: getdirentries.2,v 1.7 1995/10/12 15:40:50 jtc Exp $ +.\" +.\" Copyright (c) 1989, 1991, 1993 +.\" 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. +.\" +.\" @(#)getdirentries.2 8.1 (Berkeley) 6/9/93 +.\" +.Dd June 9, 1993 +.Dt GETDIRENTRIES 2 +.Os +.Sh NAME +.Nm getdirentries +.Nd "get directory entries in a filesystem independent format" +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn getdirentries "int fd" "char *buf" "int nbytes" "long *basep" +.Sh DESCRIPTION +.Fn Getdirentries +reads directory entries from the directory +referenced by the file descriptor +.Fa fd +into the buffer pointed to by +.Fa buf , +in a filesystem independent format. +Up to +.Fa nbytes +of data will be transferred. +.Fa Nbytes +must be greater than or equal to the +block size associated with the file, +see +.Xr stat 2 . +Some filesystems may not support +.Fn getdirentries +with buffers smaller than this size. +.Pp +The data in the buffer is a series of +.Em dirent +structures each containing the following entries: +.Bd -literal -offset indent +unsigned long d_fileno; +unsigned short d_reclen; +unsigned short d_namlen; +char d_name[MAXNAMELEN + 1]; /* see below */ +.Ed +.Pp +The +.Fa d_fileno +entry is a number which is unique for each +distinct file in the filesystem. +Files that are linked by hard links (see +.Xr link 2 ) +have the same +.Fa d_fileno . +The +.Fa d_reclen +entry is the length, in bytes, of the directory record. +The +.Fa d_name +entry contains a null terminated file name. +The +.Fa d_namlen +entry specifies the length of the file name excluding the null byte. +Thus the actual size of +.Fa d_name +may vary from 1 to +.Dv MAXNAMELEN +\&+ 1. +.Pp +Entries may be separated by extra space. +The +.Fa d_reclen +entry may be used as an offset from the start of a +.Fa dirent +structure to the next structure, if any. +.Pp +The actual number of bytes transferred is returned. +The current position pointer associated with +.Fa fd +is set to point to the next block of entries. +The pointer may not advance by the number of bytes returned by +.Fn getdirentries . +A value of zero is returned when +the end of the directory has been reached. +.Pp +.Fn Getdirentries +writes the position of the block read into the location pointed to by +.Fa basep . +Alternatively, the current position pointer may be set and retrieved by +.Xr lseek 2 . +The current position pointer should only be set to a value returned by +.Xr lseek 2 , +a value returned in the location pointed to by +.Fa basep , +or zero. +.Sh RETURN VALUES +If successful, the number of bytes actually transferred is returned. +Otherwise, -1 is returned and the global variable +.Va errno +is set to indicate the error. +.Sh ERRORS +.Fn Getdirentries +will fail if: +.Bl -tag -width Er +.It Bq Er EBADF +.Fa fd +is not a valid file descriptor open for reading. +.It Bq Er EFAULT +Either +.Fa buf +or +.Fa basep +point outside the allocated address space. +.It Bq Er EIO +An +.Tn I/O +error occurred while reading from or writing to the file system. +.El +.Sh SEE ALSO +.Xr open 2 , +.Xr lseek 2 +.Sh HISTORY +The +.Fn getdirentries +function first appeared in 4.4BSD. diff --git a/bsd/man/man2/getegid.2 b/bsd/man/man2/getegid.2 new file mode 100644 index 000000000..d9b10e73f --- /dev/null +++ b/bsd/man/man2/getegid.2 @@ -0,0 +1 @@ +.so man2/getgid.2 diff --git a/bsd/man/man2/geteuid.2 b/bsd/man/man2/geteuid.2 new file mode 100644 index 000000000..165cfe1d0 --- /dev/null +++ b/bsd/man/man2/geteuid.2 @@ -0,0 +1 @@ +.so man2/getuid.2 diff --git a/bsd/man/man2/getfh.2 b/bsd/man/man2/getfh.2 new file mode 100644 index 000000000..ff12795ad --- /dev/null +++ b/bsd/man/man2/getfh.2 @@ -0,0 +1,98 @@ +.\" $NetBSD: getfh.2,v 1.7 1995/10/12 15:40:53 jtc Exp $ +.\" +.\" Copyright (c) 1989, 1991, 1993 +.\" 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. +.\" +.\" @(#)getfh.2 8.1 (Berkeley) 6/9/93 +.\" +.Dd June 9, 1993 +.Dt GETFH 2 +.Os +.Sh NAME +.Nm getfh +.Nd get file handle +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn getfh "const char *path" "fhandle_t *fhp" +.Sh DESCRIPTION +.Fn Getfh +returns a file handle for the specified file or directory +in the file handle pointed to by +.Fa fhp . +This system call is restricted to the superuser. +.Sh RETURN VALUES +Upon successful completion, a value of 0 is returned. +Otherwise, -1 is returned and the global variable +.Va errno +is set to indicate the error. +.Sh ERRORS +.Fn Getfh +fails if one or more of the following are true: +.Bl -tag -width Er +.It Bq ENOTDIR +A component of the path prefix of +.Fa path +is not a directory. +.It Bq ENAMETOOLONG +The length of a component of +.Fa path +exceeds +.Dv {NAME_MAX} +characters, or the length of +.Fa path +exceeds +.Dv {PATH_MAX} +characters. +.It Bq ENOENT +The file referred to by +.Fa path +does not exist. +.It Bq EACCES +Search permission is denied for a component of the path prefix of +.Fa path . +.It Bq ELOOP +Too many symbolic links were encountered in translating +.Fa path . +.It Bq EFAULT +.Fa Fhp +points to an invalid address. +.It Bq EIO +An +.Tn I/O +error occurred while reading from or writing to the file system. +.El +.Sh HISTORY +The +.Fn getfh +function +first appeared in 4.4BSD. diff --git a/bsd/man/man2/getfsstat.2 b/bsd/man/man2/getfsstat.2 new file mode 100644 index 000000000..c924dd62c --- /dev/null +++ b/bsd/man/man2/getfsstat.2 @@ -0,0 +1,134 @@ +.\" $NetBSD: getfsstat.2,v 1.6 1995/06/29 11:40:44 cgd Exp $ +.\" +.\" Copyright (c) 1989, 1991, 1993 +.\" 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. +.\" +.\" @(#)getfsstat.2 8.1 (Berkeley) 6/9/93 +.\" +.Dd June 9, 1993 +.Dt GETFSSTAT 2 +.Os +.Sh NAME +.Nm getfsstat +.Nd get list of all mounted file systems +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Fd #include +.Ft int +.Fn getfsstat "struct statfs *buf" "long bufsize" "int flags" +.Sh DESCRIPTION +.Fn Getfsstat +returns information about all mounted file systems. +.Fa Buf +is a pointer to an array of +.Xr statfs +structures defined as follows: +.Bd -literal +typedef struct { int32_t val[2]; } fsid_t; + +#define MFSNAMELEN 16 /* length of fs type name, including nul */ +#define MNAMELEN 32 /* length of buffer for returned name */ + +struct statfs { + short f_type; /* type of file system (unused; zero) */ + short f_flags; /* copy of mount flags */ + long f_bsize; /* fundamental file system block size */ + long f_iosize; /* optimal transfer block size */ + long f_blocks; /* total data blocks in file system */ + long f_bfree; /* free blocks in fs */ + long f_bavail; /* free blocks avail to non-superuser */ + long f_files; /* total file nodes in file system */ + long f_ffree; /* free file nodes in fs */ + fsid_t f_fsid; /* file system id */ + uid_t f_owner; /* user that mounted the file system */ + long f_spare[4]; /* spare for later */ + char f_fstypename[MFSNAMELEN]; /* fs type name */ + char f_mntonname[MNAMELEN]; /* directory on which mounted */ + char f_mntfromname[MNAMELEN]; /* mounted file system */ +}; +.Ed +.Pp +Fields that are undefined for a particular file system are set to -1. +The buffer is filled with an array of +.Fa statfs +structures, one for each mounted file system +up to the size specified by +.Fa bufsize . +.Pp +If +.Fa buf +is given as NULL, +.Fn getfsstat +returns just the number of mounted file systems. +.Pp +Normally +.Fa flags +should be specified as +.Dv MNT_WAIT . +If +.Fa flags +is set to +.Dv MNT_NOWAIT , +.Fn getfsstat +will return the information it has available without requesting +an update from each file system. +Thus, some of the information will be out of date, but +.Fn getfsstat +will not block waiting for information from a file system that is +unable to respond. +.Sh RETURN VALUES +Upon successful completion, the number of +.Fa statfs +structures is returned. +Otherwise, -1 is returned and the global variable +.Va errno +is set to indicate the error. +.Sh ERRORS +.Fn Getfsstat +fails if one or more of the following are true: +.Bl -tag -width Er +.It Bq Er EFAULT +.Fa Buf +points to an invalid address. +.It Bq Er EIO +An +.Tn I/O +error occurred while reading from or writing to the file system. +.El +.Sh SEE ALSO +.Xr statfs 2 , +.Xr fstab 5 , +.Xr mount 8 +.Sh HISTORY +The +.Fn getfsstat +function first appeared in 4.4BSD. diff --git a/bsd/man/man2/getgid.2 b/bsd/man/man2/getgid.2 new file mode 100644 index 000000000..ee395cd65 --- /dev/null +++ b/bsd/man/man2/getgid.2 @@ -0,0 +1,82 @@ +.\" $NetBSD: getgid.2,v 1.5 1995/02/27 12:32:53 cgd Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)getgid.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt GETGID 2 +.Os BSD 4.2 +.Sh NAME +.Nm getgid , +.Nm getegid +.Nd get group process identification +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft gid_t +.Fn getgid void +.Ft gid_t +.Fn getegid void +.Sh DESCRIPTION +The +.Fn getgid +function returns the real group ID of the calling process, +.Fn getegid +returns the effective group ID of the calling process. +.Pp +The real group ID is specified at login time. +.Pp +The real group ID is the group of the user who invoked the program. +As the effective group ID gives the process additional permissions +during the execution of +.Dq Em set-group-ID +mode processes, +.Fn getgid +is used to determine the real-user-id of the calling process. +.Sh ERRORS +The +.Fn getgid +and +.Fn getegid +functions are always successful, and no return value is reserved to +indicate an error. +.Sh SEE ALSO +.Xr getuid 2 , +.Xr setregid 2 , +.Xr setgid 3 +.Sh STANDARDS +.Fn Getgid +and +.Fn getegid +conform to +.St -p1003.1-88 . diff --git a/bsd/man/man2/getgroups.2 b/bsd/man/man2/getgroups.2 new file mode 100644 index 000000000..ecc9c82ee --- /dev/null +++ b/bsd/man/man2/getgroups.2 @@ -0,0 +1,98 @@ +.\" $NetBSD: getgroups.2,v 1.8 1995/02/27 12:32:57 cgd Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)getgroups.2 8.2 (Berkeley) 4/16/94 +.\" +.Dd April 16, 1994 +.Dt GETGROUPS 2 +.Os BSD 4.2 +.Sh NAME +.Nm getgroups +.Nd get group access list +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Fd #include +.Ft int +.Fn getgroups "int gidsetlen" "gid_t *gidset" +.Sh DESCRIPTION +.Fn Getgroups +gets the current group access list of the current user process +and stores it in the array +.Fa gidset . +The parameter +.Fa gidsetlen +indicates the number of entries that may be placed in +.Fa gidset . +.Fn Getgroups +returns the actual number of groups returned in +.Fa gidset . +No more than +.Dv {NGROUPS_MAX} +will ever +be returned. +If +.Fa gidsetlen +is 0, +.Fn getgroups +returns the number of groups without modifying the +.Fa gidset +array. +.Sh RETURN VALUES +A successful call returns the number of groups in the group set. +A value of -1 indicates that an error occurred, and the error +code is stored in the global variable +.Va errno . +.Sh ERRORS +The possible errors for +.Fn getgroups +are: +.Bl -tag -width Er +.It Bq Er EINVAL +The argument +.Fa gidsetlen +is smaller than the number of groups in the group set. +.It Bq Er EFAULT +The argument +.Fa gidset +specifies +an invalid address. +.El +.Sh SEE ALSO +.Xr setgroups 2 , +.Xr initgroups 3 +.Sh HISTORY +The +.Fn getgroups +function call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/getitimer.2 b/bsd/man/man2/getitimer.2 new file mode 100644 index 000000000..2f22c203f --- /dev/null +++ b/bsd/man/man2/getitimer.2 @@ -0,0 +1,168 @@ +.\" $NetBSD: getitimer.2,v 1.6 1995/10/12 15:40:54 jtc Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)getitimer.2 8.2 (Berkeley) 12/11/93 +.\" +.Dd December 11, 1993 +.Dt GETITIMER 2 +.Os BSD 4.2 +.Sh NAME +.Nm getitimer , +.Nm setitimer +.Nd get/set value of interval timer +.Sh SYNOPSIS +.Fd #include +.Fd #define ITIMER_REAL 0 +.Fd #define ITIMER_VIRTUAL 1 +.Fd #define ITIMER_PROF 2 +.Ft int +.Fn getitimer "int which" "struct itimerval *value" +.Ft int +.Fn setitimer "int which" "const struct itimerval *value" "struct itimerval *ovalue" +.Sh DESCRIPTION +The system provides each process with three interval timers, +defined in +.Ao Pa sys/time.h Ac . +The +.Fn getitimer +call returns the current value for the timer specified in +.Fa which +in the structure at +.Fa value . +The +.Fn setitimer +call sets a timer to the specified +.Fa value +(returning the previous value of the timer if +.Fa ovalue +is non-nil). +.Pp +A timer value is defined by the +.Fa itimerval +structure: +.Bd -literal -offset indent +struct itimerval { + struct timeval it_interval; /* timer interval */ + struct timeval it_value; /* current value */ +}; +.Ed +.Pp +If +.Fa it_value +is non-zero, it indicates the time to the next timer expiration. +If +.Fa it_interval +is non-zero, it specifies a value to be used in reloading +.Fa it_value +when the timer expires. +Setting +.Fa it_value +to 0 disables a timer. Setting +.Fa it_interval +to 0 causes a timer to be disabled after its next expiration (assuming +.Fa it_value +is non-zero). +.Pp +Time values smaller than the resolution of the +system clock are rounded up to this resolution +(typically 10 milliseconds). +.Pp +The +.Dv ITIMER_REAL +timer decrements in real time. A +.Dv SIGALRM +signal is +delivered when this timer expires. +.Pp +The +.Dv ITIMER_VIRTUAL +timer decrements in process virtual time. +It runs only when the process is executing. A +.Dv SIGVTALRM +signal +is delivered when it expires. +.Pp +The +.Dv ITIMER_PROF +timer decrements both in process virtual time and +when the system is running on behalf of the process. It is designed +to be used by interpreters in statistically profiling the execution +of interpreted programs. +Each time the +.Dv ITIMER_PROF +timer expires, the +.Dv SIGPROF +signal is +delivered. Because this signal may interrupt in-progress +system calls, programs using this timer must be prepared to +restart interrupted system calls. +.Sh NOTES +Three macros for manipulating time values are defined in +.Ao Pa sys/time.h Ac . +.Fa Timerclear +sets a time value to zero, +.Fa timerisset +tests if a time value is non-zero, and +.Fa timercmp +compares two time values (beware that >= and <= do not +work with this macro). +.Sh RETURN VALUES +If the calls succeed, a value of 0 is returned. If an error occurs, +the value -1 is returned, and a more precise error code is placed +in the global variable +.Va errno . +.Sh ERRORS +.Fn Getitimer +and +.Fn setitimer +will fail if: +.Bl -tag -width Er +.It Bq Er EFAULT +The +.Fa value +parameter specified a bad address. +.It Bq Er EINVAL +A +.Fa value +parameter specified a time that was too large +to be handled. +.El +.Sh SEE ALSO +.Xr select 2 , +.Xr sigaction 2 , +.Xr gettimeofday 2 +.Sh HISTORY +The +.Fn getitimer +function call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/getlogin.2 b/bsd/man/man2/getlogin.2 new file mode 100644 index 000000000..33f127fad --- /dev/null +++ b/bsd/man/man2/getlogin.2 @@ -0,0 +1,128 @@ +.\" $NetBSD: getlogin.2,v 1.4 1995/02/27 12:33:03 cgd Exp $ +.\" +.\" Copyright (c) 1989, 1991, 1993 +.\" 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. +.\" +.\" @(#)getlogin.2 8.1 (Berkeley) 6/9/93 +.\" +.Dd June 9, 1993 +.Dt GETLOGIN 2 +.Os BSD 4.2 +.Sh NAME +.Nm getlogin , +.Nm setlogin +.Nd get/set login name +.Sh SYNOPSIS +.Fd #include +.Ft char * +.Fn getlogin void +.Ft int +.Fn setlogin "const char *name" +.Sh DESCRIPTION +The +.Fn getlogin +routine +returns the login name of the user associated with the current session, +as previously set by +.Fn setlogin . +The name is normally associated with a login shell +at the time a session is created, +and is inherited by all processes descended from the login shell. +(This is true even if some of those processes assume another user ID, +for example when +.Xr su 1 +is used.) +.Pp +.Fn Setlogin +sets the login name of the user associated with the current session to +.Fa name . +This call is restricted to the super-user, and +is normally used only when a new session is being created on behalf +of the named user +(for example, at login time, or when a remote shell is invoked). +.Sh RETURN VALUES +If a call to +.Fn getlogin +succeeds, it returns a pointer to a null-terminated string in a static buffer. +If the name has not been set, it returns +.Dv NULL . +If a call to +.Fn setlogin +succeeds, a value of 0 is returned. If +.Fn setlogin +fails, a value of -1 is returned and an error code is +placed in the global location +.Va errno . +.Sh ERRORS +The following errors may be returned by these calls: +.Bl -tag -width Er +.It Bq Er EFAULT +The +.Fa name +parameter gave an +invalid address. +.It Bq Er EINVAL +The +.Fa name +parameter +pointed to a string that was too long. +Login names are limited to +.Dv MAXLOGNAME +(from +.Ao Pa sys/param.h Ac ) +characters, currently 12. +.It Bq Er EPERM +The caller tried to set the login name and was not the super-user. +.El +.Sh SEE ALSO +.Xr setsid 2 +.Sh BUGS +Login names are limited in length by +.Fn setlogin . +However, lower limits are placed on login names elsewhere in the system +.Pf ( Dv UT_NAMESIZE +in +.Ao Pa utmp.h Ac ) . +.Pp +In earlier versions of the system, +.Fn getlogin +failed unless the process was associated with a login terminal. +The current implementation (using +.Fn setlogin ) +allows getlogin to succeed even when the process has no controlling terminal. +In earlier versions of the system, the value returned by +.Fn getlogin +could not be trusted without checking the user ID. +Portable programs should probably still make this check. +.Sh HISTORY +The +.Fn getlogin +function first appeared in 4.4BSD. diff --git a/bsd/man/man2/getpeername.2 b/bsd/man/man2/getpeername.2 new file mode 100644 index 000000000..6d5738014 --- /dev/null +++ b/bsd/man/man2/getpeername.2 @@ -0,0 +1,92 @@ +.\" $NetBSD: getpeername.2,v 1.6 1995/10/12 15:40:56 jtc Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)getpeername.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt GETPEERNAME 2 +.Os BSD 4.2 +.Sh NAME +.Nm getpeername +.Nd get name of connected peer +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn getpeername "int s" "struct sockaddr *name" "int *namelen" +.Sh DESCRIPTION +.Fn Getpeername +returns the name of the peer connected to +socket +.Fa s . +The +.Fa namelen +parameter should be initialized to indicate +the amount of space pointed to by +.Fa name . +On return it contains the actual size of the name +returned (in bytes). +The name is truncated if the buffer provided is too small. +.Sh DIAGNOSTICS +A 0 is returned if the call succeeds, -1 if it fails. +.Sh ERRORS +The call succeeds unless: +.Bl -tag -width Er +.It Bq Er EBADF +The argument +.Fa s +is not a valid descriptor. +.It Bq Er ENOTSOCK +The argument +.Fa s +is a file, not a socket. +.It Bq Er ENOTCONN +The socket is not connected. +.It Bq Er ENOBUFS +Insufficient resources were available in the system +to perform the operation. +.It Bq Er EFAULT +The +.Fa name +parameter points to memory not in a valid part of the +process address space. +.El +.Sh SEE ALSO +.Xr accept 2 , +.Xr bind 2 , +.Xr socket 2 , +.Xr getsockname 2 +.Sh HISTORY +The +.Fn getpeername +function call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/getpgid.2 b/bsd/man/man2/getpgid.2 new file mode 100644 index 000000000..8ce1967e6 --- /dev/null +++ b/bsd/man/man2/getpgid.2 @@ -0,0 +1 @@ +.so man2/getpgrp.2 diff --git a/bsd/man/man2/getpgrp.2 b/bsd/man/man2/getpgrp.2 new file mode 100644 index 000000000..7b5a0f51d --- /dev/null +++ b/bsd/man/man2/getpgrp.2 @@ -0,0 +1,143 @@ +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)getpgrp.2 8.1 (Berkeley) 6/4/93 +.\" $FreeBSD: src/lib/libc/sys/getpgrp.2,v 1.11.2.6 2001/12/14 18:34:00 ru Exp $ +.\" +.Dd June 4, 1993 +.Dt GETPGRP 2 +.Os +.Sh NAME +.Nm getpgrp +.Nd get process group +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.Ft pid_t +.Fn getpgrp void +.Ft pid_t +.Fn getpgid "pid_t pid" +.Sh DESCRIPTION +The process group of the current process is returned by +.Fn getpgrp . +The process group of the process identified by +.Fa pid +is returned by +.Fn getpgid . +If +.Fa pid +is zero, +.Fn getpgid +returns the process group of the current process. +.Pp +Process groups are used for distribution of signals, and +by terminals to arbitrate requests for their input: processes +that have the same process group as the terminal are foreground +and may read, while others will block with a signal if they attempt +to read. +.Pp +This call is thus used by programs such as +.Xr csh 1 +to create +process groups +in implementing job control. +The +.Fn tcgetpgrp +and +.Fn tcsetpgrp +calls +are used to get/set the process group of the control terminal. +.Sh RETURN VALUES +The +.Fn getpgrp +call always succeeds. +Upon successful completion, the +.Fn getpgid +call returns the process group of the specified process; +otherwise, it returns a value of \-1 and sets +.Va errno +to indicate the error. +.Sh ERRORS +.Fn getpgid +will succeed unless: +.Bl -tag -width Er +.It Bq Er ESRCH +there is no process whose process ID equals +.Fa pid +.El +.Sh SEE ALSO +.Xr getsid 2 , +.Xr setpgid 2 , +.Xr termios 4 +.Sh HISTORY +The +.Fn getpgrp +function call appeared in +.Bx 4.0 . +The +.Fn getpgid +function call is derived from its usage in System V Release 4. +.Sh STANDARDS +The +.Fn getpgrp +function call is expected to conform to +.St -p1003.1-90 . +.Sh COMPATIBILITY +This version of +.Fn getpgrp +differs from past Berkeley versions by not taking a +.Fa "pid_t pid" +argument. +This incompatibility is required by +.St -p1003.1-90 . +.Pp +From the +.St -p1003.1-90 +Rationale: +.Pp +.Bx 4.3 +provides a +.Fn getpgrp +function that returns the process group ID for a specified process. +Although this function is used to support job control, all known +job-control shells always specify the calling process with this +function. +Thus, the simpler +.At V +.Fn getpgrp +suffices, and the added complexity of the +.Bx 4.3 +.Fn getpgrp +has been omitted from POSIX.1. +The old functionality is available from the +.Fn getpgid +function. diff --git a/bsd/man/man2/getpid.2 b/bsd/man/man2/getpid.2 new file mode 100644 index 000000000..0c7f5e365 --- /dev/null +++ b/bsd/man/man2/getpid.2 @@ -0,0 +1,75 @@ +.\" $NetBSD: getpid.2,v 1.5 1995/02/27 12:33:12 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.\" @(#)getpid.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt GETPID 2 +.Os BSD 4 +.Sh NAME +.Nm getpid , +.Nm getppid +.Nd get parent or calling process identification +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft pid_t +.Fn getpid void +.Ft pid_t +.Fn getppid void +.Sh DESCRIPTION +.Fn Getpid +returns +the process ID of +the calling process. +The ID is guaranteed to be unique and is +useful for constructing temporary file names. +.Pp +.Fn Getppid +returns the process ID of the parent +of the calling process. +.Sh ERRORS +The +.Fn getpid +and +.Fn getppid +functions are always successful, and no return value is reserved to +indicate an error. +.Sh SEE ALSO +.Xr gethostid 2 +.Sh STANDARDS +.Fn Getpid +and +.Fn getppid +conform to +.St -p1003.1-88 . diff --git a/bsd/man/man2/getppid.2 b/bsd/man/man2/getppid.2 new file mode 100644 index 000000000..fca885ee4 --- /dev/null +++ b/bsd/man/man2/getppid.2 @@ -0,0 +1 @@ +.so man2/getpid.2 diff --git a/bsd/man/man2/getpriority.2 b/bsd/man/man2/getpriority.2 new file mode 100644 index 000000000..1c5713afd --- /dev/null +++ b/bsd/man/man2/getpriority.2 @@ -0,0 +1,144 @@ +.\" $NetBSD: getpriority.2,v 1.4 1995/02/27 12:33:15 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.\" @(#)getpriority.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt GETPRIORITY 2 +.Os BSD 4 +.Sh NAME +.Nm getpriority , +.Nm setpriority +.Nd get/set program scheduling priority +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn getpriority "int which" "int who" +.Ft int +.Fn setpriority "int which" "int who" "int prio" +.Sh DESCRIPTION +The scheduling +priority of the process, process group, or user, as indicated by +.Fa which +and +.Fa who +is obtained with the +.Fn getpriority +call and set with the +.Fn setpriority +call. +.Fa Which +is one of +.Dv PRIO_PROCESS , +.Dv PRIO_PGRP , +or +.Dv PRIO_USER , +and +.Fa who +is interpreted relative to +.Fa which +(a process identifier for +.Dv PRIO_PROCESS , +process group +identifier for +.Dv PRIO_PGRP , +and a user ID for +.Dv PRIO_USER ) . +A zero value of +.Fa who +denotes the current process, process group, or user. +.Fa Prio +is a value in the range -20 to 20. The default priority is 0; +lower priorities cause more favorable scheduling. +.Pp +The +.Fn getpriority +call returns the highest priority (lowest numerical value) +enjoyed by any of the specified processes. The +.Fn setpriority +call sets the priorities of all of the specified processes +to the specified value. Only the super-user may lower priorities. +.Sh RETURN VALUES +Since +.Fn getpriority +can legitimately return the value -1, it is necessary +to clear the external variable +.Va errno +prior to the +call, then check it afterward to determine +if a -1 is an error or a legitimate value. +The +.Fn setpriority +call returns 0 if there is no error, or +-1 if there is. +.Sh ERRORS +.Fn Getpriority +and +.Fn setpriority +will fail if: +.Bl -tag -width Er +.It Bq Er ESRCH +No process was located using the +.Fa which +and +.Fa who +values specified. +.It Bq Er EINVAL +.Fa Which +was not one of +.Dv PRIO_PROCESS , +.Dv PRIO_PGRP , +or +.Dv PRIO_USER . +.El +.Pp +.Bl -tag -width Er +In addition to the errors indicated above, +.Fn setpriority +will fail if: +.It Bq Er EPERM +A process was located, but neither its effective nor real user +ID matched the effective user ID of the caller. +.It Bq Er EACCES +A non super-user attempted to lower a process priority. +.El +.Sh SEE ALSO +.Xr nice 1 , +.Xr fork 2 , +.Xr renice 8 +.Sh HISTORY +The +.Fn getpriority +function call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/getrlimit.2 b/bsd/man/man2/getrlimit.2 new file mode 100644 index 000000000..c81379974 --- /dev/null +++ b/bsd/man/man2/getrlimit.2 @@ -0,0 +1,190 @@ +.\" $NetBSD: getrlimit.2,v 1.8 1995/10/12 15:40:58 jtc Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.\" @(#)getrlimit.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt GETRLIMIT 2 +.Os BSD 4 +.Sh NAME +.Nm getrlimit , +.Nm setrlimit +.Nd control maximum system resource consumption +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Fd #include +.Ft int +.Fn getrlimit "int resource" "struct rlimit *rlp" +.Ft int +.Fn setrlimit "int resource" "const struct rlimit *rlp" +.Sh DESCRIPTION +Limits on the consumption of system resources by the current process +and each process it creates may be obtained with the +.Fn getrlimit +call, and set with the +.Fn setrlimit +call. +.Pp +The +.Fa resource +parameter is one of the following: +.Bl -tag -width RLIMIT_FSIZEAA +.It Li RLIMIT_CORE +The largest size (in bytes) +.Xr core +file that may be created. +.It Li RLIMIT_CPU +The maximum amount of cpu time (in seconds) to be used by +each process. +.It Li RLIMIT_DATA +The maximum size (in bytes) of the data segment for a process; +this defines how far a program may extend its break with the +.Xr sbrk 2 +system call. +.It Li RLIMIT_FSIZE +The largest size (in bytes) file that may be created. +.It Li RLIMIT_MEMLOCK +The maximum size (in bytes) which a process may lock into memory +using the +.Xr mlock 2 +function. +.It Li RLIMIT_NOFILE +The maximum number of open files for this process. +.It Li RLIMIT_NPROC +The maximum number of simultaneous processes for this user id. +.It Li RLIMIT_RSS +The maximum size (in bytes) to which a process's resident set size may +grow. +This imposes a limit on the amount of physical memory to be given to +a process; if memory is tight, the system will prefer to take memory +from processes that are exceeding their declared resident set size. +.It Li RLIMIT_STACK +The maximum size (in bytes) of the stack segment for a process; +this defines how far a program's stack segment may be extended. +Stack extension is performed automatically by the system. +.El +.Pp +A resource limit is specified as a soft limit and a hard limit. When a +soft limit is exceeded a process may receive a signal (for example, if +the cpu time or file size is exceeded), but it will be allowed to +continue execution until it reaches the hard limit (or modifies +its resource limit). The +.Em rlimit +structure is used to specify the hard and soft limits on a resource, +.Bd -literal -offset indent +struct rlimit { + rlim_t rlim_cur; /* current (soft) limit */ + rlim_t rlim_max; /* hard limit */ +}; +.Ed +.Pp +Only the super-user may raise the maximum limits. Other users +may only alter +.Fa rlim_cur +within the range from 0 to +.Fa rlim_max +or (irreversibly) lower +.Fa rlim_max . +.Pp +An +.Dq infinite +value for a limit is defined as +.Dv RLIM_INFINITY . +.Pp +Because this information is stored in the per-process information, +this system call must be executed directly by the shell if it +is to affect all future processes created by the shell; +.Ic limit +is thus a built-in command to +.Xr csh 1 +and +.Ic ulimit +is the +.Xr sh 1 +equivalent. +.Pp +The system refuses to extend the data or stack space when the limits +would be exceeded in the normal way: a +.Xr break +call fails if the data space limit is reached. +When the stack limit is reached, the process receives +a segmentation fault +.Pq Dv SIGSEGV ; +if this signal is not +caught by a handler using the signal stack, this signal +will kill the process. +.Pp +A file I/O operation that would create a file larger that the process' +soft limit will cause the write to fail and a signal +.Dv SIGXFSZ +to be +generated; this normally terminates the process, but may be caught. When +the soft cpu time limit is exceeded, a signal +.Dv SIGXCPU +is sent to the +offending process. +.Sh RETURN VALUES +A 0 return value indicates that the call succeeded, changing +or returning the resource limit. A return value of -1 indicates +that an error occurred, and an error code is stored in the global +location +.Va errno . +.Sh ERRORS +.Fn Getrlimit +and +.Fn setrlimit +will fail if: +.Bl -tag -width Er +.It Bq Er EFAULT +The address specified for +.Fa rlp +is invalid. +.It Bq Er EPERM +The limit specified to +.Fn setrlimit +would have +raised the maximum limit value, and the caller is not the super-user. +.El +.Sh SEE ALSO +.Xr csh 1 , +.Xr sh 1 , +.Xr quota 2 , +.Xr sigaction 2 , +.Xr sigaltstack 2 , +.Xr sysctl 3 +.Sh HISTORY +The +.Fn getrlimit +function call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/getrusage.2 b/bsd/man/man2/getrusage.2 new file mode 100644 index 000000000..a361d1d36 --- /dev/null +++ b/bsd/man/man2/getrusage.2 @@ -0,0 +1,166 @@ +.\" $NetBSD: getrusage.2,v 1.4 1995/02/27 12:33:23 cgd Exp $ +.\" +.\" Copyright (c) 1985, 1991, 1993 +.\" 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. +.\" +.\" @(#)getrusage.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt GETRUSAGE 2 +.Os BSD 4 +.Sh NAME +.Nm getrusage +.Nd get information about resource utilization +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Fd #define RUSAGE_SELF 0 +.Fd #define RUSAGE_CHILDREN -1 +.Ft int +.Fn getrusage "int who" "struct rusage *rusage" +.Sh DESCRIPTION +.Fn Getrusage +returns information describing the resources utilized by the current +process, or all its terminated child processes. +The +.Fa who +parameter is either +.Dv RUSAGE_SELF +or +.Dv RUSAGE_CHILDREN . +The buffer to which +.Fa rusage +points will be filled in with +the following structure: +.Bd -literal +struct rusage { + struct timeval ru_utime; /* user time used */ + struct timeval ru_stime; /* system time used */ + long ru_maxrss; /* integral max resident set size */ + long ru_ixrss; /* integral shared text memory size */ + long ru_idrss; /* integral unshared data size */ + long ru_isrss; /* integral unshared stack size */ + 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 context switches */ +}; +.Ed +.Pp +The fields are interpreted as follows: +.Bl -tag -width ru_minfltaa +.It Fa ru_utime +the total amount of time spent executing in user mode. +.It Fa ru_stime +the total amount of time spent in the system executing on behalf +of the process(es). +.It Fa ru_maxrss +the maximum resident set size utilized (in kilobytes). +.It Fa ru_ixrss +an \*(lqintegral\*(rq value indicating the amount of memory used +by the text segment +that was also shared among other processes. This value is expressed +in units of kilobytes * ticks-of-execution. +.It Fa ru_idrss +an integral value of the amount of unshared memory residing in the +data segment of a process (expressed in units of +kilobytes * ticks-of-execution). +.It Fa ru_isrss +an integral value of the amount of unshared memory residing in the +stack segment of a process (expressed in units of +kilobytes * ticks-of-execution). +.It Fa ru_minflt +the number of page faults serviced without any I/O activity; here +I/O activity is avoided by \*(lqreclaiming\*(rq a page frame from +the list of pages awaiting reallocation. +.It Fa ru_majflt +the number of page faults serviced that required I/O activity. +.It Fa ru_nswap +the number of times a process was \*(lqswapped\*(rq out of main +memory. +.It Fa ru_inblock +the number of times the file system had to perform input. +.It Fa ru_oublock +the number of times the file system had to perform output. +.It Fa ru_msgsnd +the number of IPC messages sent. +.It Fa ru_msgrcv +the number of IPC messages received. +.It Fa ru_nsignals +the number of signals delivered. +.It Fa ru_nvcsw +the number of times a context switch resulted due to a process +voluntarily giving up the processor before its time slice was +completed (usually to await availability of a resource). +.It Fa ru_nivcsw +the number of times a context switch resulted due to a higher +priority process becoming runnable or because the current process +exceeded its time slice. +.El +.Sh NOTES +The numbers +.Fa ru_inblock +and +.Fa ru_oublock +account only for real +I/O; data supplied by the caching mechanism is charged only +to the first process to read or write the data. +.Sh ERRORS +.Fn Getrusage +returns -1 on error. +The possible errors are: +.Bl -tag -width Er +.It Bq Er EINVAL +The +.Fa who +parameter is not a valid value. +.It Bq Er EFAULT +The address specified by the +.Fa rusage +parameter is not in a valid part of the process address space. +.El +.Sh SEE ALSO +.Xr gettimeofday 2 , +.Xr wait 2 +.Sh BUGS +There is no way to obtain information about a child process +that has not yet terminated. +.Sh HISTORY +The +.Fn getrusage +function call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/getsid.2 b/bsd/man/man2/getsid.2 new file mode 100644 index 000000000..2bd3c272e --- /dev/null +++ b/bsd/man/man2/getsid.2 @@ -0,0 +1,79 @@ +.\" Copyright (c) 1997 Peter Wemm +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD: src/lib/libc/sys/getsid.2,v 1.3.2.5 2001/12/14 18:34:00 ru Exp $ +.\" +.Dd August 19, 1997 +.Dt GETSID 2 +.Os +.Sh NAME +.Nm getsid +.Nd get process session +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.Ft pid_t +.Fn getsid "pid_t pid" +.Sh DESCRIPTION +The session ID of the process identified by +.Fa pid +is returned by +.Fn getsid . +If +.Fa pid +is zero, +.Fn getsid +returns the session ID of the current process. +.Sh RETURN VALUES +Upon successful completion, the function +.Fn getsid +returns the session ID of +the specified process; otherwise, it returns a value of -1 and +sets errno to indicate an error. +.Sh ERRORS +.Fn getsid +will succeed unless: +.Bl -tag -width Er +.It Bq Er ESRCH +if there is no process with a process ID equal to +.Fa pid . +.El +.Pp +Note that an implementation may restrict this function call to +processes within the same session ID as the calling process. +.Sh SEE ALSO +.Xr getpgid 2 , +.Xr getpgrp 2 , +.Xr setpgid 2 , +.Xr setsid 2 , +.Xr termios 4 +.Sh HISTORY +The +.Fn getsid +function call appeared in +.Fx 3.0 . +The +.Fn getsid +function call is derived from its usage in +.At V . diff --git a/bsd/man/man2/getsockname.2 b/bsd/man/man2/getsockname.2 new file mode 100644 index 000000000..4582a3ea5 --- /dev/null +++ b/bsd/man/man2/getsockname.2 @@ -0,0 +1,90 @@ +.\" $NetBSD: getsockname.2,v 1.6 1995/10/12 15:41:00 jtc Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)getsockname.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt GETSOCKNAME 2 +.Os BSD 4.2 +.Sh NAME +.Nm getsockname +.Nd get socket name +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn getsockname "int s" "struct sockaddr *name" "int *namelen" +.Sh DESCRIPTION +.Fn Getsockname +returns the current +.Fa name +for the specified socket. The +.Fa namelen +parameter should be initialized to indicate +the amount of space pointed to by +.Fa name . +On return it contains the actual size of the name +returned (in bytes). +.Sh DIAGNOSTICS +A 0 is returned if the call succeeds, -1 if it fails. +.Sh ERRORS +The call succeeds unless: +.Bl -tag -width Er +.It Bq Er EBADF +The argument +.Fa s +is not a valid descriptor. +.It Bq Er ENOTSOCK +The argument +.Fa s +is a file, not a socket. +.It Bq Er ENOBUFS +Insufficient resources were available in the system +to perform the operation. +.It Bq Er EFAULT +The +.Fa name +parameter points to memory not in a valid part of the +process address space. +.El +.Sh SEE ALSO +.Xr bind 2 , +.Xr socket 2 +.Sh BUGS +Names bound to sockets in the UNIX domain are inaccessible; +.Xr getsockname +returns a zero length name. +.Sh HISTORY +The +.Fn getsockname +function call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/getsockopt.2 b/bsd/man/man2/getsockopt.2 new file mode 100644 index 000000000..cd618692a --- /dev/null +++ b/bsd/man/man2/getsockopt.2 @@ -0,0 +1,356 @@ +.\" $NetBSD: getsockopt.2,v 1.7 1995/02/27 12:33:29 cgd Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)getsockopt.2 8.3 (Berkeley) 4/19/94 +.\" +.Dd April 19, 1994 +.Dt GETSOCKOPT 2 +.Os BSD 4.3r +.Sh NAME +.Nm getsockopt , +.Nm setsockopt +.Nd get and set options on sockets +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn getsockopt "int s" "int level" "int optname" "void *optval" "int *optlen" +.Ft int +.Fn setsockopt "int s" "int level" "int optname" "const void *optval" "int optlen" +.Sh DESCRIPTION +.Fn Getsockopt +and +.Fn setsockopt +manipulate the +.Em options +associated with a socket. Options may exist at multiple +protocol levels; they are always present at the uppermost +.Dq socket +level. +.Pp +When manipulating socket options the level at which the +option resides and the name of the option must be specified. +To manipulate options at the socket level, +.Fa level +is specified as +.Dv SOL_SOCKET . +To manipulate options at any +other level the protocol number of the appropriate protocol +controlling the option is supplied. For example, +to indicate that an option is to be interpreted by the +.Tn TCP +protocol, +.Fa level +should be set to the protocol number of +.Tn TCP ; +see +.Xr getprotoent 3 . +.Pp +The parameters +.Fa optval +and +.Fa optlen +are used to access option values for +.Fn setsockopt . +For +.Fn getsockopt +they identify a buffer in which the value for the +requested option(s) are to be returned. For +.Fn getsockopt , +.Fa optlen +is a value-result parameter, initially containing the +size of the buffer pointed to by +.Fa optval , +and modified on return to indicate the actual size of +the value returned. If no option value is +to be supplied or returned, +.Fa optval +may be NULL. +.Pp +.Fa Optname +and any specified options are passed uninterpreted to the appropriate +protocol module for interpretation. +The include file +.Ao Pa sys/socket.h Ac +contains definitions for +socket level options, described below. +Options at other protocol levels vary in format and +name; consult the appropriate entries in +section +4 of the manual. +.Pp +Most socket-level options utilize an +.Fa int +parameter for +.Fa optval . +For +.Fn setsockopt , +the parameter should be non-zero to enable a boolean option, +or zero if the option is to be disabled. +.Dv SO_LINGER +uses a +.Fa struct linger +parameter, defined in +.Ao Pa sys/socket.h Ac , +which specifies the desired state of the option and the +linger interval (see below). +.Dv SO_SNDTIMEO +and +.Dv SO_RCVTIMEO +use a +.Fa struct timeval +parameter, defined in +.Ao Pa sys/time.h Ac . +.Pp +The following options are recognized at the socket level. +Except as noted, each may be examined with +.Fn getsockopt +and set with +.Fn setsockopt . +.Bl -column SO_OOBINLINE -offset indent +.It Dv SO_DEBUG Ta "enables recording of debugging information" +.It Dv SO_REUSEADDR Ta "enables local address reuse" +.It Dv SO_REUSEPORT Ta "enables duplicate address and port bindings" +.It Dv SO_KEEPALIVE Ta "enables keep connections alive" +.It Dv SO_DONTROUTE Ta "enables routing bypass for outgoing messages" +.It Dv SO_LINGER Ta "linger on close if data present" +.It Dv SO_BROADCAST Ta "enables permission to transmit broadcast messages" +.It Dv SO_OOBINLINE Ta "enables reception of out-of-band data in band" +.It Dv SO_SNDBUF Ta "set buffer size for output" +.It Dv SO_RCVBUF Ta "set buffer size for input" +.It Dv SO_SNDLOWAT Ta "set minimum count for output" +.It Dv SO_RCVLOWAT Ta "set minimum count for input" +.It Dv SO_SNDTIMEO Ta "set timeout value for output" +.It Dv SO_RCVTIMEO Ta "set timeout value for input" +.It Dv SO_TYPE Ta "get the type of the socket (get only)" +.It Dv SO_ERROR Ta "get and clear error on the socket (get only)" +.It Dv SO_NOSIGPIPE Ta "do not generate SIGPIPE, instead return EPIPE" +.El +.Pp +.Dv SO_DEBUG +enables debugging in the underlying protocol modules. +.Dv SO_REUSEADDR +indicates that the rules used in validating addresses supplied +in a +.Xr bind 2 +call should allow reuse of local addresses. +.Dv SO_REUSEPORT +allows completely duplicate bindings by multiple processes +if they all set +.Dv SO_REUSEPORT +before binding the port. +This option permits multiple instances of a program to each +receive UDP/IP multicast or broadcast datagrams destined for the bound port. +.Dv SO_KEEPALIVE +enables the +periodic transmission of messages on a connected socket. Should the +connected party fail to respond to these messages, the connection is +considered broken and processes using the socket are notified via a +.Dv SIGPIPE +signal when attempting to send data. +.Dv SO_DONTROUTE +indicates that outgoing messages should +bypass the standard routing facilities. Instead, messages are directed +to the appropriate network interface according to the network portion +of the destination address. +.Pp +.Dv SO_LINGER +controls the action taken when unsent messages +are queued on socket and a +.Xr close 2 +is performed. +If the socket promises reliable delivery of data and +.Dv SO_LINGER is set, +the system will block the process on the +.Xr close +attempt until it is able to transmit the data or until it decides it +is unable to deliver the information (a timeout period, termed the +linger interval, is specified in the +.Fn setsockopt +call when +.Dv SO_LINGER +is requested). +If +.Dv SO_LINGER +is disabled and a +.Xr close +is issued, the system will process the close in a manner that allows +the process to continue as quickly as possible. +.Pp +The option +.Dv SO_BROADCAST +requests permission to send broadcast datagrams +on the socket. +Broadcast was a privileged operation in earlier versions of the system. +With protocols that support out-of-band data, the +.Dv SO_OOBINLINE +option +requests that out-of-band data be placed in the normal data input queue +as received; it will then be accessible with +.Xr recv +or +.Xr read +calls without the +.Dv MSG_OOB +flag. +Some protocols always behave as if this option is set. +.Dv SO_SNDBUF +and +.Dv SO_RCVBUF +are options to adjust the normal +buffer sizes allocated for output and input buffers, respectively. +The buffer size may be increased for high-volume connections, +or may be decreased to limit the possible backlog of incoming data. +The system places an absolute limit on these values. +.Pp +.Dv SO_SNDLOWAT +is an option to set the minimum count for output operations. +Most output operations process all of the data supplied +by the call, delivering data to the protocol for transmission +and blocking as necessary for flow control. +Nonblocking output operations will process as much data as permitted +subject to flow control without blocking, but will process no data +if flow control does not allow the smaller of the low water mark value +or the entire request to be processed. +A +.Xr select 2 +operation testing the ability to write to a socket will return true +only if the low water mark amount could be processed. +The default value for +.Dv SO_SNDLOWAT +is set to a convenient size for network efficiency, often 1024. +.Dv SO_RCVLOWAT +is an option to set the minimum count for input operations. +In general, receive calls will block until any (non-zero) amount of data +is received, then return with the smaller of the amount available or the amount +requested. +The default value for +.Dv SO_RCVLOWAT +is 1. +If +.Dv SO_RCVLOWAT +is set to a larger value, blocking receive calls normally +wait until they have received the smaller of the low water mark value +or the requested amount. +Receive calls may still return less than the low water mark if an error +occurs, a signal is caught, or the type of data next in the receive queue +is different than that returned. +.Pp +.Dv SO_SNDTIMEO +is an option to set a timeout value for output operations. +It accepts a +.Fa struct timeval +parameter with the number of seconds and microseconds +used to limit waits for output operations to complete. +If a send operation has blocked for this much time, +it returns with a partial count +or with the error +.Er EWOULDBLOCK +if no data were sent. +In the current implementation, this timer is restarted each time additional +data are delivered to the protocol, +implying that the limit applies to output portions ranging in size +from the low water mark to the high water mark for output. +.Dv SO_RCVTIMEO +is an option to set a timeout value for input operations. +It accepts a +.Fa struct timeval +parameter with the number of seconds and microseconds +used to limit waits for input operations to complete. +In the current implementation, this timer is restarted each time additional +data are received by the protocol, +and thus the limit is in effect an inactivity timer. +If a receive operation has been blocked for this much time without +receiving additional data, it returns with a short count +or with the error +.Er EWOULDBLOCK +if no data were received. +.Pp +.Dv SO_NOSIGPIPE is an option that prevents SIGPIPE from being raised +when a write fails on a socket to which there is no reader; +instead the write to the socket returns with the error +.Er EPIPE +when there is no reader. +.Pp +Finally, +.Dv SO_TYPE +and +.Dv SO_ERROR +are options used only with +.Fn getsockopt . +.Dv SO_TYPE +returns the type of the socket, such as +.Dv SOCK_STREAM ; +it is useful for servers that inherit sockets on startup. +.Dv SO_ERROR +returns any pending error on the socket and clears +the error status. +It may be used to check for asynchronous errors on connected +datagram sockets or for other asynchronous errors. +.Sh RETURN VALUES +A 0 is returned if the call succeeds, -1 if it fails. +.Sh ERRORS +The call succeeds unless: +.Bl -tag -width Er +.It Bq Er EBADF +The argument +.Fa s +is not a valid descriptor. +.It Bq Er ENOTSOCK +The argument +.Fa s +is a file, not a socket. +.It Bq Er ENOPROTOOPT +The option is unknown at the level indicated. +.It Bq Er EFAULT +The address pointed to by +.Fa optval +is not in a valid part of the process address space. +For +.Fn getsockopt , +this error may also be returned if +.Fa optlen +is not in a valid part of the process address space. +.El +.Sh SEE ALSO +.Xr ioctl 2 , +.Xr socket 2 , +.Xr getprotoent 3 +.Xr protocols 5 +.Sh BUGS +Several of the socket options should be handled at lower levels of the system. +.Sh HISTORY +The +.Fn getsockopt +system call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/gettimeofday.2 b/bsd/man/man2/gettimeofday.2 new file mode 100644 index 000000000..febc61dcd --- /dev/null +++ b/bsd/man/man2/gettimeofday.2 @@ -0,0 +1,130 @@ +.\" $OpenBSD: gettimeofday.2,v 1.5 1997/03/16 01:18:49 flipk Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.\" @(#)gettimeofday.2 8.2 (Berkeley) 5/26/95 +.\" +.Dd May 26, 1995 +.Dt GETTIMEOFDAY 2 +.Os BSD 4 +.Sh NAME +.Nm gettimeofday , +.Nm settimeofday +.Nd get/set date and time +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn gettimeofday "struct timeval *tp" "struct timezone *tzp" +.Ft int +.Fn settimeofday "const struct timeval *tp" "const struct timezone *tzp" +.Sh DESCRIPTION +.Bf -symbolic +Note: timezone is no longer used; this information is kept outside +the kernel. +.Ef +.Pp +The system's notion of the current Greenwich time and the current time +zone is obtained with the +.Fn gettimeofday +call, and set with the +.Fn settimeofday +call. The time is expressed in seconds and microseconds +since midnight (0 hour), January 1, 1970. The resolution of the system +clock is hardware dependent, and the time may be updated continuously or +in ``ticks.'' If +.Fa tp +or +.Fa tzp +is NULL, the associated time +information will not be returned or set. +.Pp +The structures pointed to by +.Fa tp +and +.Fa tzp +are defined in +.Ao Pa sys/time.h Ac +as: +.Pp +.Bd -literal +struct timeval { + long tv_sec; /* seconds since Jan. 1, 1970 */ + long tv_usec; /* and microseconds */ +}; + +struct timezone { + int tz_minuteswest; /* of Greenwich */ + int tz_dsttime; /* type of dst correction to apply */ +}; +.Ed +.Pp +The +.Fa timezone +structure indicates the local time zone +(measured in minutes of time westward from Greenwich), +and a flag that, if nonzero, indicates that +Daylight Saving time applies locally during +the appropriate part of the year. +.Pp +Only the super-user may set the time of day or time zone. +If the system securelevel is greater than 1 (see +.Xr init 8 ), +the time may only be advanced. +This limitation is imposed to prevent a malicious super-user +from setting arbitrary time stamps on files. +The system time can still be adjusted backwards using the +.Xr adjtime 2 +system call even when the system is secure. +.Sh RETURN +A 0 return value indicates that the call succeeded. +A -1 return value indicates an error occurred, and in this +case an error code is stored into the global variable +.Va errno . +.Sh ERRORS +The following error codes may be set in +.Va errno : +.Bl -tag -width [EFAULT] +.It Bq Er EFAULT +An argument address referenced invalid memory. +.It Bq Er EPERM +A user other than the super-user attempted to set the time. +.El +.Sh SEE ALSO +.Xr date 1 , +.Xr adjtime 2 , +.Xr ctime 3 , +.Xr timed 8 +.Sh HISTORY +The +.Fn gettimeofday +function call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/getuid.2 b/bsd/man/man2/getuid.2 new file mode 100644 index 000000000..271a48dab --- /dev/null +++ b/bsd/man/man2/getuid.2 @@ -0,0 +1,82 @@ +.\" $NetBSD: getuid.2,v 1.6 1995/02/27 12:33:37 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.\" @(#)getuid.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt GETUID 2 +.Os BSD 4 +.Sh NAME +.Nm getuid , +.Nm geteuid +.Nd get user identification +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft uid_t +.Fn getuid void +.Ft uid_t +.Fn geteuid void +.Sh DESCRIPTION +The +.Fn getuid +function returns the real user ID of the calling process. +The +.Fn geteuid +function +returns the effective user ID of the calling process. +.Pp +The real user ID is that of the user who has invoked the program. +As the effective user ID +gives the process additional permissions during +execution of +.Dq Em set-user-ID +mode processes, +.Fn getuid +is used to determine the real-user-id of the calling process. +.Sh ERRORS +The +.Fn getuid +and +.Fn geteuid +functions are always successful, and no return value is reserved to +indicate an error. +.Sh SEE ALSO +.Xr getgid 2 , +.Xr setreuid 2 +.Sh STANDARDS +.Fn Geteuid +and +.Fn getuid +functions conform to +.St -p1003.1-88 . diff --git a/bsd/man/man2/intro.2 b/bsd/man/man2/intro.2 new file mode 100644 index 000000000..3892834cd --- /dev/null +++ b/bsd/man/man2/intro.2 @@ -0,0 +1,674 @@ +.\" $NetBSD: intro.2,v 1.6 1995/02/27 12:33:41 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1983, 1986, 1991, 1993 +.\" 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. +.\" +.\" @(#)intro.2 8.3 (Berkeley) 12/11/93 +.\" +.Dd December 11, 1993 +.Dt INTRO 2 +.Os BSD 4 +.Sh NAME +.Nm intro +.Nd introduction to system calls and error numbers +.Sh SYNOPSIS +.Fd #include +.Sh DESCRIPTION +This section provides an overview of the system calls, +their error returns, and other common definitions and concepts. +.\".Pp +.\".Sy System call restart +.\".Pp +.\" +.Sh DIAGNOSTICS +Nearly all of the system calls provide an error number in the external +variable +.Va errno , +which is defined as: +.Pp +.Dl extern int errno +.Pp +When a system call detects an error, +it returns an integer value +indicating failure (usually -1) +and sets the variable +.Va errno +accordingly. + +Successful calls never set +.Va errno ; +once set, it remains until another error occurs. +It should only be examined after an error. +Note that a number of system calls overload the meanings of these +error numbers, and that the meanings must be interpreted according +to the type and circumstances of the call. +.Pp +The following is a complete list of the errors and their +names as given in +.Aq Pa sys/errno.h . +.Bl -hang -width Ds +.It Er 0 Em "Error 0" . +Not used. +.It Er 1 EPERM Em "Operation not permitted" . +An attempt was made to perform an operation limited to processes +with appropriate privileges or to the owner of a file or other +resources. +.It Er 2 ENOENT Em "No such file or directory" . +A component of a specified pathname did not exist, or the +pathname was an empty string. +.It Er 3 ESRCH Em "No such process" . +No process could be found corresponding to that specified by the given +process ID. +.It Er 4 EINTR Em "Interrupted function call" . +An asynchronous signal (such as +.Dv SIGINT +or +.Dv SIGQUIT ) +was caught by the process during the execution of an interruptible +function. If the signal handler performs a normal return, the +interrupted function call will seem to have returned the error condition. +.It Er 5 EIO Em "Input/output error" . +Some physical input or output error occurred. +This error will not be reported until a subsequent operation on the same file +descriptor and may be lost (over written) by any subsequent errors. +.It Er 6 ENXIO Em "\&No such device or address" . +Input or output on a special file referred to a device that did not +exist, or +made a request beyond the limits of the device. +This error may also occur when, for example, +a tape drive is not online or no disk pack is +loaded on a drive. +.It Er 7 E2BIG Em "Arg list too long" . +The number of bytes used for the argument and environment +list of the new process exceeded the limit +.Dv NCARGS +(specified in +.Aq Pa sys/param.h ) . +.It Er 8 ENOEXEC Em "Exec format error" . +A request was made to execute a file +that, although it has the appropriate permissions, +was not in the format required for an +executable file. +.It Er 9 EBADF Em "Bad file descriptor" . +A file descriptor argument was out of range, referred to no open file, +or a read (write) request was made to a file that was only open for +writing (reading). +.It Er 10 ECHILD Em "\&No child processes" . +A +.Xr wait +or +.Xr waitpid +function was executed by a process that had no existing or unwaited-for +child processes. +.It Er 11 EDEADLK Em "Resource deadlock avoided" . +An attempt was made to lock a system resource that +would have resulted in a deadlock situation. +.It Er 12 ENOMEM Em "Cannot allocate memory" . +The new process image required more memory than was allowed by the hardware +or by system-imposed memory management constraints. +A lack of swap space is normally temporary; however, +a lack of core is not. +Soft limits may be increased to their corresponding hard limits. +.It Er 13 EACCES Em "Permission denied" . +An attempt was made to access a file in a way forbidden +by its file access permissions. +.It Er 14 EFAULT Em "Bad address" . +The system detected an invalid address in attempting to +use an argument of a call. +.It Er 15 ENOTBLK Em "Not a block device" . +A block device operation was attempted on a non-block device or file. +.It Er 16 EBUSY Em "Resource busy" . +An attempt to use a system resource which was in use at the time +in a manner which would have conflicted with the request. +.It Er 17 EEXIST Em "File exists" . +An existing file was mentioned in an inappropriate context, +for instance, as the new link name in a +.Xr link +function. +.It Er 18 EXDEV Em "Improper link" . +A hard link to a file on another file system +was attempted. +.It Er 19 ENODEV Em "Operation not supported by device" . +An attempt was made to apply an inappropriate +function to a device, +for example, +trying to read a write-only device such as a printer. +.It Er 20 ENOTDIR Em "Not a directory" . +A component of the specified pathname existed, but it was +not a directory, when a directory was expected. +.It Er 21 EISDIR Em "Is a directory" . +An attempt was made to open a directory with write mode specified. +.It Er 22 EINVAL Em "Invalid argument" . +Some invalid argument was supplied. (For example, +specifying an undefined signal to a +.Xr signal +or +.Xr kill +function). +.It Er 23 ENFILE Em "Too many open files in system" . +Maximum number of file descriptors allowable on the system +has been reached and a requests for an open cannot be satisfied +until at least one has been closed. +.It Er 24 EMFILE Em "Too many open files" . + +.Xr Getdtablesize 2 +will obtain the current limit. +.It Er 25 ENOTTY Em "Inappropriate ioctl for device" . +A control function (see +.Xr ioctl 2 ) +was attempted for a file or +special device for which the operation was inappropriate. +.It Er 26 ETXTBSY Em "Text file busy" . +The new process was a pure procedure (shared text) file +which was open for writing by another process, or +while the pure procedure file was being executed an +.Xr open +call requested write access. +.It Er 27 EFBIG Em "File too large" . +The size of a file exceeded the maximum (about +.if t 2\u\s-231\s+2\d +.if n 2.1E9 +bytes). +.It Er 28 ENOSPC Em "Device out of space" . +A +.Xr write +to an ordinary file, the creation of a +directory or symbolic link, or the creation of a directory +entry failed because no more disk blocks were available +on the file system, or the allocation of an inode for a newly +created file failed because no more inodes were available +on the file system. +.It Er 29 ESPIPE Em "Illegal seek" . +An +.Xr lseek +function was issued on a socket, pipe or +.Tn FIFO . +.It Er 30 EROFS Em "Read-only file system" . +An attempt was made to modify a file or directory +was made +on a file system that was read-only at the time. +.It Er 31 EMLINK Em "Too many links" . +Maximum allowable hard links to a single file has been exceeded (limit +of 32767 hard links per file). +.It Er 32 EPIPE Em "Broken pipe" . +A write on a pipe, socket or +.Tn FIFO +for which there is no process +to read the data. +.It Er 33 EDOM Em "Numerical argument out of domain" . +A numerical input argument was outside the defined domain of the mathematical +function. +.It Er 34 ERANGE Em "Numerical result out of range" . +A numerical result of the function was too large to fit in the +available space (perhaps exceeded precision). +.It Er 35 EAGAIN Em "Resource temporarily unavailable" . +This is a temporary condition and later calls to the +same routine may complete normally. +.It Er 36 EINPROGRESS Em "Operation now in progress" . +An operation that takes a long time to complete (such as +a +.Xr connect 2 ) +was attempted on a non-blocking object (see +.Xr fcntl 2 ) . +.It Er 37 EALREADY Em "Operation already in progress" . +An operation was attempted on a non-blocking object that already +had an operation in progress. +.It Er 38 ENOTSOCK Em "Socket operation on non-socket" . +Self-explanatory. +.It Er 39 EDESTADDRREQ Em "Destination address required" . +A required address was omitted from an operation on a socket. +.It Er 40 EMSGSIZE Em "Message too long" . +A message sent on a socket was larger than the internal message buffer +or some other network limit. +.It Er 41 EPROTOTYPE Em "Protocol wrong type for socket" . +A protocol was specified that does not support the semantics of the +socket type requested. For example, you cannot use the +.Tn ARPA +Internet +.Tn UDP +protocol with type +.Dv SOCK_STREAM . +.It Er 42 ENOPROTOOPT Em "Protocol not available" . +A bad option or level was specified in a +.Xr getsockopt 2 +or +.Xr setsockopt 2 +call. +.It Er 43 EPROTONOSUPPORT Em "Protocol not supported" . +The protocol has not been configured into the +system or no implementation for it exists. +.It Er 44 ESOCKTNOSUPPORT Em "Socket type not supported" . +The support for the socket type has not been configured into the +system or no implementation for it exists. +.It Er 45 EOPNOTSUPP Em "Operation not supported" . +The attempted operation is not supported for the type of object referenced. +Usually this occurs when a file descriptor refers to a file or socket +that cannot support this operation, +for example, trying to +.Em accept +a connection on a datagram socket. +.It Er 46 EPFNOSUPPORT Em "Protocol family not supported" . +The protocol family has not been configured into the +system or no implementation for it exists. +.It Er 47 EAFNOSUPPORT Em "Address family not supported by protocol family" . +An address incompatible with the requested protocol was used. +For example, you shouldn't necessarily expect to be able to use +.Tn NS +addresses with +.Tn ARPA +Internet protocols. +.It Er 48 EADDRINUSE Em "Address already in use" . +Only one usage of each address is normally permitted. +.It Er 49 EADDRNOTAVAIL Em "Cannot assign requested address" . +Normally results from an attempt to create a socket with an +address not on this machine. +.It Er 50 ENETDOWN Em "Network is down" . +A socket operation encountered a dead network. +.It Er 51 ENETUNREACH Em "Network is unreachable" . +A socket operation was attempted to an unreachable network. +.It Er 52 ENETRESET Em "Network dropped connection on reset" . +The host you were connected to crashed and rebooted. +.It Er 53 ECONNABORTED Em "Software caused connection abort" . +A connection abort was caused internal to your host machine. +.It Er 54 ECONNRESET Em "Connection reset by peer" . +A connection was forcibly closed by a peer. This normally +results from a loss of the connection on the remote socket +due to a timeout or a reboot. +.It Er 55 ENOBUFS Em "\&No buffer space available" . +An operation on a socket or pipe was not performed because +the system lacked sufficient buffer space or because a queue was full. +.It Er 56 EISCONN Em "Socket is already connected" . +A +.Xr connect +request was made on an already connected socket; or, +a +.Xr sendto +or +.Xr sendmsg +request on a connected socket specified a destination +when already connected. +.It Er 57 ENOTCONN Em "Socket is not connected" . +An request to send or receive data was disallowed because +the socket was not connected and (when sending on a datagram socket) +no address was supplied. +.It Er 58 ESHUTDOWN Em "Cannot send after socket shutdown" . +A request to send data was disallowed because the socket +had already been shut down with a previous +.Xr shutdown 2 +call. +.It Er 60 ETIMEDOUT Em "Operation timed out" . +A +.Xr connect +or +.Xr send +request failed because the connected party did not +properly respond after a period of time. (The timeout +period is dependent on the communication protocol.) +.It Er 61 ECONNREFUSED Em "Connection refused" . +No connection could be made because the target machine actively +refused it. This usually results from trying to connect +to a service that is inactive on the foreign host. +.It Er 62 ELOOP Em "Too many levels of symbolic links" . +A path name lookup involved more than 8 symbolic links. +.It Er 63 ENAMETOOLONG Em "File name too long" . +A component of a path name exceeded 255 +.Pq Dv MAXNAMELEN +characters, or an entire +path name exceeded 1023 +.Pq Dv MAXPATHLEN Ns -1 +characters. +.It Er 64 EHOSTDOWN Em "Host is down" . +A socket operation failed because the destination host was down. +.It Er 65 EHOSTUNREACH Em "No route to host" . +A socket operation was attempted to an unreachable host. +.It Er 66 ENOTEMPTY Em "Directory not empty" . +A directory with entries other than +.Ql \&. +and +.Ql \&.. +was supplied to a remove directory or rename call. +.It Er 67 EPROCLIM Em "Too many processes" . +.It Er 68 EUSERS Em "Too many users" . +The quota system ran out of table entries. +.It Er 69 EDQUOT Em "Disc quota exceeded" . +A +.Xr write +to an ordinary file, the creation of a +directory or symbolic link, or the creation of a directory +entry failed because the user's quota of disk blocks was +exhausted, or the allocation of an inode for a newly +created file failed because the user's quota of inodes +was exhausted. +.It Er 70 ESTALE Em "Stale NFS file handle" . +An attempt was made to access an open file (on an +.Tn NFS +filesystem) +which is now unavailable as referenced by the file descriptor. +This may indicate the file was deleted on the +.Tn NFS +server or some +other catastrophic event occurred. +.It Er 72 EBADRPC Em "RPC struct is bad" . +Exchange of +.Tn RPC +information was unsuccessful. +.It Er 73 ERPCMISMATCH Em "RPC version wrong" . +The version of +.Tn RPC +on the remote peer is not compatible with +the local version. +.It Er 74 EPROGUNAVAIL Em "RPC prog. not avail" . +The requested program is not registered on the remote host. +.It Er 75 EPROGMISMATCH Em "Program version wrong" . +The requested version of the program is not available +on the remote host +.Pq Tn RPC . +.It Er 76 EPROCUNAVAIL Em "Bad procedure for program" . +An +.Tn RPC +call was attempted for a procedure which doesn't exist +in the remote program. +.It Er 77 ENOLCK Em "No locks available" . +A system-imposed limit on the number of simultaneous file +locks was reached. +.It Er 78 ENOSYS Em "Function not implemented" . +Attempted a system call that is not available on this +system. +.Sh DEFINITIONS +.Bl -tag -width Ds +.It Process ID . +Each active process in the system is uniquely identified by a non-negative +integer called a process ID. The range of this ID is from 0 to 30000. +.It Parent process ID +A new process is created by a currently active process; (see +.Xr fork 2 ) . +The parent process ID of a process is initially the process ID of its creator. +If the creating process exits, +the parent process ID of each child is set to the ID of a system process, +.Xr init . +.It Process Group +Each active process is a member of a process group that is identified by +a non-negative integer called the process group ID. This is the process +ID of the group leader. This grouping permits the signaling of related +processes (see +.Xr termios 4 ) +and the job control mechanisms of +.Xr csh 1 . +.It Session +A session is a set of one or more process groups. +A session is created by a successful call to +.Xr setsid 2 , +which causes the caller to become the only member of the only process +group in the new session. +.It Session leader +A process that has created a new session by a successful call to +.Xr setsid 2 , +is known as a session leader. +Only a session leader may acquire a terminal as its controlling terminal (see +.Xr termios 4 ) . +.It Controlling process +A session leader with a controlling terminal is a controlling process. +.It Controlling terminal +A terminal that is associated with a session is known as the controlling +terminal for that session and its members. +.It "Terminal Process Group ID" +A terminal may be acquired by a session leader as its controlling terminal. +Once a terminal is associated with a session, any of the process groups +within the session may be placed into the foreground by setting +the terminal process group ID to the ID of the process group. +This facility is used +to arbitrate between multiple jobs contending for the same terminal; +(see +.Xr csh 1 +and +.Xr tty 4 ) . +.It "Orphaned Process Group" +A process group is considered to be +.Em orphaned +if it is not under the control of a job control shell. +More precisely, a process group is orphaned +when none of its members has a parent process that is in the same session +as the group, +but is in a different process group. +Note that when a process exits, the parent process for its children +is changed to be +.Xr init , +which is in a separate session. +Not all members of an orphaned process group are necessarily orphaned +processes (those whose creating process has exited). +The process group of a session leader is orphaned by definition. +.It "Real User ID and Real Group ID" +Each user on the system is identified by a positive integer +termed the real user ID. +.Pp +Each user is also a member of one or more groups. +One of these groups is distinguished from others and +used in implementing accounting facilities. The positive +integer corresponding to this distinguished group is termed +the real group ID. +.Pp +All processes have a real user ID and real group ID. +These are initialized from the equivalent attributes +of the process that created it. +.It "Effective User Id, Effective Group Id, and Group Access List" +Access to system resources is governed by two values: +the effective user ID, and the group access list. +The first member of the group access list is also known as the +effective group ID. +(In POSIX.1, the group access list is known as the set of supplementary +group IDs, and it is unspecified whether the effective group ID is +a member of the list.) +.Pp +The effective user ID and effective group ID are initially the +process's real user ID and real group ID respectively. Either +may be modified through execution of a set-user-ID or set-group-ID +file (possibly by one its ancestors) (see +.Xr execve 2 ) . +By convention, the effective group ID (the first member of the group access +list) is duplicated, so that the execution of a set-group-ID program +does not result in the loss of the original (real) group ID. +.Pp +The group access list is a set of group IDs +used only in determining resource accessibility. Access checks +are performed as described below in ``File Access Permissions''. +.It "Saved Set User ID and Saved Set Group ID" +When a process executes a new file, the effective user ID is set +to the owner of the file if the file is set-user-ID, and the effective +group ID (first element of the group access list) is set to the group +of the file if the file is set-group-ID. +The effective user ID of the process is then recorded as the saved set-user-ID, +and the effective group ID of the process is recorded as the saved set-group-ID. +These values may be used to regain those values as the effective user +or group ID after reverting to the real ID (see +.Xr setuid 2 ) . +(In POSIX.1, the saved set-user-ID and saved set-group-ID are optional, +and are used in setuid and setgid, but this does not work as desired +for the super-user.) +.It Super-user +A process is recognized as a +.Em super-user +process and is granted special privileges if its effective user ID is 0. +.It Special Processes +The processes with process IDs of 0, 1, and 2 are special. +Process 0 is the scheduler. Process 1 is the initialization process +.Xr init , +and is the ancestor of every other process in the system. +It is used to control the process structure. +Process 2 is the paging daemon. +.It Descriptor +An integer assigned by the system when a file is referenced +by +.Xr open 2 +or +.Xr dup 2 , +or when a socket is created by +.Xr pipe 2 , +.Xr socket 2 +or +.Xr socketpair 2 , +which uniquely identifies an access path to that file or socket from +a given process or any of its children. +.It File Name +Names consisting of up to 255 +.Pq Dv MAXNAMELEN +characters may be used to name +an ordinary file, special file, or directory. +.Pp +These characters may be selected from the set of all +.Tn ASCII +character +excluding 0 (NUL) and the +.Tn ASCII +code for +.Ql \&/ +(slash). +.Pp +Note that it is generally unwise to use +.Ql \&* , +.Ql \&? , +.Ql \&[ +or +.Ql \&] +as part of +file names because of the special meaning attached to these characters +by the shell. +.It Path Name +A path name is a +.Tn NUL Ns -terminated +character string starting with an +optional slash +.Ql \&/ , +followed by zero or more directory names separated +by slashes, optionally followed by a file name. +The total length of a path name must be less than 1024 +.Pq Dv MAXPATHLEN +characters. +.Pp +If a path name begins with a slash, the path search begins at the +.Em root +directory. +Otherwise, the search begins from the current working directory. +A slash by itself names the root directory. An empty +pathname refers to the current directory. +.It Directory +A directory is a special type of file that contains entries +that are references to other files. +Directory entries are called links. By convention, a directory +contains at least two links, +.Ql \&. +and +.Ql \&.. , +referred to as +.Em dot +and +.Em dot-dot +respectively. Dot refers to the directory itself and +dot-dot refers to its parent directory. +.It "Root Directory and Current Working Directory" +Each process has associated with it a concept of a root directory +and a current working directory for the purpose of resolving path +name searches. A process's root directory need not be the root +directory of the root file system. +.It File Access Permissions +Every file in the file system has a set of access permissions. +These permissions are used in determining whether a process +may perform a requested operation on the file (such as opening +a file for writing). Access permissions are established at the +time a file is created. They may be changed at some later time +through the +.Xr chmod 2 +call. +.Pp +File access is broken down according to whether a file may be: read, +written, or executed. Directory files use the execute +permission to control if the directory may be searched. +.Pp +File access permissions are interpreted by the system as +they apply to three different classes of users: the owner +of the file, those users in the file's group, anyone else. +Every file has an independent set of access permissions for +each of these classes. When an access check is made, the system +decides if permission should be granted by checking the access +information applicable to the caller. +.Pp +Read, write, and execute/search permissions on +a file are granted to a process if: +.Pp +The process's effective user ID is that of the super-user. (Note: +even the super-user cannot execute a non-executable file.) +.Pp +The process's effective user ID matches the user ID of the owner +of the file and the owner permissions allow the access. +.Pp +The process's effective user ID does not match the user ID of the +owner of the file, and either the process's effective +group ID matches the group ID +of the file, or the group ID of the file is in +the process's group access list, +and the group permissions allow the access. +.Pp +Neither the effective user ID nor effective group ID +and group access list of the process +match the corresponding user ID and group ID of the file, +but the permissions for ``other users'' allow access. +.Pp +Otherwise, permission is denied. +.It Sockets and Address Families +.Pp +A socket is an endpoint for communication between processes. +Each socket has queues for sending and receiving data. +.Pp +Sockets are typed according to their communications properties. +These properties include whether messages sent and received +at a socket require the name of the partner, whether communication +is reliable, the format used in naming message recipients, etc. +.Pp +Each instance of the system supports some +collection of socket types; consult +.Xr socket 2 +for more information about the types available and +their properties. +.Pp +Each instance of the system supports some number of sets of +communications protocols. Each protocol set supports addresses +of a certain format. An Address Family is the set of addresses +for a specific group of protocols. Each socket has an address +chosen from the address family in which the socket was created. +.Sh SEE ALSO +.Xr intro 3 , +.Xr perror 3 +.Sh HISTORY +An +.Nm intro +manual page appeared in +.At v6 . diff --git a/bsd/man/man2/ioctl.2 b/bsd/man/man2/ioctl.2 new file mode 100644 index 000000000..1c3d6d6ba --- /dev/null +++ b/bsd/man/man2/ioctl.2 @@ -0,0 +1,111 @@ +.\" $NetBSD: ioctl.2,v 1.5 1995/02/27 12:33:47 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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.2 8.2 (Berkeley) 12/11/93 +.\" +.Dd December 11, 1993 +.Dt IOCTL 2 +.Os BSD 4 +.Sh NAME +.Nm ioctl +.Nd control device +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn ioctl "int d" "unsigned long request" "char *argp" +.Sh DESCRIPTION +The +.Fn ioctl +function manipulates the underlying device parameters of special files. +In particular, many operating +characteristics of character special files (e.g. terminals) +may be controlled with +.Fn ioctl +requests. +The argument +.Fa d +must be an open file descriptor. +.Pp +An ioctl +.Fa request +has encoded in it whether the argument is an +.Dq in +parameter +or +.Dq out +parameter, and the size of the argument +.Fa argp +in bytes. +Macros and defines used in specifying an ioctl +.Fa request +are located in the file +.Ao Pa sys/ioctl.h Ac . +.Sh RETURN VALUES +If an error has occurred, a value of -1 is returned and +.Va errno +is set to indicate the error. +.Sh ERRORS +.Fn Ioctl +will fail if: +.Bl -tag -width Er +.It Bq Er EBADF +.Fa d +is not a valid descriptor. +.It Bq Er ENOTTY +.Fa d +is not associated with a character +special device. +.It Bq Er ENOTTY +The specified request does not apply to the kind +of object that the descriptor +.Fa d +references. +.It Bq Er EINVAL +.Fa Request +or +.Fa argp +is not valid. +.El +.Sh SEE ALSO +.Xr mt 1 , +.Xr cdio 1 , +.Xr chio 1 , +.Xr execve 2 , +.Xr fcntl 2 , +.Xr tty 4 , +.Xr intro 4 +.Sh HISTORY +An +.Fn ioctl +function call appeared in +.At v7 . diff --git a/bsd/man/man2/issetugid.2 b/bsd/man/man2/issetugid.2 new file mode 100644 index 000000000..aca73d10e --- /dev/null +++ b/bsd/man/man2/issetugid.2 @@ -0,0 +1,87 @@ +.\" $OpenBSD: issetugid.2,v 1.7 1997/02/18 00:16:09 deraadt Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.Dd August, 25 1996 +.Dt ISSETUGID 2 +.Os OpenBSD 2.0 +.Sh NAME +.Nm issetugid +.Nd is current executable running setuid or setgid +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn issetugid void +.Sh DESCRIPTION +The +.Fn issetugid +function returns 1 if the process was made setuid or setgid as +the result of the last +.Fn execve +system call. +Otherwise it returns 0. +.Pp +This system call exists so that library routines (inside libc, libtermlib, +or other libraries) can gaurantee safe behavior when used inside +setuid or setgid programs. +Some library routines may not be passed sufficient information to know +if the current program was started setuid or setgid because higher level +calling code may have made changes to the uid or the euid. +In particular, it is wise to use this call to determine if a +pathname returned from a +.Fn getenv +call may safely be used to +.Fn open +the specified file. +.Pp +.Fn issetugid +is unaffected by calls to +.Fn setuid , +.Fn fork , +and other such calls. It is only controlled by +.Fn execve . +.Sh ERRORS +The +.Fn issetugid +function is always successful, and no return value is reserved to +indicate an error. +.Sh SEE ALSO +.Xr execve 2 , +.Xr setuid 2 , +.Xr seteuid 2, +.Xr setgid 2 , +.Xr setegid 2 +.Sh HISTORY +A +.Fn lstat +function call appeared in +OpenBSD 2.0 diff --git a/bsd/man/man2/kill.2 b/bsd/man/man2/kill.2 new file mode 100644 index 000000000..6b7157f35 --- /dev/null +++ b/bsd/man/man2/kill.2 @@ -0,0 +1,132 @@ +.\" $NetBSD: kill.2,v 1.7 1995/02/27 12:33:53 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.\" @(#)kill.2 8.3 (Berkeley) 4/19/94 +.\" +.Dd April 19, 1994 +.Dt KILL 2 +.Os BSD 4 +.Sh NAME +.Nm kill +.Nd send signal to a process +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn kill "pid_t pid" "int sig" +.Sh DESCRIPTION +The +.Fn kill +function sends the signal given by +.Fa sig +to +.Fa pid , +a +process or a group of processes. +.Fa Sig +may be one of the signals specified in +.Xr sigaction 2 +or it may be 0, in which case +error checking is performed but no +signal is actually sent. +This can be used to check the validity of +.Fa pid . +.Pp +For a process to have permission to send a signal to a process designated +by +.Fa pid , +the real or effective user ID of the receiving process must match +that of the sending process or the user must have appropriate privileges +(such as given by a set-user-ID program or the user is the super-user). +A single exception is the signal SIGCONT, which may always be sent +to any descendant of the current process. +.Bl -tag -width Ds +.It \&If Fa pid No \&is greater than zero : +.Fa Sig +is sent to the process whose ID is equal to +.Fa pid. +.It \&If Fa pid No \&is zero : +.Fa Sig +is sent to all processes whose group ID is equal +to the process group ID of the sender, and for which the +process has permission; +this is a variant of +.Xr killpg 2 . +.It \&If Fa pid No \&is -1 : +If the user has super-user privileges, +the signal is sent to all processes excluding +system processes and the process sending the signal. +If the user is not the super user, the signal is sent to all processes +with the same uid as the user excluding the process sending the signal. +No error is returned if any process could be signaled. +.El +.Pp +For compatibility with System V, +if the process number is negative but not -1, +the signal is sent to all processes whose process group ID +is equal to the absolute value of the process number. +This is a variant of +.Xr killpg 2 . +.Sh RETURN VALUES +Upon successful completion, a value of 0 is returned. +Otherwise, a value of -1 is returned and +.Va errno +is set to indicate the error. +.Sh ERRORS +.Fn Kill +will fail and no signal will be sent if: +.Bl -tag -width Er +.It Bq Er EINVAL +.Fa Sig +is not a valid signal number. +.It Bq Er ESRCH +No process can be found corresponding to that specified by +.Fa pid . +.It Bq Er ESRCH +The process id was given as 0 +but the sending process does not have a process group. +.It Bq Er EPERM +The sending process is not the super-user and its effective +user id does not match the effective user-id of the receiving process. +When signaling a process group, this error is returned if any members +of the group could not be signaled. +.El +.Sh SEE ALSO +.Xr getpid 2 , +.Xr getpgrp 2 , +.Xr killpg 2 , +.Xr sigaction 2 +.Sh STANDARDS +The +.Fn kill +function is expected to conform to +.St -p1003.1-88 . diff --git a/bsd/man/man2/ktrace.2 b/bsd/man/man2/ktrace.2 new file mode 100644 index 000000000..3fdc9851a --- /dev/null +++ b/bsd/man/man2/ktrace.2 @@ -0,0 +1,168 @@ +.\" Copyright (c) 1993 +.\" 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.2 8.1 (Berkeley) 6/4/93 +.\" $FreeBSD: src/lib/libc/sys/ktrace.2,v 1.9.2.7 2001/12/14 18:34:01 ru Exp $ +.\" +.Dd June 4, 1993 +.Dt KTRACE 2 +.Os +.Sh NAME +.Nm ktrace +.Nd process tracing +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In sys/param.h +.In sys/time.h +.In sys/uio.h +.In sys/ktrace.h +.Ft int +.Fn ktrace "const char *tracefile" "int ops" "int trpoints" "int pid" +.Sh DESCRIPTION +The +.Fn ktrace +function enables or disables tracing of one or more processes. +Users may only trace their own processes. +Only the super-user can trace setuid or setgid programs. +.Pp +The +.Fa tracefile +gives the pathname of the file to be used for tracing. +The file must exist and be a regular file writable by the calling process. +All trace records are always appended to the file, +so the file must be truncated to zero length to discard +previous trace data. +If tracing points are being disabled (see KTROP_CLEAR below), +.Fa tracefile +may be NULL. +.Pp +The +.Fa ops +parameter specifies the requested ktrace operation. +The defined operations are: +.Bl -column KTRFLAG_DESCENDXXX -offset indent +.It "KTROP_SET Enable trace points specified in" +.Fa trpoints . +.It "KTROP_CLEAR Disable trace points specified in +.Fa trpoints . +.It "KTROP_CLEARFILE Stop all tracing." +.It "KTRFLAG_DESCEND The tracing change should apply to the" +specified process and all its current children. +.El +.Pp +The +.Fa trpoints +parameter specifies the trace points of interest. +The defined trace points are: +.Bl -column KTRFAC_SYSCALLXXX -offset indent +.It "KTRFAC_SYSCALL Trace system calls." +.It "KTRFAC_SYSRET Trace return values from system calls." +.It "KTRFAC_NAMEI Trace name lookup operations." +.It "KTRFAC_GENIO Trace all I/O (note that this option can" +generate much output). +.It "KTRFAC_PSIG Trace posted signals." +.It "KTRFAC_CSW Trace context switch points." +.It "KTRFAC_INHERIT Inherit tracing to future children." +.El +.Pp +Each tracing event outputs a record composed of a generic header +followed by a trace point specific structure. +The generic header is: +.Bd -literal +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; +}; +.Ed +.Pp +The +.Va ktr_len +field specifies the length of the +.Va ktr_type +data that follows this header. +The +.Va ktr_pid +and +.Va ktr_comm +fields specify the process and command generating the record. +The +.Va ktr_time +field gives the time (with microsecond resolution) +that the record was generated. +The +.Va ktr_buf +is an internal kernel pointer and is not useful. +.Pp +The generic header is followed by +.Va ktr_len +bytes of a +.Va ktr_type +record. +The type specific records are defined in the +.Aq Pa sys/ktrace.h +include file. +.Sh RETURN VALUES +.Rv -std ktrace +.Sh ERRORS +.Fn Ktrace +will fail if: +.Bl -tag -width Er +.It Bq Er ENOTDIR +A component of the path prefix is not a directory. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded 255 characters, +or an entire path name exceeded 1023 characters. +.It Bq Er ENOENT +The named tracefile does not exist. +.It Bq Er EACCES +Search permission is denied for a component of the path prefix. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating the pathname. +.It Bq Er EIO +An I/O error occurred while reading from or writing to the file system. +.It Bq Er ENOSYS +The kernel was not compiled with +.Nm +support. +.El +.Sh SEE ALSO +.Xr kdump 1 , +.Xr ktrace 1 +.Sh HISTORY +A +.Fn ktrace +function call first appeared in +.Bx 4.4 . diff --git a/bsd/man/man2/lchown.2 b/bsd/man/man2/lchown.2 new file mode 100644 index 000000000..f0a5635ae --- /dev/null +++ b/bsd/man/man2/lchown.2 @@ -0,0 +1 @@ +.so man2/chown.2 diff --git a/bsd/man/man2/link.2 b/bsd/man/man2/link.2 new file mode 100644 index 000000000..2a6f8b66c --- /dev/null +++ b/bsd/man/man2/link.2 @@ -0,0 +1,153 @@ +.\" $NetBSD: link.2,v 1.7 1995/02/27 12:34:01 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.\" @(#)link.2 8.3 (Berkeley) 1/12/94 +.\" +.Dd January 12, 1994 +.Dt LINK 2 +.Os BSD 4 +.Sh NAME +.Nm link +.Nd make a hard file link +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn link "const char *name1" "const char *name2" +.Sh DESCRIPTION +The +.Fn link +function call +atomically creates the specified directory entry (hard link) +.Fa name2 +with the attributes of the underlying object pointed at by +.Fa name1 +If the link is successful: the link count of the underlying object +is incremented; +.Fa name1 +and +.Fa name2 +share equal access and rights +to the +underlying object. +.Pp +If +.Fa name1 +is removed, the file +.Fa name2 +is not deleted and the link count of the +underlying object is +decremented. +.Pp +.Fa Name1 +must exist for the hard link to +succeed and +both +.Fa name1 +and +.Fa name2 +must be in the same file system. +As mandated by POSIX.1 +.Fa name1 +may not be a directory. +.Sh RETURN VALUES +Upon successful completion, a value of 0 is returned. Otherwise, +a value of -1 is returned and +.Va errno +is set to indicate the error. +.Sh ERRORS +.Fn Link +will fail and no link will be created if: +.Bl -tag -width Er +.It Bq Er ENOTDIR +A component of either path prefix is not a directory. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded +.Dv {NAME_MAX} +characters, or an entire path name exceeded +.Dv {PATH_MAX} +characters. +.It Bq Er ENOENT +A component of either path prefix does not exist. +.It Bq Er EACCES +A component of either path prefix denies search permission. +.It Bq Er EACCES +The requested link requires writing in a directory with a mode +that denies write permission. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating one of the pathnames. +.It Bq Er ENOENT +The file named by +.Fa name1 +does not exist. +.It Bq Er EEXIST +The link named by +.Fa name2 +does exist. +.It Bq Er EPERM +The file named by +.Fa name1 +is a directory. +.It Bq Er EXDEV +The link named by +.Fa name2 +and the file named by +.Fa name1 +are on different file systems. +.It Bq Er ENOSPC +The directory in which the entry for the new link is being placed +cannot be extended because there is no space left on the file +system containing the directory. +.ne 3v +.It Bq Er EDQUOT +The directory in which the entry for the new link +is being placed cannot be extended because the +user's quota of disk blocks on the file system +containing the directory has been exhausted. +.It Bq Er EIO +An I/O error occurred while reading from or writing to +the file system to make the directory entry. +.It Bq Er EROFS +The requested link requires writing in a directory on a read-only file +system. +.It Bq Er EFAULT +One of the pathnames specified +is outside the process's allocated address space. +.El +.Sh SEE ALSO +.Xr symlink 2 , +.Xr unlink 2 +.Sh STANDARDS +The +.Fn link +function is expected to conform to +.St -p1003.1-88 . diff --git a/bsd/man/man2/listen.2 b/bsd/man/man2/listen.2 new file mode 100644 index 000000000..a44a951bd --- /dev/null +++ b/bsd/man/man2/listen.2 @@ -0,0 +1,104 @@ +.\" $OpenBSD: listen.2,v 1.2 1996/03/19 23:15:16 niklas Exp $ +.\" $NetBSD: listen.2,v 1.7 1996/02/16 20:38:45 phil Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)listen.2 8.2 (Berkeley) 12/11/93 +.\" +.Dd December 11, 1993 +.Dt LISTEN 2 +.Os BSD 4.2 +.Sh NAME +.Nm listen +.Nd listen for connections on a socket +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn listen "int s" "int backlog" +.Sh DESCRIPTION +To accept connections, a socket +is first created with +.Xr socket 2 , +a willingness to accept incoming connections and +a queue limit for incoming connections are specified with +.Fn listen , +and then the connections are +accepted with +.Xr accept 2 . +The +.Fn listen +call applies only to sockets of type +.Dv SOCK_STREAM +or +.Dv SOCK_SEQPACKET. +.Pp +The +.Fa backlog +parameter defines the maximum length the queue of +pending connections may grow to. +If a connection +request arrives with the queue full the client may +receive an error with an indication of +.Er ECONNREFUSED , +or, if the underlying protocol supports retransmission, +the request may be ignored so that retries may succeed. +.Sh RETURN VALUES +A 0 return value indicates success; -1 indicates an error. +.Sh ERRORS +.Fn Listen +will fail if: +.Bl -tag -width Er +.It Bq Er EBADF +The argument +.Fa s +is not a valid descriptor. +.It Bq Er ENOTSOCK +The argument +.Fa s +is not a socket. +.It Bq Er EOPNOTSUPP +The socket is not of a type that supports the operation +.Fn listen . +.El +.Sh SEE ALSO +.Xr accept 2 , +.Xr connect 2 , +.Xr socket 2 +.Sh BUGS +The +.Fa backlog +is currently limited (silently) to 128. +.Sh HISTORY +The +.Fn listen +function call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/lseek.2 b/bsd/man/man2/lseek.2 new file mode 100644 index 000000000..09374f764 --- /dev/null +++ b/bsd/man/man2/lseek.2 @@ -0,0 +1,136 @@ +.\" $NetBSD: lseek.2,v 1.6 1995/02/27 12:34:09 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.\" @(#)lseek.2 8.3 (Berkeley) 4/19/94 +.\" +.Dd April 19, 1994 +.Dt LSEEK 2 +.Os BSD 4 +.Sh NAME +.Nm lseek +.Nd reposition read/write file offset +.Sh SYNOPSIS +.Fd #include +.Ft off_t +.Fn lseek "int fildes" "off_t offset" "int whence" +.Sh DESCRIPTION +The +.Fn lseek +function repositions the offset of the file descriptor +.Fa fildes +to the +argument +.Fa offset +according to the directive +.Fa whence. +The argument +.Fa fildes +must be an open +file descriptor. +.Fn Lseek +repositions the file pointer +.Fa fildes +as follows: +.Bl -item -offset indent +.It +If +.Fa whence +is +.Dv SEEK_SET , +the offset is set to +.Fa offset +bytes. +.It +If +.Fa whence +is +.Dv SEEK_CUR , +the offset is set to its current location plus +.Fa offset +bytes. +.It +If +.Fa whence +is +.Dv SEEK_END , +the offset is set to the size of the +file plus +.Fa offset +bytes. +.El +.Pp +The +.Fn lseek +function allows the file offset to be set beyond the end +of the existing end-of-file of the file. If data is later written +at this point, subsequent reads of the data in the gap return +bytes of zeros (until data is actually written into the gap). +.Pp +Some devices are incapable of seeking. The value of the pointer +associated with such a device is undefined. +.Sh RETURN VALUES +Upon successful completion, +.Fn lseek +returns the resulting offset location as measured in bytes from the +beginning of the file. +Otherwise, +a value of -1 is returned and +.Va errno +is set to indicate +the error. +.Sh ERRORS +.Fn Lseek +will fail and the file pointer will remain unchanged if: +.Bl -tag -width Er +.It Bq Er EBADF +.Em Fildes +is not an open file descriptor. +.It Bq Er ESPIPE +.Em Fildes +is associated with a pipe, socket, or FIFO. +.It Bq Er EINVAL +.Fa Whence +is not a proper value. +.El +.Sh SEE ALSO +.Xr dup 2 , +.Xr open 2 +.Sh BUGS +This document's use of +.Fa whence +is incorrect English, but is maintained for historical reasons. +.Sh STANDARDS +The +.Fn lseek +function conforms to +.St -p1003.1-88 . diff --git a/bsd/man/man2/lstat.2 b/bsd/man/man2/lstat.2 new file mode 100644 index 000000000..b1a86c195 --- /dev/null +++ b/bsd/man/man2/lstat.2 @@ -0,0 +1 @@ +.so man2/stat.2 diff --git a/bsd/man/man2/madvise.2 b/bsd/man/man2/madvise.2 new file mode 100644 index 000000000..9f5938267 --- /dev/null +++ b/bsd/man/man2/madvise.2 @@ -0,0 +1,145 @@ +.\" $NetBSD: madvise.2,v 1.7 1995/12/27 21:17:02 jtc Exp $ +.\" +.\" Copyright (c) 1991, 1993 +.\" 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. +.\" +.\" @(#)madvise.2 8.1 (Berkeley) 6/9/93 +.\" +.Dd June 9, 1993 +.Dt MADVISE 2 +.Os +.Sh NAME +.Nm madvise +.Nd give advice about use of memory +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn madvise "caddr_t addr" "size_t len" "int behav" +.Ft int +.Fn posix_madvise "caddr_t addr" "size_t len" "int behav" +.Sh DESCRIPTION +The +.Fn madvise +system call allows a process that has knowledge of its memory behavior to describe it to the system. The advice passed in may be used by the system to alter its virtual memory paging strategy. This advice may improve application and system performance. The behavior specified in +.Fa behav +can only be one of the following values: +.Pp +.Bl -tag -width MADV_SEQUENTIAL +.It Dv MADV_NORMAL +Indicates that the application has no advice to give on its behavior in the specifed address range. This is the system default behavior. This is used with +.Fn madvise +system call. +.It Dv POSIX_MADV_NORMAL +Same as MADV_NORMAL but used with +.Fn posix_madvise +system call. +.It Dv MADV_SEQUENTIAL +Indicates that the application expects to access this address range in a sequential manner. This is used with +.Fn madvise +system call. +.It Dv POSIX_MADV_SEQUENTIAL +Same as MADV_SEQUENTIAL but used with +.Fn posix_madvise +system call. +.It Dv MADV_RANDOM +Indicates that the application expects to access this address range in a random manner. This is used with +.Fn madvise +system call. +.It Dv POSIX_MADV_RANDOM +Same as MADV_RANDOM but used with +.Fn posix_madvise +system call. +.It Dv MADV_WILLNEED +Indicates that the application expects to access this address range soon. This is used with +.Fn madvise +system call. +.It Dv POSIX_MADV_WILLNEED +Same as MADV_WILLNEED but used with +.Fn posix_madvise +system call. +.It Dv MADV_DONTNEED +Indicates that the application is not expecting to access this address range soon. This is used with +.Fn madvise +system call. +.It Dv POSIX_MADV_DONTNEED +Same as MADV_DONTNEED but used with +.Fn posix_madvise +system call. +.It Dv MADV_FREE +Indicates that the application will not need the information contained in this address range so the pages may be reused right away. The address range will remain valid. This is used with +.Fn madvise +system call. +.El + +The +.Fn posix_madvise +behaves same as +.Fn madvise +except that it uses values with POSIX_ prefix for the +.Fa behav +system call argument. +.Sh RETURN VALUES +Upon successful completion, +a value of 0 is returned. +Otherwise, a value of -1 is returned and +.Va errno +is set to indicate the error. +.Sh ERRORS +.Fn madvise +fails if one or more of the following are true: +.Bl -tag -width Er +.It Bq Er EINVAL +The value of +.Fa behav +is incorrect. +.It Bq Er ENOMEM +The virtual address range specified by the +.Fa addr +and +.Fa len +are outside the range allowed for the address space. +.It Bq Er EINVAL +The address range includes unallocated regions. +.El +.Sh SEE ALSO +.Xr mincore 2 , +.Xr minherit 2 , +.Xr mprotect 2 , +.Xr msync 2 , +.Xr munmap 2 +.Sh HISTORY +The +.Nm madvise +function first appeared in 4.4BSD. +The +.Nm posix_madvise +function is part of IEEE 1003.1-2001 and was first implemented in Mac OS X 10.2. diff --git a/bsd/man/man2/mincore.2 b/bsd/man/man2/mincore.2 new file mode 100644 index 000000000..05fb3d6eb --- /dev/null +++ b/bsd/man/man2/mincore.2 @@ -0,0 +1,73 @@ +.\" $NetBSD: mincore.2,v 1.7 1995/10/12 15:41:05 jtc Exp $ +.\" +.\" Copyright (c) 1991, 1993 +.\" 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. +.\" +.\" @(#)mincore.2 8.1 (Berkeley) 6/9/93 +.\" +.Dd June 9, 1993 +.Dt MINCORE 2 +.Os +.Sh NAME +.Nm mincore +.Nd determine residency of memory pages +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn mincore "caddr_t addr" "size_t len" "char *vec" +.Sh DESCRIPTION +The +.Fn mincore +system call +allows a process to obtain information about whether pages are +core resident. +Here the current core residency of the pages is returned +in the character array +.Fa vec , +with a value of 1 meaning that the page is in-core. +.Sh RETURN VALUES +Upon successful completion, +a value of 0 is returned. +Otherwise, a value of -1 is returned and +.Va errno +is set to indicate the error. +.Sh SEE ALSO +.Xr madvise 2 , +.Xr minherit 2 , +.Xr mlock 2 , +.Xr mprotect 2 , +.Xr msync 2 , +.Xr munmap 2 +.Sh HISTORY +The +.Fn mincore +function first appeared in 4.4BSD. diff --git a/bsd/man/man2/minherit.2 b/bsd/man/man2/minherit.2 new file mode 100644 index 000000000..5943caf37 --- /dev/null +++ b/bsd/man/man2/minherit.2 @@ -0,0 +1,67 @@ +.\" $Id: minherit.2,v 1.2 2002/03/13 00:18:19 lindak Exp $ +.\" +.\" Copyright (c) 1991, 1993 +.\" 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. +.\" +.\" @(#)minherit.2 8.1 (Berkeley) 6/9/93 +.\" +.Dd June 9, 1993 +.Dt MINHERIT 2 +.Os +.Sh NAME +.Nm minherit +.Nd control the inheritance of pages +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn minherit "caddr_t addr" "size_t len" "int inherit" +.Sh DESCRIPTION +The +.Fn minherit +system call +changes the specified pages to have the inheritance characteristic +.Fa inherit , +which can be set to VM_INHERIT_NONE, VM_INHERIT_COPY, or VM_INHERIT_SHARE. +Not all implementations will guarantee that the inheritance characteristic +can be set on a page basis; +the granularity of changes may be as large as an entire region. +.Sh SEE ALSO +.Xr madvise 2 , +.Xr mincore 2 , +.Xr mprotect 2 , +.Xr msync 2 , +.Xr munmap 2 +.Sh HISTORY +The +.Fn minherit +function first appeared in +.Bx Open . diff --git a/bsd/man/man2/mkdir.2 b/bsd/man/man2/mkdir.2 new file mode 100644 index 000000000..dd305fb0d --- /dev/null +++ b/bsd/man/man2/mkdir.2 @@ -0,0 +1,114 @@ +.\" $NetBSD: mkdir.2,v 1.8 1995/02/27 12:34:22 cgd Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)mkdir.2 8.2 (Berkeley) 12/11/93 +.\" +.Dd December 11, 1993 +.Dt MKDIR 2 +.Os BSD 4.2 +.Sh NAME +.Nm mkdir +.Nd make a directory file +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn mkdir "const char *path" "mode_t mode" +.Sh DESCRIPTION +The directory +.Fa path +is created with the access permissions specified by +.Fa mode +and restricted by the +.Xr umask 2 +of the calling process. +.Pp +The directory's owner ID is set to the process's effective user ID. +The directory's group ID is set to that of the parent directory in +which it is created. +.Sh RETURN VALUES +A 0 return value indicates success. A -1 return value +indicates an error, and an error code is stored in +.Va errno . +.Sh ERRORS +.Fn Mkdir +will fail and no directory will be created if: +.Bl -tag -width Er +.It Bq Er ENOTDIR +A component of the path prefix is not a directory. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded +.Dv {NAME_MAX} +characters, or an entire path name exceeded +.Dv {PATH_MAX} +characters. +.It Bq Er ENOENT +A component of the path prefix does not exist. +.It Bq Er EACCES +Search permission is denied for a component of the path prefix. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating the pathname. +.It Bq Er EROFS +The named file resides on a read-only file system. +.It Bq Er EEXIST +The named file exists. +.It Bq Er ENOSPC +The new directory cannot be created because there is no space left +on the file system that will contain the directory. +.It Bq Er ENOSPC +There are no free inodes on the file system on which the +directory is being created. +.It Bq Er EDQUOT +The new directory cannot be created because the user's +quota of disk blocks on the file system that will +contain the directory has been exhausted. +.It Bq Er EDQUOT +The user's quota of inodes on the file system on +which the directory is being created has been exhausted. +.It Bq Er EIO +An I/O error occurred while making the directory entry or allocating the inode. +.It Bq Er EIO +An I/O error occurred while reading from or writing to the file system. +.It Bq Er EFAULT +.Fa Path +points outside the process's allocated address space. +.El +.Sh SEE ALSO +.Xr chmod 2 , +.Xr stat 2 , +.Xr umask 2 +.Sh STANDARDS +The +.Fn mkdir +function conforms to +.St -p1003.1-88 . diff --git a/bsd/man/man2/mkfifo.2 b/bsd/man/man2/mkfifo.2 new file mode 100644 index 000000000..af5d7615f --- /dev/null +++ b/bsd/man/man2/mkfifo.2 @@ -0,0 +1,124 @@ +.\" $NetBSD: mkfifo.2,v 1.8 1995/02/27 12:34:27 cgd Exp $ +.\" +.\" Copyright (c) 1990, 1991, 1993 +.\" 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. +.\" +.\" @(#)mkfifo.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt MKFIFO 2 +.Os +.Sh NAME +.Nm mkfifo +.Nd make a fifo file +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn mkfifo "const char *path" "mode_t mode" +.Sh DESCRIPTION +.Fn Mkfifo +creates a new fifo file with name +.Fa path . +The access permissions are +specified by +.Fa mode +and restricted by the +.Xr umask 2 +of the calling process. +.Pp +The fifo's owner ID is set to the process's effective user ID. +The fifo's group ID is set to that of the parent directory in +which it is created. +.Sh RETURN VALUES +A 0 return value indicates success. A -1 return value +indicates an error, and an error code is stored in +.Va errno . +.Sh ERRORS +.Fn Mkfifo +will fail and no fifo will be created if: +.Bl -tag -width Er +.It Bq Er EOPNOTSUPP +The kernel has not been configured to support fifo's. +.It Bq Er ENOTDIR +A component of the path prefix is not a directory. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded +.Dv {NAME_MAX} +characters, or an entire path name exceeded +.Dv {PATH_MAX} +characters. +.It Bq Er ENOENT +A component of the path prefix does not exist. +.It Bq Er EACCES +Search permission is denied for a component of the path prefix. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating the pathname. +.It Bq Er EROFS +The named file resides on a read-only file system. +.It Bq Er EEXIST +The named file exists. +.It Bq Er ENOSPC +The directory in which the entry for the new fifo is being placed +cannot be extended because there is no space left on the file +system containing the directory. +.It Bq Er ENOSPC +There are no free inodes on the file system on which the +fifo is being created. +.It Bq Er EDQUOT +The directory in which the entry for the new fifo +is being placed cannot be extended because the +user's quota of disk blocks on the file system +containing the directory has been exhausted. +.It Bq Er EDQUOT +The user's quota of inodes on the file system on +which the fifo is being created has been exhausted. +.It Bq Er EIO +An +.Tn I/O +error occurred while making the directory entry or allocating the inode. +.It Bq Er EIO +An +.Tn I/O +error occurred while reading from or writing to the file system. +.It Bq Er EFAULT +.Fa Path +points outside the process's allocated address space. +.El +.Sh SEE ALSO +.Xr chmod 2 , +.Xr stat 2 , +.Xr umask 2 +.Sh STANDARDS +The +.Nm mkfifo +function call conforms to +.St -p1003.1-88 . diff --git a/bsd/man/man2/mknod.2 b/bsd/man/man2/mknod.2 new file mode 100644 index 000000000..e92dd449f --- /dev/null +++ b/bsd/man/man2/mknod.2 @@ -0,0 +1,129 @@ +.\" $NetBSD: mknod.2,v 1.6 1995/02/27 12:34:33 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.\" @(#)mknod.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt MKNOD 2 +.Os BSD 4 +.Sh NAME +.Nm mknod +.Nd make a special file node +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn mknod "const char *path" "mode_t mode" "dev_t dev" +.Sh DESCRIPTION +The device special file +.Fa path +is created with the major and minor +device numbers extracted from +.Fa mode. +The access permissions of +.Fa path +are descendant from the +.Xr umask 2 +of the parent process. +.Pp +If +.Fa mode +indicates a block or character special file, +.Fa dev +is a configuration dependent specification of a character or block +I/O device and the superblock of the device. If +.Fa mode +does not indicate a block special or character special device, +.Fa dev +is ignored. +.Pp +.Fn Mknod +requires super-user privileges. +.Sh RETURN VALUES +Upon successful completion a value of 0 is returned. +Otherwise, a value of -1 is returned and +.Va errno +is set to indicate the error. +.Sh ERRORS +.Fn Mknod +will fail and the file will be not created if: +.Bl -tag -width Er +.It Bq Er ENOTDIR +A component of the path prefix is not a directory. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded +.Dv {NAME_MAX} +characters, or an entire path name exceeded +.Dv {PATH_MAX} +characters. +.It Bq Er ENOENT +A component of the path prefix does not exist. +.It Bq Er EACCES +Search permission is denied for a component of the path prefix. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating the pathname. +.It Bq Er EPERM +The process's effective user ID is not super-user. +.It Bq Er EIO +An I/O error occurred while making the directory entry or allocating the inode. +.It Bq Er ENOSPC +The directory in which the entry for the new node is being placed +cannot be extended because there is no space left on the file +system containing the directory. +.It Bq Er ENOSPC +There are no free inodes on the file system on which the +node is being created. +.It Bq Er EDQUOT +The directory in which the entry for the new node +is being placed cannot be extended because the +user's quota of disk blocks on the file system +containing the directory has been exhausted. +.It Bq Er EDQUOT +The user's quota of inodes on the file system on +which the node is being created has been exhausted. +.It Bq Er EROFS +The named file resides on a read-only file system. +.It Bq Er EEXIST +The named file exists. +.It Bq Er EFAULT +.Fa Path +points outside the process's allocated address space. +.El +.Sh SEE ALSO +.Xr chmod 2 , +.Xr stat 2 , +.Xr umask 2 +.Sh HISTORY +A +.Fn mknod +function call appeared in +.At v6 . diff --git a/bsd/man/man2/mlock.2 b/bsd/man/man2/mlock.2 new file mode 100644 index 000000000..be33648c5 --- /dev/null +++ b/bsd/man/man2/mlock.2 @@ -0,0 +1,165 @@ +.\" $NetBSD: mlock.2,v 1.3 1995/06/24 10:42:03 cgd Exp $ +.\" +.\" Copyright (c) 1993 +.\" 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. +.\" +.\" @(#)mlock.2 8.2 (Berkeley) 12/11/93 +.\" +.Dd June 2, 1993 +.Dt MLOCK 2 +.Os +.Sh NAME +.Nm mlock , +.Nm munlock +.Nd lock (unlock) physical pages in memory +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn mlock "caddr_t addr" "size_t len" +.Ft int +.Fn munlock "caddr_t addr" "size_t len" +.Sh DESCRIPTION +The +.Nm mlock +system call +locks into memory the physical pages associated with the virtual address +range starting at +.Fa addr +for +.Fa len +bytes. +The +.Nm munlock +call unlocks pages previously locked by one or more +.Nm mlock +calls. +For both, the +.Fa addr +parameter should be aligned to a multiple of the page size. +If the +.Fa len +parameter is not a multiple of the page size, it will be rounded up +to be so. +The entire range must be allocated. +.Pp +After an +.Nm mlock +call, the indicated pages will cause neither a non-resident page +nor address-translation fault until they are unlocked. +They may still cause protection-violation faults or TLB-miss faults on +architectures with software-managed TLBs. +The physical pages remain in memory until all locked mappings for the pages +are removed. +Multiple processes may have the same physical pages locked via their own +virtual address mappings. +A single process may likewise have pages multiply-locked via different virtual +mappings of the same pages or via nested +.Nm mlock +calls on the same address range. +Unlocking is performed explicitly by +.Nm munlock +or implicitly by a call to +.Nm munmap +which deallocates the unmapped address range. +Locked mappings are not inherited by the child process after a +.Xr fork 2 . +.Pp +Since physical memory is a potentially scarce resource, processes are +limited in how much they can lock down. +A single process can +.Nm mlock +the minimum of +a system-wide ``wired pages'' limit and +the per-process +.Li RLIMIT_MEMLOCK +resource limit. +.Sh RETURN VALUES +A return value of 0 indicates that the call +succeeded and all pages in the range have either been locked or unlocked. +A return value of -1 indicates an error occurred and the locked +status of all pages in the range remains unchanged. +In this case, the global location +.Va errno +is set to indicate the error. +.Sh ERRORS +.Fn Mlock +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The address given is not page aligned or the length is negative. +.It Bq Er EAGAIN +Locking the indicated range would exceed either the system or per-process +limit for locked memory. +.It Bq Er ENOMEM +Some portion of the indicated address range is not allocated. +There was an error faulting/mapping a page. +.El +.Fn Munlock +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The address given is not page aligned or the length is negative. +.It Bq Er ENOMEM +Some portion of the indicated address range is not allocated. +Some portion of the indicated address range is not locked. +.El +.Sh "SEE ALSO" +.Xr fork 2 , +.Xr mincore 2 , +.Xr minherit 2 , +.Xr mmap 2 , +.Xr munmap 2 , +.Xr setrlimit 2 , +.Xr getpagesize 3 +.Sh BUGS +Unlike The Sun implementation, multiple +.Nm mlock +calls on the same address range require the corresponding number of +.Nm munlock +calls to actually unlock the pages, i.e. +.Nm mlock +nests. +This should be considered a consequence of the implementation +and not a feature. +.Pp +The per-process resource limit is a limit on the amount of virtual +memory locked, while the system-wide limit is for the number of locked +physical pages. +Hence a process with two distinct locked mappings of the same physical page +counts as 2 pages against the per-process limit and as only a single page +in the system limit. +.Sh HISTORY +The +.Fn mlock +and +.Fn munlock +functions first appeared in 4.4BSD. diff --git a/bsd/man/man2/mmap.2 b/bsd/man/man2/mmap.2 new file mode 100644 index 000000000..7038690f1 --- /dev/null +++ b/bsd/man/man2/mmap.2 @@ -0,0 +1,207 @@ +.\" $NetBSD: mmap.2,v 1.5 1995/06/24 10:48:59 cgd Exp $ +.\" +.\" Copyright (c) 1991, 1993 +.\" 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. +.\" +.\" @(#)mmap.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt MMAP 2 +.Os BSD 4 +.Sh NAME +.Nm mmap +.Nd map files or devices into memory +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft void * +.Fn mmap "void *addr" "size_t len" "int prot" "int flags" "int fd" "off_t offset" +.Sh DESCRIPTION +The +.Nm mmap +function causes the pages starting at +.Fa addr +and continuing for at most +.Fa len +bytes to be mapped from the object described by +.Fa fd , +starting at byte offset +.Fa offset . +If +.Fa offset +or +.Fa len +is not a multiple of the pagesize, the mapped region may extend past the +specified range. +.Pp +If +.Fa addr +is non-zero, it is used as a hint to the system. +(As a convenience to the system, the actual address of the region may differ +from the address supplied.) +If +.Fa addr +is zero, an address will be selected by the system. +The actual starting address of the region is returned. +A successful +.Fa mmap +deletes any previous mapping in the allocated address range. +.Pp +The protections (region accessibility) are specified in the +.Fa prot +argument by +.Em or Ns 'ing +the following values: +.Pp +.Bl -tag -width MAP_FIXEDX +.It Dv PROT_EXEC +Pages may be executed. +.It Dv PROT_READ +Pages may be read. +.It Dv PROT_WRITE +Pages may be written. +.El +.Pp +The +.Fa flags +parameter specifies the type of the mapped object, mapping options and +whether modifications made to the mapped copy of the page are private +to the process or are to be shared with other references. +Sharing, mapping type and options are specified in the +.Fa flags +argument by +.Em or Ns 'ing +the following values: +.Pp +.Bl -tag -width MAP_FIXEDX +.It Dv MAP_ANON +Map anonymous memory not associated with any specific file. +The file descriptor used for creating +.Dv MAP_ANON +regions is used only for +naming, and may be specified as \-1 if no name is associated with the +region. +.It Dv MAP_FILE +Mapped from a regular file or character-special device memory. (This is +the default mapping type, and need not be specified.) +.It Dv MAP_FIXED +Do not permit the system to select a different address than the one +specified. +If the specified address cannot be used, +.Nm mmap +will fail. +If MAP_FIXED is specified, +.Fa addr +must be a multiple of the pagesize. +Use of this option is discouraged. +.It Dv MAP_HASSEMAPHORE +Notify the kernel that the region may contain semaphores and that special +handling may be necessary. +.It Dv MAP_INHERIT +Permit regions to be inherited across +.Xr exec 2 +system calls. +.It Dv MAP_PRIVATE +Modifications are private. +.It Dv MAP_SHARED +Modifications are shared. +.El +.Pp +The +.Xr close 2 +function does not unmap pages, see +.Xr munmap 2 +for further information. +.Pp +The current design does not allow a process to specify the location of +swap space. +In the future we may define an additional mapping type, +.Dv MAP_SWAP , +in which +the file descriptor argument specifies a file or device to which swapping +should be done. +.Sh RETURN VALUES +Upon successful completion, +.Nm mmap +returns a pointer to the mapped region. +Otherwise, a value of -1 is returned and +.Va errno +is set to indicate the error. +.Sh ERRORS +.Fn Mmap +will fail if: +.Bl -tag -width Er +.It Bq Er EACCES +The flag +.Dv PROT_READ +was specified as part of the +.Fa prot +parameter and +.Fa fd +was not open for reading. +The flags +.Dv PROT_WRITE +and +.Dv MAP_SHARED +were specified as part +of the +.Fa flags +and +.Fa prot +parameters and +.Fa fd +was not open for writing. +.It Bq Er EBADF +.Fa fd +is not a valid open file descriptor. +.It Bq Er EINVAL +.Dv MAP_FIXED +was specified and the +.I addr +parameter was not page aligned. +.Fa fd +did not reference a regular or character special file. +.It Bq Er ENOMEM +.Dv MAP_FIXED +was specified and the +.Fa addr +parameter wasn't available. +.Dv MAP_ANON +was specified and insufficient memory was available. +.El +.Sh "SEE ALSO" +.Xr getpagesize 2 , +.Xr msync 2 , +.Xr munmap 2 , +.Xr mprotect 2 , +.Xr madvise 2 , +.Xr mincore 2 , +.Xr mlock 2 diff --git a/bsd/man/man2/mount.2 b/bsd/man/man2/mount.2 new file mode 100644 index 000000000..7d6bac642 --- /dev/null +++ b/bsd/man/man2/mount.2 @@ -0,0 +1,339 @@ +.\" $OpenBSD: mount.2,v 1.6 1997/03/09 19:41:16 millert Exp $ +.\" $NetBSD: mount.2,v 1.12 1996/02/29 23:47:48 jtc Exp $ +.\" +.\" Copyright (c) 1980, 1989, 1993 +.\" 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. +.\" +.\" @(#)mount.2 8.2 (Berkeley) 12/11/93 +.\" +.Dd December 11, 1993 +.Dt MOUNT 2 +.Os BSD 4 +.Sh NAME +.Nm mount , +.Nm unmount +.Nd mount or dismount a filesystem +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn mount "const char *type" "const char *dir" "int flags" "void *data" +.Ft int +.Fn unmount "const char *dir" "int flags" +.Sh DESCRIPTION +The +.Fn mount +function grafts +a filesystem object onto the system file tree +at the point +.Ar dir . +The argument +.Ar data +describes the filesystem object to be mounted. +The argument +.Ar type +tells the kernel how to interpret +.Ar data +(See +.Ar type +below). +The contents of the filesystem +become available through the new mount point +.Ar dir . +Any files in +.Ar dir +at the time +of a successful mount are swept under the carpet so to speak, and +are unavailable until the filesystem is unmounted. +.Pp +The following +.Ar flags +may be specified to +suppress default semantics which affect filesystem access. +.Bl -tag -width MNT_SYNCHRONOUS +.It Dv MNT_RDONLY +The filesystem should be treated as read-only; +Even the super-user may not write on it. +.It Dv MNT_NOATIME +Do not update the access time on files in the filesystem unless +the modification or status change times are also being updated. +.It Dv MNT_NOEXEC +Do not allow files to be executed from the filesystem. +.It Dv MNT_NOSUID +Do not honor setuid or setgid bits on files when executing them. +.It Dv MNT_NODEV +Do not interpret special files on the filesystem. +.It Dv MNT_UNION +Union with underlying filesystem instead of obscuring it. +.It Dv MNT_SYNCHRONOUS +All I/O to the filesystem should be done synchronously. +.El +.Pp +The flag +.Dv MNT_UPDATE +indicates that the mount command is being applied +to an already mounted filesystem. +This allows the mount flags to be changed without requiring +that the filesystem be unmounted and remounted. +Some filesystems may not allow all flags to be changed. +For example, +most filesystems will not allow a change from read-write to read-only. +.Pp +The +.Fa type +argument defines the type of the filesystem. +The types of filesystems known to the system are defined in +.Aq Pa sys/mount.h . +.Fa Data +is a pointer to a structure that contains the type +specific arguments to mount. +The currently supported types of filesystems and +their type specific data are: +.Pp +.Dv MOUNT_FFS +.Bd -literal -offset indent -compact +struct ufs_args { + char *fspec; /* block special file to mount */ + struct export_args export; /* network export information */ +}; +.Ed +.Pp +.Dv MOUNT_NFS +.Bd -literal -offset indent -compact +struct nfs_args { + int version; /* args structure version */ + struct sockaddr *addr; /* file server address */ + int addrlen; /* length of address */ + int sotype; /* Socket type */ + int proto; /* and Protocol */ + u_char *fh; /* File handle to be mounted */ + int fhsize; /* Size, in bytes, of fh */ + int flags; /* flags */ + int wsize; /* write size in bytes */ + int rsize; /* read size in bytes */ + int readdirsize; /* readdir size in bytes */ + int timeo; /* initial timeout in .1 secs */ + int retrans; /* times to retry send */ + int maxgrouplist; /* Max. size of group list */ + int readahead; /* # of blocks to readahead */ + int leaseterm; /* Term (sec) of lease */ + int deadthresh; /* Retrans threshold */ + char *hostname; /* server's name */ +}; +.Ed +.Pp +.Dv MOUNT_MFS +.Bd -literal -offset indent -compact +struct mfs_args { + char *fspec; /* name to export for statfs */ + struct export_args export; /* if we can export an MFS */ + caddr_t base; /* base of filesystem in mem */ + u_long size; /* size of filesystem */ +}; +.Ed +.Pp +The +.Fn umount +function call disassociates the filesystem from the specified +mount point +.Fa dir . +.Pp +The +.Fa flags +argument may specify +.Dv MNT_FORCE +to specify that the filesystem should be forcibly unmounted even if files are +still active. +Active special devices continue to work, +but any further accesses to any other active files result in errors +even if the filesystem is later remounted. +.Sh RETURN VALUES +The +.Fn mount +returns the value 0 if the mount was successful, otherwise -1 is returned +and the variable +.Va errno +is set to indicate the error. +.Pp +.Nm Umount +returns the value 0 if the umount succeeded; otherwise -1 is returned +and the variable +.Va errno +is set to indicate the error. +.Sh ERRORS +.Fn Mount +will fail when one of the following occurs: +.Bl -tag -width [ENAMETOOLONG] +.It Bq Er EPERM +The caller is not the super-user. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded +.Dv {NAME_MAX} +characters, or an entire path name exceeded +.Dv {PATH_MAX} +characters. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating a pathname. +.It Bq Er ENOENT +A component of +.Fa dir +does not exist. +.It Bq Er ENOTDIR +A component of +.Ar name +is not a directory, +or a path prefix of +.Ar special +is not a directory. +.It Bq Er EINVAL +A pathname contains a character with the high-order bit set. +.It Bq Er EBUSY +Another process currently holds a reference to +.Fa dir . +.It Bq Er EFAULT +.Fa Dir +points outside the process's allocated address space. +.El +.Pp +The following errors can occur for a +.Em ufs +filesystem mount: +.Bl -tag -width [ENOTBLK] +.It Bq Er ENODEV +A component of ufs_args +.Ar fspec +does not exist. +.It Bq Er ENOTBLK +.Ar Fspec +is not a block device. +.It Bq Er ENXIO +The major device number of +.Ar fspec +is out of range (this indicates no device driver exists +for the associated hardware). +.It Bq Er EBUSY +.Ar Fspec +is already mounted. +.It Bq Er EMFILE +No space remains in the mount table. +.It Bq Er EINVAL +The super block for the filesystem had a bad magic +number or an out of range block size. +.It Bq Er ENOMEM +Not enough memory was available to read the cylinder +group information for the filesystem. +.It Bq Er EIO +An I/O error occurred while reading the super block or +cylinder group information. +.It Bq Er EFAULT +.Ar Fspec +points outside the process's allocated address space. +.El +.Pp +The following errors can occur for a +.Em nfs +filesystem mount: +.Bl -tag -width [ETIMEDOUT] +.It Bq Er ETIMEDOUT +.Em Nfs +timed out trying to contact the server. +.It Bq Er EFAULT +Some part of the information described by nfs_args +points outside the process's allocated address space. +.El +.Pp +The following errors can occur for a +.Em mfs +filesystem mount: +.Bl -tag -width [EMFILE] +.It Bq Er EMFILE +No space remains in the mount table. +.It Bq Er EINVAL +The super block for the filesystem had a bad magic +number or an out of range block size. +.It Bq Er ENOMEM +Not enough memory was available to read the cylinder +group information for the filesystem. +.It Bq Er EIO +A paging error occurred while reading the super block or +cylinder group information. +.It Bq Er EFAULT +.Em Name +points outside the process's allocated address space. +.El +.Pp +.Nm Umount +may fail with one of the following errors: +.Bl -tag -width [ENAMETOOLONG] +.It Bq Er EPERM +The caller is not the super-user. +.It Bq Er ENOTDIR +A component of the path is not a directory. +.It Bq Er EINVAL +The pathname contains a character with the high-order bit set. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded +.Dv {NAME_MAX} +characters, or an entire path name exceeded +.Dv {PATH_MAX} +characters. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating the pathname. +.It Bq Er EINVAL +The requested directory is not in the mount table. +.It Bq Er EBUSY +A process is holding a reference to a file located +on the filesystem. +.It Bq Er EIO +An I/O error occurred while writing cached filesystem information. +.It Bq Er EFAULT +.Fa Dir +points outside the process's allocated address space. +.El +.Pp +A +.Em ufs +or +.Em mfs +mount can also fail if the maximum number of filesystems are currently +mounted. +.Sh SEE ALSO +.Xr mount 8 , +.Xr umount 8 , +.Xr mfs 8 +.Sh BUGS +Some of the error codes need translation to more obvious messages. +.Sh HISTORY +.Fn Mount +and +.Fn umount +function calls appeared in +.At v6 . diff --git a/bsd/man/man2/mprotect.2 b/bsd/man/man2/mprotect.2 new file mode 100644 index 000000000..4870751bb --- /dev/null +++ b/bsd/man/man2/mprotect.2 @@ -0,0 +1,69 @@ +.\" $NetBSD: mprotect.2,v 1.6 1995/10/12 15:41:08 jtc Exp $ +.\" +.\" Copyright (c) 1991, 1993 +.\" 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. +.\" +.\" @(#)mprotect.2 8.1 (Berkeley) 6/9/93 +.\" +.Dd June 9, 1993 +.Dt MPROTECT 2 +.Os +.Sh NAME +.Nm mprotect +.Nd control the protection of pages +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn mprotect "caddr_t addr" "size_t len" "int prot" +.Sh DESCRIPTION +The +.Fn mprotect +system call +changes the specified pages to have protection +.Fa prot . +Not all implementations will guarantee protection on a page basis; +the granularity of protection changes may be as large as an entire region. +.Sh RETURN VALUES +Upon successful completion, +a value of 0 is returned. +Otherwise, a value of -1 is returned and +.Va errno +is set to indicate the error. +.Sh SEE ALSO +.Xr madvise 2 , +.Xr mincore 2 , +.Xr msync 2 , +.Xr munmap 2 +.Sh HISTORY +The +.Fn mprotect +function first appeared in 4.4BSD. diff --git a/bsd/man/man2/msync.2 b/bsd/man/man2/msync.2 new file mode 100644 index 000000000..831b8af34 --- /dev/null +++ b/bsd/man/man2/msync.2 @@ -0,0 +1,104 @@ +.\" Copyright (c) 1991, 1993 +.\" 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. +.\" +.\" @(#)msync.2 8.2 (Berkeley) 6/21/94 +.\" $FreeBSD: src/lib/libc/sys/msync.2,v 1.17 2000/04/21 09:41:53 phantom Exp $ +.\" +.Dd June 21, 1994 +.Dt MSYNC 2 +.Os +.Sh NAME +.Nm msync +.Nd synchronize a mapped region +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn msync "void *addr" "size_t len" "int flags" +.Sh DESCRIPTION +The +.Fn msync +system call +writes any modified pages back to the filesystem and updates +the file modification time. +If +.Fa len +is 0, all modified pages within the region containing +.Fa addr +will be flushed; +if +.Fa len +is non-zero, only those pages containing +.Fa addr +and +.Fa len-1 +succeeding locations will be examined. +The +.Fa flags +argument may be specified as follows: +.Bd -literal +MS_ASYNC Return immediately +MS_SYNC Perform synchronous writes +MS_INVALIDATE Invalidate all cached data +.Ed +.Sh RETURN VALUES +If any errors occur, -1 is returned and errno is set to indicate the +error. +Otherwise, a 0 value is returned. +.Sh ERRORS +.Fn msync +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +.Fa addr +is not a multiple of the hardware page size. +.It Bq Er EINVAL +.Fa len +is too large or negative. +.It Bq Er EINVAL +.Fa flags +was both MS_ASYNC and MS_INVALIDATE. +Only one of these flags is allowed. +.It Bq Er EIO +An I/O error occurred while writing to the file system. +.El +.Sh SEE ALSO +.Xr madvise 2 , +.Xr mincore 2 , +.Xr mprotect 2 , +.Xr munmap 2 +.Sh HISTORY +The +.Fn msync +function first appeared in +.Bx 4.4 . diff --git a/bsd/man/man2/munlock.2 b/bsd/man/man2/munlock.2 new file mode 100644 index 000000000..5e5b3c741 --- /dev/null +++ b/bsd/man/man2/munlock.2 @@ -0,0 +1 @@ +.so man2/mlock.2 diff --git a/bsd/man/man2/munmap.2 b/bsd/man/man2/munmap.2 new file mode 100644 index 000000000..ab097b704 --- /dev/null +++ b/bsd/man/man2/munmap.2 @@ -0,0 +1,83 @@ +.\" $NetBSD: munmap.2,v 1.5 1995/02/27 12:35:03 cgd Exp $ +.\" +.\" Copyright (c) 1991, 1993 +.\" 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. +.\" +.\" @(#)munmap.2 8.2 (Berkeley) 4/15/94 +.\" +.Dd April 15, 1994 +.Dt MUNMAP 2 +.Os +.Sh NAME +.Nm munmap +.Nd remove a mapping +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn munmap "caddr_t addr" "size_t len" +.Sh DESCRIPTION +The +.Fn munmap +system call +deletes the mappings for the specified address range, +and causes further references to addresses within the range +to generate invalid memory references. +.Sh RETURN VALUES +Upon successful completion, +.Nm munmap +returns zero. +Otherwise, a value of -1 is returned and +.Va errno +is set to indicate the error. +.Sh ERRORS +.Fn Munmap +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The +.Fa addr +parameter was not page aligned, the +.Fa len +parameter was negative, or +some part of the region being unmapped is not part of the currently +valid address space. +.Sh "SEE ALSO" +.Xr getpagesize 3 , +.Xr msync 2 , +.Xr munmap 2 , +.Xr mprotect 2 , +.Xr madvise 2 , +.Xr mincore 2 +.Sh HISTORY +The +.Fn munmap +function first appeared in 4.4BSD. diff --git a/bsd/man/man2/nfssvc.2 b/bsd/man/man2/nfssvc.2 new file mode 100644 index 000000000..297472162 --- /dev/null +++ b/bsd/man/man2/nfssvc.2 @@ -0,0 +1,240 @@ +.\" $NetBSD: nfssvc.2,v 1.6 1995/02/27 12:35:08 cgd Exp $ +.\" +.\" Copyright (c) 1989, 1991, 1993 +.\" 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. +.\" +.\" @(#)nfssvc.2 8.1 (Berkeley) 6/9/93 +.\" +.Dd June 9, 1993 +.Dt NFSSVC 2 +.Os +.Sh NAME +.Nm nfssvc +.Nd NFS services +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn nfssvc "int flags" "void *argstructp" +.Sh DESCRIPTION +The +.Fn nfssvc +function is used by the NFS daemons to pass information into and out +of the kernel and also to enter the kernel as a server daemon. +The +.Fa flags +argument consists of several bits that show what action is to be taken +once in the kernel and the +.Fa argstructp +points to one of three structures depending on which bits are set in +flags. +.Pp +On the client side, +.Xr nfsiod 8 +calls +.Fn nfssvc +with the +.Fa flags +argument set to +.Dv NFSSVC_BIOD +and +.Fa argstructp +set to +.Dv NULL +to enter the kernel as a block I/O server daemon. +For +.Nm NQNFS , +.Xr mount_nfs 8 +calls +.Fn nfssvc +with the +.Dv NFSSVC_MNTD +flag, optionally or'd with the flags +.Dv NFSSVC_GOTAUTH +and +.Dv NFSSVC_AUTHINFAIL +along with a pointer to a +.Bd -literal +struct nfsd_cargs { + char *ncd_dirp; /* Mount dir path */ + uid_t ncd_authuid; /* Effective uid */ + int ncd_authtype; /* Type of authenticator */ + int ncd_authlen; /* Length of authenticator string */ + char *ncd_authstr; /* Authenticator string */ +}; +.Ed +.sp +structure. +The initial call has only the +.Dv NFSSVC_MNTD +flag set to specify service for the mount point. +If the mount point is using Kerberos, then the +.Xr mount_nfs 8 +daemon will return from +.Fn nfssvc +with errno == ENEEDAUTH whenever the client side requires an ``rcmd'' +authentication ticket for the user. +.Xr Mount_nfs 8 +will attempt to get the Kerberos ticket, and if successful will call +.Fn nfssvc +with the flags +.Dv NFSSVC_MNTD +and +.Dv NFSSVC_GOTAUTH +after filling the ticket into the +ncd_authstr field +and +setting the ncd_authlen and ncd_authtype +fields of the nfsd_cargs structure. +If +.Xr mount_nfs 8 +failed to get the ticket, +.Fn nfssvc +will be called with the flags +.Dv NFSSVC_MNTD , +.Dv NFSSVC_GOTAUTH +and +.Dv NFSSVC_AUTHINFAIL +to denote a failed authentication attempt. +.Pp +On the server side, +.Fn nfssvc +is called with the flag +.Dv NFSSVC_NFSD +and a pointer to a +.Bd -literal +struct nfsd_srvargs { + struct nfsd *nsd_nfsd; /* Pointer to in kernel nfsd struct */ + uid_t nsd_uid; /* Effective uid mapped to cred */ + u_long nsd_haddr; /* Ip address of client */ + struct ucred nsd_cr; /* Cred. uid maps to */ + int nsd_authlen; /* Length of auth string (ret) */ + char *nsd_authstr; /* Auth string (ret) */ +}; +.Ed +.sp +to enter the kernel as an +.Xr nfsd 8 +daemon. +Whenever an +.Xr nfsd 8 +daemon receives a Kerberos authentication ticket, it will return from +.Fn nfssvc +with errno == ENEEDAUTH. +The +.Xr nfsd 8 +will attempt to authenticate the ticket and generate a set of credentials +on the server for the ``user id'' specified in the field nsd_uid. +This is done by first authenticating the Kerberos ticket and then mapping +the Kerberos principal to a local name and getting a set of credentials for +that user via. +.Xr getpwnam 3 +and +.Xr getgrouplist 3 . +If successful, the +.Xr nfsd 8 +will call +.Fn nfssvc +with the +.Dv NFSSVC_NFSD +and +.Dv NFSSVC_AUTHIN +flags set to pass the credential mapping in nsd_cr into the +kernel to be cached on the server socket for that client. +If the authentication failed, +.Xr nfsd 8 +calls +.Fn nfssvc +with the flags +.Dv NFSSVC_NFSD +and +.Dv NFSSVC_AUTHINFAIL +to denote an authentication failure. +.Pp +The master +.Xr nfsd 8 +server daemon calls +.Fn nfssvc +with the flag +.Dv NFSSVC_ADDSOCK +and a pointer to a +.Bd -literal +struct nfsd_args { + int sock; /* Socket to serve */ + caddr_t name; /* Client address for connection based sockets */ + int namelen; /* Length of name */ +}; +.Ed +.sp +to pass a server side +.Tn NFS +socket into the kernel for servicing by the +.Xr nfsd 8 +daemons. +.Sh RETURN VALUES +Normally +.Nm nfssvc +does not return unless the server +is terminated by a signal when a value of 0 is returned. +Otherwise, -1 is returned and the global variable +.Va errno +is set to specify the error. +.Sh ERRORS +.Bl -tag -width Er +.It Bq Er ENEEDAUTH +This special error value +is really used for authentication support, particularly Kerberos, +as explained above. +.It Bq Er EPERM +The caller is not the super-user. +.El +.Sh SEE ALSO +.Xr nfsd 8 , +.Xr mount_nfs 8 , +.Xr nfsiod 8 +.Sh HISTORY +The +.Nm nfssvc +function first appeared in 4.4BSD. +.Sh BUGS +The +.Nm nfssvc +system call is designed specifically for the +.Tn NFS +support daemons and as such is specific to their requirements. +It should really return values to indicate the need for authentication +support, since +.Dv ENEEDAUTH +is not really an error. +Several fields of the argument structures are assumed to be valid and +sometimes to be unchanged from a previous call, such that +.Nm nfssvc +must be used with extreme care. diff --git a/bsd/man/man2/open.2 b/bsd/man/man2/open.2 new file mode 100644 index 000000000..cf215d87d --- /dev/null +++ b/bsd/man/man2/open.2 @@ -0,0 +1,263 @@ +.\" $NetBSD: open.2,v 1.8 1995/02/27 12:35:14 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.\" @(#)open.2 8.2 (Berkeley) 11/16/93 +.\" +.Dd November 16, 1993 +.Dt OPEN 2 +.Os BSD 4 +.Sh NAME +.Nm open +.Nd open or create a file for reading or writing +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn open "const char *path" "int flags" "mode_t mode" +.Sh DESCRIPTION +The file name specified by +.Fa path +is opened +for reading and/or writing as specified by the +argument +.Fa flags +and the file descriptor returned to the calling process. +The +.Fa flags +argument may indicate the file is to be +created if it does not exist (by specifying the +.Dv O_CREAT +flag), in which case the file is created with mode +.Fa mode +as described in +.Xr chmod 2 +and modified by the process' umask value (see +.Xr umask 2 ) . +.Pp +The flags specified are formed by +.Em or Ns 'ing +the following values +.Pp +.Bd -literal -offset indent -compact +O_RDONLY open for reading only +O_WRONLY open for writing only +O_RDWR open for reading and writing +O_NONBLOCK do not block on open or for data to become available +O_APPEND append on each write +O_CREAT create file if it does not exist +O_TRUNC truncate size to 0 +O_EXCL error if create and file exists +O_SHLOCK atomically obtain a shared lock +O_EXLOCK atomically obtain an exclusive lock +.Ed +.Pp +Opening a file with +.Dv O_APPEND +set causes each write on the file +to be appended to the end. If +.Dv O_TRUNC +is specified and the +file exists, the file is truncated to zero length. +If +.Dv O_EXCL +is set with +.Dv O_CREAT +and the file already +exists, +.Fn open +returns an error. This may be used to +implement a simple exclusive access locking mechanism. +If +.Dv O_EXCL +is set and the last component of the pathname is +a symbolic link, +.Fn open +will fail even if the symbolic +link points to a non-existent name. +If the +.Dv O_NONBLOCK +flag is specified, do not wait for the device or file to be ready or +available. If the +.Fn open +call would result +in the process being blocked for some reason (e.g., waiting for +carrier on a dialup line), +.Fn open +returns immediately. +This flag also has the effect of making all subsequent I/O on the open file non-blocking. +.Pp +When opening a file, a lock with +.Xr flock 2 +semantics can be obtained by setting +.Dv O_SHLOCK +for a shared lock, or +.Dv O_EXLOCK +for an exclusive lock. +If creating a file with +.Dv O_CREAT , +the request for the lock will never fail +(provided that the underlying filesystem supports locking). +.Pp +If successful, +.Fn open +returns a non-negative integer, termed a file descriptor. +It returns -1 on failure. +The file pointer used to mark the current position within the +file is set to the beginning of the file. +.Pp +When a new file is created it is given the group of the directory +which contains it. +.Pp +The new descriptor is set to remain open across +.Xr execve +system calls; see +.Xr close 2 +and +.Xr fcntl 2 . +.Pp +The system imposes a limit on the number of file descriptors +open simultaneously by one process. +.Xr Getdtablesize 2 +returns the current system limit. +.Sh ERRORS +The named file is opened unless: +.Bl -tag -width Er +.It Bq Er ENOTDIR +A component of the path prefix is not a directory. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded +.Dv {NAME_MAX} +characters, or an entire path name exceeded +.Dv {PATH_MAX} +characters. +.It Bq Er ENOENT +.Dv O_CREAT +is not set and the named file does not exist. +.It Bq Er ENOENT +A component of the path name that must exist does not exist. +.It Bq Er EACCES +Search permission is denied for a component of the path prefix. +.It Bq Er EACCES +The required permissions (for reading and/or writing) +are denied for the given flags. +.It Bq Er EACCES +.Dv O_CREAT +is specified, +the file does not exist, +and the directory in which it is to be created +does not permit writing. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating the pathname. +.It Bq Er EISDIR +The named file is a directory, and the arguments specify +it is to be opened for writing. +.It Bq Er EROFS +The named file resides on a read-only file system, +and the file is to be modified. +.It Bq Er EMFILE +The process has already reached its limit for open file descriptors. +.It Bq Er ENFILE +The system file table is full. +.It Bq Er ENXIO +The named file is a character special or block +special file, and the device associated with this special file +does not exist. +.It Bq Er EINTR +The +.Fn open +operation was interrupted by a signal. +.It Bq Er EOPNOTSUPP +.Dv O_SHLOCK +or +.Dv O_EXLOCK +is specified but the underlying filesystem does not support locking. +.It Bq Er ENOSPC +.Dv O_CREAT +is specified, +the file does not exist, +and the directory in which the entry for the new file is being placed +cannot be extended because there is no space left on the file +system containing the directory. +.It Bq Er ENOSPC +.Dv O_CREAT +is specified, +the file does not exist, +and there are no free inodes on the file system on which the +file is being created. +.It Bq Er EDQUOT +.Dv O_CREAT +is specified, +the file does not exist, +and the directory in which the entry for the new file +is being placed cannot be extended because the +user's quota of disk blocks on the file system +containing the directory has been exhausted. +.It Bq Er EDQUOT +.Dv O_CREAT +is specified, +the file does not exist, +and the user's quota of inodes on the file system on +which the file is being created has been exhausted. +.It Bq Er EIO +An I/O error occurred while making the directory entry or +allocating the inode for +.Dv O_CREAT . +.It Bq Er ETXTBSY +The file is a pure procedure (shared text) file that is being +executed and the +.Fn open +call requests write access. +.It Bq Er EFAULT +.Fa Path +points outside the process's allocated address space. +.It Bq Er EEXIST +.Dv O_CREAT +and +.Dv O_EXCL +were specified and the file exists. +.It Bq Er EOPNOTSUPP +An attempt was made to open a socket (not currently implemented). +.El +.Sh SEE ALSO +.Xr chmod 2 , +.Xr close 2 , +.Xr dup 2 , +.Xr getdtablesize 2 , +.Xr lseek 2 , +.Xr read 2 , +.Xr write 2 , +.Xr umask 2 +.Sh HISTORY +An +.Fn open +function call appeared in +.At v6 . diff --git a/bsd/man/man2/pathconf.2 b/bsd/man/man2/pathconf.2 new file mode 100644 index 000000000..a947bd1e3 --- /dev/null +++ b/bsd/man/man2/pathconf.2 @@ -0,0 +1,165 @@ +.\" $NetBSD: pathconf.2,v 1.2 1995/02/27 12:35:22 cgd Exp $ +.\" +.\" Copyright (c) 1993 +.\" 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. +.\" +.\" @(#)pathconf.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt PATHCONF 2 +.Os BSD 4 +.Sh NAME +.Nm pathconf , +.Nm fpathconf +.Nd get configurable pathname variables +.Sh SYNOPSIS +.Fd #include +.Ft long +.Fn pathconf "const char *path" "int name" +.Ft long +.Fn fpathconf "int fd" "int name" +.Sh DESCRIPTION +.Pp +The +.Fn pathconf +and +.Fn fpathconf +functions provides a method for applications to determine the current +value of a configurable system limit or option variable associated +with a pathname or file descriptor. +.Pp +For +.Nm pathconf , +the +.Fa path +argument is the name of a file or directory. +For +.Nm fpathconf , +the +.Fa fd +argument is an open file descriptor. +The +.Fa name +argument specifies the system variable to be queried. +Symbolic constants for each name value are found in the include file +.Li . +.Pp +The available values are as follows: +.Pp +.Bl -tag -width "123456" +.Pp +.It Li _PC_LINK_MAX +The maximum file link count. +.It Li _PC_MAX_CANON +The maximum number of bytes in terminal canonical input line. +.It Li _PC_MAX_INPUT +The minimum maximum number of bytes for which space is available in +a terminal input queue. +.It Li _PC_NAME_MAX +The maximum number of bytes in a file name. +.It Li _PC_PATH_MAX +The maximum number of bytes in a pathname. +.It Li _PC_PIPE_BUF +The maximum number of bytes which will be written atomically to a pipe. +.It Li _PC_CHOWN_RESTRICTED +Return 1 if appropriate privileges are required for the +.Xr chown 2 +system call, otherwise 0. +.It Li _PC_NO_TRUNC +Return 1 if file names longer than KERN_NAME_MAX are truncated. +.It Li _PC_VDISABLE +Returns the terminal character disabling value. +.El +.Sh RETURN VALUES +If the call to +.Nm pathconf +or +.Nm fpathconf +is not successful, \-1 is returned and +.Va errno +is set appropriately. +Otherwise, if the variable is associated with functionality that does +not have a limit in the system, \-1 is returned and +.Va errno +is not modified. +Otherwise, the current variable value is returned. +.Sh ERRORS +If any of the following conditions occur, the +.Nm pathconf +and +.Nm fpathconf +functions shall return -1 and set +.Va errno +to the corresponding value. +.Bl -tag -width Er +.It Bq Er EINVAL +The value of the +.Fa name +argument is invalid. +.It Bq Er EINVAL +The implementation does not support an association of the variable +name with the associated file. +.El +.Fn Pathconf +will fail if: +.Bl -tag -width ENAMETOOLONGAA +.It Bq Er ENOTDIR +A component of the path prefix is not a directory. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded 255 characters, +or an entire path name exceeded 1023 characters. +.It Bq Er ENOENT +The named file does not exist. +.It Bq Er EACCES +Search permission is denied for a component of the path prefix. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating the pathname. +.It Bq Er EIO +An I/O error occurred while reading from or writing to the file system. +.El +.Pp +.Bl -tag -width [EFAULT] +.Fn Fpathconf +will fail if: +.It Bq Er EBADF +.Fa fd +is not a valid open file descriptor. +.It Bq Er EIO +An I/O error occurred while reading from or writing to the file system. +.El +.Sh SEE ALSO +.Xr sysctl 3 +.Sh HISTORY +The +.Nm pathconf +and +.Nm fpathconf +functions first appeared in 4.4BSD. diff --git a/bsd/man/man2/pipe.2 b/bsd/man/man2/pipe.2 new file mode 100644 index 000000000..759b9b9ef --- /dev/null +++ b/bsd/man/man2/pipe.2 @@ -0,0 +1,114 @@ +.\" $NetBSD: pipe.2,v 1.6 1995/02/27 12:35:27 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.\" @(#)pipe.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt PIPE 2 +.Os BSD 4 +.Sh NAME +.Nm pipe +.Nd create descriptor pair for interprocess communication +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn pipe "int *fildes" +.Sh DESCRIPTION +The +.Fn pipe +function +creates a +.Em pipe , +which is an object allowing +unidirectional data flow, +and allocates a pair of file descriptors. +The first descriptor connects to the +.Em read end +of the pipe, +and the second connects to the +.Em write end , +so that data written to +.Fa fildes[1] +appears on (i.e., can be read from) +.Fa fildes[0] . +This allows the output of one program to be +sent +to another program: +the source's standard output is set up to be +the write end of the pipe, +and the sink's standard input is set up to be +the read end of the pipe. +The pipe itself persists until all its associated descriptors are +closed. +.Pp +A pipe whose read or write end has been closed is considered +.Em widowed . +Writing on such a pipe causes the writing process to receive +a +.Dv SIGPIPE +signal. +Widowing a pipe is the only way to deliver end-of-file to a reader: +after the reader consumes any buffered data, reading a widowed pipe +returns a zero count. +.Sh RETURN VALUES +On successful creation of the pipe, zero is returned. Otherwise, +a value of -1 is returned and the variable +.Va errno +set to indicate the +error. +.Sh ERRORS +The +.Fn pipe +call will fail if: +.Bl -tag -width Er +.It Bq Er EMFILE +Too many descriptors are active. +.It Bq Er ENFILE +The system file table is full. +.It Bq Er EFAULT +The +.Fa fildes +buffer is in an invalid area of the process's address +space. +.El +.Sh SEE ALSO +.Xr sh 1 , +.Xr read 2 , +.Xr write 2 , +.Xr fork 2 , +.Xr socketpair 2 +.Sh HISTORY +A +.Fn pipe +function call appeared in +.At v6 . diff --git a/bsd/man/man2/posix_madvise.2 b/bsd/man/man2/posix_madvise.2 new file mode 100644 index 000000000..d0f9ea997 --- /dev/null +++ b/bsd/man/man2/posix_madvise.2 @@ -0,0 +1 @@ +.so man2/madvise.2 diff --git a/bsd/man/man2/pread.2 b/bsd/man/man2/pread.2 new file mode 100644 index 000000000..d5e1c8ac7 --- /dev/null +++ b/bsd/man/man2/pread.2 @@ -0,0 +1 @@ +.so man2/read.2 diff --git a/bsd/man/man2/profil.2 b/bsd/man/man2/profil.2 new file mode 100644 index 000000000..ee6d78602 --- /dev/null +++ b/bsd/man/man2/profil.2 @@ -0,0 +1,131 @@ +.\" $NetBSD: profil.2,v 1.3 1995/11/22 23:07:23 cgd Exp $ +.\" +.\" Copyright (c) 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Donn Seeley of BSDI. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)profil.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt PROFIL 2 +.Os +.Sh NAME +.Nm profil +.Nd control process profiling +.Sh SYNOPSIS +.Ft int +.Fn profil "char *samples" "size_t size" "u_long offset" "u_int scale" +.Sh DESCRIPTION +The +.Fn profil +function enables or disables +program counter profiling of the current process. +If profiling is enabled, +then at every clock tick, +the kernel updates an appropriate count in the +.Fa samples +buffer. +.Pp +The buffer +.Fa samples +contains +.Fa size +bytes and is divided into +a series of 16-bit bins. +Each bin counts the number of times the program counter +was in a particular address range in the process +when a clock tick occurred while profiling was enabled. +For a given program counter address, +the number of the corresponding bin is given +by the relation: +.Bd -literal -offset indent +[(pc - offset) / 2] * scale / 65536 +.Ed +.Pp +The +.Fa offset +parameter is the lowest address at which +the kernel takes program counter samples. +The +.Fa scale +parameter ranges from 1 to 65536 and +can be used to change the span of the bins. +A scale of 65536 maps each bin to 2 bytes of address range; +a scale of 32768 gives 4 bytes, 16384 gives 8 bytes and so on. +Intermediate values provide approximate intermediate ranges. +A +.Fa scale +value of 0 disables profiling. +.Sh RETURN VALUES +If the +.Fa scale +value is nonzero and the buffer +.Fa samples +contains an illegal address, +.Fn profil +returns \-1, +profiling is terminated and +.Va errno +is set appropriately. +Otherwise +.Fn profil +returns 0. +.Sh FILES +.Bl -tag -width /usr/lib/gcrt0.o -compact +.It Pa /usr/lib/gcrt0.o +profiling C run-time startup file +.It Pa gmon.out +conventional name for profiling output file +.El +.Sh ERRORS +The following error may be reported: +.Bl -tag -width Er +.It Bq Er EFAULT +The buffer +.Fa samples +contains an invalid address. +.El +.Sh SEE ALSO +.Xr gprof 1 +.\" .Sh HISTORY +.\" wish I knew... probably v7. +.Sh BUGS +This routine should be named +.Fn profile . +.Pp +The +.Fa samples +argument should really be a vector of type +.Fa "unsigned short" . +.Pp +The format of the gmon.out file is undocumented. diff --git a/bsd/man/man2/ptrace.2 b/bsd/man/man2/ptrace.2 new file mode 100644 index 000000000..b3590325c --- /dev/null +++ b/bsd/man/man2/ptrace.2 @@ -0,0 +1,396 @@ +.\" $OpenBSD: ptrace.2,v 1.3 1996/10/08 01:20:12 michaels Exp $ +.\" $NetBSD: ptrace.2,v 1.3 1996/02/23 01:39:41 jtc Exp $ +.\" +.\" This file is in the public domain. +.Dd November 7, 1994 +.Dt PTRACE 2 +.Os +.Sh NAME +.Nm ptrace +.Nd process tracing and debugging +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn ptrace "int request" "pid_t pid" "caddr_t addr" "int data" +.Sh DESCRIPTION +.Fn ptrace +provides tracing and debugging facilities. It allows one process (the +.Em tracing +process) to control another (the +.Em traced +process). Most of the time, the traced process runs normally, but when +it receives a signal +.Po +see +.Xr sigaction 2 +.Pc , +it stops. The tracing process is expected to notice this via +.Xr wait 2 +or the delivery of a +.Dv SIGCHLD +signal, examine the state of the stopped process, and cause it to +terminate or continue as appropriate. +.Fn ptrace +is the mechanism by which all this happens. +.Pp +The +.Fa request +argument specifies what operation is being performed; the meaning of +the rest of the arguments depends on the operation, but except for one +special case noted below, all +.Fn ptrace +calls are made by the tracing process, and the +.Fa pid +argument specifies the process ID of the traced process. +.Fa request +can be: +.Bl -tag -width 12n +.It Dv PT_TRACE_ME +This request is the only one used by the traced process; it declares +that the process expects to be traced by its parent. All the other +arguments are ignored. (If the parent process does not expect to trace +the child, it will probably be rather confused by the results; once the +traced process stops, it cannot be made to continue except via +.Eo \& +.Fn ptrace +.Ec \&.) +When a process has used this request and calls +.Xr execve 2 +or any of the routines built on it +.Po +such as +.Xr execv 3 +.Pc , +it will stop before executing the first instruction of the new image. +Also, any setuid or setgid bits on the executable being executed will +be ignored. +.It Dv PT_READ_I , Dv PT_READ_D +These requests read a single +.Li int +of data from the traced process' address space. Traditionally, +.Fn ptrace +has allowed for machines with distinct address spaces for instruction +and data, which is why there are two requests: conceptually, +.Dv PT_READ_I +reads from the instruction space and +.Dv PT_READ_D +reads from the data space. In the current OpenBSD implementation, these +two requests are completely identical. The +.Fa addr +argument specifies the address (in the traced process' virtual address +space) at which the read is to be done. This address does not have to +meet any alignment constraints. The value read is returned as the +return value from +.Eo \& +.Fn ptrace +.Ec . +.It Dv PT_WRITE_I , Dv PT_WRITE_D +These requests parallel +.Dv PT_READ_I +and +.Dv PT_READ_D , +except that they write rather than read. The +.Fa data +argument supplies the value to be written. +.\" .It Dv PT_READ_U +.\" This request reads an +.\" .Li int +.\" from the traced process' user structure. The +.\" .Fa addr +.\" argument specifies the location of the int relative to the base of the +.\" user structure; it will usually be an integer value cast to +.\" .Li caddr_t +.\" either explicitly or via the presence of a prototype for +.\" .Eo \& +.\" .Fn ptrace +.\" .Ec . +.\" Unlike +.\" .Dv PT_READ_I +.\" and +.\" .Dv PT_READ_D , +.\" .Fa addr +.\" must be aligned on an +.\" .Li int +.\" boundary. The value read is returned as the return value from +.\" .Eo \& +.\" .Fn ptrace +.\" .Ec . +.\" .It Dv PT_WRITE_U +.\" This request writes an +.\" .Li int +.\" into the traced process' user structure. +.\" .Fa addr +.\" specifies the offset, just as for +.\" .Dv PT_READ_U , +.\" and +.\" .Fa data +.\" specifies the value to be written, just as for +.\" .Dv PT_WRITE_I +.\" and +.\" .Dv PT_WRITE_D . +.It Dv PT_CONTINUE +The traced process continues execution. +.Fa addr +is an address specifying the place where execution is to be resumed (a +new value for the program counter), or +.Li (caddr_t)1 +to indicate that execution is to pick up where it left off. +.Fa data +provides a signal number to be delivered to the traced process as it +resumes execution, or 0 if no signal is to be sent. +.It Dv PT_KILL +The traced process terminates, as if +.Dv PT_CONTINUE +had been used with +.Dv SIGKILL +given as the signal to be delivered. +.It Dv PT_ATTACH +This request allows a process to gain control of an otherwise unrelated +process and begin tracing it. It does not need any cooperation from +the to-be-traced process. In this case, +.Fa pid +specifies the process ID of the to-be-traced process, and the other two +arguments are ignored. This request requires that the target process +must have the same real UID as the tracing process, and that it must +not be executing a setuid or setgid executable. (If the tracing +process is running as root, these restrictions do not apply.) The +tracing process will see the newly-traced process stop and may then +control it as if it had been traced all along. +.It Dv PT_DETACH +This request is like PT_CONTINUE, except that it does not allow +specifying an alternate place to continue execution, and after it +succeeds, the traced process is no longer traced and continues +execution normally. +.El +.Pp +Additionally, machine-specific requests can exist. On the SPARC, these +are: +.Bl -tag -width 12n +.It Dv PT_GETREGS +This request reads the traced process' machine registers into the +.Dq Li "struct reg" +(defined in +.Aq Pa machine/reg.h ) +pointed to by +.Fa addr . +.It Dv PT_SETREGS +This request is the converse of +.Dv PT_GETREGS ; +it loads the traced process' machine registers from the +.Dq Li "struct reg" +(defined in +.Aq Pa machine/reg.h ) +pointed to by +.Fa addr . +.It Dv PT_GETFPREGS +This request reads the traced process' floating-point registers into +the +.Dq Li "struct fpreg" +(defined in +.Aq Pa machine/reg.h ) +pointed to by +.Fa addr . +.It Dv PT_SETFPREGS +This request is the converse of +.Dv PT_GETFPREGS ; +it loads the traced process' floating-point registers from the +.Dq Li "struct fpreg" +(defined in +.Aq Pa machine/reg.h ) +pointed to by +.Fa addr . +.\" .It Dv PT_SYSCALL +.\" This request is like +.\" .Dv PT_CONTINUE +.\" except that the process will stop next time it executes any system +.\" call. Information about the system call can be examined with +.\" .Dv PT_READ_U +.\" and potentially modified with +.\" .Dv PT_WRITE_U +.\" through the +.\" .Li u_kproc.kp_proc.p_md +.\" element of the user structure (see below). If the process is continued +.\" with another +.\" .Dv PT_SYSCALL +.\" request, it will stop again on exit from the syscall, at which point +.\" the return values can be examined and potentially changed. The +.\" .Li u_kproc.kp_proc.p_md +.\" element is of type +.\" .Dq Li "struct mdproc" , +.\" which should be declared by including +.\" .Aq Pa sys/param.h , +.\" .Aq Pa sys/user.h , +.\" and +.\" .Aq Pa machine/proc.h , +.\" and contains the following fields (among others): +.\" .Bl -item -compact -offset indent +.\" .It +.\" .Li syscall_num +.\" .It +.\" .Li syscall_nargs +.\" .It +.\" .Li syscall_args[8] +.\" .It +.\" .Li syscall_err +.\" .It +.\" .Li syscall_rv[2] +.\" .El +.\" When a process stops on entry to a syscall, +.\" .Li syscall_num +.\" holds the number of the syscall, +.\" .Li syscall_nargs +.\" holds the number of arguments it expects, and +.\" .Li syscall_args +.\" holds the arguments themselves. (Only the first +.\" .Li syscall_nargs +.\" elements of +.\" .Li syscall_args +.\" are guaranteed to be useful.) When a process stops on exit from a +.\" syscall, +.\" .Li syscall_num +.\" is +.\" .Eo \& +.\" .Li -1 +.\" .Ec , +.\" .Li syscall_err +.\" holds the error number +.\" .Po +.\" see +.\" .Xr errno 2 +.\" .Pc , +.\" or 0 if no error occurred, and +.\" .Li syscall_rv +.\" holds the return values. (If the syscall returns only one value, only +.\" .Li syscall_rv[0] +.\" is useful.) The tracing process can modify any of these with +.\" .Dv PT_WRITE_U ; +.\" only some modifications are useful. +.\" .Pp +.\" On entry to a syscall, +.\" .Li syscall_num +.\" can be changed, and the syscall actually performed will correspond to +.\" the new number (it is the responsibility of the tracing process to fill +.\" in +.\" .Li syscall_args +.\" appropriately for the new call, but there is no need to modify +.\" .Eo \& +.\" .Li syscall_nargs +.\" .Ec ). +.\" If the new syscall number is 0, no syscall is actually performed; +.\" instead, +.\" .Li syscall_err +.\" and +.\" .Li syscall_rv +.\" are passed back to the traced process directly (and therefore should be +.\" filled in). If the syscall number is otherwise out of range, a dummy +.\" syscall which simply produces an +.\" .Er ENOSYS +.\" error is effectively performed. +.\" .Pp +.\" On exit from a syscall, only +.\" .Li syscall_err +.\" and +.\" .Li syscall_rv +.\" can usefully be changed; they are set to the values returned by the +.\" syscall and will be passed back to the traced process by the normal +.\" syscall return mechanism. +.El +.Sh ERRORS +Some requests can cause +.Fn ptrace +to return +.Li -1 +as a non-error value; to disambiguate, +.Va errno +can be set to 0 before the call and checked afterwards. The possible +errors are: +.Bl -tag -width 4n +.It Bq Er ESRCH +No process having the specified process ID exists. +.It Bq Er EINVAL +.Bl -bullet -compact +.It +A process attempted to use +.Dv PT_ATTACH +on itself. +.It +The +.Fa request +was not one of the legal requests. +.\" .It +.\" The +.\" .Fa addr +.\" to +.\" .Dv PT_READ_U +.\" or +.\" .Dv PT_WRITE_U +.\" was not +.\" .Li int Ns \&-aligned. +.It +The signal number (in +.Fa data ) +to +.Dv PT_CONTINUE +.\" or +.\" .Dv PT_SYSCALL +was neither 0 nor a legal signal number. +.It +.Dv PT_GETREGS , +.Dv PT_SETREGS , +.Dv PT_GETFPREGS , +or +.Dv PT_SETFPREGS +was attempted on a process with no valid register set. (This is +normally true only of system processes.) +.El +.It Bq Er EBUSY +.Bl -bullet -compact +.It +.Dv PT_ATTACH +was attempted on a process that was already being traced. +.It +A request attempted to manipulate a process that was being traced by +some process other than the one making the request. +.It +A request (other than +.Dv PT_ATTACH ) +specified a process that wasn't stopped. +.El +.It Bq Er EPERM +.Bl -bullet -compact +.It +A request (other than +.Dv PT_ATTACH ) +attempted to manipulate a process that wasn't being traced at all. +.It +An attempt was made to use +.Dv PT_ATTACH +on a process in violation of the requirements listed under +.Dv PT_ATTACH +above. +.El +.Sh BUGS +On the SPARC, the PC is set to the provided PC value for +.Dv PT_CONTINUE +and similar calls, but the NPC is set willy-nilly to 4 greater than the +PC value. Using +.Dv PT_GETREGS +and +.Dv PT_SETREGS +to modify the PC, passing +.Li (caddr_t)1 +to +.Eo \& +.Fn ptrace +.Ec , +should be able to sidestep this. +.Pp +Single-stepping is not available. +.\" .Pp +.\" When using +.\" .Dv PT_SYSCALL , +.\" there is no easy way to tell whether the traced process stopped because +.\" it made a syscall or because a signal was sent at a moment that it just +.\" happened to have valid-looking garbage in its +.\" .Dq Li "struct mdproc" . diff --git a/bsd/man/man2/pwrite.2 b/bsd/man/man2/pwrite.2 new file mode 100644 index 000000000..5a7182844 --- /dev/null +++ b/bsd/man/man2/pwrite.2 @@ -0,0 +1 @@ +.so man2/write.2 diff --git a/bsd/man/man2/quotactl.2 b/bsd/man/man2/quotactl.2 new file mode 100644 index 000000000..ea35c50b7 --- /dev/null +++ b/bsd/man/man2/quotactl.2 @@ -0,0 +1,225 @@ +.\" $NetBSD: quotactl.2,v 1.8 1995/02/27 12:35:43 cgd Exp $ +.\" +.\" Copyright (c) 1983, 1990, 1991, 1993 +.\" The 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. +.\" +.\" @(#)quotactl.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt QUOTACTL 2 +.Os +.Sh NAME +.Nm quotactl +.Nd manipulate filesystem quotas +.Sh SYNOPSIS +.Fd #include /* for disk quotas */ +.Ft int +.Fn quotactl "const char *path" "int cmd" "int id" "char *addr" +.Sh DESCRIPTION +The +.Fn quotactl +call enables, disables and +manipulates filesystem quotas. +A quota control command +given by +.Fa cmd +operates on the given filename +.Fa path +for the given user +.Fa id . +The address of an optional command specific data structure, +.Fa addr , +may be given; its interpretation +is discussed below with each command. +.Pp +Currently quotas are supported only for the "ffs" and "hfs" filesystems. +A command is composed of a primary command (see below) +and a command type used to interpret the +.Fa id . +Types are supported for interpretation of user identifiers +and group identifiers. +The specific commands are: +.Bl -tag -width Q_QUOTASTAT +.It Dv Q_QUOTAON +Enable disk quotas for the filesystem specified by +.Fa path . +The command type specifies the type of the quotas being enabled. +The +.Fa addr +argument specifies a file from which to take the quotas. +The quota file must exist; +it is normally created with the +.Xr quotacheck 8 +program. +The +.Fa id +argument is unused. +Only the super-user may turn quotas on. +.It Dv Q_QUOTAOFF +Disable disk quotas for the filesystem specified by +.Fa path . +The command type specifies the type of the quotas being disabled. +The +.Fa addr +and +.Fa id +arguments are unused. +Only the super-user may turn quotas off. +.It Dv Q_GETQUOTA +Get disk quota limits and current usage for the user or group +(as determined by the command type) with identifier +.Fa id . +.Fa Addr +is a pointer to a +.Fa struct dqblk +structure. +.It Dv Q_SETQUOTA +Set disk quota limits for the user or group +(as determined by the command type) with identifier +.Fa id . +.Fa Addr +is a pointer to a +.Fa struct dqblk +structure. +The usage fields of the +.Fa dqblk +structure are ignored. +This call is restricted to the super-user. +.It Dv Q_SETUSE +Set disk usage limits for the user or group +(as determined by the command type) with identifier +.Fa id . +.Fa Addr +is a pointer to a +.Fa struct dqblk +structure. +Only the usage fields are used. +This call is restricted to the super-user. +.It Dv Q_SYNC +Update the on-disk copy of quota usages. +The command type specifies which type of quotas are to be updated. +The +.Fa id +and +.Fa addr +parameters are ignored. +.It Dv Q_QUOTASTAT +Get the enable status for the filesystem specified by +.Fa path . +The command type specifies the type of the quotas whose +status is being queried. +.Fa Addr +is a pointer to an integer. Upon return, +this integer will hold a zero value if quotas for the +given type are not enabled and a non-zero value if +quotas for the given type are enabled. +The +.Fa id +parameter is ignored. +.El +.Sh RETURN VALUES +A successful call returns 0, +otherwise the value -1 is returned and the global variable +.Va errno +indicates the reason for the failure. +.Sh ERRORS +A +.Fn quotactl +call will fail if: +.Bl -tag -width Er +.It Bq Er EOPNOTSUPP +The kernel has not been compiled with the +.Dv QUOTA +option. +.It Bq Er EUSERS +The quota table cannot be expanded. +.It Bq Er EINVAL +.Fa Cmd +or the command type is invalid. +.It Bq Er EACCES +In +.Dv Q_QUOTAON , +the quota file is not a plain file. +.It Bq Er EACCES +Search permission is denied for a component of a path prefix. +.It Bq Er ENOTDIR +A component of a path prefix was not a directory. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded +.Dv {NAME_MAX} +characters, or an entire path name exceeded +.Dv {PATH_MAX} +characters. +.It Bq Er ENOENT +A filename does not exist. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating a pathname. +.It Bq Er EROFS +In +.Dv Q_QUOTAON , +the quota file resides on a read-only filesystem. +.It Bq Er EIO +An +.Tn I/O +error occurred while reading from or writing +to a file containing quotas. +.It Bq Er EFAULT +An invalid +.Fa addr +was supplied; the associated structure could not be copied in or out +of the kernel. +.It Bq Er EFAULT +.Fa Path +points outside the process's allocated address space. +.It Bq Er EPERM +The call was privileged and the caller was not the super-user. +.El +.Sh SEE ALSO +.Xr quota 1 , +.Xr fstab 5 , +.Xr edquota 8 , +.Xr quotacheck 8 , +.Xr quotaon 8 , +.Xr repquota 8 +.Sh BUGS +There should be some way to integrate this call with the resource +limit interface provided by +.Xr setrlimit 2 +and +.Xr getrlimit 2 . +.Sh HISTORY +The +.Fn quotactl +function call appeared in +.Bx 4.3 Reno . diff --git a/bsd/man/man2/read.2 b/bsd/man/man2/read.2 new file mode 100644 index 000000000..097b9a360 --- /dev/null +++ b/bsd/man/man2/read.2 @@ -0,0 +1,221 @@ +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.\" @(#)read.2 8.4 (Berkeley) 2/26/94 +.\" $FreeBSD: src/lib/libc/sys/read.2,v 1.9.2.6 2001/12/14 18:34:01 ru Exp $ +.\" +.Dd February 26, 1994 +.Dt READ 2 +.Os +.Sh NAME +.Nm read , +.Nm readv , +.Nm pread +.Nd read input +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In sys/types.h +.In sys/uio.h +.In unistd.h +.Ft ssize_t +.Fn read "int d" "void *buf" "size_t nbytes" +.Ft ssize_t +.Fn readv "int d" "const struct iovec *iov" "int iovcnt" +.Ft ssize_t +.Fn pread "int d" "void *buf" "size_t nbytes" "off_t offset" +.Sh DESCRIPTION +.Fn Read +attempts to read +.Fa nbytes +of data from the object referenced by the descriptor +.Fa d +into the buffer pointed to by +.Fa buf . +.Fn Readv +performs the same action, but scatters the input data +into the +.Fa iovcnt +buffers specified by the members of the +.Fa iov +array: iov[0], iov[1], ..., iov[iovcnt\|\-\|1]. +.Fn Pread +performs the same function, but reads from the specified position in +the file without modifying the file pointer. +.Pp +For +.Fn readv , +the +.Fa iovec +structure is defined as: +.Pp +.Bd -literal -offset indent -compact +struct iovec { + char *iov_base; /* Base address. */ + size_t iov_len; /* Length. */ +}; +.Ed +.Pp +Each +.Fa iovec +entry specifies the base address and length of an area +in memory where data should be placed. +.Fn Readv +will always fill an area completely before proceeding +to the next. +.Pp +On objects capable of seeking, the +.Fn read +starts at a position +given by the pointer associated with +.Fa d +(see +.Xr lseek 2 ) . +Upon return from +.Fn read , +the pointer is incremented by the number of bytes actually read. +.Pp +Objects that are not capable of seeking always read from the current +position. The value of the pointer associated with such an +object is undefined. +.Pp +Upon successful completion, +.Fn read , +.Fn readv , +and +.Fn pread +return the number of bytes actually read and placed in the buffer. +The system guarantees to read the number of bytes requested if +the descriptor references a normal file that has that many bytes left +before the end-of-file, but in no other case. +.Sh RETURN VALUES +If successful, the +number of bytes actually read is returned. +Upon reading end-of-file, +zero is returned. +Otherwise, a -1 is returned and the global variable +.Va errno +is set to indicate the error. +.Sh ERRORS +.Fn Read , +.Fn readv , +and +.Fn pread +will succeed unless: +.Bl -tag -width Er +.It Bq Er EBADF +.Fa D +is not a valid file or socket descriptor open for reading. +.It Bq Er EFAULT +.Fa Buf +points outside the allocated address space. +.It Bq Er EIO +An I/O error occurred while reading from the file system. +.It Bq Er EINTR +A read from a slow device was interrupted before +any data arrived by the delivery of a signal. +.It Bq Er EINVAL +The pointer associated with +.Fa d +was negative. +.It Bq Er EAGAIN +The file was marked for non-blocking I/O, +and no data were ready to be read. +.El +.Pp +In addition, +.Fn readv +may return one of the following errors: +.Bl -tag -width Er +.It Bq Er EINVAL +.Fa Iovcnt +was less than or equal to 0, or greater than 16. +.It Bq Er EINVAL +One of the +.Fa iov_len +values in the +.Fa iov +array was negative. +.It Bq Er EINVAL +The sum of the +.Fa iov_len +values in the +.Fa iov +array overflowed a 32-bit integer. +.It Bq Er EFAULT +Part of the +.Fa iov +points outside the process's allocated address space. +.El +.Pp +The +.Fn pread +call may also return the following errors: +.Bl -tag -width Er +.It Bq Er EINVAL +The specified file offset is invalid. +.It Bq Er ESPIPE +The file descriptor is associated with a pipe, socket, or FIFO. +.El +.Sh SEE ALSO +.Xr dup 2 , +.Xr fcntl 2 , +.Xr open 2 , +.Xr pipe 2 , +.Xr select 2 , +.Xr socket 2 , +.Xr socketpair 2 +.Sh STANDARDS +The +.Fn read +function call is expected to conform to +.St -p1003.1-90 . +The +.Fn readv +and +.Fn pread +functions are expected to conform to +.St -xpg4.2 . +.Sh HISTORY +The +.Fn pread +function call +appeared in +.At V.4 . +The +.Fn readv +function call +appeared in +.Bx 4.2 . +A +.Fn read +function call appeared in +.At v6 . diff --git a/bsd/man/man2/readlink.2 b/bsd/man/man2/readlink.2 new file mode 100644 index 000000000..0a604f256 --- /dev/null +++ b/bsd/man/man2/readlink.2 @@ -0,0 +1,99 @@ +.\" $NetBSD: readlink.2,v 1.7 1995/02/27 12:35:54 cgd Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)readlink.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt READLINK 2 +.Os BSD 4.2 +.Sh NAME +.Nm readlink +.Nd read value of a symbolic link +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn readlink "const char *path" "char *buf" "int bufsiz" +.Sh DESCRIPTION +.Fn Readlink +places the contents of the symbolic link +.Fa path +in the buffer +.Fa buf , +which has size +.Fa bufsiz . +.Nm Readlink +does not append a +.Dv NUL +character to +.Fa buf . +.Sh RETURN VALUES +The call returns the count of characters placed in the buffer +if it succeeds, or a -1 if an error occurs, placing the error +code in the global variable +.Va errno . +.Sh ERRORS +.Fn Readlink +will fail if: +.Bl -tag -width Er +.It Bq Er ENOTDIR +A component of the path prefix is not a directory. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded +.Dv {NAME_MAX} +characters, or an entire path name exceeded +.Dv {PATH_MAX} +characters. +.It Bq Er ENOENT +The named file does not exist. +.It Bq Er EACCES +Search permission is denied for a component of the path prefix. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating the pathname. +.It Bq Er EINVAL +The named file is not a symbolic link. +.It Bq Er EIO +An I/O error occurred while reading from the file system. +.It Bq Er EFAULT +.Fa Buf +extends outside the process's allocated address space. +.El +.Sh SEE ALSO +.Xr stat 2 , +.Xr lstat 2 , +.Xr symlink 2 +.Xr symlink 7 , +.Sh HISTORY +The +.Fn readlink +function call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/readv.2 b/bsd/man/man2/readv.2 new file mode 100644 index 000000000..d5e1c8ac7 --- /dev/null +++ b/bsd/man/man2/readv.2 @@ -0,0 +1 @@ +.so man2/read.2 diff --git a/bsd/man/man2/reboot.2 b/bsd/man/man2/reboot.2 new file mode 100644 index 000000000..ee2829c9e --- /dev/null +++ b/bsd/man/man2/reboot.2 @@ -0,0 +1,161 @@ +.\" $OpenBSD: reboot.2,v 1.2 1996/10/08 01:20:13 michaels Exp $ +.\" $NetBSD: reboot.2,v 1.5 1995/02/27 12:36:02 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.\" @(#)reboot.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt REBOOT 2 +.Os BSD 4 +.Sh NAME +.Nm reboot +.Nd reboot system or halt processor +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn reboot "int howto" +.Sh DESCRIPTION +.Fn Reboot +reboots the system. +Only the super-user may reboot a machine on demand. +However, a reboot is invoked +automatically in the event of unrecoverable system failures. +.Pp +.Fa Howto +is a mask of options; the system call interface allows the following +options, defined in the include file +.Aq Pa sys/reboot.h , +to be passed +to the new kernel or the new bootstrap and init programs. +.Bl -tag -width RB_INITNAMEA +.It Dv RB_AUTOBOOT +The default, causing the system to reboot in its usual fashion. +.It Dv RB_ASKNAME +Interpreted by the bootstrap program itself, causing it to +prompt on the console as to what file should be booted. +Normally, the system is booted from the file +.Dq Em xx Ns No (0,0)bsd , +where +.Em xx +is the default disk name, +without prompting for the file name. +.It Dv RB_DFLTROOT +Use the compiled in root device. +Normally, the system uses the device from which it was booted +as the root device if possible. +(The default behavior is dependent on the ability of the bootstrap program +to determine the drive from which it was loaded, which is not possible +on all systems.) +.It Dv RB_DUMP +Dump kernel memory before rebooting; see +.Xr savecore 8 +for more information. +.It Dv RB_HALT +the processor is simply halted; no reboot takes place. +This option should be used with caution. +.It Dv RB_INITNAME +An option allowing the specification of an init program (see +.Xr init 8 ) +other than +.Pa /sbin/init +to be run when the system reboots. +This switch is not currently available. +.It Dv RB_KDB +Load the symbol table and enable a built-in debugger in the system. +This option will have no useful function if the kernel is not configured +for debugging. +Several other options have different meaning if combined +with this option, although their use may not be possible +via the +.Fn reboot +call. +See +.Xr kadb 4 +for more information. +.It Dv RB_NOSYNC +Normally, the disks are sync'd (see +.Xr sync 8 ) +before the processor is halted or rebooted. +This option may be useful if file system changes have been made manually +or if the processor is on fire. +.It Dv RB_RDONLY +Initially mount the root file system read-only. +This is currently the default, and this option has been deprecated. +.It Dv RB_SINGLE +Normally, the reboot procedure involves an automatic disk consistency +check and then multi-user operations. +.Dv RB_SINGLE +prevents this, booting the system with a single-user shell +on the console. +.Dv RB_SINGLE +is actually interpreted by the +.Xr init 8 +program in the newly booted system. +.Pp +When no options are given (i.e., +.Dv RB_AUTOBOOT +is used), the system is +rebooted from file ``bsd'' in the root file system of unit 0 +of a disk chosen in a processor specific way. +An automatic consistency check of the disks is normally performed +(see +.Xr fsck 8 ) . +.El +.Sh RETURN VALUES +If successful, this call never returns. +Otherwise, a -1 is returned and an error is returned in the global +variable +.Va errno . +.Sh ERRORS +.Bl -tag -width Er +.It Bq Er EPERM +The caller is not the super-user. +.El +.Sh SEE ALSO +.Xr kadb 4 , +.Xr crash 8 , +.Xr halt 8 , +.Xr init 8 , +.Xr reboot 8 , +.Xr savecore 8 +.Sh BUGS +The HP300 implementation supports neither +.Dv RB_DFLTROOT +nor +.Dv RB_KDB . +.Sh HISTORY +The +.Fn reboot +function call appeared in +.Bx 4.0 . diff --git a/bsd/man/man2/recv.2 b/bsd/man/man2/recv.2 new file mode 100644 index 000000000..75ef209bf --- /dev/null +++ b/bsd/man/man2/recv.2 @@ -0,0 +1,264 @@ +.\" $NetBSD: recv.2,v 1.6 1995/02/27 12:36:08 cgd Exp $ +.\" +.\" Copyright (c) 1983, 1990, 1991, 1993 +.\" 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. +.\" +.\" @(#)recv.2 8.3 (Berkeley) 2/21/94 +.\" +.Dd February 21, 1994 +.Dt RECV 2 +.Os BSD 4.3r +.Sh NAME +.Nm recv , +.Nm recvfrom , +.Nm recvmsg +.Nd receive a message from a socket +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft ssize_t +.Fn recv "int s" "void *buf" "size_t len" "int flags" +.Ft ssize_t +.Fn recvfrom "int s" "void *buf" "size_t len" "int flags" "struct sockaddr *from" "int *fromlen" +.Ft ssize_t +.Fn recvmsg "int s" "struct msghdr *msg" "int flags" +.Sh DESCRIPTION +.Fn Recvfrom +and +.Fn recvmsg +are used to receive messages from a socket, +and may be used to receive data on a socket whether or not +it is connection-oriented. +.Pp +If +.Fa from +is non-nil, and the socket is not connection-oriented, +the source address of the message is filled in. +.Fa Fromlen +is a value-result parameter, initialized to the size of +the buffer associated with +.Fa from , +and modified on return to indicate the actual size of the +address stored there. +.Pp +The +.Fn recv +call is normally used only on a +.Em connected +socket (see +.Xr connect 2 ) +and is identical to +.Fn recvfrom +with a nil +.Fa from +parameter. +As it is redundant, it may not be supported in future releases. +.Pp +On successful completion, all three routines return the number of +message bytes read. If a message is too long to fit in the supplied +buffer, excess bytes may be discarded depending on the type of socket +the message is received from (see +.Xr socket 2 ) . +.Pp +If no messages are available at the socket, the +receive call waits for a message to arrive, unless +the socket is nonblocking (see +.Xr fcntl 2 ) +in which case the value +-1 is returned and the external variable +.Va errno +set to +.Er EAGAIN . +The receive calls normally return any data available, +up to the requested amount, +rather than waiting for receipt of the full amount requested; +this behavior is affected by the socket-level options +.Dv SO_RCVLOWAT +and +.Dv SO_RCVTIMEO +described in +.Xr getsockopt 2 . +.Pp +The +.Xr select 2 +call may be used to determine when more data arrive. +.Pp +The +.Fa flags +argument to a recv call is formed by +.Em or Ap ing +one or more of the values: +.Bl -column MSG_WAITALL -offset indent +.It Dv MSG_OOB Ta process out-of-band data +.It Dv MSG_PEEK Ta peek at incoming message +.It Dv MSG_WAITALL Ta wait for full request or error +.El +The +.Dv MSG_OOB +flag requests receipt of out-of-band data +that would not be received in the normal data stream. +Some protocols place expedited data at the head of the normal +data queue, and thus this flag cannot be used with such protocols. +The MSG_PEEK flag causes the receive operation to return data +from the beginning of the receive queue without removing that +data from the queue. +Thus, a subsequent receive call will return the same data. +The MSG_WAITALL flag requests that the operation block until +the full request is satisfied. +However, the call may still return less data than requested +if a signal is caught, an error or disconnect occurs, +or the next data to be received is of a different type than that returned. +.Pp +The +.Fn recvmsg +call uses a +.Fa msghdr +structure to minimize the number of directly supplied parameters. +This structure has the following form, as defined in +.Ao Pa sys/socket.h Ac : +.Pp +.Bd -literal +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 */ +}; +.Ed +.Pp +Here +.Fa msg_name +and +.Fa msg_namelen +specify the source address if the socket is unconnected; +.Fa msg_name +may be given as a null pointer if no names are desired or required. +.Fa Msg_iov +and +.Fa msg_iovlen +describe scatter gather locations, as discussed in +.Xr read 2 . +.Fa Msg_control , +which has length +.Fa msg_controllen , +points to a buffer for other protocol control related messages +or other miscellaneous ancillary data. +The messages are of the form: +.Bd -literal +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[]; */ +}; +.Ed +As an example, one could use this to learn of changes in the data-stream +in XNS/SPP, or in ISO, to obtain user-connection-request data by requesting +a recvmsg with no data buffer provided immediately after an +.Fn accept +call. +.Pp +Open file descriptors are now passed as ancillary data for +.Dv AF_UNIX +domain sockets, with +.Fa cmsg_level +set to +.Dv SOL_SOCKET +and +.Fa cmsg_type +set to +.Dv SCM_RIGHTS . +.Pp +The +.Fa msg_flags +field is set on return according to the message received. +.Dv MSG_EOR +indicates end-of-record; +the data returned completed a record (generally used with sockets of type +.Dv SOCK_SEQPACKET ) . +.Dv MSG_TRUNC +indicates that +the trailing portion of a datagram was discarded because the datagram +was larger than the buffer supplied. +.Dv MSG_CTRUNC +indicates that some +control data were discarded due to lack of space in the buffer +for ancillary data. +.Dv MSG_OOB +is returned to indicate that expedited or out-of-band data were received. +.Pp +.Sh RETURN VALUES +These calls return the number of bytes received, or -1 +if an error occurred. +.Sh ERRORS +The calls fail if: +.Bl -tag -width Er +.It Bq Er EBADF +The argument +.Fa s +is an invalid descriptor. +.It Bq Er ENOTCONN +The socket is associated with a connection-oriented protocol +and has not been connected (see +.Xr connect 2 +and +.Xr accept 2 ). +.It Bq Er ENOTSOCK +The argument +.Fa s +does not refer to a socket. +.It Bq Er EAGAIN +The socket is marked non-blocking, and the receive operation +would block, or +a receive timeout had been set, +and the timeout expired before data were received. +.It Bq Er EINTR +The receive was interrupted by delivery of a signal before +any data were available. +.It Bq Er EFAULT +The receive buffer pointer(s) point outside the process's +address space. +.El +.Sh SEE ALSO +.Xr fcntl 2 , +.Xr read 2 , +.Xr select 2 , +.Xr getsockopt 2 , +.Xr socket 2 +.Sh HISTORY +The +.Fn recv +function call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/recvfrom.2 b/bsd/man/man2/recvfrom.2 new file mode 100644 index 000000000..13228c391 --- /dev/null +++ b/bsd/man/man2/recvfrom.2 @@ -0,0 +1 @@ +.so man2/recv.2 diff --git a/bsd/man/man2/recvmsg.2 b/bsd/man/man2/recvmsg.2 new file mode 100644 index 000000000..13228c391 --- /dev/null +++ b/bsd/man/man2/recvmsg.2 @@ -0,0 +1 @@ +.so man2/recv.2 diff --git a/bsd/man/man2/rename.2 b/bsd/man/man2/rename.2 new file mode 100644 index 000000000..4167485d3 --- /dev/null +++ b/bsd/man/man2/rename.2 @@ -0,0 +1,203 @@ +.\" $NetBSD: rename.2,v 1.7 1995/02/27 12:36:15 cgd Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)rename.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt RENAME 2 +.Os BSD 4.2 +.Sh NAME +.Nm rename +.Nd change the name of a file +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn rename "const char *from" "const char *to" +.Sh DESCRIPTION +.Fn Rename +causes the link named +.Fa from +to be renamed as +.Fa to . +If +.Fa to +exists, it is first removed. +Both +.Fa from +and +.Fa to +must be of the same type (that is, both directories or both +non-directories), and must reside on the same file system. +.Pp +.Fn Rename +guarantees that an instance of +.Fa to +will always exist, even if the system should crash in +the middle of the operation. +.Pp +If the final component of +.Fa from +is a symbolic link, +the symbolic link is renamed, +not the file or directory to which it points. +.Sh CAVEAT +The system can deadlock if a loop in the file system graph is present. +This loop takes the form of an entry in directory +.Ql Pa a , +say +.Ql Pa a/foo , +being a hard link to directory +.Ql Pa b , +and an entry in +directory +.Ql Pa b , +say +.Ql Pa b/bar , +being a hard link +to directory +.Ql Pa a . +When such a loop exists and two separate processes attempt to +perform +.Ql rename a/foo b/bar +and +.Ql rename b/bar a/foo , +respectively, +the system may deadlock attempting to lock +both directories for modification. +Hard links to directories should be +replaced by symbolic links by the system administrator. +.Sh RETURN VALUES +A 0 value is returned if the operation succeeds, otherwise +.Fn rename +returns -1 and the global variable +.Va errno +indicates the reason for the failure. +.Sh ERRORS +.Fn Rename +will fail and neither of the argument files will be +affected if: +.Bl -tag -width Er +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded +.Dv {NAME_MAX} +characters, or an entire path name exceeded +.Dv {PATH_MAX} +characters. +.It Bq Er ENOENT +A component of the +.Fa from +path does not exist, +or a path prefix of +.Fa to +does not exist. +.It Bq Er EACCES +A component of either path prefix denies search permission. +.It Bq Er EACCES +The requested link requires writing in a directory with a mode +that denies write permission. +.It Bq Er EPERM +The directory containing +.Fa from +is marked sticky, +and neither the containing directory nor +.Fa from +are owned by the effective user ID. +.It Bq Er EPERM +The +.Fa to +file exists, +the directory containing +.Fa to +is marked sticky, +and neither the containing directory nor +.Fa to +are owned by the effective user ID. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating either pathname. +.It Bq Er ENOTDIR +A component of either path prefix is not a directory. +.It Bq Er ENOTDIR +.Fa from +is a directory, but +.Fa to +is not a directory. +.It Bq Er EISDIR +.Fa to +is a directory, but +.Fa from +is not a directory. +.It Bq Er EXDEV +The link named by +.Fa to +and the file named by +.Fa from +are on different logical devices (file systems). Note that this error +code will not be returned if the implementation permits cross-device +links. +.It Bq Er ENOSPC +The directory in which the entry for the new name is being placed +cannot be extended because there is no space left on the file +system containing the directory. +.It Bq Er EDQUOT +The directory in which the entry for the new name +is being placed cannot be extended because the +user's quota of disk blocks on the file system +containing the directory has been exhausted. +.It Bq Er EIO +An I/O error occurred while making or updating a directory entry. +.It Bq Er EROFS +The requested link requires writing in a directory on a read-only file +system. +.It Bq Er EFAULT +.Em Path +points outside the process's allocated address space. +.It Bq Er EINVAL +.Fa From +is a parent directory of +.Fa to , +or an attempt is made to rename +.Ql \&. +or +.Ql \&.. . +.It Bq Er ENOTEMPTY +.Fa To +is a directory and is not empty. +.El +.Sh SEE ALSO +.Xr open 2 +.Xr symlink 7 +.Sh STANDARDS +The +.Fn rename +function conforms to +.St -p1003.1-88 . diff --git a/bsd/man/man2/revoke.2 b/bsd/man/man2/revoke.2 new file mode 100644 index 000000000..00d099171 --- /dev/null +++ b/bsd/man/man2/revoke.2 @@ -0,0 +1,108 @@ +.\" $NetBSD: revoke.2,v 1.3 1995/10/12 15:41:11 jtc Exp $ +.\" +.\" Copyright (c) 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Berkeley Software Design, 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. +.\" +.\" @(#)revoke.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt REVOKE 2 +.Os +.Sh NAME +.Nm revoke +.Nd revoke file access +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn revoke "const char *path" +.Sh DESCRIPTION +The +.Nm revoke +function invalidates all current open file descriptors in the system +for the file named by +.Fa path . +Subsequent operations on any such descriptors +fail, with the exceptions that a +.Fn read +from a character device file which has been revoked +returns a count of zero (end of file), +and a +.Fn close +call will succeed. +If the file is a special file for a device which is open, +the device close function +is called as if all open references to the file had been closed. +.Pp +Access to a file may be revoked only by its owner or the super user. +The +.Nm revoke +function is currently supported only for block and character special +device files. +It is normally used to prepare a terminal device for a new login session, +preventing any access by a previous user of the terminal. +.Sh RETURN VALUES +A 0 value indicated that the call succeeded. A \-1 return value +indicates an error occurred and +.Va errno +is set to indicated the reason. +.Sh ERRORS +Access to the named file is revoked unless one of the following: +.Bl -tag -width Er +.It Bq Er ENOTDIR +A component of the path prefix is not a directory. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded 255 characters, +or an entire path name exceeded 1024 characters. +.It Bq Er ENOENT +The named file or a component of the path name does not exist. +.It Bq Er EACCES +Search permission is denied for a component of the path prefix. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating the pathname. +.It Bq Er EFAULT +.Fa Path +points outside the process's allocated address space. +.It Bq Er EINVAL +The named file is neither a character special or block +special file. +.It Bq Er EPERM +The caller is neither the owner of the file nor the super user. +.El +.Sh SEE ALSO +.Xr close 2 +.Sh HISTORY +The +.Nm revoke +function was introduced in +.Bx 4.3 Reno . diff --git a/bsd/man/man2/rmdir.2 b/bsd/man/man2/rmdir.2 new file mode 100644 index 000000000..8a8d595b2 --- /dev/null +++ b/bsd/man/man2/rmdir.2 @@ -0,0 +1,109 @@ +.\" $NetBSD: rmdir.2,v 1.7 1995/02/27 12:36:30 cgd Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)rmdir.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt RMDIR 2 +.Os BSD 4.2 +.Sh NAME +.Nm rmdir +.Nd remove a directory file +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn rmdir "const char *path" +.Sh DESCRIPTION +.Fn Rmdir +removes a directory file +whose name is given by +.Fa path . +The directory must not have any entries other +than +.Ql \&. +and +.Ql \&.. . +.Sh RETURN VALUES +A 0 is returned if the remove succeeds; otherwise a -1 is +returned and an error code is stored in the global location +.Va errno . +.Sh ERRORS +The named file is removed unless: +.Bl -tag -width Er +.It Bq Er ENOTDIR +A component of the path is not a directory. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded +.Dv {NAME_MAX} +characters, or an entire path name exceeded +.Dv {PATH_MAX} +characters. +.It Bq Er ENOENT +The named directory does not exist. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating the pathname. +.It Bq Er ENOTEMPTY +The named directory contains files other than +.Ql \&. +and +.Ql \&.. +in it. +.It Bq Er EACCES +Search permission is denied for a component of the path prefix. +.It Bq Er EACCES +Write permission is denied on the directory containing the link +to be removed. +.It Bq Er EPERM +The directory containing the directory to be removed is marked sticky, +and neither the containing directory nor the directory to be removed +are owned by the effective user ID. +.It Bq Er EBUSY +The directory to be removed is the mount point +for a mounted file system. +.It Bq Er EIO +An I/O error occurred while deleting the directory entry +or deallocating the inode. +.It Bq Er EROFS +The directory entry to be removed resides on a read-only file system. +.It Bq Er EFAULT +.Fa Path +points outside the process's allocated address space. +.El +.Sh SEE ALSO +.Xr mkdir 2 , +.Xr unlink 2 +.Sh HISTORY +The +.Fn rmdir +function call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/sbrk.2 b/bsd/man/man2/sbrk.2 new file mode 100644 index 000000000..a3711a537 --- /dev/null +++ b/bsd/man/man2/sbrk.2 @@ -0,0 +1 @@ +.so man2/brk.2 diff --git a/bsd/man/man2/select.2 b/bsd/man/man2/select.2 new file mode 100644 index 000000000..cc00e641d --- /dev/null +++ b/bsd/man/man2/select.2 @@ -0,0 +1,192 @@ +.\" $NetBSD: select.2,v 1.5 1995/06/27 22:32:28 cgd Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)select.2 8.2 (Berkeley) 3/25/94 +.\" +.Dd March 25, 1994 +.Dt SELECT 2 +.Os BSD 4.2 +.Sh NAME +.Nm select +.Nd synchronous I/O multiplexing +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Fd #include +.Ft int +.Fn select "int nfds" "fd_set *readfds" "fd_set *writefds" "fd_set *exceptfds" "struct timeval *timeout" +.Fn FD_SET fd &fdset +.Fn FD_CLR fd &fdset +.Fn FD_ISSET fd &fdset +.Fn FD_ZERO &fdset +.Sh DESCRIPTION +.Fn Select +examines the I/O descriptor sets whose addresses are passed in +.Fa readfds , +.Fa writefds , +and +.Fa exceptfds +to see if some of their descriptors +are ready for reading, are ready for writing, or have an exceptional +condition pending, respectively. +The first +.Fa nfds +descriptors are checked in each set; +i.e., the descriptors from 0 through +.Fa nfds Ns No -1 +in the descriptor sets are examined. +On return, +.Fn select +replaces the given descriptor sets +with subsets consisting of those descriptors that are ready +for the requested operation. +.Fn Select +returns the total number of ready descriptors in all the sets. +.Pp +The descriptor sets are stored as bit fields in arrays of integers. +The following macros are provided for manipulating such descriptor sets: +.Fn FD_ZERO &fdset +initializes a descriptor set +.Fa fdset +to the null set. +.Fn FD_SET fd &fdset +includes a particular descriptor +.Fa fd +in +.Fa fdset . +.Fn FD_CLR fd &fdset +removes +.Fa fd +from +.Fa fdset . +.Fn FD_ISSET fd &fdset +is non-zero if +.Fa fd +is a member of +.Fa fdset , +zero otherwise. +The behavior of these macros is undefined if +a descriptor value is less than zero or greater than or equal to +.Dv FD_SETSIZE , +which is normally at least equal +to the maximum number of descriptors supported by the system. +.Pp +If +.Fa timeout +is a non-nil pointer, it specifies a maximum interval to wait for the +selection to complete. If +.Fa timeout +is a nil pointer, the select blocks indefinitely. To effect a poll, the +.Fa timeout +argument should be non-nil, pointing to a zero-valued timeval structure. +.Fa Timeout +is not changed by +.Fn select , +and may be reused on subsequent calls, however it is good style to re-initialize +it before each invocation of +.Fn select . +.Pp +Any of +.Fa readfds , +.Fa writefds , +and +.Fa exceptfds +may be given as nil pointers if no descriptors are of interest. +.Sh RETURN VALUES +.Fn Select +returns the number of ready descriptors that are contained in +the descriptor sets, +or -1 if an error occurred. +If the time limit expires, +.Fn select +returns 0. +If +.Fn select +returns with an error, +including one due to an interrupted call, +the descriptor sets will be unmodified. +.Sh ERRORS +An error return from +.Fn select +indicates: +.Bl -tag -width Er +.It Bq Er EBADF +One of the descriptor sets specified an invalid descriptor. +.It Bq Er EINTR +A signal was delivered before the time limit expired and +before any of the selected events occurred. +.It Bq Er EINVAL +The specified time limit is invalid. One of its components is +negative or too large. +.El +.Sh SEE ALSO +.Xr accept 2 , +.Xr connect 2 , +.Xr getdtablesize 2 , +.Xr gettimeofday 2 , +.Xr read 2 , +.Xr recv 2 , +.Xr send 2 , +.Xr write 2 +.Sh BUGS +Although the provision of +.Xr getdtablesize 2 +was intended to allow user programs to be written independent +of the kernel limit on the number of open files, the dimension +of a sufficiently large bit field for select remains a problem. +The default size +.Dv FD_SETSIZE +(currently 1024) is somewhat smaller than +the current kernel limit to the number of open files. +However, in order to accommodate programs which might potentially +use a larger number of open files with select, it is possible +to increase this size within a program by providing +a larger definition of +.Dv FD_SETSIZE +before the inclusion of +.Aq Pa sys/types.h . +.Pp +.Fn Select +should probably have been designed to return the time remaining from the +original timeout, if any, by modifying the time value in place. +However, it is unlikely this semantic will ever be implemented, as the +change would cause source code compatibility problems. +In general it is unwise to assume that the timeout value will be +unmodified by the +.Fn select +call, and the caller should reinitialize it on each invocation. +.Sh HISTORY +The +.Fn select +function call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/send.2 b/bsd/man/man2/send.2 new file mode 100644 index 000000000..2d9daca68 --- /dev/null +++ b/bsd/man/man2/send.2 @@ -0,0 +1,168 @@ +.\" $NetBSD: send.2,v 1.6 1996/01/15 01:17:18 thorpej Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)send.2 8.2 (Berkeley) 2/21/94 +.\" +.Dd February 21, 1994 +.Dt SEND 2 +.Os BSD 4.2 +.Sh NAME +.Nm send , +.Nm sendto , +.Nm sendmsg +.Nd send a message from a socket +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft ssize_t +.Fn send "int s" "const void *msg" "size_t len" "int flags" +.Ft ssize_t +.Fn sendto "int s" "const void *msg" "size_t len" "int flags" "const struct sockaddr *to" "int tolen" +.Ft ssize_t +.Fn sendmsg "int s" "const struct msghdr *msg" "int flags" +.Sh DESCRIPTION +.Fn Send , +.Fn sendto , +and +.Fn sendmsg +are used to transmit a message to another socket. +.Fn Send +may be used only when the socket is in a +.Em connected +state, while +.Fn sendto +and +.Fn sendmsg +may be used at any time. +.Pp +The address of the target is given by +.Fa to +with +.Fa tolen +specifying its size. +The length of the message is given by +.Fa len . +If the message is too long to pass atomically through the +underlying protocol, the error +.Er EMSGSIZE +is returned, and +the message is not transmitted. +.Pp +No indication of failure to deliver is implicit in a +.Fn send . +Locally detected errors are indicated by a return value of -1. +.Pp +If no messages space is available at the socket to hold +the message to be transmitted, then +.Fn send +normally blocks, unless the socket has been placed in +non-blocking I/O mode. +The +.Xr select 2 +call may be used to determine when it is possible to +send more data. +.Pp +The +.Fa flags +parameter may include one or more of the following: +.Bd -literal +#define MSG_OOB 0x1 /* process out-of-band data */ +#define MSG_DONTROUTE 0x4 /* bypass routing, use direct interface */ +.Ed +.Pp +The flag +.Dv MSG_OOB +is used to send +.Dq out-of-band +data on sockets that support this notion (e.g. +.Dv SOCK_STREAM ) ; +the underlying protocol must also support +.Dq out-of-band +data. +.Dv MSG_DONTROUTE +is usually used only by diagnostic or routing programs. +.Pp +See +.Xr recv 2 +for a description of the +.Fa msghdr +structure. +.Sh RETURN VALUES +The call returns the number of characters sent, or -1 +if an error occurred. +.Sh ERRORS +.Fn Send , +.Fn sendto , +and +.Fn sendmsg +fail if: +.Bl -tag -width Er +.It Bq Er EBADF +An invalid descriptor was specified. +.It Bq Er ENOTSOCK +The argument +.Fa s +is not a socket. +.It Bq Er EFAULT +An invalid user space address was specified for a parameter. +.It Bq Er EMSGSIZE +The socket requires that message be sent atomically, +and the size of the message to be sent made this impossible. +.It Bq Er EAGAIN +The socket is marked non-blocking and the requested operation +would block. +.It Bq Er ENOBUFS +The system was unable to allocate an internal buffer. +The operation may succeed when buffers become available. +.It Bq Er ENOBUFS +The output queue for a network interface was full. +This generally indicates that the interface has stopped sending, +but may be caused by transient congestion. +.It Bq Er EACCES +The SO_BROADCAST option is not set on the socket, and a broadcast address +was given as the destination. +.It Bq Er EHOSTUNREACH +The destination address specified an unreachable host. +.El +.Sh SEE ALSO +.Xr fcntl 2 , +.Xr recv 2 , +.Xr select 2 , +.Xr getsockopt 2 , +.Xr socket 2 , +.Xr write 2 +.Sh HISTORY +The +.Fn send +function call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/sendmsg.2 b/bsd/man/man2/sendmsg.2 new file mode 100644 index 000000000..9a61b33bb --- /dev/null +++ b/bsd/man/man2/sendmsg.2 @@ -0,0 +1 @@ +.so man2/send.2 diff --git a/bsd/man/man2/sendto.2 b/bsd/man/man2/sendto.2 new file mode 100644 index 000000000..9a61b33bb --- /dev/null +++ b/bsd/man/man2/sendto.2 @@ -0,0 +1 @@ +.so man2/send.2 diff --git a/bsd/man/man2/setegid.2 b/bsd/man/man2/setegid.2 new file mode 100644 index 000000000..24656c29f --- /dev/null +++ b/bsd/man/man2/setegid.2 @@ -0,0 +1 @@ +.so man2/setuid.2 diff --git a/bsd/man/man2/seteuid.2 b/bsd/man/man2/seteuid.2 new file mode 100644 index 000000000..24656c29f --- /dev/null +++ b/bsd/man/man2/seteuid.2 @@ -0,0 +1 @@ +.so man2/setuid.2 diff --git a/bsd/man/man2/setgid.2 b/bsd/man/man2/setgid.2 new file mode 100644 index 000000000..24656c29f --- /dev/null +++ b/bsd/man/man2/setgid.2 @@ -0,0 +1 @@ +.so man2/setuid.2 diff --git a/bsd/man/man2/setgroups.2 b/bsd/man/man2/setgroups.2 new file mode 100644 index 000000000..1547f7027 --- /dev/null +++ b/bsd/man/man2/setgroups.2 @@ -0,0 +1,88 @@ +.\" $NetBSD: setgroups.2,v 1.7 1995/02/27 12:36:49 cgd Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993, 1994 +.\" 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. +.\" +.\" @(#)setgroups.2 8.2 (Berkeley) 4/16/94 +.\" +.Dd April 16, 1994 +.Dt SETGROUPS 2 +.Os BSD 4.2 +.Sh NAME +.Nm setgroups +.Nd set group access list +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn setgroups "int ngroups" "const gid_t *gidset" +.Sh DESCRIPTION +.Fn Setgroups +sets the group access list of the current user process +according to the array +.Fa gidset . +The parameter +.Fa ngroups +indicates the number of entries in the array and must be no +more than +.Dv {NGROUPS_MAX} . +.Pp +Only the super-user may set new groups. +.Sh RETURN VALUES +A 0 value is returned on success, -1 on error, with +an error code stored in +.Va errno . +.Sh ERRORS +The +.Fn setgroups +call will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The value of +.Fa ngroups +is greater than +.Dv {NGROUPS_MAX} . +.It Bq Er EPERM +The caller is not the super-user. +.It Bq Er EFAULT +The address specified for +.Fa gidset +is outside the process +address space. +.El +.Sh SEE ALSO +.Xr getgroups 2 , +.Xr initgroups 3 +.Sh HISTORY +The +.Fn setgroups +function call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/setitimer.2 b/bsd/man/man2/setitimer.2 new file mode 100644 index 000000000..9518567e0 --- /dev/null +++ b/bsd/man/man2/setitimer.2 @@ -0,0 +1 @@ +.so man2/getitimer.2 diff --git a/bsd/man/man2/setlogin.2 b/bsd/man/man2/setlogin.2 new file mode 100644 index 000000000..bec338046 --- /dev/null +++ b/bsd/man/man2/setlogin.2 @@ -0,0 +1 @@ +.so man2/getlogin.2 diff --git a/bsd/man/man2/setpgid.2 b/bsd/man/man2/setpgid.2 new file mode 100644 index 000000000..6b2cdbd94 --- /dev/null +++ b/bsd/man/man2/setpgid.2 @@ -0,0 +1,100 @@ +.\" $NetBSD: setpgid.2,v 1.8 1995/02/27 12:36:55 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.\" @(#)setpgid.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt SETPGID 2 +.Os BSD 4 +.Sh NAME +.Nm setpgid , +.Nm setpgrp +.Nd set process group +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn setpgid "pid_t pid" "pid_t pgrp" +.Ft int +.Fn setpgrp "pid_t pid" "pid_t pgrp" +.Sh DESCRIPTION +.Fn Setpgid +sets the process group of the specified process +.Ar pid +to the specified +.Ar pgrp . +If +.Ar pid +is zero, then the call applies to the current process. +.Pp +If the invoker is not the super-user, then the affected process +must have the same effective user-id as the invoker or be a descendant +of the invoking process. +.Sh RETURN VALUES +.Fn Setpgid +returns 0 when the operation was successful. +If the request failed, -1 is returned and the global variable +.Va errno +indicates the reason. +.Sh ERRORS +.Fn Setpgid +will fail and the process group will not be altered if: +.Bl -tag -width Er +.It Bq Er EACCESS +The value of the +.Fa pid +argument matches the process ID of a child process of the calling process, +and the child process has successfully executed one of the exec functions. +.It Bq Er EPERM +The effective user ID of the requested process is different +from that of the caller and the process is not a descendant +of the calling process. +.It Bq Er ESRCH +The value of the +.Fa pid +argument does not match the process ID of the calling process or of a +child process of the calling process. +.El +.Sh SEE ALSO +.Xr getpgrp 2 +.Sh STANDARDS +The +.Fn setpgid +function conforms to +.St -p1003.1-88 . +.Sh COMPATIBILITY +.Fn Setpgrp +is identical to +.Fn setpgid , +and is retained for calling convention compatibility with historical +versions of +.Bx . diff --git a/bsd/man/man2/setpgrp.2 b/bsd/man/man2/setpgrp.2 new file mode 100644 index 000000000..d6b107a1c --- /dev/null +++ b/bsd/man/man2/setpgrp.2 @@ -0,0 +1 @@ +.so man2/setpgid.2 diff --git a/bsd/man/man2/setpriority.2 b/bsd/man/man2/setpriority.2 new file mode 100644 index 000000000..b1dcfd91d --- /dev/null +++ b/bsd/man/man2/setpriority.2 @@ -0,0 +1 @@ +.so man2/getpriority.2 diff --git a/bsd/man/man2/setrlimit.2 b/bsd/man/man2/setrlimit.2 new file mode 100644 index 000000000..df6d7362a --- /dev/null +++ b/bsd/man/man2/setrlimit.2 @@ -0,0 +1 @@ +.so man2/getrlimit.2 diff --git a/bsd/man/man2/setsid.2 b/bsd/man/man2/setsid.2 new file mode 100644 index 000000000..8f9018b57 --- /dev/null +++ b/bsd/man/man2/setsid.2 @@ -0,0 +1,82 @@ +.\" $NetBSD: setsid.2,v 1.3 1995/10/12 15:41:13 jtc Exp $ +.\" +.\" Copyright (c) 1991, 1993 +.\" 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. +.\" +.\" @(#)setsid.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt SETSID 2 +.Os +.Sh NAME +.Nm setsid +.Nd create session and set process group ID +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft pid_t +.Fn setsid "void" +.Sh DESCRIPTION +The +.Nm setsid +function creates a new session. +The calling process is the session leader of the new session, is the +process group leader of a new process group and has no controlling +terminal. +The calling process is the only process in either the session or the +process group. +.Pp +Upon successful completion, the +.Nm setsid +function returns the value of the process group ID of the new process +group, which is the same as the process ID of the calling process. +.Sh ERRORS +If an error occurs, +.Nm setsid +returns -1 and the global variable +.Va errno +is set to indicate the error, as follows: +.Bl -tag -width Er +.It Bq Er EPERM +The calling process is already a process group leader, or the process +group ID of a process other than the calling process matches the process +ID of the calling process. +.El +.Sh SEE ALSO +.Xr setpgid 3 , +.Xr tcgetpgrp 3 , +.Xr tcsetpgrp 3 +.Sh STANDARDS +The +.Nm setsid +function is expected to be compliant with the +.St -p1003.1-88 +specification. diff --git a/bsd/man/man2/setsockopt.2 b/bsd/man/man2/setsockopt.2 new file mode 100644 index 000000000..d98c7769b --- /dev/null +++ b/bsd/man/man2/setsockopt.2 @@ -0,0 +1 @@ +.so man2/getsockopt.2 diff --git a/bsd/man/man2/settimeofday.2 b/bsd/man/man2/settimeofday.2 new file mode 100644 index 000000000..2b6eff428 --- /dev/null +++ b/bsd/man/man2/settimeofday.2 @@ -0,0 +1 @@ +.so man2/gettimeofday.2 diff --git a/bsd/man/man2/setuid.2 b/bsd/man/man2/setuid.2 new file mode 100644 index 000000000..b271097c8 --- /dev/null +++ b/bsd/man/man2/setuid.2 @@ -0,0 +1,130 @@ +.\" $NetBSD: setuid.2,v 1.3 1995/02/27 12:37:06 cgd Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)setuid.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt SETUID 2 +.Os BSD 4.2 +.Sh NAME +.Nm setuid , +.Nm seteuid , +.Nm setgid , +.Nm setegid +.Nd set user and group ID +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn setuid "uid_t uid" +.Ft int +.Fn seteuid "uid_t euid" +.Ft int +.Fn setgid "gid_t gid" +.Ft int +.Fn setegid "gid_t egid" +.Sh DESCRIPTION +The +.Fn setuid +function +sets the real and effective +user IDs and the saved set-user-ID of the current process +to the specified value. +The +.Fn setuid +function is permitted if the effective user ID is that of the super user, +or if the specified user ID is the same as the effective user ID. If +not, but the specified user ID is the same as the real user ID, +.Fn setuid +will set the effective user ID to the real user ID. +.Pp +The +.Fn setgid +function +sets the real and effective +group IDs and the saved set-group-ID of the current process +to the specified value. +The +.Fn setgid +function is permitted if the effective user ID is that of the super user, +or if the specified group ID is the same as the effective group ID. If +not, but the specified group ID is the same as the real group ID, +.Fn setgid +will set the effective group ID to the real group ID. +.Pp +The +.Fn seteuid +function +.Pq Fn setegid +sets the effective user ID (group ID) of the +current process. +The effective user ID may be set to the value +of the real user ID or the saved set-user-ID (see +.Xr intro 2 +and +.Xr execve 2 ) ; +in this way, the effective user ID of a set-user-ID executable +may be toggled by switching to the real user ID, then re-enabled +by reverting to the set-user-ID value. +Similarly, the effective group ID may be set to the value +of the real group ID or the saved set-user-ID. +.Pp +.Sh RETURN VALUES +Upon success, these functions return 0; +otherwise \-1 is returned. +.Pp +If the user is not the super user, or the uid +specified is not the real, effective ID, or saved ID, +these functions return \-1. +.Sh SEE ALSO +.Xr getuid 2 , +.Xr getgid 2 +.Sh STANDARDS +The +.Fn setuid +and +.Fn setgid +functions are compliant with the +.St -p1003.1-90 +specification with +.Li _POSIX_SAVED_IDS +defined, with the extensions allowed in section B.4.2.2. +The +.Fn seteuid +and +.Fn setegid +functions are extensions based on the +.Tn POSIX +concept of +.Li _POSIX_SAVED_IDS , +and have been proposed for a future revision of the standard. diff --git a/bsd/man/man2/shmat.2 b/bsd/man/man2/shmat.2 new file mode 100644 index 000000000..7ed9d0449 --- /dev/null +++ b/bsd/man/man2/shmat.2 @@ -0,0 +1,118 @@ +.\" $OpenBSD: shmat.2,v 1.2 1996/10/08 01:20:15 michaels Exp $ +.\" $NetBSD: shmat.2,v 1.1 1995/10/16 23:49:29 jtc Exp $ +.\" +.\" Copyright (c) 1995 Frank van der Linden +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed for the NetBSD Project +.\" by Frank van der Linden +.\" 4. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\"/ +.Dd August 17, 1995 +.Dt SHMAT 2 +.Os +.Sh NAME +.Nm shmat , +.Nm shmdt +.Nd map/unmap shared memory +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Fd #include +.Ft void * +.Fn shmat "int shmid" "void *shmaddr" "int shmflg" +.Ft int +.Fn shmdt "void *shmaddr" +.Sh DESCRIPTION +.Fn shmat +maps the shared memory segment associated with the shared memory identifier +.Fa shmid +into the address space of the calling process. The address at which the +segment is mapped is determined by the +.Fa shmaddr +parameter. If it is equal to 0, the system will pick an address itself. +Otherwise, an attempt is made to map the shared memory segment at the +address +.Fa shmaddr +specifies. If SHM_RND is set in +.Fa shmflg , +the system will round the address down to a multiple of SHMLBA bytes +(SHMLBA is defined in +.Aq Pa sys/shm.h +). + +A shared memory segment can be mapped read-only by specifying the +SHM_RDONLY flag in +.Fa shmflg . + +.Fn shmdt +unmaps the shared memory segment that is currently mapped at +.Fa shmaddr +from the calling process' address space. +.Fa shmaddr +must be a value returned by a prior +.Fn shmat +call. A shared memory segment will remain existant until it is removed by +a call to +.Xr shmctl 2 +with the IPC_RMID command. +.Sh RETURN VALUES +.Fn shmat +returns the address at which the shared memory segment has been mapped into +the calling process' address space when successful, +.Fn shmdt +returns 0 on successful completion. Otherwise, a value of -1 is returned, +and the global variable +.Va errno +is set to indicate the error. +.Sh ERRORS +.Fn shmat +will fail if: +.Bl -tag -width Er +.It Bq Er EACCESS +The calling process has no permission to access this shared memory segment. +.It Bq Er ENOMEM +There is not enough available data space for the calling process to +map the shared memory segment. +.It Bq Er EINVAL +.Fa shmid +is not a valid shared memory identifier. + +.Fa shmaddr +specifies an illegal address. +.It Bq Er EMFILE +The number of shared memory segments has reached the system-wide limit. +.El + +.Fn shmdt +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +.Fa shmaddr +is not the start address of a mapped shared memory segment. +.Sh SEE ALSO +.Xr shmctl 2 , +.Xr shmget 2 , +.Xr mmap 2 diff --git a/bsd/man/man2/shmctl.2 b/bsd/man/man2/shmctl.2 new file mode 100644 index 000000000..036db38b3 --- /dev/null +++ b/bsd/man/man2/shmctl.2 @@ -0,0 +1,188 @@ +.\" $OpenBSD: shmctl.2,v 1.2 1996/10/08 01:20:15 michaels Exp $ +.\" $NetBSD: shmctl.2,v 1.1 1995/10/16 23:49:30 jtc Exp $ +.\" +.\" Copyright (c) 1995 Frank van der Linden +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed for the NetBSD Project +.\" by Frank van der Linden +.\" 4. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\"/ +.Dd August 17, 1995 +.Dt SHMCTL 2 +.Os +.Sh NAME +.Nm shmctl +.Nd shared memory control operations +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Fd #include +.Ft int +.Fn shmctl "int shmid" "int cmd" "struct shmid_ds *buf" +.Sh DESCRIPTION +The +.Fn shmctl +system call performs some control operations on the shared memory area +specified by +.Fa shmid . + +Each shared memory segment has a data structure associated with it, +parts of which may be altered by +.Fn shmctl +and parts of which determine the actions of +.Fn shmctl . + +This structure is defined as follows in +.Aq Pa sys/shm.h : +.Bd -literal +struct shmid_ds { + struct ipc_perm shm_perm; /* operation permissions */ + int shm_segsz; /* size of segment in bytes */ + pid_t shm_lpid; /* pid of last shm op */ + pid_t shm_cpid; /* pid of creator */ + short shm_nattch; /* # of current attaches */ + time_t shm_atime; /* last shmat() time*/ + time_t shm_dtime; /* last shmdt() time */ + time_t shm_ctime; /* last change by shmctl() */ + void *shm_internal; /* sysv stupidity */ +}; +.Ed +The +.Bf -literal +ipc_perm +.Ef +structure used inside the +.Bf -literal +shmid_ds +.Ef +structure is defined in +.Aq Pa sys/ipc.h +and looks like this: +.Bd -literal +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 (see chmod(2)) */ + ushort seq; /* sequence # (to generate unique msg/sem/shm id) */ + key_t key; /* user specified msg/sem/shm key */ +}; +.Ed + +The operation to be performed by +.Fn shmctl +is specified in +.Fa cmd +and is one of: +.Bl -tag -width IPC_RMIDX +.It Dv IPC_STAT +Gather information about the shared memory segment and place it in the +structure pointed to by +.Fa buf . +.It Dv IPC_SET +Set the value of the +.Va shm_perm.uid , +.Va shm_perm.gid +and +.Va shm_perm.mode +fields in the structure associated with +.Fa shmid . +The values are taken from the corresponding fields in the structure +pointed to by +.Fa buf . +This operation can only be executed by the super-user, or a process that +has an effective user id equal to either +.Va shm_perm.cuid +or +.Va shm_perm.uid +in the data structure associated with the shared memory segment. + +.It Dv IPC_RMID +Remove the shared memory segment specified by +.Fa shmid +and destroy the data associated with it. Only the super-user or a process +with an effective uid equal to the +.Va shm_perm.cuid +or +.Va shm_perm.uid +values in the data structure associated with the queue can do this. +.El + +The read and write permissions on a shared memory identifier +are determined by the +.Va shm_perm.mode +field in the same way as is +done with files (see +.Xr chmod 2 ), +but the effective uid can match either the +.Va shm_perm.cuid +field or the +.Va shm_perm.uid +field, and the +effective gid can match either +.Va shm_perm.cgid +or +.Va shm_perm.gid . +.Sh RETURN VALUES +Upon successful completion, a value of 0 is returned. Otherwise, -1 is +returned and the global variable +.Va errno +is set to indicate the error. +.Sh ERRORS +.Fn shmctl +will fail if: +.Bl -tag -width Er +.It Bq Er EPERM +.Fa cmd +is equal to IPC_SET or IPC_RMID and the caller is not the super-user, nor does +the effective uid match either the +.Va shm_perm.uid +or +.Va shm_perm.cuid +fields of the data structure associated with the shared memory segment. + +An attempt is made to increase the value of +.Va shm_qbytes +through IPC_SET +but the caller is not the super-user. +.It Bq Er EACCESS +The command is IPC_STAT +and the caller has no read permission for this shared memory segment. +.It Bq Er EINVAL +.Fa shmid +is not a valid shared memory segment identifier. + +.Va cmd +is not a valid command. +.It Bq Er EFAULT +.Fa buf +specifies an invalid address. +.El +.Sh SEE ALSO +.Xr shmat 2 , +.Xr shmdt 2 , +.Xr shmget 2 diff --git a/bsd/man/man2/shmdt.2 b/bsd/man/man2/shmdt.2 new file mode 100644 index 000000000..41c1535a6 --- /dev/null +++ b/bsd/man/man2/shmdt.2 @@ -0,0 +1 @@ +.so man2/shmat.2 diff --git a/bsd/man/man2/shmget.2 b/bsd/man/man2/shmget.2 new file mode 100644 index 000000000..55ad6fbdd --- /dev/null +++ b/bsd/man/man2/shmget.2 @@ -0,0 +1,125 @@ +.\" $OpenBSD: shmget.2,v 1.2 1996/10/08 01:20:16 michaels Exp $ +.\" $NetBSD: shmget.2,v 1.1 1995/10/16 23:49:32 jtc Exp $ +.\" +.\" Copyright (c) 1995 Frank van der Linden +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed for the NetBSD Project +.\" by Frank van der Linden +.\" 4. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\"/ +.Dd August 17, 1995 +.Dt SHMGET 2 +.Os +.Sh NAME +.Nm shmget +.Nd get shared memory area identifier +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Fd #include +.Ft int +.Fn shmget "key_t key" "int size" "int shmflg" +.Sh DESCRIPTION +.Fn shmget +returns the shared memory identifier associated with the key +.Fa key . + +A shared memory segment is created if either +.Fa key +is equal to IPC_PRIVATE, or +.Fa key +does not have a shared memory segment identifier associated with it, and the IPC_CREAT +bit is set in +.Fa shmflg. + +If a new shared memory segment is created, the data structure associated with it (the +.Va shmid_ds +structure, see +.Xr shmctl 2 ) +is initialized as follows: +.Bl -bullet +.It +.Va shm_perm.cuid +and +.Va shm_perm.uid +are set to the effective uid of the calling process. +.It +.Va shm_perm.gid +and +.Va shm_perm.cgid +are set to the effective gid of the calling process. +.It +.Va shm_perm.mode +is set to the lower 9 bits of +.Fa shmflg . +.It +.Va shm_lpid , +.Va shm_nattch , +.Va shm_atime , +and +.Va shm_dtime +are set to 0 +.It +.Va shm_ctime +is set to the current time. +.It +.Va shm_segsz +is set to the value of +.Fa size . +.El +.Sh RETURN VALUES +Upon successful completion a positive shared memory segment identifier is returned. +Otherwise, -1 is returned and the global variable +.Va errno +is set to indicate the error. +.Sh ERRORS +.Bl -tag -width Er +.It Bq Er EACESS +A shared memory segment is already associated with +.Fa key +and the caller has no permission to access it. +.It Bq Er EEXIST +Both IPC_CREAT and IPC_EXCL are set in +.Fa shmflg , +and a shared memory segment is already associated with +.Fa key . +.It Bq Er ENOSPC +A new shared memory indentifier could not be created because the system limit +for the number of shared memory identifiers has been reached. +.It Bq Er ENOENT +IPC_CREAT was not set in +.Fa shmflg +and no shared memory segment associated with +.Fa key +was found. +.It Bq Er ENOMEM +There is not enough memory left to created a shared memory segment of the +requested size. +.El +.Sh SEE ALSO +.Xr shmctl 2 , +.Xr shmat 2 , +.Xr shmdt 2 diff --git a/bsd/man/man2/shutdown.2 b/bsd/man/man2/shutdown.2 new file mode 100644 index 000000000..927e3bdf3 --- /dev/null +++ b/bsd/man/man2/shutdown.2 @@ -0,0 +1,83 @@ +.\" $NetBSD: shutdown.2,v 1.5 1995/02/27 12:37:11 cgd Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)shutdown.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt SHUTDOWN 2 +.Os BSD 4.2 +.Sh NAME +.Nm shutdown +.Nd shut down part of a full-duplex connection +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn shutdown "int s" "int how" +.Sh DESCRIPTION +The +.Fn shutdown +call causes all or part of a full-duplex connection on +the socket associated with +.Fa s +to be shut down. +If +.Fa how +is 0, further receives will be disallowed. +If +.Fa how +is 1, further sends will be disallowed. +If +.Fa how +is 2, further sends and receives will be disallowed. +.Sh DIAGNOSTICS +A 0 is returned if the call succeeds, -1 if it fails. +.Sh ERRORS +The call succeeds unless: +.Bl -tag -width Er +.It Bq Er EBADF +.Fa S +is not a valid descriptor. +.It Bq Er ENOTSOCK +.Fa S +is a file, not a socket. +.It Bq Er ENOTCONN +The specified socket is not connected. +.El +.Sh SEE ALSO +.Xr connect 2 , +.Xr socket 2 +.Sh HISTORY +The +.Fn shutdown +function call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/sigaction.2 b/bsd/man/man2/sigaction.2 new file mode 100644 index 000000000..24435274a --- /dev/null +++ b/bsd/man/man2/sigaction.2 @@ -0,0 +1,395 @@ +.\" $NetBSD: sigaction.2,v 1.7 1995/10/12 15:41:16 jtc Exp $ +.\" +.\" Copyright (c) 1980, 1990, 1993 +.\" 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. +.\" +.\" @(#)sigaction.2 8.2 (Berkeley) 4/3/94 +.\" +.Dd April 3, 1994 +.Dt SIGACTION 2 +.Os +.Sh NAME +.Nm sigaction +.Nd software signal facilities +.Sh SYNOPSIS +.Fd #include +.Bd -literal +struct sigaction { + void (*sa_handler)(); + sigset_t sa_mask; + int sa_flags; +}; +.Ed +.Ft int +.Fn sigaction "int sig" "const struct sigaction *act" "struct sigaction *oact" +.Sh DESCRIPTION +The system defines a set of signals that may be delivered to a process. +Signal delivery resembles the occurrence of a hardware interrupt: +the signal is blocked from further occurrence, the current process +context is saved, and a new one is built. A process may specify a +.Em handler +to which a signal is delivered, or specify that a signal is to be +.Em ignored . +A process may also specify that a default action is to be taken +by the system when a signal occurs. +A signal may also be +.Em blocked , +in which case its delivery is postponed until it is +.Em unblocked . +The action to be taken on delivery is determined at the time +of delivery. +Normally, signal handlers execute on the current stack +of the process. This may be changed, on a per-handler basis, +so that signals are taken on a special +.Em "signal stack" . +.Pp +Signal routines execute with the signal that caused their +invocation +.Em blocked , +but other signals may yet occur. +A global +.Em "signal mask" +defines the set of signals currently blocked from delivery +to a process. The signal mask for a process is initialized +from that of its parent (normally empty). It +may be changed with a +.Xr sigprocmask 2 +call, or when a signal is delivered to the process. +.Pp +When a signal +condition arises for a process, the signal is added to a set of +signals pending for the process. +If the signal is not currently +.Em blocked +by the process then it is delivered to the process. +Signals may be delivered any time a process enters the operating system +(e.g., during a system call, page fault or trap, or clock interrupt). +If multiple signals are ready to be delivered at the same time, +any signals that could be caused by traps are delivered first. +Additional signals may be processed at the same time, with each +appearing to interrupt the handlers for the previous signals +before their first instructions. +The set of pending signals is returned by the +.Xr sigpending 2 +function. +When a caught signal +is delivered, the current state of the process is saved, +a new signal mask is calculated (as described below), +and the signal handler is invoked. The call to the handler +is arranged so that if the signal handling routine returns +normally the process will resume execution in the context +from before the signal's delivery. +If the process wishes to resume in a different context, then it +must arrange to restore the previous context itself. +.Pp +When a signal is delivered to a process a new signal mask is +installed for the duration of the process' signal handler +(or until a +.Xr sigprocmask +call is made). +This mask is formed by taking the union of the current signal mask set, +the signal to be delivered, and +the signal mask associated with the handler to be invoked. +.Pp +.Fn Sigaction +assigns an action for a specific signal. +If +.Fa act +is non-zero, it +specifies an action +.Pf ( Dv SIG_DFL , +.Dv SIG_IGN , +or a handler routine) and mask +to be used when delivering the specified signal. +If +.Fa oact +is non-zero, the previous handling information for the signal +is returned to the user. +.Pp +Once a signal handler is installed, it remains installed +until another +.Fn sigaction +call is made, or an +.Xr execve 2 +is performed. +A signal-specific default action may be reset by +setting +.Fa sa_handler +to +.Dv SIG_DFL . +The defaults are process termination, possibly with core dump; +no action; stopping the process; or continuing the process. +See the signal list below for each signal's default action. +If +.Fa sa_handler +is +.Dv SIG_DFL , +the default action for the signal is to discard the signal, +and if a signal is pending, +the pending signal is discarded even if the signal is masked. +If +.Fa sa_handler +is set to +.Dv SIG_IGN +current and pending instances +of the signal are ignored and discarded. +.Pp +Options may be specified by setting +.Em sa_flags . +If the +.Dv SA_NOCLDSTOP +bit is set when installing a catching function +for the +.Dv SIGCHLD +signal, +the +.Dv SIGCHLD +signal will be generated only when a child process exits, +not when a child process stops. +Further, if the +.Dv SA_ONSTACK +bit is set in +.Em sa_flags , +the system will deliver the signal to the process on a +.Em "signal stack" , +specified with +.Xr sigstack 2 . +.Pp +Finally, the +.Dv SA_SIGINFO +option causes the 2nd argument for the signal handler to be a pointer +to a +.Em siginfo_t +as described in +.Pa . +The +.Em siginfo_t +is a part of +.St -p1003.1b . +and provides much more information about the causes and +attributes of the signal that is being delivered. +.Pp +If a signal is caught during the system calls listed below, +the call may be forced to terminate +with the error +.Dv EINTR , +the call may return with a data transfer shorter than requested, +or the call may be restarted. +Restart of pending calls is requested +by setting the +.Dv SA_RESTART +bit in +.Ar sa_flags . +The affected system calls include +.Xr open 2 , +.Xr read 2 , +.Xr write 2 , +.Xr sendto 2 , +.Xr recvfrom 2 , +.Xr sendmsg 2 +and +.Xr recvmsg 2 +on a communications channel or a slow device (such as a terminal, +but not a regular file) +and during a +.Xr wait 2 +or +.Xr ioctl 2 . +However, calls that have already committed are not restarted, +but instead return a partial success (for example, a short read count). +.Pp +After a +.Xr fork 2 +or +.Xr vfork 2 +all signals, the signal mask, the signal stack, +and the restart/interrupt flags are inherited by the child. +.Pp +.Xr Execve 2 +reinstates the default +action for all signals which were caught and +resets all signals to be caught on the user stack. +Ignored signals remain ignored; +the signal mask remains the same; +signals that restart pending system calls continue to do so. +.Pp +The following is a list of all signals +with names as in the include file +.Aq Pa signal.h : +.Bl -column SIGVTALARMXX "create core imagexxx" +.It Sy " NAME " " Default Action " " Description" +.It Dv SIGHUP No " terminate process" " terminal line hangup" +.It Dv SIGINT No " terminate process" " interrupt program" +.It Dv SIGQUIT No " create core image" " quit program" +.It Dv SIGILL No " create core image" " illegal instruction" +.It Dv SIGTRAP No " create core image" " trace trap" +.It Dv SIGABRT No " create core image" Xr abort 2 +call (formerly +.Dv SIGIOT ) +.It Dv SIGEMT No " create core image" " emulate instruction executed" +.It Dv SIGFPE No " create core image" " floating-point exception" +.It Dv SIGKILL No " terminate process" " kill program" +.It Dv SIGBUS No " create core image" " bus error" +.It Dv SIGSEGV No " create core image" " segmentation violation" +.It Dv SIGSYS No " create core image" " system call given invalid argument" +.It Dv SIGPIPE No " terminate process" " write on a pipe with no reader" +.It Dv SIGALRM No " terminate process" " real-time timer expired" +.It Dv SIGTERM No " terminate process" " software termination signal" +.It Dv SIGURG No " discard signal" " urgent condition present on socket" +.It Dv SIGSTOP No " stop process" " stop (cannot be caught or ignored)" +.It Dv SIGTSTP No " stop process" " stop signal generated from keyboard" +.It Dv SIGCONT No " discard signal" " continue after stop" +.It Dv SIGCHLD No " discard signal" " child status has changed" +.It Dv SIGTTIN No " stop process" " background read attempted from control terminal" +.It Dv SIGTTOU No " stop process" " background write attempted to control terminal" +.It Dv SIGIO No " discard signal" Tn " I/O" +is possible on a descriptor (see +.Xr fcntl 2 ) +.It Dv SIGXCPU No " terminate process" " cpu time limit exceeded (see" +.Xr setrlimit 2 ) +.It Dv SIGXFSZ No " terminate process" " file size limit exceeded (see" +.Xr setrlimit 2 ) +.It Dv SIGVTALRM No " terminate process" " virtual time alarm (see" +.Xr setitimer 2 ) +.It Dv SIGPROF No " terminate process" " profiling timer alarm (see" +.Xr setitimer 2 ) +.It Dv SIGWINCH No " discard signal" " Window size change" +.It Dv SIGINFO No " discard signal" " status request from keyboard" +.It Dv SIGUSR1 No " terminate process" " User defined signal 1" +.It Dv SIGUSR2 No " terminate process" " User defined signal 2" +.El +.Sh NOTE +The mask specified in +.Fa act +is not allowed to block +.Dv SIGKILL +or +.Dv SIGSTOP . +This is done silently by the system. +.Sh RETURN VALUES +A 0 value indicated that the call succeeded. A \-1 return value +indicates an error occurred and +.Va errno +is set to indicated the reason. +.Sh EXAMPLE +The handler routine can be declared: +.Bd -literal -offset indent +void handler(sig, sip, scp) +int sig; +siginfo_t *sip; +struct sigcontext *scp; +.Ed +.Pp +Here +.Fa sig +is the signal number, into which the hardware faults and traps are +mapped. +If the +.Dv SA_SIGINFO +option is set, +.Fa sip +is a pointer to a +.Dv siginfo_t +as described in +.Pa . +If +.Dv SA_SIGINFO +is not set, this is NULL. +.Fa Scp +is a pointer to the +.Fa sigcontext +structure (defined in +.Aq Pa signal.h ) , +used to restore the context from before the signal. +.Sh ERRORS +.Fn Sigaction +will fail and no new signal handler will be installed if one +of the following occurs: +.Bl -tag -width Er +.It Bq Er EFAULT +Either +.Fa act +or +.Fa oact +points to memory that is not a valid part of the process +address space. +.It Bq Er EINVAL +.Fa Sig +is not a valid signal number. +.It Bq Er EINVAL +An attempt is made to ignore or supply a handler for +.Dv SIGKILL +or +.Dv SIGSTOP . +.El +.Sh STANDARDS +The +.Nm sigaction +function is defined by +.St -p1003.1-88 . +The +.Dv SA_ONSTACK +and +.Dv SA_RESTART +flags are Berkeley extensions, +as are the signals, +.Dv SIGTRAP , +.Dv SIGEMT , +.Dv SIGBUS , +.Dv SIGSYS , +.Dv SIGURG , +.Dv SIGIO , +.Dv SIGXCPU , +.Dv SIGXFSZ , +.Dv SIGVTALRM , +.Dv SIGPROF , +.Dv SIGWINCH , +and +.Dv SIGINFO . +Those signals are available on most +.Tn BSD Ns \-derived +systems. +.Sh SEE ALSO +.Xr kill 1 , +.Xr ptrace 2 , +.Xr kill 2 , +.Xr sigaction 2 , +.Xr sigprocmask 2 , +.Xr sigsuspend 2 , +.Xr sigblock 2 , +.Xr sigsetmask 2 , +.Xr sigpause 2 , +.Xr sigstack 2 , +.Xr sigvec 3 , +.Xr setjmp 3 , +.Xr siginterrupt 3 , +.Xr sigsetops 3 , +.Xr tty 4 diff --git a/bsd/man/man2/sigaltstack.2 b/bsd/man/man2/sigaltstack.2 new file mode 100644 index 000000000..dba3f28db --- /dev/null +++ b/bsd/man/man2/sigaltstack.2 @@ -0,0 +1,167 @@ +.\" $NetBSD: sigaltstack.2,v 1.3 1995/02/27 10:41:52 cgd Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1992, 1993 +.\" 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. +.\" +.\" @(#)sigaltstack.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt SIGALTSTACK 2 +.Os BSD 4.2 +.Sh NAME +.Nm sigaltstack +.Nd set and/or get signal stack context +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Bd -literal +struct sigaltstack { + char *ss_sp; + int ss_size; + int ss_flags; +}; +.Ed +.Ft int +.Fn sigaltstack "const struct sigaltstack *ss" "struct sigaltstack *oss" +.Sh DESCRIPTION +.Fn Sigaltstack +allows users to define an alternate stack on which signals +are to be processed. +If +.Fa ss +is non-zero, +it specifies a pointer to and the size of a +.Em "signal stack" +on which to deliver signals, +and tells the system if the process is currently executing +on that stack. +When a signal's action indicates its handler +should execute on the signal stack (specified with a +.Xr sigaction 2 +call), the system checks to see +if the process is currently executing on that stack. +If the process is not currently executing on the signal stack, +the system arranges a switch to the signal stack for the +duration of the signal handler's execution. +.Pp +If +.Dv SA_DISABLE +is set in +.Fa ss_flags , +.Fa ss_sp +and +.Fa ss_size +are ignored and the signal stack will be disabled. +Trying to disable an active stack will cause +.Nm +to return -1 with +.Va errno +set to +.Dv EINVAL . +A disabled stack will cause all signals to be +taken on the regular user stack. +If the stack is later re-enabled then all signals that were specified +to be processed on an alternate stack will resume doing so. +.Pp +If +.Fa oss +is non-zero, the current signal stack state is returned. +The +.Fa ss_flags +field will contain the value +.Dv SA_ONSTACK +if the process is currently on a signal stack and +.Dv SA_DISABLE +if the signal stack is currently disabled. +.Sh NOTES +The value +.Dv SIGSTKSZ +is defined to be the number of bytes/chars that would be used to cover +the usual case when allocating an alternate stack area. +The following code fragment is typically used to allocate an alternate stack. +.Bd -literal -offset indent +if ((sigstk.ss_sp = malloc(SIGSTKSZ)) == NULL) + /* error return */ +sigstk.ss_size = SIGSTKSZ; +sigstk.ss_flags = 0; +if (sigaltstack(&sigstk,0) < 0) + perror("sigaltstack"); +.Ed +An alternative approach is provided for programs with signal handlers +that require a specific amount of stack space other than the default size. +The value +.Dv MINSIGSTKSZ +is defined to be the number of bytes/chars that is required by +the operating system to implement the alternate stack feature. +In computing an alternate stack size, +programs should add +.Dv MINSIGSTKSZ +to their stack requirements to allow for the operating system overhead. +.Pp +Signal stacks are automatically adjusted for the direction of stack +growth and alignment requirements. +Signal stacks may or may not be protected by the hardware and +are not ``grown'' automatically as is done for the normal stack. +If the stack overflows and this space is not protected +unpredictable results may occur. +.Sh RETURN VALUES +Upon successful completion, a value of 0 is returned. +Otherwise, a value of -1 is returned and +.Va errno +is set to indicate the error. +.Sh ERRORS +.Fn Sigstack +will fail and the signal stack context will remain unchanged +if one of the following occurs. +.Bl -tag -width [ENOMEM] +.It Bq Er EFAULT +Either +.Fa ss +or +.Fa oss +points to memory that is not a valid part of the process +address space. +.It Bq Er EINVAL +An attempt was made to disable an active stack. +.It Bq Er ENOMEM +Size of alternate stack area is less than or equal to +.Dv MINSIGSTKSZ . +.El +.Sh SEE ALSO +.Xr sigaction 2 , +.Xr setjmp 3 +.Sh HISTORY +The predecessor to +.Nm sigaltstack , +the +.Fn sigstack +system call, appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/sigpending.2 b/bsd/man/man2/sigpending.2 new file mode 100644 index 000000000..3a0b95e9e --- /dev/null +++ b/bsd/man/man2/sigpending.2 @@ -0,0 +1,74 @@ +.\" $NetBSD: sigpending.2,v 1.2 1995/02/27 12:37:26 cgd Exp $ +.\" +.\" Copyright (c) 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Berkeley Software Design, 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. +.\" +.\" @(#)sigpending.2 8.3 (Berkeley) 1/12/94 +.\" +.Dd January 12, 1994 +.Dt SIGPENDING 2 +.Os +.Sh NAME +.Nm sigpending +.Nd get pending signals +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn sigpending "sigset_t *set" +.Sh DESCRIPTION +The +.Nm sigpending +function returns a mask of the signals pending for delivery +to the calling process in the location indicated by +.Fa set . +Signals may be pending because they are currently masked, +or transiently before delivery (although the latter case is not +normally detectable). +.Sh RETURN VALUES +A 0 value indicated that the call succeeded. A \-1 return value +indicates an error occurred and +.Va errno +is set to indicated the reason. +.Sh ERRORS +The +.Nm sigpending +function does not currently detect any errors. +.Sh SEE ALSO +.Xr sigaction 2 , +.Xr sigprocmask 2 +.Sh STANDARDS +The +.Nm sigpending +function is defined by +.St -p1003.1-88 . diff --git a/bsd/man/man2/sigprocmask.2 b/bsd/man/man2/sigprocmask.2 new file mode 100644 index 000000000..cd33571d5 --- /dev/null +++ b/bsd/man/man2/sigprocmask.2 @@ -0,0 +1,122 @@ +.\" $NetBSD: sigprocmask.2,v 1.6 1995/02/27 12:37:33 cgd Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)sigprocmask.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt SIGPROCMASK 2 +.Os +.Sh NAME +.Nm sigprocmask +.Nd manipulate current signal mask +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn sigprocmask "int how" "const sigset_t *set" "sigset_t *oset" +.Sh DESCRIPTION +The +.Fn sigprocmask +function examines and/or changes the current signal mask (those signals +that are blocked from delivery). +Signals are blocked if they are members of the current signal mask set. +.Pp +If +.Fa set +is not null, the action of +.Fn sigprocmask +depends on the value of the parameter +.Fa how . +The signal mask is changed as a function of the specified +.Fa set +and the current mask. +The function is specified by +.Fa how +using one of the following values from +.Aq Pa signal.h : +.Bl -tag -width SIG_UNBLOCK +.It Dv SIG_BLOCK +The new mask is the union of the current mask and the specified +.Fa set . +.It Dv SIG_UNBLOCK +The new mask is the intersection of the current mask +and the complement of the specified +.Fa set . +.It Dv SIG_SETMASK +The current mask is replaced by the specified +.Fa set . +.El +.Pp +If +.Fa oset +is not null, it is set to +the previous value of the signal mask. +When +.Fa set +is null, +the value of +.Ar how +is insignificant and the mask remains unset +providing a way to examine the signal mask without modification. +.Pp +The system +quietly disallows +.Dv SIGKILL +or +.Dv SIGSTOP +to be blocked. +.Sh RETURN VALUES +A 0 value indicated that the call succeeded. A -1 return value +indicates an error occurred and +.Va errno +is set to indicated the reason. +.Sh ERRORS +The +.Fn sigprocmask +call will fail and the signal mask will be unchanged if one +of the following occurs: +.Bl -tag -width Er +.It Bq Er EINVAL +.Fa how +has a value other than those listed here. +.El +.Sh SEE ALSO +.Xr kill 2 , +.Xr sigaction 2 , +.Xr sigsetops 3 , +.Xr sigsuspend 2 +.Sh STANDARDS +The +.Fn sigprocmask +function call is expected to +conform to +.St -p1003.1-88 . diff --git a/bsd/man/man2/sigreturn.2 b/bsd/man/man2/sigreturn.2 new file mode 100644 index 000000000..d92b3cf55 --- /dev/null +++ b/bsd/man/man2/sigreturn.2 @@ -0,0 +1,99 @@ +.\" $NetBSD: sigreturn.2,v 1.6 1995/02/27 12:37:40 cgd Exp $ +.\" +.\" Copyright (c) 1985, 1991, 1993 +.\" 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. +.\" +.\" @(#)sigreturn.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt SIGRETURN 2 +.Os BSD 4.3 +.Sh NAME +.Nm sigreturn +.Nd return from signal +.Sh SYNOPSIS +.Fd #include +.Bd -literal +struct sigcontext { + int sc_onstack; + int sc_mask; + int sc_sp; + int sc_fp; + int sc_ap; + int sc_pc; + int sc_ps; +}; +.Ed +.Ft int +.Fn sigreturn "struct sigcontext *scp" +.Sh DESCRIPTION +.Fn Sigreturn +allows users to atomically unmask, switch stacks, +and return from a signal context. +The processes signal mask and stack status are +restored from the context. +The system call does not return; +the users stack pointer, frame pointer, argument pointer, +and processor status longword are restored from the context. +Execution resumes at the specified pc. +This system call is used by the trampoline code and +.Xr longjmp 3 +when returning from a signal to the previously executing program. +.Sh NOTES +This system call is not available in 4.2 +.Tn BSD +hence it should not be used if backward compatibility is needed. +.Sh RETURN VALUES +If successful, the system call does not return. +Otherwise, a value of -1 is returned and +.Va errno +is set to indicate the error. +.Sh ERRORS +.Fn Sigreturn +will fail and the process context will remain unchanged +if one of the following occurs. +.Bl -tag -width Er +.It Bq Er EFAULT +.Fa Scp +points to memory that is not a valid part of the process +address space. +.It Bq Er EINVAL +The process status longword is invalid or would improperly +raise the privilege level of the process. +.El +.Sh SEE ALSO +.Xr sigaction 2 , +.Xr setjmp 3 +.Sh HISTORY +The +.Fn sigreturn +function call appeared in +.Bx 4.3 . diff --git a/bsd/man/man2/sigstack.2 b/bsd/man/man2/sigstack.2 new file mode 100644 index 000000000..fc3999f99 --- /dev/null +++ b/bsd/man/man2/sigstack.2 @@ -0,0 +1,53 @@ +.\" $NetBSD: sigstack.2,v 1.5 1995/02/27 13:21:35 cgd Exp $ +.\" +.\" Copyright (c) 1983, 1992, 1993 +.\" 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. +.\" +.\" @(#)sigstack.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt SIGSTACK 2 +.Os BSD 4.2 +.Sh NAME +.Nm sigstack +.Nd set and/or get signal stack context +.Sh DESCRIPTION +The +.Fn sigstack +function has been deprecated in favor of the interface described in +.Xr sigaltstack 2 . +.Sh SEE ALSO +.Xr sigaltstack 2 +.Sh HISTORY +The +.Nm +function call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/sigsuspend.2 b/bsd/man/man2/sigsuspend.2 new file mode 100644 index 000000000..93f7ff56a --- /dev/null +++ b/bsd/man/man2/sigsuspend.2 @@ -0,0 +1,82 @@ +.\" $NetBSD: sigsuspend.2,v 1.4 1995/02/27 12:37:46 cgd Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)sigsuspend.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt SIGSUSPEND 2 +.Os +.Sh NAME +.Nm sigsuspend +.Nd atomically release blocked signals and wait for interrupt +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn sigsuspend "const sigset_t *sigmask" +.Sh DESCRIPTION +.Fn Sigsuspend +temporarily changes the blocked signal mask to the set to which +.Fa sigmask +points, +and then waits for a signal to arrive; +on return the previous set of masked signals is restored. +The signal mask set +is usually empty to indicate that all +signals are to be unblocked for the duration of the call. +.Pp +In normal usage, a signal is blocked using +.Xr sigprocmask 2 +to begin a critical section, variables modified on the occurrence +of the signal are examined to determine that there is no work +to be done, and the process pauses awaiting work by using +.Fn sigsuspend +with the previous mask returned by +.Xr sigprocmask . +.Sh RETURN VALUES +The +.Fn sigsuspend +function +always terminates by being interrupted, returning -1 with +.Va errno +set to +.Dv EINTR . +.Sh SEE ALSO +.Xr sigprocmask 2 , +.Xr sigaction 2 , +.Xr sigsetops 3 +.Sh STANDARDS +The +.Nm sigsupend +function call +conforms to +.St -p1003.1-88 . diff --git a/bsd/man/man2/socket.2 b/bsd/man/man2/socket.2 new file mode 100644 index 000000000..364ab4a3c --- /dev/null +++ b/bsd/man/man2/socket.2 @@ -0,0 +1,259 @@ +.\" $NetBSD: socket.2,v 1.5 1995/02/27 12:37:53 cgd Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)socket.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt SOCKET 2 +.Os BSD 4.2 +.Sh NAME +.Nm socket +.Nd create an endpoint for communication +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn socket "int domain" "int type" "int protocol" +.Sh DESCRIPTION +.Fn Socket +creates an endpoint for communication and returns a descriptor. +.Pp +The +.Fa domain +parameter specifies a communications domain within which +communication will take place; this selects the protocol family +which should be used. +These families are defined in the include file +.Ao Pa sys/socket.h Ac . +The currently understood formats are +.Pp +.Bd -literal -offset indent -compact +AF_UNIX (UNIX internal protocols), +AF_INET (ARPA Internet protocols), +AF_ISO (ISO protocols), +AF_NS (Xerox Network Systems protocols), and +AF_IMPLINK (IMP \*(lqhost at IMP\*(rq link layer). +.Ed +.Pp +The socket has the indicated +.Fa type , +which specifies the semantics of communication. Currently +defined types are: +.Pp +.Bd -literal -offset indent -compact +SOCK_STREAM +SOCK_DGRAM +SOCK_RAW +SOCK_SEQPACKET +SOCK_RDM +.Ed +.Pp +A +.Dv SOCK_STREAM +type provides sequenced, reliable, +two-way connection based byte streams. +An out-of-band data transmission mechanism may be supported. +A +.Dv SOCK_DGRAM +socket supports +datagrams (connectionless, unreliable messages of +a fixed (typically small) maximum length). +A +.Dv SOCK_SEQPACKET +socket may provide a sequenced, reliable, +two-way connection-based data transmission path for datagrams +of fixed maximum length; a consumer may be required to read +an entire packet with each read system call. +This facility is protocol specific, and presently implemented +only for +.Dv PF_NS . +.Dv SOCK_RAW +sockets provide access to internal network protocols and interfaces. +The types +.Dv SOCK_RAW , +which is available only to the super-user, and +.Dv SOCK_RDM , +which is planned, +but not yet implemented, are not described here. +.Pp +The +.Fa protocol +specifies a particular protocol to be used with the socket. +Normally only a single protocol exists to support a particular +socket type within a given protocol family. However, it is possible +that many protocols may exist, in which case a particular protocol +must be specified in this manner. The protocol number to use is +particular to the \*(lqcommunication domain\*(rq in which communication +is to take place; see +.Xr protocols 5 . +.Pp +Sockets of type +.Dv SOCK_STREAM +are full-duplex byte streams, similar +to pipes. A stream socket must be in a +.Em connected +state before any data may be sent or received +on it. A connection to another socket is created with a +.Xr connect 2 +call. Once connected, data may be transferred using +.Xr read 2 +and +.Xr write 2 +calls or some variant of the +.Xr send 2 +and +.Xr recv 2 +calls. When a session has been completed a +.Xr close 2 +may be performed. +Out-of-band data may also be transmitted as described in +.Xr send 2 +and received as described in +.Xr recv 2 . +.Pp +The communications protocols used to implement a +.Dv SOCK_STREAM +insure that data +is not lost or duplicated. If a piece of data for which the +peer protocol has buffer space cannot be successfully transmitted +within a reasonable length of time, then +the connection is considered broken and calls +will indicate an error with +-1 returns and with +.Dv ETIMEDOUT +as the specific code +in the global variable +.Va errno . +The protocols optionally keep sockets +.Dq warm +by forcing transmissions +roughly every minute in the absence of other activity. +An error is then indicated if no response can be +elicited on an otherwise +idle connection for a extended period (e.g. 5 minutes). +A +.Dv SIGPIPE +signal is raised if a process sends +on a broken stream; this causes naive processes, +which do not handle the signal, to exit. +.Pp +.Dv SOCK_SEQPACKET +sockets employ the same system calls +as +.Dv SOCK_STREAM +sockets. The only difference +is that +.Xr read 2 +calls will return only the amount of data requested, +and any remaining in the arriving packet will be discarded. +.Pp +.Dv SOCK_DGRAM +and +.Dv SOCK_RAW +sockets allow sending of datagrams to correspondents +named in +.Xr send 2 +calls. Datagrams are generally received with +.Xr recvfrom 2 , +which returns the next datagram with its return address. +.Pp +An +.Xr fcntl 2 +call can be used to specify a process group to receive +a +.Dv SIGURG +signal when the out-of-band data arrives. +It may also enable non-blocking I/O +and asynchronous notification of I/O events +via +.Dv SIGIO . +.Pp +The operation of sockets is controlled by socket level +.Em options . +These options are defined in the file +.Ao Pa sys/socket.h Ac . +.Xr Setsockopt 2 +and +.Xr getsockopt 2 +are used to set and get options, respectively. +.Sh RETURN VALUES +A -1 is returned if an error occurs, otherwise the return +value is a descriptor referencing the socket. +.Sh ERRORS +The +.Fn socket +call fails if: +.Bl -tag -width Er +.It Bq Er EPROTONOSUPPORT +The protocol type or the specified protocol is not supported +within this domain. +.It Bq Er EMFILE +The per-process descriptor table is full. +.It Bq Er ENFILE +The system file table is full. +.It Bq Er EACCESS +Permission to create a socket of the specified type and/or protocol +is denied. +.It Bq Er ENOBUFS +Insufficient buffer space is available. +The socket cannot be created until sufficient resources are freed. +.El +.Sh SEE ALSO +.Xr accept 2 , +.Xr bind 2 , +.Xr connect 2 , +.Xr getprotoent 3 , +.Xr getsockname 2 , +.Xr getsockopt 2 , +.Xr ioctl 2 , +.Xr listen 2 , +.Xr read 2 , +.Xr recv 2 , +.Xr select 2 , +.Xr send 2 , +.Xr shutdown 2 , +.Xr socketpair 2 , +.Xr write 2 +.Rs +.%T "An Introductory 4.3 BSD Interprocess Communication Tutorial" +.%O "reprinted in UNIX Programmer's Supplementary Documents Volume 1" +.Re +.Rs +.%T "BSD Interprocess Communication Tutorial" +.%O "reprinted in UNIX Programmer's Supplementary Documents Volume 1" +.Re +.Sh HISTORY +The +.Fn socket +function call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/socketpair.2 b/bsd/man/man2/socketpair.2 new file mode 100644 index 000000000..32952769e --- /dev/null +++ b/bsd/man/man2/socketpair.2 @@ -0,0 +1,94 @@ +.\" $NetBSD: socketpair.2,v 1.5 1995/02/27 12:38:00 cgd Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)socketpair.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt SOCKETPAIR 2 +.Os BSD 4.2 +.Sh NAME +.Nm socketpair +.Nd create a pair of connected sockets +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn socketpair "int d" "int type" "int protocol" "int *sv" +.Sh DESCRIPTION +The +.Fn socketpair +call creates an unnamed pair of connected sockets in +the specified domain +.Fa d , +of the specified +.Fa type , +and using the optionally specified +.Fa protocol . +The descriptors used in referencing the new sockets +are returned in +.Fa sv Ns [0] +and +.Fa sv Ns [1] . +The two sockets are indistinguishable. +.Sh DIAGNOSTICS +A 0 is returned if the call succeeds, -1 if it fails. +.Sh ERRORS +The call succeeds unless: +.Bl -tag -width Er +.It Bq Er EMFILE +Too many descriptors are in use by this process. +.It Bq Er EAFNOSUPPORT +The specified address family is not supported on this machine. +.It Bq Er EPROTONOSUPPORT +The specified protocol is not supported on this machine. +.It Bq Er EOPNOSUPPORT +The specified protocol does not support creation of socket pairs. +.It Bq Er EFAULT +The address +.Fa sv +does not specify a valid part of the +process address space. +.El +.Sh SEE ALSO +.Xr read 2 , +.Xr write 2 , +.Xr pipe 2 +.Sh BUGS +This call is currently implemented only for the +.Tn UNIX +domain. +.Sh HISTORY +The +.Fn socketpair +function call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/stat.2 b/bsd/man/man2/stat.2 new file mode 100644 index 000000000..04f63c7ba --- /dev/null +++ b/bsd/man/man2/stat.2 @@ -0,0 +1,283 @@ +.\" $OpenBSD: stat.2,v 1.3 1997/02/13 05:20:55 millert Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993, 1994 +.\" 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.2 8.3 (Berkeley) 4/19/94 +.\" +.Dd April 19, 1994 +.Dt STAT 2 +.Os BSD 4 +.Sh NAME +.Nm stat , +.Nm lstat , +.Nm fstat +.Nd get file status +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn stat "const char *path" "struct stat *sb" +.Ft int +.Fn lstat "const char *path" "struct stat *sb" +.Ft int +.Fn fstat "int fd" "struct stat *sb" +.Sh DESCRIPTION +The +.Fn stat +function obtains information about the file pointed to by +.Fa path . +Read, write or execute +permission of the named file is not required, but all directories +listed in the path name leading to the file must be searchable. +.Pp +.Fn Lstat +is like +.Fn stat +except in the case where the named file is a symbolic link, +in which case +.Fn lstat +returns information about the link, +while +.Fn stat +returns information about the file the link references. +Unlike other filesystem objects, +symbolic links do not have an owner, group, access mode, times, etc. +Instead, these attributes are taken from the directory that +contains the link. +The only attributes returned from an +.Fn lstat +that refer to the symbolic link itself are the file type (S_IFLNK), +size, blocks, and link count (always 1). +.Pp +The +.Fn fstat +obtains the same information about an open file +known by the file descriptor +.Fa fd . +.Pp +The +.Fa sb +argument is a pointer to a +.Fn stat +structure +as defined by +.Aq Pa sys/stat.h +(shown below) +and into which information is placed concerning the file. +.Bd -literal +struct stat { + dev_t st_dev; /* device inode resides on */ + ino_t st_ino; /* inode's number */ + mode_t st_mode; /* inode protection mode */ + nlink_t st_nlink; /* number or hard links to the file */ + uid_t st_uid; /* user-id of owner */ + gid_t st_gid; /* group-id of owner */ + dev_t st_rdev; /* device type, for special file inode */ + struct timespec st_atimespec; /* time of last access */ + struct timespec st_mtimespec; /* time of last data modification */ + struct timespec st_ctimespec; /* time of last file status change */ + off_t st_size; /* file size, in bytes */ + quad_t st_blocks; /* blocks allocated for file */ + u_long st_blksize;/* optimal file sys I/O ops blocksize */ + u_long st_flags; /* user defined flags for file */ + u_long st_gen; /* file generation number */ +}; +.Ed +.Pp +The time-related fields of +.Fa struct stat +are as follows: +.Bl -tag -width XXXst_mtime +.It st_atime +Time when file data last accessed. +Changed by the +.Xr mknod 2 , +.Xr utimes 2 +and +.Xr read 2 +system calls. +.It st_mtime +Time when file data last modified. +Changed by the +.Xr mknod 2 , +.Xr utimes 2 +and +.Xr write 2 +system calls. +.It st_ctime +Time when file status was last changed (inode data modification). +Changed by the +.Xr chmod 2 , +.Xr chown 2 , +.Xr link 2 , +.Xr mknod 2 , +.Xr rename 2 , +.Xr unlink 2 , +.Xr utimes 2 +and +.Xr write 2 +system calls. +.El +.Pp +The size-related fields of the +.Fa struct stat +are as follows: +.Bl -tag -width XXXst_blksize +.It st_blksize +The optimal I/O block size for the file. +.It st_blocks +The actual number of blocks allocated for the file in 512-byte units. +As short symbolic links are stored in the inode, this number may +be zero. +.El +.Pp +The status information word +.Fa st_mode +has the following bits: +.Bd -literal +#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_IFWHT 0160000 /* whiteout */ +#define S_ISUID 0004000 /* set user id on execution */ +#define S_ISGID 0002000 /* set group id on execution */ +#define S_ISVTX 0001000 /* save swapped text even after use */ +#define S_IRUSR 0000400 /* read permission, owner */ +#define S_IWUSR 0000200 /* write permission, owner */ +#define S_IXUSR 0000100 /* execute/search permission, owner */ +.Ed +.Pp +For a list of access modes, see +.Aq Pa sys/stat.h , +.Xr access 2 +and +.Xr chmod 2 . +.Sh RETURN VALUES +Upon successful completion a value of 0 is returned. +Otherwise, a value of -1 is returned and +.Va errno +is set to indicate the error. +.Sh COMPATIBILITY +Previous versions of the system used different types for the +.Li st_dev , +.Li st_uid , +.Li st_gid , +.Li st_rdev , +.Li st_size , +.Li st_blksize +and +.Li st_blocks +fields. +.Sh ERRORS +.Fn Stat +and +.Fn lstat +will fail if: +.Bl -tag -width Er +.It Bq Er ENOTDIR +A component of the path prefix is not a directory. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded +.Dv {NAME_MAX} +characters, or an entire path name exceeded +.Dv {PATH_MAX} +characters. +.It Bq Er ENOENT +The named file does not exist. +.It Bq Er EACCES +Search permission is denied for a component of the path prefix. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating the pathname. +.It Bq Er EFAULT +.Fa Sb +or +.Em name +points to an invalid address. +.It Bq Er EIO +An I/O error occurred while reading from or writing to the file system. +.El +.Pp +.Bl -tag -width Er +.Fn Fstat +will fail if: +.It Bq Er EBADF +.Fa fd +is not a valid open file descriptor. +.It Bq Er EFAULT +.Fa Sb +points to an invalid address. +.It Bq Er EIO +An I/O error occurred while reading from or writing to the file system. +.El +.Sh CAVEATS +The file generation number, +.Fa st_gen , +is only available to the super-user. +.br +The fields in the stat structure currently marked +.Fa st_spare1 , +.Fa st_spare2 , +and +.Fa st_spare3 +are present in preparation for inode time stamps expanding +to 64 bits. This, however, can break certain programs that +depend on the time stamps being contiguous (in calls to +.Xr utimes 2 ) . +.Sh SEE ALSO +.Xr chmod 2 , +.Xr chown 2 , +.Xr utimes 2 +.Xr symlink 7 +.Sh BUGS +Applying +.Xr fstat +to a socket (and thus to a pipe) +returns a zero'd buffer, +except for the blocksize field, +and a unique device and inode number. +.Sh STANDARDS +The +.Fn stat +and +.Fn fstat +function calls are expected to conform to +.St -p1003.1-88 . +.Sh HISTORY +An +.Fn lstat +function call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/statfs.2 b/bsd/man/man2/statfs.2 new file mode 100644 index 000000000..f29355d91 --- /dev/null +++ b/bsd/man/man2/statfs.2 @@ -0,0 +1,146 @@ +.\" $NetBSD: statfs.2,v 1.10 1995/06/29 11:40:48 cgd Exp $ +.\" +.\" Copyright (c) 1989, 1991, 1993 +.\" 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. +.\" +.\" @(#)statfs.2 8.3 (Berkeley) 2/11/94 +.\" +.Dd February 11, 1994 +.Dt STATFS 2 +.Os +.Sh NAME +.Nm statfs +.Nd get file system statistics +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn statfs "const char *path" "struct statfs *buf" +.Ft int +.Fn fstatfs "int fd" "struct statfs *buf" +.Sh DESCRIPTION +.Fn Statfs +returns information about a mounted file system. +.Fa Path +is the path name of any file within the mounted file system. +.Fa Buf +is a pointer to a statfs structure defined as follows: +.Bd -literal +typedef struct { int32_t val[2]; } fsid_t; + +#define MFSNAMELEN 16 /* length of fs type name, including nul */ +#define MNAMELEN 32 /* length of buffer for returned name */ + +struct statfs { + short f_type; /* type of file system (unused; zero) */ + short f_flags; /* copy of mount flags */ + long f_bsize; /* fundamental file system block size */ + long f_iosize; /* optimal transfer block size */ + long f_blocks; /* total data blocks in file system */ + long f_bfree; /* free blocks in fs */ + long f_bavail; /* free blocks avail to non-superuser */ + long f_files; /* total file nodes in file system */ + long f_ffree; /* free file nodes in fs */ + fsid_t f_fsid; /* file system id (super-user only) */ + uid_t f_owner; /* user that mounted the file system */ + long f_spare[4]; /* spare for later */ + char f_fstypename[MFSNAMELEN]; /* fs type name */ + char f_mntonname[MNAMELEN]; /* directory on which mounted */ + char f_mntfromname[MNAMELEN]; /* mounted file system */ +}; +.Ed +.Pp +Fields that are undefined for a particular file system are set to -1. +.Fn Fstatfs +returns the same information about an open file referenced by descriptor +.Fa fd . +.Sh RETURN VALUES +Upon successful completion, a value of 0 is returned. +Otherwise, -1 is returned and the global variable +.Va errno +is set to indicate the error. +.Sh ERRORS +.Fn Statfs +fails if one or more of the following are true: +.Bl -tag -width Er +.It Bq Er ENOTDIR +A component of the path prefix of +.Fa Path +is not a directory. +.It Bq Er ENAMETOOLONG +The length of a component of +.Fa path +exceeds +.Dv {NAME_MAX} +characters, or the length of +.Fa path +exceeds +.Dv {PATH_MAX} +characters. +.It Bq Er ENOENT +The file referred to by +.Fa path +does not exist. +.It Bq Er EACCES +Search permission is denied for a component of the path prefix of +.Fa path . +.It Bq Er ELOOP +Too many symbolic links were encountered in translating +.Fa path . +.It Bq Er EFAULT +.Fa Buf +or +.Fa path +points to an invalid address. +.It Bq Er EIO +An +.Tn I/O +error occurred while reading from or writing to the file system. +.El +.Pp +.Fn Fstatfs +fails if one or more of the following are true: +.Bl -tag -width Er +.It Bq Er EBADF +.Fa fd +is not a valid open file descriptor. +.It Bq Er EFAULT +.Fa Buf +points to an invalid address. +.It Bq Er EIO +An +.Tn I/O +error occurred while reading from or writing to the file system. +.El +.Sh HISTORY +The +.Fn statfs +function first appeared in 4.4BSD. diff --git a/bsd/man/man2/symlink.2 b/bsd/man/man2/symlink.2 new file mode 100644 index 000000000..cee3f9ff6 --- /dev/null +++ b/bsd/man/man2/symlink.2 @@ -0,0 +1,139 @@ +.\" $NetBSD: symlink.2,v 1.7 1995/02/27 12:38:34 cgd Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)symlink.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt SYMLINK 2 +.Os BSD 4.2 +.Sh NAME +.Nm symlink +.Nd make symbolic link to a file +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn symlink "const char *name1" "const char *name2" +.Sh DESCRIPTION +A symbolic link +.Fa name2 +is created to +.Fa name1 +.Pf ( Fa name2 +is the name of the +file created, +.Fa name1 +is the string +used in creating the symbolic link). +Either name may be an arbitrary path name; the files need not +be on the same file system. +.Sh RETURN VALUES +Upon successful completion, a zero value is returned. +If an error occurs, the error code is stored in +.Va errno +and a -1 value is returned. +.Sh ERRORS +The symbolic link succeeds unless: +.Bl -tag -width Er +.It Bq Er ENOTDIR +A component of the +.Fa name2 +prefix is not a directory. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded +.Dv {NAME_MAX} +characters, or an entire path name exceeded +.Dv {PATH_MAX} +characters. +.It Bq Er ENOENT +The named file does not exist. +.It Bq Er EACCES +A component of the +.Fa name2 +path prefix denies search permission. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating the pathname. +.It Bq Er EEXIST +.Fa Name2 +already exists. +.It Bq Er EIO +An I/O error occurred while making the directory entry for +.Fa name2 , +or allocating the inode for +.Fa name2 , +or writing out the link contents of +.Fa name2 . +.It Bq Er EROFS +The file +.Fa name2 +would reside on a read-only file system. +.It Bq Er ENOSPC +The directory in which the entry for the new symbolic link is being placed +cannot be extended because there is no space left on the file +system containing the directory. +.It Bq Er ENOSPC +The new symbolic link cannot be created because there +there is no space left on the file +system that will contain the symbolic link. +.It Bq Er ENOSPC +There are no free inodes on the file system on which the +symbolic link is being created. +.It Bq Er EDQUOT +The directory in which the entry for the new symbolic link +is being placed cannot be extended because the +user's quota of disk blocks on the file system +containing the directory has been exhausted. +.It Bq Er EDQUOT +The new symbolic link cannot be created because the user's +quota of disk blocks on the file system that will +contain the symbolic link has been exhausted. +.It Bq Er EDQUOT +The user's quota of inodes on the file system on +which the symbolic link is being created has been exhausted. +.It Bq Er EIO +An I/O error occurred while making the directory entry or allocating the inode. +.It Bq Er EFAULT +.Fa Name1 +or +.Fa name2 +points outside the process's allocated address space. +.El +.Sh SEE ALSO +.Xr ln 1 , +.Xr link 2 , +.Xr unlink 2 +.Xr symlink 7 , +.Sh HISTORY +The +.Fn symlink +function call appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/sync.2 b/bsd/man/man2/sync.2 new file mode 100644 index 000000000..a94475b4e --- /dev/null +++ b/bsd/man/man2/sync.2 @@ -0,0 +1,76 @@ +.\" $NetBSD: sync.2,v 1.4 1995/02/27 12:38:41 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.\" @(#)sync.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt SYNC 2 +.Os BSD 4 +.Sh NAME +.Nm sync +.Nd "synchronize disk block in-core status with that on disk" +.Sh SYNOPSIS +.Fd #include +.Ft void +.Fn sync void +.Sh DESCRIPTION +The +.Fn sync +function forces a write of dirty (modified) buffers +in the block buffer cache out +to disk. The kernel keeps this information in core to reduce +the number of disk I/O transfers required by the system. +As information in the cache is lost after a system crash a +.Fn sync +call is issued +frequently +by the user process +.Xr update 8 +(about every 30 seconds). +.Pp +The function +.Xr fsync 2 +may be used to synchronize individual file descriptor +attributes. +.Sh SEE ALSO +.Xr fsync 2 , +.Xr sync 8 , +.Xr update 8 +.Sh BUGS +.Fn Sync +may return before the buffers are completely flushed. +.Sh HISTORY +A +.Fn sync +function call appeared in +.At v6 . diff --git a/bsd/man/man2/syscall.2 b/bsd/man/man2/syscall.2 new file mode 100644 index 000000000..9de1e3922 --- /dev/null +++ b/bsd/man/man2/syscall.2 @@ -0,0 +1,78 @@ +.\" $NetBSD: syscall.2,v 1.4 1995/02/27 12:38:53 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.\" @(#)syscall.2 8.1 (Berkeley) 6/16/93 +.\" +.Dd June 16, 1993 +.Dt SYSCALL 2 +.Os BSD 4 +.Sh NAME +.Nm syscall , +.Nm __syscall +.Nd indirect system call +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn syscall "int number" "..." +.Ft int +.Fn __syscall "quad_t number" "..." +.Sh DESCRIPTION +.Fn Syscall +performs the system call whose assembly language +interface has the specified +.Fa number +with the specified arguments. +Symbolic constants for system calls can be found in the header file +.Ao Pa sys/syscall.h Ac . +The +.Nm __syscall +form should be used when one or more of the parameters is a +64-bit argument to ensure that argument alignment is correct. +This system call is useful for testing new system calls that +do not have entries in the C library. +.Sh RETURN VALUES +The return values are defined by the system call being invoked. +In general, a 0 return value indicates success. +A -1 return value indicates an error, +and an error code is stored in +.Va errno . +.Sh BUGS +There is no way to simulate system calls that have multiple return values +such as +.Xr pipe 2 . +.Sh HISTORY +The +.Fn syscall +function call appeared in +.Bx 4.0 . diff --git a/bsd/man/man2/truncate.2 b/bsd/man/man2/truncate.2 new file mode 100644 index 000000000..d54ad0897 --- /dev/null +++ b/bsd/man/man2/truncate.2 @@ -0,0 +1,133 @@ +.\" $NetBSD: truncate.2,v 1.7 1995/02/27 12:39:00 cgd Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)truncate.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt TRUNCATE 2 +.Os BSD 4.2 +.Sh NAME +.Nm truncate , +.Nm ftruncate +.Nd truncate or extend a file to a specified length +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn truncate "const char *path" "off_t length" +.Ft int +.Fn ftruncate "int fd" "off_t length" +.Sh DESCRIPTION +.Fn Truncate +causes the file named by +.Fa path +or referenced by +.Fa fd +to be truncated or extended to +.Fa length +bytes in size. If the file previously +was larger than this size, the extra data +is lost. If the file was smaller than this size, it will be extended as +if by writing bytes with the value zero. +With +.Fn ftruncate , +the file must be open for writing. +.Sh RETURN VALUES +A value of 0 is returned if the call succeeds. If the call +fails a -1 is returned, and the global variable +.Va errno +specifies the error. +.Sh ERRORS +.Fn Truncate +succeeds unless: +.Bl -tag -width Er +.It Bq Er ENOTDIR +A component of the path prefix is not a directory. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded +.Dv {NAME_MAX} +characters, or an entire path name exceeded +.Dv {PATH_MAX} +characters. +.It Bq Er ENOENT +The named file does not exist. +.It Bq Er EACCES +Search permission is denied for a component of the path prefix. +.It Bq Er EACCES +The named file is not writable by the user. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating the pathname. +.It Bq Er EISDIR +The named file is a directory. +.It Bq Er EROFS +The named file resides on a read-only file system. +.It Bq Er ETXTBSY +The file is a pure procedure (shared text) file that is being executed. +.It Bq Er EIO +An I/O error occurred updating the inode. +.It Bq Er EFAULT +.Fa Path +points outside the process's allocated address space. +.El +.Pp +.Fn Ftruncate +succeeds unless: +.Bl -tag -width Er +.It Bq Er EBADF +The +.Fa fd +is not a valid descriptor. +.It Bq Er EINVAL +The +.Fa fd +references a socket, not a file. +.It Bq Er EINVAL +The +.Fa fd +is not open for writing. +.El +.Sh SEE ALSO +.Xr open 2 +.Sh BUGS +These calls should be generalized to allow ranges +of bytes in a file to be discarded. +.Pp +Use of +.Fn truncate +to extend a file is not portable. +.Sh HISTORY +The +.Fn truncate +and +.Fn ftruncate +function calls appeared in +.Bx 4.2 . diff --git a/bsd/man/man2/umask.2 b/bsd/man/man2/umask.2 new file mode 100644 index 000000000..92eff34f7 --- /dev/null +++ b/bsd/man/man2/umask.2 @@ -0,0 +1,89 @@ +.\" $NetBSD: umask.2,v 1.6 1995/02/27 12:39:06 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.\" @(#)umask.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt UMASK 2 +.Os BSD 4 +.Sh NAME +.Nm umask +.Nd set file creation mode mask +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft mode_t +.Fn umask "mode_t numask" +.Sh DESCRIPTION +The +.Fn umask +routine sets the process's file mode creation mask to +.Fa numask +and returns the previous value of the mask. The 9 low-order +access permission +bits of +.Fa numask +are used by system calls, including +.Xr open 2 , +.Xr mkdir 2 , +.Xr mkfifo 2 +and +.Xr mknod 2 +to turn off corresponding bits +requested in file mode. +(See +.Xr chmod 2 ) . +This clearing allows each user to restrict the default access +to his files. +.Pp +The default mask value is S_IWGRP|S_IWOTH (022, write access for the +owner only). +Child processes inherit the mask of the calling process. +.Sh RETURN VALUES +The previous value of the file mode mask is returned by the call. +.Sh ERRORS +The +.Fn umask +function is always successful. +.Sh SEE ALSO +.Xr chmod 2 , +.Xr mkdir 2 , +.Xr mkfifo 2 , +.Xr mknod 2 , +.Xr open 2 +.Sh STANDARDS +The +.Fn umask +function call is expected to +conform to +.St -p1003.1-88 . diff --git a/bsd/man/man2/unlink.2 b/bsd/man/man2/unlink.2 new file mode 100644 index 000000000..6dfd46035 --- /dev/null +++ b/bsd/man/man2/unlink.2 @@ -0,0 +1,116 @@ +.\" $NetBSD: unlink.2,v 1.7 1995/02/27 12:39:13 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.\" @(#)unlink.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt UNLINK 2 +.Os BSD 4 +.Sh NAME +.Nm unlink +.Nd remove directory entry +.Sh SYNOPSIS +.Fd #include +.Ft int +.Fn unlink "const char *path" +.Sh DESCRIPTION +The +.Fn unlink +function +removes the link named by +.Fa path +from its directory and decrements the link count of the +file which was referenced by the link. +If that decrement reduces the link count of the file +to zero, +and no process has the file open, then +all resources associated with the file are reclaimed. +If one or more process have the file open when the last link is removed, +the link is removed, but the removal of the file is delayed until +all references to it have been closed. +.Sh RETURN VALUES +Upon successful completion, a value of 0 is returned. +Otherwise, a value of -1 is returned and +.Va errno +is set to indicate the error. +.Sh ERRORS +The +.Fn unlink +succeeds unless: +.Bl -tag -width Er +.It Bq Er ENOTDIR +A component of the path prefix is not a directory. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded +.Dv {NAME_MAX} +characters, or an entire path name exceeded +.Dv {PATH_MAX} +characters. +.It Bq Er ENOENT +The named file does not exist. +.It Bq Er EACCES +Search permission is denied for a component of the path prefix. +.It Bq Er EACCES +Write permission is denied on the directory containing the link +to be removed. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating the pathname. +.It Bq Er EPERM +The named file is a directory and the effective user ID +of the process is not the super-user. +.It Bq Er EPERM +The directory containing the file is marked sticky, +and neither the containing directory nor the file to be removed +are owned by the effective user ID. +.It Bq Er EBUSY +The entry to be unlinked is the mount point for a +mounted file system. +.It Bq Er EIO +An I/O error occurred while deleting the directory entry +or deallocating the inode. +.It Bq Er EROFS +The named file resides on a read-only file system. +.It Bq Er EFAULT +.Fa Path +points outside the process's allocated address space. +.El +.Sh SEE ALSO +.Xr close 2 , +.Xr link 2 , +.Xr rmdir 2 +.Xr symlink 7 +.Sh HISTORY +An +.Fn unlink +function call appeared in +.At v6 . diff --git a/bsd/man/man2/unmount.2 b/bsd/man/man2/unmount.2 new file mode 100644 index 000000000..373253092 --- /dev/null +++ b/bsd/man/man2/unmount.2 @@ -0,0 +1 @@ +.so man2/mount.2 diff --git a/bsd/man/man2/utimes.2 b/bsd/man/man2/utimes.2 new file mode 100644 index 000000000..94dabd258 --- /dev/null +++ b/bsd/man/man2/utimes.2 @@ -0,0 +1,168 @@ +.\" $NetBSD: utimes.2,v 1.13 1999/03/22 19:45:11 garbled Exp $ +.\" +.\" Copyright (c) 1990, 1993 +.\" 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. +.\" +.\" @(#)utimes.2 8.1 (Berkeley) 6/4/93 +.\" $FreeBSD: src/lib/libc/sys/utimes.2,v 1.8.2.4 2001/12/14 18:34:02 ru Exp $ +.\" +.Dd June 4, 1993 +.Dt UTIMES 2 +.Os +.Sh NAME +.Nm utimes , +.Nm futimes +.Nd set file access and modification times +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In sys/time.h +.Ft int +.Fn utimes "const char *path" "const struct timeval *times" +.Ft int +.Fn futimes "int fd" "const struct timeval *times" +.Sh DESCRIPTION +The access and modification times of the file named by +.Fa path +or referenced by +.Fa fd +are changed as specified by the argument +.Fa times . +.Pp +If +.Fa times +is +.Dv NULL , +the access and modification times are set to the current time. +The caller must be the owner of the file, have permission to +write the file, or be the super-user. +.Pp +If +.Fa times +is +.Pf non- Dv NULL , +it is assumed to point to an array of two timeval structures. +The access time is set to the value of the first element, and the +modification time is set to the value of the second element. +The caller must be the owner of the file or be the super-user. +.Pp +In either case, the inode-change-time of the file is set to the current +time. +.Sh RETURN VALUES +.Rv -std +.Sh ERRORS +.Fn utimes +will fail if: +.Bl -tag -width Er +.It Bq Er EACCES +Search permission is denied for a component of the path prefix; +or the +.Fa times +argument is +.Dv NULL +and the effective user ID of the process does not +match the owner of the file, and is not the super-user, and write +access is denied. +.It Bq Er EFAULT +.Fa path +or +.Fa times +points outside the process's allocated address space. +.It Bq Er EIO +An I/O error occurred while reading or writing the affected inode. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating the pathname. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded +.Dv NAME_MAX +characters, or an entire path name exceeded +.Dv PATH_MAX +characters. +.It Bq Er ENOENT +The named file does not exist. +.It Bq Er ENOTDIR +A component of the path prefix is not a directory. +.It Bq Er EPERM +The +.Fa times +argument is not +.Dv NULL +and the calling process's effective user ID +does not match the owner of the file and is not the super-user. +.It Bq Er EROFS +The file system containing the file is mounted read-only. +.El +.Pp +.Fn futimes +will fail if: +.Bl -tag -width Er +.It Bq Er EBADF +.Fa fd +does not refer to a valid descriptor. +.El +.Pp +All of the functions will fail if: +.Bl -tag -width Er +.It Bq Er EACCES +The +.Fa times +argument is +.Dv NULL +and the effective user ID of the process does not +match the owner of the file, and is not the super-user, and write +access is denied. +.It Bq Er EFAULT +.Fa times +points outside the process's allocated address space. +.It Bq Er EIO +An I/O error occurred while reading or writing the affected inode. +.It Bq Er EPERM +The +.Fa times +argument is not +.Dv NULL +and the calling process's effective user ID +does not match the owner of the file and is not the super-user. +.It Bq Er EROFS +The file system containing the file is mounted read-only. +.El +.Sh SEE ALSO +.Xr stat 2 , +.Xr utime 3 +.Sh HISTORY +The +.Fn utimes +function call appeared in +.Bx 4.2 . +The +.Fn futimes +function call first appeared in +.Fx 3.0 . diff --git a/bsd/man/man2/vfork.2 b/bsd/man/man2/vfork.2 new file mode 100644 index 000000000..06e201dfc --- /dev/null +++ b/bsd/man/man2/vfork.2 @@ -0,0 +1,128 @@ +.\" $NetBSD: vfork.2,v 1.6 1995/02/27 12:39:30 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.\" @(#)vfork.2 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt VFORK 2 +.Os BSD 4 +.Sh NAME +.Nm vfork +.Nd spawn new process in a virtual memory efficient way +.Sh SYNOPSIS +.Fd #include +.Ft pid_t +.Fn vfork void +.Sh DESCRIPTION +.Fn Vfork +can be used to create new processes without fully copying the address +space of the old process, which is horrendously inefficient in a paged +environment. It is useful when the purpose of +.Xr fork 2 +would have been to create a new system context for an +.Xr execve . +.Fn Vfork +differs from +.Xr fork +in that the child borrows the parent's memory and thread of +control until a call to +.Xr execve 2 +or an exit (either by a call to +.Xr exit 2 +or abnormally.) +The parent process is suspended while the child is using its resources. +.Pp +.Fn Vfork +returns 0 in the child's context and (later) the pid of the child in +the parent's context. +.Pp +.Fn Vfork +can normally be used just like +.Xr fork . +It does not work, however, to return while running in the childs context +from the procedure that called +.Fn vfork +since the eventual return from +.Fn vfork +would then return to a no longer existent stack frame. +Be careful, also, to call +.Xr _exit +rather than +.Xr exit +if you can't +.Xr execve , +since +.Xr exit +will flush and close standard I/O channels, and thereby mess up the +parent processes standard I/O data structures. +(Even with +.Xr fork +it is wrong to call +.Xr exit +since buffered data would then be flushed twice.) +.Sh SEE ALSO +.Xr fork 2 , +.Xr execve 2 , +.Xr sigaction 2 , +.Xr wait 2 , +.Sh DIAGNOSTICS +Same as for +.Xr fork . +.Sh BUGS +This system call will be eliminated when proper system sharing +mechanisms are implemented. +Users should not depend on the memory +sharing semantics of +.Xr vfork +as it will, in that case, be made synonymous to +.Xr fork . +.Pp +To avoid a possible deadlock situation, +processes that are children in the middle +of a +.Fn vfork +are never sent +.Dv SIGTTOU +or +.Dv SIGTTIN +signals; rather, +output or +.Xr ioctl 2 +calls +are allowed +and input attempts result in an end-of-file indication. +.Sh HISTORY +The +.Fn vfork +function call appeared in +.Bx 3.0 . diff --git a/bsd/man/man2/wait.2 b/bsd/man/man2/wait.2 new file mode 100644 index 000000000..d72a93dce --- /dev/null +++ b/bsd/man/man2/wait.2 @@ -0,0 +1,302 @@ +.\" $NetBSD: wait.2,v 1.6 1995/02/27 12:39:37 cgd Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993, 1994 +.\" 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.2 8.2 (Berkeley) 4/19/94 +.\" +.Dd April 19, 1994 +.Dt WAIT 2 +.Os BSD 4 +.Sh NAME +.Nm wait , +.Nm waitpid , +.Nm wait4 , +.Nm wait3 +.Nd wait for process termination +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft pid_t +.Fn wait "int *status" +.Ft pid_t +.Fn waitpid "pid_t wpid" "int *status" "int options" +.Fd #include +.Fd #include +.Ft pid_t +.Fn wait3 "int *status" "int options" "struct rusage *rusage" +.Ft pid_t +.Fn wait4 "pid_t wpid" "int *status" "int options" "struct rusage *rusage" +.Sh DESCRIPTION +The +.Fn wait +function suspends execution of its calling process until +.Fa status +information is available for a terminated child process, +or a signal is received. +On return from a successful +.Fn wait +call, +the +.Fa status +area contains termination information about the process that exited +as defined below. +.Pp +The +.Fn wait4 +call provides a more general interface for programs +that need to wait for certain child processes, +that need resource utilization statistics accumulated by child processes, +or that require options. +The other wait functions are implemented using +.Fn wait4 . +.Pp +The +.Fa wpid +parameter specifies the set of child processes for which to wait. +If +.Fa wpid +is -1, the call waits for any child process. +If +.Fa wpid +is 0, +the call waits for any child process in the process group of the caller. +If +.Fa wpid +is greater than zero, the call waits for the process with process id +.Fa wpid . +If +.Fa wpid +is less than -1, the call waits for any process whose process group id +equals the absolute value of +.Fa wpid . +.Pp +The +.Fa status +parameter is defined below. The +.Fa options +parameter contains the bitwise OR of any of the following options. +The +.Dv WNOHANG +option +is used to indicate that the call should not block if +there are no processes that wish to report status. +If the +.Dv WUNTRACED +option is set, +children of the current process that are stopped +due to a +.Dv SIGTTIN , SIGTTOU , SIGTSTP , +or +.Dv SIGSTOP +signal also have +their status reported. +.Pp +If +.Fa rusage +is non-zero, a summary of the resources used by the terminated +process and all its +children is returned (this information is currently not available +for stopped processes). +.Pp +When the +.Dv WNOHANG +option is specified and no processes +wish to report status, +.Fn wait4 +returns a +process id +of 0. +.Pp +The +.Fn waitpid +call is identical to +.Fn wait4 +with an +.Fa rusage +value of zero. +The older +.Fn wait3 +call is the same as +.Fn wait4 +with a +.Fa wpid +value of -1. +.Pp +The following macros may be used to test the manner of exit of the process. +One of the first three macros will evaluate to a non-zero (true) value: +.Bl -tag -width Ds +.It Fn WIFEXITED status +True if the process terminated normally by a call to +.Xr _exit 2 +or +.Xr exit 2 . +.It Fn WIFSIGNALED status +True if the process terminated due to receipt of a signal. +.It Fn WIFSTOPPED status +True if the process has not terminated, but has stopped and can be restarted. +This macro can be true only if the wait call specified the +.Dv WUNTRACED +option +or if the child process is being traced (see +.Xr ptrace 2 ) . +.El +.Pp +Depending on the values of those macros, the following macros +produce the remaining status information about the child process: +.Bl -tag -width Ds +.It Fn WEXITSTATUS status +If +.Fn WIFEXITED status +is true, evaluates to the low-order 8 bits +of the argument passed to +.Xr _exit 2 +or +.Xr exit 2 +by the child. +.It Fn WTERMSIG status +If +.Fn WIFSIGNALED status +is true, evaluates to the number of the signal +that caused the termination of the process. +.It Fn WCOREDUMP status +If +.Fn WIFSIGNALED status +is true, evaluates as true if the termination +of the process was accompanied by the creation of a core file +containing an image of the process when the signal was received. +.It Fn WSTOPSIG status +If +.Fn WIFSTOPPED status +is true, evaluates to the number of the signal +that caused the process to stop. +.El +.Sh NOTES +See +.Xr sigaction 2 +for a list of termination signals. +A status of 0 indicates normal termination. +.Pp +If a parent process terminates without +waiting for all of its child processes to terminate, +the remaining child processes are assigned the parent +process 1 ID (the init process ID). +.Pp +If a signal is caught while any of the +.Fn wait +calls is pending, +the call may be interrupted or restarted when the signal-catching routine +returns, +depending on the options in effect for the signal; +see +.Xr intro 2 , +System call restart. +.Sh RETURN VALUES +If +.Fn wait +returns due to a stopped +or terminated child process, the process ID of the child +is returned to the calling process. Otherwise, a value of -1 +is returned and +.Va errno +is set to indicate the error. +.Pp +If +.Fn wait4 , +.Fn wait3 +or +.Fn waitpid +returns due to a stopped +or terminated child process, the process ID of the child +is returned to the calling process. +If there are no children not previously awaited, +-1 is returned with +.Va errno +set to +.Bq Er ECHILD . +Otherwise, if +.Dv WNOHANG +is specified and there are +no stopped or exited children, +0 is returned. +If an error is detected or a caught signal aborts the call, +a value of -1 +is returned and +.Va errno +is set to indicate the error. +.Sh ERRORS +.Fn Wait +will fail and return immediately if: +.Bl -tag -width Er +.It Bq Er ECHILD +The calling process has no existing unwaited-for +child processes. +.It Bq Er EFAULT +The +.Fa status +or +.Fa rusage +arguments point to an illegal address. +(May not be detected before exit of a child process.) +.It Bq Er EINTR +The call was interrupted by a caught signal, +or the signal did not have the +.Dv SA_RESTART +flag set. +.It Bq Er EINVAL +Invalid or underfined flags were passed in the +.Fa options +argument. +.El +.Sh STANDARDS +The +.Fn wait +and +.Fn waitpid +functions are defined by POSIX; +.Fn wait4 +and +.Fn wait3 +are not specified by POSIX. +The +.Fn WCOREDUMP +macro +and the ability to restart a pending +.Fn wait +call are extensions to the POSIX interface. +.Sh SEE ALSO +.Xr exit 2 , +.Xr sigaction 2 +.Sh HISTORY +A +.Fn wait +function call appeared in +.At v6 . diff --git a/bsd/man/man2/wait3.2 b/bsd/man/man2/wait3.2 new file mode 100644 index 000000000..0605b3543 --- /dev/null +++ b/bsd/man/man2/wait3.2 @@ -0,0 +1 @@ +.so man2/wait.2 diff --git a/bsd/man/man2/wait4.2 b/bsd/man/man2/wait4.2 new file mode 100644 index 000000000..0605b3543 --- /dev/null +++ b/bsd/man/man2/wait4.2 @@ -0,0 +1 @@ +.so man2/wait.2 diff --git a/bsd/man/man2/waitpid.2 b/bsd/man/man2/waitpid.2 new file mode 100644 index 000000000..0605b3543 --- /dev/null +++ b/bsd/man/man2/waitpid.2 @@ -0,0 +1 @@ +.so man2/wait.2 diff --git a/bsd/man/man2/write.2 b/bsd/man/man2/write.2 new file mode 100644 index 000000000..941b122c3 --- /dev/null +++ b/bsd/man/man2/write.2 @@ -0,0 +1,246 @@ +.\" Copyright (c) 1980, 1991, 1993 +.\" 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. +.\" +.\" @(#)write.2 8.5 (Berkeley) 4/2/94 +.\" $FreeBSD: src/lib/libc/sys/write.2,v 1.12.2.7 2001/12/14 18:34:02 ru Exp $ +.\" +.Dd April 2, 1994 +.Dt WRITE 2 +.Os +.Sh NAME +.Nm write , +.Nm writev , +.Nm pwrite +.Nd write output +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In sys/types.h +.In sys/uio.h +.In unistd.h +.Ft ssize_t +.Fn write "int d" "const void *buf" "size_t nbytes" +.Ft ssize_t +.Fn writev "int d" "const struct iovec *iov" "int iovcnt" +.Ft ssize_t +.Fn pwrite "int d" "const void *buf" "size_t nbytes" "off_t offset" +.Sh DESCRIPTION +.Fn Write +attempts to write +.Fa nbytes +of data to the object referenced by the descriptor +.Fa d +from the buffer pointed to by +.Fa buf . +.Fn Writev +performs the same action, but gathers the output data +from the +.Fa iovcnt +buffers specified by the members of the +.Fa iov +array: iov[0], iov[1], ..., iov[iovcnt\|-\|1]. +.Fn Pwrite +performs the same function, but writes to the specified position in +the file without modifying the file pointer. +.Pp +For +.Fn writev , +the +.Fa iovec +structure is defined as: +.Pp +.Bd -literal -offset indent -compact +struct iovec { + char *iov_base; /* Base address. */ + size_t iov_len; /* Length. */ +}; +.Ed +.Pp +Each +.Fa iovec +entry specifies the base address and length of an area +in memory from which data should be written. +.Fn Writev +will always write a complete area before proceeding +to the next. +.Pp +On objects capable of seeking, the +.Fn write +starts at a position +given by the pointer associated with +.Fa d , +see +.Xr lseek 2 . +Upon return from +.Fn write , +the pointer is incremented by the number of bytes which were written. +.Pp +Objects that are not capable of seeking always write from the current +position. The value of the pointer associated with such an object +is undefined. +.Pp +If the real user is not the super-user, then +.Fn write +clears the set-user-id bit on a file. +This prevents penetration of system security +by a user who +.Dq captures +a writable set-user-id file +owned by the super-user. +.Pp +When using non-blocking I/O on objects such as sockets that are subject +to flow control, +.Fn write +and +.Fn writev +may write fewer bytes than requested; +the return value must be noted, +and the remainder of the operation should be retried when possible. +.Sh RETURN VALUES +Upon successful completion the number of bytes which were written +is returned. Otherwise a -1 is returned and the global variable +.Va errno +is set to indicate the error. +.Sh ERRORS +.Fn Write , +.Fn writev , +and +.Fn pwrite +will fail and the file pointer will remain unchanged if: +.Bl -tag -width Er +.It Bq Er EBADF +.Fa D +is not a valid descriptor open for writing. +.It Bq Er EPIPE +An attempt is made to write to a pipe that is not open +for reading by any process. +.It Bq Er EPIPE +An attempt is made to write to a socket of type +.Dv SOCK_STREAM +that is not connected to a peer socket. +.It Bq Er EFBIG +An attempt was made to write a file that exceeds the process's +file size limit or the maximum file size. +.It Bq Er EFAULT +Part of +.Fa iov +or data to be written to the file +points outside the process's allocated address space. +.It Bq Er EINVAL +The pointer associated with +.Fa d +was negative. +.It Bq Er ENOSPC +There is no free space remaining on the file system +containing the file. +.It Bq Er EDQUOT +The user's quota of disk blocks on the file system +containing the file has been exhausted. +.It Bq Er EIO +An I/O error occurred while reading from or writing to the file system. +.It Bq Er EINTR +A signal interrupted the write before it could be completed. +.It Bq Er EAGAIN +The file was marked for non-blocking I/O, +and no data could be written immediately. +.El +.Pp +In addition, +.Fn writev +may return one of the following errors: +.Bl -tag -width Er +.It Bq Er EDESTADDRREQ +The destination is no longer available when writing to a +.Ux +domain datagram socket on which +.Xr connect 2 +had been used to set a destination address. +.It Bq Er EINVAL +.Fa Iovcnt +was less than or equal to 0, or greater than +.Dv UIO_MAXIOV . +.It Bq Er EINVAL +One of the +.Fa iov_len +values in the +.Fa iov +array was negative. +.It Bq Er EINVAL +The sum of the +.Fa iov_len +values in the +.Fa iov +array overflowed a 32-bit integer. +.It Bq Er ENOBUFS +The mbuf pool has been completely exhausted when writing to a socket. +.El +.Pp +The +.Fn pwrite +call may also return the following errors: +.Bl -tag -width Er +.It Bq Er EINVAL +The specified file offset is invalid. +.It Bq Er ESPIPE +The file descriptor is associated with a pipe, socket, or FIFO. +.El +.Sh SEE ALSO +.Xr fcntl 2 , +.Xr lseek 2 , +.Xr open 2 , +.Xr pipe 2 , +.Xr select 2 +.Sh STANDARDS +The +.Fn write +function call is expected to conform to +.St -p1003.1-90 . +The +.Fn writev +and +.Fn pwrite +functions are expected to conform to +.St -xpg4.2 . +.Sh HISTORY +The +.Fn pwrite +function call +appeared in +.At V.4 . +The +.Fn writev +function call +appeared in +.Bx 4.2 . +A +.Fn write +function call appeared in +.At v6 . diff --git a/bsd/man/man2/writev.2 b/bsd/man/man2/writev.2 new file mode 100644 index 000000000..5a7182844 --- /dev/null +++ b/bsd/man/man2/writev.2 @@ -0,0 +1 @@ +.so man2/write.2 diff --git a/bsd/man/man4/Makefile b/bsd/man/man4/Makefile new file mode 100644 index 000000000..855721d5e --- /dev/null +++ b/bsd/man/man4/Makefile @@ -0,0 +1,51 @@ +export MakeInc_cmd=${SRCROOT}/makedefs/MakeInc.cmd +export MakeInc_def=${SRCROOT}/makedefs/MakeInc.def +export MakeInc_rule=${SRCROOT}/makedefs/MakeInc.rule +export MakeInc_dir=${SRCROOT}/makedefs/MakeInc.dir + +include $(MakeInc_cmd) +include $(MakeInc_def) + +DATAFILES = \ + arp.4 \ + bpf.4 \ + divert.4 \ + faith.4 \ + fd.4 \ + gif.4 \ + icmp.4 \ + icmp6.4 \ + inet.4 \ + inet6.4 \ + ip.4 \ + ip6.4 \ + ipfirewall.4 \ + ipl.4 \ + ipsec.4 \ + lo.4 \ + netintro.4 \ + networking.4 \ + null.4 \ + pty.4 \ + random.4 \ + route.4 \ + scsi.4 \ + stderr.4 \ + stdin.4 \ + stdout.4 \ + stf.4 \ + tcp.4 \ + termios.4 \ + tty.4 \ + tun.4 \ + udp.4 \ + unix.4 \ + urandom.4 \ + +INSTALL_MAN_LIST = ${DATAFILES} + +INSTALL_MAN_DIR = man4 + +include $(MakeInc_rule) +include $(MakeInc_dir) + diff --git a/bsd/man/man4/arp.4 b/bsd/man/man4/arp.4 new file mode 100644 index 000000000..acdad7029 --- /dev/null +++ b/bsd/man/man4/arp.4 @@ -0,0 +1,126 @@ +.\" $NetBSD: arp.4,v 1.2 1995/03/01 11:50:56 chopps Exp $ +.\" +.\" Copyright (c) 1985, 1986, 1988, 1994 +.\" 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. +.\" +.\" from: @(#)arp4.4 6.5 (Berkeley) 4/18/94 +.\" +.Dd April 18, 1994 +.Dt ARP 4 +.Os BSD 4 +.Sh NAME +.Nm arp +.Nd Address Resolution Protocol +.Sh SYNOPSIS +.Em "pseudo-device ether" +.Sh DESCRIPTION +The Address Resolution Protocol (ARP) is a protocol used to dynamically +map between Internet host addresses and 10Mb/s Ethernet addresses. +It is used by all the 10Mb/s Ethernet interface drivers. +It is not specific to Internet protocols or to 10Mb/s Ethernet, +but this implementation currently supports only that combination. +.Pp +ARP caches Internet-Ethernet address mappings. +When an interface requests a mapping for an address not in the cache, +ARP queues the message which requires the mapping and broadcasts +a message on the associated network requesting the address mapping. +If a response is provided, the new mapping is cached and any pending +message is transmitted. +ARP will queue at most one packet while waiting for a response to a +mapping request; +only the most recently ``transmitted'' packet is kept. +If the target host does not respond after several requests, +the host is considered to be down for a short period (normally 20 seconds), +allowing an error to be returned to transmission attempts during this +interval. +The error is +.Li EHOSTDOWN +for a non-responding destination host, and +.Li EHOSTUNREACH +for a non-responding router. +.Pp +The ARP cache is stored in the system routing table as +dynamically-created host routes. +The route to a directly-attached Ethernet network is installed as a +.Dq cloning +route (one with the +.Li RTF_CLONING +flag set), +causing routes to individual hosts on that network to be created on +demand. +These routes time out periodically (normally 20 minutes after validated; +entries are not validated when not in use). +An entry for a host which is not responding is a +.Dq reject +route (one with the +.Li RTF_REJECT +flag set). +.Pp +ARP entries may be added, deleted or changed with the +.Xr arp 8 +utility. +Manually-added entries may be temporary or permanent, +and may be +.Dq published , +in which case the system will respond to ARP requests for that host +as if it were the target of the request. +.Pp +In the past, +ARP was used to negotiate the use of a trailer encapsulation. +This is no longer supported. +.Pp +ARP watches passively for hosts impersonating the local host (i.e. a host +which responds to an ARP mapping request for the local host's address). +.Sh DIAGNOSTICS +.Em "duplicate IP address %x!! sent from ethernet address: %x:%x:%x:%x:%x:%x." +ARP has discovered another host on the local network which responds to +mapping requests for its own Internet address with a different Ethernet +address, generally indicating that two hosts are attempting to use the +same Internet address. +.Sh SEE ALSO +.Xr inet 4 , +.Xr route 4 , +.Xr arp 8 , +.Xr ifconfig 8 , +.Xr route 8 +.sp +.Rs +.%A Plummer, D. +.%B "An Ethernet Address Resolution Protocol" +.%T RFC826 +.Re +.Rs +.%A Leffler, S.J. +.%A Karels, M.J. +.%B "Trailer Encapsulations +.%T RFC893 +.Re + diff --git a/bsd/man/man4/bpf.4 b/bsd/man/man4/bpf.4 new file mode 100644 index 000000000..b79476efc --- /dev/null +++ b/bsd/man/man4/bpf.4 @@ -0,0 +1,740 @@ +.\" 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: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.\" This document is derived in part from the enet man page (enet.4) +.\" distributed with 4.3BSD Unix. +.\" +.\" $FreeBSD: src/share/man/man4/bpf.4,v 1.21.2.10 2001/08/17 13:08:37 ru Exp $ +.\" +.Dd January 16, 1996 +.Dt BPF 4 +.Os +.Sh NAME +.Nm bpf +.Nd Berkeley Packet Filter +.Sh SYNOPSIS +.Cd pseudo-device bpf +.Sh DESCRIPTION +The Berkeley Packet Filter +provides a raw interface to data link layers in a protocol +independent fashion. +All packets on the network, even those destined for other hosts, +are accessible through this mechanism. +.Pp +The packet filter appears as a character special device, +.Pa /dev/bpf0 , +.Pa /dev/bpf1 , +etc. +After opening the device, the file descriptor must be bound to a +specific network interface with the +.Dv BIOCSETIF +ioctl. +A given interface can be shared be multiple listeners, and the filter +underlying each descriptor will see an identical packet stream. +.Pp +A separate device file is required for each minor device. +If a file is in use, the open will fail and +.Va errno +will be set to +.Er EBUSY . +.Pp +Associated with each open instance of a +.Nm +file is a user-settable packet filter. +Whenever a packet is received by an interface, +all file descriptors listening on that interface apply their filter. +Each descriptor that accepts the packet receives its own copy. +.Pp +Reads from these files return the next group of packets +that have matched the filter. +To improve performance, the buffer passed to read must be +the same size as the buffers used internally by +.Nm . +This size is returned by the +.Dv BIOCGBLEN +ioctl (see below), and +can be set with +.Dv BIOCSBLEN . +Note that an individual packet larger than this size is necessarily +truncated. +.Pp +The packet filter will support any link level protocol that has fixed length +headers. Currently, only Ethernet, +.Tn SLIP , +and +.Tn PPP +drivers have been modified to interact with +.Nm . +.Pp +Since packet data is in network byte order, applications should use the +.Xr byteorder 3 +macros to extract multi-byte values. +.Pp +A packet can be sent out on the network by writing to a +.Nm +file descriptor. The writes are unbuffered, meaning only one +packet can be processed per write. +Currently, only writes to Ethernets and +.Tn SLIP +links are supported. +.Sh IOCTLS +The +.Xr ioctl 2 +command codes below are defined in +.Aq Pa net/bpf.h . +All commands require +these includes: +.Bd -literal + #include + #include + #include + #include +.Ed +.Pp +Additionally, +.Dv BIOCGETIF +and +.Dv BIOCSETIF +require +.Aq Pa sys/socket.h +and +.Aq Pa net/if.h . +.Pp +In addition to +.Dv FIONREAD +the following commands may be applied to any open +.Nm +file. +The (third) argument to +.Xr ioctl 2 +should be a pointer to the type indicated. +.Bl -tag -width BIOCGRTIMEOUT +.It Dv BIOCGBLEN +.Pq Li u_int +Returns the required buffer length for reads on +.Nm +files. +.It Dv BIOCSBLEN +.Pq Li u_int +Sets the buffer length for reads on +.Nm +files. The buffer must be set before the file is attached to an interface +with +.Dv BIOCSETIF . +If the requested buffer size cannot be accommodated, the closest +allowable size will be set and returned in the argument. +A read call will result in +.Er EIO +if it is passed a buffer that is not this size. +.It Dv BIOCGDLT +.Pq Li u_int +Returns the type of the data link layer underlying the attached interface. +.Er EINVAL +is returned if no interface has been specified. +The device types, prefixed with +.Dq Li DLT_ , +are defined in +.Aq Pa net/bpf.h . +.It Dv BIOCPROMISC +Forces the interface into promiscuous mode. +All packets, not just those destined for the local host, are processed. +Since more than one file can be listening on a given interface, +a listener that opened its interface non-promiscuously may receive +packets promiscuously. This problem can be remedied with an +appropriate filter. +.It Dv BIOCFLUSH +Flushes the buffer of incoming packets, +and resets the statistics that are returned by BIOCGSTATS. +.It Dv BIOCGETIF +.Pq Li "struct ifreq" +Returns the name of the hardware interface that the file is listening on. +The name is returned in the ifr_name field of +the +.Li ifreq +structure. +All other fields are undefined. +.It Dv BIOCSETIF +.Pq Li "struct ifreq" +Sets the hardware interface associate with the file. This +command must be performed before any packets can be read. +The device is indicated by name using the +.Li ifr_name +field of the +.Li ifreq +structure. +Additionally, performs the actions of +.Dv BIOCFLUSH . +.It Dv BIOCSRTIMEOUT +.It Dv BIOCGRTIMEOUT +.Pq Li "struct timeval" +Set or get the read timeout parameter. +The argument +specifies the length of time to wait before timing +out on a read request. +This parameter is initialized to zero by +.Xr open 2 , +indicating no timeout. +.It Dv BIOCGSTATS +.Pq Li "struct bpf_stat" +Returns the following structure of packet statistics: +.Bd -literal +struct bpf_stat { + u_int bs_recv; /* number of packets received */ + u_int bs_drop; /* number of packets dropped */ +}; +.Ed +.Pp +The fields are: +.Bl -hang -offset indent +.It Li bs_recv +the number of packets received by the descriptor since opened or reset +(including any buffered since the last read call); +and +.It Li bs_drop +the number of packets which were accepted by the filter but dropped by the +kernel because of buffer overflows +(i.e., the application's reads aren't keeping up with the packet traffic). +.El +.It Dv BIOCIMMEDIATE +.Pq Li u_int +Enable or disable +.Dq immediate mode , +based on the truth value of the argument. +When immediate mode is enabled, reads return immediately upon packet +reception. Otherwise, a read will block until either the kernel buffer +becomes full or a timeout occurs. +This is useful for programs like +.Xr rarpd 8 +which must respond to messages in real time. +The default for a new file is off. +.It Dv BIOCSETF +.Pq Li "struct bpf_program" +Sets the filter program used by the kernel to discard uninteresting +packets. An array of instructions and its length is passed in using +the following structure: +.Bd -literal +struct bpf_program { + int bf_len; + struct bpf_insn *bf_insns; +}; +.Ed +.Pp +The filter program is pointed to by the +.Li bf_insns +field while its length in units of +.Sq Li struct bpf_insn +is given by the +.Li bf_len +field. +Also, the actions of +.Dv BIOCFLUSH +are performed. +See section +.Sx "FILTER MACHINE" +for an explanation of the filter language. +.It Dv BIOCVERSION +.Pq Li "struct bpf_version" +Returns the major and minor version numbers of the filter language currently +recognized by the kernel. Before installing a filter, applications must check +that the current version is compatible with the running kernel. Version +numbers are compatible if the major numbers match and the application minor +is less than or equal to the kernel minor. The kernel version number is +returned in the following structure: +.Bd -literal +struct bpf_version { + u_short bv_major; + u_short bv_minor; +}; +.Ed +.Pp +The current version numbers are given by +.Dv BPF_MAJOR_VERSION +and +.Dv BPF_MINOR_VERSION +from +.Aq Pa net/bpf.h . +An incompatible filter +may result in undefined behavior (most likely, an error returned by +.Fn ioctl +or haphazard packet matching). +.It Dv BIOCSHDRCMPLT +.It Dv BIOCGHDRCMPLT +.Pq Li u_int +Set or get the status of the +.Dq header complete +flag. +Set to zero if the link level source address should be filled in automatically +by the interface output routine. Set to one if the link level source +address will be written, as provided, to the wire. This flag is initialized +to zero by default. +.It Dv BIOCSSEESENT +.It Dv BIOCGSEESENT +.Pq Li u_int +Set or get the flag determining whether locally generated packets on the +interface should be returned by BPF. Set to zero to see only incoming +packets on the interface. Set to one to see packets originating +locally and remotely on the interface. This flag is initialized to one by +default. +.El +.Sh BPF HEADER +The following structure is prepended to each packet returned by +.Xr read 2 : +.Bd -literal +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 */ +}; +.Ed +.Pp +The fields, whose values are stored in host order, and are: +.Pp +.Bl -tag -compact -width bh_datalen +.It Li bh_tstamp +The time at which the packet was processed by the packet filter. +.It Li bh_caplen +The length of the captured portion of the packet. This is the minimum of +the truncation amount specified by the filter and the length of the packet. +.It Li bh_datalen +The length of the packet off the wire. +This value is independent of the truncation amount specified by the filter. +.It Li bh_hdrlen +The length of the +.Nm +header, which may not be equal to +.\" XXX - not really a function call +.Fn sizeof "struct bpf_hdr" . +.El +.Pp +The +.Li bh_hdrlen +field exists to account for +padding between the header and the link level protocol. +The purpose here is to guarantee proper alignment of the packet +data structures, which is required on alignment sensitive +architectures and improves performance on many other architectures. +The packet filter insures that the +.Li bpf_hdr +and the network layer +header will be word aligned. Suitable precautions +must be taken when accessing the link layer protocol fields on alignment +restricted machines. (This isn't a problem on an Ethernet, since +the type field is a short falling on an even offset, +and the addresses are probably accessed in a bytewise fashion). +.Pp +Additionally, individual packets are padded so that each starts +on a word boundary. This requires that an application +has some knowledge of how to get from packet to packet. +The macro +.Dv BPF_WORDALIGN +is defined in +.Aq Pa net/bpf.h +to facilitate +this process. It rounds up its argument +to the nearest word aligned value (where a word is +.Dv BPF_ALIGNMENT +bytes wide). +.Pp +For example, if +.Sq Li p +points to the start of a packet, this expression +will advance it to the next packet: +.Dl p = (char *)p + BPF_WORDALIGN(p->bh_hdrlen + p->bh_caplen) +.Pp +For the alignment mechanisms to work properly, the +buffer passed to +.Xr read 2 +must itself be word aligned. +The +.Xr malloc 3 +function +will always return an aligned buffer. +.Sh FILTER MACHINE +A filter program is an array of instructions, with all branches forwardly +directed, terminated by a +.Em return +instruction. +Each instruction performs some action on the pseudo-machine state, +which consists of an accumulator, index register, scratch memory store, +and implicit program counter. +.Pp +The following structure defines the instruction format: +.Bd -literal +struct bpf_insn { + u_short code; + u_char jt; + u_char jf; + u_long k; +}; +.Ed +.Pp +The +.Li k +field is used in different ways by different instructions, +and the +.Li jt +and +.Li jf +fields are used as offsets +by the branch instructions. +The opcodes are encoded in a semi-hierarchical fashion. +There are eight classes of instructions: +.Dv BPF_LD , +.Dv BPF_LDX , +.Dv BPF_ST , +.Dv BPF_STX , +.Dv BPF_ALU , +.Dv BPF_JMP , +.Dv BPF_RET , +and +.Dv BPF_MISC . +Various other mode and +operator bits are or'd into the class to give the actual instructions. +The classes and modes are defined in +.Aq Pa net/bpf.h . +.Pp +Below are the semantics for each defined +.Nm +instruction. +We use the convention that A is the accumulator, X is the index register, +P[] packet data, and M[] scratch memory store. +P[i:n] gives the data at byte offset +.Dq i +in the packet, +interpreted as a word (n=4), +unsigned halfword (n=2), or unsigned byte (n=1). +M[i] gives the i'th word in the scratch memory store, which is only +addressed in word units. The memory store is indexed from 0 to +.Dv BPF_MEMWORDS +- 1. +.Li k , +.Li jt , +and +.Li jf +are the corresponding fields in the +instruction definition. +.Dq len +refers to the length of the packet. +.Pp +.Bl -tag -width BPF_STXx +.It Dv BPF_LD +These instructions copy a value into the accumulator. The type of the +source operand is specified by an +.Dq addressing mode +and can be a constant +.Pq Dv BPF_IMM , +packet data at a fixed offset +.Pq Dv BPF_ABS , +packet data at a variable offset +.Pq Dv BPF_IND , +the packet length +.Pq Dv BPF_LEN , +or a word in the scratch memory store +.Pq Dv BPF_MEM . +For +.Dv BPF_IND +and +.Dv BPF_ABS , +the data size must be specified as a word +.Pq Dv BPF_W , +halfword +.Pq Dv BPF_H , +or byte +.Pq Dv BPF_B . +The semantics of all the recognized +.Dv BPF_LD +instructions follow. +.Pp +.Bl -tag -width "BPF_LD+BPF_W+BPF_IND" -compact +.It Li BPF_LD+BPF_W+BPF_ABS +A <- P[k:4] +.It Li BPF_LD+BPF_H+BPF_ABS +A <- P[k:2] +.It Li BPF_LD+BPF_B+BPF_ABS +A <- P[k:1] +.It Li BPF_LD+BPF_W+BPF_IND +A <- P[X+k:4] +.It Li BPF_LD+BPF_H+BPF_IND +A <- P[X+k:2] +.It Li BPF_LD+BPF_B+BPF_IND +A <- P[X+k:1] +.It Li BPF_LD+BPF_W+BPF_LEN +A <- len +.It Li BPF_LD+BPF_IMM +A <- k +.It Li BPF_LD+BPF_MEM +A <- M[k] +.El +.It Dv BPF_LDX +These instructions load a value into the index register. Note that +the addressing modes are more restrictive than those of the accumulator loads, +but they include +.Dv BPF_MSH , +a hack for efficiently loading the IP header length. +.Pp +.Bl -tag -width "BPF_LDX+BPF_W+BPF_MEM" -compact +.It Li BPF_LDX+BPF_W+BPF_IMM +X <- k +.It Li BPF_LDX+BPF_W+BPF_MEM +X <- M[k] +.It Li BPF_LDX+BPF_W+BPF_LEN +X <- len +.It Li BPF_LDX+BPF_B+BPF_MSH +X <- 4*(P[k:1]&0xf) +.El +.It Dv BPF_ST +This instruction stores the accumulator into the scratch memory. +We do not need an addressing mode since there is only one possibility +for the destination. +.Pp +.Bl -tag -width "BPF_ST" -compact +.It Li BPF_ST +M[k] <- A +.El +.It Dv BPF_STX +This instruction stores the index register in the scratch memory store. +.Pp +.Bl -tag -width "BPF_STX" -compact +.It Li BPF_STX +M[k] <- X +.El +.It Dv BPF_ALU +The alu instructions perform operations between the accumulator and +index register or constant, and store the result back in the accumulator. +For binary operations, a source mode is required +.Dv ( BPF_K +or +.Dv BPF_X ) . +.Pp +.Bl -tag -width "BPF_ALU+BPF_MUL+BPF_K" -compact +.It Li BPF_ALU+BPF_ADD+BPF_K +A <- A + k +.It Li BPF_ALU+BPF_SUB+BPF_K +A <- A - k +.It Li BPF_ALU+BPF_MUL+BPF_K +A <- A * k +.It Li BPF_ALU+BPF_DIV+BPF_K +A <- A / k +.It Li BPF_ALU+BPF_AND+BPF_K +A <- A & k +.It Li BPF_ALU+BPF_OR+BPF_K +A <- A | k +.It Li BPF_ALU+BPF_LSH+BPF_K +A <- A << k +.It Li BPF_ALU+BPF_RSH+BPF_K +A <- A >> k +.It Li BPF_ALU+BPF_ADD+BPF_X +A <- A + X +.It Li BPF_ALU+BPF_SUB+BPF_X +A <- A - X +.It Li BPF_ALU+BPF_MUL+BPF_X +A <- A * X +.It Li BPF_ALU+BPF_DIV+BPF_X +A <- A / X +.It Li BPF_ALU+BPF_AND+BPF_X +A <- A & X +.It Li BPF_ALU+BPF_OR+BPF_X +A <- A | X +.It Li BPF_ALU+BPF_LSH+BPF_X +A <- A << X +.It Li BPF_ALU+BPF_RSH+BPF_X +A <- A >> X +.It Li BPF_ALU+BPF_NEG +A <- -A +.El +.It Dv BPF_JMP +The jump instructions alter flow of control. Conditional jumps +compare the accumulator against a constant +.Pq Dv BPF_K +or the index register +.Pq Dv BPF_X . +If the result is true (or non-zero), +the true branch is taken, otherwise the false branch is taken. +Jump offsets are encoded in 8 bits so the longest jump is 256 instructions. +However, the jump always +.Pq Dv BPF_JA +opcode uses the 32 bit +.Li k +field as the offset, allowing arbitrarily distant destinations. +All conditionals use unsigned comparison conventions. +.Pp +.Bl -tag -width "BPF_JMP+BPF_KSET+BPF_X" -compact +.It Li BPF_JMP+BPF_JA +pc += k +.It Li BPF_JMP+BPF_JGT+BPF_K +pc += (A > k) ? jt : jf +.It Li BPF_JMP+BPF_JGE+BPF_K +pc += (A >= k) ? jt : jf +.It Li BPF_JMP+BPF_JEQ+BPF_K +pc += (A == k) ? jt : jf +.It Li BPF_JMP+BPF_JSET+BPF_K +pc += (A & k) ? jt : jf +.It Li BPF_JMP+BPF_JGT+BPF_X +pc += (A > X) ? jt : jf +.It Li BPF_JMP+BPF_JGE+BPF_X +pc += (A >= X) ? jt : jf +.It Li BPF_JMP+BPF_JEQ+BPF_X +pc += (A == X) ? jt : jf +.It Li BPF_JMP+BPF_JSET+BPF_X +pc += (A & X) ? jt : jf +.El +.It Dv BPF_RET +The return instructions terminate the filter program and specify the amount +of packet to accept (i.e., they return the truncation amount). A return +value of zero indicates that the packet should be ignored. +The return value is either a constant +.Pq Dv BPF_K +or the accumulator +.Pq Dv BPF_A . +.Pp +.Bl -tag -width "BPF_RET+BPF_K" -compact +.It Li BPF_RET+BPF_A +accept A bytes +.It Li BPF_RET+BPF_K +accept k bytes +.El +.It Dv BPF_MISC +The miscellaneous category was created for anything that doesn't +fit into the above classes, and for any new instructions that might need to +be added. Currently, these are the register transfer instructions +that copy the index register to the accumulator or vice versa. +.Pp +.Bl -tag -width "BPF_MISC+BPF_TAX" -compact +.It Li BPF_MISC+BPF_TAX +X <- A +.It Li BPF_MISC+BPF_TXA +A <- X +.El +.El +.Pp +The +.Nm +interface provides the following macros to facilitate +array initializers: +.Fn BPF_STMT opcode operand +and +.Fn BPF_JUMP opcode operand true_offset false_offset . +.Sh EXAMPLES +The following filter is taken from the Reverse ARP Daemon. It accepts +only Reverse ARP requests. +.Bd -literal +struct bpf_insn insns[] = { + BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12), + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETHERTYPE_REVARP, 0, 3), + BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 20), + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, REVARP_REQUEST, 0, 1), + BPF_STMT(BPF_RET+BPF_K, sizeof(struct ether_arp) + + sizeof(struct ether_header)), + BPF_STMT(BPF_RET+BPF_K, 0), +}; +.Ed +.Pp +This filter accepts only IP packets between host 128.3.112.15 and +128.3.112.35. +.Bd -literal +struct bpf_insn insns[] = { + BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12), + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETHERTYPE_IP, 0, 8), + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 26), + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x8003700f, 0, 2), + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 30), + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x80037023, 3, 4), + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x80037023, 0, 3), + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 30), + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x8003700f, 0, 1), + BPF_STMT(BPF_RET+BPF_K, (u_int)-1), + BPF_STMT(BPF_RET+BPF_K, 0), +}; +.Ed +.Pp +Finally, this filter returns only TCP finger packets. We must parse +the IP header to reach the TCP header. The +.Dv BPF_JSET +instruction +checks that the IP fragment offset is 0 so we are sure +that we have a TCP header. +.Bd -literal +struct bpf_insn insns[] = { + BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12), + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETHERTYPE_IP, 0, 10), + BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 23), + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, IPPROTO_TCP, 0, 8), + BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 20), + BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x1fff, 6, 0), + BPF_STMT(BPF_LDX+BPF_B+BPF_MSH, 14), + BPF_STMT(BPF_LD+BPF_H+BPF_IND, 14), + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 79, 2, 0), + BPF_STMT(BPF_LD+BPF_H+BPF_IND, 16), + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 79, 0, 1), + BPF_STMT(BPF_RET+BPF_K, (u_int)-1), + BPF_STMT(BPF_RET+BPF_K, 0), +}; +.Ed +.Sh SEE ALSO +.Xr tcpdump 1 , +.Xr ioctl 2 , +.Xr byteorder 3 , +.Xr ng_bpf 4 +.Rs +.%A McCanne, S. +.%A Jacobson V. +.%T "An efficient, extensible, and portable network monitor" +.Re +.Sh FILES +.Bl -tag -compact -width /dev/bpfXXX +.It Pa /dev/bpf Ns Sy n +the packet filter device +.El +.Sh BUGS +The read buffer must be of a fixed size (returned by the +.Dv BIOCGBLEN +ioctl). +.Pp +A file that does not request promiscuous mode may receive promiscuously +received packets as a side effect of another file requesting this +mode on the same hardware interface. This could be fixed in the kernel +with additional processing overhead. However, we favor the model where +all files must assume that the interface is promiscuous, and if +so desired, must utilize a filter to reject foreign packets. +.Pp +Data link protocols with variable length headers are not currently supported. +.Sh HISTORY +The Enet packet filter was created in 1980 by Mike Accetta and +Rick Rashid at Carnegie-Mellon University. Jeffrey Mogul, at +Stanford, ported the code to +.Bx +and continued its development from +1983 on. Since then, it has evolved into the Ultrix Packet Filter +at +.Tn DEC , +a +.Tn STREAMS +.Tn NIT +module under +.Tn SunOS 4.1 , +and +.Tn BPF . +.Sh AUTHORS +.An -nosplit +.An Steven McCanne , +of Lawrence Berkeley Laboratory, implemented BPF in +Summer 1990. Much of the design is due to +.An Van Jacobson . diff --git a/bsd/man/man4/divert.4 b/bsd/man/man4/divert.4 new file mode 100644 index 000000000..33922c4c3 --- /dev/null +++ b/bsd/man/man4/divert.4 @@ -0,0 +1,168 @@ +.\" $FreeBSD: src/share/man/man4/divert.4,v 1.15.2.5 2001/08/17 13:08:37 ru Exp $ +.\" +.Dd June 18, 1996 +.Dt DIVERT 4 +.Os +.Sh NAME +.Nm divert +.Nd kernel packet diversion mechanism +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Fd #include +.Ft int +.Fn socket PF_INET SOCK_RAW IPPROTO_DIVERT +.Sh DESCRIPTION +Divert sockets are similar to raw IP sockets, except that they +can be bound to a specific +.Nm +port via the +.Xr bind 2 +system call. +The IP address in the bind is ignored; only the port +number is significant. +A divert socket bound to a divert port will receive all packets diverted +to that port by some (here unspecified) kernel mechanism(s). +Packets may also be written to a divert port, in which case they +re-enter kernel IP packet processing. +.Pp +Divert sockets are normally used in conjunction with +.Fx Ns 's +packet filtering implementation and the +.Xr ipfw 8 +program. +By reading from and writing to a divert socket, matching packets +can be passed through an arbitrary ``filter'' as they travel through +the host machine, special routing tricks can be done, etc. +.Sh READING PACKETS +Packets are diverted either as they are ``incoming'' or ``outgoing.'' +Incoming packets are diverted after reception on an IP interface, +whereas outgoing packets are diverted before next hop forwarding. +.Pp +Diverted packets may be read unaltered via +.Xr read 2 , +.Xr recv 2 , +or +.Xr recvfrom 2 . +In the latter case, the address returned will have its port set to +the some tag supplied by the packet diverter, (usually the ipfw rule number) +and the IP address set to the (first) address of +the interface on which the packet was received (if the packet +was incoming) or +.Dv INADDR_ANY +(if the packet was outgoing). In the case of an incoming packet the interface +name will also be placed in the 8 bytes following the address, +(assuming it fits). +.Sh WRITING PACKETS +Writing to a divert socket is similar to writing to a raw IP socket; +the packet is injected ``as is'' into the normal kernel IP packet +processing and minimal error checking is done. +Packets are written as either incoming or outgoing: +if +.Xr write 2 +or +.Xr send 2 +is used to deliver the packet, or if +.Xr sendto 2 +is used with a destination IP address of +.Dv INADDR_ANY , +then the packet is treated as if it were outgoing, i.e., destined +for a non-local address. Otherwise, the packet is assumed to be +incoming and full packet routing is done. +.Pp +In the latter case, the +IP address specified must match the address of some local interface, +or an interface name +must be found after the IP address. +If an interface name is found, +that interface will be used and the value of the IP address will be +ignored (other than the fact that it is not +.Dv INADDR_ANY ) . +This is to indicate on which interface the packet ``arrived.'' +.Pp +Normally, packets read as incoming should be written as incoming; +similarly for outgoing packets. When reading and then writing back +packets, passing the same socket address supplied by +.Xr recvfrom 2 +unmodified to +.Xr sendto 2 +simplifies things (see below). +.Pp +The port part of the socket address passed to the +.Xr sendto 2 +contains a tag that should be meaningful to the diversion module. +In the +case of +.Xr ipfw 8 +the tag is interpreted as the rule number +.Em after which +rule processing should restart. +.Sh LOOP AVOIDANCE +Packets written into a divert socket +(using +.Xr sendto 2 ) +re-enter the packet filter at the rule number +following the tag given in the port part of the socket address, which +is usually already set at the rule number that caused the diversion +(not the next rule if there are several at the same number). If the 'tag' +is altered to indicate an alternative re-entry point, care should be taken +to avoid loops, where the same packet is diverted more than once at the +same rule. +.Sh DETAILS +To enable divert sockets, your kernel must be compiled with the option +.Dv IPDIVERT . +.Pp +If a packet is diverted but no socket is bound to the +port, or if +.Dv IPDIVERT +is not enabled in the kernel, the packet is dropped. +.Pp +Incoming packet fragments which get diverted are fully reassembled +before delivery; the diversion of any one fragment causes the entire +packet to get diverted. +If different fragments divert to different ports, +then which port ultimately gets chosen is unpredictable. +.Pp +Packets are received and sent unchanged, except that +packets read as outgoing have invalid IP header checksums, and +packets written as outgoing have their IP header checksums overwritten +with the correct value. +Packets written as incoming and having incorrect checksums will be dropped. +Otherwise, all header fields are unchanged (and therefore in network order). +.Pp +Binding to port numbers less than 1024 requires super-user access, as does +creating a socket of type SOCK_RAW. +.Sh ERRORS +Writing to a divert socket can return these errors, along with +the usual errors possible when writing raw packets: +.Bl -tag -width Er +.It Bq Er EINVAL +The packet had an invalid header, or the IP options in the packet +and the socket options set were incompatible. +.It Bq Er EADDRNOTAVAIL +The destination address contained an IP address not equal to +.Dv INADDR_ANY +that was not associated with any interface. +.El +.Sh SEE ALSO +.Xr bind 2 , +.Xr recvfrom 2 , +.Xr sendto 2 , +.Xr socket 2 , +.Xr ipfw 8 +.Sh BUGS +This is an attempt to provide a clean way for user mode processes +to implement various IP tricks like address translation, but it +could be cleaner, and it's too dependent on +.Xr ipfw 8 . +.Pp +It's questionable whether incoming fragments should be reassembled +before being diverted. +For example, if only some fragments of a +packet destined for another machine don't get routed through the +local machine, the packet is lost. +This should probably be +a settable socket option in any case. +.Sh AUTHORS +.An Archie Cobbs Aq archie@FreeBSD.org , +Whistle Communications Corp. diff --git a/bsd/man/man4/faith.4 b/bsd/man/man4/faith.4 new file mode 100644 index 000000000..ab6ccca7b --- /dev/null +++ b/bsd/man/man4/faith.4 @@ -0,0 +1,124 @@ +.\" $KAME: faith.4,v 1.9 2001/04/27 17:26:35 itojun Exp $ +.\" +.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the project nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD: src/share/man/man4/faith.4,v 1.6.2.3 2001/07/03 11:01:24 ume Exp $ +.\" +.Dd April 10, 1999 +.Dt FAITH 4 +.Os +.Sh NAME +.Nm faith +.Nd IPv6-to-IPv4 TCP relay capturing interface +.Sh SYNOPSIS +.Cd "pseudo-device faith" Op Ar count +.Sh DESCRIPTION +The +.Nm +interface captures IPv6 TCP traffic, +for implementing userland IPv6-to-IPv4 TCP relay +like +.Xr faithd 8 . +.Pp +Special action will be taken when IPv6 TCP traffic is seen on a router, +and routing table suggests to route it to +.Nm +interface. +In this case, the packet will be accepted by the router, +regardless of list of IPv6 interface addresses assigned to the router. +The packet will be captured by an IPv6 TCP socket, if it has +.Dv IN6P_FAITH +flag turned on and it has matching address/port pairs. +In result, +.Nm +will let you capture IPv6 TCP traffic to some specific destination addresses. +Userland programs, such as +.Xr faithd 8 +can use this behavior to relay IPv6 TCP traffic to IPv4 TCP traffic. +The program can accept some specific IPv6 TCP traffic, perform +.Xr getsockname 2 +to get the IPv6 destination address specified by the client, +and perform application-specific address mapping to relay IPv6 TCP to IPv4 TCP. +.Pp +The +.Dv IN6P_FAITH +flag on IPv6 TCP socket can be set by using +.Xr setsockopt 2 , +with level equals to +.Dv IPPROTO_IPV6 +and optname equals to +.Dv IPv6_FAITH . +.Pp +To handle error reports by ICMPv6, some of ICMPv6 packets routed to +.Nm +interface will be delivered to IPv6 TCP, as well. +.Pp +To understand how +.Nm +can be used, take a look at source code of +.Xr faithd 8 . +.Pp +As +.Nm +interface implements potentially dangerous operation, +great care must be taken when configuring +.Nm +interface. +To avoid possible misuse, +.Xr sysctl 8 +variable +.Li net.inet6.ip6.keepfaith +must be set to +.Li 1 +prior to the use of the interface. +When +.Li net.inet6.ip6.keepfaith +is +.Li 0 , +no packet will be captured by +.Nm +interface. +.Pp +.Nm +interface is intended to be used on routers, not on hosts. +.\" +.Sh SEE ALSO +.Xr inet 4 , +.Xr inet6 4 , +.Xr faithd 8 +.Rs +.%A Jun-ichiro itojun Hagino +.%A Kazu Yamamoto +.%T "An IPv6-to-IPv4 transport relay translator" +.%R internet draft +.%N draft-ietf-ngtrans-tcpudp-relay-04.txt +.%O work in progress material +.Re +.Sh HISTORY +The FAITH IPv6-to-IPv4 TCP relay translator was first appeared in +WIDE hydrangea IPv6 stack. diff --git a/bsd/man/man4/fd.4 b/bsd/man/man4/fd.4 new file mode 100644 index 000000000..7ab5ab196 --- /dev/null +++ b/bsd/man/man4/fd.4 @@ -0,0 +1,93 @@ +.\" $NetBSD: fd.4,v 1.3 1994/11/30 16:22:13 jtc Exp $ +.\" +.\" Copyright (c) 1990, 1991, 1993 +.\" 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. +.\" +.\" @(#)fd.4 8.1 (Berkeley) 6/9/93 +.\" +.Dd June 9, 1993 +.Dt FD 4 +.Os +.Sh NAME +.Nm fd , +.Nm stdin , +.Nm stdout , +.Nm stderr +.Nd file descriptor files +.Sh DESCRIPTION +The files +.Pa /dev/fd/0 +through +.Pa /dev/fd/# +refer to file descriptors which can be accessed through the file +system. +If the file descriptor is open and the mode the file is being opened +with is a subset of the mode of the existing descriptor, the call: +.Bd -literal -offset indent +fd = open("/dev/fd/0", mode); +.Ed +.Pp +and the call: +.Bd -literal -offset indent +fd = fcntl(0, F_DUPFD, 0); +.Ed +.Pp +are equivalent. +.Pp +Opening the files +.Pa /dev/stdin , +.Pa /dev/stdout +and +.Pa /dev/stderr +is equivalent to the following calls: +.Bd -literal -offset indent +fd = fcntl(STDIN_FILENO, F_DUPFD, 0); +fd = fcntl(STDOUT_FILENO, F_DUPFD, 0); +fd = fcntl(STDERR_FILENO, F_DUPFD, 0); +.Ed +.Pp +Flags to the +.Xr open 2 +call other than +.Dv O_RDONLY , +.Dv O_WRONLY +and +.Dv O_RDWR +are ignored. +.Sh FILES +.Bl -tag -width /dev/stderr -compact +.It Pa /dev/fd/# +.It Pa /dev/stdin +.It Pa /dev/stdout +.It Pa /dev/stderr +.El +.Sh SEE ALSO +.Xr tty 4 diff --git a/bsd/man/man4/gif.4 b/bsd/man/man4/gif.4 new file mode 100644 index 000000000..fe42f42cd --- /dev/null +++ b/bsd/man/man4/gif.4 @@ -0,0 +1,239 @@ +.\" $FreeBSD: src/share/man/man4/gif.4,v 1.3.2.9 2002/03/25 10:44:05 brooks Exp $ +.\" $KAME: gif.4,v 1.28 2001/05/18 13:15:56 itojun Exp $ +.\" +.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the project nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd April 10, 1999 +.Dt GIF 4 +.Os +.Sh NAME +.Nm gif +.Nd generic tunnel interface +.Sh SYNOPSIS +.Cd "pseudo-device gif" +.Sh DESCRIPTION +The +.Nm +interface is a generic tunnelling pseudo device for IPv4 and IPv6. +It can tunnel IPv[46] traffic over IPv[46]. +Therefore, there can be four possible configurations. +The behavior of +.Nm +is mainly based on RFC2893 IPv6-over-IPv4 configured tunnel. +On +.Nx , +.Nm +can also tunnel ISO traffic over IPv[46] using EON encapsulation. +.Pp +Each +.Nm +interface is created at runtime using interface cloning. +This is +most easily done with the +.Xr ifconfig 8 +.Cm create +command or using the +.Va gifconfig_ Ns Aq Ar interface +variable in +.Xr rc.conf 5 . +.Pp +To use +.Nm , +administrator needs to configure protocol and addresses used for the outer +header. +This can be done by using +.Xr gifconfig 8 , +or +.Dv SIOCSIFPHYADDR +ioctl. +Also, administrator needs to configure protocol and addresses used for the +inner header, by using +.Xr ifconfig 8 . +Note that IPv6 link-local address +(those start with +.Li fe80:: ) +will be automatically configured whenever possible. +You may need to remove IPv6 link-local address manually using +.Xr ifconfig 8 , +when you would like to disable the use of IPv6 as inner header +(like when you need pure IPv4-over-IPv6 tunnel). +Finally, use routing table to route the packets toward +.Nm +interface. +.Pp +.Nm +can be configured to be ECN friendly. +This can be configured by +.Dv IFF_LINK1 . +.Ss ECN friendly behavior +.Nm +can be configured to be ECN friendly, as described in +.Dv draft-ietf-ipsec-ecn-02.txt . +This is turned off by default, and can be turned on by +.Dv IFF_LINK1 +interface flag. +.Pp +Without +.Dv IFF_LINK1 , +.Nm +will show a normal behavior, like described in RFC2893. +This can be summarized as follows: +.Bl -tag -width "Ingress" -offset indent +.It Ingress +Set outer TOS bit to +.Dv 0 . +.It Egress +Drop outer TOS bit. +.El +.Pp +With +.Dv IFF_LINK1 , +.Nm +will copy ECN bits +.Dv ( 0x02 +and +.Dv 0x01 +on IPv4 TOS byte or IPv6 traffic class byte) +on egress and ingress, as follows: +.Bl -tag -width "Ingress" -offset indent +.It Ingress +Copy TOS bits except for ECN CE +(masked with +.Dv 0xfe ) +from +inner to outer. +Set ECN CE bit to +.Dv 0 . +.It Egress +Use inner TOS bits with some change. +If outer ECN CE bit is +.Dv 1 , +enable ECN CE bit on the inner. +.El +.Pp +Note that the ECN friendly behavior violates RFC2893. +This should be used in mutual agreement with the peer. +.Ss Security +Malicious party may try to circumvent security filters by using +tunnelled packets. +For better protection, +.Nm +performs martian filter and ingress filter against outer source address, +on egress. +Note that martian/ingress filters are no way complete. +You may want to secure your node by using packet filters. +Ingress filter can be turned off by +.Dv IFF_LINK2 +bit. +.\" +.Ss Miscellaneous +By default, +.Nm +tunnels may not be nested. +This behavior may be modified at runtime by setting the +.Xr sysctl 8 +variable +.Va net.link.gif.max_nesting +to the desired level of nesting. +Additionally, +.Nm +tunnels are restricted to one per pair of end points. +Parallel tunnels may be enabled by setting the +.Xr sysctl 8 +variable +.Va net.link.gif.parallel_tunnels +to 1. +.Sh SEE ALSO +.Xr inet 4 , +.Xr inet6 4 , +.Xr gifconfig 8 +.Rs +.%A R. Gilligan +.%A E. Nordmark +.%B RFC2893 +.%T Transition Mechanisms for IPv6 Hosts and Routers +.%D August 2000 +.%O ftp://ftp.isi.edu/in-notes/rfc2893.txt +.Re +.Rs +.%A Sally Floyd +.%A David L. Black +.%A K. K. Ramakrishnan +.%T "IPsec Interactions with ECN" +.%D December 1999 +.%O draft-ietf-ipsec-ecn-02.txt +.Re +.\" +.Sh HISTORY +The +.Nm +device first appeared in WIDE hydrangea IPv6 kit. +.\" +.Sh BUGS +There are many tunnelling protocol specifications, +defined differently from each other. +.Nm +may not interoperate with peers which are based on different specifications, +and are picky about outer header fields. +For example, you cannot usually use +.Nm +to talk with IPsec devices that use IPsec tunnel mode. +.Pp +The current code does not check if the ingress address +(outer source address) +configured to +.Nm +makes sense. +Make sure to configure an address which belongs to your node. +Otherwise, your node will not be able to receive packets from the peer, +and your node will generate packets with a spoofed source address. +.Pp +If the outer protocol is IPv4, +.Nm +does not try to perform path MTU discovery for the encapsulated packet +(DF bit is set to 0). +.Pp +If the outer protocol is IPv6, path MTU discovery for encapsulated packet +may affect communication over the interface. +The first bigger-than-pmtu packet may be lost. +To avoid the problem, you may want to set the interface MTU for +.Nm +to 1240 or smaller, when outer header is IPv6 and inner header is IPv4. +.Pp +.Nm +does not translate ICMP messages for outer header into inner header. +.Pp +In the past, +.Nm +had a multi-destination behavior, configurable via +.Dv IFF_LINK0 +flag. +The behavior was obsoleted and is no longer supported. +.Pp +It is thought that this is not actually a bug in gif, but rather lies +somewhere around a manipulation of an IPv6 routing table. diff --git a/bsd/man/man4/icmp.4 b/bsd/man/man4/icmp.4 new file mode 100644 index 000000000..054b77018 --- /dev/null +++ b/bsd/man/man4/icmp.4 @@ -0,0 +1,207 @@ +.\" $NetBSD: icmp.4,v 1.3 1994/11/30 16:22:14 jtc Exp $ +.\" +.\" Copyright (c) 1986, 1991, 1993 +.\" 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. +.\" +.\" @(#)icmp.4 8.1 (Berkeley) 6/5/93 +.\" +.Dd June 19, 2002 +.Dt ICMP 4 +.Os BSD 4.3 +.Sh NAME +.Nm icmp +.Nd Internet Control Message Protocol +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn socket AF_INET SOCK_RAW proto +.Sh DESCRIPTION +.Tn ICMP +is the error and control message protocol used +by +.Tn IP +and the Internet protocol family. It may be accessed +through a +.Dq raw socket +for network monitoring +and diagnostic functions. +The +.Fa proto +parameter to the socket call to create an +.Tn ICMP +socket +is obtained from +.Xr getprotobyname 3 . +.Tn ICMP +sockets are connectionless, +and are normally used with the +.Xr sendto +and +.Xr recvfrom +calls, though the +.Xr connect 2 +call may also be used to fix the destination for future +packets (in which case the +.Xr read 2 +or +.Xr recv 2 +and +.Xr write 2 +or +.Xr send 2 +system calls may be used). +.Pp +Outgoing packets automatically have an +.Tn IP +header prepended to +them (based on the destination address). +Incoming packets are received with the +.Tn IP +header and options intact. +.Ss "Non-privileged ICMP" +.Pp +.Tn ICMP +sockets can be opened with the +.Dv SOCK_DGRAM +socket type without requiring root privileges. The synopsis is the following: +.Pp +.Fn socket AF_INET SOCK_DGRAM IPPROTO_IP +.Pp +This can be used by non root privileged processes to send +.Tn ICMP +echo requests to gauge the quality of the connectivity to a host, to receive +.Tn ICMP +destination unreachable message for path MTU discovery, or to receveive +time exceeded message for traceroute. +.Pp +Datagram oriented +.Tn ICMP +sockets offer a subset of the functionality available to raw +.Tn ICMP +sockets. Only +.Tn IMCP +request messages of the following types can be sent: +ICMP_ECHO, ICMP_TSTAMP or ICMP_MASKREQ. +The code field must be the value zero (0). +The minimal length of an +.Tn ICMP +message request is eight (8) octets. +.Pp +The following +.Tn IP +level option can be used with datagram oriented +.Tn ICMP +sockets: +.Bl -column ip_opts -offset 4n +.It IP_OPTIONS +.It IP_HDRINCL +.It IP_TOS +.It IP_TTL +.It IP_RECVOPTS +.It IP_RECVRETOPTS +.It IP_RECVDSTADDR +.It IP_RETOPTS +.It IP_MULTICAST_IF +.It IP_MULTICAST_TTL +.It IP_MULTICAST_LOOP +.It IP_ADD_MEMBERSHIP +.It IP_DROP_MEMBERSHIP +.It IP_MULTICAST_VIF +.It IP_PORTRANGE +.It IP_RECVIF +.It IP_IPSEC_POLICY +.It IP_STRIPHDR +.El +.Pp +When the +.Tn IP +option IP_HDRINCL is used, the provided +.Tn IP +header must obey the following rules: +.Bl -column ip_opts -offset 4n +.It ip_v Ta Must be IPVERSION (4); +.It ip_hl Ta Between 5 and 10 (inclusive); +.It ip_tos Ta Any value; +.It ip_len Ta Must be the total length of IP datagram (IP header + ICMP message); +.It ip_id Ta Must be zero, will be automatically set; +.It ip_off Ta Must be zero, will be automatically set; +.It ip_ttl Ta Any value; +.It ip_p Ta Must be IPPROTO_IP; +.It ip_sum Ta Value ignored, will be automatically set; +.It ip_src Ta Must be an +.Tn IP +address currently assigned to one of the local interface or INADDR_ANY; +.It ip_dst Ta Any address; +.It ip_opts Ta Any option. +.El +.Pp +The maximum length of a IMCP message that can be sent is controlled +by the sysctl +variable net.inet.raw.maxdgram. +.Sh DIAGNOSTICS +A socket operation may fail with one of the following errors returned: +.Bl -tag -width [EADDRNOTAVAIL] +.It Bq Er EISCONN +when trying to establish a connection on a socket which +already has one, or when trying to send a datagram with the destination +address specified and the socket is already connected; +.It Bq Er ENOTCONN +when trying to send a datagram, but +no destination address is specified, and the socket hasn't been +connected; +.It Bq Er ENOBUFS +when the system runs out of memory for +an internal data structure; +.It Bq Er EADDRNOTAVAIL +when an attempt is made to create a +socket with a network address for which no network interface +exists; +.It Bq Er EINVAL +when an invalid value is used with +.Tn IMCP +datagram socket for a field of the +.Tn IP +or +.Tn ICMP +header. +.El +.Sh SEE ALSO +.Xr send 2 , +.Xr recv 2 , +.Xr intro 4 , +.Xr inet 4 , +.Xr ip 4 +.Sh HISTORY +The +.Nm +protocol appeared in +.Bx 4.3 . diff --git a/bsd/man/man4/icmp6.4 b/bsd/man/man4/icmp6.4 new file mode 100644 index 000000000..fe6cc97e4 --- /dev/null +++ b/bsd/man/man4/icmp6.4 @@ -0,0 +1,267 @@ +.\" Copyright (C) 1999 WIDE Project. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the project nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" Copyright (c) 1986, 1991, 1993 +.\" 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. +.\" +.\" KAME $Id: icmp6.4,v 1.2 2002/04/17 00:18:23 lindak Exp $ +.\" $FreeBSD: src/share/man/man4/icmp6.4,v 1.1.2.7 2001/12/17 11:30:12 ru Exp $ +.\" +.Dd March 13, 2000 +.Dt ICMP6 4 +.Os +.\" +.Sh NAME +.Nm icmp6 +.Nd Internet Control Message Protocol for IPv6 +.\" +.Sh SYNOPSIS +.In sys/types.h +.In sys/socket.h +.In netinet/in.h +.In netinet/icmp6.h +.Ft int +.Fn socket AF_INET6 SOCK_RAW proto +.\" +.Sh DESCRIPTION +.Tn ICMPv6 +is the error and control message protocol used +by +.Tn IPv6 +and the Internet protocol family. +It may be accessed through a +.Dq raw socket +for network monitoring and diagnostic functions. +The +.Fa proto +parameter to the socket call to create an +.Tn ICMPv6 +socket is obtained from +.Xr getprotobyname 3 , +or you can use +.Dv IPPROTO_ICMPV6 . +.Tn ICMPv6 +sockets are connectionless, and are normally used with the +.Xr sendto 2 +and +.Xr recvfrom 2 +calls, though the +.Xr connect 2 +call may also be used to fix the destination for future packets +(in which case the +.Xr read 2 +or +.Xr recv 2 +and +.Xr write 2 +or +.Xr send 2 +system calls may be used). +.Pp +Outgoing packets automatically have an +.Tn IPv6 +header prepended to them +(based on the destination address). +.Tn ICMPv6 +pseudo header checksum field +.Pq Li icmp6_cksum +will be filled automatically by the kernel. +Incoming packets are received without the +.Tn IPv6 +header nor IPv6 extension headers. +Notice that this behavior is opposite from +.Tn IPv4 +raw sockets and. +.Tn ICMPv4 +sockets. +.Pp +.Ss ICMPv6 type/code filter +Each +.Tn ICMPv6 +raw socket has an associated filter whose datatype is defined as +.Li struct icmp6_filter ; +.Pp +This structure, along with the macros and constants defined later in +this section, are defined as a result of including the +.Aq Li netinet/icmp6.h +header. +.Pp +The current filter is fetched and stored using +.Xr getsockopt 2 +and +.Xr setsockopt 2 +with a level of +.Dv IPPROTO_ICMPV6 +and an option name of +.Dv ICMP6_FILTER . +.Pp +Six macros operate on an icmp6_filter structure: +.\" is "Fn" legal for macros? +.Bl -item -offset indent +.It +.Ft void +.Fn ICMP6_FILTER_SETPASSALL "struct icmp6_filter *filterp" +.It +.Ft void +.Fn ICMP6_FILTER_SETBLOCKALL "struct icmp6_filter *filterp" +.It +.Ft void +.Fn ICMP6_FILTER_SETPASS "int type" "struct icmp6_filter *filterp" +.It +.Ft void +.Fn ICMP6_FILTER_SETBLOCK "int type" "struct icmp6_filter *filterp" +.It +.Ft int +.Fn ICMP6_FILTER_WILLPASS "int type" "const struct icmp6_filter *filterp" +.It +.Ft int +.Fn ICMP6_FILTER_WILLBLOCK "int type" "const struct icmp6_filter *filterp" +.El +.Pp +The first argument to the last four macros +(an integer) +is an +.Tn ICMPv6 +message type, between 0 and 255. +The pointer argument to all six +macros is a pointer to a filter that is modified by the first four +macros examined by the last two macros. +.Pp +The first two macros, +.Dv SETPASSALL +and +.Dv SETBLOCKALL , +let us specify that +all +.Tn ICMPv6 +messages are passed to the application or that all +.Tn ICMPv6 +messages are blocked from being passed to the application. +.Pp +The next two macros, +.Dv SETPASS +and +.Dv SETBLOCK , +let us specify that +messages of a given +.Tn ICMPv6 +type should be passed to the application +or not passed to the application +(blocked). +.Pp +The final two macros, +.Dv WILLPASS +and +.Dv WILLBLOCK , +return true or false +depending whether the specified message type is passed to the +application or blocked from being passed to the application by the +filter pointed to by the second argument. +.Pp +When an +.Tn ICMPv6 +raw socket is created, it will by default pass all +.Tn ICMPv6 +message types to the application. +.Pp +For further discussions see RFC2292. +.\" +.Sh ERRORS +A socket operation may fail with one of the following errors returned: +.Bl -tag -width Er +.It Bq Er EISCONN +when trying to establish a connection on a socket which +already has one, or when trying to send a datagram with the destination +address specified and the socket is already connected; +.It Bq Er ENOTCONN +when trying to send a datagram, but +no destination address is specified, and the socket hasn't been +connected; +.It Bq Er ENOBUFS +when the system runs out of memory for +an internal data structure; +.It Bq Er EADDRNOTAVAIL +when an attempt is made to create a +socket with a network address for which no network interface exists. +.El +.\" +.Sh SEE ALSO +.Xr recv 2 , +.Xr send 2 , +.Xr inet6 4 , +.Xr intro 4 , +.Xr ip6 4 +.Rs +.%A W. Stevens +.%A M. Thomas +.%R RFC +.%N 2292 +.%D February 1998 +.%T "Advanced Sockets API for IPv6" +.Re +.Rs +.%A A. Conta +.%A S. Deering +.%R RFC +.%N 2463 +.%D December 1998 +.%T "Internet Control Message Protocol (ICMPv6) for the Internet Protocol Version 6 (IPv6) Specification" +.Re +.\" +.Sh HISTORY +The implementation is based on KAME stack +(which is descendant of WIDE hydrangea IPv6 stack kit). +.Pp +Part of the document was shamelessly copied from RFC2292. diff --git a/bsd/man/man4/inet.4 b/bsd/man/man4/inet.4 new file mode 100644 index 000000000..5d70e315d --- /dev/null +++ b/bsd/man/man4/inet.4 @@ -0,0 +1,184 @@ +.\" $NetBSD: inet.4,v 1.3 1994/11/30 16:22:18 jtc Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)inet.4 8.1 (Berkeley) 6/5/93 +.\" +.Dd June 5, 1993 +.Dt INET 4 +.Os BSD 4.2 +.Sh NAME +.Nm inet +.Nd Internet protocol family +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Sh DESCRIPTION +The Internet protocol family is a collection of protocols +layered atop the +.Em Internet Protocol +.Pq Tn IP +transport layer, and utilizing the Internet address format. +The Internet family provides protocol support for the +.Dv SOCK_STREAM , SOCK_DGRAM , +and +.Dv SOCK_RAW +socket types; the +.Dv SOCK_RAW +interface provides access to the +.Tn IP +protocol. +.Sh ADDRESSING +Internet addresses are four byte quantities, stored in +network standard format (on the +.Tn VAX +these are word and byte +reversed). The include file +.Aq Pa netinet/in.h +defines this address +as a discriminated union. +.Pp +Sockets bound to the Internet protocol family utilize +the following addressing structure, +.Bd -literal -offset indent +struct sockaddr_in { + short sin_family; + u_short sin_port; + struct in_addr sin_addr; + char sin_zero[8]; +}; +.Ed +.Pp +Sockets may be created with the local address +.Dv INADDR_ANY +to effect +.Dq wildcard +matching on incoming messages. +The address in a +.Xr connect 2 +or +.Xr sendto 2 +call may be given as +.Dv INADDR_ANY +to mean +.Dq this host . +The distinguished address +.Dv INADDR_BROADCAST +is allowed as a shorthand for the broadcast address on the primary +network if the first network configured supports broadcast. +.Sh PROTOCOLS +The Internet protocol family is comprised of +the +.Tn IP +transport protocol, Internet Control +Message Protocol +.Pq Tn ICMP , +Transmission Control +Protocol +.Pq Tn TCP , +and User Datagram Protocol +.Pq Tn UDP . +.Tn TCP +is used to support the +.Dv SOCK_STREAM +abstraction while +.Tn UDP +is used to support the +.Dv SOCK_DGRAM +abstraction. A raw interface to +.Tn IP +is available +by creating an Internet socket of type +.Dv SOCK_RAW . +The +.Tn ICMP +message protocol is accessible from a raw socket. +.Pp +The 32-bit Internet address contains both network and host parts. +It is frequency-encoded; the most-significant bit is clear +in Class A addresses, in which the high-order 8 bits are the network +number. +Class B addresses use the high-order 16 bits as the network field, +and Class C addresses have a 24-bit network part. +Sites with a cluster of local networks and a connection to the +Internet may chose to use a single network number for the cluster; +this is done by using subnet addressing. +The local (host) portion of the address is further subdivided +into subnet and host parts. +Within a subnet, each subnet appears to be an individual network; +externally, the entire cluster appears to be a single, uniform +network requiring only a single routing entry. +Subnet addressing is enabled and examined by the following +.Xr ioctl 2 +commands on a datagram socket in the Internet domain; +they have the same form as the +.Dv SIOCIFADDR +command (see +.Xr intro 4 ) . +.Pp +.Bl -tag -width SIOCSIFNETMASK +.It Dv SIOCSIFNETMASK +Set interface network mask. +The network mask defines the network part of the address; +if it contains more of the address than the address type would indicate, +then subnets are in use. +.It Dv SIOCGIFNETMASK +Get interface network mask. +.El +.Sh SEE ALSO +.Xr ioctl 2 , +.Xr socket 2 , +.Xr intro 4 , +.Xr tcp 4 , +.Xr udp 4 , +.Xr ip 4 , +.Xr icmp 4 +.Rs +.%T "An Introductory 4.3 BSD Interprocess Communication Tutorial" +.%B PS1 +.%N 7 +.Re +.Rs +.%T "An Advanced 4.3 BSD Interprocess Communication Tutorial" +.%B PS1 +.%N 8 +.Re +.Sh CAVEAT +The Internet protocol support is subject to change as +the Internet protocols develop. Users should not depend +on details of the current implementation, but rather +the services exported. +.Sh HISTORY +The +.Nm +protocol interface appeared in +.Bx 4.2 . diff --git a/bsd/man/man4/inet6.4 b/bsd/man/man4/inet6.4 new file mode 100644 index 000000000..be9d1e818 --- /dev/null +++ b/bsd/man/man4/inet6.4 @@ -0,0 +1,530 @@ +.\" $FreeBSD: src/share/man/man4/inet6.4,v 1.4.2.8 2001/12/17 11:30:12 ru Exp $ +.\" $KAME: inet6.4,v 1.21 2001/04/05 01:00:18 itojun Exp $ +.\" +.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the project nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January 29, 1999 +.Dt INET6 4 +.Os +.Sh NAME +.Nm inet6 +.Nd Internet protocol version 6 family +.Sh SYNOPSIS +.In sys/types.h +.In netinet/in.h +.Sh DESCRIPTION +The +.Nm +family is an updated version of +.Xr inet 4 +family. +While +.Xr inet 4 +implements Internet Protocol version 4, +.Nm +implements Internet Protocol version 6. +.Pp +.Nm +is a collection of protocols layered atop the +.Em Internet Protocol version 6 +.Pq Tn IPv6 +transport layer, and utilizing the IPv6 address format. +The +.Nm +family provides protocol support for the +.Dv SOCK_STREAM , SOCK_DGRAM , +and +.Dv SOCK_RAW +socket types; the +.Dv SOCK_RAW +interface provides access to the +.Tn IPv6 +protocol. +.Sh ADDRESSING +IPv6 addresses are 16 byte quantities, stored in network standard byteorder. +The include file +.Aq Pa netinet/in.h +defines this address +as a discriminated union. +.Pp +Sockets bound to the +.Nm +family utilize the following addressing structure: +.Bd -literal -offset indent +struct sockaddr_in6 { + u_int8_t sin6_len; + u_int8_t sin6_family; + u_int16_t sin6_port; + u_int32_t sin6_flowinfo; + struct in6_addr sin6_addr; + u_int32_t sin6_scope_id; +}; +.Ed +.Pp +Sockets may be created with the local address +.Dq Dv :: +(which is equal to IPv6 address +.Dv 0:0:0:0:0:0:0:0 ) +to affect +.Dq wildcard +matching on incoming messages. +.Pp +The IPv6 specification defines scoped addresses, +like link-local or site-local addresses. +A scoped address is ambiguous to the kernel, +if it is specified without a scope identifier. +To manipulate scoped addresses properly from the userland, +programs must use the advanced API defined in RFC2292. +A compact description of the advanced API is available in +.Xr ip6 4 . +If a scoped address is specified without an explicit scope, +the kernel may raise an error. +Note that scoped addresses are not for daily use at this moment, +both from a specification and an implementation point of view. +.Pp +The KAME implementation supports an extended numeric IPv6 address notation +for link-local addresses, +like +.Dq Li fe80::1%de0 +to specify +.Do +.Li fe80::1 +on +.Li de0 +interface +.Dc . +This notation is supported by +.Xr getaddrinfo 3 +and +.Xr getnameinfo 3 . +Some of normal userland programs, such as +.Xr telnet 1 +or +.Xr ftp 1 , +are able to use this notation. +With special programs +like +.Xr ping6 8 , +you can specify the outgoing interface by an extra command line option +to disambiguate scoped addresses. +.Pp +Scoped addresses are handled specially in the kernel. +In kernel structures like routing tables or interface structures, +a scoped address will have its interface index embedded into the address. +Therefore, +the address in some kernel structures is not the same as that on the wire. +The embedded index will become visible through a +.Dv PF_ROUTE +socket, kernel memory accesses via +.Xr kvm 3 +and on some other occasions. +HOWEVER, users should never use the embedded form. +For details please consult +.Pa IMPLEMENTATION +supplied with KAME kit. +.Sh PROTOCOLS +The +.Nm +family is comprised of the +.Tn IPv6 +network protocol, Internet Control +Message Protocol version 6 +.Pq Tn ICMPv6 , +Transmission Control Protocol +.Pq Tn TCP , +and User Datagram Protocol +.Pq Tn UDP . +.Tn TCP +is used to support the +.Dv SOCK_STREAM +abstraction while +.Tn UDP +is used to support the +.Dv SOCK_DGRAM +abstraction. +Note that +.Tn TCP +and +.Tn UDP +are common to +.Xr inet 4 +and +.Nm . +A raw interface to +.Tn IPv6 +is available +by creating an Internet socket of type +.Dv SOCK_RAW . +The +.Tn ICMPv6 +message protocol is accessible from a raw socket. +.\" .Pp +.\" The 128-bit IPv6 address contains both network and host parts. +.\" However, direct examination of addresses is discouraged. +.\" For those programs which absolutely need to break addresses +.\" into their component parts, the following +.\" .Xr ioctl 2 +.\" commands are provided for a datagram socket in the +.\" .Nm +.\" domain; they have the same form as the +.\" .Dv SIOCIFADDR +.\" command (see +.\" .Xr intro 4 ) . +.\" .Pp +.\" .Bl -tag -width SIOCSIFNETMASK +.\" .It Dv SIOCSIFNETMASK +.\" Set interface network mask. +.\" The network mask defines the network part of the address; +.\" if it contains more of the address than the address type would indicate, +.\" then subnets are in use. +.\" .It Dv SIOCGIFNETMASK +.\" Get interface network mask. +.\" .El +.\" .Sh ROUTING +.\" The current implementation of Internet protocols includes some routing-table +.\" adaptations to provide enhanced caching of certain end-to-end +.\" information necessary for Transaction TCP and Path MTU Discovery. The +.\" following changes are the most significant: +.\" .Bl -enum +.\" .It +.\" All IP routes, except those with the +.\" .Dv RTF_CLONING +.\" flag and those to multicast destinations, have the +.\" .Dv RTF_PRCLONING +.\" flag forcibly enabled (they are thus said to be +.\" .Dq "protocol cloning" ). +.\" .It +.\" When the last reference to an IP route is dropped, the route is +.\" examined to determine if it was created by cloning such a route. If +.\" this is the case, the +.\" .Dv RTF_PROTO3 +.\" flag is turned on, and the expiration timer is initialized to go off +.\" in net.inet.ip.rtexpire seconds. If such a route is re-referenced, +.\" the flag and expiration timer are reset. +.\" .It +.\" A kernel timeout runs once every ten minutes, or sooner if there are +.\" soon-to-expire routes in the kernel routing table, and deletes the +.\" expired routes. +.\" .El +.\" .Pp +.\" A dynamic process is in place to modify the value of +.\" net.inet.ip.rtexpire if the number of cached routes grows too large. +.\" If after an expiration run there are still more than +.\" net.inet.ip.rtmaxcache unreferenced routes remaining, the rtexpire +.\" value is multiplied by 3/4, and any routes which have longer +.\" expiration times have those times adjusted. This process is damped +.\" somewhat by specification of a minimum rtexpire value +.\" (net.inet.ip.rtminexpire), and by restricting the reduction to once in +.\" a ten-minute period. +.\" .Pp +.\" If some external process deletes the original route from which a +.\" protocol-cloned route was generated, the ``child route'' is deleted. +.\" (This is actually a generic mechanism in the routing code support for +.\" protocol-requested cloning.) +.\" .Pp +.\" No attempt is made to manage routes which were not created by protocol +.\" cloning; these are assumed to be static, under the management of an +.\" external routing process, or under the management of a link layer +.\" (e.g., +.\" .Tn ARP +.\" for Ethernets). +.\" .Pp +.\" Only certain types of network activity will result in the cloning of a +.\" route using this mechanism. Specifically, those protocols (such as +.\" .Tn TCP +.\" and +.\" .Tn UDP ) +.\" which themselves cache a long-lasting reference to route for a destination +.\" will trigger the mechanism; whereas raw +.\" .Tn IP +.\" packets, whether locally-generated or forwarded, will not. +.Ss MIB Variables +A number of variables are implemented in the net.inet6 branch of the +.Xr sysctl 3 +MIB. +In addition to the variables supported by the transport protocols +(for which the respective manual pages may be consulted), +the following general variables are defined: +.Bl -tag -width IPV6CTL_MAXFRAGPACKETS +.It Dv IPV6CTL_FORWARDING +.Pq ip6.forwarding +Boolean: enable/disable forwarding of +.Tn IPv6 +packets. +Also, identify if the node is acting as a router. +Defaults to off. +.It Dv IPV6CTL_SENDREDIRECTS +.Pq ip6.redirect +Boolean: enable/disable sending of +.Tn ICMPv6 +redirects in response to unforwardable +.Tn IPv6 +packets. +This option is ignored unless the node is routing +.Tn IPv6 +packets, +and should normally be enabled on all systems. +Defaults to on. +.It Dv IPV6CTL_DEFHLIM +.Pq ip6.hlim +Integer: default hop limit value to use for outgoing +.Tn IPv6 +packets. +This value applies to all the transport protocols on top of +.Tn IPv6 . +There are APIs to override the value. +.It Dv IPV6CTL_MAXFRAGPACKETS +.Pq ip6.maxfragpackets +Integer: default maximum number of fragmented packets the node will accept. +0 means that the node will not accept any fragmented packets. +-1 means that the node will accept as many fragmented packets as it receives. +The flag is provided basically for avoiding possible DoS attacks. +.It Dv IPV6CTL_ACCEPT_RTADV +.Pq ip6.accept_rtadv +Boolean: enable/disable receiving of +.Tn ICMPv6 +router advertisement packets, +and autoconfiguration of address prefixes and default routers. +The node must be a host +(not a router) +for the option to be meaningful. +Defaults to off. +.It Dv IPV6CTL_KEEPFAITH +.Pq ip6.keepfaith +Boolean: enable/disable +.Dq FAITH +TCP relay IPv6-to-IPv4 translator code in the kernel. +Refer +.Xr faith 4 +and +.Xr faithd 8 +for detail. +Defaults to off. +.It Dv IPV6CTL_LOG_INTERVAL +.Pq ip6.log_interval +Integer: default interval between +.Tn IPv6 +packet forwarding engine log output +(in seconds). +.It Dv IPV6CTL_HDRNESTLIMIT +.Pq ip6.hdrnestlimit +Integer: default number of the maximum +.Tn IPv6 +extension headers +permitted on incoming +.Tn IPv6 +packets. +If set to 0, the node will accept as many extension headers as possible. +.It Dv IPV6CTL_DAD_COUNT +.Pq ip6.dad_count +Integer: default number of +.Tn IPv6 +DAD +.Pq duplicated address detection +probe packets. +The packets will be generated when +.Tn IPv6 +interface addresses are configured. +.It Dv IPV6CTL_AUTO_FLOWLABEL +.Pq ip6.auto_flowlabel +Boolean: enable/disable automatic filling of +.Tn IPv6 +flowlabel field, for outstanding connected transport protocol packets. +The field might be used by intermediate routers to identify packet flows. +Defaults to on. +.It Dv IPV6CTL_DEFMCASTHLIM +.Pq ip6.defmcasthlim +Integer: default hop limit value for an +.Tn IPv6 +multicast packet sourced by the node. +This value applies to all the transport protocols on top of +.Tn IPv6 . +There are APIs to override the value as documented in +.Xr ip6 4 . +.It Dv IPV6CTL_GIF_HLIM +.Pq ip6.gifhlim +Integer: default maximum hop limit value for an +.Tn IPv6 +packet generated by +.Xr gif 4 +tunnel interface. +.It Dv IPV6CTL_KAME_VERSION +.Pq ip6.kame_version +String: identifies the version of KAME +.Tn IPv6 +stack implemented in the kernel. +.It Dv IPV6CTL_USE_DEPRECATED +.Pq ip6.use_deprecated +Boolean: enable/disable use of deprecated address, +specified in RFC2462 5.5.4. +Defaults to on. +.It Dv IPV6CTL_RR_PRUNE +.Pq ip6.rr_prune +Integer: default interval between +.Tn IPv6 +router renumbering prefix babysitting, in seconds. +.It Dv IPV6CTL_MAPPED_ADDR +.Pq ip6.mapped_addr +Boolean: enable/disable use of +.Tn IPv4 +mapped address on +.Dv AF_INET6 +sockets. +Defaults to on. +.It Dv IPV6CTL_RTEXPIRE +.Pq ip6.rtexpire +Integer: lifetime in seconds of protocol-cloned +.Tn IP +routes after the last reference drops (default one hour). +.\"This value varies dynamically as described above. +.It Dv IPV6CTL_RTMINEXPIRE +.Pq ip6.rtminexpire +Integer: minimum value of ip.rtexpire (default ten seconds). +.\"This value has no effect on user modifications, but restricts the dynamic +.\"adaptation described above. +.It Dv IPV6CTL_RTMAXCACHE +.Pq ip6.rtmaxcache +Integer: trigger level of cached, unreferenced, protocol-cloned routes +which initiates dynamic adaptation (default 128). +.El +.Ss Interaction between IPv4/v6 sockets +The behavior of +.Dv AF_INET6 +TCP/UDP socket is documented in RFC2553. +Basically, it says this: +.Bl -bullet -compact +.It +A specific bind on an +.Dv AF_INET6 +socket +.Xr ( bind 2 +with an address specified) +should accept IPv6 traffic to that address only. +.It +If you perform a wildcard bind +on an +.Dv AF_INET6 +socket +.Xr ( bind 2 +to IPv6 address +.Li :: ) , +and there is no wildcard bind +.Dv AF_INET +socket on that TCP/UDP port, IPv6 traffic as well as IPv4 traffic +should be routed to that +.Dv AF_INET6 +socket. +IPv4 traffic should be seen as if it came from an IPv6 address like +.Li ::ffff:10.1.1.1 . +This is called an IPv4 mapped address. +.It +If there are both a wildcard bind +.Dv AF_INET +socket and a wildcard bind +.Dv AF_INET6 +socket on one TCP/UDP port, they should behave separately. +IPv4 traffic should be routed to the +.Dv AF_INET +socket and IPv6 should be routed to the +.Dv AF_INET6 +socket. +.El +.Pp +However, RFC2553 does not define the ordering constraint between calls to +.Xr bind 2 , +nor how IPv4 TCP/UDP port numbers and IPv6 TCP/UDP port numbers +relate to each other +(should they be integrated or separated). +Implemented behavior is very different from kernel to kernel. +Therefore, it is unwise to rely too much upon the behavior of +.Dv AF_INET6 +wildcard bind sockets. +It is recommended to listen to two sockets, one for +.Dv AF_INET +and another for +.Dv AF_INET6 , +when you would like to accept both IPv4 and IPv6 traffic. +.Pp +It should also be noted that +malicious parties can take advantage of the complexity presented above, +and are able to bypass access control, +if the target node routes IPv4 traffic to +.Dv AF_INET6 +socket. +Users are advised to take care handling connections +from IPv4 mapped address to +.Dv AF_INET6 +sockets. +.\".Pp +.\"Because of the above, by default, +.\"KAME/NetBSD and KAME/OpenBSD +.\"does not route IPv4 traffic to +.\".Dv AF_INET6 +.\"sockets. +.\"Listen to two sockets if you want to accept both IPv4 and IPv6 traffic. +.\"On KAME/NetBSD, IPv4 traffic may be routed with certain +.\"per-socket/per-node configuration, however, it is not recommended. +.\"Consult +.\".Xr ip6 4 +.\"for details. +.Sh SEE ALSO +.Xr ioctl 2 , +.Xr socket 2 , +.Xr sysctl 3 , +.Xr icmp6 4 , +.Xr intro 4 , +.Xr ip6 4 , +.Xr tcp 4 , +.Xr ttcp 4 , +.Xr udp 4 +.Sh STANDARDS +.Rs +.%A Tatsuya Jinmei +.%A Atsushi Onoe +.%T "An Extension of Format for IPv6 Scoped Addresses" +.%R internet draft +.%D June 2000 +.%N draft-ietf-ipngwg-scopedaddr-format-02.txt +.%O work in progress material +.Re +.Sh HISTORY +The +.Nm +protocol interfaces are defined in RFC2553 and RFC2292. +The implementation described herein appeared in the WIDE/KAME project. +.Sh BUGS +The IPv6 support is subject to change as the Internet protocols develop. +Users should not depend on details of the current implementation, +but rather the services exported. +.Pp +Users are suggested to implement +.Dq version independent +code as much as possible, as you will need to support both +.Xr inet 4 +and +.Nm . diff --git a/bsd/man/man4/ip.4 b/bsd/man/man4/ip.4 new file mode 100644 index 000000000..c351178e1 --- /dev/null +++ b/bsd/man/man4/ip.4 @@ -0,0 +1,384 @@ +.\" $NetBSD: ip.4,v 1.3 1994/11/30 16:22:19 jtc Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)ip.4 8.2 (Berkeley) 11/30/93 +.\" +.Dd November 30, 1993 +.Dt IP 4 +.Os BSD 4.2 +.Sh NAME +.Nm ip +.Nd Internet Protocol +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn socket AF_INET SOCK_RAW proto +.Sh DESCRIPTION +.Tn IP +is the transport layer protocol used +by the Internet protocol family. +Options may be set at the +.Tn IP +level +when using higher-level protocols that are based on +.Tn IP +(such as +.Tn TCP +and +.Tn UDP ) . +It may also be accessed +through a +.Dq raw socket +when developing new protocols, or +special-purpose applications. +.Pp +There are several +.Tn IP-level +.Xr setsockopt 2 / Ns +.Xr getsockopt 2 +options. +.Dv IP_OPTIONS +may be used to provide +.Tn IP +options to be transmitted in the +.Tn IP +header of each outgoing packet +or to examine the header options on incoming packets. +.Tn IP +options may be used with any socket type in the Internet family. +The format of +.Tn IP +options to be sent is that specified by the +.Tn IP +protocol specification (RFC-791), with one exception: +the list of addresses for Source Route options must include the first-hop +gateway at the beginning of the list of gateways. +The first-hop gateway address will be extracted from the option list +and the size adjusted accordingly before use. +To disable previously specified options, +use a zero-length buffer: +.Bd -literal +setsockopt(s, IPPROTO_IP, IP_OPTIONS, NULL, 0); +.Ed +.Pp +.Dv IP_TOS +and +.Dv IP_TTL +may be used to set the type-of-service and time-to-live +fields in the +.Tn IP +header for +.Dv SOCK_STREAM +and +.Dv SOCK_DGRAM +sockets. For example, +.Bd -literal +int tos = IPTOS_LOWDELAY; /* see */ +setsockopt(s, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); + +int ttl = 60; /* max = 255 */ +setsockopt(s, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); +.Ed +.Pp +If the +.Dv IP_RECVDSTADDR +option is enabled on a +.Dv SOCK_DGRAM +socket, +the +.Xr recvmsg +call will return the destination +.Tn IP +address for a +.Tn UDP +datagram. +The msg_control field in the msghdr structure points to a buffer +that contains a cmsghdr structure followed by the +.Tn IP +address. +The cmsghdr fields have the following values: +.Bd -literal +cmsg_len = sizeof(struct in_addr) +cmsg_level = IPPROTO_IP +cmsg_type = IP_RECVDSTADDR +.Ed +.Ss "Multicast Options" +.Pp +.Tn IP +multicasting is supported only on +.Dv AF_INET +sockets of type +.Dv SOCK_DGRAM +and +.Dv SOCK_RAW, +and only on networks where the interface +driver supports multicasting. +.Pp +The +.Dv IP_MULTICAST_TTL +option changes the time-to-live (TTL) +for outgoing multicast datagrams +in order to control the scope of the multicasts: +.Bd -literal +u_char ttl; /* range: 0 to 255, default = 1 */ +setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); +.Ed +.sp +Datagrams with a TTL of 1 are not forwarded beyond the local network. +Multicast datagrams with a TTL of 0 will not be transmitted on any network, +but may be delivered locally if the sending host belongs to the destination +group and if multicast loopback has not been disabled on the sending socket +(see below). Multicast datagrams with TTL greater than 1 may be forwarded +to other networks if a multicast router is attached to the local network. +.Pp +For hosts with multiple interfaces, each multicast transmission is +sent from the primary network interface. +The +.Dv IP_MULTICAST_IF +option overrides the default for +subsequent transmissions from a given socket: +.Bd -literal +struct in_addr addr; +setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &addr, sizeof(addr)); +.Ed +.sp +where "addr" is the local +.Tn IP +address of the desired interface or +.Dv INADDR_ANY +to specify the default interface. +An interface's local IP address and multicast capability can +be obtained via the +.Dv SIOCGIFCONF +and +.Dv SIOCGIFFLAGS +ioctls. +Normal applications should not need to use this option. +.Pp +If a multicast datagram is sent to a group to which the sending host itself +belongs (on the outgoing interface), a copy of the datagram is, by default, +looped back by the IP layer for local delivery. +The +.Dv IP_MULTICAST_LOOP +option gives the sender explicit control +over whether or not subsequent datagrams are looped back: +.Bd -literal +u_char loop; /* 0 = disable, 1 = enable (default) */ +setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)); +.Ed +.sp +This option +improves performance for applications that may have no more than one +instance on a single host (such as a router demon), by eliminating +the overhead of receiving their own transmissions. It should generally not +be used by applications for which there may be more than one instance on a +single host (such as a conferencing program) or for which the sender does +not belong to the destination group (such as a time querying program). +.Pp +A multicast datagram sent with an initial TTL greater than 1 may be delivered +to the sending host on a different interface from that on which it was sent, +if the host belongs to the destination group on that other interface. The +loopback control option has no effect on such delivery. +.Pp +A host must become a member of a multicast group before it can receive +datagrams sent to the group. To join a multicast group, use the +.Dv IP_ADD_MEMBERSHIP +option: +.Bd -literal +struct ip_mreq mreq; +setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); +.Ed +.sp +where +.Fa mreq +is the following structure: +.Bd -literal +struct ip_mreq { + struct in_addr imr_multiaddr; /* multicast group to join */ + struct in_addr imr_interface; /* interface to join on */ +} +.Ed +.sp +.Dv imr_interface +should +be +.Dv INADDR_ANY +to choose the default multicast interface, +or the +.Tn IP +address of a particular multicast-capable interface if +the host is multihomed. +Membership is associated with a single interface; +programs running on multihomed hosts may need to +join the same group on more than one interface. +Up to +.Dv IP_MAX_MEMBERSHIPS +(currently 20) memberships may be added on a +single socket. +.Pp +To drop a membership, use: +.Bd -literal +struct ip_mreq mreq; +setsockopt(s, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)); +.Ed +.sp +where +.Fa mreq +contains the same values as used to add the membership. +Memberships are dropped when the socket is closed or the process exits. +.\"----------------------- +.Ss "Raw IP Sockets" +.Pp +Raw +.Tn IP +sockets are connectionless, +and are normally used with the +.Xr sendto +and +.Xr recvfrom +calls, though the +.Xr connect 2 +call may also be used to fix the destination for future +packets (in which case the +.Xr read 2 +or +.Xr recv 2 +and +.Xr write 2 +or +.Xr send 2 +system calls may be used). +.Pp +If +.Fa proto +is 0, the default protocol +.Dv IPPROTO_RAW +is used for outgoing +packets, and only incoming packets destined for that protocol +are received. +If +.Fa proto +is non-zero, that protocol number will be used on outgoing packets +and to filter incoming packets. +.Pp +Outgoing packets automatically have an +.Tn IP +header prepended to +them (based on the destination address and the protocol +number the socket is created with), +unless the +.Dv IP_HDRINCL +option has been set. +Incoming packets are received with +.Tn IP +header and options intact. +.Pp +.Dv IP_HDRINCL +indicates the complete IP header is included with the data +and may be used only with the +.Dv SOCK_RAW +type. +.Bd -literal +#include + +int hincl = 1; /* 1 = on, 0 = off */ +setsockopt(s, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl)); +.Ed +.sp +Unlike previous +.Tn BSD +releases, the program must set all +the fields of the IP header, including the following: +.Bd -literal +ip->ip_v = IPVERSION; +ip->ip_hl = hlen >> 2; +ip->ip_id = 0; /* 0 means kernel set appropriate value */ +ip->ip_off = htons(offset); +ip->ip_len = htons(len); +.Ed +.sp .5 +Additionally note that starting with +.Tn OpenBSD 2.1 +the ip_off and ip_len fields are in network byte order. +If the header source address is set to +.Dv INADDR_ANY, +the kernel will choose an appropriate address. +.Sh DIAGNOSTICS +A socket operation may fail with one of the following errors returned: +.Bl -tag -width [EADDRNOTAVAIL] +.It Bq Er EISCONN +when trying to establish a connection on a socket which +already has one, or when trying to send a datagram with the destination +address specified and the socket is already connected; +.It Bq Er ENOTCONN +when trying to send a datagram, but +no destination address is specified, and the socket hasn't been +connected; +.It Bq Er ENOBUFS +when the system runs out of memory for +an internal data structure; +.It Bq Er EADDRNOTAVAIL +when an attempt is made to create a +socket with a network address for which no network interface +exists. +.It Bq Er EACESS +when an attempt is made to create +a raw IP socket by a non-privileged process. +.El +.Pp +The following errors specific to +.Tn IP +may occur when setting or getting +.Tn IP +options: +.Bl -tag -width EADDRNOTAVAILxx +.It Bq Er EINVAL +An unknown socket option name was given. +.It Bq Er EINVAL +The IP option field was improperly formed; +an option field was shorter than the minimum value +or longer than the option buffer provided. +.El +.Sh SEE ALSO +.Xr getsockopt 2 , +.Xr send 2 , +.Xr recv 2 , +.Xr intro 4 , +.Xr icmp 4 , +.Xr inet 4 +.Sh HISTORY +The +.Nm +protocol appeared in +.Bx 4.2 . diff --git a/bsd/man/man4/ip6.4 b/bsd/man/man4/ip6.4 new file mode 100644 index 000000000..3c2b1eb98 --- /dev/null +++ b/bsd/man/man4/ip6.4 @@ -0,0 +1,707 @@ +.\" $KAME: ip6.4,v 1.14 2001/02/26 09:31:39 itojun Exp $ +.\" +.\" Copyright (C) 1999 WIDE Project. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the project nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" $FreeBSD: src/share/man/man4/ip6.4,v 1.1.2.8 2001/12/17 11:30:12 ru Exp $ +.\" +.Dd March 13, 2000 +.Dt IP6 4 +.Os +.\" +.Sh NAME +.Nm ip6 +.Nd Internet Protocol version 6 (IPv6) +.\" +.Sh SYNOPSIS +.In sys/types.h +.In sys/socket.h +.In netinet/in.h +.Ft int +.Fn socket AF_INET6 SOCK_RAW proto +.\" +.Sh DESCRIPTION +.Tn IPv6 +is the network layer protocol used by the Internet protocol version 6 family +.Pq Dv AF_INET6 . +Options may be set at the +.Tn IPv6 +level when using higher-level protocols that are based on +.Tn IPv6 +(such as +.Tn TCP +and +.Tn UDP ) . +It may also be accessed through a +.Dq raw socket +when developing new protocols, or special-purpose applications. +.Pp +There are several +.Tn IPv6-level +.Xr setsockopt 2 Ns / Ns Xr getsockopt 2 +options. +They are separated into the basic IPv6 sockets API +(defined in RFC2553), +and the advanced API +(defined in RFC2292). +The basic API looks very similar to the API presented in +.Xr ip 4 . +Advanced API uses ancillary data and can handle more complex cases. +.Pp +To specify some of socket options, certain privilege +(i.e. root privilege) is required. +.\" +.Ss Basic IPv6 sockets API +.Dv IPV6_UNICAST_HOPS +may be used to set the hoplimit field in the +.Tn IPv6 +header. +As symbol name suggests, the option controls hoplimit field on unicast packets. +If -1 is specified, the kernel will use a default value. +If a value of 0 to 255 is specified, the packet will have the specified +value as hoplimit. +Other values are considered invalid, and +.Er EINVAL +will be returned. +For example: +.Bd -literal -offset indent +int hlim = 60; /* max = 255 */ +setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hlim, sizeof(hlim)); +.Ed +.Pp +.Tn IPv6 +multicasting is supported only on +.Dv AF_INET6 +sockets of type +.Dv SOCK_DGRAM +and +.Dv SOCK_RAW, +and only on networks where the interface driver supports multicasting. +.Pp +The +.Dv IPV6_MULTICAST_HOPS +option changes the hoplimit for outgoing multicast datagrams +in order to control the scope of the multicasts: +.Bd -literal -offset indent +unsigned int hlim; /* range: 0 to 255, default = 1 */ +setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hlim, sizeof(hlim)); +.Ed +.Pp +Datagrams with a hoplimit of 1 are not forwarded beyond the local network. +Multicast datagrams with a hoplimit of 0 will not be transmitted on any network, +but may be delivered locally if the sending host belongs to the destination +group and if multicast loopback has not been disabled on the sending socket +(see below). +Multicast datagrams with hoplimit greater than 1 may be forwarded +to other networks if a multicast router is attached to the local network. +.Pp +For hosts with multiple interfaces, each multicast transmission is +sent from the primary network interface. +The +.Dv IPV6_MULTICAST_IF +option overrides the default for +subsequent transmissions from a given socket: +.Bd -literal -offset indent +unsigned int outif; +outif = if_nametoindex("ne0"); +setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &outif, sizeof(outif)); +.Ed +.Pp +where "outif" is an interface index of the desired interface, +or 0 to specify the default interface. +.Pp +If a multicast datagram is sent to a group to which the sending host itself +belongs (on the outgoing interface), a copy of the datagram is, by default, +looped back by the IPv6 layer for local delivery. +The +.Dv IPV6_MULTICAST_LOOP +option gives the sender explicit control +over whether or not subsequent datagrams are looped back: +.Bd -literal -offset indent +u_char loop; /* 0 = disable, 1 = enable (default) */ +setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loop, sizeof(loop)); +.Ed +.Pp +This option +improves performance for applications that may have no more than one +instance on a single host (such as a router daemon), by eliminating +the overhead of receiving their own transmissions. +It should generally not be used by applications for which there +may be more than one instance on a single host (such as a conferencing +program) or for which the sender does not belong to the destination +group (such as a time querying program). +.Pp +A multicast datagram sent with an initial hoplimit greater than 1 may be delivered +to the sending host on a different interface from that on which it was sent, +if the host belongs to the destination group on that other interface. +The loopback control option has no effect on such delivery. +.Pp +A host must become a member of a multicast group before it can receive +datagrams sent to the group. +To join a multicast group, use the +.Dv IPV6_JOIN_GROUP +option: +.Bd -literal -offset indent +struct ipv6_mreq mreq6; +setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6, sizeof(mreq6)); +.Ed +.Pp +where +.Fa mreq6 +is the following structure: +.Bd -literal -offset indent +struct ipv6_mreq { + struct in6_addr ipv6mr_multiaddr; + u_int ipv6mr_interface; +}; +.Ed +.Pp +.Dv ipv6mr_interface +should be 0 to choose the default multicast interface, or the +interface index of a particular multicast-capable interface if +the host is multihomed. +Membership is associated with a single interface; +programs running on multihomed hosts may need to +join the same group on more than one interface. +.Pp +To drop a membership, use: +.Bd -literal -offset indent +struct ipv6_mreq mreq6; +setsockopt(s, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq6, sizeof(mreq6)); +.Ed +.Pp +where +.Fa mreq6 +contains the same values as used to add the membership. +Memberships are dropped when the socket is closed or the process exits. +.Pp +.Dv IPV6_PORTRANGE +controls how ephemeral ports are allocated for +.Dv SOCK_STREAM +and +.Dv SOCK_DGRAM +sockets. +For example, +.Bd -literal -offset indent +int range = IPV6_PORTRANGE_LOW; /* see */ +setsockopt(s, IPPROTO_IPV6, IPV6_PORTRANGE, &range, sizeof(range)); +.Ed +.Pp +.Dv IPV6_V6ONLY +controls behavior of +.Dv AF_INET6 +wildcard listening socket. +The following example sets the option to 1: +.Bd -literal -offset indent +int on = 1; +setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); +.Ed +.Pp +If set to 1, +.Dv AF_INET6 +wildcard listening socket will accept IPv6 traffic only. +If set to 0, it will accept IPv4 traffic as well, +as if it was from IPv4 mapped address like +.Li ::ffff:10.1.1.1 . +.\" RFC2553 defines the behavior when the variable is set to 0. +Note that if you set it this to 0, +IPv4 access control gets much more complicated. +For example, even if you have no listening +.Dv AF_INET +listening socket on port +.Li X , +you will end up accepting IPv4 traffic by +.Dv AF_INET6 +listening socket on the same port. +The default value for this flag is copied at socket instantiation time, +from +.Li net.inet6.ip6.v6only +.Xr sysctl 3 +variable. +The option affects +.Tn TCP +and +.Tn UDP +sockets only. +.\" +.Ss Advanced IPv6 sockets API +The advanced IPv6 sockets API lets userland programs specify or obtain +details about the IPv6 header and the IPv6 extension headers on packets. +The advanced API uses ancillary data for passing data from/to the kernel. +.Pp +There are +.Xr setsockopt 2 Ns / Ns Xr getsockopt 2 +options to get optional information on incoming packets. +They are +.Dv IPV6_PKTINFO , +.Dv IPV6_HOPLIMIT , +.Dv IPV6_HOPOPTS , +.Dv IPV6_DSTOPTS , +and +.Dv IPV6_RTHDR . +.Bd -literal -offset indent +int on = 1; + +setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on)); +setsockopt(fd, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, sizeof(on)); +setsockopt(fd, IPPROTO_IPV6, IPV6_HOPOPTS, &on, sizeof(on)); +setsockopt(fd, IPPROTO_IPV6, IPV6_DSTOPTS, &on, sizeof(on)); +setsockopt(fd, IPPROTO_IPV6, IPV6_RTHDR, &on, sizeof(on)); +.Ed +.Pp +When any of these options are enabled, the corresponding data is +returned as control information by +.Xr recvmsg 2 , +as one or more ancillary data objects. +.Pp +If +.Dv IPV6_PKTINFO +is enabled, the destination IPv6 address and the arriving interface index +will be available via +.Li struct in6_pktinfo +on ancillary data stream. +You can pick the structure by checking for an ancillary data item with +.Li cmsg_level +equals to +.Dv IPPROTO_IPV6 , +and +.Li cmsg_type +equals to +.Dv IPV6_PKTINFO . +.Pp +If +.Dv IPV6_HOPLIMIT +is enabled, hoplimit value on the packet will be made available to the +userland program. +Ancillary data stream will contain an integer data item with +.Li cmsg_level +equals to +.Dv IPPROTO_IPV6 , +and +.Li cmsg_type +equals to +.Dv IPV6_HOPLIMIT . +.Pp +.Xr inet6_option_space 3 +and friends will help you parse ancillary data items for +.Dv IPV6_HOPOPTS +and +.Dv IPV6_DSTOPTS . +Similarly, +.Xr inet6_rthdr_space 3 +and friends will help you parse ancillary data items for +.Dv IPV6_RTHDR . +.Pp +.Dv IPV6_HOPOPTS +and +.Dv IPV6_DSTOPTS +may appear multiple times on an ancillary data stream +(note that the behavior is slightly different than the specification). +Other ancillary data item will appear no more than once. +.Pp +For outgoing direction, +you can pass ancillary data items with normal payload data, using +.Xr sendmsg 2 . +Ancillary data items will be parsed by the kernel, and used to construct +the IPv6 header and extension headers. +For the 5 +.Li cmsg_level +values listed above, ancillary data format is the same as inbound case. +Additionally, you can specify +.Dv IPV6_NEXTHOP +data object. +The +.Dv IPV6_NEXTHOP +ancillary data object specifies the next hop for the +datagram as a socket address structure. +In the +.Li cmsghdr +structure +containing this ancillary data, the +.Li cmsg_level +member will be +.Dv IPPROTO_IPV6 , +the +.Li cmsg_type +member will be +.Dv IPV6_NEXTHOP , +and the first byte of +.Li cmsg_data[] +will be the first byte of the socket address structure. +.Pp +If the socket address structure contains an IPv6 address (e.g., the +sin6_family member is +.Dv AF_INET6 ) , +then the node identified by that +address must be a neighbor of the sending host. +If that address +equals the destination IPv6 address of the datagram, then this is +equivalent to the existing +.Dv SO_DONTROUTE +socket option. +.Pp +For applications that do not, or unable to use +.Xr sendmsg 2 +or +.Xr recvmsg 2 , +.Dv IPV6_PKTOPTIONS +socket option is defined. +Setting the socket option specifies any of the optional output fields: +.Bd -literal -offset indent +setsockopt(fd, IPPROTO_IPV6, IPV6_PKTOPTIONS, &buf, len); +.Ed +.Pp +The fourth argument points to a buffer containing one or more +ancillary data objects, and the fifth argument is the total length of +all these objects. +The application fills in this buffer exactly as +if the buffer were being passed to +.Xr sendmsg 2 +as control information. +.Pp +The options set by calling +.Xr setsockopt 2 +for +.Dv IPV6_PKTOPTIONS +are +called "sticky" options because once set they apply to all packets +sent on that socket. +The application can call +.Xr setsockopt 2 +again to +change all the sticky options, or it can call +.Xr setsockopt 2 +with a +length of 0 to remove all the sticky options for the socket. +.Pp +The corresponding receive option +.Bd -literal -offset indent +getsockopt(fd, IPPROTO_IPV6, IPV6_PKTOPTIONS, &buf, &len); +.Ed +.Pp +returns a buffer with one or more ancillary data objects for all the +optional receive information that the application has previously +specified that it wants to receive. +The fourth argument points to +the buffer that is filled in by the call. +The fifth argument is a +pointer to a value-result integer: when the function is called the +integer specifies the size of the buffer pointed to by the fourth +argument, and on return this integer contains the actual number of +bytes that were returned. +The application processes this buffer +exactly as if the buffer were returned by +.Xr recvmsg 2 +as control information. +.\" +.Ss Advanced API and TCP sockets +When using +.Xr getsockopt 2 +with the +.Dv IPV6_PKTOPTIONS +option and a +.Tn TCP +socket, only the options from the most recently received segment are +retained and returned to the caller, and only after the socket option +has been set. +.\" That is, +.\" .Tn TCP +.\" need not start saving a copy of the options until the application says +.\" to do so. +The application is not allowed to specify ancillary data in a call to +.Xr sendmsg 2 +on a +.Tn TCP +socket, and none of the ancillary data that we +described above is ever returned as control information by +.Xr recvmsg 2 +on a +.Tn TCP +socket. +.\" +.Ss Conflict resolution +In some cases, there are multiple APIs defined for manipulating +a IPv6 header field. +A good example is the outgoing interface for multicast datagrams: +it can be manipulated by +.Dv IPV6_MULTICAST_IF +in basic API, +.Dv IPV6_PKTINFO +in advanced API, and +.Li sin6_scope_id +field of the socket address passed to +.Xr sendto 2 . +.Pp +When conflicting options are given to the kernel, +the kernel will get the value in the following preference: +(1) options specified by using ancillary data, +(2) options specified by a sticky option of the advanced API, +(3) options specified by using the basic API, and lastly +(4) options specified by a socket address. +Note that the conflict resolution is undefined in the API specifcation +and implementation dependent. +.\" +.Ss "Raw IPv6 Sockets" +Raw +.Tn IPv6 +sockets are connectionless, and are normally used with the +.Xr sendto 2 +and +.Xr recvfrom 2 +calls, though the +.Xr connect 2 +call may also be used to fix the destination for future +packets (in which case the +.Xr read 2 +or +.Xr recv 2 +and +.Xr write 2 +or +.Xr send 2 +system calls may be used). +.Pp +If +.Fa proto +is 0, the default protocol +.Dv IPPROTO_RAW +is used for outgoing packets, and only incoming packets destined +for that protocol are received. +If +.Fa proto +is non-zero, that protocol number will be used on outgoing packets +and to filter incoming packets. +.Pp +Outgoing packets automatically have an +.Tn IPv6 +header prepended to them (based on the destination address and the +protocol number the socket is created with). +Incoming packets are received without +.Tn IPv6 +header nor extension headers. +.Pp +All data sent via raw sockets MUST be in network byte order and all +data received via raw sockets will be in network byte order. +This differs from the IPv4 raw sockets, which did not specify a byte +ordering and typically used the host's byte order. +.Pp +Another difference from IPv4 raw sockets is that complete packets +(that is, IPv6 packets with extension headers) cannot be read or +written using the IPv6 raw sockets API. +Instead, ancillary data +objects are used to transfer the extension headers, as described above. +Should an application need access to the +complete IPv6 packet, some other technique, such as the datalink +interfaces, such as +.Xr bpf 4 , +must be used. +.Pp +All fields in the IPv6 header that an application might want to +change (i.e., everything other than the version number) can be +modified using ancillary data and/or socket options by the +application for output. +All fields in a received IPv6 header (other +than the version number and Next Header fields) and all extension +headers are also made available to the application as ancillary data +on input. +Hence there is no need for a socket option similar to the +IPv4 +.Dv IP_HDRINCL +socket option. +.Pp +When writing to a raw socket the kernel will automatically fragment +the packet if its size exceeds the path MTU, inserting the required +fragmentation headers. On input the kernel reassembles received +fragments, so the reader of a raw socket never sees any fragment +headers. +.Pp +Most IPv4 implementations give special treatment to a raw socket +created with a third argument to +.Xr socket 2 +of +.Dv IPPROTO_RAW , +whose value is normally 255. +We note that this value has no special meaning to +an IPv6 raw socket (and the IANA currently reserves the value of 255 +when used as a next-header field). +.\" Note: This feature was added to +.\" IPv4 in 1988 by Van Jacobson to support traceroute, allowing a +.\" complete IP header to be passed by the application, before the +.\" .Dv IP_HDRINCL +.\" socket option was added. +.Pp +For ICMPv6 raw sockets, +the kernel will calculate and insert the ICMPv6 checksum for +since this checksum is mandatory. +.Pp +For other raw IPv6 sockets (that is, for raw IPv6 sockets created +with a third argument other than IPPROTO_ICMPV6), the application +must set the new IPV6_CHECKSUM socket option to have the kernel (1) +compute and store a psuedo header checksum for output, +and (2) verify the received +pseudo header checksum on input, +discarding the packet if the checksum is in error. +This option prevents applications from having to perform source +address selection on the packets they send. +The checksum will +incorporate the IPv6 pseudo-header, defined in Section 8.1 of RFC2460. +This new socket option also specifies an integer offset into +the user data of where the checksum is located. +.Bd -literal -offset indent +int offset = 2; +setsockopt(fd, IPPROTO_IPV6, IPV6_CHECKSUM, &offset, sizeof(offset)); +.Ed +.Pp +By default, this socket option is disabled. Setting the offset to -1 +also disables the option. By disabled we mean (1) the kernel will +not calculate and store a checksum for outgoing packets, and (2) the +kernel will not verify a checksum for received packets. +.Pp +Note: Since the checksum is always calculated by the kernel for an +ICMPv6 socket, applications are not able to generate ICMPv6 packets +with incorrect checksums (presumably for testing purposes) using this +API. +.\" +.Sh ERRORS +A socket operation may fail with one of the following errors returned: +.Bl -tag -width Er +.It Bq Er EISCONN +when trying to establish a connection on a socket which already +has one, or when trying to send a datagram with the destination +address specified and the socket is already connected; +.It Bq Er ENOTCONN +when trying to send a datagram, but no destination address is +specified, and the socket hasn't been connected; +.It Bq Er ENOBUFS +when the system runs out of memory for an internal data structure; +.It Bq Er EADDRNOTAVAIL +when an attempt is made to create a socket with a network address +for which no network interface exists. +.It Bq Er EACCES +when an attempt is made to create a raw IPv6 socket by a non-privileged process. +.El +.Pp +The following errors specific to +.Tn IPv6 +may occur: +.Bl -tag -width EADDRNOTAVAILxx +.It Bq Er EINVAL +An unknown socket option name was given. +.It Bq Er EINVAL +The ancillary data items were improperly formed, or option name was unknown. +.El +.\" +.Sh SEE ALSO +.Xr getsockopt 2 , +.Xr recv 2 , +.Xr send 2 , +.Xr setsockopt 2 , +.Xr inet6_option_space 3 , +.Xr inet6_rthdr_space 3 , +.Xr icmp6 4 , +.Xr inet6 4 , +.Xr intro 4 +.Rs +.%A W. Stevens +.%A M. Thomas +.%R RFC +.%N 2292 +.%D February 1998 +.%T "Advanced Sockets API for IPv6" +.Re +.Rs +.%A S. Deering +.%A R. Hinden +.%R RFC +.%N 2460 +.%D December 1998 +.%T "Internet Protocol, Version 6 (IPv6) Specification" +.Re +.Rs +.%A R. Gilligan +.%A S. Thomson +.%A J. Bound +.%A W. Stevens +.%R RFC +.%N 2553 +.%D March 1999 +.%T "Basic Socket Interface Extensions for IPv6" +.Re +.\" +.Sh STANDARDS +Most of the socket options are defined in +RFC2292 and/or RFC2553. +.Pp +.Dv IPV6_V6ONLY +socket option is defined in draft-ietf-ipngwg-rfc2553bis-03. +.Dv IPV6_PORTRANGE +socket option +and +conflict resolution rule +are not defined in the RFCs and should be considered implementation dependent. +.\" +.Sh HISTORY +The implementation is based on KAME stack +(which is descendant of WIDE hydrangea IPv6 stack kit). +.Pp +Part of the document was shamelessly copied from RFC2553 and RFC2292. +.\" +.Sh BUGS +The +.Dv IPV6_NEXTHOP +object/option is not fully implemented as of writing this. diff --git a/bsd/man/man4/ipfirewall.4 b/bsd/man/man4/ipfirewall.4 new file mode 100644 index 000000000..9dd42b23a --- /dev/null +++ b/bsd/man/man4/ipfirewall.4 @@ -0,0 +1,246 @@ +.Dd June 22, 1997 +.Dt IPFIREWALL 4 +.Os Darwin +.Sh NAME +.Nm ipfirewall +.Nd IP packet filter and traffic accounting +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Fd #include +.Fd #include +.Ft int +.Fn setsockopt raw_socket IPPROTO_IP "ipfw option" "struct ipfw" size +.\"-------------------------------------------------------------------------------------------- +.Sh DESCRIPTION +.\"-------------------------------------------------------------------------------------------- +IPFirewall (sometimes referred to as "ipfw") is a system facility which allows filtering, +redirecting, and other operations on IP packets travelling through network interfaces. Packets +are matched by applying an ordered list of pattern rules against each packet until a match is +found, at which point the corresponding action is taken. Rules are numbered from 1 to 65534; +multiple rules may share the same number. +.Pp +There is one rule that always exists, rule number 65535. This rule normally causes all packets +to be dropped. Hence, any packet which does not match a lower numbered rule will be dropped. +However, the kernel compile time option +.Dv IPFIREWALL_DEFAULT_TO_ACCEPT +allows the administrator to change this fixed rule to permit everything. +.Pp +The buffer passed down via the socket-option call should contain a "struct ip_fw" that is +initialized with the required parameters for the firewall command being invoked. This +structure is consistently required for every firewall command, even though in some cases +the majority of its fields will go unused. The reason for this is the API versioning that +the firewall supports for the sake of backward compatibility. The +.Dv version +field of this +structure should always be set to +.Dv IP_FW_CURRENT_API_VERSION +or an EINVAL error will be returned. +.Ss Commands +The following socket options are used to manage the rule list: +.Bl -tag -width "IP_FW_FLUSH" +.It Dv IP_FW_ADD +inserts the rule into the rule list +.It Dv IP_FW_DEL +deletes all rules having the matching rule number +.It Dv IP_FW_GET +returns the (first) rule having the matching rule number +.It Dv IP_FW_ZERO +zeros the statistics associated with all rules having the +matching rule number. +If the rule number is zero, all rules are zeroed. +.It Dv IP_FW_FLUSH +removes all rules (except 65535). +.El +.Pp +When the kernel security level is greater than 2, only +.Dv IP_FW_GET +is allowed. +.\"-------------------------------------------------------------------------------------------- +.Ss Rule Structure +.\"-------------------------------------------------------------------------------------------- +Rules are described by the following structure: +.Bd -literal +/* One ipfw rule */ +struct ip_fw { + u_int32_t version; /* Version of this structure. Should always be */ + /* set to IP_FW_CURRENT_API_VERSION by clients. */ + void *context; /* Context that is usable by user processes to */ + /* identify this rule. */ + u_int64_t fw_pcnt,fw_bcnt; /* Packet and byte counters */ + struct in_addr fw_src, fw_dst; /* Source and destination IP addr */ + struct in_addr fw_smsk, fw_dmsk; /* Mask for src and dest IP addr */ + u_short fw_number; /* Rule number */ + u_int fw_flg; /* Flags word */ +#define IP_FW_MAX_PORTS 10 /* A reasonable maximum */ + union { + u_short fw_pts[IP_FW_MAX_PORTS]; /* Array of port numbers to match */ +#define IP_FW_ICMPTYPES_MAX 128 +#define IP_FW_ICMPTYPES_DIM (IP_FW_ICMPTYPES_MAX / (sizeof(unsigned) * 8)) + unsigned fw_icmptypes[IP_FW_ICMPTYPES_DIM]; /* ICMP types bitmap */ + } fw_uar; + u_int fw_ipflg; /* IP flags word */ + u_char fw_ipopt,fw_ipnopt; /* IP options set/unset */ + u_char fw_tcpopt,fw_tcpnopt; /* TCP options set/unset */ + u_char fw_tcpf,fw_tcpnf; /* TCP flags set/unset */ + long timestamp; /* timestamp (tv_sec) of last match */ + union ip_fw_if fw_in_if, fw_out_if; /* Incoming and outgoing interfaces */ + union { + u_short fu_divert_port; /* Divert/tee port (options IPDIVERT) */ + u_short fu_pipe_nr; /* queue number (option DUMMYNET) */ + u_short fu_skipto_rule; /* SKIPTO command rule number */ + u_short fu_reject_code; /* REJECT response code */ + struct sockaddr_in fu_fwd_ip; + } fw_un; + u_char fw_prot; /* IP protocol */ + /* + * N'of src ports and # of dst ports in ports array (dst ports + * follow src ports; max of 10 ports in all; count of 0 means + * match all ports) + */ + u_char fw_nports; + void *pipe_ptr; /* flow_set ptr for dummynet pipe */ + void *next_rule_ptr ; /* next rule in case of match */ + uid_t fw_uid; /* uid to match */ + int fw_logamount; /* amount to log */ + u_int64_t fw_loghighest; /* highest number packet to log */ +}; + +The ip_fw.h header also contains macros for setting the fw_ports field and various +flags and constants for setting other fields. +.Ed +.\"-------------------------------------------------------------------------------------------- +.Ss Rule Actions +.\"-------------------------------------------------------------------------------------------- +Each rule has an action described by the IP_FW_F_COMMAND bits in the flags word: +.Bl -tag -width "IP_FW_F_DIVERT" +.It Dv IP_FW_F_DENY +drop packet +.It Dv IP_FW_F_REJECT +drop packet; send rejection via ICMP or TCP +.It Dv IP_FW_F_ACCEPT +accept packet +.It Dv IP_FW_F_COUNT +increment counters; continue matching +.It Dv IP_FW_F_DIVERT +divert packet to a +.Xr divert 4 +socket +.It Dv IP_FW_F_TEE +copy packet to a +.Xr divert 4 +socket; continue +.It Dv IP_FW_F_SKIPTO +skip to rule number +.Va fu_skipto_rule +.El +.Pp +In the case of +.Dv IP_FW_F_REJECT , +if the +.Va fu_reject_code +is a number from 0 to 255, then an ICMP unreachable packet is sent back to the +original packet's source IP address, with the corresponding code. Otherwise, the +value must be 256 and the protocol +.Dv IPPROTO_TCP , +in which case a TCP reset packet is sent instead. +.Pp +With +.Dv IP_FW_F_SKIPTO , +all succeeding rules having rule number less than +.Va fu_skipto_rule +are skipped. +.Ss Kernel Options +Options in the kernel configuration file: +.Bl -tag -width "options IPFIREWALL_VERBOSE_LIMIT" +.It Cd options IPFIREWALL +enable +.Nm +.It Cd options IPFIREWALL_VERBOSE +enable firewall logging +.It Cd options IPFIREWALL_VERBOSE_LIMIT +limit firewall logging +.It Cd options IPDIVERT +enable +.Xr divert 4 +sockets +.El +.Pp +When packets match a rule with the +.Dv IP_FW_F_PRN +bit set, and if +.Dv IPFIREWALL_VERBOSE +has been enabled,a message is written to +.Pa /dev/klog +with the +.Dv LOG_SECURITY +facility +(see +.Xr syslog 3 ) +for further logging by +.Xr syslogd 8 ; +.Dv IPFIREWALL_VERBOSE_LIMIT +limits the maximum number of times each rule can cause a log message. These variables are also +available via the +.Xr sysctl 3 +interface. +.\"-------------------------------------------------------------------------------------------- +.Sh RETURN VALUES +.\"-------------------------------------------------------------------------------------------- +The +.Fn setsockopt +function returns 0 on success. Otherwise, -1 is returned and the global variable +.Va errno +is set to indicate the error. +.\"-------------------------------------------------------------------------------------------- +.Sh ERRORS +.\"-------------------------------------------------------------------------------------------- +The +.Fn setsockopt +function will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The IP option field was improperly formed; +an option field was shorter than the minimum value +or longer than the option buffer provided. +.It Bq Er EINVAL +A structural error in ip_fw structure occurred +(n_src_p+n_dst_p too big, ports set for ALL/ICMP protocols etc.). +.It Bq Er EINVAL +The version field of the ip_fw structure was set to a value not supported by the +currently-installed +.Dv IPFirewall, +or no ip_fw structure was passed to it at all. +.It Bq Er EINVAL +An invalid rule number was used. +.El +.\"-------------------------------------------------------------------------------------------- +.Sh SEE ALSO +.\"-------------------------------------------------------------------------------------------- +.Xr setsockopt 2 , +.Xr divert 4 , +.Xr ip 4 , +.Xr ipfw 8 , +.Xr sysctl 8 , +.Xr syslogd 8 +.\"-------------------------------------------------------------------------------------------- +.Sh BUGS +.\"-------------------------------------------------------------------------------------------- +The ``tee'' rule is not yet implemented (currently it has no effect). +.Pp +This man page still needs work. +.\"-------------------------------------------------------------------------------------------- +.Sh HISTORY +.\"-------------------------------------------------------------------------------------------- +The ipfw facility was initially written as package to BSDI by +.An Daniel Boulet +.Aq danny@BouletFermat.ab.ca . +It has been heavily modified and ported to +.Fx +by +.An Ugen J.S. Antsilevich +.Aq ugen@NetVision.net.il . +.Pp +Several enhancements added by +.An Archie Cobbs +.Aq archie@FreeBSD.org . diff --git a/bsd/man/man4/ipl.4 b/bsd/man/man4/ipl.4 new file mode 100644 index 000000000..ce00ef1c3 --- /dev/null +++ b/bsd/man/man4/ipl.4 @@ -0,0 +1,63 @@ +.TH IPL 4 +.SH NAME +ipl - IP packet log device +.SH DESCRIPTION +The \fBipl\fP pseudo device's purpose is to provide an easy way to gather +packet headers of packets you wish to log. If a packet header is to be +logged, the entire header is logged (including any IP options - TCP/UDP +options are not included when it calculates header size) or not at all. +The packet contents is also logged after the header. +.LP +.PP +Prepending every packet header logged is a structure containing information +relevant to the packet following and why it was logged. The structure's +format is as follows: +.LP +.nf +struct ipl_ci { + u_long sec; /* time when the packet was logged */ + u_long usec; + u_long plen; /* length of packet data logged */ + u_short hlen; /* length of headers logged */ + u_short rule; /* rule number (for log ...) or 0 if result = log */ + u_long flags:24; /* XXX FIXME do we care about the extra bytes? */ +#if (defined(OpenBSD) && (OpenBSD <= 1991011) && (OpenBSD >= 199606)) + u_long filler:8; /* XXX FIXME do we care? */ + u_char ifname[IFNAMSIZ]; +#else + u_long unit:8; + u_char ifname[4]; +#endif +}; +.nf +.PP +In the case of the header causing the buffer to finish on a non-32bit +boundary, padding will be `appended' to ensure that the next log entry +is aligned to a 32bit boundary. +.LP +.PP +If the packet contents is more then 128 bytes, then only 128 bytes of the +packet contents is logged. Should the packet contents finish on a non-32bit +boundary, then the last few bytes are not logged to ensure the log entry +is aligned to a 32bit boundary. + +\fBipl\fP is a read-only (sequential) character pseudo-device. + +The ioctls which are loaded with this device can be found under \fBipf(4)\fP. +The only ioctl which is used for logging and doesn't affect the filter is: +.LP +.nf + ioctl(fd, SIOCIPFFB, int *) +.fi +.PP +This ioctl flushes the log buffer and returns the number of bytes flushed. +.PP +There is currently no support for non-blocking IO with this device, meaning +all read operations should be considered blocking in nature (if there is no +data to read, it will sleep until some is made available). +.SH SEE ALSO +ipf(4) +.SH BUGS +Packet headers are dropped when the internal buffer (static size) fills. +.SH FILES +/dev/ipl0 diff --git a/bsd/man/man4/ipsec.4 b/bsd/man/man4/ipsec.4 new file mode 100644 index 000000000..c6225b88f --- /dev/null +++ b/bsd/man/man4/ipsec.4 @@ -0,0 +1,325 @@ +.\" $FreeBSD: src/share/man/man4/ipsec.4,v 1.3.2.10 2001/12/17 11:30:12 ru Exp $ +.\" $KAME: ipsec.4,v 1.17 2001/06/27 15:25:10 itojun Exp $ +.\" +.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the project nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January 29, 1999 +.Dt IPSEC 4 +.Os +.Sh NAME +.Nm ipsec +.Nd IP security protocol +.Sh SYNOPSIS +.In sys/types.h +.In netinet/in.h +.In netinet6/ipsec.h +.Sh DESCRIPTION +.Nm +is a security protocol in Internet Protocol layer. +.Nm +is defined for both IPv4 and IPv6 +.Xr ( inet 4 +and +.Xr inet6 4 ) . +.Nm +consists of two sub-protocols, namely +ESP +(encapsulated security payload) +and AH +(authentication header). +ESP protects IP payload from wire-tapping by encrypting it by +secret key cryptography algorithms. +AH guarantees integrity of IP packet +and protects it from intermediate alteration or impersonation, +by attaching cryptographic checksum computed by one-way hash functions. +.Nm +has two operation modes: transport mode and tunnel mode. +Transport mode is for protecting peer-to-peer communication between end nodes. +Tunnel mode includes IP-in-IP encapsulation operation +and is designed for security gateways, like VPN configurations. +.\" +.Ss Kernel interface +.Nm +is controlled by key management engine and policy engine, +in the operating system kernel. +.Pp +Key management engine can be accessed from the userland by using +.Dv PF_KEY +sockets. +The +.Dv PF_KEY +socket API is defined in RFC2367. +.Pp +Policy engine can be controlled by extended part of +.Dv PF_KEY +API, +.Xr setsockopt 2 +operations, and +.Xr sysctl 3 +interface. +The kernel implements +extended version of +.Dv PF_KEY +interface, and allows you to define IPsec policy like per-packet filters. +.Xr setsockopt 2 +interface is used to define per-socket behavior, and +.Xr sysctl 3 +interface is used to define host-wide default behavior. +.Pp +The kernel code does not implement dynamic encryption key exchange protocol +like IKE +(Internet Key Exchange). +That should be implemented as userland programs +(usually as daemons), +by using the above described APIs. +.\" +.Ss Policy management +The kernel implements experimental policy management code. +You can manage the IPsec policy in two ways. +One is to configure per-socket policy using +.Xr setsockopt 2 . +The other is to configure kernel packet filter-based policy using +.Dv PF_KEY +interface, via +.Xr setkey 8 . +In both cases, IPsec policy must be specified with syntax described in +.Xr ipsec_set_policy 3 . +.Pp +With +.Xr setsockopt 2 , +you can define IPsec policy in per-socket basis. +You can enforce particular IPsec policy onto packets that go through +particular socket. +.Pp +With +.Xr setkey 8 +you can define IPsec policy against packets, +using sort of packet filtering rule. +Refer to +.Xr setkey 8 +on how to use it. +.Pp +In the latter case, +.Dq Li default +policy is allowed for use with +.Xr setkey 8 . +By configuring policy to +.Li default , +you can refer system-wide +.Xr sysctl 8 +variable for default settings. +The following variables are available. +.Li 1 +means +.Dq Li use , +and +.Li 2 +means +.Dq Li require +in the syntax. +.Bl -column net.inet6.ipsec6.esp_trans_deflev integerxxx +.It Sy "Name Type Changeable" +.It "net.inet.ipsec.esp_trans_deflev integer yes" +.It "net.inet.ipsec.esp_net_deflev integer yes" +.It "net.inet.ipsec.ah_trans_deflev integer yes" +.It "net.inet.ipsec.ah_net_deflev integer yes" +.It "net.inet6.ipsec6.esp_trans_deflev integer yes" +.It "net.inet6.ipsec6.esp_net_deflev integer yes" +.It "net.inet6.ipsec6.ah_trans_deflev integer yes" +.It "net.inet6.ipsec6.ah_net_deflev integer yes" +.El +.Pp +If kernel finds no matching policy system wide default value is applied. +System wide default is specified by the following +.Xr sysctl 8 +variables. +.Li 0 +means +.Dq Li discard +which asks the kernel to drop the packet. +.Li 1 +means +.Dq Li none . +.Bl -column net.inet6.ipsec6.def_policy integerxxx +.It Sy "Name Type Changeable" +.It "net.inet.ipsec.def_policy integer yes" +.It "net.inet6.ipsec6.def_policy integer yes" +.El +.\" +.Ss Miscellaneous sysctl variables +The following variables are accessible via +.Xr sysctl 8 , +for tweaking kernel IPsec behavior: +.Bl -column net.inet6.ipsec6.inbonud_call_ike integerxxx +.It Sy "Name Type Changeable" +.It "net.inet.ipsec.ah_cleartos integer yes" +.It "net.inet.ipsec.ah_offsetmask integer yes" +.It "net.inet.ipsec.dfbit integer yes" +.It "net.inet.ipsec.ecn integer yes" +.It "net.inet.ipsec.debug integer yes" +.It "net.inet6.ipsec6.ecn integer yes" +.It "net.inet6.ipsec6.debug integer yes" +.El +.Pp +The variables are interpreted as follows: +.Bl -tag -width 6n +.It Li ipsec.ah_cleartos +If set to non-zero, the kernel clears type-of-service field in the IPv4 header +during AH authentication data computation. +The variable is for tweaking AH behavior to interoperate with devices that +implement RFC1826 AH. +It should be set to non-zero +(clear the type-of-service field) +for RFC2402 conformance. +.It Li ipsec.ah_offsetmask +During AH authentication data computation, the kernel will include +16bit fragment offset field +(including flag bits) +in IPv4 header, after computing logical AND with the variable. +The variable is for tweaking AH behavior to interoperate with devices that +implement RFC1826 AH. +It should be set to zero +(clear the fragment offset field during computation) +for RFC2402 conformance. +.It Li ipsec.dfbit +The variable configures the kernel behavior on IPv4 IPsec tunnel encapsulation. +If set to 0, DF bit on the outer IPv4 header will be cleared. +1 means that the outer DF bit is set regardless from the inner DF bit. +2 means that the DF bit is copied from the inner header to the outer. +The variable is supplied to conform to RFC2401 chapter 6.1. +.It Li ipsec.ecn +If set to non-zero, IPv4 IPsec tunnel encapsulation/decapsulation behavior will +be friendly to ECN +(explicit congestion notification), +as documented in +.Li draft-ietf-ipsec-ecn-02.txt . +.Xr gif 4 +talks more about the behavior. +.It Li ipsec.debug +If set to non-zero, debug messages will be generated via +.Xr syslog 3 . +.El +.Pp +Variables under +.Li net.inet6.ipsec6 +tree has similar meaning as the +.Li net.inet.ipsec +counterpart. +.\" +.Sh PROTOCOLS +The +.Nm +protocol works like plug-in to +.Xr inet 4 +and +.Xr inet6 4 +protocols. +Therefore, +.Nm +supports most of the protocols defined upon those IP-layer protocols. +Some of the protocols, like +.Xr icmp 4 +or +.Xr icmp6 4 , +may behave differently with +.Nm . +This is because +.Nm +can prevent +.Xr icmp 4 +or +.Xr icmp6 4 +routines from looking into IP payload. +.\" +.Sh SEE ALSO +.Xr ioctl 2 , +.Xr socket 2 , +.Xr ipsec_set_policy 3 , +.Xr icmp6 4 , +.Xr intro 4 , +.Xr ip6 4 , +.Xr setkey 8 , +.Xr sysctl 8 +.\".Xr racoon 8 +.Sh STANDARDS +.Rs +.%A Daniel L. McDonald +.%A Craig Metz +.%A Bao G. Phan +.%T "PF_KEY Key Management API, Version 2" +.%R RFC +.%N 2367 +.Re +.Pp +.Rs +.%A "D. L. McDonald" +.%T "A Simple IP Security API Extension to BSD Sockets" +.%R internet draft +.%N "draft-mcdonald-simple-ipsec-api-03.txt" +.%O work in progress material +.Re +.Sh HISTORY +The implementation described herein appeared in WIDE/KAME IPv6/IPsec stack. +.Sh BUGS +The IPsec support is subject to change as the IPsec protocols develop. +.Pp +There is no single standard for policy engine API, +so the policy engine API described herein is just for KAME implementation. +.Pp +AH and tunnel mode encapsulation may not work as you might expect. +If you configure inbound +.Dq require +policy against AH tunnel or any IPsec encapsulating policy with AH +(like +.Dq Li esp/tunnel/A-B/use ah/transport/A-B/require ) , +tunnelled packets will be rejected. +This is because we enforce policy check on inner packet on reception, +and AH authenticates encapsulating +(outer) +packet, not the encapsulated +(inner) +packet +(so for the receiving kernel there's no sign of authenticity). +The issue will be solved when we revamp our policy engine to keep all the +packet decapsulation history. +.Pp +Under certain condition, +truncated result may be raised from the kernel +against +.Dv SADB_DUMP +and +.Dv SADB_SPDDUMP +operation on +.Dv PF_KEY +socket. +This occurs if there are too many database entries in the kernel +and socket buffer for the +.Dv PF_KEY +socket is insufficient. +If you manipulate many IPsec key/policy database entries, +increase the size of socket buffer. diff --git a/bsd/man/man4/lo.4 b/bsd/man/man4/lo.4 new file mode 100644 index 000000000..0491936b4 --- /dev/null +++ b/bsd/man/man4/lo.4 @@ -0,0 +1,83 @@ +.\" $NetBSD: lo.4,v 1.3 1994/11/30 16:22:23 jtc Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)lo.4 8.1 (Berkeley) 6/5/93 +.\" +.Dd June 5, 1993 +.Dt LO 4 +.Os BSD 4.2 +.Sh NAME +.Nm lo +.Nd software loopback network interface +.Sh SYNOPSIS +.Sy pseudo-device +.Nm loop +.Sh DESCRIPTION +The +.Nm loop +interface is a software loopback mechanism which may be +used for performance analysis, software testing, and/or local +communication. +As with other network interfaces, the loopback interface must have +network addresses assigned for each address family with which it is to be used. +These addresses +may be set or changed with the +.Dv SIOCSIFADDR +.Xr ioctl 2 . +The loopback interface should be the last interface configured, +as protocols may use the order of configuration as an indication of priority. +The loopback should +.Em never +be configured first unless no hardware +interfaces exist. +.Sh DIAGNOSTICS +.Bl -diag +.It lo%d: can't handle af%d. +The interface was handed +a message with addresses formatted in an unsuitable address +family; the packet was dropped. +.El +.Sh SEE ALSO +.Xr intro 4 , +.Xr inet 4 , +.Xr ns 4 +.Sh HISTORY +The +.Nm +device appeared in +.Bx 4.2 . +.Sh BUGS +Previous versions of the system enabled the loopback interface +automatically, using a nonstandard Internet address (127.1). +Use of that address is now discouraged; a reserved host address +for the local network should be used instead. diff --git a/bsd/man/man4/netintro.4 b/bsd/man/man4/netintro.4 new file mode 100644 index 000000000..1dd5f5c9e --- /dev/null +++ b/bsd/man/man4/netintro.4 @@ -0,0 +1,329 @@ +.\" $NetBSD: netintro.4,v 1.4 1995/10/19 08:03:40 jtc Exp $ +.\" +.\" Copyright (c) 1983, 1990, 1991, 1993 +.\" 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. +.\" +.\" @(#)netintro.4 8.2 (Berkeley) 11/30/93 +.\" +.Dd November 30, 1993 +.Dt NETINTRO 4 +.Os BSD 4.2 +.Sh NAME +.Nm networking +.Nd introduction to networking facilities +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Fd #include +.Sh DESCRIPTION +This section is a general introduction to the networking facilities +available in the system. +Documentation in this part of section +4 is broken up into three areas: +.Em protocol families +(domains), +.Em protocols , +and +.Em network interfaces . +.Pp +All network protocols are associated with a specific +.Em protocol family . +A protocol family provides basic services to the protocol +implementation to allow it to function within a specific +network environment. These services may include +packet fragmentation and reassembly, routing, addressing, and +basic transport. A protocol family may support multiple +methods of addressing, though the current protocol implementations +do not. A protocol family is normally comprised of a number +of protocols, one per +.Xr socket 2 +type. It is not required that a protocol family support +all socket types. A protocol family may contain multiple +protocols supporting the same socket abstraction. +.Pp +A protocol supports one of the socket abstractions detailed in +.Xr socket 2 . +A specific protocol may be accessed either by creating a +socket of the appropriate type and protocol family, or +by requesting the protocol explicitly when creating a socket. +Protocols normally accept only one type of address format, +usually determined by the addressing structure inherent in +the design of the protocol family/network architecture. +Certain semantics of the basic socket abstractions are +protocol specific. All protocols are expected to support +the basic model for their particular socket type, but may, +in addition, provide non-standard facilities or extensions +to a mechanism. For example, a protocol supporting the +.Dv SOCK_STREAM +abstraction may allow more than one byte of out-of-band +data to be transmitted per out-of-band message. +.Pp +A network interface is similar to a device interface. +Network interfaces comprise the lowest layer of the +networking subsystem, interacting with the actual transport +hardware. An interface may support one or more protocol +families and/or address formats. +The SYNOPSIS section of each network interface +entry gives a sample specification +of the related drivers for use in providing +a system description to the +.Xr config 8 +program. +The DIAGNOSTICS section lists messages which may appear on the console +and/or in the system error log, +.Pa /var/log/messages +(see +.Xr syslogd 8 ) , +due to errors in device operation. +.Sh PROTOCOLS +The system currently supports the +Internet +protocols, the Xerox Network Systems(tm) protocols, +and some of the +.Tn ISO OSI +protocols. +Raw socket interfaces are provided to the +.Tn IP +protocol +layer of the +Internet, and to the +.Tn IDP +protocol of Xerox +.Tn NS . +Consult the appropriate manual pages in this section for more +information regarding the support for each protocol family. +.Sh ADDRESSING +Associated with each protocol family is an address +format. All network address adhere to a general structure, +called a sockaddr, described below. However, each protocol +imposes finer and more specific structure, generally renaming +the variant, which is discussed in the protocol family manual +page alluded to above. +.Bd -literal -offset indent + struct sockaddr { + u_char sa_len; + u_char sa_family; + char sa_data[14]; +}; +.Ed +.Pp +The field +.Ar sa_len +contains the total length of the of the structure, +which may exceed 16 bytes. +The following address values for +.Ar sa_family +are known to the system +(and additional formats are defined for possible future implementation): +.Bd -literal +#define AF_UNIX 1 /* local to host (pipes) */ +#define AF_INET 2 /* internetwork: UDP, TCP, etc. */ +#define AF_NS 6 /* Xerox NS protocols */ +#define AF_CCITT 10 /* CCITT protocols, X.25 etc */ +#define AF_HYLINK 15 /* NSC Hyperchannel */ +#define AF_ISO 18 /* ISO protocols */ +.Ed +.Sh ROUTING +Mac OS X provides some packet routing facilities. +The kernel maintains a routing information database, which +is used in selecting the appropriate network interface when +transmitting packets. +.Pp +A user process (or possibly multiple co-operating processes) +maintains this database by sending messages over a special kind +of socket. +This supplants fixed size +.Xr ioctl 2 +used in earlier releases. +.Pp +This facility is described in +.Xr route 4 . +.Sh INTERFACES +Each network interface in a system corresponds to a +path through which messages may be sent and received. A network +interface usually has a hardware device associated with it, though +certain interfaces such as the loopback interface, +.Xr lo 4 , +do not. +.Pp +The following +.Xr ioctl +calls may be used to manipulate network interfaces. +The +.Xr ioctl +is made on a socket (typically of type +.Dv SOCK_DGRAM ) +in the desired domain. +Most of the requests supported in earlier releases +take an +.Ar ifreq +structure as its parameter. This structure has the form +.Bd -literal +struct ifreq { +#define IFNAMSIZ 16 + char ifr_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + union { + struct sockaddr ifru_addr; + struct sockaddr ifru_dstaddr; + struct sockaddr ifru_broadaddr; + short ifru_flags; + int ifru_metric; + caddr_t ifru_data; + } ifr_ifru; +#define ifr_addr ifr_ifru.ifru_addr /* address */ +#define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-to-p link */ +#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ +#define ifr_flags ifr_ifru.ifru_flags /* flags */ +#define ifr_metric ifr_ifru.ifru_metric /* metric */ +#define ifr_data ifr_ifru.ifru_data /* for use by interface */ +}; +.Ed +.Pp +Calls which are now deprecated are: +.Bl -tag -width SIOCGIFBRDADDR +.It Dv SIOCSIFADDR +Set interface address for protocol family. Following the address +assignment, the ``initialization'' routine for +the interface is called. +.It Dv SIOCSIFDSTADDR +Set point to point address for protocol family and interface. +.It Dv SIOCSIFBRDADDR +Set broadcast address for protocol family and interface. +.El +.Pp +.Xr Ioctl +requests to obtain addresses and requests both to set and +retrieve other data are still fully supported +and use the +.Ar ifreq +structure: +.Bl -tag -width SIOCGIFBRDADDR +.It Dv SIOCGIFADDR +Get interface address for protocol family. +.It Dv SIOCGIFDSTADDR +Get point to point address for protocol family and interface. +.It Dv SIOCGIFBRDADDR +Get broadcast address for protocol family and interface. +.It Dv SIOCSIFFLAGS +Set interface flags field. If the interface is marked down, +any processes currently routing packets through the interface +are notified; +some interfaces may be reset so that incoming packets are no longer received. +When marked up again, the interface is reinitialized. +.It Dv SIOCGIFFLAGS +Get interface flags. +.It Dv SIOCSIFMETRIC +Set interface routing metric. +The metric is used only by user-level routers. +.It Dv SIOCGIFMETRIC +Get interface metric. +.El +.Pp +There are two requests that make use of a new structure: +.Bl -tag -width SIOCGIFBRDADDR +.It Dv SIOCAIFADDR +An interface may have more than one address associated with it +in some protocols. This request provides a means to +add additional addresses (or modify characteristics of the +primary address if the default address for the address family +is specified). Rather than making separate calls to +set destination or broadcast addresses, or network masks +(now an integral feature of multiple protocols) +a separate structure is used to specify all three facets simultaneously +(see below). +One would use a slightly tailored version of this struct specific +to each family (replacing each sockaddr by one +of the family-specific type). +Where the sockaddr itself is larger than the +default size, one needs to modify the +.Xr ioctl +identifier itself to include the total size, as described in +.Xr ioctl . +.It Dv SIOCDIFADDR +This requests deletes the specified address from the list +associated with an interface. It also uses the +.Ar if_aliasreq +structure to allow for the possibility of protocols allowing +multiple masks or destination addresses, and also adopts the +convention that specification of the default address means +to delete the first address for the interface belonging to +the address family in which the original socket was opened. +.It Dv SIOCGIFCONF +Get interface configuration list. This request takes an +.Ar ifconf +structure (see below) as a value-result parameter. The +.Ar ifc_len +field should be initially set to the size of the buffer +pointed to by +.Ar ifc_buf . +On return it will contain the length, in bytes, of the +configuration list. +.El +.Bd -literal +/* +* Structure used in SIOCAIFADDR request. +*/ +struct ifaliasreq { + char ifra_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + struct sockaddr ifra_addr; + struct sockaddr ifra_broadaddr; + struct sockaddr ifra_mask; +}; +.Ed +.Pp +.Bd -literal +/* +* Structure used in SIOCGIFCONF request. +* Used to retrieve interface configuration +* for machine (useful for programs which +* must know all networks accessible). +*/ +struct ifconf { + int ifc_len; /* size of associated buffer */ + union { + caddr_t ifcu_buf; + struct ifreq *ifcu_req; + } ifc_ifcu; +#define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ +#define ifc_req ifc_ifcu.ifcu_req /* array of structures returned */ +}; +.Ed +.Sh SEE ALSO +.Xr socket 2 , +.Xr ioctl 2 , +.Xr intro 4 , +.Xr config 8 , +.Xr routed 8 +.Sh HISTORY +The +.Nm netintro +manual appeared in +.Bx 4.3 tahoe . diff --git a/bsd/man/man4/networking.4 b/bsd/man/man4/networking.4 new file mode 100644 index 000000000..7db2aff3a --- /dev/null +++ b/bsd/man/man4/networking.4 @@ -0,0 +1 @@ +.so man4/netintro.4 diff --git a/bsd/man/man4/null.4 b/bsd/man/man4/null.4 new file mode 100644 index 000000000..e45c98bf4 --- /dev/null +++ b/bsd/man/man4/null.4 @@ -0,0 +1,58 @@ +.\" $NetBSD: null.4,v 1.3 1994/11/30 16:22:29 jtc Exp $ +.\" +.\" Copyright (c) 1991, 1993 +.\" 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. +.\" +.\" @(#)null.4 8.1 (Berkeley) 6/5/93 +.\" +.Dd June 5, 1993 +.Dt NULL 4 +.Os +.Sh NAME +.Nm null +.Nd the null device +.Sh DESCRIPTION +The +.Nm +device accepts and reads data as any ordinary (and willing) +file \- +but throws it away. The length of the +.Nm null +device is always zero. +.Sh FILES +.Bl -tag -width /dev/null +.It Pa /dev/null +.El +.Sh HISTORY +A +.Nm +device appeared in +.At v7 . diff --git a/bsd/man/man4/pty.4 b/bsd/man/man4/pty.4 new file mode 100644 index 000000000..933f12705 --- /dev/null +++ b/bsd/man/man4/pty.4 @@ -0,0 +1,211 @@ +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)pty.4 8.2 (Berkeley) 11/30/93 +.\" +.Dd November 30, 1993 +.Dt PTY 4 +.Os BSD 4.2 +.Sh NAME +.Nm pty +.Nd pseudo terminal driver +.Sh SYNOPSIS +.Cd "pseudo-device pty" Op Ar count +.Sh DESCRIPTION +The +.Nm pty +driver provides support for a device-pair termed a +.Em pseudo terminal . +A pseudo terminal is a pair of character devices, a +.Em master +device and a +.Em slave +device. The slave device provides to a process +an interface identical +to that described in +.Xr tty 4 . +However, whereas all other devices which provide the +interface described in +.Xr tty 4 +have a hardware device of some sort behind them, the slave +device has, instead, another process manipulating +it through the master half of the pseudo terminal. +That is, anything written on the master device is +given to the slave device as input and anything written +on the slave device is presented as input on the master +device. +.Pp +In configuring, if an optional +.Ar count +is given in +the specification, that number of pseudo terminal pairs are configured; +the default count is 32. +.Pp +The following +.Xr ioctl 2 +calls apply only to pseudo terminals: +.Bl -tag -width TIOCREMOTE +.It Dv TIOCSTOP +Stops output to a terminal (e.g. like typing +.Ql ^S ) . +Takes +no parameter. +.It Dv TIOCSTART +Restarts output (stopped by +.Dv TIOCSTOP +or by typing +.Ql ^S ) . +Takes no parameter. +.It Dv TIOCPKT +Enable/disable +.Em packet +mode. Packet mode is enabled by specifying (by reference) +a nonzero parameter and disabled by specifying (by reference) +a zero parameter. When applied to the master side of a pseudo +terminal, each subsequent +.Xr read 2 +from the terminal will return data written on the slave part of +the pseudo terminal preceded by a zero byte (symbolically +defined as +.Dv TIOCPKT_DATA ) , +or a single byte reflecting control +status information. In the latter case, the byte is an inclusive-or +of zero or more of the bits: +.Bl -tag -width TIOCPKT_FLUSHWRITE +.It Dv TIOCPKT_FLUSHREAD +whenever the read queue for the terminal is flushed. +.It Dv TIOCPKT_FLUSHWRITE +whenever the write queue for the terminal is flushed. +.It Dv TIOCPKT_STOP +whenever output to the terminal is stopped a la +.Ql ^S . +.It Dv TIOCPKT_START +whenever output to the terminal is restarted. +.It Dv TIOCPKT_DOSTOP +whenever +.Em t_stopc +is +.Ql ^S +and +.Em t_startc +is +.Ql ^Q . +.It Dv TIOCPKT_NOSTOP +whenever the start and stop characters are not +.Ql ^S/^Q . +.Pp +While this mode is in use, the presence of control status information +to be read from the master side may be detected by a +.Xr select 2 +for exceptional conditions. +.Pp +This mode is used by +.Xr rlogin 1 +and +.Xr rlogind 8 +to implement a remote-echoed, locally +.Ql ^S/^Q +flow-controlled +remote login with proper back-flushing of output; it can be +used by other similar programs. +.El +.It Dv TIOCUCNTL +Enable/disable a mode that allows a small number of simple user +.Xr ioctl 2 +commands to be passed through the pseudo-terminal, +using a protocol similar to that of +.Dv TIOCPKT . +The +.Dv TIOCUCNTL +and +.Dv TIOCPKT +modes are mutually exclusive. +This mode is enabled from the master side of a pseudo terminal +by specifying (by reference) +a nonzero parameter and disabled by specifying (by reference) +a zero parameter. +Each subsequent +.Xr read 2 +from the master side will return data written on the slave part of +the pseudo terminal preceded by a zero byte, +or a single byte reflecting a user control operation on the slave side. +A user control command consists of a special +.Xr ioctl 2 +operation with no data; the command is given as +.Dv UIOCCMD Ns (n) , +where +.Ar n +is a number in the range 1-255. +The operation value +.Ar n +will be received as a single byte on the next +.Xr read 2 +from the master side. +The +.Xr ioctl 2 +.Dv UIOCCMD Ns (0) +is a no-op that may be used to probe for +the existence of this facility. +As with +.Dv TIOCPKT +mode, command operations may be detected with a +.Xr select 2 +for exceptional conditions. +.It Dv TIOCREMOTE +A mode for the master half of a pseudo terminal, independent +of +.Dv TIOCPKT . +This mode causes input to the pseudo terminal +to be flow controlled and not input edited (regardless of the +terminal mode). Each write to the control terminal produces +a record boundary for the process reading the terminal. In +normal usage, a write of data is like the data typed as a line +on the terminal; a write of 0 bytes is like typing an end-of-file +character. +.Dv TIOCREMOTE +can be used when doing remote line +editing in a window manager, or whenever flow controlled input +is required. +.El +.Sh FILES +.Bl -tag -width /dev/tty[p-sP-S][a-z0-9]x -compact +.It Pa /dev/pty[p-sP-S][a-z0-9] +master pseudo terminals +.It Pa /dev/tty[p-sP-S][a-z0-9] +slave pseudo terminals +.El +.Sh DIAGNOSTICS +None. +.Sh HISTORY +The +.Nm +driver appeared in +.Bx 4.2 . diff --git a/bsd/man/man4/random.4 b/bsd/man/man4/random.4 new file mode 100644 index 000000000..491bf1d64 --- /dev/null +++ b/bsd/man/man4/random.4 @@ -0,0 +1,75 @@ +.Dd September 6, 2001 +.Dt RANDOM 4 +.Os Darwin +.Sh NAME +.Nm random +, +.Nm urandom +.Nd random data source devices. +.Sh SYNOPSIS +.Cd "pseudo-device random" +.Sh DESCRIPTION +The +.Nm +device produces uniformly distributed random byte values +of potentially high quality. +.Pp +To obtain random bytes, open +.Nm /dev/random +for reading and read from it. +.Pp +To add entropy to the random generation system, open +.Nm /dev/random +for writing and write data that you believe to be somehow random. +.Pp +.Nm /dev/urandom +is a compatibility nod to Linux. On Linux, +.Nm /dev/urandom +will produce lower quality output if the entropy pool drains, while +.Nm /dev/random +will prefer to block and wait for additional entropy to be collected. +With Yarrow, this choice and distinction is not necessary, and +the two devices behave identically. You may use either. +.Sh OPERATION +The +.Nm +device implements the +.Nm Yarrow +pseudo random number generator algorithm and maintains its entropy pool. +Addditional entropy is fed to the generator regularly by the +.Nm SecurityServer +daemon from random jitter measurements of the kernel. +.Nm SecurityServer +is also responsible for periodically saving some entropy to disk +and reloading it during startup to provide entropy in early system +operation. +.Pp +You may feed additional entropy to the generator by writing it to the +.Nm +device, though this is not required in a normal operating environment. +.Sh LIMITATIONS AND WARNINGS +.Nm Yarrow +is a fairly resilient algorithm, and is believed +to be resistant to non-root. +The quality of its output is however dependent on regular addition +of appropriate entropy. If the +.Nm SecurityServer +system daemon fails for any reason, output quality will suffer +over time without any explicit indication from the +.Nm +device itself. +.Pp +Paranoid programmers can counter-act this risk somewhat by collecting +entropy of their choice (e.g. from keystroke or mouse timings) +and seeding it into +.Nm +directly before obtaining important random numbers. +.Sh FILES +.Bl -tag -width /dev/urandom -compact +.It Pa /dev/random +.It Pa /dev/urandom +.El +.Sh HISTORY +A +.Nm +device appeared in Linux operating system. diff --git a/bsd/man/man4/route.4 b/bsd/man/man4/route.4 new file mode 100644 index 000000000..fd9ef63f1 --- /dev/null +++ b/bsd/man/man4/route.4 @@ -0,0 +1,271 @@ +.\" $NetBSD: route.4,v 1.3 1994/11/30 16:22:31 jtc Exp $ +.\" +.\" Copyright (c) 1990, 1991, 1993 +.\" 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. +.\" +.\" @(#)route.4 8.6 (Berkeley) 4/19/94 +.\" +.Dd April 19, 1994 +.Dt ROUTE 4 +.Os +.Sh NAME +.Nm route +.Nd kernel packet forwarding database +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Fd #include +.Ft int +.Fn socket PF_ROUTE SOCK_RAW "int family" +.Sh DESCRIPTION +Mac OS X provides some packet routing facilities. +The kernel maintains a routing information database, which +is used in selecting the appropriate network interface when +transmitting packets. +.Pp +A user process (or possibly multiple co-operating processes) +maintains this database by sending messages over a special kind +of socket. +This supplants fixed size +.Xr ioctl 2 Ns 's +used in earlier releases. +Routing table changes may only be carried out by the super user. +.Pp +The operating system may spontaneously emit routing messages in response +to external events, such as receipt of a re-direct, or failure to +locate a suitable route for a request. +The message types are described in greater detail below. +.Pp +Routing database entries come in two flavors: for a specific +host, or for all hosts on a generic subnetwork (as specified +by a bit mask and value under the mask. +The effect of wildcard or default route may be achieved by using +a mask of all zeros, and there may be hierarchical routes. +.Pp +When the system is booted and addresses are assigned +to the network interfaces, each protocol family +installs a routing table entry for each interface when it is ready for traffic. +Normally the protocol specifies the route +through each interface as a +.Dq direct +connection to the destination host +or network. If the route is direct, the transport layer of +a protocol family usually requests the packet be sent to the +same host specified in the packet. Otherwise, the interface +is requested to address the packet to the gateway listed in the routing entry +(i.e. the packet is forwarded). +.Pp +When routing a packet, +the kernel will attempt to find +the most specific route matching the destination. +(If there are two different mask and value-under-the-mask pairs +that match, the more specific is the one with more bits in the mask. +A route to a host is regarded as being supplied with a mask of +as many ones as there are bits in the destination). +If no entry is found, the destination is declared to be unreachable, +and a routing\-miss message is generated if there are any +listers on the routing control socket described below. +.Pp +A wildcard routing entry is specified with a zero +destination address value, and a mask of all zeroes. +Wildcard routes will be used +when the system fails to find other routes matching the +destination. The combination of wildcard +routes and routing redirects can provide an economical +mechanism for routing traffic. +.Pp +One opens the channel for passing routing control messages +by using the socket call shown in the synopsis above: +.Pp +The +.Fa family +parameter may be +.Dv AF_UNSPEC +which will provide +routing information for all address families, or can be restricted +to a specific address family by specifying which one is desired. +There can be more than one routing socket open per system. +.Pp +Messages are formed by a header followed by a small +number of sockadders (now variable length particularly +in the +.Tn ISO +case), interpreted by position, and delimited +by the new length entry in the sockaddr. +An example of a message with four addresses might be an +.Tn ISO +redirect: +Destination, Netmask, Gateway, and Author of the redirect. +The interpretation of which address are present is given by a +bit mask within the header, and the sequence is least significant +to most significant bit within the vector. +.Pp +Any messages sent to the kernel are returned, and copies are sent +to all interested listeners. The kernel will provide the process +id. for the sender, and the sender may use an additional sequence +field to distinguish between outstanding messages. However, +message replies may be lost when kernel buffers are exhausted. +.Pp +The kernel may reject certain messages, and will indicate this +by filling in the +.Ar rtm_errno +field. +The routing code returns +.Dv EEXIST +if +requested to duplicate an existing entry, +.Dv ESRCH +if +requested to delete a non-existent entry, +or +.Dv ENOBUFS +if insufficient resources were available +to install a new route. +In the current implementation, all routing process run locally, +and the values for +.Ar rtm_errno +are available through the normal +.Em errno +mechanism, even if the routing reply message is lost. +.Pp +A process may avoid the expense of reading replies to +its own messages by issuing a +.Xr setsockopt 2 +call indicating that the +.Dv SO_USELOOPBACK +option +at the +.Dv SOL_SOCKET +level is to be turned off. +A process may ignore all messages from the routing socket +by doing a +.Xr shutdown 2 +system call for further input. +.Pp +If a route is in use when it is deleted, +the routing entry will be marked down and removed from the routing table, +but the resources associated with it will not +be reclaimed until all references to it are released. +User processes can obtain information about the routing +entry to a specific destination by using a +.Dv RTM_GET +message, +or by reading the +.Pa /dev/kmem +device, or by issuing a +.Xr getkerninfo 2 +system call. +.Pp +Messages include: +.Bd -literal +#define RTM_ADD 0x1 /* Add Route */ +#define RTM_DELETE 0x2 /* Delete Route */ +#define RTM_CHANGE 0x3 /* Change Metrics, Flags, or Gateway */ +#define RTM_GET 0x4 /* Report Information */ +#define RTM_LOOSING 0x5 /* Kernel Suspects Partitioning */ +#define RTM_REDIRECT 0x6 /* Told to use different route */ +#define RTM_MISS 0x7 /* Lookup failed on this address */ +#define RTM_RESOLVE 0xb /* request to resolve dst to LL addr */ +.Ed +.Pp +A message header consists of: +.Bd -literal +struct rt_msghdr { + u_short rmt_msglen; /* to skip over non-understood messages */ + u_char rtm_version; /* future binary compatibility */ + u_char rtm_type; /* message type */ + u_short rmt_index; /* index for associated ifp */ + pid_t rmt_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 values we are initializing */ + struct rt_metrics rtm_rmx; /* metrics themselves */ +}; +.Ed +.Pp +where +.Bd -literal +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 */ +}; +.Ed +.Pp +Flags include the values: +.Bd -literal +#define RTF_UP 0x1 /* route usable */ +#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_STATIC 0x800 /* manually added */ +#define RTF_BLACKHOLE 0x1000 /* just discard pkts (during updates) */ +#define RTF_PROTO2 0x4000 /* protocol specific routing flag #1 */ +#define RTF_PROTO1 0x8000 /* protocol specific routing flag #2 */ +.Ed +.Pp +Specifiers for metric values in rmx_locks and rtm_inits are: +.Bd -literal +#define RTV_SSTHRESH 0x1 /* init or lock _ssthresh */ +#define RTV_RPIPE 0x2 /* init or lock _recvpipe */ +#define RTV_SPIPE 0x4 /* init or lock _sendpipe */ +#define RTV_HOPCOUNT 0x8 /* init or lock _hopcount */ +#define RTV_RTT 0x10 /* init or lock _rtt */ +#define RTV_RTTVAR 0x20 /* init or lock _rttvar */ +#define RTV_MTU 0x40 /* init or lock _mtu */ +.Ed +.Pp +Specifiers for which addresses are present in the messages are: +.Bd -literal +#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 */ +.Ed diff --git a/bsd/man/man4/scsi.4 b/bsd/man/man4/scsi.4 new file mode 100644 index 000000000..85c6cb914 --- /dev/null +++ b/bsd/man/man4/scsi.4 @@ -0,0 +1,156 @@ +.\" $OpenBSD: scsi.4,v 1.1 1996/08/04 20:28:20 tholo Exp $ +.\" +.Dd August 4, 1996 +.Dt SD 4 +.Os OpenBSD +.Sh NAME +.Nm scsi +.Nd scsi system +.Sh SYNOPSIS +.Nm scsibus* at aha? +.Nm scsibus* at ncr? +.Nm device cd* at scsibus? target ? lun ? +.Nm device ch* at scsibus? target ? lun ? +.Nm device sd* at scsibus? target ? lun ? +.Nm device st* at scsibus? target ? lun ? +.Nm device ss* at scsibus? target ? lun ? +.Nm device su* at scsibus? target ? lun ? +.Nm device uk* at scsibus? target ? lun ? +.Sh DESCRIPTION +The +.Em scsi +system provides a uniform and modular system for the implementation +of drivers to control various scsi devices, and to utilize different +scsi host adapters through host adapter drivers. When the system probes the +.Em SCSI +busses, it attaches any devices it finds to the appropriate +drivers. If no driver seems appropriate, then it attaches the device to the +uk (unknown) driver so that user level scsi ioctls may +still be performed against the device. +.Sh KERNEL CONFIGURATION +The option SCSIDEBUG enables the debug ioctl. +.Pp +All devices and the SCSI busses support boot time allocation so that +an upper number of devices and controllers does not need to be configured; +.Em "device sd* at scsibus? target ? lun ?" +will suffice for any number of disk drivers. +.Pp +The devices are either +.Em wired +so they appear as a particular device unit or +.Em counted +so that they appear as the next available unused unit. +.Pp +To configure a driver in the kernel without wiring down the device use a +config line similar to +.Em "device ch* at scsibus? target ? lun ?" +to include the changer driver. +.Pp +To wire down a unit use a config line similar to +.Em "device ch1 at scsibus0 target 4 lun 0" +to assign changer 1 as the changer with SCSI ID 4, +SCSI logical unit 0 on SCSI bus 0. +Individual scsibuses can be wired down to specific controllers with +a config line similar to +.Em "scsibus0 at ahc0" +which assigns scsi bus 0 to the first unit using the ahc driver. +For controllers supporting more than one bus, +the particular bus can be specified as in +.Em "scsibus3 at ahc1 bus 1" +which assigns scsibus 1 to the second bus probed on the ahc1 device. +.Pp +When you have a mixture of wired down and counted devices then the +counting begins with the first non-wired down unit for a particular +type. That is, if you have a disk wired down as +.Em "disk sd1 at scsibus? target ? lun ?" , +then the first non-wired disk shall come on line as +.Em sd2 . +.Sh IOCTLS +There are a number of ioctls that work on any +.Em SCSI +device. They are defined in +.Em sys/scsiio.h +and can be applied against any scsi device that permits them. +For the tape, it must be applied against the control +device. See the manual page for each device type for more information about +how generic scsi ioctls may be applied to a specific device. +.Bl -tag -width DIOCSDINFO____ +.It Dv SCIOCRESET* +reset a device. +.It Dv SCIOCDEBUG +Turn on debugging.. All scsi operations originating from this device's driver +will be traced to the console, along with other information. Debugging is +controlled by four bits, described in the header file. If no debugging is +configured into the kernel, debugging will have no effect. +.Em SCSI +debugging is controlled by the configuration option +.Em SCSIDEBUG. +.It Dv SCIOCCOMMAND +Take a scsi command and data from a user process and apply them to the scsi +device. Return all status information and return data to the process. The +ioctl will return a successful status even if the device rejected the +command. As all status is returned to the user, it is up to the user +process to examine this information to decide the success of the command. +.It Dv SCIOCREPROBE +Ask the system to probe the scsi busses for any new devices. If it finds +any, they will be attached to the appropriate drivers. The search can be +narrowed to a specific bus, target or lun. The new device may or may not +be related to the device on which the ioctl was performed. +.It Dv SCIOCIDENTIFY +Ask the driver what it's bus, target and lun are. +.It Dv SCIOCDECONFIG +Ask the device to disappear. This may not happen if the device is in use. +.El +.Sh NOTES +the generic scsi part of the system is still being mapped out. +Watch this space for changes. +.Pp + A device by the name of su (scsi_user) +(e.g su0-0-0) will map bus, target and lun to minor numbers. It has not +yet decided yet whether this device will be able to open a device that is +already controlled by an explicit driver. +.Sh ADAPTERS +The system allows common device drivers to work through many different +types of adapters. The adapters take requests from the upper layers and do +all IO between the +.Em SCSI +bus and the system. The maximum size of a transfer is governed by the +adapter. Most adapters can transfer 64KB in a single operation, however +many can transfer larger amounts. +.Sh TARGET MODE +Some adapters support +.Em target mode +in which the system is capable of operating as a device, responding to +operations initiated by another system. Target mode will be supported for +some adapters, but is not yet complete for this version of the scsi system. +.Sh DIAGNOSTICS +When the kernel is compiled with option SCSIDEBUG, the SCIOCDEBUG ioctl +can be used to enable various amounts of tracing information on any +specific device. Devices not being traced will not produce trace information. +The four bits that make up the debug level, each control certain types +of debugging information. +.Bl -tag -width "Bit 0" +.It Dv Bit 0 +shows all scsi bus operations including scsi commands, +error information and the first 48 bytes of any data transferred. +.It Dv Bit 1 +shows routines called. +.It Dv Bit 2 +shows information about what branches are taken and often some +of the return values of functions. +.It Dv Bit 3 +shows more detailed information including DMA scatter-gather logs. +.El +.Sh SEE ALSO +.Xr ch 4 , +.Xr cd 4 , +.Xr sd 4 , +.Xr ss 4 , +.Xr st 4 , +.Xr su 4 +and +.Xr uk 4 +.Sh HISTORY +This +.Nm +system appeared in MACH 2.5 at TRW. diff --git a/bsd/man/man4/stderr.4 b/bsd/man/man4/stderr.4 new file mode 100644 index 000000000..7922f7e0d --- /dev/null +++ b/bsd/man/man4/stderr.4 @@ -0,0 +1 @@ +.so man4/fd.4 diff --git a/bsd/man/man4/stdin.4 b/bsd/man/man4/stdin.4 new file mode 100644 index 000000000..7922f7e0d --- /dev/null +++ b/bsd/man/man4/stdin.4 @@ -0,0 +1 @@ +.so man4/fd.4 diff --git a/bsd/man/man4/stdout.4 b/bsd/man/man4/stdout.4 new file mode 100644 index 000000000..7922f7e0d --- /dev/null +++ b/bsd/man/man4/stdout.4 @@ -0,0 +1 @@ +.so man4/fd.4 diff --git a/bsd/man/man4/stf.4 b/bsd/man/man4/stf.4 new file mode 100644 index 000000000..e1c374f38 --- /dev/null +++ b/bsd/man/man4/stf.4 @@ -0,0 +1,251 @@ +.\" $FreeBSD: src/share/man/man4/stf.4,v 1.3.2.4 2001/08/17 13:08:39 ru Exp $ +.\" $KAME: stf.4,v 1.35 2001/05/02 06:24:49 itojun Exp $ +.\" +.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the project nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd April 27, 2001 +.Dt STF 4 +.Os +.Sh NAME +.Nm stf +.Nd +.Tn 6to4 +tunnel interface +.Sh SYNOPSIS +.Cd "pseudo-device stf" +.Sh DESCRIPTION +The +.Nm +interface supports +.Dq 6to4 +IPv6 in IPv4 encapsulation. +It can tunnel IPv6 traffic over IPv4, as specified in +.Li RFC3056 . +.Pp +For ordinary nodes in 6to4 site, you do not need +.Nm +interface. +The +.Nm +interface is necessary for site border router +(called +.Dq 6to4 router +in the specification). +.Pp +Due to the way 6to4 protocol is specified, +.Nm +interface requires certain configuration to work properly. +Single +(no more than 1) +valid 6to4 address needs to be configured to the interface. +.Dq A valid 6to4 address +is an address which has the following properties. +If any of the following properties are not satisfied, +.Nm +raises runtime error on packet transmission. +Read the specification for more details. +.Bl -bullet +.It +matches +.Li 2002:xxyy:zzuu::/48 +where +.Li xxyy:zzuu +is a hexadecimal notation of an IPv4 address for the node. +IPv4 address can be taken from any of interfaces your node has. +Since the specification forbids the use of IPv4 private address, +the address needs to be a global IPv4 address. +.It +Subnet identifier portion +(48th to 63rd bit) +and interface identifier portion +(lower 64 bits) +are properly filled to avoid address collisions. +.El +.Pp +If you would like the node to behave as a relay router, +the prefix length for the IPv6 interface address needs to be 16 so that +the node would consider any 6to4 destination as +.Dq on-link . +If you would like to restrict 6to4 peers to be inside certain IPv4 prefix, +you may want to configure IPv6 prefix length as +.Dq 16 + IPv4 prefix length . +.Nm +interface will check the IPv4 source address on packets, +if the IPv6 prefix length is larger than 16. +.Pp +.Nm +can be configured to be ECN friendly. +This can be configured by +.Dv IFF_LINK1 . +See +.Xr gif 4 +for details. +.Pp +Please note that 6to4 specification is written as +.Dq accept tunnelled packet from everyone +tunnelling device. +By enabling +.Nm +device, you are making it much easier for malicious parties to inject +fabricated IPv6 packet to your node. +Also, malicious party can inject an IPv6 packet with fabricated source address +to make your node generate improper tunnelled packet. +Administrators must take caution when enabling the interface. +To prevent possible attacks, +.Nm +interface filters out the following packets. +Note that the checks are no way complete: +.Bl -bullet +.It +Packets with IPv4 unspecified addrss as outer IPv4 source/destination +.Pq Li 0.0.0.0/8 +.It +Packets with loopback address as outer IPv4 source/destination +.Pq Li 127.0.0.0/8 +.It +Packets with IPv4 multicast address as outer IPv4 source/destination +.Pq Li 224.0.0.0/4 +.It +Packets with limited broadcast address as outer IPv4 source/destination +.Pq Li 255.0.0.0/8 +.It +Packets with subnet broadcast address as outer IPv4 source/destination. +The check is made against subnet broadcast addresses for +all of the directly connected subnets. +.It +Packets that does not pass ingress filtering. +Outer IPv4 source address must meet the IPv4 topology on the routing table. +Ingress filter can be turned off by +.Dv IFF_LINK2 +bit. +.It +The same set of rules are appplied against the IPv4 address embedded into +inner IPv6 address, if the IPv6 address matches 6to4 prefix. +.El +.Pp +It is recommended to filter/audit +incoming IPv4 packet with IP protocol number 41, as necessary. +It is also recommended to filter/audit encapsulated IPv6 packets as well. +You may also want to run normal ingress filter against inner IPv6 address +to avoid spoofing. +.Pp +By setting the +.Dv IFF_LINK0 +flag on the +.Nm +interface, it is possible to disable the input path, +making the direct attacks from the outside impossible. +Note, however, there are other security risks exist. +If you wish to use the configuration, +you must not advertise your 6to4 address to others. +.\" +.Sh EXAMPLES +Note that +.Li 8504:0506 +is equal to +.Li 133.4.5.6 , +written in hexadecimals. +.Bd -literal +# ifconfig ne0 inet 133.4.5.6 netmask 0xffffff00 +# ifconfig stf0 inet6 2002:8504:0506:0000:a00:5aff:fe38:6f86 \\ + prefixlen 16 alias +.Ed +.Pp +The following configuration accepts packets from IPv4 source +.Li 9.1.0.0/16 +only. +It emits 6to4 packet only for IPv6 destination 2002:0901::/32 +(IPv4 destination will match +.Li 9.1.0.0/16 ) . +.Bd -literal +# ifconfig ne0 inet 9.1.2.3 netmask 0xffff0000 +# ifconfig stf0 inet6 2002:0901:0203:0000:a00:5aff:fe38:6f86 \\ + prefixlen 32 alias +.Ed +.Pp +The following configuration uses the +.Nm +interface as an output-only device. +You need to have alternative IPv6 connectivity +(other than 6to4) +to use this configuration. +For outbound traffic, you can reach other 6to4 networks efficiently via +.Nm stf . +For inbound traffic, you will not receive any 6to4-tunneled packets +(less security drawbacks). +Be careful not to advertise your 6to4 prefix to others +.Pq Li 2002:8504:0506::/48 , +and not to use your 6to4 prefix as a source. +.Bd -literal +# ifconfig ne0 inet 133.4.5.6 netmask 0xffffff00 +# ifconfig stf0 inet6 2002:8504:0506:0000:a00:5aff:fe38:6f86 \\ + prefixlen 16 alias deprecated link0 +# route add -inet6 2002:: -prefixlen 16 ::1 +# route change -inet6 2002:: -prefixlen 16 ::1 -ifp stf0 +.Ed +.\" +.Sh SEE ALSO +.Xr gif 4 , +.Xr inet 4 , +.Xr inet6 4 +.Pp +.Pa http://www.6bone.net/6bone_6to4.html +.Rs +.%A Brian Carpenter +.%A Keith Moore +.%T "Connection of IPv6 Domains via IPv4 Clouds" +.%D February 2001 +.%R RFC +.%N 3056 +.Re +.Rs +.%A Jun-ichiro itojun Hagino +.%T "Possible abuse against IPv6 transition technologies" +.%D July 2000 +.%N draft-itojun-ipv6-transition-abuse-01.txt +.%O work in progress +.Re +.\" +.Sh HISTORY +The +.Nm +device first appeared in WIDE/KAME IPv6 stack. +.\" +.Sh BUGS +No more than one +.Nm +interface is allowed for a node, +and no more than one IPv6 interface address is allowed for an +.Nm +interface. +It is to avoid source address selection conflicts +between IPv6 layer and IPv4 layer, +and to cope with ingress filtering rule on the other side. +This is a feature to make +.Nm +work right for all occasions. diff --git a/bsd/man/man4/tcp.4 b/bsd/man/man4/tcp.4 new file mode 100644 index 000000000..62bb958d5 --- /dev/null +++ b/bsd/man/man4/tcp.4 @@ -0,0 +1,180 @@ +.\" $NetBSD: tcp.4,v 1.3 1994/11/30 16:22:35 jtc Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)tcp.4 8.1 (Berkeley) 6/5/93 +.\" +.Dd June 5, 1993 +.Dt TCP 4 +.Os BSD 4.2 +.Sh NAME +.Nm tcp +.Nd Internet Transmission Control Protocol +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn socket AF_INET SOCK_STREAM 0 +.Sh DESCRIPTION +The +.Tn TCP +protocol provides reliable, flow-controlled, two-way +transmission of data. It is a byte-stream protocol used to +support the +.Dv SOCK_STREAM +abstraction. TCP uses the standard +Internet address format and, in addition, provides a per-host +collection of +.Dq port addresses . +Thus, each address is composed +of an Internet address specifying the host and network, with +a specific +.Tn TCP +port on the host identifying the peer entity. +.Pp +Sockets utilizing the tcp protocol are either +.Dq active +or +.Dq passive . +Active sockets initiate connections to passive +sockets. By default +.Tn TCP +sockets are created active; to create a +passive socket the +.Xr listen 2 +system call must be used +after binding the socket with the +.Xr bind 2 +system call. Only +passive sockets may use the +.Xr accept 2 +call to accept incoming connections. Only active sockets may +use the +.Xr connect 2 +call to initiate connections. +.Pp +Passive sockets may +.Dq underspecify +their location to match +incoming connection requests from multiple networks. This +technique, termed +.Dq wildcard addressing , +allows a single +server to provide service to clients on multiple networks. +To create a socket which listens on all networks, the Internet +address +.Dv INADDR_ANY +must be bound. The +.Tn TCP +port may still be specified +at this time; if the port is not specified the system will assign one. +Once a connection has been established the socket's address is +fixed by the peer entity's location. The address assigned the +socket is the address associated with the network interface +through which packets are being transmitted and received. Normally +this address corresponds to the peer entity's network. +.Pp +.Tn TCP +supports one socket option which is set with +.Xr setsockopt 2 +and tested with +.Xr getsockopt 2 . +Under most circumstances, +.Tn TCP +sends data when it is presented; +when outstanding data has not yet been acknowledged, it gathers +small amounts of output to be sent in a single packet once +an acknowledgement is received. +For a small number of clients, such as window systems +that send a stream of mouse events which receive no replies, +this packetization may cause significant delays. +Therefore, +.Tn TCP +provides a boolean option, +.Dv TCP_NODELAY +(from +.Aq Pa netinet/tcp.h , +to defeat this algorithm. +The option level for the +.Xr setsockopt +call is the protocol number for +.Tn TCP , +available from +.Xr getprotobyname 3 . +.Pp +Options at the +.Tn IP +transport level may be used with +.Tn TCP ; +see +.Xr ip 4 . +Incoming connection requests that are source-routed are noted, +and the reverse source route is used in responding. +.Sh DIAGNOSTICS +A socket operation may fail with one of the following errors returned: +.Bl -tag -width [EADDRNOTAVAIL] +.It Bq Er EISCONN +when trying to establish a connection on a socket which +already has one; +.It Bq Er ENOBUFS +when the system runs out of memory for +an internal data structure; +.It Bq Er ETIMEDOUT +when a connection was dropped +due to excessive retransmissions; +.It Bq Er ECONNRESET +when the remote peer +forces the connection to be closed; +.It Bq Er ECONNREFUSED +when the remote +peer actively refuses connection establishment (usually because +no process is listening to the port); +.It Bq Er EADDRINUSE +when an attempt +is made to create a socket with a port which has already been +allocated; +.It Bq Er EADDRNOTAVAIL +when an attempt is made to create a +socket with a network address for which no network interface +exists. +.El +.Sh SEE ALSO +.Xr getsockopt 2 , +.Xr socket 2 , +.Xr intro 4 , +.Xr inet 4 , +.Xr ip 4 +.Sh HISTORY +The +.Nm +protocol stack appeared in +.Bx 4.2 . diff --git a/bsd/man/man4/termios.4 b/bsd/man/man4/termios.4 new file mode 100644 index 000000000..c3c5ee741 --- /dev/null +++ b/bsd/man/man4/termios.4 @@ -0,0 +1,1466 @@ +.\" $NetBSD: termios.4,v 1.5 1994/11/30 16:22:36 jtc Exp $ +.\" +.\" Copyright (c) 1991, 1992, 1993 +.\" 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.4 8.4 (Berkeley) 4/19/94 +.\" +.Dd April 19, 1994 +.Dt TERMIOS 4 +.Os BSD 4 +.Sh NAME +.Nm termios +.Nd general terminal line discipline +.Sh SYNOPSIS +.Fd #include +.Sh DESCRIPTION +This describes a general terminal line discipline that is +supported on tty asynchronous communication ports. +.Ss Opening a Terminal Device File +When a terminal file is opened, it normally causes the process to wait +until a connection is established. For most hardware, the presence +of a connection is indicated by the assertion of the hardware +.Dv CARRIER line. +If the termios structure associated with the terminal file has the +.Dv CLOCAL +flag set in the cflag, or if the +.Dv O_NONBLOCK +flag is set +in the +.Xr open 2 +call, then the open will succeed even without +a connection being present. +In practice, applications +seldom open these files; they are opened by special programs, such +as +.Xr getty 2 +or +.Xr rlogind 2 , +and become +an application's standard input, output, and error files. +.Ss Job Control in a Nutshell +Every process is associated with a particular process group and session. +The grouping is hierarchical: every member of a particular process group is a +member of the same session. This structuring is used in managing groups +of related processes for purposes of +.\" .Gw "job control" ; +.Em "job control" ; +that is, the +ability from the keyboard (or from program control) to simultaneously +stop or restart +a complex command (a command composed of one or more related +processes). The grouping into process groups allows delivering +of signals that stop or start the group as a whole, along with +arbitrating which process group has access to the single controlling +terminal. The grouping at a higher layer into sessions is to restrict +the job control related signals and system calls to within processes +resulting from a particular instance of a "login". Typically, a session +is created when a user logs in, and the login terminal is setup +to be the controlling terminal; all processes spawned from that +login shell are in the same session, and inherit the controlling +terminal. +A job control shell +operating interactively (that is, reading commands from a terminal) +normally groups related processes together by placing them into the +same process group. A set of processes in the same process group +is collectively referred to as a "job". When the foreground process +group of the terminal is the same as the process group of a particular +job, that job is said to be in the "foreground". When the process +group of the terminal is different than the process group of +a job (but is still the controlling terminal), that job is said +to be in the "background". Normally the +shell reads a command and starts the job that implements that +command. If the command is to be started in the foreground (typical), it +sets the process group of the terminal to the process group +of the started job, waits for the job to complete, and then +sets the process group of the terminal back to its own process +group (it puts itself into the foreground). If the job is to +be started in the background (as denoted by the shell operator "&"), +it never changes the process group of the terminal and doesn't +wait for the job to complete (that is, it immediately attempts to read the next +command). If the job is started in the foreground, the user may +type a key (usually +.Ql \&^Z ) +which generates the terminal stop signal +.Pq Dv SIGTSTP +and has the affect of stopping the entire job. +The shell will notice that the job stopped, and will resume running after +placing itself in the foreground. +The shell also has commands for placing stopped jobs in the background, +and for placing stopped or background jobs into the foreground. +.Ss Orphaned Process Groups +An orphaned process group is a process group that has no process +whose parent is in a different process group, yet is in the same +session. Conceptually it means a process group that doesn't have +a parent that could do anything if it were to be stopped. For example, +the initial login shell is typically in an orphaned process group. +Orphaned process groups are immune to keyboard generated stop +signals and job control signals resulting from reads or writes to the +controlling terminal. +.Ss The Controlling Terminal +A terminal may belong to a process as its controlling terminal. Each +process of a session that has a controlling terminal has the same +controlling terminal. A terminal may be the controlling terminal for at +most one session. The controlling terminal for a session is allocated by +the session leader by issuing the +.Dv TIOCSCTTY +ioctl. A controlling terminal +is never acquired by merely opening a terminal device file. +When a controlling terminal becomes +associated with a session, its foreground process group is set to +the process group of the session leader. +.Pp +The controlling terminal is inherited by a child process during a +.Xr fork 2 +function call. A process relinquishes its controlling terminal when it +creates a new session with the +.Xr setsid 2 +function; other processes +remaining in the old session that had this terminal as their controlling +terminal continue to have it. +A process does not relinquish its +controlling terminal simply by closing all of its file descriptors +associated with the controlling terminal if other processes continue to +have it open. +.Pp +When a controlling process terminates, the controlling terminal is +disassociated from the current session, allowing it to be acquired by a +new session leader. Subsequent access to the terminal by other processes +in the earlier session will be denied, with attempts to access the +terminal treated as if modem disconnect had been sensed. +.Ss Terminal Access Control +If a process is in the foreground process group of its controlling +terminal, read operations are allowed. +Any attempts by a process +in a background process group to read from its controlling terminal +causes a +.Dv SIGTTIN +signal to be sent to +the process's group +unless one of the +following special cases apply: If the reading process is ignoring or +blocking the +.Dv SIGTTIN signal, or if the process group of the reading +process is orphaned, the +.Xr read 2 +returns -1 with +.Va errno set to +.Er Dv EIO +and no +signal is sent. The default action of the +.Dv SIGTTIN +signal is to stop the +process to which it is sent. +.Pp +If a process is in the foreground process group of its controlling +terminal, write operations are allowed. +Attempts by a process in a background process group to write to its +controlling terminal will cause the process group to be sent a +.Dv SIGTTOU +signal unless one of the following special cases apply: If +.Dv TOSTOP +is not +set, or if +.Dv TOSTOP +is set and the process is ignoring or blocking the +.Dv SIGTTOU +signal, the process is allowed to write to the terminal and the +.Dv SIGTTOU +signal is not sent. If +.Dv TOSTOP +is set, and the process group of +the writing process is orphaned, and the writing process is not ignoring +or blocking +.Dv SIGTTOU , +the +.Xr write +returns -1 with +errno set to +.Er Dv EIO +and no signal is sent. +.Pp +Certain calls that set terminal parameters are treated in the same +fashion as write, except that +.Dv TOSTOP +is ignored; that is, the effect is +identical to that of terminal writes when +.Dv TOSTOP +is set. +.Ss Input Processing and Reading Data +A terminal device associated with a terminal device file may operate in +full-duplex mode, so that data may arrive even while output is occurring. +Each terminal device file has associated with it an input queue, into +which incoming data is stored by the system before being read by a +process. The system imposes a limit, +.Pf \&{ Dv MAX_INPUT Ns \&} , +on the number of +bytes that may be stored in the input queue. The behavior of the system +when this limit is exceeded depends on the setting of the +.Dv IMAXBEL +flag in the termios +.Fa c_iflag . +If this flag is set, the terminal +is sent an +.Tn ASCII +.Dv BEL +character each time a character is received +while the input queue is full. Otherwise, the input queue is flushed +upon receiving the character. +.Pp +Two general kinds of input processing are available, determined by +whether the terminal device file is in canonical mode or noncanonical +mode. Additionally, +input characters are processed according to the +.Fa c_iflag +and +.Fa c_lflag +fields. Such processing can include echoing, which +in general means transmitting input characters immediately back to the +terminal when they are received from the terminal. This is useful for +terminals that can operate in full-duplex mode. +.Pp +The manner in which data is provided to a process reading from a terminal +device file is dependent on whether the terminal device file is in +canonical or noncanonical mode. +.Pp +Another dependency is whether the +.Dv O_NONBLOCK +flag is set by +.Xr open() +or +.Xr fcntl() . +If the +.Dv O_NONBLOCK +flag is clear, then the read request is +blocked until data is available or a signal has been received. If the +.Dv O_NONBLOCK +flag is set, then the read request is completed, without +blocking, in one of three ways: +.Bl -enum -offset indent +.It +If there is enough data available to satisfy the entire request, +and the read completes successfully the number of +bytes read is returned. +.It +If there is not enough data available to satisfy the entire +request, and the read completes successfully, having read as +much data as possible, the number of bytes read is returned. +.It +If there is no data available, the read returns -1, with +errno set to +.Er EAGAIN . +.El +.Pp +When data is available depends on whether the input processing mode is +canonical or noncanonical. +.Ss Canonical Mode Input Processing +In canonical mode input processing, terminal input is processed in units +of lines. A line is delimited by a newline +.Ql \&\en +character, an end-of-file +.Pq Dv EOF +character, or an end-of-line +.Pq Dv EOL +character. See the +.Sx "Special Characters" +section for +more information on +.Dv EOF +and +.Dv EOL . +This means that a read request will +not return until an entire line has been typed, or a signal has been +received. Also, no matter how many bytes are requested in the read call, +at most one line is returned. It is not, however, necessary to +read a whole line at once; any number of bytes, even one, may be +requested in a read without losing information. +.Pp +.Pf \&{ Dv MAX_CANON Ns \&} +is a limit on the +number of bytes in a line. +The behavior of the system when this limit is +exceeded is the same as when the input queue limit +.Pf \&{ Dv MAX_INPUT Ns \&} , +is exceeded. +.Pp +Erase and kill processing occur when either of two special characters, +the +.Dv ERASE +and +.Dv KILL +characters (see the +.Sx "Special Characters section" ) , +is received. +This processing affects data in the input queue that has not yet been +delimited by a newline +.Dv NL, +.Dv EOF , +or +.Dv EOL +character. This un-delimited +data makes up the current line. The +.Dv ERASE +character deletes the last +character in the current line, if there is any. The +.Dv KILL +character +deletes all data in the current line, if there is any. The +.Dv ERASE +and +.Dv KILL +characters have no effect if there is no data in the current line. +The +.Dv ERASE +and +.Dv KILL +characters themselves are not placed in the input +queue. +.Ss Noncanonical Mode Input Processing +In noncanonical mode input processing, input bytes are not assembled into +lines, and erase and kill processing does not occur. The values of the +.Dv MIN +and +.Dv TIME +members of the +.Fa c_cc +array are used to determine how to +process the bytes received. +.Pp +.Dv MIN +represents the minimum number of bytes that should be received when +the +.Xr read +function successfully returns. +.Dv TIME +is a timer of 0.1 second +granularity that is used to time out bursty and short term data +transmissions. If +.Dv MIN +is greater than +.Dv \&{ Dv MAX_INPUT Ns \&} , +the response to the +request is undefined. The four possible values for +.Dv MIN +and +.Dv TIME +and +their interactions are described below. +.Ss "Case A: MIN > 0, TIME > 0" +In this case +.Dv TIME +serves as an inter-byte timer and is activated after +the first byte is received. Since it is an inter-byte timer, it is reset +after a byte is received. The interaction between +.Dv MIN +and +.Dv TIME +is as +follows: as soon as one byte is received, the inter-byte timer is +started. If +.Dv MIN +bytes are received before the inter-byte timer expires +(remember that the timer is reset upon receipt of each byte), the read is +satisfied. If the timer expires before +.Dv MIN +bytes are received, the +characters received to that point are returned to the user. Note that if +.Dv TIME +expires at least one byte is returned because the timer would +not have been enabled unless a byte was received. In this case +.Pf \&( Dv MIN +> 0, +.Dv TIME +> 0) the read blocks until the +.Dv MIN +and +.Dv TIME +mechanisms are +activated by the receipt of the first byte, or a signal is received. If +data is in the buffer at the time of the read(), the result is as +if data had been received immediately after the read(). +.Ss "Case B: MIN > 0, TIME = 0" +In this case, since the value of +.Dv TIME +is zero, the timer plays no role +and only +.Dv MIN +is significant. A pending read is not satisfied until +.Dv MIN +bytes are received (i.e., the pending read blocks until +.Dv MIN +bytes +are received), or a signal is received. A program that uses this case to +read record-based terminal +.Dv I/O +may block indefinitely in the read +operation. +.Ss "Case C: MIN = 0, TIME > 0" +In this case, since +.Dv MIN += 0, +.Dv TIME +no longer represents an inter-byte +timer. It now serves as a read timer that is activated as soon as the +read function is processed. A read is satisfied as soon as a single +byte is received or the read timer expires. Note that in this case if +the timer expires, no bytes are returned. If the timer does not +expire, the only way the read can be satisfied is if a byte is received. +In this case the read will not block indefinitely waiting for a byte; if +no byte is received within +.Dv TIME Ns *0.1 +seconds after the read is initiated, +the read returns a value of zero, having read no data. If data is +in the buffer at the time of the read, the timer is started as if +data had been received immediately after the read. +.Ss Case D: MIN = 0, TIME = 0 +The minimum of either the number of bytes requested or the number of +bytes currently available is returned without waiting for more +bytes to be input. If no characters are available, read returns a +value of zero, having read no data. +.Ss Writing Data and Output Processing +When a process writes one or more bytes to a terminal device file, they +are processed according to the +.Fa c_oflag +field (see the +.Sx "Output Modes +section). The +implementation may provide a buffering mechanism; as such, when a call to +write() completes, all of the bytes written have been scheduled for +transmission to the device, but the transmission will not necessarily +have been completed. +.\" See also .Sx "6.4.2" for the effects of +.\" .Dv O_NONBLOCK +.\" on write. +.Ss Special Characters +Certain characters have special functions on input or output or both. +These functions are summarized as follows: +.Bl -tag -width indent +.It Dv INTR +Special character on input and is recognized if the +.Dv ISIG +flag (see the +.Sx "Local Modes" +section) is enabled. Generates a +.Dv SIGINT +signal which is sent to all processes in the foreground +process group for which the terminal is the controlling +terminal. If +.Dv ISIG +is set, the +.Dv INTR +character is +discarded when processed. +.It Dv QUIT +Special character on input and is recognized if the +.Dv ISIG +flag is enabled. Generates a +.Dv SIGQUIT +signal which is +sent to all processes in the foreground process group +for which the terminal is the controlling terminal. If +.Dv ISIG +is set, the +.Dv QUIT +character is discarded when +processed. +.It Dv ERASE +Special character on input and is recognized if the +.Dv ICANON +flag is set. Erases the last character in the +current line; see +.Sx "Canonical Mode Input Processing" . +It does not erase beyond +the start of a line, as delimited by an +.Dv NL , +.Dv EOF , +or +.Dv EOL +character. If +.Dv ICANON +is set, the +.Dv ERASE +character is +discarded when processed. +.It Dv KILL +Special character on input and is recognized if the +.Dv ICANON +flag is set. Deletes the entire line, as +delimited by a +.Dv NL , +.Dv EOF , +or +.Dv EOL +character. If +.Dv ICANON +is set, the +.Dv KILL +character is discarded when processed. +.It Dv EOF +Special character on input and is recognized if the +.Dv ICANON +flag is set. When received, all the bytes +waiting to be read are immediately passed to the +process, without waiting for a newline, and the +.Dv EOF +is discarded. Thus, if there are no bytes waiting (that +is, the +.Dv EOF +occurred at the beginning of a line), a byte +count of zero is returned from the read(), +representing an end-of-file indication. If +.Dv ICANON +is +set, the +.Dv EOF +character is discarded when processed. +.Dv NL +Special character on input and is recognized if the +.Dv ICANON +flag is set. It is the line delimiter +.Ql \&\en . +.It Dv EOL +Special character on input and is recognized if the +.Dv ICANON +flag is set. Is an additional line delimiter, +like +.Dv NL . +.It Dv SUSP +If the +.Dv ISIG +flag is enabled, receipt of the +.Dv SUSP +character causes a +.Dv SIGTSTP +signal to be sent to all processes in the +foreground process group for which the terminal is the +controlling terminal, and the +.Dv SUSP +character is +discarded when processed. +.It Dv STOP +Special character on both input and output and is +recognized if the +.Dv IXON +(output control) or +.Dv IXOFF +(input +control) flag is set. Can be used to temporarily +suspend output. It is useful with fast terminals to +prevent output from disappearing before it can be read. +If +.Dv IXON +is set, the +.Dv STOP +character is discarded when +processed. +.It Dv START +Special character on both input and output and is +recognized if the +.Dv IXON +(output control) or +.Dv IXOFF +(input +control) flag is set. Can be used to resume output that +has been suspended by a +.Dv STOP +character. If +.Dv IXON +is set, the +.Dv START +character is discarded when processed. +.Dv CR +Special character on input and is recognized if the +.Dv ICANON +flag is set; it is the +.Ql \&\er , +as denoted in the +.Tn \&C +Standard {2}. When +.Dv ICANON +and +.Dv ICRNL +are set and +.Dv IGNCR +is not set, this character is translated into a +.Dv NL , +and +has the same effect as a +.Dv NL +character. +.El +.Pp +The following special characters are extensions defined by this +system and are not a part of 1003.1 termios. +.Bl -tag -width indent +.It Dv EOL2 +Secondary +.Dv EOL +character. Same function as +.Dv EOL. +.It Dv WERASE +Special character on input and is recognized if the +.Dv ICANON +flag is set. Erases the last word in the current +line according to one of two algorithms. If the +.Dv ALTWERASE +flag is not set, first any preceding whitespace is +erased, and then the maximal sequence of non-whitespace +characters. If +.Dv ALTWERASE +is set, first any preceding +whitespace is erased, and then the maximal sequence +of alphabetic/underscores or non alphabetic/underscores. +As a special case in this second algorithm, the first previous +non-whitespace character is skipped in determining +whether the preceding word is a sequence of +alphabetic/undercores. This sounds confusing but turns +out to be quite practical. +.It Dv REPRINT +Special character on input and is recognized if the +.Dv ICANON +flag is set. Causes the current input edit line +to be retyped. +.It Dv DSUSP +Has similar actions to the +.Dv SUSP +character, except that +the +.Dv SIGTSTP +signal is delivered when one of the processes +in the foreground process group issues a read() to the +controlling terminal. +.It Dv LNEXT +Special character on input and is recognized if the +.Dv IEXTEN +flag is set. Receipt of this character causes the next +character to be taken literally. +.It Dv DISCARD +Special character on input and is recognized if the +.Dv IEXTEN +flag is set. Receipt of this character toggles the flushing +of terminal output. +.It Dv STATUS +Special character on input and is recognized if the +.Dv ICANON +flag is set. Receipt of this character causes a +.Dv SIGINFO +signal to be sent to the foreground process group of the +terminal. Also, if the +.Dv NOKERNINFO +flag is not set, it +causes the kernel to write a status message to the terminal +that displays the current load average, the name of the +command in the foreground, its process ID, the symbolic +wait channel, the number of user and system seconds used, +the percentage of cpu the process is getting, and the resident +set size of the process. +.El +.Pp +The +.Dv NL +and +.Dv CR +characters cannot be changed. +The values for all the remaining characters can be set and are +described later in the document under +Special Control Characters. +.Pp +Special +character functions associated with changeable special control characters +can be disabled individually by setting their value to +.Dv {_POSIX_VDISABLE}; +see +.Sx "Special Control Characters" . +.Pp +If two or more special characters have the same value, the function +performed when that character is received is undefined. +.Ss Modem Disconnect +If a modem disconnect is detected by the terminal interface for a +controlling terminal, and if +.Dv CLOCAL +is not set in the +.Fa c_cflag +field for +the terminal, the +.Dv SIGHUP +signal is sent to the controlling +process associated with the terminal. Unless other arrangements have +been made, this causes the controlling process to terminate. +Any subsequent call to the read() function returns the value zero, +indicating end of file. Thus, processes that read a terminal +file and test for end-of-file can terminate appropriately after a +disconnect. +.\" If the +.\" .Er EIO +.\" condition specified in 6.1.1.4 that applies +.\" when the implementation supports job control also exists, it is +.\" unspecified whether the +.\" .Dv EOF +.\" condition or the +.\" .Pf [ Dv EIO +.\" ] is returned. +Any +subsequent write() to the terminal device returns -1, with +.Va errno +set to +.Er EIO , +until the device is closed. +.Sh General Terminal Interface +.Pp +.Ss Closing a Terminal Device File +The last process to close a terminal device file causes any output +to be sent to the device and any input to be discarded. Then, if +.Dv HUPCL +is set in the control modes, and the communications port supports a +disconnect function, the terminal device performs a disconnect. +.Ss Parameters That Can Be Set +Routines that need to control certain terminal +.Tn I/O +characteristics +do so by using the termios structure as defined in the header +.Aq Pa termios.h . +This structure contains minimally four scalar elements of bit flags +and one array of special characters. The scalar flag elements are +named: +.Fa c_iflag , +.Fa c_oflag , +.Fa c_cflag , +and +.Fa c_lflag . +The character array is named +.Fa c_cc , +and its maximum index is +.Dv NCCS . +.Ss Input Modes +Values of the +.Fa c_iflag +field describe the basic +terminal input control, and are composed of +following masks: +.Pp +.Bl -tag -width IMAXBEL -offset indent -compact +.It Dv IGNBRK +/* ignore BREAK condition */ +.It Dv BRKINT +/* map BREAK to SIGINTR */ +.It Dv IGNPAR +/* ignore (discard) parity errors */ +.It Dv PARMRK +/* mark parity and framing errors */ +.It Dv INPCK +/* enable checking of parity errors */ +.It Dv ISTRIP +/* strip 8th bit off chars */ +.It Dv INLCR +/* map NL into CR */ +.It Dv IGNCR +/* ignore CR */ +.It Dv ICRNL +/* map CR to NL (ala CRMOD) */ +.It Dv IXON +/* enable output flow control */ +.It Dv IXOFF +/* enable input flow control */ +.It Dv IXANY +/* any char will restart after stop */ +.It Dv IMAXBEL +/* ring bell on input queue full */ +.It Dv IUCLC +/* translate upper case to lower case */ +.El +.Pp +In the context of asynchronous serial data transmission, a break +condition is defined as a sequence of zero-valued bits that continues for +more than the time to send one byte. The entire sequence of zero-valued +bits is interpreted as a single break condition, even if it continues for +a time equivalent to more than one byte. In contexts other than +asynchronous serial data transmission the definition of a break condition +is implementation defined. +.Pp +If +.Dv IGNBRK +is set, a break condition detected on input is ignored, that +is, not put on the input queue and therefore not read by any process. If +.Dv IGNBRK +is not set and +.Dv BRKINT +is set, the break condition flushes the +input and output queues and if the terminal is the controlling terminal +of a foreground process group, the break condition generates a +single +.Dv SIGINT +signal to that foreground process group. If neither +.Dv IGNBRK +nor +.Dv BRKINT +is set, a break condition is read as a single +.Ql \&\e0 , +or if +.Dv PARMRK +is set, as +.Ql \&\e377 , +.Ql \&\e0 , +.Ql \&\e0 . +.Pp +If +.Dv IGNPAR +is set, a byte with a framing or parity error (other than +break) is ignored. +.Pp +If +.Dv PARMRK +is set, and +.Dv IGNPAR +is not set, a byte with a framing or parity +error (other than break) is given to the application as the +three-character sequence +.Ql \&\e377 , +.Ql \&\e0 , +X, where +.Ql \&\e377 , +.Ql \&\e0 +is a two-character +flag preceding each sequence and X is the data of the character received +in error. To avoid ambiguity in this case, if +.Dv ISTRIP +is not set, a valid +character of +.Ql \&\e377 +is given to the application as +.Ql \&\e377 , +.Ql \&\e377 . +If +neither +.Dv PARMRK +nor +.Dv IGNPAR +is set, a framing or parity error (other than +break) is given to the application as a single character +.Ql \&\e0 . +.Pp +If +.Dv INPCK +is set, input parity checking is enabled. If +.Dv INPCK +is not set, +input parity checking is disabled, allowing output parity generation +without input parity errors. Note that whether input parity checking is +enabled or disabled is independent of whether parity detection is enabled +or disabled (see +.Sx "Control Modes" ) . +If parity detection is enabled but input +parity checking is disabled, the hardware to which the terminal is +connected recognizes the parity bit, but the terminal special file +does not check whether this bit is set correctly or not. +.Pp +If +.Dv ISTRIP +is set, valid input bytes are first stripped to seven bits, +otherwise all eight bits are processed. +.Pp +If +.Dv INLCR +is set, a received +.Dv NL +character is translated into a +.Dv CR +character. If +.Dv IGNCR +is set, a received +.Dv CR +character is ignored (not +read). If +.Dv IGNCR +is not set and +.Dv ICRNL +is set, a received +.Dv CR +character is +translated into a +.Dv NL +character. +.Pp +If +.Dv IXON +is set, start/stop output control is enabled. A received +.Dv STOP +character suspends output and a received +.Dv START +character +restarts output. If +.Dv IXANY +is also set, then any character may +restart output. When +.Dv IXON +is set, +.Dv START +and +.Dv STOP +characters are not +read, but merely perform flow control functions. When +.Dv IXON +is not set, +the +.Dv START +and +.Dv STOP +characters are read. +.Pp +If +.Dv IXOFF +is set, start/stop input control is enabled. The system shall +transmit one or more +.Dv STOP +characters, which are intended to cause the +terminal device to stop transmitting data, as needed to prevent the input +queue from overflowing and causing the undefined behavior described in +.Sx "Input Processing and Reading Data" , +and shall transmit one or more +.Dv START +characters, which are +intended to cause the terminal device to resume transmitting data, as +soon as the device can continue transmitting data without risk of +overflowing the input queue. The precise conditions under which +.Dv STOP +and +START +characters are transmitted are implementation defined. +.Pp +If +.Dv IMAXBEL +is set and the input queue is full, subsequent input shall cause an +.Tn ASCII +.Dv BEL +character to be transmitted to +the output queue. +.Pp +If +.Dv IUCLC +is set, characters will be translated from upper to lower case on +input. +.Pp +The initial input control value after open() is implementation defined. +.Ss Output Modes +Values of the +.Fa c_oflag +field describe the basic terminal output control, +and are composed of the following masks: +.Pp +.Bl -tag -width OXTABS -offset indent -compact +.It Dv OPOST +/* enable following output processing */ +.It Dv ONLCR +/* map NL to CR-NL (ala +.Dv CRMOD) +*/ +.It Dv OXTABS +/* expand tabs to spaces */ +.It Dv ONOEOT +/* discard +.Dv EOT Ns 's +.Ql \&^D +on output) */ +.It Dv OCRNL +/* map CR to NL */ +.It Dv OLCUC +/* translate lower case to upper case */ +.It Dv ONOCR +/* No CR output at column 0 */ +.It Dv ONLRET +/* NL performs CR function */ +.El +.Pp +If +.Dv OPOST +is set, the remaining flag masks are interpreted as follows; +otherwise characters are transmitted without change. +.Pp +If +.Dv ONLCR +is set, newlines are translated to carriage return, linefeeds. +.Pp +If +.Dv OXTABS +is set, tabs are expanded to the appropriate number of +spaces (assuming 8 column tab stops). +.Pp +If +.Dv ONOEOT +is set, +.Tn ASCII +.Dv EOT NS 's +are discarded on output. +.Pp +If +.Dv OCRNL +is set, carriage returns are translated to newlines. +.Pp +If +.Dv OLCUC +is set, lower case is translated to upper case on output. +.Pp +If +.Dv ONOCR +is set, no CR character is output when at column 0. +.Pp +If +.Dv ONLRET +is set, NL also performs CR on output, and reset current +column to 0. +.Ss Control Modes +Values of the +.Fa c_cflag +field describe the basic +terminal hardware control, and are composed of the +following masks. +Not all values +specified are supported by all hardware. +.Pp +.Bl -tag -width CRTSXIFLOW -offset indent -compact +.It Dv CSIZE +/* character size mask */ +.It Dv CS5 +/* 5 bits (pseudo) */ +.It Dv CS6 +/* 6 bits */ +.It Dv CS7 +/* 7 bits */ +.It Dv CS8 +/* 8 bits */ +.It Dv CSTOPB +/* send 2 stop bits */ +.It Dv CREAD +/* enable receiver */ +.It Dv PARENB +/* parity enable */ +.It Dv PARODD +/* odd parity, else even */ +.It Dv HUPCL +/* hang up on last close */ +.It Dv CLOCAL +/* ignore modem status lines */ +.It Dv CCTS_OFLOW +/* +.Dv CTS +flow control of output */ +.It Dv CRTSCTS +/* same as +.Dv CCTS_OFLOW +*/ +.It Dv CRTS_IFLOW +/* RTS flow control of input */ +.It Dv MDMBUF +/* flow control output via Carrier */ +.El +.Pp +The +.Dv CSIZE +bits specify the byte size in bits for both transmission and +reception. The +.Fa c_cflag +is masked with +.Dv CSIZE +and compared with the +values +.Dv CS5 , +.Dv CS6 , +.Dv CS7 , +or +.Dv CS8 . +This size does not include the parity bit, if any. If +.Dv CSTOPB +is set, two stop bits are used, otherwise one stop bit. For example, at +110 baud, two stop bits are normally used. +.Pp +If +.Dv CREAD +is set, the receiver is enabled. Otherwise, no character is +received. +Not all hardware supports this bit. In fact, this flag +is pretty silly and if it were not part of the +.Nm termios +specification +it would be omitted. +.Pp +If +.Dv PARENB +is set, parity generation and detection are enabled and a parity +bit is added to each character. If parity is enabled, +.Dv PARODD +specifies +odd parity if set, otherwise even parity is used. +.Pp +If +.Dv HUPCL +is set, the modem control lines for the port are lowered +when the last process with the port open closes the port or the process +terminates. The modem connection is broken. +.Pp +If +.Dv CLOCAL +is set, a connection does not depend on the state of the modem +status lines. If +.Dv CLOCAL +is clear, the modem status lines are +monitored. +.Pp +Under normal circumstances, a call to the open() function waits for +the modem connection to complete. However, if the +.Dv O_NONBLOCK +flag is set +or if +.Dv CLOCAL +has been set, the open() function returns +immediately without waiting for the connection. +.Pp +The +.Dv CCTS_OFLOW +.Pf ( Dv CRTSCTS ) +flag is currently unused. +.Pp +If +.Dv MDMBUF +is set then output flow control is controlled by the state +of Carrier Detect. +.Pp +If the object for which the control modes are set is not an asynchronous +serial connection, some of the modes may be ignored; for example, if an +attempt is made to set the baud rate on a network connection to a +terminal on another host, the baud rate may or may not be set on the +connection between that terminal and the machine it is directly connected +to. +.Ss Local Modes +Values of the +.Fa c_lflag +field describe the control of +various functions, and are composed of the following +masks. +.Pp +.Bl -tag -width NOKERNINFO -offset indent -compact +.It Dv ECHOKE +/* visual erase for line kill */ +.It Dv ECHOE +/* visually erase chars */ +.It Dv ECHO +/* enable echoing */ +.It Dv ECHONL +/* echo +.Dv NL +even if +.Dv ECHO +is off */ +.It Dv ECHOPRT +/* visual erase mode for hardcopy */ +.It Dv ECHOCTL +/* echo control chars as ^(Char) */ +.It Dv ISIG +/* enable signals +.Dv INTR , +.Dv QUIT , +.Dv [D]SUSP +*/ +.It Dv ICANON +/* canonicalize input lines */ +.It Dv ALTWERASE +/* use alternate +.Dv WERASE +algorithm */ +.It Dv IEXTEN +/* enable +.Dv DISCARD +and +.Dv LNEXT +*/ +.It Dv EXTPROC +/* external processing */ +.It Dv TOSTOP +/* stop background jobs from output */ +.It Dv FLUSHO +/* output being flushed (state) */ +.It Dv NOKERNINFO +/* no kernel output from +.Dv VSTATUS +*/ +.It Dv PENDIN +/* XXX retype pending input (state) */ +.It Dv NOFLSH +/* don't flush after interrupt */ +.El +.Pp +If +.Dv ECHO +is set, input characters are echoed back to the terminal. If +.Dv ECHO +is not set, input characters are not echoed. +.Pp +If +.Dv ECHOE +and +.Dv ICANON +are set, the +.Dv ERASE +character causes the terminal +to erase the last character in the current line from the display, if +possible. If there is no character to erase, an implementation may echo +an indication that this was the case or do nothing. +.Pp +If +.Dv ECHOK +and +.Dv ICANON +are set, the +.Dv KILL +character causes +the current line to be discarded and the system echoes the +.Ql \&\en +character after the +.Dv KILL +character. +.Pp +If +.Dv ECHOKE +and +.Dv ICANON +are set, the +.Dv KILL +character causes +the current line to be discarded and the system causes +the terminal +to erase the line from the display. +.Pp +If +.Dv ECHOPRT +and +.Dv ICANON +are set, the system assumes +that the display is a printing device and prints a +backslash and the erased characters when processing +.Dv ERASE +characters, followed by a forward slash. +.Pp +If +.Dv ECHOCTL +is set, the system echoes control characters +in a visible fashion using a caret followed by the control character. +.Pp +If +.Dv ALTWERASE +is set, the system uses an alternative algorithm +for determining what constitutes a word when processing +.Dv WERASE +characters (see +.Dv WERASE ) . +.Pp +If +.Dv ECHONL +and +.Dv ICANON +are set, the +.Ql \&\en +character echoes even if +.Dv ECHO +is not set. +.Pp +If +.Dv ICANON +is set, canonical processing is enabled. This enables the +erase and kill edit functions, and the assembly of input characters into +lines delimited by +.Dv NL, +.Dv EOF , +and +.Dv EOL, +as described in +.Sx "Canonical Mode Input Processing" . +.Pp +If +.Dv ICANON +is not set, read requests are satisfied directly from the input +queue. A read is not satisfied until at least +.Dv MIN +bytes have been +received or the timeout value +.Dv TIME +expired between bytes. The time value +represents tenths of seconds. See +.Sx "Noncanonical Mode Input Processing" +for more details. +.Pp +If +.Dv ISIG +is set, each input character is checked against the special +control characters +.Dv INTR , +.Dv QUIT , +and +.Dv SUSP +(job control only). If an input +character matches one of these control characters, the function +associated with that character is performed. If +.Dv ISIG +is not set, no +checking is done. Thus these special input functions are possible only +if +.Dv ISIG +is set. +.Pp +If +.Dv IEXTEN +is set, implementation-defined functions are recognized +from the input data. How +.Dv IEXTEN +being set +interacts with +.Dv ICANON , +.Dv ISIG , +.Dv IXON , +or +.Dv IXOFF +is implementation defined. +If +.Dv IEXTEN +is not set, then +implementation-defined functions are not recognized, and the +corresponding input characters are not processed as described for +.Dv ICANON , +.Dv ISIG , +.Dv IXON , +and +.Dv IXOFF . +.Pp +If +.Dv NOFLSH +is set, the normal flush of the input and output queues +associated with the +.Dv INTR , +.Dv QUIT , +and +.Dv SUSP +characters +are not be done. +.Pp +If +.Dv ICANON +is set, an upper case character is preserved on input if prefixed by +a \\ character. In addition, this prefix is added to upper case +characters on output. +.Pp +In addition, the following special character translations are in effect: +.Pp +.Bl -column "for:" "use:" -offset indent -compact +.It Em "for: use:" +.It Dv ` Ta \&\e' +.It Dv | Ta \&\e! +.It Dv ~ Ta \&\e^ +.It Dv { Ta \&\e( +.It Dv } Ta \&\e) +.It Dv \&\e Ta \&\e\e +.El +.Pp +If +.Dv TOSTOP +is set, the signal +.Dv SIGTTOU +is sent to the process group of a process that tries to write to +its controlling terminal if it is not in the foreground process group for +that terminal. This signal, by default, stops the members of the process +group. Otherwise, the output generated by that process is output to the +current output stream. Processes that are blocking or ignoring +.Dv SIGTTOU +signals are excepted and allowed to produce output and the +.Dv SIGTTOU +signal +is not sent. +.Pp +If +.Dv NOKERNINFO +is set, the kernel does not produce a status message +when processing +.Dv STATUS +characters (see +.Dv STATUS ) . +.Ss Special Control Characters +The special control characters values are defined by the array +.Fa c_cc . +This table lists the array index, the corresponding special character, +and the system default value. For an accurate list of +the system defaults, consult the header file +.Aq Pa ttydefaults.h . +.Pp +.Bl -column "Index Name" "Special Character" -offset indent -compact +.It Em "Index Name Special Character Default Value" +.It Dv VEOF Ta EOF Ta \&^D +.It Dv VEOL Ta EOL Ta _POSIX_VDISABLE +.It Dv VEOL2 Ta EOL2 Ta _POSIX_VDISABLE +.It Dv VERASE Ta ERASE Ta \&^? Ql \&\e177 +.It Dv VWERASE Ta WERASE Ta \&^W +.It Dv VKILL Ta KILL Ta \&^U +.It Dv VREPRINT Ta REPRINT Ta \&^R +.It Dv VINTR Ta INTR Ta \&^C +.It Dv VQUIT Ta QUIT Ta \&^\e\e Ql \&\e34 +.It Dv VSUSP Ta SUSP Ta \&^Z +.It Dv VDSUSP Ta DSUSP Ta \&^Y +.It Dv VSTART Ta START Ta \&^Q +.It Dv VSTOP Ta STOP Ta \&^S +.It Dv VLNEXT Ta LNEXT Ta \&^V +.It Dv VDISCARD Ta DISCARD Ta \&^O +.It Dv VMIN Ta --- Ta \&1 +.It Dv VTIME Ta --- Ta \&0 +.It Dv VSTATUS Ta STATUS Ta \&^T +.El +.Pp +If the +value of one of the changeable special control characters (see +.Sx "Special Characters" ) +is +.Dv {_POSIX_VDISABLE} , +that function is disabled; that is, no input +data is recognized as the disabled special character. +If +.Dv ICANON +is +not set, the value of +.Dv {_POSIX_VDISABLE} +has no special meaning for the +.Dv VMIN +and +.Dv VTIME +entries of the +.Fa c_cc +array. +.Pp +The initial values of the flags and control characters +after open() is set according to +the values in the header +.Aq Pa sys/ttydefaults.h . +.Sh SEE ALSO +.Xr tcgetattr 3 , +.Xr tcsetattr 3 diff --git a/bsd/man/man4/tty.4 b/bsd/man/man4/tty.4 new file mode 100644 index 000000000..f8177dc05 --- /dev/null +++ b/bsd/man/man4/tty.4 @@ -0,0 +1,397 @@ +.\" Copyright (c) 1991, 1992, 1993 +.\" 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.4 8.3 (Berkeley) 4/19/94 +.\" $FreeBSD$ +.\" +.Dd August 14, 1992 +.Dt TTY 4 +.Os BSD 4 +.Sh NAME +.Nm tty +.Nd general terminal interface +.Sh SYNOPSIS +.Fd #include +.Sh DESCRIPTION +This section describes the interface to the terminal drivers +in the system. +.Ss Terminal Special Files +Each hardware terminal port on the system usually has a terminal special device +file associated with it in the directory ``/dev/'' (for +example, ``/dev/tty03''). +When a user logs into +the system on one of these hardware terminal ports, the system has already +opened the associated device and prepared the line for normal interactive +use (see +.Xr getty 8 .) +There is also a special case of a terminal file that connects not to +a hardware terminal port, but to another program on the other side. +These special terminal devices are called +.Em ptys +and provide the mechanism necessary to give users the same interface to the +system when logging in over a network (using +.Xr rlogin 1 , +or +.Xr telnet 1 +for example). Even in these cases the details of how the terminal +file was opened and set up is already handled by special software +in the system. +Thus, users do not normally need to worry about the details of +how these lines are opened or used. Also, these lines are often used +for dialing out of a system (through an out-calling modem), but again +the system provides programs that hide the details of accessing +these terminal special files (see +.Xr tip 1 ). +.Pp +When an interactive user logs in, the system prepares the line to +behave in a certain way (called a +.Em "line discipline" ) , +the particular details of which is described in +.Xr stty 1 +at the command level, and in +.Xr termios 4 +at the programming level. A user may be concerned with changing +settings associated with his particular login terminal and should refer +to the preceding man pages for the common cases. The remainder of +this man page is concerned +with describing details of using and controlling terminal devices +at a low level, such as that possibly required by a program wishing +to provide features similar to those provided by the system. +.Ss Line disciplines +A terminal file is used like any other file in the system in that +it can be opened, read, and written to using standard system +calls. For each existing terminal file, there is a software processing module +called a +.Em "line discipline" +is associated with it. The +.Em "line discipline" +essentially glues the low level device driver code with the high +level generic interface routines (such as +.Xr read 2 +and +.Xr write 2 ), +and is responsible for implementing the semantics associated +with the device. When a terminal file is first opened by a program, +the default +.Em "line discipline" +called the +.Dv termios +line discipline is associated with the file. This is the primary +line discipline that is used in most cases and provides the semantics +that users normally associate with a terminal. When the +.Dv termios +line discipline is in effect, the terminal file behaves and is +operated according to the rules described in +.Xr termios 4 . +Please refer to that man page for a full description of the terminal +semantics. +The operations described here +generally represent features common +across all +.Em "line disciplines" , +however some of these calls may not +make sense in conjunction with a line discipline other than +.Dv termios , +and some may not be supported by the underlying +hardware (or lack thereof, as in the case of ptys). +.Ss Terminal File Operations +All of the following operations are invoked using the +.Xr ioctl 2 +system call. Refer to that man page for a description of +the +.Em request +and +.Em argp +parameters. +In addition to the ioctl +.Em requests +defined here, the specific line discipline +in effect will define other +.Em requests +specific to it (actually +.Xr termios 4 +defines them as function calls, not ioctl +.Em requests . ) +The following section lists the available ioctl requests. The +name of the request, a description of its purpose, and the typed +.Em argp +parameter (if any) +are listed. For example, the first entry says +.Pp +.D1 Em "TIOCSETD int *ldisc" +.Pp +and would be called on the terminal associated with +file descriptor zero by the following code fragment: +.Bd -literal + int ldisc; + + ldisc = TTYDISC; + ioctl(0, TIOCSETD, &ldisc); +.Ed +.Ss Terminal File Request Descriptions +.Bl -tag -width TIOCGWINSZ +.It Dv TIOCSETD Fa int *ldisc +Change to the new line discipline pointed to by +.Fa ldisc . +The available line disciplines are listed in +.Pa Aq sys/ttycom.h +and currently are: +.Pp +.Bl -tag -width TIOCGWINSZ -compact +.It TTYDISC +Termios interactive line discipline. +.It TABLDISC +Tablet line discipline. +.It SLIPDISC +Serial IP line discipline. +.It PPPDISC +PPP line discipline. +.El +.Pp +.It Dv TIOCGETD Fa int *ldisc +Return the current line discipline in the integer pointed to by +.Fa ldisc . +.It Dv TIOCSBRK Fa void +Set the terminal hardware into BREAK condition. +.It Dv TIOCCBRK Fa void +Clear the terminal hardware BREAK condition. +.It Dv TIOCSDTR Fa void +Assert data terminal ready (DTR). +.It Dv TIOCCDTR Fa void +Clear data terminal ready (DTR). +.It Dv TIOCGPGRP Fa int *tpgrp +Return the current process group the terminal is associated +with in the integer pointed to by +.Fa tpgrp . +This is the underlying call that implements the +.Xr termios 4 +.Fn tcgetattr +call. +.It Dv TIOCSPGRP Fa int *tpgrp +Associate the terminal with the process group (as an integer) pointed to by +.Fa tpgrp . +This is the underlying call that implements the +.Xr termios 4 +.Fn tcsetattr +call. +.It Dv TIOCGETA Fa struct termios *term +Place the current value of the termios state associated with the +device in the termios structure pointed to by +.Fa term . +This is the underlying call that implements the +.Xr termios 4 +.Fn tcgetattr +call. +.It Dv TIOCSETA Fa struct termios *term +Set the termios state associated with the device immediately. +This is the underlying call that implements the +.Xr termios 4 +.Fn tcsetattr +call with the +.Dv TCSANOW +option. +.It Dv TIOCSETAW Fa struct termios *term +First wait for any output to complete, then set the termios state +associated with the device. +This is the underlying call that implements the +.Xr termios 4 +.Fn tcsetattr +call with the +.Dv TCSADRAIN +option. +.It Dv TIOCSETAF Fa struct termios *term +First wait for any output to complete, clear any pending input, +then set the termios state associated with the device. +This is the underlying call that implements the +.Xr termios 4 +.Fn tcsetattr +call with the +.Dv TCSAFLUSH +option. +.It Dv TIOCOUTQ Fa int *num +Place the current number of characters in the output queue in the +integer pointed to by +.Fa num . +.It Dv TIOCSTI Fa char *cp +Simulate typed input. Pretend as if the terminal received the +character pointed to by +.Fa cp . +.It Dv TIOCNOTTY Fa void +This call is obsolete but left for compatibility. In the past, when +a process that didn't have a controlling terminal (see +.Em The Controlling Terminal +in +.Xr termios 4 ) +first opened a terminal device, it acquired that terminal as its +controlling terminal. For some programs this was a hazard as they +didn't want a controlling terminal in the first place, and this +provided a mechanism to disassociate the controlling terminal from +the calling process. It +.Em must +be called by opening the file +.Pa /dev/tty +and calling +.Dv TIOCNOTTY +on that file descriptor. +.Pp +The current system does not allocate a controlling terminal to +a process on an +.Fn open +call: there is a specific ioctl called +.Dv TIOSCTTY +to make a terminal the controlling +terminal. +In addition, a program can +.Fn fork +and call the +.Fn setsid +system call which will place the process into its own session - which +has the effect of disassociating it from the controlling terminal. This +is the new and preferred method for programs to lose their controlling +terminal. +.It Dv TIOCSTOP Fa void +Stop output on the terminal (like typing ^S at the keyboard). +.It Dv TIOCSTART Fa void +Start output on the terminal (like typing ^Q at the keyboard). +.It Dv TIOCSCTTY Fa void +Make the terminal the controlling terminal for the process (the process +must not currently have a controlling terminal). +.It Dv TIOCDRAIN Fa void +Wait until all output is drained. +.It Dv TIOCEXCL Fa void +Set exclusive use on the terminal. No further opens are permitted +except by root. Of course, this means that programs that are run by +root (or setuid) will not obey the exclusive setting - which limits +the usefulness of this feature. +.It Dv TIOCNXCL Fa void +Clear exclusive use of the terminal. Further opens are permitted. +.It Dv TIOCFLUSH Fa int *what +If the value of the int pointed to by +.Fa what +contains the +.Dv FREAD +bit as defined in +.Pa Aq sys/file.h , +then all characters in the input queue are cleared. If it contains +the +.Dv FWRITE +bit, then all characters in the output queue are cleared. If the +value of the integer is zero, then it behaves as if both the +.Dv FREAD +and +.Dv FWRITE +bits were set (i.e. clears both queues). +.It Dv TIOCGWINSZ Fa struct winsize *ws +Put the window size information associated with the terminal in the +.Va winsize +structure pointed to by +.Fa ws . +The window size structure contains the number of rows and columns (and pixels +if appropriate) of the devices attached to the terminal. It is set by user software +and is the means by which most full\&-screen oriented programs determine the +screen size. The +.Va winsize +structure is defined in +.Pa Aq sys/ioctl.h . +.It Dv TIOCSWINSZ Fa struct winsize *ws +Set the window size associated with the terminal to be the value in +the +.Va winsize +structure pointed to by +.Fa ws +(see above). +.It Dv TIOCCONS Fa int *on +If +.Fa on +points to a non-zero integer, redirect kernel console output (kernel printf's) +to this terminal. +If +.Fa on +points to a zero integer, redirect kernel console output back to the normal +console. This is usually used on workstations to redirect kernel messages +to a particular window. +.It Dv TIOCMSET Fa int *state +The integer pointed to by +.Fa state +contains bits that correspond to modem state. Following is a list +of defined variables and the modem state they represent: +.Pp +.Bl -tag -width TIOCMXCTS -compact +.It TIOCM_LE +Line Enable. +.It TIOCM_DTR +Data Terminal Ready. +.It TIOCM_RTS +Request To Send. +.It TIOCM_ST +Secondary Transmit. +.It TIOCM_SR +Secondary Receive. +.It TIOCM_CTS +Clear To Send. +.It TIOCM_CAR +Carrier Detect. +.It TIOCM_CD +Carrier Detect (synonym). +.It TIOCM_RNG +Ring Indication. +.It TIOCM_RI +Ring Indication (synonym). +.It TIOCM_DSR +Data Set Ready. +.El +.Pp +This call sets the terminal modem state to that represented by +.Fa state . +Not all terminals may support this. +.It Dv TIOCMGET Fa int *state +Return the current state of the terminal modem lines as represented +above in the integer pointed to by +.Fa state . +.It Dv TIOCMBIS Fa int *state +The bits in the integer pointed to by +.Fa state +represent modem state as described above, however the state is OR-ed +in with the current state. +.It Dv TIOCMBIC Fa int *state +The bits in the integer pointed to by +.Fa state +represent modem state as described above, however each bit which is on +in +.Fa state +is cleared in the terminal. +.El +.Sh SEE ALSO +.Xr stty 1 , +.Xr ioctl 2 , +.Xr pty 4 , +.Xr termios 4 , +.Xr getty 8 diff --git a/bsd/man/man4/tun.4 b/bsd/man/man4/tun.4 new file mode 100644 index 000000000..60ecbb06a --- /dev/null +++ b/bsd/man/man4/tun.4 @@ -0,0 +1,361 @@ +.\" $OpenBSD: tun.4,v 1.2 1996/12/16 16:08:52 deraadt Exp $ +.Dd March 10, 1996 +.Dt TUN 4 +.Os OpenBSD 1.2 +.Sh NAME +.Nm tun +.Nd Tunnel Network Interface +.Sh SYNOPSIS +.Cd "pseudo-device tun 4" +.Sh DESCRIPTION +The +.Nm tun +interface is a software loopback mechanism that can be loosely +described as the network interface analog of the +.Xr pty 4 , +that is, +.Nm tun +does for network interfaces what the +.Nm pty +driver does for terminals. +.Pp +The +.Nm tun +driver, like the +.Nm pty +driver, provides two interfaces: an interface like the usual facility +it is simulating (a network interface in the case of +.Nm tun , +or a terinal for +.Nm pty ) , +and a character-special device +.Dq control +interface. +.Pp +The network interfaces are named +.Sy tun Ns Ar 0 , +.Sy tun Ns Ar 1 , +etc, as many in all as the +.Ar count +figure given on the +.Sy pseudo-device +line. Each one supports the usual network-interface +.Xr ioctl 2 Ns s , +such as +.Dv SIOCSIFADDR +and +.Dv SIOCSIFNETMASK , +and thus can be used with +.Xr ifconfig 8 +like any other interface. At boot time, they are +.Dv POINTOPOINT +interfaces, but this can be changed; see the description of the control +device, below. When the system chooses to transmit a packet on the +network interface, the packet can be read from the control device (it +appears as +.Dq input +there); writing a packet to the control device generates an input +packet on the network interface, as if the (nonexistent) hardware had +just received it. +.Pp +There are two control interfaces. The +.Em data +interface, normally +.Pa /dev/tun Ns Sy N , +is exclusive-open (it cannot be opened if it is already open), is +normally restricted to the super-user, and can +.Dq transmit +and +.Dq receive +packets. The +.Em control +interface, normally +.Pa /dev/tunc Ns Sy N , +cannot send and receive packets, but can be opened by many processes at +once; it is intended for status queries and changes (many of which can +also be implemented with +.Fn ioctl +calls on the data interface). There are a number of status bits that +can be set or cleared via the control interfaces; they are mentioned +below where applicable, and they are all summarized in the discussions +of the control interfaces. +.\" Why isn't .Ss documented in mdoc(7) and mdoc.samples(7)? +.Ss The data interface +The data interface supports +.Xr read 2 , +.Xr write 2 , +and +.Xr ioctl 2 +calls to, respectively, collect +.Dq output +packets, generate +.Dq input +packets, and perform control functions. As mentioned above, this +interface is exclusive-open; if the +.Dv SUONLY +bit is set (which it is by default), it cannot be opened at all except +by the super-user. By default, a +.Fn read +call will return an error +.Pf ( Er EHOSTDOWN ) +if the interface is not +.Dq ready +(which means that the control device is open and the interface's +address has been set); if preferred, the +.Dv RRWAIT +bit can be set, in which case a +.Fn read +call will block (even if non-blocking I/O has been enabled) until the +interface is ready. Once the interface is ready, +.Fn read +will return a packet if one is available; if not, it will either block +until one is or return +.Er EWOULDBLOCK , +depending on whether non-blocking I/O has been enabled. If the packet +is longer than is allowed for in the buffer passed to +.Fn read , +the extra data will be silently dropped. +.Pp +The first byte of data will always be the address family (eg, +.Dv AF_INET ) +of the packet. By default, the packet data follows immediately, but if +the +.Dv PREPADDR +bit is set, the address to which the packet is to be sent is placed +after the address family byte and before the packet data. The size and +layout of the address depends on the address family; for +.Dv AF_INET , +for example, it is a +.Va struct in_addr . +A +.Xr write 2 +call passes a packet in to be +.Dq received +on the pseudo-interface. Each +.Fn write +call supplies exactly one packet; the packet length is taken from the +amount of data provided to +.Fn write . +The first byte must be the address family of the packet, much as in +packets returned by +.Fn read ; +the packet data always follows immediately. +A large number of +.Xr ioctl 2 +calls are also supported. They are defined in +.Aq Pa net/if_tun.h Ns . +.Bl -tag -width TUN_PREPADDR +.It Dv TUNSDEBUG +The argument should be a pointer to an +.Va int ; +this sets the internal debugging variable to that value. What, if +anything, this variable controls is not documented here; see the source +code. +.It Dv TUNGDEBUG +The argument should be a pointer to an +.Va int ; +this stores the internal debugging variable's value into it. +.It Dv TUNSMODE +The argument should be a pointer to an +.Va int ; +its value must be +.Dv IFF_POINTOPOINT +or +.Dv IFF_BROADCAST . +The type of the corresponding +.Em tun Ns Sy n +interface is set to the supplied type. If the value is anything else, +an +.Er EINVAL +error occurs. The interface must be down at the time; if it is up, an +.Er EBUSY +error occurs. +.\" X .It Dv TUNSFLAG +.\" X The interface's flag bits are set as specified in the +.\" X .Va int +.\" X argument. Only some of the bits can be modified; the rest are +.\" X read-only. The bits are defined in +.\" X .Aq Pa net/if_tun.h +.\" X with a +.\" X .Dv TUN_ +.\" X prefix; for example, the bit called +.\" X .Dv RRWAIT +.\" X in this document would be referred to in source code as +.\" X .Dv TUN_RRWAIT . +.\" X The bits are: +.\" X .\" Why isn't the way to create a table like this documented in mdoc(7) +.\" X .\" or mdoc.samples(7)?! +.\" X .Bl -column "TUN_PREPADDR" "RO/RW" -compact -indent-two +.\" X .It Name Ta RO/RW Ta Meaning +.\" X .It Dv TUN_OPEN Ta RO Ta "Data control device is open." +.\" X .It Dv TUN_INITED Ta RO Ta "Initialized." +.\" X .It Dv TUN_RCOLL Ta RO Ta "Select-for-read collision." +.\" X .It Dv TUN_IASET Ta RO Ta "Address has been set." +.\" X .It Dv TUN_DSTADDR Ta RO Ta "Destination address has been set." +.\" X .It Dv TUN_RWAIT Ta RO Ta "A process is blocked in Fn read Ns ." +.\" X .It Dv TUN_ASYNC Ta RO Ta "Generate Dv SIGIO No for readers." +.\" X .It Dv TUN_NBIO Ta RO Ta "Non-blocking I/O for reads." +.\" X .It Dv TUN_BRDADDR Ta RO Ta "Broadcast address has been set." +.\" X .It Dv TUN_PREPADDR Ta RW Ta "Prepend sent-to address for reads." +.\" X .It Dv TUN_STAYUP Ta RW Ta "Don't take interface down on close." +.\" X .It Dv TUN_SUONLY Ta RW Ta "Data control device is super-user only." +.\" X .It Dv TUN_RRWAIT Ta RW Ta "Wait for ready when reading." +.\" X .El +.\" X .It Dv TUNGFLAG +.\" X The interface's flag bits are fetched into the argument +.\" X .Va int . +.\" X The flags and their meanings are as for +.\" X .Dv TUNSFLAG . +.\" X .It Dv FIONBIO +.\" X Turn non-blocking I/O for reads off or on, according as the argument +.\" X .Va int Ns 's +.\" X value is or isn't zero. (Writes are always nonblocking.) +.\" X .It Dv FIOASYNC +.\" X Turn asynchronous I/O for reads (ie, generation of +.\" X .Dv SIGIO +.\" X when data is available to be read) off or on, according as the argument +.\" X .Va int Ns 's +.\" X value is or isn't zero. +.\" X .It Dv FIONREAD +.\" X If any packets are queued to be read, store the size of the first one +.\" X into the argument +.\" X .Va int ; +.\" X otherwise, store zero. +.\" X .It Dv TIOCSPGRP +.\" X Set the process group to receive +.\" X .Dv SIGIO +.\" X signals, when asynchronous I/O is enabled, to the argument +.\" X .Va int +.\" X value. +.\" X .It Dv TIOCGPGRP +.\" X Retrieve the process group value for +.\" X .Dv SIGIO +.\" X signals into the argument +.\" X .Va int +.\" X value. +.El +The data control device also supports +.Xr select 2 +for read; selecting for write is pointless, and always succeeds, since +writes are always nonblocking (if the packet cannot be accepted for a +transient reason (eg, no buffer space available), it is silently +dropped; if the reason is not transient (eg, packet too large), an +error is returned). +.Pp +On the last close of the data device, by default, the interface is +brought down (as if with +.Dq ifconfig tun Ns Sy n down ) ; +if the +.Dv STAYUP +bit is set, this is not done. In either case, all queued packets are +thrown away. (If the interface is up when the data device is not open, +either because of +.Dv STAYUP +or because it was explicitly brought up, output packets are always +thrown away rather than letting them pile up.) +.Ss The control interface +The alternative control interface is a text-based interface designed +for shell-script or human use; it allows control of many of the things +that can be done with +.Fn ioctl +calls on the data interface, and a few more as well. +.Pp +.Fn read Ns s +on the control interface always return a single line of text (or just +the beginning of the line, if the buffer passed to +.Xr read 2 +was too small to take the whole line). The line contains items in the +general format +.Do +.Li item=value +.Dc , +where +.Li item +is a keyword and +.Li value +is a value appropriate to the keyword. This line is intended for human +use; programs should use the +.Fn ioctl +interface. Here is an actual example (broken because of width +restrictions): +.Bd -literal +unit=0 flags=(open,inited,!rcoll,iaset,!dstaddr,!rwait,!async, +!nbio,!brdaddr,prepaddr,stayup,suonly,rrwait) type=broadcast +mtu=1500 coll=0 ipkts=0/0 opkts=0/0 pgrp=0 +.Ed +.Pp +Note that the current file offset is ignored for reads, so using a tool like +.Xr cat 1 +will result in infinite output. Use something more like +.Dq head\ \&-1 +for command-line use. It is possible to +.Xr select 2 +for reading on this device, which will indicate that the device is +readable whenever the state is changed. +.Pp +Writes to the control interface are interpreted as modifications to the +state. Each +.Fn write +call is treated separately. The data written is broken at whitespace +(blanks, tabs, newlines); each resulting fragment has its first +character examined. If this character is a +.Ql \&+ +or +.Ql \&\- , +the rest of the fragment is taken as a flag name, and the flag is +turned on (for +.Ql \&+ ) +or off (for +.Ql \&\- ) . +(Flag names are as generated on reads; they are the same as the +.Dv TUN_ Ns Em xxx +constants, with the leading +.Dv TUN_ +removed and the rest lowercased.) If the first character is +.Ql t , +the second character must be +.Ql b +or +.Ql p , +and the interface type is set to +.Dv IFF_BROADCAST +or +.Dv IFF_POINTOPOINT , +respectively. If the first character is +.Ql g +or +.Ql m , +the rest of the fragment is taken as a number in decimal (possibly with +a leading \&\- sign) and the result is taken as a new process group, +for +.Ql g +or MTU, for +.Ql m . +(The MTU must not be less than 1; attempts to set it so return +.Er EIO . ) +.Pp +This interface is useful for command-line reconfiguration, such as +setting the interface type at boot time, with +.Sh SEE ALSO +.Xr intro 4 , +.Xr inet 4 +.Sh BUGS +The +.Dv SUONLY +bit is a botch, especially since the control interface, which is never +restricted by the kernel, can change it. Access control really should +be handled by the permission bits on the +.Pa /dev +entries for the data and control devices; this bit is a historical +artifact. +.Pp +The process-group values for +.Dv SIGIO +signals should be checked; as it stands, the driver can be used (by +anyone who can open the control or data device) to send any desired +signal to an arbitrary process or process group. (Until this is fixed, +you should be careful to set the permisison bits to allow only root to +open the control device, and either do the same for the data device or +leave the +.Dv SUONLY +bit set.) diff --git a/bsd/man/man4/udp.4 b/bsd/man/man4/udp.4 new file mode 100644 index 000000000..5e8f7eae3 --- /dev/null +++ b/bsd/man/man4/udp.4 @@ -0,0 +1,139 @@ +.\" $NetBSD: udp.4,v 1.3 1994/11/30 16:22:41 jtc Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)udp.4 8.1 (Berkeley) 6/5/93 +.\" +.Dd June 5, 1993 +.Dt UDP 4 +.Os BSD 4.2 +.Sh NAME +.Nm udp +.Nd Internet User Datagram Protocol +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn socket AF_INET SOCK_DGRAM 0 +.Sh DESCRIPTION +.Tn UDP +is a simple, unreliable datagram protocol which is used +to support the +.Dv SOCK_DGRAM +abstraction for the Internet +protocol family. +.Tn UDP +sockets are connectionless, and are +normally used with the +.Xr sendto +and +.Xr recvfrom +calls, though the +.Xr connect 2 +call may also be used to fix the destination for future +packets (in which case the +.Xr recv 2 +or +.Xr read 2 +and +.Xr send 2 +or +.Xr write 2 +system calls may be used). +.Pp +.Tn UDP +address formats are identical to those used by +.Tn TCP . +In particular +.Tn UDP +provides a port identifier in addition +to the normal Internet address format. Note that the +.Tn UDP +port +space is separate from the +.Tn TCP +port space (i.e. a +.Tn UDP +port +may not be +.Dq connected +to a +.Tn TCP +port). In addition broadcast +packets may be sent (assuming the underlying network supports +this) by using a reserved +.Dq broadcast address ; +this address +is network interface dependent. +.Pp +Options at the +.Tn IP +transport level may be used with +.Tn UDP ; +see +.Xr ip 4 . +.Sh DIAGNOSTICS +A socket operation may fail with one of the following errors returned: +.Bl -tag -width [EADDRNOTAVAIL] +.It Bq Er EISCONN +when trying to establish a connection on a socket which +already has one, or when trying to send a datagram with the destination +address specified and the socket is already connected; +.It Bq Er ENOTCONN +when trying to send a datagram, but +no destination address is specified, and the socket hasn't been +connected; +.It Bq Er ENOBUFS +when the system runs out of memory for +an internal data structure; +.It Bq Er EADDRINUSE +when an attempt +is made to create a socket with a port which has already been +allocated; +.It Bq Er EADDRNOTAVAIL +when an attempt is made to create a +socket with a network address for which no network interface +exists. +.El +.Sh SEE ALSO +.Xr getsockopt 2 , +.Xr recv 2 , +.Xr send 2 , +.Xr socket 2 , +.Xr intro 4 , +.Xr inet 4 , +.Xr ip 4 +.Sh HISTORY +The +.Nm +protocol appeared in +.Bx 4.2 . diff --git a/bsd/man/man4/unix.4 b/bsd/man/man4/unix.4 new file mode 100644 index 000000000..db8816b6e --- /dev/null +++ b/bsd/man/man4/unix.4 @@ -0,0 +1,163 @@ +.\" $NetBSD: unix.4,v 1.3 1994/11/30 16:22:43 jtc Exp $ +.\" +.\" Copyright (c) 1991, 1993 +.\" 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. +.\" +.\" @(#)unix.4 8.1 (Berkeley) 6/9/93 +.\" +.Dd June 9, 1993 +.Dt UNIX 4 +.Os +.Sh NAME +.Nm unix +.Nd UNIX-domain protocol family +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Sh DESCRIPTION +The +.Tn UNIX Ns -domain +protocol family is a collection of protocols +that provides local (on-machine) interprocess +communication through the normal +.Xr socket 2 +mechanisms. +The +.Tn UNIX Ns -domain +family supports the +.Dv SOCK_STREAM +and +.Dv SOCK_DGRAM +socket types and uses +filesystem pathnames for addressing. +.Sh ADDRESSING +.Tn UNIX Ns -domain +addresses are variable-length filesystem pathnames of +at most 104 characters. +The include file +.Aq Pa sys/un.h +defines this address: +.Bd -literal -offset indent +struct sockaddr_un { + u_char sun_len; + u_char sun_family; + char sun_path[104]; +}; +.Ed +.Pp +Binding a name to a +.Tn UNIX Ns -domain +socket with +.Xr bind 2 +causes a socket file to be created in the filesystem. +This file is +.Em not +removed when the socket is closed\(em\c +.Xr unlink 2 +must be used to remove the file. +.Pp +The +.Tn UNIX Ns -domain +protocol family does not support broadcast addressing or any form +of +.Dq wildcard +matching on incoming messages. +All addresses are absolute- or relative-pathnames +of other +.Tn UNIX Ns -domain +sockets. +Normal filesystem access-control mechanisms are also +applied when referencing pathnames; e.g., the destination +of a +.Xr connect 2 +or +.Xr sendto 2 +must be writable. +.Sh PROTOCOLS +The +.Tn UNIX Ns -domain +protocol family is comprised of simple +transport protocols that support the +.Dv SOCK_STREAM +and +.Dv SOCK_DGRAM +abstractions. +.Dv SOCK_STREAM +sockets also support the communication of +.Ux +file descriptors through the use of the +.Ar msg_control +field in the +.Ar msg +argument to +.Xr sendmsg 2 +and +.Xr recvmsg 2 . +.Pp +Any valid descriptor may be sent in a message. +The file descriptor(s) to be passed are described using a +.Ar struct cmsghdr +that is defined in the include file +.Aq Pa sys/socket.h . +The type of the message is +.Dv SCM_RIGHTS , +and the data portion of the messages is an array of integers +representing the file descriptors to be passed. +The number of descriptors being passed is defined +by the length field of the message; +the length field is the sum of the size of the header +plus the size of the array of file descriptors. +.Pp +The received descriptor is a +.Em duplicate +of the sender's descriptor, as if it were created with a call to +.Xr dup 2 . +Per-process descriptor flags, set with +.Xr fcntl 2 , +are +.Em not +passed to a receiver. +Descriptors that are awaiting delivery, or that are +purposely not received, are automatically closed by the system +when the destination socket is closed. +.Sh SEE ALSO +.Xr socket 2 , +.Xr intro 4 +.Rs +.%T "An Introductory 4.3 BSD Interprocess Communication Tutorial" +.%B PS1 +.%N 7 +.Re +.Rs +.%T "An Advanced 4.3 BSD Interprocess Communication Tutorial" +.%B PS1 +.%N 8 +.Re diff --git a/bsd/man/man4/urandom.4 b/bsd/man/man4/urandom.4 new file mode 100644 index 000000000..b95979fa8 --- /dev/null +++ b/bsd/man/man4/urandom.4 @@ -0,0 +1 @@ +.so man4/random.4 diff --git a/bsd/man/man5/Makefile b/bsd/man/man5/Makefile new file mode 100644 index 000000000..0780eadfa --- /dev/null +++ b/bsd/man/man5/Makefile @@ -0,0 +1,24 @@ +export MakeInc_cmd=${SRCROOT}/makedefs/MakeInc.cmd +export MakeInc_def=${SRCROOT}/makedefs/MakeInc.def +export MakeInc_rule=${SRCROOT}/makedefs/MakeInc.rule +export MakeInc_dir=${SRCROOT}/makedefs/MakeInc.dir + +include $(MakeInc_cmd) +include $(MakeInc_def) + +DATAFILES = \ + acct.5 \ + core.5 \ + dir.5 \ + dirent.5 \ + fs.5 \ + inode.5 \ + types.5 + +INSTALL_MAN_LIST = ${DATAFILES} + +INSTALL_MAN_DIR = man5 + +include $(MakeInc_rule) +include $(MakeInc_dir) + diff --git a/bsd/man/man5/acct.5 b/bsd/man/man5/acct.5 new file mode 100644 index 000000000..64745330b --- /dev/null +++ b/bsd/man/man5/acct.5 @@ -0,0 +1,114 @@ +.\" $NetBSD: acct.5,v 1.4 1995/10/22 01:40:10 ghudson Exp $ +.\" +.\" Copyright (c) 1991, 1993 +.\" 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.5 8.1 (Berkeley) 6/5/93 +.\" +.Dd June 5, 1993 +.Dt ACCT 5 +.Os +.Sh NAME +.Nm acct +.Nd execution accounting file +.Sh SYNOPSIS +.Fd #include +.Sh DESCRIPTION +The kernel maintains the following +.Fa acct +information structure for all +processes. If a process terminates, and accounting is enabled, +the kernel calls the +.Xr acct 2 +function call to prepare and append the record +to the accounting file. +.Bd -literal +/* + * 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]; /* name of command */ + 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; /* memory usage average */ + 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 +.Ed +.Pp +If a terminated process was created by an +.Xr execve 2 , +the name of the executed file (at most ten characters of it) +is saved in the field +.Fa ac_comm +and its status is saved by setting one of more of the following flags in +.Fa ac_flag: +.Dv AFORK , +.Dv ASU , +.Dv ACOMPAT , +.Dv ACORE +and +.Dv ASIG . +.Sh SEE ALSO +.Xr acct 2 , +.Xr accton 8 , +.Xr execve 2 , +.Xr lastcomm 1 , +.Xr sa 8 +.Sh HISTORY +A +.Nm +file format appeared in +.At v7 . diff --git a/bsd/man/man5/core.5 b/bsd/man/man5/core.5 new file mode 100644 index 000000000..097ce4f34 --- /dev/null +++ b/bsd/man/man5/core.5 @@ -0,0 +1,60 @@ +.\""Copyright (c) 2001 Apple Computer, Inc. All Rights Reserved. +.\"The contents of this file constitute Original Code as defined in and are +.\"subject to the Apple Public Source License Version 1.2 (the 'License'). +.\"You may not use this file except in compliance with the +.\"License. Please obtain a copy of the License at +.\"http://www.apple.com/publicsource and read it before using this file. +.\" +.\"This Original Code and all software distributed under the License are +.\"distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +.\"EXPRESS OR IMPLIED, AND APPLE +.\"HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY +.\"WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, +.\"QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the +.\"specific language governing rights and limitations under the License." +.Dd March 18, 2002 +.Dt CORE 5 +.Os +.Sh NAME +.Nm core +.Nd memory image file format +.Sh SYNOPSIS +.In sys/param.h +.Sh DESCRIPTION +A small number of signals which cause abnormal termination of a process +also cause a record of the process's in-core state to be written +to disk for later examination by one of the available debuggers. +(See +.Xr sigaction 2 . ) +This memory image is written to a file named by default +.Nm core.pid +in the +.Nm /cores +directory; +provided the terminated process had write permission in the directory, +and the directory existed. +.Pp +The maximum size of a core file is limited by +.Xr setrlimit 2 . +Files which would be larger than the limit are not created. +.Pp +The core file consists of the +.Pa Xr Mach-O 5 +header as described in the +.Aq Pa sys/loader.h +file. +The remainder of the core +file consists of various sections described in the +.Xr Mach-O 5 +header. +.Sh SEE ALSO +.Xr gdb 1 , +.Xr setrlimit 2 , +.Xr sigaction 2 , +.Xr Mach-O 5, +.Xr sysctl 8 +.Sh HISTORY +A +.Nm +file format appeared in +.At v6 . diff --git a/bsd/man/man5/dir.5 b/bsd/man/man5/dir.5 new file mode 100644 index 000000000..d852d0c86 --- /dev/null +++ b/bsd/man/man5/dir.5 @@ -0,0 +1,153 @@ +.\" $NetBSD: dir.5,v 1.5 1995/03/28 17:30:20 jtc Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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.5 8.3 (Berkeley) 4/19/94 +.\" +.Dd April 19, 1994 +.Dt DIR 5 +.Os BSD 4.2 +.Sh NAME +.Nm dir , +.Nm dirent +.Nd directory file format +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Sh DESCRIPTION +Directories provide a convenient hierarchical method of grouping +files while obscuring the underlying details of the storage medium. +A directory file is differentiated from a plain file +by a flag in its +.Xr inode 5 +entry. +It consists of records (directory entries) each of which contains +information about a file and a pointer to the file itself. +Directory entries may contain other directories +as well as plain files; such nested directories are refered to as +subdirectories. +A hierarchy of directories and files is formed in this manner +and is called a file system (or referred to as a file system tree). +.\" An entry in this tree, +.\" nested or not nested, +.\" is a pathname. +.Pp +Each directory file contains two special directory entries; one is a pointer +to the directory itself +called dot +.Ql \&. +and the other a pointer to its parent directory called dot-dot +.Ql \&.. . +Dot and dot-dot +are valid pathnames, however, +the system root directory +.Ql / , +has no parent and dot-dot points to itself like dot. +.Pp +File system nodes are ordinary directory files on which has +been grafted a file system object, such as a physical disk or a +partitioned area of such a disk. +(See +.Xr mount 1 +and +.Xr mount 8 . ) +.Pp +The directory entry format is defined in the file +.Aq dirent.h : +.Bd -literal +#ifndef _DIRENT_H_ +#define _DIRENT_H_ + +/* +* A directory entry has a struct dirent 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. +*/ + +struct dirent { + u_long d_fileno; /* file number of entry */ + u_short d_reclen; /* length of this record */ + u_short d_namlen; /* length of string in d_name */ +#ifdef _POSIX_SOURCE + char d_name[MAXNAMLEN + 1]; /* maximum name length */ +#else +#define MAXNAMLEN 255 + char d_name[MAXNAMLEN + 1]; /* maximum name length */ +#endif + +}; + +#ifdef _POSIX_SOURCE +typedef void * DIR; +#else + +#define d_ino d_fileno /* backward compatibility */ + +/* definitions for library routines operating on directories. */ +#define DIRBLKSIZ 1024 + +/* structure describing an open directory. */ +typedef struct _dirdesc { + int dd_fd; /* file descriptor associated with directory */ + long dd_loc; /* offset in current buffer */ + long dd_size; /* amount of data returned by getdirentries */ + char *dd_buf; /* data buffer */ + int dd_len; /* size of data buffer */ + long dd_seek; /* magic cookie returned by getdirentries */ +} DIR; + +#define dirfd(dirp) ((dirp)->dd_fd) + +#ifndef NULL +#define NULL 0 +#endif + +#endif /* _POSIX_SOURCE */ + +#ifndef _KERNEL + +#include + +#endif /* !_KERNEL */ + +#endif /* !_DIRENT_H_ */ +.Ed +.Sh SEE ALSO +.Xr fs 5 , +.Xr inode 5 +.Sh HISTORY +A +.Nm +file format appeared in +.At v7 . diff --git a/bsd/man/man5/dirent.5 b/bsd/man/man5/dirent.5 new file mode 100644 index 000000000..44d0093c0 --- /dev/null +++ b/bsd/man/man5/dirent.5 @@ -0,0 +1 @@ +.so man5/dir.5 diff --git a/bsd/man/man5/fs.5 b/bsd/man/man5/fs.5 new file mode 100644 index 000000000..18da833e6 --- /dev/null +++ b/bsd/man/man5/fs.5 @@ -0,0 +1,343 @@ +.\" $NetBSD: fs.5,v 1.3 1994/11/30 19:31:17 jtc Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" 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. +.\" +.\" @(#)fs.5 8.2 (Berkeley) 4/19/94 +.\" +.Dd April 19, 1994 +.Dt FS 5 +.Os BSD 4.2 +.Sh NAME +.Nm fs , +.Nm inode +.Nd format of file system volume +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Fd #include +.Sh DESCRIPTION +The files +.Aq Pa fs.h +and +.Aq Pa inode.h +declare several structures, defined variables and macros +which are used to create and manage the underlying format of +file system objects on random access devices (disks). +.Pp +The block size and number of blocks which +comprise a file system are parameters of the file system. +Sectors beginning at +.Dv BBLOCK +and continuing for +.Dv BBSIZE +are used +for a disklabel and for some hardware primary +and secondary bootstrapping programs. +.Pp +The actual file system begins at sector +.Dv SBLOCK +with the +.Em super-block +that is of size +.Dv SBSIZE . +The following structure described the super-block and is +from the file +.Aq Pa ufs/fs.h : +.Bd -literal +#define FS_MAGIC 0x011954 +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[56]; /* reserved for future constants */ + 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 rotational 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 */ +}; +.Ed +.Pp +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. +.Pp +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 file system creation +time and the critical +super-block data does not change, so the copies need not be +referenced further unless disaster strikes. +.Pp +Addresses stored in inodes are capable of addressing fragments +of `blocks'. File system blocks of at most size +.Dv MAXBSIZE +can +be optionally broken into 2, 4, or 8 pieces, each of which is +addressable; these pieces may be +.Dv DEV_BSIZE , +or some multiple of +a +.Dv DEV_BSIZE +unit. +.Pp +Large files consist of exclusively large data blocks. To avoid +undue wasted disk space, the last data block of a small file is +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 +.Fn blksize fs ip lbn +macro. +.Pp +The file system records space availability at the fragment level; +to determine block availability, aligned fragments are examined. +.Pp +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). +.Pp +The +.Fa fs_minfree +element gives the minimum acceptable percentage of file system +blocks that may be free. If the freelist drops below this level +only the super-user may continue to allocate blocks. +The +.Fa fs_minfree +element +may be set to 0 if no reserve of free blocks is deemed necessary, +however severe performance degradations will be observed if the +file system is run at greater than 90% full; thus the default +value of +.Fa fs_minfree +is 10%. +.Pp +Empirically the best trade-off between block fragmentation and +overall disk utilization at a loading of 90% comes with a +fragmentation of 8, thus the default fragment size is an eighth +of the block size. +.Pp +The element +.Fa fs_optim +specifies whether the file system should try to minimize the time spent +allocating blocks, or if it should attempt to minimize the space +fragmentation on the disk. +If the value of fs_minfree (see above) is less than 10%, +then the file system defaults to optimizing for space to avoid +running out of full sized blocks. +If the value of minfree is greater than or equal to 10%, +fragmentation is unlikely to be problematical, and +the file system defaults to optimizing for time. +.Pp +.Em Cylinder group related limits : +Each cylinder keeps track of the availability of blocks at different +rotational positions, so that sequential blocks can be laid out +with minimum rotational latency. With the default of 8 distinguished +rotational positions, the resolution of the +summary information is 2ms for a typical 3600 rpm drive. +.Pp +The element +.Fa fs_rotdelay +gives the minimum number of milliseconds to initiate +another disk transfer on the same cylinder. +It is used in determining the rotationally optimal +layout for disk blocks within a file; +the default value for +.Fa fs_rotdelay +is 2ms. +.Pp +Each file system has a statically allocated number of inodes. +An inode is allocated for each +.Dv NBPI +bytes of disk space. +The inode allocation strategy is extremely conservative. +.Pp +.Dv MINBSIZE +is the smallest allowable block size. +With a +.Dv MINBSIZE +of 4096 +it is possible to create files of size +2^32 with only two levels of indirection. +.Dv MINBSIZE +must be big enough to hold a cylinder group block, +thus changes to +.Pq Fa struct cg +must keep its size within +.Dv MINBSIZE . +Note that super-blocks are never more than size +.Dv SBSIZE . +.Pp +The path name on which the file system is mounted is maintained in +.Fa fs_fsmnt . +.Dv 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 +.Dv MAXCSBUFS. +For a 4096 byte block size, it is currently parameterized for a +maximum of two million cylinders. +.Pp +Per cylinder group information is summarized in blocks allocated +from the first cylinder group's data blocks. +These blocks are read in from +.Fa fs_csaddr +(size +.Fa fs_cssize ) +in addition to the super-block. +.Pp +.Sy N.B.: +.Xr sizeof Pq Fa struct csum +must be a power of two in order for +the +.Fn fs_cs +macro to work. +.Pp +The +.Em "Super-block for a file system" : +The size of the rotational layout tables +is limited by the fact that the super-block is of size +.Dv SBSIZE . +The size of these tables is +.Em inversely +proportional to the block +size of the file system. The size of the tables is +increased when sector sizes are not powers of two, +as this increases the number of cylinders +included before the rotational pattern repeats +.Pq Fa fs_cpc . +The size of the rotational layout +tables is derived from the number of bytes remaining in +.Pq Fa struct fs . +.Pp +The number of blocks of data per cylinder group +is limited because cylinder groups are at most one block. +The inode and free block tables +must fit into a single block after deducting space for +the cylinder group structure +.Pq Fa struct cg . +.Pp +The +.Em Inode : +The inode is the focus of all file activity in the +file system. +There is a unique inode allocated +for each active file, +each current directory, each mounted-on file, +text file, and the root. +An inode is `named' by its device/i-number pair. +For further information, see the include file +.Aq Pa sys/inode.h . +.Sh HISTORY +A super-block structure named filsys appeared in +.At v6 . +The file system described in this manual appeared +in +.Bx 4.2 . diff --git a/bsd/man/man5/inode.5 b/bsd/man/man5/inode.5 new file mode 100644 index 000000000..1b47f6228 --- /dev/null +++ b/bsd/man/man5/inode.5 @@ -0,0 +1 @@ +.so man5/fs.5 diff --git a/bsd/man/man5/types.5 b/bsd/man/man5/types.5 new file mode 100644 index 000000000..533fa7328 --- /dev/null +++ b/bsd/man/man5/types.5 @@ -0,0 +1,149 @@ +.\" $NetBSD: types.5,v 1.3 1994/11/30 19:31:34 jtc Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" 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.5 8.1 (Berkeley) 6/5/93 +.\" +.Dd AUGUST 2, 2001 +.Dt TYPES 5 +.Os Darwin +.Sh NAME +.Nm types +.Nd system data types +.Sh SYNOPSIS +.Fd #include +.Sh DESCRIPTION +The file +.Pa sys/types.h +contains the defined data types used in the kernel (most are +used through out the system). +.Bd -literal +#ifndef _TYPES_H_ +#define _TYPES_H_ + +typedef short dev_t; +#ifndef _POSIX_SOURCE + /* major part of a device */ +#define major(x) ((int)(((unsigned)(x)>>8)&0377)) + /* minor part of a device */ +#define minor(x) ((int)((x)&0377)) + /* make a device number */ +#define makedev(x,y) ((dev_t)(((x)<<8) | (y))) +#endif + +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 */ + +#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 +typedef struct _uquad { unsigned long val[2]; } u_quad; +typedef struct _quad { long val[2]; } quad; +#endif +typedef long * qaddr_t; /* should be typedef quad * qaddr_t; */ + +typedef long daddr_t; +typedef char * caddr_t; +typedef u_long ino_t; +typedef long swblk_t; +typedef long segsz_t; +typedef long off_t; +typedef u_short uid_t; +typedef u_short gid_t; +typedef short pid_t; +typedef u_short nlink_t; +typedef u_short mode_t; +typedef u_long fixpt_t; + +#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 >= NOFILE (param.h). + */ +#ifndef FD_SETSIZE +#define FD_SETSIZE 1024 +#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))) + +#endif /* !_POSIX_SOURCE */ +#endif /* !_TYPES_H_ */ +.Ed +.Sh SEE ALSO +.Xr fs 5 , +.Xr time 3 , +.Xr lseek 2 , +.Xr adb 1 +.Sh HISTORY +A +.Nm +file appeared in +.At v7 . diff --git a/bsd/man/man9/Makefile b/bsd/man/man9/Makefile new file mode 100644 index 000000000..1e5e8000b --- /dev/null +++ b/bsd/man/man9/Makefile @@ -0,0 +1,21 @@ +export MakeInc_cmd=${SRCROOT}/makedefs/MakeInc.cmd +export MakeInc_def=${SRCROOT}/makedefs/MakeInc.def +export MakeInc_rule=${SRCROOT}/makedefs/MakeInc.rule +export MakeInc_dir=${SRCROOT}/makedefs/MakeInc.dir + +include $(MakeInc_cmd) +include $(MakeInc_def) + +DATAFILES = \ + copy.9 \ + fetch.9 \ + store.9 \ + style.9 \ + +INSTALL_MAN_LIST = ${DATAFILES} + +INSTALL_MAN_DIR = man9 + +include $(MakeInc_rule) +include $(MakeInc_dir) + diff --git a/bsd/man/man9/copy.9 b/bsd/man/man9/copy.9 new file mode 100644 index 000000000..5d82b9da4 --- /dev/null +++ b/bsd/man/man9/copy.9 @@ -0,0 +1,136 @@ +.\" $NetBSD: copy.9,v 1.2 1996/01/09 03:23:04 thorpej Exp $ +.\" +.\" Copyright (c) 1996 Jason R. Thorpe. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed by Kenneth Stailey. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed for the NetBSD Project +.\" by Jason R. Thorpe. +.\" 4. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +.\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD: src/share/man/man9/copy.9,v 1.6.2.5 2001/12/17 11:30:18 ru Exp $ +.\" +.Dd January 7, 1996 +.Dt COPY 9 +.Os +.Sh NAME +.Nm copy , +.Nm copyin , +.Nm copyout , +.Nm copystr , +.Nm copyinstr +.Nd kernel copy functions +.Sh SYNOPSIS +.In sys/types.h +.In sys/systm.h +.Ft int +.Fn copyin "const void *uaddr" "void *kaddr" "size_t len" +.Ft int +.Fn copyout "const void *kaddr" "void *uaddr" "size_t len" +.Ft int +.Fn copystr "const void *kfaddr" "void *kdaddr" "size_t len" "size_t *done" +.Ft int +.Fn copyinstr "const void *uaddr" "void *kaddr" "size_t len" "size_t *done" +.\" .Ft int +.\" .Fn copyoutstr "const void *kaddr" "void *uaddr" "size_t len" "size_t *done" +.Sh DESCRIPTION +The +.Nm +functions are designed to copy contiguous data from one address +to another. All but +.Fn copystr +copy data from user-space to kernel-space or vice-versa. +.Pp +The +.Nm +routines provide the following functionality: +.Bl -tag -width "copyoutstr()" +.It Fn copyin +Copies +.Pa len +bytes of data from the user-space address +.Pa uaddr +to the kernel-space address +.Pa kaddr . +.It Fn copyout +Copies +.Pa len +bytes of data from the kernel-space address +.Pa kaddr +to the user-space address +.Pa uaddr . +.It Fn copystr +Copies a NUL-terminated string, at most +.Pa len +bytes long, from kernel-space address +.Pa kfaddr +to kernel-space address +.Pa kdaddr . +The number of bytes actually copied, including the terminating +NUL, is returned in +.Pa *done . +.It Fn copyinstr +Copies a NUL-terminated string, at most +.Pa len +bytes long, from user-space address +.Pa uaddr +to kernel-space address +.Pa kaddr . +The number of bytes actually copied, including the terminating +NUL, is returned in +.Pa *done . +.\" .It Fn copyoutstr +.\" Copies a NUL-terminated string, at most +.\" bytes long, from kernel-space address +.\" .Pa kaddr +.\" to user-space address +.\" .Pa uaddr . +.\" The number of bytes actually copied, including the terminating +.\" NUL, is returned in +.\" .Pa *done . +.El +.Sh RETURN VALUES +The +.Nm +functions return 0 on success or +.Er EFAULT +if a bad address is encountered. +In addition, the +.Fn copystr , +and +.Fn copyinstr +.\" .Fn copyinstr , +.\" and +.\" .Fn copyoutstr +functions return +.Er ENAMETOOLONG +if the string is longer than +.Pa len +bytes. +.Sh SEE ALSO +.Xr fetch 9 , +.Xr store 9 diff --git a/bsd/man/man9/fetch.9 b/bsd/man/man9/fetch.9 new file mode 100644 index 000000000..5669d0078 --- /dev/null +++ b/bsd/man/man9/fetch.9 @@ -0,0 +1,89 @@ +.\" $NetBSD: fetch.9,v 1.2 1996/01/09 21:59:24 perry Exp $ +.\" +.\" Copyright (c) 1996 Jason R. Thorpe. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed by Kenneth Stailey. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed for the NetBSD Project +.\" by Jason R. Thorpe. +.\" 4. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +.\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD: src/share/man/man9/fetch.9,v 1.6.2.4 2001/12/17 11:30:18 ru Exp $ +.\" +.Dd January 7, 1996 +.Dt FETCH 9 +.Os +.Sh NAME +.Nm fetch , +.Nm fubyte , +.Nm fusword , +.Nm fuswintr , +.Nm fuword +.Nd fetch data from user-space +.Sh SYNOPSIS +.In sys/types.h +.In sys/time.h +.In sys/systm.h +.In sys/resourcevar.h +.Ft int +.Fn fubyte "const void *base" +.Ft int +.Fn fusword "void *base" +.Ft int +.Fn fuswintr "void *base" +.Ft long +.Fn fuword "const void *base" +.Sh DESCRIPTION +The +.Nm +functions are designed to copy small amounts of data from user-space. +.Pp +The +.Nm +routines provide the following functionality: +.Bl -tag -width "fuswintr()" +.It Fn fubyte +Fetches a byte of data from the user-space address +.Pa base . +.It Fn fusword +Fetches a short word of data from the user-space address +.Pa base . +.It Fn fuswintr +Fetches a short word of data from the user-space address +.Pa base . +This function is safe to call during an interrupt context. +.It Fn fuword +Fetches a word of data from the user-space address +.Pa base . +.El +.Sh RETURN VALUES +The +.Nm +functions return the data fetched or -1 on failure. +.Sh SEE ALSO +.Xr copy 9 , +.Xr store 9 diff --git a/bsd/man/man9/store.9 b/bsd/man/man9/store.9 new file mode 100644 index 000000000..5ef2d664e --- /dev/null +++ b/bsd/man/man9/store.9 @@ -0,0 +1,89 @@ +.\" $NetBSD: store.9,v 1.2 1996/01/09 21:59:27 perry Exp $ +.\" +.\" Copyright (c) 1996 Jason R. Thorpe. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed by Kenneth Stailey. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed for the NetBSD Project +.\" by Jason R. Thorpe. +.\" 4. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +.\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD: src/share/man/man9/store.9,v 1.7.2.4 2001/12/17 11:30:19 ru Exp $ +.\" +.Dd January 7, 1996 +.Dt STORE 9 +.Os +.Sh NAME +.Nm store , +.Nm subyte , +.Nm susword , +.Nm suswintr , +.Nm suword +.Nd store data to user-space +.Sh SYNOPSIS +.In sys/types.h +.In sys/time.h +.In sys/systm.h +.In sys/resourcevar.h +.Ft int +.Fn subyte "void *base" "int byte" +.Ft int +.Fn susword "void *base" "int word" +.Ft int +.Fn suswintr "void *base" "int word" +.Ft int +.Fn suword "void *base" "long word" +.Sh DESCRIPTION +The +.Nm +functions are designed to copy small amounts of data to user-space. +.Pp +The +.Nm +routines provide the following functionality: +.Bl -tag -width "suswintr()" +.It Fn subyte +Stores a byte of data to the user-space address +.Pa base . +.It Fn susword +Stores a short word of data to the user-space address +.Pa base . +.It Fn suswintr +Stores a short word of data to the user-space address +.Pa base . +This function is safe to call during an interrupt context. +.It Fn suword +Stores a word of data to the user-space address +.Pa base . +.El +.Sh RETURN VALUES +The +.Nm +functions return 0 on success or -1 on failure. +.Sh SEE ALSO +.Xr copy 9 , +.Xr fetch 9 diff --git a/bsd/man/man9/style.9 b/bsd/man/man9/style.9 new file mode 100644 index 000000000..115fe669a --- /dev/null +++ b/bsd/man/man9/style.9 @@ -0,0 +1,700 @@ +.\" Copyright (c) 1995-2001 FreeBSD Inc. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL [your name] OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" +.Dd December 7, 2001 +.Dt STYLE 9 +.Os +.Sh NAME +.Nm style +.Nd "kernel source file style guide" +.Sh DESCRIPTION +This file specifies the preferred style for kernel source files in the +.Fx +source tree. +It is also a guide for preferred userland code style. +.Bd -literal +/* + * Style guide for FreeBSD. Based on the CSRG's KNF (Kernel Normal Form). + * + * @(#)style 1.14 (Berkeley) 4/28/95 + * $FreeBSD: src/share/man/man9/style.9,v 1.32.2.16 2001/12/17 11:30:19 ru Exp $ + */ + +/* + * VERY important single-line comments look like this. + */ + +/* Most single-line comments look like this. */ + +/* + * Multi-line comments look like this. Make them real sentences. Fill + * them so they look like real paragraphs. + */ +.Ed +.Pp +After any copyright header, there is a blank line, and the +.Va rcsid +for source files. +Version control system ID tags should only exist once in a file +(unlike this one). +Non-C/C++ source files follow the example above, while C/C++ source files +follow the one below. +All VCS (version control system) revision identification from files obtained +from elsewhere should be maintained, including, where applicable, multiple IDs +showing a file's history. +In general, keep the IDs intact, including any +.So Li $ Sc Ns s . +There is no reason to add +.Qq Li "From" +in front of foreign VCS IDs. +Most +.No non- Ns Fx +VCS IDs should be indented by a tab if in a comment. +.Bd -literal +#include +__RCSID("@(#)style 1.14 (Berkeley) 4/28/95"); +__FBSDID("$FreeBSD: src/share/man/man9/style.9,v 1.32.2.16 2001/12/17 11:30:19 ru Exp $"); +.Ed +.Pp +Leave another blank line before the header files. +.Pp +Kernel include files (i.e.\& +.Pa sys/*.h ) +come first; normally, include +.Aq Pa sys/types.h +OR +.Aq Pa sys/param.h , +but not both. +.Aq Pa sys/types.h +includes +.Aq Pa sys/cdefs.h , +and it is okay to depend on that. +.Bd -literal +#include /* Non-local includes in angle brackets. */ +.Ed +.Pp +For a network program, put the network include files next. +.Bd -literal +#include +#include +#include +#include +#include +.Ed +.Pp +Leave a blank line before the next group, the +.Pa /usr +include files, +which should be sorted alphabetically by name. +.Bd -literal +#include +.Ed +.Pp +Global pathnames are defined in +.Aq Pa paths.h . +Pathnames local +to the program go in +.Qq Pa pathnames.h +in the local directory. +.Bd -literal +#include +.Ed +.Pp +Leave another blank line before the user include files. +.Bd -literal +#include "pathnames.h" /* Local includes in double quotes. */ +.Ed +.Pp +Do not +.Ic #define +or declare names in the implementation namespace except +for implementing application interfaces. +.Pp +The names of +.Dq unsafe +macros (ones that have side effects), and the names of macros for +manifest constants, are all in uppercase. +The expansions of expression-like macros are either a single token +or have outer parentheses. +Put a single tab character between the +.Ic #define +and the macro name. +If a macro is an inline expansion of a function, the function name is +all in lowercase and the macro has the same name all in uppercase. +.\" XXX the above conflicts with ANSI style where the names are the +.\" same and you #undef the macro (if any) to get the function. +.\" It is not followed for MALLOC(), and not very common if inline +.\" functions are used. +If a +macro needs more than a single line, use braces +.Ql ( \&{ +and +.Ql \&} ) . +Right-justify the +backslashes; it makes it easier to read. +If the macro encapsulates a compound statement, enclose it in a +.Ic do +loop, +so that it can safely be used in +.Ic if +statements. +Any final statement-terminating semicolon should be +supplied by the macro invocation rather than the macro, to make parsing easier +for pretty-printers and editors. +.Bd -literal +#define MACRO(x, y) do { \e + variable = (x) + (y); \e + (y) += 2; \e +} while(0) +.Ed +.Pp +Enumeration values are all uppercase. +.Bd -literal +enum enumtype { ONE, TWO } et; +.Ed +.Pp +When declaring variables in structures, declare them sorted by use, then +by size, and then in alphabetical order. +The first category normally does not apply, but there are exceptions. +Each one gets its own line. +Try to make the structure +readable by aligning the member names using either one or two tabs +depending upon your judgment. +You should use one tab if it suffices to align most of the member names. +Names following extremely long types +should be separated by a single space. +.Pp +Major structures should be declared at the top of the file in which they +are used, or in separate header files if they are used in multiple +source files. +Use of the structures should be by separate declarations +and should be +.Ic extern +if they are declared in a header file. +.Bd -literal +struct foo { + struct foo *next; /* List of active foo. */ + struct mumble amumble; /* Comment for mumble. */ + int bar; /* Try to align the comments. */ + struct verylongtypename *baz; /* Won't fit in 2 tabs. */ +}; +struct foo *foohead; /* Head of global foo list. */ +.Ed +.Pp +Use +.Xr queue 3 +macros rather than rolling your own lists, whenever possible. +Thus, +the previous example would be better written: +.Bd -literal +#include + +struct foo { + LIST_ENTRY(foo) link; /* Use queue macros for foo lists. */ + struct mumble amumble; /* Comment for mumble. */ + int bar; /* Try to align the comments. */ + struct verylongtypename *baz; /* Won't fit in 2 tabs. */ +}; +LIST_HEAD(, foo) foohead; /* Head of global foo list. */ +.Ed +.Pp +Avoid using typedefs for structure types. +This makes it impossible +for applications to use pointers to such a structure opaquely, which +is both possible and beneficial when using an ordinary struct tag. +When convention requires a +.Ic typedef , +make its name match the struct tag. +Avoid typedefs ending in +.Dq Li _t , +except as specified in Standard C or by \*[Px]. +.Bd -literal +/* Make the structure name match the typedef. */ +typedef struct bar { + int level; +} BAR; +.Ed +.Pp +All functions are prototyped somewhere. +.Pp +Function prototypes for private functions (i.e. functions not used +elsewhere) go at the top of the first source module. +Functions +local to one source module should be declared +.Ic static . +.Pp +Functions used from other parts of the kernel are prototyped in the +relevant include file. +.Pp +Functions that are used locally in more than one module go into a +separate header file, e.g.\& +.Qq Pa extern.h . +.Pp +Only use the +.Dv __P +macro from the include file +.Aq Pa sys/cdefs.h +if the source +file in general is (to be) compilable with a K&R Old Testament compiler. +Use of the +.Dv __P +macro in new code is discouraged, although modifications +to existing files should be consistent with that file's conventions. +.Pp +In general code can be considered +.Dq "new code" +when it makes up about 50% or more of the file(s) involved. +This is enough +to break precedents in the existing code and use the current +.Nm +guidelines. +.Pp +The kernel has a name associated with parameter types, e.g., in the kernel +use: +.Bd -literal +void function(int fd); +.Ed +.Pp +In header files visible to userland applications, prototypes that are +visible must use either +.Dq protected +names (ones beginning with an underscore) +or no names with the types. +It is preferable to use protected names. +E.g., use: +.Bd -literal +void function(int); +.Ed +.Pp +or: +.Bd -literal +void function(int _fd); +.Ed +.Pp +Prototypes may have an extra space after a tab to enable function names +to line up: +.Bd -literal +static char *function(int _arg, const char *_arg2, struct foo *_arg3, + struct bar *_arg4); +static void usage(void); + +/* + * All major routines should have a comment briefly describing what + * they do. The comment before the "main" routine should describe + * what the program does. + */ +int +main(int argc, char *argv[]) +{ + long num; + int ch; + char *ep; + +.Ed +.Pp +For consistency, +.Xr getopt 3 +should be used to parse options. +Options +should be sorted in the +.Xr getopt 3 +call and the +.Ic switch +statement, unless +parts of the +.Ic switch +cascade. +Elements in a +.Ic switch +statement that cascade should have a +.Li FALLTHROUGH +comment. +Numerical arguments should be checked for accuracy. +Code that cannot be reached should have a +.Li NOTREACHED +comment. +.Bd -literal + while ((ch = getopt(argc, argv, "abn:")) != -1) + switch (ch) { /* Indent the switch. */ + case 'a': /* Don't indent the case. */ + aflag = 1; + /* FALLTHROUGH */ + case 'b': + bflag = 1; + break; + case 'n': + num = strtol(optarg, &ep, 10); + if (num <= 0 || *ep != '\e0') { + warnx("illegal number, -n argument -- %s", + optarg); + usage(); + } + break; + case '?': + default: + usage(); + /* NOTREACHED */ + } + argc -= optind; + argv += optind; +.Ed +.Pp +Space after keywords +.Pq Ic if , while , for , return , switch . +No braces are +used for control statements with zero or only a single statement unless that +statement is more than a single line in which case they are permitted. +Forever loops are done with +.Ic for Ns 's , +not +.Ic while Ns 's . +.Bd -literal + for (p = buf; *p != '\e0'; ++p) + ; /* nothing */ + for (;;) + stmt; + for (;;) { + z = a + really + long + statement + that + needs + + two lines + gets + indented + four + spaces + + on + the + second + and + subsequent + lines; + } + for (;;) { + if (cond) + stmt; + } + if (val != NULL) + val = realloc(val, newsize); +.Ed +.Pp +Parts of a +.Ic for +loop may be left empty. +Do not put declarations +inside blocks unless the routine is unusually complicated. +.Bd -literal + for (; cnt < 15; cnt++) { + stmt1; + stmt2; + } +.Ed +.Pp +Indentation is an 8 character tab. +Second level indents are four spaces. +If you have to wrap a long statement, put the operator at the end of the +line. +.Bd -literal + while (cnt < 20 && this_variable_name_is_too_long_for_its_own_good && + ep != NULL) + z = a + really + long + statement + that + needs + + two lines + gets + indented + four + spaces + + on + the + second + and + subsequent + lines; +.Ed +.Pp +Do not add whitespace at the end of a line, and only use tabs +followed by spaces +to form the indentation. +Do not use more spaces than a tab will produce +and do not use spaces in front of tabs. +.Pp +Closing and opening braces go on the same line as the +.Ic else . +Braces that are not necessary may be left out. +.Bd -literal + if (test) + stmt; + else if (bar) { + stmt; + stmt; + } else + stmt; +.Ed +.Pp +No spaces after function names. +Commas have a space after them. +No spaces +after +.Ql \&( +or +.Ql \&[ +or preceding +.Ql \&] +or +.Ql \&) +characters. +.Bd -literal + error = function(a1, a2); + if (error != 0) + exit(error); +.Ed +.Pp +Unary operators do not require spaces, binary operators do. +Do not use parentheses unless they are required for precedence or unless the +statement is confusing without them. +Remember that other people may +confuse easier than you. +Do YOU understand the following? +.Bd -literal + a = b->c[0] + ~d == (e || f) || g && h ? i : j >> 1; + k = !(l & FLAGS); +.Ed +.Pp +Exits should be 0 on success, or according to the predefined +values in +.Xr sysexits 3 . +.Bd -literal + exit(EX_OK); /* + * Avoid obvious comments such as + * "Exit 0 on success." + */ +} +.Ed +.Pp +The function type should be on a line by itself +preceding the function. +.Bd -literal +static char * +function(int a1, int a2, float fl, int a4) +{ +.Ed +.Pp +When declaring variables in functions declare them sorted by size, +then in alphabetical order; multiple ones per line are okay. +If a line overflows reuse the type keyword. +.Pp +Be careful to not obfuscate the code by initializing variables in +the declarations. +Use this feature only thoughtfully. +DO NOT use function calls in initializers. +.Bd -literal + struct foo one, *two; + double three; + int *four, five; + char *six, seven, eight, nine, ten, eleven, twelve; + + four = myfunction(); +.Ed +.Pp +Do not declare functions inside other functions; ANSI C says that +such declarations have file scope regardless of the nesting of the +declaration. +Hiding file declarations in what appears to be a local +scope is undesirable and will elicit complaints from a good compiler. +.Pp +Casts and +.Ic sizeof Ns 's +are not followed by a space. +Note that +.Xr indent 1 +does not understand this rule. +.Pp +.Dv NULL +is the preferred null pointer constant. +Use +.Dv NULL +instead of +.Vt ( "type *" ) Ns 0 +or +.Vt ( "type *" ) Ns Dv NULL +in contexts where the compiler knows the +type, e.g., in assignments. +Use +.Vt ( "type *" ) Ns Dv NULL +in other contexts, +in particular for all function args. +(Casting is essential for +variadic args and is necessary for other args if the function prototype +might not be in scope.) +Test pointers against +.Dv NULL , +e.g., use: +.Pp +.Bd -literal +(p = f()) == NULL +.Ed +.Pp +not: +.Bd -literal +!(p = f()) +.Ed +.Pp +Do not use +.Ic \&! +for tests unless it is a boolean, e.g. use +.Bd -literal +if (*p == '\e0') +.Ed +.Pp +not +.Bd -literal +if (!*p) +.Ed +.Pp +Routines returning +.Vt "void *" +should not have their return values cast +to any pointer type. +.Pp +Use +.Xr err 3 +or +.Xr warn 3 , +do not roll your own. +.Bd -literal + if ((four = malloc(sizeof(struct foo))) == NULL) + err(1, (char *)NULL); + if ((six = (int *)overflow()) == NULL) + errx(1, "number overflowed"); + return (eight); +} +.Ed +.Pp +Old-style function declarations look like this: +.Bd -literal +static char * +function(a1, a2, fl, a4) + int a1, a2; /* Declare ints, too, don't default them. */ + float fl; /* Beware double vs. float prototype differences. */ + int a4; /* List in order declared. */ +{ +.Ed +.Pp +Use ANSI function declarations unless you explicitly need K&R compatibility. +Long parameter lists are wrapped with a normal four space indent. +.Pp +Variable numbers of arguments should look like this. +.Bd -literal +#include + +void +vaf(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + STUFF; + va_end(ap); + /* No return needed for void functions. */ +} + +static void +usage() +{ + /* Insert an empty line if the function has no local variables. */ +.Ed +.Pp +Use +.Xr printf 3 , +not +.Xr fputs 3 , +.Xr puts 3 , +.Xr putchar 3 , +whatever; it is faster and usually cleaner, not +to mention avoiding stupid bugs. +.Pp +Usage statements should look like the manual pages +.Sx SYNOPSIS . +The usage statement should be structured in the following order: +.Bl -enum +.It +Options without operands come first, +in alphabetical order, +inside a single set of brackets +.Ql ( \&[ +and +.Ql \&] ) . +.It +Options with operands come next, +also in alphabetical order, +with each option and its argument inside its own pair of brackets. +.It +Required arguments +(if any) +are next, +listed in the order they should be specified on the command line. +.It +Finally, +any optional arguments should be listed, +listed in the order they should be specified, +and all inside brackets. +.El +.Pp +A bar +.Pq Ql \&| +separates +.Dq either-or +options/arguments, +and multiple options/arguments which are specified together are +placed in a single set of brackets. +.Bd -literal -offset 4n +"usage: f [-aDde] [-b b_arg] [-m m_arg] req1 req2 [opt1 [opt2]]\en" +"usage: f [-a | -b] [-c [-dEe] [-n number]]\en" +.Ed +.Bd -literal + (void)fprintf(stderr, "usage: f [-ab]\en"); + exit(EX_USAGE); +} +.Ed +.Pp +Note that the manual page options description should list the options in +pure alphabetical order. +That is, without regard to whether an option takes arguments or not. +The alphabetical ordering should take into account the case ordering +shown above. +.Pp +New core kernel code should be reasonably compliant with the +.Nm +guides. +The guidelines for third-party maintained modules and device drivers are more +relaxed but at a minimum should be internally consistent with their style. +.Pp +Stylistic changes (including whitespace changes) are hard on the source +repository and are to be avoided without good reason. +Code that is approximately +.Fx +KNF +.Nm +compliant in the repository must not diverge from compliance. +.Pp +Whenever possible, code should be run through a code checker +(e.g., +.Xr lint 1 +or +.Nm gcc Fl Wall ) +and produce minimal warnings. +.Sh SEE ALSO +.Xr indent 1 , +.Xr lint 1 , +.Xr err 3 , +.Xr sysexits 3 , +.Xr warn 3 +.Sh HISTORY +This man page is largely based on the +.Pa src/admin/style/style +file from the +.Bx 4.4 Lite2 +release, with occasional updates to reflect the current practice and +desire of the +.Fx +project. diff --git a/bsd/miscfs/devfs/devfs.h b/bsd/miscfs/devfs/devfs.h index 4a395d31d..c76d8544a 100644 --- a/bsd/miscfs/devfs/devfs.h +++ b/bsd/miscfs/devfs/devfs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -50,6 +50,9 @@ #ifndef _MISCFS_DEVFS_DEVFS_H_ #define _MISCFS_DEVFS_DEVFS_H_ +#include + +#ifdef __APPLE_API_UNSTABLE #define DEVFS_CHAR 0 #define DEVFS_BLOCK 1 @@ -94,7 +97,9 @@ int devfs_link __P((void * handle, char *fmt, ...)); void devfs_remove __P((void * handle)); __END_DECLS +#endif /* __APPLE_API_UNSTABLE */ +#ifdef __APPLE_API_PRIVATE /* XXX */ #define UID_ROOT 0 #define UID_BIN 3 @@ -107,5 +112,6 @@ __END_DECLS #define GID_BIN 7 #define GID_GAMES 13 #define GID_DIALER 68 +#endif /* __APPLE_API_PRIVATE */ #endif /* !_MISCFS_DEVFS_DEVFS_H_ */ diff --git a/bsd/miscfs/devfs/devfs_proto.h b/bsd/miscfs/devfs/devfs_proto.h index 55f196b60..3683d6b57 100644 --- a/bsd/miscfs/devfs/devfs_proto.h +++ b/bsd/miscfs/devfs/devfs_proto.h @@ -1,14 +1,14 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ - * + * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 1.1 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. - * + * * This Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -16,17 +16,22 @@ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. - * + * * @APPLE_LICENSE_HEADER_END@ */ /* THIS FILE HAS BEEN PRODUCED AUTOMATICALLY */ +#ifndef __DEVFS_DEVFS_PROTO_H__ +#define __DEVFS_DEVFS_PROTO_H__ + +#include + +#ifdef __APPLE_API_PRIVATE int devfs_sinit(void); devdirent_t * dev_findname(devnode_t * dir,char *name); int dev_add_name(char * name, devnode_t * dirnode, devdirent_t * back, devnode_t * dnp, devdirent_t * *dirent_pp); int dev_add_node(int entrytype, devnode_type_t * typeinfo, devnode_t * proto, devnode_t * *dn_pp, struct devfsmount *dvm); -int dev_touch(devdirent_t * key) /* update the node for this dev */; void devnode_free(devnode_t * dnp); void devfs_dn_free(devnode_t * dnp); int devfs_propogate(devdirent_t * parent,devdirent_t * child); @@ -41,5 +46,8 @@ int dev_add_entry(char *name, devnode_t * parent, int type, devnode_type_t * typ devnode_t * proto, struct devfsmount *dvm, devdirent_t * *nm_pp); int devfs_mount(struct mount *mp, char *path, caddr_t data, struct nameidata *ndp, struct proc *p); + +#endif /* __APPLE_API_PRIVATE */ +#endif /* __DEVFS_DEVFS_PROTO_H__ */ /* THIS FILE PRODUCED AUTOMATICALLY */ /* DO NOT EDIT (see reproto.sh) */ diff --git a/bsd/miscfs/devfs/devfs_tree.c b/bsd/miscfs/devfs/devfs_tree.c index 60e1c0978..9707f8a9c 100644 --- a/bsd/miscfs/devfs/devfs_tree.c +++ b/bsd/miscfs/devfs/devfs_tree.c @@ -1051,8 +1051,6 @@ dev_add_entry(char *name, devnode_t * parent, int type, devnode_type_t * typeinf return error; } -#include - /* * Function: devfs_make_node * @@ -1077,7 +1075,6 @@ devfs_make_node(dev_t dev, int chrblk, uid_t uid, devnode_type_t typeinfo; char *name, *path, buf[256]; /* XXX */ - char * b_ptr = buf; boolean_t funnel_state; int i; va_list ap; @@ -1093,9 +1090,8 @@ devfs_make_node(dev_t dev, int chrblk, uid_t uid, goto out; va_start(ap, fmt); - prf(fmt, ap, TOSTR, (struct tty *)&b_ptr); + vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); - *b_ptr = 0; name = NULL; @@ -1152,7 +1148,6 @@ devfs_make_link(void *original, char *fmt, ...) va_list ap; char *p, buf[256]; /* XXX */ - char * b_ptr = buf; int i; boolean_t funnel_state; @@ -1164,9 +1159,8 @@ devfs_make_link(void *original, char *fmt, ...) } va_start(ap, fmt); - prf(fmt, ap, TOSTR, (struct tty *)&b_ptr); + vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); - *b_ptr = 0; p = NULL; diff --git a/bsd/miscfs/devfs/devfs_vfsops.c b/bsd/miscfs/devfs/devfs_vfsops.c index cdc5ee8a5..136dc458e 100644 --- a/bsd/miscfs/devfs/devfs_vfsops.c +++ b/bsd/miscfs/devfs/devfs_vfsops.c @@ -201,13 +201,15 @@ devfs_unmount( struct mount *mp, int mntflags, struct proc *p) { struct devfsmount *devfs_mp_p = (struct devfsmount *)mp->mnt_data; int flags = 0; + int force = 0; int error; if (mntflags & MNT_FORCE) { flags |= FORCECLOSE; + force = 1; } error = vflush(mp, NULLVP, flags); - if (error) + if (error && !force) return error; DEVFS_LOCK(p); diff --git a/bsd/miscfs/devfs/devfsdefs.h b/bsd/miscfs/devfs/devfsdefs.h index 6f5ef57a9..e6f299f3d 100644 --- a/bsd/miscfs/devfs/devfsdefs.h +++ b/bsd/miscfs/devfs/devfsdefs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -55,7 +55,12 @@ * Renamed structures/elements to clarify usage in code. */ +#ifndef __DEVFS_DEVFSDEFS_H__ +#define __DEVFS_DEVFSDEFS_H__ +#include + +#ifdef __APPLE_API_PRIVATE #define DEVMAXNAMESIZE 32 /* XXX */ #define DEVMAXPATHSIZE 128 /* XXX */ @@ -280,3 +285,5 @@ dn_copy_times(devnode_t * target, devnode_t * source) target->dn_ctime = source->dn_ctime; return; } +#endif /* __APPLE_API_PRIVATE */ +#endif /* __DEVFS_DEVFSDEFS_H__ */ diff --git a/bsd/miscfs/devfs/reproto.sh b/bsd/miscfs/devfs/reproto.sh index e994e0c2b..4012a1b36 100644 --- a/bsd/miscfs/devfs/reproto.sh +++ b/bsd/miscfs/devfs/reproto.sh @@ -7,8 +7,36 @@ exec /usr/bin/perl << *EOF* open(PROTO, ">devfs_proto.h") || die "Cannot open devfs_proto.h\n"; +print PROTO "" . +"/*\n" . +" * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.\n" . +" *\n" . +" * \@APPLE_LICENSE_HEADER_START\@\n" . +" *\n" . +" * The contents of this file constitute Original Code as defined in and\n" . +" * are subject to the Apple Public Source License Version 1.1 (the\n" . +" * \"License\"). You may not use this file except in compliance with the\n" . +" * License. Please obtain a copy of the License at\n" . +" * http://www.apple.com/publicsource and read it before using this file.\n" . +" *\n" . +" * This Original Code and all software distributed under the License are\n" . +" * distributed on an \"AS IS\" basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n" . +" * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n" . +" * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n" . +" * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the\n" . +" * License for the specific language governing rights and limitations\n" . +" * under the License.\n" . +" *\n" . +" * \@APPLE_LICENSE_HEADER_END\@\n" . +" */\n"; + print PROTO "/* THIS FILE HAS BEEN PRODUCED AUTOMATICALLY */\n"; +print PROTO "#ifndef __DEVFS_DEVFS_PROTO_H__\n"; +print PROTO "#define __DEVFS_DEVFS_PROTO_H__\n"; +print PROTO "\n#include \n"; +print PROTO "\n#ifdef __APPLE_API_PRIVATE\n"; + while (\$file = <*.c>) { if(open(F, \$file) == 0) { warn "Cannot open \$file.\n"; @@ -36,6 +64,9 @@ while (\$file = <*.c>) { close F; } +print PROTO "\n#endif /* __APPLE_API_PRIVATE */\n"; +print PROTO "#endif /* __DEVFS_DEVFS_PROTO_H__ */\n"; + print PROTO "/* THIS FILE PRODUCED AUTOMATICALLY */\n" . "/* DO NOT EDIT (see reproto.sh) */\n"; diff --git a/bsd/miscfs/fdesc/fdesc.h b/bsd/miscfs/fdesc/fdesc.h index 5de532434..a2c8ec310 100644 --- a/bsd/miscfs/fdesc/fdesc.h +++ b/bsd/miscfs/fdesc/fdesc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -59,7 +59,12 @@ * * #Id: fdesc.h,v 1.8 1993/04/06 15:28:33 jsp Exp # */ +#ifndef __FDESC_FDESC_H__ +#define __FDESC_FDESC_H__ +#include + +#ifdef __APPLE_API_PRIVATE #ifdef KERNEL struct fdescmount { struct vnode *f_root; /* Root node */ @@ -70,7 +75,6 @@ struct fdescmount { #define FD_STDIN 4 #define FD_STDOUT 5 #define FD_STDERR 6 -#define FD_CTTY 7 #define FD_DESC 8 #define FD_MAX 12 @@ -79,7 +83,6 @@ typedef enum { Fdevfd, Fdesc, Flink, - Fctty } fdntype; struct fdescnode { @@ -94,10 +97,11 @@ struct fdescnode { #define VFSTOFDESC(mp) ((struct fdescmount *)((mp)->mnt_data)) #define VTOFDESC(vp) ((struct fdescnode *)(vp)->v_data) -extern dev_t devctty; extern int fdesc_init __P((struct vfsconf *)); extern int fdesc_root __P((struct mount *, struct vnode **)); extern int fdesc_allocvp __P((fdntype, int, struct mount *, struct vnode **)); extern int (**fdesc_vnodeop_p)(void *); extern struct vfsops fdesc_vfsops; #endif /* KERNEL */ +#endif /* __APPLE_API_PRIVATE */ +#endif /* __FDESC_FDESC_H__ */ diff --git a/bsd/miscfs/fdesc/fdesc_vfsops.c b/bsd/miscfs/fdesc/fdesc_vfsops.c index 31a987a43..0afbec394 100644 --- a/bsd/miscfs/fdesc/fdesc_vfsops.c +++ b/bsd/miscfs/fdesc/fdesc_vfsops.c @@ -136,19 +136,17 @@ fdesc_unmount(mp, mntflags, p) { int error; int flags = 0; + int force = 0; struct vnode *rootvp = VFSTOFDESC(mp)->f_root; - if (mntflags & MNT_FORCE) + if (mntflags & MNT_FORCE) { flags |= FORCECLOSE; + force = 1; + } - /* - * Clear out buffer cache. I don't think we - * ever get anything cached at this level at the - * moment, but who knows... - */ - if (rootvp->v_usecount > 1) + if ( (rootvp->v_usecount > 1) && !force ) return (EBUSY); - if (error = vflush(mp, rootvp, flags)) + if ( (error = vflush(mp, rootvp, flags)) && !force ) return (error); /* diff --git a/bsd/miscfs/fdesc/fdesc_vnops.c b/bsd/miscfs/fdesc/fdesc_vnops.c index f5a7d31c9..0ad6d806e 100644 --- a/bsd/miscfs/fdesc/fdesc_vnops.c +++ b/bsd/miscfs/fdesc/fdesc_vnops.c @@ -83,19 +83,16 @@ #include #include -#define cttyvp(p) ((p)->p_flag & P_CONTROLT ? (p)->p_session->s_ttyvp : NULL) - #define FDL_WANT 0x01 #define FDL_LOCKED 0x02 static int fdcache_lock; -dev_t devctty; #if (FD_STDIN != FD_STDOUT-1) || (FD_STDOUT != FD_STDERR-1) FD_STDIN, FD_STDOUT, FD_STDERR must be a sequence n, n+1, n+2 #endif -#define NFDCACHE 4 +#define NFDCACHE 3 #define FD_NHASH(ix) \ (&fdhashtbl[(ix) & fdhash]) @@ -109,7 +106,6 @@ fdesc_init(vfsp) struct vfsconf *vfsp; { - devctty = makedev(nchrdev, 0); fdhashtbl = hashinit(NFDCACHE, M_CACHE, &fdhash); } @@ -207,7 +203,6 @@ fdesc_lookup(ap) default: case Flink: case Fdesc: - case Fctty: error = ENOTDIR; goto bad; @@ -222,21 +217,6 @@ fdesc_lookup(ap) return (0); } - if (cnp->cn_namelen == 3 && bcmp(pname, "tty", 3) == 0) { - struct vnode *ttyvp = cttyvp(p); - if (ttyvp == NULL) { - error = ENXIO; - goto bad; - } - error = fdesc_allocvp(Fctty, FD_CTTY, dvp->v_mount, &fvp); - if (error) - goto bad; - *vpp = fvp; - fvp->v_type = VCHR; - vn_lock(fvp, LK_SHARED | LK_RETRY, p); - return (0); - } - ln = 0; switch (cnp->cn_namelen) { case 5: @@ -340,9 +320,6 @@ fdesc_open(ap) error = ENODEV; break; - case Fctty: - error = cttyopen(devctty, ap->a_mode, 0, ap->a_p); - break; } return (error); @@ -397,7 +374,7 @@ fdesc_attr(fd, vap, cred, p) break; default: - panic("fdesc attr"); + return (EBADF); break; } @@ -422,7 +399,6 @@ fdesc_getattr(ap) case Froot: case Fdevfd: case Flink: - case Fctty: bzero((caddr_t) vap, sizeof(*vap)); vattr_null(vap); vap->va_fileid = VTOFDESC(vp)->fd_ix; @@ -448,14 +424,6 @@ fdesc_getattr(ap) vap->va_size = strlen(VTOFDESC(vp)->fd_link); break; - case Fctty: - vap->va_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; - vap->va_type = VCHR; - vap->va_nlink = 1; - vap->va_size = 0; - vap->va_rdev = devctty; - break; - default: vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; vap->va_type = VDIR; @@ -471,7 +439,7 @@ fdesc_getattr(ap) break; default: - panic("fdesc_getattr"); + return (EBADF); break; } @@ -502,9 +470,6 @@ fdesc_setattr(ap) case Fdesc: break; - case Fctty: - return (0); - default: return (EACCES); } @@ -546,7 +511,6 @@ static struct dirtmp { { FD_STDIN, UIO_MX, 5, "stdin" }, { FD_STDOUT, UIO_MX, 6, "stdout" }, { FD_STDERR, UIO_MX, 6, "stderr" }, - { FD_CTTY, UIO_MX, 3, "tty" }, { 0 } }; @@ -570,12 +534,9 @@ fdesc_readdir(ap) * requests do not need cookies. */ if (ap->a_ncookies) - panic("fdesc_readdir: not hungry"); + return (EINVAL); switch (VTOFDESC(ap->a_vp)->fd_type) { - case Fctty: - return (0); - case Fdesc: return (ENOTDIR); @@ -601,11 +562,6 @@ fdesc_readdir(ap) i++; switch (dt->d_fileno) { - case FD_CTTY: - if (cttyvp(uio->uio_procp) == NULL) - continue; - break; - case FD_STDIN: case FD_STDOUT: case FD_STDERR: @@ -695,19 +651,8 @@ fdesc_read(ap) struct ucred *a_cred; } */ *ap; { - int error = EOPNOTSUPP; - switch (VTOFDESC(ap->a_vp)->fd_type) { - case Fctty: - error = cttyread(devctty, ap->a_uio, ap->a_ioflag); - break; - - default: - error = EOPNOTSUPP; - break; - } - - return (error); + return (EOPNOTSUPP); } int @@ -719,19 +664,7 @@ fdesc_write(ap) struct ucred *a_cred; } */ *ap; { - int error = EOPNOTSUPP; - - switch (VTOFDESC(ap->a_vp)->fd_type) { - case Fctty: - error = cttywrite(devctty, ap->a_uio, ap->a_ioflag); - break; - - default: - error = EOPNOTSUPP; - break; - } - - return (error); + return (EOPNOTSUPP); } int @@ -745,20 +678,7 @@ fdesc_ioctl(ap) struct proc *a_p; } */ *ap; { - int error = EOPNOTSUPP; - - switch (VTOFDESC(ap->a_vp)->fd_type) { - case Fctty: - error = cttyioctl(devctty, ap->a_command, ap->a_data, - ap->a_fflag, ap->a_p); - break; - - default: - error = EOPNOTSUPP; - break; - } - - return (error); + return (EOPNOTSUPP); } int @@ -772,19 +692,7 @@ fdesc_select(ap) struct proc *a_p; } */ *ap; { - int error = EOPNOTSUPP; - - switch (VTOFDESC(ap->a_vp)->fd_type) { - case Fctty: - error = cttyselect(devctty, ap->a_fflags, ap->a_wql, ap->a_p); - break; - - default: - error = EOPNOTSUPP; - break; - } - - return (error); + return (EOPNOTSUPP); } int @@ -892,7 +800,7 @@ int fdesc_badop() { - panic("fdesc: bad op"); + return (ENOTSUP); /* NOTREACHED */ } diff --git a/bsd/miscfs/fifofs/fifo.h b/bsd/miscfs/fifofs/fifo.h index 23ffa9d1a..1d212b694 100644 --- a/bsd/miscfs/fifofs/fifo.h +++ b/bsd/miscfs/fifofs/fifo.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -54,7 +54,12 @@ * * @(#)fifo.h 8.3 (Berkeley) 8/10/94 */ +#ifndef __FIFOFS_FOFO_H__ +#define __FIFOFS_FOFO_H__ +#include + +#ifdef __APPLE_API_PRIVATE /* * Prototypes for fifo operations on vnodes. */ @@ -106,3 +111,5 @@ int fifo_advlock __P((struct vop_advlock_args *)); #define fifo_bwrite ((int (*) __P((struct vop_bwrite_args *)))nullop) #define fifo_blktooff ((int (*) __P((struct vop_blktooff_args *)))err_blktooff) +#endif /* __APPLE_API_PRIVATE */ +#endif /* __FIFOFS_FOFO_H__ */ diff --git a/bsd/miscfs/fifofs/fifo_vnops.c b/bsd/miscfs/fifofs/fifo_vnops.c index 7406534b5..93c037e3d 100644 --- a/bsd/miscfs/fifofs/fifo_vnops.c +++ b/bsd/miscfs/fifofs/fifo_vnops.c @@ -389,13 +389,13 @@ fifo_select(ap) struct file filetmp; int ready; - if (ap->a_fflags & FREAD) { + if (ap->a_which & FREAD) { filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock; ready = soo_select(&filetmp, ap->a_which, ap->a_wql, ap->a_p); if (ready) return (ready); } - if (ap->a_fflags & FWRITE) { + if (ap->a_which & FWRITE) { filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock; ready = soo_select(&filetmp, ap->a_which, ap->a_wql, ap->a_p); if (ready) diff --git a/bsd/miscfs/kernfs/kernfs.h b/bsd/miscfs/kernfs/kernfs.h deleted file mode 100644 index e40e53220..000000000 --- a/bsd/miscfs/kernfs/kernfs.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* $NetBSD: kernfs.h,v 1.9 1995/03/29 22:08:22 briggs Exp $ */ - -/* - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software donated to Berkeley by - * Jan-Simon Pendry. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)kernfs.h 8.5 (Berkeley) 6/15/94 - */ - -#define _PATH_KERNFS "/kern" /* Default mountpoint */ - -#ifdef KERNEL -struct kernfs_mount { - struct vnode *kf_root; /* Root node */ -}; - -struct kernfs_node { - struct kern_target *kf_kt; -}; - -#define VFSTOKERNFS(mp) ((struct kernfs_mount *)((mp)->mnt_data)) -#define VTOKERN(vp) ((struct kernfs_node *)(vp)->v_data) - -extern int (**kernfs_vnodeop_p)(void *); -extern struct vfsops kernfs_vfsops; -extern dev_t rrootdev; -#endif /* KERNEL */ diff --git a/bsd/miscfs/kernfs/kernfs_vfsops.c b/bsd/miscfs/kernfs/kernfs_vfsops.c deleted file mode 100644 index 76d28e5ff..000000000 --- a/bsd/miscfs/kernfs/kernfs_vfsops.c +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* $NetBSD: kernfs_vfsops.c,v 1.23 1995/03/09 12:05:52 mycroft Exp $ */ - -/* - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software donated to Berkeley by - * Jan-Simon Pendry. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)kernfs_vfsops.c 8.5 (Berkeley) 6/15/94 - */ - -/* - * Kernel params Filesystem - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -dev_t rrootdev = NODEV; - -kernfs_init() -{ - -} - -void -kernfs_get_rrootdev() -{ - static int tried = 0; - int cmaj; - - if (tried) { - /* Already did it once. */ - return; - } - tried = 1; - - if (rootdev == NODEV) - return; - for (cmaj = 0; cmaj < nchrdev; cmaj++) { - rrootdev = makedev(cmaj, minor(rootdev)); - if (chrtoblk(rrootdev) == rootdev) - return; - } - rrootdev = NODEV; - printf("kernfs_get_rrootdev: no raw root device\n"); -} - -/* - * Mount the Kernel params filesystem - */ -kernfs_mount(mp, path, data, ndp, p) - struct mount *mp; - char *path; - caddr_t data; - struct nameidata *ndp; - struct proc *p; -{ - int error = 0; - size_t size; - struct kernfs_mount *fmp; - struct vnode *rvp; - -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_mount(mp = %x)\n", mp); -#endif - - /* - * Update is a no-op - */ - if (mp->mnt_flag & MNT_UPDATE) - return (EOPNOTSUPP); - - MALLOC(fmp, struct kernfs_mount *, sizeof(struct kernfs_mount), - M_MISCFSMNT, M_WAITOK); - if (error = getnewvnode(VT_KERNFS, mp, kernfs_vnodeop_p, &rvp)) { - FREE(fmp, M_MISCFSMNT); - return (error); - } - - rvp->v_type = VDIR; - rvp->v_flag |= VROOT; -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_mount: root vp = %x\n", rvp); -#endif - fmp->kf_root = rvp; - mp->mnt_flag |= MNT_LOCAL; - mp->mnt_data = (qaddr_t)fmp; - getnewfsid(mp, makefstype(MOUNT_KERNFS)); - - (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); - bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); - bzero(mp->mnt_stat.f_mntfromname, MNAMELEN); - bcopy("kernfs", mp->mnt_stat.f_mntfromname, sizeof("kernfs")); -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_mount: at %s\n", mp->mnt_stat.f_mntonname); -#endif - - kernfs_get_rrootdev(); - return (0); -} - -kernfs_start(mp, flags, p) - struct mount *mp; - int flags; - struct proc *p; -{ - - return (0); -} - -kernfs_unmount(mp, mntflags, p) - struct mount *mp; - int mntflags; - struct proc *p; -{ - int error; - int flags = 0; - extern int doforce; - struct vnode *rootvp = VFSTOKERNFS(mp)->kf_root; - -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_unmount(mp = %x)\n", mp); -#endif - - if (mntflags & MNT_FORCE) { - /* kernfs can never be rootfs so don't check for it */ - if (!doforce) - return (EINVAL); - flags |= FORCECLOSE; - } - - /* - * Clear out buffer cache. I don't think we - * ever get anything cached at this level at the - * moment, but who knows... - */ - if (rootvp->v_usecount > 1) - return (EBUSY); -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_unmount: calling vflush\n"); -#endif - if (error = vflush(mp, rootvp, flags)) - return (error); - -#ifdef KERNFS_DIAGNOSTIC - vprint("kernfs root", rootvp); -#endif - /* - * Clean out the old root vnode for reuse. - */ - vrele(rootvp); - vgone(rootvp); - /* - * Finally, throw away the kernfs_mount structure - */ - free(mp->mnt_data, M_MISCFSMNT); - mp->mnt_data = 0; - return (0); -} - -kernfs_root(mp, vpp) - struct mount *mp; - struct vnode **vpp; -{ - struct vnode *vp; - -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_root(mp = %x)\n", mp); -#endif - - /* - * Return locked reference to root. - */ - vp = VFSTOKERNFS(mp)->kf_root; - VREF(vp); - VOP_LOCK(vp); - *vpp = vp; - return (0); -} - -kernfs_quotactl(mp, cmd, uid, arg, p) - struct mount *mp; - int cmd; - uid_t uid; - caddr_t arg; - struct proc *p; -{ - - return (EOPNOTSUPP); -} - -kernfs_statfs(mp, sbp, p) - struct mount *mp; - struct statfs *sbp; - struct proc *p; -{ - -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_statfs(mp = %x)\n", mp); -#endif - -#ifdef COMPAT_09 - sbp->f_type = 7; -#else - sbp->f_type = 0; -#endif - sbp->f_bsize = DEV_BSIZE; - sbp->f_iosize = DEV_BSIZE; - sbp->f_blocks = 2; /* 1K to keep df happy */ - sbp->f_bfree = 0; - sbp->f_bavail = 0; - sbp->f_files = 0; - sbp->f_ffree = 0; - if (sbp != &mp->mnt_stat) { - bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); - bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); - bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); - } - strncpy(sbp->f_fstypename, mp->mnt_op->vfs_name, MFSNAMELEN); - sbp->f_fstypename[MFSNAMELEN] = '\0'; - return (0); -} - -kernfs_sync(mp, waitfor) - struct mount *mp; - int waitfor; -{ - - return (0); -} - -/* - * Kernfs flat namespace lookup. - * Currently unsupported. - */ -kernfs_vget(mp, ino, vpp) - struct mount *mp; - ino_t ino; - struct vnode **vpp; -{ - - return (EOPNOTSUPP); -} - - -kernfs_fhtovp(mp, fhp, setgen, vpp) - struct mount *mp; - struct fid *fhp; - int setgen; - struct vnode **vpp; -{ - - return (EOPNOTSUPP); -} - -kernfs_vptofh(vp, fhp) - struct vnode *vp; - struct fid *fhp; -{ - - return (EOPNOTSUPP); -} - -struct vfsops kernfs_vfsops = { - MOUNT_KERNFS, - kernfs_mount, - kernfs_start, - kernfs_unmount, - kernfs_root, - kernfs_quotactl, - kernfs_statfs, - kernfs_sync, - kernfs_vget, - kernfs_fhtovp, - kernfs_vptofh, - kernfs_init, -}; diff --git a/bsd/miscfs/kernfs/kernfs_vnops.c b/bsd/miscfs/kernfs/kernfs_vnops.c deleted file mode 100644 index d416d9879..000000000 --- a/bsd/miscfs/kernfs/kernfs_vnops.c +++ /dev/null @@ -1,785 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* $NetBSD: kernfs_vnops.c,v 1.35 1995/02/03 16:18:46 mycroft Exp $ */ - -/* - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software donated to Berkeley by - * Jan-Simon Pendry. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)kernfs_vnops.c 8.9 (Berkeley) 6/15/94 - */ - -/* - * Kernel parameter filesystem (/kern) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define KSTRING 256 /* Largest I/O available via this filesystem */ -#define UIO_MX 32 - -#define READ_MODE (S_IRUSR|S_IRGRP|S_IROTH) -#define WRITE_MODE (S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH) -#define DIR_MODE (S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) - -struct kern_target { - u_char kt_type; - u_char kt_namlen; - char *kt_name; - void *kt_data; -#define KTT_NULL 1 -#define KTT_TIME 5 -#define KTT_INT 17 -#define KTT_STRING 31 -#define KTT_HOSTNAME 47 -#define KTT_AVENRUN 53 -#define KTT_DEVICE 71 -#define KTT_MSGBUF 89 - u_char kt_tag; - u_char kt_vtype; - mode_t kt_mode; -} kern_targets[] = { -/* NOTE: The name must be less than UIO_MX-16 chars in length */ -#define N(s) sizeof(s)-1, s - /* name data tag type ro/rw */ - { DT_DIR, N("."), 0, KTT_NULL, VDIR, DIR_MODE }, - { DT_DIR, N(".."), 0, KTT_NULL, VDIR, DIR_MODE }, - { DT_REG, N("boottime"), &boottime.tv_sec, KTT_INT, VREG, READ_MODE }, - { DT_REG, N("copyright"), copyright, KTT_STRING, VREG, READ_MODE }, - { DT_REG, N("hostname"), 0, KTT_HOSTNAME, VREG, WRITE_MODE }, - { DT_REG, N("hz"), &hz, KTT_INT, VREG, READ_MODE }, - { DT_REG, N("loadavg"), 0, KTT_AVENRUN, VREG, READ_MODE }, - { DT_REG, N("msgbuf"), 0, KTT_MSGBUF, VREG, READ_MODE }, - { DT_REG, N("pagesize"), &cnt.v_page_size, KTT_INT, VREG, READ_MODE }, - { DT_REG, N("physmem"), &physmem, KTT_INT, VREG, READ_MODE }, -#if 0 - { DT_DIR, N("root"), 0, KTT_NULL, VDIR, DIR_MODE }, -#endif - { DT_BLK, N("rootdev"), &rootdev, KTT_DEVICE, VBLK, READ_MODE }, - { DT_CHR, N("rrootdev"), &rrootdev, KTT_DEVICE, VCHR, READ_MODE }, - { DT_REG, N("time"), 0, KTT_TIME, VREG, READ_MODE }, - { DT_REG, N("version"), version, KTT_STRING, VREG, READ_MODE }, -#undef N -}; -static int nkern_targets = sizeof(kern_targets) / sizeof(kern_targets[0]); - -int -kernfs_xread(kt, off, bufp, len) - struct kern_target *kt; - int off; - char **bufp; - int len; -{ - - switch (kt->kt_tag) { - case KTT_TIME: { - struct timeval tv; - - microtime(&tv); - sprintf(*bufp, "%d %d\n", tv.tv_sec, tv.tv_usec); - break; - } - - case KTT_INT: { - int *ip = kt->kt_data; - - sprintf(*bufp, "%d\n", *ip); - break; - } - - case KTT_STRING: { - char *cp = kt->kt_data; - - *bufp = cp; - break; - } - - case KTT_MSGBUF: { - extern struct msgbuf *msgbufp; - long n; - - if (off >= MSG_BSIZE) - return (0); - n = msgbufp->msg_bufx + off; - if (n >= MSG_BSIZE) - n -= MSG_BSIZE; - len = min(MSG_BSIZE - n, MSG_BSIZE - off); - *bufp = msgbufp->msg_bufc + n; - return (len); - } - - case KTT_HOSTNAME: { - char *cp = hostname; - int xlen = hostnamelen; - - if (xlen >= (len-2)) - return (EINVAL); - - bcopy(cp, *bufp, xlen); - (*bufp)[xlen] = '\n'; - (*bufp)[xlen+1] = '\0'; - break; - } - - case KTT_AVENRUN: - averunnable.fscale = FSCALE; - sprintf(*bufp, "%ld %ld %ld %ld\n", - averunnable.ldavg[0], averunnable.ldavg[1], - averunnable.ldavg[2], averunnable.fscale); - break; - - default: - return (0); - } - - len = strlen(*bufp); - if (len <= off) - return (0); - *bufp += off; - return (len - off); -} - -int -kernfs_xwrite(kt, buf, len) - struct kern_target *kt; - char *buf; - int len; -{ - - switch (kt->kt_tag) { - case KTT_HOSTNAME: - if (buf[len-1] == '\n') - --len; - bcopy(buf, hostname, len); - hostname[len] = '\0'; - hostnamelen = len; - return (0); - - default: - return (EIO); - } -} - - -/* - * vp is the current namei directory - * ndp is the name to locate in that directory... - */ -kernfs_lookup(ap) - struct vop_lookup_args /* { - struct vnode * a_dvp; - struct vnode ** a_vpp; - struct componentname * a_cnp; - } */ *ap; -{ - struct componentname *cnp = ap->a_cnp; - struct vnode **vpp = ap->a_vpp; - struct vnode *dvp = ap->a_dvp; - char *pname = cnp->cn_nameptr; - struct kern_target *kt; - struct vnode *fvp; - int error, i; - struct kernfs_node *kp; - -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_lookup(%x)\n", ap); - printf("kernfs_lookup(dp = %x, vpp = %x, cnp = %x)\n", dvp, vpp, ap->a_cnp); - printf("kernfs_lookup(%s)\n", pname); -#endif - - *vpp = NULLVP; - - if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) - return (EROFS); - - if (cnp->cn_namelen == 1 && *pname == '.') { - *vpp = dvp; - VREF(dvp); - /*VOP_LOCK(dvp);*/ - return (0); - } - -#if 0 - if (cnp->cn_namelen == 4 && bcmp(pname, "root", 4) == 0) { - *vpp = rootdir; - VREF(rootdir); - VOP_LOCK(rootdir); - return (0); - } -#endif - - for (kt = kern_targets, i = 0; i < nkern_targets; kt++, i++) { - if (cnp->cn_namelen == kt->kt_namlen && - bcmp(kt->kt_name, pname, cnp->cn_namelen) == 0) - goto found; - } - -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_lookup: i = %d, failed", i); -#endif - - return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS); - -found: - if (kt->kt_tag == KTT_DEVICE) { - dev_t *dp = kt->kt_data; - loop: - if (*dp == NODEV || !vfinddev(*dp, kt->kt_vtype, &fvp)) - return (ENOENT); - *vpp = fvp; - if (vget(fvp, LK_SHARED, current_proc())) - goto loop; - return (0); - } - -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_lookup: allocate new vnode\n"); -#endif - MALLOC(kp, void *, sizeof(struct kernfs_node), M_TEMP, M_WAITOK); - if (error = getnewvnode(VT_KERNFS, dvp->v_mount, kernfs_vnodeop_p, - &fvp)) { - FREE(kp, M_TEMP); - return (error); - } - - fvp->v_data = kp; - VTOKERN(fvp)->kf_kt = kt; - fvp->v_type = kt->kt_vtype; - if (fvp->v_type == VREG) - ubc_info_init(fvp); - *vpp = fvp; - -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_lookup: newvp = %x\n", fvp); -#endif - return (0); -} - -kernfs_open(ap) - struct vop_open_args /* { - struct vnode *a_vp; - int a_mode; - struct ucred *a_cred; - struct proc *a_p; - } */ *ap; -{ - - /* Only need to check access permissions. */ - return (0); -} - -int -kernfs_access(ap) - struct vop_access_args /* { - struct vnode *a_vp; - int a_mode; - struct ucred *a_cred; - struct proc *a_p; - } */ *ap; -{ - struct vnode *vp = ap->a_vp; - mode_t fmode = - (vp->v_flag & VROOT) ? DIR_MODE : VTOKERN(vp)->kf_kt->kt_mode; - - return (vaccess(fmode, (uid_t)0, (gid_t)0, ap->a_mode, ap->a_cred)); -} - -kernfs_getattr(ap) - struct vop_getattr_args /* { - struct vnode *a_vp; - struct vattr *a_vap; - struct ucred *a_cred; - struct proc *a_p; - } */ *ap; -{ - struct vnode *vp = ap->a_vp; - struct vattr *vap = ap->a_vap; - int error = 0; - char strbuf[KSTRING], *buf; - - bzero((caddr_t) vap, sizeof(*vap)); - vattr_null(vap); - vap->va_uid = 0; - vap->va_gid = 0; - vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; - vap->va_size = 0; - vap->va_blocksize = DEV_BSIZE; - microtime(&vap->va_atime); - vap->va_mtime = vap->va_atime; - vap->va_ctime = vap->va_ctime; - vap->va_gen = 0; - vap->va_flags = 0; - vap->va_rdev = 0; - vap->va_bytes = 0; - - if (vp->v_flag & VROOT) { -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_getattr: stat rootdir\n"); -#endif - vap->va_type = VDIR; - vap->va_mode = DIR_MODE; - vap->va_nlink = 2; - vap->va_fileid = 2; - vap->va_size = DEV_BSIZE; - } else { - struct kern_target *kt = VTOKERN(vp)->kf_kt; - int nbytes, total; -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_getattr: stat target %s\n", kt->kt_name); -#endif - vap->va_type = kt->kt_vtype; - vap->va_mode = kt->kt_mode; - vap->va_nlink = 1; - vap->va_fileid = 1 + (kt - kern_targets) / sizeof(*kt); - total = 0; - while (buf = strbuf, - nbytes = kernfs_xread(kt, total, &buf, sizeof(strbuf))) - total += nbytes; - vap->va_size = total; - } - -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_getattr: return error %d\n", error); -#endif - return (error); -} - -kernfs_setattr(ap) - struct vop_setattr_args /* { - struct vnode *a_vp; - struct vattr *a_vap; - struct ucred *a_cred; - struct proc *a_p; - } */ *ap; -{ - - /* - * Silently ignore attribute changes. - * This allows for open with truncate to have no - * effect until some data is written. I want to - * do it this way because all writes are atomic. - */ - return (0); -} - -int -kernfs_read(ap) - struct vop_read_args /* { - struct vnode *a_vp; - struct uio *a_uio; - int a_ioflag; - struct ucred *a_cred; - } */ *ap; -{ - struct vnode *vp = ap->a_vp; - struct uio *uio = ap->a_uio; - struct kern_target *kt; - char strbuf[KSTRING], *buf; - int off, len; - int error; - - if (vp->v_type == VDIR) - return (EOPNOTSUPP); - - kt = VTOKERN(vp)->kf_kt; - -#ifdef KERNFS_DIAGNOSTIC - printf("kern_read %s\n", kt->kt_name); -#endif - - off = uio->uio_offset; -#if 0 - while (buf = strbuf, -#else - if (buf = strbuf, -#endif - len = kernfs_xread(kt, off, &buf, sizeof(strbuf))) { - if (error = uiomove(buf, len, uio)) - return (error); - off += len; - } - return (0); -} - -int -kernfs_write(ap) - struct vop_write_args /* { - struct vnode *a_vp; - struct uio *a_uio; - int a_ioflag; - struct ucred *a_cred; - } */ *ap; -{ - struct vnode *vp = ap->a_vp; - struct uio *uio = ap->a_uio; - struct kern_target *kt; - int error, xlen; - char strbuf[KSTRING]; - - if (vp->v_type == VDIR) - return (EOPNOTSUPP); - - kt = VTOKERN(vp)->kf_kt; - - if (uio->uio_offset != 0) - return (EINVAL); - - xlen = min(uio->uio_resid, KSTRING-1); - if (error = uiomove(strbuf, xlen, uio)) - return (error); - - if (uio->uio_resid != 0) - return (EIO); - - strbuf[xlen] = '\0'; - xlen = strlen(strbuf); - return (kernfs_xwrite(kt, strbuf, xlen)); -} - -kernfs_readdir(ap) - struct vop_readdir_args /* { - struct vnode *a_vp; - struct uio *a_uio; - struct ucred *a_cred; - int *a_eofflag; - u_long *a_cookies; - int a_ncookies; - } */ *ap; -{ - struct uio *uio = ap->a_uio; - struct kern_target *kt; - struct dirent d; - int i; - int error; - - if (ap->a_vp->v_type != VDIR) - return (ENOTDIR); - - /* - * We don't allow exporting kernfs mounts, and currently local - * requests do not need cookies. - */ - if (ap->a_ncookies != NULL) - panic("kernfs_readdir: not hungry"); - - i = uio->uio_offset / UIO_MX; - error = 0; - for (kt = &kern_targets[i]; - uio->uio_resid >= UIO_MX && i < nkern_targets; kt++, i++) { - struct dirent *dp = &d; -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_readdir: i = %d\n", i); -#endif - - if (kt->kt_tag == KTT_DEVICE) { - dev_t *dp = kt->kt_data; - struct vnode *fvp; - - if (*dp == NODEV || !vfinddev(*dp, kt->kt_vtype, &fvp)) - continue; - } - - bzero((caddr_t)dp, UIO_MX); - dp->d_namlen = kt->kt_namlen; - bcopy(kt->kt_name, dp->d_name, kt->kt_namlen+1); - -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_readdir: name = %s, len = %d\n", - dp->d_name, dp->d_namlen); -#endif - /* - * Fill in the remaining fields - */ - dp->d_reclen = UIO_MX; - dp->d_fileno = i + 3; - dp->d_type = kt->kt_type; - /* - * And ship to userland - */ - if (error = uiomove((caddr_t)dp, UIO_MX, uio)) - break; - } - - uio->uio_offset = i * UIO_MX; - - return (error); -} - -kernfs_inactive(ap) - struct vop_inactive_args /* { - struct vnode *a_vp; - } */ *ap; -{ - struct vnode *vp = ap->a_vp; - -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_inactive(%x)\n", vp); -#endif - /* - * Clear out the v_type field to avoid - * nasty things happening in vgone(). - */ - vp->v_type = VNON; - return (0); -} - -kernfs_reclaim(ap) - struct vop_reclaim_args /* { - struct vnode *a_vp; - } */ *ap; -{ - struct vnode *vp = ap->a_vp; - -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_reclaim(%x)\n", vp); -#endif - if (vp->v_data) { - FREE(vp->v_data, M_TEMP); - vp->v_data = 0; - } - return (0); -} - -/* - * Return POSIX pathconf information applicable to special devices. - */ -kernfs_pathconf(ap) - struct vop_pathconf_args /* { - struct vnode *a_vp; - int a_name; - register_t *a_retval; - } */ *ap; -{ - - switch (ap->a_name) { - case _PC_LINK_MAX: - *ap->a_retval = LINK_MAX; - return (0); - case _PC_MAX_CANON: - *ap->a_retval = MAX_CANON; - return (0); - case _PC_MAX_INPUT: - *ap->a_retval = MAX_INPUT; - return (0); - case _PC_PIPE_BUF: - *ap->a_retval = PIPE_BUF; - return (0); - case _PC_CHOWN_RESTRICTED: - *ap->a_retval = 1; - return (0); - case _PC_VDISABLE: - *ap->a_retval = _POSIX_VDISABLE; - return (0); - default: - return (EINVAL); - } - /* NOTREACHED */ -} - -/* - * Print out the contents of a /dev/fd vnode. - */ -/* ARGSUSED */ -kernfs_print(ap) - struct vop_print_args /* { - struct vnode *a_vp; - } */ *ap; -{ - - printf("tag VT_KERNFS, kernfs vnode\n"); - return (0); -} - -/*void*/ -kernfs_vfree(ap) - struct vop_vfree_args /* { - struct vnode *a_pvp; - ino_t a_ino; - int a_mode; - } */ *ap; -{ - - return (0); -} - -/* - * /dev/fd vnode unsupported operation - */ -kernfs_enotsupp() -{ - - return (EOPNOTSUPP); -} - -/* - * /dev/fd "should never get here" operation - */ -kernfs_badop() -{ - - panic("kernfs: bad op"); - /* NOTREACHED */ -} - -/* - * kernfs vnode null operation - */ -kernfs_nullop() -{ - - return (0); -} - -#define kernfs_create ((int (*) __P((struct vop_create_args *)))kernfs_enotsupp) -#define kernfs_mknod ((int (*) __P((struct vop_mknod_args *)))kernfs_enotsupp) -#define kernfs_close ((int (*) __P((struct vop_close_args *)))nullop) -#define kernfs_ioctl ((int (*) __P((struct vop_ioctl_args *)))kernfs_enotsupp) -#define kernfs_select ((int (*) __P((struct vop_select_args *)))kernfs_enotsupp) -#define kernfs_mmap ((int (*) __P((struct vop_mmap_args *)))kernfs_enotsupp) -#define kernfs_fsync ((int (*) __P((struct vop_fsync_args *)))nullop) -#define kernfs_seek ((int (*) __P((struct vop_seek_args *)))nullop) -#define kernfs_remove ((int (*) __P((struct vop_remove_args *)))kernfs_enotsupp) -#define kernfs_link ((int (*) __P((struct vop_link_args *)))kernfs_enotsupp) -#define kernfs_rename ((int (*) __P((struct vop_rename_args *)))kernfs_enotsupp) -#define kernfs_mkdir ((int (*) __P((struct vop_mkdir_args *)))kernfs_enotsupp) -#define kernfs_rmdir ((int (*) __P((struct vop_rmdir_args *)))kernfs_enotsupp) -#define kernfs_symlink ((int (*) __P((struct vop_symlink_args *)))kernfs_enotsupp) -#define kernfs_readlink \ - ((int (*) __P((struct vop_readlink_args *)))kernfs_enotsupp) -#define kernfs_abortop ((int (*) __P((struct vop_abortop_args *)))nullop) -#define kernfs_lock ((int (*) __P((struct vop_lock_args *)))nullop) -#define kernfs_unlock ((int (*) __P((struct vop_unlock_args *)))nullop) -#define kernfs_bmap ((int (*) __P((struct vop_bmap_args *)))kernfs_badop) -#define kernfs_strategy ((int (*) __P((struct vop_strategy_args *)))kernfs_badop) -#define kernfs_islocked ((int (*) __P((struct vop_islocked_args *)))nullop) -#define kernfs_advlock ((int (*) __P((struct vop_advlock_args *)))kernfs_enotsupp) -#define kernfs_blkatoff \ - ((int (*) __P((struct vop_blkatoff_args *)))kernfs_enotsupp) -#define kernfs_valloc ((int(*) __P(( \ - struct vnode *pvp, \ - int mode, \ - struct ucred *cred, \ - struct vnode **vpp))) kernfs_enotsupp) -#define kernfs_truncate \ - ((int (*) __P((struct vop_truncate_args *)))kernfs_enotsupp) -#define kernfs_update ((int (*) __P((struct vop_update_args *)))kernfs_enotsupp) -#define kernfs_bwrite ((int (*) __P((struct vop_bwrite_args *)))kernfs_enotsupp) - -#define VOPFUNC int (*)(void *) - -int (**kernfs_vnodeop_p)(void *); -struct vnodeopv_entry_desc kernfs_vnodeop_entries[] = { - { &vop_default_desc, (VOPFUNC)vn_default_error }, - { &vop_lookup_desc, (VOPFUNC)kernfs_lookup }, /* lookup */ - { &vop_create_desc, (VOPFUNC)kernfs_create }, /* create */ - { &vop_mknod_desc, (VOPFUNC)kernfs_mknod }, /* mknod */ - { &vop_open_desc, (VOPFUNC)kernfs_open }, /* open */ - { &vop_close_desc, (VOPFUNC)kernfs_close }, /* close */ - { &vop_access_desc, (VOPFUNC)kernfs_access }, /* access */ - { &vop_getattr_desc, (VOPFUNC)kernfs_getattr }, /* getattr */ - { &vop_setattr_desc, (VOPFUNC)kernfs_setattr }, /* setattr */ - { &vop_read_desc, (VOPFUNC)kernfs_read }, /* read */ - { &vop_write_desc, (VOPFUNC)kernfs_write }, /* write */ - { &vop_ioctl_desc, (VOPFUNC)kernfs_ioctl }, /* ioctl */ - { &vop_select_desc, (VOPFUNC)kernfs_select }, /* select */ - { &vop_mmap_desc, (VOPFUNC)kernfs_mmap }, /* mmap */ - { &vop_fsync_desc, (VOPFUNC)kernfs_fsync }, /* fsync */ - { &vop_seek_desc, (VOPFUNC)kernfs_seek }, /* seek */ - { &vop_remove_desc, (VOPFUNC)kernfs_remove }, /* remove */ - { &vop_link_desc, (VOPFUNC)kernfs_link }, /* link */ - { &vop_rename_desc, (VOPFUNC)kernfs_rename }, /* rename */ - { &vop_mkdir_desc, (VOPFUNC)kernfs_mkdir }, /* mkdir */ - { &vop_rmdir_desc, (VOPFUNC)kernfs_rmdir }, /* rmdir */ - { &vop_symlink_desc, (VOPFUNC)kernfs_symlink }, /* symlink */ - { &vop_readdir_desc, (VOPFUNC)kernfs_readdir }, /* readdir */ - { &vop_readlink_desc, (VOPFUNC)kernfs_readlink },/* readlink */ - { &vop_abortop_desc, (VOPFUNC)kernfs_abortop }, /* abortop */ - { &vop_inactive_desc, (VOPFUNC)kernfs_inactive },/* inactive */ - { &vop_reclaim_desc, (VOPFUNC)kernfs_reclaim }, /* reclaim */ - { &vop_lock_desc, (VOPFUNC)kernfs_lock }, /* lock */ - { &vop_unlock_desc, (VOPFUNC)kernfs_unlock }, /* unlock */ - { &vop_bmap_desc, (VOPFUNC)kernfs_bmap }, /* bmap */ - { &vop_strategy_desc, (VOPFUNC)kernfs_strategy },/* strategy */ - { &vop_print_desc, (VOPFUNC)kernfs_print }, /* print */ - { &vop_islocked_desc, (VOPFUNC)kernfs_islocked },/* islocked */ - { &vop_pathconf_desc, (VOPFUNC)kernfs_pathconf },/* pathconf */ - { &vop_advlock_desc, (VOPFUNC)kernfs_advlock }, /* advlock */ - { &vop_blkatoff_desc, (VOPFUNC)kernfs_blkatoff },/* blkatoff */ - { &vop_valloc_desc, (VOPFUNC)kernfs_valloc }, /* valloc */ - { &vop_vfree_desc, (VOPFUNC)kernfs_vfree }, /* vfree */ - { &vop_truncate_desc, (VOPFUNC)kernfs_truncate },/* truncate */ - { &vop_update_desc, (VOPFUNC)kernfs_update }, /* update */ - { &vop_bwrite_desc, (VOPFUNC)kernfs_bwrite }, /* bwrite */ - { &vop_copyfile_desc, (VOPFUNC)err_copyfile }, /* Copyfile */ - { (struct vnodeop_desc*)NULL, (int(*)())NULL } -}; -struct vnodeopv_desc kernfs_vnodeop_opv_desc = - { &kernfs_vnodeop_p, kernfs_vnodeop_entries }; diff --git a/bsd/miscfs/nullfs/null.h b/bsd/miscfs/nullfs/null.h index d709c61b7..a4ccc0e36 100644 --- a/bsd/miscfs/nullfs/null.h +++ b/bsd/miscfs/nullfs/null.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -59,7 +59,12 @@ * * null.h 8.2 (Berkeley) 1/21/94 */ +#ifdef __NULLFS_NULL_H__ +#define __NULLFS_NULL_H__ +#include + +#ifdef __APPLE_API_PRIVATE struct null_args { char *target; /* Target of loopback */ }; @@ -94,3 +99,6 @@ extern struct vnode *null_checkvp __P((struct vnode *vp, char *fil, int lno)); extern int (**null_vnodeop_p)(void *); extern struct vfsops null_vfsops; #endif /* KERNEL */ + +#endif /* __APPLE_API_PRIVATE */ +#endif /* __NULLFS_NULL_H__ */ diff --git a/bsd/miscfs/nullfs/null_vfsops.c b/bsd/miscfs/nullfs/null_vfsops.c index ffcaa3d81..66f61af3d 100644 --- a/bsd/miscfs/nullfs/null_vfsops.c +++ b/bsd/miscfs/nullfs/null_vfsops.c @@ -205,27 +205,20 @@ nullfs_unmount(mp, mntflags, p) struct vnode *nullm_rootvp = MOUNTTONULLMOUNT(mp)->nullm_rootvp; int error; int flags = 0; + int force = 0; #ifdef NULLFS_DIAGNOSTIC printf("nullfs_unmount(mp = %x)\n", mp); #endif - if (mntflags & MNT_FORCE) + if (mntflags & MNT_FORCE) { flags |= FORCECLOSE; + force = 1; + } - /* - * Clear out buffer cache. I don't think we - * ever get anything cached at this level at the - * moment, but who knows... - */ -#if 0 - mntflushbuf(mp, 0); - if (mntinvalbuf(mp, 1)) - return (EBUSY); -#endif - if (nullm_rootvp->v_usecount > 1) + if ( (nullm_rootvp->v_usecount > 1) && !force ) return (EBUSY); - if (error = vflush(mp, nullm_rootvp, flags)) + if ( (error = vflush(mp, nullm_rootvp, flags)) && !force ) return (error); #ifdef NULLFS_DIAGNOSTIC diff --git a/bsd/miscfs/portal/portal.h b/bsd/miscfs/portal/portal.h deleted file mode 100644 index 44a251605..000000000 --- a/bsd/miscfs/portal/portal.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ -/* - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software donated to Berkeley by - * Jan-Simon Pendry. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)portal.h 8.4 (Berkeley) 1/21/94 - */ - -struct portal_args { - char *pa_config; /* Config file */ - int pa_socket; /* Socket to server */ -}; - -struct portal_cred { - int pcr_flag; /* File open mode */ - uid_t pcr_uid; /* From ucred */ - short pcr_ngroups; /* From ucred */ - gid_t pcr_groups[NGROUPS]; /* From ucred */ -}; - -#ifdef KERNEL -struct portalmount { - struct vnode *pm_root; /* Root node */ - struct file *pm_server; /* Held reference to server socket */ -}; - -struct portalnode { - int pt_size; /* Length of Arg */ - char *pt_arg; /* Arg to send to server */ - int pt_fileid; /* cookie */ -}; - -#define VFSTOPORTAL(mp) ((struct portalmount *)((mp)->mnt_data)) -#define VTOPORTAL(vp) ((struct portalnode *)(vp)->v_data) - -#define PORTAL_ROOTFILEID 2 - -extern int (**portal_vnodeop_p)(void *); -extern struct vfsops portal_vfsops; -#endif /* KERNEL */ diff --git a/bsd/miscfs/portal/portal_vfsops.c b/bsd/miscfs/portal/portal_vfsops.c deleted file mode 100644 index 2cdb39e78..000000000 --- a/bsd/miscfs/portal/portal_vfsops.c +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ -/* - * Copyright (c) 1992, 1993, 1995 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software donated to Berkeley by - * Jan-Simon Pendry. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)portal_vfsops.c 8.11 (Berkeley) 5/14/95 - * - * @(#)portal_vfsops.c 8.6 (Berkeley) 1/21/94 - */ - -/* - * Portal Filesystem - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int -portal_init(vfsp) - struct vfsconf *vfsp; -{ - - return (0); -} - -/* - * Mount the per-process file descriptors (/dev/fd) - */ -int -portal_mount(mp, path, data, ndp, p) - struct mount *mp; - char *path; - caddr_t data; - struct nameidata *ndp; - struct proc *p; -{ - struct file *fp; - struct portal_args args; - struct portalmount *fmp; - struct socket *so; - struct vnode *rvp; - u_int size; - int error; - struct portalnode *pnp; - - /* - * Update is a no-op - */ - if (mp->mnt_flag & MNT_UPDATE) - return (EOPNOTSUPP); - - if (error = copyin(data, (caddr_t) &args, sizeof(struct portal_args))) - return (error); - - if (error = getsock(p->p_fd, args.pa_socket, &fp)) - return (error); - so = (struct socket *) fp->f_data; - if (so->so_proto->pr_domain->dom_family != AF_UNIX) - return (ESOCKTNOSUPPORT); - - fmp = (struct portalmount *) _MALLOC(sizeof(struct portalmount), - M_UFSMNT, M_WAITOK); /* XXX */ - MALLOC(pnp, void *, sizeof(struct portalnode), M_TEMP, M_WAITOK); - error = getnewvnode(VT_PORTAL, mp, portal_vnodeop_p, &rvp); /* XXX */ - if (error) { - FREE(pnp, M_TEMP); - FREE(fmp, M_UFSMNT); - return (error); - } - rvp->v_data = pnp; - - rvp->v_type = VDIR; - rvp->v_flag |= VROOT; - VTOPORTAL(rvp)->pt_arg = 0; - VTOPORTAL(rvp)->pt_size = 0; - VTOPORTAL(rvp)->pt_fileid = PORTAL_ROOTFILEID; - fmp->pm_root = rvp; - fmp->pm_server = fp; - - (void)fref(fp); - - mp->mnt_flag |= MNT_LOCAL; - mp->mnt_data = (qaddr_t) fmp; - vfs_getnewfsid(mp); - - (void)copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); - bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); - (void)copyinstr(args.pa_config, - mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size); - bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); - -#ifdef notdef - bzero(mp->mnt_stat.f_mntfromname, MNAMELEN); - bcopy("portal", mp->mnt_stat.f_mntfromname, sizeof("portal")); -#endif - - return (0); -} - -int -portal_start(mp, flags, p) - struct mount *mp; - int flags; - struct proc *p; -{ - - return (0); -} - -int -portal_unmount(mp, mntflags, p) - struct mount *mp; - int mntflags; - struct proc *p; -{ - struct vnode *rootvp = VFSTOPORTAL(mp)->pm_root; - int error, flags = 0; - - - if (mntflags & MNT_FORCE) - flags |= FORCECLOSE; - - /* - * Clear out buffer cache. I don't think we - * ever get anything cached at this level at the - * moment, but who knows... - */ -#ifdef notyet - mntflushbuf(mp, 0); - if (mntinvalbuf(mp, 1)) - return (EBUSY); -#endif - if (rootvp->v_usecount > 1) - return (EBUSY); - if (error = vflush(mp, rootvp, flags)) - return (error); - - /* - * Release reference on underlying root vnode - */ - vrele(rootvp); - /* - * And blow it away for future re-use - */ - vgone(rootvp); - /* - * Shutdown the socket. This will cause the select in the - * daemon to wake up, and then the accept will get ECONNABORTED - * which it interprets as a request to go and bury itself. - */ - thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); - soshutdown((struct socket *) VFSTOPORTAL(mp)->pm_server->f_data, 2); - thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); - /* - * Discard reference to underlying file. Must call closef because - * this may be the last reference. - */ - closef(VFSTOPORTAL(mp)->pm_server, (struct proc *) 0); - /* - * Finally, throw away the portalmount structure - */ - _FREE(mp->mnt_data, M_UFSMNT); /* XXX */ - mp->mnt_data = 0; - return (0); -} - -int -portal_root(mp, vpp) - struct mount *mp; - struct vnode **vpp; -{ - struct proc *p = current_proc(); /* XXX */ - struct vnode *vp; - - /* - * Return locked reference to root. - */ - vp = VFSTOPORTAL(mp)->pm_root; - VREF(vp); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - *vpp = vp; - return (0); -} - -int -portal_statfs(mp, sbp, p) - struct mount *mp; - struct statfs *sbp; - struct proc *p; -{ - - sbp->f_flags = 0; - sbp->f_bsize = DEV_BSIZE; - sbp->f_iosize = DEV_BSIZE; - sbp->f_blocks = 2; /* 1K to keep df happy */ - sbp->f_bfree = 0; - sbp->f_bavail = 0; - sbp->f_files = 1; /* Allow for "." */ - sbp->f_ffree = 0; /* See comments above */ - if (sbp != &mp->mnt_stat) { - sbp->f_type = mp->mnt_vfc->vfc_typenum; - bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); - bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); - bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); - } - return (0); -} - -#define portal_fhtovp ((int (*) __P((struct mount *, struct fid *, \ - struct mbuf *, struct vnode **, int *, struct ucred **)))eopnotsupp) -#define portal_quotactl ((int (*) __P((struct mount *, int, uid_t, caddr_t, \ - struct proc *)))eopnotsupp) -#define portal_sync ((int (*) __P((struct mount *, int, struct ucred *, \ - struct proc *)))nullop) -#define portal_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \ - size_t, struct proc *)))eopnotsupp) -#define portal_vget ((int (*) __P((struct mount *, ino_t, struct vnode **))) \ - eopnotsupp) -#define portal_vptofh ((int (*) __P((struct vnode *, struct fid *)))eopnotsupp) - -struct vfsops portal_vfsops = { - portal_mount, - portal_start, - portal_unmount, - portal_root, - portal_quotactl, - portal_statfs, - portal_sync, - portal_vget, - portal_fhtovp, - portal_vptofh, - portal_init, - portal_sysctl, -}; diff --git a/bsd/miscfs/portal/portal_vnops.c b/bsd/miscfs/portal/portal_vnops.c deleted file mode 100644 index 8059b1ca0..000000000 --- a/bsd/miscfs/portal/portal_vnops.c +++ /dev/null @@ -1,792 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ -/* - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software donated to Berkeley by - * Jan-Simon Pendry. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)portal_vnops.c 8.14 (Berkeley) 5/21/95 - * - * @(#)portal_vnops.c 8.8 (Berkeley) 1/21/94 - */ - -/* - * Portal Filesystem - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int portal_fileid = PORTAL_ROOTFILEID+1; - -static void -portal_closefd(p, fd) - struct proc *p; - int fd; -{ - int error; - struct { - int fd; - } ua; - int rc; - - ua.fd = fd; - error = close(p, &ua, &rc); - /* - * We should never get an error, and there isn't anything - * we could do if we got one, so just print a message. - */ - if (error) - printf("portal_closefd: error = %d\n", error); -} - -/* - * vp is the current namei directory - * cnp is the name to locate in that directory... - */ -int -portal_lookup(ap) - struct vop_lookup_args /* { - struct vnode * a_dvp; - struct vnode ** a_vpp; - struct componentname * a_cnp; - } */ *ap; -{ - struct componentname *cnp = ap->a_cnp; - struct vnode **vpp = ap->a_vpp; - struct vnode *dvp = ap->a_dvp; - char *pname = cnp->cn_nameptr; - struct portalnode *pt; - int error; - struct vnode *fvp = 0; - char *path; - int size; - - *vpp = NULLVP; - - if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) - return (EROFS); - - if (cnp->cn_namelen == 1 && *pname == '.') { - *vpp = dvp; - VREF(dvp); - /*VOP_LOCK(dvp);*/ - return (0); - } - - MALLOC(pt, void *, sizeof(struct portalnode), M_TEMP, M_WAITOK); - error = getnewvnode(VT_PORTAL, dvp->v_mount, portal_vnodeop_p, &fvp); - if (error) { - FREE(pt, M_TEMP); - goto bad; - } - fvp->v_type = VREG; - ubc_info_init(fvp); - fvp->v_data = pt; - - /* - * Save all of the remaining pathname and - * advance the namei next pointer to the end - * of the string. - */ - for (size = 0, path = pname; *path; path++) - size++; - cnp->cn_consume = size - cnp->cn_namelen; - - MALLOC(pt->pt_arg, caddr_t, size+1, M_TEMP, M_WAITOK); - pt->pt_size = size+1; - bcopy(pname, pt->pt_arg, pt->pt_size); - pt->pt_fileid = portal_fileid++; - - *vpp = fvp; - /*VOP_LOCK(fvp);*/ - return (0); - -bad: - if (fvp) - vrele(fvp); - return (error); -} - -/* This should be called only from network funnel */ -static int -portal_connect(so, so2) - struct socket *so; - struct socket *so2; -{ - /* from unp_connect, bypassing the namei stuff... */ - struct socket *so3; - struct unpcb *unp2; - struct unpcb *unp3; - - if (so2 == 0) - return (ECONNREFUSED); - - if (so->so_type != so2->so_type) - return (EPROTOTYPE); - - if ((so2->so_options & SO_ACCEPTCONN) == 0) - return (ECONNREFUSED); - - if ((so3 = sonewconn(so2, 0)) == 0) - return (ECONNREFUSED); - - unp2 = sotounpcb(so2); - unp3 = sotounpcb(so3); - if (unp2->unp_addr) - unp3->unp_addr = m_copy(unp2->unp_addr, 0, (int)M_COPYALL); - - so2 = so3; - - - return (unp_connect2(so, so2)); -} - -int -portal_open(ap) - struct vop_open_args /* { - struct vnode *a_vp; - int a_mode; - struct ucred *a_cred; - struct proc *a_p; - } */ *ap; -{ - struct socket *so = 0; - struct portalnode *pt; - struct proc *p = ap->a_p; - struct vnode *vp = ap->a_vp; - int s; - struct uio auio; - struct iovec aiov[2]; - int res; - struct mbuf *cm = 0; - struct cmsghdr *cmsg; - int newfds; - int *ip; - int fd; - int error; - int len; - struct portalmount *fmp; - struct file *fp; - struct portal_cred pcred; - - /* - * Nothing to do when opening the root node. - */ - if (vp->v_flag & VROOT) - return (0); - - /* - * Can't be opened unless the caller is set up - * to deal with the side effects. Check for this - * by testing whether the p_dupfd has been set. - */ - if (p->p_dupfd >= 0) - return (ENODEV); - - pt = VTOPORTAL(vp); - fmp = VFSTOPORTAL(vp->v_mount); - - /* - * Create a new socket. - */ - thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); - error = socreate(AF_UNIX, &so, SOCK_STREAM, 0); - if (error) { - thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); - goto bad; - } - - /* - * Reserve some buffer space - */ - res = pt->pt_size + sizeof(pcred) + 512; /* XXX */ - error = soreserve(so, res, res); - if (error) { - thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); - goto bad; - } - - /* - * Kick off connection - */ - error = portal_connect(so, (struct socket *)fmp->pm_server->f_data); - if (error) { - thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); - goto bad; - } - - /* - * Wait for connection to complete - */ - /* - * XXX: Since the mount point is holding a reference on the - * underlying server socket, it is not easy to find out whether - * the server process is still running. To handle this problem - * we loop waiting for the new socket to be connected (something - * which will only happen if the server is still running) or for - * the reference count on the server socket to drop to 1, which - * will happen if the server dies. Sleep for 5 second intervals - * and keep polling the reference count. XXX. - */ - s = splnet(); - while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { - if (fcount(fmp->pm_server) == 1) { - error = ECONNREFUSED; - splx(s); - thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); - goto bad; - } - (void) tsleep((caddr_t) &so->so_timeo, PSOCK, "portalcon", 5 * hz); - } - splx(s); - - if (so->so_error) { - error = so->so_error; - thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); - goto bad; - } - - /* - * Set miscellaneous flags - */ - so->so_rcv.sb_timeo = 0; - so->so_snd.sb_timeo = 0; - so->so_rcv.sb_flags |= SB_NOINTR; - so->so_snd.sb_flags |= SB_NOINTR; - - - pcred.pcr_flag = ap->a_mode; - pcred.pcr_uid = ap->a_cred->cr_uid; - pcred.pcr_ngroups = ap->a_cred->cr_ngroups; - bcopy(ap->a_cred->cr_groups, pcred.pcr_groups, NGROUPS * sizeof(gid_t)); - aiov[0].iov_base = (caddr_t) &pcred; - aiov[0].iov_len = sizeof(pcred); - aiov[1].iov_base = pt->pt_arg; - aiov[1].iov_len = pt->pt_size; - auio.uio_iov = aiov; - auio.uio_iovcnt = 2; - auio.uio_rw = UIO_WRITE; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_procp = p; - auio.uio_offset = 0; - auio.uio_resid = aiov[0].iov_len + aiov[1].iov_len; - - error = sosend(so, (struct sockaddr *) 0, &auio, - (struct mbuf *) 0, (struct mbuf *) 0, 0); - if (error) { - thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); - goto bad; - } - - len = auio.uio_resid = sizeof(int); - do { - struct mbuf *m = 0; - int flags = MSG_WAITALL; - error = soreceive(so, (struct sockaddr **) 0, &auio, - &m, &cm, &flags); - if (error) { - thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); - goto bad; - } - - /* - * Grab an error code from the mbuf. - */ - if (m) { - m = m_pullup(m, sizeof(int)); /* Needed? */ - if (m) { - error = *(mtod(m, int *)); - m_freem(m); - } else { - error = EINVAL; - } - } else { - if (cm == 0) { - error = ECONNRESET; /* XXX */ -#ifdef notdef - break; -#endif - } - } - } while (cm == 0 && auio.uio_resid == len && !error); - - if (cm == 0) { - thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); - goto bad; - } - - if (auio.uio_resid) { - error = 0; -#ifdef notdef - error = EMSGSIZE; - thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); - goto bad; -#endif - } - - /* - * XXX: Break apart the control message, and retrieve the - * received file descriptor. Note that more than one descriptor - * may have been received, or that the rights chain may have more - * than a single mbuf in it. What to do? - */ - cmsg = mtod(cm, struct cmsghdr *); - newfds = (cmsg->cmsg_len - sizeof(*cmsg)) / sizeof (int); - if (newfds == 0) { - error = ECONNREFUSED; - thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); - goto bad; - } - /* - * At this point the rights message consists of a control message - * header, followed by a data region containing a vector of - * integer file descriptors. The fds were allocated by the action - * of receiving the control message. - */ - thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); - ip = (int *) (cmsg + 1); - fd = *ip++; - if (newfds > 1) { - /* - * Close extra fds. - */ - int i; - printf("portal_open: %d extra fds\n", newfds - 1); - for (i = 1; i < newfds; i++) { - portal_closefd(p, *ip); - ip++; - } - } - - /* - * Check that the mode the file is being opened for is a subset - * of the mode of the existing descriptor. - */ - fp = *fdfile(p, fd); - if (((ap->a_mode & (FREAD|FWRITE)) | fp->f_flag) != fp->f_flag) { - portal_closefd(p, fd); - error = EACCES; - goto bad; - } - - /* - * Save the dup fd in the proc structure then return the - * special error code (ENXIO) which causes magic things to - * happen in vn_open. The whole concept is, well, hmmm. - */ - p->p_dupfd = fd; - error = ENXIO; - -bad:; - /* - * And discard the control message. - */ - if (cm) { - m_freem(cm); - } - - if (so) { - thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); - soshutdown(so, 2); - soclose(so); - thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); - } - return (error); -} - -int -portal_getattr(ap) - struct vop_getattr_args /* { - struct vnode *a_vp; - struct vattr *a_vap; - struct ucred *a_cred; - struct proc *a_p; - } */ *ap; -{ - struct vnode *vp = ap->a_vp; - struct vattr *vap = ap->a_vap; - struct timeval tv; - - bzero(vap, sizeof(*vap)); - vattr_null(vap); - vap->va_uid = 0; - vap->va_gid = 0; - vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; - vap->va_size = DEV_BSIZE; - vap->va_blocksize = DEV_BSIZE; - microtime(&tv); - TIMEVAL_TO_TIMESPEC(&tv, &vap->va_atime); - vap->va_mtime = vap->va_atime; - vap->va_ctime = vap->va_ctime; - vap->va_gen = 0; - vap->va_flags = 0; - vap->va_rdev = 0; - /* vap->va_qbytes = 0; */ - vap->va_bytes = 0; - /* vap->va_qsize = 0; */ - if (vp->v_flag & VROOT) { - vap->va_type = VDIR; - vap->va_mode = S_IRUSR|S_IWUSR|S_IXUSR| - S_IRGRP|S_IWGRP|S_IXGRP| - S_IROTH|S_IWOTH|S_IXOTH; - vap->va_nlink = 2; - vap->va_fileid = 2; - } else { - vap->va_type = VREG; - vap->va_mode = S_IRUSR|S_IWUSR| - S_IRGRP|S_IWGRP| - S_IROTH|S_IWOTH; - vap->va_nlink = 1; - vap->va_fileid = VTOPORTAL(vp)->pt_fileid; - } - return (0); -} - -int -portal_setattr(ap) - struct vop_setattr_args /* { - struct vnode *a_vp; - struct vattr *a_vap; - struct ucred *a_cred; - struct proc *a_p; - } */ *ap; -{ - - /* - * Can't mess with the root vnode - */ - if (ap->a_vp->v_flag & VROOT) - return (EACCES); - - return (0); -} - -/* - * Fake readdir, just return empty directory. - * It is hard to deal with '.' and '..' so don't bother. - */ -int -portal_readdir(ap) - struct vop_readdir_args /* { - struct vnode *a_vp; - struct uio *a_uio; - struct ucred *a_cred; - int *a_eofflag; - u_long *a_cookies; - int a_ncookies; - } */ *ap; -{ - - /* - * We don't allow exporting portal mounts, and currently local - * requests do not need cookies. - */ - if (ap->a_ncookies) - panic("portal_readdir: not hungry"); - - return (0); -} - -int -portal_inactive(ap) - struct vop_inactive_args /* { - struct vnode *a_vp; - struct proc *a_p; - } */ *ap; -{ - - VOP_UNLOCK(ap->a_vp, 0, ap->a_p); - return (0); -} - -int -portal_reclaim(ap) - struct vop_reclaim_args /* { - struct vnode *a_vp; - } */ *ap; -{ - struct portalnode *pt = VTOPORTAL(ap->a_vp); - - if (pt->pt_arg) { - _FREE((caddr_t) pt->pt_arg, M_TEMP); - pt->pt_arg = 0; - } - FREE(ap->a_vp->v_data, M_TEMP); - ap->a_vp->v_data = 0; - - return (0); -} - -/* - * Return POSIX pathconf information applicable to special devices. - */ -portal_pathconf(ap) - struct vop_pathconf_args /* { - struct vnode *a_vp; - int a_name; - int *a_retval; - } */ *ap; -{ - - switch (ap->a_name) { - case _PC_LINK_MAX: - *ap->a_retval = LINK_MAX; - return (0); - case _PC_MAX_CANON: - *ap->a_retval = MAX_CANON; - return (0); - case _PC_MAX_INPUT: - *ap->a_retval = MAX_INPUT; - return (0); - case _PC_PIPE_BUF: - *ap->a_retval = PIPE_BUF; - return (0); - case _PC_CHOWN_RESTRICTED: - *ap->a_retval = 1; - return (0); - case _PC_VDISABLE: - *ap->a_retval = _POSIX_VDISABLE; - return (0); - default: - return (EINVAL); - } - /* NOTREACHED */ -} - -/* - * Print out the contents of a Portal vnode. - */ -/* ARGSUSED */ -int -portal_print(ap) - struct vop_print_args /* { - struct vnode *a_vp; - } */ *ap; -{ - - printf("tag VT_PORTAL, portal vnode\n"); - return (0); -} - -/*void*/ -int -portal_vfree(ap) - struct vop_vfree_args /* { - struct vnode *a_pvp; - ino_t a_ino; - int a_mode; - } */ *ap; -{ - - return (0); -} - - -/* - * Portal vnode unsupported operation - */ -int -portal_enotsupp() -{ - - return (EOPNOTSUPP); -} - -/* - * Portal "should never get here" operation - */ -int -portal_badop() -{ - - panic("portal: bad op"); - /* NOTREACHED */ -} - -/* - * Portal vnode null operation - */ -int -portal_nullop() -{ - - return (0); -} - -#define portal_create ((int (*) __P((struct vop_create_args *)))portal_enotsupp) -#define portal_mknod ((int (*) __P((struct vop_mknod_args *)))portal_enotsupp) -#define portal_close ((int (*) __P((struct vop_close_args *)))nullop) -#define portal_access ((int (*) __P((struct vop_access_args *)))nullop) -#define portal_read ((int (*) __P((struct vop_read_args *)))portal_enotsupp) -#define portal_write ((int (*) __P((struct vop_write_args *)))portal_enotsupp) -#define portal_ioctl ((int (*) __P((struct vop_ioctl_args *)))portal_enotsupp) -#define portal_select ((int (*) __P((struct vop_select_args *)))portal_enotsupp) -#define portal_mmap ((int (*) __P((struct vop_mmap_args *)))portal_enotsupp) -#define portal_revoke vop_revoke -#define portal_fsync ((int (*) __P((struct vop_fsync_args *)))nullop) -#define portal_seek ((int (*) __P((struct vop_seek_args *)))nullop) -#define portal_remove ((int (*) __P((struct vop_remove_args *)))portal_enotsupp) -#define portal_link ((int (*) __P((struct vop_link_args *)))portal_enotsupp) -#define portal_rename ((int (*) __P((struct vop_rename_args *)))portal_enotsupp) -#define portal_mkdir ((int (*) __P((struct vop_mkdir_args *)))portal_enotsupp) -#define portal_rmdir ((int (*) __P((struct vop_rmdir_args *)))portal_enotsupp) -#define portal_symlink \ - ((int (*) __P((struct vop_symlink_args *)))portal_enotsupp) -#define portal_readlink \ - ((int (*) __P((struct vop_readlink_args *)))portal_enotsupp) -#define portal_abortop ((int (*) __P((struct vop_abortop_args *)))nullop) -#define portal_lock ((int (*) __P((struct vop_lock_args *)))vop_nolock) -#define portal_unlock ((int (*) __P((struct vop_unlock_args *)))vop_nounlock) -#define portal_bmap ((int (*) __P((struct vop_bmap_args *)))portal_badop) -#define portal_strategy \ - ((int (*) __P((struct vop_strategy_args *)))portal_badop) -#define portal_islocked \ - ((int (*) __P((struct vop_islocked_args *)))vop_noislocked) -#define fifo_islocked ((int(*) __P((struct vop_islocked_args *)))vop_noislocked) -#define portal_advlock \ - ((int (*) __P((struct vop_advlock_args *)))portal_enotsupp) -#define portal_blkatoff \ - ((int (*) __P((struct vop_blkatoff_args *)))portal_enotsupp) -#define portal_valloc ((int(*) __P(( \ - struct vnode *pvp, \ - int mode, \ - struct ucred *cred, \ - struct vnode **vpp))) portal_enotsupp) -#define portal_truncate \ - ((int (*) __P((struct vop_truncate_args *)))portal_enotsupp) -#define portal_update ((int (*) __P((struct vop_update_args *)))portal_enotsupp) -#define portal_copyfile ((int (*) __P((struct vop_copyfile *)))err_copyfile) -#define portal_bwrite ((int (*) __P((struct vop_bwrite_args *)))portal_enotsupp) -#define portal_blktooff \ - ((int (*) __P((struct vop_blktooff_args *)))portal_enotsupp) -#define portal_offtoblk \ - ((int (*) __P((struct vop_offtoblk_args *)))portal_enotsupp) -#define portal_cmap \ - ((int (*) __P((struct vop_cmap_args *)))portal_enotsupp) - -#define VOPFUNC int (*)(void *) - -int (**portal_vnodeop_p)(void *); -struct vnodeopv_entry_desc portal_vnodeop_entries[] = { - { &vop_default_desc, (VOPFUNC)vn_default_error }, - { &vop_lookup_desc, (VOPFUNC)portal_lookup }, /* lookup */ - { &vop_create_desc, (VOPFUNC)portal_create }, /* create */ - { &vop_mknod_desc, (VOPFUNC)portal_mknod }, /* mknod */ - { &vop_open_desc, (VOPFUNC)portal_open }, /* open */ - { &vop_close_desc, (VOPFUNC)portal_close }, /* close */ - { &vop_access_desc, (VOPFUNC)portal_access }, /* access */ - { &vop_getattr_desc, (VOPFUNC)portal_getattr }, /* getattr */ - { &vop_setattr_desc, (VOPFUNC)portal_setattr }, /* setattr */ - { &vop_read_desc, (VOPFUNC)portal_read }, /* read */ - { &vop_write_desc, (VOPFUNC)portal_write }, /* write */ - { &vop_ioctl_desc, (VOPFUNC)portal_ioctl }, /* ioctl */ - { &vop_select_desc, (VOPFUNC)portal_select }, /* select */ - { &vop_mmap_desc, (VOPFUNC)portal_mmap }, /* mmap */ - { &vop_revoke_desc, (VOPFUNC)portal_revoke }, /* revoke */ - { &vop_fsync_desc, (VOPFUNC)portal_fsync }, /* fsync */ - { &vop_seek_desc, (VOPFUNC)portal_seek }, /* seek */ - { &vop_remove_desc, (VOPFUNC)portal_remove }, /* remove */ - { &vop_link_desc, (VOPFUNC)portal_link }, /* link */ - { &vop_rename_desc, (VOPFUNC)portal_rename }, /* rename */ - { &vop_mkdir_desc, (VOPFUNC)portal_mkdir }, /* mkdir */ - { &vop_rmdir_desc, (VOPFUNC)portal_rmdir }, /* rmdir */ - { &vop_symlink_desc, (VOPFUNC)portal_symlink }, /* symlink */ - { &vop_readdir_desc, (VOPFUNC)portal_readdir }, /* readdir */ - { &vop_readlink_desc, (VOPFUNC)portal_readlink }, /* readlink */ - { &vop_abortop_desc, (VOPFUNC)portal_abortop }, /* abortop */ - { &vop_inactive_desc, (VOPFUNC)portal_inactive }, /* inactive */ - { &vop_reclaim_desc, (VOPFUNC)portal_reclaim }, /* reclaim */ - { &vop_lock_desc, (VOPFUNC)portal_lock }, /* lock */ - { &vop_unlock_desc, (VOPFUNC)portal_unlock }, /* unlock */ - { &vop_bmap_desc, (VOPFUNC)portal_bmap }, /* bmap */ - { &vop_strategy_desc, (VOPFUNC)portal_strategy }, /* strategy */ - { &vop_print_desc, (VOPFUNC)portal_print }, /* print */ - { &vop_islocked_desc, (VOPFUNC)portal_islocked }, /* islocked */ - { &vop_pathconf_desc, (VOPFUNC)portal_pathconf }, /* pathconf */ - { &vop_advlock_desc, (VOPFUNC)portal_advlock }, /* advlock */ - { &vop_blkatoff_desc, (VOPFUNC)portal_blkatoff }, /* blkatoff */ - { &vop_valloc_desc, (VOPFUNC)portal_valloc }, /* valloc */ - { &vop_vfree_desc, (VOPFUNC)portal_vfree }, /* vfree */ - { &vop_truncate_desc, (VOPFUNC)portal_truncate }, /* truncate */ - { &vop_update_desc, (VOPFUNC)portal_update }, /* update */ - { &vop_bwrite_desc, (VOPFUNC)portal_bwrite }, /* bwrite */ - { &vop_pagein_desc, (VOPFUNC)err_pagein }, /* Pagein */ - { &vop_pageout_desc, (VOPFUNC)err_pageout }, /* Pageout */ - { &vop_copyfile_desc, (VOPFUNC)portal_copyfile }, /* Copyfile */ - { &vop_blktooff_desc, (VOPFUNC)portal_blktooff }, /* blktooff */ - { &vop_blktooff_desc, (VOPFUNC)portal_offtoblk }, /* offtoblk */ - { &vop_cmap_desc, (VOPFUNC)portal_cmap }, /* cmap */ - { (struct vnodeop_desc*)NULL, (int(*)())NULL } -}; -struct vnodeopv_desc portal_vnodeop_opv_desc = - { &portal_vnodeop_p, portal_vnodeop_entries }; diff --git a/bsd/miscfs/procfs/procfs.h b/bsd/miscfs/procfs/procfs.h deleted file mode 100644 index 143366050..000000000 --- a/bsd/miscfs/procfs/procfs.h +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* $NetBSD: procfs.h,v 1.13 1995/03/29 22:08:30 briggs Exp $ */ - -/* - * Copyright (c) 1993 Jan-Simon Pendry - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Jan-Simon Pendry. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)procfs.h 8.7 (Berkeley) 6/15/94 - */ - -/* - * The different types of node in a procfs filesystem - */ -typedef enum { - Proot, /* the filesystem root */ - Pcurproc, /* symbolic link for curproc */ - Pproc, /* a process-specific sub-directory */ - Pfile, /* the executable file */ - Pmem, /* the process's memory image */ - Pregs, /* the process's register set */ - Pfpregs, /* the process's FP register set */ - Pctl, /* process control */ - Pstatus, /* process status */ - Pnote, /* process notifier */ - Pnotepg /* process group notifier */ -} pfstype; - -/* - * control data for the proc file system. - */ -struct pfsnode { - struct pfsnode *pfs_next; /* next on list */ - struct vnode *pfs_vnode; /* vnode associated with this pfsnode */ - pfstype pfs_type; /* type of procfs node */ - pid_t pfs_pid; /* associated process */ - u_short pfs_mode; /* mode bits for stat() */ - u_long pfs_flags; /* open flags */ - u_long pfs_fileno; /* unique file id */ -}; - -#define PROCFS_NOTELEN 64 /* max length of a note (/proc/$pid/note) */ -#define PROCFS_CTLLEN 8 /* max length of a ctl msg (/proc/$pid/ctl */ - -/* - * Kernel stuff follows - */ -#ifdef KERNEL -#define CNEQ(cnp, s, len) \ - ((cnp)->cn_namelen == (len) && \ - (bcmp((s), (cnp)->cn_nameptr, (len)) == 0)) - -/* - * Format of a directory entry in /proc, ... - * This must map onto struct dirent (see ) - */ -#define PROCFS_NAMELEN 8 -struct pfsdent { - u_int32_t d_fileno; - u_int16_t d_reclen; - u_int8_t d_type; - u_int8_t d_namlen; - char d_name[PROCFS_NAMELEN]; -}; -#define UIO_MX sizeof(struct pfsdent) -#define PROCFS_FILENO(pid, type) \ - (((type) < Pproc) ? \ - ((type) + 2) : \ - ((((pid)+1) << 4) + ((int) (type)))) - -/* - * Convert between pfsnode vnode - */ -#define VTOPFS(vp) ((struct pfsnode *)(vp)->v_data) -#define PFSTOV(pfs) ((pfs)->pfs_vnode) - -typedef struct vfs_namemap vfs_namemap_t; -struct vfs_namemap { - const char *nm_name; - int nm_val; -}; - -int vfs_getuserstr __P((struct uio *, char *, int *)); -vfs_namemap_t *vfs_findname __P((vfs_namemap_t *, char *, int)); - -#define PFIND(pid) ((pid) ? pfind(pid) : &kernel_proc) -int procfs_freevp __P((struct vnode *)); -int procfs_allocvp __P((struct mount *, struct vnode **, long, pfstype)); -struct vnode *procfs_findtextvp __P((struct proc *)); -int procfs_donote __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -int procfs_doregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -int procfs_dofpregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -int procfs_domem __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -int procfs_doctl __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -int procfs_dostatus __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); - -/* functions to check whether or not files should be displayed */ -int procfs_validfile __P((struct proc *)); -int procfs_validfpregs __P((struct proc *)); -int procfs_validregs __P((struct proc *)); - -#define PROCFS_LOCKED 0x01 -#define PROCFS_WANT 0x02 - -extern int (**procfs_vnodeop_p)(void *); -extern struct vfsops procfs_vfsops; - -/* - * Prototypes for procfs vnode ops - */ -int procfs_badop(); /* varargs */ -int procfs_rw __P((struct vop_read_args *)); -int procfs_lookup __P((struct vop_lookup_args *)); -#define procfs_create ((int (*) __P((struct vop_create_args *))) procfs_badop) -#define procfs_mknod ((int (*) __P((struct vop_mknod_args *))) procfs_badop) -int procfs_open __P((struct vop_open_args *)); -int procfs_close __P((struct vop_close_args *)); -int procfs_access __P((struct vop_access_args *)); -int procfs_getattr __P((struct vop_getattr_args *)); -int procfs_setattr __P((struct vop_setattr_args *)); -#define procfs_read procfs_rw -#define procfs_write procfs_rw -int procfs_ioctl __P((struct vop_ioctl_args *)); -#define procfs_select ((int (*) __P((struct vop_select_args *))) procfs_badop) -#define procfs_mmap ((int (*) __P((struct vop_mmap_args *))) procfs_badop) -#define procfs_fsync ((int (*) __P((struct vop_fsync_args *))) procfs_badop) -#define procfs_seek ((int (*) __P((struct vop_seek_args *))) procfs_badop) -#define procfs_remove ((int (*) __P((struct vop_remove_args *))) procfs_badop) -#define procfs_link ((int (*) __P((struct vop_link_args *))) procfs_badop) -#define procfs_rename ((int (*) __P((struct vop_rename_args *))) procfs_badop) -#define procfs_mkdir ((int (*) __P((struct vop_mkdir_args *))) procfs_badop) -#define procfs_rmdir ((int (*) __P((struct vop_rmdir_args *))) procfs_badop) -#define procfs_symlink ((int (*) __P((struct vop_symlink_args *))) procfs_badop) -int procfs_readdir __P((struct vop_readdir_args *)); -int procfs_readlink __P((struct vop_readlink_args *)); -int procfs_abortop __P((struct vop_abortop_args *)); -int procfs_inactive __P((struct vop_inactive_args *)); -int procfs_reclaim __P((struct vop_reclaim_args *)); -#define procfs_lock ((int (*) __P((struct vop_lock_args *))) nullop) -#define procfs_unlock ((int (*) __P((struct vop_unlock_args *))) nullop) -int procfs_bmap __P((struct vop_bmap_args *)); -#define procfs_strategy ((int (*) __P((struct vop_strategy_args *))) procfs_badop) -int procfs_print __P((struct vop_print_args *)); -#define procfs_islocked ((int (*) __P((struct vop_islocked_args *))) nullop) -#define procfs_advlock ((int (*) __P((struct vop_advlock_args *))) procfs_badop) -#define procfs_blkatoff ((int (*) __P((struct vop_blkatoff_args *))) procfs_badop) -#define procfs_valloc ((int (*) __P((struct vop_valloc_args *))) procfs_badop) -#define procfs_vfree ((int (*) __P((struct vop_vfree_args *))) nullop) -#define procfs_truncate ((int (*) __P((struct vop_truncate_args *))) procfs_badop) -#define procfs_update ((int (*) __P((struct vop_update_args *))) nullop) -#endif /* KERNEL */ diff --git a/bsd/miscfs/procfs/procfs_ctl.c b/bsd/miscfs/procfs/procfs_ctl.c deleted file mode 100644 index 8b5854ed3..000000000 --- a/bsd/miscfs/procfs/procfs_ctl.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* $NetBSD: procfs_ctl.c,v 1.12 1994/06/29 06:34:46 cgd Exp $ */ - -/* - * Copyright (c) 1993 Jan-Simon Pendry - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Jan-Simon Pendry. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)procfs_ctl.c 8.4 (Berkeley) 6/15/94 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * True iff process (p) is in trace wait state - * relative to process (curp) - */ -#define TRACE_WAIT_P(curp, p) \ - ((p)->p_stat == SSTOP && \ - (p)->p_pptr == (curp) && \ - ((p)->p_flag & P_TRACED)) - -#define PROCFS_CTL_ATTACH 1 -#define PROCFS_CTL_DETACH 2 -#define PROCFS_CTL_STEP 3 -#define PROCFS_CTL_RUN 4 -#define PROCFS_CTL_WAIT 5 - -static vfs_namemap_t ctlnames[] = { - /* special /proc commands */ - { "attach", PROCFS_CTL_ATTACH }, - { "detach", PROCFS_CTL_DETACH }, - { "step", PROCFS_CTL_STEP }, - { "run", PROCFS_CTL_RUN }, - { "wait", PROCFS_CTL_WAIT }, - { 0 }, -}; - -static vfs_namemap_t signames[] = { - /* regular signal names */ - { "hup", SIGHUP }, { "int", SIGINT }, - { "quit", SIGQUIT }, { "ill", SIGILL }, - { "trap", SIGTRAP }, { "abrt", SIGABRT }, - { "iot", SIGIOT }, { "emt", SIGEMT }, - { "fpe", SIGFPE }, { "kill", SIGKILL }, - { "bus", SIGBUS }, { "segv", SIGSEGV }, - { "sys", SIGSYS }, { "pipe", SIGPIPE }, - { "alrm", SIGALRM }, { "term", SIGTERM }, - { "urg", SIGURG }, { "stop", SIGSTOP }, - { "tstp", SIGTSTP }, { "cont", SIGCONT }, - { "chld", SIGCHLD }, { "ttin", SIGTTIN }, - { "ttou", SIGTTOU }, { "io", SIGIO }, - { "xcpu", SIGXCPU }, { "xfsz", SIGXFSZ }, - { "vtalrm", SIGVTALRM }, { "prof", SIGPROF }, - { "winch", SIGWINCH }, { "info", SIGINFO }, - { "usr1", SIGUSR1 }, { "usr2", SIGUSR2 }, - { 0 }, -}; - -static int -procfs_control(curp, p, op) - struct proc *curp; - struct proc *p; - int op; -{ - int error; - - /* - * Attach - attaches the target process for debugging - * by the calling process. - */ - if (op == PROCFS_CTL_ATTACH) { - /* check whether already being traced */ - if (p->p_flag & P_TRACED) - return (EBUSY); - - /* can't trace yourself! */ - if (p->p_pid == curp->p_pid) - return (EINVAL); - - /* - * Go ahead and set the trace flag. - * Save the old parent (it's reset in - * _DETACH, and also in kern_exit.c:wait4() - * Reparent the process so that the tracing - * proc gets to see all the action. - * Stop the target. - */ - p->p_flag |= P_TRACED; - p->p_xstat = 0; /* XXX ? */ - if (p->p_pptr != curp) { - p->p_oppid = p->p_pptr->p_pid; - proc_reparent(p, curp); - } - psignal(p, SIGSTOP); - return (0); - } - - /* - * Target process must be stopped, owned by (curp) and - * be set up for tracing (P_TRACED flag set). - * Allow DETACH to take place at any time for sanity. - * Allow WAIT any time, of course. - */ - switch (op) { - case PROCFS_CTL_DETACH: - case PROCFS_CTL_WAIT: - break; - - default: - if (!TRACE_WAIT_P(curp, p)) - return (EBUSY); - } - - /* - * do single-step fixup if needed - */ - FIX_SSTEP(p); - - /* - * Don't deliver any signal by default. - * To continue with a signal, just send - * the signal name to the ctl file - */ - p->p_xstat = 0; - - switch (op) { - /* - * Detach. Cleans up the target process, reparent it if possible - * and set it running once more. - */ - case PROCFS_CTL_DETACH: - /* if not being traced, then this is a painless no-op */ - if ((p->p_flag & P_TRACED) == 0) - return (0); - - /* not being traced any more */ - p->p_flag &= ~P_TRACED; - - /* give process back to original parent */ - if (p->p_oppid != p->p_pptr->p_pid) { - struct proc *pp; - - pp = pfind(p->p_oppid); - if (pp) - proc_reparent(p, pp); - } - - p->p_oppid = 0; - p->p_flag &= ~P_WAITED; /* XXX ? */ - wakeup((caddr_t) curp); /* XXX for CTL_WAIT below ? */ - - break; - - /* - * Step. Let the target process execute a single instruction. - */ - case PROCFS_CTL_STEP: - if (error = process_sstep(p, 1)) - return (error); - break; - - /* - * Run. Let the target process continue running until a breakpoint - * or some other trap. - */ - case PROCFS_CTL_RUN: - break; - - /* - * Wait for the target process to stop. - * If the target is not being traced then just wait - * to enter - */ - case PROCFS_CTL_WAIT: - error = 0; - if (p->p_flag & P_TRACED) { - while (error == 0 && - (p->p_stat != SSTOP) && - (p->p_flag & P_TRACED) && - (p->p_pptr == curp)) { - error = tsleep((caddr_t) p, - PWAIT|PCATCH, "procfsx", 0); - } - if (error == 0 && !TRACE_WAIT_P(curp, p)) - error = EBUSY; - } else { - while (error == 0 && p->p_stat != SSTOP) { - error = tsleep((caddr_t) p, - PWAIT|PCATCH, "procfs", 0); - } - } - return (error); - - default: - panic("procfs_control"); - } - - if (p->p_stat == SSTOP) - setrunnable(p); - return (0); -} - -int -procfs_doctl(curp, p, pfs, uio) - struct proc *curp; - struct pfsnode *pfs; - struct uio *uio; - struct proc *p; -{ - int xlen; - int error; - char msg[PROCFS_CTLLEN+1]; - vfs_namemap_t *nm; - - if (uio->uio_rw != UIO_WRITE) - return (EOPNOTSUPP); - - xlen = PROCFS_CTLLEN; - error = vfs_getuserstr(uio, msg, &xlen); - if (error) - return (error); - - /* - * Map signal names into signal generation - * or debug control. Unknown commands and/or signals - * return EOPNOTSUPP. - * - * Sending a signal while the process is being debugged - * also has the side effect of letting the target continue - * to run. There is no way to single-step a signal delivery. - */ - error = EOPNOTSUPP; - - nm = vfs_findname(ctlnames, msg, xlen); - if (nm) { - error = procfs_control(curp, p, nm->nm_val); - } else { - nm = vfs_findname(signames, msg, xlen); - if (nm) { - if (TRACE_WAIT_P(curp, p)) { - p->p_xstat = nm->nm_val; - FIX_SSTEP(p); - setrunnable(p); - } else { - psignal(p, nm->nm_val); - } - error = 0; - } - } - - return (error); -} diff --git a/bsd/miscfs/procfs/procfs_fpregs.c b/bsd/miscfs/procfs/procfs_fpregs.c deleted file mode 100644 index 58c8d5a41..000000000 --- a/bsd/miscfs/procfs/procfs_fpregs.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* $NetBSD: procfs_fpregs.c,v 1.3 1994/06/29 06:34:48 cgd Exp $ */ - -/* - * Copyright (c) 1993 Jan-Simon Pendry - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Jan-Simon Pendry. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)procfs_fpregs.c 8.2 (Berkeley) 6/15/94 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int -procfs_dofpregs(curp, p, pfs, uio) - struct proc *curp; - struct proc *p; - struct pfsnode *pfs; - struct uio *uio; -{ -#if defined(PT_GETFPREGS) || defined(PT_SETFPREGS) - int error; - struct fpreg r; - char *kv; - int kl; - - kl = sizeof(r); - kv = (char *) &r; - - kv += uio->uio_offset; - kl -= uio->uio_offset; - if (kl > uio->uio_resid) - kl = uio->uio_resid; - - if (kl < 0) - error = EINVAL; - else - error = process_read_fpregs(p, &r); - if (error == 0) - error = uiomove(kv, kl, uio); - if (error == 0 && uio->uio_rw == UIO_WRITE) { - if (p->p_stat != SSTOP) - error = EBUSY; - else - error = process_write_fpregs(p, &r); - } - - uio->uio_offset = 0; - return (error); -#else - return (EINVAL); -#endif -} - -int -procfs_validfpregs(p) - struct proc *p; -{ - -#if defined(PT_SETFPREGS) || defined(PT_GETFPREGS) - return ((p->p_flag & P_SYSTEM) == 0); -#else - return (0); -#endif -} diff --git a/bsd/miscfs/procfs/procfs_mem.c b/bsd/miscfs/procfs/procfs_mem.c deleted file mode 100644 index 37830f9c0..000000000 --- a/bsd/miscfs/procfs/procfs_mem.c +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* $NetBSD: procfs_mem.c,v 1.7 1995/01/05 07:10:54 chopps Exp $ */ - -/* - * Copyright (c) 1993 Jan-Simon Pendry - * Copyright (c) 1993 Sean Eric Fagan - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Jan-Simon Pendry and Sean Eric Fagan. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)procfs_mem.c 8.5 (Berkeley) 6/15/94 - */ - -/* - * This is a lightly hacked and merged version - * of sef's pread/pwrite functions - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int -procfs_rwmem(p, uio) - struct proc *p; - struct uio *uio; -{ - int error; - int writing; - - writing = uio->uio_rw == UIO_WRITE; - - /* - * Only map in one page at a time. We don't have to, but it - * makes things easier. This way is trivial - right? - */ - do { - vm_map_t map, tmap; - vm_object_t object; - vm_offset_t kva; - vm_offset_t uva; - int page_offset; /* offset into page */ - vm_offset_t pageno; /* page number */ - vm_map_entry_t out_entry; - vm_prot_t out_prot; - vm_page_t m; - boolean_t wired, single_use; - vm_offset_t off; - u_int len; - int fix_prot; - - uva = (vm_offset_t) uio->uio_offset; - if (uva > VM_MAXUSER_ADDRESS) { - error = 0; - break; - } - - /* - * Get the page number of this segment. - */ - pageno = trunc_page(uva); - page_offset = uva - pageno; - - /* - * How many bytes to copy - */ - len = min(PAGE_SIZE - page_offset, uio->uio_resid); - - /* - * The map we want... - */ - map = &p->p_vmspace->vm_map; - - /* - * Check the permissions for the area we're interested - * in. - */ - fix_prot = 0; - if (writing) - fix_prot = !vm_map_check_protection(map, pageno, - pageno + PAGE_SIZE, VM_PROT_WRITE); - - if (fix_prot) { - /* - * If the page is not writable, we make it so. - * XXX It is possible that a page may *not* be - * read/executable, if a process changes that! - * We will assume, for now, that a page is either - * VM_PROT_ALL, or VM_PROT_READ|VM_PROT_EXECUTE. - */ - error = vm_map_protect(map, pageno, - pageno + PAGE_SIZE, VM_PROT_ALL, 0); - if (error) - break; - } - - /* - * Now we need to get the page. out_entry, out_prot, wired, - * and single_use aren't used. One would think the vm code - * would be a *bit* nicer... We use tmap because - * vm_map_lookup() can change the map argument. - */ - tmap = map; - error = vm_map_lookup(&tmap, pageno, - writing ? VM_PROT_WRITE : VM_PROT_READ, - &out_entry, &object, &off, &out_prot, - &wired, &single_use); - /* - * We're done with tmap now. - */ - if (!error) - vm_map_lookup_done(tmap, out_entry); - - /* - * Fault the page in... - */ - if (!error && writing && object->shadow) { - m = vm_page_lookup(object, off); - if (m == 0 || (m->flags & PG_COPYONWRITE)) - error = vm_fault(map, pageno, - VM_PROT_WRITE, FALSE); - } - - /* Find space in kernel_map for the page we're interested in */ - if (!error) { - kva = VM_MIN_KERNEL_ADDRESS; - error = vm_map_find(kernel_map, object, off, &kva, - PAGE_SIZE, 1); - } - - if (!error) { - /* - * Neither vm_map_lookup() nor vm_map_find() appear - * to add a reference count to the object, so we do - * that here and now. - */ - vm_object_reference(object); - - /* - * Mark the page we just found as pageable. - */ - error = vm_map_pageable(kernel_map, kva, - kva + PAGE_SIZE, 0); - - /* - * Now do the i/o move. - */ - if (!error) - error = uiomove(kva + page_offset, len, uio); - - vm_map_remove(kernel_map, kva, kva + PAGE_SIZE); - } - if (fix_prot) - vm_map_protect(map, pageno, pageno + PAGE_SIZE, - VM_PROT_READ|VM_PROT_EXECUTE, 0); - } while (error == 0 && uio->uio_resid > 0); - - return (error); -} - -/* - * Copy data in and out of the target process. - * We do this by mapping the process's page into - * the kernel and then doing a uiomove direct - * from the kernel address space. - */ -int -procfs_domem(curp, p, pfs, uio) - struct proc *curp; - struct proc *p; - struct pfsnode *pfs; - struct uio *uio; -{ - - if (uio->uio_resid == 0) - return (0); - - return (procfs_rwmem(p, uio)); -} - -/* - * Given process (p), find the vnode from which - * it's text segment is being executed. - * - * It would be nice to grab this information from - * the VM system, however, there is no sure-fire - * way of doing that. Instead, fork(), exec() and - * wait() all maintain the p_textvp field in the - * process proc structure which contains a held - * reference to the exec'ed vnode. - */ -struct vnode * -procfs_findtextvp(p) - struct proc *p; -{ - - return (p->p_textvp); -} - - -#ifdef probably_never -/* - * Given process (p), find the vnode from which - * it's text segment is being mapped. - * - * (This is here, rather than in procfs_subr in order - * to keep all the VM related code in one place.) - */ -struct vnode * -procfs_findtextvp(p) - struct proc *p; -{ - int error; - vm_object_t object; - vm_offset_t pageno; /* page number */ - - /* find a vnode pager for the user address space */ - - for (pageno = VM_MIN_ADDRESS; - pageno < VM_MAXUSER_ADDRESS; - pageno += PAGE_SIZE) { - vm_map_t map; - vm_map_entry_t out_entry; - vm_prot_t out_prot; - boolean_t wired, single_use; - vm_offset_t off; - - map = &p->p_vmspace->vm_map; - error = vm_map_lookup(&map, pageno, - VM_PROT_READ, - &out_entry, &object, &off, &out_prot, - &wired, &single_use); - - if (!error) { - vm_pager_t pager; - - printf("procfs: found vm object\n"); - vm_map_lookup_done(map, out_entry); - printf("procfs: vm object = %x\n", object); - - /* - * At this point, assuming no errors, object - * is the VM object mapping UVA (pageno). - * Ensure it has a vnode pager, then grab - * the vnode from that pager's handle. - */ - - pager = object->pager; - printf("procfs: pager = %x\n", pager); - if (pager) - printf("procfs: found pager, type = %d\n", pager->pg_type); - if (pager && pager->pg_type == PG_VNODE) { - struct vnode *vp; - - vp = (struct vnode *) pager->pg_handle; - printf("procfs: vp = 0x%x\n", vp); - return (vp); - } - } - } - - printf("procfs: text object not found\n"); - return (0); -} -#endif /* probably_never */ diff --git a/bsd/miscfs/procfs/procfs_note.c b/bsd/miscfs/procfs/procfs_note.c deleted file mode 100644 index 3f9d2c080..000000000 --- a/bsd/miscfs/procfs/procfs_note.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* $NetBSD: procfs_note.c,v 1.8 1994/06/29 06:34:53 cgd Exp $ */ - -/* - * Copyright (c) 1993 Jan-Simon Pendry - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Jan-Simon Pendry. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)procfs_note.c 8.2 (Berkeley) 1/21/94 - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -int -procfs_donote(curp, p, pfs, uio) - struct proc *curp; - struct proc *p; - struct pfsnode *pfs; - struct uio *uio; -{ - int xlen; - int error; - char note[PROCFS_NOTELEN+1]; - - if (uio->uio_rw != UIO_WRITE) - return (EINVAL); - - xlen = PROCFS_NOTELEN; - error = vfs_getuserstr(uio, note, &xlen); - if (error) - return (error); - - /* send to process's notify function */ - return (EOPNOTSUPP); -} diff --git a/bsd/miscfs/procfs/procfs_regs.c b/bsd/miscfs/procfs/procfs_regs.c deleted file mode 100644 index eb0998939..000000000 --- a/bsd/miscfs/procfs/procfs_regs.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* $NetBSD: procfs_regs.c,v 1.8 1994/06/29 06:34:54 cgd Exp $ */ - -/* - * Copyright (c) 1993 Jan-Simon Pendry - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Jan-Simon Pendry. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)procfs_regs.c 8.4 (Berkeley) 6/15/94 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int -procfs_doregs(curp, p, pfs, uio) - struct proc *curp; - struct proc *p; - struct pfsnode *pfs; - struct uio *uio; -{ -#if defined(PT_GETREGS) || defined(PT_SETREGS) - int error; - struct reg r; - char *kv; - int kl; - - kl = sizeof(r); - kv = (char *) &r; - - kv += uio->uio_offset; - kl -= uio->uio_offset; - if (kl > uio->uio_resid) - kl = uio->uio_resid; - - if (kl < 0) - error = EINVAL; - else - error = process_read_regs(p, &r); - if (error == 0) - error = uiomove(kv, kl, uio); - if (error == 0 && uio->uio_rw == UIO_WRITE) { - if (p->p_stat != SSTOP) - error = EBUSY; - else - error = process_write_regs(p, &r); - } - - uio->uio_offset = 0; - return (error); -#else - return (EINVAL); -#endif -} - -int -procfs_validregs(p) - struct proc *p; -{ - -#if defined(PT_SETREGS) || defined(PT_GETREGS) - return ((p->p_flag & P_SYSTEM) == 0); -#else - return (0); -#endif -} diff --git a/bsd/miscfs/procfs/procfs_status.c b/bsd/miscfs/procfs/procfs_status.c deleted file mode 100644 index 0d5def29d..000000000 --- a/bsd/miscfs/procfs/procfs_status.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* $NetBSD: procfs_status.c,v 1.9 1994/06/29 06:34:56 cgd Exp $ */ - -/* - * Copyright (c) 1993 Jan-Simon Pendry - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Jan-Simon Pendry. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)procfs_status.c 8.4 (Berkeley) 6/15/94 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int -procfs_dostatus(curp, p, pfs, uio) - struct proc *curp; - struct proc *p; - struct pfsnode *pfs; - struct uio *uio; -{ - struct session *sess; - struct tty *tp; - struct ucred *cr; - char *ps; - char *sep; - int pid, ppid, pgid, sid; - int i; - int xlen; - int error; - char psbuf[256]; /* XXX - conservative */ - - if (uio->uio_rw != UIO_READ) - return (EOPNOTSUPP); - - pid = p->p_pid; - ppid = p->p_pptr ? p->p_pptr->p_pid : 0, - pgid = p->p_pgrp->pg_id; - sess = p->p_pgrp->pg_session; - sid = sess->s_leader ? sess->s_leader->p_pid : 0; - -/* comm pid ppid pgid sid maj,min ctty,sldr start ut st wmsg uid groups ... */ - - ps = psbuf; - bcopy(p->p_comm, ps, MAXCOMLEN); - ps[MAXCOMLEN] = '\0'; - ps += strlen(ps); - ps += sprintf(ps, " %d %d %d %d ", pid, ppid, pgid, sid); - - if ((p->p_flag&P_CONTROLT) && (tp = sess->s_ttyp)) - ps += sprintf(ps, "%d,%d ", major(tp->t_dev), minor(tp->t_dev)); - else - ps += sprintf(ps, "%d,%d ", -1, -1); - - sep = ""; - if (sess->s_ttyvp) { - ps += sprintf(ps, "%sctty", sep); - sep = ","; - } - if (SESS_LEADER(p)) { - ps += sprintf(ps, "%ssldr", sep); - sep = ","; - } - if (*sep != ',') - ps += sprintf(ps, "noflags"); - - if (p->p_flag & P_INMEM) - ps += sprintf(ps, " %d,%d", - p->p_stats->p_start.tv_sec, - p->p_stats->p_start.tv_usec); - else - ps += sprintf(ps, " -1,-1"); - - { - struct timeval ut, st; - - calcru(p, &ut, &st, (void *) 0); - ps += sprintf(ps, " %d,%d %d,%d", - ut.tv_sec, - ut.tv_usec, - st.tv_sec, - st.tv_usec); - } - - ps += sprintf(ps, " %s", - (p->p_wchan && p->p_wmesg) ? p->p_wmesg : "nochan"); - - cr = p->p_ucred; - - ps += sprintf(ps, " %d", cr->cr_uid); - for (i = 0; i < cr->cr_ngroups; i++) - ps += sprintf(ps, ",%d", cr->cr_groups[i]); - ps += sprintf(ps, "\n"); - - xlen = ps - psbuf; - xlen -= uio->uio_offset; - ps = psbuf + uio->uio_offset; - xlen = imin(xlen, uio->uio_resid); - if (xlen <= 0) - error = 0; - else - error = uiomove(ps, xlen, uio); - - return (error); -} diff --git a/bsd/miscfs/procfs/procfs_subr.c b/bsd/miscfs/procfs/procfs_subr.c deleted file mode 100644 index dc245204d..000000000 --- a/bsd/miscfs/procfs/procfs_subr.c +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* $NetBSD: procfs_subr.c,v 1.13 1994/06/29 06:34:57 cgd Exp $ */ - -/* - * Copyright (c) 1993 Jan-Simon Pendry - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Jan-Simon Pendry. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)procfs_subr.c 8.5 (Berkeley) 6/15/94 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct pfsnode *pfshead; -static int pfsvplock; - -/* - * allocate a pfsnode/vnode pair. the vnode is - * referenced, but not locked. - * - * the pid, pfs_type, and mount point uniquely - * identify a pfsnode. the mount point is needed - * because someone might mount this filesystem - * twice. - * - * all pfsnodes are maintained on a singly-linked - * list. new nodes are only allocated when they cannot - * be found on this list. entries on the list are - * removed when the vfs reclaim entry is called. - * - * a single lock is kept for the entire list. this is - * needed because the getnewvnode() function can block - * waiting for a vnode to become free, in which case there - * may be more than one process trying to get the same - * vnode. this lock is only taken if we are going to - * call getnewvnode, since the kernel itself is single-threaded. - * - * if an entry is found on the list, then call vget() to - * take a reference. this is done because there may be - * zero references to it and so it needs to removed from - * the vnode free list. - */ -int -procfs_allocvp(mp, vpp, pid, pfs_type) - struct mount *mp; - struct vnode **vpp; - long pid; - pfstype pfs_type; -{ - struct pfsnode *pfs; - struct vnode *vp; - struct pfsnode **pp; - int error; - -loop: - for (pfs = pfshead; pfs != 0; pfs = pfs->pfs_next) { - vp = PFSTOV(pfs); - if (pfs->pfs_pid == pid && - pfs->pfs_type == pfs_type && - vp->v_mount == mp) { - if (vget(vp, 0, current_proc())) - goto loop; - *vpp = vp; - return (0); - } - } - - /* - * otherwise lock the vp list while we call getnewvnode - * since that can block. - */ - if (pfsvplock & PROCFS_LOCKED) { - pfsvplock |= PROCFS_WANT; - sleep((caddr_t) &pfsvplock, PINOD); - goto loop; - } - pfsvplock |= PROCFS_LOCKED; - - MALLOC(pfs, void *, sizeof(struct pfsnode), M_TEMP, M_WAITOK); - if (error = getnewvnode(VT_PROCFS, mp, procfs_vnodeop_p, vpp)) { - FREE(pfs, M_TEMP); - goto out; - } - vp = *vpp; - vp->v_data = pfs; - - pfs->pfs_next = 0; - pfs->pfs_pid = (pid_t) pid; - pfs->pfs_type = pfs_type; - pfs->pfs_vnode = vp; - pfs->pfs_flags = 0; - pfs->pfs_fileno = PROCFS_FILENO(pid, pfs_type); - - switch (pfs_type) { - case Proot: /* /proc = dr-xr-xr-x */ - pfs->pfs_mode = (VREAD|VEXEC) | - (VREAD|VEXEC) >> 3 | - (VREAD|VEXEC) >> 6; - vp->v_type = VDIR; - vp->v_flag |= VROOT; - break; - - case Pcurproc: /* /proc/curproc = lr--r--r-- */ - pfs->pfs_mode = (VREAD) | - (VREAD >> 3) | - (VREAD >> 6); - vp->v_type = VLNK; - break; - - case Pproc: - pfs->pfs_mode = (VREAD|VEXEC) | - (VREAD|VEXEC) >> 3 | - (VREAD|VEXEC) >> 6; - vp->v_type = VDIR; - break; - - case Pfile: - case Pmem: - case Pregs: - case Pfpregs: - pfs->pfs_mode = (VREAD|VWRITE); - vp->v_type = VREG; - break; - - case Pctl: - case Pnote: - case Pnotepg: - pfs->pfs_mode = (VWRITE); - vp->v_type = VREG; - break; - - case Pstatus: - pfs->pfs_mode = (VREAD) | - (VREAD >> 3) | - (VREAD >> 6); - vp->v_type = VREG; - break; - - default: - panic("procfs_allocvp"); - } - - if (vp->v_type == VREG) - ubc_info_init(vp); - - /* add to procfs vnode list */ - for (pp = &pfshead; *pp; pp = &(*pp)->pfs_next) - continue; - *pp = pfs; - -out: - pfsvplock &= ~PROCFS_LOCKED; - - if (pfsvplock & PROCFS_WANT) { - pfsvplock &= ~PROCFS_WANT; - wakeup((caddr_t) &pfsvplock); - } - - return (error); -} - -int -procfs_freevp(vp) - struct vnode *vp; -{ - struct pfsnode **pfspp; - struct pfsnode *pfs = VTOPFS(vp); - - for (pfspp = &pfshead; *pfspp != 0; pfspp = &(*pfspp)->pfs_next) { - if (*pfspp == pfs) { - *pfspp = pfs->pfs_next; - break; - } - } - - FREE(vp->v_data, M_TEMP); - vp->v_data = 0; - return (0); -} - -int -procfs_rw(ap) - struct vop_read_args *ap; -{ - struct vnode *vp = ap->a_vp; - struct uio *uio = ap->a_uio; - struct proc *curp = uio->uio_procp; - struct pfsnode *pfs = VTOPFS(vp); - struct proc *p; - - p = PFIND(pfs->pfs_pid); - if (p == 0) - return (EINVAL); - - switch (pfs->pfs_type) { - case Pnote: - case Pnotepg: - return (procfs_donote(curp, p, pfs, uio)); - - case Pregs: - return (procfs_doregs(curp, p, pfs, uio)); - - case Pfpregs: - return (procfs_dofpregs(curp, p, pfs, uio)); - - case Pctl: - return (procfs_doctl(curp, p, pfs, uio)); - - case Pstatus: - return (procfs_dostatus(curp, p, pfs, uio)); - - case Pmem: - return (procfs_domem(curp, p, pfs, uio)); - - default: - return (EOPNOTSUPP); - } -} - -/* - * Get a string from userland into (buf). Strip a trailing - * nl character (to allow easy access from the shell). - * The buffer should be *buflenp + 1 chars long. vfs_getuserstr - * will automatically add a nul char at the end. - * - * Returns 0 on success or the following errors - * - * EINVAL: file offset is non-zero. - * EMSGSIZE: message is longer than kernel buffer - * EFAULT: user i/o buffer is not addressable - */ -int -vfs_getuserstr(uio, buf, buflenp) - struct uio *uio; - char *buf; - int *buflenp; -{ - int xlen; - int error; - - if (uio->uio_offset != 0) - return (EINVAL); - - xlen = *buflenp; - - /* must be able to read the whole string in one go */ - if (xlen < uio->uio_resid) - return (EMSGSIZE); - xlen = uio->uio_resid; - - if (error = uiomove(buf, xlen, uio)) - return (error); - - /* allow multiple writes without seeks */ - uio->uio_offset = 0; - - /* cleanup string and remove trailing newline */ - buf[xlen] = '\0'; - xlen = strlen(buf); - if (xlen > 0 && buf[xlen-1] == '\n') - buf[--xlen] = '\0'; - *buflenp = xlen; - - return (0); -} - -vfs_namemap_t * -vfs_findname(nm, buf, buflen) - vfs_namemap_t *nm; - char *buf; - int buflen; -{ - - for (; nm->nm_name; nm++) - if (bcmp(buf, (char *) nm->nm_name, buflen+1) == 0) - return (nm); - - return (0); -} diff --git a/bsd/miscfs/procfs/procfs_vfsops.c b/bsd/miscfs/procfs/procfs_vfsops.c deleted file mode 100644 index ef382ca6c..000000000 --- a/bsd/miscfs/procfs/procfs_vfsops.c +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* $NetBSD: procfs_vfsops.c,v 1.23 1995/03/09 12:05:54 mycroft Exp $ */ - -/* - * Copyright (c) 1993 Jan-Simon Pendry - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Jan-Simon Pendry. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)procfs_vfsops.c 8.5 (Berkeley) 6/15/94 - */ - -/* - * procfs VFS interface - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for PAGE_SIZE */ - -/* - * VFS Operations. - * - * mount system call - */ -/* ARGSUSED */ -procfs_mount(mp, path, data, ndp, p) - struct mount *mp; - char *path; - caddr_t data; - struct nameidata *ndp; - struct proc *p; -{ - size_t size; - - if (UIO_MX & (UIO_MX-1)) { - log(LOG_ERR, "procfs: invalid directory entry size"); - return (EINVAL); - } - - if (mp->mnt_flag & MNT_UPDATE) - return (EOPNOTSUPP); - - mp->mnt_flag |= MNT_LOCAL; - mp->mnt_data = 0; - getnewfsid(mp, makefstype(MOUNT_PROCFS)); - - (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN, &size); - bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); - bzero(mp->mnt_stat.f_mntfromname, MNAMELEN); - bcopy("procfs", mp->mnt_stat.f_mntfromname, sizeof("procfs")); - return (0); -} - -/* - * unmount system call - */ -procfs_unmount(mp, mntflags, p) - struct mount *mp; - int mntflags; - struct proc *p; -{ - int error; - extern int doforce; - int flags = 0; - - if (mntflags & MNT_FORCE) { - /* procfs can never be rootfs so don't check for it */ - if (!doforce) - return (EINVAL); - flags |= FORCECLOSE; - } - - if (error = vflush(mp, 0, flags)) - return (error); - - return (0); -} - -procfs_root(mp, vpp) - struct mount *mp; - struct vnode **vpp; -{ - - return (procfs_allocvp(mp, vpp, 0, Proot)); -} - -/* ARGSUSED */ -procfs_start(mp, flags, p) - struct mount *mp; - int flags; - struct proc *p; -{ - - return (0); -} - -/* - * Get file system statistics. - */ -procfs_statfs(mp, sbp, p) - struct mount *mp; - struct statfs *sbp; - struct proc *p; -{ - -#ifdef COMPAT_09 - sbp->f_type = 10; -#else - sbp->f_type = 0; -#endif - sbp->f_bsize = PAGE_SIZE; - sbp->f_iosize = PAGE_SIZE; - sbp->f_blocks = 1; /* avoid divide by zero in some df's */ - sbp->f_bfree = 0; - sbp->f_bavail = 0; - sbp->f_files = maxproc; /* approx */ - sbp->f_ffree = maxproc - nprocs; /* approx */ - if (sbp != &mp->mnt_stat) { - bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); - bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); - bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); - } - strncpy(sbp->f_fstypename, mp->mnt_op->vfs_name, MFSNAMELEN); - sbp->f_fstypename[MFSNAMELEN] = '\0'; - return (0); -} - -procfs_quotactl(mp, cmds, uid, arg, p) - struct mount *mp; - int cmds; - uid_t uid; - caddr_t arg; - struct proc *p; -{ - - return (EOPNOTSUPP); -} - -procfs_sync(mp, waitfor) - struct mount *mp; - int waitfor; -{ - - return (0); -} - -procfs_vget(mp, ino, vpp) - struct mount *mp; - ino_t ino; - struct vnode **vpp; -{ - - return (EOPNOTSUPP); -} - -procfs_fhtovp(mp, fhp, vpp) - struct mount *mp; - struct fid *fhp; - struct vnode **vpp; -{ - - return (EINVAL); -} - -procfs_vptofh(vp, fhp) - struct vnode *vp; - struct fid *fhp; -{ - - return (EINVAL); -} - -procfs_init() -{ - - return (0); -} - -struct vfsops procfs_vfsops = { - MOUNT_PROCFS, - procfs_mount, - procfs_start, - procfs_unmount, - procfs_root, - procfs_quotactl, - procfs_statfs, - procfs_sync, - procfs_vget, - procfs_fhtovp, - procfs_vptofh, - procfs_init, -}; diff --git a/bsd/miscfs/procfs/procfs_vnops.c b/bsd/miscfs/procfs/procfs_vnops.c deleted file mode 100644 index 6a9b52654..000000000 --- a/bsd/miscfs/procfs/procfs_vnops.c +++ /dev/null @@ -1,918 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* $NetBSD: procfs_vnops.c,v 1.32 1995/02/03 16:18:55 mycroft Exp $ */ - -/* - * Copyright (c) 1993 Jan-Simon Pendry - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Jan-Simon Pendry. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)procfs_vnops.c 8.8 (Berkeley) 6/15/94 - */ - -/* - * procfs vnode interface - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for PAGE_SIZE */ -#include -#include -#include - -/* - * Vnode Operations. - * - */ - -/* - * This is a list of the valid names in the - * process-specific sub-directories. It is - * used in procfs_lookup and procfs_readdir - */ -struct proc_target { - u_char pt_type; - u_char pt_namlen; - char *pt_name; - pfstype pt_pfstype; - int (*pt_valid) __P((struct proc *p)); -} proc_targets[] = { -#define N(s) sizeof(s)-1, s - /* name type validp */ - { DT_DIR, N("."), Pproc, NULL }, - { DT_DIR, N(".."), Proot, NULL }, - { DT_REG, N("file"), Pfile, procfs_validfile }, - { DT_REG, N("mem"), Pmem, NULL }, - { DT_REG, N("regs"), Pregs, procfs_validregs }, - { DT_REG, N("fpregs"), Pfpregs, procfs_validfpregs }, - { DT_REG, N("ctl"), Pctl, NULL }, - { DT_REG, N("status"), Pstatus, NULL }, - { DT_REG, N("note"), Pnote, NULL }, - { DT_REG, N("notepg"), Pnotepg, NULL }, -#undef N -}; -static int nproc_targets = sizeof(proc_targets) / sizeof(proc_targets[0]); - -static pid_t atopid __P((const char *, u_int)); - -/* - * set things up for doing i/o on - * the pfsnode (vp). (vp) is locked - * on entry, and should be left locked - * on exit. - * - * for procfs we don't need to do anything - * in particular for i/o. all that is done - * is to support exclusive open on process - * memory images. - */ -procfs_open(ap) - struct vop_open_args /* { - struct vnode *a_vp; - int a_mode; - struct ucred *a_cred; - struct proc *a_p; - } */ *ap; -{ - struct pfsnode *pfs = VTOPFS(ap->a_vp); - - switch (pfs->pfs_type) { - case Pmem: - if (PFIND(pfs->pfs_pid) == 0) - return (ENOENT); /* was ESRCH, jsp */ - - if ((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL) || - (pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE)) - return (EBUSY); - - if (ap->a_mode & FWRITE) - pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL); - - return (0); - - default: - break; - } - - return (0); -} - -/* - * close the pfsnode (vp) after doing i/o. - * (vp) is not locked on entry or exit. - * - * nothing to do for procfs other than undo - * any exclusive open flag (see _open above). - */ -procfs_close(ap) - struct vop_close_args /* { - struct vnode *a_vp; - int a_fflag; - struct ucred *a_cred; - struct proc *a_p; - } */ *ap; -{ - struct pfsnode *pfs = VTOPFS(ap->a_vp); - - switch (pfs->pfs_type) { - case Pmem: - if ((ap->a_fflag & FWRITE) && (pfs->pfs_flags & O_EXCL)) - pfs->pfs_flags &= ~(FWRITE|O_EXCL); - break; - } - - return (0); -} - -/* - * do an ioctl operation on pfsnode (vp). - * (vp) is not locked on entry or exit. - */ -procfs_ioctl(ap) - struct vop_ioctl_args /* { - struct vnode *a_vp; - u_long a_command; - caddr_t a_data; - int a_fflag; - struct ucred *a_cred; - struct proc *a_p; - } */ *ap; -{ - - return (ENOTTY); -} - -/* - * do block mapping for pfsnode (vp). - * since we don't use the buffer cache - * for procfs this function should never - * be called. in any case, it's not clear - * what part of the kernel ever makes use - * of this function. for sanity, this is the - * usual no-op bmap, although returning - * (EIO) would be a reasonable alternative. - */ -procfs_bmap(ap) - struct vop_bmap_args /* { - struct vnode *a_vp; - daddr_t a_bn; - struct vnode **a_vpp; - daddr_t *a_bnp; - } */ *ap; -{ - - if (ap->a_vpp != NULL) - *ap->a_vpp = ap->a_vp; - if (ap->a_bnp != NULL) - *ap->a_bnp = ap->a_bn; - return (0); -} - -/* - * _inactive is called when the pfsnode - * is vrele'd and the reference count goes - * to zero. (vp) will be on the vnode free - * list, so to get it back vget() must be - * used. - * - * for procfs, check if the process is still - * alive and if it isn't then just throw away - * the vnode by calling vgone(). this may - * be overkill and a waste of time since the - * chances are that the process will still be - * there and PFIND is not free. - * - * (vp) is not locked on entry or exit. - */ -procfs_inactive(ap) - struct vop_inactive_args /* { - struct vnode *a_vp; - } */ *ap; -{ - struct pfsnode *pfs = VTOPFS(ap->a_vp); - - if (PFIND(pfs->pfs_pid) == 0) - vgone(ap->a_vp); - - return (0); -} - -/* - * _reclaim is called when getnewvnode() - * wants to make use of an entry on the vnode - * free list. at this time the filesystem needs - * to free any private data and remove the node - * from any private lists. - */ -procfs_reclaim(ap) - struct vop_reclaim_args /* { - struct vnode *a_vp; - } */ *ap; -{ - - return (procfs_freevp(ap->a_vp)); -} - -/* - * Return POSIX pathconf information applicable to special devices. - */ -procfs_pathconf(ap) - struct vop_pathconf_args /* { - struct vnode *a_vp; - int a_name; - register_t *a_retval; - } */ *ap; -{ - - switch (ap->a_name) { - case _PC_LINK_MAX: - *ap->a_retval = LINK_MAX; - return (0); - case _PC_MAX_CANON: - *ap->a_retval = MAX_CANON; - return (0); - case _PC_MAX_INPUT: - *ap->a_retval = MAX_INPUT; - return (0); - case _PC_PIPE_BUF: - *ap->a_retval = PIPE_BUF; - return (0); - case _PC_CHOWN_RESTRICTED: - *ap->a_retval = 1; - return (0); - case _PC_VDISABLE: - *ap->a_retval = _POSIX_VDISABLE; - return (0); - default: - return (EINVAL); - } - /* NOTREACHED */ -} - -/* - * _print is used for debugging. - * just print a readable description - * of (vp). - */ -procfs_print(ap) - struct vop_print_args /* { - struct vnode *a_vp; - } */ *ap; -{ - struct pfsnode *pfs = VTOPFS(ap->a_vp); - - printf("tag VT_PROCFS, type %s, pid %d, mode %x, flags %x\n", - pfs->pfs_type, pfs->pfs_pid, pfs->pfs_mode, pfs->pfs_flags); -} - -/* - * _abortop is called when operations such as - * rename and create fail. this entry is responsible - * for undoing any side-effects caused by the lookup. - * this will always include freeing the pathname buffer. - */ -procfs_abortop(ap) - struct vop_abortop_args /* { - struct vnode *a_dvp; - struct componentname *a_cnp; - } */ *ap; -{ - - if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) - FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI); - return (0); -} - -/* - * generic entry point for unsupported operations - */ -procfs_badop() -{ - - return (EIO); -} - -/* - * Invent attributes for pfsnode (vp) and store - * them in (vap). - * Directories lengths are returned as zero since - * any real length would require the genuine size - * to be computed, and nothing cares anyway. - * - * this is relatively minimal for procfs. - */ -procfs_getattr(ap) - struct vop_getattr_args /* { - struct vnode *a_vp; - struct vattr *a_vap; - struct ucred *a_cred; - struct proc *a_p; - } */ *ap; -{ - struct pfsnode *pfs = VTOPFS(ap->a_vp); - struct vattr *vap = ap->a_vap; - struct proc *procp; - int error; - - /* first check the process still exists */ - switch (pfs->pfs_type) { - case Proot: - case Pcurproc: - procp = 0; - break; - - default: - procp = PFIND(pfs->pfs_pid); - if (procp == 0) - return (ENOENT); - } - - error = 0; - - /* start by zeroing out the attributes */ - VATTR_NULL(vap); - - /* next do all the common fields */ - vap->va_type = ap->a_vp->v_type; - vap->va_mode = pfs->pfs_mode; - vap->va_fileid = pfs->pfs_fileno; - vap->va_flags = 0; - vap->va_blocksize = PAGE_SIZE; - vap->va_bytes = vap->va_size = 0; - - /* - * Make all times be current TOD. - * It would be possible to get the process start - * time from the p_stat structure, but there's - * no "file creation" time stamp anyway, and the - * p_stat structure is not addressible if u. gets - * swapped out for that process. - * - * XXX - * Note that microtime() returns a timeval, not a timespec. - */ - microtime(&vap->va_ctime); - vap->va_atime = vap->va_mtime = vap->va_ctime; - - /* - * If the process has exercised some setuid or setgid - * privilege, then rip away read/write permission so - * that only root can gain access. - */ - switch (pfs->pfs_type) { - case Pmem: - case Pregs: - case Pfpregs: - if (procp->p_flag & P_SUGID) - vap->va_mode &= ~((VREAD|VWRITE)| - ((VREAD|VWRITE)>>3)| - ((VREAD|VWRITE)>>6)); - case Pctl: - case Pstatus: - case Pnote: - case Pnotepg: - vap->va_nlink = 1; - vap->va_uid = procp->p_ucred->cr_uid; - vap->va_gid = procp->p_ucred->cr_gid; - break; - } - - /* - * now do the object specific fields - * - * The size could be set from struct reg, but it's hardly - * worth the trouble, and it puts some (potentially) machine - * dependent data into this machine-independent code. If it - * becomes important then this function should break out into - * a per-file stat function in the corresponding .c file. - */ - - switch (pfs->pfs_type) { - case Proot: - /* - * Set nlink to 1 to tell fts(3) we don't actually know. - */ - vap->va_nlink = 1; - vap->va_uid = 0; - vap->va_gid = 0; - vap->va_size = vap->va_bytes = DEV_BSIZE; - break; - - case Pcurproc: { - char buf[16]; /* should be enough */ - vap->va_nlink = 1; - vap->va_uid = 0; - vap->va_gid = 0; - vap->va_size = vap->va_bytes = - sprintf(buf, "%ld", (long)curproc->p_pid); - break; - } - - case Pproc: - vap->va_nlink = 2; - vap->va_uid = procp->p_ucred->cr_uid; - vap->va_gid = procp->p_ucred->cr_gid; - vap->va_size = vap->va_bytes = DEV_BSIZE; - break; - - case Pfile: - error = EOPNOTSUPP; - break; - - case Pmem: - vap->va_bytes = vap->va_size = - ctob(procp->p_vmspace->vm_tsize + - procp->p_vmspace->vm_dsize + - procp->p_vmspace->vm_ssize); - break; - -#if defined(PT_GETREGS) || defined(PT_SETREGS) - case Pregs: - vap->va_bytes = vap->va_size = sizeof(struct reg); - break; -#endif - -#if defined(PT_GETFPREGS) || defined(PT_SETFPREGS) - case Pfpregs: - vap->va_bytes = vap->va_size = sizeof(struct fpreg); - break; -#endif - - case Pctl: - case Pstatus: - case Pnote: - case Pnotepg: - break; - - default: - panic("procfs_getattr"); - } - - return (error); -} - -procfs_setattr(ap) - struct vop_setattr_args /* { - struct vnode *a_vp; - struct vattr *a_vap; - struct ucred *a_cred; - struct proc *a_p; - } */ *ap; -{ - /* - * just fake out attribute setting - * it's not good to generate an error - * return, otherwise things like creat() - * will fail when they try to set the - * file length to 0. worse, this means - * that echo $note > /proc/$pid/note will fail. - */ - - return (0); -} - -/* - * implement access checking. - * - * actually, the check for super-user is slightly - * broken since it will allow read access to write-only - * objects. this doesn't cause any particular trouble - * but does mean that the i/o entry points need to check - * that the operation really does make sense. - */ -procfs_access(ap) - struct vop_access_args /* { - struct vnode *a_vp; - int a_mode; - struct ucred *a_cred; - struct proc *a_p; - } */ *ap; -{ - struct vattr va; - int error; - - if (error = VOP_GETATTR(ap->a_vp, &va, ap->a_cred, ap->a_p)) - return (error); - - return (vaccess(va.va_mode, va.va_uid, va.va_gid, ap->a_mode, - ap->a_cred)); -} - -/* - * lookup. this is incredibly complicated in the - * general case, however for most pseudo-filesystems - * very little needs to be done. - * - * unless you want to get a migraine, just make sure your - * filesystem doesn't do any locking of its own. otherwise - * read and inwardly digest ufs_lookup(). - */ -procfs_lookup(ap) - struct vop_lookup_args /* { - struct vnode * a_dvp; - struct vnode ** a_vpp; - struct componentname * a_cnp; - } */ *ap; -{ - struct componentname *cnp = ap->a_cnp; - struct vnode **vpp = ap->a_vpp; - struct vnode *dvp = ap->a_dvp; - char *pname = cnp->cn_nameptr; - struct proc_target *pt; - struct vnode *fvp; - pid_t pid; - struct pfsnode *pfs; - struct proc *p; - int i; - - *vpp = NULL; - - if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) - return (EROFS); - - if (cnp->cn_namelen == 1 && *pname == '.') { - *vpp = dvp; - VREF(dvp); - /*VOP_LOCK(dvp);*/ - return (0); - } - - pfs = VTOPFS(dvp); - switch (pfs->pfs_type) { - case Proot: - if (cnp->cn_flags & ISDOTDOT) - return (EIO); - - if (CNEQ(cnp, "curproc", 7)) - return (procfs_allocvp(dvp->v_mount, vpp, 0, Pcurproc)); - - pid = atopid(pname, cnp->cn_namelen); - if (pid == NO_PID) - break; - - p = PFIND(pid); - if (p == 0) - break; - - return (procfs_allocvp(dvp->v_mount, vpp, pid, Pproc)); - - case Pproc: - if (cnp->cn_flags & ISDOTDOT) - return (procfs_root(dvp->v_mount, vpp)); - - p = PFIND(pfs->pfs_pid); - if (p == 0) - break; - - for (pt = proc_targets, i = 0; i < nproc_targets; pt++, i++) { - if (cnp->cn_namelen == pt->pt_namlen && - bcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 && - (pt->pt_valid == NULL || (*pt->pt_valid)(p))) - goto found; - } - break; - - found: - if (pt->pt_pfstype == Pfile) { - fvp = procfs_findtextvp(p); - /* We already checked that it exists. */ - VREF(fvp); - VOP_LOCK(fvp); - *vpp = fvp; - return (0); - } - - return (procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid, - pt->pt_pfstype)); - - default: - return (ENOTDIR); - } - - return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS); -} - -int -procfs_validfile(p) - struct proc *p; -{ - - return (procfs_findtextvp(p) != NULLVP); -} - -/* - * readdir returns directory entries from pfsnode (vp). - * - * the strategy here with procfs is to generate a single - * directory entry at a time (struct pfsdent) and then - * copy that out to userland using uiomove. a more efficent - * though more complex implementation, would try to minimize - * the number of calls to uiomove(). for procfs, this is - * hardly worth the added code complexity. - * - * this should just be done through read() - */ -procfs_readdir(ap) - struct vop_readdir_args /* { - struct vnode *a_vp; - struct uio *a_uio; - struct ucred *a_cred; - int *a_eofflag; - u_long *a_cookies; - int a_ncookies; - } */ *ap; -{ - struct uio *uio = ap->a_uio; - struct pfsdent d; - struct pfsdent *dp = &d; - struct pfsnode *pfs; - int error; - int count; - int i; - - /* - * We don't allow exporting procfs mounts, and currently local - * requests do not need cookies. - */ - if (ap->a_ncookies) - panic("procfs_readdir: not hungry"); - - pfs = VTOPFS(ap->a_vp); - - if (uio->uio_resid < UIO_MX) - return (EINVAL); - if (uio->uio_offset & (UIO_MX-1)) - return (EINVAL); - if (uio->uio_offset < 0) - return (EINVAL); - - error = 0; - count = 0; - i = uio->uio_offset / UIO_MX; - - switch (pfs->pfs_type) { - /* - * this is for the process-specific sub-directories. - * all that is needed to is copy out all the entries - * from the procent[] table (top of this file). - */ - case Pproc: { - struct proc *p; - struct proc_target *pt; - - p = PFIND(pfs->pfs_pid); - if (p == NULL) - break; - - for (pt = &proc_targets[i]; - uio->uio_resid >= UIO_MX && i < nproc_targets; pt++, i++) { - if (pt->pt_valid && (*pt->pt_valid)(p) == 0) - continue; - - dp->d_reclen = UIO_MX; - dp->d_fileno = PROCFS_FILENO(pfs->pfs_pid, pt->pt_pfstype); - dp->d_namlen = pt->pt_namlen; - bcopy(pt->pt_name, dp->d_name, pt->pt_namlen + 1); - dp->d_type = pt->pt_type; - - if (error = uiomove((caddr_t)dp, UIO_MX, uio)) - break; - } - - break; - } - - /* - * this is for the root of the procfs filesystem - * what is needed is a special entry for "curproc" - * followed by an entry for each process on allproc -#ifdef PROCFS_ZOMBIE - * and zombproc. -#endif - */ - - case Proot: { -#ifdef PROCFS_ZOMBIE - int doingzomb = 0; -#endif - int pcnt = 0; - volatile struct proc *p = allproc.lh_first; - - again: - for (; p && uio->uio_resid >= UIO_MX; i++, pcnt++) { - bzero((char *) dp, UIO_MX); - dp->d_reclen = UIO_MX; - - switch (i) { - case 0: /* `.' */ - case 1: /* `..' */ - dp->d_fileno = PROCFS_FILENO(0, Proot); - dp->d_namlen = i + 1; - bcopy("..", dp->d_name, dp->d_namlen); - dp->d_name[i + 1] = '\0'; - dp->d_type = DT_DIR; - break; - - case 2: - dp->d_fileno = PROCFS_FILENO(0, Pcurproc); - dp->d_namlen = 7; - bcopy("curproc", dp->d_name, 8); - dp->d_type = DT_LNK; - break; - - default: - while (pcnt < i) { - pcnt++; - p = p->p_list.le_next; - if (!p) - goto done; - } - dp->d_fileno = PROCFS_FILENO(p->p_pid, Pproc); - dp->d_namlen = sprintf(dp->d_name, "%ld", - (long)p->p_pid); - dp->d_type = DT_REG; - p = p->p_list.le_next; - break; - } - - if (error = uiomove((caddr_t)dp, UIO_MX, uio)) - break; - } - done: - -#ifdef PROCFS_ZOMBIE - if (p == 0 && doingzomb == 0) { - doingzomb = 1; - p = zombproc.lh_first; - goto again; - } -#endif - - break; - - } - - default: - error = ENOTDIR; - break; - } - - uio->uio_offset = i * UIO_MX; - - return (error); -} - -/* - * readlink reads the link of `curproc' - */ -procfs_readlink(ap) - struct vop_readlink_args *ap; -{ - struct uio *uio = ap->a_uio; - char buf[16]; /* should be enough */ - int len; - - if (VTOPFS(ap->a_vp)->pfs_fileno != PROCFS_FILENO(0, Pcurproc)) - return (EINVAL); - - len = sprintf(buf, "%ld", (long)curproc->p_pid); - - return (uiomove((caddr_t)buf, len, ap->a_uio)); -} - -/* - * convert decimal ascii to pid_t - */ -static pid_t -atopid(b, len) - const char *b; - u_int len; -{ - pid_t p = 0; - - while (len--) { - char c = *b++; - if (c < '0' || c > '9') - return (NO_PID); - p = 10 * p + (c - '0'); - if (p > PID_MAX) - return (NO_PID); - } - - return (p); -} - -/* - * procfs vnode operations. - */ - -#define VOPFUNC int (*)(void *) - -int (**procfs_vnodeop_p)(void *); -struct vnodeopv_entry_desc procfs_vnodeop_entries[] = { - { &vop_default_desc, (VOPFUNC)vn_default_error }, - { &vop_lookup_desc, (VOPFUNC)procfs_lookup }, /* lookup */ - { &vop_create_desc, (VOPFUNC)procfs_create }, /* create */ - { &vop_mknod_desc, (VOPFUNC)procfs_mknod }, /* mknod */ - { &vop_open_desc, (VOPFUNC)procfs_open }, /* open */ - { &vop_close_desc, (VOPFUNC)procfs_close }, /* close */ - { &vop_access_desc, (VOPFUNC)procfs_access }, /* access */ - { &vop_getattr_desc, (VOPFUNC)procfs_getattr }, /* getattr */ - { &vop_setattr_desc, (VOPFUNC)procfs_setattr }, /* setattr */ - { &vop_read_desc, (VOPFUNC)procfs_read }, /* read */ - { &vop_write_desc, (VOPFUNC)procfs_write }, /* write */ - { &vop_ioctl_desc, (VOPFUNC)procfs_ioctl }, /* ioctl */ - { &vop_select_desc, (VOPFUNC)procfs_select }, /* select */ - { &vop_mmap_desc, (VOPFUNC)procfs_mmap }, /* mmap */ - { &vop_fsync_desc, (VOPFUNC)procfs_fsync }, /* fsync */ - { &vop_seek_desc, (VOPFUNC)procfs_seek }, /* seek */ - { &vop_remove_desc, (VOPFUNC)procfs_remove }, /* remove */ - { &vop_link_desc, (VOPFUNC)procfs_link }, /* link */ - { &vop_rename_desc, (VOPFUNC)procfs_rename }, /* rename */ - { &vop_mkdir_desc, (VOPFUNC)procfs_mkdir }, /* mkdir */ - { &vop_rmdir_desc, (VOPFUNC)procfs_rmdir }, /* rmdir */ - { &vop_symlink_desc, (VOPFUNC)procfs_symlink }, /* symlink */ - { &vop_readdir_desc, (VOPFUNC)procfs_readdir }, /* readdir */ - { &vop_readlink_desc, (VOPFUNC)procfs_readlink }, /* readlink */ - { &vop_abortop_desc, (VOPFUNC)procfs_abortop }, /* abortop */ - { &vop_inactive_desc, (VOPFUNC)procfs_inactive }, /* inactive */ - { &vop_reclaim_desc, (VOPFUNC)procfs_reclaim }, /* reclaim */ - { &vop_lock_desc, (VOPFUNC)procfs_lock }, /* lock */ - { &vop_unlock_desc, (VOPFUNC)procfs_unlock }, /* unlock */ - { &vop_bmap_desc, (VOPFUNC)procfs_bmap }, /* bmap */ - { &vop_strategy_desc, (VOPFUNC)procfs_strategy }, /* strategy */ - { &vop_print_desc, (VOPFUNC)procfs_print }, /* print */ - { &vop_islocked_desc, (VOPFUNC)procfs_islocked }, /* islocked */ - { &vop_pathconf_desc, (VOPFUNC)procfs_pathconf }, /* pathconf */ - { &vop_advlock_desc, (VOPFUNC)procfs_advlock }, /* advlock */ - { &vop_blkatoff_desc, (VOPFUNC)procfs_blkatoff }, /* blkatoff */ - { &vop_valloc_desc, (VOPFUNC)procfs_valloc }, /* valloc */ - { &vop_vfree_desc, (VOPFUNC)procfs_vfree }, /* vfree */ - { &vop_truncate_desc, (VOPFUNC)procfs_truncate }, /* truncate */ - { &vop_update_desc, (VOPFUNC)procfs_update }, /* update */ - { &vop_copyfile_desc, (VOPFUNC)err_copyfile }, /* Copyfile */ -{ (struct vnodeop_desc*)NULL, (int(*)())NULL } -}; -struct vnodeopv_desc procfs_vnodeop_opv_desc = - { &procfs_vnodeop_p, procfs_vnodeop_entries }; diff --git a/bsd/miscfs/specfs/spec_vnops.c b/bsd/miscfs/specfs/spec_vnops.c index 81b836085..52eea7f81 100644 --- a/bsd/miscfs/specfs/spec_vnops.c +++ b/bsd/miscfs/specfs/spec_vnops.c @@ -73,6 +73,7 @@ #include #include +#include struct vnode *speclisth[SPECHSZ]; @@ -589,8 +590,28 @@ spec_strategy(ap) struct buf *a_bp; } */ *ap; { - (*bdevsw[major(ap->a_bp->b_dev)].d_strategy)(ap->a_bp); - return (0); + struct buf *bp; + + bp = ap->a_bp; + + if (kdebug_enable) { + int code = 0; + + if (bp->b_flags & B_READ) + code |= DKIO_READ; + if (bp->b_flags & B_ASYNC) + code |= DKIO_ASYNC; + + if (bp->b_flags & B_META) + code |= DKIO_META; + else if (bp->b_flags & (B_PGIN | B_PAGEOUT)) + code |= DKIO_PAGING; + + KERNEL_DEBUG_CONSTANT(FSDBG_CODE(DBG_DKRW, code) | DBG_FUNC_NONE, + bp, bp->b_dev, bp->b_blkno, bp->b_bcount, 0); + } + (*bdevsw[major(bp->b_dev)].d_strategy)(bp); + return (0); } /* diff --git a/bsd/miscfs/specfs/specdev.h b/bsd/miscfs/specfs/specdev.h index fa1e5c2bc..6db592f44 100644 --- a/bsd/miscfs/specfs/specdev.h +++ b/bsd/miscfs/specfs/specdev.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -58,6 +58,9 @@ #ifndef _MISCFS_SPECFS_SPECDEV_H_ #define _MISCFS_SPECFS_SPECDEV_H_ +#include + +#ifdef __APPLE_API_PRIVATE #include /* @@ -160,4 +163,5 @@ int spec_blktooff __P((struct vop_blktooff_args *)); int spec_offtoblk __P((struct vop_offtoblk_args *)); int spec_cmap __P((struct vop_cmap_args *)); +#endif /* __APPLE_API_PRIVATE */ #endif /* _MISCFS_SPECFS_SPECDEV_H_ */ diff --git a/bsd/miscfs/synthfs/synthfs.h b/bsd/miscfs/synthfs/synthfs.h index 74fb3f1f2..28a85f8b2 100644 --- a/bsd/miscfs/synthfs/synthfs.h +++ b/bsd/miscfs/synthfs/synthfs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -32,6 +32,9 @@ #ifndef __SYNTHFS_H__ #define __SYNTHFS_H__ +#include + +#ifdef __APPLE_API_PRIVATE #include #include #include @@ -228,4 +231,5 @@ int synthfs_remove_symlink __P((struct vnode *vp)); int synthfs_move_rename_entry __P((struct vnode *source_vp, struct vnode *newparent_vp, char *newname)); int synthfs_derive_vnode_path __P((struct vnode *vp, char *vnpath, size_t pathbuffersize)); +#endif /* __APPLE_API_PRIVATE */ #endif /* __SYNTHFS_H__ */ diff --git a/bsd/miscfs/synthfs/synthfs_vfsops.c b/bsd/miscfs/synthfs/synthfs_vfsops.c index 121b99dcb..6d32cacb0 100644 --- a/bsd/miscfs/synthfs/synthfs_vfsops.c +++ b/bsd/miscfs/synthfs/synthfs_vfsops.c @@ -280,8 +280,8 @@ synthfs_mount(mp, path, data, ndp, p) { size_t size; - (void) copyinstr(path, mp->mnt_stat.f_mntonname, sizeof(mp->mnt_stat.f_mntonname) - 1, &size); - synthfs_mount_fs(mp, path, data, ndp, p); + (void) copyinstr(path, mp->mnt_stat.f_mntonname, sizeof(mp->mnt_stat.f_mntonname) - 1, &size); + return (synthfs_mount_fs(mp, path, data, ndp, p)); } diff --git a/bsd/miscfs/umapfs/umap.h b/bsd/miscfs/umapfs/umap.h deleted file mode 100644 index 190f6cc50..000000000 --- a/bsd/miscfs/umapfs/umap.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* $NetBSD: umap.h,v 1.4 1995/03/29 22:09:57 briggs Exp $ */ - -/* - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software donated to Berkeley by - * the UCLA Ficus project. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (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: @(#)null_vnops.c 1.5 (Berkeley) 7/10/92 - * @(#)umap.h 8.3 (Berkeley) 1/21/94 - */ - -#define MAPFILEENTRIES 64 -#define GMAPFILEENTRIES 16 -#define NOBODY 32767 -#define NULLGROUP 65534 - -struct umap_args { - char *target; /* Target of loopback */ - int nentries; /* # of entries in user map array */ - int gnentries; /* # of entries in group map array */ - uid_t (*mapdata)[2]; /* pointer to array of user mappings */ - gid_t (*gmapdata)[2]; /* pointer to array of group mappings */ -}; - -struct umap_mount { - struct mount *umapm_vfs; - struct vnode *umapm_rootvp; /* Reference to root umap_node */ - int info_nentries; /* number of uid mappings */ - int info_gnentries; /* number of gid mappings */ - uid_t info_mapdata[MAPFILEENTRIES][2]; /* mapping data for - user mapping in ficus */ - gid_t info_gmapdata[GMAPFILEENTRIES][2]; /*mapping data for - group mapping in ficus */ -}; - -#ifdef KERNEL -/* - * A cache of vnode references - */ -struct umap_node { - LIST_ENTRY(umap_node) umap_hash; /* Hash list */ - struct vnode *umap_lowervp; /* Aliased vnode - VREFed once */ - struct vnode *umap_vnode; /* Back pointer to vnode/umap_node */ -}; - -extern int umap_node_create __P((struct mount *mp, struct vnode *target, struct vnode **vpp)); -extern u_long umap_reverse_findid __P((u_long id, u_long map[][2], int nentries)); -extern void umap_mapids __P((struct mount *v_mount, struct ucred *credp)); - -#define MOUNTTOUMAPMOUNT(mp) ((struct umap_mount *)((mp)->mnt_data)) -#define VTOUMAP(vp) ((struct umap_node *)(vp)->v_data) -#define UMAPTOV(xp) ((xp)->umap_vnode) -#ifdef UMAPFS_DIAGNOSTIC -extern struct vnode *umap_checkvp __P((struct vnode *vp, char *fil, int lno)); -#define UMAPVPTOLOWERVP(vp) umap_checkvp((vp), __FILE__, __LINE__) -#else -#define UMAPVPTOLOWERVP(vp) (VTOUMAP(vp)->umap_lowervp) -#endif - -extern int (**umap_vnodeop_p)(void *); -extern struct vfsops umap_vfsops; -#endif /* KERNEL */ diff --git a/bsd/miscfs/umapfs/umap_subr.c b/bsd/miscfs/umapfs/umap_subr.c deleted file mode 100644 index 3eba697d0..000000000 --- a/bsd/miscfs/umapfs/umap_subr.c +++ /dev/null @@ -1,470 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* $NetBSD: umap_subr.c,v 1.4 1994/09/20 06:43:02 cgd Exp $ */ - -/* - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software donated to Berkeley by - * Jan-Simon Pendry. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (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: Id: lofs_subr.c, v 1.11 1992/05/30 10:05:43 jsp Exp - * @(#)umap_subr.c 8.6 (Berkeley) 1/26/94 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */ -#define NUMAPNODECACHE 16 - -/* - * Null layer cache: - * Each cache entry holds a reference to the target vnode - * along with a pointer to the alias vnode. When an - * entry is added the target vnode is VREF'd. When the - * alias is removed the target vnode is vrele'd. - */ - -#define UMAP_NHASH(vp) \ - (&umap_node_hashtbl[(((u_long)vp)>>LOG2_SIZEVNODE) & umap_node_hash]) -LIST_HEAD(umap_node_hashhead, umap_node) *umap_node_hashtbl; -u_long umap_node_hash; - -/* - * Initialise cache headers - */ -umapfs_init() -{ - -#ifdef UMAPFS_DIAGNOSTIC - printf("umapfs_init\n"); /* printed during system boot */ -#endif - umap_node_hashtbl = hashinit(NUMAPNODECACHE, M_CACHE, &umap_node_hash); -} - -/* - * umap_findid is called by various routines in umap_vnodeops.c to - * find a user or group id in a map. - */ -static u_long -umap_findid(id, map, nentries) - u_long id; - u_long map[][2]; - int nentries; -{ - int i; - - /* Find uid entry in map */ - i = 0; - while ((ilh_first; a != 0; a = a->umap_hash.le_next) { - if (a->umap_lowervp == targetvp && - a->umap_vnode->v_mount == mp) { - vp = UMAPTOV(a); - /* - * We need vget for the VXLOCK - * stuff, but we don't want to lock - * the lower node. - */ - if (vget(vp, 0, current_proc())) { -#ifdef UMAPFS_DIAGNOSTIC - printf ("umap_node_find: vget failed.\n"); -#endif - goto loop; - } - return (vp); - } - } - -#ifdef UMAPFS_DIAGNOSTIC - printf("umap_node_find(%x, %x): NOT found\n", mp, targetvp); -#endif - - return (0); -} - -/* - * Make a new umap_node node. - * Vp is the alias vnode, lowervp is the target vnode. - * Maintain a reference to lowervp. - */ -static int -umap_node_alloc(mp, lowervp, vpp) - struct mount *mp; - struct vnode *lowervp; - struct vnode **vpp; -{ - struct umap_node_hashhead *hd; - struct umap_node *xp; - struct vnode *vp, *nvp; - int error; - extern int (**dead_vnodeop_p)(void *); - struct specinfo *sp = (struct specinfo *)0; - - if (lowervp->v_type == VBLK || lowervp->v_type == VCHR) - MALLOC_ZONE(sp, struct specinfo *, sizeof(struct specinfo), - M_VNODE, M_WAITOK); - - MALLOC(xp, struct umap_node *, sizeof(struct umap_node), M_TEMP, - M_WAITOK); - if (error = getnewvnode(VT_UMAP, mp, umap_vnodeop_p, &vp)) { - FREE(xp, M_TEMP); - if (sp) - FREE_ZONE(sp, sizeof (struct specinfo), M_VNODE); - return (error); - } - vp->v_type = lowervp->v_type; - - if (vp->v_type == VBLK || vp->v_type == VCHR) { - vp->v_specinfo = sp; - vp->v_rdev = lowervp->v_rdev; - } - - vp->v_data = xp; - xp->umap_vnode = vp; - xp->umap_lowervp = lowervp; - /* - * Before we insert our new node onto the hash chains, - * check to see if someone else has beaten us to it. - */ - if (nvp = umap_node_find(lowervp)) { - *vpp = nvp; - - /* free the substructures we've allocated. */ - FREE(xp, M_TEMP); - if (sp) { - vp->v_specinfo = (struct specinfo *)0; - FREE_ZONE(sp, sizeof (struct specinfo), M_VNODE); - } - - vp->v_type = VBAD; /* node is discarded */ - vp->v_op = dead_vnodeop_p; /* so ops will still work */ - vrele(vp); /* get rid of it. */ - return (0); - } - - /* - * XXX if it's a device node, it needs to be checkalias()ed. - * however, for locking reasons, that's just not possible. - * so we have to do most of the dirty work inline. Note that - * this is a limited case; we know that there's going to be - * an alias, and we know that that alias will be a "real" - * device node, i.e. not tagged VT_NON. - */ - if (vp->v_type == VBLK || vp->v_type == VCHR) { - struct vnode *cvp, **cvpp; - - cvpp = &speclisth[SPECHASH(vp->v_rdev)]; -loop: - for (cvp = *cvpp; cvp; cvp = cvp->v_specnext) { - if (vp->v_rdev != cvp->v_rdev || - vp->v_type != cvp->v_type) - continue; - - /* - * Alias, but not in use, so flush it out. - */ - if (cvp->v_usecount == 0) { - vgone(cvp); - goto loop; - } - if (vget(cvp, 0, current_proc())) /* can't lock; will die! */ - goto loop; - break; - } - - vp->v_hashchain = cvpp; - vp->v_specnext = *cvpp; - vp->v_specflags = 0; - *cvpp = vp; -#if DIAGNOSTIC - if (cvp == NULLVP) - panic("umap_node_alloc: no alias for device"); -#endif - vp->v_flag |= VALIASED; - cvp->v_flag |= VALIASED; - vrele(cvp); - } - /* XXX end of transmogrified checkalias() */ - - if (vp->v_type == VREG) - ubc_info_init(vp); - - *vpp = vp; - VREF(lowervp); /* Extra VREF will be vrele'd in umap_node_create */ - hd = UMAP_NHASH(lowervp); - LIST_INSERT_HEAD(hd, xp, umap_hash); - return (0); -} - - -/* - * Try to find an existing umap_node vnode refering - * to it, otherwise make a new umap_node vnode which - * contains a reference to the target vnode. - */ -int -umap_node_create(mp, targetvp, newvpp) - struct mount *mp; - struct vnode *targetvp; - struct vnode **newvpp; -{ - struct vnode *aliasvp; - - if (aliasvp = umap_node_find(mp, targetvp)) { - /* - * Take another reference to the alias vnode - */ -#ifdef UMAPFS_DIAGNOSTIC - vprint("umap_node_create: exists", ap->umap_vnode); -#endif - /* VREF(aliasvp); */ - } else { - int error; - - /* - * Get new vnode. - */ -#ifdef UMAPFS_DIAGNOSTIC - printf("umap_node_create: create new alias vnode\n"); -#endif - /* - * Make new vnode reference the umap_node. - */ - if (error = umap_node_alloc(mp, targetvp, &aliasvp)) - return (error); - - /* - * aliasvp is already VREF'd by getnewvnode() - */ - } - - vrele(targetvp); - -#ifdef UMAPFS_DIAGNOSTIC - vprint("umap_node_create: alias", aliasvp); - vprint("umap_node_create: target", targetvp); -#endif - - *newvpp = aliasvp; - return (0); -} - -#ifdef UMAPFS_DIAGNOSTIC -int umap_checkvp_barrier = 1; -struct vnode * -umap_checkvp(vp, fil, lno) - struct vnode *vp; - char *fil; - int lno; -{ - struct umap_node *a = VTOUMAP(vp); -#if 0 - /* - * Can't do this check because vop_reclaim runs - * with funny vop vector. - */ - if (vp->v_op != umap_vnodeop_p) { - printf ("umap_checkvp: on non-umap-node\n"); - while (umap_checkvp_barrier) /*WAIT*/ ; - panic("umap_checkvp"); - } -#endif - if (a->umap_lowervp == NULL) { - /* Should never happen */ - int i; u_long *p; - printf("vp = %x, ZERO ptr\n", vp); - for (p = (u_long *) a, i = 0; i < 8; i++) - printf(" %x", p[i]); - printf("\n"); - /* wait for debugger */ - while (umap_checkvp_barrier) /*WAIT*/ ; - panic("umap_checkvp"); - } - if (a->umap_lowervp->v_usecount < 1) { - int i; u_long *p; - printf("vp = %x, unref'ed lowervp\n", vp); - for (p = (u_long *) a, i = 0; i < 8; i++) - printf(" %x", p[i]); - printf("\n"); - /* wait for debugger */ - while (umap_checkvp_barrier) /*WAIT*/ ; - panic ("umap with unref'ed lowervp"); - } -#if 0 - printf("umap %x/%d -> %x/%d [%s, %d]\n", - a->umap_vnode, a->umap_vnode->v_usecount, - a->umap_lowervp, a->umap_lowervp->v_usecount, - fil, lno); -#endif - return (a->umap_lowervp); -} -#endif - -/* umap_mapids maps all of the ids in a credential, both user and group. */ - -void -umap_mapids(v_mount, credp) - struct mount *v_mount; - struct ucred *credp; -{ - int i, unentries, gnentries; - uid_t uid, *usermap; - gid_t gid, *groupmap; - - unentries = MOUNTTOUMAPMOUNT(v_mount)->info_nentries; - usermap = &(MOUNTTOUMAPMOUNT(v_mount)->info_mapdata[0][0]); - gnentries = MOUNTTOUMAPMOUNT(v_mount)->info_gnentries; - groupmap = &(MOUNTTOUMAPMOUNT(v_mount)->info_gmapdata[0][0]); - - /* Find uid entry in map */ - - uid = (uid_t) umap_findid(credp->cr_uid, usermap, unentries); - - if (uid != -1) - credp->cr_uid = uid; - else - credp->cr_uid = (uid_t) NOBODY; - -#ifdef notdef - /* cr_gid is the same as cr_groups[0] in 4BSD */ - - /* Find gid entry in map */ - - gid = (gid_t) umap_findid(credp->cr_gid, groupmap, gnentries); - - if (gid != -1) - credp->cr_gid = gid; - else - credp->cr_gid = NULLGROUP; -#endif - - /* Now we must map each of the set of groups in the cr_groups - structure. */ - - i = 0; - while (credp->cr_groups[i] != 0) { - gid = (gid_t) umap_findid(credp->cr_groups[i], - groupmap, gnentries); - - if (gid != -1) - credp->cr_groups[i++] = gid; - else - credp->cr_groups[i++] = NULLGROUP; - } -} diff --git a/bsd/miscfs/umapfs/umap_vfsops.c b/bsd/miscfs/umapfs/umap_vfsops.c deleted file mode 100644 index 2c60387fd..000000000 --- a/bsd/miscfs/umapfs/umap_vfsops.c +++ /dev/null @@ -1,438 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* $NetBSD: umap_vfsops.c,v 1.7 1995/03/09 12:05:59 mycroft Exp $ */ - -/* - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software donated to Berkeley by - * the UCLA Ficus project. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (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: @(#)null_vfsops.c 1.5 (Berkeley) 7/10/92 - * @(#)umap_vfsops.c 8.3 (Berkeley) 1/21/94 - */ - -/* - * Umap Layer - * (See mount_umap(8) for a description of this layer.) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Mount umap layer - */ -int -umapfs_mount(mp, path, data, ndp, p) - struct mount *mp; - char *path; - caddr_t data; - struct nameidata *ndp; - struct proc *p; -{ - struct umap_args args; - struct vnode *lowerrootvp, *vp; - struct vnode *umapm_rootvp; - struct umap_mount *amp; - size_t size; - int error; - -#ifdef UMAPFS_DIAGNOSTIC - printf("umapfs_mount(mp = %x)\n", mp); -#endif - - /* - * Update is a no-op - */ - if (mp->mnt_flag & MNT_UPDATE) { - return (EOPNOTSUPP); - /* return (VFS_MOUNT(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, path, data, ndp, p));*/ - } - - /* - * Get argument - */ - if (error = copyin(data, (caddr_t)&args, sizeof(struct umap_args))) - return (error); - - /* - * Find lower node - */ - NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF, - UIO_USERSPACE, args.target, p); - if (error = namei(ndp)) - return (error); - - /* - * Sanity check on lower vnode - */ - lowerrootvp = ndp->ni_vp; -#ifdef UMAPFS_DIAGNOSTIC - printf("vp = %x, check for VDIR...\n", lowerrootvp); -#endif - vrele(ndp->ni_dvp); - ndp->ni_dvp = 0; - - if (lowerrootvp->v_type != VDIR) { - vput(lowerrootvp); - return (EINVAL); - } - -#ifdef UMAPFS_DIAGNOSTIC - printf("mp = %x\n", mp); -#endif - -// amp = (struct umap_mount *) malloc(sizeof(struct umap_mount), -// M_UFSMNT, M_WAITOK); /* XXX */ - MALLOC(amp, struct umap_mount *, sizeof(struct umap_mount), - M_UFSMNT, M_WAITOK); - - /* - * Save reference to underlying FS - */ - amp->umapm_vfs = lowerrootvp->v_mount; - - /* - * Now copy in the number of entries and maps for umap mapping. - */ - amp->info_nentries = args.nentries; - amp->info_gnentries = args.gnentries; - error = copyin(args.mapdata, (caddr_t)amp->info_mapdata, - 2*sizeof(u_long)*args.nentries); - if (error) - return (error); - -#ifdef UMAP_DIAGNOSTIC - printf("umap_mount:nentries %d\n",args.nentries); - for (i = 0; i < args.nentries; i++) - printf(" %d maps to %d\n", amp->info_mapdata[i][0], - amp->info_mapdata[i][1]); -#endif - - error = copyin(args.gmapdata, (caddr_t)amp->info_gmapdata, - 2*sizeof(u_long)*args.nentries); - if (error) - return (error); - -#ifdef UMAP_DIAGNOSTIC - printf("umap_mount:gnentries %d\n",args.gnentries); - for (i = 0; i < args.gnentries; i++) - printf(" group %d maps to %d\n", - amp->info_gmapdata[i][0], - amp->info_gmapdata[i][1]); -#endif - - - /* - * Save reference. Each mount also holds - * a reference on the root vnode. - */ - error = umap_node_create(mp, lowerrootvp, &vp); - /* - * Unlock the node (either the lower or the alias) - */ - VOP_UNLOCK(vp); - /* - * Make sure the node alias worked - */ - if (error) { - vrele(lowerrootvp); - free(amp, M_UFSMNT); /* XXX */ - return (error); - } - - /* - * Keep a held reference to the root vnode. - * It is vrele'd in umapfs_unmount. - */ - umapm_rootvp = vp; - umapm_rootvp->v_flag |= VROOT; - amp->umapm_rootvp = umapm_rootvp; - if (UMAPVPTOLOWERVP(umapm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) - mp->mnt_flag |= MNT_LOCAL; - mp->mnt_data = (qaddr_t) amp; - getnewfsid(mp, makefstype(MOUNT_LOFS)); - - (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); - bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); - (void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, - &size); - bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); -#ifdef UMAPFS_DIAGNOSTIC - printf("umapfs_mount: lower %s, alias at %s\n", - mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); -#endif - return (0); -} - -/* - * VFS start. Nothing needed here - the start routine - * on the underlying filesystem will have been called - * when that filesystem was mounted. - */ -int -umapfs_start(mp, flags, p) - struct mount *mp; - int flags; - struct proc *p; -{ - - return (0); - /* return (VFS_START(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, flags, p)); */ -} - -/* - * Free reference to umap layer - */ -int -umapfs_unmount(mp, mntflags, p) - struct mount *mp; - int mntflags; - struct proc *p; -{ - struct vnode *umapm_rootvp = MOUNTTOUMAPMOUNT(mp)->umapm_rootvp; - int error; - int flags = 0; - extern int doforce; - -#ifdef UMAPFS_DIAGNOSTIC - printf("umapfs_unmount(mp = %x)\n", mp); -#endif - - if (mntflags & MNT_FORCE) { - /* lofs can never be rootfs so don't check for it */ - if (!doforce) - return (EINVAL); - flags |= FORCECLOSE; - } - - /* - * Clear out buffer cache. I don't think we - * ever get anything cached at this level at the - * moment, but who knows... - */ -#ifdef notyet - mntflushbuf(mp, 0); - if (mntinvalbuf(mp, 1)) - return (EBUSY); -#endif - if (umapm_rootvp->v_usecount > 1) - return (EBUSY); - if (error = vflush(mp, umapm_rootvp, flags)) - return (error); - -#ifdef UMAPFS_DIAGNOSTIC - vprint("alias root of lower", umapm_rootvp); -#endif - /* - * Release reference on underlying root vnode - */ - vrele(umapm_rootvp); - /* - * And blow it away for future re-use - */ - vgone(umapm_rootvp); - /* - * Finally, throw away the umap_mount structure - */ - free(mp->mnt_data, M_UFSMNT); /* XXX */ - mp->mnt_data = 0; - return (0); -} - -int -umapfs_root(mp, vpp) - struct mount *mp; - struct vnode **vpp; -{ - struct vnode *vp; - -#ifdef UMAPFS_DIAGNOSTIC - printf("umapfs_root(mp = %x, vp = %x->%x)\n", mp, - MOUNTTOUMAPMOUNT(mp)->umapm_rootvp, - UMAPVPTOLOWERVP(MOUNTTOUMAPMOUNT(mp)->umapm_rootvp) - ); -#endif - - /* - * Return locked reference to root. - */ - vp = MOUNTTOUMAPMOUNT(mp)->umapm_rootvp; - VREF(vp); - VOP_LOCK(vp); - *vpp = vp; - return (0); -} - -int -umapfs_quotactl(mp, cmd, uid, arg, p) - struct mount *mp; - int cmd; - uid_t uid; - caddr_t arg; - struct proc *p; -{ - - return (VFS_QUOTACTL(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, cmd, uid, arg, p)); -} - -int -umapfs_statfs(mp, sbp, p) - struct mount *mp; - struct statfs *sbp; - struct proc *p; -{ - int error; - struct statfs mstat; - -#ifdef UMAPFS_DIAGNOSTIC - printf("umapfs_statfs(mp = %x, vp = %x->%x)\n", mp, - MOUNTTOUMAPMOUNT(mp)->umapm_rootvp, - UMAPVPTOLOWERVP(MOUNTTOUMAPMOUNT(mp)->umapm_rootvp) - ); -#endif - - bzero(&mstat, sizeof(mstat)); - - error = VFS_STATFS(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, &mstat, p); - if (error) - return (error); - - /* now copy across the "interesting" information and fake the rest */ - sbp->f_type = mstat.f_type; - sbp->f_flags = mstat.f_flags; - sbp->f_bsize = mstat.f_bsize; - sbp->f_iosize = mstat.f_iosize; - sbp->f_blocks = mstat.f_blocks; - sbp->f_bfree = mstat.f_bfree; - sbp->f_bavail = mstat.f_bavail; - sbp->f_files = mstat.f_files; - sbp->f_ffree = mstat.f_ffree; - if (sbp != &mp->mnt_stat) { - bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); - bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); - bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); - } - strncpy(sbp->f_fstypename, mp->mnt_op->vfs_name, MFSNAMELEN); - sbp->f_fstypename[MFSNAMELEN] = '\0'; - return (0); -} - -int -umapfs_sync(mp, waitfor, cred, p) - struct mount *mp; - int waitfor; - struct ucred *cred; - struct proc *p; -{ - - /* - * XXX - Assumes no data cached at umap layer. - */ - return (0); -} - -int -umapfs_vget(mp, ino, vpp) - struct mount *mp; - ino_t ino; - struct vnode **vpp; -{ - - return (VFS_VGET(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, ino, vpp)); -} - -int -umapfs_fhtovp(mp, fidp, nam, vpp, exflagsp, credanonp) - struct mount *mp; - struct fid *fidp; - struct mbuf *nam; - struct vnode **vpp; - int *exflagsp; - struct ucred**credanonp; -{ - - return (EOPNOTSUPP); -} - -int -umapfs_vptofh(vp, fhp) - struct vnode *vp; - struct fid *fhp; -{ - - return (EOPNOTSUPP); -} - -int umapfs_init __P((void)); - -struct vfsops umap_vfsops = { - MOUNT_UMAP, - umapfs_mount, - umapfs_start, - umapfs_unmount, - umapfs_root, - umapfs_quotactl, - umapfs_statfs, - umapfs_sync, - umapfs_vget, - umapfs_fhtovp, - umapfs_vptofh, - umapfs_init, -}; diff --git a/bsd/miscfs/umapfs/umap_vnops.c b/bsd/miscfs/umapfs/umap_vnops.c deleted file mode 100644 index 47600b41d..000000000 --- a/bsd/miscfs/umapfs/umap_vnops.c +++ /dev/null @@ -1,520 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* $NetBSD: umap_vnops.c,v 1.3 1994/08/19 11:25:42 mycroft Exp $ */ - -/* - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software donated to Berkeley by - * the UCLA Ficus project. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)umap_vnops.c 8.3 (Berkeley) 1/5/94 - */ - -/* - * Umap Layer - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -int umap_bug_bypass = 0; /* for debugging: enables bypass printf'ing */ - -/* - * This is the 10-Apr-92 bypass routine. - * See null_vnops.c:null_bypass for more details. - */ -int -umap_bypass(ap) - struct vop_generic_args /* { - struct vnodeop_desc *a_desc; - - } */ *ap; -{ - extern int (**umap_vnodeop_p)(void *); /* not extern, really "forward" */ - struct ucred **credpp = 0, *credp = 0; - struct ucred *savecredp, *savecompcredp = 0; - struct ucred *compcredp = 0; - struct vnode **this_vp_p; - int error; - struct vnode *old_vps[VDESC_MAX_VPS]; - struct vnode *vp1 = 0; - struct vnode **vps_p[VDESC_MAX_VPS]; - struct vnode ***vppp; - struct vnodeop_desc *descp = ap->a_desc; - int reles, i; - struct componentname **compnamepp = 0; - - if (umap_bug_bypass) - printf ("umap_bypass: %s\n", descp->vdesc_name); - -#ifdef SAFETY - /* - * We require at least one vp. - */ - if (descp->vdesc_vp_offsets == NULL || - descp->vdesc_vp_offsets[0] == VDESC_NO_OFFSET) - panic ("umap_bypass: no vp's in map.\n"); -#endif - - /* - * Map the vnodes going in. - * Later, we'll invoke the operation based on - * the first mapped vnode's operation vector. - */ - reles = descp->vdesc_flags; - for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) { - if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET) - break; /* bail out at end of list */ - vps_p[i] = this_vp_p = - VOPARG_OFFSETTO(struct vnode**, descp->vdesc_vp_offsets[i], ap); - - if (i == 0) { - vp1 = *vps_p[0]; - } - - /* - * We're not guaranteed that any but the first vnode - * are of our type. Check for and don't map any - * that aren't. (Must map first vp or vclean fails.) - */ - - if (i && (*this_vp_p)->v_op != umap_vnodeop_p) { - old_vps[i] = NULL; - } else { - old_vps[i] = *this_vp_p; - *(vps_p[i]) = UMAPVPTOLOWERVP(*this_vp_p); - if (reles & 1) - VREF(*this_vp_p); - } - - } - - /* - * Fix the credentials. (That's the purpose of this layer.) - */ - - if (descp->vdesc_cred_offset != VDESC_NO_OFFSET) { - - credpp = VOPARG_OFFSETTO(struct ucred**, - descp->vdesc_cred_offset, ap); - - /* Save old values */ - - savecredp = *credpp; - if (savecredp != NOCRED) - *credpp = crdup(savecredp); - credp = *credpp; - - if (umap_bug_bypass && credp->cr_uid != 0) - printf("umap_bypass: user was %d, group %d\n", - credp->cr_uid, credp->cr_gid); - - /* Map all ids in the credential structure. */ - - umap_mapids(vp1->v_mount, credp); - - if (umap_bug_bypass && credp->cr_uid != 0) - printf("umap_bypass: user now %d, group %d\n", - credp->cr_uid, credp->cr_gid); - } - - /* BSD often keeps a credential in the componentname structure - * for speed. If there is one, it better get mapped, too. - */ - - if (descp->vdesc_componentname_offset != VDESC_NO_OFFSET) { - - compnamepp = VOPARG_OFFSETTO(struct componentname**, - descp->vdesc_componentname_offset, ap); - - savecompcredp = (*compnamepp)->cn_cred; - if (savecompcredp != NOCRED) - (*compnamepp)->cn_cred = crdup(savecompcredp); - compcredp = (*compnamepp)->cn_cred; - - if (umap_bug_bypass && compcredp->cr_uid != 0) - printf("umap_bypass: component credit user was %d, group %d\n", - compcredp->cr_uid, compcredp->cr_gid); - - /* Map all ids in the credential structure. */ - - umap_mapids(vp1->v_mount, compcredp); - - if (umap_bug_bypass && compcredp->cr_uid != 0) - printf("umap_bypass: component credit user now %d, group %d\n", - compcredp->cr_uid, compcredp->cr_gid); - } - - /* - * Call the operation on the lower layer - * with the modified argument structure. - */ - error = VCALL(*(vps_p[0]), descp->vdesc_offset, ap); - - /* - * Maintain the illusion of call-by-value - * by restoring vnodes in the argument structure - * to their original value. - */ - reles = descp->vdesc_flags; - for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) { - if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET) - break; /* bail out at end of list */ - if (old_vps[i]) { - *(vps_p[i]) = old_vps[i]; - if (reles & 1) - vrele(*(vps_p[i])); - }; - }; - - /* - * Map the possible out-going vpp - * (Assumes that the lower layer always returns - * a VREF'ed vpp unless it gets an error.) - */ - if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET && - !(descp->vdesc_flags & VDESC_NOMAP_VPP) && - !error) { - if (descp->vdesc_flags & VDESC_VPP_WILLRELE) - goto out; - vppp = VOPARG_OFFSETTO(struct vnode***, - descp->vdesc_vpp_offset, ap); - error = umap_node_create(old_vps[0]->v_mount, **vppp, *vppp); - }; - - out: - /* - * Free duplicate cred structure and restore old one. - */ - if (descp->vdesc_cred_offset != VDESC_NO_OFFSET) { - if (umap_bug_bypass && credp && credp->cr_uid != 0) - printf("umap_bypass: returning-user was %d\n", - credp->cr_uid); - - if (savecredp != NOCRED) { - if (credp != NOCRED) - crfree(credp); - *credpp = savecredp; - if (umap_bug_bypass && credpp && (*credpp)->cr_uid != 0) - printf("umap_bypass: returning-user now %d\n\n", - savecredp->cr_uid); - } - } - - if (descp->vdesc_componentname_offset != VDESC_NO_OFFSET) { - if (umap_bug_bypass && compcredp && compcredp->cr_uid != 0) - printf("umap_bypass: returning-component-user was %d\n", - compcredp->cr_uid); - - if (savecompcredp != NOCRED) { - if (compcredp != NOCRED) - crfree(compcredp); - (*compnamepp)->cn_cred = savecompcredp; - if (umap_bug_bypass && credpp && (*credpp)->cr_uid != 0) - printf("umap_bypass: returning-component-user now %d\n", - savecompcredp->cr_uid); - } - } - - return (error); -} - - -/* - * We handle getattr to change the fsid. - */ -int -umap_getattr(ap) - struct vop_getattr_args /* { - struct vnode *a_vp; - struct vattr *a_vap; - struct ucred *a_cred; - struct proc *a_p; - } */ *ap; -{ - uid_t uid; - gid_t gid; - int error, tmpid, nentries, gnentries; - uid_t (*mapdata)[2]; - gid_t (*gmapdata)[2]; - struct vnode **vp1p; - struct vnodeop_desc *descp = ap->a_desc; - - if (error = umap_bypass(ap)) - return (error); - /* Requires that arguments be restored. */ - ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; - - /* - * Umap needs to map the uid and gid returned by a stat - * into the proper values for this site. This involves - * finding the returned uid in the mapping information, - * translating it into the uid on the other end, - * and filling in the proper field in the vattr - * structure pointed to by ap->a_vap. The group - * is easier, since currently all groups will be - * translate to the NULLGROUP. - */ - - /* Find entry in map */ - - uid = ap->a_vap->va_uid; - gid = ap->a_vap->va_gid; - if (umap_bug_bypass) - printf("umap_getattr: mapped uid = %d, mapped gid = %d\n", uid, - gid); - - vp1p = VOPARG_OFFSETTO(struct vnode**, descp->vdesc_vp_offsets[0], ap); - nentries = MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_nentries; - mapdata = (MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_mapdata); - gnentries = MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_gnentries; - gmapdata = (MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_gmapdata); - - /* Reverse map the uid for the vnode. Since it's a reverse - map, we can't use umap_mapids() to do it. */ - - tmpid = umap_reverse_findid(uid, mapdata, nentries); - - if (tmpid != -1) { - ap->a_vap->va_uid = (uid_t) tmpid; - if (umap_bug_bypass) - printf("umap_getattr: original uid = %d\n", uid); - } else - ap->a_vap->va_uid = (uid_t) NOBODY; - - /* Reverse map the gid for the vnode. */ - - tmpid = umap_reverse_findid(gid, gmapdata, gnentries); - - if (tmpid != -1) { - ap->a_vap->va_gid = (gid_t) tmpid; - if (umap_bug_bypass) - printf("umap_getattr: original gid = %d\n", gid); - } else - ap->a_vap->va_gid = (gid_t) NULLGROUP; - - return (0); -} - -int -umap_inactive(ap) - struct vop_inactive_args /* { - struct vnode *a_vp; - } */ *ap; -{ - /* - * Do nothing (and _don't_ bypass). - * Wait to vrele lowervp until reclaim, - * so that until then our umap_node is in the - * cache and reusable. - * - */ - return (0); -} - -int -umap_reclaim(ap) - struct vop_reclaim_args /* { - struct vnode *a_vp; - } */ *ap; -{ - struct vnode *vp = ap->a_vp; - struct umap_node *xp = VTOUMAP(vp); - struct vnode *lowervp = xp->umap_lowervp; - - /* After this assignment, this node will not be re-used. */ - xp->umap_lowervp = NULL; - LIST_REMOVE(xp, umap_hash); - FREE(vp->v_data, M_TEMP); - vp->v_data = NULL; - vrele(lowervp); - return (0); -} - -int -umap_strategy(ap) - struct vop_strategy_args /* { - struct buf *a_bp; - } */ *ap; -{ - struct buf *bp = ap->a_bp; - int error; - struct vnode *savedvp; - - savedvp = bp->b_vp; - bp->b_vp = UMAPVPTOLOWERVP(bp->b_vp); - - error = VOP_STRATEGY(ap->a_bp); - - bp->b_vp = savedvp; - - return (error); -} - -int -umap_bwrite(ap) - struct vop_bwrite_args /* { - struct buf *a_bp; - } */ *ap; -{ - struct buf *bp = ap->a_bp; - int error; - struct vnode *savedvp; - - savedvp = bp->b_vp; - bp->b_vp = UMAPVPTOLOWERVP(bp->b_vp); - - error = VOP_BWRITE(ap->a_bp); - - bp->b_vp = savedvp; - - return (error); -} - - -int -umap_print(ap) - struct vop_print_args /* { - struct vnode *a_vp; - } */ *ap; -{ - struct vnode *vp = ap->a_vp; - printf("\ttag VT_UMAPFS, vp=%x, lowervp=%x\n", vp, UMAPVPTOLOWERVP(vp)); - return (0); -} - -int -umap_rename(ap) - struct vop_rename_args /* { - struct vnode *a_fdvp; - struct vnode *a_fvp; - struct componentname *a_fcnp; - struct vnode *a_tdvp; - struct vnode *a_tvp; - struct componentname *a_tcnp; - } */ *ap; -{ - int error; - struct componentname *compnamep; - struct ucred *compcredp, *savecompcredp; - struct vnode *vp; - - /* - * Rename is irregular, having two componentname structures. - * We need to map the cre in the second structure, - * and then bypass takes care of the rest. - */ - - vp = ap->a_fdvp; - compnamep = ap->a_tcnp; - compcredp = compnamep->cn_cred; - - savecompcredp = compcredp; - compcredp = compnamep->cn_cred = crdup(savecompcredp); - - if (umap_bug_bypass && compcredp->cr_uid != 0) - printf("umap_rename: rename component credit user was %d, group %d\n", - compcredp->cr_uid, compcredp->cr_gid); - - /* Map all ids in the credential structure. */ - - umap_mapids(vp->v_mount, compcredp); - - if (umap_bug_bypass && compcredp->cr_uid != 0) - printf("umap_rename: rename component credit user now %d, group %d\n", - compcredp->cr_uid, compcredp->cr_gid); - - error = umap_bypass(ap); - - /* Restore the additional mapped componentname cred structure. */ - - crfree(compcredp); - compnamep->cn_cred = savecompcredp; - - return error; -} - -/* - * Global vfs data structures - */ -/* - * XXX - strategy, bwrite are hand coded currently. They should - * go away with a merged buffer/block cache. - * - */ - -#define VOPFUNC int (*)(void *) - -int (**umap_vnodeop_p)(void *); -struct vnodeopv_entry_desc umap_vnodeop_entries[] = { - { &vop_default_desc, (VOPFUNC)umap_bypass }, - { &vop_getattr_desc, (VOPFUNC)umap_getattr }, - { &vop_inactive_desc, (VOPFUNC)umap_inactive }, - { &vop_reclaim_desc, (VOPFUNC)umap_reclaim }, - { &vop_print_desc, (VOPFUNC)umap_print }, - { &vop_rename_desc, (VOPFUNC)umap_rename }, - { &vop_strategy_desc, (VOPFUNC)umap_strategy }, - { &vop_bwrite_desc, (VOPFUNC)umap_bwrite }, - - { (struct vnodeop_desc*) NULL, (int(*)()) NULL } -}; -struct vnodeopv_desc umap_vnodeop_opv_desc = - { &umap_vnodeop_p, umap_vnodeop_entries }; diff --git a/bsd/miscfs/union/union.h b/bsd/miscfs/union/union.h index 9181e8d51..147df4c7f 100644 --- a/bsd/miscfs/union/union.h +++ b/bsd/miscfs/union/union.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -58,7 +58,12 @@ * * @(#)union.h 8.9 (Berkeley) 12/10/94 */ +#ifndef __UNION_UNION_H__ +#define __UNION_UNION_H__ +#include + +#ifdef __APPLE_API_PRIVATE struct union_args { char *target; /* Target of loopback */ int mntflags; /* Options on the mount */ @@ -149,3 +154,6 @@ extern void union_newsize __P((struct vnode *, off_t, off_t)); extern int (**union_vnodeop_p)(void *); extern struct vfsops union_vfsops; #endif /* KERNEL */ + +#endif /* __APPLE_API_PRIVATE */ +#endif /* __UNION_UNION_H__ */ diff --git a/bsd/miscfs/volfs/volfs.h b/bsd/miscfs/volfs/volfs.h index 91395838e..92ea0b2ad 100644 --- a/bsd/miscfs/volfs/volfs.h +++ b/bsd/miscfs/volfs/volfs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -23,7 +23,12 @@ /* * Header file for volfs */ +#ifndef __VOLFS_VOLFS_H__ +#define __VOLFS_VOLFS_H__ +#include + +#ifdef __APPLE_API_PRIVATE struct volfs_mntdata { struct vnode *volfs_rootvp; @@ -187,3 +192,6 @@ typedef struct VopDbgStoreRec { #define DBG_VOP_UPDATE_VP(I, VP) #endif /* DBG_VOP_TEST_LOCKS */ + +#endif /* __APPLE_API_PRIVATE */ +#endif /* __VOLFS_VOLFS_H__ */ diff --git a/bsd/net/Makefile b/bsd/net/Makefile index 1cb5c616e..946c7517a 100644 --- a/bsd/net/Makefile +++ b/bsd/net/Makefile @@ -20,23 +20,29 @@ EXPINC_SUBDIRS_PPC = \ EXPINC_SUBDIRS_I386 = \ DATAFILES= \ - bpf.h bpf_compat.h bpfdesc.h bridge.h dlil.h dlil_pvt.h \ - etherdefs.h ethernet.h hostcache.h if.h if_arp.h if_atm.h \ - if_dl.h if_gif.h if_llc.h if_media.h if_mib.h \ - if_ppp.h if_pppvar.h if_slvar.h if_sppp.h if_tun.h \ - if_tunvar.h if_types.h if_var.h if_vlan_var.h kext_net.h \ - ndrv.h net_osdep.h netisr.h pfkeyv2.h ppp_comp.h ppp_defs.h \ - radix.h raw_cb.h route.h slcompress.h slip.h tokendefs.h \ - tokensr.h zlib.h + bpf.h bpf_compat.h bpfdesc.h dlil.h dlil_pvt.h \ + etherdefs.h ethernet.h if.h if_arp.h \ + if_dl.h if_llc.h if_media.h if_mib.h \ + if_ppp.h if_slvar.h \ + if_types.h if_var.h iso88025.h \ + kext_net.h ndrv.h net_osdep.h netisr.h pfkeyv2.h \ + ppp_defs.h radix.h raw_cb.h route.h slcompress.h slip.h + +PRIVATE_DATAFILES = \ + ndrv_var.h zlib.h if_pppvar.h if_sppp.h ppp_comp.h if_atm.h \ + if_tun.h if_vlan_var.h INSTALL_MI_LIST = ${DATAFILES} INSTALL_MI_DIR = net -EXPORT_MI_LIST = ${DATAFILES} +EXPORT_MI_LIST = ${INSTALL_MI_LIST} -EXPORT_MI_DIR = net +EXPORT_MI_DIR = ${INSTALL_MI_DIR} +INSTALL_MI_LCL_LIST = ${DATAFILES} ${PRIVATE_DATAFILES} + +INSTALL_MI_LCL_KERN_LIST = ${PRIVATE_DATAFILES} include $(MakeInc_rule) include $(MakeInc_dir) diff --git a/bsd/net/bpf.c b/bsd/net/bpf.c index 8c95fcdb6..4c75819d5 100644 --- a/bsd/net/bpf.c +++ b/bsd/net/bpf.c @@ -58,11 +58,10 @@ * * @(#)bpf.c 8.2 (Berkeley) 3/28/94 * + * $FreeBSD: src/sys/net/bpf.c,v 1.59.2.5 2001/01/05 04:49:09 jdp Exp $ */ -#include "bpfilter.h" - -#if NBPFILTER > 0 +#include "bpf.h" #ifndef __GNUC__ #define inline @@ -77,17 +76,17 @@ #include #include #include - - -#include - - #include #include #include #include #include +#if defined(sparc) && BSD < 199103 +#include +#endif +#include + #include #include @@ -104,13 +103,15 @@ #include #include +#if NBPFILTER > 0 + /* * Older BSDs don't have kernel malloc. */ #if BSD < 199103 extern bcopy(); static caddr_t bpf_alloc(); - +#include #define BPF_BUFSIZE (MCLBYTES-8) #define UIOMOVE(cp, len, code, uio) uiomove(cp, len, code, uio) #else @@ -124,27 +125,32 @@ static caddr_t bpf_alloc(); * The default read buffer size is patchable. */ static int bpf_bufsize = BPF_BUFSIZE; - - - SYSCTL_INT(_debug, OID_AUTO, bpf_bufsize, CTLFLAG_RW, &bpf_bufsize, 0, ""); - +static int bpf_maxbufsize = BPF_MAXBUFSIZE; +SYSCTL_INT(_debug, OID_AUTO, bpf_maxbufsize, CTLFLAG_RW, + &bpf_maxbufsize, 0, ""); /* * bpf_iflist is the list of interfaces; each corresponds to an ifnet * bpf_dtab holds the descriptors, indexed by minor device # */ static struct bpf_if *bpf_iflist; +#ifdef __APPLE__ +/* + * BSD now stores the bpf_d in the dev_t which is a struct + * on their system. Our dev_t is an int, so we still store + * the bpf_d in a separate table indexed by minor device #. + */ static struct bpf_d bpf_dtab[NBPFILTER]; static int bpf_dtab_init; static int nbpfilter = NBPFILTER; +#endif static int bpf_allocbufs __P((struct bpf_d *)); static void bpf_attachd __P((struct bpf_d *d, struct bpf_if *bp)); static void bpf_detachd __P((struct bpf_d *d)); static void bpf_freed __P((struct bpf_d *)); -static void bpf_ifname __P((struct ifnet *, struct ifreq *)); static void bpf_mcopy __P((const void *, void *, size_t)); static int bpf_movein __P((struct uio *, int, struct mbuf **, struct sockaddr *, int *)); @@ -156,27 +162,44 @@ static void catchpacket __P((struct bpf_d *, u_char *, u_int, static void reset_d __P((struct bpf_d *)); static int bpf_setf __P((struct bpf_d *, struct bpf_program *)); +/* + * Darwin differs from BSD here, the following are static + * on BSD and not static on Darwin. + */ d_open_t bpfopen; d_close_t bpfclose; d_read_t bpfread; d_write_t bpfwrite; d_ioctl_t bpfioctl; + select_fcn_t bpfpoll; - -#define BPF_MAJOR 7 - +#ifdef __APPLE__ void bpf_mtap(struct ifnet *, struct mbuf *); int bpfopen(), bpfclose(), bpfread(), bpfwrite(), bpfioctl(), bpfpoll(); +#endif - +/* Darwin's cdevsw struct differs slightly from BSDs */ +#define CDEV_MAJOR 23 static struct cdevsw bpf_cdevsw = { - bpfopen, bpfclose, bpfread, bpfwrite, - bpfioctl, nulldev, nulldev, NULL, bpfpoll, - eno_mmap, eno_strat, eno_getc, eno_putc, 0 + /* open */ bpfopen, + /* close */ bpfclose, + /* read */ bpfread, + /* write */ bpfwrite, + /* ioctl */ bpfioctl, + /* stop */ nulldev, + /* reset */ nulldev, + /* tty */ NULL, + /* select */ bpfpoll, + /* mmap */ eno_mmap, + /* strategy*/ eno_strat, + /* getc */ eno_getc, + /* putc */ eno_putc, + /* type */ 0 }; + static int bpf_movein(uio, linktype, mp, sockp, datlen) register struct uio *uio; @@ -239,6 +262,10 @@ bpf_movein(uio, linktype, mp, sockp, datlen) hlen = 12; /* XXX 4(ATM_PH) + 3(LLC) + 5(SNAP) */ break; #endif + case DLT_PPP: + sockp->sa_family = AF_UNSPEC; + hlen = 4; /* This should match PPP_HDRLEN */ + break; default: return (EIO); @@ -290,6 +317,8 @@ bpf_movein(uio, linktype, mp, sockp, datlen) return (error); } +#ifdef __APPLE__ +/* Callback registered with Ethernet driver. */ int bpf_tap_callback(struct ifnet *ifp, struct mbuf *m) { boolean_t funnel_state; @@ -308,7 +337,7 @@ int bpf_tap_callback(struct ifnet *ifp, struct mbuf *m) thread_funnel_set(network_flock, funnel_state); return 0; } - +#endif /* * Attach file to the bpf interface, i.e. make d listen on bp. @@ -319,8 +348,6 @@ bpf_attachd(d, bp) struct bpf_d *d; struct bpf_if *bp; { - struct ifnet *ifp; - /* * Point d at bp, and add d to the interface's list of listeners. * Finally, point the driver's bpf cookie at the interface so @@ -331,10 +358,11 @@ bpf_attachd(d, bp) bp->bif_dlist = d; bp->bif_ifp->if_bpf = bp; - ifp = bp->bif_ifp; - if (ifp->if_set_bpf_tap) - (*ifp->if_set_bpf_tap)(ifp, BPF_TAP_INPUT_OUTPUT, bpf_tap_callback); +#ifdef __APPLE__ + if (bp->bif_ifp->if_set_bpf_tap) + (*bp->bif_ifp->if_set_bpf_tap)(bp->bif_ifp, BPF_TAP_INPUT_OUTPUT, bpf_tap_callback); +#endif } /* @@ -346,11 +374,12 @@ bpf_detachd(d) { struct bpf_d **p; struct bpf_if *bp; +#ifdef __APPLE__ struct ifnet *ifp; ifp = d->bd_bif->bif_ifp; - if (ifp->if_set_bpf_tap) - (*ifp->if_set_bpf_tap)(ifp, BPF_TAP_DISABLE, 0); + +#endif bp = d->bd_bif; /* @@ -364,8 +393,9 @@ bpf_detachd(d) * Something is really wrong if we were able to put * the driver into promiscuous mode, but can't * take it out. + * Most likely the network interface is gone. */ - panic("bpf: ifpromisc failed"); + printf("bpf: ifpromisc failed"); } /* Remove d from the interface's descriptor list. */ p = &bp->bif_dlist; @@ -375,15 +405,19 @@ bpf_detachd(d) panic("bpf_detachd: descriptor not in list"); } *p = (*p)->bd_next; - if (bp->bif_dlist == 0) + if (bp->bif_dlist == 0) { /* * Let the driver know that there are no more listeners. */ + if (ifp->if_set_bpf_tap) + (*ifp->if_set_bpf_tap)(ifp, BPF_TAP_DISABLE, 0); d->bd_bif->bif_ifp->if_bpf = 0; + } d->bd_bif = 0; } +#ifdef __APPLE__ /* * Mark a descriptor free by making it point to itself. * This is probably cheaper than marking with a constant since @@ -392,7 +426,7 @@ bpf_detachd(d) #define D_ISFREE(d) ((d) == (d)->bd_next) #define D_MARKFREE(d) ((d)->bd_next = (d)) #define D_MARKUSED(d) ((d)->bd_next = 0) - +#endif /* * Open ethernet device. Returns ENXIO for illegal minor device number, * EBUSY if file is open by another process. @@ -407,24 +441,42 @@ bpfopen(dev, flags, fmt, p) { register struct bpf_d *d; +#ifdef __APPLE__ if (minor(dev) >= nbpfilter) return (ENXIO); thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); + + d = &bpf_dtab[minor(dev)]; +#else + if (p->p_prison) + return (EPERM); + + d = dev->si_drv1; +#endif /* - * Each minor can be opened by only one process. If the requested + * Each minor can be opened by only one process. If the requested * minor is in use, return EBUSY. */ - d = &bpf_dtab[minor(dev)]; +#ifdef __APPLE__ if (!D_ISFREE(d)) { thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); return (EBUSY); } - + /* Mark "free" and do most initialization. */ bzero((char *)d, sizeof(*d)); +#else + if (d) + return (EBUSY); + make_dev(&bpf_cdevsw, minor(dev), 0, 0, 0600, "bpf%d", lminor(dev)); + MALLOC(d, struct bpf_d *, sizeof(*d), M_BPF, M_WAITOK); + bzero(d, sizeof(*d)); + dev->si_drv1 = d; +#endif d->bd_bufsize = bpf_bufsize; d->bd_sig = SIGIO; + d->bd_seesent = 1; thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); return (0); } @@ -446,12 +498,19 @@ bpfclose(dev, flags, fmt, p) thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); +#ifndef __APPLE__ + funsetown(d->bd_sigio); +#endif s = splimp(); +#ifdef __APPLE__ d = &bpf_dtab[minor(dev)]; +#endif if (d->bd_bif) bpf_detachd(d); splx(s); +#ifdef __APPLE__ selthreadclear(&d->bd_sel); +#endif bpf_freed(d); thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); return (0); @@ -467,8 +526,6 @@ bpf_timeout(arg) { boolean_t funnel_state; struct bpf_d *d = (struct bpf_d *)arg; - - funnel_state = thread_funnel_set(network_flock, TRUE); d->bd_timedout = 1; wakeup(arg); @@ -525,8 +582,6 @@ bpfread(dev, uio, ioflag) int error; int s; - - thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); d = &bpf_dtab[minor(dev)]; @@ -535,7 +590,7 @@ bpfread(dev, uio, ioflag) * as kernel buffers. */ if (uio->uio_resid != d->bd_bufsize) { - thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); + thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); return (EINVAL); } @@ -555,6 +610,19 @@ bpfread(dev, uio, ioflag) ROTATE_BUFFERS(d); break; } + + /* + * No data is available, check to see if the bpf device + * is still pointed at a real interface. If not, return + * ENXIO so that the userland process knows to rebind + * it before using it again. + */ + if (d->bd_bif == NULL) { + splx(s); + thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); + return (ENXIO); + } + if (ioflag & IO_NDELAY) error = EWOULDBLOCK; else @@ -623,6 +691,10 @@ bpf_wakeup(d) #if BSD >= 199103 selwakeup(&d->bd_sel); +#ifndef __APPLE__ + /* XXX */ + d->bd_sel.si_pid = 0; +#endif #else if (d->bd_selproc) { selwakeup(d->bd_selproc, (int)d->bd_selcoll); @@ -639,17 +711,15 @@ bpfwrite(dev, uio, ioflag) int ioflag; { register struct bpf_d *d; - struct ifnet *ifp; struct mbuf *m; int error, s; static struct sockaddr dst; int datlen; - - thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); d = &bpf_dtab[minor(dev)]; + if (d->bd_bif == 0) { thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); return (ENXIO); @@ -673,18 +743,16 @@ bpfwrite(dev, uio, ioflag) return (EMSGSIZE); } - s = splnet(); + if (d->bd_hdrcmplt) + dst.sa_family = pseudo_AF_HDRCMPLT; - error = dlil_output((u_long) ifp, m, - (caddr_t) 0, &dst, 0); + s = splnet(); - /* - error = dlil_inject_if_output(m, DLIL_NULL_FILTER); - */ + error = dlil_output(ifp->if_data.default_proto, m, + (caddr_t) 0, &dst, 0); splx(s); thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); - /* * The driver frees the mbuf. */ @@ -725,9 +793,13 @@ reset_d(d) * BIOCGSTATS Get packet stats. * BIOCIMMEDIATE Set immediate mode. * BIOCVERSION Get filter language version. + * BIOCGHDRCMPLT Get "header already complete" flag + * BIOCSHDRCMPLT Set "header already complete" flag + * BIOCGSEESENT Get "see packets sent" flag + * BIOCSSEESENT Set "see packets sent" flag */ /* ARGSUSED */ - int +int bpfioctl(dev, cmd, addr, flags, p) dev_t dev; u_long cmd; @@ -797,8 +869,8 @@ bpfioctl(dev, cmd, addr, flags, p) else { register u_int size = *(u_int *)addr; - if (size > BPF_MAXBUFSIZE) - *(u_int *)addr = size = BPF_MAXBUFSIZE; + if (size > bpf_maxbufsize) + *(u_int *)addr = size = bpf_maxbufsize; else if (size < BPF_MINBUFSIZE) *(u_int *)addr = size = BPF_MINBUFSIZE; d->bd_bufsize = size; @@ -853,13 +925,18 @@ bpfioctl(dev, cmd, addr, flags, p) break; /* - * Set interface name. + * Get interface name. */ case BIOCGETIF: if (d->bd_bif == 0) error = EINVAL; - else - bpf_ifname(d->bd_bif->bif_ifp, (struct ifreq *)addr); + else { + struct ifnet *const ifp = d->bd_bif->bif_ifp; + struct ifreq *const ifr = (struct ifreq *)addr; + + snprintf(ifr->ifr_name, sizeof(ifr->ifr_name), + "%s%d", ifp->if_name, ifp->if_unit); + } break; /* @@ -925,13 +1002,41 @@ bpfioctl(dev, cmd, addr, flags, p) break; } + /* + * Get "header already complete" flag + */ + case BIOCGHDRCMPLT: + *(u_int *)addr = d->bd_hdrcmplt; + break; + + /* + * Set "header already complete" flag + */ + case BIOCSHDRCMPLT: + d->bd_hdrcmplt = *(u_int *)addr ? 1 : 0; + break; + + /* + * Get "see sent packets" flag + */ + case BIOCGSEESENT: + *(u_int *)addr = d->bd_seesent; + break; + + /* + * Set "see sent packets" flag + */ + case BIOCSSEESENT: + d->bd_seesent = *(u_int *)addr; + break; + case FIONBIO: /* Non-blocking I/O */ break; case FIOASYNC: /* Send signal on receive packets */ d->bd_async = *(int *)addr; break; -#if ISFB31 +#ifndef __APPLE__ case FIOSETOWN: error = fsetown(*(int *)addr, &d->bd_sigio); break; @@ -1001,8 +1106,10 @@ bpf_setf(d, fp) size = flen * sizeof(*fp->bf_insns); fcode = (struct bpf_insn *) _MALLOC(size, M_DEVBUF, M_WAIT); +#ifdef __APPLE__ if (fcode == NULL) return (ENOBUFS); +#endif if (copyin((caddr_t)fp->bf_insns, (caddr_t)fcode, size) == 0 && bpf_validate(fcode, (int)flen)) { s = splimp(); @@ -1077,28 +1184,6 @@ bpf_setif(d, ifr) return (ENXIO); } -/* - * Convert an interface name plus unit number of an ifp to a single - * name which is returned in the ifr. - */ -static void -bpf_ifname(ifp, ifr) - struct ifnet *ifp; - struct ifreq *ifr; -{ - char *s = ifp->if_name; - char *d = ifr->ifr_name; - - while (*d++ = *s++) - continue; - d--; /* back to the null */ - /* XXX Assume that unit number is less than 10. */ - *d++ = ifp->if_unit + '0'; - *d = '\0'; -} - - - /* * Support for select() and poll() system calls * @@ -1122,13 +1207,18 @@ bpfpoll(dev, events, wql, p) */ d = &bpf_dtab[minor(dev)]; + if (d->bd_bif == NULL) { + thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); + return (ENXIO); + } + s = splimp(); - if (events & (POLLIN | POLLRDNORM)) + if (events & (POLLIN | POLLRDNORM)) { if (d->bd_hlen != 0 || (d->bd_immediate && d->bd_slen != 0)) revents |= events & (POLLIN | POLLRDNORM); else selrecord(p, &d->bd_sel, wql); - + } splx(s); thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); return (revents); @@ -1155,15 +1245,20 @@ bpf_tap(ifp, pkt, pktlen) * interfaces shared any data. This is not the case. */ thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); - if ((bp = ifp->if_bpf)) { - for (d = bp->bif_dlist; d != 0; d = d->bd_next) { - ++d->bd_rcount; - slen = bpf_filter(d->bd_filter, pkt, pktlen, pktlen); - if (slen != 0) - catchpacket(d, pkt, pktlen, slen, bcopy); - } + bp = ifp->if_bpf; +#ifdef __APPLE__ + if (bp) { +#endif + for (d = bp->bif_dlist; d != 0; d = d->bd_next) { + ++d->bd_rcount; + slen = bpf_filter(d->bd_filter, pkt, pktlen, pktlen); + if (slen != 0) + catchpacket(d, pkt, pktlen, slen, bcopy); + } +#ifdef __APPLE__ } thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); +#endif } /* @@ -1211,6 +1306,8 @@ bpf_mtap(ifp, m) pktlen += m0->m_len; for (d = bp->bif_dlist; d != 0; d = d->bd_next) { + if (!d->bd_seesent && (m->m_pkthdr.rcvif == NULL)) + continue; ++d->bd_rcount; slen = bpf_filter(d->bd_filter, (u_char *)m, pktlen, 0); if (slen != 0) @@ -1375,6 +1472,7 @@ bpfattach(ifp, dlt, hdrlen) */ bp->bif_hdrlen = BPF_WORDALIGN(hdrlen + SIZEOF_BPF_HDR) - hdrlen; +#ifdef __APPLE__ /* * Mark all the descriptors free if this hasn't been done. */ @@ -1383,42 +1481,151 @@ bpfattach(ifp, dlt, hdrlen) D_MARKFREE(&bpf_dtab[i]); bpf_dtab_init = 1; } -#if 0 +#else if (bootverbose) printf("bpf: %s%d attached\n", ifp->if_name, ifp->if_unit); #endif } +/* + * Detach bpf from an interface. This involves detaching each descriptor + * associated with the interface, and leaving bd_bif NULL. Notify each + * descriptor as it's detached so that any sleepers wake up and get + * ENXIO. + */ +void +bpfdetach(ifp) + struct ifnet *ifp; +{ + struct bpf_if *bp, *bp_prev; + struct bpf_d *d; + int s; + + s = splimp(); + + /* Locate BPF interface information */ + bp_prev = NULL; + for (bp = bpf_iflist; bp != NULL; bp = bp->bif_next) { + if (ifp == bp->bif_ifp) + break; + bp_prev = bp; + } + +#ifdef __APPLE__ + /* Check for no BPF interface information */ + if (bp == NULL) { + return; + } +#endif + + /* Interface wasn't attached */ + if (bp->bif_ifp == NULL) { + splx(s); +#ifndef __APPLE__ + printf("bpfdetach: %s%d was not attached\n", ifp->if_name, + ifp->if_unit); +#endif + return; + } + + while ((d = bp->bif_dlist) != NULL) { + bpf_detachd(d); + bpf_wakeup(d); + } + + if (bp_prev) { + bp_prev->bif_next = bp->bif_next; + } else { + bpf_iflist = bp->bif_next; + } + + FREE(bp, M_DEVBUF); + + splx(s); +} + static void *bpf_devfs_token[NBPFILTER]; static int bpf_devsw_installed; void bpf_init __P((void *unused)); + void bpf_init(unused) void *unused; { +#ifdef __APPLE__ int i; - int maj; + int maj; if (!bpf_devsw_installed ) { - bpf_devsw_installed = 1; - maj = cdevsw_add(BPF_MAJOR, &bpf_cdevsw); - if (maj == -1) { - printf("bpf_init: failed to allocate a major number!\n"); - nbpfilter = 0; - return; - } - for (i = 0 ; i < nbpfilter; i++) { - bpf_devfs_token[i] = devfs_make_node(makedev(maj, i), - DEVFS_CHAR, UID_ROOT, GID_WHEEL, 0600, - "bpf%x", i); - } - } + bpf_devsw_installed = 1; + maj = cdevsw_add(CDEV_MAJOR, &bpf_cdevsw); + if (maj == -1) { + printf("bpf_init: failed to allocate a major number!\n"); + nbpfilter = 0; + return; + } + for (i = 0 ; i < nbpfilter; i++) { + bpf_devfs_token[i] = devfs_make_node(makedev(maj, i), + DEVFS_CHAR, UID_ROOT, GID_WHEEL, 0600, + "bpf%x", i); + } + } +#else + cdevsw_add(&bpf_cdevsw); +#endif } -/* +#ifndef __APPLE__ SYSINIT(bpfdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,bpf_drvinit,NULL) -*/ - #endif + +#else /* !BPF */ +#ifndef __APPLE__ +/* + * NOP stubs to allow bpf-using drivers to load and function. + * + * A 'better' implementation would allow the core bpf functionality + * to be loaded at runtime. + */ + +void +bpf_tap(ifp, pkt, pktlen) + struct ifnet *ifp; + register u_char *pkt; + register u_int pktlen; +{ +} + +void +bpf_mtap(ifp, m) + struct ifnet *ifp; + struct mbuf *m; +{ +} + +void +bpfattach(ifp, dlt, hdrlen) + struct ifnet *ifp; + u_int dlt, hdrlen; +{ +} + +void +bpfdetach(ifp) + struct ifnet *ifp; +{ +} + +u_int +bpf_filter(pc, p, wirelen, buflen) + register const struct bpf_insn *pc; + register u_char *p; + u_int wirelen; + register u_int buflen; +{ + return -1; /* "no filter" behaviour */ +} +#endif /* !defined(__APPLE__) */ +#endif /* NBPFILTER > 0 */ diff --git a/bsd/net/bpf.h b/bsd/net/bpf.h index a930619f0..6f3afea4d 100644 --- a/bsd/net/bpf.h +++ b/bsd/net/bpf.h @@ -59,10 +59,14 @@ * @(#)bpf.h 8.1 (Berkeley) 6/10/93 * @(#)bpf.h 1.34 (LBL) 6/16/96 * + * $FreeBSD: src/sys/net/bpf.h,v 1.21.2.3 2001/08/01 00:23:13 fenner Exp $ */ #ifndef _NET_BPF_H_ #define _NET_BPF_H_ +#include +#include +#include /* BSD style release date */ #define BPF_RELEASE 199606 @@ -81,7 +85,6 @@ typedef u_int32_t bpf_u_int32; #define BPF_MAXBUFSIZE 0x8000 #define BPF_MINBUFSIZE 32 - /* * Structure for BIOCSETF. */ @@ -132,6 +135,10 @@ struct bpf_version { #define BIOCVERSION _IOR('B',113, struct bpf_version) #define BIOCGRSIG _IOR('B',114, u_int) #define BIOCSRSIG _IOW('B',115, u_int) +#define BIOCGHDRCMPLT _IOR('B',116, u_int) +#define BIOCSHDRCMPLT _IOW('B',117, u_int) +#define BIOCGSEESENT _IOR('B',118, u_int) +#define BIOCSSEESENT _IOW('B',119, u_int) /* * Structure prepended to each packet. @@ -169,8 +176,88 @@ struct bpf_hdr { #define DLT_FDDI 10 /* FDDI */ #define DLT_ATM_RFC1483 11 /* LLC/SNAP encapsulated atm */ #define DLT_RAW 12 /* raw IP */ -#define DLT_SLIP_BSDOS 13 /* BSD/OS Serial Line IP */ -#define DLT_PPP_BSDOS 14 /* BSD/OS Point-to-point Protocol */ + +/* + * These are values from BSD/OS's "bpf.h". + * These are not the same as the values from the traditional libpcap + * "bpf.h"; however, these values shouldn't be generated by any + * OS other than BSD/OS, so the correct values to use here are the + * BSD/OS values. + * + * Platforms that have already assigned these values to other + * DLT_ codes, however, should give these codes the values + * from that platform, so that programs that use these codes will + * continue to compile - even though they won't correctly read + * files of these types. + */ +#define DLT_SLIP_BSDOS 15 /* BSD/OS Serial Line IP */ +#define DLT_PPP_BSDOS 16 /* BSD/OS Point-to-point Protocol */ + +#define DLT_ATM_CLIP 19 /* Linux Classical-IP over ATM */ + +/* + * This value is defined by NetBSD; other platforms should refrain from + * using it for other purposes, so that NetBSD savefiles with a link + * type of 50 can be read as this type on all platforms. + */ +#define DLT_PPP_SERIAL 50 /* PPP over serial with HDLC encapsulation */ + +/* + * This value was defined by libpcap 0.5; platforms that have defined + * it with a different value should define it here with that value - + * a link type of 104 in a save file will be mapped to DLT_C_HDLC, + * whatever value that happens to be, so programs will correctly + * handle files with that link type regardless of the value of + * DLT_C_HDLC. + * + * The name DLT_C_HDLC was used by BSD/OS; we use that name for source + * compatibility with programs written for BSD/OS. + * + * libpcap 0.5 defined it as DLT_CHDLC; we define DLT_CHDLC as well, + * for source compatibility with programs written for libpcap 0.5. + */ +#define DLT_C_HDLC 104 /* Cisco HDLC */ +#define DLT_CHDLC DLT_C_HDLC + +/* + * Reserved for future use. + * Do not pick other numerical value for these unless you have also + * picked up the tcpdump.org top-of-CVS-tree version of "savefile.c", + * which will arrange that capture files for these DLT_ types have + * the same "network" value on all platforms, regardless of what + * value is chosen for their DLT_ type (thus allowing captures made + * on one platform to be read on other platforms, even if the two + * platforms don't use the same numerical values for all DLT_ types). + */ +#define DLT_IEEE802_11 105 /* IEEE 802.11 wireless */ + +/* + * Values between 106 and 107 are used in capture file headers as + * link-layer types corresponding to DLT_ types that might differ + * between platforms; don't use those values for new DLT_ new types. + */ + +/* + * OpenBSD DLT_LOOP, for loopback devices; it's like DLT_NULL, except + * that the AF_ type in the link-layer header is in network byte order. + * + * OpenBSD defines it as 12, but that collides with DLT_RAW, so we + * define it as 108 here. If OpenBSD picks up this file, it should + * define DLT_LOOP as 12 in its version, as per the comment above - + * and should not use 108 for any purpose. + */ +#define DLT_LOOP 108 + +/* + * Values between 109 and 112 are used in capture file headers as + * link-layer types corresponding to DLT_ types that might differ + * between platforms; don't use those values for new DLT_ new types. + */ + +/* + * This is for Linux cooked sockets. + */ +#define DLT_LINUX_SLL 113 /* * The instruction encodings. @@ -244,20 +331,31 @@ struct bpf_insn { #define BPF_STMT(code, k) { (u_short)(code), 0, 0, k } #define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k } +/* Forward declerations */ +struct ifnet; +struct mbuf; + #ifdef KERNEL -int bpf_validate __P((struct bpf_insn *, int)); +#ifdef __APPLE_API_UNSTABLE +int bpf_validate __P((const struct bpf_insn *, int)); void bpf_tap __P((struct ifnet *, u_char *, u_int)); void bpf_mtap __P((struct ifnet *, struct mbuf *)); -void bpfattach __P(( struct ifnet *, u_int, u_int)); +void bpfattach __P((struct ifnet *, u_int, u_int)); +void bpfdetach __P((struct ifnet *)); + void bpfilterattach __P((int)); -u_int bpf_filter __P((struct bpf_insn *, u_char *, u_int, u_int)); -#endif +u_int bpf_filter __P((const struct bpf_insn *, u_char *, u_int, u_int)); + +#ifdef __APPLE__ +#define BPF_TAP(x, y, z) bpf_tap(x,y,z) +#define BPF_MTAP(x, y) bpf_mtap(x, y) +#endif /* __APPLE__ */ +#endif /* __APPLE_API_UNSTABLE */ +#endif /* KERNEL */ /* * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST). */ #define BPF_MEMWORDS 16 -#define BPF_TAP(x, y, z) bpf_tap(x,y,z) -#define BPF_MTAP(x, y) bpf_mtap(x, y) #endif diff --git a/bsd/net/bpf_compat.h b/bsd/net/bpf_compat.h index 550bdd836..ddec919d9 100644 --- a/bsd/net/bpf_compat.h +++ b/bsd/net/bpf_compat.h @@ -52,6 +52,7 @@ * SUCH DAMAGE. * * @(#)bpf_compat.h 8.1 (Berkeley) 6/10/93 + * $FreeBSD: src/sys/net/bpf_compat.h,v 1.6 1999/08/28 00:48:13 peter Exp $ */ #ifndef _NET_BPF_COMPAT_H_ diff --git a/bsd/net/bpf_filter.c b/bsd/net/bpf_filter.c index 72976d9c8..102e3c492 100644 --- a/bsd/net/bpf_filter.c +++ b/bsd/net/bpf_filter.c @@ -58,6 +58,7 @@ * * @(#)bpf_filter.c 8.1 (Berkeley) 6/10/93 * + * $FreeBSD: src/sys/net/bpf_filter.c,v 1.17 1999/12/29 04:38:31 peter Exp $ */ #include @@ -203,7 +204,7 @@ m_xhalf(m, k, err) */ u_int bpf_filter(pc, p, wirelen, buflen) - register struct bpf_insn *pc; + register const struct bpf_insn *pc; register u_char *p; u_int wirelen; register u_int buflen; @@ -305,7 +306,8 @@ bpf_filter(pc, p, wirelen, buflen) case BPF_LD|BPF_W|BPF_IND: k = X + pc->k; - if (pc->k > buflen || X > buflen - pc->k || sizeof(int32_t) > buflen - k) { + if (pc->k > buflen || X > buflen - pc->k || + sizeof(int32_t) > buflen - k) { #ifdef KERNEL int merr; @@ -329,7 +331,8 @@ bpf_filter(pc, p, wirelen, buflen) case BPF_LD|BPF_H|BPF_IND: k = X + pc->k; - if (X > buflen || pc->k > buflen - X || sizeof(int16_t) > buflen - pc->k) { + if (X > buflen || pc->k > buflen - X || + sizeof(int16_t) > buflen - k) { #ifdef KERNEL int merr; @@ -538,11 +541,11 @@ bpf_filter(pc, p, wirelen, buflen) */ int bpf_validate(f, len) - struct bpf_insn *f; + const struct bpf_insn *f; int len; { register int i; - register struct bpf_insn *p; + const struct bpf_insn *p; for (i = 0; i < len; ++i) { /* @@ -557,7 +560,8 @@ bpf_validate(f, len) if (from >= len || p->k >= len - from) return 0; } - else if (from >= len || p->jt >= len - from || p->jf >= len - from) + else if (from >= len || p->jt >= len - from || + p->jf >= len - from) return 0; } /* diff --git a/bsd/net/bpfdesc.h b/bsd/net/bpfdesc.h index 194640f3c..b8f80bb63 100644 --- a/bsd/net/bpfdesc.h +++ b/bsd/net/bpfdesc.h @@ -58,10 +58,16 @@ * * @(#)bpfdesc.h 8.1 (Berkeley) 6/10/93 * + * $FreeBSD: src/sys/net/bpfdesc.h,v 1.14.2.1 2000/03/19 05:55:36 rwatson Exp $ */ #ifndef _NET_BPFDESC_H_ #define _NET_BPFDESC_H_ +#include +#ifdef __APPLE_API_PRIVATE +/* + * The items in this header file should be wrapped in #ifdef KERNEL. + */ #include @@ -98,10 +104,10 @@ struct bpf_d { u_char bd_immediate; /* true to return on packet arrival */ int bd_async; /* non-zero if packet reception should generate signal */ int bd_sig; /* signal to send upon packet reception */ -#if ISFB31 - struct sigio * bd_sigio; /* information for async I/O */ -#else +#ifdef __APPLE__ pid_t bd_sigio; +#else + struct sigio * bd_sigio; /* information for async I/O */ #endif #if BSD < 199103 @@ -112,6 +118,9 @@ struct bpf_d { u_char bd_pad; /* explicit alignment */ struct selinfo bd_sel; /* bsd select info */ #endif + int bd_hdrcmplt; /* false to fill in src lladdr automatically */ + int bd_seesent; /* true if bpf should see sent packets */ + }; /* @@ -125,4 +134,5 @@ struct bpf_if { struct ifnet *bif_ifp; /* corresponding interface */ }; +#endif /* __APPLE_API_PRIVATE */ #endif diff --git a/bsd/net/bridge.c b/bsd/net/bridge.c index d562eb62d..2f364dee5 100644 --- a/bsd/net/bridge.c +++ b/bsd/net/bridge.c @@ -43,6 +43,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * $FreeBSD: src/sys/net/bridge.c,v 1.16.2.14 2001/02/09 23:13:41 luigi Exp $ */ /* @@ -51,14 +52,13 @@ * A bridging table holds the source MAC address/dest. interface for each * known node. The table is indexed using an hash of the source address. * - * Input packets are tapped near the end of the input routine in each - * driver (near the call to bpf_mtap, or before the call to ether_input) - * and analysed calling bridge_in(). Depending on the result, the packet + * Input packets are tapped near the beginning of ether_input(), and + * analysed by calling bridge_in(). Depending on the result, the packet * can be forwarded to one or more output interfaces using bdg_forward(), * and/or sent to the upper layer (e.g. in case of multicast). * * Output packets are intercepted near the end of ether_output(), - * the correct destination is selected calling bdg_dst_lookup(), + * the correct destination is selected calling bridge_dst_lookup(), * and then forwarding is done using bdg_forward(). * Bridging is controlled by the sysctl variable net.link.ether.bridge * @@ -67,9 +67,8 @@ * * In case of loops in the bridging topology, the bridge detects this * event and temporarily mutes output bridging on one of the ports. - * Periodically, interfaces are unmuted by bdg_timeout(). (For the - * mute flag i am temporarily using IFF_LINK2 but this has to - * change.) Muting is only implemented as a safety measure, and also as + * Periodically, interfaces are unmuted by bdg_timeout(). + * Muting is only implemented as a safety measure, and also as * a mechanism to support a user-space implementation of the spanning * tree algorithm. In the final release, unmuting will only occur * because of explicit action of the user-level daemon. @@ -85,11 +84,6 @@ * from doing both (modulo bugs in the implementation...). * * THINGS TO REMEMBER - * - bridging requires some (small) modifications to the interface - * driver. Currently (980911) the "ed", "de", "tx", "lnc" drivers - * have been modified and tested. "fxp", "ep", "fe" have been - * modified but not tested. See the "ed" and "de" drivers as - * examples on how to operate. * - bridging is incompatible with multicast routing on the same * machine. There is not an easy fix to this. * - loop detection is still not very robust. @@ -116,11 +110,13 @@ #include "opt_ipfw.h" #include "opt_ipdn.h" -#if defined(IPFIREWALL) && defined(DUMMYNET) +#if defined(IPFIREWALL) #include #include +#if defined(DUMMYNET) #include #endif +#endif #include @@ -139,79 +135,244 @@ #define DDB(x) x #define DEB(x) -/* - * System initialization - */ - static void bdginit(void *); +static void bdgtakeifaces(void); static void flush_table(void); - -SYSINIT(interfaces, SI_SUB_PROTO_IF, SI_ORDER_FIRST, bdginit, NULL) +static void bdg_promisc_on(void); +static void parse_bdg_cfg(void); static int bdg_ipfw = 0 ; int do_bridge = 0; bdg_hash_table *bdg_table = NULL ; /* - * we need additional info for the bridge. The bdg_ifp2sc[] array - * provides a pointer to this struct using the if_index. - * bdg_softc has a backpointer to the struct ifnet, the bridge - * flags, and a group (bridging occurs only between port of the - * same group). + * System initialization + */ + +SYSINIT(interfaces, SI_SUB_PROTO_IF, SI_ORDER_FIRST, bdginit, NULL) + +static struct bdg_stats bdg_stats ; +struct bdg_softc *ifp2sc = NULL ; +/* XXX make it static of size BDG_MAX_PORTS */ + +#define IFP_CHK(ifp, x) \ + if (ifp2sc[ifp->if_index].magic != 0xDEADBEEF) { x ; } + +/* + * turn off promisc mode, optionally clear the IFF_USED flag. + * The flag is turned on by parse_bdg_config */ -struct bdg_softc { +static void +bdg_promisc_off(int clear_used) +{ struct ifnet *ifp ; - /* ((struct arpcom *)ifp)->ac_enaddr is the eth. addr */ - int flags ; - int group ; -} ; - -static struct bdg_softc **ifp2sc = NULL ; - -#if 0 /* new code using ifp2sc */ -#define SAMEGROUP(ifp,src) (src == NULL || \ - ifp2sc[ifp->if_index]->group == ifp2sc[src->if_index]->group ) -#define MUTED(ifp) (ifp2sc[ifp->if_index]->flags & IFF_MUTE) -#define MUTE(ifp) ifp2sc[ifp->if_index]->flags |= IFF_MUTE -#define UNMUTE(ifp) ifp2sc[ifp->if_index]->flags &= ~IFF_MUTE -#else -#define SAMEGROUP(a,b) 1 -#define MUTED(ifp) (ifp->if_flags & IFF_MUTE) -#define MUTE(ifp) ifp->if_flags |= IFF_MUTE -#define UNMUTE(ifp) ifp->if_flags &= ~IFF_MUTE -#endif + TAILQ_FOREACH(ifp, &ifnet, if_link) { + if ( (ifp2sc[ifp->if_index].flags & IFF_BDG_PROMISC) ) { + int s, ret ; + s = splimp(); + ret = ifpromisc(ifp, 0); + splx(s); + ifp2sc[ifp->if_index].flags &= ~(IFF_BDG_PROMISC|IFF_MUTE) ; + DEB(printf(">> now %s%d promisc OFF if_flags 0x%x bdg_flags 0x%x\n", + ifp->if_name, ifp->if_unit, + ifp->if_flags, ifp2sc[ifp->if_index].flags);) + } + if (clear_used) { + ifp2sc[ifp->if_index].flags &= ~(IFF_USED) ; + bdg_stats.s[ifp->if_index].name[0] = '\0'; + } + } +} + +/* + * set promisc mode on the interfaces we use. + */ +static void +bdg_promisc_on() +{ + struct ifnet *ifp ; + int s ; + + TAILQ_FOREACH(ifp, &ifnet, if_link) { + if ( !BDG_USED(ifp) ) + continue ; + if ( 0 == ( ifp->if_flags & IFF_UP) ) { + s = splimp(); + if_up(ifp); + splx(s); + } + if ( !(ifp2sc[ifp->if_index].flags & IFF_BDG_PROMISC) ) { + int ret ; + s = splimp(); + ret = ifpromisc(ifp, 1); + splx(s); + ifp2sc[ifp->if_index].flags |= IFF_BDG_PROMISC ; + printf(">> now %s%d promisc ON if_flags 0x%x bdg_flags 0x%x\n", + ifp->if_name, ifp->if_unit, + ifp->if_flags, ifp2sc[ifp->if_index].flags); + } + if (BDG_MUTED(ifp)) { + printf(">> unmuting %s%d\n", ifp->if_name, ifp->if_unit); + BDG_UNMUTE(ifp) ; + } + } +} static int -sysctl_bdg SYSCTL_HANDLER_ARGS +sysctl_bdg(SYSCTL_HANDLER_ARGS) { int error, oldval = do_bridge ; error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); - printf("called sysctl for bridge name %s arg2 %d val %d->%d\n", + DEB( printf("called sysctl for bridge name %s arg2 %d val %d->%d\n", oidp->oid_name, oidp->oid_arg2, - oldval, do_bridge); + oldval, do_bridge); ) + if (bdg_table == NULL) do_bridge = 0 ; if (oldval != do_bridge) { + bdg_promisc_off( 1 ); /* reset previously used interfaces */ flush_table(); + if (do_bridge) { + parse_bdg_cfg(); + bdg_promisc_on(); + } } return error ; } +static char bridge_cfg[256] = { "" } ; + +/* + * parse the config string, set IFF_USED, name and cluster_id + * for all interfaces found. + */ +static void +parse_bdg_cfg() +{ + char *p, *beg ; + int i, l, cluster; + struct bdg_softc *b; + + for (p= bridge_cfg; *p ; p++) { + /* interface names begin with [a-z] and continue up to ':' */ + if (*p < 'a' || *p > 'z') + continue ; + for ( beg = p ; *p && *p != ':' ; p++ ) + ; + if (*p == 0) /* end of string, ':' not found */ + return ; + l = p - beg ; /* length of name string */ + p++ ; + DEB(printf("-- match beg(%d) <%s> p <%s>\n", l, beg, p);) + for (cluster = 0 ; *p && *p >= '0' && *p <= '9' ; p++) + cluster = cluster*10 + (*p -'0'); + /* + * now search in bridge strings + */ + for (i=0, b = ifp2sc ; i < if_index ; i++, b++) { + char buf[32]; + struct ifnet *ifp = b->ifp ; + + if (ifp == NULL) + continue; + sprintf(buf, "%s%d", ifp->if_name, ifp->if_unit); + if (!strncmp(beg, buf, l)) { /* XXX not correct for >10 if! */ + b->cluster_id = htons(cluster) ; + b->flags |= IFF_USED ; + sprintf(bdg_stats.s[ifp->if_index].name, + "%s%d:%d", ifp->if_name, ifp->if_unit, cluster); + + DEB(printf("--++ found %s\n", + bdg_stats.s[ifp->if_index].name);) + break ; + } + } + if (*p == '\0') + break ; + } +} + +static int +sysctl_bdg_cfg(SYSCTL_HANDLER_ARGS) +{ + int error = 0 ; + char oldval[256] ; + + strcpy(oldval, bridge_cfg) ; + + error = sysctl_handle_string(oidp, + bridge_cfg, oidp->oid_arg2, req); + DEB( + printf("called sysctl for bridge name %s arg2 %d err %d val %s->%s\n", + oidp->oid_name, oidp->oid_arg2, + error, + oldval, bridge_cfg); + ) + if (strcmp(oldval, bridge_cfg)) { + bdg_promisc_off( 1 ); /* reset previously-used interfaces */ + flush_table(); + parse_bdg_cfg(); /* and set new ones... */ + if (do_bridge) + bdg_promisc_on(); /* re-enable interfaces */ + } + return error ; +} + +static int +sysctl_refresh(SYSCTL_HANDLER_ARGS) +{ + if (req->newptr) + bdgtakeifaces(); + + return 0; +} + + SYSCTL_DECL(_net_link_ether); +SYSCTL_PROC(_net_link_ether, OID_AUTO, bridge_cfg, CTLTYPE_STRING|CTLFLAG_RW, + &bridge_cfg, sizeof(bridge_cfg), &sysctl_bdg_cfg, "A", + "Bridge configuration"); + SYSCTL_PROC(_net_link_ether, OID_AUTO, bridge, CTLTYPE_INT|CTLFLAG_RW, - &do_bridge, 0, &sysctl_bdg, "I", "Bridging"); + &do_bridge, 0, &sysctl_bdg, "I", "Bridging"); + +SYSCTL_INT(_net_link_ether, OID_AUTO, bridge_ipfw, CTLFLAG_RW, + &bdg_ipfw,0,"Pass bridged pkts through firewall"); + +#define SY(parent, var, comment) \ + static int var ; \ + SYSCTL_INT(parent, OID_AUTO, var, CTLFLAG_RW, &(var), 0, comment); + +int bdg_ipfw_drops; +SYSCTL_INT(_net_link_ether, OID_AUTO, bridge_ipfw_drop, + CTLFLAG_RW, &bdg_ipfw_drops,0,""); + +int bdg_ipfw_colls; +SYSCTL_INT(_net_link_ether, OID_AUTO, bridge_ipfw_collisions, + CTLFLAG_RW, &bdg_ipfw_colls,0,""); + +SYSCTL_PROC(_net_link_ether, OID_AUTO, bridge_refresh, CTLTYPE_INT|CTLFLAG_WR, + NULL, 0, &sysctl_refresh, "I", "iface refresh"); -SYSCTL_INT(_net_link_ether, OID_AUTO, bridge_ipfw, CTLFLAG_RW, &bdg_ipfw,0,""); #if 1 /* diagnostic vars */ -int bdg_in_count = 0 , bdg_in_ticks = 0 , bdg_fw_count = 0, bdg_fw_ticks = 0 ; -SYSCTL_INT(_net_link_ether, OID_AUTO, bdginc, CTLFLAG_RW, &bdg_in_count,0,""); -SYSCTL_INT(_net_link_ether, OID_AUTO, bdgint, CTLFLAG_RW, &bdg_in_ticks,0,""); -SYSCTL_INT(_net_link_ether, OID_AUTO, bdgfwc, CTLFLAG_RW, &bdg_fw_count,0,""); -SYSCTL_INT(_net_link_ether, OID_AUTO, bdgfwt, CTLFLAG_RW, &bdg_fw_ticks,0,""); + +SY(_net_link_ether, verbose, "Be verbose"); +SY(_net_link_ether, bdg_split_pkts, "Packets split in bdg_forward"); + +SY(_net_link_ether, bdg_thru, "Packets through bridge"); + +SY(_net_link_ether, bdg_copied, "Packets copied in bdg_forward"); + +SY(_net_link_ether, bdg_copy, "Force copy in bdg_forward"); +SY(_net_link_ether, bdg_predict, "Correctly predicted header location"); + +SY(_net_link_ether, bdg_fw_avg, "Cycle counter avg"); +SY(_net_link_ether, bdg_fw_ticks, "Cycle counter item"); +SY(_net_link_ether, bdg_fw_count, "Cycle counter count"); #endif -static struct bdg_stats bdg_stats ; + SYSCTL_STRUCT(_net_link_ether, PF_BDG, bdgstats, CTLFLAG_RD, &bdg_stats , bdg_stats, "bridge statistics"); @@ -250,12 +411,8 @@ bdg_timeout_funneled(void * dummy) static void bdg_timeout(void *dummy) { - struct ifnet *ifp ; - int s ; static int slowtimer = 0 ; - boolean_t funnel_state; - - + if (do_bridge) { static int age_index = 0 ; /* index of table position to age */ int l = age_index + HASH_SIZE/4 ; @@ -277,109 +434,90 @@ bdg_timeout(void *dummy) if (--slowtimer <= 0 ) { slowtimer = 5 ; - for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) { - if (ifp->if_type != IFT_ETHER) - continue ; - if ( 0 == ( ifp->if_flags & IFF_UP) ) { - s = splimp(); - if_up(ifp); - splx(s); - } - if ( 0 == ( ifp->if_flags & IFF_PROMISC) ) { - int ret ; - s = splimp(); - ret = ifpromisc(ifp, 1); - splx(s); - printf(">> now %s%d flags 0x%x promisc %d\n", - ifp->if_name, ifp->if_unit, - ifp->if_flags, ret); - } - if (MUTED(ifp)) { - printf(">> unmuting %s%d\n", ifp->if_name, ifp->if_unit); - UNMUTE(ifp) ; - } - } + bdg_promisc_on() ; /* we just need unmute, really */ bdg_loops = 0 ; } } timeout(bdg_timeout_funneled, (void *)0, 2*hz ); - } /* * local MAC addresses are held in a small array. This makes comparisons * much faster. */ -unsigned char bdg_addresses[6*BDG_MAX_PORTS]; +bdg_addr bdg_addresses[BDG_MAX_PORTS]; int bdg_ports ; /* - * initialization of bridge code. + * initialization of bridge code. This needs to be done after all + * interfaces have been configured. */ static void -bdginit(dummy) - void *dummy; +bdginit(void *dummy) { - int i ; - struct ifnet *ifp; - struct arpcom *ac ; - u_char *eth_addr ; - /* - * initialization of bridge code - */ + if (bdg_table == NULL) bdg_table = (struct hash_table *) _MALLOC(HASH_SIZE * sizeof(struct hash_table), M_IFADDR, M_WAITOK); - if (bdg_table == NULL) - return (ENOBUFS); flush_table(); - ifp2sc = _MALLOC(if_index * sizeof(struct bdg_softc *), M_IFADDR, M_WAITOK ); - if (ifp2sc == NULL) - return (ENOBUFS); - bzero(ifp2sc, if_index * sizeof(struct bdg_softc *) ); + ifp2sc = _MALLOC(BDG_MAX_PORTS * sizeof(struct bdg_softc), + M_IFADDR, M_WAITOK ); + bzero(ifp2sc, BDG_MAX_PORTS * sizeof(struct bdg_softc) ); bzero(&bdg_stats, sizeof(bdg_stats) ); + bdgtakeifaces(); + bdg_timeout(0); + do_bridge=0; +} + +void +bdgtakeifaces(void) +{ + int i ; + struct ifnet *ifp; + struct arpcom *ac ; + bdg_addr *p = bdg_addresses ; + struct bdg_softc *bp; + bdg_ports = 0 ; - eth_addr = bdg_addresses ; + *bridge_cfg = '\0'; - printf("BRIDGE 981214, have %d interfaces\n", if_index); + printf("BRIDGE 010131, have %d interfaces\n", if_index); for (i = 0 , ifp = ifnet.tqh_first ; i < if_index ; - i++, ifp = ifp->if_link.tqe_next) + i++, ifp = TAILQ_NEXT(ifp, if_link) ) if (ifp->if_type == IFT_ETHER) { /* ethernet ? */ + bp = &ifp2sc[ifp->if_index] ; ac = (struct arpcom *)ifp; - sprintf(bdg_stats.s[ifp->if_index].name, - "%s%d", ifp->if_name, ifp->if_unit); - printf("-- index %d %s type %d phy %d addrl %d addr %6D\n", - ifp->if_index, - bdg_stats.s[ifp->if_index].name, - (int)ifp->if_type, (int) ifp->if_physical, - (int)ifp->if_addrlen, - ac->ac_enaddr, "." ); - bcopy(ac->ac_enaddr, eth_addr, 6); - eth_addr += 6 ; - - ifp2sc[bdg_ports] = _MALLOC(sizeof(struct bdg_softc), - M_IFADDR, M_WAITOK ); - if (ifp2sc[bdg_ports] == NULL) - return (ENOBUFS); - ifp2sc[bdg_ports]->ifp = ifp ; - ifp2sc[bdg_ports]->flags = 0 ; - ifp2sc[bdg_ports]->group = 0 ; - bdg_ports ++ ; - } - bdg_timeout(0); - do_bridge=0; + sprintf(bridge_cfg + strlen(bridge_cfg), + "%s%d:1,", ifp->if_name, ifp->if_unit); + printf("-- index %d %s type %d phy %d addrl %d addr %6D\n", + ifp->if_index, + bdg_stats.s[ifp->if_index].name, + (int)ifp->if_type, (int) ifp->if_physical, + (int)ifp->if_addrlen, + ac->ac_enaddr, "." ); + bcopy(ac->ac_enaddr, p->etheraddr, 6); + p++ ; + bp->ifp = ifp ; + bp->flags = IFF_USED ; + bp->cluster_id = htons(1) ; + bp->magic = 0xDEADBEEF ; + + sprintf(bdg_stats.s[ifp->if_index].name, + "%s%d:%d", ifp->if_name, ifp->if_unit, + ntohs(bp->cluster_id)); + bdg_ports ++ ; + } + } /* * bridge_in() is invoked to perform bridging decision on input packets. + * * On Input: - * m packet to be bridged. The mbuf need not to hold the - * whole packet, only the first 14 bytes suffice. We - * assume them to be contiguous. No alignment assumptions - * because they are not a problem on i386 class machines. + * eh Ethernet header of the incoming packet. * * On Return: destination of packet, one of * BDG_BCAST broadcast @@ -392,16 +530,12 @@ bdginit(dummy) * to fetch more of the packet, or simply drop it completely. */ - struct ifnet * -bridge_in(struct mbuf *m) +bridge_in(struct ifnet *ifp, struct ether_header *eh) { int index; - struct ifnet *ifp = m->m_pkthdr.rcvif, *dst , *old ; - int dropit = MUTED(ifp) ; - struct ether_header *eh; - - eh = mtod(m, struct ether_header *); + struct ifnet *dst , *old ; + int dropit = BDG_MUTED(ifp) ; /* * hash the source address @@ -410,8 +544,10 @@ bridge_in(struct mbuf *m) bdg_table[index].used = 1 ; old = bdg_table[index].name ; if ( old ) { /* the entry is valid. */ + IFP_CHK(old, printf("bridge_in-- reading table\n") ); + if (!BDG_MATCH( eh->ether_shost, bdg_table[index].etheraddr) ) { - printf("collision at %d\n", index); + bdg_ipfw_colls++ ; bdg_table[index].name = NULL ; } else if (old != ifp) { /* @@ -427,11 +563,11 @@ bridge_in(struct mbuf *m) bdg_loops, eh->ether_shost, ".", ifp->if_name, ifp->if_unit, old->if_name, old->if_unit, - old->if_flags & IFF_MUTE ? "muted":"ignore"); + BDG_MUTED(old) ? "muted":"active"); dropit = 1 ; - if ( !MUTED(old) ) { + if ( !BDG_MUTED(old) ) { if (++bdg_loops > 10) - MUTE(old) ; + BDG_MUTE(old) ; } } } @@ -445,7 +581,7 @@ bridge_in(struct mbuf *m) bcopy(eh->ether_shost, bdg_table[index].etheraddr, 6); bdg_table[index].name = ifp ; } - dst = bridge_dst_lookup(m); + dst = bridge_dst_lookup(eh); /* Return values: * BDG_BCAST, BDG_MCAST, BDG_LOCAL, BDG_UNKNOWN, BDG_DROP, ifp. * For muted interfaces, the first 3 are changed in BDG_LOCAL, @@ -481,205 +617,267 @@ bridge_in(struct mbuf *m) } /* - * Forward to dst, excluding src port and (if not a single interface) - * muted interfaces. The packet is freed if marked as such - * and not for a local destination. - * A cleaner implementation would be to make bdg_forward() - * always consume the packet, leaving to the caller the task - * to make a copy if it needs it. As it is now, bdg_forward() - * can keep a copy alive in some cases. + * Forward to dst, excluding src port and muted interfaces. + * If src == NULL, the pkt comes from ether_output, and dst is the real + * interface the packet is originally sent to. In this case we must forward + * it to the whole cluster. We never call bdg_forward ether_output on + * interfaces which are not part of a cluster. + * + * The packet is freed if possible (i.e. surely not of interest for + * the upper layer), otherwise a copy is left for use by the caller + * (pointer in m0). + * + * It would be more efficient to make bdg_forward() always consume + * the packet, leaving to the caller the task to check if it needs a copy + * and get one in case. As it is now, bdg_forward() can sometimes make + * a copy whereas it is not necessary. + * + * XXX be careful about eh, it can be a pointer into *m */ -int -bdg_forward (struct mbuf **m0, struct ifnet *dst) +struct mbuf * +bdg_forward(struct mbuf *m0, struct ether_header *const eh, struct ifnet *dst) { - struct ifnet *src = (*m0)->m_pkthdr.rcvif; /* could be NULL in output */ - struct ifnet *ifp ; - struct ip *ip; - int error=0, s ; - int once = 0; /* execute the loop only once */ - int canfree = 1 ; /* can free the buf at the end */ - struct mbuf *m ; + struct ifnet *src = m0->m_pkthdr.rcvif; /* could be NULL in output */ + struct ifnet *ifp, *last = NULL ; + int s ; + int shared = bdg_copy ; /* someone else is using the mbuf */ + int once = 0; /* loop only once */ + struct ifnet *real_dst = dst ; /* real dst from ether_output */ +#ifdef IPFIREWALL + struct ip_fw_chain *rule = NULL ; /* did we match a firewall rule ? */ +#endif - struct ether_header *eh = mtod(*m0, struct ether_header *); /* XXX */ + /* + * XXX eh is usually a pointer within the mbuf (some ethernet drivers + * do that), so we better copy it before doing anything with the mbuf, + * or we might corrupt the header. + */ + struct ether_header save_eh = *eh ; + +#if defined(IPFIREWALL) && defined(DUMMYNET) + if (m0->m_type == MT_DUMMYNET) { + /* extract info from dummynet header */ + rule = (struct ip_fw_chain *)(m0->m_data) ; + m0 = m0->m_next ; + src = m0->m_pkthdr.rcvif; + shared = 0 ; /* For sure this is our own mbuf. */ + } else +#endif + bdg_thru++; /* only count once */ + if (src == NULL) /* packet from ether_output */ + dst = bridge_dst_lookup(eh); if (dst == BDG_DROP) { /* this should not happen */ - printf("xx bdg_forward for BDG_DROP)\n"); - m_freem(*m0) ; - *m0 = NULL ; - return 0; + printf("xx bdg_forward for BDG_DROP\n"); + m_freem(m0); + return NULL; } if (dst == BDG_LOCAL) { /* this should not happen as well */ printf("xx ouch, bdg_forward for local pkt\n"); - return 0; + return m0; } if (dst == BDG_BCAST || dst == BDG_MCAST || dst == BDG_UNKNOWN) { - ifp = ifnet.tqh_first ; + ifp = ifnet.tqh_first ; /* scan all ports */ once = 0 ; - if (dst != BDG_UNKNOWN) - canfree = 0 ; + if (dst != BDG_UNKNOWN) /* need a copy for the local stack */ + shared = 1 ; } else { ifp = dst ; - once = 1 ; /* and also canfree */ + once = 1 ; } -#if IPFIREWALL + if ( (u_int)(ifp) <= (u_int)BDG_FORWARD ) + panic("bdg_forward: bad dst"); + +#ifdef IPFIREWALL /* - * do filtering in a very similar way to what is done - * in ip_output. Only for IP packets, and only pass/fail/dummynet - * is supported. The tricky thing is to make sure that enough of - * the packet (basically, Eth+IP+TCP/UDP headers) is contiguous - * so that calls to m_pullup in ip_fw_chk will not kill the - * ethernet header. + * Do filtering in a very similar way to what is done in ip_output. + * Only if firewall is loaded, enabled, and the packet is not + * from ether_output() (src==NULL, or we would filter it twice). + * Additional restrictions may apply e.g. non-IP, short packets, + * and pkts already gone through a pipe. */ - if (ip_fw_chk_ptr) { - u_int16_t dummy ; - struct ip_fw_chain *rule; - int off; - - m = *m0 ; - if (m->m_type == MT_DUMMYNET) { - /* - * the packet was already tagged, so part of the - * processing was already done, and we need to go down. - */ - rule = (struct ip_fw_chain *)(m->m_data) ; - (*m0) = m = m->m_next ; - - src = m->m_pkthdr.rcvif; /* could be NULL in output */ - eh = mtod(m, struct ether_header *); /* XXX */ - canfree = 1 ; /* for sure, a copy is not needed later. */ - goto forward; /* HACK! */ - } else - rule = NULL ; - if (bdg_ipfw == 0) - goto forward ; - if (src == NULL) - goto forward ; /* do not apply to packets from ether_output */ - if (canfree == 0 ) /* need to make a copy */ - m = m_copypacket(*m0, M_DONTWAIT); - if (m == NULL) { - /* fail... */ - return 0 ; + if (ip_fw_chk_ptr && bdg_ipfw != 0 && src != NULL) { + struct ip *ip ; + int i; + + if (rule != NULL) /* dummynet packet, already partially processed */ + goto forward; /* HACK! I should obey the fw_one_pass */ + if (ntohs(save_eh.ether_type) != ETHERTYPE_IP) + goto forward ; /* not an IP packet, ipfw is not appropriate */ + if (m0->m_pkthdr.len < sizeof(struct ip) ) + goto forward ; /* header too short for an IP pkt, cannot filter */ + /* + * i need some amt of data to be contiguous, and in case others need + * the packet (shared==1) also better be in the first mbuf. + */ + i = min(m0->m_pkthdr.len, max_protohdr) ; + if ( shared || m0->m_len < i) { + m0 = m_pullup(m0, i) ; + if (m0 == NULL) { + printf("-- bdg: pullup failed.\n") ; + return NULL ; + } } - - dummy = 0 ; + /* * before calling the firewall, swap fields the same as IP does. * here we assume the pkt is an IP one and the header is contiguous */ - eh = mtod(m, struct ether_header *); - ip = (struct ip *)(eh + 1 ) ; + ip = mtod(m0, struct ip *); NTOHS(ip->ip_len); - NTOHS(ip->ip_id); NTOHS(ip->ip_off); /* - * The third parameter to the firewall code is the dst. interface. + * The third parameter to the firewall code is the dst. interface. * Since we apply checks only on input pkts we use NULL. + * The firewall knows this is a bridged packet as the cookie ptr + * is NULL. */ - off = (*ip_fw_chk_ptr)(NULL, 0, NULL, &dummy, &m, &rule, NULL) ; - if (m == NULL) { /* pkt discarded by firewall */ - if (canfree) - *m0 = NULL ; - return 0 ; - } + i = (*ip_fw_chk_ptr)(&ip, 0, NULL, NULL /* cookie */, &m0, &rule, NULL); + if ( (i & IP_FW_PORT_DENY_FLAG) || m0 == NULL) /* drop */ + return m0 ; /* - * on return, the mbuf pointer might have changed. Restore - * *m0 (if it was the same as m), eh, ip and then - * restore original ordering. + * If we get here, the firewall has passed the pkt, but the mbuf + * pointer might have changed. Restore ip and the fields NTOHS()'d. */ - eh = mtod(m, struct ether_header *); - ip = (struct ip *)(eh + 1 ) ; - if (canfree) /* m was a reference to *m0, so update *m0 */ - *m0 = m ; + ip = mtod(m0, struct ip *); HTONS(ip->ip_len); - HTONS(ip->ip_id); HTONS(ip->ip_off); - if (off == 0) { - if (canfree == 0) - m_freem(m); + + if (i == 0) /* a PASS rule. */ goto forward ; - } -#if DUMMYNET - if (off & 0x10000) { +#ifdef DUMMYNET + if (i & IP_FW_PORT_DYNT_FLAG) { /* - * pass the pkt to dummynet. Need to include m, dst, rule. - * Dummynet consumes the packet in all cases. + * Pass the pkt to dummynet, which consumes it. + * If shared, make a copy and keep the original. + * Need to prepend the ethernet header, optimize the common + * case of eh pointing already into the original mbuf. */ - dummynet_io((off & 0xffff), DN_TO_BDG_FWD, m, dst, NULL, 0, rule); - if (canfree) /* dummynet has consumed the original one */ - *m0 = NULL ; - return 0 ; + struct mbuf *m ; + if (shared) { + m = m_copypacket(m0, M_DONTWAIT); + if (m == NULL) { + printf("bdg_fwd: copy(1) failed\n"); + return m0; + } + } else { + m = m0 ; /* pass the original to dummynet */ + m0 = NULL ; /* and nothing back to the caller */ + } + if ( (void *)(eh + 1) == (void *)m->m_data) { + m->m_data -= ETHER_HDR_LEN ; + m->m_len += ETHER_HDR_LEN ; + m->m_pkthdr.len += ETHER_HDR_LEN ; + bdg_predict++; + } else { + M_PREPEND(m, ETHER_HDR_LEN, M_DONTWAIT); + if (!m && verbose) printf("M_PREPEND failed\n"); + if (m == NULL) /* nope... */ + return m0 ; + bcopy(&save_eh, mtod(m, struct ether_header *), ETHER_HDR_LEN); + } + dummynet_io((i & 0xffff),DN_TO_BDG_FWD,m,real_dst,NULL,0,rule,0); + return m0 ; } #endif + /* + * XXX add divert/forward actions... + */ /* if none of the above matches, we have to drop the pkt */ - if (m) - m_freem(m); - if (canfree && m != *m0) { - m_freem(*m0); - *m0 = NULL ; - } - return 0 ; + bdg_ipfw_drops++ ; + printf("bdg_forward: No rules match, so dropping packet!\n"); + return m0 ; } forward: -#endif /* COMPAT_IPFW */ - if (canfree && once) - m = *m0 ; - else - m = NULL ; - - for ( ; ifp ; ifp = ifp->if_link.tqe_next ) { - if (ifp != src && ifp->if_type == IFT_ETHER && - (ifp->if_flags & (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING) && - SAMEGROUP(ifp, src) && !MUTED(ifp) ) { - if (m == NULL) { /* do i need to make a copy ? */ - if (canfree && ifp->if_link.tqe_next == NULL) /* last one! */ - m = *m0 ; - else /* on a P5-90, m_packetcopy takes 540 ticks */ - m = m_copypacket(*m0, M_DONTWAIT); +#endif /* IPFIREWALL */ + /* + * Again, bring up the headers in case of shared bufs to avoid + * corruptions in the future. + */ + if ( shared ) { + int i = min(m0->m_pkthdr.len, max_protohdr) ; + + m0 = m_pullup(m0, i) ; + if (m0 == NULL) { + printf("-- bdg: pullup2 failed.\n") ; + return NULL ; + } + } + /* now real_dst is used to determine the cluster where to forward */ + if (src != NULL) /* pkt comes from ether_input */ + real_dst = src ; + for (;;) { + if (last) { /* need to forward packet leftover from previous loop */ + struct mbuf *m ; + if (shared == 0 && once ) { /* no need to copy */ + m = m0 ; + m0 = NULL ; /* original is gone */ + } else { + m = m_copypacket(m0, M_DONTWAIT); if (m == NULL) { - printf("bdg_forward: sorry, m_copy failed!\n"); - return ENOBUFS ; + printf("bdg_forward: sorry, m_copypacket failed!\n"); + return m0 ; /* the original is still there... */ } } /* - * execute last part of ether_output. + * Add header (optimized for the common case of eh pointing + * already into the mbuf) and execute last part of ether_output: + * queue pkt and start output if interface not yet active. */ + if ( (void *)(eh + 1) == (void *)m->m_data) { + m->m_data -= ETHER_HDR_LEN ; + m->m_len += ETHER_HDR_LEN ; + m->m_pkthdr.len += ETHER_HDR_LEN ; + bdg_predict++; + } else { + M_PREPEND(m, ETHER_HDR_LEN, M_DONTWAIT); + if (!m && verbose) printf("M_PREPEND failed\n"); + if (m == NULL) + return m0; + bcopy(&save_eh, mtod(m, struct ether_header *), ETHER_HDR_LEN); + } 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); - MUTE(ifp); /* good measure... */ + if (IF_QFULL(&last->if_snd)) { + IF_DROP(&last->if_snd); +#if 0 + BDG_MUTE(last); /* should I also mute ? */ +#endif splx(s); - error = ENOBUFS ; + m_freem(m); /* consume the pkt anyways */ } else { - ifp->if_obytes += m->m_pkthdr.len ; + last->if_obytes += m->m_pkthdr.len ; if (m->m_flags & M_MCAST) - ifp->if_omcasts++; - IF_ENQUEUE(&ifp->if_snd, m); - if ((ifp->if_flags & IFF_OACTIVE) == 0) - (*ifp->if_start)(ifp); + last->if_omcasts++; + if (m->m_pkthdr.len != m->m_len) /* this pkt is on >1 bufs */ + bdg_split_pkts++; + + IF_ENQUEUE(&last->if_snd, m); + if ((last->if_flags & IFF_OACTIVE) == 0) + (*last->if_start)(last); splx(s); - if (m == *m0) - *m0 = NULL ; /* the packet is gone... */ - m = NULL ; } - BDG_STAT(ifp, BDG_OUT); + BDG_STAT(last, BDG_OUT); + last = NULL ; + if (once) + break ; } - if (once) + if (ifp == NULL) break ; + /* + * If the interface is used for bridging, not muted, not full, + * up and running, is not the source interface, and belongs to + * the same cluster as the 'real_dst', then send here. + */ + if ( BDG_USED(ifp) && !BDG_MUTED(ifp) && !IF_QFULL(&ifp->if_snd) && + (ifp->if_flags & (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING) && + ifp != src && BDG_SAMECLUSTER(ifp, real_dst) ) + last = ifp ; + ifp = TAILQ_NEXT(ifp, if_link) ; + if (ifp == NULL) + once = 1 ; } - - /* cleanup any mbuf leftover. */ - if (m) - m_freem(m); - if (m == *m0) - *m0 = NULL ; - if (canfree && *m0) { - m_freem(*m0); - *m0 = NULL ; - } - return error ; + DEB(bdg_fw_ticks += (u_long)(rdtsc() - ticks) ; bdg_fw_count++ ; + if (bdg_fw_count != 0) bdg_fw_avg = bdg_fw_ticks/bdg_fw_count; ) + return m0 ; } diff --git a/bsd/net/bridge.h b/bsd/net/bridge.h index 7f348134e..a9c6b277d 100644 --- a/bsd/net/bridge.h +++ b/bsd/net/bridge.h @@ -46,6 +46,9 @@ */ #ifndef _NET_BRIDGE_H_ #define _NET_BRIDGE_H_ +#include + +#warning This is not used by Darwin, do not include extern int do_bridge; /* @@ -59,8 +62,43 @@ typedef struct hash_table { extern bdg_hash_table *bdg_table ; +/* + * We need additional info for the bridge. The bdg_ifp2sc[] array + * provides a pointer to this struct using the if_index. + * bdg_softc has a backpointer to the struct ifnet, the bridge + * flags, and a cluster (bridging occurs only between port of the + * same cluster). + */ +struct bdg_softc { + struct ifnet *ifp ; + /* also ((struct arpcom *)ifp)->ac_enaddr is the eth. addr */ + int flags ; +#define IFF_BDG_PROMISC 0x0001 /* set promisc mode on this if. */ +#define IFF_MUTE 0x0002 /* mute this if for bridging. */ +#define IFF_USED 0x0004 /* use this if for bridging. */ + short cluster_id ; /* in network format */ + u_long magic; +} ; + +extern struct bdg_softc *ifp2sc; + +#define BDG_USED(ifp) (ifp2sc[ifp->if_index].flags & IFF_USED) +#define BDG_MUTED(ifp) (ifp2sc[ifp->if_index].flags & IFF_MUTE) +#define BDG_MUTE(ifp) ifp2sc[ifp->if_index].flags |= IFF_MUTE +#define BDG_UNMUTE(ifp) ifp2sc[ifp->if_index].flags &= ~IFF_MUTE +#define BDG_CLUSTER(ifp) (ifp2sc[ifp->if_index].cluster_id) +#define BDG_EH(ifp) ((struct arpcom *)ifp)->ac_enaddr + +#define BDG_SAMECLUSTER(ifp,src) \ + (src == NULL || BDG_CLUSTER(ifp) == BDG_CLUSTER(src) ) + + #define BDG_MAX_PORTS 128 -extern unsigned char bdg_addresses[6*BDG_MAX_PORTS]; +typedef struct _bdg_addr { + unsigned char etheraddr[6] ; + short cluster_id ; +} bdg_addr ; +extern bdg_addr bdg_addresses[BDG_MAX_PORTS]; extern int bdg_ports ; /* @@ -73,9 +111,9 @@ extern int bdg_ports ; #define IFF_MUTE IFF_LINK2 /* will need a separate flag... */ -struct ifnet *bridge_in(struct mbuf *m); +struct ifnet *bridge_in(struct ifnet *ifp, struct ether_header *eh); /* bdg_forward frees the mbuf if necessary, returning null */ -int bdg_forward (struct mbuf **m, struct ifnet *dst); +struct mbuf *bdg_forward(struct mbuf *m0, struct ether_header *eh, struct ifnet *dst); #ifdef __i386__ #define BDG_MATCH(a,b) ( \ @@ -122,7 +160,7 @@ struct bdg_stats { #define BDG_STAT(ifp, type) bdg_stats.s[ifp->if_index].p_in[(int)type]++ -#if KERNEL +#ifdef KERNEL /* * Find the right pkt destination: * BDG_BCAST is a broadcast @@ -130,15 +168,17 @@ struct bdg_stats { * BDG_LOCAL is for a local address * BDG_DROP must be dropped * other ifp of the dest. interface (incl.self) + * + * We assume this is only called for interfaces for which bridging + * is enabled, i.e. BDG_USED(ifp) is true. */ static __inline struct ifnet * -bridge_dst_lookup(struct mbuf *m) +bridge_dst_lookup(struct ether_header *eh) { - struct ether_header *eh = mtod(m, struct ether_header *); struct ifnet *dst ; int index ; - u_char *eth_addr = bdg_addresses ; + bdg_addr *p ; if (IS_ETHER_BROADCAST(eh->ether_dhost)) return BDG_BCAST ; @@ -147,9 +187,8 @@ bridge_dst_lookup(struct mbuf *m) /* * Lookup local addresses in case one matches. */ - for (index = bdg_ports, eth_addr = bdg_addresses ; - index ; index--, eth_addr += 6 ) - if (BDG_MATCH(eth_addr, eh->ether_dhost) ) + for (index = bdg_ports, p = bdg_addresses ; index ; index--, p++ ) + if (BDG_MATCH(p->etheraddr, eh->ether_dhost) ) return BDG_LOCAL ; /* * Look for a possible destination in table @@ -164,5 +203,4 @@ bridge_dst_lookup(struct mbuf *m) #endif /* KERNEL */ -#endif /* ! _NET_BRIDGE_H_ */ - +#endif /* _NET_BRIDGE_H_ */ diff --git a/bsd/net/dlil.c b/bsd/net/dlil.c index f364ed70c..a534c0852 100644 --- a/bsd/net/dlil.c +++ b/bsd/net/dlil.c @@ -42,8 +42,10 @@ #include #include -#include #include +#include +#include + #include #include @@ -56,8 +58,8 @@ #define DBG_FNC_DLIL_IFOUT DLILDBG_CODE(DBG_DLIL_STATIC, (3 << 8)) -#define MAX_DL_TAGS 50 -#define MAX_DLIL_FILTERS 50 +#define MAX_DL_TAGS 16 +#define MAX_DLIL_FILTERS 16 #define MAX_FRAME_TYPE_SIZE 4 /* LONGWORDS */ #define MAX_LINKADDR 4 /* LONGWORDS */ #define M_NKE M_IFADDR @@ -72,6 +74,20 @@ struct dl_tag_str { }; +struct dlil_ifnet { + /* ifnet and drvr_ext are used by the stack and drivers + drvr_ext extends the public ifnet and must follow dl_if */ + struct ifnet dl_if; /* public ifnet */ + void *drvr_ext[4]; /* driver reserved (e.g arpcom extension for enet) */ + + /* dlil private fields */ + TAILQ_ENTRY(dlil_ifnet) dl_if_link; /* dlil_ifnet are link together */ + /* it is not the ifnet list */ + void *if_uniqueid; /* unique id identifying the interface */ + size_t if_uniqueid_len;/* length of the unique id */ + char if_namestorage[IFNAMSIZ]; /* interface name storage for detached interfaces */ +}; + struct dlil_stats_str { int inject_pr_in1; int inject_pr_in2; @@ -104,6 +120,7 @@ struct if_family_str { int (*add_if)(struct ifnet *ifp); int (*del_if)(struct ifnet *ifp); + int (*init_if)(struct ifnet *ifp); int (*add_proto)(struct ddesc_head_str *demux_desc_head, struct if_proto *proto, u_long dl_tag); int (*del_proto)(struct if_proto *proto, u_long dl_tag); @@ -116,15 +133,20 @@ struct if_family_str { struct dlil_stats_str dlil_stats; static -struct dlil_filter_id_str dlil_filters[MAX_DLIL_FILTERS+1]; +struct dlil_filter_id_str *dlil_filters; + +static +struct dl_tag_str *dl_tag_array; static -struct dl_tag_str dl_tag_array[MAX_DL_TAGS+1]; +TAILQ_HEAD(, dlil_ifnet) dlil_ifnet_head; static TAILQ_HEAD(, if_family_str) if_family_head; static ifnet_inited = 0; +static u_long dl_tag_nb = 0; +static u_long dlil_filters_nb = 0; int dlil_initialized = 0; decl_simple_lock_data(, dlil_input_lock) @@ -132,11 +154,15 @@ int dlil_input_thread_wakeup = 0; int dlil_expand_mcl; static struct mbuf *dlil_input_mbuf_head = NULL; static struct mbuf *dlil_input_mbuf_tail = NULL; +#if NLOOP > 1 +#error dlil_input() needs to be revised to support more than on loopback interface +#endif static struct mbuf *dlil_input_loop_head = NULL; static struct mbuf *dlil_input_loop_tail = NULL; static void dlil_input_thread(void); extern void run_netisr(void); +extern void bpfdetach(struct ifnet*); /* @@ -173,10 +199,11 @@ struct ifnet *ifbyfamily(u_long family, short unit) return 0; } -struct if_proto *dlttoproto(dl_tag) - u_long dl_tag; +struct if_proto *dlttoproto(u_long dl_tag) { - return dl_tag_array[dl_tag].proto; + if (dl_tag < dl_tag_nb && dl_tag_array[dl_tag].ifp) + return dl_tag_array[dl_tag].proto; + return 0; } @@ -224,27 +251,6 @@ int dlil_find_dltag(u_long if_family, short unit, u_long proto_family, u_long * } -int dlil_get_next_dl_tag(u_long current_tag, struct dl_tag_attr_str *next) -{ - int i; - - for (i = (current_tag+1); i < MAX_DL_TAGS; i++) - if (dl_tag_array[i].ifp) { - next->dl_tag = i; - next->if_flags = dl_tag_array[i].ifp->if_flags; - next->if_unit = dl_tag_array[i].ifp->if_unit; - next->protocol_family = dl_tag_array[i].proto->protocol_family; - next->if_family = dl_tag_array[i].ifp->if_family; - return 0; - } - - /* - * If we got here, there are no more entries - */ - - return ENOENT; -} - void dlil_post_msg(struct ifnet *ifp, u_long event_subclass, u_long event_code, struct net_event_data *event_data, u_long event_data_len) { @@ -285,14 +291,26 @@ dlil_init() { int i; - printf("dlil_init\n"); - + TAILQ_INIT(&dlil_ifnet_head); TAILQ_INIT(&if_family_head); - for (i=0; i < MAX_DL_TAGS; i++) - dl_tag_array[i].ifp = 0; - for (i=0; i < MAX_DLIL_FILTERS; i++) - dlil_filters[i].type = 0; + // create the dl tag array + MALLOC(dl_tag_array, void *, sizeof(struct dl_tag_str) * MAX_DL_TAGS, M_NKE, M_WAITOK); + if (dl_tag_array == 0) { + printf("dlil_init tags array allocation failed\n"); + return; //very bad + } + bzero(dl_tag_array, sizeof(struct dl_tag_str) * MAX_DL_TAGS); + dl_tag_nb = MAX_DL_TAGS; + + // create the dl filters array + MALLOC(dlil_filters, void *, sizeof(struct dlil_filter_id_str) * MAX_DLIL_FILTERS, M_NKE, M_WAITOK); + if (dlil_filters == 0) { + printf("dlil_init filters array allocation failed\n"); + return; //very bad + } + bzero(dlil_filters, sizeof(struct dlil_filter_id_str) * MAX_DLIL_FILTERS); + dlil_filters_nb = MAX_DLIL_FILTERS; bzero(&dlil_stats, sizeof(dlil_stats)); @@ -304,16 +322,29 @@ dlil_init() (void) kernel_thread(kernel_task, dlil_input_thread); } - u_long get_new_filter_id() { u_long i; - - for (i=1; i < MAX_DLIL_FILTERS; i++) + u_char *p; + + for (i=1; i < dlil_filters_nb; i++) if (dlil_filters[i].type == 0) - return i; - - return 0; + break; + + if (i == dlil_filters_nb) { + // expand the filters array by MAX_DLIL_FILTERS + MALLOC(p, u_char *, sizeof(struct dlil_filter_id_str) * (dlil_filters_nb + MAX_DLIL_FILTERS), M_NKE, M_WAITOK); + if (p == 0) + return 0; + + bcopy(dlil_filters, p, sizeof(struct dlil_filter_id_str) * dlil_filters_nb); + bzero(p + sizeof(struct dlil_filter_id_str) * dlil_filters_nb, sizeof(struct dlil_filter_id_str) * MAX_DL_TAGS); + dlil_filters_nb += MAX_DLIL_FILTERS; + FREE(dlil_filters, M_NKE); + dlil_filters = (struct dlil_filter_id_str *)p; + } + + return i; } @@ -323,24 +354,36 @@ int dlil_attach_interface_filter(struct ifnet *ifp, int insertion_point) { int s; - int retval; + int retval = 0; struct dlil_filterq_entry *tmp_ptr; struct dlil_filterq_entry *if_filt; struct dlil_filterq_head *fhead = (struct dlil_filterq_head *) &ifp->if_flt_head; boolean_t funnel_state; - MALLOC(tmp_ptr, struct dlil_filterq_entry *, sizeof(*tmp_ptr), M_NKE, M_WAITOK); if (tmp_ptr == NULL) - return (ENOBUFS); + return (ENOBUFS); bcopy((caddr_t) if_filter, (caddr_t) &tmp_ptr->variants.if_filter, sizeof(struct dlil_if_flt_str)); funnel_state = thread_funnel_set(network_flock, TRUE); - s = splnet(); + *filter_id = get_new_filter_id(); + if (*filter_id == 0) { + FREE(tmp_ptr, M_NKE); + retval = ENOMEM; + goto end; + } + + dlil_filters[*filter_id].filter_ptr = tmp_ptr; + dlil_filters[*filter_id].head = (struct dlil_filterq_head *) &ifp->if_flt_head; + dlil_filters[*filter_id].type = DLIL_IF_FILTER; + dlil_filters[*filter_id].ifp = ifp; + tmp_ptr->filter_id = *filter_id; + tmp_ptr->type = DLIL_IF_FILTER; + if (insertion_point != DLIL_LAST_FILTER) { TAILQ_FOREACH(if_filt, fhead, que) if (insertion_point == if_filt->filter_id) { @@ -351,22 +394,7 @@ int dlil_attach_interface_filter(struct ifnet *ifp, else TAILQ_INSERT_TAIL(fhead, tmp_ptr, que); - if (*filter_id = get_new_filter_id()) { - dlil_filters[*filter_id].filter_ptr = tmp_ptr; - dlil_filters[*filter_id].head = (struct dlil_filterq_head *) &ifp->if_flt_head; - dlil_filters[*filter_id].type = DLIL_IF_FILTER; - dlil_filters[*filter_id].ifp = ifp; - tmp_ptr->filter_id = *filter_id; - tmp_ptr->type = DLIL_IF_FILTER; - retval = 0; - } - else { - kprintf("dlil_attach_interface_filter - can't alloc filter_id\n"); - TAILQ_REMOVE(fhead, tmp_ptr, que); - FREE(tmp_ptr, M_NKE); - retval = ENOMEM; - } - +end: splx(s); thread_funnel_set(network_flock, funnel_state); return retval; @@ -378,28 +406,39 @@ int dlil_attach_protocol_filter(u_long dl_tag, u_long *filter_id, int insertion_point) { - struct dlil_filterq_entry *tmp_ptr; - struct dlil_filterq_entry *pr_filt; + struct dlil_filterq_entry *tmp_ptr, *pr_filt; int s; - int retval; + int retval = 0; boolean_t funnel_state; - - if (dl_tag > MAX_DL_TAGS) - return ERANGE; - - if (dl_tag_array[dl_tag].ifp == 0) - return ENOENT; + + if (dl_tag >= dl_tag_nb || dl_tag_array[dl_tag].ifp == 0) + return (ENOENT); MALLOC(tmp_ptr, struct dlil_filterq_entry *, sizeof(*tmp_ptr), M_NKE, M_WAITOK); if (tmp_ptr == NULL) - return (ENOBUFS); + return (ENOBUFS); bcopy((caddr_t) pr_filter, (caddr_t) &tmp_ptr->variants.pr_filter, sizeof(struct dlil_pr_flt_str)); funnel_state = thread_funnel_set(network_flock, TRUE); - s = splnet(); + + *filter_id = get_new_filter_id(); + if (*filter_id == 0) { + FREE(tmp_ptr, M_NKE); + retval = ENOMEM; + goto end; + } + + dlil_filters[*filter_id].filter_ptr = tmp_ptr; + dlil_filters[*filter_id].head = dl_tag_array[dl_tag].pr_flt_head; + dlil_filters[*filter_id].type = DLIL_PR_FILTER; + dlil_filters[*filter_id].proto = dl_tag_array[dl_tag].proto; + dlil_filters[*filter_id].ifp = dl_tag_array[dl_tag].ifp; + tmp_ptr->filter_id = *filter_id; + tmp_ptr->type = DLIL_PR_FILTER; + if (insertion_point != DLIL_LAST_FILTER) { TAILQ_FOREACH(pr_filt, dl_tag_array[dl_tag].pr_flt_head, que) if (insertion_point == pr_filt->filter_id) { @@ -410,24 +449,7 @@ int dlil_attach_protocol_filter(u_long dl_tag, else TAILQ_INSERT_TAIL(dl_tag_array[dl_tag].pr_flt_head, tmp_ptr, que); - - if (*filter_id = get_new_filter_id()) { - dlil_filters[*filter_id].filter_ptr = tmp_ptr; - dlil_filters[*filter_id].head = dl_tag_array[dl_tag].pr_flt_head; - dlil_filters[*filter_id].type = DLIL_PR_FILTER; - dlil_filters[*filter_id].proto = dl_tag_array[dl_tag].proto; - dlil_filters[*filter_id].ifp = dl_tag_array[dl_tag].ifp; - tmp_ptr->filter_id = *filter_id; - tmp_ptr->type = DLIL_PR_FILTER; - retval = 0; - } - else { - kprintf("dlil_attach_protocol_filter - can't alloc filter_id\n"); - TAILQ_REMOVE(dl_tag_array[dl_tag].pr_flt_head, tmp_ptr, que); - FREE(tmp_ptr, M_NKE); - retval = ENOMEM; - } - +end: splx(s); thread_funnel_set(network_flock, funnel_state); return retval; @@ -438,23 +460,18 @@ int dlil_detach_filter(u_long filter_id) { struct dlil_filter_id_str *flt; - int s; + int s, retval = 0; boolean_t funnel_state; - if (filter_id > MAX_DLIL_FILTERS) { - kprintf("dlil_detach_filter - Bad filter_id value %d\n", filter_id); - return ERANGE; - } - funnel_state = thread_funnel_set(network_flock, TRUE); s = splnet(); - flt = &dlil_filters[filter_id]; - if (flt->type == 0) { - kprintf("dlil_detach_filter - no such filter_id %d\n", filter_id); - thread_funnel_set(network_flock, funnel_state); - return ENOENT; + + if (filter_id >= dlil_filters_nb || dlil_filters[filter_id].type == 0) { + retval = ENOENT; + goto end; } + flt = &dlil_filters[filter_id]; if (flt->type == DLIL_IF_FILTER) { if (IFILT(flt->filter_ptr).filter_detach) @@ -470,9 +487,11 @@ dlil_detach_filter(u_long filter_id) TAILQ_REMOVE(flt->head, flt->filter_ptr, que); FREE(flt->filter_ptr, M_NKE); flt->type = 0; + +end: splx(s); thread_funnel_set(network_flock, funnel_state); - return 0; + return retval; } @@ -520,11 +539,10 @@ dlil_input_thread_continue(void) while (m) { struct mbuf *m0 = m->m_nextpkt; void *header = m->m_pkthdr.header; - struct ifnet *ifp = (struct ifnet *) m->m_pkthdr.aux; + struct ifnet *ifp = &loif[0]; m->m_nextpkt = NULL; m->m_pkthdr.header = NULL; - m->m_pkthdr.aux = NULL; (void) dlil_input_packet(ifp, m, header); m = m0; } @@ -536,11 +554,7 @@ dlil_input_thread_continue(void) dlil_input_loop_head == NULL && netisr == 0) { assert_wait(&dlil_input_thread_wakeup, THREAD_UNINT); -#if defined (__i386__) - thread_block(0); -#else - thread_block(dlil_input_thread_continue); -#endif + (void) thread_block(dlil_input_thread_continue); /* NOTREACHED */ } } @@ -551,15 +565,14 @@ void dlil_input_thread(void) register thread_t self = current_thread(); extern void stack_privilege(thread_t thread); - printf("dlil_input_thread %x\n", self); - /* * Make sure that this thread * always has a kernel stack, and * bind it to the master cpu. */ stack_privilege(self); - ml_thread_policy(current_thread(), MACHINE_GROUP, (MACHINE_NETWORK_GROUP|MACHINE_NETWORK_NETISR)); + ml_thread_policy(current_thread(), MACHINE_GROUP, + (MACHINE_NETWORK_GROUP|MACHINE_NETWORK_NETISR)); /* The dlil thread is always funneled */ thread_funnel_set(network_flock, TRUE); @@ -866,39 +879,16 @@ dlil_output(u_long dl_tag, char dst_linkaddr_buffer[MAX_LINKADDR * 4]; struct dlil_filterq_head *fhead; - KERNEL_DEBUG(DBG_FNC_DLIL_OUTPUT | DBG_FUNC_START,0,0,0,0,0); - /* - * Temporary hackery until all the existing protocols can become fully - * "dl_tag aware". Some things only have the ifp, so this handles that - * case for the time being. - */ - - if (dl_tag > MAX_DL_TAGS) { - /* dl_tag is really an ifnet pointer! */ - - ifp = (struct ifnet *) dl_tag; - dl_tag = ifp->if_data.default_proto; - if (dl_tag) - proto = dl_tag_array[dl_tag].proto; - else - retval = ENOENT; - } - else { - if ((dl_tag == 0) || (dl_tag_array[dl_tag].ifp == 0)) - retval = ENOENT; - else { - ifp = dl_tag_array[dl_tag].ifp; - proto = dl_tag_array[dl_tag].proto; - } - } - - if (retval) { - m_freem(m); - return retval; + if (dl_tag >= dl_tag_nb || dl_tag_array[dl_tag].ifp == 0) { + m_freem(m); + return ENOENT; } + ifp = dl_tag_array[dl_tag].ifp; + proto = dl_tag_array[dl_tag].proto; + frame_type = frame_type_buffer; dst_linkaddr = dst_linkaddr_buffer; @@ -958,10 +948,11 @@ dlil_output(u_long dl_tag, #if BRIDGE if (do_bridge) { struct mbuf *m0 = m ; + struct ether_header *eh = mtod(m, struct ether_header *); if (m->m_pkthdr.rcvif) m->m_pkthdr.rcvif = NULL ; - ifp = bridge_dst_lookup(m); + ifp = bridge_dst_lookup(eh); bdg_forward(&m0, ifp); if (m0) m_freem(m0); @@ -1028,7 +1019,7 @@ dlil_ioctl(u_long proto_fam, struct dlil_filterq_head *fhead; int retval = EOPNOTSUPP; int retval2 = EOPNOTSUPP; - u_long dl_tag; + u_long dl_tag; struct if_family_str *if_family; @@ -1133,12 +1124,11 @@ dlil_attach_protocol(struct dlil_proto_reg_str *proto, struct if_proto *ifproto; u_long i; struct if_family_str *if_family; - int error; struct dlil_proto_head *tmp; struct kev_dl_proto_data ev_pr_data; - int s; + int s, retval = 0; boolean_t funnel_state; - + u_char *p; if ((proto->protocol_family == 0) || (proto->interface_family == 0)) return EINVAL; @@ -1149,36 +1139,42 @@ dlil_attach_protocol(struct dlil_proto_reg_str *proto, if ((!if_family) || (if_family->flags & DLIL_SHUTDOWN)) { kprintf("dlil_attach_protocol -- no interface family module %d", proto->interface_family); - splx(s); - thread_funnel_set(network_flock, funnel_state); - return ENOENT; + retval = ENOENT; + goto end; } ifp = ifbyfamily(proto->interface_family, proto->unit_number); if (!ifp) { kprintf("dlil_attach_protocol -- no such interface %d unit %d\n", proto->interface_family, proto->unit_number); - splx(s); - thread_funnel_set(network_flock, funnel_state); - return ENOENT; + retval = ENOENT; + goto end; } if (dlil_find_dltag(proto->interface_family, proto->unit_number, proto->protocol_family, &i) == 0) { - thread_funnel_set(network_flock, funnel_state); - return EEXIST; + retval = EEXIST; + goto end; } - for (i=1; i < MAX_DL_TAGS; i++) + for (i=1; i < dl_tag_nb; i++) if (dl_tag_array[i].ifp == 0) break; - if (i >= MAX_DL_TAGS) { - splx(s); - thread_funnel_set(network_flock, funnel_state); - return ENOMEM; + if (i == dl_tag_nb) { + // expand the tag array by MAX_DL_TAGS + MALLOC(p, u_char *, sizeof(struct dl_tag_str) * (dl_tag_nb + MAX_DL_TAGS), M_NKE, M_WAITOK); + if (p == 0) { + retval = ENOBUFS; + goto end; + } + bcopy(dl_tag_array, p, sizeof(struct dl_tag_str) * dl_tag_nb); + bzero(p + sizeof(struct dl_tag_str) * dl_tag_nb, sizeof(struct dl_tag_str) * MAX_DL_TAGS); + dl_tag_nb += MAX_DL_TAGS; + FREE(dl_tag_array, M_NKE); + dl_tag_array = (struct dl_tag_str *)p; } - + /* * Allocate and init a new if_proto structure */ @@ -1186,8 +1182,8 @@ dlil_attach_protocol(struct dlil_proto_reg_str *proto, ifproto = _MALLOC(sizeof(struct if_proto), M_IFADDR, M_WAITOK); if (!ifproto) { printf("ERROR - DLIL failed if_proto allocation\n"); - thread_funnel_set(network_flock, funnel_state); - return ENOMEM; + retval = ENOMEM; + goto end; } bzero(ifproto, sizeof(struct if_proto)); @@ -1218,13 +1214,11 @@ dlil_attach_protocol(struct dlil_proto_reg_str *proto, * Call family module add_proto routine so it can refine the * demux descriptors as it wishes. */ - error = (*if_family->add_proto)(&proto->demux_desc_head, ifproto, *dl_tag); - if (error) { - dl_tag_array[*dl_tag].ifp = 0; + retval = (*if_family->add_proto)(&proto->demux_desc_head, ifproto, *dl_tag); + if (retval) { + dl_tag_array[i].ifp = 0; FREE(ifproto, M_IFADDR); - splx(s); - thread_funnel_set(network_flock, funnel_state); - return error; + goto end; } /* @@ -1244,9 +1238,10 @@ dlil_attach_protocol(struct dlil_proto_reg_str *proto, (struct net_event_data *)&ev_pr_data, sizeof(struct kev_dl_proto_data)); +end: splx(s); thread_funnel_set(network_flock, funnel_state); - return 0; + return retval; } @@ -1260,22 +1255,17 @@ dlil_detach_protocol(u_long dl_tag) struct dlil_proto_head *tmp; struct if_family_str *if_family; struct dlil_filterq_entry *filter; - int s, retval; + int s, retval = 0; struct dlil_filterq_head *fhead; struct kev_dl_proto_data ev_pr_data; boolean_t funnel_state; - - if (dl_tag > MAX_DL_TAGS) - return ERANGE; - funnel_state = thread_funnel_set(network_flock, TRUE); - s = splnet(); - if (dl_tag_array[dl_tag].ifp == 0) { - splx(s); - thread_funnel_set(network_flock, funnel_state); - return ENOENT; + + if (dl_tag >= dl_tag_nb || dl_tag_array[dl_tag].ifp == 0) { + retval = ENOENT; + goto end; } ifp = dl_tag_array[dl_tag].ifp; @@ -1283,9 +1273,8 @@ dlil_detach_protocol(u_long dl_tag) if_family = find_family_module(ifp->if_family); if (if_family == NULL) { - splx(s); - thread_funnel_set(network_flock, funnel_state); - return ENOENT; + retval = ENOENT; + goto end; } tmp = (struct dlil_proto_head *) &ifp->proto_head; @@ -1313,6 +1302,13 @@ dlil_detach_protocol(u_long dl_tag) /* the reserved field carries the number of protocol still attached (subject to change) */ ev_pr_data.proto_family = proto->protocol_family; + + /* + * Cleanup routes that may still be in the routing table for that interface/protocol pair. + */ + + if_rtproto_del(ifp, proto->protocol_family); + TAILQ_REMOVE(tmp, proto, next); FREE(proto, M_IFADDR); @@ -1322,9 +1318,7 @@ dlil_detach_protocol(u_long dl_tag) (struct net_event_data *)&ev_pr_data, sizeof(struct kev_dl_proto_data)); - if (ifp->refcnt == 0 && (ifp->if_eflags & IFEF_DETACH_DISABLED) == 0) { - if (ifp->if_flags & IFF_UP) - printf("WARNING - dlil_detach_protocol - ifp refcnt 0, but IF still up\n"); + if (ifp->refcnt == 0) { TAILQ_REMOVE(&ifnet, ifp, if_link); @@ -1361,9 +1355,10 @@ dlil_detach_protocol(u_long dl_tag) (*ifp->if_free)(ifp); } +end: splx(s); thread_funnel_set(network_flock, funnel_state); - return 0; + return retval; } @@ -1397,33 +1392,42 @@ dlil_if_attach(struct ifnet *ifp) return ENODEV; } + if (ifp->refcnt == 0) { + /* + * Call the family module to fill in the appropriate fields in the + * ifnet structure. + */ + + stat = (*if_family->add_if)(ifp); + if (stat) { + splx(s); + kprintf("dlil_if_attach -- add_if failed with %d\n", stat); + thread_funnel_set(network_flock, funnel_state); + return stat; + } + if_family->refcnt++; - /* - * Call the family module to fill in the appropriate fields in the - * ifnet structure. - */ - - stat = (*if_family->add_if)(ifp); - if (stat) { - splx(s); - kprintf("dlil_if_attach -- add_if failed with %d\n", stat); - thread_funnel_set(network_flock, funnel_state); - return stat; + /* + * Add the ifp to the interface list. + */ + + tmp = (struct dlil_proto_head *) &ifp->proto_head; + TAILQ_INIT(tmp); + + ifp->if_data.default_proto = 0; + ifp->offercnt = 0; + TAILQ_INIT(&ifp->if_flt_head); + old_if_attach(ifp); + + if (if_family->init_if) { + stat = (*if_family->init_if)(ifp); + if (stat) { + kprintf("dlil_if_attach -- init_if failed with %d\n", stat); + } + } } - - /* - * Add the ifp to the interface list. - */ - - tmp = (struct dlil_proto_head *) &ifp->proto_head; - TAILQ_INIT(tmp); - ifp->if_data.default_proto = 0; - ifp->refcnt = 1; - ifp->offercnt = 0; - TAILQ_INIT(&ifp->if_flt_head); - old_if_attach(ifp); - if_family->refcnt++; + ifp->refcnt++; dlil_post_msg(ifp, KEV_DL_SUBCLASS, KEV_DL_IF_ATTACHED, 0, 0); @@ -1446,8 +1450,6 @@ dlil_if_detach(struct ifnet *ifp) funnel_state = thread_funnel_set(network_flock, TRUE); s = splnet(); - if (ifp->if_flags & IFF_UP) - printf("WARNING - dlil_if_detach called for UP interface\n"); if_family = find_family_module(ifp->if_family); @@ -1464,7 +1466,9 @@ dlil_if_detach(struct ifnet *ifp) ifp->refcnt--; - if (ifp->refcnt == 0 && (ifp->if_eflags & IFEF_DETACH_DISABLED) == 0) { + if (ifp->refcnt == 0) { + /* Let BPF know the interface is detaching. */ + bpfdetach(ifp); TAILQ_REMOVE(&ifnet, ifp, if_link); (*if_family->del_if)(ifp); @@ -1518,6 +1522,24 @@ dlil_reg_if_modules(u_long interface_family, thread_funnel_set(network_flock, funnel_state); return EINVAL; } + + /* + * The following is a gross hack to keep from breaking + * Vicomsoft's internet gateway on Jaguar. Vicomsoft + * does not zero the reserved fields in dlil_ifmod_reg_str. + * As a result, we have to zero any function that used to + * be reserved fields at the time Vicomsoft built their + * kext. Radar #2974305 + */ + if (ifmod->reserved[0] != 0 || ifmod->reserved[1] != 0 || ifmod->reserved[2]) { + if (interface_family == 123) { /* Vicom */ + ifmod->init_if = 0; + } else { + splx(s); + thread_funnel_set(network_flock, funnel_state); + return EINVAL; + } + } if_family = (struct if_family_str *) _MALLOC(sizeof(struct if_family_str), M_IFADDR, M_WAITOK); if (!if_family) { @@ -1533,6 +1555,7 @@ dlil_reg_if_modules(u_long interface_family, if_family->shutdown = ifmod->shutdown; if_family->add_if = ifmod->add_if; if_family->del_if = ifmod->del_if; + if_family->init_if = ifmod->init_if; if_family->add_proto = ifmod->add_proto; if_family->del_proto = ifmod->del_proto; if_family->ifmod_ioctl = ifmod->ifmod_ioctl; @@ -1548,7 +1571,7 @@ dlil_reg_if_modules(u_long interface_family, int dlil_dereg_if_modules(u_long interface_family) { struct if_family_str *if_family; - int s; + int s, ret = 0; boolean_t funnel_state; funnel_state = thread_funnel_set(network_flock, TRUE); @@ -1567,12 +1590,14 @@ int dlil_dereg_if_modules(u_long interface_family) TAILQ_REMOVE(&if_family_head, if_family, if_fam_next); FREE(if_family, M_IFADDR); } - else + else { if_family->flags |= DLIL_SHUTDOWN; + ret = DLIL_WAIT_FOR_FREE; + } splx(s); thread_funnel_set(network_flock, funnel_state); - return 0; + return ret; } @@ -1603,12 +1628,9 @@ dlil_inject_if_input(struct mbuf *m, char *frame_header, u_long from_id) struct dlil_filterq_head *fhead; int match_found; - dlil_stats.inject_if_in1++; - if (from_id > MAX_DLIL_FILTERS) - return ERANGE; - if (dlil_filters[from_id].type != DLIL_IF_FILTER) + if (from_id >= dlil_filters_nb || dlil_filters[from_id].type != DLIL_IF_FILTER) return ENOENT; ifp = dlil_filters[from_id].ifp; @@ -1741,19 +1763,14 @@ dlil_inject_pr_input(struct mbuf *m, char *frame_header, u_long from_id) struct if_proto *ifproto = 0; int match_found; struct ifnet *ifp; - dlil_stats.inject_pr_in1++; - if (from_id > MAX_DLIL_FILTERS) - return ERANGE; - - if (dlil_filters[from_id].type != DLIL_PR_FILTER) + if (from_id >= dlil_filters_nb || dlil_filters[from_id].type != DLIL_PR_FILTER) return ENOENT; ifproto = dlil_filters[from_id].proto; ifp = dlil_filters[from_id].ifp; - /* * Call any attached protocol filters. */ @@ -1815,7 +1832,6 @@ dlil_inject_pr_output(struct mbuf *m, int match_found; u_long dl_tag; - dlil_stats.inject_pr_out1++; if (raw == 0) { if (frame_type) @@ -1829,15 +1845,11 @@ dlil_inject_pr_output(struct mbuf *m, return EINVAL; } - if (from_id > MAX_DLIL_FILTERS) - return ERANGE; - - if (dlil_filters[from_id].type != DLIL_PR_FILTER) + if (from_id >= dlil_filters_nb || dlil_filters[from_id].type != DLIL_PR_FILTER) return ENOENT; ifp = dlil_filters[from_id].ifp; dl_tag = dlil_filters[from_id].proto->dl_tag; - frame_type = frame_type_buffer; dst_linkaddr = dst_linkaddr_buffer; @@ -1890,10 +1902,11 @@ dlil_inject_pr_output(struct mbuf *m, #if BRIDGE if (do_bridge) { struct mbuf *m0 = m ; + struct ether_header *eh = mtod(m, struct ether_header *); if (m->m_pkthdr.rcvif) m->m_pkthdr.rcvif = NULL ; - ifp = bridge_dst_lookup(m); + ifp = bridge_dst_lookup(eh); bdg_forward(&m0, ifp); if (m0) m_freem(m0); @@ -1956,12 +1969,8 @@ dlil_inject_if_output(struct mbuf *m, u_long from_id) struct dlil_filterq_head *fhead; int match_found; - dlil_stats.inject_if_out1++; - if (from_id > MAX_DLIL_FILTERS) - return ERANGE; - - if (dlil_filters[from_id].type != DLIL_IF_FILTER) + if (from_id > dlil_filters_nb || dlil_filters[from_id].type != DLIL_IF_FILTER) return ENOENT; ifp = dlil_filters[from_id].ifp; @@ -2012,3 +2021,127 @@ dlil_inject_if_output(struct mbuf *m, u_long from_id) else return retval; } + +static +int dlil_recycle_ioctl(struct ifnet *ifnet_ptr, u_long ioctl_code, void *ioctl_arg) +{ + + return EOPNOTSUPP; +} + +static +int dlil_recycle_output(struct ifnet *ifnet_ptr, struct mbuf *m) +{ + + m_freem(m); + return 0; +} + +static +int dlil_recycle_free(struct ifnet *ifnet_ptr) +{ + return 0; +} + +static +int dlil_recycle_set_bpf_tap(struct ifnet *ifp, int mode, + int (*bpf_callback)(struct ifnet *, struct mbuf *)) +{ + /* XXX not sure what to do here */ + return 0; +} + +int dlil_if_acquire(u_long family, void *uniqueid, size_t uniqueid_len, + struct ifnet **ifp) +{ + struct ifnet *ifp1 = NULL; + struct dlil_ifnet *dlifp1 = NULL; + int s, ret = 0; + boolean_t funnel_state; + + funnel_state = thread_funnel_set(network_flock, TRUE); + s = splnet(); + + TAILQ_FOREACH(dlifp1, &dlil_ifnet_head, dl_if_link) { + + ifp1 = (struct ifnet *)dlifp1; + + if (ifp1->if_family == family) { + + /* same uniqueid and same len or no unique id specified */ + if ((uniqueid_len == dlifp1->if_uniqueid_len) + && !bcmp(uniqueid, dlifp1->if_uniqueid, uniqueid_len)) { + + /* check for matching interface in use */ + if (ifp1->if_eflags & IFEF_INUSE) { + if (uniqueid_len) { + ret = EBUSY; + goto end; + } + } + else { + + ifp1->if_eflags |= (IFEF_INUSE + IFEF_REUSE); + *ifp = ifp1; + goto end; + } + } + } + } + + /* no interface found, allocate a new one */ + MALLOC(dlifp1, struct dlil_ifnet *, sizeof(*dlifp1), M_NKE, M_WAITOK); + if (dlifp1 == 0) { + ret = ENOMEM; + goto end; + } + + bzero(dlifp1, sizeof(*dlifp1)); + + if (uniqueid_len) { + MALLOC(dlifp1->if_uniqueid, void *, uniqueid_len, M_NKE, M_WAITOK); + if (dlifp1->if_uniqueid == 0) { + FREE(dlifp1, M_NKE); + ret = ENOMEM; + goto end; + } + bcopy(uniqueid, dlifp1->if_uniqueid, uniqueid_len); + dlifp1->if_uniqueid_len = uniqueid_len; + } + + ifp1 = (struct ifnet *)dlifp1; + ifp1->if_eflags |= IFEF_INUSE; + + TAILQ_INSERT_TAIL(&dlil_ifnet_head, dlifp1, dl_if_link); + + *ifp = ifp1; + +end: + + splx(s); + thread_funnel_set(network_flock, funnel_state); + return ret; +} + +void dlil_if_release(struct ifnet *ifp) +{ + struct dlil_ifnet *dlifp = (struct dlil_ifnet *)ifp; + int s; + boolean_t funnel_state; + + funnel_state = thread_funnel_set(network_flock, TRUE); + s = splnet(); + + ifp->if_eflags &= ~IFEF_INUSE; + ifp->if_ioctl = dlil_recycle_ioctl; + ifp->if_output = dlil_recycle_output; + ifp->if_free = dlil_recycle_free; + ifp->if_set_bpf_tap = dlil_recycle_set_bpf_tap; + + strncpy(dlifp->if_namestorage, ifp->if_name, IFNAMSIZ); + ifp->if_name = dlifp->if_namestorage; + + splx(s); + thread_funnel_set(network_flock, funnel_state); +} + diff --git a/bsd/net/dlil.h b/bsd/net/dlil.h index 63bd169f2..1727d78ff 100644 --- a/bsd/net/dlil.h +++ b/bsd/net/dlil.h @@ -29,6 +29,7 @@ #ifndef DLIL_H #define DLIL_H +#include #if __STDC__ @@ -39,7 +40,7 @@ struct ether_header; #endif - +#ifdef __APPLE_API_UNSTABLE #define DLIL_LAST_FILTER -1 #define DLIL_NULL_FILTER -2 @@ -153,6 +154,7 @@ typedef int (*dl_ioctl_func)(u_long dl_tag, +#ifdef __APPLE_API_PRIVATE struct dlil_filterq_entry { TAILQ_ENTRY(dlil_filterq_entry) que; u_long filter_id; @@ -162,7 +164,9 @@ struct dlil_filterq_entry { struct dlil_pr_flt_str pr_filter; } variants; }; - +#else +struct dlil_filterq_entry; +#endif /* __APPLE_API_PRIVATE */ TAILQ_HEAD(dlil_filterq_head, dlil_filterq_entry); @@ -182,6 +186,7 @@ struct if_proto { }; +#ifdef __APPLE_API_PRIVATE TAILQ_HEAD(dlil_proto_head, if_proto); struct dlil_tag_list_entry { @@ -189,8 +194,10 @@ struct dlil_tag_list_entry { struct ifnet *ifp; u_long dl_tag; }; +#endif /* __APPLE_API_PRIVATE */ +#ifdef __APPLE_API_OBSOLETE /* Obsolete types */ #define DLIL_DESC_RAW 1 #define DLIL_DESC_802_2 2 @@ -203,6 +210,7 @@ struct dlil_tag_list_entry { * DLIL_DESC_802_2_SNAP - obsolete, data in variants.desc_802_2_SNAP * protocol field in host byte order */ +#endif /* __APPLE_API_OBSOLETE */ /* Ehernet specific types */ #define DLIL_DESC_ETYPE2 4 @@ -325,7 +333,8 @@ struct dlil_ifmod_reg_str { int (*del_proto)(struct if_proto *proto, u_long dl_tag); int (*ifmod_ioctl)(struct ifnet *ifp, u_long ioctl_cmd, caddr_t data); int (*shutdown)(); - u_long reserved[4]; + int (*init_if)(struct ifnet *ifp); + u_long reserved[3]; }; @@ -361,4 +370,111 @@ int dlil_dereg_if_modules(u_long interface_family); int dlil_if_detach(struct ifnet *ifp); + +/* + +Function : dlil_if_acquire + + DLIL manages the list of ifnet interfaces allocated using the dlil_if_acquire + function. This list if not the same as the list of attached interfaces, + visible with ifconfig. + This list contains attached as well as detached interfaces. + Detached interfaces are kept in the list to prevent the kernel from crashing + by using an old ifp. + + if it succeeds, dlil_if_acquire returns an ifnet data structure. + This ifnet can either be a new allocated block of memory, or an ifnet + that already existed and that DLIL has found in its list of unused + interface and that matches the family/uniqueid tuple. + + dlil_if_acquire can fail if the requested interface is already in use, + or if no memory is available to create a new interface. + + The typical sequence of call for a driver will be : + dlil_if_acquire(... &ifp) + ... Fill in the ifnet ... + dlil_if_attach(ifp) + ... Driver work ... + dlil_if_detach(ifp) + dlil_if_release(ifp) + + Important : ifnet allocated by DLIL are managed by DLIL. DLIL takes care + of them, and keeps them until a driver wants to reuse them, but DLIL may + also decide to free them when not in use by a driver. + + Note : the structure returned will actually be large enough to contain + an arpcom structure (ifnet + ethernet) structure. + Drivers cannot extend the structure and must to store their private + information in if_sofc and if_private. + +Parameters : + 'family' uniquely identifies DLIL interface family. + 'uniqueid' is a unique identifier for that interface, managed by the + driver (for example MAC address for ethernet). + 'uniqueid_len' is the length of the unique id. + 'ifp' contains on output the allocated ifnet. + +Return code : + +0 : + + If an ifnet matching the uniqueid is found, the matching ifnet is returned + in ifp and the flags IFEF_REUSE and IF_INUSE are set in the if_eflags. + The fields in the ifnet are NOT zeroed and may contain old values that + the driver can reuse. [They are not necessarily the values that were + there when the driver released the ifnet, as protocol might have + continued to update them]. + + If no matching ifnet is found, a new structure is allocated and returned + in ifp with all fields initialized to 0. + The flag IF_INUSE is set in the if_eflags. IFEF_REUSE is NOT set. + dlil_if_acquire will copy the uniqueid and keep it for matching purpose. + + If 'uniqueid' is NULL, then dlil_if_acquire will return the first + ifnet that contains a null uniqueid for that family, with the flags + IFEF_REUSE and IF_INUSE set. + If no ifnet is available, a new one will be created. + +ENOMEM: + + If no matching interface is found, and no memory can be allocated, + dlil_if_acquire will return ENOMEM. + + +EBUSY: + + If the unique id matches the id of an interface currently in use, + dlil_if_acquire will return EBUSY. + An interface 'in use' is an allocated interface, not necessarily attached. + +*/ + +int dlil_if_acquire(u_long family, void *uniqueid, size_t uniqueid_len, + struct ifnet **ifp); + + +/* + +Function : dlil_if_release + + dlil_if_release will transfer control of the ifnet to DLIL. + DLIL will keep the interface in its list, marking it unused. + The fields will be left in their current state, so the driver can reuse + the ifnet later, by calling dlil_if_acquire. + The if_eflags IF_INUSE will be cleared. + The fields if_output, if_ioctl, if_free and if_set_bpf_tap will be changed + to point to DLIL private functions. + After calling dlil_if_acquire, the driver can safely terminate and + unload if necessary. + Note : if the call to dlil_if_detach returns DLIL_WAIT_FOR_FREE, the + driver can safely ignore it and call dlil_if_release. + +Parameters : + ifp is the pointer to the ifnet to release. + +*/ + +void dlil_if_release(struct ifnet *ifp); + +#endif /* __APPLE_API_UNSTABLE */ #endif /* DLIL_H */ diff --git a/bsd/net/dlil_ethersubr.c b/bsd/net/dlil_ethersubr.c deleted file mode 100644 index ae32c57c5..000000000 --- a/bsd/net/dlil_ethersubr.c +++ /dev/null @@ -1,1227 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1982, 1989, 1993 - * 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. - * - */ - - - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#if INET -#include -#include -#include -#include -#include -#endif -#if INET6 -#include -#include -#endif - - -#include -#include - -#include - - -#if LLC && CCITT -extern struct ifqueue pkintrq; -#endif - -/* General stuff from if_ethersubr.c - may not need some of it */ - -#include -#if NETAT -extern struct ifqueue atalkintrq; -#endif - - -#if BRIDGE -#include -#endif - -/* #include "vlan.h" */ -#if NVLAN > 0 -#include -#endif /* NVLAN > 0 */ - - -extern struct ifnet_blue *blue_if; -extern struct mbuf *splitter_input(struct mbuf *, struct ifnet *); - -static u_long lo_dlt = 0; -static ivedonethis = 0; -static int ether_resolvemulti __P((struct ifnet *, struct sockaddr **, - struct sockaddr *)); -u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - -#define IFP2AC(IFP) ((struct arpcom *)IFP) - -/* This stuff is new */ - -#define DB_HEADER_SIZE 20 -struct en_desc { - short total_len; - u_short ethertype; - u_long dl_tag; - struct ifnet *ifp; - struct if_proto *proto; - u_long proto_id_length; - u_long proto_id_data[8]; /* probably less - proto-id and bitmasks */ -}; - -#define LITMUS_SIZE 16 -#define ETHER_DESC_BLK_SIZE 50 -#define MAX_INTERFACES 50 - -/* - * Statics for demux module - */ - -struct ether_desc_blk_str { - u_long n_blocks; - u_long *block_ptr; -}; - -struct dl_es_at_entry -{ - struct ifnet *ifp; - u_long dl_tag; - int ref_count; -}; - - -static struct ether_desc_blk_str ether_desc_blk[MAX_INTERFACES]; -static u_long litmus_mask[LITMUS_SIZE]; -static u_long litmus_length = 0; - - -/* - * Temp static for protocol registration XXX - */ - -#define MAX_EN_COUNT 30 - -static struct dl_es_at_entry en_at_array[MAX_EN_COUNT]; - -/* - * This could be done below in-line with heavy casting, but the pointer arithmetic is - * prone to error. - */ - -static -int desc_in_bounds(block, current_ptr, offset_length) - u_int block; - char *current_ptr; - u_long offset_length; -{ - u_long end_of_block; - u_long current_ptr_tmp; - - current_ptr_tmp = (u_long) current_ptr; - end_of_block = (u_long) ether_desc_blk[block].block_ptr; - end_of_block += (ETHER_DESC_BLK_SIZE * ether_desc_blk[block].n_blocks); - if ((current_ptr_tmp + offset_length) < end_of_block) - return 1; - else - return 0; -} - - -/* - * Release all descriptor entries owned by this dl_tag (there may be several). - * Setting the dl_tag to 0 releases the entry. Eventually we should compact-out - * the unused entries. - */ -static -int ether_del_proto(struct if_proto *proto, u_long dl_tag) -{ - char *current_ptr = (char *) ether_desc_blk[proto->ifp->family_cookie].block_ptr; - struct en_desc *ed; - int i; - int found = 0; - - ed = (struct en_desc *) current_ptr; - - while(ed->total_len) { - if (ed->dl_tag == dl_tag) { - found = 1; - ed->dl_tag = 0; - } - - current_ptr += ed->total_len; - ed = (struct en_desc *) current_ptr; - } - } - - - -static -int ether_add_proto(struct ddesc_head_str *desc_head, struct if_proto *proto, u_long dl_tag) -{ - char *current_ptr; - struct dlil_demux_desc *desc; - u_long id_length; /* IN LONGWORDS!!! */ - struct en_desc *ed; - u_long *bitmask; - u_long *proto_id; - int i; - short total_length; - u_long block_count; - u_long *tmp; - - - TAILQ_FOREACH(desc, desc_head, next) { - switch (desc->type) - { - case DLIL_DESC_RAW: - id_length = desc->variants.bitmask.proto_id_length; - break; - - case DLIL_DESC_802_2: - id_length = 1; - break; - - case DLIL_DESC_802_2_SNAP: - id_length = 2; - break; - - default: - return EINVAL; - } - -restart: - block_count = ether_desc_blk[proto->ifp->family_cookie].n_blocks; - current_ptr = (char *) ether_desc_blk[proto->ifp->family_cookie].block_ptr; - ed = (struct en_desc *) current_ptr; - total_length = ((id_length << 2) * 2) + DB_HEADER_SIZE; - - while ((ed->total_len) && (desc_in_bounds(proto->ifp->family_cookie, - current_ptr, total_length))) { - if ((ed->dl_tag == 0) && (total_length <= ed->total_len)) - break; - else - current_ptr += *(short *)current_ptr; - - ed = (struct en_desc *) current_ptr; - } - - if (!desc_in_bounds(proto->ifp->family_cookie, current_ptr, total_length)) { - - tmp = _MALLOC((ETHER_DESC_BLK_SIZE * (block_count + 1)), - M_IFADDR, M_WAITOK); - if (tmp == 0) { - /* - * Remove any previous descriptors set in the call. - */ - ether_del_proto(proto, dl_tag); - return ENOMEM; - } - - bzero(tmp, ETHER_DESC_BLK_SIZE * (block_count + 1)); - bcopy(ether_desc_blk[proto->ifp->family_cookie].block_ptr, - tmp, (ETHER_DESC_BLK_SIZE * block_count)); - FREE(ether_desc_blk[proto->ifp->family_cookie].block_ptr, M_IFADDR); - ether_desc_blk[proto->ifp->family_cookie].n_blocks = block_count + 1; - ether_desc_blk[proto->ifp->family_cookie].block_ptr = tmp; - goto restart; - } - - if (ed->total_len == 0) - ed->total_len = total_length; - ed->ethertype = *((u_short *) desc->native_type); - - ed->dl_tag = dl_tag; - ed->proto = proto; - ed->proto_id_length = id_length; - ed->ifp = proto->ifp; - - switch (desc->type) - { - case DLIL_DESC_RAW: - bcopy(desc->variants.bitmask.proto_id, &ed->proto_id_data[0], (id_length << 2) ); - bcopy(desc->variants.bitmask.proto_id_mask, &ed->proto_id_data[id_length], - (id_length << 2)); - break; - - case DLIL_DESC_802_2: - ed->proto_id_data[0] = 0; - bcopy(&desc->variants.desc_802_2, &ed->proto_id_data[0], 3); - ed->proto_id_data[1] = 0xffffff00; - break; - - case DLIL_DESC_802_2_SNAP: - /* XXX Add verification of fixed values here */ - - ed->proto_id_data[0] = 0; - ed->proto_id_data[1] = 0; - bcopy(&desc->variants.desc_802_2_SNAP, &ed->proto_id_data[0], 8); - ed->proto_id_data[2] = 0xffffffff; - ed->proto_id_data[3] = 0xffffffff;; - break; - } - - if (id_length) { - proto_id = (u_long *) &ed->proto_id_data[0]; - bitmask = (u_long *) &ed->proto_id_data[id_length]; - for (i=0; i < (id_length); i++) { - litmus_mask[i] &= bitmask[i]; - litmus_mask[i] &= proto_id[i]; - } - if (id_length > litmus_length) - litmus_length = id_length; - } - } - - return 0; -} - - -static -int ether_shutdown() -{ - return 0; -} - - - - -/* - * Process a received Ethernet packet; - * the packet is in the mbuf chain m without - * the ether header, which is provided separately. - */ -int -new_ether_input(m, frame_header, ifp, dl_tag, sync_ok) - struct mbuf *m; - char *frame_header; - struct ifnet *ifp; - u_long dl_tag; - int sync_ok; - -{ - register struct ether_header *eh = (struct ether_header *) frame_header; - register struct ifqueue *inq=0; - u_short ether_type; - int s; - u_int16_t ptype = -1; - unsigned char buf[18]; - -#if ISO || LLC || NETAT - register struct llc *l; -#endif - - -#if DLIL_BLUEBOX - - /* - * Y-adapter input processing: - * - Don't split if coming from a dummy if - * - If coming from a real if, if splitting enabled, - * then filter the incoming packet - */ - if (ifp != (struct ifnet *)blue_if) - { /* Is splitter turned on? */ - if (ifp->if_flags&IFF_SPLITTER) - { m->m_data -= sizeof(struct ether_header); - m->m_len += sizeof (struct ether_header); - m->m_pkthdr.len += sizeof(struct ether_header); - /* - * Check to see if destined for BlueBox or Rhapsody - * If NULL return, mbuf's been consumed by the BlueBox. - * Otherwise, send on to Rhapsody - */ - if ((m = splitter_input(m, ifp)) == NULL) - return EJUSTRETURN; - m->m_data += sizeof(struct ether_header); - m->m_len -= sizeof (struct ether_header); - m->m_pkthdr.len -= sizeof(struct ether_header); - } - } else - { /* Get the "real" IF */ - ifp = ((struct ndrv_cb *)(blue_if->ifb_so->so_pcb))->nd_if; - m->m_pkthdr.rcvif = ifp; - blue_if->pkts_looped_b2r++; - } - -#endif - if ((ifp->if_flags & IFF_UP) == 0) { - m_freem(m); - return EJUSTRETURN; - } - - ifp->if_lastchange = time; - - if (eh->ether_dhost[0] & 1) { - if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost, - sizeof(etherbroadcastaddr)) == 0) - m->m_flags |= M_BCAST; - else - m->m_flags |= M_MCAST; - } - if (m->m_flags & (M_BCAST|M_MCAST)) - ifp->if_imcasts++; - - ether_type = ntohs(eh->ether_type); - -#if NVLAN > 0 - if (ether_type == vlan_proto) { - if (vlan_input(eh, m) < 0) - ifp->if_data.ifi_noproto++; - return EJUSTRETURN; - } -#endif /* NVLAN > 0 */ - - switch (ether_type) { -#if INET - case ETHERTYPE_IP: - if (ipflow_fastforward(m)) - return EJUSTRETURN; - ptype = mtod(m, struct ip *)->ip_p; - if ((sync_ok == 0) || - (ptype != IPPROTO_TCP && ptype != IPPROTO_UDP)) { - schednetisr(NETISR_IP); - } - - inq = &ipintrq; - break; - - case ETHERTYPE_ARP: - schednetisr(NETISR_ARP); - inq = &arpintrq; - break; -#endif -#if INET6 - case ETHERTYPE_IPV6: - schednetisr(NETISR_IPV6); - inq = &ip6intrq; - break; -#endif - - - default: { -#if NETAT - if (ether_type > ETHERMTU) - return ENOENT; - l = mtod(m, struct llc *); - switch (l->llc_dsap) { - case LLC_SNAP_LSAP: - - /* Temporary hack: check for AppleTalk and AARP packets */ - /* WARNING we're checking only on the "ether_type" (the 2 bytes - * of the SNAP header. This shouldn't be a big deal, - * AppleTalk pat_input is making sure we have the right packets - * because it needs to discrimante AARP from EtherTalk packets. - */ - - if (l->llc_ssap == LLC_SNAP_LSAP && - l->llc_un.type_snap.control == 0x03) { - -#ifdef APPLETALK_DEBUG - printf("new_ether_input: SNAP Cntrol type=0x%x Src=%s\n", - l->llc_un.type_snap.ether_type, - ether_sprintf(buf, &eh->ether_shost)); - printf(" Dst=%s\n", - ether_sprintf(buf, &eh->ether_dhost)); -#endif /* APPLETALK_DEBUG */ - - if ((l->llc_un.type_snap.ether_type == 0x809B) || - (l->llc_un.type_snap.ether_type == 0x80F3)) { - - - /* - * note: for AppleTalk we need to pass the enet header of the - * packet up stack. To do so, we made sure in that the FULL packet - * is copied in the mbuf by the mace driver, and only the m_data and - * length have been shifted to make IP and the other guys happy. - */ - - m->m_data -= sizeof(*eh); - m->m_len += sizeof(*eh); - m->m_pkthdr.len += sizeof(*eh); -#ifdef APPLETALK_DEBUG - l == (struct llc *)(eh+1); - if (l->llc_un.type_snap.ether_type == 0x80F3) { - kprintf("new_ether_input: RCV AppleTalk type=0x%x Src=%s\n", - l->llc_un.type_snap.ether_type, - ether_sprintf(buf, &eh->ether_shost)); - kprintf(" Dst=%s\n", - ether_sprintf(buf, &eh->ether_dhost)); - } -#endif /* APPLETALK_DEBUG */ - schednetisr(NETISR_APPLETALK); - inq = &atalkintrq ; - - break; - } - } - - break; - - - default: - return ENOENT; - } - -#else /*NETAT*/ - return ENOENT; -#endif /* NETAT */ - - } - } - - if (inq == 0) - return ENOENT; - - s = splimp(); - if (IF_QFULL(inq)) { - IF_DROP(inq); - m_freem(m); - splx(s); - return EJUSTRETURN; - } else - IF_ENQUEUE(inq, m); - splx(s); - - if ((sync_ok) && - (ptype == IPPROTO_TCP || ptype == IPPROTO_UDP)) { - extern void ipintr(void); - - s = splnet(); - ipintr(); - splx(s); - } - - return 0; -} - - - - -int ether_demux(ifp, m, frame_header, proto) - struct ifnet *ifp; - struct mbuf *m; - char *frame_header; - struct if_proto **proto; - -{ - register struct ether_header *eh = (struct ether_header *)frame_header; - u_short ether_type; - char *current_ptr = (char *) ether_desc_blk[ifp->family_cookie].block_ptr; - struct dlil_demux_desc *desc; - register u_long temp; - u_long *data; - register struct if_proto *ifproto; - u_long i; - struct en_desc *ed; - - - if (eh->ether_dhost[0] & 1) { - if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost, - sizeof(etherbroadcastaddr)) == 0) - m->m_flags |= M_BCAST; - else - m->m_flags |= M_MCAST; - } - - ether_type = ntohs(eh->ether_type); - - /* - * Search through the connected protocols for a match. - */ - - - data = mtod(m, u_long *); - ed = (struct en_desc *) current_ptr; - while (desc_in_bounds(ifp->family_cookie, current_ptr, DB_HEADER_SIZE)) { - if (ed->total_len == 0) - break; - - if ((ed->dl_tag != 0) && (ed->ifp == ifp) && - ((ed->ethertype == ntohs(eh->ether_type)) || (ed->ethertype == 0))) { - if (ed->proto_id_length) { - for (i=0; i < (ed->proto_id_length); i++) { - temp = ntohs(data[i]) & ed->proto_id_data[ed->proto_id_length + i]; - if ((temp ^ ed->proto_id_data[i])) - break; - } - - if (i >= (ed->proto_id_length)) { - *proto = ed->proto; - return 0; - } - } - else { - *proto = ed->proto; - return 0; - } - } - current_ptr += ed->total_len; - ed = (struct en_desc *) current_ptr; - } - -/* - kprintf("ether_demux - No match for <%x><%x><%x><%x><%x><%x><%x<%x>\n", - eh->ether_type,data[0], data[1], data[2], data[3], data[4],data[5],data[6]); -*/ - - return ENOENT; -} - - - -/* - * 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. - */ -int -ether_frameout(ifp, m, ndest, edst, ether_type) - register struct ifnet *ifp; - struct mbuf **m; - struct sockaddr *ndest; - char *edst; - char *ether_type; -{ - register struct ether_header *eh; - int hlen; /* link layer header lenght */ - struct arpcom *ac = IFP2AC(ifp); - - - hlen = ETHER_HDR_LEN; - - /* - * If a simplex interface, and the packet is being sent to our - * Ethernet address or a broadcast address, loopback a copy. - * XXX To make a simplex device behave exactly like a duplex - * device, we should copy in the case of sending to our own - * ethernet address (thus letting the original actually appear - * on the wire). However, we don't do that here for security - * reasons and compatibility with the original behavior. - */ - if ((ifp->if_flags & IFF_SIMPLEX) && - ((*m)->m_flags & M_LOOP)) { - if (lo_dlt == 0) - dlil_find_dltag(APPLE_IF_FAM_LOOPBACK, 0, PF_INET, &lo_dlt); - - if (lo_dlt) { - if ((*m)->m_flags & M_BCAST) { - struct mbuf *n = m_copy(*m, 0, (int)M_COPYALL); - dlil_output(lo_dlt, n, 0, ndest, 0); - } - else - { - if (bcmp(edst, ac->ac_enaddr, ETHER_ADDR_LEN) == 0) { - dlil_output(lo_dlt, *m, 0, ndest, 0); - return EJUSTRETURN; - } - } - } - } - - - /* - * Add local net header. If no space in first mbuf, - * allocate another. - */ - M_PREPEND(*m, sizeof (struct ether_header), M_DONTWAIT); - if (*m == 0) { - return (EJUSTRETURN); - } - - - eh = mtod(*m, struct ether_header *); - (void)memcpy(&eh->ether_type, ether_type, - sizeof(eh->ether_type)); - (void)memcpy(eh->ether_dhost, edst, 6); - (void)memcpy(eh->ether_shost, ac->ac_enaddr, - sizeof(eh->ether_shost)); - -#if DLIL_BLUEBOX - /* - * We're already to send. Let's check for the blue box... - */ - if (ifp->if_flags&IFF_SPLITTER) - { - (*m)->m_flags |= 0x10; - if ((*m = splitter_input(*m, ifp)) == NULL) - return EJUSTRETURN; - else - return (0); - } - else -#endif - return 0; -} - - -static -int ether_add_if(struct ifnet *ifp) -{ - u_long i; - - ifp->if_framer = ether_frameout; - ifp->if_demux = ether_demux; - - for (i=0; i < MAX_INTERFACES; i++) - if (ether_desc_blk[i].n_blocks == 0) - break; - - if (i == MAX_INTERFACES) - return EOVERFLOW; - - ether_desc_blk[i].block_ptr = _MALLOC(ETHER_DESC_BLK_SIZE, M_IFADDR, M_WAITOK); - if (ether_desc_blk[i].block_ptr == 0) - return ENOMEM; - - ether_desc_blk[i].n_blocks = 1; - bzero(ether_desc_blk[i].block_ptr, ETHER_DESC_BLK_SIZE); - - ifp->family_cookie = i; - - return 0; -} - -static -int ether_del_if(struct ifnet *ifp) -{ - if ((ifp->family_cookie < MAX_INTERFACES) && - (ether_desc_blk[ifp->family_cookie].n_blocks)) { - FREE(ether_desc_blk[ifp->family_cookie].block_ptr, M_IFADDR); - ether_desc_blk[ifp->family_cookie].n_blocks = 0; - return 0; - } - else - return ENOENT; -} - - - - -int -ether_pre_output(ifp, m0, dst_netaddr, route, type, edst, dl_tag ) - struct ifnet *ifp; - struct mbuf **m0; - struct sockaddr *dst_netaddr; - caddr_t route; - char *type; - char *edst; - u_long dl_tag; -{ - struct rtentry *rt0 = (struct rtentry *) route; - int s; - register struct mbuf *m = *m0; - register struct rtentry *rt; - register struct ether_header *eh; - int off, len = m->m_pkthdr.len; - int hlen; /* link layer header lenght */ - struct arpcom *ac = IFP2AC(ifp); - - - - if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) - return ENETDOWN; - - rt = rt0; - if (rt) { - if ((rt->rt_flags & RTF_UP) == 0) { - rt0 = rt = rtalloc1(dst_netaddr, 1, 0UL); - if (rt0) - rt->rt_refcnt--; - else - return EHOSTUNREACH; - } - - if (rt->rt_flags & RTF_GATEWAY) { - if (rt->rt_gwroute == 0) - goto lookup; - if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { - rtfree(rt); rt = rt0; - lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, - 0UL); - if ((rt = rt->rt_gwroute) == 0) - return (EHOSTUNREACH); - } - } - - - if (rt->rt_flags & RTF_REJECT) - if (rt->rt_rmx.rmx_expire == 0 || - time_second < rt->rt_rmx.rmx_expire) - return (rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); - } - - hlen = ETHER_HDR_LEN; - - /* - * Tell ether_frameout it's ok to loop packet unless negated below. - */ - m->m_flags |= M_LOOP; - - switch (dst_netaddr->sa_family) { - -#if INET - case AF_INET: - if (!arpresolve(ac, rt, m, dst_netaddr, edst, rt0)) - return (EJUSTRETURN); /* if not yet resolved */ - off = m->m_pkthdr.len - m->m_len; - *(u_short *)type = htons(ETHERTYPE_IP); - break; -#endif - -#if INET6 - case AF_INET6: - if (!nd6_storelladdr(&ac->ac_if, rt, m, dst_netaddr, (u_char *)edst)) { - /* this must be impossible, so we bark */ - kprintf("nd6_storelladdr failed\n"); - return(0); - } - off = m->m_pkthdr.len - m->m_len; - *(u_short *)type = htons(ETHERTYPE_IPV6); - break; -#endif - - - case AF_UNSPEC: - m->m_flags &= ~M_LOOP; - eh = (struct ether_header *)dst_netaddr->sa_data; - (void)memcpy(edst, eh->ether_dhost, 6); - *(u_short *)type = eh->ether_type; - break; - -#if NETAT - case AF_APPLETALK: - { - eh = (struct ether_header *)dst_netaddr->sa_data; - bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, 6); - - *(u_short *)type = m->m_pkthdr.len; - } - break; - -#endif /* NETAT */ - - default: - kprintf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, - dst_netaddr->sa_family); - - return EAFNOSUPPORT; - } - - return (0); -} - - - - - -int -ether_ioctl(dl_tag, ifp, command, data) - u_long dl_tag; - struct ifnet *ifp; - int command; - caddr_t data; -{ - struct ifaddr *ifa = (struct ifaddr *) data; - struct ifreq *ifr = (struct ifreq *) data; - int error = 0; - boolean_t funnel_state; - - funnel_state = thread_funnel_set(TRUE); - - switch (command) { - case SIOCSIFADDR: - ifp->if_flags |= IFF_UP; - - switch (ifa->ifa_addr->sa_family) { - - case AF_INET: - - if (ifp->if_init) - ifp->if_init(ifp->if_softc); /* before arpwhohas */ - - - arp_ifinit(IFP2AC(ifp), ifa); - - break; - - default: - break; - } - - break; - - case SIOCGIFADDR: - { - struct sockaddr *sa; - - sa = (struct sockaddr *) & ifr->ifr_data; - bcopy(IFP2AC(ifp)->ac_enaddr, - (caddr_t) sa->sa_data, ETHER_ADDR_LEN); - } - break; - - case SIOCSIFMTU: - /* - * Set the interface MTU. - */ - if (ifr->ifr_mtu > ETHERMTU) { - error = EINVAL; - } else { - ifp->if_mtu = ifr->ifr_mtu; - } - break; - } - - (void) thread_funnel_set(funnel_state); - - return (error); -} - - - - -/* - * Y-adapter filter check - * The rules here: - * For Rhap: return 1 - * For Both: return 0 - * Not for Rhap: return -1 - * Multicast/Broadcast => For Both - * Atalk address registered - * filter matches => For Rhap else Not For Rhap - * IP address registered - * filter matches => For Rhap else Not For Rhap - * For Rhap - * Note this is *not* a general filter mechanism in that we know - * what we *could* be looking for. - * WARNING: this is a big-endian routine. - * Note: ARP and AARP packets are implicitly accepted for "both" - */ -int -Filter_check(struct mbuf **m0) -{ register struct BlueFilter *bf; - register unsigned char *p; - register unsigned short *s; - register unsigned long *l; - int total, flags; - struct mbuf *m; - extern struct mbuf *m_pullup(struct mbuf *, int); - extern void kprintf( const char *, ...); -#define FILTER_LEN 32 - - m = *m0; - flags = m->m_flags; - if (FILTER_LEN > m->m_pkthdr.len) - return(1); - while ((FILTER_LEN > m->m_len) && m->m_next) { - total = m->m_len + (m->m_next)->m_len; - if ((m = m_pullup(m, min(FILTER_LEN, total))) == 0) - return(-1); - } - *m0 = m; - - p = mtod(m, unsigned char *); /* Point to destination media addr */ - if (p[0] & 0x01) /* Multicast/broadcast */ - return(0); - s = (unsigned short *)p; - bf = &RhapFilter[BFS_ATALK]; -#if 0 - kprintf("!PKT: %x, %x, %x\n", s[6], s[7], s[8]); -#endif - - if (bf->BF_flags) /* Filtering Appletalk */ - { - l = (unsigned long *)&s[8]; -#if 0 - kprintf("!AT: %x, %x, %x, %x, %x, %x\n", s[6], s[7], - *l, s[10], s[13], p[30]); -#endif - if (s[6] <= ETHERMTU) - { if (s[7] == 0xaaaa) /* Could be Atalk */ - { /* Verify SNAP header */ - if (*l == 0x03080007 && s[10] == 0x809b) - { if (s[13] == bf->BF_address && - p[30] == bf->BF_node) - return(1); - } else if (*l == 0x03000000 && s[10] == 0x80f3) - /* AARP pkts aren't net-addressed */ - return(0); - return(0); - } else /* Not for us? */ - return(0); - } /* Fall through */ - } /* Fall through */ - bf++; /* Look for IP next */ - if (bf->BF_flags) /* Filtering IP */ - { - l = (unsigned long *)&s[15]; -#if 0 - kprintf("!IP: %x, %x\n", s[6], *l); -#endif - if (s[6] > ETHERMTU) - { if (s[6] == 0x800) /* Is IP */ - { /* Verify IP address */ - if (*l == bf->BF_address) - return(1); - else /* Not for us */ - return(0); - } else if (s[6] == 0x806) - /* ARP pkts aren't net-addressed */ - return(0); - } - } - return(0); /* No filters => Accept */ -} - - - -int ether_family_init() -{ - - int i; - - if (ivedonethis) - return 0; - - ivedonethis = 1; - - - if (dlil_reg_if_modules(APPLE_IF_FAM_ETHERNET, ether_add_if, ether_del_if, - ether_add_proto, ether_del_proto, - ether_shutdown)) { - printf("WARNING: ether_family_init -- Can't register if family modules\n"); - return EIO; - } - - for (i=0; i < (LITMUS_SIZE/4); i++) - litmus_mask[i] = 0xffffffff; - - for (i=0; i < MAX_INTERFACES; i++) - ether_desc_blk[i].n_blocks = 0; - - for (i=0; i < MAX_EN_COUNT; i++) - en_at_array[i].ifp = 0; - - return 0; -} - - - -u_long ether_attach_inet(struct ifnet *ifp) -{ - struct dlil_proto_reg_str reg; - struct dlil_demux_desc desc; - struct dlil_demux_desc desc2; -#if INET6 - struct dlil_demux_desc desc3; -#endif - u_long ip_dl_tag=0; - u_short en_native=ETHERTYPE_IP; - u_short arp_native=ETHERTYPE_ARP; -#if INET6 - u_short en_6native=ETHERTYPE_IPV6; -#endif - int stat; - int i; - - - stat = dlil_find_dltag(ifp->if_family, ifp->if_unit, PF_INET, &ip_dl_tag); - if (stat == 0) - return ip_dl_tag; - - TAILQ_INIT(®.demux_desc_head); - desc.type = DLIL_DESC_RAW; - desc.variants.bitmask.proto_id_length = 0; - desc.variants.bitmask.proto_id = 0; - desc.variants.bitmask.proto_id_mask = 0; - desc.native_type = (char *) &en_native; - TAILQ_INSERT_TAIL(®.demux_desc_head, &desc, next); - reg.interface_family = ifp->if_family; - reg.unit_number = ifp->if_unit; - reg.input = new_ether_input; - reg.pre_output = ether_pre_output; - reg.event = 0; - reg.offer = 0; - reg.ioctl = ether_ioctl; - reg.default_proto = 1; - reg.protocol_family = PF_INET; - - desc2 = desc; - desc2.native_type = (char *) &arp_native; - TAILQ_INSERT_TAIL(®.demux_desc_head, &desc2, next); - -#if INET6 - desc3 = desc; - desc3.native_type = (char *) &en_6native; - TAILQ_INSERT_TAIL(®.demux_desc_head, &desc3, next); -#endif - - stat = dlil_attach_protocol(®, &ip_dl_tag); - if (stat) { - printf("WARNING: ether_attach_inet can't attach ip to interface\n"); - return stat; - } - - return ip_dl_tag; -} - -void ether_attach_at(struct ifnet *ifp, u_long *at_dl_tag, u_long *aarp_dl_tag) -{ - struct dlil_proto_reg_str reg; - struct dlil_demux_desc desc; - struct dlil_demux_desc desc2; - u_short native = 0; /* 802.2 frames use a length here */ - int stat; - int first_empty; - int i; - - - first_empty = MAX_EN_COUNT; - for (i=0; i < MAX_EN_COUNT; i++) { - if (en_at_array[i].ifp == 0) - first_empty = i; - - if (en_at_array[i].ifp == ifp) { - en_at_array[i].ref_count++; - *at_dl_tag = *aarp_dl_tag = en_at_array[i].dl_tag; - return; - } - } - - if (first_empty == MAX_EN_COUNT) - return; - - TAILQ_INIT(®.demux_desc_head); - desc.type = DLIL_DESC_802_2_SNAP; - desc.variants.desc_802_2_SNAP.dsap = LLC_SNAP_LSAP; - desc.variants.desc_802_2_SNAP.ssap = LLC_SNAP_LSAP; - desc.variants.desc_802_2_SNAP.control_code = 0x03; - desc.variants.desc_802_2_SNAP.org[0] = 0x08; - desc.variants.desc_802_2_SNAP.org[1] = 0x00; - desc.variants.desc_802_2_SNAP.org[2] = 0x07; - desc.variants.desc_802_2_SNAP.protocol_type = 0x809B; - desc.native_type = (char *) &native; - TAILQ_INSERT_TAIL(®.demux_desc_head, &desc, next); - reg.interface_family = ifp->if_family; - reg.unit_number = ifp->if_unit; - reg.input = new_ether_input; - reg.pre_output = ether_pre_output; - reg.event = 0; - reg.offer = 0; - reg.ioctl = ether_ioctl; - reg.default_proto = 0; - reg.protocol_family = PF_APPLETALK; - - desc2 = desc; - desc2.variants.desc_802_2_SNAP.protocol_type = 0x80F3; - desc2.variants.desc_802_2_SNAP.org[0] = 0; - desc2.variants.desc_802_2_SNAP.org[1] = 0; - desc2.variants.desc_802_2_SNAP.org[2] = 0; - - TAILQ_INSERT_TAIL(®.demux_desc_head, &desc2, next); - - stat = dlil_attach_protocol(®, at_dl_tag); - if (stat) { - printf("WARNING: ether_attach_at can't attach at to interface\n"); - return; - } - - *aarp_dl_tag = *at_dl_tag; - - en_at_array[first_empty].ifp = ifp; - en_at_array[first_empty].dl_tag = *at_dl_tag; - en_at_array[first_empty].ref_count = 1; - -} /* ether_attach_at */ - - -void ether_detach_at(struct ifnet *ifp) -{ - int i; - - for (i=0; i < MAX_EN_COUNT; i++) { - if (en_at_array[i].ifp == ifp) - break; - } - - if (i < MAX_EN_COUNT) { - if (en_at_array[i].ref_count > 1) - en_at_array[i].ref_count--; - else { - if (en_at_array[i].ref_count == 1) { - dlil_detach_protocol(en_at_array[i].dl_tag); - en_at_array[i].ifp = 0; - } - } - } -} diff --git a/bsd/net/dlil_pvt.h b/bsd/net/dlil_pvt.h index 273614cf8..91da52b03 100644 --- a/bsd/net/dlil_pvt.h +++ b/bsd/net/dlil_pvt.h @@ -21,6 +21,8 @@ */ #ifndef DLIL_PVT_H #define DLIL_PVT_H +#include +#ifdef __APPLE_API_PRIVATE #include #include @@ -41,6 +43,5 @@ struct dlil_family_mod_str { int (*del_proto)(struct if_proto *proto); } - - +#endif /* __APPLE_API_PRIVATE */ #endif diff --git a/bsd/net/ether_if_module.c b/bsd/net/ether_if_module.c index 86ea43d32..27e9dd8b8 100644 --- a/bsd/net/ether_if_module.c +++ b/bsd/net/ether_if_module.c @@ -71,6 +71,7 @@ #include #include #include +#include /* For M_LOOP */ /* #if INET @@ -109,7 +110,6 @@ extern struct ifqueue atalkintrq; #endif /* NVLAN > 0 */ static u_long lo_dlt = 0; -static ivedonethis = 0; #define IFP2AC(IFP) ((struct arpcom *)IFP) @@ -249,7 +249,7 @@ ether_add_proto(struct ddesc_head_str *desc_head, struct if_proto *proto, u_long } ed[i].proto = proto; - ed[i].data[0] = 0; + ed[i].data[0] = 0; ed[i].data[1] = 0; switch (desc->type) { @@ -291,7 +291,7 @@ ether_add_proto(struct ddesc_head_str *desc_head, struct if_proto *proto, u_long case DLIL_DESC_SNAP: { u_int8_t* pDest = ((u_int8_t*)&ed[i].data[0]) + 3; ed[i].type = DLIL_DESC_SNAP; - bcopy(&desc->native_type, pDest, 5); + bcopy(desc->native_type, pDest, 5); } break; } @@ -341,7 +341,7 @@ int ether_demux(ifp, m, frame_header, proto) * longs for quick compares. */ - if (ntohs(ether_type) < 1500) { + if (ntohs(ether_type) <= 1500) { extProto1 = *(u_int32_t*)data; // SAP or SNAP @@ -516,6 +516,24 @@ int ether_del_if(struct ifnet *ifp) return ENOENT; } +static +int ether_init_if(struct ifnet *ifp) +{ + register struct ifaddr *ifa; + register struct sockaddr_dl *sdl; + + ifa = ifnet_addrs[ifp->if_index - 1]; + if (ifa == 0) { + printf("ether_ifattach: no lladdr!\n"); + return; + } + sdl = (struct sockaddr_dl *)ifa->ifa_addr; + sdl->sdl_type = IFT_ETHER; + sdl->sdl_alen = ifp->if_addrlen; + bcopy((IFP2AC(ifp))->ac_enaddr, LLADDR(sdl), ifp->if_addrlen); + + return 0; +} int @@ -571,13 +589,13 @@ int ether_family_init() int i; struct dlil_ifmod_reg_str ifmod_reg; - if (ivedonethis) - return 0; - - ivedonethis = 1; + /* ethernet family is built-in, called from bsd_init */ + thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); + bzero(&ifmod_reg, sizeof(ifmod_reg)); ifmod_reg.add_if = ether_add_if; ifmod_reg.del_if = ether_del_if; + ifmod_reg.init_if = ether_init_if; ifmod_reg.add_proto = ether_add_proto; ifmod_reg.del_proto = ether_del_proto; ifmod_reg.ifmod_ioctl = ether_ifmod_ioctl; @@ -591,5 +609,7 @@ int ether_family_init() for (i=0; i < MAX_INTERFACES; i++) ether_desc_blk[i].n_count = 0; + thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); + return 0; } diff --git a/bsd/net/ether_inet6_pr_module.c b/bsd/net/ether_inet6_pr_module.c index 5855805bd..9764e8a97 100644 --- a/bsd/net/ether_inet6_pr_module.c +++ b/bsd/net/ether_inet6_pr_module.c @@ -86,7 +86,6 @@ #include -#include #include @@ -105,10 +104,6 @@ extern struct ifqueue pkintrq; #include #endif /* NVLAN > 0 */ - -extern struct ifnet_blue *blue_if; -extern struct mbuf *splitter_input(struct mbuf *, struct ifnet *); - static u_long lo_dlt = 0; static ivedonethis = 0; static u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; @@ -208,7 +203,6 @@ inet6_ether_pre_output(ifp, m0, dst_netaddr, route, type, edst, dl_tag ) register struct mbuf *m = *m0; register struct rtentry *rt; register struct ether_header *eh; - int off, len = m->m_pkthdr.len; int hlen; /* link layer header lenght */ struct arpcom *ac = IFP2AC(ifp); @@ -222,7 +216,7 @@ inet6_ether_pre_output(ifp, m0, dst_netaddr, route, type, edst, dl_tag ) if ((rt->rt_flags & RTF_UP) == 0) { rt0 = rt = rtalloc1(dst_netaddr, 1, 0UL); if (rt0) - rt->rt_refcnt--; + rtunref(rt); else return EHOSTUNREACH; } @@ -262,7 +256,6 @@ inet6_ether_pre_output(ifp, m0, dst_netaddr, route, type, edst, dl_tag ) printf("nd6_storelladdr failed\n"); return(0); } - off = m->m_pkthdr.len - m->m_len; *(u_short *)type = htons(ETHERTYPE_IPV6); break; @@ -324,8 +317,10 @@ ether_inet6_prmod_ioctl(dl_tag, ifp, command, data) sdl->sdl_slen = 0; e_addr = LLADDR(sdl); ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr); +#ifndef __APPLE__ printf("ether_resolvemulti AF_INET6 Adding %x:%x:%x:%x:%x:%x\n", e_addr[0], e_addr[1], e_addr[2], e_addr[3], e_addr[4], e_addr[5]); +#endif *rsreq->llsa = (struct sockaddr *)sdl; return 0; @@ -358,14 +353,10 @@ ether_inet6_prmod_ioctl(dl_tag, ifp, command, data) case SIOCSIFMTU: /* - * Set the interface MTU. + * IOKit IONetworkFamily will set the right MTU according to the driver */ - if (ifr->ifr_mtu > ETHERMTU) { - error = EINVAL; - } else { - ifp->if_mtu = ifr->ifr_mtu; - } - break; + + return (0); default: return EOPNOTSUPP; @@ -417,3 +408,19 @@ u_long ether_attach_inet6(struct ifnet *ifp) return ip_dl_tag; } + +int ether_detach_inet6(struct ifnet *ifp) +{ + u_long ip_dl_tag = 0; + int stat; + + stat = dlil_find_dltag(ifp->if_family, ifp->if_unit, PF_INET6, &ip_dl_tag); + if (stat == 0) { + stat = dlil_detach_protocol(ip_dl_tag); + if (stat) { + printf("WARNING: ether_detach_inet6 can't detach ip6 from interface\n"); + } + } + return stat; +} + diff --git a/bsd/net/ether_inet_pr_module.c b/bsd/net/ether_inet_pr_module.c index b206d8f73..59d7a8d49 100644 --- a/bsd/net/ether_inet_pr_module.c +++ b/bsd/net/ether_inet_pr_module.c @@ -237,7 +237,7 @@ inet_ether_pre_output(ifp, m0, dst_netaddr, route, type, edst, dl_tag ) if ((rt->rt_flags & RTF_UP) == 0) { rt0 = rt = rtalloc1(dst_netaddr, 1, 0UL); if (rt0) - rt->rt_refcnt--; + rtunref(rt); else return EHOSTUNREACH; } @@ -377,6 +377,13 @@ ether_inet_prmod_ioctl(dl_tag, ifp, command, data) arp_ifinit(IFP2AC(ifp), ifa); + /* + * Register new IP and MAC addresses with the kernel debugger + * for the en0 interface. + */ + if (ifp->if_unit == 0) + kdp_set_ip_and_mac_addresses(&(IA_SIN(ifa)->sin_addr), &(IFP2AC(ifp)->ac_enaddr)); + break; default: @@ -397,14 +404,10 @@ ether_inet_prmod_ioctl(dl_tag, ifp, command, data) case SIOCSIFMTU: /* - * Set the interface MTU. + * IOKit IONetworkFamily will set the right MTU according to the driver */ - if (ifr->ifr_mtu > ETHERMTU) { - error = EINVAL; - } else { - ifp->if_mtu = ifr->ifr_mtu; - } - break; + + return (0); default: return EOPNOTSUPP; @@ -462,8 +465,6 @@ ether_attach_inet(struct ifnet *ifp) printf("WARNING: ether_attach_inet can't attach ip to interface\n"); return stat; } - /* XXX avoid free'ing the interface */ - ifp->if_eflags |= IFEF_DETACH_DISABLED; return ip_dl_tag; } diff --git a/bsd/net/etherdefs.h b/bsd/net/etherdefs.h index cd56710f9..6e577eb14 100644 --- a/bsd/net/etherdefs.h +++ b/bsd/net/etherdefs.h @@ -46,12 +46,18 @@ */ #ifndef _ETHERDEFS_ #define _ETHERDEFS_ +#include +#if !defined(KERNEL) || defined(__APPLE_API_OBSOLETE) + +#include +#warning net/etherdefs.h is obsolete! Use net/ethernet.h #include + /* * Ethernet address - 6 octets */ -#define NUM_EN_ADDR_BYTES 6 +#define NUM_EN_ADDR_BYTES ETHER_ADDR_LEN typedef struct ether_addr enet_addr_t; @@ -60,10 +66,10 @@ typedef struct ether_header ether_header_t; #define IFTYPE_ETHERNET "10MB Ethernet" -#define ETHERHDRSIZE 14 -#define ETHERMAXPACKET (ETHERHDRSIZE + ETHERMTU) -#define ETHERMINPACKET 64 -#define ETHERCRC 4 +#define ETHERHDRSIZE ETHER_HDR_LEN +#define ETHERMAXPACKET ETHER_MAX_LEN +#define ETHERMINPACKET ETHER_MIN_LEN +#define ETHERCRC ETHER_CRC_LEN /* * Byte and bit in an enet_addr_t defining individual/group destination. @@ -72,4 +78,5 @@ typedef struct ether_header ether_header_t; #define EA_GROUP_BIT 0x01 +#endif /* KERNEL && !__APPLE_API_OBSOLETE */ #endif /* _ETHERDEFS_ */ diff --git a/bsd/net/ethernet.h b/bsd/net/ethernet.h index de84f184e..accdc05d0 100644 --- a/bsd/net/ethernet.h +++ b/bsd/net/ethernet.h @@ -26,6 +26,7 @@ #ifndef _NET_ETHERNET_H_ #define _NET_ETHERNET_H_ +#include /* * The number of bytes in an ethernet (MAC) address. @@ -101,11 +102,13 @@ struct ether_addr { #define ETHERMTU (ETHER_MAX_LEN-ETHER_HDR_LEN-ETHER_CRC_LEN) #define ETHERMIN (ETHER_MIN_LEN-ETHER_HDR_LEN-ETHER_CRC_LEN) -#if KERNEL +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE struct ether_addr *ether_aton __P((char *)); +#endif /* __APPLE_API_PRIVATE */ #endif -#if !KERNEL +#ifndef KERNEL #include /* diff --git a/bsd/net/hostcache.c b/bsd/net/hostcache.c deleted file mode 100644 index f2a6ff463..000000000 --- a/bsd/net/hostcache.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright 1997 Massachusetts Institute of Technology - * - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby - * granted, provided that both the above copyright notice and this - * permission notice appear in all copies, that both the above - * copyright notice and this permission notice appear in all - * supporting documentation, and that the name of M.I.T. not be used - * in advertising or publicity pertaining to distribution of the - * software without specific, written prior permission. M.I.T. makes - * no representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied - * warranty. - * - * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS - * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT - * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -#include -#include -#include -#include -#include - -#include -#include - -MALLOC_DEFINE(M_HOSTCACHE, "hostcache", "per-host cache structure"); - -static struct hctable hctable[AF_MAX]; -static int hc_timeout_interval = 120; -static int hc_maxidle = 1800; - -static int cmpsa(const struct sockaddr *sa1, const struct sockaddr *sa2); -static void hc_timeout(void *xhct); -static void maybe_bump_hash(struct hctable *hct); - -int -hc_init(int af, struct hccallback *hccb, int init_nelem, int primes) -{ - struct hctable *hct; - struct hchead *heads; - u_long nelem; - - hct = &hctable[af]; - nelem = init_nelem; - if (hct->hct_nentries) - return 0; - - if (primes) { - heads = phashinit(init_nelem, M_HOSTCACHE, &nelem); - } else { - int i; - MALLOC(heads, struct hchead *, nelem * sizeof *heads, - M_HOSTCACHE, M_WAITOK); - for (i = 0; i < nelem; i++) { - LIST_INIT(&heads[i]); - } - } - - hct->hct_heads = heads; - hct->hct_nentries = nelem; - hct->hct_primes = primes; - timeout(hc_timeout, hct, hc_timeout_interval * hz); - return 0; -} - -struct hcentry * -hc_get(struct sockaddr *sa) -{ - u_long hash; - struct hcentry *hc; - struct hctable *hct; - int s; - - hct = &hctable[sa->sa_family]; - if (hct->hct_nentries == 0) - return 0; - hash = hct->hct_cb->hccb_hash(sa, hct->hct_nentries); - hc = hct->hct_heads[hash].lh_first; - for (; hc; hc = hc->hc_link.le_next) { - if (cmpsa(hc->hc_host, sa) == 0) - break; - } - if (hc == 0) - return 0; - s = splnet(); - if (hc->hc_rt && (hc->hc_rt->rt_flags & RTF_UP) == 0) { - RTFREE(hc->hc_rt); - hc->hc_rt = 0; - } - if (hc->hc_rt == 0) { - hc->hc_rt = rtalloc1(hc->hc_host, 1, 0); - } - hc_ref(hc); - splx(s); - /* XXX move to front of list? */ - return hc; -} - -void -hc_ref(struct hcentry *hc) -{ - int s = splnet(); - if (hc->hc_refcnt++ == 0) { - hc->hc_hct->hct_idle--; - hc->hc_hct->hct_active++; - } - splx(s); -} - -void -hc_rele(struct hcentry *hc) -{ - int s = splnet(); -#ifdef DIAGNOSTIC - printf("hc_rele: %p: negative refcnt!\n", (void *)hc); -#endif - hc->hc_refcnt--; - if (hc->hc_refcnt == 0) { - hc->hc_hct->hct_idle++; - hc->hc_hct->hct_active--; - hc->hc_idlesince = mono_time; /* XXX right one? */ - } - splx(s); -} - -/* - * The user is expected to initialize hc_host with the address and everything - * else to the appropriate form of `0'. - */ -int -hc_insert(struct hcentry *hc) -{ - struct hcentry *hc2; - struct hctable *hct; - u_long hash; - int s; - - hct = &hctable[hc->hc_host->sa_family]; - hash = hct->hct_cb->hccb_hash(hc->hc_host, hct->hct_nentries); - - hc2 = hct->hct_heads[hash].lh_first; - for (; hc2; hc2 = hc2->hc_link.le_next) { - if (cmpsa(hc2->hc_host, hc->hc_host) == 0) - break; - } - if (hc2 != 0) - return EEXIST; - hc->hc_hct = hct; - s = splnet(); - LIST_INSERT_HEAD(&hct->hct_heads[hash], hc, hc_link); - hct->hct_idle++; - /* - * If the table is now more than 75% full, consider bumping it. - */ - if (100 * (hct->hct_idle + hct->hct_active) > 75 * hct->hct_nentries) - maybe_bump_hash(hct); - splx(s); - return 0; -} - -/* - * It's not clear to me how much sense this makes as an external interface, - * since it is expected that the deletion will normally be handled by - * the cache timeout. - */ -int -hc_delete(struct hcentry *hc) -{ - struct hctable *hct; - int error, s; - - if (hc->hc_refcnt > 0) - return 0; - - hct = hc->hc_hct; - error = hct->hct_cb->hccb_delete(hc); - if (error) - return 0; - - s = splnet(); - LIST_REMOVE(hc, hc_link); - hc->hc_hct->hct_idle--; - splx(s); - FREE(hc, M_HOSTCACHE); - return 0; -} - -static void -hc_timeout(void *xhct) -{ - struct hcentry *hc; - struct hctable *hct; - int j, s; - time_t start; - - hct = xhct; - start = mono_time.tv_sec; /* for simplicity */ - - if (hct->hct_idle == 0) - return; - for (j = 0; j < hct->hct_nentries; j++) { - for (hc = hct->hct_heads[j].lh_first; hc; - hc = hc->hc_link.le_next) { - if (hc->hc_refcnt > 0) - continue; - if (hc->hc_idlesince.tv_sec + hc_maxidle <= start) { - if (hct->hct_cb->hccb_delete(hc)) - continue; - s = splnet(); - LIST_REMOVE(hc, hc_link); - hct->hct_idle--; - splx(s); - } - } - } - /* - * Fiddle something here based on tot_idle... - */ - timeout(hc_timeout, xhct, hc_timeout_interval * hz); -} - -static int -cmpsa(const struct sockaddr *sa1, const struct sockaddr *sa2) -{ - if (sa1->sa_len != sa2->sa_len) - return ((int)sa1->sa_len - sa2->sa_len); - return bcmp(sa1, sa2, sa1->sa_len); -} - -static void -maybe_bump_hash(struct hctable *hct) -{ - ; /* XXX fill me in */ -} diff --git a/bsd/net/hostcache.h b/bsd/net/hostcache.h deleted file mode 100644 index 616c2d0d8..000000000 --- a/bsd/net/hostcache.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright 1997 Massachusetts Institute of Technology - * - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby - * granted, provided that both the above copyright notice and this - * permission notice appear in all copies, that both the above - * copyright notice and this permission notice appear in all - * supporting documentation, and that the name of M.I.T. not be used - * in advertising or publicity pertaining to distribution of the - * software without specific, written prior permission. M.I.T. makes - * no representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied - * warranty. - * - * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS - * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT - * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -#ifndef _NET_HOSTCACHE_H -#define _NET_HOSTCACHE_H 1 - -/* - * This file defines the interface between network protocols and - * the cache of host-specific information maintained by the kernel. - * The generic interface takes care of inserting and deleting entries, - * maintaining mutual exclusion, and enforcing policy constraint on the - * size of the cache and the maximum age of its entries. - * It replaces an earlier scheme which overloaded the routing table - * for this purpose, and should be significantly more efficient - * at performing most operations. (It does keep a route to each - * entry in the cache.) Most protocols will want to define a - * structure which begins with `struct hcentry' so that they - * can keep additional, protocol-specific information in it. - */ - -#include - -struct hcentry { - LIST_ENTRY(hcentry) hc_link; - struct timeval hc_idlesince; /* time last ref dropped */ - struct sockaddr *hc_host; /* address of this entry's host */ - struct rtentry *hc_rt; /* route to get there */ - /* struct nexthop *hc_nh; */ - int hc_refcnt; /* reference count */ - struct hctable *hc_hct; /* back ref to table */ -}; - -struct hccallback { - u_long (*hccb_hash)(struct sockaddr *, u_long); - int (*hccb_delete)(struct hcentry *); - u_long (*hccb_bump)(u_long); -}; - -LIST_HEAD(hchead, hcentry); - -struct hctable { - u_long hct_nentries; - u_long hct_active; - u_long hct_idle; - struct hchead *hct_heads; - struct hccallback *hct_cb; - int hct_primes; -}; - -#ifdef KERNEL - -#ifdef MALLOC_DECLARE -MALLOC_DECLARE(M_HOSTCACHE); -#endif -/* - * The table-modification functions must be called from user mode, as - * they may block waiting for memory and/or locks. - */ -int hc_init(int af, struct hccallback *hccb, int init_nelem, int primes); -struct hcentry *hc_get(struct sockaddr *sa); -void hc_ref(struct hcentry *hc); -void hc_rele(struct hcentry *hc); -int hc_insert(struct hcentry *hc); -int hc_delete(struct hcentry *hc); -#endif /* KERNEL */ - -#endif /* _NET_HOSTCACHE_H */ diff --git a/bsd/net/if.c b/bsd/net/if.c index 088e52b99..17213f3db 100644 --- a/bsd/net/if.c +++ b/bsd/net/if.c @@ -52,12 +52,9 @@ * SUCH DAMAGE. * * @(#)if.c 8.3 (Berkeley) 1/4/94 + * $FreeBSD: src/sys/net/if.c,v 1.85.2.9 2001/07/24 19:10:17 brooks Exp $ */ -/* -#include "opt_compat.h" -*/ - #include #include #include @@ -70,13 +67,30 @@ #include #include #include + #include +#include #include +#include +#include #include -#include +#include +#ifdef __APPLE__ #include -#include +//#include #include +#endif + +#if defined(INET) || defined(INET6) +/*XXX*/ +#include +#include +#if INET6 +#include +#include +#endif +#endif + /* * System initialization */ @@ -96,19 +110,16 @@ struct ifnethead ifnet; /* depend on static init XXX */ * XXX: declare here to avoid to include many inet6 related files.. * should be more generalized? */ -extern void nd6_setmtu __P((struct ifnet *)); -#endif +extern void nd6_setmtu __P((struct ifnet *)); +extern int ip6_auto_on; +#endif /* * Network interface utility routines. * * Routines with ifa_ifwith* names take sockaddr *'s as * parameters. - * - * This routine assumes that it will be called at splimp() or higher. */ -/* ARGSUSED*/ - int if_index = 0; struct ifaddr **ifnet_addrs; @@ -129,11 +140,16 @@ old_if_attach(ifp) register struct sockaddr_dl *sdl; register struct ifaddr *ifa; static int if_indexlim = 8; - + static int inited; if (ifp->if_snd.ifq_maxlen == 0) ifp->if_snd.ifq_maxlen = ifqmaxlen; + if (!inited) { + TAILQ_INIT(&ifnet); + inited = 1; + } + TAILQ_INSERT_TAIL(&ifnet, ifp, if_link); ifp->if_index = ++if_index; /* @@ -144,6 +160,7 @@ old_if_attach(ifp) * this unlikely case. */ TAILQ_INIT(&ifp->if_addrhead); + TAILQ_INIT(&ifp->if_prefixhead); LIST_INIT(&ifp->if_multiaddrs); getmicrotime(&ifp->if_lastchange); if (ifnet_addrs == 0 || if_index >= if_indexlim) { @@ -158,8 +175,8 @@ old_if_attach(ifp) ifnet_addrs = (struct ifaddr **)q; /* grow ifindex2ifnet */ - n = if_indexlim * sizeof(struct ifnet *); - q = (caddr_t)_MALLOC(n, M_IFADDR, M_WAITOK); + n = if_indexlim * sizeof(struct ifaddr *); + q = (struct ifaddr **)_MALLOC(n, M_IFADDR, M_WAITOK); bzero(q, n); if (ifindex2ifnet) { bcopy((caddr_t)ifindex2ifnet, q, n/2); @@ -205,6 +222,7 @@ old_if_attach(ifp) TAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link); } } + /* * Locate an interface based on a complete address. */ @@ -219,7 +237,7 @@ ifa_ifwithaddr(addr) #define equal(a1, a2) \ (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0) for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) - for (ifa = ifp->if_addrhead.tqh_first; ifa; + for (ifa = ifp->if_addrhead.tqh_first; ifa; ifa = ifa->ifa_link.tqe_next) { if (ifa->ifa_addr->sa_family != addr->sa_family) continue; @@ -246,7 +264,7 @@ ifa_ifwithdstaddr(addr) for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) if (ifp->if_flags & IFF_POINTOPOINT) - for (ifa = ifp->if_addrhead.tqh_first; ifa; + for (ifa = ifp->if_addrhead.tqh_first; ifa; ifa = ifa->ifa_link.tqe_next) { if (ifa->ifa_addr->sa_family != addr->sa_family) continue; @@ -280,7 +298,7 @@ ifa_ifwithnet(addr) return (ifnet_addrs[sdl->sdl_index - 1]); } - /* + /* * Scan though each interface, looking for ones that have * addresses in this address family. */ @@ -291,21 +309,30 @@ ifa_ifwithnet(addr) if (ifa->ifa_addr->sa_family != af) next: continue; -#if 0 /* for maching gif tunnel dst as routing entry gateway */ - if (ifp->if_flags & IFF_POINTOPOINT) { +#ifndef __APPLE__ +/* This breaks tunneling application trying to install a route with + * a specific subnet and the local address as the destination + * It's breaks binary compatibility with previous version of MacOS X + */ + if ( + +#if INET6 /* XXX: for maching gif tunnel dst as routing entry gateway */ + addr->sa_family != AF_INET6 && +#endif + ifp->if_flags & IFF_POINTOPOINT) { /* - * This is a bit broken as it doesn't - * take into account that the remote end may + * This is a bit broken as it doesn't + * take into account that the remote end may * be a single node in the network we are * looking for. - * The trouble is that we don't know the + * The trouble is that we don't know the * netmask for the remote end. */ if (ifa->ifa_dstaddr != 0 && equal(addr, ifa->ifa_dstaddr)) return (ifa); } else -#endif +#endif /* __APPLE__*/ { /* * if we have a special address handler, @@ -370,7 +397,7 @@ ifaof_ifpforaddr(addr, ifp) if (af >= AF_MAX) return (0); - for (ifa = ifp->if_addrhead.tqh_first; ifa; + for (ifa = ifp->if_addrhead.tqh_first; ifa; ifa = ifa->ifa_link.tqe_next) { if (ifa->ifa_addr->sa_family != af) continue; @@ -422,9 +449,7 @@ link_rtrequest(cmd, rt, sa) return; ifa = ifaof_ifpforaddr(dst, ifp); if (ifa) { - IFAFREE(rt->rt_ifa); - rt->rt_ifa = ifa; - ifa->ifa_refcnt++; + rtsetifa(rt, ifa); if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest) ifa->ifa_rtrequest(cmd, rt, sa); } @@ -469,8 +494,10 @@ if_route(ifp, flag, fam) if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family)) pfctlinput(PRC_IFUP, ifa->ifa_addr); rt_ifmsg(ifp); + #if INET6 - in6_if_up(ifp); + if (ip6_auto_on) /* Only if IPv6 is on on configured on on all ifs */ + in6_if_up(ifp); #endif } @@ -519,52 +546,46 @@ if_qflush(ifq) ifq->ifq_len = 0; } - /* * Map interface name to * interface structure pointer. */ struct ifnet * -ifunit(name) - register char *name; +ifunit(const char *name) { char namebuf[IFNAMSIZ + 1]; - register char *cp, *cp2; - char *end; - register struct ifnet *ifp; + const char *cp; + struct ifnet *ifp; int unit; - unsigned len; - register char c = '\0'; + unsigned len, m; + char c; - /* - * Look for a non numeric part - */ - end = name + IFNAMSIZ; - cp2 = namebuf; - cp = name; - while ((cp < end) && (c = *cp)) { - if (c >= '0' && c <= '9') - break; - *cp2++ = c; - cp++; - } - if ((cp == end) || (c == '\0') || (cp == name)) - return ((struct ifnet *)0); - *cp2 = '\0'; - /* - * check we have a legal number (limit to 7 digits?) - */ + len = strlen(name); + if (len < 2 || len > IFNAMSIZ) + return NULL; + cp = name + len - 1; + c = *cp; + if (c < '0' || c > '9') + return NULL; /* trailing garbage */ + unit = 0; + m = 1; + do { + if (cp == name) + return NULL; /* no interface name */ + unit += (c - '0') * m; + if (unit > 1000000) + return NULL; /* number is unreasonable */ + m *= 10; + c = *--cp; + } while (c >= '0' && c <= '9'); len = cp - name + 1; - for (unit = 0; - ((c = *cp) >= '0') && (c <= '9') && (unit < 1000000); cp++ ) - unit = (unit * 10) + (c - '0'); - if (*cp != '\0') - return 0; /* no trailing garbage allowed */ + bcopy(name, namebuf, len); + namebuf[len] = '\0'; /* * Now search all the interfaces for this name/number */ for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) { - if (bcmp(ifp->if_name, namebuf, len)) + if (strcmp(ifp->if_name, namebuf)) continue; if (unit == ifp->if_unit) break; @@ -613,9 +634,10 @@ ifioctl(so, cmd, data, p) { register struct ifnet *ifp; register struct ifreq *ifr; + struct ifstat *ifs; int error = 0; - struct kev_msg ev_msg; short oif_flags; + struct kev_msg ev_msg; struct net_event_data ev_data; switch (cmd) { @@ -650,36 +672,41 @@ ifioctl(so, cmd, data, p) error = suser(p->p_ucred, &p->p_acflag); if (error) return (error); - if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { +#ifndef __APPLE__ + if (ifp->if_flags & IFF_SMART) { + /* Smart drivers twiddle their own routes */ + } else +#endif + if (ifp->if_flags & IFF_UP && + (ifr->ifr_flags & IFF_UP) == 0) { int s = splimp(); if_down(ifp); splx(s); - } - if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0) { + } else if (ifr->ifr_flags & IFF_UP && + (ifp->if_flags & IFF_UP) == 0) { int s = splimp(); if_up(ifp); splx(s); } ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | - (ifr->ifr_flags &~ IFF_CANTCHANGE); + (ifr->ifr_flags &~ IFF_CANTCHANGE); error = dlil_ioctl(so->so_proto->pr_domain->dom_family, ifp, cmd, (caddr_t) data); if (error == 0) { - ev_msg.vendor_code = KEV_VENDOR_APPLE; - ev_msg.kev_class = KEV_NETWORK_CLASS; - ev_msg.kev_subclass = KEV_DL_SUBCLASS; - - ev_msg.event_code = KEV_DL_SIFFLAGS; - strncpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ); - ev_data.if_family = ifp->if_family; - ev_data.if_unit = (unsigned long) ifp->if_unit; - ev_msg.dv[0].data_length = sizeof(struct net_event_data); - ev_msg.dv[0].data_ptr = &ev_data; - ev_msg.dv[1].data_length = 0; - kev_post_msg(&ev_msg); - + ev_msg.vendor_code = KEV_VENDOR_APPLE; + ev_msg.kev_class = KEV_NETWORK_CLASS; + ev_msg.kev_subclass = KEV_DL_SUBCLASS; + + ev_msg.event_code = KEV_DL_SIFFLAGS; + strncpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ); + ev_data.if_family = ifp->if_family; + ev_data.if_unit = (unsigned long) ifp->if_unit; + ev_msg.dv[0].data_length = sizeof(struct net_event_data); + ev_msg.dv[0].data_ptr = &ev_data; + ev_msg.dv[1].data_length = 0; + kev_post_msg(&ev_msg); } getmicrotime(&ifp->if_lastchange); break; @@ -714,24 +741,23 @@ ifioctl(so, cmd, data, p) return error; error = dlil_ioctl(so->so_proto->pr_domain->dom_family, - ifp, cmd, (caddr_t) data); + ifp, cmd, (caddr_t) data); if (error == 0) { + ev_msg.vendor_code = KEV_VENDOR_APPLE; + ev_msg.kev_class = KEV_NETWORK_CLASS; + ev_msg.kev_subclass = KEV_DL_SUBCLASS; + + ev_msg.event_code = KEV_DL_SIFPHYS; + strncpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ); + ev_data.if_family = ifp->if_family; + ev_data.if_unit = (unsigned long) ifp->if_unit; + ev_msg.dv[0].data_length = sizeof(struct net_event_data); + ev_msg.dv[0].data_ptr = &ev_data; + ev_msg.dv[1].data_length = 0; + kev_post_msg(&ev_msg); - ev_msg.vendor_code = KEV_VENDOR_APPLE; - ev_msg.kev_class = KEV_NETWORK_CLASS; - ev_msg.kev_subclass = KEV_DL_SUBCLASS; - - ev_msg.event_code = KEV_DL_SIFPHYS; - strncpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ); - ev_data.if_family = ifp->if_family; - ev_data.if_unit = (unsigned long) ifp->if_unit; - ev_msg.dv[0].data_length = sizeof(struct net_event_data); - ev_msg.dv[0].data_ptr = &ev_data; - ev_msg.dv[1].data_length = 0; - kev_post_msg(&ev_msg); - - getmicrotime(&ifp->if_lastchange); + getmicrotime(&ifp->if_lastchange); } return(error); @@ -744,11 +770,7 @@ ifioctl(so, cmd, data, p) return (error); if (ifp->if_ioctl == NULL) return (EOPNOTSUPP); - /* - * 72 was chosen below because it is the size of a TCP/IP - * header (40) + the minimum mss (32). - */ - if (ifr->ifr_mtu < 72 || ifr->ifr_mtu > 65535) + if (ifr->ifr_mtu < IF_MINMTU || ifr->ifr_mtu > IF_MAXMTU) return (EINVAL); error = dlil_ioctl(so->so_proto->pr_domain->dom_family, @@ -769,17 +791,18 @@ ifioctl(so, cmd, data, p) kev_post_msg(&ev_msg); getmicrotime(&ifp->if_lastchange); + rt_ifmsg(ifp); } /* * If the link MTU changed, do network layer specific procedure. */ -#ifdef INET6 - if (ifp->if_mtu != oldmtu) { - nd6_setmtu(ifp); - } -#endif + if (ifp->if_mtu != oldmtu) { +#if INET6 + nd6_setmtu(ifp); +#endif } - return(error); + return (error); + } case SIOCADDMULTI: case SIOCDELMULTI: @@ -791,13 +814,12 @@ ifioctl(so, cmd, data, p) if ((ifp->if_flags & IFF_MULTICAST) == 0) return EOPNOTSUPP; -#if 0 - /* - * Don't let users change protocols' entries. - */ +#ifndef __APPLE__ + /* Don't let users screw up protocols' entries. */ if (ifr->ifr_addr.sa_family != AF_LINK) return EINVAL; #endif + if (cmd == SIOCADDMULTI) { struct ifmultiaddr *ifma; error = if_addmulti(ifp, &ifr->ifr_addr, &ifma); @@ -823,8 +845,15 @@ ifioctl(so, cmd, data, p) } return error; - case SIOCSIFMEDIA: + case SIOCSIFPHYADDR: + case SIOCDIFPHYADDR: +#ifdef INET6 + case SIOCSIFPHYADDR_IN6: +#endif + case SIOCSLIFPHYADDR: + case SIOCSIFMEDIA: case SIOCSIFGENERIC: + case SIOCSIFLLADDR: error = suser(p->p_ucred, &p->p_acflag); if (error) return (error); @@ -836,6 +865,13 @@ ifioctl(so, cmd, data, p) getmicrotime(&ifp->if_lastchange); return error; + case SIOCGIFSTATUS: + ifs = (struct ifstat *)data; + ifs->ascii[0] = '\0'; + + case SIOCGIFPSRCADDR: + case SIOCGIFPDSTADDR: + case SIOCGLIFPHYADDR: case SIOCGIFMEDIA: case SIOCGIFGENERIC: @@ -870,7 +906,6 @@ ifioctl(so, cmd, data, p) if (ifr->ifr_addr.sa_len == 0) ifr->ifr_addr.sa_len = 16; #endif - /* Fall through! */ break; case OSIOCGIFADDR: @@ -888,7 +923,6 @@ ifioctl(so, cmd, data, p) case OSIOCGIFNETMASK: cmd = SIOCGIFNETMASK; } - error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd, data, @@ -899,29 +933,19 @@ ifioctl(so, cmd, data, p) case OSIOCGIFDSTADDR: case OSIOCGIFBRDADDR: case OSIOCGIFNETMASK: - *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family; - } - - - } + *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family; - if (error == EOPNOTSUPP) - error = dlil_ioctl(so->so_proto->pr_domain->dom_family, - ifp, cmd, (caddr_t) data); - -#if INET6 - if ((oif_flags ^ ifp->if_flags) & IFF_UP) { - if (ifp->if_flags & IFF_UP) { - int s = splimp(); - in6_if_up(ifp); - splx(s); } } -#endif -#endif +#endif /* COMPAT_43 */ + if (error == EOPNOTSUPP) + error = dlil_ioctl(so->so_proto->pr_domain->dom_family, + ifp, cmd, (caddr_t) data); + + return (error); } - return (error); + return (0); } /* @@ -937,7 +961,9 @@ ifpromisc(ifp, pswitch) { struct ifreq ifr; int error; + int oldflags; + oldflags = ifp->if_flags; if (pswitch) { /* * If the device is not configured up, we cannot put it in @@ -954,11 +980,15 @@ ifpromisc(ifp, pswitch) if (--ifp->if_pcount > 0) return (0); ifp->if_flags &= ~IFF_PROMISC; + log(LOG_INFO, "%s%d: promiscuous mode disabled\n", + ifp->if_name, ifp->if_unit); } ifr.ifr_flags = ifp->if_flags; error = dlil_ioctl(0, ifp, SIOCSIFFLAGS, (caddr_t)&ifr); if (error == 0) rt_ifmsg(ifp); + else + ifp->if_flags = oldflags; return error; } @@ -983,28 +1013,28 @@ ifconf(cmd, data) ifrp = ifc->ifc_req; for (; space > sizeof (ifr) && ifp; ifp = ifp->if_link.tqe_next) { char workbuf[64]; - int ifnlen; + int ifnlen, addrs; ifnlen = snprintf(workbuf, sizeof(workbuf), "%s%d", ifp->if_name, ifp->if_unit); if(ifnlen + 1 > sizeof ifr.ifr_name) { error = ENAMETOOLONG; + break; } else { strcpy(ifr.ifr_name, workbuf); } - if ((ifa = ifp->if_addrhead.tqh_first) == 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_link.tqe_next) { + addrs = 0; + ifa = ifp->if_addrhead.tqh_first; + for ( ; space > sizeof (ifr) && ifa; + ifa = ifa->ifa_link.tqe_next) { register struct sockaddr *sa = ifa->ifa_addr; -#if COMPAT_43 +#ifndef __APPLE__ + if (curproc->p_prison && prison_if(curproc, sa)) + continue; +#endif + addrs++; +#ifdef COMPAT_43 if (cmd == OSIOCGIFCONF) { struct osockaddr *osa = (struct osockaddr *)&ifr.ifr_addr; @@ -1021,9 +1051,10 @@ ifconf(cmd, data) sizeof (ifr)); ifrp++; } else { - space -= sa->sa_len - sizeof(*sa); - if (space < sizeof (ifr)) + if (space < sizeof (ifr) + sa->sa_len - + sizeof(*sa)) break; + space -= sa->sa_len - sizeof(*sa); error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr.ifr_name)); if (error == 0) @@ -1036,6 +1067,17 @@ ifconf(cmd, data) break; space -= sizeof (ifr); } + if (error) + break; + if (!addrs) { + 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++; + } } ifc->ifc_len -= space; return (error); @@ -1075,7 +1117,7 @@ if_allmulti(ifp, onswitch) /* * Add a multicast listenership to the interface in question. - * The link layer provides a routine which converts + * The link layer provides a routine which converts */ int if_addmulti(ifp, sa, retifma) @@ -1093,7 +1135,7 @@ if_addmulti(ifp, sa, retifma) * If the matching multicast address already exists * then don't add a new one, just add a reference */ - for (ifma = ifp->if_multiaddrs.lh_first; ifma; + for (ifma = ifp->if_multiaddrs.lh_first; ifma; ifma = ifma->ifma_link.le_next) { if (equal(sa, ifma->ifma_addr)) { ifma->ifma_refcount++; @@ -1108,16 +1150,18 @@ if_addmulti(ifp, sa, retifma) * find out which AF_LINK address this maps to, if it isn't one * already. */ - rsreq.sa = sa; rsreq.llsa = &llsa; error = dlil_ioctl(sa->sa_family, ifp, SIOCRSLVMULTI, (caddr_t) &rsreq); + + /* to be similar to FreeBSD */ + if (error == EOPNOTSUPP) + error = 0; if (error) return error; - MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma, M_IFMADDR, M_WAITOK); MALLOC(dupsa, struct sockaddr *, sa->sa_len, M_IFMADDR, M_WAITOK); bcopy(sa, dupsa, sa->sa_len); @@ -1167,7 +1211,6 @@ if_addmulti(ifp, sa, retifma) * interface to let them know about it. */ s = splimp(); - dlil_ioctl(0, ifp, SIOCADDMULTI, (caddr_t) 0); splx(s); @@ -1186,7 +1229,7 @@ if_delmulti(ifp, sa) struct ifmultiaddr *ifma; int s; - for (ifma = ifp->if_multiaddrs.lh_first; ifma; + for (ifma = ifp->if_multiaddrs.lh_first; ifma; ifma = ifma->ifma_link.le_next) if (equal(sa, ifma->ifma_addr)) break; @@ -1202,19 +1245,13 @@ if_delmulti(ifp, sa) sa = ifma->ifma_lladdr; s = splimp(); LIST_REMOVE(ifma, ifma_link); + /* + * Make sure the interface driver is notified + * in the case of a link layer mcast group being left. + */ + if (ifma->ifma_addr->sa_family == AF_LINK && sa == 0) + dlil_ioctl(0, ifp, SIOCDELMULTI, 0); splx(s); -#if INET6 /* XXX: for IPv6 multicast routers */ - if (ifma->ifma_addr->sa_family == AF_INET6 ) { - struct sockaddr_in6 *sin6; - /* - * An IP6 address of all 0 means stop listening - * to all of Ethernet multicast addresses. - */ - sin6 = (struct sockaddr_in6 *)ifma->ifma_addr; - if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) - ifp->if_flags &= ~IFF_ALLMULTI; - } -#endif /* INET6 */ FREE(ifma->ifma_addr, M_IFMADDR); FREE(ifma, M_IFMADDR); if (sa == 0) @@ -1231,7 +1268,7 @@ if_delmulti(ifp, sa) * in the record for the link-layer address. (So we don't complain * in that case.) */ - for (ifma = ifp->if_multiaddrs.lh_first; ifma; + for (ifma = ifp->if_multiaddrs.lh_first; ifma; ifma = ifma->ifma_link.le_next) if (equal(sa, ifma->ifma_addr)) break; @@ -1254,6 +1291,19 @@ if_delmulti(ifp, sa) return 0; } + +/* + * We don't use if_setlladdr, our interfaces are responsible for + * handling the SIOCSIFLLADDR ioctl. + */ +#ifndef __APPLE__ +int +if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len) +{ + ... +} +#endif + struct ifmultiaddr * ifmaof_ifpforaddr(sa, ifp) struct sockaddr *sa; @@ -1289,3 +1339,61 @@ int if_down_all(void) splx(s); return(0); /* Sheesh */ } + +/* + * Delete Routes for a Network Interface + * + * Called for each routing entry via the rnh->rnh_walktree() call above + * to delete all route entries referencing a detaching network interface. + * + * Arguments: + * rn pointer to node in the routing table + * arg argument passed to rnh->rnh_walktree() - detaching interface + * + * Returns: + * 0 successful + * errno failed - reason indicated + * + */ +static int +if_rtdel(rn, arg) + struct radix_node *rn; + void *arg; +{ + struct rtentry *rt = (struct rtentry *)rn; + struct ifnet *ifp = arg; + int err; + + if (rt != NULL && rt->rt_ifp == ifp) { + + /* + * Protect (sorta) against walktree recursion problems + * with cloned routes + */ + if ((rt->rt_flags & RTF_UP) == 0) + return (0); + + err = rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, + rt_mask(rt), rt->rt_flags, + (struct rtentry **) NULL); + if (err) { + log(LOG_WARNING, "if_rtdel: error %d\n", err); + } + } + + return (0); +} + +/* + * Removes routing table reference to a given interfacei + * for a given protocol family + */ + +void if_rtproto_del(struct ifnet *ifp, int protocol) +{ + + struct radix_node_head *rnh; + + if (((rnh = rt_tables[protocol]) != NULL) && (ifp != NULL)) + (void) rnh->rnh_walktree(rnh, if_rtdel, ifp); +} diff --git a/bsd/net/if.h b/bsd/net/if.h index 50ccff96f..793a9aa88 100644 --- a/bsd/net/if.h +++ b/bsd/net/if.h @@ -52,12 +52,14 @@ * SUCH DAMAGE. * * @(#)if.h 8.1 (Berkeley) 6/10/93 + * $FreeBSD: src/sys/net/if.h,v 1.58.2.2 2001/07/24 19:10:18 brooks Exp $ */ #ifndef _NET_IF_H_ #define _NET_IF_H_ +#include - +#ifdef __APPLE__ /* * Define Data-Link event subclass, and associated * events. @@ -80,14 +82,17 @@ #define KEV_DL_LINK_ON 13 #define KEV_DL_PROTO_ATTACHED 14 #define KEV_DL_PROTO_DETACHED 15 +#endif /* * does not depend on on most other systems. This * helps userland compatability. (struct timeval ifi_lastchange) */ - #include + +#ifdef __APPLE__ #include +#endif #define IFF_UP 0x1 /* interface is up */ @@ -107,13 +112,13 @@ #define IFF_LINK2 0x4000 /* per link layer defined bit */ #define IFF_ALTPHYS IFF_LINK2 /* use alternate physical connection */ #define IFF_MULTICAST 0x8000 /* supports multicast */ -#define IFF_SPLITTER IFF_LINK2 /* Y splitter in force */ -#ifdef KERNEL_PRIVATE +#if KERNEL_PRIVATE /* extended flags definitions: (all bits are reserved for internal/future use) */ #define IFEF_AUTOCONFIGURING 0x1 #define IFEF_DVR_REENTRY_OK 0x20 /* When set, driver may be reentered from its own thread */ -#define IFEF_DETACH_DISABLED 0x80000000 +#define IFEF_INUSE 0x40000000 /* DLIL ifnet recycler, ifnet in use */ +#define IFEF_REUSE 0x20000000 /* DLIL ifnet recycler, ifnet is not new */ #endif KERNEL_PRIVATE @@ -190,7 +195,12 @@ struct ifreq { #define ifr_addr ifr_ifru.ifru_addr /* address */ #define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-to-p link */ #define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ +#ifdef __APPLE__ #define ifr_flags ifr_ifru.ifru_flags /* flags */ +#else +#define ifr_flags ifr_ifru.ifru_flags[0] /* flags */ +#define ifr_prevflags ifr_ifru.ifru_flags[1] /* flags */ +#endif /* __APPLE__ */ #define ifr_metric ifr_ifru.ifru_metric /* metric */ #define ifr_mtu ifr_ifru.ifru_mtu /* mtu */ #define ifr_phys ifr_ifru.ifru_phys /* physical wire */ @@ -224,6 +234,20 @@ struct ifmediareq { int ifm_count; /* # entries in ifm_ulist array */ int *ifm_ulist; /* media words */ }; + +/* + * Structure used to retrieve aux status data from interfaces. + * Kernel suppliers to this interface should respect the formatting + * needed by ifconfig(8): each line starts with a TAB and ends with + * a newline. The canonical example to copy and paste is in if_tun.c. + */ + +#define IFSTATMAX 800 /* 10 lines of text */ +struct ifstat { + char ifs_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + char ascii[IFSTATMAX + 1]; +}; + /* * Structure used in SIOCGIFCONF request. * Used to retrieve interface configuration @@ -240,6 +264,8 @@ struct ifconf { #define ifc_req ifc_ifcu.ifcu_req /* array of structures returned */ }; +#ifdef __APPLE__ +#ifdef __APPLE_API_UNSTABLE /* * DLIL KEV_DL_PROTO_ATTACHED/DETACHED structure */ @@ -248,21 +274,22 @@ struct kev_dl_proto_data { u_long proto_family; u_long proto_remaining_count; }; +#endif /* __APPLE_API_UNSTABLE */ +#endif /* * Structure for SIOC[AGD]LIFADDR */ struct if_laddrreq { - char iflr_name[IFNAMSIZ]; - unsigned int flags; -#define IFLR_PREFIX 0x8000 /* in: prefix given out: kernel fills id */ - unsigned int prefixlen; /* in/out */ - struct sockaddr_storage addr; /* in/out */ - struct sockaddr_storage dstaddr; /* out */ + char iflr_name[IFNAMSIZ]; + u_int flags; +#define IFLR_PREFIX 0x8000 /* in: prefix given out: kernel fills id */ + u_int prefixlen; /* in/out */ + struct sockaddr_storage addr; /* in/out */ + struct sockaddr_storage dstaddr; /* out */ }; - #ifdef KERNEL #ifdef MALLOC_DECLARE MALLOC_DECLARE(M_IFADDR); @@ -271,22 +298,26 @@ MALLOC_DECLARE(M_IFMADDR); #endif #ifndef KERNEL -struct if_nameindex { - unsigned int if_index; /* 1, 2, ... */ - char *if_name; /* null terminated name: "le0", ... */ -}; - +struct if_nameindex { + u_int if_index; /* 1, 2, ... */ + char *if_name; /* null terminated name: "le0", ... */ +}; + __BEGIN_DECLS -unsigned int if_nametoindex __P((const char *)); -char *if_indextoname __P((unsigned int, char *)); -struct if_nameindex *if_nameindex __P((void)); -void if_freenameindex __P((struct if_nameindex *)); +u_int if_nametoindex __P((const char *)); +char *if_indextoname __P((u_int, char *)); +struct if_nameindex *if_nameindex __P((void)); +void if_freenameindex __P((struct if_nameindex *)); __END_DECLS #endif -/* XXX - this should go away soon */ #ifdef KERNEL -#include +#ifndef __APPLE__ +struct proc; + +int prison_if __P((struct proc *p, struct sockaddr *sa)); +#endif + #endif #endif /* !_NET_IF_H_ */ diff --git a/bsd/net/if_arp.h b/bsd/net/if_arp.h index 2c3b44705..af389b6a5 100644 --- a/bsd/net/if_arp.h +++ b/bsd/net/if_arp.h @@ -52,10 +52,13 @@ * SUCH DAMAGE. * * @(#)if_arp.h 8.1 (Berkeley) 6/10/93 + * $FreeBSD: src/sys/net/if_arp.h,v 1.14.2.1 2000/07/11 20:46:55 archie Exp $ */ #ifndef _NET_IF_ARP_H_ #define _NET_IF_ARP_H_ +#include +#include /* * Address Resolution Protocol. @@ -70,6 +73,7 @@ struct arphdr { u_short ar_hrd; /* format of hardware address */ #define ARPHRD_ETHER 1 /* ethernet hardware format */ +#define ARPHRD_IEEE802 6 /* token-ring hardware format */ #define ARPHRD_FRELAY 15 /* frame relay hardware format */ u_short ar_pro; /* format of protocol address */ u_char ar_hln; /* length of hardware address */ @@ -108,7 +112,9 @@ struct arpreq { #define ATF_PUBL 0x08 /* publish entry (respond for other host) */ #define ATF_USETRAILERS 0x10 /* has requested trailers */ +#ifdef __APPLE_API_UNSTABLE +#ifdef __APPLE__ /* * Ethernet multicast address structure. There is one of these for each * multicast address or range of multicast addresses that we are supposed @@ -132,6 +138,7 @@ struct ether_multi { struct ether_multistep { struct ether_multi *e_enm; }; +#endif /* __APPLE__ */ #ifdef KERNEL /* @@ -145,12 +152,18 @@ struct arpcom { */ struct ifnet ac_if; /* network-visible interface */ u_char ac_enaddr[6]; /* ethernet hardware address */ +#ifdef __APPLE__ struct in_addr ac_ipaddr; /* copy of ip address- XXX */ struct ether_multi *ac_multiaddrs; /* list of ether multicast addrs */ +#endif int ac_multicnt; /* length of ac_multiaddrs list */ +#ifndef __APPLE__ + void *ac_netgraph; /* ng_ether(4) netgraph node info */ +#endif }; #endif +#endif /* __APPLE_API_UNSTABLE */ #endif /* !_NET_IF_ARP_H_ */ diff --git a/bsd/net/if_atm.h b/bsd/net/if_atm.h index 2d79db332..b9d1420eb 100644 --- a/bsd/net/if_atm.h +++ b/bsd/net/if_atm.h @@ -20,6 +20,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* $NetBSD: if_atm.h,v 1.7 1996/11/09 23:02:27 chuck Exp $ */ +/* $FreeBSD: src/sys/net/if_atm.h,v 1.4 1999/12/29 04:38:34 peter Exp $ */ /* * @@ -57,21 +58,15 @@ * net/if_atm.h */ - -#ifndef NO_ATM_PVCEXT -/* - * ATM_PVCEXT enables PVC extention: VP/VC shaping - * and PVC shadow interfaces. - */ -#define ATM_PVCEXT /* enable pvc extention */ -#endif - #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) #define RTALLOC1(A,B) rtalloc1((A),(B)) -#elif defined(__FreeBSD__) +#elif defined(__FreeBSD__) || defined(__APPLE__) #define RTALLOC1(A,B) rtalloc1((A),(B),0UL) #endif +#warning if_atm.h is not used by the darwin kernel + + /* * pseudo header for packet transmission */ @@ -90,9 +85,6 @@ struct atm_pseudohdr { #define ATM_PH_AAL5 0x01 /* use AAL5? (0 == aal0) */ #define ATM_PH_LLCSNAP 0x02 /* use the LLC SNAP encoding (iff aal5) */ -#if ATM_PVCEXT -#define ATM_PH_INERNAL 0x20 /* reserve for kernel internal use */ -#endif #define ATM_PH_DRIVER7 0x40 /* reserve for driver's use */ #define ATM_PH_DRIVER8 0x80 /* reserve for driver's use */ @@ -111,28 +103,6 @@ struct atm_pseudoioctl { #define SIOCATMENA _IOWR('a', 123, struct atm_pseudoioctl) /* enable */ #define SIOCATMDIS _IOWR('a', 124, struct atm_pseudoioctl) /* disable */ -#if ATM_PVCEXT - -/* structure to control PVC transmitter */ -struct pvctxreq { - /* first entry must be compatible with struct ifreq */ - char pvc_ifname[IFNAMSIZ]; /* if name, e.g. "en0" */ - struct atm_pseudohdr pvc_aph; /* (flags) + vpi:vci */ - struct atm_pseudohdr pvc_joint; /* for vp shaping: another vc - to share the shaper */ - int pvc_pcr; /* peak cell rate (shaper value) */ -}; - -/* use ifioctl for now */ -#define SIOCSPVCTX _IOWR('i', 95, struct pvctxreq) -#define SIOCGPVCTX _IOWR('i', 96, struct pvctxreq) -#define SIOCSPVCSIF _IOWR('i', 97, struct ifreq) -#define SIOCGPVCSIF _IOWR('i', 98, struct ifreq) - -#ifdef KERNEL -#define ATM_PH_PVCSIF ATM_PH_INERNAL /* pvc shadow interface */ -#endif -#endif /* ATM_PVCEXT */ /* * XXX forget all the garbage in if_llc.h and do it the easy way @@ -152,16 +122,12 @@ struct atmllc { } #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE void atm_ifattach __P((struct ifnet *)); void atm_input __P((struct ifnet *, struct atm_pseudohdr *, struct mbuf *, void *)); int atm_output __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *)); +#endif /* __APPLE_API_PRIVATE */ #endif -#if ATM_PVCEXT -char *shadow2if __P((char *)); -#ifdef KERNEL -struct ifnet *pvc_attach __P((struct ifnet *)); -int pvc_setaph __P((struct ifnet *, struct atm_pseudohdr *)); -#endif -#endif + diff --git a/bsd/net/if_atmsubr.c b/bsd/net/if_atmsubr.c deleted file mode 100644 index eb7bdb7f5..000000000 --- a/bsd/net/if_atmsubr.c +++ /dev/null @@ -1,652 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* $NetBSD: if_atmsubr.c,v 1.10 1997/03/11 23:19:51 chuck Exp $ */ - -/* - * - * Copyright (c) 1996 Charles D. Cranor and Washington University. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Charles D. Cranor and - * Washington University. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (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_atmsubr.c - */ - -#include "opt_inet.h" -#include "opt_natm.h" - -#include -#include -#include -#include -#include -#include -#include - - -#include -#include -#include -#include -#include -#include - -#include -#include -#include /* XXX: for ETHERTYPE_* */ -#if defined(INET) || defined(INET6) -#include -#endif -#if NATM -#include -#endif - -#ifndef ETHERTYPE_IPV6 -#define ETHERTYPE_IPV6 0x86dd -#endif - -#define senderr(e) { error = (e); goto bad;} - -/* - * atm_output: ATM output routine - * inputs: - * "ifp" = ATM interface to output to - * "m0" = the packet to output - * "dst" = the sockaddr to send to (either IP addr, or raw VPI/VCI) - * "rt0" = the route to use - * returns: error code [0 == ok] - * - * note: special semantic: if (dst == NULL) then we assume "m" already - * has an atm_pseudohdr on it and just send it directly. - * [for native mode ATM output] if dst is null, then - * rt0 must also be NULL. - */ - -int -atm_output(ifp, m0, dst, rt0) - register struct ifnet *ifp; - struct mbuf *m0; - struct sockaddr *dst; - struct rtentry *rt0; -{ - u_int16_t etype = 0; /* if using LLC/SNAP */ - int s, error = 0, sz; - struct atm_pseudohdr atmdst, *ad; - register struct mbuf *m = m0; - register struct rtentry *rt; - struct atmllc *atmllc; - struct atmllc *llc_hdr = NULL; - u_int32_t atm_flags; - - if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) - senderr(ENETDOWN); - - /* - * check route - */ - if ((rt = rt0) != NULL) { - - if ((rt->rt_flags & RTF_UP) == 0) { /* route went down! */ - if ((rt0 = rt = RTALLOC1(dst, 0)) != NULL) - rt->rt_refcnt--; - else - senderr(EHOSTUNREACH); - } - - if (rt->rt_flags & RTF_GATEWAY) { - if (rt->rt_gwroute == 0) - goto lookup; - if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { - rtfree(rt); rt = rt0; - lookup: rt->rt_gwroute = RTALLOC1(rt->rt_gateway, 0); - if ((rt = rt->rt_gwroute) == 0) - senderr(EHOSTUNREACH); - } - } - - /* XXX: put RTF_REJECT code here if doing ATMARP */ - - } - - /* - * check for non-native ATM traffic (dst != NULL) - */ - if (dst) { - switch (dst->sa_family) { -#if defined(INET) || defined(INET6) - case AF_INET: - case AF_INET6: - if (!atmresolve(rt, m, dst, &atmdst)) { - m = NULL; - /* XXX: atmresolve already free'd it */ - senderr(EHOSTUNREACH); - /* XXX: put ATMARP stuff here */ - /* XXX: watch who frees m on failure */ - } - if (dst->sa_family == AF_INET6) - etype = htons(ETHERTYPE_IPV6); - else - etype = htons(ETHERTYPE_IP); - break; -#endif /* INET || INET6 */ - - case AF_UNSPEC: - /* - * XXX: bpfwrite or output from a pvc shadow if. - * assuming dst contains 12 bytes (atm pseudo - * header (4) + LLC/SNAP (8)) - */ - bcopy(dst->sa_data, &atmdst, sizeof(atmdst)); - llc_hdr = (struct atmllc *)(dst->sa_data + sizeof(atmdst)); - break; - - default: -#if defined(__NetBSD__) || defined(__OpenBSD__) - printf("%s: can't handle af%d\n", ifp->if_xname, - dst->sa_family); -#elif defined(__FreeBSD__) || defined(__bsdi__) - printf("%s%d: can't handle af%d\n", ifp->if_name, - ifp->if_unit, dst->sa_family); -#endif - senderr(EAFNOSUPPORT); - } - - /* - * must add atm_pseudohdr to data - */ - sz = sizeof(atmdst); - atm_flags = ATM_PH_FLAGS(&atmdst); - if (atm_flags & ATM_PH_LLCSNAP) sz += 8; /* sizeof snap == 8 */ - M_PREPEND(m, sz, M_DONTWAIT); - if (m == 0) - senderr(ENOBUFS); - ad = mtod(m, struct atm_pseudohdr *); - *ad = atmdst; - if (atm_flags & ATM_PH_LLCSNAP) { - atmllc = (struct atmllc *)(ad + 1); - if (llc_hdr == NULL) { - bcopy(ATMLLC_HDR, atmllc->llchdr, - sizeof(atmllc->llchdr)); - ATM_LLC_SETTYPE(atmllc, etype); - /* note: already in network order */ - } - else - bcopy(llc_hdr, atmllc, sizeof(struct atmllc)); - } - } - - /* - * Queue message on interface, and start output if interface - * not yet active. - */ - s = splimp(); - if (IF_QFULL(&ifp->if_snd)) { - IF_DROP(&ifp->if_snd); - splx(s); - senderr(ENOBUFS); - } - ifp->if_obytes += m->m_pkthdr.len; - IF_ENQUEUE(&ifp->if_snd, m); - if ((ifp->if_flags & IFF_OACTIVE) == 0) - (*ifp->if_start)(ifp); - splx(s); - return (error); - -bad: - if (m) - m_freem(m); - return (error); -} - -/* - * Process a received ATM packet; - * the packet is in the mbuf chain m. - */ -void -atm_input(ifp, ah, m, rxhand) - struct ifnet *ifp; - register struct atm_pseudohdr *ah; - struct mbuf *m; - void *rxhand; -{ - register struct ifqueue *inq; - u_int16_t etype = ETHERTYPE_IP; /* default */ - int s; - - if ((ifp->if_flags & IFF_UP) == 0) { - m_freem(m); - return; - } - ifp->if_ibytes += m->m_pkthdr.len; - -#if ATM_PVCEXT - if (ATM_PH_FLAGS(ah) & ATM_PH_PVCSIF) { - /* - * when PVC shadow interface is used, pointer to - * the shadow interface is passed as rxhand. - * override the receive interface of the packet. - */ - m->m_pkthdr.rcvif = (struct ifnet *)rxhand; - rxhand = NULL; - } -#endif /* ATM_PVCEXT */ - - if (rxhand) { -#if NATM - struct natmpcb *npcb = rxhand; - s = splimp(); /* in case 2 atm cards @ diff lvls */ - npcb->npcb_inq++; /* count # in queue */ - splx(s); - schednetisr(NETISR_NATM); - inq = &natmintrq; - m->m_pkthdr.rcvif = rxhand; /* XXX: overload */ -#else - printf("atm_input: NATM detected but not configured in kernel\n"); - m_freem(m); - return; -#endif - } else { - /* - * handle LLC/SNAP header, if present - */ - if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) { - struct atmllc *alc; - if (m->m_len < sizeof(*alc) && - (m = m_pullup(m, sizeof(*alc))) == 0) - return; /* failed */ - alc = mtod(m, struct atmllc *); - if (bcmp(alc, ATMLLC_HDR, 6)) { -#if defined(__NetBSD__) || defined(__OpenBSD__) - printf("%s: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n", - ifp->if_xname, ATM_PH_VPI(ah), ATM_PH_VCI(ah)); -#elif defined(__FreeBSD__) || defined(__bsdi__) - printf("%s%d: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n", - ifp->if_name, ifp->if_unit, ATM_PH_VPI(ah), ATM_PH_VCI(ah)); -#endif - m_freem(m); - return; - } - etype = ATM_LLC_TYPE(alc); - m_adj(m, sizeof(*alc)); - } - - switch (etype) { -#if INET - case ETHERTYPE_IP: - schednetisr(NETISR_IP); - inq = &ipintrq; - break; -#endif -#if INET6 - case ETHERTYPE_IPV6: - schednetisr(NETISR_IPV6); - inq = &ip6intrq; - break; -#endif - default: - m_freem(m); - return; - } - } - - s = splimp(); - if (IF_QFULL(inq)) { - IF_DROP(inq); - m_freem(m); - } else - IF_ENQUEUE(inq, m); - splx(s); -} - -/* - * Perform common duties while attaching to interface list - */ -void -atm_ifattach(ifp) - register struct ifnet *ifp; -{ - register struct ifaddr *ifa; - register struct sockaddr_dl *sdl; - - ifp->if_type = IFT_ATM; - ifp->if_addrlen = 0; - ifp->if_hdrlen = 0; - ifp->if_mtu = ATMMTU; - ifp->if_output = atm_output; - -#if defined(__NetBSD__) || defined(__OpenBSD__) - for (ifa = ifp->if_addrlist.tqh_first; ifa != 0; - ifa = ifa->ifa_list.tqe_next) -#elif defined(__FreeBSD__) && (__FreeBSD__ > 2) - for (ifa = ifp->if_addrhead.tqh_first; ifa; - ifa = ifa->ifa_link.tqe_next) -#elif defined(__FreeBSD__) || defined(__bsdi__) - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) -#endif - if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) && - sdl->sdl_family == AF_LINK) { - sdl->sdl_type = IFT_ATM; - sdl->sdl_alen = ifp->if_addrlen; -#ifdef notyet /* if using ATMARP, store hardware address using the next line */ - bcopy(ifp->hw_addr, LLADDR(sdl), ifp->if_addrlen); -#endif - break; - } - -} - -#if ATM_PVCEXT -/* - * ATM PVC shadow interface: a trick to assign a shadow interface - * to a PVC. - * with shadow interface, each PVC looks like an individual - * Point-to-Point interface. - * as oposed to the NBMA model, a shadow interface is inherently - * multicast capable (no LANE/MARS required). - */ -struct pvcsif { - struct ifnet sif_shadow; /* shadow ifnet structure per pvc */ - struct atm_pseudohdr sif_aph; /* flags + vpi:vci */ - struct ifnet *sif_ifp; /* pointer to the genuine interface */ -}; - -static int pvc_output __P((struct ifnet *, struct mbuf *, - struct sockaddr *, struct rtentry *)); -static int pvc_ioctl __P((struct ifnet *, u_long, caddr_t)); - -/* - * create and attach per pvc shadow interface - * (currently detach is not supported) - */ -static int pvc_number = 0; - -struct ifnet * -pvc_attach(ifp) - struct ifnet *ifp; -{ - struct pvcsif *pvcsif; - struct ifnet *shadow; - struct ifaddr *ifa; - struct sockaddr_dl *sdl; - int s; - - MALLOC(pvcsif, struct pvcsif *, sizeof(struct pvcsif), - M_DEVBUF, M_WAITOK); - bzero(pvcsif, sizeof(struct pvcsif)); - - pvcsif->sif_ifp = ifp; - shadow = &pvcsif->sif_shadow; - - shadow->if_name = "pvc"; - shadow->if_family = APPLE_IF_FAM_PVC; - shadow->if_unit = pvc_number++; - shadow->if_flags = ifp->if_flags | (IFF_POINTOPOINT | IFF_MULTICAST); - shadow->if_ioctl = pvc_ioctl; - shadow->if_output = pvc_output; - shadow->if_start = NULL; - shadow->if_mtu = ifp->if_mtu; - shadow->if_type = ifp->if_type; - shadow->if_addrlen = ifp->if_addrlen; - shadow->if_hdrlen = ifp->if_hdrlen; - shadow->if_softc = pvcsif; - shadow->if_snd.ifq_maxlen = 50; /* dummy */ - - s = splimp(); - if_attach(shadow); - -#if defined(__NetBSD__) || defined(__OpenBSD__) - for (ifa = shadow->if_addrlist.tqh_first; ifa != 0; - ifa = ifa->ifa_list.tqe_next) -#elif defined(__FreeBSD__) && (__FreeBSD__ > 2) - for (ifa = shadow->if_addrhead.tqh_first; ifa; - ifa = ifa->ifa_link.tqe_next) -#elif defined(__FreeBSD__) || defined(__bsdi__) - for (ifa = shadow->if_addrlist; ifa; ifa = ifa->ifa_next) -#endif - if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) && - sdl->sdl_family == AF_LINK) { - sdl->sdl_type = IFT_ATM; - sdl->sdl_alen = shadow->if_addrlen; - break; - } - splx(s); - - return (shadow); -} - -/* - * pvc_output relays the packet to atm_output along with vpi:vci info. - */ -static int -pvc_output(shadow, m, dst, rt) - struct ifnet *shadow; - struct mbuf *m; - struct sockaddr *dst; - struct rtentry *rt; -{ - struct pvcsif *pvcsif; - struct sockaddr dst_addr; - struct atmllc *atmllc; - u_int16_t etype = 0; - int error = 0; - - if ((shadow->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) - senderr(ENETDOWN); - - pvcsif = shadow->if_softc; - if (ATM_PH_VCI(&pvcsif->sif_aph) == 0) - senderr(ENETDOWN); - - /* - * create a dummy sockaddr: (using bpfwrite interface) - * put atm pseudo header and llc/snap into sa_data (12 bytes) - * and mark it as AF_UNSPEC. - */ - if (dst) { - switch (dst->sa_family) { -#if defined(INET) || defined(INET6) - case AF_INET: - case AF_INET6: - if (dst->sa_family == AF_INET6) - etype = htons(ETHERTYPE_IPV6); - else - etype = htons(ETHERTYPE_IP); - break; -#endif - - default: - printf("%s%d: can't handle af%d\n", shadow->if_name, - shadow->if_unit, dst->sa_family); - senderr(EAFNOSUPPORT); - } - } - - dst_addr.sa_family = AF_UNSPEC; - bcopy(&pvcsif->sif_aph, dst_addr.sa_data, - sizeof(struct atm_pseudohdr)); - atmllc = (struct atmllc *) - (dst_addr.sa_data + sizeof(struct atm_pseudohdr)); - bcopy(ATMLLC_HDR, atmllc->llchdr, sizeof(atmllc->llchdr)); - ATM_LLC_SETTYPE(atmllc, etype); /* note: already in network order */ - - return atm_output(pvcsif->sif_ifp, m, &dst_addr, rt); - -bad: - if (m) - m_freem(m); - return (error); -} - -static int -pvc_ioctl(shadow, cmd, data) - struct ifnet *shadow; - u_long cmd; - caddr_t data; -{ - struct ifnet *ifp; - struct pvcsif *pvcsif; - struct ifreq *ifr = (struct ifreq *) data; - void (*ifa_rtrequest)(int, struct rtentry *, struct sockaddr *) = NULL; - int error = 0; - - pvcsif = (struct pvcsif *)shadow->if_softc; - ifp = pvcsif->sif_ifp; - if (ifp == 0 || ifp->if_ioctl == 0) - return (EOPNOTSUPP); - - /* - * pre process - */ - switch (cmd) { - case SIOCGPVCSIF: - snprintf(ifr->ifr_name, sizeof(ifr->ifr_name), - "%s%d", ifp->if_name, ifp->if_unit); - return (0); - - case SIOCGPVCTX: - do { - struct pvctxreq *pvcreq = (struct pvctxreq *)data; - - snprintf(pvcreq->pvc_ifname, - sizeof(pvcreq->pvc_ifname), "%s%d", - ifp->if_name, ifp->if_unit); - pvcreq->pvc_aph = pvcsif->sif_aph; - } while (0); - break; - - case SIOCADDMULTI: - case SIOCDELMULTI: - if (ifr == 0) - return (EAFNOSUPPORT); /* XXX */ - switch (ifr->ifr_addr.sa_family) { -#if INET - case AF_INET: - return (0); -#endif -#if INET6 - case AF_INET6: - return (0); -#endif - default: - return (EAFNOSUPPORT); - } - break; - case SIOCSIFADDR: - if (ifp->if_flags & IFF_UP) { - /* real if is already up */ - shadow->if_flags = ifp->if_flags | - (IFF_POINTOPOINT|IFF_MULTICAST); - return (0); - } - /* - * XXX: save the rtrequest field since the atm driver - * overwrites this field. - */ - ifa_rtrequest = ((struct ifaddr *)data)->ifa_rtrequest; - break; - - case SIOCSIFFLAGS: - if ((shadow->if_flags & IFF_UP) == 0) { - /* - * interface down. don't pass this to - * the real interface. - */ - return (0); - } - if (shadow->if_flags & IFF_UP) { - /* - * interface up. if the real if is already up, - * nothing to do. - */ - if (ifp->if_flags & IFF_UP) { - shadow->if_flags = ifp->if_flags | - (IFF_POINTOPOINT|IFF_MULTICAST); - return (0); - } - } - break; - } - - /* - * pass the ioctl to the genuine interface - */ - error = (*ifp->if_ioctl)(ifp, cmd, data); - - /* - * post process - */ - switch (cmd) { - case SIOCSIFMTU: - shadow->if_mtu = ifp->if_mtu; - break; - case SIOCSIFADDR: - /* restore rtrequest */ - ((struct ifaddr *)data)->ifa_rtrequest = ifa_rtrequest; - /* fall into... */ - case SIOCSIFFLAGS: - /* update if_flags */ - shadow->if_flags = ifp->if_flags - | (IFF_POINTOPOINT|IFF_MULTICAST); - break; - } - - return (error); -} - -int pvc_setaph(shadow, aph) - struct ifnet *shadow; - struct atm_pseudohdr *aph; -{ - struct pvcsif *pvcsif; - - pvcsif = shadow->if_softc; - bcopy(aph, &pvcsif->sif_aph, sizeof(struct atm_pseudohdr)); - return (0); -} - -#endif /* ATM_PVCEXT */ diff --git a/bsd/net/if_blue.c b/bsd/net/if_blue.c deleted file mode 100644 index 55458ec4b..000000000 --- a/bsd/net/if_blue.c +++ /dev/null @@ -1,677 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* Copyright (c) 1997, 1998 Apple Computer, Inc. All Rights Reserved */ -/* - * @(#)if_blue.c 1.1 (MacOSX) 6/10/43 - * Justin Walker, 9970520 - * First wave - splitter and notification support for the Blue Box - * 980130 - Second wave - Performance improvements, reorg and cleanup - */ - -#include -#if KDEBUG - -#define DBG_SPLT_BFCHK DRVDBG_CODE(DBG_DRVSPLT, 0) -#define DBG_SPLT_APPND DRVDBG_CODE(DBG_DRVSPLT, 1) -#define DBG_SPLT_MBUF DRVDBG_CODE(DBG_DRVSPLT, 2) -#define DBG_SPLT_DUP DRVDBG_CODE(DBG_DRVSPLT, 3) -#define DBG_SPLT_PAD DRVDBG_CODE(DBG_DRVSPLT, 4) - -#endif - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include "if_blue.h" -#include "ndrv.h" - -#if INET -#include -#include -#endif -#include - -#if NS -#include -#include -#endif - -#if ISO -#include -#include -#include -#include -#endif - -#if LLC -#include -#include -#endif - -#include -#include -#include -#include - -/* Dummy IFs to differentiate source of looped packets */ -struct ifnet rhap_if_s; -struct ifnet *rhap_if = &rhap_if_s; -struct ifnet_blue *blue_if; -struct sockaddr_dl ndrvsrc = {sizeof (struct sockaddr_dl), AF_NDRV}; - -struct ifqueue blueq; - -extern int if_register(register struct BlueFilter *f -#ifdef BF_if - , - register struct ifnet *ifp -#endif - ); - -/* - * Blue Box support: - * 1st cut: the Y splitter - * A process turns on the splitter by opening the "raw" device - * (socket() for AF_NDRV) and issuing an SIOCSSPLITTER ioctl. - * Incoming packets are routed into MacOSX as well as to the requesting - * interface. - * Outbound packets are sent, and are examined to see if they should go - * back up (loopback, sort of). Packets that are looped back include: - * broadcast - * multicast - */ -int -new_splitter(register struct socket *so) -{ register struct ifnet_blue *ifb; - register struct ndrv_cb *np; - register struct ifnet *ifp; - struct BlueFilter filter; - int retval; - - if ((ifb = _MALLOC(sizeof (struct ifnet_blue), M_PCB, M_WAITOK)) - == NULL) - { -#if BLUE_DEBUG - kprintf("Can't create new splitter\n"); -#endif - return(ENOBUFS); - } - bzero(ifb, sizeof(struct ifnet_blue)); - np = (struct ndrv_cb *)so->so_pcb; -#if BLUE_DEBUG - kprintf("NEW SPLT: %x, %x\n", so, np); - if (np) - printf("SIG: %x, ifp: %x\n", np->nd_signature, np->nd_if); -#endif - if (np == NULL) - return(EINVAL); /* XXX */ - if (np->nd_signature != NDRV_SIGNATURE) - return(EINVAL); /* XXX */ - if ((ifp = np->nd_if) == NULL) - return(EINVAL); /* XXX */ - if (ifp->if_flags & IFF_SPLITTER) - return(EBUSY); - if ((ifp->if_flags&IFF_UP) == 0) - return(ENXIO); - /* - * Bump the receive sockbuf size - need a big buffer - * to offset the scheduling latencies of the system - * Try to get something if our grandiose design fails. - */ - if (sbreserve(&so->so_rcv, 131072) == 0) - { if (sbreserve(&so->so_rcv, 65536) == 0 && - sbreserve(&so->so_rcv, 32768) == 0 && - sbreserve(&so->so_rcv, 16384) == 0) - return(ENOBUFS); - } - ifp->if_flags |= IFF_SPLITTER; - /* - * Register each IP address associated with this ifnet - * This takes care of addresses registered prior to startup - * of the BlueBox. - * TODO: Appletalk sockaddrs - */ -#define IFA2IN(ifa) \ - ((struct in_addr) \ - ((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr).s_addr - { struct ifaddr *ifa; - - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) - { if (ifa->ifa_addr->sa_family == AF_INET) - { filter.BF_flags = (BF_ALLOC|BF_IP); - filter.BF_address = IFA2IN(ifa); -#if BLUE_DEBUG - kprintf("[1] IP registering [%x] %x\n", - filter.BF_flags, - (unsigned int)filter.BF_address); -#endif - retval = if_register(&filter); -#if BLUE_DEBUG - if (retval) - kprintf("if_register(IP) returns %d\n", - retval); -#endif - } - } - } - - blue_if = (struct ifnet_blue *)ifb; - ifb->blue_pid = ((struct proc *)current_proc())->p_pid; - ifb->ifb_so = so; - ifp->if_Y = (void *)ifb; - return(0); -} - -/* - * Determine if destined for BlueBox or not. Called from ether_output() - * and ether_input(). - * Returns NULL if we ate the packet, otherwise, the mbuf to continue with. - */ -struct mbuf * -splitter_input(register struct mbuf *m, register struct ifnet *ifp) -{ register struct ifnet_blue *ifb; -#if 0 - register int s, flags; -#else - register int flags; -#endif - int rv; - register struct mbuf *m0 = NULL; - struct mbuf *m1; - extern struct mbuf *m_dup(struct mbuf *, int); - extern int BlueFilter_check(struct mbuf **, struct ifnet_blue *); - extern void blue_notify(struct mbuf *); - extern int blue_notify1(struct mbuf *); - - if ((ifb = (struct ifnet_blue *)ifp->if_Y) == NULL) - { ifp->if_flags &= ~IFF_SPLITTER; - return(m); - } - flags = m->m_flags; - m1 = m; - /* Check filters */ - if ((rv = BlueFilter_check(&m1, ifb)) == -1) - return(m1); /* Not for BB, MacOSX will want to see it. */ - m = m1; - if (rv == 0) /* It's for both - dup the packet */ - { m0 = m_dup(m, M_DONTWAIT); - if (m0 == NULL) - { blue_if->no_bufs1++; - return(m); /* Give it to MacOSX */ - } - } else - { /* Oy, veh! The depths to which we stoop! */ - /* We'll just assume M_PKTHDR is set */ - if (m->m_next == 0 && (m->m_flags & M_EXT) - && m->m_pkthdr.len <= MHLEN) - { m0 = m_dup(m, M_DONTWAIT); - if (m0) - { m_freem(m); - m = NULL; - } else - m0 = m; - } else - m0 = m; - } - if (flags & 0x10) - blue_if->pkts_looped_r2b++; - -#if 0 - schednetisr(NETISR_BLUE); - s = splimp(); - if (IF_QFULL(&blueq)) { - IF_DROP(&blueq); - m_freem(m0); - } else - IF_ENQUEUE(&blueq, m0); - splx(s); -#else - blue_notify1(m0); - sorwakeup(blue_if->ifb_so); - blue_if->sig_sent++; -#endif - /* If we eat the packet (rv==1) return NULL */ - return(rv == 0 ? m : NULL); -} - -void -blue_notify() -{ register int do_notify = 0; - register int s; - register struct mbuf *m; - extern int blue_notify1(struct mbuf *); - - /* - * Move the packets from the blue queue to the indicated socket - * If we haven't told anyone yet, send a signal. - */ - for (;;) - { s = splimp(); - IF_DEQUEUE(&blueq, m); - splx(s); - if (m == 0) - break; - - do_notify = blue_notify1(m); - } - if (do_notify) - sorwakeup(blue_if->ifb_so); /* Start by using SIGIO */ -} - -int -blue_notify1(register struct mbuf *m) -{ register int rv; - - /* move packet from if queue to socket */ - /* !!!Fix this to work generically!!! */ - ndrvsrc.sdl_type = IFT_ETHER; - ndrvsrc.sdl_nlen = 0; - ndrvsrc.sdl_alen = 6; - ndrvsrc.sdl_slen = 0; - bcopy(m->m_data+6, &ndrvsrc.sdl_data, 6); - - if (sbappendaddr(&(blue_if->ifb_so->so_rcv), - (struct sockaddr *)&ndrvsrc, m, - (struct mbuf *)0) == 0) - { register struct mbuf *n; - - KERNEL_DEBUG(DBG_SPLT_APPND | DBG_FUNC_NONE, - blue_if->ifb_so->so_rcv.sb_cc, - blue_if->ifb_so->so_rcv.sb_hiwat, - blue_if->ifb_so->so_rcv.sb_mbcnt, - blue_if->ifb_so->so_rcv.sb_mbmax, - blue_if->ifb_so->so_rcv.sb_lowat ); - if (m->m_flags & M_PKTHDR) - KERNEL_DEBUG(DBG_SPLT_MBUF, 0, m->m_pkthdr.len, - m->m_flags, 0, 0); - for (n = m; n; n = n->m_next) - KERNEL_DEBUG(DBG_SPLT_MBUF, 1, - (int)n, (int)n->m_next, n->m_len, - n->m_flags); - m_freem(m); - blue_if->full_sockbuf++; - rv = 1; - } else - { register struct mbuf *n; - - KERNEL_DEBUG(DBG_SPLT_APPND | DBG_FUNC_NONE, - blue_if->ifb_so->so_rcv.sb_cc, - blue_if->ifb_so->so_rcv.sb_hiwat, - blue_if->ifb_so->so_rcv.sb_mbcnt, - blue_if->ifb_so->so_rcv.sb_mbmax, - blue_if->ifb_so->so_rcv.sb_lowat ); - if (m->m_flags & M_PKTHDR) - KERNEL_DEBUG(DBG_SPLT_MBUF, 2, m->m_pkthdr.len, - m->m_flags, 0, 0); - for (n = m; n; n = n->m_next) - KERNEL_DEBUG(DBG_SPLT_MBUF, 3, - (int)n, (int)n->m_next, n->m_len, - n->m_flags); - blue_if->pkts_up++; - rv = 0; - } - return(rv); -} - -/* - * Check the incoming packet against the registered filters - * Rules (the rules are subtly different for input to the - * y-adapter customer and the "real" stacks): - * For BB: return 1 - * For Both: return 0 - * Not For BB: return -1 - * Multicast/Broadcast => For Both - * Hack: - * if no registered filters, For Both - * Atalk filter registered - * filter matches => For BB else Not For BB - * IP filter registered - * filter matches => For BB else Not For BB - * Not For BB - * WARNING: this is a big-endian routine. - * WARNING 2: m_pullup can give you a new mbuf! - */ -int -BlueFilter_check(struct mbuf **m0, register struct ifnet_blue *ifb) -{ register struct BlueFilter *bf; - register unsigned char *p; - register unsigned short *s; - register unsigned long *l; - int total, flags; - register struct mbuf *m; - extern struct mbuf *m_pullup(struct mbuf *, int); -#define FILTER_LEN 32 - - KERNEL_DEBUG(DBG_SPLT_BFCHK | DBG_FUNC_START, 0, 0, 0, 0, 0 ); - - m = *m0; - if (FILTER_LEN > m->m_pkthdr.len) - { KERNEL_DEBUG(DBG_SPLT_BFCHK | DBG_FUNC_END, 0, 0, 0, 0, 0 ); - return(-1); - } - flags = m->m_flags; - while ((FILTER_LEN > m->m_len) && m->m_next) { - total = m->m_len + (m->m_next)->m_len; - if ((m = m_pullup(m, min(FILTER_LEN, total))) == 0) - { KERNEL_DEBUG(DBG_SPLT_BFCHK | DBG_FUNC_END, 1, flags, total, 0, 0); - return(-1); - } - } - *m0 = m; /* Update, just in case */ - - p = mtod(m, unsigned char *); /* Point to destination media addr */ - if (p[0] & 0x01) /* Multicast/broadcast */ - { KERNEL_DEBUG(DBG_SPLT_BFCHK | DBG_FUNC_END, 2, 0, 0, 0, 0 ); - return(0); - } - s = (unsigned short *)p; - bf = &ifb->filter[BFS_ATALK]; - if (!bf->BF_flags && !bf[1].BF_flags) /* Hack for Developer Release Blue Box */ - { KERNEL_DEBUG(DBG_SPLT_BFCHK | DBG_FUNC_END, 3, 0, 0, 0, 0 ); - return(0); - } -#if BLUE_DEBUG - kprintf("PKT: %x, %x, %x\n", s[6], s[7], s[8]); -#endif - if (bf->BF_flags) /* Filtering Appletalk */ - { l = (unsigned long *)&s[8]; -#if BLUE_DEBUG - kprintf("AT: %x, %x, %x, %x, %x, %x\n", s[6], s[7], - *l, s[10], s[13], p[30]); -#endif - if (s[6] <= ETHERMTU) - { if (s[7] == 0xaaaa) /* Could be Atalk */ - { /* Verify SNAP header */ - if (*l == 0x03080007 && s[10] == 0x809b) - { if ((bf->BF_flags&BF_VALID) == 0 || - (s[13] == bf->BF_address && - p[30] == bf->BF_node)) - { KERNEL_DEBUG(DBG_SPLT_BFCHK | DBG_FUNC_END, 4, - s[13], p[30], 0, 0 ); - return(1); - } - } else if (*l == 0x03000000 && s[10] == 0x80f3) - /* AARP pkts aren't net-addressed */ - { KERNEL_DEBUG(DBG_SPLT_BFCHK | DBG_FUNC_END, 5, 0, 0, 0, 0 ); - return(0); - } - /* Not for us */ - KERNEL_DEBUG(DBG_SPLT_BFCHK | DBG_FUNC_END, 6, s[13], p[30], 0, 0 ); - return(-1); - } else /* Not for us? */ - { KERNEL_DEBUG(DBG_SPLT_BFCHK | DBG_FUNC_END, 7, s[7], 0, 0, 0 ); - return(-1); - } - } /* Fall through */ - } /* Fall through */ - bf++; /* Look for IP next */ - if (bf->BF_flags) /* Filtering IP */ - { - l = (unsigned long *)&s[15]; -#if BLUE_DEBUG - kprintf("IP: %x, %x\n", s[6], *l); -#endif - if (s[6] > ETHERMTU) - { if (s[6] == 0x800) /* Is IP */ - { /* Verify IP address */ - if ((bf->BF_flags&BF_VALID) == 0 || - *l == bf->BF_address) - { KERNEL_DEBUG(DBG_SPLT_BFCHK | DBG_FUNC_END, 8, *l, 0, 0, 0 ); - return(1); - } else /* Not for us */ - { KERNEL_DEBUG(DBG_SPLT_BFCHK | DBG_FUNC_END, 9, *l, 0, 0, 0 ); - return(-1); - } - } else if (s[6] == 0x806) - { /* ARP pkts aren't net-addressed */ - KERNEL_DEBUG(DBG_SPLT_BFCHK | DBG_FUNC_END, 10, 0, 0, 0, 0 ); - return(0); - } - } - } - KERNEL_DEBUG(DBG_SPLT_BFCHK | DBG_FUNC_END, 11, s[6], 0, 0, 0 ); - return(-1); -} - -int -splitter_ctl(register struct socket *so, register int cmd, - register caddr_t data, register struct ifnet *ifp) -{ register struct ndrv_cb *np = sotondrvcb(so); - register struct ifnet_blue *ifb; - register struct BlueFilter *bf = (struct BlueFilter *)data, *bf1; - u_long at_dl_tag; - - - if ((ifb = np->nd_if->if_Y) == NULL) - return(ENXIO); - - if (cmd == SIOCSSPLTFILT) - { -#if BLUE_DEBUG -kprintf("Filter: %s, %x, %x, %x\n", bf->ifr_name, bf->BF_flags, bf->BF_address, - bf->BF_node); -#endif - if (bf->BF_flags & BF_ATALK) - bf1 = &ifb->filter[BFS_ATALK]; - else if (bf->BF_flags & BF_IP) - bf1 = &ifb->filter[BFS_IP]; - else - return(EINVAL); - if (bf->BF_flags&BF_ALLOC) - { if ((bf1->BF_flags&(BF_ALLOC|BF_VALID)) == - (BF_ALLOC|BF_VALID)) - return(EBUSY); - *bf1 = *bf; - bf1->BF_flags |= BF_VALID; - } else if (bf->BF_flags&BF_DEALLOC) - { if (bf1->BF_flags&BF_ALLOC) - bf1->BF_flags = 0; - else - return(EINVAL); - } - /* Register AppleTalk Tags if not registered */ - - ether_attach_at(ifp, &at_dl_tag, - &at_dl_tag); - - - } else if (cmd == SIOCZSPLTSTAT) - { ifb->pkts_up = 0; - ifb->pkts_out = 0; - ifb->pkts_looped_r2b = 0; - ifb->pkts_looped_b2r = 0; - ifb->no_bufs1 = 0; - ifb->no_bufs2 = 0; - ifb->full_sockbuf = 0; - } else if (cmd == SIOCGSPLTSTAT) - { register struct Ystats *ys = (struct Ystats *)data; - ys->YS_blue_pid = ifb->blue_pid; - ys->YS_filter[BFS_ATALK] = ifb->filter[BFS_ATALK]; - ys->YS_filter[BFS_IP] = ifb->filter[BFS_IP]; - ys->YS_pkts_up = ifb->pkts_up; - ys->YS_pkts_out = ifb->pkts_out; - ys->YS_pkts_looped_b2r = ifb->pkts_looped_b2r; - ys->YS_pkts_looped_r2b = ifb->pkts_looped_r2b; - ys->YS_no_bufs1 = ifb->no_bufs1; - ys->YS_no_bufs2 = ifb->no_bufs2; - ys->YS_full_sockbuf = ifb->full_sockbuf; - } else - return(EINVAL); - return(0); -} - -void -splitter_close(register struct ndrv_cb *np) -{ extern struct ifnet_blue *blue_if; - extern void ndrv_flushq(struct ifqueue *); - - if (blue_if) - { /* If we're the guy holding the Y-adapter, clean it up */ - if (blue_if->blue_pid == - ((struct proc *)current_proc())->p_pid) - { if (np->nd_if) - { np->nd_if->if_flags &= ~IFF_SPLITTER; - np->nd_if->if_Y = 0; - } - - BFIx = 0; - /* Clean out the filter supply */ - bzero(RhapFilter, - sizeof(struct BlueFilter) * BFCount); - blue_if->ifb_so = 0; - blue_if->filter[0].BF_flags = 0; - blue_if->filter[1].BF_flags = 0; - ndrv_flushq(&blueq); - if (np->nd_laddr) - { FREE((caddr_t) np->nd_laddr, M_IFADDR); - np->nd_laddr = 0; - } - } - } - remque((queue_t)np); - FREE((caddr_t)np, M_PCB); -} - -/* - * Dup the mbuf chain passed in. The whole thing. No cute additional cruft. - * And really copy the thing. That way, we don't "precompute" checksums - * for unsuspecting consumers. - * Assumption: m->m_nextpkt == 0. - * Trick: for small packets, don't dup into a cluster. That way received - * packets don't take up too much room in the sockbuf (cf. sbspace()). - */ -int MDFail; - -struct mbuf * -m_dup(register struct mbuf *m, int how) -{ register struct mbuf *n, **np; - struct mbuf *top; - int copyhdr = 0; - - KERNEL_DEBUG(DBG_SPLT_DUP | DBG_FUNC_START, m->m_flags, m->m_len, - m->m_pkthdr.len, 0, 0 ); - np = ⊤ - top = 0; - if (m->m_flags & M_PKTHDR) - copyhdr = 1; - - /* - * Quick check: if we have one mbuf and its data fits in an - * mbuf with packet header, just copy and go. - */ - if (m->m_next == NULL) - { /* Then just move the data into an mbuf and be done... */ - if (copyhdr) - { if (m->m_pkthdr.len <= MHLEN) - { if ((n = m_gethdr(how, m->m_type)) == NULL) - return(NULL); - bcopy(m->m_data, n->m_data, m->m_pkthdr.len); - n->m_pkthdr.len = m->m_pkthdr.len; - n->m_len = m->m_len; - KERNEL_DEBUG(DBG_SPLT_DUP | DBG_FUNC_END, 2, - m->m_pkthdr.len, m->m_flags, - n->m_flags, 0 ); - return(n); - } - } else if (m->m_len <= MLEN) - { if ((n = m_get(how, m->m_type)) == NULL) - return(NULL); - bcopy(m->m_data, n->m_data, m->m_len); - n->m_len = m->m_len; - KERNEL_DEBUG(DBG_SPLT_DUP | DBG_FUNC_END, 3, m->m_len, - m->m_flags, n->m_flags, 0 ); - return(n); - } - } - while (m) - { -#if BLUE_DEBUG - kprintf("<%x: %x, %x, %x\n", m, m->m_flags, m->m_len, - m->m_data); -#endif - if (copyhdr) - n = m_gethdr(how, m->m_type); - else - n = m_get(how, m->m_type); - if (n == 0) - goto nospace; - if (m->m_flags & M_EXT) - { MCLGET(n, how); - if ((n->m_flags & M_EXT) == 0) - goto nospace; - } - *np = n; - if (copyhdr) - { /* Don't use M_COPY_PKTHDR: preserve m_data */ - n->m_pkthdr = m->m_pkthdr; - n->m_pkthdr.aux = (struct mbuf *)NULL; /*###LD080800 Avoid problems with IPsec */ - - n->m_flags |= (m->m_flags & M_COPYFLAGS); - copyhdr = 0; - if ((n->m_flags & M_EXT) == 0) - n->m_data = n->m_pktdat; - } - n->m_len = m->m_len; - /* - * Get the dup on the same bdry as the original - * Assume that the two mbufs have the same offset to data area - * (up to word bdries) - */ - bcopy(mtod(m, caddr_t), mtod(n, caddr_t), (unsigned)n->m_len); - m = m->m_next; - np = &n->m_next; -#if BLUE_DEBUG - kprintf(">%x: %x, %x, %x\n", n, n->m_flags, n->m_len, - n->m_data); -#endif - } - - if (top == 0) - MDFail++; - KERNEL_DEBUG(DBG_SPLT_DUP | DBG_FUNC_END, 0, (int)top, 0, 0, 0 ); - return (top); - nospace: - m_freem(top); - MDFail++; - KERNEL_DEBUG(DBG_SPLT_DUP | DBG_FUNC_END, 1, 0, 0, 0, 0 ); - return (0); -} diff --git a/bsd/net/if_blue.h b/bsd/net/if_blue.h deleted file mode 100644 index fcc906e35..000000000 --- a/bsd/net/if_blue.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* Copyright (c) 1997, 1998 Apple Computer, Inc. All Rights Reserved */ -/* - * @(#)if_blue.h 1.1 (MacOSX) 6/10/43 - * Justin Walker - * 970520 - First version - * 980130 - Second version - performance improvements - */ - -#ifndef _IF_BLUE_H -#define _IF_BLUE_H - -#define BLUE_DEBUG 0 - -/* - * Y-adapter filter mechanism. - * Specifies the Atalk or IP network address of this node. - * If BF_ALLOC is set and BF_VALID is not, the corresponding - * protocol type should be captured. - */ -struct BlueFilter -{ -#define IFNAMSIZ 16 - char ifr_name[IFNAMSIZ]; /* if name, e.g. "en0" */ - short BF_flags; - unsigned long BF_address; /* IP address or Atalk Network # */ - unsigned char BF_node; /* Atalk node # */ -#ifdef notyet - struct ifnet *BF_if; /* Destination of "passed" pkts */ -#endif -}; - -#define BF_ALLOC 0x01 /* Entry in use */ -#define BF_DEALLOC 0x02 /* Clear matching entry */ -#define BF_VALID 0x04 /* Address is valid */ -#define BF_ATALK 0x08 /* Appletalk network address */ -#define BF_IP 0x10 /* IP network address */ - -struct Ystats -{ char YS_name[IFNAMSIZ]; /* if name, e.g. "en0" */ - struct BlueFilter YS_filter[2]; - pid_t YS_blue_pid; - int YS_pkts_up; - int YS_pkts_out; - int YS_pkts_looped_r2b; - int YS_pkts_looped_b2r; - int YS_no_bufs1; - int YS_no_bufs2; - int YS_full_sockbuf; -}; - -struct ifnet_blue -{ struct ifnet ifb_ifn; - struct socket *ifb_so; - pid_t blue_pid; - int sig_to_send; - int sig_sent; /* Set when new pkt arrives; cleared when mt */ - struct BlueFilter filter[2]; /* Only need to check IP, A/talk */ - /* Stats */ - int pkts_up; - int pkts_out; - int pkts_looped_r2b; - int pkts_looped_b2r; - int no_bufs1; /* splitter_input got null mbuf */ - int no_bufs2; /* ndrv_output couldn't dup mbuf */ - int full_sockbuf; -}; - -/* Preallocate slots in blue_if to simplify filtering */ -#define BFS_ATALK 0x0 /* The Atalk filter */ -#define BFS_IP 0x1 /* The IP filter */ - -#define SIOCSSPLITTER _IOW('i', 123, struct ifreq) /* set 'splitter' */ -#define SIOCGSPLITTER _IOR('i', 122, struct ifreq) /* get 'splitter' */ -#define SIOCGSPLTSTAT _IOWR('i', 121, struct Ystats) -#define SIOCSSPLTFILT _IOW('i', 120, struct BlueFilter) -#define SIOCZSPLTSTAT _IO('i', 119) /* Clear stats */ - -/* - * Config structure for the Y adapter - NYI - */ -struct if_splitter -{ char ifs_on; /* 1=>on */ - char ifs_qmax; /* !0 => maxqlen */ - short ifs_wait; /* Time to wait for signal */ - short ifs_sig; /* Signal to send */ - short ifs_pad; /* Extra space */ -}; - -#ifdef KERNEL -extern struct ifqueue blueq; /* Place to put incoming BB packets */ - -#define BFCount 10 -extern struct BlueFilter RhapFilter[]; /* Filters for MacOSX side */ -extern int BFIx; -#endif -#endif /* _IF_BLUE_H */ diff --git a/bsd/net/if_disc.c b/bsd/net/if_disc.c index 5a95376fb..c8c266bc4 100644 --- a/bsd/net/if_disc.c +++ b/bsd/net/if_disc.c @@ -52,6 +52,7 @@ * SUCH DAMAGE. * * From: @(#)if_loop.c 8.1 (Berkeley) 6/10/93 + * $FreeBSD: src/sys/net/if_disc.c,v 1.26.2.1 2001/03/06 00:32:09 obrien Exp $ */ /* @@ -71,17 +72,13 @@ #include #include -#include "bpfilter.h" -#include "opt_inet.h" - -#if TINY_DSMTU +#ifdef TINY_DSMTU #define DSMTU (1024+512) #else #define DSMTU 65532 #endif -static void discattach __P((void *dummy)); -PSEUDO_SET(discattach, if_disc); +static void discattach __P((void)); static struct ifnet discif; static int discoutput(struct ifnet *, struct mbuf *, struct sockaddr *, @@ -91,8 +88,7 @@ static int discioctl(struct ifnet *, u_long, caddr_t); /* ARGSUSED */ static void -discattach(dummy) - void *dummy; +discattach() { register struct ifnet *ifp = &discif; @@ -106,11 +102,33 @@ discattach(dummy) ifp->if_hdrlen = 0; ifp->if_addrlen = 0; if_attach(ifp); -#if NBPFILTER > 0 bpfattach(ifp, DLT_NULL, sizeof(u_int)); -#endif } +#ifndef __APPLE__ +static int +disc_modevent(module_t mod, int type, void *data) +{ + switch (type) { + case MOD_LOAD: + discattach(); + break; + case MOD_UNLOAD: + printf("if_disc module unload - not possible for this module type\n"); + return EINVAL; + } + return 0; +} + +static moduledata_t disc_mod = { + "if_disc", + disc_modevent, + NULL +}; + +DECLARE_MODULE(if_disc, disc_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); +#endif + static int discoutput(ifp, m, dst, rt) struct ifnet *ifp; @@ -120,7 +138,6 @@ discoutput(ifp, m, dst, rt) { if ((m->m_flags & M_PKTHDR) == 0) panic("discoutput no HDR"); -#if NBPFILTER > 0 /* BPF write needs to be handled specially */ if (dst->sa_family == AF_UNSPEC) { dst->sa_family = *(mtod(m, int *)); @@ -146,7 +163,6 @@ discoutput(ifp, m, dst, rt) bpf_mtap(&discif, &m0); } -#endif m->m_pkthdr.rcvif = ifp; ifp->if_opackets++; @@ -205,6 +221,10 @@ discioctl(ifp, cmd, data) case AF_INET: break; #endif +#if INET6 + case AF_INET6: + break; +#endif default: error = EAFNOSUPPORT; diff --git a/bsd/net/if_dl.h b/bsd/net/if_dl.h index ff1f3a03b..16201a909 100644 --- a/bsd/net/if_dl.h +++ b/bsd/net/if_dl.h @@ -52,10 +52,12 @@ * SUCH DAMAGE. * * @(#)if_dl.h 8.1 (Berkeley) 6/10/93 + * $FreeBSD: src/sys/net/if_dl.h,v 1.10 2000/03/01 02:46:25 archie Exp $ */ #ifndef _NET_IF_DL_H_ #define _NET_IF_DL_H_ +#include /* * A Link-Level Sockaddr may specify the interface in one of two @@ -80,7 +82,7 @@ */ struct sockaddr_dl { u_char sdl_len; /* Total length of sockaddr */ - u_char sdl_family; /* AF_DLI */ + u_char sdl_family; /* AF_LINK */ 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. */ @@ -88,6 +90,11 @@ struct sockaddr_dl { 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 */ +#ifndef __APPLE__ + /* For TokenRing */ + u_short sdl_rcf; /* source routing control */ + u_short sdl_route[16]; /* source routing information */ +#endif }; #define LLADDR(s) ((caddr_t)((s)->sdl_data + (s)->sdl_nlen)) diff --git a/bsd/net/if_dummy.c b/bsd/net/if_dummy.c index ef184de9e..50ce06568 100644 --- a/bsd/net/if_dummy.c +++ b/bsd/net/if_dummy.c @@ -101,16 +101,6 @@ #include #endif -#if NS -#include -#include -#endif - -#if ISO -#include -#include -#endif - #if NETATALK #include #include diff --git a/bsd/net/if_ether.c b/bsd/net/if_ether.c deleted file mode 100644 index 5c8af20b3..000000000 --- a/bsd/net/if_ether.c +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ diff --git a/bsd/net/if_ethersubr.c b/bsd/net/if_ethersubr.c index 7547d9608..892d07158 100644 --- a/bsd/net/if_ethersubr.c +++ b/bsd/net/if_ethersubr.c @@ -52,15 +52,9 @@ * SUCH DAMAGE. * * @(#)if_ethersubr.c 8.1 (Berkeley) 6/10/93 + * $FreeBSD: src/sys/net/if_ethersubr.c,v 1.70.2.17 2001/08/01 00:47:49 fenner Exp $ */ -#if NOTFB31 -#include "opt_atalk.h" -#include "opt_inet.h" -#include "opt_ipx.h" -#include "opt_bdg.h" -#endif - #include #include #include @@ -77,7 +71,7 @@ #include #include -#if INET +#if INET || INET6 #include #include #include @@ -90,26 +84,6 @@ #include #endif -#if NS -#include -#include -ushort ns_nettype; -int ether_outputdebug = 0; -int ether_inputdebug = 0; -#endif - -#if ISO -#include -#include -#include -#include -#endif - -/*#if LLC -#include -#include -#endif*/ - #include #if LLC && CCITT @@ -136,17 +110,18 @@ extern u_char etherbroadcastaddr[]; */ +/* + IONetworkingFamily should call dlil_if_attach + ether_ifattach becomes obsolete, but remains for + temporary compatibility with third parties extensions +*/ void ether_ifattach(ifp) register struct ifnet *ifp; { - register struct ifaddr *ifa; - register struct sockaddr_dl *sdl; boolean_t funnel_state; funnel_state = thread_funnel_set(network_flock, TRUE); - printf("ether_ifattach called for %s\n", ifp->if_name); - ether_family_init(); ifp->if_name = "en"; ifp->if_family = APPLE_IF_FAM_ETHERNET; @@ -159,19 +134,6 @@ ether_ifattach(ifp) ifp->if_baudrate = 10000000; dlil_if_attach(ifp); - ifa = ifnet_addrs[ifp->if_index - 1]; - if (ifa == 0) { - printf("ether_ifattach: no lladdr!\n"); - (void) thread_funnel_set(network_flock, funnel_state); - return; - } - sdl = (struct sockaddr_dl *)ifa->ifa_addr; - sdl->sdl_type = IFT_ETHER; - sdl->sdl_alen = ifp->if_addrlen; - bcopy((IFP2AC(ifp))->ac_enaddr, LLADDR(sdl), ifp->if_addrlen); -#ifdef INET6 - in6_ifattach_getifid(ifp); -#endif (void) thread_funnel_set(network_flock, funnel_state); } diff --git a/bsd/net/if_faith.c b/bsd/net/if_faith.c index 6aafc2ecf..9c9d4ebe7 100644 --- a/bsd/net/if_faith.c +++ b/bsd/net/if_faith.c @@ -19,7 +19,7 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* $KAME: if_faith.c,v 1.11 2000/02/22 14:01:46 itojun Exp $ */ +/* $KAME: if_faith.c,v 1.21 2001/02/20 07:59:26 itojun Exp $ */ /* * Copyright (c) 1982, 1986, 1993 @@ -52,6 +52,8 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * $FreeBSD: src/sys/net/if_faith.c,v 1.3.2.2 2001/07/05 14:46:25 ume Exp $ */ /* * derived from @@ -62,9 +64,6 @@ /* * Loopback interface driver for protocol testing and timing. */ -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -#include "opt_inet.h" -#endif #include "faith.h" #if NFAITH > 0 @@ -75,21 +74,16 @@ #include #include #include -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined(__APPLE__) #include -#else -#include -#endif #include -#if defined(__bsdi__) || defined(__NetBSD__) -#include -#endif +#include #include #include #include #include #include +#include #if INET #include @@ -104,31 +98,24 @@ #endif #include #include +#include #endif #include -#include "faith.h" -#include "bpfilter.h" +#include "bpf.h" #include -#if defined(__FreeBSD__) && __FreeBSD__ < 3 -static int faithioctl __P((struct ifnet *, int, caddr_t)); -#else -static int faithioctl __P((struct ifnet *, u_long, caddr_t)); -#endif +static int faithioctl __P((struct ifnet *, u_long, void*)); int faith_pre_output __P((struct ifnet *, register struct mbuf **, struct sockaddr *, - register struct rtentry *, char *, char *, u_long)); + caddr_t, char *, char *, u_long)); static void faithrtrequest __P((int, struct rtentry *, struct sockaddr *)); -#if defined(__FreeBSD__) || defined (__APPLE__) -void faithattach __P((void *)); -#else -void faithattach __P((int)); +void faithattach __P((void)); +#ifndef __APPLE__ +PSEUDO_SET(faithattach, if_faith); #endif -#define HAVE_OLD_BPF 1 - static struct ifnet faithif[NFAITH]; static struct if_proto *faith_array[NFAITH]; static int faith_count = 0; @@ -192,6 +179,7 @@ void faith_reg_if_mods() { struct dlil_ifmod_reg_str faith_ifmod; + bzero(&faith_ifmod, sizeof(faith_ifmod)); faith_ifmod.add_if = faith_add_if; faith_ifmod.del_if = faith_del_if; faith_ifmod.add_proto = faith_add_proto; @@ -239,7 +227,7 @@ u_long faith_attach_inet(struct ifnet *ifp) reg.pre_output = faith_pre_output; reg.event = 0; reg.offer = 0; - reg.ioctl = faithioctl; + reg.ioctl = 0; reg.default_proto = 0; reg.protocol_family = PF_INET; @@ -252,8 +240,7 @@ u_long faith_attach_inet(struct ifnet *ifp) } void -faithattach(faith) - void *faith; +faithattach(void) { struct ifnet *ifp; int i; @@ -267,8 +254,8 @@ faithattach(faith) ifp->if_unit = i; ifp->if_family = APPLE_IF_FAM_FAITH; ifp->if_mtu = FAITHMTU; - /* Change to BROADCAST experimentaly to announce its prefix. */ - ifp->if_flags = /* IFF_LOOPBACK */ IFF_BROADCAST | IFF_MULTICAST; + /* LOOPBACK commented out to announce IPv6 routes to faith */ + ifp->if_flags = /* IFF_LOOPBACK | */ IFF_MULTICAST; ifp->if_ioctl = faithioctl; ifp->if_output = NULL; ifp->if_type = IFT_FAITH; @@ -286,11 +273,11 @@ faithattach(faith) } int -faith_pre_output(ifp, m0, dst, rt, frame_type, dst_addr, dl_tag) +faith_pre_output(ifp, m0, dst, route_entry, frame_type, dst_addr, dl_tag) struct ifnet *ifp; register struct mbuf **m0; struct sockaddr *dst; - register struct rtentry *rt; + caddr_t route_entry; char *frame_type; char *dst_addr; u_long dl_tag; @@ -298,6 +285,7 @@ faith_pre_output(ifp, m0, dst, rt, frame_type, dst_addr, dl_tag) int s, isr; register struct ifqueue *ifq = 0; register struct mbuf *m = *m0; + struct rtentry *rt = (struct rtentry*)route_entry; if ((m->m_flags & M_PKTHDR) == 0) panic("faithoutput no HDR"); @@ -319,13 +307,13 @@ faith_pre_output(ifp, m0, dst, rt, frame_type, dst_addr, dl_tag) * try to free it or keep a pointer a to it). */ struct mbuf m0; - u_int af = dst->sa_family; + u_int32_t af = dst->sa_family; m0.m_next = m; m0.m_len = 4; m0.m_data = (char *)⁡ -#if HAVE_OLD_BPF +#ifdef HAVE_OLD_BPF bpf_mtap(ifp, &m0); #else bpf_mtap(ifp->if_bpf, &m0); @@ -334,10 +322,8 @@ faith_pre_output(ifp, m0, dst, rt, frame_type, dst_addr, dl_tag) #endif if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) { - m_freem(m); - return (EJUSTRETURN); -// return (rt->rt_flags & RTF_BLACKHOLE ? 0 : -// rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); + return (rt->rt_flags & RTF_BLACKHOLE ? 0 : + rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); } ifp->if_opackets++; ifp->if_obytes += m->m_pkthdr.len; @@ -355,8 +341,6 @@ faith_pre_output(ifp, m0, dst, rt, frame_type, dst_addr, dl_tag) break; #endif default: - kprintf("faith_pre_output: m=%x family is unknown...(0x%x\n", m, dst->sa_family); - m_freem(m); return EAFNOSUPPORT; } @@ -366,9 +350,8 @@ faith_pre_output(ifp, m0, dst, rt, frame_type, dst_addr, dl_tag) s = splimp(); if (IF_QFULL(ifq)) { IF_DROP(ifq); - m_freem(m); splx(s); - return (EJUSTRETURN); + return (ENOBUFS); } IF_ENQUEUE(ifq, m); schednetisr(isr); @@ -403,17 +386,13 @@ faithrtrequest(cmd, rt, sa) /* ARGSUSED */ static int faithioctl(ifp, cmd, data) - register struct ifnet *ifp; -#if defined(__FreeBSD__) && __FreeBSD__ < 3 - int cmd; -#else + struct ifnet *ifp; u_long cmd; -#endif - caddr_t data; + void* data; { - register struct ifaddr *ifa; - register struct ifreq *ifr = (struct ifreq *)data; - register int error = 0; + struct ifaddr *ifa; + struct ifreq *ifr = (struct ifreq *)data; + int error = 0; switch (cmd) { @@ -449,11 +428,9 @@ faithioctl(ifp, cmd, data) break; #ifdef SIOCSIFMTU -#ifndef __OpenBSD__ case SIOCSIFMTU: ifp->if_mtu = ifr->ifr_mtu; break; -#endif #endif case SIOCSIFFLAGS: @@ -464,4 +441,36 @@ faithioctl(ifp, cmd, data) } return (error); } + +#if INET6 +/* + * XXX could be slow + * XXX could be layer violation to call sys/net from sys/netinet6 + */ +int +faithprefix(in6) + struct in6_addr *in6; +{ + struct rtentry *rt; + struct sockaddr_in6 sin6; + int ret; + + if (ip6_keepfaith == 0) + return 0; + + bzero(&sin6, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_len = sizeof(struct sockaddr_in6); + sin6.sin6_addr = *in6; + rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL); + if (rt && rt->rt_ifp && rt->rt_ifp->if_type == IFT_FAITH && + (rt->rt_ifp->if_flags & IFF_UP) != 0) + ret = 1; + else + ret = 0; + if (rt) + rtfree(rt); + return ret; +} +#endif #endif /* NFAITH > 0 */ diff --git a/bsd/net/if_faith.h b/bsd/net/if_faith.h new file mode 100644 index 000000000..3e97f5744 --- /dev/null +++ b/bsd/net/if_faith.h @@ -0,0 +1,46 @@ +/* $FreeBSD: src/sys/net/if_faith.h,v 1.1.2.2 2001/07/05 14:46:25 ume Exp $ */ +/* $KAME: if_faith.h,v 1.1 2000/07/26 05:49:21 itojun Exp $ */ + +/* + * Copyright (C) 2000 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _NET_IF_FAITH_H_ +#define _NET_IF_FAITH_H_ +#include + +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE +#if INET6 +struct in6_addr; +int faithprefix __P((struct in6_addr *)); +#endif /* INET6 */ +#endif /* __APPLE_API_PRIVATE */ +#endif /* KERNEL */ + +#endif /* _NET_IF_FAITH_H_ */ diff --git a/bsd/net/if_fddisubr.c b/bsd/net/if_fddisubr.c index 9f893cba4..dd1ef3a32 100644 --- a/bsd/net/if_fddisubr.c +++ b/bsd/net/if_fddisubr.c @@ -88,32 +88,10 @@ #include #endif -#if NS -#include -#include -#endif - #if DECNET #include #endif -#if ISO -#include -#include -#include -#include -#endif - -#if LLC -#include -#include -#endif - - -#if LLC && CCITT -extern struct ifqueue pkintrq; -#endif - #include "bpfilter.h" #define senderr(e) { error = (e); goto bad;} @@ -161,7 +139,7 @@ fddi_output(ifp, m0, dst, rt0) if (rt = rt0) { if ((rt->rt_flags & RTF_UP) == 0) { if (rt0 = rt = RTALLOC1(dst, 1)) - rt->rt_refcnt--; + rtunref(rt); else senderr(EHOSTUNREACH); } diff --git a/bsd/net/if_gif.c b/bsd/net/if_gif.c index e54b949e2..6ada7aa5e 100644 --- a/bsd/net/if_gif.c +++ b/bsd/net/if_gif.c @@ -19,7 +19,8 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* $KAME: if_gif.c,v 1.15 2000/02/22 14:01:46 itojun Exp $ */ +/* $FreeBSD: src/sys/net/if_gif.c,v 1.4.2.6 2001/07/24 19:10:18 brooks Exp $ */ +/* $KAME: if_gif.c,v 1.47 2001/05/01 05:28:42 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -50,13 +51,6 @@ * SUCH DAMAGE. */ -/* - * gif.c - */ -#if BSD310 -#include "opt_inet.h" -#endif - #include #include #include @@ -67,6 +61,7 @@ #include #include #include +#include #include #include @@ -75,18 +70,16 @@ #include #include -#if INET #include #include -#include #include +#if INET +#include #include +#include #endif /* INET */ #if INET6 -#ifndef INET -#include -#endif #include #include #include @@ -98,24 +91,51 @@ #include #include -#include "gif.h" -#include "bpfilter.h" - #include -#if NGIF > 0 +#define GIFNAME "gif" +#define GIFDEV "if_gif" +#define GIF_MAXUNIT 0x7fff /* ifp->if_unit is only 15 bits */ -void gifattach __P((void *)); +#ifndef __APPLE__ +static MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface"); +#endif + +TAILQ_HEAD(gifhead, gif_softc) gifs = TAILQ_HEAD_INITIALIZER(gifs); + +#ifdef __APPLE__ +void gifattach __P((void)); int gif_pre_output __P((struct ifnet *, register struct mbuf **, struct sockaddr *, - register struct rtentry *, char *, char *, u_long)); + caddr_t, char *, char *, u_long)); +static void gif_create_dev(void); +static int gif_encapcheck(const struct mbuf*, int, int, void*); + + +int ngif = 0; /* number of interfaces */ +#endif + +#if INET +struct protosw in_gif_protosw = +{ SOCK_RAW, 0, 0/*IPPROTO_IPV[46]*/, PR_ATOMIC|PR_ADDR, + in_gif_input, 0, 0, 0, + 0, + 0, 0, 0, 0, + 0, + &rip_usrreqs +}; +#endif +#if INET6 +struct ip6protosw in6_gif_protosw = +{ SOCK_RAW, 0, 0/*IPPROTO_IPV[46]*/, PR_ATOMIC|PR_ADDR, + in6_gif_input, + 0, 0, 0, + 0, + 0, 0, 0, 0, + 0, + &rip6_usrreqs +}; +#endif -/* - * gif global variable definitions - */ -int ngif = NGIF; /* number of interfaces */ -struct gif_softc *gif = 0; -static struct if_proto *gif_array[NGIF]; -static gif_count = 0 ; #ifndef MAX_GIF_NEST /* * This macro controls the upper limitation on nesting of gif tunnels. @@ -131,38 +151,40 @@ static int max_gif_nesting = MAX_GIF_NEST; -#if 0 +#ifdef __APPLE__ +/* + * Theory of operation: initially, one gif interface is created. + * Any time a gif interface is configured, if there are no other + * unconfigured gif interfaces, a new gif interface is created. + * BSD uses the clone mechanism to dynamically create more + * gif interfaces. + * + * We have some extra glue to support DLIL. + */ + +/* GIF interface module support */ int gif_demux(ifp, m, frame_header, proto) struct ifnet *ifp; struct mbuf *m; char *frame_header; struct if_proto **proto; { - int i; - return 0; + struct gif_softc* gif = (struct gif_softc*)ifp->if_softc; + + /* Only one protocol may be attached to a gif interface. */ + *proto = gif->gif_proto; + + return 0; } -int gif_framer(ifp, m, dest, dest_linkaddr, frame_type) - struct ifnet *ifp; - struct mbuf **m; - struct sockaddr *dest; - char *dest_linkaddr; - char *frame_type; - -{ - char *to_ptr; - - return 0; -} -#endif static int gif_add_if(struct ifnet *ifp) -{ - ifp->if_demux = 0; +{ + ifp->if_demux = gif_demux; ifp->if_framer = 0; return 0; } - + static int gif_del_if(struct ifnet *ifp) { @@ -171,46 +193,39 @@ int gif_del_if(struct ifnet *ifp) static int gif_add_proto(struct ddesc_head_str *desc_head, struct if_proto *proto, u_long dl_tag) -{ - int i; - - for (i=0; i < gif_count; i++) - if (gif_array[i] == 0) { - gif_array[gif_count] = proto; - return 0; - } +{ + /* Only one protocol may be attached at a time */ + struct gif_softc* gif = (struct gif_softc*)proto->ifp; - if ((i == gif_count) && (gif_count == NGIF)) - panic("gif_add_proto -- Too many attachments\n"); + if (gif->gif_proto != NULL) + printf("gif_add_proto: request add_proto for gif%d\n", gif->gif_if.if_unit); - gif_array[gif_count++] = proto; + gif->gif_proto = proto; - return (0); + return 0; } static int gif_del_proto(struct if_proto *proto, u_long dl_tag) -{ - int i; - - for (i=0; i < gif_count; i++) - if (gif_array[i] == proto) { - gif_array[i] = 0; - return 0; - } +{ + if (((struct gif_softc*)proto->ifp)->gif_proto == proto) + ((struct gif_softc*)proto->ifp)->gif_proto = NULL; + else + return ENOENT; - return ENOENT; + return 0; } int gif_shutdown() { - return 0; + return 0; } void gif_reg_if_mods() { struct dlil_ifmod_reg_str gif_ifmod; + bzero(&gif_ifmod, sizeof(gif_ifmod)); gif_ifmod.add_if = gif_add_if; gif_ifmod.del_if = gif_del_if; gif_ifmod.add_proto = gif_add_proto; @@ -221,28 +236,22 @@ void gif_reg_if_mods() if (dlil_reg_if_modules(APPLE_IF_FAM_GIF, &gif_ifmod)) panic("Couldn't register gif modules\n"); -} +} -u_long gif_attach_inet(struct ifnet *ifp) +/* Glue code to attach inet to a gif interface through DLIL */ + +u_long gif_attach_proto_family(struct ifnet *ifp, int af) { struct dlil_proto_reg_str reg; struct dlil_demux_desc desc; u_long dl_tag=0; short native=0; - int stat; - int i; - - for (i=0; i < gif_count; i++) { - if (gif_array[i] && (gif_array[i]->ifp == ifp) && - (gif_array[i]->protocol_family == PF_INET)) { -#if 0 - kprintf("gif_attach for %s%d found dl_tag=%d\n", - ifp->if_name, ifp->if_unit, gif_array[i]->dl_tag); -#endif - return gif_array[i]->dl_tag; - - } - } + int stat; + + /* Check if we're already attached */ + stat = dlil_find_dltag(ifp->if_family, ifp->if_unit, af, &dl_tag); + if (stat == 0) + return dl_tag; TAILQ_INIT(®.demux_desc_head); desc.type = DLIL_DESC_RAW; @@ -257,67 +266,185 @@ u_long gif_attach_inet(struct ifnet *ifp) reg.pre_output = gif_pre_output; reg.event = 0; reg.offer = 0; - reg.ioctl = gif_ioctl; + reg.ioctl = 0; reg.default_proto = 0; - reg.protocol_family = PF_INET; + reg.protocol_family = af; stat = dlil_attach_protocol(®, &dl_tag); if (stat) { - panic("gif_attach_inet can't attach interface\n"); + panic("gif_attach_proto_family can't attach interface fam=%d\n", af); } return dl_tag; } +u_long gif_detach_proto_family(struct ifnet *ifp, int af) +{ + u_long ip_dl_tag = 0; + int stat; + + stat = dlil_find_dltag(ifp->if_family, ifp->if_unit, af, &ip_dl_tag); + if (stat == 0) { + stat = dlil_detach_protocol(ip_dl_tag); + if (stat) { + printf("WARNING: gif_detach can't detach IP fam=%d from interface\n", af); + } + } + return (stat); +} + +#endif + +/* Function to setup the first gif interface */ void -gifattach(dummy) - void *dummy; +gifattach(void) { - register struct gif_softc *sc; - register int i; + /* Init the list of interfaces */ + TAILQ_INIT(&gifs); gif_reg_if_mods(); /* DLIL modules */ - gif = sc = _MALLOC (ngif * sizeof(struct gif_softc), M_DEVBUF, M_WAITOK); - bzero(sc, ngif * sizeof(struct gif_softc)); - for (i = 0; i < ngif; sc++, i++) { - sc->gif_if.if_name = "gif"; - sc->gif_if.if_unit = i; - sc->gif_if.if_family = APPLE_IF_FAM_GIF; - sc->gif_if.if_mtu = GIF_MTU; - sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; - sc->gif_if.if_ioctl = gif_ioctl; - sc->gif_if.if_output = NULL; - sc->gif_if.if_type = IFT_GIF; - dlil_if_attach(&sc->gif_if); + /* Create first device */ + gif_create_dev(); +} + +/* Creates another gif device if there are none free */ +static void +gif_create_dev(void) +{ + struct gif_softc *sc; + + + /* Can't create more than GIF_MAXUNIT */ + if (ngif >= GIF_MAXUNIT) + return; + + /* Check for unused gif interface */ + TAILQ_FOREACH(sc, &gifs, gif_link) { + /* If unused, return, no need to create a new interface */ + if ((sc->gif_if.if_flags & IFF_RUNNING) == 0) + return; + } + + sc = _MALLOC(sizeof(struct gif_softc), M_DEVBUF, M_WAITOK); + if (sc == NULL) { + log(LOG_ERR, "gifattach: failed to allocate gif%d\n", ngif); + return; + } + + bzero(sc, sizeof(struct gif_softc)); + sc->gif_if.if_softc = sc; + sc->gif_if.if_name = GIFNAME; + sc->gif_if.if_unit = ngif; + + sc->encap_cookie4 = sc->encap_cookie6 = NULL; +#ifdef INET + sc->encap_cookie4 = encap_attach_func(AF_INET, -1, + gif_encapcheck, &in_gif_protosw, sc); + if (sc->encap_cookie4 == NULL) { + printf("%s: unable to attach encap4\n", if_name(&sc->gif_if)); + FREE(sc, M_DEVBUF); + return; + } +#endif +#ifdef INET6 + sc->encap_cookie6 = encap_attach_func(AF_INET6, -1, + gif_encapcheck, (struct protosw*)&in6_gif_protosw, sc); + if (sc->encap_cookie6 == NULL) { + if (sc->encap_cookie4) { + encap_detach(sc->encap_cookie4); + sc->encap_cookie4 = NULL; + } + printf("%s: unable to attach encap6\n", if_name(&sc->gif_if)); + FREE(sc, M_DEVBUF); + return; + } +#endif + + sc->gif_if.if_family= APPLE_IF_FAM_GIF; + sc->gif_if.if_mtu = GIF_MTU; + sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; #if 0 - kprintf("gifattach: Attaching gif%d sc=%x gif_if=%x\n", i, sc, &sc->gif_if); + /* turn off ingress filter */ + sc->gif_if.if_flags |= IFF_LINK2; #endif -#if NBPFILTER > 0 -#ifdef HAVE_OLD_BPF - bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int)); -#else - bpfattach(&sc->gif_if.if_bpf, &sc->gif_if, DLT_NULL, sizeof(u_int)); + sc->gif_if.if_ioctl = gif_ioctl; + sc->gif_if.if_output = NULL; /* pre_output returns error or EJUSTRETURN */ + sc->gif_if.if_type = IFT_GIF; + dlil_if_attach(&sc->gif_if); + bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int)); + TAILQ_INSERT_TAIL(&gifs, sc, gif_link); + ngif++; +} + +static int +gif_encapcheck(m, off, proto, arg) + const struct mbuf *m; + int off; + int proto; + void *arg; +{ + struct ip ip; + struct gif_softc *sc; + + sc = (struct gif_softc *)arg; + if (sc == NULL) + return 0; + + if ((sc->gif_if.if_flags & IFF_UP) == 0) + return 0; + + /* no physical address */ + if (!sc->gif_psrc || !sc->gif_pdst) + return 0; + + switch (proto) { +#if INET + case IPPROTO_IPV4: + break; #endif +#if INET6 + case IPPROTO_IPV6: + break; #endif + default: + return 0; } -} -#ifdef __FreeBSD__ -PSEUDO_SET(gifattach, if_gif); + /* LINTED const cast */ + m_copydata((struct mbuf *)m, 0, sizeof(ip), (caddr_t)&ip); + + switch (ip.ip_v) { +#if INET + case 4: + if (sc->gif_psrc->sa_family != AF_INET || + sc->gif_pdst->sa_family != AF_INET) + return 0; + return gif_encapcheck4(m, off, proto, arg); +#endif +#if INET6 + case 6: + if (sc->gif_psrc->sa_family != AF_INET6 || + sc->gif_pdst->sa_family != AF_INET6) + return 0; + return gif_encapcheck6(m, off, proto, arg); #endif + default: + return 0; + } +} int gif_pre_output(ifp, m0, dst, rt, frame, address, dl_tag) struct ifnet *ifp; struct mbuf **m0; struct sockaddr *dst; - struct rtentry *rt; /* added in net2 */ + caddr_t rt; char *frame; char *address; u_long dl_tag; { - register struct gif_softc *sc = (struct gif_softc*)ifp; + struct gif_softc *sc = (struct gif_softc*)ifp; register struct mbuf * m = *m0; int error = 0; static int called = 0; /* XXX: MUTEX */ @@ -333,7 +460,6 @@ gif_pre_output(ifp, m0, dst, rt, frame, address, dl_tag) log(LOG_NOTICE, "gif_output: recursively called too many times(%d)\n", called); - m_freem(m); error = EIO; /* is there better errno? */ goto end; } @@ -341,17 +467,11 @@ gif_pre_output(ifp, m0, dst, rt, frame, address, dl_tag) getmicrotime(&ifp->if_lastchange); m->m_flags &= ~(M_BCAST|M_MCAST); if (!(ifp->if_flags & IFF_UP) || -#if 0 - sc->gif_flags & GIFF_INUSE || -#endif sc->gif_psrc == NULL || sc->gif_pdst == NULL) { - m_freem(m); error = ENETDOWN; - printf("gif_output: packed discarded ENETDOWN\n"); goto end; } -#if NBPFILTER > 0 if (ifp->if_bpf) { /* * We need to prepend the address family as @@ -361,64 +481,58 @@ gif_pre_output(ifp, m0, dst, rt, frame, address, dl_tag) * try to free it or keep a pointer a to it). */ struct mbuf m0; - u_int af = dst->sa_family; + u_int32_t af = dst->sa_family; m0.m_next = m; m0.m_len = 4; m0.m_data = (char *)⁡ -#ifdef HAVE_OLD_BPF bpf_mtap(ifp, &m0); -#else - bpf_mtap(ifp->if_bpf, &m0); -#endif } -#endif ifp->if_opackets++; ifp->if_obytes += m->m_pkthdr.len; -#if 0 - s = splnet(); - sc->gif_flags |= GIFF_INUSE; -#endif + /* inner AF-specific encapsulation */ + + /* XXX should we check if our outer source is legal? */ + + /* dispatch to output logic based on outer AF */ switch (sc->gif_psrc->sa_family) { #if INET case AF_INET: - error = in_gif_output(ifp, dst->sa_family, m, rt); - if (error) - printf("in_gif_output returned error=%d\n", error); + error = in_gif_output(ifp, dst->sa_family, m, (struct rtentry*)rt); break; #endif #if INET6 case AF_INET6: - error = in6_gif_output(ifp, dst->sa_family, m, rt); - if (error) - printf("in6_gif_output returned error=%d\n", error); + error = in6_gif_output(ifp, dst->sa_family, m, (struct rtentry*)rt); break; #endif default: - m_freem(m); error = ENETDOWN; + goto end; } -#if 0 - sc->gif_flags &= ~GIFF_INUSE; - splx(s); -#endif end: called = 0; /* reset recursion counter */ - if (error) ifp->if_oerrors++; - return EJUSTRETURN; + if (error) + ifp->if_oerrors++; + if (error == 0) + error = EJUSTRETURN; /* if no error, packet got sent already */ + return error; } -void -gif_input(m, af, gifp) +int +gif_input(m, frame_header, gifp, dl_tag, sync_ok) struct mbuf *m; - int af; - struct ifnet *gifp; + char* frame_header; + struct ifnet* gifp; + u_long dl_tag; + int sync_ok; { int s, isr; - register struct ifqueue *ifq = 0; + struct ifqueue *ifq = 0; + int af; if (gifp == NULL) { /* just in case */ @@ -426,10 +540,12 @@ gif_input(m, af, gifp) return; } + /* Assume packet is of type of protocol attached to this interface */ + af = ((struct gif_softc*)(gifp->if_softc))->gif_proto->protocol_family; + if (m->m_pkthdr.rcvif) m->m_pkthdr.rcvif = gifp; -#if NBPFILTER > 0 if (gifp->if_bpf) { /* * We need to prepend the address family as @@ -439,19 +555,14 @@ gif_input(m, af, gifp) * try to free it or keep a pointer a to it). */ struct mbuf m0; - u_int af = AF_INET6; + u_int32_t af1 = af; m0.m_next = m; m0.m_len = 4; - m0.m_data = (char *)⁡ + m0.m_data = (char *)&af1; -#ifdef HAVE_OLD_BPF bpf_mtap(gifp, &m0); -#else - bpf_mtap(gifp->if_bpf, &m0); -#endif } -#endif /*NBPFILTER > 0*/ /* * Put the packet to the network layer input queue according to the @@ -480,7 +591,7 @@ gif_input(m, af, gifp) #endif default: m_freem(m); - return; + return (EJUSTRETURN); } s = splimp(); @@ -488,7 +599,7 @@ gif_input(m, af, gifp) IF_DROP(ifq); /* update statistics */ m_freem(m); splx(s); - return; + return (EJUSTRETURN); } IF_ENQUEUE(ifq, m); /* we need schednetisr since the address family may change */ @@ -497,7 +608,7 @@ gif_input(m, af, gifp) gifp->if_ibytes += m->m_pkthdr.len; splx(s); - return; + return (0); } /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */ @@ -505,13 +616,15 @@ int gif_ioctl(ifp, cmd, data) struct ifnet *ifp; u_long cmd; - caddr_t data; + void* data; { struct gif_softc *sc = (struct gif_softc*)ifp; struct ifreq *ifr = (struct ifreq*)data; int error = 0, size; struct sockaddr *dst, *src; - int i; + struct sockaddr *sa; + int s; + struct ifnet *ifp2; struct gif_softc *sc2; switch (cmd) { @@ -523,87 +636,191 @@ gif_ioctl(ifp, cmd, data) case SIOCADDMULTI: case SIOCDELMULTI: - /* Called from if_addmulti() with data == NULL if __FreeBSD__ >= 3 */ -#if !defined(__APPLE__) - switch (ifr->ifr_addr.sa_family) { -#ifdef INET - case AF_INET: /* IP supports Multicast */ - break; -#endif /* INET */ -#ifdef INET6 - case AF_INET6: /* IP6 supports Multicast */ - break; -#endif /* INET6 */ - default: /* Other protocols doesn't support Multicast */ - error = EAFNOSUPPORT; - break; - } -#endif /*not FreeBSD3*/ break; #ifdef SIOCSIFMTU /* xxx */ -#ifndef __OpenBSD__ case SIOCGIFMTU: break; + case SIOCSIFMTU: { -#ifdef __bsdi__ - short mtu; - mtu = *(short *)ifr->ifr_data; -#else u_long mtu; mtu = ifr->ifr_mtu; -#endif if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) { return (EINVAL); } ifp->if_mtu = mtu; } break; -#endif #endif /* SIOCSIFMTU */ case SIOCSIFPHYADDR: #if INET6 case SIOCSIFPHYADDR_IN6: #endif /* INET6 */ - /* can't configure same pair of address onto two gif */ - src = (struct sockaddr *) - &(((struct in_aliasreq *)data)->ifra_addr); - dst = (struct sockaddr *) - &(((struct in_aliasreq *)data)->ifra_dstaddr); - for (i = 0; i < ngif; i++) { - sc2 = gif + i; + case SIOCSLIFPHYADDR: + switch (cmd) { +#if INET + case SIOCSIFPHYADDR: + src = (struct sockaddr *) + &(((struct in_aliasreq *)data)->ifra_addr); + dst = (struct sockaddr *) + &(((struct in_aliasreq *)data)->ifra_dstaddr); + break; +#endif +#if INET6 + case SIOCSIFPHYADDR_IN6: + src = (struct sockaddr *) + &(((struct in6_aliasreq *)data)->ifra_addr); + dst = (struct sockaddr *) + &(((struct in6_aliasreq *)data)->ifra_dstaddr); + break; +#endif + case SIOCSLIFPHYADDR: + src = (struct sockaddr *) + &(((struct if_laddrreq *)data)->addr); + dst = (struct sockaddr *) + &(((struct if_laddrreq *)data)->dstaddr); + } + + /* sa_family must be equal */ + if (src->sa_family != dst->sa_family) + return EINVAL; + + /* validate sa_len */ + switch (src->sa_family) { +#if INET + case AF_INET: + if (src->sa_len != sizeof(struct sockaddr_in)) + return EINVAL; + break; +#endif +#if INET6 + case AF_INET6: + if (src->sa_len != sizeof(struct sockaddr_in6)) + return EINVAL; + break; +#endif + default: + return EAFNOSUPPORT; + } + switch (dst->sa_family) { +#if INET + case AF_INET: + if (dst->sa_len != sizeof(struct sockaddr_in)) + return EINVAL; + break; +#endif +#if INET6 + case AF_INET6: + if (dst->sa_len != sizeof(struct sockaddr_in6)) + return EINVAL; + break; +#endif + default: + return EAFNOSUPPORT; + } + + /* check sa_family looks sane for the cmd */ + switch (cmd) { + case SIOCSIFPHYADDR: + if (src->sa_family == AF_INET) + break; + return EAFNOSUPPORT; +#if INET6 + case SIOCSIFPHYADDR_IN6: + if (src->sa_family == AF_INET6) + break; + return EAFNOSUPPORT; +#endif /* INET6 */ + case SIOCSLIFPHYADDR: + /* checks done in the above */ + break; + } + + TAILQ_FOREACH(ifp2, &ifnet, if_link) { + if (strcmp(ifp2->if_name, GIFNAME) != 0) + continue; + sc2 = ifp2->if_softc; if (sc2 == sc) continue; if (!sc2->gif_pdst || !sc2->gif_psrc) continue; - if (sc2->gif_pdst->sa_family == dst->sa_family && - sc2->gif_pdst->sa_len == dst->sa_family && - bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 && - sc2->gif_psrc->sa_family == src->sa_family && - sc2->gif_psrc->sa_len == src->sa_family && + if (sc2->gif_pdst->sa_family != dst->sa_family || + sc2->gif_pdst->sa_len != dst->sa_len || + sc2->gif_psrc->sa_family != src->sa_family || + sc2->gif_psrc->sa_len != src->sa_len) + continue; +#ifndef XBONEHACK + /* can't configure same pair of address onto two gifs */ + if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 && bcmp(sc2->gif_psrc, src, src->sa_len) == 0) { error = EADDRNOTAVAIL; goto bad; } - } +#endif - switch (ifr->ifr_addr.sa_family) { -#if INET - case AF_INET: - return in_gif_ioctl(ifp, cmd, data); -#endif /* INET */ + /* can't configure multiple multi-dest interfaces */ +#define multidest(x) \ + (((struct sockaddr_in *)(x))->sin_addr.s_addr == INADDR_ANY) #if INET6 - case AF_INET6: - return in6_gif_ioctl(ifp, cmd, data); -#endif /* INET6 */ - default: - error = EPROTOTYPE; - goto bad; - break; +#define multidest6(x) \ + (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(x))->sin6_addr)) +#endif + if (dst->sa_family == AF_INET && + multidest(dst) && multidest(sc2->gif_pdst)) { + error = EADDRNOTAVAIL; + goto bad; + } +#if INET6 + if (dst->sa_family == AF_INET6 && + multidest6(dst) && multidest6(sc2->gif_pdst)) { + error = EADDRNOTAVAIL; + goto bad; + } +#endif } + + if (sc->gif_psrc) + FREE((caddr_t)sc->gif_psrc, M_IFADDR); + sa = (struct sockaddr *)_MALLOC(src->sa_len, M_IFADDR, M_WAITOK); + bcopy((caddr_t)src, (caddr_t)sa, src->sa_len); + sc->gif_psrc = sa; + + if (sc->gif_pdst) + FREE((caddr_t)sc->gif_pdst, M_IFADDR); + sa = (struct sockaddr *)_MALLOC(dst->sa_len, M_IFADDR, M_WAITOK); + bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len); + sc->gif_pdst = sa; + + ifp->if_flags |= IFF_RUNNING; + + gif_attach_proto_family(ifp, src->sa_family); + + s = splimp(); + if_up(ifp); /* mark interface UP and send up RTM_IFINFO */ +#ifdef __APPLE__ + /* Make sure at least one unused device is still available */ + gif_create_dev(); +#endif + splx(s); + + error = 0; break; + +#ifdef SIOCDIFPHYADDR + case SIOCDIFPHYADDR: + if (sc->gif_psrc) { + FREE((caddr_t)sc->gif_psrc, M_IFADDR); + sc->gif_psrc = NULL; + } + if (sc->gif_pdst) { + FREE((caddr_t)sc->gif_pdst, M_IFADDR); + sc->gif_pdst = NULL; + } + /* change the IFF_{UP, RUNNING} flag as well? */ + break; +#endif case SIOCGIFPSRCADDR: #if INET6 @@ -614,25 +831,27 @@ gif_ioctl(ifp, cmd, data) goto bad; } src = sc->gif_psrc; - switch (sc->gif_psrc->sa_family) { + switch (cmd) { #if INET - case AF_INET: + case SIOCGIFPSRCADDR: dst = &ifr->ifr_addr; - size = sizeof(struct sockaddr_in); + size = sizeof(ifr->ifr_addr); break; #endif /* INET */ #if INET6 - case AF_INET6: + case SIOCGIFPSRCADDR_IN6: dst = (struct sockaddr *) &(((struct in6_ifreq *)data)->ifr_addr); - size = sizeof(struct sockaddr_in6); + size = sizeof(((struct in6_ifreq *)data)->ifr_addr); break; #endif /* INET6 */ default: error = EADDRNOTAVAIL; goto bad; } - bcopy((caddr_t)src, (caddr_t)dst, size); + if (src->sa_len > size) + return EINVAL; + bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); break; case SIOCGIFPDSTADDR: @@ -644,51 +863,79 @@ gif_ioctl(ifp, cmd, data) goto bad; } src = sc->gif_pdst; - switch (sc->gif_pdst->sa_family) { + switch (cmd) { #if INET - case AF_INET: + case SIOCGIFPDSTADDR: dst = &ifr->ifr_addr; - size = sizeof(struct sockaddr_in); + size = sizeof(ifr->ifr_addr); break; #endif /* INET */ #if INET6 - case AF_INET6: + case SIOCGIFPDSTADDR_IN6: dst = (struct sockaddr *) &(((struct in6_ifreq *)data)->ifr_addr); - size = sizeof(struct sockaddr_in6); + size = sizeof(((struct in6_ifreq *)data)->ifr_addr); break; #endif /* INET6 */ default: error = EADDRNOTAVAIL; goto bad; } - bcopy((caddr_t)src, (caddr_t)dst, size); + if (src->sa_len > size) + return EINVAL; + bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); break; - case SIOCSIFFLAGS: - if (sc->gif_psrc == NULL) - break; - switch (sc->gif_psrc->sa_family) { -#if INET - case AF_INET: - return in_gif_ioctl(ifp, cmd, data); -#endif /* INET */ -#if INET6 - case AF_INET6: - return in6_gif_ioctl(ifp, cmd, data); -#endif /* INET6 */ - default: - error = EPROTOTYPE; + case SIOCGLIFPHYADDR: + if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) { + error = EADDRNOTAVAIL; goto bad; - break; } + + /* copy src */ + src = sc->gif_psrc; + dst = (struct sockaddr *) + &(((struct if_laddrreq *)data)->addr); + size = sizeof(((struct if_laddrreq *)data)->addr); + if (src->sa_len > size) + return EINVAL; + bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); + + /* copy dst */ + src = sc->gif_pdst; + dst = (struct sockaddr *) + &(((struct if_laddrreq *)data)->dstaddr); + size = sizeof(((struct if_laddrreq *)data)->dstaddr); + if (src->sa_len > size) + return EINVAL; + bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); + break; + + case SIOCSIFFLAGS: + /* if_ioctl() takes care of it */ break; default: - error = EINVAL; + error = EOPNOTSUPP; break; } bad: return error; } -#endif /*NGIF > 0*/ + +void +gif_delete_tunnel(sc) + struct gif_softc *sc; +{ + /* XXX: NetBSD protects this function with splsoftnet() */ + + if (sc->gif_psrc) { + FREE((caddr_t)sc->gif_psrc, M_IFADDR); + sc->gif_psrc = NULL; + } + if (sc->gif_pdst) { + FREE((caddr_t)sc->gif_pdst, M_IFADDR); + sc->gif_pdst = NULL; + } + /* change the IFF_UP flag as well? */ +} diff --git a/bsd/net/if_gif.h b/bsd/net/if_gif.h index 3e5d4996b..a74b84a4e 100644 --- a/bsd/net/if_gif.h +++ b/bsd/net/if_gif.h @@ -56,16 +56,21 @@ #ifndef _NET_IF_GIF_H_ #define _NET_IF_GIF_H_ +#include #include /* xxx sigh, why route have struct route instead of pointer? */ struct encaptab; +#ifdef __APPLE_API_PRIVATE struct gif_softc { - struct ifnet gif_if; /* common area */ + struct ifnet gif_if; /* common area - must be at the top */ struct sockaddr *gif_psrc; /* Physical src addr */ struct sockaddr *gif_pdst; /* Physical dst addr */ +#ifdef __APPLE__ + struct if_proto *gif_proto; /* dlil protocol attached */ +#endif union { struct route gifscr_ro; /* xxx */ #if INET6 @@ -73,31 +78,27 @@ struct gif_softc { #endif } gifsc_gifscr; int gif_flags; - const struct encaptab *encap_cookie; - short gif_oflags; /* copy of ifp->if_flags */ + const struct encaptab *encap_cookie4; + const struct encaptab *encap_cookie6; + TAILQ_ENTRY(gif_softc) gif_link; /* all gif's are linked */ }; #define gif_ro gifsc_gifscr.gifscr_ro #if INET6 #define gif_ro6 gifsc_gifscr.gifscr_ro6 #endif - -#define GIFF_INUSE 0x1 /* gif is in use */ +#endif /* __APPLE_API_PRIVATE */ #define GIF_MTU (1280) /* Default MTU */ #define GIF_MTU_MIN (1280) /* Minimum MTU */ #define GIF_MTU_MAX (8192) /* Maximum MTU */ -#define GIF_TTL 30 -#define GIF_HLIM 30 - -extern int ngif; -extern struct gif_softc *gif; - +#ifdef __APPLE_API_PRIVATE /* Prototypes */ -void gif_input __P((struct mbuf *, int, struct ifnet *)); +int gif_input __P((struct mbuf *, char*, struct ifnet *, u_long, int)); int gif_output __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *)); -int gif_ioctl __P((struct ifnet *, u_long, caddr_t)); +int gif_ioctl __P((struct ifnet *, u_long, void*)); +#endif /* __APPLE_API_PRIVATE */ #endif /* _NET_IF_GIF_H_ */ diff --git a/bsd/net/if_llc.h b/bsd/net/if_llc.h index 2d8fe4f03..8f077d367 100644 --- a/bsd/net/if_llc.h +++ b/bsd/net/if_llc.h @@ -56,6 +56,7 @@ #ifndef _NET_IF_LLC_H_ #define _NET_IF_LLC_H_ +#include /* * IEEE 802.2 Link Level Control headers, for use in conjunction with diff --git a/bsd/net/if_loop.c b/bsd/net/if_loop.c index e8cef396f..6c90a9cca 100644 --- a/bsd/net/if_loop.c +++ b/bsd/net/if_loop.c @@ -52,6 +52,7 @@ * SUCH DAMAGE. * * @(#)if_loop.c 8.1 (Berkeley) 6/10/93 + * $FreeBSD: src/sys/net/if_loop.c,v 1.47.2.5 2001/07/03 11:01:41 ume Exp $ */ /* @@ -92,16 +93,6 @@ #include #endif -#if NS -#include -#include -#endif - -#if ISO -#include -#include -#endif - #include #if NETAT @@ -280,14 +271,10 @@ lo_output(ifp, m) ifp->if_opackets++; ifp->if_ipackets++; - /* WARNING - * This won't work for loopbacked multicast - */ m->m_pkthdr.header = mtod(m, char *); - m->m_pkthdr.aux = ifp; /* HACKERY */ - m->m_pkthdr.csum_data = 0xffff; /* loopback checksums are always OK */ - m->m_pkthdr.csum_flags = CSUM_DATA_VALID | CSUM_PSEUDO_HDR | - CSUM_IP_CHECKED | CSUM_IP_VALID; + m->m_pkthdr.csum_data = 0xffff; /* loopback checksums are always OK */ + m->m_pkthdr.csum_flags = CSUM_DATA_VALID | CSUM_PSEUDO_HDR | + CSUM_IP_CHECKED | CSUM_IP_VALID; return dlil_input(ifp, m, m); } @@ -335,6 +322,7 @@ lo_pre_output(ifp, m, dst, route, frame_type, dst_addr, dl_tag) #endif #if INET6 case AF_INET6: + (*m)->m_flags |= M_LOOP; ifq = &ip6intrq; isr = NETISR_IPV6; break; @@ -512,6 +500,7 @@ void lo_reg_if_mods() { struct dlil_ifmod_reg_str lo_ifmod; + bzero(&lo_ifmod, sizeof(lo_ifmod)); lo_ifmod.add_if = lo_add_if; lo_ifmod.del_if = lo_del_if; lo_ifmod.add_proto = lo_add_proto; @@ -565,6 +554,47 @@ u_long lo_attach_inet(struct ifnet *ifp) return dl_tag; } +u_long lo_attach_inet6(struct ifnet *ifp) +{ + struct dlil_proto_reg_str reg; + struct dlil_demux_desc desc; + u_long dl_tag=0; + short native=0; + int stat; + int i; + + for (i=0; i < lo_count; i++) { + if ((lo_array[i]) && (lo_array[i]->ifp == ifp)) { + if (lo_array[i]->protocol_family == PF_INET6) + return lo_array[i]->dl_tag; + } + } + + TAILQ_INIT(®.demux_desc_head); + desc.type = DLIL_DESC_RAW; + desc.variants.bitmask.proto_id_length = 0; + desc.variants.bitmask.proto_id = 0; + desc.variants.bitmask.proto_id_mask = 0; + desc.native_type = (char *) &native; + TAILQ_INSERT_TAIL(®.demux_desc_head, &desc, next); + reg.interface_family = ifp->if_family; + reg.unit_number = ifp->if_unit; + reg.input = lo_input; + reg.pre_output = lo_pre_output; + reg.event = 0; + reg.offer = 0; + reg.ioctl = loioctl; + reg.default_proto = 0; + reg.protocol_family = PF_INET6; + + stat = dlil_attach_protocol(®, &dl_tag); + if (stat) { + panic("lo_attach_inet6 can't attach interface\n"); + } + + return dl_tag; +} + int lo_set_bpf_tap(struct ifnet *ifp, int mode, int (*bpf_callback)(struct ifnet *, struct mbuf *)) { @@ -604,7 +634,7 @@ loopattach(dummy) ifp->if_unit = i++; ifp->if_mtu = LOMTU; ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST; - ifp->if_ioctl = 0; + ifp->if_ioctl = loioctl; ifp->if_set_bpf_tap = lo_set_bpf_tap; ifp->if_output = lo_output; ifp->if_type = IFT_LOOP; diff --git a/bsd/net/if_media.c b/bsd/net/if_media.c index 59778216b..ed5ec87ab 100644 --- a/bsd/net/if_media.c +++ b/bsd/net/if_media.c @@ -20,6 +20,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* $NetBSD: if_media.c,v 1.1 1997/03/17 02:55:15 thorpej Exp $ */ +/* $FreeBSD: src/sys/net/if_media.c,v 1.9.2.4 2001/07/04 00:12:38 brooks Exp $ */ /* * Copyright (c) 1997 @@ -109,6 +110,19 @@ ifmedia_init(ifm, dontcare_mask, change_callback, status_callback) ifm->ifm_status = status_callback; } +void +ifmedia_removeall(ifm) + struct ifmedia *ifm; +{ + struct ifmedia_entry *entry; + + for (entry = LIST_FIRST(&ifm->ifm_list); entry; + entry = LIST_FIRST(&ifm->ifm_list)) { + LIST_REMOVE(entry, ifm_list); + FREE(entry, M_IFADDR); + } +} + /* * Add a media configuration to the list of supported media * for a specific interface instance. @@ -133,7 +147,7 @@ ifmedia_add(ifm, mword, data, aux) } #endif - entry = _MALLOC(sizeof(*entry), M_IFADDR, M_WAITOK); + entry = _MALLOC(sizeof(*entry), M_IFADDR, M_NOWAIT); if (entry == NULL) panic("ifmedia_add: can't malloc entry"); @@ -277,6 +291,7 @@ ifmedia_ioctl(ifp, ifr, ifm, cmd) { struct ifmedia_entry *ep; int *kptr, count; + int usermax; /* user requested max */ kptr = NULL; /* XXX gcc */ @@ -287,7 +302,25 @@ ifmedia_ioctl(ifp, ifr, ifm, cmd) (*ifm->ifm_status)(ifp, ifmr); count = 0; - ep = ifm->ifm_list.lh_first; + usermax = 0; + + /* + * If there are more interfaces on the list, count + * them. This allows the caller to set ifmr->ifm_count + * to 0 on the first call to know how much space to + * allocate. + */ + LIST_FOREACH(ep, &ifm->ifm_list, ifm_list) + usermax++; + + /* + * Don't allow the user to ask for too many + * or a negative number. + */ + if (ifmr->ifm_count > usermax) + ifmr->ifm_count = usermax; + else if (ifmr->ifm_count < 0) + return (EINVAL); if (ifmr->ifm_count != 0) { kptr = (int *) _MALLOC(ifmr->ifm_count * sizeof(int), @@ -296,23 +329,17 @@ ifmedia_ioctl(ifp, ifr, ifm, cmd) /* * Get the media words from the interface's list. */ + ep = LIST_FIRST(&ifm->ifm_list); for (; ep != NULL && count < ifmr->ifm_count; - ep = ep->ifm_list.le_next, count++) + ep = LIST_NEXT(ep, ifm_list), count++) kptr[count] = ep->ifm_media; if (ep != NULL) error = E2BIG; /* oops! */ + } else { + count = usermax; } - /* - * If there are more interfaces on the list, count - * them. This allows the caller to set ifmr->ifm_count - * to 0 on the first call to know how much space to - * callocate. - */ - for (; ep != NULL; ep = ep->ifm_list.le_next) - count++; - /* * We do the copyout on E2BIG, because that's * just our way of telling userland that there @@ -358,8 +385,7 @@ ifmedia_match(ifm, target, mask) match = NULL; mask = ~mask; - for (next = ifm->ifm_list.lh_first; next != NULL; - next = next->ifm_list.le_next) { + LIST_FOREACH(next, &ifm->ifm_list, ifm_list) { if ((next->ifm_media & mask) == (target & mask)) { #if defined(IFMEDIA_DEBUG) || defined(DIAGNOSTIC) if (match) { diff --git a/bsd/net/if_media.h b/bsd/net/if_media.h index 827081bfd..f17ed30fa 100644 --- a/bsd/net/if_media.h +++ b/bsd/net/if_media.h @@ -20,6 +20,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* $NetBSD: if_media.h,v 1.3 1997/03/26 01:19:27 thorpej Exp $ */ +/* $FreeBSD: src/sys/net/if_media.h,v 1.9.2.1 2001/07/04 00:12:38 brooks Exp $ */ /* * Copyright (c) 1997 @@ -57,6 +58,7 @@ #ifndef _NET_IF_MEDIA_H_ #define _NET_IF_MEDIA_H_ +#include /* * Prototypes and definitions for BSD/OS-compatible network interface @@ -74,6 +76,7 @@ #include +#ifdef __APPLE_API_UNSTABLE /* * Driver callbacks for media status and change requests. */ @@ -121,7 +124,8 @@ void ifmedia_set __P((struct ifmedia *ifm, int mword)); int ifmedia_ioctl __P((struct ifnet *ifp, struct ifreq *ifr, struct ifmedia *ifm, u_long cmd)); -#endif /*KERNEL */ +#endif /* __APPLE_API_UNSTABLE */ +#endif /* KERNEL */ /* * if_media Options word: @@ -148,8 +152,8 @@ int ifmedia_ioctl __P((struct ifnet *ifp, struct ifreq *ifr, #define IFM_100_VG 9 /* 100VG-AnyLAN */ #define IFM_100_T2 10 /* 100BaseT2 */ #define IFM_1000_SX 11 /* 1000BaseSX - multi-mode fiber */ -#define IFM_10_STP 12 /* 10BaseT over shielded TP */ -#define IFM_10_FL 13 /* 10BaseFL - Fiber */ +#define IFM_10_STP 12 /* 10BaseT over shielded TP */ +#define IFM_10_FL 13 /* 10baseFL - Fiber */ #define IFM_1000_LX 14 /* 1000baseLX - single-mode fiber */ #define IFM_1000_CX 15 /* 1000baseCX - 150ohm STP */ #define IFM_1000_TX 16 /* 1000baseTX - 4 pair cat 5 */ @@ -163,9 +167,14 @@ int ifmedia_ioctl __P((struct ifnet *ifp, struct ifreq *ifr, #define IFM_TOK_STP16 4 /* Shielded twisted pair 16m - DB9 */ #define IFM_TOK_UTP4 5 /* Unshielded twisted pair 4m - RJ45 */ #define IFM_TOK_UTP16 6 /* Unshielded twisted pair 16m - RJ45 */ +#define IFM_TOK_STP100 7 /* Shielded twisted pair 100m - DB9 */ +#define IFM_TOK_UTP100 8 /* Unshielded twisted pair 100m - RJ45 */ #define IFM_TOK_ETR 0x00000200 /* Early token release */ #define IFM_TOK_SRCRT 0x00000400 /* Enable source routing features */ #define IFM_TOK_ALLR 0x00000800 /* All routes / Single route bcast */ +#define IFM_TOK_DTR 0x00002000 /* Dedicated token ring */ +#define IFM_TOK_CLASSIC 0x00004000 /* Classic token ring */ +#define IFM_TOK_AUTO 0x00008000 /* Automatic Dedicate/Classic token ring */ /* * FDDI @@ -186,6 +195,7 @@ int ifmedia_ioctl __P((struct ifnet *ifp, struct ifreq *ifr, #define IFM_IEEE80211_DS5 6 /* Direct Sequence 5Mbps*/ #define IFM_IEEE80211_DS11 7 /* Direct Sequence 11Mbps*/ #define IFM_IEEE80211_DS1 8 /* Direct Sequence 1Mbps */ +#define IFM_IEEE80211_DS22 9 /* Direct Sequence 22Mbps */ #define IFM_IEEE80211_ADHOC 0x00000100 /* Operate in Adhoc mode */ /* @@ -225,9 +235,19 @@ int ifmedia_ioctl __P((struct ifnet *ifp, struct ifreq *ifr, /* * Macros to extract various bits of information from the media word. */ -#define IFM_TYPE(x) ((x) & IFM_NMASK) -#define IFM_SUBTYPE(x) ((x) & IFM_TMASK) -#define IFM_INST(x) (((x) & IFM_IMASK) >> IFM_ISHIFT) +#define IFM_TYPE(x) ((x) & IFM_NMASK) +#define IFM_SUBTYPE(x) ((x) & IFM_TMASK) +#define IFM_TYPE_OPTIONS(x) ((x) & IFM_OMASK) +#define IFM_INST(x) (((x) & IFM_IMASK) >> IFM_ISHIFT) +#define IFM_OPTIONS(x) ((x) & (IFM_OMASK|IFM_GMASK)) + +#define IFM_INST_MAX IFM_INST(IFM_IMASK) + +/* + * Macro to create a media word. + */ +#define IFM_MAKEWORD(type, subtype, options, instance) \ + ((type) | (subtype) | (options) | ((instance) << IFM_ISHIFT)) /* * NetBSD extension not defined in the BSDI API. This is used in various @@ -345,6 +365,7 @@ struct ifmedia_description { { IFM_IEEE80211_DS2, "DS2" }, \ { IFM_IEEE80211_DS5, "DS5" }, \ { IFM_IEEE80211_DS11, "DS11" }, \ + { IFM_IEEE80211_DS22, "DS22" }, \ { 0, NULL }, \ } diff --git a/bsd/net/if_mib.c b/bsd/net/if_mib.c index c57aa756b..fc94438fe 100644 --- a/bsd/net/if_mib.c +++ b/bsd/net/if_mib.c @@ -47,6 +47,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * $FreeBSD: src/sys/net/if_mib.c,v 1.8.2.1 2000/08/03 00:09:34 ps Exp $ */ #include diff --git a/bsd/net/if_mib.h b/bsd/net/if_mib.h index 6e51fb2ab..dc7417e89 100644 --- a/bsd/net/if_mib.h +++ b/bsd/net/if_mib.h @@ -47,11 +47,14 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * $FreeBSD: src/sys/net/if_mib.h,v 1.6 1999/08/28 00:48:19 peter Exp $ */ #ifndef _NET_IF_MIB_H #define _NET_IF_MIB_H 1 +#include +#ifdef __APPLE_API_UNSTABLE struct ifmibdata { char ifmd_name[IFNAMSIZ]; /* name of interface */ int ifmd_pcount; /* number of promiscuous listeners */ @@ -187,4 +190,5 @@ enum { * Put other types of interface MIBs here, or in interface-specific * header files if convenient ones already exist. */ +#endif /* __APPLE_API_UNSTABLE */ #endif /* _NET_IF_MIB_H */ diff --git a/bsd/net/if_ppp.h b/bsd/net/if_ppp.h index 50e6969ec..9d5f7cd36 100644 --- a/bsd/net/if_ppp.h +++ b/bsd/net/if_ppp.h @@ -37,10 +37,12 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * + * $FreeBSD: src/sys/net/if_ppp.h,v 1.14 1999/08/28 00:48:20 peter Exp $ */ #ifndef _IF_PPP_H_ #define _IF_PPP_H_ +#include /* XXX this used to be self-contained. */ #include diff --git a/bsd/net/if_pppvar.h b/bsd/net/if_pppvar.h index a302b64ad..ec688a95b 100644 --- a/bsd/net/if_pppvar.h +++ b/bsd/net/if_pppvar.h @@ -60,8 +60,16 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * + * $FreeBSD: src/sys/net/if_pppvar.h,v 1.15 2000/01/29 16:56:23 peter Exp $ */ +#include +#ifndef DONT_WARN_OBSOLETE +#warning if_pppvar.h is not used by the darwin kernel +#endif + +#ifdef __APPLE_API_PRIVATE + /* * Supported network protocols. These values are used for * indexing sc_npmode. @@ -118,7 +126,7 @@ struct ppp_softc { int sc_rawin_count; /* # in sc_rawin */ }; -extern struct ppp_softc ppp_softc[NPPP]; +extern struct ppp_softc ppp_softc[]; struct ppp_softc *pppalloc __P((pid_t pid)); void pppdealloc __P((struct ppp_softc *sc)); @@ -129,3 +137,4 @@ int pppoutput __P((struct ifnet *ifp, struct mbuf *m0, void ppp_restart __P((struct ppp_softc *sc)); void ppppktin __P((struct ppp_softc *sc, struct mbuf *m, int lost)); struct mbuf *ppp_dequeue __P((struct ppp_softc *sc)); +#endif /* __APPLE_API_PRIVATE */ diff --git a/bsd/net/if_sl.c b/bsd/net/if_sl.c deleted file mode 100644 index 1ee15c39a..000000000 --- a/bsd/net/if_sl.c +++ /dev/null @@ -1,897 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ -/* - * Copyright (c) 1987, 1989, 1992, 1993 - * 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_sl.c 8.9 (Berkeley) 1/9/95 - */ - -/* - * Serial Line interface - * - * Rick Adams - * Center for Seismic Studies - * 1300 N 17th Street, Suite 1450 - * Arlington, Virginia 22209 - * (703)276-7900 - * rick@seismo.ARPA - * seismo!rick - * - * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris). - * N.B.: this belongs in netinet, not net, the way it stands now. - * Should have a link-layer type designation, but wouldn't be - * backwards-compatible. - * - * Converted to 4.3BSD Beta by Chris Torek. - * Other changes made at Berkeley, based in part on code by Kirk Smith. - * W. Jolitz added slip abort. - * - * Hacked almost beyond recognition by Van Jacobson (van@helios.ee.lbl.gov). - * Added priority queuing for "interactive" traffic; hooks for TCP - * header compression; ICMP filtering (at 2400 baud, some cretin - * pinging you can use up all your bandwidth). Made low clist behavior - * more robust and slightly less likely to hang serial line. - * Sped up a bunch of things. - * - * Note that splimp() is used throughout to block both (tty) input - * interrupts and network activity; thus, splimp must be >= spltty. - */ - -#include "sl.h" -#if NSL > 0 - -#include "bpfilter.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#if INET -#include -#include -#include -#include -#else -Huh? Slip without inet? -#endif - -#include -#include -#include - -#if NBPFILTER > 0 -#include -#include -#endif - -/* - * SLMAX is a hard limit on input packet size. To simplify the code - * and improve performance, we require that packets fit in an mbuf - * cluster, and if we get a compressed packet, there's enough extra - * room to expand the header into a max length tcp/ip header (128 - * bytes). So, SLMAX can be at most - * MCLBYTES - 128 - * - * SLMTU is a hard limit on output packet size. To insure good - * interactive response, SLMTU wants to be the smallest size that - * amortizes the header cost. (Remember that even with - * type-of-service queuing, we have to wait for any in-progress - * packet to finish. I.e., we wait, on the average, 1/2 * mtu / - * cps, where cps is the line speed in characters per second. - * E.g., 533ms wait for a 1024 byte MTU on a 9600 baud line. The - * average compressed header size is 6-8 bytes so any MTU > 90 - * bytes will give us 90% of the line bandwidth. A 100ms wait is - * tolerable (500ms is not), so want an MTU around 296. (Since TCP - * will send 256 byte segments (to allow for 40 byte headers), the - * typical packet size on the wire will be around 260 bytes). In - * 4.3tahoe+ systems, we can set an MTU in a route so we do that & - * leave the interface MTU relatively high (so we don't IP fragment - * when acting as a gateway to someone using a stupid MTU). - * - * Similar considerations apply to SLIP_HIWAT: It's the amount of - * data that will be queued 'downstream' of us (i.e., in clists - * waiting to be picked up by the tty output interrupt). If we - * queue a lot of data downstream, it's immune to our t.o.s. queuing. - * E.g., if SLIP_HIWAT is 1024, the interactive traffic in mixed - * telnet/ftp will see a 1 sec wait, independent of the mtu (the - * wait is dependent on the ftp window size but that's typically - * 1k - 4k). So, we want SLIP_HIWAT just big enough to amortize - * the cost (in idle time on the wire) of the tty driver running - * off the end of its clists & having to call back slstart for a - * new packet. For a tty interface with any buffering at all, this - * cost will be zero. Even with a totally brain dead interface (like - * the one on a typical workstation), the cost will be <= 1 character - * time. So, setting SLIP_HIWAT to ~100 guarantees that we'll lose - * at most 1% while maintaining good interactive response. - */ -#if NBPFILTER > 0 -#define BUFOFFSET (128+sizeof(struct ifnet **)+SLIP_HDRLEN) -#else -#define BUFOFFSET (128+sizeof(struct ifnet **)) -#endif -#define SLMAX (MCLBYTES - BUFOFFSET) -#define SLBUFSIZE (SLMAX + BUFOFFSET) -#define SLMTU 296 -#define SLIP_HIWAT roundup(50,CBSIZE) - -/* - * SLIP ABORT ESCAPE MECHANISM: - * (inspired by HAYES modem escape arrangement) - * 1sec escape 1sec escape 1sec escape { 1sec escape 1sec escape } - * within window time signals a "soft" exit from slip mode by remote end - * if the IFF_DEBUG flag is on. - */ -#define ABT_ESC '\033' /* can't be t_intr - distant host must know it*/ -#define ABT_IDLE 1 /* in seconds - idle before an escape */ -#define ABT_COUNT 3 /* count of escapes for abort */ -#define ABT_WINDOW (ABT_COUNT*2+2) /* in seconds - time to count */ - -struct sl_softc sl_softc[NSL]; - -#define FRAME_END 0xc0 /* Frame End */ -#define FRAME_ESCAPE 0xdb /* Frame Esc */ -#define TRANS_FRAME_END 0xdc /* transposed frame end */ -#define TRANS_FRAME_ESCAPE 0xdd /* transposed frame esc */ - -static int slinit __P((struct sl_softc *)); -static struct mbuf *sl_btom __P((struct sl_softc *, int)); - -/* - * Called from boot code to establish sl interfaces. - */ -void -slattach() -{ - register struct sl_softc *sc; - register int i = 0; - - for (sc = sl_softc; i < NSL; sc++) { - sc->sc_if.if_name = "sl"; - sc->sc_if.if_family = APPLE_IF_FAM_SLIP; - sc->sc_if.if_next = NULL; - sc->sc_if.if_unit = i++; - sc->sc_if.if_mtu = SLMTU; - sc->sc_if.if_flags = - IFF_POINTOPOINT | SC_AUTOCOMP | IFF_MULTICAST; - sc->sc_if.if_type = IFT_SLIP; - sc->sc_if.if_ioctl = slioctl; - sc->sc_if.if_output = sloutput; - sc->sc_if.if_snd.ifq_maxlen = 50; - sc->sc_fastq.ifq_maxlen = 32; - if_attach(&sc->sc_if); -#if NBPFILTER > 0 - bpfattach(&sc->sc_bpf, &sc->sc_if, DLT_SLIP, SLIP_HDRLEN); -#endif - } -} - -static int -slinit(sc) - register struct sl_softc *sc; -{ - register caddr_t p; - - if (sc->sc_ep == (u_char *) 0) { - MCLALLOC(p, M_WAIT); - if (p) - sc->sc_ep = (u_char *)p + SLBUFSIZE; - else { - printf("sl%d: can't allocate buffer\n", sc - sl_softc); - sc->sc_if.if_flags &= ~IFF_UP; - return (0); - } - } - sc->sc_buf = sc->sc_ep - SLMAX; - sc->sc_mp = sc->sc_buf; - sl_compress_init(&sc->sc_comp, -1); - return (1); -} - -/* - * Line specific open routine. - * Attach the given tty to the first available sl unit. - */ -/* ARGSUSED */ -int -slopen(dev, tp) - dev_t dev; - register struct tty *tp; -{ - struct proc *p = curproc; /* XXX */ - register struct sl_softc *sc; - register int nsl; - int error; - int s; - - if (error = suser(p->p_ucred, &p->p_acflag)) - return (error); - - if (tp->t_line == SLIPDISC) - return (0); - - for (nsl = NSL, sc = sl_softc; --nsl >= 0; sc++) - if (sc->sc_ttyp == NULL) { - if (slinit(sc) == 0) - return (ENOBUFS); - tp->t_sc = (caddr_t)sc; - sc->sc_ttyp = tp; - sc->sc_if.if_baudrate = tp->t_ospeed; - ttyflush(tp, FREAD | FWRITE); - - /* - * make sure tty output queue is large enough - * to hold a full-sized packet (including frame - * end, and a possible extra frame end). full-sized - * packet occupies a max of 2*SLMTU bytes (because - * of possible escapes), and add two on for frame - * ends. - */ - s = spltty(); - if (tp->t_outq.c_cn < 2*SLMTU+2) { - sc->sc_oldbufsize = tp->t_outq.c_cn; - sc->sc_oldbufquot = tp->t_outq.c_cq != 0; - - clfree(&tp->t_outq); - error = clalloc(&tp->t_outq, 3*SLMTU, 0); - if (error) { - splx(s); - return(error); - } - } else - sc->sc_oldbufsize = sc->sc_oldbufquot = 0; - splx(s); - - return (0); - } - return (ENXIO); -} - -/* - * Line specific close routine. - * Detach the tty from the sl unit. - */ -void -slclose(tp) - struct tty *tp; -{ - register struct sl_softc *sc; - int s; - - ttywflush(tp); - s = splimp(); /* actually, max(spltty, splnet) */ - tp->t_line = 0; - tp->t_state = 0; - sc = (struct sl_softc *)tp->t_sc; - if (sc != NULL) { - if_down(&sc->sc_if); - sc->sc_ttyp = NULL; - tp->t_sc = NULL; - MCLFREE((caddr_t)(sc->sc_ep - SLBUFSIZE)); - sc->sc_ep = 0; - sc->sc_mp = 0; - sc->sc_buf = 0; - } - /* if necessary, install a new outq buffer of the appropriate size */ - if (sc->sc_oldbufsize != 0) { - clfree(&tp->t_outq); - clalloc(&tp->t_outq, sc->sc_oldbufsize, sc->sc_oldbufquot); - } - splx(s); -} - -/* - * Line specific (tty) ioctl routine. - * Provide a way to get the sl unit number. - */ -/* ARGSUSED */ -int -sltioctl(tp, cmd, data, flag) - struct tty *tp; - u_long cmd; - caddr_t data; - int flag; -{ - struct sl_softc *sc = (struct sl_softc *)tp->t_sc; - - switch (cmd) { - case SLIOCGUNIT: - *(int *)data = sc->sc_if.if_unit; - break; - - default: - return (-1); - } - return (0); -} - -/* - * Queue a packet. Start transmission if not active. - * Compression happens in slstart; if we do it here, IP TOS - * will cause us to not compress "background" packets, because - * ordering gets trashed. It can be done for all packets in slstart. - */ -int -sloutput(ifp, m, dst, rtp) - struct ifnet *ifp; - register struct mbuf *m; - struct sockaddr *dst; - struct rtentry *rtp; -{ - register struct sl_softc *sc = &sl_softc[ifp->if_unit]; - register struct ip *ip; - register struct ifqueue *ifq; - int s; - - /* - * `Cannot happen' (see slioctl). Someday we will extend - * the line protocol to support other address families. - */ - if (dst->sa_family != AF_INET) { - printf("sl%d: af%d not supported\n", sc->sc_if.if_unit, - dst->sa_family); - m_freem(m); - sc->sc_if.if_noproto++; - return (EAFNOSUPPORT); - } - - if (sc->sc_ttyp == NULL) { - m_freem(m); - return (ENETDOWN); /* sort of */ - } - if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0 && - (sc->sc_ttyp->t_cflag & CLOCAL) == 0) { - m_freem(m); - return (EHOSTUNREACH); - } - ifq = &sc->sc_if.if_snd; - ip = mtod(m, struct ip *); - if (sc->sc_if.if_flags & SC_NOICMP && ip->ip_p == IPPROTO_ICMP) { - m_freem(m); - return (ENETRESET); /* XXX ? */ - } - if (ip->ip_tos & IPTOS_LOWDELAY) - ifq = &sc->sc_fastq; - s = splimp(); - if (sc->sc_oqlen && sc->sc_ttyp->t_outq.c_cc == sc->sc_oqlen) { - /* if output's been stalled for too long, and restart */ - timersub(&time, &sc->sc_if.if_lastchange, &tv); - if (tv.tv_sec > 0) { - sc->sc_otimeout++; - slstart(sc->sc_ttyp); - } - } - if (IF_QFULL(ifq)) { - IF_DROP(ifq); - m_freem(m); - splx(s); - sc->sc_if.if_oerrors++; - return (ENOBUFS); - } - IF_ENQUEUE(ifq, m); - sc->sc_if.if_lastchange = time; - if ((sc->sc_oqlen = sc->sc_ttyp->t_outq.c_cc) == 0) - slstart(sc->sc_ttyp); - splx(s); - return (0); -} - -/* - * Start output on interface. Get another datagram - * to send from the interface queue and map it to - * the interface before starting output. - */ -void -slstart(tp) - register struct tty *tp; -{ - register struct sl_softc *sc = (struct sl_softc *)tp->t_sc; - register struct mbuf *m; - register u_char *cp; - register struct ip *ip; - int s; - struct mbuf *m2; -#if NBPFILTER > 0 - u_char bpfbuf[SLMTU + SLIP_HDRLEN]; - register int len; -#endif - - for (;;) { - /* - * If there is more in the output queue, just send it now. - * We are being called in lieu of ttstart and must do what - * it would. - */ - if (tp->t_outq.c_cc != 0) { - (*tp->t_oproc)(tp); - if (tp->t_outq.c_cc > SLIP_HIWAT) - return; - } - /* - * This happens briefly when the line shuts down. - */ - if (sc == NULL) - return; - - /* - * Do not remove the packet from the IP queue if it - * doesn't look like the packet will fit into the - * current serial output queue, with a packet full of - * escapes this could be as bad as SLMTU*2+2. - */ - if (tp->t_outq.c_cn - tp->t_outq.c_cc < 2*SLMTU+2) - return; - - /* - * Get a packet and send it to the interface. - */ - s = splimp(); - IF_DEQUEUE(&sc->sc_fastq, m); - if (m) - sc->sc_if.if_omcasts++; /* XXX */ - else - IF_DEQUEUE(&sc->sc_if.if_snd, m); - splx(s); - if (m == NULL) - return; - - /* - * We do the header compression here rather than in sloutput - * because the packets will be out of order if we are using TOS - * queueing, and the connection id compression will get - * munged when this happens. - */ -#if NBPFILTER > 0 - if (sc->sc_bpf) { - /* - * We need to save the TCP/IP header before it's - * compressed. To avoid complicated code, we just - * copy the entire packet into a stack buffer (since - * this is a serial line, packets should be short - * and/or the copy should be negligible cost compared - * to the packet transmission time). - */ - register struct mbuf *m1 = m; - register u_char *cp = bpfbuf + SLIP_HDRLEN; - - len = 0; - do { - register int mlen = m1->m_len; - - bcopy(mtod(m1, caddr_t), cp, mlen); - cp += mlen; - len += mlen; - } while (m1 = m1->m_next); - } -#endif - if ((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP) { - if (sc->sc_if.if_flags & SC_COMPRESS) - *mtod(m, u_char *) |= sl_compress_tcp(m, ip, - &sc->sc_comp, 1); - } -#if NBPFILTER > 0 - if (sc->sc_bpf) { - /* - * Put the SLIP pseudo-"link header" in place. The - * compressed header is now at the beginning of the - * mbuf. - */ - bpfbuf[SLX_DIR] = SLIPDIR_OUT; - bcopy(mtod(m, caddr_t), &bpfbuf[SLX_CHDR], CHDR_LEN); - BPF_TAP(sc->sc_bpf, bpfbuf, len + SLIP_HDRLEN); - } -#endif - sc->sc_if.if_lastchange = time; - - /* - * The extra FRAME_END will start up a new packet, and thus - * will flush any accumulated garbage. We do this whenever - * the line may have been idle for some time. - */ - if (tp->t_outq.c_cc == 0) { - ++sc->sc_if.if_obytes; - (void) putc(FRAME_END, &tp->t_outq); - } - - while (m) { - register u_char *ep; - - cp = mtod(m, u_char *); ep = cp + m->m_len; - while (cp < ep) { - /* - * Find out how many bytes in the string we can - * handle without doing something special. - */ - register u_char *bp = cp; - - while (cp < ep) { - switch (*cp++) { - case FRAME_ESCAPE: - case FRAME_END: - --cp; - goto out; - } - } - out: - if (cp > bp) { - /* - * Put n characters at once - * into the tty output queue. - */ - if (b_to_q((u_char *)bp, cp - bp, - &tp->t_outq)) - break; - sc->sc_if.if_obytes += cp - bp; - } - /* - * If there are characters left in the mbuf, - * the first one must be special.. - * Put it out in a different form. - */ - if (cp < ep) { - if (putc(FRAME_ESCAPE, &tp->t_outq)) - break; - if (putc(*cp++ == FRAME_ESCAPE ? - TRANS_FRAME_ESCAPE : TRANS_FRAME_END, - &tp->t_outq)) { - (void) unputc(&tp->t_outq); - break; - } - sc->sc_if.if_obytes += 2; - } - } - MFREE(m, m2); - m = m2; - } - - if (putc(FRAME_END, &tp->t_outq)) { - /* - * Not enough room. Remove a char to make room - * and end the packet normally. - * If you get many collisions (more than one or two - * a day) you probably do not have enough clists - * and you should increase "nclist" in param.c. - */ - (void) unputc(&tp->t_outq); - (void) putc(FRAME_END, &tp->t_outq); - sc->sc_if.if_collisions++; - } else { - ++sc->sc_if.if_obytes; - sc->sc_if.if_opackets++; - } - } -} - -/* - * Copy data buffer to mbuf chain; add ifnet pointer. - */ -static struct mbuf * -sl_btom(sc, len) - register struct sl_softc *sc; - register int len; -{ - register struct mbuf *m; - - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) - return (NULL); - - /* - * If we have more than MHLEN bytes, it's cheaper to - * queue the cluster we just filled & allocate a new one - * for the input buffer. Otherwise, fill the mbuf we - * allocated above. Note that code in the input routine - * guarantees that packet will fit in a cluster. - */ - if (len >= MHLEN) { - MCLGET(m, M_DONTWAIT); - if ((m->m_flags & M_EXT) == 0) { - /* - * we couldn't get a cluster - if memory's this - * low, it's time to start dropping packets. - */ - (void) m_free(m); - return (NULL); - } - sc->sc_ep = mtod(m, u_char *) + SLBUFSIZE; - m->m_data = (caddr_t)sc->sc_buf; - m->m_ext.ext_buf = (caddr_t)((long)sc->sc_buf &~ MCLOFSET); - } else - bcopy((caddr_t)sc->sc_buf, mtod(m, caddr_t), len); - - m->m_len = len; - m->m_pkthdr.len = len; - m->m_pkthdr.rcvif = &sc->sc_if; - return (m); -} - -/* - * tty interface receiver interrupt. - */ -void -slinput(c, tp) - register int c; - register struct tty *tp; -{ - register struct sl_softc *sc; - register struct mbuf *m; - register int len; - int s; -#if NBPFILTER > 0 - u_char chdr[CHDR_LEN]; -#endif - - tk_nin++; - sc = (struct sl_softc *)tp->t_sc; - if (sc == NULL) - return; - if (c & TTY_ERRORMASK || ((tp->t_state & TS_CARR_ON) == 0 && - (tp->t_cflag & CLOCAL) == 0)) { - sc->sc_flags |= SC_ERROR; - return; - } - c &= TTY_CHARMASK; - - ++sc->sc_if.if_ibytes; - - if (sc->sc_if.if_flags & IFF_DEBUG) { - - if (c == ABT_ESC) { - /* - * If we have a previous abort, see whether - * this one is within the time limit. - */ - if (sc->sc_abortcount && - time.tv_sec >= sc->sc_starttime + ABT_WINDOW) - sc->sc_abortcount = 0; - /* - * If we see an abort after "idle" time, count it; - * record when the first abort escape arrived. - */ - if (time.tv_sec >= sc->sc_lasttime + ABT_IDLE) { - if (++sc->sc_abortcount == 1) - sc->sc_starttime = time.tv_sec; - if (sc->sc_abortcount >= ABT_COUNT) { - slclose(tp); - return; - } - } - } else - sc->sc_abortcount = 0; - sc->sc_lasttime = time.tv_sec; - } - - switch (c) { - - case TRANS_FRAME_ESCAPE: - if (sc->sc_escape) - c = FRAME_ESCAPE; - break; - - case TRANS_FRAME_END: - if (sc->sc_escape) - c = FRAME_END; - break; - - case FRAME_ESCAPE: - sc->sc_escape = 1; - return; - - case FRAME_END: - if(sc->sc_flags & SC_ERROR) { - sc->sc_flags &= ~SC_ERROR; - goto newpack; - } - len = sc->sc_mp - sc->sc_buf; - if (len < 3) - /* less than min length packet - ignore */ - goto newpack; - -#if NBPFILTER > 0 - if (sc->sc_bpf) { - /* - * Save the compressed header, so we - * can tack it on later. Note that we - * will end up copying garbage in some - * cases but this is okay. We remember - * where the buffer started so we can - * compute the new header length. - */ - bcopy(sc->sc_buf, chdr, CHDR_LEN); - } -#endif - - if ((c = (*sc->sc_buf & 0xf0)) != (IPVERSION << 4)) { - if (c & 0x80) - c = TYPE_COMPRESSED_TCP; - else if (c == TYPE_UNCOMPRESSED_TCP) - *sc->sc_buf &= 0x4f; /* XXX */ - /* - * We've got something that's not an IP packet. - * If compression is enabled, try to decompress it. - * Otherwise, if `auto-enable' compression is on and - * it's a reasonable packet, decompress it and then - * enable compression. Otherwise, drop it. - */ - if (sc->sc_if.if_flags & SC_COMPRESS) { - len = sl_uncompress_tcp(&sc->sc_buf, len, - (u_int)c, &sc->sc_comp); - if (len <= 0) - goto error; - } else if ((sc->sc_if.if_flags & SC_AUTOCOMP) && - c == TYPE_UNCOMPRESSED_TCP && len >= 40) { - len = sl_uncompress_tcp(&sc->sc_buf, len, - (u_int)c, &sc->sc_comp); - if (len <= 0) - goto error; - sc->sc_if.if_flags |= SC_COMPRESS; - } else - goto error; - } -#if NBPFILTER > 0 - if (sc->sc_bpf) { - /* - * Put the SLIP pseudo-"link header" in place. - * We couldn't do this any earlier since - * decompression probably moved the buffer - * pointer. Then, invoke BPF. - */ - register u_char *hp = sc->sc_buf - SLIP_HDRLEN; - - hp[SLX_DIR] = SLIPDIR_IN; - bcopy(chdr, &hp[SLX_CHDR], CHDR_LEN); - BPF_TAP(sc->sc_bpf, hp, len + SLIP_HDRLEN); - } -#endif - m = sl_btom(sc, len); - if (m == NULL) - goto error; - - sc->sc_if.if_ipackets++; - sc->sc_if.if_lastchange = time; - s = splimp(); - if (IF_QFULL(&ipintrq)) { - IF_DROP(&ipintrq); - sc->sc_if.if_ierrors++; - sc->sc_if.if_iqdrops++; - m_freem(m); - } else { - IF_ENQUEUE(&ipintrq, m); - schednetisr(NETISR_IP); - } - splx(s); - goto newpack; - } - if (sc->sc_mp < sc->sc_ep) { - *sc->sc_mp++ = c; - sc->sc_escape = 0; - return; - } - - /* can't put lower; would miss an extra frame */ - sc->sc_flags |= SC_ERROR; - -error: - sc->sc_if.if_ierrors++; -newpack: - sc->sc_mp = sc->sc_buf = sc->sc_ep - SLMAX; - sc->sc_escape = 0; -} - -/* - * Process an ioctl request. - */ -int -slioctl(ifp, cmd, data) - register struct ifnet *ifp; - u_long cmd; - caddr_t data; -{ - register struct ifaddr *ifa = (struct ifaddr *)data; - register struct ifreq *ifr; - register int s = splimp(), error = 0; - - switch (cmd) { - - case SIOCSIFADDR: - if (ifa->ifa_addr->sa_family == AF_INET) - ifp->if_flags |= IFF_UP; - else - error = EAFNOSUPPORT; - break; - - case SIOCSIFDSTADDR: - if (ifa->ifa_addr->sa_family != AF_INET) - error = EAFNOSUPPORT; - break; - - case SIOCADDMULTI: - case SIOCDELMULTI: - ifr = (struct ifreq *)data; - if (ifr == 0) { - error = EAFNOSUPPORT; /* XXX */ - break; - } - switch (ifr->ifr_addr.sa_family) { - -#if INET - case AF_INET: - break; -#endif - - default: - error = EAFNOSUPPORT; - break; - } - break; - - default: - error = EINVAL; - } - splx(s); - return (error); -} -#endif diff --git a/bsd/net/if_slvar.h b/bsd/net/if_slvar.h index 25786201c..cb3132ef1 100644 --- a/bsd/net/if_slvar.h +++ b/bsd/net/if_slvar.h @@ -57,11 +57,17 @@ #ifndef _NET_IF_SLVAR_H_ #define _NET_IF_SLVAR_H_ +#include + +#ifndef DONT_WARN_OBSOLETE +#warning if_slvar.h is not used by the darwin kernel +#endif #include #include #include +#ifdef __APPLE_API_PRIVATE /* * Definitions for SLIP interface data structures @@ -105,5 +111,5 @@ struct sl_softc { #define SC_NOICMP IFF_LINK1 /* suppress ICMP traffic */ #define SC_AUTOCOMP IFF_LINK2 /* auto-enable TCP compression */ - +#endif /* __APPLE_API_PRIVATE */ #endif diff --git a/bsd/net/if_sppp.h b/bsd/net/if_sppp.h index 713ef0832..f0b6435bc 100644 --- a/bsd/net/if_sppp.h +++ b/bsd/net/if_sppp.h @@ -41,6 +41,11 @@ #ifndef _NET_IF_SPPP_H_ #define _NET_IF_SPPP_H_ 1 +#include + +#ifndef DONT_WARN_OBSOLETE +#warning if_sppp.h is not used by the darwin kernel +#endif #define IDX_LCP 0 /* idx into state table */ @@ -97,6 +102,7 @@ enum ppp_phase { PHASE_AUTHENTICATE, PHASE_NETWORK }; +#ifdef __APPLE_API_PRIVATE struct sppp { /* NB: pp_if _must_ be first */ struct ifnet pp_if; /* network interface data */ @@ -151,6 +157,8 @@ struct sppp { int pp_loweri; }; +#endif /* __APPLE_API_PRIVATE */ + #define PP_KEEPALIVE 0x01 /* use keepalive protocol */ #define PP_CISCO 0x02 /* use Cisco protocol instead of PPP */ /* 0x04 was PP_TIMO */ @@ -182,6 +190,7 @@ struct spppreq { }; #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE void sppp_attach (struct ifnet *ifp); void sppp_detach (struct ifnet *ifp); void sppp_input (struct ifnet *ifp, struct mbuf *m); @@ -190,6 +199,7 @@ struct mbuf *sppp_dequeue (struct ifnet *ifp); struct mbuf *sppp_pick(struct ifnet *ifp); int sppp_isempty (struct ifnet *ifp); void sppp_flush (struct ifnet *ifp); +#endif /* __APPLE_API_PRIVATE */ #endif #endif /* _NET_IF_SPPP_H_ */ diff --git a/bsd/net/if_spppsubr.c b/bsd/net/if_spppsubr.c deleted file mode 100644 index 6d621b2f6..000000000 --- a/bsd/net/if_spppsubr.c +++ /dev/null @@ -1,4295 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Synchronous PPP/Cisco link level subroutines. - * Keepalive protocol implemented in both Cisco and PPP modes. - * - * Copyright (C) 1994-1996 Cronyx Engineering Ltd. - * Author: Serge Vakulenko, - * - * Heavily revamped to conform to RFC 1661. - * Copyright (C) 1997, Joerg Wunsch. - * - * This software is distributed with NO WARRANTIES, not even the implied - * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Authors grant any other persons or organisations permission to use - * or modify this software as long as this message is kept with the software, - * all derivative works or modified versions. - * - * From: Version 2.4, Thu Apr 30 17:17:21 MSD 1997 - * - */ - -#include - -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -#include "opt_inet.h" -#include "opt_ipx.h" -#endif - -#ifdef NetBSD1_3 -# if NetBSD1_3 > 6 -# include "opt_inet.h" -# include "opt_iso.h" -# endif -#endif - -#include -#include -#include -#include -#include -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -#include -#endif -#include -#include - - -#if defined (__OpenBSD__) -#include -#else -#include -#endif - -#include -#include -#include -#include - -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -#include -#endif -#if defined (__NetBSD__) || defined (__OpenBSD__) -#include /* XXX for softnet */ -#endif - -#include - -#if INET -#include -#include -#include -#include -#include -# if defined (__FreeBSD__) || defined (__OpenBSD__) -# include -# else -# include -# endif -#else -# error Huh? sppp without INET? -#endif - -#if IPX -#include -#include -#endif - -#if NS -#include -#include -#endif - -#if ISO -#include -#include -#include -#include -#endif - -#include - -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -# define UNTIMEOUT(fun, arg, handle) untimeout(fun, arg, handle) -# define TIMEOUT(fun, arg1, arg2, handle) handle = timeout(fun, arg1, arg2) -# define IOCTL_CMD_T u_long -#else -# define UNTIMEOUT(fun, arg, handle) untimeout(fun, arg) -# define TIMEOUT(fun, arg1, arg2, handle) timeout(fun, arg1, arg2) -# define IOCTL_CMD_T int -#endif - -#define MAXALIVECNT 3 /* max. alive packets */ - -/* - * Interface flags that can be set in an ifconfig command. - * - * Setting link0 will make the link passive, i.e. it will be marked - * as being administrative openable, but won't be opened to begin - * with. Incoming calls will be answered, or subsequent calls with - * -link1 will cause the administrative open of the LCP layer. - * - * Setting link1 will cause the link to auto-dial only as packets - * arrive to be sent. - * - * Setting IFF_DEBUG will syslog the option negotiation and state - * transitions at level kern.debug. Note: all logs consistently look - * like - * - * : - * - * with being something like "bppp0", and - * being one of "lcp", "ipcp", "cisco", "chap", "pap", etc. - */ - -#define IFF_PASSIVE IFF_LINK0 /* wait passively for connection */ -#define IFF_AUTO IFF_LINK1 /* auto-dial on output */ - -#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ -#define PPP_UI 0x03 /* Unnumbered Information */ -#define PPP_IP 0x0021 /* Internet Protocol */ -#define PPP_ISO 0x0023 /* ISO OSI Protocol */ -#define PPP_XNS 0x0025 /* Xerox NS Protocol */ -#define PPP_IPX 0x002b /* Novell IPX Protocol */ -#define PPP_LCP 0xc021 /* Link Control Protocol */ -#define PPP_PAP 0xc023 /* Password Authentication Protocol */ -#define PPP_CHAP 0xc223 /* Challenge-Handshake Auth Protocol */ -#define PPP_IPCP 0x8021 /* Internet Protocol Control Protocol */ - -#define CONF_REQ 1 /* PPP configure request */ -#define CONF_ACK 2 /* PPP configure acknowledge */ -#define CONF_NAK 3 /* PPP configure negative ack */ -#define CONF_REJ 4 /* PPP configure reject */ -#define TERM_REQ 5 /* PPP terminate request */ -#define TERM_ACK 6 /* PPP terminate acknowledge */ -#define CODE_REJ 7 /* PPP code reject */ -#define PROTO_REJ 8 /* PPP protocol reject */ -#define ECHO_REQ 9 /* PPP echo request */ -#define ECHO_REPLY 10 /* PPP echo reply */ -#define DISC_REQ 11 /* PPP discard request */ - -#define LCP_OPT_MRU 1 /* maximum receive unit */ -#define LCP_OPT_ASYNC_MAP 2 /* async control character map */ -#define LCP_OPT_AUTH_PROTO 3 /* authentication protocol */ -#define LCP_OPT_QUAL_PROTO 4 /* quality protocol */ -#define LCP_OPT_MAGIC 5 /* magic number */ -#define LCP_OPT_RESERVED 6 /* reserved */ -#define LCP_OPT_PROTO_COMP 7 /* protocol field compression */ -#define LCP_OPT_ADDR_COMP 8 /* address/control field compression */ - -#define IPCP_OPT_ADDRESSES 1 /* both IP addresses; deprecated */ -#define IPCP_OPT_COMPRESSION 2 /* IP compression protocol (VJ) */ -#define IPCP_OPT_ADDRESS 3 /* local IP address */ - -#define PAP_REQ 1 /* PAP name/password request */ -#define PAP_ACK 2 /* PAP acknowledge */ -#define PAP_NAK 3 /* PAP fail */ - -#define CHAP_CHALLENGE 1 /* CHAP challenge request */ -#define CHAP_RESPONSE 2 /* CHAP challenge response */ -#define CHAP_SUCCESS 3 /* CHAP response ok */ -#define CHAP_FAILURE 4 /* CHAP response failed */ - -#define CHAP_MD5 5 /* hash algorithm - MD5 */ - -#define CISCO_MULTICAST 0x8f /* Cisco multicast address */ -#define CISCO_UNICAST 0x0f /* Cisco unicast address */ -#define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */ -#define CISCO_ADDR_REQ 0 /* Cisco address request */ -#define CISCO_ADDR_REPLY 1 /* Cisco address reply */ -#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */ - -/* states are named and numbered according to RFC 1661 */ -#define STATE_INITIAL 0 -#define STATE_STARTING 1 -#define STATE_CLOSED 2 -#define STATE_STOPPED 3 -#define STATE_CLOSING 4 -#define STATE_STOPPING 5 -#define STATE_REQ_SENT 6 -#define STATE_ACK_RCVD 7 -#define STATE_ACK_SENT 8 -#define STATE_OPENED 9 - -struct ppp_header { - u_char address; - u_char control; - u_short protocol; -}; -#define PPP_HEADER_LEN sizeof (struct ppp_header) - -struct lcp_header { - u_char type; - u_char ident; - u_short len; -}; -#define LCP_HEADER_LEN sizeof (struct lcp_header) - -struct cisco_packet { - u_long type; - u_long par1; - u_long par2; - u_short rel; - u_short time0; - u_short time1; -}; -#define CISCO_PACKET_LEN 18 - -/* - * We follow the spelling and capitalization of RFC 1661 here, to make - * it easier comparing with the standard. Please refer to this RFC in - * case you can't make sense out of these abbreviation; it will also - * explain the semantics related to the various events and actions. - */ -struct cp { - u_short proto; /* PPP control protocol number */ - u_char protoidx; /* index into state table in struct sppp */ - u_char flags; -#define CP_LCP 0x01 /* this is the LCP */ -#define CP_AUTH 0x02 /* this is an authentication protocol */ -#define CP_NCP 0x04 /* this is a NCP */ -#define CP_QUAL 0x08 /* this is a quality reporting protocol */ - const char *name; /* name of this control protocol */ - /* event handlers */ - void (*Up)(struct sppp *sp); - void (*Down)(struct sppp *sp); - void (*Open)(struct sppp *sp); - void (*Close)(struct sppp *sp); - void (*TO)(void *sp); - int (*RCR)(struct sppp *sp, struct lcp_header *h, int len); - void (*RCN_rej)(struct sppp *sp, struct lcp_header *h, int len); - void (*RCN_nak)(struct sppp *sp, struct lcp_header *h, int len); - /* actions */ - void (*tlu)(struct sppp *sp); - void (*tld)(struct sppp *sp); - void (*tls)(struct sppp *sp); - void (*tlf)(struct sppp *sp); - void (*scr)(struct sppp *sp); -}; - -static struct sppp *spppq; -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -static struct callout_handle keepalive_ch; -#endif - -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -#define SPP_FMT "%s%d: " -#define SPP_ARGS(ifp) (ifp)->if_name, (ifp)->if_unit -#else -#define SPP_FMT "%s: " -#define SPP_ARGS(ifp) (ifp)->if_xname -#endif - -/* - * The following disgusting hack gets around the problem that IP TOS - * can't be set yet. We want to put "interactive" traffic on a high - * priority queue. To decide if traffic is interactive, we check that - * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control. - * - * XXX is this really still necessary? - joerg - - */ -static u_short interactive_ports[8] = { - 0, 513, 0, 0, - 0, 21, 0, 23, -}; -#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p)) - -/* almost every function needs these */ -#define STDDCL \ - struct ifnet *ifp = &sp->pp_if; \ - int debug = ifp->if_flags & IFF_DEBUG - -static int sppp_output(struct ifnet *ifp, struct mbuf *m, - struct sockaddr *dst, struct rtentry *rt); - -static void sppp_cisco_send(struct sppp *sp, int type, long par1, long par2); -static void sppp_cisco_input(struct sppp *sp, struct mbuf *m); - -static void sppp_cp_input(const struct cp *cp, struct sppp *sp, - struct mbuf *m); -static void sppp_cp_send(struct sppp *sp, u_short proto, u_char type, - u_char ident, u_short len, void *data); -/* static void sppp_cp_timeout(void *arg); */ -static void sppp_cp_change_state(const struct cp *cp, struct sppp *sp, - int newstate); -static void sppp_auth_send(const struct cp *cp, - struct sppp *sp, unsigned int type, unsigned int id, - ...); - -static void sppp_up_event(const struct cp *cp, struct sppp *sp); -static void sppp_down_event(const struct cp *cp, struct sppp *sp); -static void sppp_open_event(const struct cp *cp, struct sppp *sp); -static void sppp_close_event(const struct cp *cp, struct sppp *sp); -static void sppp_to_event(const struct cp *cp, struct sppp *sp); - -static void sppp_null(struct sppp *sp); - -static void sppp_lcp_init(struct sppp *sp); -static void sppp_lcp_up(struct sppp *sp); -static void sppp_lcp_down(struct sppp *sp); -static void sppp_lcp_open(struct sppp *sp); -static void sppp_lcp_close(struct sppp *sp); -static void sppp_lcp_TO(void *sp); -static int sppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len); -static void sppp_lcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len); -static void sppp_lcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len); -static void sppp_lcp_tlu(struct sppp *sp); -static void sppp_lcp_tld(struct sppp *sp); -static void sppp_lcp_tls(struct sppp *sp); -static void sppp_lcp_tlf(struct sppp *sp); -static void sppp_lcp_scr(struct sppp *sp); -static void sppp_lcp_check_and_close(struct sppp *sp); -static int sppp_ncp_check(struct sppp *sp); - -static void sppp_ipcp_init(struct sppp *sp); -static void sppp_ipcp_up(struct sppp *sp); -static void sppp_ipcp_down(struct sppp *sp); -static void sppp_ipcp_open(struct sppp *sp); -static void sppp_ipcp_close(struct sppp *sp); -static void sppp_ipcp_TO(void *sp); -static int sppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len); -static void sppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len); -static void sppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len); -static void sppp_ipcp_tlu(struct sppp *sp); -static void sppp_ipcp_tld(struct sppp *sp); -static void sppp_ipcp_tls(struct sppp *sp); -static void sppp_ipcp_tlf(struct sppp *sp); -static void sppp_ipcp_scr(struct sppp *sp); - -static void sppp_pap_input(struct sppp *sp, struct mbuf *m); -static void sppp_pap_init(struct sppp *sp); -static void sppp_pap_open(struct sppp *sp); -static void sppp_pap_close(struct sppp *sp); -static void sppp_pap_TO(void *sp); -static void sppp_pap_my_TO(void *sp); -static void sppp_pap_tlu(struct sppp *sp); -static void sppp_pap_tld(struct sppp *sp); -static void sppp_pap_scr(struct sppp *sp); - -static void sppp_chap_input(struct sppp *sp, struct mbuf *m); -static void sppp_chap_init(struct sppp *sp); -static void sppp_chap_open(struct sppp *sp); -static void sppp_chap_close(struct sppp *sp); -static void sppp_chap_TO(void *sp); -static void sppp_chap_tlu(struct sppp *sp); -static void sppp_chap_tld(struct sppp *sp); -static void sppp_chap_scr(struct sppp *sp); - -static const char *sppp_auth_type_name(u_short proto, u_char type); -static const char *sppp_cp_type_name(u_char type); -static const char *sppp_dotted_quad(u_long addr); -static const char *sppp_ipcp_opt_name(u_char opt); -static const char *sppp_lcp_opt_name(u_char opt); -static const char *sppp_phase_name(enum ppp_phase phase); -static const char *sppp_proto_name(u_short proto); -static const char *sppp_state_name(int state); -static int sppp_params(struct sppp *sp, u_long cmd, void *data); -static int sppp_strnlen(u_char *p, int max); -static void sppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst, - u_long *srcmask); -static void sppp_keepalive(void *dummy); -static void sppp_phase_network(struct sppp *sp); -static void sppp_print_bytes(const u_char *p, u_short len); -static void sppp_print_string(const char *p, u_short len); -static void sppp_qflush(struct ifqueue *ifq); -static void sppp_set_ip_addr(struct sppp *sp, u_long src); - -/* our control protocol descriptors */ -static const struct cp lcp = { - PPP_LCP, IDX_LCP, CP_LCP, "lcp", - sppp_lcp_up, sppp_lcp_down, sppp_lcp_open, sppp_lcp_close, - sppp_lcp_TO, sppp_lcp_RCR, sppp_lcp_RCN_rej, sppp_lcp_RCN_nak, - sppp_lcp_tlu, sppp_lcp_tld, sppp_lcp_tls, sppp_lcp_tlf, - sppp_lcp_scr -}; - -static const struct cp ipcp = { - PPP_IPCP, IDX_IPCP, CP_NCP, "ipcp", - sppp_ipcp_up, sppp_ipcp_down, sppp_ipcp_open, sppp_ipcp_close, - sppp_ipcp_TO, sppp_ipcp_RCR, sppp_ipcp_RCN_rej, sppp_ipcp_RCN_nak, - sppp_ipcp_tlu, sppp_ipcp_tld, sppp_ipcp_tls, sppp_ipcp_tlf, - sppp_ipcp_scr -}; - -static const struct cp pap = { - PPP_PAP, IDX_PAP, CP_AUTH, "pap", - sppp_null, sppp_null, sppp_pap_open, sppp_pap_close, - sppp_pap_TO, 0, 0, 0, - sppp_pap_tlu, sppp_pap_tld, sppp_null, sppp_null, - sppp_pap_scr -}; - -static const struct cp chap = { - PPP_CHAP, IDX_CHAP, CP_AUTH, "chap", - sppp_null, sppp_null, sppp_chap_open, sppp_chap_close, - sppp_chap_TO, 0, 0, 0, - sppp_chap_tlu, sppp_chap_tld, sppp_null, sppp_null, - sppp_chap_scr -}; - -static const struct cp *cps[IDX_COUNT] = { - &lcp, /* IDX_LCP */ - &ipcp, /* IDX_IPCP */ - &pap, /* IDX_PAP */ - &chap, /* IDX_CHAP */ -}; - - - /* - * Exported functions, comprising our interface to the lower layer. - */ - -/* - * Process the received packet. - */ -void -sppp_input(struct ifnet *ifp, struct mbuf *m) -{ - struct ppp_header *h; - struct ifqueue *inq = 0; - int s; - struct sppp *sp = (struct sppp *)ifp; - int debug = ifp->if_flags & IFF_DEBUG; - - if (ifp->if_flags & IFF_UP) - /* Count received bytes, add FCS and one flag */ - ifp->if_ibytes += m->m_pkthdr.len + 3; - - if (m->m_pkthdr.len <= PPP_HEADER_LEN) { - /* Too small packet, drop it. */ - if (debug) - log(LOG_DEBUG, - SPP_FMT "input packet is too small, %d bytes\n", - SPP_ARGS(ifp), m->m_pkthdr.len); - drop: - ++ifp->if_ierrors; - ++ifp->if_iqdrops; - m_freem (m); - return; - } - - /* Get PPP header. */ - h = mtod (m, struct ppp_header*); - m_adj (m, PPP_HEADER_LEN); - - switch (h->address) { - case PPP_ALLSTATIONS: - if (h->control != PPP_UI) - goto invalid; - if (sp->pp_flags & PP_CISCO) { - if (debug) - log(LOG_DEBUG, - SPP_FMT "PPP packet in Cisco mode " - "\n", - SPP_ARGS(ifp), - h->address, h->control, ntohs(h->protocol)); - goto drop; - } - switch (ntohs (h->protocol)) { - default: - if (sp->state[IDX_LCP] == STATE_OPENED) - sppp_cp_send (sp, PPP_LCP, PROTO_REJ, - ++sp->pp_seq, m->m_pkthdr.len + 2, - &h->protocol); - if (debug) - log(LOG_DEBUG, - SPP_FMT "invalid input protocol " - "\n", - SPP_ARGS(ifp), - h->address, h->control, ntohs(h->protocol)); - ++ifp->if_noproto; - goto drop; - case PPP_LCP: - sppp_cp_input(&lcp, sp, m); - m_freem (m); - return; - case PPP_PAP: - if (sp->pp_phase >= PHASE_AUTHENTICATE) - sppp_pap_input(sp, m); - m_freem (m); - return; - case PPP_CHAP: - if (sp->pp_phase >= PHASE_AUTHENTICATE) - sppp_chap_input(sp, m); - m_freem (m); - return; -#if INET - case PPP_IPCP: - if (sp->pp_phase == PHASE_NETWORK) - sppp_cp_input(&ipcp, sp, m); - m_freem (m); - return; - case PPP_IP: - if (sp->state[IDX_IPCP] == STATE_OPENED) { - schednetisr (NETISR_IP); - inq = &ipintrq; - } - break; -#endif -#if IPX - case PPP_IPX: - /* IPX IPXCP not implemented yet */ - if (sp->pp_phase == PHASE_NETWORK) { - schednetisr (NETISR_IPX); - inq = &ipxintrq; - } - break; -#endif -#if NS - case PPP_XNS: - /* XNS IDPCP not implemented yet */ - if (sp->pp_phase == PHASE_NETWORK) { - schednetisr (NETISR_NS); - inq = &nsintrq; - } - break; -#endif -#if ISO - case PPP_ISO: - /* OSI NLCP not implemented yet */ - if (sp->pp_phase == PHASE_NETWORK) { - schednetisr (NETISR_ISO); - inq = &clnlintrq; - } - break; -#endif - } - break; - case CISCO_MULTICAST: - case CISCO_UNICAST: - /* Don't check the control field here (RFC 1547). */ - if (! (sp->pp_flags & PP_CISCO)) { - if (debug) - log(LOG_DEBUG, - SPP_FMT "Cisco packet in PPP mode " - "\n", - SPP_ARGS(ifp), - h->address, h->control, ntohs(h->protocol)); - goto drop; - } - switch (ntohs (h->protocol)) { - default: - ++ifp->if_noproto; - goto invalid; - case CISCO_KEEPALIVE: - sppp_cisco_input ((struct sppp*) ifp, m); - m_freem (m); - return; -#if INET - case ETHERTYPE_IP: - schednetisr (NETISR_IP); - inq = &ipintrq; - break; -#endif -#if IPX - case ETHERTYPE_IPX: - schednetisr (NETISR_IPX); - inq = &ipxintrq; - break; -#endif -#if NS - case ETHERTYPE_NS: - schednetisr (NETISR_NS); - inq = &nsintrq; - break; -#endif - } - break; - default: /* Invalid PPP packet. */ - invalid: - if (debug) - log(LOG_DEBUG, - SPP_FMT "invalid input packet " - "\n", - SPP_ARGS(ifp), - h->address, h->control, ntohs(h->protocol)); - goto drop; - } - - if (! (ifp->if_flags & IFF_UP) || ! inq) - goto drop; - - /* Check queue. */ - s = splimp(); - if (IF_QFULL (inq)) { - /* Queue overflow. */ - IF_DROP(inq); - splx(s); - if (debug) - log(LOG_DEBUG, SPP_FMT "protocol queue overflow\n", - SPP_ARGS(ifp)); - goto drop; - } - IF_ENQUEUE(inq, m); - splx(s); -} - -/* - * Enqueue transmit packet. - */ -static int -sppp_output(struct ifnet *ifp, struct mbuf *m, - struct sockaddr *dst, struct rtentry *rt) -{ - struct sppp *sp = (struct sppp*) ifp; - struct ppp_header *h; - struct ifqueue *ifq; - int s, rv = 0; - int debug = ifp->if_flags & IFF_DEBUG; - - s = splimp(); - - if ((ifp->if_flags & IFF_UP) == 0 || - (ifp->if_flags & (IFF_RUNNING | IFF_AUTO)) == 0) { - m_freem (m); - splx (s); - return (ENETDOWN); - } - - if ((ifp->if_flags & (IFF_RUNNING | IFF_AUTO)) == IFF_AUTO) { - /* - * Interface is not yet running, but auto-dial. Need - * to start LCP for it. - */ - ifp->if_flags |= IFF_RUNNING; - splx(s); - lcp.Open(sp); - s = splimp(); - } - - ifq = &ifp->if_snd; -#if INET - if (dst->sa_family == AF_INET) { - /* XXX Check mbuf length here? */ - struct ip *ip = mtod (m, struct ip*); - struct tcphdr *tcp = (struct tcphdr*) ((long*)ip + ip->ip_hl); - - /* - * When using dynamic local IP address assignment by using - * 0.0.0.0 as a local address, the first TCP session will - * not connect because the local TCP checksum is computed - * using 0.0.0.0 which will later become our real IP address - * so the TCP checksum computed at the remote end will - * become invalid. So we - * - don't let packets with src ip addr 0 thru - * - we flag TCP packets with src ip 0 as an error - */ - - if(ip->ip_src.s_addr == INADDR_ANY) /* -hm */ - { - m_freem(m); - splx(s); - if(ip->ip_p == IPPROTO_TCP) - return(EADDRNOTAVAIL); - else - return(0); - } - - /* - * Put low delay, telnet, rlogin and ftp control packets - * in front of the queue. - */ - if (IF_QFULL (&sp->pp_fastq)) - ; - else if (ip->ip_tos & IPTOS_LOWDELAY) - ifq = &sp->pp_fastq; - else if (m->m_len < sizeof *ip + sizeof *tcp) - ; - else if (ip->ip_p != IPPROTO_TCP) - ; - else if (INTERACTIVE (ntohs (tcp->th_sport))) - ifq = &sp->pp_fastq; - else if (INTERACTIVE (ntohs (tcp->th_dport))) - ifq = &sp->pp_fastq; - } -#endif - - /* - * Prepend general data packet PPP header. For now, IP only. - */ - M_PREPEND (m, PPP_HEADER_LEN, M_DONTWAIT); - if (! m) { - if (debug) - log(LOG_DEBUG, SPP_FMT "no memory for transmit header\n", - SPP_ARGS(ifp)); - ++ifp->if_oerrors; - splx (s); - return (ENOBUFS); - } - /* - * May want to check size of packet - * (albeit due to the implementation it's always enough) - */ - h = mtod (m, struct ppp_header*); - if (sp->pp_flags & PP_CISCO) { - h->address = CISCO_UNICAST; /* unicast address */ - h->control = 0; - } else { - h->address = PPP_ALLSTATIONS; /* broadcast address */ - h->control = PPP_UI; /* Unnumbered Info */ - } - - switch (dst->sa_family) { -#if INET - case AF_INET: /* Internet Protocol */ - if (sp->pp_flags & PP_CISCO) - h->protocol = htons (ETHERTYPE_IP); - else { - /* - * Don't choke with an ENETDOWN early. It's - * possible that we just started dialing out, - * so don't drop the packet immediately. If - * we notice that we run out of buffer space - * below, we will however remember that we are - * not ready to carry IP packets, and return - * ENETDOWN, as opposed to ENOBUFS. - */ - h->protocol = htons(PPP_IP); - if (sp->state[IDX_IPCP] != STATE_OPENED) - rv = ENETDOWN; - } - break; -#endif -#if NS - case AF_NS: /* Xerox NS Protocol */ - h->protocol = htons ((sp->pp_flags & PP_CISCO) ? - ETHERTYPE_NS : PPP_XNS); - break; -#endif -#if IPX - case AF_IPX: /* Novell IPX Protocol */ - h->protocol = htons ((sp->pp_flags & PP_CISCO) ? - ETHERTYPE_IPX : PPP_IPX); - break; -#endif -#if ISO - case AF_ISO: /* ISO OSI Protocol */ - if (sp->pp_flags & PP_CISCO) - goto nosupport; - h->protocol = htons (PPP_ISO); - break; -nosupport: -#endif - default: - m_freem (m); - ++ifp->if_oerrors; - splx (s); - return (EAFNOSUPPORT); - } - - /* - * Queue message on interface, and start output if interface - * not yet active. - */ - if (IF_QFULL (ifq)) { - IF_DROP (&ifp->if_snd); - m_freem (m); - ++ifp->if_oerrors; - splx (s); - return (rv? rv: ENOBUFS); - } - IF_ENQUEUE (ifq, m); - if (! (ifp->if_flags & IFF_OACTIVE)) - (*ifp->if_start) (ifp); - - /* - * Count output packets and bytes. - * The packet length includes header, FCS and 1 flag, - * according to RFC 1333. - */ - ifp->if_obytes += m->m_pkthdr.len + 3; - splx (s); - return (0); -} - -void -sppp_attach(struct ifnet *ifp) -{ - struct sppp *sp = (struct sppp*) ifp; - - /* Initialize keepalive handler. */ - if (! spppq) - TIMEOUT(sppp_keepalive, 0, hz * 10, keepalive_ch); - - /* Insert new entry into the keepalive list. */ - sp->pp_next = spppq; - spppq = sp; - - sp->pp_if.if_mtu = PP_MTU; - sp->pp_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; - sp->pp_if.if_type = IFT_PPP; - sp->pp_if.if_output = sppp_output; -#if 0 - sp->pp_flags = PP_KEEPALIVE; -#endif - sp->pp_fastq.ifq_maxlen = 32; - sp->pp_cpq.ifq_maxlen = 20; - sp->pp_loopcnt = 0; - sp->pp_alivecnt = 0; - sp->pp_seq = 0; - sp->pp_rseq = 0; - sp->pp_phase = PHASE_DEAD; - sp->pp_up = lcp.Up; - sp->pp_down = lcp.Down; - - sppp_lcp_init(sp); - sppp_ipcp_init(sp); - sppp_pap_init(sp); - sppp_chap_init(sp); -} - -void -sppp_detach(struct ifnet *ifp) -{ - struct sppp **q, *p, *sp = (struct sppp*) ifp; - int i; - - /* Remove the entry from the keepalive list. */ - for (q = &spppq; (p = *q); q = &p->pp_next) - if (p == sp) { - *q = p->pp_next; - break; - } - - /* Stop keepalive handler. */ - if (! spppq) - UNTIMEOUT(sppp_keepalive, 0, keepalive_ch); - - for (i = 0; i < IDX_COUNT; i++) - UNTIMEOUT((cps[i])->TO, (void *)sp, sp->ch[i]); - UNTIMEOUT(sppp_pap_my_TO, (void *)sp, sp->pap_my_to_ch); -} - -/* - * Flush the interface output queue. - */ -void -sppp_flush(struct ifnet *ifp) -{ - struct sppp *sp = (struct sppp*) ifp; - - sppp_qflush (&sp->pp_if.if_snd); - sppp_qflush (&sp->pp_fastq); - sppp_qflush (&sp->pp_cpq); -} - -/* - * Check if the output queue is empty. - */ -int -sppp_isempty(struct ifnet *ifp) -{ - struct sppp *sp = (struct sppp*) ifp; - int empty, s; - - s = splimp(); - empty = !sp->pp_fastq.ifq_head && !sp->pp_cpq.ifq_head && - !sp->pp_if.if_snd.ifq_head; - splx(s); - return (empty); -} - -/* - * Get next packet to send. - */ -struct mbuf * -sppp_dequeue(struct ifnet *ifp) -{ - struct sppp *sp = (struct sppp*) ifp; - struct mbuf *m; - int s; - - s = splimp(); - /* - * Process only the control protocol queue until we have at - * least one NCP open. - * - * Do always serve all three queues in Cisco mode. - */ - IF_DEQUEUE(&sp->pp_cpq, m); - if (m == NULL && - (sppp_ncp_check(sp) || (sp->pp_flags & PP_CISCO) != 0)) { - IF_DEQUEUE(&sp->pp_fastq, m); - if (m == NULL) - IF_DEQUEUE (&sp->pp_if.if_snd, m); - } - splx(s); - return m; -} - -/* - * Pick the next packet, do not remove it from the queue. - */ -struct mbuf * -sppp_pick(struct ifnet *ifp) -{ - struct sppp *sp = (struct sppp*)ifp; - struct mbuf *m; - int s; - - s= splimp (); - - m = sp->pp_cpq.ifq_head; - if (m == NULL && - (sp->pp_phase == PHASE_NETWORK || - (sp->pp_flags & PP_CISCO) != 0)) - if ((m = sp->pp_fastq.ifq_head) == NULL) - m = sp->pp_if.if_snd.ifq_head; - splx (s); - return (m); -} - -/* - * Process an ioctl request. Called on low priority level. - */ -int -sppp_ioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, void *data) -{ - struct ifreq *ifr = (struct ifreq*) data; - struct sppp *sp = (struct sppp*) ifp; - int s, rv, going_up, going_down, newmode; - - s = splimp(); - rv = 0; - switch (cmd) { - case SIOCAIFADDR: - case SIOCSIFDSTADDR: - break; - - case SIOCSIFADDR: - if_up(ifp); - /* fall through... */ - - case SIOCSIFFLAGS: - going_up = ifp->if_flags & IFF_UP && - (ifp->if_flags & IFF_RUNNING) == 0; - going_down = (ifp->if_flags & IFF_UP) == 0 && - ifp->if_flags & IFF_RUNNING; - newmode = ifp->if_flags & (IFF_AUTO | IFF_PASSIVE); - if (newmode == (IFF_AUTO | IFF_PASSIVE)) { - /* sanity */ - newmode = IFF_PASSIVE; - ifp->if_flags &= ~IFF_AUTO; - } - - if (going_up || going_down) - lcp.Close(sp); - if (going_up && newmode == 0) { - /* neither auto-dial nor passive */ - ifp->if_flags |= IFF_RUNNING; - if (!(sp->pp_flags & PP_CISCO)) - lcp.Open(sp); - } else if (going_down) { - sppp_flush(ifp); - ifp->if_flags &= ~IFF_RUNNING; - } - - break; - -#ifdef SIOCSIFMTU -#ifndef ifr_mtu -#define ifr_mtu ifr_metric -#endif - case SIOCSIFMTU: - if (ifr->ifr_mtu < 128 || ifr->ifr_mtu > sp->lcp.their_mru) - return (EINVAL); - ifp->if_mtu = ifr->ifr_mtu; - break; -#endif -#ifdef SLIOCSETMTU - case SLIOCSETMTU: - if (*(short*)data < 128 || *(short*)data > sp->lcp.their_mru) - return (EINVAL); - ifp->if_mtu = *(short*)data; - break; -#endif -#ifdef SIOCGIFMTU - case SIOCGIFMTU: - ifr->ifr_mtu = ifp->if_mtu; - break; -#endif -#ifdef SLIOCGETMTU - case SLIOCGETMTU: - *(short*)data = ifp->if_mtu; - break; -#endif - case SIOCADDMULTI: - case SIOCDELMULTI: - break; - - case SIOCGIFGENERIC: - case SIOCSIFGENERIC: - rv = sppp_params(sp, cmd, data); - break; - - default: - rv = ENOTTY; - } - splx(s); - return rv; -} - - - /* - * Cisco framing implementation. - */ - -/* - * Handle incoming Cisco keepalive protocol packets. - */ -static void -sppp_cisco_input(struct sppp *sp, struct mbuf *m) -{ - STDDCL; - struct cisco_packet *h; - u_long me, mymask; - - if (m->m_pkthdr.len < CISCO_PACKET_LEN) { - if (debug) - log(LOG_DEBUG, - SPP_FMT "cisco invalid packet length: %d bytes\n", - SPP_ARGS(ifp), m->m_pkthdr.len); - return; - } - h = mtod (m, struct cisco_packet*); - if (debug) - log(LOG_DEBUG, - SPP_FMT "cisco input: %d bytes " - "<0x%lx 0x%lx 0x%lx 0x%x 0x%x-0x%x>\n", - SPP_ARGS(ifp), m->m_pkthdr.len, - (u_long)ntohl (h->type), (u_long)h->par1, (u_long)h->par2, (u_int)h->rel, - (u_int)h->time0, (u_int)h->time1); - switch (ntohl (h->type)) { - default: - if (debug) - addlog(SPP_FMT "cisco unknown packet type: 0x%lx\n", - SPP_ARGS(ifp), (u_long)ntohl (h->type)); - break; - case CISCO_ADDR_REPLY: - /* Reply on address request, ignore */ - break; - case CISCO_KEEPALIVE_REQ: - sp->pp_alivecnt = 0; - sp->pp_rseq = ntohl (h->par1); - if (sp->pp_seq == sp->pp_rseq) { - /* Local and remote sequence numbers are equal. - * Probably, the line is in loopback mode. */ - if (sp->pp_loopcnt >= MAXALIVECNT) { - printf (SPP_FMT "loopback\n", - SPP_ARGS(ifp)); - sp->pp_loopcnt = 0; - if (ifp->if_flags & IFF_UP) { - if_down (ifp); - sppp_qflush (&sp->pp_cpq); - } - } - ++sp->pp_loopcnt; - - /* Generate new local sequence number */ -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - sp->pp_seq = random(); -#else - sp->pp_seq ^= time.tv_sec ^ time.tv_usec; -#endif - break; - } - sp->pp_loopcnt = 0; - if (! (ifp->if_flags & IFF_UP) && - (ifp->if_flags & IFF_RUNNING)) { - if_up(ifp); - printf (SPP_FMT "up\n", SPP_ARGS(ifp)); - } - break; - case CISCO_ADDR_REQ: - sppp_get_ip_addrs(sp, &me, 0, &mymask); - if (me != 0L) - sppp_cisco_send(sp, CISCO_ADDR_REPLY, me, mymask); - break; - } -} - -/* - * Send Cisco keepalive packet. - */ -static void -sppp_cisco_send(struct sppp *sp, int type, long par1, long par2) -{ - STDDCL; - struct ppp_header *h; - struct cisco_packet *ch; - struct mbuf *m; -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - struct timeval tv; -#else - u_long t = (time.tv_sec - boottime.tv_sec) * 1000; -#endif - -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - getmicrouptime(&tv); -#endif - - MGETHDR (m, M_DONTWAIT, MT_DATA); - if (! m) - return; - m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + CISCO_PACKET_LEN; - m->m_pkthdr.rcvif = 0; - - h = mtod (m, struct ppp_header*); - h->address = CISCO_MULTICAST; - h->control = 0; - h->protocol = htons (CISCO_KEEPALIVE); - - ch = (struct cisco_packet*) (h + 1); - ch->type = htonl (type); - ch->par1 = htonl (par1); - ch->par2 = htonl (par2); - ch->rel = -1; - -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - ch->time0 = htons ((u_short) (tv.tv_sec >> 16)); - ch->time1 = htons ((u_short) tv.tv_sec); -#else - ch->time0 = htons ((u_short) (t >> 16)); - ch->time1 = htons ((u_short) t); -#endif - - if (debug) - log(LOG_DEBUG, - SPP_FMT "cisco output: <0x%lx 0x%lx 0x%lx 0x%x 0x%x-0x%x>\n", - SPP_ARGS(ifp), (u_long)ntohl (ch->type), (u_long)ch->par1, - (u_long)ch->par2, (u_int)ch->rel, (u_int)ch->time0, (u_int)ch->time1); - - if (IF_QFULL (&sp->pp_cpq)) { - IF_DROP (&sp->pp_fastq); - IF_DROP (&ifp->if_snd); - m_freem (m); - } else - IF_ENQUEUE (&sp->pp_cpq, m); - if (! (ifp->if_flags & IFF_OACTIVE)) - (*ifp->if_start) (ifp); - ifp->if_obytes += m->m_pkthdr.len + 3; -} - - /* - * PPP protocol implementation. - */ - -/* - * Send PPP control protocol packet. - */ -static void -sppp_cp_send(struct sppp *sp, u_short proto, u_char type, - u_char ident, u_short len, void *data) -{ - STDDCL; - struct ppp_header *h; - struct lcp_header *lh; - struct mbuf *m; - - if (len > MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN) - len = MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN; - MGETHDR (m, M_DONTWAIT, MT_DATA); - if (! m) - return; - m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + LCP_HEADER_LEN + len; - m->m_pkthdr.rcvif = 0; - - h = mtod (m, struct ppp_header*); - h->address = PPP_ALLSTATIONS; /* broadcast address */ - h->control = PPP_UI; /* Unnumbered Info */ - h->protocol = htons (proto); /* Link Control Protocol */ - - lh = (struct lcp_header*) (h + 1); - lh->type = type; - lh->ident = ident; - lh->len = htons (LCP_HEADER_LEN + len); - if (len) - bcopy (data, lh+1, len); - - if (debug) { - log(LOG_DEBUG, SPP_FMT "%s output <%s id=0x%x len=%d", - SPP_ARGS(ifp), - sppp_proto_name(proto), - sppp_cp_type_name (lh->type), lh->ident, - ntohs (lh->len)); - if (len) - sppp_print_bytes ((u_char*) (lh+1), len); - addlog(">\n"); - } - if (IF_QFULL (&sp->pp_cpq)) { - IF_DROP (&sp->pp_fastq); - IF_DROP (&ifp->if_snd); - m_freem (m); - ++ifp->if_oerrors; - } else - IF_ENQUEUE (&sp->pp_cpq, m); - if (! (ifp->if_flags & IFF_OACTIVE)) - (*ifp->if_start) (ifp); - ifp->if_obytes += m->m_pkthdr.len + 3; -} - -/* - * Handle incoming PPP control protocol packets. - */ -static void -sppp_cp_input(const struct cp *cp, struct sppp *sp, struct mbuf *m) -{ - STDDCL; - struct lcp_header *h; - int len = m->m_pkthdr.len; - int rv; - u_char *p; - - if (len < 4) { - if (debug) - log(LOG_DEBUG, - SPP_FMT "%s invalid packet length: %d bytes\n", - SPP_ARGS(ifp), cp->name, len); - return; - } - h = mtod (m, struct lcp_header*); - if (debug) { - log(LOG_DEBUG, - SPP_FMT "%s input(%s): <%s id=0x%x len=%d", - SPP_ARGS(ifp), cp->name, - sppp_state_name(sp->state[cp->protoidx]), - sppp_cp_type_name (h->type), h->ident, ntohs (h->len)); - if (len > 4) - sppp_print_bytes ((u_char*) (h+1), len-4); - addlog(">\n"); - } - if (len > ntohs (h->len)) - len = ntohs (h->len); - p = (u_char *)(h + 1); - switch (h->type) { - case CONF_REQ: - if (len < 4) { - if (debug) - addlog(SPP_FMT "%s invalid conf-req length %d\n", - SPP_ARGS(ifp), cp->name, - len); - ++ifp->if_ierrors; - break; - } - /* handle states where RCR doesn't get a SCA/SCN */ - switch (sp->state[cp->protoidx]) { - case STATE_CLOSING: - case STATE_STOPPING: - return; - case STATE_CLOSED: - sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, - 0, 0); - return; - } - rv = (cp->RCR)(sp, h, len); - switch (sp->state[cp->protoidx]) { - case STATE_OPENED: - (cp->tld)(sp); - (cp->scr)(sp); - /* fall through... */ - case STATE_ACK_SENT: - case STATE_REQ_SENT: - sppp_cp_change_state(cp, sp, rv? - STATE_ACK_SENT: STATE_REQ_SENT); - break; - case STATE_STOPPED: - sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; - (cp->scr)(sp); - sppp_cp_change_state(cp, sp, rv? - STATE_ACK_SENT: STATE_REQ_SENT); - break; - case STATE_ACK_RCVD: - if (rv) { - sppp_cp_change_state(cp, sp, STATE_OPENED); - if (debug) - log(LOG_DEBUG, SPP_FMT "%s tlu\n", - SPP_ARGS(ifp), - cp->name); - (cp->tlu)(sp); - } else - sppp_cp_change_state(cp, sp, STATE_ACK_RCVD); - break; - default: - printf(SPP_FMT "%s illegal %s in state %s\n", - SPP_ARGS(ifp), cp->name, - sppp_cp_type_name(h->type), - sppp_state_name(sp->state[cp->protoidx])); - ++ifp->if_ierrors; - } - break; - case CONF_ACK: - if (h->ident != sp->confid[cp->protoidx]) { - if (debug) - addlog(SPP_FMT "%s id mismatch 0x%x != 0x%x\n", - SPP_ARGS(ifp), cp->name, - h->ident, sp->confid[cp->protoidx]); - ++ifp->if_ierrors; - break; - } - switch (sp->state[cp->protoidx]) { - case STATE_CLOSED: - case STATE_STOPPED: - sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0); - break; - case STATE_CLOSING: - case STATE_STOPPING: - break; - case STATE_REQ_SENT: - sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; - sppp_cp_change_state(cp, sp, STATE_ACK_RCVD); - break; - case STATE_OPENED: - (cp->tld)(sp); - /* fall through */ - case STATE_ACK_RCVD: - (cp->scr)(sp); - sppp_cp_change_state(cp, sp, STATE_REQ_SENT); - break; - case STATE_ACK_SENT: - sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; - sppp_cp_change_state(cp, sp, STATE_OPENED); - if (debug) - log(LOG_DEBUG, SPP_FMT "%s tlu\n", - SPP_ARGS(ifp), cp->name); - (cp->tlu)(sp); - break; - default: - printf(SPP_FMT "%s illegal %s in state %s\n", - SPP_ARGS(ifp), cp->name, - sppp_cp_type_name(h->type), - sppp_state_name(sp->state[cp->protoidx])); - ++ifp->if_ierrors; - } - break; - case CONF_NAK: - case CONF_REJ: - if (h->ident != sp->confid[cp->protoidx]) { - if (debug) - addlog(SPP_FMT "%s id mismatch 0x%x != 0x%x\n", - SPP_ARGS(ifp), cp->name, - h->ident, sp->confid[cp->protoidx]); - ++ifp->if_ierrors; - break; - } - if (h->type == CONF_NAK) - (cp->RCN_nak)(sp, h, len); - else /* CONF_REJ */ - (cp->RCN_rej)(sp, h, len); - - switch (sp->state[cp->protoidx]) { - case STATE_CLOSED: - case STATE_STOPPED: - sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0); - break; - case STATE_REQ_SENT: - case STATE_ACK_SENT: - sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; - (cp->scr)(sp); - break; - case STATE_OPENED: - (cp->tld)(sp); - /* fall through */ - case STATE_ACK_RCVD: - sppp_cp_change_state(cp, sp, STATE_ACK_SENT); - (cp->scr)(sp); - break; - case STATE_CLOSING: - case STATE_STOPPING: - break; - default: - printf(SPP_FMT "%s illegal %s in state %s\n", - SPP_ARGS(ifp), cp->name, - sppp_cp_type_name(h->type), - sppp_state_name(sp->state[cp->protoidx])); - ++ifp->if_ierrors; - } - break; - - case TERM_REQ: - switch (sp->state[cp->protoidx]) { - case STATE_ACK_RCVD: - case STATE_ACK_SENT: - sppp_cp_change_state(cp, sp, STATE_REQ_SENT); - /* fall through */ - case STATE_CLOSED: - case STATE_STOPPED: - case STATE_CLOSING: - case STATE_STOPPING: - case STATE_REQ_SENT: - sta: - /* Send Terminate-Ack packet. */ - if (debug) - log(LOG_DEBUG, SPP_FMT "%s send terminate-ack\n", - SPP_ARGS(ifp), cp->name); - sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0); - break; - case STATE_OPENED: - (cp->tld)(sp); - sp->rst_counter[cp->protoidx] = 0; - sppp_cp_change_state(cp, sp, STATE_STOPPING); - goto sta; - break; - default: - printf(SPP_FMT "%s illegal %s in state %s\n", - SPP_ARGS(ifp), cp->name, - sppp_cp_type_name(h->type), - sppp_state_name(sp->state[cp->protoidx])); - ++ifp->if_ierrors; - } - break; - case TERM_ACK: - switch (sp->state[cp->protoidx]) { - case STATE_CLOSED: - case STATE_STOPPED: - case STATE_REQ_SENT: - case STATE_ACK_SENT: - break; - case STATE_CLOSING: - sppp_cp_change_state(cp, sp, STATE_CLOSED); - (cp->tlf)(sp); - break; - case STATE_STOPPING: - sppp_cp_change_state(cp, sp, STATE_STOPPED); - (cp->tlf)(sp); - break; - case STATE_ACK_RCVD: - sppp_cp_change_state(cp, sp, STATE_REQ_SENT); - break; - case STATE_OPENED: - (cp->tld)(sp); - (cp->scr)(sp); - sppp_cp_change_state(cp, sp, STATE_ACK_RCVD); - break; - default: - printf(SPP_FMT "%s illegal %s in state %s\n", - SPP_ARGS(ifp), cp->name, - sppp_cp_type_name(h->type), - sppp_state_name(sp->state[cp->protoidx])); - ++ifp->if_ierrors; - } - break; - case CODE_REJ: - case PROTO_REJ: - /* XXX catastrophic rejects (RXJ-) aren't handled yet. */ - log(LOG_INFO, - SPP_FMT "%s: ignoring RXJ (%s) for proto 0x%x, " - "danger will robinson\n", - SPP_ARGS(ifp), cp->name, - sppp_cp_type_name(h->type), ntohs(*((u_short *)p))); - switch (sp->state[cp->protoidx]) { - case STATE_CLOSED: - case STATE_STOPPED: - case STATE_REQ_SENT: - case STATE_ACK_SENT: - case STATE_CLOSING: - case STATE_STOPPING: - case STATE_OPENED: - break; - case STATE_ACK_RCVD: - sppp_cp_change_state(cp, sp, STATE_REQ_SENT); - break; - default: - printf(SPP_FMT "%s illegal %s in state %s\n", - SPP_ARGS(ifp), cp->name, - sppp_cp_type_name(h->type), - sppp_state_name(sp->state[cp->protoidx])); - ++ifp->if_ierrors; - } - break; - case DISC_REQ: - if (cp->proto != PPP_LCP) - goto illegal; - /* Discard the packet. */ - break; - case ECHO_REQ: - if (cp->proto != PPP_LCP) - goto illegal; - if (sp->state[cp->protoidx] != STATE_OPENED) { - if (debug) - addlog(SPP_FMT "lcp echo req but lcp closed\n", - SPP_ARGS(ifp)); - ++ifp->if_ierrors; - break; - } - if (len < 8) { - if (debug) - addlog(SPP_FMT "invalid lcp echo request " - "packet length: %d bytes\n", - SPP_ARGS(ifp), len); - break; - } - if (ntohl (*(long*)(h+1)) == sp->lcp.magic) { - /* Line loopback mode detected. */ - printf(SPP_FMT "loopback\n", SPP_ARGS(ifp)); - if_down (ifp); - sppp_qflush (&sp->pp_cpq); - - /* Shut down the PPP link. */ - /* XXX */ - lcp.Down(sp); - lcp.Up(sp); - break; - } - *(long*)(h+1) = htonl (sp->lcp.magic); - if (debug) - addlog(SPP_FMT "got lcp echo req, sending echo rep\n", - SPP_ARGS(ifp)); - sppp_cp_send (sp, PPP_LCP, ECHO_REPLY, h->ident, len-4, h+1); - break; - case ECHO_REPLY: - if (cp->proto != PPP_LCP) - goto illegal; - if (h->ident != sp->lcp.echoid) { - ++ifp->if_ierrors; - break; - } - if (len < 8) { - if (debug) - addlog(SPP_FMT "lcp invalid echo reply " - "packet length: %d bytes\n", - SPP_ARGS(ifp), len); - break; - } - if (debug) - addlog(SPP_FMT "lcp got echo rep\n", - SPP_ARGS(ifp)); - if (ntohl (*(long*)(h+1)) != sp->lcp.magic) - sp->pp_alivecnt = 0; - break; - default: - /* Unknown packet type -- send Code-Reject packet. */ - illegal: - if (debug) - addlog(SPP_FMT "%s send code-rej for 0x%x\n", - SPP_ARGS(ifp), cp->name, h->type); - sppp_cp_send(sp, cp->proto, CODE_REJ, ++sp->pp_seq, - m->m_pkthdr.len, h); - ++ifp->if_ierrors; - } -} - - -/* - * The generic part of all Up/Down/Open/Close/TO event handlers. - * Basically, the state transition handling in the automaton. - */ -static void -sppp_up_event(const struct cp *cp, struct sppp *sp) -{ - STDDCL; - - if (debug) - log(LOG_DEBUG, SPP_FMT "%s up(%s)\n", - SPP_ARGS(ifp), cp->name, - sppp_state_name(sp->state[cp->protoidx])); - - switch (sp->state[cp->protoidx]) { - case STATE_INITIAL: - sppp_cp_change_state(cp, sp, STATE_CLOSED); - break; - case STATE_STARTING: - sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; - (cp->scr)(sp); - sppp_cp_change_state(cp, sp, STATE_REQ_SENT); - break; - default: - printf(SPP_FMT "%s illegal up in state %s\n", - SPP_ARGS(ifp), cp->name, - sppp_state_name(sp->state[cp->protoidx])); - } -} - -static void -sppp_down_event(const struct cp *cp, struct sppp *sp) -{ - STDDCL; - - if (debug) - log(LOG_DEBUG, SPP_FMT "%s down(%s)\n", - SPP_ARGS(ifp), cp->name, - sppp_state_name(sp->state[cp->protoidx])); - - switch (sp->state[cp->protoidx]) { - case STATE_CLOSED: - case STATE_CLOSING: - sppp_cp_change_state(cp, sp, STATE_INITIAL); - break; - case STATE_STOPPED: - sppp_cp_change_state(cp, sp, STATE_STARTING); - (cp->tls)(sp); - break; - case STATE_STOPPING: - case STATE_REQ_SENT: - case STATE_ACK_RCVD: - case STATE_ACK_SENT: - sppp_cp_change_state(cp, sp, STATE_STARTING); - break; - case STATE_OPENED: - (cp->tld)(sp); - sppp_cp_change_state(cp, sp, STATE_STARTING); - break; - default: - printf(SPP_FMT "%s illegal down in state %s\n", - SPP_ARGS(ifp), cp->name, - sppp_state_name(sp->state[cp->protoidx])); - } -} - - -static void -sppp_open_event(const struct cp *cp, struct sppp *sp) -{ - STDDCL; - - if (debug) - log(LOG_DEBUG, SPP_FMT "%s open(%s)\n", - SPP_ARGS(ifp), cp->name, - sppp_state_name(sp->state[cp->protoidx])); - - switch (sp->state[cp->protoidx]) { - case STATE_INITIAL: - sppp_cp_change_state(cp, sp, STATE_STARTING); - (cp->tls)(sp); - break; - case STATE_STARTING: - break; - case STATE_CLOSED: - sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; - (cp->scr)(sp); - sppp_cp_change_state(cp, sp, STATE_REQ_SENT); - break; - case STATE_STOPPED: - case STATE_STOPPING: - case STATE_REQ_SENT: - case STATE_ACK_RCVD: - case STATE_ACK_SENT: - case STATE_OPENED: - break; - case STATE_CLOSING: - sppp_cp_change_state(cp, sp, STATE_STOPPING); - break; - } -} - - -static void -sppp_close_event(const struct cp *cp, struct sppp *sp) -{ - STDDCL; - - if (debug) - log(LOG_DEBUG, SPP_FMT "%s close(%s)\n", - SPP_ARGS(ifp), cp->name, - sppp_state_name(sp->state[cp->protoidx])); - - switch (sp->state[cp->protoidx]) { - case STATE_INITIAL: - case STATE_CLOSED: - case STATE_CLOSING: - break; - case STATE_STARTING: - sppp_cp_change_state(cp, sp, STATE_INITIAL); - (cp->tlf)(sp); - break; - case STATE_STOPPED: - sppp_cp_change_state(cp, sp, STATE_CLOSED); - break; - case STATE_STOPPING: - sppp_cp_change_state(cp, sp, STATE_CLOSING); - break; - case STATE_OPENED: - (cp->tld)(sp); - /* fall through */ - case STATE_REQ_SENT: - case STATE_ACK_RCVD: - case STATE_ACK_SENT: - sp->rst_counter[cp->protoidx] = sp->lcp.max_terminate; - sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq, 0, 0); - sppp_cp_change_state(cp, sp, STATE_CLOSING); - break; - } -} - -static void -sppp_to_event(const struct cp *cp, struct sppp *sp) -{ - STDDCL; - int s; - - s = splimp(); - if (debug) - log(LOG_DEBUG, SPP_FMT "%s TO(%s) rst_counter = %d\n", - SPP_ARGS(ifp), cp->name, - sppp_state_name(sp->state[cp->protoidx]), - sp->rst_counter[cp->protoidx]); - - if (--sp->rst_counter[cp->protoidx] < 0) - /* TO- event */ - switch (sp->state[cp->protoidx]) { - case STATE_CLOSING: - sppp_cp_change_state(cp, sp, STATE_CLOSED); - (cp->tlf)(sp); - break; - case STATE_STOPPING: - sppp_cp_change_state(cp, sp, STATE_STOPPED); - (cp->tlf)(sp); - break; - case STATE_REQ_SENT: - case STATE_ACK_RCVD: - case STATE_ACK_SENT: - sppp_cp_change_state(cp, sp, STATE_STOPPED); - (cp->tlf)(sp); - break; - } - else - /* TO+ event */ - switch (sp->state[cp->protoidx]) { - case STATE_CLOSING: - case STATE_STOPPING: - sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq, - 0, 0); - TIMEOUT(cp->TO, (void *)sp, sp->lcp.timeout, - sp->ch[cp->protoidx]); - break; - case STATE_REQ_SENT: - case STATE_ACK_RCVD: - (cp->scr)(sp); - /* sppp_cp_change_state() will restart the timer */ - sppp_cp_change_state(cp, sp, STATE_REQ_SENT); - break; - case STATE_ACK_SENT: - (cp->scr)(sp); - TIMEOUT(cp->TO, (void *)sp, sp->lcp.timeout, - sp->ch[cp->protoidx]); - break; - } - - splx(s); -} - -/* - * Change the state of a control protocol in the state automaton. - * Takes care of starting/stopping the restart timer. - */ -void -sppp_cp_change_state(const struct cp *cp, struct sppp *sp, int newstate) -{ - sp->state[cp->protoidx] = newstate; - - UNTIMEOUT(cp->TO, (void *)sp, sp->ch[cp->protoidx]); - switch (newstate) { - case STATE_INITIAL: - case STATE_STARTING: - case STATE_CLOSED: - case STATE_STOPPED: - case STATE_OPENED: - break; - case STATE_CLOSING: - case STATE_STOPPING: - case STATE_REQ_SENT: - case STATE_ACK_RCVD: - case STATE_ACK_SENT: - TIMEOUT(cp->TO, (void *)sp, sp->lcp.timeout, - sp->ch[cp->protoidx]); - break; - } -} - /* - *--------------------------------------------------------------------------* - * * - * The LCP implementation. * - * * - *--------------------------------------------------------------------------* - */ -static void -sppp_lcp_init(struct sppp *sp) -{ - sp->lcp.opts = (1 << LCP_OPT_MAGIC); - sp->lcp.magic = 0; - sp->state[IDX_LCP] = STATE_INITIAL; - sp->fail_counter[IDX_LCP] = 0; - sp->lcp.protos = 0; - sp->lcp.mru = sp->lcp.their_mru = PP_MTU; - - /* - * Initialize counters and timeout values. Note that we don't - * use the 3 seconds suggested in RFC 1661 since we are likely - * running on a fast link. XXX We should probably implement - * the exponential backoff option. Note that these values are - * relevant for all control protocols, not just LCP only. - */ - sp->lcp.timeout = 1 * hz; - sp->lcp.max_terminate = 2; - sp->lcp.max_configure = 10; - sp->lcp.max_failure = 10; -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - callout_handle_init(&sp->ch[IDX_LCP]); -#endif -} - -static void -sppp_lcp_up(struct sppp *sp) -{ - STDDCL; - - /* - * If this interface is passive or dial-on-demand, and we are - * still in Initial state, it means we've got an incoming - * call. Activate the interface. - */ - if ((ifp->if_flags & (IFF_AUTO | IFF_PASSIVE)) != 0) { - if (debug) - log(LOG_DEBUG, - SPP_FMT "Up event", SPP_ARGS(ifp)); - ifp->if_flags |= IFF_RUNNING; - if (sp->state[IDX_LCP] == STATE_INITIAL) { - if (debug) - addlog("(incoming call)\n"); - sp->pp_flags |= PP_CALLIN; - lcp.Open(sp); - } else if (debug) - addlog("\n"); - } - - sppp_up_event(&lcp, sp); -} - -static void -sppp_lcp_down(struct sppp *sp) -{ - STDDCL; - - sppp_down_event(&lcp, sp); - - /* - * If this is neither a dial-on-demand nor a passive - * interface, simulate an ``ifconfig down'' action, so the - * administrator can force a redial by another ``ifconfig - * up''. XXX For leased line operation, should we immediately - * try to reopen the connection here? - */ - if ((ifp->if_flags & (IFF_AUTO | IFF_PASSIVE)) == 0) { - log(LOG_INFO, - SPP_FMT "Down event, taking interface down.\n", - SPP_ARGS(ifp)); - if_down(ifp); - } else { - if (debug) - log(LOG_DEBUG, - SPP_FMT "Down event (carrier loss)\n", - SPP_ARGS(ifp)); - } - sp->pp_flags &= ~PP_CALLIN; - if (sp->state[IDX_LCP] != STATE_INITIAL) - lcp.Close(sp); - ifp->if_flags &= ~IFF_RUNNING; -} - -static void -sppp_lcp_open(struct sppp *sp) -{ - /* - * If we are authenticator, negotiate LCP_AUTH - */ - if (sp->hisauth.proto != 0) - sp->lcp.opts |= (1 << LCP_OPT_AUTH_PROTO); - else - sp->lcp.opts &= ~(1 << LCP_OPT_AUTH_PROTO); - sp->pp_flags &= ~PP_NEEDAUTH; - sppp_open_event(&lcp, sp); -} - -static void -sppp_lcp_close(struct sppp *sp) -{ - sppp_close_event(&lcp, sp); -} - -static void -sppp_lcp_TO(void *cookie) -{ - sppp_to_event(&lcp, (struct sppp *)cookie); -} - -/* - * Analyze a configure request. Return true if it was agreeable, and - * caused action sca, false if it has been rejected or nak'ed, and - * caused action scn. (The return value is used to make the state - * transition decision in the state automaton.) - */ -static int -sppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len) -{ - STDDCL; - u_char *buf, *r, *p; - int origlen, rlen; - u_long nmagic; - u_short authproto; - - len -= 4; - origlen = len; - buf = r = _MALLOC(len, M_TEMP, M_WAITOK); - if (! buf) - return (0); - - if (debug) - log(LOG_DEBUG, SPP_FMT "lcp parse opts: ", - SPP_ARGS(ifp)); - - /* pass 1: check for things that need to be rejected */ - p = (void*) (h+1); - for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { - if (debug) - addlog(" %s ", sppp_lcp_opt_name(*p)); - switch (*p) { - case LCP_OPT_MAGIC: - /* Magic number. */ - /* fall through, both are same length */ - case LCP_OPT_ASYNC_MAP: - /* Async control character map. */ - if (len >= 6 || p[1] == 6) - continue; - if (debug) - addlog("[invalid] "); - break; - case LCP_OPT_MRU: - /* Maximum receive unit. */ - if (len >= 4 && p[1] == 4) - continue; - if (debug) - addlog("[invalid] "); - break; - case LCP_OPT_AUTH_PROTO: - if (len < 4) { - if (debug) - addlog("[invalid] "); - break; - } - authproto = (p[2] << 8) + p[3]; - if (authproto == PPP_CHAP && p[1] != 5) { - if (debug) - addlog("[invalid chap len] "); - break; - } - if (sp->myauth.proto == 0) { - /* we are not configured to do auth */ - if (debug) - addlog("[not configured] "); - break; - } - /* - * Remote want us to authenticate, remember this, - * so we stay in PHASE_AUTHENTICATE after LCP got - * up. - */ - sp->pp_flags |= PP_NEEDAUTH; - continue; - default: - /* Others not supported. */ - if (debug) - addlog("[rej] "); - break; - } - /* Add the option to rejected list. */ - bcopy (p, r, p[1]); - r += p[1]; - rlen += p[1]; - } - if (rlen) { - if (debug) - addlog(" send conf-rej\n"); - sppp_cp_send (sp, PPP_LCP, CONF_REJ, h->ident, rlen, buf); - return 0; - } else if (debug) - addlog("\n"); - - /* - * pass 2: check for option values that are unacceptable and - * thus require to be nak'ed. - */ - if (debug) - log(LOG_DEBUG, SPP_FMT "lcp parse opt values: ", - SPP_ARGS(ifp)); - - p = (void*) (h+1); - len = origlen; - for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { - if (debug) - addlog(" %s ", sppp_lcp_opt_name(*p)); - switch (*p) { - case LCP_OPT_MAGIC: - /* Magic number -- extract. */ - nmagic = (u_long)p[2] << 24 | - (u_long)p[3] << 16 | p[4] << 8 | p[5]; - if (nmagic != sp->lcp.magic) { - if (debug) - addlog("0x%lx ", nmagic); - continue; - } - /* - * Local and remote magics equal -- loopback? - */ - if (sp->pp_loopcnt >= MAXALIVECNT*5) { - printf (SPP_FMT "loopback\n", - SPP_ARGS(ifp)); - sp->pp_loopcnt = 0; - if (ifp->if_flags & IFF_UP) { - if_down(ifp); - sppp_qflush(&sp->pp_cpq); - /* XXX ? */ - lcp.Down(sp); - lcp.Up(sp); - } - } else if (debug) - addlog("[glitch] "); - ++sp->pp_loopcnt; - /* - * We negate our magic here, and NAK it. If - * we see it later in an NAK packet, we - * suggest a new one. - */ - nmagic = ~sp->lcp.magic; - /* Gonna NAK it. */ - p[2] = nmagic >> 24; - p[3] = nmagic >> 16; - p[4] = nmagic >> 8; - p[5] = nmagic; - break; - - case LCP_OPT_ASYNC_MAP: - /* Async control character map -- check to be zero. */ - if (! p[2] && ! p[3] && ! p[4] && ! p[5]) { - if (debug) - addlog("[empty] "); - continue; - } - if (debug) - addlog("[non-empty] "); - /* suggest a zero one */ - p[2] = p[3] = p[4] = p[5] = 0; - break; - - case LCP_OPT_MRU: - /* - * Maximum receive unit. Always agreeable, - * but ignored by now. - */ - sp->lcp.their_mru = p[2] * 256 + p[3]; - if (debug) - addlog("%lu ", sp->lcp.their_mru); - continue; - - case LCP_OPT_AUTH_PROTO: - authproto = (p[2] << 8) + p[3]; - if (sp->myauth.proto != authproto) { - /* not agreed, nak */ - if (debug) - addlog("[mine %s != his %s] ", - sppp_proto_name(sp->hisauth.proto), - sppp_proto_name(authproto)); - p[2] = sp->myauth.proto >> 8; - p[3] = sp->myauth.proto; - break; - } - if (authproto == PPP_CHAP && p[4] != CHAP_MD5) { - if (debug) - addlog("[chap not MD5] "); - p[4] = CHAP_MD5; - break; - } - continue; - } - /* Add the option to nak'ed list. */ - bcopy (p, r, p[1]); - r += p[1]; - rlen += p[1]; - } - if (rlen) { - if (++sp->fail_counter[IDX_LCP] >= sp->lcp.max_failure) { - if (debug) - addlog(" max_failure (%d) exceeded, " - "send conf-rej\n", - sp->lcp.max_failure); - sppp_cp_send(sp, PPP_LCP, CONF_REJ, h->ident, rlen, buf); - } else { - if (debug) - addlog(" send conf-nak\n"); - sppp_cp_send (sp, PPP_LCP, CONF_NAK, h->ident, rlen, buf); - } - return 0; - } else { - if (debug) - addlog(" send conf-ack\n"); - sp->fail_counter[IDX_LCP] = 0; - sp->pp_loopcnt = 0; - sppp_cp_send (sp, PPP_LCP, CONF_ACK, - h->ident, origlen, h+1); - } - - FREE(buf, M_TEMP); - return (rlen == 0); -} - -/* - * Analyze the LCP Configure-Reject option list, and adjust our - * negotiation. - */ -static void -sppp_lcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len) -{ - STDDCL; - u_char *buf, *p; - - len -= 4; - buf = MALLOC (len, M_TEMP, M_WAITOK); - if (!buf) - return; - - if (debug) - log(LOG_DEBUG, SPP_FMT "lcp rej opts: ", - SPP_ARGS(ifp)); - - p = (void*) (h+1); - for (; len > 1 && p[1]; len -= p[1], p += p[1]) { - if (debug) - addlog(" %s ", sppp_lcp_opt_name(*p)); - switch (*p) { - case LCP_OPT_MAGIC: - /* Magic number -- can't use it, use 0 */ - sp->lcp.opts &= ~(1 << LCP_OPT_MAGIC); - sp->lcp.magic = 0; - break; - case LCP_OPT_MRU: - /* - * Should not be rejected anyway, since we only - * negotiate a MRU if explicitly requested by - * peer. - */ - sp->lcp.opts &= ~(1 << LCP_OPT_MRU); - break; - case LCP_OPT_AUTH_PROTO: - /* - * Peer doesn't want to authenticate himself, - * deny unless this is a dialout call, and - * AUTHFLAG_NOCALLOUT is set. - */ - if ((sp->pp_flags & PP_CALLIN) == 0 && - (sp->hisauth.flags & AUTHFLAG_NOCALLOUT) != 0) { - if (debug) - addlog("[don't insist on auth " - "for callout]"); - sp->lcp.opts &= ~(1 << LCP_OPT_AUTH_PROTO); - break; - } - if (debug) - addlog("[access denied]\n"); - lcp.Close(sp); - break; - } - } - if (debug) - addlog("\n"); - FREE(buf, M_TEMP); - return; -} - -/* - * Analyze the LCP Configure-NAK option list, and adjust our - * negotiation. - */ -static void -sppp_lcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len) -{ - STDDCL; - u_char *buf, *p; - u_long magic; - - len -= 4; - buf = MALLOC (len, M_TEMP, M_WAITOK); - if (!buf) - return; - - if (debug) - log(LOG_DEBUG, SPP_FMT "lcp nak opts: ", - SPP_ARGS(ifp)); - - p = (void*) (h+1); - for (; len > 1 && p[1]; len -= p[1], p += p[1]) { - if (debug) - addlog(" %s ", sppp_lcp_opt_name(*p)); - switch (*p) { - case LCP_OPT_MAGIC: - /* Magic number -- renegotiate */ - if ((sp->lcp.opts & (1 << LCP_OPT_MAGIC)) && - len >= 6 && p[1] == 6) { - magic = (u_long)p[2] << 24 | - (u_long)p[3] << 16 | p[4] << 8 | p[5]; - /* - * If the remote magic is our negated one, - * this looks like a loopback problem. - * Suggest a new magic to make sure. - */ - if (magic == ~sp->lcp.magic) { - if (debug) - addlog("magic glitch "); -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - sp->lcp.magic = random(); -#else - sp->lcp.magic = time.tv_sec + time.tv_usec; -#endif - } else { - sp->lcp.magic = magic; - if (debug) - addlog("%lu ", magic); - } - } - break; - case LCP_OPT_MRU: - /* - * Peer wants to advise us to negotiate an MRU. - * Agree on it if it's reasonable, or use - * default otherwise. - */ - if (len >= 4 && p[1] == 4) { - u_int mru = p[2] * 256 + p[3]; - if (debug) - addlog("%d ", mru); - if (mru < PP_MTU || mru > PP_MAX_MRU) - mru = PP_MTU; - sp->lcp.mru = mru; - sp->lcp.opts |= (1 << LCP_OPT_MRU); - } - break; - case LCP_OPT_AUTH_PROTO: - /* - * Peer doesn't like our authentication method, - * deny. - */ - if (debug) - addlog("[access denied]\n"); - lcp.Close(sp); - break; - } - } - if (debug) - addlog("\n"); - FREE(buf, M_TEMP); - return; -} - -static void -sppp_lcp_tlu(struct sppp *sp) -{ - STDDCL; - int i; - u_long mask; - - /* XXX ? */ - if (! (ifp->if_flags & IFF_UP) && - (ifp->if_flags & IFF_RUNNING)) { - /* Coming out of loopback mode. */ - if_up(ifp); - printf (SPP_FMT "up\n", SPP_ARGS(ifp)); - } - - for (i = 0; i < IDX_COUNT; i++) - if ((cps[i])->flags & CP_QUAL) - (cps[i])->Open(sp); - - if ((sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) != 0 || - (sp->pp_flags & PP_NEEDAUTH) != 0) - sp->pp_phase = PHASE_AUTHENTICATE; - else - sp->pp_phase = PHASE_NETWORK; - - if (debug) - log(LOG_DEBUG, SPP_FMT "phase %s\n", SPP_ARGS(ifp), - sppp_phase_name(sp->pp_phase)); - - /* - * Open all authentication protocols. This is even required - * if we already proceeded to network phase, since it might be - * that remote wants us to authenticate, so we might have to - * send a PAP request. Undesired authentication protocols - * don't do anything when they get an Open event. - */ - for (i = 0; i < IDX_COUNT; i++) - if ((cps[i])->flags & CP_AUTH) - (cps[i])->Open(sp); - - if (sp->pp_phase == PHASE_NETWORK) { - /* Notify all NCPs. */ - for (i = 0; i < IDX_COUNT; i++) - if ((cps[i])->flags & CP_NCP) - (cps[i])->Open(sp); - } - - /* Send Up events to all started protos. */ - for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1) - if (sp->lcp.protos & mask && ((cps[i])->flags & CP_LCP) == 0) - (cps[i])->Up(sp); - - /* notify low-level driver of state change */ - if (sp->pp_chg) - sp->pp_chg(sp, (int)sp->pp_phase); - - if (sp->pp_phase == PHASE_NETWORK) - /* if no NCP is starting, close down */ - sppp_lcp_check_and_close(sp); -} - -static void -sppp_lcp_tld(struct sppp *sp) -{ - STDDCL; - int i; - u_long mask; - - sp->pp_phase = PHASE_TERMINATE; - - if (debug) - log(LOG_DEBUG, SPP_FMT "phase %s\n", SPP_ARGS(ifp), - sppp_phase_name(sp->pp_phase)); - - /* - * Take upper layers down. We send the Down event first and - * the Close second to prevent the upper layers from sending - * ``a flurry of terminate-request packets'', as the RFC - * describes it. - */ - for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1) - if (sp->lcp.protos & mask && ((cps[i])->flags & CP_LCP) == 0) { - (cps[i])->Down(sp); - (cps[i])->Close(sp); - } -} - -static void -sppp_lcp_tls(struct sppp *sp) -{ - STDDCL; - - sp->pp_phase = PHASE_ESTABLISH; - - if (debug) - log(LOG_DEBUG, SPP_FMT "phase %s\n", SPP_ARGS(ifp), - sppp_phase_name(sp->pp_phase)); - - /* Notify lower layer if desired. */ - if (sp->pp_tls) - (sp->pp_tls)(sp); - else - (sp->pp_up)(sp); -} - -static void -sppp_lcp_tlf(struct sppp *sp) -{ - STDDCL; - - sp->pp_phase = PHASE_DEAD; - if (debug) - log(LOG_DEBUG, SPP_FMT "phase %s\n", SPP_ARGS(ifp), - sppp_phase_name(sp->pp_phase)); - - /* Notify lower layer if desired. */ - if (sp->pp_tlf) - (sp->pp_tlf)(sp); - else - (sp->pp_down)(sp); -} - -static void -sppp_lcp_scr(struct sppp *sp) -{ - char opt[6 /* magicnum */ + 4 /* mru */ + 5 /* chap */]; - int i = 0; - u_short authproto; - - if (sp->lcp.opts & (1 << LCP_OPT_MAGIC)) { - if (! sp->lcp.magic) -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - sp->lcp.magic = random(); -#else - sp->lcp.magic = time.tv_sec + time.tv_usec; -#endif - opt[i++] = LCP_OPT_MAGIC; - opt[i++] = 6; - opt[i++] = sp->lcp.magic >> 24; - opt[i++] = sp->lcp.magic >> 16; - opt[i++] = sp->lcp.magic >> 8; - opt[i++] = sp->lcp.magic; - } - - if (sp->lcp.opts & (1 << LCP_OPT_MRU)) { - opt[i++] = LCP_OPT_MRU; - opt[i++] = 4; - opt[i++] = sp->lcp.mru >> 8; - opt[i++] = sp->lcp.mru; - } - - if (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) { - authproto = sp->hisauth.proto; - opt[i++] = LCP_OPT_AUTH_PROTO; - opt[i++] = authproto == PPP_CHAP? 5: 4; - opt[i++] = authproto >> 8; - opt[i++] = authproto; - if (authproto == PPP_CHAP) - opt[i++] = CHAP_MD5; - } - - sp->confid[IDX_LCP] = ++sp->pp_seq; - sppp_cp_send (sp, PPP_LCP, CONF_REQ, sp->confid[IDX_LCP], i, &opt); -} - -/* - * Check the open NCPs, return true if at least one NCP is open. - */ -static int -sppp_ncp_check(struct sppp *sp) -{ - int i, mask; - - for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1) - if (sp->lcp.protos & mask && (cps[i])->flags & CP_NCP) - return 1; - return 0; -} - -/* - * Re-check the open NCPs and see if we should terminate the link. - * Called by the NCPs during their tlf action handling. - */ -static void -sppp_lcp_check_and_close(struct sppp *sp) -{ - - if (sp->pp_phase < PHASE_NETWORK) - /* don't bother, we are already going down */ - return; - - if (sppp_ncp_check(sp)) - return; - - lcp.Close(sp); -} - /* - *--------------------------------------------------------------------------* - * * - * The IPCP implementation. * - * * - *--------------------------------------------------------------------------* - */ - -static void -sppp_ipcp_init(struct sppp *sp) -{ - sp->ipcp.opts = 0; - sp->ipcp.flags = 0; - sp->state[IDX_IPCP] = STATE_INITIAL; - sp->fail_counter[IDX_IPCP] = 0; -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - callout_handle_init(&sp->ch[IDX_IPCP]); -#endif -} - -static void -sppp_ipcp_up(struct sppp *sp) -{ - sppp_up_event(&ipcp, sp); -} - -static void -sppp_ipcp_down(struct sppp *sp) -{ - sppp_down_event(&ipcp, sp); -} - -static void -sppp_ipcp_open(struct sppp *sp) -{ - STDDCL; - u_long myaddr, hisaddr; - - sp->ipcp.flags &= ~(IPCP_HISADDR_SEEN|IPCP_MYADDR_SEEN|IPCP_MYADDR_DYN); - - sppp_get_ip_addrs(sp, &myaddr, &hisaddr, 0); - /* - * If we don't have his address, this probably means our - * interface doesn't want to talk IP at all. (This could - * be the case if somebody wants to speak only IPX, for - * example.) Don't open IPCP in this case. - */ - if (hisaddr == 0L) { - /* XXX this message should go away */ - if (debug) - log(LOG_DEBUG, SPP_FMT "ipcp_open(): no IP interface\n", - SPP_ARGS(ifp)); - return; - } - - if (myaddr == 0L) { - /* - * I don't have an assigned address, so i need to - * negotiate my address. - */ - sp->ipcp.flags |= IPCP_MYADDR_DYN; - sp->ipcp.opts |= (1 << IPCP_OPT_ADDRESS); - } else - sp->ipcp.flags |= IPCP_MYADDR_SEEN; - sppp_open_event(&ipcp, sp); -} - -static void -sppp_ipcp_close(struct sppp *sp) -{ - sppp_close_event(&ipcp, sp); - if (sp->ipcp.flags & IPCP_MYADDR_DYN) - /* - * My address was dynamic, clear it again. - */ - sppp_set_ip_addr(sp, 0L); -} - -static void -sppp_ipcp_TO(void *cookie) -{ - sppp_to_event(&ipcp, (struct sppp *)cookie); -} - -/* - * Analyze a configure request. Return true if it was agreeable, and - * caused action sca, false if it has been rejected or nak'ed, and - * caused action scn. (The return value is used to make the state - * transition decision in the state automaton.) - */ -static int -sppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len) -{ - u_char *buf, *r, *p; - struct ifnet *ifp = &sp->pp_if; - int rlen, origlen, debug = ifp->if_flags & IFF_DEBUG; - u_long hisaddr, desiredaddr; - int gotmyaddr = 0; - - len -= 4; - origlen = len; - /* - * Make sure to allocate a buf that can at least hold a - * conf-nak with an `address' option. We might need it below. - */ - buf = r = MALLOC ((len < 6? 6: len), M_TEMP, M_WAITOK); - if (! buf) - return (0); - - /* pass 1: see if we can recognize them */ - if (debug) - log(LOG_DEBUG, SPP_FMT "ipcp parse opts: ", - SPP_ARGS(ifp)); - p = (void*) (h+1); - for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { - if (debug) - addlog(" %s ", sppp_ipcp_opt_name(*p)); - switch (*p) { -#ifdef notyet - case IPCP_OPT_COMPRESSION: - if (len >= 6 && p[1] >= 6) { - /* correctly formed compress option */ - continue; - } - if (debug) - addlog("[invalid] "); - break; -#endif - case IPCP_OPT_ADDRESS: - if (len >= 6 && p[1] == 6) { - /* correctly formed address option */ - continue; - } - if (debug) - addlog("[invalid] "); - break; - default: - /* Others not supported. */ - if (debug) - addlog("[rej] "); - break; - } - /* Add the option to rejected list. */ - bcopy (p, r, p[1]); - r += p[1]; - rlen += p[1]; - } - if (rlen) { - if (debug) - addlog(" send conf-rej\n"); - sppp_cp_send (sp, PPP_IPCP, CONF_REJ, h->ident, rlen, buf); - return 0; - } else if (debug) - addlog("\n"); - - /* pass 2: parse option values */ - sppp_get_ip_addrs(sp, 0, &hisaddr, 0); - if (debug) - log(LOG_DEBUG, SPP_FMT "ipcp parse opt values: ", - SPP_ARGS(ifp)); - p = (void*) (h+1); - len = origlen; - for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { - if (debug) - addlog(" %s ", sppp_ipcp_opt_name(*p)); - switch (*p) { -#ifdef notyet - case IPCP_OPT_COMPRESSION: - continue; -#endif - case IPCP_OPT_ADDRESS: - /* This is the address he wants in his end */ - desiredaddr = p[2] << 24 | p[3] << 16 | - p[4] << 8 | p[5]; - if (desiredaddr == hisaddr || - (hisaddr == 1 && desiredaddr != 0)) { - /* - * Peer's address is same as our value, - * or we have set it to 0.0.0.1 to - * indicate that we do not really care, - * this is agreeable. Gonna conf-ack - * it. - */ - if (debug) - addlog("%s [ack] ", - sppp_dotted_quad(hisaddr)); - /* record that we've seen it already */ - sp->ipcp.flags |= IPCP_HISADDR_SEEN; - continue; - } - /* - * The address wasn't agreeable. This is either - * he sent us 0.0.0.0, asking to assign him an - * address, or he send us another address not - * matching our value. Either case, we gonna - * conf-nak it with our value. - * XXX: we should "rej" if hisaddr == 0 - */ - if (debug) { - if (desiredaddr == 0) - addlog("[addr requested] "); - else - addlog("%s [not agreed] ", - sppp_dotted_quad(desiredaddr)); - - p[2] = hisaddr >> 24; - p[3] = hisaddr >> 16; - p[4] = hisaddr >> 8; - p[5] = hisaddr; - } - break; - } - /* Add the option to nak'ed list. */ - bcopy (p, r, p[1]); - r += p[1]; - rlen += p[1]; - } - - /* - * If we are about to conf-ack the request, but haven't seen - * his address so far, gonna conf-nak it instead, with the - * `address' option present and our idea of his address being - * filled in there, to request negotiation of both addresses. - * - * XXX This can result in an endless req - nak loop if peer - * doesn't want to send us his address. Q: What should we do - * about it? XXX A: implement the max-failure counter. - */ - if (rlen == 0 && !(sp->ipcp.flags & IPCP_HISADDR_SEEN) && !gotmyaddr) { - buf[0] = IPCP_OPT_ADDRESS; - buf[1] = 6; - buf[2] = hisaddr >> 24; - buf[3] = hisaddr >> 16; - buf[4] = hisaddr >> 8; - buf[5] = hisaddr; - rlen = 6; - if (debug) - addlog("still need hisaddr "); - } - - if (rlen) { - if (debug) - addlog(" send conf-nak\n"); - sppp_cp_send (sp, PPP_IPCP, CONF_NAK, h->ident, rlen, buf); - } else { - if (debug) - addlog(" send conf-ack\n"); - sppp_cp_send (sp, PPP_IPCP, CONF_ACK, - h->ident, origlen, h+1); - } - - FREE(buf, M_TEMP); - return (rlen == 0); -} - -/* - * Analyze the IPCP Configure-Reject option list, and adjust our - * negotiation. - */ -static void -sppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len) -{ - u_char *buf, *p; - struct ifnet *ifp = &sp->pp_if; - int debug = ifp->if_flags & IFF_DEBUG; - - len -= 4; - buf = MALLOC (len, M_TEMP, M_WAITOK); - if (!buf) - return; - - if (debug) - log(LOG_DEBUG, SPP_FMT "ipcp rej opts: ", - SPP_ARGS(ifp)); - - p = (void*) (h+1); - for (; len > 1 && p[1]; len -= p[1], p += p[1]) { - if (debug) - addlog(" %s ", sppp_ipcp_opt_name(*p)); - switch (*p) { - case IPCP_OPT_ADDRESS: - /* - * Peer doesn't grok address option. This is - * bad. XXX Should we better give up here? - * XXX We could try old "addresses" option... - */ - sp->ipcp.opts &= ~(1 << IPCP_OPT_ADDRESS); - break; -#ifdef notyet - case IPCP_OPT_COMPRESS: - sp->ipcp.opts &= ~(1 << IPCP_OPT_COMPRESS); - break; -#endif - } - } - if (debug) - addlog("\n"); - FREE(buf, M_TEMP); - return; -} - -/* - * Analyze the IPCP Configure-NAK option list, and adjust our - * negotiation. - */ -static void -sppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len) -{ - u_char *buf, *p; - struct ifnet *ifp = &sp->pp_if; - int debug = ifp->if_flags & IFF_DEBUG; - u_long wantaddr; - - len -= 4; - buf = MALLOC (len, M_TEMP, M_WAITOK); - if (!buf) - return; - - if (debug) - log(LOG_DEBUG, SPP_FMT "ipcp nak opts: ", - SPP_ARGS(ifp)); - - p = (void*) (h+1); - for (; len > 1 && p[1]; len -= p[1], p += p[1]) { - if (debug) - addlog(" %s ", sppp_ipcp_opt_name(*p)); - switch (*p) { - case IPCP_OPT_ADDRESS: - /* - * Peer doesn't like our local IP address. See - * if we can do something for him. We'll drop - * him our address then. - */ - if (len >= 6 && p[1] == 6) { - wantaddr = p[2] << 24 | p[3] << 16 | - p[4] << 8 | p[5]; - sp->ipcp.opts |= (1 << IPCP_OPT_ADDRESS); - if (debug) - addlog("[wantaddr %s] ", - sppp_dotted_quad(wantaddr)); - /* - * When doing dynamic address assignment, - * we accept his offer. Otherwise, we - * ignore it and thus continue to negotiate - * our already existing value. - * XXX: Bogus, if he said no once, he'll - * just say no again, might as well die. - */ - if (sp->ipcp.flags & IPCP_MYADDR_DYN) { - sppp_set_ip_addr(sp, wantaddr); - if (debug) - addlog("[agree] "); - sp->ipcp.flags |= IPCP_MYADDR_SEEN; - } - } - break; -#ifdef notyet - case IPCP_OPT_COMPRESS: - /* - * Peer wants different compression parameters. - */ - break; -#endif - } - } - if (debug) - addlog("\n"); - FREE(buf, M_TEMP); - return; -} - -static void -sppp_ipcp_tlu(struct sppp *sp) -{ - /* we are up - notify isdn daemon */ - if (sp->pp_con) - sp->pp_con(sp); -} - -static void -sppp_ipcp_tld(struct sppp *sp) -{ -} - -static void -sppp_ipcp_tls(struct sppp *sp) -{ - /* indicate to LCP that it must stay alive */ - sp->lcp.protos |= (1 << IDX_IPCP); -} - -static void -sppp_ipcp_tlf(struct sppp *sp) -{ - /* we no longer need LCP */ - sp->lcp.protos &= ~(1 << IDX_IPCP); - sppp_lcp_check_and_close(sp); -} - -static void -sppp_ipcp_scr(struct sppp *sp) -{ - char opt[6 /* compression */ + 6 /* address */]; - u_long ouraddr; - int i = 0; - -#ifdef notyet - if (sp->ipcp.opts & (1 << IPCP_OPT_COMPRESSION)) { - opt[i++] = IPCP_OPT_COMPRESSION; - opt[i++] = 6; - opt[i++] = 0; /* VJ header compression */ - opt[i++] = 0x2d; /* VJ header compression */ - opt[i++] = max_slot_id; - opt[i++] = comp_slot_id; - } -#endif - - if (sp->ipcp.opts & (1 << IPCP_OPT_ADDRESS)) { - sppp_get_ip_addrs(sp, &ouraddr, 0, 0); - opt[i++] = IPCP_OPT_ADDRESS; - opt[i++] = 6; - opt[i++] = ouraddr >> 24; - opt[i++] = ouraddr >> 16; - opt[i++] = ouraddr >> 8; - opt[i++] = ouraddr; - } - - sp->confid[IDX_IPCP] = ++sp->pp_seq; - sppp_cp_send(sp, PPP_IPCP, CONF_REQ, sp->confid[IDX_IPCP], i, &opt); -} - - - /* - *--------------------------------------------------------------------------* - * * - * The CHAP implementation. * - * * - *--------------------------------------------------------------------------* - */ - -/* - * The authentication protocols don't employ a full-fledged state machine as - * the control protocols do, since they do have Open and Close events, but - * not Up and Down, nor are they explicitly terminated. Also, use of the - * authentication protocols may be different in both directions (this makes - * sense, think of a machine that never accepts incoming calls but only - * calls out, it doesn't require the called party to authenticate itself). - * - * Our state machine for the local authentication protocol (we are requesting - * the peer to authenticate) looks like: - * - * RCA- - * +--------------------------------------------+ - * V scn,tld| - * +--------+ Close +---------+ RCA+ - * | |<----------------------------------| |------+ - * +--->| Closed | TO* | Opened | sca | - * | | |-----+ +-------| |<-----+ - * | +--------+ irc | | +---------+ - * | ^ | | ^ - * | | | | | - * | | | | | - * | TO-| | | | - * | |tld TO+ V | | - * | | +------->+ | | - * | | | | | | - * | +--------+ V | | - * | | |<----+<--------------------+ | - * | | Req- | scr | - * | | Sent | | - * | | | | - * | +--------+ | - * | RCA- | | RCA+ | - * +------+ +------------------------------------------+ - * scn,tld sca,irc,ict,tlu - * - * - * with: - * - * Open: LCP reached authentication phase - * Close: LCP reached terminate phase - * - * RCA+: received reply (pap-req, chap-response), acceptable - * RCN: received reply (pap-req, chap-response), not acceptable - * TO+: timeout with restart counter >= 0 - * TO-: timeout with restart counter < 0 - * TO*: reschedule timeout for CHAP - * - * scr: send request packet (none for PAP, chap-challenge) - * sca: send ack packet (pap-ack, chap-success) - * scn: send nak packet (pap-nak, chap-failure) - * ict: initialize re-challenge timer (CHAP only) - * - * tlu: this-layer-up, LCP reaches network phase - * tld: this-layer-down, LCP enters terminate phase - * - * Note that in CHAP mode, after sending a new challenge, while the state - * automaton falls back into Req-Sent state, it doesn't signal a tld - * event to LCP, so LCP remains in network phase. Only after not getting - * any response (or after getting an unacceptable response), CHAP closes, - * causing LCP to enter terminate phase. - * - * With PAP, there is no initial request that can be sent. The peer is - * expected to send one based on the successful negotiation of PAP as - * the authentication protocol during the LCP option negotiation. - * - * Incoming authentication protocol requests (remote requests - * authentication, we are peer) don't employ a state machine at all, - * they are simply answered. Some peers [Ascend P50 firmware rev - * 4.50] react allergically when sending IPCP requests while they are - * still in authentication phase (thereby violating the standard that - * demands that these NCP packets are to be discarded), so we keep - * track of the peer demanding us to authenticate, and only proceed to - * phase network once we've seen a positive acknowledge for the - * authentication. - */ - -/* - * Handle incoming CHAP packets. - */ -void -sppp_chap_input(struct sppp *sp, struct mbuf *m) -{ - STDDCL; - struct lcp_header *h; - int len, x; - u_char *value, *name, digest[AUTHKEYLEN], dsize; - int value_len, name_len; - MD5_CTX ctx; - - len = m->m_pkthdr.len; - if (len < 4) { - if (debug) - log(LOG_DEBUG, - SPP_FMT "chap invalid packet length: %d bytes\n", - SPP_ARGS(ifp), len); - return; - } - h = mtod (m, struct lcp_header*); - if (len > ntohs (h->len)) - len = ntohs (h->len); - - switch (h->type) { - /* challenge, failure and success are his authproto */ - case CHAP_CHALLENGE: - value = 1 + (u_char*)(h+1); - value_len = value[-1]; - name = value + value_len; - name_len = len - value_len - 5; - if (name_len < 0) { - if (debug) { - log(LOG_DEBUG, - SPP_FMT "chap corrupted challenge " - "<%s id=0x%x len=%d", - SPP_ARGS(ifp), - sppp_auth_type_name(PPP_CHAP, h->type), - h->ident, ntohs(h->len)); - if (len > 4) - sppp_print_bytes((u_char*) (h+1), len-4); - addlog(">\n"); - } - break; - } - - if (debug) { - log(LOG_DEBUG, - SPP_FMT "chap input <%s id=0x%x len=%d name=", - SPP_ARGS(ifp), - sppp_auth_type_name(PPP_CHAP, h->type), h->ident, - ntohs(h->len)); - sppp_print_string((char*) name, name_len); - addlog(" value-size=%d value=", value_len); - sppp_print_bytes(value, value_len); - addlog(">\n"); - } - - /* Compute reply value. */ - MD5Init(&ctx); - MD5Update(&ctx, &h->ident, 1); - MD5Update(&ctx, sp->myauth.secret, - sppp_strnlen(sp->myauth.secret, AUTHKEYLEN)); - MD5Update(&ctx, value, value_len); - MD5Final(digest, &ctx); - dsize = sizeof digest; - - sppp_auth_send(&chap, sp, CHAP_RESPONSE, h->ident, - sizeof dsize, (const char *)&dsize, - sizeof digest, digest, - (size_t)sppp_strnlen(sp->myauth.name, AUTHNAMELEN), - sp->myauth.name, - 0); - break; - - case CHAP_SUCCESS: - if (debug) { - log(LOG_DEBUG, SPP_FMT "chap success", - SPP_ARGS(ifp)); - if (len > 4) { - addlog(": "); - sppp_print_string((char*)(h + 1), len - 4); - } - addlog("\n"); - } - x = splimp(); - sp->pp_flags &= ~PP_NEEDAUTH; - if (sp->myauth.proto == PPP_CHAP && - (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) && - (sp->lcp.protos & (1 << IDX_CHAP)) == 0) { - /* - * We are authenticator for CHAP but didn't - * complete yet. Leave it to tlu to proceed - * to network phase. - */ - splx(x); - break; - } - splx(x); - sppp_phase_network(sp); - break; - - case CHAP_FAILURE: - if (debug) { - log(LOG_INFO, SPP_FMT "chap failure", - SPP_ARGS(ifp)); - if (len > 4) { - addlog(": "); - sppp_print_string((char*)(h + 1), len - 4); - } - addlog("\n"); - } else - log(LOG_INFO, SPP_FMT "chap failure\n", - SPP_ARGS(ifp)); - /* await LCP shutdown by authenticator */ - break; - - /* response is my authproto */ - case CHAP_RESPONSE: - value = 1 + (u_char*)(h+1); - value_len = value[-1]; - name = value + value_len; - name_len = len - value_len - 5; - if (name_len < 0) { - if (debug) { - log(LOG_DEBUG, - SPP_FMT "chap corrupted response " - "<%s id=0x%x len=%d", - SPP_ARGS(ifp), - sppp_auth_type_name(PPP_CHAP, h->type), - h->ident, ntohs(h->len)); - if (len > 4) - sppp_print_bytes((u_char*)(h+1), len-4); - addlog(">\n"); - } - break; - } - if (h->ident != sp->confid[IDX_CHAP]) { - if (debug) - log(LOG_DEBUG, - SPP_FMT "chap dropping response for old ID " - "(got %d, expected %d)\n", - SPP_ARGS(ifp), - h->ident, sp->confid[IDX_CHAP]); - break; - } - if (name_len != sppp_strnlen(sp->hisauth.name, AUTHNAMELEN) - || bcmp(name, sp->hisauth.name, name_len) != 0) { - log(LOG_INFO, SPP_FMT "chap response, his name ", - SPP_ARGS(ifp)); - sppp_print_string(name, name_len); - addlog(" != expected "); - sppp_print_string(sp->hisauth.name, - sppp_strnlen(sp->hisauth.name, AUTHNAMELEN)); - addlog("\n"); - } - if (debug) { - log(LOG_DEBUG, SPP_FMT "chap input(%s) " - "<%s id=0x%x len=%d name=", - SPP_ARGS(ifp), - sppp_state_name(sp->state[IDX_CHAP]), - sppp_auth_type_name(PPP_CHAP, h->type), - h->ident, ntohs (h->len)); - sppp_print_string((char*)name, name_len); - addlog(" value-size=%d value=", value_len); - sppp_print_bytes(value, value_len); - addlog(">\n"); - } - if (value_len != AUTHKEYLEN) { - if (debug) - log(LOG_DEBUG, - SPP_FMT "chap bad hash value length: " - "%d bytes, should be %d\n", - SPP_ARGS(ifp), value_len, - AUTHKEYLEN); - break; - } - - MD5Init(&ctx); - MD5Update(&ctx, &h->ident, 1); - MD5Update(&ctx, sp->hisauth.secret, - sppp_strnlen(sp->hisauth.secret, AUTHKEYLEN)); - MD5Update(&ctx, sp->myauth.challenge, AUTHKEYLEN); - MD5Final(digest, &ctx); - -#define FAILMSG "Failed..." -#define SUCCMSG "Welcome!" - - if (value_len != sizeof digest || - bcmp(digest, value, value_len) != 0) { - /* action scn, tld */ - sppp_auth_send(&chap, sp, CHAP_FAILURE, h->ident, - sizeof(FAILMSG) - 1, (u_char *)FAILMSG, - 0); - chap.tld(sp); - break; - } - /* action sca, perhaps tlu */ - if (sp->state[IDX_CHAP] == STATE_REQ_SENT || - sp->state[IDX_CHAP] == STATE_OPENED) - sppp_auth_send(&chap, sp, CHAP_SUCCESS, h->ident, - sizeof(SUCCMSG) - 1, (u_char *)SUCCMSG, - 0); - if (sp->state[IDX_CHAP] == STATE_REQ_SENT) { - sppp_cp_change_state(&chap, sp, STATE_OPENED); - chap.tlu(sp); - } - break; - - default: - /* Unknown CHAP packet type -- ignore. */ - if (debug) { - log(LOG_DEBUG, SPP_FMT "chap unknown input(%s) " - "<0x%x id=0x%xh len=%d", - SPP_ARGS(ifp), - sppp_state_name(sp->state[IDX_CHAP]), - h->type, h->ident, ntohs(h->len)); - if (len > 4) - sppp_print_bytes((u_char*)(h+1), len-4); - addlog(">\n"); - } - break; - - } -} - -static void -sppp_chap_init(struct sppp *sp) -{ - /* Chap doesn't have STATE_INITIAL at all. */ - sp->state[IDX_CHAP] = STATE_CLOSED; - sp->fail_counter[IDX_CHAP] = 0; -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - callout_handle_init(&sp->ch[IDX_CHAP]); -#endif -} - -static void -sppp_chap_open(struct sppp *sp) -{ - if (sp->myauth.proto == PPP_CHAP && - (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) != 0) { - /* we are authenticator for CHAP, start it */ - chap.scr(sp); - sp->rst_counter[IDX_CHAP] = sp->lcp.max_configure; - sppp_cp_change_state(&chap, sp, STATE_REQ_SENT); - } - /* nothing to be done if we are peer, await a challenge */ -} - -static void -sppp_chap_close(struct sppp *sp) -{ - if (sp->state[IDX_CHAP] != STATE_CLOSED) - sppp_cp_change_state(&chap, sp, STATE_CLOSED); -} - -static void -sppp_chap_TO(void *cookie) -{ - struct sppp *sp = (struct sppp *)cookie; - STDDCL; - int s; - - s = splimp(); - if (debug) - log(LOG_DEBUG, SPP_FMT "chap TO(%s) rst_counter = %d\n", - SPP_ARGS(ifp), - sppp_state_name(sp->state[IDX_CHAP]), - sp->rst_counter[IDX_CHAP]); - - if (--sp->rst_counter[IDX_CHAP] < 0) - /* TO- event */ - switch (sp->state[IDX_CHAP]) { - case STATE_REQ_SENT: - chap.tld(sp); - sppp_cp_change_state(&chap, sp, STATE_CLOSED); - break; - } - else - /* TO+ (or TO*) event */ - switch (sp->state[IDX_CHAP]) { - case STATE_OPENED: - /* TO* event */ - sp->rst_counter[IDX_CHAP] = sp->lcp.max_configure; - /* fall through */ - case STATE_REQ_SENT: - chap.scr(sp); - /* sppp_cp_change_state() will restart the timer */ - sppp_cp_change_state(&chap, sp, STATE_REQ_SENT); - break; - } - - splx(s); -} - -static void -sppp_chap_tlu(struct sppp *sp) -{ - STDDCL; - int i, x; - - i = 0; - sp->rst_counter[IDX_CHAP] = sp->lcp.max_configure; - - /* - * Some broken CHAP implementations (Conware CoNet, firmware - * 4.0.?) don't want to re-authenticate their CHAP once the - * initial challenge-response exchange has taken place. - * Provide for an option to avoid rechallenges. - */ - if ((sp->hisauth.flags & AUTHFLAG_NORECHALLENGE) == 0) { - /* - * Compute the re-challenge timeout. This will yield - * a number between 300 and 810 seconds. - */ - i = 300 + ((unsigned)(random() & 0xff00) >> 7); - TIMEOUT(chap.TO, (void *)sp, i * hz, sp->ch[IDX_CHAP]); - } - - if (debug) { - log(LOG_DEBUG, - SPP_FMT "chap %s, ", - SPP_ARGS(ifp), - sp->pp_phase == PHASE_NETWORK? "reconfirmed": "tlu"); - if ((sp->hisauth.flags & AUTHFLAG_NORECHALLENGE) == 0) - addlog("next re-challenge in %d seconds\n", i); - else - addlog("re-challenging supressed\n"); - } - - x = splimp(); - /* indicate to LCP that we need to be closed down */ - sp->lcp.protos |= (1 << IDX_CHAP); - - if (sp->pp_flags & PP_NEEDAUTH) { - /* - * Remote is authenticator, but his auth proto didn't - * complete yet. Defer the transition to network - * phase. - */ - splx(x); - return; - } - splx(x); - - /* - * If we are already in phase network, we are done here. This - * is the case if this is a dummy tlu event after a re-challenge. - */ - if (sp->pp_phase != PHASE_NETWORK) - sppp_phase_network(sp); -} - -static void -sppp_chap_tld(struct sppp *sp) -{ - STDDCL; - - if (debug) - log(LOG_DEBUG, SPP_FMT "chap tld\n", SPP_ARGS(ifp)); - UNTIMEOUT(chap.TO, (void *)sp, sp->ch[IDX_CHAP]); - sp->lcp.protos &= ~(1 << IDX_CHAP); - - lcp.Close(sp); -} - -static void -sppp_chap_scr(struct sppp *sp) -{ - u_long *ch, seed; - u_char clen; - - /* Compute random challenge. */ - ch = (u_long *)sp->myauth.challenge; -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - read_random(&seed, sizeof seed); -#else - { - struct timeval tv; - microtime(&tv); - seed = tv.tv_sec ^ tv.tv_usec; - } -#endif - ch[0] = seed ^ random(); - ch[1] = seed ^ random(); - ch[2] = seed ^ random(); - ch[3] = seed ^ random(); - clen = AUTHKEYLEN; - - sp->confid[IDX_CHAP] = ++sp->pp_seq; - - sppp_auth_send(&chap, sp, CHAP_CHALLENGE, sp->confid[IDX_CHAP], - sizeof clen, (const char *)&clen, - (size_t)AUTHKEYLEN, sp->myauth.challenge, - (size_t)sppp_strnlen(sp->myauth.name, AUTHNAMELEN), - sp->myauth.name, - 0); -} - /* - *--------------------------------------------------------------------------* - * * - * The PAP implementation. * - * * - *--------------------------------------------------------------------------* - */ -/* - * For PAP, we need to keep a little state also if we are the peer, not the - * authenticator. This is since we don't get a request to authenticate, but - * have to repeatedly authenticate ourself until we got a response (or the - * retry counter is expired). - */ - -/* - * Handle incoming PAP packets. */ -static void -sppp_pap_input(struct sppp *sp, struct mbuf *m) -{ - STDDCL; - struct lcp_header *h; - int len, x; - u_char *name, *passwd, mlen; - int name_len, passwd_len; - - len = m->m_pkthdr.len; - if (len < 5) { - if (debug) - log(LOG_DEBUG, - SPP_FMT "pap invalid packet length: %d bytes\n", - SPP_ARGS(ifp), len); - return; - } - h = mtod (m, struct lcp_header*); - if (len > ntohs (h->len)) - len = ntohs (h->len); - switch (h->type) { - /* PAP request is my authproto */ - case PAP_REQ: - name = 1 + (u_char*)(h+1); - name_len = name[-1]; - passwd = name + name_len + 1; - if (name_len > len - 6 || - (passwd_len = passwd[-1]) > len - 6 - name_len) { - if (debug) { - log(LOG_DEBUG, SPP_FMT "pap corrupted input " - "<%s id=0x%x len=%d", - SPP_ARGS(ifp), - sppp_auth_type_name(PPP_PAP, h->type), - h->ident, ntohs(h->len)); - if (len > 4) - sppp_print_bytes((u_char*)(h+1), len-4); - addlog(">\n"); - } - break; - } - if (debug) { - log(LOG_DEBUG, SPP_FMT "pap input(%s) " - "<%s id=0x%x len=%d name=", - SPP_ARGS(ifp), - sppp_state_name(sp->state[IDX_PAP]), - sppp_auth_type_name(PPP_PAP, h->type), - h->ident, ntohs(h->len)); - sppp_print_string((char*)name, name_len); - addlog(" passwd="); - sppp_print_string((char*)passwd, passwd_len); - addlog(">\n"); - } - if (name_len > AUTHNAMELEN || - passwd_len > AUTHKEYLEN || - bcmp(name, sp->hisauth.name, name_len) != 0 || - bcmp(passwd, sp->hisauth.secret, passwd_len) != 0) { - /* action scn, tld */ - mlen = sizeof(FAILMSG) - 1; - sppp_auth_send(&pap, sp, PAP_NAK, h->ident, - sizeof mlen, (const char *)&mlen, - sizeof(FAILMSG) - 1, (u_char *)FAILMSG, - 0); - pap.tld(sp); - break; - } - /* action sca, perhaps tlu */ - if (sp->state[IDX_PAP] == STATE_REQ_SENT || - sp->state[IDX_PAP] == STATE_OPENED) { - mlen = sizeof(SUCCMSG) - 1; - sppp_auth_send(&pap, sp, PAP_ACK, h->ident, - sizeof mlen, (const char *)&mlen, - sizeof(SUCCMSG) - 1, (u_char *)SUCCMSG, - 0); - } - if (sp->state[IDX_PAP] == STATE_REQ_SENT) { - sppp_cp_change_state(&pap, sp, STATE_OPENED); - pap.tlu(sp); - } - break; - - /* ack and nak are his authproto */ - case PAP_ACK: - UNTIMEOUT(sppp_pap_my_TO, (void *)sp, sp->pap_my_to_ch); - if (debug) { - log(LOG_DEBUG, SPP_FMT "pap success", - SPP_ARGS(ifp)); - name_len = *((char *)h); - if (len > 5 && name_len) { - addlog(": "); - sppp_print_string((char*)(h+1), name_len); - } - addlog("\n"); - } - x = splimp(); - sp->pp_flags &= ~PP_NEEDAUTH; - if (sp->myauth.proto == PPP_PAP && - (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) && - (sp->lcp.protos & (1 << IDX_PAP)) == 0) { - /* - * We are authenticator for PAP but didn't - * complete yet. Leave it to tlu to proceed - * to network phase. - */ - splx(x); - break; - } - splx(x); - sppp_phase_network(sp); - break; - - case PAP_NAK: - UNTIMEOUT(sppp_pap_my_TO, (void *)sp, sp->pap_my_to_ch); - if (debug) { - log(LOG_INFO, SPP_FMT "pap failure", - SPP_ARGS(ifp)); - name_len = *((char *)h); - if (len > 5 && name_len) { - addlog(": "); - sppp_print_string((char*)(h+1), name_len); - } - addlog("\n"); - } else - log(LOG_INFO, SPP_FMT "pap failure\n", - SPP_ARGS(ifp)); - /* await LCP shutdown by authenticator */ - break; - - default: - /* Unknown PAP packet type -- ignore. */ - if (debug) { - log(LOG_DEBUG, SPP_FMT "pap corrupted input " - "<0x%x id=0x%x len=%d", - SPP_ARGS(ifp), - h->type, h->ident, ntohs(h->len)); - if (len > 4) - sppp_print_bytes((u_char*)(h+1), len-4); - addlog(">\n"); - } - break; - - } -} - -static void -sppp_pap_init(struct sppp *sp) -{ - /* PAP doesn't have STATE_INITIAL at all. */ - sp->state[IDX_PAP] = STATE_CLOSED; - sp->fail_counter[IDX_PAP] = 0; -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - callout_handle_init(&sp->ch[IDX_PAP]); - callout_handle_init(&sp->pap_my_to_ch); -#endif -} - -static void -sppp_pap_open(struct sppp *sp) -{ - if (sp->hisauth.proto == PPP_PAP && - (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) != 0) { - /* we are authenticator for PAP, start our timer */ - sp->rst_counter[IDX_PAP] = sp->lcp.max_configure; - sppp_cp_change_state(&pap, sp, STATE_REQ_SENT); - } - if (sp->myauth.proto == PPP_PAP) { - /* we are peer, send a request, and start a timer */ - pap.scr(sp); - TIMEOUT(sppp_pap_my_TO, (void *)sp, sp->lcp.timeout, - sp->pap_my_to_ch); - } -} - -static void -sppp_pap_close(struct sppp *sp) -{ - if (sp->state[IDX_PAP] != STATE_CLOSED) - sppp_cp_change_state(&pap, sp, STATE_CLOSED); -} - -/* - * That's the timeout routine if we are authenticator. Since the - * authenticator is basically passive in PAP, we can't do much here. - */ -static void -sppp_pap_TO(void *cookie) -{ - struct sppp *sp = (struct sppp *)cookie; - STDDCL; - int s; - - s = splimp(); - if (debug) - log(LOG_DEBUG, SPP_FMT "pap TO(%s) rst_counter = %d\n", - SPP_ARGS(ifp), - sppp_state_name(sp->state[IDX_PAP]), - sp->rst_counter[IDX_PAP]); - - if (--sp->rst_counter[IDX_PAP] < 0) - /* TO- event */ - switch (sp->state[IDX_PAP]) { - case STATE_REQ_SENT: - pap.tld(sp); - sppp_cp_change_state(&pap, sp, STATE_CLOSED); - break; - } - else - /* TO+ event, not very much we could do */ - switch (sp->state[IDX_PAP]) { - case STATE_REQ_SENT: - /* sppp_cp_change_state() will restart the timer */ - sppp_cp_change_state(&pap, sp, STATE_REQ_SENT); - break; - } - - splx(s); -} - -/* - * That's the timeout handler if we are peer. Since the peer is active, - * we need to retransmit our PAP request since it is apparently lost. - * XXX We should impose a max counter. - */ -static void -sppp_pap_my_TO(void *cookie) -{ - struct sppp *sp = (struct sppp *)cookie; - STDDCL; - - if (debug) - log(LOG_DEBUG, SPP_FMT "pap peer TO\n", - SPP_ARGS(ifp)); - - pap.scr(sp); -} - -static void -sppp_pap_tlu(struct sppp *sp) -{ - STDDCL; - int x; - - sp->rst_counter[IDX_PAP] = sp->lcp.max_configure; - - if (debug) - log(LOG_DEBUG, SPP_FMT "%s tlu\n", - SPP_ARGS(ifp), pap.name); - - x = splimp(); - /* indicate to LCP that we need to be closed down */ - sp->lcp.protos |= (1 << IDX_PAP); - - if (sp->pp_flags & PP_NEEDAUTH) { - /* - * Remote is authenticator, but his auth proto didn't - * complete yet. Defer the transition to network - * phase. - */ - splx(x); - return; - } - splx(x); - sppp_phase_network(sp); -} - -static void -sppp_pap_tld(struct sppp *sp) -{ - STDDCL; - - if (debug) - log(LOG_DEBUG, SPP_FMT "pap tld\n", SPP_ARGS(ifp)); - UNTIMEOUT(pap.TO, (void *)sp, sp->ch[IDX_PAP]); - UNTIMEOUT(sppp_pap_my_TO, (void *)sp, sp->pap_my_to_ch); - sp->lcp.protos &= ~(1 << IDX_PAP); - - lcp.Close(sp); -} - -static void -sppp_pap_scr(struct sppp *sp) -{ - u_char idlen, pwdlen; - - sp->confid[IDX_PAP] = ++sp->pp_seq; - pwdlen = sppp_strnlen(sp->myauth.secret, AUTHKEYLEN); - idlen = sppp_strnlen(sp->myauth.name, AUTHNAMELEN); - - sppp_auth_send(&pap, sp, PAP_REQ, sp->confid[IDX_PAP], - sizeof idlen, (const char *)&idlen, - (size_t)idlen, sp->myauth.name, - sizeof pwdlen, (const char *)&pwdlen, - (size_t)pwdlen, sp->myauth.secret, - 0); -} - /* - * Random miscellaneous functions. - */ - -/* - * Send a PAP or CHAP proto packet. - * - * Varadic function, each of the elements for the ellipsis is of type - * ``size_t mlen, const u_char *msg''. Processing will stop iff - * mlen == 0. - * NOTE: never declare variadic functions with types subject to type - * promotion (i.e. u_char). This is asking for big trouble depending - * on the architecture you are on... - */ - -static void -sppp_auth_send(const struct cp *cp, struct sppp *sp, - unsigned int type, unsigned int id, - ...) -{ - STDDCL; - struct ppp_header *h; - struct lcp_header *lh; - struct mbuf *m; - u_char *p; - int len; - unsigned int mlen; - const char *msg; - va_list ap; - - MGETHDR (m, M_DONTWAIT, MT_DATA); - if (! m) - return; - m->m_pkthdr.rcvif = 0; - - h = mtod (m, struct ppp_header*); - h->address = PPP_ALLSTATIONS; /* broadcast address */ - h->control = PPP_UI; /* Unnumbered Info */ - h->protocol = htons(cp->proto); - - lh = (struct lcp_header*)(h + 1); - lh->type = type; - lh->ident = id; - p = (u_char*) (lh+1); - - va_start(ap, id); - len = 0; - - while ((mlen = (unsigned int)va_arg(ap, size_t)) != 0) { - msg = va_arg(ap, const char *); - len += mlen; - if (len > MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN) { - va_end(ap); - m_freem(m); - return; - } - - bcopy(msg, p, mlen); - p += mlen; - } - va_end(ap); - - m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + LCP_HEADER_LEN + len; - lh->len = htons (LCP_HEADER_LEN + len); - - if (debug) { - log(LOG_DEBUG, SPP_FMT "%s output <%s id=0x%x len=%d", - SPP_ARGS(ifp), cp->name, - sppp_auth_type_name(cp->proto, lh->type), - lh->ident, ntohs(lh->len)); - if (len) - sppp_print_bytes((u_char*) (lh+1), len); - addlog(">\n"); - } - if (IF_QFULL (&sp->pp_cpq)) { - IF_DROP (&sp->pp_fastq); - IF_DROP (&ifp->if_snd); - m_freem (m); - ++ifp->if_oerrors; - } else - IF_ENQUEUE (&sp->pp_cpq, m); - if (! (ifp->if_flags & IFF_OACTIVE)) - (*ifp->if_start) (ifp); - ifp->if_obytes += m->m_pkthdr.len + 3; -} - -/* - * Flush interface queue. - */ -static void -sppp_qflush(struct ifqueue *ifq) -{ - 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; -} - -/* - * Send keepalive packets, every 10 seconds. - */ -static void -sppp_keepalive(void *dummy) -{ - struct sppp *sp; - int s; - - s = splimp(); - for (sp=spppq; sp; sp=sp->pp_next) { - struct ifnet *ifp = &sp->pp_if; - - /* Keepalive mode disabled or channel down? */ - if (! (sp->pp_flags & PP_KEEPALIVE) || - ! (ifp->if_flags & IFF_RUNNING)) - continue; - - /* No keepalive in PPP mode if LCP not opened yet. */ - if (! (sp->pp_flags & PP_CISCO) && - sp->pp_phase < PHASE_AUTHENTICATE) - continue; - - if (sp->pp_alivecnt == MAXALIVECNT) { - /* No keepalive packets got. Stop the interface. */ - printf (SPP_FMT "down\n", SPP_ARGS(ifp)); - if_down (ifp); - sppp_qflush (&sp->pp_cpq); - if (! (sp->pp_flags & PP_CISCO)) { - /* XXX */ - /* Shut down the PPP link. */ - lcp.Down(sp); - /* Initiate negotiation. XXX */ - lcp.Up(sp); - } - } - if (sp->pp_alivecnt <= MAXALIVECNT) - ++sp->pp_alivecnt; - if (sp->pp_flags & PP_CISCO) - sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq, - sp->pp_rseq); - else if (sp->pp_phase >= PHASE_AUTHENTICATE) { - long nmagic = htonl (sp->lcp.magic); - sp->lcp.echoid = ++sp->pp_seq; - sppp_cp_send (sp, PPP_LCP, ECHO_REQ, - sp->lcp.echoid, 4, &nmagic); - } - } - splx(s); - TIMEOUT(sppp_keepalive, 0, hz * 10, keepalive_ch); -} - -/* - * Get both IP addresses. - */ -static void -sppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst, u_long *srcmask) -{ - struct ifnet *ifp = &sp->pp_if; - struct ifaddr *ifa; - struct sockaddr_in *si, *sm; - u_long ssrc, ddst; - - sm = NULL; - ssrc = ddst = 0L; - /* - * Pick the first AF_INET address from the list, - * aliases don't make any sense on a p2p link anyway. - */ - si = 0; -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) -#elif defined(__NetBSD__) || defined (__OpenBSD__) - for (ifa = ifp->if_addrlist.tqh_first; - ifa; - ifa = ifa->ifa_list.tqe_next) -#else - for (ifa = ifp->if_addrlist; - ifa; - ifa = ifa->ifa_next) -#endif - if (ifa->ifa_addr->sa_family == AF_INET) { - si = (struct sockaddr_in *)ifa->ifa_addr; - sm = (struct sockaddr_in *)ifa->ifa_netmask; - if (si) - break; - } - if (ifa) { - if (si && si->sin_addr.s_addr) { - ssrc = si->sin_addr.s_addr; - if (srcmask) - *srcmask = ntohl(sm->sin_addr.s_addr); - } - - si = (struct sockaddr_in *)ifa->ifa_dstaddr; - if (si && si->sin_addr.s_addr) - ddst = si->sin_addr.s_addr; - } - - if (dst) *dst = ntohl(ddst); - if (src) *src = ntohl(ssrc); -} - -/* - * Set my IP address. Must be called at splimp. - */ -static void -sppp_set_ip_addr(struct sppp *sp, u_long src) -{ - STDDCL; - struct ifaddr *ifa; - struct sockaddr_in *si; - - /* - * Pick the first AF_INET address from the list, - * aliases don't make any sense on a p2p link anyway. - */ - si = 0; -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) -#elif defined(__NetBSD__) || defined (__OpenBSD__) - for (ifa = ifp->if_addrlist.tqh_first; - ifa; - ifa = ifa->ifa_list.tqe_next) -#else - for (ifa = ifp->if_addrlist; - ifa; - ifa = ifa->ifa_next) -#endif - { - if (ifa->ifa_addr->sa_family == AF_INET) - { - si = (struct sockaddr_in *)ifa->ifa_addr; - if (si) - break; - } - } - - if (ifa && si) - { - int error; -#if __NetBSD_Version__ >= 103080000 - struct sockaddr_in new_sin = *si; - - new_sin.sin_addr.s_addr = htonl(src); - error = in_ifinit(ifp, ifatoia(ifa), &new_sin, 1); - if(debug && error) - { - log(LOG_DEBUG, SPP_FMT "sppp_set_ip_addr: in_ifinit " - " failed, error=%d\n", SPP_ARGS(ifp), error); - } -#else - /* delete old route */ - error = rtinit(ifa, (int)RTM_DELETE, RTF_HOST); - if(debug && error) - { - log(LOG_DEBUG, SPP_FMT "sppp_set_ip_addr: rtinit DEL failed, error=%d\n", - SPP_ARGS(ifp), error); - } - - /* set new address */ - si->sin_addr.s_addr = htonl(src); - - /* add new route */ - error = rtinit(ifa, (int)RTM_ADD, RTF_HOST); - if (debug && error) - { - log(LOG_DEBUG, SPP_FMT "sppp_set_ip_addr: rtinit ADD failed, error=%d", - SPP_ARGS(ifp), error); - } -#endif - } -} - -static int -sppp_params(struct sppp *sp, u_long cmd, void *data) -{ - u_long subcmd; - struct ifreq *ifr = (struct ifreq *)data; - struct spppreq spr; - - /* - * ifr->ifr_data is supposed to point to a struct spppreq. - * Check the cmd word first before attempting to fetch all the - * data. - */ - if ((subcmd = fuword(ifr->ifr_data)) == -1) - return EFAULT; - - if (copyin((caddr_t)ifr->ifr_data, &spr, sizeof spr) != 0) - return EFAULT; - - switch (subcmd) { - case SPPPIOGDEFS: - if (cmd != SIOCGIFGENERIC) - return EINVAL; - /* - * We copy over the entire current state, but clean - * out some of the stuff we don't wanna pass up. - * Remember, SIOCGIFGENERIC is unprotected, and can be - * called by any user. No need to ever get PAP or - * CHAP secrets back to userland anyway. - */ - bcopy(sp, &spr.defs, sizeof(struct sppp)); - bzero(spr.defs.myauth.secret, AUTHKEYLEN); - bzero(spr.defs.myauth.challenge, AUTHKEYLEN); - bzero(spr.defs.hisauth.secret, AUTHKEYLEN); - bzero(spr.defs.hisauth.challenge, AUTHKEYLEN); - return copyout(&spr, (caddr_t)ifr->ifr_data, sizeof spr); - - case SPPPIOSDEFS: - if (cmd != SIOCSIFGENERIC) - return EINVAL; - /* - * We have a very specific idea of which fields we allow - * being passed back from userland, so to not clobber our - * current state. For one, we only allow setting - * anything if LCP is in dead phase. Once the LCP - * negotiations started, the authentication settings must - * not be changed again. (The administrator can force an - * ifconfig down in order to get LCP back into dead - * phase.) - * - * Also, we only allow for authentication parameters to be - * specified. - * - * XXX Should allow to set or clear pp_flags. - * - * Finally, if the respective authentication protocol to - * be used is set differently than 0, but the secret is - * passed as all zeros, we don't trash the existing secret. - * This allows an administrator to change the system name - * only without clobbering the secret (which he didn't get - * back in a previous SPPPIOGDEFS call). However, the - * secrets are cleared if the authentication protocol is - * reset to 0. - */ - if (sp->pp_phase != PHASE_DEAD) - return EBUSY; - - if ((spr.defs.myauth.proto != 0 && spr.defs.myauth.proto != PPP_PAP && - spr.defs.myauth.proto != PPP_CHAP) || - (spr.defs.hisauth.proto != 0 && spr.defs.hisauth.proto != PPP_PAP && - spr.defs.hisauth.proto != PPP_CHAP)) - return EINVAL; - - if (spr.defs.myauth.proto == 0) - /* resetting myauth */ - bzero(&sp->myauth, sizeof sp->myauth); - else { - /* setting/changing myauth */ - sp->myauth.proto = spr.defs.myauth.proto; - bcopy(spr.defs.myauth.name, sp->myauth.name, AUTHNAMELEN); - if (spr.defs.myauth.secret[0] != '\0') - bcopy(spr.defs.myauth.secret, sp->myauth.secret, - AUTHKEYLEN); - } - if (spr.defs.hisauth.proto == 0) - /* resetting hisauth */ - bzero(&sp->hisauth, sizeof sp->hisauth); - else { - /* setting/changing hisauth */ - sp->hisauth.proto = spr.defs.hisauth.proto; - sp->hisauth.flags = spr.defs.hisauth.flags; - bcopy(spr.defs.hisauth.name, sp->hisauth.name, AUTHNAMELEN); - if (spr.defs.hisauth.secret[0] != '\0') - bcopy(spr.defs.hisauth.secret, sp->hisauth.secret, - AUTHKEYLEN); - } - break; - - default: - return EINVAL; - } - - return 0; -} - -static void -sppp_phase_network(struct sppp *sp) -{ - STDDCL; - int i; - u_long mask; - - sp->pp_phase = PHASE_NETWORK; - - if (debug) - log(LOG_DEBUG, SPP_FMT "phase %s\n", SPP_ARGS(ifp), - sppp_phase_name(sp->pp_phase)); - - /* Notify NCPs now. */ - for (i = 0; i < IDX_COUNT; i++) - if ((cps[i])->flags & CP_NCP) - (cps[i])->Open(sp); - - /* Send Up events to all NCPs. */ - for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1) - if (sp->lcp.protos & mask && ((cps[i])->flags & CP_NCP)) - (cps[i])->Up(sp); - - /* if no NCP is starting, all this was in vain, close down */ - sppp_lcp_check_and_close(sp); -} - - -static const char * -sppp_cp_type_name(u_char type) -{ - static char buf[12]; - switch (type) { - case CONF_REQ: return "conf-req"; - case CONF_ACK: return "conf-ack"; - case CONF_NAK: return "conf-nak"; - case CONF_REJ: return "conf-rej"; - case TERM_REQ: return "term-req"; - case TERM_ACK: return "term-ack"; - case CODE_REJ: return "code-rej"; - case PROTO_REJ: return "proto-rej"; - case ECHO_REQ: return "echo-req"; - case ECHO_REPLY: return "echo-reply"; - case DISC_REQ: return "discard-req"; - } - snprintf (buf, sizeof(buf), "0x%x", type); - return buf; -} - -static const char * -sppp_auth_type_name(u_short proto, u_char type) -{ - static char buf[12]; - switch (proto) { - case PPP_CHAP: - switch (type) { - case CHAP_CHALLENGE: return "challenge"; - case CHAP_RESPONSE: return "response"; - case CHAP_SUCCESS: return "success"; - case CHAP_FAILURE: return "failure"; - } - case PPP_PAP: - switch (type) { - case PAP_REQ: return "req"; - case PAP_ACK: return "ack"; - case PAP_NAK: return "nak"; - } - } - snprintf (buf, sizeof(buf), "0x%x", type); - return buf; -} - -static const char * -sppp_lcp_opt_name(u_char opt) -{ - static char buf[12]; - switch (opt) { - case LCP_OPT_MRU: return "mru"; - case LCP_OPT_ASYNC_MAP: return "async-map"; - case LCP_OPT_AUTH_PROTO: return "auth-proto"; - case LCP_OPT_QUAL_PROTO: return "qual-proto"; - case LCP_OPT_MAGIC: return "magic"; - case LCP_OPT_PROTO_COMP: return "proto-comp"; - case LCP_OPT_ADDR_COMP: return "addr-comp"; - } - snprintf (buf, sizeof(buf), "0x%x", opt); - return buf; -} - -static const char * -sppp_ipcp_opt_name(u_char opt) -{ - static char buf[12]; - switch (opt) { - case IPCP_OPT_ADDRESSES: return "addresses"; - case IPCP_OPT_COMPRESSION: return "compression"; - case IPCP_OPT_ADDRESS: return "address"; - } - snprintf (buf, sizeof(buf), "0x%x", opt); - return buf; -} - -static const char * -sppp_state_name(int state) -{ - switch (state) { - case STATE_INITIAL: return "initial"; - case STATE_STARTING: return "starting"; - case STATE_CLOSED: return "closed"; - case STATE_STOPPED: return "stopped"; - case STATE_CLOSING: return "closing"; - case STATE_STOPPING: return "stopping"; - case STATE_REQ_SENT: return "req-sent"; - case STATE_ACK_RCVD: return "ack-rcvd"; - case STATE_ACK_SENT: return "ack-sent"; - case STATE_OPENED: return "opened"; - } - return "illegal"; -} - -static const char * -sppp_phase_name(enum ppp_phase phase) -{ - switch (phase) { - case PHASE_DEAD: return "dead"; - case PHASE_ESTABLISH: return "establish"; - case PHASE_TERMINATE: return "terminate"; - case PHASE_AUTHENTICATE: return "authenticate"; - case PHASE_NETWORK: return "network"; - } - return "illegal"; -} - -static const char * -sppp_proto_name(u_short proto) -{ - static char buf[12]; - switch (proto) { - case PPP_LCP: return "lcp"; - case PPP_IPCP: return "ipcp"; - case PPP_PAP: return "pap"; - case PPP_CHAP: return "chap"; - } - snprintf(buf, sizeof(buf), "0x%x", (unsigned)proto); - return buf; -} - -static void -sppp_print_bytes(const u_char *p, u_short len) -{ - addlog(" %02x", *p++); - while (--len > 0) - addlog("-%02x", *p++); -} - -static void -sppp_print_string(const char *p, u_short len) -{ - u_char c; - - while (len-- > 0) { - c = *p++; - /* - * Print only ASCII chars directly. RFC 1994 recommends - * using only them, but we don't rely on it. */ - if (c < ' ' || c > '~') - addlog("\\x%x", c); - else - addlog("%c", c); - } -} - -static const char * -sppp_dotted_quad(u_long addr) -{ - static char s[16]; - sprintf(s, "%d.%d.%d.%d", - (int)((addr >> 24) & 0xff), - (int)((addr >> 16) & 0xff), - (int)((addr >> 8) & 0xff), - (int)(addr & 0xff)); - return s; -} - -static int -sppp_strnlen(u_char *p, int max) -{ - int len; - - for (len = 0; len < max && *p; ++p) - ++len; - return len; -} - -/* a dummy, used to drop uninteresting events */ -static void -sppp_null(struct sppp *unused) -{ - /* do just nothing */ -} diff --git a/bsd/net/if_stf.c b/bsd/net/if_stf.c new file mode 100644 index 000000000..7bdf6faa5 --- /dev/null +++ b/bsd/net/if_stf.c @@ -0,0 +1,812 @@ +/* $FreeBSD: src/sys/net/if_stf.c,v 1.1.2.6 2001/07/24 19:10:18 brooks Exp $ */ +/* $KAME: if_stf.c,v 1.62 2001/06/07 22:32:16 itojun Exp $ */ + +/* + * Copyright (C) 2000 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * 6to4 interface, based on RFC3056. + * + * 6to4 interface is NOT capable of link-layer (I mean, IPv4) multicasting. + * There is no address mapping defined from IPv6 multicast address to IPv4 + * address. Therefore, we do not have IFF_MULTICAST on the interface. + * + * Due to the lack of address mapping for link-local addresses, we cannot + * throw packets toward link-local addresses (fe80::x). Also, we cannot throw + * packets to link-local multicast addresses (ff02::x). + * + * Here are interesting symptoms due to the lack of link-local address: + * + * Unicast routing exchange: + * - RIPng: Impossible. Uses link-local multicast packet toward ff02::9, + * and link-local addresses as nexthop. + * - OSPFv6: Impossible. OSPFv6 assumes that there's link-local address + * assigned to the link, and makes use of them. Also, HELLO packets use + * link-local multicast addresses (ff02::5 and ff02::6). + * - BGP4+: Maybe. You can only use global address as nexthop, and global + * address as TCP endpoint address. + * + * Multicast routing protocols: + * - PIM: Hello packet cannot be used to discover adjacent PIM routers. + * Adjacent PIM routers must be configured manually (is it really spec-wise + * correct thing to do?). + * + * ICMPv6: + * - Redirects cannot be used due to the lack of link-local address. + * + * stf interface does not have, and will not need, a link-local address. + * It seems to have no real benefit and does not help the above symptoms much. + * Even if we assign link-locals to interface, we cannot really + * use link-local unicast/multicast on top of 6to4 cloud (since there's no + * encapsulation defined for link-local address), and the above analysis does + * not change. RFC3056 does not mandate the assignment of link-local address + * either. + * + * 6to4 interface has security issues. Refer to + * http://playground.iijlab.net/i-d/draft-itojun-ipv6-transition-abuse-00.txt + * for details. The code tries to filter out some of malicious packets. + * Note that there is no way to be 100% secure. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + + +#include + +#include + +#define IN6_IS_ADDR_6TO4(x) (ntohs((x)->s6_addr16[0]) == 0x2002) +#define GET_V4(x) ((struct in_addr *)(&(x)->s6_addr16[1])) + +struct stf_softc { + struct ifnet sc_if; /* common area */ +#ifdef __APPLE__ + struct if_proto *stf_proto; /* dlil protocol attached */ +#endif + union { + struct route __sc_ro4; + struct route_in6 __sc_ro6; /* just for safety */ + } __sc_ro46; +#define sc_ro __sc_ro46.__sc_ro4 + const struct encaptab *encap_cookie; +}; + +static struct stf_softc *stf; + +#ifdef __APPLE__ +void stfattach __P((void)); +int stf_pre_output __P((struct ifnet *, register struct mbuf **, struct sockaddr *, + caddr_t, char *, char *, u_long)); +static u_long stf_dl_tag=0; +#endif + +#ifndef __APPLE__ +static MALLOC_DEFINE(M_STF, "stf", "6to4 Tunnel Interface"); +#endif +static int ip_stf_ttl = 40; + +extern struct domain inetdomain; +struct protosw in_stf_protosw = +{ SOCK_RAW, &inetdomain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR, + in_stf_input, rip_output, 0, rip_ctloutput, + 0, + 0, 0, 0, 0, + 0, + &rip_usrreqs +}; + +static int stf_encapcheck __P((const struct mbuf *, int, int, void *)); +static struct in6_ifaddr *stf_getsrcifa6 __P((struct ifnet *)); +int stf_pre_output __P((struct ifnet *, register struct mbuf **, struct sockaddr *, + caddr_t, char *, char *, u_long)); +static int stf_checkaddr4 __P((struct stf_softc *, struct in_addr *, + struct ifnet *)); +static int stf_checkaddr6 __P((struct stf_softc *, struct in6_addr *, + struct ifnet *)); +static void stf_rtrequest __P((int, struct rtentry *, struct sockaddr *)); +int stf_ioctl __P((struct ifnet *, u_long, void *)); + + +static +int stf_add_if(struct ifnet *ifp) +{ + ifp->if_demux = 0; + ifp->if_framer = 0; + return 0; +} + +static +int stf_del_if(struct ifnet *ifp) +{ + return 0; +} + +static +int stf_add_proto(struct ddesc_head_str *desc_head, struct if_proto *proto, u_long dl_tag) +{ + /* Only one protocol may be attached at a time */ + struct stf_softc* stf = (struct stf_softc*)proto->ifp; + if (stf->stf_proto == NULL) + stf->stf_proto = proto; + else { + printf("stf_add_proto: stf already has a proto\n"); + return (EBUSY); + } + + return (0); +} + +static +int stf_del_proto(struct if_proto *proto, u_long dl_tag) +{ + if (((struct stf_softc*)proto->ifp)->stf_proto == proto) + ((struct stf_softc*)proto->ifp)->stf_proto = NULL; + else + return ENOENT; + + return 0; +} + +int stf_shutdown() +{ + return 0; +} + +void stf_reg_if_mods() +{ + struct dlil_ifmod_reg_str stf_ifmod; + + bzero(&stf_ifmod, sizeof(stf_ifmod)); + stf_ifmod.add_if = stf_add_if; + stf_ifmod.del_if = stf_del_if; + stf_ifmod.add_proto = stf_add_proto; + stf_ifmod.del_proto = stf_del_proto; + stf_ifmod.ifmod_ioctl = 0; + stf_ifmod.shutdown = stf_shutdown; + + + if (dlil_reg_if_modules(APPLE_IF_FAM_STF, &stf_ifmod)) + panic("Couldn't register stf modules\n"); + +} + +u_long stf_attach_inet6(struct ifnet *ifp) +{ + struct dlil_proto_reg_str reg; + struct dlil_demux_desc desc; + short native=0; + int stat, i; + + if (stf_dl_tag != 0) + return stf_dl_tag; + + TAILQ_INIT(®.demux_desc_head); + desc.type = DLIL_DESC_RAW; + desc.variants.bitmask.proto_id_length = 0; + desc.variants.bitmask.proto_id = 0; + desc.variants.bitmask.proto_id_mask = 0; + desc.native_type = (char *) &native; + TAILQ_INSERT_TAIL(®.demux_desc_head, &desc, next); + reg.interface_family = ifp->if_family; + reg.unit_number = ifp->if_unit; + reg.input = 0; + reg.pre_output = stf_pre_output; + reg.event = 0; + reg.offer = 0; + reg.ioctl = 0; + reg.default_proto = 0; + reg.protocol_family = PF_INET6; + + stat = dlil_attach_protocol(®, &stf_dl_tag); + if (stat) { + panic("stf_attach_inet6 can't attach interface\n"); + } + + return stf_dl_tag; +} + +u_long stf_detach_inet6(struct ifnet *ifp) +{ + u_long ip_dl_tag = 0; + int stat; + + stat = dlil_find_dltag(ifp->if_family, ifp->if_unit, AF_INET6, &ip_dl_tag); + if (stat == 0) { + stat = dlil_detach_protocol(ip_dl_tag); + if (stat) { + printf("WARNING: stf_detach can't detach IP AF_INET6 from interface\n"); + } + } + return (stat); +} + + +void +stfattach(void) +{ + struct ifnet *ifp; + struct stf_softc *sc; + int i, error; + + + int err; + const struct encaptab *p; + + stf_reg_if_mods(); /* DLIL modules */ + + sc = _MALLOC(sizeof(struct stf_softc), M_DEVBUF, M_WAITOK); + if (sc == 0) { + printf("stf softc attach failed\n" ); + return; + } + + bzero(sc, sizeof(*sc)); + sc->sc_if.if_name = "stf"; + sc->sc_if.if_unit = 0; + + p = encap_attach_func(AF_INET, IPPROTO_IPV6, stf_encapcheck, + &in_stf_protosw, sc); + if (p == NULL) { + printf("%s: attach failed\n", if_name(&sc->sc_if)); + FREE(sc, M_DEVBUF); + return; + } + sc->encap_cookie = p; + sc->sc_if.if_mtu = IPV6_MMTU; + sc->sc_if.if_flags = 0; + sc->sc_if.if_ioctl = stf_ioctl; + sc->sc_if.if_output = NULL; /* processing done in pre_output */ + sc->sc_if.if_type = IFT_STF; + sc->sc_if.if_family= APPLE_IF_FAM_STF; +#if 0 + /* turn off ingress filter */ + sc->sc_if.if_flags |= IFF_LINK2; +#endif + sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN; + + if (error = dlil_if_attach(&sc->sc_if)) + printf("stfattach: can't dlil_if_attach error=%d\n"); + else + bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int)); + + return ; +} + +static int +stf_encapcheck(m, off, proto, arg) + const struct mbuf *m; + int off; + int proto; + void *arg; +{ + struct ip ip; + struct in6_ifaddr *ia6; + struct stf_softc *sc; + struct in_addr a, b; + + sc = (struct stf_softc *)arg; + if (sc == NULL) + return 0; + + if ((sc->sc_if.if_flags & IFF_UP) == 0) + return 0; + + /* IFF_LINK0 means "no decapsulation" */ + if ((sc->sc_if.if_flags & IFF_LINK0) != 0) + return 0; + + if (proto != IPPROTO_IPV6) + return 0; + + /* LINTED const cast */ + m_copydata((struct mbuf *)m, 0, sizeof(ip), (caddr_t)&ip); + + if (ip.ip_v != 4) + return 0; + + ia6 = stf_getsrcifa6(&sc->sc_if); + if (ia6 == NULL) + return 0; + + /* + * check if IPv4 dst matches the IPv4 address derived from the + * local 6to4 address. + * success on: dst = 10.1.1.1, ia6->ia_addr = 2002:0a01:0101:... + */ + if (bcmp(GET_V4(&ia6->ia_addr.sin6_addr), &ip.ip_dst, + sizeof(ip.ip_dst)) != 0) + return 0; + + /* + * check if IPv4 src matches the IPv4 address derived from the + * local 6to4 address masked by prefixmask. + * success on: src = 10.1.1.1, ia6->ia_addr = 2002:0a00:.../24 + * fail on: src = 10.1.1.1, ia6->ia_addr = 2002:0b00:.../24 + */ + bzero(&a, sizeof(a)); + a.s_addr = GET_V4(&ia6->ia_addr.sin6_addr)->s_addr; + a.s_addr &= GET_V4(&ia6->ia_prefixmask.sin6_addr)->s_addr; + b = ip.ip_src; + b.s_addr &= GET_V4(&ia6->ia_prefixmask.sin6_addr)->s_addr; + if (a.s_addr != b.s_addr) + return 0; + + /* stf interface makes single side match only */ + return 32; +} + +static struct in6_ifaddr * +stf_getsrcifa6(ifp) + struct ifnet *ifp; +{ + struct ifaddr *ia; + struct in_ifaddr *ia4; + struct sockaddr_in6 *sin6; + struct in_addr in; + + for (ia = ifp->if_addrlist.tqh_first; + ia; + ia = ia->ifa_list.tqe_next) + { + if (ia->ifa_addr == NULL) + continue; + if (ia->ifa_addr->sa_family != AF_INET6) + continue; + sin6 = (struct sockaddr_in6 *)ia->ifa_addr; + if (!IN6_IS_ADDR_6TO4(&sin6->sin6_addr)) + continue; + + bcopy(GET_V4(&sin6->sin6_addr), &in, sizeof(in)); + for (ia4 = TAILQ_FIRST(&in_ifaddrhead); + ia4; + ia4 = TAILQ_NEXT(ia4, ia_link)) + { + if (ia4->ia_addr.sin_addr.s_addr == in.s_addr) + break; + } + if (ia4 == NULL) + continue; + + return (struct in6_ifaddr *)ia; + } + + return NULL; +} + +int +stf_pre_output(ifp, m0, dst, rt, frame_type, address, dl_tag) + struct ifnet *ifp; + register struct mbuf **m0; + struct sockaddr *dst; + caddr_t rt; + char *frame_type; + char *address; + u_long dl_tag; +{ + register struct mbuf *m = *m0; + struct stf_softc *sc; + struct sockaddr_in6 *dst6; + struct in_addr *in4; + struct sockaddr_in *dst4; + u_int8_t tos; + struct ip *ip; + struct ip6_hdr *ip6; + struct in6_ifaddr *ia6; + int error = 0 ; + + sc = (struct stf_softc*)ifp; + dst6 = (struct sockaddr_in6 *)dst; + + /* just in case */ + if ((ifp->if_flags & IFF_UP) == 0) { + printf("stf: IFF_DOWN\n"); + return ENETDOWN; + } + + /* + * If we don't have an ip4 address that match my inner ip6 address, + * we shouldn't generate output. Without this check, we'll end up + * using wrong IPv4 source. + */ + ia6 = stf_getsrcifa6(ifp); + if (ia6 == NULL) { + return ENETDOWN; + } + + if (m->m_len < sizeof(*ip6)) { + m = m_pullup(m, sizeof(*ip6)); + if (!m) + return ENOBUFS; + } + ip6 = mtod(m, struct ip6_hdr *); + tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; + + /* + * Pickup the right outer dst addr from the list of candidates. + * ip6_dst has priority as it may be able to give us shorter IPv4 hops. + */ + if (IN6_IS_ADDR_6TO4(&ip6->ip6_dst)) + in4 = GET_V4(&ip6->ip6_dst); + else if (IN6_IS_ADDR_6TO4(&dst6->sin6_addr)) + in4 = GET_V4(&dst6->sin6_addr); + else { + return ENETUNREACH; + } + + if (ifp->if_bpf) { + /* + * We need to prepend the address family as + * a four byte field. Cons up a dummy header + * to pacify bpf. This is safe because bpf + * will only read from the mbuf (i.e., it won't + * try to free it or keep a pointer a to it). + */ + struct mbuf m0; + u_int32_t af = AF_INET6; + + m0.m_next = m; + m0.m_len = 4; + m0.m_data = (char *)⁡ + + bpf_mtap(ifp, &m0); + } + + M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); + if (m && m->m_len < sizeof(struct ip)) + m = m_pullup(m, sizeof(struct ip)); + if (m == NULL) + return ENOBUFS; + ip = mtod(m, struct ip *); + + bzero(ip, sizeof(*ip)); + + bcopy(GET_V4(&((struct sockaddr_in6 *)&ia6->ia_addr)->sin6_addr), + &ip->ip_src, sizeof(ip->ip_src)); + bcopy(in4, &ip->ip_dst, sizeof(ip->ip_dst)); + ip->ip_p = IPPROTO_IPV6; + ip->ip_ttl = ip_stf_ttl; + ip->ip_len = m->m_pkthdr.len; /*host order*/ + if (ifp->if_flags & IFF_LINK1) + ip_ecn_ingress(ECN_ALLOWED, &ip->ip_tos, &tos); + else + ip_ecn_ingress(ECN_NOCARE, &ip->ip_tos, &tos); + + dst4 = (struct sockaddr_in *)&sc->sc_ro.ro_dst; + if (dst4->sin_family != AF_INET || + bcmp(&dst4->sin_addr, &ip->ip_dst, sizeof(ip->ip_dst)) != 0) { + /* cache route doesn't match */ + dst4->sin_family = AF_INET; + dst4->sin_len = sizeof(struct sockaddr_in); + bcopy(&ip->ip_dst, &dst4->sin_addr, sizeof(dst4->sin_addr)); + if (sc->sc_ro.ro_rt) { + RTFREE(sc->sc_ro.ro_rt); + sc->sc_ro.ro_rt = NULL; + } + } + + if (sc->sc_ro.ro_rt == NULL) { + rtalloc(&sc->sc_ro); + if (sc->sc_ro.ro_rt == NULL) { + return ENETUNREACH; + } + } + + error = ip_output(m, NULL, &sc->sc_ro, 0, NULL); + if (error == 0) + return EJUSTRETURN; +} + +static int +stf_checkaddr4(sc, in, inifp) + struct stf_softc *sc; + struct in_addr *in; + struct ifnet *inifp; /* incoming interface */ +{ + struct in_ifaddr *ia4; + + /* + * reject packets with the following address: + * 224.0.0.0/4 0.0.0.0/8 127.0.0.0/8 255.0.0.0/8 + */ + if (IN_MULTICAST(ntohl(in->s_addr))) + return -1; + switch ((ntohl(in->s_addr) & 0xff000000) >> 24) { + case 0: case 127: case 255: + return -1; + } + + /* + * reject packets with broadcast + */ + for (ia4 = TAILQ_FIRST(&in_ifaddrhead); + ia4; + ia4 = TAILQ_NEXT(ia4, ia_link)) + { + if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0) + continue; + if (in->s_addr == ia4->ia_broadaddr.sin_addr.s_addr) + return -1; + } + + /* + * perform ingress filter + */ + if (sc && (sc->sc_if.if_flags & IFF_LINK2) == 0 && inifp) { + struct sockaddr_in sin; + struct rtentry *rt; + + bzero(&sin, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_len = sizeof(struct sockaddr_in); + sin.sin_addr = *in; + rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL); + if (!rt || rt->rt_ifp != inifp) { +#if 1 + log(LOG_WARNING, "%s: packet from 0x%x dropped " + "due to ingress filter\n", if_name(&sc->sc_if), + (u_int32_t)ntohl(sin.sin_addr.s_addr)); +#endif + if (rt) + rtfree(rt); + return -1; + } + rtfree(rt); + } + + return 0; +} + +static int +stf_checkaddr6(sc, in6, inifp) + struct stf_softc *sc; + struct in6_addr *in6; + struct ifnet *inifp; /* incoming interface */ +{ + /* + * check 6to4 addresses + */ + if (IN6_IS_ADDR_6TO4(in6)) + return stf_checkaddr4(sc, GET_V4(in6), inifp); + + /* + * reject anything that look suspicious. the test is implemented + * in ip6_input too, but we check here as well to + * (1) reject bad packets earlier, and + * (2) to be safe against future ip6_input change. + */ + if (IN6_IS_ADDR_V4COMPAT(in6) || IN6_IS_ADDR_V4MAPPED(in6)) + return -1; + + return 0; +} + +void +in_stf_input(m, off) + struct mbuf *m; + int off; +{ + struct stf_softc *sc; + struct ip *ip; + struct ip6_hdr *ip6; + u_int8_t otos, itos; + int s, isr, proto; + struct ifqueue *ifq = NULL; + struct ifnet *ifp; + + ip = mtod(m, struct ip *); + proto = ip->ip_p; + + + if (proto != IPPROTO_IPV6) { + m_freem(m); + return; + } + + ip = mtod(m, struct ip *); + + sc = (struct stf_softc *)encap_getarg(m); + + if (sc == NULL || (sc->sc_if.if_flags & IFF_UP) == 0) { + m_freem(m); + return; + } + + ifp = &sc->sc_if; + + /* + * perform sanity check against outer src/dst. + * for source, perform ingress filter as well. + */ + if (stf_checkaddr4(sc, &ip->ip_dst, NULL) < 0 || + stf_checkaddr4(sc, &ip->ip_src, m->m_pkthdr.rcvif) < 0) { + m_freem(m); + return; + } + + otos = ip->ip_tos; + m_adj(m, off); + + if (m->m_len < sizeof(*ip6)) { + m = m_pullup(m, sizeof(*ip6)); + if (!m) + return; + } + ip6 = mtod(m, struct ip6_hdr *); + + /* + * perform sanity check against inner src/dst. + * for source, perform ingress filter as well. + */ + if (stf_checkaddr6(sc, &ip6->ip6_dst, NULL) < 0 || + stf_checkaddr6(sc, &ip6->ip6_src, m->m_pkthdr.rcvif) < 0) { + m_freem(m); + return; + } + + itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; + if ((ifp->if_flags & IFF_LINK1) != 0) + ip_ecn_egress(ECN_ALLOWED, &otos, &itos); + else + ip_ecn_egress(ECN_NOCARE, &otos, &itos); + ip6->ip6_flow &= ~htonl(0xff << 20); + ip6->ip6_flow |= htonl((u_int32_t)itos << 20); + + m->m_pkthdr.rcvif = ifp; + + if (ifp->if_bpf) { + /* + * We need to prepend the address family as + * a four byte field. Cons up a dummy header + * to pacify bpf. This is safe because bpf + * will only read from the mbuf (i.e., it won't + * try to free it or keep a pointer a to it). + */ + struct mbuf m0; + u_int32_t af = AF_INET6; + + m0.m_next = m; + m0.m_len = 4; + m0.m_data = (char *)⁡ + +#ifdef HAVE_OLD_BPF + bpf_mtap(ifp, &m0); +#else + bpf_mtap(ifp->if_bpf, &m0); +#endif + } + + /* + * Put the packet to the network layer input queue according to the + * specified address family. + * See net/if_gif.c for possible issues with packet processing + * reorder due to extra queueing. + */ + ifq = &ip6intrq; + isr = NETISR_IPV6; + + s = splimp(); + if (IF_QFULL(ifq)) { + IF_DROP(ifq); /* update statistics */ + m_freem(m); + splx(s); + return; + } + IF_ENQUEUE(ifq, m); + schednetisr(isr); + ifp->if_ipackets++; + ifp->if_ibytes += m->m_pkthdr.len; + splx(s); +} + +/* ARGSUSED */ +static void +stf_rtrequest(cmd, rt, sa) + int cmd; + struct rtentry *rt; + struct sockaddr *sa; +{ + + if (rt) + rt->rt_rmx.rmx_mtu = IPV6_MMTU; +} + +int +stf_ioctl(ifp, cmd, data) + struct ifnet *ifp; + u_long cmd; + void *data; +{ + struct ifaddr *ifa; + struct ifreq *ifr; + struct sockaddr_in6 *sin6; + int error; + + error = 0; + switch (cmd) { + case SIOCSIFADDR: + ifa = (struct ifaddr *)data; + if (ifa == NULL || ifa->ifa_addr->sa_family != AF_INET6) { + error = EAFNOSUPPORT; + break; + } + sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; + if (IN6_IS_ADDR_6TO4(&sin6->sin6_addr)) { + ifa->ifa_rtrequest = stf_rtrequest; + ifp->if_flags |= IFF_UP; + } else + error = EINVAL; + break; + + case SIOCADDMULTI: + case SIOCDELMULTI: + ifr = (struct ifreq *)data; + if (ifr && ifr->ifr_addr.sa_family == AF_INET6) + ; + else + error = EAFNOSUPPORT; + break; + + default: + error = EINVAL; + break; + } + + return error; +} diff --git a/bsd/net/if_stf.h b/bsd/net/if_stf.h new file mode 100644 index 000000000..c374f426d --- /dev/null +++ b/bsd/net/if_stf.h @@ -0,0 +1,41 @@ +/* $FreeBSD: src/sys/net/if_stf.h,v 1.1.2.1 2000/07/15 07:14:29 kris Exp $ */ +/* $KAME: if_stf.h,v 1.3 2000/03/25 07:23:33 sumikawa Exp $ */ + +/* + * Copyright (C) 2000 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _NET_IF_STF_H_ +#define _NET_IF_STF_H_ +#include + +#ifdef __APPLE_API_PRIVATE +void in_stf_input __P((struct mbuf *, int)); +#endif /* __APPLE_API_PRIVATE */ + +#endif /* _NET_IF_STF_H_ */ diff --git a/bsd/net/if_tun.c b/bsd/net/if_tun.c index 81eafd18e..8ed3afd27 100644 --- a/bsd/net/if_tun.c +++ b/bsd/net/if_tun.c @@ -77,11 +77,6 @@ #include #endif /* INET6 */ -#if NS -#include -#include -#endif - #include "bpfilter.h" #if NBPFILTER > 0 #include @@ -304,6 +299,12 @@ tunifioctl(ifp, cmd, data) s = splimp(); switch(cmd) { + case SIOCGIFSTATUS: + ifs = (struct ifstat *)data; + if (tp->tun_pid) + sprintf(ifs->ascii + strlen(ifs->ascii), + "\tOpened by PID %d\n", tp->tun_pid); + break; case SIOCSIFADDR: tuninit(ifp->if_unit); TUNDEBUG("%s%d: address set\n", diff --git a/bsd/net/if_tun.h b/bsd/net/if_tun.h index 8ccbda90e..23731386f 100644 --- a/bsd/net/if_tun.h +++ b/bsd/net/if_tun.h @@ -38,6 +38,8 @@ #ifndef _NET_IF_TUN_H_ #define _NET_IF_TUN_H_ +#include +#ifdef __APPLE_API_PRIVATE /* Refer to if_tunvar.h for the softc stuff */ @@ -60,4 +62,5 @@ struct tuninfo { #define TUNSIFINFO _IOW('t', 91, struct tuninfo) #define TUNGIFINFO _IOR('t', 92, struct tuninfo) +#endif /* __APPLE_API_PRIVATE */ #endif /* !_NET_IF_TUN_H_ */ diff --git a/bsd/net/if_tunvar.h b/bsd/net/if_tunvar.h index ebf00d705..9b93e0867 100644 --- a/bsd/net/if_tunvar.h +++ b/bsd/net/if_tunvar.h @@ -48,6 +48,8 @@ #ifndef _NET_IF_TUNVAR_H_ #define _NET_IF_TUNVAR_H_ +#include +#ifdef __APPLE_API_PRIVATE struct tun_softc { u_short tun_flags; /* misc flags */ @@ -67,4 +69,5 @@ struct tun_softc { struct selinfo tun_wsel; /* write select (not used) */ }; +#endif /* __APPLE_API_PRIVATE */ #endif /* !_NET_IF_TUNVAR_H_ */ diff --git a/bsd/net/if_types.h b/bsd/net/if_types.h index 38d8eaac9..befa53907 100644 --- a/bsd/net/if_types.h +++ b/bsd/net/if_types.h @@ -52,10 +52,12 @@ * SUCH DAMAGE. * * @(#)if_types.h 8.2 (Berkeley) 4/20/94 + * $FreeBSD: src/sys/net/if_types.h,v 1.8.2.3 2001/07/03 11:01:41 ume Exp $ */ #ifndef _NET_IF_TYPES_H_ #define _NET_IF_TYPES_H_ +#include /* * Interface types for benefit of parsing media address headers. @@ -117,10 +119,11 @@ #define IFT_SMDSICIP 0x34 /* SMDS InterCarrier Interface */ #define IFT_PROPVIRTUAL 0x35 /* Proprietary Virtual/internal */ #define IFT_PROPMUX 0x36 /* Proprietary Multiplexing */ -#define IFT_GIF 0x37 -#define IFT_DUMMY 0x38 -#define IFT_PVC 0x39 -#define IFT_FAITH 0x3a -#define IFT_STF 0x3b +#define IFT_GIF 0x37 /*0xf0*/ +#define IFT_FAITH 0x38 /*0xf2*/ +#define IFT_STF 0x39 /*0xf3*/ +#define IFT_L2VLAN 0x87 /* Layer 2 Virtual LAN using 802.1Q */ + +#define IFT_IEEE1394 0x90 /* IEEE1394 High Performance SerialBus*/ #endif diff --git a/bsd/net/if_var.h b/bsd/net/if_var.h index a34df56d6..3209d2b07 100644 --- a/bsd/net/if_var.h +++ b/bsd/net/if_var.h @@ -52,11 +52,14 @@ * SUCH DAMAGE. * * From: @(#)if.h 8.1 (Berkeley) 6/10/93 + * $FreeBSD: src/sys/net/if_var.h,v 1.18.2.7 2001/07/24 19:10:18 brooks Exp $ */ #ifndef _NET_IF_VAR_H_ #define _NET_IF_VAR_H_ +#include +#ifdef __APPLE__ #define APPLE_IF_FAM_LOOPBACK 1 #define APPLE_IF_FAM_ETHERNET 2 #define APPLE_IF_FAM_SLIP 3 @@ -68,7 +71,8 @@ #define APPLE_IF_FAM_MDECAP 9 #define APPLE_IF_FAM_GIF 10 #define APPLE_IF_FAM_FAITH 11 - +#define APPLE_IF_FAM_STF 12 +#endif /* * Structures defining a network interface, providing a packet @@ -103,6 +107,7 @@ struct mbuf; struct proc; struct rtentry; struct socket; +struct ether_header; struct sockaddr_dl; #endif @@ -110,12 +115,12 @@ struct sockaddr_dl; #include /* get TAILQ macros */ -struct tqdummy { -}; +#ifdef __APPLE_API_UNSTABLE +#ifdef __APPLE__ +struct tqdummy; TAILQ_HEAD(tailq_head, tqdummy); - /* This belongs up in socket.h or socketvar.h, depending on how far the * event bubbles up. */ @@ -125,14 +130,15 @@ struct net_event_data { u_long if_unit; char if_name[IFNAMSIZ]; }; - +#endif TAILQ_HEAD(ifnethead, ifnet); /* we use TAILQs so that the order of */ TAILQ_HEAD(ifaddrhead, ifaddr); /* instantiation is preserved in the list */ +TAILQ_HEAD(ifprefixhead, ifprefix); LIST_HEAD(ifmultihead, ifmultiaddr); - +#ifdef __APPLE__ /* * Structure describing information about an interface * which may be of interest to management entities. @@ -140,7 +146,9 @@ LIST_HEAD(ifmultihead, ifmultiaddr); struct if_data { /* generic interface information */ u_char ifi_type; /* ethernet, tokenring, etc */ - u_char ifi_typelen; /* Length of frame type id */ +#ifdef __APPLE__ + u_char ifi_typelen; /* Length of frame type id */ +#endif u_char ifi_physical; /* e.g., AUI, Thinnet, 10base-T, etc */ u_char ifi_addrlen; /* media address length */ u_char ifi_hdrlen; /* media header length */ @@ -161,16 +169,20 @@ struct if_data { u_long ifi_omcasts; /* packets sent via multicast */ u_long ifi_iqdrops; /* dropped on input, this interface */ u_long ifi_noproto; /* destined for unsupported protocol */ +#ifdef __APPLE__ u_long ifi_recvtiming; /* usec spent receiving when timing */ u_long ifi_xmittiming; /* usec spent xmitting when timing */ +#endif struct timeval ifi_lastchange; /* time of last administrative change */ - u_long default_proto; /* Default dl_tag when none is specified - * on dlil_output */ - u_long ifi_hwassist; /* HW offload capabilities */ - u_long ifi_reserved1; /* for future use */ - u_long ifi_reserved2; /* for future use */ +#ifdef __APPLE__ + u_long default_proto; /* Default dl_tag when none is specified + * on dlil_output */ +#endif + u_long ifi_hwassist; /* HW offload capabilities */ + u_long ifi_reserved1; /* for future use */ + u_long ifi_reserved2; /* for future use */ }; - +#endif /* * Structure defining a queue for a network interface. @@ -193,7 +205,9 @@ struct ifnet { char *if_name; /* name, e.g. ``en'' or ``lo'' */ TAILQ_ENTRY(ifnet) if_link; /* all struct ifnets are chained */ struct ifaddrhead if_addrhead; /* linked list of addresses per if */ - struct tailq_head proto_head; /* Head for if_proto structures */ +#ifdef __APPLE__ + struct tailq_head proto_head; /* Head for if_proto structures */ +#endif int if_pcount; /* number of promiscuous listeners */ struct bpf_if *if_bpf; /* packet filter structure */ u_short if_index; /* numeric abbreviation for this if */ @@ -205,6 +219,7 @@ struct ifnet { size_t if_linkmiblen; /* length of above data */ struct if_data if_data; +#ifdef __APPLE__ /* New with DLIL */ int refcnt; int offercnt; @@ -229,22 +244,27 @@ struct ifnet { /* End DLIL specific */ -/* #if defined(ppc) */ - void *if_Y; /* For Y-adapter connection */ -/* #endif */ - void *if_private; /* private to interface */ -/* procedure handles */ -#if __APPLE__ + void *reserved0; /* for future use */ + void *if_private; /* private to interface */ long if_eflags; /* autoaddr, autoaddr done, etc. */ -#else - int (*if_done) /* output complete routine */ - __P((struct ifnet *)); /* (XXX not used; fake prototype) */ -#endif - +#endif /* __APPLE__ */ struct ifmultihead if_multiaddrs; /* multicast addresses configured */ int if_amcount; /* number of all-multicast requests */ /* procedure handles */ +#ifndef __APPLE__ + int (*if_output) /* output routine (enqueue) */ + __P((struct ifnet *, struct mbuf *, struct sockaddr *, + struct rtentry *)); + void (*if_start) /* initiate output routine */ + __P((struct ifnet *)); + int (*if_done) /* output complete routine */ + __P((struct ifnet *)); /* (XXX not used; fake prototype) */ + int (*if_ioctl) /* ioctl routine */ + __P((struct ifnet *, u_long, caddr_t)); + void (*if_watchdog) /* timer routine */ + __P((struct ifnet *)); +#endif int (*if_poll_recv) /* polled receive routine */ __P((struct ifnet *, int *)); int (*if_poll_xmit) /* polled transmit routine */ @@ -259,10 +279,13 @@ struct ifnet { __P((struct ifnet *, struct sockaddr **, struct sockaddr *)); struct ifqueue if_snd; /* output queue */ struct ifqueue *if_poll_slowq; /* input queue for slow devices */ +#ifdef __APPLE__ u_long family_cookie; - struct ifprefix *if_prefixlist; /* linked list of prefixes per if */ + struct ifprefixhead if_prefixhead; /* list of prefixes per if */ void *reserved1; /* for future use */ - void *reserved2; /* for future use */ +#else + struct ifprefixhead if_prefixhead; /* list of prefixes per if */ +#endif /* __APPLE__ */ }; typedef void if_init_f_t __P((void *)); @@ -274,7 +297,7 @@ typedef void if_init_f_t __P((void *)); #define if_hdrlen if_data.ifi_hdrlen #define if_metric if_data.ifi_metric #define if_baudrate if_data.ifi_baudrate -#define if_hwassist if_data.ifi_hwassist +#define if_hwassist if_data.ifi_hwassist #define if_ipackets if_data.ifi_ipackets #define if_ierrors if_data.ifi_ierrors #define if_opackets if_data.ifi_opackets @@ -291,6 +314,12 @@ typedef void if_init_f_t __P((void *)); #define if_xmitquota if_data.ifi_xmitquota #define if_rawoutput(if, m, sa) if_output(if, m, sa, (struct rtentry *)0) +#ifndef __APPLE__ +/* for compatibility with other BSDs */ +#define if_addrlist if_addrhead +#define if_list if_link +#endif + /* * Bit values in if_ipending */ @@ -358,8 +387,18 @@ int if_enq_drop __P((struct ifqueue *, struct mbuf *)); #endif #endif +#endif /* __APPLE_API_UNSTABLE */ + +/* + * 72 was chosen below because it is the size of a TCP/IP + * header (40) + the minimum mss (32). + */ +#define IF_MINMTU 72 +#define IF_MAXMTU 65535 + #endif /* KERNEL */ +#ifdef __APPLE_API_UNSTABLE /* * The ifaddr structure contains information about one address * of an interface. They are maintained by the different address families, @@ -371,12 +410,16 @@ struct ifaddr { struct sockaddr *ifa_dstaddr; /* other end of p-to-p link */ #define ifa_broadaddr ifa_dstaddr /* broadcast address interface */ struct sockaddr *ifa_netmask; /* used to determine subnet */ +#ifndef __APPLE__ + /* Use of if_data doesn't justify change of API */ + struct if_data if_data; /* not all members are meaningful */ +#endif struct ifnet *ifa_ifp; /* back-pointer to interface */ TAILQ_ENTRY(ifaddr) ifa_link; /* queue macro glue */ void (*ifa_rtrequest) /* check or clean routes (+ or -)'d */ __P((int, struct rtentry *, struct sockaddr *)); u_short ifa_flags; /* mostly rt_flags for cloning */ - short ifa_refcnt; /* references to this structure */ + short ifa_refcnt;/* 16bit ref count, use ifaref, ifafree */ int ifa_metric; /* cost of going out this interface */ #ifdef notdef struct rtentry *ifa_rt; /* XXXX for ROUTETOIF ????? */ @@ -384,7 +427,6 @@ struct ifaddr { u_long ifa_dlt; int (*ifa_claim_addr) /* check if an addr goes to this if */ __P((struct ifaddr *, struct sockaddr *)); - }; #define IFA_ROUTE RTF_UP /* route installed */ @@ -397,7 +439,7 @@ struct ifaddr { struct ifprefix { struct sockaddr *ifpr_prefix; /* prefix of interface */ struct ifnet *ifpr_ifp; /* back-pointer to interface */ - struct ifprefix *ifpr_next; + TAILQ_ENTRY(ifprefix) ifpr_list; /* queue macro glue */ u_char ifpr_plen; /* prefix length in bits */ u_char ifpr_type; /* protocol dependent prefix type */ }; @@ -417,23 +459,31 @@ struct ifmultiaddr { void *ifma_protospec; /* protocol-specific state, if any */ }; -#if KERNEL -#define IFAFREE(ifa) \ - do { \ - if ((ifa)->ifa_refcnt <= 0) \ - ifafree(ifa); \ - else \ - (ifa)->ifa_refcnt--; \ - } while (0) +#ifdef KERNEL +#define IFAREF(ifa) ifaref(ifa) +#define IFAFREE(ifa) ifafree(ifa) +#ifdef __APPLE_API_PRIVATE extern struct ifnethead ifnet; extern struct ifnet **ifindex2ifnet; extern int ifqmaxlen; extern struct ifnet loif[]; extern int if_index; extern struct ifaddr **ifnet_addrs; +#endif /* __APPLE_API_PRIVATE */ + +#ifndef __APPLE__ +void ether_ifattach __P((struct ifnet *, int)); +void ether_ifdetach __P((struct ifnet *, int)); +void ether_input __P((struct ifnet *, struct ether_header *, struct mbuf *)); +void ether_demux __P((struct ifnet *, struct ether_header *, struct mbuf *)); +int ether_output __P((struct ifnet *, + struct mbuf *, struct sockaddr *, struct rtentry *)); +int ether_output_frame __P((struct ifnet *, struct mbuf *)); +int ether_ioctl __P((struct ifnet *, int, caddr_t)); +#endif -int if_addmulti __P((struct ifnet *, struct sockaddr *, +int if_addmulti __P((struct ifnet *, struct sockaddr *, struct ifmultiaddr **)); int if_allmulti __P((struct ifnet *, int)); void if_attach __P((struct ifnet *)); @@ -445,7 +495,7 @@ void if_up __P((struct ifnet *)); /*void ifinit __P((void));*/ /* declared in systm.h for main() */ int ifioctl __P((struct socket *, u_long, caddr_t, struct proc *)); int ifpromisc __P((struct ifnet *, int)); -struct ifnet *ifunit __P((char *)); +struct ifnet *ifunit __P((const char *)); struct ifnet *if_withname __P((struct sockaddr *)); int if_poll_recv_slow __P((struct ifnet *ifp, int *quotap)); @@ -462,13 +512,17 @@ struct ifaddr *ifa_ifwithroute __P((int, struct sockaddr *, struct sockaddr *)); struct ifaddr *ifaof_ifpforaddr __P((struct sockaddr *, struct ifnet *)); void ifafree __P((struct ifaddr *)); +void ifaref __P((struct ifaddr *)); struct ifmultiaddr *ifmaof_ifpforaddr __P((struct sockaddr *, struct ifnet *)); +#ifndef __APPLE__ int if_simloop __P((struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, int hlen)); +#endif #endif /* KERNEL */ +#endif /* __APPLE_API_UNSTABLE */ #endif /* !_NET_IF_VAR_H_ */ diff --git a/bsd/net/if_vlan_var.h b/bsd/net/if_vlan_var.h index 51656d442..6fe422d45 100644 --- a/bsd/net/if_vlan_var.h +++ b/bsd/net/if_vlan_var.h @@ -51,7 +51,9 @@ #ifndef _NET_IF_VLAN_VAR_H_ #define _NET_IF_VLAN_VAR_H_ 1 +#include +#ifdef __APPLE_API_PRIVATE #ifdef KERNEL struct ifvlan { struct arpcom ifv_ac; /* make this an interface */ @@ -101,4 +103,5 @@ extern u_int vlan_proto; extern int vlan_input(struct ether_header *eh, struct mbuf *m); #endif +#endif /* __APPLE_API_PRIVATE */ #endif /* _NET_IF_VLAN_VAR_H_ */ diff --git a/bsd/net/iso88025.h b/bsd/net/iso88025.h new file mode 100644 index 000000000..e1d1a68dc --- /dev/null +++ b/bsd/net/iso88025.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 1998, Larry Lile + * All rights reserved. + * + * For latest sources and information on this driver, please + * go to http://anarchy.stdio.com. + * + * Questions, comments or suggestions should be directed to + * Larry Lile . + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/net/iso88025.h,v 1.3.2.1 2000/10/14 20:01:06 lile Exp $ + * + * Information gathered from tokenring@freebsd, /sys/net/ethernet.h and + * the Mach token ring driver. + */ + +/* + * Fundamental constants relating to iso 802.5 + */ + +#ifndef _NET_ISO88025_H_ +#define _NET_ISO88025_H_ +#include +#ifdef __APPLE_API_PRIVATE + +/* + * General ISO 802.5 definitions + */ +#define ISO88025_ADDR_LEN 6 +#define ISO88025_HDR_LEN (ISO88025_CF_LEN + (ISO88025_ADDR_LEN * 2)) +#define ISO88025_CF_LEN 2 +#define RCF_LEN 2 +#define RIF_MAX_RD 14 +#define RIF_MAX_LEN 16 + +#define TR_AC 0x10 +#define TR_LLC_FRAME 0x40 + +#define TR_4MBPS 4000000 +#define TR_16MBPS 16000000 +#define TR_100MBPS 100000000 + +/* + * Source routing + */ +#define TR_RII 0x80 +#define TR_RCF_BCST_MASK 0xe000 +#define TR_RCF_LEN_MASK 0x1f00 +#define TR_RCF_DIR 0x0080 +#define TR_RCF_LF_MASK 0x0070 + +#define TR_RCF_RIFLEN(x) ((ntohs(x) & TR_RCF_LEN_MASK) >> 8) + +/* + * Minimum and maximum packet payload lengths. + */ +#define ISO88025_MIN_LEN 0 +#define ISO88025_MAX_LEN 17960 + +/* + * A macro to validate a length with + */ +#define ISO88025_IS_VALID_LEN(foo) \ + ((foo) >= ISO88025_MIN_LEN && (foo) <= ISO88025_MAX_LEN) + +/* + * ISO 802.5 physical header + */ +struct iso88025_header { + u_char ac; /* access control field */ + u_char fc; /* frame control field */ + u_char iso88025_dhost[ISO88025_ADDR_LEN]; /* destination address */ + u_char iso88025_shost[ISO88025_ADDR_LEN]; /* source address */ + u_short rcf; /* route control field */ + u_short rd[RIF_MAX_RD]; /* routing designators */ +}; + +struct iso88025_sockaddr_data { + u_char ether_dhost[ISO88025_ADDR_LEN]; + u_char ether_shost[ISO88025_ADDR_LEN]; + u_char ac; + u_char fc; +}; + +/* + * Structure of a 48-bit iso 802.5 address. + * ( We could also add the 16 bit addresses as a union) + */ +struct iso88025_addr { + u_char octet[ISO88025_ADDR_LEN]; +}; + +#define ISO88025_MAX_MTU 18000 +#define ISO88025_DEFAULT_MTU 1500 +#define senderr(e) { error = (e); goto bad;} + +#ifndef __APPLE__ +/* Not implemented in Darwin */ +void iso88025_ifattach __P((struct ifnet *)); +int iso88025_ioctl __P((struct ifnet *, int , caddr_t )); +int iso88025_output __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *)); +void iso88025_input __P((struct ifnet *, struct iso88025_header *, struct mbuf *)); +#endif + +#endif /* __APPLE_API_PRIVATE */ +#endif diff --git a/bsd/net/kext_net.c b/bsd/net/kext_net.c index d96e427d0..fe79fa1c5 100644 --- a/bsd/net/kext_net.c +++ b/bsd/net/kext_net.c @@ -41,6 +41,8 @@ /* List of kernel extensions (networking) known to kernel */ struct nf_list nf_list; +static int sockfilter_fix_symantec_bug(struct NFDescriptor* theirDesc); + /* * Register a global filter for the specified protocol * Make a few checks and then insert the new descriptor in the @@ -55,6 +57,13 @@ register_sockfilter(struct NFDescriptor *nfp, struct NFDescriptor *nfp1, if (nfp == NULL) return(EINVAL); + /* Fix Symantec's broken NPC kext */ + if (nfp->nf_handle == 0xf1ab02de) { + int err = sockfilter_fix_symantec_bug(nfp); + if (err != 0) + return err; + } + s = splhigh(); if (!NF_initted) { NF_initted = 1; @@ -191,3 +200,143 @@ nke_insert(struct socket *so, struct so_nke *np) (*kp->e_soif->sf_socreate)(so, so->so_proto, kp); return(0); } + +/* + * The following gunk is a fix for Symantec's broken NPC kext + * Symantec's NPC kext does not check that the kextcb->e_fcb + * is not NULL before derefing it. The result is a panic in + * the very few cases where the e_fcb is actually NULL. + * + * This gross chunk of code copies the old function ptrs + * supplied by the kext and wraps a few select ones in + * our own functions that just check for NULL before + * calling in to the kext. + */ + +static struct sockif* g_symantec_if_funcs = NULL; +static struct sockutil* g_symantec_util_funcs = NULL; +static int sym_fix_sbflush(struct sockbuf *, struct kextcb *); +static int sym_fix_sbappend(struct sockbuf *, struct mbuf *, struct kextcb *); +static int sym_fix_soclose(struct socket *, struct kextcb *); +static int sym_fix_sofree(struct socket *, struct kextcb *); +static int sym_fix_soconnect(struct socket *, struct sockaddr *, struct kextcb *); +static int sym_fix_soisconnected(struct socket *, struct kextcb *); +static int sym_fix_sosend(struct socket *, struct sockaddr **, struct uio **, struct mbuf **, + struct mbuf **, int *, struct kextcb *); +static int sym_fix_socantrcvmore(struct socket *, struct kextcb *); +static int sym_fix_socontrol(struct socket *, struct sockopt *, struct kextcb *); + +static int sockfilter_fix_symantec_bug(struct NFDescriptor* theirDesc) +{ + if (!g_symantec_if_funcs ) { + MALLOC(g_symantec_if_funcs, struct sockif*, sizeof(*g_symantec_if_funcs), M_TEMP, M_WAITOK); + + if (!g_symantec_if_funcs) + return ENOMEM; + + *g_symantec_if_funcs = *theirDesc->nf_soif; + } + + if (!g_symantec_util_funcs) { + MALLOC(g_symantec_util_funcs, struct sockutil*, sizeof(*g_symantec_util_funcs), M_TEMP, M_WAITOK); + + if (!g_symantec_util_funcs) + return ENOMEM; + + *g_symantec_util_funcs = *theirDesc->nf_soutil; + } + + if (theirDesc->nf_soutil->su_sbflush) + theirDesc->nf_soutil->su_sbflush = sym_fix_sbflush; + if (theirDesc->nf_soutil->su_sbappend) + theirDesc->nf_soutil->su_sbappend = sym_fix_sbappend; + if (theirDesc->nf_soif->sf_soclose) + theirDesc->nf_soif->sf_soclose = sym_fix_soclose; + if (theirDesc->nf_soif->sf_sofree) + theirDesc->nf_soif->sf_sofree = sym_fix_sofree; + if (theirDesc->nf_soif->sf_soconnect) + theirDesc->nf_soif->sf_soconnect = sym_fix_soconnect; + if (theirDesc->nf_soif->sf_soisconnected) + theirDesc->nf_soif->sf_soisconnected = sym_fix_soisconnected; + if (theirDesc->nf_soif->sf_sosend) + theirDesc->nf_soif->sf_sosend = sym_fix_sosend; + if (theirDesc->nf_soif->sf_socantrcvmore) + theirDesc->nf_soif->sf_socantrcvmore = sym_fix_socantrcvmore; + if (theirDesc->nf_soif->sf_socontrol) + theirDesc->nf_soif->sf_socontrol = sym_fix_socontrol; + + return 0; +} + +static int sym_fix_sbflush(struct sockbuf *p1, struct kextcb *p2) +{ + if (p2->e_fcb != NULL && g_symantec_util_funcs) + return g_symantec_util_funcs->su_sbflush(p1, p2); + else + return 0; +} + +static int sym_fix_sbappend(struct sockbuf *p1, struct mbuf *p2, struct kextcb *p3) +{ + if (p3->e_fcb != NULL && g_symantec_util_funcs) + return g_symantec_util_funcs->su_sbappend(p1, p2, p3); + else + return 0; +} + +static int sym_fix_soclose(struct socket *p1, struct kextcb *p2) +{ + if (p2->e_fcb != NULL && g_symantec_if_funcs) + return g_symantec_if_funcs->sf_soclose(p1, p2); + else + return 0; +} + +static int sym_fix_sofree(struct socket *p1, struct kextcb *p2) +{ + if (p2->e_fcb != NULL && g_symantec_if_funcs) + return g_symantec_if_funcs->sf_sofree(p1, p2); + else + return 0; +} + +static int sym_fix_soconnect(struct socket *p1, struct sockaddr *p2, struct kextcb *p3) +{ + if (p3->e_fcb != NULL && g_symantec_if_funcs) + return g_symantec_if_funcs->sf_soconnect(p1, p2, p3); + else + return 0; +} + +static int sym_fix_soisconnected(struct socket *p1, struct kextcb *p2) +{ + if (p2->e_fcb != NULL && g_symantec_if_funcs) + return g_symantec_if_funcs->sf_soisconnected(p1, p2); + else + return 0; +} + +static int sym_fix_sosend(struct socket *p1, struct sockaddr **p2, struct uio **p3, struct mbuf **p4, + struct mbuf **p5, int *p6, struct kextcb *p7) +{ + if (p7->e_fcb != NULL && g_symantec_if_funcs) + return g_symantec_if_funcs->sf_sosend(p1, p2, p3, p4, p5, p6, p7); + else + return 0; +} + +static int sym_fix_socantrcvmore(struct socket *p1, struct kextcb *p2) +{ + if (p2->e_fcb != NULL && g_symantec_if_funcs) + return g_symantec_if_funcs->sf_socantrcvmore(p1, p2); + else + return 0; +} + +static int sym_fix_socontrol(struct socket *p1, struct sockopt *p2, struct kextcb *p3) +{ + if (p3->e_fcb != NULL && g_symantec_if_funcs) + return g_symantec_if_funcs->sf_socontrol(p1, p2, p3); + else + return 0; +} diff --git a/bsd/net/kext_net.h b/bsd/net/kext_net.h index d11f61b86..ebe88e6c3 100644 --- a/bsd/net/kext_net.h +++ b/bsd/net/kext_net.h @@ -26,6 +26,7 @@ */ #ifndef NET_KEXT_NET_H #define NET_KEXT_NET_H +#include #include #include @@ -41,6 +42,8 @@ struct sockif; struct sockutil; struct sockopt; +#ifdef __APPLE_API_UNSTABLE + /* * This structure gives access to the functionality of the filter. * The kextcb provides the link from the socket structure. @@ -81,9 +84,11 @@ extern int register_sockfilter(struct NFDescriptor *, /* How to unregister: filter, original protosw, flags */ extern int unregister_sockfilter(struct NFDescriptor *, struct protosw *, int); +#ifdef __APPLE_API_PRIVATE TAILQ_HEAD(nf_list, NFDescriptor); extern struct nf_list nf_list; +#endif /* __APPLE_API_PRIVATE */ #endif #define NKE_OK 0 @@ -152,7 +157,7 @@ struct sockif /* Calls sowwakeup(), sorwakeup() */ int (*sf_soisdisconnecting)(struct socket *, struct kextcb *); /* Calls soreserve(), soqinsque(), soqremque(), sorwakeup() */ - struct socket *(*sf_sonewconn1)(struct socket *, int, struct kextcb *); + int (*sf_sonewconn)(struct socket *, int, struct kextcb *); int (*sf_soqinsque)(struct socket *, struct socket *, int, struct kextcb *); int (*sf_soqremque)(struct socket *, int, struct kextcb *); @@ -200,5 +205,6 @@ struct sockutil int (*su_sbwait)(struct sockbuf *, struct kextcb *); u_long reserved[4]; }; +#endif /* __APPLE_API_UNSTABLE */ #endif diff --git a/bsd/net/ndrv.c b/bsd/net/ndrv.c index 175b2f0e4..8c65a8faa 100644 --- a/bsd/net/ndrv.c +++ b/bsd/net/ndrv.c @@ -73,23 +73,6 @@ #endif #include -#if NS -#include -#include -#endif - -#if ISO -#include -#include -#include -#include -#endif - -#if LLC -#include -#include -#endif - #include int ndrv_do_detach(struct ndrv_cb *); @@ -100,6 +83,10 @@ int ndrv_setspec(struct ndrv_cb *np, struct sockopt *sopt); int ndrv_delspec(struct ndrv_cb *); int ndrv_to_dlil_demux(struct ndrv_demux_desc* ndrv, struct dlil_demux_desc* dlil); void ndrv_handle_ifp_detach(u_long family, short unit); +static int ndrv_do_add_multicast(struct ndrv_cb *np, struct sockopt *sopt); +static int ndrv_do_remove_multicast(struct ndrv_cb *np, struct sockopt *sopt); +static struct ndrv_multiaddr* ndrv_have_multicast(struct ndrv_cb *np, struct sockaddr* addr); +static void ndrv_remove_all_multicast(struct ndrv_cb *np); unsigned long ndrv_sendspace = NDRVSNDQ; unsigned long ndrv_recvspace = NDRVRCVQ; @@ -380,8 +367,7 @@ ndrv_bind(struct socket *so, struct sockaddr *nam, struct proc *p) if ((dlil_find_dltag(ifp->if_family, ifp->if_unit, PF_NDRV, &np->nd_send_tag) != 0) && - (ifp->if_family != APPLE_IF_FAM_PPP)) - { + (ifp->if_family != APPLE_IF_FAM_PPP)) { /* NDRV isn't registered on this interface, lets change that */ struct dlil_proto_reg_str ndrv_proto; int result = 0; @@ -576,6 +562,12 @@ ndrv_ctloutput(struct socket *so, struct sockopt *sopt) case NDRV_SETDMXSPEC: /* Set protocol spec */ error = ndrv_setspec(np, sopt); break; + case NDRV_ADDMULTICAST: + error = ndrv_do_add_multicast(np, sopt); + break; + case NDRV_DELMULTICAST: + error = ndrv_do_remove_multicast(np, sopt); + break; default: error = ENOTSUP; } @@ -610,6 +602,8 @@ ndrv_do_detach(register struct ndrv_cb *np) #if NDRV_DEBUG kprintf("NDRV detach: %x, %x\n", so, np); #endif + ndrv_remove_all_multicast(np); + if (np->nd_tag != 0) { error = dlil_detach_protocol(np->nd_tag); @@ -934,6 +928,9 @@ ndrv_handle_ifp_detach(u_long family, short unit) if (np->nd_tag != 0) ndrv_delspec(np); + /* Delete the multicasts first */ + ndrv_remove_all_multicast(np); + /* Disavow all knowledge of the ifp */ np->nd_if = NULL; np->nd_unit = 0; @@ -953,6 +950,161 @@ ndrv_handle_ifp_detach(u_long family, short unit) } } +static int +ndrv_do_add_multicast(struct ndrv_cb *np, struct sockopt *sopt) +{ + struct ndrv_multiaddr* ndrv_multi; + int result; + + if (sopt->sopt_val == NULL || sopt->sopt_valsize < 2 || + sopt->sopt_level != SOL_NDRVPROTO) + return EINVAL; + if (np->nd_if == NULL) + return ENXIO; + + // Allocate storage + MALLOC(ndrv_multi, struct ndrv_multiaddr*, sizeof(struct ndrv_multiaddr) - + sizeof(struct sockaddr) + sopt->sopt_valsize, M_IFADDR, M_WAITOK); + if (ndrv_multi == NULL) + return ENOMEM; + + // Copy in the address + result = copyin(sopt->sopt_val, &ndrv_multi->addr, sopt->sopt_valsize); + + // Validate the sockaddr + if (result == 0 && sopt->sopt_valsize != ndrv_multi->addr.sa_len) + result = EINVAL; + + if (result == 0 && ndrv_have_multicast(np, &ndrv_multi->addr)) + result = EEXIST; + + if (result == 0) + { + // Try adding the multicast + result = if_addmulti(np->nd_if, &ndrv_multi->addr, NULL); + } + + if (result == 0) + { + // Add to our linked list + ndrv_multi->next = np->nd_multiaddrs; + np->nd_multiaddrs = ndrv_multi; + } + else + { + // Free up the memory, something went wrong + FREE(ndrv_multi, M_IFADDR); + } + + return result; +} + +static int +ndrv_do_remove_multicast(struct ndrv_cb *np, struct sockopt *sopt) +{ + struct sockaddr* multi_addr; + struct ndrv_multiaddr* ndrv_entry = NULL; + int result; + + if (sopt->sopt_val == NULL || sopt->sopt_valsize < 2 || + sopt->sopt_level != SOL_NDRVPROTO) + return EINVAL; + if (np->nd_if == NULL) + return ENXIO; + + // Allocate storage + MALLOC(multi_addr, struct sockaddr*, sopt->sopt_valsize, + M_TEMP, M_WAITOK); + if (multi_addr == NULL) + return ENOMEM; + + // Copy in the address + result = copyin(sopt->sopt_val, multi_addr, sopt->sopt_valsize); + + // Validate the sockaddr + if (result == 0 && sopt->sopt_valsize != multi_addr->sa_len) + result = EINVAL; + + if (result == 0) + { + /* Find the old entry */ + ndrv_entry = ndrv_have_multicast(np, multi_addr); + + if (ndrv_entry == NULL) + result = ENOENT; + } + + if (result == 0) + { + // Try deleting the multicast + result = if_delmulti(np->nd_if, &ndrv_entry->addr); + } + + if (result == 0) + { + // Remove from our linked list + struct ndrv_multiaddr* cur = np->nd_multiaddrs; + + if (cur == ndrv_entry) + { + np->nd_multiaddrs = cur->next; + } + else + { + for (cur = cur->next; cur != NULL; cur = cur->next) + { + if (cur->next == ndrv_entry) + { + cur->next = cur->next->next; + break; + } + } + } + + // Free the memory + FREE(ndrv_entry, M_IFADDR); + } + FREE(multi_addr, M_TEMP); + + return result; +} + +static struct ndrv_multiaddr* +ndrv_have_multicast(struct ndrv_cb *np, struct sockaddr* inAddr) +{ + struct ndrv_multiaddr* cur; + for (cur = np->nd_multiaddrs; cur != NULL; cur = cur->next) + { + + if ((inAddr->sa_len == cur->addr.sa_len) && + (bcmp(&cur->addr, inAddr, inAddr->sa_len) == 0)) + { + // Found a match + return cur; + } + } + + return NULL; +} + +static void +ndrv_remove_all_multicast(struct ndrv_cb* np) +{ + struct ndrv_multiaddr* cur; + + if (np->nd_if != NULL) + { + while (np->nd_multiaddrs != NULL) + { + cur = np->nd_multiaddrs; + np->nd_multiaddrs = cur->next; + + if_delmulti(np->nd_if, &cur->addr); + FREE(cur, M_IFADDR); + } + } +} + struct pr_usrreqs ndrv_usrreqs = { ndrv_abort, pru_accept_notsupp, ndrv_attach, ndrv_bind, ndrv_connect, pru_connect2_notsupp, ndrv_control, ndrv_detach, diff --git a/bsd/net/ndrv.h b/bsd/net/ndrv.h index 7140ed56c..0824dafca 100644 --- a/bsd/net/ndrv.h +++ b/bsd/net/ndrv.h @@ -28,6 +28,7 @@ #ifndef _NET_NDRV_H #define _NET_NDRV_H +#include struct sockaddr_ndrv @@ -118,10 +119,37 @@ struct ndrv_protocol_desc #define NDRV_DELDMXSPEC 0x02 /* Delete the registered protocol */ /* NDRV_DMXSPECCNT 0x03 Obsolete */ #define NDRV_SETDMXSPEC 0x04 /* Set the protocol spec */ +#define NDRV_ADDMULTICAST 0x05 /* Add a physical multicast address */ +#define NDRV_DELMULTICAST 0x06 /* Delete a phyiscal multicast */ -#if KERNEL +/* + * SOL_NDRVPROTO - use this for the socket level when calling setsocketopt + * NDRV_DELDMXSPEC - removes the registered protocol and all related demuxes + * NDRV_SETDMXSPEC - set the protocol to receive, use struct ndrv_protocol_desc + * as the parameter. + * NDRV_ADDMULTICAST - Enable reception of a phyiscal multicast address, use + * a sockaddr of the appropriate type for the media in use. + * NDRV_DELMULTICAST - Disable reception of a phyiscal multicast address, use + * a sockaddr of the appropriate type for the media in use. + * + * When adding multicasts, the multicasts are ref counted. If the multicast is + * already registered in the kernel, the count will be bumped. When deleting + * the multicast, the count is decremented. If the count reaches zero the + * multicast is removed. If your process is killed, PF_NDRV will unregister + * the mulitcasts you've added. You can only delete multicasts you've added + * on the same socket. + * + * If the interface goes away while your socket is open, your protocol is + * immediately detached and sending/receiving is disabled on the socket. + * If you need a chance to do something, please file a bug and we can give + * you a second or two. + */ + +#ifdef KERNEL +#ifdef __APPLE_API_UNSTABLE /* Additional Kernel APIs */ struct ifnet* ndrv_get_ifp(caddr_t ndrv_pcb); +#endif /* __APPLE_API_UNSTABLE */ #endif #endif /* _NET_NDRV_H */ diff --git a/bsd/net/ndrv_var.h b/bsd/net/ndrv_var.h index 36aa93336..74f8aaf2b 100644 --- a/bsd/net/ndrv_var.h +++ b/bsd/net/ndrv_var.h @@ -27,6 +27,20 @@ #ifndef _NET_NDRV_VAR_H #define _NET_NDRV_VAR_H +#include +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE + +/* + * structure for storing a linked list of multicast addresses + * registered by this socket. May be variable in length. + */ + +struct ndrv_multiaddr +{ + struct ndrv_multiaddr* next; + struct sockaddr addr; +}; /* * The cb is plugged into the socket (so_pcb), and the ifnet structure @@ -38,16 +52,17 @@ struct ndrv_cb struct ndrv_cb *nd_next; /* Doubly-linked list */ struct ndrv_cb *nd_prev; struct socket *nd_socket; /* Back to the socket */ - unsigned int nd_signature; /* Just double-checking */ + u_int32_t nd_signature; /* Just double-checking */ struct sockaddr_ndrv *nd_faddr; struct sockaddr_ndrv *nd_laddr; struct sockproto nd_proto; /* proto family, protocol */ int nd_descrcnt; /* # elements in nd_dlist - Obsolete */ TAILQ_HEAD(dlist, dlil_demux_desc) nd_dlist; /* Descr. list */ - struct ifnet *nd_if; + struct ifnet *nd_if; /* obsolete, maintained for binary compatibility */ u_long nd_send_tag; u_long nd_tag; u_long nd_family; + struct ndrv_multiaddr* nd_multiaddrs; short nd_unit; }; @@ -58,7 +73,7 @@ struct ndrv_cb #define NDRVSNDQ 8192 #define NDRVRCVQ 8192 -#if KERNEL extern struct ndrv_cb ndrvl; /* Head of controlblock list */ -#endif +#endif /* __APPLE_API_PRIVATE */ +#endif /* KERNEL */ #endif /* _NET_NDRV_VAR_H */ diff --git a/bsd/net/net_osdep.c b/bsd/net/net_osdep.c index 6807504ea..8d2f62168 100644 --- a/bsd/net/net_osdep.c +++ b/bsd/net/net_osdep.c @@ -22,7 +22,7 @@ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -34,7 +34,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -55,9 +55,6 @@ #include #include #include -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 -#include -#endif #include #include #include @@ -68,39 +65,21 @@ #include #include -#if 0 -#ifdef INET -#include -#include -#include -#include -#include -#endif /* INET */ - -#if INET6 -#ifndef INET -#include -#endif -#include -#include -#include -#include -#include -#endif /* INET6 */ -#endif +#include -#if !(defined(__NetBSD__) || defined(__OpenBSD__)) || defined(__APPLE__) const char * if_name(ifp) struct ifnet *ifp; { - static char nam[IFNAMSIZ + 10]; /*enough?*/ +#define MAXNUMBUF 8 + static char nam[MAXNUMBUF][IFNAMSIZ + 10]; /*enough?*/ + static int ifbufround = 0; + char *cp; + + ifbufround = (ifbufround + 1) % MAXNUMBUF; + cp = nam[ifbufround]; -#ifdef __bsdi__ - sprintf(nam, "%s%d", ifp->if_name, ifp->if_unit); -#else - snprintf(nam, sizeof(nam), "%s%d", ifp->if_name, ifp->if_unit); -#endif - return nam; + snprintf(cp, IFNAMSIZ + 10, "%s%d", ifp->if_name, ifp->if_unit); + return((const char *)cp); +#undef MAXNUMBUF } -#endif diff --git a/bsd/net/net_osdep.h b/bsd/net/net_osdep.h index eeb7c2f02..e350606ac 100644 --- a/bsd/net/net_osdep.h +++ b/bsd/net/net_osdep.h @@ -22,7 +22,7 @@ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -34,7 +34,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -54,11 +54,49 @@ /* * OS dependencies: * + * - whether the IPv4 input routine convert the byte order of some fileds + * of the IP header (x: convert to the host byte order, s: strip the header + * length for possible reassembly) + * ip_len ip_id ip_off + * bsdi3: xs x x + * bsdi4: xs x + * FreeBSD: xs x + * NetBSD: x x + * OpenBSD: xs x x + * + * - ifa_ifwithaf() + * bsdi[34], netbsd, and openbsd define it in sys/net/if.c + * freebsd (all versions) does not have it. + * + * - struct rt_addrinfo + * bsdi4, netbsd 1.5R and beyond: rti_addrs, rti_info[], rti_flags, rti_ifa, + * rti_ifp, and rti_rtm. + * others: rti_addrs and rti_info[] only. + * + * - ifa->ifa_rtrequest + * bsdi4, netbsd 1.5R and beyond: rt_addrinfo * + * others: sockaddr * (note that sys/net/route.c:rtrequest() has an unsafe + * typecast code, from 4.3BSD-reno) + * + * - side effects of rtrequest{,1}(RTM_DELETE) + * BSDI[34]: delete all cloned routes underneath the route. + * FreeBSD[234]: delete all protocol-cloned routes underneath the route. + * note that cloned routes from an interface direct route + * still remain. + * NetBSD: 1.5 have no side effects. KAME/netbsd15, and post-1.5R, have + * the same effects as of BSDI. + * OpenBSD: have no side effects. KAME/openbsd has the same effects as + * of BSDI (the change is not merged - yet). + * * - privileged process * NetBSD, FreeBSD 3 * struct proc *p; * if (p && !suser(p->p_ucred, &p->p_acflag)) * privileged; + * FreeBSD 4 + * struct proc *p; + * if (p && !suser(p)) + * privileged; * OpenBSD, BSDI [34], FreeBSD 2 * struct socket *so; * if (so->so_state & SS_PRIV) @@ -68,11 +106,13 @@ * needs to give struct proc * as argument * OpenBSD, BSDI [34], FreeBSD 2 * do not need struct proc * + * * - bpf: - * OpenBSD, NetBSD, BSDI [34] + * OpenBSD, NetBSD 1.5, BSDI [34] * need caddr_t * (= if_bpf **) and struct ifnet * - * FreeBSD 2, FreeBSD 3 + * FreeBSD 2, FreeBSD 3, NetBSD post-1.5N * need only struct ifnet * as argument + * * - struct ifnet * use queue.h? member names if name * --- --- --- @@ -81,34 +121,57 @@ * OpenBSD yes standard if_xname * NetBSD yes standard if_xname * BSDI [34] no old standard if_name+unit + * * - usrreq * NetBSD, OpenBSD, BSDI [34], FreeBSD 2 - * single function with PRU_xx, arguments are mbuf + * single function with PRU_xx, arguments are mbuf * FreeBSD 3 * separates functions, non-mbuf arguments + * * - {set,get}sockopt * NetBSD, OpenBSD, BSDI [34], FreeBSD 2 * manipulation based on mbuf * FreeBSD 3 * non-mbuf manipulation using sooptcopy{in,out}() + * * - timeout() and untimeout() - * NetBSD, OpenBSD, BSDI [34], FreeBSD 2 + * NetBSD 1.4.x, OpenBSD, BSDI [34], FreeBSD 2 * timeout() is a void function * FreeBSD 3 - * timeout() is non-void, must keep returned value for untimeuot() + * timeout() is non-void, must keep returned value for untimeout() + * callout_xx is also available (sys/callout.h) + * NetBSD 1.5 + * timeout() is obsoleted, use callout_xx (sys/callout.h) + * OpenBSD 2.8 + * timeout_{add,set,del} is encouraged (sys/timeout.h) + * * - sysctl * NetBSD, OpenBSD * foo_sysctl() * BSDI [34] - * foo_sysctl() but with different style - * FreeBSD 2, FreeBSD 3 - * linker hack + * foo_sysctl() but with different style. sysctl_int_arr() takes + * care of most of the cases. + * FreeBSD + * linker hack. however, there are freebsd version differences + * (how wonderful!). + * on FreeBSD[23] function arg #define includes paren. + * int foo SYSCTL_HANDLER_ARGS; + * on FreeBSD4, function arg #define does not include paren. + * int foo(SYSCTL_HANDLER_ARGS); + * on some versions, forward reference to the tree is okay. + * on some versions, you need SYSCTL_DECL(). you need things + * like this. + * #ifdef SYSCTL_DECL + * SYSCTL_DECL(net_inet_ip6); + * #endif + * it is hard to share functions between freebsd and non-freebsd. * * - if_ioctl * NetBSD, FreeBSD 3, BSDI [34] * 2nd argument is u_long cmd * FreeBSD 2 * 2nd argument is int cmd + * * - if attach routines * NetBSD * void xxattach(int); @@ -119,6 +182,7 @@ * - ovbcopy() * in NetBSD 1.4 or later, ovbcopy() is not supplied in the kernel. * bcopy() is safe against overwrites. + * * - splnet() * NetBSD 1.4 or later requires splsoftnet(). * other operating systems use splnet(). @@ -129,40 +193,83 @@ * - struct ifnet for loopback interface * BSDI3: struct ifnet loif; * BSDI4: struct ifnet *loifp; - * NetBSD, OpenBSD, FreeBSD2: struct ifnet loif[NLOOP]; + * NetBSD, OpenBSD 2.8, FreeBSD2: struct ifnet loif[NLOOP]; + * OpenBSD 2.9: struct ifnet *lo0ifp; * * odd thing is that many of them refers loif as ifnet *loif, * not loif[NLOOP], from outside of if_loop.c. + * + * - number of bpf pseudo devices + * others: bpfilter.h, NBPFILTER + * FreeBSD4: bpf.h, NBPF + * solution: + * #if defined(__FreeBSD__) && __FreeBSD__ >= 4 + * #include "bpf.h" + * #define NBPFILTER NBPF + * #else + * #include "bpfilter.h" + * #endif + * + * - protosw for IPv4 (sys/netinet) + * FreeBSD4: struct ipprotosw in netinet/ipprotosw.h + * others: struct protosw in sys/protosw.h + * + * - protosw in general. + * NetBSD 1.5 has extra member for ipfilter (netbsd-current dropped + * it so it will go away in 1.6). + * NetBSD 1.5 requires PR_LISTEN flag bit with protocols that permit + * listen/accept (like tcp). + * + * - header files with defopt (opt_xx.h) + * FreeBSD3: opt_{inet,ipsec,ip6fw,altq}.h + * FreeBSD4: opt_{inet,inet6,ipsec,ip6fw,altq}.h + * NetBSD: opt_{inet,ipsec,altq}.h + * others: does not use defopt + * + * - (m->m_flags & M_EXT) != 0 does *not* mean that the max data length of + * the mbuf == MCLBYTES. + * + * - sys/kern/uipc_mbuf.c:m_dup() + * freebsd[34]: copies the whole mbuf chain. + * netbsd: similar arg with m_copym(). + * others: no m_dup(). + * + * - ifa_refcnt (struct ifaddr) management (IFAREF/IFAFREE). + * NetBSD 1.5: always use IFAREF whenever reference gets added. + * always use IFAFREE whenever reference gets freed. + * IFAFREE frees ifaddr when ifa_refcnt reaches 0. + * Darwin: always use ifaref whenever reference gets added. + * always use ifafree whenever reference gets freed. + * ifaref and ifafree are responsible for determining when to free. + * others: do not increase refcnt for ifp->if_addrlist and in_ifaddr. + * use IFAFREE once when ifaddr is disconnected from + * ifp->if_addrlist and in_ifaddr. IFAFREE frees ifaddr when + * ifa_refcnt goes negative. */ #ifndef __NET_NET_OSDEP_H_DEFINED_ #define __NET_NET_OSDEP_H_DEFINED_ +#include #ifdef KERNEL -#if defined(__NetBSD__) || defined(__OpenBSD__) -#define if_name(ifp) ((ifp)->if_xname) -#else struct ifnet; -extern char *if_name __P((struct ifnet *)); -#endif +extern const char *if_name __P((struct ifnet *)); -#if defined (__APPLE__) #define HAVE_OLD_BPF -#endif -//#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -#if defined (__APPLE__) #define ifa_list ifa_link #define if_addrlist if_addrhead #define if_list if_link -#endif -#if defined(__NetBSD__) && __NetBSD_Version__ >= 104000000 -#define ovbcopy bcopy +/* sys/net/if.h */ +#ifndef __APPLE__ +#define IFAREF(ifa) do { ++(ifa)->ifa_refcnt; } while (0) #endif -#if defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802) -#define HAVE_NRL_INPCB +#define WITH_CONVERT_AND_STRIP_IP_LEN + +#if 1 /* at this moment, all OSes do this */ +#define WITH_CONVERT_IP_OFF #endif #endif /*_KERNEL*/ diff --git a/bsd/net/netisr.h b/bsd/net/netisr.h index 9b5a51f4b..8f4e03ba8 100644 --- a/bsd/net/netisr.h +++ b/bsd/net/netisr.h @@ -54,6 +54,7 @@ * * @(#)netisr.h 8.1 (Berkeley) 6/10/93 */ +#include /* * The networking code runs as a seperate kernel task. @@ -77,6 +78,7 @@ #define NETISR_SET(a,b) +#ifdef __APPLE_API_PRIVATE #if defined(KERNEL) && !defined(LOCORE) extern volatile int netisr; /* scheduling bits for network */ void wakeup(void *); @@ -86,4 +88,4 @@ extern int dlil_input_thread_wakeup; #endif /* defined(KERNEL) && !defined(LOCORE) */ #define schednetisr(anisr) { netisr |= 1<<(anisr); setsoftnet(); } - +#endif __APPLE_API_PRIVATE diff --git a/bsd/net/pfkeyv2.h b/bsd/net/pfkeyv2.h index cd966f618..4b9ec8d8c 100644 --- a/bsd/net/pfkeyv2.h +++ b/bsd/net/pfkeyv2.h @@ -50,8 +50,6 @@ * SUCH DAMAGE. */ -/* $Id: pfkeyv2.h,v 1.3 2000/11/22 01:12:11 zarzycki Exp $ */ - /* * This file has been derived rfc 2367, * And added some flags of SADB_KEY_FLAGS_ as SADB_X_EXT_. @@ -60,6 +58,7 @@ #ifndef _NET_PFKEYV2_H_ #define _NET_PFKEYV2_H_ +#include /* This file defines structures and symbols for the PF_KEY Version 2 @@ -95,7 +94,7 @@ you leave this credit intact on any copies of this file. #define SADB_X_SPDDUMP 18 #define SADB_X_SPDFLUSH 19 #define SADB_X_SPDSETIDX 20 -#define SADB_X_SPDEXPIRE 21 /* not yet */ +#define SADB_X_SPDEXPIRE 21 #define SADB_X_SPDDELETE2 22 /* by policy id */ #define SADB_MAX 22 @@ -105,13 +104,9 @@ struct sadb_msg { u_int8_t sadb_msg_errno; u_int8_t sadb_msg_satype; u_int16_t sadb_msg_len; - u_int8_t sadb_msg_mode; /* XXX */ - u_int8_t sadb_msg_reserved1; + u_int16_t sadb_msg_reserved; u_int32_t sadb_msg_seq; u_int32_t sadb_msg_pid; - u_int32_t sadb_msg_reqid; /* XXX */ - /* when policy mng, value is zero. */ - u_int32_t sadb_msg_reserved2; }; struct sadb_ext { @@ -161,15 +156,6 @@ struct sadb_ident { u_int16_t sadb_ident_reserved; u_int64_t sadb_ident_id; }; -/* in order to use to divide sadb_ident.sadb_ident_id */ -union sadb_x_ident_id { - u_int64_t sadb_x_ident_id; - struct _sadb_x_ident_id_addr { - u_int16_t prefix; - u_int16_t ul_proto; - u_int32_t reserved; - } sadb_x_ident_id_addr; -}; struct sadb_sens { u_int16_t sadb_sens_len; @@ -236,8 +222,24 @@ struct sadb_x_kmprivate { u_int32_t sadb_x_kmprivate_reserved; }; +/* + * XXX Additional SA Extension. + * mode: tunnel or transport + * reqid: to make SA unique nevertheless the address pair of SA are same. + * Mainly it's for VPN. + */ +struct sadb_x_sa2 { + u_int16_t sadb_x_sa2_len; + u_int16_t sadb_x_sa2_exttype; + u_int8_t sadb_x_sa2_mode; + u_int8_t sadb_x_sa2_reserved1; + u_int16_t sadb_x_sa2_reserved2; + u_int32_t sadb_x_sa2_reserved3; + u_int32_t sadb_x_sa2_reqid; +}; + /* XXX Policy Extension */ -/* sizeof(struct sadb_x_policy) == 8 */ +/* sizeof(struct sadb_x_policy) == 16 */ struct sadb_x_policy { u_int16_t sadb_x_policy_len; u_int16_t sadb_x_policy_exttype; @@ -295,7 +297,8 @@ struct sadb_x_ipsecrequest { #define SADB_EXT_SPIRANGE 16 #define SADB_X_EXT_KMPRIVATE 17 #define SADB_X_EXT_POLICY 18 -#define SADB_EXT_MAX 18 +#define SADB_X_EXT_SA2 19 +#define SADB_EXT_MAX 19 #define SADB_SATYPE_UNSPEC 0 #define SADB_SATYPE_AH 2 @@ -316,22 +319,32 @@ struct sadb_x_ipsecrequest { #define SADB_SAFLAGS_PFS 1 -#define SADB_AALG_NONE 0 -#define SADB_AALG_MD5HMAC 1 /* 2 */ -#define SADB_AALG_SHA1HMAC 2 /* 3 */ -#define SADB_AALG_MD5 3 /* Keyed MD5 */ -#define SADB_AALG_SHA 4 /* Keyed SHA */ -#define SADB_AALG_NULL 5 /* null authentication */ -#define SADB_AALG_MAX 6 - -#define SADB_EALG_NONE 0 -#define SADB_EALG_DESCBC 1 /* 2 */ -#define SADB_EALG_3DESCBC 2 /* 3 */ -#define SADB_EALG_NULL 3 /* 11 */ -#define SADB_EALG_BLOWFISHCBC 4 -#define SADB_EALG_CAST128CBC 5 -#define SADB_EALG_RC5CBC 6 -#define SADB_EALG_MAX 7 +/* RFC2367 numbers - meets RFC2407 */ +#define SADB_AALG_NONE 0 +#define SADB_AALG_MD5HMAC 1 /*2*/ +#define SADB_AALG_SHA1HMAC 2 /*3*/ +#define SADB_AALG_MAX 8 +/* private allocations - based on RFC2407/IANA assignment */ +#define SADB_X_AALG_SHA2_256 6 /*5*/ +#define SADB_X_AALG_SHA2_384 7 /*6*/ +#define SADB_X_AALG_SHA2_512 8 /*7*/ +/* private allocations should use 249-255 (RFC2407) */ +#define SADB_X_AALG_MD5 3 /*249*/ /* Keyed MD5 */ +#define SADB_X_AALG_SHA 4 /*250*/ /* Keyed SHA */ +#define SADB_X_AALG_NULL 5 /*251*/ /* null authentication */ + +/* RFC2367 numbers - meets RFC2407 */ +#define SADB_EALG_NONE 0 +#define SADB_EALG_DESCBC 1 /*2*/ +#define SADB_EALG_3DESCBC 2 /*3*/ +#define SADB_EALG_NULL 3 /*11*/ +#define SADB_EALG_MAX 12 +/* private allocations - based on RFC2407/IANA assignment */ +#define SADB_X_EALG_CAST128CBC 5 /*6*/ +#define SADB_X_EALG_BLOWFISHCBC 4 /*7*/ +#define SADB_X_EALG_RIJNDAELCBC 12 +#define SADB_X_EALG_AES 12 +/* private allocations should use 249-255 (RFC2407) */ #if 1 /*nonstandard */ #define SADB_X_CALG_NONE 0 @@ -391,63 +404,9 @@ struct sadb_x_ipsecrequest { #define PFKEY_ADDR_SADDR(ext) \ ((struct sockaddr *)((caddr_t)(ext) + sizeof(struct sadb_address))) -#if 1 /* in 64bits */ #define PFKEY_UNUNIT64(a) ((a) << 3) #define PFKEY_UNIT64(a) ((a) >> 3) -#else -#define PFKEY_UNUNIT64(a) (a) -#define PFKEY_UNIT64(a) (a) -#endif - -#ifndef KERNEL -extern void pfkey_sadump __P((struct sadb_msg *)); -extern void pfkey_spdump __P((struct sadb_msg *)); - -struct sockaddr; -int ipsec_check_keylen __P((u_int, u_int, u_int)); -u_int pfkey_set_softrate __P((u_int, u_int)); -u_int pfkey_get_softrate __P((u_int)); -int pfkey_send_getspi __P((int, u_int, u_int, struct sockaddr *, - struct sockaddr *, u_int32_t, u_int32_t, u_int32_t, u_int32_t)); -int pfkey_send_update __P((int, u_int, u_int, struct sockaddr *, - struct sockaddr *, u_int32_t, u_int32_t, u_int, - caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int64_t, - u_int64_t, u_int64_t, u_int32_t)); -int pfkey_send_add __P((int, u_int, u_int, struct sockaddr *, - struct sockaddr *, u_int32_t, u_int32_t, u_int, - caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int64_t, - u_int64_t, u_int64_t, u_int32_t)); -int pfkey_send_delete __P((int, u_int, u_int, - struct sockaddr *, struct sockaddr *, u_int32_t)); -int pfkey_send_get __P((int, u_int, u_int, - struct sockaddr *, struct sockaddr *, u_int32_t)); -int pfkey_send_register __P((int, u_int)); -int pfkey_recv_register __P((int)); -int pfkey_send_flush __P((int, u_int)); -int pfkey_send_dump __P((int, u_int)); -int pfkey_send_promisc_toggle __P((int, int)); -int pfkey_send_spdadd __P((int, struct sockaddr *, u_int, - struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t)); -int pfkey_send_spdupdate __P((int, struct sockaddr *, u_int, - struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t)); -int pfkey_send_spddelete __P((int, struct sockaddr *, u_int, - struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t)); -int pfkey_send_spddelete2 __P((int, u_int32_t)); -int pfkey_send_spdget __P((int, u_int32_t)); -int pfkey_send_spdsetidx __P((int, struct sockaddr *, u_int, - struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t)); -int pfkey_send_spdflush __P((int)); -int pfkey_send_spddump __P((int)); - -int pfkey_open __P((void)); -void pfkey_close __P((int)); -struct sadb_msg *pfkey_recv __P((int)); -int pfkey_send __P((int, struct sadb_msg *, int)); -int pfkey_align __P((struct sadb_msg *, caddr_t *)); -int pfkey_check __P((caddr_t *)); - -#endif /*!KERNEL*/ #endif /* __PFKEY_V2_H */ diff --git a/bsd/net/ppp_comp.h b/bsd/net/ppp_comp.h index 2d4e31e97..475e85e67 100644 --- a/bsd/net/ppp_comp.h +++ b/bsd/net/ppp_comp.h @@ -49,7 +49,8 @@ #ifndef _NET_PPP_COMP_H #define _NET_PPP_COMP_H - +#include +#ifdef __APPLE_API_UNSTABLE /* * The following symbols control whether we include code for * various compression methods. @@ -182,4 +183,5 @@ struct compressor { #define CI_PREDICTOR_2 2 /* config option for Predictor-2 */ #define CILEN_PREDICTOR_2 2 /* length of its config option */ +#endif /* __APPLE_API_UNSTABLE */ #endif /* _NET_PPP_COMP_H */ diff --git a/bsd/net/ppp_defs.h b/bsd/net/ppp_defs.h index 952a8c283..416aa9ede 100644 --- a/bsd/net/ppp_defs.h +++ b/bsd/net/ppp_defs.h @@ -49,6 +49,7 @@ #ifndef _PPP_DEFS_H_ #define _PPP_DEFS_H_ +#include /* * The basic PPP frame. @@ -89,6 +90,8 @@ #define PPP_LQR 0xc025 /* Link Quality Report protocol */ #define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */ #define PPP_CBCP 0xc029 /* Callback Control Protocol */ +#define PPP_IPV6 0x57 /* Internet Protocol version 6*/ +#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */ /* * Values for FCS calculations. diff --git a/bsd/net/radix.c b/bsd/net/radix.c index 1ec496334..cfe854974 100644 --- a/bsd/net/radix.c +++ b/bsd/net/radix.c @@ -52,6 +52,7 @@ * SUCH DAMAGE. * * @(#)radix.c 8.4 (Berkeley) 11/2/94 + * $FreeBSD: src/sys/net/radix.c,v 1.20.2.2 2001/03/06 00:56:50 obrien Exp $ */ /* @@ -90,7 +91,8 @@ static char *rn_zeros, *rn_ones; #define rn_masktop (mask_rnhead->rnh_treetop) #undef Bcmp -#define Bcmp(a, b, l) (l == 0 ? 0 : bcmp((caddr_t)(a), (caddr_t)(b), (u_long)l)) +#define Bcmp(a, b, l) \ + (l == 0 ? 0 : bcmp((caddr_t)(a), (caddr_t)(b), (u_long)l)) static int rn_lexobetter __P((void *m_arg, void *n_arg)); static struct radix_mask * @@ -101,12 +103,12 @@ static int rn_satsifies_leaf __P((char *trial, struct radix_node *leaf, /* * 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 + * branching removed. The index rn_bit 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.) + * of a node n have keys whose bits all agree up to position rn_bit - 1. + * (We say the index of n is rn_bit.) * - * There is at least one descendant which has a one bit at position rn_b, + * There is at least one descendant which has a one bit at position rn_bit, * and at least one with a zero there. * * A route is determined by a pair of key and mask. We require that the @@ -116,9 +118,9 @@ static int rn_satsifies_leaf __P((char *trial, struct radix_node *leaf, * 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, + * If a node n has a descendant (k, m) with index(m) == index(n) == rn_bit, * 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 + * If the index(m) < rn_bit, 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. * @@ -141,11 +143,11 @@ rn_search(v_arg, head) register struct radix_node *x; register caddr_t v; - for (x = head, v = v_arg; x->rn_b >= 0;) { - if (x->rn_bmask & v[x->rn_off]) - x = x->rn_r; + for (x = head, v = v_arg; x->rn_bit >= 0;) { + if (x->rn_bmask & v[x->rn_offset]) + x = x->rn_right; else - x = x->rn_l; + x = x->rn_left; } return (x); } @@ -158,12 +160,12 @@ rn_search_m(v_arg, head, m_arg) register struct radix_node *x; register caddr_t v = v_arg, m = m_arg; - 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; + for (x = head; x->rn_bit >= 0;) { + if ((x->rn_bmask & m[x->rn_offset]) && + (x->rn_bmask & v[x->rn_offset])) + x = x->rn_right; else - x = x->rn_l; + x = x->rn_left; } return x; } @@ -204,7 +206,8 @@ rn_lookup(v_arg, m_arg, head) caddr_t netmask = 0; if (m_arg) { - if ((x = rn_addmask(m_arg, 1, head->rnh_treetop->rn_off)) == 0) + x = rn_addmask(m_arg, 1, head->rnh_treetop->rn_offset); + if (x == 0) return (0); netmask = x->rn_key; } @@ -247,18 +250,18 @@ rn_match(v_arg, head) register caddr_t cp = v, cp2; caddr_t cplim; struct radix_node *saved_t, *top = t; - int off = t->rn_off, vlen = *(u_char *)cp, matched_off; - register int test, b, rn_b; + int off = t->rn_offset, vlen = *(u_char *)cp, matched_off; + register int test, b, rn_bit; /* * Open code rn_search(v, top) to avoid overhead of extra * subroutine call. */ - for (; t->rn_b >= 0; ) { - if (t->rn_bmask & cp[t->rn_off]) - t = t->rn_r; + for (; t->rn_bit >= 0; ) { + if (t->rn_bmask & cp[t->rn_offset]) + t = t->rn_right; else - t = t->rn_l; + t = t->rn_left; } /* * See if we match exactly as a host destination @@ -280,8 +283,11 @@ rn_match(v_arg, head) /* * This extra grot is in case we are explicitly asked * to look up the default. Ugh! + * + * Never return the root node itself, it seems to cause a + * lot of confusion. */ - if ((t->rn_flags & RNF_ROOT) && t->rn_dupedkey) + if (t->rn_flags & RNF_ROOT) t = t->rn_dupedkey; return t; on1: @@ -290,7 +296,7 @@ on1: b--; matched_off = cp - v; b += matched_off << 3; - rn_b = -1 - b; + rn_bit = -1 - b; /* * If there is a host route in a duped-key chain, it will be first. */ @@ -303,7 +309,7 @@ on1: * a route to a net. */ if (t->rn_flags & RNF_NORMAL) { - if (rn_b <= t->rn_b) + if (rn_bit <= t->rn_bit) return t; } else if (rn_satsifies_leaf(v, t, matched_off)) return t; @@ -311,29 +317,27 @@ on1: /* start searching up the tree */ do { register struct radix_mask *m; - t = t->rn_p; + t = t->rn_parent; m = t->rn_mklist; - if (m) { - /* - * If non-contiguous masks ever become important - * we can restore the masking and open coding of - * the search and satisfaction test and put the - * calculation of "off" back before the "do". - */ - do { - if (m->rm_flags & RNF_NORMAL) { - if (rn_b <= m->rm_b) - return (m->rm_leaf); - } else { - off = min(t->rn_off, matched_off); - x = rn_search_m(v, t, m->rm_mask); - while (x && x->rn_mask != m->rm_mask) - x = x->rn_dupedkey; - if (x && rn_satsifies_leaf(v, x, off)) - return x; - } - m = m->rm_mklist; - } while (m); + /* + * If non-contiguous masks ever become important + * we can restore the masking and open coding of + * the search and satisfaction test and put the + * calculation of "off" back before the "do". + */ + while (m) { + if (m->rm_flags & RNF_NORMAL) { + if (rn_bit <= m->rm_bit) + return (m->rm_leaf); + } else { + off = min(t->rn_offset, matched_off); + x = rn_search_m(v, t, m->rm_mask); + while (x && x->rn_mask != m->rm_mask) + x = x->rn_dupedkey; + if (x && rn_satsifies_leaf(v, x, off)) + return x; + } + m = m->rm_mklist; } } while (t != top); return 0; @@ -353,13 +357,20 @@ rn_newpair(v, b, nodes) 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 = (caddr_t)v; tt->rn_p = t; + t->rn_bit = b; + t->rn_bmask = 0x80 >> (b & 7); + t->rn_left = tt; + t->rn_offset = b >> 3; + tt->rn_bit = -1; + tt->rn_key = (caddr_t)v; + tt->rn_parent = t; tt->rn_flags = t->rn_flags = RNF_ACTIVE; + tt->rn_mklist = t->rn_mklist = 0; #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; + tt->rn_twin = t; + tt->rn_ybro = rn_clist; + rn_clist = tt; #endif return t; } @@ -373,7 +384,7 @@ rn_insert(v_arg, head, dupentry, nodes) { caddr_t v = v_arg; struct radix_node *top = head->rnh_treetop; - int head_off = top->rn_off, vlen = (int)*((u_char *)v); + int head_off = top->rn_offset, vlen = (int)*((u_char *)v); register struct radix_node *t = rn_search(v_arg, top); register caddr_t cp = v + head_off; register int b; @@ -402,24 +413,29 @@ on1: 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 */ + if (cp[x->rn_offset] & x->rn_bmask) + x = x->rn_right; + else + x = x->rn_left; + } while (b > (unsigned) x->rn_bit); + /* x->rn_bit < b && x->rn_bit >= 0 */ #ifdef RN_DEBUG if (rn_debug) log(LOG_DEBUG, "rn_insert: Going In:\n"), traverse(p); #endif - t = rn_newpair(v_arg, b, nodes); tt = t->rn_l; - if ((cp[p->rn_off] & p->rn_bmask) == 0) - p->rn_l = t; + t = rn_newpair(v_arg, b, nodes); + tt = t->rn_left; + if ((cp[p->rn_offset] & p->rn_bmask) == 0) + p->rn_left = 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; + p->rn_right = t; + x->rn_parent = t; + t->rn_parent = p; /* frees x, p as temp vars below */ + if ((cp[t->rn_offset] & t->rn_bmask) == 0) { + t->rn_right = x; } else { - t->rn_r = tt; t->rn_l = x; + t->rn_right = tt; + t->rn_left = x; } #ifdef RN_DEBUG if (rn_debug) @@ -496,7 +512,7 @@ rn_addmask(n_arg, search, skip) isnormal = 0; } b += (cp - netmask) << 3; - x->rn_b = -1 - b; + x->rn_bit = -1 - b; if (isnormal) x->rn_flags |= RNF_NORMAL; return (x); @@ -530,7 +546,7 @@ rn_new_radix_mask(tt, next) return (0); } Bzero(m, sizeof *m); - m->rm_b = tt->rn_b; + m->rm_bit = tt->rn_bit; m->rm_flags = tt->rn_flags; if (tt->rn_flags & RNF_NORMAL) m->rm_leaf = tt; @@ -563,10 +579,10 @@ rn_addroute(v_arg, n_arg, head, treenodes) * nodes and possibly save time in calculating indices. */ if (netmask) { - if ((x = rn_addmask(netmask, 0, top->rn_off)) == 0) + if ((x = rn_addmask(netmask, 0, top->rn_offset)) == 0) return (0); - b_leaf = x->rn_b; - b = -1 - x->rn_b; + b_leaf = x->rn_bit; + b = -1 - x->rn_bit; netmask = x->rn_key; } /* @@ -579,9 +595,9 @@ rn_addroute(v_arg, n_arg, head, treenodes) return (0); if (netmask == 0 || (tt->rn_mask && - ((b_leaf < tt->rn_b) || /* index(netmask) > node */ - rn_refines(netmask, tt->rn_mask) || - rn_lexobetter(netmask, tt->rn_mask)))) + ((b_leaf < tt->rn_bit) /* index(netmask) > node */ + || rn_refines(netmask, tt->rn_mask) + || rn_lexobetter(netmask, tt->rn_mask)))) break; } /* @@ -599,23 +615,26 @@ rn_addroute(v_arg, n_arg, head, treenodes) /* link in at head of list */ (tt = treenodes)->rn_dupedkey = t; tt->rn_flags = t->rn_flags; - tt->rn_p = x = t->rn_p; - t->rn_p = tt; /* parent */ - if (x->rn_l == t) x->rn_l = tt; else x->rn_r = tt; + tt->rn_parent = x = t->rn_parent; + t->rn_parent = tt; /* parent */ + if (x->rn_left == t) + x->rn_left = tt; + else + x->rn_right = tt; saved_tt = tt; x = xx; } else { (tt = treenodes)->rn_dupedkey = t->rn_dupedkey; t->rn_dupedkey = tt; - tt->rn_p = t; /* parent */ + tt->rn_parent = t; /* parent */ if (tt->rn_dupedkey) /* parent */ - tt->rn_dupedkey->rn_p = tt; /* parent */ + tt->rn_dupedkey->rn_parent = tt; /* parent */ } #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 tt->rn_key = (caddr_t) v; - tt->rn_b = -1; + tt->rn_bit = -1; tt->rn_flags = RNF_ACTIVE; } /* @@ -623,18 +642,21 @@ rn_addroute(v_arg, n_arg, head, treenodes) */ if (netmask) { tt->rn_mask = netmask; - tt->rn_b = x->rn_b; + tt->rn_bit = x->rn_bit; tt->rn_flags |= x->rn_flags & RNF_NORMAL; } - t = saved_tt->rn_p; + t = saved_tt->rn_parent; if (keyduplicated) goto on2; - b_leaf = -1 - t->rn_b; - if (t->rn_r == saved_tt) x = t->rn_l; else x = t->rn_r; + b_leaf = -1 - t->rn_bit; + if (t->rn_right == saved_tt) + x = t->rn_left; + else + x = t->rn_right; /* Promote general routes from below */ - if (x->rn_b < 0) { + if (x->rn_bit < 0) { for (mp = &t->rn_mklist; x; x = x->rn_dupedkey) - if (x->rn_mask && (x->rn_b >= b_leaf) && x->rn_mklist == 0) { + if (x->rn_mask && (x->rn_bit >= b_leaf) && x->rn_mklist == 0) { *mp = m = rn_new_radix_mask(x, 0); if (m) mp = &m->rm_mklist; @@ -644,19 +666,19 @@ rn_addroute(v_arg, n_arg, head, treenodes) * 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) + if (m->rm_bit >= b_leaf) break; t->rn_mklist = m; *mp = 0; } on2: /* Add new route to highest possible ancestor's list */ - if ((netmask == 0) || (b > t->rn_b )) + if ((netmask == 0) || (b > t->rn_bit )) return tt; /* can't lift at all */ - b_leaf = tt->rn_b; + b_leaf = tt->rn_bit; do { x = t; - t = t->rn_p; - } while (b <= t->rn_b && x != top); + t = t->rn_parent; + } while (b <= t->rn_bit && x != top); /* * Search through routes associated with node to * insert new route according to index. @@ -664,15 +686,15 @@ on2: * double loop on deletion. */ for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist) { - if (m->rm_b < b_leaf) + if (m->rm_bit < b_leaf) continue; - if (m->rm_b > b_leaf) + if (m->rm_bit > b_leaf) break; if (m->rm_flags & RNF_NORMAL) { mmask = m->rm_leaf->rn_mask; if (tt->rn_flags & RNF_NORMAL) { - log(LOG_ERR, - "Non-unique normal route, mask not entered"); + log(LOG_ERR, + "Non-unique normal route, mask not entered"); return tt; } } else @@ -682,7 +704,8 @@ on2: tt->rn_mklist = m; return tt; } - if (rn_refines(netmask, mmask) || rn_lexobetter(netmask, mmask)) + if (rn_refines(netmask, mmask) + || rn_lexobetter(netmask, mmask)) break; } *mp = rn_new_radix_mask(tt, *mp); @@ -704,7 +727,7 @@ rn_delete(v_arg, netmask_arg, head) netmask = netmask_arg; x = head->rnh_treetop; tt = rn_search(v, x); - head_off = x->rn_off; + head_off = x->rn_offset; vlen = *(u_char *)v; saved_tt = tt; top = x; @@ -737,14 +760,14 @@ rn_delete(v_arg, netmask_arg, head) if (--m->rm_refs >= 0) goto on1; } - b = -1 - tt->rn_b; - t = saved_tt->rn_p; - if (b > t->rn_b) + b = -1 - tt->rn_bit; + t = saved_tt->rn_parent; + if (b > t->rn_bit) goto on1; /* Wasn't lifted at all */ do { x = t; - t = t->rn_p; - } while (b <= t->rn_b && x != top); + t = t->rn_parent; + } while (b <= t->rn_bit && x != top); for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist) if (m == saved_m) { *mp = m->rm_mklist; @@ -767,7 +790,7 @@ on1: for (t = rn_clist; t && t->rn_ybro != tt; t = t->rn_ybro) {} if (t) t->rn_ybro = tt->rn_ybro; #endif - t = tt->rn_p; + t = tt->rn_parent; dupedkey = saved_tt->rn_dupedkey; if (dupedkey) { /* @@ -776,39 +799,57 @@ on1: */ if (tt == saved_tt) { /* remove from head of chain */ - x = dupedkey; x->rn_p = t; - if (t->rn_l == tt) t->rn_l = x; else t->rn_r = x; + x = dupedkey; x->rn_parent = t; + if (t->rn_left == tt) + t->rn_left = x; + else + t->rn_right = x; } else { /* find node in front of tt on the chain */ for (x = p = saved_tt; p && p->rn_dupedkey != tt;) p = p->rn_dupedkey; if (p) { p->rn_dupedkey = tt->rn_dupedkey; - if (tt->rn_dupedkey) /* parent */ - tt->rn_dupedkey->rn_p = p; /* parent */ + if (tt->rn_dupedkey) /* parent */ + tt->rn_dupedkey->rn_parent = p; + /* parent */ } else log(LOG_ERR, "rn_delete: couldn't find us\n"); } t = tt + 1; if (t->rn_flags & RNF_ACTIVE) { #ifndef RN_DEBUG - *++x = *t; p = t->rn_p; + *++x = *t; + p = t->rn_parent; #else - b = t->rn_info; *++x = *t; t->rn_info = b; p = t->rn_p; + b = t->rn_info; + *++x = *t; + t->rn_info = b; + p = t->rn_parent; #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; + if (p->rn_left == t) + p->rn_left = x; + else + p->rn_right = x; + x->rn_left->rn_parent = x; + x->rn_right->rn_parent = x; } 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; + if (t->rn_left == tt) + x = t->rn_right; + else + x = t->rn_left; + p = t->rn_parent; + if (p->rn_right == t) + p->rn_right = x; + else + p->rn_left = x; + x->rn_parent = p; /* * Demote routes attached to us. */ if (t->rn_mklist) { - if (x->rn_b >= 0) { + if (x->rn_bit >= 0) { for (mp = &x->rn_mklist; (m = *mp);) mp = &m->rm_mklist; *mp = t->rn_mklist; @@ -838,11 +879,17 @@ on1: #ifndef RN_DEBUG *t = *x; #else - b = t->rn_info; *t = *x; t->rn_info = b; + 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; + t->rn_left->rn_parent = t; + t->rn_right->rn_parent = t; + p = x->rn_parent; + if (p->rn_left == x) + p->rn_left = t; + else + p->rn_right = t; } out: tt->rn_flags &= ~RNF_ACTIVE; @@ -873,17 +920,17 @@ rn_walktree_from(h, a, m, f, w) * rn_search_m is sort-of-open-coded here. */ /* printf("about to search\n"); */ - for (rn = h->rnh_treetop; rn->rn_b >= 0; ) { + for (rn = h->rnh_treetop; rn->rn_bit >= 0; ) { last = rn; - /* printf("rn_b %d, rn_bmask %x, xm[rn_off] %x\n", - rn->rn_b, rn->rn_bmask, xm[rn->rn_off]); */ - if (!(rn->rn_bmask & xm[rn->rn_off])) { + /* printf("rn_bit %d, rn_bmask %x, xm[rn_offset] %x\n", + rn->rn_bit, rn->rn_bmask, xm[rn->rn_offset]); */ + if (!(rn->rn_bmask & xm[rn->rn_offset])) { break; } - if (rn->rn_bmask & xa[rn->rn_off]) { - rn = rn->rn_r; + if (rn->rn_bmask & xa[rn->rn_offset]) { + rn = rn->rn_right; } else { - rn = rn->rn_l; + rn = rn->rn_left; } } /* printf("done searching\n"); */ @@ -895,7 +942,7 @@ rn_walktree_from(h, a, m, f, w) * Either way, last is the node we want to start from. */ rn = last; - lastb = rn->rn_b; + lastb = rn->rn_bit; /* printf("rn %p, lastb %d\n", rn, lastb);*/ @@ -904,26 +951,27 @@ rn_walktree_from(h, a, m, f, w) * while applying the function f to it, so we need to calculate * the successor node in advance. */ - while (rn->rn_b >= 0) - rn = rn->rn_l; + while (rn->rn_bit >= 0) + rn = rn->rn_left; while (!stopping) { - /* printf("node %p (%d)\n", rn, rn->rn_b); */ + /* printf("node %p (%d)\n", rn, rn->rn_bit); */ base = rn; /* If at right child go back up, otherwise, go right */ - while (rn->rn_p->rn_r == rn && !(rn->rn_flags & RNF_ROOT)) { - rn = rn->rn_p; + while (rn->rn_parent->rn_right == rn + && !(rn->rn_flags & RNF_ROOT)) { + rn = rn->rn_parent; /* if went up beyond last, stop */ - if (rn->rn_b < lastb) { + if (rn->rn_bit < lastb) { stopping = 1; /* printf("up too far\n"); */ } } /* Find the next *leaf* since next node might vanish, too */ - for (rn = rn->rn_p->rn_r; rn->rn_b >= 0;) - rn = rn->rn_l; + for (rn = rn->rn_parent->rn_right; rn->rn_bit >= 0;) + rn = rn->rn_left; next = rn; /* Process leaves */ while ((rn = base) != 0) { @@ -959,24 +1007,37 @@ rn_walktree(h, f, w) * the successor node in advance. */ /* First time through node, go left */ - while (rn->rn_b >= 0) - rn = rn->rn_l; + while (rn->rn_bit >= 0) + if (rn) + rn = rn->rn_left; + else return(0); for (;;) { base = rn; /* If at right child go back up, otherwise, go right */ - while (rn->rn_p->rn_r == rn && (rn->rn_flags & RNF_ROOT) == 0) - rn = rn->rn_p; + while (rn != NULL && rn->rn_parent != NULL && rn->rn_parent->rn_right == rn + && (rn->rn_flags & RNF_ROOT) == 0) + rn = rn->rn_parent; /* Find the next *leaf* since next node might vanish, too */ - for (rn = rn->rn_p->rn_r; rn->rn_b >= 0;) - rn = rn->rn_l; + if (rn == NULL || rn->rn_parent == NULL || rn->rn_parent->rn_right == NULL) + return (0); + for (rn = rn->rn_parent->rn_right; rn->rn_bit >= 0;) { + if (rn == NULL || rn->rn_parent == NULL || rn->rn_parent->rn_right == NULL || rn->rn_left == NULL) + return(0); + rn = rn->rn_left; + } next = rn; /* Process leaves */ while ((rn = base)) { + if (rn == NULL) + return(0); base = rn->rn_dupedkey; - if (!(rn->rn_flags & RNF_ROOT) && (error = (*f)(rn, w))) + if (!(rn->rn_flags & RNF_ROOT) + && (error = (*f)(rn, w))) return (error); } rn = next; + if (rn == NULL) + return (0); if (rn->rn_flags & RNF_ROOT) return (0); } @@ -999,11 +1060,11 @@ rn_inithead(head, off) *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; + t->rn_right = ttt; + t->rn_parent = t; + tt = t->rn_left; tt->rn_flags = t->rn_flags = RNF_ROOT | RNF_ACTIVE; - tt->rn_b = -1 - off; + tt->rn_bit = -1 - off; *ttt = *tt; ttt->rn_key = rn_ones; rnh->rnh_addaddr = rn_addroute; diff --git a/bsd/net/radix.h b/bsd/net/radix.h index eeef4221b..833e9f714 100644 --- a/bsd/net/radix.h +++ b/bsd/net/radix.h @@ -52,10 +52,14 @@ * SUCH DAMAGE. * * @(#)radix.h 8.2 (Berkeley) 10/31/94 + * $FreeBSD: src/sys/net/radix.h,v 1.16.2.1 2000/05/03 19:17:11 wollman Exp $ */ #ifndef _RADIX_H_ #define _RADIX_H_ +#include + +#if !defined(KERNEL) || defined(__APPLE_API_PRIVATE) #ifdef MALLOC_DECLARE MALLOC_DECLARE(M_RTABLE); @@ -67,8 +71,8 @@ MALLOC_DECLARE(M_RTABLE); 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) */ + struct radix_node *rn_parent; /* parent */ + short rn_bit; /* 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 */ @@ -93,19 +97,27 @@ struct radix_node { #endif }; -#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 - +#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_offset rn_u.rn_node.rn_Off +#define rn_left rn_u.rn_node.rn_L +#define rn_right rn_u.rn_node.rn_R + +#if 0 +/* for backward compatibility with previous definitions */ +#define rn_p rn_parent +#define rn_b rn_bit +#define rn_off rn_offset +#define rn_l rn_left +#define rn_r rn_right +#endif /* * Annotations to tree concerning potential routes applying to subtrees. */ struct radix_mask { - short rm_b; /* bit offset; -1-index(netmask) */ + short rm_bit; /* 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 */ @@ -116,8 +128,9 @@ struct radix_mask { int rm_refs; /* # of references to this struct */ }; -#define rm_mask rm_rmu.rmu_mask -#define rm_leaf rm_rmu.rmu_leaf /* extra field would make 32 bytes */ +#define rm_mask rm_rmu.rmu_mask +#define rm_leaf rm_rmu.rmu_leaf /* extra field would make 32 bytes */ + #define MKGet(m) {\ if (rn_mkfreelist) {\ @@ -186,5 +199,5 @@ struct radix_node struct radix_node_head *head)), *rn_match __P((void *, struct radix_node_head *)); - +#endif /* __APPLE_API_PRIVATE || !KERNEL */ #endif /* _RADIX_H_ */ diff --git a/bsd/net/raw_cb.h b/bsd/net/raw_cb.h index 3224741d2..d047ae38f 100644 --- a/bsd/net/raw_cb.h +++ b/bsd/net/raw_cb.h @@ -56,9 +56,11 @@ #ifndef _NET_RAW_CB_H_ #define _NET_RAW_CB_H_ +#include #include +#ifdef __APPLE_API_PRIVATE /* * Raw protocol interface control block. Used * to tie a socket to the generic raw interface. @@ -71,6 +73,7 @@ struct rawcb { struct sockproto rcb_proto; /* protocol family, protocol */ u_long reserved[4]; /* for future use */ }; +#endif /* __APPLE_API_PRIVATE */ #define sotorawcb(so) ((struct rawcb *)(so)->so_pcb) @@ -81,6 +84,7 @@ struct rawcb { #define RAWRCVQ 8192 #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE extern LIST_HEAD(rawcb_list_head, rawcb) rawcb_list; int raw_attach __P((struct socket *, int)); @@ -92,6 +96,7 @@ void raw_input __P((struct mbuf *, struct sockproto *, struct sockaddr *, struct sockaddr *)); extern struct pr_usrreqs raw_usrreqs; +#endif /* __APPLE_API_PRIVATE */ #endif #endif diff --git a/bsd/net/raw_usrreq.c b/bsd/net/raw_usrreq.c index b2f44395a..5e8a246a9 100644 --- a/bsd/net/raw_usrreq.c +++ b/bsd/net/raw_usrreq.c @@ -52,6 +52,7 @@ * SUCH DAMAGE. * * @(#)raw_usrreq.c 8.1 (Berkeley) 6/10/93 + * $FreeBSD: src/sys/net/raw_usrreq.c,v 1.18 1999/08/28 00:48:28 peter Exp $ */ #include @@ -178,14 +179,13 @@ raw_uattach(struct socket *so, int proto, struct proc *p) if (rp == 0) return EINVAL; -#if ISFB31 - if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0) - return error; -#else +#ifdef __APPLE__ if ((so->so_state & SS_PRIV) == 0) return (EPERM); +#else + if (p && (error = suser(p)) != 0) + return error; #endif - return raw_attach(so, proto); } diff --git a/bsd/net/route.c b/bsd/net/route.c index 22d8678d3..5cebf16f6 100644 --- a/bsd/net/route.c +++ b/bsd/net/route.c @@ -52,19 +52,16 @@ * SUCH DAMAGE. * * @(#)route.c 8.2 (Berkeley) 11/15/93 + * $FreeBSD: src/sys/net/route.c,v 1.59.2.3 2001/07/29 19:18:02 ume Exp $ */ - -#if NOTFB31 -#include "opt_inet.h" -#include "opt_mrouting.h" -#endif - + #include #include #include #include #include #include +#include #include #include @@ -109,9 +106,7 @@ void 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, 0UL); + rtalloc_ign(ro, 0UL); } void @@ -119,8 +114,18 @@ rtalloc_ign(ro, ignore) register struct route *ro; u_long ignore; { - if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP)) - return; /* XXX */ + struct rtentry *rt; + int s; + + if ((rt = ro->ro_rt) != NULL) { + if (rt->rt_ifp != NULL && rt->rt_flags & RTF_UP) + return; + /* XXX - We are probably always at splnet here already. */ + s = splnet(); + rtfree(rt); + ro->ro_rt = NULL; + splx(s); + } ro->ro_rt = rtalloc1(&ro->ro_dst, 1, ignore); } @@ -142,7 +147,7 @@ rtalloc1(dst, report, ignflags) u_long nflags; int s = splnet(), err = 0, msgtype = RTM_MISS; - /* + /* * Look up the address in the table for that Address Family */ if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) && @@ -167,19 +172,19 @@ rtalloc1(dst, report, ignflags) * what we have will do. Return that. */ newrt = rt; - rt->rt_refcnt++; + rtref(rt); goto miss; } if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) { /* - * If the new route specifies it be + * If the new route specifies it be * externally resolved, then go do that. */ msgtype = RTM_RESOLVE; goto miss; } } else - rt->rt_refcnt++; + rtref(rt); } else { /* * Either we hit the root or couldn't find any match, @@ -215,7 +220,6 @@ rtfree(rt) */ register struct radix_node_head *rnh = rt_tables[rt_key(rt)->sa_family]; - register struct ifaddr *ifa; if (rt == 0 || rnh == 0) panic("rtfree"); @@ -237,7 +241,7 @@ rtfree(rt) if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) { if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT)) panic ("rtfree 2"); - /* + /* * the rtentry must have been removed from the routing table * so it is represented in rttrash.. remove that now. */ @@ -250,14 +254,25 @@ rtfree(rt) } #endif - /* + /* * release references on items we hold them on.. * e.g other routes and ifaddrs. */ - if((ifa = rt->rt_ifa)) - IFAFREE(ifa); - if (rt->rt_parent) { - RTFREE(rt->rt_parent); + if (rt->rt_parent) + rtfree(rt->rt_parent); + + if(rt->rt_ifa && !(rt->rt_parent && rt->rt_parent->rt_ifa == rt->rt_ifa)) { + /* + * Only release the ifa if our parent doesn't hold it for us. + * The parent route is responsible for holding a reference + * to the ifa for us. Ifa refcounts are 16bit, if every + * cloned route held a reference, the 16bit refcount may + * rollover, making a mess :( + * + * FreeBSD solved this by making the ifa_refcount 32bits, but + * we can't do that since it changes the size of the ifaddr struct. + */ + ifafree(rt->rt_ifa); } /* @@ -274,18 +289,98 @@ rtfree(rt) } } +/* + * Decrements the refcount but does not free the route when + * the refcount reaches zero. Unless you have really good reason, + * use rtfree not rtunref. + */ +void +rtunref(struct rtentry* rt) +{ + if (rt == NULL) + panic("rtunref"); + rt->rt_refcnt--; +#if DEBUG + if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) + printf("rtunref - if rtfree were called, we would have freed route\n"); +#endif +} + +/* + * Add a reference count from an rtentry. + */ +void +rtref(struct rtentry* rt) +{ + if (rt == NULL) + panic("rtref"); + + rt->rt_refcnt++; +} + +void +rtsetifa(struct rtentry *rt, struct ifaddr* ifa) +{ + if (rt == NULL) + panic("rtsetifa"); + + if (rt->rt_ifa == ifa) + return; + + /* Release the old ifa if it isn't our parent route's ifa */ + if (rt->rt_ifa && !(rt->rt_parent && rt->rt_parent->rt_ifa == rt->rt_ifa)) + ifafree(rt->rt_ifa); + + /* Set rt_ifa */ + rt->rt_ifa = ifa; + + /* Take a reference to the ifa if it isn't our parent route's ifa */ + if (rt->rt_ifa && !(rt->rt_parent && rt->rt_parent->rt_ifa == ifa)) + ifaref(rt->rt_ifa); +} + void ifafree(ifa) register struct ifaddr *ifa; { if (ifa == NULL) panic("ifafree"); - if (ifa->ifa_refcnt == 0) + if (ifa->ifa_refcnt == 0) { +#ifdef __APPLE__ + /* Detect case where an ifa is being freed before it should */ + struct ifnet* ifp; + /* Verify this ifa isn't attached to an interface */ + for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) { + struct ifaddr *ifaInUse; + for (ifaInUse = ifp->if_addrhead.tqh_first; ifaInUse; ifaInUse = ifaInUse->ifa_link.tqe_next) { + if (ifa == ifaInUse) { + /* + * This is an ugly hack done because we can't move to a 32 bit + * refcnt like bsd has. We have to maintain binary compatibility + * in our kernel, unlike FreeBSD. + */ + log(LOG_ERR, "ifa attached to ifp is being freed, leaking insted\n"); + return; + } + } + } +#endif FREE(ifa, M_IFADDR); + } else ifa->ifa_refcnt--; } +#ifdef __APPLE__ +void +ifaref(struct ifaddr *ifa) +{ + if (ifa == NULL) + panic("ifaref"); + ifa->ifa_refcnt++; +} +#endif + /* * Force a routing table entry to the specified * destination to go through the given gateway. @@ -441,7 +536,7 @@ ifa_ifwithroute(flags, dst, gateway) struct rtentry *rt = rtalloc1(dst, 0, 0UL); if (rt == 0) return (0); - rt->rt_refcnt--; + rtunref(rt); if ((ifa = rt->rt_ifa) == 0) return (0); } @@ -509,8 +604,9 @@ rtrequest(req, dst, gateway, netmask, flags, ret_nrt) * Now search what's left of the subtree for any cloned * routes which might have been formed from this node. */ - if ((rt->rt_flags & RTF_PRCLONING) && netmask) { - rnh->rnh_walktree_from(rnh, dst, netmask, + if ((rt->rt_flags & (RTF_CLONING | RTF_PRCLONING)) && + rt_mask(rt)) { + rnh->rnh_walktree_from(rnh, dst, rt_mask(rt), rt_fixdelete, rt); } @@ -521,7 +617,7 @@ rtrequest(req, dst, gateway, netmask, flags, ret_nrt) */ if (rt->rt_gwroute) { rt = rt->rt_gwroute; - RTFREE(rt); + rtfree(rt); (rt = (struct rtentry *)rn)->rt_gwroute = 0; } @@ -534,7 +630,7 @@ rtrequest(req, dst, gateway, netmask, flags, ret_nrt) */ rt->rt_flags &= ~RTF_UP; - /* + /* * give the protocol a chance to keep things in sync. */ if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest) @@ -554,7 +650,7 @@ rtrequest(req, dst, gateway, netmask, flags, ret_nrt) if (ret_nrt) *ret_nrt = rt; else if (rt->rt_refcnt <= 0) { - rt->rt_refcnt++; + rt->rt_refcnt++; /* make a 1->0 transition */ rtfree(rt); } break; @@ -588,7 +684,7 @@ rtrequest(req, dst, gateway, netmask, flags, ret_nrt) * Add the gateway. Possibly re-malloc-ing the storage for it * also add the rt_gwroute if possible. */ - if (error = rt_setgate(rt, dst, gateway)) { + if ((error = rt_setgate(rt, dst, gateway)) != 0) { Free(rt); senderr(error); } @@ -611,10 +707,18 @@ rtrequest(req, dst, gateway, netmask, flags, ret_nrt) * This moved from below so that rnh->rnh_addaddr() can * examine the ifa and ifa->ifa_ifp if it so desires. */ - ifa->ifa_refcnt++; + /* + * Note that we do not use rtsetifa here because + * rt_parent has not been setup yet. + */ + ifaref(ifa); rt->rt_ifa = ifa; rt->rt_ifp = ifa->ifa_ifp; - rt->rt_dlt = ifa->ifa_dlt; +#ifdef __APPLE__ + rt->rt_dlt = ifa->ifa_dlt; /* dl_tag */ +#endif + /* XXX mtu manipulation will be done in rnh_addaddr -- itojun */ + rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask, rnh, rt->rt_nodes); if (rn == 0) { @@ -628,17 +732,17 @@ rtrequest(req, dst, gateway, netmask, flags, ret_nrt) */ rt2 = rtalloc1(dst, 0, RTF_PRCLONING); if (rt2 && rt2->rt_parent) { - rtrequest(RTM_DELETE, + rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt2), rt2->rt_gateway, rt_mask(rt2), rt2->rt_flags, 0); - RTFREE(rt2); + rtfree(rt2); rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask, rnh, rt->rt_nodes); } else if (rt2) { /* undo the extra ref we got */ - RTFREE(rt2); + rtfree(rt2); } } @@ -650,7 +754,7 @@ rtrequest(req, dst, gateway, netmask, flags, ret_nrt) if (rt->rt_gwroute) rtfree(rt->rt_gwroute); if (rt->rt_ifa) { - IFAFREE(rt->rt_ifa); + ifafree(rt->rt_ifa); } Free(rt_key(rt)); Free(rt); @@ -659,16 +763,23 @@ rtrequest(req, dst, gateway, netmask, flags, ret_nrt) rt->rt_parent = 0; - /* + /* * If we got here from RESOLVE, then we are cloning - * so clone the rest, and note that we + * so clone the rest, and note that we * are a clone (and increment the parent's references) */ if (req == RTM_RESOLVE) { rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */ - if ((*ret_nrt)->rt_flags & RTF_PRCLONING) { + if ((*ret_nrt)->rt_flags & (RTF_CLONING | RTF_PRCLONING)) { rt->rt_parent = (*ret_nrt); - (*ret_nrt)->rt_refcnt++; + rtref(*ret_nrt); + + /* + * If our parent is holding a reference to the same ifa, + * free our reference and rely on the parent holding it. + */ + if (rt->rt_parent && rt->rt_parent->rt_ifa == rt->rt_ifa) + ifafree(rt->rt_ifa); } } @@ -698,7 +809,7 @@ rtrequest(req, dst, gateway, netmask, flags, ret_nrt) */ if (ret_nrt) { *ret_nrt = rt; - rt->rt_refcnt++; + rtref(rt); } break; } @@ -737,9 +848,7 @@ rt_fixdelete(rn, vp) * network route and (cloned) host routes. For this reason, a simple check * of rt->rt_parent is insufficient; each candidate route must be tested * against the (mask, value) of the new route (passed as before in vp) - * to see if the new route matches it. Unfortunately, this has the obnoxious - * property of also triggering for insertion /above/ a pre-existing network - * route and clones. Sigh. This may be fixed some day. + * to see if the new route matches it. * * XXX - it may be possible to do fixdelete() for changes and reserve this * routine just for adds. I'm not sure why I thought it was necessary to do @@ -758,8 +867,8 @@ rt_fixchange(rn, vp) struct rtfc_arg *ap = vp; struct rtentry *rt0 = ap->rt0; struct radix_node_head *rnh = ap->rnh; - u_char *xk1, *xm1, *xk2; - int i, len; + u_char *xk1, *xm1, *xk2, *xmp; + int i, len, mlen; #ifdef DEBUG if (rtfcdebug) @@ -793,7 +902,29 @@ rt_fixchange(rn, vp) xm1 = (u_char *)rt_mask(rt0); xk2 = (u_char *)rt_key(rt); - for (i = rnh->rnh_treetop->rn_off; i < len; i++) { + /* avoid applying a less specific route */ + xmp = (u_char *)rt_mask(rt->rt_parent); + mlen = ((struct sockaddr *)rt_key(rt->rt_parent))->sa_len; + if (mlen > ((struct sockaddr *)rt_key(rt0))->sa_len) { +#if DEBUG + if (rtfcdebug) + printf("rt_fixchange: inserting a less " + "specific route\n"); +#endif + return 0; + } + for (i = rnh->rnh_treetop->rn_offset; i < mlen; i++) { + if ((xmp[i] & ~(xmp[i] ^ xm1[i])) != xmp[i]) { +#if DEBUG + if (rtfcdebug) + printf("rt_fixchange: inserting a less " + "specific route\n"); +#endif + return 0; + } + } + + for (i = rnh->rnh_treetop->rn_offset; i < len; i++) { if ((xk2[i] & xm1[i]) != xk1[i]) { #ifdef DEBUG if(rtfcdebug) printf("no match\n"); @@ -867,8 +998,8 @@ rt_setgate(rt0, dst, gate) */ Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen); - /* - * if we are replacing the chunk (or it's new) we need to + /* + * if we are replacing the chunk (or it's new) we need to * replace the dst as well */ if (old) { @@ -881,7 +1012,7 @@ rt_setgate(rt0, dst, gate) * so drop it. */ if (rt->rt_gwroute) { - rt = rt->rt_gwroute; RTFREE(rt); + rt = rt->rt_gwroute; rtfree(rt); rt = rt0; rt->rt_gwroute = 0; } /* @@ -897,7 +1028,7 @@ rt_setgate(rt0, dst, gate) if (rt->rt_flags & RTF_GATEWAY) { rt->rt_gwroute = rtalloc1(gate, 1, RTF_PRCLONING); if (rt->rt_gwroute == rt) { - RTFREE(rt->rt_gwroute); + rtfree(rt->rt_gwroute); rt->rt_gwroute = 0; return EDQUOT; /* failure */ } @@ -962,13 +1093,15 @@ rtinit(ifa, cmd, flags) * be confusing at best and possibly worse. */ if (cmd == RTM_DELETE) { - /* + /* * It's a delete, so it should already exist.. * If it's a net, mask off the host bits * (Assuming we have a mask) */ if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) { - m = m_get(M_WAIT, MT_SONAME); + m = m_get(M_DONTWAIT, MT_SONAME); + if (m == NULL) + return(ENOBUFS); deldst = mtod(m, struct sockaddr *); rt_maskedcopy(dst, deldst, ifa->ifa_netmask); dst = deldst; @@ -986,13 +1119,13 @@ rtinit(ifa, cmd, flags) * for us at this stage. we won't need that so * lop that off now. */ - rt->rt_refcnt--; + rtunref(rt); if (rt->rt_ifa != ifa) { /* * If the interface in the rtentry doesn't match * the interface we are using, then we don't * want to delete it, so return an error. - * This seems to be the only point of + * This seems to be the only point of * this whole RTM_DELETE clause. */ if (m) @@ -1004,7 +1137,7 @@ rtinit(ifa, cmd, flags) /* XXX */ #if 0 else { - /* + /* * One would think that as we are deleting, and we know * it doesn't exist, we could just return at this point * with an "ELSE" clause, but apparently not.. @@ -1031,7 +1164,7 @@ rtinit(ifa, cmd, flags) */ rt_newaddrmsg(cmd, ifa, error, nrt); if (rt->rt_refcnt <= 0) { - rt->rt_refcnt++; + rt->rt_refcnt++; /* need a 1->0 transition to free */ rtfree(rt); } } @@ -1044,14 +1177,16 @@ rtinit(ifa, cmd, flags) /* * We just wanted to add it.. we don't actually need a reference */ - rt->rt_refcnt--; + rtunref(rt); /* - * If it came back with an unexpected interface, then it must + * If it came back with an unexpected interface, then it must * have already existed or something. (XXX) */ if (rt->rt_ifa != ifa) { - printf("rtinit: wrong ifa (%p) was (%p)\n", ifa, - rt->rt_ifa); + if (!(rt->rt_ifa->ifa_ifp->if_flags & + (IFF_POINTOPOINT|IFF_LOOPBACK))) + printf("rtinit: wrong ifa (%p) was (%p)\n", + ifa, rt->rt_ifa); /* * Ask that the protocol in question * remove anything it has associated with @@ -1059,19 +1194,19 @@ rtinit(ifa, cmd, flags) */ if (rt->rt_ifa->ifa_rtrequest) rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0)); - /* - * Remove the referenve to the it's ifaddr. + /* + * Set the route's ifa. */ - IFAFREE(rt->rt_ifa); + rtsetifa(rt, ifa); /* * And substitute in references to the ifaddr * we are adding. */ - rt->rt_ifa = ifa; rt->rt_ifp = ifa->ifa_ifp; - rt->rt_dlt = ifa->ifa_dlt; - rt->rt_rmx.rmx_mtu = ifa->ifa_ifp->if_mtu; - ifa->ifa_refcnt++; +#ifdef __APPLE__ + rt->rt_dlt = ifa->ifa_dlt; /* dl_tag */ +#endif + rt->rt_rmx.rmx_mtu = ifa->ifa_ifp->if_mtu; /*XXX*/ /* * Now ask the protocol to check if it needs * any special processing in its new form. diff --git a/bsd/net/route.h b/bsd/net/route.h index e4c06e50a..cd5060001 100644 --- a/bsd/net/route.h +++ b/bsd/net/route.h @@ -52,10 +52,12 @@ * SUCH DAMAGE. * * @(#)route.h 8.3 (Berkeley) 4/19/94 + * $FreeBSD: src/sys/net/route.h,v 1.36.2.1 2000/08/16 06:14:23 jayanth Exp $ */ #ifndef _NET_ROUTE_H_ #define _NET_ROUTE_H_ +#include /* * Kernel resident routing tables. @@ -69,11 +71,15 @@ * to a routing entry. These are often held by protocols * in their control blocks, e.g. inpcb. */ +#if !defined(KERNEL) || defined(__APPLE_API_PRIVATE) struct route { struct rtentry *ro_rt; struct sockaddr ro_dst; u_long reserved[2]; /* for future use if needed */ }; +#else +struct route; +#endif /* * These numbers are used by reliable protocols for determining @@ -117,13 +123,13 @@ struct mbuf; #ifndef RNF_NORMAL #include #endif +#ifdef __APPLE_API_UNSTABLE 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_filler; /* was short flags field */ - short rt_refcnt; /* # held references */ + int32_t rt_refcnt; /* # held references */ u_long rt_flags; /* up/down?, host/net */ struct ifnet *rt_ifp; /* the answer: interface to use */ u_long rt_dlt; /* DLIL dl_tag */ @@ -138,6 +144,7 @@ struct rtentry { struct rtentry *rt_parent; /* cloning parent of this route */ void *rt_filler2; /* more filler */ }; +#endif /* __APPLE_API_UNSTABLE */ /* * Following structure necessary for 4.3 compatibility; @@ -162,7 +169,7 @@ struct ortentry { #define RTF_DYNAMIC 0x10 /* created dynamically (by redirect) */ #define RTF_MODIFIED 0x20 /* modified dynamically (by redirect) */ #define RTF_DONE 0x40 /* message confirmed */ -/* 0x80 unused */ +#define RTF_DELCLONE 0x80 /* delete cloned route */ #define RTF_CLONING 0x100 /* generate new routes on use */ #define RTF_XRESOLVE 0x200 /* external daemon resolves name */ #define RTF_LLINFO 0x400 /* generated by link layer (e.g. ARP) */ @@ -283,16 +290,19 @@ struct route_cb { }; #ifdef KERNEL +#ifndef __APPLE__ #define RTFREE(rt) \ - if ((rt)->rt_refcnt <= 1) \ - rtfree(rt); \ - else \ - (rt)->rt_refcnt--; -#define RTHOLD(rt) { \ - if (++(rt)->rt_refcnt <= 0) \ - panic("RTHOLD"); \ -} + do { \ + if ((rt)->rt_refcnt <= 1) \ + rtfree(rt); \ + else \ + (rt)->rt_refcnt--; \ + } while (0) +#else +#define RTFREE(rt) rtfree(rt) +#endif +#ifdef __APPLE_API_PRIVATE extern struct route_cb route_cb; extern struct radix_node_head *rt_tables[AF_MAX+1]; @@ -307,16 +317,25 @@ void rt_newmaddrmsg __P((int, struct ifmultiaddr *)); int rt_setgate __P((struct rtentry *, struct sockaddr *, struct sockaddr *)); void rtalloc __P((struct route *)); -void rtalloc_ign __P((struct route *, unsigned long)); +void rtalloc_ign __P((struct route *, u_long)); struct rtentry * - rtalloc1 __P((struct sockaddr *, int, unsigned long)); -void rtfree __P((struct rtentry *)); + rtalloc1 __P((struct sockaddr *, int, u_long)); +void rtfree __P((struct rtentry *)); +void rtref __P((struct rtentry *)); +/* + * rtunref will decrement the refcount, rtfree will decrement and free if + * the refcount has reached zero and the route is not up. + * Unless you have good reason to do otherwise, use rtfree. + */ +void rtunref __P((struct rtentry *)); +void rtsetifa __P((struct rtentry *, struct ifaddr *)); int rtinit __P((struct ifaddr *, int, int)); int rtioctl __P((int, caddr_t, struct proc *)); void rtredirect __P((struct sockaddr *, struct sockaddr *, struct sockaddr *, int, struct sockaddr *, struct rtentry **)); int rtrequest __P((int, struct sockaddr *, struct sockaddr *, struct sockaddr *, int, struct rtentry **)); +#endif /* __APPLE_API_PRIVATE */ #endif #endif diff --git a/bsd/net/rtsock.c b/bsd/net/rtsock.c index 0ff722bd2..5a8dbbe7a 100644 --- a/bsd/net/rtsock.c +++ b/bsd/net/rtsock.c @@ -66,10 +66,12 @@ #include #include #include +#include #include #include #include +#include MALLOC_DEFINE(M_RTABLE, "routetbl", "routing tables"); @@ -78,8 +80,6 @@ static struct sockaddr route_src = { 2, PF_ROUTE, }; static struct sockaddr sa_zero = { sizeof(sa_zero), AF_INET, }; static struct sockproto route_proto = { PF_ROUTE, }; - - struct walkarg { int w_tmemsize; int w_op, w_arg; @@ -166,9 +166,6 @@ rts_attach(struct socket *so, int proto, struct proc *p) case AF_NS: route_cb.ns_count++; break; - case AF_ISO: - route_cb.iso_count++; - break; } rp->rcb_faddr = &route_src; route_cb.any_count++; @@ -222,9 +219,6 @@ rts_detach(struct socket *so) case AF_NS: route_cb.ns_count--; break; - case AF_ISO: - route_cb.iso_count--; - break; } route_cb.any_count--; } @@ -359,9 +353,40 @@ route_output(m, so) case RTM_ADD: if (gate == 0) senderr(EINVAL); + +#ifdef __APPLE__ +/* XXX LD11JUL02 Special case for AOL 5.1.2 connectivity issue to AirPort BS (Radar 2969954) + * AOL is adding a circular route ("10.0.1.1/32 10.0.1.1") when establishing its ppp tunnel + * to the AP BaseStation by removing the default gateway and replacing it with their tunnel entry point. + * There is no apparent reason to add this route as there is a valid 10.0.1.1/24 route to the BS. + * That circular route was ignored on previous version of MacOS X because of a routing bug + * corrected with the merge to FreeBSD4.4 (a route generated from an RTF_CLONING route had the RTF_WASCLONED + * flag set but did not have a reference to the parent route) and that entry was left in the RT. This workaround is + * made in order to provide binary compatibility with AOL. + * If we catch a process adding a circular route with a /32 from the routing socket, we error it out instead of + * confusing the routing table with a wrong route to the previous default gateway + */ +{ + extern int check_routeselfref; +#define satosinaddr(sa) (((struct sockaddr_in *)sa)->sin_addr.s_addr) + + if (check_routeselfref && (dst && dst->sa_family == AF_INET) && + (netmask && satosinaddr(netmask) == INADDR_BROADCAST) && + (gate && satosinaddr(dst) == satosinaddr(gate))) { + log(LOG_WARNING, "route_output: circular route %ld.%ld.%ld.%ld/32 ignored\n", + (ntohl(satosinaddr(gate)>>24))&0xff, + (ntohl(satosinaddr(gate)>>16))&0xff, + (ntohl(satosinaddr(gate)>>8))&0xff, + (ntohl(satosinaddr(gate)))&0xff); + + senderr(EINVAL); + } +} +#endif error = rtrequest(RTM_ADD, dst, gate, netmask, rtm->rtm_flags, &saved_nrt); if (error == 0 && saved_nrt) { +#ifdef __APPLE__ /* * If the route request specified an interface with * IFA and/or IFP, we set the requested interface on @@ -391,12 +416,13 @@ route_output(m, so) */ rt_setif(saved_nrt, ifpaddr, ifaaddr, gate); +#endif rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, &saved_nrt->rt_rmx); saved_nrt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); saved_nrt->rt_rmx.rmx_locks |= (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); - saved_nrt->rt_refcnt--; + rtunref(saved_nrt); saved_nrt->rt_genmask = genmask; } break; @@ -406,7 +432,7 @@ route_output(m, so) rtm->rtm_flags, &saved_nrt); if (error == 0) { if ((rt = saved_nrt)) - rt->rt_refcnt++; + rtref(rt); goto report; } break; @@ -416,9 +442,9 @@ route_output(m, so) case RTM_LOCK: if ((rnh = rt_tables[dst->sa_family]) == 0) { senderr(EAFNOSUPPORT); - } else if (rt = (struct rtentry *) - rnh->rnh_lookup(dst, netmask, rnh)) - rt->rt_refcnt++; + } else if ((rt = (struct rtentry *) + rnh->rnh_lookup(dst, netmask, rnh)) != NULL) + rtref(rt); else senderr(ESRCH); switch(rtm->rtm_type) { @@ -471,10 +497,22 @@ route_output(m, so) if ((rt->rt_flags & RTF_GATEWAY) && !gate) gate = rt->rt_gateway; +#ifdef __APPLE__ + /* + * On Darwin, we call rt_setif which contains the + * equivalent to the code found at this very spot + * in BSD. + */ rt_setif(rt, ifpaddr, ifaaddr, gate); +#endif rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, &rt->rt_rmx); +#ifndef __APPLE__ + /* rt_setif, called above does this for us on darwin */ + if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) + rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, gate); +#endif if (genmask) rt->rt_genmask = genmask; /* @@ -518,13 +556,19 @@ flush: } if (rtm) { m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm); + if (m->m_pkthdr.len < rtm->rtm_msglen) { + m_freem(m); + m = NULL; + } else if (m->m_pkthdr.len > rtm->rtm_msglen) + m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len); 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 (m) + raw_input(m, &route_proto, &route_src, &route_dst); if (rp) rp->rcb_proto.sp_family = PF_ROUTE; } @@ -580,13 +624,11 @@ rt_setif(rt, Ifpaddr, Ifaaddr, Gate) if (oifa && oifa->ifa_rtrequest) oifa->ifa_rtrequest(RTM_DELETE, rt, Gate); - IFAFREE(rt->rt_ifa); - rt->rt_ifa = ifa; - ifa->ifa_refcnt++; + rtsetifa(rt, ifa); rt->rt_ifp = ifp; rt->rt_rmx.rmx_mtu = ifp->if_mtu; if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) - rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, Gate); + rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, Gate); } else goto call_ifareq; return; @@ -658,9 +700,6 @@ rt_msg1(type, rtinfo) register struct sockaddr *sa; int len, dlen; - m = m_gethdr(M_DONTWAIT, MT_DATA); - if (m == 0) - return (m); switch (type) { case RTM_DELADDR: @@ -680,8 +719,18 @@ rt_msg1(type, rtinfo) default: len = sizeof(struct rt_msghdr); } - if (len > MHLEN) + if (len > MCLBYTES) panic("rt_msg1"); + m = m_gethdr(M_DONTWAIT, MT_DATA); + if (m && len > MHLEN) { + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) { + m_free(m); + m = NULL; + } + } + if (m == 0) + return (m); m->m_pkthdr.len = m->m_len = len; m->m_pkthdr.rcvif = 0; rtm = mtod(m, struct rt_msghdr *); @@ -914,7 +963,10 @@ rt_newmaddrmsg(cmd, ifma) bzero((caddr_t)&info, sizeof(info)); ifaaddr = ifma->ifma_addr; - ifpaddr = ifp->if_addrhead.tqh_first->ifa_addr; + if (ifp && ifp->if_addrhead.tqh_first) + ifpaddr = ifp->if_addrhead.tqh_first->ifa_addr; + else + ifpaddr = NULL; /* * If a link-layer address is present, present it as a ``gateway'' * (similarly to how ARP entries, e.g., are presented). @@ -998,6 +1050,10 @@ sysctl_iflist(af, w) while ((ifa = ifa->ifa_link.tqe_next) != 0) { if (af && af != ifa->ifa_addr->sa_family) continue; +#ifndef __APPLE__ + if (curproc->p_prison && prison_if(curproc, ifa->ifa_addr)) + continue; +#endif ifaaddr = ifa->ifa_addr; netmask = ifa->ifa_netmask; brdaddr = ifa->ifa_dstaddr; @@ -1020,7 +1076,6 @@ sysctl_iflist(af, w) return (0); } - static int sysctl_rtsock SYSCTL_HANDLER_ARGS { @@ -1066,18 +1121,15 @@ sysctl_rtsock SYSCTL_HANDLER_ARGS SYSCTL_NODE(_net, PF_ROUTE, routetable, CTLFLAG_RD, sysctl_rtsock, ""); - - /* * Definitions of protocols supported in the ROUTE domain. */ struct domain routedomain; /* or at least forward */ - static struct protosw routesw[] = { { SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR, - 0, route_output, raw_ctlinput, 0, + 0, route_output, raw_ctlinput, 0, 0, raw_init, 0, 0, 0, 0, &route_usrreqs, 0, 0 @@ -1090,6 +1142,3 @@ struct domain routedomain = DOMAIN_SET(route); -#if MIP6 -#include -#endif diff --git a/bsd/net/slcompress.c b/bsd/net/slcompress.c index 7875c4e9d..47108b410 100644 --- a/bsd/net/slcompress.c +++ b/bsd/net/slcompress.c @@ -52,6 +52,7 @@ * SUCH DAMAGE. * * @(#)slcompress.c 8.2 (Berkeley) 4/16/94 + * $FreeBSD: src/sys/net/slcompress.c,v 1.16 1999/12/29 04:38:37 peter Exp $ */ /* @@ -167,6 +168,17 @@ sl_compress_init(comp, max_state) } \ } +/* + * Attempt to compress an outgoing TCP packet and return the type of + * the result. The caller must have already verified that the protocol + * is TCP. The first mbuf must contain the complete IP and TCP headers, + * and "ip" must be == mtod(m, struct ip *). "comp" supplies the + * compression state, and "compress_cid" tells us whether it is OK + * to leave out the CID field when feasible. + * + * The caller is responsible for adjusting m->m_pkthdr.len upon return, + * if m is an M_PKTHDR mbuf. + */ u_int sl_compress_tcp(m, ip, comp, compress_cid) struct mbuf *m; diff --git a/bsd/net/slcompress.h b/bsd/net/slcompress.h index 742a22a22..b784ad8db 100644 --- a/bsd/net/slcompress.h +++ b/bsd/net/slcompress.h @@ -55,15 +55,17 @@ * * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: * - Initial distribution. + * $FreeBSD: src/sys/net/slcompress.h,v 1.14.2.1 2000/05/05 13:37:06 jlemon Exp $ */ #ifndef _NET_SLCOMPRESS_H_ #define _NET_SLCOMPRESS_H_ +#include #include #define MAX_STATES 16 /* must be > 2 and < 256 */ -#define MAX_HDR MLEN /* XXX 4bsd-ism: should really be 128 */ +#define MAX_HDR 128 /* * Compressed packet format: @@ -174,6 +176,7 @@ struct slcompress { /* flag values */ #define SLF_TOSS 1 /* tossing rcvd frames because of input err */ +#if !defined(KERNEL) || defined(__APPLE_API_PRIVATE) void sl_compress_init __P((struct slcompress *, int)); u_int sl_compress_tcp __P((struct mbuf *, struct ip *, struct slcompress *, int)); @@ -181,4 +184,5 @@ int sl_uncompress_tcp __P((u_char **, int, u_int, struct slcompress *)); int sl_uncompress_tcp_core __P((u_char *, int, int, u_int, struct slcompress *, u_char **, u_int *)); +#endif /* !KERNEL || __APPLE_API_PRIVATE */ #endif /* !_NET_SLCOMPRESS_H_ */ diff --git a/bsd/net/slip.h b/bsd/net/slip.h index b46086862..7a8c06c66 100644 --- a/bsd/net/slip.h +++ b/bsd/net/slip.h @@ -52,10 +52,12 @@ * SUCH DAMAGE. * * @(#)slip.h 8.1 (Berkeley) 2/12/94 + * $FreeBSD: src/sys/net/slip.h,v 1.9 1999/08/28 00:48:29 peter Exp $ */ #ifndef _NET_SLIP_H_ #define _NET_SLIP_H_ +#include /* Ioctls operating on SLIP ttys. */ #define SLIOCGUNIT _IOR('t', 88, int) /* get slip unit number */ diff --git a/bsd/net/tokendefs.h b/bsd/net/tokendefs.h deleted file mode 100644 index 2e0be8ead..000000000 --- a/bsd/net/tokendefs.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* Copyright (c) 1991 NeXT Computer, Inc. All rights reserved. - * - * tokendefs.h - Token-Ring MAC header definitions. - * - * HISTORY - * 8-Oct-92 Joel Greenblatt at NeXT - * created - */ -#ifndef _NET_TOKENDEFS_H_ -#define _NET_TOKENDEFS_H_ - - -#include - -/* - * Token ring address - 6 octets - */ -#define NUM_TR_ADDR_BYTES 6 - -struct token_addr { - u_char token_addr_octet[NUM_TR_ADDR_BYTES]; -}; - -#define ta_byte token_addr_octet - -typedef struct token_addr token_addr_t; - -/* - * MAC header size - */ -#define MAC_HDR_MIN (1+1+6+6) /* MAC hdr size w/o ri field */ -#define MAC_HDR_MAX (MAC_HDR_MIN + RISIZE) /* MAC hdr size w/max ri */ - -/* - * The maximum size of the MAC information field as spec'd by ISO 8802/5. - */ -#define MAC_INFO_4MB 4472 /* max size of mac info field -- 4 Mbs */ -#define MAC_INFO_16MB 17800 /* max size of mac info field -- 16 Mbs */ - -/* - * Maximum DMA packet sizes for 4 & 16 Mbit assuming no CRC. - */ -#define MAC_DMA_MAX_4MB (MAC_HDR_MAX + MAC_INFO_4MB) -#define MAC_DMA_MAX_16MB (MAC_HDR_MAX + MAC_INFO_16MB) - -/* - * Routing control field. - */ -typedef struct { - -#if __BIG_ENDIAN__ - unsigned char bcast : 3, /* broadcast */ - len : 5; /* length */ - unsigned char dir : 1, /* direction */ - longf : 3, /* longest frame */ - rsrvd : 4; /* reserved */ - -#elif __LITTLE_ENDIAN__ - unsigned char len : 5, /* length */ - bcast : 3; /* broadcast */ - unsigned char rsrvd : 4, /* reserved */ - longf : 3, /* longest frame */ - dir : 1; /* direction */ -#else - error -#endif -} routing_ctl_t; - -/* bcast field ... */ -#define BI_SPECIFIC 0 /* b'0xx': non-broadcast (specific route) */ -#define BI_AR_BCAST 4 /* b'10x': all-routes broadcast */ -#define BI_SR_BCAST 6 /* b'11x': single-route broadcast */ - -/* - * longf field - */ -#define LF_S516 0 -#define LF_S1500 1 -#define LF_S2052 2 -#define LF_S4472 3 -#define LF_S8144 4 -#define LF_S11407 5 -#define LF_S17800 6 -#define LF_BCAST 7 /* All-routes broadcast */ - -#define LFB_4MB LF_S4472 /* encoded max info -- 4 Mb */ -#define LFB_16MB LF_S17800 /* encoded max info -- 16 Mb */ - -/* - * Source Routing field (2-18 bytes, must be even) - */ - -#define RISIZE 18 /* max size (bytes) of 802.5 routing field */ - -typedef struct { - routing_ctl_t rc; - u_char sn[RISIZE-sizeof(routing_ctl_t)]; -} sroute_t; - -/* - * Token Ring MAC header (IEEE 802.5, ISO 8802/5) - */ - -#define TR_DA_SIZE 6 - -typedef struct { - u_char ac; /* PPPTMRRR; PPP = token priority */ - u_char fc; /* FFrrZZZZ; FF = frame type */ -#define TR_FC_MASK 0xc0 /* mask for frame-type */ -#define TR_FC_MAC 0x00 /* frame-type = mac frame */ -#define TR_FC_DATA 0x40 /* frame-type = non-mac (data frame) */ - u_char da[TR_DA_SIZE]; /* destination address */ - u_char sa[TR_DA_SIZE]; /* source address */ -#define TR_RII 0x80 /* routing info indicator bit */ - sroute_t ri; /* routing information field */ -} tokenHeader_t; - -/* - * token-ring netif definitions - */ -#define IFTYPE_TOKENRING "4/16Mb Token-Ring" /* netif type-string */ - -/* - * Error codes - */ -#define TRINGDOWN ENETDOWN /* interface down */ -#define TNOBUFS ENOBUFS /* transmit queue full error */ -#define TBADDA EINVAL /* bad dest addr */ -#define TBADFSIZE EMSGSIZE /* bad frame size */ - -#endif /* ! _NET_TOKENDEFS_H_ */ diff --git a/bsd/net/tokensr.h b/bsd/net/tokensr.h deleted file mode 100644 index 8e9909acb..000000000 --- a/bsd/net/tokensr.h +++ /dev/null @@ -1,372 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* Copyright (c) 1993 NeXT Computer, Inc. All rights reserved. - * - * tokensr.h - Token-ring IEEE 802.5 source routing utility functions. - * - * We currently make these functions static inlines. These should - * be considered for movement to a library and made public (after - * sanitizing API). - * - * HISTORY - * - * 22-Jul-94 John Immordino (jimmord) at NeXT - * Converted static array of source routes to a hash table. - * Loosely coupled hash table entries to arp table entries, ie. - * when hash table is full, delete the first entry for which there - * is no arp entry before inserting the next source route. - * - * 26-Apr-94 John Immordino (jimmord) at NeXT - * Cleaned up. Fixed byte-swap problems, converted all addresses to - * character arrays, etc. - * - * 07-Apr-93 Joel Greenblatt at NeXT - * Created - * - */ - -#ifdef DRIVER_PRIVATE - -#ifndef _TOKENSR_ -#define _TOKENSR_ - -#include -#include -#include -#include -#include -#include -#include /* Not an Obj-C header */ - -/* - * Virtual driver parameters - * Used by if_vtrXX modules - */ -typedef struct { - int vunit; - int vflags; - int vmtu; - int vtokpri; -} vparms_t; - - -/* - * Source routing table entry - * Note: ipAddr must be the first element in order for our hash table - * code to work properly. - */ -typedef struct { - unsigned long ipAddr; /* IP address of this entry - */ - /* needed for our temporary */ - /* arp table lookup scheme */ - sroute_t ri; /* routing information field */ -} srtable_t; - - -/* - * Encoded source-routing broadcast type (used as parameter to - * source routing routines). - */ -typedef enum { - SRB_OFF, /* no source-route broadcast */ - SRB_AR, /* all-routes broadcast */ - SRB_SR, /* single-route broadcast */ - SRB_INVALID /* invalid entry */ -} srbcast_t; - -/* - * ARP code taken from bsd/netinet/if_ether.c. Need this in order - * to perform lookups of IP addresses to determine which source route - * entry to remove from the table. The first source route entry without - * a corresponding ARP entry will be removed. - */ -#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 - -extern struct arptab arptab[]; - -#define ARPTAB_HASH(a) \ - ((u_long)(a) % ARPTAB_NB) - -/* - * Change to permit multiple heterogenous interfaces to co-exist. - */ -#define ARPTAB_LOOK(at,addr,ifp) { \ - register n; \ - at = &arptab[ARPTAB_HASH(addr) * ARPTAB_BSIZ]; \ - for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) \ - if (at->at_iaddr.s_addr == addr && \ - (!(ifp) || at->at_if == (ifp))) \ - break; \ - if (n >= ARPTAB_BSIZ) \ - at = 0; \ -} - - -/* - * Initialize callers source routing table. - */ -static __inline__ -void init_src_routing(NXHashTable **sourceRouteTable) -{ - extern NXHashTablePrototype SRTablePrototype; - *sourceRouteTable = NXCreateHashTable(SRTablePrototype, 0, NULL); -} - -/* - * Search for a source route (given a destination address). - */ -static __inline__ -sroute_t *find_sr(NXHashTable *sourceRouteTable, unsigned long idst) -{ - srtable_t *sourceRouteEntry = NXHashGet(sourceRouteTable, - (const void *)&idst); - if (sourceRouteEntry) { - return &sourceRouteEntry->ri; - } - return NULL; -} - -/* - * Add an entry to the callers source routing table. - */ -static __inline__ -void add_sr(netif_t netif, NXHashTable *sourceRouteTable, unsigned long ipAddr, - sroute_t *rip, unsigned long srLimit) -{ - srtable_t *sourceRouteEntry; - struct ifnet *ifp = (struct ifnet *)netif; - - if ((rip->rc.len > 18)|| (rip->rc.len < 2) || (rip->rc.len & 1)) - return; - - /* - * See if the entry is already in the table - */ - sourceRouteEntry = NXHashGet(sourceRouteTable,&ipAddr); - if (sourceRouteEntry) { - bcopy(rip, &sourceRouteEntry->ri, rip->rc.len); - sourceRouteEntry->ri.rc.bcast = 0; /* make non-bcast */ - sourceRouteEntry->ri.rc.dir = ~sourceRouteEntry->ri.rc.dir; - return; - } - - /* - * See if there's room in the table for another entry. - */ - if (NXCountHashTable(sourceRouteTable) >= srLimit) { - BOOL dumpedOne = NO; - NXHashState state = NXInitHashState(sourceRouteTable); - - /* - * Need to delete an entry. - */ - while (NXNextHashState(sourceRouteTable, &state, - (void **)&sourceRouteEntry)) { - - struct arptab *at; - - /* - * Look for an entry without a corresponding entry in the - * arp table. - */ - ARPTAB_LOOK(at, sourceRouteEntry->ipAddr, ifp); - if (at == NULL) { - /* - * Found one - try to remove it - */ - sourceRouteEntry = - NXHashRemove(sourceRouteTable, - (const void *)&sourceRouteEntry->ipAddr); - if (sourceRouteEntry) { - kfree(sourceRouteEntry,sizeof(srtable_t)); - dumpedOne = YES; - break; - } - } - } - if (dumpedOne == NO) { - printf("add_sr: source route table overflow\n"); - return; - } - } - - sourceRouteEntry = (srtable_t *)kalloc(sizeof(srtable_t)); - - sourceRouteEntry->ipAddr = ipAddr; - bcopy(rip, &sourceRouteEntry->ri, rip->rc.len); - sourceRouteEntry->ri.rc.bcast = 0; /* make non-bcast */ - sourceRouteEntry->ri.rc.dir = ~sourceRouteEntry->ri.rc.dir; - - sourceRouteEntry = - NXHashInsert(sourceRouteTable,(const void *)&sourceRouteEntry->ipAddr); - if (sourceRouteEntry) /* shouldn't happen */ - kfree(sourceRouteEntry,sizeof(srtable_t)); -} - -/* - * Find & return the source route to the callers address. - */ -static __inline__ -void get_src_route(NXHashTable *sourceRouteTable, unsigned long idst, - unsigned char *da, tokenHeader_t *th) -{ - sroute_t *sourceRoute; - - if (da[0] & 0x80) - return; /* don't handle group addresses */ - - /* - * Find source route in srtable and copy to caller's - * tokenHeader_t (or turn off sri bit). - */ - sourceRoute = find_sr(sourceRouteTable, idst); - if (sourceRoute) { - bcopy(sourceRoute, &th->ri, sourceRoute->rc.len); - th->sa[0] |= TR_RII; - } - else - th->sa[0] &= ~TR_RII; /* turn off source routing bit */ -} - -/* - * Save the source route in the callers MAC header. - */ -static __inline__ -void save_src_route(netif_t netif, NXHashTable *sourceRouteTable, - unsigned long ipAddr, tokenHeader_t *th, unsigned long srLimit) -{ - /* - * If frame has a routing field > 2 then save it (i.e. it's been - * thru at least one bridge). - */ - if ((th->sa[0] & TR_RII) && (th->ri.rc.len > 2)) - add_sr(netif, sourceRouteTable, ipAddr, &th->ri, srLimit); -} - - -/* - * Returns length of the source routing field in callers MAC header. - * Returns -1 if the header is invalid. - */ -static __inline__ -int get_ri_len(tokenHeader_t *th) -{ - int ri_len = 0; - sroute_t *rif = (sroute_t *)&th->ri; - - if (th->sa[0] & 0x80) { - ri_len = (int)rif->rc.len; - if ((ri_len & 1) || (ri_len < 2) || (ri_len > 18)) { - ri_len = -1; - } - } - return ri_len; -} - -/* - * Returns the length of an 802.5 MAC header (including routing field). - */ -static __inline__ -int get_8025_hdr_len(tokenHeader_t *th) -{ - int ri_len; - - ri_len = get_ri_len(th); - if (ri_len < 0) - return ri_len; // bad header - - return ri_len + MAC_HDR_MIN; -} - -/* - * Returns 1 if mac address is any type of broadcast, zero otherwise. - */ -static __inline__ -int check_mac_bcast(tokenHeader_t *th) -{ - if (th->da[0] & 0x80) - return 1; // group address (I/G bit) - return 0; -} - -/* - * Build a broadcast routing field in the callers MAC header. - */ -static __inline__ -void make_sr_bcast(tokenHeader_t *th, srbcast_t type) -{ - if ((type == SRB_OFF) || (type >= SRB_INVALID)) { - th->sa[0] &= ~TR_RII; - return; - } - - th->sa[0] |= TR_RII; /* turn on rii bit to ind. src rtng field */ - - /* - * Build the routing control field for the requested - * broadcast type. - */ - if (type == SRB_AR) - th->ri.rc.bcast = BI_AR_BCAST; - else - th->ri.rc.bcast = BI_SR_BCAST; - - th->ri.rc.len = 2; - th->ri.rc.dir = 0; - th->ri.rc.longf = LF_BCAST; - th->ri.rc.rsrvd = 0; -} - -/* - * Make the callers MAC header a reply to sender. - */ -static __inline__ -void make_mac_reply(tokenHeader_t *th) -{ - - /* - * Copy source address to destination address. Turn off RII bit in - * the destination address. - */ - bcopy(th->sa, th->da, sizeof(th->da)); - th->da[0] &= ~TR_RII; - - /* - * Convert the source routing field to a reply (flip direction - * bit & turn off broadcast bits). - */ - if (th->sa[0] & TR_RII) { - th->ri.rc.dir = ~th->ri.rc.dir; - th->ri.rc.bcast = 0; - } -} - - -#endif /* _TOKENSR_ */ - -#endif /* DRIVER_PRIVATE */ diff --git a/bsd/net/zlib.c b/bsd/net/zlib.c index 8ae3ac084..948f9298d 100644 --- a/bsd/net/zlib.c +++ b/bsd/net/zlib.c @@ -31,27 +31,16 @@ * - added inflateIncomp and deflateOutputPending * - allow strm->next_out to be NULL, meaning discard the output * - */ - -/* - * ==FILEVERSION 971210== - * - * This marker is used by the Linux installation script to determine - * whether an up-to-date version of this file is already installed. + * $FreeBSD: src/sys/net/zlib.c,v 1.10 1999/12/29 04:38:38 peter Exp $ */ #define NO_DUMMY_DECL #define NO_ZCFUNCS #define MY_ZCALLOC -#if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL)) -#define inflate inflate_ppp /* FreeBSD already has an inflate :-( */ -#endif - - /* +++ zutil.h */ /* zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995-1996 Jean-loup Gailly. + * Copyright (C) 1995-2002 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -60,31 +49,46 @@ subject to change. Applications should only use zlib.h. */ -/* From: zutil.h,v 1.16 1996/07/24 13:41:13 me Exp $ */ +/* @(#) $Id: zlib.c,v 1.8 2002/03/29 03:16:07 lindak Exp $ */ #ifndef _Z_UTIL_H #define _Z_UTIL_H - +#ifdef KERNEL #include +#else +#include "zlib.h" +#endif - -#if defined(KERNEL) +#ifdef KERNEL /* Assume this is a *BSD or SVR4 kernel */ -//#include +#include #include -//#include +#include # define HAVE_MEMCPY # define memcpy(d, s, n) bcopy((s), (d), (n)) # define memset(d, v, n) bzero((d), (n)) # define memcmp bcmp +#else +#if defined(__KERNEL__) +/* Assume this is a Linux kernel */ +#include +#define HAVE_MEMCPY + +#else /* not kernel */ #ifdef STDC -//# include -//# include +# include +# include +# include #endif - -#endif /* _KERNEL || KERNEL */ +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif +#endif /* __KERNEL__ */ +#endif /* KERNEL */ #ifndef local # define local static @@ -135,8 +139,14 @@ extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ #ifdef MSDOS # define OS_CODE 0x00 -# ifdef __TURBOC__ -# include +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif # else /* MSC or DJGPP */ # include # endif @@ -152,7 +162,7 @@ extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ #if defined(VAXC) || defined(VMS) # define OS_CODE 0x02 -# define FOPEN(name, mode) \ +# define F_OPEN(name, mode) \ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") #endif @@ -164,8 +174,15 @@ extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ # define OS_CODE 0x05 #endif -#ifdef MACOS +#if defined(MACOS) || defined(TARGET_OS_MAC) # define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif #endif #ifdef __50SERIES /* Prime/PRIMOS */ @@ -180,14 +197,19 @@ extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ # define fdopen(fd,mode) NULL /* No fdopen() */ #endif +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# define fdopen(fd,type) _fdopen(fd,type) +#endif + + /* Common defaults */ #ifndef OS_CODE # define OS_CODE 0x03 /* assume Unix */ #endif -#ifndef FOPEN -# define FOPEN(name, mode) fopen((name), (mode)) +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) #endif /* functions */ @@ -202,9 +224,10 @@ extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ #if defined(pyr) # define NO_MEMCPY #endif -#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(_MSC_VER) +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) /* Use our own functions for small and medium model with MSC <= 5.0. * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. */ # define NO_MEMCPY #endif @@ -222,24 +245,22 @@ extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ # define zmemzero(dest, len) memset(dest, 0, len) # endif #else - extern void zmemcpy OF((Bytef* dest, Bytef* source, uInt len)); - extern int zmemcmp OF((Bytef* s1, Bytef* s2, uInt len)); + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); extern void zmemzero OF((Bytef* dest, uInt len)); #endif /* Diagnostic functions */ #ifdef DEBUG_ZLIB # include -# ifndef verbose -# define verbose 0 -# endif + extern int z_verbose; extern void z_error OF((char *m)); # define Assert(cond,msg) {if(!(cond)) z_error(msg);} -# define Trace(x) fprintf x -# define Tracev(x) {if (verbose) fprintf x ;} -# define Tracevv(x) {if (verbose>1) fprintf x ;} -# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} -# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} #else # define Assert(cond,msg) # define Trace(x) @@ -250,8 +271,8 @@ extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ #endif -typedef uLong (*check_func) OF((uLong check, const Bytef *buf, uInt len)); - +typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf, + uInt len)); voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); void zcfree OF((voidpf opaque, voidpf ptr)); @@ -265,7 +286,7 @@ void zcfree OF((voidpf opaque, voidpf ptr)); /* +++ deflate.h */ /* deflate.h -- internal compression state - * Copyright (C) 1995-1996 Jean-loup Gailly + * Copyright (C) 1995-2002 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -274,7 +295,7 @@ void zcfree OF((voidpf opaque, voidpf ptr)); subject to change. Applications should only use zlib.h. */ -/* From: deflate.h,v 1.10 1996/07/02 12:41:00 me Exp $ */ +/* @(#) $Id: zlib.c,v 1.8 2002/03/29 03:16:07 lindak Exp $ */ #ifndef _DEFLATE_H #define _DEFLATE_H @@ -496,12 +517,12 @@ typedef struct deflate_state { ulg opt_len; /* bit length of current block with optimal trees */ ulg static_len; /* bit length of current block with static trees */ - ulg compressed_len; /* total bit length of compressed file */ uInt matches; /* number of string matches in current block */ int last_eob_len; /* bit length of EOB code for last block */ #ifdef DEBUG_ZLIB - ulg bits_sent; /* bit length of the compressed data */ + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ #endif ush bi_buf; @@ -534,19 +555,59 @@ typedef struct deflate_state { /* in trees.c */ void _tr_init OF((deflate_state *s)); int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); -ulg _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, int eof)); void _tr_align OF((deflate_state *s)); void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, int eof)); -void _tr_stored_type_only OF((deflate_state *)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG_ZLIB +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif #endif /* --- deflate.h */ /* +++ deflate.c */ /* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1995-1996 Jean-loup Gailly. + * Copyright (C) 1995-2002 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -594,11 +655,12 @@ void _tr_stored_type_only OF((deflate_state *)); * */ -/* From: deflate.c,v 1.15 1996/07/24 13:40:58 me Exp $ */ +/* @(#) $Id: zlib.c,v 1.8 2002/03/29 03:16:07 lindak Exp $ */ /* #include "deflate.h" */ -char deflate_copyright[] = " deflate 1.0.4 Copyright 1995-1996 Jean-loup Gailly "; +const char deflate_copyright[] = + " deflate 1.1.4 Copyright 1995-2002 Jean-loup Gailly "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -626,7 +688,7 @@ local block_state deflate_slow OF((deflate_state *s, int flush)); local void lm_init OF((deflate_state *s)); local void putShortMSB OF((deflate_state *s, uInt b)); local void flush_pending OF((z_streamp strm)); -local int read_buf OF((z_streamp strm, charf *buf, unsigned size)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); #ifdef ASMV void match_init OF((void)); /* asm code initialization */ uInt longest_match OF((deflate_state *s, IPos cur_match)); @@ -669,7 +731,7 @@ typedef struct config_s { compress_func func; } config; -local config configuration_table[10] = { +local const config configuration_table[10] = { /* good lazy nice chain */ /* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ /* 1 */ {4, 4, 8, 4, deflate_fast}, /* maximum speed, no lazy matches */ @@ -708,14 +770,23 @@ struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ * Insert string str in the dictionary and set match_head to the previous head * of the hash chain (the most recent string with same hash key). Return * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. * IN assertion: all calls to to INSERT_STRING are made with consecutive * input characters and the first MIN_MATCH bytes of str are valid * (except for the last MIN_MATCH-1 bytes of the input file). */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else #define INSERT_STRING(s, str, match_head) \ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \ s->head[s->ins_h] = (Pos)(str)) +#endif /* =========================================================================== * Initialize the hash table (avoiding 64K overflow for 16 bit systems). @@ -723,10 +794,10 @@ struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ */ #define CLEAR_HASH(s) \ s->head[s->hash_size-1] = NIL; \ - zmemzero((charf *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); /* ========================================================================= */ -int deflateInit_(strm, level, version, stream_size) +int ZEXPORT deflateInit_(strm, level, version, stream_size) z_streamp strm; int level; const char *version; @@ -738,7 +809,7 @@ int deflateInit_(strm, level, version, stream_size) } /* ========================================================================= */ -int deflateInit2_(strm, level, method, windowBits, memLevel, strategy, +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, version, stream_size) z_streamp strm; int level; @@ -751,7 +822,7 @@ int deflateInit2_(strm, level, method, windowBits, memLevel, strategy, { deflate_state *s; int noheader = 0; - static char* my_version = ZLIB_VERSION; + static const char* my_version = ZLIB_VERSION; ushf *overlay; /* We overlay pending_buf and d_buf+l_buf. This works since the average @@ -774,13 +845,16 @@ int deflateInit2_(strm, level, method, windowBits, memLevel, strategy, #endif if (level == Z_DEFAULT_COMPRESSION) level = 6; +#ifdef FASTEST + level = 1; +#endif if (windowBits < 0) { /* undocumented feature: suppress zlib header */ noheader = 1; windowBits = -windowBits; } if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || - windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + windowBits < 9 || windowBits > 15 || level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) { return Z_STREAM_ERROR; } @@ -826,7 +900,7 @@ int deflateInit2_(strm, level, method, windowBits, memLevel, strategy, } /* ========================================================================= */ -int deflateSetDictionary (strm, dictionary, dictLength) +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) z_streamp strm; const Bytef *dictionary; uInt dictLength; @@ -836,12 +910,10 @@ int deflateSetDictionary (strm, dictionary, dictLength) uInt n; IPos hash_head = 0; - if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL) - return Z_STREAM_ERROR; - - s = (deflate_state *) strm->state; - if (s->status != INIT_STATE) return Z_STREAM_ERROR; + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + ((deflate_state*)strm->state)->status != INIT_STATE) return Z_STREAM_ERROR; + s = (deflate_state*)strm->state; strm->adler = adler32(strm->adler, dictionary, dictLength); if (length < MIN_MATCH) return Z_OK; @@ -851,7 +923,7 @@ int deflateSetDictionary (strm, dictionary, dictLength) dictionary += dictLength - length; /* use the tail of the dictionary */ #endif } - zmemcpy((charf *)s->window, dictionary, length); + zmemcpy(s->window, dictionary, length); s->strstart = length; s->block_start = (long)length; @@ -869,7 +941,7 @@ int deflateSetDictionary (strm, dictionary, dictLength) } /* ========================================================================= */ -int deflateReset (strm) +int ZEXPORT deflateReset (strm) z_streamp strm; { deflate_state *s; @@ -899,7 +971,7 @@ int deflateReset (strm) } /* ========================================================================= */ -int deflateParams(strm, level, strategy) +int ZEXPORT deflateParams(strm, level, strategy) z_streamp strm; int level; int strategy; @@ -909,7 +981,7 @@ int deflateParams(strm, level, strategy) int err = Z_OK; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - s = (deflate_state *) strm->state; + s = (deflate_state*)strm->state; if (level == Z_DEFAULT_COMPRESSION) { level = 6; @@ -956,17 +1028,15 @@ local void putShortMSB (s, b) local void flush_pending(strm) z_streamp strm; { - deflate_state *s = (deflate_state *) strm->state; + deflate_state* s = (deflate_state*)strm->state; unsigned len = s->pending; if (len > strm->avail_out) len = strm->avail_out; if (len == 0) return; - if (strm->next_out != Z_NULL) { - zmemcpy(strm->next_out, s->pending_out, len); - strm->next_out += len; - } - s->pending_out += len; + zmemcpy(strm->next_out, s->pending_out, len); + strm->next_out += len; + s->pending_out += len; strm->total_out += len; strm->avail_out -= len; s->pending -= len; @@ -976,7 +1046,7 @@ local void flush_pending(strm) } /* ========================================================================= */ -int deflate (strm, flush) +int ZEXPORT deflate (strm, flush) z_streamp strm; int flush; { @@ -987,9 +1057,10 @@ int deflate (strm, flush) flush > Z_FINISH || flush < 0) { return Z_STREAM_ERROR; } - s = (deflate_state *) strm->state; + s = (deflate_state*)strm->state; - if ((strm->next_in == Z_NULL && strm->avail_in != 0) || + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || (s->status == FINISH_STATE && flush != Z_FINISH)) { ERR_RETURN(strm, Z_STREAM_ERROR); } @@ -1076,10 +1147,6 @@ int deflate (strm, flush) if (bstate == block_done) { if (flush == Z_PARTIAL_FLUSH) { _tr_align(s); - } else if (flush == Z_PACKET_FLUSH) { - /* Output just the 3-bit `stored' block type value, - but not a zero length. */ - _tr_stored_type_only(s); } else { /* FULL_FLUSH or SYNC_FLUSH */ _tr_stored_block(s, (char*)0, 0L, 0); /* For a full flush, this empty block will be recognized @@ -1113,15 +1180,15 @@ int deflate (strm, flush) } /* ========================================================================= */ -int deflateEnd (strm) +int ZEXPORT deflateEnd (strm) z_streamp strm; { + deflate_state* s; int status; - deflate_state *s; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - s = (deflate_state *) strm->state; + s = (deflate_state*)strm->state; status = s->status; if (status != INIT_STATE && status != BUSY_STATE && status != FINISH_STATE) { @@ -1142,25 +1209,33 @@ int deflateEnd (strm) /* ========================================================================= * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). */ -int deflateCopy (dest, source) +int ZEXPORT deflateCopy (dest, source) z_streamp dest; z_streamp source; { +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else deflate_state *ds; deflate_state *ss; ushf *overlay; - if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { return Z_STREAM_ERROR; - ss = (deflate_state *) source->state; + } - zmemcpy(dest, source, sizeof(*dest)); + ss = (deflate_state*)source->state; + + *dest = *source; ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); if (ds == Z_NULL) return Z_MEM_ERROR; dest->state = (struct internal_state FAR *) ds; - zmemcpy(ds, ss, sizeof(*ds)); + *ds = *ss; ds->strm = dest; ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); @@ -1174,7 +1249,7 @@ int deflateCopy (dest, source) deflateEnd (dest); return Z_MEM_ERROR; } - /* ??? following zmemcpy doesn't work for 16-bit MSDOS */ + /* following zmemcpy do not work for 16-bit MSDOS */ zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); @@ -1189,18 +1264,7 @@ int deflateCopy (dest, source) ds->bl_desc.dyn_tree = ds->bl_tree; return Z_OK; -} - -/* =========================================================================== - * Return the number of bytes of output which are immediately available - * for output from the decompressor. - */ -int deflateOutputPending (strm) - z_streamp strm; -{ - if (strm == Z_NULL || strm->state == Z_NULL) return 0; - - return ((deflate_state *)(strm->state))->pending; +#endif } /* =========================================================================== @@ -1212,7 +1276,7 @@ int deflateOutputPending (strm) */ local int read_buf(strm, buf, size) z_streamp strm; - charf *buf; + Bytef *buf; unsigned size; { unsigned len = strm->avail_in; @@ -1222,7 +1286,7 @@ local int read_buf(strm, buf, size) strm->avail_in -= len; - if (!((deflate_state *)(strm->state))->noheader) { + if (!((deflate_state*)strm->state)->noheader) { strm->adler = adler32(strm->adler, strm->next_in, len); } zmemcpy(buf, strm->next_in, len); @@ -1273,6 +1337,7 @@ local void lm_init (s) /* For 80x86 and 680x0, an optimized version will be provided in match.asm or * match.S. The code will be functionally equivalent. */ +#ifndef FASTEST local uInt longest_match(s, cur_match) deflate_state *s; IPos cur_match; /* current match */ @@ -1407,9 +1472,67 @@ local uInt longest_match(s, cur_match) } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length != 0); - if ((uInt)best_len <= s->lookahead) return best_len; + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; return s->lookahead; } + +#else /* FASTEST */ +/* --------------------------------------------------------------------------- + * Optimized version for level == 1 only + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return len <= s->lookahead ? len : s->lookahead; +} +#endif /* FASTEST */ #endif /* ASMV */ #ifdef DEBUG_ZLIB @@ -1422,8 +1545,8 @@ local void check_match(s, start, match, length) int length; { /* check that the match is indeed a match */ - if (zmemcmp((charf *)s->window + match, - (charf *)s->window + start, length) != EQUAL) { + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { fprintf(stderr, " start %u, match %u, length %d\n", start, match, length); do { @@ -1476,8 +1599,7 @@ local void fill_window(s) */ } else if (s->strstart >= wsize+MAX_DIST(s)) { - zmemcpy((charf *)s->window, (charf *)s->window+wsize, - (unsigned)wsize); + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); s->match_start -= wsize; s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ s->block_start -= (long) wsize; @@ -1488,22 +1610,24 @@ local void fill_window(s) later. (Using level 0 permanently is not an optimal usage of zlib, so we don't care about this pathological case.) */ - n = s->hash_size; - p = &s->head[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - } while (--n); - - n = wsize; - p = &s->prev[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - /* If n is not on any hash chain, prev[n] is garbage but - * its value will never be used. - */ - } while (--n); + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif more += wsize; } if (s->strm->avail_in == 0) return; @@ -1521,8 +1645,7 @@ local void fill_window(s) */ Assert(more >= 2, "more < 2"); - n = read_buf(s->strm, (charf *)s->window + s->strstart + s->lookahead, - more); + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); s->lookahead += n; /* Initialize the hash value now that we have some input: */ @@ -1672,14 +1795,15 @@ local block_state deflate_fast(s, flush) if (s->match_length >= MIN_MATCH) { check_match(s, s->strstart, s->match_start, s->match_length); - bflush = _tr_tally(s, s->strstart - s->match_start, - s->match_length - MIN_MATCH); + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); s->lookahead -= s->match_length; /* Insert new strings in the hash table only if the match length * is not too large. This saves time but degrades compression. */ +#ifndef FASTEST if (s->match_length <= s->max_insert_length && s->lookahead >= MIN_MATCH) { s->match_length--; /* string at strstart already in hash table */ @@ -1691,7 +1815,9 @@ local block_state deflate_fast(s, flush) */ } while (--s->match_length != 0); s->strstart++; - } else { + } else +#endif + { s->strstart += s->match_length; s->match_length = 0; s->ins_h = s->window[s->strstart]; @@ -1706,7 +1832,7 @@ local block_state deflate_fast(s, flush) } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); - bflush = _tr_tally (s, 0, s->window[s->strstart]); + _tr_tally_lit (s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } @@ -1785,8 +1911,8 @@ local block_state deflate_slow(s, flush) check_match(s, s->strstart-1, s->prev_match, s->prev_length); - bflush = _tr_tally(s, s->strstart -1 - s->prev_match, - s->prev_length - MIN_MATCH); + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); /* Insert in hash table all strings up to the end of the match. * strstart-1 and strstart are already inserted. If there is not @@ -1812,7 +1938,8 @@ local block_state deflate_slow(s, flush) * is longer, truncate the previous match to a single literal. */ Tracevv((stderr,"%c", s->window[s->strstart-1])); - if (_tr_tally (s, 0, s->window[s->strstart-1])) { + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { FLUSH_BLOCK_ONLY(s, 0); } s->strstart++; @@ -1830,7 +1957,7 @@ local block_state deflate_slow(s, flush) Assert (flush != Z_NO_FLUSH, "no flush?"); if (s->match_available) { Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally (s, 0, s->window[s->strstart-1]); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); s->match_available = 0; } FLUSH_BLOCK(s, flush == Z_FINISH); @@ -1840,7 +1967,7 @@ local block_state deflate_slow(s, flush) /* +++ trees.c */ /* trees.c -- output deflated data using Huffman coding - * Copyright (C) 1995-1996 Jean-loup Gailly + * Copyright (C) 1995-2002 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -1870,7 +1997,9 @@ local block_state deflate_slow(s, flush) * Addison-Wesley, 1983. ISBN 0-201-06672-6. */ -/* From: trees.c,v 1.11 1996/07/24 13:41:06 me Exp $ */ +/* @(#) $Id: zlib.c,v 1.8 2002/03/29 03:16:07 lindak Exp $ */ + +/* #define GEN_TREES_H */ /* #include "deflate.h" */ @@ -1897,16 +2026,16 @@ local block_state deflate_slow(s, flush) #define REPZ_11_138 18 /* repeat a zero length 11-138 times (7 bits of repeat count) */ -local int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; -local int extra_dbits[D_CODES] /* extra bits for each distance code */ +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; -local int extra_blbits[BL_CODES]/* extra bits for each bit length code */ +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; -local uch bl_order[BL_CODES] +local const uch bl_order[BL_CODES] = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; /* The lengths of the bit length codes are sent in order of decreasing * probability, to avoid transmitting the lengths for unused bit length codes. @@ -1921,6 +2050,11 @@ local uch bl_order[BL_CODES] * Local data. These are initialized only once. */ +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + local ct_data static_ltree[L_CODES+2]; /* The static literal tree. Since the bit lengths are imposed, there is no * need for the L_CODES extra codes used during heap construction. However @@ -1933,13 +2067,13 @@ local ct_data static_dtree[D_CODES]; * 5 bits.) */ -local uch dist_code[512]; -/* distance codes. The first 256 values correspond to the distances +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances * 3 .. 258, the last 256 values correspond to the top 8 bits of * the 15 bit distances. */ -local uch length_code[MAX_MATCH-MIN_MATCH+1]; +uch _length_code[MAX_MATCH-MIN_MATCH+1]; /* length code for each normalized match length (0 == MIN_MATCH) */ local int base_length[LENGTH_CODES]; @@ -1948,9 +2082,142 @@ local int base_length[LENGTH_CODES]; local int base_dist[D_CODES]; /* First normalized distance for each code (0 = distance of 1) */ +#else +/* +++ trees.h */ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + +/* --- trees.h */ +#endif /* GEN_TREES_H */ + struct static_tree_desc_s { - ct_data *static_tree; /* static tree or NULL */ - intf *extra_bits; /* extra bits for each code or NULL */ + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ int extra_base; /* base index for extra_bits */ int elems; /* max number of elements in the tree */ int max_length; /* max bit length for the codes */ @@ -1963,7 +2230,7 @@ local static_tree_desc static_d_desc = {static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; local static_tree_desc static_bl_desc = -{(ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; /* =========================================================================== * Local (static) routines in this file. @@ -1989,23 +2256,20 @@ local void bi_flush OF((deflate_state *s)); local void copy_block OF((deflate_state *s, charf *buf, unsigned len, int header)); +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + #ifndef DEBUG_ZLIB # define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) /* Send a code of the given tree. c and tree must not have side effects */ #else /* DEBUG_ZLIB */ # define send_code(s, c, tree) \ - { if (verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ send_bits(s, tree[c].Code, tree[c].Len); } #endif -#define d_code(dist) \ - ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)]) -/* Mapping from a distance to a distance code. dist is the distance - 1 and - * must not have side effects. dist_code[256] and dist_code[257] are never - * used. - */ - /* =========================================================================== * Output a short LSB first on the stream. * IN assertion: there is enough room in pendingBuf. @@ -2063,16 +2327,17 @@ local void send_bits(s, value, length) #endif /* DEBUG_ZLIB */ +#ifndef MAX #define MAX(a,b) (a >= b ? a : b) +#endif /* the arguments must not have side effects */ /* =========================================================================== - * Initialize the various 'constant' tables. In a multi-threaded environment, - * this function may be called by two threads concurrently, but this is - * harmless since both invocations do exactly the same thing. + * Initialize the various 'constant' tables. */ local void tr_static_init() { +#if defined(GEN_TREES_H) || !defined(STDC) static int static_init_done = 0; int n; /* iterates over tree elements */ int bits; /* bit counter */ @@ -2084,12 +2349,19 @@ local void tr_static_init() if (static_init_done) return; + /* For some embedded targets, global variables are not initialized: */ + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; + /* Initialize the mapping length (0..255) -> length code (0..28) */ length = 0; for (code = 0; code < LENGTH_CODES-1; code++) { base_length[code] = length; for (n = 0; n < (1< dist code (0..29) */ dist = 0; for (code = 0 ; code < 16; code++) { base_dist[code] = dist; for (n = 0; n < (1< +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); } +#endif /* GEN_TREES_H */ /* =========================================================================== * Initialize the tree data structures for a new zlib stream. @@ -2146,8 +2484,6 @@ void _tr_init(s) { tr_static_init(); - s->compressed_len = 0L; - s->l_desc.dyn_tree = s->dyn_ltree; s->l_desc.stat_desc = &static_l_desc; @@ -2161,6 +2497,7 @@ void _tr_init(s) s->bi_valid = 0; s->last_eob_len = 8; /* enough lookahead for inflate */ #ifdef DEBUG_ZLIB + s->compressed_len = 0L; s->bits_sent = 0L; #endif @@ -2254,12 +2591,12 @@ local void gen_bitlen(s, desc) deflate_state *s; tree_desc *desc; /* the tree descriptor */ { - ct_data *tree = desc->dyn_tree; - int max_code = desc->max_code; - ct_data *stree = desc->stat_desc->static_tree; - intf *extra = desc->stat_desc->extra_bits; - int base = desc->stat_desc->extra_base; - int max_length = desc->stat_desc->max_length; + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; int h; /* heap index */ int n, m; /* iterate over the tree elements */ int bits; /* bit length */ @@ -2383,9 +2720,9 @@ local void build_tree(s, desc) deflate_state *s; tree_desc *desc; /* the tree descriptor */ { - ct_data *tree = desc->dyn_tree; - ct_data *stree = desc->stat_desc->static_tree; - int elems = desc->stat_desc->elems; + ct_data *tree = desc->dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; int n, m; /* iterate over heap elements */ int max_code = -1; /* largest code with non zero frequency */ int node; /* new node being created */ @@ -2633,23 +2970,13 @@ void _tr_stored_block(s, buf, stored_len, eof) int eof; /* true if this is the last block for a file */ { send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ +#ifdef DEBUG_ZLIB s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; s->compressed_len += (stored_len + 4) << 3; - +#endif copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ } -/* Send just the `stored block' type code without any length bytes or data. - */ -void _tr_stored_type_only(s) - deflate_state *s; -{ - send_bits(s, (STORED_BLOCK << 1), 3); - bi_windup(s); - s->compressed_len = (s->compressed_len + 3) & ~7L; -} - - /* =========================================================================== * Send one empty static block to give enough lookahead for inflate. * This takes 10 bits, of which 7 may remain in the bit buffer. @@ -2666,7 +2993,9 @@ void _tr_align(s) { send_bits(s, STATIC_TREES<<1, 3); send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG_ZLIB s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif bi_flush(s); /* Of the 10 bits for the empty block, we have already sent * (10 - bi_valid) bits. The lookahead for the last real code (before @@ -2676,7 +3005,9 @@ void _tr_align(s) if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { send_bits(s, STATIC_TREES<<1, 3); send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG_ZLIB s->compressed_len += 10L; +#endif bi_flush(s); } s->last_eob_len = 7; @@ -2684,10 +3015,9 @@ void _tr_align(s) /* =========================================================================== * Determine the best encoding for the current block: dynamic trees, static - * trees or store, and output the encoded block to the zip file. This function - * returns the total compressed length for the file so far. + * trees or store, and output the encoded block to the zip file. */ -ulg _tr_flush_block(s, buf, stored_len, eof) +void _tr_flush_block(s, buf, stored_len, eof) deflate_state *s; charf *buf; /* input block, or NULL if too old */ ulg stored_len; /* length of input block */ @@ -2734,25 +3064,6 @@ ulg _tr_flush_block(s, buf, stored_len, eof) opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ } - /* If compression failed and this is the first and last block, - * and if the .zip file can be seeked (to rewrite the local header), - * the whole file is transformed into a stored file: - */ -#ifdef STORED_FILE_OK -# ifdef FORCE_STORED_FILE - if (eof && s->compressed_len == 0L) { /* force stored file */ -# else - if (stored_len <= opt_lenb && eof && s->compressed_len==0L && seekable()) { -# endif - /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */ - if (buf == (charf*)0) error ("block vanished"); - - copy_block(s, buf, (unsigned)stored_len, 0); /* without header */ - s->compressed_len = stored_len << 3; - s->method = STORED; - } else -#endif /* STORED_FILE_OK */ - #ifdef FORCE_STORED if (buf != (char*)0) { /* force stored block */ #else @@ -2774,25 +3085,32 @@ ulg _tr_flush_block(s, buf, stored_len, eof) #endif send_bits(s, (STATIC_TREES<<1)+eof, 3); compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG_ZLIB s->compressed_len += 3 + s->static_len; +#endif } else { send_bits(s, (DYN_TREES<<1)+eof, 3); send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, max_blindex+1); compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG_ZLIB s->compressed_len += 3 + s->opt_len; +#endif } Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ init_block(s); if (eof) { bi_windup(s); +#ifdef DEBUG_ZLIB s->compressed_len += 7; /* align on byte boundary */ +#endif } Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, s->compressed_len-7*eof)); - - return s->compressed_len >> 3; } /* =========================================================================== @@ -2817,12 +3135,13 @@ int _tr_tally (s, dist, lc) (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); - s->dyn_ltree[length_code[lc]+LITERALS+1].Freq++; + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; s->dyn_dtree[d_code(dist)].Freq++; } +#ifdef TRUNCATE_BLOCK /* Try to guess if it is profitable to stop the current block here */ - if (s->level > 2 && (s->last_lit & 0xfff) == 0) { + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { /* Compute an upper bound for the compressed length */ ulg out_length = (ulg)s->last_lit*8L; ulg in_length = (ulg)((long)s->strstart - s->block_start); @@ -2837,6 +3156,7 @@ int _tr_tally (s, dist, lc) 100L - out_length*100L/in_length)); if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; } +#endif return (s->last_lit == s->lit_bufsize-1); /* We avoid equality with lit_bufsize because of wraparound at 64K * on 16 bit machines and because stored blocks are restricted to @@ -2866,7 +3186,7 @@ local void compress_block(s, ltree, dtree) Tracecv(isgraph(lc), (stderr," '%c' ", lc)); } else { /* Here, lc is the match length - MIN_MATCH */ - code = length_code[lc]; + code = _length_code[lc]; send_code(s, code+LITERALS+1, ltree); /* send the length code */ extra = extra_lbits[code]; if (extra != 0) { @@ -2987,15 +3307,15 @@ local void copy_block(s, buf, len, header) #ifdef DEBUG_ZLIB s->bits_sent += (ulg)len<<3; #endif - /* bundle up the put_byte(s, *buf++) calls */ - zmemcpy(&s->pending_buf[s->pending], buf, len); - s->pending += len; + while (len--) { + put_byte(s, *buf++); + } } /* --- trees.c */ /* +++ inflate.c */ /* inflate.c -- zlib interface to inflate modules - * Copyright (C) 1995-1996 Mark Adler + * Copyright (C) 1995-2002 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -3003,7 +3323,7 @@ local void copy_block(s, buf, len, header) /* +++ infblock.h */ /* infblock.h -- header to use infblock.c - * Copyright (C) 1995-1996 Mark Adler + * Copyright (C) 1995-2002 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -3032,20 +3352,15 @@ extern void inflate_blocks_reset OF(( extern int inflate_blocks_free OF(( inflate_blocks_statef *, - z_streamp , - uLongf *)); /* check value on output */ + z_streamp)); extern void inflate_set_dictionary OF(( inflate_blocks_statef *s, const Bytef *d, /* dictionary */ uInt n)); /* dictionary length */ -extern int inflate_addhistory OF(( - inflate_blocks_statef *, - z_streamp)); - -extern int inflate_packet_flush OF(( - inflate_blocks_statef *)); +extern int inflate_blocks_sync_point OF(( + inflate_blocks_statef *s)); /* --- infblock.h */ #ifndef NO_DUMMY_DECL @@ -3053,7 +3368,7 @@ struct inflate_blocks_state {int dummy;}; /* for buggy compilers */ #endif /* inflate private state */ -struct internal_state { +typedef struct inflate_state { /* mode */ enum { @@ -3089,47 +3404,47 @@ struct internal_state { inflate_blocks_statef *blocks; /* current inflate_blocks state */ -}; +}inflate_state; -int inflateReset(z) +int ZEXPORT inflateReset(z) z_streamp z; { - uLong c; - - if (z == Z_NULL || z->state == Z_NULL) - return Z_STREAM_ERROR; - z->total_in = z->total_out = 0; - z->msg = Z_NULL; - z->state->mode = z->state->nowrap ? BLOCKS : METHOD; - inflate_blocks_reset(z->state->blocks, z, &c); - Trace((stderr, "inflate: reset\n")); - return Z_OK; + inflate_state* s; + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + + s = (inflate_state*)z->state; + z->total_in = z->total_out = 0; + z->msg = Z_NULL; + s->mode = s->nowrap ? BLOCKS : METHOD; + inflate_blocks_reset(s->blocks, z, Z_NULL); + Tracev((stderr, "inflate: reset\n")); + return Z_OK; } -int inflateEnd(z) +int ZEXPORT inflateEnd(z) z_streamp z; { - uLong c; - if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) return Z_STREAM_ERROR; - if (z->state->blocks != Z_NULL) - inflate_blocks_free(z->state->blocks, z, &c); + if (((inflate_state*)z->state)->blocks != Z_NULL) + inflate_blocks_free(((inflate_state*)z->state)->blocks, z); ZFREE(z, z->state); z->state = Z_NULL; - Trace((stderr, "inflate: end\n")); + Tracev((stderr, "inflate: end\n")); return Z_OK; } -int inflateInit2_(z, w, version, stream_size) +int ZEXPORT inflateInit2_(z, w, version, stream_size) z_streamp z; int w; const char *version; int stream_size; { + inflate_state* s; if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || stream_size != sizeof(z_stream)) return Z_VERSION_ERROR; @@ -3147,16 +3462,17 @@ int stream_size; if (z->zfree == Z_NULL) z->zfree = zcfree; #endif if ((z->state = (struct internal_state FAR *) - ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) + ZALLOC(z,1,sizeof(struct inflate_state))) == Z_NULL) return Z_MEM_ERROR; - z->state->blocks = Z_NULL; + s = (inflate_state*)z->state; + s->blocks = Z_NULL; /* handle undocumented nowrap option (no zlib header or check) */ - z->state->nowrap = 0; + s->nowrap = 0; if (w < 0) { w = - w; - z->state->nowrap = 1; + s->nowrap = 1; } /* set window size */ @@ -3165,17 +3481,17 @@ int stream_size; inflateEnd(z); return Z_STREAM_ERROR; } - z->state->wbits = (uInt)w; + s->wbits = (uInt)w; /* create inflate_blocks state */ - if ((z->state->blocks = - inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) + if ((s->blocks = + inflate_blocks_new(z, s->nowrap ? Z_NULL : adler32, (uInt)1 << w)) == Z_NULL) { inflateEnd(z); return Z_MEM_ERROR; } - Trace((stderr, "inflate: allocated\n")); + Tracev((stderr, "inflate: allocated\n")); /* reset state */ inflateReset(z); @@ -3183,7 +3499,7 @@ int stream_size; } -int inflateInit_(z, version, stream_size) +int ZEXPORT inflateInit_(z, version, stream_size) z_streamp z; const char *version; int stream_size; @@ -3192,123 +3508,126 @@ int stream_size; } -#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;} +#define NEEDBYTE {if(z->avail_in==0)return r;r=f;} #define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) -int inflate(z, f) +int ZEXPORT inflate(z, f) z_streamp z; int f; { int r; uInt b; + inflate_state* s; - if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL || f < 0) + if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL) return Z_STREAM_ERROR; + f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; r = Z_BUF_ERROR; - while (1) switch (z->state->mode) + s = (inflate_state*)z->state; + while (1) switch (s->mode) { case METHOD: NEEDBYTE - if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED) + if (((s->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED) { - z->state->mode = BAD; + s->mode = BAD; z->msg = (char*)"unknown compression method"; - z->state->sub.marker = 5; /* can't try inflateSync */ + s->sub.marker = 5; /* can't try inflateSync */ break; } - if ((z->state->sub.method >> 4) + 8 > z->state->wbits) + if ((s->sub.method >> 4) + 8 > s->wbits) { - z->state->mode = BAD; + s->mode = BAD; z->msg = (char*)"invalid window size"; - z->state->sub.marker = 5; /* can't try inflateSync */ + s->sub.marker = 5; /* can't try inflateSync */ break; } - z->state->mode = FLAG; + s->mode = FLAG; case FLAG: NEEDBYTE b = NEXTBYTE; - if (((z->state->sub.method << 8) + b) % 31) + if (((s->sub.method << 8) + b) % 31) { - z->state->mode = BAD; + s->mode = BAD; z->msg = (char*)"incorrect header check"; - z->state->sub.marker = 5; /* can't try inflateSync */ + s->sub.marker = 5; /* can't try inflateSync */ break; } - Trace((stderr, "inflate: zlib header ok\n")); + Tracev((stderr, "inflate: zlib header ok\n")); if (!(b & PRESET_DICT)) { - z->state->mode = BLOCKS; - break; + s->mode = BLOCKS; + break; } - z->state->mode = DICT4; + s->mode = DICT4; case DICT4: NEEDBYTE - z->state->sub.check.need = (uLong)NEXTBYTE << 24; - z->state->mode = DICT3; + s->sub.check.need = (uLong)NEXTBYTE << 24; + s->mode = DICT3; case DICT3: NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 16; - z->state->mode = DICT2; + s->sub.check.need += (uLong)NEXTBYTE << 16; + s->mode = DICT2; case DICT2: NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 8; - z->state->mode = DICT1; + s->sub.check.need += (uLong)NEXTBYTE << 8; + s->mode = DICT1; case DICT1: NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE; - z->adler = z->state->sub.check.need; - z->state->mode = DICT0; + s->sub.check.need += (uLong)NEXTBYTE; + z->adler = s->sub.check.need; + s->mode = DICT0; return Z_NEED_DICT; case DICT0: - z->state->mode = BAD; + s->mode = BAD; z->msg = (char*)"need dictionary"; - z->state->sub.marker = 0; /* can try inflateSync */ + s->sub.marker = 0; /* can try inflateSync */ return Z_STREAM_ERROR; case BLOCKS: - r = inflate_blocks(z->state->blocks, z, r); - if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0) - r = inflate_packet_flush(z->state->blocks); + r = inflate_blocks(s->blocks, z, r); if (r == Z_DATA_ERROR) { - z->state->mode = BAD; - z->state->sub.marker = 0; /* can try inflateSync */ + s->mode = BAD; + s->sub.marker = 0; /* can try inflateSync */ break; } + if (r == Z_OK) + r = f; if (r != Z_STREAM_END) return r; - r = Z_OK; - inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); - if (z->state->nowrap) + r = f; + inflate_blocks_reset(s->blocks, z, &s->sub.check.was); + if (s->nowrap) { - z->state->mode = DONE; + s->mode = DONE; break; } - z->state->mode = CHECK4; + s->mode = CHECK4; case CHECK4: NEEDBYTE - z->state->sub.check.need = (uLong)NEXTBYTE << 24; - z->state->mode = CHECK3; + s->sub.check.need = (uLong)NEXTBYTE << 24; + s->mode = CHECK3; case CHECK3: NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 16; - z->state->mode = CHECK2; + s->sub.check.need += (uLong)NEXTBYTE << 16; + s->mode = CHECK2; case CHECK2: NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 8; - z->state->mode = CHECK1; + s->sub.check.need += (uLong)NEXTBYTE << 8; + s->mode = CHECK1; case CHECK1: NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE; + s->sub.check.need += (uLong)NEXTBYTE; - if (z->state->sub.check.was != z->state->sub.check.need) + if (s->sub.check.was != s->sub.check.need) { - z->state->mode = BAD; + s->mode = BAD; z->msg = (char*)"incorrect data check"; - z->state->sub.marker = 5; /* can't try inflateSync */ + s->sub.marker = 5; /* can't try inflateSync */ break; } - Trace((stderr, "inflate: zlib check ok\n")); - z->state->mode = DONE; + Tracev((stderr, "inflate: zlib check ok\n")); + s->mode = DONE; case DONE: return Z_STREAM_END; case BAD: @@ -3316,83 +3635,66 @@ int f; default: return Z_STREAM_ERROR; } - - empty: - if (f != Z_PACKET_FLUSH) - return r; - z->state->mode = BAD; - z->msg = (char *)"need more for packet flush"; - z->state->sub.marker = 0; /* can try inflateSync */ - return Z_DATA_ERROR; +#ifdef NEED_DUMMY_RETURN + return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ +#endif } -int inflateSetDictionary(z, dictionary, dictLength) +int ZEXPORT inflateSetDictionary(z, dictionary, dictLength) z_streamp z; const Bytef *dictionary; uInt dictLength; { uInt length = dictLength; + inflate_state* s; - if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0) + if (z == Z_NULL || z->state == Z_NULL || ((inflate_state*)z->state)->mode != DICT0) return Z_STREAM_ERROR; + s = (inflate_state*)z->state; if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR; z->adler = 1L; - if (length >= ((uInt)1<state->wbits)) + if (length >= ((uInt)1<wbits)) { - length = (1<state->wbits)-1; + length = (1<wbits)-1; dictionary += dictLength - length; } - inflate_set_dictionary(z->state->blocks, dictionary, length); - z->state->mode = BLOCKS; + inflate_set_dictionary(s->blocks, dictionary, length); + s->mode = BLOCKS; return Z_OK; } -/* - * This subroutine adds the data at next_in/avail_in to the output history - * without performing any output. The output buffer must be "caught up"; - * i.e. no pending output (hence s->read equals s->write), and the state must - * be BLOCKS (i.e. we should be willing to see the start of a series of - * BLOCKS). On exit, the output will also be caught up, and the checksum - * will have been updated if need be. - */ -int inflateIncomp(z) -z_stream *z; -{ - if (z->state->mode != BLOCKS) - return Z_DATA_ERROR; - return inflate_addhistory(z->state->blocks, z); -} - - -int inflateSync(z) +int ZEXPORT inflateSync(z) z_streamp z; { uInt n; /* number of bytes to look at */ Bytef *p; /* pointer to bytes */ uInt m; /* number of marker bytes found in a row */ uLong r, w; /* temporaries to save total_in and total_out */ + inflate_state* s; /* set up */ if (z == Z_NULL || z->state == Z_NULL) return Z_STREAM_ERROR; - if (z->state->mode != BAD) + s = (inflate_state*)z->state; + if (s->mode != BAD) { - z->state->mode = BAD; - z->state->sub.marker = 0; + s->mode = BAD; + s->sub.marker = 0; } if ((n = z->avail_in) == 0) return Z_BUF_ERROR; p = z->next_in; - m = z->state->sub.marker; + m = s->sub.marker; /* search */ while (n && m < 4) { - if (*p == (Byte)(m < 2 ? 0 : 0xff)) + static const Byte mark[4] = {0, 0, 0xff, 0xff}; + if (*p == mark[m]) m++; else if (*p) m = 0; @@ -3405,7 +3707,7 @@ z_streamp z; z->total_in += p - z->next_in; z->next_in = p; z->avail_in = n; - z->state->sub.marker = m; + s->sub.marker = m; /* return no joy or set up to restart on a new block */ if (m != 4) @@ -3413,17 +3715,32 @@ z_streamp z; r = z->total_in; w = z->total_out; inflateReset(z); z->total_in = r; z->total_out = w; - z->state->mode = BLOCKS; + s->mode = BLOCKS; return Z_OK; } + +/* Returns true if inflate is currently at the end of a block generated + * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH + * but removes the length bytes of the resulting empty stored block. When + * decompressing, PPP checks that at the end of input packet, inflate is + * waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(z) +z_streamp z; +{ + if (z == Z_NULL || z->state == Z_NULL || ((inflate_state*)z->state)->blocks == Z_NULL) + return Z_STREAM_ERROR; + return inflate_blocks_sync_point(((inflate_state*)z->state)->blocks); +} #undef NEEDBYTE #undef NEXTBYTE /* --- inflate.c */ /* +++ infblock.c */ /* infblock.c -- interpret and process block types to last block - * Copyright (C) 1995-1996 Mark Adler + * Copyright (C) 1995-2002 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -3432,7 +3749,7 @@ z_streamp z; /* +++ inftrees.h */ /* inftrees.h -- header to use inftrees.c - * Copyright (C) 1995-1996 Mark Adler + * Copyright (C) 1995-2002 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -3452,23 +3769,25 @@ struct inflate_huft_s { Byte Exop; /* number of extra bits or operation */ Byte Bits; /* number of bits in this code or subcode */ } what; - Bytef *pad; /* pad structure to a power of 2 (4 bytes for */ - } word; /* 16-bit, 8 bytes for 32-bit machines) */ - union { - uInt Base; /* literal, length base, or distance base */ - inflate_huft *Next; /* pointer to next level of table */ - } more; + uInt pad; /* pad structure to a power of 2 (4 bytes for */ + } word; /* 16-bit, 8 bytes for 32-bit int's) */ + uInt base; /* literal, length base, distance base, + or table offset */ }; -#ifdef DEBUG_ZLIB - extern uInt inflate_hufts; -#endif +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1004 huft structures (850 for length/literals + and 154 for distances, the latter actually the result of an + exhaustive search). The actual maximum is not known, but the + value below is more than safe. */ +#define MANY 1440 extern int inflate_trees_bits OF(( uIntf *, /* 19 code lengths */ uIntf *, /* bits tree desired/actual depth */ inflate_huft * FAR *, /* bits tree result */ - z_streamp )); /* for zalloc, zfree functions */ + inflate_huft *, /* space for trees */ + z_streamp)); /* for messages */ extern int inflate_trees_dynamic OF(( uInt, /* number of literal/length codes */ @@ -3478,23 +3797,20 @@ extern int inflate_trees_dynamic OF(( uIntf *, /* distance desired/actual bit depth */ inflate_huft * FAR *, /* literal/length tree result */ inflate_huft * FAR *, /* distance tree result */ - z_streamp )); /* for zalloc, zfree functions */ + inflate_huft *, /* space for trees */ + z_streamp)); /* for messages */ extern int inflate_trees_fixed OF(( uIntf *, /* literal desired/actual bit depth */ uIntf *, /* distance desired/actual bit depth */ inflate_huft * FAR *, /* literal/length tree result */ - inflate_huft * FAR *)); /* distance tree result */ - -extern int inflate_trees_free OF(( - inflate_huft *, /* tables to free */ - z_streamp )); /* for zfree function */ - + inflate_huft * FAR *, /* distance tree result */ + z_streamp)); /* for memory allocation */ /* --- inftrees.h */ /* +++ infcodes.h */ /* infcodes.h -- header to use infcodes.c - * Copyright (C) 1995-1996 Mark Adler + * Copyright (C) 1995-2002 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -3524,7 +3840,7 @@ extern void inflate_codes_free OF(( /* +++ infutil.h */ /* infutil.h -- types and macros common to blocks and codes - * Copyright (C) 1995-1996 Mark Adler + * Copyright (C) 1995-2002 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -3545,8 +3861,8 @@ typedef enum { DTREE, /* get length, distance trees for a dynamic block */ CODES, /* processing fixed or dynamic block */ DRY, /* output remaining window bytes */ - DONEB, /* finished last block, done */ - BADB} /* got a data error--stuck here */ + DONEB, /* finished last block, done */ + BADB} /* got a data error--stuck here */ inflate_block_mode; /* inflate blocks semi-private state */ @@ -3566,8 +3882,6 @@ struct inflate_blocks_state { inflate_huft *tb; /* bit length decoding tree */ } trees; /* if DTREE, decoding info for trees */ struct { - inflate_huft *tl; - inflate_huft *td; /* trees to free */ inflate_codes_statef *codes; } decode; /* if CODES, current state */ @@ -3577,6 +3891,7 @@ struct inflate_blocks_state { /* mode independent information */ uInt bitk; /* bits in bit buffer */ uLong bitb; /* bit buffer */ + inflate_huft *hufts; /* single malloc for tree space */ Bytef *window; /* sliding window */ Bytef *end; /* one byte after sliding window */ Bytef *read; /* window read pointer */ @@ -3603,9 +3918,9 @@ struct inflate_blocks_state { /* output bytes */ #define WAVAIL (uInt)(qread?s->read-q-1:s->end-q) #define LOADOUT {q=s->write;m=(uInt)WAVAIL;} -#define WWRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} +#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} #define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} -#define NEEDOUT {if(m==0){WWRAP if(m==0){FLUSH WWRAP if(m==0) LEAVE}}r=Z_OK;} +#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} #define OUTBYTE(a) {*q++=(Byte)(a);m--;} /* load local pointers */ #define LOAD {LOADIN LOADOUT} @@ -3630,6 +3945,10 @@ struct internal_state {int dummy;}; /* for buggy compilers */ struct inflate_codes_state {int dummy;}; /* for buggy compilers */ #endif +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + /* Table for deflate from PKZIP's appnote.txt. */ local const uInt border[] = { /* Order of the bit length code lengths */ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; @@ -3685,23 +4004,19 @@ inflate_blocks_statef *s; z_streamp z; uLongf *c; { - if (s->checkfn != Z_NULL) + if (c != Z_NULL) *c = s->check; if (s->mode == BTREE || s->mode == DTREE) ZFREE(z, s->sub.trees.blens); if (s->mode == CODES) - { inflate_codes_free(s->sub.decode.codes, z); - inflate_trees_free(s->sub.decode.td, z); - inflate_trees_free(s->sub.decode.tl, z); - } s->mode = TYPE; s->bitk = 0; s->bitb = 0; s->read = s->write = s->window; if (s->checkfn != Z_NULL) - z->adler = s->check = (*s->checkfn)(0L, Z_NULL, 0); - Trace((stderr, "inflate: blocks reset\n")); + z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0); + Tracev((stderr, "inflate: blocks reset\n")); } @@ -3715,23 +4030,27 @@ uInt w; if ((s = (inflate_blocks_statef *)ZALLOC (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) return s; + if ((s->hufts = + (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL) + { + ZFREE(z, s); + return Z_NULL; + } if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL) { + ZFREE(z, s->hufts); ZFREE(z, s); return Z_NULL; } s->end = s->window + w; s->checkfn = c; s->mode = TYPE; - Trace((stderr, "inflate: blocks allocated\n")); - inflate_blocks_reset(s, z, &s->check); + Tracev((stderr, "inflate: blocks allocated\n")); + inflate_blocks_reset(s, z, Z_NULL); return s; } -#ifdef DEBUG_ZLIB - extern uInt inflate_hufts; -#endif int inflate_blocks(s, z, r) inflate_blocks_statef *s; z_streamp z; @@ -3758,7 +4077,7 @@ int r; switch (t >> 1) { case 0: /* stored */ - Trace((stderr, "inflate: stored block%s\n", + Tracev((stderr, "inflate: stored block%s\n", s->last ? " (last)" : "")); DUMPBITS(3) t = k & 7; /* go to byte boundary */ @@ -3766,27 +4085,25 @@ int r; s->mode = LENS; /* get length of stored block */ break; case 1: /* fixed */ - Trace((stderr, "inflate: fixed codes block%s\n", + Tracev((stderr, "inflate: fixed codes block%s\n", s->last ? " (last)" : "")); { uInt bl, bd; inflate_huft *tl, *td; - inflate_trees_fixed(&bl, &bd, &tl, &td); + inflate_trees_fixed(&bl, &bd, &tl, &td, z); s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); if (s->sub.decode.codes == Z_NULL) { r = Z_MEM_ERROR; LEAVE } - s->sub.decode.tl = Z_NULL; /* don't try to free these */ - s->sub.decode.td = Z_NULL; } DUMPBITS(3) s->mode = CODES; break; case 2: /* dynamic */ - Trace((stderr, "inflate: dynamic codes block%s\n", + Tracev((stderr, "inflate: dynamic codes block%s\n", s->last ? " (last)" : "")); DUMPBITS(3) s->mode = TABLE; @@ -3843,8 +4160,6 @@ int r; } #endif t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); - if (t < 19) - t = 19; if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) { r = Z_MEM_ERROR; @@ -3865,13 +4180,15 @@ int r; s->sub.trees.blens[border[s->sub.trees.index++]] = 0; s->sub.trees.bb = 7; t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, - &s->sub.trees.tb, z); + &s->sub.trees.tb, s->hufts, z); if (t != Z_OK) { - ZFREE(z, s->sub.trees.blens); r = t; if (r == Z_DATA_ERROR) + { + ZFREE(z, s->sub.trees.blens); s->mode = BADB; + } LEAVE } s->sub.trees.index = 0; @@ -3887,8 +4204,8 @@ int r; t = s->sub.trees.bb; NEEDBITS(t) h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); - t = h->word.what.Bits; - c = h->more.Base; + t = h->bits; + c = h->base; if (c < 16) { DUMPBITS(t) @@ -3907,7 +4224,6 @@ int r; if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || (c == 16 && i < 1)) { - inflate_trees_free(s->sub.trees.tb, z); ZFREE(z, s->sub.trees.blens); s->mode = BADB; z->msg = (char*)"invalid bit length repeat"; @@ -3921,7 +4237,6 @@ int r; s->sub.trees.index = i; } } - inflate_trees_free(s->sub.trees.tb, z); s->sub.trees.tb = Z_NULL; { uInt bl, bd; @@ -3931,32 +4246,28 @@ int r; bl = 9; /* must be <= 9 for lookahead assumptions */ bd = 6; /* must be <= 9 for lookahead assumptions */ t = s->sub.trees.table; -#ifdef DEBUG_ZLIB - inflate_hufts = 0; -#endif t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), - s->sub.trees.blens, &bl, &bd, &tl, &td, z); - ZFREE(z, s->sub.trees.blens); + s->sub.trees.blens, &bl, &bd, &tl, &td, + s->hufts, z); if (t != Z_OK) { if (t == (uInt)Z_DATA_ERROR) + { + ZFREE(z, s->sub.trees.blens); s->mode = BADB; + } r = t; LEAVE } - Tracev((stderr, "inflate: trees ok, %d * %d bytes used\n", - inflate_hufts, sizeof(inflate_huft))); + Tracev((stderr, "inflate: trees ok\n")); if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) { - inflate_trees_free(td, z); - inflate_trees_free(tl, z); r = Z_MEM_ERROR; LEAVE } s->sub.decode.codes = c; - s->sub.decode.tl = tl; - s->sub.decode.td = td; } + ZFREE(z, s->sub.trees.blens); s->mode = CODES; case CODES: UPDATE @@ -3964,8 +4275,6 @@ int r; return inflate_flush(s, z, r); r = Z_OK; inflate_codes_free(s->sub.decode.codes, z); - inflate_trees_free(s->sub.decode.td, z); - inflate_trees_free(s->sub.decode.tl, z); LOAD Tracev((stderr, "inflate: codes end, %lu total out\n", z->total_out + (q >= s->read ? q - s->read : @@ -3975,13 +4284,6 @@ int r; s->mode = TYPE; break; } - if (k > 7) /* return unused byte, if any */ - { - Assert(k < 16, "inflate_codes grabbed too many bytes") - k -= 8; - n++; - p--; /* can always return one */ - } s->mode = DRY; case DRY: FLUSH @@ -4001,15 +4303,15 @@ int r; } -int inflate_blocks_free(s, z, c) +int inflate_blocks_free(s, z) inflate_blocks_statef *s; z_streamp z; -uLongf *c; { - inflate_blocks_reset(s, z, c); + inflate_blocks_reset(s, z, Z_NULL); ZFREE(z, s->window); + ZFREE(z, s->hufts); ZFREE(z, s); - Trace((stderr, "inflate: blocks freed\n")); + Tracev((stderr, "inflate: blocks freed\n")); return Z_OK; } @@ -4019,102 +4321,49 @@ inflate_blocks_statef *s; const Bytef *d; uInt n; { - zmemcpy((charf *)s->window, d, n); + zmemcpy(s->window, d, n); s->read = s->write = s->window + n; } -/* - * This subroutine adds the data at next_in/avail_in to the output history - * without performing any output. The output buffer must be "caught up"; - * i.e. no pending output (hence s->read equals s->write), and the state must - * be BLOCKS (i.e. we should be willing to see the start of a series of - * BLOCKS). On exit, the output will also be caught up, and the checksum - * will have been updated if need be. - */ -int inflate_addhistory(s, z) -inflate_blocks_statef *s; -z_stream *z; -{ - uLong b; /* bit buffer */ /* NOT USED HERE */ - uInt k; /* bits in bit buffer */ /* NOT USED HERE */ - uInt t; /* temporary storage */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - - if (s->read != s->write) - return Z_STREAM_ERROR; - if (s->mode != TYPE) - return Z_DATA_ERROR; - - /* we're ready to rock */ - LOAD - /* while there is input ready, copy to output buffer, moving - * pointers as needed. - */ - while (n) { - t = n; /* how many to do */ - /* is there room until end of buffer? */ - if (t > m) t = m; - /* update check information */ - if (s->checkfn != Z_NULL) - s->check = (*s->checkfn)(s->check, q, t); - zmemcpy(q, p, t); - q += t; - p += t; - n -= t; - z->total_out += t; - s->read = q; /* drag read pointer forward */ -/* WWRAP */ /* expand WWRAP macro by hand to handle s->read */ - if (q == s->end) { - s->read = q = s->window; - m = WAVAIL; - } - } - UPDATE - return Z_OK; -} - -/* - * At the end of a Deflate-compressed PPP packet, we expect to have seen - * a `stored' block type value but not the (zero) length bytes. +/* Returns true if inflate is currently at the end of a block generated + * by Z_SYNC_FLUSH or Z_FULL_FLUSH. + * IN assertion: s != Z_NULL */ -int inflate_packet_flush(s) - inflate_blocks_statef *s; +int inflate_blocks_sync_point(s) +inflate_blocks_statef *s; { - if (s->mode != LENS) - return Z_DATA_ERROR; - s->mode = TYPE; - return Z_OK; + return s->mode == LENS; } /* --- infblock.c */ /* +++ inftrees.c */ /* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-1996 Mark Adler + * Copyright (C) 1995-2002 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* #include "zutil.h" */ /* #include "inftrees.h" */ -char inflate_copyright[] = " inflate 1.0.4 Copyright 1995-1996 Mark Adler "; +#if !defined(BUILDFIXED) && !defined(STDC) +# define BUILDFIXED /* non ANSI compilers may not accept inffixed.h */ +#endif + +const char inflate_copyright[] = + " inflate 1.1.4 Copyright 1995-2002 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot include such an acknowledgment, I would appreciate that you keep this copyright string in the executable of your product. */ - + #ifndef NO_DUMMY_DECL struct internal_state {int dummy;}; /* for buggy compilers */ #endif /* simplify the use of the inflate_huft type with some defines */ -#define base more.Base -#define next more.Next #define exop word.what.Exop #define bits word.what.Bits @@ -4127,12 +4376,9 @@ local int huft_build OF(( const uIntf *, /* list of extra bits for non-simple codes */ inflate_huft * FAR*,/* result: starting table */ uIntf *, /* maximum lookup bits (returns actual) */ - z_streamp )); /* for zalloc function */ - -local voidpf falloc OF(( - voidpf, /* opaque pointer (not used) */ - uInt, /* number of items */ - uInt)); /* size of item */ + inflate_huft *, /* space for trees */ + uInt *, /* hufts used in space */ + uIntf * )); /* space for values */ /* Tables for deflate from PKZIP's appnote.txt. */ local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */ @@ -4186,26 +4432,22 @@ local const uInt cpdext[30] = { /* Extra bits for distance codes */ /* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ #define BMAX 15 /* maximum bit length of any code */ -#define N_MAX 288 /* maximum number of codes in any set */ -#ifdef DEBUG_ZLIB - uInt inflate_hufts; -#endif - -local int huft_build(b, n, s, d, e, t, m, zs) +local int huft_build(b, n, s, d, e, t, m, hp, hn, v) uIntf *b; /* code lengths in bits (all assumed <= BMAX) */ -uInt n; /* number of codes (assumed <= N_MAX) */ +uInt n; /* number of codes (assumed <= 288) */ uInt s; /* number of simple-valued codes (0..s-1) */ const uIntf *d; /* list of base values for non-simple codes */ const uIntf *e; /* list of extra bits for non-simple codes */ inflate_huft * FAR *t; /* result: starting table */ uIntf *m; /* maximum lookup bits, returns actual */ -z_streamp zs; /* for zalloc function */ +inflate_huft *hp; /* space for trees */ +uInt *hn; /* hufts used in space */ +uIntf *v; /* working area: values in order of bit length */ /* Given a list of code lengths and a maximum table size, make a set of tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR if the given code set is incomplete (the tables are still built in this - case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of - lengths), or Z_MEM_ERROR if not enough memory. */ + case), or Z_DATA_ERROR if the input is invalid. */ { uInt a; /* counter for codes of length k */ @@ -4217,11 +4459,11 @@ z_streamp zs; /* for zalloc function */ register uInt j; /* counter */ register int k; /* number of bits in current code */ int l; /* bits per table (returned in m) */ + uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */ register uIntf *p; /* pointer into c[], b[], or v[] */ inflate_huft *q; /* points to current table */ struct inflate_huft_s r; /* table entry for structure assignment */ inflate_huft *u[BMAX]; /* table stack */ - uInt v[N_MAX]; /* values in order of bit length */ register int w; /* bits before this table == (l * h) */ uInt x[BMAX+1]; /* bit offsets, then code stack */ uIntf *xp; /* pointer into x */ @@ -4287,7 +4529,7 @@ z_streamp zs; /* for zalloc function */ if ((j = *p++) != 0) v[x[j]++] = i; } while (++i < n); - n = x[g]; /* set n to length of v */ + n = x[g]; /* set n to length of v */ /* Generate the Huffman codes and for each, make the table entries */ @@ -4329,20 +4571,11 @@ z_streamp zs; /* for zalloc function */ } z = 1 << j; /* table entries for j-bit table */ - /* allocate and link in new table */ - if ((q = (inflate_huft *)ZALLOC - (zs,z + 1,sizeof(inflate_huft))) == Z_NULL) - { - if (h) - inflate_trees_free(u[0], zs); - return Z_MEM_ERROR; /* not enough memory */ - } -#ifdef DEBUG_ZLIB - inflate_hufts += z + 1; -#endif - *t = q + 1; /* link to list for huft_free() */ - *(t = &(q->next)) = Z_NULL; - u[h] = ++q; /* table starts after link */ + /* allocate new table */ + if (*hn + z > MANY) /* (note: doesn't matter for fixed) */ + return Z_DATA_ERROR; /* overflow of MANY */ + u[h] = q = hp + *hn; + *hn += z; /* connect to last table, if there is one */ if (h) @@ -4350,10 +4583,12 @@ z_streamp zs; /* for zalloc function */ x[h] = i; /* save pattern for backing up */ r.bits = (Byte)l; /* bits to dump before this table */ r.exop = (Byte)j; /* bits in this table */ - r.next = q; /* pointer to this table */ - j = i >> (w - l); /* (get around Turbo C bug) */ + j = i >> (w - l); + r.base = (uInt)(q - u[h-1] - j); /* offset to this table */ u[h-1][j] = r; /* connect to last table */ } + else + *t = q; /* first table is returned result */ } /* set up table entry in r */ @@ -4382,10 +4617,12 @@ z_streamp zs; /* for zalloc function */ i ^= j; /* backup over finished tables */ - while ((i & ((1 << w) - 1)) != x[h]) + mask = (1 << w) - 1; /* needed on HP, cc -O bug */ + while ((i & mask) != x[h]) { h--; /* don't need to update q */ w -= l; + mask = (1 << w) - 1; } } } @@ -4396,28 +4633,34 @@ z_streamp zs; /* for zalloc function */ } -int inflate_trees_bits(c, bb, tb, z) +int inflate_trees_bits(c, bb, tb, hp, z) uIntf *c; /* 19 code lengths */ uIntf *bb; /* bits tree desired/actual depth */ inflate_huft * FAR *tb; /* bits tree result */ -z_streamp z; /* for zfree function */ +inflate_huft *hp; /* space for trees */ +z_streamp z; /* for messages */ { int r; + uInt hn = 0; /* hufts used in space */ + uIntf *v; /* work area for huft_build */ - r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z); + if ((v = (uIntf*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, + tb, bb, hp, &hn, v); if (r == Z_DATA_ERROR) z->msg = (char*)"oversubscribed dynamic bit lengths tree"; else if (r == Z_BUF_ERROR || *bb == 0) { - inflate_trees_free(*tb, z); z->msg = (char*)"incomplete dynamic bit lengths tree"; r = Z_DATA_ERROR; } + ZFREE(z, v); return r; } -int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z) +int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z) uInt nl; /* number of literal/length codes */ uInt nd; /* number of distance codes */ uIntf *c; /* that many (total) code lengths */ @@ -4425,27 +4668,34 @@ uIntf *bl; /* literal desired/actual bit depth */ uIntf *bd; /* distance desired/actual bit depth */ inflate_huft * FAR *tl; /* literal/length tree result */ inflate_huft * FAR *td; /* distance tree result */ -z_streamp z; /* for zfree function */ +inflate_huft *hp; /* space for trees */ +z_streamp z; /* for messages */ { int r; + uInt hn = 0; /* hufts used in space */ + uIntf *v; /* work area for huft_build */ + + /* allocate work area */ + if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; /* build literal/length tree */ - r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z); + r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v); if (r != Z_OK || *bl == 0) { if (r == Z_DATA_ERROR) z->msg = (char*)"oversubscribed literal/length tree"; else if (r != Z_MEM_ERROR) { - inflate_trees_free(*tl, z); z->msg = (char*)"incomplete literal/length tree"; r = Z_DATA_ERROR; } + ZFREE(z, v); return r; } /* build distance tree */ - r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z); + r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v); if (r != Z_OK || (*bd == 0 && nl > 257)) { if (r == Z_DATA_ERROR) @@ -4455,7 +4705,6 @@ z_streamp z; /* for zfree function */ r = Z_OK; } #else - inflate_trees_free(*td, z); z->msg = (char*)"incomplete distance tree"; r = Z_DATA_ERROR; } @@ -4464,56 +4713,207 @@ z_streamp z; /* for zfree function */ z->msg = (char*)"empty distance tree with lengths"; r = Z_DATA_ERROR; } - inflate_trees_free(*tl, z); + ZFREE(z, v); return r; #endif } /* done */ + ZFREE(z, v); return Z_OK; } /* build fixed tables only once--keep them here */ +#ifdef BUILDFIXED local int fixed_built = 0; -#define FIXEDH 530 /* number of hufts used by fixed tables */ +#define FIXEDH 544 /* number of hufts used by fixed tables */ local inflate_huft fixed_mem[FIXEDH]; local uInt fixed_bl; local uInt fixed_bd; local inflate_huft *fixed_tl; local inflate_huft *fixed_td; +#else +/* +++ inffixed.h */ +/* inffixed.h -- table for decoding fixed codes + * Generated automatically by the maketree.c program + */ +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ -local voidpf falloc(q, n, s) -voidpf q; /* opaque pointer */ -uInt n; /* number of items */ -uInt s; /* size of item */ -{ - Assert(s == sizeof(inflate_huft) && n <= *(intf *)q, - "inflate_trees falloc overflow"); - *(intf *)q -= n+s-s; /* s-s to avoid warning */ - return (voidpf)(fixed_mem + *(intf *)q); -} +local uInt fixed_bl = 9; +local uInt fixed_bd = 5; +local inflate_huft fixed_tl[] = { + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254}, + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255} + }; +local inflate_huft fixed_td[] = { + {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097}, + {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385}, + {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193}, + {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577}, + {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145}, + {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577}, + {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289}, + {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577} + }; +/* --- inffixed.h */ +#endif -int inflate_trees_fixed(bl, bd, tl, td) +int inflate_trees_fixed(bl, bd, tl, td, z) uIntf *bl; /* literal desired/actual bit depth */ uIntf *bd; /* distance desired/actual bit depth */ inflate_huft * FAR *tl; /* literal/length tree result */ inflate_huft * FAR *td; /* distance tree result */ +z_streamp z; /* for memory allocation */ { - /* build fixed tables if not already (multiple overlapped executions ok) */ +#ifdef BUILDFIXED + /* build fixed tables if not already */ if (!fixed_built) { int k; /* temporary variable */ - unsigned c[288]; /* length list for huft_build */ - z_stream z; /* for falloc function */ - int f = FIXEDH; /* number of hufts left in fixed_mem */ - - /* set up fake z_stream for memory routines */ - z.zalloc = falloc; - z.zfree = Z_NULL; - z.opaque = (voidpf)&f; + uInt f = 0; /* number of hufts used in fixed_mem */ + uIntf *c; /* length list for huft_build */ + uIntf *v; /* work area for huft_build */ + + /* allocate memory */ + if ((c = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) + { + ZFREE(z, c); + return Z_MEM_ERROR; + } /* literal table */ for (k = 0; k < 144; k++) @@ -4524,60 +4924,34 @@ inflate_huft * FAR *td; /* distance tree result */ c[k] = 7; for (; k < 288; k++) c[k] = 8; - fixed_bl = 7; - huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z); + fixed_bl = 9; + huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, + fixed_mem, &f, v); /* distance table */ for (k = 0; k < 30; k++) c[k] = 5; fixed_bd = 5; - huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z); + huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, + fixed_mem, &f, v); /* done */ - Assert(f == 0, "invalid build of fixed tables"); + ZFREE(z, v); + ZFREE(z, c); fixed_built = 1; } +#endif *bl = fixed_bl; *bd = fixed_bd; *tl = fixed_tl; *td = fixed_td; return Z_OK; } - - -int inflate_trees_free(t, z) -inflate_huft *t; /* table to free */ -z_streamp z; /* for zfree function */ -/* Free the malloc'ed tables built by huft_build(), which makes a linked - list of the tables it made, with the links in a dummy first entry of - each table. */ -{ - register inflate_huft *p, *q, *r; - - /* Reverse linked list */ - p = Z_NULL; - q = t; - while (q != Z_NULL) - { - r = (q - 1)->next; - (q - 1)->next = p; - p = q; - q = r; - } - /* Go through linked list, freeing from the malloced (t[-1]) address. */ - while (p != Z_NULL) - { - q = (--p)->next; - ZFREE(z,p); - p = q; - } - return Z_OK; -} /* --- inftrees.c */ /* +++ infcodes.c */ /* infcodes.c -- process literals and length/distance pairs - * Copyright (C) 1995-1996 Mark Adler + * Copyright (C) 1995-2002 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -4589,7 +4963,7 @@ z_streamp z; /* for zfree function */ /* +++ inffast.h */ /* inffast.h -- header to use inffast.c - * Copyright (C) 1995-1996 Mark Adler + * Copyright (C) 1995-2002 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -4608,16 +4982,10 @@ extern int inflate_fast OF(( /* --- inffast.h */ /* simplify the use of the inflate_huft type with some defines */ -#define base more.Base -#define next more.Next #define exop word.what.Exop #define bits word.what.Bits -/* inflate codes private state */ -struct inflate_codes_state { - - /* mode */ - enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ +typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ START, /* x: set up for LEN */ LEN, /* i: get length/literal/eob next */ LENEXT, /* i: getting length extra (have base) */ @@ -4628,7 +4996,13 @@ struct inflate_codes_state { WASH, /* o: got eob, possibly still output waiting */ END, /* x: got eob and all data flushed */ BADCODE} /* x: got error */ - mode; /* current inflate_codes mode */ +inflate_codes_mode; + +/* inflate codes private state */ +struct inflate_codes_state { + + /* mode */ + inflate_codes_mode mode; /* current inflate_codes mode */ /* mode dependent information */ uInt len; @@ -4740,7 +5114,7 @@ int r; if ((e & 64) == 0) /* next table */ { c->sub.code.need = e; - c->sub.code.tree = t->next; + c->sub.code.tree = t + t->base; break; } if (e & 32) /* end of block */ @@ -4778,7 +5152,7 @@ int r; if ((e & 64) == 0) /* next table */ { c->sub.code.need = e; - c->sub.code.tree = t->next; + c->sub.code.tree = t + t->base; break; } c->mode = BADCODE; /* invalid code */ @@ -4793,15 +5167,9 @@ int r; Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); c->mode = COPY; case COPY: /* o: copying bytes in window, waiting for space */ -#ifndef __TURBOC__ /* Turbo C bug for following expression */ - f = (uInt)(q - s->window) < c->sub.copy.dist ? - s->end - (c->sub.copy.dist - (q - s->window)) : - q - c->sub.copy.dist; -#else f = q - c->sub.copy.dist; - if ((uInt)(q - s->window) < c->sub.copy.dist) - f = s->end - (c->sub.copy.dist - (uInt)(q - s->window)); -#endif + while (f < s->window) /* modulo window size-"while" instead */ + f += s->end - s->window; /* of "if" handles invalid distances */ while (c->len) { NEEDOUT @@ -4818,6 +5186,13 @@ int r; c->mode = START; break; case WASH: /* o: got eob, possibly more output */ + if (k > 7) /* return unused byte, if any */ + { + Assert(k < 16, "inflate_codes grabbed too many bytes") + k -= 8; + n++; + p--; /* can always return one */ + } FLUSH if (s->read != s->write) LEAVE @@ -4832,6 +5207,9 @@ int r; r = Z_STREAM_ERROR; LEAVE } +#ifdef NEED_DUMMY_RETURN + return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ +#endif } @@ -4846,7 +5224,7 @@ z_streamp z; /* +++ infutil.c */ /* inflate_util.c -- data and routines common to blocks and codes - * Copyright (C) 1995-1996 Mark Adler + * Copyright (C) 1995-2002 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -4896,10 +5274,8 @@ int r; z->adler = s->check = (*s->checkfn)(s->check, q, n); /* copy as far as end of window */ - if (p != Z_NULL) { - zmemcpy(p, q, n); - p += n; - } + zmemcpy(p, q, n); + p += n; q += n; /* see if more to copy at beginning of window */ @@ -4924,10 +5300,8 @@ int r; z->adler = s->check = (*s->checkfn)(s->check, q, n); /* copy */ - if (p != Z_NULL) { - zmemcpy(p, q, n); - p += n; - } + zmemcpy(p, q, n); + p += n; q += n; } @@ -4942,7 +5316,7 @@ int r; /* +++ inffast.c */ /* inffast.c -- process literals and length/distance pairs fast - * Copyright (C) 1995-1996 Mark Adler + * Copyright (C) 1995-2002 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -4958,14 +5332,12 @@ struct inflate_codes_state {int dummy;}; /* for buggy compilers */ #endif /* simplify the use of the inflate_huft type with some defines */ -#define base more.Base -#define next more.Next #define exop word.what.Exop #define bits word.what.Bits /* macros for bit input with no checking and for returning unused bytes */ #define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<>3);p-=c;k&=7;} +#define UNGRAB {c=z->avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;} /* Called with number of bytes left to write in window at least 258 (the maximum string length) and number of input bytes available @@ -5040,32 +5412,48 @@ z_streamp z; /* do the copy */ m -= c; - if ((uInt)(q - s->window) >= d) /* offset before dest */ - { /* just copy */ - r = q - d; - *q++ = *r++; c--; /* minimum count is three, */ - *q++ = *r++; c--; /* so unroll loop a little */ - } - else /* else offset after destination */ + r = q - d; + if (r < s->window) /* wrap if needed */ { - e = d - (uInt)(q - s->window); /* bytes from offset to end */ - r = s->end - e; /* pointer to offset */ - if (c > e) /* if source crosses, */ + do { + r += s->end - s->window; /* force pointer in window */ + } while (r < s->window); /* covers invalid distances */ + e = s->end - r; + if (c > e) { - c -= e; /* copy to end of window */ + c -= e; /* wrapped copy */ do { - *q++ = *r++; + *q++ = *r++; } while (--e); - r = s->window; /* copy rest from start of window */ + r = s->window; + do { + *q++ = *r++; + } while (--c); + } + else /* normal copy */ + { + *q++ = *r++; c--; + *q++ = *r++; c--; + do { + *q++ = *r++; + } while (--c); } } - do { /* copy all or what's left */ - *q++ = *r++; - } while (--c); + else /* normal copy */ + { + *q++ = *r++; c--; + *q++ = *r++; c--; + do { + *q++ = *r++; + } while (--c); + } break; } else if ((e & 64) == 0) - e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop; + { + t += t->base; + e = (t += ((uInt)b & inflate_mask[e]))->exop; + } else { z->msg = (char*)"invalid distance code"; @@ -5078,7 +5466,8 @@ z_streamp z; } if ((e & 64) == 0) { - if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0) + t += t->base; + if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0) { DUMPBITS(t->bits) Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? @@ -5115,15 +5504,11 @@ z_streamp z; /* +++ zutil.c */ /* zutil.c -- target dependent utility functions for the compression library - * Copyright (C) 1995-1996 Jean-loup Gailly. + * Copyright (C) 1995-2002 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ -/* From: zutil.c,v 1.17 1996/07/24 13:41:12 me Exp $ */ - -#ifdef DEBUG_ZLIB -#include -#endif +/* @(#) $Id: zlib.c,v 1.8 2002/03/29 03:16:07 lindak Exp $ */ /* #include "zutil.h" */ @@ -5135,7 +5520,7 @@ struct internal_state {int dummy;}; /* for buggy compilers */ extern void exit OF((int)); #endif -static const char *z_errmsg[10] = { +const char *z_errmsg[10] = { "need dictionary", /* Z_NEED_DICT 2 */ "stream end", /* Z_STREAM_END 1 */ "", /* Z_OK 0 */ @@ -5148,12 +5533,18 @@ static const char *z_errmsg[10] = { ""}; -const char *zlibVersion() +const char * ZEXPORT zlibVersion() { return ZLIB_VERSION; } #ifdef DEBUG_ZLIB + +# ifndef verbose +# define verbose 0 +# endif +int z_verbose = verbose; + void z_error (m) char *m; { @@ -5162,11 +5553,21 @@ void z_error (m) } #endif +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + + #ifndef HAVE_MEMCPY void zmemcpy(dest, source, len) Bytef* dest; - Bytef* source; + const Bytef* source; uInt len; { if (len == 0) return; @@ -5176,8 +5577,8 @@ void zmemcpy(dest, source, len) } int zmemcmp(s1, s2, len) - Bytef* s1; - Bytef* s2; + const Bytef* s1; + const Bytef* s2; uInt len; { uInt j; @@ -5284,7 +5685,7 @@ void zcfree (voidpf opaque, voidpf ptr) # define MY_ZCALLOC -#if (!defined(_MSC_VER) || (_MSC_VER < 600)) +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) # define _halloc halloc # define _hfree hfree #endif @@ -5333,11 +5734,11 @@ void zcfree (opaque, ptr) /* +++ adler32.c */ /* adler32.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-1996 Mark Adler + * Copyright (C) 1995-2002 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ -/* From: adler32.c,v 1.10 1996/05/22 11:52:18 me Exp $ */ +/* @(#) $Id: zlib.c,v 1.8 2002/03/29 03:16:07 lindak Exp $ */ /* #include "zlib.h" */ @@ -5352,7 +5753,7 @@ void zcfree (opaque, ptr) #define DO16(buf) DO8(buf,0); DO8(buf,8); /* ========================================================================= */ -uLong adler32(adler, buf, len) +uLong ZEXPORT adler32(adler, buf, len) uLong adler; const Bytef *buf; uInt len; diff --git a/bsd/net/zlib.h b/bsd/net/zlib.h index cd0433447..688673ae5 100644 --- a/bsd/net/zlib.h +++ b/bsd/net/zlib.h @@ -1,25 +1,15 @@ -/* $Id: zlib.h,v 1.5 2000/09/14 20:34:49 lindak Exp $ */ +/* $FreeBSD: src/sys/net/zlib.h,v 1.7 1999/12/29 04:38:38 peter Exp $ */ /* - * This file is derived from zlib.h and zconf.h from the zlib-1.0.4 - * distribution by Jean-loup Gailly and Mark Adler, with some additions - * by Paul Mackerras to aid in implementing Deflate compression and - * decompression for PPP packets. + * This file is derived from zlib.h and zconf.h from the zlib-1.1.4 + * distribution by Jean-loup Gailly and Mark Adler. */ -/* - * ==FILEVERSION 971127== - * - * This marker is used by the Linux installation script to determine - * whether an up-to-date version of this file is already installed. - */ - - /* +++ zlib.h */ /* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.0.4, Jul 24th, 1996. + version 1.1.4, March 11th, 2002 - Copyright (C) 1995-1996 Jean-loup Gailly and Mark Adler + Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -38,7 +28,7 @@ 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler - gzip@prep.ai.mit.edu madler@alumni.caltech.edu + jloup@gzip.org madler@alumni.caltech.edu The data format used by the zlib library is described by RFCs (Request for @@ -48,6 +38,9 @@ #ifndef _ZLIB_H #define _ZLIB_H +#include + +#if !defined(KERNEL) || defined(__APPLE_API_PRIVATE) #if __cplusplus extern "C" { @@ -56,12 +49,10 @@ extern "C" { /* +++ zconf.h */ /* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-1996 Jean-loup Gailly. + * Copyright (C) 1995-2002 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ -/* From: zconf.h,v 1.20 1996/07/02 15:09:28 me Exp $ */ - #ifndef _ZCONF_H #define _ZCONF_H @@ -69,7 +60,7 @@ extern "C" { * If you *really* need a unique prefix for all types and library functions, * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. */ -#if Z_PREFIX +#ifdef Z_PREFIX # define deflateInit_ z_deflateInit_ # define deflate z_deflate # define deflateEnd z_deflateEnd @@ -84,8 +75,10 @@ extern "C" { # define inflateInit2_ z_inflateInit2_ # define inflateSetDictionary z_inflateSetDictionary # define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint # define inflateReset z_inflateReset # define compress z_compress +# define compress2 z_compress2 # define uncompress z_uncompress # define adler32 z_adler32 # define crc32 z_crc32 @@ -122,15 +115,17 @@ extern "C" { #if defined(MSDOS) && !defined(__32BIT__) # define MAXSEG_64K #endif -#if MSDOS +#ifdef MSDOS # define UNALIGNED_OK #endif #if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32)) && !defined(STDC) # define STDC #endif -#if (defined(__STDC__) || defined(__cplusplus)) && !defined(STDC) -# define STDC +#if defined(__STDC__) || defined(__cplusplus) || defined(__OS2__) +# ifndef STDC +# define STDC +# endif #endif #ifndef STDC @@ -144,6 +139,12 @@ extern "C" { # define NO_DUMMY_DECL #endif +/* Old Borland C incorrectly complains about missing returns: */ +#if defined(__BORLANDC__) && (__BORLANDC__ < 0x500) +# define NEED_DUMMY_RETURN +#endif + + /* Maximum value for memLevel in deflateInit2 */ #ifndef MAX_MEM_LEVEL # ifdef MAXSEG_64K @@ -153,13 +154,17 @@ extern "C" { # endif #endif -/* Maximum value for windowBits in deflateInit2 and inflateInit2 */ +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ #ifndef MAX_WBITS # define MAX_WBITS 15 /* 32K LZ77 window */ #endif /* The memory requirements for deflate are (in bytes): - 1 << (windowBits+2) + 1 << (memLevel+9) + (1 << (windowBits+2)) + (1 << (memLevel+9)) that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) plus a few kilobytes for small objects. For example, if you want to reduce the default memory requirements from 256K to 128K, compile with @@ -191,7 +196,7 @@ extern "C" { /* MSC small or medium model */ # define SMALL_MEDIUM # ifdef _MSC_VER -# define FAR __far +# define FAR _far # else # define FAR far # endif @@ -199,19 +204,68 @@ extern "C" { #if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__)) # ifndef __32BIT__ # define SMALL_MEDIUM -# define FAR __far +# define FAR _far # endif #endif + +/* Compile with -DZLIB_DLL for Windows DLL support */ +#if defined(ZLIB_DLL) +# if defined(_WINDOWS) || defined(WINDOWS) +# ifdef FAR +# undef FAR +# endif +# include +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR _cdecl _export +# endif +# endif +# if defined (__BORLANDC__) +# if (__BORLANDC__ >= 0x0500) && defined (WIN32) +# include +# define ZEXPORT __declspec(dllexport) WINAPI +# define ZEXPORTRVA __declspec(dllexport) WINAPIV +# else +# if defined (_Windows) && defined (__DLL__) +# define ZEXPORT _export +# define ZEXPORTVA _export +# endif +# endif +# endif +#endif + +#if defined (__BEOS__) +# if defined (ZLIB_DLL) +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +#endif + +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif +#ifndef ZEXTERN +# define ZEXTERN extern +#endif + #ifndef FAR # define FAR #endif +#if !defined(MACOS) && !defined(TARGET_OS_MAC) typedef unsigned char Byte; /* 8 bits */ +#endif typedef unsigned int uInt; /* 16 bits or more */ typedef unsigned long uLong; /* 32 bits or more */ -#if defined(__BORLANDC__) && defined(SMALL_MEDIUM) - /* Borland C/C++ ignores FAR inside typedef */ +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ # define Bytef Byte FAR #else typedef Byte FAR Bytef; @@ -229,42 +283,71 @@ typedef uLong FAR uLongf; typedef Byte *voidp; #endif +#ifdef HAVE_UNISTD_H +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif -/* Compile with -DZLIB_DLL for Windows DLL support */ -#if (defined(_WINDOWS) || defined(WINDOWS)) && defined(ZLIB_DLL) -# include -# define EXPORT WINAPI -#else -# define EXPORT +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(inflate_blocks,"INBL") +# pragma map(inflate_blocks_new,"INBLNE") +# pragma map(inflate_blocks_free,"INBLFR") +# pragma map(inflate_blocks_reset,"INBLRE") +# pragma map(inflate_codes_free,"INCOFR") +# pragma map(inflate_codes,"INCO") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_flush,"INFLU") +# pragma map(inflate_mask,"INMA") +# pragma map(inflate_set_dictionary,"INSEDI2") +# pragma map(inflate_copyright,"INCOPY") +# pragma map(inflate_trees_bits,"INTRBI") +# pragma map(inflate_trees_dynamic,"INTRDY") +# pragma map(inflate_trees_fixed,"INTRFI") +# pragma map(inflate_trees_free,"INTRFR") #endif #endif /* _ZCONF_H */ /* --- zconf.h */ -#define ZLIB_VERSION "1.0.4P" +#define ZLIB_VERSION "1.1.4" /* The 'zlib' compression library provides in-memory compression and decompression functions, including integrity checks of the uncompressed data. This version of the library supports only one compression method - (deflation) but other algorithms may be added later and will have the same + (deflation) but other algorithms will be added later and will have the same stream interface. - For compression the application must provide the output buffer and - may optionally provide the input buffer for optimization. For decompression, - the application must provide the input buffer and may optionally provide - the output buffer for optimization. - Compression can be done in a single step if the buffers are large enough (for example if an input file is mmap'ed), or can be done by repeated calls of the compression function. In the latter case, the application must provide more input and/or consume the output (providing more output space) before each call. - The library does not install any signal handler. It is recommended to - add at least a handler for SIGSEGV when decompressing; the library checks - the consistency of the input data whenever possible but may go nuts - for some forms of corrupted input. + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. */ typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); @@ -308,6 +391,9 @@ typedef z_stream FAR *z_streamp; opaque value. zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + On 16-bit systems, the functions zalloc and zfree must be able to allocate exactly 65536 bytes, but will not be required to allocate more than this if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, @@ -327,7 +413,7 @@ typedef z_stream FAR *z_streamp; /* constants */ #define Z_NO_FLUSH 0 -#define Z_PARTIAL_FLUSH 1 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ #define Z_PACKET_FLUSH 2 #define Z_SYNC_FLUSH 3 #define Z_FULL_FLUSH 4 @@ -373,7 +459,7 @@ typedef z_stream FAR *z_streamp; /* basic functions */ -extern const char * EXPORT zlibVersion OF((void)); +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); /* The application can compare zlibVersion and ZLIB_VERSION for consistency. If the first character differs, the library code actually used is not compatible with the zlib.h header file used by the application. @@ -381,7 +467,7 @@ extern const char * EXPORT zlibVersion OF((void)); */ /* -extern int EXPORT deflateInit OF((z_streamp strm, int level)); +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); Initializes the internal stream state for compression. The fields zalloc, zfree and opaque must be initialized before by the caller. @@ -403,9 +489,15 @@ extern int EXPORT deflateInit OF((z_streamp strm, int level)); */ -extern int EXPORT deflate OF((z_streamp strm, int flush)); +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); /* - Performs one or both of the following actions: + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: - Compress more input starting at next_in and update next_in and avail_in accordingly. If not all input can be processed (because there is not @@ -427,30 +519,23 @@ extern int EXPORT deflate OF((z_streamp strm, int flush)); and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. - If the parameter flush is set to Z_PARTIAL_FLUSH, the current compression - block is terminated and flushed to the output buffer so that the - decompressor can get all input data available so far. For method 9, a future - variant on method 8, the current block will be flushed but not terminated. - Z_SYNC_FLUSH has the same effect as partial flush except that the compressed - output is byte aligned (the compressor can clear its internal bit buffer) - and the current block is always terminated; this can be useful if the - compressor has to be restarted from scratch after an interruption (in which - case the internal state of the compressor may be lost). - If flush is set to Z_FULL_FLUSH, the compression block is terminated, a - special marker is output and the compression dictionary is discarded; this - is useful to allow the decompressor to synchronize if one compressed block - has been damaged (see inflateSync below). Flushing degrades compression and - so should be used only when necessary. Using Z_FULL_FLUSH too often can - seriously degrade the compression. If deflate returns with avail_out == 0, - this function must be called again with the same value of the flush - parameter and more output space (updated avail_out), until the flush is - complete (deflate returns with non-zero avail_out). - - If the parameter flush is set to Z_PACKET_FLUSH, the compression - block is terminated, and a zero-length stored block is output, - omitting the length bytes (the effect of this is that the 3-bit type - code 000 for a stored block is output, and the output is then - byte-aligned). This is designed for use at the end of a PPP packet. + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + the compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). If the parameter flush is set to Z_FINISH, pending input is processed, pending output is flushed and deflate returns with Z_STREAM_END if there @@ -465,6 +550,9 @@ extern int EXPORT deflate OF((z_streamp strm, int flush)); 0.1% larger than avail_in plus 12 bytes. If deflate does not return Z_STREAM_END, then it must be called again as described above. + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + deflate() may update data_type if it can make a good guess about the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered binary. This field is only for information purposes and does not affect @@ -474,11 +562,12 @@ extern int EXPORT deflate OF((z_streamp strm, int flush)); processed or more output produced), Z_STREAM_END if all input has been consumed and all output has been produced (only when flush is set to Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example - if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible. + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). */ -extern int EXPORT deflateEnd OF((z_streamp strm)); +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any @@ -493,27 +582,35 @@ extern int EXPORT deflateEnd OF((z_streamp strm)); /* -extern int EXPORT inflateInit OF((z_streamp strm)); +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); Initializes the internal stream state for decompression. The fields - zalloc, zfree and opaque must be initialized before by the caller. If - zalloc and zfree are set to Z_NULL, inflateInit updates them to use default - allocation functions. + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. - inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_VERSION_ERROR if the zlib library version is incompatible - with the version assumed by the caller. msg is set to null if there is no - error message. inflateInit does not perform any decompression: this will be - done by inflate(). + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) */ -#if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL)) -#define inflate inflate_ppp /* FreeBSD already has an inflate :-( */ -#endif -extern int EXPORT inflate OF((z_streamp strm, int flush)); +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); /* - Performs one or both of the following actions: + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may some + introduce some output latency (reading input without producing any output) + except when forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: - Decompress more input starting at next_in and update next_in and avail_in accordingly. If not all input can be processed (because there is not @@ -534,14 +631,11 @@ extern int EXPORT inflate OF((z_streamp strm, int flush)); must be called again after making room in the output buffer because there might be more output pending. - If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH, - inflate flushes as much output as possible to the output buffer. The - flushing behavior of inflate is not specified for values of the flush - parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the - current implementation actually flushes as much output as possible - anyway. For Z_PACKET_FLUSH, inflate checks that once all the input data - has been consumed, it is expecting to see the length field of a stored - block; if not, it returns Z_DATA_ERROR. + If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much + output as possible to the output buffer. The flushing behavior of inflate is + not specified for values of the flush parameter other than Z_SYNC_FLUSH + and Z_FINISH, but the current implementation actually flushes as much output + as possible anyway. inflate() should normally be called until it returns Z_STREAM_END or an error. However if all decompression is to be performed in a single step @@ -554,22 +648,30 @@ extern int EXPORT inflate OF((z_streamp strm, int flush)); is never required, but can be used to inform inflate that a faster routine may be used for the single inflate() call. - inflate() returns Z_OK if some progress has been made (more input - processed or more output produced), Z_STREAM_END if the end of the - compressed data has been reached and all uncompressed output has been - produced, Z_NEED_DICT if a preset dictionary is needed at this point (see - inflateSetDictionary below), Z_DATA_ERROR if the input data was corrupted, - Z_STREAM_ERROR if the stream structure was inconsistent (for example if - next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, - Z_BUF_ERROR if no progress is possible or if there was not enough room in - the output buffer when Z_FINISH is used. In the Z_DATA_ERROR case, the - application may then call inflateSync to look for a good compression block. - In the Z_NEED_DICT case, strm->adler is set to the Adler32 value of the - dictionary chosen by the compressor. + If a preset dictionary is needed at this point (see inflateSetDictionary + below), inflate sets strm-adler to the adler32 checksum of the + dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise + it sets strm->adler to the adler32 checksum of all output produced + so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or + an error code as described below. At the end of the stream, inflate() + checks that its computed adler32 checksum is equal to that saved by the + compressor and returns Z_STREAM_END only if the checksum is correct. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect + adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent + (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if no progress is possible or if there was not + enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR + case, the application may then call inflateSync to look for a good + compression block. */ -extern int EXPORT inflateEnd OF((z_streamp strm)); +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any @@ -587,26 +689,25 @@ extern int EXPORT inflateEnd OF((z_streamp strm)); */ /* -extern int EXPORT deflateInit2 OF((z_streamp strm, - int level, - int method, - int windowBits, - int memLevel, - int strategy)); +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); This is another version of deflateInit with more compression options. The fields next_in, zalloc, zfree and opaque must be initialized before by the caller. The method parameter is the compression method. It must be Z_DEFLATED in - this version of the library. (Method 9 will allow a 64K history buffer and - partial block flushes.) + this version of the library. The windowBits parameter is the base two logarithm of the window size (the size of the history buffer). It should be in the range 8..15 for this - version of the library (the value 16 will be allowed for method 9). Larger - values of this parameter result in better compression at the expense of - memory usage. The default value is 15 if deflateInit is used instead. + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. The memLevel parameter specifies how much memory should be allocated for the internal compression state. memLevel=1 uses minimum memory but @@ -625,42 +726,35 @@ extern int EXPORT deflateInit2 OF((z_streamp strm, the compression ratio but not the correctness of the compressed output even if it is not set appropriately. - If next_in is not null, the library will use this buffer to hold also - some history information; the buffer must either hold the entire input - data, or have at least 1<<(windowBits+1) bytes and be writable. If next_in - is null, the library will allocate its own history buffer (and leave next_in - null). next_out need not be provided here but must be provided by the - application for the next call of deflate(). - - If the history buffer is provided by the application, next_in must - must never be changed by the application since the compressor maintains - information inside this buffer from call to call; the application - must provide more input only by increasing avail_in. next_in is always - reset by the library in this case. - - deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was - not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as - an invalid method). msg is set to null if there is no error message. - deflateInit2 does not perform any compression: this will be done by - deflate(). + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). */ -extern int EXPORT deflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); -/* - Initializes the compression dictionary (history buffer) from the given - byte sequence without producing any compressed output. This function must - be called immediately after deflateInit or deflateInit2, before any call - of deflate. The compressor and decompressor must use exactly the same +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same dictionary (see inflateSetDictionary). + The dictionary should consist of strings (byte sequences) that are likely to be encountered later in the data to be compressed, with the most commonly used strings preferably put towards the end of the dictionary. Using a - dictionary is most useful when the data to be compressed is short and - can be predicted with good accuracy; the data can then be compressed better - than with the default empty dictionary. In this version of the library, - only the last 32K bytes of the dictionary are used. + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. + Upon return of this function, strm->adler is set to the Adler32 value of the dictionary; the decompressor may later use this value to determine which dictionary has been used by the compressor. (The Adler32 value @@ -668,21 +762,16 @@ extern int EXPORT deflateSetDictionary OF((z_streamp strm, actually used by the compressor.) deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a - parameter is invalid (such as NULL dictionary) or the stream state - is inconsistent (for example if deflate has already been called for this - stream). deflateSetDictionary does not perform any compression: this will - be done by deflate(). + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). */ -extern int EXPORT deflateCopy OF((z_streamp dest, - z_streamp source)); +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); /* - Sets the destination stream as a complete copy of the source stream. If - the source stream is using an application-supplied history buffer, a new - buffer is allocated for the destination stream. The compressed output - buffer is always application-supplied. It's the responsibility of the - application to provide the correct values of next_out and avail_out for the - next call of deflate. + Sets the destination stream as a complete copy of the source stream. This function can be useful when several compression strategies will be tried, for example when there are several ways of pre-processing the input @@ -697,7 +786,7 @@ extern int EXPORT deflateCopy OF((z_streamp dest, destination. */ -extern int EXPORT deflateReset OF((z_streamp strm)); +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); /* This function is equivalent to deflateEnd followed by deflateInit, but does not free and reallocate all the internal compression state. @@ -708,14 +797,17 @@ extern int EXPORT deflateReset OF((z_streamp strm)); stream state was inconsistent (such as zalloc or state being NULL). */ -extern int EXPORT deflateParams OF((z_streamp strm, int level, int strategy)); +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); /* - Dynamically update the compression level and compression strategy. - This can be used to switch between compression and straight copy of - the input data, or to switch to a different kind of input data requiring - a different strategy. If the compression level is changed, the input - available so far is compressed with the old level (and may be flushed); - the new level will take effect only at the next call of deflate(). + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). Before the call of deflateParams, the stream state must be set as for a call of deflate(), since the currently available input may have to @@ -726,57 +818,38 @@ extern int EXPORT deflateParams OF((z_streamp strm, int level, int strategy)); if strm->avail_out was zero. */ -extern int EXPORT deflateOutputPending OF((z_streamp strm)); -/* - Returns the number of bytes of output which are immediately - available from the compressor (i.e. without any further input - or flush). -*/ - /* -extern int EXPORT inflateInit2 OF((z_streamp strm, - int windowBits)); +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); - This is another version of inflateInit with more compression options. The - fields next_out, zalloc, zfree and opaque must be initialized before by - the caller. + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. The windowBits parameter is the base two logarithm of the maximum window size (the size of the history buffer). It should be in the range 8..15 for - this version of the library (the value 16 will be allowed soon). The - default value is 15 if inflateInit is used instead. If a compressed stream - with a larger window size is given as input, inflate() will return with - the error code Z_DATA_ERROR instead of trying to allocate a larger window. - - If next_out is not null, the library will use this buffer for the history - buffer; the buffer must either be large enough to hold the entire output - data, or have at least 1< /* ADSP flags for read, write, and close routines */ #define ADSP_EOM 0x01 /* Sent or received EOM with data */ @@ -664,6 +664,7 @@ typedef struct { #define ADSPGETPEER ((AT_MID_ADSP<<8) | 238) #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE /* from h/adsp_adsp.h */ @@ -700,5 +701,6 @@ struct adsp_debug { int ad_sendWdwSeq; }; -#endif +#endif /* __APPLE_API_PRIVATE */ +#endif /* KERNEL */ #endif /* _NETAT_ADSP_H_ */ diff --git a/bsd/netat/adsp_internal.h b/bsd/netat/adsp_internal.h index 9b7c4e83c..268cbe068 100644 --- a/bsd/netat/adsp_internal.h +++ b/bsd/netat/adsp_internal.h @@ -21,8 +21,12 @@ */ #ifndef _NETAT_ADSP_INTERNAL_H_ #define _NETAT_ADSP_INTERNAL_H_ +#include + +#include #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE /* from h/adsp_portab.h */ @@ -50,7 +54,6 @@ typedef unsigned int dword; #define low(x) ((byte)(x)) #define hlword(h, l) (((byte)(l)) | (((byte)(h)) << 8)) -#define offsetof(typ,id) (size_t)&(((typ*)0)->id) /* * On a Mac, there is no need to byte-swap data on the network, so @@ -352,6 +355,7 @@ extern GLOBAL adspGlobal; /* Address of ptr to list of ccb's */ #define AT_ADSP_STREAMS ((CCB **)&(adspGlobal.ccbList)) +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ #endif /* _NETAT_ADSP_INTERNAL_H_ */ diff --git a/bsd/netat/adsp_stream.c b/bsd/netat/adsp_stream.c index 5aa9d3071..13811b3a8 100644 --- a/bsd/netat/adsp_stream.c +++ b/bsd/netat/adsp_stream.c @@ -424,7 +424,7 @@ int adsp_wput(gref, mp) case DDP_IOC_GET_CFG: /* respond to an DDP_IOC_GET_CFG sent on an adsp fd */ if (((xm = gbuf_cont(mp)) == NULL) && - (xm = gbuf_alloc(sizeof(at_inet_t), PRI_MED)) == NULL) { + (xm = gbuf_alloc(sizeof(ddp_addr_t), PRI_MED)) == NULL) { iocbp->ioc_rval = -1; adsp_iocnak(gref, mp, ENOBUFS); return 0; diff --git a/bsd/netat/appletalk.h b/bsd/netat/appletalk.h index d450f039a..7fbc4e38e 100644 --- a/bsd/netat/appletalk.h +++ b/bsd/netat/appletalk.h @@ -34,6 +34,7 @@ #ifndef _NETAT_APPLETALK_H_ #define _NETAT_APPLETALK_H_ +#include #include #include @@ -270,7 +271,8 @@ typedef struct at_state { } at_state_t; /* at_state_t 'flags' defines */ -#define AT_ST_STARTED 0x0001 +#define AT_ST_STARTED 0x0001 /* set if protocol is fully enabled */ +#define AT_ST_STARTING 0x0002 /* set if interfaces are configured */ #define AT_ST_MULTIHOME 0x0080 /* set if multihome mode */ #define AT_ST_ROUTER 0x0100 /* set if we are a router */ #define AT_ST_IF_CHANGED 0x0200 /* set when state of any I/F @@ -280,11 +282,13 @@ typedef struct at_state { #define AT_ST_NBP_CHANGED 0x1000 /* if nbp table changed (for SNMP)*/ #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE extern at_state_t at_state; /* global state of AT network */ #define ROUTING_MODE (at_state.flags & AT_ST_ROUTER) #define MULTIHOME_MODE (at_state.flags & AT_ST_MULTIHOME) #define MULTIPORT_MODE (ROUTING_MODE || MULTIHOME_MODE) +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ /* defines originally from h/at_elap.h */ diff --git a/bsd/netat/asp.h b/bsd/netat/asp.h index 780dffd57..a18a74d85 100644 --- a/bsd/netat/asp.h +++ b/bsd/netat/asp.h @@ -30,6 +30,7 @@ #ifndef _NETAT_ASP_H_ #define _NETAT_ASP_H_ +#include #define ASP_Version 0x100 @@ -125,6 +126,7 @@ union asp_primitives { }; #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE #define ASPSTATE_Close 0 #define ASPSTATE_Idle 1 @@ -212,5 +214,6 @@ typedef struct asp_scb { atevent_t delay_event; } asp_scb_t; +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ #endif /* _NETAT_ASP_H_ */ diff --git a/bsd/netat/asp_proto.c b/bsd/netat/asp_proto.c index fc1efd738..c495412de 100644 --- a/bsd/netat/asp_proto.c +++ b/bsd/netat/asp_proto.c @@ -1104,7 +1104,7 @@ asp_ack_reply(gref, mioc) if ((m = scb->sess_ioc) == 0) { scb->sess_ioc = mdata; if (scb->get_wait) - thread_wakeup(&scb->event); + wakeup(&scb->event); else atalk_notify_sel(gref); } else { @@ -1317,7 +1317,7 @@ asp_ack_reply(gref, mioc) gbuf_freem(mioc); ATDISABLE(s, scb->lock); if (scb->get_wait) - thread_wakeup(&scb->event); + wakeup(&scb->event); else atalk_notify_sel(gref); ATENABLE(s, scb->lock); @@ -1753,7 +1753,7 @@ asp_hangup(scb) */ if (scb->rem_addr.node) { if (scb->get_wait) { - thread_wakeup(&scb->event); + wakeup(&scb->event); ATENABLE(s, scb->lock); } else { ATENABLE(s, scb->lock); @@ -1882,7 +1882,7 @@ asp_putnext(gref, mproto) scb->snd_stop = 1; if (scb->get_wait) { - thread_wakeup(&scb->event); + wakeup(&scb->event); ATENABLE(s, scb->lock); } else if (mproto == scb->sess_ioc) { ATENABLE(s, scb->lock); diff --git a/bsd/netat/at.c b/bsd/netat/at.c index 00feb623e..089fd3889 100644 --- a/bsd/netat/at.c +++ b/bsd/netat/at.c @@ -38,8 +38,6 @@ #include #include #include -#include -#include #include #include @@ -51,6 +49,8 @@ #include #include +#include + extern int at_ioctl(struct atpcb *, u_long, caddr_t, int fromKernel); extern int routerStart(at_kern_err_t *); extern void elap_offline(at_ifaddr_t *); @@ -246,13 +246,13 @@ int at_control(so, cmd, data, ifp) /* check the zone name */ if (MULTIPORT_MODE) { short zno; - char ifs_in_zone[IF_TOTAL_MAX]; + at_ifnames_t ifs_in_zone; if (!(zno = zt_find_zname(&defzonep->zonename))) return(EINVAL); - getIfUsage(zno-1, ifs_in_zone); - if (!ifs_in_zone[ifID->ifPort]) + getIfUsage(zno-1, &ifs_in_zone); + if (!ifs_in_zone.at_if[ifID->ifPort]) return(EINVAL); ifID->ifDefZone = zno+1; } else { @@ -271,6 +271,10 @@ int at_control(so, cmd, data, ifp) } ifID->ifZoneName = defzonep->zonename; (void)regDefaultZone(ifID); + + /* AppleTalk zone was changed. Send event with zone info. */ + atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ZONEUPDATED, 0, &(ifID->ifZoneName)); + return(0); } } else @@ -346,18 +350,20 @@ int at_control(so, cmd, data, ifp) this zone */ int finished = FALSE; int zno; - char ifs_in_zone[IF_TOTAL_MAX]; + at_ifnames_t ifs_in_zone; if (!(zno = zt_find_zname(&nve.zone))) { return(EINVAL); } - getIfUsage(zno-1, ifs_in_zone); + getIfUsage(zno-1, &ifs_in_zone); TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) { - if (!ifs_in_zone[ifID->ifPort]) + if (!ifs_in_zone.at_if[ifID->ifPort]) /* zone doesn't match */ continue; - else + else { finished = TRUE; + break; + } } if (!finished) return(EINVAL); @@ -523,8 +529,8 @@ int at_control(so, cmd, data, ifp) break; } case AIOCSTOPATALK: - { - int *count_only = (int *)data, + { + int *count_only = (int *)data, ret; /* check for root access */ @@ -532,13 +538,26 @@ int at_control(so, cmd, data, ifp) return(EACCES); ret = ddp_shutdown(*count_only); - if (*count_only) { + + if (*count_only != 0) + { *count_only = ret; return(0); - } else - return((ret == 0)? 0 : EBUSY); + } + else + { + if (ret == 0) + { + /* AppleTalk was successfully shut down. Send event. */ + atalk_post_msg(0, KEV_ATALK_DISABLED, 0, 0); + return 0; + } + else + return EBUSY; + } + break; - } + } case SIOCSIFADDR: /* check for root access */ @@ -549,7 +568,7 @@ int at_control(so, cmd, data, ifp) else { int s; if (xpatcnt == 0) { - at_state.flags |= AT_ST_STARTED; + at_state.flags |= AT_ST_STARTING; ddp_brt_init(); } @@ -612,18 +631,18 @@ int at_control(so, cmd, data, ifp) /* complete the initialization started in SIOCSIFADDR */ case AIOCSIFADDR: - { + { at_if_cfg_t *cfgp = (at_if_cfg_t *)data; - if (!(at_state.flags & AT_ST_STARTED)) + if (!(at_state.flags & AT_ST_STARTING)) return(ENOTREADY); if (!(ifID = find_ifID(cfgp->ifr_name))) return(EINVAL); - + return(lap_online(ifID, cfgp)); break; - } + } #ifdef NOT_YET /* *** this can't be added until AT can handle dynamic addition and @@ -679,3 +698,36 @@ int at_control(so, cmd, data, ifp) return(error); } + +/* From dlil_post_msg() */ +void atalk_post_msg(struct ifnet *ifp, u_long event_code, struct at_addr *address, at_nvestr_t *zone) +{ + struct kev_atalk_data at_event_data; + struct kev_msg ev_msg; + + ev_msg.vendor_code = KEV_VENDOR_APPLE; + ev_msg.kev_class = KEV_NETWORK_CLASS; + ev_msg.kev_subclass = KEV_ATALK_SUBCLASS; + ev_msg.event_code = event_code; + + bzero(&at_event_data, sizeof(struct kev_atalk_data)); + + if (ifp != 0) { + strncpy(&at_event_data.link_data.if_name[0], ifp->if_name, IFNAMSIZ); + at_event_data.link_data.if_family = ifp->if_family; + at_event_data.link_data.if_unit = (unsigned long) ifp->if_unit; + } + + if (address != 0) { + at_event_data.node_data.address = *address; + } + else if (zone != 0) { + at_event_data.node_data.zone = *zone; + } + + ev_msg.dv[0].data_length = sizeof(struct kev_atalk_data); + ev_msg.dv[0].data_ptr = &at_event_data; + ev_msg.dv[1].data_length = 0; + + kev_post_msg(&ev_msg); +} diff --git a/bsd/netat/at_aarp.h b/bsd/netat/at_aarp.h index 4490830d0..c7fd53524 100644 --- a/bsd/netat/at_aarp.h +++ b/bsd/netat/at_aarp.h @@ -21,6 +21,7 @@ */ #ifndef _NETAT_AT_AARP_H_ #define _NETAT_AT_AARP_H_ +#include /* * Copyright (c) 1988, 1989 Apple Computer, Inc. */ @@ -174,10 +175,12 @@ typedef struct { ) #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE int aarp_chk_addr(at_ddp_t *, at_ifaddr_t *); int aarp_rcv_pkt(aarp_pkt_t *, at_ifaddr_t *); +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ #endif /* _NETAT_AT_AARP_H_ */ diff --git a/bsd/netat/at_config.h b/bsd/netat/at_config.h index 9514c64a7..b9f6abef3 100644 --- a/bsd/netat/at_config.h +++ b/bsd/netat/at_config.h @@ -25,6 +25,7 @@ #ifndef _NETAT_AT_CONFIG_H_ #define _NETAT_AT_CONFIG_H_ +#include /* originally from if_cnt.h * diff --git a/bsd/netat/at_ddp_brt.h b/bsd/netat/at_ddp_brt.h index 7cc33f78f..0b40c9893 100644 --- a/bsd/netat/at_ddp_brt.h +++ b/bsd/netat/at_ddp_brt.h @@ -26,6 +26,8 @@ #ifndef _NETAT_AT_DDP_BRT_H_ #define _NETAT_AT_DDP_BRT_H_ +#include +#ifdef __APPLE_API_PRIVATE typedef struct { int age_flag; @@ -78,5 +80,6 @@ typedef struct { /* Best Router Cache */ extern ddp_brt_t at_ddp_brt[BRTSIZE]; +#endif /* __APPLE_API_PRIVATE */ #endif /* _NETAT_AT_DDP_BRT_H_ */ diff --git a/bsd/netat/at_pat.h b/bsd/netat/at_pat.h index 97a535b2e..107b3857d 100644 --- a/bsd/netat/at_pat.h +++ b/bsd/netat/at_pat.h @@ -26,6 +26,7 @@ #ifndef _NETAT_AT_PAT_H_ #define _NETAT_AT_PAT_H_ +#include /* This is header for the PAT module. This contains a table of pointers that * should get initialized with the BNET stuff and the ethernet driver. The diff --git a/bsd/netat/at_pcb.h b/bsd/netat/at_pcb.h index 489d35961..9a4d4297a 100644 --- a/bsd/netat/at_pcb.h +++ b/bsd/netat/at_pcb.h @@ -58,7 +58,9 @@ */ /* at_pcb.h */ +#include +#ifdef __APPLE_API_PRIVATE /* * Common structure pcb for internet protocol implementation. * Here are stored pointers to local and foreign host table @@ -101,6 +103,7 @@ struct atpcb { }; #define sotoatpcb(so)((struct atpcb *)(so)->so_pcb) +#endif /* __APPLE_API_PRIVATE */ /* ddp_flags */ #define DDPFLG_CHKSUM 0x01 /* DDP checksums to be used on this connection */ @@ -109,10 +112,12 @@ struct atpcb { #define DDPFLG_HDRINCL 0x08 /* user supplies entire DDP header */ #define DDPFLG_STRIPHDR 0x200 /* drop DDP header on receive (raw) */ +#ifdef __APPLE_API_PRIVATE #ifdef KERNEL typedef struct atpcb gref_t; int at_pcballoc __P((struct socket *, struct atpcb *)); int at_pcbdetach __P((struct atpcb *)); int at_pcbbind __P((struct atpcb *, struct sockaddr *)); -#endif +#endif /* KERNEL */ +#endif /* __APPLE_API_PRIVATE */ diff --git a/bsd/netat/at_snmp.h b/bsd/netat/at_snmp.h index fbabd69c4..5e4bcb09e 100644 --- a/bsd/netat/at_snmp.h +++ b/bsd/netat/at_snmp.h @@ -21,6 +21,7 @@ */ #ifndef _NETAT_AT_SNMP_H_ #define _NETAT_AT_SNMP_H_ +#include #define MAX_PHYS_ADDR_SIZE 6 /* maximum physical addr size */ #define MAX_IFS 25 /* max # interfaces */ diff --git a/bsd/netat/at_var.h b/bsd/netat/at_var.h index 072377c0a..40c0fe696 100644 --- a/bsd/netat/at_var.h +++ b/bsd/netat/at_var.h @@ -23,6 +23,8 @@ * Copyright (c) 1998 Apple Computer, Inc. */ +#include +#ifdef __APPLE_API_PRIVATE #include /* at_var.h */ @@ -277,3 +279,27 @@ int ddp_ctloutput __P((struct socket *, struct sockopt *)); void ddp_init __P((void));; void ddp_slowtimo __P((void)); #endif + +/* + * Define AppleTalk event subclass and specific AppleTalk events. + */ + +#define KEV_ATALK_SUBCLASS 5 + +#define KEV_ATALK_ENABLED 1 /* AppleTalk enabled from user space - node/net set and valid */ +#define KEV_ATALK_DISABLED 2 /* AppleTalk disabled from user space */ +#define KEV_ATALK_ZONEUPDATED 3 /* Zone for this node set/changed */ +#define KEV_ATALK_ROUTERUP 4 /* Seed router found with valid cable range */ +#define KEV_ATALK_ROUTERUP_INVALID 5 /* Seed router found with invalid cable range */ +#define KEV_ATALK_ROUTERDOWN 6 /* Seed router down */ +#define KEV_ATALK_ZONELISTCHANGED 7 /* Zone list changed by router */ + +struct kev_atalk_data { + struct net_event_data link_data; + union { + struct at_addr address; + at_nvestr_t zone; + } node_data; +}; + +#endif /* __APPLE_API_PRIVATE */ diff --git a/bsd/netat/atp.h b/bsd/netat/atp.h index 476e926b7..6eb0af457 100644 --- a/bsd/netat/atp.h +++ b/bsd/netat/atp.h @@ -46,6 +46,7 @@ #ifndef _NETAT_ATP_H_ #define _NETAT_ATP_H_ +#include /* ATP function codes */ @@ -184,7 +185,7 @@ typedef struct { #define ATP_GETREQUEST 3 #ifdef KERNEL - +#ifdef __APPLE_API_PRIVATE /* @@ -403,19 +404,18 @@ struct atp_state { #ifdef ATP_DECLARE struct atp_trans *atp_trans_free_list = NULL; /* free transactions */ struct atp_rcb *atp_rcb_free_list = NULL; /* free rcbs */ -static struct atp_state *atp_free_list = NULL; /* free atp states */ +struct atp_state *atp_free_list = NULL; /* free atp states */ struct atp_trans_qhead atp_trans_abort; /* aborted trans list */ -static struct atp_rcb atp_rcb_data[NATP_RCB]; -static struct atp_state atp_state_data[NATP_STATE]; - +struct atp_rcb* atp_rcb_data = NULL; +struct atp_state* atp_state_data=NULL; #else extern struct atp_trans *atp_trans_free_list; /* free transactions */ extern struct atp_rcb *atp_rcb_free_list; /* free rcbs */ extern struct atp_state *atp_free_list; /* free atp states */ -extern struct atp_rcb atp_rcb_data[]; -extern struct atp_state atp_state_data[]; +extern struct atp_rcb* atp_rcb_data; +extern struct atp_state* atp_state_data; extern struct atp_trans_qhead atp_trans_abort; /* aborting trans list */ extern void atp_req_timeout(); @@ -456,5 +456,6 @@ void atp_timout(void (*func)(), struct atp_trans *, int); void atp_untimout(void (*func)(), struct atp_trans *); int atp_tid(struct atp_state *); +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ #endif /* _NETAT_ATP_H_ */ diff --git a/bsd/netat/atp_misc.c b/bsd/netat/atp_misc.c index 0bc9447b3..f8d34a439 100644 --- a/bsd/netat/atp_misc.c +++ b/bsd/netat/atp_misc.c @@ -112,7 +112,7 @@ l_notify: ATENABLE(s, atp->atp_lock); gbuf_freem(m); if (trp->tr_rsp_wait) - thread_wakeup(&trp->tr_event); + wakeup(&trp->tr_event); break; } ATENABLE(s, atp->atp_lock); @@ -184,7 +184,7 @@ register struct atp_trans *trp; if (trp->tr_rsp_wait) { trp->tr_state = TRANS_ABORTING; ATP_Q_APPEND(atp_trans_abort, trp, tr_list); - thread_wakeup(&trp->tr_event); + wakeup(&trp->tr_event); ATENABLE(s, atpgen_lock); return; } diff --git a/bsd/netat/atp_open.c b/bsd/netat/atp_open.c index de927389c..5271592ab 100644 --- a/bsd/netat/atp_open.c +++ b/bsd/netat/atp_open.c @@ -42,6 +42,7 @@ #include #include #include +#include /* for kernel_map */ #include #include @@ -109,15 +110,7 @@ void atp_init() atp_used_list = 0; atp_trans_abort.head = NULL; atp_trans_abort.tail = NULL; - - for (i = 0; i < NATP_RCB; i++) { - atp_rcb_data[i].rc_list.next = atp_rcb_free_list; - atp_rcb_free_list = &atp_rcb_data[i]; - } - for (i = 0; i < NATP_STATE; i++) { - atp_state_data[i].atp_trans_waiting = atp_free_list; - atp_free_list = &atp_state_data[i]; - } + atp_need_rel.head = NULL; atp_need_rel.tail = NULL; @@ -137,7 +130,41 @@ int atp_open(gref, flag) int flag; { register struct atp_state *atp; - register int s; + register int s, i; + vm_offset_t temp; + + /* + * Allocate and init state and reply control block lists + * if this is the first open + */ + if (atp_rcb_data == NULL) { + if (kmem_alloc(kernel_map, &temp, sizeof(struct atp_rcb) * NATP_RCB) != KERN_SUCCESS) + return(ENOMEM); + if (atp_rcb_data == NULL) { /* in case we lost funnel while allocating */ + bzero((caddr_t)temp, sizeof(struct atp_rcb) * NATP_RCB); + atp_rcb_data = (struct atp_rcb*)temp; + for (i = 0; i < NATP_RCB; i++) { + atp_rcb_data[i].rc_list.next = atp_rcb_free_list; + atp_rcb_free_list = &atp_rcb_data[i]; + } + } else + kmem_free(kernel_map, temp, sizeof(struct atp_rcb) * NATP_RCB); /* already allocated by another process */ + } + + if (atp_state_data == NULL) { + if (kmem_alloc(kernel_map, &temp, sizeof(struct atp_state) * NATP_STATE) != KERN_SUCCESS) + return(ENOMEM); + if (atp_state_data == NULL) { + bzero((caddr_t)temp, sizeof(struct atp_state) * NATP_STATE); + atp_state_data = (struct atp_state*) temp; + for (i = 0; i < NATP_STATE; i++) { + atp_state_data[i].atp_trans_waiting = atp_free_list; + atp_free_list = &atp_state_data[i]; + } + } else + kmem_free(kernel_map, temp, sizeof(struct atp_state) * NATP_STATE); + } + /* * If no atp structure available return failure diff --git a/bsd/netat/atp_read.c b/bsd/netat/atp_read.c index 200577dbf..12f93ee1c 100644 --- a/bsd/netat/atp_read.c +++ b/bsd/netat/atp_read.c @@ -539,7 +539,7 @@ register struct atp_trans *trp; if (trp->tr_bdsp == NULL) { gbuf_freem(m); if (trp->tr_rsp_wait) - thread_wakeup(&trp->tr_event); + wakeup(&trp->tr_event); } else { gbuf_set_type(m, MSG_IOCACK); ((ioc_t *)gbuf_rptr(m))->ioc_count = 0; diff --git a/bsd/netat/aurp.h b/bsd/netat/aurp.h index 3b64639c8..9bc832279 100644 --- a/bsd/netat/aurp.h +++ b/bsd/netat/aurp.h @@ -29,6 +29,7 @@ #ifndef _NETAT_AURP_H_ #define _NETAT_AURP_H_ +#include /* * AURP device ioctl (I_STR) 'subcommands' @@ -49,6 +50,7 @@ #define AURP_MAXNETACCESS 64 #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE #define AURPCODE_REG 0 #define AURPCODE_RTMPPKT 1 @@ -163,8 +165,6 @@ typedef struct { unsigned short flags; } aurp_hdr_t; -#ifdef KERNEL - #ifdef AURP_SUPPORT extern atlock_t aurpgen_lock; @@ -254,8 +254,6 @@ int AURPgetri __P((short next_entry, unsigned char *buf, short *len)); int AURPsetri __P((unsigned char node, gbuf_t *m)); int AURPupdateri __P((unsigned char node, gbuf_t *m)); -#endif /* KERNEL */ - /* AURP header for IP tunneling */ typedef struct aurp_domain { char dst_length; @@ -285,5 +283,6 @@ typedef struct aurp_domain /****### LD 9/26/97*/ extern struct aurp_global_t aurp_global; +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ #endif /* _NETAT_AURP_H_ */ diff --git a/bsd/netat/aurp_aurpd.c b/bsd/netat/aurp_aurpd.c index eca9c3757..870403244 100644 --- a/bsd/netat/aurp_aurpd.c +++ b/bsd/netat/aurp_aurpd.c @@ -310,7 +310,7 @@ void aurp_wakeup(struct socket *so, register caddr_t p, int state) ("aurp_wakeup: bit 0x%x, aurp_global.event now 0x%x\n", bit, aurp_global.event)); - thread_wakeup(&aurp_global.event_anchor); + wakeup(&aurp_global.event_anchor); } /* diff --git a/bsd/netat/ddp.c b/bsd/netat/ddp.c index 4be1a6484..93da77ebf 100644 --- a/bsd/netat/ddp.c +++ b/bsd/netat/ddp.c @@ -542,6 +542,14 @@ int ddp_output(mp, src_socket, src_addr_included) m = *mp; ddp = (at_ddp_t *)gbuf_rptr(m); + + if (!ifID) { + /* Device/Interface not configured */ + dPrintf(D_M_DDP, D_L_ERROR, ("Device/Interface not configured")); + error = ENXIO; + gbuf_freel(*mp); + goto exit_ddp_output; + } if ((ddp->dst_socket > (unsigned) (DDP_SOCKET_LAST + 1)) || (ddp->dst_socket < DDP_SOCKET_1st_RESERVED)) { diff --git a/bsd/netat/ddp.h b/bsd/netat/ddp.h index 142068932..ad79d612b 100644 --- a/bsd/netat/ddp.h +++ b/bsd/netat/ddp.h @@ -30,6 +30,7 @@ #ifndef _NETAT_DDP_H_ #define _NETAT_DDP_H_ +#include /* Header and data sizes */ @@ -124,6 +125,7 @@ typedef struct at_ddp_stats { #endif #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE #define DDP_MIN_NETWORK 0x0001 #define DDP_MAX_NETWORK 0xfffe @@ -182,5 +184,6 @@ void ddp_bit_reverse(unsigned char *); /* in ddp_lap.c */ int ddp_shutdown(int); +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ #endif /* _NETAT_DDP_H_ */ diff --git a/bsd/netat/ddp_aarp.c b/bsd/netat/ddp_aarp.c index af578e3be..430432ea6 100644 --- a/bsd/netat/ddp_aarp.c +++ b/bsd/netat/ddp_aarp.c @@ -58,6 +58,8 @@ #include #include +#include + static int probing; /* Following two variables are used to keep track of how many dynamic addresses * we have tried out at startup. @@ -158,7 +160,13 @@ int aarp_init2(elapp) elapp->ifThisNode = elapp->initial_addr; probing = PROBE_DONE; - + + /* AppleTalk was successfully started up. Send event with node and net. */ + atalk_post_msg(elapp->aa_ifp, KEV_ATALK_ENABLED, &(elapp->ifThisNode), 0); + + /* Set global flag */ + at_state.flags |= AT_ST_STARTED; + return(0); } diff --git a/bsd/netat/ddp_lap.c b/bsd/netat/ddp_lap.c index 80a700a67..2cdddeb8d 100644 --- a/bsd/netat/ddp_lap.c +++ b/bsd/netat/ddp_lap.c @@ -56,6 +56,8 @@ #include #include #include +#include /* for kernel_map */ + #include #include @@ -77,6 +79,8 @@ #include #include +#include + /* globals */ at_ifaddr_t at_interfaces[IF_TOTAL_MAX]; @@ -948,7 +952,7 @@ static void elap_online2(elapp) elapp->ifState = LAP_ONLINE_ZONELESS; elapp->startup_inprogress = FALSE; - thread_wakeup(&elapp->startup_inprogress); + wakeup(&elapp->startup_inprogress); dPrintf(D_M_ELAP, D_L_STARTUP_INFO, ("elap_online: ack 3\n")); return; } @@ -1073,8 +1077,8 @@ int ddp_shutdown(count_only) struct atp_state *atp, *atp_next; CCB *sp, *sp_next; gref_t *gref; - int i, s, - active_skts = 0; /* count of active pids for non-socketized + vm_offset_t temp_rcb_data, temp_state_data; + int i, s, active_skts = 0; /* count of active pids for non-socketized AppleTalk protocols */ extern int aarp_sched_probe(); @@ -1196,6 +1200,8 @@ int ddp_shutdown(count_only) } at_state.flags = 0; /* make sure inits are done on restart */ + + wakeup(&ifID_home->startup_inprogress); /* if rtmp_router_start still starting up */ /* from original ddp_shutdown() */ routershutdown(); @@ -1205,6 +1211,8 @@ int ddp_shutdown(count_only) CleanupGlobals(); adspInited = 0; } + + dPrintf(D_M_DDP, D_L_VERBOSE, ("DDP shutdown completed")); /* @@ -1223,6 +1231,29 @@ int ddp_shutdown(count_only) elap_offline(ifID); } ddp_start(); + + /* free buffers for large arrays used by atp. + * to prevent a race condition if the funnel is dropped + * while calling kmem_free, the fields are grabbed and + * zeroed first. + */ + if (atp_rcb_data != NULL) { + temp_rcb_data = (vm_offset_t)atp_rcb_data; + atp_rcb_data = NULL; + atp_rcb_free_list = NULL; + } else + temp_rcb_data = NULL; + if (atp_state_data != NULL) { + temp_state_data = (vm_offset_t)atp_state_data; + atp_state_data = NULL; + atp_free_list = NULL; + } else + temp_state_data = NULL; + + if (temp_rcb_data) + kmem_free(kernel_map, temp_rcb_data, sizeof(struct atp_rcb) * NATP_RCB); + if (temp_state_data) + kmem_free(kernel_map, temp_state_data, sizeof(struct atp_state) * NATP_STATE); splx(s); return(0); @@ -1291,6 +1322,10 @@ void ZIPwakeup(elapp, ZipError) switch (ZipError) { case 0 : /* success */ elapp->ifState = LAP_ONLINE; + + /* Send event with zone info. */ + atalk_post_msg(elapp->aa_ifp, KEV_ATALK_ZONEUPDATED, 0, &(elapp->ifZoneName)); + break; case ZIP_RE_AARP : /* instead of goto re_aarp; */ @@ -1298,7 +1333,7 @@ void ZIPwakeup(elapp, ZipError) appletalk node addr */ if ((elapp->startup_error = re_aarp(elapp))) { elapp->startup_inprogress = FALSE; - thread_wakeup(&elapp->startup_inprogress); + wakeup(&elapp->startup_inprogress); dPrintf(D_M_ELAP, D_L_STARTUP_INFO, ("elap_online: ack 2\n")); } @@ -1309,7 +1344,7 @@ void ZIPwakeup(elapp, ZipError) if (ZipError != ZIP_RE_AARP) { elapp->startup_error = error; elapp->startup_inprogress = FALSE; - thread_wakeup(&elapp->startup_inprogress); + wakeup(&elapp->startup_inprogress); dPrintf(D_M_ELAP, D_L_STARTUP_INFO, ("elap_online: ifZipError=%d\n", error)); } @@ -1342,7 +1377,7 @@ void AARPwakeup(probe_cb) ddp_rem_if(elapp); elapp->startup_error = EADDRNOTAVAIL; elapp->startup_inprogress = FALSE; - thread_wakeup(&elapp->startup_inprogress); + wakeup(&elapp->startup_inprogress); dPrintf(D_M_ELAP, D_L_STARTUP_INFO, ("elap_online: ack 2\n")); } else { dPrintf(D_M_ELAP,D_L_STARTUP_INFO, diff --git a/bsd/netat/ddp_nbp.c b/bsd/netat/ddp_nbp.c index 2d7e98c73..1bfec9e17 100644 --- a/bsd/netat/ddp_nbp.c +++ b/bsd/netat/ddp_nbp.c @@ -1512,17 +1512,17 @@ int nbp_mh_reg(nbpP) /* multihoming mode with a specific zone specified */ /* see which segments (interfaces) are seeded for this zone */ int zno; - char ifs_in_zone[IF_TOTAL_MAX]; + at_ifnames_t ifs_in_zone; if (!(zno = zt_find_zname(&nve.zone))) { dPrintf(D_M_NBP_LOW, D_L_WARNING, ("nbp_mh_reg: didn't find zone name\n")); return(EINVAL); } - getIfUsage(zno-1, ifs_in_zone); + getIfUsage(zno-1, &ifs_in_zone); - /* now find the first matching interface */ + /* now find the matching interfaces */ TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) { - if (!ifs_in_zone[ifID->ifPort]) + if (!ifs_in_zone.at_if[ifID->ifPort]) /* zone doesn't match */ continue; else @@ -1551,10 +1551,11 @@ int nbp_mh_reg(nbpP) continue; if (nbp_new_nve_entry(&nve, ifID) == 0) registered++; - } - if (registered && !nbpP->addr.net && !nbpP->addr.node) { - nbpP->addr.net = ifID->ifThisNode.s_net; - nbpP->addr.node = ifID->ifThisNode.s_node; + if (registered && !nbpP->addr.net && !nbpP->addr.node) { + nbpP->addr.net = ifID->ifThisNode.s_net; + nbpP->addr.node = ifID->ifThisNode.s_node; + } + } } nbpP->unique_nbp_id = (registered > 1)? 0: nve.unique_nbp_id; diff --git a/bsd/netat/ddp_proto.c b/bsd/netat/ddp_proto.c index e9073ff41..7a6298a4d 100644 --- a/bsd/netat/ddp_proto.c +++ b/bsd/netat/ddp_proto.c @@ -108,7 +108,7 @@ void ddp_putmsg(gref, mp) if (gbuf_cont(mp)) gbuf_freem(gbuf_cont(mp)); if ((gbuf_cont(mp) = - gbuf_alloc(sizeof(at_inet_t), + gbuf_alloc(sizeof(ddp_addr_t), PRI_MED)) == NULL) { ioc_ack(ENOBUFS, mp, gref); break; diff --git a/bsd/netat/ddp_r_rtmp.c b/bsd/netat/ddp_r_rtmp.c index 4c74b7fae..666a59998 100644 --- a/bsd/netat/ddp_r_rtmp.c +++ b/bsd/netat/ddp_r_rtmp.c @@ -65,6 +65,8 @@ #include #include +#include + extern void (*ddp_AURPsendx)(); extern at_ifaddr_t *aurp_ifID; extern at_ifaddr_t *ifID_table[]; @@ -1387,7 +1389,7 @@ int rtmp_router_start(keP) /* set the right net and node for each port */ Entry->NextIRNet = ifID->ifThisNode.s_net; Entry->NextIRNode= ifID->ifThisNode.s_node; - + dPrintf(D_M_RTMP, D_L_STARTUP, ("rtmp_router_start: bring port=%d [%d.%d]... on line\n", ifID->ifPort, ifID->ifThisNode.s_net, @@ -1430,6 +1432,12 @@ int rtmp_router_start(keP) != EWOULDBLOCK) { goto error; } + + /* Is the stack still up ? */ + if (!(at_state.flags & AT_ST_STARTED) || !ifID_home) { + err = ECONNABORTED; + goto error; + } startZoneInfo: err = 0; @@ -1470,6 +1478,12 @@ startZoneInfo: != EWOULDBLOCK) { goto error; } + + /* Is the stack still up ? */ + if (!(at_state.flags & AT_ST_STARTED) || !ifID_home) { + err = ECONNABORTED; + goto error; + } err = 0; router_starting_timer++; @@ -1514,6 +1528,9 @@ startZoneInfo: if ((ifID == ifID_home) || MULTIHOME_MODE) { ifID->ifZoneName = ZT_table[Index-1].Zone; (void)regDefaultZone(ifID); + + /* Send zone change event */ + atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ZONEUPDATED, 0, &(ifID->ifZoneName)); } } } diff --git a/bsd/netat/ddp_r_zip.c b/bsd/netat/ddp_r_zip.c index 573fda9e5..12d6aee82 100644 --- a/bsd/netat/ddp_r_zip.c +++ b/bsd/netat/ddp_r_zip.c @@ -68,6 +68,8 @@ #include #include +#include + static void zip_reply_to_getmyzone(); extern int at_reg_mcast(), at_unreg_mcast(); @@ -723,6 +725,10 @@ void zip_router_input (m, ifID) bcopy((caddr_t)new_zone, (caddr_t)&ifID->ifZoneName, new_zone_len+1); + /* Send network zone change event and new zone for this interface. */ + atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ZONEUPDATED, 0, &(ifID->ifZoneName)); + atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ZONELISTCHANGED, 0, 0); + /* add the new zone to the list of local zones */ if (!MULTIPORT_MODE && !DEFAULT_ZONE(&ifID->ifZoneName)) (void)setLocalZones(&ifID->ifZoneName, @@ -864,8 +870,10 @@ static void zip_netinfo_reply (netinfo, ifID) * to us. */ /* *** Do we really need to check this? *** */ - if (!zonename_equal((at_nvestr_t *)netinfo->data, &ifID->ifZoneName)) + if (!zonename_equal((at_nvestr_t *)netinfo->data, &ifID->ifZoneName)) { + dPrintf(D_M_ZIP, D_L_INFO, ("zip_netinfo_reply, !zonename_equal!!!")); return; + } ifID->ifThisCableStart = NET_VALUE(netinfo->cable_range_start); ifID->ifThisCableEnd = NET_VALUE(netinfo->cable_range_end); @@ -932,6 +940,12 @@ static void zip_netinfo_reply (netinfo, ifID) ZIPwakeup(ifID, ZIP_RE_AARP); return; } + + if (!ifID->startup_inprogress) { + /* Send event with zone info. This covers case where we get zone info + after startup. During startup this event is sent from ZIPwakeup. */ + atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ZONEUPDATED, 0, &(ifID->ifZoneName)); + } ZIPwakeup(ifID, 0); /* no error */ return; @@ -963,6 +977,10 @@ int zip_control (ifID, control) ifID->ifZoneName.len = 1; ifID->ifZoneName.str[0] = '*'; ifID->ifZoneName.str[1] = '\0'; + + /* Send event with zone info. */ + atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ZONEUPDATED, 0, &(ifID->ifZoneName)); + break; default : break; diff --git a/bsd/netat/ddp_rtmp.c b/bsd/netat/ddp_rtmp.c index 59e7a25fd..c1b40b63e 100644 --- a/bsd/netat/ddp_rtmp.c +++ b/bsd/netat/ddp_rtmp.c @@ -55,6 +55,8 @@ #include #include +#include + extern void rtmp_router_input(); /****************************************************************/ @@ -141,16 +143,24 @@ void trackrouter(ifID, net, node) unused = router; } if (unused) { - router_added++; + router_added++; + if (ifID->ifARouter.s_net == 0) { + /* Send event that this interface just got a router. This does not + discriminate on whether this router is valid or not. If it is not + valid rtmp_input will send a KEV_ATALK_ROUTERUP_INVALID event. */ + atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ROUTERUP, 0, 0); + } + unused->ifID = ifID; NET(unused) = net; NODE(unused) = node; + ifID->ifRouterState = ROUTER_AROUND; timeout(ddp_age_router, (caddr_t) unused, 50*SYS_HZ); + if (NET(ifID) == 0 && NODE(ifID) == 0) { NET(ifID) = net; NODE(ifID) = node; - ifID->ifRouterState = ROUTER_AROUND; } } } @@ -189,24 +199,30 @@ void ddp_age_router(deadrouter) newrouter = NULL; } if (newrouter) { + /* Set our router to another on the list and go on with life */ NET(ourrouter) = NET(newrouter); NODE(ourrouter) = NODE(newrouter); } else { /* from gorouterless() */ + /* We have no other routers. */ ATTRACE(AT_MID_DDP, AT_SID_TIMERS, AT_LV_WARNING, FALSE, "ddp_age_router entry : ARouter = 0x%x, RouterState = 0x%x", ATALK_VALUE(ourrouter->ifARouter), ourrouter->ifRouterState, 0); switch (ourrouter->ifRouterState) { case ROUTER_AROUND : + /* This is where we lose our cable. + Reset router fields and state accordingly. */ ourrouter->ifARouter.s_net = 0; ourrouter->ifARouter.s_node = 0; - dPrintf(D_M_RTMP,D_L_INFO, - ("rtmp.c Gorouterless!!!!!!!!\n")); ourrouter->ifThisCableStart = DDP_MIN_NETWORK; ourrouter->ifThisCableEnd = DDP_MAX_NETWORK; ourrouter->ifRouterState = NO_ROUTER; + + /* Send event to indicate that we've lost our seed router. */ + atalk_post_msg(ourrouter->aa_ifp, KEV_ATALK_ROUTERDOWN, 0, 0); + zip_control(ourrouter, ZIP_NO_ROUTER); break; case ROUTER_WARNING : @@ -285,13 +301,18 @@ void rtmp_input (mp, ifID) * ignore the presence of router */ if (ifID->ifRouterState == NO_ROUTER) { - dPrintf(D_M_RTMP, D_L_STARTUP, - ("Warning: new router came up: invalid startup net/node\n")); + dPrintf(D_M_RTMP, D_L_INFO, ("rtmp_input: new router came up, INVALID: net \ + in startup range.\n")); + /* trackrouter sends a KEV_ATALK_ROUTERUP event to note that + a new router has come up when we had none before. */ trackrouter(ifID, NET_VALUE(rtmp->at_rtmp_this_net), rtmp->at_rtmp_id[0] ); ifID->ifRouterState = ROUTER_WARNING; + + /* This router is invalid. Send event. */ + atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ROUTERUP_INVALID, 0, 0); } } else { /* our address @@ -308,6 +329,11 @@ void rtmp_input (mp, ifID) */ ifID->ifThisCableStart = range_start; ifID->ifThisCableEnd = range_end; + + /* A seed router that gives us back our cable range came up. + It's a valid router and gives us our network back. */ + atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ROUTERUP, 0, 0); + trackrouter(ifID, NET_VALUE(rtmp->at_rtmp_this_net), rtmp->at_rtmp_id[0] @@ -320,13 +346,17 @@ void rtmp_input (mp, ifID) * router */ if (ifID->ifRouterState == NO_ROUTER) { - dPrintf(D_M_RTMP,D_L_ERROR, - ("Warning: new router came up: invalid net/node\n")); + /* trackrouter sends a KEV_ATALK_ROUTERUP event to note that + a new router has come up when we had none before. */ trackrouter(ifID, NET_VALUE(rtmp->at_rtmp_this_net), rtmp->at_rtmp_id[0] ); ifID->ifRouterState = ROUTER_WARNING; + + /* A new seed router came up, but the cable range is different + than what we had before. */ + atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ROUTERUP_INVALID, 0, 0); } } } diff --git a/bsd/netat/ddp_rtmptable.c b/bsd/netat/ddp_rtmptable.c index a197b7d6c..aaefa9ae8 100644 --- a/bsd/netat/ddp_rtmptable.c +++ b/bsd/netat/ddp_rtmptable.c @@ -880,6 +880,14 @@ void routing_needed(mp, ifID, bypass) /* somehow, come to that point... */ + /* if multihomed - need to set source address to the interface + * the packet is being sent from. + */ + if (MULTIHOME_MODE) { + NET_ASSIGN(ddp->src_net, ifID_table[Entry->NetPort]->ifThisNode.s_net); + ddp->src_node = ifID_table[Entry->NetPort]->ifThisNode.s_node; + } + ifID->ifStatistics.fwdPkts++; ifID->ifStatistics.fwdBytes += msgsize; @@ -1108,8 +1116,8 @@ void getIfUsage(zone, ifs_in_zone) int zone; at_ifnames_t *ifs_in_zone; -/* sets a "1" in each element of the char array for each I/F in the - requested zone. The char array has a 1:1 correspondence with the +/* sets the interface name in each element of the array for each I/F in the + requested zone. The array has a 1:1 correspondence with the ifID_table. Zone is assumed to be valid and local, so if we're in single port mode, we'll set the home port and thats it. */ diff --git a/bsd/netat/ddp_usrreq.c b/bsd/netat/ddp_usrreq.c index c3db5fba4..7d327ab60 100644 --- a/bsd/netat/ddp_usrreq.c +++ b/bsd/netat/ddp_usrreq.c @@ -184,7 +184,14 @@ int ddp_pru_send(struct socket *so, int flags, struct mbuf *m, if (pcb == NULL) return (EINVAL); - + + /* + * Set type to MSG_DATA. Otherwise looped back packet is not + * recognized by atp_input() and possibly other protocols. + */ + + MCHTYPE(m, MSG_DATA); + if (!(pcb->ddp_flags & DDPFLG_HDRINCL)) { /* prepend a DDP header */ M_PREPEND(m, DDP_X_HDR_SIZE, M_WAIT); diff --git a/bsd/netat/debug.h b/bsd/netat/debug.h index 1a802b0e9..34c8517f5 100644 --- a/bsd/netat/debug.h +++ b/bsd/netat/debug.h @@ -27,6 +27,8 @@ #ifndef _NETAT_DEBUG_H_ #define _NETAT_DEBUG_H_ +#include +#ifdef __APPLE_API_PRIVATE #define D_L_FATAL 0x00000001 #define D_L_ERROR 0x00000002 @@ -258,5 +260,6 @@ static char *at_mid_strings[] = { #endif +#endif /* __APPLE_API_PRIVATE */ #endif /* _NETAT_DEBUG_H_ */ diff --git a/bsd/netat/drv_dep.c b/bsd/netat/drv_dep.c index 96fa0d78a..64ecd48be 100644 --- a/bsd/netat/drv_dep.c +++ b/bsd/netat/drv_dep.c @@ -46,9 +46,7 @@ #include #include #include -#include #include -#include #include #include @@ -189,7 +187,7 @@ int pat_output(patp, mlist, dst_addr, type) mlist = m->m_nextpkt; m->m_nextpkt = 0; - M_PREPEND(m, sizeof(llc_header_t), M_DONTWAIT) + M_PREPEND(m, sizeof(llc_header_t), M_DONTWAIT); if (m == 0) { continue; } diff --git a/bsd/netat/ep.h b/bsd/netat/ep.h index 569e591d8..2f46f707b 100644 --- a/bsd/netat/ep.h +++ b/bsd/netat/ep.h @@ -29,6 +29,7 @@ #ifndef _NETAT_EP_H_ #define _NETAT_EP_H_ +#include #define EP_REQUEST 1 /* Echo request packet */ #define EP_REPLY 2 /* Echo reply packet */ diff --git a/bsd/netat/lap.h b/bsd/netat/lap.h index 196fe8775..aec11df28 100644 --- a/bsd/netat/lap.h +++ b/bsd/netat/lap.h @@ -28,6 +28,7 @@ #ifndef _NETAT_LAP_H_ #define _NETAT_LAP_H_ +#include #define AT_MID_ELAP 202 diff --git a/bsd/netat/nbp.h b/bsd/netat/nbp.h index d6386b349..8c77bed8b 100644 --- a/bsd/netat/nbp.h +++ b/bsd/netat/nbp.h @@ -52,6 +52,7 @@ #ifndef _NETAT_NBP_H_ #define _NETAT_NBP_H_ +#include /* NBP packet types */ @@ -97,6 +98,7 @@ typedef struct at_nbp { #define DEFAULT_ZONE(zone) (!(zone)->len || ((zone)->len == 1 && (zone)->str[0] == '*')) #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE /* Struct for name registry */ typedef struct _nve_ { @@ -142,5 +144,6 @@ extern int nbp_fillin_nve(); extern at_nvestr_t *getSPLocalZone(int); extern at_nvestr_t *getLocalZone(int); +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ #endif /* _NETAT_NBP_H_ */ diff --git a/bsd/netat/pap.h b/bsd/netat/pap.h index df5a08d0c..6abed58d8 100644 --- a/bsd/netat/pap.h +++ b/bsd/netat/pap.h @@ -35,6 +35,7 @@ #ifndef _NETAT_PAP_H_ #define _NETAT_PAP_H_ +#include #define AT_PAP_DATA_SIZE 512 /* Maximum PAP data size */ #define AT_PAP_STATUS_SIZE 255 /* Maximum PAP status length */ diff --git a/bsd/netat/routing_tables.h b/bsd/netat/routing_tables.h index e7a15ad78..5376ab6a7 100644 --- a/bsd/netat/routing_tables.h +++ b/bsd/netat/routing_tables.h @@ -31,6 +31,8 @@ #ifndef _NETAT_ROUTING_TABLES_H_ #define _NETAT_ROUTING_TABLES_H_ +#include +#ifdef __APPLE_API_PRIVATE /* RTMP table entry state bitmap (EntryState) values */ @@ -211,4 +213,5 @@ extern void rtmp_router_input(); #endif /* KERNEL */ +#endif /* __APPLE_API_PRIVATE */ #endif /* _NETAT_ROUTING_TABLES_H_ */ diff --git a/bsd/netat/rtmp.h b/bsd/netat/rtmp.h index 7d9a7113c..8f7365b21 100644 --- a/bsd/netat/rtmp.h +++ b/bsd/netat/rtmp.h @@ -26,6 +26,7 @@ #ifndef _NETAT_RTMP_H_ #define _NETAT_RTMP_H_ +#include /* Changed 03-22-94 for router support LD */ diff --git a/bsd/netat/sys_glue.c b/bsd/netat/sys_glue.c index d5df3286b..b546b7c2f 100644 --- a/bsd/netat/sys_glue.c +++ b/bsd/netat/sys_glue.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -393,10 +393,12 @@ int _ATrw(fp, rw, uio, ext) return 0; } /* _ATrw */ -int _ATread(fp, uio, cred) +int _ATread(fp, uio, cred, flags, p) void *fp; struct uio *uio; void *cred; + int flags; + struct proc *p; { int stat; @@ -406,10 +408,12 @@ int _ATread(fp, uio, cred) return stat; } -int _ATwrite(fp, uio, cred) +int _ATwrite(fp, uio, cred, flags, p) void *fp; struct uio *uio; void *cred; + int flags; + struct proc *p; { int stat; @@ -650,7 +654,7 @@ void atalk_putnext(gref, m) #ifdef APPLETALK_DEBUG kprintf("wakeup gref = 0x%x\n", (unsigned)gref); #endif - thread_wakeup(&gref->iocevent); + wakeup(&gref->iocevent); } } break; @@ -669,7 +673,7 @@ void atalk_putnext(gref, m) gref->rdhead = m; if (gref->sevents & POLLMSG) { gref->sevents &= ~POLLMSG; - thread_wakeup(&gref->event); + wakeup(&gref->event); } if (gref->sevents & POLLIN) { gref->sevents &= ~POLLIN; @@ -686,7 +690,7 @@ void atalk_enablew(gref) gref_t *gref; { if (gref->sevents & POLLSYNC) - thread_wakeup(&gref->event); + wakeup(&gref->event); } void atalk_flush(gref) @@ -737,7 +741,7 @@ void atalk_notify(gref, errno) /* blocked read */ if (gref->sevents & POLLMSG) { gref->sevents &= ~POLLMSG; - thread_wakeup(&gref->event); + wakeup(&gref->event); } /* select */ if (gref->sevents & POLLIN) { diff --git a/bsd/netat/sysglue.h b/bsd/netat/sysglue.h index 0885bb142..62afbde1f 100644 --- a/bsd/netat/sysglue.h +++ b/bsd/netat/sysglue.h @@ -34,6 +34,7 @@ #ifndef _NETAT_SYSGLUE_H_ #define _NETAT_SYSGLUE_H_ +#include /* The following is originally from netat/h/localglue.h, which was @@ -88,6 +89,7 @@ typedef struct { #endif #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE #define SYS_HZ HZ /* Number of clock (SYS_SETTIMER) ticks per second */ #define HZ hz /* HZ ticks definition used throughout AppleTalk */ @@ -186,5 +188,6 @@ int gbuf_msgsize(gbuf_t *m); #undef timeout #undef untimeout +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ #endif /* _NETAT_SYSGLUE_H_ */ diff --git a/bsd/netat/zip.h b/bsd/netat/zip.h index 1a402989a..457c246cb 100644 --- a/bsd/netat/zip.h +++ b/bsd/netat/zip.h @@ -30,6 +30,7 @@ #ifndef _NETAT_ZIP_H_ #define _NETAT_ZIP_H_ +#include /* Definitions for ZIP, per AppleTalk Zone Information Protocol * documentation from `Inside AppleTalk', July 14, 1986. diff --git a/bsd/netccitt/Makefile b/bsd/netccitt/Makefile deleted file mode 100644 index 77353c827..000000000 --- a/bsd/netccitt/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -export MakeInc_cmd=${SRCROOT}/makedefs/MakeInc.cmd -export MakeInc_def=${SRCROOT}/makedefs/MakeInc.def -export MakeInc_rule=${SRCROOT}/makedefs/MakeInc.rule -export MakeInc_dir=${SRCROOT}/makedefs/MakeInc.dir - - -include $(MakeInc_cmd) -include $(MakeInc_def) - -INSTINC_SUBDIRS = \ - -INSTINC_SUBDIRS_PPC = \ - -INSTINC_SUBDIRS_I386 = \ - -EXPINC_SUBDIRS = \ - -EXPINC_SUBDIRS_PPC = \ - -EXPINC_SUBDIRS_I386 = \ - -DATAFILES = \ - dll.h hd_var.h hdlc.h llc_var.h pk.h pk_var.h \ - x25.h x25_sockaddr.h x25acct.h x25err.h - -INSTALL_MI_LIST = ${DATAFILES} - -INSTALL_MI_DIR = netccitt - -EXPORT_MI_LIST = ${DATAFILES} - -EXPORT_MI_DIR = netccitt - - -include $(MakeInc_rule) -include $(MakeInc_dir) - - diff --git a/bsd/netccitt/ccitt_proto.c b/bsd/netccitt/ccitt_proto.c deleted file mode 100644 index cf5f8edd6..000000000 --- a/bsd/netccitt/ccitt_proto.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* Copyright (c) 1998-1999 Apple Computer, Inc. All Rights Reserved */ -/* - * Copyright (c) University of British Columbia, 1984 - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * the Laboratory for Computation Vision and the Computer Science Department - * of the University of British Columbia. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)ccitt_proto.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include - -#include - -#include - -/* - * Definitions of protocols supported in the CCITT domain. - */ - -extern struct domain ccittdomain; -#define DOMAIN &ccittdomain - -#if LLC -int llc_output(); -void llc_ctlinput(), llc_init(), llc_timer(); -#endif -#if HDLC -int hd_output(); -void hd_ctlinput(), hd_init(), hd_timer(); -#endif -int pk_usrreq(), pk_ctloutput(); -void pk_timer(), pk_init(), pk_input(), pk_ctlinput(); - -struct protosw ccittsw[] = { -#if LLC - { 0, DOMAIN, IEEEPROTO_802LLC,0, - 0, llc_output, llc_ctlinput, 0, - 0, - llc_init, 0, llc_timer, 0, - }, -#endif -#if HDLC - { 0, DOMAIN, CCITTPROTO_HDLC,0, - 0, hd_output, hd_ctlinput, 0, - 0, - hd_init, 0, hd_timer, 0, - }, -#endif - { SOCK_STREAM, DOMAIN, CCITTPROTO_X25, PR_CONNREQUIRED|PR_ATOMIC|PR_WANTRCVD, - pk_input, 0, pk_ctlinput, pk_ctloutput, - pk_usrreq, - pk_init, 0, pk_timer, 0, - } -}; - -#if 0 -/*need to look at other init functions, use net_add_proto() to assure - things are init'd properly*/ -LINK_PROTOS(ccittsw); -#endif - -/* No init or rights functions; a routing init function; no header sizes */ -struct domain ccittdomain = - { AF_CCITT, "ccitt", link_ccittsw_protos, 0, 0, ccittsw, - &ccittsw[sizeof(ccittsw)/sizeof(ccittsw[0])], 0, - rn_inithead, 32, sizeof (struct sockaddr_x25) }; diff --git a/bsd/netccitt/dll.h b/bsd/netccitt/dll.h deleted file mode 100644 index 63f7f979d..000000000 --- a/bsd/netccitt/dll.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (C) Dirk Husemann, Computer Science Department IV, - * University of Erlangen-Nuremberg, Germany, 1990, 1991, 1992 - * Copyright (c) 1992, 1993 - * 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. - * - * @(#)dll.h 8.1 (Berkeley) 6/10/93 - */ - -/* - * We define the additional PRC_* codes in here - */ -#ifdef KERNEL -#ifndef PRC_IFUP -#define PRC_IFUP 3 -#endif -#define PRC_CONNECT_INDICATION 8 -#define PRC_CONNECT_REQUEST 9 -#define PRC_DISCONNECT_REQUEST 10 -#define PRC_DISCONNECT_INDICATION 11 -#define PRC_RESET_REQUEST 12 -#endif - -/* - * Data link layer configuration --- basically a copy of the relevant parts - * of x25config, implemented to become a little bit more network - * layer independent. (Probably only used for casting et al.) - */ -struct dllconfig { - u_short dllcfg_unused0:4, - dllcfg_unused1:4, - dllcfg_trace:1, /* link level tracing flag */ - dllcfg_window:7; /* link level window size */ - u_short dllcfg_xchxid:1, /* exchange XID (not yet) */ - dllcfg_unused2:7; /* here be dragons */ -}; - -struct dll_ctlinfo { - union { - struct { - struct dllconfig *dctli_up_cfg; - u_char dctli_up_lsap; - } CTLI_UP; - struct { - caddr_t dctli_down_pcb; - struct rtentry *dctli_down_rt; - struct dllconfig *dctli_down_llconf; - } CTLI_DOWN; - } CTLIun; -}; -#define dlcti_cfg CTLIun.CTLI_UP.dctli_up_cfg -#define dlcti_lsap CTLIun.CTLI_UP.dctli_up_lsap -#define dlcti_pcb CTLIun.CTLI_DOWN.dctli_down_pcb -#define dlcti_rt CTLIun.CTLI_DOWN.dctli_down_rt -#define dlcti_conf CTLIun.CTLI_DOWN.dctli_down_llconf diff --git a/bsd/netccitt/hd_debug.c b/bsd/netccitt/hd_debug.c deleted file mode 100644 index 38a705d4e..000000000 --- a/bsd/netccitt/hd_debug.c +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) University of British Columbia, 1984 - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * the Laboratory for Computation Vision and the Computer Science Department - * of the University of British Columbia. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)hd_debug.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#ifdef HDLCDEBUG -#define NTRACE 32 - -struct hdlctrace { - struct hdcb *ht_hdp; - short ht_dir; - struct mbuf *ht_frame; - struct timeval ht_time; -} hdtrace[NTRACE]; - -int lasttracelogged, freezetrace; -#endif - -hd_trace (hdp, direction, frame) -struct hdcb *hdp; -register struct Hdlc_frame *frame; -{ - register char *s; - register int nr, pf, ns, i; - struct Hdlc_iframe *iframe = (struct Hdlc_iframe *) frame; - -#ifdef HDLCDEBUG - hd_savetrace (hdp, direction, frame); -#endif - if (hdp -> hd_xcp -> xc_ltrace) { - if (direction == RX) - printf ("F-In: "); - else if (direction == 2) - printf ("F-Xmt: "); - else - printf ("F-Out: "); - - nr = iframe -> nr; - pf = iframe -> pf; - ns = iframe -> ns; - - switch (hd_decode (hdp, frame)) { - case SABM: - printf ("SABM : PF=%d\n", pf); - break; - - case DISC: - printf ("DISC : PF=%d\n", pf); - break; - - case DM: - printf ("DM : PF=%d\n", pf); - break; - - case FRMR: - { - register struct Frmr_frame *f = (struct Frmr_frame *)frame; - - printf ("FRMR : PF=%d, TEXT=", pf); - for (s = (char *) frame, i = 0; i < 5; ++i, ++s) - printf ("%x ", (int) * s & 0xff); - printf ("\n"); - printf ("control=%x v(s)=%d v(r)=%d w%d x%d y%d z%d\n", - f->frmr_control, f->frmr_ns, f->frmr_nr, - f->frmr_w, f->frmr_x, f->frmr_y, f->frmr_z); - break; - } - - case UA: - printf ("UA : PF=%d\n", pf); - break; - - case RR: - printf ("RR : N(R)=%d, PF=%d\n", nr, pf); - break; - - case RNR: - printf ("RNR : N(R)=%d, PF=%d\n", nr, pf); - break; - - case REJ: - printf ("REJ : N(R)=%d, PF=%d\n", nr, pf); - break; - - case IFRAME: - { - register struct mbuf *m; - register int len = 0; - - for(m = dtom (frame); m; m = m -> m_next) - len += m -> m_len; - len -= HDHEADERLN; - printf ("IFRAME : N(R)=%d, PF=%d, N(S)=%d, DATA(%d)=", - nr, pf, ns, len); - for (s = (char *)iframe->i_field, i = 0; i < 3; ++i, ++s) - printf ("%x ", (int) *s & 0xff); - printf ("\n"); - break; - } - - default: - printf ("ILLEGAL: "); - for (s = (char *) frame, i = 0; i < 5; ++i, ++s) - printf ("%x ", (int) *s & 0xff); - printf ("\n"); - } - - } -} - -#ifdef HDLCDEBUG -static -hd_savetrace (hdp, dir, frame) -struct hdcb *hdp; -struct Hdlc_frame *frame; -{ - register struct hdlctrace *htp; - register struct mbuf *m; - - if (freezetrace) - return; - htp = &hdtrace[lasttracelogged]; - lasttracelogged = (lasttracelogged + 1) % NTRACE; - if (m = htp->ht_frame) - m_freem (m); - m = dtom (frame); - htp->ht_frame = m_copy (m, 0, m->m_len); - htp->ht_hdp = hdp; - htp->ht_dir = dir; - htp->ht_time = time; -} - -hd_dumptrace (hdp) -struct hdcb *hdp; -{ - register int i, ltrace; - register struct hdlctrace *htp; - - freezetrace = 1; - hd_status (hdp); - printf ("retransmit queue:"); - for (i = 0; i < 8; i++) - printf (" %x", hdp -> hd_retxq[i]); - printf ("\n"); - ltrace = hdp -> hd_xcp -> xc_ltrace; - hdp -> hd_xcp -> xc_ltrace = 1; - for (i = 0; i < NTRACE; i++) { - htp = &hdtrace[(lasttracelogged + i) % NTRACE]; - if (htp->ht_hdp != hdp || htp->ht_frame == 0) - continue; - printf ("%d/%d ", htp->ht_time.tv_sec & 0xff, - htp->ht_time.tv_usec / 10000); - hd_trace (htp->ht_hdp, htp->ht_dir, - mtod (htp->ht_frame, struct Hdlc_frame *)); - m_freem (htp->ht_frame); - htp->ht_frame = 0; - } - hdp -> hd_xcp -> xc_ltrace = ltrace; - freezetrace = 0; -} -#endif diff --git a/bsd/netccitt/hd_input.c b/bsd/netccitt/hd_input.c deleted file mode 100644 index ff9009816..000000000 --- a/bsd/netccitt/hd_input.c +++ /dev/null @@ -1,690 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) University of British Columbia, 1984 - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * the Laboratory for Computation Vision and the Computer Science Department - * of the University of British Columbia. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)hd_input.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -static frame_reject(); -static rej_routine(); -static free_iframes(); -/* - * HDLC INPUT INTERFACE - * - * This routine is called when the HDLC physical device has - * completed reading a frame. - */ - -hdintr () -{ - register struct mbuf *m; - register struct hdcb *hdp; - register struct ifnet *ifp; - register int s; - static struct ifnet *lastifp; - static struct hdcb *lasthdp; - - for (;;) { - s = splimp (); - IF_DEQUEUE (&hdintrq, m); - splx (s); - if (m == 0) - break; - if (m->m_len < HDHEADERLN) { - printf ("hdintr: packet too short (len=%d)\n", - m->m_len); - m_freem (m); - continue; - } - if ((m->m_flags & M_PKTHDR) == 0) - panic("hdintr"); - ifp = m->m_pkthdr.rcvif; - - /* - * look up the appropriate hdlc control block - */ - - if (ifp == lastifp) - hdp = lasthdp; - else { - for (hdp = hdcbhead; hdp; hdp = hdp->hd_next) - if (hdp->hd_ifp == ifp) - break; - if (hdp == 0) { - printf ("hdintr: unknown interface %x\n", ifp); - m_freem (m); - continue; - } - lastifp = ifp; - lasthdp = hdp; - } - - /* Process_rxframe returns FALSE if the frame was NOT queued - for the next higher layers. */ - if (process_rxframe (hdp, m) == FALSE) - m_freem (m); - } -} - -process_rxframe (hdp, fbuf) -register struct hdcb *hdp; -register struct mbuf *fbuf; -{ - register int queued = FALSE, frametype, pf; - register struct Hdlc_frame *frame; - - frame = mtod (fbuf, struct Hdlc_frame *); - pf = ((struct Hdlc_iframe *) frame) -> pf; - - hd_trace (hdp, RX, frame); - if (frame -> address != ADDRESS_A && frame -> address != ADDRESS_B) - return (queued); - - switch ((frametype = hd_decode (hdp, frame)) + hdp->hd_state) { - case DM + DISC_SENT: - case UA + DISC_SENT: - /* - * Link now closed. Leave timer running - * so hd_timer() can periodically check the - * status of interface driver flag bit IFF_UP. - */ - hdp->hd_state = DISCONNECTED; - break; - - case DM + INIT: - case UA + INIT: - /* - * This is a non-standard state change needed for DCEs - * that do dynamic link selection. We can't go into the - * usual "SEND DM" state because a DM is a SARM in LAP. - */ - hd_writeinternal (hdp, SABM, POLLOFF); - hdp->hd_state = SABM_SENT; - SET_TIMER (hdp); - break; - - case SABM + DM_SENT: - case SABM + WAIT_SABM: - hd_writeinternal (hdp, UA, pf); - case UA + SABM_SENT: - case UA + WAIT_UA: - KILL_TIMER (hdp); - hd_initvars (hdp); - hdp->hd_state = ABM; - hd_message (hdp, "Link level operational"); - /* Notify the packet level - to send RESTART. */ - (void) pk_ctlinput (PRC_LINKUP, hdp->hd_pkp); - break; - - case SABM + SABM_SENT: - /* Got a SABM collision. Acknowledge the remote's SABM - via UA but still wait for UA. */ - hd_writeinternal (hdp, UA, pf); - break; - - case SABM + ABM: - /* Request to reset the link from the remote. */ - KILL_TIMER (hdp); - hd_message (hdp, "Link reset"); -#ifdef HDLCDEBUG - hd_dumptrace (hdp); -#endif - hd_flush (hdp->hd_ifp); - hd_writeinternal (hdp, UA, pf); - hd_initvars (hdp); - (void) pk_ctlinput (PRC_LINKRESET, hdp->hd_pkp); - hdp->hd_resets++; - break; - - case SABM + WAIT_UA: - hd_writeinternal (hdp, UA, pf); - break; - - case DM + ABM: - hd_message (hdp, "DM received: link down"); -#ifdef HDLCDEBUG - hd_dumptrace (hdp); -#endif - (void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_pkp); - hd_flush (hdp->hd_ifp); - case DM + DM_SENT: - case DM + WAIT_SABM: - case DM + WAIT_UA: - hd_writeinternal (hdp, SABM, pf); - hdp->hd_state = SABM_SENT; - SET_TIMER (hdp); - break; - - case DISC + INIT: - case DISC + DM_SENT: - case DISC + SABM_SENT: - /* Note: This is a non-standard state change. */ - hd_writeinternal (hdp, UA, pf); - hd_writeinternal (hdp, SABM, POLLOFF); - hdp->hd_state = SABM_SENT; - SET_TIMER (hdp); - break; - - case DISC + WAIT_UA: - hd_writeinternal (hdp, DM, pf); - SET_TIMER (hdp); - hdp->hd_state = DM_SENT; - break; - - case DISC + ABM: - hd_message (hdp, "DISC received: link down"); - (void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_pkp); - case DISC + WAIT_SABM: - hd_writeinternal (hdp, UA, pf); - hdp->hd_state = DM_SENT; - SET_TIMER (hdp); - break; - - case UA + ABM: - hd_message (hdp, "UA received: link down"); - (void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_pkp); - case UA + WAIT_SABM: - hd_writeinternal (hdp, DM, pf); - hdp->hd_state = DM_SENT; - SET_TIMER (hdp); - break; - - case FRMR + DM_SENT: - hd_writeinternal (hdp, SABM, pf); - hdp->hd_state = SABM_SENT; - SET_TIMER (hdp); - break; - - case FRMR + WAIT_SABM: - hd_writeinternal (hdp, DM, pf); - hdp->hd_state = DM_SENT; - SET_TIMER (hdp); - break; - - case FRMR + ABM: - hd_message (hdp, "FRMR received: link down"); - (void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_pkp); -#ifdef HDLCDEBUG - hd_dumptrace (hdp); -#endif - hd_flush (hdp->hd_ifp); - hd_writeinternal (hdp, SABM, pf); - hdp->hd_state = WAIT_UA; - SET_TIMER (hdp); - break; - - case RR + ABM: - case RNR + ABM: - case REJ + ABM: - process_sframe (hdp, (struct Hdlc_sframe *)frame, frametype); - break; - - case IFRAME + ABM: - queued = process_iframe (hdp, fbuf, (struct Hdlc_iframe *)frame); - break; - - case IFRAME + SABM_SENT: - case RR + SABM_SENT: - case RNR + SABM_SENT: - case REJ + SABM_SENT: - hd_writeinternal (hdp, DM, POLLON); - hdp->hd_state = DM_SENT; - SET_TIMER (hdp); - break; - - case IFRAME + WAIT_SABM: - case RR + WAIT_SABM: - case RNR + WAIT_SABM: - case REJ + WAIT_SABM: - hd_writeinternal (hdp, FRMR, POLLOFF); - SET_TIMER (hdp); - break; - - case ILLEGAL + SABM_SENT: - hdp->hd_unknown++; - hd_writeinternal (hdp, DM, POLLOFF); - hdp->hd_state = DM_SENT; - SET_TIMER (hdp); - break; - - case ILLEGAL + ABM: - hd_message (hdp, "Unknown frame received: link down"); - (void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_pkp); - case ILLEGAL + WAIT_SABM: - hdp->hd_unknown++; -#ifdef HDLCDEBUG - hd_dumptrace (hdp); -#endif - hd_writeinternal (hdp, FRMR, POLLOFF); - hdp->hd_state = WAIT_SABM; - SET_TIMER (hdp); - break; - } - - return (queued); -} - -process_iframe (hdp, fbuf, frame) -register struct hdcb *hdp; -struct mbuf *fbuf; -register struct Hdlc_iframe *frame; -{ - register int nr = frame -> nr, - ns = frame -> ns, - pf = frame -> pf; - register int queued = FALSE; - - /* - * Validate the iframe's N(R) value. It's N(R) value must be in - * sync with our V(S) value and our "last received nr". - */ - - if (valid_nr (hdp, nr, FALSE) == FALSE) { - frame_reject (hdp, Z, frame); - return (queued); - } - - - /* - * This section tests the IFRAME for proper sequence. That is, it's - * sequence number N(S) MUST be equal to V(S). - */ - - if (ns != hdp->hd_vr) { - hdp->hd_invalid_ns++; - if (pf || (hdp->hd_condition & REJ_CONDITION) == 0) { - hdp->hd_condition |= REJ_CONDITION; - /* - * Flush the transmit queue. This is ugly but we - * have no choice. A reject response must be - * immediately sent to the DCE. Failure to do so - * may result in another out of sequence iframe - * arriving (and thus sending another reject) - * before the first reject is transmitted. This - * will cause the DCE to receive two or more - * rejects back to back, which must never happen. - */ - hd_flush (hdp->hd_ifp); - hd_writeinternal (hdp, REJ, pf); - } - return (queued); - } - hdp->hd_condition &= ~REJ_CONDITION; - - /* - * This section finally tests the IFRAME's sequence number against - * the window size (K) and the sequence number of the last frame - * we have acknowledged. If the IFRAME is completely correct then - * it is queued for the packet level. - */ - - if (ns != (hdp -> hd_lasttxnr + hdp -> hd_xcp -> xc_lwsize) % MODULUS) { - hdp -> hd_vr = (hdp -> hd_vr + 1) % MODULUS; - if (pf == 1) { - /* Must generate a RR or RNR with final bit on. */ - hd_writeinternal (hdp, RR, POLLON); - } else - /* - * Hopefully we can piggyback the RR, if not we will generate - * a RR when T3 timer expires. - */ - if (hdp -> hd_rrtimer == 0) - hdp->hd_rrtimer = hd_t3; - - /* Forward iframe to packet level of X.25. */ - fbuf -> m_data += HDHEADERLN; - fbuf -> m_len -= HDHEADERLN; - fbuf -> m_pkthdr.len -= HDHEADERLN; - fbuf -> m_pkthdr.rcvif = (struct ifnet *)hdp -> hd_pkp; -#ifdef BSD4_3 - fbuf->m_act = 0; /* probably not necessary */ -#else - { - register struct mbuf *m; - - for (m = fbuf; m -> m_next; m = m -> m_next) - m -> m_act = (struct mbuf *) 0; - m -> m_act = (struct mbuf *) 1; - } -#endif - pk_input (fbuf); - queued = TRUE; - hd_start (hdp); - } else { - /* - * Here if the remote station has transmitted more iframes then - * the number which have been acknowledged plus K. - */ - hdp->hd_invalid_ns++; - frame_reject (hdp, W, frame); - } - return (queued); -} - -/* - * This routine is used to determine if a value (the middle parameter) - * is between two other values. The low value is the first parameter - * the high value is the last parameter. The routine checks the middle - * value to see if it is within the range of the first and last values. - * The reason we need this routine is the values are modulo some base - * hence a simple test for greater or less than is not sufficient. - */ - -bool -range_check (rear, value, front) -int rear, - value, - front; -{ - register bool result = FALSE; - - if (front > rear) - result = (rear <= value) && (value <= front); - else - result = (rear <= value) || (value <= front); - - return (result); -} - -/* - * This routine handles all the frame reject conditions which can - * arise as a result of secondary processing. The frame reject - * condition Y (frame length error) are handled elsewhere. - */ - -static -frame_reject (hdp, rejectcode, frame) -struct hdcb *hdp; -struct Hdlc_iframe *frame; -{ - register struct Frmr_frame *frmr = &hd_frmr; - - frmr -> frmr_control = ((struct Hdlc_frame *) frame) -> control; - - frmr -> frmr_ns = frame -> ns; - frmr -> frmr_f1_0 = 0; - frmr -> frmr_nr = frame -> nr; - frmr -> frmr_f2_0 = 0; - - frmr -> frmr_0000 = 0; - frmr -> frmr_w = frmr -> frmr_x = frmr -> frmr_y = - frmr -> frmr_z = 0; - switch (rejectcode) { - case Z: - frmr -> frmr_z = 1;/* invalid N(R). */ - break; - - case Y: - frmr -> frmr_y = 1;/* iframe length error. */ - break; - - case X: - frmr -> frmr_x = 1;/* invalid information field. */ - frmr -> frmr_w = 1; - break; - - case W: - frmr -> frmr_w = 1;/* invalid N(S). */ - } - - hd_writeinternal (hdp, FRMR, POLLOFF); - - hdp->hd_state = WAIT_SABM; - SET_TIMER (hdp); -} - -/* - * This procedure is invoked when ever we receive a supervisor - * frame such as RR, RNR and REJ. All processing for these - * frames is done here. - */ - -process_sframe (hdp, frame, frametype) -register struct hdcb *hdp; -register struct Hdlc_sframe *frame; -int frametype; -{ - register int nr = frame -> nr, pf = frame -> pf, pollbit = 0; - - if (valid_nr (hdp, nr, pf) == TRUE) { - switch (frametype) { - case RR: - hdp->hd_condition &= ~REMOTE_RNR_CONDITION; - break; - - case RNR: - hdp->hd_condition |= REMOTE_RNR_CONDITION; - hdp->hd_retxcnt = 0; - break; - - case REJ: - hdp->hd_condition &= ~REMOTE_RNR_CONDITION; - rej_routine (hdp, nr); - } - - if (pf == 1) { - hdp->hd_retxcnt = 0; - hdp->hd_condition &= ~TIMER_RECOVERY_CONDITION; - - if (frametype == RR && hdp->hd_lastrxnr == hdp->hd_vs - && hdp->hd_timer == 0 && hdp->hd_txq.head == 0) - hd_writeinternal(hdp, RR, pf); - else - /* If any iframes have been queued because of the - timer condition, transmit then now. */ - if (hdp->hd_condition & REMOTE_RNR_CONDITION) { - /* Remote is busy or timer condition, so only - send one. */ - if (hdp->hd_vs != hdp->hd_retxqi) - hd_send_iframe (hdp, hdp->hd_retxq[hdp->hd_vs], pollbit); - } - else /* Flush the retransmit list first. */ - while (hdp->hd_vs != hdp->hd_retxqi) - hd_send_iframe (hdp, hdp->hd_retxq[hdp->hd_vs], POLLOFF); - } - - hd_start (hdp); - } else - frame_reject (hdp, Z, (struct Hdlc_iframe *)frame); /* Invalid N(R). */ -} - -/* - * This routine tests the validity of the N(R) which we have received. - * If it is ok, then all the iframes which it acknowledges (if any) - * will be freed. - */ - -bool -valid_nr (hdp, nr, finalbit) -register struct hdcb *hdp; -register int finalbit; -{ - /* Make sure it really does acknowledge something. */ - if (hdp->hd_lastrxnr == nr) - return (TRUE); - - /* - * This section validates the frame's N(R) value. It's N(R) value - * must be in syncronization with our V(S) value and our "last - * received nr" variable. If it is correct then we are able to send - * more IFRAME's, else frame reject condition is entered. - */ - - if (range_check (hdp->hd_lastrxnr, nr, hdp->hd_vs) == FALSE) { - if ((hdp->hd_condition & TIMER_RECOVERY_CONDITION) && - range_check (hdp->hd_vs, nr, hdp->hd_xx) == TRUE) - hdp->hd_vs = nr; - - else { - hdp->hd_invalid_nr++; - return (FALSE); - } - } - - /* - * If we get to here, we do have a valid frame but it might be out - * of sequence. However, we should still accept the receive state - * number N(R) since it has already passed our previous test and it - * does acknowledge frames which we are sending. - */ - - KILL_TIMER (hdp); - free_iframes (hdp, &nr, finalbit);/* Free all acknowledged iframes */ - if (nr != hdp->hd_vs) - SET_TIMER (hdp); - - return (TRUE); -} - -/* - * This routine determines how many iframes need to be retransmitted. - * It then resets the Send State Variable V(S) to accomplish this. - */ - -static -rej_routine (hdp, rejnr) -register struct hdcb *hdp; -register int rejnr; -{ - register int anchor; - - /* - * Flush the output queue. Any iframes queued for - * transmission will be out of sequence. - */ - - hd_flush (hdp->hd_ifp); - - /* - * Determine how many frames should be re-transmitted. In the case - * of a normal REJ this should be 1 to K. In the case of a timer - * recovery REJ (ie. a REJ with the Final Bit on) this could be 0. - */ - - anchor = hdp->hd_vs; - if (hdp->hd_condition & TIMER_RECOVERY_CONDITION) - anchor = hdp->hd_xx; - - anchor = (anchor - rejnr + 8) % MODULUS; - - if (anchor > 0) { - - /* There is at least one iframe to retransmit. */ - KILL_TIMER (hdp); - hdp->hd_vs = rejnr; - - while (hdp->hd_vs != hdp->hd_retxqi) - hd_send_iframe (hdp, hdp->hd_retxq[hdp->hd_vs], POLLOFF); - - } - hd_start (hdp); -} - -/* - * This routine frees iframes from the retransmit queue. It is called - * when a previously written iframe is acknowledged. - */ - -static -free_iframes (hdp, nr, finalbit) -register struct hdcb *hdp; -int *nr; -register int finalbit; - -{ - register int i, k; - - /* - * We need to do the following because of a funny quirk in the - * protocol. This case occures when in Timer recovery condition - * we get a N(R) which acknowledges all the outstanding iframes - * but with the Final Bit off. In this case we need to save the last - * iframe for possible retransmission even though it has already been - * acknowledged! - */ - - if ((hdp->hd_condition & TIMER_RECOVERY_CONDITION) && *nr == hdp->hd_xx && finalbit == 0) { - *nr = (*nr - 1 + 8) % MODULUS; -/* printf ("QUIRK\n"); */ - } - - k = (*nr - hdp->hd_lastrxnr + 8) % MODULUS; - - /* Loop here freeing all acknowledged iframes. */ - for (i = 0; i < k; ++i) { - m_freem (hdp->hd_retxq[hdp->hd_lastrxnr]); - hdp->hd_retxq[hdp->hd_lastrxnr] = 0; - hdp->hd_lastrxnr = (hdp->hd_lastrxnr + 1) % MODULUS; - } - -} diff --git a/bsd/netccitt/hd_output.c b/bsd/netccitt/hd_output.c deleted file mode 100644 index 17fd5dedd..000000000 --- a/bsd/netccitt/hd_output.c +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) University of British Columbia, 1984 - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * the Laboratory for Computation Vision and the Computer Science Department - * of the University of British Columbia. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)hd_output.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -/* - * HDLC OUTPUT INTERFACE - * - * This routine is called when the X.25 packet layer output routine - * has a information frame (iframe) to write. It is also called - * by the input and control routines of the HDLC layer. - */ - -hd_output (hdp, m0) -register struct hdcb *hdp; -struct mbuf *m0; -{ - struct x25config *xcp; - register struct mbuf *m = m0; - int len; - - if (m == NULL) - panic ("hd_output"); - if ((m->m_flags & M_PKTHDR) == 0) - panic ("hd_output 2"); - - if (hdp->hd_state != ABM) { - m_freem (m); - return; - } - - /* - * Make room for the hdlc header either by prepending - * another mbuf, or by adjusting the offset and length - * of the first mbuf in the mbuf chain. - */ - - M_PREPEND(m, HDHEADERLN, M_DONTWAIT); - if (m == NULL) - return; - for (len = 0; m; m = m->m_next) - len += m->m_len; - m = m0; - m->m_pkthdr.len = len; - - hd_append (&hdp->hd_txq, m); - hd_start (hdp); -} - -hd_start (hdp) -register struct hdcb *hdp; -{ - register struct mbuf *m; - - /* - * The iframe is only transmitted if all these conditions are FALSE. - * The iframe remains queued (hdp->hd_txq) however and will be - * transmitted as soon as these conditions are cleared. - */ - - while (!(hdp->hd_condition & (TIMER_RECOVERY_CONDITION | REMOTE_RNR_CONDITION | REJ_CONDITION))) { - if (hdp->hd_vs == (hdp->hd_lastrxnr + hdp->hd_xcp->xc_lwsize) % MODULUS) { - - /* We have now exceeded the maximum number of - outstanding iframes. Therefore, we must wait - until at least one is acknowledged if this - condition is not turned off before we are - requested to write another iframe. */ - hdp->hd_window_condition++; - break; - } - - /* hd_remove top iframe from transmit queue. */ - if ((m = hd_remove (&hdp->hd_txq)) == NULL) - break; - - hd_send_iframe (hdp, m, POLLOFF); - } -} - -/* - * This procedure is passed a buffer descriptor for an iframe. It builds - * the rest of the control part of the frame and then writes it out. It - * also starts the acknowledgement timer and keeps the iframe in the - * Retransmit queue (Retxq) just in case we have to do this again. - * - * Note: This routine is also called from hd_input.c when retransmission - * of old frames is required. - */ - -hd_send_iframe (hdp, buf, poll_bit) -register struct hdcb *hdp; -register struct mbuf *buf; -int poll_bit; -{ - register struct Hdlc_iframe *iframe; - struct mbuf *m; - - KILL_TIMER (hdp); - - if (buf == 0) { - printf ("hd_send_iframe: zero arg\n"); -#ifdef HDLCDEBUG - hd_status (hdp); - hd_dumptrace (hdp); -#endif - hdp->hd_vs = (hdp->hd_vs + 7) % MODULUS; - return; - } - iframe = mtod (buf, struct Hdlc_iframe *); - - iframe -> hdlc_0 = 0; - iframe -> nr = hdp->hd_vr; - iframe -> pf = poll_bit; - iframe -> ns = hdp->hd_vs; - iframe -> address = ADDRESS_B; - hdp->hd_lasttxnr = hdp->hd_vr; - hdp->hd_rrtimer = 0; - - if (hdp->hd_vs == hdp->hd_retxqi) { - /* Check for retransmissions. */ - /* Put iframe only once in the Retransmission queue. */ - hdp->hd_retxq[hdp->hd_retxqi] = buf; - hdp->hd_retxqi = (hdp->hd_retxqi + 1) % MODULUS; - hdp->hd_iframes_out++; - } - - hdp->hd_vs = (hdp->hd_vs + 1) % MODULUS; - - hd_trace (hdp, TX, (struct Hdlc_frame *)iframe); - - /* Write buffer on device. */ - m = hdp->hd_dontcopy ? buf : m_copy(buf, 0, (int)M_COPYALL); - if (m == 0) { - printf("hdlc: out of mbufs\n"); - return; - } - (*hdp->hd_output)(hdp, m); - SET_TIMER (hdp); -} - -hd_ifoutput(hdp, m) -register struct mbuf *m; -register struct hdcb *hdp; -{ - /* - * Queue message on interface, and start output if interface - * not yet active. - */ - register struct ifnet *ifp = hdp->hd_ifp; - int s = splimp(); - - if (IF_QFULL(&ifp->if_snd)) { - IF_DROP(&ifp->if_snd); - /* printf("%s%d: HDLC says OK to send but queue full, may hang\n", - ifp->if_name, ifp->if_unit);*/ - m_freem(m); - } else { - IF_ENQUEUE(&ifp->if_snd, m); - if ((ifp->if_flags & IFF_OACTIVE) == 0) - (*ifp->if_start)(ifp); - } - splx(s); -} - - -/* - * This routine gets control when the timer expires because we have not - * received an acknowledgement for a iframe. - */ - -hd_resend_iframe (hdp) -register struct hdcb *hdp; -{ - - if (hdp->hd_retxcnt++ < hd_n2) { - if (!(hdp->hd_condition & TIMER_RECOVERY_CONDITION)) { - hdp->hd_xx = hdp->hd_vs; - hdp->hd_condition |= TIMER_RECOVERY_CONDITION; - } - - hdp->hd_vs = hdp->hd_lastrxnr; - hd_send_iframe (hdp, hdp->hd_retxq[hdp->hd_vs], POLLON); - } else { - /* At this point we have not received a RR even after N2 - retries - attempt to reset link. */ - - hd_initvars (hdp); - hd_writeinternal (hdp, SABM, POLLOFF); - hdp->hd_state = WAIT_UA; - SET_TIMER (hdp); - hd_message (hdp, "Timer recovery failed: link down"); - (void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_pkp); - } -} diff --git a/bsd/netccitt/hd_subr.c b/bsd/netccitt/hd_subr.c deleted file mode 100644 index b65f6bf37..000000000 --- a/bsd/netccitt/hd_subr.c +++ /dev/null @@ -1,415 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) University of British Columbia, 1984 - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * the Laboratory for Computation Vision and the Computer Science Department - * of the University of British Columbia. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)hd_subr.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -hd_init () -{ - - hdintrq.ifq_maxlen = IFQ_MAXLEN; -} - -hd_ctlinput (prc, addr) -int prc; -struct sockaddr *addr; -{ - register struct x25config *xcp = (struct x25config *)addr; - register struct hdcb *hdp; - register struct ifaddr *ifa; - struct ifnet *ifp; - caddr_t pk_newlink(); - - if (addr->sa_family != AF_CCITT) - return (EAFNOSUPPORT); - if (xcp->xc_lptype != HDLCPROTO_LAPB) - return (EPROTONOSUPPORT); - ifa = ifa_ifwithaddr(addr); - if (ifa == 0 || ifa->ifa_addr->sa_family != AF_CCITT || - (ifp = ifa->ifa_ifp) == 0) - panic ("hd_ctlinput"); - for (hdp = hdcbhead; hdp; hdp = hdp->hd_next) - if (hdp->hd_ifp == ifp) - break; - - if (hdp == 0) { /* new interface */ - int error; - int hd_ifoutput(), hd_output(); - - /* an hdcb is now too big to fit in an mbuf */ - MALLOC(hdp, struct hdcb *, sizeof (*hdp), M_PCB, M_NOWAIT); - if (hdp == 0) - return (ENOBUFS); - bzero((caddr_t)hdp, sizeof(*hdp)); - hdp->hd_pkp = - (caddr_t) pk_newlink ((struct x25_ifaddr *) ifa, - (caddr_t) hdp); - ((struct x25_ifaddr *)ifa)->ia_pkcb = - (struct pkcb *) hdp->hd_pkp; - if (hdp -> hd_pkp == 0) { - FREE(hdp, M_PCB); - return (ENOBUFS); - } - hdp->hd_ifp = ifp; - hdp->hd_ifa = ifa; - hdp->hd_xcp = xcp; - hdp->hd_state = INIT; - hdp->hd_output = hd_ifoutput; - hdp->hd_next = hdcbhead; - hdcbhead = hdp; - } else if (hdp->hd_pkp == 0) { /* interface got reconfigured */ - hdp->hd_pkp = - (caddr_t) pk_newlink ((struct x25_ifaddr *) ifa, - (caddr_t) hdp); - ((struct x25_ifaddr *)ifa)->ia_pkcb = - (struct pkcb *) hdp->hd_pkp; - if (hdp -> hd_pkp == 0) { - FREE(hdp, M_PCB); - return (ENOBUFS); - } - } - - switch (prc) { - case PRC_IFUP: - if (xcp->xc_lwsize == 0 || - xcp->xc_lwsize > MAX_WINDOW_SIZE) - xcp->xc_lwsize = MAX_WINDOW_SIZE; - if (hdp->hd_state == INIT) - SET_TIMER (hdp); - break; - - case PRC_IFDOWN: - if (hdp->hd_state == ABM) - hd_message (hdp, "Operator shutdown: link closed"); - (void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_pkp); - - /* fall thru to ... */ - - case PRC_DISCONNECT_REQUEST: - /* drop reference to pkcb --- it's dead meat */ - hdp->hd_pkp = (caddr_t) 0; - ((struct x25_ifaddr *)ifa)->ia_pkcb = (struct pkcb *) 0; - - hd_writeinternal (hdp, DISC, POLLON); - hdp->hd_state = DISC_SENT; - SET_TIMER (hdp); - } - return (0); -} - -hd_initvars (hdp) -register struct hdcb *hdp; -{ - register struct mbuf *m; - register int i; - - /* Clear Transmit queue. */ - while ((m = hd_remove (&hdp->hd_txq)) != NULL) - m_freem (m); - - /* Clear Retransmit queue. */ - i = hdp->hd_lastrxnr; - while (i != hdp->hd_retxqi) { - m_freem (hdp->hd_retxq[i]); - i = (i + 1) % MODULUS; - } - hdp->hd_retxqi = 0; - - hdp->hd_vs = hdp->hd_vr = 0; - hdp->hd_lasttxnr = hdp->hd_lastrxnr = 0; - hdp->hd_rrtimer = 0; - KILL_TIMER(hdp); - hdp->hd_retxcnt = 0; - hdp->hd_condition = 0; -} - -hd_decode (hdp, frame) -register struct hdcb *hdp; -struct Hdlc_frame *frame; -{ - register int frametype = ILLEGAL; - register struct Hdlc_iframe *iframe = (struct Hdlc_iframe *) frame; - register struct Hdlc_sframe *sframe = (struct Hdlc_sframe *) frame; - register struct Hdlc_uframe *uframe = (struct Hdlc_uframe *) frame; - - if (iframe -> hdlc_0 == 0) { - frametype = IFRAME; - hdp->hd_iframes_in++; - } - - else if (sframe -> hdlc_01 == 1) { - /* Supervisory format. */ - switch (sframe -> s2) { - case 0: - frametype = RR; - hdp->hd_rrs_in++; - break; - - case 1: - frametype = RNR; - hdp->hd_rnrs_in++; - break; - - case 2: - frametype = REJ; - hdp->hd_rejs_in++; - } - } - else if (uframe -> hdlc_11 == 3) { - /* Unnumbered format. */ - switch (uframe -> m3) { - case 0: - frametype = DM; - break; - - case 1: - frametype = SABM; - break; - - case 2: - frametype = DISC; - break; - - case 3: - frametype = UA; - break; - - case 4: - frametype = FRMR; - hdp->hd_frmrs_in++; - } - } - return (frametype); -} - -/* - * This routine is called when the HDLC layer internally generates a - * command or response for the remote machine ( eg. RR, UA etc. ). - * Only supervisory or unnumbered frames are processed. - */ - -hd_writeinternal (hdp, frametype, pf) -register struct hdcb *hdp; -register int frametype, pf; -{ - register struct mbuf *buf; - struct Hdlc_frame *frame; - register struct Hdlc_sframe *sframe; - register struct Hdlc_uframe *uframe; - - MGETHDR (buf, M_DONTWAIT, MT_HEADER); - if (buf == 0) - return; - frame = mtod (buf, struct Hdlc_frame *); - sframe = mtod (buf, struct Hdlc_sframe *); - uframe = mtod (buf, struct Hdlc_uframe *); - - /* Assume a response - address structure for DTE */ - frame -> address = ADDRESS_A; - buf -> m_len = 2; - buf -> m_act = buf -> m_next = NULL; - - switch (frametype) { - case RR: - frame -> control = RR_CONTROL; - hdp->hd_rrs_out++; - break; - - case RNR: - frame -> control = RNR_CONTROL; - hdp->hd_rnrs_out++; - break; - - case REJ: - frame -> control = REJ_CONTROL; - hdp->hd_rejs_out++; - break; - - case SABM: - frame -> control = SABM_CONTROL; - frame -> address = ADDRESS_B; - break; - - case DISC: - if ((hdp->hd_ifp->if_flags & IFF_UP) == 0) { - hdp->hd_state = DISCONNECTED; - (void) m_freem (buf); - hd_flush (hdp->hd_ifp); - return; - } - frame -> control = DISC_CONTROL; - frame -> address = ADDRESS_B; - break; - - case DM: - frame -> control = DM_CONTROL; - break; - - case UA: - frame -> control = UA_CONTROL; - break; - - case FRMR: - frame -> control = FRMR_CONTROL; - bcopy ((caddr_t)&hd_frmr, (caddr_t)frame -> info, 3); - buf -> m_len = 5; - hdp->hd_frmrs_out++; - - } - - if (sframe -> hdlc_01 == 1) { - /* Supervisory format - RR, REJ, or RNR. */ - sframe -> nr = hdp->hd_vr; - sframe -> pf = pf; - hdp->hd_lasttxnr = hdp->hd_vr; - hdp->hd_rrtimer = 0; - } - else - uframe -> pf = pf; - - hd_trace (hdp, TX, frame); - buf -> m_pkthdr.len = buf -> m_len; - (*hdp->hd_output) (hdp, buf); -} - -struct mbuf * -hd_remove (q) -struct hdtxq *q; -{ - register struct mbuf *m; - - m = q -> head; - if (m) { - if ((q -> head = m -> m_act) == NULL) - q -> tail = NULL; - m -> m_act = 0; - } - return (m); -} - -hd_append (q, m) -register struct hdtxq *q; -register struct mbuf *m; -{ - - m -> m_act = NULL; - if (q -> tail == NULL) - q -> head = m; - else - q -> tail -> m_act = m; - q -> tail = m; -} - -hd_flush (ifp) -struct ifnet *ifp; -{ - register struct mbuf *m; - register int s; - - while (1) { - s = splimp (); - IF_DEQUEUE (&ifp->if_snd, m); - splx (s); - if (m == 0) - break; - m_freem (m); - } -} - -hd_message (hdp, msg) -struct hdcb *hdp; -char *msg; -{ - char *format_ntn (); - - if (hdcbhead -> hd_next) - printf ("HDLC(%s): %s\n", format_ntn (hdp->hd_xcp), msg); - else - printf ("HDLC: %s\n", msg); -} - -#ifdef HDLCDEBUG -hd_status (hdp) -struct hdcb *hdp; -{ - printf ("HDLC STATUS:\n V(S)=%d, V(R)=%d, retxqi=%d,\n", - hdp->hd_vs, hdp->hd_vr, hdp->hd_retxqi); - - printf ("Last_rx_nr=%d, Last_tx_nr=%d,\n Condition=%d, Xx=%d\n", - hdp->hd_lastrxnr, hdp->hd_lasttxnr, hdp->hd_condition, hdp->hd_xx); -} -#endif diff --git a/bsd/netccitt/hd_timer.c b/bsd/netccitt/hd_timer.c deleted file mode 100644 index 17ccb091a..000000000 --- a/bsd/netccitt/hd_timer.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) University of British Columbia, 1984 - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * the Laboratory for Computation Vision and the Computer Science Department - * of the University of British Columbia. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)hd_timer.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -/* - * these can be patched with adb if the - * default values are inappropriate - */ - -int hd_t1 = T1; -int hd_t3 = T3; -int hd_n2 = N2; - -/* - * HDLC TIMER - * - * This routine is called every 500ms by the kernel. Decrement timer by this - * amount - if expired then process the event. - */ - -hd_timer () -{ - register struct hdcb *hdp; - register int s = splimp (); - - for (hdp = hdcbhead; hdp; hdp = hdp->hd_next) { - if (hdp->hd_rrtimer && (--hdp->hd_rrtimer == 0)) { - if (hdp->hd_lasttxnr != hdp->hd_vr) - hd_writeinternal (hdp, RR, POLLOFF); - } - - if (!(hdp->hd_timer && --hdp->hd_timer == 0)) - continue; - - switch (hdp->hd_state) { - case INIT: - case DISC_SENT: - hd_writeinternal (hdp, DISC, POLLON); - break; - - case ABM: - if (hdp->hd_lastrxnr != hdp->hd_vs) { /* XXX */ - hdp->hd_timeouts++; - hd_resend_iframe (hdp); - } - break; - - case WAIT_SABM: - hd_writeinternal (hdp, FRMR, POLLOFF); - if (++hdp->hd_retxcnt == hd_n2) { - hdp->hd_retxcnt = 0; - hd_writeinternal (hdp, SABM, POLLOFF); - hdp->hd_state = WAIT_UA; - } - break; - - case DM_SENT: - if (++hdp->hd_retxcnt == hd_n2) { - /* Notify the packet level. */ - (void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_pkp); - hdp->hd_retxcnt = 0; - hdp->hd_state = SABM_SENT; - hd_writeinternal (hdp, SABM, POLLOFF); - } else - hd_writeinternal (hdp, DM, POLLOFF); - break; - - case WAIT_UA: - if (++hdp->hd_retxcnt == hd_n2) { - hdp->hd_retxcnt = 0; - hd_writeinternal (hdp, DM, POLLOFF); - hdp->hd_state = DM_SENT; - } else - hd_writeinternal (hdp, SABM, POLLOFF); - break; - - case SABM_SENT: - /* Do this indefinitely. */ - hd_writeinternal (hdp, SABM, POLLON); - break; - - case DISCONNECTED: - /* - * Poll the interface driver flags waiting - * for the IFF_UP bit to come on. - */ - if (hdp->hd_ifp->if_flags & IFF_UP) - hdp->hd_state = INIT; - - } - SET_TIMER (hdp); - } - - splx (s); -} diff --git a/bsd/netccitt/hd_var.h b/bsd/netccitt/hd_var.h deleted file mode 100644 index 1bbe85a58..000000000 --- a/bsd/netccitt/hd_var.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) University of British Columbia, 1984 - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * the Laboratory for Computation Vision and the Computer Science Department - * of the University of British Columbia. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)hd_var.h 8.1 (Berkeley) 6/10/93 - */ - -/* - * - * hdlc control block - * - */ - -struct hdtxq { - struct mbuf *head; - struct mbuf *tail; -}; - -struct hdcb { - struct hdcb *hd_next; /* pointer to next hdlc control block */ - char hd_state; /* link state */ - char hd_vs; /* send state variable */ - char hd_vr; /* receive state variable */ - char hd_lastrxnr; /* last received N(R) */ - char hd_lasttxnr; /* last transmitted N(R) */ - char hd_condition; -#define TIMER_RECOVERY_CONDITION 0x01 -#define REJ_CONDITION 0x02 -#define REMOTE_RNR_CONDITION 0X04 - char hd_retxcnt; - char hd_xx; - struct hdtxq hd_txq; - struct mbuf *hd_retxq[MODULUS]; - char hd_retxqi; - char hd_rrtimer; - char hd_timer; -#define SET_TIMER(hdp) hdp->hd_timer = hd_t1 -#define KILL_TIMER(hdp) hdp->hd_timer = 0 - char hd_dontcopy; /* if-driver doesn't free I-frames */ - struct ifnet *hd_ifp; /* device's network visible interface */ - struct ifaddr *hd_ifa; /* device's X.25 network address */ - struct x25config *hd_xcp; - caddr_t hd_pkp; /* Level III junk */ - int (*hd_output)(); /* separate entry for HDLC direct output */ - - /* link statistics */ - - long hd_iframes_in; - long hd_iframes_out; - long hd_rrs_in; - long hd_rrs_out; - short hd_rejs_in; - short hd_rejs_out; - long hd_window_condition; - short hd_invalid_ns; - short hd_invalid_nr; - short hd_timeouts; - short hd_resets; - short hd_unknown; - short hd_frmrs_in; - short hd_frmrs_out; - short hd_rnrs_in; - short hd_rnrs_out; -}; - -#ifdef KERNEL -struct hdcb *hdcbhead; /* head of linked list of hdcb's */ -struct Frmr_frame hd_frmr; /* rejected frame diagnostic info */ -struct ifqueue hdintrq; /* hdlc packet input queue */ - -int hd_t1; /* timer T1 value */ -int hd_t3; /* RR send timer */ -int hd_n2; /* frame retransmission limit */ -#endif diff --git a/bsd/netccitt/hdlc.h b/bsd/netccitt/hdlc.h deleted file mode 100644 index 2ab17e3d3..000000000 --- a/bsd/netccitt/hdlc.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) University of British Columbia, 1984 - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by the - * Laboratory for Computation Vision and the Computer Science Department - * of the University of British Columbia. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)hdlc.h 8.1 (Berkeley) 6/10/93 - */ - -#ifndef ORDER4 -#define FALSE 0 -#define TRUE 1 -typedef u_char octet; -typedef char bool; - -/* - * HDLC Packet format definitions - * This will eventually have to be rewritten without reference - * to bit fields, to be compliant with ANSI C and alignment safe. - */ - -#if BYTE_ORDER == BIG_ENDIAN -#define ORDER4(a, b, c, d) a , b , c , d -#define ORDER5(a, b, c, d, e) a , b , c , d , e -#endif - -#if BYTE_ORDER == LITTLE_ENDIAN -#define ORDER4(a, b, c, d) d , c , b , a -#define ORDER5(a, b, c, d, e) e , d , c , b , a -#endif -#endif - -#define MAX_INFO_LEN 4096+3+4 -#define ADDRESS_A 3 /* B'00000011' */ -#define ADDRESS_B 1 /* B'00000001' */ - -struct Hdlc_iframe { - octet address; - octet ORDER4(nr:3, pf:1, ns:3, hdlc_0:1); - octet i_field[MAX_INFO_LEN]; -}; - -struct Hdlc_sframe { - octet address; - octet ORDER4(nr:3, pf:1, s2:2, hdlc_01:2); -}; - -struct Hdlc_uframe { - octet address; - octet ORDER4(m3:3, pf:1, m2:2, hdlc_11:2); -}; - -struct Frmr_frame { - octet address; - octet control; - octet frmr_control; - octet ORDER4(frmr_nr:3, frmr_f1_0:1, frmr_ns:3, frmr_f2_0:1); - octet ORDER5(frmr_0000:4, frmr_z:1, frmr_y:1, frmr_x:1, frmr_w:1); -}; - -#define HDHEADERLN 2 -#define MINFRLN 2 /* Minimum frame length. */ - -struct Hdlc_frame { - octet address; - octet control; - octet info[3]; /* min for FRMR */ -}; - -#define SABM_CONTROL 057 /* B'00101111' */ -#define UA_CONTROL 0143 /* B'01100011' */ -#define DISC_CONTROL 0103 /* B'01000011' */ -#define DM_CONTROL 017 /* B'00001111' */ -#define FRMR_CONTROL 0207 /* B'10000111' */ -#define RR_CONTROL 01 /* B'00000001' */ -#define RNR_CONTROL 05 /* B'00000101' */ -#define REJ_CONTROL 011 /* B'00001001' */ - -#define POLLOFF 0 -#define POLLON 1 - -/* Define Link State constants. */ - -#define INIT 0 -#define DM_SENT 1 -#define SABM_SENT 2 -#define ABM 3 -#define WAIT_SABM 4 -#define WAIT_UA 5 -#define DISC_SENT 6 -#define DISCONNECTED 7 -#define MAXSTATE 8 - -/* The following constants are used in a switch statement to process - frames read from the communications line. */ - -#define SABM 0 * MAXSTATE -#define DM 1 * MAXSTATE -#define DISC 2 * MAXSTATE -#define UA 3 * MAXSTATE -#define FRMR 4 * MAXSTATE -#define RR 5 * MAXSTATE -#define RNR 6 * MAXSTATE -#define REJ 7 * MAXSTATE -#define IFRAME 8 * MAXSTATE -#define ILLEGAL 9 * MAXSTATE - -#define T1 (3 * PR_SLOWHZ) /* IFRAME TIMEOUT - 3 seconds */ -#define T3 (T1 / 2) /* RR generate timeout - 1.5 seconds */ -#define N2 10 -#define MODULUS 8 -#define MAX_WINDOW_SIZE 7 - -#define Z 0 -#define Y 1 -#define X 2 -#define W 3 -#define A 4 - -#define TX 0 -#define RX 1 - -bool range_check (); -bool valid_nr (); -struct mbuf *hd_remove (); diff --git a/bsd/netccitt/if_x25subr.c b/bsd/netccitt/if_x25subr.c deleted file mode 100644 index 4edf1b77a..000000000 --- a/bsd/netccitt/if_x25subr.c +++ /dev/null @@ -1,820 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1990, 1993 - * 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_x25subr.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#if INET -#include -#include -#endif - -#if NS -#include -#include -#endif - -#if ISO -int tp_incoming(); -#include -#include -#include -#endif - -extern struct ifnet loif; -struct llinfo_x25 llinfo_x25 = {&llinfo_x25, &llinfo_x25}; -#ifndef _offsetof -#define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m)) -#endif -struct sockaddr *x25_dgram_sockmask; -struct sockaddr_x25 x25_dgmask = { - _offsetof(struct sockaddr_x25, x25_udata[1]), /* _len */ - 0, /* _family */ - 0, /* _net */ - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* _addr */ - {0}, /* opts */ - -1, /* _udlen */ - {-1} /* _udata */ -}; - -struct if_x25stats { - int ifx_wrongplen; - int ifx_nophdr; -} if_x25stats; -int x25_autoconnect = 0; - -#define senderr(x) {error = x; goto bad;} -/* - * Ancillary routines - */ -static struct llinfo_x25 * -x25_lxalloc(rt) -register struct rtentry *rt; -{ - register struct llinfo_x25 *lx; - register struct sockaddr *dst = rt_key(rt); - register struct ifaddr *ifa; - - MALLOC(lx, struct llinfo_x25 *, sizeof (*lx), M_PCB, M_NOWAIT); - if (lx == 0) - return lx; - Bzero(lx, sizeof(*lx)); - lx->lx_rt = rt; - lx->lx_family = dst->sa_family; - RTHOLD(rt); - if (rt->rt_llinfo) - insque(lx, (struct llinfo_x25 *)rt->rt_llinfo); - else { - rt->rt_llinfo = (caddr_t)lx; - insque(lx, &llinfo_x25); - } - for (ifa = rt->rt_ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { - if (ifa->ifa_addr->sa_family == AF_CCITT) - lx->lx_ia = (struct x25_ifaddr *)ifa; - } - return lx; -} -x25_lxfree(lx) -register struct llinfo_x25 *lx; -{ - register struct rtentry *rt = lx->lx_rt; - register struct pklcd *lcp = lx->lx_lcd; - - if (lcp) { - lcp->lcd_upper = 0; - pk_disconnect(lcp); - } - if ((rt->rt_llinfo == (caddr_t)lx) && (lx->lx_next->lx_rt == rt)) - rt->rt_llinfo = (caddr_t)lx->lx_next; - else - rt->rt_llinfo = 0; - RTFREE(rt); - remque(lx); - FREE(lx, M_PCB); -} -/* - * Process a x25 packet as datagram; - */ -x25_ifinput(lcp, m) -struct pklcd *lcp; -register struct mbuf *m; -{ - struct llinfo_x25 *lx = (struct llinfo_x25 *)lcp->lcd_upnext; - register struct ifnet *ifp; - struct ifqueue *inq; - extern struct timeval time; - int s, len, isr; - - if (m == 0 || lcp->lcd_state != DATA_TRANSFER) { - x25_connect_callback(lcp, 0); - return; - } - pk_flowcontrol(lcp, 0, 1); /* Generate RR */ - ifp = m->m_pkthdr.rcvif; - ifp->if_lastchange = time; - switch (m->m_type) { - default: - if (m) - m_freem(m); - return; - - case MT_DATA: - /* FALLTHROUGH */; - } - switch (lx->lx_family) { -#if INET - case AF_INET: - isr = NETISR_IP; - inq = &ipintrq; - break; - -#endif -#if NS - case AF_NS: - isr = NETISR_NS; - inq = &nsintrq; - break; - -#endif -#if ISO - case AF_ISO: - isr = NETISR_ISO; - inq = &clnlintrq; - break; -#endif - default: - m_freem(m); - ifp->if_noproto++; - return; - } - s = splimp(); - schednetisr(isr); - if (IF_QFULL(inq)) { - IF_DROP(inq); - m_freem(m); - } else { - IF_ENQUEUE(inq, m); - ifp->if_ibytes += m->m_pkthdr.len; - } - splx(s); -} -x25_connect_callback(lcp, m) -register struct pklcd *lcp; -register struct mbuf *m; -{ - register struct llinfo_x25 *lx = (struct llinfo_x25 *)lcp->lcd_upnext; - int do_clear = 1; - if (m == 0) - goto refused; - if (m->m_type != MT_CONTROL) { - printf("x25_connect_callback: should panic\n"); - goto refused; - } - switch (pk_decode(mtod(m, struct x25_packet *))) { - case CALL_ACCEPTED: - lcp->lcd_upper = x25_ifinput; - if (lcp->lcd_sb.sb_mb) - lcp->lcd_send(lcp); /* XXX start queued packets */ - return; - default: - do_clear = 0; - refused: - lcp->lcd_upper = 0; - lx->lx_lcd = 0; - if (do_clear) - pk_disconnect(lcp); - return; - } -} -#define SA(p) ((struct sockaddr *)(p)) -#define RT(p) ((struct rtentry *)(p)) - -x25_dgram_incoming(lcp, m0) -register struct pklcd *lcp; -struct mbuf *m0; -{ - register struct rtentry *rt, *nrt; - register struct mbuf *m = m0->m_next; /* m0 has calling sockaddr_x25 */ - void x25_rtrequest(); - - rt = rtalloc1(SA(&lcp->lcd_faddr), 0); - if (rt == 0) { -refuse: lcp->lcd_upper = 0; - pk_close(lcp); - return; - } - rt->rt_refcnt--; - if ((nrt = RT(rt->rt_llinfo)) == 0 || rt_mask(rt) != x25_dgram_sockmask) - goto refuse; - if ((nrt->rt_flags & RTF_UP) == 0) { - rt->rt_llinfo = (caddr_t)rtalloc1(rt->rt_gateway, 0); - rtfree(nrt); - if ((nrt = RT(rt->rt_llinfo)) == 0) - goto refuse; - nrt->rt_refcnt--; - } - if (nrt->rt_ifa == 0 || nrt->rt_ifa->ifa_rtrequest != x25_rtrequest) - goto refuse; - lcp->lcd_send(lcp); /* confirm call */ - x25_rtattach(lcp, nrt); - m_freem(m); -} - -/* - * X.25 output routine. - */ -x25_ifoutput(ifp, m0, dst, rt) -struct ifnet *ifp; -struct mbuf *m0; -struct sockaddr *dst; -register struct rtentry *rt; -{ - register struct mbuf *m = m0; - register struct llinfo_x25 *lx; - struct pklcd *lcp; - int s, error = 0; - -int plen; -for (plen = 0; m; m = m->m_next) - plen += m->m_len; -m = m0; - - if ((ifp->if_flags & IFF_UP) == 0) - senderr(ENETDOWN); - while (rt == 0 || (rt->rt_flags & RTF_GATEWAY)) { - if (rt) { - if (rt->rt_llinfo) { - rt = (struct rtentry *)rt->rt_llinfo; - continue; - } - dst = rt->rt_gateway; - } - if ((rt = rtalloc1(dst, 1)) == 0) - senderr(EHOSTUNREACH); - rt->rt_refcnt--; - } - /* - * Sanity checks. - */ - if ((rt->rt_ifp != ifp) || - (rt->rt_flags & (RTF_CLONING | RTF_GATEWAY)) || - ((lx = (struct llinfo_x25 *)rt->rt_llinfo) == 0)) { - senderr(ENETUNREACH); - } -if ((m->m_flags & M_PKTHDR) == 0) { - if_x25stats.ifx_nophdr++; - m = m_gethdr(M_NOWAIT, MT_HEADER); - if (m == 0) - senderr(ENOBUFS); - m->m_pkthdr.len = plen; - m->m_next = m0; -} -if (plen != m->m_pkthdr.len) { - if_x25stats.ifx_wrongplen++; - m->m_pkthdr.len = plen; -} -next_circuit: - lcp = lx->lx_lcd; - if (lcp == 0) { - lx->lx_lcd = lcp = pk_attach((struct socket *)0); - if (lcp == 0) - senderr(ENOBUFS); - lcp->lcd_upper = x25_connect_callback; - lcp->lcd_upnext = (caddr_t)lx; - lcp->lcd_packetsize = lx->lx_ia->ia_xc.xc_psize; - lcp->lcd_flags = X25_MBS_HOLD; - } - switch (lcp->lcd_state) { - case READY: - if (dst->sa_family == AF_INET && - ifp->if_type == IFT_X25DDN && - rt->rt_gateway->sa_family != AF_CCITT) - x25_ddnip_to_ccitt(dst, rt); - if (rt->rt_gateway->sa_family != AF_CCITT) { - if ((rt->rt_flags & RTF_XRESOLVE) == 0) - senderr(EHOSTUNREACH); - } else if (x25_autoconnect) - error = pk_connect(lcp, - (struct sockaddr_x25 *)rt->rt_gateway); - if (error) - senderr(error); - /* FALLTHROUGH */ - case SENT_CALL: - case DATA_TRANSFER: - if (sbspace(&lcp->lcd_sb) < 0) { - lx = lx->lx_next; - if (lx->lx_rt != rt) - senderr(ENOSPC); - goto next_circuit; - } - if (lx->lx_ia) - lcp->lcd_dg_timer = - lx->lx_ia->ia_xc.xc_dg_idletimo; - pk_send(lcp, m); - break; - default: - /* - * We count on the timer routine to close idle - * connections, if there are not enough circuits to go - * around. - * - * So throw away data for now. - * After we get it all working, we'll rewrite to handle - * actively closing connections (other than by timers), - * when circuits get tight. - * - * In the DDN case, the imp itself closes connections - * under heavy load. - */ - error = ENOBUFS; - bad: - if (m) - m_freem(m); - } - return (error); -} - -/* - * Simpleminded timer routine. - */ -x25_iftimeout(ifp) -struct ifnet *ifp; -{ - register struct pkcb *pkcb = 0; - register struct pklcd **lcpp, *lcp; - int s = splimp(); - - FOR_ALL_PKCBS(pkcb) - if (pkcb->pk_ia->ia_ifp == ifp) - for (lcpp = pkcb->pk_chan + pkcb->pk_maxlcn; - --lcpp > pkcb->pk_chan;) - if ((lcp = *lcpp) && - lcp->lcd_state == DATA_TRANSFER && - (lcp->lcd_flags & X25_DG_CIRCUIT) && - (lcp->lcd_dg_timer && --lcp->lcd_dg_timer == 0)) { - lcp->lcd_upper(lcp, 0); - } - splx(s); -} -/* - * This routine gets called when validating additions of new routes - * or deletions of old ones. - */ -x25_rtrequest(cmd, rt, dst) -register struct rtentry *rt; -struct sockaddr *dst; -{ - register struct llinfo_x25 *lx = (struct llinfo_x25 *)rt->rt_llinfo; - register struct sockaddr_x25 *sa =(struct sockaddr_x25 *)rt->rt_gateway; - register struct pklcd *lcp; - - /* would put this pk_init, except routing table doesn't - exist yet. */ - if (x25_dgram_sockmask == 0) { - struct radix_node *rn_addmask(); - x25_dgram_sockmask = - SA(rn_addmask((caddr_t)&x25_dgmask, 0, 4)->rn_key); - } - if (rt->rt_flags & RTF_GATEWAY) { - if (rt->rt_llinfo) - RTFREE((struct rtentry *)rt->rt_llinfo); - rt->rt_llinfo = (cmd == RTM_ADD) ? - (caddr_t)rtalloc1(rt->rt_gateway, 1) : 0; - return; - } - if ((rt->rt_flags & RTF_HOST) == 0) - return; - if (cmd == RTM_DELETE) { - while (rt->rt_llinfo) - x25_lxfree((struct llinfo *)rt->rt_llinfo); - x25_rtinvert(RTM_DELETE, rt->rt_gateway, rt); - return; - } - if (lx == 0 && (lx = x25_lxalloc(rt)) == 0) - return; - if ((lcp = lx->lx_lcd) && lcp->lcd_state != READY) { - /* - * This can only happen on a RTM_CHANGE operation - * though cmd will be RTM_ADD. - */ - if (lcp->lcd_ceaddr && - Bcmp(rt->rt_gateway, lcp->lcd_ceaddr, - lcp->lcd_ceaddr->x25_len) != 0) { - x25_rtinvert(RTM_DELETE, lcp->lcd_ceaddr, rt); - lcp->lcd_upper = 0; - pk_disconnect(lcp); - } - lcp = 0; - } - x25_rtinvert(RTM_ADD, rt->rt_gateway, rt); -} - -int x25_dont_rtinvert = 0; - -x25_rtinvert(cmd, sa, rt) -register struct sockaddr *sa; -register struct rtentry *rt; -{ - struct rtentry *rt2 = 0; - /* - * rt_gateway contains PID indicating which proto - * family on the other end, so will be different - * from general host route via X.25. - */ - if (rt->rt_ifp->if_type == IFT_X25DDN || x25_dont_rtinvert) - return; - if (sa->sa_family != AF_CCITT) - return; - if (cmd != RTM_DELETE) { - rtrequest(RTM_ADD, sa, rt_key(rt), x25_dgram_sockmask, - RTF_PROTO2, &rt2); - if (rt2) { - rt2->rt_llinfo = (caddr_t) rt; - RTHOLD(rt); - } - return; - } - rt2 = rt; - if ((rt = rtalloc1(sa, 0)) == 0 || - (rt->rt_flags & RTF_PROTO2) == 0 || - rt->rt_llinfo != (caddr_t)rt2) { - printf("x25_rtchange: inverse route foulup\n"); - return; - } else - rt2->rt_refcnt--; - rtrequest(RTM_DELETE, sa, rt_key(rt2), x25_dgram_sockmask, - 0, (struct rtentry **) 0); -} - -static struct sockaddr_x25 blank_x25 = {sizeof blank_x25, AF_CCITT}; -/* - * IP to X25 address routine copyright ACC, used by permission. - */ -union imp_addr { - struct in_addr ip; - struct imp { - u_char s_net; - u_char s_host; - u_char s_lh; - u_char s_impno; - } imp; -}; - -/* - * The following is totally bogus and here only to preserve - * the IP to X.25 translation. - */ -x25_ddnip_to_ccitt(src, rt) -struct sockaddr_in *src; -register struct rtentry *rt; -{ - register struct sockaddr_x25 *dst = (struct sockaddr_x25 *)rt->rt_gateway; - union imp_addr imp_addr; - int imp_no, imp_port, temp; - char *x25addr = dst->x25_addr; - - - imp_addr.ip = src->sin_addr; - *dst = blank_x25; - if ((imp_addr.imp.s_net & 0x80) == 0x00) { /* class A */ - imp_no = imp_addr.imp.s_impno; - imp_port = imp_addr.imp.s_host; - } else if ((imp_addr.imp.s_net & 0xc0) == 0x80) { /* class B */ - imp_no = imp_addr.imp.s_impno; - imp_port = imp_addr.imp.s_lh; - } else { /* class C */ - imp_no = imp_addr.imp.s_impno / 32; - imp_port = imp_addr.imp.s_impno % 32; - } - - x25addr[0] = 12; /* length */ - /* DNIC is cleared by struct copy above */ - - if (imp_port < 64) { /* Physical: 0000 0 IIIHH00 [SS] *//* s_impno - * -> III, s_host -> HH */ - x25addr[5] = 0; /* set flag bit */ - x25addr[6] = imp_no / 100; - x25addr[7] = (imp_no % 100) / 10; - x25addr[8] = imp_no % 10; - x25addr[9] = imp_port / 10; - x25addr[10] = imp_port % 10; - } else { /* Logical: 0000 1 RRRRR00 [SS] *//* s - * _host * 256 + s_impno -> RRRRR */ - temp = (imp_port << 8) + imp_no; - x25addr[5] = 1; - x25addr[6] = temp / 10000; - x25addr[7] = (temp % 10000) / 1000; - x25addr[8] = (temp % 1000) / 100; - x25addr[9] = (temp % 100) / 10; - x25addr[10] = temp % 10; - } -} - -/* - * This routine is a sketch and is not to be believed!!!!! - * - * This is a utility routine to be called by x25 devices when a - * call request is honored with the intent of starting datagram forwarding. - */ -x25_dg_rtinit(dst, ia, af) -struct sockaddr_x25 *dst; -register struct x25_ifaddr *ia; -{ - struct sockaddr *sa = 0; - struct rtentry *rt; - struct in_addr my_addr; - static struct sockaddr_in sin = {sizeof(sin), AF_INET}; - - if (ia->ia_ifp->if_type == IFT_X25DDN && af == AF_INET) { - /* - * Inverse X25 to IP mapping copyright and courtesy ACC. - */ - int imp_no, imp_port, temp; - union imp_addr imp_addr; - { - /* - * First determine our IP addr for network - */ - register struct in_ifaddr *ina; - extern struct in_ifaddr *in_ifaddr; - - for (ina = in_ifaddr; ina; ina = ina->ia_next) - if (ina->ia_ifp == ia->ia_ifp) { - my_addr = ina->ia_addr.sin_addr; - break; - } - } - { - - register char *x25addr = dst->x25_addr; - - switch (x25addr[5] & 0x0f) { - case 0: /* Physical: 0000 0 IIIHH00 [SS] */ - imp_no = - ((int) (x25addr[6] & 0x0f) * 100) + - ((int) (x25addr[7] & 0x0f) * 10) + - ((int) (x25addr[8] & 0x0f)); - - - imp_port = - ((int) (x25addr[9] & 0x0f) * 10) + - ((int) (x25addr[10] & 0x0f)); - break; - case 1: /* Logical: 0000 1 RRRRR00 [SS] */ - temp = ((int) (x25addr[6] & 0x0f) * 10000) - + ((int) (x25addr[7] & 0x0f) * 1000) - + ((int) (x25addr[8] & 0x0f) * 100) - + ((int) (x25addr[9] & 0x0f) * 10) - + ((int) (x25addr[10] & 0x0f)); - - imp_port = temp >> 8; - imp_no = temp & 0xff; - break; - default: - return (0L); - } - imp_addr.ip = my_addr; - if ((imp_addr.imp.s_net & 0x80) == 0x00) { - /* class A */ - imp_addr.imp.s_host = imp_port; - imp_addr.imp.s_impno = imp_no; - imp_addr.imp.s_lh = 0; - } else if ((imp_addr.imp.s_net & 0xc0) == 0x80) { - /* class B */ - imp_addr.imp.s_lh = imp_port; - imp_addr.imp.s_impno = imp_no; - } else { - /* class C */ - imp_addr.imp.s_impno = (imp_no << 5) + imp_port; - } - } - sin.sin_addr = imp_addr.ip; - sa = (struct sockaddr *)&sin; - } else { - /* - * This uses the X25 routing table to do inverse - * lookup of x25 address to sockaddr. - */ - if (rt = rtalloc1(SA(dst), 0)) { - sa = rt->rt_gateway; - rt->rt_refcnt--; - } - } - /* - * Call to rtalloc1 will create rtentry for reverse path - * to callee by virtue of cloning magic and will allocate - * space for local control block. - */ - if (sa && (rt = rtalloc1(sa, 1))) - rt->rt_refcnt--; -} -int x25_startproto = 1; - -pk_init() -{ - /* - * warning, sizeof (struct sockaddr_x25) > 32, - * but contains no data of interest beyond 32 - */ - if (x25_startproto) { - pk_protolisten(0xcc, 1, x25_dgram_incoming); - pk_protolisten(0x81, 1, x25_dgram_incoming); - } -} - -struct x25_dgproto { - u_char spi; - u_char spilen; - int (*f)(); -} x25_dgprototab[] = { -#if (ISO) && (TPCONS) -{ 0x0, 0, tp_incoming}, -#endif -{ 0xcc, 1, x25_dgram_incoming}, -{ 0xcd, 1, x25_dgram_incoming}, -{ 0x81, 1, x25_dgram_incoming}, -}; - -pk_user_protolisten(info) -register u_char *info; -{ - register struct x25_dgproto *dp = x25_dgprototab - + ((sizeof x25_dgprototab) / (sizeof *dp)); - register struct pklcd *lcp; - - while (dp > x25_dgprototab) - if ((--dp)->spi == info[0]) - goto gotspi; - return ESRCH; - -gotspi: if (info[1]) - return pk_protolisten(dp->spi, dp->spilen, dp->f); - for (lcp = pk_listenhead; lcp; lcp = lcp->lcd_listen) - if (lcp->lcd_laddr.x25_udlen == dp->spilen && - Bcmp(&dp->spi, lcp->lcd_laddr.x25_udata, dp->spilen) == 0) { - pk_disconnect(lcp); - return 0; - } - return ESRCH; -} - -/* - * This routine transfers an X.25 circuit to or from a routing entry. - * If the supplied circuit is * in DATA_TRANSFER state, it is added to the - * routing entry. If freshly allocated, it glues back the vc from - * the rtentry to the socket. - */ -pk_rtattach(so, m0) -register struct socket *so; -struct mbuf *m0; -{ - register struct pklcd *lcp = (struct pklcd *)so->so_pcb; - register struct mbuf *m = m0; - struct sockaddr *dst = mtod(m, struct sockaddr *); - register struct rtentry *rt = rtalloc1(dst, 0); - register struct llinfo_x25 *lx; - caddr_t cp; -#define ROUNDUP(a) \ - ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) -#define transfer_sockbuf(s, f, l) \ - while (m = (s)->sb_mb)\ - {(s)->sb_mb = m->m_act; m->m_act = 0; sbfree((s), m); f(l, m);} - - if (rt) - rt->rt_refcnt--; - cp = (dst->sa_len < m->m_len) ? ROUNDUP(dst->sa_len) + (caddr_t)dst : 0; - while (rt && - ((cp == 0 && rt_mask(rt) != 0) || - (cp != 0 && (rt_mask(rt) == 0 || - Bcmp(cp, rt_mask(rt), rt_mask(rt)->sa_len)) != 0))) - rt = (struct rtentry *)rt->rt_nodes->rn_dupedkey; - if (rt == 0 || (rt->rt_flags & RTF_GATEWAY) || - (lx = (struct llinfo_x25 *)rt->rt_llinfo) == 0) - return ESRCH; - if (lcp == 0) - return ENOTCONN; - switch (lcp->lcd_state) { - default: - return ENOTCONN; - - case READY: - /* Detach VC from rtentry */ - if (lx->lx_lcd == 0) - return ENOTCONN; - lcp->lcd_so = 0; - pk_close(lcp); - lcp = lx->lx_lcd; - if (lx->lx_next->lx_rt == rt) - x25_lxfree(lx); - lcp->lcd_so = so; - lcp->lcd_upper = 0; - lcp->lcd_upnext = 0; - transfer_sockbuf(&lcp->lcd_sb, sbappendrecord, &so->so_snd); - soisconnected(so); - return 0; - - case DATA_TRANSFER: - /* Add VC to rtentry */ - lcp->lcd_so = 0; - lcp->lcd_sb = so->so_snd; /* structure copy */ - bzero((caddr_t)&so->so_snd, sizeof(so->so_snd)); /* XXXXXX */ - so->so_pcb = 0; - x25_rtattach(lcp, rt); - transfer_sockbuf(&so->so_rcv, x25_ifinput, lcp); - soisdisconnected(so); - } - return 0; -} -x25_rtattach(lcp0, rt) -register struct pklcd *lcp0; -struct rtentry *rt; -{ - register struct llinfo_x25 *lx = (struct llinfo_x25 *)rt->rt_llinfo; - register struct pklcd *lcp; - register struct mbuf *m; - if (lcp = lx->lx_lcd) { /* adding an additional VC */ - if (lcp->lcd_state == READY) { - transfer_sockbuf(&lcp->lcd_sb, pk_output, lcp0); - lcp->lcd_upper = 0; - pk_close(lcp); - } else { - lx = x25_lxalloc(rt); - if (lx == 0) - return ENOBUFS; - } - } - lx->lx_lcd = lcp = lcp0; - lcp->lcd_upper = x25_ifinput; - lcp->lcd_upnext = (caddr_t)lx; -} diff --git a/bsd/netccitt/llc_input.c b/bsd/netccitt/llc_input.c deleted file mode 100644 index aacbce91c..000000000 --- a/bsd/netccitt/llc_input.c +++ /dev/null @@ -1,489 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (C) Dirk Husemann, Computer Science Department IV, - * University of Erlangen-Nuremberg, Germany, 1990, 1991, 1992 - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Dirk Husemann and the Computer Science Department (IV) of - * the University of Erlangen-Nuremberg, Germany. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)llc_input.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -/* - * This module implements LLC as specified by ISO 8802-2. - */ - - -/* - * llcintr() handles all LLC frames (except ISO CLNS ones for the time being) - * and tries to pass them on to the appropriate network layer entity. - */ -void -llcintr() -{ - register struct mbuf *m; - register int i; - register int frame_kind; - register u_char cmdrsp; - struct llc_linkcb *linkp; - struct rtentry *sirt; - struct npaidbentry *sapinfo; - struct sdl_hdr *sdlhdr; - struct llc *frame; - char *c; - long expected_len; - - struct ifnet *ifp; - struct rtentry *llrt; - struct rtentry *nlrt; - - for (;;) { - i = splimp(); - IF_DEQUEUE(&llcintrq, m); - splx(i); - if (m == 0) - break; -#if DIAGNOSTIC - if ((m->m_flags & M_PKTHDR) == 0) - panic("llcintr no HDR"); -#endif - /* - * Get ifp this packet was received on - */ - ifp = m->m_pkthdr.rcvif; - - sdlhdr = mtod(m, struct sdl_hdr *); - - /* - * [Copied from net/ip_input.c] - * - * Check that the amount of data in the buffers is - * at least as much as the LLC header tells us. - * Trim mbufs if longer than expected. - * Drop packets if shorter than we think they are. - * - * Layout of mbuf chain at this point: - * - * +-------------------------------+----+ -\ - * | sockaddr_dl src - sdlhdr_src | 20 | \ - * +-------------------------------+----+ | - * | sockaddr_dl dst - sdlhdr_dst | 20 | > sizeof(struct sdl_hdr) == 44 - * +-------------------------------+----+ | - * | LLC frame len - sdlhdr_len | 04 | / - * +-------------------------------+----+ -/ - * / - * | m_next - * \ - * +----------------------------+----+ -\ - * | llc DSAP | 01 | \ - * +----------------------------+----+ | - * | llc SSAP | 01 | | - * +----------------------------+----+ > sdlhdr_len - * | llc control | 01 | | - * +----------------------------+----+ | - * | ... | | / - * -/ - * - * Thus the we expect to have exactly - * (sdlhdr->sdlhdr_len+sizeof(struct sdl_hdr)) in the mbuf chain - */ - expected_len = sdlhdr->sdlhdr_len + sizeof(struct sdl_hdr); - - if (m->m_pkthdr.len < expected_len) { - m_freem(m); - continue; - } - if (m->m_pkthdr.len > expected_len) { - if (m->m_len == m->m_pkthdr.len) { - m->m_len = expected_len; - m->m_pkthdr.len = expected_len; - } else - m_adj(m, expected_len - m->m_pkthdr.len); - } - - /* - * Get llc header - */ - if (m->m_len > sizeof(struct sdl_hdr)) - frame = mtod((struct mbuf *)((struct sdl_hdr*)(m+1)), - struct llc *); - else frame = mtod(m->m_next, struct llc *); - if (frame == (struct llc *) NULL) - panic("llcintr no llc header"); - - /* - * Now check for bogus I/S frame, i.e. those with a control - * field telling us they're an I/S frame yet their length - * is less than the established I/S frame length (DSAP + SSAP + - * control + N(R)&P/F = 4) --- we drop those suckers - */ - if (((frame->llc_control & 0x03) != 0x03) - && ((expected_len - sizeof(struct sdl_hdr)) < LLC_ISFRAMELEN)) { - m_freem(m); - printf("llc: hurz error\n"); - continue; - } - - /* - * Get link control block for the addressed link connection. - * If there is none we take care of it later on. - */ - cmdrsp = (frame->llc_ssap & 0x01); - frame->llc_ssap &= ~0x01; - if (llrt = rtalloc1((struct sockaddr *)&sdlhdr->sdlhdr_src, 0)) - llrt->rt_refcnt--; -#ifdef notyet - else llrt = npaidb_enter(&sdlhdr->sdlhdr_src, 0, 0, 0); -#endif /* notyet */ - else { - /* - * We cannot do anything currently here as we - * don't `know' this link --- drop it - */ - m_freem(m); - continue; - } - linkp = ((struct npaidbentry *)(llrt->rt_llinfo))->np_link; - nlrt = ((struct npaidbentry *)(llrt->rt_llinfo))->np_rt; - - /* - * If the link is not existing right now, we can try and look up - * the SAP info block. - */ - if ((linkp == 0) && frame->llc_ssap) - sapinfo = llc_getsapinfo(frame->llc_dsap, ifp); - - /* - * Handle XID and TEST frames - * XID: if DLSAP == 0, return type-of-services - * window-0 - * DLSAP-0 - * format-identifier-? - * if DLSAP != 0, locate sapcb and return - * type-of-services - * SAP-window - * format-identifier-? - * TEST: swap (snpah_dst, snpah_src) and return frame - * - * Also toggle the CMD/RESP bit - * - * Is this behaviour correct? Check ISO 8802-2 (90)! - */ - frame_kind = llc_decode(frame, (struct llc_linkcb *)0); - switch(frame_kind) { - case LLCFT_XID: - if (linkp || sapinfo) { - if (linkp) - frame->llc_window = linkp->llcl_window; - else frame->llc_window = sapinfo->si_window; - frame->llc_fid = 9; /* XXX */ - frame->llc_class = sapinfo->si_class; - frame->llc_ssap = frame->llc_dsap; - } else { - frame->llc_window = 0; - frame->llc_fid = 9; - frame->llc_class = 1; - frame->llc_dsap = frame->llc_ssap = 0; - } - - /* fall thru to */ - case LLCFT_TEST: - sdl_swapaddr(&(mtod(m, struct sdl_hdr *)->sdlhdr_dst), - &(mtod(m, struct sdl_hdr *)->sdlhdr_src)); - - /* Now set the CMD/RESP bit */ - frame->llc_ssap |= (cmdrsp == 0x0 ? 0x1 : 0x0); - - /* Ship it out again */ - (*ifp->if_output)(ifp, m, - (struct sockaddr *) &(mtod(m, struct sdl_hdr *)->sdlhdr_dst), - (struct rtentry *) 0); - continue; - } - - /* - * Create link control block in case it is not existing - */ - if (linkp == 0 && sapinfo) { - if ((linkp = llc_newlink(&sdlhdr->sdlhdr_src, ifp, nlrt, - (nlrt == 0) ? 0 : nlrt->rt_llinfo, - llrt)) == 0) { - printf("llcintr: couldn't create new link\n"); - m_freem(m); - continue; - } - ((struct npaidbentry *)llrt->rt_llinfo)->np_link = linkp; - } else if (linkp == 0) { - /* The link is not known to us, drop the frame and continue */ - m_freem(m); - continue; - } - - /* - * Drop SNPA header and get rid of empty mbuf at the - * front of the mbuf chain (I don't like 'em) - */ - m_adj(m, sizeof(struct sdl_hdr)); - /* - * LLC_UFRAMELEN is sufficient, m_pullup() will pull up - * the min(m->m_len, maxprotohdr_len [=40]) thus doing - * the trick ... - */ - if ((m = m_pullup(m, LLC_UFRAMELEN))) - /* - * Pass it on thru the elements of procedure - */ - llc_input(linkp, m, cmdrsp); - } - return; -} - -/* - * llc_input() --- We deal with the various incoming frames here. - * Basically we (indirectly) call the appropriate - * state handler function that's pointed to by - * llcl_statehandler. - * - * The statehandler returns an action code --- - * further actions like - * o notify network layer - * o block further sending - * o deblock link - * o ... - * are then enacted accordingly. - */ -llc_input(struct llc_linkcb *linkp, struct mbuf *m, u_char cmdrsp) -{ - int frame_kind; - int pollfinal; - int action = 0; - struct llc *frame; - struct ifnet *ifp = linkp->llcl_if; - - if ((frame = mtod(m, struct llc *)) == (struct llc *) 0) { - m_freem(m); - return 0; - } - pollfinal = ((frame->llc_control & 0x03) == 0x03) ? - LLCGBITS(frame->llc_control, u_pf) : - LLCGBITS(frame->llc_control_ext, s_pf); - - /* - * first decode the frame - */ - frame_kind = llc_decode(frame, linkp); - - switch (action = llc_statehandler(linkp, frame, frame_kind, cmdrsp, - pollfinal)) { - case LLC_DATA_INDICATION: - m_adj(m, LLC_ISFRAMELEN); - if (m = m_pullup(m, NLHDRSIZEGUESS)) { - m->m_pkthdr.rcvif = (struct ifnet *)linkp->llcl_nlnext; - (*linkp->llcl_sapinfo->si_input)(m); - } - break; - } - - /* release mbuf if not an info frame */ - if (action != LLC_DATA_INDICATION && m) - m_freem(m); - - /* try to get frames out ... */ - llc_start(linkp); - - return 0; -} - -/* - * This routine is called by configuration setup. It sets up a station control - * block and notifies all registered upper level protocols. - */ -caddr_t -llc_ctlinput(int prc, struct sockaddr *addr, caddr_t info) -{ - struct ifnet *ifp; - struct ifaddr *ifa; - struct dll_ctlinfo *ctlinfo = (struct dll_ctlinfo *)info; - u_char sap; - struct dllconfig *config; - caddr_t pcb; - struct rtentry *nlrt; - struct rtentry *llrt; - struct llc_linkcb *linkp; - register int i; - - /* info must point to something valid at all times */ - if (info == 0) - return 0; - - if (prc == PRC_IFUP || prc == PRC_IFDOWN) { - /* we use either this set ... */ - ifa = ifa_ifwithaddr(addr); - ifp = ifa ? ifa->ifa_ifp : 0; - if (ifp == 0) - return 0; - - sap = ctlinfo->dlcti_lsap; - config = ctlinfo->dlcti_cfg; - pcb = (caddr_t) 0; - nlrt = (struct rtentry *) 0; - } else { - /* or this one */ - sap = 0; - config = (struct dllconfig *) 0; - pcb = ctlinfo->dlcti_pcb; - nlrt = ctlinfo->dlcti_rt; - - if ((llrt = rtalloc1(nlrt->rt_gateway, 0))) - llrt->rt_refcnt--; - else return 0; - - linkp = ((struct npaidbentry *)llrt->rt_llinfo)->np_link; - } - - switch (prc) { - case PRC_IFUP: - (void) llc_setsapinfo(ifp, addr->sa_family, sap, config); - return 0; - - case PRC_IFDOWN: { - register struct llc_linkcb *linkp; - register struct llc_linkcb *nlinkp; - register int i; - - /* - * All links are accessible over the doubly linked list llccb_q - */ - if (!LQEMPTY) { - /* - * A for-loop is not that great an idea as the linkp - * will get deleted by llc_timer() - */ - linkp = LQFIRST; - while (LQVALID(linkp)) { - nlinkp = LQNEXT(linkp); - if (linkp->llcl_if = ifp) { - i = splimp(); - (void)llc_statehandler(linkp, (struct llc *)0, - NL_DISCONNECT_REQUEST, - 0, 1); - splx(i); - } - linkp = nlinkp; - } - } - } - - case PRC_CONNECT_REQUEST: - if (linkp == 0) { - if ((linkp = llc_newlink((struct sockaddr_dl *) nlrt->rt_gateway, - nlrt->rt_ifp, nlrt, - pcb, llrt)) == 0) - return (0); - ((struct npaidbentry *)llrt->rt_llinfo)->np_link = linkp; - i = splimp(); - (void)llc_statehandler(linkp, (struct llc *) 0, - NL_CONNECT_REQUEST, 0, 1); - splx(i); - } - return ((caddr_t)linkp); - - case PRC_DISCONNECT_REQUEST: - if (linkp == 0) - panic("no link control block!"); - - i = splimp(); - (void)llc_statehandler(linkp, (struct llc *) 0, - NL_DISCONNECT_REQUEST, 0, 1); - splx(i); - - /* - * The actual removal of the link control block is done by the - * cleaning neutrum (i.e. llc_timer()). - */ - break; - - case PRC_RESET_REQUEST: - if (linkp == 0) - panic("no link control block!"); - - i = splimp(); - (void)llc_statehandler(linkp, (struct llc *) 0, - NL_RESET_REQUEST, 0, 1); - splx(i); - - break; - - } - - return 0; -} diff --git a/bsd/netccitt/llc_output.c b/bsd/netccitt/llc_output.c deleted file mode 100644 index 951429296..000000000 --- a/bsd/netccitt/llc_output.c +++ /dev/null @@ -1,325 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (C) Dirk Husemann, Computer Science Department IV, - * University of Erlangen-Nuremberg, Germany, 1990, 1991, 1992 - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Dirk Husemann and the Computer Science Department (IV) of - * the University of Erlangen-Nuremberg, Germany. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)llc_output.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -/* - * llc_output() --- called by an upper layer (network layer) entity whenever - * there is an INFO frame to be transmitted. We enqueue the - * info frame and call llc_start() to do the actual sending. - */ - -llc_output(struct llc_linkcb *linkp, struct mbuf *m) -{ - register int i; - - i = splimp(); - LLC_ENQUEUE(linkp, m); - llc_start(linkp); - splx(i); - -} - - -/* - * llc_start() --- We try to subsequently dequeue all the frames available and - * send them out. - */ -void -llc_start(struct llc_linkcb *linkp) -{ - register int i; - register struct mbuf *m; - int action; - - while ((LLC_STATEEQ(linkp, NORMAL) || LLC_STATEEQ(linkp, BUSY) || - LLC_STATEEQ(linkp, REJECT)) && - (linkp->llcl_slotsfree > 0) && - (LLC_GETFLAG(linkp, REMOTE_BUSY) == 0)) { - LLC_DEQUEUE(linkp, m); - if (m == NULL) - break; - LLC_SETFRAME(linkp, m); - (void)llc_statehandler(linkp, (struct llc *) 0, NL_DATA_REQUEST, - 0, 0); - } -} - - -/* - * llc_send() --- Handles single frames. If dealing with INFO frames we need to - * prepend the LLC header, otherwise we just allocate an mbuf. - * In both cases the actual send is done by llc_rawsend(). - */ -llc_send(struct llc_linkcb *linkp, int frame_kind, int cmdrsp, int pollfinal) -{ - register struct mbuf *m = (struct mbuf *)0; - register struct llc *frame; - - if (frame_kind == LLCFT_INFO) - m = linkp->llcl_output_buffers[llc_seq2slot(linkp, - linkp->llcl_vs)]; - LLC_GETHDR(frame, m); - - /* pass it on to llc_rawsend() */ - llc_rawsend(linkp, m, frame, frame_kind, linkp->llcl_vs, cmdrsp, pollfinal); - - if (frame_kind == LLCFT_INFO) - LLC_INC(linkp->llcl_vs); - - return 0; -} - -/* - * llc_resend() --- llc_resend() retransmits all unacknowledged INFO frames. - */ -llc_resend(struct llc_linkcb *linkp, int cmdrsp, int pollfinal) -{ - register struct llc *frame; - register struct mbuf *m; - register int seq, slot; - - if (linkp->llcl_slotsfree < linkp->llcl_window) - /* assert lock between nr_received & V(S) */ - if (linkp->llcl_nr_received != linkp->llcl_vs) - panic("llc: V(S) != N(R) received\n"); - - for (slot = llc_seq2slot(linkp, linkp->llcl_vs); - slot != linkp->llcl_freeslot; - LLC_INC(linkp->llcl_vs), - slot = llc_seq2slot(linkp, linkp->llcl_vs)) { - m = linkp->llcl_output_buffers[slot]; - LLC_GETHDR(frame, m); - llc_rawsend(linkp, m, frame, LLCFT_INFO, linkp->llcl_vs, - cmdrsp, pollfinal); - pollfinal = 0; - } - - return 0; -} - -/* - * llc_rawsend() --- constructs an LLC frame and sends it out via the - * associated interface of the link control block. - * - * We need to make sure that outgoing frames have the correct length, - * in particular the 4 byte ones (RR, RNR, REJ) as LLC_GETHDR() will - * set the mbuf len to 3 as default len for non INFO frames ... - * - * Frame kind Length (w/o MAC header, {D,S}SAP incl.) - * -------------------------------------------------------------- - * DISC, SABME, UA, DM 3 bytes ({D,S}SAP + CONTROL) - * RR, RNR, REJ 4 bytes ({D,S}SAP + CONTROL0 + CONTROL1) - * XID 6 bytes ({D,S}SAP + CONTROL0 + FI,CLASS,WINDOW) - * FRMR 7 bytes ({D,S}SAP + CONTROL0 + REJ CONTROL,V(S),V(R),CAUSE) - * INFO 4 -- MTU - * UI, TEST 3 -- MTU - * - */ -#define LLC_SETLEN(m, l) (m)->m_pkthdr.len = (m)->m_len = (l) - -llc_rawsend(struct llc_linkcb *linkp, struct mbuf *m, struct llc *frame, - int frame_kind, int vs, int cmdrsp, int pollfinal) -{ - register short adjust = LLC_UFRAMELEN; - struct ifnet *ifp; - - switch (frame_kind) { - /* supervisory and information frames */ - case LLCFT_INFO: - frame->llc_control = LLC_INFO; - LLCSBITS(frame->llc_control, i_ns, vs); - LLCSBITS(frame->llc_control_ext, i_nr, linkp->llcl_vr); - adjust = LLC_ISFRAMELEN; - break; - case LLCFT_RR: - frame->llc_control = LLC_RR; - LLC_SETLEN(m, LLC_ISFRAMELEN); - LLCSBITS(frame->llc_control_ext, s_nr, linkp->llcl_vr); - adjust = LLC_ISFRAMELEN; - break; - case LLCFT_RNR: - frame->llc_control = LLC_RNR; - LLC_SETLEN(m, LLC_ISFRAMELEN); - LLCSBITS(frame->llc_control_ext, s_nr, linkp->llcl_vr); - adjust = LLC_ISFRAMELEN; - break; - case LLCFT_REJ: - frame->llc_control = LLC_REJ; - LLC_SETLEN(m, LLC_ISFRAMELEN); - LLCSBITS(frame->llc_control_ext, s_nr, linkp->llcl_vr); - adjust = LLC_ISFRAMELEN; - break; - /* unnumbered frames */ - case LLCFT_DM: - frame->llc_control = LLC_DM; - break; - case LLCFT_SABME: - frame->llc_control = LLC_SABME; - break; - case LLCFT_DISC: - frame->llc_control = LLC_DISC; - break; - case LLCFT_UA: - frame->llc_control = LLC_UA; - break; - case LLCFT_UI: - frame->llc_control = LLC_UI; - break; - case LLCFT_FRMR: - frame->llc_control = LLC_FRMR; - /* get more space --- FRMR frame are longer then usual */ - LLC_SETLEN(m, LLC_FRMRLEN); - bcopy((caddr_t) &linkp->llcl_frmrinfo, - (caddr_t) &frame->llc_frmrinfo, - sizeof(struct frmrinfo)); - break; - default: - /* - * We don't send {XID, TEST} frames - */ - if (m) - m_freem(m); - return; - } - - /* - * Fill in DSAP/SSAP - */ - frame->llc_dsap = frame->llc_ssap = LLSAPADDR(&linkp->llcl_addr); - frame->llc_ssap |= cmdrsp; - - /* - * Check for delayed action pending. ISO 8802-2, 7.9.2 (5) - * and ISO 8802-2, 7.9.2.3 (32), (34), (36) pertain to this - * piece of code --- hopefully we got it right here (i.e. - * in the spirit of (32), (34), and (36) ... - */ - switch (frame_kind) { - case LLCFT_RR: - case LLCFT_RNR: - case LLCFT_REJ: - case LLCFT_INFO: - switch (LLC_GETFLAG(linkp, DACTION)) { - case LLC_DACKCMD: - case LLC_DACKRSP: - LLC_STOPTIMER(linkp, DACTION); - break; - case LLC_DACKCMDPOLL: - if (cmdrsp == LLC_CMD) { - pollfinal = 1; - LLC_STOPTIMER(linkp, DACTION); - } - break; - case LLC_DACKRSPFINAL: - if (cmdrsp == LLC_RSP) { - pollfinal = 1; - LLC_STOPTIMER(linkp, DACTION); - } - break; - } - break; - } - - if (adjust == LLC_UFRAMELEN) - LLCSBITS(frame->llc_control, u_pf, pollfinal); - else LLCSBITS(frame->llc_control_ext, s_pf, pollfinal); - - /* - * Get interface to send frame onto - */ - ifp = linkp->llcl_if; - if (frame_kind == LLCFT_INFO) { - /* - * send out a copy of the frame, retain the - * original - */ - (*ifp->if_output)(ifp, m_copy(m, 0, (int)M_COPYALL), - rt_key(linkp->llcl_nlrt), - linkp->llcl_nlrt); - /* - * Account for the LLC header and let it ``disappear'' - * as the raw info frame payload is what we hold in - * the output_buffers of the link. - */ - m_adj(m, LLC_ISFRAMELEN); - } else (*ifp->if_output)(ifp, m, - rt_key(linkp->llcl_nlrt), - linkp->llcl_nlrt); -} - diff --git a/bsd/netccitt/llc_subr.c b/bsd/netccitt/llc_subr.c deleted file mode 100644 index c8c56d1cf..000000000 --- a/bsd/netccitt/llc_subr.c +++ /dev/null @@ -1,2379 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (C) Dirk Husemann, Computer Science Department IV, - * University of Erlangen-Nuremberg, Germany, 1990, 1991, 1992 - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Dirk Husemann and the Computer Science Department (IV) of - * the University of Erlangen-Nuremberg, Germany. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)llc_subr.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -/* - * Frame names for diagnostic messages - */ -char *frame_names[] = { "INFO", "RR", "RNR", "REJ", "DM", "SABME", "DISC", - "UA", "FRMR", "UI", "XID", "TEST", "ILLEGAL", "TIMER", "N2xT1"}; - - -/* - * Trace level - */ -int llc_tracelevel = LLCTR_URGENT; - -/* - * Values for accessing various bitfields - */ -struct bitslice llc_bitslice[] = { -/* mask, shift value */ - { 0x1, 0x0 }, - { 0xfe, 0x1 }, - { 0x3, 0x0 }, - { 0xc, 0x2 }, - { 0x10, 0x4 }, - { 0xe0, 0x5 }, - { 0x1f, 0x0 } -}; - -/* - * We keep the link control blocks on a doubly linked list - - * primarily for checking in llc_time() - */ - -struct llccb_q llccb_q = { &llccb_q, &llccb_q }; - -/* - * Flag for signalling wether route tree for AF_LINK has been - * initialized yet. - */ - -int af_link_rts_init_done = 0; - - -/* - * Functions dealing with struct sockaddr_dl */ - -/* Compare sdl_a w/ sdl_b */ - -sdl_cmp(struct sockaddr_dl *sdl_a, struct sockaddr_dl *sdl_b) -{ - if (LLADDRLEN(sdl_a) != LLADDRLEN(sdl_b)) - return(1); - return(bcmp((caddr_t) sdl_a->sdl_data, (caddr_t) sdl_b->sdl_data, - LLADDRLEN(sdl_a))); -} - -/* Copy sdl_f to sdl_t */ - -sdl_copy(struct sockaddr_dl *sdl_f, struct sockaddr_dl *sdl_t) -{ - bcopy((caddr_t) sdl_f, (caddr_t) sdl_t, sdl_f->sdl_len); -} - -/* Swap sdl_a w/ sdl_b */ - -sdl_swapaddr(struct sockaddr_dl *sdl_a, struct sockaddr_dl *sdl_b) -{ - struct sockaddr_dl sdl_tmp; - - sdl_copy(sdl_a, &sdl_tmp); - sdl_copy(sdl_b, sdl_a); - sdl_copy(&sdl_tmp, sdl_b); -} - -/* Fetch the sdl of the associated if */ - -struct sockaddr_dl * -sdl_getaddrif(struct ifnet *ifp) -{ - register struct ifaddr *ifa; - - for(ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) - if (ifa->ifa_addr->sa_family == AF_LINK ) - return((struct sockaddr_dl *)(ifa->ifa_addr)); - - return((struct sockaddr_dl *)0); -} - -/* Check addr of interface with the one given */ - -sdl_checkaddrif(struct ifnet *ifp, struct sockaddr_dl *sdl_c) -{ - register struct ifaddr *ifa; - - for(ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) - if ((ifa->ifa_addr->sa_family == AF_LINK ) && - !sdl_cmp((struct sockaddr_dl *)(ifa->ifa_addr), sdl_c)) - return(1); - - return(0); -} - -/* Build an sdl from MAC addr, DLSAP addr, and interface */ - -sdl_setaddrif(struct ifnet *ifp, u_char *mac_addr, u_char dlsap_addr, - u_char mac_len, struct sockaddr_dl *sdl_to) -{ - register struct sockaddr_dl *sdl_tmp; - - if ((sdl_tmp = sdl_getaddrif(ifp)) ) { - sdl_copy(sdl_tmp, sdl_to); - bcopy((caddr_t) mac_addr, (caddr_t) LLADDR(sdl_to), mac_len); - *(LLADDR(sdl_to)+mac_len) = dlsap_addr; - sdl_to->sdl_alen = mac_len+1; - return(1); - } else return(0); -} - -/* Fill out the sdl header aggregate */ - -sdl_sethdrif(struct ifnet *ifp, u_char *mac_src, u_char dlsap_src, u_char *mac_dst, - u_char dlsap_dst, u_char mac_len, struct sdl_hdr *sdlhdr_to) -{ - if ( !sdl_setaddrif(ifp, mac_src, dlsap_src, mac_len, - &sdlhdr_to->sdlhdr_src) || - !sdl_setaddrif(ifp, mac_dst, dlsap_dst, mac_len, - &sdlhdr_to->sdlhdr_dst) ) - return(0); - else return(1); -} - -static struct sockaddr_dl sap_saddr; -static struct sockaddr_dl sap_sgate = { - sizeof(struct sockaddr_dl), /* _len */ - AF_LINK /* _af */ -}; - -/* - * Set sapinfo for SAP address, llcconfig, af, and interface - */ -struct npaidbentry * -llc_setsapinfo(struct ifnet *ifp, u_char af, u_char sap, struct dllconfig *llconf) -{ - struct protosw *pp; - struct sockaddr_dl *ifdl_addr; - struct rtentry *sirt = (struct rtentry *)0; - struct npaidbentry *sapinfo; - u_char saploc; - int size = sizeof(struct npaidbentry); - - USES_AF_LINK_RTS; - - /* - * We rely/assume that only STREAM protocols will make use of - * connection oriented LLC2. If this will one day not be the - * case this will obviously fail. - */ - pp = pffindtype (af, SOCK_STREAM); - if (pp == 0 || pp->pr_input == 0 || pp->pr_ctlinput == 0) { - printf("network level protosw error"); - return 0; - } - - /* - * We need a way to jot down the LLC2 configuration for - * a certain LSAP address. To do this we enter - * a "route" for the SAP. - */ - ifdl_addr = sdl_getaddrif(ifp); - sdl_copy(ifdl_addr, &sap_saddr); - sdl_copy(ifdl_addr, &sap_sgate); - saploc = LLSAPLOC(&sap_saddr, ifp); - sap_saddr.sdl_data[saploc] = sap; - sap_saddr.sdl_alen++; - - /* now enter it */ - rtrequest(RTM_ADD, (struct sockaddr *)&sap_saddr, - (struct sockaddr *)&sap_sgate, 0, 0, &sirt); - if (sirt == 0) - return 0; - - /* Plug in config information in rt->rt_llinfo */ - -// sirt->rt_llinfo = malloc(size , M_PCB, M_WAITOK); - MALLOC(sirt->rt_llinfo, caddr_t, size, M_PCB, M_WAITOK); - sapinfo = (struct npaidbentry *) sirt->rt_llinfo; - if (sapinfo) { - bzero ((caddr_t)sapinfo, size); - /* - * For the time being we support LLC CLASS II here - * only - */ - sapinfo->si_class = LLC_CLASS_II; - sapinfo->si_window = llconf->dllcfg_window; - sapinfo->si_trace = llconf->dllcfg_trace; - if (sapinfo->si_trace) - llc_tracelevel--; - else llc_tracelevel++; - sapinfo->si_input = pp->pr_input; - sapinfo->si_ctlinput = (caddr_t (*)())pp->pr_ctlinput; - - return (sapinfo); - } - - return 0; -} - -/* - * Get sapinfo for SAP address and interface - */ -struct npaidbentry * -llc_getsapinfo(u_char sap, struct ifnet *ifp) -{ - struct sockaddr_dl *ifdl_addr; - struct sockaddr_dl si_addr; - struct rtentry *sirt; - u_char saploc; - - USES_AF_LINK_RTS; - - ifdl_addr = sdl_getaddrif(ifp); - sdl_copy(ifdl_addr, &si_addr); - saploc = LLSAPLOC(&si_addr, ifp); - si_addr.sdl_data[saploc] = sap; - si_addr.sdl_alen++; - - if ((sirt = rtalloc1((struct sockaddr *)&si_addr, 0))) - sirt->rt_refcnt--; - else return(0); - - return((struct npaidbentry *)sirt->rt_llinfo); -} - -/* - * llc_seq2slot() --- We only allocate enough memory to hold the window. This - * introduces the necessity to keep track of two ``pointers'' - * - * o llcl_freeslot the next free slot to be used - * this one advances modulo llcl_window - * o llcl_projvs the V(S) associated with the next frame - * to be set via llcl_freeslot - * this one advances modulo LLC_MAX_SEQUENCE - * - * A new frame is inserted at llcl_output_buffers[llcl_freeslot], after - * which both llcl_freeslot and llcl_projvs are incremented. - * - * The slot sl(sn) for any given sequence number sn is given by - * - * sl(sn) = (llcl_freeslot + llcl_window - 1 - (llcl_projvs + - * LLC_MAX_SEQUENCE- sn) % LLC_MAX_SEQUENCE) % - * llcl_window - * - * i.e. we first calculate the number of frames we need to ``go back'' - * from the current one (really the next one, but that doesn't matter as - * llcl_projvs is likewise of by plus one) and subtract that from the - * pointer to the most recently taken frame (llcl_freeslot - 1). - */ - -short -llc_seq2slot(struct llc_linkcb *linkp, short seqn) -{ - register sn = 0; - - sn = (linkp->llcl_freeslot + linkp->llcl_window - - (linkp->llcl_projvs + LLC_MAX_SEQUENCE - seqn) % - LLC_MAX_SEQUENCE) % linkp->llcl_window; - - return sn; -} - -/* - * LLC2 link state handler - * - * There is in most cases one function per LLC2 state. The LLC2 standard - * ISO 8802-2 allows in some cases for ambiguities, i.e. we have the choice - * to do one thing or the other. Right now I have just chosen one but have also - * indicated the spot by "multiple possibilities". One could make the behavior - * in those cases configurable, allowing the superuser to enter a profile word - * (32/64 bits, whatever is needed) that would suit her needs [I quite like - * that idea, perhaps I'll get around to it]. - * - * [Preceeding each state handler function is the description as taken from - * ISO 8802-2, section 7.9.2.1] - */ - -/* - * ADM --- The connection component is in the asynchronous disconnected mode. - * It can accept an SABME PDU from a remote LLC SSAP or, at the request - * of the service access point user, can initiate an SABME PDU - * transmission to a remote LLC DSAP, to establish a data link - * connection. It also responds to a DISC command PDU and to any - * command PDU with the P bit set to ``1''. - */ -int -llc_state_ADM(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, - int cmdrsp, int pollfinal) -{ - int action = 0; - - switch(frame_kind + cmdrsp) { - case NL_CONNECT_REQUEST: - llc_send(linkp, LLCFT_SABME, LLC_CMD, pollfinal); - LLC_SETFLAG(linkp, P, pollfinal); - LLC_SETFLAG(linkp, S, 0); - linkp->llcl_retry = 0; - LLC_NEWSTATE(linkp, SETUP); - break; - case LLCFT_SABME + LLC_CMD: - /* - * ISO 8802-2, table 7-1, ADM state says to set - * the P flag, yet this will cause an SABME [P] to be - * answered with an UA only, not an UA [F], all - * other `disconnected' states set the F flag, so ... - */ - LLC_SETFLAG(linkp, F, pollfinal); - LLC_NEWSTATE(linkp, CONN); - action = LLC_CONNECT_INDICATION; - break; - case LLCFT_DISC + LLC_CMD: - llc_send(linkp, LLCFT_DM, LLC_RSP, pollfinal); - break; - default: - if (cmdrsp == LLC_CMD && pollfinal == 1) - llc_send(linkp, LLCFT_DM, LLC_RSP, 1); - /* remain in ADM state */ - } - - return action; -} - -/* - * CONN --- The local connection component has received an SABME PDU from a - * remote LLC SSAP, and it is waiting for the local user to accept or - * refuse the connection. - */ -int -llc_state_CONN(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, - int cmdrsp, int pollfinal) -{ - int action = 0; - - switch(frame_kind + cmdrsp) { - case NL_CONNECT_RESPONSE: - llc_send(linkp, LLCFT_UA, LLC_RSP, LLC_GETFLAG(linkp, F)); - LLC_RESETCOUNTER(linkp); - LLC_SETFLAG(linkp, P, 0); - LLC_SETFLAG(linkp, REMOTE_BUSY, 0); - LLC_NEWSTATE(linkp, NORMAL); - break; - case NL_DISCONNECT_REQUEST: - llc_send(linkp, LLCFT_DM, LLC_RSP, LLC_GETFLAG(linkp, F)); - LLC_NEWSTATE(linkp, ADM); - break; - case LLCFT_SABME + LLC_CMD: - LLC_SETFLAG(linkp, F, pollfinal); - break; - case LLCFT_DM + LLC_RSP: - LLC_NEWSTATE(linkp, ADM); - action = LLC_DISCONNECT_INDICATION; - break; - /* all other frames effect nothing here */ - } - - return action; -} - -/* - * RESET_WAIT --- The local connection component is waiting for the local user - * to indicate a RESET_REQUEST or a DISCONNECT_REQUEST. - */ -int -llc_state_RESET_WAIT(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, - int cmdrsp, int pollfinal) -{ - int action = 0; - - switch(frame_kind + cmdrsp) { - case NL_RESET_REQUEST: - if (LLC_GETFLAG(linkp, S) == 0) { - llc_send(linkp, LLCFT_SABME, LLC_CMD, pollfinal); - LLC_SETFLAG(linkp, P, pollfinal); - LLC_START_ACK_TIMER(linkp); - linkp->llcl_retry = 0; - LLC_NEWSTATE(linkp, RESET); - } else { - llc_send(linkp, LLCFT_UA, LLC_RSP, - LLC_GETFLAG(linkp, F)); - LLC_RESETCOUNTER(linkp); - LLC_SETFLAG(linkp, P, 0); - LLC_SETFLAG(linkp, REMOTE_BUSY, 0); - LLC_NEWSTATE(linkp, NORMAL); - action = LLC_RESET_CONFIRM; - } - break; - case NL_DISCONNECT_REQUEST: - if (LLC_GETFLAG(linkp, S) == 0) { - llc_send(linkp, LLCFT_DISC, LLC_CMD, pollfinal); - LLC_SETFLAG(linkp, P, pollfinal); - LLC_START_ACK_TIMER(linkp); - linkp->llcl_retry = 0; - LLC_NEWSTATE(linkp, D_CONN); - } else { - llc_send(linkp, LLCFT_DM, LLC_RSP, - LLC_GETFLAG(linkp, F)); - LLC_NEWSTATE(linkp, ADM); - } - break; - case LLCFT_DM + LLC_RSP: - LLC_NEWSTATE(linkp, ADM); - action = LLC_DISCONNECT_INDICATION; - break; - case LLCFT_SABME + LLC_CMD: - LLC_SETFLAG(linkp, S, 1); - LLC_SETFLAG(linkp, F, pollfinal); - break; - case LLCFT_DISC + LLC_CMD: - llc_send(linkp, LLCFT_DM, LLC_RSP, pollfinal); - LLC_NEWSTATE(linkp, ADM); - action = LLC_DISCONNECT_INDICATION; - break; - } - - return action; -} - -/* - * RESET_CHECK --- The local connection component is waiting for the local user - * to accept or refuse a remote reset request. - */ -int -llc_state_RESET_CHECK(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, - int cmdrsp, int pollfinal) -{ - int action = 0; - - switch(frame_kind + cmdrsp) { - case NL_RESET_RESPONSE: - llc_send(linkp, LLCFT_UA, LLC_RSP, LLC_GETFLAG(linkp, F)); - LLC_RESETCOUNTER(linkp); - LLC_SETFLAG(linkp, P, 0); - LLC_SETFLAG(linkp, REMOTE_BUSY, 0); - LLC_NEWSTATE(linkp, NORMAL); - break; - case NL_DISCONNECT_REQUEST: - llc_send(linkp, LLCFT_DM, LLC_RSP, LLC_GETFLAG(linkp, F)); - LLC_NEWSTATE(linkp, ADM); - break; - case LLCFT_DM + LLC_RSP: - action = LLC_DISCONNECT_INDICATION; - break; - case LLCFT_SABME + LLC_CMD: - LLC_SETFLAG(linkp, F, pollfinal); - break; - case LLCFT_DISC + LLC_CMD: - llc_send(linkp, LLCFT_DM, LLC_RSP, pollfinal); - LLC_NEWSTATE(linkp, ADM); - action = LLC_DISCONNECT_INDICATION; - break; - } - - return action; -} - -/* - * SETUP --- The connection component has transmitted an SABME command PDU to a - * remote LLC DSAP and is waiting for a reply. - */ -int -llc_state_SETUP(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, - int cmdrsp, int pollfinal) -{ - int action = 0; - - switch(frame_kind + cmdrsp) { - case LLCFT_SABME + LLC_CMD: - LLC_RESETCOUNTER(linkp); - llc_send(linkp, LLCFT_UA, LLC_RSP, pollfinal); - LLC_SETFLAG(linkp, S, 1); - break; - case LLCFT_UA + LLC_RSP: - if (LLC_GETFLAG(linkp, P) == pollfinal) { - LLC_STOP_ACK_TIMER(linkp); - LLC_RESETCOUNTER(linkp); - LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); - LLC_SETFLAG(linkp, REMOTE_BUSY, 0); - LLC_NEWSTATE(linkp, NORMAL); - action = LLC_CONNECT_CONFIRM; - } - break; - case LLC_ACK_TIMER_EXPIRED: - if (LLC_GETFLAG(linkp, S) == 1) { - LLC_SETFLAG(linkp, P, 0); - LLC_SETFLAG(linkp, REMOTE_BUSY, 0), - LLC_NEWSTATE(linkp, NORMAL); - action = LLC_CONNECT_CONFIRM; - } else if (linkp->llcl_retry < llc_n2) { - llc_send(linkp, LLCFT_SABME, LLC_CMD, pollfinal); - LLC_SETFLAG(linkp, P, pollfinal); - LLC_START_ACK_TIMER(linkp); - linkp->llcl_retry++; - } else { - LLC_NEWSTATE(linkp, ADM); - action = LLC_DISCONNECT_INDICATION; - } - break; - case LLCFT_DISC + LLC_CMD: - llc_send(linkp, LLCFT_DM, LLC_RSP, pollfinal); - LLC_STOP_ACK_TIMER(linkp); - LLC_NEWSTATE(linkp, ADM); - action = LLC_DISCONNECT_INDICATION; - break; - case LLCFT_DM + LLC_RSP: - LLC_STOP_ACK_TIMER(linkp); - LLC_NEWSTATE(linkp, ADM); - action = LLC_DISCONNECT_INDICATION; - break; - } - - return action; -} - -/* - * RESET --- As a result of a service access point user request or the receipt - * of a FRMR response PDU, the local connection component has sent an - * SABME command PDU to the remote LLC DSAP to reset the data link - * connection and is waiting for a reply. - */ -int -llc_state_RESET(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, - int cmdrsp, int pollfinal) -{ - int action = 0; - - switch(frame_kind + cmdrsp) { - case LLCFT_SABME + LLC_CMD: - LLC_RESETCOUNTER(linkp); - LLC_SETFLAG(linkp, S, 1); - llc_send(linkp, LLCFT_UA, LLC_RSP, pollfinal); - break; - case LLCFT_UA + LLC_RSP: - if (LLC_GETFLAG(linkp, P) == pollfinal) { - LLC_STOP_ACK_TIMER(linkp); - LLC_RESETCOUNTER(linkp); - LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); - LLC_SETFLAG(linkp, REMOTE_BUSY, 0); - LLC_NEWSTATE(linkp, NORMAL); - action = LLC_RESET_CONFIRM; - } - break; - case LLC_ACK_TIMER_EXPIRED: - if (LLC_GETFLAG(linkp, S) == 1) { - LLC_SETFLAG(linkp, P, 0); - LLC_SETFLAG(linkp, REMOTE_BUSY, 0); - LLC_NEWSTATE(linkp, NORMAL); - action = LLC_RESET_CONFIRM; - } else if (linkp->llcl_retry < llc_n2) { - llc_send(linkp, LLCFT_SABME, LLC_CMD, pollfinal); - LLC_SETFLAG(linkp, P, pollfinal); - LLC_START_ACK_TIMER(linkp); - linkp->llcl_retry++; - } else { - LLC_NEWSTATE(linkp, ADM); - action = LLC_DISCONNECT_INDICATION; - } - break; - case LLCFT_DISC + LLC_CMD: - llc_send(linkp, LLCFT_DM, LLC_RSP, pollfinal); - LLC_STOP_ACK_TIMER(linkp); - LLC_NEWSTATE(linkp, ADM); - action = LLC_DISCONNECT_INDICATION; - break; - case LLCFT_DM + LLC_RSP: - LLC_STOP_ACK_TIMER(linkp); - LLC_NEWSTATE(linkp, ADM); - action = LLC_DISCONNECT_INDICATION; - break; - } - - return action; -} - -/* - * D_CONN --- At the request of the service access point user, the local LLC - * has sent a DISC command PDU to the remote LLC DSAP and is waiting - * for a reply. - */ -int -llc_state_D_CONN(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, - int cmdrsp, int pollfinal) -{ - int action = 0; - - switch(frame_kind + cmdrsp) { - case LLCFT_SABME + LLC_CMD: - llc_send(linkp, LLCFT_DM, LLC_RSP, pollfinal); - LLC_STOP_ACK_TIMER(linkp); - LLC_NEWSTATE(linkp, ADM); - break; - case LLCFT_UA + LLC_RSP: - if (LLC_GETFLAG(linkp, P) == pollfinal) { - LLC_STOP_ACK_TIMER(linkp); - LLC_NEWSTATE(linkp, ADM); - } - break; - case LLCFT_DISC + LLC_CMD: - llc_send(linkp, LLCFT_UA, LLC_RSP, pollfinal); - break; - case LLCFT_DM + LLC_RSP: - LLC_STOP_ACK_TIMER(linkp); - LLC_NEWSTATE(linkp, ADM); - break; - case LLC_ACK_TIMER_EXPIRED: - if (linkp->llcl_retry < llc_n2) { - llc_send(linkp, LLCFT_DISC, LLC_CMD, pollfinal); - LLC_SETFLAG(linkp, P, pollfinal); - LLC_START_ACK_TIMER(linkp); - linkp->llcl_retry++; - } else LLC_NEWSTATE(linkp, ADM); - break; - } - - return action; -} - -/* - * ERROR --- The local connection component has detected an error in a received - * PDU and has sent a FRMR response PDU. It is waiting for a reply from - * the remote connection component. - */ -int -llc_state_ERROR(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, - int cmdrsp, int pollfinal) -{ - int action = 0; - - switch(frame_kind + cmdrsp) { - case LLCFT_SABME + LLC_CMD: - LLC_STOP_ACK_TIMER(linkp); - LLC_NEWSTATE(linkp, RESET_CHECK); - action = LLC_RESET_INDICATION_REMOTE; - break; - case LLCFT_DISC + LLC_CMD: - llc_send(linkp, LLCFT_UA, LLC_RSP, pollfinal); - LLC_STOP_ACK_TIMER(linkp); - LLC_NEWSTATE(linkp, ADM); - action = LLC_DISCONNECT_INDICATION; - break; - case LLCFT_DM + LLC_RSP: - LLC_STOP_ACK_TIMER(linkp); - LLC_NEWSTATE(linkp, ADM); - action = LLC_DISCONNECT_INDICATION; - break; - case LLCFT_FRMR + LLC_RSP: - LLC_STOP_ACK_TIMER(linkp); - LLC_SETFLAG(linkp, S, 0); - LLC_NEWSTATE(linkp, RESET_WAIT); - action = LLC_FRMR_RECEIVED; - break; - case LLC_ACK_TIMER_EXPIRED: - if (linkp->llcl_retry < llc_n2) { - llc_send(linkp, LLCFT_FRMR, LLC_RSP, 0); - LLC_START_ACK_TIMER(linkp); - linkp->llcl_retry++; - } else { - LLC_SETFLAG(linkp, S, 0); - LLC_NEWSTATE(linkp, RESET_WAIT); - action = LLC_RESET_INDICATION_LOCAL; - } - break; - default: - if (cmdrsp == LLC_CMD){ - llc_send(linkp, LLCFT_FRMR, LLC_RSP, pollfinal); - LLC_START_ACK_TIMER(linkp); - } - break; - - } - - return action; -} - -/* - * NORMAL, BUSY, REJECT, AWAIT, AWAIT_BUSY, and AWAIT_REJECT all share - * a common core state handler. - */ -int -llc_state_NBRAcore(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, - int cmdrsp, int pollfinal) -{ - int action = 0; - - switch(frame_kind + cmdrsp) { - case NL_DISCONNECT_REQUEST: - llc_send(linkp, LLCFT_DISC, LLC_CMD, pollfinal); - LLC_SETFLAG(linkp, P, pollfinal); - LLC_STOP_ALL_TIMERS(linkp); - LLC_START_ACK_TIMER(linkp); - linkp->llcl_retry = 0; - LLC_NEWSTATE(linkp, D_CONN); - break; - case NL_RESET_REQUEST: - llc_send(linkp, LLCFT_SABME, LLC_CMD, pollfinal); - LLC_SETFLAG(linkp, P, pollfinal); - LLC_STOP_ALL_TIMERS(linkp); - LLC_START_ACK_TIMER(linkp); - linkp->llcl_retry = 0; - LLC_SETFLAG(linkp, S, 0); - LLC_NEWSTATE(linkp, RESET); - break; - case LLCFT_SABME + LLC_CMD: - LLC_SETFLAG(linkp, F, pollfinal); - LLC_STOP_ALL_TIMERS(linkp); - LLC_NEWSTATE(linkp, RESET_CHECK); - action = LLC_RESET_INDICATION_REMOTE; - break; - case LLCFT_DISC + LLC_CMD: - llc_send(linkp, LLCFT_UA, LLC_RSP, pollfinal); - LLC_STOP_ALL_TIMERS(linkp); - LLC_NEWSTATE(linkp, ADM); - action = LLC_DISCONNECT_INDICATION; - break; - case LLCFT_FRMR + LLC_RSP: - LLC_STOP_ALL_TIMERS(linkp); - LLC_SETFLAG(linkp, S, 0); - LLC_NEWSTATE(linkp, RESET_WAIT); - action = LLC_FRMR_RECEIVED; - break; - case LLCFT_DM + LLC_RSP: - LLC_STOP_ALL_TIMERS(linkp); - LLC_NEWSTATE(linkp, ADM); - action = LLC_DISCONNECT_INDICATION; - break; - case LLC_INVALID_NR + LLC_CMD: - case LLC_INVALID_NS + LLC_CMD: - LLC_SETFRMR(linkp, frame, cmdrsp, - (frame_kind == LLC_INVALID_NR ? LLC_FRMR_Z : - (LLC_FRMR_V | LLC_FRMR_W))); - llc_send(linkp, LLCFT_FRMR, LLC_RSP, pollfinal); - LLC_STOP_ALL_TIMERS(linkp); - LLC_START_ACK_TIMER(linkp); - linkp->llcl_retry = 0; - LLC_NEWSTATE(linkp, ERROR); - action = LLC_FRMR_SENT; - break; - case LLC_INVALID_NR + LLC_RSP: - case LLC_INVALID_NS + LLC_RSP: - case LLCFT_UA + LLC_RSP: - case LLC_BAD_PDU: { - char frmrcause = 0; - - switch (frame_kind) { - case LLC_INVALID_NR: frmrcause = LLC_FRMR_Z; break; - case LLC_INVALID_NS: frmrcause = LLC_FRMR_V | LLC_FRMR_W; break; - default: frmrcause = LLC_FRMR_W; - } - LLC_SETFRMR(linkp, frame, cmdrsp, frmrcause); - llc_send(linkp, LLCFT_FRMR, LLC_RSP, 0); - LLC_STOP_ALL_TIMERS(linkp); - LLC_START_ACK_TIMER(linkp); - linkp->llcl_retry = 0; - LLC_NEWSTATE(linkp, ERROR); - action = LLC_FRMR_SENT; - break; - } - default: - if (cmdrsp == LLC_RSP && pollfinal == 1 && - LLC_GETFLAG(linkp, P) == 0) { - LLC_SETFRMR(linkp, frame, cmdrsp, LLC_FRMR_W); - LLC_STOP_ALL_TIMERS(linkp); - LLC_START_ACK_TIMER(linkp); - linkp->llcl_retry = 0; - LLC_NEWSTATE(linkp, ERROR); - action = LLC_FRMR_SENT; - } - break; - case LLC_P_TIMER_EXPIRED: - case LLC_ACK_TIMER_EXPIRED: - case LLC_REJ_TIMER_EXPIRED: - case LLC_BUSY_TIMER_EXPIRED: - if (linkp->llcl_retry >= llc_n2) { - LLC_STOP_ALL_TIMERS(linkp); - LLC_SETFLAG(linkp, S, 0); - LLC_NEWSTATE(linkp, RESET_WAIT); - action = LLC_RESET_INDICATION_LOCAL; - } - break; - } - - return action; -} - -/* - * NORMAL --- A data link connection exists between the local LLC service access - * point and the remote LLC service access point. Sending and - * reception of information and supervisory PDUs can be performed. - */ -int -llc_state_NORMAL(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, - int cmdrsp, int pollfinal) -{ - int action = LLC_PASSITON; - - switch(frame_kind + cmdrsp) { - case NL_DATA_REQUEST: - if (LLC_GETFLAG(linkp, REMOTE_BUSY) == 0) { -#ifdef not_now - if (LLC_GETFLAG(linkp, P) == 0) { - /* multiple possibilities */ - llc_send(linkp, LLCFT_INFO, LLC_CMD, 1); - LLC_START_P_TIMER(linkp); - if (LLC_TIMERXPIRED(linkp, ACK) != LLC_TIMER_RUNNING) - LLC_START_ACK_TIMER(linkp); - } else { -#endif - /* multiple possibilities */ - llc_send(linkp, LLCFT_INFO, LLC_CMD, 0); - if (LLC_TIMERXPIRED(linkp, ACK) != LLC_TIMER_RUNNING) - LLC_START_ACK_TIMER(linkp); -#ifdef not_now - } -#endif - action = 0; - } - break; - case LLC_LOCAL_BUSY_DETECTED: - if (LLC_GETFLAG(linkp, P) == 0) { - /* multiple possibilities --- action-wise */ - /* multiple possibilities --- CMD/RSP-wise */ - llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); - LLC_START_P_TIMER(linkp); - LLC_SETFLAG(linkp, DATA, 0); - LLC_NEWSTATE(linkp, BUSY); - action = 0; - } else { - /* multiple possibilities --- CMD/RSP-wise */ - llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); - LLC_SETFLAG(linkp, DATA, 0); - LLC_NEWSTATE(linkp, BUSY); - action = 0; - } - break; - case LLC_INVALID_NS + LLC_CMD: - case LLC_INVALID_NS + LLC_RSP: { - register int p = LLC_GETFLAG(linkp, P); - register int nr = LLCGBITS(frame->llc_control_ext, s_nr); - - if (cmdrsp == LLC_CMD && pollfinal == 1) { - llc_send(linkp, LLCFT_REJ, LLC_RSP, 1); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_START_REJ_TIMER(linkp); - LLC_NEWSTATE(linkp, REJECT); - action = 0; - } else if (pollfinal == 0 && p == 1) { - llc_send(linkp, LLCFT_REJ, LLC_CMD, 0); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_START_REJ_TIMER(linkp); - LLC_NEWSTATE(linkp, REJECT); - action = 0; - } else if ((pollfinal == 0 && p == 0) || - (pollfinal == 1 && p == 1 && cmdrsp == LLC_RSP)) { - llc_send(linkp, LLCFT_REJ, LLC_CMD, 1); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_START_P_TIMER(linkp); - LLC_START_REJ_TIMER(linkp); - if (cmdrsp == LLC_RSP && pollfinal == 1) { - LLC_CLEAR_REMOTE_BUSY(linkp, action); - } else action = 0; - LLC_NEWSTATE(linkp, REJECT); - } - break; - } - case LLCFT_INFO + LLC_CMD: - case LLCFT_INFO + LLC_RSP: { - register int p = LLC_GETFLAG(linkp, P); - register int nr = LLCGBITS(frame->llc_control_ext, s_nr); - - if (cmdrsp == LLC_CMD && pollfinal == 1) { - LLC_INC(linkp->llcl_vr); - LLC_SENDACKNOWLEDGE(linkp, LLC_RSP, 1); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - action = LLC_DATA_INDICATION; - } else if (pollfinal == 0 && p == 1) { - LLC_INC(linkp->llcl_vr); - LLC_SENDACKNOWLEDGE(linkp, LLC_CMD, 0); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - action = LLC_DATA_INDICATION; - } else if ((pollfinal == 0 && p == 0 && cmdrsp == LLC_CMD) || - (pollfinal == p && cmdrsp == LLC_RSP)) { - LLC_INC(linkp->llcl_vr); - LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); - LLC_SENDACKNOWLEDGE(linkp, LLC_CMD, 0); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - if (cmdrsp == LLC_RSP && pollfinal == 1) - LLC_CLEAR_REMOTE_BUSY(linkp, action); - action = LLC_DATA_INDICATION; - } - break; - } - case LLCFT_RR + LLC_CMD: - case LLCFT_RR + LLC_RSP: { - register int p = LLC_GETFLAG(linkp, P); - register int nr = LLCGBITS(frame->llc_control_ext, s_nr); - - if (cmdrsp == LLC_CMD && pollfinal == 1) { - LLC_SENDACKNOWLEDGE(linkp, LLC_RSP, 1); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_CLEAR_REMOTE_BUSY(linkp, action); - } else if ((pollfinal == 0) || - (cmdrsp == LLC_RSP && pollfinal == 1 && p == 1)) { - LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_CLEAR_REMOTE_BUSY(linkp, action); - } - break; - } - case LLCFT_RNR + LLC_CMD: - case LLCFT_RNR + LLC_RSP: { - register int p = LLC_GETFLAG(linkp, P); - register int nr = LLCGBITS(frame->llc_control_ext, s_nr); - - if (cmdrsp == LLC_CMD && pollfinal == 1) { - llc_send(linkp, LLCFT_RR, LLC_RSP, 1); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_SET_REMOTE_BUSY(linkp, action); - } else if ((pollfinal == 0) || - (cmdrsp == LLC_RSP && pollfinal == 1 && p == 1)) { - LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_SET_REMOTE_BUSY(linkp, action); - } - break; - } - case LLCFT_REJ + LLC_CMD: - case LLCFT_REJ + LLC_RSP: { - register int p = LLC_GETFLAG(linkp, P); - register int nr = LLCGBITS(frame->llc_control_ext, s_nr); - - if (cmdrsp == LLC_CMD && pollfinal == 1) { - linkp->llcl_vs = nr; - LLC_UPDATE_NR_RECEIVED(linkp, nr); - llc_resend(linkp, LLC_RSP, 1); - LLC_CLEAR_REMOTE_BUSY(linkp, action); - } else if (pollfinal == 0 && p == 1) { - linkp->llcl_vs = nr; - LLC_UPDATE_NR_RECEIVED(linkp, nr); - llc_resend(linkp, LLC_CMD, 0); - LLC_CLEAR_REMOTE_BUSY(linkp, action); - } else if ((pollfinal == 0 && p == 0 && cmdrsp == LLC_CMD) || - (pollfinal == p && cmdrsp == LLC_RSP)) { - linkp->llcl_vs = nr; - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_START_P_TIMER(linkp); - llc_resend(linkp, LLC_CMD, 1); - LLC_CLEAR_REMOTE_BUSY(linkp, action); - } - break; - } - case NL_INITIATE_PF_CYCLE: - if (LLC_GETFLAG(linkp, P) == 0) { - llc_send(linkp, LLCFT_RR, LLC_CMD, 1); - LLC_START_P_TIMER(linkp); - action = 0; - } - break; - case LLC_P_TIMER_EXPIRED: - if (linkp->llcl_retry < llc_n2) { - llc_send(linkp, LLCFT_RR, LLC_CMD, 1); - LLC_START_P_TIMER(linkp); - linkp->llcl_retry++; - LLC_NEWSTATE(linkp, AWAIT); - action = 0; - } - break; - case LLC_ACK_TIMER_EXPIRED: - case LLC_BUSY_TIMER_EXPIRED: - if ((LLC_GETFLAG(linkp, P) == 0) - && (linkp->llcl_retry < llc_n2)) { - llc_send(linkp, LLCFT_RR, LLC_CMD, 1); - LLC_START_P_TIMER(linkp); - linkp->llcl_retry++; - LLC_NEWSTATE(linkp, AWAIT); - action = 0; - } - break; - } - if (action == LLC_PASSITON) - action = llc_state_NBRAcore(linkp, frame, frame_kind, - cmdrsp, pollfinal); - - return action; -} - -/* - * BUSY --- A data link connection exists between the local LLC service access - * point and the remote LLC service access point. I PDUs may be sent. - * Local conditions make it likely that the information feld of - * received I PDUs will be ignored. Supervisory PDUs may be both sent - * and received. - */ -int -llc_state_BUSY(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, - int cmdrsp, int pollfinal) -{ - int action = LLC_PASSITON; - - switch(frame_kind + cmdrsp) { - case NL_DATA_REQUEST: - if (LLC_GETFLAG(linkp, REMOTE_BUSY) == 0) - if (LLC_GETFLAG(linkp, P) == 0) { - llc_send(linkp, LLCFT_INFO, LLC_CMD, 1); - LLC_START_P_TIMER(linkp); - if (LLC_TIMERXPIRED(linkp, ACK) != LLC_TIMER_RUNNING) - LLC_START_ACK_TIMER(linkp); - action = 0; - } else { - llc_send(linkp, LLCFT_INFO, LLC_CMD, 0); - if (LLC_TIMERXPIRED(linkp, ACK) != LLC_TIMER_RUNNING) - LLC_START_ACK_TIMER(linkp); - action = 0; - } - break; - case LLC_LOCAL_BUSY_CLEARED: { - register int p = LLC_GETFLAG(linkp, P); - register int df = LLC_GETFLAG(linkp, DATA); - - switch (df) { - case 1: - if (p == 0) { - /* multiple possibilities */ - llc_send(linkp, LLCFT_REJ, LLC_CMD, 1); - LLC_START_REJ_TIMER(linkp); - LLC_START_P_TIMER(linkp); - LLC_NEWSTATE(linkp, REJECT); - action = 0; - } else { - llc_send(linkp, LLCFT_REJ, LLC_CMD, 0); - LLC_START_REJ_TIMER(linkp); - LLC_NEWSTATE(linkp, REJECT); - action = 0; - } - break; - case 0: - if (p == 0) { - /* multiple possibilities */ - llc_send(linkp, LLCFT_RR, LLC_CMD, 1); - LLC_START_P_TIMER(linkp); - LLC_NEWSTATE(linkp, NORMAL); - action = 0; - } else { - llc_send(linkp, LLCFT_RR, LLC_CMD, 0); - LLC_NEWSTATE(linkp, NORMAL); - action = 0; - } - break; - case 2: - if (p == 0) { - /* multiple possibilities */ - llc_send(linkp, LLCFT_RR, LLC_CMD, 1); - LLC_START_P_TIMER(linkp); - LLC_NEWSTATE(linkp, REJECT); - action = 0; - } else { - llc_send(linkp, LLCFT_RR, LLC_CMD, 0); - LLC_NEWSTATE(linkp, REJECT); - action =0; - } - break; - } - break; - } - case LLC_INVALID_NS + LLC_CMD: - case LLC_INVALID_NS + LLC_RSP: { - register int p = LLC_GETFLAG(linkp, P); - register int nr = LLCGBITS(frame->llc_control_ext, s_nr); - - if (cmdrsp == LLC_CMD && pollfinal == 1) { - llc_send(linkp, LLCFT_RNR, LLC_RSP, 1); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - if (LLC_GETFLAG(linkp, DATA) == 0) - LLC_SETFLAG(linkp, DATA, 1); - action = 0; - } else if ((cmdrsp == LLC_CMD && pollfinal == 0 && p == 0) || - (cmdrsp == LLC_RSP && pollfinal == p)) { - llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); - LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - if (LLC_GETFLAG(linkp, DATA) == 0) - LLC_SETFLAG(linkp, DATA, 1); - if (cmdrsp == LLC_RSP && pollfinal == 1) { - LLC_CLEAR_REMOTE_BUSY(linkp, action); - } else action = 0; - } else if (pollfinal == 0 && p == 1) { - llc_send(linkp, LLCFT_RNR, LLC_RSP, 1); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - if (LLC_GETFLAG(linkp, DATA) == 0) - LLC_SETFLAG(linkp, DATA, 1); - action = 0; - } - break; - } - case LLCFT_INFO + LLC_CMD: - case LLCFT_INFO + LLC_RSP: { - register int p = LLC_GETFLAG(linkp, P); - register int nr = LLCGBITS(frame->llc_control_ext, s_nr); - - if (cmdrsp == LLC_CMD && pollfinal == 1) { - LLC_INC(linkp->llcl_vr); - llc_send(linkp, LLCFT_RNR, LLC_RSP, 1); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - if (LLC_GETFLAG(linkp, DATA) == 2) - LLC_STOP_REJ_TIMER(linkp); - LLC_SETFLAG(linkp, DATA, 0); - action = LLC_DATA_INDICATION; - } else if ((cmdrsp == LLC_CMD && pollfinal == 0 && p == 0) || - (cmdrsp == LLC_RSP && pollfinal == p)) { - LLC_INC(linkp->llcl_vr); - llc_send(linkp, LLCFT_RNR, LLC_CMD, 1); - LLC_START_P_TIMER(linkp); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - if (LLC_GETFLAG(linkp, DATA) == 2) - LLC_STOP_REJ_TIMER(linkp); - if (cmdrsp == LLC_RSP && pollfinal == 1) - LLC_CLEAR_REMOTE_BUSY(linkp, action); - action = LLC_DATA_INDICATION; - } else if (pollfinal == 0 && p == 1) { - LLC_INC(linkp->llcl_vr); - llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - if (LLC_GETFLAG(linkp, DATA) == 2) - LLC_STOP_REJ_TIMER(linkp); - LLC_SETFLAG(linkp, DATA, 0); - action = LLC_DATA_INDICATION; - } - break; - } - case LLCFT_RR + LLC_CMD: - case LLCFT_RR + LLC_RSP: - case LLCFT_RNR + LLC_CMD: - case LLCFT_RNR + LLC_RSP: { - register int p = LLC_GETFLAG(linkp, P); - register int nr = LLCGBITS(frame->llc_control_ext, s_nr); - - if (cmdrsp == LLC_CMD && pollfinal == 1) { - llc_send(linkp, LLCFT_RNR, LLC_RSP, 1); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - if (frame_kind == LLCFT_RR) { - LLC_CLEAR_REMOTE_BUSY(linkp, action); - } else { - LLC_SET_REMOTE_BUSY(linkp, action); - } - } else if (pollfinal = 0 || - (cmdrsp == LLC_RSP && pollfinal == 1)) { - LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - if (frame_kind == LLCFT_RR) { - LLC_CLEAR_REMOTE_BUSY(linkp, action); - } else { - LLC_SET_REMOTE_BUSY(linkp, action); - } - } - break; - } - case LLCFT_REJ + LLC_CMD: - case LLCFT_REJ + LLC_RSP: { - register int p = LLC_GETFLAG(linkp, P); - register int nr = LLCGBITS(frame->llc_control_ext, s_nr); - - if (cmdrsp == LLC_CMD && pollfinal == 1) { - linkp->llcl_vs = nr; - LLC_UPDATE_NR_RECEIVED(linkp, nr); - llc_send(linkp, LLCFT_RNR, LLC_RSP, 1); - llc_resend(linkp, LLC_CMD, 0); - LLC_CLEAR_REMOTE_BUSY(linkp, action); - } else if ((cmdrsp == LLC_CMD && pollfinal == 0 && p == 0) || - (cmdrsp == LLC_RSP && pollfinal == p)) { - linkp->llcl_vs = nr; - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); - llc_resend(linkp, LLC_CMD, 0); - LLC_CLEAR_REMOTE_BUSY(linkp, action); - } else if (pollfinal == 0 && p == 1) { - linkp->llcl_vs = nr; - LLC_UPDATE_NR_RECEIVED(linkp, nr); - llc_resend(linkp, LLC_CMD, 0); - LLC_CLEAR_REMOTE_BUSY(linkp, action); - } - break; - } - case NL_INITIATE_PF_CYCLE: - if (LLC_GETFLAG(linkp, P) == 0) { - llc_send(linkp, LLCFT_RNR, LLC_CMD, 1); - LLC_START_P_TIMER(linkp); - action = 0; - } - break; - case LLC_P_TIMER_EXPIRED: - /* multiple possibilities */ - if (linkp->llcl_retry < llc_n2) { - llc_send(linkp, LLCFT_RNR, LLC_CMD, 1); - LLC_START_P_TIMER(linkp); - linkp->llcl_retry++; - LLC_NEWSTATE(linkp, AWAIT_BUSY); - action = 0; - } - break; - case LLC_ACK_TIMER_EXPIRED: - case LLC_BUSY_TIMER_EXPIRED: - if (LLC_GETFLAG(linkp, P) == 0 && linkp->llcl_retry < llc_n2) { - llc_send(linkp, LLCFT_RNR, LLC_CMD, 1); - LLC_START_P_TIMER(linkp); - linkp->llcl_retry++; - LLC_NEWSTATE(linkp, AWAIT_BUSY); - action = 0; - } - break; - case LLC_REJ_TIMER_EXPIRED: - if (linkp->llcl_retry < llc_n2) - if (LLC_GETFLAG(linkp, P) == 0) { - /* multiple possibilities */ - llc_send(linkp, LLCFT_RNR, LLC_CMD, 1); - LLC_START_P_TIMER(linkp); - linkp->llcl_retry++; - LLC_SETFLAG(linkp, DATA, 1); - LLC_NEWSTATE(linkp, AWAIT_BUSY); - action = 0; - } else{ - LLC_SETFLAG(linkp, DATA, 1); - LLC_NEWSTATE(linkp, BUSY); - action = 0; - } - - break; - } - if (action == LLC_PASSITON) - action = llc_state_NBRAcore(linkp, frame, frame_kind, - cmdrsp, pollfinal); - - return action; -} - -/* - * REJECT --- A data link connection exists between the local LLC service - * access point and the remote LLC service access point. The local - * connection component has requested that the remote connection - * component resend a specific I PDU that the local connection - * componnent has detected as being out of sequence. Both I PDUs and - * supervisory PDUs may be sent and received. - */ -int -llc_state_REJECT(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, - int cmdrsp, int pollfinal) -{ - int action = LLC_PASSITON; - - switch(frame_kind + cmdrsp) { - case NL_DATA_REQUEST: - if (LLC_GETFLAG(linkp, P) == 0) { - llc_send(linkp, LLCFT_INFO, LLC_CMD, 1); - LLC_START_P_TIMER(linkp); - if (LLC_TIMERXPIRED(linkp, ACK) != LLC_TIMER_RUNNING) - LLC_START_ACK_TIMER(linkp); - LLC_NEWSTATE(linkp, REJECT); - action = 0; - } else { - llc_send(linkp, LLCFT_INFO, LLC_CMD, 0); - if (LLC_TIMERXPIRED(linkp, ACK) != LLC_TIMER_RUNNING) - LLC_START_ACK_TIMER(linkp); - LLC_NEWSTATE(linkp, REJECT); - action = 0; - } - break; - case NL_LOCAL_BUSY_DETECTED: - if (LLC_GETFLAG(linkp, P) == 0) { - llc_send(linkp, LLCFT_RNR, LLC_CMD, 1); - LLC_START_P_TIMER(linkp); - LLC_SETFLAG(linkp, DATA, 2); - LLC_NEWSTATE(linkp, BUSY); - action = 0; - } else { - llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); - LLC_SETFLAG(linkp, DATA, 2); - LLC_NEWSTATE(linkp, BUSY); - action = 0; - } - break; - case LLC_INVALID_NS + LLC_CMD: - case LLC_INVALID_NS + LLC_RSP: { - register int p = LLC_GETFLAG(linkp, P); - register int nr = LLCGBITS(frame->llc_control_ext, s_nr); - - if (cmdrsp == LLC_CMD && pollfinal == 1) { - llc_send(linkp, LLCFT_RR, LLC_RSP, 1); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - action = 0; - } else if (pollfinal == 0 || - (cmdrsp == LLC_RSP && pollfinal == 1 && p == 1)) { - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); - if (cmdrsp == LLC_RSP && pollfinal == 1) { - LLC_CLEAR_REMOTE_BUSY(linkp, action); - } else action = 0; - } - break; - } - case LLCFT_INFO + LLC_CMD: - case LLCFT_INFO + LLC_RSP: { - register int p = LLC_GETFLAG(linkp, P); - register int nr = LLCGBITS(frame->llc_control_ext, s_nr); - - if (cmdrsp == LLC_CMD && pollfinal == 1) { - LLC_INC(linkp->llcl_vr); - LLC_SENDACKNOWLEDGE(linkp, LLC_RSP, 1); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_STOP_REJ_TIMER(linkp); - LLC_NEWSTATE(linkp, NORMAL); - action = LLC_DATA_INDICATION; - } else if ((cmdrsp = LLC_RSP && pollfinal == p) || - (cmdrsp == LLC_CMD && pollfinal == 0 && p == 0)) { - LLC_INC(linkp->llcl_vr); - LLC_SENDACKNOWLEDGE(linkp, LLC_CMD, 1); - LLC_START_P_TIMER(linkp); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - if (cmdrsp == LLC_RSP && pollfinal == 1) - LLC_CLEAR_REMOTE_BUSY(linkp, action); - LLC_STOP_REJ_TIMER(linkp); - LLC_NEWSTATE(linkp, NORMAL); - action = LLC_DATA_INDICATION; - } else if (pollfinal == 0 && p == 1) { - LLC_INC(linkp->llcl_vr); - LLC_SENDACKNOWLEDGE(linkp, LLC_CMD, 0); - LLC_STOP_REJ_TIMER(linkp); - LLC_NEWSTATE(linkp, NORMAL); - action = LLC_DATA_INDICATION; - } - break; - } - case LLCFT_RR + LLC_CMD: - case LLCFT_RR + LLC_RSP: { - register int p = LLC_GETFLAG(linkp, P); - register int nr = LLCGBITS(frame->llc_control_ext, s_nr); - - if (cmdrsp == LLC_CMD && pollfinal == 1) { - LLC_SENDACKNOWLEDGE(linkp, LLC_RSP, 1); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_CLEAR_REMOTE_BUSY(linkp, action); - } else if (pollfinal == 0 || - (cmdrsp == LLC_RSP && pollfinal == 1 && p == 1)) { - LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_CLEAR_REMOTE_BUSY(linkp, action); - } - break; - } - case LLCFT_RNR + LLC_CMD: - case LLCFT_RNR + LLC_RSP: { - register int p = LLC_GETFLAG(linkp, P); - register int nr = LLCGBITS(frame->llc_control_ext, s_nr); - - if (cmdrsp == LLC_CMD && pollfinal == 1) { - llc_send(linkp, LLCFT_RR, LLC_RSP, 1); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_SET_REMOTE_BUSY(linkp, action); - } else if (pollfinal == 0 || - (cmdrsp == LLC_RSP && pollfinal == 1 && p == 1)) { - LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - action = 0; - } - break; - } - case LLCFT_REJ + LLC_CMD: - case LLCFT_REJ + LLC_RSP: { - register int p = LLC_GETFLAG(linkp, P); - register int nr = LLCGBITS(frame->llc_control_ext, s_nr); - - if (cmdrsp == LLC_CMD && pollfinal == 1) { - linkp->llcl_vs = nr; - LLC_UPDATE_NR_RECEIVED(linkp, nr); - llc_resend(linkp, LLC_RSP, 1); - LLC_CLEAR_REMOTE_BUSY(linkp, action); - } else if ((cmdrsp == LLC_CMD && pollfinal == 0 && p == 0) || - (cmdrsp == LLC_RSP && pollfinal == p)) { - linkp->llcl_vs = nr; - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_UPDATE_P_FLAG(linkp, cmdrsp, pollfinal); - llc_resend(linkp, LLC_CMD, 0); - LLC_CLEAR_REMOTE_BUSY(linkp, action); - } else if (pollfinal == 0 && p == 1) { - linkp->llcl_vs = nr; - LLC_UPDATE_NR_RECEIVED(linkp, nr); - llc_resend(linkp, LLC_CMD, 0); - LLC_CLEAR_REMOTE_BUSY(linkp, action); - } - break; - } - case NL_INITIATE_PF_CYCLE: - if (LLC_GETFLAG(linkp, P) == 0) { - llc_send(linkp, LLCFT_RR, LLC_CMD, 1); - LLC_START_P_TIMER(linkp); - action = 0; - } - break; - case LLC_REJ_TIMER_EXPIRED: - if (LLC_GETFLAG(linkp, P) == 0 && linkp->llcl_retry < llc_n2) { - llc_send(linkp, LLCFT_REJ, LLC_CMD, 1); - LLC_START_P_TIMER(linkp); - LLC_START_REJ_TIMER(linkp); - linkp->llcl_retry++; - action = 0; - } - case LLC_P_TIMER_EXPIRED: - if (linkp->llcl_retry < llc_n2) { - llc_send(linkp, LLCFT_RR, LLC_CMD, 1); - LLC_START_P_TIMER(linkp); - LLC_START_REJ_TIMER(linkp); - linkp->llcl_retry++; - LLC_NEWSTATE(linkp, AWAIT_REJECT); - action = 0; - } - break; - case LLC_ACK_TIMER_EXPIRED: - case LLC_BUSY_TIMER_EXPIRED: - if (LLC_GETFLAG(linkp, P) == 0 && linkp->llcl_retry < llc_n2) { - llc_send(linkp, LLCFT_RR, LLC_CMD, 1); - LLC_START_P_TIMER(linkp); - LLC_START_REJ_TIMER(linkp); - linkp->llcl_retry++; - /* - * I cannot locate the description of RESET_V(S) - * in ISO 8802-2, table 7-1, state REJECT, last event, - * and assume they meant to set V(S) to 0 ... - */ - linkp->llcl_vs = 0; /* XXX */ - LLC_NEWSTATE(linkp, AWAIT_REJECT); - action = 0; - } - - break; - } - if (action == LLC_PASSITON) - action = llc_state_NBRAcore(linkp, frame, frame_kind, - cmdrsp, pollfinal); - - return action; -} - -/* - * AWAIT --- A data link connection exists between the local LLC service access - * point and the remote LLC service access point. The local LLC is - * performing a timer recovery operation and has sent a command PDU - * with the P bit set to ``1'', and is awaiting an acknowledgement - * from the remote LLC. I PDUs may be received but not sent. - * Supervisory PDUs may be both sent and received. - */ -int -llc_state_AWAIT(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, - int cmdrsp, int pollfinal) -{ - int action = LLC_PASSITON; - - switch(frame_kind + cmdrsp) { - case LLC_LOCAL_BUSY_DETECTED: - llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); - LLC_SETFLAG(linkp, DATA, 0); - LLC_NEWSTATE(linkp, AWAIT_BUSY); - action = 0; - break; - case LLC_INVALID_NS + LLC_CMD: - case LLC_INVALID_NS + LLC_RSP: { - register int p = LLC_GETFLAG(linkp, P); - register int nr = LLCGBITS(frame->llc_control_ext, s_nr); - - if (cmdrsp == LLC_CMD && pollfinal == 1) { - llc_send(linkp, LLCFT_REJ, LLC_RSP, 1); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_START_REJ_TIMER(linkp); - LLC_NEWSTATE(linkp, AWAIT_REJECT); - action = 0; - } else if (cmdrsp == LLC_RSP && pollfinal == 1) { - llc_send(linkp, LLCFT_REJ, LLC_CMD, 0); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - linkp->llcl_vs = nr; - LLC_STOP_P_TIMER(linkp); - llc_resend(linkp, LLC_CMD, 0); - LLC_START_REJ_TIMER(linkp); - LLC_CLEAR_REMOTE_BUSY(linkp, action); - LLC_NEWSTATE(linkp, REJECT); - } else if (pollfinal == 0) { - llc_send(linkp, LLCFT_REJ, LLC_CMD, 0); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_START_REJ_TIMER(linkp); - LLC_NEWSTATE(linkp, AWAIT_REJECT); - action = 0; - } - break; - } - case LLCFT_INFO + LLC_RSP: - case LLCFT_INFO + LLC_CMD: { - register int p = LLC_GETFLAG(linkp, P); - register int nr = LLCGBITS(frame->llc_control_ext, s_nr); - - LLC_INC(linkp->llcl_vr); - if (cmdrsp == LLC_CMD && pollfinal == 1) { - llc_send(linkp, LLCFT_RR, LLC_RSP, 1); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - action = LLC_DATA_INDICATION; - } else if (cmdrsp == LLC_RSP && pollfinal == 1) { - LLC_UPDATE_NR_RECEIVED(linkp, nr); - linkp->llcl_vs = nr; - llc_resend(linkp, LLC_CMD, 1); - LLC_START_P_TIMER(linkp); - LLC_CLEAR_REMOTE_BUSY(linkp, action); - LLC_NEWSTATE(linkp, NORMAL); - action = LLC_DATA_INDICATION; - } else if (pollfinal == 0) { - llc_send(linkp, LLCFT_RR, LLC_CMD, 0); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - action = LLC_DATA_INDICATION; - } - break; - } - case LLCFT_RR + LLC_CMD: - case LLCFT_RR + LLC_RSP: - case LLCFT_REJ + LLC_CMD: - case LLCFT_REJ + LLC_RSP: { - register int p = LLC_GETFLAG(linkp, P); - register int nr = LLCGBITS(frame->llc_control_ext, s_nr); - - if (cmdrsp == LLC_CMD && pollfinal == 1) { - llc_send(linkp, LLCFT_RR, LLC_RSP, 1); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_CLEAR_REMOTE_BUSY(linkp, action); - } else if (cmdrsp == LLC_RSP && pollfinal == 1) { - LLC_UPDATE_NR_RECEIVED(linkp, nr); - linkp->llcl_vs = nr; - LLC_STOP_P_TIMER(linkp); - llc_resend(linkp, LLC_CMD, 0); - LLC_CLEAR_REMOTE_BUSY(linkp, action); - LLC_NEWSTATE(linkp, NORMAL); - } else if (pollfinal == 0) { - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_CLEAR_REMOTE_BUSY(linkp, action); - } - break; - } - case LLCFT_RNR + LLC_CMD: - case LLCFT_RNR + LLC_RSP: { - register int p = LLC_GETFLAG(linkp, P); - register int nr = LLCGBITS(frame->llc_control_ext, s_nr); - - if (pollfinal == 1 && cmdrsp == LLC_CMD) { - llc_send(linkp, LLCFT_RR, LLC_RSP, 1); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_SET_REMOTE_BUSY(linkp, action); - } else if (pollfinal == 1 && cmdrsp == LLC_RSP) { - LLC_UPDATE_NR_RECEIVED(linkp, nr); - linkp->llcl_vs = nr; - LLC_STOP_P_TIMER(linkp); - LLC_SET_REMOTE_BUSY(linkp, action); - LLC_NEWSTATE(linkp, NORMAL); - } else if (pollfinal == 0) { - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_SET_REMOTE_BUSY(linkp, action); - } - break; - } - case LLC_P_TIMER_EXPIRED: - if (linkp->llcl_retry < llc_n2) { - llc_send(linkp, LLCFT_RR, LLC_CMD, 1); - LLC_START_P_TIMER(linkp); - linkp->llcl_retry++; - action = 0; - } - break; - } - if (action == LLC_PASSITON) - action = llc_state_NBRAcore(linkp, frame, frame_kind, - cmdrsp, pollfinal); - - return action; -} - -/* - * AWAIT_BUSY --- A data link connection exists between the local LLC service - * access point and the remote LLC service access point. The - * local LLC is performing a timer recovery operation and has - * sent a command PDU with the P bit set to ``1'', and is - * awaiting an acknowledgement from the remote LLC. I PDUs may - * not be sent. Local conditions make it likely that the - * information feld of receoved I PDUs will be ignored. - * Supervisory PDUs may be both sent and received. - */ -int -llc_state_AWAIT_BUSY(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, - int cmdrsp, int pollfinal) -{ - int action = LLC_PASSITON; - - switch(frame_kind + cmdrsp) { - case LLC_LOCAL_BUSY_CLEARED: - switch (LLC_GETFLAG(linkp, DATA)) { - case 1: - llc_send(linkp, LLCFT_REJ, LLC_CMD, 0); - LLC_START_REJ_TIMER(linkp); - LLC_NEWSTATE(linkp, AWAIT_REJECT); - action = 0; - break; - case 0: - llc_send(linkp, LLCFT_RR, LLC_CMD, 0); - LLC_NEWSTATE(linkp, AWAIT); - action = 0; - break; - case 2: - llc_send(linkp, LLCFT_RR, LLC_CMD, 0); - LLC_NEWSTATE(linkp, AWAIT_REJECT); - action = 0; - break; - } - break; - case LLC_INVALID_NS + LLC_CMD: - case LLC_INVALID_NS + LLC_RSP: { - register int p = LLC_GETFLAG(linkp, P); - register int nr = LLCGBITS(frame->llc_control_ext, s_nr); - - if (cmdrsp == LLC_CMD && pollfinal == 1) { - llc_send(linkp, LLCFT_RNR, LLC_RSP, 1); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_SETFLAG(linkp, DATA, 1); - action = 0; - } else if (cmdrsp == LLC_RSP && pollfinal == 1) { - /* optionally */ - llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - linkp->llcl_vs = nr; - LLC_STOP_P_TIMER(linkp); - LLC_SETFLAG(linkp, DATA, 1); - LLC_CLEAR_REMOTE_BUSY(linkp, action); - llc_resend(linkp, LLC_CMD, 0); - LLC_NEWSTATE(linkp, BUSY); - } else if (pollfinal == 0) { - /* optionally */ - llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_SETFLAG(linkp, DATA, 1); - action = 0; - } - } - case LLCFT_INFO + LLC_CMD: - case LLCFT_INFO + LLC_RSP: { - register int p = LLC_GETFLAG(linkp, P); - register int nr = LLCGBITS(frame->llc_control_ext, s_nr); - - if (cmdrsp == LLC_CMD && pollfinal == 1) { - llc_send(linkp, LLCFT_RNR, LLC_RSP, 1); - LLC_INC(linkp->llcl_vr); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_SETFLAG(linkp, DATA, 0); - action = LLC_DATA_INDICATION; - } else if (cmdrsp == LLC_RSP && pollfinal == 1) { - llc_send(linkp, LLCFT_RNR, LLC_CMD, 1); - LLC_INC(linkp->llcl_vr); - LLC_START_P_TIMER(linkp); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - linkp->llcl_vs = nr; - LLC_SETFLAG(linkp, DATA, 0); - LLC_CLEAR_REMOTE_BUSY(linkp, action); - llc_resend(linkp, LLC_CMD, 0); - LLC_NEWSTATE(linkp, BUSY); - action = LLC_DATA_INDICATION; - } else if (pollfinal == 0) { - llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); - LLC_INC(linkp->llcl_vr); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_SETFLAG(linkp, DATA, 0); - action = LLC_DATA_INDICATION; - } - break; - } - case LLCFT_RR + LLC_CMD: - case LLCFT_REJ + LLC_CMD: - case LLCFT_RR + LLC_RSP: - case LLCFT_REJ + LLC_RSP: { - register int p = LLC_GETFLAG(linkp, P); - register int nr = LLCGBITS(frame->llc_control_ext, s_nr); - - if (cmdrsp == LLC_CMD && pollfinal == 1) { - llc_send(linkp, LLCFT_RNR, LLC_RSP, 1); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_CLEAR_REMOTE_BUSY(linkp, action); - } else if (cmdrsp == LLC_RSP && pollfinal == 1) { - LLC_UPDATE_NR_RECEIVED(linkp, nr); - linkp->llcl_vs = nr; - LLC_STOP_P_TIMER(linkp); - llc_resend(linkp, LLC_CMD, 0); - LLC_CLEAR_REMOTE_BUSY(linkp, action); - LLC_NEWSTATE(linkp, BUSY); - } else if (pollfinal == 0) { - LLC_UPDATE_NR_RECEIVED(linkp, nr); - linkp->llcl_vs = nr; - LLC_STOP_P_TIMER(linkp); - llc_resend(linkp, LLC_CMD, 0); - LLC_CLEAR_REMOTE_BUSY(linkp, action); - } - break; - } - case LLCFT_RNR + LLC_CMD: - case LLCFT_RNR + LLC_RSP: { - register int p = LLC_GETFLAG(linkp, P); - register int nr = LLCGBITS(frame->llc_control_ext, s_nr); - - if (cmdrsp == LLC_CMD && pollfinal == 1) { - llc_send(linkp, LLCFT_RNR, LLC_RSP, 1); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_SET_REMOTE_BUSY(linkp, action); - } else if (cmdrsp == LLC_RSP && pollfinal == 1) { - LLC_UPDATE_NR_RECEIVED(linkp, nr); - linkp->llcl_vs = nr; - LLC_STOP_P_TIMER(linkp); - LLC_SET_REMOTE_BUSY(linkp, action); - LLC_NEWSTATE(linkp, BUSY); - } else if (pollfinal == 0) { - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_SET_REMOTE_BUSY(linkp, action); - } - break; - } - case LLC_P_TIMER_EXPIRED: - if (linkp->llcl_retry < llc_n2) { - llc_send(linkp, LLCFT_RNR, LLC_CMD, 1); - LLC_START_P_TIMER(linkp); - linkp->llcl_retry++; - action = 0; - } - break; - } - if (action == LLC_PASSITON) - action = llc_state_NBRAcore(linkp, frame, frame_kind, - cmdrsp, pollfinal); - - return action; -} - -/* - * AWAIT_REJECT --- A data link connection exists between the local LLC service - * access point and the remote LLC service access point. The - * local connection component has requested that the remote - * connection component re-transmit a specific I PDU that the - * local connection component has detected as being out of - * sequence. Before the local LLC entered this state it was - * performing a timer recovery operation and had sent a - * command PDU with the P bit set to ``1'', and is still - * awaiting an acknowledgment from the remote LLC. I PDUs may - * be received but not transmitted. Supervisory PDUs may be - * both transmitted and received. - */ -int -llc_state_AWAIT_REJECT(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, - int cmdrsp, int pollfinal) -{ - int action = LLC_PASSITON; - - switch(frame_kind + cmdrsp) { - case LLC_LOCAL_BUSY_DETECTED: - llc_send(linkp, LLCFT_RNR, LLC_CMD, 0); - LLC_SETFLAG(linkp, DATA, 2); - LLC_NEWSTATE(linkp, AWAIT_BUSY); - action = 0; - break; - case LLC_INVALID_NS + LLC_CMD: - case LLC_INVALID_NS + LLC_RSP: { - register int nr = LLCGBITS(frame->llc_control_ext, s_nr); - - if (cmdrsp == LLC_CMD && pollfinal == 1) { - llc_send(linkp, LLCFT_RR, LLC_RSP, 1); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - action = 0; - } else if (cmdrsp == LLC_RSP && pollfinal == 1) { - LLC_UPDATE_NR_RECEIVED(linkp, nr); - linkp->llcl_vs = nr; - llc_resend(linkp, LLC_CMD, 1); - LLC_START_P_TIMER(linkp); - LLC_CLEAR_REMOTE_BUSY(linkp, action); - LLC_NEWSTATE(linkp, REJECT); - } else if (pollfinal == 0) { - LLC_UPDATE_NR_RECEIVED(linkp, nr); - action = 0; - } - break; - } - case LLCFT_INFO + LLC_CMD: - case LLCFT_INFO + LLC_RSP: { - register int nr = LLCGBITS(frame->llc_control_ext, s_nr); - - if (cmdrsp == LLC_CMD && pollfinal == 1) { - LLC_INC(linkp->llcl_vr); - llc_send(linkp, LLCFT_RR, LLC_RSP, 1); - LLC_STOP_REJ_TIMER(linkp); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_NEWSTATE(linkp, AWAIT); - action = LLC_DATA_INDICATION; - } else if (cmdrsp == LLC_RSP && pollfinal == 1) { - LLC_INC(linkp->llcl_vr); - LLC_STOP_P_TIMER(linkp); - LLC_STOP_REJ_TIMER(linkp); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - linkp->llcl_vs = nr; - llc_resend(linkp, LLC_CMD, 0); - LLC_CLEAR_REMOTE_BUSY(linkp, action); - LLC_NEWSTATE(linkp, NORMAL); - action = LLC_DATA_INDICATION; - } else if (pollfinal == 0) { - LLC_INC(linkp->llcl_vr); - llc_send(linkp, LLCFT_RR, LLC_CMD, 0); - LLC_STOP_REJ_TIMER(linkp); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_NEWSTATE(linkp, AWAIT); - action = LLC_DATA_INDICATION; - } - break; - } - case LLCFT_RR + LLC_CMD: - case LLCFT_REJ + LLC_CMD: - case LLCFT_RR + LLC_RSP: - case LLCFT_REJ + LLC_RSP: { - register int nr = LLCGBITS(frame->llc_control_ext, s_nr); - - if (cmdrsp == LLC_CMD && pollfinal == 1) { - llc_send(linkp, LLCFT_RR, LLC_RSP, 1); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_CLEAR_REMOTE_BUSY(linkp, action); - } else if (cmdrsp == LLC_RSP && pollfinal == 1) { - LLC_UPDATE_NR_RECEIVED(linkp, nr); - linkp->llcl_vs = nr; - llc_resend(linkp, LLC_CMD, 1); - LLC_START_P_TIMER(linkp); - LLC_CLEAR_REMOTE_BUSY(linkp, action); - LLC_NEWSTATE(linkp, REJECT); - } else if (pollfinal == 0) { - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_CLEAR_REMOTE_BUSY(linkp, action); - } - break; - } - case LLCFT_RNR + LLC_CMD: - case LLCFT_RNR + LLC_RSP: { - register int nr = LLCGBITS(frame->llc_control_ext, s_nr); - - if (cmdrsp == LLC_CMD && pollfinal == 1) { - llc_send(linkp, LLCFT_RR, LLC_RSP, 1); - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_SET_REMOTE_BUSY(linkp, action); - } else if (cmdrsp == LLC_RSP && pollfinal == 1) { - LLC_UPDATE_NR_RECEIVED(linkp, nr); - linkp->llcl_vs = nr; - LLC_STOP_P_TIMER(linkp); - LLC_SET_REMOTE_BUSY(linkp, action); - LLC_NEWSTATE(linkp, REJECT); - } else if (pollfinal == 0) { - LLC_UPDATE_NR_RECEIVED(linkp, nr); - LLC_SET_REMOTE_BUSY(linkp, action); - } - break; - } - case LLC_P_TIMER_EXPIRED: - if (linkp->llcl_retry < llc_n2) { - llc_send(linkp, LLCFT_REJ, LLC_CMD, 1); - LLC_START_P_TIMER(linkp); - linkp->llcl_retry++; - action = 0; - } - break; - } - if (action == LLC_PASSITON) - action = llc_state_NBRAcore(linkp, frame, frame_kind, - cmdrsp, pollfinal); - - return action; -} - - -/* - * llc_statehandler() --- Wrapper for llc_state_*() functions. - * Deals with action codes and checks for - * ``stuck'' links. - */ - -int -llc_statehandler(struct llc_linkcb *linkp, struct llc *frame, int frame_kind, - int cmdrsp, int pollfinal) -{ - register int action = 0; - - /* - * To check for ``zombie'' links each time llc_statehandler() gets called - * the AGE timer of linkp is reset. If it expires llc_timer() will - * take care of the link --- i.e. kill it 8=) - */ - LLC_STARTTIMER(linkp, AGE); - - /* - * Now call the current statehandler function. - */ - action = (*linkp->llcl_statehandler)(linkp, frame, frame_kind, - cmdrsp, pollfinal); -once_more_and_again: - switch (action) { - case LLC_CONNECT_INDICATION: { - int naction; - - LLC_TRACE(linkp, LLCTR_INTERESTING, "CONNECT INDICATION"); - linkp->llcl_nlnext = - (*linkp->llcl_sapinfo->si_ctlinput) - (PRC_CONNECT_INDICATION, - (struct sockaddr *) &linkp->llcl_addr, (caddr_t) linkp); - if (linkp->llcl_nlnext == 0) - naction = NL_DISCONNECT_REQUEST; - else naction = NL_CONNECT_RESPONSE; - action = (*linkp->llcl_statehandler)(linkp, frame, naction, 0, 0); - goto once_more_and_again; - } - case LLC_CONNECT_CONFIRM: - /* llc_resend(linkp, LLC_CMD, 0); */ - llc_start(linkp); - break; - case LLC_DISCONNECT_INDICATION: - LLC_TRACE(linkp, LLCTR_INTERESTING, "DISCONNECT INDICATION"); - (*linkp->llcl_sapinfo->si_ctlinput) - (PRC_DISCONNECT_INDICATION, - (struct sockaddr *) &linkp->llcl_addr, linkp->llcl_nlnext); - break; - /* internally visible only */ - case LLC_RESET_CONFIRM: - case LLC_RESET_INDICATION_LOCAL: - /* - * not much we can do here, the state machine either makes it or - * brakes it ... - */ - break; - case LLC_RESET_INDICATION_REMOTE: - LLC_TRACE(linkp, LLCTR_SHOULDKNOW, "RESET INDICATION (REMOTE)"); - action = (*linkp->llcl_statehandler)(linkp, frame, - NL_RESET_RESPONSE, 0, 0); - goto once_more_and_again; - case LLC_FRMR_SENT: - LLC_TRACE(linkp, LLCTR_URGENT, "FRMR SENT"); - break; - case LLC_FRMR_RECEIVED: - LLC_TRACE(linkp, LLCTR_URGEN, "FRMR RECEIVED"); - action = (*linkp->llcl_statehandler)(linkp, frame, - NL_RESET_REQUEST, 0, 0); - - goto once_more_and_again; - case LLC_REMOTE_BUSY: - LLC_TRACE(linkp, LLCTR_SHOULDKNOW, "REMOTE BUSY"); - break; - case LLC_REMOTE_NOT_BUSY: - LLC_TRACE(linkp, LLCTR_SHOULDKNOW, "REMOTE BUSY CLEARED"); - /* - * try to get queued frames out - */ - llc_start(linkp); - break; - } - - /* - * Only LLC_DATA_INDICATION is for the time being - * passed up to the network layer entity. - * The remaining action codes are for the time - * being visible internally only. - * However, this can/may be changed if necessary. - */ - - return action; -} - - -/* - * Core LLC2 routines - */ - -/* - * The INIT call. This routine is called once after the system is booted. - */ - -llc_init() -{ - llcintrq.ifq_maxlen = IFQ_MAXLEN; -} - - -/* - * In case of a link reset we need to shuffle the frames queued inside the - * LLC2 window. - */ - -void -llc_resetwindow(struct llc_linkcb *linkp) -{ - register struct mbuf *mptr = (struct mbuf *) 0; - register struct mbuf *anchor = (struct mbuf *)0; - register short i; - - /* Pick up all queued frames and collect them in a linked mbuf list */ - if (linkp->llcl_slotsfree != linkp->llcl_window) { - i = llc_seq2slot(linkp, linkp->llcl_nr_received); - anchor = mptr = linkp->llcl_output_buffers[i]; - for (; i != linkp->llcl_freeslot; - i = llc_seq2slot(linkp, i+1)) { - if (linkp->llcl_output_buffers[i]) { - mptr->m_nextpkt = linkp->llcl_output_buffers[i]; - mptr = mptr->m_nextpkt; - } else panic("LLC2 window broken"); - } - } - /* clean closure */ - if (mptr) - mptr->m_nextpkt = (struct mbuf *) 0; - - /* Now --- plug 'em in again */ - if (anchor != (struct mbuf *)0) { - for (i = 0, mptr = anchor; mptr != (struct mbuf *) 0; i++) { - linkp->llcl_output_buffers[i] = mptr; - mptr = mptr->m_nextpkt; - linkp->llcl_output_buffers[i]->m_nextpkt = (struct mbuf *)0; - } - linkp->llcl_freeslot = i; - } else linkp->llcl_freeslot = 0; - - /* We're resetting the link, the next frame to be acknowledged is 0 */ - linkp->llcl_nr_received = 0; - - /* set distance between LLC2 sequence number and the top of window to 0 */ - linkp->llcl_projvs = linkp->llcl_freeslot; - - return; -} - -/* - * llc_newlink() --- We allocate enough memory to contain a link control block - * and initialize it properly. We don't intiate the actual - * setup of the LLC2 link here. - */ -struct llc_linkcb * -llc_newlink(struct sockaddr_dl *dst, struct ifnet *ifp, struct rtentry *nlrt, - caddr_t nlnext, struct rtentry *llrt) -{ - struct llc_linkcb *nlinkp; - u_char sap = LLSAPADDR(dst); - short llcwindow; - - - /* allocate memory for link control block */ - MALLOC(nlinkp, struct llc_linkcb *, sizeof(struct llc_linkcb), - M_PCB, M_NOWAIT); - if (nlinkp == 0) - return (NULL); - bzero((caddr_t)nlinkp, sizeof(struct llc_linkcb)); - - /* copy link address */ - sdl_copy(dst, &nlinkp->llcl_addr); - - /* hold on to the network layer route entry */ - nlinkp->llcl_nlrt = nlrt; - - /* likewise the network layer control block */ - nlinkp->llcl_nlnext = nlnext; - - /* jot down the link layer route entry */ - nlinkp->llcl_llrt = llrt; - - /* reset writeq */ - nlinkp->llcl_writeqh = nlinkp->llcl_writeqt = NULL; - - /* setup initial state handler function */ - nlinkp->llcl_statehandler = llc_state_ADM; - - /* hold on to interface pointer */ - nlinkp->llcl_if = ifp; - - /* get service access point information */ - nlinkp->llcl_sapinfo = llc_getsapinfo(sap, ifp); - - /* get window size from SAP info block */ - if ((llcwindow = nlinkp->llcl_sapinfo->si_window) == 0) - llcwindow = LLC_MAX_WINDOW; - - /* allocate memory for window buffer */ - MALLOC(nlinkp->llcl_output_buffers, struct mbuf **, - llcwindow*sizeof(struct mbuf *), M_PCB, M_NOWAIT); - if (nlinkp->llcl_output_buffers == 0) { - FREE(nlinkp, M_PCB); - return(NULL); - } - bzero((caddr_t)nlinkp->llcl_output_buffers, - llcwindow*sizeof(struct mbuf *)); - - /* set window size & slotsfree */ - nlinkp->llcl_slotsfree = nlinkp->llcl_window = llcwindow; - - /* enter into linked listed of link control blocks */ - insque(nlinkp, &llccb_q); - - return(nlinkp); -} - -/* - * llc_dellink() --- farewell to link control block - */ -llc_dellink(struct llc_linkcb *linkp) -{ - register struct mbuf *m; - register struct mbuf *n; - register struct npaidbentry *sapinfo = linkp->llcl_sapinfo; - register i; - - /* notify upper layer of imminent death */ - if (linkp->llcl_nlnext && sapinfo->si_ctlinput) - (*sapinfo->si_ctlinput) - (PRC_DISCONNECT_INDICATION, - (struct sockaddr *)&linkp->llcl_addr, linkp->llcl_nlnext); - - /* pull the plug */ - if (linkp->llcl_llrt) - ((struct npaidbentry *)(linkp->llcl_llrt->rt_llinfo))->np_link - = (struct llc_linkcb *) 0; - - /* leave link control block queue */ - remque(linkp); - - /* drop queued packets */ - for (m = linkp->llcl_writeqh; m;) { - n = m->m_act; - m_freem(m); - m = n; - } - - /* drop packets in the window */ - for(i = 0; i < linkp->llcl_window; i++) - if (linkp->llcl_output_buffers[i]) - m_freem(linkp->llcl_output_buffers[i]); - - /* return the window space */ - FREE((caddr_t)linkp->llcl_output_buffers, M_PCB); - - /* return the control block space --- now it's gone ... */ - FREE((caddr_t)linkp, M_PCB); -} - -llc_decode(struct llc* frame, struct llc_linkcb * linkp) -{ - register int ft = LLC_BAD_PDU; - - if ((frame->llc_control & 01) == 0) { - ft = LLCFT_INFO; - /* S or U frame ? */ - } else switch (frame->llc_control) { - - /* U frames */ - case LLC_UI: - case LLC_UI_P: ft = LLC_UI; break; - case LLC_DM: - case LLC_DM_P: ft =LLCFT_DM; break; - case LLC_DISC: - case LLC_DISC_P: ft = LLCFT_DISC; break; - case LLC_UA: - case LLC_UA_P: ft = LLCFT_UA; break; - case LLC_SABME: - case LLC_SABME_P: ft = LLCFT_SABME; break; - case LLC_FRMR: - case LLC_FRMR_P: ft = LLCFT_FRMR; break; - case LLC_XID: - case LLC_XID_P: ft = LLCFT_XID; break; - case LLC_TEST: - case LLC_TEST_P: ft = LLCFT_TEST; break; - - /* S frames */ - case LLC_RR: ft = LLCFT_RR; break; - case LLC_RNR: ft = LLCFT_RNR; break; - case LLC_REJ: ft = LLCFT_REJ; break; - } /* switch */ - - if (linkp) { - switch (ft) { - case LLCFT_INFO: - if (LLCGBITS(frame->llc_control, i_ns) != linkp->llcl_vr) { - ft = LLC_INVALID_NS; - break; - } - /* fall thru --- yeeeeeee */ - case LLCFT_RR: - case LLCFT_RNR: - case LLCFT_REJ: - /* splash! */ - if (LLC_NR_VALID(linkp, LLCGBITS(frame->llc_control_ext, - s_nr)) == 0) - ft = LLC_INVALID_NR; - break; - } - } - - return ft; -} - -/* - * llc_anytimersup() --- Checks if at least one timer is still up and running. - */ -int -llc_anytimersup(struct llc_linkcb * linkp) -{ - register int i; - - FOR_ALL_LLC_TIMERS(i) - if (linkp->llcl_timers[i] > 0) - break; - if (i == LLC_AGE_SHIFT) - return 0; - else return 1; -} - -/* - * llc_link_dump() - dump link info - */ - -#define SAL(s) ((struct sockaddr_dl *)&(s)->llcl_addr) -#define CHECK(l, s) if (LLC_STATEEQ(l, s)) return #s - -char *timer_names[] = {"ACK", "P", "BUSY", "REJ", "AGE"}; - -char * -llc_getstatename(struct llc_linkcb *linkp) -{ - CHECK(linkp, ADM); - CHECK(linkp, CONN); - CHECK(linkp, RESET_WAIT); - CHECK(linkp, RESET_CHECK); - CHECK(linkp, SETUP); - CHECK(linkp, RESET); - CHECK(linkp, D_CONN); - CHECK(linkp, ERROR); - CHECK(linkp, NORMAL); - CHECK(linkp, BUSY); - CHECK(linkp, REJECT); - CHECK(linkp, AWAIT); - CHECK(linkp, AWAIT_BUSY); - CHECK(linkp, AWAIT_REJECT); - - return "UNKNOWN - eh?"; -} - -void -llc_link_dump(struct llc_linkcb* linkp, const char *message) -{ - register int i; - register char *state; - - /* print interface */ - printf("if %s%d\n", linkp->llcl_if->if_name, linkp->llcl_if->if_unit); - - /* print message */ - printf(">> %s <<\n", message); - - /* print MAC and LSAP */ - printf("llc addr "); - for (i = 0; i < (SAL(linkp)->sdl_alen)-2; i++) - printf("%x:", (char)*(LLADDR(SAL(linkp))+i) & 0xff); - printf("%x,", (char)*(LLADDR(SAL(linkp))+i) & 0xff); - printf("%x\n", (char)*(LLADDR(SAL(linkp))+i+1) & 0xff); - - /* print state we're in and timers */ - printf("state %s, ", llc_getstatename(linkp)); - for (i = LLC_ACK_SHIFT; i < LLC_AGE_SHIFT; i++) - printf("%s-%c %d/", timer_names[i], - (linkp->llcl_timerflags & (1<llcl_timers[i]); - printf("%s-%c %d\n", timer_names[i], (linkp->llcl_timerflags & (1<llcl_timers[i]); - - /* print flag values */ - printf("flags P %d/F %d/S %d/DATA %d/REMOTE_BUSY %d\n", - LLC_GETFLAG(linkp, P), LLC_GETFLAG(linkp, S), - LLC_GETFLAG(linkp, DATA), LLC_GETFLAG(linkp, REMOTE_BUSY)); - - /* print send and receive state variables, ack, and window */ - printf("V(R) %d/V(S) %d/N(R) received %d/window %d/freeslot %d\n", - linkp->llcl_vs, linkp->llcl_vr, linkp->llcl_nr_received, - linkp->llcl_window, linkp->llcl_freeslot); - - /* further expansions can follow here */ - -} - -void -llc_trace(struct llc_linkcb *linkp, int level, const char *message) -{ - if (linkp->llcl_sapinfo->si_trace && level > llc_tracelevel) - llc_link_dump(linkp, message); - - return; -} diff --git a/bsd/netccitt/llc_timer.c b/bsd/netccitt/llc_timer.c deleted file mode 100644 index 6014a31ff..000000000 --- a/bsd/netccitt/llc_timer.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (C) Dirk Husemann, Computer Science Department IV, - * University of Erlangen-Nuremberg, Germany, 1990, 1991, 1992 - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Dirk Husemann and the Computer Science Department (IV) of - * the University of Erlangen-Nuremberg, Germany. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)llc_timer.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - - -/* - * Various timer values. They can be adjusted - * by patching the binary with adb if necessary. - */ -/* ISO 8802-2 timers */ -int llc_n2 = LLC_N2_VALUE; -int llc_ACK_timer = LLC_ACK_TIMER; -int llc_P_timer = LLC_P_TIMER; -int llc_BUSY_timer = LLC_BUSY_TIMER; -int llc_REJ_timer = LLC_REJ_TIMER; -/* Implementation specific timers */ -int llc_AGE_timer = LLC_AGE_TIMER; -int llc_DACTION_timer = LLC_DACTION_TIMER; - -/* - * The timer routine. We are called every 500ms by the kernel. - * Handle the various virtual timers. - */ - -void -llc_timer() -{ - register struct llc_linkcb *linkp; - register struct llc_linkcb *nlinkp; - register int timer; - register int action; - register int s = splimp(); - - /* - * All links are accessible over the doubly linked list llccb_q - */ - if (!LQEMPTY) { - /* - * A for-loop is not that great an idea as the linkp - * might get deleted if the age timer has expired ... - */ - linkp = LQFIRST; - while (LQVALID(linkp)) { - nlinkp = LQNEXT(linkp); - /* - * Check implementation specific timers first - */ - /* The delayed action/acknowledge idle timer */ - switch (LLC_TIMERXPIRED(linkp, DACTION)) { - case LLC_TIMER_RUNNING: - LLC_AGETIMER(linkp, DACTION); - break; - case LLC_TIMER_EXPIRED: { - register int cmdrsp; - register int pollfinal; - - switch (LLC_GETFLAG(linkp, DACTION)) { - case LLC_DACKCMD: - cmdrsp = LLC_CMD, pollfinal = 0; - break; - case LLC_DACKCMDPOLL: - cmdrsp = LLC_CMD, pollfinal = 1; - break; - case LLC_DACKRSP: - cmdrsp = LLC_RSP, pollfinal = 0; - break; - case LLC_DACKRSPFINAL: - cmdrsp = LLC_RSP, pollfinal = 1; - break; - } - llc_send(linkp, LLCFT_RR, cmdrsp, pollfinal); - LLC_STOPTIMER(linkp, DACTION); - break; - } - } - /* The link idle timer */ - switch (LLC_TIMERXPIRED(linkp, AGE)) { - case LLC_TIMER_RUNNING: - LLC_AGETIMER(linkp, AGE); - break; - case LLC_TIMER_EXPIRED: - /* - * Only crunch the link when really no - * timers are running any more. - */ - if (llc_anytimersup(linkp) == 0) { - llc_dellink(linkp); - LLC_STOPTIMER(linkp, AGE); - goto gone; - } else { - LLC_STARTTIMER(linkp, AGE); - } - break; - } - /* - * Now, check all the ISO 8802-2 timers - */ - FOR_ALL_LLC_TIMERS(timer) { - action = 0; - if ((linkp->llcl_timerflags & (1<llcl_timers[timer] == 0)) { - switch (timer) { - case LLC_ACK_SHIFT: - action = LLC_ACK_TIMER_EXPIRED; - break; - case LLC_P_SHIFT: - action = LLC_P_TIMER_EXPIRED; - break; - case LLC_BUSY_SHIFT: - action = LLC_BUSY_TIMER_EXPIRED; - break; - case LLC_REJ_SHIFT: - action = LLC_REJ_TIMER_EXPIRED; - break; - } - linkp->llcl_timerflags &= ~(1<llcl_timers[timer] > 0) - linkp->llcl_timers[timer]--; - } - -gone: linkp = nlinkp; - } - } - splx (s); -} diff --git a/bsd/netccitt/llc_var.h b/bsd/netccitt/llc_var.h deleted file mode 100644 index 0bb1d3948..000000000 --- a/bsd/netccitt/llc_var.h +++ /dev/null @@ -1,680 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (C) Dirk Husemann, Computer Science Department IV, - * University of Erlangen-Nuremberg, Germany, 1990, 1991, 1992 - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Dirk Husemann and the Computer Science Department (IV) of - * the University of Erlangen-Nuremberg, Germany. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)llc_var.h 8.1 (Berkeley) 6/10/93 - */ - -#ifdef __STDC__ -/* - * Forward structure declarations for function prototypes [sic]. - */ -struct llc; -#endif - -#define NPAIDB_LINK 0 - -struct npaidbentry { - union { - /* MAC,DLSAP -> CONS */ - struct { - struct llc_linkcb *NE_link; - struct rtentry *NE_rt; - } NE; - /* SAP info for unconfigured incoming calls */ - struct { - u_short SI_class; -#define LLC_CLASS_I 0x1 -#define LLC_CLASS_II 0x3 -#define LLC_CLASS_III 0x4 /* Future */ -#define LLC_CLASS_IV 0x7 /* Future */ - u_short SI_window; - u_short SI_trace; - u_short SI_xchxid; - void (*SI_input) - __P((struct mbuf *)); - caddr_t (*SI_ctlinput) - __P((int, struct sockaddr *, caddr_t)); - } SI; - } NESIun; -}; -#define np_link NESIun.NE.NE_link -#define np_rt NESIun.NE.NE_rt -#define si_class NESIun.SI.SI_class -#define si_window NESIun.SI.SI_window -#define si_trace NESIun.SI.SI_trace -#define si_xchxid NESIun.SI.SI_xchxid -#define si_input NESIun.SI.SI_input -#define si_ctlinput NESIun.SI.SI_ctlinput - -#define NPDL_SAPNETMASK 0x7e - -/* - * Definitions for accessing bitfields/bitslices inside - * LLC2 headers - */ -struct bitslice { - unsigned int bs_mask; - unsigned int bs_shift; -}; - - -#define i_z 0 -#define i_ns 1 -#define i_pf 0 -#define i_nr 1 -#define s_oz 2 -#define s_selector 3 -#define s_pf 0 -#define s_nr 1 -#define u_bb 2 -#define u_select_other 3 -#define u_pf 4 -#define u_select 5 -#define f_vs 1 -#define f_cr 0 -#define f_vr 1 -#define f_wxyzv 6 - -#define LLCGBITS(Arg, Index) (((Arg) & llc_bitslice[(Index)].bs_mask) >> llc_bitslice[(Index)].bs_shift) -#define LLCSBITS(Arg, Index, Val) (Arg) |= (((Val) << llc_bitslice[(Index)].bs_shift) & llc_bitslice[(Index)].bs_mask) -#define LLCCSBITS(Arg, Index, Val) (Arg) = (((Val) << llc_bitslice[(Index)].bs_shift) & llc_bitslice[(Index)].bs_mask) - -extern struct bitslice llc_bitslice[]; - -#define LLC_CMD 0 -#define LLC_RSP 1 -#define LLC_MAXCMDRSP 2 - -/* - * LLC events --- These events may either be frames received from the - * remote LLC DSAP, request from the network layer user, - * timer events from llc_timer(), or diagnostic events from - * llc_input(). - */ - -/* LLC frame types */ -#define LLCFT_INFO 0 * LLC_MAXCMDRSP -#define LLCFT_RR 1 * LLC_MAXCMDRSP -#define LLCFT_RNR 2 * LLC_MAXCMDRSP -#define LLCFT_REJ 3 * LLC_MAXCMDRSP -#define LLCFT_DM 4 * LLC_MAXCMDRSP -#define LLCFT_SABME 5 * LLC_MAXCMDRSP -#define LLCFT_DISC 6 * LLC_MAXCMDRSP -#define LLCFT_UA 7 * LLC_MAXCMDRSP -#define LLCFT_FRMR 8 * LLC_MAXCMDRSP -#define LLCFT_UI 9 * LLC_MAXCMDRSP -#define LLCFT_XID 10 * LLC_MAXCMDRSP -#define LLCFT_TEST 11 * LLC_MAXCMDRSP - -/* LLC2 timer events */ -#define LLC_ACK_TIMER_EXPIRED 12 * LLC_MAXCMDRSP -#define LLC_P_TIMER_EXPIRED 13 * LLC_MAXCMDRSP -#define LLC_REJ_TIMER_EXPIRED 14 * LLC_MAXCMDRSP -#define LLC_BUSY_TIMER_EXPIRED 15 * LLC_MAXCMDRSP - -/* LLC2 diagnostic events */ -#define LLC_INVALID_NR 16 * LLC_MAXCMDRSP -#define LLC_INVALID_NS 17 * LLC_MAXCMDRSP -#define LLC_BAD_PDU 18 * LLC_MAXCMDRSP -#define LLC_LOCAL_BUSY_DETECTED 19 * LLC_MAXCMDRSP -#define LLC_LOCAL_BUSY_CLEARED 20 * LLC_MAXCMDRSP - -/* Network layer user requests */ -/* - * NL_CONNECT_REQUEST --- The user has requested that a data link connection - * be established with a remote LLC DSAP. - */ -#define NL_CONNECT_REQUEST 21 * LLC_MAXCMDRSP -/* - * NL_CONNECT_RESPONSE --- The user has accepted the data link connection. - */ -#define NL_CONNECT_RESPONSE 22 * LLC_MAXCMDRSP -/* - * NL_RESET_REQUEST --- The user has requested that the data link with the - * remote LLC DSAP be reset. - */ -#define NL_RESET_REQUEST 23 * LLC_MAXCMDRSP -/* - * NL_RESET_RESPONSE --- The user has accepted the reset of the data link - * connection. - */ -#define NL_RESET_RESPONSE 24 * LLC_MAXCMDRSP -/* - * NL_DISCONNECT_REQUEST --- The user has requested that the data link - * connection with remote LLC DSAP be terminated. - */ -#define NL_DISCONNECT_REQUEST 25 * LLC_MAXCMDRSP -/* - * NL_DATA_REQUEST --- The user has requested that a data unit be sent ot the - * remote LLC DSAP. - */ -#define NL_DATA_REQUEST 26 * LLC_MAXCMDRSP -/* - * NL_INITIATE_PF_CYCLE --- The local LLC wants to initiate a P/F cycle. - */ -#define NL_INITIATE_PF_CYCLE 27 * LLC_MAXCMDRSP -/* - * NL_LOCAL_BUSY_DETECTED --- The local entity has encountered a busy condition - */ -#define NL_LOCAL_BUSY_DETECTED 28 * LLC_MAXCMDRSP - -#define LLCFT_NONE 255 - -/* return message from state handlers */ - -/* - * LLC_CONNECT_INDICATION --- Inform the user that a connection has been - * requested by a remote LLC SSAP. - */ -#define LLC_CONNECT_INDICATION 1 -/* - * LLC_CONNECT_CONFIRM --- The connection service component indicates that the - * remote network entity has accepted the connection. - */ -#define LLC_CONNECT_CONFIRM 2 -/* - * LLC_DISCONNECT_INDICATION --- Inform the user that the remote network - * entity has intiated disconnection of the data - * link connection. - */ -#define LLC_DISCONNECT_INDICATION 3 -/* - * LLC_RESET_CONFIRM --- The connection service component indicates that the - * remote network entity has accepted the reset. - */ -#define LLC_RESET_CONFIRM 4 -/* - * LLC_RESET_INDICATION_REMOTE --- The remote network entity or remote peer - * has initiated a reset of the data link - * connection. - */ -#define LLC_RESET_INDICATION_REMOTE 5 -/* - * LLC_RESET_INDICATION_LOCAL --- The local LLC has determined that the data - * link connection is in need of - * reinitialization. - */ -#define LLC_RESET_INDICATION_LOCAL 6 -/* - * LLC_FRMR_RECEIVED --- The local connection service component has received a - * FRMR response PDU. - */ -#define LLC_FRMR_RECEIVED 7 -/* - * LLC_FRMR_SENT --- The local connection component has received an ivalid - * PDU, and has sent a FRMR response PDU. - */ -#define LLC_FRMR_SENT 8 -/* - * LLC_DATA_INDICATION --- The connection service component passes the data - * unit from the received I PDU to the user. - */ -#define LLC_DATA_INDICATION 9 -/* - * LLC_REMOTE_NOT_BUSY --- The remote LLC DSAP is no longer busy. The local - * connection service component will now accept a - * DATA_REQUEST. - */ -#define LLC_REMOTE_NOT_BUSY 10 -/* - * LLC_REMOTE_BUSY --- The remote LLC DSAP is busy. The local connection - * service component will not accept a DATA_REQUEST. - */ -#define LLC_REMOTE_BUSY 11 - -/* Internal return code */ -#define LLC_PASSITON 255 - -#define INFORMATION_CONTROL 0x00 -#define SUPERVISORY_CONTROL 0x02 -#define UNUMBERED_CONTROL 0x03 - -/* - * Other necessary definitions - */ - -#define LLC_MAX_SEQUENCE 128 -#define LLC_MAX_WINDOW 127 -#define LLC_WINDOW_SIZE 7 - -/* - * Don't we love this one? CCITT likes its bits 8=) - */ -#define NLHDRSIZEGUESS 3 - -/* - * LLC control block - */ - -struct llc_linkcb { - struct llccb_q { - struct llccb_q *q_forw; /* admin chain */ - struct llccb_q *q_backw; - } llcl_q; - struct npaidbentry *llcl_sapinfo; /* SAP information */ - struct sockaddr_dl llcl_addr; /* link snpa address */ - struct rtentry *llcl_nlrt; /* layer 3 -> LLC */ - struct rtentry *llcl_llrt; /* LLC -> layer 3 */ - struct ifnet *llcl_if; /* our interface */ - caddr_t llcl_nlnext; /* cb for network layer */ - struct mbuf *llcl_writeqh; /* Write queue head */ - struct mbuf *llcl_writeqt; /* Write queue tail */ - struct mbuf **llcl_output_buffers; - short llcl_timers[6]; /* timer array */ - long llcl_timerflags; /* flags signalling running timers */ - int (*llcl_statehandler) - __P((struct llc_linkcb *, struct llc *, int, int, int)); - int llcl_P_flag; - int llcl_F_flag; - int llcl_S_flag; - int llcl_DATA_flag; - int llcl_REMOTE_BUSY_flag; - int llcl_DACTION_flag; /* delayed action */ - int llcl_retry; - /* - * The following components deal --- in one way or the other --- - * with the LLC2 window. Indicated by either [L] or [W] is the - * domain of the specific component: - * - * [L] The domain is 0--LLC_MAX_WINDOW - * [W] The domain is 0--llcl_window - */ - short llcl_vr; /* next to receive [L] */ - short llcl_vs; /* next to send [L] */ - short llcl_nr_received; /* next frame to b ack'd [L] */ - short llcl_freeslot; /* next free slot [W] */ - short llcl_projvs; /* V(S) associated with freeslot */ - short llcl_slotsfree; /* free slots [W] */ - short llcl_window; /* window size */ - /* - * In llcl_frmrinfo we jot down the last frmr info field, which we - * need to do as we need to be able to resend it in the ERROR state. - */ - struct frmrinfo llcl_frmrinfo; /* last FRMR info field */ -}; -#define llcl_frmr_pdu0 llcl_frmrinfo.rej_pdu_0 -#define llcl_frmr_pdu1 llcl_frmrinfo.rej_pdu_1 -#define llcl_frmr_control llcl_frmrinfo.frmr_control -#define llcl_frmr_control_ext llcl_frmrinfo.frmr_control_ext -#define llcl_frmr_cause llcl_frmrinfo.frmr_cause - -#define LQNEXT(l) (struct llc_linkcb *)((l)->llcl_q.q_forw) -#define LQEMPTY (llccb_q.q_forw == &llccb_q) -#define LQFIRST (struct llc_linkcb *)(llccb_q.q_forw) -#define LQVALID(l) (!((struct llccb_q *)(l) == &llccb_q)) - -#define LLC_ENQUEUE(l, m) if ((l)->llcl_writeqh == NULL) { \ - (l)->llcl_writeqh = (m); \ - (l)->llcl_writeqt = (m); \ - } else { \ - (l)->llcl_writeqt->m_nextpkt = (m); \ - (l)->llcl_writeqt = (m); \ - } - -#define LLC_DEQUEUE(l, m) if ((l)->llcl_writeqh == NULL) \ - (m) = NULL; \ - else { \ - (m) = (l)->llcl_writeqh; \ - (l)->llcl_writeqh = (l)->llcl_writeqh->m_nextpkt; \ - } - -#define LLC_SETFRAME(l, m) { \ - if ((l)->llcl_slotsfree > 0) { \ - (l)->llcl_slotsfree--; \ - (l)->llcl_output_buffers[(l)->llcl_freeslot] = (m); \ - (l)->llcl_freeslot = ((l)->llcl_freeslot+1) % (l)->llcl_window; \ - LLC_INC((l)->llcl_projvs); \ - } \ - } - -/* - * handling of sockaddr_dl's - */ - -#define LLADDRLEN(s) ((s)->sdl_alen + (s)->sdl_nlen) -#define LLSAPADDR(s) ((s)->sdl_data[LLADDRLEN(s)-1] & 0xff) -#define LLSAPLOC(s, if) ((s)->sdl_nlen + (if)->if_addrlen) - -struct sdl_hdr { - struct sockaddr_dl sdlhdr_dst; - struct sockaddr_dl sdlhdr_src; - long sdlhdr_len; -}; - -#define LLC_GETHDR(f,m) { \ - struct mbuf *_m = (struct mbuf *) (m); \ - if (_m) { \ - M_PREPEND(_m, LLC_ISFRAMELEN, M_DONTWAIT); \ - bzero(mtod(_m, caddr_t), LLC_ISFRAMELEN); \ - } else { \ - MGETHDR (_m, M_DONTWAIT, MT_HEADER); \ - if (_m != NULL) { \ - _m->m_pkthdr.len = _m->m_len = LLC_UFRAMELEN; \ - _m->m_next = _m->m_act = NULL; \ - bzero(mtod(_m, caddr_t), LLC_UFRAMELEN); \ - } else return; \ - } \ - (m) = _m; \ - (f) = mtod(m, struct llc *); \ - } - -#define LLC_NEWSTATE(l, LLCstate) (l)->llcl_statehandler = llc_state_##LLCstate -#define LLC_STATEEQ(l, LLCstate) ((l)->llcl_statehandler == llc_state_##LLCstate ? 1 : 0) - -#define LLC_ACK_SHIFT 0 -#define LLC_P_SHIFT 1 -#define LLC_BUSY_SHIFT 2 -#define LLC_REJ_SHIFT 3 -#define LLC_AGE_SHIFT 4 -#define LLC_DACTION_SHIFT 5 - -#define LLC_TIMER_NOTRUNNING 0 -#define LLC_TIMER_RUNNING 1 -#define LLC_TIMER_EXPIRED 2 - -#define LLC_STARTTIMER(l, LLCtimer) { \ - (l)->llcl_timers[LLC_##LLCtimer##_SHIFT] = llc_##LLCtimer##_timer; \ - (l)->llcl_timerflags |= (1<llcl_timers[LLC_##LLCtimer##_SHIFT] = 0; \ - (l)->llcl_timerflags &= ~(1<llcl_timers[LLC_##LLCtimer##_SHIFT] > 0) \ - (l)->llcl_timers[LLC_##LLCtimer##_SHIFT]--; - -#define LLC_TIMERXPIRED(l, LLCtimer) \ - (((l)->llcl_timerflags & (1<llcl_timers[LLC_##LLCtimer##_SHIFT] == 0 ) ? \ - LLC_TIMER_EXPIRED : LLC_TIMER_RUNNING) : LLC_TIMER_NOTRUNNING) - -#define FOR_ALL_LLC_TIMERS(t) for ((t) = LLC_ACK_SHIFT; (t) < LLC_AGE_SHIFT; (t)++) - -#define LLC_SETFLAG(l, LLCflag, v) (l)->llcl_##LLCflag##_flag = (v) -#define LLC_GETFLAG(l, LLCflag) (l)->llcl_##LLCflag##_flag - -#define LLC_RESETCOUNTER(l) { \ - (l)->llcl_vs = (l)->llcl_vr = (l)->llcl_retry = 0; \ - llc_resetwindow((l)); \ - } - -/* - * LLC2 macro definitions - */ - - -#define LLC_START_ACK_TIMER(l) LLC_STARTTIMER((l), ACK) -#define LLC_STOP_ACK_TIMER(l) LLC_STOPTIMER((l), ACK) -#define LLC_START_REJ_TIMER(l) LLC_STARTTIMER((l), REJ) -#define LLC_STOP_REJ_TIMER(l) LLC_STOPTIMER((l), REJ) -#define LLC_START_P_TIMER(l) { \ - LLC_STARTTIMER((l), P); \ - if (LLC_GETFLAG((l), P) == 0) \ - (l)->llcl_retry = 0; \ - LLC_SETFLAG((l), P, 1); \ - } -#define LLC_STOP_P_TIMER(l) { \ - LLC_STOPTIMER((l), P); \ - LLC_SETFLAG((l), P, 0); \ - } -#define LLC_STOP_ALL_TIMERS(l) { \ - LLC_STOPTIMER((l), ACK); \ - LLC_STOPTIMER((l), REJ); \ - LLC_STOPTIMER((l), BUSY); \ - LLC_STOPTIMER((l), P); \ - } - - -#define LLC_INC(i) (i) = ((i)+1) % LLC_MAX_SEQUENCE - -#define LLC_NR_VALID(l, nr) ((l)->llcl_vs < (l)->llcl_nr_received ? \ - (((nr) >= (l)->llcl_nr_received) || \ - ((nr) <= (l)->llcl_vs) ? 1 : 0) : \ - (((nr) <= (l)->llcl_vs) && \ - ((nr) >= (l)->llcl_nr_received) ? 1 : 0)) - -#define LLC_UPDATE_P_FLAG(l, cr, pf) { \ - if ((cr) == LLC_RSP && (pf) == 1) { \ - LLC_SETFLAG((l), P, 0); \ - LLC_STOPTIMER((l), P); \ - } \ - } - -#define LLC_UPDATE_NR_RECEIVED(l, nr) { \ - while ((l)->llcl_nr_received != (nr)) { \ - struct mbuf *_m; \ - register short seq; \ - if ((_m = (l)->llcl_output_buffers[seq = llc_seq2slot((l), (l)->llcl_nr_received)])) \ - m_freem(_m); \ - (l)->llcl_output_buffers[seq] = NULL; \ - LLC_INC((l)->llcl_nr_received); \ - (l)->llcl_slotsfree++; \ - } \ - (l)->llcl_retry = 0; \ - if ((l)->llcl_slotsfree < (l)->llcl_window) { \ - LLC_START_ACK_TIMER(l); \ - } else LLC_STOP_ACK_TIMER(l); \ - LLC_STARTTIMER((l), DACTION); \ - } - -#define LLC_SET_REMOTE_BUSY(l,a) { \ - if (LLC_GETFLAG((l), REMOTE_BUSY) == 0) { \ - LLC_SETFLAG((l), REMOTE_BUSY, 1); \ - LLC_STARTTIMER((l), BUSY); \ - (a) = LLC_REMOTE_BUSY; \ - } else { \ - (a) = 0; \ - } \ - } -#define LLC_CLEAR_REMOTE_BUSY(l,a) { \ - if (LLC_GETFLAG((l), REMOTE_BUSY) == 1) { \ - LLC_SETFLAG((l), REMOTE_BUSY, 1); \ - LLC_STOPTIMER((l), BUSY); \ - if (LLC_STATEEQ((l), NORMAL) || \ - LLC_STATEEQ((l), REJECT) || \ - LLC_STATEEQ((l), BUSY)) \ - llc_resend((l), LLC_CMD, 0); \ - (a) = LLC_REMOTE_NOT_BUSY; \ - } else { \ - (a) = 0; \ - } \ - } - -#define LLC_DACKCMD 0x1 -#define LLC_DACKCMDPOLL 0x2 -#define LLC_DACKRSP 0x3 -#define LLC_DACKRSPFINAL 0x4 - -#define LLC_SENDACKNOWLEDGE(l, cmd, pf) { \ - if ((cmd) == LLC_CMD) { \ - LLC_SETFLAG((l), DACTION, ((pf) == 0 ? LLC_DACKCMD : LLC_DACKCMDPOLL)); \ - } else { \ - LLC_SETFLAG((l), DACTION, ((pf) == 0 ? LLC_DACKRSP : LLC_DACKRSPFINAL)); \ - } \ - } - -#define LLC_FRMR_W (1<<0) -#define LLC_FRMR_X (1<<1) -#define LLC_FRMR_Y (1<<2) -#define LLC_FRMR_Z (1<<3) -#define LLC_FRMR_V (1<<4) - -#define LLC_SETFRMR(l, f, cr, c) { \ - if ((f)->llc_control & 0x3) { \ - (l)->llcl_frmr_pdu0 = (f)->llc_control; \ - (l)->llcl_frmr_pdu1 = 0; \ - } else { \ - (l)->llcl_frmr_pdu0 = (f)->llc_control; \ - (l)->llcl_frmr_pdu1 = (f)->llc_control_ext; \ - } \ - LLCCSBITS((l)->llcl_frmr_control, f_vs, (l)->llcl_vs); \ - LLCCSBITS((l)->llcl_frmr_control_ext, f_cr, (cr)); \ - LLCSBITS((l)->llcl_frmr_control_ext, f_vr, (l)->llcl_vr); \ - LLCCSBITS((l)->llcl_frmr_cause, f_wxyzv, (c)); \ - } - -/* - * LLC tracing levels: - * LLCTR_INTERESTING interesting event, we might care to know about - * it, but then again, we might not ... - * LLCTR_SHOULDKNOW we probably should know about this event - * LLCTR_URGENT something has gone utterly wrong ... - */ -#define LLCTR_INTERESTING 1 -#define LLCTR_SHOULDKNOW 2 -#define LLCTR_URGENT 3 - -#ifdef LLCDEBUG -#define LLC_TRACE(lp, l, msg) llc_trace((lp), (l), (msg)) -#else /* LLCDEBUG */ -#define LLC_TRACE(lp, l, msg) /* NOOP */ -#endif /* LLCDEBUG */ - -#define LLC_N2_VALUE 15 /* up to 15 retries */ -#define LLC_ACK_TIMER 10 /* 5 secs */ -#define LLC_P_TIMER 4 /* 2 secs */ -#define LLC_BUSY_TIMER 12 /* 6 secs */ -#define LLC_REJ_TIMER 12 /* 6 secs */ -#define LLC_AGE_TIMER 40 /* 20 secs */ -#define LLC_DACTION_TIMER 2 /* 1 secs */ - -#if defined (KERNEL) && defined(LLC) -extern int llc_n2; -extern int llc_ACK_timer; -extern int llc_P_timer; -extern int llc_REJ_timer; -extern int llc_BUSY_timer; -extern int llc_AGE_timer; -extern int llc_DACTION_timer; - -extern int af_link_rts_init_done; - -#define USES_AF_LINK_RTS { \ - if (!af_link_rts_init_done) { \ - rn_inithead((void **)&rt_tables[AF_LINK], 32); \ - af_link_rts_init_done++; \ - } \ - } - -struct ifqueue llcintrq; - -extern struct llccb_q llccb_q; -extern char *frame_names[]; - -/* - * Function prototypes - */ -int sdl_cmp __P((struct sockaddr_dl *, struct sockaddr_dl *)); -int sdl_copy __P((struct sockaddr_dl *, struct sockaddr_dl *)); -int sdl_swapaddr __P((struct sockaddr_dl *, struct sockaddr_dl *)); -int sdl_checkaddrif __P((struct ifnet *, struct sockaddr_dl *)); -int sdl_setaddrif __P((struct ifnet *, u_char *, u_char, u_char, - struct sockaddr_dl *)); -int sdl_sethdrif __P((struct ifnet *, u_char *, u_char, u_char *, u_char, u_char, - struct sdl_hdr *)); -struct npaidbentry *llc_setsapinfo __P((struct ifnet *, u_char, u_char, - struct dllconfig *)); -struct npaidbentry *llc_getsapinfo __P((u_char, struct ifnet *)); -struct rtentry *npaidb_enrich __P((short, caddr_t, struct sockaddr_dl *)); -int npaidb_destroy __P((struct rtentry *)); -short llc_seq2slot __P((struct llc_linkcb *, short)); -int llc_state_ADM __P((struct llc_linkcb *, struct llc *, int, int, int)); -int llc_state_CONN __P((struct llc_linkcb *, struct llc *, int, int, int)); -int llc_state_RESET_WAIT __P((struct llc_linkcb *, struct llc *, - int, int, int)); -int llc_state_RESET_CHECK __P((struct llc_linkcb *, struct llc *, - int, int, int)); -int llc_state_SETUP __P((struct llc_linkcb *, struct llc *, int, int, int)); -int llc_state_RESET __P((struct llc_linkcb *, struct llc *, int, int, int)); -int llc_state_D_CONN __P((struct llc_linkcb *, struct llc *, int, int, int)); -int llc_state_ERROR __P((struct llc_linkcb *, struct llc *, int, int, int)); -int llc_state_NBRAcore __P((struct llc_linkcb *, struct llc *, int, int, int)); -int llc_state_NORMAL __P((struct llc_linkcb *, struct llc *, int, int, int)); -int llc_state_BUSY __P((struct llc_linkcb *, struct llc *, int, int, int)); -int llc_state_REJECT __P((struct llc_linkcb *, struct llc *, int, int, int)); -int llc_state_AWAIT __P((struct llc_linkcb *, struct llc *, int, int, int)); -int llc_state_AWAIT_BUSY __P((struct llc_linkcb *, struct llc *, int, int, int)); -int llc_state_AWAIT_REJECT __P((struct llc_linkcb *, struct llc *, int, int, int)); -int llc_statehandler __P((struct llc_linkcb *, struct llc *, int, int, int)); -int llc_init __P((void)); -struct llc_linkcb *llc_newlink __P((struct sockaddr_dl *, struct ifnet *, - struct rtentry *, caddr_t, struct rtentry *)); -int llc_dellink __P((struct llc_linkcb *)); -int llc_anytimersup __P((struct llc_linkcb *)); -char * llc_getstatename __P((struct llc_linkcb *)); -void llc_link_dump __P((struct llc_linkcb *, const char *)); -void llc_trace __P((struct llc_linkcb *, int, const char *)); -void llc_resetwindow __P((struct llc_linkcb *)); -int llc_decode __P((struct llc *, struct llc_linkcb *)); -void llc_timer __P((void)); -void llcintr __P((void)); -int llc_input __P((struct llc_linkcb *, struct mbuf *, u_char)); -caddr_t llc_ctlinput __P((int, struct sockaddr *, caddr_t)); -int llc_output __P((struct llc_linkcb *, struct mbuf *)); -void llc_start __P((struct llc_linkcb *)); -int llc_send __P((struct llc_linkcb *, int, int, int)); -int llc_resend __P((struct llc_linkcb *, int, int)); -int llc_rawsend __P((struct llc_linkcb *, struct mbuf *, struct llc *, int, int, - int, int)); -int cons_rtrequest __P((int, struct rtentry *, struct sockaddr *)); -int x25_llcglue __P((int, struct sockaddr *)); - -#endif - - diff --git a/bsd/netccitt/pk.h b/bsd/netccitt/pk.h deleted file mode 100644 index 0a17e3367..000000000 --- a/bsd/netccitt/pk.h +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) University of British Columbia, 1984 - * Copyright (c) 1990, 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * the Laboratory for Computation Vision and the Computer Science Department - * of the University of British Columbia. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)pk.h 8.1 (Berkeley) 6/10/93 - */ - -/* - * - * X.25 Packet Level Definitions: - * - */ - -/* Packet type identifier field defintions. */ - -#define X25_CALL 11 -#define X25_CALL_ACCEPTED 15 -#define X25_CLEAR 19 -#define X25_CLEAR_CONFIRM 23 -#define X25_DATA 0 -#define X25_INTERRUPT 35 -#define X25_INTERRUPT_CONFIRM 39 - -#define X25_RR 1 -#define X25_RNR 5 -#define X25_REJECT 9 -#define X25_RESET 27 -#define X25_RESET_CONFIRM 31 -#define X25_DIAGNOSTIC 241 - -#define X25_RESTART 251 -#define X25_RESTART_CONFIRM 255 - -/* Restart cause field definitions. */ - -#define X25_RESTART_DTE_ORIGINATED 0 -#define X25_RESTART_LOCAL_PROCEDURE_ERROR 1 -#define X25_RESTART_NETWORK_CONGESTION 3 -#define X25_RESTART_NETWORK_OPERATIONAL 7 -#define X25_RESTART_DTE_ORIGINATED2 128 - - -/* Miscellaneous definitions. */ - -#define DATA_PACKET_DESIGNATOR 0x01 -#define RR_OR_RNR_PACKET_DESIGNATOR 0x02 -#define RR_PACKET_DESIGNATOR 0x04 - -#define DEFAULT_WINDOW_SIZE 2 -#define MODULUS 8 - -#define ADDRLN 1 -#define MAXADDRLN 15 -#define FACILITIESLN 1 -#define MAXFACILITIESLN 10 -#define MAXUSERDATA 16 -#define MAXCALLINFOLN 1+15+1+10+16 - -#define PACKET_OK 0 -#define IGNORE_PACKET 1 -#define ERROR_PACKET 2 - -typedef char bool; -#define FALSE 0 -#define TRUE 1 - -/* - * X.25 Packet format definitions - * This will eventually have to be rewritten without reference - * to bit fields, to be ansi C compliant and allignment safe. - */ - -typedef u_char octet; - -struct x25_calladdr { - octet addrlens; - octet address_field[MAXADDRLN]; -}; - -struct x25_packet { - octet bits; - octet logical_channel_number; - octet packet_type; - octet packet_data; -}; -#define packet_cause packet_data - -struct data_packet { - octet bits; -}; - -#define FACILITIES_REVERSE_CHARGE 0x1 -#define FACILITIES_THROUGHPUT 0x2 -#define FACILITIES_PACKETSIZE 0x42 -#define FACILITIES_WINDOWSIZE 0x43 - -#define PKHEADERLN 3 - -#define DP(xp) (((struct data_packet *)&(xp) -> packet_type) -> bits) -#define PS(xp) X25GBITS(DP(xp), p_s) -#define PR(xp) X25GBITS(DP(xp), p_r) -#define MBIT(xp) X25GBITS(DP(xp), m_bit) -#define SPR(xp, v) X25SBITS(DP(xp), p_r, (v)) -#define SPS(xp, v) X25SBITS(DP(xp), p_s, (v)) -#define SMBIT(xp, v) X25SBITS(DP(xp), m_bit, (v)) - -#define LCN(xp) (xp -> logical_channel_number + \ - (X25GBITS(xp -> bits, lc_group_number) ? (X25GBITS(xp -> bits, lc_group_number) << 8) : 0)) -#define SET_LCN(xp, lcn) ((xp -> logical_channel_number = lcn), \ - (X25SBITS(xp -> bits, lc_group_number, lcn > 255 ? lcn >> 8 : 0))) - -struct mbuf *pk_template (); - -/* Define X.25 packet level states. */ - -/* Call setup and clearing substates. */ - -#define LISTEN 0 -#define READY 1 -#define RECEIVED_CALL 2 -#define SENT_CALL 3 -#define DATA_TRANSFER 4 -#define RECEIVED_CLEAR 5 -#define SENT_CLEAR 6 - -/* DTE states. */ - -#define DTE_WAITING 7 -#define DTE_RECEIVED_RESTART 8 -#define DTE_SENT_RESTART 9 -#define DTE_READY 0 - -/* Cleaning out ... */ - -#define LCN_ZOMBIE 10 - -#define MAXSTATES 11 - -/* - * The following definitions are used in a switch statement after - * determining the packet type. These values are returned by the - * pk_decode procedure. - */ - -#define CALL 0 * MAXSTATES -#define CALL_ACCEPTED 1 * MAXSTATES -#define CLEAR 2 * MAXSTATES -#define CLEAR_CONF 3 * MAXSTATES -#define DATA 4 * MAXSTATES -#define INTERRUPT 5 * MAXSTATES -#define INTERRUPT_CONF 6 * MAXSTATES -#define RR 7 * MAXSTATES -#define RNR 8 * MAXSTATES -#define RESET 9 * MAXSTATES -#define RESET_CONF 10 * MAXSTATES -#define RESTART 11 * MAXSTATES -#define RESTART_CONF 12 * MAXSTATES -#define REJECT 13 * MAXSTATES -#define DIAG_TYPE 14 * MAXSTATES -#define INVALID_PACKET 15 * MAXSTATES -#define DELETE_PACKET INVALID_PACKET - -/* - * The following definitions are used by the restart procedures - * for noting wether the PLE is supposed to behave as DTE or DCE - * (essentially necessary for operation over LLC2) - */ -#define DTE_DXERESOLVING 0x0001 -#define DTE_PLAYDTE 0x0002 -#define DTE_PLAYDCE 0x0004 -#define DTE_CONNECTPENDING 0x0010 -#define DTE_PRETENDDTE 0x0020 - -#define MAXRESTARTCOLLISIONS 10 diff --git a/bsd/netccitt/pk_acct.c b/bsd/netccitt/pk_acct.c deleted file mode 100644 index c5aa584b3..000000000 --- a/bsd/netccitt/pk_acct.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) University of British Columbia, 1984 - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * the Laboratory for Computation Vision and the Computer Science Department - * of the University of British Columbia. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)pk_acct.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - - -struct vnode *pkacctp; -/* - * Turn on packet accounting - */ - -pk_accton (path) - char *path; -{ - register struct vnode *vp = NULL; - struct nameidata nd; - struct vnode *oacctp = pkacctp; - struct proc *p = current_proc(); - int error; - - if (path == 0) - goto close; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, p); - if (error = vn_open (&nd, FWRITE, 0644)) - return (error); - vp = nd.ni_vp; - VOP_UNLOCK(vp); - if (vp -> v_type != VREG) { - vrele (vp); - return (EACCES); - } - pkacctp = vp; - if (oacctp) { - close: - error = vn_close (oacctp, FWRITE, p -> p_ucred, p); - } - return (error); -} - -/* - * Write a record on the accounting file. - */ - -pk_acct (lcp) -register struct pklcd *lcp; -{ - register struct vnode *vp; - register struct sockaddr_x25 *sa; - register char *src, *dst; - register int len; - register long etime; - static struct x25acct acbuf; - - if ((vp = pkacctp) == 0) - return; - bzero ((caddr_t)&acbuf, sizeof (acbuf)); - if (lcp -> lcd_ceaddr != 0) - sa = lcp -> lcd_ceaddr; - else if (lcp -> lcd_craddr != 0) { - sa = lcp -> lcd_craddr; - acbuf.x25acct_callin = 1; - } else - return; - - if (sa -> x25_opts.op_flags & X25_REVERSE_CHARGE) - acbuf.x25acct_revcharge = 1; - acbuf.x25acct_stime = lcp -> lcd_stime; - acbuf.x25acct_etime = time.tv_sec - acbuf.x25acct_stime; - acbuf.x25acct_uid = current_proc() -> p_cred -> p_ruid; - acbuf.x25acct_psize = sa -> x25_opts.op_psize; - acbuf.x25acct_net = sa -> x25_net; - /* - * Convert address to bcd - */ - src = sa -> x25_addr; - dst = acbuf.x25acct_addr; - for (len = 0; *src; len++) - if (len & 01) - *dst++ |= *src++ & 0xf; - else - *dst = *src++ << 4; - acbuf.x25acct_addrlen = len; - - bcopy (sa -> x25_udata, acbuf.x25acct_udata, - sizeof (acbuf.x25acct_udata)); - acbuf.x25acct_txcnt = lcp -> lcd_txcnt; - acbuf.x25acct_rxcnt = lcp -> lcd_rxcnt; - - (void) vn_rdwr(UIO_WRITE, vp, (caddr_t)&acbuf, sizeof (acbuf), - (off_t)0, UIO_SYSSPACE, IO_UNIT|IO_APPEND, - current_proc() -> p_ucred, (int *)0, - (struct proc *)0); -} diff --git a/bsd/netccitt/pk_debug.c b/bsd/netccitt/pk_debug.c deleted file mode 100644 index 11f09bfd6..000000000 --- a/bsd/netccitt/pk_debug.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) University of British Columbia, 1984 - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * the Laboratory for Computation Vision and the Computer Science Department - * of the University of British Columbia. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)pk_debug.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -char *pk_state[] = { - "Listen", "Ready", "Received-Call", - "Sent-Call", "Data-Transfer","Received-Clear", - "Sent-Clear", -}; - -char *pk_name[] = { - "Call", "Call-Conf", "Clear", - "Clear-Conf", "Data", "Intr", "Intr-Conf", - "Rr", "Rnr", "Reset", "Reset-Conf", - "Restart", "Restart-Conf", "Reject", "Diagnostic", - "Invalid" -}; - -pk_trace (xcp, m, dir) -struct x25config *xcp; -register struct mbuf *m; -char *dir; -{ - register char *s; - struct x25_packet *xp = mtod(m, struct x25_packet *); - register int i, len = 0, cnt = 0; - - if (xcp -> xc_ptrace == 0) - return; - - i = pk_decode (xp) / MAXSTATES; - for (; m; m = m -> m_next) { - len = len + m -> m_len; - ++cnt; - } - printf ("LCN=%d %s: %s #=%d, len=%d ", - LCN(xp), dir, pk_name[i], cnt, len); - for (s = (char *) xp, i = 0; i < 5; ++i, ++s) - printf ("%x ", (int) * s & 0xff); - printf ("\n"); -} - -mbuf_cache(c, m) -register struct mbuf_cache *c; -struct mbuf *m; -{ - register struct mbuf **mp; - - if (c->mbc_size != c->mbc_oldsize) { - unsigned zero_size, copy_size; - unsigned new_size = c->mbc_size * sizeof(m); - caddr_t cache = (caddr_t)c->mbc_cache; - - if (new_size) { -// c->mbc_cache = (struct mbuf **) -// malloc(new_size, M_MBUF, M_NOWAIT); - MALLOC(c->mbc_cache, struct mbuf **, new_size, M_MBUF, M_NOWAIT); - if (c->mbc_cache == 0) { - c->mbc_cache = (struct mbuf **)cache; - return; - } - c->mbc_num %= c->mbc_size; - } else - c->mbc_cache = 0; - if (c->mbc_size < c->mbc_oldsize) { - register struct mbuf **mplim; - mp = c->mbc_size + (struct mbuf **)cache; - mplim = c->mbc_oldsize + (struct mbuf **)cache; - while (mp < mplim) - m_freem(*mp++); - zero_size = 0; - } else - zero_size = (c->mbc_size - c->mbc_oldsize) * sizeof(m); - copy_size = new_size - zero_size; - c->mbc_oldsize = c->mbc_size; - if (copy_size) - bcopy(cache, (caddr_t)c->mbc_cache, copy_size); - if (cache) - FREE(cache, M_MBUF); - if (zero_size) - bzero(copy_size + (caddr_t)c->mbc_cache, zero_size); - } - if (c->mbc_size == 0) - return; - mp = c->mbc_cache + c->mbc_num; - c->mbc_num = (1 + c->mbc_num) % c->mbc_size; - if (*mp) - m_freem(*mp); - if (*mp = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) - (*mp)->m_flags |= m->m_flags & 0x08; -} diff --git a/bsd/netccitt/pk_input.c b/bsd/netccitt/pk_input.c deleted file mode 100644 index 4cc5f27dd..000000000 --- a/bsd/netccitt/pk_input.c +++ /dev/null @@ -1,1145 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) University of British Columbia, 1984 - * Copyright (C) Computer Science Department IV, - * University of Erlangen-Nuremberg, Germany, 1992 - * Copyright (c) 1991, 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by the - * Laboratory for Computation Vision and the Computer Science Department - * of the the University of British Columbia and the Computer Science - * Department (IV) of the University of Erlangen-Nuremberg, Germany. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)pk_input.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -struct pkcb_q pkcb_q = {&pkcb_q, &pkcb_q}; - -/* - * ccittintr() is the generic interrupt handler for HDLC, LLC2, and X.25. This - * allows to have kernel running X.25 but no HDLC or LLC2 or both (in case we - * employ boards that do all the stuff themselves, e.g. ADAX X.25 or TPS ISDN.) - */ -void -ccittintr () -{ - extern struct ifqueue pkintrq; - extern struct ifqueue hdintrq; - extern struct ifqueue llcintrq; - -#if HDLC - if (hdintrq.ifq_len) - hdintr (); -#endif -#if LLC - if (llcintrq.ifq_len) - llcintr (); -#endif - if (pkintrq.ifq_len) - pkintr (); -} - -struct pkcb * -pk_newlink (ia, llnext) -struct x25_ifaddr *ia; -caddr_t llnext; -{ - register struct x25config *xcp = &ia -> ia_xc; - register struct pkcb *pkp; - register struct pklcd *lcp; - register struct protosw *pp; - unsigned size; - - pp = pffindproto (AF_CCITT, (int) xcp -> xc_lproto, 0); - if (pp == 0 || pp -> pr_output == 0) { - pk_message (0, xcp, "link level protosw error"); - return ((struct pkcb *)0); - } - /* - * Allocate a network control block structure - */ - size = sizeof (struct pkcb); -// pkp = (struct pkcb *) malloc (size, M_PCB, M_WAITOK); - MALLOC(pkp, struct pkcb *, size, M_PCB, M_WAITOK); - if (pkp == 0) - return ((struct pkcb *)0); - bzero ((caddr_t) pkp, size); - pkp -> pk_lloutput = pp -> pr_output; - pkp -> pk_llctlinput = (caddr_t (*)()) pp -> pr_ctlinput; - pkp -> pk_xcp = xcp; - pkp -> pk_ia = ia; - pkp -> pk_state = DTE_WAITING; - pkp -> pk_llnext = llnext; - insque (pkp, &pkcb_q); - - /* - * set defaults - */ - - if (xcp -> xc_pwsize == 0) - xcp -> xc_pwsize = DEFAULT_WINDOW_SIZE; - if (xcp -> xc_psize == 0) - xcp -> xc_psize = X25_PS128; - /* - * Allocate logical channel descriptor vector - */ - - (void) pk_resize (pkp); - return (pkp); -} - - -pk_dellink (pkp) -register struct pkcb *pkp; -{ - register int i; - register struct protosw *pp; - - /* - * Essentially we have the choice to - * (a) go ahead and let the route be deleted and - * leave the pkcb associated with that route - * as it is, i.e. the connections stay open - * (b) do a pk_disconnect() on all channels associated - * with the route via the pkcb and then proceed. - * - * For the time being we stick with (b) - */ - - for (i = 1; i < pkp -> pk_maxlcn; ++i) - if (pkp -> pk_chan[i]) - pk_disconnect (pkp -> pk_chan[i]); - - /* - * Free the pkcb - */ - - /* - * First find the protoswitch to get hold of the link level - * protocol to be notified that the packet level entity is - * dissolving ... - */ - pp = pffindproto (AF_CCITT, (int) pkp -> pk_xcp -> xc_lproto, 0); - if (pp == 0 || pp -> pr_output == 0) { - pk_message (0, pkp -> pk_xcp, "link level protosw error"); - return (EPROTONOSUPPORT); - } - - pkp -> pk_refcount--; - if (!pkp -> pk_refcount) { - struct dll_ctlinfo ctlinfo; - - remque (pkp); - if (pkp -> pk_rt -> rt_llinfo == (caddr_t) pkp) - pkp -> pk_rt -> rt_llinfo = (caddr_t) NULL; - - /* - * Tell the link level that the pkcb is dissolving - */ - if (pp -> pr_ctlinput && pkp -> pk_llnext) { - ctlinfo.dlcti_pcb = pkp -> pk_llnext; - ctlinfo.dlcti_rt = pkp -> pk_rt; - (pp -> pr_ctlinput)(PRC_DISCONNECT_REQUEST, - pkp -> pk_xcp, &ctlinfo); - } - FREE((caddr_t) pkp -> pk_chan, M_IFADDR); - FREE((caddr_t) pkp, M_PCB); - } - - return (0); -} - - -pk_resize (pkp) -register struct pkcb *pkp; -{ - struct pklcd *dev_lcp = 0; - struct x25config *xcp = pkp -> pk_xcp; - if (pkp -> pk_chan && - (pkp -> pk_maxlcn != xcp -> xc_maxlcn)) { - pk_restart (pkp, X25_RESTART_NETWORK_CONGESTION); - dev_lcp = pkp -> pk_chan[0]; - FREE((caddr_t) pkp -> pk_chan, M_IFADDR); - pkp -> pk_chan = 0; - } - if (pkp -> pk_chan == 0) { - unsigned size; - pkp -> pk_maxlcn = xcp -> xc_maxlcn; - size = (pkp -> pk_maxlcn + 1) * sizeof (struct pklcd *); -// pkp -> pk_chan = -// (struct pklcd **) malloc (size, M_IFADDR, M_WAITOK); - MALLOC(pkp->pk_chan, struct pklcd **, size, M_IFADDR, M_WAITOK); - if (pkp -> pk_chan) { - bzero ((caddr_t) pkp -> pk_chan, size); - /* - * Allocate a logical channel descriptor for lcn 0 - */ - if (dev_lcp == 0 && - (dev_lcp = pk_attach ((struct socket *)0)) == 0) - return (ENOBUFS); - dev_lcp -> lcd_state = READY; - dev_lcp -> lcd_pkp = pkp; - pkp -> pk_chan[0] = dev_lcp; - } else { - if (dev_lcp) - pk_close (dev_lcp); - return (ENOBUFS); - } - } - return 0; -} - -/* - * This procedure is called by the link level whenever the link - * becomes operational, is reset, or when the link goes down. - */ -/*VARARGS*/ -caddr_t -pk_ctlinput (code, src, addr) - int code; - struct sockaddr *src; - caddr_t addr; -{ - register struct pkcb *pkp = (struct pkcb *) addr; - - switch (code) { - case PRC_LINKUP: - if (pkp -> pk_state == DTE_WAITING) - pk_restart (pkp, X25_RESTART_NETWORK_CONGESTION); - break; - - case PRC_LINKDOWN: - pk_restart (pkp, -1); /* Clear all active circuits */ - pkp -> pk_state = DTE_WAITING; - break; - - case PRC_LINKRESET: - pk_restart (pkp, X25_RESTART_NETWORK_CONGESTION); - break; - - case PRC_CONNECT_INDICATION: { - struct rtentry *llrt; - - if ((llrt = rtalloc1(src, 0)) == 0) - return 0; - else llrt -> rt_refcnt--; - - pkp = (((struct npaidbentry *) llrt -> rt_llinfo) -> np_rt) ? - (struct pkcb *)(((struct npaidbentry *) llrt -> rt_llinfo) -> np_rt -> rt_llinfo) : (struct pkcb *) 0; - if (pkp == (struct pkcb *) 0) - return 0; - pkp -> pk_llnext = addr; - - return ((caddr_t) pkp); - } - case PRC_DISCONNECT_INDICATION: - pk_restart (pkp, -1) ; /* Clear all active circuits */ - pkp -> pk_state = DTE_WAITING; - pkp -> pk_llnext = (caddr_t) 0; - } - return (0); -} -struct ifqueue pkintrq; -/* - * This routine is called if there are semi-smart devices that do HDLC - * in hardware and want to queue the packet and call level 3 directly - */ -pkintr () -{ - register struct mbuf *m; - register struct ifaddr *ifa; - register struct ifnet *ifp; - register int s; - - for (;;) { - s = splimp (); - IF_DEQUEUE (&pkintrq, m); - splx (s); - if (m == 0) - break; - if (m -> m_len < PKHEADERLN) { - printf ("pkintr: packet too short (len=%d)\n", - m -> m_len); - m_freem (m); - continue; - } - pk_input (m); - } -} -struct mbuf *pk_bad_packet; -struct mbuf_cache pk_input_cache = {0 }; -/* - * X.25 PACKET INPUT - * - * This procedure is called by a link level procedure whenever - * an information frame is received. It decodes the packet and - * demultiplexes based on the logical channel number. - * - * We change the original conventions of the UBC code here -- - * since there may be multiple pkcb's for a given interface - * of type 802.2 class 2, we retrieve which one it is from - * m_pkthdr.rcvif (which has been overwritten by lower layers); - * That field is then restored for the benefit of upper layers which - * may make use of it, such as CLNP. - * - */ - -#define RESTART_DTE_ORIGINATED(xp) (((xp) -> packet_cause == X25_RESTART_DTE_ORIGINATED) || \ - ((xp) -> packet_cause >= X25_RESTART_DTE_ORIGINATED2)) - -pk_input (m) -register struct mbuf *m; -{ - register struct x25_packet *xp; - register struct pklcd *lcp; - register struct socket *so = 0; - register struct pkcb *pkp; - int ptype, lcn, lcdstate = LISTEN; - - if (pk_input_cache.mbc_size || pk_input_cache.mbc_oldsize) - mbuf_cache (&pk_input_cache, m); - if ((m -> m_flags & M_PKTHDR) == 0) - panic ("pkintr"); - - if ((pkp = (struct pkcb *) m -> m_pkthdr.rcvif) == 0) - return; - xp = mtod (m, struct x25_packet *); - ptype = pk_decode (xp); - lcn = LCN(xp); - lcp = pkp -> pk_chan[lcn]; - - /* - * If the DTE is in Restart state, then it will ignore data, - * interrupt, call setup and clearing, flow control and reset - * packets. - */ - if (lcn < 0 || lcn > pkp -> pk_maxlcn) { - pk_message (lcn, pkp -> pk_xcp, "illegal lcn"); - m_freem (m); - return; - } - - pk_trace (pkp -> pk_xcp, m, "P-In"); - - if (pkp -> pk_state != DTE_READY && ptype != RESTART && ptype != RESTART_CONF) { - m_freem (m); - return; - } - if (lcp) { - so = lcp -> lcd_so; - lcdstate = lcp -> lcd_state; - } else { - if (ptype == CLEAR) { /* idle line probe (Datapac specific) */ - /* send response on lcd 0's output queue */ - lcp = pkp -> pk_chan[0]; - lcp -> lcd_template = pk_template (lcn, X25_CLEAR_CONFIRM); - pk_output (lcp); - m_freem (m); - return; - } - if (ptype != CALL) - ptype = INVALID_PACKET; - } - - if (lcn == 0 && ptype != RESTART && ptype != RESTART_CONF) { - pk_message (0, pkp -> pk_xcp, "illegal ptype (%d, %s) on lcn 0", - ptype, pk_name[ptype / MAXSTATES]); - if (pk_bad_packet) - m_freem (pk_bad_packet); - pk_bad_packet = m; - return; - } - - m -> m_pkthdr.rcvif = pkp -> pk_ia -> ia_ifp; - - switch (ptype + lcdstate) { - /* - * Incoming Call packet received. - */ - case CALL + LISTEN: - pk_incoming_call (pkp, m); - break; - - /* - * Call collision: Just throw this "incoming call" away since - * the DCE will ignore it anyway. - */ - case CALL + SENT_CALL: - pk_message ((int) lcn, pkp -> pk_xcp, - "incoming call collision"); - break; - - /* - * Call confirmation packet received. This usually means our - * previous connect request is now complete. - */ - case CALL_ACCEPTED + SENT_CALL: - MCHTYPE(m, MT_CONTROL); - pk_call_accepted (lcp, m); - break; - - /* - * This condition can only happen if the previous state was - * SENT_CALL. Just ignore the packet, eventually a clear - * confirmation should arrive. - */ - case CALL_ACCEPTED + SENT_CLEAR: - break; - - /* - * Clear packet received. This requires a complete tear down - * of the virtual circuit. Free buffers and control blocks. - * and send a clear confirmation. - */ - case CLEAR + READY: - case CLEAR + RECEIVED_CALL: - case CLEAR + SENT_CALL: - case CLEAR + DATA_TRANSFER: - lcp -> lcd_state = RECEIVED_CLEAR; - lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CLEAR_CONFIRM); - pk_output (lcp); - pk_clearcause (pkp, xp); - if (lcp -> lcd_upper) { - MCHTYPE(m, MT_CONTROL); - lcp -> lcd_upper (lcp, m); - } - pk_close (lcp); - lcp = 0; - break; - - /* - * Clear collision: Treat this clear packet as a confirmation. - */ - case CLEAR + SENT_CLEAR: - pk_close (lcp); - break; - - /* - * Clear confirmation received. This usually means the virtual - * circuit is now completely removed. - */ - case CLEAR_CONF + SENT_CLEAR: - pk_close (lcp); - break; - - /* - * A clear confirmation on an unassigned logical channel - just - * ignore it. Note: All other packets on an unassigned channel - * results in a clear. - */ - case CLEAR_CONF + READY: - case CLEAR_CONF + LISTEN: - break; - - /* - * Data packet received. Pass on to next level. Move the Q and M - * bits into the data portion for the next level. - */ - case DATA + DATA_TRANSFER: - if (lcp -> lcd_reset_condition) { - ptype = DELETE_PACKET; - break; - } - - /* - * Process the P(S) flow control information in this Data packet. - * Check that the packets arrive in the correct sequence and that - * they are within the "lcd_input_window". Input window rotation is - * initiated by the receive interface. - */ - - if (PS(xp) != ((lcp -> lcd_rsn + 1) % MODULUS) || - PS(xp) == ((lcp -> lcd_input_window + lcp -> lcd_windowsize) % MODULUS)) { - m_freem (m); - pk_procerror (RESET, lcp, "p(s) flow control error", 1); - break; - } - lcp -> lcd_rsn = PS(xp); - - if (pk_ack (lcp, PR(xp)) != PACKET_OK) { - m_freem (m); - break; - } - m -> m_data += PKHEADERLN; - m -> m_len -= PKHEADERLN; - m -> m_pkthdr.len -= PKHEADERLN; - - lcp -> lcd_rxcnt++; - if (lcp -> lcd_flags & X25_MBS_HOLD) { - register struct mbuf *n = lcp -> lcd_cps; - int mbit = MBIT(xp); - octet q_and_d_bits; - - if (n) { - n -> m_pkthdr.len += m -> m_pkthdr.len; - while (n -> m_next) - n = n -> m_next; - n -> m_next = m; - m = lcp -> lcd_cps; - - if (lcp -> lcd_cpsmax && - n -> m_pkthdr.len > lcp -> lcd_cpsmax) { - pk_procerror (RESET, lcp, - "C.P.S. overflow", 128); - return; - } - q_and_d_bits = 0xc0 & *(octet *) xp; - xp = (struct x25_packet *) - (mtod (m, octet *) - PKHEADERLN); - *(octet *) xp |= q_and_d_bits; - } - if (mbit) { - lcp -> lcd_cps = m; - pk_flowcontrol (lcp, 0, 1); - return; - } - lcp -> lcd_cps = 0; - } - if (so == 0) - break; - if (lcp -> lcd_flags & X25_MQBIT) { - octet t = (X25GBITS(xp -> bits, q_bit)) ? t = 0x80 : 0; - - if (MBIT(xp)) - t |= 0x40; - m -> m_data -= 1; - m -> m_len += 1; - m -> m_pkthdr.len += 1; - *mtod (m, octet *) = t; - } - - /* - * Discard Q-BIT packets if the application - * doesn't want to be informed of M and Q bit status - */ - if (X25GBITS(xp -> bits, q_bit) - && (lcp -> lcd_flags & X25_MQBIT) == 0) { - m_freem (m); - /* - * NB. This is dangerous: sending a RR here can - * cause sequence number errors if a previous data - * packet has not yet been passed up to the application - * (RR's are normally generated via PRU_RCVD). - */ - pk_flowcontrol (lcp, 0, 1); - } else { - sbappendrecord (&so -> so_rcv, m); - sorwakeup (so); - } - break; - - /* - * Interrupt packet received. - */ - case INTERRUPT + DATA_TRANSFER: - if (lcp -> lcd_reset_condition) - break; - lcp -> lcd_intrdata = xp -> packet_data; - lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_INTERRUPT_CONFIRM); - pk_output (lcp); - m -> m_data += PKHEADERLN; - m -> m_len -= PKHEADERLN; - m -> m_pkthdr.len -= PKHEADERLN; - MCHTYPE(m, MT_OOBDATA); - if (so) { - if (so -> so_options & SO_OOBINLINE) - sbinsertoob (&so -> so_rcv, m); - else - m_freem (m); - sohasoutofband (so); - } - break; - - /* - * Interrupt confirmation packet received. - */ - case INTERRUPT_CONF + DATA_TRANSFER: - if (lcp -> lcd_reset_condition) - break; - if (lcp -> lcd_intrconf_pending == TRUE) - lcp -> lcd_intrconf_pending = FALSE; - else - pk_procerror (RESET, lcp, "unexpected packet", 43); - break; - - /* - * Receiver ready received. Rotate the output window and output - * any data packets waiting transmission. - */ - case RR + DATA_TRANSFER: - if (lcp -> lcd_reset_condition || - pk_ack (lcp, PR(xp)) != PACKET_OK) { - ptype = DELETE_PACKET; - break; - } - if (lcp -> lcd_rnr_condition == TRUE) - lcp -> lcd_rnr_condition = FALSE; - pk_output (lcp); - break; - - /* - * Receiver Not Ready received. Packets up to the P(R) can be - * be sent. Condition is cleared with a RR. - */ - case RNR + DATA_TRANSFER: - if (lcp -> lcd_reset_condition || - pk_ack (lcp, PR(xp)) != PACKET_OK) { - ptype = DELETE_PACKET; - break; - } - lcp -> lcd_rnr_condition = TRUE; - break; - - /* - * Reset packet received. Set state to FLOW_OPEN. The Input and - * Output window edges ar set to zero. Both the send and receive - * numbers are reset. A confirmation is returned. - */ - case RESET + DATA_TRANSFER: - if (lcp -> lcd_reset_condition) - /* Reset collision. Just ignore packet. */ - break; - - pk_resetcause (pkp, xp); - lcp -> lcd_window_condition = lcp -> lcd_rnr_condition = - lcp -> lcd_intrconf_pending = FALSE; - lcp -> lcd_output_window = lcp -> lcd_input_window = - lcp -> lcd_last_transmitted_pr = 0; - lcp -> lcd_ssn = 0; - lcp -> lcd_rsn = MODULUS - 1; - - lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESET_CONFIRM); - pk_output (lcp); - - pk_flush (lcp); - if (so == 0) - break; - wakeup ((caddr_t) & so -> so_timeo); - sorwakeup (so); - sowwakeup (so); - break; - - /* - * Reset confirmation received. - */ - case RESET_CONF + DATA_TRANSFER: - if (lcp -> lcd_reset_condition) { - lcp -> lcd_reset_condition = FALSE; - pk_output (lcp); - } - else - pk_procerror (RESET, lcp, "unexpected packet", 32); - break; - - case DATA + SENT_CLEAR: - ptype = DELETE_PACKET; - case RR + SENT_CLEAR: - case RNR + SENT_CLEAR: - case INTERRUPT + SENT_CLEAR: - case INTERRUPT_CONF + SENT_CLEAR: - case RESET + SENT_CLEAR: - case RESET_CONF + SENT_CLEAR: - /* Just ignore p if we have sent a CLEAR already. - */ - break; - - /* - * Restart sets all the permanent virtual circuits to the "Data - * Transfer" stae and all the switched virtual circuits to the - * "Ready" state. - */ - case RESTART + READY: - switch (pkp -> pk_state) { - case DTE_SENT_RESTART: - /* - * Restart collision. - * If case the restart cause is "DTE originated" we - * have a DTE-DTE situation and are trying to resolve - * who is going to play DTE/DCE [ISO 8208:4.2-4.5] - */ - if (RESTART_DTE_ORIGINATED(xp)) { - pk_restart (pkp, X25_RESTART_DTE_ORIGINATED); - pk_message (0, pkp -> pk_xcp, - "RESTART collision"); - if ((pkp -> pk_restartcolls++) > MAXRESTARTCOLLISIONS) { - pk_message (0, pkp -> pk_xcp, - "excessive RESTART collisions"); - pkp -> pk_restartcolls = 0; - } - break; - } - pkp -> pk_state = DTE_READY; - pkp -> pk_dxerole |= DTE_PLAYDTE; - pkp -> pk_dxerole &= ~DTE_PLAYDCE; - pk_message (0, pkp -> pk_xcp, - "Packet level operational"); - pk_message (0, pkp -> pk_xcp, - "Assuming DTE role"); - if (pkp -> pk_dxerole & DTE_CONNECTPENDING) - pk_callcomplete (pkp); - break; - - default: - pk_restart (pkp, -1); - pk_restartcause (pkp, xp); - pkp -> pk_chan[0] -> lcd_template = pk_template (0, - X25_RESTART_CONFIRM); - pk_output (pkp -> pk_chan[0]); - pkp -> pk_state = DTE_READY; - pkp -> pk_dxerole |= RESTART_DTE_ORIGINATED(xp) ? DTE_PLAYDCE : - DTE_PLAYDTE; - if (pkp -> pk_dxerole & DTE_PLAYDTE) { - pkp -> pk_dxerole &= ~DTE_PLAYDCE; - pk_message (0, pkp -> pk_xcp, - "Assuming DTE role"); - } else { - pkp -> pk_dxerole &= ~DTE_PLAYDTE; - pk_message (0, pkp -> pk_xcp, - "Assuming DCE role"); - } - if (pkp -> pk_dxerole & DTE_CONNECTPENDING) - pk_callcomplete (pkp); - } - break; - - /* - * Restart confirmation received. All logical channels are set - * to READY. - */ - case RESTART_CONF + READY: - switch (pkp -> pk_state) { - case DTE_SENT_RESTART: - pkp -> pk_state = DTE_READY; - pkp -> pk_dxerole |= DTE_PLAYDTE; - pkp -> pk_dxerole &= ~DTE_PLAYDCE; - pk_message (0, pkp -> pk_xcp, - "Packet level operational"); - pk_message (0, pkp -> pk_xcp, - "Assuming DTE role"); - if (pkp -> pk_dxerole & DTE_CONNECTPENDING) - pk_callcomplete (pkp); - break; - - default: - /* Restart local procedure error. */ - pk_restart (pkp, X25_RESTART_LOCAL_PROCEDURE_ERROR); - pkp -> pk_state = DTE_SENT_RESTART; - pkp -> pk_dxerole &= ~(DTE_PLAYDTE | DTE_PLAYDCE); - } - break; - - default: - if (lcp) { - pk_procerror (CLEAR, lcp, "unknown packet error", 33); - pk_message (lcn, pkp -> pk_xcp, - "\"%s\" unexpected in \"%s\" state", - pk_name[ptype/MAXSTATES], pk_state[lcdstate]); - } else - pk_message (lcn, pkp -> pk_xcp, - "packet arrived on unassigned lcn"); - break; - } - if (so == 0 && lcp && lcp -> lcd_upper && lcdstate == DATA_TRANSFER) { - if (ptype != DATA && ptype != INTERRUPT) - MCHTYPE(m, MT_CONTROL); - lcp -> lcd_upper (lcp, m); - } else if (ptype != DATA && ptype != INTERRUPT) - m_freem (m); -} - -static -prune_dnic (from, to, dnicname, xcp) -char *from, *to, *dnicname; -register struct x25config *xcp; -{ - register char *cp1 = from, *cp2 = from; - if (xcp -> xc_prepnd0 && *cp1 == '0') { - from = ++cp1; - goto copyrest; - } - if (xcp -> xc_nodnic) { - for (cp1 = dnicname; *cp2 = *cp1++;) - cp2++; - cp1 = from; - } -copyrest: - for (cp1 = dnicname; *cp2 = *cp1++;) - cp2++; -} -/* static */ -pk_simple_bsd (from, to, lower, len) -register octet *from, *to; -register len, lower; -{ - register int c; - while (--len >= 0) { - c = *from; - if (lower & 0x01) - *from++; - else - c >>= 4; - c &= 0x0f; c |= 0x30; *to++ = c; lower++; - } - *to = 0; -} - -/*static octet * */ -pk_from_bcd (a, iscalling, sa, xcp) -register struct x25_calladdr *a; -int iscalling; -register struct sockaddr_x25 *sa; -register struct x25config *xcp; -{ - octet buf[MAXADDRLN+1]; - octet *cp; - unsigned count; - - bzero ((caddr_t) sa, sizeof (*sa)); - sa -> x25_len = sizeof (*sa); - sa -> x25_family = AF_CCITT; - if (iscalling) { - cp = a -> address_field + (X25GBITS(a -> addrlens, called_addrlen) / 2); - count = X25GBITS(a -> addrlens, calling_addrlen); - pk_simple_bsd (cp, buf, X25GBITS(a -> addrlens, called_addrlen), count); - } else { - count = X25GBITS(a -> addrlens, called_addrlen); - pk_simple_bsd (a -> address_field, buf, 0, count); - } - if (xcp -> xc_addr.x25_net && (xcp -> xc_nodnic || xcp -> xc_prepnd0)) { - octet dnicname[sizeof (long) * NBBY/3 + 2]; - - sprintf ((char *) dnicname, "%d", xcp -> xc_addr.x25_net); - prune_dnic ((char *) buf, sa -> x25_addr, dnicname, xcp); - } else - bcopy ((caddr_t) buf, (caddr_t) sa -> x25_addr, count + 1); -} - -static -save_extra (m0, fp, so) -struct mbuf *m0; -octet *fp; -struct socket *so; -{ - register struct mbuf *m; - struct cmsghdr cmsghdr; - if (m = m_copy (m, 0, (int)M_COPYALL)) { - int off = fp - mtod (m0, octet *); - int len = m -> m_pkthdr.len - off + sizeof (cmsghdr); - cmsghdr.cmsg_len = len; - cmsghdr.cmsg_level = AF_CCITT; - cmsghdr.cmsg_type = PK_FACILITIES; - m_adj (m, off); - M_PREPEND (m, sizeof (cmsghdr), M_DONTWAIT); - if (m == 0) - return; - bcopy ((caddr_t)&cmsghdr, mtod (m, caddr_t), sizeof (cmsghdr)); - MCHTYPE(m, MT_CONTROL); - sbappendrecord (&so -> so_rcv, m); - } -} - -/* - * This routine handles incoming call packets. It matches the protocol - * field on the Call User Data field (usually the first four bytes) with - * sockets awaiting connections. - */ - -pk_incoming_call (pkp, m0) -struct mbuf *m0; -struct pkcb *pkp; -{ - register struct pklcd *lcp = 0, *l; - register struct sockaddr_x25 *sa; - register struct x25_calladdr *a; - register struct socket *so = 0; - struct x25_packet *xp = mtod (m0, struct x25_packet *); - struct mbuf *m; - struct x25config *xcp = pkp -> pk_xcp; - int len = m0 -> m_pkthdr.len; - int udlen; - char *errstr = "server unavailable"; - octet *u, *facp; - int lcn = LCN(xp); - - /* First, copy the data from the incoming call packet to a X25 address - descriptor. It is to be regretted that you have - to parse the facilities into a sockaddr to determine - if reverse charging is being requested */ - if ((m = m_get (M_DONTWAIT, MT_SONAME)) == 0) - return; - sa = mtod (m, struct sockaddr_x25 *); - a = (struct x25_calladdr *) &xp -> packet_data; - facp = u = (octet *) (a -> address_field + - ((X25GBITS(a -> addrlens, called_addrlen) + X25GBITS(a -> addrlens, calling_addrlen) + 1) / 2)); - u += *u + 1; - udlen = min (16, ((octet *) xp) + len - u); - if (udlen < 0) - udlen = 0; - pk_from_bcd (a, 1, sa, pkp -> pk_xcp); /* get calling address */ - pk_parse_facilities (facp, sa); - bcopy ((caddr_t) u, sa -> x25_udata, udlen); - sa -> x25_udlen = udlen; - - /* - * Now, loop through the listen sockets looking for a match on the - * PID. That is the first few octets of the user data field. - * This is the closest thing to a port number for X.25 packets. - * It does provide a way of multiplexing services at the user level. - */ - - for (l = pk_listenhead; l; l = l -> lcd_listen) { - struct sockaddr_x25 *sxp = l -> lcd_ceaddr; - - if (bcmp (sxp -> x25_udata, u, sxp -> x25_udlen)) - continue; - if (sxp -> x25_net && - sxp -> x25_net != xcp -> xc_addr.x25_net) - continue; - /* - * don't accept incoming calls with the D-Bit on - * unless the server agrees - */ - if (X25GBITS(xp -> bits, d_bit) && !(sxp -> x25_opts.op_flags & X25_DBIT)) { - errstr = "incoming D-Bit mismatch"; - break; - } - /* - * don't accept incoming collect calls unless - * the server sets the reverse charging option. - */ - if ((sxp -> x25_opts.op_flags & (X25_OLDSOCKADDR|X25_REVERSE_CHARGE)) == 0 && - sa -> x25_opts.op_flags & X25_REVERSE_CHARGE) { - errstr = "incoming collect call refused"; - break; - } - if (l -> lcd_so) { - if (so = sonewconn (l -> lcd_so, SS_ISCONNECTED)) - lcp = (struct pklcd *) so -> so_pcb; - } else - lcp = pk_attach ((struct socket *) 0); - if (lcp == 0) { - /* - * Insufficient space or too many unaccepted - * connections. Just throw the call away. - */ - errstr = "server malfunction"; - break; - } - lcp -> lcd_upper = l -> lcd_upper; - lcp -> lcd_upnext = l -> lcd_upnext; - lcp -> lcd_lcn = lcn; - lcp -> lcd_state = RECEIVED_CALL; - sa -> x25_opts.op_flags |= (sxp -> x25_opts.op_flags & - ~X25_REVERSE_CHARGE) | l -> lcd_flags; - pk_assoc (pkp, lcp, sa); - lcp -> lcd_faddr = *sa; - lcp -> lcd_laddr.x25_udlen = sxp -> x25_udlen; - lcp -> lcd_craddr = &lcp -> lcd_faddr; - lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CALL_ACCEPTED); - if (lcp -> lcd_flags & X25_DBIT) { - if (X25GBITS(xp -> bits, d_bit)) - X25SBITS(mtod (lcp -> lcd_template, - struct x25_packet *) -> bits, d_bit, 1); - else - lcp -> lcd_flags &= ~X25_DBIT; - } - if (so) { - pk_output (lcp); - soisconnected (so); - if (so -> so_options & SO_OOBINLINE) - save_extra (m0, facp, so); - } else if (lcp -> lcd_upper) { - (*lcp -> lcd_upper) (lcp, m0); - } - (void) m_free (m); - return; - } - - /* - * If the call fails for whatever reason, we still need to build a - * skeleton LCD in order to be able to properly receive the CLEAR - * CONFIRMATION. - */ -#ifdef WATERLOO /* be explicit */ - if (l == 0 && bcmp (sa -> x25_udata, "ean", 3) == 0) - pk_message (lcn, pkp -> pk_xcp, "host=%s ean%c: %s", - sa -> x25_addr, sa -> x25_udata[3] & 0xff, errstr); - else if (l == 0 && bcmp (sa -> x25_udata, "\1\0\0\0", 4) == 0) - pk_message (lcn, pkp -> pk_xcp, "host=%s x29d: %s", - sa -> x25_addr, errstr); - else -#endif - pk_message (lcn, pkp -> pk_xcp, "host=%s pid=%x %x %x %x: %s", - sa -> x25_addr, sa -> x25_udata[0] & 0xff, - sa -> x25_udata[1] & 0xff, sa -> x25_udata[2] & 0xff, - sa -> x25_udata[3] & 0xff, errstr); - if ((lcp = pk_attach ((struct socket *)0)) == 0) { - (void) m_free (m); - return; - } - lcp -> lcd_lcn = lcn; - lcp -> lcd_state = RECEIVED_CALL; - pk_assoc (pkp, lcp, sa); - (void) m_free (m); - pk_clear (lcp, 0, 1); -} - -pk_call_accepted (lcp, m) -struct pklcd *lcp; -struct mbuf *m; -{ - register struct x25_calladdr *ap; - register octet *fcp; - struct x25_packet *xp = mtod (m, struct x25_packet *); - int len = m -> m_len; - - lcp -> lcd_state = DATA_TRANSFER; - if (lcp -> lcd_so) - soisconnected (lcp -> lcd_so); - if ((lcp -> lcd_flags & X25_DBIT) && (X25GBITS(xp -> bits, d_bit) == 0)) - lcp -> lcd_flags &= ~X25_DBIT; - if (len > 3) { - ap = (struct x25_calladdr *) &xp -> packet_data; - fcp = (octet *) ap -> address_field + (X25GBITS(ap -> addrlens, calling_addrlen) + - X25GBITS(ap -> addrlens, called_addrlen) + 1) / 2; - if (fcp + *fcp <= ((octet *) xp) + len) - pk_parse_facilities (fcp, lcp -> lcd_ceaddr); - } - pk_assoc (lcp -> lcd_pkp, lcp, lcp -> lcd_ceaddr); - if (lcp -> lcd_so == 0 && lcp -> lcd_upper) - lcp -> lcd_upper (lcp, m); -} - -pk_parse_facilities (fcp, sa) -register octet *fcp; -register struct sockaddr_x25 *sa; -{ - register octet *maxfcp; - - maxfcp = fcp + *fcp; - fcp++; - while (fcp < maxfcp) { - /* - * Ignore national DCE or DTE facilities - */ - if (*fcp == 0 || *fcp == 0xff) - break; - switch (*fcp) { - case FACILITIES_WINDOWSIZE: - sa -> x25_opts.op_wsize = fcp[1]; - fcp += 3; - break; - - case FACILITIES_PACKETSIZE: - sa -> x25_opts.op_psize = fcp[1]; - fcp += 3; - break; - - case FACILITIES_THROUGHPUT: - sa -> x25_opts.op_speed = fcp[1]; - fcp += 2; - break; - - case FACILITIES_REVERSE_CHARGE: - if (fcp[1] & 01) - sa -> x25_opts.op_flags |= X25_REVERSE_CHARGE; - /* - * Datapac specific: for a X.25(1976) DTE, bit 2 - * indicates a "hi priority" (eg. international) call. - */ - if (fcp[1] & 02 && sa -> x25_opts.op_psize == 0) - sa -> x25_opts.op_psize = X25_PS128; - fcp += 2; - break; - - default: -/*printf("unknown facility %x, class=%d\n", *fcp, (*fcp & 0xc0) >> 6);*/ - switch ((*fcp & 0xc0) >> 6) { - case 0: /* class A */ - fcp += 2; - break; - - case 1: - fcp += 3; - break; - - case 2: - fcp += 4; - break; - - case 3: - fcp++; - fcp += *fcp; - } - } - } -} diff --git a/bsd/netccitt/pk_llcsubr.c b/bsd/netccitt/pk_llcsubr.c deleted file mode 100644 index 54fd65e71..000000000 --- a/bsd/netccitt/pk_llcsubr.c +++ /dev/null @@ -1,392 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (C) Dirk Husemann, Computer Science Department IV, - * University of Erlangen-Nuremberg, Germany, 1990, 1991, 1992 - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Dirk Husemann and the Computer Science Department (IV) of - * the University of Erlangen-Nuremberg, Germany. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)pk_llcsubr.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - - -/* - * Routing support for X.25 - * - * We distinguish between two cases: - * RTF_HOST: - * rt_key(rt) X.25 address of host - * rt_gateway SNPA (MAC+DLSAP) address of host - * rt_llinfo pkcb for rt_key(rt) - * - * RTF_GATEWAY - * rt_key(rt) X.25 address of host or suitably masked network - * rt_gateway X.25 address of next X.25 gateway (switch) - * rt_llinfo rtentry for rt_gateway address - * ought to be of type RTF_HOST - * - * - * Mapping of X.121 to pkcbs: - * - * HDLC uses the DTE-DCE model of X.25, therefore we need a many-to-one - * relationship, i.e.: - * - * {X.121_a, X.121_b, X.121_c, ..., X.121_i} -> pkcb_0 - * - * LLC2 utilizes the DTE-DTE model of X.25, resulting effectively in a - * one-to-one relationship, i.e.: - * - * {X.121_j} -> pkcb_1a - * {X.121_k} -> pkcb_1b - * ... - * {X.121_q} -> pkcb_1q - * - * It might make sense to allow a many-to-one relation for LLC2 also, - * - * {X.121_r, X.121_s, X.121_t, X.121_u} -> pkcb_2a - * - * This would make addresses X.121_[r-u] essentially aliases of one - * address ({X.121_[r-u]} would constitute a representative set). - * - * Each one-to-one relation must obviously be entered individually with - * a route add command, whereas a many-to-one relationship can be - * either entered individually or generated by using a netmask. - * - * To facilitate dealings the many-to-one case for LLC2 can only be - * established via a netmask. - * - */ - -#define XTRACTPKP(rt) ((rt)->rt_flags & RTF_GATEWAY ? \ - ((rt)->rt_llinfo ? \ - (struct pkcb *) ((struct rtentry *)((rt)->rt_llinfo))->rt_llinfo : \ - (struct pkcb *) NULL) : \ - (struct pkcb *)((rt)->rt_llinfo)) - -#define equal(a1, a2) (bcmp((caddr_t)(a1), \ - (caddr_t)(a2), \ - (a1)->sa_len) == 0) -#define XIFA(rt) ((struct x25_ifaddr *)((rt)->rt_ifa)) -#define SA(s) ((struct sockaddr *)s) - -int -cons_rtrequest(int cmd, struct rtentry *rt, struct sockaddr *dst) -{ - register struct pkcb *pkp; - register int i; - register char one_to_one; - struct pkcb *pk_newlink(); - struct rtentry *npaidb_enter(); - - pkp = XTRACTPKP(rt); - - switch(cmd) { - case RTM_RESOLVE: - case RTM_ADD: - if (pkp) - return(EEXIST); - - if (rt->rt_flags & RTF_GATEWAY) { - if (rt->rt_llinfo) - RTFREE((struct rtentry *)rt->rt_llinfo); - rt->rt_llinfo = (caddr_t) rtalloc1(rt->rt_gateway, 1); - return(0); - } - /* - * Assumptions: (1) ifnet structure is filled in - * (2) at least the pkcb created via - * x25config (ifconfig?) has been - * set up already. - * (3) HDLC interfaces have an if_type of - * IFT_X25{,DDN}, LLC2 interfaces - * anything else (any better way to - * do this?) - * - */ - if (!rt->rt_ifa) - return (ENETDOWN); - - /* - * We differentiate between dealing with a many-to-one - * (HDLC: DTE-DCE) and a one-to-one (LLC2: DTE-DTE) - * relationship (by looking at the if type). - * - * Only in case of the many-to-one relationship (HDLC) - * we set the ia->ia_pkcb pointer to the pkcb allocated - * via pk_newlink() as we will use just that one pkcb for - * future route additions (the rtentry->rt_llinfo pointer - * points to the pkcb allocated for that route). - * - * In case of the one-to-one relationship (LLC2) we - * create a new pkcb (via pk_newlink()) for each new rtentry. - * - * NOTE: Only in case of HDLC does ia->ia_pkcb point - * to a pkcb, in the LLC2 case it doesn't (as we don't - * need it here)! - */ - one_to_one = ISISO8802(rt->rt_ifp); - - if (!(pkp = XIFA(rt)->ia_pkcb) && !one_to_one) - XIFA(rt)->ia_pkcb = pkp = - pk_newlink(XIFA(rt), (caddr_t) 0); - else if (one_to_one && - !equal(rt->rt_gateway, rt->rt_ifa->ifa_addr)) { - pkp = pk_newlink(XIFA(rt), (caddr_t) 0); - /* - * We also need another route entry for mapping - * MAC+LSAP->X.25 address - */ - pkp->pk_llrt = npaidb_enter(rt->rt_gateway, rt_key(rt), rt, 0); - } - if (pkp) { - if (!pkp->pk_rt) - pkp->pk_rt = rt; - pkp->pk_refcount++; - } - rt->rt_llinfo = (caddr_t) pkp; - - return(0); - - case RTM_DELETE: - { - /* - * The pkp might be empty if we are dealing - * with an interface route entry for LLC2, in this - * case we don't need to do anything ... - */ - if (pkp) { - if ( rt->rt_flags & RTF_GATEWAY ) { - if (rt->rt_llinfo) - RTFREE((struct rtentry *)rt->rt_llinfo); - return(0); - } - - if (pkp->pk_llrt) - npaidb_destroy(pkp->pk_llrt); - - pk_dellink (pkp); - - return(0); - } - } - } -} - -/* - * Network Protocol Addressing Information DataBase (npaidb) - * - * To speed up locating the entity dealing with an LLC packet use is made - * of a routing tree. This npaidb routing tree is handled - * by the normal rn_*() routines just like (almost) any other routing tree. - * - * The mapping being done by the npaidb_*() routines is as follows: - * - * Key: MAC,LSAP (enhancing struct sockaddr_dl) - * Gateway: sockaddr_x25 (i.e. X.25 address - X.121 or NSAP) - * Llinfo: npaidbentry { - * struct llc_linkcb *npaidb_linkp; - * struct rtentry *npaidb_rt; - * } - * - * Using the npaidbentry provided by llinfo we can then access - * - * o the pkcb by using (struct pkcb *) (npaidb_rt->rt_llinfo) - * o the linkcb via npaidb_linkp - * - * The following functions are provided - * - * o npaidb_enter(struct sockaddr_dl *sdl, struct sockaddr_x25 *sx25, - * struct struct llc_linkcb *link, struct rtentry *rt) - * - * o npaidb_enrich(short type, caddr_t info) - * - */ - -struct sockaddr_dl npdl_netmask = { - sizeof(struct sockaddr_dl), /* _len */ - 0, /* _family */ - 0, /* _index */ - 0, /* _type */ - -1, /* _nlen */ - -1, /* _alen */ - -1, /* _slen */ - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* _data */ -}; -struct sockaddr npdl_dummy; - -int npdl_datasize = sizeof(struct sockaddr_dl)- - ((int)((caddr_t)&((struct sockaddr_dl *)0)->sdl_data[0])); - -struct rtentry * -npaidb_enter(struct sockaddr_dl *key, struct sockaddr *value, - struct rtentry *rt, struct llc_linkcb *link) -{ - struct rtentry *nprt; register int i; - - USES_AF_LINK_RTS; - - if ((nprt = rtalloc1(SA(key), 0)) == 0) { - register u_int size = sizeof(struct npaidbentry); - register u_char saploc = LLSAPLOC(key, rt->rt_ifp); - - /* - * set up netmask: LLC2 packets have the lowest bit set in - * response packets (e.g. 0x7e for command packets, 0x7f for - * response packets), to facilitate the lookup we use a netmask - * of 11111110 for the SAP position. The remaining positions - * are zeroed out. - */ - npdl_netmask.sdl_data[saploc] = NPDL_SAPNETMASK; - bzero((caddr_t)&npdl_netmask.sdl_data[saploc+1], - npdl_datasize-saploc-1); - - if (value == 0) - value = &npdl_dummy; - - /* now enter it */ - rtrequest(RTM_ADD, SA(key), SA(value), - SA(&npdl_netmask), 0, &nprt); - - /* and reset npdl_netmask */ - for (i = saploc; i < npdl_datasize; i++) - npdl_netmask.sdl_data[i] = -1; - -// nprt->rt_llinfo = malloc(size , M_PCB, M_WAITOK); - MALLOC(nprt->rt_llinfo, caddr_t, size , M_PCB, M_WAITOK); - if (nprt->rt_llinfo) { - bzero (nprt->rt_llinfo, size); - ((struct npaidbentry *) (nprt->rt_llinfo))->np_rt = rt; - } - } else nprt->rt_refcnt--; - return nprt; -} - -struct rtentry * -npaidb_enrich(short type, caddr_t info, struct sockaddr_dl *sdl) -{ - struct rtentry *rt; - - USES_AF_LINK_RTS; - - if (rt = rtalloc1((struct sockaddr *)sdl, 0)) { - rt->rt_refcnt--; - switch (type) { - case NPAIDB_LINK: - ((struct npaidbentry *)(rt->rt_llinfo))->np_link = - (struct llc_linkcb *) info; - break; - } - return rt; - } - - return ((struct rtentry *) 0); - -} - -npaidb_destroy(struct rtentry *rt) -{ - USES_AF_LINK_RTS; - - if (rt->rt_llinfo) - FREE((caddr_t) rt->rt_llinfo, M_PCB); - return(rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt), - 0, 0)); -} - - -#if LLC -/* - * Glue between X.25 and LLC2 - */ -int -x25_llcglue(int prc, struct sockaddr *addr) -{ - register struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)addr; - register struct x25_ifaddr *x25ifa; - struct dll_ctlinfo ctlinfo; - - if((x25ifa = (struct x25_ifaddr *)ifa_ifwithaddr(addr)) == 0) - return 0; - - ctlinfo.dlcti_cfg = - (struct dllconfig *)(((struct sockaddr_x25 *)(&x25ifa->ia_xc))+1); - ctlinfo.dlcti_lsap = LLC_X25_LSAP; - - return ((int)llc_ctlinput(prc, addr, (caddr_t)&ctlinfo)); -} -#endif /* LLC */ diff --git a/bsd/netccitt/pk_output.c b/bsd/netccitt/pk_output.c deleted file mode 100644 index 2fa3124fe..000000000 --- a/bsd/netccitt/pk_output.c +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) University of British Columbia, 1984 - * Copyright (C) Computer Science Department IV, - * University of Erlangen-Nuremberg, Germany, 1992 - * Copyright (c) 1991, 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by the - * Laboratory for Computation Vision and the Computer Science Department - * of the the University of British Columbia and the Computer Science - * Department (IV) of the University of Erlangen-Nuremberg, Germany. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)pk_output.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -struct mbuf_cache pk_output_cache = {0 }, pk_input_cache; -struct mbuf *nextpk (); - -pk_output (lcp) -register struct pklcd *lcp; -{ - register struct x25_packet *xp; - register struct mbuf *m; - register struct pkcb *pkp = lcp -> lcd_pkp; - - if (lcp == 0 || pkp == 0) { - printf ("pk_output: zero arg\n"); - return; - } - - while ((m = nextpk (lcp)) != NULL) { - xp = mtod (m, struct x25_packet *); - - switch (pk_decode (xp) + lcp -> lcd_state) { - /* - * All the work is already done - just set the state and - * pass to peer. - */ - case CALL + READY: - lcp -> lcd_state = SENT_CALL; - lcp -> lcd_timer = pk_t21; - break; - - /* - * Just set the state to allow packet to flow and send the - * confirmation. - */ - case CALL_ACCEPTED + RECEIVED_CALL: - lcp -> lcd_state = DATA_TRANSFER; - break; - - /* - * Just set the state. Keep the LCD around till the clear - * confirmation is returned. - */ - case CLEAR + RECEIVED_CALL: - case CLEAR + SENT_CALL: - case CLEAR + DATA_TRANSFER: - lcp -> lcd_state = SENT_CLEAR; - lcp -> lcd_retry = 0; - /* fall through */ - - case CLEAR + SENT_CLEAR: - lcp -> lcd_timer = pk_t23; - lcp -> lcd_retry++; - break; - - case CLEAR_CONF + RECEIVED_CLEAR: - case CLEAR_CONF + SENT_CLEAR: - case CLEAR_CONF + READY: - lcp -> lcd_state = READY; - break; - - case DATA + DATA_TRANSFER: - SPS(xp, lcp -> lcd_ssn); - lcp -> lcd_input_window = - (lcp -> lcd_rsn + 1) % MODULUS; - SPR(xp, lcp -> lcd_input_window); - lcp -> lcd_last_transmitted_pr = lcp -> lcd_input_window; - lcp -> lcd_ssn = (lcp -> lcd_ssn + 1) % MODULUS; - if (lcp -> lcd_ssn == ((lcp -> lcd_output_window + lcp -> lcd_windowsize) % MODULUS)) - lcp -> lcd_window_condition = TRUE; - break; - - case INTERRUPT + DATA_TRANSFER: -#ifdef ancient_history - xp -> packet_data = 0; -#endif - lcp -> lcd_intrconf_pending = TRUE; - break; - - case INTERRUPT_CONF + DATA_TRANSFER: - break; - - case RR + DATA_TRANSFER: - case RNR + DATA_TRANSFER: - lcp -> lcd_input_window = - (lcp -> lcd_rsn + 1) % MODULUS; - SPR(xp, lcp -> lcd_input_window); - lcp -> lcd_last_transmitted_pr = lcp -> lcd_input_window; - break; - - case RESET + DATA_TRANSFER: - lcp -> lcd_reset_condition = TRUE; - break; - - case RESET_CONF + DATA_TRANSFER: - lcp -> lcd_reset_condition = FALSE; - break; - - /* - * A restart should be only generated internally. Therefore - * all logic for restart is in the pk_restart routine. - */ - case RESTART + READY: - lcp -> lcd_timer = pk_t20; - break; - - /* - * Restarts are all handled internally. Therefore all the - * logic for the incoming restart packet is handled in the - * pk_input routine. - */ - case RESTART_CONF + READY: - break; - - default: - m_freem (m); - return; - } - - /* Trace the packet. */ - pk_trace (pkp -> pk_xcp, m, "P-Out"); - - /* Pass the packet on down to the link layer */ - if (pk_input_cache.mbc_size || pk_input_cache.mbc_oldsize) { - m->m_flags |= 0x08; - mbuf_cache(&pk_input_cache, m); - } - (*pkp -> pk_lloutput) (pkp -> pk_llnext, m, pkp -> pk_rt); - } -} - -/* - * This procedure returns the next packet to send or null. A - * packet is composed of one or more mbufs. - */ - -struct mbuf * -nextpk (lcp) -struct pklcd *lcp; -{ - register struct mbuf *m, *n; - struct socket *so = lcp -> lcd_so; - register struct sockbuf *sb = & (so ? so -> so_snd : lcp -> lcd_sb); - - if (lcp -> lcd_template) { - m = lcp -> lcd_template; - lcp -> lcd_template = NULL; - } else { - if (lcp -> lcd_rnr_condition || lcp -> lcd_window_condition || - lcp -> lcd_reset_condition) - return (NULL); - - if ((m = sb -> sb_mb) == 0) - return (NULL); - - sb -> sb_mb = m -> m_nextpkt; - m->m_act = 0; - for (n = m; n; n = n -> m_next) - sbfree (sb, n); - } - return (m); -} diff --git a/bsd/netccitt/pk_subr.c b/bsd/netccitt/pk_subr.c deleted file mode 100644 index cb6cec959..000000000 --- a/bsd/netccitt/pk_subr.c +++ /dev/null @@ -1,1214 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) University of British Columbia, 1984 - * Copyright (C) Computer Science Department IV, - * University of Erlangen-Nuremberg, Germany, 1992 - * Copyright (c) 1991, 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by the - * Laboratory for Computation Vision and the Computer Science Department - * of the the University of British Columbia and the Computer Science - * Department (IV) of the University of Erlangen-Nuremberg, Germany. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)pk_subr.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -int pk_sendspace = 1024 * 2 + 8; -int pk_recvspace = 1024 * 2 + 8; - -struct pklcd_q pklcd_q = {&pklcd_q, &pklcd_q}; - -struct x25bitslice x25_bitslice[] = { -/* mask, shift value */ - { 0xf0, 0x4 }, - { 0xf, 0x0 }, - { 0x80, 0x7 }, - { 0x40, 0x6 }, - { 0x30, 0x4 }, - { 0xe0, 0x5 }, - { 0x10, 0x4 }, - { 0xe, 0x1 }, - { 0x1, 0x0 } -}; - - -/* - * Attach X.25 protocol to socket, allocate logical channel descripter - * and buffer space, and enter LISTEN state if we are to accept - * IN-COMMING CALL packets. - * - */ - -struct pklcd * -pk_attach (so) -struct socket *so; -{ - register struct pklcd *lcp; - register int error = ENOBUFS; - int pk_output (); - - MALLOC(lcp, struct pklcd *, sizeof (*lcp), M_PCB, M_NOWAIT); - if (lcp) { - bzero ((caddr_t)lcp, sizeof (*lcp)); - insque (&lcp -> lcd_q, &pklcd_q); - lcp -> lcd_state = READY; - lcp -> lcd_send = pk_output; - if (so) { - error = soreserve (so, pk_sendspace, pk_recvspace); - lcp -> lcd_so = so; - if (so -> so_options & SO_ACCEPTCONN) - lcp -> lcd_state = LISTEN; - } else - sbreserve (&lcp -> lcd_sb, pk_sendspace); - } - if (so) { - so -> so_pcb = (caddr_t) lcp; - so -> so_error = error; - } - return (lcp); -} - -/* - * Disconnect X.25 protocol from socket. - */ - -pk_disconnect (lcp) -register struct pklcd *lcp; -{ - register struct socket *so = lcp -> lcd_so; - register struct pklcd *l, *p; - - switch (lcp -> lcd_state) { - case LISTEN: - for (p = 0, l = pk_listenhead; l && l != lcp; p = l, l = l -> lcd_listen); - if (p == 0) { - if (l != 0) - pk_listenhead = l -> lcd_listen; - } - else - if (l != 0) - p -> lcd_listen = l -> lcd_listen; - pk_close (lcp); - break; - - case READY: - pk_acct (lcp); - pk_close (lcp); - break; - - case SENT_CLEAR: - case RECEIVED_CLEAR: - break; - - default: - pk_acct (lcp); - if (so) { - soisdisconnecting (so); - sbflush (&so -> so_rcv); - } - pk_clear (lcp, 241, 0); /* Normal Disconnect */ - - } -} - -/* - * Close an X.25 Logical Channel. Discard all space held by the - * connection and internal descriptors. Wake up any sleepers. - */ - -pk_close (lcp) -struct pklcd *lcp; -{ - register struct socket *so = lcp -> lcd_so; - - /* - * If the X.25 connection is torn down due to link - * level failure (e.g. LLC2 FRMR) and at the same the user - * level is still filling up the socket send buffer that - * send buffer is locked. An attempt to sbflush () that send - * buffer will lead us into - no, not temptation but - panic! - * So - we'll just check wether the send buffer is locked - * and if that's the case we'll mark the lcp as zombie and - * have the pk_timer () do the cleaning ... - */ - - if (so && so -> so_snd.sb_flags & SB_LOCK) - lcp -> lcd_state = LCN_ZOMBIE; - else - pk_freelcd (lcp); - - if (so == NULL) - return; - - so -> so_pcb = 0; - soisdisconnected (so); - /* sofree (so); /* gak!!! you can't do that here */ -} - -/* - * Create a template to be used to send X.25 packets on a logical - * channel. It allocates an mbuf and fills in a skeletal packet - * depending on its type. This packet is passed to pk_output where - * the remainer of the packet is filled in. -*/ - -struct mbuf * -pk_template (lcn, type) -int lcn, type; -{ - register struct mbuf *m; - register struct x25_packet *xp; - - MGETHDR (m, M_DONTWAIT, MT_HEADER); - if (m == 0) - panic ("pk_template"); - m -> m_act = 0; - - /* - * Efficiency hack: leave a four byte gap at the beginning - * of the packet level header with the hope that this will - * be enough room for the link level to insert its header. - */ - m -> m_data += max_linkhdr; - m -> m_pkthdr.len = m -> m_len = PKHEADERLN; - - xp = mtod (m, struct x25_packet *); - *(long *)xp = 0; /* ugly, but fast */ -/* xp -> q_bit = 0;*/ - X25SBITS(xp -> bits, fmt_identifier, 1); -/* xp -> lc_group_number = 0;*/ - - SET_LCN(xp, lcn); - xp -> packet_type = type; - - return (m); -} - -/* - * This routine restarts all the virtual circuits. Actually, - * the virtual circuits are not "restarted" as such. Instead, - * any active switched circuit is simply returned to READY - * state. - */ - -pk_restart (pkp, restart_cause) -register struct pkcb *pkp; -int restart_cause; -{ - register struct mbuf *m; - register struct pklcd *lcp; - register int i; - - /* Restart all logical channels. */ - if (pkp -> pk_chan == 0) - return; - - /* - * Don't do this if we're doing a restart issued from - * inside pk_connect () --- which is only done if and - * only if the X.25 link is down, i.e. a RESTART needs - * to be done to get it up. - */ - if (!(pkp -> pk_dxerole & DTE_CONNECTPENDING)) { - for (i = 1; i <= pkp -> pk_maxlcn; ++i) - if ((lcp = pkp -> pk_chan[i]) != NULL) { - if (lcp -> lcd_so) { - lcp -> lcd_so -> so_error = ENETRESET; - pk_close (lcp); - } else { - pk_flush (lcp); - lcp -> lcd_state = READY; - if (lcp -> lcd_upper) - lcp -> lcd_upper (lcp, 0); - } - } - } - - if (restart_cause < 0) - return; - - pkp -> pk_state = DTE_SENT_RESTART; - pkp -> pk_dxerole &= ~(DTE_PLAYDCE | DTE_PLAYDTE); - lcp = pkp -> pk_chan[0]; - m = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESTART); - m -> m_pkthdr.len = m -> m_len += 2; - mtod (m, struct x25_packet *) -> packet_data = 0; /* DTE only */ - mtod (m, octet *)[4] = restart_cause; - pk_output (lcp); -} - - -/* - * This procedure frees up the Logical Channel Descripter. - */ - -pk_freelcd (lcp) -register struct pklcd *lcp; -{ - if (lcp == NULL) - return; - - if (lcp -> lcd_lcn > 0) - lcp -> lcd_pkp -> pk_chan[lcp -> lcd_lcn] = NULL; - - pk_flush (lcp); - remque (&lcp -> lcd_q); - FREE((caddr_t)lcp, M_PCB); -} - -static struct x25_ifaddr * -pk_ifwithaddr (sx) - struct sockaddr_x25 *sx; -{ - struct ifnet *ifp; - struct ifaddr *ifa; - register struct x25_ifaddr *ia; - char *addr = sx -> x25_addr; - - 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_CCITT) { - ia = (struct x25_ifaddr *)ifa; - if (bcmp (addr, ia -> ia_xc.xc_addr.x25_addr, - 16) == 0) - return (ia); - - } - return ((struct x25_ifaddr *)0); -} - - -/* - * Bind a address and protocol value to a socket. The important - * part is the protocol value - the first four characters of the - * Call User Data field. - */ - -#define XTRACTPKP(rt) ((rt) -> rt_flags & RTF_GATEWAY ? \ - ((rt) -> rt_llinfo ? \ - (struct pkcb *) ((struct rtentry *)((rt) -> rt_llinfo)) -> rt_llinfo : \ - (struct pkcb *) NULL) : \ - (struct pkcb *)((rt) -> rt_llinfo)) - -pk_bind (lcp, nam) -struct pklcd *lcp; -struct mbuf *nam; -{ - register struct pklcd *pp; - register struct sockaddr_x25 *sa; - - if (nam == NULL) - return (EADDRNOTAVAIL); - if (lcp -> lcd_ceaddr) /* XXX */ - return (EADDRINUSE); - if (pk_checksockaddr (nam)) - return (EINVAL); - sa = mtod (nam, struct sockaddr_x25 *); - - /* - * If the user wishes to accept calls only from a particular - * net (net != 0), make sure the net is known - */ - - if (sa -> x25_addr[0]) { - if (!pk_ifwithaddr (sa)) - return (ENETUNREACH); - } else if (sa -> x25_net) { - if (!ifa_ifwithnet ((struct sockaddr *)sa)) - return (ENETUNREACH); - } - - /* - * For ISO's sake permit default listeners, but only one such . . . - */ - for (pp = pk_listenhead; pp; pp = pp -> lcd_listen) { - register struct sockaddr_x25 *sa2 = pp -> lcd_ceaddr; - if ((sa2 -> x25_udlen == sa -> x25_udlen) && - (sa2 -> x25_udlen == 0 || - (bcmp (sa2 -> x25_udata, sa -> x25_udata, - min (sa2 -> x25_udlen, sa -> x25_udlen)) == 0))) - return (EADDRINUSE); - } - lcp -> lcd_laddr = *sa; - lcp -> lcd_ceaddr = &lcp -> lcd_laddr; - return (0); -} - -/* - * Include a bound control block in the list of listeners. - */ -pk_listen (lcp) -register struct pklcd *lcp; -{ - register struct pklcd **pp; - - if (lcp -> lcd_ceaddr == 0) - return (EDESTADDRREQ); - - lcp -> lcd_state = LISTEN; - /* - * Add default listener at end, any others at start. - */ - if (lcp -> lcd_ceaddr -> x25_udlen == 0) { - for (pp = &pk_listenhead; *pp; ) - pp = &((*pp) -> lcd_listen); - *pp = lcp; - } else { - lcp -> lcd_listen = pk_listenhead; - pk_listenhead = lcp; - } - return (0); -} -/* - * Include a listening control block for the benefit of other protocols. - */ -pk_protolisten (spi, spilen, callee) -int (*callee) (); -{ - register struct pklcd *lcp = pk_attach ((struct socket *)0); - register struct mbuf *nam; - register struct sockaddr_x25 *sa; - int error = ENOBUFS; - - if (lcp) { - if (nam = m_getclr (MT_SONAME, M_DONTWAIT)) { - sa = mtod (nam, struct sockaddr_x25 *); - sa -> x25_family = AF_CCITT; - sa -> x25_len = nam -> m_len = sizeof (*sa); - sa -> x25_udlen = spilen; - sa -> x25_udata[0] = spi; - lcp -> lcd_upper = callee; - lcp -> lcd_flags = X25_MBS_HOLD; - if ((error = pk_bind (lcp, nam)) == 0) - error = pk_listen (lcp); - (void) m_free (nam); - } - if (error) - pk_freelcd (lcp); - } - return error; /* Hopefully Zero !*/ -} - -/* - * Associate a logical channel descriptor with a network. - * Fill in the default network specific parameters and then - * set any parameters explicitly specified by the user or - * by the remote DTE. - */ - -pk_assoc (pkp, lcp, sa) -register struct pkcb *pkp; -register struct pklcd *lcp; -register struct sockaddr_x25 *sa; -{ - - lcp -> lcd_pkp = pkp; - lcp -> lcd_packetsize = pkp -> pk_xcp -> xc_psize; - lcp -> lcd_windowsize = pkp -> pk_xcp -> xc_pwsize; - lcp -> lcd_rsn = MODULUS - 1; - pkp -> pk_chan[lcp -> lcd_lcn] = lcp; - - if (sa -> x25_opts.op_psize) - lcp -> lcd_packetsize = sa -> x25_opts.op_psize; - else - sa -> x25_opts.op_psize = lcp -> lcd_packetsize; - if (sa -> x25_opts.op_wsize) - lcp -> lcd_windowsize = sa -> x25_opts.op_wsize; - else - sa -> x25_opts.op_wsize = lcp -> lcd_windowsize; - sa -> x25_net = pkp -> pk_xcp -> xc_addr.x25_net; - lcp -> lcd_flags |= sa -> x25_opts.op_flags; - lcp -> lcd_stime = time.tv_sec; -} - -pk_connect (lcp, sa) -register struct pklcd *lcp; -register struct sockaddr_x25 *sa; -{ - register struct pkcb *pkp; - register struct rtentry *rt; - register struct rtentry *nrt; - - struct rtentry *npaidb_enter (); - struct pkcb *pk_newlink (); - - if (sa -> x25_addr[0] == '\0') - return (EDESTADDRREQ); - - /* - * Is the destination address known? - */ - if (!(rt = rtalloc1 ((struct sockaddr *)sa, 1))) - return (ENETUNREACH); - - if (!(pkp = XTRACTPKP(rt))) - pkp = pk_newlink ((struct x25_ifaddr *) (rt -> rt_ifa), - (caddr_t) 0); - - /* - * Have we entered the LLC address? - */ - if (nrt = npaidb_enter (rt -> rt_gateway, rt_key (rt), rt, 0)) - pkp -> pk_llrt = nrt; - - /* - * Have we allocated an LLC2 link yet? - */ - if (pkp -> pk_llnext == (caddr_t)0 && pkp -> pk_llctlinput) { - struct dll_ctlinfo ctlinfo; - - ctlinfo.dlcti_rt = rt; - ctlinfo.dlcti_pcb = (caddr_t) pkp; - ctlinfo.dlcti_conf = - (struct dllconfig *) (&((struct x25_ifaddr *)(rt -> rt_ifa)) -> ia_xc); - pkp -> pk_llnext = - (pkp -> pk_llctlinput) (PRC_CONNECT_REQUEST, 0, &ctlinfo); - } - - if (pkp -> pk_state != DTE_READY && pkp -> pk_state != DTE_WAITING) - return (ENETDOWN); - if ((lcp -> lcd_lcn = pk_getlcn (pkp)) == 0) - return (EMFILE); - - lcp -> lcd_faddr = *sa; - lcp -> lcd_ceaddr = & lcp -> lcd_faddr; - pk_assoc (pkp, lcp, lcp -> lcd_ceaddr); - - /* - * If the link is not up yet, initiate an X.25 RESTART - */ - if (pkp -> pk_state == DTE_WAITING) { - pkp -> pk_dxerole |= DTE_CONNECTPENDING; - pk_ctlinput (PRC_LINKUP, (struct sockaddr *)0, pkp); - if (lcp -> lcd_so) - soisconnecting (lcp -> lcd_so); - return 0; - } - - if (lcp -> lcd_so) - soisconnecting (lcp -> lcd_so); - lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CALL); - pk_callrequest (lcp, lcp -> lcd_ceaddr, pkp -> pk_xcp); - return (*pkp -> pk_ia -> ia_start) (lcp); -} - -/* - * Complete all pending X.25 call requests --- this gets called after - * the X.25 link has been restarted. - */ -#define RESHUFFLELCN(maxlcn, lcn) ((maxlcn) - (lcn) + 1) - -pk_callcomplete (pkp) - register struct pkcb *pkp; -{ - register struct pklcd *lcp; - register int i; - register int ni; - - - if (pkp -> pk_dxerole & DTE_CONNECTPENDING) - pkp -> pk_dxerole &= ~DTE_CONNECTPENDING; - else return; - - if (pkp -> pk_chan == 0) - return; - - /* - * We pretended to be a DTE for allocating lcns, if - * it turns out that we are in reality performing as a - * DCE we need to reshuffle the lcps. - * - * /+---------------+-------- - - * / | a (maxlcn-1) | \ - * / +---------------+ \ - * +--- * | b (maxlcn-2) | \ - * | \ +---------------+ \ - * r | \ | c (maxlcn-3) | \ - * e | \+---------------+ | - * s | | . | - * h | | . | m - * u | | . | a - * f | | . | x - * f | | . | l - * l | /+---------------+ | c - * e | / | c' ( 3 ) | | n - * | / +---------------+ | - * +--> * | b' ( 2 ) | / - * \ +---------------+ / - * \ | a' ( 1 ) | / - * \+---------------+ / - * | 0 | / - * +---------------+-------- - - * - */ - if (pkp -> pk_dxerole & DTE_PLAYDCE) { - /* Sigh, reshuffle it */ - for (i = pkp -> pk_maxlcn; i > 0; --i) - if (pkp -> pk_chan[i]) { - ni = RESHUFFLELCN(pkp -> pk_maxlcn, i); - pkp -> pk_chan[ni] = pkp -> pk_chan[i]; - pkp -> pk_chan[i] = NULL; - pkp -> pk_chan[ni] -> lcd_lcn = ni; - } - } - - for (i = 1; i <= pkp -> pk_maxlcn; ++i) - if ((lcp = pkp -> pk_chan[i]) != NULL) { - /* if (lcp -> lcd_so) - soisconnecting (lcp -> lcd_so); */ - lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CALL); - pk_callrequest (lcp, lcp -> lcd_ceaddr, pkp -> pk_xcp); - (*pkp -> pk_ia -> ia_start) (lcp); - } -} - -struct bcdinfo { - octet *cp; - unsigned posn; -}; -/* - * Build the rest of the CALL REQUEST packet. Fill in calling - * address, facilities fields and the user data field. - */ - -pk_callrequest (lcp, sa, xcp) -struct pklcd *lcp; -register struct sockaddr_x25 *sa; -register struct x25config *xcp; -{ - register struct x25_calladdr *a; - register struct mbuf *m = lcp -> lcd_template; - register struct x25_packet *xp = mtod (m, struct x25_packet *); - struct bcdinfo b; - - if (lcp -> lcd_flags & X25_DBIT) - X25SBITS(xp -> bits, d_bit, 1); - a = (struct x25_calladdr *) &xp -> packet_data; - b.cp = (octet *) a -> address_field; - b.posn = 0; - X25SBITS(a -> addrlens, called_addrlen, to_bcd (&b, sa, xcp)); - X25SBITS(a -> addrlens, calling_addrlen, to_bcd (&b, &xcp -> xc_addr, xcp)); - if (b.posn & 0x01) - *b.cp++ &= 0xf0; - m -> m_pkthdr.len = m -> m_len += b.cp - (octet *) a; - - if (lcp -> lcd_facilities) { - m -> m_pkthdr.len += - (m -> m_next = lcp -> lcd_facilities) -> m_pkthdr.len; - lcp -> lcd_facilities = 0; - } else - pk_build_facilities (m, sa, (int)xcp -> xc_type); - - m_copyback (m, m -> m_pkthdr.len, sa -> x25_udlen, sa -> x25_udata); -} - -pk_build_facilities (m, sa, type) -register struct mbuf *m; -struct sockaddr_x25 *sa; -{ - register octet *cp; - register octet *fcp; - register int revcharge; - - cp = mtod (m, octet *) + m -> m_len; - fcp = cp + 1; - revcharge = sa -> x25_opts.op_flags & X25_REVERSE_CHARGE ? 1 : 0; - /* - * This is specific to Datapac X.25(1976) DTEs. International - * calls must have the "hi priority" bit on. - */ - if (type == X25_1976 && sa -> x25_opts.op_psize == X25_PS128) - revcharge |= 02; - if (revcharge) { - *fcp++ = FACILITIES_REVERSE_CHARGE; - *fcp++ = revcharge; - } - switch (type) { - case X25_1980: - case X25_1984: - *fcp++ = FACILITIES_PACKETSIZE; - *fcp++ = sa -> x25_opts.op_psize; - *fcp++ = sa -> x25_opts.op_psize; - - *fcp++ = FACILITIES_WINDOWSIZE; - *fcp++ = sa -> x25_opts.op_wsize; - *fcp++ = sa -> x25_opts.op_wsize; - } - *cp = fcp - cp - 1; - m -> m_pkthdr.len = (m -> m_len += *cp + 1); -} - -to_bcd (b, sa, xcp) -register struct bcdinfo *b; -struct sockaddr_x25 *sa; -register struct x25config *xcp; -{ - register char *x = sa -> x25_addr; - unsigned start = b -> posn; - /* - * The nodnic and prepnd0 stuff looks tedious, - * but it does allow full X.121 addresses to be used, - * which is handy for routing info (& OSI type 37 addresses). - */ - if (xcp -> xc_addr.x25_net && (xcp -> xc_nodnic || xcp -> xc_prepnd0)) { - char dnicname[sizeof (long) * NBBY/3 + 2]; - register char *p = dnicname; - - sprintf (p, "%d", xcp -> xc_addr.x25_net & 0x7fff); - for (; *p; p++) /* *p == 0 means dnic matched */ - if ((*p ^ *x++) & 0x0f) - break; - if (*p || xcp -> xc_nodnic == 0) - x = sa -> x25_addr; - if (*p && xcp -> xc_prepnd0) { - if ((b -> posn)++ & 0x01) - *(b -> cp)++; - else - *(b -> cp) = 0; - } - } - while (*x) - if ((b -> posn)++ & 0x01) - *(b -> cp)++ |= *x++ & 0x0F; - else - *(b -> cp) = *x++ << 4; - return ((b -> posn) - start); -} - -/* - * This routine gets the first available logical channel number. The - * search is - * - from the highest number to lowest number if playing DTE, and - * - from lowest to highest number if playing DCE. - */ - -pk_getlcn (pkp) -register struct pkcb *pkp; -{ - register int i; - - if (pkp -> pk_chan == 0) - return (0); - if ( pkp -> pk_dxerole & DTE_PLAYDCE ) { - for (i = 1; i <= pkp -> pk_maxlcn; ++i) - if (pkp -> pk_chan[i] == NULL) - break; - } else { - for (i = pkp -> pk_maxlcn; i > 0; --i) - if (pkp -> pk_chan[i] == NULL) - break; - } - i = ( i > pkp -> pk_maxlcn ? 0 : i ); - return (i); -} - -/* - * This procedure sends a CLEAR request packet. The lc state is - * set to "SENT_CLEAR". - */ - -pk_clear (lcp, diagnostic, abortive) -register struct pklcd *lcp; -{ - register struct mbuf *m = pk_template (lcp -> lcd_lcn, X25_CLEAR); - - m -> m_len += 2; - m -> m_pkthdr.len += 2; - mtod (m, struct x25_packet *) -> packet_data = 0; - mtod (m, octet *)[4] = diagnostic; - if (lcp -> lcd_facilities) { - m -> m_next = lcp -> lcd_facilities; - m -> m_pkthdr.len += m -> m_next -> m_len; - lcp -> lcd_facilities = 0; - } - if (abortive) - lcp -> lcd_template = m; - else { - struct socket *so = lcp -> lcd_so; - struct sockbuf *sb = so ? & so -> so_snd : & lcp -> lcd_sb; - sbappendrecord (sb, m); - } - pk_output (lcp); - -} - -/* - * This procedure generates RNR's or RR's to inhibit or enable - * inward data flow, if the current state changes (blocked ==> open or - * vice versa), or if forced to generate one. One forces RNR's to ack data. - */ -pk_flowcontrol (lcp, inhibit, forced) -register struct pklcd *lcp; -{ - inhibit = (inhibit != 0); - if (lcp == 0 || lcp -> lcd_state != DATA_TRANSFER || - (forced == 0 && lcp -> lcd_rxrnr_condition == inhibit)) - return; - lcp -> lcd_rxrnr_condition = inhibit; - lcp -> lcd_template = - pk_template (lcp -> lcd_lcn, inhibit ? X25_RNR : X25_RR); - pk_output (lcp); -} - -/* - * This procedure sends a RESET request packet. It re-intializes - * virtual circuit. - */ - -static -pk_reset (lcp, diagnostic) -register struct pklcd *lcp; -{ - register struct mbuf *m; - register struct socket *so = lcp -> lcd_so; - - if (lcp -> lcd_state != DATA_TRANSFER) - return; - - if (so) - so -> so_error = ECONNRESET; - lcp -> lcd_reset_condition = TRUE; - - /* Reset all the control variables for the channel. */ - pk_flush (lcp); - lcp -> lcd_window_condition = lcp -> lcd_rnr_condition = - lcp -> lcd_intrconf_pending = FALSE; - lcp -> lcd_rsn = MODULUS - 1; - lcp -> lcd_ssn = 0; - lcp -> lcd_output_window = lcp -> lcd_input_window = - lcp -> lcd_last_transmitted_pr = 0; - m = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESET); - m -> m_pkthdr.len = m -> m_len += 2; - mtod (m, struct x25_packet *) -> packet_data = 0; - mtod (m, octet *)[4] = diagnostic; - pk_output (lcp); - -} - -/* - * This procedure frees all data queued for output or delivery on a - * virtual circuit. - */ - -pk_flush (lcp) -register struct pklcd *lcp; -{ - register struct socket *so; - - if (lcp -> lcd_template) - m_freem (lcp -> lcd_template); - - if (lcp -> lcd_cps) { - m_freem (lcp -> lcd_cps); - lcp -> lcd_cps = 0; - } - if (lcp -> lcd_facilities) { - m_freem (lcp -> lcd_facilities); - lcp -> lcd_facilities = 0; - } - if (so = lcp -> lcd_so) - sbflush (&so -> so_snd); - else - sbflush (&lcp -> lcd_sb); -} - -/* - * This procedure handles all local protocol procedure errors. - */ - -pk_procerror (error, lcp, errstr, diagnostic) -register struct pklcd *lcp; -char *errstr; -{ - - pk_message (lcp -> lcd_lcn, lcp -> lcd_pkp -> pk_xcp, errstr); - - switch (error) { - case CLEAR: - if (lcp -> lcd_so) { - lcp -> lcd_so -> so_error = ECONNABORTED; - soisdisconnecting (lcp -> lcd_so); - } - pk_clear (lcp, diagnostic, 1); - break; - - case RESET: - pk_reset (lcp, diagnostic); - } -} - -/* - * This procedure is called during the DATA TRANSFER state to check - * and process the P(R) values received in the DATA, RR OR RNR - * packets. - */ - -pk_ack (lcp, pr) -struct pklcd *lcp; -unsigned pr; -{ - register struct socket *so = lcp -> lcd_so; - - if (lcp -> lcd_output_window == pr) - return (PACKET_OK); - if (lcp -> lcd_output_window < lcp -> lcd_ssn) { - if (pr < lcp -> lcd_output_window || pr > lcp -> lcd_ssn) { - pk_procerror (RESET, lcp, - "p(r) flow control error", 2); - return (ERROR_PACKET); - } - } - else { - if (pr < lcp -> lcd_output_window && pr > lcp -> lcd_ssn) { - pk_procerror (RESET, lcp, - "p(r) flow control error #2", 2); - return (ERROR_PACKET); - } - } - - lcp -> lcd_output_window = pr; /* Rotate window. */ - if (lcp -> lcd_window_condition == TRUE) - lcp -> lcd_window_condition = FALSE; - - if (so && ((so -> so_snd.sb_flags & SB_WAIT) || - (so -> so_snd.sb_flags & SB_NOTIFY))) - sowwakeup (so); - - return (PACKET_OK); -} - -/* - * This procedure decodes the X.25 level 3 packet returning a - * code to be used in switchs or arrays. - */ - -pk_decode (xp) -register struct x25_packet *xp; -{ - register int type; - - if (X25GBITS(xp -> bits, fmt_identifier) != 1) - return (INVALID_PACKET); -#ifdef ancient_history - /* - * Make sure that the logical channel group number is 0. - * This restriction may be removed at some later date. - */ - if (xp -> lc_group_number != 0) - return (INVALID_PACKET); -#endif - /* - * Test for data packet first. - */ - if (!(xp -> packet_type & DATA_PACKET_DESIGNATOR)) - return (DATA); - - /* - * Test if flow control packet (RR or RNR). - */ - if (!(xp -> packet_type & RR_OR_RNR_PACKET_DESIGNATOR)) - switch (xp -> packet_type & 0x1f) { - case X25_RR: - return (RR); - case X25_RNR: - return (RNR); - case X25_REJECT: - return (REJECT); - } - - /* - * Determine the rest of the packet types. - */ - switch (xp -> packet_type) { - case X25_CALL: - type = CALL; - break; - - case X25_CALL_ACCEPTED: - type = CALL_ACCEPTED; - break; - - case X25_CLEAR: - type = CLEAR; - break; - - case X25_CLEAR_CONFIRM: - type = CLEAR_CONF; - break; - - case X25_INTERRUPT: - type = INTERRUPT; - break; - - case X25_INTERRUPT_CONFIRM: - type = INTERRUPT_CONF; - break; - - case X25_RESET: - type = RESET; - break; - - case X25_RESET_CONFIRM: - type = RESET_CONF; - break; - - case X25_RESTART: - type = RESTART; - break; - - case X25_RESTART_CONFIRM: - type = RESTART_CONF; - break; - - case X25_DIAGNOSTIC: - type = DIAG_TYPE; - break; - - default: - type = INVALID_PACKET; - } - return (type); -} - -/* - * A restart packet has been received. Print out the reason - * for the restart. - */ - -pk_restartcause (pkp, xp) -struct pkcb *pkp; -register struct x25_packet *xp; -{ - register struct x25config *xcp = pkp -> pk_xcp; - register int lcn = LCN(xp); - - switch (xp -> packet_data) { - case X25_RESTART_LOCAL_PROCEDURE_ERROR: - pk_message (lcn, xcp, "restart: local procedure error"); - break; - - case X25_RESTART_NETWORK_CONGESTION: - pk_message (lcn, xcp, "restart: network congestion"); - break; - - case X25_RESTART_NETWORK_OPERATIONAL: - pk_message (lcn, xcp, "restart: network operational"); - break; - - default: - pk_message (lcn, xcp, "restart: unknown cause"); - } -} - -#define MAXRESETCAUSE 7 - -int Reset_cause[] = { - EXRESET, EXROUT, 0, EXRRPE, 0, EXRLPE, 0, EXRNCG -}; - -/* - * A reset packet has arrived. Return the cause to the user. - */ - -pk_resetcause (pkp, xp) -struct pkcb *pkp; -register struct x25_packet *xp; -{ - register struct pklcd *lcp = - pkp -> pk_chan[LCN(xp)]; - register int code = xp -> packet_data; - - if (code > MAXRESETCAUSE) - code = 7; /* EXRNCG */ - - pk_message (LCN(xp), lcp -> lcd_pkp, "reset code 0x%x, diagnostic 0x%x", - xp -> packet_data, 4[(u_char *)xp]); - - if (lcp -> lcd_so) - lcp -> lcd_so -> so_error = Reset_cause[code]; -} - -#define MAXCLEARCAUSE 25 - -int Clear_cause[] = { - EXCLEAR, EXCBUSY, 0, EXCINV, 0, EXCNCG, 0, - 0, 0, EXCOUT, 0, EXCAB, 0, EXCNOB, 0, 0, 0, EXCRPE, - 0, EXCLPE, 0, 0, 0, 0, 0, EXCRRC -}; - -/* - * A clear packet has arrived. Return the cause to the user. - */ - -pk_clearcause (pkp, xp) -struct pkcb *pkp; -register struct x25_packet *xp; -{ - register struct pklcd *lcp = - pkp -> pk_chan[LCN(xp)]; - register int code = xp -> packet_data; - - if (code > MAXCLEARCAUSE) - code = 5; /* EXRNCG */ - if (lcp -> lcd_so) - lcp -> lcd_so -> so_error = Clear_cause[code]; -} - -char * -format_ntn (xcp) -register struct x25config *xcp; -{ - - return (xcp -> xc_addr.x25_addr); -} - -/* VARARGS1 */ -pk_message (lcn, xcp, fmt, a1, a2, a3, a4, a5, a6) -struct x25config *xcp; -char *fmt; -{ - - if (lcn) - if (!PQEMPTY) - printf ("X.25(%s): lcn %d: ", format_ntn (xcp), lcn); - else - printf ("X.25: lcn %d: ", lcn); - else - if (!PQEMPTY) - printf ("X.25(%s): ", format_ntn (xcp)); - else - printf ("X.25: "); - - printf (fmt, a1, a2, a3, a4, a5, a6); - printf ("\n"); -} - -pk_fragment (lcp, m0, qbit, mbit, wait) -struct mbuf *m0; -register struct pklcd *lcp; -{ - register struct mbuf *m = m0; - register struct x25_packet *xp; - register struct sockbuf *sb; - struct mbuf *head = 0, *next, **mp = &head, *m_split (); - int totlen, psize = 1 << (lcp -> lcd_packetsize); - - if (m == 0) - return 0; - if (m -> m_flags & M_PKTHDR == 0) - panic ("pk_fragment"); - totlen = m -> m_pkthdr.len; - m -> m_act = 0; - sb = lcp -> lcd_so ? &lcp -> lcd_so -> so_snd : & lcp -> lcd_sb; - do { - if (totlen > psize) { - if ((next = m_split (m, psize, wait)) == 0) - goto abort; - totlen -= psize; - } else - next = 0; - M_PREPEND(m, PKHEADERLN, wait); - if (m == 0) - goto abort; - *mp = m; - mp = & m -> m_act; - *mp = 0; - xp = mtod (m, struct x25_packet *); - 0[(char *)xp] = 0; - if (qbit) - X25SBITS(xp -> bits, q_bit, 1); - if (lcp -> lcd_flags & X25_DBIT) - X25SBITS(xp -> bits, d_bit, 1); - X25SBITS(xp -> bits, fmt_identifier, 1); - xp -> packet_type = X25_DATA; - SET_LCN(xp, lcp -> lcd_lcn); - if (next || (mbit && (totlen == psize || - (lcp -> lcd_flags & X25_DBIT)))) - SMBIT(xp, 1); - } while (m = next); - for (m = head; m; m = next) { - next = m -> m_act; - m -> m_act = 0; - sbappendrecord (sb, m); - } - return 0; -abort: - if (wait) - panic ("pk_fragment null mbuf after wait"); - if (next) - m_freem (next); - for (m = head; m; m = next) { - next = m -> m_act; - m_freem (m); - } - return ENOBUFS; -} diff --git a/bsd/netccitt/pk_timer.c b/bsd/netccitt/pk_timer.c deleted file mode 100644 index d664e0913..000000000 --- a/bsd/netccitt/pk_timer.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) Computing Centre, University of British Columbia, 1984 - * Copyright (C) Computer Science Department IV, - * University of Erlangen-Nuremberg, Germany, 1990, 1992 - * Copyright (c) 1990, 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by the - * Laboratory for Computation Vision and the Computer Science Department - * of the the University of British Columbia and the Computer Science - * Department (IV) of the University of Erlangen-Nuremberg, Germany. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)pk_timer.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -/* - * Various timer values. They can be adjusted - * by patching the binary with adb if necessary. - */ -int pk_t20 = 18 * PR_SLOWHZ; /* restart timer */ -int pk_t21 = 20 * PR_SLOWHZ; /* call timer */ -/* XXX pk_t22 is never used */ -int pk_t22 = 18 * PR_SLOWHZ; /* reset timer */ -int pk_t23 = 18 * PR_SLOWHZ; /* clear timer */ - -pk_timer () -{ - register struct pkcb *pkp; - register struct pklcd *lcp, **pp; - register int lcns_jammed, cant_restart; - - FOR_ALL_PKCBS(pkp) { - switch (pkp -> pk_state) { - case DTE_SENT_RESTART: - lcp = pkp -> pk_chan[0]; - /* - * If restart failures are common, a link level - * reset should be initiated here. - */ - if (lcp -> lcd_timer && --lcp -> lcd_timer == 0) { - pk_message (0, pkp -> pk_xcp, - "packet level restart failed"); - pkp -> pk_state = DTE_WAITING; - } - break; - - case DTE_READY: - lcns_jammed = cant_restart = 0; - for (pp = &pkp -> pk_chan[1]; pp <= &pkp -> pk_chan[pkp -> pk_maxlcn]; pp++) { - if ((lcp = *pp) == 0) - continue; - switch (lcp -> lcd_state) { - case SENT_CALL: - if (--lcp -> lcd_timer == 0) { - if (lcp -> lcd_so) - lcp -> lcd_so -> so_error = ETIMEDOUT; - pk_clear (lcp, 49, 1); - } - break; - - case SENT_CLEAR: - if (lcp -> lcd_retry >= 3) - lcns_jammed++; - else - if (--lcp -> lcd_timer == 0) - pk_clear (lcp, 50, 1); - break; - - case DATA_TRANSFER: /* lcn active */ - cant_restart++; - break; - - case LCN_ZOMBIE: /* zombie state */ - pk_freelcd (lcp); - break; - } - } - if (lcns_jammed > pkp -> pk_maxlcn / 2 && cant_restart == 0) { - pk_message (0, pkp -> pk_xcp, "%d lcns jammed: attempting restart", lcns_jammed); - pk_restart (pkp, 0); - } - } - } -} diff --git a/bsd/netccitt/pk_usrreq.c b/bsd/netccitt/pk_usrreq.c deleted file mode 100644 index ba1cb9500..000000000 --- a/bsd/netccitt/pk_usrreq.c +++ /dev/null @@ -1,626 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) University of British Columbia, 1984 - * Copyright (C) Computer Science Department IV, - * University of Erlangen-Nuremberg, Germany, 1992 - * Copyright (c) 1991, 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by the - * Laboratory for Computation Vision and the Computer Science Department - * of the the University of British Columbia and the Computer Science - * Department (IV) of the University of Erlangen-Nuremberg, Germany. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)pk_usrreq.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -static old_to_new(); -static new_to_old(); -/* - * - * X.25 Packet level protocol interface to socket abstraction. - * - * Process an X.25 user request on a logical channel. If this is a send - * request then m is the mbuf chain of the send data. If this is a timer - * expiration (called from the software clock routine) them timertype is - * the particular timer. - * - */ - -pk_usrreq (so, req, m, nam, control) -struct socket *so; -int req; -register struct mbuf *m, *nam; -struct mbuf *control; -{ - register struct pklcd *lcp = (struct pklcd *) so -> so_pcb; - register int error = 0; - - if (req == PRU_CONTROL) - return (pk_control (so, (int)m, (caddr_t)nam, - (struct ifnet *)control)); - if (control && control -> m_len) { - error = EINVAL; - goto release; - } - if (lcp == NULL && req != PRU_ATTACH) { - error = EINVAL; - goto release; - } - -/* - pk_trace (pkcbhead, TR_USER, (struct pklcd *)0, - req, (struct x25_packet *)0); -*/ - - switch (req) { - /* - * X.25 attaches to socket via PRU_ATTACH and allocates a logical - * channel descriptor. If the socket is to receive connections, - * then the LISTEN state is entered. - */ - case PRU_ATTACH: - if (lcp) { - error = EISCONN; - /* Socket already connected. */ - break; - } - lcp = pk_attach (so); - if (lcp == 0) - error = ENOBUFS; - break; - - /* - * Detach a logical channel from the socket. If the state of the - * channel is embryonic, simply discard it. Otherwise we have to - * initiate a PRU_DISCONNECT which will finish later. - */ - case PRU_DETACH: - pk_disconnect (lcp); - break; - - /* - * Give the socket an address. - */ - case PRU_BIND: - if (nam -> m_len == sizeof (struct x25_sockaddr)) - old_to_new (nam); - error = pk_bind (lcp, nam); - break; - - /* - * Prepare to accept connections. - */ - case PRU_LISTEN: - error = pk_listen (lcp); - break; - - /* - * Initiate a CALL REQUEST to peer entity. Enter state SENT_CALL - * and mark the socket as connecting. Set timer waiting for - * CALL ACCEPT or CLEAR. - */ - case PRU_CONNECT: - if (nam -> m_len == sizeof (struct x25_sockaddr)) - old_to_new (nam); - if (pk_checksockaddr (nam)) - return (EINVAL); - error = pk_connect (lcp, mtod (nam, struct sockaddr_x25 *)); - break; - - /* - * Initiate a disconnect to peer entity via a CLEAR REQUEST packet. - * The socket will be disconnected when we receive a confirmation - * or a clear collision. - */ - case PRU_DISCONNECT: - pk_disconnect (lcp); - break; - - /* - * Accept an INCOMING CALL. Most of the work has already been done - * by pk_input. Just return the callers address to the user. - */ - case PRU_ACCEPT: - if (lcp -> lcd_craddr == NULL) - break; - bcopy ((caddr_t)lcp -> lcd_craddr, mtod (nam, caddr_t), - sizeof (struct sockaddr_x25)); - nam -> m_len = sizeof (struct sockaddr_x25); - if (lcp -> lcd_flags & X25_OLDSOCKADDR) - new_to_old (nam); - break; - - /* - * After a receive, we should send a RR. - */ - case PRU_RCVD: - pk_flowcontrol (lcp, /*sbspace (&so -> so_rcv) <= */ 0, 1); - break; - - /* - * Send INTERRUPT packet. - */ - case PRU_SENDOOB: - if (m == 0) { - MGETHDR(m, M_WAITOK, MT_OOBDATA); - m -> m_pkthdr.len = m -> m_len = 1; - *mtod (m, octet *) = 0; - } - if (m -> m_pkthdr.len > 32) { - m_freem (m); - error = EMSGSIZE; - break; - } - MCHTYPE(m, MT_OOBDATA); - /* FALLTHROUGH */ - - /* - * Do send by placing data on the socket output queue. - */ - case PRU_SEND: - if (control) { - register struct cmsghdr *ch = mtod (m, struct cmsghdr *); - control -> m_len -= sizeof (*ch); - control -> m_data += sizeof (*ch); - error = pk_ctloutput (PRCO_SETOPT, so, ch -> cmsg_level, - ch -> cmsg_type, &control); - } - if (error == 0 && m) - error = pk_send (lcp, m); - break; - - /* - * Abort a virtual circuit. For example all completed calls - * waiting acceptance. - */ - case PRU_ABORT: - pk_disconnect (lcp); - break; - - /* Begin unimplemented hooks. */ - - case PRU_SHUTDOWN: - error = EOPNOTSUPP; - break; - - case PRU_CONTROL: - error = EOPNOTSUPP; - break; - - case PRU_SENSE: -#ifdef BSD4_3 - ((struct stat *)m) -> st_blksize = so -> so_snd.sb_hiwat; -#else - error = EOPNOTSUPP; -#endif - break; - - /* End unimplemented hooks. */ - - case PRU_SOCKADDR: - if (lcp -> lcd_ceaddr == 0) - return (EADDRNOTAVAIL); - nam -> m_len = sizeof (struct sockaddr_x25); - bcopy ((caddr_t)lcp -> lcd_ceaddr, mtod (nam, caddr_t), - sizeof (struct sockaddr_x25)); - if (lcp -> lcd_flags & X25_OLDSOCKADDR) - new_to_old (nam); - break; - - case PRU_PEERADDR: - if (lcp -> lcd_state != DATA_TRANSFER) - return (ENOTCONN); - nam -> m_len = sizeof (struct sockaddr_x25); - bcopy (lcp -> lcd_craddr ? (caddr_t)lcp -> lcd_craddr : - (caddr_t)lcp -> lcd_ceaddr, - mtod (nam, caddr_t), sizeof (struct sockaddr_x25)); - if (lcp -> lcd_flags & X25_OLDSOCKADDR) - new_to_old (nam); - break; - - /* - * Receive INTERRUPT packet. - */ - case PRU_RCVOOB: - if (so -> so_options & SO_OOBINLINE) { - register struct mbuf *n = so -> so_rcv.sb_mb; - if (n && n -> m_type == MT_OOBDATA) { - unsigned len = n -> m_pkthdr.len; - so -> so_rcv.sb_mb = n -> m_nextpkt; - if (len != n -> m_len && - (n = m_pullup (n, len)) == 0) - break; - m -> m_len = len; - bcopy (mtod (m, caddr_t), mtod (n, caddr_t), len); - m_freem (n); - } - break; - } - m -> m_len = 1; - *mtod (m, char *) = lcp -> lcd_intrdata; - break; - - default: - panic ("pk_usrreq"); - } -release: - if (control != NULL) - m_freem (control); - return (error); -} - -/* - * If you want to use UBC X.25 level 3 in conjunction with some - * other X.25 level 2 driver, have the ifp -> if_ioctl routine - * assign pk_start to ia -> ia_start when called with SIOCSIFCONF_X25. - */ -/* ARGSUSED */ -pk_start (lcp) -register struct pklcd *lcp; -{ - pk_output (lcp); - return (0); /* XXX pk_output should return a value */ -} - -#ifndef _offsetof -#define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m)) -#endif -struct sockaddr_x25 pk_sockmask = { - _offsetof(struct sockaddr_x25, x25_addr[0]), /* x25_len */ - 0, /* x25_family */ - -1, /* x25_net id */ -}; - -/*ARGSUSED*/ -pk_control (so, cmd, data, ifp) -struct socket *so; -int cmd; -caddr_t data; -register struct ifnet *ifp; -{ - register struct ifreq_x25 *ifr = (struct ifreq_x25 *)data; - register struct ifaddr *ifa = 0; - register struct x25_ifaddr *ia = 0; - struct pklcd *dev_lcp = 0; - int error, s, old_maxlcn; - unsigned n; - - /* - * Find address for this interface, if it exists. - */ - if (ifp) - for (ifa = ifp -> if_addrlist; ifa; ifa = ifa -> ifa_next) - if (ifa -> ifa_addr -> sa_family == AF_CCITT) - break; - - ia = (struct x25_ifaddr *)ifa; - switch (cmd) { - case SIOCGIFCONF_X25: - if (ifa == 0) - return (EADDRNOTAVAIL); - ifr -> ifr_xc = ia -> ia_xc; - return (0); - - case SIOCSIFCONF_X25: - if ((so->so_state & SS_PRIV) == 0) - return (EPERM); - if (ifp == 0) - panic ("pk_control"); - if (ifa == (struct ifaddr *)0) { - register struct mbuf *m; - - MALLOC(ia, struct x25_ifaddr *, sizeof (*ia), - M_IFADDR, M_WAITOK); - if (ia == 0) - return (ENOBUFS); - bzero ((caddr_t)ia, sizeof (*ia)); - if (ifa = ifp -> if_addrlist) { - for ( ; ifa -> ifa_next; ifa = ifa -> ifa_next) - ; - ifa -> ifa_next = &ia -> ia_ifa; - } else - ifp -> if_addrlist = &ia -> ia_ifa; - ifa = &ia -> ia_ifa; - ifa -> ifa_netmask = (struct sockaddr *)&pk_sockmask; - ifa -> ifa_addr = (struct sockaddr *)&ia -> ia_xc.xc_addr; - ifa -> ifa_dstaddr = (struct sockaddr *)&ia -> ia_dstaddr; /* XXX */ - ia -> ia_ifp = ifp; - ia -> ia_dstaddr.x25_family = AF_CCITT; - ia -> ia_dstaddr.x25_len = pk_sockmask.x25_len; - } else if (ISISO8802(ifp) == 0) { - rtinit (ifa, (int)RTM_DELETE, 0); - } - old_maxlcn = ia -> ia_maxlcn; - ia -> ia_xc = ifr -> ifr_xc; - ia -> ia_dstaddr.x25_net = ia -> ia_xc.xc_addr.x25_net; - if (ia -> ia_maxlcn != old_maxlcn && old_maxlcn != 0) { - /* VERY messy XXX */ - register struct pkcb *pkp; - FOR_ALL_PKCBS(pkp) - if (pkp -> pk_ia == ia) - pk_resize (pkp); - } - /* - * Give the interface a chance to initialize if this -p * is its first address, and to validate the address. - */ - ia -> ia_start = pk_start; - s = splimp(); - if (ifp -> if_ioctl) - error = (*ifp -> if_ioctl)(ifp, SIOCSIFCONF_X25, - (caddr_t) ifa); - if (error) - ifp -> if_flags &= ~IFF_UP; - else if (ISISO8802(ifp) == 0) - error = rtinit (ifa, (int)RTM_ADD, RTF_UP); - splx (s); - return (error); - - default: - if (ifp == 0 || ifp -> if_ioctl == 0) - return (EOPNOTSUPP); - return ((*ifp -> if_ioctl)(ifp, cmd, data)); - } -} - -pk_ctloutput (cmd, so, level, optname, mp) -struct socket *so; -struct mbuf **mp; -int cmd, level, optname; -{ - register struct mbuf *m = *mp; - register struct pklcd *lcp = (struct pklcd *) so -> so_pcb; - int error = EOPNOTSUPP; - - if (m == 0) - return (EINVAL); - if (cmd == PRCO_SETOPT) switch (optname) { - case PK_FACILITIES: - if (m == 0) - return (EINVAL); - lcp -> lcd_facilities = m; - *mp = 0; - return (0); - - case PK_ACCTFILE: - if ((so->so_state & SS_PRIV) == 0) - error = EPERM; - else if (m -> m_len) - error = pk_accton (mtod (m, char *)); - else - error = pk_accton ((char *)0); - break; - - case PK_RTATTACH: - error = pk_rtattach (so, m); - break; - - case PK_PRLISTEN: - error = pk_user_protolisten (mtod (m, u_char *)); - } - if (*mp) { - (void) m_freem (*mp); - *mp = 0; - } - return (error); - -} - - -/* - * Do an in-place conversion of an "old style" - * socket address to the new style - */ - -static -old_to_new (m) -register struct mbuf *m; -{ - register struct x25_sockaddr *oldp; - register struct sockaddr_x25 *newp; - register char *ocp, *ncp; - struct sockaddr_x25 new; - - oldp = mtod (m, struct x25_sockaddr *); - newp = &new; - bzero ((caddr_t)newp, sizeof (*newp)); - - newp -> x25_family = AF_CCITT; - newp -> x25_len = sizeof(*newp); - newp -> x25_opts.op_flags = (oldp -> xaddr_facilities & X25_REVERSE_CHARGE) - | X25_MQBIT | X25_OLDSOCKADDR; - if (oldp -> xaddr_facilities & XS_HIPRIO) /* Datapac specific */ - newp -> x25_opts.op_psize = X25_PS128; - bcopy ((caddr_t)oldp -> xaddr_addr, newp -> x25_addr, - (unsigned)min (oldp -> xaddr_len, sizeof (newp -> x25_addr) - 1)); - if (bcmp ((caddr_t)oldp -> xaddr_proto, newp -> x25_udata, 4) != 0) { - bcopy ((caddr_t)oldp -> xaddr_proto, newp -> x25_udata, 4); - newp -> x25_udlen = 4; - } - ocp = (caddr_t)oldp -> xaddr_userdata; - ncp = newp -> x25_udata + 4; - while (*ocp && ocp < (caddr_t)oldp -> xaddr_userdata + 12) { - if (newp -> x25_udlen == 0) - newp -> x25_udlen = 4; - *ncp++ = *ocp++; - newp -> x25_udlen++; - } - bcopy ((caddr_t)newp, mtod (m, char *), sizeof (*newp)); - m -> m_len = sizeof (*newp); -} - -/* - * Do an in-place conversion of a new style - * socket address to the old style - */ - -static -new_to_old (m) -register struct mbuf *m; -{ - register struct x25_sockaddr *oldp; - register struct sockaddr_x25 *newp; - register char *ocp, *ncp; - struct x25_sockaddr old; - - oldp = &old; - newp = mtod (m, struct sockaddr_x25 *); - bzero ((caddr_t)oldp, sizeof (*oldp)); - - oldp -> xaddr_facilities = newp -> x25_opts.op_flags & X25_REVERSE_CHARGE; - if (newp -> x25_opts.op_psize == X25_PS128) - oldp -> xaddr_facilities |= XS_HIPRIO; /* Datapac specific */ - ocp = (char *)oldp -> xaddr_addr; - ncp = newp -> x25_addr; - while (*ncp) { - *ocp++ = *ncp++; - oldp -> xaddr_len++; - } - - bcopy (newp -> x25_udata, (caddr_t)oldp -> xaddr_proto, 4); - if (newp -> x25_udlen > 4) - bcopy (newp -> x25_udata + 4, (caddr_t)oldp -> xaddr_userdata, - (unsigned)(newp -> x25_udlen - 4)); - - bcopy ((caddr_t)oldp, mtod (m, char *), sizeof (*oldp)); - m -> m_len = sizeof (*oldp); -} - - -pk_checksockaddr (m) -struct mbuf *m; -{ - register struct sockaddr_x25 *sa = mtod (m, struct sockaddr_x25 *); - register char *cp; - - if (m -> m_len != sizeof (struct sockaddr_x25)) - return (1); - if (sa -> x25_family != AF_CCITT || - sa -> x25_udlen > sizeof (sa -> x25_udata)) - return (1); - for (cp = sa -> x25_addr; *cp; cp++) { - if (*cp < '0' || *cp > '9' || - cp >= &sa -> x25_addr[sizeof (sa -> x25_addr) - 1]) - return (1); - } - return (0); -} - -pk_send (lcp, m) -struct pklcd *lcp; -register struct mbuf *m; -{ - int mqbit = 0, error = 0; - register struct x25_packet *xp; - register struct socket *so; - - if (m -> m_type == MT_OOBDATA) { - if (lcp -> lcd_intrconf_pending) - error = ETOOMANYREFS; - if (m -> m_pkthdr.len > 32) - error = EMSGSIZE; - M_PREPEND(m, PKHEADERLN, M_WAITOK); - if (m == 0 || error) - goto bad; - *(mtod (m, octet *)) = 0; - xp = mtod (m, struct x25_packet *); - X25SBITS(xp -> bits, fmt_identifier, 1); - xp -> packet_type = X25_INTERRUPT; - SET_LCN(xp, lcp -> lcd_lcn); - sbinsertoob ( (so = lcp -> lcd_so) ? - &so -> so_snd : &lcp -> lcd_sb, m); - goto send; - } - /* - * Application has elected (at call setup time) to prepend - * a control byte to each packet written indicating m-bit - * and q-bit status. Examine and then discard this byte. - */ - if (lcp -> lcd_flags & X25_MQBIT) { - if (m -> m_len < 1) { - m_freem (m); - return (EMSGSIZE); - } - mqbit = *(mtod (m, u_char *)); - m -> m_len--; - m -> m_data++; - m -> m_pkthdr.len--; - } - error = pk_fragment (lcp, m, mqbit & 0x80, mqbit & 0x40, 1); -send: - if (error == 0 && lcp -> lcd_state == DATA_TRANSFER) - lcp -> lcd_send (lcp); /* XXXXXXXXX fix pk_output!!! */ - return (error); -bad: - if (m) - m_freem (m); - return (error); -} diff --git a/bsd/netccitt/pk_var.h b/bsd/netccitt/pk_var.h deleted file mode 100644 index 94b3b76ae..000000000 --- a/bsd/netccitt/pk_var.h +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) Computing Centre, University of British Columbia, 1985 - * Copyright (C) Computer Science Department IV, - * University of Erlangen-Nuremberg, Germany, 1990, 1991, 1992 - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by the - * Laboratory for Computation Vision and the Computer Science Department - * of the the University of British Columbia and the Computer Science - * Department (IV) of the University of Erlangen-Nuremberg, Germany. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)pk_var.h 8.1 (Berkeley) 6/10/93 - */ - -/* - * - * X.25 Logical Channel Descriptor - * - */ - -struct pklcd { - struct pklcd_q { - struct pklcd_q *q_forw; /* debugging chain */ - struct pklcd_q *q_back; /* debugging chain */ - } lcd_q; - int (*lcd_upper)(); /* switch to socket vs datagram vs ...*/ - caddr_t lcd_upnext; /* reference for lcd_upper() */ - int (*lcd_send)(); /* if X.25 front end, direct connect */ - caddr_t lcd_downnext; /* reference for lcd_send() */ - short lcd_lcn; /* Logical channel number */ - short lcd_state; /* Logical Channel state */ - short lcd_timer; /* Various timer values */ - short lcd_dg_timer; /* to reclaim idle datagram circuits */ - bool lcd_intrconf_pending; /* Interrupt confirmation pending */ - octet lcd_intrdata; /* Octet of incoming intr data */ - char lcd_retry; /* Timer retry count */ - char lcd_rsn; /* Seq no of last received packet */ - char lcd_ssn; /* Seq no of next packet to send */ - char lcd_output_window; /* Output flow control window */ - char lcd_input_window; /* Input flow control window */ - char lcd_last_transmitted_pr;/* Last Pr value transmitted */ - bool lcd_rnr_condition; /* Remote in busy condition */ - bool lcd_window_condition; /* Output window size exceeded */ - bool lcd_reset_condition; /* True, if waiting reset confirm */ - bool lcd_rxrnr_condition; /* True, if we have sent rnr */ - char lcd_packetsize; /* Maximum packet size */ - char lcd_windowsize; /* Window size - both directions */ - octet lcd_closed_user_group; /* Closed user group specification */ - char lcd_flags; /* copy of sockaddr_x25 op_flags */ - struct mbuf *lcd_facilities; /* user supplied facilities for cr */ - struct mbuf *lcd_template; /* Address of response packet */ - struct socket *lcd_so; /* Socket addr for connection */ - struct sockaddr_x25 *lcd_craddr;/* Calling address pointer */ - struct sockaddr_x25 *lcd_ceaddr;/* Called address pointer */ - time_t lcd_stime; /* time circuit established */ - long lcd_txcnt; /* Data packet transmit count */ - long lcd_rxcnt; /* Data packet receive count */ - short lcd_intrcnt; /* Interrupt packet transmit count */ - struct pklcd *lcd_listen; /* Next lcd on listen queue */ - struct pkcb *lcd_pkp; /* Network this lcd is attached to */ - struct mbuf *lcd_cps; /* Complete Packet Sequence reassembly*/ - long lcd_cpsmax; /* Max length for CPS */ - struct sockaddr_x25 lcd_faddr; /* Remote Address (Calling) */ - struct sockaddr_x25 lcd_laddr; /* Local Address (Called) */ - struct sockbuf lcd_sb; /* alternate for datagram service */ -}; - -/* - * Per network information, allocated dynamically - * when a new network is configured. - */ - -struct pkcb { - struct pkcb_q { - struct pkcb_q *q_forw; - struct pkcb_q *q_backw; - } pk_q; - short pk_state; /* packet level status */ - short pk_maxlcn; /* local copy of xc_maxlcn */ - int (*pk_lloutput) (); /* link level output procedure */ - caddr_t (*pk_llctlinput) (); /* link level ctloutput procedure */ - caddr_t pk_llnext; /* handle for next level down */ - struct x25config *pk_xcp; /* network specific configuration */ - struct x25_ifaddr *pk_ia; /* backpointer to ifaddr */ - struct pklcd **pk_chan; /* actual size == xc_maxlcn+1 */ - short pk_dxerole; /* DXE role of PLE over LLC2 */ - short pk_restartcolls; /* counting RESTART collisions til resolved */ - struct rtentry *pk_rt; /* back pointer to route */ - struct rtentry *pk_llrt; /* pointer to reverse mapping */ - u_short pk_refcount; /* ref count */ -}; - -#define FOR_ALL_PKCBS(p) for((p) = (struct pkcb *)(pkcb_q.q_forw); \ - (pkcb_q.q_forw != &pkcb_q) && ((struct pkcb_q *)(p) != &pkcb_q); \ - (p) = (struct pkcb *)((p) -> pk_q.q_forw)) - -#define PQEMPTY (pkcb_q.q_forw == &pkcb_q) - -/* - * Interface address, x25 version. Exactly one of these structures is - * allocated for each interface with an x25 address. - * - * The ifaddr structure conatins the protocol-independent part - * of the structure, and is assumed to be first. - */ -struct x25_ifaddr { - struct ifaddr ia_ifa; /* protocol-independent info */ -#define ia_ifp ia_ifa.ifa_ifp -#define ia_flags ia_ifa.ifa_flags - struct x25config ia_xc; /* network specific configuration */ - struct pkcb *ia_pkcb; -#define ia_maxlcn ia_xc.xc_maxlcn - int (*ia_start) (); /* connect, confirm method */ - struct sockaddr_x25 ia_dstaddr; /* reserve space for route dst */ -}; - -/* - * ``Link-Level'' extension to Routing Entry for upper level - * packet switching via X.25 virtual circuits. - */ -struct llinfo_x25 { - struct llinfo_x25 *lx_next; /* chain together in linked list */ - struct llinfo_x25 *lx_prev; /* chain together in linked list */ - struct rtentry *lx_rt; /* back pointer to route */ - struct pklcd *lx_lcd; /* local connection block */ - struct x25_ifaddr *lx_ia; /* may not be same as rt_ifa */ - int lx_state; /* can't trust lcd->lcd_state */ - int lx_flags; - int lx_timer; /* for idle timeout */ - int lx_family; /* for dispatch */ -}; - -/* States for lx_state */ -#define LXS_NEWBORN 0 -#define LXS_RESOLVING 1 -#define LXS_FREE 2 -#define LXS_CONNECTING 3 -#define LXS_CONNECTED 4 -#define LXS_DISCONNECTING 5 -#define LXS_LISTENING 6 - -/* flags */ -#define LXF_VALID 0x1 /* Circuit is live, etc. */ -#define LXF_RTHELD 0x2 /* this lcb references rtentry */ -#define LXF_LISTEN 0x4 /* accepting incoming calls */ - -/* - * Definitions for accessing bitfields/bitslices inside X.25 structs - */ - - -struct x25bitslice { - unsigned int bs_mask; - unsigned int bs_shift; -}; - -#define calling_addrlen 0 -#define called_addrlen 1 -#define q_bit 2 -#define d_bit 3 -#define fmt_identifier 4 -#define lc_group_number 1 -#define p_r 5 -#define m_bit 6 -#define p_s 7 -#define zilch 8 - -#define X25GBITS(Arg, Index) (((Arg) & x25_bitslice[(Index)].bs_mask) >> x25_bitslice[(Index)].bs_shift) -#define X25SBITS(Arg, Index, Val) (Arg) |= (((Val) << x25_bitslice[(Index)].bs_shift) & x25_bitslice[(Index)].bs_mask) -#define X25CSBITS(Arg, Index, Val) (Arg) = (((Val) << x25_bitslice[(Index)].bs_shift) & x25_bitslice[(Index)].bs_mask) - -extern struct x25bitslice x25_bitslice[]; - - -#define ISOFIFTTYPE(i,t) ((i)->if_type == (t)) -#define ISISO8802(i) ((ISOFIFTTYPE(i, IFT_ETHER) || \ - ISOFIFTTYPE(i, IFT_ISO88023) || \ - ISOFIFTTYPE(i, IFT_ISO88024) || \ - ISOFIFTTYPE(i, IFT_ISO88025) || \ - ISOFIFTTYPE(i, IFT_ISO88026) || \ - ISOFIFTTYPE(i, IFT_P10) || \ - ISOFIFTTYPE(i, IFT_P80) || \ - ISOFIFTTYPE(i, IFT_FDDI))) - -/* - * miscellenous debugging info - */ -struct mbuf_cache { - int mbc_size; - int mbc_num; - int mbc_oldsize; - struct mbuf **mbc_cache; -}; - -#if defined(KERNEL) && defined(CCITT) -extern struct pkcb_q pkcb_q; -struct pklcd *pk_listenhead; -struct pklcd *pk_attach(); - -extern char *pk_name[], *pk_state[]; -int pk_t20, pk_t21, pk_t22, pk_t23; -#endif diff --git a/bsd/netccitt/x25.h b/bsd/netccitt/x25.h deleted file mode 100644 index 06a7b75de..000000000 --- a/bsd/netccitt/x25.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) University of British Columbia, 1984 - * Copyright (c) 1990, 1992, 1993 - * The Regents of the University of California. All rights reserved. - * University of Erlangen-Nuremberg, Germany, 1992 - * - * This code is derived from software contributed to Berkeley by the - * Laboratory for Computation Vision and the Computer Science Department - * of the the University of British Columbia and the Computer Science - * Department (IV) of the University of Erlangen-Nuremberg, Germany. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)x25.h 8.1 (Berkeley) 6/10/93 - */ - -#ifdef KERNEL -#define PRC_IFUP 3 -#define PRC_LINKUP 4 -#define PRC_LINKDOWN 5 -#define PRC_LINKRESET 6 -#define PRC_LINKDONTCOPY 7 -#ifndef PRC_DISCONNECT_REQUEST -#define PRC_DISCONNECT_REQUEST 10 -#endif -#endif - -#define CCITTPROTO_HDLC 1 -#define CCITTPROTO_X25 2 /* packet level protocol */ -#define IEEEPROTO_802LLC 3 /* doesn't belong here */ - -#define HDLCPROTO_LAP 1 -#define HDLCPROTO_LAPB 2 -#define HDLCPROTO_UNSET 3 -#define HDLCPROTO_LAPD 4 - -/* socket options */ -#define PK_ACCTFILE 1 /* use level = CCITTPROTO_X25 */ -#define PK_FACILITIES 2 /* use level = CCITTPROTO_X25 */ -#define PK_RTATTACH 3 /* use level = CCITTPROTO_X25 */ -#define PK_PRLISTEN 4 /* use level = CCITTPROTO_X25 */ - -#define MAX_FACILITIES 109 /* maximum size for facilities */ - -/* - * X.25 Socket address structure. It contains the X.121 or variation of - * X.121, facilities information, higher level protocol value (first four - * bytes of the User Data field), and the last 12 characters of the User - * Data field. - */ - -struct x25_sockaddr { /* obsolete - use sockaddr_x25 */ - short xaddr_len; /* Length of xaddr_addr. */ - u_char xaddr_addr[15]; /* Network dependent or X.121 address. */ - u_char xaddr_facilities; /* Facilities information. */ -#define XS_REVERSE_CHARGE 0x01 -#define XS_HIPRIO 0x02 - u_char xaddr_proto[4]; /* Protocol ID (4 bytes of user data). */ - u_char xaddr_userdata[12]; /* Remaining User data field. */ -}; - -/* - * X.25 Socket address structure. It contains the network id, X.121 - * address, facilities information, higher level protocol value (first four - * bytes of the User Data field), and up to 12 characters of User Data. - */ - -struct sockaddr_x25 { - u_char x25_len; - u_char x25_family; /* must be AF_CCITT */ - short x25_net; /* network id code (usually a dnic) */ - char x25_addr[16]; /* X.121 address (null terminated) */ - struct x25opts { - char op_flags; /* miscellaneous options */ - /* pk_var.h defines other lcd_flags */ -#define X25_REVERSE_CHARGE 0x01 /* remote DTE pays for call */ -#define X25_DBIT 0x02 /* not yet supported */ -#define X25_MQBIT 0x04 /* prepend M&Q bit status byte to packet data */ -#define X25_OLDSOCKADDR 0x08 /* uses old sockaddr structure */ -#define X25_DG_CIRCUIT 0x10 /* lcd_flag: used for datagrams */ -#define X25_DG_ROUTING 0x20 /* lcd_flag: peer addr not yet known */ -#define X25_MBS_HOLD 0x40 /* lcd_flag: collect m-bit sequences */ - char op_psize; /* requested packet size */ -#define X25_PS128 7 -#define X25_PS256 8 -#define X25_PS512 9 - char op_wsize; /* window size (1 .. 7) */ - char op_speed; /* throughput class */ - } x25_opts; - short x25_udlen; /* user data field length */ - char x25_udata[16]; /* user data field */ -}; - -/* - * network configuration info - * this structure must be 16 bytes long - */ - -struct x25config { - struct sockaddr_x25 xc_addr; - /* link level parameters */ - u_short xc_lproto:4, /* link level protocol eg. CCITTPROTO_HDLC */ - xc_lptype:4, /* protocol type eg. HDLCPROTO_LAPB */ - xc_ltrace:1, /* link level tracing flag */ - xc_lwsize:7; /* link level window size */ - u_short xc_lxidxchg:1, /* link level XID exchange flag - NOT YET */ - /* packet level parameters */ - xc_rsvd1:2, - xc_pwsize:3, /* default window size */ - xc_psize:4, /* default packet size 7=128, 8=256, ... */ - xc_type:3, /* network type */ -#define X25_1976 0 -#define X25_1980 1 -#define X25_1984 2 -#define X25_DDN 3 -#define X25_BASIC 4 - xc_ptrace:1, /* packet level tracing flag */ - xc_nodnic:1, /* remove our dnic when calling on net */ - xc_prepnd0:1; /* prepend 0 when making offnet calls */ - u_short xc_maxlcn; /* max logical channels */ - u_short xc_dg_idletimo; /* timeout for idle datagram circuits. */ -}; - -#ifdef IFNAMSIZ -struct ifreq_x25 { - char ifr_name[IFNAMSIZ]; /* if name, e.g. "en0" */ - struct x25config ifr_xc; -}; -#define SIOCSIFCONF_X25 _IOW('i', 12, struct ifreq_x25) /* set ifnet config */ -#define SIOCGIFCONF_X25 _IOWR('i',13, struct ifreq_x25) /* get ifnet config */ -#endif diff --git a/bsd/netccitt/x25_sockaddr.h b/bsd/netccitt/x25_sockaddr.h deleted file mode 100644 index 06a7b75de..000000000 --- a/bsd/netccitt/x25_sockaddr.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) University of British Columbia, 1984 - * Copyright (c) 1990, 1992, 1993 - * The Regents of the University of California. All rights reserved. - * University of Erlangen-Nuremberg, Germany, 1992 - * - * This code is derived from software contributed to Berkeley by the - * Laboratory for Computation Vision and the Computer Science Department - * of the the University of British Columbia and the Computer Science - * Department (IV) of the University of Erlangen-Nuremberg, Germany. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)x25.h 8.1 (Berkeley) 6/10/93 - */ - -#ifdef KERNEL -#define PRC_IFUP 3 -#define PRC_LINKUP 4 -#define PRC_LINKDOWN 5 -#define PRC_LINKRESET 6 -#define PRC_LINKDONTCOPY 7 -#ifndef PRC_DISCONNECT_REQUEST -#define PRC_DISCONNECT_REQUEST 10 -#endif -#endif - -#define CCITTPROTO_HDLC 1 -#define CCITTPROTO_X25 2 /* packet level protocol */ -#define IEEEPROTO_802LLC 3 /* doesn't belong here */ - -#define HDLCPROTO_LAP 1 -#define HDLCPROTO_LAPB 2 -#define HDLCPROTO_UNSET 3 -#define HDLCPROTO_LAPD 4 - -/* socket options */ -#define PK_ACCTFILE 1 /* use level = CCITTPROTO_X25 */ -#define PK_FACILITIES 2 /* use level = CCITTPROTO_X25 */ -#define PK_RTATTACH 3 /* use level = CCITTPROTO_X25 */ -#define PK_PRLISTEN 4 /* use level = CCITTPROTO_X25 */ - -#define MAX_FACILITIES 109 /* maximum size for facilities */ - -/* - * X.25 Socket address structure. It contains the X.121 or variation of - * X.121, facilities information, higher level protocol value (first four - * bytes of the User Data field), and the last 12 characters of the User - * Data field. - */ - -struct x25_sockaddr { /* obsolete - use sockaddr_x25 */ - short xaddr_len; /* Length of xaddr_addr. */ - u_char xaddr_addr[15]; /* Network dependent or X.121 address. */ - u_char xaddr_facilities; /* Facilities information. */ -#define XS_REVERSE_CHARGE 0x01 -#define XS_HIPRIO 0x02 - u_char xaddr_proto[4]; /* Protocol ID (4 bytes of user data). */ - u_char xaddr_userdata[12]; /* Remaining User data field. */ -}; - -/* - * X.25 Socket address structure. It contains the network id, X.121 - * address, facilities information, higher level protocol value (first four - * bytes of the User Data field), and up to 12 characters of User Data. - */ - -struct sockaddr_x25 { - u_char x25_len; - u_char x25_family; /* must be AF_CCITT */ - short x25_net; /* network id code (usually a dnic) */ - char x25_addr[16]; /* X.121 address (null terminated) */ - struct x25opts { - char op_flags; /* miscellaneous options */ - /* pk_var.h defines other lcd_flags */ -#define X25_REVERSE_CHARGE 0x01 /* remote DTE pays for call */ -#define X25_DBIT 0x02 /* not yet supported */ -#define X25_MQBIT 0x04 /* prepend M&Q bit status byte to packet data */ -#define X25_OLDSOCKADDR 0x08 /* uses old sockaddr structure */ -#define X25_DG_CIRCUIT 0x10 /* lcd_flag: used for datagrams */ -#define X25_DG_ROUTING 0x20 /* lcd_flag: peer addr not yet known */ -#define X25_MBS_HOLD 0x40 /* lcd_flag: collect m-bit sequences */ - char op_psize; /* requested packet size */ -#define X25_PS128 7 -#define X25_PS256 8 -#define X25_PS512 9 - char op_wsize; /* window size (1 .. 7) */ - char op_speed; /* throughput class */ - } x25_opts; - short x25_udlen; /* user data field length */ - char x25_udata[16]; /* user data field */ -}; - -/* - * network configuration info - * this structure must be 16 bytes long - */ - -struct x25config { - struct sockaddr_x25 xc_addr; - /* link level parameters */ - u_short xc_lproto:4, /* link level protocol eg. CCITTPROTO_HDLC */ - xc_lptype:4, /* protocol type eg. HDLCPROTO_LAPB */ - xc_ltrace:1, /* link level tracing flag */ - xc_lwsize:7; /* link level window size */ - u_short xc_lxidxchg:1, /* link level XID exchange flag - NOT YET */ - /* packet level parameters */ - xc_rsvd1:2, - xc_pwsize:3, /* default window size */ - xc_psize:4, /* default packet size 7=128, 8=256, ... */ - xc_type:3, /* network type */ -#define X25_1976 0 -#define X25_1980 1 -#define X25_1984 2 -#define X25_DDN 3 -#define X25_BASIC 4 - xc_ptrace:1, /* packet level tracing flag */ - xc_nodnic:1, /* remove our dnic when calling on net */ - xc_prepnd0:1; /* prepend 0 when making offnet calls */ - u_short xc_maxlcn; /* max logical channels */ - u_short xc_dg_idletimo; /* timeout for idle datagram circuits. */ -}; - -#ifdef IFNAMSIZ -struct ifreq_x25 { - char ifr_name[IFNAMSIZ]; /* if name, e.g. "en0" */ - struct x25config ifr_xc; -}; -#define SIOCSIFCONF_X25 _IOW('i', 12, struct ifreq_x25) /* set ifnet config */ -#define SIOCGIFCONF_X25 _IOWR('i',13, struct ifreq_x25) /* get ifnet config */ -#endif diff --git a/bsd/netccitt/x25acct.h b/bsd/netccitt/x25acct.h deleted file mode 100644 index 14a52242d..000000000 --- a/bsd/netccitt/x25acct.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) University of British Columbia, 1984 - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * the Laboratory for Computation Vision and the Computer Science Department - * of the University of British Columbia. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)x25acct.h 8.1 (Berkeley) 6/10/93 - */ - -/* - * Format of X.25 accounting record written - * to X25ACCTF whenever a circuit is closed. - */ - -#ifdef waterloo -#define X25ACCTF "/usr/adm/logs/x25acct" -#else -#define X25ACCTF "/usr/adm/x25acct" -#endif - -struct x25acct { - time_t x25acct_stime; /* start time */ -#ifdef waterloo - u_long x25acct_etime; /* elapsed time (seconds) */ -#else - u_short x25acct_etime; /* elapsed time (seconds) */ -#endif - short x25acct_uid; /* user id */ - short x25acct_net; /* network id */ - u_short x25acct_psize:4, /* packet size */ - x25acct_addrlen:4, /* x25acct_addr length */ - x25acct_revcharge:1, /* reverse charging */ - x25acct_callin:1, /* incoming call */ - x25acct_unused:6; - char x25acct_addr[8]; /* remote DTE address (in bcd) */ - char x25acct_udata[4]; /* protocol id */ - long x25acct_txcnt; /* packets transmitted */ - long x25acct_rxcnt; /* packets received */ -}; diff --git a/bsd/netccitt/x25err.h b/bsd/netccitt/x25err.h deleted file mode 100644 index 97b47a8a1..000000000 --- a/bsd/netccitt/x25err.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) University of British Columbia, 1984 - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * the Laboratory for Computation Vision and the Computer Science Department - * of the University of British Columbia. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)x25err.h 8.1 (Berkeley) 6/10/93 - */ - -/* - * - * X.25 Reset and Clear errors and diagnostics. These values are - * returned in the u_error field of the u structure. - * - */ - -#define EXRESET 100 /* Reset: call reset */ -#define EXROUT 101 /* Reset: out of order */ -#define EXRRPE 102 /* Reset: remote procedure error */ -#define EXRLPE 103 /* Reset: local procedure error */ -#define EXRNCG 104 /* Reset: network congestion */ - -#define EXCLEAR 110 /* Clear: call cleared */ -#define EXCBUSY 111 /* Clear: number busy */ -#define EXCOUT 112 /* Clear: out of order */ -#define EXCRPE 113 /* Clear: remote procedure error */ -#define EXCRRC 114 /* Clear: collect call refused */ -#define EXCINV 115 /* Clear: invalid call */ -#define EXCAB 116 /* Clear: access barred */ -#define EXCLPE 117 /* Clear: local procedure error */ -#define EXCNCG 118 /* Clear: network congestion */ -#define EXCNOB 119 /* Clear: not obtainable */ - diff --git a/bsd/netinet/Makefile b/bsd/netinet/Makefile index 55b955b83..a680385a0 100644 --- a/bsd/netinet/Makefile +++ b/bsd/netinet/Makefile @@ -20,15 +20,18 @@ EXPINC_SUBDIRS_PPC = \ EXPINC_SUBDIRS_I386 = \ DATAFILES = \ - bootp.h icmp6.h icmp_var.h if_atm.h if_ether.h if_fddi.h \ - igmp.h igmp_var.h in.h in_gif.h in_hostcache.h in_pcb.h \ + bootp.h icmp6.h icmp_var.h if_ether.h \ + igmp.h igmp_var.h in.h in_gif.h in_pcb.h \ in_systm.h in_var.h ip.h ip6.h ip_compat.h \ - ip_dummynet.h ip_ecn.h ip_encap.h ip_flow.h \ + ip_dummynet.h ip_ecn.h ip_encap.h \ ip_fw.h ip_icmp.h ip_mroute.h \ - ip_var.h ipl.h tcp.h \ + ip_var.h tcp.h \ tcp_debug.h tcp_fsm.h tcp_seq.h tcp_timer.h tcp_var.h \ tcpip.h udp.h udp_var.h +PRIVATE_DATAFILES = \ + if_fddi.h if_atm.h ip_flow.h + INSTALL_MI_LIST = ${DATAFILES} INSTALL_MI_DIR = netinet @@ -37,6 +40,9 @@ EXPORT_MI_LIST = ${DATAFILES} EXPORT_MI_DIR = netinet +INSTALL_MI_LCL_LIST = ${DATAFILES} ${PRIVATE_DATAFILES} + +INSTALL_MI_LCL_KERN_LIST = ${PRIVATE_DATAFILES} include $(MakeInc_rule) include $(MakeInc_dir) diff --git a/bsd/netinet/dhcp.h b/bsd/netinet/dhcp.h new file mode 100644 index 000000000..6ce2c61c7 --- /dev/null +++ b/bsd/netinet/dhcp.h @@ -0,0 +1,86 @@ + +#ifndef _NETINET_DHCP_H +#define _NETINET_DHCP_H +#include + +/* + * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * dhcp.h + * - definitions for DHCP (as specified in RFC2132) + */ +#include +#include +#include +#include +#include + +struct dhcp { + u_char dp_op; /* packet opcode type */ + u_char dp_htype; /* hardware addr type */ + u_char dp_hlen; /* hardware addr length */ + u_char dp_hops; /* gateway hops */ + u_int32_t dp_xid; /* transaction ID */ + u_int16_t dp_secs; /* seconds since boot began */ + u_int16_t dp_flags; /* flags */ + struct in_addr dp_ciaddr; /* client IP address */ + struct in_addr dp_yiaddr; /* 'your' IP address */ + struct in_addr dp_siaddr; /* server IP address */ + struct in_addr dp_giaddr; /* gateway IP address */ + u_char dp_chaddr[16]; /* client hardware address */ + u_char dp_sname[64]; /* server host name */ + u_char dp_file[128]; /* boot file name */ + u_char dp_options[0]; /* variable-length options field */ +}; + +struct dhcp_packet { + struct ip ip; + struct udphdr udp; + struct dhcp dhcp; +}; + +#define DHCP_PACKET_OPTIONS_MIN 312 +#define DHCP_PACKET_MIN (sizeof(struct dhcp) + DHCP_PACKET_OPTIONS_MIN) + +/* dhcp message types */ +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNAK 6 +#define DHCPRELEASE 7 +#define DHCPINFORM 8 + +typedef int32_t dhcp_time_secs_t; /* absolute time */ +typedef int32_t dhcp_lease_t; /* relative time */ +#define dhcp_time_hton htonl +#define dhcp_time_ntoh ntohl +#define dhcp_lease_hton htonl +#define dhcp_lease_ntoh ntohl + +#define DHCP_INFINITE_LEASE ((dhcp_lease_t)-1) +#define DHCP_INFINITE_TIME ((dhcp_time_secs_t)-1) + +#define DHCP_FLAGS_BROADCAST ((u_short)0x0001) + +#endif _NETINET_DHCP_H diff --git a/bsd/netinet/dhcp_options.c b/bsd/netinet/dhcp_options.c new file mode 100644 index 000000000..f6114a058 --- /dev/null +++ b/bsd/netinet/dhcp_options.c @@ -0,0 +1,543 @@ +/* + * dhcp_options.c + * - routines to parse and access dhcp options + * and create new dhcp option areas + * - handles overloaded areas as well as vendor-specific options + * that are encoded using the RFC 2132 encoding + */ + +/* + * Modification History + * + * March 15, 2002 Dieter Siegmund (dieter@apple) + * - imported from bootp project + */ + +#include +#include +#include +#include + +#include +#include + +static __inline__ void +my_free(void * ptr) +{ + _FREE(ptr, M_TEMP); +} + +static __inline__ void * +my_malloc(int size) +{ + void * data; + MALLOC(data, void *, size, M_TEMP, M_WAITOK); + return (data); +} + +static __inline__ void * +my_realloc(void * oldptr, int oldsize, int newsize) +{ + void * data; + + MALLOC(data, void *, newsize, M_TEMP, M_WAITOK); + bcopy(oldptr, data, oldsize); + my_free(oldptr); + return (data); +} + +/* + * Functions: ptrlist_* + * Purpose: + * A dynamically growable array of pointers. + */ + +#define PTRLIST_NUMBER 16 + +static void +ptrlist_init(ptrlist_t * list) +{ + bzero(list, sizeof(*list)); + return; +} + +static void +ptrlist_free(ptrlist_t * list) +{ + if (list->array) + my_free(list->array); + ptrlist_init(list); + return; +} + +static int +ptrlist_count(ptrlist_t * list) +{ + if (list == NULL || list->array == NULL) + return (0); + + return (list->count); +} + +static void * +ptrlist_element(ptrlist_t * list, int i) +{ + if (list->array == NULL) + return (NULL); + if (i < list->count) + return (list->array[i]); + return (NULL); +} + + +static boolean_t +ptrlist_grow(ptrlist_t * list) +{ + if (list->array == NULL) { + if (list->size == 0) + list->size = PTRLIST_NUMBER; + list->count = 0; + list->array = my_malloc(sizeof(*list->array) * list->size); + } + else if (list->size == list->count) { +#ifdef DEBUG + printf("doubling %d to %d\n", list->size, list->size * 2); +#endif DEBUG + list->array = my_realloc(list->array, + sizeof(*list->array) * list->size, + sizeof(*list->array) * list->size * 2); + list->size *= 2; + } + if (list->array == NULL) + return (FALSE); + return (TRUE); +} + +static boolean_t +ptrlist_add(ptrlist_t * list, void * element) +{ + if (ptrlist_grow(list) == FALSE) + return (FALSE); + + list->array[list->count++] = element; + return (TRUE); +} + +/* concatenates extra onto list */ +static boolean_t +ptrlist_concat(ptrlist_t * list, ptrlist_t * extra) +{ + if (extra->count == 0) + return (TRUE); + + if ((extra->count + list->count) > list->size) { + int old_size = list->size; + + list->size = extra->count + list->count; + if (list->array == NULL) + list->array = my_malloc(sizeof(*list->array) * list->size); + else + list->array = my_realloc(list->array, old_size, + sizeof(*list->array) * list->size); + } + if (list->array == NULL) + return (FALSE); + bcopy(extra->array, list->array + list->count, + extra->count * sizeof(*list->array)); + list->count += extra->count; + return (TRUE); +} + + +/* + * Functions: dhcpol_* + * + * Purpose: + * Routines to parse/access existing options buffers. + */ +boolean_t +dhcpol_add(dhcpol_t * list, void * element) +{ + return (ptrlist_add((ptrlist_t *)list, element)); +} + +int +dhcpol_count(dhcpol_t * list) +{ + return (ptrlist_count((ptrlist_t *)list)); +} + +void * +dhcpol_element(dhcpol_t * list, int i) +{ + return (ptrlist_element((ptrlist_t *)list, i)); +} + +void +dhcpol_init(dhcpol_t * list) +{ + ptrlist_init((ptrlist_t *)list); +} + +void +dhcpol_free(dhcpol_t * list) +{ + ptrlist_free((ptrlist_t *)list); +} + +boolean_t +dhcpol_concat(dhcpol_t * list, dhcpol_t * extra) +{ + return (ptrlist_concat((ptrlist_t *)list, (ptrlist_t *)extra)); +} + +/* + * Function: dhcpol_parse_buffer + * + * Purpose: + * Parse the given buffer into DHCP options, returning the + * list of option pointers in the given dhcpol_t. + * Parsing continues until we hit the end of the buffer or + * the end tag. + */ +boolean_t +dhcpol_parse_buffer(dhcpol_t * list, void * buffer, int length, + unsigned char * err) +{ + int len; + unsigned char * scan; + unsigned char tag; + + if (err) + err[0] = '\0'; + + dhcpol_init(list); + + len = length; + tag = dhcptag_pad_e; + for (scan = (unsigned char *)buffer; tag != dhcptag_end_e && len > 0; ) { + + tag = scan[DHCP_TAG_OFFSET]; + + switch (tag) { + case dhcptag_end_e: + dhcpol_add(list, scan); /* remember that it was terminated */ + scan++; + len--; + break; + case dhcptag_pad_e: /* ignore pad */ + scan++; + len--; + break; + default: { + unsigned char option_len = scan[DHCP_LEN_OFFSET]; + + dhcpol_add(list, scan); + len -= (option_len + 2); + scan += (option_len + 2); + break; + } + } + } + if (len < 0) { + /* ran off the end */ + if (err) + sprintf(err, "parse failed near tag %d", tag); + dhcpol_free(list); + return (FALSE); + } + return (TRUE); +} + +/* + * Function: dhcpol_find + * + * Purpose: + * Finds the first occurence of the given option, and returns its + * length and the option data pointer. + * + * The optional start parameter allows this function to + * return the next start point so that successive + * calls will retrieve the next occurence of the option. + * Before the first call, *start should be set to 0. + */ +void * +dhcpol_find(dhcpol_t * list, int tag, int * len_p, int * start) +{ + int i = 0; + + if (tag == dhcptag_end_e || tag == dhcptag_pad_e) + return (NULL); + + if (start) + i = *start; + + for (; i < dhcpol_count(list); i++) { + unsigned char * option = dhcpol_element(list, i); + + if (option[DHCP_TAG_OFFSET] == tag) { + if (len_p) + *len_p = option[DHCP_LEN_OFFSET]; + if (start) + *start = i + 1; + return (option + DHCP_OPTION_OFFSET); + } + } + return (NULL); +} + +/* + * Function: dhcpol_get + * + * Purpose: + * Accumulate all occurences of the given option into a + * malloc'd buffer, and return its length. Used to get + * all occurrences of a particular option in a single + * data area. + * Note: + * Use _FREE(val, M_TEMP) to free the returned data area. + */ +void * +dhcpol_get(dhcpol_t * list, int tag, int * len_p) +{ + int i; + char * data = NULL; + int data_len = 0; + + if (tag == dhcptag_end_e || tag == dhcptag_pad_e) + return (NULL); + + for (i = 0; i < dhcpol_count(list); i++) { + unsigned char * option = dhcpol_element(list, i); + + if (option[DHCP_TAG_OFFSET] == tag) { + int len = option[DHCP_LEN_OFFSET]; + + if (data_len == 0) { + data = my_malloc(len); + } + else { + data = my_realloc(data, data_len, data_len + len); + } + bcopy(option + DHCP_OPTION_OFFSET, data + data_len, len); + data_len += len; + } + } + *len_p = data_len; + return (data); +} + +/* + * Function: dhcpol_parse_packet + * + * Purpose: + * Parse the option areas in the DHCP packet. + * Verifies that the packet has the right magic number, + * then parses and accumulates the option areas. + * First the pkt->dp_options is parsed. If that contains + * the overload option, it parses pkt->dp_file if specified, + * then parses pkt->dp_sname if specified. + */ +boolean_t +dhcpol_parse_packet(dhcpol_t * options, struct dhcp * pkt, int len, + unsigned char * err) +{ + char rfc_magic[4] = RFC_OPTIONS_MAGIC; + + dhcpol_init(options); /* make sure it's empty */ + + if (err) + err[0] = '\0'; + + if (len < (sizeof(*pkt) + RFC_MAGIC_SIZE)) { + if (err) { + sprintf(err, "packet is too short: %d < %d", + len, (int)sizeof(*pkt) + RFC_MAGIC_SIZE); + } + return (FALSE); + } + if (bcmp(pkt->dp_options, rfc_magic, RFC_MAGIC_SIZE)) { + if (err) + sprintf(err, "missing magic number"); + return (FALSE); + } + if (dhcpol_parse_buffer(options, pkt->dp_options + RFC_MAGIC_SIZE, + len - sizeof(*pkt) - RFC_MAGIC_SIZE, err) == FALSE) + return (FALSE); + { /* get overloaded options */ + unsigned char * overload; + int overload_len; + + overload = (unsigned char *) + dhcpol_find(options, dhcptag_option_overload_e, + &overload_len, NULL); + if (overload && overload_len == 1) { /* has overloaded options */ + dhcpol_t extra; + + dhcpol_init(&extra); + if (*overload == DHCP_OVERLOAD_FILE + || *overload == DHCP_OVERLOAD_BOTH) { + if (dhcpol_parse_buffer(&extra, pkt->dp_file, + sizeof(pkt->dp_file), NULL)) { + dhcpol_concat(options, &extra); + dhcpol_free(&extra); + } + } + if (*overload == DHCP_OVERLOAD_SNAME + || *overload == DHCP_OVERLOAD_BOTH) { + if (dhcpol_parse_buffer(&extra, pkt->dp_sname, + sizeof(pkt->dp_sname), NULL)) { + dhcpol_concat(options, &extra); + dhcpol_free(&extra); + } + } + } + } + return (TRUE); +} + +/* + * Function: dhcpol_parse_vendor + * + * Purpose: + * Given a set of options, find the vendor specific option(s) + * and parse all of them into a single option list. + * + * Return value: + * TRUE if vendor specific options existed and were parsed succesfully, + * FALSE otherwise. + */ +boolean_t +dhcpol_parse_vendor(dhcpol_t * vendor, dhcpol_t * options, + unsigned char * err) +{ + dhcpol_t extra; + boolean_t ret = FALSE; + int start = 0; + + if (err) + err[0] = '\0'; + + dhcpol_init(vendor); + dhcpol_init(&extra); + + for (;;) { + void * data; + int len; + + data = dhcpol_find(options, dhcptag_vendor_specific_e, &len, &start); + if (data == NULL) { + break; /* out of for */ + } + + if (dhcpol_parse_buffer(&extra, data, len, err) == FALSE) { + goto failed; + } + + if (dhcpol_concat(vendor, &extra) == FALSE) { + if (err) + sprintf(err, "dhcpol_concat() failed at %d\n", start); + goto failed; + } + dhcpol_free(&extra); + ret = TRUE; + } + if (ret == FALSE) { + if (err) + strcpy(err, "missing vendor specific options"); + } + return (ret); + + failed: + dhcpol_free(vendor); + dhcpol_free(&extra); + return (FALSE); +} + +#ifdef TEST_DHCP_OPTIONS +char test_empty[] = { + 99, 130, 83, 99, + 255, +}; + +char test_simple[] = { + 99, 130, 83, 99, + 1, 4, 255, 255, 252, 0, + 3, 4, 17, 202, 40, 1, + 255, +}; + +char test_vendor[] = { + 99, 130, 83, 99, + 1, 4, 255, 255, 252, 0, + 3, 4, 17, 202, 40, 1, + 43, 6, 1, 4, 1, 2, 3, 4, + 43, 6, 1, 4, 1, 2, 3, 4, + 255, +}; + +char test_no_end[] = { + 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x05, 0x36, + 0x04, 0xc0, 0xa8, 0x01, 0x01, 0x33, 0x04, 0x80, + 0x00, 0x80, 0x00, 0x01, 0x04, 0xff, 0xff, 0xff, + 0x00, 0x03, 0x04, 0xc0, 0xa8, 0x01, 0x01, 0x06, + 0x0c, 0x18, 0x1a, 0xa3, 0x21, 0x18, 0x1a, 0xa3, + 0x20, 0x18, 0x5e, 0xa3, 0x21, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +char test_too_short[] = { + 0x1 +}; +struct test { + char * name; + char * data; + int len; + boolean_t result; +}; + +struct test tests[] = { + { "empty", test_empty, sizeof(test_empty), TRUE }, + { "simple", test_simple, sizeof(test_simple), TRUE }, + { "vendor", test_vendor, sizeof(test_vendor), TRUE }, + { "no_end", test_no_end, sizeof(test_no_end), TRUE }, + { "too_short", test_too_short, sizeof(test_too_short), FALSE }, + { NULL, NULL, 0, FALSE }, +}; + + +static char buf[2048]; + +int +main() +{ + int i; + dhcpol_t options; + char error[256]; + struct dhcp * pkt = (struct dhcp *)buf; + + dhcpol_init(&options); + + for (i = 0; tests[i].name; i++) { + printf("\nTest %d: ", i); + bcopy(tests[i].data, pkt->dp_options, tests[i].len); + if (dhcpol_parse_packet(&options, pkt, + sizeof(*pkt) + tests[i].len, + error) != tests[i].result) { + printf("test '%s' FAILED\n", tests[i].name); + if (tests[i].result == TRUE) { + printf("error message returned was %s\n", error); + } + } + else { + printf("test '%s' PASSED\n", tests[i].name); + if (tests[i].result == FALSE) { + printf("error message returned was %s\n", error); + } + } + dhcpol_free(&options); + } + exit(0); +} +#endif TEST_DHCP_OPTIONS diff --git a/bsd/netinet/dhcp_options.h b/bsd/netinet/dhcp_options.h new file mode 100644 index 000000000..0b5020d11 --- /dev/null +++ b/bsd/netinet/dhcp_options.h @@ -0,0 +1,198 @@ + +#ifndef _NETINET_DHCP_OPTIONS_H +#define _NETINET_DHCP_OPTIONS_H +#include +/* + * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * dhcp_options.h + * - routines to parse and access dhcp options + */ + +/* + * Modification History + * + * March 15, 2002 Dieter Siegmund (dieter@apple) + * - imported from bootp project + */ +#include +#include + + +/* overloaded option values */ +#define DHCP_OVERLOAD_FILE 1 +#define DHCP_OVERLOAD_SNAME 2 +#define DHCP_OVERLOAD_BOTH 3 + +/* + * DHCP_OPTION_SIZE_MAX + * - the largest size that an option can be (limited to an 8-bit quantity) + */ +#define DHCP_OPTION_SIZE_MAX 255 + +#define DHCP_TAG_OFFSET 0 +#define DHCP_LEN_OFFSET 1 +#define DHCP_OPTION_OFFSET 2 + + + +#define RFC_OPTIONS_MAGIC { 99, 130, 83, 99 } +#define RFC_MAGIC_SIZE 4 /* bytes */ + +typedef enum { + /* rfc 1497 vendor extensions: 0..18, 255 */ + dhcptag_pad_e = 0, + dhcptag_end_e = 255, + dhcptag_subnet_mask_e = 1, + dhcptag_time_offset_e = 2, + dhcptag_router_e = 3, + dhcptag_time_server_e = 4, + dhcptag_name_server_e = 5, + dhcptag_domain_name_server_e = 6, + dhcptag_log_server_e = 7, + dhcptag_cookie_server_e = 8, + dhcptag_lpr_server_e = 9, + dhcptag_impress_server_e = 10, + dhcptag_resource_location_server_e = 11, + dhcptag_host_name_e = 12, + dhcptag_boot_file_size_e = 13, + dhcptag_merit_dump_file_e = 14, + dhcptag_domain_name_e = 15, + dhcptag_swap_server_e = 16, + dhcptag_root_path_e = 17, + dhcptag_extensions_path_e = 18, + + /* ip layer parameters per host: 19..25 */ + dhcptag_ip_forwarding_e = 19, + dhcptag_non_local_source_routing_e = 20, + dhcptag_policy_filter_e = 21, + dhcptag_max_dgram_reassembly_size_e = 22, + dhcptag_default_ip_time_to_live_e = 23, + dhcptag_path_mtu_aging_timeout_e = 24, + dhcptag_path_mtu_plateau_table_e = 25, + + /* ip layer parameters per interface: 26..33 */ + dhcptag_interface_mtu_e = 26, + dhcptag_all_subnets_local_e = 27, + dhcptag_broadcast_address_e = 28, + dhcptag_perform_mask_discovery_e = 29, + dhcptag_mask_supplier_e = 30, + dhcptag_perform_router_discovery_e = 31, + dhcptag_router_solicitation_address_e = 32, + dhcptag_static_route_e = 33, + dhcptag_trailer_encapsulation_e = 34, + dhcptag_arp_cache_timeout_e = 35, + dhcptag_ethernet_encapsulation_e = 36, + + /* tcp parameters: 37..39 */ + dhcptag_default_ttl_e = 37, + dhcptag_keepalive_interval_e = 38, + dhcptag_keepalive_garbage_e = 39, + + /* application & service parameters: 40..49, 64, 65, 68..76, 78, 79, 95 */ + dhcptag_nis_domain_e = 40, + dhcptag_nis_servers_e = 41, + dhcptag_network_time_protocol_servers_e = 42, + dhcptag_vendor_specific_e = 43, + dhcptag_nb_over_tcpip_name_server_e = 44, + dhcptag_nb_over_tcpip_dgram_dist_server_e = 45, + dhcptag_nb_over_tcpip_node_type_e = 46, + dhcptag_nb_over_tcpip_scope_e = 47, + dhcptag_x_windows_font_server_e = 48, + dhcptag_x_windows_display_manager_e = 49, + dhcptag_nis_plus_domain_e = 64, + dhcptag_nis_plus_servers_e = 65, + dhcptag_mobile_ip_home_agent_e = 68, + dhcptag_smtp_server_e = 69, + dhcptag_pop3_server_e = 70, + dhcptag_nntp_server_e = 71, + dhcptag_default_www_server_e = 72, + dhcptag_default_finger_server_e = 73, + dhcptag_default_irc_server_e = 74, + dhcptag_streettalk_server_e = 75, + dhcptag_stda_server_e = 76, + dhcptag_slp_directory_agent_e = 78, + dhcptag_slp_service_scope_e = 79, + dhcptag_ldap_url_e = 95, + + /* dhcp-specific extensions: 50..61, 66, 67 */ + dhcptag_requested_ip_address_e = 50, + dhcptag_lease_time_e = 51, + dhcptag_option_overload_e = 52, + dhcptag_dhcp_message_type_e = 53, + dhcptag_server_identifier_e = 54, + dhcptag_parameter_request_list_e = 55, + dhcptag_message_e = 56, + dhcptag_max_dhcp_message_size_e = 57, + dhcptag_renewal_t1_time_value_e = 58, + dhcptag_rebinding_t2_time_value_e = 59, + dhcptag_vendor_class_identifier_e = 60, + dhcptag_client_identifier_e = 61, + dhcptag_tftp_server_name_e = 66, + dhcptag_bootfile_name_e = 67, + + /* netinfo parent tags: 112, 113 */ + dhcptag_netinfo_server_address_e = 112, + dhcptag_netinfo_server_tag_e = 113, + + /* ad-hoc network disable option */ + dhcptag_auto_configure_e = 116, +} dhcptag_t; + +/* + * Module: dhcpol (dhcp options list) + * + * Purpose: + * Routines to parse and retrieve dhcp options. + */ + +typedef struct { + void * * array; /* malloc'd array of pointers */ + int size; /* number of elements in array */ + int count; /* number of occupied elements */ +} ptrlist_t; + +typedef ptrlist_t dhcpol_t; + +#ifdef __APPLE_API_PRIVATE + +void dhcpol_init(dhcpol_t * list); +void dhcpol_free(dhcpol_t * list); +int dhcpol_count(dhcpol_t * list); +boolean_t dhcpol_add(dhcpol_t * list, void * element); +void * dhcpol_element(dhcpol_t * list, int i); +boolean_t dhcpol_concat(dhcpol_t * list, dhcpol_t * extra); +boolean_t dhcpol_parse_buffer(dhcpol_t * list, void * buffer, + int length, unsigned char * err); +void * dhcpol_find(dhcpol_t * list, int tag, int * len_p, + int * start); +void * dhcpol_get(dhcpol_t * list, int tag, int * len_p); +boolean_t dhcpol_parse_packet(dhcpol_t * options, + struct dhcp * pkt, int len, + unsigned char * err); +boolean_t dhcpol_parse_vendor(dhcpol_t * vendor, + dhcpol_t * options, + unsigned char * err); +void dhcpol_print(dhcpol_t * list); +#endif /* __APPLE_API_PRIVATE */ +#endif _NETINET_DHCP_OPTIONS_H diff --git a/bsd/netinet/icmp6.h b/bsd/netinet/icmp6.h index 14281112c..0a3f67a7f 100644 --- a/bsd/netinet/icmp6.h +++ b/bsd/netinet/icmp6.h @@ -19,7 +19,7 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* $KAME: icmp6.h,v 1.9 2000/03/09 21:09:16 itojun Exp $ */ +/* $KAME: icmp6.h,v 1.46 2001/04/27 15:09:48 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -87,6 +87,7 @@ #ifndef _NETINET_ICMP6_H_ #define _NETINET_ICMP6_H_ +#include #define ICMPV6_PLD_MAXLEN 1232 /* IPV6_MMTU - sizeof(struct ip6_hdr) - sizeof(struct icmp6_hdr) */ @@ -141,10 +142,13 @@ struct icmp6_hdr { #define ICMP6_NI_REPLY 140 /* node information reply */ /* The definitions below are experimental. TBA */ -#define MLD6_MTRACE_RESP 141 /* mtrace response(to sender) */ -#define MLD6_MTRACE 142 /* mtrace messages */ +#define MLD6_MTRACE_RESP 200 /* mtrace response(to sender) */ +#define MLD6_MTRACE 201 /* mtrace messages */ -#define ICMP6_MAXTYPE 142 +#define ICMP6_HADISCOV_REQUEST 202 /* XXX To be defined */ +#define ICMP6_HADISCOV_REPLY 203 /* XXX To be defined */ + +#define ICMP6_MAXTYPE 203 #define ICMP6_DST_UNREACH_NOROUTE 0 /* no route to destination */ #define ICMP6_DST_UNREACH_ADMIN 1 /* administratively prohibited */ @@ -162,7 +166,11 @@ struct icmp6_hdr { #define ICMP6_INFOMSG_MASK 0x80 /* all informational messages */ -#define ICMP6_NI_SUCESS 0 /* node information successful reply */ +#define ICMP6_NI_SUBJ_IPV6 0 /* Query Subject is an IPv6 address */ +#define ICMP6_NI_SUBJ_FQDN 1 /* Query Subject is a Domain name */ +#define ICMP6_NI_SUBJ_IPV4 2 /* Query Subject is an IPv4 address */ + +#define ICMP6_NI_SUCCESS 0 /* node information successful reply */ #define ICMP6_NI_REFUSED 1 /* node information request is refused */ #define ICMP6_NI_UNKNOWN 2 /* unknown Qtype */ @@ -217,6 +225,18 @@ struct nd_router_advert { /* router advertisement */ #define ND_RA_FLAG_MANAGED 0x80 #define ND_RA_FLAG_OTHER 0x40 #define ND_RA_FLAG_HA 0x20 + +/* + * Router preference values based on draft-draves-ipngwg-router-selection-01. + * These are non-standard definitions. + */ +#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */ + +#define ND_RA_FLAG_RTPREF_HIGH 0x08 /* 00001000 */ +#define ND_RA_FLAG_RTPREF_MEDIUM 0x00 /* 00000000 */ +#define ND_RA_FLAG_RTPREF_LOW 0x18 /* 00011000 */ +#define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */ + #define nd_ra_router_lifetime nd_ra_hdr.icmp6_data16[1] struct nd_neighbor_solicit { /* neighbor solicitation */ @@ -275,8 +295,8 @@ struct nd_opt_hdr { /* Neighbor discovery option header */ #define ND_OPT_PREFIX_INFORMATION 3 #define ND_OPT_REDIRECTED_HEADER 4 #define ND_OPT_MTU 5 -#define ND_OPT_ADV_INTERVAL 7 /* MIPv6 */ -#define ND_OPT_HA_INFORMATION 8 /* MIPv6 */ + +#define ND_OPT_ROUTE_INFO 200 /* draft-ietf-ipngwg-router-preference, not officially assigned yet */ struct nd_opt_prefix_info { /* prefix information */ u_int8_t nd_opt_pi_type; @@ -291,7 +311,6 @@ struct nd_opt_prefix_info { /* prefix information */ #define ND_OPT_PI_FLAG_ONLINK 0x80 #define ND_OPT_PI_FLAG_AUTO 0x40 -#define ND_OPT_PI_FLAG_RTADDR 0x20 struct nd_opt_rd_hdr { /* redirected header */ u_int8_t nd_opt_rh_type; @@ -308,19 +327,13 @@ struct nd_opt_mtu { /* MTU option */ u_int32_t nd_opt_mtu_mtu; }; -struct nd_opt_advint { /* Advertisement Interval option (MIPv6) */ - u_int8_t nd_opt_int_type; - u_int8_t nd_opt_int_len; - u_int16_t nd_opt_int_reserved; - u_int32_t nd_opt_int_interval; -}; - -struct nd_opt_hai { /* Home Agent Information option (MIPv6) */ - u_int8_t nd_opt_hai_type; - u_int8_t nd_opt_hai_len; - u_int16_t nd_opt_hai_reserved; - u_int16_t nd_opt_hai_pref; - u_int16_t nd_opt_hai_lifetime; +struct nd_opt_route_info { /* route info */ + u_int8_t nd_opt_rti_type; + u_int8_t nd_opt_rti_len; + u_int8_t nd_opt_rti_prefixlen; + u_int8_t nd_opt_rti_flags; + u_int32_t nd_opt_rti_lifetime; + /* followed by prefix */ }; /* @@ -330,7 +343,7 @@ struct nd_opt_hai { /* Home Agent Information option (MIPv6) */ struct icmp6_namelookup { struct icmp6_hdr icmp6_nl_hdr; u_int8_t icmp6_nl_nonce[8]; - u_int32_t icmp6_nl_ttl; + int32_t icmp6_nl_ttl; #if 0 u_int8_t icmp6_nl_len; u_int8_t icmp6_nl_name[3]; @@ -353,11 +366,12 @@ struct icmp6_nodeinfo { #define ni_qtype icmp6_ni_hdr.icmp6_data16[0] #define ni_flags icmp6_ni_hdr.icmp6_data16[1] - #define NI_QTYPE_NOOP 0 /* NOOP */ #define NI_QTYPE_SUPTYPES 1 /* Supported Qtypes */ -#define NI_QTYPE_FQDN 2 /* FQDN */ -#define NI_QTYPE_NODEADDR 3 /* Node Addresses. XXX: spec says 2, but it may be a typo... */ +#define NI_QTYPE_FQDN 2 /* FQDN (draft 04) */ +#define NI_QTYPE_DNSNAME 2 /* DNS Name */ +#define NI_QTYPE_NODEADDR 3 /* Node Addresses */ +#define NI_QTYPE_IPV4ADDR 4 /* IPv4 Addresses */ #if BYTE_ORDER == BIG_ENDIAN #define NI_SUPTYPE_FLAG_COMPRESS 0x1 @@ -412,38 +426,24 @@ struct ni_reply_fqdn { /* * Router Renumbering. as router-renum-08.txt */ -#if BYTE_ORDER == BIG_ENDIAN /* net byte order */ struct icmp6_router_renum { /* router renumbering header */ struct icmp6_hdr rr_hdr; - u_int8_t rr_segnum; - u_int8_t rr_test : 1; - u_int8_t rr_reqresult : 1; - u_int8_t rr_forceapply : 1; - u_int8_t rr_specsite : 1; - u_int8_t rr_prevdone : 1; - u_int8_t rr_flags_reserved : 3; - u_int16_t rr_maxdelay; - u_int32_t rr_reserved; + u_int8_t rr_segnum; + u_int8_t rr_flags; + u_int16_t rr_maxdelay; + u_int32_t rr_reserved; }; -#elif BYTE_ORDER == LITTLE_ENDIAN -struct icmp6_router_renum { /* router renumbering header */ - struct icmp6_hdr rr_hdr; - u_int8_t rr_segnum; - u_int8_t rr_flags_reserved : 3; - u_int8_t rr_prevdone : 1; - u_int8_t rr_specsite : 1; - u_int8_t rr_forceapply : 1; - u_int8_t rr_reqresult : 1; - u_int8_t rr_test : 1; - u_int16_t rr_maxdelay; - u_int32_t rr_reserved; -}; -#endif /* BYTE_ORDER */ -#define rr_type rr_hdr.icmp6_type -#define rr_code rr_hdr.icmp6_code -#define rr_cksum rr_hdr.icmp6_cksum -#define rr_seqnum rr_hdr.icmp6_data32[0] +#define ICMP6_RR_FLAGS_TEST 0x80 +#define ICMP6_RR_FLAGS_REQRESULT 0x40 +#define ICMP6_RR_FLAGS_FORCEAPPLY 0x20 +#define ICMP6_RR_FLAGS_SPECSITE 0x10 +#define ICMP6_RR_FLAGS_PREVDONE 0x08 + +#define rr_type rr_hdr.icmp6_type +#define rr_code rr_hdr.icmp6_code +#define rr_cksum rr_hdr.icmp6_cksum +#define rr_seqnum rr_hdr.icmp6_data32[0] struct rr_pco_match { /* match prefix part */ u_int8_t rpm_code; @@ -453,7 +453,7 @@ struct rr_pco_match { /* match prefix part */ u_int8_t rpm_minlen; u_int8_t rpm_maxlen; u_int16_t rpm_reserved; - struct in6_addr rpm_prefix; + struct in6_addr rpm_prefix; }; #define RPM_PCO_ADD 1 @@ -461,67 +461,41 @@ struct rr_pco_match { /* match prefix part */ #define RPM_PCO_SETGLOBAL 3 #define RPM_PCO_MAX 4 -#if BYTE_ORDER == BIG_ENDIAN /* net byte order */ struct rr_pco_use { /* use prefix part */ u_int8_t rpu_uselen; u_int8_t rpu_keeplen; - u_int8_t rpu_mask_onlink : 1; - u_int8_t rpu_mask_autonomous : 1; - u_int8_t rpu_mask_reserved : 6; - u_int8_t rpu_onlink : 1; - u_int8_t rpu_autonomous : 1; - u_int8_t rpu_raflags_reserved : 6; + u_int8_t rpu_ramask; + u_int8_t rpu_raflags; u_int32_t rpu_vltime; u_int32_t rpu_pltime; - u_int32_t rpu_decr_vltime : 1; - u_int32_t rpu_decr_pltime : 1; - u_int32_t rpu_flags_reserved : 6; - u_int32_t rpu_reserved : 24; - struct in6_addr rpu_prefix; + u_int32_t rpu_flags; + struct in6_addr rpu_prefix; }; +#define ICMP6_RR_PCOUSE_RAFLAGS_ONLINK 0x80 +#define ICMP6_RR_PCOUSE_RAFLAGS_AUTO 0x40 + +#if BYTE_ORDER == BIG_ENDIAN +#define ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME 0x80000000 +#define ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME 0x40000000 #elif BYTE_ORDER == LITTLE_ENDIAN -struct rr_pco_use { /* use prefix part */ - u_int8_t rpu_uselen; - u_int8_t rpu_keeplen; - u_int8_t rpu_mask_reserved : 6; - u_int8_t rpu_mask_autonomous : 1; - u_int8_t rpu_mask_onlink : 1; - u_int8_t rpu_raflags_reserved : 6; - u_int8_t rpu_autonomous : 1; - u_int8_t rpu_onlink : 1; - u_int32_t rpu_vltime; - u_int32_t rpu_pltime; - u_int32_t rpu_flags_reserved : 6; - u_int32_t rpu_decr_pltime : 1; - u_int32_t rpu_decr_vltime : 1; - u_int32_t rpu_reserved : 24; - struct in6_addr rpu_prefix; -}; -#endif /* BYTE_ORDER */ +#define ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME 0x80 +#define ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME 0x40 +#endif -#if BYTE_ORDER == BIG_ENDIAN /* net byte order */ struct rr_result { /* router renumbering result message */ - u_int8_t rrr_reserved; - u_int8_t rrr_flags_reserved : 6; - u_int8_t rrr_outofbound : 1; - u_int8_t rrr_forbidden : 1; + u_int16_t rrr_flags; u_int8_t rrr_ordinal; u_int8_t rrr_matchedlen; u_int32_t rrr_ifid; - struct in6_addr rrr_prefix; + struct in6_addr rrr_prefix; }; +#if BYTE_ORDER == BIG_ENDIAN +#define ICMP6_RR_RESULT_FLAGS_OOB 0x0002 +#define ICMP6_RR_RESULT_FLAGS_FORBIDDEN 0x0001 #elif BYTE_ORDER == LITTLE_ENDIAN -struct rr_result { /* router renumbering result message */ - u_int8_t rrr_reserved; - u_int8_t rrr_forbidden : 1; - u_int8_t rrr_outofbound : 1; - u_int8_t rrr_flags_reserved : 6; - u_int8_t rrr_ordinal; - u_int8_t rrr_matchedlen; - u_int32_t rrr_ifid; - struct in6_addr rrr_prefix; -}; -#endif /* BYTE_ORDER */ +#define ICMP6_RR_RESULT_FLAGS_OOB 0x0200 +#define ICMP6_RR_RESULT_FLAGS_FORBIDDEN 0x0100 +#endif /* * icmp6 filter structures. @@ -532,6 +506,7 @@ struct icmp6_filter { }; #ifdef KERNEL +#ifdef __APPLE_API_UNSTABLE #define ICMP6_FILTER_SETPASSALL(filterp) \ do { \ int i; u_char *p; \ @@ -541,6 +516,7 @@ do { \ } while (0) #define ICMP6_FILTER_SETBLOCKALL(filterp) \ bzero(filterp, sizeof(struct icmp6_filter)) +#endif /* __APPLE_API_UNSTABLE */ #else /* KERNEL */ #define ICMP6_FILTER_SETPASSALL(filterp) \ memset(filterp, 0xff, sizeof(struct icmp6_filter)) @@ -557,10 +533,27 @@ do { \ #define ICMP6_FILTER_WILLBLOCK(type, filterp) \ ((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type) & 31))) == 0) +#ifdef __APPLE_API_UNSTABLE /* * Variables related to this implementation * of the internet control message protocol version 6. */ +struct icmp6errstat { + u_quad_t icp6errs_dst_unreach_noroute; + u_quad_t icp6errs_dst_unreach_admin; + u_quad_t icp6errs_dst_unreach_beyondscope; + u_quad_t icp6errs_dst_unreach_addr; + u_quad_t icp6errs_dst_unreach_noport; + u_quad_t icp6errs_packet_too_big; + u_quad_t icp6errs_time_exceed_transit; + u_quad_t icp6errs_time_exceed_reassembly; + u_quad_t icp6errs_paramprob_header; + u_quad_t icp6errs_paramprob_nextheader; + u_quad_t icp6errs_paramprob_option; + u_quad_t icp6errs_redirect; /* we regard redirect as an error here */ + u_quad_t icp6errs_unknown; +}; + struct icmp6stat { /* statistics related to icmp6 packets generated */ u_quad_t icp6s_error; /* # of calls to icmp6_error */ @@ -575,6 +568,32 @@ struct icmp6stat { u_quad_t icp6s_reflect; /* number of responses */ u_quad_t icp6s_inhist[256]; u_quad_t icp6s_nd_toomanyopt; /* too many ND options */ + struct icmp6errstat icp6s_outerrhist; +#define icp6s_odst_unreach_noroute \ + icp6s_outerrhist.icp6errs_dst_unreach_noroute +#define icp6s_odst_unreach_admin icp6s_outerrhist.icp6errs_dst_unreach_admin +#define icp6s_odst_unreach_beyondscope \ + icp6s_outerrhist.icp6errs_dst_unreach_beyondscope +#define icp6s_odst_unreach_addr icp6s_outerrhist.icp6errs_dst_unreach_addr +#define icp6s_odst_unreach_noport icp6s_outerrhist.icp6errs_dst_unreach_noport +#define icp6s_opacket_too_big icp6s_outerrhist.icp6errs_packet_too_big +#define icp6s_otime_exceed_transit \ + icp6s_outerrhist.icp6errs_time_exceed_transit +#define icp6s_otime_exceed_reassembly \ + icp6s_outerrhist.icp6errs_time_exceed_reassembly +#define icp6s_oparamprob_header icp6s_outerrhist.icp6errs_paramprob_header +#define icp6s_oparamprob_nextheader \ + icp6s_outerrhist.icp6errs_paramprob_nextheader +#define icp6s_oparamprob_option icp6s_outerrhist.icp6errs_paramprob_option +#define icp6s_oredirect icp6s_outerrhist.icp6errs_redirect +#define icp6s_ounknown icp6s_outerrhist.icp6errs_unknown + u_quad_t icp6s_pmtuchg; /* path MTU changes */ + u_quad_t icp6s_nd_badopt; /* bad ND options */ + u_quad_t icp6s_badns; /* bad neighbor solicitation */ + u_quad_t icp6s_badna; /* bad neighbor advertisement */ + u_quad_t icp6s_badrs; /* bad router advertisement */ + u_quad_t icp6s_badra; /* bad router advertisement */ + u_quad_t icp6s_badredirect; /* bad redirect message */ }; /* @@ -583,7 +602,6 @@ struct icmp6stat { #define ICMPV6CTL_STATS 1 #define ICMPV6CTL_REDIRACCEPT 2 /* accept/process redirects */ #define ICMPV6CTL_REDIRTIMEOUT 3 /* redirect cache time */ -#define ICMPV6CTL_ERRRATELIMIT 5 /* ICMPv6 error rate limitation */ #define ICMPV6CTL_ND6_PRUNE 6 #define ICMPV6CTL_ND6_DELAY 8 #define ICMPV6CTL_ND6_UMAXTRIES 9 @@ -591,7 +609,14 @@ struct icmp6stat { #define ICMPV6CTL_ND6_USELOOPBACK 11 /*#define ICMPV6CTL_ND6_PROXYALL 12 obsoleted, do not reuse here */ #define ICMPV6CTL_NODEINFO 13 -#define ICMPV6CTL_MAXID 14 +#define ICMPV6CTL_ERRPPSLIMIT 14 /* ICMPv6 error pps limitation */ +#define ICMPV6CTL_ND6_MAXNUDHINT 15 +#define ICMPV6CTL_MTUDISC_HIWAT 16 +#define ICMPV6CTL_MTUDISC_LOWAT 17 +#define ICMPV6CTL_ND6_DEBUG 18 +#define ICMPV6CTL_ND6_DRLIST 19 +#define ICMPV6CTL_ND6_PRLIST 20 +#define ICMPV6CTL_MAXID 21 #define ICMPV6CTL_NAMES { \ { 0, 0 }, \ @@ -599,7 +624,7 @@ struct icmp6stat { { "rediraccept", CTLTYPE_INT }, \ { "redirtimeout", CTLTYPE_INT }, \ { 0, 0 }, \ - { "errratelimit", CTLTYPE_INT }, \ + { 0, 0 }, \ { "nd6_prune", CTLTYPE_INT }, \ { 0, 0 }, \ { "nd6_delay", CTLTYPE_INT }, \ @@ -608,27 +633,15 @@ struct icmp6stat { { "nd6_useloopback", CTLTYPE_INT }, \ { 0, 0 }, \ { "nodeinfo", CTLTYPE_INT }, \ + { "errppslimit", CTLTYPE_INT }, \ + { "nd6_maxnudhint", CTLTYPE_INT }, \ + { "mtudisc_hiwat", CTLTYPE_INT }, \ + { "mtudisc_lowat", CTLTYPE_INT }, \ + { "nd6_debug", CTLTYPE_INT }, \ + { 0, 0 }, \ + { 0, 0 }, \ } - -#ifdef __bsdi__ -#define ICMPV6CTL_VARS { \ - 0, \ - 0, \ - &icmp6_rediraccept, \ - &icmp6_redirtimeout, \ - 0, \ - 0, \ - &icmp6errratelim, \ - &nd6_prune, \ - 0, \ - &nd6_delay, \ - &nd6_umaxtries, \ - &nd6_mmaxtries, \ - &nd6_useloopback, \ - 0, \ - &icmp6_nodeinfo, \ -} -#endif +#endif /* __APPLE_API_UNSTABLE */ #define RTF_PROBEMTU RTF_PROTO1 @@ -638,6 +651,7 @@ struct rtentry; struct rttimer; struct in6_multi; # endif +#ifdef __APPLE_API_PRIVATE void icmp6_init __P((void)); void icmp6_paramerror __P((struct mbuf *, int)); void icmp6_error __P((struct mbuf *, int, int, int)); @@ -647,13 +661,9 @@ void icmp6_reflect __P((struct mbuf *, size_t)); void icmp6_prepare __P((struct mbuf *)); void icmp6_redirect_input __P((struct mbuf *, int)); void icmp6_redirect_output __P((struct mbuf *, struct rtentry *)); -#ifdef __bsdi__ -int icmp6_sysctl __P((int *, u_int, void *, size_t *, void *, size_t)); -void icmp6_mtuexpire __P((struct rtentry *, struct rttimer *)); -#endif /*__bsdi__*/ -#if defined(__NetBSD__) || defined(__OpenBSD__) -int icmp6_sysctl __P((int *, u_int, void *, size_t *, void *, size_t)); -#endif + +struct ip6ctlparam; +void icmp6_mtudisc_update __P((struct ip6ctlparam *, int)); /* XXX: is this the right place for these macros? */ #define icmp6_ifstat_inc(ifp, tag) \ @@ -720,6 +730,7 @@ do { \ extern int icmp6_rediraccept; /* accept/process redirects */ extern int icmp6_redirtimeout; /* cache time for redirect routes */ +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ #endif /* !_NETINET_ICMP6_H_ */ diff --git a/bsd/netinet/icmp_var.h b/bsd/netinet/icmp_var.h index f8e7633e5..56005f1ab 100644 --- a/bsd/netinet/icmp_var.h +++ b/bsd/netinet/icmp_var.h @@ -52,16 +52,13 @@ * SUCH DAMAGE. * * @(#)icmp_var.h 8.1 (Berkeley) 6/10/93 + * $FreeBSD: src/sys/netinet/icmp_var.h,v 1.15.2.1 2001/02/24 21:35:18 bmilekic Exp $ */ #ifndef _NETINET_ICMP_VAR_H_ #define _NETINET_ICMP_VAR_H_ - -#ifdef KERNEL -#if ISFB31 -#include "opt_icmp_bandlim.h" /* for ICMP_BANDLIM */ -#endif -#endif +#include +#ifdef __APPLE_API_UNSTABLE /* * Variables related to this implementation @@ -98,12 +95,21 @@ struct icmpstat { { "stats", CTLTYPE_STRUCT }, \ { "icmplim", CTLTYPE_INT }, \ } +#endif /* __APPLE_API_UNSTABLE */ #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE SYSCTL_DECL(_net_inet_icmp); #ifdef ICMP_BANDLIM extern int badport_bandlim __P((int)); #endif +#define BANDLIM_UNLIMITED -1 +#define BANDLIM_ICMP_UNREACH 0 +#define BANDLIM_ICMP_ECHO 1 +#define BANDLIM_ICMP_TSTAMP 2 +#define BANDLIM_RST_CLOSEDPORT 3 /* No connection, and no listeners */ +#define BANDLIM_RST_OPENPORT 4 /* No connection, listener */ +#define BANDLIM_MAX 4 +#endif /* __APPLE_API_PRIVATE */ #endif - #endif diff --git a/bsd/netinet/if_atm.c b/bsd/netinet/if_atm.c index cfc61835f..f4639f632 100644 --- a/bsd/netinet/if_atm.c +++ b/bsd/netinet/if_atm.c @@ -51,15 +51,14 @@ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/sys/netinet/if_atm.c,v 1.8 1999/12/07 17:39:06 shin Exp $ */ /* * IP <=> ATM address resolution. */ -#include "opt_inet.h" -#include "opt_natm.h" - #if defined(INET) || defined(INET6) #include @@ -258,7 +257,7 @@ register struct atm_pseudohdr *desten; /* OUT */ if (rt == NULL) { rt = RTALLOC1(dst, 0); if (rt == NULL) goto bad; /* failed */ - rt->rt_refcnt--; /* don't keep LL references */ + rtunref(rt); /* don't keep LL references */ if ((rt->rt_flags & RTF_GATEWAY) != 0 || (rt->rt_flags & RTF_LLINFO) == 0 || /* XXX: are we using LLINFO? */ diff --git a/bsd/netinet/if_atm.h b/bsd/netinet/if_atm.h index 79417f4e0..9c31d421b 100644 --- a/bsd/netinet/if_atm.h +++ b/bsd/netinet/if_atm.h @@ -19,6 +19,7 @@ * * @APPLE_LICENSE_HEADER_END@ */ +/* $FreeBSD: src/sys/netinet/if_atm.h,v 1.2.6.1 2000/08/03 01:07:02 peter Exp $ */ /* $NetBSD: if_atm.h,v 1.2 1996/07/03 17:17:17 chuck Exp $ */ /* @@ -56,7 +57,9 @@ /* * if_atm.h */ +#include +#ifdef __APPLE_API_PRIVATE struct atm_pseudohdr; struct mbuf; struct rtentry; @@ -65,3 +68,4 @@ struct sockaddr; void atm_rtrequest __P((int, struct rtentry *, struct sockaddr *)); int atmresolve __P((struct rtentry *, struct mbuf *, struct sockaddr *, struct atm_pseudohdr *)); +#endif /* __APPLE_API_PRIVATE */ diff --git a/bsd/netinet/if_ether.c b/bsd/netinet/if_ether.c index 3cd5fb6b1..07e99d6eb 100644 --- a/bsd/netinet/if_ether.c +++ b/bsd/netinet/if_ether.c @@ -52,6 +52,7 @@ * SUCH DAMAGE. * * @(#)if_ether.c 8.1 (Berkeley) 6/10/93 + * $FreeBSD: src/sys/netinet/if_ether.c,v 1.64.2.11 2001/07/25 17:27:56 jlemon Exp $ */ /* @@ -60,16 +61,10 @@ * add "inuse/lock" bit (or ref. count) along with valid bit */ -#if NOTFB31 -#include "opt_inet.h" -#include "opt_bdg.h" -#endif - #include #include - +#include #include - #include #include #include @@ -78,13 +73,21 @@ #include #include +#include #include #include +#include +#if BRIDGE +#include +#include +#endif #include #include #include +#include + #define SIN(s) ((struct sockaddr_in *)s) #define SDL(s) ((struct sockaddr_dl *)s) @@ -159,16 +162,13 @@ static void arptimer(ignored_arg) void *ignored_arg; { - int s ; - register struct llinfo_arp *la; +#ifdef __APPLE__ + boolean_t funnel_state = thread_funnel_set(network_flock, TRUE); +#endif + int s = splnet(); + register struct llinfo_arp *la = llinfo_arp.lh_first; struct llinfo_arp *ola; - boolean_t funnel_state; - - funnel_state = thread_funnel_set(network_flock, TRUE); - s = splnet(); - la = llinfo_arp.lh_first; - timeout(arptimer, (caddr_t)0, arpt_prune * hz); while ((ola = la) != 0) { register struct rtentry *rt = la->la_rt; @@ -177,8 +177,9 @@ arptimer(ignored_arg) arptfree(ola); /* timer has expired, clear */ } splx(s); +#ifdef __APPLE__ (void) thread_funnel_set(network_flock, FALSE); - +#endif } /* @@ -199,6 +200,9 @@ arp_rtrequest(req, rt, sa) arpinit_done = 1; LIST_INIT(&llinfo_arp); timeout(arptimer, (caddr_t)0, hz); +#ifndef __APPLE__ + register_netisr(NETISR_ARP, arpintr); +#endif } if (rt->rt_flags & RTF_GATEWAY) return; @@ -273,7 +277,7 @@ arp_rtrequest(req, rt, sa) if (in_broadcast(SIN(rt_key(rt))->sin_addr, rt->rt_ifp)) { memcpy(LLADDR(SDL(gate)), etherbroadcastaddr, 6); SDL(gate)->sdl_alen = 6; - rt->rt_expire = 0; + rt->rt_expire = time_second; } #endif @@ -311,31 +315,27 @@ arp_rtrequest(req, rt, sa) } } - - - /* * Broadcast an ARP packet, asking who has addr on interface ac. */ void arpwhohas(ac, addr) - register struct arpcom *ac; - register struct in_addr *addr; -{ struct ifnet *ifp = (struct ifnet *)ac; + struct arpcom *ac; + struct in_addr *addr; +{ + struct ifnet *ifp = (struct ifnet *)ac; struct ifaddr *ifa = TAILQ_FIRST(&ifp->if_addrhead); - while (ifa) - { if (ifa->ifa_addr->sa_family == AF_INET) - { arprequest(ac, &SIN(ifa->ifa_addr)->sin_addr, addr, ac->ac_enaddr); + while (ifa) { + if (ifa->ifa_addr->sa_family == AF_INET) { + arprequest(ac, &SIN(ifa->ifa_addr)->sin_addr, addr, ac->ac_enaddr); return; } - ifa = TAILQ_NEXT(ifa, ifa_link); + ifa = TAILQ_NEXT(ifa, ifa_link); } return; /* XXX */ } - - /* * Broadcast an ARP request. Caller specifies: * - arp header source ip address @@ -352,19 +352,47 @@ arprequest(ac, sip, tip, enaddr) register struct ether_header *eh; register struct ether_arp *ea; struct sockaddr sa; + static u_char llcx[] = { 0x82, 0x40, LLC_SNAP_LSAP, LLC_SNAP_LSAP, + LLC_UI, 0x00, 0x00, 0x00, 0x08, 0x06 }; if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL) return; - m->m_len = sizeof(*ea); - m->m_pkthdr.len = sizeof(*ea); m->m_pkthdr.rcvif = (struct ifnet *)0; - MH_ALIGN(m, sizeof(*ea)); - ea = mtod(m, struct ether_arp *); - eh = (struct ether_header *)sa.sa_data; - bzero((caddr_t)ea, sizeof (*ea)); - (void)memcpy(eh->ether_dhost, etherbroadcastaddr, sizeof(eh->ether_dhost)); - eh->ether_type = htons(ETHERTYPE_ARP); /* if_output will not swap */ - ea->arp_hrd = htons(ARPHRD_ETHER); + switch (ac->ac_if.if_type) { + case IFT_ISO88025: + m->m_len = sizeof(*ea) + sizeof(llcx); + m->m_pkthdr.len = sizeof(*ea) + sizeof(llcx); + MH_ALIGN(m, sizeof(*ea) + sizeof(llcx)); + (void)memcpy(mtod(m, caddr_t), llcx, sizeof(llcx)); + (void)memcpy(sa.sa_data, etherbroadcastaddr, 6); + (void)memcpy(sa.sa_data + 6, enaddr, 6); + sa.sa_data[6] |= TR_RII; + sa.sa_data[12] = TR_AC; + sa.sa_data[13] = TR_LLC_FRAME; + ea = (struct ether_arp *)(mtod(m, char *) + sizeof(llcx)); + bzero((caddr_t)ea, sizeof (*ea)); + ea->arp_hrd = htons(ARPHRD_IEEE802); + break; + case IFT_FDDI: + case IFT_ETHER: + /* + * This may not be correct for types not explicitly + * listed, but this is our best guess + */ + default: + 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)); + /* if_output will not swap */ + eh->ether_type = htons(ETHERTYPE_ARP); + (void)memcpy(eh->ether_dhost, etherbroadcastaddr, + sizeof(eh->ether_dhost)); + ea->arp_hrd = htons(ARPHRD_ETHER); + break; + } 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 */ @@ -374,7 +402,7 @@ arprequest(ac, sip, tip, enaddr) (void)memcpy(ea->arp_tpa, tip, sizeof(ea->arp_tpa)); sa.sa_family = AF_UNSPEC; sa.sa_len = sizeof(sa); - dlil_output((u_long) ac, m, 0, &sa, 0); + dlil_output(((struct ifnet *)ac)->if_data.default_proto, m, 0, &sa, 0); } /* @@ -396,7 +424,7 @@ arpresolve(ac, rt, m, dst, desten, rt0) register u_char *desten; struct rtentry *rt0; { - register struct llinfo_arp *la = 0; + struct llinfo_arp *la = 0; struct sockaddr_dl *sdl; if (m->m_flags & M_BCAST) { /* broadcast */ @@ -431,6 +459,14 @@ arpresolve(ac, rt, m, dst, desten, rt0) bcopy(LLADDR(sdl), desten, sdl->sdl_alen); return 1; } + /* + * If ARP is disabled on this interface, stop. + * XXX + * Probably should not allocate empty llinfo struct if we are + * not going to be sending out an arp request. + */ + if (ac->ac_if.if_flags & IFF_NOARP) + return (0); /* * There is an arptab entry, but no ethernet address * response yet. Replace the held mbuf with this @@ -475,27 +511,41 @@ arpintr() splx(s); if (m == 0 || (m->m_flags & M_PKTHDR) == 0) panic("arpintr"); - if (m->m_len >= sizeof(struct arphdr) && - (ar = mtod(m, struct arphdr *)) && - ntohs(ar->ar_hrd) == ARPHRD_ETHER && - m->m_len >= - sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln) + + if (m->m_len < sizeof(struct arphdr) && + ((m = m_pullup(m, sizeof(struct arphdr))) == NULL)) { + log(LOG_ERR, "arp: runt packet -- m_pullup failed\n"); + continue; + } + ar = mtod(m, struct arphdr *); + + if (ntohs(ar->ar_hrd) != ARPHRD_ETHER + && ntohs(ar->ar_hrd) != ARPHRD_IEEE802) { + log(LOG_ERR, + "arp: unknown hardware address format (0x%2D)\n", + (unsigned char *)&ar->ar_hrd, ""); + m_freem(m); + continue; + } - switch (ntohs(ar->ar_pro)) { + if (m->m_pkthdr.len < sizeof(struct arphdr) + 2 * ar->ar_hln + + 2 * ar->ar_pln) { + log(LOG_ERR, "arp: runt packet\n"); + m_freem(m); + continue; + } -#if INET - case ETHERTYPE_IP: - in_arpinput(m); - continue; + switch (ntohs(ar->ar_pro)) { +#ifdef INET + case ETHERTYPE_IP: + in_arpinput(m); + continue; #endif - } + } m_freem(m); } } -NETISR_SET(NETISR_ARP, arpintr); - - #if INET /* * ARP for Internet protocols on 10 Mb/s Ethernet. @@ -511,6 +561,12 @@ NETISR_SET(NETISR_ARP, arpintr); * We no longer reply to requests for ETHERTYPE_TRAIL protocol either, * but formerly didn't normally send requests. */ +static int log_arp_wrong_iface = 0; + +SYSCTL_INT(_net_link_ether_inet, OID_AUTO, log_arp_wrong_iface, CTLFLAG_RW, + &log_arp_wrong_iface, 0, + "log arp packets arriving on the wrong interface"); + static void in_arpinput(m) struct mbuf *m; @@ -518,48 +574,65 @@ in_arpinput(m) register struct ether_arp *ea; register struct arpcom *ac = (struct arpcom *)m->m_pkthdr.rcvif; struct ether_header *eh; + struct iso88025_header *th = (struct iso88025_header *)0; register struct llinfo_arp *la = 0; register struct rtentry *rt; struct in_ifaddr *ia, *maybe_ia = 0; struct sockaddr_dl *sdl; struct sockaddr sa; struct in_addr isaddr, itaddr, myaddr; - int op; + int op, rif_len; unsigned char buf[18]; + unsigned char buf2[18]; + + if (m->m_len < sizeof(struct ether_arp) && + (m = m_pullup(m, sizeof(struct ether_arp))) == NULL) { + log(LOG_ERR, "in_arp: runt packet -- m_pullup failed\n"); + return; + } ea = mtod(m, struct ether_arp *); op = ntohs(ea->arp_op); (void)memcpy(&isaddr, ea->arp_spa, sizeof (isaddr)); (void)memcpy(&itaddr, ea->arp_tpa, sizeof (itaddr)); +#if __APPLE__ /* Don't respond to requests for 0.0.0.0 */ if (itaddr.s_addr == 0 && op == ARPOP_REQUEST) { m_freem(m); return; } +#endif - for (ia = in_ifaddrhead.tqh_first; ia; ia = ia->ia_link.tqe_next) -#if BRIDGE + for (ia = in_ifaddrhead.tqh_first; ia; ia = ia->ia_link.tqe_next) { /* * For a bridge, we want to check the address irrespective * of the receive interface. (This will change slightly * when we have clusters of interfaces). */ - { +#if BRIDGE +#define BRIDGE_TEST (do_bridge) #else - if (ia->ia_ifp == &ac->ac_if) { +#define BRIDGE_TEST (0) /* cc will optimise the test away */ #endif + if ((BRIDGE_TEST) || (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)) + (isaddr.s_addr == ia->ia_addr.sin_addr.s_addr)) { break; + } } + } if (maybe_ia == 0) { m_freem(m); return; } 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))) { + m_freem(m); /* it's from me, ignore it. */ + return; + } if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)etherbroadcastaddr, sizeof (ea->arp_sha))) { log(LOG_ERR, @@ -569,46 +642,81 @@ in_arpinput(m) return; } if (isaddr.s_addr == myaddr.s_addr) { - log(LOG_ERR, - "duplicate IP address %s sent from ethernet address %s\n", - inet_ntoa(isaddr), ether_sprintf(buf, ea->arp_sha)); + log(LOG_ERR, + "duplicate IP address %s sent from ethernet address %s\n", + inet_ntoa(isaddr), ether_sprintf(buf, ea->arp_sha)); itaddr = myaddr; goto reply; } la = arplookup(isaddr.s_addr, itaddr.s_addr == myaddr.s_addr, 0); if (la && (rt = la->la_rt) && (sdl = SDL(rt->rt_gateway))) { -#ifndef BRIDGE /* the following is not an error when doing bridging */ - if (rt->rt_ifp != &ac->ac_if) { - log(LOG_ERR, "arp: %s is on %s%d but got reply from %6D on %s%d\n", + /* the following is not an error when doing bridging */ + if (!BRIDGE_TEST && rt->rt_ifp != &ac->ac_if) { + if (log_arp_wrong_iface) + log(LOG_ERR, "arp: %s is on %s%d but got reply from %s on %s%d\n", inet_ntoa(isaddr), rt->rt_ifp->if_name, rt->rt_ifp->if_unit, - ea->arp_sha, ":", + ether_sprintf(buf, ea->arp_sha), ac->ac_if.if_name, ac->ac_if.if_unit); - goto reply; + goto reply; } -#endif if (sdl->sdl_alen && - bcmp((caddr_t)ea->arp_sha, LLADDR(sdl), sdl->sdl_alen)) + bcmp((caddr_t)ea->arp_sha, LLADDR(sdl), sdl->sdl_alen)) { if (rt->rt_expire) - log(LOG_INFO, "arp: %s moved from %6D to %6D on %s%d\n", - inet_ntoa(isaddr), (u_char *)LLADDR(sdl), ":", - ea->arp_sha, ":", + log(LOG_INFO, "arp: %s moved from %s to %s on %s%d\n", + inet_ntoa(isaddr), + ether_sprintf(buf, (u_char *)LLADDR(sdl)), + ether_sprintf(buf2, ea->arp_sha), ac->ac_if.if_name, ac->ac_if.if_unit); else { log(LOG_ERR, - "arp: %6D attempts to modify permanent entry for %s on %s%d", - ea->arp_sha, ":", inet_ntoa(isaddr), + "arp: %s attempts to modify permanent entry for %s on %s%d", + ether_sprintf(buf, ea->arp_sha), inet_ntoa(isaddr), ac->ac_if.if_name, ac->ac_if.if_unit); goto reply; } + } (void)memcpy(LLADDR(sdl), ea->arp_sha, sizeof(ea->arp_sha)); sdl->sdl_alen = sizeof(ea->arp_sha); +#ifndef __APPLE__ + /* TokenRing */ + sdl->sdl_rcf = (u_short)0; + /* + * If we receive an arp from a token-ring station over + * a token-ring nic then try to save the source + * routing info. + */ + if (ac->ac_if.if_type == IFT_ISO88025) { + th = (struct iso88025_header *)m->m_pkthdr.header; + rif_len = TR_RCF_RIFLEN(th->rcf); + if ((th->iso88025_shost[0] & TR_RII) && + (rif_len > 2)) { + sdl->sdl_rcf = th->rcf; + sdl->sdl_rcf ^= htons(TR_RCF_DIR); + memcpy(sdl->sdl_route, th->rd, rif_len - 2); + sdl->sdl_rcf &= ~htons(TR_RCF_BCST_MASK); + /* + * Set up source routing information for + * reply packet (XXX) + */ + m->m_data -= rif_len; + m->m_len += rif_len; + m->m_pkthdr.len += rif_len; + } else { + th->iso88025_shost[0] &= ~TR_RII; + } + m->m_data -= 8; + m->m_len += 8; + m->m_pkthdr.len += 8; + th->rcf = sdl->sdl_rcf; + } +#endif if (rt->rt_expire) rt->rt_expire = time_second + arpt_keep; rt->rt_flags &= ~RTF_REJECT; la->la_asked = 0; if (la->la_hold) { - dlil_output((u_long) ac, la->la_hold, rt, + dlil_output(((struct ifnet *)ac)->if_data.default_proto, la->la_hold, rt, rt_key(rt), 0); la->la_hold = 0; } @@ -671,15 +779,45 @@ reply: (void)memcpy(ea->arp_spa, &itaddr, sizeof(ea->arp_spa)); ea->arp_op = htons(ARPOP_REPLY); ea->arp_pro = htons(ETHERTYPE_IP); /* let's be sure! */ - eh = (struct ether_header *)sa.sa_data; - if (IN_LINKLOCAL(ntohl(*((u_int32_t*)ea->arp_spa)))) - (void)memcpy(eh->ether_dhost, etherbroadcastaddr, sizeof(eh->ether_dhost)); - else - (void)memcpy(eh->ether_dhost, ea->arp_tha, sizeof(eh->ether_dhost)); - eh->ether_type = htons(ETHERTYPE_ARP); + switch (ac->ac_if.if_type) { + case IFT_ISO88025: + /* Re-arrange the source/dest address */ + memcpy(th->iso88025_dhost, th->iso88025_shost, + sizeof(th->iso88025_dhost)); + memcpy(th->iso88025_shost, ac->ac_enaddr, + sizeof(th->iso88025_shost)); + /* Set the source routing bit if neccesary */ + if (th->iso88025_dhost[0] & TR_RII) { + th->iso88025_dhost[0] &= ~TR_RII; + if (TR_RCF_RIFLEN(th->rcf) > 2) + th->iso88025_shost[0] |= TR_RII; + } + /* Copy the addresses, ac and fc into sa_data */ + memcpy(sa.sa_data, th->iso88025_dhost, + sizeof(th->iso88025_dhost) * 2); + sa.sa_data[(sizeof(th->iso88025_dhost) * 2)] = TR_AC; + sa.sa_data[(sizeof(th->iso88025_dhost) * 2) + 1] = TR_LLC_FRAME; + break; + case IFT_ETHER: + case IFT_FDDI: + /* + * May not be correct for types not explictly + * listed, but it is our best guess. + */ + default: + eh = (struct ether_header *)sa.sa_data; +#ifdef __APPLE__ + if (IN_LINKLOCAL(ntohl(*((u_int32_t*)ea->arp_spa)))) + (void)memcpy(eh->ether_dhost, etherbroadcastaddr, sizeof(eh->ether_dhost)); + else +#endif + (void)memcpy(eh->ether_dhost, ea->arp_tha, sizeof(eh->ether_dhost)); + eh->ether_type = htons(ETHERTYPE_ARP); + break; + } sa.sa_family = AF_UNSPEC; sa.sa_len = sizeof(sa); - dlil_output((u_long) ac, m, 0, &sa, 0); + dlil_output(((struct ifnet *)ac)->if_data.default_proto, m, 0, &sa, 0); return; } #endif @@ -722,7 +860,7 @@ arplookup(addr, create, proxy) rt = rtalloc1((struct sockaddr *)&sin, create, 0UL); if (rt == 0) return (0); - rt->rt_refcnt--; + rtunref(rt); if (rt->rt_flags & RTF_GATEWAY) why = "host is not on local network"; diff --git a/bsd/netinet/if_ether.h b/bsd/netinet/if_ether.h index 7ac0d866e..0d9799b6b 100644 --- a/bsd/netinet/if_ether.h +++ b/bsd/netinet/if_ether.h @@ -52,20 +52,21 @@ * SUCH DAMAGE. * * @(#)if_ether.h 8.3 (Berkeley) 5/2/95 + * $FreeBSD: src/sys/netinet/if_ether.h,v 1.24 1999/12/29 04:40:58 peter Exp $ */ #ifndef _NETINET_IF_ETHER_H_ #define _NETINET_IF_ETHER_H_ - +#include #include #include #include -#include #define ea_byte ether_addr_octet - +#ifdef __APPLE__ +#ifdef __APPLE_API_UNSTABLE /* * Macro for looking up the ether_multi record for a given range of Ethernet * multicast addresses connected to a given arpcom structure. If no matching @@ -107,9 +108,9 @@ (step).e_enm = (ac)->ac_multiaddrs; \ ETHER_NEXT_MULTI((step), (enm)); \ } +#endif /* __APPLE_API_UNSTABLE */ +#endif /* __APPLE__ */ -#define ETHERTYPE_IPV6 0x86dd - /* * Macro to map an IP multicast address to an Ethernet multicast address. * The high-order 25 bits of the Ethernet address are statically assigned, @@ -132,8 +133,8 @@ * and the low-order 32 bits are taken from the low end of the IP6 address. */ #define ETHER_MAP_IPV6_MULTICAST(ip6addr, enaddr) \ -/* struct in6_addr *ip6addr; */ \ -/* u_char enaddr[ETHER_ADDR_LEN]; */ \ +/* struct in6_addr *ip6addr; */ \ +/* u_char enaddr[ETHER_ADDR_LEN]; */ \ { \ (enaddr)[0] = 0x33; \ (enaddr)[1] = 0x33; \ @@ -180,13 +181,17 @@ struct sockaddr_inarp { #define RTF_ANNOUNCE RTF_PROTO2 /* announce new arp entry */ #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE extern u_char ether_ipmulticast_min[ETHER_ADDR_LEN]; extern u_char ether_ipmulticast_max[ETHER_ADDR_LEN]; extern struct ifqueue arpintrq; int arpresolve __P((struct arpcom *, struct rtentry *, struct mbuf *, struct sockaddr *, u_char *, struct rtentry *)); +#endif /* __APPLE_API_PRIVATE */ +#ifdef __APPLE_API_UNSTABLE void arp_ifinit __P((struct arpcom *, struct ifaddr *)); +#endif /* __APPLE_API_UNSTABLE */ #endif #endif diff --git a/bsd/netinet/if_fddi.h b/bsd/netinet/if_fddi.h index b44792a77..dd33f7311 100644 --- a/bsd/netinet/if_fddi.h +++ b/bsd/netinet/if_fddi.h @@ -54,10 +54,12 @@ * SUCH DAMAGE. * * @(#)if_fddi.h 8.1 (Berkeley) 6/10/93 + * $FreeBSD: src/sys/netinet/if_fddi.h,v 1.8 1999/12/29 04:40:58 peter Exp $ */ #ifndef _NETINET_IF_FDDI_H_ #define _NETINET_IF_FDDI_H_ +#include /* * Structure of an 100Mb/s FDDI header. @@ -89,7 +91,8 @@ struct fddi_header { #define FDDIFC_LLC_SYNC 0xd0 #define FDDIFC_SMT 0x40 -#if defined(KERNEL) +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE #define fddibroadcastaddr etherbroadcastaddr #define fddi_ipmulticast_min ether_ipmulticast_min #define fddi_ipmulticast_max ether_ipmulticast_max @@ -101,7 +104,7 @@ void fddi_ifattach __P((struct ifnet *)); void fddi_input __P((struct ifnet *, struct fddi_header *, struct mbuf *)); int fddi_output __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *)); - +#endif /* __APPLE_API_PRIVATE */ #endif #endif diff --git a/bsd/netinet/if_tun.h b/bsd/netinet/if_tun.h index 6e548368a..6ffd6734b 100644 --- a/bsd/netinet/if_tun.h +++ b/bsd/netinet/if_tun.h @@ -37,7 +37,9 @@ #ifndef _NET_IF_TUN_H_ #define _NET_IF_TUN_H_ +#include +#ifdef __APPLE_API_PRIVATE struct tun_softc { u_short tun_flags; /* misc flags */ #define TUN_OPEN 0x0001 @@ -59,6 +61,7 @@ struct tun_softc { caddr_t tun_bpf; #endif }; +#endif /* __APPLE_API_PRIVATE */ /* Maximum packet size */ #define TUNMTU 1500 diff --git a/bsd/netinet/igmp.c b/bsd/netinet/igmp.c index 380540120..3dd855ca8 100644 --- a/bsd/netinet/igmp.c +++ b/bsd/netinet/igmp.c @@ -89,7 +89,9 @@ #include #include +#ifndef __APPLE__ static MALLOC_DEFINE(M_IGMP, "igmp", "igmp state"); +#endif static struct router_info * find_rti __P((struct ifnet *ifp)); @@ -154,11 +156,7 @@ find_rti(ifp) rti = rti->rti_next; } -#if ISFB31 MALLOC(rti, struct router_info *, sizeof *rti, M_IGMP, M_NOWAIT); -#else - MALLOC(rti, struct router_info *, sizeof *rti, M_TEMP, M_WAITOK); -#endif rti->rti_ifp = ifp; rti->rti_type = IGMP_V2_ROUTER; rti->rti_time = 0; @@ -505,9 +503,6 @@ igmp_sendpkt(inm, type, addr) * XXX * Do we have to worry about reentrancy here? Don't think so. */ -#if IPSEC - m->m_pkthdr.rcvif = NULL; -#endif /*IPSEC*/ ip_output(m, router_alert, &igmprt, 0, &imo); ++igmpstat.igps_snd_reports; diff --git a/bsd/netinet/igmp.h b/bsd/netinet/igmp.h index b854c8ad0..dc62c7da5 100644 --- a/bsd/netinet/igmp.h +++ b/bsd/netinet/igmp.h @@ -56,10 +56,12 @@ * SUCH DAMAGE. * * @(#)igmp.h 8.1 (Berkeley) 6/10/93 + * $FreeBSD: src/sys/netinet/igmp.h,v 1.10 1999/08/28 00:49:15 peter Exp $ */ #ifndef _NETINET_IGMP_H_ #define _NETINET_IGMP_H_ +#include /* * Internet Group Management Protocol (IGMP) definitions. diff --git a/bsd/netinet/igmp_var.h b/bsd/netinet/igmp_var.h index 54cec3475..8d440ff63 100644 --- a/bsd/netinet/igmp_var.h +++ b/bsd/netinet/igmp_var.h @@ -60,6 +60,9 @@ #ifndef _NETINET_IGMP_VAR_H_ #define _NETINET_IGMP_VAR_H_ +#include + +#ifdef __APPLE_API_UNSTABLE /* * Internet Group Management Protocol (IGMP), @@ -83,6 +86,7 @@ struct igmpstat { }; #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE #define IGMP_RANDOM_DELAY(X) (random() % (X) + 1) /* @@ -114,6 +118,7 @@ void igmp_slowtimo __P((void)); SYSCTL_DECL(_net_inet_igmp); +#endif /* __APPLE_API_PRIVATE */ #endif /* @@ -127,6 +132,6 @@ SYSCTL_DECL(_net_inet_igmp); { "stats", CTLTYPE_STRUCT }, \ } +#endif /* __APPLE_API_UNSTABLE */ #endif - diff --git a/bsd/netinet/in.c b/bsd/netinet/in.c index e8e82accd..c950c9931 100644 --- a/bsd/netinet/in.c +++ b/bsd/netinet/in.c @@ -52,6 +52,7 @@ * SUCH DAMAGE. * * @(#)in.c 8.4 (Berkeley) 1/9/95 + * $FreeBSD: src/sys/netinet/in.c,v 1.44.2.5 2001/08/13 16:26:17 ume Exp $ */ #include @@ -66,12 +67,8 @@ #include #include -#include -#if NGIF > 0 -#include "gif.h" #include -#include -#endif +#include #include #include @@ -107,6 +104,9 @@ struct in_multihead in_multihead; /* XXX BSS initialization */ extern void arp_rtrequest(); extern int ether_detach_inet(struct ifnet *ifp); +#if INET6 +extern int ip6_auto_on; +#endif /* * Return 1 if an internet address is for a ``local'' host @@ -239,43 +239,12 @@ in_control(so, cmd, data, ifp, p) struct kev_msg ev_msg; struct kev_in_data in_event_data; -#if NGIF > 0 - if (ifp && ifp->if_type == IFT_GIF) { - switch (cmd) { - case SIOCSIFPHYADDR: -#if 1 - if (p && - (error = suser(p->p_ucred, &p->p_acflag)) != 0) - return(error); -#else - if ((so->so_state & SS_PRIV) == 0) - return (EPERM); -#endif - case SIOCGIFPSRCADDR: - case SIOCGIFPDSTADDR: -#if NGIF > 0 - if (strcmp(ifp->if_name, "gif") == 0) - dl_tag = gif_attach_inet(ifp); - return gif_ioctl(ifp, cmd, data); -#endif - } - } -#endif -#if NFAITH > 0 - if (ifp && ifp->if_type == IFT_FAITH) - dl_tag = faith_attach_inet(ifp); -#endif switch (cmd) { case SIOCALIFADDR: case SIOCDLIFADDR: -#if 1 if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0) return error; -#else - if ((so->so_state & SS_PRIV) == 0) - return (EPERM); -#endif /*fall through*/ case SIOCGLIFADDR: if (!ifp) @@ -306,13 +275,8 @@ in_control(so, cmd, data, ifp, p) switch (cmd) { case SIOCAUTOADDR: -#if 1 if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0) return error; -#else - if ((so->so_state & SS_PRIV) == 0) - return (EPERM); -#endif break; case SIOCAIFADDR: @@ -341,13 +305,12 @@ in_control(so, cmd, data, ifp, p) case SIOCSIFADDR: case SIOCSIFNETMASK: case SIOCSIFDSTADDR: - -#if ISFB31 - if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0) - return error; -#else +#ifdef __APPLE__ if ((so->so_state & SS_PRIV) == 0) return (EPERM); +#else + if (p && (error = suser(p)) != 0) + return error; #endif if (ifp == 0) @@ -374,11 +337,21 @@ in_control(so, cmd, data, ifp, p) * Temorary code for protocol attachment XXX */ - if (strcmp(ifp->if_name, "en") == 0) + if (ifp->if_type == IFT_ETHER) dl_tag = ether_attach_inet(ifp); - if (strcmp(ifp->if_name, "lo") == 0) + if (ifp->if_type == IFT_LOOP) dl_tag = lo_attach_inet(ifp); +#if NFAITH + /* Is this right? */ + if (ifp && ifp->if_type == IFT_FAITH) + dl_tag = faith_attach_inet(ifp); +#endif +#if NGIF + /* Is this right? */ + if (ifp && ifp->if_type == IFT_GIF) + dl_tag = gif_attach_proto_family(ifp, PF_INET); +#endif /* End of temp code */ ifa->ifa_dlt = dl_tag; @@ -400,20 +373,20 @@ in_control(so, cmd, data, ifp, p) case SIOCPROTOATTACH: case SIOCPROTODETACH: if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0) - return error; + return error; if (ifp == 0) return (EADDRNOTAVAIL); - if (strcmp(ifp->if_name, "en")) - return ENODEV; - break; + if (strcmp(ifp->if_name, "en")) + return ENODEV; + break; case SIOCSIFBRDADDR: -#if ISFB31 - if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0) - return error; -#else +#ifdef __APPLE__ if ((so->so_state & SS_PRIV) == 0) return (EPERM); +#else + if (p && (error = suser(p)) != 0) + return error; #endif /* FALLTHROUGH */ @@ -548,14 +521,30 @@ in_control(so, cmd, data, ifp, p) case SIOCPROTOATTACH: ether_attach_inet(ifp); +#if INET6 + if (ip6_auto_on) /* FreeBSD compat mode: Acquire linklocal addresses for IPv6 for if */ + in6_if_up(ifp); +#endif break; case SIOCPROTODETACH: // if an ip address is still present, refuse to detach - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) - if (ifa->ifa_addr->sa_family == AF_INET) - return EBUSY; - return ether_detach_inet(ifp); + TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) + if (ifa->ifa_addr->sa_family == AF_INET) + return EBUSY; + error = ether_detach_inet(ifp); + if (error) + return(error); +#if INET6 + if (ip6_auto_on) { /* if we linked ipv6 addresses to v4, remove them now */ + in6_purgeif(ifp); + error = ether_detach_inet6(ifp); + if (error) + return(error); + } +#endif + break; + case SIOCSIFNETMASK: i = ifra->ifra_addr.sin_addr.s_addr; @@ -627,7 +616,7 @@ in_control(so, cmd, data, ifp, p) * Report event. */ - if (error == 0) { + if ((error == 0) || (error == EEXIST)) { ev_msg.vendor_code = KEV_VENDOR_APPLE; ev_msg.kev_class = KEV_NETWORK_CLASS; ev_msg.kev_subclass = KEV_INET_SUBCLASS; @@ -663,6 +652,12 @@ in_control(so, cmd, data, ifp, p) return (error); case SIOCDIFADDR: + error = dlil_ioctl(PF_INET, ifp, SIOCDIFADDR, (caddr_t)ia); + if (error == EOPNOTSUPP) + error = 0; + if (error) + return error; + ev_msg.vendor_code = KEV_VENDOR_APPLE; ev_msg.kev_class = KEV_NETWORK_CLASS; ev_msg.kev_subclass = KEV_INET_SUBCLASS; @@ -691,7 +686,28 @@ in_control(so, cmd, data, ifp, p) kev_post_msg(&ev_msg); + /* + * in_ifscrub kills the interface route. + */ in_ifscrub(ifp, ia); +#ifndef __APPLE__ + /* + * in_ifadown gets rid of all the rest of + * the routes. This is not quite the right + * thing to do, but at least if we are running + * a routing process they will come back. + */ + in_ifadown(&ia->ia_ifa, 1); + /* + * XXX horrible hack to detect that we are being called + * from if_detach() + */ + if (!ifnet_addrs[ifp->if_index - 1]) { + in_pcbpurgeif0(LIST_FIRST(ripcbinfo.listhead), ifp); + in_pcbpurgeif0(LIST_FIRST(udbinfo.listhead), ifp); + } +#endif + /* * Protect from ipintr() traversing address list * while we're modifying it. @@ -702,33 +718,37 @@ in_control(so, cmd, data, ifp, p) TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); oia = ia; TAILQ_REMOVE(&in_ifaddrhead, oia, ia_link); - IFAFREE(&oia->ia_ifa); - - /* - * If the interface supports multicast, and no address is left, - * remove the "all hosts" multicast group from that interface. - */ - if (ifp->if_flags & IFF_MULTICAST) { - struct in_addr addr; - struct in_multi *inm; - - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) - if (ifa->ifa_addr->sa_family == AF_INET) - break; - - if (ifa == 0) { - addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); - IN_LOOKUP_MULTI(addr, ifp, inm); - if (inm) - in_delmulti(inm); - } - } + ifafree(&oia->ia_ifa); + +#ifdef __APPLE__ + /* + * If the interface supports multicast, and no address is left, + * remove the "all hosts" multicast group from that interface. + */ + if (ifp->if_flags & IFF_MULTICAST) { + struct in_addr addr; + struct in_multi *inm; + + TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) + if (ifa->ifa_addr->sa_family == AF_INET) + break; + + if (ifa == 0) { + addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); + IN_LOOKUP_MULTI(addr, ifp, inm); + if (inm) + in_delmulti(inm); + } + } +#endif splx(s); break; +#ifdef __APPLE__ case SIOCSETOT: { /* * Inspiration from tcp_ctloutput() and ip_ctloutput() + * Special ioctl for OpenTransport sockets */ struct inpcb *inp, *cloned_inp; int error = 0; @@ -801,23 +821,37 @@ in_control(so, cmd, data, ifp, p) imo->imo_membership[i] = in_addmulti(&cloned_imo->imo_membership[i]->inm_addr, cloned_imo->imo_membership[i]->inm_ifp); + if (imo->imo_membership[i] == NULL) { + error = ENOBUFS; + break; + } + } + if (i < cloned_imo->imo_num_memberships) { + /* Failed, perform cleanup */ + for (i--; i >= 0; i--) + in_delmulti(imo->imo_membership[i]); + break; } } } splx(s); break; } +#endif /* __APPLE__ */ default: - return EOPNOTSUPP; - + return EOPNOTSUPP; + /* Darwin: dlil_ioctl called from ifioctl */ +#ifndef __APPLE__ + return ((*ifp->if_ioctl)(ifp, cmd, data)); +#endif } return (0); } /* * SIOC[GAD]LIFADDR. - * SIOCGLIFADDR: get first address. (???) + * SIOCGLIFADDR: get first address. (?!?) * SIOCGLIFADDR with IFLR_PREFIX: * get first address that matches the specified prefix. * SIOCALIFADDR: add the specified address. @@ -870,12 +904,7 @@ in_lifaddr_ioctl(so, cmd, data, ifp, p) return EINVAL; break; default: /*shouldn't happen*/ -#if 0 - panic("invalid cmd to in_lifaddr_ioctl"); - /*NOTREACHED*/ -#else return EOPNOTSUPP; -#endif } if (sizeof(struct in_addr) * 8 < iflr->prefixlen) return EINVAL; @@ -1032,22 +1061,22 @@ in_ifinit(ifp, ia, sin, scrub) int s = splimp(), flags = RTF_UP, error; u_long dl_tag; - - 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. + */ error = dlil_ioctl(PF_INET, ifp, SIOCSIFADDR, (caddr_t)ia); if (error == EOPNOTSUPP) error = 0; - if (error) { splx(s); ia->ia_addr = oldaddr; return (error); } - splx(s); if (scrub) { ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr; @@ -1092,19 +1121,22 @@ in_ifinit(ifp, ia, sin, scrub) } if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0) ia->ia_flags |= IFA_ROUTE; + /* XXX check if the subnet route points to the same interface */ + if (error == EEXIST) + error = 0; /* * If the interface supports multicast, join the "all hosts" * multicast group on that interface. */ if (ifp->if_flags & IFF_MULTICAST) { - struct in_multi *inm; + struct in_multi *inm; struct in_addr addr; addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); - IN_LOOKUP_MULTI(addr, ifp, inm); - if (inm == 0) - in_addmulti(&addr, ifp); + IN_LOOKUP_MULTI(addr, ifp, inm); + if (inm == 0) + in_addmulti(&addr, ifp); } return (error); } @@ -1133,7 +1165,7 @@ in_broadcast(in, ifp) */ #define ia ((struct in_ifaddr *)ifa) for (ifa = ifp->if_addrhead.tqh_first; ifa; - ifa = ifa->ifa_link.tqe_next) { + ifa = ifa->ifa_link.tqe_next) { if (ifa->ifa_addr == NULL) return (0); if (ifa->ifa_addr->sa_family == AF_INET && @@ -1187,8 +1219,10 @@ in_addmulti(ap, ifp) * If ifma->ifma_protospec is null, then if_addmulti() created * a new record. Otherwise, we are done. */ - if (ifma->ifma_protospec != 0) + if (ifma->ifma_protospec != 0) { + splx(s); return ifma->ifma_protospec; + } inm = (struct in_multi *) _MALLOC(sizeof(*inm), M_IPMADDR, M_WAITOK); if (inm == NULL) { @@ -1220,6 +1254,8 @@ in_delmulti(inm) { struct ifmultiaddr *ifma = inm->inm_ifma; int s = splnet(); + + /* We intentionally do this a bit differently than BSD */ if (ifma->ifma_refcount == 1) { /* @@ -1234,6 +1270,4 @@ in_delmulti(inm) /* XXX - should be separate API for when we have an ifma? */ if_delmulti(ifma->ifma_ifp, ifma->ifma_addr); splx(s); - - } diff --git a/bsd/netinet/in.h b/bsd/netinet/in.h index 12bc02389..7fcd67541 100644 --- a/bsd/netinet/in.h +++ b/bsd/netinet/in.h @@ -52,10 +52,12 @@ * SUCH DAMAGE. * * @(#)in.h 8.3 (Berkeley) 1/3/94 + * $FreeBSD: src/sys/netinet/in.h,v 1.48.2.2 2001/04/21 14:53:06 ume Exp $ */ #ifndef _NETINET_IN_H_ #define _NETINET_IN_H_ +#include /* * Constants and structures defined by the internet system, @@ -66,12 +68,12 @@ * Protocols (RFC 1700) */ #define IPPROTO_IP 0 /* dummy for IP */ -#define IPPROTO_HOPOPTS 0 /* IP6 hop-by-hop options */ +#define IPPROTO_HOPOPTS 0 /* IP6 hop-by-hop options */ #define IPPROTO_ICMP 1 /* control message protocol */ #define IPPROTO_IGMP 2 /* group mgmt protocol */ #define IPPROTO_GGP 3 /* gateway^2 (deprecated) */ -#define IPPROTO_IPIP 4 /* IP encapsulation in IP */ -#define IPPROTO_IPV4 4 /* IP header */ +#define IPPROTO_IPV4 4 /* IPv4 encapsulation */ +#define IPPROTO_IPIP IPPROTO_IPV4 /* for compatibility */ #define IPPROTO_TCP 6 /* tcp */ #define IPPROTO_ST 7 /* Stream protocol II */ #define IPPROTO_EGP 8 /* exterior gateway protocol */ @@ -116,8 +118,8 @@ #define IPPROTO_GRE 47 /* General Routing Encap. */ #define IPPROTO_MHRP 48 /* Mobile Host Routing */ #define IPPROTO_BHA 49 /* BHA */ -#define IPPROTO_ESP 50 /* SIPP Encap Sec. Payload */ -#define IPPROTO_AH 51 /* SIPP Auth Header */ +#define IPPROTO_ESP 50 /* IP6 Encap Sec. Payload */ +#define IPPROTO_AH 51 /* IP6 Auth Header */ #define IPPROTO_INLSP 52 /* Integ. Net Layer Security */ #define IPPROTO_SWIPE 53 /* IP with encryption */ #define IPPROTO_NHRP 54 /* Next Hop Resolution */ @@ -167,10 +169,7 @@ #define IPPROTO_GMTP 100 /* GMTP*/ #define IPPROTO_IPCOMP 108 /* payload compression (IPComp) */ /* 101-254: Partly Unassigned */ -#if defined(PM) -#define IPPROTO_PM 101 /* PM - Packet Management by SuMiRe */ -#endif -#define IPPROTO_PIM 103 /* Protocol Independent Mcast */ +#define IPPROTO_PIM 103 /* Protocol Independent Mcast */ #define IPPROTO_PGM 113 /* PGM */ /* 255: Reserved */ /* BSD Private, local use, namespace incursion */ @@ -253,7 +252,7 @@ * Internet address (a structure for historical reasons) */ struct in_addr { - u_int32_t s_addr; + in_addr_t s_addr; }; /* @@ -299,8 +298,10 @@ struct in_addr { #define INADDR_ALLRTRS_GROUP (u_int32_t)0xe0000002 /* 224.0.0.2 */ #define INADDR_MAX_LOCAL_GROUP (u_int32_t)0xe00000ff /* 224.0.0.255 */ +#ifdef __APPLE__ #define IN_LINKLOCALNETNUM (u_int32_t)0xA9FE0000 /* 169.254.0.0 */ #define IN_LINKLOCAL(i) (((u_int32_t)(i) & IN_CLASSB_NET) == IN_LINKLOCALNETNUM) +#endif #define IN_LOOPBACKNET 127 /* official! */ @@ -352,19 +353,30 @@ struct ip_opts { #define IP_RSVP_VIF_ON 17 /* set RSVP per-vif socket */ #define IP_RSVP_VIF_OFF 18 /* unset RSVP per-vif socket */ #define IP_PORTRANGE 19 /* int; range to choose for unspec port */ -#define IP_RECVIF 20 /* bool; receive reception if w/dgram */ -#define IP_IPSEC_POLICY 21 /* int; set/get security policy */ -#define IP_FAITH 22 /* bool; accept FAITH'ed connections */ +#define IP_RECVIF 20 /* bool; receive reception if w/dgram */ +/* for IPSEC */ +#define IP_IPSEC_POLICY 21 /* int; set/get security policy */ +#define IP_FAITH 22 /* bool; accept FAITH'ed connections */ +#ifdef __APPLE__ #define IP_STRIPHDR 23 /* bool: drop receive of raw IP header */ +#endif + +#define IP_FW_ADD 40 /* add a firewall rule to chain */ +#define IP_FW_DEL 41 /* delete a firewall rule from chain */ +#define IP_FW_FLUSH 42 /* flush firewall rule chain */ +#define IP_FW_ZERO 43 /* clear single/all firewall counter(s) */ +#define IP_FW_GET 44 /* get entire firewall rule chain */ +#define IP_FW_RESETLOG 45 /* reset logging counters */ -#define IP_FW_ADD 50 /* add a firewall rule to chain */ -#define IP_FW_DEL 51 /* delete a firewall rule from chain */ -#define IP_FW_FLUSH 52 /* flush firewall rule chain */ -#define IP_FW_ZERO 53 /* clear single/all firewall counter(s) */ -#define IP_FW_GET 54 /* get entire firewall rule chain */ -#define IP_NAT 55 /* set/get NAT opts */ -#define IP_FW_RESETLOG 56 /* reset logging counters */ +/* These older firewall socket option codes are maintained for backward compatibility. */ +#define IP_OLD_FW_ADD 50 /* add a firewall rule to chain */ +#define IP_OLD_FW_DEL 51 /* delete a firewall rule from chain */ +#define IP_OLD_FW_FLUSH 52 /* flush firewall rule chain */ +#define IP_OLD_FW_ZERO 53 /* clear single/all firewall counter(s) */ +#define IP_OLD_FW_GET 54 /* get entire firewall rule chain */ +#define IP_NAT__XXX 55 /* set/get NAT opts XXX Deprecated, do not use */ +#define IP_OLD_FW_RESETLOG 56 /* reset logging counters */ #define IP_DUMMYNET_CONFIGURE 60 /* add/configure a dummynet pipe */ #define IP_DUMMYNET_DEL 61 /* delete a dummynet pipe from chain */ @@ -400,7 +412,7 @@ struct ip_mreq { * Third level is protocol number. * Fourth level is desired variable within that protocol. */ -#define IPPROTO_MAXID (IPPROTO_ESP + 1) /* don't list to IPPROTO_MAX */ +#define IPPROTO_MAXID (IPPROTO_AH + 1) /* don't list to IPPROTO_MAX */ #define CTL_IPPROTO_NAMES { \ { "ip", CTLTYPE_NODE }, \ @@ -472,12 +484,12 @@ struct ip_mreq { #define IPCTL_SOURCEROUTE 8 /* may perform source routes */ #define IPCTL_DIRECTEDBROADCAST 9 /* may re-broadcast received packets */ #define IPCTL_INTRQMAXLEN 10 /* max length of netisr queue */ -#define IPCTL_INTRQDROPS 11 /* number of netisr q drops */ +#define IPCTL_INTRQDROPS 11 /* number of netisr q drops */ #define IPCTL_STATS 12 /* ipstat structure */ #define IPCTL_ACCEPTSOURCEROUTE 13 /* may accept source routed packets */ -#define IPCTL_FASTFORWARDING 14 /* use fast IP forwarding code */ -#define IPCTL_KEEPFAITH 15 -#define IPCTL_GIF_TTL 16 /* default TTL for gif encap packet */ +#define IPCTL_FASTFORWARDING 14 /* use fast IP forwarding code */ +#define IPCTL_KEEPFAITH 15 /* FAITH IPv4->IPv6 translater ctl */ +#define IPCTL_GIF_TTL 16 /* default TTL for gif encap packet */ #define IPCTL_MAXID 17 #define IPCTL_NAMES { \ @@ -506,6 +518,7 @@ struct ip_mreq { #undef __KAME_NETINET_IN_H_INCLUDED_ #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE struct ifnet; struct mbuf; /* forward declarations for Standard C */ int in_broadcast __P((struct in_addr, struct ifnet *)); @@ -517,6 +530,7 @@ u_short in_pseudo __P((u_int, u_int, u_int)); int in_localaddr __P((struct in_addr)); char *inet_ntoa __P((struct in_addr)); /* in libkern */ u_long in_netof __P((struct in_addr)); +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ #endif diff --git a/bsd/netinet/in_bootp.c b/bsd/netinet/in_bootp.c index 623197668..d203b0e77 100644 --- a/bsd/netinet/in_bootp.c +++ b/bsd/netinet/in_bootp.c @@ -64,7 +64,7 @@ #include #include #include - +#include #ifdef BOOTP_DEBUG #define dprintf(x) printf x; @@ -77,17 +77,12 @@ #define IP_CH(ip) ((u_char *)ip) #define IP_LIST(ip) IP_CH(ip)[0],IP_CH(ip)[1],IP_CH(ip)[2],IP_CH(ip)[3] -/* tag values (from RFC 2132) */ -#define TAG_PAD 0 -#define TAG_END 255 -#define TAG_SUBNET_MASK 1 -#define TAG_ROUTER 3 -#define RFC_OPTIONS_MAGIC { 99, 130, 83, 99 } -static unsigned char rfc_magic[4] = RFC_OPTIONS_MAGIC; - - -static struct sockaddr_in blank_sin = { sizeof(struct sockaddr_in), - AF_INET }; +static __inline__ struct sockaddr_in +blank_sin() +{ + struct sockaddr_in blank = { sizeof(struct sockaddr_in), AF_INET }; + return (blank); +} static __inline__ void print_reply(struct bootp *bp, int bp_len) @@ -159,10 +154,16 @@ static void make_bootp_request(struct bootp_packet * pkt, u_char * hwaddr, u_char hwtype, u_char hwlen) { + char rfc_magic[4] = RFC_OPTIONS_MAGIC; + bzero(pkt, sizeof (*pkt)); pkt->bp_ip.ip_v = IPVERSION; pkt->bp_ip.ip_hl = sizeof (struct ip) >> 2; +#ifdef RANDOM_IP_ID + pkt->bp_ip.ip_id = ip_randomid(); +#else pkt->bp_ip.ip_id = htons(ip_id++); +#endif pkt->bp_ip.ip_ttl = MAXTTL; pkt->bp_ip.ip_p = IPPROTO_UDP; pkt->bp_ip.ip_src.s_addr = 0; @@ -176,7 +177,7 @@ make_bootp_request(struct bootp_packet * pkt, pkt->bp_bootp.bp_ciaddr.s_addr = 0; bcopy(hwaddr, pkt->bp_bootp.bp_chaddr, hwlen); bcopy(rfc_magic, pkt->bp_bootp.bp_vend, sizeof(rfc_magic)); - pkt->bp_bootp.bp_vend[4] = TAG_END; + pkt->bp_bootp.bp_vend[4] = dhcptag_end_e; pkt->bp_udp.uh_ulen = htons(sizeof(pkt->bp_udp) + sizeof(pkt->bp_bootp)); pkt->bp_ip.ip_len = htons(sizeof(struct ip) + ntohs(pkt->bp_udp.uh_ulen)); pkt->bp_ip.ip_sum = 0; @@ -263,12 +264,12 @@ send_bootp_request(struct ifnet * ifp, struct socket * so, struct sockaddr_in sin; /* Address to send to */ - sin = blank_sin; + sin = blank_sin(); sin.sin_port = htons(IPPORT_BOOTPS); sin.sin_addr.s_addr = INADDR_BROADCAST; m = ip_pkt_to_mbuf((caddr_t)pkt, sizeof(*pkt)); - return (dlil_output((u_long) ifp, m, 0, (struct sockaddr *)&sin, 0)); + return (dlil_output(ifp->if_data.default_proto, m, 0, (struct sockaddr *)&sin, 0)); } /* @@ -277,7 +278,7 @@ send_bootp_request(struct ifnet * ifp, struct socket * so, * Return a received packet or an error if none available. */ int -receive_packet(struct socket * so, caddr_t pp, int psize) +receive_packet(struct socket * so, caddr_t pp, int psize, int * actual_size) { struct iovec aiov; struct uio auio; @@ -295,6 +296,7 @@ receive_packet(struct socket * so, caddr_t pp, int psize) rcvflg = MSG_WAITALL; error = soreceive(so, (struct sockaddr **) 0, &auio, 0, 0, &rcvflg); + *actual_size = psize - auio.uio_resid; return (error); } @@ -304,8 +306,9 @@ receive_packet(struct socket * so, caddr_t pp, int psize) * Wakeup the process waiting for something on a socket. */ static void -bootp_timeout(struct socket * * socketflag) +bootp_timeout(void * arg) { + struct socket * * socketflag = (struct socket * *)arg; struct socket * so = *socketflag; boolean_t funnel_state; @@ -318,49 +321,6 @@ bootp_timeout(struct socket * * socketflag) return; } -#define TAG_OFFSET 0 -#define LEN_OFFSET 1 -#define OPTION_OFFSET 2 - -void * -packet_option(struct bootp * pkt, u_char t) -{ - void * buffer = pkt->bp_vend + sizeof(rfc_magic); - int len; - unsigned char option_len; - void * ret = NULL; - unsigned char * scan; - unsigned char tag = TAG_PAD; - - len = sizeof(pkt->bp_vend) - sizeof(rfc_magic); - for (scan = buffer; len > 0; ) { - tag = scan[TAG_OFFSET]; - if (tag == TAG_END) /* we hit the end of the options */ - break; - if (tag == TAG_PAD) { /* discard pad characters */ - scan++; - len--; - } - else { - if (t == tag && ret == NULL) - ret = scan + OPTION_OFFSET; - option_len = scan[LEN_OFFSET]; - len -= (option_len + 2); - scan += (option_len + 2); - } - } - if (len < 0 || tag != TAG_END) { /* we ran off the end */ - if (len < 0) { - dprintf(("bootp: error parsing options\n")); - } - else { - dprintf(("bootp: end tag missing\n")); - } - ret = NULL; - } - return (ret); -} - /* * Function: rate_packet * Purpose: @@ -371,20 +331,16 @@ packet_option(struct bootp * pkt, u_char t) */ #define GOOD_RATING 3 static __inline__ int -rate_packet(struct bootp * pkt) +rate_packet(struct bootp * pkt, int pkt_size, dhcpol_t * options_p) { - int rating = 0; - - if (pkt->bp_yiaddr.s_addr) { - struct in_addr * ip; + int len; + int rating = 1; + if (dhcpol_find(options_p, dhcptag_subnet_mask_e, &len, NULL) != NULL) { + rating++; + } + if (dhcpol_find(options_p, dhcptag_router_e, &len, NULL) != NULL) { rating++; - ip = (struct in_addr *)packet_option(pkt, TAG_SUBNET_MASK); - if (ip) - rating++; - ip = (struct in_addr *)packet_option(pkt, TAG_ROUTER); - if (ip) - rating++; } return (rating); } @@ -419,7 +375,7 @@ bootp_loop(struct socket * so, struct ifnet * ifp, int max_try, char hwtype = 0; struct bootp_packet * request = NULL; struct bootp * reply = NULL; - struct bootp * saved_reply = NULL; + int reply_size = DHCP_PACKET_MIN; struct timeval start_time; u_long xid; int retry; @@ -457,8 +413,7 @@ bootp_loop(struct socket * so, struct ifnet * ifp, int max_try, /* make a request/reply packet */ request = (struct bootp_packet *)kalloc(sizeof(*request)); make_bootp_request(request, hwaddr, hwtype, hwlen); - reply = (struct bootp *)kalloc(sizeof(*reply)); - saved_reply = (struct bootp *)kalloc(sizeof(*saved_reply)); + reply = (struct bootp *)kalloc(reply_size); iaddr_p->s_addr = 0; printf("bootp: sending request"); for (retry = 0; retry < max_try; retry++) { @@ -477,30 +432,57 @@ bootp_loop(struct socket * so, struct ifnet * ifp, int max_try, timeflag = so; wait_ticks += random_range(-RAND_TICKS, RAND_TICKS); dprintf(("bootp: waiting %d ticks\n", wait_ticks)); - timeout(bootp_timeout, &timeflag, wait_ticks); + timeout((timeout_fcn_t)bootp_timeout, &timeflag, wait_ticks); while (TRUE) { - error = receive_packet(so, (caddr_t)reply, sizeof(*reply)); + int n = 0; + + error = receive_packet(so, (caddr_t)reply, reply_size, &n); if (error == 0) { dprintf(("\nbootp: received packet\n")); if (ntohl(reply->bp_xid) == xid && reply->bp_yiaddr.s_addr && bcmp(reply->bp_chaddr, hwaddr, hwlen) == 0) { - int rating; + int rating; + dhcpol_t options; + #ifdef BOOTP_DEBUG - print_reply_short(reply, sizeof(*reply)); + print_reply_short(reply, n); #endif BOOTP_DEBUG - rating = rate_packet(reply); - if (rating > last_rating) - *saved_reply = *reply; + (void)dhcpol_parse_packet(&options, (struct dhcp *)reply, + n, NULL); + rating = rate_packet(reply, n, &options); + if (rating > last_rating) { + struct in_addr * ip; + int len; + + *iaddr_p = reply->bp_yiaddr; + ip = (struct in_addr *) + dhcpol_find(&options, + dhcptag_subnet_mask_e, &len, NULL); + if (ip) { + *netmask_p = *ip; + } + ip = (struct in_addr *) + dhcpol_find(&options, dhcptag_router_e, &len, NULL); + if (ip) { + *router_p = *ip; + } + printf("%sbootp: got " + "response from %s (" IP_FORMAT ")\n", + last_rating == 0 ? "\n" : "", + reply->bp_sname, + IP_LIST(&reply->bp_siaddr)); + } + dhcpol_free(&options); if (rating >= GOOD_RATING) { - untimeout(bootp_timeout, &timeflag); - goto save_values; + untimeout((timeout_fcn_t)bootp_timeout, &timeflag); + goto done; } if (gather_count == 0) { - untimeout(bootp_timeout, &timeflag); + untimeout((timeout_fcn_t)bootp_timeout, &timeflag); timeflag = so; - timeout(bootp_timeout, &timeflag, + timeout((timeout_fcn_t)bootp_timeout, &timeflag, hz * GATHER_TIME_SECS); } gather_count++; @@ -515,7 +497,7 @@ bootp_loop(struct socket * so, struct ifnet * ifp, int max_try, else if (timeflag == NULL) { /* timed out */ if (gather_count) { dprintf(("bootp: gathering time has expired")); - goto save_values; /* we have a packet */ + goto done; /* we have a packet */ } break; /* retry */ } @@ -524,7 +506,7 @@ bootp_loop(struct socket * so, struct ifnet * ifp, int max_try, } if (error && (error != EWOULDBLOCK)) { dprintf(("bootp: failed to receive packets: %d\n", error)); - untimeout(bootp_timeout, &timeflag); + untimeout((timeout_fcn_t)bootp_timeout, &timeflag); goto cleanup; } wait_ticks *= 2; @@ -536,29 +518,14 @@ bootp_loop(struct socket * so, struct ifnet * ifp, int max_try, error = ETIMEDOUT; goto cleanup; - save_values: + done: error = 0; - printf("\nbootp: got response from %s (" IP_FORMAT ")\n", - saved_reply->bp_sname, IP_LIST(&saved_reply->bp_siaddr)); - /* return the ip address */ - *iaddr_p = saved_reply->bp_yiaddr; - { - struct in_addr * ip; - ip = (struct in_addr *)packet_option(saved_reply, TAG_SUBNET_MASK); - if (ip) - *netmask_p = *ip; - ip = (struct in_addr *)packet_option(saved_reply, TAG_ROUTER); - if (ip) - *router_p = *ip; - } cleanup: if (request) kfree((caddr_t)request, sizeof (*request)); if (reply) - kfree((caddr_t)reply, sizeof(*reply)); - if (saved_reply) - kfree((caddr_t)saved_reply, sizeof(*saved_reply)); + kfree((caddr_t)reply, reply_size); return (error); } @@ -587,7 +554,7 @@ int bootp(struct ifnet * ifp, struct in_addr * iaddr_p, int max_try, /* assign the all-zeroes address */ bzero(&ifr, sizeof(ifr)); sprintf(ifr.ifr_name, "%s%d", ifp->if_name, ifp->if_unit); - *((struct sockaddr_in *)&ifr.ifr_addr) = blank_sin; + *((struct sockaddr_in *)&ifr.ifr_addr) = blank_sin(); error = ifioctl(so, SIOCSIFADDR, (caddr_t)&ifr, procp); if (error) { dprintf(("bootp: SIOCSIFADDR all-zeroes IP failed: %d\n", @@ -630,4 +597,3 @@ int bootp(struct ifnet * ifp, struct in_addr * iaddr_p, int max_try, } return (error); } - diff --git a/bsd/netinet/in_gif.c b/bsd/netinet/in_gif.c index d76365f87..1971b49bc 100644 --- a/bsd/netinet/in_gif.c +++ b/bsd/netinet/in_gif.c @@ -19,7 +19,7 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* $KAME: in_gif.c,v 1.27 2000/03/30 01:29:05 jinmei Exp $ */ +/* $KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -50,39 +50,20 @@ * SUCH DAMAGE. */ -/* - * in_gif.c - */ -#if BSD310 -#include "opt_mrouting.h" -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -#include "opt_inet.h" -#endif -#endif #include #include #include #include -#include #include #include -#ifdef __FreeBSD__ #include #include -#endif -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 -#include -#endif -#include -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) #include -#endif #include #include -#include #include #include @@ -103,20 +84,11 @@ #include -#include "gif.h" - #include -#if NGIF > 0 -int ip_gif_ttl = GIF_TTL; -#else -int ip_gif_ttl = 0; -#endif - -extern struct protosw in_gif_protosw; - -SYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, - CTLFLAG_RW, &ip_gif_ttl , 0, ""); +int ip_gif_ttl = GIF_TTL; +SYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW, + &ip_gif_ttl, 0, ""); int in_gif_output(ifp, family, m, rt) @@ -125,7 +97,7 @@ in_gif_output(ifp, family, m, rt) struct mbuf *m; struct rtentry *rt; { - register struct gif_softc *sc = (struct gif_softc*)ifp; + struct gif_softc *sc = (struct gif_softc*)ifp; struct sockaddr_in *dst = (struct sockaddr_in *)&sc->gif_ro.ro_dst; struct sockaddr_in *sin_src = (struct sockaddr_in *)sc->gif_psrc; struct sockaddr_in *sin_dst = (struct sockaddr_in *)sc->gif_pdst; @@ -136,7 +108,6 @@ in_gif_output(ifp, family, m, rt) if (sin_src == NULL || sin_dst == NULL || sin_src->sin_family != AF_INET || sin_dst->sin_family != AF_INET) { - printf("in_gif_output: unknown family src=%x dst=%x\n", sin_src->sin_family, sin_dst->sin_family); m_freem(m); return EAFNOSUPPORT; } @@ -184,29 +155,12 @@ in_gif_output(ifp, family, m, rt) bzero(&iphdr, sizeof(iphdr)); iphdr.ip_src = sin_src->sin_addr; - if (ifp->if_flags & IFF_LINK0) { - /* multi-destination mode */ - if (sin_dst->sin_addr.s_addr != INADDR_ANY) - iphdr.ip_dst = sin_dst->sin_addr; - else if (rt) { - if (family != AF_INET) { - m_freem(m); - return EINVAL; /*XXX*/ - } - iphdr.ip_dst = ((struct sockaddr_in *) - (rt->rt_gateway))->sin_addr; - } else { - m_freem(m); - return ENETUNREACH; - } - } else { - /* bidirectional configured tunnel mode */ - if (sin_dst->sin_addr.s_addr != INADDR_ANY) - iphdr.ip_dst = sin_dst->sin_addr; - else { - m_freem(m); - return ENETUNREACH; - } + /* bidirectional configured tunnel mode */ + if (sin_dst->sin_addr.s_addr != INADDR_ANY) + iphdr.ip_dst = sin_dst->sin_addr; + else { + m_freem(m); + return ENETUNREACH; } iphdr.ip_p = proto; /* version will be set in ip_output() */ @@ -214,6 +168,8 @@ in_gif_output(ifp, family, m, rt) iphdr.ip_len = m->m_pkthdr.len + sizeof(struct ip); if (ifp->if_flags & IFF_LINK1) ip_ecn_ingress(ECN_ALLOWED, &iphdr.ip_tos, &tos); + else + ip_ecn_ingress(ECN_NOCARE, &iphdr.ip_tos, &tos); /* prepend new IP header */ M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); @@ -223,8 +179,7 @@ in_gif_output(ifp, family, m, rt) printf("ENOBUFS in in_gif_output %d\n", __LINE__); return ENOBUFS; } - - *(mtod(m, struct ip *)) = iphdr; + bcopy(&iphdr, mtod(m, struct ip *), sizeof(struct ip)); if (dst->sin_family != sin_dst->sin_family || dst->sin_addr.s_addr != sin_dst->sin_addr.s_addr) { @@ -233,7 +188,7 @@ in_gif_output(ifp, family, m, rt) dst->sin_len = sizeof(struct sockaddr_in); dst->sin_addr = sin_dst->sin_addr; if (sc->gif_ro.ro_rt) { - RTFREE(sc->gif_ro.ro_rt); + rtfree(sc->gif_ro.ro_rt); sc->gif_ro.ro_rt = NULL; } #if 0 @@ -247,17 +202,19 @@ in_gif_output(ifp, family, m, rt) m_freem(m); return ENETUNREACH; } + + /* if it constitutes infinite encapsulation, punt. */ + if (sc->gif_ro.ro_rt->rt_ifp == ifp) { + m_freem(m); + return ENETUNREACH; /*XXX*/ + } #if 0 ifp->if_mtu = sc->gif_ro.ro_rt->rt_ifp->if_mtu - sizeof(struct ip); #endif } -#ifndef __OpenBSD__ error = ip_output(m, NULL, &sc->gif_ro, 0, NULL); -#else - error = ip_output(m, NULL, &sc->gif_ro, 0, NULL, NULL); -#endif return(error); } @@ -266,73 +223,18 @@ in_gif_input(m, off) struct mbuf *m; int off; { - struct gif_softc *sc; struct ifnet *gifp = NULL; struct ip *ip; int i, af, proto; u_int8_t otos; - if (gif == NULL) { - m_freem(m); - return; - } - ip = mtod(m, struct ip *); - proto = ip->ip_p; - -#if 0 - /* this code will be soon improved. */ -#define satosin(sa) ((struct sockaddr_in *)(sa)) - for (i = 0, sc = gif; i < ngif; i++, sc++) { - if (sc->gif_psrc == NULL - || sc->gif_pdst == NULL - || sc->gif_psrc->sa_family != AF_INET - || sc->gif_pdst->sa_family != AF_INET) { - continue; - } + proto = ip->ip_p; - if ((sc->gif_if.if_flags & IFF_UP) == 0) - continue; - - if ((sc->gif_if.if_flags & IFF_LINK0) - && satosin(sc->gif_psrc)->sin_addr.s_addr == ip->ip_dst.s_addr - && satosin(sc->gif_pdst)->sin_addr.s_addr == INADDR_ANY) { - gifp = &sc->gif_if; - continue; - } - if (satosin(sc->gif_psrc)->sin_addr.s_addr == ip->ip_dst.s_addr - && satosin(sc->gif_pdst)->sin_addr.s_addr == ip->ip_src.s_addr) - { - gifp = &sc->gif_if; - break; - } - } -#else gifp = (struct ifnet *)encap_getarg(m); -#endif - if (gifp == NULL) { - /* for backward compatibility */ - if (proto == IPPROTO_IPV4) { -#ifdef __OpenBSD__ -#if defined(MROUTING) || defined(IPSEC) - ip4_input(m, off, proto); - return; -#endif -#else -#if MROUTING - ipip_input(m, off); - return; -#endif /*MROUTING*/ -#endif - } - m_freem(m); - ipstat.ips_nogif++; - return; - } - - if ((gifp->if_flags & IFF_UP) == 0) { + if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) { m_freem(m); ipstat.ips_nogif++; return; @@ -355,6 +257,8 @@ in_gif_input(m, off) ip = mtod(m, struct ip *); if (gifp->if_flags & IFF_LINK1) ip_ecn_egress(ECN_ALLOWED, &otos, &ip->ip_tos); + else + ip_ecn_egress(ECN_NOCARE, &otos, &ip->ip_tos); break; } #endif @@ -373,6 +277,8 @@ in_gif_input(m, off) itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; if (gifp->if_flags & IFF_LINK1) ip_ecn_egress(ECN_ALLOWED, &otos, &itos); + else + ip_ecn_egress(ECN_NOCARE, &otos, &itos); ip6->ip6_flow &= ~htonl(0xff << 20); ip6->ip6_flow |= htonl((u_int32_t)itos << 20); break; @@ -383,128 +289,91 @@ in_gif_input(m, off) m_freem(m); return; } +#ifdef __APPLE__ + /* Should we free m if dlil_input returns an error? */ + if (m->m_pkthdr.rcvif) /* replace the rcvif by gifp for dlil to route it correctly */ + m->m_pkthdr.rcvif = gifp; + dlil_input_packet(gifp, m, NULL); +#else gif_input(m, af, gifp); +#endif return; } +/* + * we know that we are in IFF_UP, outer address available, and outer family + * matched the physical addr family. see gif_encapcheck(). + */ int -in_gif_ioctl(ifp, cmd, data) - struct ifnet *ifp; -#if defined(__FreeBSD__) && __FreeBSD__ < 3 - int cmd; -#else - u_long cmd; -#endif - caddr_t data; +gif_encapcheck4(m, off, proto, arg) + const struct mbuf *m; + int off; + int proto; + void *arg; { - struct gif_softc *sc = (struct gif_softc*)ifp; - struct ifreq *ifr = (struct ifreq*)data; - int error = 0, size; - struct sockaddr *sa, *dst, *src; - const struct encaptab *p; - struct sockaddr_in smask4, dmask4; - - switch (cmd) { - case SIOCSIFFLAGS: - /* - * whenever we change our idea about multi-destination mode - * we need to update encap attachment. - */ - if (((ifp->if_flags ^ sc->gif_oflags) & IFF_LINK0) == 0) - break; - if (sc->gif_psrc == NULL || sc->gif_pdst == NULL || - sc->gif_psrc->sa_family != sc->gif_pdst->sa_family) - break; - bzero(&smask4, sizeof(smask4)); - smask4.sin_addr.s_addr = ~0; - dmask4 = smask4; - if ((ifp->if_flags & IFF_LINK0) != 0 && - ((struct sockaddr_in *)dst)->sin_addr.s_addr == - INADDR_ANY) { - bzero(&dmask4, sizeof(dmask4)); - } - p = encap_attach(sc->gif_psrc->sa_family, -1, sc->gif_psrc, - (struct sockaddr *)&smask4, sc->gif_pdst, - (struct sockaddr *)&dmask4, - (struct protosw *)&in_gif_protosw, &sc->gif_if); - if (p == NULL) { - error = EINVAL; - goto bad; - } - if (sc->encap_cookie != NULL) - (void)encap_detach(sc->encap_cookie); - sc->encap_cookie = p; - sc->gif_oflags = ifp->if_flags; - - break; - - case SIOCSIFPHYADDR: - switch (ifr->ifr_addr.sa_family) { - case AF_INET: - src = (struct sockaddr *) - &(((struct in_aliasreq *)data)->ifra_addr); - dst = (struct sockaddr *) - &(((struct in_aliasreq *)data)->ifra_dstaddr); - - bzero(&smask4, sizeof(smask4)); - smask4.sin_addr.s_addr = ~0; - dmask4 = smask4; - if ((ifp->if_flags & IFF_LINK0) != 0 && - ((struct sockaddr_in *)dst)->sin_addr.s_addr == - INADDR_ANY) { - bzero(&dmask4, sizeof(dmask4)); - } - size = sizeof(struct sockaddr_in); - break; - default: - error = EAFNOSUPPORT; - goto bad; - } - - if (sc->encap_cookie) - (void)encap_detach(sc->encap_cookie); - if (sc->gif_psrc != NULL) { - _FREE((caddr_t)sc->gif_psrc, M_IFADDR); - sc->gif_psrc = NULL; - } - if (sc->gif_pdst != NULL) { - _FREE((caddr_t)sc->gif_pdst, M_IFADDR); - sc->gif_pdst = NULL; - } + struct ip ip; + struct gif_softc *sc; + struct sockaddr_in *src, *dst; + int addrmatch; + struct in_ifaddr *ia4; + + /* sanity check done in caller */ + sc = (struct gif_softc *)arg; + src = (struct sockaddr_in *)sc->gif_psrc; + dst = (struct sockaddr_in *)sc->gif_pdst; + + /* LINTED const cast */ + m_copydata((struct mbuf *)m, 0, sizeof(ip), (caddr_t)&ip); + + /* check for address match */ + addrmatch = 0; + if (src->sin_addr.s_addr == ip.ip_dst.s_addr) + addrmatch |= 1; + if (dst->sin_addr.s_addr == ip.ip_src.s_addr) + addrmatch |= 2; + if (addrmatch != 3) + return 0; + + /* martian filters on outer source - NOT done in ip_input! */ + if (IN_MULTICAST(ntohl(ip.ip_src.s_addr))) + return 0; + switch ((ntohl(ip.ip_src.s_addr) & 0xff000000) >> 24) { + case 0: case 127: case 255: + return 0; + } + /* reject packets with broadcast on source */ + for (ia4 = TAILQ_FIRST(&in_ifaddrhead); ia4; + ia4 = TAILQ_NEXT(ia4, ia_link)) + { + if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0) + continue; + if (ip.ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr) + return 0; + } - p = encap_attach(ifr->ifr_addr.sa_family, -1, src, - (struct sockaddr *)&smask4, dst, - (struct sockaddr *)&dmask4, - (struct protosw *)&in_gif_protosw, &sc->gif_if); - if (p == NULL) { - error = EINVAL; - goto bad; + /* ingress filters on outer source */ + if ((sc->gif_if.if_flags & IFF_LINK2) == 0 && + (m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.rcvif) { + struct sockaddr_in sin; + struct rtentry *rt; + + bzero(&sin, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_len = sizeof(struct sockaddr_in); + sin.sin_addr = ip.ip_src; + rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL); + if (!rt || rt->rt_ifp != m->m_pkthdr.rcvif) { +#if 0 + log(LOG_WARNING, "%s: packet from 0x%x dropped " + "due to ingress filter\n", if_name(&sc->gif_if), + (u_int32_t)ntohl(sin.sin_addr.s_addr)); +#endif + if (rt) + rtfree(rt); + return 0; } - sc->encap_cookie = p; - sc->gif_oflags = ifp->if_flags; - - sa = (struct sockaddr *)_MALLOC(size, M_IFADDR, M_WAITOK); - if (sa == NULL) - return (ENOMEM); - bcopy((caddr_t)src, (caddr_t)sa, size); - sc->gif_psrc = sa; - - sa = (struct sockaddr *)_MALLOC(size, M_IFADDR, M_WAITOK); - if (sa == NULL) - return (ENOMEM); - bcopy((caddr_t)dst, (caddr_t)sa, size); - sc->gif_pdst = sa; - - ifp->if_flags |= IFF_UP; - if_up(ifp); /* send up RTM_IFINFO */ - - error = 0; - break; - default: - error = EINVAL; - goto bad; + rtfree(rt); } - bad: - return error; + return 32 * 2; } diff --git a/bsd/netinet/in_gif.h b/bsd/netinet/in_gif.h index 8a1906d27..e6d09d293 100644 --- a/bsd/netinet/in_gif.h +++ b/bsd/netinet/in_gif.h @@ -52,6 +52,8 @@ #ifndef _NETINET_IN_GIF_H_ #define _NETINET_IN_GIF_H_ +#include +#ifdef __APPLE_API_PRIVATE #define GIF_TTL 30 @@ -59,10 +61,7 @@ extern int ip_gif_ttl; void in_gif_input __P((struct mbuf *, int)); int in_gif_output __P((struct ifnet *, int, struct mbuf *, struct rtentry *)); -#if defined(__FreeBSD__) && __FreeBSD__ < 3 -int in_gif_ioctl __P((struct ifnet *, int, caddr_t)); -#else -int in_gif_ioctl __P((struct ifnet *, u_long, caddr_t)); -#endif +int gif_encapcheck4 __P((const struct mbuf *, int, int, void *)); +#endif /* __APPLE_API_PRIVATE */ #endif /*_NETINET_IN_GIF_H_*/ diff --git a/bsd/netinet/in_hostcache.c b/bsd/netinet/in_hostcache.c deleted file mode 100644 index 0ff6a4070..000000000 --- a/bsd/netinet/in_hostcache.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright 1997 Massachusetts Institute of Technology - * - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby - * granted, provided that both the above copyright notice and this - * permission notice appear in all copies, that both the above - * copyright notice and this permission notice appear in all - * supporting documentation, and that the name of M.I.T. not be used - * in advertising or publicity pertaining to distribution of the - * software without specific, written prior permission. M.I.T. makes - * no representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied - * warranty. - * - * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS - * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT - * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/* - * Manage the IP per-host cache (really a thin veneer over the generic - * per-host cache code). - */ - -/* Look up an entry -- can be called from interrupt context. */ -struct in_hcentry * -inhc_lookup(struct sockaddr_in *sin) -{ - struct hcentry *hc; - - hc = hc_get((struct sockaddr *)sin); - return ((struct in_hcentry *)hc); -} - -/* Look up and possibly create an entry -- must be called from user mode. */ -struct in_hcentry * -inhc_alloc(struct sockaddr_in *sin) -{ - struct in_hcentry *inhc; - struct rtentry *rt; - int error; - /* xxx mutual exclusion for smp */ - - inhc = inhc_lookup(sin); - if (inhc != 0) - return inhc; - - rt = rtalloc1(inhc->inhc_hc.hc_host, 1, 0); - if (rt == 0) - return 0; - - MALLOC(inhc, struct in_hcentry *, sizeof *inhc, M_HOSTCACHE, M_WAITOK); - if (inhc == NULL) - retturn (ENOMEM); - bzero(inhc, sizeof *inhc); - inhc->inhc_hc.hc_host = dup_sockaddr((struct sockaddr *)sin, 1); - if (in_broadcast(sin->sin_addr, rt->rt_ifp)) - inhc->inhc_flags |= INHC_BROADCAST; - else if (((struct sockaddr_in *)rt->rt_ifa->ifa_addr)->sin_addr.s_addr - == sin->sin_addr.s_addr) - inhc->inhc_flags |= INHC_LOCAL; - else if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) - inhc->inhc_flags |= INHC_MULTICAST; - inhc->inhc_pmtu = rt->rt_rmx.rmx_mtu; - inhc->inhc_recvpipe = rt->rt_rmx.rmx_recvpipe; - inhc->inhc_sendpipe = rt->rt_rmx.rmx_sendpipe; - inhc->inhc_ssthresh = rt->rt_rmx.rmx_ssthresh; - if (rt->rt_rmx.rmx_locks & RTV_RTT) - inhc->inhc_rttmin = rt->rt_rmx.rmx_rtt - / (RTM_RTTUNIT / TCP_RTT_SCALE); - inhc->inhc_hc.hc_rt = rt; - error = hc_insert(&inhc->inhc_hc); - if (error != 0) { - RTFREE(rt); - FREE(inhc, M_HOSTCACHE); - return 0; - } - /* - * We don't return the structure directly because hc_get() needs - * to be allowed to do its own processing. - */ - return (inhc_lookup(sin)); -} - -/* - * This is Van Jacobson's hash function for IPv4 addresses. - * It is designed to work with a power-of-two-sized hash table. - */ -static u_long -inhc_hash(struct sockaddr *sa, u_long nbuckets) -{ - u_long ip; - - ip = ((struct sockaddr_in *)sa)->sin_addr.s_addr; - return ((ip ^ (ip >> 23) ^ (ip >> 17)) & ~(nbuckets - 1)); -} - -/* - * We don't need to do any special work... if there are no references, - * as the caller has already ensured, then it's OK to kill. - */ -static int -inhc_delete(struct hcentry *hc) -{ - return 0; -} - -/* - * Return the next increment for the number of buckets in the hash table. - * Zero means ``do not bump''. - */ -static u_long -inhc_bump(u_long oldsize) -{ - if (oldsize < 512) - return (oldsize << 1); - return 0; -} - -static struct hccallback inhc_cb = { - inhc_hash, inhc_delete, inhc_bump -}; - -int -inhc_init(void) -{ - - return (hc_init(AF_INET, &inhc_cb, 128, 0)); -} - diff --git a/bsd/netinet/in_hostcache.h b/bsd/netinet/in_hostcache.h deleted file mode 100644 index 0ee6ca532..000000000 --- a/bsd/netinet/in_hostcache.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright 1997 Massachusetts Institute of Technology - * - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby - * granted, provided that both the above copyright notice and this - * permission notice appear in all copies, that both the above - * copyright notice and this permission notice appear in all - * supporting documentation, and that the name of M.I.T. not be used - * in advertising or publicity pertaining to distribution of the - * software without specific, written prior permission. M.I.T. makes - * no representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied - * warranty. - * - * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS - * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT - * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -#ifndef _NETINET_IN_HOSTCACHE_H -#define _NETINET_IN_HOSTCACHE_H 1 - -/* - * This file defines the particular structures contained in the host cache - * for the use of IP. - */ - -/* - * An IP host cache entry. Note that we include the srtt/var here, - * with the expectation that it might be used to keep a persistent, - * cross-connection view of this statistic. - */ -struct in_hcentry { - struct hcentry inhc_hc; - u_long inhc_pmtu; - u_long inhc_recvpipe; - u_long inhc_sendpipe; - u_long inhc_pksent; - u_long inhc_flags; - u_long inhc_ssthresh; - int inhc_srtt; /* VJ RTT estimator */ - int inhc_srttvar; /* VJ */ - u_int inhc_rttmin; /* VJ */ - int inhc_rxt; /* TCP retransmit timeout */ - u_long inhc_cc; /* deliberate type pun with tcp_cc */ - u_long inhc_ccsent; /* as above */ - u_short inhc_mssopt; -}; - -#define inhc_addr(inhc) ((struct sockaddr_in *)(inhc)->inhc_hc.hc_host) - -/* Flags for inhc_flags... */ -#define INHC_LOCAL 0x0001 /* this address is local */ -#define INHC_BROADCAST 0x0002 /* this address is broadcast */ -#define INHC_MULTICAST 0x0004 /* this address is multicast */ -#define INHC_REDUCEDMTU 0x0008 /* we reduced the mtu via PMTU discovery */ - -#ifdef KERNEL -/* - * inhc_alloc can block while adding a new entry to the cache; - * inhc_lookup will does not add new entries and so can be called - * in non-process context. - */ -struct in_hcentry *inhc_alloc(struct sockaddr_in *sin); -int inhc_init(void); -struct in_hcentry *inhc_lookup(struct sockaddr_in *sin); -#define inhc_ref(inhc) (hc_ref(&(inhc)->inhc_hc)) -#define inhc_rele(inhc) (hc_rele(&(inhc)->inhc_hc)) -#endif /* KERNEL */ - -#endif /* _NETINET_IN_HOSTCACHE_H */ diff --git a/bsd/netinet/in_pcb.c b/bsd/netinet/in_pcb.c index d12ef72b2..bc9d086db 100644 --- a/bsd/netinet/in_pcb.c +++ b/bsd/netinet/in_pcb.c @@ -52,33 +52,33 @@ * SUCH DAMAGE. * * @(#)in_pcb.c 8.4 (Berkeley) 5/24/95 + * $FreeBSD: src/sys/netinet/in_pcb.c,v 1.59.2.17 2001/08/13 16:26:17 ume Exp $ */ #include #include #include #include -#if INET6 #include -#endif #include #include #include #include +#ifndef __APPLE__ +#include +#endif #include #include #include -#if ISFB31 -#include -#else +#ifdef __APPLE__ #include #endif #include -#include #include +#include #include #include @@ -94,37 +94,39 @@ #if IPSEC #include #include -#include #endif /* IPSEC */ #include +#if IPSEC +extern int ipsec_bypass; +#endif #define DBG_FNC_PCB_LOOKUP NETDBG_CODE(DBG_NETTCP, (6 << 8)) #define DBG_FNC_PCB_HLOOKUP NETDBG_CODE(DBG_NETTCP, ((6 << 8) | 1)) struct in_addr zeroin_addr; -void in_pcbremlists __P((struct inpcb *)); -static void in_rtchange __P((struct inpcb *, int)); - - /* * These configure the range of local port addresses assigned to * "unspecified" outgoing connections/packets/whatever. */ -int ipport_lowfirstauto = IPPORT_RESERVED - 1; /* 1023 */ -int ipport_lowlastauto = IPPORT_RESERVEDSTART; /* 600 */ -int ipport_firstauto = IPPORT_HIFIRSTAUTO; /* 49152 */ -int ipport_lastauto = IPPORT_HILASTAUTO; /* 65535 */ -int ipport_hifirstauto = IPPORT_HIFIRSTAUTO; /* 49152 */ -int ipport_hilastauto = IPPORT_HILASTAUTO; /* 65535 */ +int ipport_lowfirstauto = IPPORT_RESERVED - 1; /* 1023 */ +int ipport_lowlastauto = IPPORT_RESERVEDSTART; /* 600 */ +#ifndef __APPLE__ +int ipport_firstauto = IPPORT_RESERVED; /* 1024 */ +int ipport_lastauto = IPPORT_USERRESERVED; /* 5000 */ +#else +int ipport_firstauto = IPPORT_HIFIRSTAUTO; /* 49152 */ +int ipport_lastauto = IPPORT_HILASTAUTO; /* 65535 */ +#endif +int ipport_hifirstauto = IPPORT_HIFIRSTAUTO; /* 49152 */ +int ipport_hilastauto = IPPORT_HILASTAUTO; /* 65535 */ #define RANGECHK(var, min, max) \ if ((var) < (min)) { (var) = (min); } \ else if ((var) > (max)) { (var) = (max); } - static int sysctl_net_ipport_check SYSCTL_HANDLER_ARGS { @@ -177,6 +179,9 @@ in_pcballoc(so, pcbinfo, p) { register struct inpcb *inp; caddr_t temp; +#if IPSEC + int error; +#endif if (so->cached_in_sock_layer == 0) { #if TEMPDEBUG @@ -200,9 +205,28 @@ in_pcballoc(so, pcbinfo, p) inp->inp_gencnt = ++pcbinfo->ipi_gencnt; inp->inp_pcbinfo = pcbinfo; inp->inp_socket = so; +#if IPSEC +#ifndef __APPLE__ + if (ipsec_bypass == 0) { + error = ipsec_init_policy(so, &inp->inp_sp); + if (error != 0) { + zfree(pcbinfo->ipi_zone, (vm_offset_t)inp); + return error; + } + } +#endif +#endif /*IPSEC*/ +#if defined(INET6) + if (INP_SOCKAF(so) == AF_INET6 && !ip6_mapped_addr_on) + inp->inp_flags |= IN6P_IPV6_V6ONLY; +#endif LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list); pcbinfo->ipi_count++; so->so_pcb = (caddr_t)inp; +#if INET6 + if (ip6_auto_flowlabel) + inp->inp_flags |= IN6P_AUTOFLOWLABEL; +#endif return (0); } @@ -213,7 +237,7 @@ in_pcbbind(inp, nam, p) struct proc *p; { register struct socket *so = inp->inp_socket; - u_short *lastport; + unsigned short *lastport; struct sockaddr_in *sin; struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; u_short lport = 0; @@ -272,14 +296,13 @@ in_pcbbind(inp, nam, p) SO_REUSEPORT) == 0) && (so->so_uid != t->inp_socket->so_uid)) { #if INET6 - if (ip6_mapped_addr_on == 0 || - ntohl(sin->sin_addr.s_addr) != + if (ntohl(sin->sin_addr.s_addr) != INADDR_ANY || ntohl(t->inp_laddr.s_addr) != INADDR_ANY || INP_SOCKAF(so) == INP_SOCKAF(t->inp_socket)) -#endif +#endif /* defined(INET6) */ return (EADDRINUSE); } } @@ -295,7 +318,7 @@ in_pcbbind(inp, nam, p) INADDR_ANY || INP_SOCKAF(so) == INP_SOCKAF(t->inp_socket)) -#endif +#endif /* defined(INET6) */ return (EADDRINUSE); } } @@ -337,12 +360,8 @@ in_pcbbind(inp, nam, p) do { if (count-- < 0) { /* completely used? */ - /* - * Undo any address bind that may have - * occurred above. - */ inp->inp_laddr.s_addr = INADDR_ANY; - return (EAGAIN); + return (EADDRNOTAVAIL); } --*lastport; if (*lastport > first || *lastport < last) @@ -358,12 +377,8 @@ in_pcbbind(inp, nam, p) do { if (count-- < 0) { /* completely used? */ - /* - * Undo any address bind that may have - * occurred above. - */ inp->inp_laddr.s_addr = INADDR_ANY; - return (EAGAIN); + return (EADDRNOTAVAIL); } ++*lastport; if (*lastport < first || *lastport > last) @@ -421,10 +436,10 @@ in_pcbladdr(inp, nam, plocal_sin) #define sintosa(sin) ((struct sockaddr *)(sin)) #define ifatoia(ifa) ((struct in_ifaddr *)(ifa)) if (sin->sin_addr.s_addr == INADDR_ANY) - sin->sin_addr = IA_SIN(in_ifaddrhead.tqh_first)->sin_addr; + sin->sin_addr = IA_SIN(TAILQ_FIRST(&in_ifaddrhead))->sin_addr; else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST && - (in_ifaddrhead.tqh_first->ia_ifp->if_flags & IFF_BROADCAST)) - sin->sin_addr = satosin(&in_ifaddrhead.tqh_first->ia_broadaddr)->sin_addr; + (TAILQ_FIRST(&in_ifaddrhead)->ia_ifp->if_flags & IFF_BROADCAST)) + sin->sin_addr = satosin(&TAILQ_FIRST(&in_ifaddrhead)->ia_broadaddr)->sin_addr; } if (inp->inp_laddr.s_addr == INADDR_ANY) { register struct route *ro; @@ -439,7 +454,7 @@ in_pcbladdr(inp, nam, plocal_sin) (satosin(&ro->ro_dst)->sin_addr.s_addr != sin->sin_addr.s_addr || inp->inp_socket->so_options & SO_DONTROUTE)) { - RTFREE(ro->ro_rt); + rtfree(ro->ro_rt); ro->ro_rt = (struct rtentry *)0; } if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ @@ -469,7 +484,7 @@ in_pcbladdr(inp, nam, plocal_sin) ia = ifatoia(ifa_ifwithnet(sintosa(sin))); sin->sin_port = fport; if (ia == 0) - ia = in_ifaddrhead.tqh_first; + ia = TAILQ_FIRST(&in_ifaddrhead); if (ia == 0) return (EADDRNOTAVAIL); } @@ -486,8 +501,7 @@ in_pcbladdr(inp, nam, plocal_sin) imo = inp->inp_moptions; if (imo->imo_multicast_ifp != NULL) { ifp = imo->imo_multicast_ifp; - for (ia = in_ifaddrhead.tqh_first; ia; - ia = ia->ia_link.tqe_next) + TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) if (ia->ia_ifp == ifp) break; if (ia == 0) @@ -518,7 +532,8 @@ in_pcbconnect(inp, nam, p) struct proc *p; { struct sockaddr_in *ifaddr; - register struct sockaddr_in *sin = (struct sockaddr_in *)nam; + struct sockaddr_in *sin = (struct sockaddr_in *)nam; + struct sockaddr_in sa; int error; /* @@ -533,8 +548,11 @@ in_pcbconnect(inp, nam, p) return (EADDRINUSE); } if (inp->inp_laddr.s_addr == INADDR_ANY) { - if (inp->inp_lport == 0) - (void)in_pcbbind(inp, (struct sockaddr *)0, p); + if (inp->inp_lport == 0) { + error = in_pcbbind(inp, (struct sockaddr *)0, p); + if (error) + return (error); + } inp->inp_laddr = ifaddr->sin_addr; } inp->inp_faddr = sin->sin_addr; @@ -561,6 +579,7 @@ in_pcbdetach(inp) { struct socket *so = inp->inp_socket; struct inpcbinfo *ipi = inp->inp_pcbinfo; + struct rtentry *rt = inp->inp_route.ro_rt; #if IPSEC ipsec4_delete_pcbpolicy(inp); @@ -579,9 +598,24 @@ in_pcbdetach(inp) if (inp->inp_options) (void)m_free(inp->inp_options); - if (inp->inp_route.ro_rt) - rtfree(inp->inp_route.ro_rt); + if (rt) { + /* + * route deletion requires reference count to be <= zero + */ + if ((rt->rt_flags & RTF_DELCLONE) && + (rt->rt_flags & RTF_WASCLONED) && + (rt->rt_refcnt <= 1)) { + rtunref(rt); + rt->rt_flags &= ~RTF_UP; + rtrequest(RTM_DELETE, rt_key(rt), + rt->rt_gateway, rt_mask(rt), + rt->rt_flags, (struct rtentry **)0); + } + else + rtfree(rt); + } ip_freemoptions(inp->inp_moptions); + inp->inp_vflag = 0; if (so->cached_in_sock_layer) so->so_saved_pcb = (caddr_t) inp; else @@ -624,7 +658,7 @@ in_setsockaddr(so, nam) if (!inp) { splx(s); FREE(sin, M_SONAME); - return EINVAL; + return ECONNRESET; } sin->sin_port = inp->inp_lport; sin->sin_addr = inp->inp_laddr; @@ -658,7 +692,7 @@ in_setpeeraddr(so, nam) if (!inp) { splx(s); FREE(sin, M_SONAME); - return EINVAL; + return ECONNRESET; } sin->sin_port = inp->inp_fport; sin->sin_addr = inp->inp_faddr; @@ -668,72 +702,68 @@ in_setpeeraddr(so, nam) return 0; } -/* - * 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. - */ void -in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify) +in_pcbnotifyall(head, faddr, errno, notify) struct inpcbhead *head; - struct sockaddr *dst; - u_int fport_arg, lport_arg; - struct in_addr laddr; - int cmd; + struct in_addr faddr; void (*notify) __P((struct inpcb *, int)); { - register struct inpcb *inp, *oinp; - struct in_addr faddr; - u_short fport = fport_arg, lport = lport_arg; - int errno, s; - - 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; + struct inpcb *inp, *ninp; + int s; - /* - * 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]; s = splnet(); - for (inp = head->lh_first; inp != NULL;) { - if ((inp->inp_vflag & INP_IPV4) == NULL) { - inp = LIST_NEXT(inp, inp_list); + for (inp = LIST_FIRST(head); inp != NULL; inp = ninp) { + ninp = LIST_NEXT(inp, inp_list); +#if INET6 + if ((inp->inp_vflag & INP_IPV4) == 0) continue; - } +#endif 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 = LIST_NEXT(inp, inp_list); - continue; - } - oinp = inp; - inp = LIST_NEXT(inp, inp_list); - if (notify) - (*notify)(oinp, errno); + inp->inp_socket == NULL) + continue; + (*notify)(inp, errno); } splx(s); } +void +in_pcbpurgeif0(head, ifp) + struct inpcb *head; + struct ifnet *ifp; +{ + struct inpcb *inp; + struct ip_moptions *imo; + int i, gap; + + for (inp = head; inp != NULL; inp = LIST_NEXT(inp, inp_list)) { + imo = inp->inp_moptions; + if ((inp->inp_vflag & INP_IPV4) && + imo != NULL) { + /* + * Unselect the outgoing interface if it is being + * detached. + */ + if (imo->imo_multicast_ifp == ifp) + imo->imo_multicast_ifp = NULL; + + /* + * Drop multicast group membership if we joined + * through the interface being detached. + */ + for (i = 0, gap = 0; i < imo->imo_num_memberships; + i++) { + if (imo->imo_membership[i]->inm_ifp == ifp) { + in_delmulti(imo->imo_membership[i]); + gap++; + } else if (gap != 0) + imo->imo_membership[i - gap] = + imo->imo_membership[i]; + } + imo->imo_num_memberships -= gap; + } + } +} + /* * Check for alternatives when higher level complains * about service problems. For now, invalidate cached @@ -748,7 +778,6 @@ in_losing(inp) struct rt_addrinfo info; if ((rt = inp->inp_route.ro_rt)) { - inp->inp_route.ro_rt = 0; bzero((caddr_t)&info, sizeof(info)); info.rti_info[RTAX_DST] = (struct sockaddr *)&inp->inp_route.ro_dst; @@ -759,12 +788,12 @@ in_losing(inp) (void) rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt), rt->rt_flags, (struct rtentry **)0); - else + inp->inp_route.ro_rt = 0; + rtfree(rt); /* * A new route can be allocated * the next time output is attempted. */ - rtfree(rt); } } @@ -772,7 +801,7 @@ in_losing(inp) * After a routing change, flush old routing * and allocate a (hopefully) better one. */ -static void +void in_rtchange(inp, errno) register struct inpcb *inp; int errno; @@ -810,9 +839,11 @@ in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay) * matches the local address and port we're looking for. */ head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)]; - for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { - if ((inp->inp_vflag & INP_IPV4) == NULL) + LIST_FOREACH(inp, head, inp_hash) { +#if INET6 + if ((inp->inp_vflag & INP_IPV4) == 0) continue; +#endif if (inp->inp_faddr.s_addr == INADDR_ANY && inp->inp_laddr.s_addr == laddr.s_addr && inp->inp_lport == lport) { @@ -839,7 +870,7 @@ in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay) */ porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport, pcbinfo->porthashmask)]; - for (phd = porthash->lh_first; phd != NULL; phd = phd->phd_hash.le_next) { + LIST_FOREACH(phd, porthash, phd_hash) { if (phd->phd_port == lport) break; } @@ -848,11 +879,12 @@ in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay) * Port is in use by one or more PCBs. Look for best * fit. */ - for (inp = phd->phd_pcblist.lh_first; inp != NULL; - inp = inp->inp_portlist.le_next) { + LIST_FOREACH(inp, &phd->phd_pcblist, inp_portlist) { wildcard = 0; - if ((inp->inp_vflag & INP_IPV4) == NULL) +#if INET6 + if ((inp->inp_vflag & INP_IPV4) == 0) continue; +#endif if (inp->inp_faddr.s_addr != INADDR_ANY) wildcard++; if (inp->inp_laddr.s_addr != INADDR_ANY) { @@ -882,7 +914,8 @@ in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay) * Lookup PCB in hash list. */ struct inpcb * -in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, ifp) +in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, + ifp) struct inpcbinfo *pcbinfo; struct in_addr faddr, laddr; u_int fport_arg, lport_arg; @@ -915,9 +948,11 @@ in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, ifp) * First look for an exact match. */ head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)]; - for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { - if ((inp->inp_vflag & INP_IPV4) == NULL) + LIST_FOREACH(inp, head, inp_hash) { +#if INET6 + if ((inp->inp_vflag & INP_IPV4) == 0) continue; +#endif if (inp->inp_faddr.s_addr == faddr.s_addr && inp->inp_laddr.s_addr == laddr.s_addr && inp->inp_fport == fport && @@ -935,9 +970,11 @@ in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, ifp) #endif head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)]; - for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { - if ((inp->inp_vflag & INP_IPV4) == NULL) + LIST_FOREACH(inp, head, inp_hash) { +#if INET6 + if ((inp->inp_vflag & INP_IPV4) == 0) continue; +#endif if (inp->inp_faddr.s_addr == INADDR_ANY && inp->inp_lport == lport) { #if defined(NFAITH) && NFAITH > 0 @@ -948,20 +985,20 @@ in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, ifp) if (inp->inp_laddr.s_addr == laddr.s_addr) return (inp); else if (inp->inp_laddr.s_addr == INADDR_ANY) { -#if INET6 +#if defined(INET6) if (INP_CHECK_SOCKAF(inp->inp_socket, AF_INET6)) local_wild_mapped = inp; else -#endif +#endif /* defined(INET6) */ local_wild = inp; } } } -#if INET6 +#if defined(INET6) if (local_wild == NULL) return (local_wild_mapped); -#endif +#endif /* defined(INET6) */ return (local_wild); } @@ -1000,7 +1037,7 @@ in_pcbinshash(inp) /* * Go through port list and look for a head for this lport. */ - for (phd = pcbporthash->lh_first; phd != NULL; phd = phd->phd_hash.le_next) { + LIST_FOREACH(phd, pcbporthash, phd_hash) { if (phd->phd_port == inp->inp_lport) break; } @@ -1019,8 +1056,10 @@ in_pcbinshash(inp) inp->inp_phd = phd; LIST_INSERT_HEAD(&phd->phd_pcblist, inp, inp_portlist); LIST_INSERT_HEAD(pcbhash, inp, inp_hash); +#ifdef __APPLE__ inp->hash_element = INP_PCBHASH(inp->inp_faddr.s_addr, inp->inp_lport, inp->inp_fport, pcbinfo->hashmask); +#endif return (0); } @@ -1049,8 +1088,10 @@ in_pcbrehash(inp) LIST_REMOVE(inp, inp_hash); LIST_INSERT_HEAD(head, inp, inp_hash); +#ifdef __APPLE__ inp->hash_element = INP_PCBHASH(inp->inp_faddr.s_addr, inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask); +#endif } /* @@ -1061,20 +1102,21 @@ in_pcbremlists(inp) struct inpcb *inp; { inp->inp_gencnt = ++inp->inp_pcbinfo->ipi_gencnt; +#ifdef __APPLE__ if (inp == inp->inp_pcbinfo->last_pcb) inp->inp_pcbinfo->last_pcb = 0; +#endif if (inp->inp_lport) { struct inpcbport *phd = inp->inp_phd; LIST_REMOVE(inp, inp_hash); LIST_REMOVE(inp, inp_portlist); - if (phd->phd_pcblist.lh_first == NULL) { + if (LIST_FIRST(&phd->phd_pcblist) == NULL) { LIST_REMOVE(phd, phd_hash); FREE(phd, M_PCB); } } - LIST_REMOVE(inp, inp_list); inp->inp_pcbinfo->ipi_count--; } @@ -1364,6 +1406,8 @@ in_pcb_rem_share_client(struct inpcbinfo *pcbinfo, u_char owner_id) return 0; } + + void in_pcb_nat_init(struct inpcbinfo *pcbinfo, int afamily, int pfamily, int protocol) { @@ -1371,3 +1415,15 @@ void in_pcb_nat_init(struct inpcbinfo *pcbinfo, int afamily, pcbinfo->nat_dummy_socket.so_proto = pffindproto(afamily, pfamily, protocol); pcbinfo->all_owners = 0; } + + +#ifndef __APPLE__ +prison_xinpcb(struct proc *p, struct inpcb *inp) +{ + if (!p->p_prison) + return (0); + if (ntohl(inp->inp_laddr.s_addr) == p->p_prison->pr_ip) + return (0); + return (1); +} +#endif diff --git a/bsd/netinet/in_pcb.h b/bsd/netinet/in_pcb.h index 0dc2ab78a..38acfdf50 100644 --- a/bsd/netinet/in_pcb.h +++ b/bsd/netinet/in_pcb.h @@ -52,18 +52,22 @@ * SUCH DAMAGE. * * @(#)in_pcb.h 8.1 (Berkeley) 6/10/93 + * $FreeBSD: src/sys/netinet/in_pcb.h,v 1.32.2.4 2001/08/13 16:26:17 ume Exp $ */ #ifndef _NETINET_IN_PCB_H_ #define _NETINET_IN_PCB_H_ +#include #include -#if IPSEC -#include -#endif -#define in6pcb inpcb /* for KAME src sync over BSD*'s */ -#define in6p_sp inp_sp /* for KAME src sync over BSD*'s */ + +#include /* for IPSEC */ + +#ifdef __APPLE_API_PRIVATE + +#define in6pcb inpcb /* for KAME src sync over BSD*'s */ +#define in6p_sp inp_sp /* for KAME src sync over BSD*'s */ /* * Common structure pcb for internet protocol implementation. @@ -82,8 +86,8 @@ typedef u_quad_t inp_gen_t; * by utilize following structure. (At last, same as INRIA) */ struct in_addr_4in6 { - u_int32_t ia46_pad32[3]; - struct in_addr ia46_addr4; + u_int32_t ia46_pad32[3]; + struct in_addr ia46_addr4; }; /* @@ -92,7 +96,7 @@ struct in_addr_4in6 { * that position not contain any information which is required to be * stable. */ -struct icmp6_filter; +struct icmp6_filter; struct inpcb { LIST_ENTRY(inpcb) inp_hash; /* hash list */ @@ -121,18 +125,18 @@ struct inpcb { /* protocol dependent part */ union { /* foreign host table entry */ - struct in_addr_4in6 inp46_foreign; - struct in6_addr inp6_foreign; + struct in_addr_4in6 inp46_foreign; + struct in6_addr inp6_foreign; } inp_dependfaddr; union { /* local host table entry */ - struct in_addr_4in6 inp46_local; - struct in6_addr inp6_local; + struct in_addr_4in6 inp46_local; + struct in6_addr inp6_local; } inp_dependladdr; union { /* placeholder for routing entry */ - struct route inp4_route; - struct route_in6 inp6_route; + struct route inp4_route; + struct route_in6 inp6_route; } inp_dependroute; struct { /* type of service proto */ @@ -142,54 +146,55 @@ struct inpcb { /* IP multicast options */ struct ip_moptions *inp4_moptions; } inp_depend4; -#define inp_faddr inp_dependfaddr.inp46_foreign.ia46_addr4 -#define inp_laddr inp_dependladdr.inp46_local.ia46_addr4 -#define inp_route inp_dependroute.inp4_route -#define inp_ip_tos inp_depend4.inp4_ip_tos -#define inp_options inp_depend4.inp4_options -#define inp_moptions inp_depend4.inp4_moptions +#define inp_faddr inp_dependfaddr.inp46_foreign.ia46_addr4 +#define inp_laddr inp_dependladdr.inp46_local.ia46_addr4 +#define inp_route inp_dependroute.inp4_route +#define inp_ip_tos inp_depend4.inp4_ip_tos +#define inp_options inp_depend4.inp4_options +#define inp_moptions inp_depend4.inp4_moptions struct { /* IP options */ struct mbuf *inp6_options; - /* IP6 options for incoming packets */ - struct ip6_recvpktopts *inp6_inputopts; + u_int8_t inp6_hlim; + u_int8_t unused_uint8_1; + ushort unused_uint16_1; /* IP6 options for outgoing packets */ - struct ip6_pktopts *inp6_outputopts; + struct ip6_pktopts *inp6_outputopts; /* IP multicast options */ - struct ip6_moptions *inp6_moptions; + struct ip6_moptions *inp6_moptions; /* ICMPv6 code type filter */ - struct icmp6_filter *inp6_icmp6filt; + struct icmp6_filter *inp6_icmp6filt; /* IPV6_CHECKSUM setsockopt */ - int inp6_cksum; + int inp6_cksum; u_short inp6_ifindex; short inp6_hops; } inp_depend6; -#define in6p_faddr inp_dependfaddr.inp6_foreign -#define in6p_laddr inp_dependladdr.inp6_local -#define in6p_route inp_dependroute.inp6_route -#define in6p_hops inp_depend6.inp6_hops /* default hop limit */ -#define in6p_ip6_nxt inp_ip_p -#define in6p_flowinfo inp_flow -#define in6p_vflag inp_vflag -#define in6p_options inp_depend6.inp6_options -#define in6p_inputopts inp_depend6.inp6_inputopts -#define in6p_outputopts inp_depend6.inp6_outputopts -#define in6p_moptions inp_depend6.inp6_moptions -#define in6p_icmp6filt inp_depend6.inp6_icmp6filt -#define in6p_cksum inp_depend6.inp6_cksum -#define inp6_ifindex inp_depend6.inp6_ifindex -#define in6p_flags inp_flags /* for KAME src sync over BSD*'s */ -#define in6p_socket inp_socket /* for KAME src sync over BSD*'s */ -#define in6p_lport inp_lport /* for KAME src sync over BSD*'s */ -#define in6p_fport inp_fport /* for KAME src sync over BSD*'s */ -#define in6p_ppcb inp_ppcb /* for KAME src sync over BSD*'s */ -#if IPSEC - struct inpcbpolicy *inp_sp; -#endif +#define in6p_faddr inp_dependfaddr.inp6_foreign +#define in6p_laddr inp_dependladdr.inp6_local +#define in6p_route inp_dependroute.inp6_route +#define in6p_ip6_hlim inp_depend6.inp6_hlim +#define in6p_hops inp_depend6.inp6_hops /* default hop limit */ +#define in6p_ip6_nxt inp_ip_p +#define in6p_flowinfo inp_flow +#define in6p_vflag inp_vflag +#define in6p_options inp_depend6.inp6_options +#define in6p_outputopts inp_depend6.inp6_outputopts +#define in6p_moptions inp_depend6.inp6_moptions +#define in6p_icmp6filt inp_depend6.inp6_icmp6filt +#define in6p_cksum inp_depend6.inp6_cksum +#define inp6_ifindex inp_depend6.inp6_ifindex +#define in6p_flags inp_flags /* for KAME src sync over BSD*'s */ +#define in6p_socket inp_socket /* for KAME src sync over BSD*'s */ +#define in6p_lport inp_lport /* for KAME src sync over BSD*'s */ +#define in6p_fport inp_fport /* for KAME src sync over BSD*'s */ +#define in6p_ppcb inp_ppcb /* for KAME src sync over BSD*'s */ + int hash_element; /* Array index of pcb's hash list */ caddr_t inp_saved_ppcb; /* place to save pointer while cached */ - u_long reserved[4]; + struct inpcbpolicy *inp_sp; + u_long reserved[3]; /* For future use */ }; +#endif /* __APPLE_API_PRIVATE */ /* * The range of the generation count, as used in this implementation, * is 9e19. We would have to create 300 billion connections per @@ -217,6 +222,7 @@ struct xinpgen { }; #endif /* _SYS_SOCKETVAR_H_ */ +#ifdef __APPLE_API_PRIVATE struct inpcbport { LIST_ENTRY(inpcbport) phd_hash; struct inpcbhead phd_pcblist; @@ -225,7 +231,9 @@ struct inpcbport { struct inpcbinfo { /* XXX documentation, prefixes */ struct inpcbhead *hashbase; +#ifdef __APPLE__ u_long hashsize; /* in elements */ +#endif u_long hashmask; struct inpcbporthead *porthashbase; u_long porthashmask; @@ -236,10 +244,12 @@ struct inpcbinfo { /* XXX documentation, prefixes */ void *ipi_zone; /* zone to allocate pcbs from */ u_int ipi_count; /* number of pcbs in this list */ u_quad_t ipi_gencnt; /* current generation count */ - u_char all_owners; - struct socket nat_dummy_socket; +#ifdef __APPLE__ + u_char all_owners; + struct socket nat_dummy_socket; struct inpcb *last_pcb; - caddr_t dummy_cb; + caddr_t dummy_cb; +#endif }; #define INP_PCBHASH(faddr, lport, fport, mask) \ @@ -257,22 +267,29 @@ struct inpcbinfo { /* XXX documentation, prefixes */ #define INP_ANONPORT 0x40 /* port chosen for user */ #define INP_RECVIF 0x80 /* receive incoming interface */ #define INP_MTUDISC 0x100 /* user can do MTU discovery */ -#define INP_STRIPHDR 0x200 /* drop receive of raw IP header */ -#define INP_FAITH 0x400 /* accept FAITH'ed connections */ -#define IN6P_PKTINFO 0x010000 /* receive IP6 dst and I/F */ -#define IN6P_HOPLIMIT 0x020000 /* receive hoplimit */ -#define IN6P_HOPOPTS 0x040000 /* receive hop-by-hop options */ -#define IN6P_DSTOPTS 0x080000 /* receive dst options after rthdr */ -#define IN6P_RTHDR 0x100000 /* receive routing header */ -#define IN6P_RTHDRDSTOPTS 0x200000 /* receive dstoptions before rthdr */ -#define IN6P_BINDV6ONLY 0x10000000 /* do not grab IPv4 traffic */ -#define IN6P_MINMTU 0x20000000 /* use minimum MTU */ +#ifdef __APPLE__ +#define INP_STRIPHDR 0x200 /* Strip headers in raw_ip, for OT support */ +#endif +#define INP_FAITH 0x400 /* accept FAITH'ed connections */ + +#define IN6P_IPV6_V6ONLY 0x008000 /* restrict AF_INET6 socket for v6 */ + +#define IN6P_PKTINFO 0x010000 /* receive IP6 dst and I/F */ +#define IN6P_HOPLIMIT 0x020000 /* receive hoplimit */ +#define IN6P_HOPOPTS 0x040000 /* receive hop-by-hop options */ +#define IN6P_DSTOPTS 0x080000 /* receive dst options after rthdr */ +#define IN6P_RTHDR 0x100000 /* receive routing header */ +#define IN6P_RTHDRDSTOPTS 0x200000 /* receive dstoptions before rthdr */ +#define IN6P_AUTOFLOWLABEL 0x800000 /* attach flowlabel automatically */ +#define IN6P_BINDV6ONLY 0x10000000 /* do not grab IPv4 traffic */ #define INP_CONTROLOPTS (INP_RECVOPTS|INP_RECVRETOPTS|INP_RECVDSTADDR|\ INP_RECVIF|\ IN6P_PKTINFO|IN6P_HOPLIMIT|IN6P_HOPOPTS|\ - IN6P_DSTOPTS|IN6P_RTHDR|IN6P_RTHDRDSTOPTS) -#define INP_UNMAPPABLEOPTS (IN6P_HOPOPTS|IN6P_DSTOPTS|IN6P_RTHDR) + IN6P_DSTOPTS|IN6P_RTHDR|IN6P_RTHDRDSTOPTS|\ + IN6P_AUTOFLOWLABEL) +#define INP_UNMAPPABLEOPTS (IN6P_HOPOPTS|IN6P_DSTOPTS|IN6P_RTHDR|\ + IN6P_AUTOFLOWLABEL) /* for KAME src sync over BSD*'s */ #define IN6P_HIGHPORT INP_HIGHPORT @@ -281,35 +298,38 @@ struct inpcbinfo { /* XXX documentation, prefixes */ #define IN6P_RECVIF INP_RECVIF #define IN6P_MTUDISC INP_MTUDISC #define IN6P_FAITH INP_FAITH -#define IN6P_CONTROLOPTS INP_CONTROLOPTS +#define IN6P_CONTROLOPTS INP_CONTROLOPTS /* - * socket AF version is {newer than,or include} + * socket AF version is {newer than,or include} * actual datagram AF version */ #define INPLOOKUP_WILDCARD 1 +#ifdef __APPLE__ #define INPCB_ALL_OWNERS 0xff #define INPCB_NO_OWNER 0x0 #define INPCB_OWNED_BY_X 0x80 #define INPCB_MAX_IDS 7 +#endif #define sotoinpcb(so) ((struct inpcb *)(so)->so_pcb) #define sotoin6pcb(so) sotoinpcb(so) /* for KAME src sync over BSD*'s */ -#define INP_SOCKAF(so) so->so_proto->pr_domain->dom_family +#define INP_SOCKAF(so) so->so_proto->pr_domain->dom_family -#define INP_CHECK_SOCKAF(so, af) \ - (INP_SOCKAF(so) == af) +#define INP_CHECK_SOCKAF(so, af) (INP_SOCKAF(so) == af) #ifdef KERNEL -extern int ipport_lowfirstauto; -extern int ipport_lowlastauto; -extern int ipport_firstauto; -extern int ipport_lastauto; -extern int ipport_hifirstauto; -extern int ipport_hilastauto; - +extern int ipport_lowfirstauto; +extern int ipport_lowlastauto; +extern int ipport_firstauto; +extern int ipport_lastauto; +extern int ipport_hifirstauto; +extern int ipport_hilastauto; + +void in_pcbpurgeif0 __P((struct inpcb *, struct ifnet *)); void in_losing __P((struct inpcb *)); +void in_rtchange __P((struct inpcb *, int)); int in_pcballoc __P((struct socket *, struct inpcbinfo *, struct proc *)); int in_pcbbind __P((struct inpcb *, struct sockaddr *, struct proc *)); int in_pcbconnect __P((struct inpcb *, struct sockaddr *, struct proc *)); @@ -323,13 +343,15 @@ struct inpcb * struct in_addr, u_int, int)); struct inpcb * in_pcblookup_hash __P((struct inpcbinfo *, - struct in_addr, u_int, struct in_addr, u_int, int, struct ifnet *)); -void in_pcbnotify __P((struct inpcbhead *, struct sockaddr *, - u_int, struct in_addr, u_int, int, void (*)(struct inpcb *, int))); + struct in_addr, u_int, struct in_addr, u_int, + int, struct ifnet *)); +void in_pcbnotifyall __P((struct inpcbhead *, struct in_addr, + int, void (*)(struct inpcb *, int))); void in_pcbrehash __P((struct inpcb *)); int in_setpeeraddr __P((struct socket *so, struct sockaddr **nam)); int in_setsockaddr __P((struct socket *so, struct sockaddr **nam)); +#ifdef __APPLE__ int in_pcb_grab_port __P((struct inpcbinfo *pcbinfo, u_short options, @@ -363,12 +385,13 @@ in_pcb_new_share_client(struct inpcbinfo *pcbinfo, u_char *owner_id); int in_pcb_rem_share_client(struct inpcbinfo *pcbinfo, u_char owner_id); +#endif /* __APPLE__ */ void in_pcbremlists __P((struct inpcb *inp)); -#if INET6 -int in6_selecthlim __P((struct inpcb *, struct ifnet *)); +#ifndef __APPLE__ +int prison_xinpcb __P((struct proc *p, struct inpcb *inp)); #endif - -#endif /* KERNEL */ +#endif /* _KERNEL */ +#endif /* __APPLE_API_PRIVATE */ #endif /* !_NETINET_IN_PCB_H_ */ diff --git a/bsd/netinet/in_proto.c b/bsd/netinet/in_proto.c index 4ac5b78fc..ad4409a07 100644 --- a/bsd/netinet/in_proto.c +++ b/bsd/netinet/in_proto.c @@ -54,21 +54,14 @@ * @(#)in_proto.c 8.2 (Berkeley) 2/9/95 */ -#if ISFB31 -#include "opt_ipdivert.h" -#include "opt_ipx.h" -#endif - #include #include #include #include #include - - +#include #include - #include #include @@ -76,8 +69,6 @@ #include #include #include -#include -#include #include #include #include @@ -86,6 +77,9 @@ #include #include #include +#include + + /* * TCP/IP protocol family: IP, ICMP, UDP, TCP. */ @@ -99,35 +93,14 @@ #include #endif /* IPSEC */ -#include "gif.h" -#if NGIF > 0 -#include -#endif - #if IPXIP #include #endif -#if NSIP -#include -#include -#endif - -#if PM -void pm_init __P((void)); -void pm_input __P((struct mbuf *, int)); -int pm_ctloutput __P((int, struct socket *, int, int, struct mbuf **)); -struct pr_usrreqs pm_usrreqs; -#endif - -#if NATPT -void natpt_init __P((void)); -int natpt_ctloutput __P((int, struct socket *, int, int, struct mbuf **)); -struct pr_usrreqs natpt_usrreqs; -#endif - extern struct domain inetdomain; static struct pr_usrreqs nousrreqs; +extern struct pr_usrreqs icmp_dgram_usrreqs; +extern int icmp_dgram_ctloutput(struct socket *, struct sockopt *); struct protosw inetsw[] = { { 0, &inetdomain, 0, 0, @@ -155,19 +128,25 @@ struct protosw inetsw[] = { 0, 0, 0, 0, 0, &rip_usrreqs }, -{ SOCK_RAW, &inetdomain, IPPROTO_ICMP, PR_ATOMIC|PR_ADDR, +{ SOCK_RAW, &inetdomain, IPPROTO_ICMP, PR_ATOMIC|PR_ADDR|PR_LASTHDR, icmp_input, 0, 0, rip_ctloutput, 0, 0, 0, 0, 0, 0, &rip_usrreqs }, -{ SOCK_RAW, &inetdomain, IPPROTO_IGMP, PR_ATOMIC|PR_ADDR, +{ SOCK_DGRAM, &inetdomain, IPPROTO_ICMP, PR_ATOMIC|PR_ADDR|PR_LASTHDR, + icmp_input, 0, 0, icmp_dgram_ctloutput, + 0, + 0, 0, 0, 0, + 0, &icmp_dgram_usrreqs +}, +{ SOCK_RAW, &inetdomain, IPPROTO_IGMP, PR_ATOMIC|PR_ADDR|PR_LASTHDR, igmp_input, 0, 0, rip_ctloutput, 0, igmp_init, igmp_fasttimo, igmp_slowtimo, 0, 0, &rip_usrreqs }, -{ SOCK_RAW, &inetdomain, IPPROTO_RSVP, PR_ATOMIC|PR_ADDR, +{ SOCK_RAW, &inetdomain, IPPROTO_RSVP, PR_ATOMIC|PR_ADDR|PR_LASTHDR, rsvp_input, 0, 0, rip_ctloutput, 0, 0, 0, 0, 0, @@ -195,29 +174,20 @@ struct protosw inetsw[] = { 0, &nousrreqs }, #endif /* IPSEC */ -#if NGIF > 0 -{ SOCK_RAW, &inetdomain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR, - in_gif_input, 0, 0, 0, - 0, - 0, 0, 0, 0, - 0, &nousrreqs +{ SOCK_RAW, &inetdomain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR|PR_LASTHDR, + encap4_input, 0, 0, rip_ctloutput, + 0, + encap_init, 0, 0, 0, + 0, &rip_usrreqs }, # if INET6 -{ SOCK_RAW, &inetdomain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR, - in_gif_input, 0, 0, 0, - 0, - 0, 0, 0, 0, - 0, &nousrreqs -}, -#endif -#else /*NGIF*/ -{ SOCK_RAW, &inetdomain, IPPROTO_IPIP, PR_ATOMIC|PR_ADDR, - ipip_input, 0, 0, rip_ctloutput, +{ SOCK_RAW, &inetdomain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR|PR_LASTHDR, + encap4_input, 0, 0, rip_ctloutput, 0, - 0, 0, 0, 0, + encap_init, 0, 0, 0, 0, &rip_usrreqs }, -#endif /*NGIF*/ +#endif #if IPDIVERT { SOCK_RAW, &inetdomain, IPPROTO_DIVERT, PR_ATOMIC|PR_ADDR, div_input, 0, 0, ip_ctloutput, @@ -226,23 +196,8 @@ struct protosw inetsw[] = { 0, &div_usrreqs, }, #endif -#if TPIP -{ SOCK_SEQPACKET,&inetdomain, IPPROTO_TP, PR_CONNREQUIRED|PR_WANTRCVD, - tpip_input, 0, tpip_ctlinput, tp_ctloutput, - 0, tp_usrreq, - tp_init, 0, tp_slowtimo, tp_drain, -}, -#endif -/* EON (ISO CLNL over IP) */ -#if EON -{ SOCK_RAW, &inetdomain, IPPROTO_EON, 0, - eoninput, 0, eonctlinput, 0, - 0, - eonprotoinit, 0, 0, 0, -}, -#endif #if IPXIP -{ SOCK_RAW, &inetdomain, IPPROTO_IDP, PR_ATOMIC|PR_ADDR, +{ SOCK_RAW, &inetdomain, IPPROTO_IDP, PR_ATOMIC|PR_ADDR|PR_LASTHDR, ipxip_input, 0, ipxip_ctlinput, 0, 0, 0, 0, 0, 0, @@ -250,7 +205,7 @@ struct protosw inetsw[] = { }, #endif #if NSIP -{ SOCK_RAW, &inetdomain, IPPROTO_IDP, PR_ATOMIC|PR_ADDR, +{ SOCK_RAW, &inetdomain, IPPROTO_IDP, PR_ATOMIC|PR_ADDR|PR_LASTHDR, idpip_input, 0, nsip_ctlinput, 0, 0, 0, 0, 0, 0, @@ -266,16 +221,6 @@ struct protosw inetsw[] = { }, }; -#if NGIF > 0 -struct protosw in_gif_protosw = -{ SOCK_RAW, &inetdomain, 0/*IPPROTO_IPV[46]*/, PR_ATOMIC|PR_ADDR, - in_gif_input, rip_output, 0, rip_ctloutput, - 0, - 0, 0, 0, 0, - 0, &rip_usrreqs -}; -#endif /*NGIF*/ - extern int in_inithead __P((void **, int)); int in_proto_count = (sizeof (inetsw) / sizeof (struct protosw)); @@ -291,7 +236,6 @@ struct domain inetdomain = DOMAIN_SET(inet); - SYSCTL_NODE(_net, PF_INET, inet, CTLFLAG_RW, 0, "Internet Family"); diff --git a/bsd/netinet/in_rmx.c b/bsd/netinet/in_rmx.c index f1a41c2f6..c307be910 100644 --- a/bsd/netinet/in_rmx.c +++ b/bsd/netinet/in_rmx.c @@ -47,6 +47,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * $FreeBSD: src/sys/netinet/in_rmx.c,v 1.37.2.1 2001/05/14 08:23:49 ru Exp $ */ /* @@ -77,6 +78,10 @@ extern int in_inithead __P((void **head, int off)); +#ifdef __APPLE__ +static void in_rtqtimo(void *rock); +#endif + #define RTPRF_OURS RTF_PROTO3 /* set on routes we manage */ /* @@ -154,7 +159,7 @@ in_addroute(void *v_arg, void *n_arg, struct radix_node_head *head, ret = rn_addroute(v_arg, n_arg, head, treenodes); } - RTFREE(rt2); + rtfree(rt2); } } return ret; @@ -180,21 +185,41 @@ in_matroute(void *v_arg, struct radix_node_head *head) return rn; } -int rtq_reallyold = 60*60; +static int rtq_reallyold = 60*60; /* one hour is ``really old'' */ -SYSCTL_INT(_net_inet_ip, IPCTL_RTEXPIRE, rtexpire, - CTLFLAG_RW, &rtq_reallyold , 0, ""); +SYSCTL_INT(_net_inet_ip, IPCTL_RTEXPIRE, rtexpire, CTLFLAG_RW, + &rtq_reallyold , 0, + "Default expiration time on dynamically learned routes"); -int rtq_minreallyold = 10; +static int rtq_minreallyold = 10; /* never automatically crank down to less */ -SYSCTL_INT(_net_inet_ip, IPCTL_RTMINEXPIRE, rtminexpire, - CTLFLAG_RW, &rtq_minreallyold , 0, ""); +SYSCTL_INT(_net_inet_ip, IPCTL_RTMINEXPIRE, rtminexpire, CTLFLAG_RW, + &rtq_minreallyold , 0, + "Minimum time to attempt to hold onto dynamically learned routes"); -int rtq_toomany = 128; +static int rtq_toomany = 128; /* 128 cached routes is ``too many'' */ -SYSCTL_INT(_net_inet_ip, IPCTL_RTMAXCACHE, rtmaxcache, - CTLFLAG_RW, &rtq_toomany , 0, ""); - +SYSCTL_INT(_net_inet_ip, IPCTL_RTMAXCACHE, rtmaxcache, CTLFLAG_RW, + &rtq_toomany , 0, "Upper limit on dynamically learned routes"); + +#ifdef __APPLE__ +/* XXX LD11JUL02 Special case for AOL 5.1.2 connectivity issue to AirPort BS (Radar 2969954) + * AOL is adding a circular route ("10.0.1.1/32 10.0.1.1") when establishing its ppp tunnel + * to the AP BaseStation by removing the default gateway and replacing it with their tunnel entry point. + * There is no apparent reason to add this route as there is a valid 10.0.1.1/24 route to the BS. + * That circular route was ignored on previous version of MacOS X because of a routing bug + * corrected with the merge to FreeBSD4.4 (a route generated from an RTF_CLONING route had the RTF_WASCLONED + * flag set but did not have a reference to the parent route) and that entry was left in the RT. This workaround is + * made in order to provide binary compatibility with AOL. + * If we catch a process adding a circular route with a /32 from the routing socket, we error it out instead of + * confusing the routing table with a wrong route to the previous default gateway + * If for some reason a circular route is needed, turn this sysctl (net.inet.ip.check_route_selfref) to zero. + */ +int check_routeselfref = 1; +SYSCTL_INT(_net_inet_ip, OID_AUTO, check_route_selfref, CTLFLAG_RW, + &check_routeselfref , 0, ""); +#endif + /* * On last reference drop, mark the route as belong to us so that it can be @@ -304,7 +329,7 @@ in_rtqtimo(void *rock) struct timeval atv; static time_t last_adjusted_timeout = 0; int s; - + arg.found = arg.killed = 0; arg.rnh = rnh; arg.nextstop = time_second + rtq_timeout; @@ -344,7 +369,6 @@ in_rtqtimo(void *rock) atv.tv_usec = 0; atv.tv_sec = arg.nextstop - time_second; timeout(in_rtqtimo_funnel, rock, tvtohz(&atv)); - } void @@ -370,9 +394,11 @@ int in_inithead(void **head, int off) { struct radix_node_head *rnh; - + +#ifdef __APPLE__ if (*head) - return 1; + return 1; +#endif if(!rn_inithead(head, off)) return 0; @@ -390,18 +416,18 @@ in_inithead(void **head, int off) /* - * This zaps old routes when the interface goes down. - * Currently it doesn't delete static routes; there are - * arguments one could make for both behaviors. For the moment, - * we will adopt the Principle of Least Surprise and leave them - * alone (with the knowledge that this will not be enough for some - * people). The ones we really want to get rid of are things like ARP - * entries, since the user might down the interface, walk over to a completely - * different network, and plug back in. + * This zaps old routes when the interface goes down or interface + * address is deleted. In the latter case, it deletes static routes + * that point to this address. If we don't do this, we may end up + * using the old address in the future. The ones we always want to + * get rid of are things like ARP entries, since the user might down + * the interface, walk over to a completely different network, and + * plug back in. */ struct in_ifadown_arg { struct radix_node_head *rnh; struct ifaddr *ifa; + int del; }; static int @@ -411,7 +437,8 @@ in_ifadownkill(struct radix_node *rn, void *xap) struct rtentry *rt = (struct rtentry *)rn; int err; - if (rt->rt_ifa == ap->ifa && !(rt->rt_flags & RTF_STATIC)) { + if (rt->rt_ifa == ap->ifa && + (ap->del || !(rt->rt_flags & RTF_STATIC))) { /* * We need to disable the automatic prune that happens * in this case in rtrequest() because it will blow @@ -420,7 +447,7 @@ in_ifadownkill(struct radix_node *rn, void *xap) * the routes that rtrequest() would have in any case, * so that behavior is not needed there. */ - rt->rt_flags &= ~RTF_PRCLONING; + rt->rt_flags &= ~(RTF_CLONING | RTF_PRCLONING); err = rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt), rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0); if (err) { @@ -431,7 +458,7 @@ in_ifadownkill(struct radix_node *rn, void *xap) } int -in_ifadown(struct ifaddr *ifa) +in_ifadown(struct ifaddr *ifa, int delete) { struct in_ifadown_arg arg; struct radix_node_head *rnh; @@ -441,6 +468,7 @@ in_ifadown(struct ifaddr *ifa) arg.rnh = rnh = rt_tables[AF_INET]; arg.ifa = ifa; + arg.del = delete; rnh->rnh_walktree(rnh, in_ifadownkill, &arg); ifa->ifa_flags &= ~IFA_ROUTE; return 0; diff --git a/bsd/netinet/in_systm.h b/bsd/netinet/in_systm.h index ad9fea338..347a460e3 100644 --- a/bsd/netinet/in_systm.h +++ b/bsd/netinet/in_systm.h @@ -52,10 +52,12 @@ * SUCH DAMAGE. * * @(#)in_systm.h 8.1 (Berkeley) 6/10/93 + * $FreeBSD: src/sys/netinet/in_systm.h,v 1.9 1999/12/29 04:41:00 peter Exp $ */ #ifndef _NETINET_IN_SYSTM_H_ #define _NETINET_IN_SYSTM_H_ +#include /* * Miscellaneous internetwork @@ -76,7 +78,9 @@ typedef u_int32_t n_long; /* long as received from the net */ typedef u_int32_t n_time; /* ms since 00:00 GMT, byte rev */ #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE n_time iptime __P((void)); +#endif /* __APPLE_API_PRIVATE */ #endif #endif diff --git a/bsd/netinet/in_var.h b/bsd/netinet/in_var.h index ad84f6e40..0c9d8c829 100644 --- a/bsd/netinet/in_var.h +++ b/bsd/netinet/in_var.h @@ -52,13 +52,19 @@ * SUCH DAMAGE. * * @(#)in_var.h 8.2 (Berkeley) 1/9/95 + * $FreeBSD: src/sys/netinet/in_var.h,v 1.33.2.2 2001/07/17 10:50:01 ru Exp $ */ #ifndef _NETINET_IN_VAR_H_ #define _NETINET_IN_VAR_H_ +#include #include +#ifdef __APPLE__ #include +#endif + +#ifdef __APPLE_API_UNSTABLE /* * Interface address, Internet version. One of these structures @@ -89,14 +95,15 @@ struct in_aliasreq { struct sockaddr_in ifra_broadaddr; #define ifra_dstaddr ifra_broadaddr struct sockaddr_in ifra_mask; +#ifdef __APPLE__ u_long dlt; +#endif }; - +#ifdef __APPLE__ /* * Event data, internet style. */ - struct kev_in_data { struct net_event_data link_data; struct in_addr ia_addr; @@ -109,7 +116,6 @@ struct kev_in_data { }; - /* * Define inet event subclass and specific inet events. */ @@ -122,6 +128,7 @@ struct kev_in_data { #define KEV_INET_SIFDSTADDR 4 #define KEV_INET_SIFBRDADDR 5 #define KEV_INET_SIFNETMASK 6 +#endif /* __APPLE__ */ /* * Given a pointer to an in_ifaddr (ifaddr), @@ -133,8 +140,10 @@ struct kev_in_data { #define IN_LNAOF(in, ifa) \ ((ntohl((in).s_addr) & ~((struct in_ifaddr *)(ifa)->ia_subnetmask)) +#endif /* __APPLE_API_UNSTABLE */ #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE extern TAILQ_HEAD(in_ifaddrhead, in_ifaddr) in_ifaddrhead; extern struct ifqueue ipintrq; /* ip packet input queue */ extern struct in_addr zeroin_addr; @@ -148,20 +157,11 @@ extern u_char inetctlerrmap[]; /* struct in_addr addr; */ \ /* struct ifnet *ifp; */ \ { \ - register struct in_ifaddr *ia; \ + struct in_ifaddr *ia; \ \ - for (ia = in_ifaddrhead.tqh_first; \ - ia != NULL && ((ia->ia_ifp->if_flags & IFF_POINTOPOINT)? \ - IA_DSTSIN(ia):IA_SIN(ia))->sin_addr.s_addr != (addr).s_addr; \ - ia = ia->ia_link.tqe_next) \ - continue; \ - if (ia == NULL) \ - for (ia = in_ifaddrhead.tqh_first; \ - ia != NULL; \ - ia = ia->ia_link.tqe_next) \ - if (ia->ia_ifp->if_flags & IFF_POINTOPOINT && \ - IA_SIN(ia)->sin_addr.s_addr == (addr).s_addr) \ - break; \ + TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) \ + if (IA_SIN(ia)->sin_addr.s_addr == (addr).s_addr) \ + break; \ (ifp) = (ia == NULL) ? NULL : ia->ia_ifp; \ } @@ -173,13 +173,15 @@ extern u_char inetctlerrmap[]; /* struct ifnet *ifp; */ \ /* struct in_ifaddr *ia; */ \ { \ - for ((ia) = in_ifaddrhead.tqh_first; \ + for ((ia) = TAILQ_FIRST(&in_ifaddrhead); \ (ia) != NULL && (ia)->ia_ifp != (ifp); \ - (ia) = (ia)->ia_link.tqe_next) \ + (ia) = TAILQ_NEXT((ia), ia_link)) \ continue; \ } +#endif /* __APPLE_API_PRIVATE */ #endif +#ifdef __APPLE_API_UNSTABLE /* * This information should be part of the ifnet structure but we don't wish * to change that - as it might break a number of things @@ -209,8 +211,10 @@ struct in_multi { u_int inm_state; /* state of the membership */ struct router_info *inm_rti; /* router info*/ }; +#endif /* __APPLE_API_UNSTABLE */ #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE #ifdef SYSCTL_DECL SYSCTL_DECL(_net_inet_ip); @@ -236,10 +240,9 @@ struct in_multistep { /* struct ifnet *ifp; */ \ /* struct in_multi *inm; */ \ do { \ - register struct ifmultiaddr *ifma; \ + struct ifmultiaddr *ifma; \ \ - for (ifma = (ifp)->if_multiaddrs.lh_first; ifma; \ - ifma = ifma->ifma_link.le_next) { \ + LIST_FOREACH(ifma, &((ifp)->if_multiaddrs), ifma_link) { \ if (ifma->ifma_addr->sa_family == AF_INET \ && ((struct sockaddr_in *)ifma->ifma_addr)->sin_addr.s_addr == \ (addr).s_addr) \ @@ -260,14 +263,14 @@ do { \ /* struct in_multi *inm; */ \ do { \ if (((inm) = (step).i_inm) != NULL) \ - (step).i_inm = (step).i_inm->inm_link.le_next; \ + (step).i_inm = LIST_NEXT((step).i_inm, inm_link); \ } while(0) #define IN_FIRST_MULTI(step, inm) \ /* struct in_multistep step; */ \ /* struct in_multi *inm; */ \ do { \ - (step).i_inm = in_multihead.lh_first; \ + (step).i_inm = LIST_FIRST(&in_multihead); \ IN_NEXT_MULTI((step), (inm)); \ } while(0) @@ -278,16 +281,16 @@ int in_control __P((struct socket *, u_long, caddr_t, struct ifnet *, struct proc *)); void in_rtqdrain __P((void)); void ip_input __P((struct mbuf *)); -int in_ifadown __P((struct ifaddr *ifa)); +int in_ifadown __P((struct ifaddr *ifa, int)); void in_ifscrub __P((struct ifnet *, struct in_ifaddr *)); int ipflow_fastforward __P((struct mbuf *)); void ipflow_create __P((const struct route *, struct mbuf *)); void ipflow_slowtimo __P((void)); -#endif /* KERNEL */ -#if INET6 +#endif /* __APPLE_API_PRIVATE */ +#endif /* _KERNEL */ + /* INET6 stuff */ #include -#endif #endif /* _NETINET_IN_VAR_H_ */ diff --git a/bsd/netinet/ip.h b/bsd/netinet/ip.h index bf81e1aa5..8f19e94a6 100644 --- a/bsd/netinet/ip.h +++ b/bsd/netinet/ip.h @@ -52,10 +52,12 @@ * SUCH DAMAGE. * * @(#)ip.h 8.2 (Berkeley) 6/1/94 + * $FreeBSD: src/sys/netinet/ip.h,v 1.17 1999/12/22 19:13:20 shin Exp $ */ #ifndef _NETINET_IP_H_ #define _NETINET_IP_H_ +#include /* * Definitions for internet protocol version 4. @@ -109,11 +111,10 @@ struct ip { #define IPTOS_THROUGHPUT 0x08 #define IPTOS_RELIABILITY 0x04 #define IPTOS_MINCOST 0x02 -#if 1 /* ALTQ_ECN */ /* ECN bits proposed by Sally Floyd */ -#define IPTOS_CE 0x01 /* congestion experienced */ -#define IPTOS_ECT 0x02 /* ECN-capable transport */ -#endif +#define IPTOS_CE 0x01 /* congestion experienced */ +#define IPTOS_ECT 0x02 /* ECN-capable transport */ + /* * Definitions for IP precedence (also in ip_tos) (hopefully unused) diff --git a/bsd/netinet/ip6.h b/bsd/netinet/ip6.h index 88508d6f9..6a3b65785 100644 --- a/bsd/netinet/ip6.h +++ b/bsd/netinet/ip6.h @@ -19,7 +19,7 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* $KAME: ip6.h,v 1.6 2000/02/26 12:53:07 jinmei Exp $ */ +/* $KAME: ip6.h,v 1.18 2001/03/29 05:34:30 itojun Exp $*/ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -87,6 +87,7 @@ #ifndef _NETINET_IP6_H_ #define _NETINET_IP6_H_ +#include /* * Definition for internet protocol version 6. @@ -105,7 +106,7 @@ struct ip6_hdr { } ip6_ctlun; struct in6_addr ip6_src; /* source address */ struct in6_addr ip6_dst; /* destination address */ -}; +} __attribute__((__packed__)); #define ip6_vfc ip6_ctlun.ip6_un2_vfc #define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow @@ -137,9 +138,9 @@ struct ip6_hdr { */ struct ip6_ext { - u_char ip6e_nxt; - u_char ip6e_len; -}; + u_int8_t ip6e_nxt; + u_int8_t ip6e_len; +} __attribute__((__packed__)); /* Hop-by-Hop options header */ /* XXX should we pad it to force alignment on an 8-byte boundary? */ @@ -147,7 +148,7 @@ struct ip6_hbh { u_int8_t ip6h_nxt; /* next header */ u_int8_t ip6h_len; /* length in units of 8 octets */ /* followed by options */ -}; +} __attribute__((__packed__)); /* Destination options header */ /* XXX should we pad it to force alignment on an 8-byte boundary? */ @@ -155,7 +156,7 @@ struct ip6_dest { u_int8_t ip6d_nxt; /* next header */ u_int8_t ip6d_len; /* length in units of 8 octets */ /* followed by options */ -}; +} __attribute__((__packed__)); /* Option types and related macros */ #define IP6OPT_PAD1 0x00 /* 00 0 00000 */ @@ -164,7 +165,6 @@ struct ip6_dest { #define IP6OPT_NSAP_ADDR 0xC3 /* 11 0 00011 */ #define IP6OPT_TUNNEL_LIMIT 0x04 /* 00 0 00100 */ #define IP6OPT_RTALERT 0x05 /* 00 0 00101 (KAME definition) */ -#define IP6OPT_ROUTER_ALERT 0x05 /* (2292bis def, recommended) */ #define IP6OPT_RTALERT_LEN 4 #define IP6OPT_RTALERT_MLD 0 /* Datagram contains an MLD message */ @@ -172,11 +172,11 @@ struct ip6_dest { #define IP6OPT_RTALERT_ACTNET 2 /* contains an Active Networks msg */ #define IP6OPT_MINLEN 2 -#define IP6OPT_BINDING_UPDATE 0xc6 /* 11 0 00110 */ -#define IP6OPT_BINDING_ACK 0x07 /* 00 0 00111 */ -#define IP6OPT_BINDING_REQ 0x08 /* 00 0 01000 */ -#define IP6OPT_HOME_ADDRESS 0xc9 /* 11 0 01001 */ -#define IP6OPT_EID 0x8a /* 10 0 01010 */ +#define IP6OPT_BINDING_UPDATE 0xc6 /* 11 0 00110 */ +#define IP6OPT_BINDING_ACK 0x07 /* 00 0 00111 */ +#define IP6OPT_BINDING_REQ 0x08 /* 00 0 01000 */ +#define IP6OPT_HOME_ADDRESS 0xc9 /* 11 0 01001 */ +#define IP6OPT_EID 0x8a /* 10 0 01010 */ #define IP6OPT_TYPE(o) ((o) & 0xC0) #define IP6OPT_TYPE_SKIP 0x00 @@ -186,99 +186,7 @@ struct ip6_dest { #define IP6OPT_MUTABLE 0x20 -/* IPv6 options: common part */ -struct ip6_opt { - u_int8_t ip6o_type; - u_int8_t ip6o_len; -}; - -/* Jumbo Payload Option */ -struct ip6_opt_jumbo { - u_int8_t ip6oj_type; - u_int8_t ip6oj_len; - u_int8_t ip6oj_jumbo_len[4]; -}; -#define IP6OPT_JUMBO_LEN 6 - -/* NSAP Address Option */ -struct ip6_opt_nsap { - u_int8_t ip6on_type; - u_int8_t ip6on_len; - u_int8_t ip6on_src_nsap_len; - u_int8_t ip6on_dst_nsap_len; - /* followed by source NSAP */ - /* followed by destination NSAP */ -}; - -/* Tunnel Limit Option */ -struct ip6_opt_tunnel { - u_int8_t ip6ot_type; - u_int8_t ip6ot_len; - u_int8_t ip6ot_encap_limit; -}; - -/* Router Alert Option */ -struct ip6_opt_router { - u_int8_t ip6or_type; - u_int8_t ip6or_len; - u_int8_t ip6or_value[2]; -}; -/* Router alert values (in network byte order) */ -#if BYTE_ORDER == BIG_ENDIAN -#define IP6_ALERT_MLD 0x0000 -#define IP6_ALERT_RSVP 0x0001 -#define IP6_ALERT_AN 0x0002 -#else -#if BYTE_ORDER == LITTLE_ENDIAN -#define IP6_ALERT_MLD 0x0000 -#define IP6_ALERT_RSVP 0x0100 -#define IP6_ALERT_AN 0x0200 -#endif /* LITTLE_ENDIAN */ -#endif - -/* Binding Update Option */ -struct ip6_opt_binding_update { - u_int8_t ip6ou_type; - u_int8_t ip6ou_len; - u_int8_t ip6ou_flags; - u_int8_t ip6ou_prefixlen; - u_int8_t ip6ou_seqno[2]; - u_int8_t ip6ou_lifetime[4]; - u_int8_t ip6ou_coa[16];/* Optional based on flags */ - /* followed by sub-options */ -}; - -/* Binding Update Flags */ -#define IP6_BUF_ACK 0x80 /* Request a binding ack */ -#define IP6_BUF_HOME 0x40 /* Home Registration */ -#define IP6_BUF_COA 0x20 /* Care-of-address present in option */ -#define IP6_BUF_ROUTER 0x10 /* Sending mobile node is a router */ - -/* Binding Ack Option */ -struct ip6_opt_binding_ack { - u_int8_t ip6oa_type; - u_int8_t ip6oa_len; - u_int8_t ip6oa_status; - u_int8_t ip6oa_seqno[2]; - u_int8_t ip6oa_lifetime[4]; - u_int8_t ip6oa_refresh[4]; - /* followed by sub-options */ -}; - -/* Binding Request Option */ -struct ip6_opt_binding_request { - u_int8_t ip6or_type; - u_int8_t ip6or_len; - /* followed by sub-options */ -}; - -/* Home Address Option */ -struct ip6_opt_home_address { - u_int8_t ip6oh_type; - u_int8_t ip6oh_len; - u_int8_t ip6oh_addr[16];/* Home Address */ - /* followed by sub-options */ -}; +#define IP6OPT_JUMBO_LEN 6 /* Routing header */ struct ip6_rthdr { @@ -287,7 +195,7 @@ struct ip6_rthdr { u_int8_t ip6r_type; /* routing type */ u_int8_t ip6r_segleft; /* segments left */ /* followed by routing type specific data */ -}; +} __attribute__((__packed__)); /* Type 0 Routing header */ struct ip6_rthdr0 { @@ -295,13 +203,10 @@ struct ip6_rthdr0 { u_int8_t ip6r0_len; /* length in units of 8 octets */ u_int8_t ip6r0_type; /* always zero */ u_int8_t ip6r0_segleft; /* segments left */ - u_int32_t ip6r0_reserved; /* reserved field */ - /* followed by up to 127 struct in6_addr */ - -#ifdef COMPAT_RFC2292 - struct in6_addr ip6r0_addr[1]; /* up to 127 addresses */ -#endif -}; + u_int8_t ip6r0_reserved; /* reserved field */ + u_int8_t ip6r0_slmap[3]; /* strict/loose bit map */ + struct in6_addr ip6r0_addr[1]; /* up to 23 addresses */ +} __attribute__((__packed__)); /* Fragment header */ struct ip6_frag { @@ -309,7 +214,7 @@ struct ip6_frag { u_int8_t ip6f_reserved; /* reserved field */ u_int16_t ip6f_offlg; /* offset, reserved, and flag */ u_int32_t ip6f_ident; /* identification */ -}; +} __attribute__((__packed__)); #if BYTE_ORDER == BIG_ENDIAN #define IP6F_OFF_MASK 0xfff8 /* mask out offset from _offlg */ @@ -333,6 +238,7 @@ struct ip6_frag { #define IPV6_MAXPACKET 65535 /* ip6 max packet size without Jumbo payload*/ #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE /* * IP6_EXTHDR_CHECK ensures that region between the IP6 header and the * target header (including IPv6 itself, extension headers and @@ -363,8 +269,7 @@ do { \ return ret; \ } \ } \ - } \ - else { \ + } else { \ if ((m)->m_len < (off) + (hlen)) { \ ip6stat.ip6s_tooshort++; \ in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); \ @@ -388,7 +293,6 @@ do { \ do { \ struct mbuf *t; \ int tmp; \ - ip6stat.ip6s_exthdrget++; \ if ((m)->m_len >= (off) + (len)) \ (val) = (typ)(mtod((m), caddr_t) + (off)); \ else { \ @@ -407,7 +311,6 @@ do { \ #define IP6_EXTHDR_GET0(val, typ, m, off, len) \ do { \ struct mbuf *t; \ - ip6stat.ip6s_exthdrget0++; \ if ((off) == 0) \ (val) = (typ)mtod(m, caddr_t); \ else { \ @@ -422,6 +325,7 @@ do { \ } \ } \ } while (0) +#endif /* __APPLE_API_PRIVATE */ #endif /*KERNEL*/ #endif /* not _NETINET_IP6_H_ */ diff --git a/bsd/netinet/ip_compat.h b/bsd/netinet/ip_compat.h index b6549bfc7..a39802e7f 100644 --- a/bsd/netinet/ip_compat.h +++ b/bsd/netinet/ip_compat.h @@ -28,6 +28,7 @@ * * @(#)ip_compat.h 1.8 1/14/96 */ +#include #if 0 @@ -202,7 +203,7 @@ typedef unsigned long u_32_t; * Build some macros and #defines to enable the same code to compile anywhere * Well, that's the idea, anyway :-) */ -#if KERNEL +#ifdef KERNEL # if SOLARIS # define MUTEX_ENTER(x) mutex_enter(x) # define MUTEX_EXIT(x) mutex_exit(x) diff --git a/bsd/netinet/ip_divert.c b/bsd/netinet/ip_divert.c index acfd471bf..546df390c 100644 --- a/bsd/netinet/ip_divert.c +++ b/bsd/netinet/ip_divert.c @@ -51,30 +51,25 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * $FreeBSD: src/sys/netinet/ip_divert.c,v 1.42.2.4 2001/07/29 19:32:40 ume Exp $ */ -#if ISFB31 -#include "opt_inet.h" -#include "opt_ipfw.h" -#include "opt_ipdivert.h" -#endif #ifndef INET #error "IPDIVERT requires INET." #endif #include +#include #include #include #include #include #include +#include #include #include -#if ISFB31 -#include -#endif #include #include @@ -96,31 +91,23 @@ #define DIVSNDQ (65536 + 100) #define DIVRCVQ (65536 + 100) -/* Global variables */ - /* - * ip_input() and ip_output() set this secret value before calling us to - * let us know which divert port to divert a packet to; this is done so - * we can use the existing prototype for struct protosw's pr_input(). - * This is stored in host order. - */ -u_short ip_divert_port; - -/* - * A 16 bit cookie is passed to the user process. - * The user process can send it back to help the caller know something - * about where the packet came from. + * A 16 bit cookie is passed to and from the user process. + * The user process can send it back to help the caller know + * something about where the packet originally came from. * - * If IPFW is the caller then the cookie is the rule that sent + * In the case of ipfw, then the cookie is the rule that sent * us here. On reinjection is is the rule after which processing * should continue. Leaving it the same will make processing start * at the rule number after that which sent it here. Setting it to * 0 will restart processing at the beginning. + * + * For divert_packet(), ip_divert_cookie is an input value only. + * For div_output(), ip_divert_cookie is an output value only. */ u_int16_t ip_divert_cookie; /* Internal variables */ - static struct inpcbhead divcb; static struct inpcbinfo divcbinfo; @@ -131,7 +118,6 @@ static u_long div_recvspace = DIVRCVQ; /* XXX sysctl ? */ static struct sockaddr_in divsrc = { sizeof(divsrc), AF_INET }; /* Internal functions */ - static int div_output(struct socket *so, struct mbuf *m, struct sockaddr *addr, struct mbuf *control); @@ -162,23 +148,36 @@ div_init(void) } /* - * Setup generic address and protocol structures - * for div_input routine, then pass them along with - * mbuf chain. ip->ip_len is assumed to have had - * the header length (hlen) subtracted out already. - * We tell whether the packet was incoming or outgoing - * by seeing if hlen == 0, which is a hack. + * IPPROTO_DIVERT is not a real IP protocol; don't allow any packets + * with that protocol number to enter the system from the outside. */ void -div_input(struct mbuf *m, int hlen) +div_input(struct mbuf *m, int off) +{ + ipstat.ips_noproto++; + m_freem(m); +} + +/* + * Divert a packet by passing it up to the divert socket at port 'port'. + * + * Setup generic address and protocol structures for div_input routine, + * then pass them along with mbuf chain. + */ +void +divert_packet(struct mbuf *m, int incoming, int port) { struct ip *ip; struct inpcb *inp; struct socket *sa; + u_int16_t nport; /* Sanity check */ - if (ip_divert_port == 0) - panic("div_input: port is 0"); + KASSERT(port != 0, ("%s: port=0", __FUNCTION__)); + + /* Record and reset divert cookie */ + divsrc.sin_port = ip_divert_cookie; + ip_divert_cookie = 0; /* Assure header */ if (m->m_len < sizeof(struct ip) && @@ -187,35 +186,19 @@ div_input(struct mbuf *m, int hlen) } ip = mtod(m, struct ip *); - /* Record divert cookie */ - divsrc.sin_port = ip_divert_cookie; - ip_divert_cookie = 0; - - /* Restore packet header fields */ - ip->ip_len += hlen; - HTONS(ip->ip_len); - HTONS(ip->ip_off); - /* - * Record receive interface address, if any + * Record receive interface address, if any. * But only for incoming packets. */ divsrc.sin_addr.s_addr = 0; - if (hlen) { + if (incoming) { struct ifaddr *ifa; -#if DIAGNOSTIC /* Sanity check */ - if (!(m->m_flags & M_PKTHDR)) - panic("div_input: no pkt hdr"); -#endif - - /* More fields affected by ip_input() */ - HTONS(ip->ip_id); + KASSERT((m->m_flags & M_PKTHDR), ("%s: !PKTHDR", __FUNCTION__)); /* Find IP address for receive interface */ - for (ifa = m->m_pkthdr.rcvif->if_addrhead.tqh_first; - ifa != NULL; ifa = ifa->ifa_link.tqe_next) { + TAILQ_FOREACH(ifa, &m->m_pkthdr.rcvif->if_addrhead, ifa_link) { if (ifa->ifa_addr == NULL) continue; if (ifa->ifa_addr->sa_family != AF_INET) @@ -255,11 +238,11 @@ div_input(struct mbuf *m, int hlen) /* Put packet on socket queue, if any */ sa = NULL; - for (inp = divcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) { - if (inp->inp_lport == htons(ip_divert_port)) + nport = htons((u_int16_t)port); + LIST_FOREACH(inp, &divcb, inp_list) { + if (inp->inp_lport == nport) sa = inp->inp_socket; } - ip_divert_port = 0; if (sa) { if (sbappendaddr(&sa->so_rcv, (struct sockaddr *)&divsrc, m, (struct mbuf *)0) == 0) @@ -338,7 +321,8 @@ div_output(so, m, addr, control) ipstat.ips_rawout++; /* XXX */ error = ip_output(m, inp->inp_options, &inp->inp_route, (so->so_options & SO_DONTROUTE) | - IP_ALLOWBROADCAST | IP_RAWOUTPUT, inp->inp_moptions); + IP_ALLOWBROADCAST | IP_RAWOUTPUT, + inp->inp_moptions); } else { struct ifaddr *ifa; @@ -369,8 +353,8 @@ div_output(so, m, addr, control) return error; cantsend: - ip_divert_cookie = 0; m_freem(m); + ip_divert_cookie = 0; return error; } @@ -386,27 +370,21 @@ div_attach(struct socket *so, int proto, struct proc *p) if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0) return error; + error = soreserve(so, div_sendspace, div_recvspace); + if (error) + return error; s = splnet(); error = in_pcballoc(so, &divcbinfo, p); splx(s); - if (error) - return error; - error = soreserve(so, div_sendspace, div_recvspace); if (error) return error; inp = (struct inpcb *)so->so_pcb; inp->inp_ip_p = proto; - inp->inp_flags |= INP_HDRINCL | INP_IPV4; + inp->inp_vflag |= INP_IPV4; + inp->inp_flags |= INP_HDRINCL; /* The socket is always "connected" because we always know "where" to send the packet */ so->so_state |= SS_ISCONNECTED; -#if IPSEC - error = ipsec_init_policy(so, &inp->inp_sp); - if (error != 0) { - in_pcbdetach(inp); - return error; - } -#endif /*IPSEC*/ return 0; } @@ -446,9 +424,21 @@ div_bind(struct socket *so, struct sockaddr *nam, struct proc *p) s = splnet(); inp = sotoinpcb(so); - error = in_pcbbind(inp, nam, p); + /* in_pcbbind assumes that the socket is a sockaddr_in + * and in_pcbbind requires a valid address. Since divert + * sockets don't we need to make sure the address is + * filled in properly. + * XXX -- divert should not be abusing in_pcbind + * and should probably have its own family. + */ + if (nam->sa_family != AF_INET) { + error = EAFNOSUPPORT; + } else { + ((struct sockaddr_in *)nam)->sin_addr.s_addr = INADDR_ANY; + error = in_pcbbind(inp, nam, p); + } splx(s); - return 0; + return error; } static int @@ -463,7 +453,7 @@ div_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, struct mbuf *control, struct proc *p) { /* Packet must have a header (but that's about it) */ - if (m->m_len < sizeof (struct ip) || + if (m->m_len < sizeof (struct ip) && (m = m_pullup(m, sizeof (struct ip))) == 0) { ipstat.ips_toosmall++; m_freem(m); @@ -474,6 +464,100 @@ div_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, return div_output(so, m, nam, control); } +static int +div_pcblist SYSCTL_HANDLER_ARGS +{ + int error, i, n, s; + struct inpcb *inp, **inp_list; + inp_gen_t gencnt; + struct xinpgen xig; + + /* + * The process of preparing the TCB list is too time-consuming and + * resource-intensive to repeat twice on every request. + */ + if (req->oldptr == 0) { + n = divcbinfo.ipi_count; + req->oldidx = 2 * (sizeof xig) + + (n + n/8) * sizeof(struct xinpcb); + return 0; + } + + if (req->newptr != 0) + return EPERM; + + /* + * OK, now we're committed to doing something. + */ + s = splnet(); + gencnt = divcbinfo.ipi_gencnt; + n = divcbinfo.ipi_count; + splx(s); + + xig.xig_len = sizeof xig; + xig.xig_count = n; + xig.xig_gen = gencnt; + xig.xig_sogen = so_gencnt; + error = SYSCTL_OUT(req, &xig, sizeof xig); + if (error) + return error; + + inp_list = _MALLOC(n * sizeof *inp_list, M_TEMP, M_WAITOK); + if (inp_list == 0) + return ENOMEM; + + s = splnet(); + for (inp = LIST_FIRST(divcbinfo.listhead), i = 0; inp && i < n; + inp = LIST_NEXT(inp, inp_list)) { +#ifdef __APPLE__ + if (inp->inp_gencnt <= gencnt) +#else + if (inp->inp_gencnt <= gencnt && !prison_xinpcb(req->p, inp)) +#endif + inp_list[i++] = inp; + } + splx(s); + n = i; + + error = 0; + for (i = 0; i < n; i++) { + inp = inp_list[i]; + if (inp->inp_gencnt <= gencnt) { + struct xinpcb xi; + xi.xi_len = sizeof xi; + /* XXX should avoid extra copy */ + bcopy(inp, &xi.xi_inp, sizeof *inp); + if (inp->inp_socket) + sotoxsocket(inp->inp_socket, &xi.xi_socket); + error = SYSCTL_OUT(req, &xi, sizeof xi); + } + } + if (!error) { + /* + * Give the user an updated idea of our state. + * If the generation differs from what we told + * her before, she knows that something happened + * while we were processing this request, and it + * might be necessary to retry. + */ + s = splnet(); + xig.xig_gen = divcbinfo.ipi_gencnt; + xig.xig_sogen = so_gencnt; + xig.xig_count = divcbinfo.ipi_count; + splx(s); + error = SYSCTL_OUT(req, &xig, sizeof xig); + } + FREE(inp_list, M_TEMP); + return error; +} + +#warning Fix SYSCTL net_inet_divert +#if 0 +SYSCTL_DECL(_net_inet_divert); +SYSCTL_PROC(_net_inet_divert, OID_AUTO, pcblist, CTLFLAG_RD, 0, 0, + div_pcblist, "S,xinpcb", "List of active divert sockets"); +#endif + struct pr_usrreqs div_usrreqs = { div_abort, pru_accept_notsupp, div_attach, div_bind, pru_connect_notsupp, pru_connect2_notsupp, in_control, div_detach, diff --git a/bsd/netinet/ip_dummynet.c b/bsd/netinet/ip_dummynet.c index 61cc6f414..0979e45d3 100644 --- a/bsd/netinet/ip_dummynet.c +++ b/bsd/netinet/ip_dummynet.c @@ -19,40 +19,63 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* - * Copyright (c) 1998 Luigi Rizzo - * - * Redistribution and use in source forms, with and without modification, - * are permitted provided that this entire comment appears intact. + * Copyright (c) 1998-2001 Luigi Rizzo, Universita` di Pisa + * Portions Copyright (c) 2000 Akamba Corp. + * All rights reserved * - * Redistribution in binary form may occur without any restrictions. - * Obviously, it would be nice if you gave credit where credit is due - * but requiring it would be too onerous. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. * - * This software is provided ``AS IS'' without any warranties of any kind. + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. * + * $FreeBSD: src/sys/netinet/ip_dummynet.c,v 1.24.2.11 2001/02/09 23:18:08 luigi Exp $ */ +#define DEB(x) +#define DDB(x) x + /* * This module implements IP dummynet, a bandwidth limiter/delay emulator * used in conjunction with the ipfw package. + * Description of the data structures used is in ip_dummynet.h + * Here you mainly find the following blocks of code: + * + variable declarations; + * + heap management functions; + * + scheduler and dummynet functions; + * + configuration and initialization. + * + * NOTA BENE: critical sections are protected by splimp()/splx() + * pairs. One would think that splnet() is enough as for most of + * the netinet code, but it is not so because when used with + * bridging, dummynet is invoked at splimp(). * - * Changes: + * Most important Changes: * - * 980821: changed conventions in the queueing logic - * packets passed from dummynet to ip_in/out are prepended with - * a vestigial mbuf type MT_DUMMYNET which contains a pointer - * to the matching rule. - * ip_input/output will extract the parameters, free the vestigial mbuf, - * and do the processing. - * - * 980519: fixed behaviour when deleting rules. - * 980518: added splimp()/splx() to protect against races + * 010124: Fixed WF2Q behaviour + * 010122: Fixed spl protection. + * 000601: WF2Q support + * 000106: large rewrite, use heaps to handle very many pipes. * 980513: initial release + * + * include files marked with XXX are probably not needed */ -/* include files marked with XXX are probably not needed */ - #include #include #include @@ -78,53 +101,87 @@ #include #endif +/* + * We keep a private variable for the simulation time, but we could + * probably use an existing one ("softticks" in sys/kern/kern_timer.c) + */ +static dn_key curr_time = 0 ; /* current simulation time */ + +static int dn_hash_size = 64 ; /* default hash size */ + +/* statistics on number of queue searches and search steps */ +static int searches, search_steps ; +static int pipe_expire = 1 ; /* expire queue if empty */ +static int dn_max_ratio = 16 ; /* max queues/buckets ratio */ + +static int red_lookup_depth = 256; /* RED - default lookup table depth */ +static int red_avg_pkt_size = 512; /* RED - default medium packet size */ +static int red_max_pkt_size = 1500; /* RED - default max packet size */ + +/* + * Three heaps contain queues and pipes that the scheduler handles: + * + * ready_heap contains all dn_flow_queue related to fixed-rate pipes. + * + * wfq_ready_heap contains the pipes associated with WF2Q flows + * + * extract_heap contains pipes associated with delay lines. + * + */ +static struct dn_heap ready_heap, extract_heap, wfq_ready_heap ; + +static int heap_init(struct dn_heap *h, int size) ; +static int heap_insert (struct dn_heap *h, dn_key key1, void *p); +static void heap_extract(struct dn_heap *h, void *obj); + +static void transmit_event(struct dn_pipe *pipe); +static void ready_event(struct dn_flow_queue *q); + static struct dn_pipe *all_pipes = NULL ; /* list of all pipes */ +static struct dn_flow_set *all_flow_sets = NULL ;/* list of all flow_sets */ -static int dn_debug = 0 ; /* verbose */ -static int dn_calls = 0 ; /* number of calls */ -static int dn_idle = 1; -#ifdef SYSCTL_NODE -SYSCTL_NODE(_net_inet_ip, OID_AUTO, dummynet, CTLFLAG_RW, 0, "Dummynet"); -SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, debug, CTLFLAG_RW, &dn_debug, 0, ""); -SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, calls, CTLFLAG_RD, &dn_calls, 0, ""); -SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, idle, CTLFLAG_RD, &dn_idle, 0, ""); +#if SYSCTL_NODE +SYSCTL_NODE(_net_inet_ip, OID_AUTO, dummynet, + CTLFLAG_RW, 0, "Dummynet"); +SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, hash_size, + CTLFLAG_RW, &dn_hash_size, 0, "Default hash table size"); +SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, curr_time, + CTLFLAG_RD, &curr_time, 0, "Current tick"); +SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, ready_heap, + CTLFLAG_RD, &ready_heap.size, 0, "Size of ready heap"); +SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, extract_heap, + CTLFLAG_RD, &extract_heap.size, 0, "Size of extract heap"); +SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, searches, + CTLFLAG_RD, &searches, 0, "Number of queue searches"); +SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, search_steps, + CTLFLAG_RD, &search_steps, 0, "Number of queue search steps"); +SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, expire, + CTLFLAG_RW, &pipe_expire, 0, "Expire queue if empty"); +SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, max_chain_len, + CTLFLAG_RW, &dn_max_ratio, 0, + "Max ratio between dynamic queues and buckets"); +SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, red_lookup_depth, + CTLFLAG_RD, &red_lookup_depth, 0, "Depth of RED lookup table"); +SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, red_avg_pkt_size, + CTLFLAG_RD, &red_avg_pkt_size, 0, "RED Medium packet size"); +SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, red_max_pkt_size, + CTLFLAG_RD, &red_max_pkt_size, 0, "RED Max packet size"); #endif +static int config_pipe(struct dn_pipe *p); static int ip_dn_ctl(struct sockopt *sopt); static void rt_unref(struct rtentry *); static void dummynet(void *); -static void dn_restart(void); -static void dn_move(struct dn_pipe *pipe, int immediate); static void dummynet_flush(void); +void dummynet_drain(void); +int if_tx_rdy(struct ifnet *ifp); /* - * the following is needed when deleting a pipe, because rules can + * ip_fw_chain is used when deleting a pipe, because ipfw rules can * hold references to the pipe. */ -extern LIST_HEAD (ip_fw_head, ip_fw_chain) ip_fw_chain; - -/* - * invoked to reschedule the periodic task if necessary. - * Should only be called when dn_idle = 1 ; - */ -static void -dn_restart() -{ - struct dn_pipe *pipe; - - if (!dn_idle) - return; - - for (pipe = all_pipes ; pipe ; pipe = pipe->next ) { - /* if there any pipe that needs work, restart */ - if (pipe->r.head || pipe->p.head || pipe->numbytes < 0 ) { - dn_idle = 0; - timeout(dummynet, NULL, 1); - return ; - } - } -} +extern LIST_HEAD (ip_fw_head, ip_fw_chain) ip_fw_chain_head; static void rt_unref(struct rtentry *rt) @@ -132,527 +189,1736 @@ rt_unref(struct rtentry *rt) if (rt == NULL) return ; if (rt->rt_refcnt <= 0) - printf("-- warning, refcnt now %d, decreasing\n", rt->rt_refcnt); - RTFREE(rt); + printf("-- warning, refcnt now %ld, decreasing\n", rt->rt_refcnt); + rtfree(rt); +} + +/* + * Heap management functions. + * + * In the heap, first node is element 0. Children of i are 2i+1 and 2i+2. + * Some macros help finding parent/children so we can optimize them. + * + * heap_init() is called to expand the heap when needed. + * Increment size in blocks of 16 entries. + * XXX failure to allocate a new element is a pretty bad failure + * as we basically stall a whole queue forever!! + * Returns 1 on error, 0 on success + */ +#define HEAP_FATHER(x) ( ( (x) - 1 ) / 2 ) +#define HEAP_LEFT(x) ( 2*(x) + 1 ) +#define HEAP_IS_LEFT(x) ( (x) & 1 ) +#define HEAP_RIGHT(x) ( 2*(x) + 2 ) +#define HEAP_SWAP(a, b, buffer) { buffer = a ; a = b ; b = buffer ; } +#define HEAP_INCREMENT 15 + +static int +heap_init(struct dn_heap *h, int new_size) +{ + struct dn_heap_entry *p; + + if (h->size >= new_size ) { + printf("heap_init, Bogus call, have %d want %d\n", + h->size, new_size); + return 0 ; + } + new_size = (new_size + HEAP_INCREMENT ) & ~HEAP_INCREMENT ; + p = _MALLOC(new_size * sizeof(*p), M_IPFW, M_DONTWAIT ); + if (p == NULL) { + printf(" heap_init, resize %d failed\n", new_size ); + return 1 ; /* error */ + } + if (h->size > 0) { + bcopy(h->p, p, h->size * sizeof(*p) ); + FREE(h->p, M_IPFW); + } + h->p = p ; + h->size = new_size ; + return 0 ; +} + +/* + * Insert element in heap. Normally, p != NULL, we insert p in + * a new position and bubble up. If p == NULL, then the element is + * already in place, and key is the position where to start the + * bubble-up. + * Returns 1 on failure (cannot allocate new heap entry) + * + * If offset > 0 the position (index, int) of the element in the heap is + * also stored in the element itself at the given offset in bytes. + */ +#define SET_OFFSET(heap, node) \ + if (heap->offset > 0) \ + *((int *)((char *)(heap->p[node].object) + heap->offset)) = node ; +/* + * RESET_OFFSET is used for sanity checks. It sets offset to an invalid value. + */ +#define RESET_OFFSET(heap, node) \ + if (heap->offset > 0) \ + *((int *)((char *)(heap->p[node].object) + heap->offset)) = -1 ; +static int +heap_insert(struct dn_heap *h, dn_key key1, void *p) +{ + int son = h->elements ; + + if (p == NULL) /* data already there, set starting point */ + son = key1 ; + else { /* insert new element at the end, possibly resize */ + son = h->elements ; + if (son == h->size) /* need resize... */ + if (heap_init(h, h->elements+1) ) + return 1 ; /* failure... */ + h->p[son].object = p ; + h->p[son].key = key1 ; + h->elements++ ; + } + while (son > 0) { /* bubble up */ + int father = HEAP_FATHER(son) ; + struct dn_heap_entry tmp ; + + if (DN_KEY_LT( h->p[father].key, h->p[son].key ) ) + break ; /* found right position */ + /* son smaller than father, swap and repeat */ + HEAP_SWAP(h->p[son], h->p[father], tmp) ; + SET_OFFSET(h, son); + son = father ; + } + SET_OFFSET(h, son); + return 0 ; } /* - * move packets from R-queue to P-queue + * remove top element from heap, or obj if obj != NULL */ static void -dn_move(struct dn_pipe *pipe, int immediate) -{ - struct dn_pkt *pkt; - - /* - * consistency check, should catch new pipes which are - * not initialized properly. - */ - if ( pipe->p.head == NULL && - pipe->ticks_from_last_insert != pipe->delay) { - printf("Warning, empty pipe and delay %d (should be %d)\n", - pipe->ticks_from_last_insert, pipe->delay); - pipe->ticks_from_last_insert = pipe->delay; - } - /* this ought to go in dn_dequeue() */ - if (!immediate && pipe->ticks_from_last_insert < pipe->delay) - pipe->ticks_from_last_insert++; - if ( pkt = pipe->r.head ) { +heap_extract(struct dn_heap *h, void *obj) +{ + int child, father, max = h->elements - 1 ; + + if (max < 0) { + printf("warning, extract from empty heap 0x%p\n", h); + return ; + } + father = 0 ; /* default: move up smallest child */ + if (obj != NULL) { /* extract specific element, index is at offset */ + if (h->offset <= 0) + panic("*** heap_extract from middle not supported on this heap!!!\n"); + father = *((int *)((char *)obj + h->offset)) ; + if (father < 0 || father >= h->elements) { + printf("dummynet: heap_extract, father %d out of bound 0..%d\n", + father, h->elements); + panic("heap_extract"); + } + } + RESET_OFFSET(h, father); + child = HEAP_LEFT(father) ; /* left child */ + while (child <= max) { /* valid entry */ + if (child != max && DN_KEY_LT(h->p[child+1].key, h->p[child].key) ) + child = child+1 ; /* take right child, otherwise left */ + h->p[father] = h->p[child] ; + SET_OFFSET(h, father); + father = child ; + child = HEAP_LEFT(child) ; /* left child for next loop */ + } + h->elements-- ; + if (father != max) { /* - * Move at most numbytes bytes from src and move to dst. - * delay is set to ticks_from_last_insert, which - * is reset after the first insertion; + * Fill hole with last entry and bubble up, reusing the insert code */ - while ( pkt ) { - struct ip *ip=mtod(pkt->dn_m, struct ip *); + h->p[father] = h->p[max] ; + heap_insert(h, father, NULL); /* this one cannot fail */ + } +} - /* - * queue limitation: pass packets down if the len is - * such that the pkt would go out before the next tick. - */ - if (pipe->bandwidth) { - if (pipe->numbytes < ip->ip_len) - break; - pipe->numbytes -= ip->ip_len; - } - pipe->r_len--; /* elements in queue */ - pipe->r_len_bytes -= ip->ip_len ; +#if 0 +/* + * change object position and update references + * XXX this one is never used! + */ +static void +heap_move(struct dn_heap *h, dn_key new_key, void *object) +{ + int temp; + int i ; + int max = h->elements-1 ; + struct dn_heap_entry buf ; - /* - * to add delay jitter, must act here. A lower value - * (bounded to 0) means lower delay. - */ - pkt->delay = pipe->ticks_from_last_insert; - pipe->ticks_from_last_insert = 0; - /* compensate the decrement done next in dn_dequeue */ - if (!immediate && pkt->delay >0 && pipe->p.head==NULL) - pkt->delay++; - if (pipe->p.head == NULL) - pipe->p.head = pkt; - else - (struct dn_pkt *)pipe->p.tail->dn_next = pkt; - pipe->p.tail = pkt; - pkt = (struct dn_pkt *)pkt->dn_next; - pipe->p.tail->dn_next = NULL; + if (h->offset <= 0) + panic("cannot move items on this heap"); + + i = *((int *)((char *)object + h->offset)); + if (DN_KEY_LT(new_key, h->p[i].key) ) { /* must move up */ + h->p[i].key = new_key ; + for (; i>0 && DN_KEY_LT(new_key, h->p[(temp = HEAP_FATHER(i))].key) ; + i = temp ) { /* bubble up */ + HEAP_SWAP(h->p[i], h->p[temp], buf) ; + SET_OFFSET(h, i); + } + } else { /* must move down */ + h->p[i].key = new_key ; + while ( (temp = HEAP_LEFT(i)) <= max ) { /* found left child */ + if ((temp != max) && DN_KEY_GT(h->p[temp].key, h->p[temp+1].key)) + temp++ ; /* select child with min key */ + if (DN_KEY_GT(new_key, h->p[temp].key)) { /* go down */ + HEAP_SWAP(h->p[i], h->p[temp], buf) ; + SET_OFFSET(h, i); + } else + break ; + i = temp ; } - pipe->r.head = pkt; - - /*** XXX just a sanity check */ - if ( ( pkt == NULL && pipe->r_len != 0) || - ( pkt != NULL && pipe->r_len == 0) ) - printf("-- Warning, pipe head %p len %d\n", - (void *)pkt, pipe->r_len); } - - /* - * deliver packets downstream after the delay in the P-queue. - */ + SET_OFFSET(h, i); +} +#endif /* heap_move, unused */ + +/* + * heapify() will reorganize data inside an array to maintain the + * heap property. It is needed when we delete a bunch of entries. + */ +static void +heapify(struct dn_heap *h) +{ + int i ; + + for (i = 0 ; i < h->elements ; i++ ) + heap_insert(h, i , NULL) ; +} + +/* + * cleanup the heap and free data structure + */ +static void +heap_free(struct dn_heap *h) +{ + if (h->size >0 ) + FREE(h->p, M_IPFW); + bzero(h, sizeof(*h) ); +} + +/* + * --- end of heap management functions --- + */ + +/* + * Scheduler functions: + * + * transmit_event() is called when the delay-line needs to enter + * the scheduler, either because of existing pkts getting ready, + * or new packets entering the queue. The event handled is the delivery + * time of the packet. + * + * ready_event() does something similar with fixed-rate queues, and the + * event handled is the finish time of the head pkt. + * + * wfq_ready_event() does something similar with WF2Q queues, and the + * event handled is the start time of the head pkt. + * + * In all cases, we make sure that the data structures are consistent + * before passing pkts out, because this might trigger recursive + * invocations of the procedures. + */ +static void +transmit_event(struct dn_pipe *pipe) +{ + struct dn_pkt *pkt ; - if (pipe->p.head == NULL) - return; - if (!immediate) - pipe->p.head->delay--; - while ( (pkt = pipe->p.head) && pkt->delay < 1) { + while ( (pkt = pipe->head) && DN_KEY_LEQ(pkt->output_time, curr_time) ) { /* - * first unlink, then call procedures since ip_input() - * can result in a call to ip_output cnd viceversa, - * thus causing nested calls + * first unlink, then call procedures, since ip_input() can invoke + * ip_output() and viceversa, thus causing nested calls */ - pipe->p.head = (struct dn_pkt *) pkt->dn_next ; + pipe->head = DN_NEXT(pkt) ; /* - * the trick to avoid flow-id settings here is to prepend a - * vestigial mbuf to the packet, with the following values: - * m_type = MT_DUMMYNET - * m_next = the actual mbuf to be processed by ip_input/output - * m_data = the matching rule - * The vestigial element is the same memory area used by - * the dn_pkt, and IS FREED IN ip_input/ip_output. IT IS - * NOT A REAL MBUF, just a block of memory acquired with malloc(). + * The actual mbuf is preceded by a struct dn_pkt, resembling an mbuf + * (NOT A REAL one, just a small block of malloc'ed memory) with + * m_type = MT_DUMMYNET + * m_next = actual mbuf to be processed by ip_input/output + * m_data = the matching rule + * and some other fields. + * The block IS FREED HERE because it contains parameters passed + * to the called routine. */ switch (pkt->dn_dir) { - case DN_TO_IP_OUT: { - struct rtentry *tmp_rt = pkt->ro.ro_rt ; - - (void)ip_output((struct mbuf *)pkt, (struct mbuf *)pkt->ifp, - &(pkt->ro), pkt->dn_hlen, NULL); - rt_unref (tmp_rt) ; - } + case DN_TO_IP_OUT: + (void)ip_output((struct mbuf *)pkt, NULL, NULL, 0, NULL); + rt_unref (pkt->ro.ro_rt) ; break ; + case DN_TO_IP_IN : ip_input((struct mbuf *)pkt) ; break ; + #if BRIDGE - case DN_TO_BDG_FWD : - bdg_forward((struct mbuf **)&pkt, pkt->ifp); + case DN_TO_BDG_FWD : { + struct mbuf *m = (struct mbuf *)pkt ; + struct ether_header *eh; + + if (pkt->dn_m->m_len < ETHER_HDR_LEN + && (pkt->dn_m = m_pullup(pkt->dn_m, ETHER_HDR_LEN)) == NULL) { + printf("dummynet/bridge: pullup fail, dropping pkt\n"); + break; + } + /* + * same as ether_input, make eh be a pointer into the mbuf + */ + eh = mtod(pkt->dn_m, struct ether_header *); + m_adj(pkt->dn_m, ETHER_HDR_LEN); + /* + * bdg_forward() wants a pointer to the pseudo-mbuf-header, but + * on return it will supply the pointer to the actual packet + * (originally pkt->dn_m, but could be something else now) if + * it has not consumed it. + */ + m = bdg_forward(m, eh, pkt->ifp); + if (m) + m_freem(m); + } break ; #endif + default: printf("dummynet: bad switch %d!\n", pkt->dn_dir); m_freem(pkt->dn_m); - FREE(pkt, M_IPFW); break ; } + FREE(pkt, M_IPFW); } + /* if there are leftover packets, put into the heap for next event */ + if ( (pkt = pipe->head) ) + heap_insert(&extract_heap, pkt->output_time, pipe ) ; + /* XXX should check errors on heap_insert, by draining the + * whole pipe p and hoping in the future we are more successful + */ } + /* - * this is the periodic task that moves packets between the R- - * and the P- queue + * the following macro computes how many ticks we have to wait + * before being able to transmit a packet. The credit is taken from + * either a pipe (WF2Q) or a flow_queue (per-flow queueing) */ -/*ARGSUSED*/ -void -dummynet(void * __unused unused) +#define SET_TICKS(pkt, q, p) \ + (pkt->dn_m->m_pkthdr.len*8*hz - (q)->numbytes + p->bandwidth - 1 ) / \ + p->bandwidth ; + +/* + * extract pkt from queue, compute output time (could be now) + * and put into delay line (p_queue) + */ +static void +move_pkt(struct dn_pkt *pkt, struct dn_flow_queue *q, + struct dn_pipe *p, int len) { - struct dn_pipe *p ; - int s ; - boolean_t funnel_state; + q->head = DN_NEXT(pkt) ; + q->len-- ; + q->len_bytes -= len ; - funnel_state = thread_funnel_set(network_flock, TRUE); - dn_calls++ ; - for (p = all_pipes ; p ; p = p->next ) { - /* - * Increment the amount of data that can be sent. However, - * don't do that if the channel is idle - * (r.head == NULL && numbytes >= bandwidth). - * This bug fix is from tim shepard (shep@bbn.com) - */ - s = splimp(); - if (p->r.head != NULL || p->numbytes < p->bandwidth ) - p->numbytes += p->bandwidth ; - dn_move(p, 0); /* is it really 0 (also below) ? */ - splx(s); - } - - /* - * finally, if some queue has data, restart the timer. - */ - dn_idle = 1; - dn_restart(); - (void) thread_funnel_set(network_flock, funnel_state); + pkt->output_time = curr_time + p->delay ; + if (p->head == NULL) + p->head = pkt; + else + DN_NEXT(p->tail) = pkt; + p->tail = pkt; + DN_NEXT(p->tail) = NULL; } /* - * dummynet hook for packets. - * input and output use the same code, so i use bit 16 in the pipe - * number to chose the direction: 1 for output packets, 0 for input. - * for input, only m is significant. For output, also the others. + * ready_event() is invoked every time the queue must enter the + * scheduler, either because the first packet arrives, or because + * a previously scheduled event fired. + * On invokation, drain as many pkts as possible (could be 0) and then + * if there are leftover packets reinsert the pkt in the scheduler. */ -int -dummynet_io(int pipe_nr, int dir, - struct mbuf *m, struct ifnet *ifp, struct route *ro, int hlen, - struct ip_fw_chain *rule) +static void +ready_event(struct dn_flow_queue *q) { struct dn_pkt *pkt; - struct dn_pipe *pipe; - struct ip *ip=mtod(m, struct ip *); + struct dn_pipe *p = q->fs->pipe ; + int p_was_empty ; - int s=splimp(); + if (p == NULL) { + printf("ready_event- pipe is gone\n"); + return ; + } + p_was_empty = (p->head == NULL) ; - pipe_nr &= 0xffff ; /* - * locate pipe. First time is expensive, next have direct access. + * schedule fixed-rate queues linked to this pipe: + * Account for the bw accumulated since last scheduling, then + * drain as many pkts as allowed by q->numbytes and move to + * the delay line (in p) computing output time. + * bandwidth==0 (no limit) means we can drain the whole queue, + * setting len_scaled = 0 does the job. + */ + q->numbytes += ( curr_time - q->sched_time ) * p->bandwidth; + while ( (pkt = q->head) != NULL ) { + int len = pkt->dn_m->m_pkthdr.len; + int len_scaled = p->bandwidth ? len*8*hz : 0 ; + if (len_scaled > q->numbytes ) + break ; + q->numbytes -= len_scaled ; + move_pkt(pkt, q, p, len); + } + /* + * If we have more packets queued, schedule next ready event + * (can only occur when bandwidth != 0, otherwise we would have + * flushed the whole queue in the previous loop). + * To this purpose we record the current time and compute how many + * ticks to go for the finish time of the packet. + */ + if ( (pkt = q->head) != NULL ) { /* this implies bandwidth != 0 */ + dn_key t = SET_TICKS(pkt, q, p); /* ticks i have to wait */ + q->sched_time = curr_time ; + heap_insert(&ready_heap, curr_time + t, (void *)q ); + /* XXX should check errors on heap_insert, and drain the whole + * queue on error hoping next time we are luckier. + */ + } else /* RED needs to know when the queue becomes empty */ + q->q_time = curr_time; + /* + * If the delay line was empty call transmit_event(p) now. + * Otherwise, the scheduler will take care of it. */ + if (p_was_empty) + transmit_event(p); +} - if ( (pipe = rule->rule->pipe_ptr) == NULL ) { - for (pipe=all_pipes; pipe && pipe->pipe_nr !=pipe_nr; pipe=pipe->next) - ; - if (pipe == NULL) { - splx(s); - if (dn_debug) - printf("warning, pkt for no pipe %d\n", pipe_nr); - m_freem(m); - return 0 ; - } else - rule->rule->pipe_ptr = pipe ; +/* + * Called when we can transmit packets on WF2Q queues. Take pkts out of + * the queues at their start time, and enqueue into the delay line. + * Packets are drained until p->numbytes < 0. As long as + * len_scaled >= p->numbytes, the packet goes into the delay line + * with a deadline p->delay. For the last packet, if p->numbytes<0, + * there is an additional delay. + */ +static void +ready_event_wfq(struct dn_pipe *p) +{ + int p_was_empty = (p->head == NULL) ; + struct dn_heap *sch = &(p->scheduler_heap); + struct dn_heap *neh = &(p->not_eligible_heap) ; + + if (p->if_name[0] == 0) /* tx clock is simulated */ + p->numbytes += ( curr_time - p->sched_time ) * p->bandwidth; + else { /* tx clock is for real, the ifq must be empty or this is a NOP */ + if (p->ifp && p->ifp->if_snd.ifq_head != NULL) + return ; + else { + DEB(printf("pipe %d ready from %s --\n", + p->pipe_nr, p->if_name);) + } } - + /* - * should i drop ? - * This section implements random packet drop. + * While we have backlogged traffic AND credit, we need to do + * something on the queue. */ - if ( (pipe->plr && random() < pipe->plr) || - (pipe->queue_size && pipe->r_len >= pipe->queue_size) || - (pipe->queue_size_bytes && - ip->ip_len + pipe->r_len_bytes > pipe->queue_size_bytes) || - (pkt = (struct dn_pkt *) _MALLOC(sizeof (*pkt), - M_IPFW, M_WAITOK) ) == NULL ) { - splx(s); - if (dn_debug) - printf("-- dummynet: drop from pipe %d, have %d pks, %d bytes\n", - pipe_nr, pipe->r_len, pipe->r_len_bytes); - pipe->r_drops++ ; - m_freem(m); - return 0 ; /* XXX error */ - } - bzero(pkt, sizeof(*pkt) ); - /* build and enqueue packet */ - pkt->hdr.mh_type = MT_DUMMYNET ; - (struct ip_fw_chain *)pkt->hdr.mh_data = rule ; - pkt->dn_next = NULL; - pkt->dn_m = m; - pkt->dn_dir = dir ; - pkt->delay = 0; + while ( p->numbytes >=0 && (sch->elements>0 || neh->elements >0) ) { + if (sch->elements > 0) { /* have some eligible pkts to send out */ + struct dn_flow_queue *q = sch->p[0].object ; + struct dn_pkt *pkt = q->head; + struct dn_flow_set *fs = q->fs; + u_int64_t len = pkt->dn_m->m_pkthdr.len; + int len_scaled = p->bandwidth ? len*8*hz : 0 ; - pkt->ifp = ifp; - if (dir == DN_TO_IP_OUT) { - pkt->ro = *ro; /* XXX copied! */ - if (ro->ro_rt) - ro->ro_rt->rt_refcnt++ ; /* XXX */ + heap_extract(sch, NULL); /* remove queue from heap */ + p->numbytes -= len_scaled ; + move_pkt(pkt, q, p, len); + + p->V += (len<sum ; /* update V */ + q->S = q->F ; /* update start time */ + if (q->len == 0) { /* Flow not backlogged any more */ + fs->backlogged-- ; + heap_insert(&(p->idle_heap), q->F, q); + } else { /* still backlogged */ + /* + * update F and position in backlogged queue, then + * put flow in not_eligible_heap (we will fix this later). + */ + len = (q->head)->dn_m->m_pkthdr.len; + q->F += (len<weight ; + if (DN_KEY_LEQ(q->S, p->V)) + heap_insert(neh, q->S, q); + else + heap_insert(sch, q->F, q); + } + } + /* + * now compute V = max(V, min(S_i)). Remember that all elements in sch + * have by definition S_i <= V so if sch is not empty, V is surely + * the max and we must not update it. Conversely, if sch is empty + * we only need to look at neh. + */ + if (sch->elements == 0 && neh->elements > 0) + p->V = MAX64 ( p->V, neh->p[0].key ); + /* move from neh to sch any packets that have become eligible */ + while (neh->elements > 0 && DN_KEY_LEQ(neh->p[0].key, p->V) ) { + struct dn_flow_queue *q = neh->p[0].object ; + heap_extract(neh, NULL); + heap_insert(sch, q->F, q); + } + + if (p->if_name[0] != '\0') {/* tx clock is from a real thing */ + p->numbytes = -1 ; /* mark not ready for I/O */ + break ; + } } - pkt->dn_hlen = hlen; - if (pipe->r.head == NULL) - pipe->r.head = pkt; - else - (struct dn_pkt *)pipe->r.tail->dn_next = pkt; - pipe->r.tail = pkt; - pipe->r_len++; - pipe->r_len_bytes += ip->ip_len ; + if (sch->elements == 0 && neh->elements == 0 && p->numbytes >= 0 + && p->idle_heap.elements > 0) { + /* + * no traffic and no events scheduled. We can get rid of idle-heap. + */ + int i ; + + for (i = 0 ; i < p->idle_heap.elements ; i++) { + struct dn_flow_queue *q = p->idle_heap.p[i].object ; - /* - * here we could implement RED if we like to + q->F = 0 ; + q->S = q->F + 1 ; + } + p->sum = 0 ; + p->V = 0 ; + p->idle_heap.elements = 0 ; + } + /* + * If we are getting clocks from dummynet (not a real interface) and + * If we are under credit, schedule the next ready event. + * Also fix the delivery time of the last packet. */ + if (p->if_name[0]==0 && p->numbytes < 0) { /* this implies bandwidth >0 */ + dn_key t=0 ; /* number of ticks i have to wait */ - if (pipe->r.head == pkt) { /* process immediately */ - dn_move(pipe, 1); + if (p->bandwidth > 0) + t = ( p->bandwidth -1 - p->numbytes) / p->bandwidth ; + p->tail->output_time += t ; + p->sched_time = curr_time ; + heap_insert(&wfq_ready_heap, curr_time + t, (void *)p); + /* XXX should check errors on heap_insert, and drain the whole + * queue on error hoping next time we are luckier. + */ } - splx(s); - if (dn_idle) - dn_restart(); - return 0; + /* + * If the delay line was empty call transmit_event(p) now. + * Otherwise, the scheduler will take care of it. + */ + if (p_was_empty) + transmit_event(p); } /* - * dispose all packets queued on a pipe + * This is called once per tick, or HZ times per second. It is used to + * increment the current tick counter and schedule expired events. */ static void -purge_pipe(struct dn_pipe *pipe) +dummynet(void * __unused unused) { - struct dn_pkt *pkt, *n ; - struct rtentry *tmp_rt ; + void *p ; /* generic parameter to handler */ + struct dn_heap *h ; + int s ; + struct dn_heap *heaps[3]; + int i; + struct dn_pipe *pe ; - for (pkt = pipe->r.head ; pkt ; ) { - rt_unref (tmp_rt = pkt->ro.ro_rt ) ; - m_freem(pkt->dn_m); - n = pkt ; - pkt = (struct dn_pkt *)pkt->dn_next ; - FREE(n, M_IPFW) ; - } - for (pkt = pipe->p.head ; pkt ; ) { - rt_unref (tmp_rt = pkt->ro.ro_rt ) ; - m_freem(pkt->dn_m); - n = pkt ; - pkt = (struct dn_pkt *)pkt->dn_next ; - FREE(n, M_IPFW) ; + heaps[0] = &ready_heap ; /* fixed-rate queues */ + heaps[1] = &wfq_ready_heap ; /* wfq queues */ + heaps[2] = &extract_heap ; /* delay line */ + s = splimp(); /* see note on top, splnet() is not enough */ + curr_time++ ; + for (i=0; i < 3 ; i++) { + h = heaps[i]; + while (h->elements > 0 && DN_KEY_LEQ(h->p[0].key, curr_time) ) { + DDB(if (h->p[0].key > curr_time) + printf("-- dummynet: warning, heap %d is %d ticks late\n", + i, (int)(curr_time - h->p[0].key));) + p = h->p[0].object ; /* store a copy before heap_extract */ + heap_extract(h, NULL); /* need to extract before processing */ + if (i == 0) + ready_event(p) ; + else if (i == 1) { + struct dn_pipe *pipe = p; + if (pipe->if_name[0] != '\0') + printf("*** bad ready_event_wfq for pipe %s\n", + pipe->if_name); + else + ready_event_wfq(p) ; + } else + transmit_event(p); + } } -} + /* sweep pipes trying to expire idle flow_queues */ + for (pe = all_pipes; pe ; pe = pe->next ) + if (pe->idle_heap.elements > 0 && + DN_KEY_LT(pe->idle_heap.p[0].key, pe->V) ) { + struct dn_flow_queue *q = pe->idle_heap.p[0].object ; + heap_extract(&(pe->idle_heap), NULL); + q->S = q->F + 1 ; /* mark timestamp as invalid */ + pe->sum -= q->fs->weight ; + } + splx(s); + timeout(dummynet, NULL, 1); +} + /* - * delete all pipes returning memory + * called by an interface when tx_rdy occurs. */ -static void -dummynet_flush() +int +if_tx_rdy(struct ifnet *ifp) { - struct dn_pipe *q, *p = all_pipes ; - int s = splnet() ; + struct dn_pipe *p; - all_pipes = NULL ; - splx(s) ; - /* - * purge all queued pkts and delete all pipes - */ - for ( ; p ; ) { - purge_pipe(p); - q = p ; - p = p->next ; - FREE(q, M_IPFW); + for (p = all_pipes; p ; p = p->next ) + if (p->ifp == ifp) + break ; + if (p == NULL) { + char buf[32]; + sprintf(buf, "%s%d",ifp->if_name, ifp->if_unit); + for (p = all_pipes; p ; p = p->next ) + if (!strcmp(p->if_name, buf) ) { + p->ifp = ifp ; + DEB(printf("++ tx rdy from %s (now found)\n", buf);) + break ; + } + } + if (p != NULL) { + DEB(printf("++ tx rdy from %s%d - qlen %d\n", ifp->if_name, + ifp->if_unit, ifp->if_snd.ifq_len);) + p->numbytes = 0 ; /* mark ready for I/O */ + ready_event_wfq(p); } + return 0; } -extern struct ip_fw_chain *ip_fw_default_rule ; /* - * when a firewall rule is deleted, scan all pipes and remove the flow-id - * from packets matching this rule. + * Unconditionally expire empty queues in case of shortage. + * Returns the number of queues freed. */ -void -dn_rule_delete(void *r) +static int +expire_queues(struct dn_flow_set *fs) { - struct dn_pipe *p ; - int matches = 0 ; + struct dn_flow_queue *q, *prev ; + int i, initial_elements = fs->rq_elements ; - for ( p = all_pipes ; p ; p = p->next ) { - struct dn_pkt *x ; - for (x = p->r.head ; x ; x = (struct dn_pkt *)x->dn_next ) - if (x->hdr.mh_data == r) { - matches++ ; - x->hdr.mh_data = (void *)ip_fw_default_rule ; - } - for (x = p->p.head ; x ; x = (struct dn_pkt *)x->dn_next ) - if (x->hdr.mh_data == r) { - matches++ ; - x->hdr.mh_data = (void *)ip_fw_default_rule ; + if (fs->last_expired == time_second) + return 0 ; + fs->last_expired = time_second ; + for (i = 0 ; i <= fs->rq_size ; i++) /* last one is overflow */ + for (prev=NULL, q = fs->rq[i] ; q != NULL ; ) + if (q->head != NULL || q->S != q->F+1) { + prev = q ; + q = q->next ; + } else { /* entry is idle, expire it */ + struct dn_flow_queue *old_q = q ; + + if (prev != NULL) + prev->next = q = q->next ; + else + fs->rq[i] = q = q->next ; + fs->rq_elements-- ; + FREE(old_q, M_IPFW); } - } - printf("dn_rule_delete, r %p, default %p%s, %d matches\n", - (void *)r, (void *)ip_fw_default_rule, - r == ip_fw_default_rule ? " AARGH!":"", matches); + return initial_elements - fs->rq_elements ; } /* - * handler for the various dummynet socket options - * (get, flush, config, del) + * If room, create a new queue and put at head of slot i; + * otherwise, create or use the default queue. */ -static int -ip_dn_ctl(struct sockopt *sopt) +static struct dn_flow_queue * +create_queue(struct dn_flow_set *fs, int i) { - int error = 0 ; - size_t size ; - char *buf, *bp ; - struct dn_pipe *p, tmp_pipe ; + struct dn_flow_queue *q ; - struct dn_pipe *x, *a, *b ; + if (fs->rq_elements > fs->rq_size * dn_max_ratio && + expire_queues(fs) == 0) { + /* + * No way to get room, use or create overflow queue. + */ + i = fs->rq_size ; + if ( fs->rq[i] != NULL ) + return fs->rq[i] ; + } + q = _MALLOC(sizeof(*q), M_IPFW, M_DONTWAIT) ; + if (q == NULL) { + printf("sorry, cannot allocate queue for new flow\n"); + return NULL ; + } + bzero(q, sizeof(*q) ); /* needed */ + q->fs = fs ; + q->hash_slot = i ; + q->next = fs->rq[i] ; + q->S = q->F + 1; /* hack - mark timestamp as invalid */ + fs->rq[i] = q ; + fs->rq_elements++ ; + return q ; +} - /* Disallow sets in really-really secure mode. */ - if (sopt->sopt_dir == SOPT_SET && securelevel >= 3) - return (EPERM); +/* + * Given a flow_set and a pkt in last_pkt, find a matching queue + * after appropriate masking. The queue is moved to front + * so that further searches take less time. + */ +static struct dn_flow_queue * +find_queue(struct dn_flow_set *fs) +{ + int i = 0 ; /* we need i and q for new allocations */ + struct dn_flow_queue *q, *prev; - switch (sopt->sopt_name) { - default : - panic("ip_dn_ctl -- unknown option"); + if ( !(fs->flags_fs & DN_HAVE_FLOW_MASK) ) + q = fs->rq[0] ; + else { + /* first, do the masking */ + last_pkt.dst_ip &= fs->flow_mask.dst_ip ; + last_pkt.src_ip &= fs->flow_mask.src_ip ; + last_pkt.dst_port &= fs->flow_mask.dst_port ; + last_pkt.src_port &= fs->flow_mask.src_port ; + last_pkt.proto &= fs->flow_mask.proto ; + last_pkt.flags = 0 ; /* we don't care about this one */ + /* then, hash function */ + i = ( (last_pkt.dst_ip) & 0xffff ) ^ + ( (last_pkt.dst_ip >> 15) & 0xffff ) ^ + ( (last_pkt.src_ip << 1) & 0xffff ) ^ + ( (last_pkt.src_ip >> 16 ) & 0xffff ) ^ + (last_pkt.dst_port << 1) ^ (last_pkt.src_port) ^ + (last_pkt.proto ); + i = i % fs->rq_size ; + /* finally, scan the current list for a match */ + searches++ ; + for (prev=NULL, q = fs->rq[i] ; q ; ) { + search_steps++; + if (bcmp(&last_pkt, &(q->id), sizeof(q->id) ) == 0) + break ; /* found */ + else if (pipe_expire && q->head == NULL && q->S == q->F+1 ) { + /* entry is idle and not in any heap, expire it */ + struct dn_flow_queue *old_q = q ; - case IP_DUMMYNET_GET : - for (p = all_pipes, size = 0 ; p ; p = p->next ) - size += sizeof( *p ) ; - buf = _MALLOC(size, M_TEMP, M_WAITOK); - if (buf == 0) { - error = ENOBUFS ; - break ; + if (prev != NULL) + prev->next = q = q->next ; + else + fs->rq[i] = q = q->next ; + fs->rq_elements-- ; + FREE(old_q, M_IPFW); + continue ; + } + prev = q ; + q = q->next ; } - for (p = all_pipes, bp = buf ; p ; p = p->next ) { - struct dn_pipe *q = (struct dn_pipe *)bp ; - - bcopy(p, bp, sizeof( *p ) ); - /* - * return bw and delay in bits/s and ms, respectively - */ - q->bandwidth *= (8*hz) ; - q->delay = (q->delay * 1000) / hz ; - bp += sizeof( *p ) ; + if (q && prev != NULL) { /* found and not in front */ + prev->next = q->next ; + q->next = fs->rq[i] ; + fs->rq[i] = q ; } - error = sooptcopyout(sopt, buf, size); - FREE(buf, M_TEMP); - break ; - case IP_DUMMYNET_FLUSH : - dummynet_flush() ; - break ; - case IP_DUMMYNET_CONFIGURE : - p = &tmp_pipe ; - error = sooptcopyin(sopt, p, sizeof *p, sizeof *p); - if (error) - break ; + } + if (q == NULL) { /* no match, need to allocate a new entry */ + q = create_queue(fs, i); + if (q != NULL) + q->id = last_pkt ; + } + return q ; +} + +static int +red_drops(struct dn_flow_set *fs, struct dn_flow_queue *q, int len) +{ + /* + * RED algorithm + * + * RED calculates the average queue size (avg) using a low-pass filter + * with an exponential weighted (w_q) moving average: + * avg <- (1-w_q) * avg + w_q * q_size + * where q_size is the queue length (measured in bytes or * packets). + * + * If q_size == 0, we compute the idle time for the link, and set + * avg = (1 - w_q)^(idle/s) + * where s is the time needed for transmitting a medium-sized packet. + * + * Now, if avg < min_th the packet is enqueued. + * If avg > max_th the packet is dropped. Otherwise, the packet is + * dropped with probability P function of avg. + * + */ + + int64_t p_b = 0; + /* queue in bytes or packets ? */ + u_int q_size = (fs->flags_fs & DN_QSIZE_IS_BYTES) ? q->len_bytes : q->len; + + DEB(printf("\n%d q: %2u ", (int) curr_time, q_size);) + + /* average queue size estimation */ + if (q_size != 0) { + /* + * queue is not empty, avg <- avg + (q_size - avg) * w_q + */ + int diff = SCALE(q_size) - q->avg; + int64_t v = SCALE_MUL((int64_t) diff, (int64_t) fs->w_q); + + q->avg += (int) v; + } else { + /* + * queue is empty, find for how long the queue has been + * empty and use a lookup table for computing + * (1 - * w_q)^(idle_time/s) where s is the time to send a + * (small) packet. + * XXX check wraps... + */ + if (q->avg) { + u_int t = (curr_time - q->q_time) / fs->lookup_step; + + q->avg = (t < fs->lookup_depth) ? + SCALE_MUL(q->avg, fs->w_q_lookup[t]) : 0; + } + } + DEB(printf("avg: %u ", SCALE_VAL(q->avg));) + + /* should i drop ? */ + + if (q->avg < fs->min_th) { + q->count = -1; + return 0; /* accept packet ; */ + } + if (q->avg >= fs->max_th) { /* average queue >= max threshold */ + if (fs->flags_fs & DN_IS_GENTLE_RED) { /* - * The config program passes parameters as follows: - * bandwidth = bits/second (0 = no limits); - * must be translated in bytes/tick. - * delay = ms - * must be translated in ticks. - * queue_size = slots (0 = no limit) - * queue_size_bytes = bytes (0 = no limit) - * only one can be set, must be bound-checked + * According to Gentle-RED, if avg is greater than max_th the + * packet is dropped with a probability + * p_b = c_3 * avg - c_4 + * where c_3 = (1 - max_p) / max_th, and c_4 = 1 - 2 * max_p */ - if ( p->bandwidth > 0 ) { - p->bandwidth = p->bandwidth / 8 / hz ; - if (p->bandwidth == 0) /* too little does not make sense! */ - p->bandwidth = 10 ; + p_b = SCALE_MUL((int64_t) fs->c_3, (int64_t) q->avg) - fs->c_4; + } else { + q->count = -1; + printf("- drop"); + return 1 ; + } + } else if (q->avg > fs->min_th) { + /* + * we compute p_b using the linear dropping function p_b = c_1 * + * avg - c_2, where c_1 = max_p / (max_th - min_th), and c_2 = + * max_p * min_th / (max_th - min_th) + */ + p_b = SCALE_MUL((int64_t) fs->c_1, (int64_t) q->avg) - fs->c_2; + } + if (fs->flags_fs & DN_QSIZE_IS_BYTES) + p_b = (p_b * len) / fs->max_pkt_size; + if (++q->count == 0) + q->random = random() & 0xffff; + else { + /* + * q->count counts packets arrived since last drop, so a greater + * value of q->count means a greater packet drop probability. + */ + if (SCALE_MUL(p_b, SCALE((int64_t) q->count)) > q->random) { + q->count = 0; + DEB(printf("- red drop");) + /* after a drop we calculate a new random value */ + q->random = random() & 0xffff; + return 1; /* drop */ + } + } + /* end of RED algorithm */ + return 0 ; /* accept */ +} + +static __inline +struct dn_flow_set * +locate_flowset(int pipe_nr, struct ip_fw_chain *rule) +{ + struct dn_flow_set *fs = NULL ; + + if ( (rule->rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_QUEUE ) + for (fs=all_flow_sets; fs && fs->fs_nr != pipe_nr; fs=fs->next) + ; + else { + struct dn_pipe *p1; + for (p1 = all_pipes; p1 && p1->pipe_nr != pipe_nr; p1 = p1->next) + ; + if (p1 != NULL) + fs = &(p1->fs) ; + } + if (fs != NULL) + rule->rule->pipe_ptr = fs ; /* record for the future */ + return fs ; +} + +/* + * dummynet hook for packets. Below 'pipe' is a pipe or a queue + * depending on whether WF2Q or fixed bw is used. + */ +int +dummynet_io(int pipe_nr, int dir, /* pipe_nr can also be a fs_nr */ + struct mbuf *m, struct ifnet *ifp, struct route *ro, + struct sockaddr_in *dst, + struct ip_fw_chain *rule, int flags) +{ + struct dn_pkt *pkt; + struct dn_flow_set *fs; + struct dn_pipe *pipe ; + u_int64_t len = m->m_pkthdr.len ; + struct dn_flow_queue *q = NULL ; + int s ; + + s = splimp(); + + pipe_nr &= 0xffff ; + + if ( (fs = rule->rule->pipe_ptr) == NULL ) { + fs = locate_flowset(pipe_nr, rule); + if (fs == NULL) + goto dropit ; /* this queue/pipe does not exist! */ + } + pipe = fs->pipe ; + if (pipe == NULL) { /* must be a queue, try find a matching pipe */ + for (pipe = all_pipes; pipe && pipe->pipe_nr != fs->parent_nr; + pipe = pipe->next) + ; + if (pipe != NULL) + fs->pipe = pipe ; + else { + printf("No pipe %d for queue %d, drop pkt\n", + fs->parent_nr, fs->fs_nr); + goto dropit ; + } + } + q = find_queue(fs); + if ( q == NULL ) + goto dropit ; /* cannot allocate queue */ + /* + * update statistics, then check reasons to drop pkt + */ + q->tot_bytes += len ; + q->tot_pkts++ ; + if ( fs->plr && random() < fs->plr ) + goto dropit ; /* random pkt drop */ + if ( fs->flags_fs & DN_QSIZE_IS_BYTES) { + if (q->len_bytes > fs->qsize) + goto dropit ; /* queue size overflow */ + } else { + if (q->len >= fs->qsize) + goto dropit ; /* queue count overflow */ + } + if ( fs->flags_fs & DN_IS_RED && red_drops(fs, q, len) ) + goto dropit ; + + pkt = (struct dn_pkt *)_MALLOC(sizeof (*pkt), M_IPFW, M_NOWAIT) ; + if ( pkt == NULL ) + goto dropit ; /* cannot allocate packet header */ + /* ok, i can handle the pkt now... */ + bzero(pkt, sizeof(*pkt) ); /* XXX expensive, see if we can remove it*/ + /* build and enqueue packet + parameters */ + pkt->hdr.mh_type = MT_DUMMYNET ; + (struct ip_fw_chain *)pkt->hdr.mh_data = rule ; + DN_NEXT(pkt) = NULL; + pkt->dn_m = m; + pkt->dn_dir = dir ; + + pkt->ifp = ifp; + if (dir == DN_TO_IP_OUT) { + /* + * We need to copy *ro because for ICMP pkts (and maybe others) + * the caller passed a pointer into the stack; dst might also be + * a pointer into *ro so it needs to be updated. + */ + pkt->ro = *ro; + if (ro->ro_rt) + rtref(ro->ro_rt); + if (dst == (struct sockaddr_in *)&ro->ro_dst) /* dst points into ro */ + dst = (struct sockaddr_in *)&(pkt->ro.ro_dst) ; + + pkt->dn_dst = dst; + pkt->flags = flags ; + } + if (q->head == NULL) + q->head = pkt; + else + DN_NEXT(q->tail) = pkt; + q->tail = pkt; + q->len++; + q->len_bytes += len ; + + if ( q->head != pkt ) /* flow was not idle, we are done */ + goto done; + /* + * If we reach this point the flow was previously idle, so we need + * to schedule it. This involves different actions for fixed-rate or + * WF2Q queues. + */ + if ( (rule->rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_PIPE ) { + /* + * Fixed-rate queue: just insert into the ready_heap. + */ + dn_key t = 0 ; + if (pipe->bandwidth) + t = SET_TICKS(pkt, q, pipe); + q->sched_time = curr_time ; + if (t == 0) /* must process it now */ + ready_event( q ); + else + heap_insert(&ready_heap, curr_time + t , q ); + } else { + /* + * WF2Q. First, compute start time S: if the flow was idle (S=F+1) + * set S to the virtual time V for the controlling pipe, and update + * the sum of weights for the pipe; otherwise, remove flow from + * idle_heap and set S to max(F,V). + * Second, compute finish time F = S + len/weight. + * Third, if pipe was idle, update V=max(S, V). + * Fourth, count one more backlogged flow. + */ + if (DN_KEY_GT(q->S, q->F)) { /* means timestamps are invalid */ + q->S = pipe->V ; + pipe->sum += fs->weight ; /* add weight of new queue */ + } else { + heap_extract(&(pipe->idle_heap), q); + q->S = MAX64(q->F, pipe->V ) ; + } + q->F = q->S + ( len<weight; + + if (pipe->not_eligible_heap.elements == 0 && + pipe->scheduler_heap.elements == 0) + pipe->V = MAX64 ( q->S, pipe->V ); + fs->backlogged++ ; + /* + * Look at eligibility. A flow is not eligibile if S>V (when + * this happens, it means that there is some other flow already + * scheduled for the same pipe, so the scheduler_heap cannot be + * empty). If the flow is not eligible we just store it in the + * not_eligible_heap. Otherwise, we store in the scheduler_heap + * and possibly invoke ready_event_wfq() right now if there is + * leftover credit. + * Note that for all flows in scheduler_heap (SCH), S_i <= V, + * and for all flows in not_eligible_heap (NEH), S_i > V . + * So when we need to compute max( V, min(S_i) ) forall i in SCH+NEH, + * we only need to look into NEH. + */ + if (DN_KEY_GT(q->S, pipe->V) ) { /* not eligible */ + if (pipe->scheduler_heap.elements == 0) + printf("++ ouch! not eligible but empty scheduler!\n"); + heap_insert(&(pipe->not_eligible_heap), q->S, q); + } else { + heap_insert(&(pipe->scheduler_heap), q->F, q); + if (pipe->numbytes >= 0) { /* pipe is idle */ + if (pipe->scheduler_heap.elements != 1) + printf("*** OUCH! pipe should have been idle!\n"); + DEB(printf("Waking up pipe %d at %d\n", + pipe->pipe_nr, (int)(q->F >> MY_M)); ) + pipe->sched_time = curr_time ; + ready_event_wfq(pipe); } - p->delay = ( p->delay * hz ) / 1000 ; - if (p->queue_size == 0 && p->queue_size_bytes == 0) - p->queue_size = 100 ; - if (p->queue_size != 0 ) /* buffers are prevailing */ - p->queue_size_bytes = 0 ; - if (p->queue_size > 100) - p->queue_size = 100 ; - if (p->queue_size_bytes > 1024*1024) - p->queue_size_bytes = 1024*1024 ; -#if 0 - printf("ip_dn: config pipe %d %d bit/s %d ms %d bufs\n", - p->pipe_nr, - p->bandwidth * 8 * hz , - p->delay * 1000 / hz , p->queue_size); -#endif - for (a = NULL , b = all_pipes ; b && b->pipe_nr < p->pipe_nr ; + } + } +done: + splx(s); + return 0; + +dropit: + splx(s); + if (q) + q->drops++ ; + m_freem(m); + return ENOBUFS ; +} + +/* + * Below, the rt_unref is only needed when (pkt->dn_dir == DN_TO_IP_OUT) + * Doing this would probably save us the initial bzero of dn_pkt + */ +#define DN_FREE_PKT(pkt) { \ + struct dn_pkt *n = pkt ; \ + rt_unref ( n->ro.ro_rt ) ; \ + m_freem(n->dn_m); \ + pkt = DN_NEXT(n) ; \ + FREE(n, M_IPFW) ; } + +/* + * Dispose all packets and flow_queues on a flow_set. + * If all=1, also remove red lookup table and other storage, + * including the descriptor itself. + * For the one in dn_pipe MUST also cleanup ready_heap... + */ +static void +purge_flow_set(struct dn_flow_set *fs, int all) +{ + struct dn_pkt *pkt ; + struct dn_flow_queue *q, *qn ; + int i ; + + for (i = 0 ; i <= fs->rq_size ; i++ ) { + for (q = fs->rq[i] ; q ; q = qn ) { + for (pkt = q->head ; pkt ; ) + DN_FREE_PKT(pkt) ; + qn = q->next ; + FREE(q, M_IPFW); + } + fs->rq[i] = NULL ; + } + fs->rq_elements = 0 ; + if (all) { + /* RED - free lookup table */ + if (fs->w_q_lookup) + FREE(fs->w_q_lookup, M_IPFW); + if (fs->rq) + FREE(fs->rq, M_IPFW); + /* if this fs is not part of a pipe, free it */ + if (fs->pipe && fs != &(fs->pipe->fs) ) + FREE(fs, M_IPFW); + } +} + +/* + * Dispose all packets queued on a pipe (not a flow_set). + * Also free all resources associated to a pipe, which is about + * to be deleted. + */ +static void +purge_pipe(struct dn_pipe *pipe) +{ + struct dn_pkt *pkt ; + + purge_flow_set( &(pipe->fs), 1 ); + + for (pkt = pipe->head ; pkt ; ) + DN_FREE_PKT(pkt) ; + + heap_free( &(pipe->scheduler_heap) ); + heap_free( &(pipe->not_eligible_heap) ); + heap_free( &(pipe->idle_heap) ); +} + +/* + * Delete all pipes and heaps returning memory. Must also + * remove references from all ipfw rules to all pipes. + */ +static void +dummynet_flush() +{ + struct dn_pipe *curr_p, *p ; + struct ip_fw_chain *chain ; + struct dn_flow_set *fs, *curr_fs; + int s ; + + s = splimp() ; + + /* remove all references to pipes ...*/ + LIST_FOREACH(chain, &ip_fw_chain_head, next) + chain->rule->pipe_ptr = NULL ; + /* prevent future matches... */ + p = all_pipes ; + all_pipes = NULL ; + fs = all_flow_sets ; + all_flow_sets = NULL ; + /* and free heaps so we don't have unwanted events */ + heap_free(&ready_heap); + heap_free(&wfq_ready_heap); + heap_free(&extract_heap); + splx(s) ; + /* + * Now purge all queued pkts and delete all pipes + */ + /* scan and purge all flow_sets. */ + for ( ; fs ; ) { + curr_fs = fs ; + fs = fs->next ; + purge_flow_set(curr_fs, 1); + } + for ( ; p ; ) { + purge_pipe(p); + curr_p = p ; + p = p->next ; + FREE(q, M_IPFW); + } +} + + +extern struct ip_fw_chain *ip_fw_default_rule ; +static void +dn_rule_delete_fs(struct dn_flow_set *fs, void *r) +{ + int i ; + struct dn_flow_queue *q ; + struct dn_pkt *pkt ; + + for (i = 0 ; i <= fs->rq_size ; i++) /* last one is ovflow */ + for (q = fs->rq[i] ; q ; q = q->next ) + for (pkt = q->head ; pkt ; pkt = DN_NEXT(pkt) ) + if (pkt->hdr.mh_data == r) + pkt->hdr.mh_data = (void *)ip_fw_default_rule ; +} +/* + * when a firewall rule is deleted, scan all queues and remove the flow-id + * from packets matching this rule. + */ +void +dn_rule_delete(void *r) +{ + struct dn_pipe *p ; + struct dn_pkt *pkt ; + struct dn_flow_set *fs ; + + /* + * If the rule references a queue (dn_flow_set), then scan + * the flow set, otherwise scan pipes. Should do either, but doing + * both does not harm. + */ + for ( fs = all_flow_sets ; fs ; fs = fs->next ) + dn_rule_delete_fs(fs, r); + for ( p = all_pipes ; p ; p = p->next ) { + fs = &(p->fs) ; + dn_rule_delete_fs(fs, r); + for (pkt = p->head ; pkt ; pkt = DN_NEXT(pkt) ) + if (pkt->hdr.mh_data == r) + pkt->hdr.mh_data = (void *)ip_fw_default_rule ; + } +} + +/* + * setup RED parameters + */ +static int +config_red(struct dn_flow_set *p, struct dn_flow_set * x) +{ + int i; + + x->w_q = p->w_q; + x->min_th = SCALE(p->min_th); + x->max_th = SCALE(p->max_th); + x->max_p = p->max_p; + + x->c_1 = p->max_p / (p->max_th - p->min_th); + x->c_2 = SCALE_MUL(x->c_1, SCALE(p->min_th)); + if (x->flags_fs & DN_IS_GENTLE_RED) { + x->c_3 = (SCALE(1) - p->max_p) / p->max_th; + x->c_4 = (SCALE(1) - 2 * p->max_p); + } + + /* if the lookup table already exist, free and create it again */ + if (x->w_q_lookup) + FREE(x->w_q_lookup, M_IPFW); + if (red_lookup_depth == 0) { + printf("\nnet.inet.ip.dummynet.red_lookup_depth must be > 0"); + FREE(x, M_IPFW); + return EINVAL; + } + x->lookup_depth = red_lookup_depth; + x->w_q_lookup = (u_int *) _MALLOC(x->lookup_depth * sizeof(int), + M_IPFW, M_DONTWAIT); + if (x->w_q_lookup == NULL) { + printf("sorry, cannot allocate red lookup table\n"); + FREE(x, M_IPFW); + return ENOSPC; + } + + /* fill the lookup table with (1 - w_q)^x */ + x->lookup_step = p->lookup_step ; + x->lookup_weight = p->lookup_weight ; + x->w_q_lookup[0] = SCALE(1) - x->w_q; + for (i = 1; i < x->lookup_depth; i++) + x->w_q_lookup[i] = SCALE_MUL(x->w_q_lookup[i - 1], x->lookup_weight); + if (red_avg_pkt_size < 1) + red_avg_pkt_size = 512 ; + x->avg_pkt_size = red_avg_pkt_size ; + if (red_max_pkt_size < 1) + red_max_pkt_size = 1500 ; + x->max_pkt_size = red_max_pkt_size ; + return 0 ; +} + +static int +alloc_hash(struct dn_flow_set *x, struct dn_flow_set *pfs) +{ + if (x->flags_fs & DN_HAVE_FLOW_MASK) { /* allocate some slots */ + int l = pfs->rq_size; + + if (l == 0) + l = dn_hash_size; + if (l < 4) + l = 4; + else if (l > 1024) + l = 1024; + x->rq_size = l; + } else /* one is enough for null mask */ + x->rq_size = 1; + x->rq = _MALLOC((1 + x->rq_size) * sizeof(struct dn_flow_queue *), + M_IPFW, M_DONTWAIT); + if (x->rq == NULL) { + printf("sorry, cannot allocate queue\n"); + return ENOSPC; + } + bzero(x->rq, (1+x->rq_size) * sizeof(struct dn_flow_queue *)); + x->rq_elements = 0; + return 0 ; +} + +static void +set_fs_parms(struct dn_flow_set *x, struct dn_flow_set *src) +{ + x->flags_fs = src->flags_fs; + x->qsize = src->qsize; + x->plr = src->plr; + x->flow_mask = src->flow_mask; + if (x->flags_fs & DN_QSIZE_IS_BYTES) { + if (x->qsize > 1024*1024) + x->qsize = 1024*1024 ; + } else { + if (x->qsize == 0) + x->qsize = 50 ; + if (x->qsize > 100) + x->qsize = 50 ; + } + /* configuring RED */ + if ( x->flags_fs & DN_IS_RED ) + config_red(src, x) ; /* XXX should check errors */ +} + +/* + * setup pipe or queue parameters. + */ + +static int +config_pipe(struct dn_pipe *p) +{ + int s ; + struct dn_flow_set *pfs = &(p->fs); + + /* + * The config program passes parameters as follows: + * bw = bits/second (0 means no limits), + * delay = ms, must be translated into ticks. + * qsize = slots/bytes + */ + p->delay = ( p->delay * hz ) / 1000 ; + /* We need either a pipe number or a flow_set number */ + if (p->pipe_nr == 0 && pfs->fs_nr == 0) + return EINVAL ; + if (p->pipe_nr != 0 && pfs->fs_nr != 0) + return EINVAL ; + if (p->pipe_nr != 0) { /* this is a pipe */ + struct dn_pipe *x, *a, *b; + /* locate pipe */ + for (a = NULL , b = all_pipes ; b && b->pipe_nr < p->pipe_nr ; a = b , b = b->next) ; - if (b && b->pipe_nr == p->pipe_nr) { - /* XXX should spl and flush old pipe... */ - b->bandwidth = p->bandwidth ; - b->delay = p->delay ; - b->ticks_from_last_insert = p->delay ; - b->queue_size = p->queue_size ; - b->queue_size_bytes = p->queue_size_bytes ; - b->plr = p->plr ; - } else { - int s ; - x = _MALLOC(sizeof(struct dn_pipe), M_IPFW, M_NOWAIT) ; - if (x == NULL) { - printf("ip_dummynet.c: sorry no memory\n"); - error = ENOSPC ; - break ; - } - bzero(x, sizeof(*x) ); - x->bandwidth = p->bandwidth ; - x->delay = p->delay ; - x->ticks_from_last_insert = p->delay ; - x->pipe_nr = p->pipe_nr ; - x->queue_size = p->queue_size ; - x->queue_size_bytes = p->queue_size_bytes ; - x->plr = p->plr ; - - s = splnet() ; - x->next = b ; - if (a == NULL) - all_pipes = x ; - else - a->next = x ; - splx(s); + + if (b == NULL || b->pipe_nr != p->pipe_nr) { /* new pipe */ + x = _MALLOC(sizeof(struct dn_pipe), M_IPFW, M_DONTWAIT) ; + if (x == NULL) { + printf("ip_dummynet.c: no memory for new pipe\n"); + return ENOSPC; } - break ; + bzero(x, sizeof(struct dn_pipe)); + x->pipe_nr = p->pipe_nr; + x->fs.pipe = x ; + /* idle_heap is the only one from which we extract from the middle. + */ + x->idle_heap.size = x->idle_heap.elements = 0 ; + x->idle_heap.offset=OFFSET_OF(struct dn_flow_queue, heap_pos); + } else + x = b; + + x->bandwidth = p->bandwidth ; + x->numbytes = 0; /* just in case... */ + bcopy(p->if_name, x->if_name, sizeof(p->if_name) ); + x->ifp = NULL ; /* reset interface ptr */ + x->delay = p->delay ; + set_fs_parms(&(x->fs), pfs); - case IP_DUMMYNET_DEL : - p = &tmp_pipe ; - error = sooptcopyin(sopt, p, sizeof *p, sizeof *p); - if (error) - break ; - for (a = NULL , b = all_pipes ; b && b->pipe_nr < p->pipe_nr ; + if ( x->fs.rq == NULL ) { /* a new pipe */ + s = alloc_hash(&(x->fs), pfs) ; + if (s) { + FREE(x, M_IPFW); + return s ; + } + s = splimp() ; + x->next = b ; + if (a == NULL) + all_pipes = x ; + else + a->next = x ; + splx(s); + } + } else { /* config queue */ + struct dn_flow_set *x, *a, *b ; + + /* locate flow_set */ + for (a=NULL, b=all_flow_sets ; b && b->fs_nr < pfs->fs_nr ; a = b , b = b->next) ; - if (b && b->pipe_nr == p->pipe_nr) { /* found pipe */ - int s = splnet() ; - struct ip_fw_chain *chain = ip_fw_chain.lh_first; - if (a == NULL) - all_pipes = b->next ; - else - a->next = b->next ; - /* - * remove references to this pipe from the ip_fw rules. - */ - for (; chain; chain = chain->chain.le_next) { - register struct ip_fw *const f = chain->rule; - if (f->pipe_ptr == b) - f->pipe_ptr = NULL ; - } - splx(s); - purge_pipe(b); /* remove pkts from here */ - FREE(b, M_IPFW); + if (b == NULL || b->fs_nr != pfs->fs_nr) { /* new */ + if (pfs->parent_nr == 0) /* need link to a pipe */ + return EINVAL ; + x = _MALLOC(sizeof(struct dn_flow_set), M_IPFW, M_DONTWAIT); + if (x == NULL) { + printf("ip_dummynet.c: no memory for new flow_set\n"); + return ENOSPC; } - break ; + bzero(x, sizeof(struct dn_flow_set)); + x->fs_nr = pfs->fs_nr; + x->parent_nr = pfs->parent_nr; + x->weight = pfs->weight ; + if (x->weight == 0) + x->weight = 1 ; + else if (x->weight > 100) + x->weight = 100 ; + } else { + /* Change parent pipe not allowed; must delete and recreate */ + if (pfs->parent_nr != 0 && b->parent_nr != pfs->parent_nr) + return EINVAL ; + x = b; } - return error ; + set_fs_parms(x, pfs); + + if ( x->rq == NULL ) { /* a new flow_set */ + s = alloc_hash(x, pfs) ; + if (s) { + FREE(x, M_IPFW); + return s ; + } + s = splimp() ; + x->next = b; + if (a == NULL) + all_flow_sets = x; + else + a->next = x; + splx(s); + } + } + return 0 ; +} + +/* + * Helper function to remove from a heap queues which are linked to + * a flow_set about to be deleted. + */ +static void +fs_remove_from_heap(struct dn_heap *h, struct dn_flow_set *fs) +{ + int i = 0, found = 0 ; + for (; i < h->elements ;) + if ( ((struct dn_flow_queue *)h->p[i].object)->fs == fs) { + h->elements-- ; + h->p[i] = h->p[h->elements] ; + found++ ; + } else + i++ ; + if (found) + heapify(h); } +/* + * helper function to remove a pipe from a heap (can be there at most once) + */ +static void +pipe_remove_from_heap(struct dn_heap *h, struct dn_pipe *p) +{ + if (h->elements > 0) { + int i = 0 ; + for (i=0; i < h->elements ; i++ ) { + if (h->p[i].object == p) { /* found it */ + h->elements-- ; + h->p[i] = h->p[h->elements] ; + heapify(h); + break ; + } + } + } +} + +/* + * drain all queues. Called in case of severe mbuf shortage. + */ void -ip_dn_init(void) +dummynet_drain() { - printf("DUMMYNET initialized (980901) -- size dn_pkt %d\n", - sizeof(struct dn_pkt)); - all_pipes = NULL ; - ip_dn_ctl_ptr = ip_dn_ctl; + struct dn_flow_set *fs; + struct dn_pipe *p; + struct dn_pkt *pkt; + + heap_free(&ready_heap); + heap_free(&wfq_ready_heap); + heap_free(&extract_heap); + /* remove all references to this pipe from flow_sets */ + for (fs = all_flow_sets; fs; fs= fs->next ) + purge_flow_set(fs, 0); + + for (p = all_pipes; p; p= p->next ) { + purge_flow_set(&(p->fs), 0); + for (pkt = p->head ; pkt ; ) + DN_FREE_PKT(pkt) ; + p->head = p->tail = NULL ; + } } -#if DUMMYNET_MODULE +/* + * Fully delete a pipe or a queue, cleaning up associated info. + */ +static int +delete_pipe(struct dn_pipe *p) +{ + int s ; + struct ip_fw_chain *chain ; + + if (p->pipe_nr == 0 && p->fs.fs_nr == 0) + return EINVAL ; + if (p->pipe_nr != 0 && p->fs.fs_nr != 0) + return EINVAL ; + if (p->pipe_nr != 0) { /* this is an old-style pipe */ + struct dn_pipe *a, *b; + struct dn_flow_set *fs; -#include -#include -#include + /* locate pipe */ + for (a = NULL , b = all_pipes ; b && b->pipe_nr < p->pipe_nr ; + a = b , b = b->next) ; + if (b == NULL || (b->pipe_nr != p->pipe_nr) ) + return EINVAL ; /* not found */ -MOD_MISC(dummynet); + s = splimp() ; -static ip_dn_ctl_t *old_dn_ctl_ptr ; + /* unlink from list of pipes */ + if (a == NULL) + all_pipes = b->next ; + else + a->next = b->next ; + /* remove references to this pipe from the ip_fw rules. */ + LIST_FOREACH(chain, &ip_fw_chain_head, next) + if (chain->rule->pipe_ptr == &(b->fs)) + chain->rule->pipe_ptr = NULL ; + + /* remove all references to this pipe from flow_sets */ + for (fs = all_flow_sets; fs; fs= fs->next ) + if (fs->pipe == b) { + printf("++ ref to pipe %d from fs %d\n", + p->pipe_nr, fs->fs_nr); + fs->pipe = NULL ; + purge_flow_set(fs, 0); + } + fs_remove_from_heap(&ready_heap, &(b->fs)); + purge_pipe(b); /* remove all data associated to this pipe */ + /* remove reference to here from extract_heap and wfq_ready_heap */ + pipe_remove_from_heap(&extract_heap, b); + pipe_remove_from_heap(&wfq_ready_heap, b); + splx(s); + FREE(b, M_IPFW); + } else { /* this is a WF2Q queue (dn_flow_set) */ + struct dn_flow_set *a, *b; + + /* locate set */ + for (a = NULL, b = all_flow_sets ; b && b->fs_nr < p->fs.fs_nr ; + a = b , b = b->next) ; + if (b == NULL || (b->fs_nr != p->fs.fs_nr) ) + return EINVAL ; /* not found */ + + s = splimp() ; + if (a == NULL) + all_flow_sets = b->next ; + else + a->next = b->next ; + /* remove references to this flow_set from the ip_fw rules. */ + LIST_FOREACH(chain, &ip_fw_chain_head, next) + if (chain->rule->pipe_ptr == b) + chain->rule->pipe_ptr = NULL ; + + if (b->pipe != NULL) { + /* Update total weight on parent pipe and cleanup parent heaps */ + b->pipe->sum -= b->weight * b->backlogged ; + fs_remove_from_heap(&(b->pipe->not_eligible_heap), b); + fs_remove_from_heap(&(b->pipe->scheduler_heap), b); +#if 1 /* XXX should i remove from idle_heap as well ? */ + fs_remove_from_heap(&(b->pipe->idle_heap), b); +#endif + } + purge_flow_set(b, 1); + splx(s); + } + return 0 ; +} + +/* + * helper function used to copy data from kernel in DUMMYNET_GET + */ +static char * +dn_copy_set(struct dn_flow_set *set, char *bp) +{ + int i, copied = 0 ; + struct dn_flow_queue *q, *qp = (struct dn_flow_queue *)bp; + + for (i = 0 ; i <= set->rq_size ; i++) + for (q = set->rq[i] ; q ; q = q->next, qp++ ) { + if (q->hash_slot != i) + printf("++ at %d: wrong slot (have %d, " + "should be %d)\n", copied, q->hash_slot, i); + if (q->fs != set) + printf("++ at %d: wrong fs ptr (have %p, should be %p)\n", + i, q->fs, set); + copied++ ; + bcopy(q, qp, sizeof( *q ) ); + /* cleanup pointers */ + qp->next = NULL ; + qp->head = qp->tail = NULL ; + qp->fs = NULL ; + } + if (copied != set->rq_elements) + printf("++ wrong count, have %d should be %d\n", + copied, set->rq_elements); + return (char *)qp ; +} static int -dummynet_load(struct lkm_table *lkmtp, int cmd) +dummynet_get(struct sockopt *sopt) { - int s=splnet(); - old_dn_ctl_ptr = ip_dn_ctl_ptr; - ip_dn_init(); + char *buf, *bp ; /* bp is the "copy-pointer" */ + size_t size ; + struct dn_flow_set *set ; + struct dn_pipe *p ; + int s, error=0 ; + + s = splimp(); + /* + * compute size of data structures: list of pipes and flow_sets. + */ + for (p = all_pipes, size = 0 ; p ; p = p->next ) + size += sizeof( *p ) + + p->fs.rq_elements * sizeof(struct dn_flow_queue); + for (set = all_flow_sets ; set ; set = set->next ) + size += sizeof ( *set ) + + set->rq_elements * sizeof(struct dn_flow_queue); + buf = _MALLOC(size, M_TEMP, M_DONTWAIT); + if (buf == 0) { splx(s); - return 0; + return ENOBUFS ; + } + for (p = all_pipes, bp = buf ; p ; p = p->next ) { + struct dn_pipe *pipe_bp = (struct dn_pipe *)bp ; + + /* + * copy pipe descriptor into *bp, convert delay back to ms, + * then copy the flow_set descriptor(s) one at a time. + * After each flow_set, copy the queue descriptor it owns. + */ + bcopy(p, bp, sizeof( *p ) ); + pipe_bp->delay = (pipe_bp->delay * 1000) / hz ; + /* + * XXX the following is a hack based on ->next being the + * first field in dn_pipe and dn_flow_set. The correct + * solution would be to move the dn_flow_set to the beginning + * of struct dn_pipe. + */ + pipe_bp->next = (struct dn_pipe *)DN_IS_PIPE ; + /* clean pointers */ + pipe_bp->head = pipe_bp->tail = NULL ; + pipe_bp->fs.next = NULL ; + pipe_bp->fs.pipe = NULL ; + pipe_bp->fs.rq = NULL ; + + bp += sizeof( *p ) ; + bp = dn_copy_set( &(p->fs), bp ); + } + for (set = all_flow_sets ; set ; set = set->next ) { + struct dn_flow_set *fs_bp = (struct dn_flow_set *)bp ; + bcopy(set, bp, sizeof( *set ) ); + /* XXX same hack as above */ + fs_bp->next = (struct dn_flow_set *)DN_IS_QUEUE ; + fs_bp->pipe = NULL ; + fs_bp->rq = NULL ; + bp += sizeof( *set ) ; + bp = dn_copy_set( set, bp ); + } + splx(s); + error = sooptcopyout(sopt, buf, size); + FREE(buf, M_TEMP); + return error ; } +/* + * Handler for the various dummynet socket options (get, flush, config, del) + */ static int -dummynet_unload(struct lkm_table *lkmtp, int cmd) +ip_dn_ctl(struct sockopt *sopt) { - int s=splnet(); - ip_dn_ctl_ptr = old_dn_ctl_ptr; - splx(s); - dummynet_flush(); - printf("DUMMYNET unloaded\n"); - return 0; + int error = 0 ; + struct dn_pipe *p, tmp_pipe; + + /* Disallow sets in really-really secure mode. */ + if (sopt->sopt_dir == SOPT_SET && securelevel >= 3) + return (EPERM); + + switch (sopt->sopt_name) { + default : + printf("ip_dn_ctl -- unknown option %d", sopt->sopt_name); + return EINVAL ; + + case IP_DUMMYNET_GET : + error = dummynet_get(sopt); + break ; + + case IP_DUMMYNET_FLUSH : + dummynet_flush() ; + break ; + case IP_DUMMYNET_CONFIGURE : + p = &tmp_pipe ; + error = sooptcopyin(sopt, p, sizeof *p, sizeof *p); + if (error) + break ; + error = config_pipe(p); + break ; + + case IP_DUMMYNET_DEL : /* remove a pipe or queue */ + p = &tmp_pipe ; + error = sooptcopyin(sopt, p, sizeof *p, sizeof *p); + if (error) + break ; + + error = delete_pipe(p); + break ; + } + return error ; } -int -dummynet_mod(struct lkm_table *lkmtp, int cmd, int ver) +static void +ip_dn_init(void) { - DISPATCH(lkmtp, cmd, ver, dummynet_load, dummynet_unload, lkm_nullcmd); + printf("DUMMYNET initialized (010124)\n"); + all_pipes = NULL ; + all_flow_sets = NULL ; + ready_heap.size = ready_heap.elements = 0 ; + ready_heap.offset = 0 ; + + wfq_ready_heap.size = wfq_ready_heap.elements = 0 ; + wfq_ready_heap.offset = 0 ; + + extract_heap.size = extract_heap.elements = 0 ; + extract_heap.offset = 0 ; + ip_dn_ctl_ptr = ip_dn_ctl; + timeout(dummynet, NULL, 1); } -#endif + +static ip_dn_ctl_t *old_dn_ctl_ptr ; + +static int +dummynet_modevent(module_t mod, int type, void *data) +{ + int s ; + switch (type) { + case MOD_LOAD: + s = splimp(); + old_dn_ctl_ptr = ip_dn_ctl_ptr; + ip_dn_init(); + splx(s); + break; + case MOD_UNLOAD: + s = splimp(); + ip_dn_ctl_ptr = old_dn_ctl_ptr; + splx(s); + dummynet_flush(); + break ; + default: + break ; + } + return 0 ; +} + +static moduledata_t dummynet_mod = { + "dummynet", + dummynet_modevent, + NULL +} ; +DECLARE_MODULE(dummynet, dummynet_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); diff --git a/bsd/netinet/ip_dummynet.h b/bsd/netinet/ip_dummynet.h index 312eb5b8b..9a13ae239 100644 --- a/bsd/netinet/ip_dummynet.h +++ b/bsd/netinet/ip_dummynet.h @@ -31,105 +31,336 @@ * * This software is provided ``AS IS'' without any warranties of any kind. * + * $FreeBSD: src/sys/netinet/ip_dummynet.h,v 1.10.2.3 2001/02/01 20:25:09 luigi Exp $ */ #ifndef _IP_DUMMYNET_H #define _IP_DUMMYNET_H +#include +#ifdef __APPLE_API_PRIVATE /* - * Definition of dummynet data structures. - * Dummynet handles a list of pipes, each one identified by a unique - * number (hopefully the list is short so we use a linked list). + * Definition of dummynet data structures. In the structures, I decided + * not to use the macros in in the hope of making the code + * easier to port to other architectures. The type of lists and queue we + * use here is pretty simple anyways. + */ + +/* + * We start with a heap, which is used in the scheduler to decide when + * to transmit packets etc. * - * Each list contains a set of parameters identifying the pipe, and - * a set of packets queued on the pipe itself. + * The key for the heap is used for two different values: * - * I could have used queue macros, but the management i have - * is pretty simple and this makes the code more portable. + * 1. timer ticks- max 10K/second, so 32 bits are enough; + * + * 2. virtual times. These increase in steps of len/x, where len is the + * packet length, and x is either the weight of the flow, or the + * sum of all weights. + * If we limit to max 1000 flows and a max weight of 100, then + * x needs 17 bits. The packet size is 16 bits, so we can easily + * overflow if we do not allow errors. + * So we use a key "dn_key" which is 64 bits. Some macros are used to + * compare key values and handle wraparounds. + * MAX64 returns the largest of two key values. + * MY_M is used as a shift count when doing fixed point arithmetic + * (a better name would be useful...). + */ +typedef u_int64_t dn_key ; /* sorting key */ +#define DN_KEY_LT(a,b) ((int64_t)((a)-(b)) < 0) +#define DN_KEY_LEQ(a,b) ((int64_t)((a)-(b)) <= 0) +#define DN_KEY_GT(a,b) ((int64_t)((a)-(b)) > 0) +#define DN_KEY_GEQ(a,b) ((int64_t)((a)-(b)) >= 0) +#define MAX64(x,y) (( (int64_t) ( (y)-(x) )) > 0 ) ? (y) : (x) +#define MY_M 16 /* number of left shift to obtain a larger precision */ + +/* + * XXX With this scaling, max 1000 flows, max weight 100, 1Gbit/s, the + * virtual time wraps every 15 days. + */ + +/* + * The OFFSET_OF macro is used to return the offset of a field within + * a structure. It is used by the heap management routines. + */ +#define OFFSET_OF(type, field) ((int)&( ((type *)0)->field) ) + +/* + * A heap entry is made of a key and a pointer to the actual + * object stored in the heap. + * The heap is an array of dn_heap_entry entries, dynamically allocated. + * Current size is "size", with "elements" actually in use. + * The heap normally supports only ordered insert and extract from the top. + * If we want to extract an object from the middle of the heap, we + * have to know where the object itself is located in the heap (or we + * need to scan the whole array). To this purpose, an object has a + * field (int) which contains the index of the object itself into the + * heap. When the object is moved, the field must also be updated. + * The offset of the index in the object is stored in the 'offset' + * field in the heap descriptor. The assumption is that this offset + * is non-zero if we want to support extract from the middle. + */ +struct dn_heap_entry { + dn_key key ; /* sorting key. Topmost element is smallest one */ + void *object ; /* object pointer */ +} ; + +struct dn_heap { + int size ; + int elements ; + int offset ; /* XXX if > 0 this is the offset of direct ptr to obj */ + struct dn_heap_entry *p ; /* really an array of "size" entries */ +} ; + +/* + * MT_DUMMYNET is a new (fake) mbuf type that is prepended to the + * packet when it comes out of a pipe. The definition + * ought to go in /sys/sys/mbuf.h but here it is less intrusive. */ +#define MT_DUMMYNET MT_CONTROL + /* * struct dn_pkt identifies a packet in the dummynet queue. The * first part is really an m_hdr for implementation purposes, and some * fields are saved there. When passing the packet back to the ip_input/ - * ip_output(), the struct is prepended to the mbuf chain with type + * ip_output()/bdg_forward, the struct is prepended to the mbuf chain with type * MT_DUMMYNET, and contains the pointer to the matching rule. + * + * Note: there is no real need to make this structure contain an m_hdr, + * in the future this should be changed to a normal data structure. */ struct dn_pkt { struct m_hdr hdr ; #define dn_next hdr.mh_nextpkt /* next element in queue */ +#define DN_NEXT(x) (struct dn_pkt *)(x)->dn_next #define dn_m hdr.mh_next /* packet to be forwarded */ -#define dn_hlen hdr.mh_len /* hlen, for ip_output */ -#define dn_dir hdr.mh_flags /* IP_FW_F_IN or IP_FW_F_OUT */ - int delay; /* stays queued until delay=0 */ +#define dn_dir hdr.mh_flags /* action when pkt extracted from a queue */ +#define DN_TO_IP_OUT 1 +#define DN_TO_IP_IN 2 +#define DN_TO_BDG_FWD 3 + + dn_key output_time; /* when the pkt is due for delivery */ struct ifnet *ifp; /* interface, for ip_output */ + struct sockaddr_in *dn_dst ; struct route ro; /* route, for ip_output. MUST COPY */ - -#if DUMMYNET_DEBUG - struct timeval beg, mid; /* testing only */ - int act_delay; /* testing only */ - int in_delay; /* testing only */ -#endif + int flags ; /* flags, for ip_output (IPv6 ?) */ }; -struct dn_queue { - struct dn_pkt *head, *tail; +/* + * Overall structure of dummynet (with WF2Q+): + +In dummynet, packets are selected with the firewall rules, and passed +to two different objects: PIPE or QUEUE. + +A QUEUE is just a queue with configurable size and queue management +policy. It is also associated with a mask (to discriminate among +different flows), a weight (used to give different shares of the +bandwidth to different flows) and a "pipe", which essentially +supplies the transmit clock for all queues associated with that +pipe. + +A PIPE emulates a fixed-bandwidth link, whose bandwidth is +configurable. The "clock" for a pipe can come from either an +internal timer, or from the transmit interrupt of an interface. +A pipe is also associated with one (or more, if masks are used) +queue, where all packets for that pipe are stored. + +The bandwidth available on the pipe is shared by the queues +associated with that pipe (only one in case the packet is sent +to a PIPE) according to the WF2Q+ scheduling algorithm and the +configured weights. + +In general, incoming packets are stored in the appropriate queue, +which is then placed into one of a few heaps managed by a scheduler +to decide when the packet should be extracted. +The scheduler (a function called dummynet()) is run at every timer +tick, and grabs queues from the head of the heaps when they are +ready for processing. + +There are three data structures definining a pipe and associated queues: + + + dn_pipe, which contains the main configuration parameters related + to delay and bandwidth; + + dn_flow_set, which contains WF2Q+ configuration, flow + masks, plr and RED configuration; + + dn_flow_queue, which is the per-flow queue (containing the packets) + +Multiple dn_flow_set can be linked to the same pipe, and multiple +dn_flow_queue can be linked to the same dn_flow_set. +All data structures are linked in a linear list which is used for +housekeeping purposes. + +During configuration, we create and initialize the dn_flow_set +and dn_pipe structures (a dn_pipe also contains a dn_flow_set). + +At runtime: packets are sent to the appropriate dn_flow_set (either +WFQ ones, or the one embedded in the dn_pipe for fixed-rate flows), +which in turn dispatches them to the appropriate dn_flow_queue +(created dynamically according to the masks). + +The transmit clock for fixed rate flows (ready_event()) selects the +dn_flow_queue to be used to transmit the next packet. For WF2Q, +wfq_ready_event() extract a pipe which in turn selects the right +flow using a number of heaps defined into the pipe itself. + + * + */ + +/* + * per flow queue. This contains the flow identifier, the queue + * of packets, counters, and parameters used to support both RED and + * WF2Q+. + */ +struct dn_flow_queue { + struct dn_flow_queue *next ; + struct ipfw_flow_id id ; + struct dn_pkt *head, *tail ; /* queue of packets */ + u_int len ; + u_int len_bytes ; + long numbytes ; /* credit for transmission (dynamic queues) */ + + u_int64_t tot_pkts ; /* statistics counters */ + u_int64_t tot_bytes ; + u_int32_t drops ; + int hash_slot ; /* debugging/diagnostic */ + + /* RED parameters */ + int avg ; /* average queue length est. (scaled) */ + int count ; /* arrivals since last RED drop */ + int random ; /* random value (scaled) */ + u_int32_t q_time ; /* start of queue idle time */ + + /* WF2Q+ support */ + struct dn_flow_set *fs ; /* parent flow set */ + int heap_pos ; /* position (index) of struct in heap */ + dn_key sched_time ; /* current time when queue enters ready_heap */ + + dn_key S,F ; /* start-time, finishing time */ + /* setting F < S means the timestamp is invalid. We only need + * to test this when the queue is empty. + */ } ; /* - * descriptor of a pipe. The flags field will be used to speed up the - * forwarding code paths, in case some of the parameters are not - * used. + * flow_set descriptor. Contains the "template" parameters for the + * queue configuration, and pointers to the hash table of dn_flow_queue's. + * + * The hash table is an array of lists -- we identify the slot by + * hashing the flow-id, then scan the list looking for a match. + * The size of the hash table (buckets) is configurable on a per-queue + * basis. + */ +struct dn_flow_set { + struct dn_flow_set *next; /* next flow set in all_flow_sets list */ + + u_short fs_nr ; /* flow_set number */ + u_short flags_fs; +#define DN_HAVE_FLOW_MASK 0x0001 +#define DN_IS_PIPE 0x4000 +#define DN_IS_QUEUE 0x8000 +#define DN_IS_RED 0x0002 +#define DN_IS_GENTLE_RED 0x0004 +#define DN_QSIZE_IS_BYTES 0x0008 /* queue measured in bytes */ + + struct dn_pipe *pipe ; /* pointer to parent pipe */ + u_short parent_nr ; /* parent pipe#, 0 if local to a pipe */ + + int weight ; /* WFQ queue weight */ + int qsize ; /* queue size in slots or bytes */ + int plr ; /* pkt loss rate (2^31-1 means 100%) */ + + struct ipfw_flow_id flow_mask ; + /* hash table of queues onto this flow_set */ + int rq_size ; /* number of slots */ + int rq_elements ; /* active elements */ + struct dn_flow_queue **rq; /* array of rq_size entries */ + u_int32_t last_expired ; /* do not expire too frequently */ + /* XXX some RED parameters as well ? */ + int backlogged ; /* #active queues for this flowset */ + + /* RED parameters */ +#define SCALE_RED 16 +#define SCALE(x) ( (x) << SCALE_RED ) +#define SCALE_VAL(x) ( (x) >> SCALE_RED ) +#define SCALE_MUL(x,y) ( ( (x) * (y) ) >> SCALE_RED ) + int w_q ; /* queue weight (scaled) */ + int max_th ; /* maximum threshold for queue (scaled) */ + int min_th ; /* minimum threshold for queue (scaled) */ + int max_p ; /* maximum value for p_b (scaled) */ + u_int c_1 ; /* max_p/(max_th-min_th) (scaled) */ + u_int c_2 ; /* max_p*min_th/(max_th-min_th) (scaled) */ + u_int c_3 ; /* for GRED, (1-max_p)/max_th (scaled) */ + u_int c_4 ; /* for GRED, 1 - 2*max_p (scaled) */ + u_int * w_q_lookup ; /* lookup table for computing (1-w_q)^t */ + u_int lookup_depth ; /* depth of lookup table */ + int lookup_step ; /* granularity inside the lookup table */ + int lookup_weight ; /* equal to (1-w_q)^t / (1-w_q)^(t+1) */ + int avg_pkt_size ; /* medium packet size */ + int max_pkt_size ; /* max packet size */ +} ; + +/* + * Pipe descriptor. Contains global parameters, delay-line queue, + * and the flow_set used for fixed-rate queues. + * + * For WF2Q support it also has 4 heaps holding dn_flow_queue: + * not_eligible_heap, for queues whose start time is higher + * than the virtual time. Sorted by start time. + * scheduler_heap, for queues eligible for scheduling. Sorted by + * finish time. + * backlogged_heap, all flows in the two heaps above, sorted by + * start time. This is used to compute the virtual time. + * idle_heap, all flows that are idle and can be removed. We + * do that on each tick so we do not slow down too much + * operations during forwarding. + * */ struct dn_pipe { /* a pipe */ struct dn_pipe *next ; - u_short pipe_nr ; /* number */ - u_short flags ; /* to speed up things */ -#define DN_HAVE_BW 1 -#define DN_HAVE_QUEUE 2 -#define DN_HAVE_DELAY 4 + int pipe_nr ; /* number */ int bandwidth; /* really, bytes/tick. */ - int queue_size ; - int queue_size_bytes ; int delay ; /* really, ticks */ - int plr ; /* pkt loss rate (2^31-1 means 100%) */ - - struct dn_queue r; - int r_len; /* elements in r_queue */ - int r_len_bytes; /* bytes in r_queue */ - int r_drops; /* drops from r_queue */ - struct dn_queue p ; - int ticks_from_last_insert; - long numbytes; /* which can send or receive */ -}; -/* - * The following is used to define a new mbuf type that is - * prepended to the packet when it comes out of a pipe. The definition - * ought to go in /sys/sys/mbuf.h but here it is less intrusive. - */ + struct dn_pkt *head, *tail ; /* packets in delay line */ -#define MT_DUMMYNET MT_CONTROL -/* - * what to do of a packet when it comes out of a pipe - */ -#define DN_TO_IP_OUT 1 -#define DN_TO_IP_IN 2 -#define DN_TO_BDG_FWD 3 + /* WF2Q+ */ + struct dn_heap scheduler_heap ; /* top extract - key Finish time*/ + struct dn_heap not_eligible_heap; /* top extract- key Start time */ + struct dn_heap idle_heap ; /* random extract - key Start=Finish time */ + + dn_key V ; /* virtual time */ + int sum; /* sum of weights of all active sessions */ + int numbytes; /* bit i can transmit (more or less). */ + + dn_key sched_time ; /* first time pipe is scheduled in ready_heap */ -#if KERNEL + /* the tx clock can come from an interface. In this case, the + * name is below, and the pointer is filled when the rule is + * configured. We identify this by setting the if_name to a + * non-empty string. + */ + char if_name[16]; + struct ifnet *ifp ; + int ready ; /* set if ifp != NULL and we got a signal from it */ + + struct dn_flow_set fs ; /* used with fixed-rate flows */ +}; + +#ifdef KERNEL MALLOC_DECLARE(M_IPFW); typedef int ip_dn_ctl_t __P((struct sockopt *)) ; extern ip_dn_ctl_t *ip_dn_ctl_ptr; -void ip_dn_init(void); /* called in ip_input.c */ void dn_rule_delete(void *r); /* used in ip_fw.c */ int dummynet_io(int pipe, int dir, - struct mbuf *m, struct ifnet *ifp, struct route *ro, int hlen, - struct ip_fw_chain *rule); -#endif /* KERNEL */ + struct mbuf *m, struct ifnet *ifp, struct route *ro, + struct sockaddr_in * dst, + struct ip_fw_chain *rule, int flags); +#endif +#endif /* __APPLE_API_PRIVATE */ #endif /* _IP_DUMMYNET_H */ diff --git a/bsd/netinet/ip_ecn.c b/bsd/netinet/ip_ecn.c index 33211a3d5..2dfc497e8 100644 --- a/bsd/netinet/ip_ecn.c +++ b/bsd/netinet/ip_ecn.c @@ -22,7 +22,7 @@ /* * Copyright (C) 1999 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -34,7 +34,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -47,51 +47,43 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: ip_ecn.c,v 1.3 2000/11/22 01:12:12 zarzycki Exp $ */ /* * ECN consideration on tunnel ingress/egress operation. * http://www.aciri.org/floyd/papers/draft-ipsec-ecn-00.txt */ -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -#include "opt_inet.h" -#endif - #include #include #include #include #include -#if INET #include #include #include -#endif - #if INET6 -#ifndef INET -#include -#endif #include #endif #include +#if INET6 +#include +#endif /* * modify outer ECN (TOS) field on ingress operation (tunnel encapsulation). - * call it after you've done the default initialization/copy for the outer. */ void ip_ecn_ingress(mode, outer, inner) int mode; u_int8_t *outer; - u_int8_t *inner; + const u_int8_t *inner; { if (!outer || !inner) panic("NULL pointer passed to ip_ecn_ingress"); + *outer = *inner; switch (mode) { case ECN_ALLOWED: /* ECN allowed */ *outer &= ~IPTOS_CE; @@ -106,12 +98,11 @@ ip_ecn_ingress(mode, outer, inner) /* * modify inner ECN (TOS) field on egress operation (tunnel decapsulation). - * call it after you've done the default initialization/copy for the inner. */ void ip_ecn_egress(mode, outer, inner) int mode; - u_int8_t *outer; + const u_int8_t *outer; u_int8_t *inner; { if (!outer || !inner) @@ -133,14 +124,13 @@ void ip6_ecn_ingress(mode, outer, inner) int mode; u_int32_t *outer; - u_int32_t *inner; + const u_int32_t *inner; { u_int8_t outer8, inner8; if (!outer || !inner) panic("NULL pointer passed to ip6_ecn_ingress"); - outer8 = (ntohl(*outer) >> 20) & 0xff; inner8 = (ntohl(*inner) >> 20) & 0xff; ip_ecn_ingress(mode, &outer8, &inner8); *outer &= ~htonl(0xff << 20); @@ -150,7 +140,7 @@ ip6_ecn_ingress(mode, outer, inner) void ip6_ecn_egress(mode, outer, inner) int mode; - u_int32_t *outer; + const u_int32_t *outer; u_int32_t *inner; { u_int8_t outer8, inner8; @@ -159,7 +149,6 @@ ip6_ecn_egress(mode, outer, inner) panic("NULL pointer passed to ip6_ecn_egress"); outer8 = (ntohl(*outer) >> 20) & 0xff; - inner8 = (ntohl(*inner) >> 20) & 0xff; ip_ecn_egress(mode, &outer8, &inner8); *inner &= ~htonl(0xff << 20); *inner |= htonl((u_int32_t)inner8 << 20); diff --git a/bsd/netinet/ip_ecn.h b/bsd/netinet/ip_ecn.h index 4b3e143a6..4aa2132c5 100644 --- a/bsd/netinet/ip_ecn.h +++ b/bsd/netinet/ip_ecn.h @@ -22,7 +22,7 @@ /* * Copyright (C) 1999 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -34,7 +34,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -47,22 +47,20 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: ip_ecn.h,v 1.3 2000/11/22 01:12:12 zarzycki Exp $ */ /* * ECN consideration on tunnel ingress/egress operation. * http://www.aciri.org/floyd/papers/draft-ipsec-ecn-00.txt */ +#include #define ECN_ALLOWED 1 /* ECN allowed */ #define ECN_FORBIDDEN 0 /* ECN forbidden */ #define ECN_NOCARE (-1) /* no consideration to ECN */ -#if defined(KERNEL) || defined(_KERNEL) -extern void ip_ecn_ingress __P((int, u_int8_t *, u_int8_t *)); -extern void ip_ecn_egress __P((int, u_int8_t *, u_int8_t *)); -#ifdef INET6 -extern void ip6_ecn_ingress __P((int, u_int32_t *, u_int32_t *)); -extern void ip6_ecn_egress __P((int, u_int32_t *, u_int32_t *)); -#endif +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE +extern void ip_ecn_ingress __P((int, u_int8_t *, const u_int8_t *)); +extern void ip_ecn_egress __P((int, const u_int8_t *, u_int8_t *)); +#endif /* __APPLE_API_PRIVATE */ #endif diff --git a/bsd/netinet/ip_encap.c b/bsd/netinet/ip_encap.c index 0fae46c85..e4c9c7c9b 100644 --- a/bsd/netinet/ip_encap.c +++ b/bsd/netinet/ip_encap.c @@ -19,7 +19,8 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* $KAME: ip_encap.c,v 1.21 2000/03/30 14:30:06 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet/ip_encap.c,v 1.1.2.2 2001/07/03 11:01:46 ume Exp $ */ +/* $KAME: ip_encap.c,v 1.41 2001/03/15 08:35:08 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -62,7 +63,8 @@ * mobile-ip6 (uses RFC2473) * 6to4 tunnel * Here's a list of protocol that want protocol #4: - * RFC1853 IPv4-in-IPv4 tunnel + * RFC1853 IPv4-in-IPv4 tunnelling + * RFC2003 IPv4 encapsulation within IPv4 * RFC2344 reverse tunnelling for mobile-ip4 * RFC2401 IPsec tunnel * Well, what can I say. They impose different en/decapsulation mechanism @@ -73,21 +75,7 @@ * So, clearly good old protosw does not work for protocol #4 and #41. * The code will let you match protocol via src/dst address pair. */ - -#ifdef __FreeBSD__ -# include "opt_mrouting.h" -# if __FreeBSD__ == 3 -# include "opt_inet.h" -# endif -# if __FreeBSD__ >= 4 -# include "opt_inet.h" -# include "opt_inet6.h" -# endif -#else -# ifdef __NetBSD__ -# include "opt_inet.h" -# endif -#endif +/* XXX is M_NETADDR correct? */ #include #include @@ -96,7 +84,7 @@ #include #include #include -#include +#include #include #include @@ -109,9 +97,6 @@ #if MROUTING #include #endif /* MROUTING */ -#ifdef __OpenBSD__ -#include -#endif #if INET6 #include @@ -122,26 +107,36 @@ #include -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#ifndef __APPLE__ #include #include MALLOC_DEFINE(M_NETADDR, "Export Host", "Export host address structure"); #endif +static void encap_add __P((struct encaptab *)); static int mask_match __P((const struct encaptab *, const struct sockaddr *, const struct sockaddr *)); static void encap_fillarg __P((struct mbuf *, const struct encaptab *)); +#ifndef LIST_HEAD_INITIALIZER /* rely upon BSS initialization */ LIST_HEAD(, encaptab) encaptab; +#else +LIST_HEAD(, encaptab) encaptab = LIST_HEAD_INITIALIZER(&encaptab); +#endif void encap_init() { + static int initialized = 0; + + if (initialized) + return; + initialized++; #if 0 /* * we cannot use LIST_INIT() here, since drivers may want to call - * encap_attach(), on driver attach. encap_init() wlil be called + * encap_attach(), on driver attach. encap_init() will be called * on AF_INET{,6} initialization, which happens after driver * initialization - using LIST_INIT() here can nuke encap_attach() * from drivers. @@ -150,19 +145,28 @@ encap_init() #endif } +#if INET void -encap4_input(m, off, proto) +encap4_input(m, off) struct mbuf *m; int off; - int proto; { + int proto; struct ip *ip; struct sockaddr_in s, d; - struct encaptab *ep; - + const struct protosw *psw; + struct encaptab *ep, *match; + int prio, matchprio; + +#ifndef __APPLE__ + va_start(ap, m); + off = va_arg(ap, int); + proto = va_arg(ap, int); + va_end(ap); +#endif ip = mtod(m, struct ip *); -#ifdef __OpenBSD__ +#ifdef __APPLE__ proto = ip->ip_p; #endif @@ -175,66 +179,94 @@ encap4_input(m, off, proto) d.sin_len = sizeof(struct sockaddr_in); d.sin_addr = ip->ip_dst; + match = NULL; + matchprio = 0; for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) { + if (ep->af != AF_INET) + continue; if (ep->proto >= 0 && ep->proto != proto) continue; - - if (ep->func) { - if ((*ep->func)(m, off, proto, ep->arg) == 0) - continue; - } else { + if (ep->func) + prio = (*ep->func)(m, off, proto, ep->arg); + else { /* * it's inbound traffic, we need to match in reverse * order */ - if (mask_match(ep, (struct sockaddr *)&d, - (struct sockaddr *)&s) == 0) - continue; + prio = mask_match(ep, (struct sockaddr *)&d, + (struct sockaddr *)&s); } - /* found a match */ - if (ep->psw && ep->psw->pr_input) { - encap_fillarg(m, ep); -#warning watchout pr_input! - (*ep->psw->pr_input)(m, off); + /* + * We prioritize the matches by using bit length of the + * matches. mask_match() and user-supplied matching function + * should return the bit length of the matches (for example, + * if both src/dst are matched for IPv4, 64 should be returned). + * 0 or negative return value means "it did not match". + * + * The question is, since we have two "mask" portion, we + * cannot really define total order between entries. + * For example, which of these should be preferred? + * mask_match() returns 48 (32 + 16) for both of them. + * src=3ffe::/16, dst=3ffe:501::/32 + * src=3ffe:501::/32, dst=3ffe::/16 + * + * We need to loop through all the possible candidates + * to get the best match - the search takes O(n) for + * n attachments (i.e. interfaces). + */ + if (prio <= 0) + continue; + if (prio > matchprio) { + matchprio = prio; + match = ep; + } + } + + if (match) { + /* found a match, "match" has the best one */ + psw = (const struct protosw *)match->psw; + if (psw && psw->pr_input) { + encap_fillarg(m, match); + (*psw->pr_input)(m, off); } else m_freem(m); return; } /* for backward compatibility */ +# if MROUTING +# define COMPATFUNC ipip_input +# endif /*MROUTING*/ + +#if COMPATFUNC if (proto == IPPROTO_IPV4) { -#ifdef __OpenBSD__ -#if defined(MROUTING) || defined(IPSEC) - ip4_input(m, off, proto); - return; -#endif -#else -#if MROUTING - ipip_input(m, off); + COMPATFUNC(m, off); return; -#endif /*MROUTING*/ -#endif } +#endif /* last resort: inject to raw socket */ rip_input(m, off); } +#endif #if INET6 int -encap6_input(mp, offp, proto) +encap6_input(mp, offp) struct mbuf **mp; int *offp; - int proto; { struct mbuf *m = *mp; struct ip6_hdr *ip6; struct sockaddr_in6 s, d; - struct ip6protosw *psw; - struct encaptab *ep; + const struct ip6protosw *psw; + struct encaptab *ep, *match; + int prio, matchprio; + int proto; ip6 = mtod(m, struct ip6_hdr *); + proto = ip6->ip6_nxt; bzero(&s, sizeof(s)); s.sin6_family = AF_INET6; @@ -245,28 +277,39 @@ encap6_input(mp, offp, proto) d.sin6_len = sizeof(struct sockaddr_in6); d.sin6_addr = ip6->ip6_dst; + match = NULL; + matchprio = 0; for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) { + if (ep->af != AF_INET6) + continue; if (ep->proto >= 0 && ep->proto != proto) continue; - if (ep->func) { - if ((*ep->func)(m, *offp, proto, ep->arg) == 0) - continue; - } else { + if (ep->func) + prio = (*ep->func)(m, *offp, proto, ep->arg); + else { /* * it's inbound traffic, we need to match in reverse * order */ - if (mask_match(ep, (struct sockaddr *)&d, - (struct sockaddr *)&s) == 0) - continue; + prio = mask_match(ep, (struct sockaddr *)&d, + (struct sockaddr *)&s); + } + + /* see encap4_input() for issues here */ + if (prio <= 0) + continue; + if (prio > matchprio) { + matchprio = prio; + match = ep; } + } + if (match) { /* found a match */ - psw = (struct ip6protosw *)ep->psw; -#warning watchout pr_input! + psw = (const struct ip6protosw *)match->psw; if (psw && psw->pr_input) { - encap_fillarg(m, ep); - return (*psw->pr_input)(mp, offp, proto); + encap_fillarg(m, match); + return (*psw->pr_input)(mp, offp); } else { m_freem(m); return IPPROTO_DONE; @@ -274,10 +317,18 @@ encap6_input(mp, offp, proto) } /* last resort: inject to raw socket */ - return rip6_input(mp, offp, proto); + return rip6_input(mp, offp); } #endif +static void +encap_add(ep) + struct encaptab *ep; +{ + + LIST_INSERT_HEAD(&encaptab, ep, chain); +} + /* * sp (src ptr) is always my side, and dp (dst ptr) is always remote side. * length of mask (sm and dm) is assumed to be same as sp/dp. @@ -296,11 +347,7 @@ encap_attach(af, proto, sp, sm, dp, dm, psw, arg) int error; int s; -#if defined(__NetBSD__) || defined(__OpenBSD__) - s = splsoftnet(); -#else s = splnet(); -#endif /* sanity check on args */ if (sp->sa_len > sizeof(ep->src) || dp->sa_len > sizeof(ep->dst)) { error = EINVAL; @@ -334,7 +381,7 @@ encap_attach(af, proto, sp, sm, dp, dm, psw, arg) goto fail; } - ep = _MALLOC(sizeof(*ep), M_NETADDR, M_NOWAIT); /*XXX*/ + ep = _MALLOC(sizeof(*ep), M_NETADDR, M_WAITOK); /*XXX*/ if (ep == NULL) { error = ENOBUFS; goto fail; @@ -350,18 +397,8 @@ encap_attach(af, proto, sp, sm, dp, dm, psw, arg) ep->psw = psw; ep->arg = arg; - /* - * Order of insertion will determine the priority in lookup. - * We should be careful putting them in specific-one-first order. - * The question is, since we have two "mask" portion, we cannot really - * define total order between entries. - * For example, which of these should be preferred? - * src=3ffe::/16, dst=3ffe:501::/32 - * src=3ffe:501::/32, dst=3ffe::/16 - * - * At this moment we don't care about the ordering. - */ - LIST_INSERT_HEAD(&encaptab, ep, chain); + encap_add(ep); + error = 0; splx(s); return ep; @@ -383,18 +420,14 @@ encap_attach_func(af, proto, func, psw, arg) int error; int s; -#if defined(__NetBSD__) || defined(__OpenBSD__) - s = splsoftnet(); -#else s = splnet(); -#endif /* sanity check on args */ if (!func) { error = EINVAL; goto fail; } - ep = _MALLOC(sizeof(*ep), M_NETADDR, M_NOWAIT); /*XXX*/ + ep = _MALLOC(sizeof(*ep), M_NETADDR, M_WAITOK); /*XXX*/ if (ep == NULL) { error = ENOBUFS; goto fail; @@ -407,18 +440,8 @@ encap_attach_func(af, proto, func, psw, arg) ep->psw = psw; ep->arg = arg; - /* - * Order of insertion will determine the priority in lookup. - * We should be careful putting them in specific-one-first order. - * The question is, since we have two "mask" portion, we cannot really - * define total order between entries. - * For example, which of these should be checked first? - * src=3ffe::/16, dst=3ffe:501::/32 - * src=3ffe:501::/32, dst=3ffe::/16 - * - * At this moment we don't care about the ordering. - */ - LIST_INSERT_HEAD(&encaptab, ep, chain); + encap_add(ep); + error = 0; splx(s); return ep; @@ -455,7 +478,9 @@ mask_match(ep, sp, dp) struct sockaddr_storage s; struct sockaddr_storage d; int i; - u_int8_t *p, *q, *r; + const u_int8_t *p, *q; + u_int8_t *r; + int matchlen; if (sp->sa_len > sizeof(s) || dp->sa_len > sizeof(d)) return 0; @@ -464,17 +489,25 @@ mask_match(ep, sp, dp) if (sp->sa_len != ep->src.ss_len || dp->sa_len != ep->dst.ss_len) return 0; - p = (u_int8_t *)sp; - q = (u_int8_t *)&ep->srcmask; + matchlen = 0; + + p = (const u_int8_t *)sp; + q = (const u_int8_t *)&ep->srcmask; r = (u_int8_t *)&s; - for (i = 0 ; i < sp->sa_len; i++) + for (i = 0 ; i < sp->sa_len; i++) { r[i] = p[i] & q[i]; + /* XXX estimate */ + matchlen += (q[i] ? 8 : 0); + } - p = (u_int8_t *)dp; - q = (u_int8_t *)&ep->dstmask; + p = (const u_int8_t *)dp; + q = (const u_int8_t *)&ep->dstmask; r = (u_int8_t *)&d; - for (i = 0 ; i < dp->sa_len; i++) + for (i = 0 ; i < dp->sa_len; i++) { r[i] = p[i] & q[i]; + /* XXX rough estimate */ + matchlen += (q[i] ? 8 : 0); + } /* need to overwrite len/family portion as we don't compare them */ s.ss_len = sp->sa_len; @@ -484,7 +517,7 @@ mask_match(ep, sp, dp) if (bcmp(&s, &ep->src, ep->src.ss_len) == 0 && bcmp(&d, &ep->dst, ep->dst.ss_len) == 0) { - return 1; + return matchlen; } else return 0; } diff --git a/bsd/netinet/ip_encap.h b/bsd/netinet/ip_encap.h index c795d55c0..a1c472e22 100644 --- a/bsd/netinet/ip_encap.h +++ b/bsd/netinet/ip_encap.h @@ -52,8 +52,10 @@ #ifndef _NETINET_IP_ENCAP_H_ #define _NETINET_IP_ENCAP_H_ +#include -#if KERNEL +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE struct encaptab { LIST_ENTRY(encaptab) chain; @@ -69,8 +71,8 @@ struct encaptab { }; void encap_init __P((void)); -void encap4_input __P((struct mbuf *, int, int)); -int encap6_input __P((struct mbuf **, int *, int)); +void encap4_input __P((struct mbuf *, int)); +int encap6_input __P((struct mbuf **, int *)); const struct encaptab *encap_attach __P((int, int, const struct sockaddr *, const struct sockaddr *, const struct sockaddr *, const struct sockaddr *, const struct protosw *, void *)); @@ -79,6 +81,7 @@ const struct encaptab *encap_attach_func __P((int, int, const struct protosw *, void *)); int encap_detach __P((const struct encaptab *)); void *encap_getarg __P((struct mbuf *)); +#endif /* __APPLE_API_PRIVATE */ #endif #endif /*_NETINET_IP_ENCAP_H_*/ diff --git a/bsd/netinet/ip_flow.c b/bsd/netinet/ip_flow.c index f95477801..8e0ac3cc5 100644 --- a/bsd/netinet/ip_flow.c +++ b/bsd/netinet/ip_flow.c @@ -54,6 +54,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * + * $FreeBSD: src/sys/netinet/ip_flow.c,v 1.9.2.1 2001/08/08 08:20:35 ru Exp $ */ #include @@ -84,16 +85,17 @@ static LIST_HEAD(ipflowhead, ipflow) ipflows[IPFLOW_HASHSIZE]; static int ipflow_inuse; #define IPFLOW_MAX 256 -#if ISFB31 -#else +#ifdef __APPLE__ #define M_IPFLOW M_TEMP #endif static int ipflow_active = 0; SYSCTL_INT(_net_inet_ip, IPCTL_FASTFORWARDING, fastforwarding, CTLFLAG_RW, - &ipflow_active, 0, ""); + &ipflow_active, 0, "Enable flow-based IP forwarding"); -MALLOC_DEFINE(M_IPFLOW, "ip_flow", "IP flow"); +#ifndef __APPLE__ +static MALLOC_DEFINE(M_IPFLOW, "ip_flow", "IP flow"); +#endif static unsigned ipflow_hash( @@ -135,6 +137,7 @@ ipflow_fastforward( struct ip *ip; struct ipflow *ipf; struct rtentry *rt; + struct sockaddr *dst; int error; /* @@ -185,8 +188,17 @@ ipflow_fastforward( ipf->ipf_uses++; ipf->ipf_timer = IPFLOW_TIMER; + if (rt->rt_flags & RTF_GATEWAY) + dst = rt->rt_gateway; + else + dst = &ipf->ipf_ro.ro_dst; +#ifdef __APPLE__ /* Not sure the rt_dlt is valid here !! XXX */ - if ((error = dlil_output((u_long)rt->rt_dlt, m, (caddr_t) rt, &ipf->ipf_ro.ro_dst, 0)) != 0) { + if ((error = dlil_output((u_long)rt->rt_dlt, m, (caddr_t) rt, dst, 0)) != 0) { + +#else + if ((error = (*rt->rt_ifp->if_output)(rt->rt_ifp, m, dst, rt)) != 0) { +#endif if (error == ENOBUFS) ipf->ipf_dropped++; else @@ -219,7 +231,7 @@ ipflow_free( LIST_REMOVE(ipf, ipf_next); splx(s); ipflow_addstats(ipf); - RTFREE(ipf->ipf_ro.ro_rt); + rtfree(ipf->ipf_ro.ro_rt); ipflow_inuse--; FREE(ipf, M_IPFLOW); } @@ -265,7 +277,7 @@ ipflow_reap( LIST_REMOVE(ipf, ipf_next); splx(s); ipflow_addstats(ipf); - RTFREE(ipf->ipf_ro.ro_rt); + rtfree(ipf->ipf_ro.ro_rt); return ipf; } @@ -331,7 +343,7 @@ ipflow_create( LIST_REMOVE(ipf, ipf_next); splx(s); ipflow_addstats(ipf); - RTFREE(ipf->ipf_ro.ro_rt); + rtfree(ipf->ipf_ro.ro_rt); ipf->ipf_uses = ipf->ipf_last_uses = 0; ipf->ipf_errors = ipf->ipf_dropped = 0; } @@ -340,7 +352,7 @@ ipflow_create( * Fill in the updated information. */ ipf->ipf_ro = *ro; - ro->ro_rt->rt_refcnt++; + rtref(ro->ro_rt); ipf->ipf_dst = ip->ip_dst; ipf->ipf_src = ip->ip_src; ipf->ipf_tos = ip->ip_tos; diff --git a/bsd/netinet/ip_flow.h b/bsd/netinet/ip_flow.h index 151b6ba32..23c25d366 100644 --- a/bsd/netinet/ip_flow.h +++ b/bsd/netinet/ip_flow.h @@ -54,11 +54,14 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * + * $FreeBSD: src/sys/netinet/ip_flow.h,v 1.2 1999/08/28 00:49:22 peter Exp $ */ #ifndef _NETINET_IP_FLOW_H #define _NETINET_IP_FLOW_H +#include +#ifdef __APPLE_API_PRIVATE struct ipflow { LIST_ENTRY(ipflow) ipf_next; /* next ipflow in bucket */ struct in_addr ipf_dst; /* destination address */ @@ -73,5 +76,6 @@ struct ipflow { u_long ipf_errors; /* other errors returned by if_output */ u_long ipf_last_uses; /* number of uses in last period */ }; +#endif /* __APPLE_API_PRIVATE */ #endif diff --git a/bsd/netinet/ip_ftp_pxy.c b/bsd/netinet/ip_ftp_pxy.c deleted file mode 100644 index 46152358a..000000000 --- a/bsd/netinet/ip_ftp_pxy.c +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Simple FTP transparent proxy for in-kernel use. For use with the NAT - * code. - */ - - -#define isdigit(x) ((x) >= '0' && (x) <= '9') - -#define IPF_FTP_PROXY - -#define IPF_MINPORTLEN 18 -#define IPF_MAXPORTLEN 30 - - -int ippr_ftp_init __P((fr_info_t *, ip_t *, tcphdr_t *, - ap_session_t *, nat_t *)); -int ippr_ftp_in __P((fr_info_t *, ip_t *, tcphdr_t *, - ap_session_t *, nat_t *)); -int ippr_ftp_out __P((fr_info_t *, ip_t *, tcphdr_t *, - ap_session_t *, nat_t *)); -u_short ipf_ftp_atoi __P((char **)); - - -/* - * FTP application proxy initialization. - */ -int ippr_ftp_init(fin, ip, tcp, aps, nat) -fr_info_t *fin; -ip_t *ip; -tcphdr_t *tcp; -ap_session_t *aps; -nat_t *nat; -{ - aps->aps_sport = tcp->th_sport; - aps->aps_dport = tcp->th_dport; - return 0; -} - - -int ippr_ftp_in(fin, ip, tcp, aps, nat) -fr_info_t *fin; -ip_t *ip; -tcphdr_t *tcp; -ap_session_t *aps; -nat_t *nat; -{ - u_32_t sum1, sum2; - short sel; - - if (tcp->th_sport == aps->aps_dport) { - sum2 = (u_32_t)ntohl(tcp->th_ack); - sel = aps->aps_sel; - if ((aps->aps_after[!sel] > aps->aps_after[sel]) && - (sum2 > aps->aps_after[!sel])) { - sel = aps->aps_sel = !sel; /* switch to other set */ - } - if (aps->aps_seqoff[sel] && (sum2 > aps->aps_after[sel])) { - sum1 = (u_32_t)aps->aps_seqoff[sel]; - tcp->th_ack = htonl(sum2 - sum1); - return 2; - } - } - return 0; -} - - -/* - * ipf_ftp_atoi - implement a version of atoi which processes numbers in - * pairs separated by commas (which are expected to be in the range 0 - 255), - * returning a 16 bit number combining either side of the , as the MSB and - * LSB. - */ -u_short ipf_ftp_atoi(ptr) -char **ptr; -{ - register char *s = *ptr, c; - register u_char i = 0, j = 0; - - while ((c = *s++) && isdigit(c)) { - i *= 10; - i += c - '0'; - } - if (c != ',') { - *ptr = NULL; - return 0; - } - while ((c = *s++) && isdigit(c)) { - j *= 10; - j += c - '0'; - } - *ptr = s; - return (i << 8) | j; -} - - -int ippr_ftp_out(fin, ip, tcp, aps, nat) -fr_info_t *fin; -ip_t *ip; -tcphdr_t *tcp; -ap_session_t *aps; -nat_t *nat; -{ - register u_32_t sum1, sum2; - char newbuf[IPF_MAXPORTLEN+1]; - char portbuf[IPF_MAXPORTLEN+1], *s; - int ch = 0, off = (ip->ip_hl << 2) + (tcp->th_off << 2); - u_int a1, a2, a3, a4; - u_short a5, a6; - int olen, dlen, nlen = 0, inc = 0; - tcphdr_t tcph, *tcp2 = &tcph; - void *savep; - nat_t *ipn; - struct in_addr swip; - mb_t *m = *(mb_t **)fin->fin_mp; - -#if SOLARIS - mb_t *m1; - - /* skip any leading M_PROTOs */ - while(m && (MTYPE(m) != M_DATA)) - m = m->b_cont; - PANIC((!m),("ippr_ftp_out: no M_DATA")); - - dlen = msgdsize(m) - off; - bzero(portbuf, sizeof(portbuf)); - copyout_mblk(m, off, MIN(sizeof(portbuf), dlen), portbuf); -#else - dlen = mbufchainlen(m) - off; - bzero(portbuf, sizeof(portbuf)); - m_copydata(m, off, MIN(sizeof(portbuf), dlen), portbuf); -#endif - portbuf[IPF_MAXPORTLEN] = '\0'; - - if ((dlen < IPF_MINPORTLEN) || strncmp(portbuf, "PORT ", 5)) - goto adjust_seqack; - - /* - * Skip the PORT command + space - */ - s = portbuf + 5; - /* - * Pick out the address components, two at a time. - */ - (void) ipf_ftp_atoi(&s); - if (!s) - goto adjust_seqack; - (void) ipf_ftp_atoi(&s); - if (!s) - goto adjust_seqack; - a5 = ipf_ftp_atoi(&s); - if (!s) - goto adjust_seqack; - /* - * check for CR-LF at the end. - */ - if (*s != '\n' || *(s - 1) != '\r') - goto adjust_seqack; - a6 = a5 & 0xff; - a5 >>= 8; - /* - * Calculate new address parts for PORT command - */ - a1 = ntohl(ip->ip_src.s_addr); - a2 = (a1 >> 16) & 0xff; - a3 = (a1 >> 8) & 0xff; - a4 = a1 & 0xff; - a1 >>= 24; - olen = s - portbuf + 1; - (void) snprintf(newbuf, sizeof(newbuf), "PORT %d,%d,%d,%d,%d,%d\r\n", - a1, a2, a3, a4, a5, a6); - nlen = strlen(newbuf); - inc = nlen - olen; -#if SOLARIS - for (m1 = m; m1->b_cont; m1 = m1->b_cont) - ; - if (inc > 0) { - mblk_t *nm; - - /* alloc enough to keep same trailer space for lower driver */ - nm = allocb(nlen + m1->b_datap->db_lim - m1->b_wptr, BPRI_MED); - PANIC((!nm),("ippr_ftp_out: allocb failed")); - - nm->b_band = m1->b_band; - nm->b_wptr += nlen; - - m1->b_wptr -= olen; - PANIC((m1->b_wptr < m1->b_rptr),("ippr_ftp_out: cannot handle fragmented data block")); - - linkb(m1, nm); - } else { - m1->b_wptr += inc; - } - copyin_mblk(m, off, nlen, newbuf); -#else - if (inc < 0) - m_adj(m, inc); - /* the mbuf chain will be extended if necessary by m_copyback() */ - m_copyback(m, off, nlen, newbuf); -#endif - if (inc) { -#if SOLARIS || defined(__sgi) - sum1 = ip->ip_len; - sum2 = ip->ip_len + inc; - - /* Because ~1 == -2, We really need ~1 == -1 */ - if (sum1 > sum2) - sum2--; - sum2 -= sum1; - sum2 = (sum2 & 0xffff) + (sum2 >> 16); - - fix_outcksum(&ip->ip_sum, sum2); -#endif - ip->ip_len += inc; - } - ch = 1; - - /* - * Add skeleton NAT entry for connection which will come back the - * other way. - */ - savep = fin->fin_dp; - fin->fin_dp = (char *)tcp2; - bzero((char *)tcp2, sizeof(*tcp2)); - tcp2->th_sport = htons(a5 << 8 | a6); - tcp2->th_dport = htons(20); - swip = ip->ip_src; - ip->ip_src = nat->nat_inip; - if ((ipn = nat_new(nat->nat_ptr, ip, fin, IPN_TCP, NAT_OUTBOUND))) - ipn->nat_age = fr_defnatage; - (void) fr_addstate(ip, fin, FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE); - ip->ip_src = swip; - fin->fin_dp = (char *)savep; - -adjust_seqack: - if (tcp->th_dport == aps->aps_dport) { - sum2 = (u_32_t)ntohl(tcp->th_seq); - off = aps->aps_sel; - if ((aps->aps_after[!off] > aps->aps_after[off]) && - (sum2 > aps->aps_after[!off])) { - off = aps->aps_sel = !off; /* switch to other set */ - } - if (aps->aps_seqoff[off]) { - sum1 = (u_32_t)aps->aps_after[off] - - aps->aps_seqoff[off]; - if (sum2 > sum1) { - sum1 = (u_32_t)aps->aps_seqoff[off]; - sum2 += sum1; - tcp->th_seq = htonl(sum2); - ch = 1; - } - } - - if (inc && (sum2 > aps->aps_after[!off])) { - aps->aps_after[!off] = sum2 + nlen - 1; - aps->aps_seqoff[!off] = aps->aps_seqoff[off] + inc; - } - } - return ch ? 2 : 0; -} diff --git a/bsd/netinet/ip_fw.c b/bsd/netinet/ip_fw.c deleted file mode 100644 index e652e90d9..000000000 --- a/bsd/netinet/ip_fw.c +++ /dev/null @@ -1,1408 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1993 Daniel Boulet - * Copyright (c) 1994 Ugen J.S.Antsilevich - * Copyright (c) 1996 Alex Nash - * - * Redistribution and use in source forms, with and without modification, - * are permitted provided that this entire comment appears intact. - * - * Redistribution in binary form may occur without any restrictions. - * Obviously, it would be nice if you gave credit where credit is due - * but requiring it would be too onerous. - * - * This software is provided ``AS IS'' without any warranties of any kind. - * - */ - -/* - * Implement IP packet firewall - */ -#if !IPFIREWALL_KEXT -#if ISFB31 -#if !defined(KLD_MODULE) && !defined(IPFIREWALL_MODULE) -#include "opt_ipfw.h" -#include "opt_ipdn.h" -#include "opt_ipdivert.h" -#include "opt_inet.h" -#endif -#endif -#ifndef INET -#error IPFIREWALL requires INET. -#endif /* INET */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if DUMMYNET -#include -#include -#endif -#include -#include -#include -#ifdef INET6 -#include -#endif -#include -#include -#include - -#include /* XXX ethertype_ip */ - -static int fw_debug = 1; -#if IPFIREWALL_VERBOSE -static int fw_verbose = 1; -#else -static int fw_verbose = 0; -#endif -static int fw_one_pass = 0; /* XXX */ -#if IPFIREWALL_VERBOSE_LIMIT -static int fw_verbose_limit = IPFIREWALL_VERBOSE_LIMIT; -#else -static int fw_verbose_limit = 0; -#endif - -#define IPFW_DEFAULT_RULE ((u_int)(u_short)~0) - -LIST_HEAD (ip_fw_head, ip_fw_chain) ip_fw_chain; - -MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's"); - -SYSCTL_DECL(_net_inet_ip); -SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall"); -SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, debug, CTLFLAG_RW, &fw_debug, 0, ""); -SYSCTL_INT(_net_inet_ip_fw, OID_AUTO,one_pass,CTLFLAG_RW, &fw_one_pass, 0, ""); -SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose, CTLFLAG_RW, &fw_verbose, 0, ""); -SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, &fw_verbose_limit, 0, ""); - -#define dprintf(a) if (!fw_debug); else printf a - -#define print_ip(a) printf("%d.%d.%d.%d", \ - (int)(ntohl(a.s_addr) >> 24) & 0xFF, \ - (int)(ntohl(a.s_addr) >> 16) & 0xFF, \ - (int)(ntohl(a.s_addr) >> 8) & 0xFF, \ - (int)(ntohl(a.s_addr)) & 0xFF); - -#define dprint_ip(a) if (!fw_debug); else print_ip(a) - -static int add_entry __P((struct ip_fw_head *chainptr, struct ip_fw *frwl)); -static int del_entry __P((struct ip_fw_head *chainptr, u_short number)); -static int zero_entry __P((struct ip_fw *)); -static int check_ipfw_struct __P((struct ip_fw *m)); -static __inline int - iface_match __P((struct ifnet *ifp, union ip_fw_if *ifu, - int byname)); -static int ipopts_match __P((struct ip *ip, struct ip_fw *f)); -static __inline int - port_match __P((u_short *portptr, int nports, u_short port, - int range_flag)); -static int tcpflg_match __P((struct tcphdr *tcp, struct ip_fw *f)); -static int icmptype_match __P((struct icmp * icmp, struct ip_fw * f)); -static void ipfw_report __P((struct ip_fw *f, struct ip *ip, - struct ifnet *rif, struct ifnet *oif)); - -static void flush_rule_ptrs(void); - -static int ip_fw_chk __P((struct ip **pip, int hlen, - struct ifnet *oif, u_int16_t *cookie, struct mbuf **m, - struct ip_fw_chain **flow_id, - struct sockaddr_in **next_hop)); -static int ip_fw_ctl __P((struct sockopt *sopt)); - -static char err_prefix[] = "ip_fw_ctl:"; - -/* - * Returns 1 if the port is matched by the vector, 0 otherwise - */ -static __inline int -port_match(u_short *portptr, int nports, u_short port, int range_flag) -{ - if (!nports) - return 1; - if (range_flag) { - if (portptr[0] <= port && port <= portptr[1]) { - return 1; - } - nports -= 2; - portptr += 2; - } - while (nports-- > 0) { - if (*portptr++ == port) { - return 1; - } - } - return 0; -} - -static int -tcpflg_match(struct tcphdr *tcp, struct ip_fw *f) -{ - u_char flg_set, flg_clr; - - if ((f->fw_tcpf & IP_FW_TCPF_ESTAB) && - (tcp->th_flags & (IP_FW_TCPF_RST | IP_FW_TCPF_ACK))) - return 1; - - flg_set = tcp->th_flags & f->fw_tcpf; - flg_clr = tcp->th_flags & f->fw_tcpnf; - - if (flg_set != f->fw_tcpf) - return 0; - if (flg_clr) - return 0; - - return 1; -} - -static int -icmptype_match(struct icmp *icmp, struct ip_fw *f) -{ - int type; - - if (!(f->fw_flg & IP_FW_F_ICMPBIT)) - return(1); - - type = icmp->icmp_type; - - /* check for matching type in the bitmap */ - if (type < IP_FW_ICMPTYPES_MAX && - (f->fw_uar.fw_icmptypes[type / (sizeof(unsigned) * 8)] & - (1U << (type % (8 * sizeof(unsigned)))))) - return(1); - - return(0); /* no match */ -} - -static int -is_icmp_query(struct ip *ip) -{ - const struct icmp *icmp; - int icmp_type; - - icmp = (struct icmp *)((u_int32_t *)ip + ip->ip_hl); - icmp_type = icmp->icmp_type; - - if (icmp_type == ICMP_ECHO || icmp_type == ICMP_ROUTERSOLICIT || - icmp_type == ICMP_TSTAMP || icmp_type == ICMP_IREQ || - icmp_type == ICMP_MASKREQ) - return(1); - - return(0); -} - -static int -ipopts_match(struct ip *ip, struct ip_fw *f) -{ - register u_char *cp; - int opt, optlen, cnt; - u_char opts, nopts, nopts_sve; - - cp = (u_char *)(ip + 1); - cnt = (ip->ip_hl << 2) - sizeof (struct ip); - opts = f->fw_ipopt; - nopts = nopts_sve = f->fw_ipnopt; - - 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) { - return 0; /*XXX*/ - } - } - switch (opt) { - - default: - break; - - case IPOPT_LSRR: - opts &= ~IP_FW_IPOPT_LSRR; - nopts &= ~IP_FW_IPOPT_LSRR; - break; - - case IPOPT_SSRR: - opts &= ~IP_FW_IPOPT_SSRR; - nopts &= ~IP_FW_IPOPT_SSRR; - break; - - case IPOPT_RR: - opts &= ~IP_FW_IPOPT_RR; - nopts &= ~IP_FW_IPOPT_RR; - break; - case IPOPT_TS: - opts &= ~IP_FW_IPOPT_TS; - nopts &= ~IP_FW_IPOPT_TS; - break; - } - if (opts == nopts) - break; - } - if (opts == 0 && nopts == nopts_sve) - return 1; - else - return 0; -} - -static __inline int -iface_match(struct ifnet *ifp, union ip_fw_if *ifu, int byname) -{ - /* Check by name or by IP address */ - if (byname) { - /* Check unit number (-1 is wildcard) */ - if (ifu->fu_via_if.unit != -1 - && ifp->if_unit != ifu->fu_via_if.unit) - return(0); - /* Check name */ - if (strncmp(ifp->if_name, ifu->fu_via_if.name, FW_IFNLEN)) - return(0); - return(1); - } else if (ifu->fu_via_ip.s_addr != 0) { /* Zero == wildcard */ - struct ifaddr *ia; - - for (ia = ifp->if_addrhead.tqh_first; - ia != NULL; ia = ia->ifa_link.tqe_next) { - if (ia->ifa_addr == NULL) - continue; - if (ia->ifa_addr->sa_family != AF_INET) - continue; - if (ifu->fu_via_ip.s_addr != ((struct sockaddr_in *) - (ia->ifa_addr))->sin_addr.s_addr) - continue; - return(1); - } - return(0); - } - return(1); -} - -static void -ipfw_report(struct ip_fw *f, struct ip *ip, - struct ifnet *rif, struct ifnet *oif) -{ - if (ip) { - static u_int64_t counter; - struct tcphdr *const tcp = (struct tcphdr *) ((u_int32_t *) ip+ ip->ip_hl); - struct udphdr *const udp = (struct udphdr *) ((u_int32_t *) ip+ ip->ip_hl); - struct icmp *const icmp = (struct icmp *) ((u_int32_t *) ip + ip->ip_hl); - int count; - - count = f ? f->fw_pcnt : ++counter; - if (fw_verbose_limit != 0 && count > fw_verbose_limit) - return; - - /* Print command name */ - printf("ipfw: %d ", f ? f->fw_number : -1); - if (!f) - printf("Refuse"); - else - switch (f->fw_flg & IP_FW_F_COMMAND) { - case IP_FW_F_DENY: - printf("Deny"); - break; - case IP_FW_F_REJECT: - if (f->fw_reject_code == IP_FW_REJECT_RST) - printf("Reset"); - else - printf("Unreach"); - break; - case IP_FW_F_ACCEPT: - printf("Accept"); - break; - case IP_FW_F_COUNT: - printf("Count"); - break; - case IP_FW_F_DIVERT: - printf("Divert %d", f->fw_divert_port); - break; - case IP_FW_F_TEE: - printf("Tee %d", f->fw_divert_port); - break; - case IP_FW_F_SKIPTO: - printf("SkipTo %d", f->fw_skipto_rule); - break; -#if DUMMYNET - case IP_FW_F_PIPE: - printf("Pipe %d", f->fw_skipto_rule); - break; -#endif -#if IPFIREWALL_FORWARD - case IP_FW_F_FWD: - printf("Forward to "); - print_ip(f->fw_fwd_ip.sin_addr); - if (f->fw_fwd_ip.sin_port) - printf(":%d", f->fw_fwd_ip.sin_port); - break; -#endif - default: - printf("UNKNOWN"); - break; - } - printf(" "); - - switch (ip->ip_p) { - case IPPROTO_TCP: - printf("TCP "); - print_ip(ip->ip_src); - if ((ip->ip_off & IP_OFFMASK) == 0) - printf(":%d ", ntohs(tcp->th_sport)); - else - printf(" "); - print_ip(ip->ip_dst); - if ((ip->ip_off & IP_OFFMASK) == 0) - printf(":%d", ntohs(tcp->th_dport)); - break; - case IPPROTO_UDP: - printf("UDP "); - print_ip(ip->ip_src); - if ((ip->ip_off & IP_OFFMASK) == 0) - printf(":%d ", ntohs(udp->uh_sport)); - else - printf(" "); - print_ip(ip->ip_dst); - if ((ip->ip_off & IP_OFFMASK) == 0) - printf(":%d", ntohs(udp->uh_dport)); - break; - case IPPROTO_ICMP: - if ((ip->ip_off & IP_OFFMASK) == 0) - printf("ICMP:%u.%u ", icmp->icmp_type, icmp->icmp_code); - else - printf("ICMP "); - print_ip(ip->ip_src); - printf(" "); - print_ip(ip->ip_dst); - break; - default: - printf("P:%d ", ip->ip_p); - print_ip(ip->ip_src); - printf(" "); - print_ip(ip->ip_dst); - break; - } - if (oif) - printf(" out via %s%d", oif->if_name, oif->if_unit); - else if (rif) - printf(" in via %s%d", rif->if_name, rif->if_unit); - if ((ip->ip_off & IP_OFFMASK)) - printf(" Fragment = %d",ip->ip_off & IP_OFFMASK); - printf("\n"); - if (fw_verbose_limit != 0 && count == fw_verbose_limit) - printf("ipfw: limit reached on rule #%d\n", - f ? f->fw_number : -1); - } -} - -/* - * given an ip_fw_chain *, lookup_next_rule will return a pointer - * of the same type to the next one. This can be either the jump - * target (for skipto instructions) or the next one in the chain (in - * all other cases including a missing jump target). - * Backward jumps are not allowed, so start looking from the next - * rule... - */ -static struct ip_fw_chain * lookup_next_rule(struct ip_fw_chain *me); - -static struct ip_fw_chain * -lookup_next_rule(struct ip_fw_chain *me) -{ - struct ip_fw_chain *chain ; - int rule = me->rule->fw_skipto_rule ; /* guess... */ - - if ( (me->rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_SKIPTO ) - for (chain = me->chain.le_next; chain ; chain = chain->chain.le_next ) - if (chain->rule->fw_number >= rule) - return chain ; - return me->chain.le_next ; /* failure or not a skipto */ -} - -/* - * Parameters: - * - * pip Pointer to packet header (struct ip **) - * bridge_ipfw extension: pip = NULL means a complete ethernet packet - * including ethernet header in the mbuf. Other fields - * are ignored/invalid. - * - * hlen Packet header length - * oif Outgoing interface, or NULL if packet is incoming - * *cookie Skip up to the first rule past this rule number; - * *m The packet; we set to NULL when/if we nuke it. - * *flow_id pointer to the last matching rule (in/out) - * *next_hop socket we are forwarding to (in/out). - * - * Return value: - * - * 0 The packet is to be accepted and routed normally OR - * the packet was denied/rejected and has been dropped; - * in the latter case, *m is equal to NULL upon return. - * port Divert the packet to port. - */ - -static int -ip_fw_chk(struct ip **pip, int hlen, - struct ifnet *oif, u_int16_t *cookie, struct mbuf **m, - struct ip_fw_chain **flow_id, - struct sockaddr_in **next_hop) -{ - struct ip_fw_chain *chain; - struct ip_fw *rule = NULL; - struct ip *ip = NULL ; - struct ifnet *const rif = (*m)->m_pkthdr.rcvif; - u_short offset = 0 ; - u_short src_port, dst_port; - u_int16_t skipto = *cookie; - - if (pip) { /* normal ip packet */ - ip = *pip; - offset = (ip->ip_off & IP_OFFMASK); - } else { /* bridged or non-ip packet */ - struct ether_header *eh = mtod(*m, struct ether_header *); - switch (ntohs(eh->ether_type)) { - case ETHERTYPE_IP : - if ((*m)->m_lenip_v != IPVERSION) - goto non_ip ; - hlen = ip->ip_hl << 2; - if (hlen < sizeof(struct ip)) /* minimum header length */ - goto non_ip ; - if ((*m)->m_len < 14 + hlen + 14) { - printf("-- m_len %d, need more...\n", (*m)->m_len); - goto non_ip ; - } - offset = (ip->ip_off & IP_OFFMASK); - break ; - default : -non_ip: ip = NULL ; - break ; - } - } - - if (*flow_id) { - if (fw_one_pass) - return 0 ; /* accept if passed first test */ - /* - * pkt has already been tagged. Look for the next rule - * to restart processing - */ - chain = LIST_NEXT( *flow_id, chain); - - if ( (chain = (*flow_id)->rule->next_rule_ptr) == NULL ) - chain = (*flow_id)->rule->next_rule_ptr = - lookup_next_rule(*flow_id) ; - if (! chain) goto dropit; - } else { - /* - * Go down the chain, looking for enlightment - * If we've been asked to start at a given rule immediatly, do so. - */ - chain = LIST_FIRST(&ip_fw_chain); - if ( skipto ) { - if (skipto >= IPFW_DEFAULT_RULE) - goto dropit; - while (chain && (chain->rule->fw_number <= skipto)) { - chain = LIST_NEXT(chain, chain); - } - if (! chain) goto dropit; - } - } - *cookie = 0; - for (; chain; chain = LIST_NEXT(chain, chain)) { - register struct ip_fw * f ; -again: - f = chain->rule; - - if (oif) { - /* Check direction outbound */ - if (!(f->fw_flg & IP_FW_F_OUT)) - continue; - } else { - /* Check direction inbound */ - if (!(f->fw_flg & IP_FW_F_IN)) - continue; - } - if (ip == NULL ) { - /* - * do relevant checks for non-ip packets: - * after this, only goto got_match or continue - */ - struct ether_header *eh = mtod(*m, struct ether_header *); - - /* - * make default rule always match or we have a panic - */ - if (f->fw_number == IPFW_DEFAULT_RULE) - goto got_match ; - /* - * temporary hack: - * udp from 0.0.0.0 means this rule applies. - * 1 src port is match ether type - * 2 src ports (interval) is match ether type - * 3 src ports is match ether address - */ - if ( f->fw_src.s_addr != 0 || f->fw_prot != IPPROTO_UDP - || f->fw_smsk.s_addr != 0xffffffff ) - continue; - switch (IP_FW_GETNSRCP(f)) { - case 1: /* match one type */ - if ( /* ( (f->fw_flg & IP_FW_F_INVSRC) != 0) ^ */ - ( f->fw_uar.fw_pts[0] == ntohs(eh->ether_type) ) ) { - goto got_match ; - } - break ; - default: - break ; - } - continue ; - } - - /* Fragments */ - if ((f->fw_flg & IP_FW_F_FRAG) && offset == 0 ) - continue; - - /* If src-addr doesn't match, not this rule. */ - if (((f->fw_flg & IP_FW_F_INVSRC) != 0) ^ ((ip->ip_src.s_addr - & f->fw_smsk.s_addr) != f->fw_src.s_addr)) - continue; - - /* If dest-addr doesn't match, not this rule. */ - if (((f->fw_flg & IP_FW_F_INVDST) != 0) ^ ((ip->ip_dst.s_addr - & f->fw_dmsk.s_addr) != f->fw_dst.s_addr)) - continue; - - /* Interface check */ - if ((f->fw_flg & IF_FW_F_VIAHACK) == IF_FW_F_VIAHACK) { - struct ifnet *const iface = oif ? oif : rif; - - /* Backwards compatibility hack for "via" */ - if (!iface || !iface_match(iface, - &f->fw_in_if, f->fw_flg & IP_FW_F_OIFNAME)) - continue; - } else { - /* Check receive interface */ - if ((f->fw_flg & IP_FW_F_IIFACE) - && (!rif || !iface_match(rif, - &f->fw_in_if, f->fw_flg & IP_FW_F_IIFNAME))) - continue; - /* Check outgoing interface */ - if ((f->fw_flg & IP_FW_F_OIFACE) - && (!oif || !iface_match(oif, - &f->fw_out_if, f->fw_flg & IP_FW_F_OIFNAME))) - continue; - } - - /* Check IP options */ - if (f->fw_ipopt != f->fw_ipnopt && !ipopts_match(ip, f)) - continue; - - /* Check protocol; if wildcard, match */ - if (f->fw_prot == IPPROTO_IP) - goto got_match; - - /* If different, don't match */ - if (ip->ip_p != f->fw_prot) - continue; - -/* - * here, pip==NULL for bridged pkts -- they include the ethernet - * header so i have to adjust lengths accordingly - */ -#define PULLUP_TO(l) do { \ - int len = (pip ? l : l + 14 ) ; \ - if ((*m)->m_len < (len) ) { \ - if ( (*m = m_pullup(*m, (len))) == 0) \ - goto bogusfrag; \ - ip = mtod(*m, struct ip *); \ - if (pip) \ - *pip = ip ; \ - else \ - ip = (struct ip *)((int)ip + 14); \ - offset = (ip->ip_off & IP_OFFMASK); \ - } \ - } while (0) - - /* Protocol specific checks */ - switch (ip->ip_p) { - case IPPROTO_TCP: - { - struct tcphdr *tcp; - - if (offset == 1) /* cf. RFC 1858 */ - goto bogusfrag; - if (offset != 0) { - /* - * TCP flags and ports aren't available in this - * packet -- if this rule specified either one, - * we consider the rule a non-match. - */ - if (f->fw_nports != 0 || - f->fw_tcpf != f->fw_tcpnf) - continue; - - break; - } - PULLUP_TO(hlen + 14); - tcp = (struct tcphdr *) ((u_int32_t *)ip + ip->ip_hl); - if (f->fw_tcpf != f->fw_tcpnf && !tcpflg_match(tcp, f)) - continue; - src_port = ntohs(tcp->th_sport); - dst_port = ntohs(tcp->th_dport); - goto check_ports; - } - - case IPPROTO_UDP: - { - struct udphdr *udp; - - if (offset != 0) { - /* - * Port specification is unavailable -- if this - * rule specifies a port, we consider the rule - * a non-match. - */ - if (f->fw_nports != 0) - continue; - - break; - } - PULLUP_TO(hlen + 4); - udp = (struct udphdr *) ((u_int32_t *)ip + ip->ip_hl); - src_port = ntohs(udp->uh_sport); - dst_port = ntohs(udp->uh_dport); -check_ports: - if (!port_match(&f->fw_uar.fw_pts[0], - IP_FW_GETNSRCP(f), src_port, - f->fw_flg & IP_FW_F_SRNG)) - continue; - if (!port_match(&f->fw_uar.fw_pts[IP_FW_GETNSRCP(f)], - IP_FW_GETNDSTP(f), dst_port, - f->fw_flg & IP_FW_F_DRNG)) - continue; - break; - } - - case IPPROTO_ICMP: - { - struct icmp *icmp; - - if (offset != 0) /* Type isn't valid */ - break; - PULLUP_TO(hlen + 2); - icmp = (struct icmp *) ((u_int32_t *)ip + ip->ip_hl); - if (!icmptype_match(icmp, f)) - continue; - break; - } -#undef PULLUP_TO - -bogusfrag: - if (fw_verbose) - ipfw_report(NULL, ip, rif, oif); - goto dropit; - } - -got_match: - *flow_id = chain ; /* XXX set flow id */ - /* Update statistics */ - f->fw_pcnt += 1; - if (ip) { - f->fw_bcnt += ip->ip_len; - } - f->timestamp = time_second; - - /* Log to console if desired */ - if ((f->fw_flg & IP_FW_F_PRN) && fw_verbose) - ipfw_report(f, ip, rif, oif); - - /* Take appropriate action */ - switch (f->fw_flg & IP_FW_F_COMMAND) { - case IP_FW_F_ACCEPT: - return(0); - case IP_FW_F_COUNT: - continue; -#if IPDIVERT - case IP_FW_F_DIVERT: - *cookie = f->fw_number; - return(f->fw_divert_port); -#endif - case IP_FW_F_TEE: - /* - * XXX someday tee packet here, but beware that you - * can't use m_copym() or m_copypacket() because - * the divert input routine modifies the mbuf - * (and these routines only increment reference - * counts in the case of mbuf clusters), so need - * to write custom routine. - */ - continue; - case IP_FW_F_SKIPTO: /* XXX check */ - if ( f->next_rule_ptr ) - chain = f->next_rule_ptr ; - else - chain = lookup_next_rule(chain) ; - if (! chain) goto dropit; - goto again ; -#if DUMMYNET - case IP_FW_F_PIPE: - return(f->fw_pipe_nr | 0x10000 ); -#endif -#if IPFIREWALL_FORWARD - case IP_FW_F_FWD: - /* Change the next-hop address for this packet. - * Initially we'll only worry about directly - * reachable next-hop's, but ultimately - * we will work out for next-hops that aren't - * direct the route we would take for it. We - * [cs]ould leave this latter problem to - * ip_output.c. We hope to high [name the abode of - * your favourite deity] that ip_output doesn't modify - * the new value of next_hop (which is dst there) - */ - if (next_hop != NULL) /* Make sure, first... */ - *next_hop = &(f->fw_fwd_ip); - return(0); /* Allow the packet */ -#endif - } - - /* Deny/reject this packet using this rule */ - rule = f; - break; - - } - -#if DIAGNOSTIC - /* Rule IPFW_DEFAULT_RULE should always be there and should always match */ - if (!chain) - panic("ip_fw: chain"); -#endif - - /* - * At this point, we're going to drop the packet. - * Send a reject notice if all of the following are true: - * - * - The packet matched a reject rule - * - The packet is not an ICMP packet, or is an ICMP query packet - * - The packet is not a multicast or broadcast packet - */ - if ((rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_REJECT - && ip - && (ip->ip_p != IPPROTO_ICMP || is_icmp_query(ip)) - && !((*m)->m_flags & (M_BCAST|M_MCAST)) - && !IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { - switch (rule->fw_reject_code) { - case IP_FW_REJECT_RST: - { - struct tcphdr *const tcp = - (struct tcphdr *) ((u_int32_t *)ip + ip->ip_hl); - struct tcpiphdr ti, *const tip = (struct tcpiphdr *) ip; - - if (offset != 0 || (tcp->th_flags & TH_RST)) - break; - ti.ti_i = *((struct ipovly *) ip); - ti.ti_t = *tcp; - bcopy(&ti, ip, sizeof(ti)); - NTOHL(tip->ti_seq); - NTOHL(tip->ti_ack); - tip->ti_len = ip->ip_len - hlen - (tip->ti_off << 2); - if (tcp->th_flags & TH_ACK) { - tcp_respond(NULL, (void *)tip, &tip->ti_t, *m, - (tcp_seq)0, ntohl(tcp->th_ack), TH_RST, 0); - } else { - if (tcp->th_flags & TH_SYN) - tip->ti_len++; - tcp_respond(NULL, (void *)tip, &tip->ti_t, *m, - tip->ti_seq + tip->ti_len, - (tcp_seq)0, TH_RST|TH_ACK, 0); - } - *m = NULL; - break; - } - default: /* Send an ICMP unreachable using code */ - icmp_error(*m, ICMP_UNREACH, - rule->fw_reject_code, 0L, 0); - *m = NULL; - break; - } - } - -dropit: - /* - * Finally, drop the packet. - */ - /* *cookie = 0; */ /* XXX is this necessary ? */ - if (*m) { - m_freem(*m); - *m = NULL; - } - return(0); -} - -/* - * when a rule is added/deleted, zero the direct pointers within - * all firewall rules. These will be reconstructed on the fly - * as packets are matched. - * Must be called at splnet(). - */ -static void -flush_rule_ptrs() -{ - struct ip_fw_chain *fcp ; - - for (fcp = ip_fw_chain.lh_first; fcp; fcp = fcp->chain.le_next) { - fcp->rule->next_rule_ptr = NULL ; - } -} - -static int -add_entry(struct ip_fw_head *chainptr, struct ip_fw *frwl) -{ - struct ip_fw *ftmp = 0; - struct ip_fw_chain *fwc = 0, *fcp, *fcpl = 0; - u_short nbr = 0; - int s; - - fwc = _MALLOC(sizeof *fwc, M_IPFW, M_NOWAIT); - ftmp = _MALLOC(sizeof *ftmp, M_IPFW, M_NOWAIT); - if (!fwc || !ftmp) { - dprintf(("%s MALLOC said no\n", err_prefix)); - if (fwc) FREE(fwc, M_IPFW); - if (ftmp) FREE(ftmp, M_IPFW); - return (ENOSPC); - } - - bcopy(frwl, ftmp, sizeof(struct ip_fw)); - ftmp->fw_in_if.fu_via_if.name[FW_IFNLEN - 1] = '\0'; - ftmp->fw_pcnt = 0L; - ftmp->fw_bcnt = 0L; - ftmp->next_rule_ptr = NULL ; - ftmp->pipe_ptr = NULL ; - fwc->rule = ftmp; - - s = splnet(); - - if (chainptr->lh_first == 0) { - LIST_INSERT_HEAD(chainptr, fwc, chain); - splx(s); - return(0); - } - - /* If entry number is 0, find highest numbered rule and add 100 */ - if (ftmp->fw_number == 0) { - for (fcp = LIST_FIRST(chainptr); fcp; fcp = LIST_NEXT(fcp, chain)) { - if (fcp->rule->fw_number != (u_short)-1) - nbr = fcp->rule->fw_number; - else - break; - } - if (nbr < IPFW_DEFAULT_RULE - 100) - nbr += 100; - ftmp->fw_number = nbr; - } - - /* Got a valid number; now insert it, keeping the list ordered */ - for (fcp = LIST_FIRST(chainptr); fcp; fcp = LIST_NEXT(fcp, chain)) { - if (fcp->rule->fw_number > ftmp->fw_number) { - if (fcpl) { - LIST_INSERT_AFTER(fcpl, fwc, chain); - } else { - LIST_INSERT_HEAD(chainptr, fwc, chain); - } - break; - } else { - fcpl = fcp; - } - } - flush_rule_ptrs(); - - splx(s); - return (0); -} - -static int -del_entry(struct ip_fw_head *chainptr, u_short number) -{ - struct ip_fw_chain *fcp; - - fcp = LIST_FIRST(chainptr); - if (number != (u_short)-1) { - for (; fcp; fcp = LIST_NEXT(fcp, chain)) { - if (fcp->rule->fw_number == number) { - int s; - - /* prevent access to rules while removing them */ - s = splnet(); - while (fcp && fcp->rule->fw_number == number) { - struct ip_fw_chain *next; - - next = LIST_NEXT(fcp, chain); - LIST_REMOVE(fcp, chain); -#if DUMMYNET - dn_rule_delete(fcp) ; -#endif - flush_rule_ptrs(); - FREE(fcp->rule, M_IPFW); - FREE(fcp, M_IPFW); - fcp = next; - } - splx(s); - return 0; - } - } - } - - return (EINVAL); -} - -static int -zero_entry(struct ip_fw *frwl) -{ - struct ip_fw_chain *fcp; - int s, cleared; - - if (frwl == 0) { - s = splnet(); - for (fcp = LIST_FIRST(&ip_fw_chain); fcp; fcp = LIST_NEXT(fcp, chain)) { - fcp->rule->fw_bcnt = fcp->rule->fw_pcnt = 0; - fcp->rule->timestamp = 0; - } - splx(s); - } - else { - cleared = 0; - - /* - * It's possible to insert multiple chain entries with the - * same number, so we don't stop after finding the first - * match if zeroing a specific entry. - */ - for (fcp = LIST_FIRST(&ip_fw_chain); fcp; fcp = LIST_NEXT(fcp, chain)) - if (frwl->fw_number == fcp->rule->fw_number) { - s = splnet(); - while (fcp && frwl->fw_number == fcp->rule->fw_number) { - fcp->rule->fw_bcnt = fcp->rule->fw_pcnt = 0; - fcp->rule->timestamp = 0; - fcp = LIST_NEXT(fcp, chain); - } - splx(s); - cleared = 1; - break; - } - if (!cleared) /* we didn't find any matching rules */ - return (EINVAL); - } - - if (fw_verbose) { - if (frwl) - printf("ipfw: Entry %d cleared.\n", frwl->fw_number); - else - printf("ipfw: Accounting cleared.\n"); - } - - return (0); -} - -static int -check_ipfw_struct(struct ip_fw *frwl) -{ - /* Check for invalid flag bits */ - if ((frwl->fw_flg & ~IP_FW_F_MASK) != 0) { - dprintf(("%s undefined flag bits set (flags=%x)\n", - err_prefix, frwl->fw_flg)); - return (EINVAL); - } - /* Must apply to incoming or outgoing (or both) */ - if (!(frwl->fw_flg & (IP_FW_F_IN | IP_FW_F_OUT))) { - dprintf(("%s neither in nor out\n", err_prefix)); - return (EINVAL); - } - /* Empty interface name is no good */ - if (((frwl->fw_flg & IP_FW_F_IIFNAME) - && !*frwl->fw_in_if.fu_via_if.name) - || ((frwl->fw_flg & IP_FW_F_OIFNAME) - && !*frwl->fw_out_if.fu_via_if.name)) { - dprintf(("%s empty interface name\n", err_prefix)); - return (EINVAL); - } - /* Sanity check interface matching */ - if ((frwl->fw_flg & IF_FW_F_VIAHACK) == IF_FW_F_VIAHACK) { - ; /* allow "via" backwards compatibility */ - } else if ((frwl->fw_flg & IP_FW_F_IN) - && (frwl->fw_flg & IP_FW_F_OIFACE)) { - dprintf(("%s outgoing interface check on incoming\n", - err_prefix)); - return (EINVAL); - } - /* Sanity check port ranges */ - if ((frwl->fw_flg & IP_FW_F_SRNG) && IP_FW_GETNSRCP(frwl) < 2) { - dprintf(("%s src range set but n_src_p=%d\n", - err_prefix, IP_FW_GETNSRCP(frwl))); - return (EINVAL); - } - if ((frwl->fw_flg & IP_FW_F_DRNG) && IP_FW_GETNDSTP(frwl) < 2) { - dprintf(("%s dst range set but n_dst_p=%d\n", - err_prefix, IP_FW_GETNDSTP(frwl))); - return (EINVAL); - } - if (IP_FW_GETNSRCP(frwl) + IP_FW_GETNDSTP(frwl) > IP_FW_MAX_PORTS) { - dprintf(("%s too many ports (%d+%d)\n", - err_prefix, IP_FW_GETNSRCP(frwl), IP_FW_GETNDSTP(frwl))); - return (EINVAL); - } - /* - * Protocols other than TCP/UDP don't use port range - */ - if ((frwl->fw_prot != IPPROTO_TCP) && - (frwl->fw_prot != IPPROTO_UDP) && - (IP_FW_GETNSRCP(frwl) || IP_FW_GETNDSTP(frwl))) { - dprintf(("%s port(s) specified for non TCP/UDP rule\n", - err_prefix)); - return (EINVAL); - } - - /* - * Rather than modify the entry to make such entries work, - * we reject this rule and require user level utilities - * to enforce whatever policy they deem appropriate. - */ - if ((frwl->fw_src.s_addr & (~frwl->fw_smsk.s_addr)) || - (frwl->fw_dst.s_addr & (~frwl->fw_dmsk.s_addr))) { - dprintf(("%s rule never matches\n", err_prefix)); - return (EINVAL); - } - - if ((frwl->fw_flg & IP_FW_F_FRAG) && - (frwl->fw_prot == IPPROTO_UDP || frwl->fw_prot == IPPROTO_TCP)) { - if (frwl->fw_nports) { - dprintf(("%s cannot mix 'frag' and ports\n", err_prefix)); - return (EINVAL); - } - if (frwl->fw_prot == IPPROTO_TCP && - frwl->fw_tcpf != frwl->fw_tcpnf) { - dprintf(("%s cannot mix 'frag' and TCP flags\n", err_prefix)); - return (EINVAL); - } - } - - /* Check command specific stuff */ - switch (frwl->fw_flg & IP_FW_F_COMMAND) - { - case IP_FW_F_REJECT: - if (frwl->fw_reject_code >= 0x100 - && !(frwl->fw_prot == IPPROTO_TCP - && frwl->fw_reject_code == IP_FW_REJECT_RST)) { - dprintf(("%s unknown reject code\n", err_prefix)); - return (EINVAL); - } - break; - case IP_FW_F_DIVERT: /* Diverting to port zero is invalid */ - case IP_FW_F_PIPE: /* piping through 0 is invalid */ - case IP_FW_F_TEE: - if (frwl->fw_divert_port == 0) { - dprintf(("%s can't divert to port 0\n", err_prefix)); - return (EINVAL); - } - break; - case IP_FW_F_DENY: - case IP_FW_F_ACCEPT: - case IP_FW_F_COUNT: - case IP_FW_F_SKIPTO: -#if IPFIREWALL_FORWARD - case IP_FW_F_FWD: -#endif - break; - default: - dprintf(("%s invalid command\n", err_prefix)); - return (EINVAL); - } - - return 0; -} - -static int -ip_fw_ctl(struct sockopt *sopt) -{ - int error, s; - size_t size; - char *buf, *bp; - struct ip_fw_chain *fcp; - struct ip_fw frwl; - - /* Disallow sets in really-really secure mode. */ - if (sopt->sopt_dir == SOPT_SET && securelevel >= 3) - return (EPERM); - error = 0; - - switch (sopt->sopt_name) { - case IP_FW_GET: - for (fcp = LIST_FIRST(&ip_fw_chain), size = 0; fcp; - fcp = LIST_NEXT(fcp, chain)) - size += sizeof *fcp->rule; - buf = _MALLOC(size, M_TEMP, M_WAITOK); - if (buf == 0) { - error = ENOBUFS; - break; - } - - for (fcp = LIST_FIRST(&ip_fw_chain), bp = buf; fcp; - fcp = LIST_NEXT(fcp, chain)) { - bcopy(fcp->rule, bp, sizeof *fcp->rule); - bp += sizeof *fcp->rule; - } - error = sooptcopyout(sopt, buf, size); - FREE(buf, M_TEMP); - break; - - case IP_FW_FLUSH: - for (fcp = ip_fw_chain.lh_first; - fcp != 0 && fcp->rule->fw_number != IPFW_DEFAULT_RULE; - fcp = ip_fw_chain.lh_first) { - s = splnet(); - LIST_REMOVE(fcp, chain); - FREE(fcp->rule, M_IPFW); - FREE(fcp, M_IPFW); - splx(s); - } - break; - - case IP_FW_ZERO: - if (sopt->sopt_val != 0) { - error = sooptcopyin(sopt, &frwl, sizeof frwl, - sizeof frwl); - if (error || (error = zero_entry(&frwl))) - break; - } else { - error = zero_entry(0); - } - break; - - case IP_FW_ADD: - error = sooptcopyin(sopt, &frwl, sizeof frwl, sizeof frwl); - if (error || (error = check_ipfw_struct(&frwl))) - break; - - if (frwl.fw_number == IPFW_DEFAULT_RULE) { - dprintf(("%s can't add rule %u\n", err_prefix, - (unsigned)IPFW_DEFAULT_RULE)); - error = EINVAL; - } else { - error = add_entry(&ip_fw_chain, &frwl); - } - break; - - case IP_FW_DEL: - error = sooptcopyin(sopt, &frwl, sizeof frwl, sizeof frwl); - if (error) - break; - - if (frwl.fw_number == IPFW_DEFAULT_RULE) { - dprintf(("%s can't delete rule %u\n", err_prefix, - (unsigned)IPFW_DEFAULT_RULE)); - error = EINVAL; - } else { - error = del_entry(&ip_fw_chain, frwl.fw_number); - } - break; - - default: - printf("ip_fw_ctl invalid option %d\n", sopt->sopt_name); - error = EINVAL ; - } - - return (error); -} - -struct ip_fw_chain *ip_fw_default_rule ; - -void -ip_fw_init(void) -{ - struct ip_fw default_rule; - - ip_fw_chk_ptr = ip_fw_chk; - ip_fw_ctl_ptr = ip_fw_ctl; - LIST_INIT(&ip_fw_chain); - - bzero(&default_rule, sizeof default_rule); - default_rule.fw_prot = IPPROTO_IP; - default_rule.fw_number = IPFW_DEFAULT_RULE; -#if IPFIREWALL_DEFAULT_TO_ACCEPT - default_rule.fw_flg |= IP_FW_F_ACCEPT; -#else - default_rule.fw_flg |= IP_FW_F_DENY; -#endif - default_rule.fw_flg |= IP_FW_F_IN | IP_FW_F_OUT; - if (check_ipfw_struct(&default_rule) != 0 || - add_entry(&ip_fw_chain, &default_rule)) - panic("ip_fw_init"); - - ip_fw_default_rule = ip_fw_chain.lh_first ; - printf("IP packet filtering initialized, " -#if IPDIVERT - "divert enabled, "); -#else - "divert disabled, "); -#endif -#if IPFIREWALL_FORWARD - printf("rule-based forwarding enabled, "); -#else - printf("rule-based forwarding disabled, "); -#endif -#if IPFIREWALL_DEFAULT_TO_ACCEPT - printf("default to accept, "); -#endif -#ifndef IPFIREWALL_VERBOSE - printf("logging disabled\n"); -#else - if (fw_verbose_limit == 0) - printf("unlimited logging\n"); - else - printf("logging limited to %d packets/entry\n", - fw_verbose_limit); -#endif -} - -#if ISFB31 - -/* - * ### LD 08/04/99: This is used if IPFIREWALL is a FreeBSD "KLD" module - * Right now, we're linked to the kernel all the time - * will be fixed with the use of an NKE? - * - * Note: ip_fw_init is called from div_init() in xnu - */ - -static ip_fw_chk_t *old_chk_ptr; -static ip_fw_ctl_t *old_ctl_ptr; - -#if defined(IPFIREWALL_MODULE) && !defined(KLD_MODULE) - -#include -#include -#include - -MOD_MISC(ipfw); - -static int -ipfw_load(struct lkm_table *lkmtp, int cmd) -{ - int s=splnet(); - - old_chk_ptr = ip_fw_chk_ptr; - old_ctl_ptr = ip_fw_ctl_ptr; - - ip_fw_init(); - splx(s); - return 0; -} - -static int -ipfw_unload(struct lkm_table *lkmtp, int cmd) -{ - int s=splnet(); - - ip_fw_chk_ptr = old_chk_ptr; - ip_fw_ctl_ptr = old_ctl_ptr; - - while (LIST_FIRST(&ip_fw_chain) != NULL) { - struct ip_fw_chain *fcp = LIST_FIRST(&ip_fw_chain); - LIST_REMOVE(LIST_FIRST(&ip_fw_chain), chain); - FREE(fcp->rule, M_IPFW); - FREE(fcp, M_IPFW); - } - - splx(s); - printf("IP firewall unloaded\n"); - return 0; -} - -int -ipfw_mod(struct lkm_table *lkmtp, int cmd, int ver) -{ - MOD_DISPATCH(ipfw, lkmtp, cmd, ver, - ipfw_load, ipfw_unload, lkm_nullcmd); -} -#else -static int -ipfw_modevent(module_t mod, int type, void *unused) -{ - int s; - - switch (type) { - case MOD_LOAD: - s = splnet(); - - old_chk_ptr = ip_fw_chk_ptr; - old_ctl_ptr = ip_fw_ctl_ptr; - - ip_fw_init(); - splx(s); - return 0; - case MOD_UNLOAD: - s = splnet(); - - ip_fw_chk_ptr = old_chk_ptr; - ip_fw_ctl_ptr = old_ctl_ptr; - - while (LIST_FIRST(&ip_fw_chain) != NULL) { - struct ip_fw_chain *fcp = LIST_FIRST(&ip_fw_chain); - LIST_REMOVE(LIST_FIRST(&ip_fw_chain), chain); - FREE(fcp->rule, M_IPFW); - FREE(fcp, M_IPFW); - } - - splx(s); - printf("IP firewall unloaded\n"); - return 0; - default: - break; - } - return 0; -} - -static moduledata_t ipfwmod = { - "ipfw", - ipfw_modevent, - 0 -}; -DECLARE_MODULE(ipfw, ipfwmod, SI_SUB_PSEUDO, SI_ORDER_ANY); -#endif -#endif /* ISFB31 */ -#endif /* IPFIREWALL_KEXT */ - diff --git a/bsd/netinet/ip_fw.h b/bsd/netinet/ip_fw.h index c4fbf860f..41eae12e2 100644 --- a/bsd/netinet/ip_fw.h +++ b/bsd/netinet/ip_fw.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -36,9 +36,14 @@ #ifndef _IP_FW_H #define _IP_FW_H +#include #include + +#define IP_FW_CURRENT_API_VERSION 20 /* Version of this API */ + + /* * This union structure identifies an interface, either explicitly * by name or implicitly by IP address. The flags IP_FW_F_IIFNAME @@ -67,10 +72,13 @@ union ip_fw_if { * fw_src, fw_dst, fw_smsk, fw_dmsk are always stored in network byte order. * fw_flg and fw_n*p are stored in host byte order (of course). * Port numbers are stored in HOST byte order. - * Warning: setsockopt() will fail if sizeof(struct ip_fw) > MLEN (108) */ struct ip_fw { + u_int32_t version; /* Version of this structure. Should always be */ + /* set to IP_FW_CURRENT_API_VERSION by clients. */ + void *context; /* Context that is usable by user processes to */ + /* identify this rule. */ u_int64_t fw_pcnt,fw_bcnt; /* Packet and byte counters */ struct in_addr fw_src, fw_dst; /* Source and destination IP addr */ struct in_addr fw_smsk, fw_dmsk; /* Mask for src and dest IP addr */ @@ -83,24 +91,47 @@ struct ip_fw { #define IP_FW_ICMPTYPES_DIM (IP_FW_ICMPTYPES_MAX / (sizeof(unsigned) * 8)) unsigned fw_icmptypes[IP_FW_ICMPTYPES_DIM]; /* ICMP types bitmap */ } fw_uar; + u_int fw_ipflg; /* IP flags word */ u_char fw_ipopt,fw_ipnopt; /* IP options set/unset */ + u_char fw_tcpopt,fw_tcpnopt; /* TCP options set/unset */ u_char fw_tcpf,fw_tcpnf; /* TCP flags set/unset */ long timestamp; /* timestamp (tv_sec) of last match */ union ip_fw_if fw_in_if, fw_out_if; /* Incoming and outgoing interfaces */ union { u_short fu_divert_port; /* Divert/tee port (options IPDIVERT) */ - u_short fu_pipe_nr; /* pipe number (option DUMMYNET) */ + u_short fu_pipe_nr; /* queue number (option DUMMYNET) */ u_short fu_skipto_rule; /* SKIPTO command rule number */ u_short fu_reject_code; /* REJECT response code */ struct sockaddr_in fu_fwd_ip; } fw_un; u_char fw_prot; /* IP protocol */ - u_char fw_nports; /* N'of src ports and # of dst ports */ - /* in ports array (dst ports follow */ - /* src ports; max of 10 ports in all; */ - /* count of 0 means match all ports) */ - void *pipe_ptr; /* Pipe ptr in case of dummynet pipe */ + /* + * N'of src ports and # of dst ports in ports array (dst ports + * follow src ports; max of 10 ports in all; count of 0 means + * match all ports) + */ + u_char fw_nports; + void *pipe_ptr; /* flow_set ptr for dummynet pipe */ void *next_rule_ptr ; /* next rule in case of match */ + uid_t fw_uid; /* uid to match */ + int fw_logamount; /* amount to log */ + u_int64_t fw_loghighest; /* highest number packet to log */ +}; + +/* + * extended ipfw structure... some fields in the original struct + * can be used to pass parameters up/down, namely pointers + * void *pipe_ptr + * void *next_rule_ptr + * some others can be used to pass parameters down, namely counters etc. + * u_int64_t fw_pcnt,fw_bcnt; + * long timestamp; + */ + +struct ip_fw_ext { /* extended structure */ + struct ip_fw rule; /* must be at offset 0 */ + long dont_match_prob; /* 0x7fffffff means 1.0, always fail */ + u_int dyn_type; /* type for dynamic rule */ }; #define IP_FW_GETNSRCP(rule) ((rule)->fw_nports & 0x0f) @@ -121,10 +152,37 @@ struct ip_fw { #define fw_fwd_ip fw_un.fu_fwd_ip struct ip_fw_chain { - LIST_ENTRY(ip_fw_chain) chain; - struct ip_fw *rule; + LIST_ENTRY(ip_fw_chain) next; + struct ip_fw *rule; }; +/* + * Flow mask/flow id for each queue. + */ +struct ipfw_flow_id { + u_int32_t dst_ip, src_ip ; + u_int16_t dst_port, src_port ; + u_int8_t proto ; + u_int8_t flags ; /* protocol-specific flags */ +} ; + +/* + * dynamic ipfw rule + */ +struct ipfw_dyn_rule { + struct ipfw_dyn_rule *next ; + + struct ipfw_flow_id id ; + struct ipfw_flow_id mask ; + struct ip_fw_chain *chain ; /* pointer to parent rule */ + u_int32_t type ; /* rule type */ + u_int32_t expire ; /* expire time */ + u_int64_t pcnt, bcnt; /* match counters */ + u_int32_t bucket ; /* which bucket in hash table */ + u_int32_t state ; /* state of this rule (typ. a */ + /* combination of TCP flags) */ +} ; + /* * Values for "flags" field . */ @@ -138,6 +196,7 @@ struct ip_fw_chain { #define IP_FW_F_SKIPTO 0x00000006 /* This is a skipto rule */ #define IP_FW_F_FWD 0x00000007 /* This is a "change forwarding address" rule */ #define IP_FW_F_PIPE 0x00000008 /* This is a dummynet rule */ +#define IP_FW_F_QUEUE 0x00000009 /* This is a dummynet queue */ #define IP_FW_F_IN 0x00000100 /* Check inbound packets */ #define IP_FW_F_OUT 0x00000200 /* Check outbound packets */ @@ -164,7 +223,25 @@ struct ip_fw_chain { #define IP_FW_F_ICMPBIT 0x00100000 /* ICMP type bitmap is valid */ -#define IP_FW_F_MASK 0x001FFFFF /* All possible flag bits mask */ +#define IP_FW_F_UID 0x00200000 /* filter by uid */ + +#define IP_FW_F_RND_MATCH 0x00800000 /* probabilistic rule match */ +#define IP_FW_F_SMSK 0x01000000 /* src-port + mask */ +#define IP_FW_F_DMSK 0x02000000 /* dst-port + mask */ +#define IP_FW_BRIDGED 0x04000000 /* only match bridged packets */ +#define IP_FW_F_KEEP_S 0x08000000 /* keep state */ +#define IP_FW_F_CHECK_S 0x10000000 /* check state */ + +#define IP_FW_F_SME 0x20000000 /* source = me */ +#define IP_FW_F_DME 0x40000000 /* destination = me */ + +#define IP_FW_F_MASK 0x7FFFFFFF /* All possible flag bits mask */ + +/* + * Flags for the 'fw_ipflg' field, for comparing values of ip and its protocols. + */ +#define IP_FW_IF_TCPEST 0x00000020 /* established TCP connection */ +#define IP_FW_IF_TCPMSK 0x00000020 /* mask of all TCP values */ /* * For backwards compatibility with rules specifying "via iface" but @@ -188,6 +265,15 @@ struct ip_fw_chain { #define IP_FW_IPOPT_RR 0x04 #define IP_FW_IPOPT_TS 0x08 +/* + * Definitions for TCP option names. + */ +#define IP_FW_TCPOPT_MSS 0x01 +#define IP_FW_TCPOPT_WINDOW 0x02 +#define IP_FW_TCPOPT_SACK 0x04 +#define IP_FW_TCPOPT_TS 0x08 +#define IP_FW_TCPOPT_CC 0x10 + /* * Definitions for TCP flags. */ @@ -197,12 +283,16 @@ struct ip_fw_chain { #define IP_FW_TCPF_PSH TH_PUSH #define IP_FW_TCPF_ACK TH_ACK #define IP_FW_TCPF_URG TH_URG -#define IP_FW_TCPF_ESTAB 0x40 /* * Main firewall chains definitions and global var's definitions. */ #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE + +#define IP_FW_PORT_DYNT_FLAG 0x10000 +#define IP_FW_PORT_TEE_FLAG 0x20000 +#define IP_FW_PORT_DENY_FLAG 0x40000 /* * Function definitions. @@ -217,15 +307,10 @@ typedef int ip_fw_chk_t __P((struct ip **, int, struct ifnet *, u_int16_t *, typedef int ip_fw_ctl_t __P((struct sockopt *)); extern ip_fw_chk_t *ip_fw_chk_ptr; extern ip_fw_ctl_t *ip_fw_ctl_ptr; - -/* IP NAT hooks */ -typedef int ip_nat_t __P((struct ip **, struct mbuf **, struct ifnet *, int)); -typedef int ip_nat_ctl_t __P((struct sockopt *)); -extern ip_nat_t *ip_nat_ptr; -extern ip_nat_ctl_t *ip_nat_ctl_ptr; -#define IP_NAT_IN 0x00000001 -#define IP_NAT_OUT 0x00000002 - +extern int fw_one_pass; +extern int fw_enable; +extern struct ipfw_flow_id last_pkt ; +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ #endif /* _IP_FW_H */ diff --git a/bsd/netinet/ip_icmp.c b/bsd/netinet/ip_icmp.c index 8ecf5d4a2..461ba6b00 100644 --- a/bsd/netinet/ip_icmp.c +++ b/bsd/netinet/ip_icmp.c @@ -99,6 +99,14 @@ static int icmpmaskrepl = 0; SYSCTL_INT(_net_inet_icmp, ICMPCTL_MASKREPL, maskrepl, CTLFLAG_RW, &icmpmaskrepl, 0, ""); +static int drop_redirect = 0; +SYSCTL_INT(_net_inet_icmp, OID_AUTO, drop_redirect, CTLFLAG_RW, + &drop_redirect, 0, ""); + +static int log_redirect = 0; +SYSCTL_INT(_net_inet_icmp, OID_AUTO, log_redirect, CTLFLAG_RW, + &log_redirect, 0, ""); + #if ICMP_BANDLIM /* @@ -121,9 +129,9 @@ SYSCTL_INT(_net_inet_icmp, ICMPCTL_ICMPLIM, icmplim, CTLFLAG_RD, * ICMP broadcast echo sysctl */ -static int icmpbmcastecho = 0; -SYSCTL_INT(_net_inet_icmp, OID_AUTO, bmcastecho, CTLFLAG_RW, &icmpbmcastecho, - 0, ""); +static int icmpbmcastecho = 1; +SYSCTL_INT(_net_inet_icmp, OID_AUTO, bmcastecho, CTLFLAG_RW, + &icmpbmcastecho, 0, ""); #if ICMPPRINTFS @@ -132,7 +140,7 @@ int icmpprintfs = 0; static void icmp_reflect __P((struct mbuf *)); static void icmp_send __P((struct mbuf *, struct mbuf *)); -int ip_next_mtu __P((int, int)); +static int ip_next_mtu __P((int, int)); extern struct protosw inetsw[]; @@ -160,13 +168,10 @@ icmp_error(n, type, code, dest, destifp) if (type != ICMP_REDIRECT) icmpstat.icps_error++; /* - * Don't send error if the original packet was encrypted. * 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 (n->m_flags & M_DECRYPTED) - goto freeit; if (oip->ip_off &~ (IP_MF|IP_DF)) goto freeit; if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT && @@ -184,7 +189,12 @@ icmp_error(n, type, code, dest, destifp) m = m_gethdr(M_DONTWAIT, MT_HEADER); if (m == NULL) goto freeit; - icmplen = oiplen + min(8, oip->ip_len); + icmplen = min(oiplen + 8, oip->ip_len); + if (icmplen < sizeof(struct ip)) { + printf("icmp_error: bad length\n"); + m_free(m); + goto freeit; + } m->m_len = icmplen + ICMP_MINLEN; MH_ALIGN(m, m->m_len); icp = mtod(m, struct icmp *); @@ -210,9 +220,14 @@ icmp_error(n, type, code, dest, destifp) } icp->icmp_code = code; - bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen); + m_copydata(n, 0, icmplen, (caddr_t)&icp->icmp_ip); nip = &icp->icmp_ip; - nip->ip_len = htons((u_short)(nip->ip_len + oiplen)); + + /* + * Convert fields to network representation. + */ + HTONS(nip->ip_len); + HTONS(nip->ip_off); /* * Now, copy old ip header (without options) @@ -310,15 +325,6 @@ icmp_input(m, hlen) icp->icmp_code); #endif -#if IPSEC - /* drop it if it does not match the policy */ - /* XXX Is there meaning of check in here ? */ - if (ipsec4_in_reject(m, NULL)) { - ipsecstat.in_polvio++; - goto freeit; - } -#endif - /* * Message type specific processing. */ @@ -332,33 +338,34 @@ icmp_input(m, hlen) switch (code) { case ICMP_UNREACH_NET: case ICMP_UNREACH_HOST: - case ICMP_UNREACH_PROTOCOL: - case ICMP_UNREACH_PORT: case ICMP_UNREACH_SRCFAIL: - code += PRC_UNREACH_NET; + case ICMP_UNREACH_NET_UNKNOWN: + case ICMP_UNREACH_HOST_UNKNOWN: + case ICMP_UNREACH_ISOLATED: + case ICMP_UNREACH_TOSNET: + case ICMP_UNREACH_TOSHOST: + case ICMP_UNREACH_HOST_PRECEDENCE: + case ICMP_UNREACH_PRECEDENCE_CUTOFF: + code = PRC_UNREACH_NET; break; case ICMP_UNREACH_NEEDFRAG: code = PRC_MSGSIZE; break; - case ICMP_UNREACH_NET_UNKNOWN: - case ICMP_UNREACH_NET_PROHIB: - case ICMP_UNREACH_TOSNET: - code = PRC_UNREACH_NET; + /* + * RFC 1122, Sections 3.2.2.1 and 4.2.3.9. + * Treat subcodes 2,3 as immediate RST + */ + case ICMP_UNREACH_PROTOCOL: + case ICMP_UNREACH_PORT: + code = PRC_UNREACH_PORT; break; - case ICMP_UNREACH_HOST_UNKNOWN: - case ICMP_UNREACH_ISOLATED: + case ICMP_UNREACH_NET_PROHIB: case ICMP_UNREACH_HOST_PROHIB: - case ICMP_UNREACH_TOSHOST: - code = PRC_UNREACH_HOST; - break; - case ICMP_UNREACH_FILTER_PROHIB: - case ICMP_UNREACH_HOST_PRECEDENCE: - case ICMP_UNREACH_PRECEDENCE_CUTOFF: - code = PRC_UNREACH_PORT; + code = PRC_UNREACH_ADMIN_PROHIB; break; default: @@ -440,7 +447,7 @@ icmp_input(m, hlen) } } if (rt) - RTFREE(rt); + rtfree(rt); } #endif @@ -465,7 +472,12 @@ icmp_input(m, hlen) break; } icp->icmp_type = ICMP_ECHOREPLY; - goto reflect; +#if ICMP_BANDLIM + if (badport_bandlim(BANDLIM_ICMP_ECHO) < 0) + goto freeit; + else +#endif + goto reflect; case ICMP_TSTAMP: if (!icmpbmcastecho @@ -480,7 +492,12 @@ icmp_input(m, hlen) icp->icmp_type = ICMP_TSTAMPREPLY; icp->icmp_rtime = iptime(); icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */ - goto reflect; +#if ICMP_BANDLIM + if (badport_bandlim(BANDLIM_ICMP_TSTAMP) < 0) + goto freeit; + else +#endif + goto reflect; case ICMP_MASKREQ: #define satosin(sa) ((struct sockaddr_in *)(sa)) @@ -524,6 +541,23 @@ reflect: return; case ICMP_REDIRECT: + if (log_redirect) { + u_long src, dst, gw; + + src = ntohl(ip->ip_src.s_addr); + dst = ntohl(icp->icmp_ip.ip_dst.s_addr); + gw = ntohl(icp->icmp_gwaddr.s_addr); + printf("icmp redirect from %d.%d.%d.%d: " + "%d.%d.%d.%d => %d.%d.%d.%d\n", + (int)(src >> 24), (int)((src >> 16) & 0xff), + (int)((src >> 8) & 0xff), (int)(src & 0xff), + (int)(dst >> 24), (int)((dst >> 16) & 0xff), + (int)((dst >> 8) & 0xff), (int)(dst & 0xff), + (int)(gw >> 24), (int)((gw >> 16) & 0xff), + (int)((gw >> 8) & 0xff), (int)(gw & 0xff)); + } + if (drop_redirect) + break; if (code > 3) goto badcode; if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) || @@ -628,7 +662,7 @@ icmp_reflect(m) ia = in_ifaddrhead.tqh_first; t = IA_SIN(ia)->sin_addr; ip->ip_src = t; - ip->ip_ttl = MAXTTL; + ip->ip_ttl = ip_defttl; if (optlen > 0) { register u_char *cp; @@ -662,7 +696,7 @@ icmp_reflect(m) break; len = cp[IPOPT_OLEN]; if (len < IPOPT_OLEN + sizeof(*cp) || - len > cnt) + len > cnt) break; } /* @@ -744,13 +778,9 @@ icmp_send(m, opts) } #endif bzero(&ro, sizeof ro); - -#ifdef IPSEC - ipsec_setsocket(m, NULL); -#endif /*IPSEC*/ (void) ip_output(m, opts, &ro, 0, NULL); if (ro.ro_rt) - RTFREE(ro.ro_rt); + rtfree(ro.ro_rt); } n_time @@ -770,7 +800,7 @@ iptime() * given current value MTU. If DIR is less than zero, a larger plateau * is returned; otherwise, a smaller value is returned. */ -/* static */ int +static int ip_next_mtu(mtu, dir) int mtu; int dir; @@ -828,31 +858,45 @@ ip_next_mtu(mtu, dir) int badport_bandlim(int which) { - static int lticks[2]; - static int lpackets[2]; - int dticks; + static struct timeval lticks[BANDLIM_MAX + 1]; + static int lpackets[BANDLIM_MAX + 1]; + struct timeval time; + int secs; + + const char *bandlimittype[] = { + "Limiting icmp unreach response", + "Limiting icmp ping response", + "Limiting icmp tstamp response", + "Limiting closed port RST response", + "Limiting open port RST response" + }; /* * Return ok status if feature disabled or argument out of * ranage. */ - if (icmplim <= 0 || which >= 2 || which < 0) + if (icmplim <= 0 || which > BANDLIM_MAX || which < 0) return(0); - dticks = ticks - lticks[which]; + getmicrotime(&time); + + secs = time.tv_sec - lticks[which].tv_sec ; + /* - * reset stats when cumulative dt exceeds one second. + * reset stats when cumulative delta exceeds one second. */ - if ((unsigned int)dticks > hz) { + if ((secs > 1) || (secs == 1 && (lticks[which].tv_usec > time.tv_usec))) { if (lpackets[which] > icmplim) { - printf("icmp-response bandwidth limit %d/%d pps\n", + printf("%s from %d to %d packets per second\n", + bandlimittype[which], lpackets[which], icmplim ); } - lticks[which] = ticks; + lticks[which].tv_sec = time.tv_sec; + lticks[which].tv_usec = time.tv_usec; lpackets[which] = 0; } @@ -868,4 +912,193 @@ badport_bandlim(int which) #endif +#if __APPLE__ + +/* + * Non-privileged ICMP socket operations + * - send ICMP echo request + * - all ICMP + * - limited socket options + */ + +#include +#include + +extern struct domain inetdomain; +extern u_long rip_sendspace; +extern u_long rip_recvspace; +extern struct inpcbinfo ripcbinfo; + +int rip_abort(struct socket *); +int rip_bind(struct socket *, struct sockaddr *, struct proc *); +int rip_connect(struct socket *, struct sockaddr *, struct proc *); +int rip_detach(struct socket *); +int rip_disconnect(struct socket *); +int rip_shutdown(struct socket *); + +__private_extern__ int icmp_dgram_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, struct mbuf *control, struct proc *p); +__private_extern__ int icmp_dgram_attach(struct socket *so, int proto, struct proc *p); +__private_extern__ int icmp_dgram_ctloutput(struct socket *so, struct sockopt *sopt); + +__private_extern__ struct pr_usrreqs icmp_dgram_usrreqs = { + rip_abort, pru_accept_notsupp, icmp_dgram_attach, rip_bind, rip_connect, + pru_connect2_notsupp, in_control, rip_detach, rip_disconnect, + pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp, + pru_rcvoob_notsupp, icmp_dgram_send, pru_sense_null, rip_shutdown, + in_setsockaddr, sosend, soreceive, sopoll +}; + +/* Like rip_attach but without root privilege enforcement */ +__private_extern__ int +icmp_dgram_attach(struct socket *so, int proto, struct proc *p) +{ + struct inpcb *inp; + int error, s; + + inp = sotoinpcb(so); + if (inp) + panic("icmp_dgram_attach"); + + error = soreserve(so, rip_sendspace, rip_recvspace); + if (error) + return error; + s = splnet(); + error = in_pcballoc(so, &ripcbinfo, p); + splx(s); + if (error) + return error; + inp = (struct inpcb *)so->so_pcb; + inp->inp_vflag |= INP_IPV4; + inp->inp_ip_p = IPPROTO_ICMP; + inp->inp_ip_ttl = ip_defttl; + return 0; +} + +/* + * Raw IP socket option processing. + */ +__private_extern__ int +icmp_dgram_ctloutput(struct socket *so, struct sockopt *sopt) +{ + struct inpcb *inp = sotoinpcb(so); + int error, optval; + + if (sopt->sopt_level != IPPROTO_IP) + return (EINVAL); + + switch (sopt->sopt_name) { + case IP_OPTIONS: + case IP_HDRINCL: + case IP_TOS: + case IP_TTL: + case IP_RECVOPTS: + case IP_RECVRETOPTS: + case IP_RECVDSTADDR: + case IP_RETOPTS: + case IP_MULTICAST_IF: + case IP_MULTICAST_TTL: + case IP_MULTICAST_LOOP: + case IP_ADD_MEMBERSHIP: + case IP_DROP_MEMBERSHIP: + case IP_MULTICAST_VIF: + case IP_PORTRANGE: + case IP_RECVIF: + case IP_IPSEC_POLICY: +#if defined(NFAITH) && NFAITH > 0 + case IP_FAITH: +#endif + case IP_STRIPHDR: + error = rip_ctloutput(so, sopt); + break; + + default: + error = EINVAL; + break; + } + + return (error); +} + +__private_extern__ int +icmp_dgram_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, + struct mbuf *control, struct proc *p) +{ + struct ip *ip; + struct inpcb *inp = sotoinpcb(so); + int hlen; + struct icmp *icp; + struct in_ifaddr *ia = NULL; + int icmplen; + + if ((inp->inp_flags & INP_HDRINCL) != 0) { + /* + * This is not raw IP, we liberal only for fields TOS, id and TTL + */ + ip = mtod(m, struct ip *); + + hlen = IP_VHL_HL(ip->ip_vhl) << 2; + /* Some sanity checks */ + if (m->m_pkthdr.len < hlen + ICMP_MINLEN) { + goto bad; + } + /* Only IPv4 */ + if (IP_VHL_V(ip->ip_vhl) != 4) + goto bad; + if (hlen < 20 || hlen > 40 || ip->ip_len != m->m_pkthdr.len || + ip->ip_len > 65535) + goto bad; + /* Bogus fragments can tie up peer resources */ + if (ip->ip_off != 0) + goto bad; + /* Allow only ICMP even for user provided IP header */ + if (ip->ip_p != IPPROTO_ICMP) + goto bad; + /* To prevent spoofing, specified source address must be one of ours */ + if (ip->ip_src.s_addr != INADDR_ANY) { + if (TAILQ_EMPTY(&in_ifaddrhead)) + goto bad; + TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) { + if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_src.s_addr) + goto ours; + } + goto bad; + } +ours: + /* Do not trust we got a valid checksum */ + ip->ip_sum = 0; + + icp = (struct icmp *)(((char *)m->m_data) + hlen); + icmplen = m->m_pkthdr.len - hlen; + } else { + if ((icmplen = m->m_pkthdr.len) < ICMP_MINLEN) { + goto bad; + } + icp = mtod(m, struct icmp *); + } + /* + * Allow only to send request types with code 0 + */ + if (icp->icmp_code != 0) + goto bad; + switch (icp->icmp_type) { + case ICMP_ECHO: + break; + case ICMP_TSTAMP: + if (icmplen != 20) + goto bad; + break; + case ICMP_MASKREQ: + if (icmplen != 12) + goto bad; + break; + default: + goto bad; + } + return rip_send(so, flags, m, nam, control, p); +bad: + m_freem(m); + return EINVAL; +} + +#endif /* __APPLE__ */ diff --git a/bsd/netinet/ip_icmp.h b/bsd/netinet/ip_icmp.h index 6a9fb7bfb..22e119eb1 100644 --- a/bsd/netinet/ip_icmp.h +++ b/bsd/netinet/ip_icmp.h @@ -52,10 +52,12 @@ * SUCH DAMAGE. * * @(#)ip_icmp.h 8.1 (Berkeley) 6/10/93 + * $FreeBSD: src/sys/netinet/ip_icmp.h,v 1.16 1999/12/29 04:41:01 peter Exp $ */ #ifndef _NETINET_IP_ICMP_H_ #define _NETINET_IP_ICMP_H_ +#include /* * Interface Control Message Protocol Definitions. @@ -205,8 +207,10 @@ struct icmp { (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY) #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE void icmp_error __P((struct mbuf *, int, int, n_long, struct ifnet *)); void icmp_input __P((struct mbuf *, int)); +#endif /* __APPLE_API_PRIVATE */ #endif #endif diff --git a/bsd/netinet/ip_id.c b/bsd/netinet/ip_id.c new file mode 100644 index 000000000..4e7e70980 --- /dev/null +++ b/bsd/netinet/ip_id.c @@ -0,0 +1,210 @@ +/* $OpenBSD: ip_id.c,v 1.2 1999/08/26 13:37:01 provos Exp $ */ + +/* + * Copyright 1998 Niels Provos + * All rights reserved. + * + * Theo de Raadt came up with the idea of using + * such a mathematical system to generate more random (yet non-repeating) + * ids to solve the resolver/named problem. But Niels designed the + * actual system based on the constraints. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Niels Provos. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/sys/netinet/ip_id.c,v 1.1.2.1 2001/07/19 06:37:26 kris Exp $ + */ + +/* + * seed = random 15bit + * n = prime, g0 = generator to n, + * j = random so that gcd(j,n-1) == 1 + * g = g0^j mod n will be a generator again. + * + * X[0] = random seed. + * X[n] = a*X[n-1]+b mod m is a Linear Congruential Generator + * with a = 7^(even random) mod m, + * b = random with gcd(b,m) == 1 + * m = 31104 and a maximal period of m-1. + * + * The transaction id is determined by: + * id[n] = seed xor (g^X[n] mod n) + * + * Effectivly the id is restricted to the lower 15 bits, thus + * yielding two different cycles by toggling the msb on and off. + * This avoids reuse issues caused by reseeding. + */ + +#include "opt_random_ip_id.h" +#include +#include +#include +#include + +#if RANDOM_IP_ID +#define RU_OUT 180 /* Time after wich will be reseeded */ +#define RU_MAX 30000 /* Uniq cycle, avoid blackjack prediction */ +#define RU_GEN 2 /* Starting generator */ +#define RU_N 32749 /* RU_N-1 = 2*2*3*2729 */ +#define RU_AGEN 7 /* determine ru_a as RU_AGEN^(2*rand) */ +#define RU_M 31104 /* RU_M = 2^7*3^5 - don't change */ + +#define PFAC_N 3 +const static u_int16_t pfacts[PFAC_N] = { + 2, + 3, + 2729 +}; + +static u_int16_t ru_x; +static u_int16_t ru_seed, ru_seed2; +static u_int16_t ru_a, ru_b; +static u_int16_t ru_g; +static u_int16_t ru_counter = 0; +static u_int16_t ru_msb = 0; +static long ru_reseed; +static u_int32_t tmp; /* Storage for unused random */ + +static u_int16_t pmod __P((u_int16_t, u_int16_t, u_int16_t)); +static void ip_initid __P((void)); +u_int16_t ip_randomid __P((void)); + +/* + * Do a fast modular exponation, returned value will be in the range + * of 0 - (mod-1) + */ + +#ifdef __STDC__ +static u_int16_t +pmod(u_int16_t gen, u_int16_t exp, u_int16_t mod) +#else +static u_int16_t +pmod(gen, exp, mod) + u_int16_t gen, exp, mod; +#endif +{ + u_int16_t s, t, u; + + s = 1; + t = gen; + u = exp; + + while (u) { + if (u & 1) + s = (s*t) % mod; + u >>= 1; + t = (t*t) % mod; + } + return (s); +} + +/* + * Initalizes the seed and chooses a suitable generator. Also toggles + * the msb flag. The msb flag is used to generate two distinct + * cycles of random numbers and thus avoiding reuse of ids. + * + * This function is called from id_randomid() when needed, an + * application does not have to worry about it. + */ +static void +ip_initid(void) +{ + u_int16_t j, i; + int noprime = 1; + struct timeval time; + + getmicrotime(&time); + read_random((void *) &tmp, sizeof(tmp)); + ru_x = (tmp & 0xFFFF) % RU_M; + + /* 15 bits of random seed */ + ru_seed = (tmp >> 16) & 0x7FFF; + read_random((void *) &tmp, sizeof(tmp)); + ru_seed2 = tmp & 0x7FFF; + + read_random((void *) &tmp, sizeof(tmp)); + + /* Determine the LCG we use */ + ru_b = (tmp & 0xfffe) | 1; + ru_a = pmod(RU_AGEN, (tmp >> 16) & 0xfffe, RU_M); + while (ru_b % 3 == 0) + ru_b += 2; + + read_random((void *) &tmp, sizeof(tmp)); + j = tmp % RU_N; + tmp = tmp >> 16; + + /* + * Do a fast gcd(j,RU_N-1), so we can find a j with + * gcd(j, RU_N-1) == 1, giving a new generator for + * RU_GEN^j mod RU_N + */ + + while (noprime) { + for (i=0; i=PFAC_N) + noprime = 0; + else + j = (j+1) % RU_N; + } + + ru_g = pmod(RU_GEN,j,RU_N); + ru_counter = 0; + + ru_reseed = time.tv_sec + RU_OUT; + ru_msb = ru_msb == 0x8000 ? 0 : 0x8000; +} + +u_int16_t +ip_randomid(void) +{ + int i, n; + struct timeval time; + + getmicrotime(&time); + if (ru_counter >= RU_MAX || time.tv_sec > ru_reseed) + ip_initid(); + + if (!tmp) + read_random((void *) &tmp, sizeof(tmp)); + + /* Skip a random number of ids */ + n = tmp & 0x3; tmp = tmp >> 2; + if (ru_counter + n >= RU_MAX) + ip_initid(); + + for (i = 0; i <= n; i++) + /* Linear Congruential Generator */ + ru_x = (ru_a*ru_x + ru_b) % RU_M; + + ru_counter += i; + + return (ru_seed ^ pmod(ru_g,ru_seed2 ^ ru_x,RU_N)) | ru_msb; +} + +#endif /* RANDOM_IP_ID */ diff --git a/bsd/netinet/ip_input.c b/bsd/netinet/ip_input.c index 13e920615..ce9949bdd 100644 --- a/bsd/netinet/ip_input.c +++ b/bsd/netinet/ip_input.c @@ -52,13 +52,11 @@ * SUCH DAMAGE. * * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 - * $ANA: ip_input.c,v 1.5 1996/09/18 14:34:59 wollman Exp $ + * $FreeBSD: src/sys/netinet/ip_input.c,v 1.130.2.25 2001/08/29 21:41:37 jesper Exp $ */ #define _IP_VHL -#include - #include #include #include @@ -83,31 +81,28 @@ #include #include #include -#ifdef INET6 -#include -#include -#endif #include #include #include #include -#include +#include +/* needed for AUTOCONFIGURING: */ +#include +#include +#include + +#include #define DBG_LAYER_BEG NETDBG_CODE(DBG_NETIP, 0) #define DBG_LAYER_END NETDBG_CODE(DBG_NETIP, 2) #define DBG_FNC_IP_INPUT NETDBG_CODE(DBG_NETIP, (2 << 8)) -#if IPFIREWALL -#include -#endif - #if IPSEC #include #include -#include #endif #include "faith.h" @@ -119,33 +114,62 @@ #include #endif +#if IPSEC +extern int ipsec_bypass; +#endif + int rsvp_on = 0; static int ip_rsvp_on; struct socket *ip_rsvpd; int ipforwarding = 0; SYSCTL_INT(_net_inet_ip, IPCTL_FORWARDING, forwarding, CTLFLAG_RW, - &ipforwarding, 0, ""); + &ipforwarding, 0, "Enable IP forwarding between interfaces"); static int ipsendredirects = 1; /* XXX */ SYSCTL_INT(_net_inet_ip, IPCTL_SENDREDIRECTS, redirect, CTLFLAG_RW, - &ipsendredirects, 0, ""); + &ipsendredirects, 0, "Enable sending IP redirects"); int ip_defttl = IPDEFTTL; SYSCTL_INT(_net_inet_ip, IPCTL_DEFTTL, ttl, CTLFLAG_RW, - &ip_defttl, 0, ""); + &ip_defttl, 0, "Maximum TTL on IP packets"); static int ip_dosourceroute = 0; SYSCTL_INT(_net_inet_ip, IPCTL_SOURCEROUTE, sourceroute, CTLFLAG_RW, - &ip_dosourceroute, 0, ""); + &ip_dosourceroute, 0, "Enable forwarding source routed IP packets"); static int ip_acceptsourceroute = 0; -SYSCTL_INT(_net_inet_ip, IPCTL_ACCEPTSOURCEROUTE, accept_sourceroute, - CTLFLAG_RW, &ip_acceptsourceroute, 0, ""); +SYSCTL_INT(_net_inet_ip, IPCTL_ACCEPTSOURCEROUTE, accept_sourceroute, + CTLFLAG_RW, &ip_acceptsourceroute, 0, + "Enable accepting source routed IP packets"); static int ip_keepfaith = 0; SYSCTL_INT(_net_inet_ip, IPCTL_KEEPFAITH, keepfaith, CTLFLAG_RW, - &ip_keepfaith, 0, ""); + &ip_keepfaith, 0, + "Enable packet capture for FAITH IPv4->IPv6 translater daemon"); + +static int ip_nfragpackets = 0; +static int ip_maxfragpackets; /* initialized in ip_init() */ +SYSCTL_INT(_net_inet_ip, OID_AUTO, maxfragpackets, CTLFLAG_RW, + &ip_maxfragpackets, 0, + "Maximum number of IPv4 fragment reassembly queue entries"); + +/* + * XXX - Setting ip_checkinterface mostly implements the receive side of + * the Strong ES model described in RFC 1122, but since the routing table + * and transmit implementation do not implement the Strong ES model, + * setting this to 1 results in an odd hybrid. + * + * XXX - ip_checkinterface currently must be disabled if you use ipnat + * to translate the destination address to another local interface. + * + * XXX - ip_checkinterface must be disabled if you add IP aliases + * to the loopback interface instead of the interface where the + * packets for those addresses are received. + */ +static int ip_checkinterface = 0; +SYSCTL_INT(_net_inet_ip, OID_AUTO, check_interface, CTLFLAG_RW, + &ip_checkinterface, 0, "Verify packet arrives on correct interface"); #if DIAGNOSTIC static int ipprintfs = 0; @@ -157,54 +181,64 @@ struct protosw *ip_protox[IPPROTO_MAX]; static int ipqmaxlen = IFQ_MAXLEN; struct in_ifaddrhead in_ifaddrhead; /* first inet address */ struct ifqueue ipintrq; -SYSCTL_INT(_net_inet_ip, IPCTL_INTRQMAXLEN, intr_queue_maxlen, CTLFLAG_RD, - &ipintrq.ifq_maxlen, 0, ""); +SYSCTL_INT(_net_inet_ip, IPCTL_INTRQMAXLEN, intr_queue_maxlen, CTLFLAG_RW, + &ipintrq.ifq_maxlen, 0, "Maximum size of the IP input queue"); SYSCTL_INT(_net_inet_ip, IPCTL_INTRQDROPS, intr_queue_drops, CTLFLAG_RD, - &ipintrq.ifq_drops, 0, ""); + &ipintrq.ifq_drops, 0, "Number of packets dropped from the IP input queue"); struct ipstat ipstat; SYSCTL_STRUCT(_net_inet_ip, IPCTL_STATS, stats, CTLFLAG_RD, - &ipstat, ipstat, ""); + &ipstat, ipstat, "IP statistics (struct ipstat, netinet/ip_var.h)"); /* Packet reassembly stuff */ #define IPREASS_NHASH_LOG2 6 #define IPREASS_NHASH (1 << IPREASS_NHASH_LOG2) #define IPREASS_HMASK (IPREASS_NHASH - 1) #define IPREASS_HASH(x,y) \ - ((((x) & 0xF | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPREASS_HMASK) + (((((x) & 0xF) | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPREASS_HMASK) static struct ipq ipq[IPREASS_NHASH]; static int nipq = 0; /* total # of reass queues */ static int maxnipq; +const int ipintrq_present = 1; #if IPCTL_DEFMTU SYSCTL_INT(_net_inet_ip, IPCTL_DEFMTU, mtu, CTLFLAG_RW, - &ip_mtu, 0, ""); + &ip_mtu, 0, "Default MTU"); #endif -#if !defined(COMPAT_IPFW) || COMPAT_IPFW == 1 -#undef COMPAT_IPFW -#define COMPAT_IPFW 1 -#else -#undef COMPAT_IPFW +#if IPSTEALTH +static int ipstealth = 0; +SYSCTL_INT(_net_inet_ip, OID_AUTO, stealth, CTLFLAG_RW, + &ipstealth, 0, ""); #endif -#if COMPAT_IPFW - -#include /* Firewall hooks */ ip_fw_chk_t *ip_fw_chk_ptr; ip_fw_ctl_t *ip_fw_ctl_ptr; +int fw_enable = 1 ; #if DUMMYNET ip_dn_ctl_t *ip_dn_ctl_ptr; #endif -/* IP Network Address Translation (NAT) hooks */ -ip_nat_t *ip_nat_ptr; -ip_nat_ctl_t *ip_nat_ctl_ptr; -#endif +int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int, struct mbuf **)) = NULL; + +SYSCTL_NODE(_net_inet_ip, OID_AUTO, linklocal, CTLFLAG_RW, 0, "link local"); + +struct ip_linklocal_stat ip_linklocal_stat; +SYSCTL_STRUCT(_net_inet_ip_linklocal, OID_AUTO, stat, CTLFLAG_RD, + &ip_linklocal_stat, ip_linklocal_stat, + "Number of link local packets with TTL less than 255"); + +SYSCTL_NODE(_net_inet_ip_linklocal, OID_AUTO, in, CTLFLAG_RW, 0, "link local input"); + +int ip_linklocal_in_allowbadttl = 0; +SYSCTL_INT(_net_inet_ip_linklocal_in, OID_AUTO, allowbadttl, CTLFLAG_RW, + &ip_linklocal_in_allowbadttl, 0, + "Allow incoming link local packets with TTL less than 255"); + /* * We need to save the IP options in case a protocol wants to respond @@ -221,44 +255,33 @@ static struct ip_srcrt { struct in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)]; } ip_srcrt; -#if IPDIVERT -/* - * Shared variable between ip_input() and ip_reass() to communicate - * about which packets, once assembled from fragments, get diverted, - * and to which port. - */ -static u_short frag_divert_port; -#endif - struct sockaddr_in *ip_fw_fwd_addr; -static void save_rte __P((u_char *, struct in_addr)); -static int ip_dooptions __P((struct mbuf *)); -#ifndef NATPT -static +#ifdef __APPLE__ +extern struct mbuf* m_dup(register struct mbuf *m, int how); #endif -void ip_forward __P((struct mbuf *, int)); -static void ip_freef __P((struct ipq *)); -static struct ip * - ip_reass __P((struct mbuf *, struct ipq *, struct ipq *)); -static struct in_ifaddr * - ip_rtaddr __P((struct in_addr)); -void ipintr __P((void)); - -#if PM -extern int doNatFil; -extern int doRoute; -extern int pm_in __P((struct ifnet *, struct ip *, struct mbuf *)); -extern struct route *pm_route __P((struct mbuf *)); +static void save_rte __P((u_char *, struct in_addr)); +static int ip_dooptions __P((struct mbuf *)); +static void ip_forward __P((struct mbuf *, int)); +static void ip_freef __P((struct ipq *)); +#if IPDIVERT +#ifdef IPDIVERT_44 +static struct mbuf *ip_reass __P((struct mbuf *, + struct ipq *, struct ipq *, u_int32_t *, u_int16_t *)); +#else +static struct mbuf *ip_reass __P((struct mbuf *, + struct ipq *, struct ipq *, u_int16_t *, u_int16_t *)); #endif +#else +static struct mbuf *ip_reass __P((struct mbuf *, struct ipq *, struct ipq *)); +#endif +static struct in_ifaddr *ip_rtaddr __P((struct in_addr)); +void ipintr __P((void)); -#if defined(NATPT) -extern int ip6_protocol_tr; - -int natpt_in4 __P((struct mbuf *, struct mbuf **)); - -#endif /* NATPT */ +#if RANDOM_IP_ID +extern u_short ip_id; +#endif /* * IP initialization: fill in IP protocol switch table. @@ -288,16 +311,13 @@ ip_init() for (i = 0; i < IPREASS_NHASH; i++) ipq[i].next = ipq[i].prev = &ipq[i]; - maxnipq = nmbclusters/4; + maxnipq = nmbclusters / 4; + ip_maxfragpackets = nmbclusters / 4; +#if RANDOM_IP_ID ip_id = time_second & 0xffff; - ipintrq.ifq_maxlen = ipqmaxlen; -#if DUMMYNET - ip_dn_init(); -#endif -#if IPNAT - ip_nat_init(); #endif + ipintrq.ifq_maxlen = ipqmaxlen; ip_initialized = 1; } } @@ -312,7 +332,8 @@ in_dinit() extern int in_proto_count; if (!inetdomain_initted) - { kprintf("Initing %d protosw entries\n", in_proto_count); + { + kprintf("Initing %d protosw entries\n", in_proto_count); dp = &inetdomain; for (i=0, pr = &inetsw[0]; im_type == MT_DUMMYNET) { - struct mbuf *m0 = m ; rule = (struct ip_fw_chain *)(m->m_data) ; m = m->m_next ; - FREE(m0, M_IPFW); ip = mtod(m, struct ip *); hlen = IP_VHL_HL(ip->ip_vhl) << 2; goto iphack ; @@ -365,14 +392,6 @@ ip_input(struct mbuf *m) if (m == NULL || (m->m_flags & M_PKTHDR) == 0) panic("ip_input no HDR"); #endif - /* - * If no IP addresses have been set yet but the interfaces - * are receiving, can't do anything with incoming packets yet. - * XXX This is broken! We should be able to receive broadcasts - * and multicasts even without any local addresses configured. - */ - if (TAILQ_EMPTY(&in_ifaddrhead)) - goto bad; ipstat.ips_total++; if (m->m_pkthdr.len < sizeof(struct ip)) @@ -406,14 +425,39 @@ ip_input(struct mbuf *m) ip = mtod(m, struct ip *); } - if (m->m_pkthdr.rcvif->if_hwassist == 0) + /* 127/8 must not appear on wire - RFC1122 */ + if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET || + (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) { + if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) { +#ifndef __APPLE__ + ipstat.ips_badaddr++; +#endif + goto bad; + } + } + + /* IPv4 Link-Local Addresses as defined in */ + if ((IN_LINKLOCAL(ntohl(ip->ip_dst.s_addr)) || + IN_LINKLOCAL(ntohl(ip->ip_src.s_addr)))) { + ip_linklocal_stat.iplls_in_total++; + if (ip->ip_ttl != MAXTTL) { + ip_linklocal_stat.iplls_in_badttl++; + /* Silently drop link local traffic with bad TTL */ + if (ip_linklocal_in_allowbadttl != 0) + goto bad; + } + } + if (m->m_pkthdr.rcvif->if_hwassist == 0) m->m_pkthdr.csum_flags = 0; - if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) { - sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID); - } else - sum = in_cksum(m, hlen); + if ((m->m_pkthdr.csum_flags & CSUM_TCP_SUM16) && ip->ip_p != IPPROTO_TCP) + m->m_pkthdr.csum_flags = 0; + if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) { + sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID); + } else { + sum = in_cksum(m, hlen); + } if (sum) { ipstat.ips_badsum++; goto bad; @@ -427,7 +471,6 @@ ip_input(struct mbuf *m) ipstat.ips_badlen++; goto bad; } - NTOHS(ip->ip_id); NTOHS(ip->ip_off); /* @@ -452,6 +495,12 @@ tooshort: } else m_adj(m, ip->ip_len - m->m_pkthdr.len); } + +#if IPSEC + if (ipsec_bypass == 0 && ipsec_gethist(m, NULL)) + goto pass; +#endif + /* * IpHack's section. * Right now when no processing on packet has done @@ -467,8 +516,18 @@ tooshort: #if defined(IPFIREWALL) && defined(DUMMYNET) iphack: #endif -#if COMPAT_IPFW - if (ip_fw_chk_ptr) { + /* + * Check if we want to allow this packet to be processed. + * Consider it to be bad if not. + */ + if (fr_checkp) { + struct mbuf *m1 = m; + + if ((*fr_checkp)(ip, hlen, m->m_pkthdr.rcvif, 0, &m1) || !m1) + return; + ip = mtod(m = m1, struct ip *); + } + if (fw_enable && ip_fw_chk_ptr) { #if IPFIREWALL_FORWARD /* * If we've been forwarded from the output side, then @@ -477,85 +536,45 @@ iphack: if (ip_fw_fwd_addr) goto ours; #endif /* IPFIREWALL_FORWARD */ - i = (*ip_fw_chk_ptr)(&ip, hlen, NULL, &ip_divert_cookie, - &m, &rule, &ip_fw_fwd_addr); /* - * see the comment in ip_output for the return values + * See the comment in ip_output for the return values * produced by the firewall. */ - if (!m) /* packet discarded by firewall */ - return ; - if (i == 0 && ip_fw_fwd_addr == NULL) /* common case */ - goto pass ; + i = (*ip_fw_chk_ptr)(&ip, + hlen, NULL, &divert_cookie, &m, &rule, &ip_fw_fwd_addr); + if ( (i & IP_FW_PORT_DENY_FLAG) || m == NULL) { /* drop */ + if (m) + m_freem(m); + return; + } + ip = mtod(m, struct ip *); /* just in case m changed */ + if (i == 0 && ip_fw_fwd_addr == NULL) /* common case */ + goto pass; #if DUMMYNET - if (i & 0x10000) { - /* send packet to the appropriate pipe */ - dummynet_io(i&0xffff,DN_TO_IP_IN,m,NULL,NULL,0, rule); - return ; + if ((i & IP_FW_PORT_DYNT_FLAG) != 0) { + /* send packet to the appropriate pipe */ + dummynet_io(i&0xffff,DN_TO_IP_IN,m,NULL,NULL,0, rule); + return; } #endif #if IPDIVERT - if (i > 0 && i < 0x10000) { - /* Divert packet */ - frag_divert_port = i & 0xffff ; + if (i != 0 && (i & IP_FW_PORT_DYNT_FLAG) == 0) { + /* Divert or tee packet */ + divert_info = i; goto ours; } #endif #if IPFIREWALL_FORWARD if (i == 0 && ip_fw_fwd_addr != NULL) - goto pass ; + goto pass; #endif /* * if we get here, the packet must be dropped */ - m_freem(m); - return; - } -pass: - - if (ip_nat_ptr && !(*ip_nat_ptr)(&ip, &m, m->m_pkthdr.rcvif, IP_NAT_IN)) { -#if IPFIREWALL_FORWARD - ip_fw_fwd_addr = NULL; -#endif - return; - } -#endif /* !COMPAT_IPFW */ - -#if defined(PM) - /* - * Process ip-filter/NAT. - * Return TRUE if this packed is discarded. - * Return FALSE if this packed is accepted. - */ - - if (doNatFil && pm_in(m->m_pkthdr.rcvif, ip, m)) - return; -#endif - -#if defined(NATPT) - /* - * - */ - if (ip6_protocol_tr) - { - struct mbuf *m1 = NULL; - - switch (natpt_in4(m, &m1)) - { - case IPPROTO_IP: goto dooptions; - case IPPROTO_IPV4: ip_forward(m1, 0); break; - case IPPROTO_IPV6: ip6_forward(m1, 1); break; - case IPPROTO_MAX: /* discard this packet */ - default: - } - - if (m != m1) m_freem(m); - - return; + return; } - dooptions: -#endif +pass: /* * Process options and, if not destined for us, @@ -582,37 +601,66 @@ pass: /* * Check our list of addresses, to see if the packet is for us. + * If we don't have any addresses, assume any unicast packet + * we receive might be for us (and let the upper layers deal + * with it). */ - for (ia = TAILQ_FIRST(&in_ifaddrhead); ia; - ia = TAILQ_NEXT(ia, ia_link)) { -#define satosin(sa) ((struct sockaddr_in *)(sa)) + if (TAILQ_EMPTY(&in_ifaddrhead) && + (m->m_flags & (M_MCAST|M_BCAST)) == 0) + goto ours; - if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr) - goto ours; + /* + * Cache the destination address of the packet; this may be + * changed by use of 'ipfw fwd'. + */ + pkt_dst = ip_fw_fwd_addr == NULL ? + ip->ip_dst : ip_fw_fwd_addr->sin_addr; + + /* + * Enable a consistency check between the destination address + * and the arrival interface for a unicast packet (the RFC 1122 + * strong ES model) if IP forwarding is disabled and the packet + * is not locally generated and the packet is not subject to + * 'ipfw fwd'. + * + * XXX - Checking also should be disabled if the destination + * address is ipnat'ed to a different interface. + * + * XXX - Checking is incompatible with IP aliases added + * to the loopback interface instead of the interface where + * the packets are received. + */ + checkif = ip_checkinterface && (ipforwarding == 0) && + ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) && + (ip_fw_fwd_addr == NULL); + + TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) { +#define satosin(sa) ((struct sockaddr_in *)(sa)) if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY) goto ours; - -#if IPFIREWALL_FORWARD + /* - * If the addr to forward to is one of ours, we pretend to - * be the destination for this packet. + * If the address matches, verify that the packet + * arrived via the correct interface if checking is + * enabled. */ - if (ip_fw_fwd_addr == NULL) { - if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr) - goto ours; - } else if (IA_SIN(ia)->sin_addr.s_addr == - ip_fw_fwd_addr->sin_addr.s_addr) - goto ours; -#else - if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr) + if (IA_SIN(ia)->sin_addr.s_addr == pkt_dst.s_addr && + (!checkif || ia->ia_ifp == m->m_pkthdr.rcvif)) goto ours; -#endif - if (ia->ia_ifp && ia->ia_ifp->if_flags & IFF_BROADCAST) { + /* + * Only accept broadcast packets that arrive via the + * matching interface. Reception of forwarded directed + * broadcasts would be handled via ip_forward() and + * ether_output() with the loopback into the stack for + * SIMPLEX interfaces handled by ether_output(). + */ + if (ia->ia_ifp == m->m_pkthdr.rcvif && + ia->ia_ifp && ia->ia_ifp->if_flags & IFF_BROADCAST) { if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == - ip->ip_dst.s_addr) + pkt_dst.s_addr) goto ours; - if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr) + if (ia->ia_netbroadcast.s_addr == pkt_dst.s_addr) goto ours; } } @@ -626,18 +674,12 @@ pass: * The packet is returned (relatively) intact; if * ip_mforward() returns a non-zero value, the packet * must be discarded, else it may be accepted below. - * - * (The IP ident field is put in the same byte order - * as expected when ip_mforward() is called from - * ip_output().) */ - ip->ip_id = htons(ip->ip_id); if (ip_mforward(ip, m->m_pkthdr.rcvif, m, 0) != 0) { ipstat.ips_cantforward++; m_freem(m); return; } - ip->ip_id = ntohs(ip->ip_id); /* * The process-level routing demon needs to receive @@ -665,13 +707,25 @@ pass: if (ip->ip_dst.s_addr == INADDR_ANY) goto ours; - if (m->m_pkthdr.rcvif + /* Allow DHCP/BootP responses through */ + if (m->m_pkthdr.rcvif != NULL && (m->m_pkthdr.rcvif->if_eflags & IFEF_AUTOCONFIGURING) + && hlen == sizeof(struct ip) && ip->ip_p == IPPROTO_UDP) { - goto ours; + struct udpiphdr *ui; + if (m->m_len < sizeof(struct udpiphdr) + && (m = m_pullup(m, sizeof(struct udpiphdr))) == 0) { + udpstat.udps_hdrops++; + return; + } + ui = mtod(m, struct udpiphdr *); + if (ntohs(ui->ui_dport) == IPPORT_BOOTPC) { + goto ours; + } + ip = mtod(m, struct ip *); /* in case it changed */ } -#if defined(NFAITH) && NFAITH > 0 +#if defined(NFAITH) && 0 < NFAITH /* * FAITH(Firewall Aided Internet Translator) */ @@ -698,6 +752,14 @@ pass: return; ours: +#ifndef __APPLE__ + /* Darwin does not have an if_data in ifaddr */ + /* Count the packet in the ip address stats */ + if (ia != NULL) { + ia->ia_ifa.if_ipackets++; + ia->ia_ifa.if_ibytes += m->m_pkthdr.len; + } +#endif /* * If offset or IP_MF are set, must reassemble. @@ -707,13 +769,14 @@ ours: * but it's not worth the time; just let them time out.) */ if (ip->ip_off & (IP_MF | IP_OFFMASK | IP_RF)) { + +#if 0 /* + * Reassembly should be able to treat a mbuf cluster, for later + * operation of contiguous protocol headers on the cluster. (KAME) + */ if (m->m_flags & M_EXT) { /* XXX */ if ((m = m_pullup(m, hlen)) == 0) { ipstat.ips_toosmall++; -#if IPDIVERT - frag_divert_port = 0; - ip_divert_cookie = 0; -#endif #if IPFIREWALL_FORWARD ip_fw_fwd_addr = NULL; #endif @@ -721,6 +784,7 @@ ours: } ip = mtod(m, struct ip *); } +#endif sum = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id); /* * Look for queue of fragments @@ -780,30 +844,30 @@ found: if (mff || ip->ip_off) { ipstat.ips_fragments++; m->m_pkthdr.header = ip; - ip = ip_reass(m, fp, &ipq[sum]); - if (ip == 0) { +#if IPDIVERT + m = ip_reass(m, + fp, &ipq[sum], &divert_info, &divert_cookie); +#else + m = ip_reass(m, fp, &ipq[sum]); +#endif + if (m == 0) { #if IPFIREWALL_FORWARD ip_fw_fwd_addr = NULL; #endif return; } - /* Get the length of the reassembled packets header */ - hlen = IP_VHL_HL(ip->ip_vhl) << 2; ipstat.ips_reassembled++; - m = dtom(ip); + ip = mtod(m, struct ip *); + /* Get the header length of the reassembled packet */ + hlen = IP_VHL_HL(ip->ip_vhl) << 2; #if IPDIVERT - if (frag_divert_port) { - struct mbuf m; - m.m_next = 0; - m.m_len = hlen; - m.m_data = (char *) ip; + /* Restore original checksum before diverting packet */ + if (divert_info != 0) { ip->ip_len += hlen; HTONS(ip->ip_len); HTONS(ip->ip_off); - HTONS(ip->ip_id); ip->ip_sum = 0; - ip->ip_sum = in_cksum(&m, hlen); - NTOHS(ip->ip_id); + ip->ip_sum = in_cksum(m, hlen); NTOHS(ip->ip_off); NTOHS(ip->ip_len); ip->ip_len -= hlen; @@ -817,39 +881,63 @@ found: #if IPDIVERT /* - * Divert reassembled packets to the divert protocol if required - * If divert port is null then cookie should be too, - * so we shouldn't need to clear them here. Assume ip_divert does so. + * Divert or tee packet to the divert protocol if required. + * + * If divert_info is zero then cookie should be too, so we shouldn't + * need to clear them here. Assume divert_packet() does so also. */ - if (frag_divert_port) { + if (divert_info != 0) { + struct mbuf *clone = NULL; + + /* Clone packet if we're doing a 'tee' */ + if ((divert_info & IP_FW_PORT_TEE_FLAG) != 0) + clone = m_dup(m, M_DONTWAIT); + + /* Restore packet header fields to original values */ + ip->ip_len += hlen; + HTONS(ip->ip_len); + HTONS(ip->ip_off); + + /* Deliver packet to divert input routine */ + ip_divert_cookie = divert_cookie; + divert_packet(m, 1, divert_info & 0xffff); ipstat.ips_delivered++; - ip_divert_port = frag_divert_port; - frag_divert_port = 0; - (*ip_protox[IPPROTO_DIVERT]->pr_input)(m, hlen); - return; + + /* If 'tee', continue with original packet */ + if (clone == NULL) + return; + m = clone; + ip = mtod(m, struct ip *); } +#endif - /* Don't let packets divert themselves */ - if (ip->ip_p == IPPROTO_DIVERT) { - ipstat.ips_noproto++; +#if IPSEC + /* + * enforce IPsec policy checking if we are seeing last header. + * note that we do not visit this with protocols with pcb layer + * code - like udp/tcp/raw ip. + */ + if (ipsec_bypass == 0 && (ip_protox[ip->ip_p]->pr_flags & PR_LASTHDR) != 0 && + ipsec4_in_reject(m, NULL)) { + ipsecstat.in_polvio++; goto bad; } - #endif /* * Switch out to protocol's input routine. */ ipstat.ips_delivered++; - - KERNEL_DEBUG(DBG_LAYER_END, ip->ip_dst.s_addr, + { + KERNEL_DEBUG(DBG_LAYER_END, ip->ip_dst.s_addr, ip->ip_src.s_addr, ip->ip_p, ip->ip_off, ip->ip_len); - (*ip_protox[ip->ip_p]->pr_input)(m, hlen); + (*ip_protox[ip->ip_p]->pr_input)(m, hlen); #if IPFIREWALL_FORWARD - ip_fw_fwd_addr = NULL; /* tcp needed it */ + ip_fw_fwd_addr = NULL; /* tcp needed it */ #endif - return; + return; + } bad: #if IPFIREWALL_FORWARD ip_fw_fwd_addr = NULL; @@ -885,16 +973,31 @@ ipintr(void) NETISR_SET(NETISR_IP, ipintr); /* - * 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. + * 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. + * + * When IPDIVERT enabled, keep additional state with each packet that + * tells us if we need to divert or tee the packet we're building. */ -static struct ip * + +static struct mbuf * +#if IPDIVERT +ip_reass(m, fp, where, divinfo, divcookie) +#else ip_reass(m, fp, where) +#endif register struct mbuf *m; register struct ipq *fp; struct ipq *where; +#if IPDIVERT +#ifdef IPDIVERT_44 + u_int32_t *divinfo; +#else + u_int16_t *divinfo; +#endif + u_int16_t *divcookie; +#endif { struct ip *ip = mtod(m, struct ip *); register struct mbuf *p = 0, *q, *nq; @@ -915,10 +1018,19 @@ ip_reass(m, fp, where) * If first fragment to arrive, create a reassembly queue. */ if (fp == 0) { + /* + * Enforce upper bound on number of fragmented packets + * for which we attempt reassembly; + * If maxfrag is 0, never accept fragments. + * If maxfrag is -1, accept all fragments without limitation. + */ + if ((ip_maxfragpackets >= 0) && (ip_nfragpackets >= ip_maxfragpackets)) + goto dropfrag; + ip_nfragpackets++; if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL) goto dropfrag; fp = mtod(t, struct ipq *); - insque((void *) fp, (void *) where); + insque((void*)fp, (void*)where); nipq++; fp->ipq_ttl = IPFRAGTTL; fp->ipq_p = ip->ip_p; @@ -928,7 +1040,11 @@ ip_reass(m, fp, where) fp->ipq_frags = m; m->m_nextpkt = NULL; #if IPDIVERT +#ifdef IPDIVERT_44 + fp->ipq_div_info = 0; +#else fp->ipq_divert = 0; +#endif fp->ipq_div_cookie = 0; #endif goto inserted; @@ -948,14 +1064,17 @@ ip_reass(m, fp, where) * our data already. If so, drop the data from the incoming * segment. If it provides all of our data, drop us, otherwise * stick new segment in the proper place. + * + * If some of the data is dropped from the the preceding + * segment, then it's checksum is invalidated. */ if (p) { i = GETIP(p)->ip_off + GETIP(p)->ip_len - ip->ip_off; if (i > 0) { if (i >= ip->ip_len) goto dropfrag; - m_adj(dtom(ip), i); - m->m_pkthdr.csum_flags = 0; + m_adj(m, i); + m->m_pkthdr.csum_flags = 0; ip->ip_off += i; ip->ip_len -= i; } @@ -978,7 +1097,7 @@ ip_reass(m, fp, where) GETIP(q)->ip_len -= i; GETIP(q)->ip_off += i; m_adj(q, i); - q->m_pkthdr.csum_flags = 0; + q->m_pkthdr.csum_flags = 0; break; } nq = q->m_nextpkt; @@ -990,14 +1109,17 @@ inserted: #if IPDIVERT /* - * Any fragment diverting causes the whole packet to divert + * Transfer firewall instructions to the fragment structure. + * Any fragment diverting causes the whole packet to divert. */ - if (frag_divert_port) { - fp->ipq_divert = frag_divert_port; - fp->ipq_div_cookie = ip_divert_cookie; - } - frag_divert_port = 0; - ip_divert_cookie = 0; +#ifdef IPDIVERT_44 + fp->ipq_div_info = *divinfo; +#else + fp->ipq_divert = *divinfo; +#endif + fp->ipq_div_cookie = *divcookie; + *divinfo = 0; + *divcookie = 0; #endif /* @@ -1037,20 +1159,24 @@ inserted: nq = q->m_nextpkt; q->m_nextpkt = NULL; if (q->m_pkthdr.csum_flags & CSUM_TCP_SUM16) - m->m_pkthdr.csum_flags = 0; + m->m_pkthdr.csum_flags = 0; else { - m->m_pkthdr.csum_data += q->m_pkthdr.csum_data ; - m->m_pkthdr.csum_flags &= q->m_pkthdr.csum_flags; + m->m_pkthdr.csum_flags &= q->m_pkthdr.csum_flags; + m->m_pkthdr.csum_data += q->m_pkthdr.csum_data; } m_cat(m, q); } #if IPDIVERT /* - * extract divert port for packet, if any + * Extract firewall instructions from the fragment structure. */ - frag_divert_port = fp->ipq_divert; - ip_divert_cookie = fp->ipq_div_cookie; +#ifdef IPDIVERT_44 + *divinfo = fp->ipq_div_info; +#else + *divinfo = fp->ipq_divert; +#endif + *divcookie = fp->ipq_div_cookie; #endif /* @@ -1062,24 +1188,25 @@ inserted: ip->ip_len = next; ip->ip_src = fp->ipq_src; ip->ip_dst = fp->ipq_dst; - remque((void *) fp); + remque((void*)fp); nipq--; (void) m_free(dtom(fp)); + ip_nfragpackets--; m->m_len += (IP_VHL_HL(ip->ip_vhl) << 2); m->m_data -= (IP_VHL_HL(ip->ip_vhl) << 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; + for (t = m; t; t = t->m_next) + plen += t->m_len; + m->m_pkthdr.len = plen; } - return (ip); + return (m); dropfrag: #if IPDIVERT - frag_divert_port = 0; - ip_divert_cookie = 0; + *divinfo = 0; + *divcookie = 0; #endif ipstat.ips_fragdropped++; m_freem(m); @@ -1103,8 +1230,9 @@ ip_freef(fp) fp->ipq_frags = q->m_nextpkt; m_freem(q); } - remque((void *) fp); + remque((void*)fp); (void) m_free(dtom(fp)); + ip_nfragpackets--; nipq--; } @@ -1133,6 +1261,20 @@ ip_slowtimo() } } } + /* + * If we are over the maximum number of fragments + * (due to the limit being lowered), drain off + * enough to get down to the new limit. + */ + for (i = 0; i < IPREASS_NHASH; i++) { + if (ip_maxfragpackets >= 0) { + while ((ip_nfragpackets > ip_maxfragpackets) && + (ipq[i].next != &ipq[i])) { + ipstat.ips_fragdropped++; + ip_freef(ipq[i].next); + } + } + } ipflow_slowtimo(); splx(s); } @@ -1184,7 +1326,7 @@ ip_dooptions(m) optlen = 1; else { if (cnt < IPOPT_OLEN + sizeof(*cp)) { - code = &cp[IPOPT_OLEN] - (u_char *)ip; + code = &cp[IPOPT_OLEN] - (u_char *)ip; goto bad; } optlen = cp[IPOPT_OLEN]; @@ -1209,6 +1351,10 @@ ip_dooptions(m) */ case IPOPT_LSRR: case IPOPT_SSRR: + if (optlen < IPOPT_OFFSET + sizeof(*cp)) { + code = &cp[IPOPT_OLEN] - (u_char *)ip; + goto bad; + } if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { code = &cp[IPOPT_OFFSET] - (u_char *)ip; goto bad; @@ -1231,7 +1377,7 @@ ip_dooptions(m) break; } off--; /* 0 origin */ - if (off > optlen - sizeof(struct in_addr)) { + if (off > optlen - (int)sizeof(struct in_addr)) { /* * End of source route. Should be for us. */ @@ -1306,7 +1452,7 @@ nosourcerouting: * If no space remains, ignore. */ off--; /* 0 origin */ - if (off > optlen - sizeof(struct in_addr)) + if (off > optlen - (int)sizeof(struct in_addr)) break; (void)memcpy(&ipaddr.sin_addr, &ip->ip_dst, sizeof(ipaddr.sin_addr)); @@ -1328,11 +1474,21 @@ nosourcerouting: case IPOPT_TS: code = cp - (u_char *)ip; ipt = (struct ip_timestamp *)cp; - if (ipt->ipt_len < 5) + if (ipt->ipt_len < 4 || ipt->ipt_len > 40) { + code = (u_char *)&ipt->ipt_len - (u_char *)ip; goto bad; - if (ipt->ipt_ptr > ipt->ipt_len - sizeof(int32_t)) { - if (++ipt->ipt_oflw == 0) + } + if (ipt->ipt_ptr < 5) { + code = (u_char *)&ipt->ipt_ptr - (u_char *)ip; + goto bad; + } + if (ipt->ipt_ptr > + ipt->ipt_len - (int)sizeof(int32_t)) { + if (++ipt->ipt_oflw == 0) { + code = (u_char *)&ipt->ipt_ptr - + (u_char *)ip; goto bad; + } break; } sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); @@ -1343,8 +1499,11 @@ nosourcerouting: case IPOPT_TS_TSANDADDR: if (ipt->ipt_ptr - 1 + sizeof(n_time) + - sizeof(struct in_addr) > ipt->ipt_len) + sizeof(struct in_addr) > ipt->ipt_len) { + code = (u_char *)&ipt->ipt_ptr - + (u_char *)ip; goto bad; + } ipaddr.sin_addr = dst; ia = (INA)ifaof_ifpforaddr((SA)&ipaddr, m->m_pkthdr.rcvif); @@ -1357,8 +1516,11 @@ nosourcerouting: case IPOPT_TS_PRESPEC: if (ipt->ipt_ptr - 1 + sizeof(n_time) + - sizeof(struct in_addr) > ipt->ipt_len) + sizeof(struct in_addr) > ipt->ipt_len) { + code = (u_char *)&ipt->ipt_ptr - + (u_char *)ip; goto bad; + } (void)memcpy(&ipaddr.sin_addr, sin, sizeof(struct in_addr)); if (ifa_ifwithaddr((SA)&ipaddr) == 0) @@ -1367,6 +1529,9 @@ nosourcerouting: break; default: + /* XXX can't take &ipt->ipt_flg */ + code = (u_char *)&ipt->ipt_ptr - + (u_char *)ip + 1; goto bad; } ntime = iptime(); @@ -1401,7 +1566,7 @@ ip_rtaddr(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); + rtfree(ipforward_rt.ro_rt); ipforward_rt.ro_rt = 0; } sin->sin_family = AF_INET; @@ -1540,7 +1705,7 @@ u_char inetctlerrmap[PRC_NCMDS] = { EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, EMSGSIZE, EHOSTUNREACH, 0, 0, 0, 0, 0, 0, - ENOPROTOOPT + ENOPROTOOPT, ECONNREFUSED }; /* @@ -1557,10 +1722,7 @@ u_char inetctlerrmap[PRC_NCMDS] = { * The srcrt parameter indicates whether the packet is being forwarded * via a source route. */ -#ifndef NATPT -static -#endif -void +static void ip_forward(m, srcrt) struct mbuf *m; int srcrt; @@ -1585,34 +1747,20 @@ ip_forward(m, srcrt) #endif - if (m->m_flags & M_BCAST || in_canforward(ip->ip_dst) == 0) { + if (m->m_flags & (M_BCAST|M_MCAST) || 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, 0); - return; - } - ip->ip_ttl -= IPTTLDEC; - -#if defined(PM) - if (doRoute) - { - struct route *ipfw_rt; - - if ((ipfw_rt = pm_route(m)) != NULL) - { - mcopy = m_copy(m, 0, imin((int)ip->ip_len, 64)); -#if IPSEC - ipsec_setsocket(m, NULL); -#endif /*IPSEC*/ - error = ip_output(m, (struct mbuf *)0, ipfw_rt, - IP_FORWARDING | IP_PROTOCOLROUTE , 0); - goto clearAway; - } - +#if IPSTEALTH + if (!ipstealth) { +#endif + if (ip->ip_ttl <= IPTTLDEC) { + icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, + dest, 0); + return; + } +#if IPSTEALTH } #endif @@ -1620,7 +1768,7 @@ ip_forward(m, srcrt) 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); + rtfree(ipforward_rt.ro_rt); ipforward_rt.ro_rt = 0; } sin->sin_family = AF_INET; @@ -1636,10 +1784,29 @@ ip_forward(m, srcrt) } /* - * Save at most 64 bytes of the packet in case - * we need to generate an ICMP message to the src. + * Save the IP header and at most 8 bytes of the payload, + * in case we need to generate an ICMP message to the src. + * + * We don't use m_copy() because it might return a reference + * to a shared cluster. Both this function and ip_output() + * assume exclusive access to the IP header in `m', so any + * data in a cluster may change before we reach icmp_error(). */ - mcopy = m_copy(m, 0, imin((int)ip->ip_len, 64)); + MGET(mcopy, M_DONTWAIT, m->m_type); + if (mcopy != NULL) { + M_COPY_PKTHDR(mcopy, m); + mcopy->m_len = imin((IP_VHL_HL(ip->ip_vhl) << 2) + 8, + (int)ip->ip_len); + m_copydata(m, 0, mcopy->m_len, mtod(mcopy, caddr_t)); + } + +#if IPSTEALTH + if (!ipstealth) { +#endif + ip->ip_ttl -= IPTTLDEC; +#if IPSTEALTH + } +#endif /* * If forwarding packet using same interface that it came in on, @@ -1673,14 +1840,8 @@ ip_forward(m, srcrt) } } -#if IPSEC - ipsec_setsocket(m, NULL); -#endif /*IPSEC*/ error = ip_output(m, (struct mbuf *)0, &ipforward_rt, IP_FORWARDING, 0); -#if defined(PM) - clearAway:; -#endif if (error) ipstat.ips_cantforward++; else { @@ -1733,8 +1894,14 @@ ip_forward(m, srcrt) int ipsechdr; struct route *ro; + if (ipsec_bypass) { + destifp = ipforward_rt.ro_rt->rt_ifp; + ipstat.ips_cantfrag++; + break; + } + sp = ipsec4_getpolicybyaddr(mcopy, - IPSEC_DIR_OUTBOUND, + IPSEC_DIR_OUTBOUND, IP_FORWARDING, &ipsecerror); @@ -1779,6 +1946,10 @@ ip_forward(m, srcrt) type = ICMP_SOURCEQUENCH; code = 0; break; + + case EACCES: /* ipfw denied packet */ + m_freem(mcopy); + return; } icmp_error(mcopy, type, code, dest, destifp); } diff --git a/bsd/netinet/ip_mroute.c b/bsd/netinet/ip_mroute.c index 3ceeae10b..b522d5f95 100644 --- a/bsd/netinet/ip_mroute.c +++ b/bsd/netinet/ip_mroute.c @@ -30,13 +30,9 @@ * Modified by Bill Fenner, PARC, April 1995 * * MROUTING Revision: 3.5 + * $FreeBSD: src/sys/netinet/ip_mroute.c,v 1.56.2.2 2001/07/19 06:37:26 kris Exp $ */ -#if ISFB31 -#include "opt_mrouting.h" -#else -#define MROUTE_LKM 0 -#endif #include #include @@ -53,11 +49,6 @@ #include #include #include -#ifdef INET6 -#include -#include -#endif -#include #include #include #include @@ -79,7 +70,7 @@ #endif #endif -#if !MROUTING +#ifndef MROUTING extern u_long _ip_mcast_src __P((int vifi)); extern int _ip_mforward __P((struct ip *ip, struct ifnet *ifp, struct mbuf *m, struct ip_moptions *imo)); @@ -220,7 +211,7 @@ ip_rsvp_force_done(so) * Globals. All but ip_mrouter and ip_mrtproto could be static, * except for netstat or debugging purposes. */ -#if !MROUTE_LKM +#ifndef MROUTE_LKM struct socket *ip_mrouter = NULL; static struct mrtstat mrtstat; #else /* MROUTE_LKM */ @@ -243,8 +234,6 @@ static u_int mrtdebug = 0; /* debug level */ static u_int tbfdebug = 0; /* tbf debug level */ static u_int rsvpdebug = 0; /* rsvp debug level */ - - #define EXPIRE_TIMEOUT (hz / 4) /* 4x / second */ #define UPCALL_EXPIRE 6 /* number of timeouts */ @@ -469,7 +458,7 @@ X_ip_mrouter_set(so, sopt) return (error); } -#if !MROUTE_LKM +#if !defined(MROUTE_LKM) || !MROUTE_LKM int (*ip_mrouter_set)(struct socket *, struct sockopt *) = X_ip_mrouter_set; #endif @@ -499,7 +488,7 @@ X_ip_mrouter_get(so, sopt) return (error); } -#if !MROUTE_LKM +#if !defined(MROUTE_LKM) || !MROUTE_LKM int (*ip_mrouter_get)(struct socket *, struct sockopt *) = X_ip_mrouter_get; #endif @@ -527,7 +516,7 @@ X_mrt_ioctl(cmd, data) return error; } -#if !MROUTE_LKM +#if !defined(MROUTE_LKM) || !MROUTE_LKM int (*mrt_ioctl)(int, caddr_t) = X_mrt_ioctl; #endif @@ -683,7 +672,7 @@ X_ip_mrouter_done() return 0; } -#if !MROUTE_LKM +#if !defined(MROUTE_LKM) || !MROUTE_LKM int (*ip_mrouter_done)(void) = X_ip_mrouter_done; #endif @@ -1332,7 +1321,7 @@ X_ip_mforward(ip, ifp, m, imo) } } -#if !MROUTE_LKM +#if !defined(MROUTE_LKM) || !MROUTE_LKM int (*ip_mforward)(struct ip *, struct ifnet *, struct mbuf *, struct ip_moptions *) = X_ip_mforward; #endif @@ -1528,7 +1517,7 @@ X_legal_vif_num(vif) return(0); } -#if !MROUTE_LKM +#if !defined(MROUTE_LKM) || !MROUTE_LKM int (*legal_vif_num)(int) = X_legal_vif_num; #endif @@ -1545,7 +1534,7 @@ X_ip_mcast_src(vifi) return INADDR_ANY; } -#if !MROUTE_LKM +#if !defined(MROUTE_LKM) || !MROUTE_LKM u_long (*ip_mcast_src)(int) = X_ip_mcast_src; #endif @@ -1613,7 +1602,11 @@ encap_send(ip, vifp, m) */ ip_copy = mtod(mb_copy, struct ip *); *ip_copy = multicast_encap_iphdr; +#if RANDOM_IP_ID + ip_copy->ip_id = ip_randomid(); +#else ip_copy->ip_id = htons(ip_id++); +#endif ip_copy->ip_len += len; ip_copy->ip_src = vifp->v_lcl_addr; ip_copy->ip_dst = vifp->v_rmt_addr; @@ -2181,16 +2174,6 @@ rsvp_input(m, iphlen) return; } - /* If the old-style non-vif-associated socket is set, then use - * it and ignore the new ones. - */ - if (ip_rsvpd != NULL) { - if (rsvpdebug) - printf("rsvp_input: Sending packet up old-style socket\n"); - rip_input(m, iphlen); - return; - } - s = splnet(); if (rsvpdebug) @@ -2203,31 +2186,29 @@ rsvp_input(m, iphlen) ifp = m->m_pkthdr.rcvif; /* Find which vif the packet arrived on. */ - for (vifi = 0; vifi < numvifs; vifi++) { + for (vifi = 0; vifi < numvifs; vifi++) if (viftable[vifi].v_ifp == ifp) - break; - } - - if (vifi == numvifs) { - /* Can't find vif packet arrived on. Drop packet. */ - if (rsvpdebug) - printf("rsvp_input: Can't find vif for packet...dropping it.\n"); - m_freem(m); - splx(s); - return; - } - - if (rsvpdebug) - printf("rsvp_input: check socket\n"); + break; - if (viftable[vifi].v_rsvpd == NULL) { - /* drop packet, since there is no specific socket for this - * interface */ + if (vifi == numvifs || viftable[vifi].v_rsvpd == NULL) { + /* + * If the old-style non-vif-associated socket is set, + * then use it. Otherwise, drop packet since there + * is no specific socket for this vif. + */ + if (ip_rsvpd != NULL) { if (rsvpdebug) - printf("rsvp_input: No socket defined for vif %d\n",vifi); + printf("rsvp_input: Sending packet up old-style socket\n"); + rip_input(m, iphlen); /* xxx */ + } else { + if (rsvpdebug && vifi == numvifs) + printf("rsvp_input: Can't find vif for packet.\n"); + else if (rsvpdebug && viftable[vifi].v_rsvpd == NULL) + printf("rsvp_input: No socket defined for vif %d\n",vifi); m_freem(m); - splx(s); - return; + } + splx(s); + return; } rsvp_src.sin_addr = ip->ip_src; @@ -2235,13 +2216,14 @@ rsvp_input(m, iphlen) printf("rsvp_input: m->m_len = %d, sbspace() = %ld\n", m->m_len,sbspace(&(viftable[vifi].v_rsvpd->so_rcv))); - if (socket_send(viftable[vifi].v_rsvpd, m, &rsvp_src) < 0) + if (socket_send(viftable[vifi].v_rsvpd, m, &rsvp_src) < 0) { if (rsvpdebug) printf("rsvp_input: Failed to append to socket\n"); - else + } else { if (rsvpdebug) printf("rsvp_input: send packet up\n"); - + } + splx(s); } diff --git a/bsd/netinet/ip_mroute.h b/bsd/netinet/ip_mroute.h index e87167b6f..a667f4ea4 100644 --- a/bsd/netinet/ip_mroute.h +++ b/bsd/netinet/ip_mroute.h @@ -60,6 +60,7 @@ #ifndef _NETINET_IP_MROUTE_H_ #define _NETINET_IP_MROUTE_H_ +#include /* * Definitions for IP multicast forwarding. @@ -270,19 +271,20 @@ struct tbf }; #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE struct sockopt; extern int (*ip_mrouter_set) __P((struct socket *, struct sockopt *)); extern int (*ip_mrouter_get) __P((struct socket *, struct sockopt *)); extern int (*ip_mrouter_done) __P((void)); - #if MROUTING extern int (*mrt_ioctl) __P((int, caddr_t)); #else extern int (*mrt_ioctl) __P((int, caddr_t, struct proc *)); #endif +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ #endif /* _NETINET_IP_MROUTE_H_ */ diff --git a/bsd/netinet/ip_output.c b/bsd/netinet/ip_output.c index fa63025aa..eaff4fc2d 100644 --- a/bsd/netinet/ip_output.c +++ b/bsd/netinet/ip_output.c @@ -52,17 +52,11 @@ * SUCH DAMAGE. * * @(#)ip_output.c 8.3 (Berkeley) 1/21/94 + * $FreeBSD: src/sys/netinet/ip_output.c,v 1.99.2.16 2001/07/19 06:37:26 kris Exp $ */ #define _IP_VHL -#if ISFB31 -#include "opt_ipfw.h" -#include "opt_ipdn.h" -#include "opt_ipdivert.h" -#include "opt_ipfilter.h" -#endif - #include #include #include @@ -78,15 +72,13 @@ #include #include #include -#if INET6 -#include -#include -#endif #include #include #include -#include +#include "faith.h" + +#include #include #define DBG_LAYER_BEG NETDBG_CODE(DBG_NETIP, 1) @@ -94,35 +86,27 @@ #define DBG_FNC_IP_OUTPUT NETDBG_CODE(DBG_NETIP, (1 << 8) | 1) -#ifdef vax +#if vax #include #endif -#if ISFB31 +#if __FreeBSD__ #include static MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "internet multicast options"); #endif -//static MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "internet multicast options"); - #if IPSEC #include #include +#if IPSEC_DEBUG #include - -#endif /*IPSEC*/ - -#if !defined(COMPAT_IPFW) || COMPAT_IPFW == 1 -#undef COMPAT_IPFW -#define COMPAT_IPFW 1 #else -#undef COMPAT_IPFW +#define KEYDEBUG(lev,arg) #endif +#endif /*IPSEC*/ -#if COMPAT_IPFW #include -#endif #if DUMMYNET #include @@ -138,6 +122,7 @@ static MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "internet multicast options"); u_short ip_id; static struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *)); +static struct ifnet *ip_multicast_if __P((struct in_addr *, int *)); static void ip_mloopback __P((struct ifnet *, struct mbuf *, struct sockaddr_in *, int)); static int ip_getmoptions @@ -145,14 +130,27 @@ static int ip_getmoptions static int ip_pcbopts __P((int, struct mbuf **, struct mbuf *)); static int ip_setmoptions __P((struct sockopt *, struct ip_moptions **)); + +int ip_optcopy __P((struct ip *, struct ip *)); +extern int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int, struct mbuf **)); +#ifdef __APPLE__ +extern struct mbuf* m_dup(register struct mbuf *m, int how); +#endif + static u_long lo_dl_tag = 0; -static int ip_optcopy __P((struct ip *, struct ip *)); void in_delayed_cksum(struct mbuf *m); extern int apple_hwcksum_tx; extern struct protosw inetsw[]; +extern struct ip_linklocal_stat ip_linklocal_stat; + +/* temporary: for testing */ +#if IPSEC +extern int ipsec_bypass; +#endif + /* * IP output. The packet in mbuf chain m contains a skeletal IP * header (with len, off, ttl, proto, tos, src, dst). @@ -174,52 +172,29 @@ ip_output(m0, opt, ro, flags, imo) int hlen = sizeof (struct ip); int len, off, error = 0; struct sockaddr_in *dst; - struct in_ifaddr *ia; + struct in_ifaddr *ia = NULL; int isbroadcast, sw_csum; #if IPSEC struct route iproute; - struct socket *so; + struct socket *so = NULL; struct secpolicy *sp = NULL; #endif + u_int16_t divert_cookie; /* firewall cookie */ #if IPFIREWALL_FORWARD int fwd_rewrite_src = 0; #endif - - -#if !IPDIVERT /* dummy variable for the firewall code to play with */ - u_short ip_divert_cookie = 0 ; -#endif -#if COMPAT_IPFW - struct ip_fw_chain *rule = NULL ; + struct ip_fw_chain *rule = NULL; + +#if IPDIVERT + /* Get and reset firewall cookie */ + divert_cookie = ip_divert_cookie; + ip_divert_cookie = 0; +#else + divert_cookie = 0; #endif KERNEL_DEBUG(DBG_FNC_IP_OUTPUT | DBG_FUNC_START, 0,0,0,0,0); -#if IPSEC - /* - * NOTE: m->m_pkthdr is NULL cleared below just to prevent ipfw code - * from SEGV. - * ipfw code uses rcvif to determine incoming interface, and - * KAME uses rcvif for ipsec processing. - * ipfw may not be working right with KAME at this moment. - * We need more tests. - */ -#if DUMMYNET - if (m->m_type == MT_DUMMYNET) { - if (m->m_next != NULL) { - so = (struct socket *)m->m_next->m_pkthdr.rcvif; - m->m_next->m_pkthdr.rcvif = NULL; - } else - so = NULL; - } else -#endif - { - so = ipsec_getsocket(m); - ipsec_setsocket(m, NULL); - } -#endif /*IPSEC*/ - - #if IPFIREWALL && DUMMYNET /* * dummynet packet are prepended a vestigial mbuf with @@ -227,26 +202,39 @@ ip_output(m0, opt, ro, flags, imo) * rule. */ if (m->m_type == MT_DUMMYNET) { - struct mbuf *tmp_m = m ; /* * the packet was already tagged, so part of the * processing was already done, and we need to go down. - * opt, flags and imo have already been used, and now - * they are used to hold ifp and hlen and NULL, respectively. + * Get parameters from the header. */ - rule = (struct ip_fw_chain *)(m->m_data) ; - m = m->m_next ; - FREE(tmp_m, M_IPFW); + rule = (struct ip_fw_chain *)(m->m_data) ; + opt = NULL ; + ro = & ( ((struct dn_pkt *)m)->ro ) ; + imo = NULL ; + dst = ((struct dn_pkt *)m)->dn_dst ; + ifp = ((struct dn_pkt *)m)->ifp ; + flags = ((struct dn_pkt *)m)->flags ; + m0 = m = m->m_next ; +#if IPSEC + if (ipsec_bypass == 0) { + so = ipsec_getsocket(m); + (void)ipsec_setsocket(m, NULL); + } +#endif ip = mtod(m, struct ip *); - dst = (struct sockaddr_in *)&ro->ro_dst; - ifp = (struct ifnet *)opt; hlen = IP_VHL_HL(ip->ip_vhl) << 2 ; - opt = NULL ; - flags = 0 ; /* XXX is this correct ? */ + if (ro->ro_rt != NULL) + ia = (struct in_ifaddr *)ro->ro_rt->rt_ifa; goto sendit; } else rule = NULL ; #endif +#if IPSEC + if (ipsec_bypass == 0) { + so = ipsec_getsocket(m); + (void)ipsec_setsocket(m, NULL); + } +#endif #if DIAGNOSTIC if ((m->m_flags & M_PKTHDR) == 0) @@ -266,7 +254,11 @@ ip_output(m0, opt, ro, flags, imo) if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 0) { ip->ip_vhl = IP_MAKE_VHL(IPVERSION, hlen >> 2); ip->ip_off &= IP_DF; +#if RANDOM_IP_ID + ip->ip_id = ip_randomid(); +#else ip->ip_id = htons(ip_id++); +#endif ipstat.ips_localout++; } else { hlen = IP_VHL_HL(ip->ip_vhl) << 2; @@ -283,7 +275,7 @@ ip_output(m0, opt, ro, flags, imo) */ 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); + rtfree(ro->ro_rt); ro->ro_rt = (struct rtentry *)0; } if (ro->ro_rt == 0) { @@ -377,8 +369,7 @@ ip_output(m0, opt, ro, flags, imo) if (ip->ip_src.s_addr == INADDR_ANY) { register struct in_ifaddr *ia1; - for (ia1 = in_ifaddrhead.tqh_first; ia1; - ia1 = ia1->ia_link.tqe_next) + TAILQ_FOREACH(ia1, &in_ifaddrhead, ia_link) if (ia1->ia_ifp == ifp) { ip->ip_src = IA_SIN(ia1)->sin_addr; break; @@ -491,6 +482,150 @@ ip_output(m0, opt, ro, flags, imo) } sendit: + /* + * Force IP TTL to 255 following draft-ietf-zeroconf-ipv4-linklocal.txt + */ + if (IN_LINKLOCAL(ntohl(ip->ip_src.s_addr)) || IN_LINKLOCAL(ntohl(ip->ip_dst.s_addr))) { + ip_linklocal_stat.iplls_out_total++; + if (ip->ip_ttl != MAXTTL) { + ip_linklocal_stat.iplls_out_badttl++; + ip->ip_ttl = MAXTTL; + } + } + +#if IPSEC + /* temporary for testing only: bypass ipsec alltogether */ + + if (ipsec_bypass != 0) + goto skip_ipsec; + + /* get SP for this packet */ + if (so == NULL) + sp = ipsec4_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, flags, &error); + else + sp = ipsec4_getpolicybysock(m, IPSEC_DIR_OUTBOUND, so, &error); + + if (sp == NULL) { + ipsecstat.out_inval++; + goto bad; + } + + error = 0; + + /* check policy */ + switch (sp->policy) { + case IPSEC_POLICY_DISCARD: + /* + * This packet is just discarded. + */ + ipsecstat.out_polvio++; + goto bad; + + case IPSEC_POLICY_BYPASS: + case IPSEC_POLICY_NONE: + /* no need to do IPsec. */ + goto skip_ipsec; + + case IPSEC_POLICY_IPSEC: + if (sp->req == NULL) { + /* acquire a policy */ + error = key_spdacquire(sp); + goto bad; + } + break; + + case IPSEC_POLICY_ENTRUST: + default: + printf("ip_output: Invalid policy found. %d\n", sp->policy); + } + { + struct ipsec_output_state state; + bzero(&state, sizeof(state)); + state.m = m; + if (flags & IP_ROUTETOIF) { + state.ro = &iproute; + bzero(&iproute, sizeof(iproute)); + } else + state.ro = ro; + state.dst = (struct sockaddr *)dst; + + ip->ip_sum = 0; + + /* + * XXX + * delayed checksums are not currently compatible with IPsec + */ + if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { + in_delayed_cksum(m); + m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; + } + + HTONS(ip->ip_len); + HTONS(ip->ip_off); + + error = ipsec4_output(&state, sp, flags); + + m = state.m; + if (flags & IP_ROUTETOIF) { + /* + * if we have tunnel mode SA, we may need to ignore + * IP_ROUTETOIF. + */ + if (state.ro != &iproute || state.ro->ro_rt != NULL) { + flags &= ~IP_ROUTETOIF; + ro = state.ro; + } + } else + ro = state.ro; + dst = (struct sockaddr_in *)state.dst; + if (error) { + /* mbuf is already reclaimed in ipsec4_output. */ + m0 = NULL; + switch (error) { + case EHOSTUNREACH: + case ENETUNREACH: + case EMSGSIZE: + case ENOBUFS: + case ENOMEM: + break; + default: + printf("ip4_output (ipsec): error code %d\n", error); + /*fall through*/ + case ENOENT: + /* don't show these error codes to the user */ + error = 0; + break; + } + goto bad; + } + } + + /* be sure to update variables that are affected by ipsec4_output() */ + ip = mtod(m, struct ip *); +#ifdef _IP_VHL + hlen = IP_VHL_HL(ip->ip_vhl) << 2; +#else + hlen = ip->ip_hl << 2; +#endif + if (ro->ro_rt == NULL) { + if ((flags & IP_ROUTETOIF) == 0) { + printf("ip_output: " + "can't update route after IPsec processing\n"); + error = EHOSTUNREACH; /*XXX*/ + goto bad; + } + } else { + ia = ifatoia(ro->ro_rt->rt_ifa); + ifp = ro->ro_rt->rt_ifp; + dl_tag = ia->ia_ifa.ifa_dlt; + } + + /* make it flipped, again. */ + NTOHS(ip->ip_len); + NTOHS(ip->ip_off); +skip_ipsec: +#endif /*IPSEC*/ + /* * IpHack's section. * - Xlate: translate packet's addr/port (NAT). @@ -498,25 +633,28 @@ sendit: * - Wrap: fake packet's addr/port * - Encapsulate: put it in another IP and send out. */ -#if COMPAT_IPFW - if (ip_nat_ptr && !(*ip_nat_ptr)(&ip, &m, ifp, IP_NAT_OUT)) { - error = EACCES; - goto done; + if (fr_checkp) { + struct mbuf *m1 = m; + + if ((error = (*fr_checkp)(ip, hlen, ifp, 1, &m1)) || !m1) + goto done; + ip = mtod(m = m1, struct ip *); } /* * Check with the firewall... */ - if (ip_fw_chk_ptr) { + if (fw_enable && ip_fw_chk_ptr) { struct sockaddr_in *old = dst; off = (*ip_fw_chk_ptr)(&ip, - hlen, ifp, &ip_divert_cookie, &m, &rule, &dst); + hlen, ifp, &divert_cookie, &m, &rule, &dst); /* * On return we must do the following: - * m == NULL -> drop the pkt + * IP_FW_PORT_DENY_FLAG -> drop the pkt (XXX new) * 1<=off<= 0xffff -> DIVERT - * (off & 0x10000) -> send to a DUMMYNET pipe + * (off & IP_FW_PORT_DYNT_FLAG) -> send to a DUMMYNET pipe + * (off & IP_FW_PORT_TEE_FLAG) -> TEE the packet * dst != old -> IPFIREWALL_FORWARD * off==0, dst==old -> accept * If some of the above modules is not compiled in, then @@ -525,47 +663,62 @@ sendit: * unsupported rules), but better play safe and drop * packets in case of doubt. */ - if (!m) { /* firewall said to reject */ - error = EACCES; - goto done; + if ( (off & IP_FW_PORT_DENY_FLAG) || m == NULL) { + if (m) + m_freem(m); + error = EACCES ; + goto done ; } + ip = mtod(m, struct ip *); if (off == 0 && dst == old) /* common case */ goto pass ; #if DUMMYNET - if (off & 0x10000) { + if ((off & IP_FW_PORT_DYNT_FLAG) != 0) { /* * pass the pkt to dummynet. Need to include - * pipe number, m, ifp, ro, hlen because these are + * pipe number, m, ifp, ro, dst because these are * not recomputed in the next pass. * All other parameters have been already used and * so they are not needed anymore. * XXX note: if the ifp or ro entry are deleted * while a pkt is in dummynet, we are in trouble! */ - dummynet_io(off & 0xffff, DN_TO_IP_OUT, m,ifp,ro,hlen,rule); - goto done; + error = dummynet_io(off & 0xffff, DN_TO_IP_OUT, m, + ifp,ro,dst,rule, flags); + goto done; } #endif #if IPDIVERT - if (off > 0 && off < 0x10000) { /* Divert packet */ - - /* - * delayed checksums are not currently compatible - * with divert sockets. - */ - if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { - in_delayed_cksum(m); - if (m == NULL) - return(ENOMEM); - m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; - } - - /* Restore packet header fields to original values */ - ip->ip_len = htons((u_short)ip->ip_len); - ip->ip_off = htons((u_short)ip->ip_off); - - ip_divert_port = off & 0xffff ; - (*ip_protox[IPPROTO_DIVERT]->pr_input)(m, 0); + if (off != 0 && (off & IP_FW_PORT_DYNT_FLAG) == 0) { + struct mbuf *clone = NULL; + + /* Clone packet if we're doing a 'tee' */ + if ((off & IP_FW_PORT_TEE_FLAG) != 0) + clone = m_dup(m, M_DONTWAIT); + /* + * XXX + * delayed checksums are not currently compatible + * with divert sockets. + */ + if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { + in_delayed_cksum(m); + m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; + } + + /* Restore packet header fields to original values */ + HTONS(ip->ip_len); + HTONS(ip->ip_off); + + /* Deliver packet to divert input routine */ + ip_divert_cookie = divert_cookie; + divert_packet(m, 0, off & 0xffff); + + /* If 'tee', continue with original packet */ + if (clone != NULL) { + m = clone; + ip = mtod(m, struct ip *); + goto pass; + } goto done; } #endif @@ -604,8 +757,7 @@ sendit: * as the packet runs through ip_input() as * it is done through a ISR. */ - for (ia = TAILQ_FIRST(&in_ifaddrhead); ia; - ia = TAILQ_NEXT(ia, ia_link)) { + TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) { /* * If the addr to forward to is one * of ours, we pretend to @@ -620,18 +772,15 @@ sendit: ip_fw_fwd_addr = dst; if (m->m_pkthdr.rcvif == NULL) m->m_pkthdr.rcvif = ifunit("lo0"); - - if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { - m->m_pkthdr.csum_flags |= - CSUM_DATA_VALID | CSUM_PSEUDO_HDR; - m0->m_pkthdr.csum_data = 0xffff; - } - m->m_pkthdr.csum_flags |= - CSUM_IP_CHECKED | CSUM_IP_VALID; - ip->ip_len = htons((u_short)ip->ip_len); - ip->ip_off = htons((u_short)ip->ip_off); - - + if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { + m->m_pkthdr.csum_flags |= + CSUM_DATA_VALID | CSUM_PSEUDO_HDR; + m0->m_pkthdr.csum_data = 0xffff; + } + m->m_pkthdr.csum_flags |= + CSUM_IP_CHECKED | CSUM_IP_VALID; + HTONS(ip->ip_len); + HTONS(ip->ip_off); ip_input(m); goto done; } @@ -654,7 +803,7 @@ sendit: ia = ifatoia(ro_fwd->ro_rt->rt_ifa); ifp = ro_fwd->ro_rt->rt_ifp; - dl_tag = ro->ro_rt->rt_dlt; + dl_tag = ro_fwd->ro_rt->rt_dlt; ro_fwd->ro_rt->rt_use++; if (ro_fwd->ro_rt->rt_flags & RTF_GATEWAY) dst = (struct sockaddr_in *)ro_fwd->ro_rt->rt_gateway; @@ -663,7 +812,7 @@ sendit: (ro_fwd->ro_rt->rt_flags & RTF_BROADCAST); else isbroadcast = in_broadcast(dst->sin_addr, ifp); - RTFREE(ro->ro_rt); + rtfree(ro->ro_rt); ro->ro_rt = ro_fwd->ro_rt; dst = (struct sockaddr_in *)&ro_fwd->ro_dst; @@ -685,200 +834,74 @@ sendit: error = EACCES; /* not sure this is the right error msg */ goto done; } -#endif /* COMPAT_IPFW */ pass: + m->m_pkthdr.csum_flags |= CSUM_IP; + sw_csum = m->m_pkthdr.csum_flags & ~ifp->if_hwassist; -#if defined(PM) - /* - * Processing IP filter/NAT. - * Return TRUE iff this packet is discarded. - * Return FALSE iff this packet is accepted. - */ - - if (doNatFil && pm_out(ro->ro_rt->rt_ifp, ip, m)) - goto done; -#endif - -#if IPSEC - /* get SP for this packet */ - if (so == NULL) - sp = ipsec4_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, flags, &error); - else - sp = ipsec4_getpolicybysock(m, IPSEC_DIR_OUTBOUND, so, &error); - - if (sp == NULL) { - ipsecstat.out_inval++; - goto bad; - } - - error = 0; - - /* check policy */ - switch (sp->policy) { - case IPSEC_POLICY_DISCARD: + if ((ifp->if_hwassist & CSUM_TCP_SUM16) != 0) { /* - * This packet is just discarded. + * Special case code for GMACE + * frames that can be checksumed by GMACE SUM16 HW: + * frame >64, no fragments, no UDP */ - ipsecstat.out_polvio++; - goto bad; - - case IPSEC_POLICY_BYPASS: - case IPSEC_POLICY_NONE: - /* no need to do IPsec. */ - goto skip_ipsec; - - case IPSEC_POLICY_IPSEC: - if (sp->req == NULL) { - /* XXX should be panic ? */ - printf("ip_output: No IPsec request specified.\n"); - error = EINVAL; - goto bad; - } - break; - - case IPSEC_POLICY_ENTRUST: - default: - printf("ip_output: Invalid policy found. %d\n", sp->policy); - } - - - { - struct ipsec_output_state state; - bzero(&state, sizeof(state)); - state.m = m; - if (flags & IP_ROUTETOIF) { - state.ro = &iproute; - bzero(&iproute, sizeof(iproute)); - } else - state.ro = ro; - state.dst = (struct sockaddr *)dst; - - ip->ip_sum = 0; - - /* - * delayed checksums are not currently compatible with IPsec - */ - if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { - in_delayed_cksum(m); - if (m == NULL) - return(ENOMEM); - m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; - } - - ip->ip_len = htons((u_short)ip->ip_len); - ip->ip_off = htons((u_short)ip->ip_off); - - error = ipsec4_output(&state, sp, flags); - - m = state.m; - if (flags & IP_ROUTETOIF) { - /* - * if we have tunnel mode SA, we may need to ignore - * IP_ROUTETOIF. - */ - if (state.ro != &iproute || state.ro->ro_rt != NULL) { - flags &= ~IP_ROUTETOIF; - ro = state.ro; - } - } else - ro = state.ro; - dst = (struct sockaddr_in *)state.dst; - if (error) { - /* mbuf is already reclaimed in ipsec4_output. */ - m0 = NULL; - switch (error) { - case EHOSTUNREACH: - case ENETUNREACH: - case EMSGSIZE: - case ENOBUFS: - case ENOMEM: - break; - default: - printf("ip4_output (ipsec): error code %d\n", error); - /*fall through*/ - case ENOENT: - /* don't show these error codes to the user */ - error = 0; - break; + if (apple_hwcksum_tx && (m->m_pkthdr.csum_flags & CSUM_TCP) + && (ip->ip_len > 50) && (ip->ip_len <= ifp->if_mtu)) { + /* Apple GMAC HW, expects STUFF_OFFSET << 16 | START_OFFSET */ + u_short offset = (IP_VHL_HL(ip->ip_vhl) << 2) +14 ; /* IP+Enet header length */ + u_short csumprev= m->m_pkthdr.csum_data & 0xFFFF; + m->m_pkthdr.csum_flags = CSUM_DATA_VALID | CSUM_TCP_SUM16; /* for GMAC */ + m->m_pkthdr.csum_data = (csumprev + offset) << 16 ; + m->m_pkthdr.csum_data += offset; + sw_csum = CSUM_DELAY_IP; /* do IP hdr chksum in software */ } - goto bad; - } - } - - /* be sure to update variables that are affected by ipsec4_output() */ - ip = mtod(m, struct ip *); -#ifdef _IP_VHL - hlen = IP_VHL_HL(ip->ip_vhl) << 2; -#else - hlen = ip->ip_hl << 2; -#endif - if (ro->ro_rt == NULL) { - if ((flags & IP_ROUTETOIF) == 0) { - printf("ip_output: " - "can't update route after IPsec processing\n"); - error = EHOSTUNREACH; /*XXX*/ - goto bad; + else { + /* let the software handle any UDP or TCP checksums */ + sw_csum |= (CSUM_DELAY_DATA & m->m_pkthdr.csum_flags); } - } else { - /* nobody uses ia beyond here */ - ifp = ro->ro_rt->rt_ifp; } - - /* make it flipped, again. */ - ip->ip_len = ntohs((u_short)ip->ip_len); - ip->ip_off = ntohs((u_short)ip->ip_off); -skip_ipsec: -#endif /*IPSEC*/ - - - sw_csum = m->m_pkthdr.csum_flags | CSUM_IP; - - - /* frames that can be checksumed by GMACE SUM16 HW: frame >64, no fragments, no UDP odd length */ - - if (apple_hwcksum_tx && (sw_csum & CSUM_DELAY_DATA) && (ifp->if_hwassist & CSUM_TCP_SUM16) - && (ip->ip_len > 50) && (ip->ip_len <= ifp->if_mtu) - && !((ip->ip_len & 0x1) && (sw_csum & CSUM_UDP)) ) { - - /* Apple GMAC HW, expects STUFF_OFFSET << 16 | START_OFFSET */ - u_short offset = (IP_VHL_HL(ip->ip_vhl) << 2) +14 ; /* IP+Enet header length */ - u_short csumprev= m->m_pkthdr.csum_data & 0xFFFF; - m->m_pkthdr.csum_flags = CSUM_DATA_VALID | CSUM_TCP_SUM16; /* for GMAC */ - m->m_pkthdr.csum_data = (csumprev + offset) << 16 ; - m->m_pkthdr.csum_data += offset; - sw_csum = CSUM_DELAY_IP; /* do IP hdr chksum in software */ + + if (sw_csum & CSUM_DELAY_DATA) { + in_delayed_cksum(m); + sw_csum &= ~CSUM_DELAY_DATA; + m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; } - else { - if (ifp->if_hwassist & CSUM_TCP_SUM16) /* force SW checksuming */ - m->m_pkthdr.csum_flags = 0; - else { /* not Apple enet */ - m->m_pkthdr.csum_flags = sw_csum & ifp->if_hwassist; - sw_csum &= ~ifp->if_hwassist; - } - - if (sw_csum & CSUM_DELAY_DATA) { /* perform TCP/UDP checksuming now */ - in_delayed_cksum(m); - if (m == NULL) - return(ENOMEM); - sw_csum &= ~CSUM_DELAY_DATA; - } - } + + m->m_pkthdr.csum_flags &= ifp->if_hwassist; /* - * If small enough for interface, or the interface will take + * If small enough for interface, or the interface will take * care of the fragmentation for us, can just send directly. */ - if ((u_short)ip->ip_len <= ifp->if_mtu || - ifp->if_hwassist & CSUM_FRAGMENT) { - - ip->ip_len = htons((u_short)ip->ip_len); - ip->ip_off = htons((u_short)ip->ip_off); + if ((u_short)ip->ip_len <= ifp->if_mtu || + ifp->if_hwassist & CSUM_FRAGMENT) { + HTONS(ip->ip_len); + HTONS(ip->ip_off); ip->ip_sum = 0; - if (sw_csum & CSUM_DELAY_IP) + if (sw_csum & CSUM_DELAY_IP) { ip->ip_sum = in_cksum(m, hlen); + } + +#ifndef __APPLE__ + /* Record statistics for this interface address. */ + if (!(flags & IP_FORWARDING) && ia != NULL) { + ia->ia_ifa.if_opackets++; + ia->ia_ifa.if_obytes += m->m_pkthdr.len; + } +#endif + +#if IPSEC + /* clean ipsec history once it goes out of the node */ + if (ipsec_bypass == 0) + ipsec_delaux(m); +#endif +#if __APPLE__ error = dlil_output(dl_tag, m, (void *) ro->ro_rt, (struct sockaddr *)dst, 0); +#else + error = (*ifp->if_output)(ifp, m, + (struct sockaddr *)dst, ro->ro_rt); +#endif goto done; } /* @@ -908,24 +931,23 @@ skip_ipsec: goto bad; } - /* - * if the interface will not calculate checksums on - * fragmented packets, then do it here. - */ - if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA && - (ifp->if_hwassist & CSUM_IP_FRAGS) == 0) { - in_delayed_cksum(m); + /* + * if the interface will not calculate checksums on + * fragmented packets, then do it here. + */ + if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA && + (ifp->if_hwassist & CSUM_IP_FRAGS) == 0) { + in_delayed_cksum(m); if (m == NULL) return(ENOMEM); - m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; - } + m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; + } { int mhlen, firstlen = len; struct mbuf **mnext = &m->m_nextpkt; - int nfrags = 1; - + int nfrags = 1; /* * Loop through length of segment after first fragment, @@ -966,11 +988,12 @@ skip_ipsec: } m->m_pkthdr.len = mhlen + len; m->m_pkthdr.rcvif = (struct ifnet *)0; - m->m_pkthdr.csum_flags = m0->m_pkthdr.csum_flags; - mhip->ip_off = htons((u_short)mhip->ip_off); + m->m_pkthdr.csum_flags = m0->m_pkthdr.csum_flags; + HTONS(mhip->ip_off); mhip->ip_sum = 0; - if (sw_csum & CSUM_DELAY_IP) + if (sw_csum & CSUM_DELAY_IP) { mhip->ip_sum = in_cksum(m, mhlen); + } *mnext = m; mnext = &m->m_nextpkt; nfrags++; @@ -978,7 +1001,8 @@ skip_ipsec: ipstat.ips_ofragments += nfrags; /* set first/last markers for fragment chain */ - m0->m_flags |= M_FRAG; + m->m_flags |= M_LASTFRAG; + m0->m_flags |= M_FIRSTFRAG | M_FRAG; m0->m_pkthdr.csum_data = nfrags; /* @@ -989,11 +1013,12 @@ skip_ipsec: 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_off |= IP_MF; + HTONS(ip->ip_off); ip->ip_sum = 0; - if (sw_csum & CSUM_DELAY_IP) + if (sw_csum & CSUM_DELAY_IP) { ip->ip_sum = in_cksum(m, hlen); - + } sendorfree: KERNEL_DEBUG(DBG_LAYER_END, ip->ip_dst.s_addr, @@ -1002,10 +1027,28 @@ sendorfree: for (m = m0; m; m = m0) { m0 = m->m_nextpkt; m->m_nextpkt = 0; - if (error == 0) +#if IPSEC + /* clean ipsec history once it goes out of the node */ + if (ipsec_bypass == 0) + ipsec_delaux(m); +#endif + if (error == 0) { +#ifndef __APPLE__ + /* Record statistics for this interface address. */ + if (ia != NULL) { + ia->ia_ifa.if_opackets++; + ia->ia_ifa.if_obytes += m->m_pkthdr.len; + } +#endif + +#if __APPLE__ error = dlil_output(dl_tag, m, (void *) ro->ro_rt, (struct sockaddr *)dst, 0); - else +#else + error = (*ifp->if_output)(ifp, m, + (struct sockaddr *)dst, ro->ro_rt); +#endif + } else m_freem(m); } @@ -1014,8 +1057,9 @@ sendorfree: } done: #if IPSEC + if (ipsec_bypass == 0) { if (ro == &iproute && ro->ro_rt) { - RTFREE(ro->ro_rt); + rtfree(ro->ro_rt); ro->ro_rt = NULL; } if (sp != NULL) { @@ -1023,6 +1067,7 @@ done: printf("DP ip_output call free SP:%x\n", sp)); key_freesp(sp); } + } #endif /* IPSEC */ KERNEL_DEBUG(DBG_FNC_IP_OUTPUT | DBG_FUNC_END, error,0,0,0,0); @@ -1032,41 +1077,33 @@ bad: goto done; } -extern u_short in_chksum_skip(struct mbuf *, int, int); - void in_delayed_cksum(struct mbuf *m) { - struct ip *ip; - u_short csum, csum2, offset; - - ip = mtod(m, struct ip *); - offset = IP_VHL_HL(ip->ip_vhl) << 2 ; - - csum = in_cksum_skip(m, ip->ip_len, offset); - - if ((m->m_pkthdr.csum_flags & CSUM_UDP) && csum == 0) + struct ip *ip; + u_short csum, offset; + ip = mtod(m, struct ip *); + offset = IP_VHL_HL(ip->ip_vhl) << 2 ; + csum = in_cksum_skip(m, ip->ip_len, offset); + if (m->m_pkthdr.csum_flags & CSUM_UDP && csum == 0) csum = 0xffff; - - offset += m->m_pkthdr.csum_data & 0xFFFF; /* checksum offset */ + offset += m->m_pkthdr.csum_data & 0xFFFF; /* checksum offset */ if (offset > ip->ip_len) /* bogus offset */ return; - if (offset + sizeof(u_short) > m->m_len) { - printf("delayed m_pullup, m->len: %d off: %d p: %d\n", - m->m_len, offset, ip->ip_p); - /* - * XXX - * this shouldn't happen, but if it does, the - * correct behavior may be to insert the checksum - * in the existing chain instead of rearranging it. - */ - if (m = m_pullup(m, offset + sizeof(u_short)) == 0) - return; - } - - *(u_short *)(m->m_data + offset) = csum; + if (offset + sizeof(u_short) > m->m_len) { + printf("delayed m_pullup, m->len: %d off: %d p: %d\n", + m->m_len, offset, ip->ip_p); + /* + * XXX + * this shouldn't happen, but if it does, the + * correct behavior may be to insert the checksum + * in the existing chain instead of rearranging it. + */ + m = m_pullup(m, offset + sizeof(u_short)); + } + *(u_short *)(m->m_data + offset) = csum; } /* @@ -1096,6 +1133,7 @@ ip_insertoptions(m, opt, phlen) MGETHDR(n, M_DONTWAIT, MT_HEADER); if (n == 0) return (m); + n->m_pkthdr.rcvif = (struct ifnet *)0; n->m_pkthdr.len = m->m_pkthdr.len + optlen; m->m_len -= sizeof(struct ip); m->m_data += sizeof(struct ip); @@ -1141,8 +1179,16 @@ ip_optcopy(ip, jp) *dp++ = IPOPT_NOP; optlen = 1; continue; - } else - optlen = cp[IPOPT_OLEN]; + } +#if DIAGNOSTIC + if (cnt < IPOPT_OLEN + sizeof(*cp)) + panic("malformed IPv4 option passed to ip_optcopy"); +#endif + optlen = cp[IPOPT_OLEN]; +#if DIAGNOSTIC + if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt) + panic("malformed IPv4 option passed to ip_optcopy"); +#endif /* bogus lengths should have been caught by ip_dooptions */ if (optlen > cnt) optlen = cnt; @@ -1206,7 +1252,9 @@ ip_ctloutput(so, sopt) case IP_RECVRETOPTS: case IP_RECVDSTADDR: case IP_RECVIF: +#if defined(NFAITH) && NFAITH > 0 case IP_FAITH: +#endif error = sooptcopyin(sopt, &optval, sizeof optval, sizeof optval); if (error) @@ -1242,9 +1290,11 @@ ip_ctloutput(so, sopt) OPTSET(INP_RECVIF); break; +#if defined(NFAITH) && NFAITH > 0 case IP_FAITH: OPTSET(INP_FAITH); break; +#endif } break; #undef OPTSET @@ -1295,9 +1345,9 @@ ip_ctloutput(so, sopt) struct mbuf *m; int optname; - if (error = sooptgetm(sopt, &m)) /* XXX */ + if ((error = soopt_getm(sopt, &m)) != 0) /* XXX */ break; - if (error = sooptmcopyin(sopt, m)) /* XXX */ + if ((error = soopt_mcopyin(sopt, m)) != 0) /* XXX */ break; priv = (sopt->sopt_p != NULL && suser(sopt->sopt_p->p_ucred, @@ -1339,7 +1389,9 @@ ip_ctloutput(so, sopt) case IP_RECVDSTADDR: case IP_RECVIF: case IP_PORTRANGE: +#if defined(NFAITH) && NFAITH > 0 case IP_FAITH: +#endif switch (sopt->sopt_name) { case IP_TOS: @@ -1377,9 +1429,11 @@ ip_ctloutput(so, sopt) optval = 0; break; +#if defined(NFAITH) && NFAITH > 0 case IP_FAITH: optval = OPTBIT(INP_FAITH); break; +#endif } error = sooptcopyout(sopt, &optval, sizeof optval); break; @@ -1397,23 +1451,16 @@ ip_ctloutput(so, sopt) case IP_IPSEC_POLICY: { struct mbuf *m = NULL; - size_t len = 0; caddr_t req = NULL; + size_t len = 0; - if (error = sooptgetm(sopt, &m)) /* XXX */ - break; - if (error = sooptmcopyin(sopt, m)) /* XXX */ - break; - if (m) { + if (m != 0) { req = mtod(m, caddr_t); len = m->m_len; } - error = ipsec4_get_policy(sotoinpcb(so), req, len, &m); if (error == 0) - error = sooptmcopyout(sopt, m); /* XXX */ - - /* if error, m_freem called at soopt_mcopyout(). */ + error = soopt_mcopyout(sopt, m); /* XXX */ if (error == 0) m_freem(m); break; @@ -1541,6 +1588,33 @@ bad: * transmission, and one (IP_MULTICAST_TTL) totally duplicates a * standard option (IP_TTL). */ + +/* + * following RFC1724 section 3.3, 0.0.0.0/8 is interpreted as interface index. + */ +static struct ifnet * +ip_multicast_if(a, ifindexp) + struct in_addr *a; + int *ifindexp; +{ + int ifindex; + struct ifnet *ifp; + + if (ifindexp) + *ifindexp = 0; + if (ntohl(a->s_addr) >> 24 == 0) { + ifindex = ntohl(a->s_addr) & 0xffffff; + if (ifindex < 0 || if_index < ifindex) + return NULL; + ifp = ifindex2ifnet[ifindex]; + if (ifindexp) + *ifindexp = ifindex; + } else { + INADDR_TO_IFP(*a, ifp); + } + return ifp; +} + /* * Set the IP multicast options in response to user setsockopt(). */ @@ -1553,10 +1627,11 @@ ip_setmoptions(sopt, imop) int i; struct in_addr addr; struct ip_mreq mreq; - struct ifnet *ifp; + struct ifnet *ifp = NULL; struct ip_moptions *imo = *imop; struct route ro; struct sockaddr_in *dst; + int ifindex; int s; if (imo == NULL) { @@ -1571,6 +1646,7 @@ ip_setmoptions(sopt, imop) return (ENOBUFS); *imop = imo; imo->imo_multicast_ifp = NULL; + imo->imo_multicast_addr.s_addr = INADDR_ANY; imo->imo_multicast_vif = -1; imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL; imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP; @@ -1616,13 +1692,17 @@ ip_setmoptions(sopt, imop) * it supports multicasting. */ s = splimp(); - INADDR_TO_IFP(addr, ifp); + ifp = ip_multicast_if(&addr, &ifindex); if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) { splx(s); error = EADDRNOTAVAIL; break; } imo->imo_multicast_ifp = ifp; + if (ifindex) + imo->imo_multicast_addr = addr; + else + imo->imo_multicast_addr.s_addr = INADDR_ANY; splx(s); break; @@ -1700,16 +1780,18 @@ ip_setmoptions(sopt, imop) dst->sin_family = AF_INET; dst->sin_addr = mreq.imr_multiaddr; rtalloc(&ro); - if (ro.ro_rt == NULL) { - error = EADDRNOTAVAIL; - splx(s); - break; + if (ro.ro_rt != NULL) { + ifp = ro.ro_rt->rt_ifp; + rtfree(ro.ro_rt); + } + else { + /* If there's no default route, try using loopback */ + mreq.imr_interface.s_addr = INADDR_LOOPBACK; } - ifp = ro.ro_rt->rt_ifp; - rtfree(ro.ro_rt); } - else { - INADDR_TO_IFP(mreq.imr_interface, ifp); + + if (ifp == NULL) { + ifp = ip_multicast_if(&mreq.imr_interface, NULL); } /* @@ -1777,7 +1859,7 @@ ip_setmoptions(sopt, imop) if (mreq.imr_interface.s_addr == INADDR_ANY) ifp = NULL; else { - INADDR_TO_IFP(mreq.imr_interface, ifp); + ifp = ip_multicast_if(&mreq.imr_interface, NULL); if (ifp == NULL) { error = EADDRNOTAVAIL; splx(s); @@ -1859,7 +1941,10 @@ ip_getmoptions(sopt, imo) case IP_MULTICAST_IF: if (imo == NULL || imo->imo_multicast_ifp == NULL) addr.s_addr = INADDR_ANY; - else { + else if (imo->imo_multicast_addr.s_addr) { + /* return the value user has set */ + addr = imo->imo_multicast_addr; + } else { IFP_TO_IA(imo->imo_multicast_ifp, ia); addr.s_addr = (ia == NULL) ? INADDR_ANY : IA_SIN(ia)->sin_addr.s_addr; @@ -1907,7 +1992,8 @@ ip_freemoptions(imo) if (imo != NULL) { for (i = 0; i < imo->imo_num_memberships; ++i) - in_delmulti(imo->imo_membership[i]); + if (imo->imo_membership[i] != NULL) + in_delmulti(imo->imo_membership[i]); FREE(imo, M_IPMOPTS); } } @@ -1938,11 +2024,10 @@ ip_mloopback(ifp, m, dst, hlen) * than the interface's MTU. Can this possibly matter? */ ip = mtod(copym, struct ip *); - ip->ip_len = htons((u_short)ip->ip_len); - ip->ip_off = htons((u_short)ip->ip_off); + HTONS(ip->ip_len); + HTONS(ip->ip_off); ip->ip_sum = 0; ip->ip_sum = in_cksum(copym, hlen); - /* * NB: * It's not clear whether there are any lingering @@ -1963,24 +2048,27 @@ ip_mloopback(ifp, m, dst, hlen) #endif - /* - * Mark checksum as valid or calculate checksum for loopback. - * - * This is done this way because we have to embed the ifp of - * the interface we will send the original copy of the packet - * out on in the mbuf. ip_input will check if_hwassist of the - * embedded ifp and ignore all csum_flags if if_hwassist is 0. - * The UDP checksum has not been calculated yet. - */ - if (copym->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { - if (ifp->if_hwassist) { - copym->m_pkthdr.csum_flags |= - CSUM_DATA_VALID | CSUM_PSEUDO_HDR | - CSUM_IP_CHECKED | CSUM_IP_VALID; - copym->m_pkthdr.csum_data = 0xffff; - } else - in_delayed_cksum(copym); - } + /* + * Mark checksum as valid or calculate checksum for loopback. + * + * This is done this way because we have to embed the ifp of + * the interface we will send the original copy of the packet + * out on in the mbuf. ip_input will check if_hwassist of the + * embedded ifp and ignore all csum_flags if if_hwassist is 0. + * The UDP checksum has not been calculated yet. + */ + if (copym->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { + if (ifp->if_hwassist) { + copym->m_pkthdr.csum_flags |= + CSUM_DATA_VALID | CSUM_PSEUDO_HDR | + CSUM_IP_CHECKED | CSUM_IP_VALID; + copym->m_pkthdr.csum_data = 0xffff; + } else { + NTOHS(ip->ip_len); + in_delayed_cksum(copym); + HTONS(ip->ip_len); + } + } /* @@ -1998,8 +2086,8 @@ ip_mloopback(ifp, m, dst, hlen) * to make the loopback driver compliant with the data link * requirements. */ - if (lo_dl_tag) - { copym->m_pkthdr.rcvif = ifp; + if (lo_dl_tag) { + copym->m_pkthdr.rcvif = ifp; dlil_output(lo_dl_tag, copym, 0, (struct sockaddr *) dst, 0); } else { printf("Warning: ip_output call to dlil_find_dltag failed!\n"); diff --git a/bsd/netinet/ip_var.h b/bsd/netinet/ip_var.h index c7930df60..ce1742029 100644 --- a/bsd/netinet/ip_var.h +++ b/bsd/netinet/ip_var.h @@ -56,7 +56,9 @@ #ifndef _NETINET_IP_VAR_H_ #define _NETINET_IP_VAR_H_ +#include +#ifdef __APPLE_API_PRIVATE /* * Overlay for ip header used by other protocols (tcp, udp). */ @@ -83,8 +85,12 @@ struct ipq { struct in_addr ipq_src,ipq_dst; u_long reserved[4]; /* for future use */ #if IPDIVERT - u_short ipq_divert; /* divert protocol port */ - u_short ipq_div_cookie; /* divert protocol cookie */ +#ifdef IPDIVERT_44 + u_int32_t ipq_div_info; /* ipfw divert port & flags */ +#else + u_int16_t ipq_divert; /* ipfw divert port (Maintain backward compat.) */ +#endif + u_int16_t ipq_div_cookie; /* ipfw divert cookie */ #endif }; @@ -112,8 +118,11 @@ struct ip_moptions { u_short imo_num_memberships; /* no. memberships this socket */ struct in_multi *imo_membership[IP_MAX_MEMBERSHIPS]; u_long imo_multicast_vif; /* vif num outgoing multicasts */ + struct in_addr imo_multicast_addr; /* ifindex/addr on MULTICAST_IF */ }; +#endif /* __APPLE_API_PRIVATE */ +#ifdef __APPLE_API_UNSTABLE struct ipstat { u_long ips_total; /* total packets received */ u_long ips_badsum; /* checksum bad */ @@ -143,9 +152,19 @@ struct ipstat { u_long ips_toolong; /* ip length > max ip packet size */ u_long ips_notmember; /* multicasts for unregistered grps */ u_long ips_nogif; /* no match gif found */ + u_long ips_badaddr; /* invalid address on header */ }; +#endif /* __APPLE_API_UNSTABLE */ + +#ifdef __APPLE_API_PRIVATE +#ifdef KERNEL -#if KERNEL +struct ip_linklocal_stat { + u_long iplls_in_total; + u_long iplls_in_badttl; + u_long iplls_out_total; + u_long iplls_out_badttl; +}; /* flags passed to ip_output as last parameter */ #define IP_FORWARDING 0x1 /* most of ip header exists */ @@ -159,7 +178,9 @@ struct route; struct sockopt; extern struct ipstat ipstat; +#if !defined(RANDOM_IP_ID) || RANDOM_IP_ID == 0 extern u_short ip_id; /* ip packet ctr, for ids */ +#endif extern int ip_defttl; /* default IP ttl */ extern int ipforwarding; /* ip forwarding */ extern struct protosw *ip_protox[]; @@ -184,6 +205,10 @@ void ip_slowtimo __P((void)); struct mbuf * ip_srcroute __P((void)); void ip_stripoptions __P((struct mbuf *, struct mbuf *)); +#if RANDOM_IP_ID +u_int16_t + ip_randomid __P((void)); +#endif int rip_ctloutput __P((struct socket *, struct sockopt *)); void rip_ctlinput __P((int, struct sockaddr *, void *)); void rip_init __P((void)); @@ -200,13 +225,16 @@ void ip_rsvp_force_done __P((struct socket *)); #if IPDIVERT void div_init __P((void)); void div_input __P((struct mbuf *, int)); +void divert_packet __P((struct mbuf *, int, int)); extern struct pr_usrreqs div_usrreqs; -extern u_short ip_divert_port; -extern u_short ip_divert_cookie; +extern u_int16_t ip_divert_cookie; #endif extern struct sockaddr_in *ip_fw_fwd_addr; -#endif /* KERNEL */ +void in_delayed_cksum(struct mbuf *m); + +#endif /* _KERNEL */ +#endif /* __APPLE_API_PRIVATE */ #endif /* !_NETINET_IP_VAR_H_ */ diff --git a/bsd/netinet/ipl.h b/bsd/netinet/ipl.h deleted file mode 100644 index dba3d458b..000000000 --- a/bsd/netinet/ipl.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (C) 1993-1997 by Darren Reed. - * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and due credit is given - * to the original author and the contributors. - * - * @(#)ipl.h 1.21 6/5/96 - */ - -#ifndef __IPL_H__ -#define __IPL_H__ - -#define IPL_VERSION "IP Filter v3.2.7" - -#endif diff --git a/bsd/netinet/raw_ip.c b/bsd/netinet/raw_ip.c index 34b69fd68..cf4f38aa6 100644 --- a/bsd/netinet/raw_ip.c +++ b/bsd/netinet/raw_ip.c @@ -65,7 +65,7 @@ #include #include -#if ISFB31 +#if __FreeBSD__ #include #endif @@ -76,8 +76,6 @@ #include #include #include -#include -#include #include #include #include @@ -89,22 +87,16 @@ #include #endif /*IPSEC*/ -#if ISFB31 -#include "opt_ipdn.h" -#endif - #if DUMMYNET #include #endif -#if !defined(COMPAT_IPFW) || COMPAT_IPFW == 1 -#undef COMPAT_IPFW -#define COMPAT_IPFW 1 -#else -#undef COMPAT_IPFW + +#if IPSEC +extern int ipsec_bypass; #endif -struct inpcbhead ripcb; -struct inpcbinfo ripcbinfo; +struct inpcbhead ripcb; +struct inpcbinfo ripcbinfo; /* * Nominal space allocated to a raw ip socket. @@ -156,10 +148,11 @@ rip_input(m, iphlen) ripsrc.sin_addr = ip->ip_src; LIST_FOREACH(inp, &ripcb, inp_list) { - if ((inp->inp_vflag & INP_IPV4) == NULL) +#if INET6 + if ((inp->inp_vflag & INP_IPV4) == 0) continue; -#warning do something about this - if (inp->inp_ip_p && inp->inp_ip_p != ip->ip_p) +#endif + if (inp->inp_ip_p && (inp->inp_ip_p != ip->ip_p)) continue; if (inp->inp_laddr.s_addr && inp->inp_laddr.s_addr != ip->ip_dst.s_addr) @@ -169,15 +162,24 @@ rip_input(m, iphlen) continue; if (last) { struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); + +#if IPSEC + /* check AH/ESP integrity. */ + if (ipsec_bypass == 0 && n && ipsec4_in_reject_so(n, last->inp_socket)) { + m_freem(n); + ipsecstat.in_polvio++; + /* do not inject data to pcb */ + } else +#endif /*IPSEC*/ if (n) { if (last->inp_flags & INP_CONTROLOPTS || last->inp_socket->so_options & SO_TIMESTAMP) ip_savecontrol(last, &opts, ip, n); - if (last->inp_flags & INP_STRIPHDR) { - n->m_len -= iphlen; - n->m_pkthdr.len -= iphlen; - n->m_data += iphlen; - } + if (last->inp_flags & INP_STRIPHDR) { + n->m_len -= iphlen; + n->m_pkthdr.len -= iphlen; + n->m_data += iphlen; + } if (sbappendaddr(&last->inp_socket->so_rcv, (struct sockaddr *)&ripsrc, n, opts) == 0) { @@ -186,15 +188,22 @@ rip_input(m, iphlen) m_freem(n); if (opts) m_freem(opts); - } else { - /* kprintf("rip_input calling sorwakeup\n"); */ - sorwakeup(last->inp_socket); - } + } else + sorwakeup(last->inp_socket); opts = 0; } } last = inp; } +#if IPSEC + /* check AH/ESP integrity. */ + if (ipsec_bypass == 0 && last && ipsec4_in_reject_so(m, last->inp_socket)) { + m_freem(m); + ipsecstat.in_polvio++; + ipstat.ips_delivered--; + /* do not inject data to pcb */ + } else +#endif /*IPSEC*/ if (last) { if (last->inp_flags & INP_CONTROLOPTS || last->inp_socket->so_options & SO_TIMESTAMP) @@ -210,15 +219,13 @@ rip_input(m, iphlen) m_freem(m); if (opts) m_freem(opts); - } else { - /* kprintf("rip_input calling sorwakeup\n"); */ - sorwakeup(last->inp_socket); - } + } else + sorwakeup(last->inp_socket); } else { m_freem(m); - ipstat.ips_noproto++; - ipstat.ips_delivered--; - } + ipstat.ips_noproto++; + ipstat.ips_delivered--; + } } /* @@ -246,13 +253,13 @@ rip_output(m, so, dst) } M_PREPEND(m, sizeof(struct ip), M_WAIT); ip = mtod(m, struct ip *); - ip->ip_tos = 0; + ip->ip_tos = inp->inp_ip_tos; ip->ip_off = 0; ip->ip_p = inp->inp_ip_p; ip->ip_len = m->m_pkthdr.len; ip->ip_src = inp->inp_laddr; ip->ip_dst.s_addr = dst; - ip->ip_ttl = MAXTTL; + ip->ip_ttl = inp->inp_ip_ttl; } else { if (m->m_pkthdr.len > IP_MAXPACKET) { m_freem(m); @@ -261,7 +268,7 @@ rip_output(m, so, dst) ip = mtod(m, struct ip *); /* don't allow both user specified and setsockopt options, and don't allow packet length sizes that will crash */ - if (((IP_VHL_HL(ip->ip_vhl) != (sizeof (*ip) >> 2)) + if (((IP_VHL_HL(ip->ip_vhl) != (sizeof (*ip) >> 2)) && inp->inp_options) || (ip->ip_len > m->m_pkthdr.len) || (ip->ip_len < (IP_VHL_HL(ip->ip_vhl) << 2))) { @@ -269,14 +276,21 @@ rip_output(m, so, dst) return EINVAL; } if (ip->ip_id == 0) +#if RANDOM_IP_ID + ip->ip_id = ip_randomid(); +#else ip->ip_id = htons(ip_id++); +#endif /* XXX prevent ip_output from overwriting header fields */ flags |= IP_RAWOUTPUT; ipstat.ips_rawout++; } #if IPSEC - m->m_pkthdr.rcvif = (struct ifnet *)so; /*XXX*/ + if (ipsec_bypass == 0 && ipsec_setsocket(m, so) != 0) { + m_freem(m); + return ENOBUFS; + } #endif /*IPSEC*/ return (ip_output(m, inp->inp_options, &inp->inp_route, flags, @@ -312,20 +326,16 @@ rip_ctloutput(so, sopt) error = sooptcopyout(sopt, &optval, sizeof optval); break; -#if COMPAT_IPFW + case IP_FW_ADD: case IP_FW_GET: + case IP_OLD_FW_ADD: + case IP_OLD_FW_GET: if (ip_fw_ctl_ptr == 0) error = ENOPROTOOPT; else error = ip_fw_ctl_ptr(sopt); break; - case IP_NAT: - if (ip_nat_ctl_ptr == 0) - error = ENOPROTOOPT; - else - error = ip_nat_ctl_ptr(sopt); - break; #if DUMMYNET case IP_DUMMYNET_GET: if (ip_dn_ctl_ptr == NULL) @@ -334,7 +344,6 @@ rip_ctloutput(so, sopt) error = ip_dn_ctl_ptr(sopt); break ; #endif /* DUMMYNET */ -#endif /* COMPAT_IPFW */ case MRT_INIT: case MRT_DONE: @@ -378,23 +387,22 @@ rip_ctloutput(so, sopt) break; -#if COMPAT_IPFW case IP_FW_ADD: case IP_FW_DEL: case IP_FW_FLUSH: case IP_FW_ZERO: + case IP_FW_RESETLOG: + case IP_OLD_FW_ADD: + case IP_OLD_FW_DEL: + case IP_OLD_FW_FLUSH: + case IP_OLD_FW_ZERO: + case IP_OLD_FW_RESETLOG: if (ip_fw_ctl_ptr == 0) error = ENOPROTOOPT; else error = ip_fw_ctl_ptr(sopt); break; - case IP_NAT: - if (ip_nat_ctl_ptr == 0) - error = ENOPROTOOPT; - else - error = ip_nat_ctl_ptr(sopt); - break; #if DUMMYNET case IP_DUMMYNET_CONFIGURE: case IP_DUMMYNET_DEL: @@ -405,7 +413,6 @@ rip_ctloutput(so, sopt) error = ip_dn_ctl_ptr(sopt); break ; #endif -#endif /* COMPAT_IPFW */ case IP_RSVP_ON: error = ip_rsvp_init(so); @@ -479,7 +486,7 @@ rip_ctlinput(cmd, sa, vip) * thing to do, but at least if we are running * a routing process they will come back. */ - in_ifadown(&ia->ia_ifa); + in_ifadown(&ia->ia_ifa, 1); break; } } @@ -510,10 +517,10 @@ rip_ctlinput(cmd, sa, vip) u_long rip_sendspace = RIPSNDQ; u_long rip_recvspace = RIPRCVQ; -SYSCTL_INT(_net_inet_raw, OID_AUTO, maxdgram, CTLFLAG_RW, &rip_sendspace, - 0, ""); -SYSCTL_INT(_net_inet_raw, OID_AUTO, recvspace, CTLFLAG_RW, &rip_recvspace, - 0, ""); +SYSCTL_INT(_net_inet_raw, OID_AUTO, maxdgram, CTLFLAG_RW, + &rip_sendspace, 0, "Maximum outgoing raw IP datagram size"); +SYSCTL_INT(_net_inet_raw, OID_AUTO, recvspace, CTLFLAG_RW, + &rip_recvspace, 0, "Maximum incoming raw IP datagram size"); static int rip_attach(struct socket *so, int proto, struct proc *p) @@ -524,39 +531,30 @@ rip_attach(struct socket *so, int proto, struct proc *p) inp = sotoinpcb(so); if (inp) panic("rip_attach"); - - -#if ISFB31 - if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0) - return error; +#if __APPLE__ + if ((so->so_state & SS_PRIV) == 0) + return (EPERM); #else - if ((so->so_state & SS_PRIV) == 0) - return (EPERM); + if (p && (error = suser(p)) != 0) + return error; #endif + error = soreserve(so, rip_sendspace, rip_recvspace); + if (error) + return error; s = splnet(); error = in_pcballoc(so, &ripcbinfo, p); splx(s); - if (error) - return error; - error = soreserve(so, rip_sendspace, rip_recvspace); if (error) return error; inp = (struct inpcb *)so->so_pcb; inp->inp_vflag |= INP_IPV4; inp->inp_ip_p = proto; -#if IPSEC - error = ipsec_init_policy(so, &inp->inp_sp); - if (error != 0) { - in_pcbdetach(inp); - return error; - } -#endif /*IPSEC*/ - + inp->inp_ip_ttl = ip_defttl; return 0; } -static int +__private_extern__ int rip_detach(struct socket *so) { struct inpcb *inp; @@ -573,14 +571,14 @@ rip_detach(struct socket *so) return 0; } -static int +__private_extern__ int rip_abort(struct socket *so) { soisdisconnected(so); return rip_detach(so); } -static int +__private_extern__ int rip_disconnect(struct socket *so) { if ((so->so_state & SS_ISCONNECTED) == 0) @@ -588,7 +586,7 @@ rip_disconnect(struct socket *so) return rip_abort(so); } -static int +__private_extern__ int rip_bind(struct socket *so, struct sockaddr *nam, struct proc *p) { struct inpcb *inp = sotoinpcb(so); @@ -606,7 +604,7 @@ rip_bind(struct socket *so, struct sockaddr *nam, struct proc *p) return 0; } -static int +__private_extern__ int rip_connect(struct socket *so, struct sockaddr *nam, struct proc *p) { struct inpcb *inp = sotoinpcb(so); @@ -624,14 +622,14 @@ rip_connect(struct socket *so, struct sockaddr *nam, struct proc *p) return 0; } -static int +__private_extern__ int rip_shutdown(struct socket *so) { socantsendmore(so); return 0; } -static int +__private_extern__ int rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, struct mbuf *control, struct proc *p) { @@ -654,7 +652,6 @@ rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, return rip_output(m, so, dst); } - static int rip_pcblist SYSCTL_HANDLER_ARGS { @@ -692,11 +689,11 @@ rip_pcblist SYSCTL_HANDLER_ARGS error = SYSCTL_OUT(req, &xig, sizeof xig); if (error) return error; - /* - * We are done if there is no pcb - */ - if (n == 0) - return 0; + /* + * We are done if there is no pcb + */ + if (n == 0) + return 0; inp_list = _MALLOC(n * sizeof *inp_list, M_TEMP, M_WAITOK); if (inp_list == 0) @@ -743,7 +740,6 @@ rip_pcblist SYSCTL_HANDLER_ARGS return error; } - SYSCTL_PROC(_net_inet_raw, OID_AUTO/*XXX*/, pcblist, CTLFLAG_RD, 0, 0, rip_pcblist, "S,xinpcb", "List of active raw IP sockets"); @@ -751,6 +747,6 @@ struct pr_usrreqs rip_usrreqs = { rip_abort, pru_accept_notsupp, rip_attach, rip_bind, rip_connect, pru_connect2_notsupp, in_control, rip_detach, rip_disconnect, pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp, - pru_rcvoob_notsupp, rip_send, pru_sense_null, rip_shutdown, + pru_rcvoob_notsupp, rip_send, pru_sense_null, rip_shutdown, in_setsockaddr, sosend, soreceive, sopoll }; diff --git a/bsd/netinet/tcp.h b/bsd/netinet/tcp.h index 5cd425b9c..39efb3d79 100644 --- a/bsd/netinet/tcp.h +++ b/bsd/netinet/tcp.h @@ -52,10 +52,12 @@ * SUCH DAMAGE. * * @(#)tcp.h 8.1 (Berkeley) 6/10/93 + * $FreeBSD: src/sys/netinet/tcp.h,v 1.13.2.3 2001/03/01 22:08:42 jlemon Exp $ */ #ifndef _NETINET_TCP_H_ #define _NETINET_TCP_H_ +#include typedef u_int32_t tcp_seq; typedef u_int32_t tcp_cc; /* connection count per rfc1644 */ @@ -87,7 +89,9 @@ struct tcphdr { #define TH_PUSH 0x08 #define TH_ACK 0x10 #define TH_URG 0x20 -#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG) +#define TH_ECE 0x40 +#define TH_CWR 0x80 +#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR) u_short th_win; /* window */ u_short th_sum; /* checksum */ @@ -138,6 +142,8 @@ struct tcphdr { #define TCP_MAX_WINSHIFT 14 /* maximum window shift */ +#define TCP_MAXBURST 4 /* maximum segments in a burst */ + #define TCP_MAXHLEN (0xf<<2) /* max length of header in bytes */ #define TCP_MAXOLEN (TCP_MAXHLEN - sizeof(struct tcphdr)) /* max space left for options */ diff --git a/bsd/netinet/tcp_debug.c b/bsd/netinet/tcp_debug.c index 8eef1d998..a7043db15 100644 --- a/bsd/netinet/tcp_debug.c +++ b/bsd/netinet/tcp_debug.c @@ -52,12 +52,9 @@ * SUCH DAMAGE. * * @(#)tcp_debug.c 8.1 (Berkeley) 6/10/93 + * $FreeBSD: src/sys/netinet/tcp_debug.c,v 1.16.2.1 2000/07/15 07:14:31 kris Exp $ */ -#if ISFB31 -#include "opt_inet.h" -#include "opt_tcpdebug.h" -#endif #ifndef INET #error The option TCPDEBUG requires option INET. @@ -74,11 +71,14 @@ #include #include #include +#include #include #include #include +#if INET6 #include +#endif #include #include #include @@ -98,24 +98,28 @@ static int tcp_debx; * Tcp debug routines */ void -tcp_trace(act, ostate, tp, ip, th, req) +tcp_trace(act, ostate, tp, ipgen, th, req) short act, ostate; struct tcpcb *tp; -#if INET6 - void *ip; -#else - struct ip *ip; -#endif + void *ipgen; struct tcphdr *th; int req; { #if INET6 - int isipv6 = (ip != NULL && ((struct ip *)ip)->ip_v == 6) ? 1 : 0; + int isipv6; #endif /* INET6 */ tcp_seq seq, ack; int len, flags; struct tcp_debug *td = &tcp_debug[tcp_debx++]; +#if INET6 + isipv6 = (ipgen != NULL && ((struct ip *)ipgen)->ip_v == 6) ? 1 : 0; +#endif /* INET6 */ + td->td_family = +#if INET6 + (isipv6 != 0) ? AF_INET6 : +#endif + AF_INET; if (tcp_debx == TCP_NDEBUG) tcp_debx = 0; td->td_time = iptime(); @@ -126,24 +130,54 @@ tcp_trace(act, ostate, tp, ip, th, req) td->td_cb = *tp; else bzero((caddr_t)&td->td_cb, sizeof (*tp)); - if (ip) { + if (ipgen) { + switch (td->td_family) { + case AF_INET: + bcopy((caddr_t)ipgen, (caddr_t)&td->td_ti.ti_i, + sizeof(td->td_ti.ti_i)); + bzero((caddr_t)td->td_ip6buf, sizeof(td->td_ip6buf)); + break; #if INET6 - if (isipv6) - td->td_ip6 = *(struct ip6_hdr *)ip; - else - td->td_ip = *(struct ip *)ip; -#else /* INET6 */ - td->td_ip = *ip; -#endif /* INET6 */ - } else + case AF_INET6: + bcopy((caddr_t)ipgen, (caddr_t)td->td_ip6buf, + sizeof(td->td_ip6buf)); + bzero((caddr_t)&td->td_ti.ti_i, + sizeof(td->td_ti.ti_i)); + break; +#endif + default: + bzero((caddr_t)td->td_ip6buf, sizeof(td->td_ip6buf)); + bzero((caddr_t)&td->td_ti.ti_i, + sizeof(td->td_ti.ti_i)); + break; + } + } else { + bzero((caddr_t)&td->td_ti.ti_i, sizeof(td->td_ti.ti_i)); + bzero((caddr_t)td->td_ip6buf, sizeof(td->td_ip6buf)); + } + if (th) { + switch (td->td_family) { + case AF_INET: + td->td_ti.ti_t = *th; + bzero((caddr_t)&td->td_ti6.th, sizeof(td->td_ti6.th)); + break; #if INET6 - bzero((caddr_t)&td->_td_ipx, sizeof (td->_td_ipx)); -#else /* INET6 */ - bzero((caddr_t)&td->td_ip, sizeof (*ip)); -#endif /* INET6 */ - if (th) - td->td_th = *th; - + case AF_INET6: + td->td_ti6.th = *th; + bzero((caddr_t)&td->td_ti.ti_t, + sizeof(td->td_ti.ti_t)); + break; +#endif + default: + bzero((caddr_t)&td->td_ti.ti_t, + sizeof(td->td_ti.ti_t)); + bzero((caddr_t)&td->td_ti6.th, sizeof(td->td_ti6.th)); + break; + } + } else { + bzero((caddr_t)&td->td_ti.ti_t, sizeof(td->td_ti.ti_t)); + bzero((caddr_t)&td->td_ti6.th, sizeof(td->td_ti6.th)); + } td->td_req = req; #if TCPDEBUG if (tcpconsdebug == 0) @@ -158,19 +192,15 @@ tcp_trace(act, ostate, tp, ip, th, req) case TA_INPUT: case TA_OUTPUT: case TA_DROP: - if (ip == 0) + if (ipgen == NULL || th == NULL) break; -#if INET6 - if (isipv6) { - len = ((struct ip6_hdr *)ip)->ip6_plen; - } else { - len = ((struct ip *)ip)->ip_len; - } -#else /* INET6 */ - len = ip->ip_len; -#endif /* INET6 */ seq = th->th_seq; ack = th->th_ack; + len = +#if INET6 + isipv6 ? ((struct ip6_hdr *)ipgen)->ip6_plen : +#endif + ((struct ip *)ipgen)->ip_len; if (act == TA_OUTPUT) { seq = ntohl(seq); ack = ntohl(ack); diff --git a/bsd/netinet/tcp_debug.h b/bsd/netinet/tcp_debug.h index 79eb6c7bb..76a05474e 100644 --- a/bsd/netinet/tcp_debug.h +++ b/bsd/netinet/tcp_debug.h @@ -52,25 +52,34 @@ * SUCH DAMAGE. * * @(#)tcp_debug.h 8.1 (Berkeley) 6/10/93 + * $FreeBSD: src/sys/netinet/tcp_debug.h,v 1.11 2000/01/29 11:49:05 shin Exp $ */ #ifndef _NETINET_TCP_DEBUG_H_ #define _NETINET_TCP_DEBUG_H_ +#include +#ifdef __APPLE_API_PRIVATE struct tcp_debug { n_time td_time; short td_act; short td_ostate; caddr_t td_tcb; - union { - struct ip _td_ip4; -#define td_ip _td_ipx._td_ip4 -#if INET6 - struct ip6_hdr _td_ip6; -#define td_ip6 _td_ipx._td_ip6 + int td_family; + /* + * Co-existense of td_ti and td_ti6 below is ugly, but it is necessary + * to achieve backword compatibility to some extent. + */ + struct tcpiphdr td_ti; + struct { +#if !defined(KERNEL) && defined(INET6) + struct ip6_hdr ip6; +#else + u_char ip6buf[40]; /* sizeof(struct ip6_hdr) */ #endif - } _td_ipx; - struct tcphdr td_th; + struct tcphdr th; + } td_ti6; +#define td_ip6buf td_ti6.ip6buf short td_req; struct tcpcb td_cb; }; @@ -93,5 +102,6 @@ static char *tanames[] = struct tcp_debug tcp_debug[TCP_NDEBUG]; int tcp_debx; #endif +#endif /* __APPLE_API_PRIVATE */ #endif /* !_NETINET_TCP_DEBUG_H_ */ diff --git a/bsd/netinet/tcp_fsm.h b/bsd/netinet/tcp_fsm.h index bc3f5dab8..e4a2e6826 100644 --- a/bsd/netinet/tcp_fsm.h +++ b/bsd/netinet/tcp_fsm.h @@ -52,10 +52,12 @@ * SUCH DAMAGE. * * @(#)tcp_fsm.h 8.1 (Berkeley) 6/10/93 + * $FreeBSD: src/sys/netinet/tcp_fsm.h,v 1.14 1999/11/07 04:18:30 jlemon Exp $ */ #ifndef _NETINET_TCP_FSM_H_ #define _NETINET_TCP_FSM_H_ +#include /* * TCP FSM state definitions. @@ -94,10 +96,11 @@ #define TCP6S_TIME_WAIT TCPS_TIME_WAIT #define TCPS_HAVERCVDSYN(s) ((s) >= TCPS_SYN_RECEIVED) -#define TCPS_HAVEESTABLISHED(s) ((s) >= TCPS_ESTABLISHED) +#define TCPS_HAVEESTABLISHED(s) ((s) >= TCPS_ESTABLISHED) #define TCPS_HAVERCVDFIN(s) ((s) >= TCPS_TIME_WAIT) -#ifdef TCPOUTFLAGS +#ifdef __APPLE_API_UNSTABLE +#ifdef TCPOUTFLAGS /* * Flags used when sending segments in tcp_output. * Basic flags (TH_RST,TH_ACK,TH_SYN,TH_FIN) are totally @@ -118,9 +121,12 @@ static u_char tcp_outflags[TCP_NSTATES] = { TH_ACK, /* 10, TIME_WAIT */ }; #endif +#endif /* __APPLE_API_UNSTABLE */ #if KPROF +#ifdef __APPLE_API_PRIVATE int tcp_acounts[TCP_NSTATES][PRU_NREQ]; +#endif /* __APPLE_API_PRIVATE */ #endif #ifdef TCPSTATES diff --git a/bsd/netinet/tcp_input.c b/bsd/netinet/tcp_input.c index 008e01fe4..2e14bc577 100644 --- a/bsd/netinet/tcp_input.c +++ b/bsd/netinet/tcp_input.c @@ -52,12 +52,9 @@ * SUCH DAMAGE. * * @(#)tcp_input.c 8.12 (Berkeley) 5/24/95 + * $FreeBSD: src/sys/netinet/tcp_input.c,v 1.107.2.16 2001/08/22 00:59:12 silby Exp $ */ -#if ISFB31 -#include "opt_ipfw.h" /* for ipfw_fwd */ -#include "opt_tcpdebug.h" -#endif #include #include @@ -79,11 +76,11 @@ #include #include #include -#include /* for ICMP_BANDLIM */ +#include /* for ICMP_BANDLIM */ #include -#include -#include /* for ICMP_BANDLIM */ +#include /* for ICMP_BANDLIM */ #include +#include #if INET6 #include #include @@ -96,50 +93,72 @@ #include #include #include +#if INET6 +#include +#endif #include #if TCPDEBUG #include -#if INET6 -union { - struct ip _tcp_si4; - struct ip6_hdr _tcp_si6; -} tcp_saveip; -#else -struct ip tcp_saveip; -#endif /* INET6 */ +u_char tcp_saveipgen[40]; /* the size must be of max ip header, now IPv6 */ struct tcphdr tcp_savetcp; #endif /* TCPDEBUG */ #if IPSEC #include +#if INET6 +#include +#endif #include #endif /*IPSEC*/ #include +#ifndef __APPLE__ +MALLOC_DEFINE(M_TSEGQ, "tseg_qent", "TCP segment queue entry"); +#endif + #define DBG_LAYER_BEG NETDBG_CODE(DBG_NETTCP, 0) #define DBG_LAYER_END NETDBG_CODE(DBG_NETTCP, 2) #define DBG_FNC_TCP_INPUT NETDBG_CODE(DBG_NETTCP, (3 << 8)) #define DBG_FNC_TCP_NEWCONN NETDBG_CODE(DBG_NETTCP, (7 << 8)) static int tcprexmtthresh = 3; -tcp_seq tcp_iss; tcp_cc tcp_ccgen; extern int apple_hwcksum_rx; +#if IPSEC +extern int ipsec_bypass; +#endif + struct tcpstat tcpstat; -SYSCTL_STRUCT(_net_inet_tcp, TCPCTL_STATS, stats, - CTLFLAG_RD, &tcpstat , tcpstat, ""); +SYSCTL_STRUCT(_net_inet_tcp, TCPCTL_STATS, stats, CTLFLAG_RD, + &tcpstat , tcpstat, "TCP statistics (struct tcpstat, netinet/tcp_var.h)"); -int log_in_vain = 0; +static int log_in_vain = 0; SYSCTL_INT(_net_inet_tcp, OID_AUTO, log_in_vain, CTLFLAG_RW, - &log_in_vain, 0, ""); + &log_in_vain, 0, "Log all incoming TCP connections"); + +static int blackhole = 0; +SYSCTL_INT(_net_inet_tcp, OID_AUTO, blackhole, CTLFLAG_RW, + &blackhole, 0, "Do not send RST when dropping refused connections"); int tcp_delack_enabled = 1; SYSCTL_INT(_net_inet_tcp, OID_AUTO, delayed_ack, CTLFLAG_RW, - &tcp_delack_enabled, 0, ""); + &tcp_delack_enabled, 0, + "Delay ACK to try and piggyback it onto a data packet"); + +int tcp_lq_overflow = 1; +SYSCTL_INT(_net_inet_tcp, OID_AUTO, tcp_lq_overflow, CTLFLAG_RW, + &tcp_lq_overflow, 0, + "Listen Queue Overflow"); + +#if TCP_DROP_SYNFIN +static int drop_synfin = 0; +SYSCTL_INT(_net_inet_tcp, OID_AUTO, drop_synfin, CTLFLAG_RW, + &drop_synfin, 0, "Drop TCP packets with SYN+FIN set"); +#endif -u_long tcp_now; +u_long tcp_now; struct inpcbhead tcb; #define tcb6 tcb /* for KAME src sync over BSD*'s */ struct inpcbinfo tcbinfo; @@ -147,81 +166,50 @@ struct inpcbinfo tcbinfo; static void tcp_dooptions __P((struct tcpcb *, u_char *, int, struct tcphdr *, struct tcpopt *)); static void tcp_pulloutofband __P((struct socket *, - struct tcphdr *, struct mbuf *)); + struct tcphdr *, struct mbuf *, int)); +static int tcp_reass __P((struct tcpcb *, struct tcphdr *, int *, + struct mbuf *)); static void tcp_xmit_timer __P((struct tcpcb *, int)); +static int tcp_newreno __P((struct tcpcb *, struct tcphdr *)); -/* - * Neighbor Discovery, Neighbor Unreachability Detection - * Upper layer hint. - */ -#define ND6_HINT(tp) { \ - if ((tp) && (tp)->t_inpcb && (tp)->t_inpcb->in6p_route.ro_rt) \ - nd6_nud_hint((tp)->t_inpcb->in6p_route.ro_rt, NULL); \ -} - - -extern u_long current_active_connections; -extern u_long last_active_conn_count; - -extern u_long *delack_bitmask; - - - - -/* - * 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). - */ +/* Neighbor Discovery, Neighbor Unreachability Detection Upper layer hint. */ #if INET6 -#define _ONLY_IF_INET6_(x) x +#define ND6_HINT(tp) \ +do { \ + if ((tp) && (tp)->t_inpcb && \ + ((tp)->t_inpcb->inp_vflag & INP_IPV6) != 0 && \ + (tp)->t_inpcb->in6p_route.ro_rt) \ + nd6_nud_hint((tp)->t_inpcb->in6p_route.ro_rt, NULL, 0); \ +} while (0) #else -#define _ONLY_IF_INET6_(x) +#define ND6_HINT(tp) #endif -#define TCP_REASS(tp, th, tilen, m, so, flags, isipv6, needwakeup) { \ - if ((th)->th_seq == (tp)->rcv_nxt && \ - (tp)->segq.lh_first == NULL && \ - (tp)->t_state == TCPS_ESTABLISHED) { \ - if (tcp_delack_enabled) {\ - if (last_active_conn_count > DELACK_BITMASK_THRESH) \ - TCP_DELACK_BITSET(tp->t_inpcb->hash_element); \ - tp->t_flags |= TF_DELACK; \ - } \ - else \ - tp->t_flags |= TF_ACKNOW; \ - (tp)->rcv_nxt += (tilen); \ - flags = (th)->th_flags & TH_FIN; \ - tcpstat.tcps_rcvpack++;\ - tcpstat.tcps_rcvbyte += (tilen);\ - _ONLY_IF_INET6_(ND6_HINT(tp);) \ - sbappend(&(so)->so_rcv, (m)); \ - needwakeup++; \ - } else { \ - (flags) = tcp_reass((tp), (th), (tilen), (m), (isipv6)); \ - tp->t_flags |= TF_ACKNOW; \ - } \ -} + +extern u_long *delack_bitmask; /* - * Note: - * in the ip header part of the ipqe_tcp structure only the length is used. + * Indicate whether this ack should be delayed. We can delay the ack if + * - delayed acks are enabled and + * - there is no delayed ack timer in progress and + * - our last ack wasn't a 0-sized window. We never want to delay + * the ack that opens up a 0-sized window. */ -int -tcp_reass(tp, th, tilen, m, isipv6) +#define DELAY_ACK(tp) \ + (tcp_delack_enabled && !callout_pending(tp->tt_delack) && \ + (tp->t_flags & TF_RXWIN0SENT) == 0) + + +static int +tcp_reass(tp, th, tlenp, m) register struct tcpcb *tp; register struct tcphdr *th; - u_int16_t tilen; + int *tlenp; struct mbuf *m; -#if INET6 - int isipv6; -#endif { - register struct ipqent *p, *q, *nq, *tiqe; + struct tseg_qent *q; + struct tseg_qent *p = NULL; + struct tseg_qent *nq; + struct tseg_qent *te; struct socket *so = tp->t_inpcb->inp_socket; int flags; @@ -232,16 +220,10 @@ tcp_reass(tp, th, tilen, m, isipv6) if (th == 0) goto present; -#if 0 /* Not using GETTCP(m) macro */ - m->m_pkthdr.header = ti; -#endif - - /* - * Allocate a new queue entry, before we throw away any data. - * If we can't, just drop the packet. XXX - */ - MALLOC(tiqe, struct ipqent *, sizeof (struct ipqent), M_SONAME, M_NOWAIT); - if (tiqe == NULL) { + /* Allocate a new queue entry. If we can't, just drop the pkt. XXX */ + MALLOC(te, struct tseg_qent *, sizeof (struct tseg_qent), M_TSEGQ, + M_NOWAIT); + if (te == NULL) { tcpstat.tcps_rcvmemdrop++; m_freem(m); return (0); @@ -250,10 +232,11 @@ tcp_reass(tp, th, tilen, m, isipv6) /* * Find a segment which begins after this one does. */ - for (p = NULL, q = tp->segq.lh_first; q != NULL; - p = q, q = q->ipqe_q.le_next) - if (SEQ_GT(q->ipqe_tcp->ti_seq, th->th_seq)) + LIST_FOREACH(q, &tp->t_segq, tqe_q) { + if (SEQ_GT(q->tqe_th->th_seq, th->th_seq)) break; + p = q; + } /* * If there is a preceding segment, it may provide some of @@ -261,19 +244,15 @@ tcp_reass(tp, th, tilen, m, isipv6) * segment. If it provides all of our data, drop us. */ if (p != NULL) { - register struct tcpiphdr *phdr = p->ipqe_tcp; register int i; - /* conversion to int (in i) handles seq wraparound */ - i = phdr->ti_seq + phdr->ti_len - th->th_seq; + i = p->tqe_th->th_seq + p->tqe_len - th->th_seq; if (i > 0) { - if (i >= tilen) { + if (i >= *tlenp) { tcpstat.tcps_rcvduppack++; - tcpstat.tcps_rcvdupbyte += tilen; + tcpstat.tcps_rcvdupbyte += *tlenp; m_freem(m); - FREE(tiqe, M_SONAME); - -#if 1 /* XXX: NetBSD just return 0 here */ + FREE(te, M_TSEGQ); /* * Try to present any queued data * at the left window edge to the user. @@ -281,54 +260,46 @@ tcp_reass(tp, th, tilen, m, isipv6) * completes. */ goto present; /* ??? */ -#endif } m_adj(m, i); - tilen -= i; + *tlenp -= i; th->th_seq += i; } } tcpstat.tcps_rcvoopack++; - tcpstat.tcps_rcvoobyte += tilen; + tcpstat.tcps_rcvoobyte += *tlenp; /* * While we overlap succeeding segments trim them or, * if they are completely covered, dequeue them. */ while (q) { - register struct tcpiphdr *qhdr = q->ipqe_tcp; - register int i = (th->th_seq + tilen) - qhdr->ti_seq; - + register int i = (th->th_seq + *tlenp) - q->tqe_th->th_seq; if (i <= 0) break; - if (i < qhdr->ti_len) { - qhdr->ti_seq += i; - qhdr->ti_len -= i; - m_adj(q->ipqe_m, i); + if (i < q->tqe_len) { + q->tqe_th->th_seq += i; + q->tqe_len -= i; + m_adj(q->tqe_m, i); break; } - nq = q->ipqe_q.le_next; - m_freem(q->ipqe_m); - LIST_REMOVE(q, ipqe_q); - FREE(q, M_SONAME); + + nq = LIST_NEXT(q, tqe_q); + LIST_REMOVE(q, tqe_q); + m_freem(q->tqe_m); + FREE(q, M_TSEGQ); q = nq; } - /* Insert the new fragment queue entry into place. */ - tiqe->ipqe_m = m; - /* - * There is a IP or IPv6 header in the mbuf before th - * so there is space for an ip header (for the length field) - */ -#define thtoti(x) \ - ((struct tcpiphdr *)(((char *)(x)) - (sizeof (struct ip)))) + /* Insert the new segment queue entry into place. */ + te->tqe_m = m; + te->tqe_th = th; + te->tqe_len = *tlenp; - tiqe->ipqe_tcp = thtoti(th); - tiqe->ipqe_tcp->ti_len = tilen; if (p == NULL) { - LIST_INSERT_HEAD(&tp->segq, tiqe, ipqe_q); + LIST_INSERT_HEAD(&tp->t_segq, te, tqe_q); } else { - LIST_INSERT_AFTER(p, tiqe, ipqe_q); + LIST_INSERT_AFTER(p, te, tqe_q); } present: @@ -338,42 +309,47 @@ present: */ if (!TCPS_HAVEESTABLISHED(tp->t_state)) return (0); - q = tp->segq.lh_first; - if (!q || q->ipqe_tcp->ti_seq != tp->rcv_nxt) - return (0); -#if 0 - /* - * XXX from INRIA for NetBSD, but should not happen because - * TCPS_HAVEESTABLISHED(tp->t_state) should be true here. - */ - if (tp->t_state == TCPS_SYN_RECEIVED && q->ipqe_tcp->ti_len) + q = LIST_FIRST(&tp->t_segq); + if (!q || q->tqe_th->th_seq != tp->rcv_nxt) return (0); -#endif do { - tp->rcv_nxt += q->ipqe_tcp->ti_len; - flags = q->ipqe_tcp->ti_flags & TH_FIN; - nq = q->ipqe_q.le_next; - LIST_REMOVE(q, ipqe_q); + tp->rcv_nxt += q->tqe_len; + flags = q->tqe_th->th_flags & TH_FIN; + nq = LIST_NEXT(q, tqe_q); + LIST_REMOVE(q, tqe_q); if (so->so_state & SS_CANTRCVMORE) - m_freem(q->ipqe_m); + m_freem(q->tqe_m); else - sbappend(&so->so_rcv, q->ipqe_m); - FREE(q, M_SONAME); + sbappend(&so->so_rcv, q->tqe_m); + FREE(q, M_TSEGQ); q = nq; - } while (q && q->ipqe_tcp->ti_seq == tp->rcv_nxt); + } while (q && q->tqe_th->th_seq == tp->rcv_nxt); + ND6_HINT(tp); + #if INET6 - if (isipv6) - ND6_HINT(tp); + if ((tp->t_inpcb->inp_vflag & INP_IPV6) != 0) { + + KERNEL_DEBUG(DBG_LAYER_BEG, + ((tp->t_inpcb->inp_fport << 16) | tp->t_inpcb->inp_lport), + (((tp->t_inpcb->in6p_laddr.s6_addr16[0] & 0xffff) << 16) | + (tp->t_inpcb->in6p_faddr.s6_addr16[0] & 0xffff)), + 0,0,0); + } + else #endif - - KERNEL_DEBUG(DBG_LAYER_END, ((th->th_dport << 16) | th->th_sport), - (((thtoti(th)->ti_src.s_addr & 0xffff) << 16) | (thtoti(th)->ti_dst.s_addr & 0xffff)), - th->th_seq, th->th_ack, th->th_win); - + { + KERNEL_DEBUG(DBG_LAYER_BEG, + ((tp->t_inpcb->inp_fport << 16) | tp->t_inpcb->inp_lport), + (((tp->t_inpcb->inp_laddr.s_addr & 0xffff) << 16) | + (tp->t_inpcb->inp_faddr.s_addr & 0xffff)), + 0,0,0); + } sorwakeup(so); return (flags); + } + /* * TCP input routine, follows pages 65-76 of the * protocol specification dated September, 1981 very closely. @@ -384,15 +360,34 @@ tcp6_input(mp, offp, proto) struct mbuf **mp; int *offp, proto; { - tcp_input(*mp, *offp); + register struct mbuf *m = *mp; + struct in6_ifaddr *ia6; + + IP6_EXTHDR_CHECK(m, *offp, sizeof(struct tcphdr), IPPROTO_DONE); + + /* + * draft-itojun-ipv6-tcp-to-anycast + * better place to put this in? + */ + ia6 = ip6_getdstifaddr(m); + if (ia6 && (ia6->ia6_flags & IN6_IFF_ANYCAST)) { + struct ip6_hdr *ip6; + + ip6 = mtod(m, struct ip6_hdr *); + icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR, + (caddr_t)&ip6->ip6_dst - (caddr_t)ip6); + return IPPROTO_DONE; + } + + tcp_input(m, *offp); return IPPROTO_DONE; } #endif void -tcp_input(m, off) +tcp_input(m, off0) struct mbuf *m; - int off; + int off0; { register struct tcphdr *th; register struct ip *ip = NULL; @@ -400,15 +395,14 @@ tcp_input(m, off) register struct inpcb *inp; u_char *optp = NULL; int optlen = 0; - int len, toff; - int hdroptlen; - u_int16_t tilen; + int len, tlen, off; + int drop_hdrlen; register struct tcpcb *tp = 0; register int thflags; struct socket *so = 0; int todrop, acked, ourfinisacked, needoutput = 0; struct in_addr laddr; -#if 0 +#if INET6 struct in6_addr laddr6; #endif int dropsocket = 0; @@ -417,164 +411,149 @@ tcp_input(m, off) struct tcpopt to; /* options in this segment */ struct rmxp_tao *taop; /* pointer to our TAO cache entry */ struct rmxp_tao tao_noncached; /* in case there's no cached entry */ - int need_sowwakeup = 0; - int need_sorwakeup = 0; #if TCPDEBUG short ostate = 0; #endif #if INET6 struct ip6_hdr *ip6 = NULL; - int lgminh; -#else /* INET6 */ -#define lgminh (sizeof (struct tcpiphdr)) + int isipv6; #endif /* INET6 */ - int isipv6 = (mtod(m, struct ip *)->ip_v == 6) ? 1 : 0; - + int rstreason; /* For badport_bandlim accounting purposes */ struct proc *proc0=current_proc(); - + KERNEL_DEBUG(DBG_FNC_TCP_INPUT | DBG_FUNC_START,0,0,0,0,0); +#if INET6 + isipv6 = (mtod(m, struct ip *)->ip_v == 6) ? 1 : 0; +#endif bzero((char *)&to, sizeof(to)); tcpstat.tcps_rcvtotal++; - /* - * Get IP and TCP header together in first mbuf. - * Note: IP leaves IP header in first mbuf. - */ - th = mtod(m, struct tcpiphdr *); - KERNEL_DEBUG(DBG_LAYER_BEG, ((th->th_dport << 16) | th->th_sport), - (((thtoti(th)->ti_src.s_addr & 0xffff) << 16) | (thtoti(th)->ti_dst.s_addr & 0xffff)), - th->th_seq, th->th_ack, th->th_win); - -#if INET6 - if (isipv6) { - ip6 = mtod(m, struct ip6_hdr *); - lgminh = sizeof(struct tcpip6hdr); - } else { - lgminh = sizeof(struct tcpiphdr); -#endif /* INET6 */ - ip = mtod(m, struct ip *); - ipov = (struct ipovly *)ip; -#if INET6 - } -#endif /* INET6 */ -#if INET6 - /* XXX not a good place to put this into... */ - if (isipv6 && - m && (m->m_flags & M_ANYCAST6)) { - icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR, - (caddr_t)&ip6->ip6_dst - (caddr_t)ip6); - return; - } -#endif /* INET6 */ #if INET6 if (isipv6) { - IP6_EXTHDR_CHECK(m, off, sizeof(struct tcphdr), ); + /* IP6_EXTHDR_CHECK() is already done at tcp6_input() */ ip6 = mtod(m, struct ip6_hdr *); - tilen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6); - - if (in6_cksum(m, IPPROTO_TCP, off, tilen)) { + tlen = sizeof(*ip6) + ntohs(ip6->ip6_plen) - off0; + if (in6_cksum(m, IPPROTO_TCP, off0, tlen)) { tcpstat.tcps_rcvbadsum++; goto drop; } - th = (struct tcphdr *)((caddr_t)ip6 + off); - } else -#endif /* INET6 */ - { + th = (struct tcphdr *)((caddr_t)ip6 + off0); + + KERNEL_DEBUG(DBG_LAYER_BEG, ((th->th_dport << 16) | th->th_sport), + (((ip6->ip6_src.s6_addr16[0]) << 16) | (ip6->ip6_dst.s6_addr16[0])), + th->th_seq, th->th_ack, th->th_win); /* - * Get IP and TCP header together in first mbuf. - * Note: IP leaves IP header in first mbuf. + * Be proactive about unspecified IPv6 address in source. + * As we use all-zero to indicate unbounded/unconnected pcb, + * unspecified IPv6 address can be used to confuse us. + * + * Note that packets with unspecified IPv6 destination is + * already dropped in ip6_input. */ - /* XXX: should we still require this for IPv4? */ - if (off > sizeof (struct ip)) { - ip_stripoptions(m, (struct mbuf *)0); - off = sizeof(struct ip); - if (m->m_pkthdr.csum_flags & CSUM_TCP_SUM16) - m->m_pkthdr.csum_flags = 0; /* invalidate hwcksuming */ - } - if (m->m_len < lgminh) { - if ((m = m_pullup(m, lgminh)) == 0) { - tcpstat.tcps_rcvshort++; - return; - } + if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) { + /* XXX stat */ + goto drop; } - ip = mtod(m, struct ip *); - ipov = (struct ipovly *)ip; - th = (struct tcphdr *)((caddr_t)ip + off); - tilen = ip->ip_len; - len = sizeof (struct ip) + tilen; - - if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) { - - if (apple_hwcksum_rx && (m->m_pkthdr.csum_flags & CSUM_TCP_SUM16)) { - u_short pseudo; - bzero(ipov->ih_x1, sizeof(ipov->ih_x1)); - ipov->ih_len = (u_short)tilen; - HTONS(ipov->ih_len); - pseudo = in_cksum(m, sizeof (struct ip)); - th->th_sum = in_addword(pseudo, (m->m_pkthdr.csum_data & 0xFFFF)); - } - else { - if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) - th->th_sum = m->m_pkthdr.csum_data; - else goto dotcpcksum; - } - th->th_sum ^= 0xffff; - - } else { - /* - * Checksum extended TCP header and data. - */ -dotcpcksum: - if (th->th_sum) { - len = sizeof (struct ip) + tilen; - bzero(ipov->ih_x1, sizeof(ipov->ih_x1)); - ipov->ih_len = (u_short)tilen; - HTONS(ipov->ih_len); - th = (struct tcphdr *)((caddr_t)ip + off); - th->th_sum = in_cksum(m, len); - } + } else +#endif /* INET6 */ + { + /* + * Get IP and TCP header together in first mbuf. + * Note: IP leaves IP header in first mbuf. + */ + if (off0 > sizeof (struct ip)) { + ip_stripoptions(m, (struct mbuf *)0); + off0 = sizeof(struct ip); + if (m->m_pkthdr.csum_flags & CSUM_TCP_SUM16) + m->m_pkthdr.csum_flags = 0; /* invalidate hwcksuming */ + + } + if (m->m_len < sizeof (struct tcpiphdr)) { + if ((m = m_pullup(m, sizeof (struct tcpiphdr))) == 0) { + tcpstat.tcps_rcvshort++; + return; } + } + ip = mtod(m, struct ip *); + ipov = (struct ipovly *)ip; + th = (struct tcphdr *)((caddr_t)ip + off0); + tlen = ip->ip_len; - if (th->th_sum) { - tcpstat.tcps_rcvbadsum++; - goto drop; + KERNEL_DEBUG(DBG_LAYER_BEG, ((th->th_dport << 16) | th->th_sport), + (((ip->ip_src.s_addr & 0xffff) << 16) | (ip->ip_dst.s_addr & 0xffff)), + th->th_seq, th->th_ack, th->th_win); + + if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) { + if (apple_hwcksum_rx && (m->m_pkthdr.csum_flags & CSUM_TCP_SUM16)) { + u_short pseudo; + bzero(ipov->ih_x1, sizeof(ipov->ih_x1)); + ipov->ih_len = (u_short)tlen; + HTONS(ipov->ih_len); + pseudo = in_cksum(m, sizeof (struct ip)); + th->th_sum = in_addword(pseudo, (m->m_pkthdr.csum_data & 0xFFFF)); + } else { + if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) + th->th_sum = m->m_pkthdr.csum_data; + else + th->th_sum = in_pseudo(ip->ip_src.s_addr, + ip->ip_dst.s_addr, htonl(m->m_pkthdr.csum_data + + ip->ip_len + IPPROTO_TCP)); } + th->th_sum ^= 0xffff; + } else { + /* + * Checksum extended TCP header and data. + */ + len = sizeof (struct ip) + tlen; + bzero(ipov->ih_x1, sizeof(ipov->ih_x1)); + ipov->ih_len = (u_short)tlen; + HTONS(ipov->ih_len); + th->th_sum = in_cksum(m, len); + } + if (th->th_sum) { + tcpstat.tcps_rcvbadsum++; + goto drop; } +#if INET6 + /* Re-initialization for later version check */ + ip->ip_v = IPVERSION; +#endif + } /* * Check that TCP offset makes sense, * pull out TCP options and adjust length. XXX */ - toff = th->th_off << 2; - if (toff < sizeof (struct tcphdr) || toff > tilen) { + off = th->th_off << 2; + if (off < sizeof (struct tcphdr) || off > tlen) { tcpstat.tcps_rcvbadoff++; goto drop; } - tilen -= toff; - if (toff > sizeof (struct tcphdr)) { + tlen -= off; /* tlen is used instead of ti->ti_len */ + if (off > sizeof (struct tcphdr)) { #if INET6 if (isipv6) { - IP6_EXTHDR_CHECK(m, off, toff, ); + IP6_EXTHDR_CHECK(m, off0, off, ); ip6 = mtod(m, struct ip6_hdr *); - th = (struct tcphdr *)((caddr_t)ip6 + off); + th = (struct tcphdr *)((caddr_t)ip6 + off0); } else #endif /* INET6 */ - { - if (m->m_len < sizeof(struct ip) + toff) { - if ((m = m_pullup(m, sizeof (struct ip) + toff)) == 0) { - tcpstat.tcps_rcvshort++; - return; - } - ip = mtod(m, struct ip *); - ipov = (struct ipovly *)ip; - th = (struct tcphdr *)((caddr_t)ip + off); + { + if (m->m_len < sizeof(struct ip) + off) { + if ((m = m_pullup(m, sizeof (struct ip) + off)) == 0) { + tcpstat.tcps_rcvshort++; + return; } + ip = mtod(m, struct ip *); + ipov = (struct ipovly *)ip; + th = (struct tcphdr *)((caddr_t)ip + off0); } - optlen = toff - sizeof (struct tcphdr); + } + optlen = off - sizeof (struct tcphdr); optp = (u_char *)(th + 1); /* * Do quick retrieval of timestamp options ("options @@ -596,6 +575,18 @@ dotcpcksum: } thflags = th->th_flags; +#if TCP_DROP_SYNFIN + /* + * If the drop_synfin option is enabled, drop all packets with + * both the SYN and FIN bits set. This prevents e.g. nmap from + * identifying the TCP/IP stack. + * + * This is incompatible with RFC1644 extensions (T/TCP). + */ + if (drop_synfin && (thflags & (TH_SYN|TH_FIN)) == (TH_SYN|TH_FIN)) + goto drop; +#endif + /* * Convert TCP protocol specific fields to host format. */ @@ -605,11 +596,14 @@ dotcpcksum: NTOHS(th->th_urp); /* - * Drop TCP, IP headers and TCP options. + * Delay droping TCP, IP headers, IPv6 ext headers, and TCP options, + * until after ip6_savecontrol() is called and before other functions + * which don't want those proto headers. + * Because ip6_savecontrol() is going to parse the mbuf to + * search for data to be passed up to user-land, it wants mbuf + * parameters to be unchanged. */ - hdroptlen = off+toff; - m->m_data += hdroptlen; - m->m_len -= hdroptlen; + drop_hdrlen = off0 + off; /* * Locate pcb for segment. @@ -618,7 +612,7 @@ findpcb: #if IPFIREWALL_FORWARD if (ip_fw_fwd_addr != NULL #if INET6 - && isipv6 == NULL + && isipv6 == NULL /* IPv6 support is not yet */ #endif /* INET6 */ ) { /* @@ -646,7 +640,7 @@ findpcb: ip_fw_fwd_addr = NULL; } else #endif /* IPFIREWALL_FORWARD */ - + { #if INET6 if (isipv6) inp = in6_pcblookup_hash(&tcbinfo, &ip6->ip6_src, th->th_sport, @@ -656,25 +650,21 @@ findpcb: #endif /* INET6 */ inp = in_pcblookup_hash(&tcbinfo, ip->ip_src, th->th_sport, ip->ip_dst, th->th_dport, 1, m->m_pkthdr.rcvif); + } #if IPSEC - /* due to difference from other BSD stacks */ - m->m_data -= hdroptlen; - m->m_len += hdroptlen; #if INET6 if (isipv6) { - if (inp != NULL && ipsec6_in_reject_so(m, inp->inp_socket)) { + if (ipsec_bypass == 0 && inp != NULL && ipsec6_in_reject_so(m, inp->inp_socket)) { ipsec6stat.in_polvio++; goto drop; } } else #endif /* INET6 */ - if (inp != NULL && ipsec4_in_reject_so(m, inp->inp_socket)) { + if (ipsec_bypass == 0 && inp != NULL && ipsec4_in_reject_so(m, inp->inp_socket)) { ipsecstat.in_polvio++; goto drop; } - m->m_data += hdroptlen; - m->m_len -= hdroptlen; #endif /*IPSEC*/ /* @@ -684,49 +674,73 @@ findpcb: * but should either do a listen or a connect soon. */ if (inp == NULL) { - if (log_in_vain && thflags & TH_SYN) { + if (log_in_vain) { #if INET6 - char buf[INET6_ADDRSTRLEN]; + char dbuf[INET6_ADDRSTRLEN], sbuf[INET6_ADDRSTRLEN]; #else /* INET6 */ - char buf[4*sizeof "123"]; + char dbuf[4*sizeof "123"], sbuf[4*sizeof "123"]; #endif /* INET6 */ #if INET6 if (isipv6) { - strcpy(buf, ip6_sprintf(&ip6->ip6_dst)); - log(LOG_INFO, - "Connection attempt to TCP %s:%d from %s:%d\n", - buf, ntohs(th->th_dport), - ip6_sprintf(&ip6->ip6_src), - ntohs(th->th_sport)); - } else { + strcpy(dbuf, ip6_sprintf(&ip6->ip6_dst)); + strcpy(sbuf, ip6_sprintf(&ip6->ip6_src)); + } else #endif - strcpy(buf, inet_ntoa(ip->ip_dst)); - log(LOG_INFO, - "Connection attempt to TCP %s:%d from %s:%d\n", - buf, ntohs(th->th_dport), inet_ntoa(ip->ip_src), - ntohs(th->th_sport)); -#if INET6 + { + strcpy(dbuf, inet_ntoa(ip->ip_dst)); + strcpy(sbuf, inet_ntoa(ip->ip_src)); + } + switch (log_in_vain) { + case 1: + if(thflags & TH_SYN) + log(LOG_INFO, + "Connection attempt to TCP %s:%d from %s:%d\n", + dbuf, ntohs(th->th_dport), + sbuf, + ntohs(th->th_sport)); + break; + case 2: + log(LOG_INFO, + "Connection attempt to TCP %s:%d from %s:%d flags:0x%x\n", + dbuf, ntohs(th->th_dport), sbuf, + ntohs(th->th_sport), thflags); + break; + default: + break; } -#endif /* INET6 */ } -#if ICMP_BANDLIM - if (badport_bandlim(1) < 0) - goto drop; -#endif + if (blackhole) { + switch (blackhole) { + case 1: + if (thflags & TH_SYN) + goto drop; + break; + case 2: + goto drop; + default: + goto drop; + } + } + rstreason = BANDLIM_RST_CLOSEDPORT; goto dropwithreset; } tp = intotcpcb(inp); - if (tp == 0) + if (tp == 0) { + rstreason = BANDLIM_RST_CLOSEDPORT; goto dropwithreset; + } if (tp->t_state == TCPS_CLOSED) goto drop; + +#ifdef __APPLE__ /* * Bogus state when listening port owned by SharedIP with loopback as the * only configured interface: BlueBox does not filters loopback */ if (tp->t_state == TCP_NSTATES) goto drop; +#endif /* Unscale the window into a 32-bit value. */ if ((thflags & TH_SYN) == 0) @@ -741,13 +755,11 @@ findpcb: ostate = tp->t_state; #if INET6 if (isipv6) - tcp_saveip._tcp_si6 = *ip6; + bcopy((char *)ip6, (char *)tcp_saveipgen, + sizeof(*ip6)); else - tcp_saveip._tcp_si4 = *ip; -#else /* INET6 */ - tcp_saveip = *ip; #endif /* INET6 */ - + bcopy((char *)ip, (char *)tcp_saveipgen, sizeof(*ip)); tcp_savetcp = *th; } #endif @@ -762,6 +774,11 @@ findpcb: #endif /* INET6 */ #if !IPSEC + /* + * Current IPsec implementation makes incorrect IPsec + * cache if this check is done here. + * So delay this until duplicated socket is created. + */ if ((thflags & (TH_RST|TH_ACK|TH_SYN)) != TH_SYN) { /* * Note: dropwithreset makes sure we don't @@ -769,19 +786,65 @@ findpcb: */ if (thflags & TH_ACK) { tcpstat.tcps_badsyn++; + rstreason = BANDLIM_RST_OPENPORT; goto dropwithreset; } goto drop; } #endif KERNEL_DEBUG(DBG_FNC_TCP_NEWCONN | DBG_FUNC_START,0,0,0,0,0); - so2 = sonewconn(so, 0); +#if INET6 + /* + * If deprecated address is forbidden, + * we do not accept SYN to deprecated interface + * address to prevent any new inbound connection from + * getting established. + * When we do not accept SYN, we send a TCP RST, + * with deprecated source address (instead of dropping + * it). We compromise it as it is much better for peer + * to send a RST, and RST will be the final packet + * for the exchange. + * + * If we do not forbid deprecated addresses, we accept + * the SYN packet. RFC2462 does not suggest dropping + * SYN in this case. + * If we decipher RFC2462 5.5.4, it says like this: + * 1. use of deprecated addr with existing + * communication is okay - "SHOULD continue to be + * used" + * 2. use of it with new communication: + * (2a) "SHOULD NOT be used if alternate address + * with sufficient scope is available" + * (2b) nothing mentioned otherwise. + * Here we fall into (2b) case as we have no choice in + * our source address selection - we must obey the peer. + * + * The wording in RFC2462 is confusing, and there are + * multiple description text for deprecated address + * handling - worse, they are not exactly the same. + * I believe 5.5.4 is the best one, so we follow 5.5.4. + */ + if (isipv6 && !ip6_use_deprecated) { + struct in6_ifaddr *ia6; + + if ((ia6 = ip6_getdstifaddr(m)) && + (ia6->ia6_flags & IN6_IFF_DEPRECATED)) { + tp = NULL; + rstreason = BANDLIM_RST_OPENPORT; + goto dropwithreset; + } + } +#endif + so2 = sonewconn(so, 0); if (so2 == 0) { tcpstat.tcps_listendrop++; so2 = sodropablereq(so); if (so2) { + if (tcp_lq_overflow) + sototcpcb(so2)->t_flags |= + TF_LQ_OVERFLOW; tcp_drop(sototcpcb(so2), ETIMEDOUT); so2 = sonewconn(so, 0); } @@ -809,21 +872,18 @@ findpcb: if (isipv6) inp->in6p_laddr = ip6->ip6_dst; else { - if (ip6_mapped_addr_on) { - inp->inp_vflag &= ~INP_IPV6; - inp->inp_vflag |= INP_IPV4; - } + inp->inp_vflag &= ~INP_IPV6; + inp->inp_vflag |= INP_IPV4; #endif /* INET6 */ inp->inp_laddr = ip->ip_dst; #if INET6 } #endif /* INET6 */ - inp->inp_lport = th->th_dport; if (in_pcbinshash(inp) != 0) { /* - * Undo the assignments above if we failed to put - * the PCB on the hash lists. + * Undo the assignments above if we failed to + * put the PCB on the hash lists. */ #if INET6 if (isipv6) @@ -836,12 +896,12 @@ findpcb: } #if IPSEC /* - * from IPsec perspective, it is important to do it - * after making actual listening socket. - * otherwise, cached security association will bark. + * To avoid creating incorrectly cached IPsec + * association, this is need to be done here. * * Subject: (KAME-snap 748) * From: Wayne Knowles + * ftp://ftp.kame.net/pub/mail-list/snap-users/748 */ if ((thflags & (TH_RST|TH_ACK|TH_SYN)) != TH_SYN) { /* @@ -850,6 +910,7 @@ findpcb: */ if (thflags & TH_ACK) { tcpstat.tcps_badsyn++; + rstreason = BANDLIM_RST_OPENPORT; goto dropwithreset; } goto drop; @@ -857,87 +918,59 @@ findpcb: #endif #if INET6 if (isipv6) { - struct ip6_recvpktopts newopts; - - /* - * Inherit socket options from the listening - * socket. - * Note that in6p_inputopts are not (even - * should not be) copied, since it stores + /* + * Inherit socket options from the listening + * socket. + * Note that in6p_inputopts are not (even + * should not be) copied, since it stores * previously received options and is used to - * detect if each new option is different than - * the previous one and hence should be passed - * to a user. - * If we copied in6p_inputopts, a user would - * not be able to receive options just after - * calling the accept system call. - */ + * detect if each new option is different than + * the previous one and hence should be passed + * to a user. + * If we copied in6p_inputopts, a user would + * not be able to receive options just after + * calling the accept system call. + */ inp->inp_flags |= oinp->inp_flags & INP_CONTROLOPTS; - if (oinp->in6p_outputopts) - inp->in6p_outputopts = - ip6_copypktopts(oinp->in6p_outputopts, - M_NOWAIT); + if (oinp->in6p_outputopts) + inp->in6p_outputopts = + ip6_copypktopts(oinp->in6p_outputopts, + M_NOWAIT); } else #endif /* INET6 */ inp->inp_options = ip_srcroute(); #if IPSEC /* copy old policy into new socket's */ - if (ipsec_copy_policy(sotoinpcb(oso)->inp_sp, - inp->inp_sp)) - printf("tcp_input: could not copy policy\n"); + if (sotoinpcb(oso)->inp_sp) + { + int error = 0; + /* Is it a security hole here to silently fail to copy the policy? */ + if (inp->inp_sp != NULL) + error = ipsec_init_policy(so, &inp->inp_sp); + if (error != 0 || ipsec_copy_policy(sotoinpcb(oso)->inp_sp, inp->inp_sp)) + printf("tcp_input: could not copy policy\n"); + } #endif - tp = intotcpcb(inp); tp->t_state = TCPS_LISTEN; - tp->t_flags |= tp0->t_flags & (TF_NOPUSH|TF_NOOPT); + tp->t_flags |= tp0->t_flags & (TF_NOPUSH|TF_NOOPT|TF_NODELAY); /* Compute proper scaling value from buffer space */ while (tp->request_r_scale < TCP_MAX_WINSHIFT && - TCP_MAXWIN << tp->request_r_scale < so->so_rcv.sb_hiwat) + TCP_MAXWIN << tp->request_r_scale < + so->so_rcv.sb_hiwat) tp->request_r_scale++; KERNEL_DEBUG(DBG_FNC_TCP_NEWCONN | DBG_FUNC_END,0,0,0,0,0); } } -#if INET6 - /* save packet options if user wanted */ - if (isipv6 && (inp->in6p_flags & INP_CONTROLOPTS) != 0) { - struct ip6_recvpktopts opts6; - - /* - * Temporarily re-adjusting the mbuf before ip6_savecontrol(), - * which is necessary for FreeBSD only due to difference from - * other BSD stacks. - * XXX: we'll soon make a more natural fix after getting a - * consensus. - */ -#ifndef DEFER_MADJ - m->m_data -= hdroptlen; - m->m_len += hdroptlen; -#endif - ip6_savecontrol(inp, ip6, m, &opts6, &inp->in6p_inputopts); - if (inp->in6p_inputopts) - ip6_update_recvpcbopt(inp->in6p_inputopts, &opts6); - if (opts6.head) { - if (sbappendcontrol(&inp->in6p_socket->so_rcv, - NULL, opts6.head) - == 0) - m_freem(opts6.head); - } -#ifndef DEFER_MADJ - m->m_data += hdroptlen; /* XXX */ - m->m_len -= hdroptlen; /* XXX */ -#endif - } -#endif /* INET6 */ - /* * Segment received on connection. * Reset idle time and keep-alive timer. */ - tp->t_idle = 0; + tp->t_rcvtime = 0; if (TCPS_HAVEESTABLISHED(tp->t_state)) tp->t_timer[TCPT_KEEP] = tcp_keepidle; @@ -947,8 +980,6 @@ findpcb: */ if (tp->t_state != TCPS_LISTEN && optp) tcp_dooptions(tp, optp, optlen, th, &to); - if (th->th_flags & TH_SYN) - tcp_mss(tp, to.to_maxseg, isipv6); /* sets t_maxseg */ /* * Header prediction: check for the two common cases @@ -995,7 +1026,7 @@ findpcb: tp->ts_recent = to.to_tsval; } - if (tilen == 0) { + if (tlen == 0) { if (SEQ_GT(th->th_ack, tp->snd_una) && SEQ_LEQ(th->th_ack, tp->snd_max) && tp->snd_cwnd >= tp->snd_wnd && @@ -1004,23 +1035,30 @@ findpcb: * this is a pure ack for outstanding data. */ ++tcpstat.tcps_predack; + /* + * "bad retransmit" recovery + */ + if (tp->t_rxtshift == 1 && + tcp_now < tp->t_badrxtwin) { + tp->snd_cwnd = tp->snd_cwnd_prev; + tp->snd_ssthresh = + tp->snd_ssthresh_prev; + tp->snd_nxt = tp->snd_max; + tp->t_badrxtwin = 0; + } if ((to.to_flag & TOF_TS) != 0) tcp_xmit_timer(tp, tcp_now - to.to_tsecr + 1); - else if (tp->t_rtt && + else if (tp->t_rtttime && SEQ_GT(th->th_ack, tp->t_rtseq)) - tcp_xmit_timer(tp, tp->t_rtt); + tcp_xmit_timer(tp, tp->t_rtttime); acked = th->th_ack - tp->snd_una; tcpstat.tcps_rcvackpack++; tcpstat.tcps_rcvackbyte += acked; sbdrop(&so->so_snd, acked); tp->snd_una = th->th_ack; m_freem(m); -#if INET6 - /* some progress has been done */ - if (isipv6) - ND6_HINT(tp); -#endif + ND6_HINT(tp); /* some progress has been done */ /* * If all outstanding data are acked, stop @@ -1043,29 +1081,38 @@ findpcb: return; } } else if (th->th_ack == tp->snd_una && - tp->segq.lh_first == NULL && - tilen <= sbspace(&so->so_rcv)) { + LIST_EMPTY(&tp->t_segq) && + tlen <= 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. */ ++tcpstat.tcps_preddat; - tp->rcv_nxt += tilen; + tp->rcv_nxt += tlen; tcpstat.tcps_rcvpack++; - tcpstat.tcps_rcvbyte += tilen; -#if INET6 - /* some progress has been done */ - if (isipv6) - ND6_HINT(tp); -#endif + tcpstat.tcps_rcvbyte += tlen; + ND6_HINT(tp); /* some progress has been done */ + /* + * Add data to socket buffer. + */ + m_adj(m, drop_hdrlen); /* delayed header drop */ sbappend(&so->so_rcv, m); - KERNEL_DEBUG(DBG_LAYER_END, ((th->th_dport << 16) | th->th_sport), - (((thtoti(th)->ti_src.s_addr & 0xffff) << 16) | (thtoti(th)->ti_dst.s_addr & 0xffff)), - th->th_seq, th->th_ack, th->th_win); +#if INET6 + if (isipv6) { + KERNEL_DEBUG(DBG_LAYER_END, ((th->th_dport << 16) | th->th_sport), + (((ip6->ip6_src.s6_addr16[0]) << 16) | (ip6->ip6_dst.s6_addr16[0])), + th->th_seq, th->th_ack, th->th_win); + } + else +#endif + { + KERNEL_DEBUG(DBG_LAYER_END, ((th->th_dport << 16) | th->th_sport), + (((ip->ip_src.s_addr & 0xffff) << 16) | (ip->ip_dst.s_addr & 0xffff)), + th->th_seq, th->th_ack, th->th_win); + } if (tcp_delack_enabled) { - if (last_active_conn_count > DELACK_BITMASK_THRESH) - TCP_DELACK_BITSET(tp->t_inpcb->hash_element); + TCP_DELACK_BITSET(tp->t_inpcb->hash_element); tp->t_flags |= TF_DELACK; } else { tp->t_flags |= TF_ACKNOW; @@ -1109,14 +1156,16 @@ findpcb: */ case TCPS_LISTEN: { register struct sockaddr_in *sin; -#if 0 +#if INET6 register struct sockaddr_in6 *sin6; #endif if (thflags & TH_RST) goto drop; - if (thflags & TH_ACK) + if (thflags & TH_ACK) { + rstreason = BANDLIM_RST_OPENPORT; goto dropwithreset; + } if ((thflags & TH_SYN) == 0) goto drop; if (th->th_dport == th->th_sport) { @@ -1130,29 +1179,30 @@ findpcb: if (ip->ip_dst.s_addr == ip->ip_src.s_addr) goto drop; } - + /* + * RFC1122 4.2.3.10, p. 104: discard bcast/mcast SYN + * in_broadcast() should never return true on a received + * packet with M_BCAST not set. + * + * Packets with a multicast source address should also + * be discarded. + */ + if (m->m_flags & (M_BCAST|M_MCAST)) + goto drop; #if INET6 if (isipv6) { - if (m->m_flags & (M_BCAST|M_MCAST) || - IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) + if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || + IN6_IS_ADDR_MULTICAST(&ip6->ip6_src)) goto drop; -#if 1 - /* - * Perhaps this should be a call/macro - * to a function like in6_pcbconnect(), but almost - * all of the checks have been done: we know - * that the association is unique, and the - * local address is always set here. - */ - if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) - inp->in6p_laddr = ip6->ip6_dst; - inp->in6p_faddr = ip6->ip6_src; - inp->inp_fport = th->th_sport; - - /* TODO: flowinfo initialization */ - - in_pcbrehash(inp); -#else + } else +#endif + if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) || + IN_MULTICAST(ntohl(ip->ip_src.s_addr)) || + ip->ip_src.s_addr == htonl(INADDR_BROADCAST) || + in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) + goto drop; +#if INET6 + if (isipv6) { MALLOC(sin6, struct sockaddr_in6 *, sizeof *sin6, M_SONAME, M_NOWAIT); if (sin6 == NULL) @@ -1166,33 +1216,17 @@ findpcb: if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) inp->in6p_laddr = ip6->ip6_dst; if (in6_pcbconnect(inp, (struct sockaddr *)sin6, - &proc0)) { + proc0)) { inp->in6p_laddr = laddr6; FREE(sin6, M_SONAME); goto drop; } FREE(sin6, M_SONAME); + } else #endif - } - else { -#endif /* INET6 */ - /* - * RFC1122 4.2.3.10, p. 104: discard bcast/mcast SYN - * in_broadcast() should never return true on a received - * packet with M_BCAST not set. - * - * Packets with a multicast source address should also - * be discarded. - */ - if (m->m_flags & (M_BCAST|M_MCAST)) - goto drop; - if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) || - IN_MULTICAST(ntohl(ip->ip_src.s_addr)) || - ip->ip_src.s_addr == htonl(INADDR_BROADCAST) || - in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) - goto drop; + { MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME, - M_NOWAIT); + M_NOWAIT); if (sin == NULL) goto drop; sin->sin_family = AF_INET; @@ -1203,42 +1237,27 @@ findpcb: laddr = inp->inp_laddr; if (inp->inp_laddr.s_addr == INADDR_ANY) inp->inp_laddr = ip->ip_dst; - if (in_pcbconnect(inp, (struct sockaddr *)sin, &proc0)) { + if (in_pcbconnect(inp, (struct sockaddr *)sin, proc0)) { inp->inp_laddr = laddr; FREE(sin, M_SONAME); goto drop; } FREE(sin, M_SONAME); -#if INET6 - } -#endif /* INET6 */ - - 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 ((taop = tcp_gettaocache(inp)) == NULL) { taop = &tao_noncached; bzero(taop, sizeof(*taop)); } tcp_dooptions(tp, optp, optlen, th, &to); - if (th->th_flags & TH_SYN) - tcp_mss(tp, to.to_maxseg, isipv6); /* sets t_maxseg */ if (iss) tp->iss = iss; else { -#ifdef TCP_COMPAT_42 - tcp_iss += TCP_ISSINCR/2; - tp->iss = tcp_iss; -#else - tp->iss = tcp_rndiss_next(); -#endif /* TCP_COMPAT_42 */ - } + tp->iss = tcp_new_isn(tp); + } tp->irs = th->th_seq; tcp_sendseqinit(tp); tcp_rcvseqinit(tp); + tp->snd_recover = tp->snd_una; /* * Initialization of the tcpcb for transaction; * set SND.WND = SEG.WND, @@ -1265,8 +1284,6 @@ findpcb: taop->tao_cc != 0 && CC_GT(to.to_cc, taop->tao_cc)) { taop->tao_cc = to.to_cc; - if (tp->t_state != TCPS_ESTABLISHED) - current_active_connections++; tp->t_state = TCPS_ESTABLISHED; @@ -1277,9 +1294,8 @@ findpcb: * segment. Otherwise must send ACK now in case * the other side is slow starting. */ - if (tcp_delack_enabled && - ((thflags & TH_FIN) || - (tilen != 0 && + if (tcp_delack_enabled && ((thflags & TH_FIN) || + (tlen != 0 && #if INET6 (isipv6 && in6_localaddr(&inp->in6p_faddr)) || @@ -1290,9 +1306,7 @@ findpcb: ) #endif /* INET6 */ ))) { - if (last_active_conn_count > DELACK_BITMASK_THRESH) TCP_DELACK_BITSET(tp->t_inpcb->hash_element); - tp->t_flags |= (TF_DELACK | TF_NEEDSYN); } else @@ -1338,8 +1352,10 @@ findpcb: case TCPS_SYN_RECEIVED: if ((thflags & TH_ACK) && (SEQ_LEQ(th->th_ack, tp->snd_una) || - SEQ_GT(th->th_ack, tp->snd_max))) + SEQ_GT(th->th_ack, tp->snd_max))) { + rstreason = BANDLIM_RST_OPENPORT; goto dropwithreset; + } break; /* @@ -1373,8 +1389,10 @@ findpcb: */ if (taop->tao_ccsent != 0) goto drop; - else + else { + rstreason = BANDLIM_UNLIMITED; goto dropwithreset; + } } if (thflags & TH_RST) { if (thflags & TH_ACK) { @@ -1400,11 +1418,14 @@ findpcb: * we don't get fooled into using T/TCP. */ if (to.to_flag & TOF_CCECHO) { - if (tp->cc_send != to.to_ccecho) + if (tp->cc_send != to.to_ccecho) { if (taop->tao_ccsent != 0) goto drop; - else + else { + rstreason = BANDLIM_UNLIMITED; goto dropwithreset; + } + } } else tp->t_flags &= ~TF_RCVD_CC; tcpstat.tcps_connects++; @@ -1425,8 +1446,7 @@ findpcb: * If there's data, delay ACK; if there's also a FIN * ACKNOW will be turned on later. */ - if (tcp_delack_enabled && tilen != 0) { - if (last_active_conn_count > DELACK_BITMASK_THRESH) + if (tcp_delack_enabled && tlen != 0) { TCP_DELACK_BITSET(tp->t_inpcb->hash_element); tp->t_flags |= TF_DELACK; } @@ -1443,8 +1463,6 @@ findpcb: tp->t_flags &= ~TF_NEEDFIN; thflags &= ~TH_SYN; } else { - if (tp->t_state != TCPS_ESTABLISHED) - current_active_connections++; tp->t_state = TCPS_ESTABLISHED; tp->t_timer[TCPT_KEEP] = tcp_keepidle; } @@ -1473,8 +1491,6 @@ findpcb: tp->t_state = TCPS_FIN_WAIT_1; tp->t_flags &= ~TF_NEEDFIN; } else { - if (tp->t_state != TCPS_ESTABLISHED) - current_active_connections++; tp->t_state = TCPS_ESTABLISHED; tp->t_timer[TCPT_KEEP] = tcp_keepidle; } @@ -1495,10 +1511,10 @@ trimthenstep6: * dropping FIN if necessary. */ th->th_seq++; - if (tilen > tp->rcv_wnd) { - todrop = tilen - tp->rcv_wnd; + if (tlen > tp->rcv_wnd) { + todrop = tlen - tp->rcv_wnd; m_adj(m, -todrop); - tilen = tp->rcv_wnd; + tlen = tp->rcv_wnd; thflags &= ~TH_FIN; tcpstat.tcps_rcvpackafterwin++; tcpstat.tcps_rcvbyteafterwin += todrop; @@ -1535,8 +1551,10 @@ trimthenstep6: if ((thflags & TH_SYN) && (to.to_flag & TOF_CC) && tp->cc_recv != 0) { if (tp->t_state == TCPS_TIME_WAIT && - tp->t_duration > TCPTV_MSL) + tp->t_starttime > tcp_msl) { + rstreason = BANDLIM_UNLIMITED; goto dropwithreset; + } if (CC_GT(to.to_cc, tp->cc_recv)) { tp = tcp_close(tp); goto findpcb; @@ -1571,12 +1589,10 @@ trimthenstep6: * valid if its sequence number is in the window. * Note: this does not take into account delayed ACKs, so * we should test against last_ack_sent instead of rcv_nxt. - * Also, it does not make sense to allow reset segments with - * sequence numbers greater than last_ack_sent to be processed - * since these sequence numbers are just the acknowledgement - * numbers in our outgoing packets being echoed back at us, - * and these acknowledgement numbers are monotonically - * increasing. + * The sequence number in the reset segment is normally an + * echo of our outgoing acknowlegement numbers, but some hosts + * send a reset with the sequence number at the rightmost edge + * of our receive window, and we have to handle this case. * If we have multiple segments in flight, the intial reset * segment sequence numbers will be to the left of last_ack_sent, * but they will eventually catch up. @@ -1599,14 +1615,15 @@ trimthenstep6: * 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 + * CLOSING, LAST_ACK STATES: * Close the tcb. - * TIME_WAIT state: + * TIME_WAIT STATE: * Drop the segment - see Stevens, vol. 2, p. 964 and * RFC 1337. */ if (thflags & TH_RST) { - if (tp->last_ack_sent == th->th_seq) { + if (SEQ_GEQ(th->th_seq, tp->last_ack_sent) && + SEQ_LT(th->th_seq, tp->last_ack_sent + tp->rcv_wnd)) { switch (tp->t_state) { case TCPS_SYN_RECEIVED: @@ -1616,7 +1633,6 @@ trimthenstep6: case TCPS_ESTABLISHED: case TCPS_FIN_WAIT_1: case TCPS_CLOSE_WAIT: - current_active_connections--; /* Drop through ... */ @@ -1631,7 +1647,6 @@ trimthenstep6: case TCPS_CLOSING: case TCPS_LAST_ACK: - current_active_connections--; tp = tcp_close(tp); break; @@ -1665,7 +1680,7 @@ trimthenstep6: tp->ts_recent = 0; } else { tcpstat.tcps_rcvduppack++; - tcpstat.tcps_rcvdupbyte += tilen; + tcpstat.tcps_rcvdupbyte += tlen; tcpstat.tcps_pawsdrop++; goto dropafterack; } @@ -1688,8 +1703,10 @@ trimthenstep6: * the sequence numbers haven't wrapped. This is a partial fix * for the "LAND" DoS attack. */ - if (tp->t_state == TCPS_SYN_RECEIVED && SEQ_LT(th->th_seq, tp->irs)) + if (tp->t_state == TCPS_SYN_RECEIVED && SEQ_LT(th->th_seq, tp->irs)) { + rstreason = BANDLIM_RST_OPENPORT; goto dropwithreset; + } todrop = tp->rcv_nxt - th->th_seq; if (todrop > 0) { @@ -1705,8 +1722,8 @@ trimthenstep6: /* * Following if statement from Stevens, vol. 2, p. 960. */ - if (todrop > tilen - || (todrop == tilen && (thflags & TH_FIN) == 0)) { + if (todrop > tlen + || (todrop == tlen && (thflags & TH_FIN) == 0)) { /* * Any valid FIN must be to the left of the window. * At this point the FIN must be a duplicate or out @@ -1719,16 +1736,16 @@ trimthenstep6: * But keep on processing for RST or ACK. */ tp->t_flags |= TF_ACKNOW; - todrop = tilen; + todrop = tlen; tcpstat.tcps_rcvduppack++; tcpstat.tcps_rcvdupbyte += todrop; } else { tcpstat.tcps_rcvpartduppack++; tcpstat.tcps_rcvpartdupbyte += todrop; } - m_adj(m, todrop); + drop_hdrlen += todrop; /* drop from the top afterwards */ th->th_seq += todrop; - tilen -= todrop; + tlen -= todrop; if (th->th_urp > todrop) th->th_urp -= todrop; else { @@ -1742,9 +1759,10 @@ trimthenstep6: * user processes are gone, then RST the other end. */ if ((so->so_state & SS_NOFDREF) && - tp->t_state > TCPS_CLOSE_WAIT && tilen) { + tp->t_state > TCPS_CLOSE_WAIT && tlen) { tp = tcp_close(tp); tcpstat.tcps_rcvafterclose++; + rstreason = BANDLIM_UNLIMITED; goto dropwithreset; } @@ -1752,11 +1770,11 @@ trimthenstep6: * If segment ends after window, drop trailing data * (and PUSH and FIN); if nothing left, just ACK. */ - todrop = (th->th_seq+tilen) - (tp->rcv_nxt+tp->rcv_wnd); + todrop = (th->th_seq+tlen) - (tp->rcv_nxt+tp->rcv_wnd); if (todrop > 0) { tcpstat.tcps_rcvpackafterwin++; - if (todrop >= tilen) { - tcpstat.tcps_rcvbyteafterwin += tilen; + if (todrop >= tlen) { + tcpstat.tcps_rcvbyteafterwin += tlen; /* * If a new connection request is received * while in TIME_WAIT, drop the old connection @@ -1766,11 +1784,7 @@ trimthenstep6: if (thflags & TH_SYN && tp->t_state == TCPS_TIME_WAIT && SEQ_GT(th->th_seq, tp->rcv_nxt)) { -#ifdef TCP_COMPAT_42 - iss = tp->rcv_nxt + TCP_ISSINCR; -#else - iss = tcp_rndiss_next(); -#endif /* TCP_COMPAT_42 */ + iss = tcp_new_isn(tp); tp = tcp_close(tp); goto findpcb; } @@ -1789,7 +1803,7 @@ trimthenstep6: } else tcpstat.tcps_rcvbyteafterwin += todrop; m_adj(m, -todrop); - tilen -= todrop; + tlen -= todrop; thflags &= ~(TH_PUSH|TH_FIN); } @@ -1811,6 +1825,7 @@ trimthenstep6: */ if (thflags & TH_SYN) { tp = tcp_drop(tp, ECONNRESET); + rstreason = BANDLIM_UNLIMITED; postevent(so, 0, EV_RESET); goto dropwithreset; } @@ -1842,7 +1857,6 @@ trimthenstep6: tcpstat.tcps_connects++; soisconnected(so); - current_active_connections++; /* Do window scaling? */ if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == @@ -1875,9 +1889,9 @@ trimthenstep6: * If segment contains data or ACK, will call tcp_reass() * later; if not, do so now to pass queued data to user. */ - if (tilen == 0 && (thflags & TH_FIN) == 0) + if (tlen == 0 && (thflags & TH_FIN) == 0) (void) tcp_reass(tp, (struct tcphdr *)0, 0, - (struct mbuf *)0, isipv6); + (struct mbuf *)0); tp->snd_wl1 = th->th_seq - 1; /* fall into ... */ @@ -1898,7 +1912,7 @@ trimthenstep6: case TCPS_TIME_WAIT: if (SEQ_LEQ(th->th_ack, tp->snd_una)) { - if (tilen == 0 && tiwin == tp->snd_wnd) { + if (tlen == 0 && tiwin == tp->snd_wnd) { tcpstat.tcps_rcvdupack++; /* * If we have outstanding data (other than @@ -1932,12 +1946,22 @@ trimthenstep6: u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg; - + if (tcp_do_newreno && SEQ_LT(th->th_ack, + tp->snd_recover)) { + /* False retransmit, should not + * cut window + */ + tp->snd_cwnd += tp->t_maxseg; + tp->t_dupacks = 0; + (void) tcp_output(tp); + goto drop; + } if (win < 2) win = 2; tp->snd_ssthresh = win * tp->t_maxseg; + tp->snd_recover = tp->snd_max; tp->t_timer[TCPT_REXMT] = 0; - tp->t_rtt = 0; + tp->t_rtttime = 0; tp->snd_nxt = th->th_ack; tp->snd_cwnd = tp->t_maxseg; (void) tcp_output(tp); @@ -1959,10 +1983,30 @@ trimthenstep6: * 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 (tcp_do_newreno == 0) { + if (tp->t_dupacks >= tcprexmtthresh && + tp->snd_cwnd > tp->snd_ssthresh) + tp->snd_cwnd = tp->snd_ssthresh; + tp->t_dupacks = 0; + } else if (tp->t_dupacks >= tcprexmtthresh && + !tcp_newreno(tp, th)) { + /* + * Window inflation should have left us with approx. + * snd_ssthresh outstanding data. But in case we + * would be inclined to send a burst, better to do + * it via the slow start mechanism. + */ + if (SEQ_GT(th->th_ack + tp->snd_ssthresh, tp->snd_max)) + tp->snd_cwnd = + tp->snd_max - th->th_ack + tp->t_maxseg; + else + tp->snd_cwnd = tp->snd_ssthresh; + tp->t_dupacks = 0; + } + + if (tp->t_dupacks < tcprexmtthresh) + tp->t_dupacks = 0; + if (SEQ_GT(th->th_ack, tp->snd_max)) { tcpstat.tcps_rcvacktoomuch++; goto dropafterack; @@ -1994,6 +2038,20 @@ process_ACK: tcpstat.tcps_rcvackpack++; tcpstat.tcps_rcvackbyte += acked; + /* + * If we just performed our first retransmit, and the ACK + * arrives within our recovery window, then it was a mistake + * to do the retransmit in the first place. Recover our + * original cwnd and ssthresh, and proceed to transmit where + * we left off. + */ + if (tp->t_rxtshift == 1 && tcp_now < tp->t_badrxtwin) { + tp->snd_cwnd = tp->snd_cwnd_prev; + tp->snd_ssthresh = tp->snd_ssthresh_prev; + tp->snd_nxt = tp->snd_max; + tp->t_badrxtwin = 0; /* XXX probably not required */ + } + /* * If we have a timestamp reply, update smoothed * round trip time. If no timestamp is present but @@ -2005,8 +2063,8 @@ process_ACK: */ if (to.to_flag & TOF_TS) tcp_xmit_timer(tp, tcp_now - to.to_tsecr + 1); - else if (tp->t_rtt && SEQ_GT(th->th_ack, tp->t_rtseq)) - tcp_xmit_timer(tp,tp->t_rtt); + else if (tp->t_rtttime && SEQ_GT(th->th_ack, tp->t_rtseq)) + tcp_xmit_timer(tp, tp->t_rtttime); /* * If all outstanding data is acked, stop retransmit @@ -2040,7 +2098,13 @@ process_ACK: if (cw > tp->snd_ssthresh) incr = incr * incr / cw; - tp->snd_cwnd = min(cw + incr, TCP_MAXWIN<snd_scale); + /* + * If t_dupacks != 0 here, it indicates that we are still + * in NewReno fast recovery mode, so we leave the congestion + * window alone. + */ + if (tcp_do_newreno == 0 || tp->t_dupacks == 0) + tp->snd_cwnd = min(cw + incr,TCP_MAXWIN<snd_scale); } if (acked > so->so_snd.sb_cc) { tp->snd_wnd -= so->so_snd.sb_cc; @@ -2051,7 +2115,7 @@ process_ACK: tp->snd_wnd -= acked; ourfinisacked = 0; } - need_sowwakeup++; + sowwakeup(so); tp->snd_una = th->th_ack; if (SEQ_LT(tp->snd_nxt, tp->snd_una)) tp->snd_nxt = tp->snd_una; @@ -2077,7 +2141,6 @@ process_ACK: tp->t_timer[TCPT_2MSL] = tcp_maxidle; } add_to_time_wait(tp); - current_active_connections--; tp->t_state = TCPS_FIN_WAIT_2; } break; @@ -2094,13 +2157,12 @@ process_ACK: tcp_canceltimers(tp); /* Shorten TIME_WAIT [RFC-1644, p.28] */ if (tp->cc_recv != 0 && - tp->t_duration < TCPTV_MSL) + tp->t_starttime < tcp_msl) tp->t_timer[TCPT_2MSL] = tp->t_rxtcur * TCPTV_TWTRUNC; else - tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; + tp->t_timer[TCPT_2MSL] = 2 * tcp_msl; add_to_time_wait(tp); - current_active_connections--; soisdisconnected(so); } break; @@ -2124,7 +2186,7 @@ process_ACK: * it and restart the finack timer. */ case TCPS_TIME_WAIT: - tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; + tp->t_timer[TCPT_2MSL] = 2 * tcp_msl; add_to_time_wait(tp); goto dropafterack; } @@ -2140,7 +2202,7 @@ step6: (tp->snd_wl1 == th->th_seq && (SEQ_LT(tp->snd_wl2, th->th_ack) || (tp->snd_wl2 == th->th_ack && tiwin > tp->snd_wnd))))) { /* keep track of pure window updates */ - if (tilen == 0 && + if (tlen == 0 && tp->snd_wl2 == th->th_ack && tiwin > tp->snd_wnd) tcpstat.tcps_rcvwinupd++; tp->snd_wnd = tiwin; @@ -2198,12 +2260,13 @@ step6: * but if two URG's are pending at once, some out-of-band * data may creep in... ick. */ - if (th->th_urp <= (u_long)tilen + if (th->th_urp <= (u_long)tlen #if SO_OOBINLINE && (so->so_options & SO_OOBINLINE) == 0 #endif ) - tcp_pulloutofband(so, th, m); + tcp_pulloutofband(so, th, m, + drop_hdrlen); /* hdr drop is delayed */ } else /* * If no out of band data is expected, @@ -2222,15 +2285,62 @@ dodata: /* XXX */ * case PRU_RCVD). If a FIN has already been received on this * connection then we just ignore the text. */ - if ((tilen || (thflags&TH_FIN)) && + if ((tlen || (thflags&TH_FIN)) && TCPS_HAVERCVDFIN(tp->t_state) == 0) { - TCP_REASS(tp, th, tilen, m, so, thflags, isipv6, need_sorwakeup); + m_adj(m, drop_hdrlen); /* delayed header drop */ + /* + * Insert segment which inludes th into reassembly queue of tcp with + * control block tp. Return TH_FIN if reassembly now includes + * a segment with FIN. This handle 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). + */ + if (th->th_seq == tp->rcv_nxt && + LIST_EMPTY(&tp->t_segq) && + TCPS_HAVEESTABLISHED(tp->t_state)) { +#ifdef __APPLE__ + if (tcp_delack_enabled) { + TCP_DELACK_BITSET(tp->t_inpcb->hash_element); + tp->t_flags |= TF_DELACK; + } +#else + if (DELAY_ACK(tp)) + callout_reset(tp->tt_delack, tcp_delacktime, + tcp_timer_delack, tp); +#endif + else + tp->t_flags |= TF_ACKNOW; + tp->rcv_nxt += tlen; + thflags = th->th_flags & TH_FIN; + tcpstat.tcps_rcvpack++; + tcpstat.tcps_rcvbyte += tlen; + ND6_HINT(tp); + sbappend(&so->so_rcv, m); + sorwakeup(so); + } else { + thflags = tcp_reass(tp, th, &tlen, m); + tp->t_flags |= TF_ACKNOW; + } if (tp->t_flags & TF_DELACK) { - KERNEL_DEBUG(DBG_LAYER_END, ((th->th_dport << 16) | th->th_sport), - (((thtoti(th)->ti_src.s_addr & 0xffff) << 16) | (thtoti(th)->ti_dst.s_addr & 0xffff)), - th->th_seq, th->th_ack, th->th_win); +#if INET6 + if (isipv6) { + KERNEL_DEBUG(DBG_LAYER_END, ((th->th_dport << 16) | th->th_sport), + (((ip6->ip6_src.s6_addr16[0]) << 16) | (ip6->ip6_dst.s6_addr16[0])), + th->th_seq, th->th_ack, th->th_win); + } + else +#endif + { + KERNEL_DEBUG(DBG_LAYER_END, ((th->th_dport << 16) | th->th_sport), + (((ip->ip_src.s_addr & 0xffff) << 16) | (ip->ip_dst.s_addr & 0xffff)), + th->th_seq, th->th_ack, th->th_win); + } + } /* * Note the amount of data that peer has sent into @@ -2259,9 +2369,7 @@ dodata: /* XXX */ * more input can be expected, send ACK now. */ if (tcp_delack_enabled && (tp->t_flags & TF_NEEDSYN)) { - if (last_active_conn_count > DELACK_BITMASK_THRESH) TCP_DELACK_BITSET(tp->t_inpcb->hash_element); - tp->t_flags |= TF_DELACK; } else @@ -2275,6 +2383,7 @@ dodata: /* XXX */ * enter the CLOSE_WAIT state. */ case TCPS_SYN_RECEIVED: + /*FALLTHROUGH*/ case TCPS_ESTABLISHED: tp->t_state = TCPS_CLOSE_WAIT; break; @@ -2297,14 +2406,14 @@ dodata: /* XXX */ tcp_canceltimers(tp); /* Shorten TIME_WAIT [RFC-1644, p.28] */ if (tp->cc_recv != 0 && - tp->t_duration < TCPTV_MSL) { + tp->t_starttime < tcp_msl) { tp->t_timer[TCPT_2MSL] = tp->t_rxtcur * TCPTV_TWTRUNC; /* For transaction client, force ACK now. */ tp->t_flags |= TF_ACKNOW; } else - tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; + tp->t_timer[TCPT_2MSL] = 2 * tcp_msl; add_to_time_wait(tp); soisdisconnected(so); @@ -2314,25 +2423,15 @@ dodata: /* XXX */ * In TIME_WAIT state restart the 2 MSL time_wait timer. */ case TCPS_TIME_WAIT: - tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; + tp->t_timer[TCPT_2MSL] = 2 * tcp_msl; add_to_time_wait(tp); break; } } #if TCPDEBUG - if (so->so_options & SO_DEBUG) { -#if INET6 - if (isipv6) - tcp_saveip._tcp_si6.ip6_plen = tilen; - else - tcp_saveip._tcp_si4.ip_len = tilen; -#else /* INET6 */ - tcp_saveip.ip_len = tilen; -#endif /* INET6 */ - - tcp_trace(TA_INPUT, ostate, tp, (void *)&tcp_saveip, + if (so->so_options & SO_DEBUG) + tcp_trace(TA_INPUT, ostate, tp, (void *)tcp_saveipgen, &tcp_savetcp, 0); - } #endif /* @@ -2340,10 +2439,6 @@ dodata: /* XXX */ */ if (needoutput || (tp->t_flags & TF_ACKNOW)) (void) tcp_output(tp); - if (need_sorwakeup) - sorwakeup(so); - if (need_sowwakeup) - sowwakeup(so); KERNEL_DEBUG(DBG_FNC_TCP_INPUT | DBG_FUNC_END,0,0,0,0,0); return; @@ -2365,29 +2460,18 @@ dropafterack: */ if (tp->t_state == TCPS_SYN_RECEIVED && (thflags & TH_ACK) && (SEQ_GT(tp->snd_una, th->th_ack) || - SEQ_GT(th->th_ack, tp->snd_max)) ) + SEQ_GT(th->th_ack, tp->snd_max)) ) { + rstreason = BANDLIM_RST_OPENPORT; goto dropwithreset; + } #if TCPDEBUG - if (so->so_options & SO_DEBUG) { -#if INET6 - if (isipv6) - tcp_saveip._tcp_si6.ip6_plen = tilen; - else - tcp_saveip._tcp_si4.ip_len = tilen; -#else /* INET6 */ - tcp_saveip.ip_len = tilen; -#endif /* INET6 */ - tcp_trace(TA_DROP, ostate, tp, (void *)&tcp_saveip, + if (so->so_options & SO_DEBUG) + tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, &tcp_savetcp, 0); - } #endif m_freem(m); tp->t_flags |= TF_ACKNOW; (void) tcp_output(tp); - if (need_sorwakeup) - sorwakeup(so); - if (need_sowwakeup) - sowwakeup(so); KERNEL_DEBUG(DBG_FNC_TCP_INPUT | DBG_FUNC_END,0,0,0,0,0); return; @@ -2401,8 +2485,9 @@ dropwithreset: goto drop; #if INET6 if (isipv6) { - if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) - goto drop; /* anycast check is done at the top */ + if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || + IN6_IS_ADDR_MULTICAST(&ip6->ip6_src)) + goto drop; } else #endif /* INET6 */ if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) || @@ -2410,56 +2495,33 @@ dropwithreset: ip->ip_src.s_addr == htonl(INADDR_BROADCAST) || in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) goto drop; + /* IPv6 anycast check is done at tcp6_input() */ + + /* + * Perform bandwidth limiting. + */ +#if ICMP_BANDLIM + if (badport_bandlim(rstreason) < 0) + goto drop; +#endif + #if TCPDEBUG - if (tp == 0 || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) { - if (tp == 0) { -#if INET6 - if (isipv6) - tcp_saveip._tcp_si6 = *ip6; - else - tcp_saveip._tcp_si4 = *ip; -#else /* INET6 */ - tcp_saveip = *ip; -#endif /* INET6 */ - } -#if INET6 - if (isipv6) - tcp_saveip._tcp_si6.ip6_plen = tilen; - else - tcp_saveip._tcp_si4.ip_len = tilen; -#else /* INET6 */ - tcp_saveip.ip_len = tilen; -#endif /* INET6 */ - tcp_trace(TA_DROP, ostate, tp, (void *)&tcp_saveip, + if (tp == 0 || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) + tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, &tcp_savetcp, 0); - } #endif if (thflags & TH_ACK) -#if INET6 - tcp_respond(tp, isipv6 ? (void *)ip6 : (void *)ip, th, m, - (tcp_seq)0, th->th_ack, TH_RST, isipv6); -#else /* INET6 */ - tcp_respond(tp, (void *)ip, th, m, - (tcp_seq)0, th->th_ack, TH_RST, isipv6); -#endif /* INET6 */ + /* mtod() below is safe as long as hdr dropping is delayed */ + tcp_respond(tp, mtod(m, void *), th, m, (tcp_seq)0, th->th_ack, + TH_RST); else { if (thflags & TH_SYN) - tilen++; -#if INET6 - tcp_respond(tp, isipv6 ? (void *)ip6 : (void *)ip, th, m, - th->th_seq+tilen, (tcp_seq)0, TH_RST|TH_ACK, - isipv6); -#else /* INET6 */ - tcp_respond(tp, (void *)ip, th, m, - th->th_seq+tilen, (tcp_seq)0, TH_RST|TH_ACK, - isipv6); -#endif /* INET6 */ + tlen++; + /* mtod() below is safe as long as hdr dropping is delayed */ + tcp_respond(tp, mtod(m, void *), th, m, th->th_seq+tlen, + (tcp_seq)0, TH_RST|TH_ACK); } /* destroy temporarily created socket */ - if (need_sorwakeup) - sorwakeup(so); - if (need_sowwakeup) - sowwakeup(so); if (dropsocket) (void) soabort(so); KERNEL_DEBUG(DBG_FNC_TCP_INPUT | DBG_FUNC_END,0,0,0,0,0); @@ -2470,34 +2532,11 @@ drop: * Drop space held by incoming segment and return. */ #if TCPDEBUG - if (tp == 0 || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) { - if (tp == 0) { -#if INET6 - if (isipv6) - tcp_saveip._tcp_si6 = *ip6; - else - tcp_saveip._tcp_si4 = *ip; -#else /* INET6 */ - tcp_saveip = *ip; -#endif /* INET6 */ - } -#if INET6 - if (isipv6) - tcp_saveip._tcp_si6.ip6_plen = tilen; - else - tcp_saveip._tcp_si4.ip_len = tilen; -#else /* INET6 */ - tcp_saveip.ip_len = tilen; -#endif /* INET6 */ - tcp_trace(TA_DROP, ostate, tp, (void *)&tcp_saveip, + if (tp == 0 || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) + tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, &tcp_savetcp, 0); - } #endif m_freem(m); - if (need_sorwakeup) - sorwakeup(so); - if (need_sowwakeup) - sowwakeup(so); /* destroy temporarily created socket */ if (dropsocket) (void) soabort(so); @@ -2523,8 +2562,10 @@ tcp_dooptions(tp, cp, cnt, th, to) if (opt == TCPOPT_NOP) optlen = 1; else { + if (cnt < 2) + break; optlen = cp[1]; - if (optlen <= 0) + if (optlen < 2 || optlen > cnt) break; } switch (opt) { @@ -2538,7 +2579,7 @@ tcp_dooptions(tp, cp, cnt, th, to) if (!(th->th_flags & TH_SYN)) continue; bcopy((char *) cp + 2, (char *) &mss, sizeof(mss)); - to->to_maxseg = ntohs(mss); + NTOHS(mss); break; case TCPOPT_WINDOW: @@ -2612,6 +2653,8 @@ tcp_dooptions(tp, cp, cnt, th, to) break; } } + if (th->th_flags & TH_SYN) + tcp_mss(tp, mss); /* sets t_maxseg */ } /* @@ -2621,12 +2664,13 @@ tcp_dooptions(tp, cp, cnt, th, to) * sequencing purposes. */ static void -tcp_pulloutofband(so, th, m) +tcp_pulloutofband(so, th, m, off) struct socket *so; struct tcphdr *th; register struct mbuf *m; + int off; /* delayed to be droped hdrlen */ { - int cnt = th->th_urp - 1; + int cnt = off + th->th_urp - 1; while (cnt >= 0) { if (m->m_len > cnt) { @@ -2637,6 +2681,8 @@ tcp_pulloutofband(so, th, m) tp->t_oobflags |= TCPOOB_HAVEDATA; bcopy(cp+1, cp, (unsigned)(m->m_len - cnt - 1)); m->m_len--; + if (m->m_flags & M_PKTHDR) + m->m_pkthdr.len--; return; } cnt -= m->m_len; @@ -2654,7 +2700,7 @@ tcp_pulloutofband(so, th, m) static void tcp_xmit_timer(tp, rtt) register struct tcpcb *tp; - short rtt; + int rtt; { register int delta; @@ -2698,7 +2744,7 @@ tcp_xmit_timer(tp, rtt) tp->t_srtt = rtt << TCP_RTT_SHIFT; tp->t_rttvar = rtt << (TCP_RTTVAR_SHIFT - 1); } - tp->t_rtt = 0; + tp->t_rtttime = 0; tp->t_rxtshift = 0; /* @@ -2754,12 +2800,9 @@ tcp_xmit_timer(tp, rtt) * MSS of our peer. */ void -tcp_mss(tp, offer, isipv6) +tcp_mss(tp, offer) struct tcpcb *tp; int offer; -#if INET6 - int isipv6; -#endif { register struct rtentry *rt; struct ifnet *ifp; @@ -2770,13 +2813,18 @@ tcp_mss(tp, offer, isipv6) struct rmxp_tao *taop; int origoffer = offer; #if INET6 - int lgminh = isipv6 ? sizeof (struct tcpip6hdr) : - sizeof (struct tcpiphdr); -#else /* INET6 */ -#define lgminh (sizeof (struct tcpiphdr)) -#endif /* INET6 */ + int isipv6; + int min_protoh; +#endif inp = tp->t_inpcb; +#if INET6 + isipv6 = ((inp->inp_vflag & INP_IPV6) != 0) ? 1 : 0; + min_protoh = isipv6 ? sizeof (struct ip6_hdr) + sizeof (struct tcphdr) + : sizeof (struct tcpiphdr); +#else +#define min_protoh (sizeof (struct tcpiphdr)) +#endif #if INET6 if (isipv6) rt = tcp_rtlookup6(inp); @@ -2845,23 +2893,26 @@ tcp_mss(tp, offer, isipv6) 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); + ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1, + tp->t_rttmin, TCPTV_REXMTMAX); } /* * if there's an mtu associated with the route, use it * else, use the link mtu. */ if (rt->rt_rmx.rmx_mtu) - mss = rt->rt_rmx.rmx_mtu - lgminh; + mss = rt->rt_rmx.rmx_mtu - min_protoh; else + { mss = #if INET6 - isipv6 ? nd_ifinfo[rt->rt_ifp->if_index].linkmtu : + (isipv6 ? nd_ifinfo[rt->rt_ifp->if_index].linkmtu : #endif - ifp->if_mtu - lgminh; - - if (rt->rt_rmx.rmx_mtu == 0) { + ifp->if_mtu +#if INET6 + ) +#endif + - min_protoh; #if INET6 if (isipv6) { if (!in6_localaddr(&inp->in6p_faddr)) @@ -2932,17 +2983,24 @@ tcp_mss(tp, offer, isipv6) bufsize = sb_max; (void)sbreserve(&so->so_rcv, bufsize); } + /* - * Don't force slow-start on local network. + * Set the slow-start flight size depending on whether this + * is a local network or not. */ + if ( #if INET6 - if (isipv6) { - if (!in6_localaddr(&inp->in6p_faddr)) - tp->snd_cwnd = mss; - } else -#endif /* INET6 */ - if (!in_localaddr(inp->inp_faddr)) - tp->snd_cwnd = mss; + (isipv6 && in6_localaddr(&inp->in6p_faddr)) || + (!isipv6 && +#endif + in_localaddr(inp->inp_faddr) +#if INET6 + ) +#endif + ) + tp->snd_cwnd = mss * ss_fltsz_local; + else + tp->snd_cwnd = mss * ss_fltsz; if (rt->rt_rmx.rmx_ssthresh) { /* @@ -2960,21 +3018,22 @@ tcp_mss(tp, offer, isipv6) * Determine the MSS option to send on an outgoing SYN. */ int -tcp_mssopt(tp, isipv6) +tcp_mssopt(tp) struct tcpcb *tp; -#if INET6 - int isipv6; -#endif { struct rtentry *rt; - int mss; #if INET6 - int lgminh = isipv6 ? sizeof (struct tcpip6hdr) : - sizeof (struct tcpiphdr); -#else /* INET6 */ -#define lgminh (sizeof (struct tcpiphdr)) -#endif /* INET6 */ + int isipv6; + int min_protoh; +#endif +#if INET6 + isipv6 = ((tp->t_inpcb->inp_vflag & INP_IPV6) != 0) ? 1 : 0; + min_protoh = isipv6 ? sizeof (struct ip6_hdr) + sizeof (struct tcphdr) + : sizeof (struct tcpiphdr); +#else +#define min_protoh (sizeof (struct tcpiphdr)) +#endif #if INET6 if (isipv6) rt = tcp_rtlookup6(tp->t_inpcb); @@ -2988,7 +3047,47 @@ tcp_mssopt(tp, isipv6) #endif /* INET6 */ tcp_mssdflt; - mss = rt->rt_ifp->if_mtu - lgminh; + return rt->rt_ifp->if_mtu - min_protoh; +} + - return mss; +/* + * Checks for partial ack. If partial ack arrives, force the retransmission + * of the next unacknowledged segment, do not clear tp->t_dupacks, and return + * 1. By setting snd_nxt to ti_ack, this forces retransmission timer to + * be started again. If the ack advances at least to tp->snd_recover, return 0. + */ +static int +tcp_newreno(tp, th) + struct tcpcb *tp; + struct tcphdr *th; +{ + if (SEQ_LT(th->th_ack, tp->snd_recover)) { + tcp_seq onxt = tp->snd_nxt; + u_long ocwnd = tp->snd_cwnd; +#ifdef __APPLE__ + tp->t_timer[TCPT_REXMT] = 0; +#else + callout_stop(tp->tt_rexmt); +#endif + tp->t_rtttime = 0; + tp->snd_nxt = th->th_ack; + /* + * Set snd_cwnd to one segment beyond acknowledged offset + * (tp->snd_una has not yet been updated when this function + * is called) + */ + tp->snd_cwnd = tp->t_maxseg + (th->th_ack - tp->snd_una); + (void) tcp_output(tp); + tp->snd_cwnd = ocwnd; + if (SEQ_GT(onxt, tp->snd_nxt)) + tp->snd_nxt = onxt; + /* + * Partial window deflation. Relies on fact that tp->snd_una + * not updated yet. + */ + tp->snd_cwnd -= (th->th_ack - tp->snd_una - tp->t_maxseg); + return (1); + } + return (0); } diff --git a/bsd/netinet/tcp_output.c b/bsd/netinet/tcp_output.c index 56043b059..d3e5558d3 100644 --- a/bsd/netinet/tcp_output.c +++ b/bsd/netinet/tcp_output.c @@ -52,17 +52,16 @@ * SUCH DAMAGE. * * @(#)tcp_output.c 8.4 (Berkeley) 5/24/95 + * $FreeBSD: src/sys/netinet/tcp_output.c,v 1.39.2.10 2001/07/07 04:30:38 silby Exp $ */ -#if ISFB31 -#include "opt_tcpdebug.h" -#endif #define _IP_VHL -#include #include #include +#include +#include #include #include #include @@ -74,13 +73,13 @@ #include #include #include +#include #include #if INET6 +#include #include -#include #include #endif -#include #include #define TCPOUTFLAGS #include @@ -93,6 +92,9 @@ #endif #include +#if IPSEC +#include +#endif /*IPSEC*/ #define DBG_LAYER_BEG NETDBG_CODE(DBG_NETTCP, 1) #define DBG_LAYER_END NETDBG_CODE(DBG_NETTCP, 3) @@ -103,6 +105,29 @@ extern struct mbuf *m_copypack(); #endif +static int path_mtu_discovery = 1; +SYSCTL_INT(_net_inet_tcp, OID_AUTO, path_mtu_discovery, CTLFLAG_RW, + &path_mtu_discovery, 1, "Enable Path MTU Discovery"); + +int ss_fltsz = 1; +SYSCTL_INT(_net_inet_tcp, OID_AUTO, slowstart_flightsize, CTLFLAG_RW, + &ss_fltsz, 1, "Slow start flight size"); + +int ss_fltsz_local = TCP_MAXWIN; /* something large */ +SYSCTL_INT(_net_inet_tcp, OID_AUTO, local_slowstart_flightsize, CTLFLAG_RW, + &ss_fltsz_local, 1, "Slow start flight size for local networks"); + +int tcp_do_newreno = 0; +SYSCTL_INT(_net_inet_tcp, OID_AUTO, newreno, CTLFLAG_RW, &tcp_do_newreno, + 0, "Enable NewReno Algorithms"); + +struct mbuf *m_copym_with_hdrs __P((struct mbuf*, int, int, int, struct mbuf**, int*)); + + +/* temporary: for testing */ +#if IPSEC +extern int ipsec_bypass; +#endif /* * Tcp output routine: figure out what should be sent and send it. @@ -116,18 +141,19 @@ tcp_output(tp) int off, flags, error; register struct mbuf *m; struct ip *ip = NULL; - struct ipovly *ipov = NULL; + register struct ipovly *ipov = NULL; #if INET6 struct ip6_hdr *ip6 = NULL; #endif /* INET6 */ - struct tcphdr *th; + register struct tcphdr *th; u_char opt[TCP_MAXOLEN]; unsigned ipoptlen, optlen, hdrlen; int idle, sendalot; + int maxburst = TCP_MAXBURST; struct rmxp_tao *taop; struct rmxp_tao tao_noncached; #if INET6 - int isipv6 = (tp->t_inpcb->inp_vflag & INP_IPV4) == 0; + int isipv6; #endif int last_off; int m_off; @@ -136,12 +162,25 @@ tcp_output(tp) KERNEL_DEBUG(DBG_FNC_TCP_OUTPUT | DBG_FUNC_START, 0,0,0,0,0); +#if INET6 + if (isipv6 = ((tp->t_inpcb->inp_vflag & INP_IPV6) != 0)) { + + KERNEL_DEBUG(DBG_LAYER_BEG, + ((tp->t_inpcb->inp_fport << 16) | tp->t_inpcb->inp_lport), + (((tp->t_inpcb->in6p_laddr.s6_addr16[0] & 0xffff) << 16) | + (tp->t_inpcb->in6p_faddr.s6_addr16[0] & 0xffff)), + 0,0,0); + } + else +#endif - KERNEL_DEBUG(DBG_LAYER_BEG, - ((tp->t_template->tt_dport << 16) | tp->t_template->tt_sport), - (((tp->t_template->tt_src.s_addr & 0xffff) << 16) | - (tp->t_template->tt_dst.s_addr & 0xffff)), + { + KERNEL_DEBUG(DBG_LAYER_BEG, + ((tp->t_inpcb->inp_fport << 16) | tp->t_inpcb->inp_lport), + (((tp->t_inpcb->inp_laddr.s_addr & 0xffff) << 16) | + (tp->t_inpcb->inp_faddr.s_addr & 0xffff)), 0,0,0); + } /* * Determine length of data that should be transmitted, * and flags that will be used. @@ -149,17 +188,33 @@ tcp_output(tp) * to send, then transmit; otherwise, investigate further. */ idle = (tp->snd_max == tp->snd_una); - if (idle && tp->t_idle >= tp->t_rxtcur) +#ifdef __APPLE__ + if (idle && tp->t_rcvtime >= tp->t_rxtcur) { +#else + if (idle && (ticks - tp->t_rcvtime) >= tp->t_rxtcur) { +#endif /* * 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; - - /* Never send data that's already been acked */ - if (SEQ_GT(tp->snd_una, tp->snd_nxt)) - tp->snd_nxt = tp->snd_una; + * + * Set the slow-start flight size depending on whether + * this is a local network or not. + */ + if ( +#if INET6 + (isipv6 && in6_localaddr(&tp->t_inpcb->in6p_faddr)) || + (!isipv6 && +#endif + in_localaddr(tp->t_inpcb->inp_faddr) +#if INET6 + ) +#endif + ) + tp->snd_cwnd = tp->t_maxseg * ss_fltsz_local; + else + tp->snd_cwnd = tp->t_maxseg * ss_fltsz; + } again: sendalot = 0; off = tp->snd_nxt - tp->snd_una; @@ -380,12 +435,12 @@ send: * 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 + * max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MCLBYTES */ optlen = 0; #if INET6 if (isipv6) - hdrlen = sizeof (struct tcpip6hdr); + hdrlen = sizeof (struct ip6_hdr) + sizeof (struct tcphdr); else #endif hdrlen = sizeof (struct tcpiphdr); @@ -396,7 +451,7 @@ send: opt[0] = TCPOPT_MAXSEG; opt[1] = TCPOLEN_MAXSEG; - mss = htons((u_short) tcp_mssopt(tp, isipv6)); + mss = htons((u_short) tcp_mssopt(tp)); (void)memcpy(opt + 2, &mss, sizeof(mss)); optlen = TCPOLEN_MAXSEG; @@ -508,18 +563,17 @@ send: ipoptlen = ip6_optlen(tp->t_inpcb); else #endif - if (tp->t_inpcb->inp_options) { - ipoptlen = tp->t_inpcb->inp_options->m_len - + { + if (tp->t_inpcb->inp_options) { + ipoptlen = tp->t_inpcb->inp_options->m_len - offsetof(struct ipoption, ipopt_list); - } else { - ipoptlen = 0; + } else { + ipoptlen = 0; + } } #if IPSEC -#if INET6 - ipoptlen += ipsec_hdrsiz_tcp(tp, isipv6); -#else - ipoptlen += ipsec_hdrsiz_tcp(tp, 0); -#endif + if (ipsec_bypass == 0) + ipoptlen += ipsec_hdrsiz_tcp(tp); #endif /* @@ -538,8 +592,13 @@ send: } /*#ifdef DIAGNOSTIC*/ +#if INET6 + if (max_linkhdr + hdrlen > MCLBYTES) + panic("tcphdr too big"); +#else if (max_linkhdr + hdrlen > MHLEN) panic("tcphdr too big"); +#endif /*#endif*/ /* @@ -569,6 +628,18 @@ send: m->m_len += hdrlen; m->m_data -= hdrlen; #else + /* + * try to use the new interface that allocates all + * the necessary mbuf hdrs under 1 mbuf lock and + * avoids rescanning the socket mbuf list if + * certain conditions are met. This routine can't + * be used in the following cases... + * 1) the protocol headers exceed the capacity of + * of a single mbuf header's data area (no cluster attached) + * 2) the length of the data being transmitted plus + * the protocol headers fits into a single mbuf header's + * data area (no cluster attached) + */ m = NULL; #if INET6 if (MHLEN < hdrlen + max_linkhdr) { @@ -609,11 +680,25 @@ send: goto out; } } else { + /* + * determine whether the mbuf pointer and offset passed back by the 'last' call + * to m_copym_with_hdrs are still valid... if the head of the socket chain has + * changed (due to an incoming ACK for instance), or the offset into the chain we + * just computed is different from the one last returned by m_copym_with_hdrs (perhaps + * we're re-transmitting a packet sent earlier), than we can't pass the mbuf pointer and + * offset into it as valid hints for m_copym_with_hdrs to use (if valid, these hints allow + * m_copym_with_hdrs to avoid rescanning from the beginning of the socket buffer mbuf list. + * setting the mbuf pointer to NULL is sufficient to disable the hint mechanism. + */ if (m_head != so->so_snd.sb_mb || last_off != off) m_last = NULL; last_off = off + len; m_head = so->so_snd.sb_mb; + /* + * m_copym_with_hdrs will always return the last mbuf pointer and the offset into it that + * it acted on to fullfill the current request, whether a valid 'hint' was passed in or not + */ if ((m = m_copym_with_hdrs(so->so_snd.sb_mb, off, (int) len, M_DONTWAIT, &m_last, &m_off)) == NULL) { error = ENOBUFS; goto out; @@ -647,7 +732,8 @@ send: goto out; } #if INET6 - if (isipv6) { + if (isipv6 && (MHLEN < hdrlen + max_linkhdr) && + MHLEN >= hdrlen) { MH_ALIGN(m, hdrlen); } else #endif @@ -655,27 +741,20 @@ send: m->m_len = hdrlen; } m->m_pkthdr.rcvif = (struct ifnet *)0; - if (tp->t_template == 0) - panic("tcp_output"); #if INET6 if (isipv6) { ip6 = mtod(m, struct ip6_hdr *); th = (struct tcphdr *)(ip6 + 1); - bcopy((caddr_t)&tp->t_template->tt_i6, (caddr_t)ip6, - sizeof(struct ip6_hdr)); - bcopy((caddr_t)&tp->t_template->tt_t, (caddr_t)th, - sizeof(struct tcphdr)); - } else { + tcp_fillheaders(tp, ip6, th); + } else #endif /* INET6 */ - ip = mtod(m, struct ip *); - ipov = (struct ipovly *)ip; - th = (struct tcphdr *)(ip + 1); - bcopy((caddr_t)&tp->t_template->tt_i, (caddr_t)ip, sizeof(struct ip)); - bcopy((caddr_t)&tp->t_template->tt_t, (caddr_t)th, - sizeof(struct tcphdr)); -#if INET6 + { + ip = mtod(m, struct ip *); + ipov = (struct ipovly *)ip; + th = (struct tcphdr *)(ip + 1); + /* this picks up the pseudo header (w/o the length) */ + tcp_fillheaders(tp, ip, th); } -#endif /* INET6 */ /* * Fill in fields, remembering maximum advertised @@ -731,36 +810,32 @@ send: */ tp->snd_up = tp->snd_una; /* drag it along */ - /* * Put TCP length in extended header, and then * checksum extended header and data. */ - m->m_pkthdr.len = hdrlen + len; + m->m_pkthdr.len = hdrlen + len; /* in6_cksum() need this */ #if INET6 - if (isipv6) { -#if 0 /* ip6_plen will be filled in ip6_output. */ - ip6->ip6_plen = htons((u_short)(sizeof(struct tcphdr) + - optlen + len)); -#endif - + if (isipv6) + /* + * ip6_plen is not need to be filled now, and will be filled + * in ip6_output. + */ th->th_sum = in6_cksum(m, IPPROTO_TCP, sizeof(struct ip6_hdr), sizeof(struct tcphdr) + optlen + len); - } else + else #endif /* INET6 */ { + m->m_pkthdr.csum_flags = CSUM_TCP; + m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum); + if (len + optlen) + th->th_sum = in_addword(th->th_sum, + htons((u_short)(optlen + len))); - if (len + optlen) - ipov->ih_len = htons((u_short)(sizeof (struct tcphdr) + - optlen + len)); - m->m_pkthdr.csum_flags = CSUM_TCP; - m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum); - if (len + optlen) { - th->th_sum = in_addword(th->th_sum, - htons((u_short)(optlen + len))); - } - - } + /* IP version must be set here for ipv4/ipv6 checking later */ + KASSERT(ip->ip_v == IPVERSION, + ("%s: IP version incorrect: %d", __FUNCTION__, ip->ip_v)); + } /* * In transmit state, time the transmission and arrange for @@ -787,8 +862,8 @@ send: * Time this transmission if not a retransmission and * not currently timing anything. */ - if (tp->t_rtt == 0) { - tp->t_rtt = 1; + if (tp->t_rtttime == 0) { + tp->t_rtttime = 1; tp->t_rtseq = startseq; tcpstat.tcps_segstimed++; } @@ -818,23 +893,9 @@ send: /* * Trace. */ - if (so->so_options & SO_DEBUG) { -#if INET6 - if (isipv6) - ip6->ip6_vfc = IPV6_VERSION; - else - ip->ip_vhl = IP_MAKE_VHL(IPVERSION, - IP_VHL_HL(ip->ip_vhl)); -#endif /* INET6 */ - tcp_trace(TA_OUTPUT, tp->t_state, tp, -#if INET6 - isipv6 ? (void *)ip6 : -#endif /* INET6 */ - ip, - th, 0); - - } -#endif /* TCPDEBUG */ + if (so->so_options & SO_DEBUG) + tcp_trace(TA_OUTPUT, tp->t_state, tp, mtod(m, void *), th, 0); +#endif /* * Fill in IP length and desired time to live and @@ -842,9 +903,13 @@ send: * to handle ttl and tos; we could keep them in * the template, but need a way to checksum without them. */ + /* + * m->m_pkthdr.len should have been set before cksum calcuration, + * because in6_cksum() need it. + */ #if INET6 if (isipv6) { - /* + /* * we separately set hoplimit for every segment, since the * user might want to change the value via setsockopt. * Also, desired default hop limit might be changed via @@ -857,38 +922,51 @@ send: /* TODO: IPv6 IP6TOS_ECT bit on */ #if IPSEC - ipsec_setsocket(m, so); + if (ipsec_bypass == 0 && ipsec_setsocket(m, so) != 0) { + m_freem(m); + error = ENOBUFS; + goto out; + } #endif /*IPSEC*/ error = ip6_output(m, tp->t_inpcb->in6p_outputopts, &tp->t_inpcb->in6p_route, - (so->so_options & SO_DONTROUTE) /* | IP6_DONTFRAG */, - NULL, NULL); + (so->so_options & SO_DONTROUTE), NULL, NULL); } else #endif /* INET6 */ - { -#if 1 + { struct rtentry *rt; -#endif ip->ip_len = m->m_pkthdr.len; #if INET6 - if (INP_CHECK_SOCKAF(so, AF_INET6)) - ip->ip_ttl = in6_selecthlim(tp->t_inpcb, - tp->t_inpcb->in6p_route.ro_rt ? - tp->t_inpcb->in6p_route.ro_rt->rt_ifp - : NULL); - else + if (INP_CHECK_SOCKAF(so, AF_INET6)) + ip->ip_ttl = in6_selecthlim(tp->t_inpcb, + tp->t_inpcb->in6p_route.ro_rt ? + tp->t_inpcb->in6p_route.ro_rt->rt_ifp + : NULL); + else #endif /* INET6 */ ip->ip_ttl = tp->t_inpcb->inp_ip_ttl; /* XXX */ ip->ip_tos = tp->t_inpcb->inp_ip_tos; /* XXX */ -#define thtoti(x) \ - ((struct tcpiphdr *)(((char *)(x)) - (sizeof (struct ip)))) - KERNEL_DEBUG(DBG_LAYER_END, ((th->th_dport << 16) | th->th_sport), - (((thtoti(th)->ti_src.s_addr & 0xffff) << 16) | (thtoti(th)->ti_dst.s_addr & 0xffff)), - th->th_seq, th->th_ack, th->th_win); -#if 1 +#if INET6 + if (isipv6) { + KERNEL_DEBUG(DBG_LAYER_BEG, + ((tp->t_inpcb->inp_fport << 16) | tp->t_inpcb->inp_lport), + (((tp->t_inpcb->in6p_laddr.s6_addr16[0] & 0xffff) << 16) | + (tp->t_inpcb->in6p_faddr.s6_addr16[0] & 0xffff)), + 0,0,0); + } + else +#endif + { + KERNEL_DEBUG(DBG_LAYER_BEG, + ((tp->t_inpcb->inp_fport << 16) | tp->t_inpcb->inp_lport), + (((tp->t_inpcb->inp_laddr.s_addr & 0xffff) << 16) | + (tp->t_inpcb->inp_faddr.s_addr & 0xffff)), + 0,0,0); + } + /* * See if we should do MTU discovery. We do it only if the following * are true: @@ -896,21 +974,33 @@ send: * 2) the MTU is not locked (if it is, then discovery has been * disabled) */ - if ((rt = tp->t_inpcb->inp_route.ro_rt) + if (path_mtu_discovery + && (rt = tp->t_inpcb->inp_route.ro_rt) && rt->rt_flags & RTF_UP && !(rt->rt_rmx.rmx_locks & RTV_MTU)) { ip->ip_off |= IP_DF; } -#endif - #if IPSEC - ipsec_setsocket(m, so); + if (ipsec_bypass == 0) + ipsec_setsocket(m, so); #endif /*IPSEC*/ - error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route, - so->so_options & SO_DONTROUTE, 0); + (so->so_options & SO_DONTROUTE), 0); } if (error) { + + /* + * We know that the packet was lost, so back out the + * sequence number advance, if any. + */ + if (tp->t_force == 0 || !tp->t_timer[TCPT_PERSIST]) { + /* + * No need to check for TH_FIN here because + * the TF_SENTFIN flag handles that case. + */ + if ((flags & TH_SYN) == 0) + tp->snd_nxt -= len; + } out: if (error == ENOBUFS) { if (!tp->t_timer[TCPT_REXMT] && @@ -920,7 +1010,6 @@ out: KERNEL_DEBUG(DBG_FNC_TCP_OUTPUT | DBG_FUNC_END, 0,0,0,0,0); return (0); } -#if 1 if (error == EMSGSIZE) { /* * ip_output() will have already fixed the route @@ -932,7 +1021,6 @@ out: KERNEL_DEBUG(DBG_FNC_TCP_OUTPUT | DBG_FUNC_END, 0,0,0,0,0); return 0; } -#endif if ((error == EHOSTUNREACH || error == ENETDOWN) && TCPS_HAVERCVDSYN(tp->t_state)) { tp->t_softerror = error; @@ -964,10 +1052,11 @@ void tcp_setpersist(tp) register struct tcpcb *tp; { - register int t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1; + int t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1; + int tt; if (tp->t_timer[TCPT_REXMT]) - panic("tcp_output REXMT"); + panic("tcp_setpersist: retransmit pending"); /* * Start/restart persistance timer. */ diff --git a/bsd/netinet/tcp_seq.h b/bsd/netinet/tcp_seq.h index 5281fc374..57f1c9262 100644 --- a/bsd/netinet/tcp_seq.h +++ b/bsd/netinet/tcp_seq.h @@ -52,10 +52,12 @@ * SUCH DAMAGE. * * @(#)tcp_seq.h 8.3 (Berkeley) 6/21/95 + * $FreeBSD: src/sys/netinet/tcp_seq.h,v 1.11.2.5 2001/08/22 00:59:12 silby Exp $ */ #ifndef _NETINET_TCP_SEQ_H_ #define _NETINET_TCP_SEQ_H_ +#include /* * TCP sequence numbers are 32 bit integers operated * on with modular arithmetic. These macros can be @@ -83,6 +85,7 @@ /* Macro to increment a CC: skip 0 which has a special meaning */ #define CC_INC(c) (++(c) == 0 ? ++(c) : (c)) +#ifdef __APPLE_API_PRIVATE /* * Macros to initialize tcp sequence numbers for * send and receive from initial send and receive @@ -97,28 +100,11 @@ #define TCP_PAWS_IDLE (24 * 24 * 60 * 60 * PR_SLOWHZ) /* timestamp wrap-around time */ +#endif /* __APPLE_API_PRIVATE */ #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE extern tcp_cc tcp_ccgen; /* global connection count */ - -#ifdef TCP_COMPAT_42 -/* - * Increment for tcp_iss each second. - * This is designed to increment at the standard 250 KB/s, - * but with a random component averaging 128 KB. - * We also increment tcp_iss by a quarter of this amount - * each time we use the value for a new connection. - * If defined, the tcp_random18() macro should produce a - * number in the range [0-0x3ffff] that is hard to predict. - */ -#ifndef tcp_random18 -#define tcp_random18() ((random() >> 14) & 0x3ffff) -#endif -#define TCP_ISSINCR (122*1024 + tcp_random18()) - -extern tcp_seq tcp_iss; /* tcp initial send seq # */ -#endif /* TCP_COMPAT_42 */ -#else -#define TCP_ISSINCR (250*1024) /* increment for tcp_iss each second */ +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ #endif /* _NETINET_TCP_SEQ_H_ */ diff --git a/bsd/netinet/tcp_subr.c b/bsd/netinet/tcp_subr.c index 7cd45d421..1fccf314b 100644 --- a/bsd/netinet/tcp_subr.c +++ b/bsd/netinet/tcp_subr.c @@ -52,29 +52,28 @@ * SUCH DAMAGE. * * @(#)tcp_subr.c 8.2 (Berkeley) 5/24/95 + * $FreeBSD: src/sys/netinet/tcp_subr.c,v 1.73.2.22 2001/08/22 00:59:12 silby Exp $ */ -#if ISFB31 -#include "opt_compat.h" -#include "opt_tcpdebug.h" -#endif #include #include +#include #include #include #include #include +#if INET6 #include +#endif +#include #include #include #include +#include #include -#if ISFB31 -#include -#endif #include #include @@ -83,19 +82,26 @@ #include #include #include +#if INET6 +#include +#endif #include +#if INET6 +#include +#endif #include #include #if INET6 -#include #include -#include #endif #include #include #include #include #include +#if INET6 +#include +#endif #include #if TCPDEBUG #include @@ -104,45 +110,66 @@ #if IPSEC #include +#if INET6 +#include +#endif #endif /*IPSEC*/ +#include #include #define DBG_FNC_TCP_CLOSE NETDBG_CODE(DBG_NETTCP, ((5 << 8) | 2)) -#ifndef offsetof /* XXX */ -#define offsetof(type, member) ((size_t)(&((type *)0)->member)) -#endif +/* temporary: for testing */ +#if IPSEC +extern int ipsec_bypass; +#endif + int tcp_mssdflt = TCP_MSS; -SYSCTL_INT(_net_inet_tcp, TCPCTL_MSSDFLT, mssdflt, - CTLFLAG_RW, &tcp_mssdflt , 0, ""); +SYSCTL_INT(_net_inet_tcp, TCPCTL_MSSDFLT, mssdflt, CTLFLAG_RW, + &tcp_mssdflt , 0, "Default TCP Maximum Segment Size"); -int tcp_v6mssdflt = TCP6_MSS; +#if INET6 +int tcp_v6mssdflt = TCP6_MSS; SYSCTL_INT(_net_inet_tcp, TCPCTL_V6MSSDFLT, v6mssdflt, - CTLFLAG_RW, &tcp_v6mssdflt , 0, ""); - -static int tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ; -SYSCTL_INT(_net_inet_tcp, TCPCTL_RTTDFLT, rttdflt, - CTLFLAG_RW, &tcp_rttdflt , 0, ""); + CTLFLAG_RW, &tcp_v6mssdflt , 0, + "Default TCP Maximum Segment Size for IPv6"); +#endif static int tcp_do_rfc1323 = 1; -SYSCTL_INT(_net_inet_tcp, TCPCTL_DO_RFC1323, rfc1323, - CTLFLAG_RW, &tcp_do_rfc1323 , 0, ""); +SYSCTL_INT(_net_inet_tcp, TCPCTL_DO_RFC1323, rfc1323, CTLFLAG_RW, + &tcp_do_rfc1323 , 0, "Enable rfc1323 (high performance TCP) extensions"); static int tcp_do_rfc1644 = 0; -SYSCTL_INT(_net_inet_tcp, TCPCTL_DO_RFC1644, rfc1644, - CTLFLAG_RW, &tcp_do_rfc1644 , 0, ""); +SYSCTL_INT(_net_inet_tcp, TCPCTL_DO_RFC1644, rfc1644, CTLFLAG_RW, + &tcp_do_rfc1644 , 0, "Enable rfc1644 (TTCP) extensions"); -SYSCTL_INT(_net_inet_tcp, OID_AUTO, pcbcount, CTLFLAG_RD, &tcbinfo.ipi_count, - 0, "Number of active PCBs"); +static int tcp_tcbhashsize = 0; +SYSCTL_INT(_net_inet_tcp, OID_AUTO, tcbhashsize, CTLFLAG_RD, + &tcp_tcbhashsize, 0, "Size of TCP control-block hashtable"); -static void tcp_cleartaocache __P((void)); -static void tcp_notify __P((struct inpcb *, int)); -extern u_long current_active_connections; +static int do_tcpdrain = 1; +SYSCTL_INT(_net_inet_tcp, OID_AUTO, do_tcpdrain, CTLFLAG_RW, &do_tcpdrain, 0, + "Enable tcp_drain routine for extra help when low on mbufs"); +SYSCTL_INT(_net_inet_tcp, OID_AUTO, pcbcount, CTLFLAG_RD, + &tcbinfo.ipi_count, 0, "Number of active PCBs"); +static int icmp_may_rst = 1; +SYSCTL_INT(_net_inet_tcp, OID_AUTO, icmp_may_rst, CTLFLAG_RW, &icmp_may_rst, 0, + "Certain ICMP unreachable messages may abort connections in SYN_SENT"); +static int tcp_strict_rfc1948 = 0; +SYSCTL_INT(_net_inet_tcp, OID_AUTO, strict_rfc1948, CTLFLAG_RW, + &tcp_strict_rfc1948, 0, "Determines if RFC1948 is followed exactly"); + +static int tcp_isn_reseed_interval = 0; +SYSCTL_INT(_net_inet_tcp, OID_AUTO, isn_reseed_interval, CTLFLAG_RW, + &tcp_isn_reseed_interval, 0, "Seconds between reseeding of ISN secret"); + +static void tcp_cleartaocache __P((void)); +static void tcp_notify __P((struct inpcb *, int)); /* * Target size of TCP PCB hash tables. Must be a power of two. @@ -170,6 +197,10 @@ struct inp_tp { char align[(sizeof(struct inpcb) + ALIGNM1) & ~ALIGNM1]; } inp_tp_u; struct tcpcb tcb; +#ifndef __APPLE__ + struct callout inp_tp_rexmt, inp_tp_persist, inp_tp_keep, inp_tp_2msl; + struct callout inp_tp_delack; +#endif }; #undef ALIGNMENT #undef ALIGNM1 @@ -202,44 +233,51 @@ int tcp_freeq __P((struct tcpcb *tp)); void tcp_init() { - int hashsize; - vm_size_t str_size; - int i; - -#ifdef TCP_COMPAT_42 - tcp_iss = 1; -#endif /* TCP_COMPAT_42 */ + int hashsize = TCBHASHSIZE; + vm_size_t str_size; + int i; + tcp_ccgen = 1; tcp_cleartaocache(); + + tcp_delacktime = TCPTV_DELACK; + tcp_keepinit = TCPTV_KEEP_INIT; + tcp_keepidle = TCPTV_KEEP_IDLE; + tcp_keepintvl = TCPTV_KEEPINTVL; + tcp_maxpersistidle = TCPTV_KEEP_IDLE; + tcp_msl = TCPTV_MSL; + LIST_INIT(&tcb); tcbinfo.listhead = &tcb; - if (!(getenv_int("net.inet.tcp.tcbhashsize", &hashsize))) - hashsize = TCBHASHSIZE; +#ifndef __APPLE__ + TUNABLE_INT_FETCH("net.inet.tcp.tcbhashsize", &hashsize); +#endif if (!powerof2(hashsize)) { printf("WARNING: TCB hash size not a power of 2\n"); hashsize = 512; /* safe default */ } + tcp_tcbhashsize = hashsize; tcbinfo.hashsize = hashsize; tcbinfo.hashbase = hashinit(hashsize, M_PCB, &tcbinfo.hashmask); tcbinfo.porthashbase = hashinit(hashsize, M_PCB, &tcbinfo.porthashmask); -#if ISFB31 - tcbinfo.ipi_zone = (void *) zinit("tcpcb", sizeof(struct inp_tp), maxsockets, - ZONE_INTERRUPT, 0); -#else +#ifdef __APPLE__ str_size = (vm_size_t) sizeof(struct inp_tp); - tcbinfo.ipi_zone = (void *) zinit(str_size, 120000*str_size, 8192, "inpcb_zone"); + tcbinfo.ipi_zone = (void *) zinit(str_size, 120000*str_size, 8192, "tcpcb"); +#else + tcbinfo.ipi_zone = zinit("tcpcb", sizeof(struct inp_tp), maxsockets, + ZONE_INTERRUPT, 0); #endif #if INET6 -#define TCP_LGHDR (sizeof(struct tcpip6hdr)) +#define TCP_MINPROTOHDR (sizeof(struct ip6_hdr) + sizeof(struct tcphdr)) #else /* INET6 */ -#define TCP_LGHDR (sizeof(struct tcpiphdr)) +#define TCP_MINPROTOHDR (sizeof(struct tcpiphdr)) #endif /* INET6 */ - if (max_protohdr < TCP_LGHDR) - max_protohdr = TCP_LGHDR; - if ((max_linkhdr + TCP_LGHDR) > MHLEN) + if (max_protohdr < TCP_MINPROTOHDR) + max_protohdr = TCP_MINPROTOHDR; + if (max_linkhdr + TCP_MINPROTOHDR > MHLEN) panic("tcp_init"); - +#undef TCP_MINPROTOHDR tcbinfo.last_pcb = 0; dummy_tcb.t_state = TCP_NSTATES; dummy_tcb.t_flags = 0; @@ -256,61 +294,85 @@ tcp_init() for (i=0; i < N_TIME_WAIT_SLOTS; i++) { LIST_INIT(&time_wait_slots[i]); } -#undef TCP_LGHDR +} + +/* + * Fill in the IP and TCP headers for an outgoing packet, given the tcpcb. + * tcp_template used to store this data in mbufs, but we now recopy it out + * of the tcpcb each time to conserve mbufs. + */ +void +tcp_fillheaders(tp, ip_ptr, tcp_ptr) + struct tcpcb *tp; + void *ip_ptr; + void *tcp_ptr; +{ + struct inpcb *inp = tp->t_inpcb; + struct tcphdr *tcp_hdr = (struct tcphdr *)tcp_ptr; + +#if INET6 + if ((inp->inp_vflag & INP_IPV6) != 0) { + struct ip6_hdr *ip6; + + ip6 = (struct ip6_hdr *)ip_ptr; + ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) | + (inp->in6p_flowinfo & IPV6_FLOWINFO_MASK); + ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) | + (IPV6_VERSION & IPV6_VERSION_MASK); + ip6->ip6_nxt = IPPROTO_TCP; + ip6->ip6_plen = sizeof(struct tcphdr); + ip6->ip6_src = inp->in6p_laddr; + ip6->ip6_dst = inp->in6p_faddr; + tcp_hdr->th_sum = 0; + } else +#endif + { + struct ip *ip = (struct ip *) ip_ptr; + + ip->ip_vhl = IP_VHL_BORING; + ip->ip_tos = 0; + ip->ip_len = 0; + ip->ip_id = 0; + ip->ip_off = 0; + ip->ip_ttl = 0; + ip->ip_sum = 0; + ip->ip_p = IPPROTO_TCP; + ip->ip_src = inp->inp_laddr; + ip->ip_dst = inp->inp_faddr; + tcp_hdr->th_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, + htons(sizeof(struct tcphdr) + IPPROTO_TCP)); + } + + tcp_hdr->th_sport = inp->inp_lport; + tcp_hdr->th_dport = inp->inp_fport; + tcp_hdr->th_seq = 0; + tcp_hdr->th_ack = 0; + tcp_hdr->th_x2 = 0; + tcp_hdr->th_off = 5; + tcp_hdr->th_flags = 0; + tcp_hdr->th_win = 0; + tcp_hdr->th_urp = 0; } /* * 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. + * Allocates an mbuf and fills in a skeletal tcp/ip header. The only + * use for this function is in keepalives, which use tcp_respond. */ struct tcptemp * -tcp_template(tp) +tcp_maketemplate(tp) struct tcpcb *tp; { - register struct inpcb *inp = tp->t_inpcb; - register struct mbuf *m; - register struct tcptemp *n; + struct mbuf *m; + struct tcptemp *n; - if ((n = tp->t_template) == 0) { - m = m_get(M_DONTWAIT, MT_HEADER); - if (m == NULL) - return (0); - m->m_len = sizeof (struct tcptemp); - n = mtod(m, struct tcptemp *); - } - bzero(n->tt_x1, sizeof(n->tt_x1)); - n->tt_pr = IPPROTO_TCP; - n->tt_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); - n->tt_src = inp->inp_laddr; - n->tt_dst = inp->inp_faddr; - n->tt_sport = inp->inp_lport; - n->tt_dport = inp->inp_fport; - n->tt_seq = 0; - n->tt_ack = 0; - n->tt_x2 = 0; - n->tt_off = 5; - n->tt_flags = 0; - n->tt_win = 0; - n->tt_sum = 0; - n->tt_urp = 0; - - n->tt_t.th_sum = in_pseudo(n->tt_src.s_addr, n->tt_dst.s_addr, - htons(sizeof(struct tcphdr) + IPPROTO_TCP)); + m = m_get(M_DONTWAIT, MT_HEADER); + if (m == NULL) + return (0); + m->m_len = sizeof(struct tcptemp); + n = mtod(m, struct tcptemp *); -#if INET6 - n->tt_flow = inp->inp_flow & IPV6_FLOWINFO_MASK; - if (ip6_auto_flowlabel) { - n->tt_flow &= ~IPV6_FLOWLABEL_MASK; - n->tt_flow |= (htonl(ip6_flow_seq++) & IPV6_FLOWLABEL_MASK); - } - n->tt_vfc |= IPV6_VERSION; - n->tt_pr6 = IPPROTO_TCP; - n->tt_len6 = n->tt_len; - n->tt_src6 = inp->in6p_laddr; - n->tt_dst6 = inp->in6p_faddr; -#endif /* INET6 */ + tcp_fillheaders(tp, (void *)&n->tt_ipgen, (void *)&n->tt_t); return (n); } @@ -319,10 +381,9 @@ tcp_template(tp) * 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. + * template for a connection. 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. @@ -330,34 +391,40 @@ tcp_template(tp) * NOTE: If m != NULL, then ti must point to *inside* the mbuf. */ void -tcp_respond(tp, iph, th, m, ack, seq, flags, isipv6) +tcp_respond(tp, ipgen, th, m, ack, seq, flags) struct tcpcb *tp; - void *iph; + void *ipgen; register struct tcphdr *th; register struct mbuf *m; tcp_seq ack, seq; int flags; -#if INET6 - int isipv6; -#endif { register int tlen; int win = 0; struct route *ro = 0; struct route sro; - struct ip *ip = iph; - struct tcpiphdr *ti = iph; + struct ip *ip; struct tcphdr *nth; #if INET6 struct route_in6 *ro6 = 0; struct route_in6 sro6; - struct ip6_hdr *ip6 = iph; - struct tcpip6hdr *ti6 = iph; + struct ip6_hdr *ip6; + int isipv6; #endif /* INET6 */ + int ipflags = 0; + +#if INET6 + isipv6 = IP_VHL_V(((struct ip *)ipgen)->ip_vhl) == 6; + ip6 = ipgen; +#endif /* INET6 */ + ip = ipgen; if (tp) { - if (!(flags & TH_RST)) + if (!(flags & TH_RST)) { win = sbspace(&tp->t_inpcb->inp_socket->so_rcv); + if (win > (long)TCP_MAXWIN << tp->rcv_scale) + win = (long)TCP_MAXWIN << tp->rcv_scale; + } #if INET6 if (isipv6) ro6 = &tp->t_inpcb->in6p_route; @@ -369,76 +436,78 @@ tcp_respond(tp, iph, th, m, ack, seq, flags, isipv6) if (isipv6) { ro6 = &sro6; bzero(ro6, sizeof *ro6); - } else { + } else #endif /* INET6 */ - ro = &sro; - bzero(ro, sizeof *ro); -#if INET6 + { + ro = &sro; + bzero(ro, sizeof *ro); } -#endif /* INET6 */ } if (m == 0) { m = m_gethdr(M_DONTWAIT, MT_HEADER); if (m == NULL) return; -#if TCP_COMPAT_42 - tlen = 1; -#else tlen = 0; -#endif m->m_data += max_linkhdr; #if INET6 if (isipv6) { - ti6 = mtod(m, struct tcpip6hdr *); - bcopy((caddr_t)ip6, (caddr_t)&ti6->ti6_i, + bcopy((caddr_t)ip6, mtod(m, caddr_t), sizeof(struct ip6_hdr)); - ip6 = &ti6->ti6_i; - nth = &ti6->ti6_t; - } else { + ip6 = mtod(m, struct ip6_hdr *); + nth = (struct tcphdr *)(ip6 + 1); + } else #endif /* INET6 */ - ti = mtod(m, struct tcpiphdr *); - bcopy((caddr_t)ip, (caddr_t)&ti->ti_i, sizeof(struct ip)); - ip = (struct ip *)&ti->ti_i; - nth = &ti->ti_t; -#if INET6 + { + bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); + ip = mtod(m, struct ip *); + nth = (struct tcphdr *)(ip + 1); } -#endif /* INET6 */ bcopy((caddr_t)th, (caddr_t)nth, sizeof(struct tcphdr)); flags = TH_ACK; } else { m_freem(m->m_next); m->m_next = 0; - m->m_data = (caddr_t)ti; + m->m_data = (caddr_t)ipgen; /* m_len is set later */ tlen = 0; #define xchg(a,b,type) { type t; t=a; a=b; b=t; } #if INET6 if (isipv6) { - struct in6_addr t; - - t = ip6->ip6_dst; - ip6->ip6_dst = ip6->ip6_src; - ip6->ip6_src = t; + xchg(ip6->ip6_dst, ip6->ip6_src, struct in6_addr); nth = (struct tcphdr *)(ip6 + 1); - if (th != nth) { - /* - * this is the case if an extension header - * exists between the IPv6 header and the - * TCP header. - */ - nth->th_sport = th->th_sport; - nth->th_dport = th->th_dport; - } - } else { + } else #endif /* INET6 */ - xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, n_long); - nth = th; -#if INET6 + { + xchg(ip->ip_dst.s_addr, ip->ip_src.s_addr, n_long); + nth = (struct tcphdr *)(ip + 1); + } + if (th != nth) { + /* + * this is usually a case when an extension header + * exists between the IPv6 header and the + * TCP header. + */ + nth->th_sport = th->th_sport; + nth->th_dport = th->th_dport; } -#endif /* INET6 */ xchg(nth->th_dport, nth->th_sport, n_short); #undef xchg } +#if INET6 + if (isipv6) { + ip6->ip6_plen = htons((u_short)(sizeof (struct tcphdr) + + tlen)); + tlen += sizeof (struct ip6_hdr) + sizeof (struct tcphdr); + } else +#endif + { + tlen += sizeof (struct tcpiphdr); + ip->ip_len = tlen; + ip->ip_ttl = ip_defttl; + } + m->m_len = tlen; + m->m_pkthdr.len = tlen; + m->m_pkthdr.rcvif = (struct ifnet *) 0; nth->th_seq = htonl(seq); nth->th_ack = htonl(ack); nth->th_x2 = 0; @@ -449,67 +518,50 @@ tcp_respond(tp, iph, th, m, ack, seq, flags, isipv6) else nth->th_win = htons((u_short)win); nth->th_urp = 0; - tlen += sizeof (struct tcphdr); #if INET6 if (isipv6) { - m->m_len = tlen + sizeof(struct ip6_hdr); - m->m_pkthdr.len = tlen + sizeof(struct ip6_hdr); - m->m_pkthdr.rcvif = (struct ifnet *) 0; - ip6->ip6_plen = htons((u_short)tlen); - ip6->ip6_nxt = IPPROTO_TCP; + nth->th_sum = 0; + nth->th_sum = in6_cksum(m, IPPROTO_TCP, + sizeof(struct ip6_hdr), + tlen - sizeof(struct ip6_hdr)); ip6->ip6_hlim = in6_selecthlim(tp ? tp->t_inpcb : NULL, ro6 && ro6->ro_rt ? ro6->ro_rt->rt_ifp : NULL); - nth->th_sum = in6_cksum(m, IPPROTO_TCP, - sizeof(struct ip6_hdr), tlen); - ip6->ip6_flow &= ~IPV6_FLOWLABEL_MASK; - if (ip6_auto_flowlabel) { - ip6->ip6_flow |= - (htonl(ip6_flow_seq++) & IPV6_FLOWLABEL_MASK); - } - } else { + } else #endif /* INET6 */ - ti->ti_len = htons((u_short)(tlen)); - m->m_len = tlen + sizeof(struct ip); - m->m_pkthdr.len = tlen + sizeof(struct ip); - m->m_pkthdr.rcvif = (struct ifnet *) 0; - nth->th_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, - htons((u_short)(tlen + IPPROTO_TCP))); - m->m_pkthdr.csum_flags = CSUM_TCP; - m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum); - - ip->ip_len = tlen + sizeof (struct ip); - ip->ip_ttl = ip_defttl; -#if INET6 + { + nth->th_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, + htons((u_short)(tlen - sizeof(struct ip) + ip->ip_p))); + m->m_pkthdr.csum_flags = CSUM_TCP; + m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum); } -#endif /* INET6 */ #if TCPDEBUG if (tp == NULL || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) - tcp_trace(TA_OUTPUT, 0, tp, -#if INET6 - isipv6 ? (void *)ip6 : -#endif /* INET6 */ - ip, - nth, 0); + tcp_trace(TA_OUTPUT, 0, tp, mtod(m, void *), th, 0); #endif #if IPSEC - ipsec_setsocket(m, tp ? tp->t_inpcb->inp_socket : NULL); -#endif /*IPSEC*/ + if (ipsec_bypass == 0 && ipsec_setsocket(m, tp ? tp->t_inpcb->inp_socket : NULL) != 0) { + m_freem(m); + return; + } +#endif #if INET6 if (isipv6) { - (void)ip6_output(m, NULL, ro6, 0, NULL, NULL); - if (ro6 == &sro6 && ro6->ro_rt) - RTFREE(ro6->ro_rt); - } else { + (void)ip6_output(m, NULL, ro6, ipflags, NULL, NULL); + if (ro6 == &sro6 && ro6->ro_rt) { + rtfree(ro6->ro_rt); + ro6->ro_rt = NULL; + } + } else #endif /* INET6 */ - (void)ip_output(m, NULL, ro, 0, NULL); - if (ro == &sro && ro->ro_rt) { - RTFREE(ro->ro_rt); - } -#if INET6 + { + (void) ip_output(m, NULL, ro, ipflags, NULL); + if (ro == &sro && ro->ro_rt) { + rtfree(ro->ro_rt); + ro->ro_rt = NULL; + } } -#endif /* INET6 */ } /* @@ -526,10 +578,9 @@ tcp_newtcpcb(inp) register struct tcpcb *tp; register struct socket *so = inp->inp_socket; #if INET6 - int isipv6 = (inp->inp_vflag & INP_IPV6) != 0; + int isipv6 = (inp->inp_vflag & INP_IPV6) != 0; #endif /* INET6 */ - if (so->cached_in_sock_layer == 0) { it = (struct inp_tp *)inp; tp = &it->tcb; @@ -538,13 +589,21 @@ tcp_newtcpcb(inp) tp = (struct tcpcb *) inp->inp_saved_ppcb; bzero((char *) tp, sizeof(struct tcpcb)); - tp->segq.lh_first = NULL; - tp->t_maxseg = tp->t_maxopd = + LIST_INIT(&tp->t_segq); + tp->t_maxseg = tp->t_maxopd = #if INET6 - isipv6 ? tcp_v6mssdflt : + isipv6 ? tcp_v6mssdflt : #endif /* INET6 */ - tcp_mssdflt; - + tcp_mssdflt; + +#ifndef __APPLE__ + /* Set up our timeouts. */ + callout_init(tp->tt_rexmt = &it->inp_tp_rexmt); + callout_init(tp->tt_persist = &it->inp_tp_persist); + callout_init(tp->tt_keep = &it->inp_tp_keep); + callout_init(tp->tt_2msl = &it->inp_tp_2msl); + callout_init(tp->tt_delack = &it->inp_tp_delack); +#endif if (tcp_do_rfc1323) tp->t_flags = (TF_REQ_SCALE|TF_REQ_TSTMP); @@ -562,11 +621,10 @@ tcp_newtcpcb(inp) tp->t_rxtcur = TCPTV_RTOBASE; tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT; tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT; - /* + /* * IPv4 TTL initialization is necessary for an IPv6 socket as well, * because the socket may be bound to an IPv6 wildcard address, * which may match an IPv4-mapped IPv6 address. - * XXX: is there a better approach? */ inp->inp_ip_ttl = ip_defttl; inp->inp_ppcb = (caddr_t)tp; @@ -585,6 +643,7 @@ tcp_drop(tp, errno) { struct socket *so = tp->t_inpcb->inp_socket; +#ifdef __APPLE__ switch (tp->t_state) { case TCPS_ESTABLISHED: @@ -592,10 +651,10 @@ tcp_drop(tp, errno) case TCPS_CLOSING: case TCPS_CLOSE_WAIT: case TCPS_LAST_ACK: - current_active_connections--; break; } - +#endif + if (TCPS_HAVERCVDSYN(tp->t_state)) { tp->t_state = TCPS_CLOSED; (void) tcp_output(tp); @@ -618,16 +677,26 @@ struct tcpcb * tcp_close(tp) register struct tcpcb *tp; { - register struct mbuf *q; - register struct mbuf *nq; + register struct tseg_qent *q; struct inpcb *inp = tp->t_inpcb; struct socket *so = inp->inp_socket; #if INET6 - int isipv6 = INP_CHECK_SOCKAF(so, AF_INET6); + int isipv6 = (inp->inp_vflag & INP_IPV6) != 0; #endif /* INET6 */ register struct rtentry *rt; int dosavessthresh; +#ifndef __APPLE__ + /* + * Make sure that all of our timers are stopped before we + * delete the PCB. + */ + callout_stop(tp->tt_rexmt); + callout_stop(tp->tt_persist); + callout_stop(tp->tt_keep); + callout_stop(tp->tt_2msl); + callout_stop(tp->tt_delack); +#endif KERNEL_DEBUG(DBG_FNC_TCP_CLOSE | DBG_FUNC_START, tp,0,0,0,0); switch (tp->t_state) @@ -637,7 +706,6 @@ tcp_close(tp) case TCPS_CLOSING: case TCPS_CLOSE_WAIT: case TCPS_LAST_ACK: - current_active_connections--; break; } @@ -729,9 +797,14 @@ tcp_close(tp) i = 2; i *= (u_long)(tp->t_maxseg + #if INET6 - isipv6 ? sizeof (struct tcpip6hdr) : -#endif /* INET6 */ - sizeof (struct tcpiphdr)); + (isipv6 ? sizeof (struct ip6_hdr) + + sizeof (struct tcphdr) : +#endif + sizeof (struct tcpiphdr) +#if INET6 + ) +#endif + ); if (rt->rt_rmx.rmx_ssthresh) rt->rt_rmx.rmx_ssthresh = (rt->rt_rmx.rmx_ssthresh + i) / 2; @@ -740,20 +813,31 @@ tcp_close(tp) tcpstat.tcps_cachedssthresh++; } } + rt = inp->inp_route.ro_rt; + if (rt) { + /* + * mark route for deletion if no information is + * cached. + */ + if ((tp->t_flags & TF_LQ_OVERFLOW) && + ((rt->rt_rmx.rmx_locks & RTV_RTT) == 0)){ + if (rt->rt_rmx.rmx_rtt == 0) + rt->rt_flags |= RTF_DELCLONE; + } + } no_valid_rt: /* free the reassembly queue, if any */ (void) tcp_freeq(tp); - if (tp->t_template) - (void) m_free(dtom(tp->t_template)); - +#ifdef __APPLE__ if (so->cached_in_sock_layer) inp->inp_saved_ppcb = (caddr_t) tp; +#endif inp->inp_ppcb = NULL; soisdisconnected(so); #if INET6 - if (isipv6) + if (INP_CHECK_SOCKAF(so, AF_INET6)) in6_pcbdetach(inp); else #endif /* INET6 */ @@ -767,13 +851,14 @@ int tcp_freeq(tp) struct tcpcb *tp; { - register struct ipqent *qe; + + register struct tseg_qent *q; int rv = 0; - while ((qe = tp->segq.lh_first) != NULL) { - LIST_REMOVE(qe, ipqe_q); - m_freem(qe->ipqe_m); - FREE(qe, M_SONAME); + while((q = LIST_FIRST(&tp->t_segq)) != NULL) { + LIST_REMOVE(q, tqe_q); + m_freem(q->tqe_m); + FREE(q, M_TSEGQ); rv = 1; } return (rv); @@ -782,21 +867,49 @@ tcp_freeq(tp) void tcp_drain() { + if (do_tcpdrain) + { + struct inpcb *inpb; + struct tcpcb *tcpb; + struct tseg_qent *te; + + /* + * Walk the tcpbs, if existing, and flush the reassembly queue, + * if there is one... + * XXX: The "Net/3" implementation doesn't imply that the TCP + * reassembly queue should be flushed, but in a situation + * where we're really low on mbufs, this is potentially + * usefull. + */ + for (inpb = LIST_FIRST(tcbinfo.listhead); inpb; + inpb = LIST_NEXT(inpb, inp_list)) { + if ((tcpb = intotcpcb(inpb))) { + while ((te = LIST_FIRST(&tcpb->t_segq)) + != NULL) { + LIST_REMOVE(te, tqe_q); + m_freem(te->tqe_m); + FREE(te, M_TSEGQ); + } + } + } + } } /* * 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). + * + * Do not wake up user since there currently is no mechanism for + * reporting soft errors (yet - a kqueue filter may be added). */ static void tcp_notify(inp, error) struct inpcb *inp; int error; { - register struct tcpcb *tp = (struct tcpcb *)inp->inp_ppcb; - register struct socket *so = inp->inp_socket; + struct tcpcb *tp = (struct tcpcb *)inp->inp_ppcb; /* * Ignore some errors if we are hooked up. @@ -811,15 +924,16 @@ tcp_notify(inp, error) return; } else if (tp->t_state < TCPS_ESTABLISHED && tp->t_rxtshift > 3 && tp->t_softerror) - so->so_error = error; + tcp_drop(tp, error); else tp->t_softerror = error; +#if 0 wakeup((caddr_t) &so->so_timeo); sorwakeup(so); sowwakeup(so); +#endif } - static int tcp_pcblist SYSCTL_HANDLER_ARGS { @@ -868,9 +982,13 @@ tcp_pcblist SYSCTL_HANDLER_ARGS return ENOMEM; s = splnet(); - for (inp = tcbinfo.listhead->lh_first, i = 0; inp && i < n; - inp = inp->inp_list.le_next) { + for (inp = LIST_FIRST(tcbinfo.listhead), i = 0; inp && i < n; + inp = LIST_NEXT(inp, inp_list)) { +#ifdef __APPLE__ if (inp->inp_gencnt <= gencnt) +#else + if (inp->inp_gencnt <= gencnt && !prison_xinpcb(req->p, inp)) +#endif inp_list[i++] = inp; } splx(s); @@ -881,10 +999,15 @@ tcp_pcblist SYSCTL_HANDLER_ARGS inp = inp_list[i]; if (inp->inp_gencnt <= gencnt) { struct xtcpcb xt; + caddr_t inp_ppcb; xt.xt_len = sizeof xt; /* XXX should avoid extra copy */ bcopy(inp, &xt.xt_inp, sizeof *inp); - bcopy(inp->inp_ppcb, &xt.xt_tp, sizeof xt.xt_tp); + inp_ppcb = inp->inp_ppcb; + if (inp_ppcb != NULL) + bcopy(inp_ppcb, &xt.xt_tp, sizeof xt.xt_tp); + else + bzero((char *) &xt.xt_tp, sizeof xt.xt_tp); if (inp->inp_socket) sotoxsocket(inp->inp_socket, &xt.xt_socket); error = SYSCTL_OUT(req, &xt, sizeof xt); @@ -909,34 +1032,138 @@ tcp_pcblist SYSCTL_HANDLER_ARGS return error; } - SYSCTL_PROC(_net_inet_tcp, TCPCTL_PCBLIST, pcblist, CTLFLAG_RD, 0, 0, tcp_pcblist, "S,xtcpcb", "List of active TCP connections"); +#ifndef __APPLE__ +static int +tcp_getcred(SYSCTL_HANDLER_ARGS) +{ + struct sockaddr_in addrs[2]; + struct inpcb *inp; + int error, s; + + error = suser(req->p); + if (error) + return (error); + error = SYSCTL_IN(req, addrs, sizeof(addrs)); + if (error) + return (error); + s = splnet(); + inp = in_pcblookup_hash(&tcbinfo, addrs[1].sin_addr, addrs[1].sin_port, + addrs[0].sin_addr, addrs[0].sin_port, 0, NULL); + if (inp == NULL || inp->inp_socket == NULL) { + error = ENOENT; + goto out; + } + error = SYSCTL_OUT(req, inp->inp_socket->so_cred, sizeof(struct ucred)); +out: + splx(s); + return (error); +} + +SYSCTL_PROC(_net_inet_tcp, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW, + 0, 0, tcp_getcred, "S,ucred", "Get the ucred of a TCP connection"); + +#if INET6 +static int +tcp6_getcred(SYSCTL_HANDLER_ARGS) +{ + struct sockaddr_in6 addrs[2]; + struct inpcb *inp; + int error, s, mapped = 0; + + error = suser(req->p); + if (error) + return (error); + error = SYSCTL_IN(req, addrs, sizeof(addrs)); + if (error) + return (error); + if (IN6_IS_ADDR_V4MAPPED(&addrs[0].sin6_addr)) { + if (IN6_IS_ADDR_V4MAPPED(&addrs[1].sin6_addr)) + mapped = 1; + else + return (EINVAL); + } + s = splnet(); + if (mapped == 1) + inp = in_pcblookup_hash(&tcbinfo, + *(struct in_addr *)&addrs[1].sin6_addr.s6_addr[12], + addrs[1].sin6_port, + *(struct in_addr *)&addrs[0].sin6_addr.s6_addr[12], + addrs[0].sin6_port, + 0, NULL); + else + inp = in6_pcblookup_hash(&tcbinfo, &addrs[1].sin6_addr, + addrs[1].sin6_port, + &addrs[0].sin6_addr, addrs[0].sin6_port, + 0, NULL); + if (inp == NULL || inp->inp_socket == NULL) { + error = ENOENT; + goto out; + } + error = SYSCTL_OUT(req, inp->inp_socket->so_cred, + sizeof(struct ucred)); +out: + splx(s); + return (error); +} + +SYSCTL_PROC(_net_inet6_tcp6, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW, + 0, 0, + tcp6_getcred, "S,ucred", "Get the ucred of a TCP6 connection"); +#endif +#endif /* __APPLE__*/ + void tcp_ctlinput(cmd, sa, vip) int cmd; struct sockaddr *sa; void *vip; { - register struct ip *ip = vip; - register struct tcphdr *th; + struct ip *ip = vip; + struct tcphdr *th; + struct in_addr faddr; + struct inpcb *inp; + struct tcpcb *tp; void (*notify) __P((struct inpcb *, int)) = tcp_notify; + tcp_seq icmp_seq; + int s; + + faddr = ((struct sockaddr_in *)sa)->sin_addr; + if (sa->sa_family != AF_INET || faddr.s_addr == INADDR_ANY) + return; if (cmd == PRC_QUENCH) notify = tcp_quench; + else if (icmp_may_rst && (cmd == PRC_UNREACH_ADMIN_PROHIB || + cmd == PRC_UNREACH_PORT) && ip) + notify = tcp_drop_syn_sent; else if (cmd == PRC_MSGSIZE) notify = tcp_mtudisc; - else if (!PRC_IS_REDIRECT(cmd) && - ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0)) + else if (PRC_IS_REDIRECT(cmd)) { + ip = 0; + notify = in_rtchange; + } else if (cmd == PRC_HOSTDEAD) + ip = 0; + else if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0) return; if (ip) { + s = splnet(); th = (struct tcphdr *)((caddr_t)ip + (IP_VHL_HL(ip->ip_vhl) << 2)); - in_pcbnotify(&tcb, sa, th->th_dport, ip->ip_src, th->th_sport, - cmd, notify); + inp = in_pcblookup_hash(&tcbinfo, faddr, th->th_dport, + ip->ip_src, th->th_sport, 0, NULL); + if (inp != NULL && inp->inp_socket != NULL) { + icmp_seq = htonl(th->th_seq); + tp = intotcpcb(inp); + if (SEQ_GEQ(icmp_seq, tp->snd_una) && + SEQ_LT(icmp_seq, tp->snd_max)) + (*notify)(inp, inetctlerrmap[cmd]); + } + splx(s); } else - in_pcbnotify(&tcb, sa, 0, zeroin_addr, 0, cmd, notify); + in_pcbnotifyall(&tcb, faddr, inetctlerrmap[cmd], notify); } #if INET6 @@ -946,13 +1173,17 @@ tcp6_ctlinput(cmd, sa, d) struct sockaddr *sa; void *d; { - register struct tcphdr *thp; struct tcphdr th; void (*notify) __P((struct inpcb *, int)) = tcp_notify; - struct sockaddr_in6 sa6; struct ip6_hdr *ip6; struct mbuf *m; - int off = 0 ; + struct ip6ctlparam *ip6cp = NULL; + const struct sockaddr_in6 *sa6_src = NULL; + int off; + struct tcp_portonly { + u_int16_t th_sport; + u_int16_t th_dport; + } *thp; if (sa->sa_family != AF_INET6 || sa->sa_len != sizeof(struct sockaddr_in6)) @@ -968,107 +1199,145 @@ tcp6_ctlinput(cmd, sa, d) /* if the parameter is from icmp6, decode it. */ if (d != NULL) { - struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d; + ip6cp = (struct ip6ctlparam *)d; m = ip6cp->ip6c_m; ip6 = ip6cp->ip6c_ip6; off = ip6cp->ip6c_off; + sa6_src = ip6cp->ip6c_src; } else { m = NULL; ip6 = NULL; + off = 0; /* fool gcc */ + sa6_src = &sa6_any; } - /* translate addresses into internal form */ - sa6 = *(struct sockaddr_in6 *)sa; - if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) && m && m->m_pkthdr.rcvif) - sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); - if (ip6) { /* * XXX: We assume that when IPV6 is non NULL, * M and OFF are valid. */ - struct in6_addr s; - /* translate addresses into internal form */ - memcpy(&s, &ip6->ip6_src, sizeof(s)); - if (IN6_IS_ADDR_LINKLOCAL(&s)) - s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); + /* check if we can safely examine src and dst ports */ + if (m->m_pkthdr.len < off + sizeof(*thp)) + return; + bzero(&th, sizeof(th)); + m_copydata(m, off, sizeof(*thp), (caddr_t)&th); - if (m->m_len < off + sizeof(*thp)) { - /* - * this should be rare case, - * so we compromise on this copy... - */ - m_copydata(m, off, sizeof(th), (caddr_t)&th); - thp = &th; - } else - thp = (struct tcphdr *)(mtod(m, caddr_t) + off); - in6_pcbnotify(&tcb, (struct sockaddr *)&sa6, thp->th_dport, - &s, thp->th_sport, cmd, notify); + in6_pcbnotify(&tcb, sa, th.th_dport, + (struct sockaddr *)ip6cp->ip6c_src, + th.th_sport, cmd, notify); } else - in6_pcbnotify(&tcb, (struct sockaddr *)&sa6, 0, &zeroin6_addr, + in6_pcbnotify(&tcb, sa, 0, (struct sockaddr *)sa6_src, 0, cmd, notify); } #endif /* INET6 */ -#define TCP_RNDISS_ROUNDS 16 -#define TCP_RNDISS_OUT 7200 -#define TCP_RNDISS_MAX 30000 - -u_int8_t tcp_rndiss_sbox[128]; -u_int16_t tcp_rndiss_msb; -u_int16_t tcp_rndiss_cnt; -long tcp_rndiss_reseed; -u_int16_t -tcp_rndiss_encrypt(val) - u_int16_t val; -{ - u_int16_t sum = 0, i; - - for (i = 0; i < TCP_RNDISS_ROUNDS; i++) { - sum += 0x79b9; - val ^= ((u_int16_t)tcp_rndiss_sbox[(val^sum) & 0x7f]) << 7; - val = ((val & 0xff) << 7) | (val >> 8); - } - - return val; -} - -void -tcp_rndiss_init() -{ - struct timeval time; +/* + * Following is where TCP initial sequence number generation occurs. + * + * There are two places where we must use initial sequence numbers: + * 1. In SYN-ACK packets. + * 2. In SYN packets. + * + * The ISNs in SYN-ACK packets have no monotonicity requirement, + * and should be as unpredictable as possible to avoid the possibility + * of spoofing and/or connection hijacking. To satisfy this + * requirement, SYN-ACK ISNs are generated via the arc4random() + * function. If exact RFC 1948 compliance is requested via sysctl, + * these ISNs will be generated just like those in SYN packets. + * + * The ISNs in SYN packets must be monotonic; TIME_WAIT recycling + * depends on this property. In addition, these ISNs should be + * unguessable so as to prevent connection hijacking. To satisfy + * the requirements of this situation, the algorithm outlined in + * RFC 1948 is used to generate sequence numbers. + * + * For more information on the theory of operation, please see + * RFC 1948. + * + * Implementation details: + * + * Time is based off the system timer, and is corrected so that it + * increases by one megabyte per second. This allows for proper + * recycling on high speed LANs while still leaving over an hour + * before rollover. + * + * Two sysctls control the generation of ISNs: + * + * net.inet.tcp.isn_reseed_interval controls the number of seconds + * between seeding of isn_secret. This is normally set to zero, + * as reseeding should not be necessary. + * + * net.inet.tcp.strict_rfc1948 controls whether RFC 1948 is followed + * strictly. When strict compliance is requested, reseeding is + * disabled and SYN-ACKs will be generated in the same manner as + * SYNs. Strict mode is disabled by default. + * + */ - getmicrotime(&time); - read_random(tcp_rndiss_sbox, sizeof(tcp_rndiss_sbox)); +#define ISN_BYTES_PER_SECOND 1048576 - tcp_rndiss_reseed = time.tv_sec + TCP_RNDISS_OUT; - tcp_rndiss_msb = tcp_rndiss_msb == 0x8000 ? 0 : 0x8000; - tcp_rndiss_cnt = 0; -} +u_char isn_secret[32]; +int isn_last_reseed; +MD5_CTX isn_ctx; tcp_seq -tcp_rndiss_next() +tcp_new_isn(tp) + struct tcpcb *tp; { - u_int32_t tmp; - struct timeval time; - - getmicrotime(&time); - - if (tcp_rndiss_cnt >= TCP_RNDISS_MAX || - time.tv_sec > tcp_rndiss_reseed) - tcp_rndiss_init(); - - tmp = random(); + u_int32_t md5_buffer[4]; + tcp_seq new_isn; + struct timeval time; + + /* Use arc4random for SYN-ACKs when not in exact RFC1948 mode. */ + if (((tp->t_state == TCPS_LISTEN) || (tp->t_state == TCPS_TIME_WAIT)) + && tcp_strict_rfc1948 == 0) +#ifdef __APPLE__ + return random(); +#else + return arc4random(); +#endif - /* (tmp & 0x7fff) ensures a 32768 byte gap between ISS */ - return ((tcp_rndiss_encrypt(tcp_rndiss_cnt++) | tcp_rndiss_msb) <<16) | - (tmp & 0x7fff); + /* Seed if this is the first use, reseed if requested. */ + if ((isn_last_reseed == 0) || + ((tcp_strict_rfc1948 == 0) && (tcp_isn_reseed_interval > 0) && + (((u_int)isn_last_reseed + (u_int)tcp_isn_reseed_interval*hz) + < (u_int)time.tv_sec))) { +#ifdef __APPLE__ + read_random(&isn_secret, sizeof(isn_secret)); +#else + read_random_unlimited(&isn_secret, sizeof(isn_secret)); +#endif + isn_last_reseed = time.tv_sec; + } + + /* Compute the md5 hash and return the ISN. */ + MD5Init(&isn_ctx); + MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->inp_fport, sizeof(u_short)); + MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->inp_lport, sizeof(u_short)); +#if INET6 + if ((tp->t_inpcb->inp_vflag & INP_IPV6) != 0) { + MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->in6p_faddr, + sizeof(struct in6_addr)); + MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->in6p_laddr, + sizeof(struct in6_addr)); + } else +#endif + { + MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->inp_faddr, + sizeof(struct in_addr)); + MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->inp_laddr, + sizeof(struct in_addr)); + } + MD5Update(&isn_ctx, (u_char *) &isn_secret, sizeof(isn_secret)); + MD5Final((u_char *) &md5_buffer, &isn_ctx); + new_isn = (tcp_seq) md5_buffer[0]; + new_isn += time.tv_sec * (ISN_BYTES_PER_SECOND / hz); + return new_isn; } - /* * When a source quench is received, close congestion window * to one segment. We will gradually open it again as we proceed. @@ -1084,6 +1353,22 @@ tcp_quench(inp, errno) tp->snd_cwnd = tp->t_maxseg; } +/* + * When a specific ICMP unreachable message is received and the + * connection state is SYN-SENT, drop the connection. This behavior + * is controlled by the icmp_may_rst sysctl. + */ +void +tcp_drop_syn_sent(inp, errno) + struct inpcb *inp; + int errno; +{ + struct tcpcb *tp = intotcpcb(inp); + + if (tp && tp->t_state == TCPS_SYN_SENT) + tcp_drop(tp, errno); +} + /* * When `need fragmentation' ICMP is received, update our idea of the MSS * based on the new value in the route. Also nudge TCP to send something, @@ -1102,7 +1387,7 @@ tcp_mtudisc(inp, errno) int offered; int mss; #if INET6 - int isipv6 = (tp->t_inpcb->inp_vflag & INP_IPV4) == 0; + int isipv6 = (tp->t_inpcb->inp_vflag & INP_IPV6) != 0; #endif /* INET6 */ if (tp) { @@ -1125,7 +1410,7 @@ tcp_mtudisc(inp, errno) mss = rt->rt_rmx.rmx_mtu - #if INET6 (isipv6 ? - sizeof(struct tcpip6hdr) : + sizeof(struct ip6_hdr) + sizeof(struct tcphdr) : #endif /* INET6 */ sizeof(struct tcpiphdr) #if INET6 @@ -1175,7 +1460,7 @@ tcp_mtudisc(inp, errno) tp->t_maxseg = mss; tcpstat.tcps_mturesent++; - tp->t_rtt = 0; + tp->t_rtttime = 0; tp->snd_nxt = tp->snd_una; tcp_output(tp); } @@ -1202,7 +1487,7 @@ tcp_rtlookup(inp) /* 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); + ro->ro_dst.sa_len = sizeof(struct sockaddr_in); ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = inp->inp_faddr; rtalloc(ro); @@ -1225,9 +1510,12 @@ tcp_rtlookup6(inp) if (rt == NULL || !(rt->rt_flags & RTF_UP)) { /* No route yet, so try to acquire one */ if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { - ro6->ro_dst.sin6_family = AF_INET6; - ro6->ro_dst.sin6_len = sizeof(ro6->ro_dst); - ro6->ro_dst.sin6_addr = inp->in6p_faddr; + struct sockaddr_in6 *dst6; + + dst6 = (struct sockaddr_in6 *)&ro6->ro_dst; + dst6->sin6_family = AF_INET6; + dst6->sin6_len = sizeof(*dst6); + dst6->sin6_addr = inp->in6p_faddr; rtalloc((struct route *)ro6); rt = ro6->ro_rt; } @@ -1239,11 +1527,8 @@ tcp_rtlookup6(inp) #if IPSEC /* compute ESP/AH header size for TCP, including outer IP header. */ size_t -ipsec_hdrsiz_tcp(tp, isipv6) +ipsec_hdrsiz_tcp(tp) struct tcpcb *tp; -#if INET6 - int isipv6; -#endif /* INET6 */ { struct inpcb *inp; struct mbuf *m; @@ -1254,39 +1539,29 @@ ipsec_hdrsiz_tcp(tp, isipv6) #endif /* INET6 */ struct tcphdr *th; - if (!tp || !tp->t_template || !(inp = tp->t_inpcb)) + if ((tp == NULL) || ((inp = tp->t_inpcb) == NULL)) return 0; MGETHDR(m, M_DONTWAIT, MT_DATA); if (!m) return 0; - + #if INET6 - if (isipv6) { + if ((inp->inp_vflag & INP_IPV6) != 0) { ip6 = mtod(m, struct ip6_hdr *); th = (struct tcphdr *)(ip6 + 1); - m->m_pkthdr.len = m->m_len = sizeof(struct tcpip6hdr); - bcopy((caddr_t)&tp->t_template->tt_i6, (caddr_t)ip6, - sizeof(struct ip6_hdr)); - bcopy((caddr_t)&tp->t_template->tt_t, (caddr_t)th, - sizeof(struct tcphdr)); - } else { + m->m_pkthdr.len = m->m_len = + sizeof(struct ip6_hdr) + sizeof(struct tcphdr); + tcp_fillheaders(tp, ip6, th); + hdrsiz = ipsec6_hdrsiz(m, IPSEC_DIR_OUTBOUND, inp); + } else #endif /* INET6 */ + { ip = mtod(m, struct ip *); th = (struct tcphdr *)(ip + 1); m->m_pkthdr.len = m->m_len = sizeof(struct tcpiphdr); - bcopy((caddr_t)&tp->t_template->tt_i, (caddr_t)ip, sizeof(struct ip)); - bcopy((caddr_t)&tp->t_template->tt_t, (caddr_t)th, - sizeof(struct tcphdr)); -#if INET6 - } -#endif /* INET6 */ - -#if INET6 - if (isipv6) - hdrsiz = ipsec6_hdrsiz(m, IPSEC_DIR_OUTBOUND, inp); - else -#endif /* INET6 */ + tcp_fillheaders(tp, ip, th); hdrsiz = ipsec4_hdrsiz(m, IPSEC_DIR_OUTBOUND, inp); + } m_free(m); return hdrsiz; @@ -1302,13 +1577,10 @@ struct rmxp_tao * tcp_gettaocache(inp) struct inpcb *inp; { -#if INET6 - int isipv6 = (inp->inp_vflag & INP_IPV4) == 0; -#endif /* INET6 */ struct rtentry *rt; #if INET6 - if (isipv6) + if ((inp->inp_vflag & INP_IPV6) != 0) rt = tcp_rtlookup6(inp); else #endif /* INET6 */ diff --git a/bsd/netinet/tcp_timer.c b/bsd/netinet/tcp_timer.c index 529e14bb8..e0c303b40 100644 --- a/bsd/netinet/tcp_timer.c +++ b/bsd/netinet/tcp_timer.c @@ -52,16 +52,14 @@ * SUCH DAMAGE. * * @(#)tcp_timer.c 8.2 (Berkeley) 5/24/95 + * $FreeBSD: src/sys/netinet/tcp_timer.c,v 1.34.2.11 2001/08/22 00:59:12 silby Exp $ */ -#if ISFB31 -#include "opt_compat.h" -#include "opt_tcpdebug.h" -#endif #include #include #include +#include #include #include #include @@ -73,9 +71,10 @@ #include #include -#include -#include #include +#if INET6 +#include +#endif #include #include #include @@ -91,37 +90,61 @@ #define DBG_FNC_TCP_FAST NETDBG_CODE(DBG_NETTCP, (5 << 8)) #define DBG_FNC_TCP_SLOW NETDBG_CODE(DBG_NETTCP, (5 << 8) | 1) +static int +sysctl_msec_to_ticks SYSCTL_HANDLER_ARGS +{ + int error, s, tt; -int tcp_keepinit = TCPTV_KEEP_INIT; -SYSCTL_INT(_net_inet_tcp, TCPCTL_KEEPINIT, keepinit, - CTLFLAG_RW, &tcp_keepinit , 0, ""); + tt = *(int *)oidp->oid_arg1; + s = tt * 1000 / hz; -int tcp_keepidle = TCPTV_KEEP_IDLE; -SYSCTL_INT(_net_inet_tcp, TCPCTL_KEEPIDLE, keepidle, - CTLFLAG_RW, &tcp_keepidle , 0, ""); + error = sysctl_handle_int(oidp, &s, 0, req); + if (error || !req->newptr) + return (error); + + tt = s * hz / 1000; + if (tt < 1) + return (EINVAL); + + *(int *)oidp->oid_arg1 = tt; + return (0); +} -static int tcp_keepintvl = TCPTV_KEEPINTVL; -SYSCTL_INT(_net_inet_tcp, TCPCTL_KEEPINTVL, keepintvl, - CTLFLAG_RW, &tcp_keepintvl , 0, ""); +int tcp_keepinit; +SYSCTL_PROC(_net_inet_tcp, TCPCTL_KEEPINIT, keepinit, CTLTYPE_INT|CTLFLAG_RW, + &tcp_keepinit, 0, sysctl_msec_to_ticks, "I", ""); + +int tcp_keepidle; +SYSCTL_PROC(_net_inet_tcp, TCPCTL_KEEPIDLE, keepidle, CTLTYPE_INT|CTLFLAG_RW, + &tcp_keepidle, 0, sysctl_msec_to_ticks, "I", ""); + +int tcp_keepintvl; +SYSCTL_PROC(_net_inet_tcp, TCPCTL_KEEPINTVL, keepintvl, CTLTYPE_INT|CTLFLAG_RW, + &tcp_keepintvl, 0, sysctl_msec_to_ticks, "I", ""); + +int tcp_delacktime; +SYSCTL_PROC(_net_inet_tcp, TCPCTL_DELACKTIME, delacktime, + CTLTYPE_INT|CTLFLAG_RW, &tcp_delacktime, 0, sysctl_msec_to_ticks, "I", + "Time before a delayed ACK is sent"); + +int tcp_msl; +SYSCTL_PROC(_net_inet_tcp, OID_AUTO, msl, CTLTYPE_INT|CTLFLAG_RW, + &tcp_msl, 0, sysctl_msec_to_ticks, "I", "Maximum segment lifetime"); static int always_keepalive = 0; -SYSCTL_INT(_net_inet_tcp, OID_AUTO, always_keepalive, - CTLFLAG_RW, &always_keepalive , 0, ""); +SYSCTL_INT(_net_inet_tcp, OID_AUTO, always_keepalive, CTLFLAG_RW, + &always_keepalive , 0, "Assume SO_KEEPALIVE on all TCP connections"); static int tcp_keepcnt = TCPTV_KEEPCNT; /* max idle probes */ -static int tcp_maxpersistidle = TCPTV_KEEP_IDLE; +int tcp_maxpersistidle; /* max idle time in persist */ int tcp_maxidle; - - struct inpcbhead time_wait_slots[N_TIME_WAIT_SLOTS]; int cur_tw_slot = 0; u_long *delack_bitmask; -u_long current_active_connections = 0; -u_long last_active_conn_count = 0; void add_to_time_wait(tp) @@ -134,7 +157,7 @@ void add_to_time_wait(tp) if (tp->t_timer[TCPT_2MSL] == 0) tp->t_timer[TCPT_2MSL] = 1; - tp->t_idle += tp->t_timer[TCPT_2MSL] & (N_TIME_WAIT_SLOTS - 1); + tp->t_rcvtime += tp->t_timer[TCPT_2MSL] & (N_TIME_WAIT_SLOTS - 1); tw_slot = (tp->t_timer[TCPT_2MSL] & (N_TIME_WAIT_SLOTS - 1)) + cur_tw_slot; if (tw_slot >= N_TIME_WAIT_SLOTS) tw_slot -= N_TIME_WAIT_SLOTS; @@ -170,9 +193,7 @@ tcp_fasttimo() if (!tcp_delack_enabled) return; - if ((current_active_connections > DELACK_BITMASK_THRESH) && - (last_active_conn_count > DELACK_BITMASK_THRESH)) { - for (i=0; i < (tcbinfo.hashsize / 32); i++) { + for (i=0; i < (tcbinfo.hashsize / 32); i++) { if (delack_bitmask[i]) { temp_mask = 1; for (j=0; j < 32; j++) { @@ -193,22 +214,7 @@ tcp_fasttimo() delack_bitmask[i] = 0; } elem_base += 32; - } } - else - { - for (inp = tcb.lh_first; inp != NULL; inp = inp->inp_list.le_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); - } - } - } - - last_active_conn_count = current_active_connections; KERNEL_DEBUG(DBG_FNC_TCP_FAST | DBG_FUNC_END, delack_checked,tcpstat.tcps_delack,0,0,0); splx(s); @@ -251,6 +257,13 @@ tcp_slowtimo() tp = intotcpcb(ip); if (tp == 0 || tp->t_state == TCPS_LISTEN) continue; + /* + * Bogus state when port owned by SharedIP with loopback as the + * only configured interface: BlueBox does not filters loopback + */ + if (tp->t_state == TCP_NSTATES) + continue; + for (i = 0; i < TCPT_NTIMERS; i++) { if (tp->t_timer[i] && --tp->t_timer[i] == 0) { #if TCPDEBUG @@ -269,10 +282,10 @@ tcp_slowtimo() #endif } } - tp->t_idle++; - tp->t_duration++; - if (tp->t_rtt) - tp->t_rtt++; + tp->t_rcvtime++; + tp->t_starttime++; + if (tp->t_rtttime) + tp->t_rtttime++; tpgone: ; } @@ -295,7 +308,7 @@ tpgone: tp = intotcpcb(ip); if (tp->t_timer[TCPT_2MSL] >= N_TIME_WAIT_SLOTS) { tp->t_timer[TCPT_2MSL] -= N_TIME_WAIT_SLOTS; - tp->t_idle += N_TIME_WAIT_SLOTS; + tp->t_rcvtime += N_TIME_WAIT_SLOTS; } else tp->t_timer[TCPT_2MSL] = 0; @@ -306,12 +319,6 @@ tpgone: if (++cur_tw_slot >= N_TIME_WAIT_SLOTS) cur_tw_slot = 0; - -#if TCP_COMPAT_42 - tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */ - if ((int)tcp_iss < 0) - tcp_iss = TCP_ISSINCR; /* XXX */ -#endif tcp_now++; /* for timestamps */ splx(s); KERNEL_DEBUG(DBG_FNC_TCP_SLOW | DBG_FUNC_END, tws_checked, cur_tw_slot,0,0,0); @@ -330,6 +337,9 @@ tcp_canceltimers(tp) tp->t_timer[i] = 0; } +int tcp_syn_backoff[TCP_MAXRXTSHIFT + 1] = + { 1, 1, 1, 1, 1, 2, 4, 8, 16, 32, 64, 64, 64 }; + int tcp_backoff[TCP_MAXRXTSHIFT + 1] = { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; @@ -345,10 +355,13 @@ tcp_timers(tp, timer) { register int rexmt; struct socket *so_tmp; + struct tcptemp *t_template; + #if INET6 int isipv6 = (tp->t_inpcb->inp_vflag & INP_IPV4) == 0; #endif /* INET6 */ + switch (timer) { /* @@ -359,7 +372,7 @@ tcp_timers(tp, timer) */ case TCPT_2MSL: if (tp->t_state != TCPS_TIME_WAIT && - tp->t_idle <= tcp_maxidle) { + tp->t_rcvtime <= tcp_maxidle) { tp->t_timer[TCPT_2MSL] = tcp_keepintvl; add_to_time_wait(tp); } @@ -382,11 +395,39 @@ tcp_timers(tp, timer) postevent(so_tmp, 0, EV_TIMEOUT); break; } + + if (tp->t_rxtshift == 1) { + /* + * first retransmit; record ssthresh and cwnd so they can + * be recovered if this turns out to be a "bad" retransmit. + * A retransmit is considered "bad" if an ACK for this + * segment is received within RTT/2 interval; the assumption + * here is that the ACK was already in flight. See + * "On Estimating End-to-End Network Path Properties" by + * Allman and Paxson for more details. + */ + tp->snd_cwnd_prev = tp->snd_cwnd; + tp->snd_ssthresh_prev = tp->snd_ssthresh; + tp->t_badrxtwin = tcp_now + (tp->t_srtt >> (TCP_RTT_SHIFT + 1)); + } tcpstat.tcps_rexmttimeo++; - rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift]; + if (tp->t_state == TCPS_SYN_SENT) + rexmt = TCP_REXMTVAL(tp) * tcp_syn_backoff[tp->t_rxtshift]; + else + rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift]; TCPT_RANGESET(tp->t_rxtcur, rexmt, - tp->t_rttmin, TCPTV_REXMTMAX); + tp->t_rttmin, TCPTV_REXMTMAX); tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; + + /* + * Disable rfc1323 and rfc1644 if we havn't got any response to + * our third SYN to work-around some broken terminal servers + * (most of which have hopefully been retired) that have bad VJ + * header compression code which trashes TCP segments containing + * unknown-to-them TCP options. + */ + if ((tp->t_state == TCPS_SYN_SENT) && (tp->t_rxtshift == 3)) + tp->t_flags &= ~(TF_REQ_SCALE|TF_REQ_TSTMP|TF_REQ_CC); /* * If losing, let the lower level know and try for * a better route. Also, if we backed off this far, @@ -406,6 +447,11 @@ tcp_timers(tp, timer) tp->t_srtt = 0; } tp->snd_nxt = tp->snd_una; + /* + * Note: We overload snd_recover to function also as the + * snd_last variable described in RFC 2582 + */ + tp->snd_recover = tp->snd_max; /* * Force a segment to be sent. */ @@ -413,7 +459,7 @@ tcp_timers(tp, timer) /* * If timing a segment in this window, stop the timer. */ - tp->t_rtt = 0; + tp->t_rtttime = 0; /* * Close the congestion window down to one segment * (we'll open it by one segment for each ack we get). @@ -463,8 +509,8 @@ tcp_timers(tp, timer) * backoff that we would use if retransmitting. */ if (tp->t_rxtshift == TCP_MAXRXTSHIFT && - (tp->t_idle >= tcp_maxpersistidle || - tp->t_idle >= TCP_REXMTVAL(tp) * tcp_totbackoff)) { + (tp->t_rcvtime >= tcp_maxpersistidle || + tp->t_rcvtime >= TCP_REXMTVAL(tp) * tcp_totbackoff)) { tcpstat.tcps_persistdrop++; so_tmp = tp->t_inpcb->inp_socket; tp = tcp_drop(tp, ETIMEDOUT); @@ -488,7 +534,7 @@ tcp_timers(tp, timer) if ((always_keepalive || tp->t_inpcb->inp_socket->so_options & SO_KEEPALIVE) && tp->t_state <= TCPS_CLOSING) { - if (tp->t_idle >= tcp_keepidle + tcp_maxidle) + if (tp->t_rcvtime >= tcp_keepidle + tcp_maxidle) goto dropit; /* * Send a packet designed to force a response @@ -503,41 +549,23 @@ tcp_timers(tp, timer) * correspondent TCP to respond. */ tcpstat.tcps_keepprobe++; -#if TCP_COMPAT_42 - /* - * The keepalive packet must have nonzero length - * to get a 4.2 host to respond. - */ -#if INET6 - if (isipv6) - tcp_respond(tp, (void *)&tp->t_template->tt_i6, - &tp->t_template->tt_t, - (struct mbuf *)NULL, - tp->rcv_nxt - 1, tp->snd_una - 1, - 0, isipv6); - else -#endif /* INET6 */ - tcp_respond(tp, (void *)&tp->t_template->tt_i, - &tp->t_template->tt_t, (struct mbuf *)NULL, - tp->rcv_nxt - 1, tp->snd_una - 1, 0, - isipv6); -#else -#if INET6 - if (isipv6) - tcp_respond(tp, (void *)&tp->t_template->tt_i6, - &tp->t_template->tt_t, - (struct mbuf *)NULL, tp->rcv_nxt, - tp->snd_una - 1, 0, isipv6); - else -#endif /* INET6 */ - tcp_respond(tp, (void *)&tp->t_template->tt_i, - &tp->t_template->tt_t, (struct mbuf *)NULL, - tp->rcv_nxt, tp->snd_una - 1, 0, isipv6); -#endif + t_template = tcp_maketemplate(tp); + if (t_template) { + tcp_respond(tp, t_template->tt_ipgen, + &t_template->tt_t, (struct mbuf *)NULL, + tp->rcv_nxt, tp->snd_una - 1, 0); + (void) m_free(dtom(t_template)); + } tp->t_timer[TCPT_KEEP] = tcp_keepintvl; } else tp->t_timer[TCPT_KEEP] = tcp_keepidle; break; + +#if TCPDEBUG + if (tp->t_inpcb->inp_socket->so_options & SO_DEBUG) + tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, + PRU_SLOWTIMO); +#endif dropit: tcpstat.tcps_keepdrops++; so_tmp = tp->t_inpcb->inp_socket; diff --git a/bsd/netinet/tcp_timer.h b/bsd/netinet/tcp_timer.h index 03d29b83c..a8f55353c 100644 --- a/bsd/netinet/tcp_timer.h +++ b/bsd/netinet/tcp_timer.h @@ -52,10 +52,12 @@ * SUCH DAMAGE. * * @(#)tcp_timer.h 8.1 (Berkeley) 6/10/93 + * $FreeBSD: src/sys/netinet/tcp_timer.h,v 1.18 1999/12/29 04:41:03 peter Exp $ */ #ifndef _NETINET_TCP_TIMER_H_ #define _NETINET_TCP_TIMER_H_ +#include /* * Definitions of the TCP timers. These timers are counted @@ -107,6 +109,7 @@ /* * Time constants. */ +#ifdef __APPLE_API_PRIVATE #define TCPTV_MSL ( 30*PR_SLOWHZ) /* max seg lifetime (hah!) */ #define TCPTV_SRTTBASE 0 /* base roundtrip time; if 0, no idea yet */ @@ -130,6 +133,8 @@ #define TCP_MAXRXTSHIFT 12 /* maximum retransmits */ +#define TCPTV_DELACK PR_FASTHZ /* 125ms timeout */ + #ifdef TCPTIMERS static char *tcptimers[] = { "REXMT", "PERSIST", "KEEP", "2MSL" }; @@ -138,20 +143,32 @@ static char *tcptimers[] = /* * Force a time value to be in a certain range. */ -#define TCPT_RANGESET(tv, value, tvmin, tvmax) { \ +#define TCPT_RANGESET(tv, value, tvmin, tvmax) do { \ (tv) = (value); \ if ((u_long)(tv) < (u_long)(tvmin)) \ (tv) = (tvmin); \ else if ((u_long)(tv) > (u_long)(tvmax)) \ (tv) = (tvmax); \ -} +} while(0) #ifdef KERNEL extern int tcp_keepinit; /* time to establish connection */ 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_delacktime; /* time before sending a delayed ACK */ +extern int tcp_maxpersistidle; +extern int tcp_msl; extern int tcp_ttl; /* time to live for TCP segs */ extern int tcp_backoff[]; -#endif -#endif +void tcp_timer_2msl __P((void *xtp)); +void tcp_timer_keep __P((void *xtp)); +void tcp_timer_persist __P((void *xtp)); +void tcp_timer_rexmt __P((void *xtp)); +void tcp_timer_delack __P((void *xtp)); + +#endif /* KERNEL */ +#endif /* __APPLE_API_PRIVATE */ + +#endif /* !_NETINET_TCP_TIMER_H_ */ diff --git a/bsd/netinet/tcp_usrreq.c b/bsd/netinet/tcp_usrreq.c index 2dd2747fe..d68e6f45d 100644 --- a/bsd/netinet/tcp_usrreq.c +++ b/bsd/netinet/tcp_usrreq.c @@ -52,11 +52,9 @@ * SUCH DAMAGE. * * From: @(#)tcp_usrreq.c 8.2 (Berkeley) 1/3/94 + * $FreeBSD: src/sys/netinet/tcp_usrreq.c,v 1.51.2.9 2001/08/22 00:59:12 silby Exp $ */ -#if ISFB31 -#include "opt_tcpdebug.h" -#endif #include #include @@ -75,14 +73,16 @@ #include #include -#include +#if INET6 +#include +#endif #include +#if INET6 +#include +#endif #include #include #if INET6 -#include -#include -#include #include #endif #include @@ -111,15 +111,16 @@ static int tcp_connect __P((struct tcpcb *, struct sockaddr *, static int tcp6_connect __P((struct tcpcb *, struct sockaddr *, struct proc *)); #endif /* INET6 */ -static struct tcpcb * tcp_disconnect __P((struct tcpcb *)); +static struct tcpcb * + tcp_disconnect __P((struct tcpcb *)); static struct tcpcb * tcp_usrclosed __P((struct tcpcb *)); #if TCPDEBUG -#define TCPDEBUG0 int ostate +#define TCPDEBUG0 int ostate = 0 #define TCPDEBUG1() ostate = tp ? tp->t_state : 0 #define TCPDEBUG2(req) if (tp && (so->so_options & SO_DEBUG)) \ - tcp_trace(TA_USER, ostate, tp, 0, req) + tcp_trace(TA_USER, ostate, tp, 0, 0, req) #else #define TCPDEBUG0 #define TCPDEBUG1() @@ -258,8 +259,7 @@ tcp6_usr_bind(struct socket *so, struct sockaddr *nam, struct proc *p) } inp->inp_vflag &= ~INP_IPV4; inp->inp_vflag |= INP_IPV6; - if (ip6_mapped_addr_on && (inp->inp_flags & IN6P_BINDV6ONLY) == NULL) { - + if (ip6_mapped_addr_on && (inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) { if (IN6_IS_ADDR_UNSPECIFIED(&sin6p->sin6_addr)) inp->inp_vflag |= INP_IPV4; else if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) { @@ -273,6 +273,8 @@ tcp6_usr_bind(struct socket *so, struct sockaddr *nam, struct proc *p) } } error = in6_pcbbind(inp, nam, p); + if (error) + goto out; COMMON_END(PRU_BIND); } #endif /* INET6 */ @@ -309,7 +311,7 @@ tcp6_usr_listen(struct socket *so, struct proc *p) if (inp->inp_lport == 0) { inp->inp_vflag &= ~INP_IPV4; if (ip6_mapped_addr_on && - (inp->inp_flags & IN6P_BINDV6ONLY) == NULL) + (inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) inp->inp_vflag |= INP_IPV4; error = in6_pcbbind(inp, (struct sockaddr *)0, p); } @@ -347,6 +349,10 @@ tcp_usr_connect(struct socket *so, struct sockaddr *nam, struct proc *p) goto out; } +#ifndef __APPLE__ + prison_remote_ip(p, 0, &sinp->sin_addr.s_addr); +#endif + if ((error = tcp_connect(tp, nam, p)) != 0) goto out; error = tcp_output(tp); @@ -374,12 +380,14 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct proc *p) error = EAFNOSUPPORT; goto out; } - inp->inp_vflag &= ~INP_IPV4; - inp->inp_vflag |= INP_IPV6; - if (ip6_mapped_addr_on && - IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) { + + if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) { struct sockaddr_in sin; + if (!ip6_mapped_addr_on || + (inp->inp_flags & IN6P_IPV6_V6ONLY)) + return(EINVAL); + in6_sin6_2_sin(&sin, sin6p); inp->inp_vflag |= INP_IPV4; inp->inp_vflag &= ~INP_IPV6; @@ -388,13 +396,13 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct proc *p) error = tcp_output(tp); goto out; } + inp->inp_vflag &= ~INP_IPV4; + inp->inp_vflag |= INP_IPV6; if ((error = tcp6_connect(tp, nam, p)) != 0) goto out; error = tcp_output(tp); if (error) goto out; - if (ip6_mapped_addr_on) - inp->inp_vflag |= INP_IPV6; COMMON_END(PRU_CONNECT); } #endif /* INET6 */ @@ -437,9 +445,19 @@ tcp_usr_accept(struct socket *so, struct sockaddr **nam) int s = splnet(); int error = 0; struct inpcb *inp = sotoinpcb(so); - struct tcpcb *tp; + struct tcpcb *tp = NULL; + TCPDEBUG0; - COMMON_START(); + if (so->so_state & SS_ISDISCONNECTED) { + error = ECONNABORTED; + goto out; + } + if (inp == 0) { + splx(s); + return (EINVAL); + } + tp = intotcpcb(inp); + TCPDEBUG1(); in_setpeeraddr(so, nam); COMMON_END(PRU_ACCEPT); } @@ -451,14 +469,23 @@ tcp6_usr_accept(struct socket *so, struct sockaddr **nam) int s = splnet(); int error = 0; struct inpcb *inp = sotoinpcb(so); - struct tcpcb *tp; + struct tcpcb *tp = NULL; + TCPDEBUG0; - COMMON_START(); + if (so->so_state & SS_ISDISCONNECTED) { + error = ECONNABORTED; + goto out; + } + if (inp == 0) { + splx(s); + return (EINVAL); + } + tp = intotcpcb(inp); + TCPDEBUG1(); in6_mapped_peeraddr(so, nam); COMMON_END(PRU_ACCEPT); } #endif /* INET6 */ - /* * Mark the connection as being incapable of further output. */ @@ -502,10 +529,13 @@ tcp_usr_rcvd(struct socket *so, int flags) /* * Do a send by putting data in output queue and updating urgent - * marker if URG set. Possibly send more data. + * marker if URG set. Possibly send more data. Unlike the other + * pru_*() routines, the mbuf chains are our responsibility. We + * must either enqueue them or free them. The other pru_* routines + * generally are caller-frees. */ static int -tcp_usr_send(struct socket *so, int flags, struct mbuf *m, +tcp_usr_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, struct mbuf *control, struct proc *p) { int s = splnet(); @@ -514,21 +544,40 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m, struct tcpcb *tp; #if INET6 int isipv6; -#endif /* INET6 */ +#endif + TCPDEBUG0; - COMMON_START(); - if (control && control->m_len) { - m_freem(control); /* XXX shouldn't caller do this??? */ + if (inp == NULL) { + /* + * OOPS! we lost a race, the TCP session got reset after + * we checked SS_CANTSENDMORE, eg: while doing uiomove or a + * network interrupt in the non-splnet() section of sosend(). + */ if (m) m_freem(m); - error = EINVAL; + if (control) + m_freem(control); + error = ECONNRESET; /* XXX EPIPE? */ + tp = NULL; + TCPDEBUG1(); goto out; } - #if INET6 isipv6 = nam && nam->sa_family == AF_INET6; #endif /* INET6 */ - + tp = intotcpcb(inp); + TCPDEBUG1(); + if (control) { + /* TCP doesn't do control messages (rights, creds, etc) */ + if (control->m_len) { + m_freem(control); + if (m) + m_freem(m); + error = EINVAL; + goto out; + } + m_freem(control); /* empty control, just free it */ + } if(!(flags & PRUS_OOB)) { sbappend(&so->so_snd, m); if (nam && tp->t_state < TCPS_SYN_SENT) { @@ -547,7 +596,7 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m, if (error) goto out; tp->snd_wnd = TTCP_CLIENT_SND_WND; - tcp_mss(tp, -1, isipv6); + tcp_mss(tp, -1); } if (flags & PRUS_EOF) { @@ -596,7 +645,7 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m, if (error) goto out; tp->snd_wnd = TTCP_CLIENT_SND_WND; - tcp_mss(tp, -1, isipv6); + tcp_mss(tp, -1); } tp->snd_up = tp->snd_una + so->so_snd.sb_cc; tp->t_force = 1; @@ -722,7 +771,7 @@ tcp_connect(tp, nam, p) if (oinp) { if (oinp != inp && (otp = intotcpcb(oinp)) != NULL && otp->t_state == TCPS_TIME_WAIT && - otp->t_duration < TCPTV_MSL && + otp->t_starttime < tcp_msl && (otp->t_flags & TF_RCVD_CC)) otp = tcp_close(otp); else @@ -738,12 +787,6 @@ tcp_connect(tp, nam, p) inp->inp_fport = sin->sin_port; in_pcbrehash(inp); - tp->t_template = tcp_template(tp); - if (tp->t_template == 0) { - in_pcbdisconnect(inp); - return ENOBUFS; - } - /* Compute window scaling to request. */ while (tp->request_r_scale < TCP_MAX_WINSHIFT && (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) @@ -753,13 +796,7 @@ tcp_connect(tp, nam, p) tcpstat.tcps_connattempt++; tp->t_state = TCPS_SYN_SENT; tp->t_timer[TCPT_KEEP] = tcp_keepinit; -#ifdef TCP_COMPAT_42 - tp->iss = tcp_iss; - tcp_iss =+ TCP_ISSINCR/2; -#else /* TCP_COMPAT_42 */ - tp->iss = tcp_rndiss_next(); -#endif /* !TCP_COMPAT_42 */ - + tp->iss = tcp_new_isn(tp); tcp_sendseqinit(tp); /* @@ -822,7 +859,7 @@ tcp6_connect(tp, nam, p) if (oinp) { if (oinp != inp && (otp = intotcpcb(oinp)) != NULL && otp->t_state == TCPS_TIME_WAIT && - otp->t_duration < TCPTV_MSL && + otp->t_starttime < tcp_msl && (otp->t_flags & TF_RCVD_CC)) otp = tcp_close(otp); else @@ -832,20 +869,10 @@ tcp6_connect(tp, nam, p) inp->in6p_laddr = *addr6; inp->in6p_faddr = sin6->sin6_addr; inp->inp_fport = sin6->sin6_port; - /* - * xxx kazu flowlabel is necessary for connect? - * but if this line is missing, the garbage value remains. - */ - inp->in6p_flowinfo = sin6->sin6_flowinfo; - + if ((sin6->sin6_flowinfo & IPV6_FLOWINFO_MASK) != NULL) + inp->in6p_flowinfo = sin6->sin6_flowinfo; in_pcbrehash(inp); - tp->t_template = tcp_template(tp); - if (tp->t_template == 0) { - in6_pcbdisconnect(inp); - return ENOBUFS; - } - /* Compute window scaling to request. */ while (tp->request_r_scale < TCP_MAX_WINSHIFT && (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) @@ -855,11 +882,7 @@ tcp6_connect(tp, nam, p) tcpstat.tcps_connattempt++; tp->t_state = TCPS_SYN_SENT; tp->t_timer[TCPT_KEEP] = tcp_keepinit; -#ifdef TCP_COMPAT_42 - tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; -#else - tp->iss = tcp_rndiss_next(); -#endif /* TCP_COMPAT_42 */ + tp->iss = tcp_new_isn(tp); tcp_sendseqinit(tp); /* @@ -1005,11 +1028,11 @@ tcp_ctloutput(so, sopt) * be set by the route). */ u_long tcp_sendspace = 1024*16; -SYSCTL_INT(_net_inet_tcp, TCPCTL_SENDSPACE, sendspace, - CTLFLAG_RW, &tcp_sendspace , 0, ""); +SYSCTL_INT(_net_inet_tcp, TCPCTL_SENDSPACE, sendspace, CTLFLAG_RW, + &tcp_sendspace , 0, "Maximum outgoing TCP datagram size"); u_long tcp_recvspace = 1024*16; -SYSCTL_INT(_net_inet_tcp, TCPCTL_RECVSPACE, recvspace, - CTLFLAG_RW, &tcp_recvspace , 0, ""); +SYSCTL_INT(_net_inet_tcp, TCPCTL_RECVSPACE, recvspace, CTLFLAG_RW, + &tcp_recvspace , 0, "Maximum incoming TCP datagram size"); /* * Attach TCP protocol to socket, allocating @@ -1025,8 +1048,8 @@ tcp_attach(so, p) struct inpcb *inp; int error; #if INET6 - int isipv6 = INP_CHECK_SOCKAF(so, AF_INET) == NULL; -#endif /* INET6 */ + int isipv6 = INP_CHECK_SOCKAF(so, AF_INET6) != NULL; +#endif if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { error = soreserve(so, tcp_sendspace, tcp_recvspace); @@ -1037,18 +1060,6 @@ tcp_attach(so, p) if (error) return (error); inp = sotoinpcb(so); -#if IPSEC - error = ipsec_init_policy(so, &inp->inp_sp); - if (error) { -#if INET6 - if (isipv6) - in6_pcbdetach(inp); - else -#endif /* INET6 */ - in_pcbdetach(inp); - return (error); - } -#endif /*IPSEC*/ #if INET6 if (isipv6) { inp->inp_vflag |= INP_IPV6; diff --git a/bsd/netinet/tcp_var.h b/bsd/netinet/tcp_var.h index 85e975b06..5c1742366 100644 --- a/bsd/netinet/tcp_var.h +++ b/bsd/netinet/tcp_var.h @@ -52,61 +52,56 @@ * SUCH DAMAGE. * * @(#)tcp_var.h 8.4 (Berkeley) 5/24/95 + * $FreeBSD: src/sys/netinet/tcp_var.h,v 1.56.2.8 2001/08/22 00:59:13 silby Exp $ */ #ifndef _NETINET_TCP_VAR_H_ #define _NETINET_TCP_VAR_H_ +#include +#include +#ifdef __APPLE_API_PRIVATE + #define N_TIME_WAIT_SLOTS 128 /* must be power of 2 */ /* - * Ip (reassembly or sequence) queue structures. - * - * XXX -- The following explains why the ipqe_m field is here, for TCP's use: - * 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. + * Kernel variables for tcp. */ -LIST_HEAD(ipqehead, ipqent); -struct ipqent { - LIST_ENTRY(ipqent) ipqe_q; - union { - struct ip *_ip; -#if INET6 - struct ipv6 *_ip6; -#endif - struct tcpiphdr *_tcp; - } _ipqe_u1; - struct mbuf *ipqe_m; /* mbuf contains packet */ - u_int8_t ipqe_mff; /* for IP fragmentation */ + +/* TCP segment queue entry */ +struct tseg_qent { + LIST_ENTRY(tseg_qent) tqe_q; + int tqe_len; /* TCP segment data length */ + struct tcphdr *tqe_th; /* a pointer to tcp header */ + struct mbuf *tqe_m; /* mbuf contains packet */ }; -#define ipqe_ip _ipqe_u1._ip -#if INET6 -#define ipqe_ip6 _ipqe_u1._ip6 +LIST_HEAD(tsegqe_head, tseg_qent); +#ifdef MALLOC_DECLARE +MALLOC_DECLARE(M_TSEGQ); #endif -#define ipqe_tcp _ipqe_u1._tcp + +struct tcptemp { + u_char tt_ipgen[40]; /* the size must be of max ip header, now IPv6 */ + struct tcphdr tt_t; +}; + #define tcp6cb tcpcb /* for KAME src sync over BSD*'s */ +#ifdef __APPLE__ #define TCP_DELACK_BITSET(hash_elem)\ delack_bitmask[((hash_elem) >> 5)] |= 1 << ((hash_elem) & 0x1F) #define DELACK_BITMASK_ON 1 #define DELACK_BITMASK_THRESH 300 - -/* - * Kernel variables for tcp. - */ +#endif /* * Tcp control block, one per tcp; fields: * Organized for 16 byte cacheline efficiency. */ struct tcpcb { - struct ipqehead segq; /* sequencing queue */ + struct tsegqe_head t_segq; int t_dupacks; /* consecutive dup acks recd */ - struct tcptemp *t_template; /* skeletal packet for transmit */ + struct tcptemp *unused; /* unused now: was t_template */ int t_timer[TCPT_NTIMERS]; /* tcp timers */ @@ -130,6 +125,9 @@ struct tcpcb { #define TF_RCVD_CC 0x04000 /* a CC was received in SYN */ #define TF_SENDCCNEW 0x08000 /* send CCnew instead of CC in SYN */ #define TF_MORETOCOME 0x10000 /* More data to be appended to sock */ +#define TF_LQ_OVERFLOW 0x20000 /* listen queue overflow */ +#define TF_RXWIN0SENT 0x40000 /* sent a receiver win 0 in response */ + int t_force; /* 1 if forcing out a byte */ tcp_seq snd_una; /* send unacknowledged */ @@ -157,12 +155,12 @@ struct tcpcb { */ u_int t_maxopd; /* mss plus options */ - u_int t_idle; /* inactivity time */ - u_long t_duration; /* connection duration */ - int t_rtt; /* round trip time */ + u_long t_rcvtime; /* inactivity time */ + u_long t_starttime; /* time connection was established */ + int t_rtttime; /* round trip time */ tcp_seq t_rtseq; /* sequence number being timed */ - int t_rxtcur; /* current retransmit value */ + int t_rxtcur; /* current retransmit value (ticks) */ u_int t_maxseg; /* maximum segment size */ int t_srtt; /* smoothed round-trip time */ int t_rttvar; /* variance in round-trip time */ @@ -190,7 +188,11 @@ struct tcpcb { /* RFC 1644 variables */ tcp_cc cc_send; /* send connection count */ tcp_cc cc_recv; /* receive connection count */ - u_long reserved[4]; + tcp_seq snd_recover; /* for use in fast recovery */ +/* experimental */ + u_long snd_cwnd_prev; /* cwnd prior to retransmit */ + u_long snd_ssthresh_prev; /* ssthresh prior to retransmit */ + u_long t_badrxtwin; /* window for retransmit recovery */ }; /* @@ -209,7 +211,7 @@ struct tcpopt { u_long to_tsecr; tcp_cc to_cc; /* holds CC or CCnew */ tcp_cc to_ccecho; - u_short to_maxseg; + u_short reserved; /* unused now: was to_maxseg */ }; /* @@ -266,7 +268,9 @@ struct rmxp_tao { #define TCP_REXMTVAL(tp) \ max((tp)->t_rttmin, (((tp)->t_srtt >> (TCP_RTT_SHIFT - TCP_DELTA_SHIFT)) \ + (tp)->t_rttvar) >> TCP_DELTA_SHIFT) +#endif /* __APPLE_API_PRIVATE */ +#ifdef __APPLE_API_UNSTABLE /* * TCP statistics. * Many of these should be kept per connection, @@ -337,6 +341,7 @@ struct tcpstat { u_long tcps_mturesent; /* resends due to MTU discovery */ u_long tcps_listendrop; /* listen queue overflows */ }; +#endif /* __APPLE_API_UNSTABLE */ /* * TCB structure exported to user-land via sysctl(3). @@ -365,10 +370,11 @@ struct xtcpcb { #define TCPCTL_KEEPINTVL 7 /* interval to send keepalives */ #define TCPCTL_SENDSPACE 8 /* send buffer space */ #define TCPCTL_RECVSPACE 9 /* receive buffer space */ -#define TCPCTL_KEEPINIT 10 /* receive buffer space */ +#define TCPCTL_KEEPINIT 10 /* timeout for establishing syn */ #define TCPCTL_PCBLIST 11 /* list of all outstanding PCBs */ -#define TCPCTL_V6MSSDFLT 12 /* MSS default for IPv6 */ -#define TCPCTL_MAXID 13 +#define TCPCTL_DELACKTIME 12 /* time before sending delayed ACK */ +#define TCPCTL_V6MSSDFLT 13 /* MSS default for IPv6 */ +#define TCPCTL_MAXID 14 #define TCPCTL_NAMES { \ { 0, 0 }, \ @@ -383,9 +389,11 @@ struct xtcpcb { { "recvspace", CTLTYPE_INT }, \ { "keepinit", CTLTYPE_INT }, \ { "pcblist", CTLTYPE_STRUCT }, \ + { "delacktime", CTLTYPE_INT }, \ { "v6mssdflt", CTLTYPE_INT }, \ } +#ifdef __APPLE_API_PRIVATE #ifdef KERNEL #ifdef SYSCTL_DECL SYSCTL_DECL(_net_inet_tcp); @@ -395,18 +403,20 @@ extern struct inpcbhead tcb; /* head of queue of active tcpcb's */ extern struct inpcbinfo tcbinfo; extern struct tcpstat tcpstat; /* tcp statistics */ extern int tcp_mssdflt; /* XXX */ -extern int tcp_v6mssdflt; /* XXX */ -extern u_long tcp_now; /* for RFC 1323 timestamps */ extern int tcp_delack_enabled; +extern int tcp_do_newreno; +extern int ss_fltsz; +extern int ss_fltsz_local; +#ifdef __APPLE__ +extern u_long tcp_now; /* for RFC 1323 timestamps */ +extern int tcp_delack_enabled; +#endif + void tcp_canceltimers __P((struct tcpcb *)); struct tcpcb * tcp_close __P((struct tcpcb *)); void tcp_ctlinput __P((int, struct sockaddr *, void *)); -#if INET6 -struct ip6_hdr; -void tcp6_ctlinput __P((int, struct sockaddr *,void *)); -#endif int tcp_ctloutput __P((struct socket *, struct sockopt *)); struct tcpcb * tcp_drop __P((struct tcpcb *, int)); @@ -414,79 +424,36 @@ void tcp_drain __P((void)); void tcp_fasttimo __P((void)); struct rmxp_tao * tcp_gettaocache __P((struct inpcb *)); -void tcp_init __P((void)); -#if INET6 -void tcp6_init __P((void)); -int tcp6_input __P((struct mbuf **, int *, int)); -#endif /* INET6 */ +void tcp_init __P((void)); void tcp_input __P((struct mbuf *, int)); -#if INET6 -void tcp_mss __P((struct tcpcb *, int, int)); -int tcp_mssopt __P((struct tcpcb *, int)); -#else /* INET6 */ void tcp_mss __P((struct tcpcb *, int)); int tcp_mssopt __P((struct tcpcb *)); -#endif /* INET6 */ - +void tcp_drop_syn_sent __P((struct inpcb *, int)); void tcp_mtudisc __P((struct inpcb *, int)); struct tcpcb * tcp_newtcpcb __P((struct inpcb *)); int tcp_output __P((struct tcpcb *)); void tcp_quench __P((struct inpcb *, int)); -#if INET6 -void tcp_respond __P((struct tcpcb *, void *, struct tcphdr *, - struct mbuf *, tcp_seq, tcp_seq, int, int)); -#else /* INET6 */ -void tcp_respond __P((struct tcpcb *, void *, struct tcphdr *, - struct mbuf *, tcp_seq, tcp_seq, int)); -#endif /* INET6 */ - +void tcp_respond __P((struct tcpcb *, void *, + struct tcphdr *, struct mbuf *, tcp_seq, tcp_seq, int)); struct rtentry * tcp_rtlookup __P((struct inpcb *)); -#if INET6 -struct rtentry * - tcp_rtlookup6 __P((struct inpcb *)); -#endif /* INET6 */ void tcp_setpersist __P((struct tcpcb *)); void tcp_slowtimo __P((void)); struct tcptemp * - tcp_template __P((struct tcpcb *)); + tcp_maketemplate __P((struct tcpcb *)); +void tcp_fillheaders __P((struct tcpcb *, void *, void *)); struct tcpcb * tcp_timers __P((struct tcpcb *, int)); -#if INET6 -void tcp_trace __P((int, int, struct tcpcb *, void *, struct tcphdr *, +void tcp_trace __P((int, int, struct tcpcb *, void *, struct tcphdr *, int)); -#else -void tcp_trace __P((int, int, struct tcpcb *, struct ip *, - struct tcphdr *, int)); -#endif - -#if INET6 -int tcp_reass __P((struct tcpcb *, struct tcphdr *, int, - struct mbuf *, int)); -#else /* INET6 */ -int tcp_reass __P((struct tcpcb *, struct tcphdr *, int, struct mbuf *)); -/* suppress INET6 only args */ -#define tcp_reass(x, y, z, t, i) tcp_reass(x, y, z, t) -#define tcp_mss(x, y, i) tcp_mss(x, y) -#define tcp_mssopt(x, i) tcp_mssopt(x) -#define tcp_respond(x, y, z, m, s1, s2, f, i) tcp_respond(x, y, z, m, s1, \ - s2, f) - -#endif /* INET6 */ extern struct pr_usrreqs tcp_usrreqs; -#if INET6 -extern struct pr_usrreqs tcp6_usrreqs; -#endif /* INET6 */ extern u_long tcp_sendspace; extern u_long tcp_recvspace; -void tcp_rndiss_init __P((void)); -tcp_seq tcp_rndiss_next __P((void)); -u_int16_t tcp_rndiss_encrypt __P((u_int16_t)); - - +tcp_seq tcp_new_isn __P((struct tcpcb *)); #endif /* KERNEL */ +#endif /* __APPLE_API_PRIVATE */ #endif /* _NETINET_TCP_VAR_H_ */ diff --git a/bsd/netinet/tcpip.h b/bsd/netinet/tcpip.h index 166501a5a..79410f82d 100644 --- a/bsd/netinet/tcpip.h +++ b/bsd/netinet/tcpip.h @@ -52,10 +52,12 @@ * SUCH DAMAGE. * * @(#)tcpip.h 8.1 (Berkeley) 6/10/93 + * $FreeBSD: src/sys/netinet/tcpip.h,v 1.8 1999/08/28 00:49:34 peter Exp $ */ #ifndef _NETINET_TCPIP_H_ #define _NETINET_TCPIP_H_ +#include /* * Tcp+ip header, after ip options removed. @@ -90,89 +92,4 @@ struct full_tcpiphdr { #define ti_sum ti_t.th_sum #define ti_urp ti_t.th_urp -#ifndef INET6 -/* - * Same for templates. - */ -struct tcptemp { - struct ipovly tt_i; /* overlaid ip structure */ - struct tcphdr tt_t; /* tcp header */ -}; -#define tt_x1 tt_i.ih_x1 -#define tt_pr tt_i.ih_pr -#define tt_len tt_i.ih_len -#define tt_src tt_i.ih_src -#define tt_dst tt_i.ih_dst -#define tt_sport tt_t.th_sport -#define tt_dport tt_t.th_dport -#define tt_off tt_t.th_off -#define tt_seq tt_t.th_seq -#define tt_ack tt_t.th_ack -#define tt_x2 tt_t.th_x2 -#define tt_flags tt_t.th_flags -#define tt_win tt_t.th_win -#define tt_sum tt_t.th_sum -#define tt_urp tt_t.th_urp -#else - -#define ip6tcp tcpip6hdr /* for KAME src sync over BSD*'s */ - -/* - * IPv6+TCP headers. - */ -struct tcpip6hdr { - struct ip6_hdr ti6_i; /* IPv6 header */ - struct tcphdr ti6_t; /* TCP header */ -}; -#define ti6_vfc ti6_i.ip6_vfc -#define ti6_flow ti6_i.ip6_vlow -#define ti6_plen ti6_i.ip6_plen -#define ti6_nxt ti6_i.ip6_nxt -#define ti6_hlim ti6_i.ip6_hlim -#define ti6_src ti6_i.ip6_src -#define ti6_dst ti6_i.ip6_dst -#define ti6_sport ti6_t.th_sport -#define ti6_dport ti6_t.th_dport -#define ti6_seq ti6_t.th_seq -#define ti6_ack ti6_t.th_ack -#define ti6_x2 ti6_t.th_x2 -#define ti6_off ti6_t.th_off -#define ti6_flags ti6_t.th_flags -#define ti6_win ti6_t.th_win -#define ti6_sum ti6_t.th_sum -#define ti6_urp ti6_t.th_urp - -/* - * Dual template for IPv4/IPv6 TCP. - * - * Optimized for IPv4 - */ -struct tcptemp { - struct ipovly tt_i; /* overlaid ip structure */ - struct tcphdr tt_t; /* tcp header */ - struct ip6_hdr tt_i6; /* IPv6 header */ -}; -#define tt_x1 tt_i.ih_x1 -#define tt_pr tt_i.ih_pr -#define tt_len tt_i.ih_len -#define tt_src tt_i.ih_src -#define tt_dst tt_i.ih_dst -#define tt_sport tt_t.th_sport -#define tt_dport tt_t.th_dport -#define tt_off tt_t.th_off -#define tt_seq tt_t.th_seq -#define tt_ack tt_t.th_ack -#define tt_x2 tt_t.th_x2 -#define tt_flags tt_t.th_flags -#define tt_win tt_t.th_win -#define tt_sum tt_t.th_sum -#define tt_urp tt_t.th_urp -#define tt_vfc tt_i6.ip6_vfc -#define tt_flow tt_i6.ip6_flow -#define tt_pr6 tt_i6.ip6_nxt -#define tt_len6 tt_i6.ip6_plen -#define tt_src6 tt_i6.ip6_src -#define tt_dst6 tt_i6.ip6_dst -#endif - #endif diff --git a/bsd/netinet/udp.h b/bsd/netinet/udp.h index 99a80dd29..9fa2bb55e 100644 --- a/bsd/netinet/udp.h +++ b/bsd/netinet/udp.h @@ -56,6 +56,7 @@ #ifndef _NETINET_UDP_H_ #define _NETINET_UDP_H_ +#include /* * Udp protocol header. diff --git a/bsd/netinet/udp_usrreq.c b/bsd/netinet/udp_usrreq.c index cce4259d4..4dde880ce 100644 --- a/bsd/netinet/udp_usrreq.c +++ b/bsd/netinet/udp_usrreq.c @@ -52,6 +52,7 @@ * SUCH DAMAGE. * * @(#)udp_usrreq.c 8.6 (Berkeley) 5/23/95 + * $FreeBSD: src/sys/netinet/udp_usrreq.c,v 1.64.2.13 2001/08/08 18:59:54 ghelmer Exp $ */ #include @@ -59,41 +60,37 @@ #include #include #include -#if INET6 #include -#endif #include #include #include #include #include -#if ISFB31 -#include -#endif - - #include #include #include #include #include +#if INET6 +#include +#endif #include #include #include -#include -#include #if INET6 -#include #include #endif +#include +#include #include #include #include #if IPSEC #include +extern int ipsec_bypass; #endif /*IPSEC*/ @@ -105,10 +102,6 @@ #define DBG_FNC_UDP_OUTPUT NETDBG_CODE(DBG_NETUDP, (6 << 8) | 1) -#ifndef offsetof /* XXX */ -#define offsetof(type, member) ((size_t)(&((type *)0)->member)) -#endif - #define __STDC__ 1 /* * UDP protocol implementation. @@ -122,9 +115,13 @@ static int udpcksum = 0; /* XXX */ SYSCTL_INT(_net_inet_udp, UDPCTL_CHECKSUM, checksum, CTLFLAG_RW, &udpcksum, 0, ""); -int log_in_vain; +int log_in_vain = 0; SYSCTL_INT(_net_inet_udp, OID_AUTO, log_in_vain, CTLFLAG_RW, - &log_in_vain, 0, ""); + &log_in_vain, 0, "Log all incoming UDP packets"); + +static int blackhole = 0; +SYSCTL_INT(_net_inet_udp, OID_AUTO, blackhole, CTLFLAG_RW, + &blackhole, 0, "Do not send port unreachables for refused connects"); struct inpcbhead udb; /* from udp_var.h */ #define udb6 udb /* for KAME src sync over BSD*'s */ @@ -138,7 +135,7 @@ extern int apple_hwcksum_rx; struct udpstat udpstat; /* from udp_var.h */ SYSCTL_STRUCT(_net_inet_udp, UDPCTL_STATS, stats, CTLFLAG_RD, - &udpstat, udpstat, ""); + &udpstat, udpstat, "UDP statistics (struct udpstat, netinet/udp_var.h)"); static struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET }; #if INET6 @@ -162,8 +159,8 @@ static void ip_2_ip6_hdr __P((struct ip6_hdr *ip6, struct ip *ip)); #endif static int udp_detach __P((struct socket *so)); -static int udp_output __P((struct inpcb *, struct mbuf *, struct sockaddr *, - struct mbuf *, struct proc *)); +static int udp_output __P((struct inpcb *, struct mbuf *, struct sockaddr *, + struct mbuf *, struct proc *)); void udp_init() @@ -180,18 +177,19 @@ udp_init() udbinfo.hashbase = hashinit(UDBHASHSIZE, M_PCB, &udbinfo.hashmask); udbinfo.porthashbase = hashinit(UDBHASHSIZE, M_PCB, &udbinfo.porthashmask); -#if ISFB31 - udbinfo.ipi_zone = zinit("udpcb", sizeof(struct inpcb), maxsockets, - ZONE_INTERRUPT, 0); -#else +#ifdef __APPLE__ str_size = (vm_size_t) sizeof(struct inpcb); - udbinfo.ipi_zone = (void *) zinit(str_size, 80000*str_size, 8192, "inpcb_zone"); -#endif + udbinfo.ipi_zone = (void *) zinit(str_size, 80000*str_size, 8192, "udpcb"); udbinfo.last_pcb = 0; in_pcb_nat_init(&udbinfo, AF_INET, IPPROTO_UDP, SOCK_DGRAM); +#else + udbinfo.ipi_zone = zinit("udpcb", sizeof(struct inpcb), maxsockets, + ZONE_INTERRUPT, 0); +#endif #if 0 + /* for pcb sharing testing only */ stat = in_pcb_new_share_client(&udbinfo, &fake_owner); kprintf("udp_init in_pcb_new_share_client - stat = %d\n", stat); @@ -226,20 +224,15 @@ udp_input(m, iphlen) register struct udphdr *uh; register struct inpcb *inp; struct mbuf *opts = 0; -#if INET6 - struct ip6_recvpktopts opts6; -#endif int len; struct ip save_ip; struct sockaddr *append_sa; udpstat.udps_ipackets++; -#if INET6 - bzero(&opts6, sizeof(opts6)); -#endif - KERNEL_DEBUG(DBG_FNC_UDP_INPUT | DBG_FUNC_START, 0,0,0,0,0); + if (m->m_pkthdr.csum_flags & CSUM_TCP_SUM16) + m->m_pkthdr.csum_flags = 0; /* invalidate hwcksum for UDP */ /* * Strip IP options, if any; should skip this, @@ -250,8 +243,6 @@ udp_input(m, iphlen) if (iphlen > sizeof (struct ip)) { ip_stripoptions(m, (struct mbuf *)0); iphlen = sizeof(struct ip); - if (m->m_pkthdr.csum_flags & CSUM_TCP_SUM16) - m->m_pkthdr.csum_flags = 0; /* invalidate hwcksum */ } /* @@ -268,6 +259,10 @@ udp_input(m, iphlen) } uh = (struct udphdr *)((caddr_t)ip + iphlen); + /* destination port of 0 is illegal, based on RFC768. */ + if (uh->uh_dport == 0) + goto bad; + KERNEL_DEBUG(DBG_LAYER_IN_BEG, uh->uh_dport, uh->uh_sport, ip->ip_src.s_addr, ip->ip_dst.s_addr, uh->uh_ulen); @@ -297,17 +292,8 @@ udp_input(m, iphlen) if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) { if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) uh->uh_sum = m->m_pkthdr.csum_data; - else { - if (apple_hwcksum_rx && (m->m_pkthdr.csum_flags & CSUM_TCP_SUM16)) { - bzero(((struct ipovly *)ip)->ih_x1, 9); - ((struct ipovly *)ip)->ih_len = uh->uh_ulen; - uh->uh_sum = in_addword(in_cksum(m, sizeof(struct ip)), - m->m_pkthdr.csum_data & 0xFFFF); - } - else { - goto doudpcksum; - } - } + else + goto doudpcksum; uh->uh_sum ^= 0xffff; } else { doudpcksum: @@ -322,6 +308,10 @@ doudpcksum: return; } } +#ifndef __APPLE__ + else + udpstat.udps_nosum++; +#endif if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) || in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) { @@ -356,6 +346,11 @@ doudpcksum: udp_in6.uin6_init_done = udp_ip6.uip6_init_done = 0; #endif LIST_FOREACH(inp, &udb, inp_list) { +#ifdef __APPLE__ + /* Ignore nat/SharedIP dummy pcbs */ + if (inp->inp_socket == &udbinfo.nat_dummy_socket) + continue; +#endif #if INET6 if ((inp->inp_vflag & INP_IPV4) == 0) continue; @@ -379,14 +374,15 @@ doudpcksum: #if IPSEC /* check AH/ESP integrity. */ - if (ipsec4_in_reject_so(m, last->inp_socket)) { + if (ipsec_bypass == 0 && ipsec4_in_reject_so(m, last->inp_socket)) { ipsecstat.in_polvio++; /* do not inject data to pcb */ } else #endif /*IPSEC*/ if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { - udp_append(last, ip, n, iphlen + - sizeof (struct udphdr)); + udp_append(last, ip, n, + iphlen + + sizeof(struct udphdr)); } } last = inp; @@ -412,14 +408,13 @@ doudpcksum: goto bad; } #if IPSEC - else /* check AH/ESP integrity. */ - if (m && ipsec4_in_reject_so(m, last->inp_socket)) { + if (ipsec_bypass == 0 && m && ipsec4_in_reject_so(m, last->inp_socket)) { ipsecstat.in_polvio++; goto bad; } #endif /*IPSEC*/ - udp_append(last, ip, m, iphlen + sizeof (struct udphdr)); + udp_append(last, ip, m, iphlen + sizeof(struct udphdr)); return; } /* @@ -442,17 +437,20 @@ doudpcksum: udpstat.udps_noportbcast++; goto bad; } - *ip = save_ip; #if ICMP_BANDLIM - if (badport_bandlim(0) < 0) + if (badport_bandlim(BANDLIM_ICMP_UNREACH) < 0) goto bad; #endif + if (blackhole) + goto bad; + *ip = save_ip; + ip->ip_len += iphlen; icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0); KERNEL_DEBUG(DBG_FNC_UDP_INPUT | DBG_FUNC_END, 0,0,0,0,0); return; } #if IPSEC - if (inp != NULL && ipsec4_in_reject_so(m, inp->inp_socket)) { + if (ipsec_bypass == 0 && inp != NULL && ipsec4_in_reject_so(m, inp->inp_socket)) { ipsecstat.in_polvio++; goto bad; } @@ -473,15 +471,13 @@ doudpcksum: ip_2_ip6_hdr(&udp_ip6.uip6_ip6, ip); savedflags = inp->inp_flags; inp->inp_flags &= ~INP_UNMAPPABLEOPTS; - ip6_savecontrol(inp, &udp_ip6.uip6_ip6, m, - &opts6, NULL); - + ip6_savecontrol(inp, &opts, &udp_ip6.uip6_ip6, m); inp->inp_flags = savedflags; } else #endif ip_savecontrol(inp, &opts, ip, m); } - m_adj(m, iphlen + sizeof(struct udphdr)); + m_adj(m, iphlen + sizeof(struct udphdr)); KERNEL_DEBUG(DBG_LAYER_IN_END, uh->uh_dport, uh->uh_sport, save_ip.ip_src.s_addr, save_ip.ip_dst.s_addr, uh->uh_ulen); @@ -490,7 +486,6 @@ doudpcksum: if (inp->inp_vflag & INP_IPV6) { in6_sin_2_v4mapsin6(&udp_in, &udp_in6.uin6_sin); append_sa = (struct sockaddr *)&udp_in6; - opts = opts6.head; } else #endif append_sa = (struct sockaddr *)&udp_in; @@ -506,6 +501,7 @@ bad: if (opts) m_freem(opts); KERNEL_DEBUG(DBG_FNC_UDP_INPUT | DBG_FUNC_END, 0,0,0,0,0); + return; } #if INET6 @@ -536,14 +532,10 @@ udp_append(last, ip, n, off) struct inpcb *last; struct ip *ip; struct mbuf *n; + int off; { struct sockaddr *append_sa; struct mbuf *opts = 0; -#if INET6 - struct ip6_recvpktopts opts6; - bzero(&opts6, sizeof(opts6)); -#endif - if (last->inp_flags & INP_CONTROLOPTS || last->inp_socket->so_options & SO_TIMESTAMP) { @@ -557,8 +549,7 @@ udp_append(last, ip, n, off) } savedflags = last->inp_flags; last->inp_flags &= ~INP_UNMAPPABLEOPTS; - ip6_savecontrol(last, &udp_ip6.uip6_ip6, n, - &opts6, NULL); + ip6_savecontrol(last, &opts, &udp_ip6.uip6_ip6, n); last->inp_flags = savedflags; } else #endif @@ -571,12 +562,10 @@ udp_append(last, ip, n, off) udp_in6.uin6_init_done = 1; } append_sa = (struct sockaddr *)&udp_in6.uin6_sin; - opts = opts6.head; } else #endif append_sa = (struct sockaddr *)&udp_in; m_adj(n, off); - if (sbappendaddr(&last->inp_socket->so_rcv, append_sa, n, opts) == 0) { m_freem(n); if (opts) @@ -586,8 +575,6 @@ udp_append(last, ip, n, off) sorwakeup(last->inp_socket); } - - /* * Notify a udp user of an asynchronous error; * just wake up so that he can collect error status. @@ -608,21 +595,36 @@ udp_ctlinput(cmd, sa, vip) struct sockaddr *sa; void *vip; { - register struct ip *ip = vip; - register struct udphdr *uh; + struct ip *ip = vip; + struct udphdr *uh; + void (*notify) __P((struct inpcb *, int)) = udp_notify; + struct in_addr faddr; + struct inpcb *inp; + int s; + + faddr = ((struct sockaddr_in *)sa)->sin_addr; + if (sa->sa_family != AF_INET || faddr.s_addr == INADDR_ANY) + return; - if (!PRC_IS_REDIRECT(cmd) && - ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0)) + if (PRC_IS_REDIRECT(cmd)) { + ip = 0; + notify = in_rtchange; + } else if (cmd == PRC_HOSTDEAD) + ip = 0; + else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) return; if (ip) { + s = splnet(); 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); + inp = in_pcblookup_hash(&udbinfo, faddr, uh->uh_dport, + ip->ip_src, uh->uh_sport, 0, NULL); + if (inp != NULL && inp->inp_socket != NULL) + (*notify)(inp, inetctlerrmap[cmd]); + splx(s); } else - in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify); + in_pcbnotifyall(&udb, faddr, inetctlerrmap[cmd], notify); } - static int udp_pcblist SYSCTL_HANDLER_ARGS { @@ -660,19 +662,19 @@ udp_pcblist SYSCTL_HANDLER_ARGS error = SYSCTL_OUT(req, &xig, sizeof xig); if (error) return error; - /* - * We are done if there is no pcb - */ - if (n == 0) - return 0; + /* + * We are done if there is no pcb + */ + if (n == 0) + return 0; inp_list = _MALLOC(n * sizeof *inp_list, M_TEMP, M_WAITOK); if (inp_list == 0) { return ENOMEM; } - s = splnet(); - for (inp = udbinfo.listhead->lh_first, i = 0; inp && i < n; - inp = inp->inp_list.le_next) { + + for (inp = LIST_FIRST(udbinfo.listhead), i = 0; inp && i < n; + inp = LIST_NEXT(inp, inp_list)) { if (inp->inp_gencnt <= gencnt) inp_list[i++] = inp; } @@ -719,7 +721,7 @@ SYSCTL_PROC(_net_inet_udp, UDPCTL_PCBLIST, pcblist, CTLFLAG_RD, 0, 0, static int udp_output(inp, m, addr, control, p) register struct inpcb *inp; - register struct mbuf *m; + struct mbuf *m; struct sockaddr *addr; struct mbuf *control; struct proc *p; @@ -781,26 +783,25 @@ udp_output(inp, m, addr, control, p) * and addresses and length put into network format. */ ui = mtod(m, struct udpiphdr *); - bzero(ui->ui_x1, sizeof(ui->ui_x1)); + bzero(ui->ui_x1, sizeof(ui->ui_x1)); /* XXX still needed? */ 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; + ui->ui_ulen = htons((u_short)len + sizeof(struct udphdr)); /* - * Stuff checksum and output datagram. + * Set up checksum and output datagram. */ if (udpcksum) { - ui->ui_sum = in_pseudo(ui->ui_src.s_addr, ui->ui_dst.s_addr, - htons((u_short)len + sizeof(struct udphdr) + IPPROTO_UDP)); - m->m_pkthdr.csum_flags = CSUM_UDP; - m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum); - } - else + ui->ui_sum = in_pseudo(ui->ui_src.s_addr, ui->ui_dst.s_addr, + htons((u_short)len + sizeof(struct udphdr) + IPPROTO_UDP)); + m->m_pkthdr.csum_flags = CSUM_UDP; + m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum); + } else { ui->ui_sum = 0; + } ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; ((struct ip *)ui)->ip_ttl = inp->inp_ip_ttl; /* XXX */ ((struct ip *)ui)->ip_tos = inp->inp_ip_tos; /* XXX */ @@ -809,13 +810,14 @@ udp_output(inp, m, addr, control, p) KERNEL_DEBUG(DBG_LAYER_OUT_END, ui->ui_dport, ui->ui_sport, ui->ui_src.s_addr, ui->ui_dst.s_addr, ui->ui_ulen); - #if IPSEC - ipsec_setsocket(m, inp->inp_socket); + if (ipsec_bypass == 0 && ipsec_setsocket(m, inp->inp_socket) != 0) { + error = ENOBUFS; + goto release; + } #endif /*IPSEC*/ - error = ip_output(m, inp->inp_options, &inp->inp_route, - inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST), + (inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)), inp->inp_moptions); if (addr) { @@ -835,18 +837,17 @@ release: u_long udp_sendspace = 9216; /* really max datagram size */ /* 40 1K datagrams */ SYSCTL_INT(_net_inet_udp, UDPCTL_MAXDGRAM, maxdgram, CTLFLAG_RW, - &udp_sendspace, 0, ""); - + &udp_sendspace, 0, "Maximum outgoing UDP datagram size"); -u_long udp_recvspace = 40 * (1024 + /* 40 1K datagrams */ +u_long udp_recvspace = 40 * (1024 + #if INET6 sizeof(struct sockaddr_in6) -#else /* INET6 */ +#else sizeof(struct sockaddr_in) -#endif /* INET6 */ +#endif ); SYSCTL_INT(_net_inet_udp, UDPCTL_RECVSPACE, recvspace, CTLFLAG_RW, - &udp_recvspace, 0, ""); + &udp_recvspace, 0, "Maximum incoming UDP datagram size"); static int udp_abort(struct socket *so) @@ -870,29 +871,21 @@ udp_attach(struct socket *so, int proto, struct proc *p) struct inpcb *inp; int error; long s; - if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { - error = soreserve(so, udp_sendspace, udp_recvspace); - if (error) - return error; - } + inp = sotoinpcb(so); + if (inp != 0) + return EINVAL; + + error = soreserve(so, udp_sendspace, udp_recvspace); + if (error) + return error; s = splnet(); error = in_pcballoc(so, &udbinfo, p); splx(s); - if (error) - return error; - error = soreserve(so, udp_sendspace, udp_recvspace); if (error) return error; inp = (struct inpcb *)so->so_pcb; inp->inp_vflag |= INP_IPV4; inp->inp_ip_ttl = ip_defttl; -#if IPSEC - error = ipsec_init_policy(so, &inp->inp_sp); - if (error != 0) { - in_pcbdetach(inp); - return error; - } -#endif /*IPSEC*/ return 0; } diff --git a/bsd/netinet/udp_var.h b/bsd/netinet/udp_var.h index 97adb4508..4c2976f31 100644 --- a/bsd/netinet/udp_var.h +++ b/bsd/netinet/udp_var.h @@ -56,8 +56,10 @@ #ifndef _NETINET_UDP_VAR_H_ #define _NETINET_UDP_VAR_H_ +#include #include +#ifdef __APPLE_API_PRIVATE /* * UDP kernel structures and variables. @@ -77,17 +79,9 @@ struct udpiphdr { #define ui_sum ui_u.uh_sum #define ui_next ui_i.ih_next #define ui_prev ui_i.ih_prev +#endif /* __APPLE_API_PRIVATE */ -struct udpcb { - /* XXX - these should be by reference so we can do options quickly */ - struct ip udb_ip; - struct udphdr udb_uh; - struct sockaddr_in udb_conn; - struct in_hostcache *udb_hc; - struct mbuf *udb_queue; -}; -#define inptoudpcb(inp) ((struct udpdb *)(inp)->inp_ppcb) - +#ifdef __APPLE_API_UNSTABLE struct udpstat { /* input statistics: */ u_long udps_ipackets; /* total input packets */ @@ -102,7 +96,13 @@ struct udpstat { /* output statistics: */ u_long udps_opackets; /* total output packets */ u_long udps_fastout; /* output packets on fast path */ +#ifndef __APPLE__ + u_long udps_nosum; /* no checksum */ + /* of no socket on port, arrived as multicast */ + u_long udps_noportmcast; +#endif }; +#endif /* __APPLE_API_UNSTABLE */ /* * Names for UDP sysctl objects @@ -123,6 +123,7 @@ struct udpstat { { "pcblist", CTLTYPE_STRUCT }, \ } +#ifdef __APPLE_API_PRIVATE #ifdef KERNEL SYSCTL_DECL(_net_inet_udp); @@ -131,7 +132,7 @@ extern struct inpcbhead udb; extern struct inpcbinfo udbinfo; extern u_long udp_sendspace; extern u_long udp_recvspace; -extern struct udpstat udpstat; +extern struct udpstat udpstat; extern int log_in_vain; void udp_ctlinput __P((int, struct sockaddr *, void *)); @@ -141,5 +142,6 @@ void udp_input __P((struct mbuf *, int)); void udp_notify __P((struct inpcb *inp, int errno)); int udp_shutdown __P((struct socket *so)); #endif +#endif /* __APPLE_API_PRIVATE */ #endif diff --git a/bsd/netinet6/Makefile b/bsd/netinet6/Makefile index e70225fdf..8de432c3c 100644 --- a/bsd/netinet6/Makefile +++ b/bsd/netinet6/Makefile @@ -20,11 +20,16 @@ EXPINC_SUBDIRS_PPC = \ EXPINC_SUBDIRS_I386 = \ DATAFILES = \ - ah.h esp.h icmp6.h in6.h in6_gif.h in6_ifattach.h in6_pcb.h \ - in6_prefix.h in6_var.h ip6.h ip6_fw.h ip6_mroute.h ip6_var.h \ - ip6protosw.h ipcomp.h ipsec.h mip6.h mip6_common.h mld6_var.h \ - natpt_defs.h natpt_list.h natpt_log.h natpt_soctl.h natpt_var.h \ - nd6.h pim6.h pim6_var.h udp6.h udp6_var.h + ah.h esp_rijndael.h in6_ifattach.h ip6.h \ + ip6_var.h ipsec.h pim6.h tcp6_var.h \ + ah6.h icmp6.h in6_pcb.h ip6_ecn.h \ + ip6protosw.h ipsec6.h pim6_var.h udp6_var.h \ + esp.h in6.h in6_prefix.h \ + ipcomp.h mld6_var.h raw_ip6.h esp6.h \ + in6_gif.h in6_var.h ip6_mroute.h ipcomp6.h \ + nd6.h scope6_var.h + + INSTALL_MI_LIST = ${DATAFILES} @@ -34,6 +39,10 @@ EXPORT_MI_LIST = ${DATAFILES} EXPORT_MI_DIR = netinet6 +PRIVATE_DATAFILES = \ + ip6_fw.h + +INSTALL_MI_LCL_KERN_LIST = ${PRIVATE_DATAFILES} include $(MakeInc_rule) include $(MakeInc_dir) diff --git a/bsd/netinet6/ah.h b/bsd/netinet6/ah.h index a1e9667a0..62c5eda54 100644 --- a/bsd/netinet6/ah.h +++ b/bsd/netinet6/ah.h @@ -1,3 +1,6 @@ +/* $FreeBSD: src/sys/netinet6/ah.h,v 1.3.2.2 2001/07/03 11:01:49 ume Exp $ */ +/* $KAME: ah.h,v 1.13 2000/10/18 21:28:00 itojun Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. @@ -33,14 +36,7 @@ #ifndef _NETINET6_AH_H_ #define _NETINET6_AH_H_ - -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#if defined(_KERNEL) && !defined(_LKM) -#include "opt_inet.h" -#endif -#endif - -#include /* for struct secasvar */ +#include struct ah { u_int8_t ah_nxt; /* Next Header */ @@ -59,6 +55,10 @@ struct newah { /* variable size, 32bit bound*/ /* Authentication data */ }; +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE +struct secasvar; + struct ah_algorithm_state { struct secasvar *sav; void* foo; /*per algorithm data - maybe*/ @@ -69,20 +69,15 @@ struct ah_algorithm { int (*mature) __P((struct secasvar *)); int keymin; /* in bits */ int keymax; /* in bits */ - void (*init) __P((struct ah_algorithm_state *, struct secasvar *)); + const char *name; + int (*init) __P((struct ah_algorithm_state *, struct secasvar *)); void (*update) __P((struct ah_algorithm_state *, caddr_t, size_t)); void (*result) __P((struct ah_algorithm_state *, caddr_t)); }; #define AH_MAXSUMSIZE 16 -#ifdef KERNEL -extern struct ah_algorithm ah_algorithms[]; - -struct inpcb; -#if INET6 -struct in6pcb; -#endif +extern const struct ah_algorithm *ah_algorithm_lookup __P((int)); /* cksum routines */ extern int ah_hdrlen __P((struct secasvar *)); @@ -90,17 +85,9 @@ extern int ah_hdrlen __P((struct secasvar *)); extern size_t ah_hdrsiz __P((struct ipsecrequest *)); extern void ah4_input __P((struct mbuf *, int)); extern int ah4_output __P((struct mbuf *, struct ipsecrequest *)); -extern int ah4_calccksum __P((struct mbuf *, caddr_t, - struct ah_algorithm *, struct secasvar *)); - -#if INET6 -extern int ah6_input __P((struct mbuf **, int *, int)); -extern int ah6_output __P((struct mbuf *, u_char *, struct mbuf *, - struct ipsecrequest *)); -extern int ah6_calccksum __P((struct mbuf *, caddr_t, - struct ah_algorithm *, struct secasvar *)); -#endif /* INET6 */ - +extern int ah4_calccksum __P((struct mbuf *, caddr_t, size_t, + const struct ah_algorithm *, struct secasvar *)); +#endif /* __APPLE_API_PRIVATE */ #endif /*KERNEL*/ #endif /*_NETINET6_AH_H_*/ diff --git a/bsd/netinet6/ah6.h b/bsd/netinet6/ah6.h new file mode 100644 index 000000000..02edd317f --- /dev/null +++ b/bsd/netinet6/ah6.h @@ -0,0 +1,55 @@ +/* $FreeBSD: src/sys/netinet6/ah6.h,v 1.2.2.2 2001/07/03 11:01:49 ume Exp $ */ +/* $KAME: ah.h,v 1.13 2000/10/18 21:28:00 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * RFC1826/2402 authentication header. + */ + +#ifndef _NETINET6_AH6_H_ +#define _NETINET6_AH6_H_ +#include + +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE +struct secasvar; + +extern int ah6_input __P((struct mbuf **, int *, int)); +extern int ah6_output __P((struct mbuf *, u_char *, struct mbuf *, + struct ipsecrequest *)); +extern int ah6_calccksum __P((struct mbuf *, caddr_t, size_t, + const struct ah_algorithm *, struct secasvar *)); + +extern void ah6_ctlinput __P((int, struct sockaddr *, void *)); +#endif /* __APPLE_API_PRIVATE */ +#endif + +#endif /*_NETINET6_AH6_H_*/ diff --git a/bsd/netinet6/ah_core.c b/bsd/netinet6/ah_core.c index f21899828..519c1b6a4 100644 --- a/bsd/netinet6/ah_core.c +++ b/bsd/netinet6/ah_core.c @@ -1,3 +1,6 @@ +/* $FreeBSD: src/sys/netinet6/ah_core.c,v 1.2.2.4 2001/07/03 11:01:49 ume Exp $ */ +/* $KAME: ah_core.c,v 1.44 2001/03/12 11:24:39 itojun Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. @@ -30,22 +33,8 @@ /* * RFC1826/2402 authentication header. */ -#define _IP_VHL -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#if __NetBSD__ /*XXX*/ -#include "opt_ipsec.h" -#endif -#endif -/* Some of operating systems have standard crypto checksum library */ -#if __NetBSD__ -#define HAVE_MD5 -#define HAVE_SHA1 -#endif -#if defined(__FreeBSD__) || defined(__APPLE__) -#define HAVE_MD5 1 -#endif +/* TODO: have shared routines for hmac-* algorithms */ #include #include @@ -57,7 +46,6 @@ #include #include #include -#include #include #include @@ -75,23 +63,24 @@ #endif #include +#if INET6 +#include +#endif #include +#if INET6 +#include +#endif #if IPSEC_ESP #include +#if INET6 +#include +#endif #endif #include #include -#if HAVE_MD5 #include -#else -#include -#endif -#if HAVE_SHA1 -#include -#define SHA1_RESULTLEN 20 -#else #include -#endif +#include #include @@ -100,53 +89,111 @@ static int ah_sumsiz_1216 __P((struct secasvar *)); static int ah_sumsiz_zero __P((struct secasvar *)); static int ah_none_mature __P((struct secasvar *)); -static void ah_none_init __P((struct ah_algorithm_state *, - struct secasvar *)); +static int ah_none_init __P((struct ah_algorithm_state *, struct secasvar *)); static void ah_none_loop __P((struct ah_algorithm_state *, caddr_t, size_t)); static void ah_none_result __P((struct ah_algorithm_state *, caddr_t)); static int ah_keyed_md5_mature __P((struct secasvar *)); -static void ah_keyed_md5_init __P((struct ah_algorithm_state *, +static int ah_keyed_md5_init __P((struct ah_algorithm_state *, struct secasvar *)); static void ah_keyed_md5_loop __P((struct ah_algorithm_state *, caddr_t, size_t)); static void ah_keyed_md5_result __P((struct ah_algorithm_state *, caddr_t)); static int ah_keyed_sha1_mature __P((struct secasvar *)); -static void ah_keyed_sha1_init __P((struct ah_algorithm_state *, +static int ah_keyed_sha1_init __P((struct ah_algorithm_state *, struct secasvar *)); static void ah_keyed_sha1_loop __P((struct ah_algorithm_state *, caddr_t, size_t)); static void ah_keyed_sha1_result __P((struct ah_algorithm_state *, caddr_t)); static int ah_hmac_md5_mature __P((struct secasvar *)); -static void ah_hmac_md5_init __P((struct ah_algorithm_state *, +static int ah_hmac_md5_init __P((struct ah_algorithm_state *, struct secasvar *)); static void ah_hmac_md5_loop __P((struct ah_algorithm_state *, caddr_t, size_t)); static void ah_hmac_md5_result __P((struct ah_algorithm_state *, caddr_t)); static int ah_hmac_sha1_mature __P((struct secasvar *)); -static void ah_hmac_sha1_init __P((struct ah_algorithm_state *, +static int ah_hmac_sha1_init __P((struct ah_algorithm_state *, struct secasvar *)); static void ah_hmac_sha1_loop __P((struct ah_algorithm_state *, caddr_t, size_t)); static void ah_hmac_sha1_result __P((struct ah_algorithm_state *, caddr_t)); +static int ah_hmac_sha2_256_mature __P((struct secasvar *)); +static int ah_hmac_sha2_256_init __P((struct ah_algorithm_state *, + struct secasvar *)); +static void ah_hmac_sha2_256_loop __P((struct ah_algorithm_state *, caddr_t, + size_t)); +static void ah_hmac_sha2_256_result __P((struct ah_algorithm_state *, caddr_t)); +static int ah_hmac_sha2_384_mature __P((struct secasvar *)); +static int ah_hmac_sha2_384_init __P((struct ah_algorithm_state *, + struct secasvar *)); +static void ah_hmac_sha2_384_loop __P((struct ah_algorithm_state *, caddr_t, + size_t)); +static void ah_hmac_sha2_384_result __P((struct ah_algorithm_state *, caddr_t)); +static int ah_hmac_sha2_512_mature __P((struct secasvar *)); +static int ah_hmac_sha2_512_init __P((struct ah_algorithm_state *, + struct secasvar *)); +static void ah_hmac_sha2_512_loop __P((struct ah_algorithm_state *, caddr_t, + size_t)); +static void ah_hmac_sha2_512_result __P((struct ah_algorithm_state *, caddr_t)); + +static void ah_update_mbuf __P((struct mbuf *, int, int, + const struct ah_algorithm *, struct ah_algorithm_state *)); + +const struct ah_algorithm * +ah_algorithm_lookup(idx) + int idx; +{ + /* checksum algorithms */ + static struct ah_algorithm ah_algorithms[] = { + { ah_sumsiz_1216, ah_hmac_md5_mature, 128, 128, "hmac-md5", + ah_hmac_md5_init, ah_hmac_md5_loop, + ah_hmac_md5_result, }, + { ah_sumsiz_1216, ah_hmac_sha1_mature, 160, 160, "hmac-sha1", + ah_hmac_sha1_init, ah_hmac_sha1_loop, + ah_hmac_sha1_result, }, + { ah_sumsiz_1216, ah_keyed_md5_mature, 128, 128, "keyed-md5", + ah_keyed_md5_init, ah_keyed_md5_loop, + ah_keyed_md5_result, }, + { ah_sumsiz_1216, ah_keyed_sha1_mature, 160, 160, "keyed-sha1", + ah_keyed_sha1_init, ah_keyed_sha1_loop, + ah_keyed_sha1_result, }, + { ah_sumsiz_zero, ah_none_mature, 0, 2048, "none", + ah_none_init, ah_none_loop, ah_none_result, }, + { ah_sumsiz_1216, ah_hmac_sha2_256_mature, 256, 256, + "hmac-sha2-256", + ah_hmac_sha2_256_init, ah_hmac_sha2_256_loop, + ah_hmac_sha2_256_result, }, + { ah_sumsiz_1216, ah_hmac_sha2_384_mature, 384, 384, + "hmac-sha2-384", + ah_hmac_sha2_384_init, ah_hmac_sha2_384_loop, + ah_hmac_sha2_384_result, }, + { ah_sumsiz_1216, ah_hmac_sha2_512_mature, 512, 512, + "hmac-sha2-512", + ah_hmac_sha2_512_init, ah_hmac_sha2_512_loop, + ah_hmac_sha2_512_result, }, + }; + + switch (idx) { + case SADB_AALG_MD5HMAC: + return &ah_algorithms[0]; + case SADB_AALG_SHA1HMAC: + return &ah_algorithms[1]; + case SADB_X_AALG_MD5: + return &ah_algorithms[2]; + case SADB_X_AALG_SHA: + return &ah_algorithms[3]; + case SADB_X_AALG_NULL: + return &ah_algorithms[4]; + case SADB_X_AALG_SHA2_256: + return &ah_algorithms[5]; + case SADB_X_AALG_SHA2_384: + return &ah_algorithms[6]; + case SADB_X_AALG_SHA2_512: + return &ah_algorithms[7]; + default: + return NULL; + } +} -static void ah_update_mbuf __P((struct mbuf *, int, int, struct ah_algorithm *, - struct ah_algorithm_state *)); - -/* checksum algorithms */ -/* NOTE: The order depends on SADB_AALG_x in net/pfkeyv2.h */ -struct ah_algorithm ah_algorithms[] = { - { 0, 0, 0, 0, 0, 0, }, - { ah_sumsiz_1216, ah_hmac_md5_mature, 128, 128, - ah_hmac_md5_init, ah_hmac_md5_loop, ah_hmac_md5_result, }, - { ah_sumsiz_1216, ah_hmac_sha1_mature, 160, 160, - ah_hmac_sha1_init, ah_hmac_sha1_loop, ah_hmac_sha1_result, }, - { ah_sumsiz_1216, ah_keyed_md5_mature, 128, 128, - ah_keyed_md5_init, ah_keyed_md5_loop, ah_keyed_md5_result, }, - { ah_sumsiz_1216, ah_keyed_sha1_mature, 160, 160, - ah_keyed_sha1_init, ah_keyed_sha1_loop, ah_keyed_sha1_result, }, - { ah_sumsiz_zero, ah_none_mature, 0, 2048, - ah_none_init, ah_none_loop, ah_none_result, }, -}; static int ah_sumsiz_1216(sav) @@ -181,12 +228,13 @@ ah_none_mature(sav) return 0; } -static void +static int ah_none_init(state, sav) struct ah_algorithm_state *state; struct secasvar *sav; { state->foo = NULL; + return 0; } static void @@ -212,34 +260,34 @@ ah_keyed_md5_mature(sav) return 0; } -static void +static int ah_keyed_md5_init(state, sav) struct ah_algorithm_state *state; struct secasvar *sav; { + size_t padlen; + size_t keybitlen; + u_int8_t buf[32]; + if (!state) panic("ah_keyed_md5_init: what?"); state->sav = sav; state->foo = (void *)_MALLOC(sizeof(MD5_CTX), M_TEMP, M_WAITOK); if (state->foo == NULL) - panic("ah_keyed_md5_init: what?"); + return ENOBUFS; + MD5Init((MD5_CTX *)state->foo); if (state->sav) { MD5Update((MD5_CTX *)state->foo, (u_int8_t *)_KEYBUF(state->sav->key_auth), (u_int)_KEYLEN(state->sav->key_auth)); - { /* * Pad after the key. * We cannot simply use md5_pad() since the function * won't update the total length. */ - size_t padlen; - size_t keybitlen; - u_int8_t buf[32]; - if (_KEYLEN(state->sav->key_auth) < 56) padlen = 64 - 8 - _KEYLEN(state->sav->key_auth); else @@ -265,8 +313,9 @@ ah_keyed_md5_init(state, sav) buf[2] = (keybitlen >> 16) & 0xff; buf[3] = (keybitlen >> 24) & 0xff; MD5Update((MD5_CTX *)state->foo, buf, 8); - } } + + return 0; } static void @@ -297,7 +346,7 @@ ah_keyed_md5_result(state, addr) (u_int)_KEYLEN(state->sav->key_auth)); } MD5Final(&digest[0], (MD5_CTX *)state->foo); - _FREE(state->foo, M_TEMP); + FREE(state->foo, M_TEMP); bcopy(&digest[0], (void *)addr, sizeof(digest)); } @@ -305,13 +354,19 @@ static int ah_keyed_sha1_mature(sav) struct secasvar *sav; { - struct ah_algorithm *algo; + const struct ah_algorithm *algo; if (!sav->key_auth) { ipseclog((LOG_ERR, "ah_keyed_sha1_mature: no key is given.\n")); return 1; } - algo = &ah_algorithms[sav->alg_auth]; + + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { + ipseclog((LOG_ERR, "ah_keyed_sha1_mature: unsupported algorithm.\n")); + return 1; + } + if (sav->key_auth->sadb_key_bits < algo->keymin || algo->keymax < sav->key_auth->sadb_key_bits) { ipseclog((LOG_ERR, @@ -323,12 +378,15 @@ ah_keyed_sha1_mature(sav) return 0; } -static void +static int ah_keyed_sha1_init(state, sav) struct ah_algorithm_state *state; struct secasvar *sav; { SHA1_CTX *ctxt; + size_t padlen; + size_t keybitlen; + u_int8_t buf[32]; if (!state) panic("ah_keyed_sha1_init: what?"); @@ -336,7 +394,7 @@ ah_keyed_sha1_init(state, sav) state->sav = sav; state->foo = (void *)_MALLOC(sizeof(SHA1_CTX), M_TEMP, M_WAITOK); if (!state->foo) - panic("ah_keyed_sha1_init: what?"); + return ENOBUFS; ctxt = (SHA1_CTX *)state->foo; SHA1Init(ctxt); @@ -345,14 +403,9 @@ ah_keyed_sha1_init(state, sav) SHA1Update(ctxt, (u_int8_t *)_KEYBUF(state->sav->key_auth), (u_int)_KEYLEN(state->sav->key_auth)); - { /* * Pad after the key. */ - size_t padlen; - size_t keybitlen; - u_int8_t buf[32]; - if (_KEYLEN(state->sav->key_auth) < 56) padlen = 64 - 8 - _KEYLEN(state->sav->key_auth); else @@ -378,8 +431,9 @@ ah_keyed_sha1_init(state, sav) buf[2] = (keybitlen >> 16) & 0xff; buf[3] = (keybitlen >> 24) & 0xff; SHA1Update(ctxt, buf, 8); - } } + + return 0; } static void @@ -416,20 +470,26 @@ ah_keyed_sha1_result(state, addr) SHA1Final((caddr_t)&digest[0], ctxt); bcopy(&digest[0], (void *)addr, HMACSIZE); - _FREE(state->foo, M_TEMP); + FREE(state->foo, M_TEMP); } static int ah_hmac_md5_mature(sav) struct secasvar *sav; { - struct ah_algorithm *algo; + const struct ah_algorithm *algo; if (!sav->key_auth) { ipseclog((LOG_ERR, "ah_hmac_md5_mature: no key is given.\n")); return 1; } - algo = &ah_algorithms[sav->alg_auth]; + + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { + ipseclog((LOG_ERR, "ah_hmac_md5_mature: unsupported algorithm.\n")); + return 1; + } + if (sav->key_auth->sadb_key_bits < algo->keymin || algo->keymax < sav->key_auth->sadb_key_bits) { ipseclog((LOG_ERR, @@ -441,7 +501,7 @@ ah_hmac_md5_mature(sav) return 0; } -static void +static int ah_hmac_md5_init(state, sav) struct ah_algorithm_state *state; struct secasvar *sav; @@ -460,7 +520,7 @@ ah_hmac_md5_init(state, sav) state->sav = sav; state->foo = (void *)_MALLOC(64 + 64 + sizeof(MD5_CTX), M_TEMP, M_WAITOK); if (!state->foo) - panic("ah_hmac_md5_init: what?"); + return ENOBUFS; ipad = (u_char *)state->foo; opad = (u_char *)(ipad + 64); @@ -490,6 +550,8 @@ ah_hmac_md5_init(state, sav) MD5Init(ctxt); MD5Update(ctxt, ipad, 64); + + return 0; } static void @@ -532,20 +594,26 @@ ah_hmac_md5_result(state, addr) bcopy(&digest[0], (void *)addr, HMACSIZE); - _FREE(state->foo, M_TEMP); + FREE(state->foo, M_TEMP); } static int ah_hmac_sha1_mature(sav) struct secasvar *sav; { - struct ah_algorithm *algo; + const struct ah_algorithm *algo; if (!sav->key_auth) { ipseclog((LOG_ERR, "ah_hmac_sha1_mature: no key is given.\n")); return 1; } - algo = &ah_algorithms[sav->alg_auth]; + + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { + ipseclog((LOG_ERR, "ah_hmac_sha1_mature: unsupported algorithm.\n")); + return 1; + } + if (sav->key_auth->sadb_key_bits < algo->keymin || algo->keymax < sav->key_auth->sadb_key_bits) { ipseclog((LOG_ERR, @@ -557,7 +625,7 @@ ah_hmac_sha1_mature(sav) return 0; } -static void +static int ah_hmac_sha1_init(state, sav) struct ah_algorithm_state *state; struct secasvar *sav; @@ -577,7 +645,7 @@ ah_hmac_sha1_init(state, sav) state->foo = (void *)_MALLOC(64 + 64 + sizeof(SHA1_CTX), M_TEMP, M_WAITOK); if (!state->foo) - panic("ah_hmac_sha1_init: what?"); + return ENOBUFS; ipad = (u_char *)state->foo; opad = (u_char *)(ipad + 64); @@ -607,6 +675,8 @@ ah_hmac_sha1_init(state, sav) SHA1Init(ctxt); SHA1Update(ctxt, ipad, 64); + + return 0; } static void @@ -650,7 +720,405 @@ ah_hmac_sha1_result(state, addr) bcopy(&digest[0], (void *)addr, HMACSIZE); - _FREE(state->foo, M_TEMP); + FREE(state->foo, M_TEMP); +} + +static int +ah_hmac_sha2_256_mature(sav) + struct secasvar *sav; +{ + const struct ah_algorithm *algo; + + if (!sav->key_auth) { + ipseclog((LOG_ERR, + "ah_hmac_sha2_256_mature: no key is given.\n")); + return 1; + } + + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { + ipseclog((LOG_ERR, + "ah_hmac_sha2_256_mature: unsupported algorithm.\n")); + return 1; + } + + if (sav->key_auth->sadb_key_bits < algo->keymin || + algo->keymax < sav->key_auth->sadb_key_bits) { + ipseclog((LOG_ERR, + "ah_hmac_sha2_256_mature: invalid key length %d.\n", + sav->key_auth->sadb_key_bits)); + return 1; + } + + return 0; +} + +static int +ah_hmac_sha2_256_init(state, sav) + struct ah_algorithm_state *state; + struct secasvar *sav; +{ + u_char *ipad; + u_char *opad; + SHA256_CTX *ctxt; + u_char tk[SHA256_DIGEST_LENGTH]; + u_char *key; + size_t keylen; + size_t i; + + if (!state) + panic("ah_hmac_sha2_256_init: what?"); + + state->sav = sav; + state->foo = (void *)_MALLOC(64 + 64 + sizeof(SHA256_CTX), + M_TEMP, M_NOWAIT); + if (!state->foo) + return ENOBUFS; + + ipad = (u_char *)state->foo; + opad = (u_char *)(ipad + 64); + ctxt = (SHA256_CTX *)(opad + 64); + + /* compress the key if necessery */ + if (64 < _KEYLEN(state->sav->key_auth)) { + bzero(tk, sizeof(tk)); + bzero(ctxt, sizeof(*ctxt)); + SHA256_Init(ctxt); + SHA256_Update(ctxt, _KEYBUF(state->sav->key_auth), + _KEYLEN(state->sav->key_auth)); + SHA256_Final(&tk[0], ctxt); + key = &tk[0]; + keylen = sizeof(tk) < 64 ? sizeof(tk) : 64; + } else { + key = _KEYBUF(state->sav->key_auth); + keylen = _KEYLEN(state->sav->key_auth); + } + + bzero(ipad, 64); + bzero(opad, 64); + bcopy(key, ipad, keylen); + bcopy(key, opad, keylen); + for (i = 0; i < 64; i++) { + ipad[i] ^= 0x36; + opad[i] ^= 0x5c; + } + + bzero(ctxt, sizeof(*ctxt)); + SHA256_Init(ctxt); + SHA256_Update(ctxt, ipad, 64); + + return 0; +} + +static void +ah_hmac_sha2_256_loop(state, addr, len) + struct ah_algorithm_state *state; + caddr_t addr; + size_t len; +{ + SHA256_CTX *ctxt; + + if (!state || !state->foo) + panic("ah_hmac_sha2_256_loop: what?"); + + ctxt = (SHA256_CTX *)(((u_char *)state->foo) + 128); + SHA256_Update(ctxt, (caddr_t)addr, (size_t)len); +} + +static void +ah_hmac_sha2_256_result(state, addr) + struct ah_algorithm_state *state; + caddr_t addr; +{ + u_char digest[SHA256_DIGEST_LENGTH]; + u_char *ipad; + u_char *opad; + SHA256_CTX *ctxt; + + if (!state || !state->foo) + panic("ah_hmac_sha2_256_result: what?"); + + ipad = (u_char *)state->foo; + opad = (u_char *)(ipad + 64); + ctxt = (SHA256_CTX *)(opad + 64); + + SHA256_Final((caddr_t)&digest[0], ctxt); + + bzero(ctxt, sizeof(*ctxt)); + SHA256_Init(ctxt); + SHA256_Update(ctxt, opad, 64); + SHA256_Update(ctxt, (caddr_t)&digest[0], sizeof(digest)); + SHA256_Final((caddr_t)&digest[0], ctxt); + + bcopy(&digest[0], (void *)addr, HMACSIZE); + + FREE(state->foo, M_TEMP); +} + +static int +ah_hmac_sha2_384_mature(sav) + struct secasvar *sav; +{ + const struct ah_algorithm *algo; + + if (!sav->key_auth) { + ipseclog((LOG_ERR, + "ah_hmac_sha2_384_mature: no key is given.\n")); + return 1; + } + + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { + ipseclog((LOG_ERR, + "ah_hmac_sha2_384_mature: unsupported algorithm.\n")); + return 1; + } + + if (sav->key_auth->sadb_key_bits < algo->keymin || + algo->keymax < sav->key_auth->sadb_key_bits) { + ipseclog((LOG_ERR, + "ah_hmac_sha2_384_mature: invalid key length %d.\n", + sav->key_auth->sadb_key_bits)); + return 1; + } + + return 0; +} + +static int +ah_hmac_sha2_384_init(state, sav) + struct ah_algorithm_state *state; + struct secasvar *sav; +{ + u_char *ipad; + u_char *opad; + SHA384_CTX *ctxt; + u_char tk[SHA384_DIGEST_LENGTH]; + u_char *key; + size_t keylen; + size_t i; + + if (!state) + panic("ah_hmac_sha2_384_init: what?"); + + state->sav = sav; + state->foo = (void *)_MALLOC(64 + 64 + sizeof(SHA384_CTX), + M_TEMP, M_NOWAIT); + if (!state->foo) + return ENOBUFS; + bzero(state->foo, 64 + 64 + sizeof(SHA384_CTX)); + + ipad = (u_char *)state->foo; + opad = (u_char *)(ipad + 64); + ctxt = (SHA384_CTX *)(opad + 64); + + /* compress the key if necessery */ + if (64 < _KEYLEN(state->sav->key_auth)) { + bzero(tk, sizeof(tk)); + bzero(ctxt, sizeof(*ctxt)); + SHA384_Init(ctxt); + SHA384_Update(ctxt, _KEYBUF(state->sav->key_auth), + _KEYLEN(state->sav->key_auth)); + SHA384_Final(&tk[0], ctxt); + key = &tk[0]; + keylen = sizeof(tk) < 64 ? sizeof(tk) : 64; + } else { + key = _KEYBUF(state->sav->key_auth); + keylen = _KEYLEN(state->sav->key_auth); + } + + bzero(ipad, 64); + bzero(opad, 64); + bcopy(key, ipad, keylen); + bcopy(key, opad, keylen); + for (i = 0; i < 64; i++) { + ipad[i] ^= 0x36; + opad[i] ^= 0x5c; + } + + bzero(ctxt, sizeof(*ctxt)); + SHA384_Init(ctxt); + SHA384_Update(ctxt, ipad, 64); + + return 0; +} + +static void +ah_hmac_sha2_384_loop(state, addr, len) + struct ah_algorithm_state *state; + caddr_t addr; + size_t len; +{ + SHA384_CTX *ctxt; + + if (!state || !state->foo) + panic("ah_hmac_sha2_384_loop: what?"); + + ctxt = (SHA384_CTX *)(((u_char *)state->foo) + 128); + SHA384_Update(ctxt, (caddr_t)addr, (size_t)len); +} + +static void +ah_hmac_sha2_384_result(state, addr) + struct ah_algorithm_state *state; + caddr_t addr; +{ + u_char digest[SHA384_DIGEST_LENGTH]; + u_char *ipad; + u_char *opad; + SHA384_CTX *ctxt; + + if (!state || !state->foo) + panic("ah_hmac_sha2_384_result: what?"); + + ipad = (u_char *)state->foo; + opad = (u_char *)(ipad + 64); + ctxt = (SHA384_CTX *)(opad + 64); + + SHA384_Final((caddr_t)&digest[0], ctxt); + + bzero(ctxt, sizeof(*ctxt)); + SHA384_Init(ctxt); + SHA384_Update(ctxt, opad, 64); + SHA384_Update(ctxt, (caddr_t)&digest[0], sizeof(digest)); + SHA384_Final((caddr_t)&digest[0], ctxt); + + bcopy(&digest[0], (void *)addr, HMACSIZE); + + FREE(state->foo, M_TEMP); +} + +static int +ah_hmac_sha2_512_mature(sav) + struct secasvar *sav; +{ + const struct ah_algorithm *algo; + + if (!sav->key_auth) { + ipseclog((LOG_ERR, + "ah_hmac_sha2_512_mature: no key is given.\n")); + return 1; + } + + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { + ipseclog((LOG_ERR, + "ah_hmac_sha2_512_mature: unsupported algorithm.\n")); + return 1; + } + + if (sav->key_auth->sadb_key_bits < algo->keymin || + algo->keymax < sav->key_auth->sadb_key_bits) { + ipseclog((LOG_ERR, + "ah_hmac_sha2_512_mature: invalid key length %d.\n", + sav->key_auth->sadb_key_bits)); + return 1; + } + + return 0; +} + +static int +ah_hmac_sha2_512_init(state, sav) + struct ah_algorithm_state *state; + struct secasvar *sav; +{ + u_char *ipad; + u_char *opad; + SHA512_CTX *ctxt; + u_char tk[SHA512_DIGEST_LENGTH]; + u_char *key; + size_t keylen; + size_t i; + + if (!state) + panic("ah_hmac_sha2_512_init: what?"); + + state->sav = sav; + state->foo = (void *)_MALLOC(64 + 64 + sizeof(SHA512_CTX), + M_TEMP, M_NOWAIT); + if (!state->foo) + return ENOBUFS; + bzero(state->foo, 64 + 64 + sizeof(SHA512_CTX)); + + ipad = (u_char *)state->foo; + opad = (u_char *)(ipad + 64); + ctxt = (SHA512_CTX *)(opad + 64); + + /* compress the key if necessery */ + if (64 < _KEYLEN(state->sav->key_auth)) { + bzero(tk, sizeof(tk)); + bzero(ctxt, sizeof(*ctxt)); + SHA512_Init(ctxt); + SHA512_Update(ctxt, _KEYBUF(state->sav->key_auth), + _KEYLEN(state->sav->key_auth)); + SHA512_Final(&tk[0], ctxt); + key = &tk[0]; + keylen = sizeof(tk) < 64 ? sizeof(tk) : 64; + } else { + key = _KEYBUF(state->sav->key_auth); + keylen = _KEYLEN(state->sav->key_auth); + } + + bzero(ipad, 64); + bzero(opad, 64); + bcopy(key, ipad, keylen); + bcopy(key, opad, keylen); + for (i = 0; i < 64; i++) { + ipad[i] ^= 0x36; + opad[i] ^= 0x5c; + } + + bzero(ctxt, sizeof(*ctxt)); + SHA512_Init(ctxt); + SHA512_Update(ctxt, ipad, 64); + + return 0; +} + +static void +ah_hmac_sha2_512_loop(state, addr, len) + struct ah_algorithm_state *state; + caddr_t addr; + size_t len; +{ + SHA512_CTX *ctxt; + + if (!state || !state->foo) + panic("ah_hmac_sha2_512_loop: what?"); + + ctxt = (SHA512_CTX *)(((u_char *)state->foo) + 128); + SHA512_Update(ctxt, (caddr_t)addr, (size_t)len); +} + +static void +ah_hmac_sha2_512_result(state, addr) + struct ah_algorithm_state *state; + caddr_t addr; +{ + u_char digest[SHA512_DIGEST_LENGTH]; + u_char *ipad; + u_char *opad; + SHA512_CTX *ctxt; + + if (!state || !state->foo) + panic("ah_hmac_sha2_512_result: what?"); + + ipad = (u_char *)state->foo; + opad = (u_char *)(ipad + 64); + ctxt = (SHA512_CTX *)(opad + 64); + + SHA512_Final((caddr_t)&digest[0], ctxt); + + bzero(ctxt, sizeof(*ctxt)); + SHA512_Init(ctxt); + SHA512_Update(ctxt, opad, 64); + SHA512_Update(ctxt, (caddr_t)&digest[0], sizeof(digest)); + SHA512_Final((caddr_t)&digest[0], ctxt); + + bcopy(&digest[0], (void *)addr, HMACSIZE); + + FREE(state->foo, M_TEMP); } /*------------------------------------------------------------*/ @@ -663,7 +1131,7 @@ ah_update_mbuf(m, off, len, algo, algos) struct mbuf *m; int off; int len; - struct ah_algorithm *algo; + const struct ah_algorithm *algo; struct ah_algorithm_state *algos; { struct mbuf *n; @@ -700,6 +1168,7 @@ ah_update_mbuf(m, off, len, algo, algos) } } +#if INET /* * Go generate the checksum. This function won't modify the mbuf chain * except AH itself. @@ -708,10 +1177,11 @@ ah_update_mbuf(m, off, len, algo, algos) * Don't use m_copy(), it will try to share cluster mbuf by using refcnt. */ int -ah4_calccksum(m, ahdat, algo, sav) +ah4_calccksum(m, ahdat, len, algo, sav) struct mbuf *m; caddr_t ahdat; - struct ah_algorithm *algo; + size_t len; + const struct ah_algorithm *algo; struct secasvar *sav; { int off; @@ -731,7 +1201,9 @@ ah4_calccksum(m, ahdat, algo, sav) off = 0; - (algo->init)(&algos, sav); + error = (algo->init)(&algos, sav); + if (error) + return error; advancewidth = 0; /*safety*/ @@ -748,7 +1220,7 @@ again: size_t hlen; m_copydata(m, off, sizeof(iphdr), (caddr_t)&iphdr); -#ifdef _IP_VHL +#if _IP_VHL hlen = IP_VHL_HL(iphdr.ip_vhl) << 2; #else hlen = iphdr.ip_hl << 2; @@ -789,6 +1261,25 @@ again: p = mtod(n, u_char *); i = sizeof(struct ip); while (i < hlen) { + if (i + IPOPT_OPTVAL >= hlen) { + ipseclog((LOG_ERR, "ah4_calccksum: " + "invalid IP option\n")); + error = EINVAL; + goto fail; + } + if (p[i + IPOPT_OPTVAL] == IPOPT_EOL || + p[i + IPOPT_OPTVAL] == IPOPT_NOP || + i + IPOPT_OLEN < hlen) + ; + else { + ipseclog((LOG_ERR, + "ah4_calccksum: invalid IP option " + "(type=%02x)\n", + p[i + IPOPT_OPTVAL])); + error = EINVAL; + goto fail; + } + skip = 1; switch (p[i + IPOPT_OPTVAL]) { case IPOPT_EOL: @@ -802,21 +1293,24 @@ again: case 0x94: /* Router alert */ case 0x95: /* RFC1770 */ l = p[i + IPOPT_OLEN]; + if (l < 2) + goto invalopt; skip = 0; break; default: l = p[i + IPOPT_OLEN]; + if (l < 2) + goto invalopt; skip = 1; break; } - if (l <= 0 || hlen - i < l) { + if (l < 1 || hlen - i < l) { + invalopt: ipseclog((LOG_ERR, "ah4_calccksum: invalid IP option " "(type=%02x len=%02x)\n", p[i + IPOPT_OPTVAL], p[i + IPOPT_OLEN])); - m_free(n); - n = NULL; error = EINVAL; goto fail; } @@ -898,6 +1392,11 @@ again: if (off < m->m_pkthdr.len) goto again; + if (len < (*algo->sumsiz)(sav)) { + error = EINVAL; + goto fail; + } + (algo->result)(&algos, &sumbuf[0]); bcopy(&sumbuf[0], ahdat, (*algo->sumsiz)(sav)); @@ -910,6 +1409,7 @@ fail: m_free(n); return error; } +#endif #if INET6 /* @@ -920,10 +1420,11 @@ fail: * Don't use m_copy(), it will try to share cluster mbuf by using refcnt. */ int -ah6_calccksum(m, ahdat, algo, sav) +ah6_calccksum(m, ahdat, len, algo, sav) struct mbuf *m; caddr_t ahdat; - struct ah_algorithm *algo; + size_t len; + const struct ah_algorithm *algo; struct secasvar *sav; { int newoff, off; @@ -937,7 +1438,9 @@ ah6_calccksum(m, ahdat, algo, sav) if ((m->m_flags & M_PKTHDR) == 0) return EINVAL; - (algo->init)(&algos, sav); + error = (algo->init)(&algos, sav); + if (error) + return error; off = 0; proto = IPPROTO_IPV6; @@ -1116,6 +1619,11 @@ ah6_calccksum(m, ahdat, algo, sav) goto again; } + if (len < (*algo->sumsiz)(sav)) { + error = EINVAL; + goto fail; + } + (algo->result)(&algos, &sumbuf[0]); bcopy(&sumbuf[0], ahdat, (*algo->sumsiz)(sav)); diff --git a/bsd/netinet6/ah_input.c b/bsd/netinet6/ah_input.c index 0b76ad007..7f72ff119 100644 --- a/bsd/netinet6/ah_input.c +++ b/bsd/netinet6/ah_input.c @@ -1,3 +1,6 @@ +/* $FreeBSD: src/sys/netinet6/ah_input.c,v 1.1.2.4 2001/07/03 11:01:49 ume Exp $ */ +/* $KAME: ah_input.c,v 1.59 2001/05/16 04:01:27 jinmei Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. @@ -31,11 +34,6 @@ * RFC1826/2402 authentication header. */ -#define _IP_VHL -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#endif - #include #include #include @@ -59,18 +57,34 @@ #include #include #include +#include +#if INET6 +#include +#endif #if INET6 #include #include +#include #include +#include #endif #include +#if INET6 +#include +#endif #include +#if INET6 +#include +#endif #include #include +#if IPSEC_DEBUG #include +#else +#define KEYDEBUG(lev,arg) +#endif #include @@ -79,9 +93,6 @@ #if INET extern struct protosw inetsw[]; -#if defined(__bsdi__) || defined(__NetBSD__) -extern u_char ip_protox[]; -#endif void ah4_input(struct mbuf *m, int off) @@ -89,7 +100,7 @@ ah4_input(struct mbuf *m, int off) struct ip *ip; struct ah *ah; u_int32_t spi; - struct ah_algorithm *algo; + const struct ah_algorithm *algo; size_t siz; size_t siz1; u_char *cksum; @@ -97,6 +108,8 @@ ah4_input(struct mbuf *m, int off) u_int16_t nxt; size_t hlen; int s; + size_t stripsiz = 0; + #ifndef PULLDOWN_TEST if (m->m_len < off + sizeof(struct newah)) { @@ -150,16 +163,16 @@ ah4_input(struct mbuf *m, int off) ipsecstat.in_badspi++; goto fail; } - if (sav->alg_auth == SADB_AALG_NONE) { + + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { ipseclog((LOG_DEBUG, "IPv4 AH input: " - "unspecified authentication algorithm for spi %u\n", + "unsupported authentication algorithm for spi %u\n", (u_int32_t)ntohl(spi))); ipsecstat.in_badspi++; goto fail; } - algo = &ah_algorithms[sav->alg_auth]; - siz = (*algo->sumsiz)(sav); siz1 = ((siz + 3) & ~(4 - 1)); @@ -171,11 +184,40 @@ ah4_input(struct mbuf *m, int off) sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4; + /* + * Here, we do not do "siz1 == siz". This is because the way + * RFC240[34] section 2 is written. They do not require truncation + * to 96 bits. + * For example, Microsoft IPsec stack attaches 160 bits of + * authentication data for both hmac-md5 and hmac-sha1. For hmac-sha1, + * 32 bits of padding is attached. + * + * There are two downsides to this specification. + * They have no real harm, however, they leave us fuzzy feeling. + * - if we attach more than 96 bits of authentication data onto AH, + * we will never notice about possible modification by rogue + * intermediate nodes. + * Since extra bits in AH checksum is never used, this constitutes + * no real issue, however, it is wacky. + * - even if the peer attaches big authentication data, we will never + * notice the difference, since longer authentication data will just + * work. + * + * We may need some clarification in the spec. + */ + if (siz1 < siz) { + ipseclog((LOG_NOTICE, "sum length too short in IPv4 AH input " + "(%lu, should be at least %lu): %s\n", + (u_long)siz1, (u_long)siz, + ipsec4_logpacketstr(ip, spi))); + ipsecstat.in_inval++; + goto fail; + } if ((ah->ah_len << 2) - sizoff != siz1) { ipseclog((LOG_NOTICE, "sum length mismatch in IPv4 AH input " - "(%d should be %u): %s\n", - (ah->ah_len << 2) - sizoff, (unsigned int)siz1, - ipsec4_logpacketstr(ip, spi))); + "(%d should be %lu): %s\n", + (ah->ah_len << 2) - sizoff, (u_long)siz1, + ipsec4_logpacketstr(ip, spi))); ipsecstat.in_inval++; goto fail; } @@ -230,39 +272,23 @@ ah4_input(struct mbuf *m, int off) goto fail; } - { -#if 1 /* * some of IP header fields are flipped to the host endian. * convert them back to network endian. VERY stupid. */ -#ifndef __NetBSD__ ip->ip_len = htons(ip->ip_len + hlen); - ip->ip_id = htons(ip->ip_id); -#else - ip->ip_len = htons(ip->ip_len); -#endif ip->ip_off = htons(ip->ip_off); -#endif - if (ah4_calccksum(m, (caddr_t)cksum, algo, sav)) { - _FREE(cksum, M_TEMP); + if (ah4_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) { + FREE(cksum, M_TEMP); ipsecstat.in_inval++; goto fail; } ipsecstat.in_ahhist[sav->alg_auth]++; -#if 1 /* * flip them back. */ -#ifndef __NetBSD__ ip->ip_len = ntohs(ip->ip_len) - hlen; - ip->ip_id = ntohs(ip->ip_id); -#else - ip->ip_len = ntohs(ip->ip_len); -#endif ip->ip_off = ntohs(ip->ip_off); -#endif - } { caddr_t sumpos = NULL; @@ -279,13 +305,13 @@ ah4_input(struct mbuf *m, int off) ipseclog((LOG_WARNING, "checksum mismatch in IPv4 AH input: %s %s\n", ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); - _FREE(cksum, M_TEMP); + FREE(cksum, M_TEMP); ipsecstat.in_ahauthfail++; goto fail; } } - _FREE(cksum, M_TEMP); + FREE(cksum, M_TEMP); m->m_flags |= M_AUTHIPHDR; m->m_flags |= M_AUTHIPDGM; @@ -353,7 +379,14 @@ ah4_input(struct mbuf *m, int off) } /* was it transmitted over the IPsec tunnel SA? */ - if (ipsec4_tunnel_validate(ip, nxt, sav) && nxt == IPPROTO_IPV4) { + if (sav->flags & SADB_X_EXT_OLD) { + /* RFC 1826 */ + stripsiz = sizeof(struct ah) + siz1; + } else { + /* RFC 2402 */ + stripsiz = sizeof(struct newah) + siz1; + } + if (ipsec4_tunnel_validate(m, off + stripsiz, nxt, sav)) { /* * strip off all the headers that precedes AH. * IP xx AH IP' payload -> IP' payload @@ -361,17 +394,9 @@ ah4_input(struct mbuf *m, int off) * XXX more sanity checks * XXX relationship with gif? */ - size_t stripsiz = 0; u_int8_t tos; tos = ip->ip_tos; - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1826 */ - stripsiz = sizeof(struct ah) + siz1; - } else { - /* RFC 2402 */ - stripsiz = sizeof(struct newah) + siz1; - } m_adj(m, off + stripsiz); if (m->m_len < sizeof(*ip)) { m = m_pullup(m, sizeof(*ip)); @@ -425,10 +450,16 @@ ah4_input(struct mbuf *m, int off) #endif key_sa_recordxfer(sav, m); + if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 || + ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) { + ipsecstat.in_nomem++; + goto fail; + } s = splimp(); if (IF_QFULL(&ipintrq)) { ipsecstat.in_inval++; + splx(s); goto fail; } IF_ENQUEUE(&ipintrq, m); @@ -439,21 +470,14 @@ ah4_input(struct mbuf *m, int off) } else { /* * strip off AH. - * We do deep-copy since KAME requires that - * the packet is placed in a single external mbuf. */ - size_t stripsiz = 0; - - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1826 */ - stripsiz = sizeof(struct ah) + siz1; - } else { - /* RFC 2402 */ - stripsiz = sizeof(struct newah) + siz1; - } ip = mtod(m, struct ip *); #ifndef PULLDOWN_TEST + /* + * We do deep-copy since KAME requires that + * the packet is placed in a single external mbuf. + */ ovbcopy((caddr_t)ip, (caddr_t)(((u_char *)ip) + stripsiz), off); m->m_data += stripsiz; m->m_len -= stripsiz; @@ -504,10 +528,19 @@ ah4_input(struct mbuf *m, int off) /* forget about IP hdr checksum, the check has already been passed */ key_sa_recordxfer(sav, m); + if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) { + ipsecstat.in_nomem++; + goto fail; + } - if (nxt != IPPROTO_DONE) + if (nxt != IPPROTO_DONE) { + if ((ip_protox[nxt]->pr_flags & PR_LASTHDR) != 0 && + ipsec4_in_reject(m, NULL)) { + ipsecstat.in_polvio++; + goto fail; + } (*ip_protox[nxt]->pr_input)(m, off); - else + } else m_freem(m); m = NULL; } @@ -543,13 +576,14 @@ ah6_input(mp, offp, proto) struct ip6_hdr *ip6; struct ah *ah; u_int32_t spi; - struct ah_algorithm *algo; + const struct ah_algorithm *algo; size_t siz; size_t siz1; u_char *cksum; struct secasvar *sav = NULL; u_int16_t nxt; int s; + size_t stripsiz = 0; #ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, sizeof(struct ah), IPPROTO_DONE); @@ -558,7 +592,7 @@ ah6_input(mp, offp, proto) IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah)); if (ah == NULL) { ipseclog((LOG_DEBUG, "IPv6 AH input: can't pullup\n")); - ipsecstat.in_inval++; + ipsec6stat.in_inval++; return IPPROTO_DONE; } #endif @@ -594,16 +628,16 @@ ah6_input(mp, offp, proto) ipsec6stat.in_badspi++; goto fail; } - if (sav->alg_auth == SADB_AALG_NONE) { + + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { ipseclog((LOG_DEBUG, "IPv6 AH input: " - "unspecified authentication algorithm for spi %u\n", + "unsupported authentication algorithm for spi %u\n", (u_int32_t)ntohl(spi))); ipsec6stat.in_badspi++; goto fail; } - algo = &ah_algorithms[sav->alg_auth]; - siz = (*algo->sumsiz)(sav); siz1 = ((siz + 3) & ~(4 - 1)); @@ -615,11 +649,23 @@ ah6_input(mp, offp, proto) sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4; + /* + * Here, we do not do "siz1 == siz". See ah4_input() for complete + * description. + */ + if (siz1 < siz) { + ipseclog((LOG_NOTICE, "sum length too short in IPv6 AH input " + "(%lu, should be at least %lu): %s\n", + (u_long)siz1, (u_long)siz, + ipsec6_logpacketstr(ip6, spi))); + ipsec6stat.in_inval++; + goto fail; + } if ((ah->ah_len << 2) - sizoff != siz1) { ipseclog((LOG_NOTICE, "sum length mismatch in IPv6 AH input " - "(%d should be %u): %s\n", - (ah->ah_len << 2) - sizoff, (unsigned int)siz1, - ipsec6_logpacketstr(ip6, spi))); + "(%d should be %lu): %s\n", + (ah->ah_len << 2) - sizoff, (u_long)siz1, + ipsec6_logpacketstr(ip6, spi))); ipsec6stat.in_inval++; goto fail; } @@ -630,7 +676,7 @@ ah6_input(mp, offp, proto) sizeof(struct ah) + sizoff + siz1); if (ah == NULL) { ipseclog((LOG_NOTICE, "couldn't pullup gather IPv6 AH checksum part")); - ipsecstat.in_inval++; + ipsec6stat.in_inval++; m = NULL; goto fail; } @@ -665,8 +711,8 @@ ah6_input(mp, offp, proto) goto fail; } - if (ah6_calccksum(m, (caddr_t)cksum, algo, sav)) { - _FREE(cksum, M_TEMP); + if (ah6_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) { + FREE(cksum, M_TEMP); ipsec6stat.in_inval++; goto fail; } @@ -687,13 +733,13 @@ ah6_input(mp, offp, proto) ipseclog((LOG_WARNING, "checksum mismatch in IPv6 AH input: %s %s\n", ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); - _FREE(cksum, M_TEMP); + FREE(cksum, M_TEMP); ipsec6stat.in_ahauthfail++; goto fail; } } - _FREE(cksum, M_TEMP); + FREE(cksum, M_TEMP); m->m_flags |= M_AUTHIPHDR; m->m_flags |= M_AUTHIPDGM; @@ -753,7 +799,14 @@ ah6_input(mp, offp, proto) } /* was it transmitted over the IPsec tunnel SA? */ - if (ipsec6_tunnel_validate(ip6, nxt, sav) && nxt == IPPROTO_IPV6) { + if (sav->flags & SADB_X_EXT_OLD) { + /* RFC 1826 */ + stripsiz = sizeof(struct ah) + siz1; + } else { + /* RFC 2402 */ + stripsiz = sizeof(struct newah) + siz1; + } + if (ipsec6_tunnel_validate(m, off + stripsiz, nxt, sav)) { /* * strip off all the headers that precedes AH. * IP6 xx AH IP6' payload -> IP6' payload @@ -761,17 +814,9 @@ ah6_input(mp, offp, proto) * XXX more sanity checks * XXX relationship with gif? */ - size_t stripsiz = 0; u_int32_t flowinfo; /*net endian*/ flowinfo = ip6->ip6_flow; - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1826 */ - stripsiz = sizeof(struct ah) + siz1; - } else { - /* RFC 2402 */ - stripsiz = sizeof(struct newah) + siz1; - } m_adj(m, off + stripsiz); if (m->m_len < sizeof(*ip6)) { /* @@ -815,10 +860,16 @@ ah6_input(mp, offp, proto) #endif key_sa_recordxfer(sav, m); + if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 || + ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) { + ipsec6stat.in_nomem++; + goto fail; + } s = splimp(); if (IF_QFULL(&ip6intrq)) { ipsec6stat.in_inval++; + splx(s); goto fail; } IF_ENQUEUE(&ip6intrq, m); @@ -829,10 +880,7 @@ ah6_input(mp, offp, proto) } else { /* * strip off AH. - * We do deep-copy since KAME requires that - * the packet is placed in a single mbuf. */ - size_t stripsiz = 0; char *prvnxtp; /* @@ -843,16 +891,12 @@ ah6_input(mp, offp, proto) prvnxtp = ip6_get_prevhdr(m, off); /* XXX */ *prvnxtp = nxt; - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1826 */ - stripsiz = sizeof(struct ah) + siz1; - } else { - /* RFC 2402 */ - stripsiz = sizeof(struct newah) + siz1; - } - ip6 = mtod(m, struct ip6_hdr *); #ifndef PULLDOWN_TEST + /* + * We do deep-copy since KAME requires that + * the packet is placed in a single mbuf. + */ ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off); m->m_data += stripsiz; m->m_len -= stripsiz; @@ -890,6 +934,10 @@ ah6_input(mp, offp, proto) ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz); key_sa_recordxfer(sav, m); + if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) { + ipsec6stat.in_nomem++; + goto fail; + } } *offp = off; @@ -913,4 +961,92 @@ fail: m_freem(m); return IPPROTO_DONE; } + +void +ah6_ctlinput(cmd, sa, d) + int cmd; + struct sockaddr *sa; + void *d; +{ + const struct newah *ahp; + struct newah ah; + struct secasvar *sav; + struct ip6_hdr *ip6; + struct mbuf *m; + struct ip6ctlparam *ip6cp = NULL; + int off; + struct sockaddr_in6 sa6_src, sa6_dst; + + if (sa->sa_family != AF_INET6 || + sa->sa_len != sizeof(struct sockaddr_in6)) + return; + if ((unsigned)cmd >= PRC_NCMDS) + return; + + /* if the parameter is from icmp6, decode it. */ + if (d != NULL) { + ip6cp = (struct ip6ctlparam *)d; + m = ip6cp->ip6c_m; + ip6 = ip6cp->ip6c_ip6; + off = ip6cp->ip6c_off; + } else { + m = NULL; + ip6 = NULL; + } + + if (ip6) { + /* + * XXX: We assume that when ip6 is non NULL, + * M and OFF are valid. + */ + + /* check if we can safely examine src and dst ports */ + if (m->m_pkthdr.len < off + sizeof(ah)) + return; + + if (m->m_len < off + sizeof(ah)) { + /* + * this should be rare case, + * so we compromise on this copy... + */ + m_copydata(m, off, sizeof(ah), (caddr_t)&ah); + ahp = &ah; + } else + ahp = (struct newah *)(mtod(m, caddr_t) + off); + + if (cmd == PRC_MSGSIZE) { + int valid = 0; + + /* + * Check to see if we have a valid SA corresponding to + * the address in the ICMP message payload. + */ + sav = key_allocsa(AF_INET6, + (caddr_t)&sa6_src.sin6_addr, + (caddr_t)&sa6_dst.sin6_addr, + IPPROTO_AH, ahp->ah_spi); + if (sav) { + if (sav->state == SADB_SASTATE_MATURE || + sav->state == SADB_SASTATE_DYING) + valid++; + key_freesav(sav); + } + + /* XXX Further validation? */ + + /* + * Depending on the value of "valid" and routing table + * size (mtudisc_{hi,lo}wat), we will: + * - recalcurate the new MTU and create the + * corresponding routing entry, or + * - ignore the MTU change notification. + */ + icmp6_mtudisc_update((struct ip6ctlparam *)d, valid); + } + + /* we normally notify single pcb here */ + } else { + /* we normally notify any pcb here */ + } +} #endif /* INET6 */ diff --git a/bsd/netinet6/ah_output.c b/bsd/netinet6/ah_output.c index e8c81b01f..5a4f92cff 100644 --- a/bsd/netinet6/ah_output.c +++ b/bsd/netinet6/ah_output.c @@ -1,4 +1,5 @@ -/* $KAME: ah_output.c,v 1.17 2000/03/09 08:54:48 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/ah_output.c,v 1.1.2.3 2001/07/03 11:01:49 ume Exp $ */ +/* $KAME: ah_output.c,v 1.30 2001/02/21 00:50:53 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -34,9 +35,6 @@ */ #define _IP_VHL -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#endif #include #include @@ -67,14 +65,21 @@ #endif #include +#if INET6 +#include +#endif #include +#if INET6 +#include +#endif #include #include -#include #include +#if INET static struct in_addr *ah4_finaldst __P((struct mbuf *)); +#endif /* * compute AH header size. @@ -85,7 +90,7 @@ size_t ah_hdrsiz(isr) struct ipsecrequest *isr; { - struct ah_algorithm *algo; + const struct ah_algorithm *algo; size_t hdrsiz; /* sanity check */ @@ -102,7 +107,7 @@ ah_hdrsiz(isr) goto estimate; /* we need transport mode AH. */ - algo = &ah_algorithms[isr->sav->alg_auth]; + algo = ah_algorithm_lookup(isr->sav->alg_auth); if (!algo) goto estimate; @@ -129,6 +134,7 @@ ah_hdrsiz(isr) return sizeof(struct newah) + 16; } +#if INET /* * Modify the packet so that it includes the authentication data. * The mbuf passed must start with IPv4 header. @@ -142,7 +148,7 @@ ah4_output(m, isr) struct ipsecrequest *isr; { struct secasvar *sav = isr->sav; - struct ah_algorithm *algo; + const struct ah_algorithm *algo; u_int32_t spi; u_char *ahdrpos; u_char *ahsumpos = NULL; @@ -169,7 +175,14 @@ ah4_output(m, isr) return EINVAL; } - algo = &ah_algorithms[sav->alg_auth]; + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { + ipseclog((LOG_ERR, "ah4_output: unsupported algorithm: " + "SPI=%u\n", (u_int32_t)ntohl(sav->spi))); + ipsecstat.out_inval++; + m_freem(m); + return EINVAL; + } spi = sav->spi; /* @@ -292,10 +305,11 @@ ah4_output(m, isr) * calcurate the checksum, based on security association * and the algorithm specified. */ - error = ah4_calccksum(m, (caddr_t)ahsumpos, algo, sav); + error = ah4_calccksum(m, (caddr_t)ahsumpos, plen, algo, sav); if (error) { ipseclog((LOG_ERR, "error after ah4_calccksum, called from ah4_output")); + m_freem(m); m = NULL; ipsecstat.out_inval++; return error; @@ -311,16 +325,19 @@ ah4_output(m, isr) return 0; } +#endif /* Calculate AH length */ int ah_hdrlen(sav) struct secasvar *sav; { - struct ah_algorithm *algo; + const struct ah_algorithm *algo; int plen, ahlen; - algo = &ah_algorithms[sav->alg_auth]; + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) + return 0; if (sav->flags & SADB_X_EXT_OLD) { /* RFC 1826 */ plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1); /*XXX pad to 8byte?*/ @@ -348,7 +365,7 @@ ah6_output(m, nexthdrp, md, isr) struct mbuf *mprev; struct mbuf *mah; struct secasvar *sav = isr->sav; - struct ah_algorithm *algo; + const struct ah_algorithm *algo; u_int32_t spi; u_char *ahsumpos = NULL; size_t plen; /*AH payload size in bytes*/ @@ -411,7 +428,14 @@ ah6_output(m, nexthdrp, md, isr) return EINVAL; } - algo = &ah_algorithms[sav->alg_auth]; + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { + ipseclog((LOG_ERR, "ah6_output: unsupported algorithm: " + "SPI=%u\n", (u_int32_t)ntohl(sav->spi))); + ipsec6stat.out_inval++; + m_freem(m); + return EINVAL; + } spi = sav->spi; /* @@ -444,7 +468,7 @@ ah6_output(m, nexthdrp, md, isr) ipseclog((LOG_WARNING, "replay counter overflowed. %s\n", ipsec_logsastr(sav))); - ipsecstat.out_inval++; + ipsec6stat.out_inval++; m_freem(m); return EINVAL; } @@ -462,7 +486,7 @@ ah6_output(m, nexthdrp, md, isr) * calcurate the checksum, based on security association * and the algorithm specified. */ - error = ah6_calccksum(m, (caddr_t)ahsumpos, algo, sav); + error = ah6_calccksum(m, (caddr_t)ahsumpos, plen, algo, sav); if (error) { ipsec6stat.out_inval++; m_freem(m); @@ -476,6 +500,7 @@ ah6_output(m, nexthdrp, md, isr) } #endif +#if INET /* * Find the final destination if there is loose/strict source routing option. * Returns NULL if there's no source routing options. @@ -522,6 +547,15 @@ ah4_finaldst(m) q = (u_char *)(ip + 1); i = 0; while (i < optlen) { + if (i + IPOPT_OPTVAL >= optlen) + return NULL; + if (q[i + IPOPT_OPTVAL] == IPOPT_EOL || + q[i + IPOPT_OPTVAL] == IPOPT_NOP || + i + IPOPT_OLEN < optlen) + ; + else + return NULL; + switch (q[i + IPOPT_OPTVAL]) { case IPOPT_EOL: i = optlen; /* bye */ @@ -531,8 +565,8 @@ ah4_finaldst(m) break; case IPOPT_LSRR: case IPOPT_SSRR: - if (q[i + IPOPT_OLEN] <= 0 - || optlen - i < q[i + IPOPT_OLEN]) { + if (q[i + IPOPT_OLEN] < 2 + sizeof(struct in_addr) || + optlen - i < q[i + IPOPT_OLEN]) { ipseclog((LOG_ERR, "ip_finaldst: invalid IP option " "(code=%02x len=%02x)\n", @@ -542,8 +576,8 @@ ah4_finaldst(m) i += q[i + IPOPT_OLEN] - sizeof(struct in_addr); return (struct in_addr *)(q + i); default: - if (q[i + IPOPT_OLEN] <= 0 - || optlen - i < q[i + IPOPT_OLEN]) { + if (q[i + IPOPT_OLEN] < 2 || + optlen - i < q[i + IPOPT_OLEN]) { ipseclog((LOG_ERR, "ip_finaldst: invalid IP option " "(code=%02x len=%02x)\n", @@ -556,3 +590,4 @@ ah4_finaldst(m) } return NULL; } +#endif diff --git a/bsd/netinet6/dest6.c b/bsd/netinet6/dest6.c index eca5f3ca9..c5b713b14 100644 --- a/bsd/netinet6/dest6.c +++ b/bsd/netinet6/dest6.c @@ -1,4 +1,5 @@ -/* $KAME: dest6.c,v 1.10 2000/02/28 16:18:11 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/dest6.c,v 1.1.2.3 2001/07/03 11:01:49 ume Exp $ */ +/* $KAME: dest6.c,v 1.27 2001/03/29 05:34:30 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -47,17 +48,8 @@ #include #include #include -#if !(defined(__APPLE__)) -#include -#endif #include -#if MIP6 -int (*mip6_store_dstopt_pre_hook)(struct mbuf *m, u_int8_t *opt, - u_int8_t off, u_int8_t dstlen) = NULL; -int (*mip6_rec_ctrl_sig_hook)(struct mbuf *m, int off) = NULL; -#endif /* MIP6 */ - /* * Destination options header processing. */ @@ -66,10 +58,13 @@ dest6_input(mp, offp, proto) struct mbuf **mp; int *offp, proto; { - register struct mbuf *m = *mp; + struct mbuf *m = *mp; int off = *offp, dstoptlen, optlen; struct ip6_dest *dstopts; u_int8_t *opt; + struct ip6_hdr *ip6; + + ip6 = mtod(m, struct ip6_hdr *); /* validation of the length of the header */ #ifndef PULLDOWN_TEST @@ -96,59 +91,34 @@ dest6_input(mp, offp, proto) /* search header for all options. */ for (optlen = 0; dstoptlen > 0; dstoptlen -= optlen, opt += optlen) { - switch(*opt) { - case IP6OPT_PAD1: - optlen = 1; - break; - case IP6OPT_PADN: - if (dstoptlen < IP6OPT_MINLEN) { - ip6stat.ip6s_toosmall++; - goto bad; - } - optlen = *(opt + 1) + 2; - break; + if (*opt != IP6OPT_PAD1 && + (dstoptlen < IP6OPT_MINLEN || *(opt + 1) + 2 > dstoptlen)) { + ip6stat.ip6s_toosmall++; + goto bad; + } -#if MIP6 - case IP6OPT_BINDING_UPDATE: - case IP6OPT_BINDING_ACK: - case IP6OPT_BINDING_REQ: - case IP6OPT_HOME_ADDRESS: - if (mip6_store_dstopt_pre_hook) { - if ((*mip6_store_dstopt_pre_hook)(m, opt, off, dstoptlen) != 0) - goto bad; - } + switch (*opt) { + case IP6OPT_PAD1: + optlen = 1; + break; + case IP6OPT_PADN: optlen = *(opt + 1) + 2; break; -#endif /* MIP6 */ - default: /* unknown option */ - if (dstoptlen < IP6OPT_MINLEN) { - ip6stat.ip6s_toosmall++; - goto bad; - } - if ((optlen = ip6_unknown_opt(opt, m, - opt-mtod(m, u_int8_t *))) == -1) - return(IPPROTO_DONE); - optlen += 2; - break; + default: /* unknown option */ + optlen = ip6_unknown_opt(opt, m, + opt - mtod(m, u_int8_t *)); + if (optlen == -1) + return (IPPROTO_DONE); + optlen += 2; + break; } } -#if MIP6 - if (mip6_rec_ctrl_sig_hook) { - /* - * All Destinations options have been processed. Call MIPv6 to - * process stored options. - */ - if ((*mip6_rec_ctrl_sig_hook)(m, *offp) != 0) - return(IPPROTO_DONE); - } -#endif /* MIP6 */ - *offp = off; - return(dstopts->ip6d_nxt); + return (dstopts->ip6d_nxt); bad: m_freem(m); - return(IPPROTO_DONE); + return (IPPROTO_DONE); } diff --git a/bsd/netinet6/esp.h b/bsd/netinet6/esp.h index 8add062e1..295048940 100644 --- a/bsd/netinet6/esp.h +++ b/bsd/netinet6/esp.h @@ -1,4 +1,5 @@ -/* $KAME: esp.h,v 1.5 2000/02/22 14:04:15 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/esp.h,v 1.2.2.2 2001/07/03 11:01:49 ume Exp $ */ +/* $KAME: esp.h,v 1.16 2000/10/18 21:28:00 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -35,8 +36,8 @@ #ifndef _NETINET6_ESP_H_ #define _NETINET6_ESP_H_ +#include -#include /* for struct secas */ struct esp { u_int32_t esp_spi; /* ESP */ @@ -66,41 +67,43 @@ struct esptail { /*variable size, 32bit bound*/ /* Authentication data (new IPsec)*/ }; -struct esp_algorithm_state { - struct secasvar *sav; - void* foo; /*per algorithm data - maybe*/ -}; +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE +struct secasvar; -/* XXX yet to be defined */ struct esp_algorithm { size_t padbound; /* pad boundary, in byte */ + int ivlenval; /* iv length, in byte */ int (*mature) __P((struct secasvar *)); int keymin; /* in bits */ int keymax; /* in bits */ - int (*ivlen) __P((struct secasvar *)); + int (*schedlen) __P((const struct esp_algorithm *)); + const char *name; + int (*ivlen) __P((const struct esp_algorithm *, struct secasvar *)); int (*decrypt) __P((struct mbuf *, size_t, - struct secasvar *, struct esp_algorithm *, int)); + struct secasvar *, const struct esp_algorithm *, int)); int (*encrypt) __P((struct mbuf *, size_t, size_t, - struct secasvar *, struct esp_algorithm *, int)); + struct secasvar *, const struct esp_algorithm *, int)); + /* not supposed to be called directly */ + int (*schedule) __P((const struct esp_algorithm *, struct secasvar *)); + int (*blockdecrypt) __P((const struct esp_algorithm *, + struct secasvar *, u_int8_t *, u_int8_t *)); + int (*blockencrypt) __P((const struct esp_algorithm *, + struct secasvar *, u_int8_t *, u_int8_t *)); }; -#if KERNEL -extern struct esp_algorithm esp_algorithms[]; +extern const struct esp_algorithm *esp_algorithm_lookup __P((int)); +extern int esp_max_ivlen __P((void)); /* crypt routines */ extern int esp4_output __P((struct mbuf *, struct ipsecrequest *)); extern void esp4_input __P((struct mbuf *, int off)); extern size_t esp_hdrsiz __P((struct ipsecrequest *)); -#if INET6 -extern int esp6_output __P((struct mbuf *, u_char *, struct mbuf *, - struct ipsecrequest *)); -extern int esp6_input __P((struct mbuf **, int *, int)); -#endif /* INET6 */ -#endif /*KERNEL*/ - -struct secasvar; +extern int esp_schedule __P((const struct esp_algorithm *, struct secasvar *)); extern int esp_auth __P((struct mbuf *, size_t, size_t, struct secasvar *, u_char *)); +#endif /* __APPLE_API_PRIVATE */ +#endif /*KERNEL*/ #endif /*_NETINET6_ESP_H_*/ diff --git a/bsd/netinet6/esp6.h b/bsd/netinet6/esp6.h new file mode 100644 index 000000000..06dc625a9 --- /dev/null +++ b/bsd/netinet6/esp6.h @@ -0,0 +1,51 @@ +/* $FreeBSD: src/sys/netinet6/esp6.h,v 1.2.2.2 2001/07/03 11:01:49 ume Exp $ */ +/* $KAME: esp.h,v 1.16 2000/10/18 21:28:00 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * RFC1827/2406 Encapsulated Security Payload. + */ + +#ifndef _NETINET6_ESP6_H_ +#define _NETINET6_ESP6_H_ +#include + +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE +extern int esp6_output __P((struct mbuf *, u_char *, struct mbuf *, + struct ipsecrequest *)); +extern int esp6_input __P((struct mbuf **, int *, int)); + +extern void esp6_ctlinput __P((int, struct sockaddr *, void *)); +#endif /* __APPLE_API_PRIVATE */ +#endif /*_KERNEL*/ + +#endif /*_NETINET6_ESP6_H_*/ diff --git a/bsd/netinet6/esp_core.c b/bsd/netinet6/esp_core.c index 22ff54d80..0cdede849 100644 --- a/bsd/netinet6/esp_core.c +++ b/bsd/netinet6/esp_core.c @@ -1,4 +1,5 @@ -/* $KAME: esp_core.c,v 1.11 2000/02/22 14:04:15 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/esp_core.c,v 1.1.2.2 2001/07/03 11:01:49 ume Exp $ */ +/* $KAME: esp_core.c,v 1.50 2000/11/02 12:27:38 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -30,9 +31,6 @@ */ #define _IP_VHL -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#endif #include #include @@ -58,89 +56,192 @@ #endif #include +#if INET6 +#include +#endif #include +#if INET6 +#include +#endif #include +#if INET6 +#include +#endif +#include #include #include +#include #include #include #include -#include #include static int esp_null_mature __P((struct secasvar *)); -static int esp_null_ivlen __P((struct secasvar *)); static int esp_null_decrypt __P((struct mbuf *, size_t, - struct secasvar *, struct esp_algorithm *, int)); + struct secasvar *, const struct esp_algorithm *, int)); static int esp_null_encrypt __P((struct mbuf *, size_t, size_t, - struct secasvar *, struct esp_algorithm *, int)); + struct secasvar *, const struct esp_algorithm *, int)); static int esp_descbc_mature __P((struct secasvar *)); -static int esp_descbc_ivlen __P((struct secasvar *)); -static int esp_descbc_decrypt __P((struct mbuf *, size_t, - struct secasvar *, struct esp_algorithm *, int)); -static int esp_descbc_encrypt __P((struct mbuf *, size_t, size_t, - struct secasvar *, struct esp_algorithm *, int)); +static int esp_descbc_ivlen __P((const struct esp_algorithm *, + struct secasvar *)); +static int esp_des_schedule __P((const struct esp_algorithm *, + struct secasvar *)); +static int esp_des_schedlen __P((const struct esp_algorithm *)); +static int esp_des_blockdecrypt __P((const struct esp_algorithm *, + struct secasvar *, u_int8_t *, u_int8_t *)); +static int esp_des_blockencrypt __P((const struct esp_algorithm *, + struct secasvar *, u_int8_t *, u_int8_t *)); static int esp_cbc_mature __P((struct secasvar *)); -static int esp_blowfish_cbc_decrypt __P((struct mbuf *, size_t, - struct secasvar *, struct esp_algorithm *, int)); -static int esp_blowfish_cbc_encrypt __P((struct mbuf *, size_t, - size_t, struct secasvar *, struct esp_algorithm *, int)); -static int esp_blowfish_cbc_ivlen __P((struct secasvar *)); -static int esp_cast128cbc_ivlen __P((struct secasvar *)); -static int esp_cast128cbc_decrypt __P((struct mbuf *, size_t, - struct secasvar *, struct esp_algorithm *, int)); -static int esp_cast128cbc_encrypt __P((struct mbuf *, size_t, size_t, - struct secasvar *, struct esp_algorithm *, int)); -static int esp_3descbc_ivlen __P((struct secasvar *)); -static int esp_3descbc_decrypt __P((struct mbuf *, size_t, - struct secasvar *, struct esp_algorithm *, int)); -static int esp_3descbc_encrypt __P((struct mbuf *, size_t, size_t, - struct secasvar *, struct esp_algorithm *, int)); -static int esp_rc5cbc_ivlen __P((struct secasvar *)); -static int esp_rc5cbc_decrypt __P((struct mbuf *, size_t, - struct secasvar *, struct esp_algorithm *, int)); -static int esp_rc5cbc_encrypt __P((struct mbuf *, size_t, size_t, - struct secasvar *, struct esp_algorithm *, int)); -static void esp_increment_iv __P((struct secasvar *)); -static caddr_t mbuf_find_offset __P((struct mbuf *, size_t, size_t)); - -/* NOTE: The order depends on SADB_EALG_x in netkey/keyv2.h */ -struct esp_algorithm esp_algorithms[] = { - { 0, 0, 0, 0, 0, 0, 0, }, - { 8, esp_descbc_mature, 64, 64, - esp_descbc_ivlen, esp_descbc_decrypt, esp_descbc_encrypt, }, - { 8, esp_cbc_mature, 192, 192, - esp_3descbc_ivlen, esp_3descbc_decrypt, esp_3descbc_encrypt, }, - { 1, esp_null_mature, 0, 2048, - esp_null_ivlen, esp_null_decrypt, esp_null_encrypt, }, - { 8, esp_cbc_mature, 40, 448, - esp_blowfish_cbc_ivlen, esp_blowfish_cbc_decrypt, - esp_blowfish_cbc_encrypt, }, - { 8, esp_cbc_mature, 40, 128, - esp_cast128cbc_ivlen, esp_cast128cbc_decrypt, - esp_cast128cbc_encrypt, }, - { 8, esp_cbc_mature, 40, 2040, - esp_rc5cbc_ivlen, esp_rc5cbc_decrypt, esp_rc5cbc_encrypt, }, +static int esp_blowfish_schedule __P((const struct esp_algorithm *, + struct secasvar *)); +static int esp_blowfish_schedlen __P((const struct esp_algorithm *)); +static int esp_blowfish_blockdecrypt __P((const struct esp_algorithm *, + struct secasvar *, u_int8_t *, u_int8_t *)); +static int esp_blowfish_blockencrypt __P((const struct esp_algorithm *, + struct secasvar *, u_int8_t *, u_int8_t *)); +static int esp_cast128_schedule __P((const struct esp_algorithm *, + struct secasvar *)); +static int esp_cast128_schedlen __P((const struct esp_algorithm *)); +static int esp_cast128_blockdecrypt __P((const struct esp_algorithm *, + struct secasvar *, u_int8_t *, u_int8_t *)); +static int esp_cast128_blockencrypt __P((const struct esp_algorithm *, + struct secasvar *, u_int8_t *, u_int8_t *)); +static int esp_3des_schedule __P((const struct esp_algorithm *, + struct secasvar *)); +static int esp_3des_schedlen __P((const struct esp_algorithm *)); +static int esp_3des_blockdecrypt __P((const struct esp_algorithm *, + struct secasvar *, u_int8_t *, u_int8_t *)); +static int esp_3des_blockencrypt __P((const struct esp_algorithm *, + struct secasvar *, u_int8_t *, u_int8_t *)); +static int esp_common_ivlen __P((const struct esp_algorithm *, + struct secasvar *)); +static int esp_cbc_decrypt __P((struct mbuf *, size_t, + struct secasvar *, const struct esp_algorithm *, int)); +static int esp_cbc_encrypt __P((struct mbuf *, size_t, size_t, + struct secasvar *, const struct esp_algorithm *, int)); + +#define MAXIVLEN 16 + +static const struct esp_algorithm esp_algorithms[] = { + { 8, -1, esp_descbc_mature, 64, 64, esp_des_schedlen, + "des-cbc", + esp_descbc_ivlen, esp_cbc_decrypt, + esp_cbc_encrypt, esp_des_schedule, + esp_des_blockdecrypt, esp_des_blockencrypt, }, + { 8, 8, esp_cbc_mature, 192, 192, esp_3des_schedlen, + "3des-cbc", + esp_common_ivlen, esp_cbc_decrypt, + esp_cbc_encrypt, esp_3des_schedule, + esp_3des_blockdecrypt, esp_3des_blockencrypt, }, + { 1, 0, esp_null_mature, 0, 2048, 0, "null", + esp_common_ivlen, esp_null_decrypt, + esp_null_encrypt, NULL, }, + { 8, 8, esp_cbc_mature, 40, 448, esp_blowfish_schedlen, "blowfish-cbc", + esp_common_ivlen, esp_cbc_decrypt, + esp_cbc_encrypt, esp_blowfish_schedule, + esp_blowfish_blockdecrypt, esp_blowfish_blockencrypt, }, + { 8, 8, esp_cbc_mature, 40, 128, esp_cast128_schedlen, + "cast128-cbc", + esp_common_ivlen, esp_cbc_decrypt, + esp_cbc_encrypt, esp_cast128_schedule, + esp_cast128_blockdecrypt, esp_cast128_blockencrypt, }, + { 16, 16, esp_cbc_mature, 128, 256, esp_rijndael_schedlen, + "rijndael-cbc", + esp_common_ivlen, esp_cbc_decrypt, + esp_cbc_encrypt, esp_rijndael_schedule, + esp_rijndael_blockdecrypt, esp_rijndael_blockencrypt }, }; -/* - * mbuf assumption: foo_encrypt() assumes that IV part is placed in a single - * mbuf, not across multiple mbufs. - */ +const struct esp_algorithm * +esp_algorithm_lookup(idx) + int idx; +{ -static int -esp_null_mature(sav) + switch (idx) { + case SADB_EALG_DESCBC: + return &esp_algorithms[0]; + case SADB_EALG_3DESCBC: + return &esp_algorithms[1]; + case SADB_EALG_NULL: + return &esp_algorithms[2]; + case SADB_X_EALG_BLOWFISHCBC: + return &esp_algorithms[3]; + case SADB_X_EALG_CAST128CBC: + return &esp_algorithms[4]; + case SADB_X_EALG_RIJNDAELCBC: + return &esp_algorithms[5]; + default: + return NULL; + } +} + +int +esp_max_ivlen() +{ + int idx; + int ivlen; + + ivlen = 0; + for (idx = 0; idx < sizeof(esp_algorithms)/sizeof(esp_algorithms[0]); + idx++) { + if (esp_algorithms[idx].ivlenval > ivlen) + ivlen = esp_algorithms[idx].ivlenval; + } + + return ivlen; +} + +int +esp_schedule(algo, sav) + const struct esp_algorithm *algo; struct secasvar *sav; { - /* anything is okay */ - return 0; + int error; + + /* check for key length */ + if (_KEYBITS(sav->key_enc) < algo->keymin || + _KEYBITS(sav->key_enc) > algo->keymax) { + ipseclog((LOG_ERR, + "esp_schedule %s: unsupported key length %d: " + "needs %d to %d bits\n", algo->name, _KEYBITS(sav->key_enc), + algo->keymin, algo->keymax)); + return EINVAL; + } + + /* already allocated */ + if (sav->sched && sav->schedlen != 0) + return 0; + /* no schedule necessary */ + if (!algo->schedule || !algo->schedlen) + return 0; + + sav->schedlen = (*algo->schedlen)(algo); + if (sav->schedlen < 0) + return EINVAL; + sav->sched = _MALLOC(sav->schedlen, M_SECA, M_DONTWAIT); + if (!sav->sched) { + sav->schedlen = 0; + return ENOBUFS; + } + + error = (*algo->schedule)(algo, sav); + if (error) { + ipseclog((LOG_ERR, "esp_schedule %s: error %d\n", + algo->name, error)); + FREE(sav->sched, M_SECA); + sav->sched = NULL; + sav->schedlen = 0; + } + return error; } static int -esp_null_ivlen(sav) +esp_null_mature(sav) struct secasvar *sav; { + + /* anything is okay */ return 0; } @@ -149,9 +250,10 @@ esp_null_decrypt(m, off, sav, algo, ivlen) struct mbuf *m; size_t off; /* offset to ESP header */ struct secasvar *sav; - struct esp_algorithm *algo; + const struct esp_algorithm *algo; int ivlen; { + return 0; /* do nothing */ } @@ -161,9 +263,10 @@ esp_null_encrypt(m, off, plen, sav, algo, ivlen) size_t off; /* offset to ESP header */ size_t plen; /* payload length (to be encrypted) */ struct secasvar *sav; - struct esp_algorithm *algo; + const struct esp_algorithm *algo; int ivlen; { + return 0; /* do nothing */ } @@ -171,7 +274,7 @@ static int esp_descbc_mature(sav) struct secasvar *sav; { - struct esp_algorithm *algo; + const struct esp_algorithm *algo; if (!(sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_IV4B)) { ipseclog((LOG_ERR, "esp_cbc_mature: " @@ -183,9 +286,16 @@ esp_descbc_mature(sav) ipseclog((LOG_ERR, "esp_descbc_mature: no key is given.\n")); return 1; } - algo = &esp_algorithms[sav->alg_enc]; - if (_KEYBITS(sav->key_enc) < algo->keymin - || algo->keymax < _KEYBITS(sav->key_enc)) { + + algo = esp_algorithm_lookup(sav->alg_enc); + if (!algo) { + ipseclog((LOG_ERR, + "esp_descbc_mature: unsupported algorithm.\n")); + return 1; + } + + if (_KEYBITS(sav->key_enc) < algo->keymin || + _KEYBITS(sav->key_enc) > algo->keymax) { ipseclog((LOG_ERR, "esp_descbc_mature: invalid key length %d.\n", _KEYBITS(sav->key_enc))); @@ -193,7 +303,7 @@ esp_descbc_mature(sav) } /* weak key check */ - if (des_is_weak_key((C_Block *)_KEYBUF(sav->key_enc))) { + if (des_is_weak_key((des_cblock *)_KEYBUF(sav->key_enc))) { ipseclog((LOG_ERR, "esp_descbc_mature: weak key was passed.\n")); return 1; @@ -203,241 +313,68 @@ esp_descbc_mature(sav) } static int -esp_descbc_ivlen(sav) +esp_descbc_ivlen(algo, sav) + const struct esp_algorithm *algo; struct secasvar *sav; { - if (sav && (sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_IV4B)) - return 4; - if (sav && !(sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_DERIV)) - return 4; - else + if (!sav) return 8; + if ((sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_IV4B)) + return 4; + if (!(sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_DERIV)) + return 4; + return 8; } static int -esp_descbc_decrypt(m, off, sav, algo, ivlen) - struct mbuf *m; - size_t off; /* offset to ESP header */ - struct secasvar *sav; - struct esp_algorithm *algo; - int ivlen; +esp_des_schedlen(algo) + const struct esp_algorithm *algo; { - size_t ivoff = 0; - size_t bodyoff = 0; - u_int8_t *iv; - size_t plen; - u_int8_t tiv[8]; - int derived; - derived = 0; - /* sanity check */ - if (ivlen != sav->ivlen) { - ipseclog((LOG_ERR, "esp_descbc_decrypt: bad ivlen %d/%d\n", - ivlen, sav->ivlen)); - return EINVAL; - } - if (_KEYBITS(sav->key_enc) < algo->keymin - || algo->keymax < _KEYBITS(sav->key_enc)) { - ipseclog((LOG_ERR, "esp_descbc_decrypt: bad keylen %d\n", - _KEYBITS(sav->key_enc))); - return EINVAL; - } - - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1827 */ - ivoff = off + sizeof(struct esp); - bodyoff = off + sizeof(struct esp) + ivlen; - derived = 0; - } else { - /* RFC 2406 */ - if (sav->flags & SADB_X_EXT_DERIV) { - /* - * draft-ietf-ipsec-ciph-des-derived-00.txt - * uses sequence number field as IV field. - * This draft has been deleted, but you can get from - * ftp://ftp.kame.net/pub/internet-drafts/. - */ - ivoff = off + sizeof(struct esp); - bodyoff = off + sizeof(struct esp) + sizeof(u_int32_t); - ivlen = sizeof(u_int32_t); - derived = 1; - } else { - ivoff = off + sizeof(struct newesp); - bodyoff = off + sizeof(struct newesp) + ivlen; - derived = 0; - } - } - if (ivlen == 4) { - iv = &tiv[0]; - m_copydata(m, ivoff, 4, &tiv[0]); - m_copydata(m, ivoff, 4, &tiv[4]); - tiv[4] ^= 0xff; - tiv[5] ^= 0xff; - tiv[6] ^= 0xff; - tiv[7] ^= 0xff; - } else if (ivlen == 8) { - iv = &tiv[0]; - m_copydata(m, ivoff, 8, &tiv[0]); - } else { - ipseclog((LOG_ERR, "esp_descbc_decrypt: unsupported ivlen %d\n", - ivlen)); - return EINVAL; - } - - plen = m->m_pkthdr.len; - if (plen < bodyoff) - panic("esp_descbc_decrypt: too short packet: len=%lu", - (u_long)plen); - plen -= bodyoff; - - if (plen % 8) { - ipseclog((LOG_ERR, "esp_descbc_decrypt: " - "payload length must be multiple of 8\n")); - return EINVAL; - } + return sizeof(des_key_schedule); +} - { - int deserr; - des_key_schedule ks; +static int +esp_des_schedule(algo, sav) + const struct esp_algorithm *algo; + struct secasvar *sav; +{ - deserr = des_key_sched((C_Block *)_KEYBUF(sav->key_enc), ks); - if (deserr != 0) { - ipseclog((LOG_ERR, - "esp_descbc_decrypt: key error %d\n", deserr)); + if (des_key_sched((des_cblock *)_KEYBUF(sav->key_enc), + *(des_key_schedule *)sav->sched)) return EINVAL; - } - - des_cbc_encrypt(m, bodyoff, plen, ks, (C_Block *)iv, DES_DECRYPT); - - /* for safety */ - bzero(&ks, sizeof(des_key_schedule)); - } + else + return 0; +} - /* for safety */ - bzero(&tiv[0], sizeof(tiv)); +static int +esp_des_blockdecrypt(algo, sav, s, d) + const struct esp_algorithm *algo; + struct secasvar *sav; + u_int8_t *s; + u_int8_t *d; +{ + /* assumption: d has a good alignment */ + bcopy(s, d, sizeof(DES_LONG) * 2); + des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, + *(des_key_schedule *)sav->sched, DES_DECRYPT); return 0; } static int -esp_descbc_encrypt(m, off, plen, sav, algo, ivlen) - struct mbuf *m; - size_t off; /* offset to ESP header */ - size_t plen; /* payload length (to be decrypted) */ +esp_des_blockencrypt(algo, sav, s, d) + const struct esp_algorithm *algo; struct secasvar *sav; - struct esp_algorithm *algo; - int ivlen; + u_int8_t *s; + u_int8_t *d; { - size_t ivoff = 0; - size_t bodyoff = 0; - u_int8_t *iv; - u_int8_t tiv[8]; - int derived; - - derived = 0; - - /* sanity check */ - if (plen % 8) { - ipseclog((LOG_ERR, "esp_descbc_encrypt: " - "payload length must be multiple of 8\n")); - return EINVAL; - } - if (sav->ivlen != ivlen) { - ipseclog((LOG_ERR, "esp_descbc_encrypt: bad ivlen %d/%d\n", - ivlen, sav->ivlen)); - return EINVAL; - } - if (_KEYBITS(sav->key_enc) < algo->keymin - || algo->keymax < _KEYBITS(sav->key_enc)) { - ipseclog((LOG_ERR, "esp_descbc_encrypt: bad keylen %d\n", - _KEYBITS(sav->key_enc))); - return EINVAL; - } - - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1827 */ - /* - * draft-ietf-ipsec-ciph-des-derived-00.txt - * uses sequence number field as IV field. - * This draft has been deleted, see above. - */ - ivoff = off + sizeof(struct esp); - bodyoff = off + sizeof(struct esp) + ivlen; - derived = 0; - } else { - /* RFC 2406 */ - if (sav->flags & SADB_X_EXT_DERIV) { - /* - * draft-ietf-ipsec-ciph-des-derived-00.txt - * uses sequence number field as IV field. - * This draft has been deleted, see above. - */ - ivoff = off + sizeof(struct esp); - bodyoff = off + sizeof(struct esp) + sizeof(u_int32_t); - ivlen = sizeof(u_int32_t); - derived = 1; - } else { - ivoff = off + sizeof(struct newesp); - bodyoff = off + sizeof(struct newesp) + ivlen; - derived = 0; - } - } - - if (m->m_pkthdr.len < bodyoff) - panic("assumption failed: mbuf too short"); - iv = mbuf_find_offset(m, ivoff, ivlen); - if (!iv) - panic("assumption failed: bad mbuf chain"); - if (ivlen == 4) { - if (!derived) { - bcopy(sav->iv, &tiv[0], 4); - bcopy(sav->iv, &tiv[4], 4); - tiv[4] ^= 0xff; - tiv[5] ^= 0xff; - tiv[6] ^= 0xff; - tiv[7] ^= 0xff; - bcopy(&tiv[0], iv, 4); - iv = &tiv[0]; - } else { - bcopy(iv, &tiv[0], 4); - bcopy(iv, &tiv[4], 4); - tiv[4] ^= 0xff; - tiv[5] ^= 0xff; - tiv[6] ^= 0xff; - tiv[7] ^= 0xff; - iv = &tiv[0]; - } - } else if (ivlen == 8) - bcopy((caddr_t)sav->iv, (caddr_t)iv, ivlen); - else { - ipseclog((LOG_ERR, - "esp_descbc_encrypt: unsupported ivlen %d\n", ivlen)); - return EINVAL; - } - - { - int deserr; - des_key_schedule ks; - - deserr = des_key_sched((C_Block *)_KEYBUF(sav->key_enc), ks); - if (deserr != 0) { - ipseclog((LOG_ERR, - "esp_descbc_encrypt: key error %d\n", deserr)); - return EINVAL; - } - - des_cbc_encrypt(m, bodyoff, plen, ks, (C_Block *)iv, DES_ENCRYPT); - - /* for safety */ - bzero(&ks, sizeof(des_key_schedule)); - } - - esp_increment_iv(sav); - - /* for safety */ - bzero(&tiv[0], sizeof(tiv)); + /* assumption: d has a good alignment */ + bcopy(s, d, sizeof(DES_LONG) * 2); + des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, + *(des_key_schedule *)sav->sched, DES_ENCRYPT); return 0; } @@ -446,7 +383,7 @@ esp_cbc_mature(sav) struct secasvar *sav; { int keylen; - struct esp_algorithm *algo; + const struct esp_algorithm *algo; if (sav->flags & SADB_X_EXT_OLD) { ipseclog((LOG_ERR, @@ -460,31 +397,47 @@ esp_cbc_mature(sav) } if (!sav->key_enc) { + ipseclog((LOG_ERR, "esp_cbc_mature: no key is given.\n")); + return 1; + } + + algo = esp_algorithm_lookup(sav->alg_enc); + if (!algo) { ipseclog((LOG_ERR, - "esp_cbc_mature: no key is given.\n")); + "esp_cbc_mature %s: unsupported algorithm.\n", algo->name)); return 1; } - algo = &esp_algorithms[sav->alg_enc]; + keylen = sav->key_enc->sadb_key_bits; if (keylen < algo->keymin || algo->keymax < keylen) { - ipseclog((LOG_ERR, "esp_cbc_mature: invalid key length %d.\n", - sav->key_enc->sadb_key_bits)); + ipseclog((LOG_ERR, + "esp_cbc_mature %s: invalid key length %d.\n", + algo->name, sav->key_enc->sadb_key_bits)); return 1; } switch (sav->alg_enc) { case SADB_EALG_3DESCBC: /* weak key check */ - if (des_is_weak_key((C_Block *)_KEYBUF(sav->key_enc)) - || des_is_weak_key((C_Block *)(_KEYBUF(sav->key_enc) + 8)) - || des_is_weak_key((C_Block *)(_KEYBUF(sav->key_enc) + 16))) { + if (des_is_weak_key((des_cblock *)_KEYBUF(sav->key_enc)) || + des_is_weak_key((des_cblock *)(_KEYBUF(sav->key_enc) + 8)) || + des_is_weak_key((des_cblock *)(_KEYBUF(sav->key_enc) + 16))) { ipseclog((LOG_ERR, - "esp_cbc_mature: weak key was passed.\n")); + "esp_cbc_mature %s: weak key was passed.\n", + algo->name)); return 1; } break; - case SADB_EALG_BLOWFISHCBC: - case SADB_EALG_CAST128CBC: - case SADB_EALG_RC5CBC: + case SADB_X_EALG_BLOWFISHCBC: + case SADB_X_EALG_CAST128CBC: + break; + case SADB_X_EALG_RIJNDAELCBC: + /* allows specific key sizes only */ + if (!(keylen == 128 || keylen == 192 || keylen == 256)) { + ipseclog((LOG_ERR, + "esp_cbc_mature %s: invalid key length %d.\n", + algo->name, keylen)); + return 1; + } break; } @@ -492,692 +445,602 @@ esp_cbc_mature(sav) } static int -esp_blowfish_cbc_decrypt(m, off, sav, algo, ivlen) - struct mbuf *m; - size_t off; /* offset to ESP header */ - struct secasvar *sav; - struct esp_algorithm *algo; - int ivlen; +esp_blowfish_schedlen(algo) + const struct esp_algorithm *algo; { - size_t ivoff; - size_t bodyoff; - u_int8_t *iv; - u_int8_t tiv[8]; - size_t plen; - static BF_KEY key; /* made static to avoid kernel stack overflow */ - int s; - /* sanity check */ - if (sav->ivlen != ivlen) { - ipseclog((LOG_ERR, - "esp_blowfish_cbc_decrypt: bad ivlen %d/%d\n", - ivlen, sav->ivlen)); - return EINVAL; - } - if (_KEYBITS(sav->key_enc) < algo->keymin - || algo->keymax < _KEYBITS(sav->key_enc)) { - ipseclog((LOG_ERR, - "esp_blowfish_cbc_decrypt: unsupported key length %d: " - "need %d to %d bits\n", _KEYBITS(sav->key_enc), - algo->keymin, algo->keymax)); - return EINVAL; - } - if (sav->flags & SADB_X_EXT_OLD) { - ipseclog((LOG_ERR, - "esp_blowfish_cbc_decrypt: unsupported ESP version\n")); - return EINVAL; - } - if (ivlen != 8) { - ipseclog((LOG_ERR, - "esp_blowfish_cbc_decrypt: unsupported ivlen %d\n", ivlen)); - return EINVAL; - } - - ivoff = off + sizeof(struct newesp); - bodyoff = off + sizeof(struct newesp) + ivlen; - iv = &tiv[0]; - m_copydata(m, ivoff, 8, &tiv[0]); - - plen = m->m_pkthdr.len; - if (plen < bodyoff) - panic("esp_blowfish_cbc_decrypt: too short packet: len=%lu", - (u_long)plen); - plen -= bodyoff; - - if (plen % 8) { - ipseclog((LOG_ERR, "esp_blowfish_cbc_decrypt: " - "payload length must be multiple of 8\n")); - return EINVAL; - } - -#if __NetBSD__ - s = splsoftnet(); /* XXX correct? */ -#else - s = splnet(); /* XXX correct? */ -#endif - - BF_set_key(&key, _KEYBITS(sav->key_enc) / 8, _KEYBUF(sav->key_enc)); - BF_cbc_encrypt_m(m, bodyoff, plen, &key, iv, BF_DECRYPT); - - /* for safety */ - bzero(&key, sizeof(BF_KEY)); - - splx(s); - - /* for safety */ - bzero(&tiv[0], sizeof(tiv)); - - return 0; + return sizeof(BF_KEY); } static int -esp_blowfish_cbc_encrypt(m, off, plen, sav, algo, ivlen) - struct mbuf *m; - size_t off; /* offset to ESP header */ - size_t plen; /* payload length (to be decrypted) */ +esp_blowfish_schedule(algo, sav) + const struct esp_algorithm *algo; struct secasvar *sav; - struct esp_algorithm *algo; - int ivlen; { - size_t ivoff; - size_t bodyoff; - u_int8_t *iv; - static BF_KEY key; /* made static to avoid kernel stack overflow */ - int s; - - /* sanity check */ - if (plen % 8) { - ipseclog((LOG_ERR, "esp_blowfish_cbc_encrypt: " - "payload length must be multiple of 8\n")); - return EINVAL; - } - if (sav->ivlen != ivlen) { - ipseclog((LOG_ERR, - "esp_blowfish_cbc_encrypt: bad ivlen %d/%d\n", - ivlen, sav->ivlen)); - return EINVAL; - } - if (_KEYBITS(sav->key_enc) < algo->keymin - || algo->keymax < _KEYBITS(sav->key_enc)) { - ipseclog((LOG_ERR, - "esp_blowfish_cbc_encrypt: unsupported key length %d: " - "need %d to %d bits\n", _KEYBITS(sav->key_enc), - algo->keymin, algo->keymax)); - return EINVAL; - } - if (sav->flags & SADB_X_EXT_OLD) { - ipseclog((LOG_ERR, - "esp_blowfish_cbc_encrypt: unsupported ESP version\n")); - return EINVAL; - } - if (ivlen != 8) { - ipseclog((LOG_ERR, - "esp_blowfish_cbc_encrypt: unsupported ivlen %d\n", ivlen)); - return EINVAL; - } - - ivoff = off + sizeof(struct newesp); - bodyoff = off + sizeof(struct newesp) + ivlen; - - if (m->m_pkthdr.len < bodyoff) - panic("assumption failed: mbuf too short"); - iv = mbuf_find_offset(m, ivoff, ivlen); - if (!iv) - panic("assumption failed: bad mbuf chain"); - - bcopy((caddr_t)sav->iv, (caddr_t)iv, ivlen); - -#if __NetBSD__ - s = splsoftnet(); /* XXX correct? */ -#else - s = splnet(); /* XXX correct? */ -#endif - - BF_set_key(&key, _KEYBITS(sav->key_enc) / 8, _KEYBUF(sav->key_enc)); - BF_cbc_encrypt_m(m, bodyoff, plen, &key, iv, BF_ENCRYPT); - - /* for safety */ - bzero(&key, sizeof(BF_KEY)); - - splx(s); - - esp_increment_iv(sav); + BF_set_key((BF_KEY *)sav->sched, _KEYLEN(sav->key_enc), + _KEYBUF(sav->key_enc)); return 0; } static int -esp_blowfish_cbc_ivlen(sav) +esp_blowfish_blockdecrypt(algo, sav, s, d) + const struct esp_algorithm *algo; struct secasvar *sav; + u_int8_t *s; + u_int8_t *d; { - return 8; + /* HOLY COW! BF_encrypt() takes values in host byteorder */ + BF_LONG t[2]; + + bcopy(s, t, sizeof(t)); + t[0] = ntohl(t[0]); + t[1] = ntohl(t[1]); + BF_encrypt(t, (BF_KEY *)sav->sched, BF_DECRYPT); + t[0] = htonl(t[0]); + t[1] = htonl(t[1]); + bcopy(t, d, sizeof(t)); + return 0; } static int -esp_cast128cbc_ivlen(sav) +esp_blowfish_blockencrypt(algo, sav, s, d) + const struct esp_algorithm *algo; struct secasvar *sav; + u_int8_t *s; + u_int8_t *d; { - return 8; + /* HOLY COW! BF_encrypt() takes values in host byteorder */ + BF_LONG t[2]; + + bcopy(s, t, sizeof(t)); + t[0] = ntohl(t[0]); + t[1] = ntohl(t[1]); + BF_encrypt(t, (BF_KEY *)sav->sched, BF_ENCRYPT); + t[0] = htonl(t[0]); + t[1] = htonl(t[1]); + bcopy(t, d, sizeof(t)); + return 0; } static int -esp_cast128cbc_decrypt(m, off, sav, algo, ivlen) - struct mbuf *m; - size_t off; - struct secasvar *sav; - struct esp_algorithm *algo; - int ivlen; +esp_cast128_schedlen(algo) + const struct esp_algorithm *algo; { - size_t ivoff; - size_t bodyoff; - u_int8_t iv[8]; - size_t plen; - /* sanity check */ - if (ivlen != sav->ivlen) { - ipseclog((LOG_ERR, "esp_cast128cbc_decrypt: bad ivlen %d/%d\n", - ivlen, sav->ivlen)); - return EINVAL; - } - if (_KEYBITS(sav->key_enc) < algo->keymin - || _KEYBITS(sav->key_enc) > algo->keymax) { - ipseclog((LOG_ERR, - "esp_cast128cbc_decrypt: unsupported key length %d: " - "need %d to %d bits\n", _KEYBITS(sav->key_enc), - algo->keymin, algo->keymax)); - return EINVAL; - } - if (sav->flags & SADB_X_EXT_OLD) { - ipseclog((LOG_ERR, - "esp_cast128cbc_decrypt: unsupported ESP version\n")); - return EINVAL; - } - if (ivlen != 8) { - ipseclog((LOG_ERR, - "esp_cast128cbc_decrypt: unsupported ivlen %d\n", ivlen)); - return EINVAL; - } - - ivoff = off + sizeof(struct newesp); - bodyoff = off + sizeof(struct newesp) + ivlen; - - /* copy mbuf's IV into iv */ - m_copydata(m, ivoff, 8, iv); - - plen = m->m_pkthdr.len; - if (plen < bodyoff) { - panic("esp_cast128cbc_decrypt: too short packet: len=%lu\n", - (u_long)plen); - } - plen -= bodyoff; - - if (plen % 8) { - ipseclog((LOG_ERR, "esp_cast128cbc_decrypt: " - "payload length must be multiple of 8\n")); - return EINVAL; - } - - /* decrypt */ - { - u_int8_t key[16]; - u_int32_t subkey[32]; - - bzero(key, sizeof(key)); - bcopy(_KEYBUF(sav->key_enc), key, _KEYLEN(sav->key_enc)); - - set_cast128_subkey(subkey, key); - cast128_cbc_process(m, bodyoff, plen, subkey, iv, - _KEYBITS(sav->key_enc) / 8, CAST128_DECRYPT); + return sizeof(u_int32_t) * 32; +} - /* for safety */ - bzero(subkey, sizeof(subkey)); - bzero(key, sizeof(key)); - } +static int +esp_cast128_schedule(algo, sav) + const struct esp_algorithm *algo; + struct secasvar *sav; +{ + set_cast128_subkey((u_int32_t *)sav->sched, _KEYBUF(sav->key_enc), + _KEYLEN(sav->key_enc)); return 0; } static int -esp_cast128cbc_encrypt(m, off, plen, sav, algo, ivlen) - struct mbuf *m; - size_t off; - size_t plen; +esp_cast128_blockdecrypt(algo, sav, s, d) + const struct esp_algorithm *algo; struct secasvar *sav; - struct esp_algorithm *algo; - int ivlen; + u_int8_t *s; + u_int8_t *d; { - size_t ivoff; - size_t bodyoff; - u_int8_t *iv; - - /* sanity check */ - if (plen % 8) { - ipseclog((LOG_ERR, "esp_cast128cbc_encrypt: " - "payload length must be multiple of 8\n")); - return EINVAL; - } - if (sav->ivlen != ivlen) { - ipseclog((LOG_ERR, "esp_cast128cbc_encrypt: bad ivlen %d/%d\n", - ivlen, sav->ivlen)); - return EINVAL; - } - if (_KEYBITS(sav->key_enc) < algo->keymin - || _KEYBITS(sav->key_enc) > algo->keymax) { - ipseclog((LOG_ERR, - "esp_cast128cbc_encrypt: unsupported key length %d: " - "needs %d to %d bits\n", _KEYBITS(sav->key_enc), - algo->keymin, algo->keymax)); - return EINVAL; - } - if (sav->flags & SADB_X_EXT_OLD) { - ipseclog((LOG_ERR, - "esp_cast128cbc_encrypt: unsupported ESP version\n")); - return EINVAL; - } - if (ivlen != 8) { - ipseclog((LOG_ERR, - "esp_cast128cbc_encrypt: unsupported ivlen %d\n", ivlen)); - return EINVAL; - } - ivoff = off + sizeof(struct newesp); - bodyoff = off + sizeof(struct newesp) + ivlen; + if (_KEYLEN(sav->key_enc) <= 80 / 8) + cast128_decrypt_round12(d, s, (u_int32_t *)sav->sched); + else + cast128_decrypt_round16(d, s, (u_int32_t *)sav->sched); + return 0; +} - if (m->m_pkthdr.len < bodyoff) - panic("assumption failed: mbuf too short"); - iv = mbuf_find_offset(m, ivoff, ivlen); - if (!iv) - panic("assumption failed: bad mbuf chain"); +static int +esp_cast128_blockencrypt(algo, sav, s, d) + const struct esp_algorithm *algo; + struct secasvar *sav; + u_int8_t *s; + u_int8_t *d; +{ - bcopy(sav->iv, iv, ivlen); + if (_KEYLEN(sav->key_enc) <= 80 / 8) + cast128_encrypt_round12(d, s, (u_int32_t *)sav->sched); + else + cast128_encrypt_round16(d, s, (u_int32_t *)sav->sched); + return 0; +} - /* encrypt */ - { - u_int8_t key[16]; - u_int32_t subkey[32]; +static int +esp_3des_schedlen(algo) + const struct esp_algorithm *algo; +{ - bzero(key, sizeof(key)); - bcopy(_KEYBUF(sav->key_enc), key, _KEYLEN(sav->key_enc)); + return sizeof(des_key_schedule) * 3; +} - set_cast128_subkey(subkey, key); - cast128_cbc_process(m, bodyoff, plen, subkey, iv, - _KEYBITS(sav->key_enc) / 8, CAST128_ENCRYPT); +static int +esp_3des_schedule(algo, sav) + const struct esp_algorithm *algo; + struct secasvar *sav; +{ + int error; + des_key_schedule *p; + int i; + char *k; - /* for safety */ - bzero(subkey, sizeof(subkey)); - bzero(key, sizeof(key)); - } + p = (des_key_schedule *)sav->sched; + k = _KEYBUF(sav->key_enc); + for (i = 0; i < 3; i++) { + error = des_key_sched((des_cblock *)(k + 8 * i), p[i]); + if (error) + return EINVAL; + } + return 0; +} - esp_increment_iv(sav); +static int +esp_3des_blockdecrypt(algo, sav, s, d) + const struct esp_algorithm *algo; + struct secasvar *sav; + u_int8_t *s; + u_int8_t *d; +{ + des_key_schedule *p; + + /* assumption: d has a good alignment */ + p = (des_key_schedule *)sav->sched; + bcopy(s, d, sizeof(DES_LONG) * 2); + des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, p[2], DES_DECRYPT); + des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, p[1], DES_ENCRYPT); + des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, p[0], DES_DECRYPT); + return 0; +} +static int +esp_3des_blockencrypt(algo, sav, s, d) + const struct esp_algorithm *algo; + struct secasvar *sav; + u_int8_t *s; + u_int8_t *d; +{ + des_key_schedule *p; + + /* assumption: d has a good alignment */ + p = (des_key_schedule *)sav->sched; + bcopy(s, d, sizeof(DES_LONG) * 2); + des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, p[0], DES_ENCRYPT); + des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, p[1], DES_DECRYPT); + des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, p[2], DES_ENCRYPT); return 0; } static int -esp_3descbc_ivlen(sav) +esp_common_ivlen(algo, sav) + const struct esp_algorithm *algo; struct secasvar *sav; { - return 8; + + if (!algo) + panic("esp_common_ivlen: unknown algorithm"); + return algo->ivlenval; } static int -esp_3descbc_decrypt(m, off, sav, algo, ivlen) +esp_cbc_decrypt(m, off, sav, algo, ivlen) struct mbuf *m; size_t off; struct secasvar *sav; - struct esp_algorithm *algo; + const struct esp_algorithm *algo; int ivlen; { - size_t ivoff; - size_t bodyoff; - u_int8_t *iv; - size_t plen; - u_int8_t tiv[8]; + struct mbuf *s; + struct mbuf *d, *d0, *dp; + int soff, doff; /*offset from the head of chain, to head of this mbuf */ + int sn, dn; /*offset from the head of the mbuf, to meat */ + size_t ivoff, bodyoff; + u_int8_t iv[MAXIVLEN], *ivp; + u_int8_t sbuf[MAXIVLEN], *sp; + u_int8_t *p, *q; + struct mbuf *scut; + int scutoff; + int i; + int blocklen; + int derived; - /* sanity check */ - if (ivlen != sav->ivlen) { - ipseclog((LOG_ERR, "esp_3descbc_decrypt: bad ivlen %d/%d\n", - ivlen, sav->ivlen)); - return EINVAL; - } - if (_KEYBITS(sav->key_enc) < algo->keymin - || algo->keymax < _KEYBITS(sav->key_enc)) { - ipseclog((LOG_ERR, "esp_3descbc_decrypt: bad keylen %d\n", - _KEYBITS(sav->key_enc))); - return EINVAL; - } - if (sav->flags & SADB_X_EXT_OLD) { - ipseclog((LOG_ERR, - "esp_3descbc_decrypt: unsupported ESP version\n")); - return EINVAL; - } - if (ivlen != 8) { - ipseclog((LOG_ERR, - "esp_3descbc_decrypt: unsupported ivlen %d\n", ivlen)); + if (ivlen != sav->ivlen || ivlen > sizeof(iv)) { + ipseclog((LOG_ERR, "esp_cbc_decrypt %s: " + "unsupported ivlen %d\n", algo->name, ivlen)); + m_freem(m); return EINVAL; } - ivoff = off + sizeof(struct newesp); - bodyoff = off + sizeof(struct newesp) + ivlen; - iv = &tiv[0]; - m_copydata(m, ivoff, 8, &tiv[0]); + /* assumes blocklen == padbound */ + blocklen = algo->padbound; - plen = m->m_pkthdr.len; - if (plen < bodyoff) - panic("esp_3descbc_decrypt: too short packet: len=%lu", - (u_long)plen); - - plen -= bodyoff; - - if (plen % 8) { - ipseclog((LOG_ERR, "esp_3descbc_decrypt: " - "payload length must be multiple of 8\n")); +#if DIAGNOSTIC + if (blocklen > sizeof(iv)) { + ipseclog((LOG_ERR, "esp_cbc_decrypt %s: " + "unsupported blocklen %d\n", algo->name, blocklen)); + m_freem(m); return EINVAL; } +#endif - /* decrypt packet */ - { - int deserr[3]; - des_key_schedule ks[3]; - - deserr[0] = des_key_sched((C_Block *)_KEYBUF(sav->key_enc),ks[0]); - deserr[1] = des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 8), ks[1]); - deserr[2] = des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 16), ks[2]); - if ((deserr[0] != 0) || (deserr[1] != 0) || (deserr[2] != 0)) { - ipseclog((LOG_ERR, "esp_3descbc_decrypt: key error %d/%d/%d\n", - deserr[0], deserr[1], deserr[2])); - return EINVAL; + if (sav->flags & SADB_X_EXT_OLD) { + /* RFC 1827 */ + ivoff = off + sizeof(struct esp); + bodyoff = off + sizeof(struct esp) + ivlen; + derived = 0; + } else { + /* RFC 2406 */ + if (sav->flags & SADB_X_EXT_DERIV) { + /* + * draft-ietf-ipsec-ciph-des-derived-00.txt + * uses sequence number field as IV field. + */ + ivoff = off + sizeof(struct esp); + bodyoff = off + sizeof(struct esp) + sizeof(u_int32_t); + ivlen = sizeof(u_int32_t); + derived = 1; + } else { + ivoff = off + sizeof(struct newesp); + bodyoff = off + sizeof(struct newesp) + ivlen; + derived = 0; + } } - des_3cbc_process(m, bodyoff, plen, ks, (C_Block *)iv, DES_DECRYPT); + /* grab iv */ + m_copydata(m, ivoff, ivlen, iv); - /* for safety */ - bzero(ks[0], sizeof(des_key_schedule)*3); - } - - /* for safety */ - bzero(&tiv[0], sizeof(tiv)); - - return 0; -} - -static int -esp_3descbc_encrypt(m, off, plen, sav, algo, ivlen) - struct mbuf *m; - size_t off; - size_t plen; - struct secasvar *sav; - struct esp_algorithm *algo; - int ivlen; -{ - size_t ivoff; - size_t bodyoff; - u_int8_t *iv; - - /* sanity check */ - if (plen % 8) { - ipseclog((LOG_ERR, "esp_3descbc_encrypt: " - "payload length must be multiple of 8\n")); - return EINVAL; - } - if (sav->ivlen != ivlen) { - ipseclog((LOG_ERR, "esp_3descbc_encrypt: bad ivlen %d/%d\n", - ivlen, sav->ivlen)); - return EINVAL; - } - if (_KEYBITS(sav->key_enc) < algo->keymin - || algo->keymax < _KEYBITS(sav->key_enc)) { - ipseclog((LOG_ERR, "esp_3descbc_encrypt: bad keylen %d\n", - _KEYBITS(sav->key_enc))); + /* extend iv */ + if (ivlen == blocklen) + ; + else if (ivlen == 4 && blocklen == 8) { + bcopy(&iv[0], &iv[4], 4); + iv[4] ^= 0xff; + iv[5] ^= 0xff; + iv[6] ^= 0xff; + iv[7] ^= 0xff; + } else { + ipseclog((LOG_ERR, "esp_cbc_encrypt %s: " + "unsupported ivlen/blocklen: %d %d\n", + algo->name, ivlen, blocklen)); + m_freem(m); return EINVAL; } - if (sav->flags & SADB_X_EXT_OLD) { - ipseclog((LOG_ERR, - "esp_3descbc_encrypt: unsupported ESP version\n")); + + if (m->m_pkthdr.len < bodyoff) { + ipseclog((LOG_ERR, "esp_cbc_decrypt %s: bad len %d/%lu\n", + algo->name, m->m_pkthdr.len, (unsigned long)bodyoff)); + m_freem(m); return EINVAL; } - if (ivlen != 8) { - ipseclog((LOG_ERR, - "esp_3descbc_encrypt: unsupported ivlen %d\n", ivlen)); + if ((m->m_pkthdr.len - bodyoff) % blocklen) { + ipseclog((LOG_ERR, "esp_cbc_decrypt %s: " + "payload length must be multiple of %d\n", + algo->name, blocklen)); + m_freem(m); return EINVAL; } - ivoff = off + sizeof(struct newesp); - bodyoff = off + sizeof(struct newesp) + ivlen; + s = m; + d = d0 = dp = NULL; + soff = doff = sn = dn = 0; + ivp = sp = NULL; - if (m->m_pkthdr.len < bodyoff) - panic("assumption failed: mbuf too short"); - iv = mbuf_find_offset(m, ivoff, ivlen); - if (!iv) - panic("assumption failed: bad mbuf chain"); - - bcopy((caddr_t)sav->iv, (caddr_t)iv, ivlen); - - /* encrypt packet */ - { - int deserr[3]; - des_key_schedule ks[3]; + /* skip bodyoff */ + while (soff < bodyoff) { + if (soff + s->m_len > bodyoff) { + sn = bodyoff - soff; + break; + } - deserr[0] = des_key_sched((C_Block *)_KEYBUF(sav->key_enc), ks[0]); - deserr[1] = des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 8), ks[1]); - deserr[2] = des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 16), ks[2]); - if ((deserr[0] != 0) || (deserr[1] != 0) || (deserr[2] != 0)) { - ipseclog((LOG_ERR, "esp_3descbc_encrypt: key error %d/%d/%d\n", - deserr[0], deserr[1], deserr[2])); - return EINVAL; + soff += s->m_len; + s = s->m_next; } + scut = s; + scutoff = sn; - des_3cbc_process(m, bodyoff, plen, ks, (C_Block *)iv, DES_ENCRYPT); - - /* for safety */ - bzero(ks[0], sizeof(des_key_schedule)*3); - } + /* skip over empty mbuf */ + while (s && s->m_len == 0) + s = s->m_next; - esp_increment_iv(sav); - - return 0; -} + while (soff < m->m_pkthdr.len) { + /* source */ + if (sn + blocklen <= s->m_len) { + /* body is continuous */ + sp = mtod(s, u_int8_t *) + sn; + } else { + /* body is non-continuous */ + m_copydata(s, sn, blocklen, sbuf); + sp = sbuf; + } -static int -esp_rc5cbc_ivlen(sav) - struct secasvar *sav; -{ - return 8; -} + /* destination */ + if (!d || dn + blocklen > d->m_len) { + if (d) + dp = d; + MGET(d, M_DONTWAIT, MT_DATA); + i = m->m_pkthdr.len - (soff + sn); + if (d && i > MLEN) { + MCLGET(d, M_DONTWAIT); + if ((d->m_flags & M_EXT) == 0) { + m_free(d); + d = NULL; + } + } + if (!d) { + m_freem(m); + if (d0) + m_freem(d0); + return ENOBUFS; + } + if (!d0) + d0 = d; + if (dp) + dp->m_next = d; + d->m_len = 0; + d->m_len = (M_TRAILINGSPACE(d) / blocklen) * blocklen; + if (d->m_len > i) + d->m_len = i; + dn = 0; + } -static int -esp_rc5cbc_decrypt(m, off, sav, algo, ivlen) - struct mbuf *m; - size_t off; - struct secasvar *sav; - struct esp_algorithm *algo; - int ivlen; -{ - size_t ivoff; - size_t bodyoff; - u_int8_t iv[8]; - size_t plen; + /* decrypt */ + (*algo->blockdecrypt)(algo, sav, sp, mtod(d, u_int8_t *) + dn); - /* sanity check */ - if (sav->ivlen != ivlen) { - ipseclog((LOG_ERR, "esp_rc5cbc_decrypt: bad ivlen %d/%d\n", - ivlen, sav->ivlen)); - return EINVAL; - } - if ((_KEYBITS(sav->key_enc) < 40) || (_KEYBITS(sav->key_enc) > 2040)) { - ipseclog((LOG_ERR, - "esp_rc5cbc_decrypt: unsupported key length %d: " - "need 40 to 2040 bit\n", _KEYBITS(sav->key_enc))); - return EINVAL; - } - if (sav->flags & SADB_X_EXT_OLD) { - ipseclog((LOG_ERR, - "esp_rc5cbc_decrypt: unsupported ESP version\n")); - return EINVAL; - } - if (ivlen != 8) { - ipseclog((LOG_ERR, "esp_rc5cbc_decrypt: unsupported ivlen %d\n", - ivlen)); - return EINVAL; - } + /* xor */ + p = ivp ? ivp : iv; + q = mtod(d, u_int8_t *) + dn; + for (i = 0; i < blocklen; i++) + q[i] ^= p[i]; - ivoff = off + sizeof(struct newesp); - bodyoff = off + sizeof(struct newesp) + ivlen; + /* next iv */ + if (sp == sbuf) { + bcopy(sbuf, iv, blocklen); + ivp = NULL; + } else + ivp = sp; - /* copy mbuf's IV into iv */ - m_copydata(m, ivoff, 8, iv); + sn += blocklen; + dn += blocklen; - plen = m->m_pkthdr.len; - if (plen < bodyoff) { - panic("esp_rc5cbc_decrypt: too short packet: len=%lu", - (u_long)plen); - } - plen -= bodyoff; + /* find the next source block */ + while (s && sn >= s->m_len) { + sn -= s->m_len; + soff += s->m_len; + s = s->m_next; + } - if (plen % 8) { - ipseclog((LOG_ERR, "esp_rc5cbc_decrypt: " - "payload length must be multiple of 8\n")); - return EINVAL; + /* skip over empty mbuf */ + while (s && s->m_len == 0) + s = s->m_next; } - /* decrypt */ - { - RC5_WORD e_key[34]; - - set_rc5_expandkey(e_key, _KEYBUF(sav->key_enc), - _KEYBITS(sav->key_enc) / 8, 16); - rc5_cbc_process(m, bodyoff, plen, e_key, iv, RC5_DECRYPT); + m_freem(scut->m_next); + scut->m_len = scutoff; + scut->m_next = d0; - /* for safety */ - bzero(e_key, sizeof(e_key)); - } + /* just in case */ + bzero(iv, sizeof(iv)); + bzero(sbuf, sizeof(sbuf)); return 0; } static int -esp_rc5cbc_encrypt(m, off, plen, sav, algo, ivlen) +esp_cbc_encrypt(m, off, plen, sav, algo, ivlen) struct mbuf *m; size_t off; size_t plen; struct secasvar *sav; - struct esp_algorithm *algo; + const struct esp_algorithm *algo; int ivlen; { - size_t ivoff; - size_t bodyoff; - u_int8_t *iv; - - /* sanity check */ - if (plen % 8) { - ipseclog((LOG_ERR, "esp_rc5cbc_encrypt: " - "payload length must be multiple of 8\n")); + struct mbuf *s; + struct mbuf *d, *d0, *dp; + int soff, doff; /*offset from the head of chain, to head of this mbuf */ + int sn, dn; /*offset from the head of the mbuf, to meat */ + size_t ivoff, bodyoff; + u_int8_t iv[MAXIVLEN], *ivp; + u_int8_t sbuf[MAXIVLEN], *sp; + u_int8_t *p, *q; + struct mbuf *scut; + int scutoff; + int i; + int blocklen; + int derived; + + if (ivlen != sav->ivlen || ivlen > sizeof(iv)) { + ipseclog((LOG_ERR, "esp_cbc_encrypt %s: " + "unsupported ivlen %d\n", algo->name, ivlen)); + m_freem(m); return EINVAL; } - if (sav->ivlen != ivlen) { - ipseclog((LOG_ERR, "esp_rc5cbc_encrypt: bad ivlen %d/%d\n", - ivlen, sav->ivlen)); + + /* assumes blocklen == padbound */ + blocklen = algo->padbound; + +#if DIAGNOSTIC + if (blocklen > sizeof(iv)) { + ipseclog((LOG_ERR, "esp_cbc_encrypt %s: " + "unsupported blocklen %d\n", algo->name, blocklen)); + m_freem(m); return EINVAL; } - if (_KEYBITS(sav->key_enc) < algo->keymin - || _KEYBITS(sav->key_enc) > algo->keymax) { - ipseclog((LOG_ERR, - "esp_rc5cbc_encrypt: unsupported key length %d: " - "need %d to %d bits\n", _KEYBITS(sav->key_enc), - algo->keymin, algo->keymax)); +#endif + + if (sav->flags & SADB_X_EXT_OLD) { + /* RFC 1827 */ + ivoff = off + sizeof(struct esp); + bodyoff = off + sizeof(struct esp) + ivlen; + derived = 0; + } else { + /* RFC 2406 */ + if (sav->flags & SADB_X_EXT_DERIV) { + /* + * draft-ietf-ipsec-ciph-des-derived-00.txt + * uses sequence number field as IV field. + */ + ivoff = off + sizeof(struct esp); + bodyoff = off + sizeof(struct esp) + sizeof(u_int32_t); + ivlen = sizeof(u_int32_t); + derived = 1; + } else { + ivoff = off + sizeof(struct newesp); + bodyoff = off + sizeof(struct newesp) + ivlen; + derived = 0; + } + } + + /* put iv into the packet. if we are in derived mode, use seqno. */ + if (derived) + m_copydata(m, ivoff, ivlen, iv); + else { + bcopy(sav->iv, iv, ivlen); + /* maybe it is better to overwrite dest, not source */ + m_copyback(m, ivoff, ivlen, iv); + } + + /* extend iv */ + if (ivlen == blocklen) + ; + else if (ivlen == 4 && blocklen == 8) { + bcopy(&iv[0], &iv[4], 4); + iv[4] ^= 0xff; + iv[5] ^= 0xff; + iv[6] ^= 0xff; + iv[7] ^= 0xff; + } else { + ipseclog((LOG_ERR, "esp_cbc_encrypt %s: " + "unsupported ivlen/blocklen: %d %d\n", + algo->name, ivlen, blocklen)); + m_freem(m); return EINVAL; } - if (sav->flags & SADB_X_EXT_OLD) { - ipseclog((LOG_ERR, - "esp_rc5cbc_encrypt: unsupported ESP version\n")); + + if (m->m_pkthdr.len < bodyoff) { + ipseclog((LOG_ERR, "esp_cbc_encrypt %s: bad len %d/%lu\n", + algo->name, m->m_pkthdr.len, (unsigned long)bodyoff)); + m_freem(m); return EINVAL; } - if (ivlen != 8) { - ipseclog((LOG_ERR, "esp_rc5cbc_encrypt: unsupported ivlen %d\n", - ivlen)); + if ((m->m_pkthdr.len - bodyoff) % blocklen) { + ipseclog((LOG_ERR, "esp_cbc_encrypt %s: " + "payload length must be multiple of %lu\n", + algo->name, (unsigned long)algo->padbound)); + m_freem(m); return EINVAL; } - ivoff = off + sizeof(struct newesp); - bodyoff = off + sizeof(struct newesp) + ivlen; + s = m; + d = d0 = dp = NULL; + soff = doff = sn = dn = 0; + ivp = sp = NULL; - if (m->m_pkthdr.len < bodyoff) - panic("assumption failed: mbuf too short"); - iv = mbuf_find_offset(m, ivoff, ivlen); - if (!iv) - panic("assumption failed: bad mbuf chain"); + /* skip bodyoff */ + while (soff < bodyoff) { + if (soff + s->m_len > bodyoff) { + sn = bodyoff - soff; + break; + } - bcopy(sav->iv, iv, ivlen); + soff += s->m_len; + s = s->m_next; + } + scut = s; + scutoff = sn; - /* encrypt */ - { - RC5_WORD e_key[34]; + /* skip over empty mbuf */ + while (s && s->m_len == 0) + s = s->m_next; - set_rc5_expandkey(e_key, _KEYBUF(sav->key_enc), - _KEYBITS(sav->key_enc) / 8, 16); - rc5_cbc_process(m, bodyoff, plen, e_key, iv, RC5_ENCRYPT); + while (soff < m->m_pkthdr.len) { + /* source */ + if (sn + blocklen <= s->m_len) { + /* body is continuous */ + sp = mtod(s, u_int8_t *) + sn; + } else { + /* body is non-continuous */ + m_copydata(s, sn, blocklen, sbuf); + sp = sbuf; + } - /* for safety */ - bzero(e_key, sizeof(e_key)); - } + /* destination */ + if (!d || dn + blocklen > d->m_len) { + if (d) + dp = d; + MGET(d, M_DONTWAIT, MT_DATA); + i = m->m_pkthdr.len - (soff + sn); + if (d && i > MLEN) { + MCLGET(d, M_DONTWAIT); + if ((d->m_flags & M_EXT) == 0) { + m_free(d); + d = NULL; + } + } + if (!d) { + m_freem(m); + if (d0) + m_freem(d0); + return ENOBUFS; + } + if (!d0) + d0 = d; + if (dp) + dp->m_next = d; + d->m_len = 0; + d->m_len = (M_TRAILINGSPACE(d) / blocklen) * blocklen; + if (d->m_len > i) + d->m_len = i; + dn = 0; + } - esp_increment_iv(sav); + /* xor */ + p = ivp ? ivp : iv; + q = sp; + for (i = 0; i < blocklen; i++) + q[i] ^= p[i]; - return 0; -} + /* encrypt */ + (*algo->blockencrypt)(algo, sav, sp, mtod(d, u_int8_t *) + dn); -/* - * increment iv. - */ -static void -esp_increment_iv(sav) - struct secasvar *sav; -{ - u_int8_t *x; - u_int8_t y; - int i; + /* next iv */ + ivp = mtod(d, u_int8_t *) + dn; -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) - y = time.tv_sec & 0xff; -#else - y = time_second & 0xff; -#endif - if (!y) y++; - x = (u_int8_t *)sav->iv; - for (i = 0; i < sav->ivlen; i++) { - *x = (*x + y) & 0xff; - x++; - } -} + sn += blocklen; + dn += blocklen; -static caddr_t -mbuf_find_offset(m, off, len) - struct mbuf *m; - size_t off; - size_t len; -{ - struct mbuf *n; - size_t cnt; - - if (m->m_pkthdr.len < off || m->m_pkthdr.len < off + len) - return (caddr_t)NULL; - cnt = 0; - for (n = m; n; n = n->m_next) { - if (cnt + n->m_len <= off) { - cnt += n->m_len; - continue; + /* find the next source block */ + while (s && sn >= s->m_len) { + sn -= s->m_len; + soff += s->m_len; + s = s->m_next; } - if (cnt <= off && off < cnt + n->m_len - && cnt <= off + len && off + len <= cnt + n->m_len) { - return mtod(n, caddr_t) + off - cnt; - } else - return (caddr_t)NULL; + + /* skip over empty mbuf */ + while (s && s->m_len == 0) + s = s->m_next; } - return (caddr_t)NULL; + + m_freem(scut->m_next); + scut->m_len = scutoff; + scut->m_next = d0; + + /* just in case */ + bzero(iv, sizeof(iv)); + bzero(sbuf, sizeof(sbuf)); + + key_sa_stir_iv(sav); + + return 0; } /*------------------------------------------------------------*/ +/* does not free m0 on error */ int esp_auth(m0, skip, length, sav, sum) struct mbuf *m0; @@ -1190,8 +1053,9 @@ esp_auth(m0, skip, length, sav, sum) size_t off; struct ah_algorithm_state s; u_char sumbuf[AH_MAXSUMSIZE]; - struct ah_algorithm *algo; + const struct ah_algorithm *algo; size_t siz; + int error; /* sanity checks */ if (m0->m_pkthdr.len < skip) { @@ -1215,7 +1079,8 @@ esp_auth(m0, skip, length, sav, sum) ipseclog((LOG_DEBUG, "esp_auth: NULL SA passed\n")); return EINVAL; } - if (!sav->alg_auth) { + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { ipseclog((LOG_ERR, "esp_auth: bad ESP auth algorithm passed: %d\n", sav->alg_auth)); @@ -1225,7 +1090,6 @@ esp_auth(m0, skip, length, sav, sum) m = m0; off = 0; - algo = &ah_algorithms[sav->alg_auth]; siz = (((*algo->sumsiz)(sav) + 3) & ~(4 - 1)); if (sizeof(sumbuf) < siz) { ipseclog((LOG_DEBUG, @@ -1248,7 +1112,10 @@ esp_auth(m0, skip, length, sav, sum) } } - (*algo->init)(&s, sav); + error = (*algo->init)(&s, sav); + if (error) + return error; + while (0 < length) { if (!m) panic("mbuf chain?"); diff --git a/bsd/netinet6/esp_input.c b/bsd/netinet6/esp_input.c index 7bd490e8f..3d5e88900 100644 --- a/bsd/netinet6/esp_input.c +++ b/bsd/netinet6/esp_input.c @@ -1,4 +1,5 @@ -/* $KAME: esp_input.c,v 1.22 2000/03/21 05:14:49 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/esp_input.c,v 1.1.2.3 2001/07/03 11:01:50 ume Exp $ */ +/* $KAME: esp_input.c,v 1.55 2001/03/23 08:08:47 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -33,11 +34,6 @@ * RFC1827/2406 Encapsulated Security Payload. */ -#define _IP_VHL -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#endif - #include #include #include @@ -61,16 +57,31 @@ #include #include #include +#include +#if INET6 +#include +#endif #if INET6 #include +#include #include #include +#include #endif #include +#if INET6 +#include +#endif #include +#if INET6 +#include +#endif #include +#if INET6 +#include +#endif #include #include #include @@ -82,9 +93,6 @@ #if INET extern struct protosw inetsw[]; -#if defined(__bsdi__) || defined(__NetBSD__) -extern u_char ip_protox[]; -#endif #define ESPMAXLEN \ (sizeof(struct esp) < sizeof(struct newesp) \ @@ -102,7 +110,7 @@ esp4_input(m, off) struct secasvar *sav = NULL; size_t taillen; u_int16_t nxt; - struct esp_algorithm *algo; + const struct esp_algorithm *algo; int ivlen; size_t hlen; size_t esplen; @@ -156,16 +164,15 @@ esp4_input(m, off) ipsecstat.in_badspi++; goto bad; } - if (sav->alg_enc == SADB_EALG_NONE) { + algo = esp_algorithm_lookup(sav->alg_enc); + if (!algo) { ipseclog((LOG_DEBUG, "IPv4 ESP input: " - "unspecified encryption algorithm for spi %u\n", + "unsupported encryption algorithm for spi %u\n", (u_int32_t)ntohl(spi))); ipsecstat.in_badspi++; goto bad; } - algo = &esp_algorithms[sav->alg_enc]; /*XXX*/ - /* check if we have proper ivlen information */ ivlen = sav->ivlen; if (ivlen < 0) { @@ -179,7 +186,8 @@ esp4_input(m, off) && (sav->alg_auth && sav->key_auth))) goto noreplaycheck; - if (sav->alg_auth == SADB_AALG_NULL) + if (sav->alg_auth == SADB_X_AALG_NULL || + sav->alg_auth == SADB_AALG_NONE) goto noreplaycheck; /* @@ -199,10 +207,12 @@ esp4_input(m, off) { u_char sum0[AH_MAXSUMSIZE]; u_char sum[AH_MAXSUMSIZE]; - struct ah_algorithm *sumalgo; + const struct ah_algorithm *sumalgo; size_t siz; - sumalgo = &ah_algorithms[sav->alg_auth]; + sumalgo = ah_algorithm_lookup(sav->alg_auth); + if (!sumalgo) + goto noreplaycheck; siz = (((*sumalgo->sumsiz)(sav) + 3) & ~(4 - 1)); if (AH_MAXSUMSIZE < siz) { ipseclog((LOG_DEBUG, @@ -281,22 +291,30 @@ noreplaycheck: } } - { + /* + * pre-compute and cache intermediate key + */ + if (esp_schedule(algo, sav) != 0) { + ipsecstat.in_inval++; + goto bad; + } + /* * decrypt the packet. */ if (!algo->decrypt) panic("internal error: no decrypt function"); if ((*algo->decrypt)(m, off, sav, algo, ivlen)) { - ipseclog((LOG_ERR, "decrypt fail in IPv4 ESP input: %s %s\n", - ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); + /* m is already freed */ + m = NULL; + ipseclog((LOG_ERR, "decrypt fail in IPv4 ESP input: %s\n", + ipsec_logsastr(sav))); ipsecstat.in_inval++; goto bad; } ipsecstat.in_esphist[sav->alg_enc]++; m->m_flags |= M_DECRYPTED; - } /* * find the trailer of the ESP. @@ -325,7 +343,7 @@ noreplaycheck: #endif /* was it transmitted over the IPsec tunnel SA? */ - if (ipsec4_tunnel_validate(ip, nxt, sav)) { + if (ipsec4_tunnel_validate(m, off + esplen + ivlen, nxt, sav)) { /* * strip off all the headers that precedes ESP header. * IP4 xx ESP IP4' payload -> IP4' payload @@ -365,10 +383,16 @@ noreplaycheck: #endif key_sa_recordxfer(sav, m); + if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0 || + ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) { + ipsecstat.in_nomem++; + goto bad; + } s = splimp(); if (IF_QFULL(&ipintrq)) { ipsecstat.in_inval++; + splx(s); goto bad; } IF_ENQUEUE(&ipintrq, m); @@ -401,10 +425,19 @@ noreplaycheck: ip->ip_p = nxt; key_sa_recordxfer(sav, m); + if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0) { + ipsecstat.in_nomem++; + goto bad; + } - if (nxt != IPPROTO_DONE) + if (nxt != IPPROTO_DONE) { + if ((ip_protox[nxt]->pr_flags & PR_LASTHDR) != 0 && + ipsec4_in_reject(m, NULL)) { + ipsecstat.in_polvio++; + goto bad; + } (*ip_protox[nxt]->pr_input)(m, off); - else + } else m_freem(m); m = NULL; } @@ -444,7 +477,7 @@ esp6_input(mp, offp, proto) struct secasvar *sav = NULL; size_t taillen; u_int16_t nxt; - struct esp_algorithm *algo; + const struct esp_algorithm *algo; int ivlen; size_t esplen; int s; @@ -498,16 +531,15 @@ esp6_input(mp, offp, proto) ipsec6stat.in_badspi++; goto bad; } - if (sav->alg_enc == SADB_EALG_NONE) { + algo = esp_algorithm_lookup(sav->alg_enc); + if (!algo) { ipseclog((LOG_DEBUG, "IPv6 ESP input: " - "unspecified encryption algorithm for spi %u\n", + "unsupported encryption algorithm for spi %u\n", (u_int32_t)ntohl(spi))); ipsec6stat.in_badspi++; goto bad; } - algo = &esp_algorithms[sav->alg_enc]; /*XXX*/ - /* check if we have proper ivlen information */ ivlen = sav->ivlen; if (ivlen < 0) { @@ -521,7 +553,8 @@ esp6_input(mp, offp, proto) && (sav->alg_auth && sav->key_auth))) goto noreplaycheck; - if (sav->alg_auth == SADB_AALG_NULL) + if (sav->alg_auth == SADB_X_AALG_NULL || + sav->alg_auth == SADB_AALG_NONE) goto noreplaycheck; /* @@ -541,10 +574,12 @@ esp6_input(mp, offp, proto) { u_char sum0[AH_MAXSUMSIZE]; u_char sum[AH_MAXSUMSIZE]; - struct ah_algorithm *sumalgo; + const struct ah_algorithm *sumalgo; size_t siz; - sumalgo = &ah_algorithms[sav->alg_auth]; + sumalgo = ah_algorithm_lookup(sav->alg_auth); + if (!sumalgo) + goto noreplaycheck; siz = (((*sumalgo->sumsiz)(sav) + 3) & ~(4 - 1)); if (AH_MAXSUMSIZE < siz) { ipseclog((LOG_DEBUG, @@ -622,14 +657,24 @@ noreplaycheck: #endif ip6 = mtod(m, struct ip6_hdr *); /*set it again just in case*/ + /* + * pre-compute and cache intermediate key + */ + if (esp_schedule(algo, sav) != 0) { + ipsec6stat.in_inval++; + goto bad; + } + /* * decrypt the packet. */ if (!algo->decrypt) panic("internal error: no decrypt function"); if ((*algo->decrypt)(m, off, sav, algo, ivlen)) { - ipseclog((LOG_ERR, "decrypt fail in IPv6 ESP input: %s %s\n", - ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); + /* m is already freed */ + m = NULL; + ipseclog((LOG_ERR, "decrypt fail in IPv6 ESP input: %s\n", + ipsec_logsastr(sav))); ipsec6stat.in_inval++; goto bad; } @@ -660,7 +705,7 @@ noreplaycheck: ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - taillen); /* was it transmitted over the IPsec tunnel SA? */ - if (ipsec6_tunnel_validate(ip6, nxt, sav)) { + if (ipsec6_tunnel_validate(m, off + esplen + ivlen, nxt, sav)) { /* * strip off all the headers that precedes ESP header. * IP6 xx ESP IP6' payload -> IP6' payload @@ -708,10 +753,16 @@ noreplaycheck: #endif key_sa_recordxfer(sav, m); + if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0 || + ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) { + ipsec6stat.in_nomem++; + goto bad; + } s = splimp(); if (IF_QFULL(&ip6intrq)) { ipsec6stat.in_inval++; + splx(s); goto bad; } IF_ENQUEUE(&ip6intrq, m); @@ -760,10 +811,60 @@ noreplaycheck: m->m_pkthdr.len += n->m_pkthdr.len; } +#ifndef PULLDOWN_TEST + /* + * KAME requires that the packet to be contiguous on the + * mbuf. We need to make that sure. + * this kind of code should be avoided. + * XXX other conditions to avoid running this part? + */ + if (m->m_len != m->m_pkthdr.len) { + struct mbuf *n = NULL; + int maxlen; + + MGETHDR(n, M_DONTWAIT, MT_HEADER); + maxlen = MHLEN; + if (n) + M_COPY_PKTHDR(n, m); + if (n && m->m_pkthdr.len > maxlen) { + MCLGET(n, M_DONTWAIT); + maxlen = MCLBYTES; + if ((n->m_flags & M_EXT) == 0) { + m_free(n); + n = NULL; + } + } + if (!n) { + printf("esp6_input: mbuf allocation failed\n"); + goto bad; + } + + if (m->m_pkthdr.len <= maxlen) { + m_copydata(m, 0, m->m_pkthdr.len, mtod(n, caddr_t)); + n->m_len = m->m_pkthdr.len; + n->m_pkthdr.len = m->m_pkthdr.len; + n->m_next = NULL; + m_freem(m); + } else { + m_copydata(m, 0, maxlen, mtod(n, caddr_t)); + m_adj(m, maxlen); + n->m_len = maxlen; + n->m_pkthdr.len = m->m_pkthdr.len; + n->m_next = m; + m->m_flags &= ~M_PKTHDR; + } + m = n; + } +#endif + ip6 = mtod(m, struct ip6_hdr *); ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz); key_sa_recordxfer(sav, m); + if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0) { + ipsec6stat.in_nomem++; + goto bad; + } } *offp = off; @@ -787,4 +888,108 @@ bad: m_freem(m); return IPPROTO_DONE; } + +void +esp6_ctlinput(cmd, sa, d) + int cmd; + struct sockaddr *sa; + void *d; +{ + const struct newesp *espp; + struct newesp esp; + struct ip6ctlparam *ip6cp = NULL, ip6cp1; + struct secasvar *sav; + struct ip6_hdr *ip6; + struct mbuf *m; + int off; + struct sockaddr_in6 sa6_src, sa6_dst; + + if (sa->sa_family != AF_INET6 || + sa->sa_len != sizeof(struct sockaddr_in6)) + return; + if ((unsigned)cmd >= PRC_NCMDS) + return; + + /* if the parameter is from icmp6, decode it. */ + if (d != NULL) { + ip6cp = (struct ip6ctlparam *)d; + m = ip6cp->ip6c_m; + ip6 = ip6cp->ip6c_ip6; + off = ip6cp->ip6c_off; + } else { + m = NULL; + ip6 = NULL; + } + + if (ip6) { + /* + * Notify the error to all possible sockets via pfctlinput2. + * Since the upper layer information (such as protocol type, + * source and destination ports) is embedded in the encrypted + * data and might have been cut, we can't directly call + * an upper layer ctlinput function. However, the pcbnotify + * function will consider source and destination addresses + * as well as the flow info value, and may be able to find + * some PCB that should be notified. + * Although pfctlinput2 will call esp6_ctlinput(), there is + * no possibility of an infinite loop of function calls, + * because we don't pass the inner IPv6 header. + */ + bzero(&ip6cp1, sizeof(ip6cp1)); + ip6cp1.ip6c_src = ip6cp->ip6c_src; + pfctlinput2(cmd, sa, (void *)&ip6cp1); + + /* + * Then go to special cases that need ESP header information. + * XXX: We assume that when ip6 is non NULL, + * M and OFF are valid. + */ + + /* check if we can safely examine src and dst ports */ + if (m->m_pkthdr.len < off + sizeof(esp)) + return; + + if (m->m_len < off + sizeof(esp)) { + /* + * this should be rare case, + * so we compromise on this copy... + */ + m_copydata(m, off, sizeof(esp), (caddr_t)&esp); + espp = &esp; + } else + espp = (struct newesp*)(mtod(m, caddr_t) + off); + + if (cmd == PRC_MSGSIZE) { + int valid = 0; + + /* + * Check to see if we have a valid SA corresponding to + * the address in the ICMP message payload. + */ + sav = key_allocsa(AF_INET6, + (caddr_t)&sa6_src.sin6_addr, + (caddr_t)&sa6_dst, IPPROTO_ESP, + espp->esp_spi); + if (sav) { + if (sav->state == SADB_SASTATE_MATURE || + sav->state == SADB_SASTATE_DYING) + valid++; + key_freesav(sav); + } + + /* XXX Further validation? */ + + /* + * Depending on the value of "valid" and routing table + * size (mtudisc_{hi,lo}wat), we will: + * - recalcurate the new MTU and create the + * corresponding routing entry, or + * - ignore the MTU change notification. + */ + icmp6_mtudisc_update((struct ip6ctlparam *)d, valid); + } + } else { + /* we normally notify any pcb here */ + } +} #endif /* INET6 */ diff --git a/bsd/netinet6/esp_output.c b/bsd/netinet6/esp_output.c index 26a1b0ca6..9ada8fc7c 100644 --- a/bsd/netinet6/esp_output.c +++ b/bsd/netinet6/esp_output.c @@ -1,4 +1,5 @@ -/* $KAME: esp_output.c,v 1.17 2000/02/22 14:04:15 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/esp_output.c,v 1.1.2.2 2001/07/03 11:01:50 ume Exp $ */ +/* $KAME: esp_output.c,v 1.43 2001/03/01 07:10:45 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -30,9 +31,6 @@ */ #define _IP_VHL -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#endif /* * RFC1827/2406 Encapsulated Security Payload. @@ -66,11 +64,19 @@ #endif #include +#if INET6 +#include +#endif #include +#if INET6 +#include +#endif #include +#if INET6 +#include +#endif #include #include -#include #include @@ -85,7 +91,8 @@ esp_hdrsiz(isr) struct ipsecrequest *isr; { struct secasvar *sav; - struct esp_algorithm *algo; + const struct esp_algorithm *algo; + const struct ah_algorithm *aalgo; size_t ivlen; size_t authlen; size_t hdrsiz; @@ -106,7 +113,7 @@ esp_hdrsiz(isr) goto estimate; /* we need transport mode ESP. */ - algo = &esp_algorithms[sav->alg_enc]; + algo = esp_algorithm_lookup(sav->alg_enc); if (!algo) goto estimate; ivlen = sav->ivlen; @@ -125,8 +132,9 @@ esp_hdrsiz(isr) hdrsiz = sizeof(struct esp) + ivlen + 9; } else { /* RFC 2406 */ - if (sav->replay && sav->alg_auth && sav->key_auth) - authlen = (*ah_algorithms[sav->alg_auth].sumsiz)(sav); + aalgo = ah_algorithm_lookup(sav->alg_auth); + if (aalgo && sav->replay && sav->key_auth) + authlen = (aalgo->sumsiz)(sav); else authlen = 0; hdrsiz = sizeof(struct newesp) + ivlen + 9 + authlen; @@ -138,12 +146,12 @@ esp_hdrsiz(isr) /* * ASSUMING: * sizeof(struct newesp) > sizeof(struct esp). - * 8 = ivlen for CBC mode (RFC2451). + * esp_max_ivlen() = max ivlen for CBC mode * 9 = (maximum padding length without random padding length) * + (Pad Length field) + (Next Header field). * 16 = maximum ICV we support. */ - return sizeof(struct newesp) + 8 + 9 + 16; + return sizeof(struct newesp) + esp_max_ivlen() + 9 + 16; } /* @@ -179,7 +187,7 @@ esp_output(m, nexthdrp, md, isr, af) struct esp *esp; struct esptail *esptail; struct secasvar *sav = isr->sav; - struct esp_algorithm *algo; + const struct esp_algorithm *algo; u_int32_t spi; u_int8_t nxt = 0; size_t plen; /*payload length to be encrypted*/ @@ -188,16 +196,19 @@ esp_output(m, nexthdrp, md, isr, af) int afnumber; size_t extendsiz; int error = 0; + struct ipsecstat *stat; switch (af) { #if INET case AF_INET: afnumber = 4; + stat = &ipsecstat; break; #endif #if INET6 case AF_INET6: afnumber = 6; + stat = &ipsec6stat; break; #endif default: @@ -220,28 +231,31 @@ esp_output(m, nexthdrp, md, isr, af) (u_int32_t)ntohl(ip->ip_dst.s_addr), (u_int32_t)ntohl(sav->spi))); ipsecstat.out_inval++; - m_freem(m); - return EINVAL; + break; } #endif /*INET*/ #if INET6 case AF_INET6: - { - struct ip6_hdr *ip6; - - ip6 = mtod(m, struct ip6_hdr *); ipseclog((LOG_DEBUG, "esp6_output: internal error: " "sav->replay is null: SPI=%u\n", (u_int32_t)ntohl(sav->spi))); ipsec6stat.out_inval++; - m_freem(m); - return EINVAL; - } + break; #endif /*INET6*/ + default: + panic("esp_output: should not reach here"); } + m_freem(m); + return EINVAL; } - algo = &esp_algorithms[sav->alg_enc]; /*XXX*/ + algo = esp_algorithm_lookup(sav->alg_enc); + if (!algo) { + ipseclog((LOG_ERR, "esp_output: unsupported algorithm: " + "SPI=%u\n", (u_int32_t)ntohl(sav->spi))); + m_freem(m); + return EINVAL; + } spi = sav->spi; ivlen = sav->ivlen; /* should be okey */ @@ -326,7 +340,7 @@ esp_output(m, nexthdrp, md, isr, af) * before: IP ... payload * after: IP ... ESP IV payload */ - if (M_LEADINGSPACE(md) < esphlen) { + if (M_LEADINGSPACE(md) < esphlen || (md->m_flags & M_EXT) != 0) { MGET(n, M_DONTWAIT, MT_DATA); if (!n) { m_freem(m); @@ -381,7 +395,7 @@ esp_output(m, nexthdrp, md, isr, af) ipseclog((LOG_WARNING, "replay counter overflowed. %s\n", ipsec_logsastr(sav))); - ipsecstat.out_inval++; + stat->out_inval++; m_freem(m); return EINVAL; } @@ -397,7 +411,6 @@ esp_output(m, nexthdrp, md, isr, af) { /* * find the last mbuf. make some room for ESP trailer. - * XXX new-esp authentication data */ #if INET struct ip *ip = NULL; @@ -405,6 +418,7 @@ esp_output(m, nexthdrp, md, isr, af) size_t padbound; u_char *extend; int i; + int randpadmax; if (algo->padbound) padbound = algo->padbound; @@ -418,13 +432,62 @@ esp_output(m, nexthdrp, md, isr, af) if (extendsiz == 1) extendsiz = padbound + 1; + /* random padding */ + switch (af) { +#if INET + case AF_INET: + randpadmax = ip4_esp_randpad; + break; +#endif +#if INET6 + case AF_INET6: + randpadmax = ip6_esp_randpad; + break; +#endif + default: + randpadmax = -1; + break; + } + if (randpadmax < 0 || plen + extendsiz >= randpadmax) + ; + else { + int n; + + /* round */ + randpadmax = (randpadmax / padbound) * padbound; + n = (randpadmax - plen + extendsiz) / padbound; + + if (n > 0) + n = (random() % n) * padbound; + else + n = 0; + + /* + * make sure we do not pad too much. + * MLEN limitation comes from the trailer attachment + * code below. + * 256 limitation comes from sequential padding. + * also, the 1-octet length field in ESP trailer imposes + * limitation (but is less strict than sequential padding + * as length field do not count the last 2 octets). + */ + if (extendsiz + n <= MLEN && extendsiz + n < 256) + extendsiz += n; + } + +#if DIAGNOSTIC + if (extendsiz > MLEN || extendsiz >= 256) + panic("extendsiz too big in esp_output"); +#endif + n = m; while (n->m_next) n = n->m_next; /* - * if M_EXT, the external part may be shared among - * two consequtive TCP packets. + * if M_EXT, the external mbuf data may be shared among + * two consequtive TCP packets, and it may be unsafe to use the + * trailing space. */ if (!(n->m_flags & M_EXT) && extendsiz < M_TRAILINGSPACE(n)) { extend = mtod(n, u_char *) + n->m_len; @@ -450,8 +513,7 @@ esp_output(m, nexthdrp, md, isr, af) } switch (sav->flags & SADB_X_EXT_PMASK) { case SADB_X_EXT_PRAND: - for (i = 0; i < extendsiz; i++) - extend[i] = random() & 0xff; + key_randomfill(extend, extendsiz); break; case SADB_X_EXT_PZERO: bzero(extend, extendsiz); @@ -493,6 +555,16 @@ esp_output(m, nexthdrp, md, isr, af) } } + /* + * pre-compute and cache intermediate key + */ + error = esp_schedule(algo, sav); + if (error) { + m_freem(m); + stat->out_inval++; + goto fail; + } + /* * encrypt the packet, based on security association * and the algorithm specified. @@ -500,20 +572,9 @@ esp_output(m, nexthdrp, md, isr, af) if (!algo->encrypt) panic("internal error: no encrypt function"); if ((*algo->encrypt)(m, espoff, plen + extendsiz, sav, algo, ivlen)) { + /* m is already freed */ ipseclog((LOG_ERR, "packet encryption failure\n")); - m_freem(m); - switch (af) { -#if INET - case AF_INET: - ipsecstat.out_inval++; - break; -#endif -#if INET6 - case AF_INET6: - ipsec6stat.out_inval++; - break; -#endif - } + stat->out_inval++; error = EINVAL; goto fail; } @@ -525,21 +586,33 @@ esp_output(m, nexthdrp, md, isr, af) goto noantireplay; if (!sav->key_auth) goto noantireplay; - if (!sav->alg_auth) + if (sav->key_auth == SADB_AALG_NONE) goto noantireplay; + { + const struct ah_algorithm *aalgo; u_char authbuf[AH_MAXSUMSIZE]; struct mbuf *n; u_char *p; size_t siz; +#if INET struct ip *ip; +#endif - siz = (((*ah_algorithms[sav->alg_auth].sumsiz)(sav) + 3) & ~(4 - 1)); + aalgo = ah_algorithm_lookup(sav->alg_auth); + if (!aalgo) + goto noantireplay; + siz = ((aalgo->sumsiz)(sav) + 3) & ~(4 - 1); if (AH_MAXSUMSIZE < siz) panic("assertion failed for AH_MAXSUMSIZE"); - if (esp_auth(m, espoff, m->m_pkthdr.len - espoff, sav, authbuf)) - goto noantireplay; + if (esp_auth(m, espoff, m->m_pkthdr.len - espoff, sav, authbuf)) { + ipseclog((LOG_ERR, "ESP checksum generation failure\n")); + m_freem(m); + error = EINVAL; + stat->out_inval++; + goto fail; + } n = m; while (n->m_next) @@ -598,32 +671,9 @@ noantireplay: if (!m) { ipseclog((LOG_ERR, "NULL mbuf after encryption in esp%d_output", afnumber)); - } else { - switch (af) { -#if INET - case AF_INET: - ipsecstat.out_success++; - break; -#endif -#if INET6 - case AF_INET6: - ipsec6stat.out_success++; - break; -#endif - } - } - switch (af) { -#if INET - case AF_INET: - ipsecstat.out_esphist[sav->alg_enc]++; - break; -#endif -#if INET6 - case AF_INET6: - ipsec6stat.out_esphist[sav->alg_enc]++; - break; -#endif - } + } else + stat->out_success++; + stat->out_esphist[sav->alg_enc]++; key_sa_recordxfer(sav, m); return 0; @@ -645,7 +695,7 @@ esp4_output(m, isr) if (m->m_len < sizeof(struct ip)) { ipseclog((LOG_DEBUG, "esp4_output: first mbuf too short\n")); m_freem(m); - return NULL; + return 0; } ip = mtod(m, struct ip *); /* XXX assumes that m->m_next points to payload */ @@ -664,7 +714,7 @@ esp6_output(m, nexthdrp, md, isr) if (m->m_len < sizeof(struct ip6_hdr)) { ipseclog((LOG_DEBUG, "esp6_output: first mbuf too short\n")); m_freem(m); - return NULL; + return 0; } return esp_output(m, nexthdrp, md, isr, AF_INET6); } diff --git a/bsd/netinet6/esp_rijndael.c b/bsd/netinet6/esp_rijndael.c new file mode 100644 index 000000000..fa35c593c --- /dev/null +++ b/bsd/netinet6/esp_rijndael.c @@ -0,0 +1,113 @@ +/* $FreeBSD: src/sys/netinet6/esp_rijndael.c,v 1.1.2.1 2001/07/03 11:01:50 ume Exp $ */ +/* $KAME: esp_rijndael.c,v 1.4 2001/03/02 05:53:05 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include + +/* as rijndael uses assymetric scheduled keys, we need to do it twice. */ +int +esp_rijndael_schedlen(algo) + const struct esp_algorithm *algo; +{ + + return sizeof(keyInstance) * 2; +} + +int +esp_rijndael_schedule(algo, sav) + const struct esp_algorithm *algo; + struct secasvar *sav; +{ + keyInstance *k; + + k = (keyInstance *)sav->sched; + if (rijndael_makeKey(&k[0], DIR_DECRYPT, _KEYLEN(sav->key_enc) * 8, + _KEYBUF(sav->key_enc)) < 0) + return -1; + if (rijndael_makeKey(&k[1], DIR_ENCRYPT, _KEYLEN(sav->key_enc) * 8, + _KEYBUF(sav->key_enc)) < 0) + return -1; + return 0; +} + +int +esp_rijndael_blockdecrypt(algo, sav, s, d) + const struct esp_algorithm *algo; + struct secasvar *sav; + u_int8_t *s; + u_int8_t *d; +{ + cipherInstance c; + keyInstance *p; + + /* does not take advantage of CBC mode support */ + bzero(&c, sizeof(c)); + if (rijndael_cipherInit(&c, MODE_ECB, NULL) < 0) + return -1; + p = (keyInstance *)sav->sched; + if (rijndael_blockDecrypt(&c, &p[0], s, algo->padbound * 8, d) < 0) + return -1; + return 0; +} + +int +esp_rijndael_blockencrypt(algo, sav, s, d) + const struct esp_algorithm *algo; + struct secasvar *sav; + u_int8_t *s; + u_int8_t *d; +{ + cipherInstance c; + keyInstance *p; + + /* does not take advantage of CBC mode support */ + bzero(&c, sizeof(c)); + if (rijndael_cipherInit(&c, MODE_ECB, NULL) < 0) + return -1; + p = (keyInstance *)sav->sched; + if (rijndael_blockEncrypt(&c, &p[1], s, algo->padbound * 8, d) < 0) + return -1; + return 0; +} diff --git a/bsd/netinet6/esp_rijndael.h b/bsd/netinet6/esp_rijndael.h new file mode 100644 index 000000000..e571f820f --- /dev/null +++ b/bsd/netinet6/esp_rijndael.h @@ -0,0 +1,42 @@ +/* $FreeBSD: src/sys/netinet6/esp_rijndael.h,v 1.1.2.1 2001/07/03 11:01:50 ume Exp $ */ +/* $KAME: esp_rijndael.h,v 1.1 2000/09/20 18:15:22 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include + +#ifdef __APPLE_API_PRIVATE +int esp_rijndael_schedlen __P((const struct esp_algorithm *)); +int esp_rijndael_schedule __P((const struct esp_algorithm *, + struct secasvar *)); +int esp_rijndael_blockdecrypt __P((const struct esp_algorithm *, + struct secasvar *, u_int8_t *, u_int8_t *)); +int esp_rijndael_blockencrypt __P((const struct esp_algorithm *, + struct secasvar *, u_int8_t *, u_int8_t *)); +#endif /* __APPLE_API_PRIVATE */ diff --git a/bsd/netinet6/frag6.c b/bsd/netinet6/frag6.c index 020c3d340..80b021c27 100644 --- a/bsd/netinet6/frag6.c +++ b/bsd/netinet6/frag6.c @@ -1,4 +1,5 @@ -/* $KAME: frag6.c,v 1.23 2000/02/28 16:18:11 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/frag6.c,v 1.2.2.5 2001/07/03 11:01:50 ume Exp $ */ +/* $KAME: frag6.c,v 1.31 2001/05/17 13:45:34 jinmei Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -49,9 +50,6 @@ #include #include #include -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__OpenBSD__) && !(defined(__bsdi__) && _BSDI_VERSION >= 199802) && !defined(__APPLE__) -#include -#endif #include #include @@ -69,19 +67,15 @@ static void frag6_insque __P((struct ip6q *, struct ip6q *)); static void frag6_remque __P((struct ip6q *)); static void frag6_freef __P((struct ip6q *)); +/* XXX we eventually need splreass6, or some real semaphore */ int frag6_doing_reass; u_int frag6_nfragpackets; struct ip6q ip6q; /* ip6 reassemble queue */ -/* FreeBSD tweak */ -#if !defined(M_FTABLE) && (defined(__FreeBSD__) && __FreeBSD__ >= 3) +#ifndef __APPLE__ MALLOC_DEFINE(M_FTABLE, "fragment", "fragment reassembly header"); #endif -#ifndef offsetof /* XXX */ -#define offsetof(type, member) ((size_t)(&((type *)0)->member)) -#endif - /* * Initialise reassembly queue and fragment identifier. */ @@ -90,13 +84,15 @@ frag6_init() { struct timeval tv; + ip6_maxfragpackets = nmbclusters / 4; + /* * in many cases, random() here does NOT return random number * as initialization during bootstrap time occur in fixed order. */ microtime(&tv); - ip6q.ip6q_next = ip6q.ip6q_prev = &ip6q; ip6_id = random() ^ tv.tv_usec; + ip6q.ip6q_next = ip6q.ip6q_prev = &ip6q; } /* @@ -167,7 +163,7 @@ frag6_input(mp, offp, proto) if (ro.ro_rt && ((ro.ro_rt->rt_flags & RTF_UP) == 0 || !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_dst))) { - RTFREE(ro.ro_rt); + rtfree(ro.ro_rt); ro.ro_rt = (struct rtentry *)0; } if (ro.ro_rt == NULL) { @@ -176,11 +172,7 @@ frag6_input(mp, offp, proto) dst->sin6_len = sizeof(struct sockaddr_in6); dst->sin6_addr = ip6->ip6_dst; } -#ifndef __bsdi__ rtalloc((struct route *)&ro); -#else - rtcalloc((struct route *)&ro); -#endif if (ro.ro_rt != NULL && ro.ro_rt->rt_ifa != NULL) dstifp = ((struct in6_ifaddr *)ro.ro_rt->rt_ifa)->ia_ifp; #else @@ -217,6 +209,8 @@ frag6_input(mp, offp, proto) /* offset now points to data portion */ offset += sizeof(struct ip6_frag); + frag6_doing_reass = 1; + for (q6 = ip6q.ip6q_next; q6 != &ip6q; q6 = q6->ip6q_next) if (ip6f->ip6f_ident == q6->ip6q_ident && IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &q6->ip6q_src) && @@ -228,7 +222,6 @@ frag6_input(mp, offp, proto) * the first fragment to arrive, create a reassembly queue. */ first_frag = 1; - frag6_nfragpackets++; /* * Enforce upper bound on number of fragmented packets @@ -236,11 +229,11 @@ frag6_input(mp, offp, proto) * If maxfrag is 0, never accept fragments. * If maxfrag is -1, accept all fragments without limitation. */ - if (frag6_nfragpackets >= (u_int)ip6_maxfragpackets) { - ip6stat.ip6s_fragoverflow++; - in6_ifstat_inc(dstifp, ifs6_reass_fail); - frag6_freef(ip6q.ip6q_prev); - } + if (ip6_maxfragpackets < 0) + ; + else if (frag6_nfragpackets >= (u_int)ip6_maxfragpackets) + goto dropfrag; + frag6_nfragpackets++; q6 = (struct ip6q *)_MALLOC(sizeof(struct ip6q), M_FTABLE, M_DONTWAIT); if (q6 == NULL) @@ -251,7 +244,7 @@ frag6_input(mp, offp, proto) /* ip6q_nxt will be filled afterwards, from 1st fragment */ q6->ip6q_down = q6->ip6q_up = (struct ip6asfrag *)q6; -#if notyet +#ifdef notyet q6->ip6q_nxtp = (u_char *)nxtp; #endif q6->ip6q_ident = ip6f->ip6f_ident; @@ -285,6 +278,7 @@ frag6_input(mp, offp, proto) icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, offset - sizeof(struct ip6_frag) + offsetof(struct ip6_frag, ip6f_offlg)); + frag6_doing_reass = 0; return(IPPROTO_DONE); } } @@ -292,6 +286,7 @@ frag6_input(mp, offp, proto) icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, offset - sizeof(struct ip6_frag) + offsetof(struct ip6_frag, ip6f_offlg)); + frag6_doing_reass = 0; return(IPPROTO_DONE); } /* @@ -311,7 +306,7 @@ frag6_input(mp, offp, proto) /* dequeue the fragment. */ frag6_deq(af6); - _FREE(af6, M_FTABLE); + FREE(af6, M_FTABLE); /* adjust pointer. */ ip6err = mtod(merr, struct ip6_hdr *); @@ -404,18 +399,24 @@ frag6_input(mp, offp, proto) i = af6->ip6af_up->ip6af_off + af6->ip6af_up->ip6af_frglen - ip6af->ip6af_off; if (i > 0) { +#if 0 /* suppress the noisy log */ log(LOG_ERR, "%d bytes of a fragment from %s " "overlaps the previous fragment\n", i, ip6_sprintf(&q6->ip6q_src)); +#endif + FREE(ip6af, M_FTABLE); goto dropfrag; } } if (af6 != (struct ip6asfrag *)q6) { i = (ip6af->ip6af_off + ip6af->ip6af_frglen) - af6->ip6af_off; if (i > 0) { +#if 0 /* suppress the noisy log */ log(LOG_ERR, "%d bytes of a fragment from %s " "overlaps the succeeding fragment", i, ip6_sprintf(&q6->ip6q_src)); +#endif + FREE(ip6af, M_FTABLE); goto dropfrag; } } @@ -464,13 +465,13 @@ insert: t = t->m_next; t->m_next = IP6_REASS_MBUF(af6); m_adj(t->m_next, af6->ip6af_offset); - _FREE(af6, M_FTABLE); + FREE(af6, M_FTABLE); af6 = af6dwn; } /* adjust offset to point where the original next header starts */ offset = ip6af->ip6af_offset - sizeof(struct ip6_frag); - _FREE(ip6af, M_FTABLE); + FREE(ip6af, M_FTABLE); ip6 = mtod(m, struct ip6_hdr *); ip6->ip6_plen = htons((u_short)next + offset - sizeof(struct ip6_hdr)); ip6->ip6_src = q6->ip6q_src; @@ -492,7 +493,7 @@ insert: /* this comes with no copy if the boundary is on cluster */ if ((t = m_split(m, offset, M_DONTWAIT)) == NULL) { frag6_remque(q6); - _FREE(q6, M_FTABLE); + FREE(q6, M_FTABLE); frag6_nfragpackets--; goto dropfrag; } @@ -509,7 +510,7 @@ insert: } frag6_remque(q6); - _FREE(q6, M_FTABLE); + FREE(q6, M_FTABLE); frag6_nfragpackets--; if (m->m_flags & M_PKTHDR) { /* Isn't it always true? */ @@ -536,6 +537,7 @@ insert: in6_ifstat_inc(dstifp, ifs6_reass_fail); ip6stat.ip6s_fragdropped++; m_freem(m); + frag6_doing_reass = 0; return IPPROTO_DONE; } @@ -574,11 +576,11 @@ frag6_freef(q6) ICMP6_TIME_EXCEED_REASSEMBLY, 0); } else m_freem(m); - _FREE(af6, M_FTABLE); + FREE(af6, M_FTABLE); } frag6_remque(q6); - _FREE(q6, M_FTABLE); + FREE(q6, M_FTABLE); frag6_nfragpackets--; } @@ -626,7 +628,7 @@ frag6_remque(p6) } /* - * IP timer processing; + * IPv6 reassembling timer processing; * if a timer expires on a reassembly * queue, discard it. */ @@ -634,15 +636,7 @@ void frag6_slowtimo() { struct ip6q *q6; - int s; -#ifdef __NetBSD__ - s = splsoftnet(); -#else - s = splnet(); -#endif -#if 0 - extern struct route_in6 ip6_forward_rt; -#endif + int s = splnet(); frag6_doing_reass = 1; q6 = ip6q.ip6q_next; @@ -661,7 +655,8 @@ frag6_slowtimo() * (due to the limit being lowered), drain off * enough to get down to the new limit. */ - while (frag6_nfragpackets > (u_int)ip6_maxfragpackets) { + while (frag6_nfragpackets > (u_int)ip6_maxfragpackets && + ip6q.ip6q_prev) { ip6stat.ip6s_fragoverflow++; /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ frag6_freef(ip6q.ip6q_prev); @@ -675,11 +670,11 @@ frag6_slowtimo() * destination and the cache is never replaced. */ if (ip6_forward_rt.ro_rt) { - RTFREE(ip6_forward_rt.ro_rt); + rtfree(ip6_forward_rt.ro_rt); ip6_forward_rt.ro_rt = 0; } if (ipsrcchk_rt.ro_rt) { - RTFREE(ipsrcchk_rt.ro_rt); + rtfree(ipsrcchk_rt.ro_rt); ipsrcchk_rt.ro_rt = 0; } #endif diff --git a/bsd/netinet6/icmp6.c b/bsd/netinet6/icmp6.c index 1291a6ea6..82d2d1bea 100644 --- a/bsd/netinet6/icmp6.c +++ b/bsd/netinet6/icmp6.c @@ -1,4 +1,5 @@ -/* $KAME: icmp6.c,v 1.77 2000/04/13 11:31:39 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/icmp6.c,v 1.6.2.6 2001/07/10 09:44:16 ume Exp $ */ +/* $KAME: icmp6.c,v 1.211 2001/04/04 05:56:20 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -64,12 +65,6 @@ * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94 */ -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#ifdef __NetBSD__ /*XXX*/ -#include "opt_ipsec.h" -#endif -#endif #include #include @@ -90,89 +85,155 @@ #include #include -#if defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802) -#include -#include -#endif #include #include #include #include -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__OpenBSD__) && !(defined(__bsdi__) && _BSDI_VERSION >= 199802) && !defined(__APPLE__) -#include -#else #include -#endif +#include #include #include #include -#ifdef __OpenBSD__ /*KAME IPSEC*/ -#undef IPSEC -#endif - #if IPSEC #include #include -#include + +extern int ipsec_bypass; #endif #include "faith.h" +#if defined(NFAITH) && 0 < NFAITH +#include +#endif #include +#if HAVE_NRL_INPCB +/* inpcb members */ +#define in6pcb inpcb +#define in6p_laddr inp_laddr6 +#define in6p_faddr inp_faddr6 +#define in6p_icmp6filt inp_icmp6filt +#define in6p_route inp_route +#define in6p_socket inp_socket +#define in6p_flags inp_flags +#define in6p_moptions inp_moptions6 +#define in6p_outputopts inp_outputopts6 +#define in6p_ip6 inp_ipv6 +#define in6p_flowinfo inp_flowinfo +#define in6p_sp inp_sp +#define in6p_next inp_next +#define in6p_prev inp_prev +/* macro names */ +#define sotoin6pcb sotoinpcb +/* function names */ +#define in6_pcbdetach in_pcbdetach +#define in6_rtchange in_rtchange + +/* + * for KAME src sync over BSD*'s. XXX: FreeBSD (>=3) are VERY different from + * others... + */ +#define in6p_ip6_nxt inp_ipv6.ip6_nxt +#endif + extern struct domain inet6domain; extern struct ip6protosw inet6sw[]; extern struct ip6protosw *ip6_protox[]; struct icmp6stat icmp6stat; -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__APPLE__) -extern struct in6pcb rawin6pcb; -#else extern struct inpcbhead ripcb; -#endif -extern u_int icmp6errratelim; +extern int icmp6errppslim; +static int icmp6errpps_count = 0; +static struct timeval icmp6errppslim_last; extern int icmp6_nodeinfo; -#if defined(__NetBSD__) || defined(__OpenBSD__) -static struct rttimer_queue *icmp6_mtudisc_timeout_q = NULL; -extern int pmtu_expire; -#endif -#ifndef HAVE_NRL_INPCB +static void icmp6_errcount __P((struct icmp6errstat *, int, int)); static int icmp6_rip6_input __P((struct mbuf **, int)); -#endif -static void icmp6_mtudisc_update __P((struct in6_addr *, struct icmp6_hdr *, - struct mbuf *)); static int icmp6_ratelimit __P((const struct in6_addr *, const int, const int)); static const char *icmp6_redirect_diag __P((struct in6_addr *, struct in6_addr *, struct in6_addr *)); -static struct mbuf * ni6_input __P((struct mbuf *, int)); +#ifndef HAVE_PPSRATECHECK +static int ppsratecheck __P((struct timeval *, int *, int)); +#endif +static struct mbuf *ni6_input __P((struct mbuf *, int)); +static struct mbuf *ni6_nametodns __P((const char *, int, int)); +static int ni6_dnsmatch __P((const char *, int, const char *, int)); static int ni6_addrs __P((struct icmp6_nodeinfo *, struct mbuf *, - struct ifnet **)); + struct ifnet **, char *)); static int ni6_store_addrs __P((struct icmp6_nodeinfo *, struct icmp6_nodeinfo *, struct ifnet *, int)); -#if defined(__NetBSD__) || defined(__OpenBSD__) -static struct rtentry *icmp6_mtudisc_clone __P((struct sockaddr *)); -static void icmp6_mtudisc_timeout __P((struct rtentry *, struct rttimer *)); -#endif +static int icmp6_notify_error __P((struct mbuf *, int, int, int)); #ifdef COMPAT_RFC1885 static struct route_in6 icmp6_reflect_rt; #endif -static struct timeval icmp6_nextsend = {0, 0}; -#if MIP6 -int (*mip6_icmp6_input_hook)(struct mbuf *m, int off) = NULL; -#endif /* MIP6 */ void icmp6_init() { mld6_init(); -#if defined(__NetBSD__) || defined(__OpenBSD__) - icmp6_mtudisc_timeout_q = rt_timer_queue_create(pmtu_expire); -#endif +} + +static void +icmp6_errcount(stat, type, code) + struct icmp6errstat *stat; + int type, code; +{ + switch (type) { + case ICMP6_DST_UNREACH: + switch (code) { + case ICMP6_DST_UNREACH_NOROUTE: + stat->icp6errs_dst_unreach_noroute++; + return; + case ICMP6_DST_UNREACH_ADMIN: + stat->icp6errs_dst_unreach_admin++; + return; + case ICMP6_DST_UNREACH_BEYONDSCOPE: + stat->icp6errs_dst_unreach_beyondscope++; + return; + case ICMP6_DST_UNREACH_ADDR: + stat->icp6errs_dst_unreach_addr++; + return; + case ICMP6_DST_UNREACH_NOPORT: + stat->icp6errs_dst_unreach_noport++; + return; + } + break; + case ICMP6_PACKET_TOO_BIG: + stat->icp6errs_packet_too_big++; + return; + case ICMP6_TIME_EXCEEDED: + switch (code) { + case ICMP6_TIME_EXCEED_TRANSIT: + stat->icp6errs_time_exceed_transit++; + return; + case ICMP6_TIME_EXCEED_REASSEMBLY: + stat->icp6errs_time_exceed_reassembly++; + return; + } + break; + case ICMP6_PARAM_PROB: + switch (code) { + case ICMP6_PARAMPROB_HEADER: + stat->icp6errs_paramprob_header++; + return; + case ICMP6_PARAMPROB_NEXTHEADER: + stat->icp6errs_paramprob_nextheader++; + return; + case ICMP6_PARAMPROB_OPTION: + stat->icp6errs_paramprob_option++; + return; + } + break; + case ND_REDIRECT: + stat->icp6errs_redirect++; + return; + } + stat->icp6errs_unknown++; } /* @@ -191,6 +252,9 @@ icmp6_error(m, type, code, param) icmp6stat.icp6s_error++; + /* count per-type-code statistics */ + icmp6_errcount(&icmp6stat.icp6s_outerrhist, type, code); + #ifdef M_DECRYPTED /*not openbsd*/ if (m->m_flags & M_DECRYPTED) { icmp6stat.icp6s_canterror++; @@ -282,7 +346,7 @@ icmp6_error(m, type, code, param) if (m && m->m_len < preplen) m = m_pullup(m, preplen); if (m == NULL) { - printf("ENOBUFS in icmp6_error %d\n", __LINE__); + nd6log((LOG_DEBUG, "ENOBUFS in icmp6_error %d\n", __LINE__)); return; } @@ -300,6 +364,15 @@ icmp6_error(m, type, code, param) icmp6->icmp6_code = code; icmp6->icmp6_pptr = htonl((u_int32_t)param); + /* + * icmp6_reflect() is designed to be in the input path. + * icmp6_error() can be called from both input and outut path, + * and if we are in output path rcvif could contain bogus value. + * clear m->m_pkthdr.rcvif for safety, we should have enough scope + * information in ip header (nip6). + */ + m->m_pkthdr.rcvif = NULL; + icmp6stat.icp6s_outhist[type]++; icmp6_reflect(m, sizeof(struct ip6_hdr)); /*header order: IPv6 - ICMPv6*/ @@ -326,7 +399,6 @@ icmp6_input(mp, offp, proto) int off = *offp; int icmp6len = m->m_pkthdr.len - *offp; int code, sum, noff; - struct sockaddr_in6 icmp6src; #ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_hdr), IPPROTO_DONE); @@ -359,17 +431,15 @@ icmp6_input(mp, offp, proto) code = icmp6->icmp6_code; if ((sum = in6_cksum(m, IPPROTO_ICMPV6, off, icmp6len)) != 0) { - log(LOG_ERR, + nd6log((LOG_ERR, "ICMP6 checksum error(%d|%x) %s\n", - icmp6->icmp6_type, - sum, - ip6_sprintf(&ip6->ip6_src)); + icmp6->icmp6_type, sum, ip6_sprintf(&ip6->ip6_src))); icmp6stat.icp6s_checksum++; goto freeit; } #if defined(NFAITH) && 0 < NFAITH - if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) { + if (faithprefix(&ip6->ip6_dst)) { /* * Deliver very specific ICMP6 type only. * This is important to deilver TOOBIG. Otherwise PMTUD @@ -386,34 +456,12 @@ icmp6_input(mp, offp, proto) } #endif -#if IPSEC - /* drop it if it does not match the default policy */ - if (ipsec6_in_reject(m, NULL)) { - ipsecstat.in_polvio++; - goto freeit; - } -#endif - icmp6stat.icp6s_inhist[icmp6->icmp6_type]++; icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_msg); if (icmp6->icmp6_type < ICMP6_INFOMSG_MASK) icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_error); -#if MIP6 - /* - * Mobile IPv6 - * - * Check for ICMP errors and modifications and extensions to Router - * Advertisement. - */ - if (mip6_icmp6_input_hook) { - if ((*mip6_icmp6_input_hook)(m, off) != 0) - goto freeit; - } -#endif /* MIP6 */ - switch (icmp6->icmp6_type) { - case ICMP6_DST_UNREACH: icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_dstunreach); switch (code) { @@ -507,9 +555,6 @@ icmp6_input(mp, offp, proto) * always copy the length we specified. */ if (maxlen >= MCLBYTES) { -#if DIAGNOSTIC - printf("MCLBYTES too small\n"); -#endif /* Give up remote */ m_freem(n0); break; @@ -600,21 +645,17 @@ icmp6_input(mp, offp, proto) { enum { WRU, FQDN } mode; - if (code != 0) - goto badcode; if (!icmp6_nodeinfo) break; if (icmp6len == sizeof(struct icmp6_hdr) + 4) mode = WRU; - else if (icmp6len >= sizeof(struct icmp6_hdr) + 8) /* XXX */ + else if (icmp6len >= sizeof(struct icmp6_nodeinfo)) mode = FQDN; else goto badlen; -#if defined( __FreeBSD__) || defined (__APPLE__) #define hostnamelen strlen(hostname) -#endif if (mode == FQDN) { #ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_nodeinfo), @@ -623,17 +664,19 @@ icmp6_input(mp, offp, proto) n = m_copy(m, 0, M_COPYALL); if (n) n = ni6_input(n, off); - if (n) - noff = sizeof(struct ip6_hdr); + /* XXX meaningless if n == NULL */ + noff = sizeof(struct ip6_hdr); } else { u_char *p; int maxlen, maxhlen; + if ((icmp6_nodeinfo & 5) != 5) + break; + + if (code != 0) + goto badcode; maxlen = sizeof(*nip6) + sizeof(*nicmp6) + 4; if (maxlen >= MCLBYTES) { -#if DIAGNOSTIC - printf("MCLBYTES too small\n"); -#endif /* Give up remote */ break; } @@ -649,6 +692,7 @@ icmp6_input(mp, offp, proto) /* Give up remote */ break; } + n->m_pkthdr.rcvif = NULL; n->m_len = 0; maxhlen = M_TRAILINGSPACE(n) - maxlen; if (maxhlen > hostnamelen) @@ -662,7 +706,7 @@ icmp6_input(mp, offp, proto) bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr)); p = (u_char *)(nicmp6 + 1); bzero(p, 4); - bcopy(hostname, p + 4, maxhlen); + bcopy(hostname, p + 4, maxhlen); /*meaningless TTL*/ noff = sizeof(struct ip6_hdr); M_COPY_PKTHDR(n, m); /* just for recvif */ n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) + @@ -773,10 +817,11 @@ icmp6_input(mp, offp, proto) break; default: - printf("icmp6_input: unknown type %d(src=%s, dst=%s, ifid=%d)\n", - icmp6->icmp6_type, ip6_sprintf(&ip6->ip6_src), - ip6_sprintf(&ip6->ip6_dst), - m->m_pkthdr.rcvif ? m->m_pkthdr.rcvif->if_index : 0); + nd6log((LOG_DEBUG, + "icmp6_input: unknown type %d(src=%s, dst=%s, ifid=%d)\n", + icmp6->icmp6_type, ip6_sprintf(&ip6->ip6_src), + ip6_sprintf(&ip6->ip6_dst), + m->m_pkthdr.rcvif ? m->m_pkthdr.rcvif->if_index : 0)); if (icmp6->icmp6_type < ICMP6_ECHO_REQUEST) { /* ICMPv6 error: MUST deliver it by spec... */ code = PRC_NCMDS; @@ -786,32 +831,63 @@ icmp6_input(mp, offp, proto) break; } deliver: - if (icmp6len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) { - icmp6stat.icp6s_tooshort++; - goto freeit; + if (icmp6_notify_error(m, off, icmp6len, code)) { + /* In this case, m should've been freed. */ + return(IPPROTO_DONE); } + break; + + badcode: + icmp6stat.icp6s_badcode++; + break; + + badlen: + icmp6stat.icp6s_badlen++; + break; + } + + /* deliver the packet to appropriate sockets */ + icmp6_rip6_input(&m, *offp); + + return IPPROTO_DONE; + + freeit: + m_freem(m); + return IPPROTO_DONE; +} + +static int +icmp6_notify_error(m, off, icmp6len, code) + struct mbuf *m; + int off, icmp6len; +{ + struct icmp6_hdr *icmp6; + struct ip6_hdr *eip6; + u_int32_t notifymtu; + struct sockaddr_in6 icmp6src, icmp6dst; + + if (icmp6len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) { + icmp6stat.icp6s_tooshort++; + goto freeit; + } #ifndef PULLDOWN_TEST - IP6_EXTHDR_CHECK(m, off, - sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr), - IPPROTO_DONE); - icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off); + IP6_EXTHDR_CHECK(m, off, + sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr), + -1); + icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off); #else - IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, - sizeof(*icmp6) + sizeof(struct ip6_hdr)); - if (icmp6 == NULL) { - icmp6stat.icp6s_tooshort++; - return IPPROTO_DONE; - } + IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, + sizeof(*icmp6) + sizeof(struct ip6_hdr)); + if (icmp6 == NULL) { + icmp6stat.icp6s_tooshort++; + return(-1); + } #endif - bzero(&icmp6src, sizeof(icmp6src)); - icmp6src.sin6_len = sizeof(struct sockaddr_in6); - icmp6src.sin6_family = AF_INET6; - icmp6src.sin6_addr = ((struct ip6_hdr *)(icmp6 + 1))->ip6_dst; + eip6 = (struct ip6_hdr *)(icmp6 + 1); - /* Detect the upper level protocol */ - { + /* Detect the upper level protocol */ + { void (*ctlfunc) __P((int, struct sockaddr *, void *)); - struct ip6_hdr *eip6 = (struct ip6_hdr *)(icmp6 + 1); u_int8_t nxt = eip6->ip6_nxt; int eoff = off + sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr); @@ -826,22 +902,22 @@ icmp6_input(mp, offp, proto) while (1) { /* XXX: should avoid inf. loop explicitly? */ struct ip6_ext *eh; - switch(nxt) { + switch (nxt) { case IPPROTO_HOPOPTS: case IPPROTO_DSTOPTS: case IPPROTO_AH: #ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, 0, eoff + sizeof(struct ip6_ext), - IPPROTO_DONE); + -1); eh = (struct ip6_ext *)(mtod(m, caddr_t) + eoff); #else IP6_EXTHDR_GET(eh, struct ip6_ext *, m, - eoff, sizeof(*eh)); + eoff, sizeof(*eh)); if (eh == NULL) { icmp6stat.icp6s_tooshort++; - return IPPROTO_DONE; + return(-1); } #endif @@ -862,15 +938,15 @@ icmp6_input(mp, offp, proto) */ #ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, 0, eoff + sizeof(*rth), - IPPROTO_DONE); + -1); rth = (struct ip6_rthdr *)(mtod(m, caddr_t) + eoff); #else IP6_EXTHDR_GET(rth, struct ip6_rthdr *, m, - eoff, sizeof(*rth)); + eoff, sizeof(*rth)); if (rth == NULL) { icmp6stat.icp6s_tooshort++; - return IPPROTO_DONE; + return(-1); } #endif rthlen = (rth->ip6r_len + 1) << 3; @@ -888,7 +964,7 @@ icmp6_input(mp, offp, proto) #ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, 0, eoff + rthlen, - IPPROTO_DONE); + -1); rth0 = (struct ip6_rthdr0 *)(mtod(m, caddr_t) + eoff); #else IP6_EXTHDR_GET(rth0, @@ -896,7 +972,7 @@ icmp6_input(mp, offp, proto) eoff, rthlen); if (rth0 == NULL) { icmp6stat.icp6s_tooshort++; - return IPPROTO_DONE; + return(-1); } #endif /* just ignore a bogus header */ @@ -911,15 +987,15 @@ icmp6_input(mp, offp, proto) #ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, 0, eoff + sizeof(struct ip6_frag), - IPPROTO_DONE); + -1); fh = (struct ip6_frag *)(mtod(m, caddr_t) + eoff); #else IP6_EXTHDR_GET(fh, struct ip6_frag *, m, - eoff, sizeof(*fh)); + eoff, sizeof(*fh)); if (fh == NULL) { icmp6stat.icp6s_tooshort++; - return IPPROTO_DONE; + return(-1); } #endif /* @@ -946,95 +1022,117 @@ icmp6_input(mp, offp, proto) goto notify; } } - notify: + notify: #ifndef PULLDOWN_TEST icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off); #else IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, - sizeof(*icmp6) + sizeof(struct ip6_hdr)); + sizeof(*icmp6) + sizeof(struct ip6_hdr)); if (icmp6 == NULL) { icmp6stat.icp6s_tooshort++; - return IPPROTO_DONE; + return(-1); } #endif + + eip6 = (struct ip6_hdr *)(icmp6 + 1); + bzero(&icmp6dst, sizeof(icmp6dst)); + icmp6dst.sin6_len = sizeof(struct sockaddr_in6); + icmp6dst.sin6_family = AF_INET6; + if (finaldst == NULL) + icmp6dst.sin6_addr = eip6->ip6_dst; + else + icmp6dst.sin6_addr = *finaldst; + icmp6dst.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif, + &icmp6dst.sin6_addr); +#ifndef SCOPEDROUTING + if (in6_embedscope(&icmp6dst.sin6_addr, &icmp6dst, + NULL, NULL)) { + /* should be impossbile */ + nd6log((LOG_DEBUG, + "icmp6_notify_error: in6_embedscope failed\n")); + goto freeit; + } +#endif + + /* + * retrieve parameters from the inner IPv6 header, and convert + * them into sockaddr structures. + */ + bzero(&icmp6src, sizeof(icmp6src)); + icmp6src.sin6_len = sizeof(struct sockaddr_in6); + icmp6src.sin6_family = AF_INET6; + icmp6src.sin6_addr = eip6->ip6_src; + icmp6src.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif, + &icmp6src.sin6_addr); +#ifndef SCOPEDROUTING + if (in6_embedscope(&icmp6src.sin6_addr, &icmp6src, + NULL, NULL)) { + /* should be impossbile */ + nd6log((LOG_DEBUG, + "icmp6_notify_error: in6_embedscope failed\n")); + goto freeit; + } +#endif + icmp6src.sin6_flowinfo = + (eip6->ip6_flow & IPV6_FLOWLABEL_MASK); + + if (finaldst == NULL) + finaldst = &eip6->ip6_dst; + ip6cp.ip6c_m = m; + ip6cp.ip6c_icmp6 = icmp6; + ip6cp.ip6c_ip6 = (struct ip6_hdr *)(icmp6 + 1); + ip6cp.ip6c_off = eoff; + ip6cp.ip6c_finaldst = finaldst; + ip6cp.ip6c_src = &icmp6src; + ip6cp.ip6c_nxt = nxt; + if (icmp6type == ICMP6_PACKET_TOO_BIG) { - if (finaldst == NULL) - finaldst = &((struct ip6_hdr *)(icmp6 + 1))->ip6_dst; - icmp6_mtudisc_update(finaldst, icmp6, m); + notifymtu = ntohl(icmp6->icmp6_mtu); + ip6cp.ip6c_cmdarg = (void *)¬ifymtu; + icmp6_mtudisc_update(&ip6cp, 1); /*XXX*/ } ctlfunc = (void (*) __P((int, struct sockaddr *, void *))) (ip6_protox[nxt]->pr_ctlinput); if (ctlfunc) { - ip6cp.ip6c_m = m; - ip6cp.ip6c_ip6 = (struct ip6_hdr *)(icmp6 + 1); - ip6cp.ip6c_off = eoff; - (*ctlfunc)(code, (struct sockaddr *)&icmp6src, &ip6cp); + (void) (*ctlfunc)(code, (struct sockaddr *)&icmp6dst, + &ip6cp); } - } - break; - - badcode: - icmp6stat.icp6s_badcode++; - break; - - badlen: - icmp6stat.icp6s_badlen++; - break; } + return(0); -#if HAVE_NRL_INPCB - rip6_input(&m, offp, IPPROTO_ICMPV6); -#else - icmp6_rip6_input(&m, *offp); -#endif - return IPPROTO_DONE; - - freeit: + freeit: m_freem(m); - return IPPROTO_DONE; + return(-1); } -static void -icmp6_mtudisc_update(dst, icmp6, m) - struct in6_addr *dst; - struct icmp6_hdr *icmp6;/* we can assume the validity of the pointer */ - struct mbuf *m; /* currently unused but added for scoped addrs */ +void +icmp6_mtudisc_update(ip6cp, validated) + struct ip6ctlparam *ip6cp; + int validated; { + struct in6_addr *dst = ip6cp->ip6c_finaldst; + struct icmp6_hdr *icmp6 = ip6cp->ip6c_icmp6; + struct mbuf *m = ip6cp->ip6c_m; /* will be necessary for scope issue */ u_int mtu = ntohl(icmp6->icmp6_mtu); struct rtentry *rt = NULL; struct sockaddr_in6 sin6; -#ifdef __bsdi__ - struct route_in6 ro6; -#endif + + if (!validated) + return; bzero(&sin6, sizeof(sin6)); sin6.sin6_family = PF_INET6; sin6.sin6_len = sizeof(struct sockaddr_in6); sin6.sin6_addr = *dst; - /* sin6.sin6_scope_id = XXX: should be set if DST is a scoped addr */ -#if defined(__NetBSD__) || defined(__OpenBSD__) - rt = rtalloc1((struct sockaddr *)&sin6, 1); /*clone*/ - if (!rt || (rt->rt_flags & RTF_HOST) == 0) { - if (rt) - RTFREE(rt); - rt = icmp6_mtudisc_clone((struct sockaddr *)&sin6); + /* XXX normally, this won't happen */ + if (IN6_IS_ADDR_LINKLOCAL(dst)) { + sin6.sin6_addr.s6_addr16[1] = + htons(m->m_pkthdr.rcvif->if_index); } -#else -#if defined(__FreeBSD__) || defined (__APPLE__) + /* sin6.sin6_scope_id = XXX: should be set if DST is a scoped addr */ rt = rtalloc1((struct sockaddr *)&sin6, 0, RTF_CLONING | RTF_PRCLONING); -#else -#ifdef __bsdi__ - bcopy(&sin6, &ro6.ro_dst, sizeof(struct sockaddr_in6)); - ro6.ro_rt = 0; - rtcalloc((struct route *)&ro6); - rt = ro6.ro_rt; -#else -#error no case for this particular operating system -#endif -#endif -#endif if (rt && (rt->rt_flags & RTF_HOST) && !(rt->rt_rmx.rmx_locks & RTV_MTU)) { @@ -1043,23 +1141,26 @@ icmp6_mtudisc_update(dst, icmp6, m) rt->rt_rmx.rmx_locks |= RTV_MTU; } else if (mtu < rt->rt_ifp->if_mtu && rt->rt_rmx.rmx_mtu > mtu) { + icmp6stat.icp6s_pmtuchg++; rt->rt_rmx.rmx_mtu = mtu; } } if (rt) - RTFREE(rt); + rtfree(rt); } /* - * Process a Node Information Query + * Process a Node Information Query packet, based on + * draft-ietf-ipngwg-icmp-name-lookups-07. + * + * Spec incompatibilities: + * - IPv6 Subject address handling + * - IPv4 Subject address handling support missing + * - Proxy reply (answer even if it's not for me) + * - joins NI group address at in6_ifattach() time only, does not cope + * with hostname changes by sethostname(3) */ -#if defined(__FreeBSD__) || defined (__APPLE__) #define hostnamelen strlen(hostname) -#endif -#ifndef offsetof /* XXX */ -#define offsetof(type, member) ((size_t)(&((type *)0)->member)) -#endif - static struct mbuf * ni6_input(m, off) struct mbuf *m; @@ -1068,11 +1169,19 @@ ni6_input(m, off) struct icmp6_nodeinfo *ni6, *nni6; struct mbuf *n = NULL; u_int16_t qtype; + int subjlen; int replylen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_nodeinfo); struct ni_reply_fqdn *fqdn; int addrs; /* for NI_QTYPE_NODEADDR */ struct ifnet *ifp = NULL; /* for NI_QTYPE_NODEADDR */ + struct sockaddr_in6 sin6; /* double meaning; ip6_dst and subjectaddr */ + struct sockaddr_in6 sin6_d; /* XXX: we should retrieve this from m_aux */ + struct ip6_hdr *ip6; + int oldfqdn = 0; /* if 1, return pascal string (03 draft) */ + char *subj = NULL; + struct in6_ifaddr *ia6 = NULL; + ip6 = mtod(m, struct ip6_hdr *); #ifndef PULLDOWN_TEST ni6 = (struct icmp6_nodeinfo *)(mtod(m, caddr_t) + off); #else @@ -1082,41 +1191,194 @@ ni6_input(m, off) return NULL; } #endif + + /* + * Validate IPv6 destination address. + * + * The Responder must discard the Query without further processing + * unless it is one of the Responder's unicast or anycast addresses, or + * a link-local scope multicast address which the Responder has joined. + * [icmp-name-lookups-07, Section 4.] + */ + bzero(&sin6, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_len = sizeof(struct sockaddr_in6); + bcopy(&ip6->ip6_dst, &sin6.sin6_addr, sizeof(sin6.sin6_addr)); + /* XXX scopeid */ + if ((ia6 = (struct in6_ifaddr *)ifa_ifwithaddr((struct sockaddr *)&sin6)) != NULL) { + /* unicast/anycast, fine */ + if ((ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0 && + (icmp6_nodeinfo & 4) == 0) { + nd6log((LOG_DEBUG, "ni6_input: ignore node info to " + "a temporary address in %s:%d", + __FILE__, __LINE__)); + goto bad; + } + } else if (IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) + ; /* link-local multicast, fine */ + else + goto bad; + + /* validate query Subject field. */ qtype = ntohs(ni6->ni_qtype); + subjlen = m->m_pkthdr.len - off - sizeof(struct icmp6_nodeinfo); + switch (qtype) { + case NI_QTYPE_NOOP: + case NI_QTYPE_SUPTYPES: + /* 07 draft */ + if (ni6->ni_code == ICMP6_NI_SUBJ_FQDN && subjlen == 0) + break; + /* FALLTHROUGH */ + case NI_QTYPE_FQDN: + case NI_QTYPE_NODEADDR: + switch (ni6->ni_code) { + case ICMP6_NI_SUBJ_IPV6: +#if ICMP6_NI_SUBJ_IPV6 != 0 + case 0: +#endif + /* + * backward compatibility - try to accept 03 draft + * format, where no Subject is present. + */ + if (qtype == NI_QTYPE_FQDN && ni6->ni_code == 0 && + subjlen == 0) { + oldfqdn++; + break; + } +#if ICMP6_NI_SUBJ_IPV6 != 0 + if (ni6->ni_code != ICMP6_NI_SUBJ_IPV6) + goto bad; +#endif + + if (subjlen != sizeof(sin6.sin6_addr)) + goto bad; + + /* + * Validate Subject address. + * + * Not sure what exactly "address belongs to the node" + * means in the spec, is it just unicast, or what? + * + * At this moment we consider Subject address as + * "belong to the node" if the Subject address equals + * to the IPv6 destination address; validation for + * IPv6 destination address should have done enough + * check for us. + * + * We do not do proxy at this moment. + */ + /* m_pulldown instead of copy? */ + m_copydata(m, off + sizeof(struct icmp6_nodeinfo), + subjlen, (caddr_t)&sin6.sin6_addr); + sin6.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif, + &sin6.sin6_addr); +#ifndef SCOPEDROUTING + in6_embedscope(&sin6.sin6_addr, &sin6, NULL, NULL); +#endif + bzero(&sin6_d, sizeof(sin6_d)); + sin6_d.sin6_family = AF_INET6; /* not used, actually */ + sin6_d.sin6_len = sizeof(sin6_d); /* ditto */ + sin6_d.sin6_addr = ip6->ip6_dst; + sin6_d.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif, + &ip6->ip6_dst); +#ifndef SCOPEDROUTING + in6_embedscope(&sin6_d.sin6_addr, &sin6_d, NULL, NULL); +#endif + subj = (char *)&sin6; + if (SA6_ARE_ADDR_EQUAL(&sin6, &sin6_d)) + break; + + /* + * XXX if we are to allow other cases, we should really + * be careful about scope here. + * basically, we should disallow queries toward IPv6 + * destination X with subject Y, if scope(X) > scope(Y). + * if we allow scope(X) > scope(Y), it will result in + * information leakage across scope boundary. + */ + goto bad; - switch(qtype) { - case NI_QTYPE_NOOP: - break; /* no reply data */ - case NI_QTYPE_SUPTYPES: - goto bad; /* xxx: to be implemented */ - break; - case NI_QTYPE_FQDN: - replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_name) + - hostnamelen; - break; - case NI_QTYPE_NODEADDR: - addrs = ni6_addrs(ni6, m, &ifp); - if ((replylen += addrs * sizeof(struct in6_addr)) > MCLBYTES) - replylen = MCLBYTES; /* XXX: we'll truncate later */ - - break; - default: - /* - * XXX: We must return a reply with the ICMP6 code - * `unknown Qtype' in this case. However we regard the case - * as an FQDN query for backward compatibility. - * Older versions set a random value to this field, - * so it rarely varies in the defined qtypes. - * But the mechanism is not reliable... - * maybe we should obsolete older versions. - */ - qtype = NI_QTYPE_FQDN; - replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_name) + - hostnamelen; - break; + case ICMP6_NI_SUBJ_FQDN: + /* + * Validate Subject name with gethostname(3). + * + * The behavior may need some debate, since: + * - we are not sure if the node has FQDN as + * hostname (returned by gethostname(3)). + * - the code does wildcard match for truncated names. + * however, we are not sure if we want to perform + * wildcard match, if gethostname(3) side has + * truncated hostname. + */ + n = ni6_nametodns(hostname, hostnamelen, 0); + if (!n || n->m_next || n->m_len == 0) + goto bad; + IP6_EXTHDR_GET(subj, char *, m, + off + sizeof(struct icmp6_nodeinfo), subjlen); + if (subj == NULL) + goto bad; + if (!ni6_dnsmatch(subj, subjlen, mtod(n, const char *), + n->m_len)) { + goto bad; + } + m_freem(n); + n = NULL; + break; + + case ICMP6_NI_SUBJ_IPV4: /* XXX: to be implemented? */ + default: + goto bad; + } + break; } - /* allocate a mbuf to reply. */ + /* refuse based on configuration. XXX ICMP6_NI_REFUSED? */ + switch (qtype) { + case NI_QTYPE_FQDN: + if ((icmp6_nodeinfo & 1) == 0) + goto bad; + break; + case NI_QTYPE_NODEADDR: + if ((icmp6_nodeinfo & 2) == 0) + goto bad; + break; + } + + /* guess reply length */ + switch (qtype) { + case NI_QTYPE_NOOP: + break; /* no reply data */ + case NI_QTYPE_SUPTYPES: + replylen += sizeof(u_int32_t); + break; + case NI_QTYPE_FQDN: + /* XXX will append an mbuf */ + replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen); + break; + case NI_QTYPE_NODEADDR: + addrs = ni6_addrs(ni6, m, &ifp, subj); + if ((replylen += addrs * (sizeof(struct in6_addr) + + sizeof(u_int32_t))) > MCLBYTES) + replylen = MCLBYTES; /* XXX: will truncate pkt later */ + break; + default: + /* + * XXX: We must return a reply with the ICMP6 code + * `unknown Qtype' in this case. However we regard the case + * as an FQDN query for backward compatibility. + * Older versions set a random value to this field, + * so it rarely varies in the defined qtypes. + * But the mechanism is not reliable... + * maybe we should obsolete older versions. + */ + qtype = NI_QTYPE_FQDN; + /* XXX will append an mbuf */ + replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen); + oldfqdn++; + break; + } + + /* allocate an mbuf to reply. */ MGETHDR(n, M_DONTWAIT, m->m_type); if (n == NULL) { m_freem(m); @@ -1124,12 +1386,13 @@ ni6_input(m, off) } M_COPY_PKTHDR(n, m); /* just for recvif */ if (replylen > MHLEN) { - if (replylen > MCLBYTES) - /* - * XXX: should we try to allocate more? But MCLBYTES is - * probably much larger than IPV6_MMTU... - */ + if (replylen > MCLBYTES) { + /* + * XXX: should we try to allocate more? But MCLBYTES + * is probably much larger than IPV6_MMTU... + */ goto bad; + } MCLGET(n, M_DONTWAIT); if ((n->m_flags & M_EXT) == 0) { goto bad; @@ -1137,102 +1400,286 @@ ni6_input(m, off) } n->m_pkthdr.len = n->m_len = replylen; - /* copy mbuf header and IPv6 + Node Information base headers */ - bcopy(mtod(m, caddr_t), mtod(n, caddr_t), sizeof(struct ip6_hdr)); - nni6 = (struct icmp6_nodeinfo *)(mtod(n, struct ip6_hdr *) + 1); - bcopy((caddr_t)ni6, (caddr_t)nni6, sizeof(struct icmp6_nodeinfo)); + /* copy mbuf header and IPv6 + Node Information base headers */ + bcopy(mtod(m, caddr_t), mtod(n, caddr_t), sizeof(struct ip6_hdr)); + nni6 = (struct icmp6_nodeinfo *)(mtod(n, struct ip6_hdr *) + 1); + bcopy((caddr_t)ni6, (caddr_t)nni6, sizeof(struct icmp6_nodeinfo)); + + /* qtype dependent procedure */ + switch (qtype) { + case NI_QTYPE_NOOP: + nni6->ni_code = ICMP6_NI_SUCCESS; + nni6->ni_flags = 0; + break; + case NI_QTYPE_SUPTYPES: + { + u_int32_t v; + nni6->ni_code = ICMP6_NI_SUCCESS; + nni6->ni_flags = htons(0x0000); /* raw bitmap */ + /* supports NOOP, SUPTYPES, FQDN, and NODEADDR */ + v = (u_int32_t)htonl(0x0000000f); + bcopy(&v, nni6 + 1, sizeof(u_int32_t)); + break; + } + case NI_QTYPE_FQDN: + nni6->ni_code = ICMP6_NI_SUCCESS; + fqdn = (struct ni_reply_fqdn *)(mtod(n, caddr_t) + + sizeof(struct ip6_hdr) + + sizeof(struct icmp6_nodeinfo)); + nni6->ni_flags = 0; /* XXX: meaningless TTL */ + fqdn->ni_fqdn_ttl = 0; /* ditto. */ + /* + * XXX do we really have FQDN in variable "hostname"? + */ + n->m_next = ni6_nametodns(hostname, hostnamelen, oldfqdn); + if (n->m_next == NULL) + goto bad; + /* XXX we assume that n->m_next is not a chain */ + if (n->m_next->m_next != NULL) + goto bad; + n->m_pkthdr.len += n->m_next->m_len; + break; + case NI_QTYPE_NODEADDR: + { + int lenlim, copied; + + nni6->ni_code = ICMP6_NI_SUCCESS; + n->m_pkthdr.len = n->m_len = + sizeof(struct ip6_hdr) + sizeof(struct icmp6_nodeinfo); + lenlim = M_TRAILINGSPACE(n); + copied = ni6_store_addrs(ni6, nni6, ifp, lenlim); + /* XXX: reset mbuf length */ + n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) + + sizeof(struct icmp6_nodeinfo) + copied; + break; + } + default: + break; /* XXX impossible! */ + } + + nni6->ni_type = ICMP6_NI_REPLY; + m_freem(m); + return(n); + + bad: + m_freem(m); + if (n) + m_freem(n); + return(NULL); +} +#undef hostnamelen + +/* + * make a mbuf with DNS-encoded string. no compression support. + * + * XXX names with less than 2 dots (like "foo" or "foo.section") will be + * treated as truncated name (two \0 at the end). this is a wild guess. + */ +static struct mbuf * +ni6_nametodns(name, namelen, old) + const char *name; + int namelen; + int old; /* return pascal string if non-zero */ +{ + struct mbuf *m; + char *cp, *ep; + const char *p, *q; + int i, len, nterm; + + if (old) + len = namelen + 1; + else + len = MCLBYTES; + + /* because MAXHOSTNAMELEN is usually 256, we use cluster mbuf */ + MGET(m, M_DONTWAIT, MT_DATA); + if (m && len > MLEN) { + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) + goto fail; + } + if (!m) + goto fail; + m->m_next = NULL; + + if (old) { + m->m_len = len; + *mtod(m, char *) = namelen; + bcopy(name, mtod(m, char *) + 1, namelen); + return m; + } else { + m->m_len = 0; + cp = mtod(m, char *); + ep = mtod(m, char *) + M_TRAILINGSPACE(m); + + /* if not certain about my name, return empty buffer */ + if (namelen == 0) + return m; + + /* + * guess if it looks like shortened hostname, or FQDN. + * shortened hostname needs two trailing "\0". + */ + i = 0; + for (p = name; p < name + namelen; p++) { + if (*p && *p == '.') + i++; + } + if (i < 2) + nterm = 2; + else + nterm = 1; + + p = name; + while (cp < ep && p < name + namelen) { + i = 0; + for (q = p; q < name + namelen && *q && *q != '.'; q++) + i++; + /* result does not fit into mbuf */ + if (cp + i + 1 >= ep) + goto fail; + /* + * DNS label length restriction, RFC1035 page 8. + * "i == 0" case is included here to avoid returning + * 0-length label on "foo..bar". + */ + if (i <= 0 || i >= 64) + goto fail; + *cp++ = i; + bcopy(p, cp, i); + cp += i; + p = q; + if (p < name + namelen && *p == '.') + p++; + } + /* termination */ + if (cp + nterm >= ep) + goto fail; + while (nterm-- > 0) + *cp++ = '\0'; + m->m_len = cp - mtod(m, char *); + return m; + } + + panic("should not reach here"); + /*NOTREACHED*/ + + fail: + if (m) + m_freem(m); + return NULL; +} + +/* + * check if two DNS-encoded string matches. takes care of truncated + * form (with \0\0 at the end). no compression support. + * XXX upper/lowercase match (see RFC2065) + */ +static int +ni6_dnsmatch(a, alen, b, blen) + const char *a; + int alen; + const char *b; + int blen; +{ + const char *a0, *b0; + int l; + + /* simplest case - need validation? */ + if (alen == blen && bcmp(a, b, alen) == 0) + return 1; - /* qtype dependent procedure */ - switch (qtype) { - case NI_QTYPE_NOOP: - nni6->ni_flags = 0; - break; - case NI_QTYPE_SUPTYPES: - goto bad; /* xxx: to be implemented */ - break; - case NI_QTYPE_FQDN: - if (hostnamelen > 255) { /* XXX: rare case, but may happen */ - printf("ni6_input: " - "hostname length(%d) is too large for reply\n", - hostnamelen); - goto bad; - } - fqdn = (struct ni_reply_fqdn *)(mtod(n, caddr_t) + - sizeof(struct ip6_hdr) + - sizeof(struct icmp6_nodeinfo)); - nni6->ni_flags = 0; /* XXX: meaningless TTL */ - fqdn->ni_fqdn_ttl = 0; /* ditto. */ - fqdn->ni_fqdn_namelen = hostnamelen; - bcopy(hostname, &fqdn->ni_fqdn_name[0], hostnamelen); - break; - case NI_QTYPE_NODEADDR: - { - int lenlim, copied; - - if (n->m_flags & M_EXT) - lenlim = MCLBYTES - sizeof(struct ip6_hdr) - - sizeof(struct icmp6_nodeinfo); - else - lenlim = MHLEN - sizeof(struct ip6_hdr) - - sizeof(struct icmp6_nodeinfo); - copied = ni6_store_addrs(ni6, nni6, ifp, lenlim); - /* XXX: reset mbuf length */ - n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) + - sizeof(struct icmp6_nodeinfo) + copied; - break; - } - default: - break; /* XXX impossible! */ - } + a0 = a; + b0 = b; - nni6->ni_type = ICMP6_NI_REPLY; - nni6->ni_code = ICMP6_NI_SUCESS; - m_freem(m); - return(n); + /* termination is mandatory */ + if (alen < 2 || blen < 2) + return 0; + if (a0[alen - 1] != '\0' || b0[blen - 1] != '\0') + return 0; + alen--; + blen--; + + while (a - a0 < alen && b - b0 < blen) { + if (a - a0 + 1 > alen || b - b0 + 1 > blen) + return 0; + + if ((signed char)a[0] < 0 || (signed char)b[0] < 0) + return 0; + /* we don't support compression yet */ + if (a[0] >= 64 || b[0] >= 64) + return 0; + + /* truncated case */ + if (a[0] == 0 && a - a0 == alen - 1) + return 1; + if (b[0] == 0 && b - b0 == blen - 1) + return 1; + if (a[0] == 0 || b[0] == 0) + return 0; + + if (a[0] != b[0]) + return 0; + l = a[0]; + if (a - a0 + 1 + l > alen || b - b0 + 1 + l > blen) + return 0; + if (bcmp(a + 1, b + 1, l) != 0) + return 0; + + a += 1 + l; + b += 1 + l; + } - bad: - m_freem(m); - if (n) - m_freem(n); - return(NULL); + if (a - a0 == alen && b - b0 == blen) + return 1; + else + return 0; } -#undef hostnamelen /* * calculate the number of addresses to be returned in the node info reply. */ static int -ni6_addrs(ni6, m, ifpp) +ni6_addrs(ni6, m, ifpp, subj) struct icmp6_nodeinfo *ni6; struct mbuf *m; struct ifnet **ifpp; + char *subj; { - register struct ifnet *ifp; - register struct in6_ifaddr *ifa6; - register struct ifaddr *ifa; - struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); + struct ifnet *ifp; + struct in6_ifaddr *ifa6; + struct ifaddr *ifa; + struct sockaddr_in6 *subj_ip6 = NULL; /* XXX pedant */ int addrs = 0, addrsofif, iffound = 0; + int niflags = ni6->ni_flags; + + if ((niflags & NI_NODEADDR_FLAG_ALL) == 0) { + switch (ni6->ni_code) { + case ICMP6_NI_SUBJ_IPV6: + if (subj == NULL) /* must be impossible... */ + return(0); + subj_ip6 = (struct sockaddr_in6 *)subj; + break; + default: + /* + * XXX: we only support IPv6 subject address for + * this Qtype. + */ + return(0); + } + } -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (ifp = ifnet; ifp; ifp = ifp->if_next) -#else for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) -#endif { addrsofif = 0; -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) -#else - for (ifa = ifp->if_addrlist.tqh_first; ifa; - ifa = ifa->ifa_list.tqe_next) -#endif + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; ifa6 = (struct in6_ifaddr *)ifa; - if (!(ni6->ni_flags & NI_NODEADDR_FLAG_ALL) && - IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, + if ((niflags & NI_NODEADDR_FLAG_ALL) == 0 && + IN6_ARE_ADDR_EQUAL(&subj_ip6->sin6_addr, &ifa6->ia_addr.sin6_addr)) iffound = 1; @@ -1241,36 +1688,41 @@ ni6_addrs(ni6, m, ifpp) * Node Information proxy, since they represent * addresses of IPv4-only nodes, which perforce do * not implement this protocol. - * [icmp-name-lookups-05] + * [icmp-name-lookups-07, Section 5.4] * So we don't support NI_NODEADDR_FLAG_COMPAT in * this function at this moment. */ - if (ifa6->ia6_flags & IN6_IFF_ANYCAST) - continue; /* we need only unicast addresses */ - - if ((ni6->ni_flags & (NI_NODEADDR_FLAG_LINKLOCAL | - NI_NODEADDR_FLAG_SITELOCAL | - NI_NODEADDR_FLAG_GLOBAL)) == 0) - continue; - /* What do we have to do about ::1? */ - switch(in6_addrscope(&ifa6->ia_addr.sin6_addr)) { - case IPV6_ADDR_SCOPE_LINKLOCAL: - if (ni6->ni_flags & NI_NODEADDR_FLAG_LINKLOCAL) - addrsofif++; + switch (in6_addrscope(&ifa6->ia_addr.sin6_addr)) { + case IPV6_ADDR_SCOPE_LINKLOCAL: + if ((niflags & NI_NODEADDR_FLAG_LINKLOCAL) == 0) + continue; + break; + case IPV6_ADDR_SCOPE_SITELOCAL: + if ((niflags & NI_NODEADDR_FLAG_SITELOCAL) == 0) + continue; break; - case IPV6_ADDR_SCOPE_SITELOCAL: - if (ni6->ni_flags & NI_NODEADDR_FLAG_SITELOCAL) - addrsofif++; + case IPV6_ADDR_SCOPE_GLOBAL: + if ((niflags & NI_NODEADDR_FLAG_GLOBAL) == 0) + continue; break; - case IPV6_ADDR_SCOPE_GLOBAL: - if (ni6->ni_flags & NI_NODEADDR_FLAG_GLOBAL) - addrsofif++; - break; - default: - continue; + default: + continue; + } + + /* + * check if anycast is okay. + * XXX: just experimental. not in the spec. + */ + if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0 && + (niflags & NI_NODEADDR_FLAG_ANYCAST) == 0) + continue; /* we need only unicast addresses */ + if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0 && + (icmp6_nodeinfo & 4) == 0) { + continue; } + addrsofif++; /* count the address */ } if (iffound) { *ifpp = ifp; @@ -1289,98 +1741,142 @@ ni6_store_addrs(ni6, nni6, ifp0, resid) struct ifnet *ifp0; int resid; { -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - register struct ifnet *ifp = ifp0 ? ifp0 : ifnet; -#else - register struct ifnet *ifp = ifp0 ? ifp0 : TAILQ_FIRST(&ifnet); -#endif - register struct in6_ifaddr *ifa6; - register struct ifaddr *ifa; - int docopy, copied = 0; + struct ifnet *ifp = ifp0 ? ifp0 : TAILQ_FIRST(&ifnet); + struct in6_ifaddr *ifa6; + struct ifaddr *ifa; + struct ifnet *ifp_dep = NULL; + int copied = 0, allow_deprecated = 0; u_char *cp = (u_char *)(nni6 + 1); + int niflags = ni6->ni_flags; + u_int32_t ltime; - if (ifp0 == NULL && !(ni6->ni_flags & NI_NODEADDR_FLAG_ALL)) + if (ifp0 == NULL && !(niflags & NI_NODEADDR_FLAG_ALL)) return(0); /* needless to copy */ -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (; ifp; ifp = ifp->if_next) -#else + again: + for (; ifp; ifp = TAILQ_NEXT(ifp, if_list)) -#endif { -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) -#else for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) -#endif { - docopy = 0; - if (ifa->ifa_addr->sa_family != AF_INET6) continue; ifa6 = (struct in6_ifaddr *)ifa; - if (ifa6->ia6_flags & IN6_IFF_ANYCAST) { - /* just experimental. not in the spec. */ - if (ni6->ni_flags & NI_NODEADDR_FLAG_ANYCAST) - docopy = 1; - else - continue; - } - else { /* unicast address */ - if (ni6->ni_flags & NI_NODEADDR_FLAG_ANYCAST) - continue; - else - docopy = 1; + if ((ifa6->ia6_flags & IN6_IFF_DEPRECATED) != 0 && + allow_deprecated == 0) { + /* + * prefererred address should be put before + * deprecated addresses. + */ + + /* record the interface for later search */ + if (ifp_dep == NULL) + ifp_dep = ifp; + + continue; } + else if ((ifa6->ia6_flags & IN6_IFF_DEPRECATED) == 0 && + allow_deprecated != 0) + continue; /* we now collect deprecated addrs */ /* What do we have to do about ::1? */ - switch(in6_addrscope(&ifa6->ia_addr.sin6_addr)) { - case IPV6_ADDR_SCOPE_LINKLOCAL: - if (ni6->ni_flags & NI_NODEADDR_FLAG_LINKLOCAL) - docopy = 1; + switch (in6_addrscope(&ifa6->ia_addr.sin6_addr)) { + case IPV6_ADDR_SCOPE_LINKLOCAL: + if ((niflags & NI_NODEADDR_FLAG_LINKLOCAL) == 0) + continue; + break; + case IPV6_ADDR_SCOPE_SITELOCAL: + if ((niflags & NI_NODEADDR_FLAG_SITELOCAL) == 0) + continue; break; - case IPV6_ADDR_SCOPE_SITELOCAL: - if (ni6->ni_flags & NI_NODEADDR_FLAG_SITELOCAL) - docopy = 1; + case IPV6_ADDR_SCOPE_GLOBAL: + if ((niflags & NI_NODEADDR_FLAG_GLOBAL) == 0) + continue; break; - case IPV6_ADDR_SCOPE_GLOBAL: - if (ni6->ni_flags & NI_NODEADDR_FLAG_GLOBAL) - docopy = 1; - break; - default: - continue; + default: + continue; } - if (docopy) { - if (resid < sizeof(struct in6_addr)) { - /* - * We give up much more copy. - * Set the truncate flag and return. - */ - nni6->ni_flags |= - NI_NODEADDR_FLAG_TRUNCATE; - return(copied); - } - bcopy(&ifa6->ia_addr.sin6_addr, cp, - sizeof(struct in6_addr)); - /* XXX: KAME link-local hack; remove ifindex */ - if (IN6_IS_ADDR_LINKLOCAL(&ifa6->ia_addr.sin6_addr)) - ((struct in6_addr *)cp)->s6_addr16[1] = 0; - cp += sizeof(struct in6_addr); - resid -= sizeof(struct in6_addr); - copied += sizeof(struct in6_addr); + /* + * check if anycast is okay. + * XXX: just experimental. not in the spec. + */ + if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0 && + (niflags & NI_NODEADDR_FLAG_ANYCAST) == 0) + continue; + if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0 && + (icmp6_nodeinfo & 4) == 0) { + continue; + } + + /* now we can copy the address */ + if (resid < sizeof(struct in6_addr) + + sizeof(u_int32_t)) { + /* + * We give up much more copy. + * Set the truncate flag and return. + */ + nni6->ni_flags |= + NI_NODEADDR_FLAG_TRUNCATE; + return(copied); + } + + /* + * Set the TTL of the address. + * The TTL value should be one of the following + * according to the specification: + * + * 1. The remaining lifetime of a DHCP lease on the + * address, or + * 2. The remaining Valid Lifetime of a prefix from + * which the address was derived through Stateless + * Autoconfiguration. + * + * Note that we currently do not support stateful + * address configuration by DHCPv6, so the former + * case can't happen. + */ + if (ifa6->ia6_lifetime.ia6t_expire == 0) + ltime = ND6_INFINITE_LIFETIME; + else { + if (ifa6->ia6_lifetime.ia6t_expire > + time_second) + ltime = htonl(ifa6->ia6_lifetime.ia6t_expire - time_second); + else + ltime = 0; } + + bcopy(<ime, cp, sizeof(u_int32_t)); + cp += sizeof(u_int32_t); + + /* copy the address itself */ + bcopy(&ifa6->ia_addr.sin6_addr, cp, + sizeof(struct in6_addr)); + /* XXX: KAME link-local hack; remove ifindex */ + if (IN6_IS_ADDR_LINKLOCAL(&ifa6->ia_addr.sin6_addr)) + ((struct in6_addr *)cp)->s6_addr16[1] = 0; + cp += sizeof(struct in6_addr); + + resid -= (sizeof(struct in6_addr) + sizeof(u_int32_t)); + copied += (sizeof(struct in6_addr) + + sizeof(u_int32_t)); } if (ifp0) /* we need search only on the specified IF */ break; } + if (allow_deprecated == 0 && ifp_dep != NULL) { + ifp = ifp_dep; + allow_deprecated = 1; + + goto again; + } + return(copied); } -#ifndef HAVE_NRL_INPCB /* * XXX almost dup'ed code with rip6_input. */ @@ -1390,12 +1886,12 @@ icmp6_rip6_input(mp, off) int off; { struct mbuf *m = *mp; - register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); - register struct in6pcb *in6p; + struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); + struct in6pcb *in6p; struct in6pcb *last = NULL; struct sockaddr_in6 rip6src; struct icmp6_hdr *icmp6; - struct ip6_recvpktopts opts; + struct mbuf *opts = NULL; #ifndef PULLDOWN_TEST /* this is assumed to be safe. */ @@ -1408,30 +1904,18 @@ icmp6_rip6_input(mp, off) } #endif - bzero(&opts, sizeof(opts)); bzero(&rip6src, sizeof(rip6src)); rip6src.sin6_len = sizeof(struct sockaddr_in6); rip6src.sin6_family = AF_INET6; - rip6src.sin6_addr = ip6->ip6_src; - if (IN6_IS_SCOPE_LINKLOCAL(&rip6src.sin6_addr)) - rip6src.sin6_addr.s6_addr16[1] = 0; - if (m->m_pkthdr.rcvif) { - if (IN6_IS_SCOPE_LINKLOCAL(&rip6src.sin6_addr)) - rip6src.sin6_scope_id = m->m_pkthdr.rcvif->if_index; - else - rip6src.sin6_scope_id = 0; - } else - rip6src.sin6_scope_id = 0; + /* KAME hack: recover scopeid */ + (void)in6_recoverscope(&rip6src, &ip6->ip6_src, m->m_pkthdr.rcvif); -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) LIST_FOREACH(in6p, &ripcb, inp_list) -#else - for (in6p = rawin6pcb.in6p_next; - in6p != &rawin6pcb; in6p = in6p->in6p_next) -#endif { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) - if ((in6p->inp_vflag & INP_IPV6) == NULL) + if ((in6p->inp_vflag & INP_IPV6) == 0) + continue; +#if HAVE_NRL_INPCB + if (!(in6p->in6p_flags & INP_IPV6)) continue; #endif if (in6p->in6p_ip6_nxt != IPPROTO_ICMPV6) @@ -1450,36 +1934,34 @@ icmp6_rip6_input(mp, off) struct mbuf *n; if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { if (last->in6p_flags & IN6P_CONTROLOPTS) - ip6_savecontrol(last, ip6, n, &opts, - NULL); + ip6_savecontrol(last, &opts, ip6, n); /* strip intermediate headers */ m_adj(n, off); if (sbappendaddr(&last->in6p_socket->so_rcv, (struct sockaddr *)&rip6src, - n, opts.head) == 0) { + n, opts) == 0) { /* should notify about lost packet */ m_freem(n); - if (opts.head) { - m_freem(opts.head); + if (opts) { + m_freem(opts); } } else sorwakeup(last->in6p_socket); - bzero(&opts, sizeof(opts)); + opts = NULL; } } last = in6p; } if (last) { if (last->in6p_flags & IN6P_CONTROLOPTS) - ip6_savecontrol(last, ip6, m, &opts, NULL); + ip6_savecontrol(last, &opts, ip6, m); /* strip intermediate headers */ m_adj(m, off); if (sbappendaddr(&last->in6p_socket->so_rcv, - (struct sockaddr *)&rip6src, - m, opts.head) == 0) { + (struct sockaddr *)&rip6src, m, opts) == 0) { m_freem(m); - if (opts.head) - m_freem(opts.head); + if (opts) + m_freem(opts); } else sorwakeup(last->in6p_socket); } else { @@ -1488,7 +1970,6 @@ icmp6_rip6_input(mp, off) } return IPPROTO_DONE; } -#endif /*OpenBSD*/ /* * Reflect the ip6 packet back to the source. @@ -1506,6 +1987,7 @@ icmp6_reflect(m, off) int plen; int type, code; struct ifnet *outif = NULL; + struct sockaddr_in6 sa6_src, sa6_dst; #ifdef COMPAT_RFC1885 int mtu = IPV6_MMTU; struct sockaddr_in6 *sin6 = &icmp6_reflect_rt.ro_dst; @@ -1513,9 +1995,10 @@ icmp6_reflect(m, off) /* too short to reflect */ if (off < sizeof(struct ip6_hdr)) { - printf("sanity fail: off=%lx, sizeof(ip6)=%lx in %s:%d\n", - (u_long)off, (u_long)sizeof(struct ip6_hdr), - __FILE__, __LINE__); + nd6log((LOG_DEBUG, + "sanity fail: off=%lx, sizeof(ip6)=%lx in %s:%d\n", + (u_long)off, (u_long)sizeof(struct ip6_hdr), + __FILE__, __LINE__)); goto bad; } @@ -1523,6 +2006,10 @@ icmp6_reflect(m, off) * If there are extra headers between IPv6 and ICMPv6, strip * off that header first. */ +#if DIAGNOSTIC + if (sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) > MHLEN) + panic("assumption failed in icmp6_reflect"); +#endif if (off > sizeof(struct ip6_hdr)) { size_t l; struct ip6_hdr nip6; @@ -1558,12 +2045,24 @@ icmp6_reflect(m, off) */ ip6->ip6_dst = ip6->ip6_src; - /* XXX hack for link-local addresses */ - if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst)) - ip6->ip6_dst.s6_addr16[1] = - htons(m->m_pkthdr.rcvif->if_index); - if (IN6_IS_ADDR_LINKLOCAL(&t)) - t.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); + /* + * XXX: make sure to embed scope zone information, using + * already embedded IDs or the received interface (if any). + * Note that rcvif may be NULL. + * TODO: scoped routing case (XXX). + */ + bzero(&sa6_src, sizeof(sa6_src)); + sa6_src.sin6_family = AF_INET6; + sa6_src.sin6_len = sizeof(sa6_src); + sa6_src.sin6_addr = ip6->ip6_dst; + in6_recoverscope(&sa6_src, &ip6->ip6_dst, m->m_pkthdr.rcvif); + in6_embedscope(&ip6->ip6_dst, &sa6_src, NULL, NULL); + bzero(&sa6_dst, sizeof(sa6_dst)); + sa6_dst.sin6_family = AF_INET6; + sa6_dst.sin6_len = sizeof(sa6_dst); + sa6_dst.sin6_addr = t; + in6_recoverscope(&sa6_dst, &t, m->m_pkthdr.rcvif); + in6_embedscope(&t, &sa6_dst, NULL, NULL); #ifdef COMPAT_RFC1885 /* @@ -1575,12 +2074,7 @@ icmp6_reflect(m, off) if (icmp6_reflect_rt.ro_rt == 0 || ! (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &ip6->ip6_dst))) { if (icmp6_reflect_rt.ro_rt) { -#if defined(__FreeBSD__) || defined(__APPLE__) - RTFREE(icmp6_reflect_rt.ro_rt); -#endif -#ifdef __bsdi__ rtfree(icmp6_reflect_rt.ro_rt); -#endif icmp6_reflect_rt.ro_rt = 0; } bzero(sin6, sizeof(*sin6)); @@ -1588,12 +2082,8 @@ icmp6_reflect(m, off) sin6->sin6_len = sizeof(struct sockaddr_in6); sin6->sin6_addr = ip6->ip6_dst; -#if defined(__FreeBSD__) || defined(__APPLE__) rtalloc_ign((struct route *)&icmp6_reflect_rt.ro_rt, RTF_PRCLONING); -#else - rtalloc((struct route *)&icmp6_reflect_rt.ro_rt); -#endif } if (icmp6_reflect_rt.ro_rt == 0) @@ -1611,7 +2101,7 @@ icmp6_reflect(m, off) /* * If the incoming packet was addressed directly to us(i.e. unicast), * use dst as the src for the reply. - * The IN6_IFF_NOTREADY case would be VERY rare, but is possible when + * The IN6_IFF_NOTREADY case would be VERY rare, but is possible * (for example) when we encounter an error while forwarding procedure * destined to a duplicated address of ours. */ @@ -1629,19 +2119,27 @@ icmp6_reflect(m, off) src = &t; } - if (src == 0) + if (src == 0) { + int e; + struct route_in6 ro; + /* * This case matches to multicasts, our anycast, or unicasts - * that we do not own. Select a source address which has the - * same scope. - * XXX: for (non link-local) multicast addresses, this might - * not be a good choice. + * that we do not own. Select a source address based on the + * source address of the erroneous packet. */ - if ((ia = in6_ifawithscope(m->m_pkthdr.rcvif, &t)) != 0) - src = &IA6_SIN6(ia)->sin6_addr; - - if (src == 0) - goto bad; + bzero(&ro, sizeof(ro)); + src = in6_selectsrc(&sa6_src, NULL, NULL, &ro, NULL, &e); + if (ro.ro_rt) + rtfree(ro.ro_rt); /* XXX: we could use this */ + if (src == NULL) { + nd6log((LOG_DEBUG, + "icmp6_reflect: source can't be determined: " + "dst=%s, error=%d\n", + ip6_sprintf(&sa6_src.sin6_addr), e)); + goto bad; + } + } ip6->ip6_src = *src; @@ -1652,20 +2150,22 @@ icmp6_reflect(m, off) if (m->m_pkthdr.rcvif) { /* XXX: This may not be the outgoing interface */ ip6->ip6_hlim = nd_ifinfo[m->m_pkthdr.rcvif->if_index].chlim; - } + } else + ip6->ip6_hlim = ip6_defhlim; icmp6->icmp6_cksum = 0; icmp6->icmp6_cksum = in6_cksum(m, IPPROTO_ICMPV6, sizeof(struct ip6_hdr), plen); /* - * xxx option handling + * XXX option handling */ m->m_flags &= ~(M_BCAST|M_MCAST); #if IPSEC /* Don't lookup socket */ - ipsec_setsocket(m, NULL); + if (ipsec_bypass == 0) + (void)ipsec_setsocket(m, NULL); #endif /*IPSEC*/ #ifdef COMPAT_RFC1885 @@ -1686,6 +2186,7 @@ icmp6_reflect(m, off) void icmp6_fasttimo() { + mld6_fasttimeo(); } @@ -1696,19 +2197,14 @@ icmp6_redirect_diag(src6, dst6, tgt6) struct in6_addr *tgt6; { static char buf[1024]; -#if !defined(__OpenBSD__) && !defined(__bsdi__) snprintf(buf, sizeof(buf), "(src=%s dst=%s tgt=%s)", ip6_sprintf(src6), ip6_sprintf(dst6), ip6_sprintf(tgt6)); -#else - sprintf(buf, "(src=%s dst=%s tgt=%s)", - ip6_sprintf(src6), ip6_sprintf(dst6), ip6_sprintf(tgt6)); -#endif return buf; } void icmp6_redirect_input(m, off) - register struct mbuf *m; + struct mbuf *m; int off; { struct ifnet *ifp = m->m_pkthdr.rcvif; @@ -1756,17 +2252,17 @@ icmp6_redirect_input(m, off) /* validation */ if (!IN6_IS_ADDR_LINKLOCAL(&src6)) { - log(LOG_ERR, + nd6log((LOG_ERR, "ICMP6 redirect sent from %s rejected; " - "must be from linklocal\n", ip6_sprintf(&src6)); - goto freeit; + "must be from linklocal\n", ip6_sprintf(&src6))); + goto bad; } if (ip6->ip6_hlim != 255) { - log(LOG_ERR, + nd6log((LOG_ERR, "ICMP6 redirect sent from %s rejected; " "hlim=%d (must be 255)\n", - ip6_sprintf(&src6), ip6->ip6_hlim); - goto freeit; + ip6_sprintf(&src6), ip6->ip6_hlim)); + goto bad; } { /* ip6->ip6_src must be equal to gw for icmp6->icmp6_reddst */ @@ -1777,39 +2273,45 @@ icmp6_redirect_input(m, off) sin6.sin6_family = AF_INET6; sin6.sin6_len = sizeof(struct sockaddr_in6); bcopy(&reddst6, &sin6.sin6_addr, sizeof(reddst6)); - rt = rtalloc1((struct sockaddr *)&sin6, 0 -#if defined(__FreeBSD__) || defined (__APPLE__) - , 0UL -#endif - ); + rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL); if (rt) { + if (rt->rt_gateway == NULL || + rt->rt_gateway->sa_family != AF_INET6) { + nd6log((LOG_ERR, + "ICMP6 redirect rejected; no route " + "with inet6 gateway found for redirect dst: %s\n", + icmp6_redirect_diag(&src6, &reddst6, &redtgt6))); + rtfree(rt); + goto bad; + } + gw6 = &(((struct sockaddr_in6 *)rt->rt_gateway)->sin6_addr); if (bcmp(&src6, gw6, sizeof(struct in6_addr)) != 0) { - log(LOG_ERR, + nd6log((LOG_ERR, "ICMP6 redirect rejected; " "not equal to gw-for-src=%s (must be same): " "%s\n", ip6_sprintf(gw6), - icmp6_redirect_diag(&src6, &reddst6, &redtgt6)); - RTFREE(rt); - goto freeit; + icmp6_redirect_diag(&src6, &reddst6, &redtgt6))); + rtfree(rt); + goto bad; } } else { - log(LOG_ERR, + nd6log((LOG_ERR, "ICMP6 redirect rejected; " "no route found for redirect dst: %s\n", - icmp6_redirect_diag(&src6, &reddst6, &redtgt6)); - goto freeit; + icmp6_redirect_diag(&src6, &reddst6, &redtgt6))); + goto bad; } - RTFREE(rt); + rtfree(rt); rt = NULL; } if (IN6_IS_ADDR_MULTICAST(&reddst6)) { - log(LOG_ERR, + nd6log((LOG_ERR, "ICMP6 redirect rejected; " "redirect dst must be unicast: %s\n", - icmp6_redirect_diag(&src6, &reddst6, &redtgt6)); - goto freeit; + icmp6_redirect_diag(&src6, &reddst6, &redtgt6))); + goto bad; } is_router = is_onlink = 0; @@ -1818,20 +2320,21 @@ icmp6_redirect_input(m, off) if (bcmp(&redtgt6, &reddst6, sizeof(redtgt6)) == 0) is_onlink = 1; /* on-link destination case */ if (!is_router && !is_onlink) { - log(LOG_ERR, + nd6log((LOG_ERR, "ICMP6 redirect rejected; " "neither router case nor onlink case: %s\n", - icmp6_redirect_diag(&src6, &reddst6, &redtgt6)); - goto freeit; + icmp6_redirect_diag(&src6, &reddst6, &redtgt6))); + goto bad; } /* validation passed */ icmp6len -= sizeof(*nd_rd); nd6_option_init(nd_rd + 1, icmp6len, &ndopts); if (nd6_options(&ndopts) < 0) { - log(LOG_INFO, "icmp6_redirect_input: " + nd6log((LOG_INFO, "icmp6_redirect_input: " "invalid ND option, rejected: %s\n", - icmp6_redirect_diag(&src6, &reddst6, &redtgt6)); + icmp6_redirect_diag(&src6, &reddst6, &redtgt6))); + /* nd6_options have incremented stats */ goto freeit; } @@ -1846,11 +2349,12 @@ icmp6_redirect_input(m, off) } if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { - log(LOG_INFO, + nd6log((LOG_INFO, "icmp6_redirect_input: lladdrlen mismatch for %s " "(if %d, icmp6 packet %d): %s\n", ip6_sprintf(&redtgt6), ifp->if_addrlen, lladdrlen - 2, - icmp6_redirect_diag(&src6, &reddst6, &redtgt6)); + icmp6_redirect_diag(&src6, &reddst6, &redtgt6))); + goto bad; } /* RFC 2461 8.3 */ @@ -1862,9 +2366,6 @@ icmp6_redirect_input(m, off) struct sockaddr_in6 sdst; struct sockaddr_in6 sgw; struct sockaddr_in6 ssrc; -#ifdef __bsdi__ - extern int icmp_redirtimeout; /*XXX*/ -#endif bzero(&sdst, sizeof(sdst)); bzero(&sgw, sizeof(sgw)); @@ -1878,41 +2379,17 @@ icmp6_redirect_input(m, off) rtredirect((struct sockaddr *)&sdst, (struct sockaddr *)&sgw, (struct sockaddr *)NULL, RTF_GATEWAY | RTF_HOST, (struct sockaddr *)&ssrc, -#ifdef __bsdi__ - icmp_redirtimeout -#else - (struct rtentry **)NULL -#endif /*__FreeBSD__, __NetBSD__, __bsdi__*/ - ); + (struct rtentry **)NULL); } /* finally update cached route in each socket via pfctlinput */ { struct sockaddr_in6 sdst; -#if 1 -#else - struct ip6protosw *pr; -#endif bzero(&sdst, sizeof(sdst)); sdst.sin6_family = AF_INET6; sdst.sin6_len = sizeof(struct sockaddr_in6); bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr)); -#if 1 pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&sdst); -#else - /* - * do not use pfctlinput() here, we have different prototype for - * xx_ctlinput() in ip6proto. - */ - for (pr = (struct ip6protosw *)inet6domain.dom_protosw; - pr < (struct ip6protosw *)inet6domain.dom_protoswNPROTOSW; - pr++) { - if (pr->pr_ctlinput) { - (*pr->pr_ctlinput)(PRC_REDIRECT_HOST, - (struct sockaddr *)&sdst, NULL, NULL, 0); - } - } -#endif #if IPSEC key_sa_routechange((struct sockaddr *)&sdst); #endif @@ -1920,6 +2397,11 @@ icmp6_redirect_input(m, off) freeit: m_freem(m); + return; + + bad: + icmp6stat.icp6s_badredirect++; + m_freem(m); } void @@ -1937,6 +2419,9 @@ icmp6_redirect_output(m0, rt) size_t maxlen; u_char *p; struct ifnet *outif = NULL; + struct sockaddr_in6 src_sa; + + icmp6_errcount(&icmp6stat.icp6s_outerrhist, ND_REDIRECT, 0); /* if we are not router, we don't send icmp6 redirect */ if (!ip6_forwarding || ip6_accept_rtadv) @@ -1953,7 +2438,13 @@ icmp6_redirect_output(m0, rt) * [RFC 2461, sec 8.2] */ sip6 = mtod(m0, struct ip6_hdr *); - if (nd6_is_addr_neighbor(&sip6->ip6_src, ifp) == 0) + bzero(&src_sa, sizeof(src_sa)); + src_sa.sin6_family = AF_INET6; + src_sa.sin6_len = sizeof(src_sa); + src_sa.sin6_addr = sip6->ip6_src; + /* we don't currently use sin6_scope_id, but eventually use it */ + src_sa.sin6_scope_id = in6_addr2scopeid(ifp, &sip6->ip6_src); + if (nd6_is_addr_neighbor(&src_sa, ifp) == 0) goto fail; if (IN6_IS_ADDR_MULTICAST(&sip6->ip6_dst)) goto fail; /* what should we do here? */ @@ -1975,7 +2466,9 @@ icmp6_redirect_output(m0, rt) MCLGET(m, M_DONTWAIT); if (!m) goto fail; - maxlen = (m->m_flags & M_EXT) ? MCLBYTES : MHLEN; + m->m_pkthdr.rcvif = NULL; + m->m_len = 0; + maxlen = M_TRAILINGSPACE(m); maxlen = min(IPV6_MMTU, maxlen); /* just for safety */ if (maxlen < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + @@ -2078,7 +2571,7 @@ nolladdropt:; m->m_pkthdr.len = m->m_len = p - (u_char *)ip6; /* just to be safe */ -#if M_DECRYPTED /*not openbsd*/ +#ifdef M_DECRYPTED /*not openbsd*/ if (m0->m_flags & M_DECRYPTED) goto noredhdropt; #endif @@ -2180,7 +2673,8 @@ noredhdropt:; /* send the packet to outside... */ #if IPSEC /* Don't lookup socket */ - ipsec_setsocket(m, NULL); + if (ipsec_bypass == 0) + (void)ipsec_setsocket(m, NULL); #endif /*IPSEC*/ ip6_output(m, NULL, NULL, 0, NULL, &outif); if (outif) { @@ -2198,30 +2692,22 @@ fail: m_freem(m0); } -#ifndef HAVE_NRL_INPCB +#if HAVE_NRL_INPCB +#define sotoin6pcb sotoinpcb +#define in6pcb inpcb +#define in6p_icmp6filt inp_icmp6filt +#endif /* * ICMPv6 socket option processing. - * - * NOTE: for OSes that use NRL inpcb (bsdi4/openbsd), do not forget to modify - * sys/netinet6/raw_ipv6.c:rip6_ctloutput(). */ int -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) icmp6_ctloutput(so, sopt) struct socket *so; struct sockopt *sopt; -#else -icmp6_ctloutput(op, so, level, optname, mp) - int op; - struct socket *so; - int level, optname; - struct mbuf **mp; -#endif { int error = 0; int optlen; -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) - register struct inpcb *inp = sotoinpcb(so); + struct inpcb *inp = sotoinpcb(so); int level, op, optname; if (sopt) { @@ -2231,22 +2717,12 @@ icmp6_ctloutput(op, so, level, optname, mp) optlen = sopt->sopt_valsize; } else level = op = optname = optlen = 0; -#else - register struct in6pcb *in6p = sotoin6pcb(so); - register struct mbuf *m = *mp; - - optlen = m ? m->m_len : 0; -#endif if (level != IPPROTO_ICMPV6) { -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__APPLE__) - if (op == PRCO_SETOPT && m) - (void)m_free(m); -#endif return EINVAL; } - switch(op) { + switch (op) { case PRCO_SETOPT: switch (optname) { case ICMP6_FILTER: @@ -2257,23 +2733,12 @@ icmp6_ctloutput(op, so, level, optname, mp) error = EMSGSIZE; break; } -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) if (inp->in6p_icmp6filt == NULL) { error = EINVAL; break; } error = sooptcopyin(sopt, inp->in6p_icmp6filt, optlen, optlen); -#else - p = mtod(m, struct icmp6_filter *); - if (!p || !in6p->in6p_icmp6filt) { - error = EINVAL; - break; - } - bcopy(p, in6p->in6p_icmp6filt, - sizeof(struct icmp6_filter)); - error = 0; -#endif break; } @@ -2281,37 +2746,18 @@ icmp6_ctloutput(op, so, level, optname, mp) error = ENOPROTOOPT; break; } -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__APPLE__) - if (m) - (void)m_freem(m); -#endif break; case PRCO_GETOPT: switch (optname) { case ICMP6_FILTER: { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) if (inp->in6p_icmp6filt == NULL) { error = EINVAL; break; } error = sooptcopyout(sopt, inp->in6p_icmp6filt, sizeof(struct icmp6_filter)); -#else - struct icmp6_filter *p; - - if (!in6p->in6p_icmp6filt) { - error = EINVAL; - break; - } - *mp = m = m_get(M_WAIT, MT_SOOPTS); - m->m_len = sizeof(struct icmp6_filter); - p = mtod(m, struct icmp6_filter *); - bcopy(in6p->in6p_icmp6filt, p, - sizeof(struct icmp6_filter)); - error = 0; -#endif break; } @@ -2324,7 +2770,81 @@ icmp6_ctloutput(op, so, level, optname, mp) return(error); } -#endif /*NRL inpcb*/ +#if HAVE_NRL_INPCB +#undef sotoin6pcb +#undef in6pcb +#undef in6p_icmp6filt +#endif + +#ifndef HAVE_PPSRATECHECK +#ifndef timersub +#define timersub(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ + if ((vvp)->tv_usec < 0) { \ + (vvp)->tv_sec--; \ + (vvp)->tv_usec += 1000000; \ + } \ + } while (0) +#endif + +/* + * ppsratecheck(): packets (or events) per second limitation. + */ +static int +ppsratecheck(lasttime, curpps, maxpps) + struct timeval *lasttime; + int *curpps; + int maxpps; /* maximum pps allowed */ +{ + struct timeval tv, delta; + int s, rv; + + s = splclock(); + microtime(&tv); + splx(s); + + timersub(&tv, lasttime, &delta); + + /* + * check for 0,0 is so that the message will be seen at least once. + * if more than one second have passed since the last update of + * lasttime, reset the counter. + * + * we do increment *curpps even in *curpps < maxpps case, as some may + * try to use *curpps for stat purposes as well. + */ + if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) || + delta.tv_sec >= 1) { + *lasttime = tv; + *curpps = 0; + rv = 1; + } else if (maxpps < 0) + rv = 1; + else if (*curpps < maxpps) + rv = 1; + else + rv = 0; + +#if 1 /*DIAGNOSTIC?*/ + /* be careful about wrap-around */ + if (*curpps + 1 > *curpps) + *curpps = *curpps + 1; +#else + /* + * assume that there's not too many calls to this function. + * not sure if the assumption holds, as it depends on *caller's* + * behavior, not the behavior of this function. + * IMHO it is wrong to make assumption on the caller's behavior, + * so the above #if is #if 1, not #ifdef DIAGNOSTIC. + */ + *curpps = *curpps + 1; +#endif + + return (rv); +} +#endif /* * Perform rate limit check. @@ -2340,185 +2860,16 @@ icmp6_ratelimit(dst, type, code) const int type; /* not used at this moment */ const int code; /* not used at this moment */ { - struct timeval tp; - long sec_diff, usec_diff; + int ret; - /* If we are not doing rate limitation, it is always okay to send */ - if (!icmp6errratelim) - return 0; + ret = 0; /*okay to send*/ -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) - microtime(&tp); - tp.tv_sec = time_second; -#else - tp = time; -#endif - if (tp.tv_sec < icmp6_nextsend.tv_sec - || (tp.tv_sec == icmp6_nextsend.tv_sec - && tp.tv_usec < icmp6_nextsend.tv_usec)) { + /* PPS limit */ + if (!ppsratecheck(&icmp6errppslim_last, &icmp6errpps_count, + icmp6errppslim)) { /* The packet is subject to rate limit */ - return 1; - } - sec_diff = icmp6errratelim / 1000000; - usec_diff = icmp6errratelim % 1000000; - icmp6_nextsend.tv_sec = tp.tv_sec + sec_diff; - if ((tp.tv_usec = tp.tv_usec + usec_diff) >= 1000000) { - icmp6_nextsend.tv_sec++; - icmp6_nextsend.tv_usec -= 1000000; - } - - /* it is okay to send this */ - return 0; -} - -#if defined(__NetBSD__) || defined(__OpenBSD__) -static struct rtentry * -icmp6_mtudisc_clone(dst) - struct sockaddr *dst; -{ - struct rtentry *rt; - int error; - - rt = rtalloc1(dst, 1); - if (rt == 0) - return NULL; - - /* If we didn't get a host route, allocate one */ - if ((rt->rt_flags & RTF_HOST) == 0) { - struct rtentry *nrt; - - error = rtrequest((int) RTM_ADD, dst, - (struct sockaddr *) rt->rt_gateway, - (struct sockaddr *) 0, - RTF_GATEWAY | RTF_HOST | RTF_DYNAMIC, &nrt); - if (error) { - rtfree(rt); - rtfree(nrt); - return NULL; - } - nrt->rt_rmx = rt->rt_rmx; - rtfree(rt); - rt = nrt; - } - error = rt_timer_add(rt, icmp6_mtudisc_timeout, - icmp6_mtudisc_timeout_q); - if (error) { - rtfree(rt); - return NULL; - } - - return rt; /* caller need to call rtfree() */ -} - -static void -icmp6_mtudisc_timeout(rt, r) - struct rtentry *rt; - struct rttimer *r; -{ - if (rt == NULL) - panic("icmp6_mtudisc_timeout: bad route to timeout"); - if ((rt->rt_flags & (RTF_DYNAMIC | RTF_HOST)) == - (RTF_DYNAMIC | RTF_HOST)) { - rtrequest((int) RTM_DELETE, (struct sockaddr *)rt_key(rt), - rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0); - } else { - if ((rt->rt_rmx.rmx_locks & RTV_MTU) == 0) { - rt->rt_rmx.rmx_mtu = 0; - } - } -} -#endif /*__NetBSD__ || __OpenBSD__*/ - -#ifdef __bsdi__ -void -icmp6_mtuexpire(rt, rtt) - struct rtentry *rt; - struct rttimer *rtt; -{ - rt->rt_flags |= RTF_PROBEMTU; - Free(rtt); -} - -int *icmp6_sysvars[] = ICMPV6CTL_VARS; - -int -icmp6_sysctl(name, namelen, oldp, oldlenp, newp, newlen) - int *name; - u_int namelen; - void *oldp; - size_t *oldlenp; - void *newp; - size_t newlen; -{ - if (name[0] >= ICMPV6CTL_MAXID) - return (EOPNOTSUPP); - switch (name[0]) { -#if 0 - ICMPV6CTL_ND6_PRUNE: - ICMPV6CTL_ND6_DELAY: - ICMPV6CTL_ND6_UMAXTRIES: - ICMPV6CTL_ND6_MMAXTRIES: - ICMPV6CTL_ND6_USELOOPBACK: - /* need to check the value. */ -#endif - case ICMPV6CTL_STATS: - return sysctl_rdtrunc(oldp, oldlenp, newp, &icmp6stat, - sizeof(icmp6stat)); - - default: - return (sysctl_int_arr(icmp6_sysvars, name, namelen, - oldp, oldlenp, newp, newlen)); + ret++; } -} -#endif /*__bsdi__*/ - -#if defined(__NetBSD__) || defined(__OpenBSD__) -#include -#include -int -icmp6_sysctl(name, namelen, oldp, oldlenp, newp, newlen) - int *name; - u_int namelen; - void *oldp; - size_t *oldlenp; - void *newp; - size_t newlen; -{ - /* All sysctl names at this level are terminal. */ - if (namelen != 1) - return ENOTDIR; - - switch (name[0]) { - - case ICMPV6CTL_REDIRACCEPT: - return sysctl_int(oldp, oldlenp, newp, newlen, - &icmp6_rediraccept); - case ICMPV6CTL_REDIRTIMEOUT: - return sysctl_int(oldp, oldlenp, newp, newlen, - &icmp6_redirtimeout); - case ICMPV6CTL_STATS: - return sysctl_rdstruct(oldp, oldlenp, newp, - &icmp6stat, sizeof(icmp6stat)); - case ICMPV6CTL_ERRRATELIMIT: - return sysctl_int(oldp, oldlenp, newp, newlen, - &icmp6errratelim); - case ICMPV6CTL_ND6_PRUNE: - return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_prune); - case ICMPV6CTL_ND6_DELAY: - return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_delay); - case ICMPV6CTL_ND6_UMAXTRIES: - return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_umaxtries); - case ICMPV6CTL_ND6_MMAXTRIES: - return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_mmaxtries); - case ICMPV6CTL_ND6_USELOOPBACK: - return sysctl_int(oldp, oldlenp, newp, newlen, - &nd6_useloopback); - case ICMPV6CTL_NODEINFO: - return sysctl_int(oldp, oldlenp, newp, newlen, &icmp6_nodeinfo); - default: - return ENOPROTOOPT; - } - /* NOTREACHED */ + return ret; } -#endif /* __NetBSD__ */ diff --git a/bsd/netinet6/icmp6.h b/bsd/netinet6/icmp6.h index d99439e0b..765fba558 100644 --- a/bsd/netinet6/icmp6.h +++ b/bsd/netinet6/icmp6.h @@ -1,4 +1,4 @@ -/* $KAME$ */ +/* $FreeBSD: src/sys/netinet6/icmp6.h,v 1.5.2.1 2000/07/15 07:14:33 kris Exp $ */ +/* $KAME: icmp6.h,v 1.17 2000/06/11 17:23:40 jinmei Exp $ */ -/* just for backward compatibility, will be nuked shortly */ -#error "wrong include file - include netinet/icmp6.h instead" +#error "netinet6/icmp6.h is obsolete. use netinet/icmp6.h" diff --git a/bsd/netinet6/in6.c b/bsd/netinet6/in6.c index 1a16e4106..35ffb4a8f 100644 --- a/bsd/netinet6/in6.c +++ b/bsd/netinet6/in6.c @@ -1,4 +1,5 @@ -/* $KAME: in6.c,v 1.72 2000/03/30 03:45:26 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/in6.c,v 1.7.2.7 2001/08/06 20:26:22 ume Exp $ */ +/* $KAME: in6.c,v 1.187 2001/05/24 07:43:59 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -64,14 +65,9 @@ * @(#)in.c 8.2 (Berkeley) 11/15/93 */ -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#endif #include -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) #include -#endif #include #include #include @@ -81,22 +77,20 @@ #include #include #include +#include #include #include #include -#include "gif.h" -#if NGIF > 0 -#include -#endif #include #include #include -#if __NetBSD__ -#include -#else #include +#ifndef SCOPEDROUTING +#include +#include +#include #endif #include @@ -105,21 +99,17 @@ #include #include #include +#include +#ifndef SCOPEDROUTING +#include +#endif #include -#if MIP6 -#include -#include - -struct nd_prefix *(*mip6_get_home_prefix_hook) __P((void)); -#endif /* MIP6 */ - -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#ifndef __APPLE__ MALLOC_DEFINE(M_IPMADDR, "in6_multi", "internet multicast address"); #endif - -/* + /* * Definitions of some costant IP6 addresses. */ const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; @@ -137,56 +127,16 @@ const struct in6_addr in6mask64 = IN6MASK64; const struct in6_addr in6mask96 = IN6MASK96; const struct in6_addr in6mask128 = IN6MASK128; -#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) && !defined (__APPLE__) +const struct sockaddr_in6 sa6_any = {sizeof(sa6_any), AF_INET6, + 0, 0, IN6ADDR_ANY_INIT, 0}; + static int in6_lifaddr_ioctl __P((struct socket *, u_long, caddr_t, struct ifnet *, struct proc *)); -#else -static int in6_lifaddr_ioctl __P((struct socket *, u_long, caddr_t, - struct ifnet *)); -#endif +static int in6_ifinit __P((struct ifnet *, struct in6_ifaddr *, + struct sockaddr_in6 *, int)); +static void in6_unlink_ifa __P((struct in6_ifaddr *, struct ifnet *)); -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) struct in6_multihead in6_multihead; /* XXX BSS initialization */ -#else -/* - * This structure is used to keep track of in6_multi chains which belong to - * deleted interface addresses. - */ -static LIST_HEAD(, multi6_kludge) in6_mk; /* XXX BSS initialization */ - -struct multi6_kludge { - LIST_ENTRY(multi6_kludge) mk_entry; - struct ifnet *mk_ifp; - struct in6_multihead mk_head; -}; -#endif - -/* - * Check if the loopback entry will be automatically generated. - * if 0 returned, will not be automatically generated. - * if 1 returned, will be automatically generated. - */ -static int -in6_is_ifloop_auto(struct ifaddr *ifa) -{ -#define SIN6(s) ((struct sockaddr_in6 *)s) - /* - * If RTF_CLONING is unset, or (IFF_LOOPBACK | IFF_POINTOPOINT), - * or netmask is all0 or all1, then cloning will not happen, - * then we can't rely on its loopback entry generation. - */ - if ((ifa->ifa_flags & RTF_CLONING) == 0 || - (ifa->ifa_ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) || - (SIN6(ifa->ifa_netmask)->sin6_len == sizeof(struct sockaddr_in6) - && - IN6_ARE_ADDR_EQUAL(&SIN6(ifa->ifa_netmask)->sin6_addr, - &in6mask128)) || - ((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_len == 0) - return 0; - else - return 1; -#undef SIN6 -} /* * Subroutine for in6_ifaddloop() and in6_ifremloop(). @@ -195,63 +145,86 @@ in6_is_ifloop_auto(struct ifaddr *ifa) static void in6_ifloop_request(int cmd, struct ifaddr *ifa) { - struct sockaddr_in6 lo_sa; struct sockaddr_in6 all1_sa; struct rtentry *nrt = NULL; + int e; - bzero(&lo_sa, sizeof(lo_sa)); bzero(&all1_sa, sizeof(all1_sa)); - lo_sa.sin6_family = AF_INET6; - lo_sa.sin6_len = sizeof(struct sockaddr_in6); - all1_sa = lo_sa; - lo_sa.sin6_addr = in6addr_loopback; + all1_sa.sin6_family = AF_INET6; + all1_sa.sin6_len = sizeof(struct sockaddr_in6); all1_sa.sin6_addr = in6mask128; - - /* So we add or remove static loopback entry, here. */ - rtrequest(cmd, ifa->ifa_addr, - (struct sockaddr *)&lo_sa, - (struct sockaddr *)&all1_sa, - RTF_UP|RTF_HOST, &nrt); + + /* + * We specify the address itself as the gateway, and set the + * RTF_LLINFO flag, so that the corresponding host route would have + * the flag, and thus applications that assume traditional behavior + * would be happy. Note that we assume the caller of the function + * (probably implicitly) set nd6_rtrequest() to ifa->ifa_rtrequest, + * which changes the outgoing interface to the loopback interface. + */ + e = rtrequest(cmd, ifa->ifa_addr, ifa->ifa_addr, + (struct sockaddr *)&all1_sa, + RTF_UP|RTF_HOST|RTF_LLINFO, &nrt); + if (e != 0) { + log(LOG_ERR, "in6_ifloop_request: " + "%s operation failed for %s (errno=%d)\n", + cmd == RTM_ADD ? "ADD" : "DELETE", + ip6_sprintf(&((struct in6_ifaddr *)ifa)->ia_addr.sin6_addr), + e); + } /* * Make sure rt_ifa be equal to IFA, the second argument of the * function. - * We need this because when we refer rt_ifa->ia6_flags in ip6_input, - * we assume that the rt_ifa points to the address instead of the - * loopback address. + * We need this because when we refer to rt_ifa->ia6_flags in + * ip6_input, we assume that the rt_ifa points to the address instead + * of the loopback address. */ if (cmd == RTM_ADD && nrt && ifa != nrt->rt_ifa) { - IFAFREE(nrt->rt_ifa); - ifa->ifa_refcnt++; - nrt->rt_ifa = ifa; + rtsetifa(nrt, ifa); nrt->rt_dlt = ifa->ifa_dlt; } - if (nrt) - nrt->rt_refcnt--; + + /* + * Report the addition/removal of the address to the routing socket. + * XXX: since we called rtinit for a p2p interface with a destination, + * we end up reporting twice in such a case. Should we rather + * omit the second report? + */ + if (nrt) { + rt_newaddrmsg(cmd, ifa, e, nrt); + if (cmd == RTM_DELETE) { + if (nrt->rt_refcnt <= 0) { + /* XXX: we should free the entry ourselves. */ + rtref(nrt); + rtfree(nrt); + } + } else { + /* the cmd must be RTM_ADD here */ + rtunref(nrt); + } + } } /* - * Add ownaddr as loopback rtentry, if necessary(ex. on p2p link). - * Because, KAME needs loopback rtentry for ownaddr check in - * ip6_input(). + * Add ownaddr as loopback rtentry. We previously add the route only if + * necessary (ex. on a p2p link). However, since we now manage addresses + * separately from prefixes, we should always add the route. We can't + * rely on the cloning mechanism from the corresponding interface route + * any more. */ static void in6_ifaddloop(struct ifaddr *ifa) { - if (!in6_is_ifloop_auto(ifa)) { - struct rtentry *rt; - - /* If there is no loopback entry, allocate one. */ - rt = rtalloc1(ifa->ifa_addr, 0 -#if defined(__FreeBSD__) || defined (__APPLE__) - , 0 -#endif /* __FreeBSD__ */ - ); - if (rt == 0 || (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0) - in6_ifloop_request(RTM_ADD, ifa); - if (rt) - rt->rt_refcnt--; - } + struct rtentry *rt; + + /* If there is no loopback entry, allocate one. */ + rt = rtalloc1(ifa->ifa_addr, 0, 0); + if (rt == NULL || (rt->rt_flags & RTF_HOST) == 0 || + (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0) + in6_ifloop_request(RTM_ADD, ifa); + if (rt) + rt->rt_refcnt--; } /* @@ -261,21 +234,49 @@ in6_ifaddloop(struct ifaddr *ifa) static void in6_ifremloop(struct ifaddr *ifa) { - if (!in6_is_ifloop_auto(ifa)) { - struct in6_ifaddr *ia; - int ia_count = 0; - - /* If only one ifa for the loopback entry, delete it. */ - for (ia = in6_ifaddr; ia; ia = ia->ia_next) { - if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), - &ia->ia_addr.sin6_addr)) { - ia_count++; - if (ia_count > 1) - break; - } + struct in6_ifaddr *ia; + struct rtentry *rt; + int ia_count = 0; + + /* + * Some of BSD variants do not remove cloned routes + * from an interface direct route, when removing the direct route + * (see comments in net/net_osdep.h). Even for variants that do remove + * cloned routes, they could fail to remove the cloned routes when + * we handle multple addresses that share a common prefix. + * So, we should remove the route corresponding to the deleted address + * regardless of the result of in6_is_ifloop_auto(). + */ + + /* + * Delete the entry only if exact one ifa exists. More than one ifa + * can exist if we assign a same single address to multiple + * (probably p2p) interfaces. + * XXX: we should avoid such a configuration in IPv6... + */ + for (ia = in6_ifaddr; ia; ia = ia->ia_next) { + if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), &ia->ia_addr.sin6_addr)) { + ia_count++; + if (ia_count > 1) + break; } - if (ia_count == 1) + } + + if (ia_count == 1) { + /* + * Before deleting, check if a corresponding loopbacked host + * route surely exists. With this check, we can avoid to + * delete an interface direct route whose destination is same + * as the address being removed. This can happen when remofing + * a subnet-router anycast address on an interface attahced + * to a shared medium. + */ + rt = rtalloc1(ifa->ifa_addr, 0, 0); + if (rt != NULL && (rt->rt_flags & RTF_HOST) != 0 && + (rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) { + rt->rt_refcnt--; in6_ifloop_request(RTM_DELETE, ifa); + } } } @@ -291,11 +292,7 @@ in6_ifindex2scopeid(idx) return -1; ifp = ifindex2ifnet[idx]; -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) -#else - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) -#endif + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; @@ -308,22 +305,40 @@ in6_ifindex2scopeid(idx) } int -in6_mask2len(mask) +in6_mask2len(mask, lim0) struct in6_addr *mask; + u_char *lim0; { - int x, y; - - for (x = 0; x < sizeof(*mask); x++) { - if (mask->s6_addr8[x] != 0xff) + int x = 0, y; + u_char *lim = lim0, *p; + + if (lim0 == NULL || + lim0 - (u_char *)mask > sizeof(*mask)) /* ignore the scope_id part */ + lim = (u_char *)mask + sizeof(*mask); + for (p = (u_char *)mask; p < lim; x++, p++) { + if (*p != 0xff) break; } y = 0; - if (x < sizeof(*mask)) { + if (p < lim) { for (y = 0; y < 8; y++) { - if ((mask->s6_addr8[x] & (0x80 >> y)) == 0) + if ((*p & (0x80 >> y)) == 0) break; } } + + /* + * when the limit pointer is given, do a stricter check on the + * remaining bits. + */ + if (p < lim) { + if (y != 0 && (*p & (0x00ff >> y)) != 0) + return(-1); + for (p = p + 1; p < lim; p++) + if (*p != 0) + return(-1); + } + return x * 8 + y; } @@ -345,109 +360,32 @@ in6_len2mask(mask, len) #define ia62ifa(ia6) (&((ia6)->ia_ifa)) int -#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) && !defined (__APPLE__) in6_control(so, cmd, data, ifp, p) struct socket *so; u_long cmd; caddr_t data; struct ifnet *ifp; struct proc *p; -#else -in6_control(so, cmd, data, ifp) - struct socket *so; - u_long cmd; - caddr_t data; - struct ifnet *ifp; -#endif { struct in6_ifreq *ifr = (struct in6_ifreq *)data; -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - struct ifaddr *ifa; -#endif - struct in6_ifaddr *ia = NULL, *oia; + struct in6_ifaddr *ia = NULL; struct in6_aliasreq *ifra = (struct in6_aliasreq *)data; - struct sockaddr_in6 oldaddr; -#ifdef COMPAT_IN6IFIOCTL - struct sockaddr_in6 net; -#endif - int error = 0, hostIsNew, prefixIsNew; - int newifaddr; -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__APPLE__) - time_t time_second = (time_t)time.tv_sec; -#endif - int privileged; + int privileged, error = 0; u_long dl_tag; privileged = 0; -#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) && !defined (__APPLE__) - if (p && !suser(p->p_ucred, &p->p_acflag)) - privileged++; +#ifdef __APPLE__ + if (p == NULL || !suser(p->p_ucred, &p->p_acflag)) #else - if ((so->so_state & SS_PRIV) != 0) - privileged++; + if (p == NULL || !suser(p)) #endif + privileged++; - /* - * xxx should prevent processes for link-local addresses? - */ -#if NGIF > 0 - if (ifp && ifp->if_type == IFT_GIF) { - switch (cmd) { - case SIOCSIFPHYADDR_IN6: - if (!privileged) - return(EPERM); - /*fall through*/ - case SIOCGIFPSRCADDR_IN6: - case SIOCGIFPDSTADDR_IN6: - return gif_ioctl(ifp, cmd, data); - } - } -#endif switch (cmd) { case SIOCGETSGCNT_IN6: case SIOCGETMIFCNT_IN6: return (mrt6_ioctl(cmd, data)); } -#if MIP6 - /* These require root privileges */ - switch (cmd) { - case SIOCSDEBUG_MIP6: - case SIOCSBCFLUSH_MIP6: - case SIOCSDEFCONFIG_MIP6: - case SIOCSBRUPDATE_MIP6: - case SIOCSENABLEBR_MIP6: - case SIOCSATTACH_MIP6: - case SIOCSRELEASE_MIP6: - - case SIOCSHALISTFLUSH_MIP6: - case SIOCSHAPREF_MIP6: - case SIOCSFWDSLUNICAST_MIP6: - case SIOCSFWDSLMULTICAST_MIP6: - - case SIOCSFORADDRFLUSH_MIP6: - case SIOCSHADDRFLUSH_MIP6: - case SIOCSBULISTFLUSH_MIP6: - case SIOCACOADDR_MIP6: - case SIOCAHOMEADDR_MIP6: - case SIOCSBULIFETIME_MIP6: - case SIOCSHRLIFETIME_MIP6: - case SIOCDCOADDR_MIP6: - case SIOCSPROMMODE_MIP6: - case SIOCSBU2CN_MIP6: - case SIOCSREVTUNNEL_MIP6: - case SIOCSAUTOCONFIG_MIP6: - case SIOCSEAGERMD_MIP6: - if (!privileged) - return(EPERM); - /* Anyone can use these or the user is root */ - /* case SIOCXVERYSAFECOMMAND_MIP6: */ -#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) && !defined(__APPLE__) - return mip6_ioctl(so, cmd, data, ifp, p); -#else - return mip6_ioctl(so, cmd, data, ifp); -#endif - } -#endif /* MIP6 */ if (ifp == NULL) return(EOPNOTSUPP); @@ -461,6 +399,7 @@ in6_control(so, cmd, data, ifp) if (!privileged) return(EPERM); /*fall through*/ + case OSIOCGIFINFO_IN6: case SIOCGIFINFO_IN6: case SIOCGDRLST_IN6: case SIOCGPRLST_IN6: @@ -475,13 +414,25 @@ in6_control(so, cmd, data, ifp) case SIOCAIFPREFIX_IN6: case SIOCCIFPREFIX_IN6: case SIOCSGIFPREFIX_IN6: - if (!privileged) - return(EPERM); - /*fall through*/ case SIOCGIFPREFIX_IN6: - if (ip6_forwarding == 0) + log(LOG_NOTICE, + "prefix ioctls are now invalidated. " + "please use ifconfig.\n"); + return(EOPNOTSUPP); + } + + switch(cmd) { + case SIOCSSCOPE6: + if (!privileged) return(EPERM); - return(in6_prefix_ioctl(so, cmd, data, ifp)); + return(scope6_set(ifp, ifr->ifr_ifru.ifru_scope_id)); + break; + case SIOCGSCOPE6: + return(scope6_get(ifp, ifr->ifr_ifru.ifru_scope_id)); + break; + case SIOCGSCOPE6DEF: + return(scope6_get_default(ifr->ifr_ifru.ifru_scope_id)); + break; } switch (cmd) { @@ -491,13 +442,45 @@ in6_control(so, cmd, data, ifp) return(EPERM); /*fall through*/ case SIOCGLIFADDR: -#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) && !defined (__APPLE__) return in6_lifaddr_ioctl(so, cmd, data, ifp, p); -#else - return in6_lifaddr_ioctl(so, cmd, data, ifp); -#endif } + +#ifdef __APPLE__ + + switch (cmd) { + + case SIOCPROTOATTACH: + in6_if_up(ifp); + break; + case SIOCPROTODETACH: + in6_purgeif(ifp); + switch (ifp->if_type) { + case IFT_ETHER: + error = ether_detach_inet6(ifp); + break; + case IFT_GIF: + error = gif_detach_proto_family(ifp, PF_INET6); + break; + case IFT_STF: + error = stf_detach_inet6(ifp); + break; + case IFT_LOOP: /* do not detach loopback */ + break; + default: + printf("SIOCPROTODETACH: %s%d unknown type, can't detach\n", + ifp->if_name, ifp->if_unit); + return(ENOENT); + break; + } + if (error) { + printf("SIOCPROTODETACH: %s%d ether_detach_inet6 error=%x\n", + ifp->if_name, ifp->if_unit, error); + return(error); + } + break; + } +#endif /* * Find address for this interface, if it exists. */ @@ -507,12 +490,12 @@ in6_control(so, cmd, data, ifp) if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) { if (sa6->sin6_addr.s6_addr16[1] == 0) { - /* interface ID is not embedded by the user */ + /* link ID is not embedded by the user */ sa6->sin6_addr.s6_addr16[1] = htons(ifp->if_index); } else if (sa6->sin6_addr.s6_addr16[1] != htons(ifp->if_index)) { - return(EINVAL); /* ifid is contradict */ + return(EINVAL); /* link ID contradicts */ } if (sa6->sin6_scope_id) { if (sa6->sin6_scope_id != @@ -525,110 +508,39 @@ in6_control(so, cmd, data, ifp) } switch (cmd) { + case SIOCSIFADDR_IN6: + case SIOCSIFDSTADDR_IN6: + case SIOCSIFNETMASK_IN6: + /* + * Since IPv6 allows a node to assign multiple addresses + * on a single interface, SIOCSIFxxx ioctls are not suitable + * and should be unused. + */ + /* we decided to obsolete this command (20000704) */ + return(EINVAL); case SIOCDIFADDR_IN6: /* - * for IPv4, we look for existing in6_ifaddr here to allow + * for IPv4, we look for existing in_ifaddr here to allow * "ifconfig if0 delete" to remove first IPv4 address on the * interface. For IPv6, as the spec allow multiple interface * address from the day one, we consider "remove the first one" - * semantics to be not preferrable. + * semantics to be not preferable. */ if (ia == NULL) return(EADDRNOTAVAIL); /* FALLTHROUGH */ case SIOCAIFADDR_IN6: - case SIOCSIFADDR_IN6: -#if COMPAT_IN6IFIOCTL - case SIOCSIFDSTADDR_IN6: - case SIOCSIFNETMASK_IN6: /* - * Since IPv6 allows a node to assign multiple addresses - * on a single interface, SIOCSIFxxx ioctls are not suitable - * and should be unused. + * We always require users to specify a valid IPv6 address for + * the corresponding operation. */ -#endif - if (ifra->ifra_addr.sin6_family != AF_INET6) + if (ifra->ifra_addr.sin6_family != AF_INET6 || + ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6)) return(EAFNOSUPPORT); if (!privileged) return(EPERM); - if (ia == NULL) { - ia = (struct in6_ifaddr *) - _MALLOC(sizeof(*ia), M_IFADDR, M_WAITOK); - if (ia == NULL) - return (ENOBUFS); - bzero((caddr_t)ia, sizeof(*ia)); - /* Initialize the address and masks */ - ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; - ia->ia_addr.sin6_family = AF_INET6; - ia->ia_addr.sin6_len = sizeof(ia->ia_addr); - if (ifp->if_flags & IFF_POINTOPOINT) { - ia->ia_ifa.ifa_dstaddr - = (struct sockaddr *)&ia->ia_dstaddr; - ia->ia_dstaddr.sin6_family = AF_INET6; - ia->ia_dstaddr.sin6_len = sizeof(ia->ia_dstaddr); - } else { - ia->ia_ifa.ifa_dstaddr = NULL; - bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr)); - } - ia->ia_ifa.ifa_netmask - = (struct sockaddr *)&ia->ia_prefixmask; - - ia->ia_ifp = ifp; - - printf("in6_control: Attach dl_tag for if=%s%n\n", ifp->if_name, ifp->if_unit); - - if (strcmp(ifp->if_name, "en") == 0) - dl_tag = ether_attach_inet6(ifp); - - if (strcmp(ifp->if_name, "lo") == 0) - dl_tag = lo_attach_inet(ifp); -#if NGIF > 0 - if (strcmp(ifp->if_name, "gif") == 0) - dl_tag = gif_attach_inet(ifp); -#endif -/* End of temp code */ - ia->ia_ifa.ifa_dlt = dl_tag; - - - if ((oia = in6_ifaddr) != NULL) { - for ( ; oia->ia_next; oia = oia->ia_next) - continue; - oia->ia_next = ia; - } else - in6_ifaddr = ia; - ia->ia_ifa.ifa_refcnt++; - -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - if ((ifa = ifp->if_addrlist) != NULL) { - for ( ; ifa->ifa_next; ifa = ifa->ifa_next) - continue; - ifa->ifa_next = ia62ifa(ia); - } else - ifp->if_addrlist = ia62ifa(ia); -#else - TAILQ_INSERT_TAIL(&ifp->if_addrlist, &ia->ia_ifa, - ifa_list); -#endif - ia->ia_ifa.ifa_refcnt++; - newifaddr = 1; - } else - newifaddr = 0; - - if (cmd == SIOCAIFADDR_IN6) { - /* sanity for overflow - beware unsigned */ - struct in6_addrlifetime *lt; - lt = &ifra->ifra_lifetime; - if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME - && lt->ia6t_vltime + time_second < time_second) { - return EINVAL; - } - if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME - && lt->ia6t_pltime + time_second < time_second) { - return EINVAL; - } - } break; case SIOCGIFADDR_IN6: @@ -673,6 +585,10 @@ in6_control(so, cmd, data, ifp) case SIOCGIFDSTADDR_IN6: if ((ifp->if_flags & IFF_POINTOPOINT) == 0) return(EINVAL); + /* + * XXX: should we check if ifa_dstaddr is NULL and return + * an error? + */ ifr->ifr_dstaddr = ia->ia_dstaddr; break; @@ -708,47 +624,7 @@ in6_control(so, cmd, data, ifp) ifr->ifr_ifru.ifru_icmp6stat = *icmp6_ifstat[ifp->if_index]; break; -#if COMPAT_IN6IFIOCTL /* should be unused */ - case SIOCSIFDSTADDR_IN6: - if ((ifp->if_flags & IFF_POINTOPOINT) == 0) - return(EINVAL); - oldaddr = ia->ia_dstaddr; - ia->ia_dstaddr = ifr->ifr_dstaddr; - - /* link-local index check */ - if (IN6_IS_ADDR_LINKLOCAL(&ia->ia_dstaddr.sin6_addr)) { - if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] == 0) { - /* interface ID is not embedded by the user */ - ia->ia_dstaddr.sin6_addr.s6_addr16[1] - = htons(ifp->if_index); - } else if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] != - htons(ifp->if_index)) { - ia->ia_dstaddr = oldaddr; - return(EINVAL); /* ifid is contradict */ - } - } -#ifdef __APPLE__ - error = dlil_ioctl(0, ifp, SIOCSIFDSTADDR, (caddr_t)ia); - if (error == EOPNOTSUPP) - error = 0; - if (error) { - ia->ia_dstaddr = oldaddr; - return(error); - } -#else - if (ifp->if_ioctl && (error = (ifp->if_ioctl) - (ifp, SIOCSIFDSTADDR, (caddr_t)ia))) { -#endif - 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; -#endif case SIOCGIFALIFETIME_IN6: ifr->ifr_ifru.ifru_lifetime = ia->ia6_lifetime; break; @@ -768,221 +644,162 @@ in6_control(so, cmd, data, ifp) ia->ia6_lifetime.ia6t_preferred = 0; break; - case SIOCSIFADDR_IN6: - error = in6_ifinit(ifp, ia, &ifr->ifr_addr, 1); -#if 0 - /* - * the code chokes if we are to assign multiple addresses with - * the same address prefix (rtinit() will return EEXIST, which - * is not fatal actually). we will get memory leak if we - * don't do it. - * -> we may want to hide EEXIST from rtinit(). - */ - undo: - if (error && newifaddr) { -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - if ((ifa = ifp->if_addrlist) == ia62ifa(ia)) - ifp->if_addrlist = ifa->ifa_next; - else { - while (ifa->ifa_next && - (ifa->ifa_next != ia62ifa(ia))) - ifa = ifa->ifa_next; - if (ifa->ifa_next) - ifa->ifa_next = ia62ifa(ia)->ifa_next; - else { - printf("Couldn't unlink in6_ifaddr " - "from ifp\n"); - } - } -#else - TAILQ_REMOVE(&ifp->if_addrlist, &ia->ia_ifa, ifa_list); -#endif - IFAFREE(&ia->ia_ifa); - - oia = ia; - if (oia == (ia = in6_ifaddr)) - in6_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 in6_ifaddr " - "from list\n"); - } - } - IFAFREE(&ia->ia_ifa); - } -#endif - return error; - -#if COMPAT_IN6IFIOCTL /* XXX should be unused */ - case SIOCSIFNETMASK_IN6: - ia->ia_prefixmask = ifr->ifr_addr; - bzero(&net, sizeof(net)); - net.sin6_len = sizeof(struct sockaddr_in6); - net.sin6_family = AF_INET6; - net.sin6_port = htons(0); - net.sin6_flowinfo = htonl(0); - net.sin6_addr.s6_addr32[0] - = ia->ia_addr.sin6_addr.s6_addr32[0] & - ia->ia_prefixmask.sin6_addr.s6_addr32[0]; - net.sin6_addr.s6_addr32[1] - = ia->ia_addr.sin6_addr.s6_addr32[1] & - ia->ia_prefixmask.sin6_addr.s6_addr32[1]; - net.sin6_addr.s6_addr32[2] - = ia->ia_addr.sin6_addr.s6_addr32[2] & - ia->ia_prefixmask.sin6_addr.s6_addr32[2]; - net.sin6_addr.s6_addr32[3] - = ia->ia_addr.sin6_addr.s6_addr32[3] & - ia->ia_prefixmask.sin6_addr.s6_addr32[3]; - ia->ia_net = net; - break; -#endif - case SIOCAIFADDR_IN6: - prefixIsNew = 0; - hostIsNew = 1; + { + int i, error = 0; + struct nd_prefix pr0, *pr; - if (ifra->ifra_addr.sin6_len == 0) { - ifra->ifra_addr = ia->ia_addr; - hostIsNew = 0; - } else if (IN6_ARE_ADDR_EQUAL(&ifra->ifra_addr.sin6_addr, - &ia->ia_addr.sin6_addr)) - hostIsNew = 0; + if (dlil_find_dltag(ifp->if_family, ifp->if_unit, PF_INET6, &dl_tag) == EPROTONOSUPPORT) { + in6_if_up(ifp); /* no dl_tag, the interface is not "up" for IPv6 yet */ + } - /* Validate address families: */ /* - * The destination address for a p2p link must have a family - * of AF_UNSPEC or AF_INET6. + * first, make or update the interface address structure, + * and link it to the list. */ - if ((ifp->if_flags & IFF_POINTOPOINT) != 0 && - ifra->ifra_dstaddr.sin6_family != AF_INET6 && - ifra->ifra_dstaddr.sin6_family != AF_UNSPEC) - return(EAFNOSUPPORT); + if ((error = in6_update_ifa(ifp, ifra, ia)) != 0) + return(error); + /* - * The prefixmask must have a family of AF_UNSPEC or AF_INET6. + * then, make the prefix on-link on the interface. + * XXX: we'd rather create the prefix before the address, but + * we need at least one address to install the corresponding + * interface route, so we configure the address first. */ - if (ifra->ifra_prefixmask.sin6_family != AF_INET6 && - ifra->ifra_prefixmask.sin6_family != AF_UNSPEC) - return(EAFNOSUPPORT); - if (ifra->ifra_prefixmask.sin6_len) { - in6_ifscrub(ifp, ia); - ia->ia_prefixmask = ifra->ifra_prefixmask; - prefixIsNew = 1; + /* + * convert mask to prefix length (prefixmask has already + * been validated in in6_update_ifa(). + */ + bzero(&pr0, sizeof(pr0)); + pr0.ndpr_ifp = ifp; + pr0.ndpr_plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr, + NULL); + if (pr0.ndpr_plen == 128) + break; /* we don't need to install a host route. */ + pr0.ndpr_prefix = ifra->ifra_addr; + pr0.ndpr_mask = ifra->ifra_prefixmask.sin6_addr; + /* apply the mask for safety. */ + for (i = 0; i < 4; i++) { + pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &= + ifra->ifra_prefixmask.sin6_addr.s6_addr32[i]; } - if ((ifp->if_flags & IFF_POINTOPOINT) && - (ifra->ifra_dstaddr.sin6_family == AF_INET6)) { - in6_ifscrub(ifp, ia); - oldaddr = ia->ia_dstaddr; - ia->ia_dstaddr = ifra->ifra_dstaddr; - /* link-local index check: should be a separate function? */ - if (IN6_IS_ADDR_LINKLOCAL(&ia->ia_dstaddr.sin6_addr)) { - if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] == 0) { - /* - * interface ID is not embedded by - * the user - */ - ia->ia_dstaddr.sin6_addr.s6_addr16[1] - = htons(ifp->if_index); - } else if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] != - htons(ifp->if_index)) { - ia->ia_dstaddr = oldaddr; - return(EINVAL); /* ifid is contradict */ - } + /* + * XXX: since we don't have enough APIs, we just set inifinity + * to lifetimes. They can be overridden by later advertised + * RAs (when accept_rtadv is non 0), but we'd rather intend + * such a behavior. + */ + pr0.ndpr_raf_onlink = 1; /* should be configurable? */ + pr0.ndpr_raf_auto = + ((ifra->ifra_flags & IN6_IFF_AUTOCONF) != 0); + pr0.ndpr_vltime = ifra->ifra_lifetime.ia6t_vltime; + pr0.ndpr_pltime = ifra->ifra_lifetime.ia6t_pltime; + + /* add the prefix if there's one. */ + if ((pr = nd6_prefix_lookup(&pr0)) == NULL) { + /* + * nd6_prelist_add will install the corresponding + * interface route. + */ + if ((error = nd6_prelist_add(&pr0, NULL, &pr)) != 0) + return(error); + if (pr == NULL) { + log(LOG_ERR, "nd6_prelist_add succedded but " + "no prefix\n"); + return(EINVAL); /* XXX panic here? */ } - prefixIsNew = 1; /* We lie; but effect's the same */ - } - if (hostIsNew || prefixIsNew) { - error = in6_ifinit(ifp, ia, &ifra->ifra_addr, 0); -#if 0 - if (error) - goto undo; -#endif } - if (hostIsNew && (ifp->if_flags & IFF_MULTICAST)) { - int error_local = 0; + if ((ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr)) + == NULL) { + /* XXX: this should not happen! */ + log(LOG_ERR, "in6_control: addition succeeded, but" + " no ifaddr\n"); + } else { + if ((ia->ia6_flags & IN6_IFF_AUTOCONF) != 0 && + ia->ia6_ndpr == NULL) { /* new autoconfed addr */ + ia->ia6_ndpr = pr; + pr->ndpr_refcnt++; + + /* + * If this is the first autoconf address from + * the prefix, create a temporary address + * as well (when specified). + */ + if (ip6_use_tempaddr && + pr->ndpr_refcnt == 1) { + int e; + if ((e = in6_tmpifadd(ia, 1)) != 0) { + log(LOG_NOTICE, "in6_control: " + "failed to create a " + "temporary address, " + "errno=%d\n", + e); + } + } + } /* - * join solicited multicast addr for new host id + * this might affect the status of autoconfigured + * addresses, that is, this address might make + * other addresses detached. */ - struct in6_addr llsol; - bzero(&llsol, sizeof(struct in6_addr)); - llsol.s6_addr16[0] = htons(0xff02); - llsol.s6_addr16[1] = htons(ifp->if_index); - llsol.s6_addr32[1] = 0; - llsol.s6_addr32[2] = htonl(1); - llsol.s6_addr32[3] = - ifra->ifra_addr.sin6_addr.s6_addr32[3]; - llsol.s6_addr8[12] = 0xff; - (void)in6_addmulti(&llsol, ifp, &error_local); - if (error == 0) - error = error_local; + pfxlist_onlink_check(); } - ia->ia6_flags = ifra->ifra_flags; - ia->ia6_flags &= ~IN6_IFF_DUPLICATED; /*safety*/ - ia->ia6_flags &= ~IN6_IFF_NODAD; /* Mobile IPv6 */ + dlil_find_dltag(ifp->if_family, ifp->if_unit, PF_INET6, &dl_tag); + ia->ia_ifa.ifa_dlt = dl_tag; - ia->ia6_lifetime = ifra->ifra_lifetime; - /* for sanity */ - if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { - ia->ia6_lifetime.ia6t_expire = - time_second + ia->ia6_lifetime.ia6t_vltime; - } else - ia->ia6_lifetime.ia6t_expire = 0; - if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { - ia->ia6_lifetime.ia6t_preferred = - time_second + ia->ia6_lifetime.ia6t_pltime; - } else - ia->ia6_lifetime.ia6t_preferred = 0; + in6_post_msg(ifp, KEV_INET6_NEW_USER_ADDR, ia); + break; + } + + case SIOCDIFADDR_IN6: + { + int i = 0; + struct nd_prefix pr0, *pr; /* - * Perform DAD, if needed. - * XXX It may be of use, if we can administratively - * disable DAD. + * If the address being deleted is the only one that owns + * the corresponding prefix, expire the prefix as well. + * XXX: theoretically, we don't have to warry about such + * relationship, since we separate the address management + * and the prefix management. We do this, however, to provide + * as much backward compatibility as possible in terms of + * the ioctl operation. */ - switch (ifp->if_type) { - case IFT_ARCNET: - case IFT_ETHER: - case IFT_FDDI: -#if 0 - case IFT_ATM: - case IFT_SLIP: - case IFT_PPP: -#endif - /* Mobile IPv6 modification */ - if ((ifra->ifra_flags & IN6_IFF_NODAD) == 0) { - ia->ia6_flags |= IN6_IFF_TENTATIVE; - nd6_dad_start((struct ifaddr *)ia, NULL); - } - break; - case IFT_DUMMY: - case IFT_FAITH: - case IFT_GIF: - case IFT_LOOP: - default: - break; + bzero(&pr0, sizeof(pr0)); + pr0.ndpr_ifp = ifp; + pr0.ndpr_plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, + NULL); + if (pr0.ndpr_plen == 128) + goto purgeaddr; + pr0.ndpr_prefix = ia->ia_addr; + pr0.ndpr_mask = ia->ia_prefixmask.sin6_addr; + for (i = 0; i < 4; i++) { + pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &= + ia->ia_prefixmask.sin6_addr.s6_addr32[i]; } - - if (hostIsNew) { - int iilen; - int error_local = 0; - - iilen = (sizeof(ia->ia_prefixmask.sin6_addr) << 3) - - in6_mask2len(&ia->ia_prefixmask.sin6_addr); - error_local = in6_prefix_add_ifid(iilen, ia); - if (error == 0) - error = error_local; + /* + * The logic of the following condition is a bit complicated. + * We expire the prefix when + * 1. the address obeys autoconfiguration and it is the + * only owner of the associated prefix, or + * 2. the address does not obey autoconf and there is no + * other owner of the prefix. + */ + if ((pr = nd6_prefix_lookup(&pr0)) != NULL && + (((ia->ia6_flags & IN6_IFF_AUTOCONF) != 0 && + pr->ndpr_refcnt == 1) || + ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0 && + pr->ndpr_refcnt == 0))) { + pr->ndpr_expire = 1; /* XXX: just for expiration */ } - return(error); - - case SIOCDIFADDR_IN6: - in6_purgeaddr(&ia->ia_ifa, ifp); + purgeaddr: + in6_purgeaddr(&ia->ia_ifa); break; + } default: #ifdef __APPLE__ @@ -997,17 +814,442 @@ in6_control(so, cmd, data, ifp) return((*ifp->if_ioctl)(ifp, cmd, data)); #endif } + return(0); } -void -in6_purgeaddr(ifa, ifp) - struct ifaddr *ifa; - struct ifnet *ifp; +/* + * Update parameters of an IPv6 interface address. + * If necessary, a new entry is created and linked into address chains. + * This function is separated from in6_control(). + * XXX: should this be performed under splnet()? + */ +int +in6_update_ifa(ifp, ifra, ia) + struct ifnet *ifp; + struct in6_aliasreq *ifra; + struct in6_ifaddr *ia; { - struct in6_ifaddr *oia, *ia = (void *) ifa; + int error = 0, hostIsNew = 0, plen = -1; + struct in6_ifaddr *oia; + struct sockaddr_in6 dst6; + struct in6_addrlifetime *lt; - in6_ifscrub(ifp, ia); + /* Validate parameters */ + if (ifp == NULL || ifra == NULL) /* this maybe redundant */ + return(EINVAL); + + /* + * The destination address for a p2p link must have a family + * of AF_UNSPEC or AF_INET6. + */ + if ((ifp->if_flags & IFF_POINTOPOINT) != 0 && + ifra->ifra_dstaddr.sin6_family != AF_INET6 && + ifra->ifra_dstaddr.sin6_family != AF_UNSPEC) + return(EAFNOSUPPORT); + /* + * validate ifra_prefixmask. don't check sin6_family, netmask + * does not carry fields other than sin6_len. + */ + if (ifra->ifra_prefixmask.sin6_len > sizeof(struct sockaddr_in6)) + return(EINVAL); + /* + * Because the IPv6 address architecture is classless, we require + * users to specify a (non 0) prefix length (mask) for a new address. + * We also require the prefix (when specified) mask is valid, and thus + * reject a non-consecutive mask. + */ + if (ia == NULL && ifra->ifra_prefixmask.sin6_len == 0) + return(EINVAL); + if (ifra->ifra_prefixmask.sin6_len != 0) { + plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr, + (u_char *)&ifra->ifra_prefixmask + + ifra->ifra_prefixmask.sin6_len); + if (plen <= 0) + return(EINVAL); + } + else { + /* + * In this case, ia must not be NULL. We just use its prefix + * length. + */ + plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); + } + /* + * If the destination address on a p2p interface is specified, + * and the address is a scoped one, validate/set the scope + * zone identifier. + */ + dst6 = ifra->ifra_dstaddr; + if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) && + (dst6.sin6_family == AF_INET6)) { + int scopeid; + +#ifndef SCOPEDROUTING + if ((error = in6_recoverscope(&dst6, + &ifra->ifra_dstaddr.sin6_addr, + ifp)) != 0) + return(error); +#endif + scopeid = in6_addr2scopeid(ifp, &dst6.sin6_addr); + if (dst6.sin6_scope_id == 0) /* user omit to specify the ID. */ + dst6.sin6_scope_id = scopeid; + else if (dst6.sin6_scope_id != scopeid) + return(EINVAL); /* scope ID mismatch. */ +#ifndef SCOPEDROUTING + if ((error = in6_embedscope(&dst6.sin6_addr, &dst6, NULL, NULL)) + != 0) + return(error); + dst6.sin6_scope_id = 0; /* XXX */ +#endif + } + /* + * The destination address can be specified only for a p2p or a + * loopback interface. If specified, the corresponding prefix length + * must be 128. + */ + if (ifra->ifra_dstaddr.sin6_family == AF_INET6) { + if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) == 0) { + /* XXX: noisy message */ + log(LOG_INFO, "in6_update_ifa: a destination can be " + "specified for a p2p or a loopback IF only\n"); + return(EINVAL); + } + if (plen != 128) { + /* + * The following message seems noisy, but we dare to + * add it for diagnosis. + */ + log(LOG_INFO, "in6_update_ifa: prefixlen must be 128 " + "when dstaddr is specified\n"); + return(EINVAL); + } + } + /* lifetime consistency check */ + lt = &ifra->ifra_lifetime; + if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME + && lt->ia6t_vltime + time_second < time_second) { + return EINVAL; + } + if (lt->ia6t_vltime == 0) { + /* + * the following log might be noisy, but this is a typical + * configuration mistake or a tool's bug. + */ + log(LOG_INFO, + "in6_update_ifa: valid lifetime is 0 for %s\n", + ip6_sprintf(&ifra->ifra_addr.sin6_addr)); + } + if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME + && lt->ia6t_pltime + time_second < time_second) { + return EINVAL; + } + + /* + * If this is a new address, allocate a new ifaddr and link it + * into chains. + */ + if (ia == NULL) { + hostIsNew = 1; + /* + * When in6_update_ifa() is called in a process of a received + * RA, it is called under splnet(). So, we should call malloc + * with M_NOWAIT. + */ + ia = (struct in6_ifaddr *) + _MALLOC(sizeof(*ia), M_IFADDR, M_NOWAIT); + if (ia == NULL) + return (ENOBUFS); + bzero((caddr_t)ia, sizeof(*ia)); + /* Initialize the address and masks */ + ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; + ia->ia_addr.sin6_family = AF_INET6; + ia->ia_addr.sin6_len = sizeof(ia->ia_addr); + if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) != 0) { + /* + * XXX: some functions expect that ifa_dstaddr is not + * NULL for p2p interfaces. + */ + ia->ia_ifa.ifa_dstaddr + = (struct sockaddr *)&ia->ia_dstaddr; + } else { + ia->ia_ifa.ifa_dstaddr = NULL; + } + ia->ia_ifa.ifa_netmask + = (struct sockaddr *)&ia->ia_prefixmask; + + ia->ia_ifp = ifp; + if ((oia = in6_ifaddr) != NULL) { + for ( ; oia->ia_next; oia = oia->ia_next) + continue; + oia->ia_next = ia; + } else + in6_ifaddr = ia; + + TAILQ_INSERT_TAIL(&ifp->if_addrlist, &ia->ia_ifa, + ifa_list); + } + + /* set prefix mask */ + if (ifra->ifra_prefixmask.sin6_len) { + /* + * We prohibit changing the prefix length of an existing + * address, because + * + such an operation should be rare in IPv6, and + * + the operation would confuse prefix management. + */ + if (ia->ia_prefixmask.sin6_len && + in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL) != plen) { + log(LOG_INFO, "in6_update_ifa: the prefix length of an" + " existing (%s) address should not be changed\n", + ip6_sprintf(&ia->ia_addr.sin6_addr)); + error = EINVAL; + goto unlink; + } + ia->ia_prefixmask = ifra->ifra_prefixmask; + } + + /* + * If a new destination address is specified, scrub the old one and + * install the new destination. Note that the interface must be + * p2p or loopback (see the check above.) + */ + if (dst6.sin6_family == AF_INET6 && + !IN6_ARE_ADDR_EQUAL(&dst6.sin6_addr, + &ia->ia_dstaddr.sin6_addr)) { + int e; + + if ((ia->ia_flags & IFA_ROUTE) != 0 && + (e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST)) + != 0) { + log(LOG_ERR, "in6_update_ifa: failed to remove " + "a route to the old destination: %s\n", + ip6_sprintf(&ia->ia_addr.sin6_addr)); + /* proceed anyway... */ + } + else + ia->ia_flags &= ~IFA_ROUTE; + ia->ia_dstaddr = dst6; + } + + /* reset the interface and routing table appropriately. */ + if ((error = in6_ifinit(ifp, ia, &ifra->ifra_addr, hostIsNew)) != 0) + goto unlink; + + /* + * Beyond this point, we should call in6_purgeaddr upon an error, + * not just go to unlink. + */ + +#if 0 /* disable this mechanism for now */ + /* update prefix list */ + if (hostIsNew && + (ifra->ifra_flags & IN6_IFF_NOPFX) == 0) { /* XXX */ + int iilen; + + iilen = (sizeof(ia->ia_prefixmask.sin6_addr) << 3) - plen; + if ((error = in6_prefix_add_ifid(iilen, ia)) != 0) { + in6_purgeaddr((struct ifaddr *)ia); + return(error); + } + } +#endif + + if ((ifp->if_flags & IFF_MULTICAST) != 0) { + struct sockaddr_in6 mltaddr, mltmask; + struct in6_multi *in6m; + + if (hostIsNew) { + /* + * join solicited multicast addr for new host id + */ + struct in6_addr llsol; + bzero(&llsol, sizeof(struct in6_addr)); + llsol.s6_addr16[0] = htons(0xff02); + llsol.s6_addr16[1] = htons(ifp->if_index); + llsol.s6_addr32[1] = 0; + llsol.s6_addr32[2] = htonl(1); + llsol.s6_addr32[3] = + ifra->ifra_addr.sin6_addr.s6_addr32[3]; + llsol.s6_addr8[12] = 0xff; + (void)in6_addmulti(&llsol, ifp, &error); + if (error != 0) { + log(LOG_WARNING, + "in6_update_ifa: addmulti failed for " + "%s on %s (errno=%d)\n", + ip6_sprintf(&llsol), if_name(ifp), + error); + in6_purgeaddr((struct ifaddr *)ia); + return(error); + } + } + + bzero(&mltmask, sizeof(mltmask)); + mltmask.sin6_len = sizeof(struct sockaddr_in6); + mltmask.sin6_family = AF_INET6; + mltmask.sin6_addr = in6mask32; + + /* + * join link-local all-nodes address + */ + bzero(&mltaddr, sizeof(mltaddr)); + mltaddr.sin6_len = sizeof(struct sockaddr_in6); + mltaddr.sin6_family = AF_INET6; + mltaddr.sin6_addr = in6addr_linklocal_allnodes; + mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); + + IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m); + if (in6m == NULL) { + rtrequest(RTM_ADD, + (struct sockaddr *)&mltaddr, + (struct sockaddr *)&ia->ia_addr, + (struct sockaddr *)&mltmask, + RTF_UP|RTF_CLONING, /* xxx */ + (struct rtentry **)0); + (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error); + if (error != 0) { + log(LOG_WARNING, + "in6_update_ifa: addmulti failed for " + "%s on %s (errno=%d)\n", + ip6_sprintf(&mltaddr.sin6_addr), + if_name(ifp), error); + } + } + + /* + * join node information group address + */ +#define hostnamelen strlen(hostname) + if (in6_nigroup(ifp, hostname, hostnamelen, &mltaddr.sin6_addr) + == 0) { + IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m); + if (in6m == NULL && ia != NULL) { + (void)in6_addmulti(&mltaddr.sin6_addr, + ifp, &error); + if (error != 0) { + log(LOG_WARNING, "in6_update_ifa: " + "addmulti failed for " + "%s on %s (errno=%d)\n", + ip6_sprintf(&mltaddr.sin6_addr), + if_name(ifp), error); + } + } + } +#undef hostnamelen + + /* + * join node-local all-nodes address, on loopback. + * XXX: since "node-local" is obsoleted by interface-local, + * we have to join the group on every interface with + * some interface-boundary restriction. + */ + if (ifp->if_flags & IFF_LOOPBACK) { + struct in6_ifaddr *ia_loop; + + struct in6_addr loop6 = in6addr_loopback; + ia_loop = in6ifa_ifpwithaddr(ifp, &loop6); + + mltaddr.sin6_addr = in6addr_nodelocal_allnodes; + + IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m); + if (in6m == NULL && ia_loop != NULL) { + rtrequest(RTM_ADD, + (struct sockaddr *)&mltaddr, + (struct sockaddr *)&ia_loop->ia_addr, + (struct sockaddr *)&mltmask, + RTF_UP, + (struct rtentry **)0); + (void)in6_addmulti(&mltaddr.sin6_addr, ifp, + &error); + if (error != 0) { + log(LOG_WARNING, "in6_update_ifa: " + "addmulti failed for %s on %s " + "(errno=%d)\n", + ip6_sprintf(&mltaddr.sin6_addr), + if_name(ifp), error); + } + } + } + } + + ia->ia6_flags = ifra->ifra_flags; + ia->ia6_flags &= ~IN6_IFF_DUPLICATED; /*safety*/ + ia->ia6_flags &= ~IN6_IFF_NODAD; /* Mobile IPv6 */ + + ia->ia6_lifetime = ifra->ifra_lifetime; + /* for sanity */ + if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { + ia->ia6_lifetime.ia6t_expire = + time_second + ia->ia6_lifetime.ia6t_vltime; + } else + ia->ia6_lifetime.ia6t_expire = 0; + if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { + ia->ia6_lifetime.ia6t_preferred = + time_second + ia->ia6_lifetime.ia6t_pltime; + } else + ia->ia6_lifetime.ia6t_preferred = 0; + + /* + * make sure to initialize ND6 information. this is to workaround + * issues with interfaces with IPv6 addresses, which have never brought + * up. We are assuming that it is safe to nd6_ifattach multiple times. + */ + nd6_ifattach(ifp); + + /* + * Perform DAD, if needed. + * XXX It may be of use, if we can administratively + * disable DAD. + */ + if (in6if_do_dad(ifp) && (ifra->ifra_flags & IN6_IFF_NODAD) == 0) { + ia->ia6_flags |= IN6_IFF_TENTATIVE; + nd6_dad_start((struct ifaddr *)ia, NULL); + } + + return(error); + + unlink: + /* + * XXX: if a change of an existing address failed, keep the entry + * anyway. + */ + if (hostIsNew) + in6_unlink_ifa(ia, ifp); + return(error); +} + +void +in6_purgeaddr(ifa) + struct ifaddr *ifa; +{ + struct ifnet *ifp = ifa->ifa_ifp; + struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa; + + /* stop DAD processing */ + nd6_dad_stoptimer(ifa); + + /* + * delete route to the destination of the address being purged. + * The interface must be p2p or loopback in this case. + */ + if ((ia->ia_flags & IFA_ROUTE) != 0 && ia->ia_dstaddr.sin6_len != 0) { + int e; + + if ((e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST)) + != 0) { + log(LOG_ERR, "in6_purgeaddr: failed to remove " + "a route to the p2p destination: %s on %s, " + "errno=%d\n", + ip6_sprintf(&ia->ia_addr.sin6_addr), if_name(ifp), + e); + /* proceed anyway... */ + } + else + ia->ia_flags &= ~IFA_ROUTE; + } + + /* Remove ownaddr's loopback rtentry, if it exists. */ + in6_ifremloop(&(ia->ia_ifa)); if (ifp->if_flags & IFF_MULTICAST) { /* @@ -1029,22 +1271,20 @@ in6_purgeaddr(ifa, ifp) in6_delmulti(in6m); } -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - if ((ifa = ifp->if_addrlist) == ia62ifa(ia)) - ifp->if_addrlist = ifa->ifa_next; - else { - while (ifa->ifa_next && - (ifa->ifa_next != ia62ifa(ia))) - ifa = ifa->ifa_next; - if (ifa->ifa_next) - ifa->ifa_next = ia62ifa(ia)->ifa_next; - else - printf("Couldn't unlink in6_ifaddr from ifp\n"); - } -#else + in6_post_msg(ifp, KEV_INET6_ADDR_DELETED, ia); + in6_unlink_ifa(ia, ifp); +} + +static void +in6_unlink_ifa(ia, ifp) + struct in6_ifaddr *ia; + struct ifnet *ifp; +{ + int plen, iilen; + struct in6_ifaddr *oia; + int s = splnet(); + TAILQ_REMOVE(&ifp->if_addrlist, &ia->ia_ifa, ifa_list); -#endif - IFAFREE(&ia->ia_ifa); oia = ia; if (oia == (ia = in6_ifaddr)) @@ -1054,27 +1294,71 @@ in6_purgeaddr(ifa, ifp) ia = ia->ia_next; if (ia->ia_next) ia->ia_next = oia->ia_next; - else - printf("Didn't unlink in6_ifaddr from list\n"); + else { + /* search failed */ + printf("Couldn't unlink in6_ifaddr from in6_ifaddr\n"); + } } - { - int iilen; - iilen = (sizeof(oia->ia_prefixmask.sin6_addr) << 3) - - in6_mask2len(&oia->ia_prefixmask.sin6_addr); + if (oia->ia6_ifpr) { /* check for safety */ + plen = in6_mask2len(&oia->ia_prefixmask.sin6_addr, NULL); + iilen = (sizeof(oia->ia_prefixmask.sin6_addr) << 3) - plen; in6_prefix_remove_ifid(iilen, oia); } -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined (__APPLE__) - if (oia->ia6_multiaddrs.lh_first != NULL) - in6_savemkludge(oia); -#endif - IFAFREE(&oia->ia_ifa); + /* + * When an autoconfigured address is being removed, release the + * reference to the base prefix. Also, since the release might + * affect the status of other (detached) addresses, call + * pfxlist_onlink_check(). + */ + if ((oia->ia6_flags & IN6_IFF_AUTOCONF) != 0) { + if (oia->ia6_ndpr == NULL) { + log(LOG_NOTICE, "in6_unlink_ifa: autoconf'ed address " + "%p has no prefix\n", oia); + } else { + oia->ia6_ndpr->ndpr_refcnt--; + oia->ia6_flags &= ~IN6_IFF_AUTOCONF; + oia->ia6_ndpr = NULL; + } + + pfxlist_onlink_check(); + } + + /* + * release another refcnt for the link from in6_ifaddr. + * Note that we should decrement the refcnt at least once for all *BSD. + */ + ifafree(&oia->ia_ifa); + + splx(s); +} + +void +in6_purgeif(ifp) + struct ifnet *ifp; +{ + struct ifaddr *ifa, *nifa = NULL; + + if (ifp == NULL || &ifp->if_addrlist == NULL) + return; + + for (ifa = TAILQ_FIRST(&ifp->if_addrlist); ifa != NULL; ifa = nifa) + { + nifa = TAILQ_NEXT(ifa, ifa_list); + if (ifa->ifa_addr == NULL) + continue; + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + in6_purgeaddr(ifa); + } + + in6_ifdetach(ifp); } /* * SIOC[GAD]LIFADDR. - * SIOCGLIFADDR: get first address. (???) + * SIOCGLIFADDR: get first address. (?) * SIOCGLIFADDR with IFLR_PREFIX: * get first address that matches the specified prefix. * SIOCALIFADDR: add the specified address. @@ -1096,20 +1380,12 @@ in6_purgeaddr(ifa, ifp) * address encoding scheme. (see figure on page 8) */ static int -#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) && !defined (__APPLE__) in6_lifaddr_ioctl(so, cmd, data, ifp, p) struct socket *so; u_long cmd; caddr_t data; struct ifnet *ifp; struct proc *p; -#else -in6_lifaddr_ioctl(so, cmd, data, ifp) - struct socket *so; - u_long cmd; - caddr_t data; - struct ifnet *ifp; -#endif { struct if_laddrreq *iflr = (struct if_laddrreq *)data; struct ifaddr *ifa; @@ -1213,16 +1489,11 @@ in6_lifaddr_ioctl(so, cmd, data, ifp) } } - ifra.ifra_prefixmask.sin6_family = AF_INET6; ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); in6_len2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen); ifra.ifra_flags = iflr->flags & ~IFLR_PREFIX; -#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) && !defined (__APPLE__) return in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, ifp, p); -#else - return in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, ifp); -#endif } case SIOCGLIFADDR: case SIOCDLIFADDR: @@ -1263,19 +1534,23 @@ in6_lifaddr_ioctl(so, cmd, data, ifp) } } -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) -#else - for (ifa = ifp->if_addrlist.tqh_first; - ifa; - ifa = ifa->ifa_list.tqe_next) -#endif + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; if (!cmp) break; + bcopy(IFA_IN6(ifa), &candidate, sizeof(candidate)); +#ifndef SCOPEDROUTING + /* + * XXX: this is adhoc, but is necessary to allow + * a user to specify fe80::/64 (not /10) for a + * link-local address. + */ + if (IN6_IS_ADDR_LINKLOCAL(&candidate)) + candidate.s6_addr16[1] = 0; +#endif candidate.s6_addr32[0] &= mask.s6_addr32[0]; candidate.s6_addr32[1] &= mask.s6_addr32[1]; candidate.s6_addr32[2] &= mask.s6_addr32[2]; @@ -1288,17 +1563,38 @@ in6_lifaddr_ioctl(so, cmd, data, ifp) ia = ifa2ia6(ifa); if (cmd == SIOCGLIFADDR) { +#ifndef SCOPEDROUTING + struct sockaddr_in6 *s6; +#endif + /* fill in the if_laddrreq structure */ bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin6_len); - +#ifndef SCOPEDROUTING /* XXX see above */ + s6 = (struct sockaddr_in6 *)&iflr->addr; + if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr)) { + s6->sin6_addr.s6_addr16[1] = 0; + s6->sin6_scope_id = + in6_addr2scopeid(ifp, &s6->sin6_addr); + } +#endif if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { bcopy(&ia->ia_dstaddr, &iflr->dstaddr, ia->ia_dstaddr.sin6_len); +#ifndef SCOPEDROUTING /* XXX see above */ + s6 = (struct sockaddr_in6 *)&iflr->dstaddr; + if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr)) { + s6->sin6_addr.s6_addr16[1] = 0; + s6->sin6_scope_id = + in6_addr2scopeid(ifp, + &s6->sin6_addr); + } +#endif } else bzero(&iflr->dstaddr, sizeof(iflr->dstaddr)); iflr->prefixlen = - in6_mask2len(&ia->ia_prefixmask.sin6_addr); + in6_mask2len(&ia->ia_prefixmask.sin6_addr, + NULL); iflr->flags = ia->ia6_flags; /*XXX*/ @@ -1324,386 +1620,107 @@ in6_lifaddr_ioctl(so, cmd, data, ifp) ia->ia_prefixmask.sin6_len); ifra.ifra_flags = ia->ia6_flags; -#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) && !defined (__APPLE__) return in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra, ifp, p); -#else - return in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra, - ifp); -#endif - } - } - } - - return EOPNOTSUPP; /*just for safety*/ -} - -/* - * Delete any existing route for an interface. - */ -void -in6_ifscrub(ifp, ia) - register struct ifnet *ifp; - register struct in6_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; - - /* Remove ownaddr's loopback rtentry, if it exists. */ - in6_ifremloop(&(ia->ia_ifa)); -} - -/* - * Initialize an interface's intetnet6 address - * and routing table entry. - */ -int -in6_ifinit(ifp, ia, sin6, scrub) - struct ifnet *ifp; - struct in6_ifaddr *ia; - struct sockaddr_in6 *sin6; - int scrub; -{ - struct sockaddr_in6 oldaddr; - int error, flags = RTF_UP; - u_long dl_tag; - int s = splimp(); - - oldaddr = ia->ia_addr; - ia->ia_addr = *sin6; - /* - * Give the interface a chance to initialize - * if this is its first address, - * and to validate the address if necessary. - */ -#ifdef __APPLE__ - error = dlil_ioctl(0, ifp, SIOCSIFADDR, (caddr_t)ia) ; - if (error == EOPNOTSUPP) - error = 0; - if (error) { - -#else - if (ifp->if_ioctl && - (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) { -#endif - printf("in6_ifinit SIOCSIFADDR for if=%s returns error=%x\n", if_name(ifp), error); - splx(s); - ia->ia_addr = oldaddr; - return(error); - } - - switch (ifp->if_type) { - case IFT_ARCNET: - case IFT_ETHER: - case IFT_FDDI: - ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; - ia->ia_ifa.ifa_flags |= RTF_CLONING; - break; - case IFT_PPP: - ia->ia_ifa.ifa_rtrequest = nd6_p2p_rtrequest; - ia->ia_ifa.ifa_flags |= RTF_CLONING; - break; - } - - splx(s); - if (scrub) { - ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr; - in6_ifscrub(ifp, ia); - ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; - } - /* xxx - * in_socktrim - */ - /* - * Add route for the network. - */ - ia->ia_ifa.ifa_metric = ifp->if_metric; - 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.sin6_family != AF_INET6) - return(0); - flags |= RTF_HOST; - } - if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0) - ia->ia_flags |= IFA_ROUTE; - - /* Add ownaddr as loopback rtentry, if necessary(ex. on p2p link). */ - in6_ifaddloop(&(ia->ia_ifa)); - -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined (__APPLE__) - if (ifp->if_flags & IFF_MULTICAST) - in6_restoremkludge(ia, ifp); -#endif - -#ifdef __APPLE__ - printf("in6_ifinit: Attach dl_tag for if=%s%n\n", ifp->if_name, ifp->if_unit); - - if (strcmp(ifp->if_name, "en") == 0) - dl_tag = ether_attach_inet6(ifp); - - if (strcmp(ifp->if_name, "lo") == 0) - dl_tag = lo_attach_inet(ifp); -#if NGIF > 0 - if (strcmp(ifp->if_name, "gif") == 0) - dl_tag = gif_attach_inet(ifp); -#endif -/* End of temp code */ - ia->ia_ifa.ifa_dlt = dl_tag; -#endif - - return(error); -} - -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined (__APPLE__) -/* - * Multicast address kludge: - * If there were any multicast addresses attached to this interface address, - * either move them to another address on this interface, or save them until - * such time as this interface is reconfigured for IPv6. - */ -void -in6_savemkludge(oia) - struct in6_ifaddr *oia; -{ - struct in6_ifaddr *ia; - struct in6_multi *in6m, *next; - - IFP_TO_IA6(oia->ia_ifp, ia); - if (ia) { /* there is another address */ - for (in6m = oia->ia6_multiaddrs.lh_first; in6m; in6m = next){ - next = in6m->in6m_entry.le_next; - IFAFREE(&in6m->in6m_ia->ia_ifa); - ia->ia_ifa.ifa_refcnt++; - in6m->in6m_ia = ia; - LIST_INSERT_HEAD(&ia->ia6_multiaddrs, in6m, in6m_entry); - } - } else { /* last address on this if deleted, save */ - struct multi6_kludge *mk; - - mk = _MALLOC(sizeof(*mk), M_IPMADDR, M_WAITOK); - - LIST_INIT(&mk->mk_head); - mk->mk_ifp = oia->ia_ifp; - - for (in6m = oia->ia6_multiaddrs.lh_first; in6m; in6m = next){ - next = in6m->in6m_entry.le_next; - IFAFREE(&in6m->in6m_ia->ia_ifa); /* release reference */ - in6m->in6m_ia = NULL; - LIST_INSERT_HEAD(&mk->mk_head, in6m, in6m_entry); - } - - if (mk->mk_head.lh_first != NULL) { - LIST_INSERT_HEAD(&in6_mk, mk, mk_entry); - } else { - FREE(mk, M_IPMADDR); } + } } + + return EOPNOTSUPP; /*just for safety*/ } /* - * Continuation of multicast address hack: - * If there was a multicast group list previously saved for this interface, - * then we re-attach it to the first address configured on the i/f. + * Initialize an interface's intetnet6 address + * and routing table entry. */ -void -in6_restoremkludge(ia, ifp) - struct in6_ifaddr *ia; - struct ifnet *ifp; -{ - struct multi6_kludge *mk; - - for (mk = in6_mk.lh_first; mk; mk = mk->mk_entry.le_next) { - if (mk->mk_ifp == ifp) { - struct in6_multi *in6m, *next; - - for (in6m = mk->mk_head.lh_first; in6m; in6m = next){ - next = in6m->in6m_entry.le_next; - in6m->in6m_ia = ia; - ia->ia_ifa.ifa_refcnt++; - LIST_INSERT_HEAD(&ia->ia6_multiaddrs, - in6m, in6m_entry); - } - LIST_REMOVE(mk, mk_entry); - _FREE(mk, M_IPMADDR); - break; - } - } -} - -void -in6_purgemkludge(ifp) +static int +in6_ifinit(ifp, ia, sin6, newhost) struct ifnet *ifp; + struct in6_ifaddr *ia; + struct sockaddr_in6 *sin6; + int newhost; { - struct multi6_kludge *mk; - struct in6_multi *in6m; + int error = 0, plen, ifacount = 0; + int s = splimp(); + struct ifaddr *ifa; - for (mk = in6_mk.lh_first; mk; mk = mk->mk_entry.le_next) { - if (mk->mk_ifp != ifp) + /* + * Give the interface a chance to initialize + * if this is its first address, + * and to validate the address if necessary. + */ + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) + { + if (ifa->ifa_addr == NULL) + continue; /* just for safety */ + if (ifa->ifa_addr->sa_family != AF_INET6) continue; - - /* leave from all multicast groups joined */ - while ((in6m = LIST_FIRST(&mk->mk_head)) != NULL) - in6_delmulti(in6m); - LIST_REMOVE(mk, mk_entry); - _FREE(mk, M_IPMADDR); - break; + ifacount++; } -} -/* - * Add an address to the list of IP6 multicast addresses for a - * given interface. - */ -struct in6_multi * -in6_addmulti(maddr6, ifp, errorp) - register struct in6_addr *maddr6; - register struct ifnet *ifp; - int *errorp; -{ - struct in6_ifaddr *ia; - struct in6_ifreq ifr; - struct in6_multi *in6m; -#if __NetBSD__ - int s = splsoftnet(); -#else - int s = splnet(); -#endif + ia->ia_addr = *sin6; - *errorp = 0; - /* - * See if address already in list. - */ - IN6_LOOKUP_MULTI(*maddr6, ifp, in6m); - if (in6m != NULL) { - /* - * Found it; just increment the refrence count. - */ - in6m->in6m_refcount++; - } else { - /* - * New address; allocate a new multicast record - * and link it into the interface's multicast list. - */ - in6m = (struct in6_multi *) - _MALLOC(sizeof(*in6m), M_IPMADDR, M_NOTWAIT); - if (in6m == NULL) { - splx(s); - *errorp = ENOBUFS; - return(NULL); - } - in6m->in6m_addr = *maddr6; - in6m->in6m_ifp = ifp; - in6m->in6m_refcount = 1; - IFP_TO_IA6(ifp, ia); - if (ia == NULL) { - _FREE(in6m, M_IPMADDR); - splx(s); - *errorp = EADDRNOTAVAIL; /* appropriate? */ - return(NULL); - } - in6m->in6m_ia = ia; - ia->ia_ifa.ifa_refcnt++; /* gain a reference */ - LIST_INSERT_HEAD(&ia->ia6_multiaddrs, in6m, in6m_entry); - /* - * Ask the network driver to update its multicast reception - * filter appropriately for the new address. - */ - bzero(&ifr.ifr_addr, sizeof(struct sockaddr_in6)); - ifr.ifr_addr.sin6_len = sizeof(struct sockaddr_in6); - ifr.ifr_addr.sin6_family = AF_INET6; - ifr.ifr_addr.sin6_addr = *maddr6; + if (ifacount <= 1 && #ifdef __APPLE__ - *errorp = dlil_ioctl(0, ifp, SIOCADDMULTI, (caddr_t)&ifr); - printf("in6_addmulti: if=%s%n dlil_ioctl returns=%d\n", ifp->if_name, ifp->if_unit, *errorp); - if (*errorp == EOPNOTSUPP) - *errorp = 0; - -#else - if (ifp->if_ioctl == NULL) - *errorp = ENXIO; /* XXX: appropriate? */ - else - *errorp = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, - (caddr_t)&ifr); -#endif - if (*errorp) { - LIST_REMOVE(in6m, in6m_entry); - _FREE(in6m, M_IPMADDR); + (error = dlil_ioctl(0, ifp, SIOCSIFADDR, (caddr_t)ia))) { + if (error == EOPNOTSUPP) + error = 0; + if (error) { splx(s); - return(NULL); + return(error); } - /* - * Let MLD6 know that we have joined a new IP6 multicast - * group. - */ - mld6_start_listening(in6m); } - splx(s); - return(in6m); -} - -/* - * Delete a multicast address record. - */ -void -in6_delmulti(in6m) - struct in6_multi *in6m; -{ - struct in6_ifreq ifr; -#if __NetBSD__ - int s = splsoftnet(); #else - int s = splnet(); + ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) { + splx(s); + return(error); + } #endif + splx(s); - if (--in6m->in6m_refcount == 0) { - /* - * No remaining claims to this record; let MLD6 know - * that we are leaving the multicast group. - */ - mld6_stop_listening(in6m); + ia->ia_ifa.ifa_metric = ifp->if_metric; - /* - * Unlink from list. - */ - LIST_REMOVE(in6m, in6m_entry); - if (in6m->in6m_ia) - IFAFREE(&in6m->in6m_ia->ia_ifa); /* release reference */ + /* we could do in(6)_socktrim here, but just omit it at this moment. */ + /* + * Special case: + * If the destination address is specified for a point-to-point + * interface, install a route to the destination as an interface + * direct route. + */ + plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */ + if (plen == 128 && ia->ia_dstaddr.sin6_family == AF_INET6) { + if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, + RTF_UP | RTF_HOST)) != 0) + return(error); + ia->ia_flags |= IFA_ROUTE; + } + if (plen < 128) { /* - * Notify the network driver to update its multicast - * reception filter. + * The RTF_CLONING flag is necessary for in6_is_ifloop_auto(). */ - bzero(&ifr.ifr_addr, sizeof(struct sockaddr_in6)); - ifr.ifr_addr.sin6_len = sizeof(struct sockaddr_in6); - ifr.ifr_addr.sin6_family = AF_INET6; - ifr.ifr_addr.sin6_addr = in6m->in6m_addr; -#ifdef __APPLE__ - dlil_ioctl(0, in6m->in6m_ifp, SIOCDELMULTI, (caddr_t)&ifr); -#else - (*in6m->in6m_ifp->if_ioctl)(in6m->in6m_ifp, - SIOCDELMULTI, (caddr_t)&ifr); -#endif - _FREE(in6m, M_IPMADDR); + ia->ia_ifa.ifa_flags |= RTF_CLONING; } - splx(s); + + /* Add ownaddr as loopback rtentry, if necessary(ex. on p2p link). */ + if (newhost) { + /* set the rtrequest function to create llinfo */ + ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; + in6_ifaddloop(&(ia->ia_ifa)); + } + + return(error); } -#else /* not FreeBSD3 */ + /* * Add an address to the list of IP6 multicast addresses for a * given interface. */ struct in6_multi * in6_addmulti(maddr6, ifp, errorp) - register struct in6_addr *maddr6; - register struct ifnet *ifp; + struct in6_addr *maddr6; + struct ifnet *ifp; int *errorp; { struct in6_multi *in6m; @@ -1777,13 +1794,12 @@ in6_delmulti(in6m) mld6_stop_listening(in6m); ifma->ifma_protospec = 0; LIST_REMOVE(in6m, in6m_entry); - _FREE(in6m, M_IPMADDR); + FREE(in6m, M_IPMADDR); } /* XXX - should be separate API for when we have an ifma? */ if_delmulti(ifma->ifma_ifp, ifma->ifma_addr); splx(s); } -#endif /* not FreeBSD3 */ /* * Find an IPv6 interface link-local address specific to an interface. @@ -1793,13 +1809,9 @@ in6ifa_ifpforlinklocal(ifp, ignoreflags) struct ifnet *ifp; int ignoreflags; { - register struct ifaddr *ifa; + struct ifaddr *ifa; -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) -#else - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) -#endif + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr == NULL) continue; /* just for safety */ @@ -1825,13 +1837,9 @@ in6ifa_ifpwithaddr(ifp, addr) struct ifnet *ifp; struct in6_addr *addr; { - register struct ifaddr *ifa; + struct ifaddr *ifa; -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) -#else - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) -#endif + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr == NULL) continue; /* just for safety */ @@ -1851,13 +1859,13 @@ static char digits[] = "0123456789abcdef"; static int ip6round = 0; char * ip6_sprintf(addr) -register struct in6_addr *addr; + const struct in6_addr *addr; { static char ip6buf[8][48]; - register int i; - register char *cp; - register u_short *a = (u_short *)addr; - register u_char *d; + int i; + char *cp; + u_short *a = (u_short *)addr; + u_char *d; int dcolon = 0; ip6round = (ip6round + 1) & 7; @@ -1915,93 +1923,31 @@ in6_localaddr(in6) return (0); } -/* - * Get a scope of the address. Node-local, link-local, site-local or global. - */ int -in6_addrscope (addr) -struct in6_addr *addr; +in6_is_addr_deprecated(sa6) + struct sockaddr_in6 *sa6; { - int scope; - - if (addr->s6_addr8[0] == 0xfe) { - scope = addr->s6_addr8[1] & 0xc0; - - switch (scope) { - case 0x80: - return IPV6_ADDR_SCOPE_LINKLOCAL; - break; - case 0xc0: - return IPV6_ADDR_SCOPE_SITELOCAL; - break; - default: - return IPV6_ADDR_SCOPE_GLOBAL; /* just in case */ - break; - } - } - - - if (addr->s6_addr8[0] == 0xff) { - scope = addr->s6_addr8[1] & 0x0f; + struct in6_ifaddr *ia; - /* - * due to other scope such as reserved, - * return scope doesn't work. - */ - switch (scope) { - case IPV6_ADDR_SCOPE_NODELOCAL: - return IPV6_ADDR_SCOPE_NODELOCAL; - break; - case IPV6_ADDR_SCOPE_LINKLOCAL: - return IPV6_ADDR_SCOPE_LINKLOCAL; - break; - case IPV6_ADDR_SCOPE_SITELOCAL: - return IPV6_ADDR_SCOPE_SITELOCAL; - break; - default: - return IPV6_ADDR_SCOPE_GLOBAL; - break; - } - } + for (ia = in6_ifaddr; ia; ia = ia->ia_next) { + if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, + &sa6->sin6_addr) && +#if SCOPEDROUTING + ia->ia_addr.sin6_scope_id == sa6->sin6_scope_id && +#endif + (ia->ia6_flags & IN6_IFF_DEPRECATED) != 0) + return(1); /* true */ - if (bcmp(&in6addr_loopback, addr, sizeof(addr) - 1) == 0) { - if (addr->s6_addr8[15] == 1) /* loopback */ - return IPV6_ADDR_SCOPE_NODELOCAL; - if (addr->s6_addr8[15] == 0) /* unspecified */ - return IPV6_ADDR_SCOPE_LINKLOCAL; + /* XXX: do we still have to go thru the rest of the list? */ } - return IPV6_ADDR_SCOPE_GLOBAL; -} - -int -in6_addr2scopeid(ifp, addr) - struct ifnet *ifp; /* must not be NULL */ - struct in6_addr *addr; /* must not be NULL */ -{ - int scope = in6_addrscope(addr); - - switch(scope) { - case IPV6_ADDR_SCOPE_NODELOCAL: - return(-1); /* XXX: is this an appropriate value? */ - - case IPV6_ADDR_SCOPE_LINKLOCAL: - /* XXX: we do not distinguish between a link and an I/F. */ - return(ifp->if_index); - - case IPV6_ADDR_SCOPE_SITELOCAL: - return(0); /* XXX: invalid. */ - - default: - return(0); /* XXX: treat as global. */ - } + return(0); /* false */ } /* * return length of part which dst and src are equal * hard coding... */ - int in6_matchlen(src, dst) struct in6_addr *src, *dst; @@ -2022,6 +1968,7 @@ struct in6_addr *src, *dst; return match; } +/* XXX: to be scope conscious */ int in6_are_prefix_equal(p1, p2, len) struct in6_addr *p1, *p2; @@ -2077,8 +2024,8 @@ in6_prefixlen2mask(maskp, len) */ struct in6_ifaddr * in6_ifawithscope(oifp, dst) - register struct ifnet *oifp; - register struct in6_addr *dst; + struct ifnet *oifp; + struct in6_addr *dst; { int dst_scope = in6_addrscope(dst), src_scope, best_scope = 0; int blen = -1; @@ -2087,7 +2034,9 @@ in6_ifawithscope(oifp, dst) struct in6_ifaddr *ifa_best = NULL; if (oifp == NULL) { +#if 0 printf("in6_ifawithscope: output interface is not specified\n"); +#endif return(NULL); } @@ -2096,11 +2045,7 @@ in6_ifawithscope(oifp, dst) * Comparing an interface with the outgoing interface will be done * only at the final stage of tiebreaking. */ -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (ifp = ifnet; ifp; ifp = ifp->if_next) -#else for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) -#endif { /* * We can never take an address that breaks the scope zone @@ -2109,14 +2054,7 @@ in6_ifawithscope(oifp, dst) if (in6_addr2scopeid(ifp, dst) != in6_addr2scopeid(oifp, dst)) continue; -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) -#elif defined(__FreeBSD__) && __FreeBSD__ >= 4 TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) -#else - for (ifa = ifp->if_addrlist.tqh_first; ifa; - ifa = ifa->ifa_list.tqe_next) -#endif { int tlen = -1, dscopecmp, bscopecmp, matchcmp; @@ -2125,20 +2063,6 @@ in6_ifawithscope(oifp, dst) src_scope = in6_addrscope(IFA_IN6(ifa)); -#if ADDRSELECT_DEBUG /* should be removed after stabilization */ - dscopecmp = IN6_ARE_SCOPE_CMP(src_scope, dst_scope); - printf("in6_ifawithscope: dst=%s bestaddr=%s, " - "newaddr=%s, scope=%x, dcmp=%d, bcmp=%d, " - "matchlen=%d, flgs=%x\n", - ip6_sprintf(dst), - ifa_best ? ip6_sprintf(&ifa_best->ia_addr.sin6_addr) : "none", - ip6_sprintf(IFA_IN6(ifa)), src_scope, - dscopecmp, - ifa_best ? IN6_ARE_SCOPE_CMP(src_scope, best_scope) : -1, - in6_matchlen(IFA_IN6(ifa), dst), - ((struct in6_ifaddr *)ifa)->ia6_flags); -#endif - /* * Don't use an address before completing DAD * nor a duplicated address. @@ -2175,13 +2099,20 @@ in6_ifawithscope(oifp, dst) * Also, if the current address has a smaller scope * than dst, ignore it unless ifa_best also has a * smaller scope. + * Consequently, after the two if-clause below, + * the followings must be satisfied: + * (scope(src) < scope(dst) && + * scope(best) < scope(dst)) + * OR + * (scope(best) >= scope(dst) && + * scope(src) >= scope(dst)) */ if (IN6_ARE_SCOPE_CMP(best_scope, dst_scope) < 0 && IN6_ARE_SCOPE_CMP(src_scope, dst_scope) >= 0) - goto replace; + goto replace; /* (A) */ if (IN6_ARE_SCOPE_CMP(src_scope, dst_scope) < 0 && IN6_ARE_SCOPE_CMP(best_scope, dst_scope) >= 0) - continue; + continue; /* (B) */ /* * A deprecated address SHOULD NOT be used in new @@ -2210,13 +2141,45 @@ in6_ifawithscope(oifp, dst) /* * A non-deprecated address is always preferred * to a deprecated one regardless of scopes and - * address matching. + * address matching (Note invariants ensured by the + * conditions (A) and (B) above.) */ if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED) && (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) == 0) goto replace; + /* + * When we use temporary addresses described in + * RFC 3041, we prefer temporary addresses to + * public autoconf addresses. Again, note the + * invariants from (A) and (B). Also note that we + * don't have any preference between static addresses + * and autoconf addresses (despite of whether or not + * the latter is temporary or public.) + */ + if (ip6_use_tempaddr) { + struct in6_ifaddr *ifat; + + ifat = (struct in6_ifaddr *)ifa; + if ((ifa_best->ia6_flags & + (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY)) + == IN6_IFF_AUTOCONF && + (ifat->ia6_flags & + (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY)) + == (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY)) { + goto replace; + } + if ((ifa_best->ia6_flags & + (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY)) + == (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY) && + (ifat->ia6_flags & + (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY)) + == IN6_IFF_AUTOCONF) { + continue; + } + } + /* * At this point, we have two cases: * 1. we are looking at a non-deprecated address, @@ -2243,64 +2206,68 @@ in6_ifawithscope(oifp, dst) * Smaller scopes are the last resort. * - A deprecated address is chosen only when we have * no address that has an enough scope, but is - * prefered to any addresses of smaller scopes. - * - Longest address match against dst is considered - * only for addresses that has the same scope of dst. + * prefered to any addresses of smaller scopes + * (this must be already done above.) + * - addresses on the outgoing I/F are preferred to + * ones on other interfaces if none of above + * tiebreaks. In the table below, the column "bI" + * means if the best_ifa is on the outgoing + * interface, and the column "sI" means if the ifa + * is on the outgoing interface. * - If there is no other reasons to choose one, - * addresses on the outgoing I/F are preferred. + * longest address match against dst is considered. * * The precise decision table is as follows: - * dscopecmp bscopecmp matchcmp outI/F | replace? - * !equal equal N/A Yes | Yes (1) - * !equal equal N/A No | No (2) - * larger larger N/A N/A | No (3) - * larger smaller N/A N/A | Yes (4) - * smaller larger N/A N/A | Yes (5) - * smaller smaller N/A N/A | No (6) - * equal smaller N/A N/A | Yes (7) - * equal larger (already done) - * equal equal larger N/A | Yes (8) - * equal equal smaller N/A | No (9) - * equal equal equal Yes | Yes (a) - * eaual eqaul equal No | No (b) + * dscopecmp bscopecmp match bI oI | replace? + * N/A equal N/A Y N | No (1) + * N/A equal N/A N Y | Yes (2) + * N/A equal larger N/A | Yes (3) + * N/A equal !larger N/A | No (4) + * larger larger N/A N/A | No (5) + * larger smaller N/A N/A | Yes (6) + * smaller larger N/A N/A | Yes (7) + * smaller smaller N/A N/A | No (8) + * equal smaller N/A N/A | Yes (9) + * equal larger (already done at A above) */ dscopecmp = IN6_ARE_SCOPE_CMP(src_scope, dst_scope); bscopecmp = IN6_ARE_SCOPE_CMP(src_scope, best_scope); - if (dscopecmp && bscopecmp == 0) { - if (oifp == ifp) /* (1) */ + if (bscopecmp == 0) { + struct ifnet *bifp = ifa_best->ia_ifp; + + if (bifp == oifp && ifp != oifp) /* (1) */ + continue; + if (bifp != oifp && ifp == oifp) /* (2) */ + goto replace; + + /* + * Both bifp and ifp are on the outgoing + * interface, or both two are on a different + * interface from the outgoing I/F. + * now we need address matching against dst + * for tiebreaking. + */ + tlen = in6_matchlen(IFA_IN6(ifa), dst); + matchcmp = tlen - blen; + if (matchcmp > 0) /* (3) */ goto replace; - continue; /* (2) */ + continue; /* (4) */ } if (dscopecmp > 0) { - if (bscopecmp > 0) /* (3) */ + if (bscopecmp > 0) /* (5) */ continue; - goto replace; /* (4) */ + goto replace; /* (6) */ } if (dscopecmp < 0) { - if (bscopecmp > 0) /* (5) */ + if (bscopecmp > 0) /* (7) */ goto replace; - continue; /* (6) */ + continue; /* (8) */ } /* now dscopecmp must be 0 */ if (bscopecmp < 0) - goto replace; /* (7) */ - - /* - * At last both dscopecmp and bscopecmp must be 0. - * We need address matching against dst for - * tiebreaking. - */ - tlen = in6_matchlen(IFA_IN6(ifa), dst); - matchcmp = tlen - blen; - if (matchcmp > 0) /* (8) */ - goto replace; - if (matchcmp < 0) /* (9) */ - continue; - if (oifp == ifp) /* (a) */ - goto replace; - continue; /* (b) */ + goto replace; /* (9) */ replace: ifa_best = (struct in6_ifaddr *)ifa; @@ -2335,11 +2302,10 @@ in6_ifawithscope(oifp, dst) * return the best address out of the same scope. if no address was * found, return the first valid address from designated IF. */ - struct in6_ifaddr * in6_ifawithifp(ifp, dst) - register struct ifnet *ifp; - register struct in6_addr *dst; + struct ifnet *ifp; + struct in6_addr *dst; { int dst_scope = in6_addrscope(dst), blen = -1, tlen; struct ifaddr *ifa; @@ -2348,45 +2314,13 @@ in6_ifawithifp(ifp, dst) dep[0] = dep[1] = NULL; -#if 0 -#if MIP6 - /* - * This is needed to assure that the Home Address is used for - * outgoing packets when not at home. We can't choose any other - * address if we want to keep connections up during movement. - */ - if (mip6_get_home_prefix_hook) { /* Only Mobile Node */ - struct nd_prefix *pr; - if ((pr = (*mip6_get_home_prefix_hook)()) && - !IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) - { - if (dst_scope == in6_addrscope(&pr->ndpr_addr)) { -#if MIP6_DEBUG - /* Noisy but useful */ - mip6_debug("%s: Local address %s is chosen " - "for pcb to dest %s.\n", - __FUNCTION__, - ip6_sprintf(&pr->ndpr_addr), - ip6_sprintf(dst)); -#endif - return(in6ifa_ifpwithaddr(ifp, &pr->ndpr_addr)); - } - } - } -#endif /* MIP6 */ -#endif /* 0 */ - /* * We first look for addresses in the same scope. * If there is one, return it. * If two or more, return one which matches the dst longest. * If none, return one of global addresses assigned other ifs. */ -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) -#else - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) -#endif + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; @@ -2421,11 +2355,7 @@ in6_ifawithifp(ifp, dst) if (besta) return(besta); -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) -#else - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) -#endif + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; @@ -2453,6 +2383,8 @@ in6_ifawithifp(ifp, dst) return NULL; } +extern int in6_init2done; + /* * perform DAD when interface becomes IFF_UP. */ @@ -2462,92 +2394,61 @@ in6_if_up(ifp) { struct ifaddr *ifa; struct in6_ifaddr *ia; - struct sockaddr_dl *sdl; - int type; -#if __bsdi__ - u_char ea[ETHER_ADDR_LEN]; -#else - struct ether_addr ea; -#endif - int off; int dad_delay; /* delay ticks before DAD output */ - bzero(&ea, sizeof(ea)); - sdl = NULL; + if (!in6_init2done) + return; -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) -#else - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) -#endif + /* + * special cases, like 6to4, are handled in in6_ifattach + */ + in6_ifattach(ifp, NULL); + + dad_delay = 0; + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { - if (ifa->ifa_addr->sa_family == AF_INET6 - && IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr)) { - goto dad; - } - if (ifa->ifa_addr->sa_family != AF_LINK) + if (ifa->ifa_addr->sa_family != AF_INET6) continue; - sdl = (struct sockaddr_dl *)ifa->ifa_addr; - break; + ia = (struct in6_ifaddr *)ifa; + if (ia->ia6_flags & IN6_IFF_TENTATIVE) + nd6_dad_start(ifa, &dad_delay); } +} + +int +in6if_do_dad(ifp) + struct ifnet *ifp; +{ + if ((ifp->if_flags & IFF_LOOPBACK) != 0) + return(0); switch (ifp->if_type) { - case IFT_LOOP: - in6_ifattach(ifp, IN6_IFT_LOOP, NULL, 1); - break; - case IFT_SLIP: - case IFT_PPP: +#if IFT_DUMMY case IFT_DUMMY: - case IFT_GIF: +#endif case IFT_FAITH: - type = IN6_IFT_P2P; - in6_ifattach(ifp, type, 0, 1); - break; -#if IFT_STF - case IFT_STF: /* - * This is VERY awkward to call nd6_ifattach while we will - * not do ND at all on the interface. It is necessary for - * initializing default hoplimit, and ND mtu. + * These interfaces do not have the IFF_LOOPBACK flag, + * but loop packets back. We do not have to do DAD on such + * interfaces. We should even omit it, because loop-backed + * NS would confuse the DAD procedure. */ - nd6_ifattach(ifp); - break; -#endif - case IFT_ETHER: - case IFT_FDDI: - case IFT_ATM: - type = IN6_IFT_802; - if (sdl == NULL) - break; - off = sdl->sdl_nlen; - if (bcmp(&sdl->sdl_data[off], &ea, sizeof(ea)) != 0) - in6_ifattach(ifp, type, LLADDR(sdl), 0); - break; - case IFT_ARCNET: - type = IN6_IFT_ARCNET; - if (sdl == NULL) - break; - off = sdl->sdl_nlen; - if (sdl->sdl_data[off] != 0) /* XXX ?: */ - in6_ifattach(ifp, type, LLADDR(sdl), 0); - break; + return(0); default: - break; - } + /* + * Our DAD routine requires the interface up and running. + * However, some interfaces can be up before the RUNNING + * status. Additionaly, users may try to assign addresses + * before the interface becomes up (or running). + * We simply skip DAD in such a case as a work around. + * XXX: we should rather mark "tentative" on such addresses, + * and do DAD after the interface becomes ready. + */ + if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != + (IFF_UP|IFF_RUNNING)) + return(0); -dad: - dad_delay = 0; -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) -#else - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) -#endif - { - if (ifa->ifa_addr->sa_family != AF_INET6) - continue; - ia = (struct in6_ifaddr *)ifa; - if (ia->ia6_flags & IN6_IFF_TENTATIVE) - nd6_dad_start(ifa, &dad_delay); + return(1); } } @@ -2561,11 +2462,7 @@ in6_setmaxmtu() unsigned long maxmtu = 0; struct ifnet *ifp; -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (ifp = ifnet; ifp; ifp = ifp->if_next) -#else for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) -#endif { if ((ifp->if_flags & IFF_LOOPBACK) == 0 && nd_ifinfo[ifp->if_index].linkmtu > maxmtu) @@ -2575,8 +2472,7 @@ in6_setmaxmtu() in6_maxmtu = maxmtu; } -#if MAPPED_ADDR_ENABLED -/* +/* * Convert sockaddr_in6 to sockaddr_in. Original sockaddr_in6 must be * v4 mapped addr or v4 compat addr */ @@ -2634,5 +2530,36 @@ in6_sin_2_v4mapsin6_in_sock(struct sockaddr **nam) FREE(*nam, M_SONAME); *nam = (struct sockaddr *)sin6_p; } -#endif /* MAPPED_ADDR_ENABLED */ +/* Posts in6_event_data message kernel events */ +void +in6_post_msg(struct ifnet *ifp, u_long event_code, struct in6_ifaddr *ifa) +{ + struct kev_msg ev_msg; + struct kev_in6_data in6_event_data; + + ev_msg.vendor_code = KEV_VENDOR_APPLE; + ev_msg.kev_class = KEV_NETWORK_CLASS; + ev_msg.kev_subclass = KEV_INET6_SUBCLASS; + ev_msg.event_code = event_code; + + in6_event_data.ia_addr = ifa->ia_addr; + in6_event_data.ia_net = ifa->ia_net; + in6_event_data.ia_dstaddr = ifa->ia_dstaddr; + in6_event_data.ia_prefixmask = ifa->ia_prefixmask; + in6_event_data.ia_plen = ifa->ia_plen; + in6_event_data.ia6_flags = (u_int32_t)ifa->ia6_flags; + in6_event_data.ia_lifetime = ifa->ia6_lifetime; + + if (ifp != NULL) { + strncpy(&in6_event_data.link_data.if_name[0], ifp->if_name, IFNAMSIZ); + in6_event_data.link_data.if_family = ifp->if_family; + in6_event_data.link_data.if_unit = (unsigned long) ifp->if_unit; + } + + ev_msg.dv[0].data_ptr = &in6_event_data; + ev_msg.dv[0].data_length = sizeof(struct kev_in6_data); + ev_msg.dv[1].data_length = 0; + + kev_post_msg(&ev_msg); +} diff --git a/bsd/netinet6/in6.h b/bsd/netinet6/in6.h index 7c7a745fc..64356fa23 100644 --- a/bsd/netinet6/in6.h +++ b/bsd/netinet6/in6.h @@ -1,4 +1,5 @@ -/* $KAME: in6.h,v 1.40 2000/03/25 07:23:42 sumikawa Exp $ */ +/* $FreeBSD: src/sys/netinet6/in6.h,v 1.7.2.4 2001/07/04 09:45:23 ume Exp $ */ +/* $KAME: in6.h,v 1.89 2001/05/27 13:28:35 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -65,21 +66,20 @@ */ #ifndef __KAME_NETINET_IN_H_INCLUDED_ -#error "do not include netinet6/in6.h directly, include netinet/in.h" +#error "do not include netinet6/in6.h directly, include netinet/in.h. see RFC2553" #endif #ifndef _NETINET6_IN6_H_ #define _NETINET6_IN6_H_ - -#if !defined(_XOPEN_SOURCE) -#include -#endif +#include /* * Identification of the network protocol stack + * for *BSD-current/release: http://www.kame.net/dev/cvsweb.cgi/kame/COVERAGE + * has the table of implementation/integration differences. */ #define __KAME__ -#define __KAME_VERSION "STABLE 20000425" +#define __KAME_VERSION "20010528/apple-darwin" /* * Local port number conventions: @@ -90,7 +90,7 @@ * When a user does a bind(2) or connect(2) with a port number of zero, * a non-conflicting local port address is chosen. * - * The default range is IPPORT_ANONMIX to IPPORT_ANONMAX, although + * The default range is IPPORT_ANONMIN to IPPORT_ANONMAX, although * that is settable by sysctl(3); net.inet.ip.anonportmin and * net.inet.ip.anonportmax respectively. * @@ -147,7 +147,7 @@ struct sockaddr_in6 { u_int16_t sin6_port; /* Transport layer port # (in_port_t)*/ u_int32_t sin6_flowinfo; /* IP6 flow information */ struct in6_addr sin6_addr; /* IP6 address */ - u_int32_t sin6_scope_id; /* intface scope id */ + u_int32_t sin6_scope_id; /* scope zone index */ }; /* @@ -166,6 +166,8 @@ struct sockaddr_in6 { #endif #ifdef KERNEL +extern const struct sockaddr_in6 sa6_any; + extern const struct in6_addr in6mask0; extern const struct in6_addr in6mask32; extern const struct in6_addr in6mask64; @@ -217,13 +219,11 @@ extern const struct in6_addr in6mask128; {{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }}} -#ifdef KERNEL extern const struct in6_addr in6addr_any; extern const struct in6_addr in6addr_loopback; extern const struct in6_addr in6addr_nodelocal_allnodes; extern const struct in6_addr in6addr_linklocal_allnodes; extern const struct in6_addr in6addr_linklocal_allrouters; -#endif /* * Equality @@ -233,47 +233,55 @@ extern const struct in6_addr in6addr_linklocal_allrouters; */ #ifdef KERNEL #define IN6_ARE_ADDR_EQUAL(a, b) \ - (bcmp((a), (b), sizeof(struct in6_addr)) == 0) + (bcmp(&(a)->s6_addr[0], &(b)->s6_addr[0], sizeof(struct in6_addr)) == 0) #else #define IN6_ARE_ADDR_EQUAL(a, b) \ - (memcmp((a), (b), sizeof(struct in6_addr)) == 0) + (memcmp(&(a)->s6_addr[0], &(b)->s6_addr[0], sizeof(struct in6_addr)) == 0) +#endif + +#ifdef KERNEL /* non standard */ +/* see if two addresses are equal in a scope-conscious manner. */ +#define SA6_ARE_ADDR_EQUAL(a, b) \ + (((a)->sin6_scope_id == 0 || (b)->sin6_scope_id == 0 || \ + ((a)->sin6_scope_id == (b)->sin6_scope_id)) && \ + (bcmp(&(a)->sin6_addr, &(b)->sin6_addr, sizeof(struct in6_addr)) == 0)) #endif /* * Unspecified */ #define IN6_IS_ADDR_UNSPECIFIED(a) \ - ((*(u_int32_t *)(&(a)->s6_addr[0]) == 0) && \ - (*(u_int32_t *)(&(a)->s6_addr[4]) == 0) && \ - (*(u_int32_t *)(&(a)->s6_addr[8]) == 0) && \ - (*(u_int32_t *)(&(a)->s6_addr[12]) == 0)) + ((*(const u_int32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \ + (*(const u_int32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \ + (*(const u_int32_t *)(const void *)(&(a)->s6_addr[8]) == 0) && \ + (*(const u_int32_t *)(const void *)(&(a)->s6_addr[12]) == 0)) /* * Loopback */ #define IN6_IS_ADDR_LOOPBACK(a) \ - ((*(u_int32_t *)(&(a)->s6_addr[0]) == 0) && \ - (*(u_int32_t *)(&(a)->s6_addr[4]) == 0) && \ - (*(u_int32_t *)(&(a)->s6_addr[8]) == 0) && \ - (*(u_int32_t *)(&(a)->s6_addr[12]) == ntohl(1))) + ((*(const u_int32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \ + (*(const u_int32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \ + (*(const u_int32_t *)(const void *)(&(a)->s6_addr[8]) == 0) && \ + (*(const u_int32_t *)(const void *)(&(a)->s6_addr[12]) == ntohl(1))) /* * IPv4 compatible */ #define IN6_IS_ADDR_V4COMPAT(a) \ - ((*(u_int32_t *)(&(a)->s6_addr[0]) == 0) && \ - (*(u_int32_t *)(&(a)->s6_addr[4]) == 0) && \ - (*(u_int32_t *)(&(a)->s6_addr[8]) == 0) && \ - (*(u_int32_t *)(&(a)->s6_addr[12]) != 0) && \ - (*(u_int32_t *)(&(a)->s6_addr[12]) != ntohl(1))) + ((*(const u_int32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \ + (*(const u_int32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \ + (*(const u_int32_t *)(const void *)(&(a)->s6_addr[8]) == 0) && \ + (*(const u_int32_t *)(const void *)(&(a)->s6_addr[12]) != 0) && \ + (*(const u_int32_t *)(const void *)(&(a)->s6_addr[12]) != ntohl(1))) /* * Mapped */ #define IN6_IS_ADDR_V4MAPPED(a) \ - ((*(u_int32_t *)(&(a)->s6_addr[0]) == 0) && \ - (*(u_int32_t *)(&(a)->s6_addr[4]) == 0) && \ - (*(u_int32_t *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff))) + ((*(const u_int32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \ + (*(const u_int32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \ + (*(const u_int32_t *)(const void *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff))) /* * KAME Scope Values @@ -350,31 +358,33 @@ extern const struct in6_addr in6addr_linklocal_allrouters; (__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_GLOBAL)) #endif -/* - * Wildcard Socket - */ -#if 0 /*pre-RFC2553*/ -#define IN6_IS_ADDR_ANY(a) IN6_IS_ADDR_UNSPECIFIED(a) -#endif - +#ifdef KERNEL /*nonstandard*/ /* * KAME Scope */ -#ifdef KERNEL /*nonstandard*/ #define IN6_IS_SCOPE_LINKLOCAL(a) \ ((IN6_IS_ADDR_LINKLOCAL(a)) || \ (IN6_IS_ADDR_MC_LINKLOCAL(a))) -#endif + +#define IFA6_IS_DEPRECATED(a) \ + ((a)->ia6_lifetime.ia6t_preferred != 0 && \ + (a)->ia6_lifetime.ia6t_preferred < time_second) +#define IFA6_IS_INVALID(a) \ + ((a)->ia6_lifetime.ia6t_expire != 0 && \ + (a)->ia6_lifetime.ia6t_expire < time_second) +#endif /* _KERNEL */ /* * IP6 route structure */ +#ifdef __APPLE_API_PRIVATE #if !defined(_XOPEN_SOURCE) struct route_in6 { struct rtentry *ro_rt; struct sockaddr_in6 ro_dst; }; #endif +#endif /* __APPLE_API_PRIVATE */ /* * Options for use with [gs]etsockopt at the IPV6 level. @@ -397,16 +407,20 @@ struct route_in6 { #define IPV6_LEAVE_GROUP 13 /* ip6_mreq; leave a group membership */ #define IPV6_PORTRANGE 14 /* int; range to choose for unspec port */ #define ICMP6_FILTER 18 /* icmp6_filter; icmp6 filter */ -#define IPV6_PKTINFO 19 /* in6_pktinfo; send if, src addr */ -#define IPV6_HOPLIMIT 20 /* int; send hop limit */ -#define IPV6_NEXTHOP 21 /* sockaddr; next hop addr */ -#define IPV6_HOPOPTS 22 /* ip6_hbh; send hop-by-hop option */ -#define IPV6_DSTOPTS 23 /* ip6_dest; send dst option befor rthdr */ -#define IPV6_RTHDR 24 /* ip6_rthdr; send routing header */ +/* RFC2292 options */ +#define IPV6_PKTINFO 19 /* bool; send/recv if, src/dst addr */ +#define IPV6_HOPLIMIT 20 /* bool; hop limit */ +#define IPV6_NEXTHOP 21 /* bool; next hop addr */ +#define IPV6_HOPOPTS 22 /* bool; hop-by-hop option */ +#define IPV6_DSTOPTS 23 /* bool; destination option */ +#define IPV6_RTHDR 24 /* bool; routing header */ #define IPV6_PKTOPTIONS 25 /* buf/cmsghdr; set/get IPv6 options */ - /* obsoleted by 2292bis */ + #define IPV6_CHECKSUM 26 /* int; checksum offset for raw socket */ -#define IPV6_BINDV6ONLY 27 /* bool; only bind INET6 at null bind */ +#define IPV6_V6ONLY 27 /* bool; only bind INET6 at wildcard bind */ +#ifndef _KERNEL +#define IPV6_BINDV6ONLY IPV6_V6ONLY +#endif #if 1 /*IPSEC*/ #define IPV6_IPSEC_POLICY 28 /* struct; get/set security policy */ @@ -421,22 +435,7 @@ struct route_in6 { #define IPV6_FW_GET 34 /* get entire firewall rule chain */ #endif -/* new socket options introduced in RFC2292bis */ -#define IPV6_RTHDRDSTOPTS 35 /* ip6_dest; send dst option before rthdr */ - -#define IPV6_RECVPKTINFO 36 /* bool; recv if, dst addr */ -#define IPV6_RECVHOPLIMIT 37 /* bool; recv hop limit */ -#define IPV6_RECVRTHDR 38 /* bool; recv routing header */ -#define IPV6_RECVHOPOPTS 39 /* bool; recv hop-by-hop option */ -#define IPV6_RECVDSTOPTS 40 /* bool; recv dst option after rthdr */ -#define IPV6_RECVRTHDRDSTOPTS 41 /* bool; recv dst option before rthdr */ - -#define IPV6_USE_MIN_MTU 42 /* bool; send packets at the minimum MTU */ -#define IPV6_RECVPATHMTU 43 /* bool; notify an according MTU */ - -/* the followings are used as cmsg type only */ -#define IPV6_PATHMTU 44 /* 4 bytes int; MTU notification */ -#define IPV6_REACHCONF 45 /* no data; ND reachability confirm */ +/* to define items, should talk with KAME guys first, for *BSD compatibility */ #define IPV6_RTHDR_LOOSE 0 /* this hop need not be a neighbor. XXX old spec */ #define IPV6_RTHDR_STRICT 1 /* this hop must be a neighbor. XXX old spec */ @@ -453,15 +452,15 @@ struct route_in6 { */ struct ipv6_mreq { struct in6_addr ipv6mr_multiaddr; - u_int ipv6mr_interface; + unsigned int ipv6mr_interface; }; /* * IPV6_PKTINFO: Packet information(RFC2292 sec 5) */ struct in6_pktinfo { - struct in6_addr ipi6_addr; /* src/dst IPv6 address */ - u_int ipi6_ifindex; /* send/recv interface index */ + struct in6_addr ipi6_addr; /* src/dst IPv6 address */ + unsigned int ipi6_ifindex; /* send/recv interface index */ }; /* @@ -555,93 +554,39 @@ struct in6_pktinfo { #define IPV6CTL_KAME_VERSION 20 #define IPV6CTL_USE_DEPRECATED 21 /* use deprecated addr (RFC2462 5.5.4) */ #define IPV6CTL_RR_PRUNE 22 /* walk timer for router renumbering */ -#if MAPPED_ADDR_ENABLED +#if 0 /*obsolete*/ #define IPV6CTL_MAPPED_ADDR 23 -#endif /* MAPPED_ADDR_ENABLED */ -/* New entries should be added here from current IPV6CTL_MAXID value. */ -#define IPV6CTL_MAXID 24 - -#if MAPPED_ADDR_ENABLED -#define IPV6CTL_NAMES_MAPPED_ADDR "mapped_addr" -#define IPV6CTL_TYPE_MAPPED_ADDR CTLTYPE_INT -#define IPV6CTL_VARS_MAPPED_ADDR &ip6_mapped_addr_on -#else /* MAPPED_ADDR_ENABLED */ -#define IPV6CTL_NAMES_MAPPED_ADDR 0 -#define IPV6CTL_TYPE_MAPPED_ADDR 0 -#define IPV6CTL_VARS_MAPPED_ADDR 0 -#endif /* MAPPED_ADDR_ENABLED */ - -#if IPV6CTL_BINDV6ONLY -#define IPV6CTL_NAMES_BINDV6ONLY "bindv6only" -#define IPV6CTL_TYPE_BINDV6ONLY CTLTYPE_INT -#define IPV6CTL_VARS_BINDV6ONLY &ip6_bindv6only -#else -#define IPV6CTL_NAMES_BINDV6ONLY 0 -#define IPV6CTL_TYPE_BINDV6ONLY 0 -#define IPV6CTL_VARS_BINDV6ONLY 0 #endif +#define IPV6CTL_V6ONLY 24 +#define IPV6CTL_RTEXPIRE 25 /* cloned route expiration time */ +#define IPV6CTL_RTMINEXPIRE 26 /* min value for expiration time */ +#define IPV6CTL_RTMAXCACHE 27 /* trigger level for dynamic expire */ -#define IPV6CTL_NAMES { \ - { 0, 0 }, \ - { "forwarding", CTLTYPE_INT }, \ - { "redirect", CTLTYPE_INT }, \ - { "hlim", CTLTYPE_INT }, \ - { "mtu", CTLTYPE_INT }, \ - { "forwsrcrt", CTLTYPE_INT }, \ - { 0, 0 }, \ - { 0, 0 }, \ - { "mrtproto", CTLTYPE_INT }, \ - { "maxfragpackets", CTLTYPE_INT }, \ - { "sourcecheck", CTLTYPE_INT }, \ - { "sourcecheck_logint", CTLTYPE_INT }, \ - { "accept_rtadv", CTLTYPE_INT }, \ - { "keepfaith", CTLTYPE_INT }, \ - { "log_interval", CTLTYPE_INT }, \ - { "hdrnestlimit", CTLTYPE_INT }, \ - { "dad_count", CTLTYPE_INT }, \ - { "auto_flowlabel", CTLTYPE_INT }, \ - { "defmcasthlim", CTLTYPE_INT }, \ - { "gifhlim", CTLTYPE_INT }, \ - { "kame_version", CTLTYPE_STRING }, \ - { "use_deprecated", CTLTYPE_INT }, \ - { "rr_prune", CTLTYPE_INT }, \ - { IPV6CTL_NAMES_MAPPED_ADDR, IPV6CTL_TYPE_MAPPED_ADDR }, \ - { IPV6CTL_NAMES_BINDV6ONLY, IPV6CTL_TYPE_BINDV6ONLY }, \ -} +#define IPV6CTL_USETEMPADDR 32 /* use temporary addresses (RFC3041) */ +#define IPV6CTL_TEMPPLTIME 33 /* preferred lifetime for tmpaddrs */ +#define IPV6CTL_TEMPVLTIME 34 /* valid lifetime for tmpaddrs */ +#define IPV6CTL_AUTO_LINKLOCAL 35 /* automatic link-local addr assign */ +#define IPV6CTL_RIP6STATS 36 /* raw_ip6 stats */ + +/* New entries should be added here from current IPV6CTL_MAXID value. */ +/* to define items, should talk with KAME guys first, for *BSD compatibility */ +#define IPV6CTL_MAXID 37 -#ifdef __bsdi__ -#define IPV6CTL_VARS { \ - 0, \ - &ip6_forwarding, \ - &ip6_sendredirects, \ - &ip6_defhlim, \ - 0, \ - &ip6_forward_srcrt, \ - 0, \ - 0, \ - 0, \ - &ip6_maxfragpackets, \ - &ip6_sourcecheck, \ - &ip6_sourcecheck_interval, \ - &ip6_accept_rtadv, \ - &ip6_keepfaith, \ - &ip6_log_interval, \ - &ip6_hdrnestlimit, \ - &ip6_dad_count, \ - &ip6_auto_flowlabel, \ - &ip6_defmcasthlim, \ - &ip6_gif_hlim, \ - 0, \ - &ip6_use_deprecated, \ - &ip6_rr_prune, \ - IPV6CTL_VARS_MAPPED_ADDR, \ - IPV6CTL_VARS_BINDV6ONLY, \ -} -#endif #endif /* !_XOPEN_SOURCE */ +/* + * Redefinition of mbuf flags + */ +#define M_AUTHIPHDR M_PROTO2 +#define M_DECRYPTED M_PROTO3 +#define M_LOOP M_PROTO4 +#define M_AUTHIPDGM M_PROTO5 + #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE struct cmsghdr; +struct mbuf; +struct ifnet; int in6_cksum __P((struct mbuf *, u_int8_t, u_int32_t, u_int32_t)); int in6_localaddr __P((struct in6_addr *)); @@ -649,7 +594,6 @@ int in6_addrscope __P((struct in6_addr *)); struct in6_ifaddr *in6_ifawithscope __P((struct ifnet *, struct in6_addr *)); struct in6_ifaddr *in6_ifawithifp __P((struct ifnet *, struct in6_addr *)); extern void in6_if_up __P((struct ifnet *)); -#if MAPPED_ADDR_ENABLED struct sockaddr; void in6_sin6_2_sin __P((struct sockaddr_in *sin, @@ -658,11 +602,11 @@ void in6_sin_2_v4mapsin6 __P((struct sockaddr_in *sin, struct sockaddr_in6 *sin6)); void in6_sin6_2_sin_in_sock __P((struct sockaddr *nam)); void in6_sin_2_v4mapsin6_in_sock __P((struct sockaddr **nam)); -#endif /* MAPPED_ADDR_ENABLED */ #define satosin6(sa) ((struct sockaddr_in6 *)(sa)) #define sin6tosa(sin6) ((struct sockaddr *)(sin6)) #define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa)) +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ __BEGIN_DECLS diff --git a/bsd/netinet6/in6_cksum.c b/bsd/netinet6/in6_cksum.c index 21aea718b..60cdf2e5b 100644 --- a/bsd/netinet6/in6_cksum.c +++ b/bsd/netinet6/in6_cksum.c @@ -1,4 +1,5 @@ -/* $KAME: in6_cksum.c,v 1.5 2000/02/22 14:04:17 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/in6_cksum.c,v 1.1.2.3 2001/07/03 11:01:52 ume Exp $ */ +/* $KAME: in6_cksum.c,v 1.10 2000/12/03 00:53:59 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -82,15 +83,6 @@ #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);} -static union { - u_int16_t phs[4]; - struct { - u_int32_t ph_len; - u_int8_t ph_zero[3]; - u_int8_t ph_nxt; - } ph; -} uph; - /* * m MUST contain a continuous IP6 header. * off is a offset where TCP/UDP/ICMP6 header starts. @@ -100,19 +92,26 @@ static union { int in6_cksum(m, nxt, off, len) - register struct mbuf *m; + struct mbuf *m; u_int8_t nxt; u_int32_t off, len; { - register u_int16_t *w; - register int sum = 0; - register int mlen = 0; + u_int16_t *w; + int sum = 0; + int mlen = 0; int byte_swapped = 0; #if 0 int srcifid = 0, dstifid = 0; #endif struct ip6_hdr *ip6; - + union { + u_int16_t phs[4]; + struct { + u_int32_t ph_len; + u_int8_t ph_zero[3]; + u_int8_t ph_nxt; + } ph __attribute__((__packed__)); + } uph; union { u_int8_t c[2]; u_int16_t s; @@ -128,6 +127,8 @@ in6_cksum(m, nxt, off, len) m->m_pkthdr.len, off, len); } + bzero(&uph, sizeof(uph)); + /* * First create IP6 pseudo header and calculate a summary. */ diff --git a/bsd/netinet6/in6_gif.c b/bsd/netinet6/in6_gif.c index c756948dc..8d963768c 100644 --- a/bsd/netinet6/in6_gif.c +++ b/bsd/netinet6/in6_gif.c @@ -1,4 +1,5 @@ -/* $KAME: in6_gif.c,v 1.27 2000/03/25 07:23:43 sumikawa Exp $ */ +/* $FreeBSD: src/sys/netinet6/in6_gif.c,v 1.2.2.3 2001/07/03 11:01:52 ume Exp $ */ +/* $KAME: in6_gif.c,v 1.49 2001/05/14 14:02:17 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -29,13 +30,6 @@ * SUCH DAMAGE. */ -/* - * in6_gif.c - */ - -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -#include "opt_inet.h" -#endif #include #include @@ -43,9 +37,9 @@ #include #include #include -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 -#include -#endif +#include +#include + #include #include @@ -63,18 +57,16 @@ #include #include #include -#include #endif #include +#if INET6 +#include +#endif #include #include -#if INET6 -extern struct ip6protosw in6_gif_protosw; -#endif - int in6_gif_output(ifp, family, m, rt) struct ifnet *ifp; @@ -155,34 +147,19 @@ in6_gif_output(ifp, family, m, rt) ip6->ip6_nxt = proto; ip6->ip6_hlim = ip6_gif_hlim; ip6->ip6_src = sin6_src->sin6_addr; - if (ifp->if_flags & IFF_LINK0) { - /* multi-destination mode */ - if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr)) - ip6->ip6_dst = sin6_dst->sin6_addr; - else if (rt) { - if (family != AF_INET6) { - m_freem(m); - return EINVAL; /*XXX*/ - } - ip6->ip6_dst = ((struct sockaddr_in6 *)(rt->rt_gateway))->sin6_addr; - } else { - m_freem(m); - return ENETUNREACH; - } - } else { - /* bidirectional configured tunnel mode */ - if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr)) - ip6->ip6_dst = sin6_dst->sin6_addr; - else { - m_freem(m); - return ENETUNREACH; - } + /* bidirectional configured tunnel mode */ + if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr)) + ip6->ip6_dst = sin6_dst->sin6_addr; + else { + m_freem(m); + return ENETUNREACH; } - if (ifp->if_flags & IFF_LINK1) { - otos = 0; + if (ifp->if_flags & IFF_LINK1) ip_ecn_ingress(ECN_ALLOWED, &otos, &itos); - ip6->ip6_flow |= htonl((u_int32_t)otos << 20); - } + else + ip_ecn_ingress(ECN_NOCARE, &otos, &itos); + ip6->ip6_flow &= ~ntohl(0xff00000); + ip6->ip6_flow |= htonl((u_int32_t)otos << 20); if (dst->sin6_family != sin6_dst->sin6_family || !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr)) { @@ -192,7 +169,7 @@ in6_gif_output(ifp, family, m, rt) dst->sin6_len = sizeof(struct sockaddr_in6); dst->sin6_addr = sin6_dst->sin6_addr; if (sc->gif_ro6.ro_rt) { - RTFREE(sc->gif_ro6.ro_rt); + rtfree(sc->gif_ro6.ro_rt); sc->gif_ro6.ro_rt = NULL; } #if 0 @@ -206,72 +183,52 @@ in6_gif_output(ifp, family, m, rt) m_freem(m); return ENETUNREACH; } + + /* if it constitutes infinite encapsulation, punt. */ + if (sc->gif_ro.ro_rt->rt_ifp == ifp) { + m_freem(m); + return ENETUNREACH; /*XXX*/ + } #if 0 ifp->if_mtu = sc->gif_ro6.ro_rt->rt_ifp->if_mtu - sizeof(struct ip6_hdr); #endif } +#if IPV6_MINMTU + /* + * force fragmentation to minimum MTU, to avoid path MTU discovery. + * it is too painful to ask for resend of inner packet, to achieve + * path MTU discovery for encapsulated packets. + */ + return(ip6_output(m, 0, &sc->gif_ro6, IPV6_MINMTU, 0, NULL)); +#else return(ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL)); +#endif } -int in6_gif_input(mp, offp, proto) +int in6_gif_input(mp, offp) struct mbuf **mp; - int *offp, proto; + int *offp; { struct mbuf *m = *mp; -#if 0 - struct gif_softc *sc; -#endif struct ifnet *gifp = NULL; struct ip6_hdr *ip6; -#if 0 - int i; -#endif int af = 0; u_int32_t otos; + u_int8_t proto; ip6 = mtod(m, struct ip6_hdr *); -#if 0 -#define satoin6(sa) (((struct sockaddr_in6 *)(sa))->sin6_addr) - for (i = 0, sc = gif; i < ngif; i++, sc++) { - if (sc->gif_psrc == NULL || - sc->gif_pdst == NULL || - sc->gif_psrc->sa_family != AF_INET6 || - sc->gif_pdst->sa_family != AF_INET6) { - continue; - } - if ((sc->gif_if.if_flags & IFF_UP) == 0) - continue; - if ((sc->gif_if.if_flags & IFF_LINK0) && - IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_psrc), &ip6->ip6_dst) && - IN6_IS_ADDR_UNSPECIFIED(&satoin6(sc->gif_pdst))) { - gifp = &sc->gif_if; - continue; - } - if (IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_psrc), &ip6->ip6_dst) && - IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_pdst), &ip6->ip6_src)) { - gifp = &sc->gif_if; - break; - } - } -#else gifp = (struct ifnet *)encap_getarg(m); -#endif - if (gifp == NULL) { - m_freem(m); - ip6stat.ip6s_nogif++; - return IPPROTO_DONE; - } - - if ((gifp->if_flags & IFF_UP) == 0) { + if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) { m_freem(m); ip6stat.ip6s_nogif++; return IPPROTO_DONE; } + proto = ip6->ip6_nxt; otos = ip6->ip6_flow; m_adj(m, *offp); @@ -291,6 +248,8 @@ int in6_gif_input(mp, offp, proto) ip = mtod(m, struct ip *); if (gifp->if_flags & IFF_LINK1) ip_ecn_egress(ECN_ALLOWED, &otos8, &ip->ip_tos); + else + ip_ecn_egress(ECN_NOCARE, &otos8, &ip->ip_tos); break; } #endif /* INET */ @@ -307,6 +266,8 @@ int in6_gif_input(mp, offp, proto) ip6 = mtod(m, struct ip6_hdr *); if (gifp->if_flags & IFF_LINK1) ip6_ecn_egress(ECN_ALLOWED, &otos, &ip6->ip6_flow); + else + ip6_ecn_egress(ECN_NOCARE, &otos, &ip6->ip6_flow); break; } #endif @@ -316,144 +277,69 @@ int in6_gif_input(mp, offp, proto) return IPPROTO_DONE; } - gif_input(m, af, gifp); + dlil_input(gifp, m, m); return IPPROTO_DONE; } +/* + * we know that we are in IFF_UP, outer address available, and outer family + * matched the physical addr family. see gif_encapcheck(). + */ int -in6_gif_ioctl(ifp, cmd, data) - struct ifnet *ifp; -#if defined(__FreeBSD__) && __FreeBSD__ < 3 - int cmd; -#else - u_long cmd; -#endif - caddr_t data; +gif_encapcheck6(m, off, proto, arg) + const struct mbuf *m; + int off; + int proto; + void *arg; { - struct gif_softc *sc = (struct gif_softc*)ifp; - struct ifreq *ifr = (struct ifreq*)data; - int error = 0, size; - struct sockaddr *sa, *dst, *src; - const struct encaptab *p; - struct sockaddr_in6 smask6, dmask6; - - switch (cmd) { - case SIOCSIFFLAGS: - /* - * whenever we change our idea about multi-destination mode - * we need to update encap attachment. - */ - if (((ifp->if_flags ^ sc->gif_oflags) & IFF_LINK0) == 0) - break; - if (sc->gif_psrc == NULL || sc->gif_pdst == NULL || - sc->gif_psrc->sa_family != sc->gif_pdst->sa_family) - break; - bzero(&smask6, sizeof(smask6)); - smask6.sin6_addr.s6_addr32[0] = ~0; - smask6.sin6_addr.s6_addr32[1] = ~0; - smask6.sin6_addr.s6_addr32[2] = ~0; - smask6.sin6_addr.s6_addr32[3] = ~0; -#if 0 /* we'll need to do this soon */ - smask6.sin6_scope_id = ~0; -#endif - dmask6 = smask6; - if ((ifp->if_flags & IFF_LINK0) == 0 && - IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)dst)->sin6_addr)) { - bzero(&dmask6, sizeof(dmask6)); -#if 0 /* we'll need to do this soon */ - dmask6.sin6_scope_id = ~0; -#endif - } - p = encap_attach(sc->gif_psrc->sa_family, -1, sc->gif_psrc, - (struct sockaddr *)&smask6, sc->gif_pdst, - (struct sockaddr *)&dmask6, - (struct protosw *)&in6_gif_protosw, &sc->gif_if); - if (p == NULL) { - error = EINVAL; - goto bad; - } - if (sc->encap_cookie != NULL) - (void)encap_detach(sc->encap_cookie); - sc->encap_cookie = p; - sc->gif_oflags = ifp->if_flags; - - break; - -#if INET6 - case SIOCSIFPHYADDR_IN6: -#endif - switch (ifr->ifr_addr.sa_family) { -#if INET6 - case AF_INET6: - src = (struct sockaddr *) - &(((struct in6_aliasreq *)data)->ifra_addr); - dst = (struct sockaddr *) - &(((struct in6_aliasreq *)data)->ifra_dstaddr); - - bzero(&smask6, sizeof(smask6)); - smask6.sin6_addr.s6_addr32[0] = ~0; - smask6.sin6_addr.s6_addr32[1] = ~0; - smask6.sin6_addr.s6_addr32[2] = ~0; - smask6.sin6_addr.s6_addr32[3] = ~0; -#if 0 /* we'll need to do this soon */ - smask6.sin6_scope_id = ~0; -#endif - dmask6 = smask6; - if ((ifp->if_flags & IFF_LINK0) == 0 && - IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)dst)->sin6_addr)) { - bzero(&dmask6, sizeof(dmask6)); -#if 0 /* we'll need to do this soon */ - dmask6.sin6_scope_id = ~0; + struct ip6_hdr ip6; + struct gif_softc *sc; + struct sockaddr_in6 *src, *dst; + int addrmatch; + + /* sanity check done in caller */ + sc = (struct gif_softc *)arg; + src = (struct sockaddr_in6 *)sc->gif_psrc; + dst = (struct sockaddr_in6 *)sc->gif_pdst; + + /* LINTED const cast */ + m_copydata((struct mbuf *)m, 0, sizeof(ip6), (caddr_t)&ip6); + + /* check for address match */ + addrmatch = 0; + if (IN6_ARE_ADDR_EQUAL(&src->sin6_addr, &ip6.ip6_dst)) + addrmatch |= 1; + if (IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6.ip6_src)) + addrmatch |= 2; + if (addrmatch != 3) + return 0; + + /* martian filters on outer source - done in ip6_input */ + + /* ingress filters on outer source */ + if ((sc->gif_if.if_flags & IFF_LINK2) == 0 && + (m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.rcvif) { + struct sockaddr_in6 sin6; + struct rtentry *rt; + + bzero(&sin6, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_len = sizeof(struct sockaddr_in6); + sin6.sin6_addr = ip6.ip6_src; + /* XXX scopeid */ + rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL); + if (!rt || rt->rt_ifp != m->m_pkthdr.rcvif) { +#if 0 + log(LOG_WARNING, "%s: packet from %s dropped " + "due to ingress filter\n", if_name(&sc->gif_if), + ip6_sprintf(&sin6.sin6_addr)); #endif - } - size = sizeof(struct sockaddr_in6); - break; -#endif /* INET6 */ - default: - error = EAFNOSUPPORT; - goto bad; - } - - if (sc->encap_cookie != NULL) - (void)encap_detach(sc->encap_cookie); - if (sc->gif_psrc != NULL) { - _FREE((caddr_t)sc->gif_psrc, M_IFADDR); - sc->gif_psrc = NULL; + if (rt) + rtfree(rt); + return 0; } - if (sc->gif_pdst != NULL) { - _FREE((caddr_t)sc->gif_pdst, M_IFADDR); - sc->gif_pdst = NULL; - } - - p = encap_attach(ifr->ifr_addr.sa_family, -1, src, - (struct sockaddr *)&smask6, dst, - (struct sockaddr *)&dmask6, - (struct protosw *)&in6_gif_protosw, &sc->gif_if); - if (p == NULL) { - error = EINVAL; - goto bad; - } - sc->encap_cookie = p; - sc->gif_oflags = ifp->if_flags; - - sa = (struct sockaddr *)_MALLOC(size, M_IFADDR, M_WAITOK); - bcopy((caddr_t)src, (caddr_t)sa, size); - sc->gif_psrc = sa; - - sa = (struct sockaddr *)_MALLOC(size, M_IFADDR, M_WAITOK); - bcopy((caddr_t)dst, (caddr_t)sa, size); - sc->gif_pdst = sa; - - ifp->if_flags |= IFF_UP; - if_up(ifp); /* send up RTM_IFINFO */ - - error = 0; - break; - default: - error = EINVAL; - goto bad; + rtfree(rt); } - bad: - return error; + return 128 * 2; } diff --git a/bsd/netinet6/in6_gif.h b/bsd/netinet6/in6_gif.h index 7755c69e3..f34f963dd 100644 --- a/bsd/netinet6/in6_gif.h +++ b/bsd/netinet6/in6_gif.h @@ -1,4 +1,5 @@ -/* $KAME: in6_gif.h,v 1.3 2000/02/22 14:04:17 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/in6_gif.h,v 1.2.2.1 2000/07/15 07:14:33 kris Exp $ */ +/* $KAME: in6_gif.h,v 1.5 2000/04/14 08:36:03 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -31,15 +32,14 @@ #ifndef _NETINET6_IN6_GIF_H_ #define _NETINET6_IN6_GIF_H_ +#include +#ifdef __APPLE_API_PRIVATE #define GIF_HLIM 30 -int in6_gif_input __P((struct mbuf **, int *, int)); +int in6_gif_input __P((struct mbuf **, int *)); int in6_gif_output __P((struct ifnet *, int, struct mbuf *, struct rtentry *)); -#if defined(__FreeBSD__) && __FreeBSD__ < 3 || !defined(__APPLE__) -int in6_gif_ioctl __P((struct ifnet *, int, caddr_t)); -#else -int in6_gif_ioctl __P((struct ifnet *, u_long, caddr_t)); -#endif +int gif_encapcheck6 __P((const struct mbuf *, int, int, void *)); +#endif /* __APPLE_API_PRIVATE */ #endif /*_NETINET6_IN6_GIF_H_*/ diff --git a/bsd/netinet6/in6_ifattach.c b/bsd/netinet6/in6_ifattach.c index b874f6fc2..63c5d5710 100644 --- a/bsd/netinet6/in6_ifattach.c +++ b/bsd/netinet6/in6_ifattach.c @@ -33,15 +33,11 @@ #include #include #include +#include #include #include -#ifdef __bsdi__ -#include -#elif defined(__OpenBSD__) -#include -#else +#include #include -#endif #include #include @@ -50,255 +46,727 @@ #include #include -#ifndef __NetBSD__ #include -#endif +#include #include #include +#include +#include #include #include #include +#include #include -static struct in6_addr llsol; - struct in6_ifstat **in6_ifstat = NULL; struct icmp6_ifstat **icmp6_ifstat = NULL; size_t in6_ifstatmax = 0; size_t icmp6_ifstatmax = 0; unsigned long in6_maxmtu = 0; -int found_first_ifid = 0; -#define IFID_LEN 8 -static u_int8_t first_ifid[IFID_LEN]; +#if IP6_AUTO_LINKLOCAL +int ip6_auto_linklocal = IP6_AUTO_LINKLOCAL; +#else +int ip6_auto_linklocal = 1; /* enable by default */ +#endif -static int laddr_to_eui64 __P((u_int8_t *, u_int8_t *, size_t)); -static int gen_rand_eui64 __P((u_int8_t *)); +#ifndef __APPLE__ +struct callout in6_tmpaddrtimer_ch; +#endif -#define DEBUG 1 +extern struct inpcbinfo udbinfo; +extern struct inpcbinfo ripcbinfo; -static int -laddr_to_eui64(dst, src, len) - u_int8_t *dst; - u_int8_t *src; - size_t len; -{ - static u_int8_t zero[8]; - - bzero(zero, sizeof(zero)); - - switch (len) { - case 6: - if (bcmp(zero, src, 6) == 0) - return EINVAL; - dst[0] = src[0]; - dst[1] = src[1]; - dst[2] = src[2]; - dst[3] = 0xff; - dst[4] = 0xfe; - dst[5] = src[3]; - dst[6] = src[4]; - dst[7] = src[5]; - break; - case 8: - if (bcmp(zero, src, 8) == 0) - return EINVAL; - bcopy(src, dst, len); - break; - default: - return EINVAL; - } +static int get_rand_ifid __P((struct ifnet *, struct in6_addr *)); +static int generate_tmp_ifid __P((u_int8_t *, const u_int8_t *, u_int8_t *)); +static int get_hw_ifid __P((struct ifnet *, struct in6_addr *)); +static int get_ifid __P((struct ifnet *, struct ifnet *, struct in6_addr *)); +static int in6_ifattach_linklocal __P((struct ifnet *, struct ifnet *)); +static int in6_ifattach_loopback __P((struct ifnet *)); - return 0; -} +#define EUI64_GBIT 0x01 +#define EUI64_UBIT 0x02 +#define EUI64_TO_IFID(in6) do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0) +#define EUI64_GROUP(in6) ((in6)->s6_addr[8] & EUI64_GBIT) +#define EUI64_INDIVIDUAL(in6) (!EUI64_GROUP(in6)) +#define EUI64_LOCAL(in6) ((in6)->s6_addr[8] & EUI64_UBIT) +#define EUI64_UNIVERSAL(in6) (!EUI64_LOCAL(in6)) + +#define IFID_LOCAL(in6) (!EUI64_LOCAL(in6)) +#define IFID_UNIVERSAL(in6) (!EUI64_UNIVERSAL(in6)) /* * Generate a last-resort interface identifier, when the machine has no * IEEE802/EUI64 address sources. - * The address should be random, and should not change across reboot. + * The goal here is to get an interface identifier that is + * (1) random enough and (2) does not change across reboot. + * We currently use MD5(hostname) for it. */ static int -gen_rand_eui64(dst) - u_int8_t *dst; +get_rand_ifid(ifp, in6) + struct ifnet *ifp; + struct in6_addr *in6; /*upper 64bits are preserved */ { MD5_CTX ctxt; u_int8_t digest[16]; -#if defined(__FreeBSD__) || defined (__APPLE__) int hostnamelen = strlen(hostname); + +#if 0 + /* we need at least several letters as seed for ifid */ + if (hostnamelen < 3) + return -1; #endif - /* generate 8bytes of pseudo-random value. */ + /* generate 8 bytes of pseudo-random value. */ bzero(&ctxt, sizeof(ctxt)); MD5Init(&ctxt); MD5Update(&ctxt, hostname, hostnamelen); MD5Final(digest, &ctxt); - /* assumes sizeof(digest) > sizeof(first_ifid) */ - bcopy(digest, dst, 8); + /* assumes sizeof(digest) > sizeof(ifid) */ + bcopy(digest, &in6->s6_addr[8], 8); /* make sure to set "u" bit to local, and "g" bit to individual. */ - dst[0] &= 0xfe; - dst[0] |= 0x02; /* EUI64 "local" */ + in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */ + in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */ + + /* convert EUI64 into IPv6 interface identifier */ + EUI64_TO_IFID(in6); + + return 0; +} + +static int +generate_tmp_ifid(seed0, seed1, ret) + u_int8_t *seed0, *ret; + const u_int8_t *seed1; +{ + MD5_CTX ctxt; + u_int8_t seed[16], digest[16], nullbuf[8]; + u_int32_t val32; + struct timeval tv; + + /* If there's no hisotry, start with a random seed. */ + bzero(nullbuf, sizeof(nullbuf)); + if (bcmp(nullbuf, seed0, sizeof(nullbuf)) == 0) { + int i; + + for (i = 0; i < 2; i++) { + microtime(&tv); + val32 = random() ^ tv.tv_usec; + bcopy(&val32, seed + sizeof(val32) * i, sizeof(val32)); + } + } else + bcopy(seed0, seed, 8); + + /* copy the right-most 64-bits of the given address */ + /* XXX assumption on the size of IFID */ + bcopy(seed1, &seed[8], 8); + + if (0) { /* for debugging purposes only */ + int i; + + printf("generate_tmp_ifid: new randomized ID from: "); + for (i = 0; i < 16; i++) + printf("%02x", seed[i]); + printf(" "); + } + + /* generate 16 bytes of pseudo-random value. */ + bzero(&ctxt, sizeof(ctxt)); + MD5Init(&ctxt); + MD5Update(&ctxt, seed, sizeof(seed)); + MD5Final(digest, &ctxt); + + /* + * RFC 3041 3.2.1. (3) + * Take the left-most 64-bits of the MD5 digest and set bit 6 (the + * left-most bit is numbered 0) to zero. + */ + bcopy(digest, ret, 8); + ret[0] &= ~EUI64_UBIT; + + /* + * XXX: we'd like to ensure that the generated value is not zero + * for simplicity. If the caclculated digest happens to be zero, + * use a random non-zero value as the last resort. + */ + if (bcmp(nullbuf, ret, sizeof(nullbuf)) == 0) { + log(LOG_INFO, + "generate_tmp_ifid: computed MD5 value is zero.\n"); + + microtime(&tv); + val32 = random() ^ tv.tv_usec; + val32 = 1 + (val32 % (0xffffffff - 1)); + } + + /* + * RFC 3041 3.2.1. (4) + * Take the rightmost 64-bits of the MD5 digest and save them in + * stable storage as the history value to be used in the next + * iteration of the algorithm. + */ + bcopy(&digest[8], seed0, 8); + + if (0) { /* for debugging purposes only */ + int i; + + printf("to: "); + for (i = 0; i < 16; i++) + printf("%02x", digest[i]); + printf("\n"); + } return 0; } /* - * Find first ifid on list of interfaces. - * This is assumed that ifp0's interface token (for example, IEEE802 MAC) - * is globally unique. We may need to have a flag parameter in the future. + * Get interface identifier for the specified interface. + * XXX assumes single sockaddr_dl (AF_LINK address) per an interface */ -int -in6_ifattach_getifid(ifp0) - struct ifnet *ifp0; -{ +static int +get_hw_ifid(ifp, in6) struct ifnet *ifp; + struct in6_addr *in6; /*upper 64bits are preserved */ +{ struct ifaddr *ifa; - u_int8_t *addr = NULL; - int addrlen = 0; struct sockaddr_dl *sdl; + u_int8_t *addr; + size_t addrlen; + static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + static u_int8_t allone[8] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + for (ifa = ifp->if_addrlist.tqh_first; + ifa; + ifa = ifa->ifa_list.tqe_next) + { + if (ifa->ifa_addr->sa_family != AF_LINK) + continue; + sdl = (struct sockaddr_dl *)ifa->ifa_addr; + if (sdl == NULL) + continue; + if (sdl->sdl_alen == 0) + continue; + + goto found; + } - if (found_first_ifid) - return 0; + return -1; -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (ifp = ifnet; ifp; ifp = ifp->if_next) -#else - for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) +found: + addr = LLADDR(sdl); + addrlen = sdl->sdl_alen; + + /* get EUI64 */ + switch (ifp->if_type) { + case IFT_ETHER: + case IFT_FDDI: + case IFT_ATM: + case IFT_IEEE1394: +#if IFT_IEEE80211 + case IFT_IEEE80211: #endif + /* IEEE802/EUI64 cases - what others? */ + /* IEEE1394 uses 16byte length address starting with EUI64 */ + if (addrlen > 8) + addrlen = 8; + + /* look at IEEE802/EUI64 only */ + if (addrlen != 8 && addrlen != 6) + return -1; + + /* + * check for invalid MAC address - on bsdi, we see it a lot + * since wildboar configures all-zero MAC on pccard before + * card insertion. + */ + if (bcmp(addr, allzero, addrlen) == 0) + return -1; + if (bcmp(addr, allone, addrlen) == 0) + return -1; + + /* make EUI64 address */ + if (addrlen == 8) + bcopy(addr, &in6->s6_addr[8], 8); + else if (addrlen == 6) { + in6->s6_addr[8] = addr[0]; + in6->s6_addr[9] = addr[1]; + in6->s6_addr[10] = addr[2]; + in6->s6_addr[11] = 0xff; + in6->s6_addr[12] = 0xfe; + in6->s6_addr[13] = addr[3]; + in6->s6_addr[14] = addr[4]; + in6->s6_addr[15] = addr[5]; + } + break; + + case IFT_ARCNET: + if (addrlen != 1) + return -1; + if (!addr[0]) + return -1; + + bzero(&in6->s6_addr[8], 8); + in6->s6_addr[15] = addr[0]; + + /* + * due to insufficient bitwidth, we mark it local. + */ + in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */ + in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */ + break; + + case IFT_GIF: +#if IFT_STF + case IFT_STF: +#endif + /* + * RFC2893 says: "SHOULD use IPv4 address as ifid source". + * however, IPv4 address is not very suitable as unique + * identifier source (can be renumbered). + * we don't do this. + */ + return -1; + + default: + return -1; + } + + /* sanity check: g bit must not indicate "group" */ + if (EUI64_GROUP(in6)) + return -1; + + /* convert EUI64 into IPv6 interface identifier */ + EUI64_TO_IFID(in6); + + /* + * sanity check: ifid must not be all zero, avoid conflict with + * subnet router anycast + */ + if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 && + bcmp(&in6->s6_addr[9], allzero, 7) == 0) { + return -1; + } + + return 0; +} + +/* + * Get interface identifier for the specified interface. If it is not + * available on ifp0, borrow interface identifier from other information + * sources. + */ +static int +get_ifid(ifp0, altifp, in6) + struct ifnet *ifp0; + struct ifnet *altifp; /*secondary EUI64 source*/ + struct in6_addr *in6; +{ + struct ifnet *ifp; + + /* first, try to get it from the interface itself */ + if (get_hw_ifid(ifp0, in6) == 0) { + nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n", + if_name(ifp0))); + goto success; + } + + /* try secondary EUI64 source. this basically is for ATM PVC */ + if (altifp && get_hw_ifid(altifp, in6) == 0) { + nd6log((LOG_DEBUG, "%s: got interface identifier from %s\n", + if_name(ifp0), if_name(altifp))); + goto success; + } + + /* next, try to get it from some other hardware interface */ + for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) { - if (ifp0 != NULL && ifp0 != ifp) + if (ifp == ifp0) continue; -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) + if (get_hw_ifid(ifp, in6) != 0) + continue; + + /* + * to borrow ifid from other interface, ifid needs to be + * globally unique + */ + if (IFID_UNIVERSAL(in6)) { + nd6log((LOG_DEBUG, + "%s: borrow interface identifier from %s\n", + if_name(ifp0), if_name(ifp))); + goto success; + } + } + + /* last resort: get from random number source */ + if (get_rand_ifid(ifp, in6) == 0) { + nd6log((LOG_DEBUG, + "%s: interface identifier generated by random number\n", + if_name(ifp0))); + goto success; + } + + printf("%s: failed to get interface identifier\n", if_name(ifp0)); + return -1; + +success: + nd6log((LOG_INFO, "%s: ifid: " + "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + if_name(ifp0), + in6->s6_addr[8], in6->s6_addr[9], + in6->s6_addr[10], in6->s6_addr[11], + in6->s6_addr[12], in6->s6_addr[13], + in6->s6_addr[14], in6->s6_addr[15])); + return 0; +} + +static int +in6_ifattach_linklocal(ifp, altifp) + struct ifnet *ifp; + struct ifnet *altifp; /* secondary EUI64 source */ +{ + struct in6_ifaddr *ia; + struct in6_aliasreq ifra; + struct nd_prefix pr0; + int i, error; + + /* + * configure link-local address. + */ + bzero(&ifra, sizeof(ifra)); + + /* + * in6_update_ifa() does not use ifra_name, but we accurately set it + * for safety. + */ + strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); + + ifra.ifra_addr.sin6_family = AF_INET6; + ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); + ifra.ifra_addr.sin6_addr.s6_addr16[0] = htons(0xfe80); +#if SCOPEDROUTING + ifra.ifra_addr.sin6_addr.s6_addr16[1] = 0 #else - for (ifa = ifp->if_addrlist.tqh_first; - ifa; - ifa = ifa->ifa_list.tqe_next) + ifra.ifra_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); /* XXX */ #endif - { - if (ifa->ifa_addr->sa_family != AF_LINK) - continue; - sdl = (struct sockaddr_dl *)ifa->ifa_addr; - if (sdl == NULL) - continue; - if (sdl->sdl_alen == 0) - continue; - switch (ifp->if_type) { - case IFT_ETHER: - case IFT_FDDI: - case IFT_ATM: - /* IEEE802/EUI64 cases - what others? */ - addr = LLADDR(sdl); - addrlen = sdl->sdl_alen; - /* - * to copy ifid from IEEE802/EUI64 interface, - * u bit of the source needs to be 0. - */ - if ((addr[0] & 0x02) != 0) - break; - goto found; - case IFT_ARCNET: - /* - * ARCnet interface token cannot be used as - * globally unique identifier due to its - * small bitwidth. - */ - break; - default: - break; - } + ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0; + if ((ifp->if_flags & IFF_LOOPBACK) != 0) { + ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0; + ifra.ifra_addr.sin6_addr.s6_addr32[3] = htonl(1); + } else { + if (get_ifid(ifp, altifp, &ifra.ifra_addr.sin6_addr) != 0) { + nd6log((LOG_ERR, + "%s: no ifid available\n", if_name(ifp))); + return -1; } } -#if DEBUG - printf("in6_ifattach_getifid: failed to get EUI64"); +#if SCOPEDROUTING + ifra.ifra_addr.sin6_scope_id = + in6_addr2scopeid(ifp, &ifra.ifra_addr.sin6_addr); #endif - return EADDRNOTAVAIL; -found: - if (laddr_to_eui64(first_ifid, addr, addrlen) == 0) - found_first_ifid = 1; - - if (found_first_ifid) { - printf("%s: supplying EUI64: " - "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", - if_name(ifp), - first_ifid[0] & 0xff, first_ifid[1] & 0xff, - first_ifid[2] & 0xff, first_ifid[3] & 0xff, - first_ifid[4] & 0xff, first_ifid[5] & 0xff, - first_ifid[6] & 0xff, first_ifid[7] & 0xff); - - /* invert u bit to convert EUI64 to RFC2373 interface ID. */ - first_ifid[0] ^= 0x02; - - return 0; - } else { -#if DEBUG - printf("in6_ifattach_getifid: failed to get EUI64"); + ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); + ifra.ifra_prefixmask.sin6_family = AF_INET6; + ifra.ifra_prefixmask.sin6_addr = in6mask64; +#if SCOPEDROUTING + /* take into accound the sin6_scope_id field for routing */ + ifra.ifra_prefixmask.sin6_scope_id = 0xffffffff; #endif - return EADDRNOTAVAIL; + /* link-local addresses should NEVER expire. */ + ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; + ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; + + /* + * Do not let in6_update_ifa() do DAD, since we need a random delay + * before sending an NS at the first time the inteface becomes up. + * Instead, in6_if_up() will start DAD with a proper random delay. + */ + ifra.ifra_flags |= IN6_IFF_NODAD; + + /* + * Now call in6_update_ifa() to do a bunch of procedures to configure + * a link-local address. We can set NULL to the 3rd argument, because + * we know there's no other link-local address on the interface. + */ + if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) { + /* + * XXX: When the interface does not support IPv6, this call + * would fail in the SIOCSIFADDR ioctl. I believe the + * notification is rather confusing in this case, so just + * supress it. (jinmei@kame.net 20010130) + */ + if (error != EAFNOSUPPORT) + log(LOG_NOTICE, "in6_ifattach_linklocal: failed to " + "configure a link-local address on %s " + "(errno=%d)\n", + if_name(ifp), error); + return(-1); + } + + /* + * Adjust ia6_flags so that in6_if_up will perform DAD. + * XXX: Some P2P interfaces seem not to send packets just after + * becoming up, so we skip p2p interfaces for safety. + */ + ia = in6ifa_ifpforlinklocal(ifp, 0); /* ia must not be NULL */ +#if DIAGNOSTIC + if (!ia) { + panic("ia == NULL in in6_ifattach_linklocal"); + /*NOTREACHED*/ + } +#endif + if (in6if_do_dad(ifp) && (ifp->if_flags & IFF_POINTOPOINT) == 0) { + ia->ia6_flags &= ~IN6_IFF_NODAD; + ia->ia6_flags |= IN6_IFF_TENTATIVE; } + + /* + * Make the link-local prefix (fe80::/64%link) as on-link. + * Since we'd like to manage prefixes separately from addresses, + * we make an ND6 prefix structure for the link-local prefix, + * and add it to the prefix list as a never-expire prefix. + * XXX: this change might affect some existing code base... + */ + bzero(&pr0, sizeof(pr0)); + pr0.ndpr_ifp = ifp; + /* this should be 64 at this moment. */ + pr0.ndpr_plen = in6_mask2len(&ifra.ifra_prefixmask.sin6_addr, NULL); + pr0.ndpr_mask = ifra.ifra_prefixmask.sin6_addr; + pr0.ndpr_prefix = ifra.ifra_addr; + /* apply the mask for safety. (nd6_prelist_add will apply it again) */ + for (i = 0; i < 4; i++) { + pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &= + in6mask64.s6_addr32[i]; + } + /* + * Initialize parameters. The link-local prefix must always be + * on-link, and its lifetimes never expire. + */ + pr0.ndpr_raf_onlink = 1; + pr0.ndpr_raf_auto = 1; /* probably meaningless */ + pr0.ndpr_vltime = ND6_INFINITE_LIFETIME; + pr0.ndpr_pltime = ND6_INFINITE_LIFETIME; + /* + * Since there is no other link-local addresses, nd6_prefix_lookup() + * probably returns NULL. However, we cannot always expect the result. + * For example, if we first remove the (only) existing link-local + * address, and then reconfigure another one, the prefix is still + * valid with referring to the old link-local address. + */ + if (nd6_prefix_lookup(&pr0) == NULL) { + if ((error = nd6_prelist_add(&pr0, NULL, NULL)) != 0) + return(error); + } + + in6_post_msg(ifp, KEV_INET6_NEW_LL_ADDR, ia); + return 0; +} + +static int +in6_ifattach_loopback(ifp) + struct ifnet *ifp; /* must be IFT_LOOP */ +{ + struct in6_aliasreq ifra; + int error; + + bzero(&ifra, sizeof(ifra)); + + /* + * in6_update_ifa() does not use ifra_name, but we accurately set it + * for safety. + */ + strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); + + ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); + ifra.ifra_prefixmask.sin6_family = AF_INET6; + ifra.ifra_prefixmask.sin6_addr = in6mask128; + + /* + * Always initialize ia_dstaddr (= broadcast address) to loopback + * address. Follows IPv4 practice - see in_ifinit(). + */ + ifra.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6); + ifra.ifra_dstaddr.sin6_family = AF_INET6; + ifra.ifra_dstaddr.sin6_addr = in6addr_loopback; + + ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); + ifra.ifra_addr.sin6_family = AF_INET6; + ifra.ifra_addr.sin6_addr = in6addr_loopback; + + /* the loopback address should NEVER expire. */ + ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; + ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; + + /* we don't need to perfrom DAD on loopback interfaces. */ + ifra.ifra_flags |= IN6_IFF_NODAD; + + /* skip registration to the prefix list. XXX should be temporary. */ + ifra.ifra_flags |= IN6_IFF_NOPFX; + + /* + * We can set NULL to the 3rd arg. See comments in + * in6_ifattach_linklocal(). + */ + if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) { + log(LOG_ERR, "in6_ifattach_loopback: failed to configure " + "the loopback address on %s (errno=%d)\n", + if_name(ifp), error); + return(-1); + } + + return 0; } /* - * XXX multiple loopback interface needs more care. for instance, - * nodelocal address needs to be configured onto only one of them. + * compute NI group address, based on the current hostname setting. + * see draft-ietf-ipngwg-icmp-name-lookup-* (04 and later). + * + * when ifp == NULL, the caller is responsible for filling scopeid. */ -void -in6_ifattach(ifp, type, laddr, noloop) +int +in6_nigroup(ifp, name, namelen, in6) struct ifnet *ifp; - u_int type; - caddr_t laddr; - /* size_t laddrlen; */ - int noloop; + const char *name; + int namelen; + struct in6_addr *in6; { - static size_t if_indexlim = 8; - struct sockaddr_in6 mltaddr; - struct sockaddr_in6 mltmask; - struct sockaddr_in6 gate; - struct sockaddr_in6 mask; -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - struct ifaddr **ifap; -#endif + const char *p; + u_char *q; + MD5_CTX ctxt; + u_int8_t digest[16]; + char l; + char n[64]; /* a single label must not exceed 63 chars */ + + if (!namelen || !name) + return -1; + + p = name; + while (p && *p && *p != '.' && p - name < namelen) + p++; + if (p - name > sizeof(n) - 1) + return -1; /*label too long*/ + l = p - name; + strncpy(n, name, l); + n[(int)l] = '\0'; + for (q = n; *q; q++) { + if ('A' <= *q && *q <= 'Z') + *q = *q - 'A' + 'a'; + } - struct in6_ifaddr *ia, *ib, *oia; - struct ifaddr *ifa; - int rtflag = 0; - int s; + /* generate 8 bytes of pseudo-random value. */ + bzero(&ctxt, sizeof(ctxt)); + MD5Init(&ctxt); + MD5Update(&ctxt, &l, sizeof(l)); + MD5Update(&ctxt, n, l); + MD5Final(digest, &ctxt); + + bzero(in6, sizeof(*in6)); + in6->s6_addr16[0] = htons(0xff02); + if (ifp) + in6->s6_addr16[1] = htons(ifp->if_index); + in6->s6_addr8[11] = 2; + bcopy(digest, &in6->s6_addr32[3], sizeof(in6->s6_addr32[3])); + + return 0; +} + +void +in6_nigroup_attach(name, namelen) + const char *name; + int namelen; +{ + struct ifnet *ifp; + struct sockaddr_in6 mltaddr; + struct in6_multi *in6m; int error; - if (type == IN6_IFT_P2P && found_first_ifid == 0) { - printf("%s: no ifid available for IPv6 link-local address\n", - if_name(ifp)); -#if 0 + bzero(&mltaddr, sizeof(mltaddr)); + mltaddr.sin6_family = AF_INET6; + mltaddr.sin6_len = sizeof(struct sockaddr_in6); + if (in6_nigroup(NULL, name, namelen, &mltaddr.sin6_addr) != 0) return; -#else - /* last resort */ - if (gen_rand_eui64(first_ifid) == 0) { - printf("%s: using random value as EUI64: " - "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", - if_name(ifp), - first_ifid[0] & 0xff, first_ifid[1] & 0xff, - first_ifid[2] & 0xff, first_ifid[3] & 0xff, - first_ifid[4] & 0xff, first_ifid[5] & 0xff, - first_ifid[6] & 0xff, first_ifid[7] & 0xff); - /* - * invert u bit to convert EUI64 to RFC2373 interface - * ID. - */ - first_ifid[0] ^= 0x02; - found_first_ifid = 1; + for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) + { + mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); + IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m); + if (!in6m) { + if (!in6_addmulti(&mltaddr.sin6_addr, ifp, &error)) { + nd6log((LOG_ERR, "%s: failed to join %s " + "(errno=%d)\n", if_name(ifp), + ip6_sprintf(&mltaddr.sin6_addr), + error)); + } } -#endif } +} - if ((ifp->if_flags & IFF_MULTICAST) == 0) { - printf("%s: not multicast capable, IPv6 not enabled\n", - if_name(ifp)); +void +in6_nigroup_detach(name, namelen) + const char *name; + int namelen; +{ + struct ifnet *ifp; + struct sockaddr_in6 mltaddr; + struct in6_multi *in6m; + + bzero(&mltaddr, sizeof(mltaddr)); + mltaddr.sin6_family = AF_INET6; + mltaddr.sin6_len = sizeof(struct sockaddr_in6); + if (in6_nigroup(NULL, name, namelen, &mltaddr.sin6_addr) != 0) return; + + for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) + { + mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); + IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m); + if (in6m) + in6_delmulti(in6m); + } +} + +/* + * XXX multiple loopback interface needs more care. for instance, + * nodelocal address needs to be configured onto only one of them. + * XXX multiple link-local address case + */ +void +in6_ifattach(ifp, altifp) + struct ifnet *ifp; + struct ifnet *altifp; /* secondary EUI64 source */ +{ + static size_t if_indexlim = 8; + struct in6_ifaddr *ia; + struct in6_addr in6; + u_long dl_tag; + + switch (ifp->if_type) { +#if IFT_BRIDGE /*OpenBSD 2.8*/ + /* some of the interfaces are inherently not IPv6 capable */ + case IFT_BRIDGE: + return; +#endif +#ifdef __APPLE__ + case IFT_ETHER: + dl_tag = ether_attach_inet6(ifp); + break; + + case IFT_LOOP: + dl_tag = lo_attach_inet6(ifp); +#if NGIF > 0 + case IFT_GIF: + dl_tag = gif_attach_proto_family(ifp, PF_INET6); + break; +#endif +#if NSTF > 0 + case IFT_STF: + dl_tag = stf_attach_inet6(ifp); + break; +#endif +#endif } /* @@ -307,8 +775,8 @@ in6_ifattach(ifp, type, laddr, noloop) * struct in6_ifstat **in6_ifstat * struct icmp6_ifstat **icmp6_ifstat */ - if (in6_ifstat == NULL || icmp6_ifstat == NULL - || if_index >= if_indexlim) { + if (in6_ifstat == NULL || icmp6_ifstat == NULL || + if_index >= if_indexlim) { size_t n; caddr_t q; size_t olim; @@ -324,7 +792,7 @@ in6_ifattach(ifp, type, laddr, noloop) if (in6_ifstat) { bcopy((caddr_t)in6_ifstat, q, olim * sizeof(struct in6_ifstat *)); - _FREE((caddr_t)in6_ifstat, M_IFADDR); + FREE((caddr_t)in6_ifstat, M_IFADDR); } in6_ifstat = (struct in6_ifstat **)q; in6_ifstatmax = if_indexlim; @@ -336,360 +804,74 @@ in6_ifattach(ifp, type, laddr, noloop) if (icmp6_ifstat) { bcopy((caddr_t)icmp6_ifstat, q, olim * sizeof(struct icmp6_ifstat *)); - _FREE((caddr_t)icmp6_ifstat, M_IFADDR); + FREE((caddr_t)icmp6_ifstat, M_IFADDR); } icmp6_ifstat = (struct icmp6_ifstat **)q; icmp6_ifstatmax = if_indexlim; } - /* - * To prevent to assign link-local address to PnP network - * cards multiple times. - * This is lengthy for P2P and LOOP but works. - */ -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - ifa = ifp->if_addrlist; - if (ifa != NULL) { - for ( ; ifa; ifa = ifa->ifa_next) { - ifap = &ifa->ifa_next; - if (ifa->ifa_addr->sa_family != AF_INET6) - continue; - if (IN6_IS_ADDR_LINKLOCAL(&satosin6(ifa->ifa_addr)->sin6_addr)) - return; - } - } else - ifap = &ifp->if_addrlist; -#else - ifa = TAILQ_FIRST(&ifp->if_addrlist); - if (ifa != NULL) { - for ( ; ifa; ifa = TAILQ_NEXT(ifa, ifa_list)) { - if (ifa->ifa_addr->sa_family != AF_INET6) - continue; - if (IN6_IS_ADDR_LINKLOCAL(&satosin6(ifa->ifa_addr)->sin6_addr)) - return; - } - } else { - TAILQ_INIT(&ifp->if_addrlist); - } -#endif - - /* - * link-local address - */ - ia = (struct in6_ifaddr *)_MALLOC(sizeof(*ia), M_IFADDR, M_WAITOK); - bzero((caddr_t)ia, sizeof(*ia)); - ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; - if (ifp->if_flags & IFF_POINTOPOINT) - ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; - else - ia->ia_ifa.ifa_dstaddr = NULL; - ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask; - ia->ia_ifp = ifp; -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - *ifap = (struct ifaddr *)ia; -#else - TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); -#endif - ia->ia_ifa.ifa_refcnt++; + /* initialize scope identifiers */ + scope6_ifattach(ifp); /* - * Also link into the IPv6 address chain beginning with in6_ifaddr. - * kazu opposed it, but itojun & jinmei wanted. + * quirks based on interface type */ - if ((oia = in6_ifaddr) != NULL) { - for (; oia->ia_next; oia = oia->ia_next) - continue; - oia->ia_next = ia; - } else - in6_ifaddr = ia; - ia->ia_ifa.ifa_refcnt++; - - ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6); - ia->ia_prefixmask.sin6_family = AF_INET6; - ia->ia_prefixmask.sin6_addr = in6mask64; - - bzero(&ia->ia_addr, sizeof(struct sockaddr_in6)); - ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6); - ia->ia_addr.sin6_family = AF_INET6; - ia->ia_addr.sin6_addr.s6_addr16[0] = htons(0xfe80); - ia->ia_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); - ia->ia_addr.sin6_addr.s6_addr32[1] = 0; - - switch (type) { - case IN6_IFT_LOOP: - ia->ia_addr.sin6_addr.s6_addr32[2] = 0; - ia->ia_addr.sin6_addr.s6_addr32[3] = htonl(1); - if (strcmp(ifp->if_name, "lo") == 0) { - ia->ia_ifa.ifa_dlt = lo_attach_inet(ifp); - printf("in6_ifattach: IFT_LOOP setting initial ifp=%s%d initial ia=%x ifa_dlt=%x\n", - ifp->if_name, ifp->if_unit, ia, ia->ia_ifa.ifa_dlt); - } - break; - case IN6_IFT_802: - ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; - ia->ia_ifa.ifa_flags |= RTF_CLONING; - rtflag = RTF_CLONING; - if (strcmp(ifp->if_name, "en") == 0) { - ia->ia_ifa.ifa_dlt = ether_attach_inet6(ifp); - printf("in6_ifattach: IFT_802 setting initial ifp=%s%d initial ia=%x ifa_dlt=%x\n", - ifp->if_name, ifp->if_unit, ia, ia->ia_ifa.ifa_dlt); - } - - /* fall through */ - case IN6_IFT_P2P802: - ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; - ia->ia_ifa.ifa_flags |= RTF_CLONING; - rtflag = RTF_CLONING; - if (laddr == NULL) - break; - /* XXX use laddrlen */ - if (laddr_to_eui64(&ia->ia_addr.sin6_addr.s6_addr8[8], - laddr, 6) != 0) { - break; - } - /* invert u bit to convert EUI64 to RFC2373 interface ID. */ - ia->ia_addr.sin6_addr.s6_addr8[8] ^= 0x02; - if (found_first_ifid == 0) - in6_ifattach_getifid(ifp); - bzero(&ia->ia_dstaddr, sizeof(struct sockaddr_in6)); - ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6); - ia->ia_dstaddr.sin6_family = AF_INET6; - - if (ia->ia_ifa.ifa_dlt == 0) { - ia->ia_ifa.ifa_dlt = ifp; -#if DEBUG - printf("in6_ifattach: IFT_P2P802 setting initial ifp=%s%d initial ia=%x ifa_dlt=%x\n", - ifp->if_name, ifp->if_unit, ia, ia->ia_ifa.ifa_dlt); -#endif - } - break; - case IN6_IFT_P2P: - ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; - ia->ia_ifa.ifa_flags |= RTF_CLONING; - rtflag = RTF_CLONING; - bcopy((caddr_t)first_ifid, - (caddr_t)&ia->ia_addr.sin6_addr.s6_addr8[8], - IFID_LEN); - bzero(&ia->ia_dstaddr, sizeof(struct sockaddr_in6)); - ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6); - ia->ia_dstaddr.sin6_family = AF_INET6; -#if NGIF > 0 - if (strcmp(ifp->if_name, "gif") == 0) { - ia->ia_ifa.ifa_dlt = gif_attach_inet(ifp); -#if DEBUG - printf("in6_ifattach: IFT_P2P setting initial ifp=%s%d initial ia=%x ifa_dlt=%x\n", - ifp->if_name, ifp->if_unit, ia, ia->ia_ifa.ifa_dlt); -#endif - } + switch (ifp->if_type) { +#if IFT_STF + case IFT_STF: + /* + * 6to4 interface is a very speical kind of beast. + * no multicast, no linklocal (based on 03 draft). + */ + goto statinit; #endif + default: break; - case IN6_IFT_ARCNET: - ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; - ia->ia_ifa.ifa_flags |= RTF_CLONING; - rtflag = RTF_CLONING; - if (laddr == NULL) - break; - - /* make non-global IF id out of link-level address */ - bzero(&ia->ia_addr.sin6_addr.s6_addr8[8], 7); - ia->ia_addr.sin6_addr.s6_addr8[15] = *laddr; - ia->ia_ifa.ifa_dlt = ifp; -#if DEBUG - printf("in6_ifattach: IFT_ARCNET setting initial ifp=%s%d initial ia=%x ifa_dlt=%x\n", - ifp->if_name, ifp->if_unit, ia, ia->ia_ifa.ifa_dlt); -#endif } - ia->ia_ifa.ifa_metric = ifp->if_metric; - - /* - * give the interface a chance to initialize, in case this - * is the first address to be added. + * usually, we require multicast capability to the interface */ - s = splimp(); -#ifdef __APPLE__ - error = dlil_ioctl(0, ifp, SIOCSIFADDR, (caddr_t)ia); -#else - error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia); -#endif - splx(s); -#if DEBUG - printf("in6_ifattach: Calling SIOCSIFADDR for if=%s%d ia=%x error=%x\n", ifp->if_name, ifp->if_unit, ia, error); -#endif - if (error == EOPNOTSUPP) - error = 0; - - if (error) { - switch (error) { - case EAFNOSUPPORT: - printf("%s: IPv6 not supported\n", - if_name(ifp)); - break; - default: - printf("%s: SIOCSIFADDR error %d\n", - if_name(ifp), error); - break; - } - - /* undo changes */ -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - *ifap = NULL; -#else - TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); -#endif - IFAFREE(&ia->ia_ifa); - if (oia) - oia->ia_next = ia->ia_next; - else - in6_ifaddr = ia->ia_next; - IFAFREE(&ia->ia_ifa); + if ((ifp->if_flags & IFF_MULTICAST) == 0) { + log(LOG_INFO, "in6_ifattach: " + "%s is not multicast capable, IPv6 not enabled\n", + if_name(ifp)); return; } - /* add route to the interface. */ - rtrequest(RTM_ADD, - (struct sockaddr *)&ia->ia_addr, - (struct sockaddr *)&ia->ia_addr, - (struct sockaddr *)&ia->ia_prefixmask, - RTF_UP|rtflag, - (struct rtentry **)0); - ia->ia_flags |= IFA_ROUTE; - - if (type == IN6_IFT_P2P || type == IN6_IFT_P2P802) { - /* - * route local address to loopback - */ - bzero(&gate, sizeof(gate)); - gate.sin6_len = sizeof(struct sockaddr_in6); - gate.sin6_family = AF_INET6; - gate.sin6_addr = in6addr_loopback; - bzero(&mask, sizeof(mask)); - mask.sin6_len = sizeof(struct sockaddr_in6); - mask.sin6_family = AF_INET6; - mask.sin6_addr = in6mask64; - rtrequest(RTM_ADD, - (struct sockaddr *)&ia->ia_addr, - (struct sockaddr *)&gate, - (struct sockaddr *)&mask, - RTF_UP|RTF_HOST, - (struct rtentry **)0); - } + /* initialize NDP variables */ + nd6_ifattach(ifp); /* - * loopback address + * assign loopback address for loopback interface. + * XXX multiple loopback interface case. */ - ib = (struct in6_ifaddr *)NULL; - if (type == IN6_IFT_LOOP) { - ib = (struct in6_ifaddr *) - _MALLOC(sizeof(*ib), M_IFADDR, M_WAITOK); - bzero((caddr_t)ib, sizeof(*ib)); - ib->ia_ifa.ifa_addr = (struct sockaddr *)&ib->ia_addr; - ib->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ib->ia_dstaddr; - ib->ia_ifa.ifa_netmask = (struct sockaddr *)&ib->ia_prefixmask; - ib->ia_ifa.ifa_dlt = lo_attach_inet(ifp); - ib->ia_ifp = ifp; - - ia->ia_next = ib; -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - ia->ia_ifa.ifa_next = (struct ifaddr *)ib; -#else - TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ib, - ifa_list); -#endif - ib->ia_ifa.ifa_refcnt++; - - ib->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6); - ib->ia_prefixmask.sin6_family = AF_INET6; - ib->ia_prefixmask.sin6_addr = in6mask128; - ib->ia_addr.sin6_len = sizeof(struct sockaddr_in6); - ib->ia_addr.sin6_family = AF_INET6; - ib->ia_addr.sin6_addr = in6addr_loopback; - - /* - * Always initialize ia_dstaddr (= broadcast address) - * to loopback address, to make getifaddr happier. - * - * For BSDI, it is mandatory. The BSDI version of - * ifa_ifwithroute() rejects to add a route to the loopback - * interface. Even for other systems, loopback looks somewhat - * special. - */ - ib->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6); - ib->ia_dstaddr.sin6_family = AF_INET6; - ib->ia_dstaddr.sin6_addr = in6addr_loopback; - - ib->ia_ifa.ifa_metric = ifp->if_metric; - - rtrequest(RTM_ADD, - (struct sockaddr *)&ib->ia_addr, - (struct sockaddr *)&ib->ia_addr, - (struct sockaddr *)&ib->ia_prefixmask, - RTF_UP|RTF_HOST, - (struct rtentry **)0); - - ib->ia_flags |= IFA_ROUTE; + if ((ifp->if_flags & IFF_LOOPBACK) != 0) { + in6 = in6addr_loopback; + if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) { + if (in6_ifattach_loopback(ifp) != 0) + return; + } } /* - * join multicast + * assign a link-local address, if there's none. */ - if (ifp->if_flags & IFF_MULTICAST) { - int error; /* not used */ - -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined (__APPLE__) - /* Restore saved multicast addresses(if any). */ - in6_restoremkludge(ia, ifp); -#endif - - bzero(&mltmask, sizeof(mltmask)); - mltmask.sin6_len = sizeof(struct sockaddr_in6); - mltmask.sin6_family = AF_INET6; - mltmask.sin6_addr = in6mask32; - - /* - * join link-local all-nodes address - */ - bzero(&mltaddr, sizeof(mltaddr)); - mltaddr.sin6_len = sizeof(struct sockaddr_in6); - mltaddr.sin6_family = AF_INET6; - mltaddr.sin6_addr = in6addr_linklocal_allnodes; - mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); - rtrequest(RTM_ADD, - (struct sockaddr *)&mltaddr, - (struct sockaddr *)&ia->ia_addr, - (struct sockaddr *)&mltmask, - RTF_UP|RTF_CLONING, /* xxx */ - (struct rtentry **)0); - (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error); - - if (type == IN6_IFT_LOOP) { - /* - * join node-local all-nodes address - */ - mltaddr.sin6_addr = in6addr_nodelocal_allnodes; - rtrequest(RTM_ADD, - (struct sockaddr *)&mltaddr, - (struct sockaddr *)&ib->ia_addr, - (struct sockaddr *)&mltmask, - RTF_UP, - (struct rtentry **)0); - (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error); - } else { - /* - * join solicited multicast address - */ - bzero(&llsol, sizeof(llsol)); - llsol.s6_addr16[0] = htons(0xff02); - llsol.s6_addr16[1] = htons(ifp->if_index); - llsol.s6_addr32[1] = 0; - llsol.s6_addr32[2] = htonl(1); - llsol.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3]; - llsol.s6_addr8[12] = 0xff; - (void)in6_addmulti(&llsol, ifp, &error); + if (ip6_auto_linklocal) { + ia = in6ifa_ifpforlinklocal(ifp, 0); + if (ia == NULL) { + if (in6_ifattach_linklocal(ifp, altifp) == 0) { + /* linklocal address assigned */ + } else { + /* failed to assign linklocal address. bark? */ + } } } +#if IFT_STF /* XXX */ +statinit: +#endif + /* update dynamically. */ if (in6_maxmtu < ifp->if_mtu) in6_maxmtu = ifp->if_mtu; @@ -705,52 +887,24 @@ in6_ifattach(ifp, type, laddr, noloop) bzero(icmp6_ifstat[ifp->if_index], sizeof(struct icmp6_ifstat)); } - /* initialize NDP variables */ - nd6_ifattach(ifp); - - /* mark the address TENTATIVE, if needed. */ - switch (ifp->if_type) { - case IFT_ARCNET: - case IFT_ETHER: - case IFT_FDDI: -#if 0 - case IFT_ATM: - case IFT_SLIP: - case IFT_PPP: -#endif - ia->ia6_flags |= IN6_IFF_TENTATIVE; - /* nd6_dad_start() will be called in in6_if_up */ - break; - case IFT_DUMMY: - case IFT_GIF: /*XXX*/ - case IFT_LOOP: - case IFT_FAITH: - default: - break; - } - - return; } /* * NOTE: in6_ifdetach() does not support loopback if at this moment. + * We don't need this function in bsdi, because interfaces are never removed + * from the ifnet list in bsdi. */ void in6_ifdetach(ifp) struct ifnet *ifp; { struct in6_ifaddr *ia, *oia; - struct ifaddr *ifa; -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - struct ifaddr *ifaprev = NULL; -#endif + struct ifaddr *ifa, *next; struct rtentry *rt; short rtflags; struct sockaddr_in6 sin6; struct in6_multi *in6m; -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__) struct in6_multi *in6m_next; -#endif /* nuke prefix list. this may try to remove some of ifaddrs as well */ in6_purgeprefix(ifp); @@ -758,35 +912,31 @@ in6_ifdetach(ifp) /* remove neighbor management table */ nd6_purge(ifp); -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) -#else - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) -#endif + /* nuke any of IPv6 addresses we have */ + for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next) { + next = ifa->ifa_list.tqe_next; + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + in6_purgeaddr(ifa); + } + + /* undo everything done by in6_ifattach(), just in case */ + for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next) + { + next = ifa->ifa_list.tqe_next; + + if (ifa->ifa_addr->sa_family != AF_INET6 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) { -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - ifaprev = ifa; -#endif continue; } ia = (struct in6_ifaddr *)ifa; -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined (__APPLE__) - /* leave from all multicast groups joined */ - while ((in6m = LIST_FIRST(&oia->ia6_multiaddrs)) != NULL) - in6_delmulti(in6m); -#endif - /* remove from the routing table */ if ((ia->ia_flags & IFA_ROUTE) - && (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0 -#if defined (__FreeBSD__) || defined (__APPLE__) - , 0UL -#endif - ))) { + && (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0, 0UL))) { rtflags = rt->rt_flags; rtfree(rt); rtrequest(RTM_DELETE, @@ -797,14 +947,8 @@ in6_ifdetach(ifp) } /* remove from the linked list */ -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - if (ifaprev) - ifaprev->ifa_next = ifa->ifa_next; - else - ifp->if_addrlist = ifa->ifa_next; -#else TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); -#endif + ifafree(&ia->ia_ifa); /* also remove from the IPv6 address chain(itojun&jinmei) */ oia = ia; @@ -815,18 +959,19 @@ in6_ifdetach(ifp) ia = ia->ia_next; if (ia->ia_next) ia->ia_next = oia->ia_next; -#if DEBUG - else - printf("%s: didn't unlink in6ifaddr from " - "list\n", if_name(ifp)); -#endif + else { + nd6log((LOG_ERR, + "%s: didn't unlink in6ifaddr from " + "list\n", if_name(ifp))); + } } - _FREE(ia, M_IFADDR); + IFAFREE(&oia->ia_ifa); } -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__) /* leave from all multicast groups joined */ + in6_pcbpurgeif0(LIST_FIRST(udbinfo.listhead), ifp); + in6_pcbpurgeif0(LIST_FIRST(ripcbinfo.listhead), ifp); for (in6m = LIST_FIRST(&in6_multihead); in6m; in6m = in6m_next) { in6m_next = LIST_NEXT(in6m, in6m_entry); if (in6m->in6m_ifp != ifp) @@ -834,14 +979,15 @@ in6_ifdetach(ifp) in6_delmulti(in6m); in6m = NULL; } -#endif -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__APPLE__) - /* cleanup multicast address kludge table, if there is any */ - in6_purgemkludge(ifp); -#endif - - /* remove neighbor management table */ + /* + * remove neighbor management table. we call it twice just to make + * sure we nuke everything. maybe we need just one call. + * XXX: since the first call did not release addresses, some prefixes + * might remain. We should call nd6_purge() again to release the + * prefixes after removing all addresses above. + * (Or can we just delay calling nd6_purge until at this point?) + */ nd6_purge(ifp); /* remove route to link-local allnodes multicast (ff02::1) */ @@ -850,14 +996,79 @@ in6_ifdetach(ifp) sin6.sin6_family = AF_INET6; sin6.sin6_addr = in6addr_linklocal_allnodes; sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index); -#if !defined(__FreeBSD__) && !defined (__APPLE__) - if ((rt = rtalloc1((struct sockaddr *)&sin6, 0)) != NULL) -#else - if ((rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL)) != NULL) -#endif - { + rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL); + if (rt && rt->rt_ifp == ifp) { rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt), rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0); rtfree(rt); } } + +void +in6_get_tmpifid(ifp, retbuf, baseid, generate) + struct ifnet *ifp; + u_int8_t *retbuf; + const u_int8_t *baseid; + int generate; +{ + u_int8_t nullbuf[8]; + struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index]; + + bzero(nullbuf, sizeof(nullbuf)); + if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) == 0) { + /* we've never created a random ID. Create a new one. */ + generate = 1; + } + + if (generate) { + bcopy(baseid, ndi->randomseed1, sizeof(ndi->randomseed1)); + + /* generate_tmp_ifid will update seedn and buf */ + (void)generate_tmp_ifid(ndi->randomseed0, ndi->randomseed1, + ndi->randomid); + } + bcopy(ndi->randomid, retbuf, 8); +} + +void +in6_tmpaddrtimer_funneled(void *ignored_arg) +{ +#ifdef __APPLE__ + boolean_t funnel_state; + funnel_state = thread_funnel_set(network_flock, TRUE); +#endif + in6_tmpaddrtimer(ignored_arg); +#ifdef __APPLE__ + (void) thread_funnel_set(network_flock, FALSE); +#endif +} + +void +in6_tmpaddrtimer(ignored_arg) + void *ignored_arg; +{ + int i; + struct nd_ifinfo *ndi; + u_int8_t nullbuf[8]; + int s = splnet(); + + timeout(in6_tmpaddrtimer_funneled, (caddr_t)0, + (ip6_temp_preferred_lifetime - ip6_desync_factor - + ip6_temp_regen_advance) * hz); + + bzero(nullbuf, sizeof(nullbuf)); + for (i = 1; i < if_index + 1; i++) { + ndi = &nd_ifinfo[i]; + if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) != 0) { + /* + * We've been generating a random ID on this interface. + * Create a new one. + */ + (void)generate_tmp_ifid(ndi->randomseed0, + ndi->randomseed1, + ndi->randomid); + } + } + + splx(s); +} diff --git a/bsd/netinet6/in6_ifattach.h b/bsd/netinet6/in6_ifattach.h index 4905f543b..de4a6fea4 100644 --- a/bsd/netinet6/in6_ifattach.h +++ b/bsd/netinet6/in6_ifattach.h @@ -31,20 +31,18 @@ #ifndef _NETINET6_IN6_IFATTACH_H_ #define _NETINET6_IN6_IFATTACH_H_ +#include -#if KERNEL -extern int found_first_ifid; - -int in6_ifattach_getifid __P((struct ifnet *)); -void in6_ifattach_p2p __P((void)); -void in6_ifattach __P((struct ifnet *, u_int, caddr_t, int)); +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE +void in6_nigroup_attach __P((const char *, int)); +void in6_nigroup_detach __P((const char *, int)); +void in6_ifattach __P((struct ifnet *, struct ifnet *)); void in6_ifdetach __P((struct ifnet *)); +void in6_get_tmpifid __P((struct ifnet *, u_int8_t *, const u_int8_t *, int)); +void in6_tmpaddrtimer __P((void *)); +int in6_nigroup __P((struct ifnet *, const char *, int, struct in6_addr *)); +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ -#define IN6_IFT_LOOP 1 -#define IN6_IFT_P2P 2 -#define IN6_IFT_802 3 -#define IN6_IFT_P2P802 4 -#define IN6_IFT_ARCNET 5 - #endif /* _NETINET6_IN6_IFATTACH_H_ */ diff --git a/bsd/netinet6/in6_pcb.c b/bsd/netinet6/in6_pcb.c index daa61ee2f..e2e04cd23 100644 --- a/bsd/netinet6/in6_pcb.c +++ b/bsd/netinet6/in6_pcb.c @@ -1,7 +1,7 @@ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -13,7 +13,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -25,6 +25,7 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * */ /* @@ -62,14 +63,11 @@ * @(#)in_pcb.c 8.2 (Berkeley) 1/4/94 */ -#ifdef __NetBSD__ /*XXX*/ -#include "opt_ipsec.h" -#endif - #include #include #include #include +#include #include #include #include @@ -86,6 +84,7 @@ #include #include #include +#include #include #include #include @@ -93,14 +92,23 @@ #include #include "faith.h" +#if defined(NFAITH) && NFAITH > 0 +#include +#endif #if IPSEC #include +#if INET6 +#include +#endif +#include +#if INET6 +#include +#endif #include -#include #endif /* IPSEC */ -struct in6_addr zeroin6_addr; +struct in6_addr zeroin6_addr; int in6_pcbbind(inp, nam, p) @@ -109,60 +117,32 @@ in6_pcbbind(inp, nam, p) struct proc *p; { struct socket *so = inp->inp_socket; - unsigned short *lastport; struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)NULL; struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; u_short lport = 0; int wild = 0, reuseport = (so->so_options & SO_REUSEPORT); - int error; if (!in6_ifaddr) /* XXX broken! */ return (EADDRNOTAVAIL); if (inp->inp_lport || !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) return(EINVAL); if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0) - wild = INPLOOKUP_WILDCARD; + wild = 1; if (nam) { + sin6 = (struct sockaddr_in6 *)nam; if (nam->sa_len != sizeof(*sin6)) return(EINVAL); /* - * We should check the family, but old programs - * incorrectly fail to intialize it. + * family check. */ if (nam->sa_family != AF_INET6) return(EAFNOSUPPORT); - sin6 = (struct sockaddr_in6 *)nam; - /* - * If the scope of the destination is link-local, embed the - * interface index in the address. - */ - if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) { - /* XXX boundary check is assumed to be already done. */ - /* XXX sin6_scope_id is weaker than advanced-api. */ - struct in6_pktinfo *pi; - if (inp->in6p_outputopts && - (pi = inp->in6p_outputopts->ip6po_pktinfo) && - pi->ipi6_ifindex) { - sin6->sin6_addr.s6_addr16[1] - = htons(pi->ipi6_ifindex); - } else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr) - && inp->in6p_moptions - && inp->in6p_moptions->im6o_multicast_ifp) { - sin6->sin6_addr.s6_addr16[1] = - htons(inp->in6p_moptions->im6o_multicast_ifp->if_index); - } else if (sin6->sin6_scope_id) { - /* boundary check */ - if (sin6->sin6_scope_id < 0 - || if_index < sin6->sin6_scope_id) { - return ENXIO; /* XXX EINVAL? */ - } - sin6->sin6_addr.s6_addr16[1] - = htons(sin6->sin6_scope_id & 0xffff);/*XXX*/ - /* this must be cleared for ifa_ifwithaddr() */ - sin6->sin6_scope_id = 0; - } - } + /* KAME hack: embed scopeid */ + if (in6_embedscope(&sin6->sin6_addr, sin6, inp, NULL) != 0) + return EINVAL; + /* this must be cleared for ifa_ifwithaddr() */ + sin6->sin6_scope_id = 0; lport = sin6->sin6_port; if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { @@ -185,11 +165,12 @@ in6_pcbbind(inp, nam, p) /* * XXX: bind to an anycast address might accidentally * cause sending a packet with anycast source address. + * We should allow to bind to a deprecated address, since + * the application dare to use it. */ if (ia && ((struct in6_ifaddr *)ia)->ia6_flags & - (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY| - IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) { + (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|IN6_IFF_DETACHED)) { return(EADDRNOTAVAIL); } } @@ -207,10 +188,9 @@ in6_pcbbind(inp, nam, p) if (so->so_uid && !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { - t = in6_pcblookup_local(inp->inp_pcbinfo, - &sin6->sin6_addr, - lport, - INPLOOKUP_WILDCARD); + t = in6_pcblookup_local(pcbinfo, + &sin6->sin6_addr, lport, + INPLOOKUP_WILDCARD); if (t && (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || !IN6_IS_ADDR_UNSPECIFIED(&t->in6p_laddr) || @@ -218,98 +198,60 @@ in6_pcbbind(inp, nam, p) SO_REUSEPORT) == 0) && so->so_uid != t->inp_socket->so_uid) return (EADDRINUSE); + if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 && + IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { + struct sockaddr_in sin; + + in6_sin6_2_sin(&sin, sin6); + t = in_pcblookup_local(pcbinfo, + sin.sin_addr, lport, + INPLOOKUP_WILDCARD); + if (t && + (so->so_uid != + t->inp_socket->so_uid) && + (ntohl(t->inp_laddr.s_addr) != + INADDR_ANY || + INP_SOCKAF(so) == + INP_SOCKAF(t->inp_socket))) + return (EADDRINUSE); + } } t = in6_pcblookup_local(pcbinfo, &sin6->sin6_addr, lport, wild); if (t && (reuseport & t->inp_socket->so_options) == 0) return(EADDRINUSE); + if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 && + IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { + struct sockaddr_in sin; + + in6_sin6_2_sin(&sin, sin6); + t = in_pcblookup_local(pcbinfo, sin.sin_addr, + lport, wild); + if (t && + (reuseport & t->inp_socket->so_options) + == 0 && + (ntohl(t->inp_laddr.s_addr) + != INADDR_ANY || + INP_SOCKAF(so) == + INP_SOCKAF(t->inp_socket))) + return (EADDRINUSE); + } } inp->in6p_laddr = sin6->sin6_addr; } if (lport == 0) { - ushort first, last; - int count; - - inp->inp_flags |= INP_ANONPORT; - - if (inp->inp_flags & INP_HIGHPORT) { - first = ipport_hifirstauto; /* sysctl */ - last = ipport_hilastauto; - lastport = &pcbinfo->lasthi; - } else if (inp->inp_flags & INP_LOWPORT) { -#if 0 - if (p && (error = suser(p->p_ucred, &p->p_acflag))) - return error; -#else - if ((so->so_state & SS_PRIV) == 0) - return (EPERM); -#endif - first = ipport_lowfirstauto; /* 1023 */ - last = ipport_lowlastauto; /* 600 */ - lastport = &pcbinfo->lastlow; - } else { - first = ipport_firstauto; /* sysctl */ - last = ipport_lastauto; - lastport = &pcbinfo->lastport; - } - /* - * Simple check to ensure all ports are not used up causing - * a deadlock here. - * - * We split the two cases (up and down) so that the direction - * is not being tested on each round of the loop. - */ - if (first > last) { - /* - * counting down - */ - count = first - last; - - do { - if (count-- < 0) { /* completely used? */ - /* - * Undo any address bind that may have - * occurred above. - */ - inp->in6p_laddr = in6addr_any; - return (EAGAIN); - } - --*lastport; - if (*lastport > first || *lastport < last) - *lastport = first; - lport = htons(*lastport); - } while (in6_pcblookup_local(pcbinfo, - &inp->in6p_laddr, lport, wild)); - } else { - /* - * counting up - */ - count = last - first; - - do { - if (count-- < 0) { /* completely used? */ - /* - * Undo any address bind that may have - * occurred above. - */ - inp->in6p_laddr = in6addr_any; - return (EAGAIN); - } - ++*lastport; - if (*lastport < first || *lastport > last) - *lastport = first; - lport = htons(*lastport); - } while (in6_pcblookup_local(pcbinfo, - &inp->in6p_laddr, lport, wild)); - } + int e; + if ((e = in6_pcbsetport(&inp->in6p_laddr, inp, p)) != 0) + return(e); } - inp->inp_lport = lport; - if (in_pcbinshash(inp) != 0) { - inp->in6p_laddr = in6addr_any; - inp->inp_lport = 0; - return (EAGAIN); + else { + inp->inp_lport = lport; + if (in_pcbinshash(inp) != 0) { + inp->in6p_laddr = in6addr_any; + inp->inp_lport = 0; + return (EAGAIN); + } } - inp->in6p_flowinfo = sin6 ? sin6->sin6_flowinfo : 0; /*XXX*/ return(0); } @@ -332,7 +274,6 @@ in6_pcbladdr(inp, nam, plocal_addr6) struct in6_addr **plocal_addr6; { register struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam; - struct in6_pktinfo *pi; struct ifnet *ifp = NULL; int error = 0; @@ -343,44 +284,15 @@ in6_pcbladdr(inp, nam, plocal_addr6) if (sin6->sin6_port == 0) return (EADDRNOTAVAIL); - /* - * If the scope of the destination is link-local, embed the interface - * index in the address. - */ - if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) { - /* XXX boundary check is assumed to be already done. */ - /* XXX sin6_scope_id is weaker than advanced-api. */ - if (inp->in6p_outputopts && - (pi = inp->in6p_outputopts->ip6po_pktinfo) && - pi->ipi6_ifindex) { - sin6->sin6_addr.s6_addr16[1] = htons(pi->ipi6_ifindex); - ifp = ifindex2ifnet[pi->ipi6_ifindex]; - } - else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr) && - inp->in6p_moptions && - inp->in6p_moptions->im6o_multicast_ifp) { - sin6->sin6_addr.s6_addr16[1] = - htons(inp->in6p_moptions->im6o_multicast_ifp->if_index); - ifp = ifindex2ifnet[inp->in6p_moptions->im6o_multicast_ifp->if_index]; - } else if (sin6->sin6_scope_id) { - /* boundary check */ - if (sin6->sin6_scope_id < 0 - || if_index < sin6->sin6_scope_id) { - return ENXIO; /* XXX EINVAL? */ - } - sin6->sin6_addr.s6_addr16[1] - = htons(sin6->sin6_scope_id & 0xffff);/*XXX*/ - ifp = ifindex2ifnet[sin6->sin6_scope_id]; - } - } + /* KAME hack: embed scopeid */ + if (in6_embedscope(&sin6->sin6_addr, sin6, inp, &ifp) != 0) + return EINVAL; if (in6_ifaddr) { /* * If the destination address is UNSPECIFIED addr, * use the loopback addr, e.g ::1. */ -#define satosin6(sa) ((struct sockaddr_in6 *)(sa)) -#define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa)) if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) sin6->sin6_addr = in6addr_loopback; } @@ -400,7 +312,7 @@ in6_pcbladdr(inp, nam, plocal_addr6) return(error); } /* - * Don't do pcblookup call here; return interface in + * Don't do pcblookup call here; return interface in * plocal_addr6 * and exit to caller, that will do the lookup. */ @@ -432,7 +344,7 @@ in6_pcbconnect(inp, nam, p) /* * Call inner routine, to assign local interface address. */ - if (error = in6_pcbladdr(inp, nam, &addr6)) + if ((error = in6_pcbladdr(inp, nam, &addr6)) != 0) return(error); if (in6_pcblookup_hash(inp->inp_pcbinfo, &sin6->sin6_addr, @@ -452,11 +364,11 @@ in6_pcbconnect(inp, nam, p) } inp->in6p_faddr = sin6->sin6_addr; inp->inp_fport = sin6->sin6_port; - /* - * xxx kazu flowlabel is necessary for connect? - * but if this line is missing, the garbage value remains. - */ - inp->in6p_flowinfo = sin6->sin6_flowinfo; + /* update flowinfo - draft-itojun-ipv6-flowlabel-api-00 */ + inp->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK; + if (inp->in6p_flags & IN6P_AUTOFLOWLABEL) + inp->in6p_flowinfo |= + (htonl(ip6_flow_seq++) & IPV6_FLOWLABEL_MASK); in_pcbrehash(inp); return (0); @@ -556,16 +468,9 @@ in6_selectsrc(dstsock, opts, mopts, ro, laddr, errorp) */ if (IN6_IS_ADDR_MULTICAST(dst)) { struct ifnet *ifp = mopts ? mopts->im6o_multicast_ifp : NULL; -#ifdef __bsdi__ - extern struct ifnet loif; -#endif if (ifp == NULL && IN6_IS_ADDR_MC_NODELOCAL(dst)) { -#ifdef __bsdi__ - ifp = &loif; -#else ifp = &loif[0]; -#endif } if (ifp) { @@ -610,25 +515,22 @@ in6_selectsrc(dstsock, opts, mopts, ro, laddr, errorp) if (ro) { if (ro->ro_rt && !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr, dst)) { - RTFREE(ro->ro_rt); + rtfree(ro->ro_rt); ro->ro_rt = (struct rtentry *)0; } if (ro->ro_rt == (struct rtentry *)0 || ro->ro_rt->rt_ifp == (struct ifnet *)0) { + struct sockaddr_in6 *dst6; + /* No route yet, so try to acquire one */ bzero(&ro->ro_dst, sizeof(struct sockaddr_in6)); - ro->ro_dst.sin6_family = AF_INET6; - ro->ro_dst.sin6_len = sizeof(struct sockaddr_in6); - ro->ro_dst.sin6_addr = *dst; + dst6 = (struct sockaddr_in6 *)&ro->ro_dst; + dst6->sin6_family = AF_INET6; + dst6->sin6_len = sizeof(struct sockaddr_in6); + dst6->sin6_addr = *dst; if (IN6_IS_ADDR_MULTICAST(dst)) { -#if defined(__FreeBSD__) || defined (__APPLE__) ro->ro_rt = rtalloc1(&((struct route *)ro) ->ro_dst, 0, 0UL); -#endif /*__FreeBSD__*/ -#if defined(__bsdi__) || defined(__NetBSD__) - ro->ro_rt = rtalloc1(&((struct route *)ro) - ->ro_dst, 0); -#endif /*__bsdi__*/ } else { rtalloc((struct route *)ro); } @@ -646,27 +548,6 @@ in6_selectsrc(dstsock, opts, mopts, ro, laddr, errorp) if (ia6 == 0) /* xxx scope error ?*/ ia6 = ifatoia6(ro->ro_rt->rt_ifa); } -#if 0 - /* - * xxx The followings are necessary? (kazu) - * I don't think so. - * It's for SO_DONTROUTE option in IPv4.(jinmei) - */ - if (ia6 == 0) { - struct sockaddr_in6 sin6 = {sizeof(sin6), AF_INET6, 0}; - - sin6->sin6_addr = *dst; - - ia6 = ifatoia6(ifa_ifwithdstaddr(sin6tosa(&sin6))); - if (ia6 == 0) - ia6 = ifatoia6(ifa_ifwithnet(sin6tosa(&sin6))); - if (ia6 == 0) { - *errorp = EHOSTUNREACH; /* no route */ - return(0); - } - return(&satosin6(&ia6->ia_addr)->sin6_addr); - } -#endif /* 0 */ if (ia6 == 0) { *errorp = EHOSTUNREACH; /* no route */ return(0); @@ -705,6 +586,8 @@ in6_pcbdisconnect(inp) { bzero((caddr_t)&inp->in6p_faddr, sizeof(inp->in6p_faddr)); inp->inp_fport = 0; + /* clear flowinfo - draft-itojun-ipv6-flowlabel-api-00 */ + inp->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK; in_pcbrehash(inp); if (inp->inp_socket->so_state & SS_NOFDREF) in6_pcbdetach(inp); @@ -718,20 +601,25 @@ in6_pcbdetach(inp) struct inpcbinfo *ipi = inp->inp_pcbinfo; #if IPSEC - ipsec6_delete_pcbpolicy(inp); + if (inp->in6p_sp != NULL) + ipsec6_delete_pcbpolicy(inp); #endif /* IPSEC */ inp->inp_gencnt = ++ipi->ipi_gencnt; in_pcbremlists(inp); sotoinpcb(so) = 0; sofree(so); - if (inp->in6p_inputopts) /* Free all received options. */ - m_freem(inp->in6p_inputopts->head); /* this is safe */ - ip6_freepcbopts(inp->in6p_outputopts); - ip6_freemoptions(inp->in6p_moptions); - + if (inp->in6p_options) + m_freem(inp->in6p_options); + ip6_freepcbopts(inp->in6p_outputopts); + ip6_freemoptions(inp->in6p_moptions); if (inp->in6p_route.ro_rt) rtfree(inp->in6p_route.ro_rt); + /* Check and free IPv4 related resources in case of mapped addr */ + if (inp->inp_options) + (void)m_free(inp->inp_options); + ip_freemoptions(inp->inp_moptions); + inp->inp_vflag = 0; zfree(ipi->ipi_zone, inp); } @@ -853,7 +741,7 @@ in6_mapped_peeraddr(struct socket *so, struct sockaddr **nam) if (error == 0) in6_sin_2_v4mapsin6_in_sock(nam); } else - error = in6_setpeeraddr(so, nam); + error = in6_setpeeraddr(so, nam); return error; } @@ -870,28 +758,32 @@ in6_mapped_peeraddr(struct socket *so, struct sockaddr **nam) * Must be called at splnet. */ void -in6_pcbnotify(head, dst, fport_arg, laddr6, lport_arg, cmd, notify) +in6_pcbnotify(head, dst, fport_arg, src, lport_arg, cmd, notify) struct inpcbhead *head; - struct sockaddr *dst; + struct sockaddr *dst, *src; u_int fport_arg, lport_arg; - struct in6_addr *laddr6; int cmd; void (*notify) __P((struct inpcb *, int)); { struct inpcb *inp, *ninp; - struct in6_addr faddr6; + struct sockaddr_in6 sa6_src, *sa6_dst; u_short fport = fport_arg, lport = lport_arg; + u_int32_t flowinfo; int errno, s; - void (*notify2) __P((struct inpcb *, int)); - - notify2 = NULL; if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET6) return; - faddr6 = ((struct sockaddr_in6 *)dst)->sin6_addr; - if (IN6_IS_ADDR_UNSPECIFIED(&faddr6)) + + sa6_dst = (struct sockaddr_in6 *)dst; + if (IN6_IS_ADDR_UNSPECIFIED(&sa6_dst->sin6_addr)) return; + /* + * note that src can be NULL when we get notify by local fragmentation. + */ + sa6_src = (src == NULL) ? sa6_any : *(struct sockaddr_in6 *)src; + flowinfo = sa6_src.sin6_flowinfo; + /* * Redirects go to all references to the destination, * and use in6_rtchange to invalidate the route cache. @@ -903,51 +795,43 @@ in6_pcbnotify(head, dst, fport_arg, laddr6, lport_arg, cmd, notify) if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) { fport = 0; lport = 0; - bzero((caddr_t)laddr6, sizeof(*laddr6)); - - /* - * Keep the old notify function to store a soft error - * in each PCB. - */ - if (cmd == PRC_HOSTDEAD && notify != in6_rtchange) - notify2 = notify; + bzero((caddr_t)&sa6_src.sin6_addr, sizeof(sa6_src.sin6_addr)); - notify = in6_rtchange; + if (cmd != PRC_HOSTDEAD) + notify = in6_rtchange; } errno = inet6ctlerrmap[cmd]; s = splnet(); - for (inp = LIST_FIRST(head); inp != NULL; inp = ninp) { - ninp = LIST_NEXT(inp, inp_list); + for (inp = LIST_FIRST(head); inp != NULL; inp = ninp) { + ninp = LIST_NEXT(inp, inp_list); - if ((inp->inp_vflag & INP_IPV6) == 0) + if ((inp->inp_vflag & INP_IPV6) == 0) continue; - if (notify == in6_rtchange) { - /* - * Since a non-connected PCB might have a cached route, - * we always call in6_rtchange without matching - * the PCB to the src/dst pair. - * - * XXX: we assume in6_rtchange does not free the PCB. - */ - if (IN6_ARE_ADDR_EQUAL(&inp->in6p_route.ro_dst.sin6_addr, - &faddr6)) - in6_rtchange(inp, errno); - - if (notify2 == NULL) - continue; - - notify = notify2; - } - - if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, &faddr6) || - inp->inp_socket == 0 || - (lport && inp->inp_lport != lport) || - (!IN6_IS_ADDR_UNSPECIFIED(laddr6) && - !IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr6)) || - (fport && inp->inp_fport != fport)) + /* + * Detect if we should notify the error. If no source and + * destination ports are specifed, but non-zero flowinfo and + * local address match, notify the error. This is the case + * when the error is delivered with an encrypted buffer + * by ESP. Otherwise, just compare addresses and ports + * as usual. + */ + if (lport == 0 && fport == 0 && flowinfo && + inp->inp_socket != NULL && + flowinfo == (inp->in6p_flowinfo & IPV6_FLOWLABEL_MASK) && + IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, &sa6_src.sin6_addr)) + goto do_notify; + else if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, + &sa6_dst->sin6_addr) || + inp->inp_socket == 0 || + (lport && inp->inp_lport != lport) || + (!IN6_IS_ADDR_UNSPECIFIED(&sa6_src.sin6_addr) && + !IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, + &sa6_src.sin6_addr)) || + (fport && inp->inp_fport != fport)) continue; + do_notify: if (notify) (*notify)(inp, errno); } @@ -1043,6 +927,45 @@ in6_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay) } } +void +in6_pcbpurgeif0(head, ifp) + struct in6pcb *head; + struct ifnet *ifp; +{ + struct in6pcb *in6p; + struct ip6_moptions *im6o; + struct in6_multi_mship *imm, *nimm; + + for (in6p = head; in6p != NULL; in6p = LIST_NEXT(in6p, inp_list)) { + im6o = in6p->in6p_moptions; + if ((in6p->inp_vflag & INP_IPV6) && + im6o) { + /* + * Unselect the outgoing interface if it is being + * detached. + */ + if (im6o->im6o_multicast_ifp == ifp) + im6o->im6o_multicast_ifp = NULL; + + /* + * Drop multicast group membership if we joined + * through the interface being detached. + * XXX controversial - is it really legal for kernel + * to force this? + */ + for (imm = im6o->im6o_memberships.lh_first; + imm != NULL; imm = nimm) { + nimm = imm->i6mm_chain.le_next; + if (imm->i6mm_maddr->in6m_ifp == ifp) { + LIST_REMOVE(imm, i6mm_chain); + in6_delmulti(imm->i6mm_maddr); + FREE(imm, M_IPMADDR); + } + } + } + } +} + /* * Check for alternatives when higher level complains * about service problems. For now, invalidate cached @@ -1110,6 +1033,13 @@ in6_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, ifp) struct inpcbhead *head; register struct inpcb *inp; u_short fport = fport_arg, lport = lport_arg; + int faith; + +#if defined(NFAITH) && NFAITH > 0 + faith = faithprefix(laddr); +#else + faith = 0; +#endif /* * First look for an exact match. @@ -1117,7 +1047,7 @@ in6_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, ifp) head = &pcbinfo->hashbase[INP_PCBHASH(faddr->s6_addr32[3] /* XXX */, lport, fport, pcbinfo->hashmask)]; - for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { + LIST_FOREACH(inp, head, inp_hash) { if ((inp->inp_vflag & INP_IPV6) == 0) continue; if (IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, faddr) && @@ -1135,17 +1065,13 @@ in6_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, ifp) head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)]; - for (inp = head->lh_first; inp != NULL; - inp = inp->inp_hash.le_next) { + LIST_FOREACH(inp, head, inp_hash) { if ((inp->inp_vflag & INP_IPV6) == 0) continue; if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) && inp->inp_lport == lport) { -#if defined(NFAITH) && NFAITH > 0 - if (ifp && ifp->if_type == IFT_FAITH && - (inp->inp_flags & INP_FAITH) == 0) + if (faith && (inp->inp_flags & INP_FAITH) == 0) continue; -#endif if (IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr)) return (inp); diff --git a/bsd/netinet6/in6_pcb.h b/bsd/netinet6/in6_pcb.h index 8620c248b..a3dbf5ba6 100644 --- a/bsd/netinet6/in6_pcb.h +++ b/bsd/netinet6/in6_pcb.h @@ -25,6 +25,7 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * */ /* @@ -64,12 +65,15 @@ #ifndef _NETINET6_IN6_PCB_H_ #define _NETINET6_IN6_PCB_H_ +#include #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE #define satosin6(sa) ((struct sockaddr_in6 *)(sa)) #define sin6tosa(sin6) ((struct sockaddr *)(sin6)) #define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa)) +void in6_pcbpurgeif0 __P((struct in6pcb *, struct ifnet *)); void in6_losing __P((struct inpcb *)); int in6_pcballoc __P((struct socket *, struct inpcbinfo *, struct proc *)); int in6_pcbbind __P((struct inpcb *, struct sockaddr *, struct proc *)); @@ -86,7 +90,7 @@ struct inpcb * struct in6_addr *, u_int, struct in6_addr *, u_int, int, struct ifnet *)); void in6_pcbnotify __P((struct inpcbhead *, struct sockaddr *, - u_int, struct in6_addr *, u_int, int, + u_int, struct sockaddr *, u_int, int, void (*)(struct inpcb *, int))); void in6_rtchange __P((struct inpcb *, int)); int in6_setpeeraddr __P((struct socket *so, struct sockaddr **nam)); @@ -98,9 +102,10 @@ struct in6_addr *in6_selectsrc __P((struct sockaddr_in6 *, struct ip6_moptions *, struct route_in6 *, struct in6_addr *, int *)); -int in6_selecthlim __P((struct inpcb *, struct ifnet *)); - +int in6_selecthlim __P((struct in6pcb *, struct ifnet *)); +int in6_pcbsetport __P((struct in6_addr *, struct inpcb *, struct proc *)); void init_sin6 __P((struct sockaddr_in6 *sin6, struct mbuf *m)); +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ #endif /* !_NETINET6_IN6_PCB_H_ */ diff --git a/bsd/netinet6/in6_prefix.c b/bsd/netinet6/in6_prefix.c index a1afb0124..b9096fe2b 100644 --- a/bsd/netinet6/in6_prefix.c +++ b/bsd/netinet6/in6_prefix.c @@ -65,9 +65,6 @@ */ #include -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) -#include -#endif #include #include #include @@ -75,9 +72,7 @@ #include #include #include -#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) #include -#endif #include @@ -87,9 +82,12 @@ #include #include -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -static MALLOC_DEFINE(M_IPFW, "ip6rr", "IPv6 Router Renumbering Prefix"); -static MALLOC_DEFINE(M_IPFW, "rp_addr", "IPv6 Router Renumbering Ifid"); +#ifdef __APPLE__ +#define M_IP6RR M_IP6MISC +#define M_RR_ADDR M_IP6MISC +#else +static MALLOC_DEFINE(M_IP6RR, "ip6rr", "IPv6 Router Renumbering Prefix"); +static MALLOC_DEFINE(M_RR_ADDR, "rp_addr", "IPv6 Router Renumbering Ifid"); #endif struct rr_prhead rr_prefix; @@ -160,7 +158,9 @@ in6_prefixwithifp(struct ifnet *ifp, int plen, struct in6_addr *dst) struct ifprefix *ifpr; /* search matched prefix */ - for (ifpr = ifp->if_prefixlist; ifpr; ifpr = ifpr->ifpr_next) { + for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr; + ifpr = TAILQ_NEXT(ifpr, ifpr_list)) + { if (ifpr->ifpr_prefix->sa_family != AF_INET6 || ifpr->ifpr_type != IN6_PREFIX_RR) continue; @@ -192,11 +192,7 @@ search_matched_prefix(struct ifnet *ifp, struct in6_prefixreq *ipr) * which matches the addr */ -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) -#else - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) -#endif + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; @@ -211,7 +207,9 @@ search_matched_prefix(struct ifnet *ifp, struct in6_prefixreq *ipr) if (rpp != 0) return rpp; - for (ifpr = ifp->if_prefixlist; ifpr; ifpr = ifpr->ifpr_next) { + for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr; + ifpr = TAILQ_NEXT(ifpr, ifpr_list)) + { if (ifpr->ifpr_prefix->sa_family != AF_INET6 || ifpr->ifpr_type != IN6_PREFIX_RR) continue; @@ -239,7 +237,9 @@ mark_matched_prefixes(u_long cmd, struct ifnet *ifp, struct in6_rrenumreq *irr) int matchlen, matched = 0; /* search matched prefixes */ - for (ifpr = ifp->if_prefixlist; ifpr; ifpr = ifpr->ifpr_next) { + for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr; + ifpr = TAILQ_NEXT(ifpr, ifpr_list)) + { if (ifpr->ifpr_prefix->sa_family != AF_INET6 || ifpr->ifpr_type != IN6_PREFIX_RR) continue; @@ -259,11 +259,7 @@ mark_matched_prefixes(u_long cmd, struct ifnet *ifp, struct in6_rrenumreq *irr) * search matched addr, and then search prefixes * which matche the addr */ -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) -#else - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) -#endif + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { struct rr_prefix *rpp; @@ -298,7 +294,9 @@ delmark_global_prefixes(struct ifnet *ifp, struct in6_rrenumreq *irr) struct ifprefix *ifpr; /* search matched prefixes */ - for (ifpr = ifp->if_prefixlist; ifpr; ifpr = ifpr->ifpr_next) { + for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr; + ifpr = TAILQ_NEXT(ifpr, ifpr_list)) + { if (ifpr->ifpr_prefix->sa_family != AF_INET6 || ifpr->ifpr_type != IN6_PREFIX_RR) continue; @@ -316,7 +314,9 @@ unmark_prefixes(struct ifnet *ifp) struct ifprefix *ifpr; /* unmark all prefix */ - for (ifpr = ifp->if_prefixlist; ifpr; ifpr = ifpr->ifpr_next) { + for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr; + ifpr = TAILQ_NEXT(ifpr, ifpr_list)) + { if (ifpr->ifpr_prefix->sa_family != AF_INET6 || ifpr->ifpr_type != IN6_PREFIX_RR) continue; @@ -329,9 +329,6 @@ unmark_prefixes(struct ifnet *ifp) static void init_prefix_ltimes(struct rr_prefix *rpp) { -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined (__APPLE__) - long time_second = time.tv_sec; -#endif if (rpp->rp_pltime == RR_INFINITE_LIFETIME || rpp->rp_rrf_decrprefd == 0) @@ -380,17 +377,18 @@ search_ifidwithprefix(struct rr_prefix *rpp, struct in6_addr *ifid) { struct rp_addr *rap; - for (rap = rpp->rp_addrhead.lh_first; rap != NULL; - rap = rap->ra_entry.le_next) + LIST_FOREACH(rap, &rpp->rp_addrhead, ra_entry) + { if (rr_are_ifid_equal(ifid, &rap->ra_ifid, (sizeof(struct in6_addr) << 3) - rpp->rp_plen)) break; + } return rap; } static int -assigne_ra_entry(struct rr_prefix *rpp, int iilen, struct in6_ifaddr *ia) +assign_ra_entry(struct rr_prefix *rpp, int iilen, struct in6_ifaddr *ia) { int error = 0; struct rp_addr *rap; @@ -405,7 +403,7 @@ assigne_ra_entry(struct rr_prefix *rpp, int iilen, struct in6_ifaddr *ia) sizeof(*IA6_IN6(ia)) << 3, rpp->rp_plen, iilen); /* link to ia, and put into list */ rap->ra_addr = ia; - rap->ra_addr->ia_ifa.ifa_refcnt++; + ifaref(&rap->ra_addr->ia_ifa); #if 0 /* Can't do this now, because rpp may be on th stack. should fix it? */ ia->ia6_ifpr = rp2ifpr(rpp); #endif @@ -416,6 +414,10 @@ assigne_ra_entry(struct rr_prefix *rpp, int iilen, struct in6_ifaddr *ia) return 0; } +/* + * add a link-local address to an interface. we will add new interface address + * (prefix database + new interface id). + */ static int in6_prefix_add_llifid(int iilen, struct in6_ifaddr *ia) { @@ -433,12 +435,14 @@ in6_prefix_add_llifid(int iilen, struct in6_ifaddr *ia) /* XXX: init dummy so */ bzero(&so, sizeof(so)); /* insert into list */ -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) LIST_FOREACH(rpp, &rr_prefix, rp_entry) -#else - for (rpp = LIST_FIRST(&rr_prefix); rpp; rpp = LIST_NEXT(rpp, rp_entry)) -#endif { + /* + * do not attempt to add an address, if ifp does not match + */ + if (rpp->rp_ifp != ia->ia_ifp) + continue; + s = splnet(); LIST_INSERT_HEAD(&rpp->rp_addrhead, rap, ra_entry); splx(s); @@ -447,7 +451,10 @@ in6_prefix_add_llifid(int iilen, struct in6_ifaddr *ia) return 0; } - +/* + * add an address to an interface. if the interface id portion is new, + * we will add new interface address (prefix database + new interface id). + */ int in6_prefix_add_ifid(int iilen, struct in6_ifaddr *ia) { @@ -462,7 +469,7 @@ in6_prefix_add_ifid(int iilen, struct in6_ifaddr *ia) if (ifpr == NULL) { struct rr_prefix rp; struct socket so; - int pplen = (plen == 128) ? 64 : plen; + int pplen = (plen == 128) ? 64 : plen; /* XXX hardcoded 64 is bad */ /* allocate a prefix for ia, with default properties */ @@ -493,9 +500,6 @@ in6_prefix_add_ifid(int iilen, struct in6_ifaddr *ia) /* XXX: init dummy so */ bzero(&so, sizeof(so)); -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__NetBSD__) - so.so_state |= SS_PRIV; -#endif error = add_each_prefix(&so, &rp); @@ -514,11 +518,11 @@ in6_prefix_add_ifid(int iilen, struct in6_ifaddr *ia) if (rap != NULL) { if (rap->ra_addr == NULL) { rap->ra_addr = ia; - rap->ra_addr->ia_ifa.ifa_refcnt++; + ifaref(&rap->ra_addr->ia_ifa); } else if (rap->ra_addr != ia) { /* There may be some inconsistencies between addrs. */ log(LOG_ERR, "ip6_prefix.c: addr %s/%d matched prefix" - "has already another ia %x(%s) on its ifid list\n", + " already has another ia %p(%s) on its ifid list\n", ip6_sprintf(IA6_IN6(ia)), plen, rap->ra_addr, ip6_sprintf(IA6_IN6(rap->ra_addr))); @@ -527,7 +531,7 @@ in6_prefix_add_ifid(int iilen, struct in6_ifaddr *ia) ia->ia6_ifpr = ifpr; return 0; } - error = assigne_ra_entry(ifpr2rp(ifpr), iilen, ia); + error = assign_ra_entry(ifpr2rp(ifpr), iilen, ia); if (error == 0) ia->ia6_ifpr = ifpr; return (error); @@ -546,15 +550,11 @@ in6_prefix_remove_ifid(int iilen, struct in6_ifaddr *ia) LIST_REMOVE(rap, ra_entry); splx(s); if (rap->ra_addr) - IFAFREE(&rap->ra_addr->ia_ifa); - _FREE(rap, M_IPFW); + ifafree(&rap->ra_addr->ia_ifa); + FREE(rap, M_RR_ADDR); } -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) if (LIST_EMPTY(&ifpr2rp(ia->ia6_ifpr)->rp_addrhead)) -#else - if (LIST_FIRST(&ifpr2rp(ia->ia6_ifpr)->rp_addrhead) == NULL) -#endif rp_remove(ifpr2rp(ia->ia6_ifpr)); } @@ -565,18 +565,10 @@ in6_purgeprefix(ifp) struct ifprefix *ifpr, *nextifpr; /* delete prefixes before ifnet goes away */ -#if defined(__FreeBSD__) && __FreeBSD__ >= 4 for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr; ifpr = nextifpr) -#else - for (ifpr = ifp->if_prefixlist; ifpr; ifpr = nextifpr) -#endif { -#if defined(__FreeBSD__) && __FreeBSD__ >= 4 nextifpr = TAILQ_NEXT(ifpr, ifpr_list); -#else - nextifpr = ifpr->ifpr_next; -#endif if (ifpr->ifpr_prefix->sa_family != AF_INET6 || ifpr->ifpr_type != IN6_PREFIX_RR) continue; @@ -611,20 +603,30 @@ add_each_addr(struct socket *so, struct rr_prefix *rpp, struct rp_addr *rap) in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, rpp->rp_plen); /* don't care ifra_flags for now */ + /* + * XXX: if we did this with finite lifetime values, the lifetimes would + * decrese in time and never incremented. + * we should need more clarifications on the prefix mechanism... + */ + ifra.ifra_lifetime.ia6t_vltime = rpp->rp_vltime; + ifra.ifra_lifetime.ia6t_pltime = rpp->rp_pltime; + ia6 = in6ifa_ifpwithaddr(rpp->rp_ifp, &ifra.ifra_addr.sin6_addr); if (ia6 != NULL) { if (ia6->ia6_ifpr == NULL) { /* link this addr and the prefix each other */ - IFAFREE(&rap->ra_addr->ia_ifa); + if (rap->ra_addr) + ifafree(&rap->ra_addr->ia_ifa); rap->ra_addr = ia6; - rap->ra_addr->ia_ifa.ifa_refcnt++; + ifaref(&rap->ra_addr->ia_ifa); ia6->ia6_ifpr = rp2ifpr(rpp); return; } if (ia6->ia6_ifpr == rp2ifpr(rpp)) { - IFAFREE(&rap->ra_addr->ia_ifa); + if (rap->ra_addr) + ifafree(&rap->ra_addr->ia_ifa); rap->ra_addr = ia6; - rap->ra_addr->ia_ifa.ifa_refcnt++; + ifaref(&rap->ra_addr->ia_ifa); return; } /* @@ -637,27 +639,26 @@ add_each_addr(struct socket *so, struct rr_prefix *rpp, struct rp_addr *rap) * Or, completely duplicated prefixes? * log it and return. */ - log(LOG_ERR, "in6_prefix.c: add_each_addr: addition of an addr" - "%s/%d failed because there is already another addr %s/%d\n", + log(LOG_ERR, + "in6_prefix.c: add_each_addr: addition of an addr %s/%d " + "failed because there is already another addr %s/%d\n", ip6_sprintf(&ifra.ifra_addr.sin6_addr), rpp->rp_plen, ip6_sprintf(IA6_IN6(ia6)), - in6_mask2len(&ia6->ia_prefixmask.sin6_addr)); + in6_mask2len(&ia6->ia_prefixmask.sin6_addr, NULL)); return; } /* propagate ANYCAST flag if it is set for ancestor addr */ if (rap->ra_flags.anycast != 0) ifra.ifra_flags |= IN6_IFF_ANYCAST; - error = in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, rpp->rp_ifp -#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) && !defined(__APPLE__) - , current_proc() -#endif - ); - if (error != 0) + error = in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, rpp->rp_ifp, + current_proc()); + if (error != 0) { log(LOG_ERR, "in6_prefix.c: add_each_addr: addition of an addr" "%s/%d failed because in6_control failed for error %d\n", ip6_sprintf(&ifra.ifra_addr.sin6_addr), rpp->rp_plen, error); return; + } /* * link beween this addr and the prefix will be done @@ -674,7 +675,9 @@ rrpr_update(struct socket *so, struct rr_prefix *new) int s; /* search existing prefix */ - for (ifpr = new->rp_ifp->if_prefixlist; ifpr; ifpr = ifpr->ifpr_next) { + for (ifpr = TAILQ_FIRST(&new->rp_ifp->if_prefixhead); ifpr; + ifpr = TAILQ_NEXT(ifpr, ifpr_list)) + { if (ifpr->ifpr_prefix->sa_family != AF_INET6 || ifpr->ifpr_type != IN6_PREFIX_RR) continue; @@ -709,19 +712,15 @@ rrpr_update(struct socket *so, struct rr_prefix *new) * add rp_addr entries in new into rpp, if they have not * been already included in rpp. */ -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined(__APPLE__) while (!LIST_EMPTY(&new->rp_addrhead)) -#else - while (new->rp_addrhead.lh_first != NULL) -#endif { rap = LIST_FIRST(&new->rp_addrhead); LIST_REMOVE(rap, ra_entry); if (search_ifidwithprefix(rpp, &rap->ra_ifid) != NULL) { if (rap->ra_addr) - IFAFREE(&rap->ra_addr->ia_ifa); - _FREE(rap, M_IPFW); + ifafree(&rap->ra_addr->ia_ifa); + FREE(rap, M_RR_ADDR); continue; } s = splnet(); @@ -733,7 +732,7 @@ rrpr_update(struct socket *so, struct rr_prefix *new) * We got a fresh prefix. */ /* create new prefix */ - rpp = (struct rr_prefix *)_MALLOC(sizeof(*rpp), M_IPFW, + rpp = (struct rr_prefix *)_MALLOC(sizeof(*rpp), M_IP6RR, M_NOWAIT); if (rpp == NULL) { log(LOG_ERR, "in6_prefix.c: rrpr_update:%d" @@ -744,11 +743,7 @@ rrpr_update(struct socket *so, struct rr_prefix *new) *rpp = *new; LIST_INIT(&rpp->rp_addrhead); /* move rp_addr entries of new to rpp */ -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined(__APPLE__) while (!LIST_EMPTY(&new->rp_addrhead)) -#else - while (new->rp_addrhead.lh_first != NULL) -#endif { rap = LIST_FIRST(&new->rp_addrhead); LIST_REMOVE(rap, ra_entry); @@ -762,13 +757,15 @@ rrpr_update(struct socket *so, struct rr_prefix *new) struct ifnet *ifp = rpp->rp_ifp; struct ifprefix *ifpr; - if ((ifpr = ifp->if_prefixlist) != NULL) { - for ( ; ifpr->ifpr_next; - ifpr = ifpr->ifpr_next) + if ((ifpr = TAILQ_FIRST(&ifp->if_prefixhead)) + != NULL) { + for ( ; TAILQ_NEXT(ifpr, ifpr_list); + ifpr = TAILQ_NEXT(ifpr, ifpr_list)) continue; - ifpr->ifpr_next = rp2ifpr(rpp); + TAILQ_NEXT(ifpr, ifpr_list) = rp2ifpr(rpp); } else - ifp->if_prefixlist = rp2ifpr(rpp); + TAILQ_FIRST(&ifp->if_prefixhead) = + rp2ifpr(rpp); rp2ifpr(rpp)->ifpr_type = IN6_PREFIX_RR; } /* link rr_prefix entry to rr_prefix list */ @@ -785,8 +782,8 @@ rrpr_update(struct socket *so, struct rr_prefix *new) * If it existed but not pointing to the prefix yet, * init the prefix pointer. */ - for (rap = rpp->rp_addrhead.lh_first; rap != NULL; - rap = rap->ra_entry.le_next) { + LIST_FOREACH(rap, &rpp->rp_addrhead, ra_entry) + { if (rap->ra_addr != NULL) { if (rap->ra_addr->ia6_ifpr == NULL) rap->ra_addr->ia6_ifpr = rp2ifpr(rpp); @@ -815,28 +812,30 @@ rp_remove(struct rr_prefix *rpp) struct ifnet *ifp = rpp->rp_ifp; struct ifprefix *ifpr; - if ((ifpr = ifp->if_prefixlist) == rp2ifpr(rpp)) - ifp->if_prefixlist = ifpr->ifpr_next; + if ((ifpr = TAILQ_FIRST(&ifp->if_prefixhead)) == rp2ifpr(rpp)) + TAILQ_FIRST(&ifp->if_prefixhead) = + TAILQ_NEXT(ifpr, ifpr_list); else { - while (ifpr->ifpr_next && - (ifpr->ifpr_next != rp2ifpr(rpp))) - ifpr = ifpr->ifpr_next; - if (ifpr->ifpr_next) - ifpr->ifpr_next = rp2ifpr(rpp)->ifpr_next; - else - printf("Couldn't unlink rr_prefix from ifp\n"); + while (TAILQ_NEXT(ifpr, ifpr_list) != NULL && + (TAILQ_NEXT(ifpr, ifpr_list) != rp2ifpr(rpp))) + ifpr = TAILQ_NEXT(ifpr, ifpr_list); + if (TAILQ_NEXT(ifpr, ifpr_list)) + TAILQ_NEXT(ifpr, ifpr_list) = + TAILQ_NEXT(rp2ifpr(rpp), ifpr_list); + else + printf("Couldn't unlink rr_prefix from ifp\n"); } } /* unlink rp_entry from rr_prefix list */ LIST_REMOVE(rpp, rp_entry); splx(s); - _FREE(rpp, M_IPFW); + FREE(rpp, M_IP6RR); } static int create_ra_entry(struct rp_addr **rapp) { - *rapp = (struct rp_addr *)_MALLOC(sizeof(struct rp_addr), M_IPFW, + *rapp = (struct rp_addr *)_MALLOC(sizeof(struct rp_addr), M_RR_ADDR, M_NOWAIT); if (*rapp == NULL) { log(LOG_ERR, "in6_prefix.c: init_newprefix:%d: ENOBUFS" @@ -872,8 +871,8 @@ init_newprefix(struct in6_rrenumreq *irr, struct ifprefix *ifpr, irr->irr_u_uselen, min(ifpr->ifpr_plen - irr->irr_u_uselen, irr->irr_u_keeplen)); - for (orap = (ifpr2rp(ifpr)->rp_addrhead).lh_first; orap != NULL; - orap = orap->ra_entry.le_next) { + LIST_FOREACH(orap, &(ifpr2rp(ifpr)->rp_addrhead), ra_entry) + { struct rp_addr *rap; int error = 0; @@ -905,19 +904,15 @@ free_rp_entries(struct rr_prefix *rpp) * This func is only called with rpp on stack(not on list). * So no splnet() here */ -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined(__APPLE__) while (!LIST_EMPTY(&rpp->rp_addrhead)) -#else - while (rpp->rp_addrhead.lh_first != NULL) -#endif { struct rp_addr *rap; rap = LIST_FIRST(&rpp->rp_addrhead); LIST_REMOVE(rap, ra_entry); if (rap->ra_addr) - IFAFREE(&rap->ra_addr->ia_ifa); - _FREE(rap, M_IPFW); + ifafree(&rap->ra_addr->ia_ifa); + FREE(rap, M_RR_ADDR); } } @@ -930,8 +925,9 @@ add_useprefixes(struct socket *so, struct ifnet *ifp, int error = 0; /* add prefixes to each of marked prefix */ - for (ifpr = ifp->if_prefixlist; ifpr; ifpr = nextifpr) { - nextifpr = ifpr->ifpr_next; + for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr; ifpr = nextifpr) + { + nextifpr = TAILQ_NEXT(ifpr, ifpr_list); if (ifpr->ifpr_prefix->sa_family != AF_INET6 || ifpr->ifpr_type != IN6_PREFIX_RR) continue; @@ -951,9 +947,6 @@ static void unprefer_prefix(struct rr_prefix *rpp) { struct rp_addr *rap; -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__APPLE__) - long time_second = time.tv_sec; -#endif for (rap = rpp->rp_addrhead.lh_first; rap != NULL; rap = rap->ra_entry.le_next) { @@ -978,19 +971,21 @@ delete_each_prefix(struct rr_prefix *rpp, u_char origin) s = splnet(); rap = LIST_FIRST(&rpp->rp_addrhead); - if (rap == NULL) + if (rap == NULL) { + splx(s); break; + } LIST_REMOVE(rap, ra_entry); splx(s); if (rap->ra_addr == NULL) { - _FREE(rap, M_IPFW); + FREE(rap, M_RR_ADDR); continue; } rap->ra_addr->ia6_ifpr = NULL; - in6_purgeaddr(&rap->ra_addr->ia_ifa, rpp->rp_ifp); - IFAFREE(&rap->ra_addr->ia_ifa); - _FREE(rap, M_IPFW); + in6_purgeaddr(&rap->ra_addr->ia_ifa); + ifafree(&rap->ra_addr->ia_ifa); + FREE(rap, M_RR_ADDR); } rp_remove(rpp); @@ -1003,8 +998,9 @@ delete_prefixes(struct ifnet *ifp, u_char origin) struct ifprefix *ifpr, *nextifpr; /* delete prefixes marked as tobe deleted */ - for (ifpr = ifp->if_prefixlist; ifpr; ifpr = nextifpr) { - nextifpr = ifpr->ifpr_next; + for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr; ifpr = nextifpr) + { + nextifpr = TAILQ_NEXT(ifpr, ifpr_list); if (ifpr->ifpr_prefix->sa_family != AF_INET6 || ifpr->ifpr_type != IN6_PREFIX_RR) continue; @@ -1018,12 +1014,8 @@ link_stray_ia6s(struct rr_prefix *rpp) { struct ifaddr *ifa; -#if (defined(__FreeBSD__) && __FreeBSD__ < 3) || defined(__bsdi__) - for (ifa = rpp->rp_ifp->if_addrlist; ifa; ifa = ifa->ifa_next) -#else for (ifa = rpp->rp_ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) -#endif { struct rp_addr *rap; struct rr_prefix *orpp; @@ -1046,7 +1038,7 @@ link_stray_ia6s(struct rr_prefix *rpp) rpp->rp_plen); continue; } - if ((error = assigne_ra_entry(rpp, + if ((error = assign_ra_entry(rpp, (sizeof(rap->ra_ifid) << 3) - rpp->rp_plen, (struct in6_ifaddr *)ifa)) != 0) @@ -1140,13 +1132,9 @@ in6_prefix_ioctl(struct socket *so, u_long cmd, caddr_t data, free_rp_entries(&rp_tmp); break; } -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) -#else for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) -#endif { if (ifa->ifa_addr == NULL) continue; /* just for safety */ @@ -1206,9 +1194,6 @@ in6_rr_timer(void *ignored_arg) { int s; struct rr_prefix *rpp; -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__APPLE__) - long time_second = time.tv_sec; -#endif timeout(in6_rr_timer_funneled, (caddr_t)0, ip6_rr_prune * hz); diff --git a/bsd/netinet6/in6_prefix.h b/bsd/netinet6/in6_prefix.h index 69013f928..29a04cff3 100644 --- a/bsd/netinet6/in6_prefix.h +++ b/bsd/netinet6/in6_prefix.h @@ -26,7 +26,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ +#include +#include + +#ifdef __APPLE_API_PRIVATE struct rr_prefix { struct ifprefix rp_ifpr; LIST_ENTRY(rr_prefix) rp_entry; @@ -84,3 +88,5 @@ extern struct rr_prhead rr_prefix; void in6_rr_timer __P((void *)); void in6_rr_timer_funneled __P((void *)); int delete_each_prefix __P((struct rr_prefix *rpp, u_char origin)); + +#endif /* __APPLE_API_PRIVATE */ diff --git a/bsd/netinet6/in6_proto.c b/bsd/netinet6/in6_proto.c index 488791240..3fafd2426 100644 --- a/bsd/netinet6/in6_proto.c +++ b/bsd/netinet6/in6_proto.c @@ -1,4 +1,5 @@ -/* $KAME: in6_proto.c,v 1.47 2000/03/29 07:37:22 sumikawa Exp $ */ +/* $FreeBSD: src/sys/netinet6/in6_proto.c,v 1.6.2.7 2001/07/24 19:10:18 brooks Exp $ */ +/* $KAME: in6_proto.c,v 1.91 2001/05/27 13:28:35 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -64,26 +65,16 @@ * @(#)in_proto.c 8.1 (Berkeley) 6/10/93 */ -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#if __NetBSD__ /*XXX*/ -#include "opt_ipsec.h" -#endif -#endif #include #include -#if defined(__FreeBSD__) || defined (__APPLE__) #include -#endif #include #include #include #include -#if defined (__FreeBSD__) || defined (__APPLE__) #include #include -#endif #include #include @@ -93,87 +84,62 @@ #include #include #include -#if defined (__APPLE__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3) || (defined(__NetBSD__) && !defined(TCP6)) || defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802) #include #include -#endif -#if (defined(__NetBSD__) && !defined(TCP6)) || defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802) -#include -#endif #include #include #include -#if defined (__APPLE__) #include #include #include #include #include -# if (defined(__FreeBSD__) && __FreeBSD__ >= 4) #include -# endif -#else -#if defined(__NetBSD__) && !defined(TCP6) -#include -#include -#include -#include -#include -#include -#include -#else -#include -#include -#include -#include -#include -#endif -#endif - -#include +#include #include - #include - #include -#if defined (__APPLE__) #include -#endif #if IPSEC #include +#if INET6 +#include +#endif #include +#if INET6 +#include +#endif #if IPSEC_ESP #include +#if INET6 +#include +#endif #endif #include +#if INET6 +#include +#endif #endif /*IPSEC*/ #include -#include - -#include "gif.h" -#if NGIF > 0 -#include -#endif - -#if MIP6 -#include -#endif #include -#define offsetof(type, member) ((size_t)(&((type *)0)->member)) - /* * TCP/IP protocol family: IP6, ICMP6, UDP, TCP. */ extern struct domain inet6domain; -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) static struct pr_usrreqs nousrreqs; -#endif + +#define PR_LISTEN 0 +#define PR_ABRTACPTDIS 0 + +extern struct domain inet6domain; +extern int in6_inithead __P((void **, int)); +void in6_dinit(void); struct ip6protosw inet6sw[] = { { 0, &inet6domain, IPPROTO_IPV6, 0, @@ -182,45 +148,49 @@ struct ip6protosw inet6sw[] = { ip6_init, 0, frag6_slowtimo, frag6_drain, 0, &nousrreqs }, -{ SOCK_DGRAM, &inet6domain, IPPROTO_UDP, PR_ATOMIC | PR_ADDR, +{ SOCK_DGRAM, &inet6domain, IPPROTO_UDP, PR_ATOMIC|PR_ADDR, udp6_input, 0, udp6_ctlinput, ip6_ctloutput, 0, 0, 0, 0, 0, 0, &udp6_usrreqs }, -{ SOCK_STREAM, &inet6domain, IPPROTO_TCP, PR_CONNREQUIRED | PR_WANTRCVD, +{ SOCK_STREAM, &inet6domain, IPPROTO_TCP, PR_CONNREQUIRED|PR_WANTRCVD|PR_LISTEN, tcp6_input, 0, tcp6_ctlinput, tcp_ctloutput, 0, - tcp_init, 0, 0, tcp_drain, - 0, &tcp6_usrreqs +#if INET /* don't call initialization and timeout routines twice */ + 0, 0, 0, tcp_drain, +#else + tcp_init, tcp_fasttimo, tcp_slowtimo, tcp_drain, +#endif + 0, &tcp6_usrreqs, }, -{ SOCK_RAW, &inet6domain, IPPROTO_RAW, PR_ATOMIC | PR_ADDR, - rip6_input, rip6_output, rip6_ctlinput, rip6_ctloutput, +{ SOCK_RAW, &inet6domain, IPPROTO_RAW, PR_ATOMIC|PR_ADDR, + rip6_input, rip6_output, rip6_ctlinput, rip6_ctloutput, 0, 0, 0, 0, 0, 0, &rip6_usrreqs }, -{ SOCK_RAW, &inet6domain, IPPROTO_ICMPV6, PR_ATOMIC | PR_ADDR, - icmp6_input, rip6_output, 0, rip6_ctloutput, +{ SOCK_RAW, &inet6domain, IPPROTO_ICMPV6, PR_ATOMIC|PR_ADDR|PR_LASTHDR, + icmp6_input, rip6_output, rip6_ctlinput, rip6_ctloutput, 0, icmp6_init, icmp6_fasttimo, 0, 0, 0, &rip6_usrreqs }, { SOCK_RAW, &inet6domain, IPPROTO_DSTOPTS,PR_ATOMIC|PR_ADDR, dest6_input, 0, 0, 0, - 0, + 0, 0, 0, 0, 0, 0, &nousrreqs }, { SOCK_RAW, &inet6domain, IPPROTO_ROUTING,PR_ATOMIC|PR_ADDR, route6_input, 0, 0, 0, - 0, + 0, 0, 0, 0, 0, 0, &nousrreqs }, { SOCK_RAW, &inet6domain, IPPROTO_FRAGMENT,PR_ATOMIC|PR_ADDR, frag6_input, 0, 0, 0, - 0, + 0, 0, 0, 0, 0, 0, &nousrreqs }, @@ -233,8 +203,10 @@ struct ip6protosw inet6sw[] = { }, #if IPSEC_ESP { SOCK_RAW, &inet6domain, IPPROTO_ESP, PR_ATOMIC|PR_ADDR, - esp6_input, 0, 0, 0, - 0, + esp6_input, 0, + esp6_ctlinput, + 0, + 0, 0, 0, 0, 0, 0, &nousrreqs }, @@ -246,28 +218,28 @@ struct ip6protosw inet6sw[] = { 0, &nousrreqs }, #endif /* IPSEC */ -{ SOCK_RAW, &inet6domain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR, +#if INET +{ SOCK_RAW, &inet6domain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR|PR_LASTHDR, encap6_input, rip6_output, 0, rip6_ctloutput, - 0, - 0, 0, 0, 0, - 0, &nousrreqs + 0, + encap_init, 0, 0, 0, + 0, &rip6_usrreqs }, -#if INET6 -{ SOCK_RAW, &inet6domain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR, - encap6_input, rip6_output, 0, rip6_ctloutput, - 0, - 0, 0, 0, 0, +#endif /*INET*/ +{ SOCK_RAW, &inet6domain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR|PR_LASTHDR, + encap6_input, rip6_output, 0, rip6_ctloutput, + 0, + encap_init, 0, 0, 0, 0, &rip6_usrreqs }, -#endif /*INET6*/ -{ SOCK_RAW, &inet6domain, IPPROTO_PIM, PR_ATOMIC|PR_ADDR, - pim6_input, rip6_output, 0, rip6_ctloutput, +{ SOCK_RAW, &inet6domain, IPPROTO_PIM, PR_ATOMIC|PR_ADDR|PR_LASTHDR, + pim6_input, rip6_output, 0, rip6_ctloutput, 0, 0, 0, 0, 0, 0, &rip6_usrreqs }, /* raw wildcard */ -{ SOCK_RAW, &inet6domain, 0, PR_ATOMIC | PR_ADDR, +{ SOCK_RAW, &inet6domain, 0, PR_ATOMIC|PR_ADDR, rip6_input, rip6_output, 0, rip6_ctloutput, 0, 0, 0, 0, 0, @@ -275,29 +247,8 @@ struct ip6protosw inet6sw[] = { }, }; -#if NGIF > 0 -struct ip6protosw in6_gif_protosw = -{ SOCK_RAW, &inet6domain, 0/*IPPROTO_IPV[46]*/, PR_ATOMIC|PR_ADDR, - in6_gif_input, rip6_output, 0, rip6_ctloutput, - 0, - 0, 0, 0, 0, - 0, &rip6_usrreqs -}; -#endif /*NGIF*/ -#if MIP6 -struct ip6protosw mip6_tunnel_protosw = -{ SOCK_RAW, &inet6domain, 0/*IPPROTO_IPV[46]*/, PR_ATOMIC|PR_ADDR, - mip6_tunnel_input, rip6_output, 0, rip6_ctloutput, - 0, - 0, 0, 0, 0, - 0, &rip6_usrreqs -}; -#endif /* MIP6 */ - -extern int in6_inithead __P((void **, int)); int in6_proto_count = (sizeof (inet6sw) / sizeof (struct ip6protosw)); -extern void in6_dinit(void); struct domain inet6domain = { AF_INET6, "internet6", in6_dinit, 0, 0, @@ -308,6 +259,26 @@ struct domain inet6domain = DOMAIN_SET(inet6); +/* Initialize the PF_INET6 domain, and add in the pre-defined protos */ +void +in6_dinit() +{ + register int i; + register struct ip6protosw *pr; + register struct domain *dp; + static inet6domain_initted = 0; + + if (!inet6domain_initted) { + dp = &inet6domain; + + for (i=0, pr = &inet6sw[0]; i 0 -int ip6_gif_hlim = GIF_HLIM; -#else int ip6_gif_hlim = 0; -#endif int ip6_use_deprecated = 1; /* allow deprecated addr (RFC2462 5.5.4) */ int ip6_rr_prune = 5; /* router renumbering prefix * walk list every 5 sec. */ -#if MAPPED_ADDR_ENABLED -int ip6_mapped_addr_on = 1; -#endif /* MAPPED_ADDR_ENABLED */ +int ip6_v6only = 0; +#ifdef __APPLE__ +int ip6_auto_on = 1; /* Start IPv6 per interface triggered by IPv4 address assignment */ +#endif u_int32_t ip6_id = 0UL; int ip6_keepfaith = 0; time_t ip6_log_time = (time_t)0L; /* icmp6 */ -#ifndef __bsdi__ /* * BSDI4 defines these variables in in_proto.c... * XXX: what if we don't define INET? Should we define pmtu6_expire @@ -359,7 +327,6 @@ time_t ip6_log_time = (time_t)0L; */ int pmtu_expire = 60*10; int pmtu_probe = 60*2; -#endif /* raw IP6 parameters */ /* @@ -374,90 +341,14 @@ u_long rip6_recvspace = RIPV6RCVQ; /* ICMPV6 parameters */ int icmp6_rediraccept = 1; /* accept and process redirects */ int icmp6_redirtimeout = 10 * 60; /* 10 minutes */ -u_int icmp6errratelim = 1000; /* 1000usec = 1msec */ +int icmp6errppslim = 100; /* 100pps */ int icmp6_nodeinfo = 1; /* enable/disable NI response */ -#if TCP6 -/* TCP on IP6 parameters */ -int tcp6_sendspace = 1024 * 8; -int tcp6_recvspace = 1024 * 8; -int tcp6_mssdflt = TCP6_MSS; -int tcp6_rttdflt = TCP6TV_SRTTDFLT / PR_SLOWHZ; -int tcp6_do_rfc1323 = 1; -int tcp6_conntimeo = TCP6TV_KEEP_INIT; /* initial connection timeout */ -int tcp6_43maxseg = 0; -int tcp6_pmtu = 0; - -/* - * Parameters for keepalive option. - * Connections for which SO_KEEPALIVE is set will be probed - * after being idle for a time of tcp6_keepidle (in units of PR_SLOWHZ). - * Starting at that time, the connection is probed at intervals - * of tcp6_keepintvl (same units) until a response is received - * or until tcp6_keepcnt probes have been made, at which time - * the connection is dropped. Note that a tcp6_keepidle value - * under 2 hours is nonconformant with RFC-1122, Internet Host Requirements. - */ -int tcp6_keepidle = TCP6TV_KEEP_IDLE; /* time before probing idle */ -int tcp6_keepintvl = TCP6TV_KEEPINTVL; /* interval betwn idle probes */ -int tcp6_keepcnt = TCP6TV_KEEPCNT; /* max idle probes */ -int tcp6_maxpersistidle = TCP6TV_KEEP_IDLE; /* max idle time in persist */ - -#ifndef INET_SERVER -#define TCP6_LISTEN_HASH_SIZE 17 -#define TCP6_CONN_HASH_SIZE 97 -#define TCP6_SYN_HASH_SIZE 293 -#define TCP6_SYN_BUCKET_SIZE 35 -#else -#define TCP6_LISTEN_HASH_SIZE 97 -#define TCP6_CONN_HASH_SIZE 9973 -#define TCP6_SYN_HASH_SIZE 997 -#define TCP6_SYN_BUCKET_SIZE 35 -#endif -int tcp6_listen_hash_size = TCP6_LISTEN_HASH_SIZE; -int tcp6_conn_hash_size = TCP6_CONN_HASH_SIZE; -struct tcp6_hash_list tcp6_listen_hash[TCP6_LISTEN_HASH_SIZE], - tcp6_conn_hash[TCP6_CONN_HASH_SIZE]; - -int tcp6_syn_cache_size = TCP6_SYN_HASH_SIZE; -int tcp6_syn_cache_limit = TCP6_SYN_HASH_SIZE*TCP6_SYN_BUCKET_SIZE; -int tcp6_syn_bucket_limit = 3*TCP6_SYN_BUCKET_SIZE; -struct syn_cache_head6 tcp6_syn_cache[TCP6_SYN_HASH_SIZE]; -struct syn_cache_head6 *tcp6_syn_cache_first; -int tcp6_syn_cache_interval = 8; /* runs timer every 4 seconds */ -int tcp6_syn_cache_timeo = TCP6TV_KEEP_INIT; - -/* - * Parameters for computing a desirable data segment size - * given an upper bound (either interface MTU, or peer's MSS option)_. - * As applications tend to use a buffer size that is a multiple - * of kilobytes, try for something that divides evenly. However, - * do not round down too much. - * - * Round segment size down to a multiple of TCP6_ROUNDSIZE if this - * does not result in lowering by more than (size/TCP6_ROUNDFRAC). - * For example, round 536 to 512. Older versions of the system - * effectively used MCLBYTES (1K or 2K) as TCP6_ROUNDSIZE, with - * a value of 1 for TCP6_ROUNDFRAC (eliminating its effect). - * We round to a multiple of 256 for SLIP. - */ -#ifndef TCP6_ROUNDSIZE -#define TCP6_ROUNDSIZE 256 /* round to multiple of 256 */ -#endif -#ifndef TCP6_ROUNDFRAC -#define TCP6_ROUNDFRAC 10 /* round down at most N/10, or 10% */ -#endif - -int tcp6_roundsize = TCP6_ROUNDSIZE; -int tcp6_roundfrac = TCP6_ROUNDFRAC; -#endif /*TCP6*/ - /* UDP on IP6 parameters */ int udp6_sendspace = 9216; /* really max datagram size */ int udp6_recvspace = 40 * (1024 + sizeof(struct sockaddr_in6)); /* 40 1K datagrams */ -#if defined(__FreeBSD__) || defined(__APPLE__) /* * sysctl related items. */ @@ -475,56 +366,50 @@ SYSCTL_NODE(_net_inet6, IPPROTO_ESP, ipsec6, CTLFLAG_RW, 0, "IPSEC6"); /* net.inet6.ip6 */ static int -sysctl_ip6_forwarding SYSCTL_HANDLER_ARGS +sysctl_ip6_temppltime SYSCTL_HANDLER_ARGS { int error = 0; - int old_ip6_forwarding; - int changed; + int old; error = SYSCTL_OUT(req, arg1, sizeof(int)); if (error || !req->newptr) return (error); - old_ip6_forwarding = ip6_forwarding; + old = ip6_temp_preferred_lifetime; error = SYSCTL_IN(req, arg1, sizeof(int)); - if (error != 0) - return (error); - changed = (ip6_forwarding ? 1 : 0) ^ (old_ip6_forwarding ? 1 : 0); - if (changed == 0) - return (error); - /* - * XXX while host->router removes prefix got from RA, - * router->host case nukes all the prefixes managed by in6_prefix.c - * (both RR and static). therefore, switching from host->router->host - * will remove statically configured addresses/prefixes. - * not sure if it is intended behavior or not. - */ - if (ip6_forwarding != 0) { /* host becomes router */ - int s = splnet(); - struct nd_prefix *pr, *next; - - for (pr = nd_prefix.lh_first; pr; pr = next) { - next = pr->ndpr_next; - if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) - in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); - prelist_remove(pr); - } - splx(s); - } else { /* router becomes host */ - while(!LIST_EMPTY(&rr_prefix)) - delete_each_prefix(LIST_FIRST(&rr_prefix), - PR_ORIG_KERNEL); + if (ip6_temp_preferred_lifetime < + ip6_desync_factor + ip6_temp_regen_advance) { + ip6_temp_preferred_lifetime = old; + return(EINVAL); } + return(error); +} - return (error); +static int +sysctl_ip6_tempvltime SYSCTL_HANDLER_ARGS +{ + int error = 0; + int old; + + error = SYSCTL_OUT(req, arg1, sizeof(int)); + if (error || !req->newptr) + return (error); + old = ip6_temp_valid_lifetime; + error = SYSCTL_IN(req, arg1, sizeof(int)); + if (ip6_temp_valid_lifetime < ip6_temp_preferred_lifetime) { + ip6_temp_preferred_lifetime = old; + return(EINVAL); + } + return(error); } -SYSCTL_OID(_net_inet6_ip6, IPV6CTL_FORWARDING, forwarding, - CTLTYPE_INT|CTLFLAG_RW, &ip6_forwarding, 0, sysctl_ip6_forwarding, - "I", ""); +SYSCTL_INT(_net_inet6_ip6, IPV6CTL_FORWARDING, + forwarding, CTLFLAG_RW, &ip6_forwarding, 0, ""); SYSCTL_INT(_net_inet6_ip6, IPV6CTL_SENDREDIRECTS, redirect, CTLFLAG_RW, &ip6_sendredirects, 0, ""); SYSCTL_INT(_net_inet6_ip6, IPV6CTL_DEFHLIM, hlim, CTLFLAG_RW, &ip6_defhlim, 0, ""); +SYSCTL_STRUCT(_net_inet6_ip6, IPV6CTL_STATS, stats, CTLFLAG_RD, + &ip6stat, ip6stat, ""); SYSCTL_INT(_net_inet6_ip6, IPV6CTL_MAXFRAGPACKETS, maxfragpackets, CTLFLAG_RW, &ip6_maxfragpackets, 0, ""); SYSCTL_INT(_net_inet6_ip6, IPV6CTL_ACCEPT_RTADV, @@ -549,10 +434,20 @@ SYSCTL_INT(_net_inet6_ip6, IPV6CTL_USE_DEPRECATED, use_deprecated, CTLFLAG_RW, &ip6_use_deprecated, 0, ""); SYSCTL_INT(_net_inet6_ip6, IPV6CTL_RR_PRUNE, rr_prune, CTLFLAG_RW, &ip6_rr_prune, 0, ""); -#if MAPPED_ADDR_ENABLED -SYSCTL_INT(_net_inet6_ip6, IPV6CTL_MAPPED_ADDR, - mapped_addr, CTLFLAG_RW, &ip6_mapped_addr_on, 0, ""); -#endif /* MAPPED_ADDR_ENABLED */ +SYSCTL_INT(_net_inet6_ip6, IPV6CTL_USETEMPADDR, + use_tempaddr, CTLFLAG_RW, &ip6_use_tempaddr, 0, ""); +SYSCTL_OID(_net_inet6_ip6, IPV6CTL_TEMPPLTIME, temppltime, + CTLTYPE_INT|CTLFLAG_RW, &ip6_temp_preferred_lifetime, 0, + sysctl_ip6_temppltime, "I", ""); +SYSCTL_OID(_net_inet6_ip6, IPV6CTL_TEMPVLTIME, tempvltime, + CTLTYPE_INT|CTLFLAG_RW, &ip6_temp_valid_lifetime, 0, + sysctl_ip6_tempvltime, "I", ""); +SYSCTL_INT(_net_inet6_ip6, IPV6CTL_V6ONLY, + v6only, CTLFLAG_RW, &ip6_v6only, 0, ""); +SYSCTL_INT(_net_inet6_ip6, IPV6CTL_AUTO_LINKLOCAL, + auto_linklocal, CTLFLAG_RW, &ip6_auto_linklocal, 0, ""); +SYSCTL_STRUCT(_net_inet6_ip6, IPV6CTL_RIP6STATS, rip6stats, CTLFLAG_RD, + &rip6stat, rip6stat, ""); /* net.inet6.icmp6 */ SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_REDIRACCEPT, @@ -561,8 +456,6 @@ SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_REDIRTIMEOUT, redirtimeout, CTLFLAG_RW, &icmp6_redirtimeout, 0, ""); SYSCTL_STRUCT(_net_inet6_icmp6, ICMPV6CTL_STATS, stats, CTLFLAG_RD, &icmp6stat, icmp6stat, ""); -SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ERRRATELIMIT, - errratelimit, CTLFLAG_RW, &icmp6errratelim, 0, ""); SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_PRUNE, nd6_prune, CTLFLAG_RW, &nd6_prune, 0, ""); SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_DELAY, @@ -573,54 +466,15 @@ SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_MMAXTRIES, nd6_mmaxtries, CTLFLAG_RW, &nd6_mmaxtries, 0, ""); SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_USELOOPBACK, nd6_useloopback, CTLFLAG_RW, &nd6_useloopback, 0, ""); -//SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_PROXYALL, -// nd6_proxyall, CTLFLAG_RW, &nd6_proxyall, 0, ""); SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_NODEINFO, nodeinfo, CTLFLAG_RW, &icmp6_nodeinfo, 0, ""); - - -#if defined(__FreeBSD__) && __FreeBSD__ < 3 -/* net.inet6.udp6 */ -SYSCTL_INT(_net_inet6_udp6, UDP6CTL_SENDMAX, - sendmax, CTLFLAG_RW, &udp6_sendspace, 0, ""); -SYSCTL_INT(_net_inet6_udp6, UDP6CTL_RECVSPACE, - recvspace, CTLFLAG_RW, &udp6_recvspace, 0, ""); - -/* net.inet6.tcp6 */ -SYSCTL_INT(_net_inet6_tcp6, TCP6CTL_MSSDFLT, - mssdflt, CTLFLAG_RW, &tcp6_mssdflt, 0, ""); -SYSCTL_INT(_net_inet6_tcp6, TCP6CTL_DO_RFC1323, - do_rfc1323, CTLFLAG_RW, &tcp6_do_rfc1323, 0, ""); -SYSCTL_INT(_net_inet6_tcp6, TCP6CTL_KEEPIDLE, - keepidle, CTLFLAG_RW, &tcp6_keepidle, 0, ""); -SYSCTL_INT(_net_inet6_tcp6, TCP6CTL_KEEPINTVL, - keepintvl, CTLFLAG_RW, &tcp6_keepintvl, 0, ""); -SYSCTL_INT(_net_inet6_tcp6, TCP6CTL_KEEPCNT, - keepcnt, CTLFLAG_RW, &tcp6_keepcnt, 0, ""); -SYSCTL_INT(_net_inet6_tcp6, TCP6CTL_MAXPERSISTIDLE, - maxpersistidle, CTLFLAG_RW, &tcp6_maxpersistidle, 0, ""); -SYSCTL_INT(_net_inet6_tcp6, TCP6CTL_SENDSPACE, - sendspace, CTLFLAG_RW, &tcp6_sendspace, 0, ""); -SYSCTL_INT(_net_inet6_tcp6, TCP6CTL_RECVSPACE, - recvspace, CTLFLAG_RW, &tcp6_recvspace, 0, ""); -SYSCTL_INT(_net_inet6_tcp6, TCP6CTL_CONNTIMEO, - conntimeo, CTLFLAG_RW, &tcp6_conntimeo, 0, ""); -SYSCTL_INT(_net_inet6_tcp6, TCP6CTL_PMTU, - pmtu, CTLFLAG_RW, &tcp6_pmtu, 0, ""); -SYSCTL_INT(_net_inet6_tcp6, TCP6CTL_PMTU_EXPIRE, - pmtu_expire, CTLFLAG_RW, &pmtu_expire, 0, ""); -SYSCTL_INT(_net_inet6_tcp6, TCP6CTL_PMTU_PROBE, - pmtu_probe, CTLFLAG_RW, &pmtu_probe, 0, ""); -SYSCTL_INT(_net_inet6_tcp6, TCP6CTL_43MAXSEG, - pmtu_43maxseg, CTLFLAG_RW, &tcp6_43maxseg, 0, ""); -SYSCTL_STRUCT(_net_inet6_tcp6, TCP6CTL_STATS, stats, CTLFLAG_RD, - &tcp6stat, tcp6stat, ""); -SYSCTL_INT(_net_inet6_tcp6, TCP6CTL_SYN_CACHE_LIMIT, - syn_cache_limit, CTLFLAG_RW, &tcp6_syn_cache_limit, 0, ""); -SYSCTL_INT(_net_inet6_tcp6, TCP6CTL_SYN_BUCKET_LIMIT, - syn_bucket_limit, CTLFLAG_RW, &tcp6_syn_bucket_limit, 0, ""); -SYSCTL_INT(_net_inet6_tcp6, TCP6CTL_SYN_CACHE_INTER, - syn_cache_interval, CTLFLAG_RW, &tcp6_syn_cache_interval, 0, ""); -#endif /* !(defined(__FreeBSD__) && __FreeBSD__ >= 3) */ - -#endif /* __FreeBSD__ */ +SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ERRPPSLIMIT, + errppslimit, CTLFLAG_RW, &icmp6errppslim, 0, ""); +SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_MAXNUDHINT, + nd6_maxnudhint, CTLFLAG_RW, &nd6_maxnudhint, 0, ""); +SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_DEBUG, + nd6_debug, CTLFLAG_RW, &nd6_debug, 0, ""); + +#ifdef __APPLE__ +SYSCTL_INT(_net_inet6_ip6, OID_AUTO, auto_on, CTLFLAG_RW, &ip6_auto_on,0, ""); +#endif diff --git a/bsd/netinet6/in6_rmx.c b/bsd/netinet6/in6_rmx.c index 3a5eba5ad..805f2a9e0 100644 --- a/bsd/netinet6/in6_rmx.c +++ b/bsd/netinet6/in6_rmx.c @@ -1,4 +1,5 @@ -/* $KAME: in6_rmx.c,v 1.6 2000/03/25 07:23:45 sumikawa Exp $ */ +/* $FreeBSD: src/sys/netinet6/in6_rmx.c,v 1.1.2.2 2001/07/03 11:01:52 ume Exp $ */ +/* $KAME: in6_rmx.c,v 1.10 2001/05/24 05:44:58 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -85,9 +86,7 @@ #include #include #include -#if defined(__APPLE__) #include -#endif #include #include @@ -95,26 +94,14 @@ #include -#if !defined(__APPLE__) -#include -#include -#include -#include -#else #include #include #include #include -#endif - -#if !defined(__APPLE__) -#define tcp_sendspace tcp6_sendspace -#define tcp_recvspace tcp6_recvspace -#define time_second time.tv_sec -#define tvtohz hzto -#endif extern int in6_inithead __P((void **head, int off)); +static void in6_rtqtimo __P((void *rock)); +static void in6_mtutimo __P((void *rock)); #define RTPRF_OURS RTF_PROTO3 /* set on routes we manage */ @@ -161,23 +148,6 @@ in6_addroute(void *v_arg, void *n_arg, struct radix_node_head *head, } } - /* - * We also specify a send and receive pipe size for every - * route added, to help TCP a bit. TCP doesn't actually - * want a true pipe size, which would be prohibitive in memory - * costs and is hard to compute anyway; it simply uses these - * values to size its buffers. So, we fill them in with the - * same values that TCP would have used anyway, and allow the - * installing program or the link layer to override these values - * as it sees fit. This will hopefully allow TCP more - * opportunities to save its ssthresh value. - */ - if (!rt->rt_rmx.rmx_sendpipe && !(rt->rt_rmx.rmx_locks & RTV_SPIPE)) - rt->rt_rmx.rmx_sendpipe = tcp_sendspace; - - if (!rt->rt_rmx.rmx_recvpipe && !(rt->rt_rmx.rmx_locks & RTV_RPIPE)) - rt->rt_rmx.rmx_recvpipe = tcp_recvspace; - if (!rt->rt_rmx.rmx_mtu && !(rt->rt_rmx.rmx_locks & RTV_MTU) && rt->rt_ifp) rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; @@ -204,7 +174,7 @@ in6_addroute(void *v_arg, void *n_arg, struct radix_node_head *head, ret = rn_addroute(v_arg, n_arg, head, treenodes); } - RTFREE(rt2); + rtfree(rt2); } } else if (ret == NULL && rt->rt_flags & RTF_CLONING) { struct rtentry *rt2; @@ -230,7 +200,7 @@ in6_addroute(void *v_arg, void *n_arg, struct radix_node_head *head, && rt2->rt_ifp == rt->rt_ifp) { ret = rt2->rt_nodes; } - RTFREE(rt2); + rtfree(rt2); } } return ret; @@ -256,15 +226,23 @@ in6_matroute(void *v_arg, struct radix_node_head *head) return rn; } +SYSCTL_DECL(_net_inet6_ip6); + static int rtq_reallyold = 60*60; /* one hour is ``really old'' */ - +SYSCTL_INT(_net_inet6_ip6, IPV6CTL_RTEXPIRE, rtexpire, + CTLFLAG_RW, &rtq_reallyold , 0, ""); + static int rtq_minreallyold = 10; /* never automatically crank down to less */ - +SYSCTL_INT(_net_inet6_ip6, IPV6CTL_RTMINEXPIRE, rtminexpire, + CTLFLAG_RW, &rtq_minreallyold , 0, ""); + static int rtq_toomany = 128; /* 128 cached routes is ``too many'' */ - +SYSCTL_INT(_net_inet6_ip6, IPV6CTL_RTMAXCACHE, rtmaxcache, + CTLFLAG_RW, &rtq_toomany , 0, ""); + /* * On last reference drop, mark the route as belong to us so that it can be @@ -416,7 +394,7 @@ in6_rtqtimo(void *rock) } atv.tv_usec = 0; - atv.tv_sec = arg.nextstop; + atv.tv_sec = arg.nextstop - time_second; timeout(in6_rtqtimo_funneled, rock, tvtohz(&atv)); } @@ -482,9 +460,12 @@ in6_mtutimo(void *rock) atv.tv_usec = 0; atv.tv_sec = arg.nextstop; if (atv.tv_sec < time_second) { - printf("invalid mtu expiration time on routing table\n"); +#if DIAGNOSTIC + log(LOG_DEBUG, "IPv6: invalid mtu expiration time on routing table\n"); +#endif arg.nextstop = time_second + 30; /*last resort*/ } + atv.tv_sec -= time_second; timeout(in6_mtutimo_funneled, rock, tvtohz(&atv)); } diff --git a/bsd/netinet6/in6_src.c b/bsd/netinet6/in6_src.c index ff60c18e0..5207bae56 100644 --- a/bsd/netinet6/in6_src.c +++ b/bsd/netinet6/in6_src.c @@ -1,4 +1,5 @@ -/* $KAME: in6_src.c,v 1.10 2000/03/28 09:02:23 k-sugyou Exp $ */ +/* $FreeBSD: src/sys/netinet6/in6_src.c,v 1.1.2.2 2001/07/03 11:01:52 ume Exp $ */ +/* $KAME: in6_src.c,v 1.37 2001/03/29 05:34:31 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -64,14 +65,6 @@ * @(#)in_pcb.c 8.2 (Berkeley) 1/4/94 */ -/* for MIP6 */ -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#endif - -#ifdef __NetBSD__ -#include "opt_ipsec.h" -#endif #include #include @@ -80,9 +73,6 @@ #include #include #include -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 4) -#include -#endif #include #include #include @@ -97,32 +87,21 @@ #include #include #include -#if !(defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802)) #include -#endif #include #include +#if ENABLE_DEFAULT_SCOPE +#include +#endif #include -#ifndef __bsdi__ #include "loop.h" -#endif -#if defined(__NetBSD__) || defined(__OpenBSD__) -extern struct ifnet loif[NLOOP]; -#endif - -#if MIP6 -#include -#include - -extern struct nd_prefix *(*mip6_get_home_prefix_hook) __P((void)); -#endif /* - * Return an IPv6 address, which is the most appropriate for given + * Return an IPv6 address, which is the most appropriate for a given * destination and user specified options. - * If necessary, this function lookups the routing table and return + * If necessary, this function lookups the routing table and returns * an entry to the caller for later use. */ struct in6_addr * @@ -212,21 +191,9 @@ in6_selectsrc(dstsock, opts, mopts, ro, laddr, errorp) */ if (IN6_IS_ADDR_MULTICAST(dst)) { struct ifnet *ifp = mopts ? mopts->im6o_multicast_ifp : NULL; -#ifdef __bsdi__ -#if _BSDI_VERSION >= 199802 - extern struct ifnet *loifp; -#else - extern struct ifnet loif; - struct ifnet *loifp = &loif; -#endif -#endif if (ifp == NULL && IN6_IS_ADDR_MC_NODELOCAL(dst)) { -#ifdef __bsdi__ - ifp = loifp; -#else ifp = &loif[0]; -#endif } if (ifp) { @@ -264,32 +231,6 @@ in6_selectsrc(dstsock, opts, mopts, ro, laddr, errorp) } } -#if MIP6 - /* - * This is needed to assure that the Home Address is used for - * outgoing packets when not at home. We can't choose any other - * address if we want to keep connections up during movement. - */ - if (mip6_get_home_prefix_hook) { /* Only Mobile Node */ - struct nd_prefix *pr; - if ((pr = (*mip6_get_home_prefix_hook)()) && - !IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) { - if (in6_addrscope(dst) == - in6_addrscope(&pr->ndpr_addr)) { -#if MIP6_DEBUG - /* Noisy but useful */ - mip6_debug("%s: Local address %s is chosen " - "for pcb to dest %s.\n", - __FUNCTION__, - ip6_sprintf(&pr->ndpr_addr), - ip6_sprintf(dst)); -#endif - return(&pr->ndpr_addr); - } - } - } -#endif /* MIP6 */ - /* * If route is known or can be allocated now, * our src addr is taken from the i/f, else punt. @@ -297,30 +238,25 @@ in6_selectsrc(dstsock, opts, mopts, ro, laddr, errorp) if (ro) { if (ro->ro_rt && !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr, dst)) { - RTFREE(ro->ro_rt); + rtfree(ro->ro_rt); ro->ro_rt = (struct rtentry *)0; } if (ro->ro_rt == (struct rtentry *)0 || ro->ro_rt->rt_ifp == (struct ifnet *)0) { + struct sockaddr_in6 *sa6; + /* No route yet, so try to acquire one */ bzero(&ro->ro_dst, sizeof(struct sockaddr_in6)); - ro->ro_dst.sin6_family = AF_INET6; - ro->ro_dst.sin6_len = sizeof(struct sockaddr_in6); - ro->ro_dst.sin6_addr = *dst; + sa6 = (struct sockaddr_in6 *)&ro->ro_dst; + sa6->sin6_family = AF_INET6; + sa6->sin6_len = sizeof(struct sockaddr_in6); + sa6->sin6_addr = *dst; + sa6->sin6_scope_id = dstsock->sin6_scope_id; if (IN6_IS_ADDR_MULTICAST(dst)) { -#if defined( __FreeBSD__) || defined (__APPLE__) ro->ro_rt = rtalloc1(&((struct route *)ro) ->ro_dst, 0, 0UL); -#else - ro->ro_rt = rtalloc1(&((struct route *)ro) - ->ro_dst, 0); -#endif /*__FreeBSD__*/ } else { -#ifdef __bsdi__ /* bsdi needs rtcalloc to make a host route */ - rtcalloc((struct route *)ro); -#else rtalloc((struct route *)ro); -#endif } } @@ -373,10 +309,6 @@ in6_selectsrc(dstsock, opts, mopts, ro, laddr, errorp) * hop limit of the interface specified by router advertisement. * 3. The system default hoplimit. */ -#if HAVE_NRL_INPCB -#define in6pcb inpcb -#define in6p_hops inp_hops -#endif int in6_selecthlim(in6p, ifp) struct in6pcb *in6p; @@ -389,107 +321,242 @@ in6_selecthlim(in6p, ifp) else return(ip6_defhlim); } -#if HAVE_NRL_INPCB -#undef in6pcb -#undef in6p_hops -#endif -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__OpenBSD__) && !defined(__APPLE__) /* - * Find an empty port and set it to the specified PCB. + * XXX: this is borrowed from in6_pcbbind(). If possible, we should + * share this function by all *bsd*... */ -#if HAVE_NRL_INPCB /* XXX: I really hate such ugly macros...(jinmei) */ -#define in6pcb inpcb -#define in6p_socket inp_socket -#define in6p_lport inp_lport -#define in6p_head inp_head -#define in6p_flags inp_flags -#define IN6PLOOKUP_WILDCARD INPLOOKUP_WILDCARD -#endif int -in6_pcbsetport(laddr, in6p) +in6_pcbsetport(laddr, inp, p) struct in6_addr *laddr; - struct in6pcb *in6p; + struct inpcb *inp; + struct proc *p; { - struct socket *so = in6p->in6p_socket; - struct in6pcb *head = in6p->in6p_head; - u_int16_t last_port, lport = 0; - int wild = 0; - void *t; - u_int16_t min, max; -#ifdef __NetBSD__ - struct proc *p = curproc; /* XXX */ -#endif + struct socket *so = inp->inp_socket; + u_int16_t lport = 0, first, last, *lastport; + int count, error = 0, wild = 0; + struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; /* XXX: this is redundant when called from in6_pcbbind */ - if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 && - ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || - (so->so_options & SO_ACCEPTCONN) == 0)) - wild = IN6PLOOKUP_WILDCARD; - - if (in6p->in6p_flags & IN6P_LOWPORT) { -#ifdef __NetBSD__ - if (p == 0 || (suser(p->p_ucred, &p->p_acflag) != 0)) - return (EACCES); + if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0) + wild = INPLOOKUP_WILDCARD; + + inp->inp_flags |= INP_ANONPORT; + + if (inp->inp_flags & INP_HIGHPORT) { + first = ipport_hifirstauto; /* sysctl */ + last = ipport_hilastauto; + lastport = &pcbinfo->lasthi; + } else if (inp->inp_flags & INP_LOWPORT) { +#ifdef __APPLE__ + if (p && (error = suser(p->p_ucred, &p->p_acflag))) #else - if ((so->so_state & SS_PRIV) == 0) - return (EACCES); + if (p && (error = suser(p))) #endif - min = IPV6PORT_RESERVEDMIN; - max = IPV6PORT_RESERVEDMAX; + + return error; + first = ipport_lowfirstauto; /* 1023 */ + last = ipport_lowlastauto; /* 600 */ + lastport = &pcbinfo->lastlow; } else { - min = IPV6PORT_ANONMIN; - max = IPV6PORT_ANONMAX; + first = ipport_firstauto; /* sysctl */ + last = ipport_lastauto; + lastport = &pcbinfo->lastport; + } + /* + * Simple check to ensure all ports are not used up causing + * a deadlock here. + * + * We split the two cases (up and down) so that the direction + * is not being tested on each round of the loop. + */ + if (first > last) { + /* + * counting down + */ + count = first - last; + + do { + if (count-- < 0) { /* completely used? */ + /* + * Undo any address bind that may have + * occurred above. + */ + inp->in6p_laddr = in6addr_any; + return (EAGAIN); + } + --*lastport; + if (*lastport > first || *lastport < last) + *lastport = first; + lport = htons(*lastport); + } while (in6_pcblookup_local(pcbinfo, + &inp->in6p_laddr, lport, wild)); + } else { + /* + * counting up + */ + count = last - first; + + do { + if (count-- < 0) { /* completely used? */ + /* + * Undo any address bind that may have + * occurred above. + */ + inp->in6p_laddr = in6addr_any; + return (EAGAIN); + } + ++*lastport; + if (*lastport < first || *lastport > last) + *lastport = first; + lport = htons(*lastport); + } while (in6_pcblookup_local(pcbinfo, + &inp->in6p_laddr, lport, wild)); } - /* value out of range */ - if (head->in6p_lport < min) - head->in6p_lport = min; - else if (head->in6p_lport > max) - head->in6p_lport = min; - last_port = head->in6p_lport; - goto startover; /*to randomize*/ - for (;;) { - lport = htons(head->in6p_lport); - if (IN6_IS_ADDR_V4MAPPED(laddr)) { -#if 0 - t = in_pcblookup_bind(&tcbtable, - (struct in_addr *)&in6p->in6p_laddr.s6_addr32[3], - lport); + inp->inp_lport = lport; + if (in_pcbinshash(inp) != 0) { + inp->in6p_laddr = in6addr_any; + inp->inp_lport = 0; + return (EAGAIN); + } + + return(0); +} + +/* + * generate kernel-internal form (scopeid embedded into s6_addr16[1]). + * If the address scope of is link-local, embed the interface index in the + * address. The routine determines our precedence + * between advanced API scope/interface specification and basic API + * specification. + * + * this function should be nuked in the future, when we get rid of + * embedded scopeid thing. + * + * XXX actually, it is over-specification to return ifp against sin6_scope_id. + * there can be multiple interfaces that belong to a particular scope zone + * (in specification, we have 1:N mapping between a scope zone and interfaces). + * we may want to change the function to return something other than ifp. + */ +int +in6_embedscope(in6, sin6, in6p, ifpp) + struct in6_addr *in6; + const struct sockaddr_in6 *sin6; +#ifdef HAVE_NRL_INPCB + struct inpcb *in6p; +#define in6p_outputopts inp_outputopts6 +#define in6p_moptions inp_moptions6 #else - t = NULL; + struct in6pcb *in6p; #endif - } else { -#if HAVE_NRL_INPCB - /* XXX: ugly cast... */ - t = in_pcblookup(head, (struct in_addr *)&zeroin6_addr, - 0, (struct in_addr *)laddr, - lport, wild | INPLOOKUP_IPV6); -#else - t = in6_pcblookup(head, &zeroin6_addr, 0, laddr, - lport, wild); + struct ifnet **ifpp; +{ + struct ifnet *ifp = NULL; + u_int32_t scopeid; + + *in6 = sin6->sin6_addr; + scopeid = sin6->sin6_scope_id; + if (ifpp) + *ifpp = NULL; + + /* + * don't try to read sin6->sin6_addr beyond here, since the caller may + * ask us to overwrite existing sockaddr_in6 + */ + +#ifdef ENABLE_DEFAULT_SCOPE + if (scopeid == 0) + scopeid = scope6_addr2default(in6); #endif + + if (IN6_IS_SCOPE_LINKLOCAL(in6)) { + struct in6_pktinfo *pi; + + /* + * KAME assumption: link id == interface id + */ + + if (in6p && in6p->in6p_outputopts && + (pi = in6p->in6p_outputopts->ip6po_pktinfo) && + pi->ipi6_ifindex) { + ifp = ifindex2ifnet[pi->ipi6_ifindex]; + in6->s6_addr16[1] = htons(pi->ipi6_ifindex); + } else if (in6p && IN6_IS_ADDR_MULTICAST(in6) && + in6p->in6p_moptions && + in6p->in6p_moptions->im6o_multicast_ifp) { + ifp = in6p->in6p_moptions->im6o_multicast_ifp; + in6->s6_addr16[1] = htons(ifp->if_index); + } else if (scopeid) { + /* boundary check */ + if (scopeid < 0 || if_index < scopeid) + return ENXIO; /* XXX EINVAL? */ + ifp = ifindex2ifnet[scopeid]; + /*XXX assignment to 16bit from 32bit variable */ + in6->s6_addr16[1] = htons(scopeid & 0xffff); } - if (t == 0) - break; - startover: - if (head->in6p_lport >= max) - head->in6p_lport = min; - else - head->in6p_lport++; - if (head->in6p_lport == last_port) - return (EADDRINUSE); + + if (ifpp) + *ifpp = ifp; } - in6p->in6p_lport = lport; - return(0); /* success */ + return 0; } #if HAVE_NRL_INPCB -#undef in6pcb -#undef in6p_socket -#undef in6p_lport -#undef in6p_head -#undef in6p_flags -#undef IN6PLOOKUP_WILDCARD +#undef in6p_outputopts +#undef in6p_moptions #endif -#endif /* !FreeBSD3 && !OpenBSD*/ + +/* + * generate standard sockaddr_in6 from embedded form. + * touches sin6_addr and sin6_scope_id only. + * + * this function should be nuked in the future, when we get rid of + * embedded scopeid thing. + */ +int +in6_recoverscope(sin6, in6, ifp) + struct sockaddr_in6 *sin6; + const struct in6_addr *in6; + struct ifnet *ifp; +{ + u_int32_t scopeid; + + sin6->sin6_addr = *in6; + + /* + * don't try to read *in6 beyond here, since the caller may + * ask us to overwrite existing sockaddr_in6 + */ + + sin6->sin6_scope_id = 0; + if (IN6_IS_SCOPE_LINKLOCAL(in6)) { + /* + * KAME assumption: link id == interface id + */ + scopeid = ntohs(sin6->sin6_addr.s6_addr16[1]); + if (scopeid) { + /* sanity check */ + if (scopeid < 0 || if_index < scopeid) + return ENXIO; + if (ifp && ifp->if_index != scopeid) + return ENXIO; + sin6->sin6_addr.s6_addr16[1] = 0; + sin6->sin6_scope_id = scopeid; + } + } + + return 0; +} + +/* + * just clear the embedded scope identifer. + * XXX: currently used for bsdi4 only as a supplement function. + */ +void +in6_clearscope(addr) + struct in6_addr *addr; +{ + if (IN6_IS_SCOPE_LINKLOCAL(addr)) + addr->s6_addr16[1] = 0; +} diff --git a/bsd/netinet6/in6_var.h b/bsd/netinet6/in6_var.h index c04e40310..e33393b75 100644 --- a/bsd/netinet6/in6_var.h +++ b/bsd/netinet6/in6_var.h @@ -1,3 +1,6 @@ +/* $FreeBSD: src/sys/netinet6/in6_var.h,v 1.3.2.2 2001/07/03 11:01:52 ume Exp $ */ +/* $KAME: in6_var.h,v 1.56 2001/03/29 05:34:31 itojun Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. @@ -64,6 +67,11 @@ #ifndef _NETINET6_IN6_VAR_H_ #define _NETINET6_IN6_VAR_H_ +#include + +#ifdef __APPLE__ +#include +#endif /* * Interface address, Internet version. One of these structures @@ -87,6 +95,7 @@ struct in6_addrlifetime { u_int32_t ia6t_pltime; /* prefix lifetime */ }; +#ifdef __APPLE_API_PRIVATE struct in6_ifaddr { struct ifaddr ia_ifa; /* protocol-independent info */ #define ia_ifp ia_ifa.ifa_ifp @@ -97,19 +106,21 @@ struct in6_ifaddr { struct sockaddr_in6 ia_prefixmask; /* prefix mask */ u_int32_t ia_plen; /* prefix length */ struct in6_ifaddr *ia_next; /* next in6 list of IP6 addresses */ -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__APPLE__) - LIST_HEAD(in6_multihead, in6_multi) ia6_multiaddrs; - /* list of multicast addresses */ -#endif int ia6_flags; - struct in6_addrlifetime ia6_lifetime; /* NULL = infty */ + struct in6_addrlifetime ia6_lifetime; struct ifprefix *ia6_ifpr; /* back pointer to ifprefix */ + + struct nd_prefix *ia6_ndpr; /* back pointer to the ND prefix + * (for autoconfigured addresses only) + */ }; +#endif /* __APPLE_API_PRIVATE */ /* * IPv6 interface statistics, as defined in RFC2465 Ipv6IfStatsEntry (p12). */ +#ifdef __APPLE_API_UNSTABLE struct in6_ifstat { u_quad_t ifs6_in_receive; /* # of total input datagram */ u_quad_t ifs6_in_hdrerr; /* # of datagrams with invalid hdr */ @@ -225,6 +236,7 @@ struct icmp6_ifstat { /* ipv6IfIcmpOutGroupMembReductions, # of output MLD done */ u_quad_t ifs6_out_mlddone; }; +#endif /* __APPLE_API_UNSTABLE */ struct in6_ifreq { char ifr_name[IFNAMSIZ]; @@ -238,6 +250,7 @@ struct in6_ifreq { struct in6_addrlifetime ifru_lifetime; struct in6_ifstat ifru_stat; struct icmp6_ifstat ifru_icmp6stat; + u_int32_t ifru_scope_id[16]; } ifr_ifru; }; @@ -332,6 +345,7 @@ struct in6_rrenumreq { #define irr_rrf_decrvalid irr_flags.prf_rr.decrvalid #define irr_rrf_decrprefd irr_flags.prf_rr.decrprefd +#ifdef __APPLE_API_PRIVATE /* * Given a pointer to an in6_ifaddr (ifaddr), * return a pointer to the addr as a sockaddr_in6 @@ -346,6 +360,44 @@ struct in6_rrenumreq { #define IFPR_IN6(x) (&((struct sockaddr_in6 *)((x)->ifpr_prefix))->sin6_addr) + +#ifdef __APPLE__ +/* + * Event data, internet6 style. + */ + +struct kev_in6_data { + struct net_event_data link_data; + struct sockaddr_in6 ia_addr; /* interface address */ + struct sockaddr_in6 ia_net; /* network number of interface */ + struct sockaddr_in6 ia_dstaddr; /* space for destination addr */ + struct sockaddr_in6 ia_prefixmask; /* prefix mask */ + u_int32_t ia_plen; /* prefix length */ + u_int32_t ia6_flags; /* address flags from in6_ifaddr */ + struct in6_addrlifetime ia_lifetime; /* address life info */ +}; + + +/* + * Define inet6 event subclass and specific inet6 events. + */ + +#define KEV_INET6_SUBCLASS 6 /* inet6 subclass identifier */ + +#define KEV_INET6_NEW_USER_ADDR 1 /* Userland configured IPv6 address */ +#define KEV_INET6_CHANGED_ADDR 2 /* Address changed event (future) */ +#define KEV_INET6_ADDR_DELETED 3 /* IPv6 add. in ia_addr field was deleted */ +#define KEV_INET6_NEW_LL_ADDR 4 /* Autoconfigured linklocal address has appeared */ +#define KEV_INET6_NEW_RTADV_ADDR 5 /* Autoconf router advertised address has appeared */ +#define KEV_INET6_DEFROUTER 6 /* Default router dectected by kernel */ + +#ifdef KERNEL +/* Utility function used inside netinet6 kernel code for generating events */ +void in6_post_msg(struct ifnet *, u_long, struct in6_ifaddr *); +#endif +#endif /* __APPLE__ */ +#endif /* __APPLE_API_PRIVATE */ + #ifdef KERNEL #define IN6_ARE_MASKED_ADDR_EQUAL(d, a, m) ( \ (((d)->s6_addr32[0] ^ (a)->s6_addr32[0]) & (m)->s6_addr32[0]) == 0 && \ @@ -358,12 +410,14 @@ struct in6_rrenumreq { #define SIOCGIFADDR_IN6 _IOWR('i', 33, struct in6_ifreq) #ifdef KERNEL +#ifdef __APPLE_API_OBSOLETE /* * SIOCSxxx ioctls should be unused (see comments in in6.c), but * we do not shift numbers for binary compatibility. */ #define SIOCSIFDSTADDR_IN6 _IOW('i', 14, struct in6_ifreq) #define SIOCSIFNETMASK_IN6 _IOW('i', 22, struct in6_ifreq) +#endif /* __APPLE_API_OBSOLETE */ #endif #define SIOCGIFDSTADDR_IN6 _IOWR('i', 34, struct in6_ifreq) @@ -372,15 +426,14 @@ struct in6_rrenumreq { #define SIOCDIFADDR_IN6 _IOW('i', 25, struct in6_ifreq) #define SIOCAIFADDR_IN6 _IOW('i', 26, struct in6_aliasreq) -#define SIOCSIFPHYADDR_IN6 _IOW('i', 70, struct in6_aliasreq) -#define SIOCGIFPSRCADDR_IN6 _IOWR('i', 71, struct in6_ifreq) -#define SIOCGIFPDSTADDR_IN6 _IOWR('i', 72, struct in6_ifreq) - +#define SIOCSIFPHYADDR_IN6 _IOW('i', 62, struct in6_aliasreq) +#define SIOCGIFPSRCADDR_IN6 _IOWR('i', 63, struct in6_ifreq) +#define SIOCGIFPDSTADDR_IN6 _IOWR('i', 64, struct in6_ifreq) #define SIOCGIFAFLAG_IN6 _IOWR('i', 73, struct in6_ifreq) - #define SIOCGDRLST_IN6 _IOWR('i', 74, struct in6_drlist) #define SIOCGPRLST_IN6 _IOWR('i', 75, struct in6_prlist) -#define SIOCGIFINFO_IN6 _IOWR('i', 76, struct in6_ndireq) +#define OSIOCGIFINFO_IN6 _IOWR('i', 108, struct in6_ondireq) +#define SIOCGIFINFO_IN6 _IOWR('i', 76, struct in6_ondireq) #define SIOCSNDFLUSH_IN6 _IOWR('i', 77, struct in6_ifreq) #define SIOCGNBRINFO_IN6 _IOWR('i', 78, struct in6_nbrinfo) #define SIOCSPFXFLUSH_IN6 _IOWR('i', 79, struct in6_ifreq) @@ -396,6 +449,10 @@ struct in6_rrenumreq { #define SIOCSIFINFO_FLAGS _IOWR('i', 87, struct in6_ndireq) /* XXX */ +#define SIOCSSCOPE6 _IOW('i', 88, struct in6_ifreq) +#define SIOCGSCOPE6 _IOWR('i', 89, struct in6_ifreq) +#define SIOCGSCOPE6DEF _IOWR('i', 90, struct in6_ifreq) + #define SIOCSIFPREFIX_IN6 _IOW('i', 100, struct in6_prefixreq) /* set */ #define SIOCGIFPREFIX_IN6 _IOWR('i', 101, struct in6_prefixreq) /* get */ #define SIOCDIFPREFIX_IN6 _IOW('i', 102, struct in6_prefixreq) /* del */ @@ -405,7 +462,7 @@ struct in6_rrenumreq { #define SIOCSGIFPREFIX_IN6 _IOW('i', 105, \ struct in6_rrenumreq) /* set global */ -#define SIOCGETSGCNT_IN6 _IOWR('u', 106, \ +#define SIOCGETSGCNT_IN6 _IOWR('u', 28, \ struct sioc_sg_req6) /* get s,g pkt cnt */ #define SIOCGETMIFCNT_IN6 _IOWR('u', 107, \ struct sioc_mif_req6) /* get pkt cnt per if */ @@ -418,6 +475,11 @@ struct in6_rrenumreq { #define IN6_IFF_NODAD 0x20 /* don't perform DAD on this address * (used only at first SIOC* call) */ +#define IN6_IFF_AUTOCONF 0x40 /* autoconfigurable address. */ +#define IN6_IFF_TEMPORARY 0x80 /* temporary (anonymous) address. */ +#define IN6_IFF_NOPFX 0x8000 /* skip kernel prefix management. + * XXX: this should be temporary. + */ /* do not input/output */ #define IN6_IFF_NOTREADY (IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED) @@ -428,6 +490,7 @@ struct in6_rrenumreq { #endif #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE extern struct in6_ifaddr *in6_ifaddr; extern struct in6_ifstat **in6_ifstat; @@ -448,33 +511,14 @@ extern struct ifqueue ip6intrq; /* IP6 packet input queue */ extern struct in6_addr zeroin6_addr; extern u_char inet6ctlerrmap[]; extern unsigned long in6_maxmtu; -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 #ifdef MALLOC_DECLARE MALLOC_DECLARE(M_IPMADDR); -#endif /* MALLOC_DECLARE */ #endif /* * Macro for finding the internet address structure (in6_ifaddr) corresponding * to a given interface (ifnet structure). */ -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - -#define IFP_TO_IA6(ifp, ia) \ -/* struct ifnet *ifp; */ \ -/* struct in6_ifaddr *ia; */ \ -do { \ - struct ifaddr *ifa; \ - for (ifa = (ifp)->if_addrlist; ifa; ifa = ifa->ifa_next) { \ - if (!ifa->ifa_addr) \ - continue; \ - if (ifa->ifa_addr->sa_family == AF_INET6) \ - break; \ - } \ - (ia) = (struct in6_ifaddr *)ifa; \ -} while (0) - -#else #define IFP_TO_IA6(ifp, ia) \ /* struct ifnet *ifp; */ \ @@ -489,10 +533,11 @@ do { \ } \ (ia) = (struct in6_ifaddr *)ifa; \ } while (0) -#endif -#endif /* _KERNEL */ +#endif /* __APPLE_API_PRIVATE */ +#endif /* KERNEL */ +#ifdef __APPLE_API_PRIVATE /* * Multi-cast membership entry. One for each group/ifp that a PCB * belongs to. @@ -506,20 +551,16 @@ struct in6_multi { LIST_ENTRY(in6_multi) in6m_entry; /* list glue */ struct in6_addr in6m_addr; /* IP6 multicast address */ struct ifnet *in6m_ifp; /* back pointer to ifnet */ -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined (__APPLE__) - struct in6_ifaddr *in6m_ia; /* back pointer to in6_ifaddr */ -#else struct ifmultiaddr *in6m_ifma; /* back pointer to ifmultiaddr */ -#endif u_int in6m_refcount; /* # membership claims by sockets */ u_int in6m_state; /* state of the membership */ u_int in6m_timer; /* MLD6 listener report timer */ }; +#endif /* __APPLE_API_PRIVATE */ #ifdef KERNEL -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) +#ifdef __APPLE_API_PRIVATE extern LIST_HEAD(in6_multihead, in6_multi) in6_multihead; -#endif /* * Structure used by macros below to remember position when stepping through @@ -536,14 +577,12 @@ struct in6_multistep { * returns NLL. */ -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) - #define IN6_LOOKUP_MULTI(addr, ifp, in6m) \ /* struct in6_addr addr; */ \ /* struct ifnet *ifp; */ \ /* struct in6_multi *in6m; */ \ do { \ - register struct ifmultiaddr *ifma; \ + struct ifmultiaddr *ifma; \ for (ifma = (ifp)->if_multiaddrs.lh_first; ifma; \ ifma = ifma->ifma_link.le_next) { \ if (ifma->ifma_addr->sa_family == AF_INET6 \ @@ -577,77 +616,19 @@ do { \ IN6_NEXT_MULTI((step), (in6m)); \ } while(0) -#else /* not FreeBSD3 */ - -#define IN6_LOOKUP_MULTI(addr, ifp, in6m) \ -/* struct in6_addr addr; */ \ -/* struct ifnet *ifp; */ \ -/* struct in6_multi *in6m; */ \ -do { \ - register struct in6_ifaddr *ia; \ - \ - IFP_TO_IA6((ifp), ia); \ - if (ia == NULL) \ - (in6m) = NULL; \ - else \ - for ((in6m) = ia->ia6_multiaddrs.lh_first; \ - (in6m) != NULL && \ - !IN6_ARE_ADDR_EQUAL(&(in6m)->in6m_addr, &(addr)); \ - (in6m) = in6m->in6m_entry.le_next) \ - continue; \ -} while (0) - -/* - * Macro to step through all of the in6_multi records, one at a time. - * The current position is remembered in "step", which the caller must - * provide. IN6_FIRST_MULTI(), below, must be called to initialize "step" - * and get the first record. Both macros return a NULL "in6m" when there - * are no remaining records. - */ -#define IN6_NEXT_MULTI(step, in6m) \ -/* struct in6_multistep step; */ \ -/* struct in6_multi *in6m; */ \ -do { \ - if (((in6m) = (step).i_in6m) != NULL) \ - (step).i_in6m = (in6m)->in6m_entry.le_next; \ - else \ - while ((step).i_ia != NULL) { \ - (in6m) = (step).i_ia->ia6_multiaddrs.lh_first; \ - (step).i_ia = (step).i_ia->ia_next; \ - if ((in6m) != NULL) { \ - (step).i_in6m = (in6m)->in6m_entry.le_next; \ - break; \ - } \ - } \ -} while (0) - -#define IN6_FIRST_MULTI(step, in6m) \ -/* struct in6_multistep step; */ \ -/* struct in6_multi *in6m */ \ -do { \ - (step).i_ia = in6_ifaddr; \ - (step).i_in6m = NULL; \ - IN6_NEXT_MULTI((step), (in6m)); \ -} while (0) - -#endif /* not FreeBSD3 */ - -int in6_ifinit __P((struct ifnet *, - struct in6_ifaddr *, struct sockaddr_in6 *, int)); struct in6_multi *in6_addmulti __P((struct in6_addr *, struct ifnet *, int *)); void in6_delmulti __P((struct in6_multi *)); -void in6_ifscrub __P((struct ifnet *, struct in6_ifaddr *)); extern int in6_ifindex2scopeid __P((int)); -extern int in6_mask2len __P((struct in6_addr *)); +extern int in6_mask2len __P((struct in6_addr *, u_char *)); extern void in6_len2mask __P((struct in6_addr *, int)); -#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) && !defined (__APPLE__) int in6_control __P((struct socket *, u_long, caddr_t, struct ifnet *, struct proc *)); -#else -int in6_control __P((struct socket *, u_long, caddr_t, struct ifnet *)); -#endif -void in6_purgeaddr __P((struct ifaddr *, struct ifnet *)); +int in6_update_ifa __P((struct ifnet *, struct in6_aliasreq *, + struct in6_ifaddr *)); +void in6_purgeaddr __P((struct ifaddr *)); +int in6if_do_dad __P((struct ifnet *)); +void in6_purgeif __P((struct ifnet *)); void in6_savemkludge __P((struct in6_ifaddr *)); void in6_setmaxmtu __P((void)); void in6_restoremkludge __P((struct in6_ifaddr *, struct ifnet *)); @@ -655,7 +636,7 @@ void in6_purgemkludge __P((struct ifnet *)); struct in6_ifaddr *in6ifa_ifpforlinklocal __P((struct ifnet *, int)); struct in6_ifaddr *in6ifa_ifpwithaddr __P((struct ifnet *, struct in6_addr *)); -char *ip6_sprintf __P((struct in6_addr *)); +char *ip6_sprintf __P((const struct in6_addr *)); int in6_addr2scopeid __P((struct ifnet *, struct in6_addr *)); int in6_matchlen __P((struct in6_addr *, struct in6_addr *)); int in6_are_prefix_equal __P((struct in6_addr *p1, struct in6_addr *p2, @@ -666,6 +647,15 @@ int in6_prefix_ioctl __P((struct socket *so, u_long cmd, caddr_t data, int in6_prefix_add_ifid __P((int iilen, struct in6_ifaddr *ia)); void in6_prefix_remove_ifid __P((int iilen, struct in6_ifaddr *ia)); void in6_purgeprefix __P((struct ifnet *)); -#endif /* _KERNEL */ + +int in6_is_addr_deprecated __P((struct sockaddr_in6 *)); +struct inpcb; +int in6_embedscope __P((struct in6_addr *, const struct sockaddr_in6 *, + struct inpcb *, struct ifnet **)); +int in6_recoverscope __P((struct sockaddr_in6 *, const struct in6_addr *, + struct ifnet *)); +void in6_clearscope __P((struct in6_addr *)); +#endif /* __APPLE_API_PRIVATE */ +#endif /* KERNEL */ #endif /* _NETINET6_IN6_VAR_H_ */ diff --git a/bsd/netinet6/ip6.h b/bsd/netinet6/ip6.h index 023215cc0..abc2ec12e 100644 --- a/bsd/netinet6/ip6.h +++ b/bsd/netinet6/ip6.h @@ -1,4 +1,4 @@ -/* $KAME$ */ +/* $FreeBSD: src/sys/netinet6/ip6.h,v 1.4.2.1 2000/07/15 07:14:34 kris Exp $ */ +/* $KAME: ip6.h,v 1.7 2000/03/25 07:23:36 sumikawa Exp $ */ -/* just for backward compatibility, will be nuked shortly */ -#error "wrong include file - include netinet/ip6.h instead" +#error "netinet6/ip6.h is obsolete. use netinet/ip6.h" diff --git a/bsd/netinet6/ip6_ecn.h b/bsd/netinet6/ip6_ecn.h new file mode 100644 index 000000000..27104fcb8 --- /dev/null +++ b/bsd/netinet6/ip6_ecn.h @@ -0,0 +1,44 @@ +/* $FreeBSD: src/sys/netinet6/ip6_ecn.h,v 1.2.2.2 2001/07/03 11:01:53 ume Exp $ */ +/* $KAME: ip_ecn.h,v 1.5 2000/03/27 04:58:38 sumikawa Exp $ */ + +/* + * Copyright (C) 1999 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +/* + * ECN consideration on tunnel ingress/egress operation. + * http://www.aciri.org/floyd/papers/draft-ipsec-ecn-00.txt + */ +#include + +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE +extern void ip6_ecn_ingress __P((int, u_int32_t *, const u_int32_t *)); +extern void ip6_ecn_egress __P((int, const u_int32_t *, u_int32_t *)); +#endif /* __APPLE_API_PRIVATE */ +#endif diff --git a/bsd/netinet6/ip6_forward.c b/bsd/netinet6/ip6_forward.c index 95838ed3c..18cde6fcc 100644 --- a/bsd/netinet6/ip6_forward.c +++ b/bsd/netinet6/ip6_forward.c @@ -1,4 +1,5 @@ -/* $KAME: ip6_forward.c,v 1.29 2000/02/26 18:08:38 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/ip6_forward.c,v 1.4.2.4 2001/07/03 11:01:53 ume Exp $ */ +/* $KAME: ip6_forward.c,v 1.69 2001/05/17 03:48:30 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -29,10 +30,6 @@ * SUCH DAMAGE. */ -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) -#include "opt_ip6fw.h" -#include "opt_inet.h" -#endif #include #include @@ -51,25 +48,27 @@ #include #include +#include +#include #include +#include #include #include #include #include -#if IPSEC_IPV6FWD +#include + +#if IPSEC #include +#if INET6 +#include +#endif #include -#include -#endif /* IPSEC_IPV6FWD */ +extern int ipsec_bypass; +#endif /* IPSEC */ -#if IPV6FIREWALL #include -#endif - -#if MIP6 -#include -#endif #include @@ -94,18 +93,16 @@ ip6_forward(m, srcrt) int srcrt; { struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); - register struct sockaddr_in6 *dst; - register struct rtentry *rt; + struct sockaddr_in6 *dst; + struct rtentry *rt; int error, type = 0, code = 0; struct mbuf *mcopy = NULL; -#if IPSEC_IPV6FWD + struct ifnet *origifp; /* maybe unnecessary */ +#if IPSEC struct secpolicy *sp = NULL; #endif -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__APPLE__) - long time_second = time.tv_sec; -#endif -#if IPSEC_IPV6FWD +#if IPSEC /* * Check AH/ESP integrity. */ @@ -113,15 +110,22 @@ ip6_forward(m, srcrt) * Don't increment ip6s_cantforward because this is the check * before forwarding packet actually. */ - if (ipsec6_in_reject(m, NULL)) { + if (ipsec_bypass == 0 && ipsec6_in_reject(m, NULL)) { ipsec6stat.in_polvio++; m_freem(m); return; } -#endif /*IPSEC_IPV6FWD*/ +#endif /*IPSEC*/ + /* + * Do not forward packets to multicast destination (should be handled + * by ip6_mforward(). + * Do not forward packets with unspecified source. It was discussed + * in July 2000, on ipngwg mailing list. + */ if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 || - IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { + IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || + IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) { ip6stat.ip6s_cantforward++; /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */ if (ip6_log_time + ip6_log_interval < time_second) { @@ -157,10 +161,13 @@ ip6_forward(m, srcrt) */ mcopy = m_copy(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN)); +#if IPSEC + if (ipsec_bypass != 0) + goto skip_ipsec; -#if IPSEC_IPV6FWD /* get a security policy for this packet */ - sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, 0, &error); + sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, IP_FORWARDING, + &error); if (sp == NULL) { ipsec6stat.out_inval++; ip6stat.ip6s_cantforward++; @@ -201,7 +208,7 @@ ip6_forward(m, srcrt) /* no need to do IPsec. */ key_freesp(sp); goto skip_ipsec; - + case IPSEC_POLICY_IPSEC: if (sp->req == NULL) { /* XXX should be panic ? */ @@ -248,10 +255,6 @@ ip6_forward(m, srcrt) error = ipsec6_output_tunnel(&state, sp, 0); m = state.m; -#if 0 /* XXX allocate a route (ro, dst) again later */ - ro = (struct route_in6 *)state.ro; - dst = (struct sockaddr_in6 *)state.dst; -#endif key_freesp(sp); if (error) { @@ -283,27 +286,9 @@ ip6_forward(m, srcrt) } } skip_ipsec: -#endif /* IPSEC_IPV6FWD */ - -#if MIP6 - { - struct mip6_bc *bc; - - bc = mip6_bc_find(&ip6->ip6_dst); - if ((bc != NULL) && (bc->hr_flag)) { - if (mip6_tunnel_output(&m, bc) != 0) { - ip6stat.ip6s_cantforward++; - if (mcopy) - m_freem(mcopy); - m_freem(m); - return; - } - } - ip6 = mtod(m, struct ip6_hdr *); /* m has changed */ - } -#endif - - dst = &ip6_forward_rt.ro_dst; +#endif /* IPSEC */ + + dst = (struct sockaddr_in6 *)&ip6_forward_rt.ro_dst; if (!srcrt) { /* * ip6_forward_rt.ro_dst.sin6_addr is equal to ip6->ip6_dst @@ -311,21 +296,17 @@ ip6_forward(m, srcrt) if (ip6_forward_rt.ro_rt == 0 || (ip6_forward_rt.ro_rt->rt_flags & RTF_UP) == 0) { if (ip6_forward_rt.ro_rt) { - RTFREE(ip6_forward_rt.ro_rt); + rtfree(ip6_forward_rt.ro_rt); ip6_forward_rt.ro_rt = 0; } /* this probably fails but give it a try again */ -#if __FreeBSD__ || defined(__APPLE__) rtalloc_ign((struct route *)&ip6_forward_rt, RTF_PRCLONING); -#else - rtalloc((struct route *)&ip6_forward_rt); -#endif } - + if (ip6_forward_rt.ro_rt == 0) { ip6stat.ip6s_noroute++; - /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */ + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_noroute); if (mcopy) { icmp6_error(mcopy, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE, 0); @@ -336,7 +317,7 @@ ip6_forward(m, srcrt) } else if ((rt = ip6_forward_rt.ro_rt) == 0 || !IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst->sin6_addr)) { if (ip6_forward_rt.ro_rt) { - RTFREE(ip6_forward_rt.ro_rt); + rtfree(ip6_forward_rt.ro_rt); ip6_forward_rt.ro_rt = 0; } bzero(dst, sizeof(*dst)); @@ -344,14 +325,10 @@ ip6_forward(m, srcrt) dst->sin6_family = AF_INET6; dst->sin6_addr = ip6->ip6_dst; -#if __FreeBSD__ || defined(__APPLE__) rtalloc_ign((struct route *)&ip6_forward_rt, RTF_PRCLONING); -#else - rtalloc((struct route *)&ip6_forward_rt); -#endif if (ip6_forward_rt.ro_rt == 0) { ip6stat.ip6s_noroute++; - /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */ + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_noroute); if (mcopy) { icmp6_error(mcopy, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE, 0); @@ -396,7 +373,7 @@ ip6_forward(m, srcrt) in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig); if (mcopy) { u_long mtu; -#if IPSEC_IPV6FWD +#if IPSEC struct secpolicy *sp; int ipsecerror; size_t ipsechdrsiz; @@ -446,14 +423,30 @@ ip6_forward(m, srcrt) * modified by a redirect. */ if (rt->rt_ifp == m->m_pkthdr.rcvif && !srcrt && - (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) + (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) { + if ((rt->rt_ifp->if_flags & IFF_POINTOPOINT) != 0) { + /* + * If the incoming interface is equal to the outgoing + * one, and the link attached to the interface is + * point-to-point, then it will be highly probable + * that a routing loop occurs. Thus, we immediately + * drop the packet and send an ICMPv6 error message. + * + * type/code is based on suggestion by Rich Draves. + * not sure if it is the best pick. + */ + icmp6_error(mcopy, ICMP6_DST_UNREACH, + ICMP6_DST_UNREACH_ADDR, 0); + m_freem(m); + return; + } type = ND_REDIRECT; + } -#if IPV6FIREWALL /* * Check with the firewall... */ - if (ip6_fw_chk_ptr) { + if (ip6_fw_enable && ip6_fw_chk_ptr) { u_short port = 0; /* If ipfw says divert, we have to just drop packet */ if ((*ip6_fw_chk_ptr)(&ip6, rt->rt_ifp, &port, &m)) { @@ -463,15 +456,54 @@ ip6_forward(m, srcrt) if (!m) goto freecopy; } -#endif -#if OLDIP6OUTPUT - error = (*rt->rt_ifp->if_output)(rt->rt_ifp, m, - (struct sockaddr *)dst, - ip6_forward_rt.ro_rt); + /* + * Fake scoped addresses. Note that even link-local source or + * destinaion can appear, if the originating node just sends the + * packet to us (without address resolution for the destination). + * Since both icmp6_error and icmp6_redirect_output fill the embedded + * link identifiers, we can do this stuff after making a copy for + * returning an error. + */ + if ((rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) { + /* + * See corresponding comments in ip6_output. + * XXX: but is it possible that ip6_forward() sends a packet + * to a loopback interface? I don't think so, and thus + * I bark here. (jinmei@kame.net) + * XXX: it is common to route invalid packets to loopback. + * also, the codepath will be visited on use of ::1 in + * rthdr. (itojun) + */ +#if 1 + if (0) #else - error = nd6_output(rt->rt_ifp, m, dst, rt); -#endif + if ((rt->rt_flags & (RTF_BLACKHOLE|RTF_REJECT)) == 0) +#endif + { + printf("ip6_forward: outgoing interface is loopback. " + "src %s, dst %s, nxt %d, rcvif %s, outif %s\n", + ip6_sprintf(&ip6->ip6_src), + ip6_sprintf(&ip6->ip6_dst), + ip6->ip6_nxt, if_name(m->m_pkthdr.rcvif), + if_name(rt->rt_ifp)); + } + + /* we can just use rcvif in forwarding. */ + origifp = m->m_pkthdr.rcvif; + } + else + origifp = rt->rt_ifp; +#ifndef SCOPEDROUTING + /* + * clear embedded scope identifiers if necessary. + * in6_clearscope will touch the addresses only when necessary. + */ + in6_clearscope(&ip6->ip6_src); + in6_clearscope(&ip6->ip6_dst); +#endif + + error = nd6_output(rt->rt_ifp, origifp, m, dst, rt); if (error) { in6_ifstat_inc(rt->rt_ifp, ifs6_out_discard); ip6stat.ip6s_cantforward++; diff --git a/bsd/netinet6/ip6_fw.c b/bsd/netinet6/ip6_fw.c deleted file mode 100644 index 0a7943e02..000000000 --- a/bsd/netinet6/ip6_fw.c +++ /dev/null @@ -1,1264 +0,0 @@ -/* $KAME: ip6_fw.c,v 1.11 2000/03/10 04:22:18 k-sugyou Exp $ */ - -/* - * Copyright (c) 1993 Daniel Boulet - * Copyright (c) 1994 Ugen J.S.Antsilevich - * Copyright (c) 1996 Alex Nash - * - * Redistribution and use in source forms, with and without modification, - * are permitted provided that this entire comment appears intact. - * - * Redistribution in binary form may occur without any restrictions. - * Obviously, it would be nice if you gave credit where credit is due - * but requiring it would be too onerous. - * - * This software is provided ``AS IS'' without any warranties of any kind. - * - * $Id: ip6_fw.c,v 1.3 2001/05/01 21:52:50 lindak Exp $ - */ - -/* - * Implement IPv6 packet firewall - */ - -#ifdef __FreeBSD__ -#include "opt_ip6fw.h" -#if __FreeBSD__ >= 3 -#include "opt_inet.h" -#endif -#endif - -#if IP6DIVERT -#error "NOT SUPPORTED IPV6 DIVERT" -#endif -#if IP6FW_DIVERT_RESTART -#error "NOT SUPPORTED IPV6 DIVERT" -#endif - -#include -#include -#include -#include -#include -#include -#include -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) -#include -#endif -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#if TCP6 -#include -#include -#include -#endif -#include -#include -#include -#include -#include -#include - -#if defined(__NetBSD__) || defined(__OpenBSD__) -#include -#endif -#if __FreeBSD__ || defined (__APPLE__) -#include -#endif - -#include - -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -MALLOC_DEFINE(M_IP6FW, "Ip6Fw/Ip6Acct", "Ip6Fw/Ip6Acct chain's"); -#else -#ifndef M_IP6FW -#define M_IP6FW M_TEMP -#endif -#endif - -static int fw6_debug = 1; -#if IPV6FIREWALL_VERBOSE -static int fw6_verbose = 1; -#else -static int fw6_verbose = 0; -#endif -#if IPV6FIREWALL_VERBOSE_LIMIT -static int fw6_verbose_limit = IPV6FIREWALL_VERBOSE_LIMIT; -#else -static int fw6_verbose_limit = 0; -#endif - -LIST_HEAD (ip6_fw_head, ip6_fw_chain) ip6_fw_chain; - -SYSCTL_DECL(_net_inet6_ip6); -SYSCTL_NODE(_net_inet6_ip6, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall"); -SYSCTL_INT(_net_inet6_ip6_fw, IP6FWCTL_DEBUG, debug, CTLFLAG_RW, &fw6_debug, 0, ""); -SYSCTL_INT(_net_inet6_ip6_fw, IP6FWCTL_VERBOSE, verbose, CTLFLAG_RW, &fw6_verbose, 0, ""); -SYSCTL_INT(_net_inet6_ip6_fw, IP6FWCTL_VERBLIMIT, verbose_limit, CTLFLAG_RW, &fw6_verbose_limit, 0, ""); - -#define dprintf(a) if (!fw6_debug); else printf a - -#define print_ip6(a) printf("[%s]", ip6_sprintf(a)) - -#define dprint_ip6(a) if (!fw6_debug); else print_ip6(a) - -static int add_entry6 __P((struct ip6_fw_head *chainptr, struct ip6_fw *frwl)); -static int del_entry6 __P((struct ip6_fw_head *chainptr, u_short number)); -static int zero_entry6 __P((struct mbuf *m)); -static struct ip6_fw *check_ip6fw_struct __P((struct ip6_fw *m)); -static struct ip6_fw *check_ip6fw_mbuf __P((struct mbuf *fw)); -static int ip6opts_match __P((struct ip6_hdr **ip6, struct ip6_fw *f, - struct mbuf **m, - int *off, int *nxt, u_short *offset)); -static int port_match6 __P((u_short *portptr, int nports, u_short port, - int range_flag)); -static int tcp6flg_match __P((struct tcphdr *tcp6, struct ip6_fw *f)); -static int icmp6type_match __P((struct icmp6_hdr * icmp, struct ip6_fw * f)); -static void ip6fw_report __P((struct ip6_fw *f, struct ip6_hdr *ip6, - struct ifnet *rif, struct ifnet *oif, int off, int nxt)); - -static int ip6_fw_chk __P((struct ip6_hdr **pip6, - struct ifnet *oif, u_int16_t *cookie, struct mbuf **m)); -static int ip6_fw_ctl __P((int stage, struct mbuf **mm)); - -static char err_prefix[] = "ip6_fw_ctl:"; - -/* - * Returns 1 if the port is matched by the vector, 0 otherwise - */ -static -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -__inline -#else -inline -#endif -int -port_match6(u_short *portptr, int nports, u_short port, int range_flag) -{ - if (!nports) - return 1; - if (range_flag) { - if (portptr[0] <= port && port <= portptr[1]) { - return 1; - } - nports -= 2; - portptr += 2; - } - while (nports-- > 0) { - if (*portptr++ == port) { - return 1; - } - } - return 0; -} - -static int -tcp6flg_match(struct tcphdr *tcp6, struct ip6_fw *f) -{ - u_char flg_set, flg_clr; - - if ((f->fw_tcpf & IPV6_FW_TCPF_ESTAB) && - (tcp6->th_flags & (IPV6_FW_TCPF_RST | IPV6_FW_TCPF_ACK))) - return 1; - - flg_set = tcp6->th_flags & f->fw_tcpf; - flg_clr = tcp6->th_flags & f->fw_tcpnf; - - if (flg_set != f->fw_tcpf) - return 0; - if (flg_clr) - return 0; - - return 1; -} - -static int -icmp6type_match(struct icmp6_hdr *icmp6, struct ip6_fw *f) -{ - int type; - - if (!(f->fw_flg & IPV6_FW_F_ICMPBIT)) - return(1); - - type = icmp6->icmp6_type; - - /* check for matching type in the bitmap */ - if (type < IPV6_FW_ICMPTYPES_DIM * sizeof(unsigned) * 8 && - (f->fw_icmp6types[type / (sizeof(unsigned) * 8)] & - (1U << (type % (8 * sizeof(unsigned)))))) - return(1); - - return(0); /* no match */ -} - -static int -is_icmp6_query(struct ip6_hdr *ip6, int off) -{ - const struct icmp6_hdr *icmp6; - int icmp6_type; - - icmp6 = (struct icmp6_hdr *)((caddr_t)ip6 + off); - icmp6_type = icmp6->icmp6_type; - - if (icmp6_type == ICMP6_ECHO_REQUEST || - icmp6_type == ICMP6_MEMBERSHIP_QUERY || - icmp6_type == ICMP6_WRUREQUEST || - icmp6_type == ICMP6_FQDN_QUERY || - icmp6_type == ICMP6_NI_QUERY) - return(1); - - return(0); -} - -static int -ip6opts_match(struct ip6_hdr **pip6, struct ip6_fw *f, struct mbuf **m, - int *off, int *nxt, u_short *offset) -{ - int len; - struct ip6_hdr *ip6 = *pip6; - struct ip6_ext *ip6e; - u_char opts, nopts, nopts_sve; - - opts = f->fw_ip6opt; - nopts = nopts_sve = f->fw_ip6nopt; - - *nxt = ip6->ip6_nxt; - *off = sizeof(struct ip6_hdr); - len = ntohs(ip6->ip6_plen) + sizeof(struct ip6_hdr); - while (*off < len) { - ip6e = (struct ip6_ext *)((caddr_t) ip6 + *off); - if ((*m)->m_len < *off + sizeof(*ip6e)) - goto opts_check; /* XXX */ - - switch(*nxt) { - case IPPROTO_FRAGMENT: - if ((*m)->m_len < *off + sizeof(struct ip6_frag)) { - struct ip6_frag *ip6f; - - ip6f = (struct ip6_frag *) ((caddr_t)ip6 + *off); - *offset = ip6f->ip6f_offlg | IP6F_OFF_MASK; - } - opts &= ~IPV6_FW_IP6OPT_FRAG; - nopts &= ~IPV6_FW_IP6OPT_FRAG; - *off += sizeof(struct ip6_frag); - break; - case IPPROTO_AH: - opts &= ~IPV6_FW_IP6OPT_AH; - nopts &= ~IPV6_FW_IP6OPT_AH; - *off += (ip6e->ip6e_len + 2) << 2; - break; - default: - switch (*nxt) { - case IPPROTO_HOPOPTS: - opts &= ~IPV6_FW_IP6OPT_HOPOPT; - nopts &= ~IPV6_FW_IP6OPT_HOPOPT; - break; - case IPPROTO_ROUTING: - opts &= ~IPV6_FW_IP6OPT_ROUTE; - nopts &= ~IPV6_FW_IP6OPT_ROUTE; - break; - case IPPROTO_ESP: - opts &= ~IPV6_FW_IP6OPT_ESP; - nopts &= ~IPV6_FW_IP6OPT_ESP; - break; - case IPPROTO_NONE: - opts &= ~IPV6_FW_IP6OPT_NONXT; - nopts &= ~IPV6_FW_IP6OPT_NONXT; - goto opts_check; - break; - case IPPROTO_DSTOPTS: - opts &= ~IPV6_FW_IP6OPT_OPTS; - nopts &= ~IPV6_FW_IP6OPT_OPTS; - break; - default: - goto opts_check; - break; - } - *off += (ip6e->ip6e_len + 1) << 3; - break; - } - *nxt = ip6e->ip6e_nxt; - - } - opts_check: - if (f->fw_ip6opt == f->fw_ip6nopt) /* XXX */ - return 1; - - if (opts == 0 && nopts == nopts_sve) - return 1; - else - return 0; -} - -static -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -__inline -#else -inline -#endif -int -iface_match(struct ifnet *ifp, union ip6_fw_if *ifu, int byname) -{ - /* Check by name or by IP address */ - if (byname) { -#if __NetBSD__ - { - char xname[IFNAMSIZ]; - snprintf(xname, sizeof(xname), "%s%d", ifu->fu_via_if.name, - ifu->fu_via_if.unit); - if (strcmp(ifp->if_xname, xname)) - return(0); - } -#else - /* Check unit number (-1 is wildcard) */ - if (ifu->fu_via_if.unit != -1 - && ifp->if_unit != ifu->fu_via_if.unit) - return(0); - /* Check name */ - if (strncmp(ifp->if_name, ifu->fu_via_if.name, FW_IFNLEN)) - return(0); -#endif - return(1); - } else if (!IN6_IS_ADDR_UNSPECIFIED(&ifu->fu_via_ip6)) { /* Zero == wildcard */ - struct ifaddr *ia; - -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) -#else - for (ia = ifp->if_addrlist.tqh_first; ia; ia = ia->ifa_list.tqe_next) -#endif - { - - if (ia->ifa_addr == NULL) - continue; - if (ia->ifa_addr->sa_family != AF_INET6) - continue; - if (!IN6_ARE_ADDR_EQUAL(&ifu->fu_via_ip6, - &(((struct sockaddr_in6 *) - (ia->ifa_addr))->sin6_addr))) - continue; - return(1); - } - return(0); - } - return(1); -} - -static void -ip6fw_report(struct ip6_fw *f, struct ip6_hdr *ip6, - struct ifnet *rif, struct ifnet *oif, int off, int nxt) -{ - static int counter; - struct tcphdr *const tcp6 = (struct tcphdr *) ((caddr_t) ip6+ off); - struct udphdr *const udp = (struct udphdr *) ((caddr_t) ip6+ off); - struct icmp6_hdr *const icmp6 = (struct icmp6_hdr *) ((caddr_t) ip6+ off); - int count; - - count = f ? f->fw_pcnt : ++counter; - if (fw6_verbose_limit != 0 && count > fw6_verbose_limit) - return; - - /* Print command name */ - printf("ip6fw: %d ", f ? f->fw_number : -1); - if (!f) - printf("Refuse"); - else - switch (f->fw_flg & IPV6_FW_F_COMMAND) { - case IPV6_FW_F_DENY: - printf("Deny"); - break; - case IPV6_FW_F_REJECT: - if (f->fw_reject_code == IPV6_FW_REJECT_RST) - printf("Reset"); - else - printf("Unreach"); - break; - case IPV6_FW_F_ACCEPT: - printf("Accept"); - break; - case IPV6_FW_F_COUNT: - printf("Count"); - break; - case IPV6_FW_F_DIVERT: - printf("Divert %d", f->fw_divert_port); - break; - case IPV6_FW_F_TEE: - printf("Tee %d", f->fw_divert_port); - break; - case IPV6_FW_F_SKIPTO: - printf("SkipTo %d", f->fw_skipto_rule); - break; - default: - printf("UNKNOWN"); - break; - } - printf(" "); - - switch (nxt) { - case IPPROTO_TCP: - printf("TCP "); - print_ip6(&ip6->ip6_src); - if (off > 0) - printf(":%d ", ntohs(tcp6->th_sport)); - else - printf(" "); - print_ip6(&ip6->ip6_dst); - if (off > 0) - printf(":%d", ntohs(tcp6->th_dport)); - break; - case IPPROTO_UDP: - printf("UDP "); - print_ip6(&ip6->ip6_src); - if (off > 0) - printf(":%d ", ntohs(udp->uh_sport)); - else - printf(" "); - print_ip6(&ip6->ip6_dst); - if (off > 0) - printf(":%d", ntohs(udp->uh_dport)); - break; - case IPPROTO_ICMPV6: - if (off > 0) - printf("IPV6-ICMP:%u.%u ", icmp6->icmp6_type, icmp6->icmp6_code); - else - printf("IPV6-ICMP "); - print_ip6(&ip6->ip6_src); - printf(" "); - print_ip6(&ip6->ip6_dst); - break; - default: - printf("P:%d ", nxt); - print_ip6(&ip6->ip6_src); - printf(" "); - print_ip6(&ip6->ip6_dst); - break; - } - if (oif) - printf(" out via %s", if_name(oif)); - else if (rif) - printf(" in via %s", if_name(rif)); - printf("\n"); - if (fw6_verbose_limit != 0 && count == fw6_verbose_limit) - printf("ip6fw: limit reached on rule #%d\n", - f ? f->fw_number : -1); -} - -/* - * Parameters: - * - * ip Pointer to packet header (struct ip6_hdr *) - * hlen Packet header length - * oif Outgoing interface, or NULL if packet is incoming - * #ifndef IP6FW_DIVERT_RESTART - * *cookie Ignore all divert/tee rules to this port (if non-zero) - * #else - * *cookie Skip up to the first rule past this rule number; - * #endif - * *m The packet; we set to NULL when/if we nuke it. - * - * Return value: - * - * 0 The packet is to be accepted and routed normally OR - * the packet was denied/rejected and has been dropped; - * in the latter case, *m is equal to NULL upon return. - * port Divert the packet to port. - */ - -static int -ip6_fw_chk(struct ip6_hdr **pip6, - struct ifnet *oif, u_int16_t *cookie, struct mbuf **m) -{ - struct ip6_fw_chain *chain; - struct ip6_fw *rule = NULL; - struct ip6_hdr *ip6 = *pip6; - struct ifnet *const rif = (*m)->m_pkthdr.rcvif; - u_short offset = 0; - int off = sizeof(struct ip6_hdr), nxt = ip6->ip6_nxt; - u_short src_port, dst_port; -#if IP6FW_DIVERT_RESTART - u_int16_t skipto = *cookie; -#else - u_int16_t ignport = ntohs(*cookie); -#endif - - *cookie = 0; - /* - * Go down the chain, looking for enlightment - * #if IP6FW_DIVERT_RESTART - * If we've been asked to start at a given rule immediatly, do so. - * #endif - */ - chain = LIST_FIRST(&ip6_fw_chain); -#if IP6FW_DIVERT_RESTART - if (skipto) { - if (skipto >= 65535) - goto dropit; - while (chain && (chain->rule->fw_number <= skipto)) { - chain = LIST_NEXT(chain, chain); - } - if (! chain) goto dropit; - } -#endif /* IP6FW_DIVERT_RESTART */ - for (; chain; chain = LIST_NEXT(chain, chain)) { - register struct ip6_fw *const f = chain->rule; - - if (oif) { - /* Check direction outbound */ - if (!(f->fw_flg & IPV6_FW_F_OUT)) - continue; - } else { - /* Check direction inbound */ - if (!(f->fw_flg & IPV6_FW_F_IN)) - continue; - } - -#define IN6_ARE_ADDR_MASKEQUAL(x,y,z) (\ - (((x)->s6_addr32[0] & (y)->s6_addr32[0]) == (z)->s6_addr32[0]) && \ - (((x)->s6_addr32[1] & (y)->s6_addr32[1]) == (z)->s6_addr32[1]) && \ - (((x)->s6_addr32[2] & (y)->s6_addr32[2]) == (z)->s6_addr32[2]) && \ - (((x)->s6_addr32[3] & (y)->s6_addr32[3]) == (z)->s6_addr32[3])) - - /* If src-addr doesn't match, not this rule. */ - if (((f->fw_flg & IPV6_FW_F_INVSRC) != 0) ^ - (!IN6_ARE_ADDR_MASKEQUAL(&ip6->ip6_src,&f->fw_smsk,&f->fw_src))) - continue; - - /* If dest-addr doesn't match, not this rule. */ - if (((f->fw_flg & IPV6_FW_F_INVDST) != 0) ^ - (!IN6_ARE_ADDR_MASKEQUAL(&ip6->ip6_dst,&f->fw_dmsk,&f->fw_dst))) - continue; - -#undef IN6_ARE_ADDR_MASKEQUAL - /* Interface check */ - if ((f->fw_flg & IF6_FW_F_VIAHACK) == IF6_FW_F_VIAHACK) { - struct ifnet *const iface = oif ? oif : rif; - - /* Backwards compatibility hack for "via" */ - if (!iface || !iface_match(iface, - &f->fw_in_if, f->fw_flg & IPV6_FW_F_OIFNAME)) - continue; - } else { - /* Check receive interface */ - if ((f->fw_flg & IPV6_FW_F_IIFACE) - && (!rif || !iface_match(rif, - &f->fw_in_if, f->fw_flg & IPV6_FW_F_IIFNAME))) - continue; - /* Check outgoing interface */ - if ((f->fw_flg & IPV6_FW_F_OIFACE) - && (!oif || !iface_match(oif, - &f->fw_out_if, f->fw_flg & IPV6_FW_F_OIFNAME))) - continue; - } - - /* Check IP options */ - if (!ip6opts_match(&ip6, f, m, &off, &nxt, &offset)) - continue; - - /* Fragments */ - if ((f->fw_flg & IPV6_FW_F_FRAG) && !offset) - continue; - - /* Check protocol; if wildcard, match */ - if (f->fw_prot == IPPROTO_IPV6) - goto got_match; - - /* If different, don't match */ - if (nxt != f->fw_prot) - continue; - -#define PULLUP_TO(len) do { \ - if ((*m)->m_len < (len) \ - && (*m = m_pullup(*m, (len))) == 0) { \ - goto dropit; \ - } \ - *pip6 = ip6 = mtod(*m, struct ip6_hdr *); \ - } while (0) - - /* Protocol specific checks */ - switch (nxt) { - case IPPROTO_TCP: - { - struct tcphdr *tcp6; - - if (offset == 1) { /* cf. RFC 1858 */ - PULLUP_TO(off + 4); /* XXX ? */ - goto bogusfrag; - } - if (offset != 0) { - /* - * TCP flags and ports aren't available in this - * packet -- if this rule specified either one, - * we consider the rule a non-match. - */ - if (f->fw_nports != 0 || - f->fw_tcpf != f->fw_tcpnf) - continue; - - break; - } - PULLUP_TO(off + 14); - tcp6 = (struct tcphdr *) ((caddr_t)ip6 + off); - if (f->fw_tcpf != f->fw_tcpnf && !tcp6flg_match(tcp6, f)) - continue; - src_port = ntohs(tcp6->th_sport); - dst_port = ntohs(tcp6->th_dport); - goto check_ports; - } - - case IPPROTO_UDP: - { - struct udphdr *udp; - - if (offset != 0) { - /* - * Port specification is unavailable -- if this - * rule specifies a port, we consider the rule - * a non-match. - */ - if (f->fw_nports != 0) - continue; - - break; - } - PULLUP_TO(off + 4); - udp = (struct udphdr *) ((caddr_t)ip6 + off); - src_port = ntohs(udp->uh_sport); - dst_port = ntohs(udp->uh_dport); -check_ports: - if (!port_match6(&f->fw_pts[0], - IPV6_FW_GETNSRCP(f), src_port, - f->fw_flg & IPV6_FW_F_SRNG)) - continue; - if (!port_match6(&f->fw_pts[IPV6_FW_GETNSRCP(f)], - IPV6_FW_GETNDSTP(f), dst_port, - f->fw_flg & IPV6_FW_F_DRNG)) - continue; - break; - } - - case IPPROTO_ICMPV6: - { - struct icmp6_hdr *icmp; - - if (offset != 0) /* Type isn't valid */ - break; - PULLUP_TO(off + 2); - icmp = (struct icmp6_hdr *) ((caddr_t)ip6 + off); - if (!icmp6type_match(icmp, f)) - continue; - break; - } -#undef PULLUP_TO - -bogusfrag: - if (fw6_verbose) - ip6fw_report(NULL, ip6, rif, oif, off, nxt); - goto dropit; - } - -got_match: -#ifndef IP6FW_DIVERT_RESTART - /* Ignore divert/tee rule if socket port is "ignport" */ - switch (f->fw_flg & IPV6_FW_F_COMMAND) { - case IPV6_FW_F_DIVERT: - case IPV6_FW_F_TEE: - if (f->fw_divert_port == ignport) - continue; /* ignore this rule */ - break; - } - -#endif /* IP6FW_DIVERT_RESTART */ - /* Update statistics */ - f->fw_pcnt += 1; - f->fw_bcnt += ntohs(ip6->ip6_plen); -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - f->timestamp = time_second; -#else - f->timestamp = time.tv_sec; -#endif - - /* Log to console if desired */ - if ((f->fw_flg & IPV6_FW_F_PRN) && fw6_verbose) - ip6fw_report(f, ip6, rif, oif, off, nxt); - - /* Take appropriate action */ - switch (f->fw_flg & IPV6_FW_F_COMMAND) { - case IPV6_FW_F_ACCEPT: - return(0); - case IPV6_FW_F_COUNT: - continue; - case IPV6_FW_F_DIVERT: -#if IP6FW_DIVERT_RESTART - *cookie = f->fw_number; -#else - *cookie = htons(f->fw_divert_port); -#endif /* IP6FW_DIVERT_RESTART */ - return(f->fw_divert_port); - case IPV6_FW_F_TEE: - /* - * XXX someday tee packet here, but beware that you - * can't use m_copym() or m_copypacket() because - * the divert input routine modifies the mbuf - * (and these routines only increment reference - * counts in the case of mbuf clusters), so need - * to write custom routine. - */ - continue; - case IPV6_FW_F_SKIPTO: -#if DIAGNOSTIC - while (chain->chain.le_next - && chain->chain.le_next->rule->fw_number - < f->fw_skipto_rule) -#else - while (chain->chain.le_next->rule->fw_number - < f->fw_skipto_rule) -#endif - chain = chain->chain.le_next; - continue; - } - - /* Deny/reject this packet using this rule */ - rule = f; - break; - } - -#if DIAGNOSTIC - /* Rule 65535 should always be there and should always match */ - if (!chain) - panic("ip6_fw: chain"); -#endif - - /* - * At this point, we're going to drop the packet. - * Send a reject notice if all of the following are true: - * - * - The packet matched a reject rule - * - The packet is not an ICMP packet, or is an ICMP query packet - * - The packet is not a multicast or broadcast packet - */ - if ((rule->fw_flg & IPV6_FW_F_COMMAND) == IPV6_FW_F_REJECT - && (nxt != IPPROTO_ICMPV6 || is_icmp6_query(ip6, off)) - && !((*m)->m_flags & (M_BCAST|M_MCAST)) - && !IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { - switch (rule->fw_reject_code) { - case IPV6_FW_REJECT_RST: -#if 1 /*not tested*/ - { - struct tcphdr *const tcp = - (struct tcphdr *) ((caddr_t)ip6 + off); - struct { - struct ip6_hdr ip6; - struct tcphdr th; - } ti; - tcp_seq ack, seq; - int flags; - - if (offset != 0 || (tcp->th_flags & TH_RST)) - break; - - ti.ip6 = *ip6; - ti.th = *tcp; - NTOHL(ti.th.th_seq); - NTOHL(ti.th.th_ack); - ti.ip6.ip6_nxt = IPPROTO_TCP; - if (ti.th.th_flags & TH_ACK) { - ack = 0; - seq = ti.th.th_ack; - flags = TH_RST; - } else { - ack = ti.th.th_seq; - if (((*m)->m_flags & M_PKTHDR) != 0) { - ack += (*m)->m_pkthdr.len - off - - (ti.th.th_off << 2); - } else if (ip6->ip6_plen) { - ack += ntohs(ip6->ip6_plen) + sizeof(*ip6) - - off - (ti.th.th_off << 2); - } else { - m_freem(*m); - *m = 0; - break; - } - seq = 0; - flags = TH_RST|TH_ACK; - } - bcopy(&ti, ip6, sizeof(ti)); -#if TCP6 - tcp6_respond(NULL, ip6, (struct tcp6hdr *)(ip6 + 1), - *m, ack, seq, flags); -#elif defined(__NetBSD__) - tcp_respond(NULL, NULL, *m, (struct tcphdr *)(ip6 + 1), - ack, seq, flags); -#elif defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) - tcp_respond(NULL, ip6, (struct tcphdr *)(ip6 + 1), - *m, ack, seq, flags, 1); -#else - m_freem(*m); -#endif - *m = NULL; - break; - } -#endif - default: /* Send an ICMP unreachable using code */ - if (oif) - (*m)->m_pkthdr.rcvif = oif; - icmp6_error(*m, ICMP6_DST_UNREACH, - rule->fw_reject_code, 0); - *m = NULL; - break; - } - } - -dropit: - /* - * Finally, drop the packet. - */ - if (*m) { - m_freem(*m); - *m = NULL; - } - return(0); -} - -static int -add_entry6(struct ip6_fw_head *chainptr, struct ip6_fw *frwl) -{ - struct ip6_fw *ftmp = 0; - struct ip6_fw_chain *fwc = 0, *fcp, *fcpl = 0; - u_short nbr = 0; - int s; - - fwc = _MALLOC(sizeof *fwc, M_IP6FW, M_NOWAIT); - ftmp = _MALLOC(sizeof *ftmp, M_IP6FW, M_NOWAIT); - if (!fwc || !ftmp) { - dprintf(("%s malloc said no\n", err_prefix)); - if (fwc) _FREE(fwc, M_IP6FW); - if (ftmp) _FREE(ftmp, M_IP6FW); - return (ENOSPC); - } - - bcopy(frwl, ftmp, sizeof(struct ip6_fw)); - ftmp->fw_in_if.fu_via_if.name[FW_IFNLEN - 1] = '\0'; - ftmp->fw_pcnt = 0L; - ftmp->fw_bcnt = 0L; - fwc->rule = ftmp; - - s = splnet(); - - if (!chainptr->lh_first) { - LIST_INSERT_HEAD(chainptr, fwc, chain); - splx(s); - return(0); - } else if (ftmp->fw_number == (u_short)-1) { - if (fwc) _FREE(fwc, M_IP6FW); - if (ftmp) _FREE(ftmp, M_IP6FW); - splx(s); - dprintf(("%s bad rule number\n", err_prefix)); - return (EINVAL); - } - - /* If entry number is 0, find highest numbered rule and add 100 */ - if (ftmp->fw_number == 0) { - for (fcp = chainptr->lh_first; fcp; fcp = fcp->chain.le_next) { - if (fcp->rule->fw_number != (u_short)-1) - nbr = fcp->rule->fw_number; - else - break; - } - if (nbr < (u_short)-1 - 100) - nbr += 100; - ftmp->fw_number = nbr; - } - - /* Got a valid number; now insert it, keeping the list ordered */ - for (fcp = chainptr->lh_first; fcp; fcp = fcp->chain.le_next) { - if (fcp->rule->fw_number > ftmp->fw_number) { - if (fcpl) { - LIST_INSERT_AFTER(fcpl, fwc, chain); - } else { - LIST_INSERT_HEAD(chainptr, fwc, chain); - } - break; - } else { - fcpl = fcp; - } - } - - splx(s); - return (0); -} - -static int -del_entry6(struct ip6_fw_head *chainptr, u_short number) -{ - struct ip6_fw_chain *fcp; - int s; - - s = splnet(); - - fcp = chainptr->lh_first; - if (number != (u_short)-1) { - for (; fcp; fcp = fcp->chain.le_next) { - if (fcp->rule->fw_number == number) { - LIST_REMOVE(fcp, chain); - splx(s); - _FREE(fcp->rule, M_IP6FW); - _FREE(fcp, M_IP6FW); - return 0; - } - } - } - - splx(s); - return (EINVAL); -} - -static int -zero_entry6(struct mbuf *m) -{ - struct ip6_fw *frwl; - struct ip6_fw_chain *fcp; - int s; - - if (m) { - if (m->m_len != sizeof(struct ip6_fw)) - return(EINVAL); - frwl = mtod(m, struct ip6_fw *); - } - else - frwl = NULL; - - /* - * It's possible to insert multiple chain entries with the - * same number, so we don't stop after finding the first - * match if zeroing a specific entry. - */ - s = splnet(); - for (fcp = ip6_fw_chain.lh_first; fcp; fcp = fcp->chain.le_next) - if (!frwl || frwl->fw_number == fcp->rule->fw_number) { - fcp->rule->fw_bcnt = fcp->rule->fw_pcnt = 0; - fcp->rule->timestamp = 0; - } - splx(s); - - if (fw6_verbose) { - if (frwl) - printf("ip6fw: Entry %d cleared.\n", frwl->fw_number); - else - printf("ip6fw: Accounting cleared.\n"); - } - - return(0); -} - -static struct ip6_fw * -check_ip6fw_mbuf(struct mbuf *m) -{ - /* Check length */ - if (m->m_len != sizeof(struct ip6_fw)) { - dprintf(("%s len=%d, want %d\n", err_prefix, m->m_len, - sizeof(struct ip6_fw))); - return (NULL); - } - return(check_ip6fw_struct(mtod(m, struct ip6_fw *))); -} - -static struct ip6_fw * -check_ip6fw_struct(struct ip6_fw *frwl) -{ - /* Check for invalid flag bits */ - if ((frwl->fw_flg & ~IPV6_FW_F_MASK) != 0) { - dprintf(("%s undefined flag bits set (flags=%x)\n", - err_prefix, frwl->fw_flg)); - return (NULL); - } - /* Must apply to incoming or outgoing (or both) */ - if (!(frwl->fw_flg & (IPV6_FW_F_IN | IPV6_FW_F_OUT))) { - dprintf(("%s neither in nor out\n", err_prefix)); - return (NULL); - } - /* Empty interface name is no good */ - if (((frwl->fw_flg & IPV6_FW_F_IIFNAME) - && !*frwl->fw_in_if.fu_via_if.name) - || ((frwl->fw_flg & IPV6_FW_F_OIFNAME) - && !*frwl->fw_out_if.fu_via_if.name)) { - dprintf(("%s empty interface name\n", err_prefix)); - return (NULL); - } - /* Sanity check interface matching */ - if ((frwl->fw_flg & IF6_FW_F_VIAHACK) == IF6_FW_F_VIAHACK) { - ; /* allow "via" backwards compatibility */ - } else if ((frwl->fw_flg & IPV6_FW_F_IN) - && (frwl->fw_flg & IPV6_FW_F_OIFACE)) { - dprintf(("%s outgoing interface check on incoming\n", - err_prefix)); - return (NULL); - } - /* Sanity check port ranges */ - if ((frwl->fw_flg & IPV6_FW_F_SRNG) && IPV6_FW_GETNSRCP(frwl) < 2) { - dprintf(("%s src range set but n_src_p=%d\n", - err_prefix, IPV6_FW_GETNSRCP(frwl))); - return (NULL); - } - if ((frwl->fw_flg & IPV6_FW_F_DRNG) && IPV6_FW_GETNDSTP(frwl) < 2) { - dprintf(("%s dst range set but n_dst_p=%d\n", - err_prefix, IPV6_FW_GETNDSTP(frwl))); - return (NULL); - } - if (IPV6_FW_GETNSRCP(frwl) + IPV6_FW_GETNDSTP(frwl) > IPV6_FW_MAX_PORTS) { - dprintf(("%s too many ports (%d+%d)\n", - err_prefix, IPV6_FW_GETNSRCP(frwl), IPV6_FW_GETNDSTP(frwl))); - return (NULL); - } - /* - * Protocols other than TCP/UDP don't use port range - */ - if ((frwl->fw_prot != IPPROTO_TCP) && - (frwl->fw_prot != IPPROTO_UDP) && - (IPV6_FW_GETNSRCP(frwl) || IPV6_FW_GETNDSTP(frwl))) { - dprintf(("%s port(s) specified for non TCP/UDP rule\n", - err_prefix)); - return(NULL); - } - - /* - * Rather than modify the entry to make such entries work, - * we reject this rule and require user level utilities - * to enforce whatever policy they deem appropriate. - */ - if ((frwl->fw_src.s6_addr32[0] & (~frwl->fw_smsk.s6_addr32[0])) || - (frwl->fw_src.s6_addr32[1] & (~frwl->fw_smsk.s6_addr32[1])) || - (frwl->fw_src.s6_addr32[2] & (~frwl->fw_smsk.s6_addr32[2])) || - (frwl->fw_src.s6_addr32[3] & (~frwl->fw_smsk.s6_addr32[3])) || - (frwl->fw_dst.s6_addr32[0] & (~frwl->fw_dmsk.s6_addr32[0])) || - (frwl->fw_dst.s6_addr32[1] & (~frwl->fw_dmsk.s6_addr32[1])) || - (frwl->fw_dst.s6_addr32[2] & (~frwl->fw_dmsk.s6_addr32[2])) || - (frwl->fw_dst.s6_addr32[3] & (~frwl->fw_dmsk.s6_addr32[3]))) { - dprintf(("%s rule never matches\n", err_prefix)); - return(NULL); - } - - if ((frwl->fw_flg & IPV6_FW_F_FRAG) && - (frwl->fw_prot == IPPROTO_UDP || frwl->fw_prot == IPPROTO_TCP)) { - if (frwl->fw_nports) { - dprintf(("%s cannot mix 'frag' and ports\n", err_prefix)); - return(NULL); - } - if (frwl->fw_prot == IPPROTO_TCP && - frwl->fw_tcpf != frwl->fw_tcpnf) { - dprintf(("%s cannot mix 'frag' with TCP flags\n", err_prefix)); - return(NULL); - } - } - - /* Check command specific stuff */ - switch (frwl->fw_flg & IPV6_FW_F_COMMAND) - { - case IPV6_FW_F_REJECT: - if (frwl->fw_reject_code >= 0x100 - && !(frwl->fw_prot == IPPROTO_TCP - && frwl->fw_reject_code == IPV6_FW_REJECT_RST)) { - dprintf(("%s unknown reject code\n", err_prefix)); - return(NULL); - } - break; - case IPV6_FW_F_DIVERT: /* Diverting to port zero is invalid */ - case IPV6_FW_F_TEE: - if (frwl->fw_divert_port == 0) { - dprintf(("%s can't divert to port 0\n", err_prefix)); - return (NULL); - } - break; - case IPV6_FW_F_DENY: - case IPV6_FW_F_ACCEPT: - case IPV6_FW_F_COUNT: - case IPV6_FW_F_SKIPTO: - break; - default: - dprintf(("%s invalid command\n", err_prefix)); - return(NULL); - } - - return frwl; -} - -static int -ip6_fw_ctl(int stage, struct mbuf **mm) -{ - int error; - struct mbuf *m; - - if (stage == IPV6_FW_GET) { - struct ip6_fw_chain *fcp = ip6_fw_chain.lh_first; -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) - *mm = m = m_get(M_WAIT, MT_DATA); /* XXX */ -#else - *mm = m = m_get(M_WAIT, MT_SOOPTS); -#endif - if (!m) - return(ENOBUFS); - if (sizeof *(fcp->rule) > MLEN) { - MCLGET(m, M_WAIT); - if ((m->m_flags & M_EXT) == 0) { - m_free(m); - return(ENOBUFS); - } - } - for (; fcp; fcp = fcp->chain.le_next) { - memcpy(m->m_data, fcp->rule, sizeof *(fcp->rule)); - m->m_len = sizeof *(fcp->rule); -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) - m->m_next = m_get(M_WAIT, MT_DATA); /* XXX */ -#else - m->m_next = m_get(M_WAIT, MT_SOOPTS); -#endif - if (!m->m_next) { - m_freem(*mm); - return(ENOBUFS); - } - m = m->m_next; - if (sizeof *(fcp->rule) > MLEN) { - MCLGET(m, M_WAIT); - if ((m->m_flags & M_EXT) == 0) { - m_freem(*mm); - return(ENOBUFS); - } - } - m->m_len = 0; - } - return (0); - } - m = *mm; - /* only allow get calls if secure mode > 2 */ - if (securelevel > 2) { - if (m) { - (void)m_freem(m); - *mm = 0; - } - return(EPERM); - } - if (stage == IPV6_FW_FLUSH) { - while (ip6_fw_chain.lh_first != NULL && - ip6_fw_chain.lh_first->rule->fw_number != (u_short)-1) { - struct ip6_fw_chain *fcp = ip6_fw_chain.lh_first; - int s = splnet(); - LIST_REMOVE(ip6_fw_chain.lh_first, chain); - splx(s); - _FREE(fcp->rule, M_IP6FW); - _FREE(fcp, M_IP6FW); - } - if (m) { - (void)m_freem(m); - *mm = 0; - } - return (0); - } - if (stage == IPV6_FW_ZERO) { - error = zero_entry6(m); - if (m) { - (void)m_freem(m); - *mm = 0; - } - return (error); - } - if (m == NULL) { - printf("%s NULL mbuf ptr\n", err_prefix); - return (EINVAL); - } - - if (stage == IPV6_FW_ADD) { - struct ip6_fw *frwl = check_ip6fw_mbuf(m); - - if (!frwl) - error = EINVAL; - else - error = add_entry6(&ip6_fw_chain, frwl); - if (m) { - (void)m_freem(m); - *mm = 0; - } - return error; - } - if (stage == IPV6_FW_DEL) { - if (m->m_len != sizeof(struct ip6_fw)) { - dprintf(("%s len=%d, want %d\n", err_prefix, m->m_len, - sizeof(struct ip6_fw))); - error = EINVAL; - } else if (mtod(m, struct ip6_fw *)->fw_number == (u_short)-1) { - dprintf(("%s can't delete rule 65535\n", err_prefix)); - error = EINVAL; - } else - error = del_entry6(&ip6_fw_chain, - mtod(m, struct ip6_fw *)->fw_number); - if (m) { - (void)m_freem(m); - *mm = 0; - } - return error; - } - - dprintf(("%s unknown request %d\n", err_prefix, stage)); - if (m) { - (void)m_freem(m); - *mm = 0; - } - return (EINVAL); -} - -void -ip6_fw_init(void) -{ - struct ip6_fw default_rule; - - ip6_fw_chk_ptr = ip6_fw_chk; - ip6_fw_ctl_ptr = ip6_fw_ctl; - LIST_INIT(&ip6_fw_chain); - - bzero(&default_rule, sizeof default_rule); - default_rule.fw_prot = IPPROTO_IPV6; - default_rule.fw_number = (u_short)-1; -#if IPV6FIREWALL_DEFAULT_TO_ACCEPT - default_rule.fw_flg |= IPV6_FW_F_ACCEPT; -#else - default_rule.fw_flg |= IPV6_FW_F_DENY; -#endif - default_rule.fw_flg |= IPV6_FW_F_IN | IPV6_FW_F_OUT; - if (check_ip6fw_struct(&default_rule) == NULL || - add_entry6(&ip6_fw_chain, &default_rule)) - panic(__FUNCTION__); - -#if 1 /* NOT SUPPORTED IPV6 DIVERT */ - printf("IPv6 packet filtering initialized, "); -#else - printf("IPv6 packet filtering initialized, " -#if IP6DIVERT - "divert enabled, "); -#else - "divert disabled, "); -#endif -#endif -#if IPV6FIREWALL_DEFAULT_TO_ACCEPT - printf("default to accept, "); -#endif -#ifndef IPV6FIREWALL_VERBOSE - printf("logging disabled\n"); -#else - if (fw6_verbose_limit == 0) - printf("unlimited logging\n"); - else - printf("logging limited to %d packets/entry\n", - fw6_verbose_limit); -#endif -} diff --git a/bsd/netinet6/ip6_fw.h b/bsd/netinet6/ip6_fw.h index 59c1fd933..ea7b3fe75 100644 --- a/bsd/netinet6/ip6_fw.h +++ b/bsd/netinet6/ip6_fw.h @@ -1,5 +1,24 @@ -/* $KAME: ip6_fw.h,v 1.2 2000/02/22 14:04:21 itojun Exp $ */ - +/* + * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ /* * Copyright (c) 1993 Daniel Boulet * Copyright (c) 1994 Ugen J.S.Antsilevich @@ -17,8 +36,13 @@ #ifndef _IP6_FW_H #define _IP6_FW_H +#include #include +#ifdef __APPLE_API_PRIVATE + +#define IP6_FW_CURRENT_API_VERSION 20 /* Version of this API */ + /* * This union structure identifies an interface, either explicitly @@ -36,8 +60,8 @@ union ip6_fw_if { struct in6_addr fu_via_ip6; /* Specified by IPv6 address */ struct { /* Specified by interface name */ -#define FW_IFNLEN IFNAMSIZ - char name[FW_IFNLEN]; +#define IP6FW_IFNLEN IFNAMSIZ + char name[IP6FW_IFNLEN]; short unit; /* -1 means match any unit */ } fu_via_if; }; @@ -52,16 +76,21 @@ union ip6_fw_if { */ struct ip6_fw { + u_int32_t version; /* Version of this structure. Should always be */ + /* set to IP6_FW_CURRENT_API_VERSION by clients. */ + void *context; /* Context that is usable by user processes to */ + /* identify this rule. */ u_long fw_pcnt,fw_bcnt; /* Packet and byte counters */ struct in6_addr fw_src, fw_dst; /* Source and destination IPv6 addr */ struct in6_addr fw_smsk, fw_dmsk; /* Mask for src and dest IPv6 addr */ u_short fw_number; /* Rule number */ u_short fw_flg; /* Flags word */ #define IPV6_FW_MAX_PORTS 10 /* A reasonable maximum */ + u_int fw_ipflg; /* IP flags word */ u_short fw_pts[IPV6_FW_MAX_PORTS]; /* Array of port numbers to match */ u_char fw_ip6opt,fw_ip6nopt; /* IPv6 options set/unset */ u_char fw_tcpf,fw_tcpnf; /* TCP flags set/unset */ -#define IPV6_FW_ICMPTYPES_DIM (32 / (sizeof(unsigned) * 8)) +#define IPV6_FW_ICMPTYPES_DIM (256 / (sizeof(unsigned) * 8)) unsigned fw_icmp6types[IPV6_FW_ICMPTYPES_DIM]; /* ICMP types bitmap */ long timestamp; /* timestamp (tv_sec) of last match */ union ip6_fw_if fw_in_if, fw_out_if;/* Incoming and outgoing interfaces */ @@ -136,6 +165,11 @@ struct ip6_fw_chain { #define IPV6_FW_F_MASK 0xFFFF /* All possible flag bits mask */ +/* + * Flags for the 'fw_ipflg' field, for comparing values of ip and its protocols. */ +#define IPV6_FW_IF_TCPEST 0x00000020 /* established TCP connection */ +#define IPV6_FW_IF_TCPMSK 0x00000020 /* mask of all TCP values */ + /* * For backwards compatibility with rules specifying "via iface" but * not restricted to only "in" or "out" packets, we define this combination @@ -170,36 +204,14 @@ struct ip6_fw_chain { #define IPV6_FW_TCPF_PSH TH_PUSH #define IPV6_FW_TCPF_ACK TH_ACK #define IPV6_FW_TCPF_URG TH_URG -#define IPV6_FW_TCPF_ESTAB 0x40 - -/* - * Names for IPV6_FW sysctl objects - */ -#define IP6FWCTL_DEBUG 1 -#define IP6FWCTL_VERBOSE 2 -#define IP6FWCTL_VERBLIMIT 3 -#define IP6FWCTL_MAXID 4 - -#define IP6FWCTL_NAMES { \ - { 0, 0 }, \ - { 0, 0 }, \ - { "debug", CTLTYPE_INT }, \ - { "verbose", CTLTYPE_INT }, \ - { "verbose_limit", CTLTYPE_INT }, \ -} - -#define IP6FWCTL_VARS { \ - 0, \ - 0, \ - &fw6_debug, \ - &fw6_verbose, \ - &fw6_verbose_limit, \ -} /* * Main firewall chains definitions and global var's definitions. */ -#if KERNEL +#ifdef KERNEL + +#define M_IP6FW M_IPFW + /* * Function definitions. @@ -213,7 +225,9 @@ typedef int ip6_fw_chk_t __P((struct ip6_hdr**, struct ifnet*, typedef int ip6_fw_ctl_t __P((int, struct mbuf**)); extern ip6_fw_chk_t *ip6_fw_chk_ptr; extern ip6_fw_ctl_t *ip6_fw_ctl_ptr; +extern int ip6_fw_enable; #endif /* KERNEL */ +#endif /* __APPLE_API_PRIVATE */ #endif /* _IP6_FW_H */ diff --git a/bsd/netinet6/ip6_input.c b/bsd/netinet6/ip6_input.c index 0f69d6a6b..2d87b6f5c 100644 --- a/bsd/netinet6/ip6_input.c +++ b/bsd/netinet6/ip6_input.c @@ -1,4 +1,5 @@ -/* $KAME: ip6_input.c,v 1.75 2000/03/28 23:11:05 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/ip6_input.c,v 1.11.2.10 2001/07/24 19:10:18 brooks Exp $ */ +/* $KAME: ip6_input.c,v 1.194 2001/05/27 13:28:35 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -63,16 +64,7 @@ * * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 */ -#define _IP_VHL -#ifdef __FreeBSD__ -#include "opt_ip6fw.h" -#endif -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#ifdef __NetBSD__ /*XXX*/ -#include "opt_ipsec.h" -#endif -#endif + #include #include @@ -86,11 +78,10 @@ #include #include #include -#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) #include -#endif #include +#include #include #include #include @@ -105,111 +96,73 @@ #include #include #include -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802) || defined (__APPLE__) #include -#endif -#if defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802) -#include -#endif #include #include #include #include -#if MIP6 -#include +#if IPSEC +#include +#if INET6 +#include +#endif +extern int ipsec_bypass; #endif -#if IPV6FIREWALL #include -#endif #include /* we need it for NLOOP. */ -#ifndef __bsdi__ #include "loop.h" -#endif #include "faith.h" -#include "gif.h" -#include "bpfilter.h" #include extern struct domain inet6domain; extern struct ip6protosw inet6sw[]; -#ifdef __bsdi__ -#if _BSDI_VERSION < 199802 -extern struct ifnet loif; -#else -extern struct ifnet *loifp; -#endif -#endif struct ip6protosw * ip6_protox[IPPROTO_MAX]; static int ip6qmaxlen = IFQ_MAXLEN; struct in6_ifaddr *in6_ifaddr; -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 4) -struct ifqueue ip6intrq; -#endif -#if defined(__NetBSD__) || defined(__OpenBSD__) -extern struct ifnet loif[NLOOP]; -#endif +extern void in6_tmpaddrtimer_funneled(void *); +extern void nd6_timer_funneled(void *); +extern void in6_rr_timer_funneled(void *); + int ip6_forward_srcrt; /* XXX */ int ip6_sourcecheck; /* XXX */ int ip6_sourcecheck_interval; /* XXX */ -#if defined(__FreeBSD__) && __FreeBSD__ >= 4 const int int6intrq_present = 1; -#endif -#if IPV6FIREWALL +int ip6_ours_check_algorithm; +int in6_init2done = 0; + + /* firewall hooks */ ip6_fw_chk_t *ip6_fw_chk_ptr; ip6_fw_ctl_t *ip6_fw_ctl_ptr; -#endif +int ip6_fw_enable = 1; struct ip6stat ip6stat; +#ifdef __APPLE__ +struct ifqueue ip6intrq; +#endif + static void ip6_init2 __P((void *)); +static struct mbuf *ip6_setdstifaddr __P((struct mbuf *, struct in6_ifaddr *)); static int ip6_hopopts_input __P((u_int32_t *, u_int32_t *, struct mbuf **, int *)); #if PULLDOWN_TEST static struct mbuf *ip6_pullexthdr __P((struct mbuf *, size_t, int)); #endif -#if NATPT -extern int ip6_protocol_tr; - -int natpt_in6 __P((struct mbuf *, struct mbuf **)); -extern void ip_forward __P((struct mbuf *, int)); -#endif - -/* Initialize the PF_INET6 domain, and add in the pre-defined protos */ -void -in6_dinit() -{ register int i; - register struct ip6protosw *pr; - register struct domain *dp; - static inet6domain_initted = 0; - extern int in6_proto_count; - - if (!inet6domain_initted) - { - dp = &inet6domain; - - for (i=0, pr = &inet6sw[0]; ipr_next) { + for (pr = (struct ip6protosw*)inet6domain.dom_protosw; pr; pr = pr->pr_next) { if(!((unsigned int)pr->pr_domain)) continue; /* If uninitialized, skip */ if (pr->pr_domain->dom_family == PF_INET6 && pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) { @@ -237,60 +194,75 @@ ip6_init() } ip6intrq.ifq_maxlen = ip6qmaxlen; +#ifndef __APPLE__ + register_netisr(NETISR_IPV6, ip6intr); +#endif nd6_init(); frag6_init(); -#if IPV6FIREWALL - ip6_fw_init(); -#endif /* * in many cases, random() here does NOT return random number * as initialization during bootstrap time occur in fixed order. */ microtime(&tv); ip6_flow_seq = random() ^ tv.tv_usec; - timeout(ip6_init2, (caddr_t)0, 6 * hz); + microtime(&tv); + ip6_desync_factor = (random() ^ tv.tv_usec) % MAX_TEMP_DESYNC_FACTOR; + timeout(ip6_init2, (caddr_t)0, 1 * hz); } static void ip6_init2(dummy) void *dummy; { - int ret; -#if defined(__bsdi__) && _BSDI_VERSION < 199802 - struct ifnet *loifp = &loif; -#endif #ifdef __APPLE__ boolean_t funnel_state; funnel_state = thread_funnel_set(network_flock, TRUE); #endif - - /* get EUI64 from somewhere */ - ret = in6_ifattach_getifid(NULL); - /* * to route local address of p2p link to loopback, * assign loopback address first. */ - in6_ifattach(&loif[0], IN6_IFT_LOOP, NULL, 0); + in6_ifattach(&loif[0], NULL); -#if MIP6 - /* Initialize the Mobile IPv6 code */ - mip6_init(); -#endif +#ifdef __APPLE__ + /* nd6_timer_init */ + timeout(nd6_timer_funneled, (caddr_t)0, hz); -#import -#if NGIF > 0 - gifattach(); + /* router renumbering prefix list maintenance */ + timeout(in6_rr_timer_funneled, (caddr_t)0, hz); + + /* timer for regeneranation of temporary addresses randomize ID */ + timeout(in6_tmpaddrtimer_funneled, (caddr_t)0, + (ip6_temp_preferred_lifetime - ip6_desync_factor - + ip6_temp_regen_advance) * hz); + +#if NGIF + gifattach(); #endif -#import -#if NFAITH > 0 - faithattach(); +#if NFAITH + faithattach(); #endif - +#if NSTF + stfattach(); +#endif +#else /* nd6_timer_init */ - timeout(nd6_timer_funneled, (caddr_t)0, hz); + + callout_init(&nd6_timer_ch); + callout_reset(&nd6_timer_ch, hz, nd6_timer, NULL); + /* router renumbering prefix list maintenance */ - timeout(in6_rr_timer_funneled, (caddr_t)0, hz); + callout_init(&in6_rr_timer_ch); + callout_reset(&in6_rr_timer_ch, hz, in6_rr_timer, NULL); + + /* timer for regeneranation of temporary addresses randomize ID */ + callout_reset(&in6_tmpaddrtimer_ch, + (ip6_temp_preferred_lifetime - ip6_desync_factor - + ip6_temp_regen_advance) * hz, + in6_tmpaddrtimer, NULL); +#endif + + in6_init2done = 1; #ifdef __APPLE__ (void) thread_funnel_set(network_flock, FALSE); #endif @@ -298,7 +270,8 @@ ip6_init2(dummy) #if __FreeBSD__ /* cheat */ -SYSINIT(netinet6init2, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, ip6_init2, NULL); +/* This must be after route_init(), which is now SI_ORDER_THIRD */ +SYSINIT(netinet6init2, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE, ip6_init2, NULL); #endif /* @@ -320,8 +293,6 @@ ip6intr(void) } } -NETISR_SET(NETISR_IPV6, ip6intr); - extern struct route_in6 ip6_forward_rt; void @@ -334,9 +305,6 @@ ip6_input(m) u_int32_t rtalert = ~0; int nxt = 0, ours = 0; struct ifnet *deliverifp = NULL; -#if defined(__bsdi__) && _BSDI_VERSION < 199802 - struct ifnet *loifp = &loif; -#endif #if IPSEC /* @@ -349,6 +317,11 @@ ip6_input(m) } #endif + /* + * make sure we don't have onion peering information into m_aux. + */ + ip6_delaux(m); + /* * mbuf statistics by kazu */ @@ -358,22 +331,51 @@ ip6_input(m) else ip6stat.ip6s_mext1++; } else { +#define M2MMAX (sizeof(ip6stat.ip6s_m2m)/sizeof(ip6stat.ip6s_m2m[0])) if (m->m_next) { - if (m->m_flags & M_LOOP) + if (m->m_flags & M_LOOP) { ip6stat.ip6s_m2m[loif[0].if_index]++; /*XXX*/ - else if (m->m_pkthdr.rcvif->if_index <= 31) + } else if (m->m_pkthdr.rcvif->if_index < M2MMAX) ip6stat.ip6s_m2m[m->m_pkthdr.rcvif->if_index]++; else ip6stat.ip6s_m2m[0]++; } else ip6stat.ip6s_m1++; +#undef M2MMAX } in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_receive); ip6stat.ip6s_total++; #ifndef PULLDOWN_TEST - /* XXX is the line really necessary? */ + /* + * L2 bridge code and some other code can return mbuf chain + * that does not conform to KAME requirement. too bad. + * XXX: fails to join if interface MTU > MCLBYTES. jumbogram? + */ + if (m && m->m_next != NULL && m->m_pkthdr.len < MCLBYTES) { + struct mbuf *n; + + MGETHDR(n, M_DONTWAIT, MT_HEADER); + if (n) + M_COPY_PKTHDR(n, m); + if (n && m->m_pkthdr.len > MHLEN) { + MCLGET(n, M_DONTWAIT); + if ((n->m_flags & M_EXT) == 0) { + m_freem(n); + n = NULL; + } + } + if (!n) { + m_freem(m); + return; /*ENOBUFS*/ + } + + m_copydata(m, 0, m->m_pkthdr.len, mtod(n, caddr_t)); + n->m_len = m->m_pkthdr.len; + m_freem(m); + m = n; + } IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), /*nothing*/); #endif @@ -397,11 +399,10 @@ ip6_input(m) ip6stat.ip6s_nxthist[ip6->ip6_nxt]++; -#if IPV6FIREWALL /* * Check with the firewall... */ - if (ip6_fw_chk_ptr) { + if (ip6_fw_enable && ip6_fw_chk_ptr) { u_short port = 0; /* If ipfw says divert, we have to just drop packet */ /* use port as a dummy argument */ @@ -412,23 +413,44 @@ ip6_input(m) if (!m) return; } -#endif /* - * Scope check + * Check against address spoofing/corruption. */ if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src) || IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst)) { + /* + * XXX: "badscope" is not very suitable for a multicast source. + */ + ip6stat.ip6s_badscope++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); + goto bad; + } + if ((IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src) || + IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) && + (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) { ip6stat.ip6s_badscope++; in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); goto bad; } - /* - * Don't check IPv4 mapped address here. SIIT assumes that - * routers would forward IPv6 native packets with IPv4 mapped - * address normally. + * The following check is not documented in specs. A malicious + * party may be able to use IPv4 mapped addr to confuse tcp/udp stack + * and bypass security checks (act as if it was from 127.0.0.1 by using + * IPv6 src ::ffff:127.0.0.1). Be cautious. + * + * This check chokes if we are in an SIIT cloud. As none of BSDs + * support IPv4-less kernel compilation, we cannot support SIIT + * environment at all. So, it makes more sense for us to reject any + * malicious packets for non-SIIT environment, than try to do a + * partical support for SIIT environment. */ + if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || + IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { + ip6stat.ip6s_badscope++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); + goto bad; + } #if 0 /* * Reject packets with IPv4 compatible addresses (auto tunnel). @@ -444,33 +466,52 @@ ip6_input(m) goto bad; } #endif - if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src) || - IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) { - if (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) { - ours = 1; - deliverifp = m->m_pkthdr.rcvif; - goto hbhcheck; - } else { + + /* drop packets if interface ID portion is already filled */ + if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) { + if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src) && + ip6->ip6_src.s6_addr16[1]) { + ip6stat.ip6s_badscope++; + goto bad; + } + if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst) && + ip6->ip6_dst.s6_addr16[1]) { ip6stat.ip6s_badscope++; - in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); goto bad; } } - if (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) { - if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst)) { - ours = 1; - deliverifp = m->m_pkthdr.rcvif; - goto hbhcheck; + if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) + ip6->ip6_src.s6_addr16[1] + = htons(m->m_pkthdr.rcvif->if_index); + if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) + ip6->ip6_dst.s6_addr16[1] + = htons(m->m_pkthdr.rcvif->if_index); + +#if 0 /* this case seems to be unnecessary. (jinmei, 20010401) */ + /* + * We use rt->rt_ifp to determine if the address is ours or not. + * If rt_ifp is lo0, the address is ours. + * The problem here is, rt->rt_ifp for fe80::%lo0/64 is set to lo0, + * so any address under fe80::%lo0/64 will be mistakenly considered + * local. The special case is supplied to handle the case properly + * by actually looking at interface addresses + * (using in6ifa_ifpwithaddr). + */ + if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) != 0 && + IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst)) { + if (!in6ifa_ifpwithaddr(m->m_pkthdr.rcvif, &ip6->ip6_dst)) { + icmp6_error(m, ICMP6_DST_UNREACH, + ICMP6_DST_UNREACH_ADDR, 0); + /* m is already freed */ + return; } - } else { - if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) - ip6->ip6_src.s6_addr16[1] - = htons(m->m_pkthdr.rcvif->if_index); - if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) - ip6->ip6_dst.s6_addr16[1] - = htons(m->m_pkthdr.rcvif->if_index); + + ours = 1; + deliverifp = m->m_pkthdr.rcvif; + goto hbhcheck; } +#endif /* * Multicast check @@ -499,23 +540,39 @@ ip6_input(m) /* * Unicast check */ - if (ip6_forward_rt.ro_rt == 0 || - !IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, - &ip6_forward_rt.ro_dst.sin6_addr)) { + switch (ip6_ours_check_algorithm) { + default: + /* + * XXX: I intentionally broke our indentation rule here, + * since this switch-case is just for measurement and + * therefore should soon be removed. + */ + if (ip6_forward_rt.ro_rt != NULL && + (ip6_forward_rt.ro_rt->rt_flags & RTF_UP) != 0 && + IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, + &((struct sockaddr_in6 *)(&ip6_forward_rt.ro_dst))->sin6_addr)) + ip6stat.ip6s_forward_cachehit++; + else { + struct sockaddr_in6 *dst6; + if (ip6_forward_rt.ro_rt) { - RTFREE(ip6_forward_rt.ro_rt); + /* route is down or destination is different */ + ip6stat.ip6s_forward_cachemiss++; + rtfree(ip6_forward_rt.ro_rt); ip6_forward_rt.ro_rt = 0; } + bzero(&ip6_forward_rt.ro_dst, sizeof(struct sockaddr_in6)); - ip6_forward_rt.ro_dst.sin6_len = sizeof(struct sockaddr_in6); - ip6_forward_rt.ro_dst.sin6_family = AF_INET6; - ip6_forward_rt.ro_dst.sin6_addr = ip6->ip6_dst; + dst6 = (struct sockaddr_in6 *)&ip6_forward_rt.ro_dst; + dst6->sin6_len = sizeof(struct sockaddr_in6); + dst6->sin6_family = AF_INET6; + dst6->sin6_addr = ip6->ip6_dst; +#if SCOPEDROUTING + ip6_forward_rt.ro_dst.sin6_scope_id = + in6_addr2scopeid(m->m_pkthdr.rcvif, &ip6->ip6_dst); +#endif -#if __FreeBSD__ || defined(__APPLE__) rtalloc_ign((struct route *)&ip6_forward_rt, RTF_PRCLONING); -#else - rtalloc((struct route *)&ip6_forward_rt); -#endif } #define rt6_key(r) ((struct sockaddr_in6 *)((r)->rt_nodes->rn_key)) @@ -528,10 +585,27 @@ ip6_input(m) * route to the loopback interface for the destination of the packet. * But we think it's even useful in some situations, e.g. when using * a special daemon which wants to intercept the packet. + * + * XXX: some OSes automatically make a cloned route for the destination + * of an outgoing packet. If the outgoing interface of the packet + * is a loopback one, the kernel would consider the packet to be + * accepted, even if we have no such address assinged on the interface. + * We check the cloned flag of the route entry to reject such cases, + * assuming that route entries for our own addresses are not made by + * cloning (it should be true because in6_addloop explicitly installs + * the host route). However, we might have to do an explicit check + * while it would be less efficient. Or, should we rather install a + * reject route for such a case? */ if (ip6_forward_rt.ro_rt && (ip6_forward_rt.ro_rt->rt_flags & (RTF_HOST|RTF_GATEWAY)) == RTF_HOST && +#if RTF_WASCLONED + !(ip6_forward_rt.ro_rt->rt_flags & RTF_WASCLONED) && +#endif +#if RTF_CLONED + !(ip6_forward_rt.ro_rt->rt_flags & RTF_CLONED) && +#endif #if 0 /* * The check below is redundant since the comparison of @@ -539,23 +613,43 @@ ip6_input(m) * already done through looking up the routing table. */ IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, - &rt6_key(ip6_forward_rt.ro_rt)->sin6_addr) && + &rt6_key(ip6_forward_rt.ro_rt)->sin6_addr) #endif ip6_forward_rt.ro_rt->rt_ifp->if_type == IFT_LOOP) { struct in6_ifaddr *ia6 = (struct in6_ifaddr *)ip6_forward_rt.ro_rt->rt_ifa; - /* packet to tentative address must not be received */ - if (ia6->ia6_flags & IN6_IFF_ANYCAST) - m->m_flags |= M_ANYCAST6; + + /* + * record address information into m_aux. + */ + (void)ip6_setdstifaddr(m, ia6); + + /* + * packets to a tentative, duplicated, or somehow invalid + * address must not be accepted. + */ if (!(ia6->ia6_flags & IN6_IFF_NOTREADY)) { - /* this interface is ready */ + /* this address is ready */ ours = 1; deliverifp = ia6->ia_ifp; /* correct? */ + /* Count the packet in the ip address stats */ +#ifndef __APPLE__ + + ia6->ia_ifa.if_ipackets++; + ia6->ia_ifa.if_ibytes += m->m_pkthdr.len; +#endif goto hbhcheck; } else { - /* this interface is not ready, fall through */ + /* address is not ready, so discard the packet. */ + nd6log((LOG_INFO, + "ip6_input: packet to an unready address %s->%s\n", + ip6_sprintf(&ip6->ip6_src), + ip6_sprintf(&ip6->ip6_dst))); + + goto bad; } } + } /* XXX indentation (see above) */ /* * FAITH(Firewall Aided Internet Translator) @@ -572,59 +666,6 @@ ip6_input(m) } #endif -#if NATPT - /* - * NAT-PT (Network Address Translation - Protocol Translation) - */ - if (ip6_protocol_tr) - { - struct mbuf *m1 = NULL; - - switch (natpt_in6(m, &m1)) - { - case IPPROTO_IP: goto processpacket; - case IPPROTO_IPV4: ip_forward(m1, 0); break; - case IPPROTO_IPV6: ip6_forward(m1, 0); break; - case IPPROTO_MAX: /* discard this packet */ - default: break; - - case IPPROTO_DONE: /* discard without free */ - return; - } - - if (m != m1) - m_freem(m); - - return; - } - - processpacket: -#endif - -#if 0 - { - /* - * Last resort: check in6_ifaddr for incoming interface. - * The code is here until I update the "goto ours hack" code above - * working right. - */ - struct ifaddr *ifa; - for (ifa = m->m_pkthdr.rcvif->if_addrlist.tqh_first; - ifa; - ifa = ifa->ifa_list.tqe_next) { - if (ifa->ifa_addr == NULL) - continue; /* just for safety */ - if (ifa->ifa_addr->sa_family != AF_INET6) - continue; - if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), &ip6->ip6_dst)) { - ours = 1; - deliverifp = ifa->ifa_ifp; - goto hbhcheck; - } - } - } -#endif - /* * Now there is no reason to process the packet if it's not our own * and we're not a router. @@ -636,6 +677,27 @@ ip6_input(m) } hbhcheck: + /* + * record address information into m_aux, if we don't have one yet. + * note that we are unable to record it, if the address is not listed + * as our interface address (e.g. multicast addresses, addresses + * within FAITH prefixes and such). + */ + if (deliverifp && !ip6_getdstifaddr(m)) { + struct in6_ifaddr *ia6; + + ia6 = in6_ifawithifp(deliverifp, &ip6->ip6_dst); + if (ia6) { + if (!ip6_setdstifaddr(m, ia6)) { + /* + * XXX maybe we should drop the packet here, + * as we could not provide enough information + * to the upper layers. + */ + } + } + } + /* * Process Hop-by-Hop options header if it's contained. * m may be modified in ip6_hopopts_input(). @@ -651,8 +713,29 @@ ip6_input(m) #endif return; /* m have already been freed */ } + /* adjust pointer */ ip6 = mtod(m, struct ip6_hdr *); + + /* + * if the payload length field is 0 and the next header field + * indicates Hop-by-Hop Options header, then a Jumbo Payload + * option MUST be included. + */ + if (ip6->ip6_plen == 0 && plen == 0) { + /* + * Note that if a valid jumbo payload option is + * contained, ip6_hoptops_input() must set a valid + * (non-zero) payload length to the variable plen. + */ + ip6stat.ip6s_badoptions++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); + icmp6_error(m, ICMP6_PARAM_PROB, + ICMP6_PARAMPROB_HEADER, + (caddr_t)&ip6->ip6_plen - (caddr_t)ip6); + return; + } #ifndef PULLDOWN_TEST /* ip6_hopopts_input() ensures that mbuf is contiguous */ hbh = (struct ip6_hbh *)(ip6 + 1); @@ -741,30 +824,10 @@ ip6_input(m) /* * Tell launch routine the next header */ -#if defined(__NetBSD__) && defined(IFA_STATS) - if (IFA_STATS && deliverifp != NULL) { - struct in6_ifaddr *ia6; - ia6 = in6_ifawithifp(deliverifp, &ip6->ip6_dst); - if (ia6) - ia6->ia_ifa.ifa_data.ifad_inbytes += m->m_pkthdr.len; - } -#endif ip6stat.ip6s_delivered++; in6_ifstat_inc(deliverifp, ifs6_in_deliver); nest = 0; -#if MIP6 - /* - * Mobile IPv6 - * - * Assume that the received packet shall be processed by MIPv6 when - * the destination header has been taken care of. Because of this, - * some flags have to be reset for later evaluation. - */ - if (mip6_new_packet_hook) - (*mip6_new_packet_hook)(m); -#endif /* MIP6 */ - while (nxt != IPPROTO_DONE) { if (ip6_hdrnestlimit && (++nest > ip6_hdrnestlimit)) { ip6stat.ip6s_toomanyhdr++; @@ -775,27 +838,78 @@ ip6_input(m) * protection against faulty packet - there should be * more sanity checks in header chain processing. */ - if (m->m_pkthdr.len == 0 || m->m_pkthdr.len < off) { + if (m->m_pkthdr.len < off) { ip6stat.ip6s_tooshort++; in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); goto bad; } - -#if MIP6 - if ((nxt != IPPROTO_HOPOPTS) && (nxt != IPPROTO_DSTOPTS) && - (nxt != IPPROTO_ROUTING) && (nxt != IPPROTO_FRAGMENT) && - (nxt != IPPROTO_ESP) && (nxt != IPPROTO_AH)) { - if (mip6_route_optimize_hook) - (*mip6_route_optimize_hook)(m); + +#if 0 + /* + * do we need to do it for every header? yeah, other + * functions can play with it (like re-allocate and copy). + */ + mhist = ip6_addaux(m); + if (mhist && M_TRAILINGSPACE(mhist) >= sizeof(nxt)) { + hist = mtod(mhist, caddr_t) + mhist->m_len; + bcopy(&nxt, hist, sizeof(nxt)); + mhist->m_len += sizeof(nxt); + } else { + ip6stat.ip6s_toomanyhdr++; + goto bad; + } +#endif + +#if IPSEC + /* + * enforce IPsec policy checking if we are seeing last header. + * note that we do not visit this with protocols with pcb layer + * code - like udp/tcp/raw ip. + */ + if ((ipsec_bypass == 0) && (ip6_protox[nxt]->pr_flags & PR_LASTHDR) != 0 && + ipsec6_in_reject(m, NULL)) { + ipsec6stat.in_polvio++; + goto bad; } #endif - nxt = (*ip6_protox[nxt]->pr_input)(&m, &off, nxt); + + nxt = (*ip6_protox[nxt]->pr_input)(&m, &off); } return; bad: m_freem(m); } +/* + * set/grab in6_ifaddr correspond to IPv6 destination address. + * XXX backward compatibility wrapper + */ +static struct mbuf * +ip6_setdstifaddr(m, ia6) + struct mbuf *m; + struct in6_ifaddr *ia6; +{ + struct mbuf *n; + + n = ip6_addaux(m); + if (n) + mtod(n, struct ip6aux *)->ip6a_dstia6 = ia6; + return n; /* NULL if failed to set */ +} + +struct in6_ifaddr * +ip6_getdstifaddr(m) + struct mbuf *m; +{ + struct mbuf *n; + + n = ip6_findaux(m); + if (n) + return mtod(n, struct ip6aux *)->ip6a_dstia6; + else + return NULL; +} + /* * Hop-by-Hop options header processing. If a valid jumbo payload option is * included, the real payload length will be stored in plenp. @@ -807,7 +921,7 @@ ip6_hopopts_input(plenp, rtalertp, mp, offp) struct mbuf **mp; int *offp; { - register struct mbuf *m = *mp; + struct mbuf *m = *mp; int off = *offp, hbhlen; struct ip6_hbh *hbh; u_int8_t *opt; @@ -853,6 +967,10 @@ ip6_hopopts_input(plenp, rtalertp, mp, offp) * This function is separate from ip6_hopopts_input() in order to * handle a case where the sending node itself process its hop-by-hop * options header. In such a case, the function is called from ip6_output(). + * + * The function assumes that hbh header is located right after the IPv6 header + * (RFC2460 p7), opthead is pointer into data content in m, and opthead to + * opthead + hbhlen is located in continuous memory region. */ int ip6_process_hopopts(m, opthead, hbhlen, rtalertp, plenp) @@ -866,97 +984,115 @@ ip6_process_hopopts(m, opthead, hbhlen, rtalertp, plenp) int optlen = 0; u_int8_t *opt = opthead; u_int16_t rtalert_val; + u_int32_t jumboplen; + const int erroff = sizeof(struct ip6_hdr) + sizeof(struct ip6_hbh); for (; hbhlen > 0; hbhlen -= optlen, opt += optlen) { - switch(*opt) { - case IP6OPT_PAD1: - optlen = 1; - break; - case IP6OPT_PADN: - if (hbhlen < IP6OPT_MINLEN) { - ip6stat.ip6s_toosmall++; - goto bad; - } - optlen = *(opt + 1) + 2; - break; - case IP6OPT_RTALERT: - /* XXX may need check for alignment */ - if (hbhlen < IP6OPT_RTALERT_LEN) { - ip6stat.ip6s_toosmall++; - goto bad; - } - if (*(opt + 1) != IP6OPT_RTALERT_LEN - 2) - /* XXX: should we discard the packet? */ - log(LOG_ERR, "length of router alert opt is inconsitent(%d)", - *(opt + 1)); - optlen = IP6OPT_RTALERT_LEN; - bcopy((caddr_t)(opt + 2), (caddr_t)&rtalert_val, 2); - *rtalertp = ntohs(rtalert_val); - break; - case IP6OPT_JUMBO: - /* XXX may need check for alignment */ - if (hbhlen < IP6OPT_JUMBO_LEN) { - ip6stat.ip6s_toosmall++; - goto bad; - } - if (*(opt + 1) != IP6OPT_JUMBO_LEN - 2) - /* XXX: should we discard the packet? */ - log(LOG_ERR, "length of jumbopayload opt " - "is inconsistent(%d)", - *(opt + 1)); - optlen = IP6OPT_JUMBO_LEN; - - /* - * We can simply cast because of the alignment - * requirement of the jumbo payload option. - */ -#if 0 - *plenp = ntohl(*(u_int32_t *)(opt + 2)); -#else - bcopy(opt + 2, plenp, sizeof(*plenp)); - *plenp = htonl(*plenp); + switch (*opt) { + case IP6OPT_PAD1: + optlen = 1; + break; + case IP6OPT_PADN: + if (hbhlen < IP6OPT_MINLEN) { + ip6stat.ip6s_toosmall++; + goto bad; + } + optlen = *(opt + 1) + 2; + break; + case IP6OPT_RTALERT: + /* XXX may need check for alignment */ + if (hbhlen < IP6OPT_RTALERT_LEN) { + ip6stat.ip6s_toosmall++; + goto bad; + } + if (*(opt + 1) != IP6OPT_RTALERT_LEN - 2) { + /* XXX stat */ + icmp6_error(m, ICMP6_PARAM_PROB, + ICMP6_PARAMPROB_HEADER, + erroff + opt + 1 - opthead); + return(-1); + } + optlen = IP6OPT_RTALERT_LEN; + bcopy((caddr_t)(opt + 2), (caddr_t)&rtalert_val, 2); + *rtalertp = ntohs(rtalert_val); + break; + case IP6OPT_JUMBO: + /* XXX may need check for alignment */ + if (hbhlen < IP6OPT_JUMBO_LEN) { + ip6stat.ip6s_toosmall++; + goto bad; + } + if (*(opt + 1) != IP6OPT_JUMBO_LEN - 2) { + /* XXX stat */ + icmp6_error(m, ICMP6_PARAM_PROB, + ICMP6_PARAMPROB_HEADER, + erroff + opt + 1 - opthead); + return(-1); + } + optlen = IP6OPT_JUMBO_LEN; + + /* + * IPv6 packets that have non 0 payload length + * must not contain a jumbo payload option. + */ + ip6 = mtod(m, struct ip6_hdr *); + if (ip6->ip6_plen) { + ip6stat.ip6s_badoptions++; + icmp6_error(m, ICMP6_PARAM_PROB, + ICMP6_PARAMPROB_HEADER, + erroff + opt - opthead); + return(-1); + } + + /* + * We may see jumbolen in unaligned location, so + * we'd need to perform bcopy(). + */ + bcopy(opt + 2, &jumboplen, sizeof(jumboplen)); + jumboplen = (u_int32_t)htonl(jumboplen); + +#if 1 + /* + * if there are multiple jumbo payload options, + * *plenp will be non-zero and the packet will be + * rejected. + * the behavior may need some debate in ipngwg - + * multiple options does not make sense, however, + * there's no explicit mention in specification. + */ + if (*plenp != 0) { + ip6stat.ip6s_badoptions++; + icmp6_error(m, ICMP6_PARAM_PROB, + ICMP6_PARAMPROB_HEADER, + erroff + opt + 2 - opthead); + return(-1); + } #endif - if (*plenp <= IPV6_MAXPACKET) { - /* - * jumbo payload length must be larger - * than 65535 - */ - ip6stat.ip6s_badoptions++; - icmp6_error(m, ICMP6_PARAM_PROB, - ICMP6_PARAMPROB_HEADER, - sizeof(struct ip6_hdr) + - sizeof(struct ip6_hbh) + - opt + 2 - opthead); - return(-1); - } - - ip6 = mtod(m, struct ip6_hdr *); - if (ip6->ip6_plen) { - /* - * IPv6 packets that have non 0 payload length - * must not contain a jumbo paylod option. - */ - ip6stat.ip6s_badoptions++; - icmp6_error(m, ICMP6_PARAM_PROB, - ICMP6_PARAMPROB_HEADER, - sizeof(struct ip6_hdr) + - sizeof(struct ip6_hbh) + - opt - opthead); - return(-1); - } - break; - default: /* unknown option */ - if (hbhlen < IP6OPT_MINLEN) { - ip6stat.ip6s_toosmall++; - goto bad; - } - if ((optlen = ip6_unknown_opt(opt, m, - sizeof(struct ip6_hdr) + - sizeof(struct ip6_hbh) + - opt - opthead)) == -1) - return(-1); - optlen += 2; - break; + + /* + * jumbo payload length must be larger than 65535. + */ + if (jumboplen <= IPV6_MAXPACKET) { + ip6stat.ip6s_badoptions++; + icmp6_error(m, ICMP6_PARAM_PROB, + ICMP6_PARAMPROB_HEADER, + erroff + opt + 2 - opthead); + return(-1); + } + *plenp = jumboplen; + + break; + default: /* unknown option */ + if (hbhlen < IP6OPT_MINLEN) { + ip6stat.ip6s_toosmall++; + goto bad; + } + optlen = ip6_unknown_opt(opt, m, + erroff + opt - opthead); + if (optlen == -1) + return(-1); + optlen += 2; + break; } } @@ -981,26 +1117,26 @@ ip6_unknown_opt(optp, m, off) { struct ip6_hdr *ip6; - switch(IP6OPT_TYPE(*optp)) { - case IP6OPT_TYPE_SKIP: /* ignore the option */ - return((int)*(optp + 1)); - case IP6OPT_TYPE_DISCARD: /* silently discard */ - m_freem(m); - return(-1); - case IP6OPT_TYPE_FORCEICMP: /* send ICMP even if multicasted */ - ip6stat.ip6s_badoptions++; - icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_OPTION, off); - return(-1); - case IP6OPT_TYPE_ICMP: /* send ICMP if not multicasted */ - ip6stat.ip6s_badoptions++; - ip6 = mtod(m, struct ip6_hdr *); - if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || - (m->m_flags & (M_BCAST|M_MCAST))) - m_freem(m); - else - icmp6_error(m, ICMP6_PARAM_PROB, - ICMP6_PARAMPROB_OPTION, off); - return(-1); + switch (IP6OPT_TYPE(*optp)) { + case IP6OPT_TYPE_SKIP: /* ignore the option */ + return((int)*(optp + 1)); + case IP6OPT_TYPE_DISCARD: /* silently discard */ + m_freem(m); + return(-1); + case IP6OPT_TYPE_FORCEICMP: /* send ICMP even if multicasted */ + ip6stat.ip6s_badoptions++; + icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_OPTION, off); + return(-1); + case IP6OPT_TYPE_ICMP: /* send ICMP if not multicasted */ + ip6stat.ip6s_badoptions++; + ip6 = mtod(m, struct ip6_hdr *); + if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || + (m->m_flags & (M_BCAST|M_MCAST))) + m_freem(m); + else + icmp6_error(m, ICMP6_PARAM_PROB, + ICMP6_PARAMPROB_OPTION, off); + return(-1); } m_freem(m); /* XXX: NOTREACHED */ @@ -1018,134 +1154,58 @@ ip6_unknown_opt(optp, m, off) * very first mbuf on the mbuf chain. */ void -ip6_savecontrol(in6p, ip6, m, ctl, prevctlp) -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined(__APPLE__) - register struct inpcb *in6p; -#else - register struct in6pcb *in6p; -#endif - register struct ip6_hdr *ip6; - register struct mbuf *m; - struct ip6_recvpktopts *ctl, **prevctlp; +ip6_savecontrol(in6p, mp, ip6, m) + struct inpcb *in6p; + struct mbuf **mp; + struct ip6_hdr *ip6; + struct mbuf *m; { - register struct mbuf **mp; - struct cmsghdr *cm = NULL; - struct ip6_recvpktopts *prevctl = NULL; -#if HAVE_NRL_INPCB -# define in6p_flags inp_flags -#endif -#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__) struct proc *p = current_proc(); /* XXX */ -#endif -#ifdef __bsdi__ -# define sbcreatecontrol so_cmsg -#endif int privileged = 0; + int rthdr_exist = 0; - - if (ctl == NULL) /* validity check */ - return; - bzero(ctl, sizeof(*ctl)); /* XXX is it really OK? */ - mp = &ctl->head; - - /* - * If caller wanted to keep history, allocate space to store the - * history at the first time. - */ - if (prevctlp) { - if (*prevctlp == NULL) { - MALLOC(prevctl, struct ip6_recvpktopts *, - sizeof(*prevctl), M_IP6OPT, M_NOWAIT); - if (prevctl == NULL) { - printf("ip6_savecontrol: can't allocate " - " enough space for history\n"); - return; - } - bzero(prevctl, sizeof(*prevctl)); - *prevctlp = prevctl; - } - else - prevctl = *prevctlp; - } - -#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ == 3) - if (p && !suser(p->p_ucred, &p->p_acflag)) - privileged++; -#elif defined(__FreeBSD__) && __FreeBSD__ >= 4 - if (p && !suser(p)) - privileged++; -#else -#if HAVE_NRL_INPCB - if ((in6p->inp_socket->so_state & SS_PRIV) != 0) - privileged++; +#ifdef __APPLE__ + if (p && !suser(p->p_ucred, &p->p_acflag)) #else - if ((in6p->in6p_socket->so_state & SS_PRIV) != 0) - privileged++; -#endif + if (p && !suser(p)) #endif + privileged++; #if SO_TIMESTAMP - if (in6p->in6p_socket->so_options & SO_TIMESTAMP) { + if ((in6p->in6p_socket->so_options & SO_TIMESTAMP) != 0) { struct timeval tv; microtime(&tv); *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv), SCM_TIMESTAMP, SOL_SOCKET); if (*mp) { - /* always set regradless of the previous value */ - ctl->timestamp = *mp; mp = &(*mp)->m_next; } } #endif /* RFC 2292 sec. 5 */ - if (in6p->in6p_flags & IN6P_PKTINFO) { - struct in6_pktinfo pi6, *prevpi = NULL; + if ((in6p->in6p_flags & IN6P_PKTINFO) != 0) { + struct in6_pktinfo pi6; bcopy(&ip6->ip6_dst, &pi6.ipi6_addr, sizeof(struct in6_addr)); if (IN6_IS_SCOPE_LINKLOCAL(&pi6.ipi6_addr)) pi6.ipi6_addr.s6_addr16[1] = 0; pi6.ipi6_ifindex = (m && m->m_pkthdr.rcvif) ? m->m_pkthdr.rcvif->if_index : 0; - if (prevctl && prevctl->pktinfo) { - cm = mtod(prevctl->pktinfo, struct cmsghdr *); - prevpi = (struct in6_pktinfo *)CMSG_DATA(cm); - } - - /* - * Make a new option only if this is the first time or if the - * option value is chaned from last time. - */ - if (prevpi == NULL || bcmp(prevpi, &pi6, sizeof(pi6))) { - *mp = sbcreatecontrol((caddr_t) &pi6, - sizeof(struct in6_pktinfo), - IPV6_PKTINFO, - IPPROTO_IPV6); - if (*mp) { - ctl->pktinfo = *mp; - mp = &(*mp)->m_next; - } - } + *mp = sbcreatecontrol((caddr_t) &pi6, + sizeof(struct in6_pktinfo), IPV6_PKTINFO, + IPPROTO_IPV6); + if (*mp) + mp = &(*mp)->m_next; } - if (in6p->in6p_flags & IN6P_HOPLIMIT) { - int hlim = ip6->ip6_hlim & 0xff, oldhlim = -1; - - if (prevctl && prevctl->hlim) { - cm = mtod(prevctl->hlim, struct cmsghdr *); - oldhlim = (*(int *)CMSG_DATA(cm)) & 0xff; - } - - if (oldhlim < 0 || hlim != oldhlim) { - *mp = sbcreatecontrol((caddr_t) &hlim, - sizeof(int), IPV6_HOPLIMIT, - IPPROTO_IPV6); - if (*mp) { - ctl->hlim = *mp; - mp = &(*mp)->m_next; - } - } + if ((in6p->in6p_flags & IN6P_HOPLIMIT) != 0) { + int hlim = ip6->ip6_hlim & 0xff; + *mp = sbcreatecontrol((caddr_t) &hlim, + sizeof(int), IPV6_HOPLIMIT, IPPROTO_IPV6); + if (*mp) + mp = &(*mp)->m_next; } /* @@ -1154,7 +1214,7 @@ ip6_savecontrol(in6p, ip6, m, ctl, prevctlp) * be some hop-by-hop options which can be returned to normal user. * See RFC 2292 section 6. */ - if ((in6p->in6p_flags & IN6P_HOPOPTS) && privileged) { + if ((in6p->in6p_flags & IN6P_HOPOPTS) != 0 && privileged) { /* * Check if a hop-by-hop options header is contatined in the * received packet, and if so, store the options as ancillary @@ -1164,9 +1224,9 @@ ip6_savecontrol(in6p, ip6, m, ctl, prevctlp) */ struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); if (ip6->ip6_nxt == IPPROTO_HOPOPTS) { - struct ip6_hbh *hbh, *prevhbh = NULL; - int hbhlen = 0, prevhbhlen = 0; -#ifdef PULLDOWN_TEST + struct ip6_hbh *hbh; + int hbhlen = 0; +#if PULLDOWN_TEST struct mbuf *ext; #endif @@ -1189,45 +1249,57 @@ ip6_savecontrol(in6p, ip6, m, ctl, prevctlp) } #endif - if (prevctl && prevctl->hbh) { - cm = mtod(prevctl->hbh, struct cmsghdr *); - prevhbh = (struct ip6_hbh *)CMSG_DATA(cm); - prevhbhlen = (prevhbh->ip6h_len + 1) << 3; - } /* - * Check if there's difference between the current - * and previous HbH headers. - * XXX: should the next header field be ignored? + * XXX: We copy whole the header even if a jumbo + * payload option is included, which option is to + * be removed before returning in the RFC 2292. + * Note: this constraint is removed in 2292bis. */ - if (prevhbh == NULL || hbhlen != prevhbhlen || - bcmp(prevhbh, hbh, hbhlen)) { - /* - * XXX: We copy whole the header even if a - * jumbo payload option is included, which - * option is to be removed before returning - * in the RFC 2292. - * Note: this constraint is removed in - * 2292bis. - */ - *mp = sbcreatecontrol((caddr_t)hbh, hbhlen, - IPV6_HOPOPTS, - IPPROTO_IPV6); - if (*mp) { - ctl->hbh = *mp; - mp = &(*mp)->m_next; - } - } -#ifdef PULLDOWN_TEST + *mp = sbcreatecontrol((caddr_t)hbh, hbhlen, + IPV6_HOPOPTS, IPPROTO_IPV6); + if (*mp) + mp = &(*mp)->m_next; +#if PULLDOWN_TEST m_freem(ext); #endif } } /* IPV6_DSTOPTS and IPV6_RTHDR socket options */ - if (in6p->in6p_flags & (IN6P_DSTOPTS | IN6P_RTHDR)) { + if ((in6p->in6p_flags & (IN6P_DSTOPTS | IN6P_RTHDRDSTOPTS)) != 0) { + int proto, off, nxt; + + /* + * go through the header chain to see if a routing header is + * contained in the packet. We need this information to store + * destination options headers (if any) properly. + * XXX: performance issue. We should record this info when + * processing extension headers in incoming routine. + * (todo) use m_aux? + */ + proto = IPPROTO_IPV6; + off = 0; + nxt = -1; + while (1) { + int newoff; + + newoff = ip6_nexthdr(m, off, proto, &nxt); + if (newoff < 0) + break; + if (newoff < off) /* invalid, check for safety */ + break; + if ((proto = nxt) == IPPROTO_ROUTING) { + rthdr_exist = 1; + break; + } + off = newoff; + } + } + + if ((in6p->in6p_flags & + (IN6P_RTHDR | IN6P_DSTOPTS | IN6P_RTHDRDSTOPTS)) != 0) { struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); int nxt = ip6->ip6_nxt, off = sizeof(struct ip6_hdr); - int rthdr = 0; /* flag if we've passed a routing header */ /* * Search for destination options headers or routing @@ -1239,7 +1311,7 @@ ip6_savecontrol(in6p, ip6, m, ctl, prevctlp) while (1) { /* is explicit loop prevention necessary? */ struct ip6_ext *ip6e = NULL; int elen; -#ifdef PULLDOWN_TEST +#if PULLDOWN_TEST struct mbuf *ext = NULL; #endif @@ -1287,124 +1359,33 @@ ip6_savecontrol(in6p, ip6, m, ctl, prevctlp) switch (nxt) { case IPPROTO_DSTOPTS: - { - struct ip6_dest *prevdest1 = NULL, - *prevdest2 = NULL; - int prevdestlen; - - if ((in6p->in6p_flags & - (IN6P_DSTOPTS | IN6P_RTHDRDSTOPTS)) == 0) + if ((in6p->in6p_flags & IN6P_DSTOPTS) == 0) break; - /* - * We also require super-user privilege for - * the option. - * See the comments on IN6_HOPOPTS. - */ + /* + * We also require super-user privilege for + * the option. + * See the comments on IN6_HOPOPTS. + */ if (!privileged) break; - /* - * Save a dst opt header before a routing - * header if the user wanted. - */ - if (rthdr == 0 && - (in6p->in6p_flags & IN6P_RTHDRDSTOPTS)) { - if (prevctl && prevctl->dest1) { - cm = mtod(prevctl->dest1, - struct cmsghdr *); - prevdest1 = (struct ip6_dest *)CMSG_DATA(cm); - prevdestlen = (prevdest1->ip6d_len + 1) << 3; - } - - /* - * If this is the 1st dst opt header - * (that is placed before rthdr) - * we enconter and this header is - * not different from the previous one, - * simply ignore the header. - */ - if (ctl->dest1 == NULL && - (prevdest1 && - prevdestlen == elen && - bcmp(ip6e, prevdest1, elen) == 0)) - break; - - *mp = sbcreatecontrol((caddr_t)ip6e, - elen, - IPV6_RTHDRDSTOPTS, - IPPROTO_IPV6); - if (ctl->dest1 == NULL) - ctl->dest1 = *mp; - if (*mp) - mp = &(*mp)->m_next; - } - /* - * Save a dst opt header after a routing - * header if the user wanted. - */ - if (rthdr && - (in6p->in6p_flags & IN6P_DSTOPTS)) { - if (prevctl && prevctl->dest2) { - cm = mtod(prevctl->dest2, - struct cmsghdr *); - prevdest2 = (struct ip6_dest *)CMSG_DATA(cm); - prevdestlen = (prevdest2->ip6d_len + 1) << 3; - } - /* see the above comment */ - if (ctl->dest2 == NULL && - (prevdest2 && - prevdestlen == elen && - bcmp(ip6e, prevdest2, elen) == 0)) - break; - - *mp = sbcreatecontrol((caddr_t)ip6e, - elen, - IPV6_DSTOPTS, - IPPROTO_IPV6); - if (ctl->dest2 == NULL) - ctl->dest2 = *mp; - - if (*mp) - mp = &(*mp)->m_next; - } + *mp = sbcreatecontrol((caddr_t)ip6e, elen, + IPV6_DSTOPTS, + IPPROTO_IPV6); + if (*mp) + mp = &(*mp)->m_next; break; - } case IPPROTO_ROUTING: - { - struct ip6_rthdr *prevrth = NULL; - int prevrhlen = 0; - - rthdr++; if (!in6p->in6p_flags & IN6P_RTHDR) break; - if (prevctl && prevctl->rthdr) { - cm = mtod(prevctl->rthdr, - struct cmsghdr *); - prevrth = (struct ip6_rthdr *)CMSG_DATA(cm); - prevrhlen = - (prevrth->ip6r_len + 1) << 3; - } - - /* - * Check if the rthdr should be passed to - * a user. See the comments for dstopt hdr. - */ - if (ctl->rthdr == NULL && prevrth && - prevrhlen == elen && - bcmp(ip6e, prevrth, elen) == 0) - break; - *mp = sbcreatecontrol((caddr_t)ip6e, elen, IPV6_RTHDR, IPPROTO_IPV6); - if (ctl->rthdr == NULL) - ctl->rthdr = *mp; if (*mp) mp = &(*mp)->m_next; break; - } case IPPROTO_HOPOPTS: case IPPROTO_AH: /* is it possible? */ break; @@ -1416,7 +1397,7 @@ ip6_savecontrol(in6p, ip6, m, ctl, prevctlp) * the code just in case (nxt overwritten or * other cases). */ -#ifdef PULLDOWN_TEST +#if PULLDOWN_TEST m_freem(ext); #endif goto loopend; @@ -1427,23 +1408,18 @@ ip6_savecontrol(in6p, ip6, m, ctl, prevctlp) off += elen; nxt = ip6e->ip6e_nxt; ip6e = NULL; -#ifdef PULLDOWN_TEST +#if PULLDOWN_TEST m_freem(ext); ext = NULL; #endif } loopend: + ; } -#ifdef __bsdi__ -# undef sbcreatecontrol -#endif -#ifdef __OpenBSD__ -# undef in6p_flags -#endif } -#ifdef PULLDOWN_TEST +#if PULLDOWN_TEST /* * pull single extension header from mbuf chain. returns single mbuf that * contains the result, or NULL on error. @@ -1458,7 +1434,7 @@ ip6_pullexthdr(m, off, nxt) size_t elen; struct mbuf *n; -#ifdef DIAGNOSTIC +#if DIAGNOSTIC switch (nxt) { case IPPROTO_DSTOPTS: case IPPROTO_ROUTING: @@ -1499,172 +1475,6 @@ ip6_pullexthdr(m, off, nxt) } #endif -/* - * Merge new IPv6 received options to previous ones. - * If a new option is not given, just re-link the option chain. - * If an old option exists but a corresponding new one doesn't, just - * keep the ole option. - * If a new option exists but a corresponding old one doesn't, just - * copy the new option. - * If both new and old options exist, free old one and overwrite the option - * with the new option. - * Otherwise, do nothing for the option. - * XXX: in any case, options that don't follow the recommend order and - * number of extension headers (RFC 2460 Section 4.1) are simply ignored. - * XXX: We assume that each option is stored in a single mbuf. - */ -#define CLEAN_RECVOPT(old, type) \ -do { \ - if ((old)->type && (old)->type->m_next) { \ - (old)->type->m_next = NULL; \ - } \ -} while (0) -#define MERGE_RECVOPT(new, old, type) if ((new)->type) {\ - if ((old)->type)\ - m_free((old)->type);\ - (old)->type = m_copy((new)->type, 0, (new)->type->m_len);\ - if (((old)->type) && ((old)->type->m_next)) {\ - m_freem((old)->type);\ - old->type = NULL;\ - }\ - } -#define LINK_RECVOPTS(opt, type, p) if ((opt)->type) {\ - *(p) = (opt)->type;\ - (p) = &(opt)->type->m_next;\ - } - -static void dump_inputopts __P((char *, struct ip6_recvpktopts *)); -static void -dump_inputopts(str, p) - char *str; - struct ip6_recvpktopts *p; -{ -#if 1 - return; -#else -#define PRINT1(p, name) \ -do { \ - if (p->name) { \ - printf(" %s: %p", #name, (p)->name); \ - if (p->name->m_next) \ - printf("[%p]", (p)->name->m_next); \ - } \ -} while (0) - - printf("%s p=%p head=%p", str, p, p->head); - PRINT1(p, hlim); - PRINT1(p, pktinfo); - PRINT1(p, hbh); - PRINT1(p, dest1); - PRINT1(p, dest2); - PRINT1(p, rthdr); - printf("\n"); -#undef PRINT1 -#endif -} - -void -ip6_update_recvpcbopt(old, new) - struct ip6_recvpktopts *new, *old; -{ - struct mbuf **mp; - - if (old == NULL) { - printf("ip6_update_recvpcbopt: invalid arguments\n"); - return; - } - - dump_inputopts("old before", old); - if (new) - dump_inputopts("new before", new); - -#if 0 - /* - * cleanup m->m_next linkage. note that we do it in reverse order - * to prevent possible memory leakage. - */ - old->head = NULL; - CLEAN_RECVOPT(old, rthdr); - CLEAN_RECVOPT(old, dest2); - CLEAN_RECVOPT(old, dest1); - CLEAN_RECVOPT(old, hbh); - CLEAN_RECVOPT(old, pktinfo); - CLEAN_RECVOPT(old, hlim); -#endif - - if (new) { - MERGE_RECVOPT(new, old, hlim); - MERGE_RECVOPT(new, old, pktinfo); - MERGE_RECVOPT(new, old, hbh); - MERGE_RECVOPT(new, old, dest1); - MERGE_RECVOPT(new, old, dest2); - MERGE_RECVOPT(new, old, rthdr); - } - - dump_inputopts("old middle", old); - if (new) - dump_inputopts("new middle", new); - - /* link options */ - mp = &old->head; - LINK_RECVOPTS(old, hlim, mp); - LINK_RECVOPTS(old, pktinfo, mp); - LINK_RECVOPTS(old, hbh, mp); - LINK_RECVOPTS(old, dest1, mp); - LINK_RECVOPTS(old, dest2, mp); - LINK_RECVOPTS(old, rthdr, mp); - *mp = NULL; - - dump_inputopts("old after", old); - if (new) - dump_inputopts("new after", new); -} - -#undef MERGE_RECVOPT -#undef LINK_RECVOPTS - -void -ip6_reset_rcvopt(opts, optname) - struct ip6_recvpktopts *opts; - int optname; -{ - if (opts == NULL) - return; - - switch(optname) { - case IPV6_RECVPKTINFO: - if (opts->pktinfo) m_free(opts->pktinfo); - opts->pktinfo = NULL; - break; - case IPV6_RECVHOPLIMIT: - if (opts->hlim) m_free(opts->hlim); - opts->hlim = NULL; - break; - case IPV6_RECVHOPOPTS: - if (opts->hbh) m_free(opts->hbh); - opts->hbh = NULL; - break; - case IPV6_RECVRTHDRDSTOPTS: - if (opts->dest1) m_free(opts->dest1); - opts->dest1 = NULL; - break; - case IPV6_RECVDSTOPTS: - if (opts->dest2) m_free(opts->dest2); - opts->dest2 = NULL; - break; - case IPV6_RECVRTHDR: - if (opts->rthdr) m_free(opts->rthdr); - opts->rthdr = NULL; - break; - default: - printf("ip6_reset_rcvopt: invalid option name (%d)\n", - optname); - return; - } - - ip6_update_recvpcbopt(opts, NULL); /* re-link the option chain */ -} - /* * Get pointer to the previous header followed by the header * currently processed. @@ -1695,7 +1505,7 @@ ip6_get_prevhdr(m, off) while (len < off) { ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + len); - switch(nxt) { + switch (nxt) { case IPPROTO_FRAGMENT: len += sizeof(struct ip6_frag); break; @@ -1824,6 +1634,55 @@ ip6_lasthdr(m, off, proto, nxtp) } } +struct mbuf * +ip6_addaux(m) + struct mbuf *m; +{ + struct mbuf *n; + +#if DIAGNOSTIC + if (sizeof(struct ip6aux) > MHLEN) + panic("assumption failed on sizeof(ip6aux)"); +#endif + n = m_aux_find(m, AF_INET6, -1); + if (n) { + if (n->m_len < sizeof(struct ip6aux)) { + printf("conflicting use of ip6aux"); + return NULL; + } + } else { + n = m_aux_add(m, AF_INET6, -1); + n->m_len = sizeof(struct ip6aux); + bzero(mtod(n, caddr_t), n->m_len); + } + return n; +} + +struct mbuf * +ip6_findaux(m) + struct mbuf *m; +{ + struct mbuf *n; + + n = m_aux_find(m, AF_INET6, -1); + if (n && n->m_len < sizeof(struct ip6aux)) { + printf("conflicting use of ip6aux"); + n = NULL; + } + return n; +} + +void +ip6_delaux(m) + struct mbuf *m; +{ + struct mbuf *n; + + n = m_aux_find(m, AF_INET6, -1); + if (n) + m_aux_delete(m, n); +} + /* * System control for IP6 */ @@ -1836,102 +1695,3 @@ u_char inet6ctlerrmap[PRC_NCMDS] = { 0, 0, 0, 0, ENOPROTOOPT }; - -#if defined(__NetBSD__) || defined(__OpenBSD__) -#include -#include - -int -ip6_sysctl(name, namelen, oldp, oldlenp, newp, newlen) - int *name; - u_int namelen; - void *oldp; - size_t *oldlenp; - void *newp; - size_t newlen; -{ - /* All sysctl names at this level are terminal. */ - if (namelen != 1) - return ENOTDIR; - - switch (name[0]) { - - case IPV6CTL_FORWARDING: - return sysctl_int(oldp, oldlenp, newp, newlen, - &ip6_forwarding); - case IPV6CTL_SENDREDIRECTS: - return sysctl_int(oldp, oldlenp, newp, newlen, - &ip6_sendredirects); - case IPV6CTL_DEFHLIM: - return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_defhlim); - case IPV6CTL_MAXFRAGPACKETS: - return sysctl_int(oldp, oldlenp, newp, newlen, - &ip6_maxfragpackets); - case IPV6CTL_ACCEPT_RTADV: - return sysctl_int(oldp, oldlenp, newp, newlen, - &ip6_accept_rtadv); - case IPV6CTL_KEEPFAITH: - return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_keepfaith); - case IPV6CTL_LOG_INTERVAL: - return sysctl_int(oldp, oldlenp, newp, newlen, - &ip6_log_interval); - case IPV6CTL_HDRNESTLIMIT: - return sysctl_int(oldp, oldlenp, newp, newlen, - &ip6_hdrnestlimit); - case IPV6CTL_DAD_COUNT: - return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_dad_count); - case IPV6CTL_AUTO_FLOWLABEL: - return sysctl_int(oldp, oldlenp, newp, newlen, - &ip6_auto_flowlabel); - case IPV6CTL_DEFMCASTHLIM: - return sysctl_int(oldp, oldlenp, newp, newlen, - &ip6_defmcasthlim); - case IPV6CTL_GIF_HLIM: - return sysctl_int(oldp, oldlenp, newp, newlen, - &ip6_gif_hlim); - case IPV6CTL_KAME_VERSION: - return sysctl_rdstring(oldp, oldlenp, newp, __KAME_VERSION); - case IPV6CTL_USE_DEPRECATED: - return sysctl_int(oldp, oldlenp, newp, newlen, - &ip6_use_deprecated); - case IPV6CTL_RR_PRUNE: - return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_rr_prune); -#if defined(__NetBSD__) && !defined(INET6_BINDV6ONLY) - case IPV6CTL_BINDV6ONLY: - return sysctl_int(oldp, oldlenp, newp, newlen, - &ip6_bindv6only); -#endif - default: - return EOPNOTSUPP; - } - /* NOTREACHED */ -} -#endif /* __NetBSD__ || __OpenBSD__ */ - -#ifdef __bsdi__ -int *ip6_sysvars[] = IPV6CTL_VARS; - -int -ip6_sysctl(name, namelen, oldp, oldlenp, newp, newlen) - int *name; - u_int namelen; - void *oldp; - size_t *oldlenp; - void *newp; - size_t newlen; -{ - if (name[0] >= IPV6CTL_MAXID) - return (EOPNOTSUPP); - - switch (name[0]) { - case IPV6CTL_STATS: - return sysctl_rdtrunc(oldp, oldlenp, newp, &ip6stat, - sizeof(ip6stat)); - case IPV6CTL_KAME_VERSION: - return sysctl_rdstring(oldp, oldlenp, newp, __KAME_VERSION); - default: - return (sysctl_int_arr(ip6_sysvars, name, namelen, - oldp, oldlenp, newp, newlen)); - } -} -#endif /* __bsdi__ */ diff --git a/bsd/netinet6/ip6_mroute.c b/bsd/netinet6/ip6_mroute.c index 6140af6fe..e4b060f9e 100644 --- a/bsd/netinet6/ip6_mroute.c +++ b/bsd/netinet6/ip6_mroute.c @@ -1,4 +1,5 @@ -/* $KAME: ip6_mroute.c,v 1.15 2000/02/22 14:04:21 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/ip6_mroute.c,v 1.2.2.4 2001/07/03 11:01:53 ume Exp $ */ +/* $KAME: ip6_mroute.c,v 1.46 2001/04/04 05:17:30 itojun Exp $ */ /* * Copyright (C) 1998 WIDE Project. @@ -44,21 +45,10 @@ * MROUTING Revision: 3.5.1.2 + PIM-SMv2 (pimd) Support */ -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#endif - -#ifndef _KERNEL -# ifdef KERNEL -# define _KERNEL -# endif -#endif #include #include -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) #include -#endif #include #include #include @@ -67,9 +57,6 @@ #include #include #include -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) -#include -#endif #include #include @@ -85,7 +72,7 @@ #include #include -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#ifndef __APPLE__ static MALLOC_DEFINE(M_MRTABLE, "mf6c", "multicast forwarding cache entry"); #endif @@ -95,9 +82,6 @@ static int ip6_mdq __P((struct mbuf *, struct ifnet *, struct mf6c *)); static void phyint_send __P((struct ip6_hdr *, struct mif6 *, struct mbuf *)); static int set_pim6 __P((int *)); -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__APPLE__) -static int get_pim6 __P((struct mbuf *)); -#endif static int socket_send __P((struct socket *, struct mbuf *, struct sockaddr_in6 *)); static int register_send __P((struct ip6_hdr *, struct mif6 *, @@ -108,6 +92,7 @@ static int register_send __P((struct ip6_hdr *, struct mif6 *, * except for netstat or debugging purposes. */ struct socket *ip6_mrouter = NULL; +int ip6_mrouter_ver = 0; int ip6_mrtproto = IPPROTO_PIM; /* for netstat only */ struct mrt6stat mrt6stat; @@ -128,6 +113,8 @@ u_int mrt6debug = 0; /* debug level */ #endif static void expire_upcalls __P((void *)); +static void expire_upcalls_funneled __P((void *)); + #define EXPIRE_TIMEOUT (hz / 4) /* 4x / second */ #define UPCALL_EXPIRE 6 /* number of timeouts */ @@ -158,10 +145,6 @@ static mifi_t reg_mif_num = (mifi_t)-1; static struct pim6stat pim6stat; -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -static struct callout_handle expire_upcalls_ch; -#endif - /* * one-back cache used by ipip_input to locate a tunnel's mif * given a datagram's src ip address. @@ -181,8 +164,8 @@ static int pim6; * Quality of service parameter to be added in the future!!! */ -#define MF6CFIND(o, g, rt) { \ - register struct mf6c *_rt = mf6ctable[MF6CHASH(o,g)]; \ +#define MF6CFIND(o, g, rt) do { \ + struct mf6c *_rt = mf6ctable[MF6CHASH(o,g)]; \ rt = NULL; \ mrt6stat.mrt6s_mfc_lookups++; \ while (_rt) { \ @@ -197,14 +180,14 @@ static int pim6; if (rt == NULL) { \ mrt6stat.mrt6s_mfc_misses++; \ } \ -} +} while (0) /* * Macros to compute elapsed time efficiently * Borrowed from Van Jacobson's scheduling code */ -#define TV_DELTA(a, b, delta) { \ - register int xxs; \ +#define TV_DELTA(a, b, delta) do { \ + int xxs; \ \ delta = (a).tv_usec - (b).tv_usec; \ if ((xxs = (a).tv_sec - (b).tv_sec)) { \ @@ -219,7 +202,7 @@ static int pim6; delta += (1000000 * xxs); \ } \ } \ -} +} while (0) #define TV_LT(a, b) (((a).tv_usec < (b).tv_usec && \ (a).tv_sec <= (b).tv_sec) || (a).tv_sec < (b).tv_sec) @@ -232,16 +215,18 @@ static void collate(); static int get_sg_cnt __P((struct sioc_sg_req6 *)); static int get_mif6_cnt __P((struct sioc_mif_req6 *)); -static int ip6_mrouter_init __P((struct socket *, struct mbuf *)); +static int ip6_mrouter_init __P((struct socket *, struct mbuf *, int)); static int add_m6if __P((struct mif6ctl *)); static int del_m6if __P((mifi_t *)); static int add_m6fc __P((struct mf6cctl *)); static int del_m6fc __P((struct mf6cctl *)); +#ifndef __APPLE__ +static struct callout expire_upcalls_ch; +#endif /* * Handle MRT setsockopt commands to modify the multicast routing tables. */ -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) int ip6_mrouter_set(so, sopt) struct socket *so; @@ -253,68 +238,48 @@ ip6_mrouter_set(so, sopt) if (so != ip6_mrouter && sopt->sopt_name != MRT6_INIT) return (EACCES); - if (error = sooptgetm(sopt, &m)) /* XXX */ + if ((error = soopt_getm(sopt, &m)) != 0) /* XXX */ return (error); - if (error = sooptmcopyin(sopt, m)) /* XXX */ + if ((error = soopt_mcopyin(sopt, m)) != 0) /* XXX */ return (error); switch (sopt->sopt_name) { - case MRT6_INIT: - error = ip6_mrouter_init(so, m); - break; - case MRT6_DONE: - error = ip6_mrouter_done(); - break; - case MRT6_ADD_MIF: - error = add_m6if(mtod(m, struct mif6ctl *)); - break; - case MRT6_DEL_MIF: - error = del_m6if(mtod(m, mifi_t *)); - break; - case MRT6_ADD_MFC: - error = add_m6fc(mtod(m, struct mf6cctl *)); - break; - case MRT6_DEL_MFC: - error = del_m6fc(mtod(m, struct mf6cctl *)); - break; - case MRT6_PIM: - error = set_pim6(mtod(m, int *)); - break; - default: - error = EOPNOTSUPP; - break; + case MRT6_INIT: +#if MRT6_OINIT + case MRT6_OINIT: +#endif + error = ip6_mrouter_init(so, m, sopt->sopt_name); + break; + case MRT6_DONE: + error = ip6_mrouter_done(); + break; + case MRT6_ADD_MIF: + error = add_m6if(mtod(m, struct mif6ctl *)); + break; + case MRT6_DEL_MIF: + error = del_m6if(mtod(m, mifi_t *)); + break; + case MRT6_ADD_MFC: + error = add_m6fc(mtod(m, struct mf6cctl *)); + break; + case MRT6_DEL_MFC: + error = del_m6fc(mtod(m, struct mf6cctl *)); + break; + case MRT6_PIM: + error = set_pim6(mtod(m, int *)); + break; + default: + error = EOPNOTSUPP; + break; } (void)m_freem(m); return(error); } -#else -int -ip6_mrouter_set(cmd, so, m) - int cmd; - struct socket *so; - struct mbuf *m; -{ - if (cmd != MRT6_INIT && so != ip6_mrouter) - return EACCES; - - switch (cmd) { - case MRT6_INIT: return ip6_mrouter_init(so, m); - case MRT6_DONE: return ip6_mrouter_done(); - case MRT6_ADD_MIF: return add_m6if(mtod(m, struct mif6ctl *)); - case MRT6_DEL_MIF: return del_m6if(mtod(m, mifi_t *)); - case MRT6_ADD_MFC: return add_m6fc(mtod(m, struct mf6cctl *)); - case MRT6_DEL_MFC: return del_m6fc(mtod(m, struct mf6cctl *)); - case MRT6_PIM: return set_pim6(mtod(m, int *)); - default: return EOPNOTSUPP; - } -} -#endif /* * Handle MRT getsockopt commands */ -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) int ip6_mrouter_get(so, sopt) struct socket *so; @@ -331,27 +296,6 @@ ip6_mrouter_get(so, sopt) } return (error); } -#else -int -ip6_mrouter_get(cmd, so, m) - int cmd; - struct socket *so; - struct mbuf **m; -{ - struct mbuf *mb; - - if (so != ip6_mrouter) return EACCES; - - *m = mb = m_get(M_WAIT, MT_SOOPTS); - - switch (cmd) { - case MRT6_PIM: return get_pim6(mb); - default: - m_free(mb); - return EOPNOTSUPP; - } -} -#endif /* * Handle ioctl commands to obtain information from the cache @@ -361,20 +305,20 @@ mrt6_ioctl(cmd, data) int cmd; caddr_t data; { - int error = 0; - - switch (cmd) { - case SIOCGETSGCNT_IN6: - return(get_sg_cnt((struct sioc_sg_req6 *)data)); - break; /* for safety */ - case SIOCGETMIFCNT_IN6: - return(get_mif6_cnt((struct sioc_mif_req6 *)data)); - break; /* for safety */ - default: - return (EINVAL); - break; - } - return error; + int error = 0; + + switch (cmd) { + case SIOCGETSGCNT_IN6: + return(get_sg_cnt((struct sioc_sg_req6 *)data)); + break; /* for safety */ + case SIOCGETMIFCNT_IN6: + return(get_mif6_cnt((struct sioc_mif_req6 *)data)); + break; /* for safety */ + default: + return (EINVAL); + break; + } + return error; } /* @@ -382,16 +326,12 @@ mrt6_ioctl(cmd, data) */ static int get_sg_cnt(req) - register struct sioc_sg_req6 *req; + struct sioc_sg_req6 *req; { - register struct mf6c *rt; + struct mf6c *rt; int s; -#if __NetBSD__ - s = splsoftnet(); -#else s = splnet(); -#endif MF6CFIND(req->src.sin6_addr, req->grp.sin6_addr, rt); splx(s); if (rt != NULL) { @@ -412,9 +352,9 @@ get_sg_cnt(req) */ static int get_mif6_cnt(req) - register struct sioc_mif_req6 *req; + struct sioc_mif_req6 *req; { - register mifi_t mifi = req->mifi; + mifi_t mifi = req->mifi; if (mifi >= nummifs) return EINVAL; @@ -427,24 +367,6 @@ get_mif6_cnt(req) return 0; } -#if !(defined(__FreeBSD__) && __FreeBSD__ >=3) || !defined(__APPLE__) -/* - * Get PIM processiong global - */ -static int -get_pim6(m) - struct mbuf *m; -{ - int *i; - - i = mtod(m, int *); - - *i = pim6; - - return 0; -} -#endif - static int set_pim6(i) int *i; @@ -461,9 +383,10 @@ set_pim6(i) * Enable multicast routing */ static int -ip6_mrouter_init(so, m) +ip6_mrouter_init(so, m, cmd) struct socket *so; struct mbuf *m; + int cmd; { int *v; @@ -488,16 +411,19 @@ ip6_mrouter_init(so, m) if (ip6_mrouter != NULL) return EADDRINUSE; ip6_mrouter = so; + ip6_mrouter_ver = cmd; bzero((caddr_t)mf6ctable, sizeof(mf6ctable)); bzero((caddr_t)nexpire, sizeof(nexpire)); pim6 = 0;/* used for stubbing out/in pim stuff */ -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - expire_upcalls_ch = +#ifndef __APPLE__ + callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT, + expire_upcalls, NULL); +#else + timeout(expire_upcalls_funneled, (caddr_t)NULL, EXPIRE_TIMEOUT); #endif - timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT); #if MRT6DEBUG if (mrt6debug) @@ -521,11 +447,7 @@ ip6_mrouter_done() struct rtdetq *rte; int s; -#if __NetBSD__ - s = splsoftnet(); -#else s = splnet(); -#endif /* * For each phyint in use, disable promiscuous reception of all IPv6 @@ -568,11 +490,11 @@ ip6_mrouter_done() pim6 = 0; /* used to stub out/in pim specific code */ - untimeout(expire_upcalls, (caddr_t)NULL -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - , expire_upcalls_ch +#ifndef __APPLE__ + callout_stop(&expire_upcalls_ch); +#else + untimeout(expire_upcalls_funneled, (caddr_t)NULL); #endif - ); /* * Free all multicast forwarding cache entries. @@ -586,12 +508,12 @@ ip6_mrouter_done() struct rtdetq *n = rte->next; m_free(rte->m); - _FREE(rte, M_MRTABLE); + FREE(rte, M_MRTABLE); rte = n; } frt = rt; rt = rt->mf6c_next; - _FREE(frt, M_MRTABLE); + FREE(frt, M_MRTABLE); } } @@ -603,6 +525,7 @@ ip6_mrouter_done() reg_mif_num = -1; ip6_mrouter = NULL; + ip6_mrouter_ver = 0; splx(s); @@ -621,13 +544,10 @@ static struct sockaddr_in6 sin6 = { sizeof(sin6), AF_INET6 }; */ static int add_m6if(mifcp) - register struct mif6ctl *mifcp; + struct mif6ctl *mifcp; { - register struct mif6 *mifp; + struct mif6 *mifp; struct ifnet *ifp; -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__APPLE__) - struct in6_ifreq ifr; -#endif int error, s; #if notyet struct tbf *m_tbf = tbftable + mifcp->mif6c_mifi; @@ -644,12 +564,7 @@ add_m6if(mifcp) if (mifcp->mif6c_flags & MIFF_REGISTER) { if (reg_mif_num == (mifi_t)-1) { -#if defined(__NetBSD__) || defined(__OpenBSD__) - strcpy(multicast_register_if.if_xname, - "register_mif"); /* XXX */ -#else multicast_register_if.if_name = "register_mif"; -#endif multicast_register_if.if_flags |= IFF_LOOPBACK; multicast_register_if.if_index = mifcp->mif6c_mifi; reg_mif_num = mifcp->mif6c_mifi; @@ -663,32 +578,14 @@ add_m6if(mifcp) if ((ifp->if_flags & IFF_MULTICAST) == 0) return EOPNOTSUPP; -#if __NetBSD__ - s = splsoftnet(); -#else s = splnet(); -#endif -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__) error = if_allmulti(ifp, 1); -#else - /* - * Enable promiscuous reception of all IPv6 multicasts - * from the interface. - */ - ifr.ifr_addr.sin6_family = AF_INET6; - ifr.ifr_addr.sin6_addr = in6addr_any; - error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr); -#endif splx(s); if (error) return error; } -#if __NetBSD__ - s = splsoftnet(); -#else s = splnet(); -#endif mifp->m6_flags = mifcp->mif6c_flags; mifp->m6_ifp = ifp; #if notyet @@ -724,12 +621,9 @@ static int del_m6if(mifip) mifi_t *mifip; { - register struct mif6 *mifp = mif6table + *mifip; - register mifi_t mifi; + struct mif6 *mifp = mif6table + *mifip; + mifi_t mifi; struct ifnet *ifp; -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__APPLE__) - struct in6_ifreq ifr; -#endif int s; if (*mifip >= nummifs) @@ -737,11 +631,7 @@ del_m6if(mifip) if (mifp->m6_ifp == NULL) return EINVAL; -#if __NetBSD__ - s = splsoftnet(); -#else s = splnet(); -#endif if (!(mifp->m6_flags & MIFF_REGISTER)) { /* @@ -750,13 +640,7 @@ del_m6if(mifip) */ ifp = mifp->m6_ifp; -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__) if_allmulti(ifp, 0); -#else - ifr.ifr_addr.sin6_family = AF_INET6; - ifr.ifr_addr.sin6_addr = in6addr_any; - (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr); -#endif } #if notyet @@ -791,7 +675,7 @@ add_m6fc(mfccp) struct mf6c *rt; u_long hash; struct rtdetq *rte; - register u_short nstl; + u_short nstl; int s; MF6CFIND(mfccp->mf6cc_origin.sin6_addr, @@ -807,11 +691,7 @@ add_m6fc(mfccp) mfccp->mf6cc_parent); #endif -#if __NetBSD__ - s = splsoftnet(); -#else s = splnet(); -#endif rt->mf6c_parent = mfccp->mf6cc_parent; rt->mf6c_ifset = mfccp->mf6cc_ifset; splx(s); @@ -821,11 +701,7 @@ add_m6fc(mfccp) /* * Find the entry for which the upcall was made and update */ -#if __NetBSD__ - s = splsoftnet(); -#else s = splnet(); -#endif hash = MF6CHASH(mfccp->mf6cc_origin.sin6_addr, mfccp->mf6cc_mcastgrp.sin6_addr); for (rt = mf6ctable[hash], nstl = 0; rt; rt = rt->mf6c_next) { @@ -872,7 +748,7 @@ add_m6fc(mfccp) #if UPCALL_TIMING collate(&(rte->t)); #endif /* UPCALL_TIMING */ - _FREE(rte, M_MRTABLE); + FREE(rte, M_MRTABLE); rte = n; } rt->mf6c_stall = NULL; @@ -902,6 +778,7 @@ add_m6fc(mfccp) rt->mf6c_origin = mfccp->mf6cc_origin; rt->mf6c_mcastgrp = mfccp->mf6cc_mcastgrp; rt->mf6c_parent = mfccp->mf6cc_parent; + rt->mf6c_ifset = mfccp->mf6cc_ifset; /* initialize pkt counters per src-grp */ rt->mf6c_pkt_cnt = 0; rt->mf6c_byte_cnt = 0; @@ -925,6 +802,7 @@ add_m6fc(mfccp) rt->mf6c_origin = mfccp->mf6cc_origin; rt->mf6c_mcastgrp = mfccp->mf6cc_mcastgrp; rt->mf6c_parent = mfccp->mf6cc_parent; + rt->mf6c_ifset = mfccp->mf6cc_ifset; /* initialize pkt counters per src-grp */ rt->mf6c_pkt_cnt = 0; rt->mf6c_byte_cnt = 0; @@ -947,11 +825,11 @@ add_m6fc(mfccp) */ static void collate(t) - register struct timeval *t; + struct timeval *t; { - register u_long d; - register struct timeval tp; - register u_long delta; + u_long d; + struct timeval tp; + u_long delta; GET_TIME(tp); @@ -993,11 +871,7 @@ del_m6fc(mfccp) ip6_sprintf(&mcastgrp.sin6_addr)); #endif -#if __NetBSD__ - s = splsoftnet(); -#else s = splnet(); -#endif nptr = &mf6ctable[hash]; while ((rt = *nptr) != NULL) { @@ -1016,7 +890,7 @@ del_m6fc(mfccp) } *nptr = rt->mf6c_next; - _FREE(rt, M_MRTABLE); + FREE(rt, M_MRTABLE); splx(s); @@ -1054,13 +928,13 @@ socket_send(s, mm, src) int ip6_mforward(ip6, ifp, m) - register struct ip6_hdr *ip6; + struct ip6_hdr *ip6; struct ifnet *ifp; struct mbuf *m; { - register struct mf6c *rt; - register struct mif6 *mifp; - register struct mbuf *mm; + struct mf6c *rt; + struct mif6 *mifp; + struct mbuf *mm; int s; mifi_t mifi; @@ -1080,14 +954,32 @@ ip6_mforward(ip6, ifp, m) return 0; ip6->ip6_hlim--; + /* + * Source address check: do not forward packets with unspecified + * source. It was discussed in July 2000, on ipngwg mailing list. + * This is rather more serious than unicast cases, because some + * MLD packets can be sent with the unspecified source address + * (although such packets must normally set 1 to the hop limit field). + */ + if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) { + ip6stat.ip6s_cantforward++; + if (ip6_log_time + ip6_log_interval < time_second) { + ip6_log_time = time_second; + log(LOG_DEBUG, + "cannot forward " + "from %s to %s nxt %d received on %s\n", + ip6_sprintf(&ip6->ip6_src), + ip6_sprintf(&ip6->ip6_dst), + ip6->ip6_nxt, + if_name(m->m_pkthdr.rcvif)); + } + return 0; + } + /* * Determine forwarding mifs from the forwarding cache table */ -#if __NetBSD__ - s = splsoftnet(); -#else s = splnet(); -#endif MF6CFIND(ip6->ip6_src, ip6->ip6_dst, rt); /* Entry exists, so forward if necessary */ @@ -1101,10 +993,10 @@ ip6_mforward(ip6, ifp, m) * send message to routing daemon */ - register struct mbuf *mb0; - register struct rtdetq *rte; - register u_long hash; -/* register int i, npkts;*/ + struct mbuf *mb0; + struct rtdetq *rte; + u_long hash; +/* int i, npkts;*/ #if UPCALL_TIMING struct timeval tp; @@ -1138,7 +1030,7 @@ ip6_mforward(ip6, ifp, m) (M_HASCL(mb0) || mb0->m_len < sizeof(struct ip6_hdr))) mb0 = m_pullup(mb0, sizeof(struct ip6_hdr)); if (mb0 == NULL) { - _FREE(rte, M_MRTABLE); + FREE(rte, M_MRTABLE); splx(s); return ENOBUFS; } @@ -1156,12 +1048,15 @@ ip6_mforward(ip6, ifp, m) if (rt == NULL) { struct mrt6msg *im; +#if MRT6_OINIT + struct omrt6msg *oim; +#endif /* no upcall, so make a new entry */ rt = (struct mf6c *)_MALLOC(sizeof(*rt), M_MRTABLE, M_NOWAIT); if (rt == NULL) { - _FREE(rte, M_MRTABLE); + FREE(rte, M_MRTABLE); m_freem(mb0); splx(s); return ENOBUFS; @@ -1173,9 +1068,9 @@ ip6_mforward(ip6, ifp, m) mm = m_copy(mb0, 0, sizeof(struct ip6_hdr)); if (mm == NULL) { - _FREE(rte, M_MRTABLE); + FREE(rte, M_MRTABLE); m_freem(mb0); - _FREE(rt, M_MRTABLE); + FREE(rt, M_MRTABLE); splx(s); return ENOBUFS; } @@ -1185,9 +1080,30 @@ ip6_mforward(ip6, ifp, m) */ sin6.sin6_addr = ip6->ip6_src; - im = mtod(mm, struct mrt6msg *); - im->im6_msgtype = MRT6MSG_NOCACHE; - im->im6_mbz = 0; + im = NULL; +#if MRT6_OINIT + oim = NULL; +#endif + switch (ip6_mrouter_ver) { +#if MRT6_OINIT + case MRT6_OINIT: + oim = mtod(mm, struct omrt6msg *); + oim->im6_msgtype = MRT6MSG_NOCACHE; + oim->im6_mbz = 0; + break; +#endif + case MRT6_INIT: + im = mtod(mm, struct mrt6msg *); + im->im6_msgtype = MRT6MSG_NOCACHE; + im->im6_mbz = 0; + break; + default: + FREE(rte, M_MRTABLE); + m_freem(mb0); + FREE(rt, M_MRTABLE); + splx(s); + return EINVAL; + } #if MRT6DEBUG if (mrt6debug & DEBUG_FORWARD) @@ -1200,15 +1116,24 @@ ip6_mforward(ip6, ifp, m) mifp++, mifi++) ; - im->im6_mif = mifi; + switch (ip6_mrouter_ver) { +#if MRT6_OINIT + case MRT6_OINIT: + oim->im6_mif = mifi; + break; +#endif + case MRT6_INIT: + im->im6_mif = mifi; + break; + } if (socket_send(ip6_mrouter, mm, &sin6) < 0) { log(LOG_WARNING, "ip6_mforward: ip6_mrouter " "socket queue full\n"); mrt6stat.mrt6s_upq_sockfull++; - _FREE(rte, M_MRTABLE); + FREE(rte, M_MRTABLE); m_freem(mb0); - _FREE(rt, M_MRTABLE); + FREE(rt, M_MRTABLE); splx(s); return ENOBUFS; } @@ -1235,12 +1160,12 @@ ip6_mforward(ip6, ifp, m) } else { /* determine if q has overflowed */ struct rtdetq **p; - register int npkts = 0; + int npkts = 0; for (p = &rt->mf6c_stall; *p != NULL; p = &(*p)->next) if (++npkts > MAX_UPQ6) { mrt6stat.mrt6s_upq_ovflw++; - _FREE(rte, M_MRTABLE); + FREE(rte, M_MRTABLE); m_freem(mb0); splx(s); return 0; @@ -1263,24 +1188,24 @@ ip6_mforward(ip6, ifp, m) } } -/* - * Clean up cache entries if upcalls are not serviced - * Call from the Slow Timeout mechanism, every half second. - */ static void expire_upcalls_funneled(unused) - void *unused; + void *unused; { #ifdef __APPLE__ - boolean_t funnel_state; - funnel_state = thread_funnel_set(network_flock, TRUE); + boolean_t funnel_state; + funnel_state = thread_funnel_set(network_flock, TRUE); #endif - expire_upcalls(unused); + expire_upcalls(unused); #ifdef __APPLE__ (void) thread_funnel_set(network_flock, FALSE); #endif } +/* + * Clean up cache entries if upcalls are not serviced + * Call from the Slow Timeout mechanism, every half second. + */ static void expire_upcalls(unused) void *unused; @@ -1290,11 +1215,7 @@ expire_upcalls(unused) int i; int s; -#if __NetBSD__ - s = splsoftnet(); -#else s = splnet(); -#endif for (i = 0; i < MF6CTBLSIZ; i++) { if (nexpire[i] == 0) continue; @@ -1322,24 +1243,27 @@ expire_upcalls(unused) do { struct rtdetq *n = rte->next; m_freem(rte->m); - _FREE(rte, M_MRTABLE); + FREE(rte, M_MRTABLE); rte = n; } while (rte != NULL); mrt6stat.mrt6s_cache_cleanups++; nexpire[i]--; *nptr = mfc->mf6c_next; - _FREE(mfc, M_MRTABLE); + FREE(mfc, M_MRTABLE); } else { nptr = &mfc->mf6c_next; } } } splx(s); -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - expire_upcalls_ch = -#endif + +#ifndef __APPLE__ + callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT, + expire_upcalls, NULL); +#else timeout(expire_upcalls_funneled, (caddr_t)NULL, EXPIRE_TIMEOUT); +#endif } /* @@ -1347,14 +1271,14 @@ expire_upcalls(unused) */ static int ip6_mdq(m, ifp, rt) - register struct mbuf *m; - register struct ifnet *ifp; - register struct mf6c *rt; + struct mbuf *m; + struct ifnet *ifp; + struct mf6c *rt; { - register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); - register mifi_t mifi, iif; - register struct mif6 *mifp; - register int plen = m->m_pkthdr.len; + struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); + mifi_t mifi, iif; + struct mif6 *mifp; + int plen = m->m_pkthdr.len; /* * Macro to send packet on mif. Since RSVP packets don't get counted on @@ -1362,12 +1286,12 @@ ip6_mdq(m, ifp, rt) * seperate. */ -#define MC6_SEND(ip6,mifp,m) { \ - if ((mifp)->m6_flags & MIFF_REGISTER) \ - register_send((ip6), (mifp), (m)); \ - else \ - phyint_send((ip6), (mifp), (m)); \ -} +#define MC6_SEND(ip6, mifp, m) do { \ + if ((mifp)->m6_flags & MIFF_REGISTER) \ + register_send((ip6), (mifp), (m)); \ + else \ + phyint_send((ip6), (mifp), (m)); \ +} while (0) /* * Don't forward if it didn't arrive from the parent mif @@ -1390,55 +1314,83 @@ ip6_mdq(m, ifp, rt) * packets on this interface, send a message to the * routing daemon. */ - if(mifi < nummifs) /* have to make sure this is a valid mif */ - if(mif6table[mifi].m6_ifp) - - if (pim6 && (m->m_flags & M_LOOP) == 0) { - /* - * Check the M_LOOP flag to avoid an - * unnecessary PIM assert. - * XXX: M_LOOP is an ad-hoc hack... - */ - static struct sockaddr_in6 sin6 = - { sizeof(sin6), AF_INET6 }; - - register struct mbuf *mm; - struct mrt6msg *im; - - mm = m_copy(m, 0, - sizeof(struct ip6_hdr)); - if (mm && - (M_HASCL(mm) || - mm->m_len < sizeof(struct ip6_hdr))) - mm = m_pullup(mm, sizeof(struct ip6_hdr)); - if (mm == NULL) - return ENOBUFS; - + /* have to make sure this is a valid mif */ + if (mifi < nummifs && mif6table[mifi].m6_ifp) + if (pim6 && (m->m_flags & M_LOOP) == 0) { + /* + * Check the M_LOOP flag to avoid an + * unnecessary PIM assert. + * XXX: M_LOOP is an ad-hoc hack... + */ + static struct sockaddr_in6 sin6 = + { sizeof(sin6), AF_INET6 }; + + struct mbuf *mm; + struct mrt6msg *im; +#if MRT6_OINIT + struct omrt6msg *oim; +#endif + + mm = m_copy(m, 0, sizeof(struct ip6_hdr)); + if (mm && + (M_HASCL(mm) || + mm->m_len < sizeof(struct ip6_hdr))) + mm = m_pullup(mm, sizeof(struct ip6_hdr)); + if (mm == NULL) + return ENOBUFS; + +#if MRT6_OINIT + oim = NULL; +#endif + im = NULL; + switch (ip6_mrouter_ver) { +#if MRT6_OINIT + case MRT6_OINIT: + oim = mtod(mm, struct omrt6msg *); + oim->im6_msgtype = MRT6MSG_WRONGMIF; + oim->im6_mbz = 0; + break; +#endif + case MRT6_INIT: im = mtod(mm, struct mrt6msg *); - im->im6_msgtype = MRT6MSG_WRONGMIF; - im->im6_mbz = 0; - - for (mifp = mif6table, iif = 0; - iif < nummifs && mifp && - mifp->m6_ifp != ifp; - mifp++, iif++); - - im->im6_mif = iif; + im->im6_msgtype = MRT6MSG_WRONGMIF; + im->im6_mbz = 0; + break; + default: + m_freem(mm); + return EINVAL; + } + for (mifp = mif6table, iif = 0; + iif < nummifs && mifp && + mifp->m6_ifp != ifp; + mifp++, iif++) + ; + + switch (ip6_mrouter_ver) { +#if MRT6_OINIT + case MRT6_OINIT: + oim->im6_mif = iif; + sin6.sin6_addr = oim->im6_src; + break; +#endif + case MRT6_INIT: + im->im6_mif = iif; sin6.sin6_addr = im->im6_src; + break; + } - mrt6stat.mrt6s_upcalls++; + mrt6stat.mrt6s_upcalls++; - if (socket_send(ip6_mrouter, mm, - &sin6) < 0) { + if (socket_send(ip6_mrouter, mm, &sin6) < 0) { #if MRT6DEBUG - if (mrt6debug) - log(LOG_WARNING, "mdq, ip6_mrouter socket queue full\n"); + if (mrt6debug) + log(LOG_WARNING, "mdq, ip6_mrouter socket queue full\n"); #endif - ++mrt6stat.mrt6s_upq_sockfull; - return ENOBUFS; - } /* if socket Q full */ - } /* if PIM */ + ++mrt6stat.mrt6s_upq_sockfull; + return ENOBUFS; + } /* if socket Q full */ + } /* if PIM */ return 0; } /* if wrong iif */ @@ -1460,6 +1412,25 @@ ip6_mdq(m, ifp, rt) */ for (mifp = mif6table, mifi = 0; mifi < nummifs; mifp++, mifi++) if (IF_ISSET(mifi, &rt->mf6c_ifset)) { + /* + * check if the outgoing packet is going to break + * a scope boundary. + * XXX For packets through PIM register tunnel + * interface, we believe a routing daemon. + */ + if ((mif6table[rt->mf6c_parent].m6_flags & + MIFF_REGISTER) == 0 && + (mif6table[mifi].m6_flags & MIFF_REGISTER) == 0 && + (in6_addr2scopeid(ifp, &ip6->ip6_dst) != + in6_addr2scopeid(mif6table[mifi].m6_ifp, + &ip6->ip6_dst) || + in6_addr2scopeid(ifp, &ip6->ip6_src) != + in6_addr2scopeid(mif6table[mifi].m6_ifp, + &ip6->ip6_src))) { + ip6stat.ip6s_badscope++; + continue; + } + mifp->m6_pkt_out++; mifp->m6_bytes_out += plen; MC6_SEND(ip6, mifp, m); @@ -1473,16 +1444,13 @@ phyint_send(ip6, mifp, m) struct mif6 *mifp; struct mbuf *m; { - register struct mbuf *mb_copy; + struct mbuf *mb_copy; struct ifnet *ifp = mifp->m6_ifp; int error = 0; -#if __NetBSD__ - int s = splsoftnet(); -#else - int s = splnet(); -#endif - static struct route_in6 ro6; + int s = splnet(); /* needs to protect static "ro" below. */ + static struct route_in6 ro; struct in6_multi *in6m; + struct sockaddr_in6 *dst6; /* * Make a new reference to the packet; make sure that @@ -1493,8 +1461,10 @@ phyint_send(ip6, mifp, m) if (mb_copy && (M_HASCL(mb_copy) || mb_copy->m_len < sizeof(struct ip6_hdr))) mb_copy = m_pullup(mb_copy, sizeof(struct ip6_hdr)); - if (mb_copy == NULL) + if (mb_copy == NULL) { + splx(s); return; + } /* set MCAST flag to the outgoing packet */ mb_copy->m_flags |= M_MCAST; @@ -1512,7 +1482,7 @@ phyint_send(ip6, mifp, m) /* XXX: ip6_output will override ip6->ip6_hlim */ im6o.im6o_multicast_hlim = ip6->ip6_hlim; im6o.im6o_multicast_loop = 1; - error = ip6_output(mb_copy, NULL, &ro6, + error = ip6_output(mb_copy, NULL, &ro, IPV6_FORWARDING, &im6o, NULL); #if MRT6DEBUG @@ -1528,31 +1498,38 @@ phyint_send(ip6, mifp, m) * If we belong to the destination multicast group * on the outgoing interface, loop back a copy. */ + dst6 = (struct sockaddr_in6 *)&ro.ro_dst; IN6_LOOKUP_MULTI(ip6->ip6_dst, ifp, in6m); if (in6m != NULL) { - ro6.ro_dst.sin6_len = sizeof(struct sockaddr_in6); - ro6.ro_dst.sin6_family = AF_INET6; - ro6.ro_dst.sin6_addr = ip6->ip6_dst; - ip6_mloopback(ifp, m, &ro6.ro_dst); + dst6->sin6_len = sizeof(struct sockaddr_in6); + dst6->sin6_family = AF_INET6; + dst6->sin6_addr = ip6->ip6_dst; + ip6_mloopback(ifp, m, (struct sockaddr_in6 *)&ro.ro_dst); } /* * Put the packet into the sending queue of the outgoing interface * if it would fit in the MTU of the interface. */ if (mb_copy->m_pkthdr.len < ifp->if_mtu || ifp->if_mtu < IPV6_MMTU) { - ro6.ro_dst.sin6_len = sizeof(struct sockaddr_in6); - ro6.ro_dst.sin6_family = AF_INET6; - ro6.ro_dst.sin6_addr = ip6->ip6_dst; + dst6->sin6_len = sizeof(struct sockaddr_in6); + dst6->sin6_family = AF_INET6; + dst6->sin6_addr = ip6->ip6_dst; /* * We just call if_output instead of nd6_output here, since * we need no ND for a multicast forwarded packet...right? */ #ifdef __APPLE__ + /* Make sure the HW checksum flags are cleaned before sending the packet */ + + mb_copy->m_pkthdr.rcvif = (struct ifnet *)0; + mb_copy->m_pkthdr.csum_data = 0; + mb_copy->m_pkthdr.csum_flags = 0; + error = dlil_output(ifptodlt(ifp, PF_INET6), mb_copy, - NULL, (struct sockaddr *)&ro6.ro_dst, 0); + NULL, (struct sockaddr *)&ro.ro_dst, 0); #else error = (*ifp->if_output)(ifp, mb_copy, - (struct sockaddr *)&ro6.ro_dst, + (struct sockaddr *)&ro.ro_dst, NULL); #endif #if MRT6DEBUG @@ -1560,47 +1537,35 @@ phyint_send(ip6, mifp, m) log(LOG_DEBUG, "phyint_send on mif %d err %d\n", mifp - mif6table, error); #endif - } - else { + } else { #if MULTICAST_PMTUD icmp6_error(mb_copy, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu); - return; #else #if MRT6DEBUG -#if __NetBSD__ - if (mrt6debug & DEBUG_DEBUG_XMIT) - log(LOG_DEBUG, - "phyint_send: packet too big on %s o %s g %s" - " size %d(discarded)\n", - ifp->if_xname, - ip6_sprintf(&ip6->ip6_src), - ip6_sprintf(&ip6->ip6_dst), - mb_copy->m_pkthdr.len); -#else if (mrt6debug & DEBUG_XMIT) log(LOG_DEBUG, - "phyint_send: packet too big on %s%u o %s g %s" + "phyint_send: packet too big on %s o %s g %s" " size %d(discarded)\n", - ifp->if_name, ifp->if_unit, + if_name(ifp), ip6_sprintf(&ip6->ip6_src), ip6_sprintf(&ip6->ip6_dst), mb_copy->m_pkthdr.len); -#endif /* __NetBSD__ */ #endif /* MRT6DEBUG */ m_freem(mb_copy); /* simply discard the packet */ - return; #endif } + + splx(s); } static int register_send(ip6, mif, m) - register struct ip6_hdr *ip6; + struct ip6_hdr *ip6; struct mif6 *mif; - register struct mbuf *m; + struct mbuf *m; { - register struct mbuf *mm; - register int i, len = m->m_pkthdr.len; + struct mbuf *mm; + int i, len = m->m_pkthdr.len; static struct sockaddr_in6 sin6 = { sizeof(sin6), AF_INET6 }; struct mrt6msg *im6; @@ -1615,6 +1580,7 @@ register_send(ip6, mif, m) MGETHDR(mm, M_DONTWAIT, MT_HEADER); if (mm == NULL) return ENOBUFS; + mm->m_pkthdr.rcvif = NULL; mm->m_data += max_linkhdr; mm->m_len = sizeof(struct ip6_hdr); @@ -1653,8 +1619,8 @@ register_send(ip6, mif, m) log(LOG_WARNING, "register_send: ip_mrouter socket queue full\n"); #endif - ++mrt6stat.mrt6s_upq_sockfull; - return ENOBUFS; + ++mrt6stat.mrt6s_upq_sockfull; + return ENOBUFS; } return 0; } @@ -1667,25 +1633,27 @@ register_send(ip6, mif, m) * is stripped off, and the inner packet is passed to register_mforward. */ int -pim6_input(mp, offp, proto) +pim6_input(mp, offp) struct mbuf **mp; - int *offp, proto; + int *offp; { - register struct pim *pim; /* pointer to a pim struct */ - register struct ip6_hdr *ip6; - register int pimlen; + struct pim *pim; /* pointer to a pim struct */ + struct ip6_hdr *ip6; + int pimlen; struct mbuf *m = *mp; - int minlen; + int minlen; int off = *offp; + int proto; ++pim6stat.pim6s_rcv_total; - ip6 = mtod(m, struct ip6_hdr *); - pimlen = m->m_pkthdr.len - *offp; + ip6 = mtod(m, struct ip6_hdr *); + pimlen = m->m_pkthdr.len - *offp; + proto = ip6->ip6_nxt; - /* - * Validate lengths - */ + /* + * Validate lengths + */ if (pimlen < PIM_MINLEN) { ++pim6stat.pim6s_rcv_tooshort; #if MRT6DEBUG @@ -1725,9 +1693,8 @@ pim6_input(mp, offp, proto) } #endif - -#define PIM6_CHECKSUM 1 -#if PIM6_CHECKSUM +#define PIM6_CHECKSUM +#ifdef PIM6_CHECKSUM { int cksumlen; @@ -1822,6 +1789,18 @@ pim6_input(mp, offp, proto) ip6_sprintf(&eip6->ip6_dst), ntohs(eip6->ip6_plen)); #endif + + /* verify the version number of the inner packet */ + if ((eip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { + ++pim6stat.pim6s_rcv_badregisters; +#if MRT6DEBUG + log(LOG_DEBUG, "pim6_input: invalid IP version (%d) " + "of the inner packet\n", + (eip6->ip6_vfc & IPV6_VERSION)); +#endif + m_freem(m); + return(IPPROTO_NONE); + } /* verify the inner packet is destined to a mcast group */ if (!IN6_IS_ADDR_MULTICAST(&eip6->ip6_dst)) { @@ -1866,25 +1845,20 @@ pim6_input(mp, offp, proto) } #endif -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - rc = if_simloop(mif6table[reg_mif_num].m6_ifp, m, - (struct sockaddr *) &dst, NULL); -#else -#if defined (__APPLE__) +#ifdef __APPLE__ + if (lo_dl_tag == 0) - dlil_find_dltag(APPLE_IF_FAM_LOOPBACK, 0, PF_INET6, &lo_dl_tag); + dlil_find_dltag(APPLE_IF_FAM_LOOPBACK, 0, PF_INET, &lo_dl_tag); if (lo_dl_tag) - dlil_output(lo_dl_tag, m, 0, (struct sockaddr *) &dst, 0); + dlil_output(lo_dl_tag, m, 0, (struct sockaddr *)&dst, 0); else { printf("Warning: pim6_input call to dlil_find_dltag failed!\n"); m_freem(m); } #else - rc = looutput(mif6table[reg_mif_num].m6_ifp, m, - (struct sockaddr *) &dst, - (struct rtentry *) NULL); -#endif + rc = if_simloop(mif6table[reg_mif_num].m6_ifp, m, + dst.sin6_family, NULL); #endif /* prepare the register head to send to the mrouting daemon */ @@ -1898,6 +1872,6 @@ pim6_input(mp, offp, proto) * encapsulated ip6 header. */ pim6_input_to_daemon: - rip6_input(&m, offp, proto); + rip6_input(&m, offp); return(IPPROTO_DONE); } diff --git a/bsd/netinet6/ip6_mroute.h b/bsd/netinet6/ip6_mroute.h index 9fe2e5801..5bae8b74e 100644 --- a/bsd/netinet6/ip6_mroute.h +++ b/bsd/netinet6/ip6_mroute.h @@ -1,4 +1,5 @@ -/* $KAME: ip6_mroute.h,v 1.7 2000/02/22 14:04:22 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/ip6_mroute.h,v 1.2.2.2 2001/07/03 11:01:53 ume Exp $ */ +/* $KAME: ip6_mroute.h,v 1.17 2001/02/10 02:05:52 itojun Exp $ */ /* * Copyright (C) 1998 WIDE Project. @@ -45,17 +46,21 @@ #ifndef _NETINET6_IP6_MROUTE_H_ #define _NETINET6_IP6_MROUTE_H_ +#include /* * Multicast Routing set/getsockopt commands. */ -#define MRT6_INIT 100 /* initialize forwarder */ +#ifdef KERNEL +#define MRT6_OINIT 100 /* initialize forwarder (omrt6msg) */ +#endif #define MRT6_DONE 101 /* shut down forwarder */ #define MRT6_ADD_MIF 102 /* add multicast interface */ #define MRT6_DEL_MIF 103 /* delete multicast interface */ #define MRT6_ADD_MFC 104 /* insert forwarding cache entry */ #define MRT6_DEL_MFC 105 /* delete forwarding cache entry */ #define MRT6_PIM 107 /* enable pim code */ +#define MRT6_INIT 108 /* initialize forwarder (mrt6msg) */ #if BSD >= 199103 #define GET_TIME(t) microtime(&t) @@ -75,7 +80,7 @@ typedef u_short mifi_t; /* type of a mif index */ #define IF_SETSIZE 256 #endif -typedef long if_mask; +typedef u_int32_t if_mask; #define NIFBITS (sizeof(if_mask) * NBBY) /* bits per mask */ #ifndef howmany @@ -83,7 +88,7 @@ typedef long if_mask; #endif typedef struct if_set { - fd_mask ifs_bits[howmany(IF_SETSIZE, NIFBITS)]; + if_mask ifs_bits[howmany(IF_SETSIZE, NIFBITS)]; } if_set; #define IF_SET(n, p) ((p)->ifs_bits[(n)/NIFBITS] |= (1 << ((n) % NIFBITS))) @@ -135,21 +140,45 @@ struct mrt6stat { u_quad_t mrt6s_upq_sockfull; /* upcalls dropped - socket full */ }; +#if MRT6_OINIT /* * Struct used to communicate from kernel to multicast router * note the convenient similarity to an IPv6 header. + * XXX old version, superseded by mrt6msg. */ -struct mrt6msg { +struct omrt6msg { u_long unused1; u_char im6_msgtype; /* what type of message */ -#define MRT6MSG_NOCACHE 1 +#if 0 +#define MRT6MSG_NOCACHE 1 #define MRT6MSG_WRONGMIF 2 #define MRT6MSG_WHOLEPKT 3 /* used for user level encap*/ +#endif u_char im6_mbz; /* must be zero */ u_char im6_mif; /* mif rec'd on */ u_char unused2; struct in6_addr im6_src, im6_dst; }; +#endif + +/* + * Structure used to communicate from kernel to multicast router. + * We'll overlay the structure onto an MLD header (not an IPv6 header + * like igmpmsg{} used for IPv4 implementation). This is because this + * structure will be passed via an IPv6 raw socket, on which an application + * will only receive the payload i.e. the data after the IPv6 header and all + * the extension headers. (see Section 3 of draft-ietf-ipngwg-2292bis-01) + */ +struct mrt6msg { +#define MRT6MSG_NOCACHE 1 +#define MRT6MSG_WRONGMIF 2 +#define MRT6MSG_WHOLEPKT 3 /* used for user level encap*/ + u_char im6_mbz; /* must be zero */ + u_char im6_msgtype; /* what type of message */ + u_int16_t im6_mif; /* mif rec'd on */ + u_int32_t im6_pad; /* padding for 64bit arch */ + struct in6_addr im6_src, im6_dst; +}; /* * Argument structure used by multicast routing daemon to get src-grp @@ -174,7 +203,8 @@ struct sioc_mif_req6 { u_quad_t obytes; /* Output byte count on mif */ }; -#if KERNEL +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE /* * The kernel's multicast-interface structure. */ @@ -244,6 +274,7 @@ int ip6_mrouter_set __P((struct socket *so, struct sockopt *sopt)); int ip6_mrouter_get __P((struct socket *so, struct sockopt *sopt)); int ip6_mrouter_done __P((void)); int mrt6_ioctl __P((int, caddr_t)); +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ #endif /* !_NETINET6_IP6_MROUTE_H_ */ diff --git a/bsd/netinet6/ip6_output.c b/bsd/netinet6/ip6_output.c index a6e82dac0..a079aa4b0 100644 --- a/bsd/netinet6/ip6_output.c +++ b/bsd/netinet6/ip6_output.c @@ -1,4 +1,5 @@ -/* $KAME: ip6_output.c,v 1.94 2000/04/04 14:45:44 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/ip6_output.c,v 1.13.2.10 2001/07/15 18:18:34 ume Exp $ */ +/* $KAME: ip6_output.c,v 1.180 2001/05/21 05:37:50 jinmei Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -64,15 +65,6 @@ * @(#)ip_output.c 8.3 (Berkeley) 1/21/94 */ -#if __FreeBSD__ -#include "opt_ip6fw.h" -#endif -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#if __NetBSD__ /*XXX*/ -#include "opt_ipsec.h" -#endif -#endif #include #include @@ -82,9 +74,7 @@ #include #include #include -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__) #include -#endif #include #include @@ -92,40 +82,33 @@ #include #include -#if defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802) -#include -#include -#endif +#include #include #include #include -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802) || defined (__APPLE__) #include -#else -#include -#endif #include #if IPSEC #include +#if INET6 +#include +#endif #include -#include +extern int ipsec_bypass; #endif /* IPSEC */ -#ifndef __bsdi__ -#include "loop.h" -#endif +#include #include -#if IPV6FIREWALL -#include -#endif - -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#ifndef __APPLE__ static MALLOC_DEFINE(M_IPMOPTS, "ip6_moptions", "internet multicast options"); #endif + +static u_long lo_dl_tag = 0; + struct ip6_exthdrs { struct mbuf *ip6e_ip6; struct mbuf *ip6e_hbh; @@ -134,15 +117,8 @@ struct ip6_exthdrs { struct mbuf *ip6e_dest2; }; -static int ip6_pcbopt __P((int, u_char *, int, struct ip6_pktopts **, int)); -static int ip6_getpcbopt __P((struct ip6_pktopts *, int, void **, int *)); -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined(__APPLE__) static int ip6_pcbopts __P((struct ip6_pktopts **, struct mbuf *, struct socket *, struct sockopt *sopt)); -#else -static int ip6_pcbopts __P((struct ip6_pktopts **, struct mbuf *, - struct socket *)); -#endif static int ip6_setmoptions __P((int, struct ip6_moptions **, struct mbuf *)); static int ip6_getmoptions __P((int, struct ip6_moptions *, struct mbuf **)); static int ip6_copyexthdr __P((struct mbuf **, caddr_t, int)); @@ -150,19 +126,6 @@ static int ip6_insertfraghdr __P((struct mbuf *, struct mbuf *, int, struct ip6_frag **)); static int ip6_insert_jumboopt __P((struct ip6_exthdrs *, u_int32_t)); static int ip6_splithdr __P((struct mbuf *, struct ip6_exthdrs *)); -#if defined(__bsdi__) || defined(__OpenBSD__) -extern struct ifnet loif; -#endif - -#if __NetBSD__ -extern struct ifnet **ifindex2ifnet; -extern struct ifnet loif[NLOOP]; -#endif - -#if MIP6 -int (*mip6_output_hook)(struct mbuf *m, struct ip6_pktopts **opt); -#endif /* MIP6 */ -static u_long lo_dl_tag = 0; /* * IP6 output. The packet in mbuf chain m contains a skeletal IP6 @@ -170,6 +133,10 @@ static u_long lo_dl_tag = 0; * This function may modify ver and hlim only. * The mbuf chain containing the packet will be freed. * The mbuf opt, if present, will not be freed. + * + * type of "mtu": rt_rmx.rmx_mtu is u_long, ifnet.ifr_mtu is int, and + * nd_ifinfo.linkmtu is u_int32_t. so we use u_long to hold largest one, + * which is rt_rmx.rmx_mtu. */ int ip6_output(m0, opt, ro, flags, im6o, ifpp) @@ -181,13 +148,13 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp) struct ifnet **ifpp; /* XXX: just for statistics */ { struct ip6_hdr *ip6, *mhip6; - struct ifnet *ifp; + struct ifnet *ifp, *origifp; struct mbuf *m = m0; int hlen, tlen, len, off; struct route_in6 ip6route; struct sockaddr_in6 *dst; int error = 0; - struct in6_ifaddr *ia; + struct in6_ifaddr *ia = NULL; u_long mtu; u_int32_t optlen = 0, plen = 0, unfragpartlen = 0; struct ip6_exthdrs exthdrs; @@ -195,21 +162,22 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp) struct route_in6 *ro_pmtu = NULL; int hdrsplit = 0; int needipsec = 0; - - #if IPSEC int needipsectun = 0; - struct socket *so; + struct socket *so = NULL; struct secpolicy *sp = NULL; /* for AH processing. stupid to have "socket" variable in IP layer... */ - so = ipsec_getsocket(m); - ipsec_setsocket(m, NULL); + if (ipsec_bypass == 0) + { + so = ipsec_getsocket(m); + (void)ipsec_setsocket(m, NULL); + } ip6 = mtod(m, struct ip6_hdr *); #endif /* IPSEC */ -#define MAKE_EXTHDR(hp,mp) \ - { \ +#define MAKE_EXTHDR(hp, mp) \ + do { \ if (hp) { \ struct ip6_ext *eh = (struct ip6_ext *)(hp); \ error = ip6_copyexthdr((mp), (caddr_t)(hp), \ @@ -217,34 +185,15 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp) if (error) \ goto freehdrs; \ } \ - } + } while (0) bzero(&exthdrs, sizeof(exthdrs)); -#if MIP6 - /* - * Mobile IPv6 - * - * Call Mobile IPv6 to check if there are any Destination Header - * options to add. - */ - if (mip6_output_hook) { - error = (*mip6_output_hook)(m, &opt); - if (error) - goto freehdrs; - } -#endif /* MIP6 */ - if (opt) { /* Hop-by-Hop options header */ MAKE_EXTHDR(opt->ip6po_hbh, &exthdrs.ip6e_hbh); - if (opt->ip6po_rthdr) { - /* - * Destination options header(1st part) - * This only makes sence with a routing header. - */ - MAKE_EXTHDR(opt->ip6po_dest1, &exthdrs.ip6e_dest1); - } + /* Destination options header(1st part) */ + MAKE_EXTHDR(opt->ip6po_dest1, &exthdrs.ip6e_dest1); /* Routing header */ MAKE_EXTHDR(opt->ip6po_rthdr, &exthdrs.ip6e_rthdr); /* Destination options header(2nd part) */ @@ -252,6 +201,9 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp) } #if IPSEC + if (ipsec_bypass != 0) + goto skip_ipsec; + /* get a security policy for this packet */ if (so == NULL) sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, 0, &error); @@ -260,7 +212,7 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp) if (sp == NULL) { ipsec6stat.out_inval++; - goto bad; + goto freehdrs; } error = 0; @@ -272,7 +224,7 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp) * This packet is just discarded. */ ipsec6stat.out_polvio++; - goto bad; + goto freehdrs; case IPSEC_POLICY_BYPASS: case IPSEC_POLICY_NONE: @@ -284,7 +236,7 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp) if (sp->req == NULL) { /* acquire a policy */ error = key_spdacquire(sp); - goto bad; + goto freehdrs; } needipsec = 1; break; @@ -293,6 +245,7 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp) default: printf("ip6_output: Invalid policy found. %d\n", sp->policy); } + skip_ipsec: #endif /* IPSEC */ /* @@ -375,8 +328,8 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp) ip6->ip6_nxt = IPPROTO_DSTOPTS; } -#define MAKE_CHAIN(m,mp,p,i)\ - {\ +#define MAKE_CHAIN(m, mp, p, i)\ + do {\ if (m) {\ if (!hdrsplit) \ panic("assumption failed: hdr not split"); \ @@ -387,7 +340,7 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp) (mp)->m_next = (m);\ (mp) = (m);\ }\ - } + } while (0) /* * result: IPv6 hbh dest1 rthdr dest2 payload * m will point to IPv6 header. mprev will point to the @@ -465,19 +418,17 @@ skip_ipsec2:; (struct ip6_rthdr *)(mtod(exthdrs.ip6e_rthdr, struct ip6_rthdr *)); struct ip6_rthdr0 *rh0; - struct in6_addr *addr; finaldst = ip6->ip6_dst; - switch(rh->ip6r_type) { + switch (rh->ip6r_type) { case IPV6_RTHDR_TYPE_0: rh0 = (struct ip6_rthdr0 *)rh; - addr = (struct in6_addr *)(rh0 + 1); - - ip6->ip6_dst = *addr; - bcopy((caddr_t)(addr + 1), (caddr_t)addr, - sizeof(struct in6_addr)*(rh0->ip6r0_segleft - 1) + ip6->ip6_dst = rh0->ip6r0_addr[0]; + bcopy((caddr_t)&rh0->ip6r0_addr[1], + (caddr_t)&rh0->ip6r0_addr[0], + sizeof(struct in6_addr)*(rh0->ip6r0_segleft - 1) ); - *(addr + rh0->ip6r0_segleft - 1) = finaldst; + rh0->ip6r0_addr[rh0->ip6r0_segleft - 1] = finaldst; break; default: /* is it possible? */ error = EINVAL; @@ -518,7 +469,7 @@ skip_ipsec2:; */ if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 || !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_dst))) { - RTFREE(ro->ro_rt); + rtfree(ro->ro_rt); ro->ro_rt = (struct rtentry *)0; } if (ro->ro_rt == 0) { @@ -526,6 +477,11 @@ skip_ipsec2:; dst->sin6_family = AF_INET6; dst->sin6_len = sizeof(struct sockaddr_in6); dst->sin6_addr = ip6->ip6_dst; +#if SCOPEDROUTING + /* XXX: sin6_scope_id should already be fixed at this point */ + if (IN6_IS_SCOPE_LINKLOCAL(&dst->sin6_addr)) + dst->sin6_scope_id = ntohs(dst->sin6_addr.s6_addr16[1]); +#endif } #if IPSEC if (needipsec && needipsectun) { @@ -589,18 +545,11 @@ skip_ipsec2:; * ifp must point it. */ if (ro->ro_rt == 0) { -#ifndef __bsdi__ /* * non-bsdi always clone routes, if parent is * PRF_CLONING. */ rtalloc((struct route *)ro); -#else - if (ro == &ip6route) /* xxx kazu */ - rtalloc((struct route *)ro); - else - rtcalloc((struct route *)ro); -#endif } if (ro->ro_rt == 0) { ip6stat.ip6s_noroute++; @@ -678,11 +627,7 @@ skip_ipsec2:; in6_ifstat_inc(ifp, ifs6_out_discard); goto bad; } else { -#ifdef __bsdi__ - ifp = loifp; -#else ifp = &loif[0]; -#endif } } @@ -699,11 +644,7 @@ skip_ipsec2:; if (ifp == NULL) { if (ro->ro_rt == 0) { ro->ro_rt = rtalloc1((struct sockaddr *) - &ro->ro_dst, 0 -#if __FreeBSD__ || defined (__APPLE__) - , 0UL -#endif - ); + &ro->ro_dst, 0, 0UL); } if (ro->ro_rt == 0) { ip6stat.ip6s_noroute++; @@ -779,12 +720,6 @@ skip_ipsec2:; if (ifpp) *ifpp = ifp; - /* - * Upper-layer reachability confirmation - */ - if (opt && (opt->ip6po_flags & IP6PO_REACHCONF)) - nd6_nud_hint(ro->ro_rt, NULL); - /* * Determine path MTU. */ @@ -795,7 +730,7 @@ skip_ipsec2:; if (ro_pmtu->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 || !IN6_ARE_ADDR_EQUAL(&sin6_fin->sin6_addr, &finaldst))) { - RTFREE(ro_pmtu->ro_rt); + rtfree(ro_pmtu->ro_rt); ro_pmtu->ro_rt = (struct rtentry *)0; } if (ro_pmtu->ro_rt == 0) { @@ -804,18 +739,14 @@ skip_ipsec2:; sin6_fin->sin6_len = sizeof(struct sockaddr_in6); sin6_fin->sin6_addr = finaldst; -#ifdef __bsdi__ /* bsdi needs rtcalloc to clone a route. */ - rtcalloc((struct route *)ro_pmtu); -#else rtalloc((struct route *)ro_pmtu); -#endif } } if (ro_pmtu->ro_rt != NULL) { u_int32_t ifmtu = nd_ifinfo[ifp->if_index].linkmtu; mtu = ro_pmtu->ro_rt->rt_rmx.rmx_mtu; - if (mtu > ifmtu) { + if (mtu > ifmtu || mtu == 0) { /* * The MTU on the route is larger than the MTU on * the interface! This shouldn't happen, unless the @@ -823,6 +754,9 @@ skip_ipsec2:; * interface was brought up. Change the MTU in the * route to match the interface MTU (as long as the * field isn't locked). + * + * if MTU on the route is 0, we need to fix the MTU. + * this case happens with path MTU discovery timeouts. */ mtu = ifmtu; if ((ro_pmtu->ro_rt->rt_rmx.rmx_locks & RTV_MTU) == 0) @@ -835,29 +769,63 @@ skip_ipsec2:; /* * advanced API (IPV6_USE_MIN_MTU) overrides mtu setting */ - if (mtu > IPV6_MMTU) { - if ((opt && (opt->ip6po_flags & IP6PO_MINMTU)) || - (flags & IPV6_MINMTU)) { - mtu = IPV6_MMTU; - } - } + if ((flags & IPV6_MINMTU) != 0 && mtu > IPV6_MMTU) + mtu = IPV6_MMTU; - /* - * Fake link-local scope-class addresses - */ - if ((ifp->if_flags & IFF_LOOPBACK) == 0) { + /* Fake scoped addresses */ + if ((ifp->if_flags & IFF_LOOPBACK) != 0) { + /* + * If source or destination address is a scoped address, and + * the packet is going to be sent to a loopback interface, + * we should keep the original interface. + */ + + /* + * XXX: this is a very experimental and temporary solution. + * We eventually have sockaddr_in6 and use the sin6_scope_id + * field of the structure here. + * We rely on the consistency between two scope zone ids + * of source add destination, which should already be assured + * larger scopes than link will be supported in the near + * future. + */ + origifp = NULL; if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) - ip6->ip6_src.s6_addr16[1] = 0; - if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) - ip6->ip6_dst.s6_addr16[1] = 0; + origifp = ifindex2ifnet[ntohs(ip6->ip6_src.s6_addr16[1])]; + else if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) + origifp = ifindex2ifnet[ntohs(ip6->ip6_dst.s6_addr16[1])]; + /* + * XXX: origifp can be NULL even in those two cases above. + * For example, if we remove the (only) link-local address + * from the loopback interface, and try to send a link-local + * address without link-id information. Then the source + * address is ::1, and the destination address is the + * link-local address with its s6_addr16[1] being zero. + * What is worse, if the packet goes to the loopback interface + * by a default rejected route, the null pointer would be + * passed to looutput, and the kernel would hang. + * The following last resort would prevent such disaster. + */ + if (origifp == NULL) + origifp = ifp; } + else + origifp = ifp; +#ifndef SCOPEDROUTING + /* + * clear embedded scope identifiers if necessary. + * in6_clearscope will touch the addresses only when necessary. + */ + in6_clearscope(&ip6->ip6_src); + in6_clearscope(&ip6->ip6_dst); +#endif -#if IPV6FIREWALL /* * Check with the firewall... */ - if (ip6_fw_chk_ptr) { + if (ip6_fw_enable && ip6_fw_chk_ptr) { u_short port = 0; + m->m_pkthdr.rcvif = NULL; /*XXX*/ /* If ipfw says divert, we have to just drop packet */ if ((*ip6_fw_chk_ptr)(&ip6, ifp, &port, &m)) { m_freem(m); @@ -868,7 +836,6 @@ skip_ipsec2:; goto done; } } -#endif /* * If the outgoing packet contains a hop-by-hop options header, @@ -876,11 +843,14 @@ skip_ipsec2:; * (RFC 2460, section 4.) */ if (exthdrs.ip6e_hbh) { - struct ip6_hbh *hbh = mtod(exthdrs.ip6e_hbh, - struct ip6_hbh *); + struct ip6_hbh *hbh = mtod(exthdrs.ip6e_hbh, struct ip6_hbh *); u_int32_t dummy1; /* XXX unused */ u_int32_t dummy2; /* XXX unused */ +#if DIAGNOSTIC + if ((hbh->ip6h_len + 1) << 3 > exthdrs.ip6e_hbh->m_len) + panic("ip6e_hbh is not continuous"); +#endif /* * XXX: if we have to send an ICMPv6 error to the sender, * we need the M_LOOP flag since icmp6_error() expects @@ -923,23 +893,19 @@ skip_ipsec2:; #endif ) { -#if defined(__NetBSD__) && defined(IFA_STATS) - if (IFA_STATS) { - struct in6_ifaddr *ia6; - ip6 = mtod(m, struct ip6_hdr *); - ia6 = in6_ifawithifp(ifp, &ip6->ip6_src); - if (ia6) { - ia->ia_ifa.ifa_data.ifad_outbytes += - m->m_pkthdr.len; - } - } + /* Record statistics for this interface address. */ + if (ia && !(flags & IPV6_FORWARDING)) { +#ifndef __APPLE__ + ia->ia_ifa.if_opackets++; + ia->ia_ifa.if_obytes += m->m_pkthdr.len; #endif -#if OLDIP6OUTPUT - error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, - ro->ro_rt); -#else - error = nd6_output(ifp, m, dst, ro->ro_rt); + } +#ifdef IPSEC + /* clean ipsec history once it goes out of the node */ + ipsec_delaux(m); #endif + + error = nd6_output(ifp, origifp, m, dst, ro->ro_rt); goto done; } else if (mtu < IPV6_MMTU) { /* @@ -967,6 +933,7 @@ skip_ipsec2:; hlen = unfragpartlen; if (mtu > IPV6_MAXPACKET) mtu = IPV6_MAXPACKET; + len = (mtu - hlen - sizeof(struct ip6_frag)) & ~7; if (len < 8) { error = EMSGSIZE; @@ -1006,6 +973,7 @@ skip_ipsec2:; ip6stat.ip6s_odropped++; goto sendorfree; } + m->m_pkthdr.rcvif = NULL; m->m_flags = m0->m_flags & M_COPYFLAGS; *mnext = m; mnext = &m->m_nextpkt; @@ -1055,24 +1023,18 @@ sendorfree: m0 = m->m_nextpkt; m->m_nextpkt = 0; if (error == 0) { -#if defined(__NetBSD__) && defined(IFA_STATS) - if (IFA_STATS) { - struct in6_ifaddr *ia6; - ip6 = mtod(m, struct ip6_hdr *); - ia6 = in6_ifawithifp(ifp, &ip6->ip6_src); - if (ia6) { - ia->ia_ifa.ifa_data.ifad_outbytes += - m->m_pkthdr.len; - } - } + /* Record statistics for this interface address. */ + if (ia) { +#ifndef __APPLE__ + ia->ia_ifa.if_opackets++; + ia->ia_ifa.if_obytes += m->m_pkthdr.len; #endif -#if OLDIP6OUTPUT - error = (*ifp->if_output)(ifp, m, - (struct sockaddr *)dst, - ro->ro_rt); -#else - error = nd6_output(ifp, m, dst, ro->ro_rt); + } +#if IPSEC + /* clean ipsec history once it goes out of the node */ + ipsec_delaux(m); #endif + error = nd6_output(ifp, origifp, m, dst, ro->ro_rt); } else m_freem(m); } @@ -1081,10 +1043,10 @@ sendorfree: ip6stat.ip6s_fragmented++; done: - if (ro == &ip6route && ro->ro_rt) { /* brace necessary for RTFREE */ - RTFREE(ro->ro_rt); + if (ro == &ip6route && ro->ro_rt) { /* brace necessary for rtfree */ + rtfree(ro->ro_rt); } else if (ro_pmtu == &ip6route && ro_pmtu->ro_rt) { - RTFREE(ro_pmtu->ro_rt); + rtfree(ro_pmtu->ro_rt); } #if IPSEC @@ -1145,6 +1107,7 @@ ip6_insert_jumboopt(exthdrs, plen) { struct mbuf *mopt; u_char *optbuf; + u_int32_t v; #define JUMBOOPTLEN 8 /* length of jumbo payload option and padding */ @@ -1167,18 +1130,42 @@ ip6_insert_jumboopt(exthdrs, plen) mopt = exthdrs->ip6e_hbh; if (M_TRAILINGSPACE(mopt) < JUMBOOPTLEN) { - caddr_t oldoptp = mtod(mopt, caddr_t); + /* + * XXX assumption: + * - exthdrs->ip6e_hbh is not referenced from places + * other than exthdrs. + * - exthdrs->ip6e_hbh is not an mbuf chain. + */ int oldoptlen = mopt->m_len; + struct mbuf *n; - if (mopt->m_flags & M_EXT) - return(ENOBUFS); /* XXX */ - MCLGET(mopt, M_DONTWAIT); - if ((mopt->m_flags & M_EXT) == 0) + /* + * XXX: give up if the whole (new) hbh header does + * not fit even in an mbuf cluster. + */ + if (oldoptlen + JUMBOOPTLEN > MCLBYTES) return(ENOBUFS); - bcopy(oldoptp, mtod(mopt, caddr_t), oldoptlen); - optbuf = mtod(mopt, caddr_t) + oldoptlen; - mopt->m_len = oldoptlen + JUMBOOPTLEN; + /* + * As a consequence, we must always prepare a cluster + * at this point. + */ + MGET(n, M_DONTWAIT, MT_DATA); + if (n) { + MCLGET(n, M_DONTWAIT); + if ((n->m_flags & M_EXT) == 0) { + m_freem(n); + n = NULL; + } + } + if (!n) + return(ENOBUFS); + n->m_len = oldoptlen + JUMBOOPTLEN; + bcopy(mtod(mopt, caddr_t), mtod(n, caddr_t), + oldoptlen); + optbuf = mtod(n, caddr_t) + oldoptlen; + m_freem(mopt); + mopt = exthdrs->ip6e_hbh = n; } else { optbuf = mtod(mopt, u_char *) + mopt->m_len; mopt->m_len += JUMBOOPTLEN; @@ -1197,7 +1184,8 @@ ip6_insert_jumboopt(exthdrs, plen) /* fill in the option. */ optbuf[2] = IP6OPT_JUMBO; optbuf[3] = 4; - *(u_int32_t *)&optbuf[4] = htonl(plen + JUMBOOPTLEN); + v = (u_int32_t)htonl(plen + JUMBOOPTLEN); + bcopy(&v, &optbuf[4], sizeof(u_int32_t)); /* finally, adjust the packet header length */ exthdrs->ip6e_ip6->m_pkthdr.len += JUMBOOPTLEN; @@ -1231,7 +1219,7 @@ ip6_insertfraghdr(m0, m, hlen, frghdrp) ; if ((mlast->m_flags & M_EXT) == 0 && - M_TRAILINGSPACE(mlast) < sizeof(struct ip6_frag)) { + M_TRAILINGSPACE(mlast) >= sizeof(struct ip6_frag)) { /* use the trailing space of the last mbuf for the fragment hdr */ *frghdrp = (struct ip6_frag *)(mtod(mlast, caddr_t) + mlast->m_len); @@ -1255,25 +1243,13 @@ ip6_insertfraghdr(m0, m, hlen, frghdrp) /* * IP6 socket option processing. */ -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) int ip6_ctloutput(so, sopt) struct socket *so; struct sockopt *sopt; -#else -int -ip6_ctloutput(op, so, level, optname, mp) - int op; - struct socket *so; - int level, optname; - struct mbuf **mp; -#endif { - int privileged, optdatalen; - void *optdata; - struct ip6_recvpktopts *rcvopts; -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) - register struct inpcb *in6p = sotoinpcb(so); + int privileged; + struct inpcb *in6p = sotoinpcb(so); int error, optval; int level, op, optname; int optlen; @@ -1288,73 +1264,31 @@ ip6_ctloutput(op, so, level, optname, mp) } else { panic("ip6_ctloutput: arg soopt is NULL"); } -#else -#if HAVE_NRL_INPCB - register struct inpcb *inp = sotoinpcb(so); -#else - register struct in6pcb *in6p = sotoin6pcb(so); -#endif - register struct mbuf *m = *mp; - int error, optval; - int optlen; -#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) && !defined (__APPLE__) - struct proc *p = curproc; /* XXX */ -#endif - - optlen = m ? m->m_len : 0; -#endif error = optval = 0; -#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) && !defined (__APPLE__) privileged = (p == 0 || suser(p->p_ucred, &p->p_acflag)) ? 0 : 1; -#else -#if HAVE_NRL_INPCB - privileged = (inp->inp_socket->so_state & SS_PRIV); -#else - privileged = (in6p->in6p_socket->so_state & SS_PRIV); -#endif -#endif - -#if defined(HAVE_NRL_INPCB) - rcvopts = inp->inp_inputopts6; -#else - rcvopts = in6p->in6p_inputopts; -#endif if (level == IPPROTO_IPV6) { switch (op) { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) case SOPT_SET: -#else - case PRCO_SETOPT: -#endif switch (optname) { case IPV6_PKTOPTIONS: - { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) + { struct mbuf *m; - error = sooptgetm(sopt, &m); /* XXX */ + error = soopt_getm(sopt, &m); /* XXX */ if (error != NULL) break; - error = sooptmcopyin(sopt, m); /* XXX */ + error = soopt_mcopyin(sopt, m); /* XXX */ if (error != NULL) break; error = ip6_pcbopts(&in6p->in6p_outputopts, m, so, sopt); m_freem(m); /* XXX */ -#else -#if HAVE_NRL_INPCB - error = ip6_pcbopts(&inp->inp_outputopts6, - m, so); -#else - error = ip6_pcbopts(&in6p->in6p_outputopts, - m, so); -#endif /* HAVE_NRL_INPCB */ -#endif /* FreeBSD >= 3 */ break; } + /* * Use of some Hop-by-Hop options or some * Destination options, might require special @@ -1368,244 +1302,110 @@ ip6_ctloutput(op, so, level, optname, mp) * receiving ANY hbh/dst options in order to avoid * overhead of parsing options in the kernel. */ - case IPV6_RECVHOPOPTS: - case IPV6_RECVDSTOPTS: - case IPV6_RECVRTHDRDSTOPTS: - if (!privileged) { - error = EPERM; - break; - } - /* fall through */ case IPV6_UNICAST_HOPS: - case IPV6_HOPLIMIT: case IPV6_CHECKSUM: case IPV6_FAITH: - case IPV6_RECVPKTINFO: - case IPV6_RECVHOPLIMIT: - case IPV6_RECVRTHDR: - case IPV6_USE_MIN_MTU: -#ifdef notyet /* To be implemented */ - case IPV6_RECVPATHMTU: -#endif -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) - case IPV6_BINDV6ONLY: -#endif - if (optlen != sizeof(int)) + case IPV6_V6ONLY: + if (optlen != sizeof(int)) { error = EINVAL; - else { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) - error = sooptcopyin(sopt, &optval, - sizeof optval, sizeof optval); - if (error) - break; -#else - optval = *mtod(m, int *); -#endif - switch (optname) { - - case IPV6_UNICAST_HOPS: - if (optval < -1 || optval >= 256) - error = EINVAL; - else { - /* -1 = kernel default */ -#if HAVE_NRL_INPCB - inp->inp_hops = optval; -#else - in6p->in6p_hops = optval; + break; + } + error = sooptcopyin(sopt, &optval, + sizeof optval, sizeof optval); + if (error) + break; + switch (optname) { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) - if ((in6p->in6p_vflag & - INP_IPV4) != 0) - in6p->inp_ip_ttl = optval; -#endif -#endif - } - break; -#if HAVE_NRL_INPCB -#define OPTSET(bit) \ - if (optval) \ - inp->inp_flags |= (bit); \ - else \ - inp->inp_flags &= ~(bit); -#else + case IPV6_UNICAST_HOPS: + if (optval < -1 || optval >= 256) + error = EINVAL; + else { + /* -1 = kernel default */ + in6p->in6p_hops = optval; + + if ((in6p->in6p_vflag & + INP_IPV4) != 0) + in6p->inp_ip_ttl = optval; + } + break; #define OPTSET(bit) \ +do { \ if (optval) \ in6p->in6p_flags |= (bit); \ else \ - in6p->in6p_flags &= ~(bit); -#endif -#if HAVE_NRL_INPCB -#define OPTBIT(bit) (inp->inp_flags & (bit) ? 1 : 0) -#else + in6p->in6p_flags &= ~(bit); \ +} while (0) #define OPTBIT(bit) (in6p->in6p_flags & (bit) ? 1 : 0) -#endif - - case IPV6_RECVPKTINFO: - OPTSET(IN6P_PKTINFO); - if (OPTBIT(IN6P_PKTINFO) == 0) - ip6_reset_rcvopt(rcvopts, IPV6_RECVPKTINFO); - break; - - case IPV6_HOPLIMIT: - { -#if COMPAT_RFC2292 - OPTSET(IN6P_HOPLIMIT); - if (OPTBIT(IN6P_HOPLIMIT) == 0) - ip6_reset_rcvopt(rcvopts, IPV6_RECVHOPLIMIT); - break; -#else /* new advanced API (2292bis) */ - struct ip6_pktopts **optp; -#if HAVE_NRL_INPCB - optp = &inp->inp_outputopts6; -#else - optp = &in6p->in6p_outputopts; -#endif - error = ip6_pcbopt(IPV6_HOPLIMIT, - (u_char *)&optval, - sizeof(optval), - optp, - privileged); - break; -#endif - } - - case IPV6_RECVHOPLIMIT: - OPTSET(IN6P_HOPLIMIT); - if (OPTBIT(IN6P_HOPLIMIT) == 0) - ip6_reset_rcvopt(rcvopts, IPV6_RECVHOPLIMIT); - break; - - case IPV6_RECVHOPOPTS: - OPTSET(IN6P_HOPOPTS); - if (OPTBIT(IN6P_HOPOPTS) == 0) - ip6_reset_rcvopt(rcvopts, IPV6_RECVHOPOPTS); - break; - - case IPV6_RECVDSTOPTS: - OPTSET(IN6P_DSTOPTS); - if (OPTBIT(IN6P_DSTOPTS) == 0) - ip6_reset_rcvopt(rcvopts, IPV6_RECVDSTOPTS); - break; - - case IPV6_RECVRTHDRDSTOPTS: - OPTSET(IN6P_RTHDRDSTOPTS); - if (OPTBIT(IN6P_RTHDRDSTOPTS) == 0) - ip6_reset_rcvopt(rcvopts, IPV6_RECVRTHDRDSTOPTS); - break; - - case IPV6_RECVRTHDR: - OPTSET(IN6P_RTHDR); - if (OPTBIT(IN6P_RTHDR) == 0) - ip6_reset_rcvopt(rcvopts, IPV6_RECVRTHDR); - break; - - case IPV6_CHECKSUM: -#if HAVE_NRL_INPCB - inp->inp_csumoffset = optval; -#else - in6p->in6p_cksum = optval; -#endif - break; - - case IPV6_FAITH: - OPTSET(IN6P_FAITH); - break; + case IPV6_CHECKSUM: + in6p->in6p_cksum = optval; + break; - case IPV6_USE_MIN_MTU: - OPTSET(IN6P_MINMTU); - break; + case IPV6_FAITH: + OPTSET(IN6P_FAITH); + break; -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || (defined(__NetBSD__) && !defined(INET6_BINDV6ONLY)) || defined (__APPLE__) - case IPV6_BINDV6ONLY: - OPTSET(IN6P_BINDV6ONLY); + case IPV6_V6ONLY: + /* + * make setsockopt(IPV6_V6ONLY) + * available only prior to bind(2). + * see ipng mailing list, Jun 22 2001. + */ + if (in6p->in6p_lport || + !IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) + { + error = EINVAL; break; -#endif } + /* + * XXX: BINDV6ONLY should be integrated + * into V6ONLY. + */ + OPTSET(IN6P_BINDV6ONLY); + OPTSET(IN6P_IPV6_V6ONLY); + break; } break; + case IPV6_PKTINFO: + case IPV6_HOPLIMIT: case IPV6_HOPOPTS: - case IPV6_RTHDR: case IPV6_DSTOPTS: - case IPV6_RTHDRDSTOPTS: - if (optlen == sizeof(int)) { - /* RFC 2292 */ -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) - error = sooptcopyin(sopt, &optval, - sizeof optval, sizeof optval); - if (error == 0) - break; -#else - optval = *mtod(m, int *); -#endif - switch(optname) { - case IPV6_PKTINFO: - OPTSET(IN6P_PKTINFO); - if (OPTBIT(IN6P_PKTINFO) == 0) - ip6_reset_rcvopt(rcvopts, IPV6_RECVPKTINFO); - break; - case IPV6_HOPOPTS: - /* - * Check super-user privilege. - * See comments for - * IPV6_RECVHOPOPTS. - */ - if (!privileged) - return(EPERM); - OPTSET(IN6P_HOPOPTS); - if (OPTBIT(IN6P_HOPOPTS) == 0) - ip6_reset_rcvopt(rcvopts, IPV6_RECVHOPOPTS); - break; - case IPV6_DSTOPTS: - if (!privileged) - return(EPERM); - OPTSET(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS); /* XXX */ - if (OPTBIT(IN6P_DSTOPTS) == 0) { - ip6_reset_rcvopt(rcvopts, IPV6_RECVDSTOPTS); - ip6_reset_rcvopt(rcvopts, IPV6_RECVRTHDRDSTOPTS); - } - break; - case IPV6_RTHDR: - OPTSET(IN6P_RTHDR); - if (OPTBIT(IN6P_RTHDR) == 0) - ip6_reset_rcvopt(rcvopts, IPV6_RECVRTHDR); - break; - } + case IPV6_RTHDR: + /* RFC 2292 */ + if (optlen != sizeof(int)) { + error = EINVAL; + break; + } + error = sooptcopyin(sopt, &optval, + sizeof optval, sizeof optval); + if (error) + break; + switch (optname) { + case IPV6_PKTINFO: + OPTSET(IN6P_PKTINFO); + break; + case IPV6_HOPLIMIT: + OPTSET(IN6P_HOPLIMIT); + break; + case IPV6_HOPOPTS: + /* + * Check super-user privilege. + * See comments for IPV6_RECVHOPOPTS. + */ + if (!privileged) + return(EPERM); + OPTSET(IN6P_HOPOPTS); + break; + case IPV6_DSTOPTS: + if (!privileged) + return(EPERM); + OPTSET(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS); /* XXX */ + break; + case IPV6_RTHDR: + OPTSET(IN6P_RTHDR); break; - } else { - /* new advanced API (2292bis) */ - u_char *optbuf; - int optlen; - struct ip6_pktopts **optp; - -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) - optbuf = sopt->sopt_val; - optlen = sopt->sopt_valsize; -#else /* !fbsd3 */ - if (m && m->m_next) { - error = EINVAL; /* XXX */ - break; - } - if (m) { - optbuf = mtod(m, u_char *); - optlen = m->m_len; - } else { - optbuf = NULL; - optlen = 0; - } -#endif - -#if HAVE_NRL_INPCB - optp = &inp->inp_outputopts6; -#else - optp = &in6p->in6p_outputopts; -#endif - - error = ip6_pcbopt(optname, - optbuf, optlen, - optp, privileged); } break; #undef OPTSET @@ -1615,7 +1415,6 @@ ip6_ctloutput(op, so, level, optname, mp) case IPV6_MULTICAST_LOOP: case IPV6_JOIN_GROUP: case IPV6_LEAVE_GROUP: -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) { struct mbuf *m; if (sopt->sopt_valsize > MLEN) { @@ -1636,265 +1435,129 @@ ip6_ctloutput(op, so, level, optname, mp) m); (void)m_free(m); } -#else -#if HAVE_NRL_INPCB - error = ip6_setmoptions(optname, - &inp->inp_moptions6, m); - /* - * XXX: setting the flag would be redundant - * except at the first time. Also, we - * actually don't have to reset the flag, - * since ip6_freemoptions() would simply - * return when the inp_moptions6 is NULL. - */ - if (inp->inp_moptions6) - inp->inp_flags |= INP_IPV6_MCAST; - else - inp->inp_flags &= ~INP_IPV6_MCAST; -#else - error = ip6_setmoptions(optname, - &in6p->in6p_moptions, m); -#endif -#endif break; -#ifndef __bsdi__ - case IPV6_PORTRANGE: -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) - error = sooptcopyin(sopt, &optval, sizeof optval, - sizeof optval); - if (error) - break; -#else - optval = *mtod(m, int *); -#endif + case IPV6_PORTRANGE: + error = sooptcopyin(sopt, &optval, + sizeof optval, sizeof optval); + if (error) + break; -#if HAVE_NRL_INPCB -# define in6p inp -# define in6p_flags inp_flags -#endif - switch (optval) { - case IPV6_PORTRANGE_DEFAULT: - in6p->in6p_flags &= ~(IN6P_LOWPORT); - in6p->in6p_flags &= ~(IN6P_HIGHPORT); - break; + switch (optval) { + case IPV6_PORTRANGE_DEFAULT: + in6p->in6p_flags &= ~(IN6P_LOWPORT); + in6p->in6p_flags &= ~(IN6P_HIGHPORT); + break; - case IPV6_PORTRANGE_HIGH: - in6p->in6p_flags &= ~(IN6P_LOWPORT); - in6p->in6p_flags |= IN6P_HIGHPORT; - break; + case IPV6_PORTRANGE_HIGH: + in6p->in6p_flags &= ~(IN6P_LOWPORT); + in6p->in6p_flags |= IN6P_HIGHPORT; + break; - case IPV6_PORTRANGE_LOW: - in6p->in6p_flags &= ~(IN6P_HIGHPORT); - in6p->in6p_flags |= IN6P_LOWPORT; - break; + case IPV6_PORTRANGE_LOW: + in6p->in6p_flags &= ~(IN6P_HIGHPORT); + in6p->in6p_flags |= IN6P_LOWPORT; + break; - default: - error = EINVAL; + default: + error = EINVAL; + break; + } break; - } -#if HAVE_NRL_INPCB -# undef in6p -# undef in6p_flags -#endif - break; -#endif #if IPSEC case IPV6_IPSEC_POLICY: { caddr_t req = NULL; size_t len = 0; -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) struct mbuf *m; -#endif -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) - if (error = sooptgetm(sopt, &m)) /* XXX */ + if ((error = soopt_getm(sopt, &m)) != 0) /* XXX */ break; - if (error = sooptmcopyin(sopt, m)) /* XXX */ + if (error = soopt_mcopyin(sopt, m)) /* XXX */ break; -#endif if (m) { req = mtod(m, caddr_t); len = m->m_len; } -#if HAVE_NRL_INPCB - error = ipsec6_set_policy(inp, optname, req, - len, privileged); -#else error = ipsec6_set_policy(in6p, optname, req, len, privileged); -#endif -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) m_freem(m); -#endif } break; -#endif /* IPSEC */ +#endif /* KAME IPSEC */ -#if IPV6FIREWALL case IPV6_FW_ADD: case IPV6_FW_DEL: case IPV6_FW_FLUSH: case IPV6_FW_ZERO: { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) struct mbuf *m; struct mbuf **mp = &m; -#endif -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) if (ip6_fw_ctl_ptr == NULL) return EINVAL; - if (error = sooptgetm(sopt, &m)) /* XXX */ + /* XXX */ + if ((error = soopt_getm(sopt, &m)) != 0) break; - if (error = sooptmcopyin(sopt, m)) /* XXX */ + /* XXX */ + if ((error = soopt_mcopyin(sopt, m)) != 0) break; -#else - if (ip6_fw_ctl_ptr == NULL) { - if (m) (void)m_free(m); - return EINVAL; - } -#endif error = (*ip6_fw_ctl_ptr)(optname, mp); m = *mp; } break; -#endif default: error = ENOPROTOOPT; break; } -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__APPLE__) - if (m) - (void)m_free(m); -#endif break; -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) case SOPT_GET: -#else - case PRCO_GETOPT: -#endif switch (optname) { case IPV6_PKTOPTIONS: -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) - if (in6p->in6p_inputopts && - in6p->in6p_inputopts->head) { - error = sooptmcopyout(sopt, - in6p->in6p_inputopts->head); + if (in6p->in6p_options) { + struct mbuf *m; + m = m_copym(in6p->in6p_options, + 0, M_COPYALL, M_WAIT); + error = soopt_mcopyout(sopt, m); + if (error == 0) + m_freem(m); } else sopt->sopt_valsize = 0; -#elif defined(HAVE_NRL_INPCB) - if (inp->inp_options) { - *mp = m_copym(inp->inp_options, 0, - M_COPYALL, M_WAIT); - } else { - *mp = m_get(M_WAIT, MT_SOOPTS); - (*mp)->m_len = 0; - } -#else - if (in6p->in6p_inputopts && - in6p->in6p_inputopts->head) { - *mp = m_copym(in6p->in6p_inputopts->head, - 0, M_COPYALL, M_WAIT); - } else { - *mp = m_get(M_WAIT, MT_SOOPTS); - (*mp)->m_len = 0; - } -#endif break; - case IPV6_RECVHOPOPTS: - case IPV6_RECVDSTOPTS: - case IPV6_RECVRTHDRDSTOPTS: - if (!privileged) { - error = EPERM; - break; - } - /* fall through */ case IPV6_UNICAST_HOPS: case IPV6_CHECKSUM: - case IPV6_RECVPKTINFO: - case IPV6_RECVHOPLIMIT: - case IPV6_RECVRTHDR: - case IPV6_USE_MIN_MTU: -#ifdef notyet /* To be implemented */ - case IPV6_RECVPATHMTU: -#endif - case IPV6_FAITH: -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || (defined(__NetBSD__) && !defined(INET6_BINDV6ONLY)) || defined(__APPLE__) - case IPV6_BINDV6ONLY: -#endif -#ifndef __bsdi__ + case IPV6_V6ONLY: case IPV6_PORTRANGE: -#endif switch (optname) { case IPV6_UNICAST_HOPS: -#if HAVE_NRL_INPCB - optval = inp->inp_hops; -#else optval = in6p->in6p_hops; -#endif - break; - - case IPV6_RECVPKTINFO: - optval = OPTBIT(IN6P_PKTINFO); - break; - - case IPV6_RECVHOPLIMIT: - optval = OPTBIT(IN6P_HOPLIMIT); - break; - - case IPV6_RECVHOPOPTS: - optval = OPTBIT(IN6P_HOPOPTS); - break; - - case IPV6_RECVDSTOPTS: - optval = OPTBIT(IN6P_DSTOPTS); - break; - - case IPV6_RECVRTHDRDSTOPTS: - optval = OPTBIT(IN6P_RTHDRDSTOPTS); break; case IPV6_CHECKSUM: -#if HAVE_NRL_INPCB - optval = inp->inp_csumoffset; -#else optval = in6p->in6p_cksum; -#endif - break; - - case IPV6_USE_MIN_MTU: - optval = OPTBIT(IN6P_MINMTU); break; case IPV6_FAITH: optval = OPTBIT(IN6P_FAITH); break; -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || (defined(__NetBSD__) && !defined(INET6_BINDV6ONLY)) || defined (__APPLE__) - case IPV6_BINDV6ONLY: + case IPV6_V6ONLY: + /* XXX: see the setopt case. */ optval = OPTBIT(IN6P_BINDV6ONLY); break; -#endif -#ifndef __bsdi__ case IPV6_PORTRANGE: { int flags; -#if HAVE_NRL_INPCB - flags = inp->inp_flags; -#else flags = in6p->in6p_flags; -#endif if (flags & IN6P_HIGHPORT) optval = IPV6_PORTRANGE_HIGH; else if (flags & IN6P_LOWPORT) @@ -1903,84 +1566,43 @@ ip6_ctloutput(op, so, level, optname, mp) optval = 0; break; } -#endif } -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) error = sooptcopyout(sopt, &optval, sizeof optval); -#else - *mp = m = m_get(M_WAIT, MT_SOOPTS); - m->m_len = sizeof(int); - *mtod(m, int *) = optval; -#endif break; case IPV6_PKTINFO: + case IPV6_HOPLIMIT: case IPV6_HOPOPTS: case IPV6_RTHDR: case IPV6_DSTOPTS: - case IPV6_RTHDRDSTOPTS: -#if COMPAT_RFC2292 if (optname == IPV6_HOPOPTS || optname == IPV6_DSTOPTS || !privileged) return(EPERM); - switch(optname) { + switch (optname) { case IPV6_PKTINFO: - optbit = OPTBIT(IN6P_PKTINFO); + optval = OPTBIT(IN6P_PKTINFO); break; case IPV6_HOPLIMIT: optval = OPTBIT(IN6P_HOPLIMIT); break; case IPV6_HOPOPTS: - optbit = OPTBIT(IN6P_HOPOPTS); + if (!privileged) + return(EPERM); + optval = OPTBIT(IN6P_HOPOPTS); break; case IPV6_RTHDR: - optbit = OPTBIT(IN6P_RTHDR); + optval = OPTBIT(IN6P_RTHDR); break; case IPV6_DSTOPTS: - optbit = OPTBIT(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS); + if (!privileged) + return(EPERM); + optval = OPTBIT(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS); break; - case IPV6_RTHDRDSTOPTS: /* in 2292bis only */ - return(EOPNOTSUPP); } -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) error = sooptcopyout(sopt, &optval, sizeof optval); -#else - *mp = m = m_get(M_WAIT, MT_SOOPTS); - m->m_len = sizeof(int); - *mtod(m, int *) = optval; -#endif /* FreeBSD3 */ -#else /* new advanced API */ -#if HAVE_NRL_INPCB -#define in6p inp -#define in6p_outputopts inp_outputopts6 -#endif - error = ip6_getpcbopt(in6p->in6p_outputopts, - optname, &optdata, - &optdatalen); - if (error == 0) { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) - /* note that optdatalen maybe 0 */ - error = sooptcopyout(sopt, optdata, - optdatalen); -#else /* !FreeBSD3 */ - if (optdatalen > MCLBYTES) - return(EMSGSIZE); /* XXX */ - *mp = m = m_get(M_WAIT, MT_SOOPTS); - if (optdatalen > MLEN) - MCLGET(m, M_WAIT); - m->m_len = optdatalen; - bcopy(optdata, mtod(m, void *), - optdatalen); -#endif /* FreeBSD3 */ - } -#if HAVE_NRL_INPCB -#undef in6p -#undef in6p_outputopts -#endif -#endif /* COMPAT_RFC2292 */ break; case IPV6_MULTICAST_IF: @@ -1988,7 +1610,6 @@ ip6_ctloutput(op, so, level, optname, mp) case IPV6_MULTICAST_LOOP: case IPV6_JOIN_GROUP: case IPV6_LEAVE_GROUP: -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) { struct mbuf *m; error = ip6_getmoptions(sopt->sopt_name, @@ -1998,11 +1619,6 @@ ip6_ctloutput(op, so, level, optname, mp) mtod(m, char *), m->m_len); m_freem(m); } -#elif defined(HAVE_NRL_INPCB) - error = ip6_getmoptions(optname, inp->inp_moptions6, mp); -#else - error = ip6_getmoptions(optname, in6p->in6p_moptions, mp); -#endif break; #if IPSEC @@ -2010,61 +1626,44 @@ ip6_ctloutput(op, so, level, optname, mp) { caddr_t req = NULL; size_t len = 0; -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) struct mbuf *m = NULL; struct mbuf **mp = &m; - error = sooptgetm(sopt, &m); /* XXX */ + error = soopt_getm(sopt, &m); /* XXX */ if (error != NULL) break; - error = sooptmcopyin(sopt, m); /* XXX */ + error = soopt_mcopyin(sopt, m); /* XXX */ if (error != NULL) break; -#endif if (m) { req = mtod(m, caddr_t); len = m->m_len; } -#if HAVE_NRL_INPCB - error = ipsec6_get_policy(inp, req, len, mp); -#else error = ipsec6_get_policy(in6p, req, len, mp); -#endif -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) if (error == 0) - error = sooptmcopyout(sopt, m); /*XXX*/ - m_freem(m); -#endif + error = soopt_mcopyout(sopt, m); /*XXX*/ + if (error == 0 && m) + m_freem(m); break; } -#endif /* IPSEC */ +#endif /* KAME IPSEC */ -#if IPV6FIREWALL case IPV6_FW_GET: { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) struct mbuf *m; struct mbuf **mp = &m; -#endif if (ip6_fw_ctl_ptr == NULL) { -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__) - if (m) - (void)m_free(m); -#endif return EINVAL; } error = (*ip6_fw_ctl_ptr)(optname, mp); -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) if (error == 0) - error = sooptmcopyout(sopt, m); /* XXX */ - if (m) + error = soopt_mcopyout(sopt, m); /* XXX */ + if (error == 0 && m) m_freem(m); -#endif } break; -#endif default: error = ENOPROTOOPT; @@ -2074,10 +1673,6 @@ ip6_ctloutput(op, so, level, optname, mp) } } else { error = EINVAL; -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__APPLE__) - if (op == PRCO_SETOPT && *mp) - (void)m_free(*mp); -#endif } return(error); } @@ -2087,38 +1682,27 @@ ip6_ctloutput(op, so, level, optname, mp) * specifying behavior of outgoing packets. */ static int -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) ip6_pcbopts(pktopt, m, so, sopt) -#else -ip6_pcbopts(pktopt, m, so) -#endif struct ip6_pktopts **pktopt; - register struct mbuf *m; + struct mbuf *m; struct socket *so; -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) struct sockopt *sopt; -#endif { - register struct ip6_pktopts *opt = *pktopt; + struct ip6_pktopts *opt = *pktopt; int error = 0; -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) struct proc *p = sopt->sopt_p; -#else - struct proc *p = curproc; /* XXX */ -#endif int priv = 0; /* turn off any old options. */ if (opt) { #if DIAGNOSTIC - if (opt->ip6po_pktinfo || opt->ip6po_nexthop || - opt->ip6po_hbh || opt->ip6po_dest1 || opt->ip6po_dest2 || - opt->ip6po_rhinfo.ip6po_rhi_rthdr) - printf("ip6_pcbopts: all specified options are cleared.\n"); + if (opt->ip6po_pktinfo || opt->ip6po_nexthop || + opt->ip6po_hbh || opt->ip6po_dest1 || opt->ip6po_dest2 || + opt->ip6po_rhinfo.ip6po_rhi_rthdr) + printf("ip6_pcbopts: all specified options are cleared.\n"); #endif ip6_clearpktopts(opt, 1, -1); - } - else + } else opt = _MALLOC(sizeof(*opt), M_IP6OPT, M_WAITOK); *pktopt = NULL; @@ -2127,15 +1711,13 @@ ip6_pcbopts(pktopt, m, so) * Only turning off any previous options. */ if (opt) - _FREE(opt, M_IP6OPT); + FREE(opt, M_IP6OPT); return(0); } /* set options specified by user. */ -#if 0 if (p && !suser(p->p_ucred, &p->p_acflag)) priv = 1; -#endif if ((error = ip6_setpktoptions(m, opt, priv, 1)) != 0) { ip6_clearpktopts(opt, 1, -1); /* XXX: discard all options */ return(error); @@ -2145,288 +1727,16 @@ ip6_pcbopts(pktopt, m, so) } /* - * Set up an IP6 option in pcb for insertion in output packets or - * specifying behavior of outgoing packets. - * XXX: The logic of this function is very similar to ip6_setpktoptions(). + * initialize ip6_pktopts. beware that there are non-zero default values in + * the struct. */ -static int -ip6_pcbopt(optname, buf, len, pktopt, priv) - int optname, len, priv; - u_char *buf; - struct ip6_pktopts **pktopt; -{ +void +init_ip6pktopts(opt) struct ip6_pktopts *opt; - struct in6_pktinfo *pktinfo; - - if (*pktopt == NULL) { - *pktopt = _MALLOC(sizeof(struct ip6_pktopts), M_IP6OPT, - M_WAITOK); - bzero(*pktopt, sizeof(struct ip6_pktopts)); - (*pktopt)->ip6po_hlim = -1; - } - opt = *pktopt; - - switch(optname) { - case IPV6_PKTINFO: - if (len == 0) { /* just remove the option */ - ip6_clearpktopts(opt, 1, IPV6_PKTINFO); - break; - } - - if (len != sizeof(struct in6_pktinfo)) - return EINVAL; - pktinfo = (struct in6_pktinfo *)buf; - - /* - * An application can clear any sticky IPV6_PKTINFO option by - * doing a "regular" setsockopt with ipi6_addr being - * in6addr_any and ipi6_ifindex being zero. - * [rfc2292bis-01, Section 6] - * XXX: Is this a good feature?? (jinmei@kame.net) - */ - if (pktinfo->ipi6_ifindex == 0 && - IN6_IS_ADDR_UNSPECIFIED(&pktinfo->ipi6_addr)) { - ip6_clearpktopts(opt, 1, IPV6_PKTINFO); - break; - } - - /* XXX: this overrides the original data space */ - if (pktinfo->ipi6_ifindex && - IN6_IS_ADDR_LINKLOCAL(&pktinfo->ipi6_addr)) - pktinfo->ipi6_addr.s6_addr16[1] = - htons(pktinfo->ipi6_ifindex); - - if (pktinfo->ipi6_ifindex > if_index || - pktinfo->ipi6_ifindex < 0) - return(ENXIO); - - /* - * Check if the requested source address is indeed a unicast - * address assigned to the node. - */ - if (!IN6_IS_ADDR_UNSPECIFIED(&pktinfo->ipi6_addr)) { - struct ifaddr *ia; - struct sockaddr_in6 sin6; - - bzero(&sin6, sizeof(sin6)); - sin6.sin6_len = sizeof(sin6); - sin6.sin6_family = AF_INET6; - sin6.sin6_addr = pktinfo->ipi6_addr; - ia = ifa_ifwithaddr(sin6tosa(&sin6)); - if (ia == NULL) - return(EADDRNOTAVAIL); - } - - if (opt->ip6po_pktinfo == NULL) - opt->ip6po_pktinfo = _MALLOC(sizeof(struct in6_pktinfo), - M_IP6OPT, M_WAITOK); - bcopy(pktinfo, opt->ip6po_pktinfo, sizeof(*pktinfo)); - - break; - case IPV6_HOPLIMIT: - { - int *hlimp; - - if (len != sizeof(int)) - return(EINVAL); - hlimp = (int *)buf; - if (*hlimp < -1 || *hlimp > 255) - return(EINVAL); - - opt->ip6po_hlim = *hlimp; - break; - } - case IPV6_NEXTHOP: - if (!priv) - return(EPERM); - - if (len == 0) { /* just remove the option */ - ip6_clearpktopts(opt, 1, IPV6_NEXTHOP); - break; - } - - /* check if cmsg_len is large enough for sa_len */ - if (len < sizeof(u_char) || - len < *buf) - return(EINVAL); - - /* turn off the previous option */ - ip6_clearpktopts(opt, 1, IPV6_NEXTHOP); - - opt->ip6po_nexthop = _MALLOC(*buf, M_IP6OPT, M_WAITOK); - bcopy(buf, opt->ip6po_nexthop, *buf); - break; - case IPV6_HOPOPTS: - { - struct ip6_hbh *hbh; - int hbhlen; - - /* - * XXX: We don't allow a non-privileged user to set ANY HbH - * options, since per-option restriction has too much - * overhead. - */ - if (!priv) - return(EPERM); - - if (len == 0) { - ip6_clearpktopts(opt, 1, IPV6_HOPOPTS); - break; /* just remove the option */ - } - - if (len < sizeof(struct ip6_hbh)) - return(EINVAL); - hbh = (struct ip6_hbh *)buf; - hbhlen = (hbh->ip6h_len + 1) << 3; - if (len != hbhlen) - return(EINVAL); - - /* turn off the previous option */ - ip6_clearpktopts(opt, 1, IPV6_HOPOPTS); - - opt->ip6po_hbh = _MALLOC(hbhlen, M_IP6OPT, M_WAITOK); - bcopy(buf, opt->ip6po_hbh, hbhlen); - - break; - } - case IPV6_DSTOPTS: - case IPV6_RTHDRDSTOPTS: - { - struct ip6_dest *dest, *newdest; - int destlen; - - if (!priv) /* XXX: see the comment for IPV6_HOPOPTS */ - return(EPERM); - - if (len == 0) { - ip6_clearpktopts(opt, 1, optname); - break; /* just remove the option */ - } - - if (len < sizeof(struct ip6_dest)) - return(EINVAL); - dest = (struct ip6_dest *)buf; - destlen = (dest->ip6d_len + 1) << 3; - if (len != destlen) - return(EINVAL); - - /* turn off the previous option */ - ip6_clearpktopts(opt, 1, optname); - - newdest = _MALLOC(destlen, M_IP6OPT, M_WAITOK); - bcopy(buf, newdest, destlen); - - if (optname == IPV6_DSTOPTS) - opt->ip6po_dest2 = newdest; - else - opt->ip6po_dest1 = newdest; - - break; - } - case IPV6_RTHDR: - { - struct ip6_rthdr *rth; - int rthlen; - - if (len == 0) { - ip6_clearpktopts(opt, 1, IPV6_RTHDR); - break; /* just remove the option */ - } - - if (len < sizeof(struct ip6_rthdr)) - return(EINVAL); - rth = (struct ip6_rthdr *)buf; - rthlen = (rth->ip6r_len + 1) << 3; - if (len != rthlen) - return(EINVAL); - - switch(rth->ip6r_type) { - case IPV6_RTHDR_TYPE_0: - if (rth->ip6r_len == 0) /* must contain one addr */ - return(EINVAL); - if (rth->ip6r_len % 2) /* length must be even */ - return(EINVAL); - if (rth->ip6r_len / 2 != rth->ip6r_segleft) - return(EINVAL); - break; - default: - return(EINVAL); /* not supported */ - } - - /* turn off the previous option */ - ip6_clearpktopts(opt, 1, IPV6_RTHDR); - - opt->ip6po_rthdr = _MALLOC(rthlen, M_IP6OPT, M_WAITOK); - bcopy(buf, opt->ip6po_rthdr, rthlen); - - break; - } - default: - return(ENOPROTOOPT); - } /* end of switch */ - - return(0); -} - -static int -ip6_getpcbopt(pktopt, optname, datap, datalenp) - struct ip6_pktopts *pktopt; - int optname, *datalenp; - void **datap; { - void *optdata = NULL; - struct ip6_ext *ip6e; - int optdatalen = 0; - if (pktopt == NULL) - goto end; - - switch(optname) { - case IPV6_PKTINFO: - if (pktopt->ip6po_pktinfo) { - optdata = (void *)pktopt->ip6po_pktinfo; - optdatalen = sizeof(struct in6_pktinfo); - } - break; - case IPV6_HOPLIMIT: - optdata = (void *)&pktopt->ip6po_hlim; - optdatalen = sizeof(int); - break; - case IPV6_HOPOPTS: - if (pktopt->ip6po_hbh) { - optdata = (void *)pktopt->ip6po_hbh; - ip6e = (struct ip6_ext *)pktopt->ip6po_hbh; - optdatalen = (ip6e->ip6e_len + 1) << 3; - } - break; - case IPV6_RTHDR: - if (pktopt->ip6po_rthdr) { - optdata = (void *)pktopt->ip6po_rthdr; - ip6e = (struct ip6_ext *)pktopt->ip6po_rthdr; - optdatalen = (ip6e->ip6e_len + 1) << 3; - } - break; - case IPV6_RTHDRDSTOPTS: - if (pktopt->ip6po_dest1) { - optdata = (void *)pktopt->ip6po_dest1; - ip6e = (struct ip6_ext *)pktopt->ip6po_dest1; - optdatalen = (ip6e->ip6e_len + 1) << 3; - } - break; - case IPV6_DSTOPTS: - if (pktopt->ip6po_dest2) { - optdata = (void *)pktopt->ip6po_dest2; - ip6e = (struct ip6_ext *)pktopt->ip6po_dest2; - optdatalen = (ip6e->ip6e_len + 1) << 3; - } - break; - } - - end: - *datap = optdata; - *datalenp = optdatalen; - - return(0); + bzero(opt, sizeof(*opt)); + opt->ip6po_hlim = -1; /* -1 means default hop limit */ } void @@ -2437,52 +1747,55 @@ ip6_clearpktopts(pktopt, needfree, optname) if (pktopt == NULL) return; - if (optname == -1 || optname == IPV6_PKTINFO) { + if (optname == -1) { if (needfree && pktopt->ip6po_pktinfo) - _FREE(pktopt->ip6po_pktinfo, M_IP6OPT); + FREE(pktopt->ip6po_pktinfo, M_IP6OPT); pktopt->ip6po_pktinfo = NULL; } - if (optname == -1 || optname == IPV6_HOPLIMIT) + if (optname == -1) pktopt->ip6po_hlim = -1; - if (optname == -1 || optname == IPV6_NEXTHOP) { + if (optname == -1) { if (needfree && pktopt->ip6po_nexthop) - _FREE(pktopt->ip6po_nexthop, M_IP6OPT); + FREE(pktopt->ip6po_nexthop, M_IP6OPT); pktopt->ip6po_nexthop = NULL; } - if (optname == -1 || optname == IPV6_HOPOPTS) { + if (optname == -1) { if (needfree && pktopt->ip6po_hbh) - _FREE(pktopt->ip6po_hbh, M_IP6OPT); + FREE(pktopt->ip6po_hbh, M_IP6OPT); pktopt->ip6po_hbh = NULL; } - if (optname == -1 || optname == IPV6_RTHDRDSTOPTS) { + if (optname == -1) { if (needfree && pktopt->ip6po_dest1) - _FREE(pktopt->ip6po_dest1, M_IP6OPT); + FREE(pktopt->ip6po_dest1, M_IP6OPT); pktopt->ip6po_dest1 = NULL; } - if (optname == -1 || optname == IPV6_RTHDR) { + if (optname == -1) { if (needfree && pktopt->ip6po_rhinfo.ip6po_rhi_rthdr) - _FREE(pktopt->ip6po_rhinfo.ip6po_rhi_rthdr, M_IP6OPT); + FREE(pktopt->ip6po_rhinfo.ip6po_rhi_rthdr, M_IP6OPT); pktopt->ip6po_rhinfo.ip6po_rhi_rthdr = NULL; if (pktopt->ip6po_route.ro_rt) { - RTFREE(pktopt->ip6po_route.ro_rt); + rtfree(pktopt->ip6po_route.ro_rt); pktopt->ip6po_route.ro_rt = NULL; } } - if (optname == -1 || optname == IPV6_DSTOPTS) { + if (optname == -1) { if (needfree && pktopt->ip6po_dest2) - _FREE(pktopt->ip6po_dest2, M_IP6OPT); + FREE(pktopt->ip6po_dest2, M_IP6OPT); pktopt->ip6po_dest2 = NULL; } } -#define PKTOPT_EXTHDRCPY(type) if (src->type) {\ +#define PKTOPT_EXTHDRCPY(type) \ +do {\ + if (src->type) {\ int hlen =\ (((struct ip6_ext *)src->type)->ip6e_len + 1) << 3;\ dst->type = _MALLOC(hlen, M_IP6OPT, canwait);\ if (dst->type == NULL && canwait == M_NOWAIT)\ goto bad;\ bcopy(src->type, dst->type, hlen);\ - } + }\ +} while (0) struct ip6_pktopts * ip6_copypktopts(src, canwait) @@ -2502,7 +1815,6 @@ ip6_copypktopts(src, canwait) bzero(dst, sizeof(*dst)); dst->ip6po_hlim = src->ip6po_hlim; - dst->ip6po_flags = src->ip6po_flags; if (src->ip6po_pktinfo) { dst->ip6po_pktinfo = _MALLOC(sizeof(*dst->ip6po_pktinfo), M_IP6OPT, canwait); @@ -2526,12 +1838,12 @@ ip6_copypktopts(src, canwait) bad: printf("ip6_copypktopts: copy failed"); - if (dst->ip6po_pktinfo) _FREE(dst->ip6po_pktinfo, M_IP6OPT); - if (dst->ip6po_nexthop) _FREE(dst->ip6po_nexthop, M_IP6OPT); - if (dst->ip6po_hbh) _FREE(dst->ip6po_hbh, M_IP6OPT); - if (dst->ip6po_dest1) _FREE(dst->ip6po_dest1, M_IP6OPT); - if (dst->ip6po_dest2) _FREE(dst->ip6po_dest2, M_IP6OPT); - if (dst->ip6po_rthdr) _FREE(dst->ip6po_rthdr, M_IP6OPT); + if (dst->ip6po_pktinfo) FREE(dst->ip6po_pktinfo, M_IP6OPT); + if (dst->ip6po_nexthop) FREE(dst->ip6po_nexthop, M_IP6OPT); + if (dst->ip6po_hbh) FREE(dst->ip6po_hbh, M_IP6OPT); + if (dst->ip6po_dest1) FREE(dst->ip6po_dest1, M_IP6OPT); + if (dst->ip6po_dest2) FREE(dst->ip6po_dest2, M_IP6OPT); + if (dst->ip6po_rthdr) FREE(dst->ip6po_rthdr, M_IP6OPT); return(NULL); } #undef PKTOPT_EXTHDRCPY @@ -2545,7 +1857,7 @@ ip6_freepcbopts(pktopt) ip6_clearpktopts(pktopt, 1, -1); - _FREE(pktopt, M_IP6OPT); + FREE(pktopt, M_IP6OPT); } /* @@ -2565,8 +1877,7 @@ ip6_setmoptions(optname, im6op, m) struct route_in6 ro; struct sockaddr_in6 *dst; struct in6_multi_mship *imm; - - struct proc *p = current_proc(); /* ### */ + struct proc *p = current_proc(); /* XXX */ if (im6o == NULL) { /* @@ -2595,7 +1906,7 @@ ip6_setmoptions(optname, im6op, m) error = EINVAL; break; } - ifindex = *(mtod(m, u_int *)); + bcopy(mtod(m, u_int *), &ifindex, sizeof(ifindex)); if (ifindex < 0 || if_index < ifindex) { error = ENXIO; /* XXX EINVAL? */ break; @@ -2618,7 +1929,7 @@ ip6_setmoptions(optname, im6op, m) error = EINVAL; break; } - optval = *(mtod(m, u_int *)); + bcopy(mtod(m, u_int *), &optval, sizeof(optval)); if (optval < -1 || optval >= 256) error = EINVAL; else if (optval == -1) @@ -2633,8 +1944,12 @@ ip6_setmoptions(optname, im6op, m) * Set the loopback flag for outgoing multicast packets. * Must be zero or one. */ - if (m == NULL || m->m_len != sizeof(u_int) || - (loop = *(mtod(m, u_int *))) > 1) { + if (m == NULL || m->m_len != sizeof(u_int)) { + error = EINVAL; + break; + } + bcopy(mtod(m, u_int *), &loop, sizeof(loop)); + if (loop > 1) { error = EINVAL; break; } @@ -2657,12 +1972,11 @@ ip6_setmoptions(optname, im6op, m) * all multicast addresses. Only super user is allowed * to do this. */ -#if ISFB31 - if (suser(p->p_ucred, &p->p_acflag)) { + if (suser(p->p_ucred, &p->p_acflag)) + { error = EACCES; break; } -#endif } else if (!IN6_IS_ADDR_MULTICAST(&mreq->ipv6mr_multiaddr)) { error = EINVAL; break; @@ -2689,11 +2003,7 @@ ip6_setmoptions(optname, im6op, m) * XXX: is it a good approach? */ if (IN6_IS_ADDR_MC_NODELOCAL(&mreq->ipv6mr_multiaddr)) { -#ifdef __bsdi__ - ifp = loifp; -#else ifp = &loif[0]; -#endif } else { ro.ro_rt = NULL; dst = (struct sockaddr_in6 *)&ro.ro_dst; @@ -2752,7 +2062,7 @@ ip6_setmoptions(optname, im6op, m) } if ((imm->i6mm_maddr = in6_addmulti(&mreq->ipv6mr_multiaddr, ifp, &error)) == NULL) { - _FREE(imm, M_IPMADDR); + FREE(imm, M_IPMADDR); break; } LIST_INSERT_HEAD(&im6o->im6o_memberships, imm, i6mm_chain); @@ -2817,7 +2127,7 @@ ip6_setmoptions(optname, im6op, m) */ LIST_REMOVE(imm, i6mm_chain); in6_delmulti(imm->i6mm_maddr); - _FREE(imm, M_IPMADDR); + FREE(imm, M_IPMADDR); break; default: @@ -2832,7 +2142,7 @@ ip6_setmoptions(optname, im6op, m) im6o->im6o_multicast_hlim == ip6_defmcasthlim && im6o->im6o_multicast_loop == IPV6_DEFAULT_MULTICAST_LOOP && im6o->im6o_memberships.lh_first == NULL) { - _FREE(*im6op, M_IPMOPTS); + FREE(*im6op, M_IPMOPTS); *im6op = NULL; } @@ -2845,16 +2155,12 @@ ip6_setmoptions(optname, im6op, m) static int ip6_getmoptions(optname, im6o, mp) int optname; - register struct ip6_moptions *im6o; - register struct mbuf **mp; + struct ip6_moptions *im6o; + struct mbuf **mp; { u_int *hlim, *loop, *ifindex; -#if __FreeBSD__ || defined (__APPLE__) *mp = m_get(M_WAIT, MT_HEADER); /*XXX*/ -#else - *mp = m_get(M_WAIT, MT_SOOPTS); -#endif switch (optname) { @@ -2895,7 +2201,7 @@ ip6_getmoptions(optname, im6o, mp) */ void ip6_freemoptions(im6o) - register struct ip6_moptions *im6o; + struct ip6_moptions *im6o; { struct in6_multi_mship *imm; @@ -2906,9 +2212,9 @@ ip6_freemoptions(im6o) LIST_REMOVE(imm, i6mm_chain); if (imm->i6mm_maddr) in6_delmulti(imm->i6mm_maddr); - _FREE(imm, M_IPMADDR); + FREE(imm, M_IPMADDR); } - _FREE(im6o, M_IPMOPTS); + FREE(im6o, M_IPMOPTS); } /* @@ -2920,13 +2226,12 @@ ip6_setpktoptions(control, opt, priv, needcopy) struct ip6_pktopts *opt; int priv, needcopy; { - register struct cmsghdr *cm = 0; + struct cmsghdr *cm = 0; if (control == 0 || opt == 0) return(EINVAL); - bzero(opt, sizeof(*opt)); - opt->ip6po_hlim = -1; /* -1 means to use default hop limit */ + init_ip6pktopts(opt); /* * XXX: Currently, we assume all the optional information is stored @@ -2943,7 +2248,10 @@ ip6_setpktoptions(control, opt, priv, needcopy) if (cm->cmsg_level != IPPROTO_IPV6) continue; - switch(cm->cmsg_type) { + /* + * XXX should check if RFC2292 API is mixed with 2292bis API + */ + switch (cm->cmsg_type) { case IPV6_PKTINFO: if (cm->cmsg_len != CMSG_LEN(sizeof(struct in6_pktinfo))) return(EINVAL); @@ -2952,8 +2260,8 @@ ip6_setpktoptions(control, opt, priv, needcopy) opt->ip6po_pktinfo = _MALLOC(sizeof(struct in6_pktinfo), M_IP6OPT, M_WAITOK); - *opt->ip6po_pktinfo = - *(struct in6_pktinfo *)CMSG_DATA(cm); + bcopy(CMSG_DATA(cm), opt->ip6po_pktinfo, + sizeof(struct in6_pktinfo)); } else opt->ip6po_pktinfo = (struct in6_pktinfo *)CMSG_DATA(cm); @@ -2969,10 +2277,11 @@ ip6_setpktoptions(control, opt, priv, needcopy) /* * Check if the requested source address is indeed a - * unicast address assigned to the node. + * unicast address assigned to the node, and can be + * used as the packet's source address. */ if (!IN6_IS_ADDR_UNSPECIFIED(&opt->ip6po_pktinfo->ipi6_addr)) { - struct ifaddr *ia; + struct in6_ifaddr *ia6; struct sockaddr_in6 sin6; bzero(&sin6, sizeof(sin6)); @@ -2980,8 +2289,10 @@ ip6_setpktoptions(control, opt, priv, needcopy) sin6.sin6_family = AF_INET6; sin6.sin6_addr = opt->ip6po_pktinfo->ipi6_addr; - ia = ifa_ifwithaddr(sin6tosa(&sin6)); - if (ia == NULL) + ia6 = (struct in6_ifaddr *)ifa_ifwithaddr(sin6tosa(&sin6)); + if (ia6 == NULL || + (ia6->ia6_flags & (IN6_IFF_ANYCAST | + IN6_IFF_NOTREADY)) != 0) return(EADDRNOTAVAIL); } break; @@ -2998,7 +2309,7 @@ ip6_setpktoptions(control, opt, priv, needcopy) case IPV6_NEXTHOP: if (!priv) return(EPERM); - + if (cm->cmsg_len < sizeof(u_char) || /* check if cmsg_len is large enough for sa_len */ cm->cmsg_len < CMSG_LEN(*CMSG_DATA(cm))) @@ -3039,7 +2350,7 @@ ip6_setpktoptions(control, opt, priv, needcopy) case IPV6_DSTOPTS: { - struct ip6_dest *dest; + struct ip6_dest *dest, **newdest; int destlen; if (cm->cmsg_len < CMSG_LEN(sizeof(struct ip6_dest))) @@ -3049,29 +2360,30 @@ ip6_setpktoptions(control, opt, priv, needcopy) if (cm->cmsg_len != CMSG_LEN(destlen)) return(EINVAL); - /* - * If there is no routing header yet, the destination - * options header should be put on the 1st part. - * Otherwise, the header should be on the 2nd part. - * (See RFC 2460, section 4.1) + /* + * The old advacned API is ambiguous on this + * point. Our approach is to determine the + * position based according to the existence + * of a routing header. Note, however, that + * this depends on the order of the extension + * headers in the ancillary data; the 1st part + * of the destination options header must + * appear before the routing header in the + * ancillary data, too. + * RFC2292bis solved the ambiguity by + * introducing separate cmsg types. */ - if (opt->ip6po_rthdr == NULL) { - if (needcopy) { - opt->ip6po_dest1 = - _MALLOC(destlen, M_IP6OPT, - M_WAITOK); - bcopy(dest, opt->ip6po_dest1, destlen); - } else - opt->ip6po_dest1 = dest; - } else { - if (needcopy) { - opt->ip6po_dest2 = - _MALLOC(destlen, M_IP6OPT, - M_WAITOK); - bcopy(dest, opt->ip6po_dest2, destlen); - } else - opt->ip6po_dest2 = dest; - } + if (opt->ip6po_rthdr == NULL) + newdest = &opt->ip6po_dest1; + else + newdest = &opt->ip6po_dest2; + + if (needcopy) { + *newdest = _MALLOC(destlen, M_IP6OPT, M_WAITOK); + bcopy(dest, *newdest, destlen); + } else + *newdest = dest; + break; } @@ -3087,7 +2399,7 @@ ip6_setpktoptions(control, opt, priv, needcopy) if (cm->cmsg_len != CMSG_LEN(rthlen)) return(EINVAL); - switch(rth->ip6r_type) { + switch (rth->ip6r_type) { case IPV6_RTHDR_TYPE_0: /* must contain one addr */ if (rth->ip6r_len == 0) @@ -3112,28 +2424,6 @@ ip6_setpktoptions(control, opt, priv, needcopy) break; } - case IPV6_REACHCONF: -#if 1 - /* - * it looks dangerous to allow IPV6_REACHCONF to - * normal user. it affects the ND state (system state) - * and can affect communication by others - jinmei - */ - if (!priv) - return(EPERM); -#endif - - if (cm->cmsg_len != CMSG_LEN(0)) - return(EINVAL); - opt->ip6po_flags |= IP6PO_REACHCONF; - break; - - case IPV6_USE_MIN_MTU: - if (cm->cmsg_len != CMSG_LEN(0)) - return(EINVAL); - opt->ip6po_flags |= IP6PO_MINMTU; - break; - default: return(ENOPROTOOPT); } @@ -3151,34 +2441,63 @@ ip6_setpktoptions(control, opt, priv, needcopy) void ip6_mloopback(ifp, m, dst) struct ifnet *ifp; - register struct mbuf *m; - register struct sockaddr_in6 *dst; + struct mbuf *m; + struct sockaddr_in6 *dst; { - struct mbuf *copym; + struct mbuf *copym; + struct ip6_hdr *ip6; copym = m_copy(m, 0, M_COPYALL); - if (copym != NULL) { + if (copym == NULL) + return; + + /* + * Make sure to deep-copy IPv6 header portion in case the data + * is in an mbuf cluster, so that we can safely override the IPv6 + * header portion later. + */ + if ((copym->m_flags & M_EXT) != 0 || + copym->m_len < sizeof(struct ip6_hdr)) { + copym = m_pullup(copym, sizeof(struct ip6_hdr)); + if (copym == NULL) + return; + } + +#if DIAGNOSTIC + if (copym->m_len < sizeof(*ip6)) { + m_freem(copym); + return; + } +#endif + + ip6 = mtod(copym, struct ip6_hdr *); +#ifndef SCOPEDROUTING + /* + * clear embedded scope identifiers if necessary. + * in6_clearscope will touch the addresses only when necessary. + */ + in6_clearscope(&ip6->ip6_src); + in6_clearscope(&ip6->ip6_dst); +#endif + #ifdef __APPLE__ - /* - * TedW: - * We need to send all loopback traffic down to dlil in case - * a filter has tapped-in. - */ - - if (lo_dl_tag == 0) - dlil_find_dltag(APPLE_IF_FAM_LOOPBACK, 0, PF_INET6, &lo_dl_tag); - - if (lo_dl_tag) - dlil_output(lo_dl_tag, copym, 0, (struct sockaddr *) dst, 0); - else { - printf("Warning: ip6_mloopback call to dlil_find_dltag failed!\n"); - m_freem(copym); - } + + /* Makes sure the HW checksum flags are cleaned before sending the packet */ + + copym->m_pkthdr.rcvif = (struct ifnet *)0; + copym->m_pkthdr.csum_data = 0; + copym->m_pkthdr.csum_flags = 0; + + if (lo_dl_tag == 0) + dlil_find_dltag(APPLE_IF_FAM_LOOPBACK, 0, PF_INET, &lo_dl_tag); + + if (lo_dl_tag) + dlil_output(lo_dl_tag, copym, 0, (struct sockaddr *)&dst, 0); + else + m_free(copym); #else - (void)if_simloop(ifp, copym, (struct sockaddr *)dst, NULL); - (void)looutput(ifp, copym, (struct sockaddr *)dst, NULL); + (void)if_simloop(ifp, copym, dst->sin6_family, NULL); #endif - } } /* @@ -3216,10 +2535,6 @@ ip6_splithdr(m, exthdrs) /* * Compute IPv6 extension header length. */ -#if HAVE_NRL_INPCB -# define in6pcb inpcb -# define in6p_outputopts inp_outputopts6 -#endif int ip6_optlen(in6p) struct in6pcb *in6p; @@ -3242,7 +2557,3 @@ ip6_optlen(in6p) return len; #undef elen } -#if HAVE_NRL_INPCB -# undef in6pcb -# undef in6p_outputopts -#endif diff --git a/bsd/netinet6/ip6_var.h b/bsd/netinet6/ip6_var.h index d863360c0..65a5047b7 100644 --- a/bsd/netinet6/ip6_var.h +++ b/bsd/netinet6/ip6_var.h @@ -1,4 +1,5 @@ -/* $KAME: ip6_var.h,v 1.31 2000/04/04 08:48:26 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/ip6_var.h,v 1.2.2.2 2001/07/03 11:01:54 ume Exp $ */ +/* $KAME: ip6_var.h,v 1.62 2001/05/03 14:51:48 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -66,7 +67,9 @@ #ifndef _NETINET6_IP6_VAR_H_ #define _NETINET6_IP6_VAR_H_ +#include +#ifdef __APPLE_API_PRIVATE /* * IP6 reassembly queue structure. Each fragment * being reassembled is attached to one of these structures. @@ -127,6 +130,7 @@ struct ip6po_rhinfo { #define ip6po_route ip6po_rhinfo.ip6po_rhi_route struct ip6_pktopts { + struct mbuf *ip6po_m; /* Pointer to mbuf storing the data */ int ip6po_hlim; /* Hoplimit for outgoing packets */ /* Outgoing IF/address information */ @@ -144,30 +148,12 @@ struct ip6_pktopts { /* Destination options header (after a routing header) */ struct ip6_dest *ip6po_dest2; - - int ip6po_flags; -#define IP6PO_REACHCONF 0x01 /* upper-layer reachability confirmation */ -#define IP6PO_MINMTU 0x02 /* use minimum MTU (IPV6_USE_MIN_MTU) */ }; /* * Control options for incoming packets */ -struct ip6_recvpktopts { - struct mbuf *head; /* mbuf chain of data passed to a user */ - -#ifdef SO_TIMESTAMP - struct mbuf *timestamp; /* timestamp */ -#endif - struct mbuf *hlim; /* received hop limit */ - struct mbuf *pktinfo; /* packet information of rcv packet */ - struct mbuf *hbh; /* HbH options header of rcv packet */ - struct mbuf *dest1; /* Dest opt header of rcv packet */ - struct mbuf *dest2; /* Dest opt header (after rthdr) of rcv packet */ - struct mbuf *rthdr; /* Routing header of rcv packet */ -}; - struct ip6stat { u_quad_t ip6s_total; /* total packets received */ u_quad_t ip6s_tooshort; /* packet too short */ @@ -200,20 +186,6 @@ struct ip6stat { u_quad_t ip6s_exthdrtoolong; /* ext hdr are not continuous */ u_quad_t ip6s_nogif; /* no match gif found */ u_quad_t ip6s_toomanyhdr; /* discarded due to too many headers */ - /* XXX the following two items are not really AF_INET6 thing */ - u_quad_t ip6s_exthdrget; /* # of calls to IP6_EXTHDR_GET */ - u_quad_t ip6s_exthdrget0; /* # of calls to IP6_EXTHDR_GET0 */ - u_quad_t ip6s_pulldown; /* # of calls to m_pulldown */ - u_quad_t ip6s_pulldown_copy; /* # of mbuf copies in m_pulldown */ - u_quad_t ip6s_pulldown_alloc; /* # of mbuf allocs in m_pulldown */ - u_quad_t ip6s_pullup; /* # of calls to m_pullup */ - u_quad_t ip6s_pullup_copy; /* # of possible m_pullup copies */ - u_quad_t ip6s_pullup_alloc; /* # of possible m_pullup mallocs */ - u_quad_t ip6s_pullup_fail; /* # of possible m_pullup failures */ - u_quad_t ip6s_pullup2; /* # of calls to m_pullup2 */ - u_quad_t ip6s_pullup2_copy; /* # of possible m_pullup2 copies */ - u_quad_t ip6s_pullup2_alloc; /* # of possible m_pullup2 mallocs */ - u_quad_t ip6s_pullup2_fail; /* # of possible m_pullup2 failures */ /* * statistics for improvement of the source address selection @@ -238,9 +210,43 @@ struct ip6stat { u_quad_t ip6s_sources_otherscope[16]; /* number of times that an deprecated address is chosen */ u_quad_t ip6s_sources_deprecated[16]; + + u_quad_t ip6s_forward_cachehit; + u_quad_t ip6s_forward_cachemiss; +}; + +#ifdef KERNEL +/* + * IPv6 onion peeling state. + * it will be initialized when we come into ip6_input(). + * XXX do not make it a kitchen sink! + */ +struct ip6aux { + u_int32_t ip6a_flags; +#define IP6A_SWAP 0x01 /* swapped home/care-of on packet */ +#define IP6A_HASEEN 0x02 /* HA was present */ +#define IP6A_BRUID 0x04 /* BR Unique Identifier was present */ +#define IP6A_RTALERTSEEN 0x08 /* rtalert present */ + + /* ip6.ip6_src */ + struct in6_addr ip6a_careof; /* care-of address of the peer */ + struct in6_addr ip6a_home; /* home address of the peer */ + u_int16_t ip6a_bruid; /* BR unique identifier */ + + /* ip6.ip6_dst */ + struct in6_ifaddr *ip6a_dstia6; /* my ifaddr that matches ip6_dst */ + + /* rtalert */ + u_int16_t ip6a_rtalert; /* rtalert option value */ + + /* + * decapsulation history will be here. + * with IPsec it may not be accurate. + */ }; +#endif -#if KERNEL +#ifdef KERNEL /* flags passed to ip6_output as last parameter */ #define IPV6_DADOUTPUT 0x01 /* DAD */ #define IPV6_FORWARDING 0x02 /* most of IPv6 header exists */ @@ -256,12 +262,8 @@ extern int ip6_gif_hlim; /* Hop limit for gif encap packet */ extern int ip6_use_deprecated; /* allow deprecated addr as source */ extern int ip6_rr_prune; /* router renumbering prefix * walk list every 5 sec. */ -#if INET6 -extern int ip6_mapped_addr_on; -#endif -#if defined(__NetBSD__) && !defined(INET6_BINDV6ONLY) -extern int ip6_bindv6only; -#endif +#define ip6_mapped_addr_on (!ip6_v6only) +extern int ip6_v6only; extern struct socket *ip6_mrouter; /* multicast routing daemon */ extern int ip6_sendredirects; /* send IP redirects when forwarding? */ @@ -277,69 +279,60 @@ extern int ip6_dad_count; /* DupAddrDetectionTransmits */ extern u_int32_t ip6_flow_seq; extern int ip6_auto_flowlabel; +extern int ip6_auto_linklocal; + +extern int ip6_anonportmin; /* minimum ephemeral port */ +extern int ip6_anonportmax; /* maximum ephemeral port */ +extern int ip6_lowportmin; /* minimum reserved port */ +extern int ip6_lowportmax; /* maximum reserved port */ + +extern int ip6_use_tempaddr; /* whether to use temporary addresses. */ -#if !defined(__APPLE__) -//#if !defined(__FreeBSD__) || __FreeBSD__ < 3 -struct in6pcb; -#endif -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) extern struct pr_usrreqs rip6_usrreqs; +struct sockopt; struct inpcb; -struct sockopt; -#endif -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__) int icmp6_ctloutput __P((struct socket *, struct sockopt *sopt)); -#else -int icmp6_ctloutput __P((int, struct socket *, int, int, struct mbuf **)); -#endif +struct in6_ifaddr; void ip6_init __P((void)); void ip6intr __P((void)); void ip6_input __P((struct mbuf *)); +struct in6_ifaddr *ip6_getdstifaddr __P((struct mbuf *)); void ip6_freepcbopts __P((struct ip6_pktopts *)); void ip6_freemoptions __P((struct ip6_moptions *)); int ip6_unknown_opt __P((u_int8_t *, struct mbuf *, int)); char * ip6_get_prevhdr __P((struct mbuf *, int)); int ip6_nexthdr __P((struct mbuf *, int, int, int *)); int ip6_lasthdr __P((struct mbuf *, int, int, int *)); + +struct mbuf *ip6_addaux __P((struct mbuf *)); +struct mbuf *ip6_findaux __P((struct mbuf *)); +void ip6_delaux __P((struct mbuf *)); + int ip6_mforward __P((struct ip6_hdr *, struct ifnet *, struct mbuf *)); int ip6_process_hopopts __P((struct mbuf *, u_int8_t *, int, u_int32_t *, u_int32_t *)); -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) -void ip6_savecontrol __P((struct inpcb *, struct ip6_hdr *, struct mbuf *, - struct ip6_recvpktopts *, - struct ip6_recvpktopts **)); -#else -void ip6_savecontrol __P((struct in6pcb *, struct ip6_hdr *, struct mbuf *, - struct ip6_recvpktopts *, - struct ip6_recvpktopts **)); -#endif -void ip6_update_recvpcbopt __P((struct ip6_recvpktopts *, - struct ip6_recvpktopts *)); -void ip6_reset_rcvopt __P((struct ip6_recvpktopts *, int)); +void ip6_savecontrol __P((struct inpcb *, struct mbuf **, struct ip6_hdr *, + struct mbuf *)); +void ip6_notify_pmtu __P((struct inpcb *, struct sockaddr_in6 *, + u_int32_t *)); int ip6_sysctl __P((int *, u_int, void *, size_t *, void *, size_t)); void ip6_forward __P((struct mbuf *, int)); void ip6_mloopback __P((struct ifnet *, struct mbuf *, struct sockaddr_in6 *)); int ip6_output __P((struct mbuf *, struct ip6_pktopts *, - struct route_in6 *, int, + struct route_in6 *, + int, struct ip6_moptions *, struct ifnet **)); -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) int ip6_ctloutput __P((struct socket *, struct sockopt *sopt)); -#else -int ip6_ctloutput __P((int, struct socket *, int, int, struct mbuf **)); -#endif +void init_ip6pktopts __P((struct ip6_pktopts *)); int ip6_setpktoptions __P((struct mbuf *, struct ip6_pktopts *, int, int)); void ip6_clearpktopts __P((struct ip6_pktopts *, int, int)); struct ip6_pktopts *ip6_copypktopts __P((struct ip6_pktopts *, int)); -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) int ip6_optlen __P((struct inpcb *)); -#else -int ip6_optlen __P((struct in6pcb *)); -#endif int route6_input __P((struct mbuf **, int *, int)); @@ -349,20 +342,16 @@ void frag6_slowtimo __P((void)); void frag6_drain __P((void)); void rip6_init __P((void)); -int rip6_input __P((struct mbuf **mp, int *offp, int proto)); +int rip6_input __P((struct mbuf **mp, int *offset)); void rip6_ctlinput __P((int, struct sockaddr *, void *)); -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) int rip6_ctloutput __P((struct socket *so, struct sockopt *sopt)); -#else -int rip6_ctloutput __P((int, struct socket *, int, int, struct mbuf **)); -#endif -int rip6_output __P((struct mbuf *, struct socket *, struct sockaddr_in6 *, - struct mbuf *)); +int rip6_output __P((struct mbuf *, struct socket *, struct sockaddr_in6 *, struct mbuf *)); int rip6_usrreq __P((struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *, struct proc *)); int dest6_input __P((struct mbuf **, int *, int)); int none_input __P((struct mbuf **, int *, int)); -#endif /* _KERNEL */ +#endif /* KERNEL */ +#endif /* __APPLE_API_PRIVATE */ #endif /* !_NETINET6_IP6_VAR_H_ */ diff --git a/bsd/netinet6/ip6protosw.h b/bsd/netinet6/ip6protosw.h index 61edf5ccf..3f8758f9d 100644 --- a/bsd/netinet6/ip6protosw.h +++ b/bsd/netinet6/ip6protosw.h @@ -1,7 +1,10 @@ +/* $FreeBSD: src/sys/netinet6/ip6protosw.h,v 1.2.2.3 2001/07/03 11:01:54 ume Exp $ */ +/* $KAME: ip6protosw.h,v 1.22 2001/02/08 18:02:08 itojun Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -13,7 +16,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -63,11 +66,12 @@ * SUCH DAMAGE. * * @(#)protosw.h 8.1 (Berkeley) 6/2/93 - * $Id: ip6protosw.h,v 1.2 2000/09/14 20:35:15 lindak Exp $ */ #ifndef _NETINET6_IP6PROTOSW_H_ #define _NETINET6_IP6PROTOSW_H_ +#include +#ifdef __APPLE_API_PRIVATE /* * Protocol switch table for IPv6. @@ -80,20 +84,38 @@ struct socket; struct domain; struct proc; struct ip6_hdr; -#ifdef __FreeBSD__ +struct icmp6_hdr; +struct in6_addr; struct pr_usrreqs; -#endif -#include -#include /* * argument type for the last arg of pr_ctlinput(). * should be consulted only with AF_INET6 family. + * + * IPv6 ICMP IPv6 [exthdrs] finalhdr paylaod + * ^ ^ ^ ^ + * | | ip6c_ip6 ip6c_off + * | ip6c_icmp6 + * ip6c_m + * + * ip6c_finaldst usually points to ip6c_ip6->ip6_dst. if the original + * (internal) packet carries a routing header, it may point the final + * dstination address in the routing header. + * + * ip6c_src: ip6c_ip6->ip6_src + scope info + flowlabel in ip6c_ip6 + * (beware of flowlabel, if you try to compare it against others) + * ip6c_dst: ip6c_finaldst + scope info */ struct ip6ctlparam { struct mbuf *ip6c_m; /* start of mbuf chain */ + struct icmp6_hdr *ip6c_icmp6; /* icmp6 header of target packet */ struct ip6_hdr *ip6c_ip6; /* ip6 header of target packet */ int ip6c_off; /* offset of the target proto header */ + struct sockaddr_in6 *ip6c_src; /* srcaddr w/ additional info */ + struct sockaddr_in6 *ip6c_dst; /* (final) dstaddr w/ additional info */ + struct in6_addr *ip6c_finaldst; /* final destination address */ + void *ip6c_cmdarg; /* control command dependent data */ + u_int8_t ip6c_nxt; /* final next header field */ }; struct ip6protosw { @@ -102,7 +124,7 @@ struct ip6protosw { short pr_protocol; /* protocol number */ unsigned int pr_flags; /* see below */ /* protocol-protocol hooks */ - int (*pr_input) __P((struct mbuf **, int *, int)); + int (*pr_input) __P((struct mbuf **, int *)); /* input to protocol (from below) */ int (*pr_output) __P((struct mbuf *m, struct socket *so, struct sockaddr_in6 *, struct mbuf *)); @@ -125,13 +147,19 @@ struct ip6protosw { /* slow timeout (500ms) */ void (*pr_drain) __P((void)); /* flush any excess space possible */ -/* ### Added for MacOS X */ +#ifdef __APPLE__ + /* for compat. with IPv4 protosw */ int (*pr_sysctl)(); /* sysctl for protocol */ +#endif struct pr_usrreqs *pr_usrreqs; /* supersedes pr_usrreq() */ -/* ### Added MacOS X Implant hooks */ +#ifdef __APPLE__ + /* Filter hooks */ TAILQ_HEAD(pr6_sfilter, NFDescriptor) pr_sfilter; - struct protosw *pr_next; /* Chain for domain */ + struct ip6protosw *pr_next; /* Chain for domain */ + u_long reserved[4]; +#endif }; +#endif /* __APPLE_API_PRIVATE */ #endif diff --git a/bsd/netinet6/ipcomp.h b/bsd/netinet6/ipcomp.h index 25ca896f0..383a67555 100644 --- a/bsd/netinet6/ipcomp.h +++ b/bsd/netinet6/ipcomp.h @@ -1,3 +1,6 @@ +/* $FreeBSD: src/sys/netinet6/ipcomp.h,v 1.1.2.2 2001/07/03 11:01:54 ume Exp $ */ +/* $KAME: ipcomp.h,v 1.8 2000/09/26 07:55:14 itojun Exp $ */ + /* * Copyright (C) 1999 WIDE Project. * All rights reserved. @@ -33,6 +36,7 @@ #ifndef _NETINET6_IPCOMP_H_ #define _NETINET6_IPCOMP_H_ +#include struct ipcomp { u_int8_t comp_nxt; /* Next Header */ @@ -48,7 +52,8 @@ struct ipcomp { #define IPCOMP_CPI_NEGOTIATE_MIN 256 -#if defined(KERNEL) || defined(_KERNEL) +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE struct ipcomp_algorithm { int (*compress) __P((struct mbuf *, struct mbuf *, size_t *)); int (*decompress) __P((struct mbuf *, struct mbuf *, size_t *)); @@ -56,14 +61,10 @@ struct ipcomp_algorithm { }; struct ipsecrequest; -extern struct ipcomp_algorithm ipcomp_algorithms[]; +extern const struct ipcomp_algorithm *ipcomp_algorithm_lookup __P((int)); extern void ipcomp4_input __P((struct mbuf *, int)); extern int ipcomp4_output __P((struct mbuf *, struct ipsecrequest *)); -#if INET6 -extern int ipcomp6_input __P((struct mbuf **, int *)); -extern int ipcomp6_output __P((struct mbuf *, u_char *, struct mbuf *, - struct ipsecrequest *)); -#endif +#endif /* __APPLE_API_PRIVATE */ #endif /*KERNEL*/ #endif /*_NETINET6_IPCOMP_H_*/ diff --git a/bsd/netinet6/ipcomp6.h b/bsd/netinet6/ipcomp6.h new file mode 100644 index 000000000..b0ca0316e --- /dev/null +++ b/bsd/netinet6/ipcomp6.h @@ -0,0 +1,49 @@ +/* $FreeBSD: src/sys/netinet6/ipcomp6.h,v 1.1.2.2 2001/07/03 11:01:54 ume Exp $ */ +/* $KAME: ipcomp.h,v 1.8 2000/09/26 07:55:14 itojun Exp $ */ + +/* + * Copyright (C) 1999 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * RFC2393 IP payload compression protocol (IPComp). + */ + +#ifndef _NETINET6_IPCOMP6_H_ +#define _NETINET6_IPCOMP6_H_ +#include + +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE +extern int ipcomp6_input __P((struct mbuf **, int *)); +extern int ipcomp6_output __P((struct mbuf *, u_char *, struct mbuf *, + struct ipsecrequest *)); +#endif /* __APPLE_API_PRIVATE */ +#endif /*KERNEL*/ + +#endif /*_NETINET6_IPCOMP6_H_*/ diff --git a/bsd/netinet6/ipcomp_core.c b/bsd/netinet6/ipcomp_core.c index 9ef5e3d14..1ca103860 100644 --- a/bsd/netinet6/ipcomp_core.c +++ b/bsd/netinet6/ipcomp_core.c @@ -1,4 +1,5 @@ -/* $KAME: ipcomp_core.c,v 1.10 2000/02/22 14:04:23 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/ipcomp_core.c,v 1.1.2.2 2001/07/03 11:01:54 ume Exp $ */ +/* $KAME: ipcomp_core.c,v 1.24 2000/10/23 04:24:22 itojun Exp $ */ /* * Copyright (C) 1999 WIDE Project. @@ -33,10 +34,6 @@ * RFC2393 IP payload compression protocol (IPComp). */ -#define _IP_VHL -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#endif #include #include @@ -57,11 +54,14 @@ #include #include -#include -#include -#include #include +#if INET6 +#include +#endif #include +#if INET6 +#include +#endif #include @@ -82,13 +82,57 @@ static int deflate_window_out = -12; static const int deflate_window_in = -1 * MAX_WBITS; /* don't change it */ static int deflate_memlevel = MAX_MEM_LEVEL; -struct ipcomp_algorithm ipcomp_algorithms[] = { - { NULL, NULL, -1 }, - { NULL, NULL, -1 }, +static z_stream deflate_stream; +static z_stream inflate_stream; + +static const struct ipcomp_algorithm ipcomp_algorithms[] = { { deflate_compress, deflate_decompress, 90 }, - { NULL, NULL, 90 }, }; +const struct ipcomp_algorithm * +ipcomp_algorithm_lookup(idx) + int idx; +{ + + if (idx == SADB_X_CALG_DEFLATE) { + /* + * Avert your gaze, ugly hack follows! + * We init here so our malloc can allocate using M_WAIT. + * We don't want to allocate if ipcomp isn't used, and we + * don't want to allocate on the input or output path. + * Allocation fails if we use M_NOWAIT because init allocates + * something like 256k (ouch). + */ + if (deflate_stream.zalloc == NULL) { + deflate_stream.zalloc = deflate_alloc; + deflate_stream.zfree = deflate_free; + if (deflateInit2(&deflate_stream, deflate_policy, Z_DEFLATED, + deflate_window_out, deflate_memlevel, Z_DEFAULT_STRATEGY)) { + /* Allocation failed */ + bzero(&deflate_stream, sizeof(deflate_stream)); +#if IPSEC_DEBUG + printf("ipcomp_algorithm_lookup: deflateInit2 failed.\n"); +#endif + } + } + + if (inflate_stream.zalloc == NULL) { + inflate_stream.zalloc = deflate_alloc; + inflate_stream.zfree = deflate_free; + if (inflateInit2(&inflate_stream, deflate_window_in)) { + /* Allocation failed */ + bzero(&inflate_stream, sizeof(inflate_stream)); +#if IPSEC_DEBUG + printf("ipcomp_algorithm_lookup: inflateInit2 failed.\n"); +#endif + } + } + + return &ipcomp_algorithms[0]; + } + return NULL; +} + static void * deflate_alloc(aux, items, siz) void *aux; @@ -96,7 +140,7 @@ deflate_alloc(aux, items, siz) u_int siz; { void *ptr; - MALLOC(ptr, void *, items * siz, M_TEMP, M_NOWAIT); + ptr = _MALLOC(items * siz, M_TEMP, M_WAIT); return ptr; } @@ -117,165 +161,210 @@ deflate_common(m, md, lenp, mode) { struct mbuf *mprev; struct mbuf *p; - struct mbuf *n, *n0 = NULL, **np; - z_stream zs; + struct mbuf *n = NULL, *n0 = NULL, **np; + z_stream *zs; int error = 0; int zerror; size_t offset; - int firsttime, final, flush; + +#define MOREBLOCK() \ +do { \ + /* keep the reply buffer into our chain */ \ + if (n) { \ + n->m_len = zs->total_out - offset; \ + offset = zs->total_out; \ + *np = n; \ + np = &n->m_next; \ + n = NULL; \ + } \ + \ + /* get a fresh reply buffer */ \ + MGET(n, M_DONTWAIT, MT_DATA); \ + if (n) { \ + MCLGET(n, M_DONTWAIT); \ + } \ + if (!n) { \ + error = ENOBUFS; \ + goto fail; \ + } \ + n->m_len = 0; \ + n->m_len = M_TRAILINGSPACE(n); \ + n->m_next = NULL; \ + /* \ + * if this is the first reply buffer, reserve \ + * region for ipcomp header. \ + */ \ + if (*np == NULL) { \ + n->m_len -= sizeof(struct ipcomp); \ + n->m_data += sizeof(struct ipcomp); \ + } \ + \ + zs->next_out = mtod(n, u_int8_t *); \ + zs->avail_out = n->m_len; \ +} while (0) for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next) ; if (!mprev) panic("md is not in m in deflate_common"); - bzero(&zs, sizeof(zs)); - zs.zalloc = deflate_alloc; - zs.zfree = deflate_free; - zerror = mode ? inflateInit2(&zs, deflate_window_in) - : deflateInit2(&zs, deflate_policy, Z_DEFLATED, - deflate_window_out, deflate_memlevel, - Z_DEFAULT_STRATEGY); - if (zerror != Z_OK) { + zs = mode ? &inflate_stream : &deflate_stream; + if (zs->zalloc == NULL) { + /* + * init is called in ipcomp_algorithm_lookup. + * if zs->zalloc is NULL, either init hasn't been called (unlikely) + * or init failed because of no memory. + */ error = ENOBUFS; goto fail; } + + zs->next_in = 0; + zs->avail_in = 0; + zs->next_out = 0; + zs->avail_out = 0; n0 = n = NULL; np = &n0; offset = 0; - firsttime = 1; - final = 0; - flush = Z_NO_FLUSH; zerror = 0; p = md; - while (1) { - /* - * first time, we need to setup the buffer before calling - * compression function. - */ - if (firsttime) - firsttime = 0; - else { - zerror = mode ? inflate(&zs, flush) - : deflate(&zs, flush); - } + while (p && p->m_len == 0) { + p = p->m_next; + } + /* input stream and output stream are available */ + while (p && zs->avail_in == 0) { /* get input buffer */ - if (p && zs.avail_in == 0) { - zs.next_in = mtod(p, u_int8_t *); - zs.avail_in = p->m_len; + if (p && zs->avail_in == 0) { + zs->next_in = mtod(p, u_int8_t *); + zs->avail_in = p->m_len; p = p->m_next; - if (!p) { - final = 1; - flush = Z_PARTIAL_FLUSH; + while (p && p->m_len == 0) { + p = p->m_next; } } /* get output buffer */ - if (zs.next_out == NULL || zs.avail_out == 0) { - /* keep the reply buffer into our chain */ - if (n) { - n->m_len = zs.total_out - offset; - offset = zs.total_out; - *np = n; - np = &n->m_next; - } + if (zs->next_out == NULL || zs->avail_out == 0) { + MOREBLOCK(); + } - /* get a fresh reply buffer */ - MGET(n, M_DONTWAIT, MT_DATA); - if (n) { - MCLGET(n, M_DONTWAIT); - } - if (!n) { - error = ENOBUFS; - goto fail; - } - n->m_len = 0; - n->m_len = M_TRAILINGSPACE(n); - n->m_next = NULL; - /* - * if this is the first reply buffer, reserve - * region for ipcomp header. - */ - if (*np == NULL) { - n->m_len -= sizeof(struct ipcomp); - n->m_data += sizeof(struct ipcomp); + zerror = mode ? inflate(zs, Z_NO_FLUSH) + : deflate(zs, Z_NO_FLUSH); + + if (zerror == Z_STREAM_END) + ; /*once more.*/ + else if (zerror == Z_OK) { + /* inflate: Z_OK can indicate the end of decode */ + if (mode && !p && zs->avail_out != 0) + goto terminate; + else + ; /*once more.*/ + } else { + if (zs->msg) { + ipseclog((LOG_ERR, "ipcomp_%scompress: " + "%sflate(Z_NO_FLUSH): %s\n", + mode ? "de" : "", mode ? "in" : "de", + zs->msg)); + } else { + ipseclog((LOG_ERR, "ipcomp_%scompress: " + "%sflate(Z_NO_FLUSH): unknown error (%d)\n", + mode ? "de" : "", mode ? "in" : "de", + zerror)); } + mode ? inflateReset(zs) : deflateReset(zs); +/* mode ? inflateEnd(zs) : deflateEnd(zs);*/ + error = EINVAL; + goto fail; + } + } - zs.next_out = mtod(n, u_int8_t *); - zs.avail_out = n->m_len; + if (zerror == Z_STREAM_END) + goto terminate; + + /* termination */ + while (1) { + /* get output buffer */ + if (zs->next_out == NULL || zs->avail_out == 0) { + MOREBLOCK(); } - if (zerror == Z_OK) { - /* - * to terminate deflate/inflate process, we need to - * call {in,de}flate() with different flushing methods. - * - * deflate() needs at least one Z_PARTIAL_FLUSH, - * then use Z_FINISH until we get to the end. - * (if we use Z_FLUSH without Z_PARTIAL_FLUSH, deflate() - * will assume contiguous single output buffer, and that - * is not what we want) - * inflate() does not care about flushing method, but - * needs output buffer until it gets to the end. - * - * the most outer loop will be terminated with - * Z_STREAM_END. - */ - if (final == 1) { - /* reached end of mbuf chain */ - if (mode == 0) - final = 2; - else - final = 3; - } else if (final == 2) { - /* terminate deflate case */ - flush = Z_FINISH; - } else if (final == 3) { - /* terminate inflate case */ - ; - } - } else if (zerror == Z_STREAM_END) + zerror = mode ? inflate(zs, Z_FINISH) + : deflate(zs, Z_FINISH); + + if (zerror == Z_STREAM_END) break; + else if (zerror == Z_OK) + ; /*once more.*/ else { - ipseclog((LOG_ERR, "ipcomp_%scompress: %sflate: %s\n", - mode ? "de" : "", mode ? "in" : "de", - zs.msg ? zs.msg : "unknown error")); + if (zs->msg) { + ipseclog((LOG_ERR, "ipcomp_%scompress: " + "%sflate(Z_FINISH): %s\n", + mode ? "de" : "", mode ? "in" : "de", + zs->msg)); + } else { + ipseclog((LOG_ERR, "ipcomp_%scompress: " + "%sflate(Z_FINISH): unknown error (%d)\n", + mode ? "de" : "", mode ? "in" : "de", + zerror)); + } + mode ? inflateReset(zs) : deflateReset(zs); +/* mode ? inflateEnd(zs) : deflateEnd(zs); */ error = EINVAL; goto fail; } } - zerror = mode ? inflateEnd(&zs) : deflateEnd(&zs); - if (zerror != Z_OK) { - ipseclog((LOG_ERR, "ipcomp_%scompress: %sflate: %s\n", - mode ? "de" : "", mode ? "in" : "de", - zs.msg ? zs.msg : "unknown error")); - error = EINVAL; - goto fail; - } + +terminate: /* keep the final reply buffer into our chain */ if (n) { - n->m_len = zs.total_out - offset; - offset = zs.total_out; + n->m_len = zs->total_out - offset; + offset = zs->total_out; *np = n; np = &n->m_next; + n = NULL; } /* switch the mbuf to the new one */ mprev->m_next = n0; m_freem(md); - *lenp = zs.total_out; + *lenp = zs->total_out; + + /* reset the inflate/deflate state */ + zerror = mode ? inflateReset(zs) : deflateReset(zs); + if (zerror != Z_OK) { + /* + * A failure here is uncommon. If this does + * fail, the packet can still be used but + * the z_stream will be messed up so subsequent + * inflates/deflates will probably fail. + */ + if (zs->msg) { + ipseclog((LOG_ERR, "ipcomp_%scompress: " + "%sflateEnd: %s\n", + mode ? "de" : "", mode ? "in" : "de", + zs->msg)); + } else { + ipseclog((LOG_ERR, "ipcomp_%scompress: " + "%sflateEnd: unknown error (%d)\n", + mode ? "de" : "", mode ? "in" : "de", + zerror)); + } + } return 0; fail: if (m) m_freem(m); + if (n) + m_freem(n); if (n0) m_freem(n0); return error; +#undef MOREBLOCK } static int diff --git a/bsd/netinet6/ipcomp_input.c b/bsd/netinet6/ipcomp_input.c index 43039d9c7..7ea00daf6 100644 --- a/bsd/netinet6/ipcomp_input.c +++ b/bsd/netinet6/ipcomp_input.c @@ -1,4 +1,5 @@ -/* $KAME: ipcomp_input.c,v 1.11 2000/02/22 14:04:23 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/ipcomp_input.c,v 1.1.2.2 2001/07/03 11:01:54 ume Exp $ */ +/* $KAME: ipcomp_input.c,v 1.25 2001/03/01 09:12:09 itojun Exp $ */ /* * Copyright (C) 1999 WIDE Project. @@ -33,10 +34,6 @@ * RFC2393 IP payload compression protocol (IPComp). */ -#define _IP_VHL -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#endif #include #include @@ -68,29 +65,29 @@ #include #endif #include +#if INET6 +#include +#endif #include +#if INET6 +#include +#endif #include #include -#include #include #define IPLEN_FLIPPED -#if INET -extern struct protosw * ip_protox[]; -#if defined(__bsdi__) || defined(__NetBSD__) -extern u_char ip_protox[]; -#endif - void ipcomp4_input(struct mbuf *m, int off) { + struct mbuf *md; struct ip *ip; struct ipcomp *ipcomp; - struct ipcomp_algorithm *algo; + const struct ipcomp_algorithm *algo; u_int16_t cpi; /* host order */ u_int16_t nxt; size_t hlen; @@ -99,42 +96,23 @@ ipcomp4_input(struct mbuf *m, int off) struct secasvar *sav = NULL; - if (off + sizeof(struct ipcomp) > MHLEN) { - /*XXX the restriction should be relaxed*/ + if (m->m_pkthdr.len < off + sizeof(struct ipcomp)) { ipseclog((LOG_DEBUG, "IPv4 IPComp input: assumption failed " - "(header too long)\n")); + "(packet too short)\n")); ipsecstat.in_inval++; goto fail; } - if (m->m_len < off + sizeof(struct ipcomp)) { - m = m_pullup(m, off + sizeof(struct ipcomp)); - if (!m) { - ipseclog((LOG_DEBUG, "IPv4 IPComp input: can't pullup;" - "dropping the packet for simplicity\n")); - ipsecstat.in_nomem++; - goto fail; - } - } else if (m->m_len > off + sizeof(struct ipcomp)) { - /* chop header part from the packet header chain */ - struct mbuf *n; - MGETHDR(n, M_DONTWAIT, MT_HEADER); - if (!n) { - ipsecstat.in_nomem++; - goto fail; - } - M_COPY_PKTHDR(n, m); - MH_ALIGN(n, off + sizeof(struct ipcomp)); - n->m_len = off + sizeof(struct ipcomp); - bcopy(mtod(m, caddr_t), mtod(n, caddr_t), - off + sizeof(struct ipcomp)); - m_adj(m, off + sizeof(struct ipcomp)); - m->m_flags &= ~M_PKTHDR; - n->m_next = m; - m = n; - } + md = m_pulldown(m, off, sizeof(*ipcomp), NULL); + if (!m) { + m = NULL; /*already freed*/ + ipseclog((LOG_DEBUG, "IPv4 IPComp input: assumption failed " + "(pulldown failure)\n")); + ipsecstat.in_inval++; + goto fail; + } + ipcomp = mtod(md, struct ipcomp *); ip = mtod(m, struct ip *); - ipcomp = (struct ipcomp *)(((caddr_t)ip) + off); nxt = ipcomp->comp_nxt; #ifdef _IP_VHL hlen = IP_VHL_HL(ip->ip_vhl) << 2; @@ -154,10 +132,7 @@ ipcomp4_input(struct mbuf *m, int off) /* other parameters to look at? */ } } - if (cpi < IPCOMP_MAX && ipcomp_algorithms[cpi].decompress != NULL) - algo = &ipcomp_algorithms[cpi]; - else - algo = NULL; + algo = ipcomp_algorithm_lookup(cpi); if (!algo) { ipseclog((LOG_WARNING, "IPv4 IPComp input: unknown cpi %u\n", cpi)); @@ -167,7 +142,8 @@ ipcomp4_input(struct mbuf *m, int off) /* chop ipcomp header */ ipcomp = NULL; - m->m_len -= sizeof(struct ipcomp); + md->m_data += sizeof(struct ipcomp); + md->m_len -= sizeof(struct ipcomp); m->m_pkthdr.len -= sizeof(struct ipcomp); #ifdef IPLEN_FLIPPED ip->ip_len -= sizeof(struct ipcomp); @@ -224,13 +200,23 @@ ipcomp4_input(struct mbuf *m, int off) if (sav) { key_sa_recordxfer(sav, m); + if (ipsec_addhist(m, IPPROTO_IPCOMP, (u_int32_t)cpi) != 0) { + ipsecstat.in_nomem++; + goto fail; + } key_freesav(sav); sav = NULL; } - if (nxt != IPPROTO_DONE) + if (nxt != IPPROTO_DONE) { + if ((ip_protox[nxt]->pr_flags & PR_LASTHDR) != 0 && + ipsec4_in_reject(m, NULL)) { + ipsecstat.in_polvio++; + goto fail; + } (*ip_protox[nxt]->pr_input)(m, off); - else + + } else m_freem(m); m = NULL; @@ -244,7 +230,6 @@ fail: m_freem(m); return; } -#endif /* INET */ #if INET6 int @@ -255,66 +240,30 @@ ipcomp6_input(mp, offp) struct mbuf *m, *md; int off; struct ip6_hdr *ip6; - struct mbuf *ipcompm; struct ipcomp *ipcomp; - struct ipcomp_algorithm *algo; + const struct ipcomp_algorithm *algo; u_int16_t cpi; /* host order */ u_int16_t nxt; int error; size_t newlen; struct secasvar *sav = NULL; + char *prvnxtp; m = *mp; off = *offp; - IP6_EXTHDR_CHECK(m, off, sizeof(struct ipcomp), IPPROTO_DONE); - - { - int skip; - struct mbuf *n; - struct mbuf *p, *q; - size_t l; - - skip = off; - for (n = m; n && skip > 0; n = n->m_next) { - if (n->m_len <= skip) { - skip -= n->m_len; - continue; - } - break; - } - if (!n) { - ipseclog((LOG_DEBUG, "IPv6 IPComp input: wrong mbuf chain\n")); - ipsecstat.in_inval++; - goto fail; - } - if (n->m_len < skip + sizeof(struct ipcomp)) { - ipseclog((LOG_DEBUG, "IPv6 IPComp input: wrong mbuf chain\n")); - ipsecstat.in_inval++; + md = m_pulldown(m, off, sizeof(*ipcomp), NULL); + if (!m) { + m = NULL; /*already freed*/ + ipseclog((LOG_DEBUG, "IPv6 IPComp input: assumption failed " + "(pulldown failure)\n")); + ipsec6stat.in_inval++; goto fail; } + ipcomp = mtod(md, struct ipcomp *); ip6 = mtod(m, struct ip6_hdr *); - ipcompm = n; - ipcomp = (struct ipcomp *)(mtod(n, caddr_t) + skip); - if (n->m_len > skip + sizeof(struct ipcomp)) { - /* split mbuf to ease the following steps*/ - l = n->m_len - (skip + sizeof(struct ipcomp)); - p = m_copym(n, skip + sizeof(struct ipcomp), l , M_DONTWAIT); - if (!p) { - ipsecstat.in_nomem++; - goto fail; - } - for (q = p; q && q->m_next; q = q->m_next) - ; - q->m_next = n->m_next; - n->m_next = p; - n->m_len -= l; - md = p; - } else - md = n->m_next; - } - nxt = ipcomp->comp_nxt; + cpi = ntohs(ipcomp->comp_cpi); if (cpi >= IPCOMP_CPI_NEGOTIATE_MIN) { @@ -327,10 +276,7 @@ ipcomp6_input(mp, offp) /* other parameters to look at? */ } } - if (cpi < IPCOMP_MAX && ipcomp_algorithms[cpi].decompress != NULL) - algo = &ipcomp_algorithms[cpi]; - else - algo = NULL; + algo = ipcomp_algorithm_lookup(cpi); if (!algo) { ipseclog((LOG_WARNING, "IPv6 IPComp input: unknown cpi %u; " "dropping the packet for simplicity\n", cpi)); @@ -338,7 +284,13 @@ ipcomp6_input(mp, offp) goto fail; } - newlen = m->m_pkthdr.len - off - sizeof(struct ipcomp); + /* chop ipcomp header */ + ipcomp = NULL; + md->m_data += sizeof(struct ipcomp); + md->m_len -= sizeof(struct ipcomp); + m->m_pkthdr.len -= sizeof(struct ipcomp); + + newlen = m->m_pkthdr.len - off; error = (*algo->decompress)(m, md, &newlen); if (error != 0) { if (error == EINVAL) @@ -349,7 +301,7 @@ ipcomp6_input(mp, offp) goto fail; } ipsec6stat.in_comphist[cpi]++; - m->m_pkthdr.len = off + sizeof(struct ipcomp) + newlen; + m->m_pkthdr.len = off + newlen; /* * returning decompressed packet onto icmp is meaningless. @@ -357,25 +309,21 @@ ipcomp6_input(mp, offp) */ m->m_flags |= M_DECRYPTED; - { - char *prvnxtp; - - /* chop IPComp header */ + /* update next header field */ prvnxtp = ip6_get_prevhdr(m, off); *prvnxtp = nxt; - ipcompm->m_len -= sizeof(struct ipcomp); - ipcompm->m_pkthdr.len -= sizeof(struct ipcomp); - /* adjust payload length */ - ip6 = mtod(m, struct ip6_hdr *); - if (((m->m_pkthdr.len - sizeof(struct ip6_hdr)) & ~0xffff) != 0) - ip6->ip6_plen = 0; /*now a jumbogram*/ - else - ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr)); - } + /* + * no need to adjust payload length, as all the IPv6 protocols + * look at m->m_pkthdr.len + */ if (sav) { key_sa_recordxfer(sav, m); + if (ipsec_addhist(m, IPPROTO_IPCOMP, (u_int32_t)cpi) != 0) { + ipsec6stat.in_nomem++; + goto fail; + } key_freesav(sav); sav = NULL; } diff --git a/bsd/netinet6/ipcomp_output.c b/bsd/netinet6/ipcomp_output.c index 484c0b481..a8a839b93 100644 --- a/bsd/netinet6/ipcomp_output.c +++ b/bsd/netinet6/ipcomp_output.c @@ -1,4 +1,5 @@ -/* $KAME: ipcomp_output.c,v 1.11 2000/02/22 14:04:23 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/ipcomp_output.c,v 1.1.2.2 2001/07/03 11:01:54 ume Exp $ */ +/* $KAME: ipcomp_output.c,v 1.23 2001/01/23 08:59:37 itojun Exp $ */ /* * Copyright (C) 1999 WIDE Project. @@ -33,10 +34,6 @@ * RFC2393 IP payload compression protocol (IPComp). */ -#define _IP_VHL -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#endif #include #include @@ -68,11 +65,16 @@ #include #endif #include +#if INET6 +#include +#endif #include +#if INET6 +#include +#endif #include #include -#include #include @@ -82,7 +84,7 @@ static int ipcomp_output __P((struct mbuf *, u_char *, struct mbuf *, /* * Modify the packet so that the payload is compressed. * The mbuf (m) must start with IPv4 or IPv6 header. - * On failure, free the given mbuf and return NULL. + * On failure, free the given mbuf and return non-zero. * * on invocation: * m nexthdrp md @@ -107,25 +109,29 @@ ipcomp_output(m, nexthdrp, md, isr, af) { struct mbuf *n; struct mbuf *md0; + struct mbuf *mcopy; struct mbuf *mprev; struct ipcomp *ipcomp; struct secasvar *sav = isr->sav; - struct ipcomp_algorithm *algo; + const struct ipcomp_algorithm *algo; u_int16_t cpi; /* host order */ size_t plen0, plen; /*payload length to be compressed*/ size_t compoff; int afnumber; int error = 0; + struct ipsecstat *stat; switch (af) { #if INET case AF_INET: afnumber = 4; + stat = &ipsecstat; break; #endif #if INET6 case AF_INET6: afnumber = 6; + stat = &ipsec6stat; break; #endif default: @@ -134,9 +140,9 @@ ipcomp_output(m, nexthdrp, md, isr, af) } /* grab parameters */ - if ((ntohl(sav->spi) & ~0xffff) != 0 || sav->alg_enc >= IPCOMP_MAX - || ipcomp_algorithms[sav->alg_enc].compress == NULL) { - ipsecstat.out_inval++; + algo = ipcomp_algorithm_lookup(sav->alg_enc); + if ((ntohl(sav->spi) & ~0xffff) != 0 || !algo) { + stat->out_inval++; m_freem(m); return EINVAL; } @@ -144,7 +150,6 @@ ipcomp_output(m, nexthdrp, md, isr, af) cpi = sav->alg_enc; else cpi = ntohl(sav->spi) & 0xffff; - algo = &ipcomp_algorithms[sav->alg_enc]; /*XXX*/ /* compute original payload length */ plen = 0; @@ -156,11 +161,21 @@ ipcomp_output(m, nexthdrp, md, isr, af) return 0; /* - * keep the original data packet, so that we can backout - * our changes when compression is not necessary. + * retain the original packet for two purposes: + * (1) we need to backout our changes when compression is not necessary. + * (2) byte lifetime computation should use the original packet. + * see RFC2401 page 23. + * compromise two m_copym(). we will be going through every byte of + * the payload during compression process anyways. */ + mcopy = m_copym(m, 0, M_COPYALL, M_NOWAIT); + if (mcopy == NULL) { + error = ENOBUFS; + return 0; + } md0 = m_copym(md, 0, M_COPYALL, M_NOWAIT); if (md0 == NULL) { + m_freem(mcopy); error = ENOBUFS; return 0; } @@ -172,26 +187,17 @@ ipcomp_output(m, nexthdrp, md, isr, af) if (mprev == NULL || mprev->m_next != md) { ipseclog((LOG_DEBUG, "ipcomp%d_output: md is not in chain\n", afnumber)); - switch (af) { -#if INET - case AF_INET: - ipsecstat.out_inval++; - break; -#endif -#if INET6 - case AF_INET6: - ipsec6stat.out_inval++; - break; -#endif - } + stat->out_inval++; m_freem(m); m_freem(md0); + m_freem(mcopy); return EINVAL; } mprev->m_next = NULL; if ((md = ipsec_copypkt(md)) == NULL) { m_freem(m); m_freem(md0); + m_freem(mcopy); error = ENOBUFS; goto fail; } @@ -202,33 +208,12 @@ ipcomp_output(m, nexthdrp, md, isr, af) ipseclog((LOG_ERR, "packet compression failure\n")); m = NULL; m_freem(md0); - switch (af) { -#if INET - case AF_INET: - ipsecstat.out_inval++; - break; -#endif -#if INET6 - case AF_INET6: - ipsec6stat.out_inval++; - break; -#endif - } + m_freem(mcopy); + stat->out_inval++; error = EINVAL; goto fail; } - switch (af) { -#if INET - case AF_INET: - ipsecstat.out_comphist[sav->alg_enc]++; - break; -#endif -#if INET6 - case AF_INET6: - ipsec6stat.out_comphist[sav->alg_enc]++; - break; -#endif - } + stat->out_comphist[sav->alg_enc]++; md = mprev->m_next; /* @@ -237,13 +222,17 @@ ipcomp_output(m, nexthdrp, md, isr, af) */ if (plen0 < plen) { m_freem(md); + m_freem(mcopy); mprev->m_next = md0; return 0; } - /* no need to backout change beyond here */ + /* + * no need to backout change beyond here. + */ m_freem(md0); md0 = NULL; + m->m_pkthdr.len -= plen0; m->m_pkthdr.len += plen; @@ -336,47 +325,14 @@ ipcomp_output(m, nexthdrp, md, isr, af) ipseclog((LOG_DEBUG, "NULL mbuf after compression in ipcomp%d_output", afnumber)); - switch (af) { -#if INET - case AF_INET: - ipsecstat.out_inval++; - break; -#endif -#if INET6 - case AF_INET6: - ipsec6stat.out_inval++; - break; -#endif - } - } else { - switch (af) { -#if INET - case AF_INET: - ipsecstat.out_success++; - break; -#endif -#if INET6 - case AF_INET6: - ipsec6stat.out_success++; - break; -#endif - } + stat->out_inval++; } -#if 0 - switch (af) { -#if INET - case AF_INET: - ipsecstat.out_esphist[sav->alg_enc]++; - break; -#endif -#if INET6 - case AF_INET6: - ipsec6stat.out_esphist[sav->alg_enc]++; - break; -#endif - } -#endif - key_sa_recordxfer(sav, m); + stat->out_success++; + + /* compute byte lifetime against original packet */ + key_sa_recordxfer(sav, mcopy); + m_freem(mcopy); + return 0; fail: @@ -398,7 +354,7 @@ ipcomp4_output(m, isr) ipseclog((LOG_DEBUG, "ipcomp4_output: first mbuf too short\n")); ipsecstat.out_inval++; m_freem(m); - return NULL; + return 0; } ip = mtod(m, struct ip *); /* XXX assumes that m->m_next points to payload */ @@ -406,7 +362,7 @@ ipcomp4_output(m, isr) } #endif /*INET*/ -#if INET6 +#ifdef INET6 int ipcomp6_output(m, nexthdrp, md, isr) struct mbuf *m; @@ -418,7 +374,7 @@ ipcomp6_output(m, nexthdrp, md, isr) ipseclog((LOG_DEBUG, "ipcomp6_output: first mbuf too short\n")); ipsec6stat.out_inval++; m_freem(m); - return NULL; + return 0; } return ipcomp_output(m, nexthdrp, md, isr, AF_INET6); } diff --git a/bsd/netinet6/ipsec.c b/bsd/netinet6/ipsec.c index c494fb4da..9991df62f 100644 --- a/bsd/netinet6/ipsec.c +++ b/bsd/netinet6/ipsec.c @@ -1,4 +1,5 @@ -/* $KAME: ipsec.c,v 1.56 2000/04/04 08:47:34 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/ipsec.c,v 1.3.2.7 2001/07/19 06:37:23 kris Exp $ */ +/* $KAME: ipsec.c,v 1.103 2001/05/24 07:14:18 sakane Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -32,14 +33,6 @@ /* * IPsec controller part. */ -#define _IP_VHL - -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#if __NetBSD__ /*XXX*/ -#include "opt_ipsec.h" -#endif -#endif #include #include @@ -53,12 +46,7 @@ #include #include #include -#ifdef __NetBSD__ -#include -#endif -#if defined(__NetBSD__) || defined(__FreeBSD__) || defined (__APPLE__) #include -#endif #include #include @@ -71,52 +59,52 @@ #include #include #include - #if INET6 +#include +#endif +#include +#include + #include +#if INET6 #include #endif #include #if INET6 -#if !((defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802)) || defined (__APPLE__) -#include -#endif #include #endif #include +#if INET6 +#include +#endif #include +#if INET6 +#include +#endif #if IPSEC_ESP #include +#if INET6 +#include +#endif #endif #include +#if INET6 +#include +#endif #include #include #include #include -#ifdef HAVE_NRL_INPCB -#define in6pcb inpcb -#define in6p_sp inp_sp -#define in6p_fport inp_fport -#define in6p_lport inp_lport -#define in6p_socket inp_socket -#define sotoin6pcb(so) ((struct inpcb *)(so)->so_pcb) -#endif - -#ifdef __NetBSD__ -#define ovbcopy bcopy -#endif - -#ifdef IPSEC_DEBUG +#if IPSEC_DEBUG int ipsec_debug = 1; #else int ipsec_debug = 0; #endif struct ipsecstat ipsecstat; -int ip4_inbound_call_ike = 0; int ip4_ah_cleartos = 1; int ip4_ah_offsetmask = 0; /* maybe IP_DF? */ int ip4_ipsec_dfbit = 0; /* DF bit on encap. 0: clear 1: set 2: copy */ @@ -126,14 +114,18 @@ int ip4_ah_trans_deflev = IPSEC_LEVEL_USE; int ip4_ah_net_deflev = IPSEC_LEVEL_USE; struct secpolicy ip4_def_policy; int ip4_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ +int ip4_esp_randpad = -1; +static int sysctl_def_policy SYSCTL_HANDLER_ARGS; -#if defined(__FreeBSD__) || defined(__APPLE__) SYSCTL_DECL(_net_inet_ipsec); +#if INET6 +SYSCTL_DECL(_net_inet6_ipsec6); +#endif /* net.inet.ipsec */ SYSCTL_STRUCT(_net_inet_ipsec, IPSECCTL_STATS, stats, CTLFLAG_RD, &ipsecstat, ipsecstat, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_POLICY, - def_policy, CTLFLAG_RW, &ip4_def_policy.policy, 0, ""); +SYSCTL_PROC(_net_inet_ipsec, IPSECCTL_DEF_POLICY, def_policy, CTLTYPE_INT|CTLFLAG_RW, + &ip4_def_policy.policy, 0, &sysctl_def_policy, "I", ""); SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_TRANSLEV, esp_trans_deflev, CTLFLAG_RW, &ip4_esp_trans_deflev, 0, ""); SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev, @@ -142,8 +134,6 @@ SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev, CTLFLAG_RW, &ip4_ah_trans_deflev, 0, ""); SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, CTLFLAG_RW, &ip4_ah_net_deflev, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_INBOUND_CALL_IKE, - inbound_call_ike, CTLFLAG_RW, &ip4_inbound_call_ike, 0, ""); SYSCTL_INT(_net_inet_ipsec, IPSECCTL_AH_CLEARTOS, ah_cleartos, CTLFLAG_RW, &ip4_ah_cleartos, 0, ""); SYSCTL_INT(_net_inet_ipsec, IPSECCTL_AH_OFFSETMASK, @@ -154,20 +144,23 @@ SYSCTL_INT(_net_inet_ipsec, IPSECCTL_ECN, ecn, CTLFLAG_RW, &ip4_ipsec_ecn, 0, ""); SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEBUG, debug, CTLFLAG_RW, &ipsec_debug, 0, ""); -#endif /* __FreeBSD__ */ +SYSCTL_INT(_net_inet_ipsec, IPSECCTL_ESP_RANDPAD, + esp_randpad, CTLFLAG_RW, &ip4_esp_randpad, 0, ""); + +/* for performance, we bypass ipsec until a security policy is set */ +int ipsec_bypass = 1; +SYSCTL_INT(_net_inet_ipsec, OID_AUTO, bypass, CTLFLAG_RD, &ipsec_bypass,0, ""); #if INET6 struct ipsecstat ipsec6stat; -int ip6_inbound_call_ike = 0; int ip6_esp_trans_deflev = IPSEC_LEVEL_USE; int ip6_esp_net_deflev = IPSEC_LEVEL_USE; int ip6_ah_trans_deflev = IPSEC_LEVEL_USE; int ip6_ah_net_deflev = IPSEC_LEVEL_USE; struct secpolicy ip6_def_policy; int ip6_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ +int ip6_esp_randpad = -1; -#if defined(__FreeBSD__) || defined(__APPLE__) -SYSCTL_DECL(_net_inet6_ipsec6); /* net.inet6.ipsec6 */ SYSCTL_STRUCT(_net_inet6_ipsec6, IPSECCTL_STATS, stats, CTLFLAG_RD, &ipsec6stat, ipsecstat, ""); @@ -181,23 +174,26 @@ SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev, CTLFLAG_RW, &ip6_ah_trans_deflev, 0, ""); SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, CTLFLAG_RW, &ip6_ah_net_deflev, 0, ""); -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_INBOUND_CALL_IKE, - inbound_call_ike, CTLFLAG_RW, &ip6_inbound_call_ike, 0, ""); SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_ECN, ecn, CTLFLAG_RW, &ip6_ipsec_ecn, 0, ""); SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEBUG, debug, CTLFLAG_RW, &ipsec_debug, 0, ""); -#endif /*__FreeBSD__*/ +SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_ESP_RANDPAD, + esp_randpad, CTLFLAG_RW, &ip6_esp_randpad, 0, ""); #endif /* INET6 */ static int ipsec_setspidx_mbuf - __P((struct secpolicyindex *, u_int, u_int, struct mbuf *)); -static void ipsec4_setspidx_inpcb __P((struct mbuf *, struct inpcb *pcb)); -static void ipsec4_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *)); + __P((struct secpolicyindex *, u_int, u_int, struct mbuf *, int)); +static int ipsec4_setspidx_inpcb __P((struct mbuf *, struct inpcb *pcb)); +#if INET6 +static int ipsec6_setspidx_in6pcb __P((struct mbuf *, struct in6pcb *pcb)); +#endif +static int ipsec_setspidx __P((struct mbuf *, struct secpolicyindex *, int)); +static void ipsec4_get_ulp __P((struct mbuf *m, struct secpolicyindex *, int)); +static int ipsec4_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *)); #if INET6 -static void ipsec6_get_ulp __P((struct mbuf *m, struct secpolicyindex *)); -static void ipsec6_setspidx_in6pcb __P((struct mbuf *, struct in6pcb *pcb)); -static void ipsec6_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *)); +static void ipsec6_get_ulp __P((struct mbuf *m, struct secpolicyindex *, int)); +static int ipsec6_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *)); #endif static struct inpcbpolicy *ipsec_newpcbpolicy __P((void)); static void ipsec_delpcbpolicy __P((struct inpcbpolicy *)); @@ -208,14 +204,40 @@ static int ipsec_get_policy __P((struct secpolicy *pcb_sp, struct mbuf **mp)); static void vshiftl __P((unsigned char *, int, int)); static int ipsec_in_reject __P((struct secpolicy *, struct mbuf *)); static size_t ipsec_hdrsiz __P((struct secpolicy *)); +#if INET static struct mbuf *ipsec4_splithdr __P((struct mbuf *)); +#endif #if INET6 static struct mbuf *ipsec6_splithdr __P((struct mbuf *)); #endif +#if INET static int ipsec4_encapsulate __P((struct mbuf *, struct secasvar *)); +#endif #if INET6 static int ipsec6_encapsulate __P((struct mbuf *, struct secasvar *)); #endif +static struct mbuf *ipsec_addaux __P((struct mbuf *)); +static struct mbuf *ipsec_findaux __P((struct mbuf *)); +static void ipsec_optaux __P((struct mbuf *, struct mbuf *)); + +static int +sysctl_def_policy SYSCTL_HANDLER_ARGS +{ + int old_policy = ip4_def_policy.policy; + int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); + + if (ip4_def_policy.policy != IPSEC_POLICY_NONE && + ip4_def_policy.policy != IPSEC_POLICY_DISCARD) { + ip4_def_policy.policy = old_policy; + return EINVAL; + } + + /* Turn off the bypass if the default security policy changes */ + if (ipsec_bypass != 0 && ip4_def_policy.policy != IPSEC_POLICY_NONE) + ipsec_bypass = 0; + + return error; +} /* * For OUTBOUND packet having a socket. Searching SPD for packet, @@ -243,37 +265,44 @@ ipsec4_getpolicybysock(m, dir, so, error) /* sanity check */ if (m == NULL || so == NULL || error == NULL) panic("ipsec4_getpolicybysock: NULL pointer was passed.\n"); + + switch (so->so_proto->pr_domain->dom_family) { + case AF_INET: + pcbsp = sotoinpcb(so)->inp_sp; + break; +#if INET6 + case AF_INET6: + pcbsp = sotoin6pcb(so)->in6p_sp; + break; +#endif + } + + if (!pcbsp){ + /* Socket has not specified an IPSEC policy */ + return ipsec4_getpolicybyaddr(m, dir, 0, error); + } switch (so->so_proto->pr_domain->dom_family) { case AF_INET: /* set spidx in pcb */ - ipsec4_setspidx_inpcb(m, sotoinpcb(so)); - pcbsp = sotoinpcb(so)->inp_sp; + *error = ipsec4_setspidx_inpcb(m, sotoinpcb(so)); break; #if INET6 case AF_INET6: /* set spidx in pcb */ - ipsec6_setspidx_in6pcb(m, sotoin6pcb(so)); - pcbsp = sotoin6pcb(so)->in6p_sp; + *error = ipsec6_setspidx_in6pcb(m, sotoin6pcb(so)); break; #endif default: panic("ipsec4_getpolicybysock: unsupported address family\n"); } + if (*error) + return NULL; /* sanity check */ if (pcbsp == NULL) panic("ipsec4_getpolicybysock: pcbsp is NULL.\n"); -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined(__APPLE__) - KEYDEBUG(KEYDEBUG_IPSEC_DATA, - printf("send: priv=%d ", pcbsp->priv); - if (so->so_cred) { - printf("p_ruid=%d ", so->so_cred->p_ruid); - printf("p_svuid=%d ", so->so_cred->p_svuid); - printf("cr_uid=%d\n", so->so_cred->pc_ucred->cr_uid); - }); -#endif switch (dir) { case IPSEC_DIR_INBOUND: currsp = pcbsp->sp_in; @@ -403,6 +432,9 @@ ipsec4_getpolicybyaddr(m, dir, flag, error) { struct secpolicy *sp = NULL; + if (ipsec_bypass != 0) + return 0; + /* sanity check */ if (m == NULL || error == NULL) panic("ipsec4_getpolicybyaddr: NULL pointer was passed.\n"); @@ -413,7 +445,8 @@ ipsec4_getpolicybyaddr(m, dir, flag, error) bzero(&spidx, sizeof(spidx)); /* make a index to look for a policy */ - *error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET, m); + *error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET, m, + (flag & IP_FORWARDING) ? 0 : 1); if (*error != 0) return NULL; @@ -469,10 +502,19 @@ ipsec6_getpolicybysock(m, dir, so, error) if (m == NULL || so == NULL || error == NULL) panic("ipsec6_getpolicybysock: NULL pointer was passed.\n"); - /* set spidx in pcb */ - ipsec6_setspidx_in6pcb(m, sotoin6pcb(so)); +#if DIAGNOSTIC + if (so->so_proto->pr_domain->dom_family != AF_INET6) + panic("ipsec6_getpolicybysock: socket domain != inet6\n"); +#endif pcbsp = sotoin6pcb(so)->in6p_sp; + + if (!pcbsp){ + return ipsec6_getpolicybyaddr(m, dir, 0, error); + } + + /* set spidx in pcb */ + ipsec6_setspidx_in6pcb(m, sotoin6pcb(so)); /* sanity check */ if (pcbsp == NULL) @@ -624,7 +666,8 @@ ipsec6_getpolicybyaddr(m, dir, flag, error) bzero(&spidx, sizeof(spidx)); /* make a index to look for a policy */ - *error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET6, m); + *error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET6, m, + (flag & IP_FORWARDING) ? 0 : 1); if (*error != 0) return NULL; @@ -665,135 +708,100 @@ ipsec6_getpolicybyaddr(m, dir, flag, error) * other: failure, and set errno. */ int -ipsec_setspidx_mbuf(spidx, dir, family, m) +ipsec_setspidx_mbuf(spidx, dir, family, m, needport) struct secpolicyindex *spidx; u_int dir, family; struct mbuf *m; + int needport; { - struct sockaddr *sa1, *sa2; + int error; /* sanity check */ if (spidx == NULL || m == NULL) panic("ipsec_setspidx_mbuf: NULL pointer was passed.\n"); - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setspidx_mbuf: begin\n"); kdebug_mbuf(m)); - - /* initialize */ bzero(spidx, sizeof(*spidx)); + error = ipsec_setspidx(m, spidx, needport); + if (error) + goto bad; spidx->dir = dir; - sa1 = (struct sockaddr *)&spidx->src; - sa2 = (struct sockaddr *)&spidx->dst; - sa1->sa_len = sa2->sa_len = _SALENBYAF(family); - sa1->sa_family = sa2->sa_family = family; - spidx->prefs = spidx->prefd = _INALENBYAF(family) << 3; - { - /* sanity check for packet length. */ - struct mbuf *n; - int tlen; + return 0; - tlen = 0; - for (n = m; n; n = n->m_next) - tlen += n->m_len; - if (m->m_pkthdr.len != tlen) { - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setspidx_mbuf: " - "total of m_len(%d) != pkthdr.len(%d), " - "ignored.\n", - tlen, m->m_pkthdr.len)); - goto bad; - } - } + bad: + /* XXX initialize */ + bzero(spidx, sizeof(*spidx)); + return EINVAL; +} - switch (family) { - case AF_INET: - { - struct ip *ip; - struct ip ipbuf; +static int +ipsec4_setspidx_inpcb(m, pcb) + struct mbuf *m; + struct inpcb *pcb; +{ + struct secpolicyindex *spidx; + int error; - /* sanity check 1 for minimum ip header length */ - if (m->m_pkthdr.len < sizeof(struct ip)) { - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setspidx_mbuf: " - "pkthdr.len(%d) < sizeof(struct ip), " - "ignored.\n", - m->m_pkthdr.len)); - goto bad; - } + if (ipsec_bypass != 0) + return 0; - /* - * get IPv4 header packet. usually the mbuf is contiguous - * and we need no copies. - */ - if (m->m_len >= sizeof(*ip)) - ip = mtod(m, struct ip *); - else { - m_copydata(m, 0, sizeof(ipbuf), (caddr_t)&ipbuf); - ip = &ipbuf; - } + /* sanity check */ + if (pcb == NULL) + panic("ipsec4_setspidx_inpcb: no PCB found.\n"); + if (pcb->inp_sp == NULL) + panic("ipsec4_setspidx_inpcb: no inp_sp found.\n"); + if (pcb->inp_sp->sp_out == NULL || pcb->inp_sp->sp_in == NULL) + panic("ipsec4_setspidx_inpcb: no sp_in/out found.\n"); - /* some more checks on IPv4 header. */ - bcopy(&ip->ip_src, _INADDRBYSA(&spidx->src), - sizeof(ip->ip_src)); - bcopy(&ip->ip_dst, _INADDRBYSA(&spidx->dst), - sizeof(ip->ip_dst)); + bzero(&pcb->inp_sp->sp_in->spidx, sizeof(*spidx)); + bzero(&pcb->inp_sp->sp_out->spidx, sizeof(*spidx)); - spidx->ul_proto = ip->ip_p; - _INPORTBYSA(&spidx->src) = IPSEC_PORT_ANY; - _INPORTBYSA(&spidx->dst) = IPSEC_PORT_ANY; - break; - } + spidx = &pcb->inp_sp->sp_in->spidx; + error = ipsec_setspidx(m, spidx, 1); + if (error) + goto bad; + spidx->dir = IPSEC_DIR_INBOUND; -#if INET6 - case AF_INET6: - { - struct ip6_hdr *ip6; - struct ip6_hdr ip6buf; + spidx = &pcb->inp_sp->sp_out->spidx; + error = ipsec_setspidx(m, spidx, 1); + if (error) + goto bad; + spidx->dir = IPSEC_DIR_OUTBOUND; - /* sanity check 1 for minimum ip header length */ - if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) { - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setspidx_mbuf: " - "pkthdr.len(%d) < sizeof(struct ip6_hdr), " - "ignored.\n", - m->m_pkthdr.len)); - goto bad; - } + return 0; - /* - * get IPv6 header packet. usually the mbuf is contiguous - * and we need no copies. - */ - if (m->m_len >= sizeof(*ip6)) - ip6 = mtod(m, struct ip6_hdr *); - else { - m_copydata(m, 0, sizeof(ip6buf), (caddr_t)&ip6buf); - ip6 = &ip6buf; - } +bad: + bzero(&pcb->inp_sp->sp_in->spidx, sizeof(*spidx)); + bzero(&pcb->inp_sp->sp_out->spidx, sizeof(*spidx)); + return error; +} - /* some more checks on IPv4 header. */ - if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setspidx_mbuf: " - "wrong ip version on packet " - "(expected IPv6), ignored.\n")); - goto bad; - } +#if INET6 +static int +ipsec6_setspidx_in6pcb(m, pcb) + struct mbuf *m; + struct in6pcb *pcb; +{ + struct secpolicyindex *spidx; + int error; - bcopy(&ip6->ip6_src, _INADDRBYSA(&spidx->src), - sizeof(ip6->ip6_src)); - bcopy(&ip6->ip6_dst, _INADDRBYSA(&spidx->dst), - sizeof(ip6->ip6_dst)); + /* sanity check */ + if (pcb == NULL) + panic("ipsec6_setspidx_in6pcb: no PCB found.\n"); + if (pcb->in6p_sp == NULL) + panic("ipsec6_setspidx_in6pcb: no in6p_sp found.\n"); + if (pcb->in6p_sp->sp_out == NULL || pcb->in6p_sp->sp_in == NULL) + panic("ipsec6_setspidx_in6pcb: no sp_in/out found.\n"); - ipsec6_get_ulp(m, spidx); - break; - } -#endif /* INET6 */ - default: - panic("ipsec_secsecidx: no supported family passed.\n"); - } + bzero(&pcb->in6p_sp->sp_in->spidx, sizeof(*spidx)); + bzero(&pcb->in6p_sp->sp_out->spidx, sizeof(*spidx)); + + spidx = &pcb->in6p_sp->sp_in->spidx; + error = ipsec_setspidx(m, spidx, 1); + if (error) + goto bad; + spidx->dir = IPSEC_DIR_INBOUND; KEYDEBUG(KEYDEBUG_IPSEC_DUMP, printf("ipsec_setspidx_mbuf: end\n"); @@ -801,221 +809,276 @@ ipsec_setspidx_mbuf(spidx, dir, family, m) return 0; - bad: - /* XXX initialize */ - bzero(spidx, sizeof(*spidx)); - return EINVAL; +bad: + bzero(&pcb->in6p_sp->sp_in->spidx, sizeof(*spidx)); + bzero(&pcb->in6p_sp->sp_out->spidx, sizeof(*spidx)); + return error; } +#endif -#if INET6 /* - * Get upper layer protocol number and port number if there. - * Assumed all extension headers are in single mbuf. + * configure security policy index (src/dst/proto/sport/dport) + * by looking at the content of mbuf. + * the caller is responsible for error recovery (like clearing up spidx). */ -#include -#include -static void -ipsec6_get_ulp(m, spidx) +static int +ipsec_setspidx(m, spidx, needport) struct mbuf *m; struct secpolicyindex *spidx; + int needport; { - int off, nxt; + struct ip *ip = NULL; + struct ip ipbuf; + u_int v; + struct mbuf *n; + int len; + int error; - /* sanity check */ if (m == NULL) - panic("ipsec6_get_ulp: NULL pointer was passed.\n"); + panic("ipsec_setspidx: m == 0 passed.\n"); - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec6_get_ulp:\n"); kdebug_mbuf(m)); - - /* set default */ - spidx->ul_proto = IPSEC_ULPROTO_ANY; - _INPORTBYSA(&spidx->src) = IPSEC_PORT_ANY; - _INPORTBYSA(&spidx->dst) = IPSEC_PORT_ANY; + /* + * validate m->m_pkthdr.len. we see incorrect length if we + * mistakenly call this function with inconsistent mbuf chain + * (like 4.4BSD tcp/udp processing). XXX should we panic here? + */ + len = 0; + for (n = m; n; n = n->m_next) + len += n->m_len; + if (m->m_pkthdr.len != len) { + KEYDEBUG(KEYDEBUG_IPSEC_DUMP, + printf("ipsec_setspidx: " + "total of m_len(%d) != pkthdr.len(%d), " + "ignored.\n", + len, m->m_pkthdr.len)); + return EINVAL; + } - nxt = -1; - off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt); - if (off < 0 || m->m_pkthdr.len < off) - return; + if (m->m_pkthdr.len < sizeof(struct ip)) { + KEYDEBUG(KEYDEBUG_IPSEC_DUMP, + printf("ipsec_setspidx: " + "pkthdr.len(%d) < sizeof(struct ip), ignored.\n", + m->m_pkthdr.len)); + return EINVAL; + } - switch (nxt) { - case IPPROTO_TCP: - spidx->ul_proto = nxt; - if (off + sizeof(struct tcphdr) <= m->m_pkthdr.len) { - struct tcphdr th; - m_copydata(m, off, sizeof(th), (caddr_t)&th); - _INPORTBYSA(&spidx->src) = th.th_sport; - _INPORTBYSA(&spidx->dst) = th.th_dport; - } - break; - case IPPROTO_UDP: - spidx->ul_proto = nxt; - if (off + sizeof(struct udphdr) <= m->m_pkthdr.len) { - struct udphdr uh; - m_copydata(m, off, sizeof(uh), (caddr_t)&uh); - _INPORTBYSA(&spidx->src) = uh.uh_sport; - _INPORTBYSA(&spidx->dst) = uh.uh_dport; + if (m->m_len >= sizeof(*ip)) + ip = mtod(m, struct ip *); + else { + m_copydata(m, 0, sizeof(ipbuf), (caddr_t)&ipbuf); + ip = &ipbuf; + } +#ifdef _IP_VHL + v = _IP_VHL_V(ip->ip_vhl); +#else + v = ip->ip_v; +#endif + switch (v) { + case 4: + error = ipsec4_setspidx_ipaddr(m, spidx); + if (error) + return error; + ipsec4_get_ulp(m, spidx, needport); + return 0; +#ifdef INET6 + case 6: + if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) { + KEYDEBUG(KEYDEBUG_IPSEC_DUMP, + printf("ipsec_setspidx: " + "pkthdr.len(%d) < sizeof(struct ip6_hdr), " + "ignored.\n", m->m_pkthdr.len)); + return EINVAL; } - break; - case IPPROTO_ICMPV6: - spidx->ul_proto = nxt; - break; + error = ipsec6_setspidx_ipaddr(m, spidx); + if (error) + return error; + ipsec6_get_ulp(m, spidx, needport); + return 0; +#endif default: - break; + KEYDEBUG(KEYDEBUG_IPSEC_DUMP, + printf("ipsec_setspidx: " + "unknown IP version %u, ignored.\n", v)); + return EINVAL; } } -#endif static void -ipsec4_setspidx_inpcb(m, pcb) +ipsec4_get_ulp(m, spidx, needport) struct mbuf *m; - struct inpcb *pcb; -{ struct secpolicyindex *spidx; - struct sockaddr *sa1, *sa2; + int needport; +{ + struct ip ip; + struct ip6_ext ip6e; + u_int8_t nxt; + int off; + struct tcphdr th; + struct udphdr uh; /* sanity check */ - if (pcb == NULL) - panic("ipsec4_setspidx_inpcb: no PCB found.\n"); - if (pcb->inp_sp == NULL) - panic("ipsec4_setspidx_inpcb: no inp_sp found.\n"); - if (pcb->inp_sp->sp_out ==NULL || pcb->inp_sp->sp_in == NULL) - panic("ipsec4_setspidx_inpcb: no sp_in/out found.\n"); - - bzero(&pcb->inp_sp->sp_in->spidx, sizeof(*spidx)); - bzero(&pcb->inp_sp->sp_out->spidx, sizeof(*spidx)); + if (m == NULL) + panic("ipsec4_get_ulp: NULL pointer was passed.\n"); + if (m->m_pkthdr.len < sizeof(ip)) + panic("ipsec4_get_ulp: too short\n"); - spidx = &pcb->inp_sp->sp_in->spidx; - spidx->dir = IPSEC_DIR_INBOUND; - sa1 = (struct sockaddr *)&spidx->src; - sa2 = (struct sockaddr *)&spidx->dst; - sa1->sa_len = sa2->sa_len = _SALENBYAF(AF_INET); - sa1->sa_family = sa2->sa_family = AF_INET; - spidx->prefs = _INALENBYAF(AF_INET) << 3; - spidx->prefd = _INALENBYAF(AF_INET) << 3; - spidx->ul_proto = pcb->inp_socket->so_proto->pr_protocol; - _INPORTBYSA(&spidx->src) = pcb->inp_fport; - _INPORTBYSA(&spidx->dst) = pcb->inp_lport; - ipsec4_setspidx_ipaddr(m, spidx); + /* set default */ + spidx->ul_proto = IPSEC_ULPROTO_ANY; + ((struct sockaddr_in *)&spidx->src)->sin_port = IPSEC_PORT_ANY; + ((struct sockaddr_in *)&spidx->dst)->sin_port = IPSEC_PORT_ANY; - spidx = &pcb->inp_sp->sp_out->spidx; - spidx->dir = IPSEC_DIR_OUTBOUND; - sa1 = (struct sockaddr *)&spidx->src; - sa2 = (struct sockaddr *)&spidx->dst; - sa1->sa_len = sa2->sa_len = _SALENBYAF(AF_INET); - sa1->sa_family = sa2->sa_family = AF_INET; - spidx->prefs = _INALENBYAF(AF_INET) << 3; - spidx->prefd = _INALENBYAF(AF_INET) << 3; - spidx->ul_proto = pcb->inp_socket->so_proto->pr_protocol; - _INPORTBYSA(&spidx->src) = pcb->inp_lport; - _INPORTBYSA(&spidx->dst) = pcb->inp_fport; - ipsec4_setspidx_ipaddr(m, spidx); + m_copydata(m, 0, sizeof(ip), (caddr_t)&ip); + /* ip_input() flips it into host endian XXX need more checking */ + if (ip.ip_off & (IP_MF | IP_OFFMASK)) + return; - return; + nxt = ip.ip_p; +#ifdef _IP_VHL + off = _IP_VHL_HL(ip->ip_vhl) << 2; +#else + off = ip.ip_hl << 2; +#endif + while (off < m->m_pkthdr.len) { + switch (nxt) { + case IPPROTO_TCP: + spidx->ul_proto = nxt; + if (!needport) + return; + if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) + return; + m_copydata(m, off, sizeof(th), (caddr_t)&th); + ((struct sockaddr_in *)&spidx->src)->sin_port = + th.th_sport; + ((struct sockaddr_in *)&spidx->dst)->sin_port = + th.th_dport; + return; + case IPPROTO_UDP: + spidx->ul_proto = nxt; + if (!needport) + return; + if (off + sizeof(struct udphdr) > m->m_pkthdr.len) + return; + m_copydata(m, off, sizeof(uh), (caddr_t)&uh); + ((struct sockaddr_in *)&spidx->src)->sin_port = + uh.uh_sport; + ((struct sockaddr_in *)&spidx->dst)->sin_port = + uh.uh_dport; + return; + case IPPROTO_AH: + if (m->m_pkthdr.len > off + sizeof(ip6e)) + return; + m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e); + off += (ip6e.ip6e_len + 2) << 2; + nxt = ip6e.ip6e_nxt; + break; + case IPPROTO_ICMP: + default: + /* XXX intermediate headers??? */ + spidx->ul_proto = nxt; + return; + } + } } -static void +/* assumes that m is sane */ +static int ipsec4_setspidx_ipaddr(m, spidx) struct mbuf *m; struct secpolicyindex *spidx; { struct ip *ip = NULL; struct ip ipbuf; + struct sockaddr_in *sin; - /* sanity check 1 for minimum ip header length */ - if (m == NULL) - panic("ipsec4_setspidx_ipaddr: m == 0 passed.\n"); - - if (m->m_pkthdr.len < sizeof(struct ip)) { - printf("ipsec4_setspidx_ipaddr: " - "pkthdr.len(%d) < sizeof(struct ip), " - "ignored.\n", - m->m_pkthdr.len); - return; - } - - if (m && m->m_len >= sizeof(*ip)) + if (m->m_len >= sizeof(*ip)) ip = mtod(m, struct ip *); else { m_copydata(m, 0, sizeof(ipbuf), (caddr_t)&ipbuf); ip = &ipbuf; } - bcopy(&ip->ip_src, _INADDRBYSA(&spidx->src), sizeof(ip->ip_src)); - bcopy(&ip->ip_dst, _INADDRBYSA(&spidx->dst), sizeof(ip->ip_dst)); + sin = (struct sockaddr_in *)&spidx->src; + bzero(sin, sizeof(*sin)); + sin->sin_family = AF_INET; + sin->sin_len = sizeof(struct sockaddr_in); + bcopy(&ip->ip_src, &sin->sin_addr, sizeof(ip->ip_src)); + spidx->prefs = sizeof(struct in_addr) << 3; - return; + sin = (struct sockaddr_in *)&spidx->dst; + bzero(sin, sizeof(*sin)); + sin->sin_family = AF_INET; + sin->sin_len = sizeof(struct sockaddr_in); + bcopy(&ip->ip_dst, &sin->sin_addr, sizeof(ip->ip_dst)); + spidx->prefd = sizeof(struct in_addr) << 3; + return 0; } #if INET6 static void -ipsec6_setspidx_in6pcb(m, pcb) +ipsec6_get_ulp(m, spidx, needport) struct mbuf *m; - struct in6pcb *pcb; -{ struct secpolicyindex *spidx; - struct sockaddr *sa1, *sa2; + int needport; +{ + int off, nxt; + struct tcphdr th; + struct udphdr uh; /* sanity check */ - if (pcb == NULL) - panic("ipsec6_setspidx_in6pcb: no PCB found.\n"); - if (pcb->in6p_sp == NULL) - panic("ipsec6_setspidx_in6pcb: no in6p_sp found.\n"); - if (pcb->in6p_sp->sp_out ==NULL || pcb->in6p_sp->sp_in == NULL) - panic("ipsec6_setspidx_in6pcb: no sp_in/out found.\n"); + if (m == NULL) + panic("ipsec6_get_ulp: NULL pointer was passed.\n"); - bzero(&pcb->in6p_sp->sp_in->spidx, sizeof(*spidx)); - bzero(&pcb->in6p_sp->sp_out->spidx, sizeof(*spidx)); + KEYDEBUG(KEYDEBUG_IPSEC_DUMP, + printf("ipsec6_get_ulp:\n"); kdebug_mbuf(m)); - spidx = &pcb->in6p_sp->sp_in->spidx; - spidx->dir = IPSEC_DIR_INBOUND; - sa1 = (struct sockaddr *)&spidx->src; - sa2 = (struct sockaddr *)&spidx->dst; - sa1->sa_len = sa2->sa_len = _SALENBYAF(AF_INET6); - sa1->sa_family = sa2->sa_family = AF_INET6; - spidx->prefs = _INALENBYAF(AF_INET6) << 3; - spidx->prefd = _INALENBYAF(AF_INET6) << 3; - spidx->ul_proto = pcb->in6p_socket->so_proto->pr_protocol; - _INPORTBYSA(&spidx->src) = pcb->in6p_fport; - _INPORTBYSA(&spidx->dst) = pcb->in6p_lport; - ipsec6_setspidx_ipaddr(m, spidx); - - spidx = &pcb->in6p_sp->sp_out->spidx; - spidx->dir = IPSEC_DIR_OUTBOUND; - sa1 = (struct sockaddr *)&spidx->src; - sa2 = (struct sockaddr *)&spidx->dst; - sa1->sa_len = sa2->sa_len = _SALENBYAF(AF_INET6); - sa1->sa_family = sa2->sa_family = AF_INET6; - spidx->prefs = _INALENBYAF(AF_INET6) << 3; - spidx->prefd = _INALENBYAF(AF_INET6) << 3; - spidx->ul_proto = pcb->in6p_socket->so_proto->pr_protocol; - _INPORTBYSA(&spidx->src) = pcb->in6p_lport; - _INPORTBYSA(&spidx->dst) = pcb->in6p_fport; - ipsec6_setspidx_ipaddr(m, spidx); + /* set default */ + spidx->ul_proto = IPSEC_ULPROTO_ANY; + ((struct sockaddr_in6 *)&spidx->src)->sin6_port = IPSEC_PORT_ANY; + ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = IPSEC_PORT_ANY; - return; + nxt = -1; + off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt); + if (off < 0 || m->m_pkthdr.len < off) + return; + + switch (nxt) { + case IPPROTO_TCP: + spidx->ul_proto = nxt; + if (!needport) + break; + if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) + break; + m_copydata(m, off, sizeof(th), (caddr_t)&th); + ((struct sockaddr_in6 *)&spidx->src)->sin6_port = th.th_sport; + ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = th.th_dport; + break; + case IPPROTO_UDP: + spidx->ul_proto = nxt; + if (!needport) + break; + if (off + sizeof(struct udphdr) > m->m_pkthdr.len) + break; + m_copydata(m, off, sizeof(uh), (caddr_t)&uh); + ((struct sockaddr_in6 *)&spidx->src)->sin6_port = uh.uh_sport; + ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = uh.uh_dport; + break; + case IPPROTO_ICMPV6: + default: + /* XXX intermediate headers??? */ + spidx->ul_proto = nxt; + break; + } } -static void +/* assumes that m is sane */ +static int ipsec6_setspidx_ipaddr(m, spidx) struct mbuf *m; struct secpolicyindex *spidx; { struct ip6_hdr *ip6 = NULL; struct ip6_hdr ip6buf; - - /* sanity check 1 for minimum ip header length */ - if (m == NULL) - panic("ipsec6_setspidx_in6pcb: m == 0 passed.\n"); - - if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) { - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec6_setspidx_ipaddr: " - "pkthdr.len(%d) < sizeof(struct ip6_hdr), " - "ignored.\n", - m->m_pkthdr.len)); - return; - } + struct sockaddr_in6 *sin6; if (m->m_len >= sizeof(*ip6)) ip6 = mtod(m, struct ip6_hdr *); @@ -1024,18 +1087,29 @@ ipsec6_setspidx_ipaddr(m, spidx) ip6 = &ip6buf; } - if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setspidx_mbuf: " - "wrong ip version on packet " - "(expected IPv6), ignored.\n")); - return; + sin6 = (struct sockaddr_in6 *)&spidx->src; + bzero(sin6, sizeof(*sin6)); + sin6->sin6_family = AF_INET6; + sin6->sin6_len = sizeof(struct sockaddr_in6); + bcopy(&ip6->ip6_src, &sin6->sin6_addr, sizeof(ip6->ip6_src)); + if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) { + sin6->sin6_addr.s6_addr16[1] = 0; + sin6->sin6_scope_id = ntohs(ip6->ip6_src.s6_addr16[1]); } + spidx->prefs = sizeof(struct in6_addr) << 3; - bcopy(&ip6->ip6_src, _INADDRBYSA(&spidx->src), sizeof(ip6->ip6_src)); - bcopy(&ip6->ip6_dst, _INADDRBYSA(&spidx->dst), sizeof(ip6->ip6_dst)); + sin6 = (struct sockaddr_in6 *)&spidx->dst; + bzero(sin6, sizeof(*sin6)); + sin6->sin6_family = AF_INET6; + sin6->sin6_len = sizeof(struct sockaddr_in6); + bcopy(&ip6->ip6_dst, &sin6->sin6_addr, sizeof(ip6->ip6_dst)); + if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { + sin6->sin6_addr.s6_addr16[1] = 0; + sin6->sin6_scope_id = ntohs(ip6->ip6_dst.s6_addr16[1]); + } + spidx->prefd = sizeof(struct in6_addr) << 3; - return; + return 0; } #endif @@ -1052,7 +1126,7 @@ static void ipsec_delpcbpolicy(p) struct inpcbpolicy *p; { - _FREE(p, M_SECA); + FREE(p, M_SECA); } /* initialize policy in PCB */ @@ -1072,32 +1146,17 @@ ipsec_init_policy(so, pcb_sp) ipseclog((LOG_DEBUG, "ipsec_init_policy: No more memory.\n")); return ENOBUFS; } - bzero(new, sizeof(*new)); - -#if defined(__NetBSD__) || defined (__APPLE__) - if (so->so_uid == 0) /*XXX*/ - new->priv = 1; - else - new->priv = 0; -#elif defined(__FreeBSD__) && __FreeBSD__ >= 3 + bzero(new, sizeof(*new)); + +#ifdef __APPLE__ + if (so->so_uid == 0) +#else if (so->so_cred != 0 && so->so_cred->pc_ucred->cr_uid == 0) +#endif new->priv = 1; else new->priv = 0; - KEYDEBUG(KEYDEBUG_IPSEC_DATA, - printf("init: priv=%d ", new->priv); - if (so->so_cred) { - printf("p_ruid=%d ", so->so_cred->p_ruid); - printf("p_svuid=%d ", so->so_cred->p_svuid); - printf("cr_uid=%d\n", so->so_cred->pc_ucred->cr_uid); - } else - printf("so_cred is NULL\n"); - ); -#else - new->priv = so->so_state & SS_PRIV; -#endif - if ((new->sp_in = key_newsp()) == NULL) { ipsec_delpcbpolicy(new); return ENOBUFS; @@ -1125,6 +1184,9 @@ ipsec_copy_policy(old, new) { struct secpolicy *sp; + if (ipsec_bypass != 0) + return 0; + sp = ipsec_deepcopy_policy(old->sp_in); if (sp) { key_freesp(new->sp_in); @@ -1196,7 +1258,7 @@ ipsec_deepcopy_policy(src) fail: for (p = newchain; p; p = r) { r = p->next; - _FREE(p, M_SECA); + FREE(p, M_SECA); p = NULL; } return NULL; @@ -1268,11 +1330,7 @@ ipsec_get_policy(pcb_sp, mp) return ENOBUFS; } -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) (*mp)->m_type = MT_DATA; -#else - (*mp)->m_type = MT_SOOPTS; -#endif KEYDEBUG(KEYDEBUG_IPSEC_DUMP, printf("ipsec_get_policy:\n"); kdebug_mbuf(*mp)); @@ -1290,6 +1348,7 @@ ipsec4_set_policy(inp, optname, request, len, priv) { struct sadb_x_policy *xpl; struct secpolicy **pcb_sp; + int error = 0; /* sanity check. */ if (inp == NULL || request == NULL) @@ -1298,6 +1357,12 @@ ipsec4_set_policy(inp, optname, request, len, priv) return EINVAL; xpl = (struct sadb_x_policy *)request; + if (inp->inp_sp == NULL) { + error = ipsec_init_policy(inp->inp_socket, &inp->inp_sp); + if (error) + return error; + } + /* select direction */ switch (xpl->sadb_x_policy_dir) { case IPSEC_DIR_INBOUND: @@ -1312,6 +1377,10 @@ ipsec4_set_policy(inp, optname, request, len, priv) return EINVAL; } + /* turn bypass off */ + if (ipsec_bypass != 0) + ipsec_bypass = 0; + return ipsec_set_policy(pcb_sp, optname, request, len, priv); } @@ -1324,15 +1393,20 @@ ipsec4_get_policy(inp, request, len, mp) { struct sadb_x_policy *xpl; struct secpolicy *pcb_sp; + int error = 0; /* sanity check. */ if (inp == NULL || request == NULL || mp == NULL) return EINVAL; - if (inp->inp_sp == NULL) - panic("policy in PCB is NULL\n"); if (len < sizeof(*xpl)) return EINVAL; xpl = (struct sadb_x_policy *)request; + + if (inp->inp_sp == NULL) { + error = ipsec_init_policy(inp->inp_socket, &inp->inp_sp); + if (error) + return error; + } /* select direction */ switch (xpl->sadb_x_policy_dir) { @@ -1390,6 +1464,7 @@ ipsec6_set_policy(in6p, optname, request, len, priv) { struct sadb_x_policy *xpl; struct secpolicy **pcb_sp; + int error = 0; /* sanity check. */ if (in6p == NULL || request == NULL) @@ -1397,6 +1472,12 @@ ipsec6_set_policy(in6p, optname, request, len, priv) if (len < sizeof(*xpl)) return EINVAL; xpl = (struct sadb_x_policy *)request; + + if (in6p->in6p_sp == NULL) { + error = ipsec_init_policy(in6p->inp_socket, &in6p->in6p_sp); + if (error) + return error; + } /* select direction */ switch (xpl->sadb_x_policy_dir) { @@ -1412,6 +1493,10 @@ ipsec6_set_policy(in6p, optname, request, len, priv) return EINVAL; } + /* turn bypass off */ + if (ipsec_bypass != 0) + ipsec_bypass = 0; + return ipsec_set_policy(pcb_sp, optname, request, len, priv); } @@ -1424,15 +1509,20 @@ ipsec6_get_policy(in6p, request, len, mp) { struct sadb_x_policy *xpl; struct secpolicy *pcb_sp; + int error = 0; /* sanity check. */ if (in6p == NULL || request == NULL || mp == NULL) return EINVAL; - if (in6p->in6p_sp == NULL) - panic("policy in PCB is NULL\n"); if (len < sizeof(*xpl)) return EINVAL; xpl = (struct sadb_x_policy *)request; + + if (in6p->in6p_sp == NULL) { + error = ipsec_init_policy(in6p->inp_socket, &in6p->in6p_sp); + if (error) + return error; + } /* select direction */ switch (xpl->sadb_x_policy_dir) { @@ -1532,7 +1622,7 @@ ipsec_get_reqlevel(isr) ((struct sockaddr *)&isr->sp->spidx.src)->sa_family); } -#undef IPSEC_CHECK_DEFAULT(lev) +#undef IPSEC_CHECK_DEFAULT /* set level */ switch (isr->level) { @@ -1618,6 +1708,8 @@ ipsec_in_reject(sp, m) need_conf = 0; need_icv = 0; + /* XXX should compare policy against ipsec header history */ + for (isr = sp->req; isr != NULL; isr = isr->next) { /* get current level */ @@ -1643,7 +1735,8 @@ ipsec_in_reject(sp, m) case IPPROTO_IPCOMP: /* * we don't really care, as IPcomp document says that - * we shouldn't compress small packets + * we shouldn't compress small packets, IPComp policy + * should always be treated as being in "use" level. */ break; } @@ -1707,12 +1800,10 @@ ipsec4_in_reject(m, inp) { if (inp == NULL) return ipsec4_in_reject_so(m, NULL); - else { - if (inp->inp_socket) - return ipsec4_in_reject_so(m, inp->inp_socket); - else - panic("ipsec4_in_reject: invalid inpcb/socket"); - } + if (inp->inp_socket) + return ipsec4_in_reject_so(m, inp->inp_socket); + else + panic("ipsec4_in_reject: invalid inpcb/socket"); } #if INET6 @@ -1761,12 +1852,10 @@ ipsec6_in_reject(m, in6p) { if (in6p == NULL) return ipsec6_in_reject_so(m, NULL); - else { - if (in6p->in6p_socket) - return ipsec6_in_reject_so(m, in6p->in6p_socket); - else - panic("ipsec6_in_reject: invalid in6p/socket"); - } + if (in6p->in6p_socket) + return ipsec6_in_reject_so(m, in6p->in6p_socket); + else + panic("ipsec6_in_reject: invalid in6p/socket"); } #endif @@ -1949,7 +2038,7 @@ ipsec4_encapsulate(m, sav) } #if 0 /* XXX if the dst is myself, perform nothing. */ - if (key_ismyaddr(AF_INET, _INADDRBYSA(&sav->sah->saidx.dst))) { + if (key_ismyaddr((struct sockaddr *)&sav->sah->saidx.dst)) { m_freem(m); return EINVAL; } @@ -1960,7 +2049,7 @@ ipsec4_encapsulate(m, sav) ip = mtod(m, struct ip *); #ifdef _IP_VHL - hlen = IP_VHL_HL(ip->ip_vhl) << 2; + hlen = _IP_VHL_HL(ip->ip_vhl) << 2; #else hlen = ip->ip_hl << 2; #endif @@ -2032,11 +2121,16 @@ ipsec4_encapsulate(m, sav) ipseclog((LOG_ERR, "IPv4 ipsec: size exceeds limit: " "leave ip_len as is (invalid packet)\n")); } +#ifdef RANDOM_IP_ID + ip->ip_id = ip_randomid(); +#else ip->ip_id = htons(ip_id++); +#endif bcopy(&((struct sockaddr_in *)&sav->sah->saidx.src)->sin_addr, &ip->ip_src, sizeof(ip->ip_src)); bcopy(&((struct sockaddr_in *)&sav->sah->saidx.dst)->sin_addr, &ip->ip_dst, sizeof(ip->ip_dst)); + ip->ip_ttl = IPDEFTTL; /* XXX Should ip_src be updated later ? */ @@ -2063,7 +2157,7 @@ ipsec6_encapsulate(m, sav) } #if 0 /* XXX if the dst is myself, perform nothing. */ - if (key_ismyaddr(AF_INET6, _INADDRBYSA(&sav->sah->saidx.dst))) { + if (key_ismyaddr((struct sockaddr *)&sav->sah->saidx.dst)) { m_freem(m); return EINVAL; } @@ -2116,6 +2210,7 @@ ipsec6_encapsulate(m, sav) &ip6->ip6_src, sizeof(ip6->ip6_src)); bcopy(&((struct sockaddr_in6 *)&sav->sah->saidx.dst)->sin6_addr, &ip6->ip6_dst, sizeof(ip6->ip6_dst)); + ip6->ip6_hlim = IPV6_DEFHLIM; /* XXX Should ip6_src be updated later ? */ @@ -2328,11 +2423,11 @@ ipsec4_logpacketstr(ip, spi) snprintf(buf, sizeof(buf), "packet(SPI=%u ", (u_int32_t)ntohl(spi)); while (p && *p) p++; - snprintf(p, sizeof(buf) - (p - buf), "src=%d.%d.%d.%d", + snprintf(p, sizeof(buf) - (p - buf), "src=%u.%u.%u.%u", s[0], s[1], s[2], s[3]); while (p && *p) p++; - snprintf(p, sizeof(buf) - (p - buf), " dst=%d.%d.%d.%d", + snprintf(p, sizeof(buf) - (p - buf), " dst=%u.%u.%u.%u", d[0], d[1], d[2], d[3]); while (p && *p) p++; @@ -2437,6 +2532,7 @@ ipsec_dumpmbuf(m) printf("---\n"); } +#if INET /* * IPsec output logic for IPv4. */ @@ -2451,11 +2547,8 @@ ipsec4_output(state, sp, flags) struct secasindex saidx; int s; int error; -#if IPSEC_SRCSEL - struct in_ifaddr *ia; -#endif struct sockaddr_in *dst4; - struct sockaddr *sa; + struct sockaddr_in *sin; if (!state) panic("state == NULL in ipsec4_output"); @@ -2486,21 +2579,23 @@ ipsec4_output(state, sp, flags) /* make SA index for search proper SA */ ip = mtod(state->m, struct ip *); bcopy(&isr->saidx, &saidx, sizeof(saidx)); - sa = (struct sockaddr *)&saidx.src; - if (sa->sa_len == 0) { - sa->sa_len = _SALENBYAF(AF_INET); - sa->sa_family = AF_INET; - _INPORTBYSA(&saidx.src) = IPSEC_PORT_ANY; - bcopy(&ip->ip_src, _INADDRBYSA(&saidx.src), - sizeof(ip->ip_src)); + saidx.mode = isr->saidx.mode; + saidx.reqid = isr->saidx.reqid; + sin = (struct sockaddr_in *)&saidx.src; + if (sin->sin_len == 0) { + sin->sin_len = sizeof(*sin); + sin->sin_family = AF_INET; + sin->sin_port = IPSEC_PORT_ANY; + bcopy(&ip->ip_src, &sin->sin_addr, + sizeof(sin->sin_addr)); } - sa = (struct sockaddr *)&saidx.dst; - if (sa->sa_len == 0) { - sa->sa_len = _SALENBYAF(AF_INET); - sa->sa_family = AF_INET; - _INPORTBYSA(&saidx.dst) = IPSEC_PORT_ANY; - bcopy(&ip->ip_dst, _INADDRBYSA(&saidx.dst), - sizeof(ip->ip_dst)); + sin = (struct sockaddr_in *)&saidx.dst; + if (sin->sin_len == 0) { + sin->sin_len = sizeof(*sin); + sin->sin_family = AF_INET; + sin->sin_port = IPSEC_PORT_ANY; + bcopy(&ip->ip_dst, &sin->sin_addr, + sizeof(sin->sin_addr)); } if ((error = key_checkrequest(isr, &saidx)) != 0) { @@ -2544,11 +2639,7 @@ ipsec4_output(state, sp, flags) * There may be the case that SA status will be changed when * we are refering to one. So calling splsoftnet(). */ -#if __NetBSD__ - s = splsoftnet(); -#else s = splnet(); -#endif if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { /* @@ -2564,8 +2655,6 @@ ipsec4_output(state, sp, flags) goto bad; } - ip = mtod(state->m, struct ip *); - state->m = ipsec4_splithdr(state->m); if (!state->m) { splx(s); @@ -2586,8 +2675,8 @@ ipsec4_output(state, sp, flags) if (state->ro->ro_rt && ((state->ro->ro_rt->rt_flags & RTF_UP) == 0 || dst4->sin_addr.s_addr != ip->ip_dst.s_addr)) { - RTFREE(state->ro->ro_rt); - bzero((caddr_t)state->ro, sizeof (*state->ro)); + rtfree(state->ro->ro_rt); + state->ro->ro_rt = NULL; } if (state->ro->ro_rt == 0) { dst4->sin_family = AF_INET; @@ -2601,19 +2690,11 @@ ipsec4_output(state, sp, flags) goto bad; } -#if IPSEC_SRCSEL - /* - * Which address in SA or in routing table should I - * select from ? But I had set from SA at - * ipsec4_encapsulate(). - */ - ia = (struct in_ifaddr *)(state->ro->ro_rt->rt_ifa); + /* adjust state->dst if tunnel endpoint is offlink */ if (state->ro->ro_rt->rt_flags & RTF_GATEWAY) { state->dst = (struct sockaddr *)state->ro->ro_rt->rt_gateway; dst4 = (struct sockaddr_in *)state->dst; } - ip->ip_src = IA_SIN(ia)->sin_addr; -#endif } else splx(s); @@ -2672,6 +2753,7 @@ bad: state->m = NULL; return error; } +#endif #if INET6 /* @@ -2691,7 +2773,7 @@ ipsec6_output_trans(state, nexthdrp, mprev, sp, flags, tun) struct secasindex saidx; int error = 0; int plen; - struct sockaddr *sa; + struct sockaddr_in6 *sin6; if (!state) panic("state == NULL in ipsec6_output"); @@ -2720,21 +2802,33 @@ ipsec6_output_trans(state, nexthdrp, mprev, sp, flags, tun) /* make SA index for search proper SA */ ip6 = mtod(state->m, struct ip6_hdr *); bcopy(&isr->saidx, &saidx, sizeof(saidx)); - sa = (struct sockaddr *)&saidx.src; - if (sa->sa_len == 0) { - sa->sa_len = _SALENBYAF(AF_INET6); - sa->sa_family = AF_INET6; - _INPORTBYSA(&saidx.src) = IPSEC_PORT_ANY; - bcopy(&ip6->ip6_src, _INADDRBYSA(&saidx.src), - sizeof(ip6->ip6_src)); + saidx.mode = isr->saidx.mode; + saidx.reqid = isr->saidx.reqid; + sin6 = (struct sockaddr_in6 *)&saidx.src; + if (sin6->sin6_len == 0) { + sin6->sin6_len = sizeof(*sin6); + sin6->sin6_family = AF_INET6; + sin6->sin6_port = IPSEC_PORT_ANY; + bcopy(&ip6->ip6_src, &sin6->sin6_addr, + sizeof(ip6->ip6_src)); + if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) { + /* fix scope id for comparing SPD */ + sin6->sin6_addr.s6_addr16[1] = 0; + sin6->sin6_scope_id = ntohs(ip6->ip6_src.s6_addr16[1]); + } } - sa = (struct sockaddr *)&saidx.dst; - if (sa->sa_len == 0) { - sa->sa_len = _SALENBYAF(AF_INET6); - sa->sa_family = AF_INET6; - _INPORTBYSA(&saidx.dst) = IPSEC_PORT_ANY; - bcopy(&ip6->ip6_dst, _INADDRBYSA(&saidx.dst), - sizeof(ip6->ip6_dst)); + sin6 = (struct sockaddr_in6 *)&saidx.dst; + if (sin6->sin6_len == 0) { + sin6->sin6_len = sizeof(*sin6); + sin6->sin6_family = AF_INET6; + sin6->sin6_port = IPSEC_PORT_ANY; + bcopy(&ip6->ip6_dst, &sin6->sin6_addr, + sizeof(ip6->ip6_dst)); + if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { + /* fix scope id for comparing SPD */ + sin6->sin6_addr.s6_addr16[1] = 0; + sin6->sin6_scope_id = ntohs(ip6->ip6_dst.s6_addr16[1]); + } } if (key_checkrequest(isr, &saidx) == ENOENT) { @@ -2747,6 +2841,18 @@ ipsec6_output_trans(state, nexthdrp, mprev, sp, flags, tun) */ ipsec6stat.out_nosa++; error = ENOENT; + + /* + * Notify the fact that the packet is discarded + * to ourselves. I believe this is better than + * just silently discarding. (jinmei@kame.net) + * XXX: should we restrict the error to TCP packets? + * XXX: should we directly notify sockets via + * pfctlinputs? + */ + icmp6_error(state->m, ICMP6_DST_UNREACH, + ICMP6_DST_UNREACH_ADMIN, 0); + state->m = NULL; /* icmp6_error freed the mbuf */ goto bad; } @@ -2837,9 +2943,6 @@ ipsec6_output_tunnel(state, sp, flags) struct secasindex saidx; int error = 0; int plen; -#if IPSEC_SRCSEL - struct in6_addr *ia6; -#endif struct sockaddr_in6* dst6; int s; @@ -2905,11 +3008,7 @@ ipsec6_output_tunnel(state, sp, flags) * There may be the case that SA status will be changed when * we are refering to one. So calling splsoftnet(). */ -#if __NetBSD__ - s = splsoftnet(); -#else s = splnet(); -#endif if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { /* @@ -2926,8 +3025,6 @@ ipsec6_output_tunnel(state, sp, flags) goto bad; } - ip6 = mtod(state->m, struct ip6_hdr *); - state->m = ipsec6_splithdr(state->m); if (!state->m) { splx(s); @@ -2949,8 +3046,8 @@ ipsec6_output_tunnel(state, sp, flags) if (state->ro->ro_rt && ((state->ro->ro_rt->rt_flags & RTF_UP) == 0 || !IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr, &ip6->ip6_dst))) { - RTFREE(state->ro->ro_rt); - bzero((caddr_t)state->ro, sizeof (*state->ro)); + rtfree(state->ro->ro_rt); + state->ro->ro_rt = NULL; } if (state->ro->ro_rt == 0) { bzero(dst6, sizeof(*dst6)); @@ -2965,28 +3062,12 @@ ipsec6_output_tunnel(state, sp, flags) error = EHOSTUNREACH; goto bad; } -#if 0 /* XXX Is the following need ? */ + + /* adjust state->dst if tunnel endpoint is offlink */ if (state->ro->ro_rt->rt_flags & RTF_GATEWAY) { state->dst = (struct sockaddr *)state->ro->ro_rt->rt_gateway; dst6 = (struct sockaddr_in6 *)state->dst; } -#endif -#if IPSEC_SRCSEL - /* - * Which address in SA or in routing table should I - * select from ? But I had set from SA at - * ipsec6_encapsulate(). - */ - ia6 = in6_selectsrc(dst6, NULL, NULL, - (struct route_in6 *)state->ro, - NULL, &error); - if (ia6 == NULL) { - ip6stat.ip6s_noroute++; - ipsec6stat.out_noroute++; - goto bad; - } - ip6->ip6_src = *ia6; -#endif } else splx(s); @@ -3045,6 +3126,7 @@ bad: } #endif /*INET6*/ +#if INET /* * Chop IP header and option off from the payload. */ @@ -3060,7 +3142,7 @@ ipsec4_splithdr(m) panic("ipsec4_splithdr: first mbuf too short"); ip = mtod(m, struct ip *); #ifdef _IP_VHL - hlen = IP_VHL_HL(ip->ip_vhl) << 2; + hlen = _IP_VHL_HL(ip->ip_vhl) << 2; #else hlen = ip->ip_hl << 2; #endif @@ -3086,6 +3168,7 @@ ipsec4_splithdr(m) } return m; } +#endif #if INET6 static struct mbuf * @@ -3126,38 +3209,89 @@ ipsec6_splithdr(m) /* validate inbound IPsec tunnel packet. */ int -ipsec4_tunnel_validate(ip, nxt0, sav) - struct ip *ip; +ipsec4_tunnel_validate(m, off, nxt0, sav) + struct mbuf *m; /* no pullup permitted, m->m_len >= ip */ + int off; u_int nxt0; struct secasvar *sav; { u_int8_t nxt = nxt0 & 0xff; struct sockaddr_in *sin; + struct sockaddr_in osrc, odst, isrc, idst; int hlen; + struct secpolicy *sp; + struct ip *oip; +#if DIAGNOSTIC + if (m->m_len < sizeof(struct ip)) + panic("too short mbuf on ipsec4_tunnel_validate"); +#endif if (nxt != IPPROTO_IPV4) return 0; + if (m->m_pkthdr.len < off + sizeof(struct ip)) + return 0; + /* do not decapsulate if the SA is for transport mode only */ + if (sav->sah->saidx.mode == IPSEC_MODE_TRANSPORT) + return 0; + + oip = mtod(m, struct ip *); #ifdef _IP_VHL - hlen = IP_VHL_HL(ip->ip_vhl) << 2; + hlen = _IP_VHL_HL(oip->ip_vhl) << 2; #else - hlen = ip->ip_hl << 2; + hlen = oip->ip_hl << 2; #endif if (hlen != sizeof(struct ip)) return 0; - switch (((struct sockaddr *)&sav->sah->saidx.dst)->sa_family) { - case AF_INET: - sin = (struct sockaddr_in *)&sav->sah->saidx.dst; - if (bcmp(&ip->ip_dst, &sin->sin_addr, sizeof(ip->ip_dst)) != 0) - return 0; - break; -#if INET6 - case AF_INET6: - /* should be supported, but at this moment we don't. */ - /*FALLTHROUGH*/ -#endif - default: + + /* AF_INET6 should be supported, but at this moment we don't. */ + sin = (struct sockaddr_in *)&sav->sah->saidx.dst; + if (sin->sin_family != AF_INET) return 0; - } + if (bcmp(&oip->ip_dst, &sin->sin_addr, sizeof(oip->ip_dst)) != 0) + return 0; + + /* XXX slow */ + bzero(&osrc, sizeof(osrc)); + bzero(&odst, sizeof(odst)); + bzero(&isrc, sizeof(isrc)); + bzero(&idst, sizeof(idst)); + osrc.sin_family = odst.sin_family = isrc.sin_family = idst.sin_family = + AF_INET; + osrc.sin_len = odst.sin_len = isrc.sin_len = idst.sin_len = + sizeof(struct sockaddr_in); + osrc.sin_addr = oip->ip_src; + odst.sin_addr = oip->ip_dst; + m_copydata(m, off + offsetof(struct ip, ip_src), sizeof(isrc.sin_addr), + (caddr_t)&isrc.sin_addr); + m_copydata(m, off + offsetof(struct ip, ip_dst), sizeof(idst.sin_addr), + (caddr_t)&idst.sin_addr); + + /* + * RFC2401 5.2.1 (b): (assume that we are using tunnel mode) + * - if the inner destination is multicast address, there can be + * multiple permissible inner source address. implementation + * may want to skip verification of inner source address against + * SPD selector. + * - if the inner protocol is ICMP, the packet may be an error report + * from routers on the other side of the VPN cloud (R in the + * following diagram). in this case, we cannot verify inner source + * address against SPD selector. + * me -- gw === gw -- R -- you + * + * we consider the first bullet to be users responsibility on SPD entry + * configuration (if you need to encrypt multicast traffic, set + * the source range of SPD selector to 0.0.0.0/0, or have explicit + * address ranges for possible senders). + * the second bullet is not taken care of (yet). + * + * therefore, we do not do anything special about inner source. + */ + + sp = key_gettunnel((struct sockaddr *)&osrc, (struct sockaddr *)&odst, + (struct sockaddr *)&isrc, (struct sockaddr *)&idst); + if (!sp) + return 0; + key_freesp(sp); return 1; } @@ -3165,28 +3299,64 @@ ipsec4_tunnel_validate(ip, nxt0, sav) #if INET6 /* validate inbound IPsec tunnel packet. */ int -ipsec6_tunnel_validate(ip6, nxt0, sav) - struct ip6_hdr *ip6; +ipsec6_tunnel_validate(m, off, nxt0, sav) + struct mbuf *m; /* no pullup permitted, m->m_len >= ip */ + int off; u_int nxt0; struct secasvar *sav; { u_int8_t nxt = nxt0 & 0xff; struct sockaddr_in6 *sin6; + struct sockaddr_in6 osrc, odst, isrc, idst; + struct secpolicy *sp; + struct ip6_hdr *oip6; +#if DIAGNOSTIC + if (m->m_len < sizeof(struct ip6_hdr)) + panic("too short mbuf on ipsec6_tunnel_validate"); +#endif if (nxt != IPPROTO_IPV6) return 0; - switch (((struct sockaddr *)&sav->sah->saidx.dst)->sa_family) { - case AF_INET6: - sin6 = ((struct sockaddr_in6 *)&sav->sah->saidx.dst); - if (!IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &sin6->sin6_addr)) - return 0; - break; - case AF_INET: - /* should be supported, but at this moment we don't. */ - /*FALLTHROUGH*/ - default: + if (m->m_pkthdr.len < off + sizeof(struct ip6_hdr)) + return 0; + /* do not decapsulate if the SA is for transport mode only */ + if (sav->sah->saidx.mode == IPSEC_MODE_TRANSPORT) + return 0; + + oip6 = mtod(m, struct ip6_hdr *); + /* AF_INET should be supported, but at this moment we don't. */ + sin6 = (struct sockaddr_in6 *)&sav->sah->saidx.dst; + if (sin6->sin6_family != AF_INET6) + return 0; + if (!IN6_ARE_ADDR_EQUAL(&oip6->ip6_dst, &sin6->sin6_addr)) return 0; - } + + /* XXX slow */ + bzero(&osrc, sizeof(osrc)); + bzero(&odst, sizeof(odst)); + bzero(&isrc, sizeof(isrc)); + bzero(&idst, sizeof(idst)); + osrc.sin6_family = odst.sin6_family = isrc.sin6_family = + idst.sin6_family = AF_INET6; + osrc.sin6_len = odst.sin6_len = isrc.sin6_len = idst.sin6_len = + sizeof(struct sockaddr_in6); + osrc.sin6_addr = oip6->ip6_src; + odst.sin6_addr = oip6->ip6_dst; + m_copydata(m, off + offsetof(struct ip6_hdr, ip6_src), + sizeof(isrc.sin6_addr), (caddr_t)&isrc.sin6_addr); + m_copydata(m, off + offsetof(struct ip6_hdr, ip6_dst), + sizeof(idst.sin6_addr), (caddr_t)&idst.sin6_addr); + + /* + * regarding to inner source address validation, see a long comment + * in ipsec4_tunnel_validate. + */ + + sp = key_gettunnel((struct sockaddr *)&osrc, (struct sockaddr *)&odst, + (struct sockaddr *)&isrc, (struct sockaddr *)&idst); + if (!sp) + return 0; + key_freesp(sp); return 1; } @@ -3213,16 +3383,8 @@ ipsec_copypkt(m) * XXX: is this approach effective? */ if ( -#if __bsdi__ - n->m_ext.ext_func || -#else n->m_ext.ext_free || -#endif -#if __NetBSD__ - MCLISREFERENCED(n) -#else mclrefcnt[mtocl(n->m_ext.ext_buf)] > 1 -#endif ) { int remain, copied; @@ -3261,7 +3423,7 @@ ipsec_copypkt(m) */ remain = n->m_len; copied = 0; - while(1) { + while (1) { int len; struct mbuf *mn; @@ -3291,6 +3453,7 @@ ipsec_copypkt(m) MGETHDR(mn, M_DONTWAIT, MT_HEADER); if (mn == NULL) goto fail; + mn->m_pkthdr.rcvif = NULL; mm->m_next = mn; mm = mn; } @@ -3314,355 +3477,146 @@ ipsec_copypkt(m) return(NULL); } -void -ipsec_setsocket(m, so) +static struct mbuf * +ipsec_addaux(m) struct mbuf *m; - struct socket *so; { struct mbuf *n; n = m_aux_find(m, AF_INET, IPPROTO_ESP); - if (so && !n) + if (!n) n = m_aux_add(m, AF_INET, IPPROTO_ESP); - if (n) { - if (so) { - *mtod(n, struct socket **) = so; - /* - * XXX think again about it when we put decryption - * histrory into aux mbuf - */ - n->m_len = sizeof(struct socket *); - } else - m_aux_delete(m, n); - } + if (!n) + return n; /* ENOBUFS */ + n->m_len = sizeof(struct socket *); + bzero(mtod(n, void *), n->m_len); + return n; } -struct socket * -ipsec_getsocket(m) +static struct mbuf * +ipsec_findaux(m) struct mbuf *m; { struct mbuf *n; n = m_aux_find(m, AF_INET, IPPROTO_ESP); - if (n && n->m_len >= sizeof(struct socket *)) - return *mtod(n, struct socket **); - else - return NULL; +#if DIAGNOSTIC + if (n && n->m_len < sizeof(struct socket *)) + panic("invalid ipsec m_aux"); +#endif + return n; } -#ifdef __bsdi__ -/* - * System control for IP - */ -u_char ipsecctlerrmap[PRC_NCMDS] = { - 0, 0, 0, 0, - 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, - EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, - EMSGSIZE, EHOSTUNREACH, 0, 0, - 0, 0, 0, 0, - ENOPROTOOPT -}; - -int *ipsec_sysvars[] = IPSECCTL_VARS; - -int -ipsec_sysctl(name, namelen, oldp, oldlenp, newp, newlen) - int *name; - u_int namelen; - void *oldp; - size_t *oldlenp; - void *newp; - size_t newlen; +void +ipsec_delaux(m) + struct mbuf *m; { - if (name[0] >= IPSECCTL_MAXID) - return (EOPNOTSUPP); - - switch (name[0]) { - case IPSECCTL_STATS: - return sysctl_rdtrunc(oldp, oldlenp, newp, &ipsecstat, - sizeof(ipsecstat)); - case IPSECCTL_DEF_POLICY: - if (newp != NULL && newlen == sizeof(int)) { - switch (*(int *)newp) { - case IPSEC_POLICY_DISCARD: - case IPSEC_POLICY_NONE: - break; - default: - return EINVAL; - } - } - return (sysctl_int_arr(ipsec_sysvars, name, namelen, - oldp, oldlenp, newp, newlen)); - case IPSECCTL_DEF_ESP_TRANSLEV: - case IPSECCTL_DEF_ESP_NETLEV: - case IPSECCTL_DEF_AH_TRANSLEV: - case IPSECCTL_DEF_AH_NETLEV: - if (newp != NULL && newlen == sizeof(int)) { - switch (*(int *)newp) { - case IPSEC_LEVEL_USE: - case IPSEC_LEVEL_REQUIRE: - break; - default: - return EINVAL; - } - } - return (sysctl_int_arr(ipsec_sysvars, name, namelen, - oldp, oldlenp, newp, newlen)); - default: - return (sysctl_int_arr(ipsec_sysvars, name, namelen, - oldp, oldlenp, newp, newlen)); - } + struct mbuf *n; + + n = m_aux_find(m, AF_INET, IPPROTO_ESP); + if (n) + m_aux_delete(m, n); } -#if INET6 -/* - * System control for IP6 - */ -u_char ipsec6ctlerrmap[PRC_NCMDS] = { - 0, 0, 0, 0, - 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, - EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, - EMSGSIZE, EHOSTUNREACH, 0, 0, - 0, 0, 0, 0, - ENOPROTOOPT -}; +/* if the aux buffer is unnecessary, nuke it. */ +static void +ipsec_optaux(m, n) + struct mbuf *m; + struct mbuf *n; +{ -int *ipsec6_sysvars[] = IPSEC6CTL_VARS; + if (!n) + return; + if (n->m_len == sizeof(struct socket *) && !*mtod(n, struct socket **)) + ipsec_delaux(m); +} int -ipsec6_sysctl(name, namelen, oldp, oldlenp, newp, newlen) - int *name; - u_int namelen; - void *oldp; - size_t *oldlenp; - void *newp; - size_t newlen; +ipsec_setsocket(m, so) + struct mbuf *m; + struct socket *so; { - if (name[0] >= IPSECCTL_MAXID) /* xxx no 6 in this definition */ - return (EOPNOTSUPP); - - switch (name[0]) { - case IPSECCTL_STATS: /* xxx no 6 in this definition */ - return sysctl_rdtrunc(oldp, oldlenp, newp, &ipsec6stat, - sizeof(ipsec6stat)); - case IPSECCTL_DEF_POLICY: - if (newp != NULL && newlen == sizeof(int)) { - switch (*(int *)newp) { - case IPSEC_POLICY_DISCARD: - case IPSEC_POLICY_NONE: - break; - default: - return EINVAL; - } - } - return (sysctl_int_arr(ipsec6_sysvars, name, namelen, - oldp, oldlenp, newp, newlen)); - case IPSECCTL_DEF_ESP_TRANSLEV: - case IPSECCTL_DEF_ESP_NETLEV: - case IPSECCTL_DEF_AH_TRANSLEV: - case IPSECCTL_DEF_AH_NETLEV: - if (newp != NULL && newlen == sizeof(int)) { - switch (*(int *)newp) { - case IPSEC_LEVEL_USE: - case IPSEC_LEVEL_REQUIRE: - break; - default: - return EINVAL; - } - } - return (sysctl_int_arr(ipsec6_sysvars, name, namelen, - oldp, oldlenp, newp, newlen)); - default: - return (sysctl_int_arr(ipsec6_sysvars, name, namelen, - oldp, oldlenp, newp, newlen)); - } -} -#endif /*INET6*/ -#endif /*__bsdi__*/ + struct mbuf *n; + /* if so == NULL, don't insist on getting the aux mbuf */ + if (so) { + n = ipsec_addaux(m); + if (!n) + return ENOBUFS; + } else + n = ipsec_findaux(m); + if (n && n->m_len >= sizeof(struct socket *)) + *mtod(n, struct socket **) = so; + ipsec_optaux(m, n); + return 0; +} -#if __NetBSD__ -/* - * System control for IPSEC - */ -u_char ipsecctlermap[PRC_NCMDS] = { - 0, 0, 0, 0, - 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, - EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, - EMSGSIZE, EHOSTUNREACH, 0, 0, - 0, 0, 0, 0, - ENOPROTOOPT -}; +struct socket * +ipsec_getsocket(m) + struct mbuf *m; +{ + struct mbuf *n; -int *ipsec_sysvars[] = IPSECCTL_VARS; + n = ipsec_findaux(m); + if (n && n->m_len >= sizeof(struct socket *)) + return *mtod(n, struct socket **); + else + return NULL; +} int -ipsec_sysctl(name, namelen, oldp, oldlenp, newp, newlen) - int *name; - u_int namelen; - void *oldp; - size_t *oldlenp; - void *newp; - size_t newlen; +ipsec_addhist(m, proto, spi) + struct mbuf *m; + int proto; + u_int32_t spi; { - /* All sysctl names at this level are terminal. */ - if (namelen != 1) - return ENOTDIR; - - /* common sanity checks */ - switch (name[0]) { - case IPSECCTL_DEF_ESP_TRANSLEV: - case IPSECCTL_DEF_ESP_NETLEV: - case IPSECCTL_DEF_AH_TRANSLEV: - case IPSECCTL_DEF_AH_NETLEV: - if (newp != NULL && newlen == sizeof(int)) { - switch (*(int *)newp) { - case IPSEC_LEVEL_USE: - case IPSEC_LEVEL_REQUIRE: - break; - default: - return EINVAL; - } - } - } - - switch (name[0]) { + struct mbuf *n; + struct ipsec_history *p; - case IPSECCTL_STATS: - return sysctl_struct(oldp, oldlenp, newp, newlen, - &ipsecstat, sizeof(ipsecstat)); - case IPSECCTL_DEF_POLICY: - if (newp != NULL && newlen == sizeof(int)) { - switch (*(int *)newp) { - case IPSEC_POLICY_DISCARD: - case IPSEC_POLICY_NONE: - break; - default: - return EINVAL; - } - } - return sysctl_int(oldp, oldlenp, newp, newlen, - &ip4_def_policy.policy); - case IPSECCTL_DEF_ESP_TRANSLEV: - return sysctl_int(oldp, oldlenp, newp, newlen, - &ip4_esp_trans_deflev); - case IPSECCTL_DEF_ESP_NETLEV: - return sysctl_int(oldp, oldlenp, newp, newlen, - &ip4_esp_net_deflev); - case IPSECCTL_DEF_AH_TRANSLEV: - return sysctl_int(oldp, oldlenp, newp, newlen, - &ip4_ah_trans_deflev); - case IPSECCTL_DEF_AH_NETLEV: - return sysctl_int(oldp, oldlenp, newp, newlen, - &ip4_ah_net_deflev); - case IPSECCTL_INBOUND_CALL_IKE: - return sysctl_int(oldp, oldlenp, newp, newlen, - &ip4_inbound_call_ike); - case IPSECCTL_AH_CLEARTOS: - return sysctl_int(oldp, oldlenp, newp, newlen, - &ip4_ah_cleartos); - case IPSECCTL_AH_OFFSETMASK: - return sysctl_int(oldp, oldlenp, newp, newlen, - &ip4_ah_offsetmask); - case IPSECCTL_DFBIT: - return sysctl_int(oldp, oldlenp, newp, newlen, - &ip4_ipsec_dfbit); - case IPSECCTL_ECN: - return sysctl_int(oldp, oldlenp, newp, newlen, &ip4_ipsec_ecn); - case IPSECCTL_DEBUG: - return sysctl_int(oldp, oldlenp, newp, newlen, &ipsec_debug); - default: - return EOPNOTSUPP; - } - /* NOTREACHED */ + n = ipsec_addaux(m); + if (!n) + return ENOBUFS; + if (M_TRAILINGSPACE(n) < sizeof(*p)) + return ENOSPC; /*XXX*/ + p = (struct ipsec_history *)(mtod(n, caddr_t) + n->m_len); + n->m_len += sizeof(*p); + bzero(p, sizeof(*p)); + p->ih_proto = proto; + p->ih_spi = spi; + return 0; } -#if INET6 -/* - * System control for IPSEC6 - */ -u_char ipsec6ctlermap[PRC_NCMDS] = { - 0, 0, 0, 0, - 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, - EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, - EMSGSIZE, EHOSTUNREACH, 0, 0, - 0, 0, 0, 0, - ENOPROTOOPT -}; +struct ipsec_history * +ipsec_gethist(m, lenp) + struct mbuf *m; + int *lenp; +{ + struct mbuf *n; + int l; -int *ipsec6_sysvars[] = IPSEC6CTL_VARS; + n = ipsec_findaux(m); + if (!n) + return NULL; + l = n->m_len; + if (sizeof(struct socket *) > l) + return NULL; + if ((l - sizeof(struct socket *)) % sizeof(struct ipsec_history)) + return NULL; + /* XXX does it make more sense to divide by sizeof(ipsec_history)? */ + if (lenp) + *lenp = l - sizeof(struct socket *); + return (struct ipsec_history *) + (mtod(n, caddr_t) + sizeof(struct socket *)); +} -int -ipsec6_sysctl(name, namelen, oldp, oldlenp, newp, newlen) - int *name; - u_int namelen; - void *oldp; - size_t *oldlenp; - void *newp; - size_t newlen; +void +ipsec_clearhist(m) + struct mbuf *m; { - /* All sysctl names at this level are terminal. */ - if (namelen != 1) - return ENOTDIR; - - /* common sanity checks */ - switch (name[0]) { - case IPSECCTL_DEF_ESP_TRANSLEV: - case IPSECCTL_DEF_ESP_NETLEV: - case IPSECCTL_DEF_AH_TRANSLEV: - case IPSECCTL_DEF_AH_NETLEV: - if (newp != NULL && newlen == sizeof(int)) { - switch (*(int *)newp) { - case IPSEC_LEVEL_USE: - case IPSEC_LEVEL_REQUIRE: - break; - default: - return EINVAL; - } - } - } - - switch (name[0]) { + struct mbuf *n; - case IPSECCTL_STATS: - return sysctl_struct(oldp, oldlenp, newp, newlen, - &ipsec6stat, sizeof(ipsec6stat)); - case IPSECCTL_DEF_POLICY: - if (newp != NULL && newlen == sizeof(int)) { - switch (*(int *)newp) { - case IPSEC_POLICY_DISCARD: - case IPSEC_POLICY_NONE: - break; - default: - return EINVAL; - } - } - return sysctl_int(oldp, oldlenp, newp, newlen, - &ip6_def_policy.policy); - case IPSECCTL_DEF_ESP_TRANSLEV: - return sysctl_int(oldp, oldlenp, newp, newlen, - &ip6_esp_trans_deflev); - case IPSECCTL_DEF_ESP_NETLEV: - return sysctl_int(oldp, oldlenp, newp, newlen, - &ip6_esp_net_deflev); - case IPSECCTL_DEF_AH_TRANSLEV: - return sysctl_int(oldp, oldlenp, newp, newlen, - &ip6_ah_trans_deflev); - case IPSECCTL_DEF_AH_NETLEV: - return sysctl_int(oldp, oldlenp, newp, newlen, - &ip6_ah_net_deflev); - case IPSECCTL_INBOUND_CALL_IKE: - return sysctl_int(oldp, oldlenp, newp, newlen, - &ip6_inbound_call_ike); - case IPSECCTL_ECN: - return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_ipsec_ecn); - case IPSECCTL_DEBUG: - return sysctl_int(oldp, oldlenp, newp, newlen, &ipsec_debug); - default: - return EOPNOTSUPP; - } - /* NOTREACHED */ + n = ipsec_findaux(m); + if ((n) && n->m_len > sizeof(struct socket *)) + n->m_len = sizeof(struct socket *); + ipsec_optaux(m, n); } -#endif /*INET6*/ - -#endif /* __NetBSD__ */ diff --git a/bsd/netinet6/ipsec.h b/bsd/netinet6/ipsec.h index b800edc6f..e4948d4aa 100644 --- a/bsd/netinet6/ipsec.h +++ b/bsd/netinet6/ipsec.h @@ -1,4 +1,5 @@ -/* $KAME: ipsec.h,v 1.28 2000/03/15 13:07:57 sakane Exp $ */ +/* $FreeBSD: src/sys/netinet6/ipsec.h,v 1.4.2.2 2001/07/03 11:01:54 ume Exp $ */ +/* $KAME: ipsec.h,v 1.44 2001/03/23 08:08:47 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -35,14 +36,16 @@ #ifndef _NETINET6_IPSEC_H_ #define _NETINET6_IPSEC_H_ +#include #include #include -#if KERNEL +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE /* * Security Policy Index - * NOTE: Encure to be same address family and upper layer protocol. + * NOTE: Ensure to be same address family and upper layer protocol. * NOTE: ul_proto, port number, uid, gid: * ANY: reserved for waldcard. * 0 to (~0 - 1): is one of the number of each value. @@ -77,6 +80,18 @@ struct secpolicy { struct ipsecrequest *req; /* pointer to the ipsec request tree, */ /* if policy == IPSEC else this value == NULL.*/ + + /* + * lifetime handler. + * the policy can be used without limitiation if both lifetime and + * validtime are zero. + * "lifetime" is passed by sadb_lifetime.sadb_lifetime_addtime. + * "validtime" is passed by sadb_lifetime.sadb_lifetime_usetime. + */ + long created; /* time created the policy */ + long lastused; /* updated every when kernel sends a packet */ + long lifetime; /* duration of the lifetime of this policy */ + long validtime; /* duration this policy is valid without use */ }; /* Request for IPsec */ @@ -105,10 +120,11 @@ struct secspacq { struct secpolicyindex spidx; - u_int32_t tick; /* for lifetime */ + long created; /* for lifetime */ int count; /* for lifetime */ /* XXX: here is mbuf place holder to be sent ? */ }; +#endif /* __APPLE_API_PRIVATE */ #endif /*KERNEL*/ /* according to IANA assignment, port 0x0000 and proto 0xff are reserved. */ @@ -135,9 +151,9 @@ struct secspacq { /* Policy level */ /* - * IPSEC, ENTRUST and BYPASS are allowd for setsockopt() in PCB, - * DISCARD, IPSEC and NONE are allowd for setkey() in SPD. - * DISCARD and NONE are allowd for system default. + * IPSEC, ENTRUST and BYPASS are allowed for setsockopt() in PCB, + * DISCARD, IPSEC and NONE are allowed for setkey() in SPD. + * DISCARD and NONE are allowed for system default. */ #define IPSEC_POLICY_DISCARD 0 /* discarding packet */ #define IPSEC_POLICY_NONE 1 /* through IPsec engine */ @@ -164,6 +180,7 @@ struct secspacq { */ #define IPSEC_REPLAYWSIZE 32 +#ifdef __APPLE_API_UNSTABLE /* statistics for ipsec processing */ struct ipsecstat { u_quad_t in_success; /* succeeded inbound process */ @@ -193,6 +210,7 @@ struct ipsecstat { u_quad_t out_ahhist[256]; u_quad_t out_comphist[256]; }; +#endif /* __APPLE_API_UNSTABLE */ /* * Definitions for IPsec & Key sysctl operations. @@ -206,13 +224,16 @@ struct ipsecstat { #define IPSECCTL_DEF_ESP_NETLEV 4 /* int; ESP tunnel mode */ #define IPSECCTL_DEF_AH_TRANSLEV 5 /* int; AH transport mode */ #define IPSECCTL_DEF_AH_NETLEV 6 /* int; AH tunnel mode */ +#if 0 /*obsolete, do not reuse*/ #define IPSECCTL_INBOUND_CALL_IKE 7 +#endif #define IPSECCTL_AH_CLEARTOS 8 #define IPSECCTL_AH_OFFSETMASK 9 #define IPSECCTL_DFBIT 10 #define IPSECCTL_ECN 11 #define IPSECCTL_DEBUG 12 -#define IPSECCTL_MAXID 13 +#define IPSECCTL_ESP_RANDPAD 13 +#define IPSECCTL_MAXID 14 #define IPSECCTL_NAMES { \ { 0, 0 }, \ @@ -222,12 +243,13 @@ struct ipsecstat { { "esp_net_deflev", CTLTYPE_INT }, \ { "ah_trans_deflev", CTLTYPE_INT }, \ { "ah_net_deflev", CTLTYPE_INT }, \ - { "inbound_call_ike", CTLTYPE_INT }, \ + { 0, 0 }, \ { "ah_cleartos", CTLTYPE_INT }, \ { "ah_offsetmask", CTLTYPE_INT }, \ { "dfbit", CTLTYPE_INT }, \ { "ecn", CTLTYPE_INT }, \ { "debug", CTLTYPE_INT }, \ + { "esp_randpad", CTLTYPE_INT }, \ } #define IPSEC6CTL_NAMES { \ @@ -238,81 +260,41 @@ struct ipsecstat { { "esp_net_deflev", CTLTYPE_INT }, \ { "ah_trans_deflev", CTLTYPE_INT }, \ { "ah_net_deflev", CTLTYPE_INT }, \ - { "inbound_call_ike", CTLTYPE_INT }, \ + { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { "ecn", CTLTYPE_INT }, \ { "debug", CTLTYPE_INT }, \ + { "esp_randpad", CTLTYPE_INT }, \ } -#ifdef __bsdi__ -#define IPSECCTL_VARS { \ - 0, \ - 0, \ - &ip4_def_policy.policy, \ - &ip4_esp_trans_deflev, \ - &ip4_esp_net_deflev, \ - &ip4_ah_trans_deflev, \ - &ip4_ah_net_deflev, \ - &ip4_inbound_call_ike, \ - &ip4_ah_cleartos, \ - &ip4_ah_offsetmask, \ - &ip4_ipsec_dfbit, \ - &ip4_ipsec_ecn, \ - &ipsec_debug, \ -} - -#define IPSEC6CTL_VARS { \ - 0, \ - 0, \ - &ip6_def_policy.policy, \ - &ip6_esp_trans_deflev, \ - &ip6_esp_net_deflev, \ - &ip6_ah_trans_deflev, \ - &ip6_ah_net_deflev, \ - &ip6_inbound_call_ike, \ - 0, \ - 0, \ - 0, \ - &ip6_ipsec_ecn, \ - &ipsec_debug, \ -} -#endif - -#if KERNEL +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE struct ipsec_output_state { struct mbuf *m; struct route *ro; struct sockaddr *dst; }; +struct ipsec_history { + int ih_proto; + u_int32_t ih_spi; +}; + extern int ipsec_debug; -#if INET extern struct ipsecstat ipsecstat; extern struct secpolicy ip4_def_policy; extern int ip4_esp_trans_deflev; extern int ip4_esp_net_deflev; extern int ip4_ah_trans_deflev; extern int ip4_ah_net_deflev; -extern int ip4_inbound_call_ike; extern int ip4_ah_cleartos; extern int ip4_ah_offsetmask; extern int ip4_ipsec_dfbit; extern int ip4_ipsec_ecn; -#endif - -#if INET6 -extern struct ipsecstat ipsec6stat; -extern struct secpolicy ip6_def_policy; -extern int ip6_esp_trans_deflev; -extern int ip6_esp_net_deflev; -extern int ip6_ah_trans_deflev; -extern int ip6_ah_net_deflev; -extern int ip6_inbound_call_ike; -extern int ip6_ipsec_ecn; -#endif +extern int ip4_esp_randpad; #define ipseclog(x) do { if (ipsec_debug) log x; } while (0) @@ -321,17 +303,7 @@ extern struct secpolicy *ipsec4_getpolicybysock extern struct secpolicy *ipsec4_getpolicybyaddr __P((struct mbuf *, u_int, int, int *)); -#if INET6 -extern struct secpolicy *ipsec6_getpolicybysock - __P((struct mbuf *, u_int, struct socket *, int *)); -extern struct secpolicy *ipsec6_getpolicybyaddr - __P((struct mbuf *, u_int, int, int *)); -#endif /*INET6*/ - struct inpcb; -#if INET6 -struct in6pcb; -#endif extern int ipsec_init_policy __P((struct socket *so, struct inpcbpolicy **)); extern int ipsec_copy_policy __P((struct inpcbpolicy *, struct inpcbpolicy *)); @@ -345,92 +317,40 @@ extern int ipsec4_delete_pcbpolicy __P((struct inpcb *)); extern int ipsec4_in_reject_so __P((struct mbuf *, struct socket *)); extern int ipsec4_in_reject __P((struct mbuf *, struct inpcb *)); -#if INET6 -extern int ipsec6_in_reject_so __P((struct mbuf *, struct socket *)); -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) -extern int ipsec6_delete_pcbpolicy __P((struct inpcb *)); -extern int ipsec6_set_policy __P((struct inpcb *inp, int optname, - caddr_t request, size_t len, int priv)); -extern int ipsec6_get_policy - __P((struct inpcb *inp, caddr_t request, size_t len, struct mbuf **mp)); -extern int ipsec6_in_reject __P((struct mbuf *, struct inpcb *)); -#else -extern int ipsec6_delete_pcbpolicy __P((struct in6pcb *)); -extern int ipsec6_set_policy __P((struct in6pcb *in6p, int optname, - caddr_t request, size_t len, int priv)); -extern int ipsec6_get_policy __P((struct in6pcb *in6p, caddr_t request, - size_t len, struct mbuf **mp)); -extern int ipsec6_in_reject __P((struct mbuf *, struct in6pcb *)); -#endif -#endif /*INET6*/ - struct secas; struct tcpcb; -struct tcp6cb; extern int ipsec_chkreplay __P((u_int32_t, struct secasvar *)); extern int ipsec_updatereplay __P((u_int32_t, struct secasvar *)); extern size_t ipsec4_hdrsiz __P((struct mbuf *, u_int, struct inpcb *)); -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) -extern size_t ipsec_hdrsiz_tcp __P((struct tcpcb *, int)); -#else -extern size_t ipsec4_hdrsiz_tcp __P((struct tcpcb *)); -#endif -#if INET6 -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) -extern size_t ipsec6_hdrsiz __P((struct mbuf *, u_int, struct inpcb *)); -#else -extern size_t ipsec6_hdrsiz __P((struct mbuf *, u_int, struct in6pcb *)); -#if defined(__NetBSD__) && !defined(TCP6) -extern size_t ipsec6_hdrsiz_tcp __P((struct tcpcb *)); -#else -extern size_t ipsec6_hdrsiz_tcp __P((struct tcp6cb *)); -#endif -#endif -#endif +extern size_t ipsec_hdrsiz_tcp __P((struct tcpcb *)); struct ip; -#if INET6 -struct ip6_hdr; -#endif extern const char *ipsec4_logpacketstr __P((struct ip *, u_int32_t)); -#if INET6 -extern const char *ipsec6_logpacketstr __P((struct ip6_hdr *, u_int32_t)); -#endif extern const char *ipsec_logsastr __P((struct secasvar *)); extern void ipsec_dumpmbuf __P((struct mbuf *)); extern int ipsec4_output __P((struct ipsec_output_state *, struct secpolicy *, int)); -#if INET6 -extern int ipsec6_output_trans __P((struct ipsec_output_state *, u_char *, - struct mbuf *, struct secpolicy *, int, int *)); -extern int ipsec6_output_tunnel __P((struct ipsec_output_state *, - struct secpolicy *, int)); -#endif -extern int ipsec4_tunnel_validate __P((struct ip *, u_int, struct secasvar *)); -#if INET6 -extern int ipsec6_tunnel_validate __P((struct ip6_hdr *, u_int, +extern int ipsec4_tunnel_validate __P((struct mbuf *, int, u_int, struct secasvar *)); -#endif extern struct mbuf *ipsec_copypkt __P((struct mbuf *)); -extern void ipsec_setsocket __P((struct mbuf *, struct socket *)); +extern void ipsec_delaux __P((struct mbuf *)); +extern int ipsec_setsocket __P((struct mbuf *, struct socket *)); extern struct socket *ipsec_getsocket __P((struct mbuf *)); - -#if defined(__bsdi__) || defined(__NetBSD__) -extern int ipsec_sysctl __P((int *, u_int, void *, size_t *, void *, size_t)); -extern int ipsec6_sysctl __P((int *, u_int, void *, size_t *, void *, size_t)); -#endif /* __bsdi__ || __NetBSD__ */ - +extern int ipsec_addhist __P((struct mbuf *, int, u_int32_t)); +extern struct ipsec_history *ipsec_gethist __P((struct mbuf *, int *)); +extern void ipsec_clearhist __P((struct mbuf *)); +#endif /* __APPLE_API_PRIVATE */ #endif /*KERNEL*/ #ifndef KERNEL -extern caddr_t ipsec_set_policy __P((char *policy, int buflen)); -extern int ipsec_get_policylen __P((caddr_t buf)); -extern char *ipsec_dump_policy __P((caddr_t buf, char *delimiter)); +extern caddr_t ipsec_set_policy __P((char *, int)); +extern int ipsec_get_policylen __P((caddr_t)); +extern char *ipsec_dump_policy __P((caddr_t, char *)); -extern char *ipsec_strerror __P((void)); +extern const char *ipsec_strerror __P((void)); #endif /*!KERNEL*/ #endif /*_NETINET6_IPSEC_H_*/ diff --git a/bsd/netinet6/ipsec6.h b/bsd/netinet6/ipsec6.h new file mode 100644 index 000000000..9fd4fc75a --- /dev/null +++ b/bsd/netinet6/ipsec6.h @@ -0,0 +1,86 @@ +/* $FreeBSD: src/sys/netinet6/ipsec6.h,v 1.3.2.2 2001/07/03 11:01:54 ume Exp $ */ +/* $KAME: ipsec.h,v 1.44 2001/03/23 08:08:47 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * IPsec controller part. + */ + +#ifndef _NETINET6_IPSEC6_H_ +#define _NETINET6_IPSEC6_H_ +#include + +#include +#include + +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE +extern struct ipsecstat ipsec6stat; +extern struct secpolicy ip6_def_policy; +extern int ip6_esp_trans_deflev; +extern int ip6_esp_net_deflev; +extern int ip6_ah_trans_deflev; +extern int ip6_ah_net_deflev; +extern int ip6_ipsec_ecn; +extern int ip6_esp_randpad; + +extern struct secpolicy *ipsec6_getpolicybysock + __P((struct mbuf *, u_int, struct socket *, int *)); +extern struct secpolicy *ipsec6_getpolicybyaddr + __P((struct mbuf *, u_int, int, int *)); + +struct inpcb; + +extern int ipsec6_in_reject_so __P((struct mbuf *, struct socket *)); +extern int ipsec6_delete_pcbpolicy __P((struct inpcb *)); +extern int ipsec6_set_policy __P((struct inpcb *inp, int optname, + caddr_t request, size_t len, int priv)); +extern int ipsec6_get_policy + __P((struct inpcb *inp, caddr_t request, size_t len, struct mbuf **mp)); +extern int ipsec6_in_reject __P((struct mbuf *, struct inpcb *)); + +struct tcp6cb; + +extern size_t ipsec6_hdrsiz __P((struct mbuf *, u_int, struct inpcb *)); + +struct ip6_hdr; +extern const char *ipsec6_logpacketstr __P((struct ip6_hdr *, u_int32_t)); + +extern int ipsec6_output_trans __P((struct ipsec_output_state *, u_char *, + struct mbuf *, struct secpolicy *, int, int *)); +extern int ipsec6_output_tunnel __P((struct ipsec_output_state *, + struct secpolicy *, int)); +extern int ipsec6_tunnel_validate __P((struct mbuf *, int, u_int, + struct secasvar *)); +#endif /* __APPLE_API_PRIVATE */ +#endif /*KERNEL*/ + +#endif /*_NETINET6_IPSEC6_H_*/ diff --git a/bsd/netinet6/mip6.c b/bsd/netinet6/mip6.c deleted file mode 100644 index 4a2e27c67..000000000 --- a/bsd/netinet6/mip6.c +++ /dev/null @@ -1,3164 +0,0 @@ -/* $KAME: mip6.c,v 1.20 2000/03/18 03:05:38 itojun Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, 1998, 1999 and 2000 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * Copyright (c) 1999 and 2000 Ericsson Radio Systems AB - * All rights reserved. - * - * Author: Conny Larsson - * Mattias Pettersson - * - */ - -/* - * TODO: nuke calls to in6_control, it is not supposed to be called from - * softintr - */ - -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#if MIP6_DEBUG -#include -#include -#include -#include -#include -#endif - -#include - -int (*mip6_rec_ra_hook)(struct mbuf *, int) = 0; - -struct in6_addr * (*mip6_global_addr_hook)(struct in6_addr *) = 0; -struct mip6_subopt_hal * (*mip6_hal_dynamic_hook)(struct in6_addr *) = 0; -int (*mip6_write_config_data_ha_hook)(u_long, void *) = 0; -int (*mip6_clear_config_data_ha_hook)(u_long, void *) = 0; -int (*mip6_enable_func_ha_hook)(u_long, caddr_t) = 0; - -int (*mip6_rec_ba_hook)(struct mbuf *, int) = 0; -int (*mip6_rec_br_hook)(struct mbuf *, int) = 0; -void (*mip6_stop_bu_hook)(struct in6_addr *) = 0; -int (*mip6_write_config_data_mn_hook)(u_long, void *) = 0; -int (*mip6_clear_config_data_mn_hook)(u_long, caddr_t) = 0; -int (*mip6_enable_func_mn_hook)(u_long, caddr_t) = 0; - - -#if MIP6_DEBUG -int mip6_debug_is_enabled = 0; -#endif - - -/* Declaration of Global variables. */ -struct mip6_bc *mip6_bcq = NULL; /* First entry in BC list */ -struct mip6_na *mip6_naq = NULL; /* First entry in NA retrans. list */ -struct mip6_prefix *mip6_pq = NULL; /* Ptr to prefix queue */ -struct mip6_config mip6_config; /* Config parameters for MIPv6 */ -struct mip6_link_list *mip6_llq = NULL; /* List of links receiving RA's */ - - -#if 0 /* Phasing out MIP6_HA and MIP6_MN */ -#if MIP6_HA -u_int8_t mip6_module = MIP6_HA_MODULE; /* Info about loaded modules (HA) */ -#elif defined(MIP6_MN) -u_int8_t mip6_module = MIP6_MN_MODULE; /* Info about loaded modules (MN) */ -#else -u_int8_t mip6_module = 0; /* Info about loaded modules (CN) */ -#endif -#else /* 0 */ -u_int8_t mip6_module = 0; /* Info about loaded modules (CN) */ -#endif /* 0 */ - -extern struct ip6protosw mip6_tunnel_protosw; - - -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -struct callout_handle mip6_timer_na_handle; -struct callout_handle mip6_timer_bc_handle; -struct callout_handle mip6_timer_prefix_handle; -#endif - - -/* Definitions of some costant IP6 addresses. */ -struct in6_addr in6addr_linklocal; -struct in6_addr in6addr_sitelocal; -struct in6_addr in6addr_aha_64; -struct in6_addr in6addr_aha_nn; - - -/* - ############################################################################## - # - # INITIALIZATION AND EXIT FUNCTIONS - # These functions are executed when the MIPv6 code is activated and de- - # activated respectively. - # - ############################################################################## - */ - -/* - ****************************************************************************** - * Function: mip6_init - * Description: Initialization of MIPv6 variables that must be initialized - * before the code is executed. - ****************************************************************************** - */ -void -mip6_init(void) -{ - static int mip6_init_done = 0; - - if (mip6_init_done) - return; - - /* Initialize global addresses. */ - in6addr_linklocal.s6_addr32[0] = MIP6_ADDR_INT32_ULL; - in6addr_linklocal.s6_addr32[1] = 0x00000000; - in6addr_linklocal.s6_addr32[2] = 0x00000000; - in6addr_linklocal.s6_addr32[3] = 0x00000000; - - in6addr_sitelocal.s6_addr32[0] = MIP6_ADDR_INT32_USL; - in6addr_sitelocal.s6_addr32[1] = 0x00000000; - in6addr_sitelocal.s6_addr32[2] = 0x00000000; - in6addr_sitelocal.s6_addr32[3] = 0x00000000; - - in6addr_aha_64.s6_addr32[0] = 0x00000000; - in6addr_aha_64.s6_addr32[1] = 0xffffffff; - in6addr_aha_64.s6_addr32[2] = MIP6_ADDR_INT32_AHA2; - in6addr_aha_64.s6_addr32[3] = MIP6_ADDR_INT32_AHA1; - - in6addr_aha_nn.s6_addr32[0] = 0x00000000; - in6addr_aha_nn.s6_addr32[1] = 0xffffffff; - in6addr_aha_nn.s6_addr32[2] = 0xffffffff; - in6addr_aha_nn.s6_addr32[3] = MIP6_ADDR_INT32_AHA1; - -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - /* Initialize handle for timer functions. */ - callout_handle_init(&mip6_timer_na_handle); - callout_handle_init(&mip6_timer_bc_handle); - callout_handle_init(&mip6_timer_prefix_handle); -#endif - - /* Initialize global variable */ - bzero(&mip6_config, sizeof(struct mip6_config)); - - /* Set default values for MIP6 configuration parameters. */ - LIST_INIT(&mip6_config.fna_list); - - mip6_config.bu_lifetime = 600; - mip6_config.br_update = 60; - mip6_config.hr_lifetime = 3600; - mip6_config.enable_outq = 1; - - mip6_enable_hooks(MIP6_GENERIC_HOOKS); - mip6_enable_hooks(MIP6_CONFIG_HOOKS); - - mip6_init_done = 1; - printf("%s: MIP6 initialized\n", __FUNCTION__); -} - - - -/* - ****************************************************************************** - * Function: mip6_exit - * Description: This function is called when the module is unloaded (relesed) - * from the kernel. - ****************************************************************************** - */ -void -mip6_exit() -{ - struct mip6_na *nap, *nap_tmp; - struct mip6_bc *bcp, *bcp_nxt; - struct mip6_prefix *prefix; - int s; - - /* Cancel outstanding timeout function calls. */ -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - untimeout(mip6_timer_na, (void *)NULL, mip6_timer_na_handle); - untimeout(mip6_timer_bc, (void *)NULL , mip6_timer_bc_handle); - untimeout(mip6_timer_prefix, (void *)NULL, mip6_timer_prefix_handle); -#else - untimeout(mip6_timer_na, (void *)NULL); - untimeout(mip6_timer_bc, (void *)NULL); - untimeout(mip6_timer_prefix, (void *)NULL); -#endif - - /* Remove each entry in every queue. */ - s = splnet(); - for (nap = mip6_naq; nap;) { - nap_tmp = nap; - nap = nap->next; - _FREE(nap_tmp, M_TEMP); - } - mip6_naq = NULL; - - for (bcp = mip6_bcq; bcp;) { - mip6_bc_delete(bcp, &bcp_nxt); - bcp = bcp_nxt; - } - mip6_bcq = NULL; - - for (prefix = mip6_pq; prefix;) - prefix = mip6_prefix_delete(prefix); - mip6_pq = NULL; - splx(s); -} - - - -/* - ############################################################################## - # - # RECEIVING FUNCTIONS - # These functions receives the incoming IPv6 packet and further processing of - # the packet depends on the content in the packet. - # - ############################################################################## - */ - -/* - ****************************************************************************** - * Function: mip6_rec_ctrl_sig - * Description: This function receives incoming signals and calls the approp- - * riate function for further processing of the destination - * option. - * Ret value: 0 Everything is OK. - * IPPROTO_DONE Error code used when something went wrong. - ****************************************************************************** - */ -int -mip6_rec_ctrl_sig(m_in, off) -struct mbuf *m_in; /* Mbuf containing the entire IPv6 packet */ -int off; /* Offset (bytes) from beginning of mbuf to start of - destination option */ -{ - register struct ip6_hdr *ip6; /* IPv6 header */ - int res; /* Result of function call */ - -#if MIP6_DEBUG - static int count = 0; - - count += 1; - mip6_debug("\nMIPv6 Start processing a control signal (%d)\n", count); -#endif - - res = 0; - if (mip6_inp == NULL) { - log(LOG_ERR, "%s: Variabel mip6_inp is NULL\n", - __FUNCTION__); - return IPPROTO_DONE; - } - ip6 = mtod(m_in, struct ip6_hdr *); - - /* Store necessary data from IPv6 header */ - mip6_inp->ip6_src = ip6->ip6_src; - mip6_inp->ip6_dst = ip6->ip6_dst; - - /* Process incoming signal (BU, BA, BR and/or Home Address option) */ - if (mip6_inp->optflag & MIP6_DSTOPT_BU) { - res = mip6_rec_bu(m_in, off); - if (res != 0) { -#if MIP6_DEBUG - mip6_debug("\nMIPv6 Error processing control " - "signal BU (%d)\n", count); -#endif - return res; - } - } - - if (MIP6_IS_MN_ACTIVE) { - if (mip6_inp->optflag & MIP6_DSTOPT_BA) { - if (mip6_rec_ba_hook) - res = (*mip6_rec_ba_hook)(m_in, off); - if (res != 0) { -#if MIP6_DEBUG - mip6_debug("\nMIPv6 Error processing control " - "signal BA (%d)\n", count); -#endif - return res; - } - } - } - - if (MIP6_IS_MN_ACTIVE) { - if (mip6_inp->optflag & MIP6_DSTOPT_BR) { - if (mip6_rec_br_hook) - res = (*mip6_rec_br_hook)(m_in, off); - if (res != 0) { -#if MIP6_DEBUG - mip6_debug("\nMIPv6 Error processing control " - "signal BR (%d)\n", count); -#endif - return res; - } - } - } - - if (mip6_inp->optflag & MIP6_DSTOPT_HA) - mip6_ha2srcaddr(m_in); - -#if MIP6_DEBUG - mip6_debug("\nMIPv6 Finished processing a control signal (%d)\n", - count); -#endif - return 0; -} - - - -/* - ****************************************************************************** - * Function: mip6_icmp6_input - * Description: Every ICMP6 message must be checked for errors. If a Router - * Advertisement is included the Home Agent List must be up- - * dated. - * The check of the Router Advertisement can not be done in - * function nd6_ra_input since this function only deals with - * configuration issues. - * Ret value: 0 Everything is OK. - * IPPROTO_DONE Error code used when something went wrong. - ****************************************************************************** - */ -int -mip6_icmp6_input(m, off) -struct mbuf *m; /* Mbuf containing the entire IPv6 packet */ -int off; /* Offset from start of mbuf to icmp6 message */ -{ - struct ip6_hdr *ip6; /* IPv6 header */ - struct ip6_hdr *ip6_icmp; /* IPv6 header in icmpv6 packet */ - struct icmp6_hdr *icmp6; /* ICMP6 header */ - struct mip6_bc *bcp; /* Binding Cache list entry */ - struct mip6_bc *bcp_nxt; /* Binding Cache list entry */ - struct nd_router_advert *ra; /* Router Advertisement */ - u_int8_t *err_ptr; /* Octet offset for error */ - int icmp6len, err_off, res = 0; - - ip6 = mtod(m, struct ip6_hdr *); - icmp6len = m->m_pkthdr.len - off; - icmp6 = (struct icmp6_hdr *)((caddr_t)ip6 + off); - - switch (icmp6->icmp6_type) { - case ICMP6_DST_UNREACH: - /* First we have to find the destination address - from the original IPv6 packet. Make sure that - the IPv6 packet is included in the ICMPv6 packet. */ - if ((off + sizeof(struct icmp6_hdr) + - sizeof(struct ip6_hdr)) >= m->m_pkthdr.len) - return 0; - - ip6_icmp = (struct ip6_hdr *) ((caddr_t)icmp6 + - sizeof(struct icmp6_hdr)); - - /* Remove BC entry if present */ - bcp = mip6_bc_find(&ip6_icmp->ip6_dst); - if (bcp && !bcp->hr_flag) - mip6_bc_delete(bcp, &bcp_nxt); - break; - - case ICMP6_PARAM_PROB: - if (icmp6->icmp6_code != ICMP6_PARAMPROB_OPTION) - break; - - /* First we have to find the destination address - from the original IPv6 packet. Make sure that - the ptr is within the ICMPv6 packet. */ - err_off = ntohl(icmp6->icmp6_data32[0]); - if ((off + sizeof(struct icmp6_hdr) + err_off) >= - m->m_pkthdr.len) - return 0; - - ip6_icmp = (struct ip6_hdr *)((caddr_t)icmp6 + - sizeof(struct icmp6_hdr)); - - /* Check which option that failed */ - err_ptr = (u_int8_t *) ((caddr_t)icmp6 + - sizeof(struct icmp6_hdr) + - err_off); - - if (MIP6_IS_MN_ACTIVE && (*err_ptr == IP6OPT_BINDING_UPDATE)) { - if (mip6_stop_bu_hook) - (*mip6_stop_bu_hook)(&ip6_icmp->ip6_dst); - } - - if (*err_ptr == IP6OPT_HOME_ADDRESS) { - log(LOG_ERR, - "Node %s does not recognize Home Address option\n", - ip6_sprintf(&ip6_icmp->ip6_dst)); - /* The message is discarded by the icmp code. */ - } - break; - - case ND_ROUTER_ADVERT: - if (icmp6->icmp6_code != 0) - break; - if (icmp6len < sizeof(struct nd_router_advert)) - break; - - ra = (struct nd_router_advert *)icmp6; - if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_HA) == 0) - break; - - if (mip6_rec_ra_hook) { - res = mip6_rec_ra_hook(m, off); - if (res) return res; - break; - } - } - return 0; -} - - - -/* - ############################################################################## - # - # CONTROL SIGNAL FUNCTIONS - # Functions for processing of incoming control signals (Binding Update and - # Home Address option). - # - ############################################################################## - */ - -/* - ****************************************************************************** - * Function: mip6_rec_bu - * Description: Receive a Binding Update option and evaluate the contents. - * Ret value: 0 Everything is OK. - * IPPROTO_DONE Error code used when something went wrong. - ****************************************************************************** - */ -int -mip6_rec_bu(m_in, off) -struct mbuf *m_in; /* Mbuf containing the entire IPv6 packet */ -int off; /* Offset from start of mbuf to start of dest option */ -{ - struct in6_addr *src_addr; /* Src addr for HA sending BU */ - struct mip6_subopt_hal *hal; /* Home Agents List sub-option */ - struct mip6_bc *bcp; /* Binding Cache list entry */ - struct mip6_bc *bcp_nxt; - struct in6_addr *coa; /* COA of the MN sending the BU */ - struct mip6_subbuf *subbuf; /* Buffer containing sub-options */ - struct in6_addr ll_allnode; /* Link local all nodes address */ - u_int32_t min_time; /* Minimum lifetime to be sent in BA */ - u_long na_flags = 0; /* Flags for NA message */ - int send_na; /* If node becomes HA for MN, broadcast NA */ - int res, error; - u_int8_t rtr; -#if MIP6_DEBUG - u_int8_t var; - int offset, ii; -#endif - - subbuf = NULL; - - /* Find the care-of address used by the MN when sending the BU. */ - if (mip6_inp->coa) - coa = &mip6_inp->coa->coa; - else - coa = &mip6_inp->ip6_src; - - /* Make sure that the BU contains a valid AH or ESP header. */ -#if IPSEC -#ifndef __OpenBSD__ - if ( !((m_in->m_flags & M_AUTHIPHDR && m_in->m_flags & M_AUTHIPDGM) || - (m_in->m_flags & M_AUTHIPDGM && m_in->m_flags & M_DECRYPTED))) { - ip6stat.ip6s_badoptions++; - log(LOG_INFO, - "%s: No AH or ESP header in BU from host %s\n", - __FUNCTION__, - ip6_sprintf(coa)); - return IPPROTO_DONE; - } -#endif -#endif - - /* Make sure that the BU contains a valid Home Address option. */ - if ((mip6_inp->optflag & MIP6_DSTOPT_HA) == 0) { - ip6stat.ip6s_badoptions++; - log(LOG_INFO, - "%s: No Home Address option included in BU from host %s\n", - __FUNCTION__, ip6_sprintf(coa)); - return IPPROTO_DONE; - } - - /* Make sure that the length field in the BU is >= 8. */ - if (mip6_inp->bu_opt->len < IP6OPT_BULEN) { - ip6stat.ip6s_badoptions++; - log(LOG_INFO, - "%s: Length field to short (%d) in BU from host %s\n", - __FUNCTION__, mip6_inp->bu_opt->len, ip6_sprintf(coa)); - return IPPROTO_DONE; - } - - /* The sequence no in the BU must be greater than or equal to the - sequence number in the previous BU recieved (modulo 2^^16). */ - send_na = 0; - bcp = mip6_bc_find(&mip6_inp->ha_opt->home_addr); - if (bcp != NULL) { - if (MIP6_LEQ(mip6_inp->bu_opt->seqno, bcp->seqno)) { - ip6stat.ip6s_badoptions++; - log(LOG_INFO, - "%s: Received sequence number (%d) <= " - "current (%d) in BU from host %s\n", - __FUNCTION__, mip6_inp->bu_opt->seqno, - bcp->seqno, ip6_sprintf(coa)); - return IPPROTO_DONE; - } - if (!bcp->hr_flag) - send_na = 1; - } else - send_na = 1; - -#if MIP6_DEBUG - mip6_debug("\nReceived Binding Update\n"); - mip6_debug("IP Header Src: %s\n", - ip6_sprintf(&mip6_inp->ip6_src)); - mip6_debug("IP Header Dst: %s\n", - ip6_sprintf(&mip6_inp->ip6_dst)); - mip6_debug("Type/Length/Flags: %x / %u / ", - mip6_inp->bu_opt->type, mip6_inp->bu_opt->len); - if (mip6_inp->bu_opt->flags & MIP6_BU_AFLAG) - mip6_debug("A "); - if (mip6_inp->bu_opt->flags & MIP6_BU_HFLAG) - mip6_debug("H "); - if (mip6_inp->bu_opt->flags & MIP6_BU_RFLAG) - mip6_debug("R "); - mip6_debug("\n"); - mip6_debug("Seq no/Life time: %u / %u\n", - mip6_inp->bu_opt->seqno, - mip6_inp->bu_opt->lifetime); - mip6_debug("Prefix length: %u\n", - mip6_inp->bu_opt->prefix_len); - - if (mip6_inp->bu_opt->len > IP6OPT_BULEN) { - offset = mip6_opt_offset(m_in, off, IP6OPT_BINDING_UPDATE); - if (offset == 0) goto end_debug; - - mip6_debug("Sub-options present (TLV coded)\n"); - for (ii = IP6OPT_BULEN; ii < mip6_inp->bu_opt->len; ii++) { - if ((ii - IP6OPT_BULEN) % 16 == 0) - mip6_debug("\t0x:"); - if ((ii - IP6OPT_BULEN) % 4 == 0) - mip6_debug(" "); - m_copydata(m_in, offset + 2 + ii, sizeof(var), - (caddr_t)&var); - mip6_debug("%02x", var); - if ((ii - IP6OPT_BULEN + 1) % 16 == 0) - mip6_debug("\n"); - } - if ((ii - IP6OPT_BULEN) % 16) - mip6_debug("\n"); - } - end_debug: -#endif - - /* Shall Dynamic Home Agent Address Discovery be performed? */ - src_addr = NULL; - hal = NULL; - - if (MIP6_IS_HA_ACTIVE) { - if ((mip6_inp->ip6_dst.s6_addr8[15] & 0x7f) == - MIP6_ADDR_ANYCAST_HA) { - if (mip6_global_addr_hook) - src_addr = (*mip6_global_addr_hook) - (&mip6_inp->ip6_dst); - if (src_addr == NULL) { - log(LOG_ERR, - "%s: No global source address found\n", - __FUNCTION__); - return IPPROTO_DONE; - } - - if (mip6_hal_dynamic_hook) - hal = (*mip6_hal_dynamic_hook)(src_addr); - if (mip6_store_subopt(&subbuf, (caddr_t)hal)) { - if (subbuf) _FREE(subbuf, M_TEMP); - return IPPROTO_DONE; - } - error = mip6_send_ba(src_addr, - &mip6_inp->ha_opt->home_addr, - coa, subbuf, MIP6_BA_STATUS_DHAAD, - mip6_inp->bu_opt->seqno, 0); - return error; - } - } - - /* Check if BU includes Unique Identifier sub-option is present. */ - /* XXX Code have to be added. */ - - /* Check if this is a request to cache a binding for the MN. */ - if ((mip6_inp->bu_opt->lifetime != 0) && - (! IN6_ARE_ADDR_EQUAL(&mip6_inp->ha_opt->home_addr, coa))) { - /* The request to cache the binding depends on if the H-bit - is set or not in the BU. */ - error = 0; - if (mip6_inp->bu_opt->flags & MIP6_BU_HFLAG) { - /* The H-bit is set. Register the primary coa. Is the - node is a router implementing HA functionality */ - if ((!ip6_forwarding || !MIP6_IS_HA_ACTIVE) && - (mip6_inp->bu_opt->flags & MIP6_BU_AFLAG)) { - error = mip6_send_ba( - &mip6_inp->ip6_dst, - &mip6_inp->ha_opt->home_addr, - coa, NULL, MIP6_BA_STATUS_HOMEREGNOSUP, - mip6_inp->bu_opt->seqno, 0); - return error; - } - - /* Verify that the home address is an on-link IPv6 - address and that the prefix length is correct. */ - res = mip6_addr_on_link(&mip6_inp->ha_opt->home_addr, - mip6_inp->bu_opt->prefix_len); - if ((res != 0) && - (mip6_inp->bu_opt->flags & MIP6_BU_AFLAG)) { - error = mip6_send_ba( - &mip6_inp->ip6_dst, - &mip6_inp->ha_opt->home_addr, - coa, NULL, res, - mip6_inp->bu_opt->seqno, 0); - return error; - } - - /* Other reject reasons may be added, e.g. - insufficient resources to serve a MN. */ - /* XXX Code may be added. */ - - /* The BU is OK and this node becomes the HA for - the MN. Find out which lifetime to use in the BA */ - min_time = mip6_min_lifetime( - &mip6_inp->ha_opt->home_addr, - mip6_inp->bu_opt->prefix_len); - min_time = min(min_time, - mip6_inp->bu_opt->lifetime); - - /* Create a new or update an existing BC entry. */ - rtr = mip6_inp->bu_opt->flags & MIP6_BU_RFLAG; - bcp = mip6_bc_find(&mip6_inp->ha_opt->home_addr); - if (bcp) - mip6_bc_update(bcp, coa, min_time, 1, rtr, - mip6_inp->bu_opt->prefix_len, - mip6_inp->bu_opt->seqno, - bcp->info, bcp->lasttime); - else { - bcp = mip6_bc_create( - &mip6_inp->ha_opt->home_addr, - coa, min_time, 1, rtr, - mip6_inp->bu_opt->prefix_len, - mip6_inp->bu_opt->seqno); - if (bcp == NULL) - return IPPROTO_DONE; - } - - /* Send a BA to the mobile node if the A-bit is - set in the BU. */ - if (mip6_inp->bu_opt->flags & MIP6_BU_AFLAG) { - error = mip6_send_ba(&mip6_inp->ip6_dst, - &bcp->home_addr, - &bcp->coa, - NULL, - MIP6_BA_STATUS_ACCEPT, - bcp->seqno, - bcp->lifetime); - if (error) - return error; - } - - /* The HA shall act as a proxy for the MN while it - is at a FN. Create a new or move an existing - tunnel to the MN. */ - error = mip6_tunnel(&mip6_inp->ip6_dst, - &bcp->coa, - MIP6_TUNNEL_MOVE, MIP6_NODE_HA, - (void *)bcp); - if (error) - return IPPROTO_DONE; - error = mip6_proxy(&bcp->home_addr, - &mip6_inp->ip6_dst, RTM_ADD); - if (error) { -#if MIP6_DEBUG - mip6_debug("%s: set proxy error = %d\n", - __FUNCTION__, error); -#endif - return IPPROTO_DONE; - } - - /* Create a NA for the MN if the HA did not already - have a BC entry for this MN marked as a "home - registration". - The first NA will be sent in the create function, - the remaining NAs are sent by the timer function. */ - if (send_na) { - ll_allnode = in6addr_linklocal_allnodes; - na_flags |= ND_NA_FLAG_OVERRIDE; - if (mip6_inp->bu_opt->flags & MIP6_BU_RFLAG) - na_flags |= ND_NA_FLAG_ROUTER; - - mip6_na_create(&mip6_inp->ha_opt->home_addr, - &ll_allnode, - &mip6_inp->ha_opt->home_addr, - mip6_inp->bu_opt->prefix_len, - na_flags, 1); - } - } else { - /* The H-bit is NOT set. Request to cache a binding. - Create a new or update an existing BC entry. */ - rtr = mip6_inp->bu_opt->flags & MIP6_BU_RFLAG; - bcp = mip6_bc_find(&mip6_inp->ha_opt->home_addr); - if (bcp) - mip6_bc_update(bcp, coa, - mip6_inp->bu_opt->lifetime, - 0, rtr, - mip6_inp->bu_opt->prefix_len, - mip6_inp->bu_opt->seqno, - bcp->info, bcp->lasttime); - else { - bcp = mip6_bc_create( - &mip6_inp->ha_opt->home_addr, - coa, mip6_inp->bu_opt->lifetime, - 0, rtr, mip6_inp->bu_opt->prefix_len, - mip6_inp->bu_opt->seqno); - if (bcp == NULL) - return IPPROTO_DONE; - } - - /* Send a BA to the mobile node if the A-bit is - set in the BU. */ - if (mip6_inp->bu_opt->flags & MIP6_BU_AFLAG) { - error = mip6_send_ba(&mip6_inp->ip6_dst, - &bcp->home_addr, - &bcp->coa, NULL, - MIP6_BA_STATUS_ACCEPT, - bcp->seqno, - bcp->lifetime); - return error; - } - } - return 0; - } - - /* Check if this is a request to delete a binding for the MN. */ - if ((mip6_inp->bu_opt->lifetime == 0) || - (IN6_ARE_ADDR_EQUAL(&mip6_inp->ha_opt->home_addr, coa))) { - /* The request to delete the binding depends on if the - H-bit is set or not in the BU. */ - if (mip6_inp->bu_opt->flags & MIP6_BU_HFLAG) { - /* The H-bit is set. Make sure that there is an - entry in the BC marked as "home registration" - for this MN. */ - error = 0; - if (((bcp == NULL) || (bcp->hr_flag == 0)) && - (mip6_inp->bu_opt->flags & MIP6_BU_AFLAG)) { - error = mip6_send_ba( - &mip6_inp->ip6_dst, - &mip6_inp->ha_opt->home_addr, - coa, NULL, MIP6_BA_STATUS_NOTHA, - mip6_inp->bu_opt->seqno, 0); - return error; - } - - /* The HA should delete BC entry, remove tunnel and - stop acting as a proxy for the MN. */ - error = mip6_bc_delete(bcp, &bcp_nxt); - if (error) - return IPPROTO_DONE; - - /* Send a BA to the MN if the A-bit is set. */ - if (mip6_inp->bu_opt->flags & MIP6_BU_AFLAG) { - error = mip6_send_ba( - &mip6_inp->ip6_dst, - &mip6_inp->ha_opt->home_addr, - coa, NULL, MIP6_BA_STATUS_ACCEPT, - mip6_inp->bu_opt->seqno, 0); - if (error) - return error; - } - } else { - /* The H-bit is NOT set. Request the CN to delete - the binding. */ - if (bcp != NULL) { - error = mip6_bc_delete(bcp, &bcp_nxt); - if (error) - return IPPROTO_DONE; - } - - if (mip6_inp->bu_opt->flags & MIP6_BU_AFLAG) { - error = mip6_send_ba( - &mip6_inp->ip6_dst, - &mip6_inp->ha_opt->home_addr, - coa, NULL, MIP6_BA_STATUS_ACCEPT, - mip6_inp->bu_opt->seqno, 0); - if (error) - return error; - } - } - return 0; - } - return 0; -} - - - -/* - ****************************************************************************** - * Function: mip6_ha2srcaddr - * Description: Copy Home Address option to IPv6 header source address, i.e - * replacing the existing source address. - ****************************************************************************** - */ -void -mip6_ha2srcaddr(m) -struct mbuf *m; /* The entire IPv6 packet */ -{ - register struct ip6_hdr *ip6; /* IPv6 header */ - -#if MIP6_DEBUG - mip6_debug("\nReceived Home Address Option\n"); - mip6_debug("Type/Length: %x / %u\n", mip6_inp->ha_opt->type, - mip6_inp->ha_opt->len); - mip6_debug("Home Address: %s\n", - ip6_sprintf(&mip6_inp->ha_opt->home_addr)); -#endif - - /* Copy the Home Address option address to the Source Address */ - ip6 = mtod(m, struct ip6_hdr *); - ip6->ip6_src = mip6_inp->ha_opt->home_addr; -} - - - -/* - ############################################################################## - # - # SENDING FUNCTIONS - # These functions are called when an IPv6 packet has been created internally - # by MIPv6 and shall be sent directly to its destination or when an option - # (BU, BA, BR) has been created and shall be stored in the mipv6 output queue - # for piggybacking on the first outgoing packet sent to the node. - # - ############################################################################## - */ - -/* - ****************************************************************************** - * Function: mip6_send_ba - * Description: Send a Binding Acknowledgement back to the Mobile Node. A new - * IPv6 packet is built including a IPv6 header, a Routing header - * and a Destination header (where the BA is stored). - * Ret value: 0 OK - * IPPROTO_DONE If anything goes wrong. - ****************************************************************************** - */ -int -mip6_send_ba(ip6_src, ip6_dst, coa, subbuf, status, seqno, lifetime) -struct in6_addr *ip6_src; /* Source address for packet */ -struct in6_addr *ip6_dst; /* Destination address for packet */ -struct in6_addr *coa; /* Care-of address for MN */ -struct mip6_subbuf *subbuf; /* Home Agents List sub-option */ -u_int8_t status; /* Result of the Binding Update request */ -u_int16_t seqno; /* Seq no in the BU being acknowledged */ -u_int32_t lifetime; /* Proposed lifetime in the BU */ -{ - struct mbuf *m_ip6; /* IPv6 header stored in a mbuf */ - struct mip6_opt_ba *ba_opt; /* BA allocated in this function */ - struct ip6_pktopts *opt; /* Options for IPv6 packet */ - int error; -#if MIP6_DEBUG - u_int8_t var; - int ii; -#endif - - opt = (struct ip6_pktopts *)MALLOC ip6_pktopts), - M_TEMP, M_WAITOK); - if (opt == NULL) - return IPPROTO_DONE; - bzero(opt, sizeof(struct ip6_pktopts)); - - opt->ip6po_hlim = -1; /* -1 means to use default hop limit */ - m_ip6 = mip6_create_ip6hdr(ip6_src, ip6_dst, IPPROTO_NONE); - if(m_ip6 == NULL) - return IPPROTO_DONE; - - opt->ip6po_rhinfo.ip6po_rhi_rthdr = mip6_create_rh(coa, - IPPROTO_DSTOPTS); - if(opt->ip6po_rhinfo.ip6po_rhi_rthdr == NULL) - return IPPROTO_DONE; - - ba_opt = mip6_create_ba(status, seqno, lifetime); - if (ba_opt == NULL) - return IPPROTO_DONE; - - opt->ip6po_dest2 = mip6_create_dh((void *)ba_opt, subbuf, - IPPROTO_NONE); - if(opt->ip6po_dest2 == NULL) - return IPPROTO_DONE; - - mip6_config.enable_outq = 0; - error = ip6_output(m_ip6, opt, NULL, 0, NULL, NULL); - if (error) { - _FREE(opt->ip6po_rhinfo.ip6po_rhi_rthdr, M_TEMP); - _FREE(opt->ip6po_dest2, M_TEMP); - _FREE(ba_opt, M_TEMP); - mip6_config.enable_outq = 1; - log(LOG_ERR, - "%s: ip6_output function failed to send BA, error = %d\n", - __FUNCTION__, error); - return error; - } - mip6_config.enable_outq = 1; - -#if MIP6_DEBUG - mip6_debug("\nSent Binding Acknowledgement\n"); - mip6_debug("IP Header Src: %s\n", ip6_sprintf(ip6_src)); - mip6_debug("IP Header Dst: %s\n", ip6_sprintf(ip6_dst)); - mip6_debug("Type/Length/Status: %x / %u / %u\n", - ba_opt->type, ba_opt->len, ba_opt->status); - mip6_debug("Seq no/Life time: %u / %u\n", - ba_opt->seqno, ba_opt->lifetime); - mip6_debug("Refresh time: %u\n", ba_opt->refresh); - - if (subbuf) { - mip6_debug("Sub-options present (TLV coded)\n"); - for (ii = 0; ii < subbuf->len; ii++) { - if (ii % 16 == 0) - mip6_debug("\t0x:"); - if (ii % 4 == 0) - mip6_debug(" "); - bcopy((caddr_t)&subbuf->buffer[ii], (caddr_t)&var, 1); - mip6_debug("%02x", var); - if ((ii + 1) % 16 == 0) - mip6_debug("\n"); - } - if (ii % 16) - mip6_debug("\n"); - } -#endif - - _FREE(opt->ip6po_rhinfo.ip6po_rhi_rthdr, M_TEMP); - _FREE(opt->ip6po_dest2, M_TEMP); - _FREE(ba_opt, M_TEMP); - return 0; -} - - - -/* - ****************************************************************************** - * Function: mip6_send_na - * Description: Sends a Neighbor Advertisement for a specific prefix. If the - * address is a aggregatable unicast address, i.e. prefix length - * is 64, a NA is sent to the site local and link local addresse - * as well. - * Ret value: - - ****************************************************************************** - */ -void -mip6_send_na(nap) -struct mip6_na *nap; /* Neighbor Advertisement sent */ -{ - struct mip6_prefix *pq; - struct nd_prefix *pr; /* Prefix list entry */ - struct in6_addr new_addr; /* New constructed address */ - struct in6_addr sl_addr; /* Site local address */ - - nap->no -= 1; - -#if MIP6_DEBUG - mip6_debug("\nSent Neighbor Advertisement (0x%x)\n", nap); -#endif - - /* Send NA for specified address if length equal to 0, otherwise for - each prefix with the same length as the address. - Different prefix list is used for HA and MN. */ - if (nap->prefix_len == 0) { - nd6_na_output(nap->ifp, &nap->dst_addr, &nap->target_addr, - nap->flags, nap->use_link_opt, NULL); -#if MIP6_DEBUG - mip6_debug("Target Address: %s\n", - ip6_sprintf(&nap->target_addr)); -#endif - } - - if ((MIP6_IS_HA_ACTIVE) && (nap->prefix_len != 0)) { - for (pq = mip6_pq; pq; pq = pq->next) { - if ((nap->prefix_len == pq->prefix_len) && - in6_are_prefix_equal(&pq->prefix, - &nap->target_addr, - pq->prefix_len)) { - mip6_build_in6addr(&new_addr, - &nap->target_addr, - &pq->prefix, - pq->prefix_len); - nd6_na_output(nap->ifp, &nap->dst_addr, - &new_addr, nap->flags, - nap->use_link_opt, NULL); -#if MIP6_DEBUG - mip6_debug("Target Address: %s\n", - ip6_sprintf(&new_addr)); -#endif - } else - continue; - - if (nap->prefix_len == 64) { - /* NA for the site-local address is - only sent if length equals to 64. */ - bcopy((caddr_t)&in6addr_sitelocal, - (caddr_t)&sl_addr, 6); - bcopy((caddr_t)&nap->target_addr + 6, - (caddr_t)&sl_addr + 6, 2); - mip6_build_in6addr(&new_addr, - &nap->target_addr, - &sl_addr, - nap->prefix_len); - nd6_na_output(nap->ifp, - &nap->dst_addr, - &new_addr, - nap->flags, - nap->use_link_opt, NULL); -#if MIP6_DEBUG - mip6_debug("Target Address: %s\n", - ip6_sprintf(&new_addr)); -#endif - - /* NA for the link-local address is - only sent if length equals to 64. */ - mip6_build_in6addr(&new_addr, - &nap->target_addr, - &in6addr_linklocal, - nap->prefix_len); - nd6_na_output(nap->ifp, - &nap->dst_addr, - &new_addr, - nap->flags, - nap->use_link_opt, NULL); -#if MIP6_DEBUG - mip6_debug("Target Address: %s\n", - ip6_sprintf(&new_addr)); -#endif - } - } - } else { - for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { - if ((nap->prefix_len == pr->ndpr_plen) && - in6_are_prefix_equal(&nap->target_addr, - &pr->ndpr_addr, - pr->ndpr_plen)) { - mip6_build_in6addr( - &new_addr, - &nap->target_addr, - &pr->ndpr_prefix.sin6_addr, - pr->ndpr_plen); - nd6_na_output(nap->ifp, - &nap->dst_addr, - &new_addr, - nap->flags, - nap->use_link_opt, NULL); -#if MIP6_DEBUG - mip6_debug("Target Address: %s\n", - ip6_sprintf(&new_addr)); -#endif - } else - continue; - - if (nap->prefix_len == 64) { - /* NA for the site-local address is - only sent if length equals to 64. */ - bcopy((caddr_t)&in6addr_sitelocal, - (caddr_t)&sl_addr, 6); - bcopy((caddr_t)&nap->target_addr + 6, - (caddr_t)&sl_addr + 6, 2); - mip6_build_in6addr(&new_addr, - &nap->target_addr, - &sl_addr, - nap->prefix_len); - nd6_na_output(nap->ifp, - &nap->dst_addr, - &new_addr, - nap->flags, - nap->use_link_opt, NULL); -#if MIP6_DEBUG - mip6_debug("Target Address: %s\n", - ip6_sprintf(&new_addr)); -#endif - - /* NA for the link-local address is - only sent if length equals to 64. */ - mip6_build_in6addr(&new_addr, - &nap->target_addr, - &in6addr_linklocal, - nap->prefix_len); - nd6_na_output(nap->ifp, - &nap->dst_addr, - &new_addr, - nap->flags, - nap->use_link_opt, NULL); -#if MIP6_DEBUG - mip6_debug("Target Address: %s\n", - ip6_sprintf(&new_addr)); -#endif - } - } - } - return; -} - - - -/* - ############################################################################## - # - # UTILITY FUNCTIONS - # Miscellaneous functions needed for the internal processing of incoming and - # outgoing control signals. - # - ############################################################################## - */ - -/* - ****************************************************************************** - * Function: mip6_create_ip6hdr - * Description: Create and fill in data for an IPv6 header to be used by - * packets originating from MIPv6. - * Ret value: NULL if a IPv6 header could not be created. - * Otherwise, pointer to a mbuf including the IPv6 header. - ****************************************************************************** - */ -struct mbuf * -mip6_create_ip6hdr(ip6_src, ip6_dst, next) -struct in6_addr *ip6_src; /* Source address for packet */ -struct in6_addr *ip6_dst; /* Destination address for packet */ -u_int8_t next; /* Next header following the IPv6 header */ -{ - struct ip6_hdr *ip6; /* IPv6 header */ - struct mbuf *m; /* Ptr to mbuf allocated for output data */ - - /* Allocate memory for the IPv6 header and fill it with data */ - ip6 = (struct ip6_hdr *)MALLOC ip6_hdr), - M_TEMP, M_WAITOK); - if (ip6 == NULL) - return NULL; - bzero(ip6, sizeof(struct ip6_hdr)); - - ip6->ip6_flow = 0; - ip6->ip6_vfc &= ~IPV6_VERSION_MASK; - ip6->ip6_vfc |= IPV6_VERSION; - ip6->ip6_plen = 0; - ip6->ip6_nxt = next; - ip6->ip6_hlim = IPV6_DEFHLIM; - - ip6->ip6_src = *ip6_src; - ip6->ip6_dst = *ip6_dst; - - /* Allocate memory for mbuf and copy IPv6 header to mbuf. */ - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) { - return NULL; - } - - m->m_len = sizeof(*ip6); - m->m_pkthdr.len = m->m_len; - m->m_pkthdr.rcvif = NULL; - bcopy((caddr_t)ip6, mtod(m, caddr_t), sizeof(*ip6)); - _FREE(ip6, M_TEMP); - return m; -} - - - -/* - ****************************************************************************** - * Function: mip6_create_rh - * Description: Create a routing header of type 0 and add the COA for the MN. - * Ret value: A pointer to the ip6_rthdr structure if everything is OK. - * Otherwise NULL. - ****************************************************************************** - */ -struct ip6_rthdr * -mip6_create_rh(coa, next) -struct in6_addr *coa; /* Care-of address for the MN */ -u_int8_t next; /* Next header following the routing header */ -{ - struct ip6_rthdr0 *rthdr0; /* Routing header type 0 */ - int len; - - len = sizeof(struct ip6_rthdr0) + sizeof(struct in6_addr); - rthdr0 = (struct ip6_rthdr0 *)MALLOC M_TEMP, M_WAITOK); - if (rthdr0 == NULL) - return NULL; - bzero(rthdr0, len); - - rthdr0->ip6r0_nxt = next; - rthdr0->ip6r0_len = 2; - rthdr0->ip6r0_type = 0; - rthdr0->ip6r0_segleft = 1; - rthdr0->ip6r0_reserved = 0; - bcopy((caddr_t)coa, (caddr_t)rthdr0 + sizeof(struct ip6_rthdr0), - sizeof(struct in6_addr)); - return (struct ip6_rthdr *)rthdr0; -} - - - -/* - ****************************************************************************** - * Function: mip6_create_ba - * Description: Create a Binding Acknowledgement option for transmission. - * Ret value: NULL if a BA option could not be created. - * Otherwise, pointer to the BA option. - ****************************************************************************** - */ -struct mip6_opt_ba * -mip6_create_ba(status, seqno, lifetime) -u_int8_t status; /* Result of the Binding Update request */ -u_int16_t seqno; /* Sequence number in the BU being acknowledged */ -u_int32_t lifetime; /* Proposed lifetime in the BU */ -{ - struct mip6_opt_ba *ba_opt; /* BA allocated in this function */ - - /* Allocate a Binding Aknowledgement option and set values */ - ba_opt = (struct mip6_opt_ba *)MALLOC mip6_opt_ba), - M_TEMP, M_WAITOK); - if (ba_opt == NULL) - return NULL; - bzero(ba_opt, sizeof(struct mip6_opt_ba)); - - ba_opt->type = IP6OPT_BINDING_ACK; - ba_opt->len = IP6OPT_BALEN; - ba_opt->status = status; - ba_opt->seqno = seqno; - ba_opt->lifetime = lifetime; - - /* Calculate value for refresh time */ - if (MIP6_IS_HA_ACTIVE) - ba_opt->refresh = (ba_opt->lifetime * 8) / 10; - else - ba_opt->refresh = ba_opt->lifetime; - - return ba_opt; -} - - - -/* - ****************************************************************************** - * Function: mip6_create_dh - * Description: Create a destination header and add either a BA or BU option. - * Ret value: A pointer to the ip6_dest structure if everything is OK. - * Otherwise NULL. - ****************************************************************************** - */ -struct ip6_dest * -mip6_create_dh(arg_opt, arg_sub, next) -void *arg_opt; /* BU or a BA option */ -struct mip6_subbuf *arg_sub; /* BU or BA sub-option (NULL if not present) */ -u_int8_t next; /* Next header following the dest header */ -{ - struct mip6_opt *opt; /* Destination option */ - struct ip6_dest *dest; /* Destination header */ - int off; /* Offset from start of Dest Header (byte) */ - int error; /* Error code from function call */ - - opt = (struct mip6_opt *)arg_opt; - dest = NULL; - if (opt->type == IP6OPT_BINDING_ACK) { - off = 3; - error = mip6_add_ba(&dest, &off, - (struct mip6_opt_ba *)opt, arg_sub); - if (error) { - if (dest != NULL) - _FREE(dest, M_TEMP); - return NULL; - } - dest->ip6d_nxt = next; - } else if (opt->type == IP6OPT_BINDING_UPDATE) { - off = 2; - error = mip6_add_bu(&dest, &off, - (struct mip6_opt_bu *)opt, arg_sub); - if (error) { - if (dest != NULL) - _FREE(dest, M_TEMP); - return NULL; - } - dest->ip6d_nxt = next; - } - return dest; -} - - - -/* - ****************************************************************************** - * Function: mip6_opt_offset - * Description: Find offset for BU, BA or BR option in the Destination Header. - * The option type is specified as input parameter and the offset - * to start of the first option of the specified type is returned. - * Ret value: Offset (bytes) to specified option from beginning of m_in. - * If no option is found a length of 0 is returned indicating an - * error. - ****************************************************************************** - */ -int -mip6_opt_offset(m_in, off, type) -struct mbuf *m_in; /* Mbuf containing the entire IPv6 packet */ -int off; /* Offset from start of mbuf to start of dest option */ -int type; /* Type of option to look for */ -{ - int ii; /* Internal counter */ - u_int8_t opttype; /* Option type found in Destination Header*/ - u_int8_t optlen; /* Option length incl type and length */ - u_int32_t len; /* Length of Destination Header in bytes */ - u_int8_t len8; /* Length of Destination Header in bytes */ - u_int32_t offset; /* Offset to BU option from beginning of m_in */ - - m_copydata(m_in, off + 1, sizeof(len8), (caddr_t)&len8); - len = (len8 + 1) << 3; - - offset = 0; - for (ii = 2; ii < len;) { - m_copydata(m_in, off + ii, sizeof(opttype), (caddr_t)&opttype); - if (opttype == type) { - offset = off + ii; - break; - } else if (opttype == IP6OPT_PAD1) { - ii += 1; - continue; - } else { - ii += 1; - } - - m_copydata(m_in, off + ii, sizeof(optlen), (caddr_t)&optlen); - ii += 1 + optlen; - } - return offset; -} - - - -/* - ****************************************************************************** - * Function: mip6_addr_on_link - * Description: Check if an address is an on-link IPv6 address with respect to - * the home agent's current prefix list. - * Ret value: 0 = OK - * 133 = Not home subnet - * 136 = Incorrect interface identifier length - ****************************************************************************** - */ -int -mip6_addr_on_link(addr, prefix_len) -struct in6_addr *addr; /* IPv6 address to check */ -int prefix_len; /* Prefix length for the address */ -{ - struct mip6_prefix *pr; /* Pointer to entries in the prexix list */ - - for (pr = mip6_pq; pr; pr = pr->next) { - /* Check if the IPv6 prefixes are equal, i.e. of the same - IPv6 type of address. */ - /* If they are, verify that the prefix length is correct. */ - if (in6_are_prefix_equal(addr, &pr->prefix, pr->prefix_len)) { - if (prefix_len == 0) - return 0; - - if (pr->prefix_len == prefix_len) - return 0; - else - return MIP6_BA_STATUS_IFLEN; - } - } - return MIP6_BA_STATUS_SUBNET; -} - - - -/* - ****************************************************************************** - * Function: mip6_min_lifetime - * Description: Decide the remaining valid lifetime for a home address. If the - * prefix length is zero the lifetime is the lifetime of the - * prefix list entry for this prefix. - * If the prefix length is non-zero the lifetime is the minimum - * remaining valid lifetime for all subnet prefixes on the mobile - * node's home link. - * Note: This function is only used by the Home Agent. - * Ret value: Lifetime - ****************************************************************************** - */ -u_int32_t -mip6_min_lifetime(addr, prefix_len) -struct in6_addr *addr; /* IPv6 address to check */ -int prefix_len; /* Prefix length for the address */ -{ - struct mip6_prefix *pr; /* Ptr to entries in the prexix list */ - u_int32_t min_time; /* Minimum life time */ - - min_time = 0xffffffff; - - for (pr = mip6_pq; pr; pr = pr->next) { - /* Different handling depending on the prefix length. */ - if (prefix_len == 0) { - if (in6_are_prefix_equal(addr, &pr->prefix, - pr->prefix_len)) { - return pr->valid_time; - } - } else - min_time = min(min_time, pr->valid_time); - } - return min_time; -} - - - -/* - ****************************************************************************** - * Function: mip6_build_in6addr - * Description: Build an in6 address from a prefix and the interface id. - * The length of the different parts is decided by prefix_len. - * Ret value: - - ****************************************************************************** - */ -void -mip6_build_in6addr(new_addr, id, prefix, prefix_len) -struct in6_addr *new_addr; /* New address built in this function */ -struct in6_addr *id; /* Interface id part of the address */ -const struct in6_addr *prefix; /* Prefix part of the address */ -int prefix_len; /* Prefix length (bits) */ -{ - u_int8_t byte_pr, byte_id; - int ii, jj; - - for (ii = 0; ii < prefix_len / 8; ii++) - new_addr->s6_addr8[ii] = prefix->s6_addr8[ii]; - - if (prefix_len % 8) { - /* Add the last bits of the prefix to the common byte. */ - byte_pr = prefix->s6_addr8[ii]; - byte_pr = byte_pr >> (8 - (prefix_len % 8)); - byte_pr = byte_pr << (8 - (prefix_len % 8)); - - /* Then, add the first bits of the interface id to the - common byte. */ - byte_id = id->s6_addr8[ii]; - byte_id = byte_id << (prefix_len % 8); - byte_id = byte_id >> (prefix_len % 8); - new_addr->s6_addr8[ii] = byte_pr | byte_id; - ii += 1; - } - - for (jj = ii; jj < 16; jj++) - new_addr->s6_addr8[jj] = id->s6_addr8[jj]; -} - - - -/* - ****************************************************************************** - * Function: mip6_build_ha_anycast - * Description: Build an mobile IPv6 Home-Agents anycast address from a prefix - * and the prefix length. The interface id is according to - * RFC2526. - * Ret value: - - ****************************************************************************** - */ -void -mip6_build_ha_anycast(new_addr, prefix, prefix_len) -struct in6_addr *new_addr; /* New address built in this function */ -const struct in6_addr *prefix; /* Prefix part of the address */ -int prefix_len; /* Prefix length (bits) */ -{ - struct in6_addr addr; - - - if (prefix->s6_addr8[0] == 0xff) { - *new_addr = in6addr_any; - return; - } - - if (((prefix->s6_addr8[0] & 0xe0) != 0) && (prefix_len != 64)) { - *new_addr = in6addr_any; - return; - } - - if (((prefix->s6_addr8[0] & 0xe0) != 0) && (prefix_len == 64)) - addr = in6addr_aha_64; - else - addr = in6addr_aha_nn; - - mip6_build_in6addr(new_addr, &addr, prefix, prefix_len); -} - - - -/* - ****************************************************************************** - * Function: mip6_add_ifaddr - * Description: Similar to "ifconfig prefixlen ". - * Ret value: Standard error codes. - ****************************************************************************** - */ -int -mip6_add_ifaddr(struct in6_addr *addr, - struct ifnet *ifp, - int plen, - int flags) /* Note: IN6_IFF_NODAD available flag */ -{ - struct in6_aliasreq *ifra, dummy; - struct sockaddr_in6 *sa6; - struct sockaddr_in6 oldaddr; - struct in6_ifaddr *ia, *oia; - struct in6_addrlifetime *lt; - int error = 0, hostIsNew, prefixIsNew; - int s; -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - struct ifaddr *ifa; -#endif -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) - time_t time_second = (time_t)time.tv_sec; -#endif - - bzero(&dummy, sizeof(dummy)); - ifra = &dummy; - - ifra->ifra_addr.sin6_len = sizeof(ifra->ifra_addr); - ifra->ifra_addr.sin6_family = AF_INET6; - ifra->ifra_addr.sin6_addr = *addr; - - if (plen != 0) { - ifra->ifra_prefixmask.sin6_len = - sizeof(ifra->ifra_prefixmask); - ifra->ifra_prefixmask.sin6_family = AF_INET6; - in6_prefixlen2mask(&ifra->ifra_prefixmask.sin6_addr, plen); - /* XXXYYY Should the prefix also change its prefixmask? */ - } - - ifra->ifra_flags = flags; - ifra->ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; - ifra->ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; - - sa6 = &ifra->ifra_addr; - - /* "ifconfig ifp inet6 Home_Address prefixlen 64/128 (alias?)" */ - if (ifp == 0) - return EOPNOTSUPP; - - s = splnet(); - - /* - * Code recycled from in6_control(). - */ - - /* - * Find address for this interface, if it exists. - */ - if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) { - if (sa6->sin6_addr.s6_addr16[1] == 0) { - /* interface ID is not embedded by the user */ - sa6->sin6_addr.s6_addr16[1] = - htons(ifp->if_index); - } - else if (sa6->sin6_addr.s6_addr16[1] != - htons(ifp->if_index)) { - splx(s); - return(EINVAL); /* ifid is contradict */ - } - if (sa6->sin6_scope_id) { - if (sa6->sin6_scope_id != - (u_int32_t)ifp->if_index) { - splx(s); - return(EINVAL); - } - sa6->sin6_scope_id = 0; /* XXX: good way? */ - } - } - ia = in6ifa_ifpwithaddr(ifp, &sa6->sin6_addr); - - if (ia == 0) { - ia = (struct in6_ifaddr *) - MALLOC M_IFADDR, M_WAITOK); - if (ia == NULL) { - splx(s); - return (ENOBUFS); - } - bzero((caddr_t)ia, sizeof(*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_prefixmask; - - ia->ia_ifp = ifp; - if ((oia = in6_ifaddr) != NULL) { - for ( ; oia->ia_next; oia = oia->ia_next) - continue; - oia->ia_next = ia; - } else - in6_ifaddr = ia; - ia->ia_ifa.ifa_refcnt++; - -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - if ((ifa = ifp->if_addrlist) != NULL) { - for ( ; ifa->ifa_next; ifa = ifa->ifa_next) - continue; - ifa->ifa_next = &ia->ia_ifa; - } else - ifp->if_addrlist = &ia->ia_ifa; -#else - TAILQ_INSERT_TAIL(&ifp->if_addrlist, &ia->ia_ifa, - ifa_list); -#endif - ia->ia_ifa.ifa_refcnt++; - } - - /* sanity for overflow - beware unsigned */ - lt = &ifra->ifra_lifetime; - if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME - && lt->ia6t_vltime + time_second < time_second) { - splx(s); - return EINVAL; - } - if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME - && lt->ia6t_pltime + time_second < time_second) { - splx(s); - return EINVAL; - } - prefixIsNew = 0; - hostIsNew = 1; - - if (ifra->ifra_addr.sin6_len == 0) { - ifra->ifra_addr = ia->ia_addr; - hostIsNew = 0; - } else if (IN6_ARE_ADDR_EQUAL(&ifra->ifra_addr.sin6_addr, - &ia->ia_addr.sin6_addr)) - hostIsNew = 0; - - if (ifra->ifra_prefixmask.sin6_len) { - in6_ifscrub(ifp, ia); - ia->ia_prefixmask = ifra->ifra_prefixmask; - prefixIsNew = 1; - } - if ((ifp->if_flags & IFF_POINTOPOINT) && - (ifra->ifra_dstaddr.sin6_family == AF_INET6)) { - in6_ifscrub(ifp, ia); - oldaddr = ia->ia_dstaddr; - ia->ia_dstaddr = ifra->ifra_dstaddr; - /* link-local index check: should be a separate function? */ - if (IN6_IS_ADDR_LINKLOCAL(&ia->ia_dstaddr.sin6_addr)) { - if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] == 0) { - /* - * interface ID is not embedded by - * the user - */ - ia->ia_dstaddr.sin6_addr.s6_addr16[1] - = htons(ifp->if_index); - } else if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] != - htons(ifp->if_index)) { - ia->ia_dstaddr = oldaddr; - splx(s); - return(EINVAL); /* ifid is contradict */ - } - } - prefixIsNew = 1; /* We lie; but effect's the same */ - } - if (ifra->ifra_addr.sin6_family == AF_INET6 && - (hostIsNew || prefixIsNew)) - { - error = in6_ifinit(ifp, ia, &ifra->ifra_addr, 0); - } - if (ifra->ifra_addr.sin6_family == AF_INET6 - && hostIsNew && (ifp->if_flags & IFF_MULTICAST)) { - int error_local = 0; - - /* - * join solicited multicast addr for new host id - */ - struct in6_addr llsol; - bzero(&llsol, sizeof(struct in6_addr)); - llsol.s6_addr16[0] = htons(0xff02); - llsol.s6_addr16[1] = htons(ifp->if_index); - llsol.s6_addr32[1] = 0; - llsol.s6_addr32[2] = htonl(1); - llsol.s6_addr32[3] = - ifra->ifra_addr.sin6_addr.s6_addr32[3]; - llsol.s6_addr8[12] = 0xff; - (void)in6_addmulti(&llsol, ifp, &error_local); - if (error == 0) - error = error_local; - } - - ia->ia6_flags = ifra->ifra_flags; - ia->ia6_flags &= ~IN6_IFF_DUPLICATED; /*safety*/ - ia->ia6_flags &= ~IN6_IFF_NODAD; /* Mobile IPv6 */ - - ia->ia6_lifetime = ifra->ifra_lifetime; - /* for sanity */ - if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { - ia->ia6_lifetime.ia6t_expire = - time_second + ia->ia6_lifetime.ia6t_vltime; - } else - ia->ia6_lifetime.ia6t_expire = 0; - if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { - ia->ia6_lifetime.ia6t_preferred = - time_second + ia->ia6_lifetime.ia6t_pltime; - } else - ia->ia6_lifetime.ia6t_preferred = 0; - - /* - * Perform DAD, if needed. - * XXX It may be of use, if we can administratively - * disable DAD. - */ - switch (ifp->if_type) { - case IFT_ARCNET: - case IFT_ETHER: - case IFT_FDDI: -#if 0 - case IFT_ATM: - case IFT_SLIP: - case IFT_PPP: -#endif - /* Mobile IPv6 modification */ - if ((ifra->ifra_flags & IN6_IFF_NODAD) == 0) { - ia->ia6_flags |= IN6_IFF_TENTATIVE; - nd6_dad_start((struct ifaddr *)ia, NULL); - } - break; - case IFT_DUMMY: - case IFT_FAITH: - case IFT_GIF: - case IFT_LOOP: - default: - break; - } - - if (hostIsNew) { - int iilen; - int error_local = 0; - - iilen = (sizeof(ia->ia_prefixmask.sin6_addr) << 3) - - in6_mask2len(&ia->ia_prefixmask.sin6_addr); - error_local = in6_prefix_add_ifid(iilen, ia); - if (error == 0) - error = error_local; - } - - splx(s); - return error; - - -} - - - -/* - ****************************************************************************** - * Function: mip6_tunnel_output - * Description: Encapsulates packet in an outer header which is determined - * of the Binding Cache entry provided. Note that packet is - * (currently) not sent here, but should be sent by the caller. - * Ret value: != 0 if failure. It's up to the caller to free the mbuf chain. - ****************************************************************************** - */ -int -mip6_tunnel_output(mp, bc) - struct mbuf **mp; - struct mip6_bc *bc; -{ - struct sockaddr_in6 dst; - const struct encaptab *ep = bc->ep; - struct mbuf *m = *mp; - struct sockaddr_in6 *sin6_src = (struct sockaddr_in6 *)&ep->src; - struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)&ep->dst; - struct ip6_hdr *ip6; - u_int8_t itos; - int len; - - bzero(&dst, sizeof(dst)); - dst.sin6_len = sizeof(struct sockaddr_in6); - dst.sin6_family = AF_INET6; - dst.sin6_addr = bc->coa; - - if (ep->af != AF_INET6 || ep->dst.ss_len != dst.sin6_len || - bcmp(&ep->dst, &dst, dst.sin6_len) != 0 ) - return EFAULT; - - /* Recursion problems? */ - - if (IN6_IS_ADDR_UNSPECIFIED(&sin6_src->sin6_addr)) { - return EFAULT; - } - - len = m->m_pkthdr.len; - - if (m->m_len < sizeof(*ip6)) { - m = m_pullup(m, sizeof(*ip6)); - if (!m) - return ENOBUFS; - } - ip6 = mtod(m, struct ip6_hdr *); - itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; - - - /* prepend new IP header */ - M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT); - if (m && m->m_len < sizeof(struct ip6_hdr)) - m = m_pullup(m, sizeof(struct ip6_hdr)); - if (m == NULL) { -#if MIP6_DEBUG - printf("ENOBUFS in mip6_tunnel_output %d\n", __LINE__); -#endif - return ENOBUFS; - } - - ip6 = mtod(m, struct ip6_hdr *); - ip6->ip6_flow = 0; - ip6->ip6_vfc &= ~IPV6_VERSION_MASK; - ip6->ip6_vfc |= IPV6_VERSION; - ip6->ip6_plen = htons((u_short)len); - ip6->ip6_nxt = IPPROTO_IPV6; - ip6->ip6_hlim = ip6_gif_hlim; /* Same? */ - ip6->ip6_src = sin6_src->sin6_addr; - - /* bidirectional configured tunnel mode */ - if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr)) - ip6->ip6_dst = sin6_dst->sin6_addr; - else - return ENETUNREACH; - - *mp = m; - return 0; -} - - - -/* - ****************************************************************************** - * Function: mip6_tunnel_input - * Description: similar to gif_input() and in6_gif_input(). - * Ret value: standard error codes. - ****************************************************************************** - */ -int -mip6_tunnel_input(mp, offp, proto) -struct mbuf **mp; -int *offp, proto; -{ - struct mbuf *m = *mp; - struct ip6_hdr *ip6; - int s, af = 0; - u_int32_t otos; - - ip6 = mtod(m, struct ip6_hdr *); - otos = ip6->ip6_flow; - m_adj(m, *offp); - - switch (proto) { - case IPPROTO_IPV6: - { - struct ip6_hdr *ip6; - af = AF_INET6; - if (m->m_len < sizeof(*ip6)) { - m = m_pullup(m, sizeof(*ip6)); - if (!m) - return IPPROTO_DONE; - } - m->m_flags |= M_MIP6TUNNEL; /* Tell MN that this packet - was tunnelled. */ - ip6 = mtod(m, struct ip6_hdr *); - - s = splimp(); - if (IF_QFULL(&ip6intrq)) { - IF_DROP(&ip6intrq); /* update statistics */ - m_freem(m); - splx(s); - return IPPROTO_DONE; - } - IF_ENQUEUE(&ip6intrq, m); -#if 0 - /* we don't need it as we tunnel IPv6 in IPv6 only. */ - schednetisr(NETISR_IPV6); -#endif - splx(s); - break; - } - default: -#if MIP6_DEBUG - mip6_debug("%s: protocol %d not supported.\n", __FUNCTION__, - proto); -#endif - m_freem(m); - return IPPROTO_DONE; - } - - return IPPROTO_DONE; -} - - - -/* - ****************************************************************************** - * Function: mip6_tunnel - * Description: Create, move or delete a tunnel from the Home Agent to the MN - * or from the Mobile Node to the Home Agent. - * Ret value: Standard error codes. - ****************************************************************************** - */ -int -mip6_tunnel(ip6_src, ip6_dst, action, start, entry) -struct in6_addr *ip6_src; /* Tunnel start point */ -struct in6_addr *ip6_dst; /* Tunnel end point */ -int action; /* Action: MIP6_TUNNEL_{ADD,MOVE,DEL} */ -int start; /* Either the Home Agent or the Mobile Node */ -void *entry; /* BC or ESM depending on start variable */ -{ - const struct encaptab *ep; /* Encapsulation entry */ - const struct encaptab **ep_store; /* Where to store encap reference */ - struct sockaddr_in6 src, srcm; - struct sockaddr_in6 dst, dstm; - struct in6_addr mask; - int mask_len = 128; - - ep_store = NULL; - if ((start == MIP6_NODE_MN) && (entry != NULL)) - ep_store = &((struct mip6_esm *)entry)->ep; - else if ((start == MIP6_NODE_HA) && (entry != NULL)) - ep_store = &((struct mip6_bc *)entry)->ep; - else { -#if MIP6_DEBUG - printf("%s: Tunnel not modified\n", __FUNCTION__); -#endif - return 0; - } - - if (action == MIP6_TUNNEL_DEL) { - /* Moving to Home network. Remove tunnel. */ - if (ep_store && *ep_store) { - encap_detach(*ep_store); - *ep_store = NULL; - } - return 0; - } - - if ((action == MIP6_TUNNEL_ADD) || (action == MIP6_TUNNEL_MOVE)) { - if (action == MIP6_TUNNEL_MOVE && ep_store && *ep_store) { - /* Remove the old encapsulation entry first. */ - encap_detach(*ep_store); - *ep_store = NULL; - } - - bzero(&src, sizeof(src)); - src.sin6_family = AF_INET6; - src.sin6_len = sizeof(struct sockaddr_in6); - src.sin6_addr = *ip6_src; - - in6_prefixlen2mask(&mask, mask_len); - bzero(&srcm, sizeof(srcm)); - srcm.sin6_family = AF_INET6; - srcm.sin6_len = sizeof(struct sockaddr_in6); - srcm.sin6_addr = mask; - - bzero(&dst, sizeof(dst)); - dst.sin6_family = AF_INET6; - dst.sin6_len = sizeof(struct sockaddr_in6); - dst.sin6_addr = *ip6_dst; - - in6_prefixlen2mask(&mask, mask_len); - bzero(&dstm, sizeof(dstm)); - dstm.sin6_family = AF_INET6; - dstm.sin6_len = sizeof(struct sockaddr_in6); - dstm.sin6_addr = mask; - - ep = encap_attach(AF_INET6, -1, - (struct sockaddr *)&src, - (struct sockaddr *)&srcm, - (struct sockaddr *)&dst, - (struct sockaddr *)&dstm, - (struct protosw *)&mip6_tunnel_protosw, - NULL); - if (ep == NULL) - return EINVAL; - *ep_store = ep; - return 0; - } - return EINVAL; -} - - - -/* - ****************************************************************************** - * Function: mip6_proxy - * Description: Set or delete address to act proxy for. - * Ret value: Standard error codes. - ****************************************************************************** - */ -int -mip6_proxy(struct in6_addr* addr, - struct in6_addr* local, - int cmd) -{ - struct sockaddr_in6 mask /* = {sizeof(mask), AF_INET6 }*/; - struct sockaddr_in6 sa6; - struct sockaddr_dl *sdl; - struct ifaddr *ifa; - struct ifnet *ifp; - int flags, error; - struct rtentry *nrt; - - if (cmd == RTM_DELETE) { - struct rtentry *rt; - - bzero(&sa6, sizeof(sa6)); - sa6.sin6_family = AF_INET6; - sa6.sin6_len = sizeof(sa6); - sa6.sin6_addr = *addr; - -#ifdef __FreeBSD__ || defined (__APPLE__) - rt = rtalloc1((struct sockaddr *)&sa6, 1, 0UL); -#else - rt = rtalloc1((struct sockaddr *)&sa6, 1); -#endif - if (rt == NULL) - return EHOSTUNREACH; - - error = rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, - rt_mask(rt), 0, (struct rtentry **)0); - rt->rt_refcnt--; - rt = NULL; - return error; - } - - /* Create sa6 */ - bzero(&sa6, sizeof(sa6)); - sa6.sin6_family = AF_INET6; - sa6.sin6_len = sizeof(sa6); - sa6.sin6_addr = *local; - - ifa = ifa_ifwithaddr((struct sockaddr *)&sa6); - if (ifa == NULL) - return EINVAL; - - sa6.sin6_addr = *addr; - - /* Create sdl */ - ifp = ifa->ifa_ifp; - -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) -#else - for (ifa = ifp->if_addrlist.tqh_first; ifa; - ifa = ifa->ifa_list.tqe_next) -#endif - if (ifa->ifa_addr->sa_family == AF_LINK) - break; - - if (!ifa) - return EINVAL; - - MALLOC(sdl, struct sockaddr_dl *, ifa->ifa_addr->sa_len, M_IFMADDR, - M_WAITOK); - bcopy((struct sockaddr_dl *)ifa->ifa_addr, sdl, ifa->ifa_addr->sa_len); - - /* Create mask */ - bzero(&mask, sizeof(mask)); - mask.sin6_family = AF_INET6; - mask.sin6_len = sizeof(mask); - - in6_len2mask(&mask.sin6_addr, 128); - - flags = (RTF_STATIC | RTF_ANNOUNCE | RTA_NETMASK); - - error = rtrequest(RTM_ADD, (struct sockaddr *)&sa6, - (struct sockaddr *)sdl, - (struct sockaddr *)&mask, flags, &nrt); - - if (error == 0) { - /* avoid expiration */ - if (nrt) { - nrt->rt_rmx.rmx_expire = 0; - nrt->rt_genmask = NULL; - nrt->rt_refcnt--; - } - else - error = EINVAL; - } - _FREE(sdl, M_IFMADDR); - return error; -} - - - -/* - ############################################################################## - # - # LIST FUNCTIONS - # The correspondent node maintains a Binding Cache list for each node from - # which it has received a BU. - # It also maintains a list of Neighbor Advertisements that shall be sent - # either by the home agent when start acting as a proxy for the mobile node - # or by the mobile node when returning to the home network. - # - ############################################################################## - */ - -/* - ****************************************************************************** - * Function: mip6_bc_find - * Description: Find an entry in the Binding Cache list. - * Ret value: Pointer to Binding Cache entry or NULL if no entry found. - ****************************************************************************** - */ -struct mip6_bc * -mip6_bc_find(home_addr) -struct in6_addr *home_addr; /* Home Address of the MN for which the BC - entry is searched */ -{ - struct mip6_bc *bcp; /* Entry in the Binding Cache list */ - - for (bcp = mip6_bcq; bcp; bcp = bcp->next) { - if (IN6_ARE_ADDR_EQUAL(home_addr, &bcp->home_addr)) - return bcp; - } - return NULL; -} - - - -/* - ****************************************************************************** - * Function: mip6_bc_create - * Description: Create a new Binding Cache entry, add it first to the Binding - * Cache list and set parameters for the entry. - * Ret value: Pointer to the created BC entry or NULL. - * Note 1: If the BC timeout function has not been started it is started. - * The BC timeout function will be called once every second until - * there are no more entries in the BC list. - * Note 2: The gif i/f is created/updated in function mip6_tunnel and - * should not be taken care of here. - ****************************************************************************** - */ -struct mip6_bc * -mip6_bc_create(home_addr, coa, lifetime, hr, rtr, prefix_len, seqno) -struct in6_addr *home_addr; /* Home Address for the mobile node */ -struct in6_addr *coa; /* COA for the mobile node */ -u_int32_t lifetime; /* Remaining lifetime for this BC entry */ -u_int8_t hr; /* Flag for home registration (0/1) */ -u_int8_t rtr; /* MN is router (0/1) */ -u_int8_t prefix_len; /* Prefix length for Home Address */ -u_int16_t seqno; /* Sequence number in the received BU */ -{ - struct mip6_bc *bcp; /* Created BC list entry*/ - int s; - - bcp = (struct mip6_bc *)MALLOC mip6_bc), - M_TEMP, M_WAITOK); - if (bcp == NULL) - return NULL; - bzero((caddr_t)bcp, sizeof(struct mip6_bc)); - - bcp->next = NULL; - bcp->home_addr = *home_addr; - bcp->coa = *coa; - bcp->lifetime = lifetime; - bcp->hr_flag = hr; - bcp->prefix_len = prefix_len; - bcp->seqno = seqno; - bcp->lasttime = 0; - bcp->ep = NULL; - - if (bcp->hr_flag) - bcp->rtr_flag = rtr; - else { - bcp->rtr_flag = 0; - - if (mip6_config.br_update > 60) - bcp->info.br_interval = 60; - else if (mip6_config.br_update < 2) - bcp->info.br_interval = 2; - else - bcp->info.br_interval = mip6_config.br_update; - } - - /* Insert the entry as the first entry in the Binding Cache list. */ - s = splnet(); - if (mip6_bcq == NULL) { - mip6_bcq = bcp; -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - mip6_timer_bc_handle = -#endif - timeout(mip6_timer_bc, (void *)0, hz); - } else { - bcp->next = mip6_bcq; - mip6_bcq = bcp; - } - splx(s); - -#if MIP6_DEBUG - mip6_debug("\nBinding Cache Entry created (0x%x)\n", bcp); - mip6_debug("Home Addr/Prefix len: %s / %u\n", - ip6_sprintf(&bcp->home_addr), bcp->prefix_len); - mip6_debug("Care-of Address: %s\n", ip6_sprintf(&bcp->coa)); - mip6_debug("Remaining lifetime: %u\n", bcp->lifetime); - mip6_debug("Sequence number: %u\n", bcp->seqno); - mip6_debug("Home reg/Router: "); - if (bcp->hr_flag) - mip6_debug("TRUE / "); - else - mip6_debug("FALSE / "); - - if (bcp->rtr_flag) - mip6_debug("TRUE\n"); - else - mip6_debug("FALSE\n"); -#endif - return bcp; -} - - - -/* - ****************************************************************************** - * Function: mip6_bc_update - * Description: Update an existing Binding Cache entry - * Ret value: - - * Note: The gif i/f is created/updated in function mip6_tunnel and - * should not be taken care of here. - ****************************************************************************** - */ -void -mip6_bc_update(bcp, coa, lifetime, hr, rtr, prefix_len, seqno, info, lasttime) -struct mip6_bc *bcp; /* BC entry being allocated or updated */ -struct in6_addr *coa; /* COA for the mobile node */ -u_int32_t lifetime; /* Remaining lifetime for this BC entry */ -u_int8_t hr; /* Flag for home registration (0/1) */ -u_int8_t rtr; /* MN is router (0/1) */ -u_int8_t prefix_len; /* Prefix length for Home Address */ -u_int16_t seqno; /* Sequence number in the received BU */ -struct bc_info info; /* Usage info for cache replacement policy */ -time_t lasttime; /* The time at which a BR was last sent */ -{ - bcp->coa = *coa; - bcp->lifetime = lifetime; - bcp->hr_flag = hr; - bcp->prefix_len = prefix_len; - bcp->seqno = seqno; - - if (bcp->hr_flag) { - bcp->rtr_flag = rtr; - bzero((caddr_t)&bcp->info, sizeof(struct bc_info)); - } else { - bcp->rtr_flag = 0; - - if (info.br_interval > 60) - bcp->info.br_interval = 60; - else if (info.br_interval < 2) - bcp->info.br_interval = 2; - else - bcp->info.br_interval = info.br_interval; - } - bcp->lasttime = lasttime; - -#if MIP6_DEBUG - mip6_debug("\nBinding Cache Entry updated (0x%x)\n", bcp); - mip6_debug("Home Addr/Prefix len: %s / %u\n", - ip6_sprintf(&bcp->home_addr), bcp->prefix_len); - mip6_debug("Care-of Address: %s\n", ip6_sprintf(&bcp->coa)); - mip6_debug("Remaining lifetime: %u\n", bcp->lifetime); - mip6_debug("Sequence number: %u\n", bcp->seqno); - mip6_debug("Home reg/Router: "); - if (bcp->hr_flag) - mip6_debug("TRUE / "); - else - mip6_debug("FALSE / "); - - if (bcp->rtr_flag) - mip6_debug("TRUE\n"); - else - mip6_debug("FALSE\n"); -#endif - return; -} - - - -/* - ****************************************************************************** - * Function: mip6_bc_delete - * Description: Delete an entry in the Binding Cache list. - * Ret value: Error code - * Pointer to next entry in list or NULL if last entry removed. - ****************************************************************************** - */ -int -mip6_bc_delete(bcp_del, bcp_nxt) -struct mip6_bc *bcp_del; /* Pointer to BC entry to delete */ -struct mip6_bc **bcp_nxt; /* Returns next entry in the list */ -{ - struct mip6_bc *bcp; /* Current entry in the BC list */ - struct mip6_bc *bcp_prev; /* Previous entry in the BC list */ - struct mip6_bc *bcp_next; /* Next entry in the BC list */ - int s, error = 0; - - s = splnet(); - bcp_prev = NULL; - bcp_next = NULL; - for (bcp = mip6_bcq; bcp; bcp = bcp->next) { - bcp_next = bcp->next; - if (bcp != bcp_del) { - bcp_prev = bcp; - continue; - } - - /* Make sure that the list pointers are correct. */ - if (bcp_prev == NULL) - mip6_bcq = bcp->next; - else - bcp_prev->next = bcp->next; - - if (bcp->hr_flag) { - /* The HA should stop acting as a proxy for the MN. */ - error = mip6_proxy(&bcp->home_addr, NULL, RTM_DELETE); - if (error) { -#if MIP6_DEBUG - mip6_debug("%s: delete proxy error = %d\n", - __FUNCTION__, error); -#endif - *bcp_nxt = bcp_next; - return error; - } - - /* Delete the existing tunnel to the MN. */ - mip6_tunnel(NULL, NULL, MIP6_TUNNEL_DEL, MIP6_NODE_HA, - (void *)bcp); - } - -#if MIP6_DEBUG - mip6_debug("\nBinding Cache Entry deleted (0x%x)\n", bcp); -#endif - _FREE(bcp, M_TEMP); - - /* Remove the timer if the BC queue is empty */ - if (mip6_bcq == NULL) { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - untimeout(mip6_timer_bc, (void *)NULL, - mip6_timer_bc_handle); - callout_handle_init(&mip6_timer_bc_handle); -#else - untimeout(mip6_timer_bc, (void *)NULL); -#endif - } - break; - } - splx(s); - - *bcp_nxt = bcp_next; - return error; -} - - - -/* - ****************************************************************************** - * Function: mip6_na_create - * Description: Create a NA entry and add it to the list of Neighbor Adver- - * tisements. The NA will be repeateadly sent by either the - * Mobile Node when returning to its home link or by the Home - * Agent when acting as a proxy for a Mobile Node while away - * from its home network. - * Note: The first Neighbor Advertisement is sent by this function. - * Ret value: Pointer to the created entry or NULL in case of error. - ****************************************************************************** - */ -struct mip6_na * -mip6_na_create(home_addr, dst_addr, target_addr, prefix_len, - flags, use_link_opt) -struct in6_addr *home_addr; /* Home address of the mobile node */ -struct in6_addr *dst_addr; /* Destination address */ -struct in6_addr *target_addr; /* Target address */ -u_int8_t prefix_len; /* Prefix length of the home address */ -u_long flags; /* Flags for the NA message */ -int use_link_opt; /* Include Target link layer address option or - not (0 = Do not include, 1 = Include) */ -{ - struct mip6_na *nap; /* Created NA message */ - struct mip6_link_list *llp; /* Link list entry */ - struct mip6_ha_list *halp; /* Home agent list entry */ - struct mip6_addr_list *addrp; /* Address list entry */ - struct nd_prefix *pr; /* Prefix list entry */ - int s, start_timer = 0; - - llp = NULL; - halp = NULL; - addrp = NULL; - pr = NULL; - - if (mip6_naq == NULL) - start_timer = 1; - - nap = (struct mip6_na *)MALLOC mip6_na), - M_TEMP, M_WAITOK); - if (nap == NULL) - return NULL; - bzero(nap, sizeof(struct mip6_na)); - - nap->next = NULL; - nap->home_addr = *home_addr; - nap->dst_addr = *dst_addr; - nap->target_addr = *target_addr; - nap->prefix_len = prefix_len; - nap->flags = flags; - nap->use_link_opt = use_link_opt; - nap->no = MIP6_MAX_ADVERT_REXMIT; - - /* The interface that shall be used may not be assumed to be the - interface of the incoming packet, but must be the interface stated - in the prefix that matches the home address. */ - if (MIP6_IS_HA_ACTIVE) { - for (llp = mip6_llq; llp; llp = llp->next) { - for (halp = llp->ha_list; halp; halp = halp->next) { - for (addrp = halp->addr_list; addrp; - addrp = addrp->next) { - if (in6_are_prefix_equal( - home_addr, - &addrp->ip6_addr, - addrp->prefix_len)) - break; - } - if (addrp != NULL) - break; - } - if (addrp != NULL) - break; - } - if (addrp == NULL) { - log(LOG_ERR, - "%s: No interface found for sending Neighbor " - "Advertisements at\n", __FUNCTION__); - return NULL; - } - nap->ifp = llp->ifp; - } - - if (MIP6_IS_MN_ACTIVE) { - for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { - if (!pr->ndpr_stateflags.onlink) - continue; - if (in6_are_prefix_equal(home_addr, - &pr->ndpr_prefix.sin6_addr, - pr->ndpr_plen)) - break; - } - if (pr == NULL) { - log(LOG_ERR, - "%s: No interface found for sending Neighbor " - "Advertisements at\n", __FUNCTION__); - return NULL; - } - nap->ifp = pr->ndpr_ifp; - } - - /* Add the new na entry first to the list. */ - s = splnet(); - nap->next = mip6_naq; - mip6_naq = nap; - splx(s); - -#if MIP6_DEBUG - mip6_debug("\nCreated Neighbor Advertisement List entry (0x%x)\n", - nap); - mip6_debug("Interface being used: %s\n", if_name(nap->ifp)); - mip6_debug("Home Addr/Prefix len: %s / %d\n", - ip6_sprintf(&nap->home_addr), nap->prefix_len); - mip6_debug("Destination Address: %s\n", ip6_sprintf(&nap->dst_addr)); - mip6_debug("Target Address: %s\n", - ip6_sprintf(&nap->target_addr)); - if (nap->use_link_opt) - mip6_debug("Incl Target ll_addr : TRUE\n"); - else - mip6_debug("Incl Target ll_addr : FALSE\n"); -#endif - - /* Send the Neighbor Advertisment entry to speed up cache changes. */ - mip6_send_na(nap); - - if (start_timer) { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - mip6_timer_na_handle = -#endif - timeout(mip6_timer_na, (void *)0, hz); - } - return nap; -} - - - -/* - ****************************************************************************** - * Function: mip6_na_delete - * Description: Delete an entry in the NA list. - * Ret value: Pointer to next entry in list or NULL if last entry removed. - ****************************************************************************** - */ -struct mip6_na * -mip6_na_delete(nap_del) -struct mip6_na *nap_del; /* Pointer to NA entry to delete */ -{ - struct mip6_na *nap; /* Current entry in the NA list */ - struct mip6_na *nap_prev; /* Previous entry in the NA list */ - struct mip6_na *nap_next; /* Next entry in the NA list */ - int s; - - s = splnet(); - nap_prev = NULL; - nap_next = NULL; - for (nap = mip6_naq; nap; nap = nap->next) { - nap_next = nap->next; - if (nap == nap_del) { - if (nap_prev == NULL) - mip6_naq = nap->next; - else - nap_prev->next = nap->next; - -#if MIP6_DEBUG - mip6_debug("\nNeighbor Advertisement Entry " - "deleted (0x%x)\n", nap); -#endif - _FREE(nap, M_TEMP); - - /* Remove the timer if the NA queue is empty */ - if (mip6_naq == NULL) { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - untimeout(mip6_timer_na, (void *)NULL, - mip6_timer_na_handle); - callout_handle_init(&mip6_timer_na_handle); -#else - untimeout(mip6_timer_na, (void *)NULL); -#endif - } - break; - } - nap_prev = nap; - } - splx(s); - return nap_next; -} - - - -/* - ****************************************************************************** - * Function: mip6_prefix_find - * Description: Try to find an existing prefix entry in the prefix list. - * Ret value: Pointer to found prefix list entry or NULL. - ****************************************************************************** - */ -struct mip6_prefix * -mip6_prefix_find(prefix, prefix_len) -struct in6_addr *prefix; /* Prefix to search for */ -u_int8_t prefix_len; /* Prefix length */ -{ - struct mip6_prefix *pq; - - for (pq = mip6_pq; pq; pq = pq->next) { - if (in6_are_prefix_equal(&pq->prefix, prefix, prefix_len)) - return pq; - } - return NULL; -} - - - -/* - ****************************************************************************** - * Function: mip6_prefix_create - * Description: Create a prefix and add it as the first entry in the list. - * Start the timer if not started already. - * Ret value: Pointer to created prefix list entry or NULL. - ****************************************************************************** - */ -struct mip6_prefix * -mip6_prefix_create(ifp, prefix, prefix_len, valid_time) -struct ifnet *ifp; /* Outgoing interface */ -struct in6_addr *prefix; /* Prefix to search for */ -u_int8_t prefix_len; /* Prefix length */ -u_int32_t valid_time; /* Time (s) that the prefix is valid */ -{ - struct mip6_prefix *pq; - int s, start_timer = 0; - - if (mip6_pq == NULL) - start_timer = 1; - - pq = (struct mip6_prefix *)MALLOC mip6_prefix), - M_TEMP, M_WAITOK); - if (pq == NULL) - return NULL; - bzero(pq, sizeof(struct mip6_prefix)); - - s = splnet(); - pq->next = mip6_pq; - pq->ifp = ifp; - pq->prefix = *prefix; - pq->prefix_len = prefix_len; - pq->valid_time = valid_time; - mip6_pq = pq; - splx(s); - -#if MIP6_DEBUG - mip6_debug("\nInternal Prefix list entry created (0x%x)\n", pq); - mip6_debug("Interface: %s\n", if_name(ifp)); - mip6_debug("Prefix: %s\n", ip6_sprintf(&pq->prefix)); - mip6_debug("Prefix len: %d\n", pq->prefix_len); - mip6_debug("Life time: %d\n", htonl(pq->valid_time)); -#endif - - if (start_timer) { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - mip6_timer_prefix_handle = -#endif - timeout(mip6_timer_prefix, (void *)0, hz); - } - return pq; -} - - - -/* - ****************************************************************************** - * Function: mip6_prefix_delete - * Description: Delete the requested prefix list entry. - * Ret value: Ptr to next entry in list or NULL if last entry removed. - ****************************************************************************** - */ -struct mip6_prefix * -mip6_prefix_delete(pre_del) -struct mip6_prefix *pre_del; /* Prefix list entry to be deleted */ -{ - struct mip6_prefix *pre; /* Current entry in the list */ - struct mip6_prefix *pre_prev; /* Previous entry in the list */ - struct mip6_prefix *pre_next; /* Next entry in the list */ - int s; - - /* Find the requested entry in the link list. */ - s = splnet(); - pre_next = NULL; - pre_prev = NULL; - for (pre = mip6_pq; pre; pre = pre->next) { - pre_next = pre->next; - if (pre == pre_del) { - if (pre_prev == NULL) - mip6_pq = pre->next; - else - pre_prev->next = pre->next; - -#if MIP6_DEBUG - mip6_debug("\nMIPv6 prefix entry deleted (0x%x)\n", pre); -#endif - _FREE(pre, M_TEMP); - - /* Remove the timer if the prefix queue is empty */ - if (mip6_pq == NULL) { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - untimeout(mip6_timer_prefix, (void *)NULL, - mip6_timer_prefix_handle); - callout_handle_init(&mip6_timer_prefix_handle); -#else - untimeout(mip6_timer_prefix, (void *)NULL); -#endif - } - break; - } - pre_prev = pre; - } - splx(s); - return pre_next; -} - - - -/* - ############################################################################## - # - # TIMER FUNCTIONS - # These functions are called at regular basis. They operate on the lists, e.g. - # reducing timer counters and removing entries from the list if needed. - # - ############################################################################## - */ - -/* - ****************************************************************************** - * Function: mip6_timer_na - * Description: Called once every second. For each entry in the list a Neighbor - * Advertisement is sent until the counter value reaches 0. Then - * the entry is removed. - * Ret value: - - ****************************************************************************** - */ -void -mip6_timer_na(arg) -void *arg; /* Not used */ -{ - struct mip6_na *nap; /* Neighbor Advertisement entry */ - int s; -#ifdef __APPLE__ - boolean_t funnel_state; - funnel_state = thread_funnel_set(network_flock, TRUE); -#endif - - /* Go through the entire list of Neighbor Advertisement entries. */ - s = splnet(); - for (nap = mip6_naq; nap;) { - mip6_send_na(nap); - if (nap->no <= 0) - nap = mip6_na_delete(nap); - else - nap = nap->next; - } - splx(s); - - if (mip6_naq != NULL) { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - mip6_timer_na_handle = -#endif - timeout(mip6_timer_na, (void *)0, hz); - } -#ifdef __APPLE__ - (void) thread_funnel_set(network_flock, FALSE); -#endif -} - - - -/* - ****************************************************************************** - * Function: mip6_timer_bc - * Description: Called once every second. For each entry in the BC list, a - * counter is reduced by 1 until it reaches the value of zero, - * then the entry is removed. - * Ret value: - - ****************************************************************************** - */ -void -mip6_timer_bc(arg) -void *arg; /* Not used */ -{ - struct mip6_bc *bcp; /* Current entry in the BC list */ - struct mip6_bc *bcp_nxt; /* Next BC list entry */ - int s; -#ifdef __APPLE__ - boolean_t funnel_state; - funnel_state = thread_funnel_set(network_flock, TRUE); -#endif - - /* Go through the entire list of Binding Cache entries. */ - s = splnet(); - for (bcp = mip6_bcq; bcp;) { - bcp->lifetime -= 1; - if (bcp->lifetime == 0) { - mip6_bc_delete(bcp, &bcp_nxt); - bcp = bcp_nxt; - } else - bcp = bcp->next; - } - splx(s); - - /* XXX */ - /* Code have to be added to take care of bc_info.br_interval - variable. */ - /* We have to send a BR when the mip6_bc.lifetime == - mip6_bc.bc_info.br_interval. */ - if (mip6_bcq != NULL) { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - mip6_timer_bc_handle = -#endif - timeout(mip6_timer_bc, (void *)0, hz); - } -#ifdef __APPLE__ - (void) thread_funnel_set(network_flock, FALSE); -#endif - return; -} - - - -/* - ****************************************************************************** - * Function: mip6_timer_prefix - * Description: Called once every second. Search the list of prefixes and if - * a prefix has timed out it is removed from the list. - * Ret value: - - ****************************************************************************** - */ - -void -mip6_timer_prefix_funneled(arg) -void *arg; /* Not used */ -{ -#ifdef __APPLE__ - boolean_t funnel_state; - funnel_state = thread_funnel_set(network_flock, TRUE); -#endif - mip6_timer_prefix(arg); -#ifdef __APPLE__ - (void) thread_funnel_set(network_flock, FALSE); -#endif -} - -void -mip6_timer_prefix(arg) -void *arg; /* Not used */ -{ - struct mip6_prefix *pq_entry; /* Current entry in the prefix list */ - int s; - - /* Go through the entire list of prefix entries. */ - s = splnet(); - for (pq_entry = mip6_pq; pq_entry;) { - pq_entry->valid_time -= 1; - if (pq_entry->valid_time == 0) - pq_entry = mip6_prefix_delete(pq_entry); - else - pq_entry = pq_entry->next; - } - splx(s); - - if (mip6_pq != NULL) { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - mip6_timer_prefix_handle = -#endif - timeout(mip6_timer_prefix, (void *)0, hz); - } - return; -} - - - -/* - ############################################################################## - # - # IOCTL AND DEBUG FUNCTIONS - # - ############################################################################## - */ - -/* - ****************************************************************************** - * Function: mip6_ioctl - * Description: The ioctl handler for MIPv6. These are used by the - * configuration program to set and get various parameters. - * Ret value: 0 or error code - ****************************************************************************** - */ -int -#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) -mip6_ioctl(so, cmd, data, ifp, p) -struct socket *so; -u_long cmd; -caddr_t data; -struct ifnet *ifp; -struct proc *p; -#else -mip6_ioctl(so, cmd, data, ifp) -struct socket *so; -u_long cmd; -caddr_t data; -struct ifnet *ifp; -#endif -{ - int res; - - /* Note: privileges already checked in in6_control(). */ - - res = 0; - switch (cmd) { - case SIOCSBCFLUSH_MIP6: - case SIOCSDEFCONFIG_MIP6: - res = mip6_clear_config_data(cmd, data); - return res; - - case SIOCSBRUPDATE_MIP6: - res = mip6_write_config_data(cmd, data); - return res; - - case SIOCSHAPREF_MIP6: - /* Note: this one can be run before attach. */ - if (mip6_write_config_data_ha_hook) - res = (*mip6_write_config_data_ha_hook) - (cmd, data); - break; - - case SIOCACOADDR_MIP6: - case SIOCAHOMEADDR_MIP6: - case SIOCSBULIFETIME_MIP6: - case SIOCSHRLIFETIME_MIP6: - case SIOCDCOADDR_MIP6: - /* Note: these can be run before attach. */ - if (mip6_write_config_data_mn_hook) - res = (*mip6_write_config_data_mn_hook) - (cmd, data); - break; - - case SIOCSDEBUG_MIP6: - case SIOCSENABLEBR_MIP6: - case SIOCSATTACH_MIP6: - res = mip6_enable_func(cmd, data); - return res; - - case SIOCSFWDSLUNICAST_MIP6: - case SIOCSFWDSLMULTICAST_MIP6: - /* Note: these can be run before attach. */ - if (mip6_enable_func_ha_hook) - res = (*mip6_enable_func_ha_hook)(cmd, data); - break; - - case SIOCSPROMMODE_MIP6: - case SIOCSBU2CN_MIP6: - case SIOCSREVTUNNEL_MIP6: - case SIOCSAUTOCONFIG_MIP6: - case SIOCSEAGERMD_MIP6: - /* Note: these can be run before attach. */ - if (mip6_enable_func_mn_hook) - res = (*mip6_enable_func_mn_hook)(cmd, data); - break; - - case SIOCSRELEASE_MIP6: - mip6_release(); - return res; - - default: - res = EOPNOTSUPP; - break; - } - - if (MIP6_IS_HA_ACTIVE) { - res = 0; - switch (cmd) { - case SIOCSHALISTFLUSH_MIP6: - if (mip6_clear_config_data_ha_hook) - res = (*mip6_clear_config_data_ha_hook) - (cmd, data); - break; - - default: - res = EOPNOTSUPP; - break; - } - } - - if (MIP6_IS_MN_ACTIVE) { - res = 0; - switch (cmd) { - case SIOCSFORADDRFLUSH_MIP6: - case SIOCSHADDRFLUSH_MIP6: - case SIOCSBULISTFLUSH_MIP6: - if (mip6_clear_config_data_mn_hook) - res = (*mip6_clear_config_data_mn_hook) - (cmd, data); - break; - - default: - res = EOPNOTSUPP; - break; - } - } - if (res) { -#if MIP6_DEBUG - printf("%s: unknown command: %lu\n", __FUNCTION__, (u_long)cmd); -#endif - } - return res; -} - - - -/* - ****************************************************************************** - * Function: mip6_debug - * Description: This function displays MIPv6 debug messages to the console - * if activated with the configuration program. Note that this - * is included only when "options MIP6_DEBUG" is defined. - * Ret value: - - ****************************************************************************** - */ -#if MIP6_DEBUG -void mip6_debug(char *fmt, ...) -{ -#ifndef __bsdi__ - va_list ap; - - if (!mip6_debug_is_enabled) - return; - - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); -#endif -} - - - -void -mip6_enable_debug(int status) -{ - mip6_debug_is_enabled = status; -} -#endif /* MIP6_DEBUG */ - - - -/* - ****************************************************************************** - * Function: mip6_write_config_data - * Description: This function is called to write certain config values for - * MIPv6. The data is written into the global config structure. - * Ret value: - - ****************************************************************************** - */ -int mip6_write_config_data(u_long cmd, caddr_t data) -{ - int retval = 0; - - switch (cmd) { - case SIOCSBRUPDATE_MIP6: - mip6_config.br_update = *(u_int8_t *)data; - break; - } - return retval; -} - - - -/* - ****************************************************************************** - * Function: mip6_clear_config_data - * Description: This function is called to clear internal lists handled by - * MIPv6. - * Ret value: - - ****************************************************************************** - */ -int mip6_clear_config_data(u_long cmd, caddr_t data) -{ - int s, retval = 0; - struct mip6_bc *bcp, *bcp_nxt; - - s = splnet(); - switch (cmd) { - case SIOCSBCFLUSH_MIP6: - for (bcp = mip6_bcq; bcp;) { - if(!bcp->hr_flag) { - mip6_bc_delete(bcp, &bcp_nxt); - bcp = bcp_nxt; - } else - bcp = bcp->next; - } - break; - - case SIOCSDEFCONFIG_MIP6: - mip6_config.bu_lifetime = 600; - mip6_config.br_update = 60; - mip6_config.hr_lifetime = 3600; - mip6_config.enable_outq = 1; - break; - } - splx(s); - return retval; -} - - - -/* - ****************************************************************************** - * Function: mip6_enable_func - * Description: This function is called to enable or disable certain functions - * in mip6. The data is written into the global config struct. - * Ret value: - - ****************************************************************************** - */ -int mip6_enable_func(u_long cmd, caddr_t data) -{ - int enable; - int retval = 0; - - enable = ((struct mip6_input_data *)data)->value; - - switch (cmd) { - case SIOCSDEBUG_MIP6: -#if MIP6_DEBUG - mip6_enable_debug(enable); -#else - printf("No Mobile IPv6 debug information available!\n"); -#endif - break; - - case SIOCSENABLEBR_MIP6: - mip6_config.enable_br = enable; - break; - - case SIOCSATTACH_MIP6: - printf("%s: attach %d\n", __FUNCTION__, enable); /* RM */ - retval = mip6_attach(enable); - break; - } - return retval; -} diff --git a/bsd/netinet6/mip6.h b/bsd/netinet6/mip6.h deleted file mode 100644 index 328968380..000000000 --- a/bsd/netinet6/mip6.h +++ /dev/null @@ -1,861 +0,0 @@ -/* $KAME: mip6.h,v 1.8 2000/03/18 03:05:39 itojun Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _NETINET6_MIP6_H_ -#define _NETINET6_MIP6_H_ - -#include -#include - -struct ifnet; - -/* - * Definition For Mobile Internet Protocol Version 6. - * Draft draft-ietf-mobileip-ipv6-09.txt - */ - -/* Definition of MIPv6 states for the Event-State machine */ -#define MIP6_STATE_UNDEF 0x01 -#define MIP6_STATE_HOME 0x02 -#define MIP6_STATE_DEREG 0x03 -#define MIP6_STATE_NOTREG 0x04 -#define MIP6_STATE_REG 0x05 -#define MIP6_STATE_REREG 0x06 -#define MIP6_STATE_REGNEWCOA 0x07 - - -/* Definition of states used by the move detection algorithm used by MIPv6. */ -#define MIP6_MD_BOOT 0x01 -#define MIP6_MD_UNDEFINED 0x02 -#define MIP6_MD_HOME 0x03 -#define MIP6_MD_FOREIGN 0x04 - - -/* Definition of Home Address route states used by the move detection - algorithm used by MIPv6. */ -#define MIP6_ROUTE_NET 0x01 -#define MIP6_ROUTE_HOST 0x02 - - -/* Type of node calling mip6_tunnel */ -#define MIP6_NODE_MN 0x01 -#define MIP6_NODE_HA 0x02 - - -/* Movement Detection default values */ -#define MIP6_MAX_LOST_ADVINTS 3 - - -/* Scope for hook activation */ -#define MIP6_GENERIC_HOOKS 0x01 -#define MIP6_SPECIFIC_HOOKS 0x02 -#define MIP6_CONFIG_HOOKS 0x03 - - -/* Definition of states for tunnels set up by the Home Agent and the MN. */ -#define MIP6_TUNNEL_ADD 0 -#define MIP6_TUNNEL_MOVE 1 -#define MIP6_TUNNEL_DEL 2 - - -/* Definition of length for different destination options */ -#define IP6OPT_BULEN 8 /* Length of BU option */ -#define IP6OPT_BALEN 11 /* Length of BA option */ -#define IP6OPT_BRLEN 0 /* Length of BR option */ -#define IP6OPT_HALEN 16 /* Length of HA option */ -#define IP6OPT_UIDLEN 2 /* Length of Unique Identifier sub-option */ -#define IP6OPT_HALISTLEN 16 /* Length of HA List sub-ption */ -#define IP6OPT_COALEN 16 /* Length of Alternate COA sub-option */ - - -/* Definition of minimum length of MIPv6 destination options. - Length includes option Type and Length. */ -#define IP6OPT_BAMINLEN (IP6OPT_MINLEN + IP6OPT_BALEN) -#define IP6OPT_BRMINLEN (IP6OPT_MINLEN + IP6OPT_BRLEN) -#define IP6OPT_BUMINLEN (IP6OPT_MINLEN + IP6OPT_BULEN) -#define IP6OPT_HAMINLEN (IP6OPT_MINLEN + IP6OPT_HALEN) - - -/* Definition of sub-options used by the Destination Options */ -#define IP6SUBOPT_UNIQUEID 0x02 /* Unique Identifier (BU, BR) */ -#define IP6SUBOPT_HALIST 0x03 /* Home Agents List (BA) */ -#define IP6SUBOPT_ALTCOA 0x04 /* Alternate COA (BU) */ - - -/* Definition of MIPv6 Binding Update option flags */ -#define MIP6_BU_AFLAG 0x80 /* BU Acknowledgement flag present */ -#define MIP6_BU_HFLAG 0x40 /* BU Home Registration flag present */ -#define MIP6_BU_RFLAG 0x20 /* BU MN is Router flag present */ - - -/* Definition of flags used for indication of options present in a - destination header (mip6_indata->optflag) */ -#define MIP6_DSTOPT_BU 0x80 /* BU Option present */ -#define MIP6_DSTOPT_BA 0x40 /* BA Option present */ -#define MIP6_DSTOPT_BR 0x20 /* BR Option present */ -#define MIP6_DSTOPT_HA 0x10 /* HA Option present */ -#define MIP6_DSTOPT_UID 0x08 /* Sub-option Unique Id present */ -#define MIP6_DSTOPT_COA 0x04 /* Sub-option Alternate COA present */ -#define MIP6_DSTOPT_HAL 0x02 /* Sub-option HAs List present */ - - -#if 0 -/* Definition of flags for Home Agent */ -#define ND_RA_FLAG_HA 0x20 /* RA indicates that router works as HA */ -#define ND_OPT_PI_FLAG_RADDR 0x20 /* Prefix Information option incl. global - IP address */ -#endif - - -/* Definition of timers for signals */ -#define MIP6_BU_LIFETIME 600 /* Lifetime for BU (s) */ -#define MIP6_BU_LIFETIME_DEFRTR 60 /* Lifetime for BU sent to previous def - router (s) */ -#define MIP6_BU_LIFETIME_DHAAD 16 /* Lifetime for BU when Dynamic Home - Agent Address Discovery (s) */ -#define MIP6_MAX_FAST_UPDATES 5 /* Max number of fast updates (BUs) - being sent */ -#define MIP6_MAX_UPDATE_RATE 1 /* Rate limiting for sending successive - fast BUs (sec) */ -#define MIP6_SLOW_UPDATE_RATE 10 /* Rate limiting for sending successive - slow BUs (sec) */ -#define MIP6_MAX_BINDACK_TIMEOUT 256 /* Max time to wait for a BA */ -#define MIP6_MAX_ADVERT_REXMIT 3 /* Max retransmission of NA when retur- - ning to home link */ -#define MIP6_OUTQ_LIFETIME 20 /* Max number of 0.1s units that an entry - is stored in the output queue */ -#define MIP6_OUTQ_INTERVAL 5 /* Interval in units of 0.1s that the out - queue is searched */ - - -/* Definition of Binding Acknowledgement status field */ -#define MIP6_BA_STATUS_ACCEPT 0 /* Binding Update accepted */ -#define MIP6_BA_STATUS_UNSPEC 128 /* Reason unspecified */ -#define MIP6_BA_STATUS_PROHIBIT 130 /* Administratively prohibited */ -#define MIP6_BA_STATUS_RESOURCE 131 /* Insufficient resources */ -#define MIP6_BA_STATUS_HOMEREGNOSUP 132 /* Home registration not supported */ -#define MIP6_BA_STATUS_SUBNET 133 /* Not home subnet */ -#define MIP6_BA_STATUS_DHAAD 135 /* Dynamic home agent address - discovery response */ -#define MIP6_BA_STATUS_IFLEN 136 /* Incorrect interface id length */ -#define MIP6_BA_STATUS_NOTHA 137 /* Not home agent for this MN */ - - -/* Macro for modulo 2^^16 comparison */ -#define MIP6_LEQ(a,b) ((int16_t)((a)-(b)) <= 0) - - -/* Macros started with MIP6_ADDR is Mobile IPv6 local */ -#define MIP6_ADDR_ANYCAST_HA 0x7e - -#if BYTE_ORDER == BIG_ENDIAN -#define MIP6_ADDR_INT32_ULL 0xfe800000 /* Unicast Link Local */ -#define MIP6_ADDR_INT32_USL 0xfec00000 /* Unicast Site Local */ -#define MIP6_ADDR_INT32_AHA1 0xfffffffe /* Anycast Home Agent bit 97-128 */ -#define MIP6_ADDR_INT32_AHA2 0xfdffffff /* Anycast Home Agent bit 65-96 */ -#elif BYTE_ORDER == LITTLE_ENDIAN -#define MIP6_ADDR_INT32_ULL 0x000080fe -#define MIP6_ADDR_INT32_USL 0x0000c0fe -#define MIP6_ADDR_INT32_AHA1 0xfeffffff -#define MIP6_ADDR_INT32_AHA2 0xfffffffd -#endif - - -/* Definition of some useful macros to handle IP6 addresses */ -extern struct in6_addr in6addr_linklocal; -extern struct in6_addr in6addr_sitelocal; -extern struct in6_addr in6addr_aha_64; /* 64 bits identifier */ -extern struct in6_addr in6addr_aha_nn; /* 121-nn bits identifier */ - - -/* Definition of states for flag in queue for outgoing packets. */ -enum send_state {NOT_SENT, SENT}; - - -/* Definition of event-state machine type. */ -enum esm_type {PERMANENT, TEMPORARY}; - - -/* Configuration parameters needed for MIPv6. Controlled by the user */ -struct mip6_static_addr { - LIST_ENTRY(mip6_static_addr) addr_entry; /* Next IPv6 address list */ - struct ifnet *ifp; /* Interface */ - u_int8_t prefix_len; /* Prefix length for address */ - struct in6_addr ip6_addr; /* Address to be used at foreign network */ -}; - - -/* - * fna_list List of pre-assigned care-of addresses to be used at - * foreign networks that the MN might visit - * bu_lifetime Used by the MN when sending a BU to the CN if it wants - * to use a smaller value than received in the home - * registration acknowledgement - * br_update Indicates when the CN sends a BR to the MN. The value - * should be given as percentage of the bu_lifetime - * ha_pref Preference for the Home Agent - * hr_lifetime Default life time for home registration (only sent to the - * Home Agent) - * fwd_sl_unicast Enable forwarding of site local unicast dest addresses - * fwd_sl_multicast Enable forwarding of site local multicast dest addresses - * enable_prom_mode Enable link layer promiscus mode (used by move detection) - * enable_bu_to_cn Enable BU being sent to the CN (Route optimization on/off) - * enable_rev_tunnel Enable tunneling of packets from MN to CN via Home Agent - * enable_br Enable sending BR to the MN - * autoconfig Only enable MIP6 if the mip6 deamon is running - * eager_md Enable eager Movement Detection - * enable_outq Enable reading from the MIP6 output queue for piggy - * backing (Not configurable, handled internally) - */ -struct mip6_config { - LIST_HEAD(fna_list, mip6_static_addr) fna_list; - u_int32_t bu_lifetime; - u_int8_t br_update; - int16_t ha_pref; - u_int32_t hr_lifetime; - u_int8_t fwd_sl_unicast; - u_int8_t fwd_sl_multicast; - u_int8_t enable_prom_mode; - u_int8_t enable_bu_to_cn; - u_int8_t enable_rev_tunnel; - u_int8_t enable_br; - u_int8_t autoconfig; - u_int8_t eager_md; - u_int8_t enable_outq; -}; - - -/* Generic option format */ -struct mip6_bu_data { - u_int8_t prefix_len; /* Prefix length for a Home Address */ - u_int8_t ack; /* Acknowledgement flag */ -}; - - -/* Generic option format */ -struct mip6_opt { - u_int8_t type; /* Option type */ - u_int8_t len; /* Option length (octets) excl. type and length */ -} __attribute__ ((packed)); - - -/* List of prefixes extracted from Router Advertisments being sent by - the Home Agent. */ -struct mip6_prefix { - struct mip6_prefix *next; /* Ptr to next entry in the list */ - struct ifnet *ifp; /* Outgoing interface */ - struct in6_addr prefix; /* Announced prefix (on-link) */ - u_int8_t prefix_len; /* Prefix length for IP address */ - u_int32_t valid_time; /* Remaining (s) until prefix expires */ -} __attribute__ ((packed)); - - -/* Binding Update destination option format */ -struct mip6_opt_bu { - u_int8_t type; /* Option type */ - u_int8_t len; /* Option length excluding Type and length */ - u_int8_t flags; /* Flags (A, H and R) */ - u_int8_t prefix_len; /* Prefix length for IP address */ - u_int16_t seqno; /* Sequence number */ - u_int32_t lifetime; /* Seconds remaining until the binding expires */ -} __attribute__ ((packed)); - - -/* Binding Acknowledgement destination option format */ -struct mip6_opt_ba { - u_int8_t type; /* Option type */ - u_int8_t len; /* Option length (octets) excl. type and length */ - u_int8_t status; /* Result of the BU */ - u_int16_t seqno; /* Sequence number */ - u_int32_t lifetime; /* Granted lifetime (s) for the BU in the BC */ - u_int32_t refresh; /* Interval for MN to send BU to refresh BC */ -} __attribute__ ((packed)); - - -/* Binding Request destination option format */ -struct mip6_opt_br { - u_int8_t type; /* Option type */ - u_int8_t len; /* Option length (octets) excl. type and length */ -} __attribute__ ((packed)); - - -/* Home Address option format */ -struct mip6_opt_ha { - u_int8_t type; /* Option type */ - u_int8_t len; /* Option length excl. type and length */ - struct in6_addr home_addr; /* Home Addr of the MN sending the packet */ -} __attribute__ ((packed)); - - -/* Unique Identifier sub-option format */ -struct mip6_subopt_id { - u_int8_t type; /* Sub-option type */ - u_int8_t len; /* Sub-option length (octets) excl. type and length */ - u_int16_t id; /* Unique identifier */ -} __attribute__ ((packed)); - - -/* Home Agents list sub-option format */ -struct mip6_subopt_hal { - u_int8_t type; /* Sub-option type */ - u_int8_t len; /* Sub-option length excl. type and length */ - struct in6_addr halist[1]; /* List of HA's on the home link */ -} __attribute__ ((packed)); - - -/* Alternate Care-of Address sub-option format */ -struct mip6_subopt_coa { - u_int8_t type; /* Sub-option type */ - u_int8_t len; /* Length (octets) excl. type and len fields */ - struct in6_addr coa; /* Alternate COA */ -} __attribute__ ((packed)); - - -/* Buffer for storing a consequtive sequence of sub-options */ -struct mip6_subbuf { - u_int16_t len; /* # of used bytes in buffer */ - char buffer[512]; -}; - - -/* The event-state machine must be maintained for each Home Address. */ -struct mip6_dad { - struct mip6_subopt_hal *hal; /* Home Agents list */ - int index; /* Next entry in list to try */ -}; - -struct mip6_hafn { - time_t time; /* Absolute expire time */ - int16_t pref; /* Preference for this HA */ - u_int8_t prefix_len; /* Prefix_len for HA Address */ - struct in6_addr addr; /* FN Home Agent global unicast address */ -}; - -struct mip6_esm { - struct mip6_esm *next; /* Ptr to next entry in the list */ - struct ifnet *ifp; /* I/f where home address is applied */ - const struct encaptab *ep; /* Encapsulation attach (MN -> HA) */ - int state; /* State for the home address */ - enum esm_type type; /* Type of event-state machine */ - struct in6_addr home_addr; /* Home address */ - u_int8_t prefix_len; /* Prefix_len for Home Address */ - u_int16_t lifetime; /* if type=PERMANENT 0xFFFF, else x */ - struct in6_addr ha_hn; /* Home agent address (home network) */ - struct in6_addr coa; /* Current primary care-of address */ - struct mip6_hafn *ha_fn; /* Home agent address (foreign network) */ - struct mip6_dad *dad; /* For Dynamic HA Address Discovery */ -}; - - -/* Binding Cache parameters. Bindings for other IPv6 nodes. */ -/* Maintained by each node. */ -struct bc_info { - u_int32_t br_interval; /* % of mip6_lifetime, max 60s, min 2s */ - u_int8_t no_of_sent_br; /* Number of sent BR to a Mobile Node */ - u_int8_t max_advert; /* ? */ - u_int8_t ra_tunneled; /* RA being tunneled to MN */ - u_int8_t ra_interval; /* Interval for sending RA */ -}; - -struct mip6_bc { - struct mip6_bc *next; /* Ptr to next entry in the list */ - struct in6_addr home_addr; /* Home Address of the MN for which this is - the BC entry */ - struct in6_addr coa; /* COA for MN indicated by the HA field */ - u_int32_t lifetime; /* Remaining lifetime for this BC entry */ - u_int8_t hr_flag; /* Flag for home registration entry (T/F) */ - u_int8_t rtr_flag; /* MN is a router (T/F) */ - u_int8_t prefix_len; /* Prefix length in last received BU */ - u_int16_t seqno; /* Maximum value of the sequence number */ - struct bc_info info; /* Usage info for cache replacement policy */ - time_t lasttime; /* The time at which a BR was last sent */ - const struct encaptab *ep; /* Encapsulation attach (HA -> MN) */ -}; - - - -/* Binding Update List parameters. Information for each BU sent by this MN */ -/* Each MN maintains this list. */ -struct mip6_retrans { - struct mip6_opt_bu *bu_opt; /* BU option in case of retransmission */ - struct mip6_subbuf *bu_subopt; /* BU sub-option in case of retrans. */ - u_int8_t ba_timeout; /* Exponential back-off starting at 1 */ - u_int8_t time_left; /* Time left until next retransmission */ -}; - -struct mip6_bul { - struct mip6_bul *next; /* Ptr to next entry in the list */ - struct in6_addr dst_addr; /* Destination address for sent BU */ - struct in6_addr bind_addr; /* Home Address or previous COA */ - struct in6_addr coa; /* Care-of address sent in the BU */ - u_int32_t lifetime; /* Remaining binding lifetime */ - u_int32_t refreshtime; /* Refresh time for the BU */ - u_int16_t seqno; /* Last value for sent seq number */ - time_t lasttime; /* Time at which a BU was last sent */ - u_int32_t no_of_sent_bu; /* Number of sent BU to a MN */ - struct mip6_retrans *state; /* Status for BU being acknowledged */ - u_int8_t bu_flag; /* Flag for sending future BU (T/F) */ - u_int8_t hr_flag; /* Flag for home reg (True / False) */ - u_int8_t update_rate; /* Seconds between consequtive BUs */ -}; - - -/* Home Agent List parameters. Information about each other HA on the link - that this node is serving as a HA. One HA list for each link it is - serving. */ -/* Each HA maintains this list. */ -struct mip6_addr_list { - struct mip6_addr_list *next; /* Ptr to next entry in the list */ - struct in6_addr ip6_addr; /* IPv6 address */ - u_int8_t prefix_len; -}; - -struct mip6_ha_list { - struct mip6_ha_list *next; /* Ptr to next entry in the list */ - struct in6_addr ll_addr; /* Link-local IP-addr of a node on - the home link */ - u_int16_t lifetime; /* Remaining lifetime of this HA - list entry */ - int16_t pref; /* Preference for this HA */ - struct mip6_addr_list *addr_list; /* List of global IP addresses for - this HA */ -}; - -struct mip6_link_list { - struct mip6_link_list *next; /* Ptr to next entry in the list */ - struct mip6_ha_list *ha_list; /* List of Home Agents for the link */ - struct ifnet *ifp; /* Interface */ - char ifname[IFNAMSIZ+1]; /* Link identifier */ -}; - - -/* Neighbor Advertisement information stored for retransmission when the - Mobile Node is returning to its Home Network or the Home Agent is - requested to act as a proxy for the Mobile Node when it is moving to a - Foreign Network. */ -struct mip6_na -{ - struct mip6_na *next; /* Ptr to next entry in the list */ - struct ifnet *ifp; /* Interface for sending the NA */ - struct in6_addr home_addr; /* Home address of the mobile node */ - struct in6_addr dst_addr; /* Destination address */ - struct in6_addr target_addr; /* Target address */ - u_int8_t prefix_len; /* Prefix length for home address */ - u_long flags; /* Flags for the NA message */ - int use_link_opt; /* Include Target link layer address - option or not - (0 = Do not include, 1 = Include) */ - int no; /* Remaining no of times to send the NA */ -}; - - -/* Definition of global variable used by Mobile IPv6. All variables are - stored in node byte order. */ -struct mip6_indata { - u_int8_t flag; /* How to handle tunneled packets */ - u_int8_t optflag; /* Dest options and sub-options flag */ - struct in6_addr ip6_src; /* Orig src addr from IPv6 header */ - struct in6_addr ip6_dst; /* Orig dst addr from IPv6 header */ - struct mip6_opt_bu *bu_opt; /* BU option present */ - struct mip6_opt_ba *ba_opt; /* BA option present */ - struct mip6_opt_br *br_opt; /* BR option present */ - struct mip6_opt_ha *ha_opt; /* HA option present */ - struct mip6_subopt_id *uid; /* Sub-option Unique ID present */ - struct mip6_subopt_coa *coa; /* Sub-option alt coa present */ - struct mip6_subopt_hal *hal; /* Sub-option HAs List present */ -}; - - -/* Queue of outgoing packets that are waiting to be sent. */ -struct mip6_output { - struct mip6_output *next; /* Ptr to next option in chain */ - void *opt; /* BU, BA or BR dest option to be sent */ - struct mip6_subbuf *subopt; /* Sub-option to be sent (if present) */ - struct in6_addr ip6_dst; /* Destination address for IPv6 packet */ - struct in6_addr ip6_src; /* Source address for IPv6 packet */ - enum send_state flag; /* Has packet been sent or not? */ - u_int32_t lifetime; /* Time remaining for entry in output queue - (units of 0.1s) */ -}; - -#ifdef KERNEL - -/* - * Macro MIP6_FREEINDATA free memory allocated for the global variable - * mip6_inp and its members. Set the variable to point at NULL when - * the memory has been freed. - */ -#define MIP6_FREEINDATA \ -do { \ - if (mip6_inp != NULL) { \ - if (mip6_inp->bu_opt != NULL) \ - _FREE(mip6_inp->bu_opt, M_TEMP); \ - if (mip6_inp->ba_opt != NULL) \ - _FREE(mip6_inp->ba_opt, M_TEMP); \ - if (mip6_inp->br_opt != NULL) \ - _FREE(mip6_inp->br_opt, M_TEMP); \ - if (mip6_inp->ha_opt != NULL) \ - _FREE(mip6_inp->ha_opt, M_TEMP); \ - if (mip6_inp->uid != NULL) \ - _FREE(mip6_inp->uid, M_TEMP); \ - if (mip6_inp->coa != NULL) \ - _FREE(mip6_inp->coa, M_TEMP); \ - if (mip6_inp->hal != NULL) \ - _FREE(mip6_inp->hal, M_TEMP); \ - _FREE(mip6_inp, M_TEMP); \ - mip6_inp = NULL; \ - } \ -} while (0) - -#define MIP6_IS_MN_ACTIVE ((mip6_module & MIP6_MN_MODULE) == MIP6_MN_MODULE) -#define MIP6_IS_HA_ACTIVE ((mip6_module & MIP6_HA_MODULE) == MIP6_HA_MODULE) - - -/* External Declaration of Global variables. */ -extern struct mip6_indata *mip6_inp; /* Input data rec in one packet */ -extern struct mip6_output *mip6_outq; /* Ptr to output queue */ -extern struct mip6_esm *mip6_esmq; /* Ptr to list of Home Addresses */ -extern struct mip6_bc *mip6_bcq; /* First entry in the BC list */ -extern struct mip6_prefix *mip6_pq; /* First entry in prefix list */ -extern struct mip6_config mip6_config; /* Config parameters for MIP6 */ -extern struct mip6_bul *mip6_bulq; -extern struct mip6_link_list *mip6_llq; -extern struct nd_prefix *mip6_home_prefix; -extern struct nd_prefix *mip6_primary_prefix; - -extern u_int8_t mip6_module; /* Info about loaded modules (MN/HA) */ -extern int mip6_md_state; /* Movement Detection state */ -extern int mip6_route_state; /* Home Address route state */ -extern int mip6_max_lost_advints; /* No. lost Adv before start of NUD */ -extern int mip6_nd6_delay; -extern int mip6_nd6_umaxtries; - - -/* External declaration of function prototypes (mip6_io.c) */ -extern int mip6_new_packet - __P((struct mbuf *)); -extern int mip6_store_dstopt_pre - __P((struct mbuf *, u_int8_t *, u_int8_t, u_int8_t)); -extern int mip6_store_dstopt - __P((struct mbuf *, u_int8_t *, u_int8_t)); -extern int mip6_store_dstsubopt - __P((struct mbuf *, u_int8_t *, u_int8_t, int, int)); -extern int mip6_output - __P((struct mbuf *, struct ip6_pktopts **)); -extern int mip6_add_rh - __P((struct ip6_pktopts **, struct mip6_bc *)); -extern void mip6_align - __P((struct ip6_dest *, int *)); -extern void mip6_dest_offset - __P((struct ip6_dest *, int *)); -extern int mip6_add_ha - __P((struct ip6_dest **, int *, struct in6_addr *, struct in6_addr *)); -extern int mip6_add_bu - __P((struct ip6_dest **, int *, struct mip6_opt_bu *, - struct mip6_subbuf *)); -extern int mip6_add_ba - __P((struct ip6_dest **, int *, struct mip6_opt_ba *, - struct mip6_subbuf *)); -extern int mip6_add_br - __P((struct ip6_dest **, int *, struct mip6_opt_br *, - struct mip6_subbuf *)); -extern int mip6_store_subopt - __P((struct mip6_subbuf **, caddr_t)); - - -/* External declaration of function prototypes (mip6.c) */ -extern void mip6_init - __P((void)); -extern void mip6_exit - __P((void)); -extern int mip6_rec_ctrl_sig - __P((struct mbuf *, int)); -extern int mip6_icmp6_input - __P((struct mbuf *, int)); -extern int mip6_rec_bu - __P((struct mbuf *, int)); -extern void mip6_ha2srcaddr - __P((struct mbuf *)); -extern int mip6_send_ba - __P((struct in6_addr *, struct in6_addr *, struct in6_addr *, - struct mip6_subbuf *, u_int8_t, u_int16_t, u_int32_t)); -extern void mip6_send_na - __P((struct mip6_na *)); -extern struct mbuf *mip6_create_ip6hdr - __P((struct in6_addr *, struct in6_addr *, u_int8_t)); -extern struct ip6_rthdr *mip6_create_rh - __P((struct in6_addr *, u_int8_t)); -extern struct mip6_opt_ba *mip6_create_ba - __P((u_int8_t, u_int16_t, u_int32_t)); -extern struct ip6_dest *mip6_create_dh - __P((void *, struct mip6_subbuf *, u_int8_t)); -extern int mip6_opt_offset - __P((struct mbuf *, int, int)); -extern int mip6_addr_on_link - __P((struct in6_addr *, int)); -extern u_int32_t mip6_min_lifetime - __P((struct in6_addr *, int)); -extern void mip6_build_in6addr - __P((struct in6_addr *, struct in6_addr *, const struct in6_addr *, - int)); -extern void mip6_build_ha_anycast - __P((struct in6_addr *, const struct in6_addr *, int)); -extern int mip6_add_ifaddr - __P((struct in6_addr *addr, struct ifnet *ifp, int plen, int flags)); -extern int mip6_tunnel_output - __P((struct mbuf **, struct mip6_bc *)); -extern int mip6_tunnel_input - __P((struct mbuf **, int *, int)); -extern int mip6_tunnel - __P((struct in6_addr *, struct in6_addr *, int, int, void *)); -extern int mip6_proxy - __P((struct in6_addr*, struct in6_addr*, int)); -extern struct mip6_bc *mip6_bc_find - __P((struct in6_addr *)); -extern struct mip6_bc *mip6_bc_create - __P((struct in6_addr *, struct in6_addr *, u_int32_t, u_int8_t, - u_int8_t, u_int8_t, u_int16_t)); -extern void mip6_bc_update - __P((struct mip6_bc *, struct in6_addr *, u_int32_t, u_int8_t, - u_int8_t, u_int8_t, u_int16_t, struct bc_info, time_t)); -extern int mip6_bc_delete - __P((struct mip6_bc *, struct mip6_bc **)); -extern struct mip6_na *mip6_na_create - __P((struct in6_addr *, struct in6_addr *, struct in6_addr *, - u_int8_t, u_long, int)); -extern struct mip6_na *mip6_na_delete - __P((struct mip6_na *)); -extern struct mip6_prefix *mip6_prefix_find - __P((struct in6_addr *, u_int8_t)); -extern struct mip6_prefix *mip6_prefix_create - __P((struct ifnet *, struct in6_addr *, u_int8_t, u_int32_t)); -extern struct mip6_prefix *mip6_prefix_delete - __P((struct mip6_prefix *)); -extern void mip6_timer_na - __P((void *)); -extern void mip6_timer_bc - __P((void *)); -extern void mip6_timer_prefix - __P((void *)); - -#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) -extern int mip6_ioctl __P((struct socket *, u_long, caddr_t, struct ifnet *, - struct proc *)); -#else -extern int mip6_ioctl __P((struct socket *, u_long, caddr_t, struct ifnet *)); -#endif - -#if MIP6_DEBUG -void mip6_debug __P((char *, ...)); -#endif - -extern void mip6_enable_debug - __P((int)); -extern int mip6_write_config_data - __P((u_long, caddr_t)); -extern int mip6_clear_config_data - __P((u_long, caddr_t)); -extern int mip6_enable_func - __P((u_long, caddr_t)); - - -/* External declaration of function prototypes (mip6_md.c) */ -extern void mip6_md_init - __P((void)); -extern void mip6_select_defrtr - __P((void)); -extern void mip6_prelist_update - __P((struct nd_prefix *, struct nd_defrouter *)); -extern void mip6_eager_md - __P((int enable)); -extern void mip6_expired_defrouter - __P((struct nd_defrouter *dr)); -extern void mip6_probe_defrouter - __P((struct nd_defrouter *dr)); -extern void mip6_probe_pfxrtrs - __P((void)); -extern void mip6_store_advint - __P((struct nd_opt_advint *, struct nd_defrouter *)); -extern int mip6_delete_ifaddr - __P((struct in6_addr *addr, struct ifnet *ifp)); -extern struct nd_prefix *mip6_get_home_prefix - __P((void)); -extern int mip6_get_md_state - __P((void)); -extern void mip6_md_exit - __P((void)); - - -/* External declaration of function prototypes (mip6_mn.c) */ -extern void mip6_mn_init - __P((void)); -extern void mip6_mn_exit - __P((void)); -extern void mip6_new_defrtr - __P((int, struct nd_prefix *, struct nd_prefix *, - struct nd_defrouter *)); -extern int mip6_rec_ba - __P((struct mbuf *, int)); -extern int mip6_rec_br - __P((struct mbuf *, int)); -extern int mip6_rec_hal - __P((struct in6_addr *, struct in6_addr *, struct mip6_subopt_hal *)); -extern int mip6_rec_ramn - __P((struct mbuf *, int)); -extern int mip6_route_optimize - __P((struct mbuf *)); -extern int mip6_send_bu - __P((struct mip6_bul *, struct mip6_bu_data *, struct mip6_subbuf *)); -extern void mip6_send_bu2fn - __P((struct in6_addr *, struct mip6_hafn *, struct in6_addr *, - struct ifnet *, u_int32_t)); -extern void mip6_update_cns - __P((struct in6_addr *, struct in6_addr *, u_int8_t, u_int32_t)); -extern void mip6_queue_bu - __P((struct mip6_bul *, struct in6_addr *, struct in6_addr *, - u_int8_t, u_int32_t)); -extern struct mip6_opt_bu *mip6_create_bu - __P((u_int8_t, int, int, u_int16_t, u_int32_t)); -extern void mip6_stop_bu - __P((struct in6_addr *)); -extern int mip6_ba_error - __P((struct in6_addr *, struct in6_addr *, struct in6_addr *, - u_int8_t)); -extern u_int32_t mip6_prefix_lifetime - __P((struct in6_addr *)); -extern struct mip6_retrans * mip6_create_retrans - __P((struct mip6_bul *)); -extern void mip6_clear_retrans - __P((struct mip6_bul *)); -extern struct mip6_bul *mip6_bul_find - __P((struct in6_addr *, struct in6_addr *)); -extern struct mip6_bul *mip6_bul_create - __P((struct in6_addr *, struct in6_addr *, struct in6_addr *, - u_int32_t, u_int8_t)); -extern struct mip6_bul *mip6_bul_delete - __P((struct mip6_bul *)); -extern struct mip6_esm *mip6_esm_find - __P((struct in6_addr *)); -extern struct mip6_esm *mip6_esm_create - __P((struct ifnet *, struct in6_addr *, struct in6_addr *, - struct in6_addr *, u_int8_t, int, enum esm_type, u_int16_t)); -extern struct mip6_esm *mip6_esm_delete - __P((struct mip6_esm *)); -extern int mip6_outq_create - __P((void *, struct mip6_subbuf *, struct in6_addr *, - struct in6_addr *, enum send_state)); -extern struct mip6_output *mip6_outq_delete - __P((struct mip6_output *)); -extern void mip6_outq_flush - __P((void)); -extern void mip6_timer_outqueue - __P((void *)); -extern void mip6_timer_bul - __P((void *)); -extern void mip6_timer_esm - __P((void *)); -extern int mip6_write_config_data_mn - __P((u_long, void *)); -extern int mip6_clear_config_data_mn - __P((u_long, caddr_t)); -extern int mip6_enable_func_mn - __P((u_long, caddr_t)); - - -/* External declaration of function prototypes (mip6_ha.c). */ -extern void mip6_ha_init - __P((void)); -extern void mip6_ha_exit - __P((void)); -extern int mip6_rec_raha - __P((struct mbuf *, int)); -extern int mip6_ra_options - __P((struct mip6_ha_list *, caddr_t, int)); -extern struct mip6_subopt_hal * mip6_hal_dynamic - __P((struct in6_addr *)); -extern struct in6_addr *mip6_global_addr - __P((struct in6_addr *)); -extern void mip6_icmp6_output - __P((struct mbuf *)); -extern void mip6_prefix_examine - __P((struct mip6_ha_list *, struct ifnet *, caddr_t, int)); -extern struct mip6_link_list *mip6_ll_find - __P((char *)); -extern struct mip6_link_list *mip6_ll_create - __P((char *, struct ifnet *)); -extern struct mip6_link_list *mip6_ll_delete - __P((struct mip6_link_list *)); -extern struct mip6_ha_list *mip6_hal_find - __P((struct mip6_ha_list *, struct in6_addr *)); -extern struct mip6_ha_list *mip6_hal_create - __P((struct mip6_ha_list **, struct in6_addr *, u_int32_t, int16_t)); -extern void mip6_hal_sort - __P((struct mip6_ha_list **)); -extern struct mip6_ha_list *mip6_hal_delete - __P((struct mip6_ha_list **, struct mip6_ha_list *)); -extern void mip6_timer_ll - __P((void *)); -extern int mip6_write_config_data_ha - __P((u_long, void *)); -extern int mip6_clear_config_data_ha - __P((u_long, void *)); -extern int mip6_enable_func_ha - __P((u_long, caddr_t)); - - -/* External declaration of function prototypes (mip6_hooks.c). */ -extern void mip6_minus_a_case - __P((struct nd_prefix *)); -extern struct nd_prefix *mip6_find_auto_home_addr - __P((void)); -extern void mip6_enable_hooks - __P((int)); -extern void mip6_disable_hooks - __P((int)); -extern int mip6_attach - __P((int)); -extern int mip6_release - __P((void)); - - -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -extern struct callout_handle mip6_timer_na_handle; -extern struct callout_handle mip6_timer_bc_handle; -extern struct callout_handle mip6_timer_outqueue_handle; -extern struct callout_handle mip6_timer_bul_handle; -extern struct callout_handle mip6_timer_esm_handle; -extern struct callout_handle mip6_timer_prefix_handle; -extern struct callout_handle mip6_timer_ll_handle; -#endif - -#endif /* _KERNEL */ - -#endif /* not _NETINET6_MIP6_H_ */ diff --git a/bsd/netinet6/mip6_common.h b/bsd/netinet6/mip6_common.h deleted file mode 100644 index 70f3a3d6f..000000000 --- a/bsd/netinet6/mip6_common.h +++ /dev/null @@ -1,141 +0,0 @@ -/* $KAME: mip6_common.h,v 1.9 2000/03/25 07:23:50 sumikawa Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * Copyright (c) 1999 and 2000 Ericsson Radio Systems AB - * All rights reserved. - * - * Author: Hesham Soliman - * Martti Kuparinen - */ - - -#ifndef _NETINET6_MIP6_COMMON_H_ -#define _NETINET6_MIP6_COMMON_H_ - - - -/* SIOCs used for communication between kernel and user space. - * - * SIOCSDEBUG_MIP6 Set MIP6 debug on/off - * - * SIOCSBCFLUSH_MIP6 Remove list of BC - * - * SIOCSDEFCONFIG_MIP6 Restore default configuration - * - * SIOCSBRUPDATE_MIP6 Set time when CN should send Binding request - * - * SIOCSENABLEBR_MIP6 Enable sending BR to the MN - * - * SIOCSHALISTFLUSH_MIP6 Remove list of Home Agents - * - * SIOCSHAPREF_MIP6 HA preference - * - * SIOCSFWDSLUNICAST_MIP6 Enable forwarding of SL Unicast dest addresses - * - * SIOCSFWDSLMULTICAST_MIP6 Enable forwarding of SL Multicast dest addresses - * - * SIOCSFORADDRFLUSH_MIP6 Remove default foreign address from list - * - * SIOCSHADDRFLUSH_MIP6 Remove Home Address - * - * SIOCSBULISTFLUSH_MIP6 Remove Binding Update list - * - * SIOCACOADDR_MIP6 Set Default foreign IP Address - * - * SIOCAHOMEADDR_MIP6 Add home address - * - * SIOCSBULIFETIME_MIP6 Set default BU lifetime - * - * SIOCSHRLIFETIME_MIP6 Set default lifetime for home registration, not BU - * - * SIOCDCOADDR_MIP6 Remove default foreign address from list - * - * SIOCSPROMMODE_MIP6 Enable link layer promiscuous mode - * - * SIOCSBU2CN_MIP6 Enable sending BU to CN, i.e. Route opt on/off - * - * SIOCSREVTUNNEL_MIP6 Enable tunneling of packets from MN to CN via HA - * - * SIOCSAUTOCONFIG_MIP6 Allow autoconfiguration of Home address - * - * SIOCSEAGERMD_MIP6 Enable eager Movement Detection - * - */ -#define SIOCSDEBUG_MIP6 _IOWR('M', 1, struct mip6_input_data) -#define SIOCSBCFLUSH_MIP6 _IOWR('M', 2, int) -#define SIOCSDEFCONFIG_MIP6 _IOWR('M', 3, int) -#define SIOCSBRUPDATE_MIP6 _IOWR('M', 4, u_int8_t) -#define SIOCSENABLEBR_MIP6 _IOWR('M', 5, u_int8_t) - -#define SIOCSHALISTFLUSH_MIP6 _IOWR('M', 6, int) -#define SIOCSHAPREF_MIP6 _IOWR('M', 7, int) -#define SIOCSFWDSLUNICAST_MIP6 _IOWR('M', 8, int) -#define SIOCSFWDSLMULTICAST_MIP6 _IOWR('M', 9, int) - -#define SIOCSFORADDRFLUSH_MIP6 _IOWR('M', 10, int) -#define SIOCSHADDRFLUSH_MIP6 _IOWR('M', 11, int) -#define SIOCSBULISTFLUSH_MIP6 _IOWR('M', 12, int) -#define SIOCACOADDR_MIP6 _IOWR('M', 13, struct mip6_input_data) -#define SIOCAHOMEADDR_MIP6 _IOWR('M', 14, struct mip6_input_data) -#define SIOCSBULIFETIME_MIP6 _IOWR('M', 15, struct mip6_input_data) -#define SIOCSHRLIFETIME_MIP6 _IOWR('M', 16, struct mip6_input_data) -#define SIOCDCOADDR_MIP6 _IOWR('M', 17, struct mip6_input_data) -#define SIOCSPROMMODE_MIP6 _IOWR('M', 18, struct mip6_input_data) -#define SIOCSBU2CN_MIP6 _IOWR('M', 19, struct mip6_input_data) -#define SIOCSREVTUNNEL_MIP6 _IOWR('M', 20, struct mip6_input_data) -#define SIOCSAUTOCONFIG_MIP6 _IOWR('M', 21, struct mip6_input_data) -#define SIOCSEAGERMD_MIP6 _IOWR('M', 22, struct mip6_input_data) -#define SIOCSATTACH_MIP6 _IOWR('M', 23, struct mip6_input_data) -#define SIOCSRELEASE_MIP6 _IOWR('M', 24, struct mip6_input_data) - - -/* - * Information about which module that has been compiled into the kernel or - * loaded as a module. - */ -#define MIP6_MN_MODULE 0x01 -#define MIP6_HA_MODULE 0x02 - - -/* - * Generic message to pass configuration parameters from mip6config to - * kernel. - */ -struct mip6_input_data { - char if_name[IFNAMSIZ]; /* Interface name */ - u_int8_t prefix_len; /* Prefix length for address */ - struct in6_addr ip6_addr; /* Address */ - struct in6_addr ha_addr; /* Corresponding Home Agent */ - u_int32_t value; /* Value */ -}; - -#endif /* not _NETINET6_MIP6_COMMON_H_ */ diff --git a/bsd/netinet6/mip6_ha.c b/bsd/netinet6/mip6_ha.c deleted file mode 100644 index 2ca6725d2..000000000 --- a/bsd/netinet6/mip6_ha.c +++ /dev/null @@ -1,1196 +0,0 @@ -/* $KAME: mip6_ha.c,v 1.8 2000/03/18 03:05:40 itojun Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, 1998, 1999 and 2000 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * Copyright (c) 1999 and 2000 Ericsson Radio Systems AB - * All rights reserved. - * - * Author: Conny Larsson - * - */ - -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#endif - -/* - * Mobile IPv6 Home Agent - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -/* Declaration of Global variables. */ -struct callout_handle mip6_timer_ll_handle; -#endif - - -/* - ############################################################################## - # - # INITIALIZATION AND EXIT FUNCTIONS - # These functions are executed when the MIPv6 code is activated and de- - # activated respectively. - # - ############################################################################## - */ - -/* - ****************************************************************************** - * Function: mip6_ha_init - * Description: Initialization of MIPv6 variables that must be initialized - * before the HA code is executed. - ****************************************************************************** - */ -void -mip6_ha_init(void) -{ -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - /* Initialize handle for timer functions. */ - callout_handle_init(&mip6_timer_ll_handle); -#endif -} - - - -/* - ****************************************************************************** - * Function: mip6_ha_exit - * Description: This function is called when the HA module is unloaded - * (relesed) from the kernel. - ****************************************************************************** - */ -void -mip6_ha_exit() -{ - struct mip6_link_list *llp; - int s; - - /* Cancel outstanding timeout function calls. */ -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - untimeout(mip6_timer_ll, (void *)NULL, mip6_timer_ll_handle); -#else - untimeout(mip6_timer_ll, (void *)NULL); -#endif - - /* Remove each entry in every queue. */ - s = splnet(); - for (llp = mip6_llq; llp;) - llp = mip6_ll_delete(llp); - mip6_llq = NULL; - splx(s); -} - - - -/* - ############################################################################## - # - # RECEIVING FUNCTIONS - # These functions receives the incoming IPv6 packet and further processing of - # the packet depends on the content in the packet. - # - ############################################################################## - */ - -/* - ****************************************************************************** - * Function: mip6_rec_raha - * Description: Processed by a Home Agent. Includes a Router Advertisement - * with a H-bit set in the flags variable (checked by the calling - * function). - * A link list entry and a Home Agent List entry are created or - * modified if needed. - * Ret value: 0 Everything is OK. Otherwise appropriate error code. - ****************************************************************************** - */ -int -mip6_rec_raha(m, off) -struct mbuf *m; /* Mbuf containing the entire IPv6 packet */ -int off; /* Offset from start of mbuf to start of RA */ -{ - struct ifnet *ifp; /* Receiving interface */ - struct ip6_hdr *ip6; /* IPv6 header */ - struct nd_router_advert *ra; /* Router Advertisement */ - struct mip6_link_list *llp; /* Link list entry */ - struct mip6_ha_list *halp; /* Home Agent list entry */ - caddr_t icmp6msg; /* Copy of mbuf (consequtively) */ - char ifname[IFNAMSIZ+1]; /* Interface name */ - int res, s, icmp6len; - - /* Find out if the RA can be processed */ - ip6 = mtod(m, struct ip6_hdr *); - if (ip6->ip6_hlim != 255) { - log(LOG_INFO, - "%s: Invalid hlim %d in Router Advertisement\n", - __FUNCTION__, ip6->ip6_hlim); - return 0; - } - - if (!IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src)) { - log(LOG_INFO, - "%s: Source Address %s is not link-local\n", - __FUNCTION__, ip6_sprintf(&ip6->ip6_src)); - return 0; - } - - /* Find out which interface the RA arrived at */ - ifp = m->m_pkthdr.rcvif; - sprintf(ifname, "%s", if_name(ifp)); - - llp = mip6_ll_find(ifname); - if (llp == NULL) { - llp = mip6_ll_create(ifname, ifp); - if (llp == NULL) - return ENOBUFS; - } - - /* The mbuf data must be stored consequtively to be able to - cast data from it. */ - icmp6len = m->m_pkthdr.len - off; - icmp6msg = (caddr_t)MALLOC(icmp6len, M_TEMP, M_NOWAIT); - if (icmp6msg == NULL) - return IPPROTO_DONE; - - m_copydata(m, off, icmp6len, icmp6msg); - ra = (struct nd_router_advert *)icmp6msg; - - /* Find the Home Agent sending the RA and read its options. - This section must have high priority since the Home Agent - list entry lifetime is initialized to 0 and could be - removed by the timer function before the RA options have - been evaluated. */ - s = splnet(); - halp = mip6_hal_find(llp->ha_list, &ip6->ip6_src); - if (halp == NULL) { - halp = mip6_hal_create(&llp->ha_list, &ip6->ip6_src, - ntohl(ra->nd_ra_router_lifetime), 0); - if (halp == NULL) { - splx(s); - return ENOBUFS; - } - } else { - halp->lifetime = ntohl(ra->nd_ra_router_lifetime); - halp->pref = 0; - } - - res = mip6_ra_options(halp, icmp6msg, icmp6len); - if (res) { - splx(s); - return res; - } - splx(s); - return 0; -} - - - -/* - ############################################################################## - # - # UTILITY FUNCTIONS - # Miscellaneous functions needed for the internal processing of incoming and - # outgoing control signals. - # - ############################################################################## - */ - -/* - ****************************************************************************** - * Function: mip6_ra_options - * Description: Search through all the options in the Router Advertisement - * and store them in the Home Agent List. - * Ret value: 0 Everything is OK. Otherwise appropriate error code. - ****************************************************************************** - */ -int -mip6_ra_options(halp, icmp6msg, icmp6len) -struct mip6_ha_list *halp; /* Home Agent list entry */ -caddr_t icmp6msg; /* icmp6 message */ -int icmp6len; /* Length of icmp6 message */ -{ - struct mip6_addr_list *ap; /* Address list entry */ - struct nd_opt_hai *hai; /* Home Agent information option */ - struct nd_opt_advint *ai; /* Advertisement Interval option */ - struct nd_opt_prefix_info *pi; /* Ptr to prefix information */ - u_int8_t *optp; /* Ptr to current option in RA */ - int cur_off; /* Cur offset from start of RA */ - - /* Process each option in the RA */ - cur_off = sizeof(struct nd_router_advert); - while (cur_off < icmp6len) { - optp = ((caddr_t)icmp6msg + cur_off); - if (*optp == ND_OPT_PREFIX_INFORMATION) { - /* Check the prefix information option */ - pi = (struct nd_opt_prefix_info *)optp; - if (pi->nd_opt_pi_len != 4) { - ip6stat.ip6s_badoptions++; - return IPPROTO_DONE; - } - - if (!(pi->nd_opt_pi_flags_reserved & - ND_OPT_PI_FLAG_RTADDR)) { - cur_off += 4 * 8; - continue; - } - - if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix) || - IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) { - cur_off += 4 * 8; - continue; - } - - /* Aggregatable unicast address, rfc2374 */ - if (((pi->nd_opt_pi_prefix.s6_addr8[0] & 0xe0) > 0x10) - && (pi->nd_opt_pi_prefix_len != 64)) { - cur_off += 4 * 8; - continue; - } - - /* Store the address if not already present */ - for (ap = halp->addr_list; ap; ap = ap->next) { - if (IN6_ARE_ADDR_EQUAL(&ap->ip6_addr, - &pi->nd_opt_pi_prefix)) - break; - } - - if (ap == NULL) { - /* Create a new address list entry. */ - ap = (struct mip6_addr_list *) - MALLOC(sizeof(struct mip6_addr_list), - M_TEMP, M_WAITOK); - if (ap == NULL) - return ENOBUFS; - bzero(ap, sizeof(struct mip6_addr_list)); - - ap->next = halp->addr_list; - ap->ip6_addr = pi->nd_opt_pi_prefix; - ap->prefix_len = pi->nd_opt_pi_prefix_len; - halp->addr_list = ap; - } - cur_off += 4 * 8; - continue; - } else if (*optp == ND_OPT_ADV_INTERVAL) { - /* Check the advertisement interval option */ - ai = (struct nd_opt_advint *)optp; - if (ai->nd_opt_int_len != 1) { - ip6stat.ip6s_badoptions++; - return IPPROTO_DONE; - } - - /* XXX. Function call to move detection */ - cur_off += 8; - continue; - } else if (*optp == ND_OPT_HA_INFORMATION) { - /* Check the home agent information option */ - hai = (struct nd_opt_hai *)optp; - if (hai->nd_opt_hai_len != 1) { - ip6stat.ip6s_badoptions++; - return IPPROTO_DONE; - } - - halp->pref = ntohs(hai->nd_opt_hai_pref); - halp->lifetime = ntohs(hai->nd_opt_hai_lifetime); - cur_off += 8; - continue; - } else { - if (*(optp + 1) == 0) { - ip6stat.ip6s_badoptions++; - return IPPROTO_DONE; - } - cur_off += *(optp + 1) * 8; - } - } - return 0; -} - - - -/* - ****************************************************************************** - * Function: mip6_hal_dynamic - * Description: Search through all the link lists and home agents list and - * create a Home Agents List sub-option to be used in dynamic - * home agent address discovery. - * If my own global source address is included in the first - * home agents list entry, leave it. It will be in the source - * address of the outgoing packet anyway. - * Ret value: Ptr to the sub-option or NULL. - ****************************************************************************** - */ -struct mip6_subopt_hal * -mip6_hal_dynamic(own_addr) -struct in6_addr *own_addr; /* Own global unicast source address used */ -{ - struct mip6_link_list *llp; /* Link list entry */ - struct mip6_ha_list *halp; /* Home Agent list entry */ - struct mip6_subopt_hal *opt; /* Home Agents list sub-option */ - struct mip6_addr_list *addrp; /* Address list entry */ - struct mip6_addr_list *tmp_addrp; /* Temporary address list entry */ - struct ifaddr *if_addr; /* Interface data */ - struct sockaddr_in6 sin6; - char ifname[IFNAMSIZ+1]; /* Interface name */ - int ii, len, found; - - /* Find the interface */ - bzero(&sin6, sizeof(struct sockaddr_in6)); - sin6.sin6_len = sizeof(struct sockaddr_in6); - sin6.sin6_family = AF_INET6; - sin6.sin6_addr = *own_addr; - - if_addr = ifa_ifwithaddr((struct sockaddr *)&sin6); - if (if_addr == NULL) - return NULL; - - sprintf(ifname, "%s", if_name(if_addr->ifa_ifp)); - - llp = mip6_ll_find(ifname); - if (llp == NULL) - return NULL; - - /* Allocate memory for home agent list sub option */ - opt = (struct mip6_subopt_hal *)MALLOC(sizeof(struct mip6_subopt_hal) + - 31 * sizeof(struct in6_addr), - M_TEMP, M_WAITOK); - if (opt == NULL) - return NULL; - - opt->type = IP6SUBOPT_HALIST; - opt->len = 0; - - /* Search the home agents list for the specific link. */ - /* First, sort the Home Agent list in decending order */ - mip6_hal_sort(&llp->ha_list); - ii = 0; - for (halp = llp->ha_list; halp; halp = halp->next) { - tmp_addrp = NULL; - found = 0; - for (addrp = halp->addr_list; addrp; addrp = addrp->next) { - len = addrp->prefix_len; - if (in6_are_prefix_equal(own_addr, &addrp->ip6_addr, len)) { - if (IN6_ARE_ADDR_EQUAL(own_addr, &addrp->ip6_addr)) { - found = 1; - break; - } else if (tmp_addrp == NULL) - tmp_addrp = addrp; - } - } - - if (found && (ii != 0)) { - opt->halist[ii] = addrp->ip6_addr; - opt->len += IP6OPT_HALISTLEN; - ii += 1; - } else if (tmp_addrp != NULL) { - opt->halist[ii] = tmp_addrp->ip6_addr; - opt->len += IP6OPT_HALISTLEN; - ii += 1; - } - } - - if (opt->len != 0) - return opt; - else { - _FREE(opt, M_TEMP); - return NULL; - } -} - - - -/* - ****************************************************************************** - * Function: mip6_global_addr - * Description: Search the list of IP addresses and find the interface for - * the anycast address. Find a link local address and use this - * address while searching through the list of home agents. - * When my own home agent is found, pick the first global address - * which matches the aycast prefix. - * Ret value: Ptr to the global unicast address or NULL. - ****************************************************************************** - */ -struct in6_addr * -mip6_global_addr(anycast_addr) -struct in6_addr *anycast_addr; /* Home Agents anycast address */ -{ - struct in6_ifaddr *ia; /* I/f address for anycast address */ - struct in6_ifaddr *ia_ll; /* I/f address for link local address */ - struct ifnet *ifp; /* Interface */ - struct mip6_ha_list *halp; /* Home Agent list entry */ - struct mip6_addr_list *addrp; /* Address list entry */ - struct mip6_link_list *llp; /* Link list entry for anycast address */ - char ifname[IFNAMSIZ+1]; /* Interface name */ - - /* Find out the interface for the anycast address */ - for (ia = in6_ifaddr; ia; ia = ia->ia_next) - { - if (ia->ia_addr.sin6_family != AF_INET6) - continue; - if ((ia->ia6_flags & IN6_IFF_ANYCAST) && - IN6_ARE_ADDR_EQUAL(anycast_addr, &ia->ia_addr.sin6_addr)) - break; - } - - if (ia == NULL) - return NULL; - - ifp = ia->ia_ifa.ifa_ifp; - sprintf(ifname, "%s", if_name(ifp)); - llp = mip6_ll_find(ifname); - if (llp == NULL) - return NULL; - - /* Use link local address to identify my own home agent list entry */ - /* XXX: I'm not sure if the 2nd arg is OK(jinmei@kame) */ - ia_ll = in6ifa_ifpforlinklocal(ifp, 0); - if (ia_ll == NULL) - return NULL; - halp = mip6_hal_find(llp->ha_list, &ia_ll->ia_addr.sin6_addr); - if (halp == NULL) - return NULL; - - /* Find my global address */ - for (addrp = halp->addr_list; addrp; addrp = addrp->next) { - if (in6_are_prefix_equal(anycast_addr, &addrp->ip6_addr, - addrp->prefix_len)) - return &addrp->ip6_addr; - } - return NULL; -} - - - -/* - ****************************************************************************** - * Function: mip6_icmp6_output - * Description: Takes care of an outgoing Router Advertisement. It finds the - * outgoing interface and add each prefix to the home agents list. - * Each prefix is also added to the internal prefix list used - * when a BU is received to decide whether the MN is on-link or - * not. - * Ret value: - - ****************************************************************************** - */ -void -mip6_icmp6_output(m) -struct mbuf *m; /* Mbuf chain with IPv6 packet */ -{ - struct ip6_hdr *ip6; /* IPv6 header */ - struct icmp6_hdr *icmp6; /* ICMP6 header */ - struct nd_router_advert *ra; /* Router Advertisement */ - struct ifaddr *if_addr; /* Interface address */ - struct mip6_link_list *llp; /* Link list entry */ - struct mip6_ha_list *halp; /* Home Agent list entry */ - struct sockaddr_in6 sin6; - caddr_t icmp6msg; /* Copy of mbuf (consequtively) */ - char ifname[IFNAMSIZ+1]; /* Interface name */ - int icmp6len, s, res; - - /* Check if the packet shall be processed */ - if (!MIP6_IS_HA_ACTIVE) - return; - - ip6 = mtod(m, struct ip6_hdr *); - if (ip6->ip6_nxt != IPPROTO_ICMPV6) - return; - - /* The mbuf data must be stored consequtively to be able to cast data - from it. */ - icmp6len = m->m_pkthdr.len - sizeof(struct ip6_hdr); - icmp6msg = (caddr_t)MALLOC(icmp6len, M_TEMP, M_WAITOK); - if (icmp6msg == NULL) - return; - - m_copydata(m, sizeof(struct ip6_hdr), icmp6len, icmp6msg); - icmp6 = (struct icmp6_hdr *)icmp6msg; - - /* Check if the packet shall be processed */ - if (icmp6->icmp6_type != ND_ROUTER_ADVERT) { - _FREE(icmp6msg, M_TEMP); - return; - } - - if (icmp6->icmp6_code != 0) { - _FREE(icmp6msg, M_TEMP); - return; - } - - if (icmp6len < sizeof(struct nd_router_advert)) { - _FREE(icmp6msg, M_TEMP); - return; - } - - /* Find the outgoing interface */ - bzero(&sin6, sizeof(struct sockaddr_in6)); - sin6.sin6_len = sizeof(struct sockaddr_in6); - sin6.sin6_family = AF_INET6; - sin6.sin6_addr = ip6->ip6_src; - - if_addr = ifa_ifwithaddr((struct sockaddr *)&sin6); - if (if_addr == NULL) { - _FREE(icmp6msg, M_TEMP); - return; - } - - sprintf(ifname, "%s", if_name(if_addr->ifa_ifp)); - - llp = mip6_ll_find(ifname); - if (llp == NULL) { - llp = mip6_ll_create(ifname, if_addr->ifa_ifp); - if (llp == NULL) { - _FREE(icmp6msg, M_TEMP); - return; - } - } - - /* Find the Home Agent sending the RA and read its options. - This section must have high priority since the Home Agent list - entry lifetime is initialized to 0 and could be removed by the - timer function before the RA options have been evaluated. */ - s = splnet(); - ra = (struct nd_router_advert *)icmp6; - halp = mip6_hal_find(llp->ha_list, &ip6->ip6_src); - if (halp == NULL) { - halp = mip6_hal_create(&llp->ha_list, &ip6->ip6_src, - ntohl(ra->nd_ra_router_lifetime), 0); - if (halp == NULL) { - _FREE(icmp6msg, M_TEMP); - splx(s); - return; - } - } else { - halp->lifetime = ntohl(ra->nd_ra_router_lifetime); - halp->pref = 0; - } - - res = mip6_ra_options(halp, icmp6msg, icmp6len); - if (res) { - _FREE(icmp6msg, M_TEMP); - splx(s); - return; - } - splx(s); - - /* Add the prefix to prefix list and the anycast address to the - interface. */ - mip6_prefix_examine(halp, if_addr->ifa_ifp, icmp6msg, icmp6len); - _FREE(icmp6msg, M_TEMP); - return; -} - - - -/* - ****************************************************************************** - * Function: mip6_prefix_examine - * Description: Add each prefix in a RA to the internal prefix list. Make - * sure that the Home-Agents anycast address for the prefix - * has been assigned to the interface. - * Ret value: - - ****************************************************************************** - */ -void -mip6_prefix_examine(halp, ifp, icmp6msg, icmp6len) -struct mip6_ha_list *halp; /* Home Agent list entry */ -struct ifnet *ifp; /* Outgoing i/f for prefixes */ -caddr_t icmp6msg; /* icmp6 message */ -int icmp6len; /* Length of icmp6 message */ -{ - struct nd_opt_prefix_info *pi; /* Ptr to prefix information */ - struct mip6_prefix *pq; /* Prefix queue entry */ - struct in6_addr anycast_addr; - int cur_off; /* Cur offset from start of mbuf */ - u_int8_t *opt_ptr; /* Ptr to current option in RA */ - - /* Process each option in the RA */ - cur_off = sizeof(struct nd_router_advert); - while (cur_off < icmp6len) { - opt_ptr = ((caddr_t)icmp6msg + cur_off); - if (*opt_ptr == ND_OPT_PREFIX_INFORMATION) { - /* Check the prefix information option */ - pi = (struct nd_opt_prefix_info *)opt_ptr; - if (pi->nd_opt_pi_len != 4) - return; - - if (!(pi->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK)) { - cur_off += 4 * 8; - continue; - } - - if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix) || - IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) { - cur_off += 4 * 8; - continue; - } - - /* Aggregatable unicast address, rfc2374 */ - if (((pi->nd_opt_pi_prefix.s6_addr8[0] & 0xe0) > 0x10) && - (pi->nd_opt_pi_prefix_len != 64)) { - cur_off += 4 * 8; - continue; - } - - /* Store the prefix if not already present */ - pq = mip6_prefix_find(&pi->nd_opt_pi_prefix, - pi->nd_opt_pi_prefix_len); - if (pq == NULL) { - int error; - pq = mip6_prefix_create(ifp, &pi->nd_opt_pi_prefix, - pi->nd_opt_pi_prefix_len, - pi->nd_opt_pi_valid_time); - if (pq == NULL) - return; - - /* Create an Home Agent anycast address, add it to the - interface */ - mip6_build_ha_anycast(&anycast_addr, - &pi->nd_opt_pi_prefix, - pi->nd_opt_pi_prefix_len); - error = mip6_add_ifaddr(&anycast_addr, ifp, - pi->nd_opt_pi_prefix_len, - IN6_IFF_ANYCAST); - if (error) - printf("%s: address assignment error (errno = %d).\n", - __FUNCTION__, error); - - } else - pq->valid_time = ntohl(pi->nd_opt_pi_valid_time); - - cur_off += 4 * 8; - continue; - } else { - if (*(opt_ptr + 1) == 0) { - return; - } - cur_off += *(opt_ptr + 1) * 8; - } - } -} - - - -/* - ############################################################################## - # - # LIST FUNCTIONS - # The Home Agent maintains three lists (link list, home agent list and global - # address list) which are integrated into each other. Besides from this an - # internal prefix list is maintained in order to know which prefixes it is - # supposed to be home network for. The functions in this section are used for - # maintenance (create, find, delete and update entries) of these lists. - # - ############################################################################## - */ - -/* - ****************************************************************************** - * Function: mip6_ll_find - * Description: For each physical interface, i.e. link, that a Home Agent - * send and receive Router Advertisements at, a link list entry - * is maintained. - * Ret value: Pointer to found link list entry or NULL. - ****************************************************************************** - */ -struct mip6_link_list * -mip6_ll_find(ifname) -char *ifname; -{ - struct mip6_link_list *llp; - - for (llp = mip6_llq; llp; llp = llp->next) { - if (strcmp(ifname, llp->ifname) == 0) - return llp; - } - return NULL; -} - - - -/* - ****************************************************************************** - * Function: mip6_ll_create - * Description: Create a new link list entry and add it first to the link - * list. Start the timer if not already started. - * Ret value: Pointer to created link list entry or NULL. - ****************************************************************************** - */ -struct mip6_link_list * -mip6_ll_create(ifname, ifp) -char *ifname; -struct ifnet *ifp; -{ - struct mip6_link_list *llp; - int s, start_timer = 0; - - if (mip6_llq == NULL) - start_timer = 1; - - llp = (struct mip6_link_list *)MALLOC(sizeof(struct mip6_link_list), - M_TEMP, M_WAITOK); - if (llp == NULL) - return NULL; - bzero(llp, sizeof(struct mip6_link_list)); - - /* Add the new link list entry first to the list. */ - s = splnet(); - llp->next = mip6_llq; - strcpy(llp->ifname, ifname); - llp->ifp = ifp; - llp->ha_list = NULL; - mip6_llq = llp; - splx(s); - - if (start_timer) { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - mip6_timer_ll_handle = -#endif - timeout(mip6_timer_ll_funneled, (void *)0, hz); - } - return llp; -} - - - -/* - ****************************************************************************** - * Function: mip6_ll_delete - * Description: Delete the requested link list entry. - * Ret value: Ptr to next entry in list or NULL if last entry removed. - ****************************************************************************** - */ -struct mip6_link_list * -mip6_ll_delete(llp_del) -struct mip6_link_list *llp_del; /* Link list entry to be deleted */ -{ - struct mip6_link_list *llp; /* Current entry in the list */ - struct mip6_link_list *llp_prev; /* Previous entry in the list */ - struct mip6_link_list *llp_next; /* Next entry in the list */ - struct mip6_ha_list *halp; /* Home Agents list */ - int s; - - /* Find the requested entry in the link list. */ - s = splnet(); - llp_next = NULL; - llp_prev = NULL; - for (llp = mip6_llq; llp; llp = llp->next) { - llp_next = llp->next; - if (llp == llp_del) { - if (llp_prev == NULL) - mip6_llq = llp->next; - else - llp_prev->next = llp->next; - - if (llp->ha_list) { - for (halp = llp->ha_list; halp;) - halp = mip6_hal_delete(&llp->ha_list, halp); - } - -#if MIP6_DEBUG - mip6_debug("\nLink List entry deleted (0x%x)\n", llp); -#endif - _FREE(llp, M_TEMP); - - /* Remove the timer if the BC queue is empty */ - if (mip6_llq == NULL) { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - untimeout(mip6_timer_ll, (void *)NULL, mip6_timer_ll_handle); - callout_handle_init(&mip6_timer_ll_handle); -#else - untimeout(mip6_timer_ll, (void *)NULL); -#endif - } - break; - } - llp_prev = llp; - } - splx(s); - return llp_next; -} - - - -/* - ****************************************************************************** - * Function: mip6_hal_find - * Description: Find a Home Agent list entry at a specific link. There will - * be one entry for each node sending a Router Advertisement - * with the H-bit set including a Prefix Information option - * with the R-bit set, for which the Router lifetime or the - * Home Agent lifetime (included in a separate option) is not 0. - * Ret value: Pointer to found Home Agent list entry or NULL. - ****************************************************************************** - */ -struct mip6_ha_list * -mip6_hal_find(hal_start, ll_addr) -struct mip6_ha_list *hal_start; /* First entry in the Home Agents list */ -struct in6_addr *ll_addr; /* Link local address to search for */ -{ - struct mip6_ha_list *halp; - - for (halp = hal_start; halp; halp = halp->next) { - if (IN6_ARE_ADDR_EQUAL(&halp->ll_addr, ll_addr)) - return halp; - } - return NULL; -} - - - -/* - ****************************************************************************** - * Function: mip6_hal_create - * Description: Create a Home Agent list entry for a specific link. - * Ret value: Pointer to created Home Agent list entry or NULL. - ****************************************************************************** - */ -struct mip6_ha_list * -mip6_hal_create(hal_start, ll_addr, lifetime, pref) -struct mip6_ha_list **hal_start; /* First entry in the Home Agents list */ -struct in6_addr *ll_addr; /* Link local address to search for */ -u_int32_t lifetime; /* Node lifetime */ -int16_t pref; /* Node preference */ -{ - struct mip6_ha_list *halp; - int s; - - halp = (struct mip6_ha_list *)MALLOC(sizeof(struct mip6_ha_list), - M_TEMP, M_WAITOK); - if (halp == NULL) - return NULL; - bzero(halp, sizeof(struct mip6_ha_list)); - - /* Add the new home agent list entry first to the list. */ - s = splnet(); - halp->next = *hal_start; - halp->ll_addr = *ll_addr; - halp->lifetime = lifetime; - halp->pref = pref; - halp->addr_list = NULL; - *hal_start = halp; - splx(s); - return halp; -} - - - -/* - ****************************************************************************** - * Function: mip6_hal_sort - * Description: Sort the Home Agent list in decending order. Uses a temporary - * list where all the existing elements are moved. - * Ret value: - - ****************************************************************************** - */ -void -mip6_hal_sort(ha_head) -struct mip6_ha_list **ha_head; /* Start of Home Agent list */ -{ - struct mip6_ha_list *start, *halp; - struct mip6_ha_list *halp_prev, *halp_before, *halp_move; - struct mip6_ha_list *local_start, *local_last; - int16_t last_pref; - int s; - - if (*ha_head == NULL) - return; - - s = splnet(); - start = *ha_head; - local_start = NULL; - local_last = NULL; - - while (1) { - /* Find entry with highest preference */ - last_pref = SHRT_MIN; - halp_prev = NULL; - for (halp = start; halp; halp = halp->next) { - if (halp->pref > last_pref) { - last_pref = halp->pref; - halp_move = halp; - halp_before = halp_prev; - } - halp_prev = halp; - } - - /* Move it to the new list */ - if (local_start == NULL) - local_start = halp_move; - else - local_last->next = halp_move; - local_last = halp_move; - - /* Update the existing list */ - if (halp_before == NULL) - start = halp_move->next; - else - halp_before->next = halp_move->next; - - if (start == NULL) - break; - } - *ha_head = local_start; - splx(s); - return; -} - - - -/* - ****************************************************************************** - * Function: mip6_hal_delete - * Description: Delete a Home Agent list entry. If there are any address list - * entries associated with the Home Agent entry they are deleted - * as well. - * Ret value: Pointer to the next Home Agent list entry. - * NULL if the remaining list is empty or end of list reached. - ****************************************************************************** - */ -struct mip6_ha_list * -mip6_hal_delete(ha_start, ha_delete) -struct mip6_ha_list **ha_start; /* First list entry of HAs for a link */ -struct mip6_ha_list *ha_delete; /* Home Agent entry to delete */ -{ - struct mip6_ha_list *halp; /* Current HA list entry */ - struct mip6_ha_list *halp_prev; /* Previous HA list entry */ - struct mip6_addr_list *addrp; /* Address list entry */ - struct mip6_addr_list *addr_delete; /* Address list entry to delete */ - int s; - - s = splnet(); - halp_prev = NULL; - for (halp = *ha_start; halp; halp = halp->next) { - if (halp != ha_delete) { - halp_prev = halp; - continue; - } - - /* Search the address list and remove each entry */ - for (addrp = halp->addr_list; addrp;) { - addr_delete = addrp; - addrp = addrp->next; - _FREE(addr_delete, M_TEMP); - } - - /* Make sure that the pointer to the first entry is correct */ - if (halp == *ha_start) { - *ha_start = halp->next; - _FREE(halp, M_TEMP); - splx(s); - return *ha_start; - } else { - halp_prev->next = halp->next; - _FREE(halp, M_TEMP); - splx(s); - return halp_prev->next; - } - } - splx(s); - return NULL; -} - - - -/* - ############################################################################## - # - # TIMER FUNCTIONS - # These functions are called at regular basis. They operate on the lists, - # e.g. reducing timer counters and removing entries from the list if needed. - # - ############################################################################## - */ - -/* - ****************************************************************************** - * Function: mip6_timer_ll - * Description: Search the Home Agent list for each link and delete entries for - * which the timer has expired. - * If there are more entries left in the Home Agent list, call - * this fuction again once every second until the list is empty. - * Ret value: - - ****************************************************************************** - */ -void -mip6_timer_ll_funneled(arg) -void *arg; /* Not used */ -{ -#ifdef __APPLE__ - boolean_t funnel_state; - funnel_state = thread_funnel_set(network_flock, TRUE); -#endif - mip6_timer_ll(arg); -#ifdef __APPLE__ - (void) thread_funnel_set(network_flock, FALSE); -#endif -} -void -mip6_timer_ll(arg) -void *arg; /* Not used */ -{ - struct mip6_link_list *llp; /* Current Link list entry */ - struct mip6_ha_list *halp; /* Current Home Agent list entry */ - int s; - - /* Go through the entire Home Agent List and delete all entries - for which the time has expired. */ - s = splnet(); - for (llp = mip6_llq; llp;) { - for (halp = llp->ha_list; halp;) { - halp->lifetime -= 1; - if (halp->lifetime == 0) - halp = mip6_hal_delete(&llp->ha_list, halp); - else - halp = halp->next; - } - - if (llp->ha_list == NULL) - llp = mip6_ll_delete(llp); - else - llp = llp->next; - } - splx(s); - - if (mip6_llq != NULL) { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - mip6_timer_ll_handle = -#endif - timeout(mip6_timer_ll_funneled, (void *)0, hz); - } -} - - - -/* - ############################################################################## - # - # IOCTL FUNCTIONS - # These functions are called from mip6_ioctl. - # - ############################################################################## - */ - -/* - ****************************************************************************** - * Function: mip6_write_config_data_ha - * Description: This function is called to write certain config values for - * MIPv6. The data is written into the global config structure. - * Ret value: - - ****************************************************************************** - */ -int mip6_write_config_data_ha(u_long cmd, void *arg) -{ - int retval = 0; - - switch (cmd) { - case SIOCSHAPREF_MIP6: - mip6_config.ha_pref = ((struct mip6_input_data *)arg)->value; - break; - } - return retval; -} - - - -/* - ****************************************************************************** - * Function: mip6_clear_config_data_ha - * Description: This function is called to clear internal lists handled by - * MIPv6. - * Ret value: - - ****************************************************************************** - */ -int mip6_clear_config_data_ha(u_long cmd, void *data) -{ - int retval = 0; - int s; - struct mip6_link_list *llp; - - s = splnet(); - switch (cmd) { - case SIOCSHALISTFLUSH_MIP6: - for (llp = mip6_llq; llp;) - llp = mip6_ll_delete(llp); - break; - } - splx(s); - return retval; -} - - - -/* - ****************************************************************************** - * Function: mip6_enable_func_ha - * Description: This function is called to enable or disable certain functions - * in mip6. The data is written into the global config struct. - * Ret value: - - ****************************************************************************** - */ -int mip6_enable_func_ha(u_long cmd, caddr_t data) -{ - int enable; - int retval = 0; - - enable = ((struct mip6_input_data *)data)->value; - - switch (cmd) { - case SIOCSFWDSLUNICAST_MIP6: - mip6_config.fwd_sl_unicast = enable; - break; - - case SIOCSFWDSLMULTICAST_MIP6: - mip6_config.fwd_sl_multicast = enable; - break; - } - return retval; -} diff --git a/bsd/netinet6/mip6_hooks.c b/bsd/netinet6/mip6_hooks.c deleted file mode 100644 index 25a05263f..000000000 --- a/bsd/netinet6/mip6_hooks.c +++ /dev/null @@ -1,428 +0,0 @@ -/* $KAME: mip6_hooks.c,v 1.8 2000/03/25 07:23:51 sumikawa Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, 1998, 1999 and 2000 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * Copyright (c) 1999 and 2000 Ericsson Radio Systems AB - * All rights reserved. - * - * Author: Mattias Pettersson - * Hesham Soliman - * Martti Kuparinen - * - */ -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * These are defined in sys/netinet6/ - */ -extern int (*mip6_store_dstopt_pre_hook)(struct mbuf *, u_int8_t *, - u_int8_t, u_int8_t); -extern int (*mip6_rec_ctrl_sig_hook)(struct mbuf *, int); -extern int (*mip6_new_packet_hook)(struct mbuf *); -extern int (*mip6_icmp6_input_hook)(struct mbuf *, int); -extern int (*mip6_output_hook)(struct mbuf *, struct ip6_pktopts **); -extern int (*mip6_rec_ra_hook)(struct mbuf *, int); - -/* Home Agent-specific hooks */ -extern struct in6_addr * (*mip6_global_addr_hook)(struct in6_addr *); -extern struct mip6_subopt_hal * (*mip6_hal_dynamic_hook)(struct in6_addr *); -extern int (*mip6_write_config_data_ha_hook)(u_long, void *); -extern int (*mip6_clear_config_data_ha_hook)(u_long, void *); -extern int (*mip6_enable_func_ha_hook)(u_long, caddr_t); -extern void (*mip6_icmp6_output_hook)(struct mbuf *); - -/* Mobile Node-specific hooks */ -extern int (*mip6_route_optimize_hook)(struct mbuf *); -extern void (*mip6_select_defrtr_hook)(void); -extern struct nd_prefix * (*mip6_get_home_prefix_hook)(void); -extern void (*mip6_prelist_update_hook)(struct nd_prefix *, - struct nd_defrouter *); -extern void (*mip6_expired_defrouter_hook)(struct nd_defrouter *); -extern void (*mip6_probe_pfxrtrs_hook)(void); -extern void (*mip6_store_advint_hook)(struct nd_opt_advint *, - struct nd_defrouter *); -extern int (*mip6_get_md_state_hook)(void); -extern int (*mip6_rec_ba_hook)(struct mbuf *, int); -extern int (*mip6_rec_br_hook)(struct mbuf *, int); -extern void (*mip6_stop_bu_hook)(struct in6_addr *); -extern int (*mip6_write_config_data_mn_hook)(u_long, void *); -extern int (*mip6_clear_config_data_mn_hook)(u_long, caddr_t); -extern int (*mip6_enable_func_mn_hook)(u_long, caddr_t); -extern void (*mip6_minus_a_case_hook)(struct nd_prefix *); -extern struct mip6_esm * (*mip6_esm_find_hook)(struct in6_addr *); - - -void -mip6_minus_a_case(struct nd_prefix *pr) -{ - struct in6_addr addr; - - if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr) || - IN6_IS_ADDR_MULTICAST(&pr->ndpr_addr) || - IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_addr)) { - return; - } - - addr = in6addr_any; - mip6_esm_create(pr->ndpr_ifp, NULL, &addr, &pr->ndpr_addr, - pr->ndpr_plen, MIP6_STATE_UNDEF, PERMANENT, 0xFFFF); -#if MIP6_DEBUG - mip6_debug("Late Home Address %s found for autoconfig'd case. Starting" - " Mobile IPv6.\n", ip6_sprintf(&pr->ndpr_addr)); -#endif - mip6_minus_a_case_hook = 0; - mip6_enable_hooks(MIP6_SPECIFIC_HOOKS); - mip6_md_init(); -} - -struct nd_prefix * -mip6_find_auto_home_addr(void) -{ - struct nd_prefix *pr; -#if 0 - struct in6_ifaddr *ia6; -#endif - - for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { -#if MIP6_DEBUG - mip6_debug("%s: scanning prefix %s (pr = %p)\n", __FUNCTION__, - ip6_sprintf(&pr->ndpr_prefix.sin6_addr), pr); -#endif - if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr) || - IN6_IS_ADDR_MULTICAST(&pr->ndpr_addr) || - IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_addr)) { - continue; - } -#if 0 - ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr); - if (ia6 && (ia6->ia6_flags | IN6_IFF_DETACHED)) - continue; - else - break; /* XXXYYY Remove in v2.0. */ -#else -#if MIP6_DEBUG - mip6_debug("%s: skipping detached test on prefix %s " - "(pr = %p)\n", __FUNCTION__, - ip6_sprintf(&pr->ndpr_prefix.sin6_addr), pr); -#endif - break; -#endif -#if 0 /* XXXYYY Add in v2.0 */ - for (pfxrtr = pr->ndpr_advrtrs.lh_first; pfxrtr; - pfxrtr = pfxrtr->pfr_next) { - if ((pfxrtr->router->flags & ND_RA_FLAG_HA) - == ND_RA_FLAG_HA) - break; - } -#endif /* 0 */ - } - if (pr) { -#if MIP6_DEBUG - mip6_debug("Found an autoconfigured home address " - "immediately: %s\n", ip6_sprintf(&pr->ndpr_addr)); -#endif - } - else { -#if MIP6_DEBUG - mip6_debug("Couldn't find an autoconfigured home address " - "immediately.\n"); -#endif - } - return pr; -} - - -void -mip6_enable_hooks(int scope) -{ - int s; - - /* - * Activate the hook functions. After this some packets might come - * to the module... - * Note: mip6_minus_a_case_hook() is an exception and is not handled - * here. - */ - s = splimp(); - if (scope == MIP6_GENERIC_HOOKS) { - mip6_store_dstopt_pre_hook = mip6_store_dstopt_pre; - mip6_rec_ctrl_sig_hook = mip6_rec_ctrl_sig; - mip6_new_packet_hook = mip6_new_packet; - mip6_icmp6_input_hook = mip6_icmp6_input; - mip6_output_hook = mip6_output; - } - - if (scope == MIP6_CONFIG_HOOKS) { - /* Activate Home Agent-specific hooks */ - mip6_write_config_data_ha_hook = mip6_write_config_data_ha; - mip6_clear_config_data_ha_hook = mip6_clear_config_data_ha; - mip6_enable_func_ha_hook = mip6_enable_func_ha; - - /* Activate Mobile Node-specific hooks */ - mip6_write_config_data_mn_hook = mip6_write_config_data_mn; - mip6_clear_config_data_mn_hook = mip6_clear_config_data_mn; - mip6_enable_func_mn_hook = mip6_enable_func_mn; - } - - if (scope == MIP6_SPECIFIC_HOOKS) { - /* Activate Home Agent-specific hooks */ - if (MIP6_IS_HA_ACTIVE) { - mip6_rec_ra_hook = mip6_rec_raha; - mip6_global_addr_hook = mip6_global_addr; - mip6_hal_dynamic_hook = mip6_hal_dynamic; - mip6_icmp6_output_hook = mip6_icmp6_output; - } - - /* Activate Mobile Node-specific hooks */ - if (MIP6_IS_MN_ACTIVE) { - mip6_route_optimize_hook = mip6_route_optimize; - mip6_rec_ra_hook = mip6_rec_ramn; - mip6_select_defrtr_hook = mip6_select_defrtr; - mip6_get_home_prefix_hook = mip6_get_home_prefix; - mip6_prelist_update_hook = mip6_prelist_update; - mip6_expired_defrouter_hook = mip6_expired_defrouter; - mip6_probe_pfxrtrs_hook = mip6_probe_pfxrtrs; - mip6_store_advint_hook = mip6_store_advint; - mip6_get_md_state_hook = mip6_get_md_state; - mip6_rec_ba_hook = mip6_rec_ba; - mip6_rec_br_hook = mip6_rec_bu; - mip6_stop_bu_hook = mip6_stop_bu; - mip6_esm_find_hook = mip6_esm_find; - } - } - splx(s); - return; -} - - -void -mip6_disable_hooks(int scope) -{ - int s; - - /* - * Deactivate the hook functions. After this some packets might not - * come to the module... - */ - s = splimp(); - - if (scope == MIP6_GENERIC_HOOKS) { - mip6_store_dstopt_pre_hook = 0; - mip6_rec_ctrl_sig_hook = 0; - mip6_new_packet_hook = 0; - mip6_icmp6_input_hook = 0; - mip6_output_hook = 0; - } - - if (scope == MIP6_SPECIFIC_HOOKS) { - - /* De-activate Home Agent-specific hooks */ - if (MIP6_IS_HA_ACTIVE) { - mip6_rec_ra_hook = 0; - mip6_global_addr_hook = 0; - mip6_hal_dynamic_hook = 0; - mip6_write_config_data_ha_hook = 0; - mip6_clear_config_data_ha_hook = 0; - mip6_enable_func_ha_hook = 0; - } - - /* De-activate Mobile Node-specific hooks */ - if (MIP6_IS_MN_ACTIVE) { - mip6_route_optimize_hook = 0; - mip6_rec_ra_hook = 0; - mip6_select_defrtr_hook = 0; - mip6_get_home_prefix_hook = 0; - mip6_prelist_update_hook = 0; - mip6_expired_defrouter_hook = 0; - mip6_probe_pfxrtrs_hook = 0; - mip6_store_advint_hook = 0; - mip6_get_md_state_hook = 0; - mip6_rec_ba_hook = 0; - mip6_rec_br_hook = 0; - mip6_stop_bu_hook = 0; - mip6_write_config_data_mn_hook = 0; - mip6_clear_config_data_mn_hook = 0; - mip6_enable_func_mn_hook = 0; - mip6_esm_find_hook = 0; - mip6_minus_a_case_hook = 0; - } - } - splx(s); - return; -} - - -int -mip6_attach(int module) -{ - /* - * Important that necessary settings have been done _before_ calling - * mip6_attach(), e.g. home address specified or autoconfig set. - * mip6config program sees to that. - */ - -/* - No support for modules here yet. XXXYYY - - Old check (not valid any longer): - #if (defined(MIP6_MN) || defined (MIP6_HA) || defined(MIP6_MODULES)) -*/ - if (mip6_module) { -#if MIP6_DEBUG - char *old = "?", *new = "?"; - if (mip6_module == MIP6_HA_MODULE) - strcpy(old, "Home Agent"); - if (mip6_module == MIP6_MN_MODULE) - strcpy(old, "Mobile Node"); - if (module == MIP6_HA_MODULE) - strcpy(new, "Home Agent"); - if (module == MIP6_MN_MODULE) - strcpy(new, "Mobile Node"); - - mip6_debug("Can't switch operation mode from %s to %s \n" - "- please deactivate first (\"mip6config -x\")\n", - old, new); -#endif - return EINVAL; - } - - switch (module) { - case MIP6_HA_MODULE: - printf("%s: attach ha\n", __FUNCTION__); /* RM */ - mip6_module = module; - mip6_ha_init(); - break; - - case MIP6_MN_MODULE: - printf("%s: attach mn\n", __FUNCTION__); /* RM */ - mip6_module = module; - mip6_mn_init(); - break; - - default: -#if MIP6_DEBUG - mip6_debug("%s: illegal attach (module = %d)\n", __FUNCTION__, - module); -#endif - return EINVAL; - } - - if (MIP6_IS_MN_ACTIVE) { - if(mip6_get_home_prefix_hook) /* Test arbitrary hook */ - return 0; - - /* - * If autoconfig state: find a global address to use as Home - * Address. - * - Take first available on any interface, else if no found: - * - Enable hook to wait for a Router Advertisement to give - * us one. - */ - if (mip6_config.autoconfig) { - struct nd_prefix *pr; - struct in6_addr addr; - - addr = in6addr_any; - if ((pr = mip6_find_auto_home_addr()) != NULL) { - mip6_esm_create(pr->ndpr_ifp, &addr, &addr, - &pr->ndpr_addr,pr->ndpr_plen, - MIP6_STATE_UNDEF, PERMANENT, - 0xFFFF); - mip6_enable_hooks(MIP6_SPECIFIC_HOOKS); - mip6_md_init(); - } - else { -#if MIP6_DEBUG - mip6_debug("Waiting for Router Advertisement " - "to give me an address.\n"); -#endif - mip6_minus_a_case_hook = mip6_minus_a_case; - } - } - else { - /* Manual config */ - mip6_enable_hooks(MIP6_SPECIFIC_HOOKS); - mip6_md_init(); - } - } - - if (MIP6_IS_HA_ACTIVE) { - /* XXXYYY Build anycast or is it done? */ - mip6_enable_hooks(MIP6_SPECIFIC_HOOKS); - } - return 0; -} - - -int -mip6_release(void) -{ - /* Disable the hooks */ - mip6_disable_hooks(MIP6_SPECIFIC_HOOKS); - - if (MIP6_IS_MN_ACTIVE) { - mip6_mn_exit(); - mip6_md_exit(); - } - - if (MIP6_IS_HA_ACTIVE) - mip6_ha_exit(); - -/* - Correspondent Node functionality is never terminated. - mip6_disable_hooks(MIP6_GENERIC_HOOKS); - mip6_exit(); -*/ - - mip6_module = 0; /* Make HA or MN inactive */ - - return 0; -} diff --git a/bsd/netinet6/mip6_io.c b/bsd/netinet6/mip6_io.c deleted file mode 100644 index 739a1177f..000000000 --- a/bsd/netinet6/mip6_io.c +++ /dev/null @@ -1,1507 +0,0 @@ -/* $KAME: mip6_io.c,v 1.7 2000/03/25 07:23:53 sumikawa Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, 1998, 1999 and 2000 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * Copyright (c) 1999 and 2000 Ericsson Radio Systems AB - * All rights reserved. - * - * Author: Conny Larsson - * - */ - -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -void (*mip6_icmp6_output_hook)(struct mbuf *) = 0; -struct mip6_esm * (*mip6_esm_find_hook)(struct in6_addr *) = 0; - - -/* Declaration of Global variables. */ -struct mip6_indata *mip6_inp = NULL; -struct mip6_output *mip6_outq = NULL; - - - -/* - ############################################################################## - # - # RECEIVING FUNCTIONS - # These functions receives the incoming IPv6 packet and further processing of - # the packet depends on the content in the packet. - # - ############################################################################## - */ - -/* - ****************************************************************************** - * Function: mip6_new_packet - * Description: Called once when a new IPv6 packet is received. Resets the - * mip6_inp variable needed later when options in the dest- - * ination header are validated. - * Ret value: 0 if OK. Otherwise IPPROTO_DONE. - * Note: A prerequisite for this function is that the AH or ESP header - * is included in the same IPv6 packet as the destination header, - * i.e we are using transport mode and not tunneling mode. - ****************************************************************************** - */ -int -mip6_new_packet(m) -struct mbuf *m; /* Mbuf containing IPv6 header */ -{ - /* If memory for global variable mip6_indata already allocated, - discard it. */ - if (mip6_inp != NULL) { - if (mip6_inp->bu_opt != NULL) - FREE(mip6_inp->bu_opt, M_TEMP); - if (mip6_inp->ba_opt != NULL) - FREE(mip6_inp->ba_opt, M_TEMP); - if (mip6_inp->br_opt != NULL) - FREE(mip6_inp->br_opt, M_TEMP); - if (mip6_inp->ha_opt != NULL) - FREE(mip6_inp->ha_opt, M_TEMP); - if (mip6_inp->uid != NULL) - FREE(mip6_inp->uid, M_TEMP); - if (mip6_inp->coa != NULL) - FREE(mip6_inp->coa, M_TEMP); - if (mip6_inp->hal != NULL) - FREE(mip6_inp->hal, M_TEMP); - FREE(mip6_inp, M_TEMP); - mip6_inp = NULL; - } - - /* Allocate memory for global variable mip6_inp */ - mip6_inp = (struct mip6_indata *) - MALLOC(sizeof(struct mip6_indata), M_TEMP, M_WAITOK); - if (mip6_inp == NULL) - panic("%s: We should not come here !!!!", __FUNCTION__); - bzero(mip6_inp, sizeof(struct mip6_indata)); - - return 0; -} - - - -/* - ****************************************************************************** - * Function: mip6_store_dstopt_pre - * Description: Pre-processing used by the hook function. - * Ret value: 0 if OK. Otherwise IPPROTO_DONE - ****************************************************************************** - */ -int -mip6_store_dstopt_pre(m, opt, off, dstlen) -struct mbuf *m; /* Pointer to the beginning of mbuf */ -u_int8_t *opt; /* Pointer to the beginning of current option in mbuf */ -u_int8_t off; /* Offset from beginning of mbuf to end of dest header */ -u_int8_t dstlen; /* Remaining length of Destination header */ -{ - u_int8_t type; /* Destination option type */ - - type = *opt; - if (type == IP6OPT_BINDING_UPDATE) { - if (dstlen < IP6OPT_BUMINLEN) { - ip6stat.ip6s_toosmall++; - return IPPROTO_DONE; - } - - if (mip6_store_dstopt(m, opt, off-dstlen) != 0) - return IPPROTO_DONE; - } else if (type == IP6OPT_BINDING_ACK) { - if (dstlen < IP6OPT_BAMINLEN) { - ip6stat.ip6s_toosmall++; - return IPPROTO_DONE; - } - - if (mip6_store_dstopt(m, opt, off-dstlen) != 0) - return IPPROTO_DONE; - } else if (type == IP6OPT_BINDING_REQ) { - if (dstlen < IP6OPT_BRMINLEN) { - ip6stat.ip6s_toosmall++; - return IPPROTO_DONE; - } - - if (mip6_store_dstopt(m, opt, off-dstlen) != 0) - return IPPROTO_DONE; - } else if (type == IP6OPT_HOME_ADDRESS) { - if (dstlen < IP6OPT_HAMINLEN) { - ip6stat.ip6s_toosmall++; - return IPPROTO_DONE; - } - - if (mip6_store_dstopt(m, opt, off-dstlen) != 0) - return IPPROTO_DONE; - } - - return 0; -} - - - -/* - ****************************************************************************** - * Function: mip6_store_dstopt - * Description: Save each MIPv6 option from the Destination header continously. - * They will be evaluated when the entire destination header has - * been read. - * Ret value: 0 if OK - * Otherwise protocol error code from netinet/in.h - ****************************************************************************** - */ -int -mip6_store_dstopt(mp, opt, optoff) -struct mbuf *mp; /* Pointer to the beginning of mbuf */ -u_int8_t *opt; /* Pointer to the beginning of current option in mbuf */ -u_int8_t optoff; /* Offset from beginning of mbuf to start of current - option */ -{ - struct mip6_opt_bu *bu_opt; /* Ptr to BU option data */ - struct mip6_opt_ba *ba_opt; /* Ptr to BA option data */ - struct mip6_opt_br *br_opt; /* Ptr to BR option data */ - struct mip6_opt_ha *ha_opt; /* Ptr to HA option data */ - int tmplen; /* Tmp length for positioning in option */ - int totlen; /* Total length of option + sub-option */ - int error; - - /* Find out what kind of buffer we are dealing with */ - switch (*opt) { - case IP6OPT_BINDING_UPDATE: - /* Allocate and store Binding Update option data */ - mip6_inp->bu_opt = (struct mip6_opt_bu *) - MALLOC(sizeof(struct mip6_opt_bu), M_TEMP, M_WAITOK); - if (mip6_inp->bu_opt == NULL) - return ENOBUFS; - bzero(mip6_inp->bu_opt, sizeof(struct mip6_opt_bu)); - - bu_opt = mip6_inp->bu_opt; - m_copydata(mp, optoff, sizeof(bu_opt->type), - (caddr_t)&bu_opt->type); - tmplen = sizeof(bu_opt->type); - m_copydata(mp, optoff + tmplen, sizeof(bu_opt->len), - (caddr_t)&bu_opt->len); - tmplen += sizeof(bu_opt->len); - m_copydata(mp, optoff + tmplen, sizeof(bu_opt->flags), - (caddr_t)&bu_opt->flags); - tmplen += sizeof(bu_opt->flags); - m_copydata(mp, optoff + tmplen, sizeof(bu_opt->prefix_len), - (caddr_t)&bu_opt->prefix_len); - tmplen += sizeof(bu_opt->prefix_len); - m_copydata(mp, optoff + tmplen, sizeof(bu_opt->seqno), - (caddr_t)&bu_opt->seqno); - tmplen += sizeof(bu_opt->seqno); - m_copydata(mp, optoff + tmplen, sizeof(bu_opt->lifetime), - (caddr_t)&bu_opt->lifetime); - tmplen += sizeof(bu_opt->lifetime); - - bu_opt->seqno = ntohs(bu_opt->seqno); - bu_opt->lifetime = ntohl(bu_opt->lifetime); - - /* Set the BU option present flag */ - mip6_inp->optflag |= MIP6_DSTOPT_BU; - - /* If sub-options are present, store them as well. */ - if (bu_opt->len > IP6OPT_BULEN) { - totlen = bu_opt->len + 2; - error = mip6_store_dstsubopt(mp, opt, optoff, totlen, tmplen); - if (error) - return error; - } - break; - case IP6OPT_BINDING_ACK: - /* Allocate and store all Binding Acknowledgement option data */ - mip6_inp->ba_opt = (struct mip6_opt_ba *) - MALLOC(sizeof(struct mip6_opt_ba), M_TEMP, M_WAITOK); - if (mip6_inp->ba_opt == NULL) - return ENOBUFS; - bzero(mip6_inp->ba_opt, sizeof(struct mip6_opt_ba)); - - ba_opt = mip6_inp->ba_opt; - m_copydata(mp, optoff, sizeof(ba_opt->type), - (caddr_t)&ba_opt->type); - tmplen = sizeof(ba_opt->type); - m_copydata(mp, optoff + tmplen, sizeof(ba_opt->len), - (caddr_t)&ba_opt->len); - tmplen += sizeof(ba_opt->len); - m_copydata(mp, optoff + tmplen, sizeof(ba_opt->status), - (caddr_t)&ba_opt->status); - tmplen += sizeof(ba_opt->status); - m_copydata(mp, optoff + tmplen, sizeof(ba_opt->seqno), - (caddr_t)&ba_opt->seqno); - tmplen += sizeof(ba_opt->seqno); - m_copydata(mp, optoff + tmplen, sizeof(ba_opt->lifetime), - (caddr_t)&ba_opt->lifetime); - tmplen += sizeof(ba_opt->lifetime); - m_copydata(mp, optoff + tmplen, sizeof(ba_opt->refresh), - (caddr_t)&ba_opt->refresh); - tmplen += sizeof(ba_opt->refresh); - - ba_opt->seqno = ntohs(ba_opt->seqno); - ba_opt->lifetime = ntohl(ba_opt->lifetime); - ba_opt->refresh = ntohl(ba_opt->refresh); - - /* Set the BA option present flag */ - mip6_inp->optflag |= MIP6_DSTOPT_BA; - - /* If sub-options are present, store them as well */ - if (ba_opt->len > IP6OPT_BALEN) { - totlen = ba_opt->len + 2; - error = mip6_store_dstsubopt(mp, opt, optoff, totlen, tmplen); - if (error) - return error; - } - break; - case IP6OPT_BINDING_REQ: - /* Allocate and store Binding Update option data */ - mip6_inp->br_opt = (struct mip6_opt_br *) - MALLOC(sizeof(struct mip6_opt_br), M_TEMP, M_WAITOK); - if (mip6_inp->br_opt == NULL) - return ENOBUFS; - bzero(mip6_inp->br_opt, sizeof(struct mip6_opt_br)); - - br_opt = mip6_inp->br_opt; - m_copydata(mp, optoff, sizeof(br_opt->type), - (caddr_t)&br_opt->type); - tmplen = sizeof(br_opt->type); - m_copydata(mp, optoff + tmplen, sizeof(br_opt->len), - (caddr_t)&br_opt->len); - tmplen += sizeof(br_opt->len); - - /* Set the BR option present flag */ - mip6_inp->optflag |= MIP6_DSTOPT_BR; - - /* If sub-options are present, store them as well. */ - if (br_opt->len > IP6OPT_BRLEN) { - totlen = br_opt->len + 2; - error = mip6_store_dstsubopt(mp, opt, optoff, totlen, tmplen); - if (error) - return error; - } - break; - case IP6OPT_HOME_ADDRESS: - /* Allocate and store Home Address option data */ - mip6_inp->ha_opt = (struct mip6_opt_ha *) - MALLOC(sizeof(struct mip6_opt_ha), M_TEMP, M_WAITOK); - if (mip6_inp->ha_opt == NULL) - return ENOBUFS; - bzero(mip6_inp->ha_opt, sizeof(struct mip6_opt_ha)); - - /* Store Home Address option data */ - ha_opt = mip6_inp->ha_opt; - m_copydata(mp, optoff, sizeof(ha_opt->type), - (caddr_t)&ha_opt->type); - tmplen = sizeof(ha_opt->type); - m_copydata(mp, optoff + tmplen, sizeof(ha_opt->len), - (caddr_t)&ha_opt->len); - tmplen += sizeof(ha_opt->len); - m_copydata(mp, optoff + tmplen, sizeof(ha_opt->home_addr), - (caddr_t)&ha_opt->home_addr); - tmplen += sizeof(ha_opt->home_addr); - - /* Set the HA option present flag */ - mip6_inp->optflag |= MIP6_DSTOPT_HA; - break; - default: - /* We will not come here since the calling function knows - which options to call this function for. */ - } - return 0; -} - - - -/* - ****************************************************************************** - * Function: mip6_store_dstsubopt - * Description: Save each MIPv6 suboption from the Destination header. - * They will be evaluated when the entire destination header has - * been read. - * Ret value: 0 if OK - * Otherwise protocol error code from netinet/in.h - ****************************************************************************** - */ -int -mip6_store_dstsubopt(mp, opt, optoff, totlen, tmplen) -struct mbuf *mp; /* Pointer to start of mbuf */ -u_int8_t *opt; /* Pointer to start of current option in mbuf */ -u_int8_t optoff; /* Offset from start of mbuf to current option */ -int totlen; /* Total length for option + sub-options */ -int tmplen; /* Tmp length for positioning in option */ -{ - struct mip6_subopt_hal *hal; - struct mip6_subopt_coa *coa; - int ii, len; - - /* Loop over the sub-options. */ - while (tmplen < totlen) { - switch (*(opt + tmplen)) { - case IP6OPT_PAD1: - tmplen += 1; - break; - case IP6OPT_PADN: - tmplen += *(opt + tmplen + 1) + 2; - break; - case IP6SUBOPT_UNIQUEID: - /* Make sure that the length is OK */ - if (*(opt + tmplen + 1) != IP6OPT_UIDLEN) { - MIP6_FREEINDATA; - return EIO; - } - - /* Allocate and store additional sub-option data */ - mip6_inp->uid = (struct mip6_subopt_id *) - MALLOC(sizeof(struct mip6_subopt_id), M_TEMP, M_WAITOK); - if (mip6_inp->uid == NULL) - return ENOBUFS; - bzero(mip6_inp->uid, sizeof(struct mip6_subopt_id)); - - m_copydata(mp, optoff + tmplen, sizeof(struct mip6_subopt_id), - (caddr_t)mip6_inp->uid); - tmplen += sizeof(struct mip6_subopt_id); - mip6_inp->uid->id = ntohs(mip6_inp->uid->id); - - /* Set the Unique Id sub-option present flag */ - mip6_inp->optflag |= MIP6_DSTOPT_UID; - break; - case IP6SUBOPT_HALIST: - /* Make sure that the length is OK */ - if (*(opt + tmplen + 1) % IP6OPT_HALISTLEN) { - MIP6_FREEINDATA; - return EIO; - } - - /* Allocate and store additional sub-option data */ - len = *(opt + tmplen +1) / IP6OPT_HALISTLEN; - mip6_inp->hal = (struct mip6_subopt_hal *) - MALLOC(sizeof(struct mip6_subopt_hal) + - (len - 1) * sizeof(struct in6_addr), - M_TEMP, M_WAITOK); - if (mip6_inp->hal == NULL) { - MIP6_FREEINDATA; - return ENOMEM; - } - - hal = mip6_inp->hal; - m_copydata(mp, optoff + tmplen, sizeof(hal->type), - (caddr_t)&hal->type); - tmplen += sizeof(hal->type); - m_copydata(mp, optoff + tmplen, sizeof(hal->len), - (caddr_t)&hal->len); - tmplen += sizeof(hal->len); - - /* Loop over the addresses */ - for (ii = 0; ii < len; ii++) { - m_copydata(mp, optoff, tmplen, (caddr_t)&hal->halist[ii]); - tmplen += sizeof(struct in6_addr); - } - - /* Set the BA HA List sub-option present flag */ - mip6_inp->optflag |= MIP6_DSTOPT_HAL; - break; - case IP6SUBOPT_ALTCOA: - /* Make sure that the length is OK */ - if (*(opt + tmplen + 1) != IP6OPT_COALEN) { - MIP6_FREEINDATA; - return EIO; - } - - /* Allocate and store additional sub-option data */ - mip6_inp->coa = (struct mip6_subopt_coa *) - MALLOC(sizeof(struct mip6_subopt_coa), M_TEMP, M_WAITOK); - if (mip6_inp->coa == NULL) - return ENOBUFS; - bzero(mip6_inp->coa, sizeof(struct mip6_subopt_coa)); - - coa = mip6_inp->coa; - m_copydata(mp, optoff + tmplen, sizeof(coa->type), - (caddr_t)&coa->type); - tmplen += sizeof(coa->type); - m_copydata(mp, optoff + tmplen, sizeof(coa->len), - (caddr_t)&coa->len); - tmplen += sizeof(coa->len); - m_copydata(mp, optoff + tmplen, sizeof(coa->coa), - (caddr_t)&coa->coa); - tmplen += sizeof(coa->coa); - - /* Set the Alternate COA sub-option present flag */ - mip6_inp->optflag |= MIP6_DSTOPT_COA; - break; - default: - /* Quietly ignore and skip over the sub-option. - No statistics done. */ - tmplen += *(opt + tmplen + 1) + 2; - } - } - return 0; -} - - - -/* - ############################################################################## - # - # SENDING FUNCTIONS - # Functions used for processing of the outgoing IPv6 packet. - # - ############################################################################## - */ - -/* - ****************************************************************************** - * Function: mip6_output - * Description: This function is always called by function ip6_output. If there - * are any Destination Header options they will be added. A Home - * Address option MUST be added if the MN is roaming. Otherwise - * nothing is done. - * The options are stored in an output queue as a chain of mbufs - * associated with a destination address. This approach makes it - * possible to send it in any IPv6 packet carrying any payload, - * i.e piggy backing. - * Ret value: 0 if OK - * Otherwise any appropriate error code - ****************************************************************************** - */ -int -mip6_output(m, pktopt) -struct mbuf *m; /* Includes IPv6 header */ -struct ip6_pktopts **pktopt; /* Packet Extension headers, options and data */ -{ - struct ip6_pktopts *opt; /* Packet Extension headers (local) */ - struct mip6_output *outp; /* Ptr to mip6 output element */ - struct mip6_esm *esp; /* Ptr to entry in event state list */ - struct ip6_hdr *ip6; /* IPv6 header */ - struct mip6_bc *bcp; /* Binding Cache list entry */ - struct mip6_bul *bulp; - struct mip6_bul *bulp_hr; - struct in6_addr *dst_addr; /* Original dst address for the packet */ - int error; /* Error code from function call */ - int off; /* Offset from start of Destination Header in bytes */ - u_int8_t opttype; /* Option type */ - - ip6 = mtod(m, struct ip6_hdr *); - opt = *pktopt; - - /* We have to maintain a list of all prefixes announced by the - rtadvd deamon (for on-link determination). */ - if (MIP6_IS_HA_ACTIVE) { - if (ip6->ip6_nxt == IPPROTO_ICMPV6) - if (mip6_icmp6_output_hook) (*mip6_icmp6_output_hook)(m); - } - - /* If a COA for the destination address exist, i.e a BC entry is found, - then add a Routing Header and change the destination address to the - MN's COA. */ - dst_addr = &ip6->ip6_dst; - bcp = mip6_bc_find(&ip6->ip6_dst); - if (bcp != NULL) { - dst_addr = &bcp->home_addr; - if ((error = mip6_add_rh(&opt, bcp)) != 0) - return error; - } - - /* If this is a MN and the source address is one of the home addresses - for the MN then a Home Address option must be inserted. */ - esp = NULL; - if (MIP6_IS_MN_ACTIVE) { - if (mip6_esm_find_hook) - esp = (*mip6_esm_find_hook)(&ip6->ip6_src); - - if ((esp != NULL) && (esp->state >= MIP6_STATE_DEREG)) { - if (opt == NULL) { - opt = (struct ip6_pktopts *) - MALLOC(sizeof(struct ip6_pktopts), M_TEMP, M_WAITOK); - if (opt == NULL) - return ENOBUFS; - bzero(opt, sizeof(struct ip6_pktopts)); - opt->ip6po_hlim = -1; /* -1 means to use default hop limit */ - } - - mip6_dest_offset(opt->ip6po_dest2, &off); - if ((error = mip6_add_ha(&opt->ip6po_dest2, - &off, &ip6->ip6_src, &esp->coa)) != 0) - return error; - - /* If the MN initiate the traffic it should add a BU option - to the packet if no BUL entry exist and there is a BUL - "home registration" entry. */ - bulp = mip6_bul_find(dst_addr, &esp->home_addr); - bulp_hr = mip6_bul_find(NULL, &esp->home_addr); - if ((bulp == NULL) && (bulp_hr != NULL)) { - /* Create BUL entry and BU option. */ - bulp = mip6_bul_create(dst_addr, &esp->home_addr, - &esp->coa, - bulp_hr->lifetime, 0); - if (bulp == NULL) - return ENOBUFS; - mip6_queue_bu(bulp, &esp->home_addr, &esp->coa, 0, - bulp_hr->lifetime); - } - } - } - - /* BU, BR and BA should not be sent to link-local, loop-back and - multicast addresses. */ - if (IN6_IS_ADDR_LINKLOCAL(dst_addr) || IN6_IS_ADDR_LOOPBACK(dst_addr) || - IN6_IS_ADDR_MULTICAST(dst_addr)) { - *pktopt = opt; - return 0; - } - - /* If the packet has not been generated completely by MIP6 the - output queue is searched. */ - outp = NULL; - if (mip6_config.enable_outq) { - for (outp = mip6_outq; outp; outp = outp->next) { - if ((outp->flag == NOT_SENT) && - (IN6_ARE_ADDR_EQUAL(&outp->ip6_dst, dst_addr))) - break; - } - } - if (outp == NULL) { - *pktopt = opt; - return 0; - } - - /* Destination option (either BU, BR or BA) found in the output list. - Add it to the existing destination options. */ - if (opt == NULL) { - opt = (struct ip6_pktopts *)MALLOC(sizeof(struct ip6_pktopts), - M_TEMP, M_WAITOK); - if (opt == NULL) - return ENOBUFS; - bzero(opt, sizeof(struct ip6_pktopts)); - opt->ip6po_hlim = -1; /* -1 means to use default hop limit */ - } - - mip6_dest_offset(opt->ip6po_dest2, &off); - bcopy((caddr_t)outp->opt, (caddr_t)&opttype, 1); - if (opttype == IP6OPT_BINDING_UPDATE) { - /* Add my Binding Update option to the Destination Header */ - error = mip6_add_bu(&opt->ip6po_dest2, &off, - (struct mip6_opt_bu *)outp->opt, - (struct mip6_subbuf *)outp->subopt); - if (error) - return error; - } else if (opttype == IP6OPT_BINDING_ACK) { - /* Add my BA option to the Destination Header */ - error = mip6_add_ba(&opt->ip6po_dest2, &off, - (struct mip6_opt_ba *)outp->opt, - (struct mip6_subbuf *)outp->subopt); - if (error) - return error; - } else if (opttype == IP6OPT_BINDING_REQ) { - /* Add my BR option to the Destination Header */ - error = mip6_add_br(&opt->ip6po_dest2, &off, - (struct mip6_opt_br *)outp->opt, - (struct mip6_subbuf *)outp->subopt); - if (error) - return error; - } - - /* Set flag for entry in output queueu to indicate that it has - been sent. */ - outp->flag = SENT; - *pktopt = opt; - return 0; -} - - - -/* - ############################################################################## - # - # UTILITY FUNCTIONS - # Miscellaneous functions needed for the internal processing of incoming and - # outgoing control signals. - # - ############################################################################## - */ - -/* - ****************************************************************************** - * Function: mip6_add_rh - * Description: Add a Routing Header type 0 to the outgoing packet, if its not - * already present, and add the COA for the MN. - * If a Routing Header type 0 exist, but contains no data, or the - * COA for the MN is missing it is added to the Routing Header. - * If the Routing Header is not of type 0 the function returns. - * Ret value: 0 OK. Routing Header might have been added - * ENOBUFS No memory available - * Note: The destination address for the outgoing packet is not changed - * since this is taken care of in the ip6_output function. - ****************************************************************************** - */ -int -mip6_add_rh(opt, bcp) -struct ip6_pktopts **opt; /* Packet Ext headers, options and data */ -struct mip6_bc *bcp; /* Binding Cache list entry */ -{ - struct ip6_pktopts *opt_local; /* Pkt Ext headers, options & data */ - struct ip6_rthdr0 *rthdr0; /* Routing header type 0 */ - struct in6_addr *ip6rt_addr; /* IPv6 routing address(es) */ - caddr_t ptr; /* Temporary pointer */ - int ii, len, new_len, idx; - - /* A Multicast address must not appear in a Routing Header. */ - if (IN6_IS_ADDR_MULTICAST(&bcp->coa)) - return 0; - - opt_local = *opt; - if (opt_local == NULL) { - /* No Packet options present at all. Add a Routing Header. */ - opt_local = (struct ip6_pktopts *)MALLOC(sizeof(struct ip6_pktopts), - M_TEMP, M_WAITOK); - if (opt_local == NULL) - return ENOBUFS; - bzero(opt_local, sizeof(struct ip6_pktopts)); - opt_local->ip6po_hlim = -1; /* -1 means to use default hop limit */ - - opt_local->ip6po_rhinfo.ip6po_rhi_rthdr = - mip6_create_rh(&bcp->coa, IPPROTO_IP); - if(opt_local->ip6po_rhinfo.ip6po_rhi_rthdr == NULL) - return ENOBUFS; - } else if (opt_local->ip6po_rhinfo.ip6po_rhi_rthdr == NULL) { - /* Packet extension header allocated but no RH present, add one. */ - opt_local->ip6po_rhinfo.ip6po_rhi_rthdr = - mip6_create_rh(&bcp->coa, IPPROTO_IP); - if(opt_local->ip6po_rhinfo.ip6po_rhi_rthdr == NULL) - return ENOBUFS; - } else { - /* A RH exist. Don't do anything if the type is not 0. */ - if (opt_local->ip6po_rhinfo.ip6po_rhi_rthdr->ip6r_type != - IPV6_RTHDR_TYPE_0) - return 0; - - /* If the outgoing packet contains a BA the Routing Header is - correct generated by MIP6. No further action is needed. */ - if (opt_local->ip6po_dest2 == NULL) - return 0; - - len = (opt_local->ip6po_dest2->ip6d_len + 1) << 3; - ii = 2; - ptr = (caddr_t)opt_local->ip6po_dest2 + 2; - while (ii < len) { - if (*ptr == IP6OPT_PAD1) { - ii += 1; - ptr += 1; - continue; - } - if (*ptr == IP6OPT_BINDING_ACK) - return 0; - ii += *(ptr + 1) + 2; - ptr += *(ptr + 1) + 2; - } - - /* A routing header exist and the outgoing packet does not include - a BA. The routing header has been generated by a user and must - be checked. If the last segment is not equal to the MN's COA, - add it. */ - len = opt_local->ip6po_rhinfo.ip6po_rhi_rthdr->ip6r_len; - if (len == 0) - new_len = 2; - else { - new_len = len + 2; - idx = (len / 2) - 1; - rthdr0 = (struct ip6_rthdr0 *) - opt_local->ip6po_rhinfo.ip6po_rhi_rthdr; - ptr = (caddr_t)rthdr0 + sizeof(struct ip6_rthdr0); - ip6rt_addr = (struct in6_addr *)ptr; - if (IN6_ARE_ADDR_EQUAL(&bcp->coa, ip6rt_addr + idx)) - return 0; - } - - rthdr0 = (struct ip6_rthdr0 *) - MALLOC(sizeof(struct ip6_rthdr0) + - (new_len / 2) * sizeof(struct in6_addr), M_TEMP, M_WAITOK); - if (rthdr0 == NULL) - return ENOBUFS; - - bcopy((caddr_t)opt_local->ip6po_rhinfo.ip6po_rhi_rthdr, - (caddr_t)rthdr0, (len + 1) * 8); - bcopy((caddr_t)&bcp->coa, (caddr_t)rthdr0 + (len + 1) * 8, - sizeof(struct in6_addr)); - rthdr0->ip6r0_len = new_len; - rthdr0->ip6r0_segleft = new_len / 2; - - FREE(opt_local->ip6po_rhinfo.ip6po_rhi_rthdr, M_IP6OPT); - opt_local->ip6po_rhinfo.ip6po_rhi_rthdr = - (struct ip6_rthdr *)rthdr0; - } - - /* Change the IP destination address to the COA for the MN. */ - *opt = opt_local; - return 0; -} - - - -/* - ****************************************************************************** - * Function: mip6_align - * Description: Align the outgoing Destination Header to 8-byte - * Ret value: - - ****************************************************************************** - */ -void -mip6_align(dstopt, off) -struct ip6_dest *dstopt; /* IPv6 destination options for the packet */ -int *off; /* Offset from start of Destination Header (byte) */ -{ - int rest; /* Rest of modulo division */ - u_int8_t padlen; /* Number of bytes to pad */ - u_int8_t padn; /* Number for option type PADN */ - - padn = IP6OPT_PADN; - rest = *off % 8; - if (rest) { - padlen = 8 - rest; - if (rest == 7) { - /* Add a PAD1 option */ - bzero((caddr_t)dstopt + *off, 1); - *off += 1; - } else { - /* Add a PADN option */ - bzero((caddr_t)dstopt + *off, padlen); - bcopy(&padn, (caddr_t)dstopt + *off, 1); - padlen = padlen - 2; - bcopy(&padlen, (caddr_t)dstopt + *off + 1, 1); - *off += padlen + 2; - } - } -} - - - -/* - ****************************************************************************** - * Function: mip6_dest_offset - * Description: Calculate offset for new data in the Destination Header. - * Additional options will be added beginning at the offset. - ****************************************************************************** - */ -void -mip6_dest_offset(dstopt, off) -struct ip6_dest *dstopt; /* IPv6 destination options for the packet */ -int *off; /* Offset from start of Destination Header (byte) */ -{ - int ii; /* Internal counter */ - u_int8_t opttype; /* Option type found in Destination Header*/ - u_int8_t optlen; /* Option length incl type and length */ - u_int32_t len; /* Length of Destination Header in bytes */ - - if (dstopt == NULL) { - *off = 0; - return; - } - - len = (dstopt->ip6d_len + 1) << 3; - *off = 2; - - for (ii = 2; ii < len;) { - bcopy((caddr_t)dstopt + ii, (caddr_t)&opttype, 1); - if (opttype == IP6OPT_PAD1) { - *off = ii; - ii += 1; - continue; - } - bcopy((caddr_t)dstopt + ii + 1, (caddr_t)&optlen, 1); - if (opttype == IP6OPT_PADN) { - *off = ii; - ii += 2 + optlen; - } else { - ii += 2 + optlen; - *off = ii; - } - } -} - - - -/* - ****************************************************************************** - * Function: mip6_add_ha - * Description: Add Home Address option to the Destination Header. Change the - * IPv6 source address to the care-of address of the MN. - * Ret value: 0 if OK - * Otherwise any appropriate error code - ****************************************************************************** - */ -int -mip6_add_ha(dstopt, off, src_addr, coa) -struct ip6_dest **dstopt; /* IPv6 destination options for the packet */ -int *off; /* Offset from start of Dest Header (byte) */ -struct in6_addr *src_addr; /* IPv6 header source address */ -struct in6_addr *coa; /* MN's care-of address */ -{ - struct ip6_dest *new_opt; /* Old dest options + Home address option */ - struct ip6_dest *dest; /* Local variable for destination option */ - int ii; /* Internal counter */ - int rest; /* Rest of modulo division */ - u_int8_t padn; /* Number for option type PADN */ - u_int8_t opttype; /* Option type */ - u_int8_t optlen; /* Option length excluding type and length */ - u_int8_t dstlen; /* destination Header length in 8-bytes */ - u_int32_t len; /* Length of Destination Header in bytes */ - - /* Allocate memory for the Home Address option */ - dest = *dstopt; - if (dest == NULL) { - dest = (struct ip6_dest *)MALLOC(sizeof(struct ip6_dest) + - sizeof(struct mip6_opt_ha), - M_TEMP, M_WAITOK); - if (dest == NULL) - return ENOBUFS; - bzero(dest, sizeof(struct ip6_dest) + sizeof(struct mip6_opt_ha)); - *off = 2; - } else { - len = (dest->ip6d_len + 1) << 3; - new_opt = (struct ip6_dest *)MALLOC(len + - sizeof(struct mip6_opt_ha), - M_TEMP, M_WAITOK); - if (new_opt == NULL) - return ENOBUFS; - bzero(new_opt, len + sizeof(struct mip6_opt_ha)); - bcopy((caddr_t)dest, (caddr_t)new_opt, len); - FREE(dest, M_IP6OPT); - dest = new_opt; - } - - /* Make sure that the offset is correct for adding a Home Address - option */ - padn = IP6OPT_PADN; - rest = *off % 4; - if (rest == 0) { - /* Add a PADN option with length 0 */ - bzero((caddr_t)dest + *off, 2); - bcopy(&padn, (caddr_t)dest + *off, 1); - *off += 2; - } else if (rest == 1) { - /* Add a PAD1 option */ - bzero((caddr_t)dest + *off, 1); - *off += 1; - } else if (rest == 3) { - /* Add a PADN option with length 1 */ - bzero((caddr_t)dest + *off, 3); - bcopy(&padn, (caddr_t)dest + *off, 1); - bcopy(&padn, (caddr_t)dest + *off + 1, 1); - *off += 3; - } - - /* Add the options in the way they shall be added. */ - opttype = IP6OPT_HOME_ADDRESS; - optlen = IP6OPT_HALEN; - - bcopy(&opttype, (caddr_t)dest + *off, 1); - *off += 1; - bcopy(&optlen, (caddr_t)dest + *off, 1); - *off += 1; - - for (ii = 0; ii < 4; ii++) { - bcopy((caddr_t)&src_addr->s6_addr32[ii], (caddr_t)dest + *off, 4); - *off += 4; - } - - /* Align the Destination Header to 8-byte */ - mip6_align(dest, off); - - /* Change the total length of the Destination header */ - dstlen = (*off >> 3) - 1; - bcopy(&dstlen, (caddr_t)dest + 1, 1); - - /* Change the IP6 source address to the care-of address */ - src_addr->s6_addr32[0] = coa->s6_addr32[0]; - src_addr->s6_addr32[1] = coa->s6_addr32[1]; - src_addr->s6_addr32[2] = coa->s6_addr32[2]; - src_addr->s6_addr32[3] = coa->s6_addr32[3]; - *dstopt = dest; - return 0; -} - - - -/* - ****************************************************************************** - * Function: mip6_add_bu - * Description: Copy BU option and sub-option (if present) to a Destination - * Header. - * Memory in the Destination Header for the BU is created, the - * header is aligned to 8-byte alignment and the total length of - * the header is updated. - * Ret value: 0 if OK - * Otherwise any appropriate error code - ****************************************************************************** - */ -int -mip6_add_bu(dstopt, off, optbu, subopt) -struct ip6_dest **dstopt; /* IPv6 destination options for the packet */ -int *off; /* Offset from start of Dest Header (byte) */ -struct mip6_opt_bu *optbu; /* BU option data */ -struct mip6_subbuf *subopt; /* BU sub-option data (NULL if not present) */ -{ - struct ip6_dest *new_opt; /* Old destination options + BU option */ - struct ip6_dest *dest; /* Local variable for destination option */ - u_int8_t padn; /* Number for option type PADN */ - u_int8_t dstlen; /* Destination Header length in 8-bytes */ - int offlen; /* Offset for option length in the buffer */ - int rest; /* Rest of modulo division */ - int optlen; /* Length of BU option incl sub-options */ - int tmp16; /* Temporary converting of 2-byte */ - int tmp32; /* Temporary converting of 4-byte */ - int len; /* Length of allocated memory */ - int after, before; - - /* Verify input */ - if (optbu == NULL) - return 0; - - /* Allocate memory for the BU option and sub-option (if present). */ - dest = *dstopt; - if (dest == NULL) { - len = sizeof(struct ip6_dest) + sizeof(struct mip6_opt_bu) + 8; - if (subopt != NULL) - len += subopt->len; - - dest = (struct ip6_dest *)MALLOC(len, M_TEMP, M_WAITOK); - if (dest == NULL) - return ENOBUFS; - bzero(dest, len); - *off = 2; - } else { - len = (dest->ip6d_len + 1) << 3; - len += sizeof(struct mip6_opt_bu) + 8; - if (subopt != NULL) - len += subopt->len; - - new_opt = (struct ip6_dest *)MALLOC(len, M_TEMP, M_WAITOK); - if (new_opt == NULL) - return ENOBUFS; - - bzero(new_opt, len); - bcopy((caddr_t)dest, (caddr_t)new_opt, (dest->ip6d_len + 1) << 3); - FREE(dest, M_IP6OPT); - dest = new_opt; - } - - /* Compensate for the alignment requirement. */ - padn = IP6OPT_PADN; - rest = *off % 4; - if (rest == 0) { - /* Add a PADN option with length 0 */ - bzero((caddr_t)dest + *off, 2); - bcopy(&padn, (caddr_t)dest + *off, 1); - *off += 2; - } else if (rest == 1) { - /* Add a PAD1 option */ - bzero((caddr_t)dest + *off, 1); - *off += 1; - } else if (rest == 3) { - /* Add a PADN option with length 1 */ - bzero((caddr_t)dest + *off, 3); - bcopy(&padn, (caddr_t)dest + *off, 1); - bcopy(&padn, (caddr_t)dest + *off + 1, 1); - *off += 3; - } - offlen = *off + 1; - - /* Reset BU option length in case of retransmission. */ - optbu->len = IP6OPT_BULEN; - - /* Copy the BU data from the internal structure to the Dest Header */ - bcopy((caddr_t)&optbu->type, (caddr_t)dest + *off, sizeof(optbu->type)); - *off += sizeof(optbu->type); - bcopy((caddr_t)&optbu->len, (caddr_t)dest + *off, sizeof(optbu->len)); - *off += sizeof(optbu->len); - bcopy((caddr_t)&optbu->flags, (caddr_t)dest + *off, sizeof(optbu->flags)); - *off += sizeof(optbu->flags); - bcopy((caddr_t)&optbu->prefix_len, (caddr_t)dest + *off, - sizeof(optbu->prefix_len)); - *off += sizeof(optbu->prefix_len); - tmp16 = htons(optbu->seqno); - bcopy((caddr_t)&tmp16, (caddr_t)dest + *off, sizeof(optbu->seqno)); - *off += sizeof(optbu->seqno); - tmp32 = htonl(optbu->lifetime); - bcopy((caddr_t)&tmp32, (caddr_t)dest + *off, sizeof(optbu->lifetime)); - *off += sizeof(optbu->lifetime); - - /* If sub-options are present, add them as well. */ - optlen = optbu->len; - if (subopt) { - /* Align the Destination Header to 8-byte before sub-options - are added. */ - before = *off; - mip6_align(dest, off); - after = *off; - optlen += after - before; - - bcopy((caddr_t)subopt->buffer, (caddr_t)dest + *off, subopt->len); - *off += subopt->len; - optlen += subopt->len; - optbu->len += subopt->len; - } - - /* Make sure that the option length is correct. */ - bcopy((caddr_t)&optlen, (caddr_t)dest + offlen, 1); - - /* Align the Destination Header to 8-byte */ - mip6_align(dest, off); - - /* Change the total length of the Destination header */ - dstlen = (*off >> 3) - 1; - bcopy(&dstlen, (caddr_t)dest + 1, 1); - *dstopt = dest; - return 0; -} - - - -/* - ****************************************************************************** - * Function: mip6_add_ba - * Description: Copy BA option and sub-option (if present) to a Destination - * Header. - * Memory in the Destination Header for the BU is created, the - * header is aligned to 8-byte alignment and the total length of - * the header is updated. - * Ret value: 0 if OK - * Otherwise any appropriate error code - ****************************************************************************** - */ -int -mip6_add_ba(dstopt, off, optba, subopt) -struct ip6_dest **dstopt; /* IPv6 dest options for the packet */ -int *off; /* Offset from start of dest Header (byte) */ -struct mip6_opt_ba *optba; /* BA option data */ -struct mip6_subbuf *subopt; /* BA sub-option data (NULL if not present) */ -{ - struct ip6_dest *new_opt; /* Old destination options + BA option */ - struct ip6_dest *dest; /* Local variable for destination option */ - u_int8_t padn; /* Number for option type PADN */ - u_int8_t dstlen; /* Destination Header length in 8-bytes */ - int offlen; /* Offset for option length in the buffer */ - int optlen; /* Length of BA option incl sub-options */ - int rest; /* Rest of modulo division */ - int tmp16; /* Temporary converting of 2-byte */ - int tmp32; /* Temporary converting of 4-byte */ - int len; /* Length of allocated memory */ - int after, before; - - /* Verify input */ - if (optba == NULL) - return 0; - - /* Allocate memory for the BA option and sub-option (if present). */ - dest = *dstopt; - if (dest == NULL) { - len = sizeof(struct ip6_dest) + sizeof(struct mip6_opt_ba) + 8; - if (subopt != NULL) - len += subopt->len; - - dest = (struct ip6_dest *)MALLOC(len, M_TEMP, M_WAITOK); - if (dest == NULL) - return ENOBUFS; - bzero(dest, len); - *off = 2; - } else { - len = (dest->ip6d_len + 1) << 3; - len += sizeof(struct mip6_opt_ba) + 8; - if (subopt != NULL) - len += subopt->len; - - new_opt = (struct ip6_dest *)MALLOC(len, M_TEMP, M_WAITOK); - if (new_opt == NULL) - return ENOBUFS; - bzero(new_opt, len); - bcopy((caddr_t)dest, (caddr_t)new_opt, (dest->ip6d_len + 1) << 3); - FREE(dest, M_IP6OPT); - dest = new_opt; - } - - /* Compensate for the alignment requirement. */ - padn = IP6OPT_PADN; - rest = *off % 4; - if (rest == 1) { - /* Add a PADN option with length 0 */ - bzero((caddr_t)dest + *off, 2); - bcopy(&padn, (caddr_t)dest + *off, 1); - *off += 2; - } else if (rest == 2) { - /* Add a PAD1 option */ - bzero((caddr_t)dest + *off, 1); - *off += 1; - } else if (rest == 0) { - /* Add a PADN option with length 1 */ - bzero((caddr_t)dest + *off, 3); - bcopy(&padn, (caddr_t)dest + *off, 1); - bcopy(&padn, (caddr_t)dest + *off + 1, 1); - *off += 3; - } - offlen = *off + 1; - - /* Copy the BA data from the internal structure to mbuf */ - bcopy((caddr_t)&optba->type, (caddr_t)dest + *off, sizeof(optba->type)); - *off += sizeof(optba->type); - bcopy((caddr_t)&optba->len, (caddr_t)dest + *off, sizeof(optba->len)); - *off += sizeof(optba->len); - bcopy((caddr_t)&optba->status, (caddr_t)dest + *off, - sizeof(optba->status)); - *off += sizeof(optba->status); - tmp16 = htons(optba->seqno); - bcopy((caddr_t)&tmp16, (caddr_t)dest + *off, sizeof(optba->seqno)); - *off += sizeof(optba->seqno); - tmp32 = htonl(optba->lifetime); - bcopy((caddr_t)&tmp32, (caddr_t)dest + *off, sizeof(optba->lifetime)); - *off += sizeof(optba->lifetime); - tmp32 = htonl(optba->refresh); - bcopy((caddr_t)&tmp32, (caddr_t)dest + *off, sizeof(optba->refresh)); - *off += sizeof(optba->refresh); - - /* If sub-options are present, add them as well. */ - optlen = IP6OPT_BALEN; - if (subopt) { - /* Align the Destination Header to 8-byte before sub-options - are added. */ - before = *off; - mip6_align(dest, off); - after = *off; - optlen += after - before; - - bcopy((caddr_t)subopt->buffer, (caddr_t)dest + *off, subopt->len); - *off += subopt->len; - optlen += subopt->len; - optba->len += subopt->len; - } - - /* Make sure that the option length is correct. */ - bcopy((caddr_t)&optlen, (caddr_t)dest + offlen, 1); - - /* Align the Destination Header to 8-byte */ - mip6_align(dest, off); - - /* Change the total length of the Destination header */ - dstlen = (*off >> 3) - 1; - bcopy(&dstlen, (caddr_t)dest + 1, 1); - *dstopt = dest; - return 0; -} - - - -/* - ****************************************************************************** - * Function: mip6_add_br - * Description: Copy BR option and sub-option (if present) to a Destination - * Header. - * Memory in the Destination Header for the BU is created, the - * header is aligned to 8-byte alignment and the total length of - * the header is updated. - * Ret value: 0 if OK - * Otherwise any appropriate error code - ****************************************************************************** - */ -int -mip6_add_br(dstopt, off, optbr, subopt) -struct ip6_dest **dstopt; /* IPv6 destination options for the packet */ -int *off; /* Offset from start of Dest Header (byte) */ -struct mip6_opt_br *optbr; /* BR option data */ -struct mip6_subbuf *subopt; /* BR sub-option data (NULL if not present) */ -{ - struct ip6_dest *new_opt; /* Old destination options + BU option */ - struct ip6_dest *dest; /* Local variable for destination option */ - u_int8_t dstlen; /* Destination Header length in 8-bytes */ - int offlen; /* Offset for option length in the buffer */ - int rest; /* Rest of modulo division */ - int optlen; /* Length of BR option incl sub-options */ - int len; /* Length of allocated memory */ - int after, before; - - /* Verify input */ - if (optbr == NULL) - return 0; - - /* Allocate memory for the BR option and sub-option (if present). */ - dest = *dstopt; - if (dest == NULL) { - len = sizeof(struct ip6_dest) + sizeof(struct mip6_opt_br) + 8; - if (subopt != NULL) - len += subopt->len; - - dest = (struct ip6_dest *)MALLOC(len, M_TEMP, M_WAITOK); - if (dest == NULL) - return ENOBUFS; - - bzero(dest, len); - *off = 2; - } else { - len = (dest->ip6d_len + 1) << 3; - len += sizeof(struct mip6_opt_br) + 8; - if (subopt != NULL) - len += subopt->len; - - new_opt = (struct ip6_dest *)MALLOC(len, M_TEMP, M_WAITOK); - if (new_opt == NULL) - return ENOBUFS; - - bzero(new_opt, len); - bcopy((caddr_t)dest, (caddr_t)new_opt, (dest->ip6d_len + 1) << 3); - FREE(dest, M_IP6OPT); - dest = new_opt; - } - - /* Compensate for the alignment requirement. */ - rest = *off % 4; - if ((rest == 1) || (rest == 3)) { - /* Add a PAD1 option */ - bzero((caddr_t)dest + *off, 1); - *off += 1; - } - offlen = *off +1; - - /* Copy the BR data from the internal structure to mbuf */ - bcopy((caddr_t)&optbr->type, (caddr_t)dest + *off, sizeof(optbr->type)); - *off += sizeof(optbr->type); - bcopy((caddr_t)&optbr->len, (caddr_t)dest + *off, sizeof(optbr->len)); - *off += sizeof(optbr->len); - - - /* If sub-options are present, add them as well. */ - optlen = IP6OPT_BRLEN; - if (subopt) { - /* Align the Destination Header to 8-byte before sub-options - are added. */ - before = *off; - mip6_align(dest, off); - after = *off; - optlen += after - before; - - bcopy((caddr_t)subopt->buffer, (caddr_t)dest + *off, subopt->len); - *off += subopt->len; - optlen += subopt->len; - optbr->len += subopt->len; - } - - /* Make sure that the option length is correct. */ - bcopy((caddr_t)&optlen, (caddr_t)dest + offlen, 1); - - /* Align the Destination Header to 8-byte */ - mip6_align(dest, off); - - /* Change the total length of the Destination header */ - dstlen = (*off >> 3) - 1; - bcopy(&dstlen, (caddr_t)dest + 1, 1); - *dstopt = dest; - return 0; -} - - - -/* - ****************************************************************************** - * Function: mip6_store_subopt - * Description: Store a sub-option in a buffer. The buffer must be allocated - * by the calling function and big enough to hold all the sub- - * options that may be added to an option (BU, BR or BA). - * Alignement requirement for the different sub-options are taken - * care of before its added to the buffer. - * Ret value: 0 if OK. Otherwise 1 - ****************************************************************************** - */ -int -mip6_store_subopt(subbuf, subopt) -struct mip6_subbuf **subbuf; /* Buffert containing sub-options */ -caddr_t subopt; /* TLV coded sub-option */ -{ - struct mip6_subopt_id *uid; - struct mip6_subopt_hal *hal; - struct mip6_subopt_coa *altcoa; - struct mip6_subbuf *buf; - u_int8_t pad1, padn; - u_int16_t tmp16; - int rest, no, ii, padlen; - - /* Make sure that a sub-option is present. */ - if (subopt == NULL) - return 0; - - /* Allocate memory for buffer if not already allocated. */ - buf = *subbuf; - if (buf == NULL) { - buf = (struct mip6_subbuf *)MALLOC(sizeof(struct mip6_subbuf), - M_TEMP, M_WAITOK); - if (buf == NULL) - return 1; - bzero(buf, sizeof(struct mip6_subbuf)); - } - - /* Find offset in the current buffer */ - padn = IP6OPT_PADN; - pad1 = IP6OPT_PAD1; - - switch (*subopt) { - case IP6SUBOPT_UNIQUEID: - /* Make sure that the length is OK */ - uid = (struct mip6_subopt_id *)subopt; - if (uid->len != IP6OPT_UIDLEN) - return 1; - - /* Compensate for the alignment requirement. */ - rest = buf->len % 2; - if (rest == 1) { - bcopy(&pad1, (caddr_t)buf->buffer + buf->len, 1); - buf->len += 1; - } - - /* Copy the sub-option to the buffer. */ - bcopy(&uid->type, (caddr_t)buf->buffer + buf->len, - sizeof(uid->type)); - buf->len += sizeof(uid->type); - - bcopy(&uid->len, (caddr_t)buf->buffer + buf->len, - sizeof(uid->len)); - buf->len += sizeof(uid->len); - - tmp16 = htons(uid->id); - bcopy(&tmp16, (caddr_t)buf->buffer + buf->len, sizeof(tmp16)); - buf->len += sizeof(tmp16); - break; - case IP6SUBOPT_HALIST: - /* Make sure that the length is OK */ - hal = (struct mip6_subopt_hal *)subopt; - if (hal->len % IP6OPT_HALISTLEN) - return 1; - - /* Compensate for the alignment requirement. */ - rest = buf->len % 8; - if (rest > 3) { - padlen = rest - 4; - bcopy(&padn, (caddr_t)buf->buffer + buf->len, 1); - buf->len += 1; - bcopy(&padlen, (caddr_t)buf->buffer + buf->len, 1); - buf->len += 1; - bzero((caddr_t)buf->buffer + buf->len, padlen); - buf->len += padlen; - } else if (rest == 3) { - bcopy(&pad1, (caddr_t)buf->buffer + buf->len, 1); - buf->len += 1; - } else if (rest <= 1) { - padlen = rest + 4; - bcopy(&padn, (caddr_t)buf->buffer + buf->len, 1); - buf->len += 1; - bcopy(&padlen, (caddr_t)buf->buffer + buf->len, 1); - buf->len += 1; - bzero((caddr_t)buf->buffer + buf->len, padlen); - buf->len += padlen; - } - - /* Copy the sub-option to the buffer. */ - bcopy(&hal->type, (caddr_t)buf->buffer + buf->len, - sizeof(hal->type)); - buf->len += sizeof(hal->type); - - bcopy(&hal->len, (caddr_t)buf->buffer + buf->len, - sizeof(hal->len)); - buf->len += sizeof(hal->len); - - /* Loop over the addresses */ - no = hal->len / IP6OPT_HALISTLEN; - for (ii = 0; ii < no; ii++) { - bcopy(&hal->halist[ii], (caddr_t)buf->buffer + buf->len, - sizeof(hal->halist)); - buf->len += sizeof(hal->halist); - } - break; - case IP6SUBOPT_ALTCOA: - /* Make sure that the length is OK */ - altcoa = (struct mip6_subopt_coa *)subopt; - if (altcoa->len % IP6OPT_COALEN) - return 1; - - /* Compensate for the alignment requirement. */ - rest = buf->len % 8; - if (rest > 3) { - padlen = rest - 4; - bcopy(&padn, (caddr_t)buf->buffer + buf->len, 1); - buf->len += 1; - bcopy(&padlen, (caddr_t)buf->buffer + buf->len, 1); - buf->len += 1; - bzero((caddr_t)buf->buffer + buf->len, padlen); - buf->len += padlen; - } else if (rest == 3) { - bcopy(&pad1, (caddr_t)buf->buffer + buf->len, 1); - buf->len += 1; - } else if (rest <= 1) { - padlen = rest + 4; - bcopy(&padn, (caddr_t)buf->buffer + buf->len, 1); - buf->len += 1; - bcopy(&padlen, (caddr_t)buf->buffer + buf->len, 1); - buf->len += 1; - bzero((caddr_t)buf->buffer + buf->len, padlen); - buf->len += padlen; - } - - /* Copy the sub-option to the buffer. */ - bcopy(&altcoa->type, (caddr_t)buf->buffer + buf->len, - sizeof(altcoa->type)); - buf->len += sizeof(altcoa->type); - - bcopy(&altcoa->len, (caddr_t)buf->buffer + buf->len, - sizeof(altcoa->len)); - buf->len += sizeof(altcoa->len); - - bcopy(&altcoa->coa, (caddr_t)buf->buffer + buf->len, - sizeof(altcoa->coa)); - buf->len += sizeof(altcoa->coa); - break; - default: - } - *subbuf = buf; - return 0; -} diff --git a/bsd/netinet6/mip6_md.c b/bsd/netinet6/mip6_md.c deleted file mode 100644 index 16b670388..000000000 --- a/bsd/netinet6/mip6_md.c +++ /dev/null @@ -1,1293 +0,0 @@ -/* $KAME: mip6_md.c,v 1.14 2000/03/25 07:23:53 sumikawa Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, 1998, 1999 and 2000 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * Copyright (c) 1999 and 2000 Ericsson Radio Systems AB - * All rights reserved. - * - * Author: Mattias Pettersson - * - */ - -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#endif - -/* - * Mobile IPv6 Movement Detection for Mobile Nodes - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) -#include -#endif -#include -#include - -#include - -struct nd_prefix *mip6_home_prefix; -struct nd_prefix *mip6_primary_prefix; -struct in6_addr mip6_primary_defrtr; -int mip6_md_state = MIP6_MD_UNDEFINED; -/* - * Mobile IPv6 Home Address route state for the Mobile Node. - * route_state NET == MD_HOME == network route. - * route_state HOST == MD_FOREIGN|UNDEFINED == host route. - */ -int mip6_route_state = MIP6_ROUTE_NET; /* According to MD_UNDEFINED state. */ -int mip6_max_lost_advints = MIP6_MAX_LOST_ADVINTS; -int mip6_nd6_delay = 0; -int mip6_nd6_umaxtries = 0; - - -/* - ****************************************************************************** - * Function: mip6_tell_em - * Description: Print state change and tell event-state machine. - * Ret value: - - ****************************************************************************** - */ -static void -mip6_tell_em(int state, - struct nd_prefix *hp, - struct nd_prefix *pp, - struct nd_defrouter *dr) -{ -#if MIP6_DEBUG - mip6_debug("\nNew state: "); - switch (state) { - case MIP6_MD_HOME: - mip6_debug("HOME!\n"); - break; - case MIP6_MD_FOREIGN: - mip6_debug("FOREIGN!\n"); - break; - case MIP6_MD_UNDEFINED: - mip6_debug("UNDEFINED!\n"); - break; - } - mip6_debug("Home Prefix = %s\n", hp ? ip6_sprintf( - &hp->ndpr_prefix.sin6_addr) : "NULL"); - mip6_debug("Primary Prefix = %s\n", pp ? ip6_sprintf( - &pp->ndpr_prefix.sin6_addr) : "NULL"); - mip6_debug("Default Router = %s\n", dr ? ip6_sprintf( - &dr->rtaddr) : "NULL"); -#endif - mip6_new_defrtr(state, hp, pp, dr); -} - - -/* - ****************************************************************************** - * Function: mip6_md_init - * Description: Scan through the Event-State Machine List. - * Create a Home Prefix and a Home Address for the Mobile Node - * and add it to the prefix list (or just update it if the prefix - * is already existing). Detect which initial Movement Detection - * state we are in (HOME, FOREIGN or UNDEFINED) and tell the - * event-state machine. - * Ret value: - - ****************************************************************************** - */ -void -mip6_md_init() -{ - struct nd_prefix *pr, *existing_pr = NULL; - struct nd_defrouter *dr; - struct in6_ifaddr *ia; - struct mip6_esm *esp; /* Entry in the Event State machine list */ - int i, s, error; - - for (esp = mip6_esmq; esp; esp = esp->next) { - - /* - * Add the home prefix statically to the prefix list. - * Code taken from prelist_update(), prelist_add() and - * in6_ifadd(). - */ - pr = (struct nd_prefix *)MALLOC(sizeof(*pr), M_TEMP, M_WAITOK); - if (pr == NULL) { - log(LOG_ERR, "mip6_md_init: no mem for home prefix\n"); - } else { - bzero(pr, sizeof(*pr)); - - pr->ndpr_ifp = esp->ifp; - pr->ndpr_plen = esp->prefix_len; - - pr->ndpr_prefix.sin6_family = AF_INET6; - pr->ndpr_prefix.sin6_len = sizeof(pr->ndpr_prefix); - pr->ndpr_prefix.sin6_addr = esp->home_addr; - in6_prefixlen2mask(&pr->ndpr_mask, pr->ndpr_plen); - - /* make prefix in the canonical form */ - for (i = 0; i < 4; i++) - pr->ndpr_prefix.sin6_addr.s6_addr32[i] &= - pr->ndpr_mask.s6_addr32[i]; - - /* TODO: link into interface prefix list */ - - /* Default settings for unadvertised home prefix */ - pr->ndpr_raf_onlink = 0; - pr->ndpr_raf_auto = 0; - - /* - * If home prefix already exists in prefix list, use that - * entry instead. - */ - if ( (existing_pr = prefix_lookup(pr)) ) { - _FREE(pr, M_TEMP); - pr = existing_pr; - } - - /* Update (or set) certain fields in the home prefix */ - pr->ndpr_vltime = ND6_INFINITE_LIFETIME; - pr->ndpr_pltime = ND6_INFINITE_LIFETIME; - - if (in6_init_prefix_ltimes(pr)) { - log(LOG_ERR, "mip6_md_init: bad lifetimes\n"); - goto failure; - } - - - s = splnet(); /* Must be before goto statement */ - - if (existing_pr != NULL) { -#if MIP6_DEBUG - mip6_debug("mip6_md_init: Home prefix already exists, " - "no need to create new prefix.\n"); -#endif - goto skip_initialization; - } - - /* New prefix, fix all initialization. */ - - pr->ndpr_statef_onlink = 0; /* Should be 0 since there - are no adv rtrs for - this pfx yet */ - LIST_INIT(&pr->ndpr_advrtrs); - - skip_initialization: - - /* If an autoconfigured address exists for pr, delete it */ - if (existing_pr != NULL) { - if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) { - ia = in6ifa_ifpwithaddr(pr->ndpr_ifp, - &pr->ndpr_addr); - if (ia) { - error = mip6_delete_ifaddr( - &ia->ia_addr.sin6_addr, - pr->ndpr_ifp); - if (error) - printf("%s: address assignment" - " error " - "(errno = %d).\n", - __FUNCTION__, error); - } - } - } - - pr->ndpr_addr = esp->home_addr; - - if (existing_pr == NULL) { - /* link ndpr_entry to nd_prefix list */ - LIST_INSERT_HEAD(&nd_prefix, pr, ndpr_entry); - } - - splx(s); - } - if (esp != mip6_esmq) { -#if MIP6_DEBUG - mip6_debug("%s: Only supporting one home address in this " - "version.\n", __FUNCTION__); -#endif - } - mip6_home_prefix = pr; - - dr = TAILQ_FIRST(&nd_defrouter); -/* XXXYYY Add check for probably reachable router here as well. Mattias */ - if (pr->ndpr_advrtrs.lh_first && dr && - pfxrtr_lookup(pr, dr)) { - /* If we have home pfxrtrs and defrtr is one of these, then - we're home. */ - mip6_md_state = MIP6_MD_HOME; - /* XXX BUG ALERT: missing curly brace? */ - if ((error = mip6_add_ifaddr(&pr->ndpr_addr, pr->ndpr_ifp, 64, - IN6_IFF_NODAD)) != 0) - printf("%s: address assignment error (errno = %d).\n", - __FUNCTION__, error); - mip6_route_state = MIP6_ROUTE_NET; - mip6_primary_prefix = mip6_home_prefix; - mip6_primary_defrtr = dr->rtaddr; - - mip6_tell_em(MIP6_MD_HOME, mip6_home_prefix, NULL, dr); - } - else { - if (dr) { - mip6_md_state = MIP6_MD_FOREIGN; - if ((error = mip6_add_ifaddr( - &pr->ndpr_addr, pr->ndpr_ifp, 128, - IN6_IFF_NODAD)) != 0) - printf("%s: address assignment error " - "(errno = %d).\n", - __FUNCTION__, error); - mip6_route_state = MIP6_ROUTE_HOST; - - for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { - if ((pfxrtr_lookup(pr, dr) != NULL) && - !IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)&& - !IN6_IS_ADDR_MULTICAST(&pr->ndpr_addr) && - !IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_addr)) { - break; - } - } - if (pr) { - mip6_primary_prefix = pr; - mip6_primary_defrtr = dr->rtaddr; - mip6_tell_em(MIP6_MD_FOREIGN, mip6_home_prefix, - pr, dr); - } - else { -#if MIP6_DEBUG - mip6_debug("%s: At FOREIGN, but no primary " - "prefix found!\n", __FUNCTION__); -#endif - goto undefined; - } - } - else { - undefined: - mip6_md_state = MIP6_MD_UNDEFINED; - if ((error = mip6_add_ifaddr(&pr->ndpr_addr, - pr->ndpr_ifp, 64, - IN6_IFF_NODAD)) != 0) - printf("%s: address assignment error " - "(errno = %d).\n", __FUNCTION__, error); - mip6_route_state = MIP6_ROUTE_NET; - mip6_primary_defrtr = in6addr_any; - mip6_primary_prefix = NULL; - - mip6_tell_em(MIP6_MD_UNDEFINED, mip6_home_prefix, - NULL, NULL); - } - } - failure: - } -} - - -/* - ****************************************************************************** - * Function: mip6_select_defrtr - * Description: Usually called as an extension to defrtrlist_del() when the - * previous primary default router times out. Tries to select a - * new default router that announces the Home Prefix if available. - * Manages the Movement Detection state transitions and - * reconfigures the Home Address with host or network route. - * Finally informs the event-state machine about any transitions - * and new default routers. - * Ret value: - - ****************************************************************************** - */ -void -mip6_select_defrtr() -{ - struct nd_prefix *pr = NULL/*, *prev_primary_prefix*/; - struct nd_defrouter *dr, anydr; - struct nd_pfxrouter *pfxrtr; - struct rtentry *rt = NULL; - struct llinfo_nd6 *ln = NULL; - int s = splnet(), error, state; - - pr = mip6_primary_prefix; - /* Only for sanity check */ - dr = mip6_primary_prefix ? - defrouter_lookup(&mip6_primary_defrtr, - mip6_primary_prefix->ndpr_ifp) : NULL; - state = mip6_md_state; - -#if MIP6_DEBUG - mip6_debug("\n"); -#endif -#if MIP6_DEBUG - mip6_debug("%s: previous primary dr = %s.\n", __FUNCTION__, - ip6_sprintf(&mip6_primary_defrtr)); - mip6_debug("%s: dr = %s.\n", __FUNCTION__, - dr ? ip6_sprintf(&dr->rtaddr) : "NULL"); -#endif - - if ( (mip6_md_state == MIP6_MD_HOME) || - (mip6_md_state == MIP6_MD_UNDEFINED) ) { - if ((pr = mip6_home_prefix) == NULL){ - log(LOG_ERR, "mip6_select_defrtr: no home prefix\n"); - splx(s); - return; - } - - if ((pfxrtr = find_pfxlist_reachable_router(pr)) != NULL) { -#if MIP6_DEBUG - mip6_debug("%s: there are (reachable) pfxrtrs at " - "home.\n", __FUNCTION__); -#endif - if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr) && - !(IN6_IS_ADDR_MULTICAST(&pr->ndpr_addr) || - IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_addr))) { - - /* Pick first reachable pfxrtr. */ - state = MIP6_MD_HOME; - - dr = pfxrtr->router; - - /* Place dr first since its prim. */ - TAILQ_REMOVE(&nd_defrouter, dr, dr_entry); - TAILQ_INSERT_HEAD(&nd_defrouter, dr, dr_entry); - -#if MIP6_DEBUG - mip6_debug("%s: picking %s as default router " - "on home subnet.\n", - __FUNCTION__, - ip6_sprintf(&(dr->rtaddr))); -#endif - goto found; - } - } - - if (pr->ndpr_advrtrs.lh_first == NULL) { -#if MIP6_DEBUG - mip6_debug("%s: there are no pfxrtrs at home, trying " - "non-home instead.\n", __FUNCTION__); -#endif - } - - /* - * No home prefix defrtr found, just drop through and pick - * one by the ordinary procedure below. - */ -#if MIP6_DEBUG - mip6_debug("%s: no home prefix router found.\n", __FUNCTION__); -#endif - } - - /* - * Go through the Default Router List in search for a (probably) - * reachable router that advertises a prefix and with an associated - * Care-of Address. This is a merge from defrouter_select(). - */ - if (TAILQ_FIRST(&nd_defrouter)) { - for (dr = TAILQ_FIRST(&nd_defrouter); dr; - dr = TAILQ_NEXT(dr, dr_entry)) { - - if ((rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) && - (ln = (struct llinfo_nd6 *)rt->rt_llinfo) && - ND6_IS_LLINFO_PROBREACH(ln)) { - - /* - * Find a Care-of Address from a prefix - * announced by this router. - */ - for (pr = nd_prefix.lh_first; pr; - pr = pr->ndpr_next) { - if ((pfxrtr_lookup(pr, dr) != NULL) && - !IN6_IS_ADDR_UNSPECIFIED( - &pr->ndpr_addr) && - !IN6_IS_ADDR_MULTICAST( - &pr->ndpr_addr) && - !IN6_IS_ADDR_LINKLOCAL( - &pr->ndpr_addr)) { - state = MIP6_MD_FOREIGN; - -#if MIP6_DEBUG - mip6_debug("%s: new probably reachable defrtr %s on foreign subnet selected.\n", __FUNCTION__, ip6_sprintf(&dr->rtaddr)); -#endif - - /* - * Place dr first since - * its prim. - */ - TAILQ_REMOVE(&nd_defrouter, - dr, dr_entry); - TAILQ_INSERT_HEAD( - &nd_defrouter, - dr, dr_entry); - - goto found; - } - } - } - } - - /* - * No (probably) reachable router found that matched our requirements. - * Go through the Default Router List again in search for any - * router that advertises a prefix and with an associated - * Care-of Address. This is a merge from defrouter_select(). - */ - for(dr = TAILQ_FIRST(&nd_defrouter); dr; dr = TAILQ_NEXT(dr, dr_entry)){ - /* - * Find a Care-of Address from a prefix announced by - * this router. - */ - for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { - if ((pfxrtr_lookup(pr, dr) != NULL) && - !IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)&& - !IN6_IS_ADDR_MULTICAST(&pr->ndpr_addr) && - !IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_addr)) { - state = MIP6_MD_FOREIGN; - -#if MIP6_DEBUG - mip6_debug("%s: new (unreachable?) " - "defrtr %s on foreign subnet " - "selected.\n", __FUNCTION__, - ip6_sprintf(&dr->rtaddr)); -#endif - - /* Place dr first since its prim. */ - TAILQ_REMOVE(&nd_defrouter, dr, - dr_entry); - TAILQ_INSERT_HEAD(&nd_defrouter, dr, - dr_entry); - goto found; - } - } - } - } - - /* - * No new defrtr or no with an associated Care-of Address found - * -> State = undefined - */ - pr = NULL; - dr = NULL; - state = MIP6_MD_UNDEFINED; -#if MIP6_DEBUG - mip6_debug("%s: no new good defrtr found.\n", __FUNCTION__); -#endif - - found: - /* XXXYYY Hope this merge is correct now... Fingers crossed. Mattias */ -#if MIP6_DEBUG - mip6_debug("%s: found: dr = %s.\n", __FUNCTION__, dr ? ip6_sprintf(&dr->rtaddr) : "NULL"); -#endif - if ((dr = TAILQ_FIRST(&nd_defrouter)) != NULL) { -#if MIP6_DEBUG - mip6_debug("%s: TAILQ: dr = %s.\n", __FUNCTION__, dr ? ip6_sprintf(&dr->rtaddr) : "NULL"); -#endif - /* - * De-install the previous default gateway and install - * a new one. - * Note that if there is no reachable router in the list, - * the head entry will be used anyway. - * XXX: do we have to check the current routing table entry? - */ - bzero(&anydr, sizeof(anydr)); - defrouter_delreq(&anydr, 0); - defrouter_addreq(dr); - } - else { - /* - * The Default Router List is empty, so install the default - * route to an inteface. - * XXX: The specification does not say this mechanism should - * be restricted to hosts, but this would be not useful - * (even harmful) for routers. - */ - if (!ip6_forwarding) { - /* - * De-install the current default route - * in advance. - */ - bzero(&anydr, sizeof(anydr)); - defrouter_delreq(&anydr, 0); - if (nd6_defifp) { - /* - * Install a route to the default interface - * as default route. - */ - defrouter_addifreq(nd6_defifp); - } - else /* noisy log? */ - log(LOG_INFO, "defrouter_select: " - "there's no default router and no default" - " interface\n"); - } - } - - - /* - * If we grab a (unreachable) defrouter that actually is a home - * prefix router, we should consider ourself at home rather than - * default foreign. - */ - if (dr) { - struct nd_pfxrouter *pfxrtr; - - pfxrtr = pfxrtr_lookup(mip6_home_prefix, dr); - if (pfxrtr && dr == pfxrtr->router) { -#if MIP6_DEBUG - mip6_debug("%s: dr = %s is obviously a home pfxrtr.\n", __FUNCTION__, dr ? ip6_sprintf(&dr->rtaddr) : "NULL"); -#endif - state = MIP6_MD_HOME; - pr = mip6_home_prefix; - } - } - - /* - * First case: same router as last time. - * Second case: coming from UNDEFINED, we might have had a router, but - * we didn't have a care-of address. - */ - if (IN6_ARE_ADDR_EQUAL(&mip6_primary_defrtr, - (dr ? &dr->rtaddr : &in6addr_any)) && - !(dr && mip6_primary_prefix == NULL)) { -#if MIP6_DEBUG - mip6_debug("%s: Warning: Primary default router hasn't " - "changed! No action taken.\n", __FUNCTION__); -#endif - return; - } - - /* - * Switch between network and host route for the Home Address - * in the following cases: - * - * md_state route_state - * - * HOME -> FOREIGN NET -> HOST - * UNDEFINED -> FOREIGN NET -> HOST - * FOREIGN -> HOME HOST -> NET - * FOREIGN -> UNDEFINED HOST -> NET - */ - - if ((state == MIP6_MD_HOME || state == MIP6_MD_UNDEFINED) - && mip6_route_state == MIP6_ROUTE_HOST) { - error = mip6_add_ifaddr(&mip6_home_prefix->ndpr_addr, - mip6_home_prefix->ndpr_ifp, 64, - IN6_IFF_NODAD); - if (error) - printf("%s: address assignment error (errno = %d).\n", - __FUNCTION__, error); - mip6_route_state = MIP6_ROUTE_NET; - } - else if (state == MIP6_MD_FOREIGN && - mip6_route_state == MIP6_ROUTE_NET) { - error = mip6_add_ifaddr(&mip6_home_prefix->ndpr_addr, - mip6_home_prefix->ndpr_ifp, 128, - IN6_IFF_NODAD); - if (error) - printf("%s: address assignment error (errno = %d).\n", - __FUNCTION__, error); - mip6_route_state = MIP6_ROUTE_HOST; - } - - /* - * If the Mobile Node has changed its primary prefix (probably due to - * a move to a different subnet), clear the Neighbor Cache from entries - * cloned from the previous primary prefix. This does not happen when - * we keep the same prefix but change default router. - */ -#if MIP6_DEBUG - mip6_debug("mip6_primary_prefix = %s\n", mip6_primary_prefix ? ip6_sprintf(&mip6_primary_prefix->ndpr_prefix.sin6_addr) : "NULL"); - mip6_debug("pr = %s\n", pr ? ip6_sprintf(&pr->ndpr_prefix.sin6_addr) : "NULL"); -#endif - if (mip6_primary_prefix && (pr != mip6_primary_prefix)) { - register struct llinfo_nd6 *ln; - - /* Taken from nd6_timer() */ - ln = llinfo_nd6.ln_next; - /* XXX BSD/OS separates this code -- itojun */ - while (ln && ln != &llinfo_nd6) { - struct rtentry *rt; - struct ifnet *ifp; - struct sockaddr_in6 *dst; - struct llinfo_nd6 *next = ln->ln_next; - - if ((rt = ln->ln_rt) == NULL) { - ln = next; - continue; - } - if ((ifp = rt->rt_ifp) == NULL) { - ln = next; - continue; - } - dst = (struct sockaddr_in6 *)rt_key(rt); - /* sanity check */ - if (!rt) - panic("rt=0 in %s(ln=%p)\n", __FUNCTION__, ln); - if (!dst) - panic("dst=0 in %s(ln=%p)\n", __FUNCTION__, ln); - - /* Skip if the address belongs to us */ - if (ln->ln_expire == 0) { - ln = next; - continue; - } - -#if MIP6_DEBUG - mip6_debug("Checking neighbor %s\n", dst ? ip6_sprintf(&dst->sin6_addr) : "NULL"); -#endif - if (in6_are_prefix_equal(&dst->sin6_addr, - &mip6_primary_prefix-> - ndpr_prefix.sin6_addr, - mip6_primary_prefix-> - ndpr_plen)) { - - /* Fake an INCOMPLETE neighbor that we're giving up */ - struct mbuf *m = ln->ln_hold; - if (m) { - m_freem(m); - } - ln->ln_hold = NULL; - -#if MIP6_DEBUG - mip6_debug("Deleting Neighbor %s.\n", - ip6_sprintf(&(satosin6( - rt_key(rt))->sin6_addr))); -#endif - -#if IPSEC -#ifndef __OpenBSD__ - key_sa_routechange(rt_key(rt)); -#endif -#endif - -#if MIP6_DEBUG - mip6_debug("Ref count = %d, now pfctlinput\n", - rt->rt_refcnt); -#endif - - /* New era */ - pfctlinput(PRC_REDIRECT_HOST, rt_key(rt)); - -#if 0 -#if MIP6_DEBUG - mip6_debug("Ref count = %d, now rt_mip6msg\n", - rt->rt_refcnt); -#endif - - rt_mip6msg(RTM_DELETE, ifp, rt); /* Useless? */ -#endif /* 0 */ -#if MIP6_DEBUG - mip6_debug("Ref count = %d, now RTM_DELETE\n", - rt->rt_refcnt); -#endif - nd6_free(rt); - } - ln = next; - /* - * XXX Also remove the link-local addresses which - * aren't ours? - */ - } - - ln = llinfo_nd6.ln_next; - while (ln && ln != &llinfo_nd6) { - struct rtentry *rt; - struct ifnet *ifp; - struct sockaddr_dl *sdl; - struct sockaddr_in6 *dst; - struct llinfo_nd6 *next = ln->ln_next; - - if ((rt = ln->ln_rt) == NULL) { - ln = next; - continue; - } - if ((ifp = rt->rt_ifp) == NULL) { - ln = next; - continue; - } - dst = (struct sockaddr_in6 *)rt_key(rt); - /* sanity check */ - if (!rt) - panic("rt=0 in %s(ln=%p)\n", __FUNCTION__, ln); - if (!dst) - panic("dst=0 in %s(ln=%p)\n", __FUNCTION__, ln); - - /* Skip if the address belongs to us */ - if (ln->ln_expire == 0) { - ln = next; - continue; - } - -#if MIP6_DEBUG - mip6_debug("Checking neighbor %s round 2\n", dst ? ip6_sprintf(&dst->sin6_addr) : "NULL"); -#endif - if (in6_are_prefix_equal(&dst->sin6_addr, - &mip6_primary_prefix-> - ndpr_prefix.sin6_addr, - mip6_primary_prefix-> - ndpr_plen)) { - -#if MIP6_DEBUG - mip6_debug("Deleting Neighbor %s round 2.\n", - ip6_sprintf(&(satosin6( - rt_key(rt))->sin6_addr))); -#endif - -#if MIP6_DEBUG - mip6_debug("Ref count = %d, now RTM_DELETE\n", - rt->rt_refcnt); -#endif - if (rt && rt->rt_gateway && - rt->rt_gateway->sa_family == AF_LINK) { - sdl = (struct sockaddr_dl *)rt-> - rt_gateway; - rtrequest(RTM_DELETE, rt_key(rt), - (struct sockaddr *)0, - rt_mask(rt), 0, - (struct rtentry **)0); - } - } - ln = next; - /* - * XXX Also remove the link-local addresses which - * aren't ours? - */ - } - } - - /* - * Make decision permanent. - * Primary Default Router is already set above. - */ - mip6_md_state = state; - mip6_primary_prefix = pr; /* Other depend on this */ - /* - * Save rtaddr for next mip6_select_defrtr session. - */ - mip6_primary_defrtr = dr ? dr->rtaddr : in6addr_any; - - /* - * Assumptions made below: - * - dr is the chosen Default Router - * - pr is the new Primary Prefix if we're not home - */ - switch (mip6_md_state) { - case MIP6_MD_HOME: - mip6_tell_em(mip6_md_state, mip6_home_prefix, NULL, dr); - break; - - case MIP6_MD_FOREIGN: - mip6_tell_em(mip6_md_state, mip6_home_prefix, pr, dr); - break; - case MIP6_MD_UNDEFINED: - /* - * Note: we pass dr == NULL, but we might have a Default - * Router anyway, but with no prefix/Care-of Address - * associated. - */ - mip6_tell_em(mip6_md_state, mip6_home_prefix, NULL, NULL); - break; - } - splx(s); - return; -} - - -/* - ****************************************************************************** - * Function: mip6_prelist_update(pr, dr) - * Description: A hook to ND's prelist_update(). Checks if the Home Prefix - * was announced and in that case tries to force the Mobile Node - * to select that default router. If the Mobile Node was in - * UNDEFINED state we want to select that router immediately, no - * matter what the prefix was. - * Ret value: - - ****************************************************************************** - */ -void -mip6_prelist_update(pr, dr) - struct nd_prefix *pr; - struct nd_defrouter *dr; -{ - if (dr == NULL) { - return; - } - if (pr == mip6_home_prefix) { - /* It was the Home Prefix that was advertised. */ - - if (mip6_md_state != MIP6_MD_HOME) { - /* - * We're not home but here's a router advertising - * our home prefix => make it primary defrtr and - * we're home! - */ -#if MIP6_DEBUG - mip6_debug("%s: returning home.\n", __FUNCTION__); -#endif - mip6_md_state = MIP6_MD_HOME; - - /* State must be home before call. */ - if (TAILQ_FIRST(&nd_defrouter) != NULL) { - defrouter_select(); - } - else { -#if MIP6_DEBUG - mip6_debug("%s: Undef -> Home: no previous " - "router available " - "at this stage.\n", __FUNCTION__); -#endif - /* XXXYYY or use defrouter_select()? */ - mip6_select_defrtr(); - } - } - } - else if (mip6_md_state == MIP6_MD_UNDEFINED) { - /* - * Take care of transitions from UNDEFINED to FOREIGN, when the - * prefix is already known. - */ - if (TAILQ_FIRST(&nd_defrouter) != NULL) { - defrouter_select(); - } - else { -#if MIP6_DEBUG - mip6_debug("%s: Strange, no default router available" - "at this stage.\n", __FUNCTION__); -#endif - /* XXXYYY or use defrouter_select()? */ - mip6_select_defrtr(); - } - } -} - - -/* - ****************************************************************************** - * Function: mip6_eager_md() - * Description: If eager Movement Detection is chosen, trim parameters to a - * really fast hand-off. The disadvantage is that the detection - * becomes very exposed to go into state UNDEFINED if one single - * packet is lost. - * Ret value: - - ****************************************************************************** - */ -void -mip6_eager_md(int enable) -{ - mip6_config.eager_md = enable; - if (enable) { - mip6_max_lost_advints = 1; /* Aggressive values */ - if (!mip6_nd6_delay) { - mip6_nd6_delay = nd6_delay; /* Store */ - mip6_nd6_umaxtries = nd6_umaxtries; /* Store */ - } - nd6_delay = 1; /* Aggressive values */ - nd6_umaxtries = 1; - } - else { - mip6_max_lost_advints = MIP6_MAX_LOST_ADVINTS; - if (mip6_nd6_delay) { - nd6_delay = mip6_nd6_delay; /* Restore */ - nd6_umaxtries = mip6_nd6_umaxtries; /* Restore */ - mip6_nd6_delay = 0; - mip6_nd6_umaxtries = 0; - } - } -} - - -/* - ****************************************************************************** - * Function: mip6_expired_defrouter() - * Description: If the field advint_expire (which is parallel to field - * expire for router lifetime) times out, allow a small number - * of lost Router Advertisements before doubting if this - * particular default router is still reachable. - * Ret value: - - ****************************************************************************** - */ -void -mip6_expired_defrouter(struct nd_defrouter *dr) -{ -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__) - long time_second = time.tv_sec; -#endif - - if (!dr) - return; - - if (dr->advint_expire && dr->advint_expire < time_second) { - if (++(dr->advints_lost) < mip6_max_lost_advints) { - /* advints_lost starts at 0. max = 1 (or more). */ - dr->advint_expire = time_second + dr->advint / 1000; -#if MIP6_DEBUG - mip6_debug("Adv Int #%d lost from router %s.\n", - dr->advints_lost, ip6_sprintf(&dr->rtaddr)); -#endif - } - else { - dr->advint_expire = 0; -#if MIP6_DEBUG - mip6_debug("Adv Int #%d lost from router %s.\n", - dr->advints_lost, ip6_sprintf(&dr->rtaddr)); -#endif - mip6_probe_defrouter(dr); - } - } -} - - -/* - ****************************************************************************** - * Function: mip6_probe_defrouter() - * Description: Probes a default router to see if it is still reachable. - * Ordinary Neigbor Discovery routines (NUD) takes care of the - * rest. Puts this router into ND state PROBE. - * Ret value: - - ****************************************************************************** - */ -void -mip6_probe_defrouter(struct nd_defrouter *dr) -{ -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__) - long time_second = time.tv_sec; -#endif - struct rtentry *rt; - struct llinfo_nd6 *ln; - - if (!dr) - return; - - if (!(rt = nd6_lookup(&dr->rtaddr, 0, NULL))) - return; - - if ((rt->rt_flags & RTF_GATEWAY) - || (rt->rt_flags & RTF_LLINFO) == 0 - || !rt->rt_llinfo - || !rt->rt_gateway - || rt->rt_gateway->sa_family != AF_LINK) { - /* This is not a host route. */ - return; - } - - ln = (struct llinfo_nd6 *)rt->rt_llinfo; - if ((ln->ln_state == ND6_LLINFO_INCOMPLETE) - || (ln->ln_state == ND6_LLINFO_PROBE) - || (ln->ln_state == ND6_LLINFO_WAITDELETE) - || (ln->ln_state == ND6_LLINFO_NOSTATE)) - return; - - /* Force state to PROBE, simulate DELAY->PROBE */ - ln->ln_asked = 1; - ln->ln_state = ND6_LLINFO_PROBE; - ln->ln_expire = time_second + - nd_ifinfo[rt->rt_ifp->if_index].retrans / 1000; - nd6_ns_output(rt->rt_ifp, &dr->rtaddr, &dr->rtaddr, - ln, 0); -#if MIP6_DEBUG - mip6_debug("Probing defrouter %s\n", ip6_sprintf(&dr->rtaddr)); -#endif -} - - -/* - ****************************************************************************** - * Function: mip6_probe_pfxrtrs() - * Description: If a new or previously detached prefix is heard, probe (NUD) - * all prefix routers on the current primary prefix in order to - * quickly detect if we have moved. This is only enabled in - * eager Movement Detection. - * Ret value: - - ****************************************************************************** - */ -void -mip6_probe_pfxrtrs() -{ - struct nd_pfxrouter *pfr; - if (!mip6_config.eager_md) - return; - - if (!mip6_primary_prefix) - return; - -#if MIP6_DEBUG - mip6_debug("New or detached prefix received, probe old routers:\n"); -#endif - for (pfr = mip6_primary_prefix->ndpr_advrtrs.lh_first; - pfr; pfr = pfr->pfr_next) { - mip6_probe_defrouter(pfr->router); - } -} - - -/* - ****************************************************************************** - * Function: mip6_store_advint(ai, dr) - * Description: If Advertisement Interval option is available in Router - * Advertisements, keep a timer for this expiry parallel to the - * ordinary Router lifetime timer. - * Ret value: - - ****************************************************************************** - */ -void -mip6_store_advint(struct nd_opt_advint *ai, - struct nd_defrouter *dr) -{ -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__) - long time_second = time.tv_sec; -#endif - - /* Check the advertisement interval option */ - if (ai->nd_opt_int_len != 1) { - log(LOG_INFO, "%s: bad Advertisement Interval Option " - "length\n", __FUNCTION__); - } - else if (dr) { - dr->advint = ntohl(ai->nd_opt_int_interval); /* milliseconds */ - - /* Sorry for delay between reception and this setting */ - dr->advint_expire = time_second + dr->advint / 1000; - dr->advints_lost = 0; - } -} - - -/* - ****************************************************************************** - * Function: mip6_delete_ifaddr - * Description: Similar to "ifconfig delete". - * Ret value: - - ****************************************************************************** - */ -int -mip6_delete_ifaddr(struct in6_addr *addr, - struct ifnet *ifp) -{ - struct in6_aliasreq *ifra, dummy; - struct sockaddr_in6 *sa6; - struct in6_ifaddr *ia, *oia; - int s; -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) || defined (__APPLE__) - struct ifaddr *ifa; -#endif - - bzero(&dummy, sizeof(dummy)); - ifra = &dummy; - - ifra->ifra_addr.sin6_len = sizeof(ifra->ifra_addr); - ifra->ifra_addr.sin6_family = AF_INET6; - ifra->ifra_addr.sin6_addr = *addr; - - sa6 = &ifra->ifra_addr; - - if (ifp == 0) - return(EOPNOTSUPP); - - s = splnet(); - - /* - * Code recycled from in6_control(). - */ - - /* - * Find address for this interface, if it exists. - */ - if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) { - if (sa6->sin6_addr.s6_addr16[1] == 0) { - /* interface ID is not embedded by the user */ - sa6->sin6_addr.s6_addr16[1] = - htons(ifp->if_index); - } - else if (sa6->sin6_addr.s6_addr16[1] != - htons(ifp->if_index)) { - splx(s); - return(EINVAL); /* ifid is contradict */ - } - if (sa6->sin6_scope_id) { - if (sa6->sin6_scope_id != - (u_int32_t)ifp->if_index) { - splx(s); - return(EINVAL); - } - sa6->sin6_scope_id = 0; /* XXX: good way? */ - } - } - ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr); - - /* - * for IPv4, we look for existing in6_ifaddr here to allow - * "ifconfig if0 delete" to remove first IPv4 address on the - * interface. For IPv6, as the spec allow multiple interface - * address from the day one, we consider "remove the first one" - * semantics to be not preferrable. - */ - if (ia == 0) { - splx(s); - return(EADDRNOTAVAIL); - } - /* FALLTHROUGH */ - - if (ia == 0) { - ia = (struct in6_ifaddr *) - MALLOC(sizeof(*ia), M_IFADDR, M_WAITOK); - if (ia == NULL) { - splx(s); - return (ENOBUFS); - } - bzero((caddr_t)ia, sizeof(*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_prefixmask; - - ia->ia_ifp = ifp; - if ((oia = in6_ifaddr) != NULL) { - for ( ; oia->ia_next; oia = oia->ia_next) - continue; - oia->ia_next = ia; - } else - in6_ifaddr = ia; - ia->ia_ifa.ifa_refcnt++; - -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) || defined (__APPLE__) - if ((ifa = ifp->if_addrlist) != NULL) { - for ( ; ifa->ifa_next; ifa = ifa->ifa_next) - continue; - ifa->ifa_next = &ia->ia_ifa; - } else - ifp->if_addrlist = &ia->ia_ifa; -#else - TAILQ_INSERT_TAIL(&ifp->if_addrlist, &ia->ia_ifa, - ifa_list); -#endif - ia->ia_ifa.ifa_refcnt++; - } - - in6_purgeaddr(&ia->ia_ifa, ifp); - - splx(s); - return(0); -} - - -#if 0 -/* - ****************************************************************************** - * Function: mip6_delete_ifaddr - * Description: Similar to "ifconfig delete". - * Ret value: - - ****************************************************************************** - */ -void -mip6_delete_ifaddr(struct in6_addr *addr, - struct ifnet *ifp) -{ - struct in6_aliasreq in6_addreq; - int s, error = 0; - - bzero(&in6_addreq, sizeof(in6_addreq)); - in6_addreq.ifra_addr.sin6_len = sizeof(in6_addreq.ifra_addr); - in6_addreq.ifra_addr.sin6_family = AF_INET6; - in6_addreq.ifra_addr.sin6_addr = *addr; - - s =splnet(); - error = in6_control(NULL, SIOCDIFADDR_IN6, (caddr_t)&in6_addreq, ifp -#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) && !define (__APPLE__) - , NULL -#endif - ); - splx(s); - if (error) { -#if MIP6_DEBUG - mip6_debug("%s: Attempt to delete addr %s failed.\n", __FUNCTION__, - ip6_sprintf(addr)); -#endif - } -} -#endif /* 0 */ - -struct nd_prefix * -mip6_get_home_prefix(void) -{ - return(mip6_home_prefix); -} - - -int -mip6_get_md_state(void) -{ - return(mip6_md_state); -} - - -/* - ****************************************************************************** - * Function: mip6_md_exit - * Description: Tidy up after the Mobile IPv6 Movement Detection. This is - * used when releasing the kernel module. The Home Prefix is - * deleted (even if we're home) since it's parameters might be - * way wrong. The Home Address is released as well. If at home, - * the prefix and address will be automagically configured as - * specified by ND. - * Ret value: - - ****************************************************************************** - */ -void -mip6_md_exit() -{ - struct nd_prefix *pr; - - /* - * XXXYYY Should use mip6_esmq when multiple Home Addresses are - * supported. - */ - pr = mip6_home_prefix; - if (pr && pr->ndpr_ifp && !IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) { - mip6_delete_ifaddr(&pr->ndpr_addr, pr->ndpr_ifp); - - prelist_remove(pr); - mip6_home_prefix = NULL; - -#if MIP6_DEBUG - mip6_debug("Home Prefix and Home Address removed.\n"); -#endif - } -} diff --git a/bsd/netinet6/mip6_mn.c b/bsd/netinet6/mip6_mn.c deleted file mode 100644 index dde4bf515..000000000 --- a/bsd/netinet6/mip6_mn.c +++ /dev/null @@ -1,3106 +0,0 @@ -/* $KAME: mip6_mn.c,v 1.11 2000/03/18 03:05:42 itojun Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, 1998, 1999 and 2000 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * Copyright (c) 1999 and 2000 Ericsson Radio Systems AB - * All rights reserved. - * - * Author: Conny Larsson - * - */ - -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#endif - -/* - * Mobile IPv6 Mobile Nodes - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Declaration of Global variables. */ -struct mip6_bul *mip6_bulq = NULL; /* First entry in Binding Update list */ -struct mip6_esm *mip6_esmq = NULL; /* List of event-state machines */ - -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -struct callout_handle mip6_timer_outqueue_handle; -struct callout_handle mip6_timer_bul_handle; -struct callout_handle mip6_timer_esm_handle; -#endif - - -/* - ############################################################################## - # - # INITIALIZATION AND EXIT FUNCTIONS - # These functions are executed when the MIPv6 code is activated and de- - # activated respectively. - # - ############################################################################## - */ - -/* - ****************************************************************************** - * Function: mip6_mn_init - * Description: Initialization of MIPv6 variables that must be initialized - * before the MN code is executed. - ****************************************************************************** - */ -void -mip6_mn_init(void) -{ -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - /* Initialize handle for timer functions. */ - callout_handle_init(&mip6_timer_outqueue_handle); - callout_handle_init(&mip6_timer_bul_handle); - callout_handle_init(&mip6_timer_esm_handle); -#endif - - printf("%s: MIP6 Mobile Node initialized\n", __FUNCTION__); -} - - - -/* - ****************************************************************************** - * Function: mip6_mn_exit - * Description: This function is called when the MN module is unloaded - * (relesed) from the kernel. - ****************************************************************************** - */ -void -mip6_mn_exit() -{ - struct mip6_output *outp, *outp_tmp; - struct mip6_bul *bulp; - struct mip6_esm *esp; - int s; - - /* Cancel outstanding timeout function calls. */ -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - untimeout(mip6_timer_outqueue, (void *)NULL, - mip6_timer_outqueue_handle); - untimeout(mip6_timer_bul, (void *)NULL, mip6_timer_bul_handle); - untimeout(mip6_timer_esm, (void *)NULL, mip6_timer_esm_handle); -#else - untimeout(mip6_timer_outqueue, (void *)NULL); - untimeout(mip6_timer_bul, (void *)NULL); - untimeout(mip6_timer_esm, (void *)NULL); -#endif - - /* Remove each entry in every queue. */ - s = splnet(); - for (outp = mip6_outq; outp;) { - outp_tmp = outp; - outp = outp->next; - if (outp_tmp->opt) - _FREE(outp_tmp->opt, M_TEMP); - if (outp_tmp->subopt) - _FREE(outp_tmp->subopt, M_TEMP); - _FREE(outp_tmp, M_TEMP); - } - mip6_outq = NULL; - - for (bulp = mip6_bulq; bulp;) - bulp = mip6_bul_delete(bulp); - mip6_bulq = NULL; - - for (esp = mip6_esmq; esp;) - esp = mip6_esm_delete(esp); - mip6_esmq = NULL; - splx(s); -} - - - -/* - ############################################################################## - # - # RECEIVING FUNCTIONS - # These functions receives the incoming IPv6 packet and further processing of - # the packet depends on the content in the packet. - # - ############################################################################## - */ - -/* - ****************************************************************************** - * Function: mip6_new_defrtr - * Description: Called from the move detection algorithm when it has decided - * to change default router, i.e the network that we were - * connected to has changed. - * Ret value: - - ****************************************************************************** - */ -void -mip6_new_defrtr(state, home_prefix, prim_prefix, def_router) -int state; /* State from move detection algorithm */ -struct nd_prefix *home_prefix; /* Prefix for Home Address */ -struct nd_prefix *prim_prefix; /* Prefix for primary care-of address */ -struct nd_defrouter *def_router; /* New default router being used */ -{ - struct in6_addr *home_addr; /* Home Address for Mobile Node */ - struct in6_addr *prim_addr; /* Primary Care-of Adress for MN */ - struct mip6_esm *esp; /* Home address entry */ - struct mip6_bul *bulp; /* Entry in the BU list */ - struct ifaddr *if_addr; /* Interface address */ - struct mip6_bu_data bu_data; /* Data used when a BU is created */ - struct in6_addr ll_all_addr; /* Link local all nodes address */ - struct in6_addr old_coa; - struct sockaddr_in6 sin6; - u_int32_t lifetime; /* Lifetime used in BU */ - u_long na_flags; /* Flags for NA message */ - - /* Check incoming parameters */ - if (home_prefix != NULL) - home_addr = &home_prefix->ndpr_addr; - else { - log(LOG_ERR, "%s: No home address configured\n", __FUNCTION__); - return; - } - - esp = mip6_esm_find(home_addr); - if (esp == NULL) { - log(LOG_ERR, - "%s: No event-state machine found\n", __FUNCTION__); - return; - } - - if (prim_prefix != NULL) - prim_addr = &prim_prefix->ndpr_addr; - else - prim_addr = NULL; - - /* Decide how the mobile node has moved. */ - if ((prim_prefix == NULL) && (state == MIP6_MD_UNDEFINED)) { - /* The Mobile Node is not connected to a network */ - esp->state = MIP6_STATE_UNDEF; - esp->coa = in6addr_any; - if (esp->ha_fn != NULL) { - _FREE(esp->ha_fn, M_TEMP); - esp->ha_fn = NULL; - } - if (mip6_tunnel(NULL, NULL, MIP6_TUNNEL_DEL, MIP6_NODE_MN, - (void *)esp)) - return; - } else if ((prim_prefix == NULL) && (state == MIP6_MD_HOME)) { - /* The Mobile Node is returning to the home link. Change the - parameters for the event-state machine. */ - esp->state = MIP6_STATE_DEREG; - old_coa = esp->coa; - esp->coa = esp->home_addr; - - /* Send a BU de-registration to the Home Agent. */ - bulp = mip6_bul_find(NULL, home_addr); - if (bulp == NULL) { - /* The event-state machine was in state undefined. */ - esp->state = MIP6_STATE_HOME; - - /* When returning home and no home registration exist - we can not assume the home address to be unique. - Perform DAD, but find the i/f address first. */ - bzero(&sin6, sizeof(struct sockaddr_in6)); - sin6.sin6_len = sizeof(struct sockaddr_in6); - sin6.sin6_family = AF_INET6; - sin6.sin6_addr = esp->home_addr; - - if_addr = ifa_ifwithaddr((struct sockaddr *)&sin6); - if (if_addr == NULL) - return; - - ((struct in6_ifaddr *)if_addr)->ia6_flags |= - IN6_IFF_TENTATIVE; - nd6_dad_start(if_addr, NULL); - return; - } - - bulp->lifetime = mip6_config.hr_lifetime; - bulp->refreshtime = bulp->lifetime; - bulp->coa = bulp->bind_addr; - - bu_data.prefix_len = esp->prefix_len; - bu_data.ack = 1; - - if (mip6_send_bu(bulp, &bu_data, NULL) != 0) - return; - - /* Send a BU to the previous foreign network. */ - if ( !IN6_IS_ADDR_UNSPECIFIED(&old_coa) && - (esp->ha_fn != NULL)) { - /* Find lifetime used for the BU to the def router. */ - lifetime = mip6_prefix_lifetime(&old_coa); - lifetime = min(lifetime, MIP6_BU_LIFETIME_DEFRTR); - - /* Create a tunnel used by the MN to receive - incoming tunneled packets. */ - if (mip6_tunnel(home_addr, &esp->ha_fn->addr, - MIP6_TUNNEL_ADD, - MIP6_NODE_MN, (void *)esp)) - return; - - mip6_send_bu2fn(&old_coa, esp->ha_fn, home_addr, - esp->ifp, lifetime); - _FREE(esp->ha_fn, M_TEMP); - esp->ha_fn = NULL; - } - - /* The Mobile Node must send a Neighbor Advertisement to inform - other nodes that it has arrived back to its home network. - The first NA will be sent in the create function, the - remaining NAs are sent by the timer function. */ - ll_all_addr = in6addr_linklocal_allnodes; - na_flags = ND_NA_FLAG_OVERRIDE; - mip6_na_create(home_addr, &ll_all_addr, home_addr, - esp->prefix_len, na_flags, 1); - } else if ((prim_prefix != NULL) && (state == MIP6_MD_FOREIGN)) { - /* If no Home Agent Address exist. Build an anycast address */ - if (IN6_IS_ADDR_UNSPECIFIED(&esp->ha_hn)) { - mip6_build_ha_anycast(&esp->ha_hn, &esp->home_addr, - esp->prefix_len); - if (IN6_IS_ADDR_UNSPECIFIED(&esp->ha_hn)) { - log(LOG_ERR, - "%s: Could not create anycast address " - "for Mobile Node, wrong prefix length\n", - __FUNCTION__); - return; - } - } - - if ((esp->state == MIP6_STATE_UNDEF) || - (esp->state == MIP6_STATE_HOME) || - (esp->state == MIP6_STATE_DEREG)) { - /* Home Network --> Foreign Network */ - /* Update state information for the home address. */ - esp->state = MIP6_STATE_NOTREG; - esp->coa = *prim_addr; - if (esp->ha_fn != NULL) { - _FREE(esp->ha_fn, M_TEMP); - esp->ha_fn = NULL; - } - - /* Find an existing or create a new BUL entry. */ - bulp = mip6_bul_find(NULL, &esp->home_addr); - if (bulp == NULL) { - bulp = mip6_bul_create(&esp->ha_hn, - &esp->home_addr, - prim_addr, - mip6_config.hr_lifetime, - 1); - if (bulp == NULL) - return; - } else { - bulp->coa = *prim_addr; - bulp->lifetime = mip6_config.hr_lifetime; - bulp->refreshtime = bulp->lifetime; - } - - /* Send a BU registration to the Home Agent. */ - bulp->coa = *prim_addr; - bulp->lifetime = mip6_config.hr_lifetime; - bulp->refreshtime = mip6_config.hr_lifetime; - - bu_data.prefix_len = esp->prefix_len; - bu_data.ack = 1; - - if (mip6_send_bu(bulp, &bu_data, NULL) != 0) - return; - } else if (esp->state == MIP6_STATE_REG || - esp->state == MIP6_STATE_REREG || - esp->state == MIP6_STATE_REGNEWCOA || - esp->state == MIP6_STATE_NOTREG) { - /* Foreign Network --> New Foreign Network */ - /* Update state information for the home address. */ - esp->state = MIP6_STATE_REGNEWCOA; - old_coa = esp->coa; - esp->coa = *prim_addr; - - /* Find an existing or create a new BUL entry. */ - bulp = mip6_bul_find(NULL, &esp->home_addr); - if (bulp == NULL) { - bulp = mip6_bul_create(&esp->ha_hn, - &esp->home_addr, - prim_addr, - mip6_config.hr_lifetime, - 1); - if (bulp == NULL) - return; - } - - /* Send a BU registration to the Home Agent. */ - bulp->coa = *prim_addr; - bulp->lifetime = mip6_config.hr_lifetime; - bulp->refreshtime = mip6_config.hr_lifetime; - bulp->no_of_sent_bu = 0; - - bu_data.prefix_len = esp->prefix_len; - bu_data.ack = 1; - - if (mip6_send_bu(bulp, &bu_data, NULL) != 0) - return; - - /* Send a BU registration to the previous default - router. */ - if ( !IN6_IS_ADDR_UNSPECIFIED(&old_coa) && - (esp->ha_fn)) { - /* Find lifetime to be used for the BU to - the def router. */ - lifetime = mip6_prefix_lifetime(&old_coa); - lifetime = min(lifetime, - MIP6_BU_LIFETIME_DEFRTR); - - /* Create a tunnel used by the MN to receive - incoming tunneled packets. */ - if (mip6_tunnel(prim_addr, &esp->ha_fn->addr, - MIP6_TUNNEL_MOVE, - MIP6_NODE_MN, (void *)esp)) - return; - - mip6_send_bu2fn(&old_coa, esp->ha_fn, - prim_addr, - esp->ifp, lifetime); - _FREE(esp->ha_fn, M_TEMP); - esp->ha_fn = NULL; - } - } - } else - esp->state = MIP6_STATE_UNDEF; -} - - - -/* - ############################################################################## - # - # CONTROL SIGNAL FUNCTIONS - # Functions for processing of incoming control signals (Binding Acknowledge- - # ment and Binding Request option) and sub-options (Home Agents list). - # - ############################################################################## - */ - -/* - ****************************************************************************** - * Function: mip6_rec_ba - * Description: Receive a BA option and evaluate the contents. - * Ret value: 0 Everything is OK. - * IPPROTO_DONE Error code used when something went wrong. - ****************************************************************************** - */ -int -mip6_rec_ba(m_in, off) -struct mbuf *m_in; /* Mbuf containing the entire IPv6 packet */ -int off; /* Offset from start of mbuf to start of dest option */ -{ - struct mip6_esm *esp; /* Home address entry */ - struct mip6_bul *bulp; /* Entry in the Binding Update list */ - struct in6_addr *from_src; /* Source address in received packet */ - struct in6_addr bind_addr; /* Binding addr in BU causing this BA */ - u_int8_t hr_flag; - int error; -#if MIP6_DEBUG - u_int8_t var; - int ii, offset; -#endif - - /* Make sure that the BA contains a valid AH or ESP header. */ -#if IPSEC -#ifndef __OpenBSD__ - if ( !((m_in->m_flags & M_AUTHIPHDR && m_in->m_flags & M_AUTHIPDGM) || - (m_in->m_flags & M_AUTHIPDGM && m_in->m_flags & M_DECRYPTED))) { - ip6stat.ip6s_badoptions++; - log(LOG_ERR, "%s: No AH or ESP included in BA\n", - __FUNCTION__); - return IPPROTO_DONE; - } -#endif -#endif - - /* Make sure that the length field in the BA is >= 11. */ - if (mip6_inp->ba_opt->len < IP6OPT_BALEN) { - ip6stat.ip6s_badoptions++; - log(LOG_ERR, "%s: Length field in BA < 11\n", __FUNCTION__); - return IPPROTO_DONE; - } - - /* Make sure that the sent BU sequence number == received BA sequence - number. But first, find the source address for the incoming packet - (it may include a home address option). */ - if (mip6_inp->optflag & MIP6_DSTOPT_HA) - from_src = &mip6_inp->ha_opt->home_addr; - else - from_src = &mip6_inp->ip6_src; - - bulp = mip6_bul_find(from_src, &mip6_inp->ip6_dst); - if (bulp == NULL) { - log(LOG_ERR, "%s: No Binding Update List entry found\n", - __FUNCTION__); - return IPPROTO_DONE; - } - - if (mip6_inp->ba_opt->seqno != bulp->seqno) { - ip6stat.ip6s_badoptions++; - log(LOG_ERR, - "%s: Received sequence number not equal to sent\n", - __FUNCTION__); - return IPPROTO_DONE; - } - -#if MIP6_DEBUG - mip6_debug("\nReceived Binding Acknowledgement\n"); - mip6_debug("IP Header Src: %s\n", ip6_sprintf(from_src)); - mip6_debug("IP Header Dst: %s\n", - ip6_sprintf(&mip6_inp->ip6_dst)); - mip6_debug("Type/Length/Status: %x / %u / %u\n", - mip6_inp->ba_opt->type, - mip6_inp->ba_opt->len, mip6_inp->ba_opt->status); - mip6_debug("Seq no/Life time: %u / %u\n", mip6_inp->ba_opt->seqno, - mip6_inp->ba_opt->lifetime); - mip6_debug("Refresh time: %u\n", mip6_inp->ba_opt->refresh); - - if (mip6_inp->ba_opt->len > IP6OPT_BALEN) { - offset = mip6_opt_offset(m_in, off, IP6OPT_BINDING_ACK); - if (offset == 0) - goto end_debug; - - mip6_debug("Sub-options present (TLV coded)\n"); - for (ii = IP6OPT_BALEN; ii < mip6_inp->ba_opt->len; ii++) { - if ((ii - IP6OPT_BALEN) % 16 == 0) - mip6_debug("\t0x:"); - if ((ii - IP6OPT_BALEN) % 4 == 0) - mip6_debug(" "); - m_copydata(m_in, offset + 2 + ii, sizeof(var), - (caddr_t)&var); - mip6_debug("%02x", var); - if ((ii - IP6OPT_BALEN + 1) % 16 == 0) - mip6_debug("\n"); - } - if ((ii - IP6OPT_BALEN) % 16) - mip6_debug("\n"); - } - end_debug: -#endif - - /* Check the status field in the BA. */ - if (mip6_inp->ba_opt->status >= 128) { - /* Remove the BUL entry and process the error - (order is important). */ - bind_addr = bulp->bind_addr; - hr_flag = bulp->hr_flag; - mip6_bul_delete(bulp); - - error = mip6_ba_error(from_src, &mip6_inp->ip6_dst, - &bind_addr, hr_flag); - return error; - } - - /* BA was accepted. Update corresponding entry in the BUL. - Stop retransmitting the BU. */ - bulp->no_of_sent_bu = 0; - bulp->update_rate = MIP6_MAX_UPDATE_RATE; - mip6_clear_retrans(bulp); - - /* If the BA was received from the Home Agent the state - of the event state machine shall be updated. */ - if (bulp->hr_flag) { - esp = mip6_esm_find(&bulp->bind_addr); - if (esp == NULL) { - log(LOG_ERR, "%s: No event-state machine found\n", - __FUNCTION__); - return IPPROTO_DONE; - } - - /* If Dynamic Home Agent Address Discovery, change - HA address and remove esp->dad entry. */ - if (esp->dad) { - esp->ha_hn = *from_src; - bulp->dst_addr = *from_src; - if (esp->dad->hal) - _FREE(esp->dad->hal, M_TEMP); - _FREE(esp->dad, M_TEMP); - esp->dad = NULL; - } - - /* Update the state for the home address. */ - if (esp->state == MIP6_STATE_DEREG) { - mip6_bul_delete(bulp); - - /* Remove the tunnel for the MN */ - mip6_tunnel(NULL, NULL, MIP6_TUNNEL_DEL, - MIP6_NODE_MN, (void *)esp); - - /* Send BU to each CN in the BUL to remove its - BC entry. */ - mip6_update_cns(&esp->home_addr, - &esp->home_addr, 0, 0); - mip6_outq_flush(); - - /* Don't set the state until BUs have been sent to - all CNs, otherwise the Home Address option will - not be added for the outgoing packet. */ - esp->state = MIP6_STATE_HOME; - esp->coa = in6addr_any; - } else { - esp->state = MIP6_STATE_REG; - - /* Create or modify a tunnel used by the MN to - receive incoming tunneled packets. */ - if (mip6_tunnel(&esp->coa, &esp->ha_hn, - MIP6_TUNNEL_MOVE, MIP6_NODE_MN, - (void *)esp)) - return IPPROTO_DONE; - - /* Send BU to each CN in the BUL to update BC entry. */ - bulp->lifetime = mip6_inp->ba_opt->lifetime; - bulp->refreshtime = mip6_inp->ba_opt->refresh; - mip6_update_cns(&esp->home_addr, &esp->coa, 0, - bulp->lifetime); - } - } - return 0; -} - - - -/* - ****************************************************************************** - * Function: mip6_rec_br - * Description: Receive a Binding Request option and evaluate the contents. - * Ret value: 0 Everything is OK. - * IPPROTO_DONE Error code used when something went wrong. - ****************************************************************************** - */ -int -mip6_rec_br(m_in, off) -struct mbuf *m_in; /* Mbuf containing the entire IPv6 packet */ -int off; /* Offset from start of mbuf to start of dest option */ -{ - struct mip6_opt_bu *bu_opt; /* BU allocated in function */ - struct in6_addr *from_src; /* Src address in rec packet */ - struct mip6_esm *esp; /* Home address entry */ - struct mip6_bul *bulp_cn; /* CN entry in the BU list */ - struct mip6_bul *bulp_ha; /* HA entry in the BU list */ - struct mip6_subbuf *subbuf = NULL; /* Sub-options for an option */ - struct mip6_subopt_coa altcoa; /* Alternate care-of address */ -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__) - long time_second = time.tv_sec; -#endif -#if MIP6_DEBUG - const struct mbuf *m = (const struct mbuf *)m_in; - u_int8_t var; - int ii, offset; -#endif - - /* Make sure that the BA contains a valid AH or ESP header. */ - if (mip6_inp->br_opt->type != IP6OPT_BINDING_REQ) { - ip6stat.ip6s_badoptions++; - return IPPROTO_DONE; - } - -#if MIP6_DEBUG - mip6_debug("\nReceived Binding Request\n"); - mip6_debug("Type/Length: %x / %u\n", mip6_inp->br_opt->type, - mip6_inp->br_opt->len); - - if (mip6_inp->br_opt->len > IP6OPT_BRLEN) { - offset = mip6_opt_offset(m_in, off, IP6OPT_BINDING_REQ); - if (offset == 0) - goto end_debug; - - mip6_debug("Sub-options present (TLV coded)\n"); - for (ii = IP6OPT_BRLEN; ii < mip6_inp->br_opt->len; ii++) { - if (m->m_len < offset + 2 + ii + 1) - break; - if ((ii - IP6OPT_BRLEN) % 16 == 0) - mip6_debug("\t0x:"); - if ((ii - IP6OPT_BRLEN) % 4 == 0) - mip6_debug(" "); - m_copydata(m_in, offset + 2 + ii, sizeof(var), - (caddr_t)&var); - mip6_debug("%02x", var); - if ((ii - IP6OPT_BRLEN + 1) % 16 == 0) - mip6_debug("\n"); - } - if ((ii - IP6OPT_BRLEN) % 16) - mip6_debug("\n"); - } - end_debug: -#endif - - /* Check if the BR includes a Unique Identifier sub-option. */ - if (mip6_inp->br_opt->len > IP6OPT_BRLEN) { - /* Received tunneled Router Advertisement when the MN's home - subnet is renumbered while the MN is away from home. */ - /* XXX Code have to be added. */ - } else { - /* A CN is requesting the MN to send a BU to update its BC. */ - /* Find the source address for the incoming packet (it may - include a home address option). */ - if (mip6_inp->optflag & MIP6_DSTOPT_HA) - from_src = &mip6_inp->ha_opt->home_addr; - else - from_src = &mip6_inp->ip6_src; - - /* Find out which lifetime to use in the BU */ - bulp_cn = mip6_bul_find(from_src, &mip6_inp->ip6_dst); - if (bulp_cn == NULL) - return IPPROTO_DONE; - - esp = mip6_esm_find(&mip6_inp->ip6_dst); - if (esp == NULL) { - log(LOG_ERR, "%s: no event-state machine found\n", - __FUNCTION__); - return IPPROTO_DONE; - } - - bulp_ha = mip6_bul_find(&esp->ha_hn, &mip6_inp->ip6_dst); - if (bulp_ha == NULL) - return IPPROTO_DONE; - - if (bulp_ha->lifetime > bulp_cn->lifetime) { - /* Send a BU to the previous default router. */ - bulp_cn->seqno += 1; - bu_opt = mip6_create_bu(0, 0, 0, bulp_cn->seqno, - bulp_ha->lifetime); - if (bu_opt == NULL) - return IPPROTO_DONE; - - altcoa.type = IP6SUBOPT_ALTCOA; - altcoa.len = IP6OPT_COALEN; - altcoa.coa = bulp_cn->coa; - if (mip6_store_subopt(&subbuf, (caddr_t)&altcoa) - != 0) { - if (subbuf) - _FREE(subbuf, M_TEMP); - return IPPROTO_DONE; - } - - mip6_outq_create(bu_opt, subbuf, &esp->home_addr, - from_src, NOT_SENT); - - bulp_cn->lifetime = bulp_ha->lifetime; - bulp_cn->refreshtime = bulp_ha->lifetime; - bulp_cn->lasttime = time_second; - bulp_cn->no_of_sent_bu = 0; - bulp_cn->update_rate = MIP6_MAX_UPDATE_RATE; - mip6_clear_retrans(bulp_cn); - } - } - return 0; -} - - - -/* - ****************************************************************************** - * Function: mip6_rec_hal - * Description: Performs Dynamic Home Agent Address Discovery. Called when a - * list of global home agent addresses is received. Checks if the - * received packets source address is in the list. If not it shall - * be added as the first entry in the list. - * Save the home agent address list in the event-state machine - * and send a BU to the first address in the list. - * Note: The timeout used in the BU is a trade off between how long - * time it shall wait before the next entry in the list is picked - * and, if successful first registration, the time to perform - * next registration. I believe 16 - 32 seconds will be fine. - * Ret value: 0 Everything is OK. - * IPPROTO_DONE Error code used when something went wrong. - ****************************************************************************** - */ -int -mip6_rec_hal(src, dst, hal) -struct in6_addr *src; /* Incoming packet source address */ -struct in6_addr *dst; /* Incoming packet destination address */ -struct mip6_subopt_hal *hal; /* List of HA's on the home link */ -{ - struct mip6_esm *esp; /* Event-state machine */ - struct mip6_bul *bulp; /* Entry in the Binding Update list */ - struct mip6_subbuf *subbuf; /* Buffer containing sub-options */ - struct mip6_bu_data bu_data; /* Data used when a BU is created */ - int found, ii, new_len, index; - - subbuf = NULL; - - /* Find the event-state machine */ - esp = mip6_esm_find(dst); - if (esp == NULL) { - log(LOG_ERR, - "%s: Couldn't find an event-state machine for " - "home address %s\n", - __FUNCTION__, ip6_sprintf(dst)); - return IPPROTO_DONE; - } - - /* If the incoming source address is not in the list of home - agents it is treated as the HA with highest preference. - Otherwise, the HA's are tried in the listed order. */ - found = 0; - if (hal == NULL) - new_len = IP6OPT_HALEN; - else { - index = hal->len / IP6OPT_HALEN; - for (ii = 0; ii < index; ii++) { - if (IN6_ARE_ADDR_EQUAL(&hal->halist[ii], src)) { - found = 1; - break; - } - } - if (found) - new_len = hal->len; - else - new_len = hal->len + IP6OPT_HALEN; - } - - /* Store the home agents list in the event-state machine. Add the - incoming packets source address if necessary. */ - esp->dad = (struct mip6_dad *)MALLOC(sizeof(struct mip6_dad), - M_TEMP, M_WAITOK); - if (esp->dad == NULL) - return IPPROTO_DONE; - bzero(esp->dad, sizeof(struct mip6_dad)); - - index = new_len / IP6OPT_HALEN; - esp->dad->hal = (struct mip6_subopt_hal *) - MALLOC(sizeof(struct mip6_subopt_hal) + - ((index - 1) * sizeof(struct in6_addr)), - M_TEMP, M_WAITOK); - if (esp->dad->hal == NULL) - return IPPROTO_DONE; - - esp->dad->hal->type = IP6SUBOPT_HALIST; - esp->dad->hal->len = new_len; - if (found) { - for (ii = 0; ii < index; ii++) { - bcopy(&hal->halist[ii], &esp->dad->hal->halist[ii], - sizeof(struct in6_addr)); - } - } else { - bcopy(src, &esp->dad->hal->halist[0], sizeof(struct in6_addr)); - for (ii = 0; ii < index - 1; ii++) { - bcopy(&hal->halist[ii], &esp->dad->hal->halist[ii+1], - sizeof(struct in6_addr)); - } - } - - /* Create a BUL entry. If there exist one already something is - wrong and an error message is sent to the console. */ - bulp = mip6_bul_find(src, dst); - if (bulp != NULL) { - log(LOG_ERR, - "%s: A BUL entry found but it shouldn't have been. " - "Internal error that must be looked into\n", __FUNCTION__); - return IPPROTO_DONE; - } - - bulp = mip6_bul_create(&esp->dad->hal->halist[0], &esp->home_addr, - &esp->coa, MIP6_BU_LIFETIME_DHAAD, 1); - if (bulp == NULL) - return IPPROTO_DONE; - - /* Send a BU registration to the Home Agent with highest preference. */ - bu_data.prefix_len = esp->prefix_len; - bu_data.ack = 1; - - if (mip6_send_bu(bulp, &bu_data, subbuf) != 0) - return IPPROTO_DONE; - - /* Set index to next entry to be used in the list. - Starts at 0 (which has been sent in this function) */ - if ((esp->dad->hal->len / IP6OPT_HALEN) == 1) - esp->dad->index = 0; - else - esp->dad->index = 1; - - return 0; -}; - - - -/* - ****************************************************************************** - * Function: mip6_rec_ramn - * Description: Processed by a Mobile Node. Includes a Router Advertisement - * with a H-bit set in the flags variable (checked by the calling - * function). - * The global unicast address for the home agent with the highest - * preference and the time when it expires are stored. - * Ret value: 0 Everything is OK. Otherwise appropriate error code. - ****************************************************************************** - */ -int -mip6_rec_ramn(m, off) -struct mbuf *m; /* Mbuf containing the entire IPv6 packet */ -int off; /* Offset from start of mbuf to start of RA */ -{ - struct ip6_hdr *ip6; /* IPv6 header */ - struct nd_router_advert *ra; /* Router Advertisement */ - struct mip6_esm *esp; /* Event-state machine */ - struct nd_opt_hai *hai; /* Home Agent information option */ - struct nd_opt_prefix_info *pi; /* Ptr to prefix information */ - u_int8_t *opt_ptr; /* Ptr to current option in RA */ - int cur_off; /* Cur offset from start of RA */ - caddr_t icmp6msg; /* Copy of mbuf (consequtively) */ - int16_t tmp_pref; - time_t tmp_lifetime; - int icmp6len; -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__) - long time_second = time.tv_sec; -#endif - - /* Find out if the RA can be processed */ - ip6 = mtod(m, struct ip6_hdr *); - if (ip6->ip6_hlim != 255) { - log(LOG_INFO, - "%s: Invalid hlim %d in Router Advertisement\n", - __FUNCTION__, - ip6->ip6_hlim); - return 0; - } - - if (!IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src)) { - log(LOG_INFO, - "%s: Source address %s is not link-local\n", __FUNCTION__, - ip6_sprintf(&ip6->ip6_src)); - return 0; - } - - /* The mbuf data must be stored consequtively to be able to - cast data from it. */ - icmp6len = m->m_pkthdr.len - off; - icmp6msg = (caddr_t)MALLOC(icmp6len, M_TEMP, M_WAITOK); - if (icmp6msg == NULL) - return IPPROTO_DONE; - - m_copydata(m, off, icmp6len, icmp6msg); - ra = (struct nd_router_advert *)icmp6msg; - - /* First, if a Home Agent Information option is present then the Home - Agent preference and lifetime is taken from the option. */ - cur_off = sizeof(struct nd_router_advert); - tmp_lifetime = ntohl(ra->nd_ra_router_lifetime); - tmp_pref = 0; - - while (cur_off < icmp6len) { - opt_ptr = ((caddr_t)icmp6msg + cur_off); - if (*opt_ptr == ND_OPT_HA_INFORMATION) { - /* Check the home agent information option */ - hai = (struct nd_opt_hai *)opt_ptr; - if (hai->nd_opt_hai_len != 1) { - ip6stat.ip6s_badoptions++; - return IPPROTO_DONE; - } - - tmp_pref = ntohs(hai->nd_opt_hai_pref); - tmp_lifetime = ntohs(hai->nd_opt_hai_lifetime); - cur_off += 8; - continue; - } else { - if (*(opt_ptr + 1) == 0) { - ip6stat.ip6s_badoptions++; - return IPPROTO_DONE; - } - cur_off += *(opt_ptr + 1) * 8; - } - } - - /* Go through all prefixes and store global address for the Home - Agent with the highest preference. */ - cur_off = sizeof(struct nd_router_advert); - while (cur_off < icmp6len) { - opt_ptr = ((caddr_t)icmp6msg + cur_off); - if (*opt_ptr == ND_OPT_PREFIX_INFORMATION) { - /* Check the prefix information option */ - pi = (struct nd_opt_prefix_info *)opt_ptr; - if (pi->nd_opt_pi_len != 4) { - ip6stat.ip6s_badoptions++; - return IPPROTO_DONE; - } - - if (!(pi->nd_opt_pi_flags_reserved & - ND_OPT_PI_FLAG_RTADDR)) { - cur_off += 4 * 8; - continue; - } - - if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix) || - IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) { - cur_off += 4 * 8; - continue; - } - - /* Aggregatable unicast address, rfc2374 */ - if (((pi->nd_opt_pi_prefix.s6_addr8[0] & 0xe0) > - 0x10) && (pi->nd_opt_pi_prefix_len != 64)) { - cur_off += 4 * 8; - continue; - } - - /* Only save the address if it's equal to the coa. */ - for (esp = mip6_esmq; esp; esp = esp->next) { - if (in6_are_prefix_equal( - &pi->nd_opt_pi_prefix, - &esp->coa, - pi->nd_opt_pi_prefix_len)) { - if (esp->ha_fn == NULL) { - esp->ha_fn = (struct mip6_hafn *) - MALLOC(sizeof(struct mip6_hafn), M_TEMP, M_WAITOK); - if (esp->ha_fn == NULL) - return ENOBUFS; - bzero(esp->ha_fn, sizeof(struct mip6_hafn)); - - esp->ha_fn->addr = pi->nd_opt_pi_prefix; - esp->ha_fn->prefix_len = pi->nd_opt_pi_prefix_len; - esp->ha_fn->pref = tmp_pref; - esp->ha_fn->time = time_second + tmp_lifetime; - } else { - if (tmp_pref > esp->ha_fn->pref) { - esp->ha_fn->addr = pi->nd_opt_pi_prefix; - esp->ha_fn->prefix_len = pi->nd_opt_pi_prefix_len; - esp->ha_fn->pref = tmp_pref; - esp->ha_fn->time = time_second + tmp_lifetime; - } else - esp->ha_fn->time = time_second + tmp_lifetime; - } - } - } - - cur_off += 4 * 8; - continue; - } else { - if (*(opt_ptr + 1) == 0) { - ip6stat.ip6s_badoptions++; - return IPPROTO_DONE; - } - cur_off += *(opt_ptr + 1) * 8; - } - } - return 0; -} - - -/* - ****************************************************************************** - * Function: mip6_route_optimize - * Description: When a tunneled packet is received a BU shall be sent to the - * CN if no Binding Update List entry exist or if the rate limit - * for sending BUs for an existing BUL entry is not exceded. - * Ret value: 0 Everything is OK. - * IPPROTO_DONE Error code used when something went wrong. - ****************************************************************************** - */ -int -mip6_route_optimize(m) -struct mbuf *m; /* Mbuf containing the entire IPv6 packet */ -{ - struct ip6_hdr *ip6; - struct mip6_esm *esp; - struct mip6_bul *bulp, *bulp_hr; - struct mip6_subbuf *subbuf; /* Buffer containing sub-options */ - struct mip6_bu_data bu_data; /* Data used when a BU is created */ - struct mip6_subopt_coa altcoa; /* Alternate care-of address */ - time_t t; -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__) - long time_second = time.tv_sec; -#endif - - /* Make sure that all requirements are meet for sending a BU to - the original sender of the packet. */ - if (!(m->m_flags & M_MIP6TUNNEL)) - return 0; - - ip6 = mtod(m, struct ip6_hdr *); - esp = mip6_esm_find(&ip6->ip6_dst); - if (esp == NULL) - return 0; - - /* Try to find an existing BUL entry. */ - bulp = mip6_bul_find(&ip6->ip6_src, &esp->home_addr); - if (bulp == NULL) { - /* Some information needed from the BU home registration */ - bulp_hr = mip6_bul_find(NULL, &esp->home_addr); - if (bulp_hr == NULL) - return 0; - bulp = mip6_bul_create(&ip6->ip6_src, &esp->home_addr, - &esp->coa, bulp_hr->lifetime, 0); - if (bulp == NULL) - return IPPROTO_DONE; - } else { - /* If the existing BUL entry is waiting for an ack or - has disabled sending BU, no BU shall be sent. */ - if ((bulp->state) || (bulp->bu_flag == 0)) - return 0; - - /* Check the rate limiting for sending Binding Updates */ - t = (time_t)time_second; -#if MIP6_DEBUG - mip6_debug("%s: Rate limiting for sending BU\n", __FUNCTION__); - mip6_debug("(time - bulp->lasttime) < bulp->update_rate\n"); - mip6_debug("time = %lu\n", (u_long)t); - mip6_debug("bulp->lasttimetime = %lu\n", bulp->lasttime); - mip6_debug("bulp->update_rate = %d\n", bulp->update_rate); -#endif - if ((t - bulp->lasttime) < bulp->update_rate) - return 0; - } - - /* OK we have to send a BU. */ - subbuf = NULL; - bu_data.prefix_len = esp->prefix_len; - bu_data.ack = 0; - - altcoa.type = IP6SUBOPT_ALTCOA; - altcoa.len = IP6OPT_COALEN; - altcoa.coa = bulp->coa; - if (mip6_store_subopt(&subbuf, (caddr_t)&altcoa)) { - if (subbuf) _FREE(subbuf, M_TEMP); - return IPPROTO_DONE; - } - - if (mip6_send_bu(bulp, &bu_data, subbuf) != 0) - return IPPROTO_DONE; - return 0; -} - - - -/* - ############################################################################## - # - # SENDING FUNCTIONS - # These functions are called when an IPv6 packet has been created internally - # by MIPv6 and shall be sent directly to its destination or when an option - # (BU, BA, BR) has been created and shall be stored in the mipv6 output queue - # for piggybacking on the first outgoing packet sent to the node. - # - ############################################################################## - */ - -/* - ****************************************************************************** - * Function: mip6_send_bu - * Description: Send a Binding Update option to a node (CN, HA or MN). A new - * IPv6 packet is built including an IPv6 header and a Destination - * header (where the BU is stored). - * Arguments: bulp - BUL entry for which the BU is sent. - * data - BU data needed when the BU option is created. NULL - * if the BU option stored in the BUL entry is used. - * subopt - Sub-options for the BU. NULL if the BU sub-options - * stored in the BUL entry is used. - * Note: The following combinations of indata are possible: - * data == NULL && subbuf == NULL Use existing data, i.e used for - * retransmission - * data != NULL && subbuf == NULL Clear existing data and send a - * new BU without sub-options - * data != NULL && subbuf != NULL Clear existing data and send a - * new BU with new sub-options - * Ret value: 0 if everything OK. Otherwise appropriate error code. - ****************************************************************************** - */ -int -mip6_send_bu(bulp, data, subbuf) -struct mip6_bul *bulp; -struct mip6_bu_data *data; -struct mip6_subbuf *subbuf; -{ - struct mbuf *m_ip6; /* IPv6 header stored in a mbuf */ - struct ip6_pktopts *pktopt; /* Options for IPv6 packet */ - struct mip6_opt_bu *bu_opt; /* Binding Update option */ - struct mip6_subbuf *bu_subopt; /* Binding Update sub-options */ - struct mip6_esm *esp; /* Home address entry */ - int error; -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__) - long time_second = time.tv_sec; -#endif -#if MIP6_DEBUG - int ii; - u_int8_t var; -#endif - - /* Make sure that it's allowed to send a BU */ - if (bulp == NULL) - return 0; - - if (!bulp->bu_flag) { - log(LOG_INFO, - "%s: BU not sent to host %s due to an ICMP Parameter " - "Problem, Code 2, when a BU was sent previously\n", - __FUNCTION__, ip6_sprintf(&bulp->dst_addr)); - return 0; - } - - /* Only send BU if we are not in state UNDEFINED */ - esp = mip6_esm_find(&bulp->bind_addr); - if (esp == NULL) { - log(LOG_ERR, "%s: We should never come here\n", __FUNCTION__); - return 0; - } else if (esp->state == MIP6_STATE_UNDEF) { - log(LOG_INFO, - "%s: Mobile Node with home address %s not connected to " - "any network. Binding Update could not be sent.\n", - __FUNCTION__, ip6_sprintf(&bulp->bind_addr)); - return 0; - } - - /* Evaluate parameters according to the note in the function header */ - if ((data == NULL) && (subbuf == NULL)) { - if ((bulp->state == NULL) || (bulp->state->bu_opt == NULL)) { - log(LOG_ERR, - "%s: No existing BU option to send\n", - __FUNCTION__); - return 0; - } - bulp->seqno += 1; - bu_opt = bulp->state->bu_opt; - bu_opt->seqno = bulp->seqno; - bu_subopt = bulp->state->bu_subopt; - } else if (data != NULL) { - mip6_clear_retrans(bulp); - if (data->ack) { - bulp->state = mip6_create_retrans(bulp); - if (bulp->state == NULL) - return ENOBUFS; - } - - bulp->seqno += 1; - bu_opt = mip6_create_bu(data->prefix_len, data->ack, - bulp->hr_flag, - bulp->seqno, bulp->lifetime); - if (bu_opt == NULL) { - mip6_clear_retrans(bulp); - bulp->seqno -= 1; - return ENOBUFS; - } - - if (data->ack) { - bulp->state->bu_opt = bu_opt; - bulp->state->bu_subopt = subbuf; - bu_subopt = bulp->state->bu_subopt; - } else - bu_subopt = subbuf; - } else { - log(LOG_ERR, - "%s: Function parameter error. We should not come here\n", - __FUNCTION__); - return 0; - } - - /* Allocate necessary memory and send the BU */ - pktopt = (struct ip6_pktopts *)MALLOC(sizeof(struct ip6_pktopts), - M_TEMP, M_NOWAIT); - if (pktopt == NULL) - return ENOBUFS; - bzero(pktopt, sizeof(struct ip6_pktopts)); - - pktopt->ip6po_hlim = -1; /* -1 means to use default hop limit */ - m_ip6 = mip6_create_ip6hdr(&bulp->bind_addr, &bulp->dst_addr, - IPPROTO_NONE); - if(m_ip6 == NULL) { - _FREE(pktopt, M_TEMP); - return ENOBUFS; - } - - pktopt->ip6po_dest2 = mip6_create_dh((void *)bu_opt, bu_subopt, - IPPROTO_NONE); - if(pktopt->ip6po_dest2 == NULL) { - _FREE(pktopt, M_TEMP); - _FREE(m_ip6, M_TEMP); - return ENOBUFS; - } - - mip6_config.enable_outq = 0; - error = ip6_output(m_ip6, pktopt, NULL, 0, NULL, NULL); - if (error) { - _FREE(pktopt->ip6po_dest2, M_TEMP); - _FREE(pktopt, M_TEMP); - mip6_config.enable_outq = 1; - log(LOG_ERR, - "%s: ip6_output function failed to send BU, error = %d\n", - __FUNCTION__, error); - return error; - } - mip6_config.enable_outq = 1; - - /* Update Binding Update List variables. */ - bulp->lasttime = time_second; - bulp->no_of_sent_bu += 1; - - if ( !(bu_opt->flags & MIP6_BU_AFLAG)) { - if (bulp->no_of_sent_bu >= MIP6_MAX_FAST_UPDATES) - bulp->update_rate = MIP6_SLOW_UPDATE_RATE; - } - -#if MIP6_DEBUG - mip6_debug("\nSent Binding Update option (0x%x)\n", bu_opt); - mip6_debug("IP Header Src: %s\n", ip6_sprintf(&bulp->bind_addr)); - mip6_debug("IP Header Dst: %s\n", ip6_sprintf(&bulp->dst_addr)); - mip6_debug("Type/Length/Flags: %x / %u / ", bu_opt->type, bu_opt->len); - if (bu_opt->flags & MIP6_BU_AFLAG) - mip6_debug("A "); - if (bu_opt->flags & MIP6_BU_HFLAG) - mip6_debug("H "); - if (bu_opt->flags & MIP6_BU_RFLAG) - mip6_debug("R "); - mip6_debug("\n"); - mip6_debug("Seq no/Life time: %u / %u\n", bu_opt->seqno, - bu_opt->lifetime); - mip6_debug("Prefix length: %u\n", bu_opt->prefix_len); - - if (bu_subopt) { - mip6_debug("Sub-options present (TLV coded)\n"); - for (ii = 0; ii < bu_subopt->len; ii++) { - if (ii % 16 == 0) - mip6_debug("\t0x:"); - if (ii % 4 == 0) - mip6_debug(" "); - bcopy((caddr_t)&bu_subopt->buffer[ii], - (caddr_t)&var, 1); - mip6_debug("%02x", var); - if ((ii + 1) % 16 == 0) - mip6_debug("\n"); - } - if (ii % 16) - mip6_debug("\n"); - } -#endif - - _FREE(pktopt->ip6po_dest2, M_TEMP); - _FREE(pktopt, M_TEMP); - return 0; -} - - - -/* - ****************************************************************************** - * Function: mip6_send_bu2fn - * Description: Create a new or modify an existing Binding Update List entry, - * create a Bindig Update option and a new temporary event-state - * machine and send the Binding Update option to a Home Agent at - * the previous foreign network. - * Ret value: - - ****************************************************************************** - */ -void -mip6_send_bu2fn(old_coa, old_ha, coa, esm_ifp, lifetime) -struct in6_addr *old_coa; /* Previous care-of address */ -struct mip6_hafn *old_ha; /* Previous Home Agent address */ -struct in6_addr *coa; /* Current coa or home address */ -struct ifnet *esm_ifp; /* Physical i/f used by event-state machine */ -u_int32_t lifetime; /* Lifetime for BU */ -{ - struct mip6_esm *esp; /* ESM for prev COA */ - struct mip6_bul *bulp; /* BU list entry*/ - struct mip6_subbuf *subbuf; /* Buffer containing sub-options */ - struct mip6_bu_data bu_data; /* Data used when a BU is created */ - struct mip6_subopt_coa altcoa; /* Alternate care-of address */ -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__) - long time_second = time.tv_sec; -#endif - - /* Make sure that the Home Agent at the previous network exist and - that it's still valid. */ - if (old_ha == NULL) - return; - else { - if (time_second > old_ha->time) { - log(LOG_INFO, - "%s: Timer had expired for Home Agent on " - "previous network. No BU sent\n", - __FUNCTION__); - return; - } - } - - /* Find an existing or create a new BUL entry. */ - bulp = mip6_bul_find(NULL, old_coa); - if (bulp == NULL) { - bulp = mip6_bul_create(&old_ha->addr, old_coa, coa, - lifetime, 1); - if (bulp == NULL) - return; - } else { - bulp->dst_addr = old_ha->addr; - bulp->coa = *coa; - bulp->lifetime = lifetime; - bulp->refreshtime = lifetime; - mip6_clear_retrans(bulp); - } - - /* Create an event-state machine to be used when the home address - option is created for outgoing packets. The event-state machine - must be removed when the BUL entry is removed. */ - esp = mip6_esm_create(esm_ifp, &old_ha->addr, coa, old_coa, 0, - MIP6_STATE_NOTREG, TEMPORARY, - MIP6_BU_LIFETIME_DEFRTR); - if (esp == NULL) - return; - - /* Send the Binding Update option */ - subbuf = NULL; - - bu_data.prefix_len = 0; - bu_data.ack = 0; - - altcoa.type = IP6SUBOPT_ALTCOA; - altcoa.len = IP6OPT_COALEN; - altcoa.coa = *coa; - if (mip6_store_subopt(&subbuf, (caddr_t)&altcoa)) { - if (subbuf) - _FREE(subbuf, M_TEMP); - return; - } - - if (mip6_send_bu(bulp, &bu_data, subbuf) != 0) - return; -} - - - -/* - ****************************************************************************** - * Function: mip6_update_cns - * Description: Search the BUL for each entry with a matching home address for - * which no Binding Update has been sent for the new COA. - * Call a function for queueing the BU. - * Note: Since this BU is stored in the MN for a couple of seconds - * before it is piggybacked or flashed from the queue it may - * not have the ack-bit set. - * Ret value: - - ****************************************************************************** - */ -void -mip6_update_cns(home_addr, coa, prefix_len, lifetime) -struct in6_addr *home_addr; /* Home Address for MN */ -struct in6_addr *coa; /* New Primary COA for MN */ -u_int8_t prefix_len; /* Prefix length for Home Address */ -u_int32_t lifetime; /* Lifetime for BU registration */ -{ - struct mip6_bul *bulp; /* Entry in the Binding Update List */ - - /* Try to find existing entry in the BUL. Home address must match. */ - for (bulp = mip6_bulq; bulp;) { - if (IN6_ARE_ADDR_EQUAL(home_addr, &bulp->bind_addr) && - !IN6_ARE_ADDR_EQUAL(coa, &bulp->coa)) { - /* Queue a BU for transmission to the node. */ - mip6_queue_bu(bulp, home_addr, coa, - prefix_len, lifetime); - - /* Remove BUL entry if it's a de-registration. */ - if (IN6_ARE_ADDR_EQUAL(home_addr, coa) || - (lifetime == 0)) - bulp = mip6_bul_delete(bulp); - else - bulp = bulp->next; - } else - bulp = bulp->next; - } -} - - - -/* - ****************************************************************************** - * Function: mip6_queue_bu - * Description: Create a BU and a sub-option (alternate care-of address). - * Update the BUL entry and store it in the output queue for - * piggy-backing. - * Note: Since this BU is stored in the MN for a couple of seconds - * before it is piggybacked or flashed from the queue it may - * not have the ack-bit set. - * Ret value: - - ****************************************************************************** - */ -void -mip6_queue_bu(bulp, home_addr, coa, prefix_len, lifetime) -struct mip6_bul *bulp; /* Entry in the Binding Update List */ -struct in6_addr *home_addr; /* Home Address for MN */ -struct in6_addr *coa; /* New Primary COA for MN */ -u_int8_t prefix_len; /* Prefix length for Home Address */ -u_int32_t lifetime; /* Lifetime for BU registration */ -{ - struct mip6_opt_bu *bu_opt; /* BU allocated in this function */ - struct mip6_subbuf *subbuf; /* Buffer containing sub-options */ - struct mip6_subopt_coa altcoa; /* Alternate care-of address */ -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__) - long time_second = time.tv_sec; -#endif - - /* Check if it's allowed to send a BU to this node. */ - if ((coa == NULL) || (bulp == NULL)) - return; - - if (bulp->bu_flag == 0) { - log(LOG_INFO, - "%s: BU not sent to host %s due to an ICMP Parameter " - "Problem, Code 2, when a BU was sent previously\n", - __FUNCTION__, ip6_sprintf(&bulp->dst_addr)); - return; - } - - /* Create the sub-option */ - subbuf = NULL; - altcoa.type = IP6SUBOPT_ALTCOA; - altcoa.len = IP6OPT_COALEN; - altcoa.coa = *coa; - if (mip6_store_subopt(&subbuf, (caddr_t)&altcoa)) { - if (subbuf) - _FREE(subbuf, M_TEMP); - return; - } - - /* Create a BU. */ - bulp->seqno += 1; - bu_opt = mip6_create_bu(prefix_len, 0, 0, bulp->seqno, lifetime); - if (bu_opt == NULL) { - log(LOG_ERR, "%s: Could not create a BU\n", __FUNCTION__); - return; - } - - /* Update BUL entry */ - bulp->coa = *coa; - bulp->lifetime = lifetime; - bulp->refreshtime = lifetime; - bulp->lasttime = time_second; - bulp->no_of_sent_bu += 1; - mip6_clear_retrans(bulp); - - /* Add entry to the output queue for transmission to the CN. */ - mip6_outq_create(bu_opt, subbuf, home_addr, &bulp->dst_addr, NOT_SENT); -} - - - -/* - ############################################################################## - # - # UTILITY FUNCTIONS - # Miscellaneous functions needed for processing of incoming control signals - # or events originated from the move detection algorithm. - # - ############################################################################## - */ - -/* - ****************************************************************************** - * Function: mip6_create_bu - * Description: Create a Binding Update option for transmission. - * Ret value: Pointer to the BU option or NULL. - * Note: Variable seqno and lifetime set in function - * mip6_update_bul_entry. - ****************************************************************************** - */ -struct mip6_opt_bu * -mip6_create_bu(prefix_len, ack, hr, seqno, lifetime) -u_int8_t prefix_len; /* Prefix length for Home Address */ -int ack; /* Ack required (0 = FALSE otherwise TRUE) */ -int hr; /* Home Registration (0 = FALSE otherwise TRUE) */ -u_int16_t seqno; /* Sequence number */ -u_int32_t lifetime; /* Suggested lifetime for the BU registration */ -{ - struct mip6_opt_bu *bu_opt; /* BU allocated in this function */ - - /* Allocate and store Binding Update option data */ - bu_opt = (struct mip6_opt_bu *)MALLOC(sizeof(struct mip6_opt_bu), - M_TEMP, M_WAITOK); - if (bu_opt == NULL) - return NULL; - bzero(bu_opt, sizeof(struct mip6_opt_bu)); - - bu_opt->type = IP6OPT_BINDING_UPDATE; - bu_opt->len = IP6OPT_BULEN; - bu_opt->seqno = seqno; - bu_opt->lifetime = lifetime; - - /* The prefix length field is valid only for "home registration" BU. */ - if (hr) { - bu_opt->flags |= MIP6_BU_HFLAG; - bu_opt->prefix_len = prefix_len; - if (ip6_forwarding) - bu_opt->flags |= MIP6_BU_RFLAG; - } else - bu_opt->prefix_len = 0; - - if (ack) - bu_opt->flags |= MIP6_BU_AFLAG; - -#if MIP6_DEBUG - mip6_debug("\nBinding Update option created (0x%x)\n", bu_opt); -#endif - return bu_opt; -} - - - -/* - ****************************************************************************** - * Function: mip6_stop_bu - * Description: Stop sending a Binding Update to the host that has generated - * the icmp error message. - * Ret value: - - ****************************************************************************** - */ -void -mip6_stop_bu(ip6_dst) -struct in6_addr *ip6_dst; /* Host that generated ICMP error message */ -{ - struct mip6_bul *bulp; /* Entry in the BU list */ - - /* No future BU shall be sent to this destination. */ - for (bulp = mip6_bulq; bulp; bulp = bulp->next) { - if (IN6_ARE_ADDR_EQUAL(ip6_dst, &bulp->dst_addr)) - bulp->bu_flag = 0; - } -} - - - -/* - ****************************************************************************** - * Function: mip6_ba_error - * Description: Each incoming BA error is taken care of by this function. - * If a registration to the Home Agent failed then dynamic home - * agent address discovery shall be performed. If a de-regi- - * stration failed then perform the same actions as when a - * BA with status equals to 0 is received. - * If a registration or de-registration to the CN failed then - * the error is logged, no further action is taken. - * If dynamic home agent address discovery already has been - * done then take the next entry in the list. If its just one - * entry in the list discard it and send a BU with destination - * address equals to Home Agents anycast address. - * Ret value: 0 Everything is OK. - * IPPROTO_DONE Error code used when something went wrong. - ****************************************************************************** - */ -int -mip6_ba_error(src, dst, bind_addr, hr_flag) -struct in6_addr *src; /* Src address for received BA option */ -struct in6_addr *dst; /* Dst address for received BA option */ -struct in6_addr *bind_addr; /* Binding addr in BU causing this error */ -u_int8_t hr_flag; /* Home reg flag in BU causing this error */ -{ - struct mip6_bul *bulp; /* New BUL entry*/ - struct mip6_esm *esp; /* Home address entry */ - struct in6_addr *dst_addr; - struct mip6_bu_data bu_data; /* Data used when a BU is created */ - u_int32_t lifetime; - int error, max_index; - - if (mip6_inp->ba_opt->status == MIP6_BA_STATUS_UNSPEC) { - /* Reason unspecified - Received when either a Home Agent or Correspondent Node - was not able to process the BU. */ - log(LOG_INFO, - "\nBinding Acknowledgement error = %d " - "(Reason unspecified) from host %s\n", - mip6_inp->ba_opt->status, ip6_sprintf(src)); - } else if (mip6_inp->ba_opt->status == MIP6_BA_STATUS_PROHIBIT) { - /* Administratively prohibited */ - log(LOG_INFO, - "\nBinding Acknowledgement error = %d " - "(Administratively prohibited) from host %s\n", - mip6_inp->ba_opt->status, ip6_sprintf(src)); - log(LOG_INFO, "Contact your system administrator\n"); - } else if (mip6_inp->ba_opt->status == MIP6_BA_STATUS_RESOURCE) { - /* Insufficient resources - Received when a Home Agent receives a BU with the H-bit - set and insufficient space exist or can be reclaimed - (sec. 8.7). */ - log(LOG_INFO, - "\nBinding Acknowledgement error = %d " - "(Insufficient resources) from host %s\n", - mip6_inp->ba_opt->status, ip6_sprintf(src)); - } else if (mip6_inp->ba_opt->status == MIP6_BA_STATUS_HOMEREGNOSUP) { - /* Home registration not supported - Received when a primary care-of address registration - (sec. 9.3) is done and the node is not a router - implementing Home Agent functionality. */ - log(LOG_INFO, - "\nBinding Acknowledgement error = %d " - "(Home registration not supported) from host %s\n", - mip6_inp->ba_opt->status, ip6_sprintf(src)); - } else if (mip6_inp->ba_opt->status == MIP6_BA_STATUS_SUBNET) { - /* Not home subnet - Received when a primary care-of address registration - (sec. 9.3) is done and the home address for the binding - is not an on-link IPv6 address with respect to the Home - Agent's current prefix list. */ - log(LOG_INFO, - "\nBinding Acknowledgement error = %d " - "(Not home subnet) from host %s\n", - mip6_inp->ba_opt->status, ip6_sprintf(src)); - } else if (mip6_inp->ba_opt->status == MIP6_BA_STATUS_DHAAD) { - /* Dynamic Home Agent Address Discovery - Received when a Mobile Node is trying to find out the - global address of the home agents on its home subnetwork - (sec 9.2). */ - error = mip6_rec_hal(src, dst, mip6_inp->hal); - return error; - } else if (mip6_inp->ba_opt->status == MIP6_BA_STATUS_IFLEN) { - /* Incorrect subnet prefix length - Received when a primary care-of address registration - (sec. 9.3) is done and the prefix length in the BU - differs from the length of the home agent's own knowledge - of the subnet prefix length on the home link. */ - log(LOG_INFO, - "\nBinding Acknowledgement error = %d " - "(Incorrect subnet prefix length) from host %s\n", - mip6_inp->ba_opt->status, ip6_sprintf(src)); - } else if (mip6_inp->ba_opt->status == MIP6_BA_STATUS_NOTHA) { - /* Not Home Agent for this Mobile Node - Received when a primary care-of address de-registration - (sec. 9.4) is done and the Home Agent has no entry for - this mobil node marked as "home registration" in its - Binding Cache. */ - log(LOG_INFO, - "\nBinding Acknowledgement error = %d " - "(Not Home Agent for this Mobile Node) from host %s\n", - mip6_inp->ba_opt->status, ip6_sprintf(src)); - } else { - log(LOG_INFO, - "\nBinding Acknowledgement error = %d (Unknown) " - "from host %s\n", - mip6_inp->ba_opt->status, ip6_sprintf(src)); - } - - /* Furthr processing according to the desription in the header. */ - if (hr_flag) { - esp = mip6_esm_find(bind_addr); - if (esp == NULL) { - log(LOG_ERR, - "%s: No event-state machine found\n", - __FUNCTION__); - return IPPROTO_DONE; - } - - /* If it's a de-registration, clear up the ESM. */ - if (esp->state == MIP6_STATE_DEREG) { - /* Remove the tunnel for the MN */ - mip6_tunnel(NULL, NULL, MIP6_TUNNEL_DEL, - MIP6_NODE_MN, (void *)esp); - - /* Send BU to each entry (CN) in the BUL to remove - the BC entry. */ - mip6_update_cns(&esp->home_addr, &esp->home_addr, - 0, 0); - mip6_outq_flush(); - - /* Don't set the state until BUs have been sent - to all CNs, otherwise the Home Address option - will not be added for the outgoing packet. */ - esp->state = MIP6_STATE_HOME; - esp->coa = in6addr_any; - return 0; - } - - /* If it's a registration, perform dynamic home agent address - discovery or use the existing. */ - if (esp->dad) { - if (esp->dad->hal->len == IP6OPT_HALEN) { - if (esp->dad->hal) - _FREE(esp->dad->hal, M_TEMP); - _FREE(esp->dad, M_TEMP); - - /* Build an anycast address */ - mip6_build_ha_anycast(&esp->ha_hn, - &esp->home_addr, - esp->prefix_len); - if (IN6_IS_ADDR_UNSPECIFIED(&esp->ha_hn)) { - log(LOG_ERR, - "%s: Could not create anycast " - "address for Mobile Node, " - "wrong prefix length\n", - __FUNCTION__); - return IPPROTO_DONE; - } - dst_addr = &esp->ha_hn; - lifetime = mip6_config.hr_lifetime; - } else { - dst_addr = &esp->dad->hal->halist[esp->dad->index]; - max_index = (esp->dad->hal->len / IP6OPT_HALEN) - 1; - if (esp->dad->index == max_index) - esp->dad->index = 0; - else - esp->dad->index += 1; - lifetime = MIP6_BU_LIFETIME_DHAAD; - } - } else { - /* Build an anycast address */ - mip6_build_ha_anycast(&esp->ha_hn, &esp->home_addr, - esp->prefix_len); - if (IN6_IS_ADDR_UNSPECIFIED(&esp->ha_hn)) { - log(LOG_ERR, - "%s: Could not create anycast address for Mobile " - "Node, wrong prefix length\n", __FUNCTION__); - return IPPROTO_DONE; - } - dst_addr = &esp->ha_hn; - lifetime = mip6_config.hr_lifetime; - } - - /* Create a new BUL entry and send a BU to the Home Agent */ - bulp = mip6_bul_create(dst_addr, &esp->home_addr, &esp->coa, - lifetime, 1); - if (bulp == NULL) - return IPPROTO_DONE; - - bu_data.prefix_len = esp->prefix_len; - bu_data.ack = 1; - - if (mip6_send_bu(bulp, &bu_data, NULL) != 0) - return IPPROTO_DONE; - } - return 0; -} - - - -/* - ****************************************************************************** - * Function: mip6_prefix_lifetime - * Description: Decide the remaining valid lifetime for a home address. Search - * the prefix list for a match and use this lifetime value. - * Note: This function is used by the MN since no test of the on-link - * flag is done. - * Ret value: Lifetime - ****************************************************************************** - */ -u_int32_t -mip6_prefix_lifetime(addr) -struct in6_addr *addr; /* IPv6 address to check */ -{ - struct nd_prefix *pr; /* Entries in the prexix list */ - u_int32_t min_time; /* Minimum life time */ - - min_time = 0xffffffff; - for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { - if (in6_are_prefix_equal(addr, &pr->ndpr_prefix.sin6_addr, - pr->ndpr_plen)) { - return pr->ndpr_vltime; - } - } - return min_time; -} - - - -/* - ****************************************************************************** - * Function: mip6_create_retrans - * Description: Removes the current content of the bulp->state variable and - * allocates new memory. - * Ret value: Pointer to the allocated memory or NULL. - ****************************************************************************** - */ -struct mip6_retrans * -mip6_create_retrans(bulp) -struct mip6_bul *bulp; -{ - if (bulp == NULL) - return NULL; - - mip6_clear_retrans(bulp); - bulp->state = (struct mip6_retrans *)MALLOC( - sizeof(struct mip6_retrans), - M_TEMP, M_WAITOK); - if (bulp->state == NULL) - return NULL; - bzero(bulp->state, sizeof(struct mip6_retrans)); - - bulp->state->bu_opt = NULL; - bulp->state->bu_subopt = NULL; - bulp->state->ba_timeout = 2; - bulp->state->time_left = 2; - return bulp->state; -} - - - -/* - ****************************************************************************** - * Function: mip6_clear_retrans - * Description: Removes the current content of the bulp->state variable and - * sets it to NULL. - * Ret value: - - ****************************************************************************** - */ -void -mip6_clear_retrans(bulp) -struct mip6_bul *bulp; -{ - if (bulp == NULL) - return; - - if (bulp->state) { - if (bulp->state->bu_opt) - _FREE(bulp->state->bu_opt, M_TEMP); - if (bulp->state->bu_subopt) - _FREE(bulp->state->bu_subopt, M_TEMP); - _FREE(bulp->state, M_TEMP); - bulp->state = NULL; - } - return; -} - - - -/* - ############################################################################## - # - # LIST FUNCTIONS - # The Mobile Node maintains a Bindig Update List (BUL) for each node to which - # a BU has been sent. - # Besides from this a list of event-state machines, one for each home address - # is handled by the Mobile Node and the Correspondent Node since it may - # become mobile at any time. - # An output queue for piggybacking of options (BU, BA, BR) on the first - # outgoing packet sent to the node is also maintained. If the option has not - # been sent with a packet within MIP6_OUTQ_LIFETIME it will be sent in a - # separate packet. - # - ############################################################################## - */ - -/* - ****************************************************************************** - * Function: mip6_bul_find - * Description: Find a Binding Update List entry for which a matching can be - * found for both the destination and binding address. - * If variable dst_addr is NULL an entry for home registration - * will be searched for. - * Ret value: Pointer to Binding Update List entry or NULL - ****************************************************************************** - */ -struct mip6_bul * -mip6_bul_find(dst_addr, bind_addr) -struct in6_addr *dst_addr; /* Destination Address for Binding Update */ -struct in6_addr *bind_addr; /* Home Address for MN or previous COA */ -{ - struct mip6_bul *bulp; /* Entry in the Binding Update list */ - - if (dst_addr == NULL) { - for (bulp = mip6_bulq; bulp; bulp = bulp->next) { - if (IN6_ARE_ADDR_EQUAL(bind_addr, &bulp->bind_addr) && - (bulp->hr_flag)) - break; - } - } else { - for (bulp = mip6_bulq; bulp; bulp = bulp->next) { - if (IN6_ARE_ADDR_EQUAL(dst_addr, &bulp->dst_addr) && - IN6_ARE_ADDR_EQUAL(bind_addr, &bulp->bind_addr)) - break; - } - if (bulp != NULL) - return bulp; - - /* It might be that the dest address for the BU was the Home - Agent anycast address and in that case we try to find it. */ - for (bulp = mip6_bulq; bulp; bulp = bulp->next) { - if ((bulp->dst_addr.s6_addr8[15] & 0x7f) == - MIP6_ADDR_ANYCAST_HA && - IN6_ARE_ADDR_EQUAL(bind_addr, &bulp->bind_addr)) { - break; - } - } - } - return bulp; -} - - - - -/* - ****************************************************************************** - * Function: mip6_bul_create - * Description: Create a new Binding Update List entry and insert it as the - * first entry in the list. - * Ret value: Pointer to Binding Update List entry or NULL. - * Note: If the BUL timeout function has not been started it is started. - * The BUL timeout function will be called once every second until - * there are no more entries in the BUL. - ****************************************************************************** - */ -struct mip6_bul * -mip6_bul_create(dst_addr, bind_addr, coa, lifetime, hr) -struct in6_addr *dst_addr; /* Dst address for Binding Update */ -struct in6_addr *bind_addr; /* Home Address for MN or previous COA */ -struct in6_addr *coa; /* Primary COA for MN */ -u_int32_t lifetime; /* Lifetime for BU */ -u_int8_t hr; /* Home registration flag */ -{ - struct mip6_bul *bulp; /* New Binding Update list entry */ - int s; - - bulp = (struct mip6_bul *)MALLOC(sizeof(struct mip6_bul), - M_TEMP, M_WAITOK); - if (bulp == NULL) - return NULL; - bzero(bulp, sizeof(struct mip6_bul)); - - bulp->next = NULL; - bulp->dst_addr = *dst_addr; - bulp->bind_addr = *bind_addr; - bulp->coa = *coa; - bulp->lifetime = lifetime; - bulp->refreshtime = lifetime; - bulp->seqno = 0; - bulp->lasttime = 0; - bulp->no_of_sent_bu = 0; - bulp->state = NULL; - bulp->bu_flag = 1; - bulp->hr_flag = hr; - bulp->update_rate = MIP6_MAX_UPDATE_RATE; - - /* Insert the entry as the first entry in the BUL. */ - s = splnet(); - if (mip6_bulq == NULL) { - mip6_bulq = bulp; -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - mip6_timer_bul_handle = -#endif - timeout(mip6_timer_bul, (void *)0, hz); - } else { - bulp->next = mip6_bulq; - mip6_bulq = bulp; - } - splx(s); - -#if MIP6_DEBUG - mip6_debug("\nBinding Update List Entry created (0x%x)\n", bulp); - mip6_debug("Destination Address: %s\n", ip6_sprintf(&bulp->dst_addr)); - mip6_debug("Binding Address: %s\n", ip6_sprintf(&bulp->bind_addr)); - mip6_debug("Care-of Address: %s\n", ip6_sprintf(&bulp->coa)); - mip6_debug("Life/Refresh time: %u / %u\n", bulp->lifetime, - bulp->refreshtime); - mip6_debug("Seq no/Home reg: %u / ", bulp->seqno); - if (bulp->hr_flag) - mip6_debug("TRUE\n"); - else - mip6_debug("FALSE\n"); -#endif - return bulp; -} - - - -/* - ****************************************************************************** - * Function: mip6_bul_delete - * Description: Delete the requested Binding Update list entry. - * Ret value: Ptr to next entry in list or NULL if last entry removed. - ****************************************************************************** - */ -struct mip6_bul * -mip6_bul_delete(bul_remove) -struct mip6_bul *bul_remove; /* BUL entry to be deleted */ -{ - struct mip6_bul *bulp; /* Current entry in the BU list */ - struct mip6_bul *bulp_prev; /* Previous entry in the BU list */ - struct mip6_bul *bulp_next; /* Next entry in the BU list */ - int s; - - /* Find the requested entry in the BUL. */ - s = splnet(); - bulp_next = NULL; - bulp_prev = NULL; - for (bulp = mip6_bulq; bulp; bulp = bulp->next) { - bulp_next = bulp->next; - if (bulp == bul_remove) { - if (bulp_prev == NULL) - mip6_bulq = bulp->next; - else - bulp_prev->next = bulp->next; -#if MIP6_DEBUG - mip6_debug("\nBU List Entry deleted (0x%x)\n", bulp); -#endif - mip6_clear_retrans(bulp); - _FREE(bulp, M_TEMP); - - /* Remove the timer if the BUL queue is empty */ - if (mip6_bulq == NULL) { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - untimeout(mip6_timer_bul, (void *)NULL, - mip6_timer_bul_handle); - callout_handle_init(&mip6_timer_bul_handle); -#else - untimeout(mip6_timer_bul, (void *)NULL); -#endif - } - break; - } - bulp_prev = bulp; - } - splx(s); - return bulp_next; -} - - - -/* - ****************************************************************************** - * Function: mip6_esm_find - * Description: Find an event-state machine for which the Mobile Nodes home - * address matches and the type is correct. - * Ret value: Pointer to event-state machine entry or NULL - ****************************************************************************** - */ -struct mip6_esm * -mip6_esm_find(home_addr) -struct in6_addr *home_addr; /* MNs home address */ -{ - struct mip6_esm *esp; - - for (esp = mip6_esmq; esp; esp = esp->next) { - if (IN6_ARE_ADDR_EQUAL(home_addr, &esp->home_addr)) - return esp; - } - return NULL; -} - - - -/* - ****************************************************************************** - * Function: mip6_esm_create - * Description: Create an event-state machine entry and add it first to the - * list. If type is PERMANENT the lifetime will be set to 0xFFFF, - * otherwise it will be set to the specified lifetime. If type is - * TEMPORARY the timer will be started if not already started. - * Ret value: Pointer to an event-state machine or NULL. - ****************************************************************************** - */ -struct mip6_esm * -mip6_esm_create(ifp, ha_hn, coa, home_addr, prefix_len, state, - type, lifetime) -struct ifnet *ifp; /* Physical i/f used by this home address */ -struct in6_addr *ha_hn; /* Home agent address (home network) */ -struct in6_addr *coa; /* Current care-of address */ -struct in6_addr *home_addr; /* Home address */ -u_int8_t prefix_len; /* Prefix length for the home address */ -int state; /* State of the home address */ -enum esm_type type; /* Permanent or Temporary esm */ -u_int16_t lifetime; /* Lifetime for event-state machine */ -{ - struct mip6_esm *esp, *esp_tmp; - int start_timer, s; - - esp = (struct mip6_esm *)MALLOC(sizeof(struct mip6_esm), - M_TEMP, M_WAITOK); - if (esp == NULL) { - log(LOG_ERR, - "%s: Could not create an event-state machine\n", - __FUNCTION__); - return NULL; - } - bzero(esp, sizeof(struct mip6_esm)); - - esp->next = NULL; - esp->ifp = ifp; - esp->ep = NULL; - esp->state = state; - esp->type = type; - esp->home_addr = *home_addr; - esp->prefix_len = prefix_len; - esp->ha_hn = *ha_hn; - esp->coa = *coa; - esp->ha_fn = NULL; - esp->dad = NULL; - - if (type == PERMANENT) { - esp->lifetime = 0xFFFF; - start_timer = 0; - } else { - esp->lifetime = lifetime; - start_timer = 1; - } - - /* If no TEMPORARY already exist and the new is TEMPORARY, start - the timer. */ - for (esp_tmp = mip6_esmq; esp_tmp; esp_tmp = esp_tmp->next) { - if (esp_tmp->type == TEMPORARY) - start_timer = 0; - } - - /* Insert entry as the first entry in the event-state machine list */ - s = splnet(); - if (mip6_esmq == NULL) - mip6_esmq = esp; - else { - esp->next = mip6_esmq; - mip6_esmq = esp; - } - splx(s); - - if (start_timer) { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - mip6_timer_esm_handle = -#endif - timeout(mip6_timer_esm, (void *)0, hz); - } - return esp; -} - - - -/* - ****************************************************************************** - * Function: mip6_esm_delete - * Description: Delete the requested event-state machine. - * Ret value: Ptr to next entry in list or NULL if last entry removed. - ****************************************************************************** - */ -struct mip6_esm * -mip6_esm_delete(esm_remove) -struct mip6_esm *esm_remove; /* Event-state machine to be deleted */ -{ - struct mip6_esm *esp; /* Current entry in event-state list */ - struct mip6_esm *esp_prev; /* Previous entry in event-state list */ - struct mip6_esm *esp_next; /* Next entry in the event-state list */ - int s; - - /* Find the requested entry in the event-state list. */ - s = splnet(); - esp_next = NULL; - esp_prev = NULL; - for (esp = mip6_esmq; esp; esp = esp->next) { - esp_next = esp->next; - if (esp == esm_remove) { - if (esp_prev == NULL) - mip6_esmq = esp->next; - else - esp_prev->next = esp->next; - - mip6_tunnel(NULL, NULL, MIP6_TUNNEL_DEL, MIP6_NODE_MN, - (void *)esp); - - if (esp->dad) { - if (esp->dad->hal) - _FREE(esp->dad->hal, M_TEMP); - _FREE(esp->dad, M_TEMP); - } - - if (esp->ha_fn) { - _FREE(esp->ha_fn, M_TEMP); - esp->ha_fn = NULL; - } - -#if MIP6_DEBUG - mip6_debug("\nEvent-state machine deleted (0x%x)\n", - esp); -#endif - _FREE(esp, M_TEMP); - - /* Remove the timer if the ESM queue is empty */ - if (mip6_esmq == NULL) { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - untimeout(mip6_timer_esm, (void *)NULL, - mip6_timer_esm_handle); - callout_handle_init(&mip6_timer_esm_handle); -#else - untimeout(mip6_timer_esm, (void *)NULL); -#endif - } - break; - } - esp_prev = esp; - } - splx(s); - return esp_next; -} - - - -/* - ****************************************************************************** - * Function: mip6_outq_create - * Description: Add an entry to the output queue and store the destination - * option and the sub-option (if present) to this entry. - * Ret value: 0 Everything is OK - * Otherwise appropriate error code - * Note: If the outqueue timeout function has not been started it is - * started. The outqueue timeout function will be called once - * every MIP6_OUTQ_INTERVAL second until there are no more entries - * in the list. - ****************************************************************************** - */ -int -mip6_outq_create(opt, subbuf, src_addr, dst_addr, flag) -void *opt; /* Destination option (BU, BR or BA) */ -struct mip6_subbuf *subbuf; /* Buffer containing destination sub-options */ -struct in6_addr *src_addr; /* Source address for the option */ -struct in6_addr *dst_addr; /* Destination address for the option */ -enum send_state flag; /* Flag indicating the state of the entry */ -{ - struct mip6_output *outp; /* Pointer to output list entry */ - int s; - - outp = (struct mip6_output *)MALLOC(sizeof(struct mip6_output), - M_TEMP, M_WAITOK); - if (outp == NULL) - return ENOBUFS; - bzero(outp, sizeof(struct mip6_output)); - - outp->next = NULL; - outp->opt = opt; - outp->subopt = subbuf; - outp->ip6_dst = *dst_addr; - outp->ip6_src = *src_addr; - outp->flag = flag; - outp->lifetime = MIP6_OUTQ_LIFETIME; - - s = splnet(); - if (mip6_outq == NULL) { - mip6_outq = outp; -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - mip6_timer_outqueue_handle = -#endif - timeout(mip6_timer_outqueue, (void *)0, - hz * (MIP6_OUTQ_INTERVAL/10)); - } else { - /* Add this entry as the first entry in the queue. */ - outp->next = mip6_outq; - mip6_outq = outp; - } - splx(s); - return 0; -} - - - -/* - ****************************************************************************** - * Function: mip6_outq_delete - * Description: Delete the requested output queue entry. - * Ret value: Ptr to next entry in list or NULL if last entry removed. - ****************************************************************************** - */ -struct mip6_output * -mip6_outq_delete(oqp_remove) -struct mip6_output *oqp_remove; /* Output queue entry to be deleted */ -{ - struct mip6_output *oqp; /* Current entry in output queue */ - struct mip6_output *oqp_prev; /* Previous entry in output queue */ - struct mip6_output *oqp_next; /* Next entry in the output queue */ - int s; - - /* Find the requested entry in the output queue. */ - s = splnet(); - oqp_next = NULL; - oqp_prev = NULL; - for (oqp = mip6_outq; oqp; oqp = oqp->next) { - oqp_next = oqp->next; - if (oqp == oqp_remove) { - if (oqp_prev == NULL) - mip6_outq = oqp->next; - else - oqp_prev->next = oqp->next; - - if (oqp->opt) - _FREE(oqp->opt, M_TEMP); - - if (oqp->subopt) - _FREE(oqp->subopt, M_TEMP); - -#if MIP6_DEBUG - mip6_debug("\nOutput Queue entry deleted (0x%x)\n", - oqp); -#endif - _FREE(oqp, M_TEMP); - - /* Remove the timer if the output queue is empty */ - if (mip6_outq == NULL) { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - untimeout(mip6_timer_outqueue, (void *)NULL, - mip6_timer_outqueue_handle); - callout_handle_init( - &mip6_timer_outqueue_handle); -#else - untimeout(mip6_timer_outqueue, (void *)NULL); -#endif - } - break; - } - oqp_prev = oqp; - } - splx(s); - return oqp_next; -} - - - -/* - ****************************************************************************** - * Function: mip6_outq_flush - * Description: All entries in the output queue that have not been sent are - * sent and then removed. No consideration of the time left for - * the entry is taken. - * Ret value: - - * XXX The code is almost the same as in mip6_timer_outqueue - ****************************************************************************** - */ -void -mip6_outq_flush() -{ - struct mip6_output *outp; /* Ptr to current mip6 output element */ - struct ip6_pktopts *pktopt; /* Packet Ext headers, options and data */ - struct mip6_opt *opt; /* Destination option */ - struct mbuf *m_ip6; /* IPv6 header stored in a mbuf */ - int error; /* Error code from function call */ - int off; /* Offset from start of DH (byte) */ - int s; - - /* Go through the entire output queue and send all packets that - have not been sent. */ - s = splnet(); - for (outp = mip6_outq; outp;) { - if (outp->flag == NOT_SENT) { - m_ip6 = mip6_create_ip6hdr(&outp->ip6_src, - &outp->ip6_dst, - IPPROTO_NONE); - if (m_ip6 == NULL) { - outp = outp->next; - continue; - } - - /* Allocate packet extension header. */ - pktopt = (struct ip6_pktopts *) - MALLOC(sizeof(struct ip6_pktopts), - M_TEMP, M_WAITOK); - if (pktopt == NULL) { - _FREE(m_ip6, M_TEMP); - outp = outp->next; - continue; - } - bzero(pktopt, sizeof(struct ip6_pktopts)); - pktopt->ip6po_hlim = -1; /* -1 use def hop limit */ - - opt = (struct mip6_opt *)outp->opt; - off = 2; - if (opt->type == IP6OPT_BINDING_UPDATE) { - /* Add my BU option to the Dest Header */ - error = mip6_add_bu(&pktopt->ip6po_dest2, - &off, - (struct mip6_opt_bu *) - outp->opt, - outp->subopt); - if (error) { - _FREE(m_ip6, M_TEMP); - _FREE(pktopt, M_TEMP); - outp = outp->next; - continue; - } - } else if (opt->type == IP6OPT_BINDING_ACK) { - /* Add my BA option to the Dest Header */ - error = mip6_add_ba(&pktopt->ip6po_dest2, - &off, - (struct mip6_opt_ba *) - outp->opt, - outp->subopt); - if (error) { - _FREE(m_ip6, M_TEMP); - _FREE(pktopt, M_TEMP); - outp = outp->next; - continue; - } - } else if (opt->type == IP6OPT_BINDING_REQ) { - /* Add my BR option to the Dest Header */ - error = mip6_add_br(&pktopt->ip6po_dest2, - &off, - (struct mip6_opt_br *) - outp->opt, - outp->subopt); - if (error) { - _FREE(m_ip6, M_TEMP); - _FREE(pktopt, M_TEMP); - outp = outp->next; - continue; - } - } - - /* Disable the search of the output queue to make - sure that we not end up in an infinite loop. */ - mip6_config.enable_outq = 0; - error = ip6_output(m_ip6, pktopt, NULL, 0, NULL, NULL); - if (error) { - _FREE(m_ip6, M_TEMP); - _FREE(pktopt, M_TEMP); - mip6_config.enable_outq = 1; - outp = outp->next; - log(LOG_ERR, - "%s: ip6_output function failed, " - "error = %d\n", __FUNCTION__, error); - continue; - } - mip6_config.enable_outq = 1; - outp->flag = SENT; -#if MIP6_DEBUG - mip6_debug("\nEntry from Output Queue sent\n"); -#endif - } - - /* Remove entry from the queue that has been sent. */ - if (outp->flag == SENT) - outp = mip6_outq_delete(outp); - else - outp = outp->next; - - /* Remove the timer if the output queue is empty */ - if (mip6_outq == NULL) { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - untimeout(mip6_timer_outqueue, (void *)NULL, - mip6_timer_outqueue_handle); - callout_handle_init(&mip6_timer_outqueue_handle); -#else - untimeout(mip6_timer_outqueue, (void *)NULL); -#endif - } - } - splx(s); -} - - - -/* - ############################################################################## - # - # TIMER FUNCTIONS - # These functions are called at regular basis. They operate on the lists, e.g. - # reducing timer counters and removing entries from the list if needed. - # - ############################################################################## - */ - -/* - ****************************************************************************** - * Function: mip6_timer_outqueue - * Description: Search the outqueue for entries that have not been sent yet and - * for which the lifetime has expired. - * If there are more entries left in the output queue, call this - * fuction again every MIP6_OUTQ_INTERVAL until the queue is - * empty. - * Ret value: - - ****************************************************************************** - */ -void -mip6_timer_outqueue(arg) -void *arg; /* Not used */ -{ - struct mip6_output *outp; /* Ptr to current mip6 output element */ - struct ip6_pktopts *pktopt; /* Packet Ext headers, options and data */ - struct mip6_opt *opt; /* Destination option */ - struct mbuf *m_ip6; /* IPv6 header stored in a mbuf */ - int error; /* Error code from function call */ - int off; /* Offset from start of DH (byte) */ - -#ifdef __APPLE__ - boolean_t funnel_state; - funnel_state = thread_funnel_set(network_flock, TRUE); -#endif - /* Go through the entire output queue and send all packets that - have not been sent. */ - for (outp = mip6_outq; outp;) { - if (outp->flag == NOT_SENT) - outp->lifetime -= MIP6_OUTQ_INTERVAL; - - if ((outp->flag == NOT_SENT) && (outp->lifetime <= 0)) { - m_ip6 = mip6_create_ip6hdr(&outp->ip6_src, - &outp->ip6_dst, - IPPROTO_NONE); - if (m_ip6 == NULL) { - outp = outp->next; - continue; - } - - /* Allocate packet extension header. */ - pktopt = (struct ip6_pktopts *) - MALLOC(sizeof(struct ip6_pktopts), - M_TEMP, M_WAITOK); - if (pktopt == NULL) { - _FREE(m_ip6, M_TEMP); - outp = outp->next; - continue; - } - bzero(pktopt, sizeof(struct ip6_pktopts)); - pktopt->ip6po_hlim = -1; /* -1 default hop limit */ - - opt = (struct mip6_opt *)outp->opt; - off = 2; - if (opt->type == IP6OPT_BINDING_UPDATE) { - /* Add my BU option to the Dest Header */ - error = mip6_add_bu(&pktopt->ip6po_dest2, - &off, - (struct mip6_opt_bu *) - outp->opt, - outp->subopt); - if (error) { - _FREE(m_ip6, M_TEMP); - _FREE(pktopt, M_TEMP); - outp = outp->next; - continue; - } - } else if (opt->type == IP6OPT_BINDING_ACK) { - /* Add my BA option to the Dest Header */ - error = mip6_add_ba(&pktopt->ip6po_dest2, - &off, - (struct mip6_opt_ba *) - outp->opt, - outp->subopt); - if (error) { - _FREE(m_ip6, M_TEMP); - _FREE(pktopt, M_TEMP); - outp = outp->next; - continue; - } - } else if (opt->type == IP6OPT_BINDING_REQ) { - /* Add my BR option to the Dest Header */ - error = mip6_add_br(&pktopt->ip6po_dest2, - &off, - (struct mip6_opt_br *) - outp->opt, - outp->subopt); - if (error) { - _FREE(m_ip6, M_TEMP); - _FREE(pktopt, M_TEMP); - outp = outp->next; - continue; - } - } - - /* Disable the search of the output queue to make - sure that we not end up in an infinite loop. */ - mip6_config.enable_outq = 0; - error = ip6_output(m_ip6, pktopt, NULL, 0, NULL, NULL); - if (error) { - _FREE(m_ip6, M_TEMP); - _FREE(pktopt, M_TEMP); - mip6_config.enable_outq = 1; - outp = outp->next; - log(LOG_ERR, - "%s: ip6_output function failed, " - "error = %d\n", __FUNCTION__, error); - continue; - } - mip6_config.enable_outq = 1; - outp->flag = SENT; -#if MIP6_DEBUG - mip6_debug("\nEntry from Output Queue sent\n"); -#endif - } - - /* Remove entry from the queue that has been sent. */ - if (outp->flag == SENT) - outp = mip6_outq_delete(outp); - else - outp = outp->next; - } - - if (mip6_outq != NULL) { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - mip6_timer_outqueue_handle = -#endif - timeout(mip6_timer_outqueue, (void *)0, - hz * (MIP6_OUTQ_INTERVAL/10)); - } -#ifdef __APPLE__ - (void) thread_funnel_set(network_flock, FALSE); -#endif -} - - - -/* - ****************************************************************************** - * Function: mip6_timer_bul - * Description: Search the Binding Update list for entries for which the life- - * time or refresh time has expired. - * If there are more entries left in the output queue, call this - * fuction again once every second until the queue is empty. - * Ret value: - - ****************************************************************************** - */ -void -mip6_timer_bul(arg) -void *arg; /* Not used */ -{ - struct mip6_bul *bulp; /* Ptr to current BUL element */ - struct mip6_bul *new_bulp; /* Pointer to new BUL entry */ - struct mip6_esm *esp; /* Home address entry */ - struct mip6_opt_bu *bu_opt; /* BU option to be sent */ - struct in6_addr *dst_addr; /* Destination address for BU */ - struct mip6_subbuf *subbuf; /* Buffer containing sub-options */ - struct mip6_bu_data bu_data; /* Data used when a BU is created */ - struct mip6_subopt_coa altcoa; /* Alternate care-of address */ - u_int32_t lifetime; - int max_index, s; -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) - long time_second = time.tv_sec; -#endif -#ifdef __APPLE__ - boolean_t funnel_state; - funnel_state = thread_funnel_set(network_flock, TRUE); -#endif - - /* Go through the entire BUL and check if any BU have to be sent. */ - subbuf = NULL; - s = splnet(); - for (bulp = mip6_bulq; bulp;) { - /* Find the correct event-state machine */ - esp = mip6_esm_find(&bulp->bind_addr); - if (esp == NULL) { - bulp = bulp->next; - continue; - } - - /* If infinity lifetime, don't decrement it. */ - if (bulp->lifetime == 0xffffffff) { - bulp = bulp->next; - continue; - } - - bulp->lifetime -= 1; - if (bulp->lifetime == 0) { - if ((bulp->hr_flag) && (esp->type == PERMANENT)) { - /* If this BUL entry is for the Home Agent - a new one must be created before the old - is deleted. The new entry shall try to - register the MN again. - This is not done for the previous default - router. */ - if ((esp->state == MIP6_STATE_REG) || - (esp->state == MIP6_STATE_REREG) || - (esp->state == MIP6_STATE_REGNEWCOA) || - (esp->state == MIP6_STATE_NOTREG)) - esp->state = MIP6_STATE_NOTREG; - else if ((esp->state == MIP6_STATE_HOME) || - (esp->state == MIP6_STATE_DEREG)) - esp->state = MIP6_STATE_DEREG; - else - esp->state = MIP6_STATE_UNDEF; - - /* If Dynamic Home Agent Address Discovery, - pick the dst address from the esp->dad list - and set index. */ - if (esp->dad) { - dst_addr = &esp->dad->hal-> - halist[esp->dad->index]; - max_index = (esp->dad->hal->len / - IP6OPT_HALEN) - 1; - if (esp->dad->index == max_index) - esp->dad->index = 0; - else - esp->dad->index += 1; - lifetime = MIP6_BU_LIFETIME_DHAAD; - } else { - dst_addr = &esp->ha_hn; - lifetime = mip6_config.hr_lifetime; - } - - /* Send BU to the decided destination */ - new_bulp = mip6_bul_create(dst_addr, - &esp->home_addr, - &bulp->coa, - lifetime, 1); - if (new_bulp == NULL) - break; - - bu_data.prefix_len = esp->prefix_len; - bu_data.ack = 1; - - if (mip6_send_bu(new_bulp, &bu_data, NULL) - != 0) - break; - } - - /* The BUL entry must be deleted. */ - bulp = mip6_bul_delete(bulp); - continue; - } - - if (bulp->refreshtime > 0) - bulp->refreshtime -= 1; - - /* Skip the bul entry if its not allowed to send any further - BUs to the host. */ - if (bulp->bu_flag == 0) { - bulp = bulp->next; - continue; - } - - /* Check if a BU has already been sent to the destination. */ - if (bulp->state != NULL) { - bulp->state->time_left -= 1; - if (bulp->state->time_left == 0) { - if (bulp->hr_flag) { - /* This is a BUL entry for the HA */ - bulp->state->bu_opt->lifetime = - bulp->lifetime; - bulp->state->bu_opt->seqno++; - if (mip6_send_bu(bulp, NULL, NULL) - != 0) - break; - - if (bulp->state->ba_timeout < - MIP6_MAX_BINDACK_TIMEOUT) - bulp->state->ba_timeout = - 2 * bulp->state-> - ba_timeout; - else - bulp->state->ba_timeout = - (u_int8_t)MIP6_MAX_BINDACK_TIMEOUT; - - bulp->state->time_left = bulp->state->ba_timeout; - } else { - /* This is a BUL entry for a Correspondent Node */ - if (bulp->state->ba_timeout >= MIP6_MAX_BINDACK_TIMEOUT) { - /* Do NOT continue to retransmit the BU */ - bulp->no_of_sent_bu = 0; - mip6_clear_retrans(bulp); - } else { - bulp->state->bu_opt->lifetime = bulp->lifetime; - bulp->state->bu_opt->seqno++; - if (mip6_send_bu(bulp, NULL, NULL) != 0) - break; - - bulp->state->ba_timeout = 2 * bulp->state->ba_timeout; - bulp->state->time_left = bulp->state->ba_timeout; - } - } - } - bulp = bulp->next; - continue; - } - - /* Refreshtime has expired and no BU has been sent to the HA - so far. Then we do it. */ - if (bulp->refreshtime == 0) { - /* Store sub-option for BU option. */ - altcoa.type = IP6SUBOPT_ALTCOA; - altcoa.len = IP6OPT_COALEN; - altcoa.coa = bulp->coa; - if (mip6_store_subopt(&subbuf, (caddr_t)&altcoa)) { - if (subbuf) - _FREE(subbuf, M_TEMP); - break; - } - - if (bulp->hr_flag) { - /* Since this is an entry for the Home Agent a new BU - is being sent for which we require the receiver to - respond with a BA. */ - bu_data.prefix_len = esp->prefix_len; - bu_data.ack = 1; - - bulp->lifetime = mip6_config.hr_lifetime; - if (mip6_send_bu(bulp, &bu_data, subbuf) != 0) - break; - } else { - /* This is an entry for a CN that has requested a BU to be - sent when the refreshtime expires. We will NOT require - this BU to be acknowledged. */ - bulp->seqno += 1; - bu_opt = mip6_create_bu(0, 0, 0, bulp->seqno, - mip6_config.hr_lifetime); - if (bu_opt == NULL) - break; - - bulp->lasttime = time_second; - mip6_outq_create(bu_opt, subbuf, &bulp->bind_addr, - &bulp->dst_addr, NOT_SENT); - } - bulp = bulp->next; - continue; - } - bulp = bulp->next; - } - - if (mip6_bulq != NULL) { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - mip6_timer_bul_handle = -#endif - timeout(mip6_timer_bul, (void *)0, hz); - } - splx(s); -#ifdef __APPLE__ - (void) thread_funnel_set(network_flock, FALSE); -#endif -} - - - -/* - ****************************************************************************** - * Function: mip6_timer_esm - * Description: This function is called when an event-state machine has been - * created for sending a BU to the previous default router. The - * event-state machine entry is needed for the correct addition - * of the home address option for outgoing packets. - * When the life time for the BU expires the event-state machine - * is removed as well. - * Ret value: - - ****************************************************************************** - */ -void -mip6_timer_esm(arg) -void *arg; /* Not used */ -{ - struct mip6_esm *esp; /* Current event-state machine entry */ - int s, start_timer; -#ifdef __APPLE__ - boolean_t funnel_state; - funnel_state = thread_funnel_set(network_flock, TRUE); -#endif - - /* Go through the entire list of event-state machines. */ - s = splnet(); - for (esp = mip6_esmq; esp;) { - if (esp->type == TEMPORARY) { - esp->lifetime -= 1; - - if (esp->lifetime == 0) - esp = mip6_esm_delete(esp); - else - esp = esp->next; - continue; - } - esp = esp->next; - } - - /* Only start the timer if there is a TEMPORARY machine in the list. */ - start_timer = 0; - for (esp = mip6_esmq; esp; esp = esp->next) { - if (esp->type == TEMPORARY) { - start_timer = 1; - break; - } - } - - if (start_timer) { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - mip6_timer_esm_handle = -#endif - timeout(mip6_timer_esm, (void *)0, hz); - } - splx(s); -#ifdef __APPLE__ - (void) thread_funnel_set(network_flock, FALSE); -#endif -} - - - -/* - ############################################################################## - # - # IOCTL FUNCTIONS - # These functions are called from mip6_ioctl. - # - ############################################################################## - */ - -/* - ****************************************************************************** - * Function: mip6_write_config_data_mn - * Description: This function is called to write certain config values for - * MIPv6. The data is written into the global config structure. - * Ret value: - - ****************************************************************************** - */ -int mip6_write_config_data_mn(u_long cmd, void *arg) -{ - struct mip6_esm *p; - struct ifnet *ifp; - struct mip6_input_data *input; - struct mip6_static_addr *np; - char ifn[10]; - int retval = 0; - struct in6_addr any = in6addr_any; - - switch (cmd) { - case SIOCACOADDR_MIP6: - input = (struct mip6_input_data *) arg; - np = (struct mip6_static_addr *) - MALLOC(sizeof(struct mip6_static_addr), - M_TEMP, M_WAITOK); - if (np == NULL) - return ENOBUFS; - - np->ip6_addr = input->ip6_addr; - np->prefix_len = input->prefix_len; - np->ifp = ifunit(input->if_name); - if (np->ifp == NULL) { - strncpy(ifn, input->if_name, sizeof(ifn)); - return EINVAL; - } - LIST_INSERT_HEAD(&mip6_config.fna_list, np, addr_entry); - break; - - case SIOCAHOMEADDR_MIP6: - input = (struct mip6_input_data *) arg; - ifp = ifunit(input->if_name); - if (ifp == NULL) - return EINVAL; - - p = mip6_esm_create(ifp, &input->ha_addr, &any, - &input->ip6_addr, input->prefix_len, - MIP6_STATE_UNDEF, PERMANENT, 0xFFFF); - if (p == NULL) - return EINVAL; /*XXX*/ - - break; - - case SIOCSBULIFETIME_MIP6: - mip6_config.bu_lifetime = ((struct mip6_input_data *)arg)->value; - break; - - case SIOCSHRLIFETIME_MIP6: - mip6_config.hr_lifetime = ((struct mip6_input_data *)arg)->value; - break; - - case SIOCDCOADDR_MIP6: - input = (struct mip6_input_data *) arg; - for (np = mip6_config.fna_list.lh_first; np != NULL; - np = np->addr_entry.le_next){ - if (IN6_ARE_ADDR_EQUAL(&input->ip6_addr, &np->ip6_addr)) - break; - } - if (np == NULL){ - retval = EADDRNOTAVAIL; - return retval; - } - LIST_REMOVE(np, addr_entry); - break; - } - return retval; -} - - - -/* - ****************************************************************************** - * Function: mip6_clear_config_data_mn - * Description: This function is called to clear internal lists handled by - * MIPv6. - * Ret value: - - ****************************************************************************** - */ -int mip6_clear_config_data_mn(u_long cmd, caddr_t data) -{ - int retval = 0; - int s; - - struct mip6_static_addr *np; - struct mip6_bul *bulp; - - s = splnet(); - switch (cmd) { - case SIOCSFORADDRFLUSH_MIP6: - for (np = LIST_FIRST(&mip6_config.fna_list); np; - np = LIST_NEXT(np, addr_entry)) { - LIST_REMOVE(np, addr_entry); - } - break; - - case SIOCSHADDRFLUSH_MIP6: - retval = EINVAL; - break; - - case SIOCSBULISTFLUSH_MIP6: - for (bulp = mip6_bulq; bulp;) - bulp = mip6_bul_delete(bulp); - break; - } - splx(s); - return retval; -} - - - -/* - ****************************************************************************** - * Function: mip6_enable_func_mn - * Description: This function is called to enable or disable certain functions - * in mip6. The data is written into the global config struct. - * Ret value: - - ****************************************************************************** - */ -int mip6_enable_func_mn(u_long cmd, caddr_t data) -{ - int enable; - int retval = 0; - - enable = ((struct mip6_input_data *)data)->value; - - switch (cmd) { - case SIOCSPROMMODE_MIP6: - mip6_config.enable_prom_mode = enable; - break; - - case SIOCSBU2CN_MIP6: - mip6_config.enable_bu_to_cn = enable; - break; - - case SIOCSREVTUNNEL_MIP6: - mip6_config.enable_rev_tunnel = enable; - break; - - case SIOCSAUTOCONFIG_MIP6: - mip6_config.autoconfig = enable; - break; - - case SIOCSEAGERMD_MIP6: - mip6_eager_md(enable); - break; - } - return retval; -} diff --git a/bsd/netinet6/mld6.c b/bsd/netinet6/mld6.c index 6117d50bc..3d90c11e4 100644 --- a/bsd/netinet6/mld6.c +++ b/bsd/netinet6/mld6.c @@ -1,4 +1,5 @@ -/* $KAME: mld6.c,v 1.17 2000/03/01 12:37:25 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/mld6.c,v 1.4.2.2 2001/07/03 11:01:54 ume Exp $ */ +/* $KAME: mld6.c,v 1.27 2001/04/04 05:17:30 itojun Exp $ */ /* * Copyright (C) 1998 WIDE Project. @@ -68,9 +69,6 @@ * @(#)igmp.c 8.1 (Berkeley) 7/19/93 */ -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#endif #include #include @@ -129,20 +127,15 @@ mld6_init() hbh_buf[5] = IP6OPT_RTALERT_LEN - 2; bcopy((caddr_t)&rtalert_code, &hbh_buf[6], sizeof(u_int16_t)); + init_ip6pktopts(&ip6_opts); ip6_opts.ip6po_hbh = hbh; - /* We will specify the hoplimit by a multicast option. */ - ip6_opts.ip6po_hlim = -1; } void mld6_start_listening(in6m) struct in6_multi *in6m; { -#ifdef __NetBSD__ - int s = splsoftnet(); -#else int s = splnet(); -#endif /* * RFC2710 page 10: @@ -193,36 +186,37 @@ mld6_input(m, off) struct ifnet *ifp = m->m_pkthdr.rcvif; struct in6_multi *in6m; struct in6_ifaddr *ia; -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) struct ifmultiaddr *ifma; -#endif int timer; /* timer value in the MLD query header */ +#ifndef PULLDOWN_TEST + IP6_EXTHDR_CHECK(m, off, sizeof(*mldh),); + mldh = (struct mld6_hdr *)(mtod(m, caddr_t) + off); +#else + IP6_EXTHDR_GET(mldh, struct mld6_hdr *, m, off, sizeof(*mldh)); + if (mldh == NULL) { + icmp6stat.icp6s_tooshort++; + return; + } +#endif + /* source address validation */ + ip6 = mtod(m, struct ip6_hdr *);/* in case mpullup */ if (!IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src)) { log(LOG_ERR, - "mld6_input: src %s is not link-local\n", - ip6_sprintf(&ip6->ip6_src)); + "mld6_input: src %s is not link-local (grp=%s)\n", + ip6_sprintf(&ip6->ip6_src), + ip6_sprintf(&mldh->mld6_addr)); /* * spec (RFC2710) does not explicitly * specify to discard the packet from a non link-local * source address. But we believe it's expected to do so. + * XXX: do we have to allow :: as source? */ m_freem(m); return; } -#ifndef PULLDOWN_TEST - IP6_EXTHDR_CHECK(m, off, sizeof(*mldh),); - mldh = (struct mld6_hdr *)(mtod(m, caddr_t) + off); -#else - IP6_EXTHDR_GET(mldh, struct mld6_hdr *, m, off, sizeof(*mldh)); - if (mldh == NULL) { - icmp6stat.icp6s_tooshort++; - return; - } -#endif - /* * In the MLD6 specification, there are 3 states and a flag. * @@ -240,7 +234,7 @@ mld6_input(m, off) break; if (!IN6_IS_ADDR_UNSPECIFIED(&mldh->mld6_addr) && - !IN6_IS_ADDR_MULTICAST(&mldh->mld6_addr)) + !IN6_IS_ADDR_MULTICAST(&mldh->mld6_addr)) break; /* print error or log stat? */ if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld6_addr)) mldh->mld6_addr.s6_addr16[1] = @@ -272,15 +266,8 @@ mld6_input(m, off) mld6_all_nodes_linklocal.s6_addr16[1] = htons(ifp->if_index); /* XXX */ -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) -#else - for (in6m = ia->ia6_multiaddrs.lh_first; - in6m; - in6m = in6m->in6m_entry.le_next) -#endif { -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) if (ifma->ifma_addr->sa_family != AF_INET6) continue; in6m = (struct in6_multi *)ifma->ifma_protospec; @@ -289,13 +276,6 @@ mld6_input(m, off) IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) < IPV6_ADDR_SCOPE_LINKLOCAL) continue; -#else - if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, - &mld6_all_nodes_linklocal) || - IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) < - IPV6_ADDR_SCOPE_LINKLOCAL) - continue; -#endif if (IN6_IS_ADDR_UNSPECIFIED(&mldh->mld6_addr) || IN6_ARE_ADDR_EQUAL(&mldh->mld6_addr, @@ -363,7 +343,7 @@ mld6_input(m, off) void mld6_fasttimeo() { - register struct in6_multi *in6m; + struct in6_multi *in6m; struct in6_multistep step; int s; @@ -374,11 +354,7 @@ mld6_fasttimeo() if (!mld6_timers_are_running) return; -#ifdef __NetBSD__ - s = splsoftnet(); -#else s = splnet(); -#endif mld6_timers_are_running = 0; IN6_FIRST_MULTI(step, in6m); while (in6m != NULL) { @@ -432,6 +408,7 @@ mld6_sendpkt(in6m, type, dst) } mh->m_next = md; + mh->m_pkthdr.rcvif = NULL; mh->m_pkthdr.len = sizeof(struct ip6_hdr) + sizeof(struct mld6_hdr); mh->m_len = sizeof(struct ip6_hdr); MH_ALIGN(mh, sizeof(struct ip6_hdr)); @@ -479,16 +456,16 @@ mld6_sendpkt(in6m, type, dst) ip6_output(mh, &ip6_opts, NULL, 0, &im6o, &outif); if (outif) { icmp6_ifstat_inc(outif, ifs6_out_msg); - switch(type) { - case MLD6_LISTENER_QUERY: - icmp6_ifstat_inc(outif, ifs6_out_mldquery); - break; - case MLD6_LISTENER_REPORT: - icmp6_ifstat_inc(outif, ifs6_out_mldreport); - break; - case MLD6_LISTENER_DONE: - icmp6_ifstat_inc(outif, ifs6_out_mlddone); - break; + switch (type) { + case MLD6_LISTENER_QUERY: + icmp6_ifstat_inc(outif, ifs6_out_mldquery); + break; + case MLD6_LISTENER_REPORT: + icmp6_ifstat_inc(outif, ifs6_out_mldreport); + break; + case MLD6_LISTENER_DONE: + icmp6_ifstat_inc(outif, ifs6_out_mlddone); + break; } } } diff --git a/bsd/netinet6/mld6_var.h b/bsd/netinet6/mld6_var.h index a9f467e4b..dd252c18a 100644 --- a/bsd/netinet6/mld6_var.h +++ b/bsd/netinet6/mld6_var.h @@ -1,3 +1,6 @@ +/* $FreeBSD: src/sys/netinet6/mld6_var.h,v 1.1.2.1 2000/07/15 07:14:36 kris Exp $ */ +/* $KAME: mld6_var.h,v 1.4 2000/03/25 07:23:54 sumikawa Exp $ */ + /* * Copyright (C) 1998 WIDE Project. * All rights reserved. @@ -29,8 +32,10 @@ #ifndef _NETINET6_MLD6_VAR_H_ #define _NETINET6_MLD6_VAR_H_ +#include -#if KERNEL +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE #define MLD6_RANDOM_DELAY(X) (random() % (X) + 1) @@ -45,6 +50,7 @@ void mld6_input __P((struct mbuf *, int)); void mld6_start_listening __P((struct in6_multi *)); void mld6_stop_listening __P((struct in6_multi *)); void mld6_fasttimeo __P((void)); +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ #endif /* _NETINET6_MLD6_VAR_H_ */ diff --git a/bsd/netinet6/natpt_defs.h b/bsd/netinet6/natpt_defs.h deleted file mode 100644 index 39fa41c4f..000000000 --- a/bsd/netinet6/natpt_defs.h +++ /dev/null @@ -1,319 +0,0 @@ -/* $KAME: natpt_defs.h,v 1.7 2000/03/25 07:23:54 sumikawa Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#define SAME (0) - -#define NATPT_MAXHASH (397) -#define MAXTSLOTENTRY (4096) - -#define SZSIN6 sizeof(struct sockaddr_in6) -#define SZSIN sizeof(struct sockaddr_in) - -#define CAR(p) ((p)->car) -#define CDR(p) ((p)->cdr) -#define CAAR(p) (CAR(CAR(p))) -#define CADR(p) (CAR(CDR(p))) -#define CDAR(p) (CDR(CAR(p))) -#define CDDR(p) (CDR(CDR(p))) - -#ifndef TCP6 -#define tcp6hdr tcphdr -#endif - - -#if defined(NATPT_ASSERT) && (NATPT_ASSERT != 0) -# if defined(__STDC__) -# define ASSERT(e) ((e) ? (void)0 : natpt_assert(__FILE__, __LINE__, #e)) -# else /* PCC */ -# define ASSERT(e) ((e) ? (void)0 : natpt_assert(__FILE__, __LINE__, "e")) -# endif -#else -# undef NATPT_ASSERT -# define ASSERT(e) ((void)0) -#endif - - -#define IN4_ARE_ADDR_EQUAL(a, b) \ - ((a)->s_addr == (b)->s_addr) - - -#define ReturnEnobufs(m) if (m == NULL) { errno = ENOBUFS; return (NULL); } - - -#if (defined(KERNEL)) || (defined(_KERNEL)) - -#define isDebug(d) (natpt_debug & (d)) -#define isDump(d) (natpt_dump & (d)) - -#define D_DIVEIN4 0x00000001 -#define D_PEEKOUTGOINGV4 0x00000002 -#define D_TRANSLATINGIPV4 0x00000010 -#define D_TRANSLATEDIPV4 0x00001000 - -#define D_DIVEIN6 0x00010000 -#define D_IN6REJECT 0x00020000 -#define D_IN6ACCEPT 0x00040000 -#define D_PEEKOUTGOINGV6 0x00080000 -#define D_TRANSLATINGIPV6 0x00100000 -#define D_TRANSLATEDIPV6 0x01000000 - -#define fixSuMiReICMPBug (1) - -#ifdef fixSuMiReICMPBug -#define IPDST (0xc48db2cb) /* == 203.178.141.196 XXX */ -#define ICMPSRC (0x02c410ac) /* == 172.16.196.2 XXX */ -#endif - -#endif /* defined(KERNEL) */ - -/* - * OS dependencies - */ - -#ifdef KERNEL - -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) -#define rcb_list list -#endif - -#ifdef __NetBSD__ -/* - * Macros for type conversion - * dtom(x) - convert data pointer within mbuf to mbuf pointer (XXX) - */ -#define dtom(x) ((struct mbuf *)((long)(x) & ~(MSIZE-1))) -#endif - -#endif /* _KERNEL */ - - -/* - * Structure definitions. - */ - -typedef struct _cell -{ - struct _cell *car; - struct _cell *cdr; -} Cell; - - -/* Interface Box structure */ - -struct ifBox -{ - int side; -#define noSide (0) -#define inSide (1) -#define outSide (2) - char ifName[IFNAMSIZ]; - struct ifnet *ifnet; -}; - - -/* IP ... */ - -struct _cv /* 28[byte] */ -{ - u_char ip_p; /* IPPROTO_(ICMP[46]|TCP|UDP) */ - u_char ip_payload; /* IPPROTO_(ICMP|TCP|UDP) */ - - u_char inout; -/* #define NATPT_UNSPEC (0) */ -/* #define NATPT_INBOUND (1) */ -/* #define NATPT_OUTBOUND (2) */ - - u_char flags; -#define NATPT_TRACEROUTE (0x01) -#define NATPT_NEEDFRAGMENT (0x02) - - int poff; /* payload offset */ - int plen; /* payload length */ - - struct mbuf *m; - struct _tSlot *ats; - union - { - struct ip *_ip4; - struct ip6_hdr *_ip6; - } _ip; - union - { - caddr_t _caddr; - struct icmp *_icmp4; - struct icmp6_hdr *_icmp6; - struct tcphdr *_tcp4; - struct tcp6hdr *_tcp6; - struct udphdr *_udp; - } _payload; -}; - - -/* IP address structure */ - -union inaddr /* sizeof(): 16[byte] */ -{ - struct in_addr in4; - struct in6_addr in6; -}; - - -struct pAddr /* sizeof(): 44[byte] */ -{ - u_char ip_p; /* protocol family (within struct _tSlot) */ - u_char sa_family; /* address family (within struct _cSlot) */ - - u_short port[2]; -#define _port0 port[0] -#define _port1 port[1] - -#define _sport port[0] -#define _dport port[1] -#define _eport port[1] - - union inaddr addr[2]; - -#define in4src addr[0].in4 -#define in4dst addr[1].in4 -#define in4Addr addr[0].in4 -#define in4Mask addr[1].in4 -#define in4RangeStart addr[0].in4 -#define in4RangeEnd addr[1].in4 - -#define in6src addr[0].in6 -#define in6dst addr[1].in6 -#define in6Addr addr[0].in6 -#define in6Mask addr[1].in6 - - struct - { - u_char type; -#define ADDR_ANY (0) -#define ADDR_SINGLE (1) -#define ADDR_MASK (2) -#define ADDR_RANGE (3) -#define ADDR_FAITH (4) - - u_char prefix; - } ad; -}; - - -/* Configuration slot entry */ - -struct _cSlot /* sizeof(): 100[byte] */ -{ - u_char flags; -#define NATPT_STATIC (1) /* Rule was set statically */ -#define NATPT_DYNAMIC (2) /* Rule was set dynamically */ -#define NATPT_FAITH (3) - - u_char dir; -#define NATPT_UNSPEC (0) -#define NATPT_INBOUND (1) -#define NATPT_OUTBOUND (2) - - u_char map; -#define NATPT_PORT_MAP (0x01) /* Mapping dest port */ -#define NATPT_PORT_MAP_DYNAMIC (0x02) /* Mapping dest port dynamically */ -#define NATPT_ADDR_MAP (0x04) /* Mapping dest addr */ -#define NATPT_ADDR_MAP_DYNAMIC (0x08) /* Mapping dest addr dynamically */ - - u_char proto; - - u_short prefix; - u_short cport; /* current port */ - - struct pAddr local, remote; - struct _cSlotAux *aux; /* place holder */ -}; - - -#if 0 -/* Configuration slot auxiliary entry */ -/* currently not used */ - -struct _cSlotAux /* sizeof(): 0[byte] */ -{ -}; -#endif - - -/* Translation slot entry */ - -struct _tSlot /* sizeof(): 104[byte] */ -{ - u_char ip_payload; - - u_char session; -/* #define NATPT_UNSPEC (0) */ -/* #define NATPT_INBOUND (1) */ -/* #define NATPT_OUTBOUND (2) */ - - u_char remap; -/* #define NATPT_PORT_REMAP (0x01) */ -/* #define NATPT_ADDR_REMAP (0x02) */ - -/* #define NATPT_STATIC (0x1) */ -/* #define NATPT_DYNAMIC (0x2) */ -/* #define NATPT_FAITH (0x3) */ - - struct pAddr local; - struct pAddr remote; - time_t tstamp; - int lcount; - - union - { - struct _idseq - { - n_short icd_id; - n_short icd_seq; - } ih_idseq; - struct _tcpstate *tcp; - } suit; -}; - - -struct _tcpstate /* sizeof(): 28[byte] */ -{ - short _state; - short _session; - u_long _ip_id[2]; /* IP packet Identification */ - /* [0]: current packet */ - /* [1]: just before packet */ - u_short _port[2]; /* [0]:outGoing srcPort, [1]:inComing dstPort */ -/* u_long _iss; initial send sequence number */ - u_long _delta[3]; /* Sequence delta */ - /* [0]: current (cumulative) */ - /* [1]: just before (cumulative) */ - /* [2]: (this time) */ -}; diff --git a/bsd/netinet6/natpt_dispatch.c b/bsd/netinet6/natpt_dispatch.c deleted file mode 100644 index 22d775f3f..000000000 --- a/bsd/netinet6/natpt_dispatch.c +++ /dev/null @@ -1,718 +0,0 @@ -/* $KAME: natpt_dispatch.c,v 1.9 2000/03/25 07:23:54 sumikawa Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include - -#ifdef __FreeBSD__ -# include -#endif - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - - -/* - * - */ - -u_int natpt_debug; -u_int natpt_dump; - -static struct _cell *ifBox; - -struct ifnet *natpt_ip6src; - -struct in6_addr faith_prefix - = {{{0x00000000, 0x00000000, 0x00000000, 0x00000000}}}; -struct in6_addr faith_prefixmask - = {{{0x00000000, 0x00000000, 0x00000000, 0x00000000}}}; -struct in6_addr natpt_prefix - = {{{0x00000000, 0x00000000, 0x00000000, 0x00000000}}}; -struct in6_addr natpt_prefixmask - = {{{0x00000000, 0x00000000, 0x00000000, 0x00000000}}}; - -int natpt_in4 __P((struct mbuf *, struct mbuf **)); -int natpt_in6 __P((struct mbuf *, struct mbuf **)); -int natpt_out4 __P((struct mbuf *, struct mbuf **)); -int natpt_out6 __P((struct mbuf *, struct mbuf **)); -int natpt_incomingIPv4 __P((int, struct mbuf *, struct mbuf **)); -int natpt_outgoingIPv4 __P((int, struct mbuf *, struct mbuf **)); -int natpt_incomingIPv6 __P((int, struct mbuf *, struct mbuf **)); -int natpt_outgoingIPv6 __P((int, struct mbuf *, struct mbuf **)); - -int configCv4 __P((int, struct mbuf *, struct _cv *)); -int configCv6 __P((int, struct mbuf *, struct _cv *)); -caddr_t foundFinalPayload __P((struct mbuf *, int *, int *)); -int sanityCheckIn4 __P((struct _cv *)); -int sanityCheckOut6 __P((struct _cv *)); -int checkMTU __P((struct _cv *)); - - -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -static MALLOC_DEFINE(M_NATPT, "NATPT", "Network Address Translation - Protocol Translation"); -#endif - - -/* - * - */ - -int -natpt_in4(struct mbuf *m4, struct mbuf **m6) -{ - Cell *p; - struct ifnet *ifnet; - struct ifBox *ifb; - int rv = IPPROTO_IP; - - if (natpt_initialized == 0) - return (IPPROTO_IP); /* goto ours */ - - if (isDump(D_DIVEIN4)) - natpt_logMBuf(LOG_DEBUG, m4, "dive into natpt_in4."); - - ifnet = m4->m_pkthdr.rcvif; - for (p = ifBox; p; p = CDR(p)) - { - ifb = (struct ifBox *)CAR(p); - if (ifb->ifnet == ifnet) - { - if (ifb->side == outSide) - rv = natpt_incomingIPv4(NATPT_INBOUND, m4, m6); - else - rv = natpt_outgoingIPv4(NATPT_OUTBOUND, m4, m6); - goto exit; - } - } - - exit:; - return (rv); -} - - -int -natpt_in6(struct mbuf *m6, struct mbuf **m4) -{ - Cell *p; - struct ifnet *ifnet; - struct ifBox *ifb; - struct ip6_hdr *ip6; - struct in6_addr cand; - int rv = IPPROTO_IP; - - if (natpt_initialized == 0) - return (IPPROTO_IP); /* goto mcastcheck */ - - if (isDump(D_DIVEIN6)) - natpt_logMBuf(LOG_DEBUG, m6, "dive into natpt_in6."); - - ip6 = mtod(m6, struct ip6_hdr *); - - cand.s6_addr32[0] = ip6->ip6_dst.s6_addr32[0] & natpt_prefixmask.s6_addr32[0]; - cand.s6_addr32[1] = ip6->ip6_dst.s6_addr32[1] & natpt_prefixmask.s6_addr32[1]; - cand.s6_addr32[2] = ip6->ip6_dst.s6_addr32[2] & natpt_prefixmask.s6_addr32[2]; - cand.s6_addr32[3] = ip6->ip6_dst.s6_addr32[3] & natpt_prefixmask.s6_addr32[3]; - - if ((cand.s6_addr32[0] != natpt_prefix.s6_addr32[0]) - || (cand.s6_addr32[1] != natpt_prefix.s6_addr32[1]) - || (cand.s6_addr32[2] != natpt_prefix.s6_addr32[2]) - || (cand.s6_addr32[3] != natpt_prefix.s6_addr32[3])) - { - if (isDump(D_IN6REJECT)) - natpt_logMBuf(LOG_DEBUG, m6, "v6 translation rejected."); - - return (IPPROTO_IP); /* goto mcastcheck */ - } - - if (isDump(D_IN6ACCEPT)) - natpt_logMBuf(LOG_DEBUG, m6, "v6 translation start."); - - ifnet = m6->m_pkthdr.rcvif; - for (p = ifBox; p; p = CDR(p)) - { - ifb = (struct ifBox *)CAR(p); - if (ifb->ifnet == ifnet) - { - if (ifb->side == outSide) - rv = natpt_incomingIPv6(NATPT_INBOUND, m6, m4); - else - rv = natpt_outgoingIPv6(NATPT_OUTBOUND, m6, m4); - goto exit; - } - } - - exit:; - return (rv); -} - - -int -natpt_out4(struct mbuf *m4, struct mbuf **m6) -{ - Cell *p; - struct ifnet *ifnet; - struct ifBox *ifb; - int rv = IPPROTO_IP; - - ifnet = m4->m_pkthdr.rcvif; - for (p = ifBox; p; p = CDR(p)) - { - ifb = (struct ifBox *)CAR(p); - if (ifb->ifnet == ifnet) - { - if (ifb->side == outSide) - rv = natpt_outgoingIPv4(NATPT_OUTBOUND, m4, m6); - else - rv = natpt_incomingIPv4(NATPT_INBOUND, m4, m6); - goto exit; - } - } - - exit:; - return (rv); -} - - - -int -natpt_out6(struct mbuf *m6, struct mbuf **m4) -{ - Cell *p; - struct ifnet *ifnet; - struct ifBox *ifb; - int rv = IPPROTO_IP; - - ifnet = m6->m_pkthdr.rcvif; - for (p = ifBox; p; p = CDR(p)) - { - ifb = (struct ifBox *)CAR(p); - if (ifb->ifnet == ifnet) - { - if (ifb->side == outSide) - rv = natpt_outgoingIPv6(NATPT_OUTBOUND, m6, m4); - else - rv = natpt_incomingIPv6(NATPT_INBOUND, m6, m4); - goto exit; - } - } - - exit:; - return (rv); -} - - -int -natpt_incomingIPv4(int sess, struct mbuf *m4, struct mbuf **m6) -{ - int rv; - struct _cv cv; - struct _cSlot *acs; - struct _tSlot *ats; - - if ((rv = configCv4(sess, m4, &cv)) == IPPROTO_MAX) - return (IPPROTO_MAX); /* discard this packet */ - - if ((rv = sanityCheckIn4(&cv)) != IPPROTO_IPV4) - return (IPPROTO_DONE); /* discard this packet without free */ - - cv.ats = lookingForIncomingV4Hash(&cv); - if ((ats = checkTraceroute6Return(&cv)) != NULL) - cv.ats = ats; - - if (cv.ats == NULL) - { - if ((acs = lookingForIncomingV4Rule(&cv)) == NULL) - return (IPPROTO_IP); /* goto ours */ - - if ((cv.ats = internIncomingV4Hash(sess, acs, &cv)) == NULL) - return (IPPROTO_IP); /* goto ours */ - } - - if (checkMTU(&cv) != IPPROTO_IPV4) - return (IPPROTO_DONE); /* discard this packet without free */ - -#ifdef NATPT_NAT - if (cv.ats->local.sa_family == AF_INET) - { - if ((*m6 = translatingIPv4To4(&cv, &cv.ats->local)) != NULL) - return (IPPROTO_IPV4); - } - else -#endif - { - if ((*m6 = translatingIPv4To6(&cv, &cv.ats->local)) != NULL) - return (IPPROTO_IPV6); - } - - return (IPPROTO_MAX); /* discard this packet */ -} - - -int -natpt_outgoingIPv4(int sess, struct mbuf *m4, struct mbuf **m6) -{ - int rv; - struct _cv cv; - struct _cSlot *acs; - struct ip *ip4; - - if ((rv = configCv4(sess, m4, &cv)) == IPPROTO_MAX) - return (IPPROTO_MAX); /* discard this packet */ - - if ((cv.ats = lookingForOutgoingV4Hash(&cv)) == NULL) - { - if ((acs = lookingForOutgoingV4Rule(&cv)) == NULL) - return (IPPROTO_IP); /* goto ours */ - - ip4 = mtod(m4, struct ip *); - if (ip4->ip_ttl <= IPTTLDEC) - { - n_long dest = 0; - - icmp_error(m4, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, dest, 0); - return (IPPROTO_MAX); /* discard this packet */ - } - - if ((cv.ats = internOutgoingV4Hash(sess, acs, &cv)) == NULL) - return (IPPROTO_IP); /* goto ours */ - } - -#ifdef NATPT_NAT - if (cv.ats->remote.sa_family == AF_INET) - { - if ((*m6 = translatingIPv4To4(&cv, &cv.ats->remote)) != NULL) - return (IPPROTO_IPV4); - } - else -#endif - { - if ((*m6 = translatingIPv4To6(&cv, &cv.ats->remote)) != NULL) - return (IPPROTO_IPV6); - } - - return (IPPROTO_MAX); /* discard this packet */ -} - - -int -natpt_incomingIPv6(int sess, struct mbuf *m6, struct mbuf **m4) -{ - int rv; - struct _cv cv; - struct _cSlot *acs; - struct ip6_hdr *ip6; - - rv = configCv6(sess, m6, &cv); - if ((rv == IPPROTO_IP) || (rv == IPPROTO_MAX) || (rv == IPPROTO_DONE)) - return (rv); - - if ((cv.ats = lookingForIncomingV6Hash(&cv)) == NULL) - { - if ((acs = lookingForIncomingV6Rule(&cv)) == NULL) - return (IPPROTO_IP); /* goto mcastcheck */ - - ip6 = mtod(m6, struct ip6_hdr *); - if (ip6->ip6_hlim <= IPV6_HLIMDEC) - { - icmp6_error(m6, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT, 0); - return (IPPROTO_MAX); /* discard this packet */ - } - - if ((cv.ats = internIncomingV6Hash(sess, acs, &cv)) == NULL) - return (IPPROTO_IP); /* goto mcastcheck */ - } - - if ((*m4 = translatingIPv6To4(&cv, &cv.ats->local)) != NULL) - return (IPPROTO_IPV4); - - return (IPPROTO_MAX); /* discard this packet */ -} - - -int -natpt_outgoingIPv6(int sess, struct mbuf *m6, struct mbuf **m4) -{ - int rv; - struct _cv cv6; - struct _cSlot *acs; - - rv = configCv6(sess, m6, &cv6); - if ((rv == IPPROTO_IP) || (rv == IPPROTO_MAX) || (rv == IPPROTO_DONE)) - return (rv); - - if ((rv = sanityCheckOut6(&cv6)) != IPPROTO_IPV6) - return (IPPROTO_DONE); /* discard this packet */ - - if (isDump(D_PEEKOUTGOINGV6)) - natpt_logIp6(LOG_DEBUG, cv6._ip._ip6); - - if ((cv6.ats = lookingForOutgoingV6Hash(&cv6)) == NULL) - { - if ((acs = lookingForOutgoingV6Rule(&cv6)) == NULL) - return (IPPROTO_IP); /* goto mcastcheck */ - - if ((cv6.ats = internOutgoingV6Hash(sess, acs, &cv6)) == NULL) - return (IPPROTO_IP); /* goto mcastcheck */ - } - - if ((*m4 = translatingIPv6To4(&cv6, &cv6.ats->remote)) != NULL) - return (IPPROTO_IPV4); - - return (IPPROTO_MAX); /* discard this packet */ -} - - -int -configCv4(int sess, struct mbuf *m, struct _cv *cv) -{ - struct ip *ip = mtod(m, struct ip *); - - bzero(cv, sizeof(struct _cv)); - cv->ip_p = ip->ip_p; - cv->m = m; - cv->_ip._ip4 = ip; - cv->inout = sess; - - switch (ip->ip_p) - { - case IPPROTO_ICMP: - case IPPROTO_TCP: - case IPPROTO_UDP: - cv->ip_payload = ip->ip_p; - cv->_payload._caddr = (caddr_t)((u_long *)ip + ip->ip_hl); - cv->poff = cv->_payload._caddr - (caddr_t)cv->_ip._ip4; - cv->plen = (caddr_t)m->m_data + m->m_len - cv->_payload._caddr; - return (ip->ip_p); - } - - return (IPPROTO_MAX); -} - - -int -configCv6(int sess, struct mbuf *m, struct _cv *cv) -{ - int proto; - int offset; - caddr_t tcpudp; - - bzero(cv, sizeof(struct _cv)); - cv->m = m; - cv->_ip._ip6 = mtod(m, struct ip6_hdr *); - cv->inout = sess; - - if ((tcpudp = foundFinalPayload(m, &proto, &offset))) - { - switch (proto) - { - case IPPROTO_ICMP: - case IPPROTO_ICMPV6: - case IPPROTO_TCP: - case IPPROTO_UDP: - cv->ip_p = proto; - cv->ip_payload = proto; - if (proto == IPPROTO_ICMPV6) - cv->ip_payload = IPPROTO_ICMP; - cv->_payload._caddr = tcpudp; - cv->poff = offset; - cv->plen = (caddr_t)m->m_data + m->m_len - cv->_payload._caddr; - return (proto); - } - } - - return (proto); -} - - -caddr_t -foundFinalPayload(struct mbuf *m, int *proto, int *offset) -{ - int nxt; - int off; - struct ip6_hdr *ip6; - struct ip6_ext *ip6ext; - - ip6 = mtod(m, struct ip6_hdr *); - nxt = ip6->ip6_nxt; - off = sizeof(struct ip6_hdr); - ip6ext = (struct ip6_ext *)((struct ip6_hdr *)(ip6 + 1)); - while (nxt != IPPROTO_NONE && off + sizeof(*ip6ext) < m->m_len) - { - switch (nxt) - { - case IPPROTO_HOPOPTS: - case IPPROTO_ROUTING: -#if 0 - case IPPROTO_FRAGMENT: -#endif - case IPPROTO_DSTOPTS: - nxt = ip6ext->ip6e_nxt; - off += ip6ext->ip6e_len; - ip6ext = (struct ip6_ext *)(((caddr_t)ip6ext) + ip6ext->ip6e_len); - break; - - case IPPROTO_ICMPV6: - case IPPROTO_TCP: - case IPPROTO_UDP: - *proto = nxt; - *offset = off; - return ((caddr_t)ip6ext); - - default: - *proto = IPPROTO_IP; /* goto mcastcheck */ - *offset = off; - return (NULL); - } - } - - *proto = IPPROTO_IP; /* goto mcastcheck */ - *offset = off; - return (NULL); -} - - -int -sanityCheckIn4(struct _cv *cv4) -{ - struct mbuf *m4 = cv4->m; - struct ip *ip4 = mtod(m4, struct ip *); - - if (ip4->ip_ttl <= IPTTLDEC) - { - n_long dest = 0; - - icmp_error(m4, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, dest, 0); - return (IPPROTO_DONE); /* discard this packet without free */ - } - - return (IPPROTO_IPV4); -} - - -int -sanityCheckOut6(struct _cv *cv6) -{ - struct mbuf *m6 = cv6->m; - struct ip6_hdr *ip6 = mtod(m6, struct ip6_hdr *); - - if (ip6->ip6_hlim <= IPV6_HLIMDEC) - { - icmp6_error(m6, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT, 0); - return (IPPROTO_DONE); /* discard this packet */ - } - - return (IPPROTO_IPV6); -} - - -int -checkMTU(struct _cv *cv4) -{ - int mmtu; - struct mbuf *m4 = cv4->m; - struct ip *ip4 = mtod(m4, struct ip *); - - mmtu = IPV6_MMTU - sizeof(struct ip6_hdr) - sizeof(struct ip6_frag); - /* This should be 1232[byte] */ - - if ((m4->m_flags & M_PKTHDR) - && (m4->m_pkthdr.len >= mmtu)) - { - if (ip4->ip_off & IP_DF) - { - n_long dest = 0; - struct ifnet destif; - - bzero(&destif, sizeof(struct ifnet)); - destif.if_mtu = mmtu; - -#ifdef fixSuMiReICMPBug - ip4->ip_dst.s_addr = IPDST; /* XXX */ -#endif - - icmp_error(m4, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, dest, &destif); - return (IPPROTO_DONE); /* discard this packet without free */ - } - - cv4->flags |= NATPT_NEEDFRAGMENT; /* fragment, then translate */ - } - - return (IPPROTO_IPV4); -} - - -/* - * - */ - - -struct ifBox * -natpt_asIfBox(char *ifName) -{ - Cell *p; - - for (p = ifBox; p; p = CDR(p)) - { - if (strcmp(ifName, ((struct ifBox *)CAR(p))->ifName) == SAME) - return ((struct ifBox *)CAR(p)); - } - - return (NULL); -} - - -struct ifBox * -natpt_setIfBox(char *ifName) -{ - struct ifnet *p; - struct ifBox *q; - char Wow[IFNAMSIZ]; - -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (p = ifnet; p; p = p->if_next) -#else - for (p = TAILQ_FIRST(&ifnet); p; p = TAILQ_NEXT(p, if_list)) -#endif - { -#ifdef __NetBSD__ - sprintf(Wow, "%s%c", p->if_xname, '\0'); -#else - sprintf(Wow, "%s%d%c", p->if_name, p->if_unit, '\0'); -#endif - if (strcmp(ifName, Wow) != SAME) - continue; - - natpt_ip6src = p; - - MALLOC(q, struct ifBox *, sizeof(struct ifBox), M_NATPT, M_WAITOK); - bzero(q, sizeof(struct ifBox)); - - q->ifnet = p; -#ifdef __NetBSD__ - sprintf(q->ifName, "%s%c", p->if_xname, '\0'); -#else - sprintf(q->ifName, "%s%d%c", p->if_name, p->if_unit, '\0'); -#endif - - LST_hookup_list((Cell**)&ifBox, q); - return (q); - } - return (NULL); -} - - -/* - * - */ - -void -natpt_debugProbe() -{ - printf("DebugProbe"); -} - - -void -natpt_assert(const char *file, int line, const char *failedexpr) -{ - (void)printf("natpt assertion \"%s\" failed: file \"%s\", line %d\n", - failedexpr, file, line); - panic("natpt assertion"); - /* NOTREACHED */ -} - - -/* - * - */ - -void -natpt_initialize() -{ - struct ifnet *ifn; - struct ifaddr *ifa; - struct ifBox *ibox; - - if (natpt_initialized) - return; - - natpt_initialized = 1; - -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (ifn = ifnet; ifn; ifn = ifn->if_next) -#else - for (ifn = TAILQ_FIRST(&ifnet); ifn; ifn = TAILQ_NEXT(ifn, if_list)) -#endif - { -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (ifa = ifn->if_addrlist; ifa; ifa = ifa->ifa_next) -#else - for (ifa = ifn->if_addrlist.tqh_first; ifa; - ifa = ifa->ifa_list.tqe_next) -#endif - { - if (((ifa->ifa_addr->sa_family) == AF_INET) - || ((ifa->ifa_addr->sa_family) == AF_INET6)) - { - MALLOC(ibox, struct ifBox *, sizeof(struct ifBox), M_TEMP, M_WAITOK); -#ifdef __NetBSD__ - sprintf(ibox->ifName, "%s", ifn->if_xname); -#else - sprintf(ibox->ifName, "%s%d", ifn->if_name, ifn->if_unit); -#endif - ibox->ifnet = ifn; - ibox->side = NULL; - LST_hookup_list(&ifBox, ibox); - goto nextif; - } - } - nextif: - } -} diff --git a/bsd/netinet6/natpt_list.c b/bsd/netinet6/natpt_list.c deleted file mode 100644 index 6a9fb33aa..000000000 --- a/bsd/netinet6/natpt_list.c +++ /dev/null @@ -1,54 +0,0 @@ -/* $KAME: natpt_list.c,v 1.6 2000/03/25 07:23:55 sumikawa Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (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 (defined(KERNEL)) || (defined(_KERNEL)) -/* #include */ -#include -#include -#include -#include - -#ifdef __FreeBSD__ -# include -#endif - -#include - -#include -#include - -#include - -#define INCLUDE_NATPT_LIST_C 1 -#include - -#endif /* defined(KERNEL) */ diff --git a/bsd/netinet6/natpt_list.h b/bsd/netinet6/natpt_list.h deleted file mode 100644 index 10a77de75..000000000 --- a/bsd/netinet6/natpt_list.h +++ /dev/null @@ -1,254 +0,0 @@ -/* $KAME: natpt_list.h,v 1.5 2000/03/25 07:23:55 sumikawa Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#define CELL_FREE_MARKER ((Cell *)0xdeadface) -#define CELL_WEIRD_ADDR ((Cell *)0xdeadbeef) - -Cell *LST_cons __P((void *, void *)); -void LST_free __P((Cell *)); -Cell *LST_last __P((Cell *)); -int LST_length __P((Cell *)); -Cell *LST_hookup __P((Cell *, void *)); -Cell *LST_hookup_list __P((Cell **, void *)); -Cell *LST_remove_elem __P((Cell **, void *)); - - -#ifdef INCLUDE_NATPT_LIST_C - -/* - * Typedefs and Miscellaneous definitions - */ - -#ifndef NULL -#define NULL 0 -#endif - -#define CELL_NUMS 64 -#define CELL_PAGE (CELL_NUMS * sizeof(Cell)) - - -/* - * Typedefs and Miscellaneous definitions - */ - -static int _cell_used; -static int _cell_free; -static Cell *_cell_freeList; -static Cell *_cell_mallBlock; - -static Cell *_getCell __P((void)); -static Cell *_getEmptyCell __P((void)); - - -#ifdef KERNEL -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -static MALLOC_DEFINE(M_NATPT, "NATPT", "Network Address Translation - Protocol Translation"); -#endif /* defined(__FreeBSD__) && __FreeBSD__ >= 3 */ -#endif /* defined(_KERNEL) */ - - -/* - * - */ - -Cell * -LST_cons(void *c_car, void *c_cdr) -{ - Cell *ptr = NULL; - - ptr = _getCell(); - CAR(ptr) = c_car; - CDR(ptr) = c_cdr; - - _cell_used++; - _cell_free--; - - return (ptr); -} - - -void -LST_free(Cell *cell) -{ - if (CAR(cell) != CELL_FREE_MARKER) - { - CAR(cell) = CELL_FREE_MARKER; - CDR(cell) = _cell_freeList; - _cell_freeList = cell; - - _cell_used--; - _cell_free++; - } -} - - -Cell * -LST_last(Cell *list) -{ - register Cell *ptr = NULL; - - if (list == NULL) - ptr = NULL; - else - for (ptr = list; CDR(ptr) != NULL; ptr = CDR(ptr)) ; - - return (ptr); -} - - -int -LST_length(Cell *list) -{ - register int retval = 0; - - if (list == NULL) - retval = 0; - else - { - register Cell *ptr; - - for (ptr = list; ptr; retval++, ptr = CDR(ptr)) ; - } - - return (retval); -} - - -Cell * -LST_hookup(Cell *list, void *elem) -{ - register Cell *ptr = NULL; - - if (list == NULL) - ptr = LST_cons(elem, NULL); - else - CDR(LST_last(list)) = LST_cons(elem, NULL); - - return (ptr); -} - - -Cell * -LST_hookup_list(Cell **list, void *elem) -{ - register Cell *ptr = NULL; - - if (*list == NULL) - *list = LST_cons(elem, NULL); - else - CDR(LST_last(*list)) = LST_cons(elem, NULL); - - return (ptr); -} - - -Cell * -LST_remove_elem(Cell **list, void *elem) -{ - register Cell *p, *q; - - if (*list == NULL) - return (NULL); - - for (p = *list, q = NULL; p; q = p, p = CDR(p)) - { - if (CAR(p) == elem) - { - if (q == NULL) - *list = CDR(p); - else - CDR(q) = CDR(p); - - LST_free(p); - return (elem); - } - } - - return (NULL); -} - - -/* - * - */ - -static Cell * -_getCell() -{ - Cell *ptr = NULL; - - if (_cell_freeList == NULL) - _cell_freeList = _getEmptyCell(); - - ptr = _cell_freeList; - _cell_freeList = CDR(_cell_freeList); - - return (ptr); -} - - -static Cell * -_getEmptyCell() -{ - register int iter; - register Cell *ptr = NULL; - register Cell *p; - -#if (defined(KERNEL)) || (defined(_KERNEL)) - MALLOC(ptr, Cell *, CELL_PAGE, M_NATPT, M_NOWAIT); -#else - ptr = (Cell *)malloc(CELL_PAGE); -#endif /* defined(KERNEL) */ - if (ptr == NULL) - { - printf("ENOBUFS in _getEmptyCell %d\n", __LINE__); - return (ptr); - } - - CAR(ptr) = (Cell *)ptr; - CDR(ptr) = NULL; - - if (_cell_mallBlock == NULL) - _cell_mallBlock = ptr; - else - CDR(LST_last(_cell_mallBlock)) = ptr; - - ptr++; - for (iter = CELL_NUMS - 2 , p = ptr; iter; iter-- , p++) - CAR(p) = CELL_WEIRD_ADDR, CDR(p) = p + 1; - CAR(p) = CELL_WEIRD_ADDR; - CDR(p) = NULL; - _cell_free += CELL_NUMS - 1; - - return (ptr); -} - -#endif /* defined(INCLUDE_NATPT_LIST_C) */ diff --git a/bsd/netinet6/natpt_log.c b/bsd/netinet6/natpt_log.c deleted file mode 100644 index b7460b969..000000000 --- a/bsd/netinet6/natpt_log.c +++ /dev/null @@ -1,170 +0,0 @@ -/* $KAME: natpt_log.c,v 1.6 2000/03/25 07:23:55 sumikawa Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include - - -/* - * - */ - -static struct sockaddr _natpt_dst = {2, PF_INET}; -static struct sockaddr _natpt_src = {2, PF_INET}; - - -struct mbuf *natpt_lbuf __P((int type, int priorities, size_t size)); - - -/* - * - */ - -void -natpt_logMsg(int priorities, void *item, size_t size) -{ - natpt_log(LOG_MSG, priorities, item, size); -} - - -void -natpt_logMBuf(int priorities, struct mbuf *m, char *msg) -{ - if (msg) - natpt_log(LOG_MSG, priorities, (void *)msg, strlen(msg)+1); - natpt_log(LOG_MBUF, priorities, (void *)m->m_data, min(m->m_len, LBFSZ)); -} - - -void -natpt_logIp4(int priorities, struct ip *ip4) -{ - natpt_log(LOG_IP4, priorities, (void *)ip4, sizeof(struct ip)+8); -} - - -void -natpt_logIp6(int priorities, struct ip6_hdr *ip6) -{ - natpt_log(LOG_IP6, priorities, (void *)ip6, sizeof(struct ip6_hdr)+8); -} - - -int -natpt_log(int type, int priorities, void *item, size_t size) -{ - struct sockproto proto; - struct mbuf *m; - struct lbuf *p; - - if ((m = natpt_lbuf(type, priorities, size)) == NULL) - return (ENOBUFS); - - p = (struct lbuf *)m->m_data; - m_copyback(m, sizeof(struct l_hdr), p->l_hdr.lh_size, (caddr_t)item); - - proto.sp_family = AF_INET; - proto.sp_protocol = IPPROTO_AHIP; - natpt_input(m, &proto, &_natpt_src, &_natpt_dst); - - return (0); -} - - -int -natpt_logIN6addr(int priorities, char *msg, struct in6_addr *sin6addr) -{ - int size, msgsz; - struct mbuf *m; - struct lbuf *p; - - msgsz = strlen(msg)+1; - size = sizeof(struct l_hdr) + IN6ADDRSZ + msgsz; - - m = natpt_lbuf(LOG_IN6ADDR, priorities, size); - if (m == NULL) - return (ENOBUFS); - - { - struct sockproto proto; - - p = (struct lbuf *)m->m_pktdat; - bcopy(sin6addr, p->l_addr.in6addr, sizeof(struct in6_addr)); - strncpy(p->l_msg, msg, min(msgsz, MSGSZ-1)); - p->l_msg[MSGSZ-1] = '\0'; - - proto.sp_family = AF_INET; - proto.sp_protocol = IPPROTO_AHIP; - natpt_input(m, &proto, &_natpt_src, &_natpt_dst); - } - - return (0); -} - - -struct mbuf * -natpt_lbuf(int type, int priorities, size_t size) -{ - struct mbuf *m; - struct lbuf *p; - - MGETHDR(m, M_NOWAIT, MT_DATA); - if (m == NULL) - return (NULL); - - m->m_pkthdr.len = m->m_len = MHLEN; - m->m_pkthdr.rcvif = NULL; - - p = (struct lbuf *)m->m_data; - p->l_hdr.lh_type = type; - p->l_hdr.lh_pri = priorities; - p->l_hdr.lh_size = size; - microtime((struct timeval *)&p->l_hdr.lh_sec); - - return (m); -} diff --git a/bsd/netinet6/natpt_log.h b/bsd/netinet6/natpt_log.h deleted file mode 100644 index 70014115f..000000000 --- a/bsd/netinet6/natpt_log.h +++ /dev/null @@ -1,129 +0,0 @@ -/* $KAME: natpt_log.h,v 1.5 2000/03/25 07:23:55 sumikawa Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _NATPT_LOG_H -#define _NATPT_LOG_H - - -#if (defined(KERNEL)) || (defined(_KERNEL)) - -/* Header at beginning of logged packet. */ - -struct l_pkt -{ - char ifName[IFNAMSIZ]; - char __buf[4]; -}; - - -/* Header at beginning of active Transration Table */ - -struct l_att -{ - u_int _stub; -#define ATT_ALLOC (0) -#define ATT_REMOVE (1) -#define ATT_FASTEN (2) -#define ATT_UNFASTEN (3) -#define ATT_REGIST (4) - caddr_t _addr; -#if 0 - struct _aTT _att; - struct _tcpstate _state; -#endif -}; -#endif /* defined(KERNEL) */ - - -/* Header at beginning of each lbuf. */ - -#ifndef IN6ADDRSZ -#define IN6ADDRSZ 16 /* IPv6 T_AAAA */ -#define INT16SZ 2 /* for systems without 16-bit ints */ -#endif /* !defined(IN6ADDRSZ) */ - -#define LBFSZ (MHLEN - sizeof(struct l_hdr)) /* LBUF payload within MBUF */ -#define MSGSZ (LBFSZ - IN6ADDRSZ) /* max message size */ - - -enum -{ - LOG_MSG, - LOG_MBUF, - LOG_IP4, - LOG_IP6, - LOG_IN4ADDR, - LOG_IN6ADDR, - LOG_CSLOT, - LOG_TSLOT, - LOG_RULE -}; - - -struct l_hdr -{ - u_short lh_type; /* Type of data in this lbuf */ - u_short lh_pri; /* Priorities of thie message */ - size_t lh_size; /* Amount of data in this lbuf */ - u_long lh_sec; /* Timestamp in second */ - u_long lh_usec; /* Timestamp in microsecond */ -}; - - -struct l_addr -{ - char in6addr[IN6ADDRSZ]; - char __msg[MSGSZ]; -}; - - -/* Definition of whole lbuf */ - -struct lbuf -{ - struct l_hdr l_hdr; - union - { -#ifdef _KERNEL - struct l_pkt l_pkt; - struct l_att l_att; -#endif /* defined(_KERNEL) */ - struct l_addr __laddr; - char __buf[LBFSZ]; - } l_dat; -}; - - -#define l_addr l_dat.__laddr -#define l_msg l_dat.__laddr.__msg - - -#endif /* !_NATPT_LOG_H */ diff --git a/bsd/netinet6/natpt_rule.c b/bsd/netinet6/natpt_rule.c deleted file mode 100644 index d045e40d4..000000000 --- a/bsd/netinet6/natpt_rule.c +++ /dev/null @@ -1,497 +0,0 @@ -/* $KAME: natpt_rule.c,v 1.9 2000/03/25 07:23:56 sumikawa Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include -#if (defined(__FreeBSD__) && __FreeBSD__ < 3) || defined(__bsdi__) -#include -#endif - -#include -#include -#include -#include -#include - - -/* - * - */ - -Cell *natptStatic; /* list of struct _cSlot */ -Cell *natptDynamic; /* list of struct _cSlot */ -Cell *natptFaith; /* list of struct _cSlot */ - -int matchIn4addr __P((struct _cv *, struct pAddr *)); -int matchIn6addr __P((struct _cv *, struct pAddr *)); -static void _flushPtrRules __P((struct _cell **)); - - -extern struct in6_addr faith_prefix; -extern struct in6_addr faith_prefixmask; -extern struct in6_addr natpt_prefix; -extern struct in6_addr natpt_prefixmask; - -extern void in4_len2mask __P((struct in_addr *, int)); -extern void in6_len2mask __P((struct in6_addr *, int)); - - -/* - * - */ - -struct _cSlot * -lookingForIncomingV4Rule(struct _cv *cv) -{ - Cell *p; - struct _cSlot *acs; - - for (p = natptStatic; p; p = CDR(p)) - { - acs = (struct _cSlot *)CAR(p); - if ((acs->dir == NATPT_INBOUND) - && ((acs->proto == 0) - || (acs->proto == cv->ip_payload)) - && (matchIn4addr(cv, &acs->remote) != 0)) - return (acs); - } - - for (p = natptDynamic; p; p = CDR(p)) - { - acs = (struct _cSlot *)CAR(p); - if ((acs->dir == NATPT_INBOUND) - && ((acs->proto == 0) - || (acs->proto == cv->ip_payload)) - && (matchIn4addr(cv, &acs->remote) != 0)) - return (acs); - } - - return (NULL); -} - - -struct _cSlot * -lookingForOutgoingV4Rule(struct _cv *cv) -{ - Cell *p; - struct _cSlot *acs; - - for (p = natptStatic; p; p = CDR(p)) - { - acs = (struct _cSlot *)CAR(p); - - if ((acs->dir == NATPT_OUTBOUND) - && (matchIn4addr(cv, &acs->local) != 0)) - return (acs); - } - - for (p = natptDynamic; p; p = CDR(p)) - { - acs = (struct _cSlot *)CAR(p); - if ((acs->dir == NATPT_OUTBOUND) - && (matchIn4addr(cv, &acs->local) != 0)) - return (acs); - } - - return (NULL); -} - - -struct _cSlot * -lookingForIncomingV6Rule(struct _cv *cv) -{ - Cell *p; - struct _cSlot *acs; - - for (p = natptStatic; p; p = CDR(p)) - { - acs = (struct _cSlot *)CAR(p); - if ((acs->dir == NATPT_INBOUND) - && (matchIn6addr(cv, &acs->remote)) != 0) - return (acs); - } - - for (p = natptDynamic; p; p = CDR(p)) - { - acs = (struct _cSlot *)CAR(p); - if ((acs->dir == NATPT_INBOUND) - && (matchIn6addr(cv, &acs->remote)) != 0) - return (acs); - } - - return (NULL); -} - - -struct _cSlot * -lookingForOutgoingV6Rule(struct _cv *cv) -{ - Cell *p; - struct _cSlot *acs; - - for (p = natptStatic; p; p = CDR(p)) - { - acs = (struct _cSlot *)CAR(p); - if ((acs->dir == NATPT_OUTBOUND) - && ((acs->proto == 0) - || (acs->proto == cv->ip_payload)) - && (matchIn6addr(cv, &acs->local)) != 0) - return (acs); - } - - for (p = natptDynamic; p; p = CDR(p)) - { - acs = (struct _cSlot *)CAR(p); - if ((acs->dir == NATPT_OUTBOUND) - && ((acs->proto == 0) - || (acs->proto == cv->ip_payload)) - && (matchIn6addr(cv, &acs->local)) != 0) - return (acs); - } - - for (p = natptFaith; p; p = CDR(p)) - { - acs = (struct _cSlot *)CAR(p); - if ((acs->dir == NATPT_OUTBOUND) - && ((acs->proto == 0) - || (acs->proto == cv->ip_payload)) - && (matchIn6addr(cv, &acs->local)) != 0) - return (acs); - } - - return (NULL); -} - - -int -matchIn4addr(struct _cv *cv4, struct pAddr *from) -{ - struct in_addr in4from = cv4->_ip._ip4->ip_src; - struct in_addr in4masked; - - if (from->sa_family != AF_INET) - return (0); - - switch (from->ad.type) - { - case ADDR_ANY: goto port; - - case ADDR_SINGLE: - if (in4from.s_addr == from->in4Addr.s_addr) goto port; - return (0); - - case ADDR_MASK: - in4masked.s_addr = in4from.s_addr & from->in4Mask.s_addr; - if (in4masked.s_addr == from->in4Addr.s_addr) goto port; - return (0); - - case ADDR_RANGE: - if ((in4from.s_addr >= from->in4RangeStart.s_addr) - && (in4from.s_addr <= from->in4RangeEnd.s_addr)) goto port; - return (0); - - default: - return (0); - } - -port:; - if ((cv4->ip_payload != IPPROTO_UDP) - && (cv4->ip_payload != IPPROTO_TCP)) return (1); - - if (from->_port0 == 0) return (1); - - if (from->_port1 == 0) - { - if ((cv4->_payload._tcp4->th_dport == from->_port0)) return (1); - } - else - { - u_short dport = ntohs(cv4->_payload._tcp4->th_dport); - u_short port0 = ntohs(from->_port0); - u_short port1 = ntohs(from->_port1); - - if ((dport >= port0) - && (dport <= port1)) return (1); - } - - return (0); -} - - -int -matchIn6addr(struct _cv *cv6, struct pAddr *from) -{ - struct in6_addr *in6from = &cv6->_ip._ip6->ip6_src; - struct in6_addr in6masked; - - if (from->sa_family != AF_INET6) - return (0); - - switch (from->ad.type) - { - case ADDR_ANY: goto port; - - case ADDR_SINGLE: - if (IN6_ARE_ADDR_EQUAL(in6from, &from->in6Addr)) goto port; - return (0); - - case ADDR_MASK: - in6masked.s6_addr32[0] = in6from->s6_addr32[0] & from->in6Mask.s6_addr32[0]; - in6masked.s6_addr32[1] = in6from->s6_addr32[1] & from->in6Mask.s6_addr32[1]; - in6masked.s6_addr32[2] = in6from->s6_addr32[2] & from->in6Mask.s6_addr32[2]; - in6masked.s6_addr32[3] = in6from->s6_addr32[3] & from->in6Mask.s6_addr32[3]; - - if (IN6_ARE_ADDR_EQUAL(&in6masked, &from->in6Addr)) goto port; - return (0); - - default: - return (0); - } - -port:; - if ((cv6->ip_payload != IPPROTO_UDP) - && (cv6->ip_payload != IPPROTO_TCP)) return (1); - - if (from->_port0 == 0) return (1); - - if (from->_port1 == 0) - { - if (cv6->_payload._tcp6->th_dport == from->_port0) return (1); - } - else - { - u_short dport = ntohs(cv6->_payload._tcp6->th_dport); -#ifdef UnusedVariable - u_short port0 = ntohs(from->_port0); - u_short port1 = ntohs(from->_port1); -#endif - - if ((dport >= from->_port0) - && (dport <= from->_port1)) return (1); - } - - - return (0); -} -/* - * - */ - -int -_natptEnableTrans(caddr_t addr) -{ - char Wow[64]; - - sprintf(Wow, "map enable"); - natpt_logMsg(LOG_INFO, Wow, strlen(Wow)); - - ip6_protocol_tr = 1; - return (0); -} - - -int -_natptDisableTrans(caddr_t addr) -{ - char Wow[64]; - - sprintf(Wow, "map disable"); - natpt_logMsg(LOG_INFO, Wow, strlen(Wow)); - - ip6_protocol_tr = 0; - return (0); -} - - -int -_natptSetRule(caddr_t addr) -{ - struct natpt_msgBox *mbx = (struct natpt_msgBox *)addr; - struct _cSlot *cst; - Cell **anchor; - -#if 0 - if (((ifb = natpt_asIfBox(mbx->m_ifName)) == NULL) - && ((ifb = natpt_setIfBox(mbx->m_ifName)) == NULL)) - return (ENXIO); -#endif - - if (mbx->flags == NATPT_FAITH) - return (_natptSetFaithRule(addr)); - - MALLOC(cst, struct _cSlot *, sizeof(struct _cSlot), M_TEMP, M_WAITOK); - copyin(mbx->freight, cst, sizeof(struct _cSlot)); - - { - struct pAddr *from; - - from = &cst->local; - if (cst->dir == NATPT_INBOUND) - from = &cst->remote; - - if (from->sa_family == AF_INET) - { - in4_len2mask(&from->in4Mask, cst->prefix); - from->in4Addr.s_addr &= from->in4Mask.s_addr; - } - else - { - in6_len2mask(&from->in6Mask, cst->prefix); - from->in6Addr.s6_addr32[0] - = from->in6Addr.s6_addr32[0] & from->in6Mask.s6_addr32[0]; - from->in6Addr.s6_addr32[1] - = from->in6Addr.s6_addr32[1] & from->in6Mask.s6_addr32[1]; - from->in6Addr.s6_addr32[2] - = from->in6Addr.s6_addr32[2] & from->in6Mask.s6_addr32[2]; - from->in6Addr.s6_addr32[3] - = from->in6Addr.s6_addr32[3] & from->in6Mask.s6_addr32[3]; - } - } - - natpt_log(LOG_CSLOT, LOG_DEBUG, (void *)cst, sizeof(struct _cSlot)); - - anchor = &natptStatic; - if (cst->flags == NATPT_DYNAMIC) - anchor = &natptDynamic; - - LST_hookup_list(anchor, cst); - - return (0); -} - - -int -_natptSetFaithRule(caddr_t addr) -{ - struct natpt_msgBox *mbx = (struct natpt_msgBox *)addr; - struct _cSlot *cst; - - MALLOC(cst, struct _cSlot *, sizeof(struct _cSlot), M_TEMP, M_WAITOK); - copyin(mbx->freight, cst, sizeof(struct _cSlot)); - - LST_hookup_list(&natptFaith, cst); - - return (0); -} - - -int -_natptFlushRule(caddr_t addr) -{ - struct natpt_msgBox *mbx = (struct natpt_msgBox *)addr; - - if (mbx->flags & FLUSH_STATIC) - _flushPtrRules(&natptStatic); - - if (mbx->flags & FLUSH_DYNAMIC) - _flushPtrRules(&natptDynamic); - - return (0); -} - - -int -_natptSetPrefix(caddr_t addr) -{ - struct natpt_msgBox *mbx = (struct natpt_msgBox *)addr; - struct pAddr *load; - - MALLOC(load, struct pAddr *, sizeof(struct pAddr), M_TEMP, M_WAITOK); - copyin(mbx->freight, load, SZSIN6 * 2); - - if (mbx->flags & PREFIX_FAITH) - { - faith_prefix = load->addr[0].in6; - faith_prefixmask = load->addr[1].in6; - - natpt_logIN6addr(LOG_INFO, "FAITH prefix: ", &faith_prefix); - natpt_logIN6addr(LOG_INFO, "FAITH prefixmask: ", &faith_prefixmask); - } - else if (mbx->flags & PREFIX_NATPT) - { - natpt_prefix = load->addr[0].in6; - natpt_prefixmask = load->addr[1].in6; - - natpt_logIN6addr(LOG_INFO, "NATPT prefix: ", &natpt_prefix); - natpt_logIN6addr(LOG_INFO, "NATPT prefixmask: ", &natpt_prefixmask); - } - - FREE(load, M_TEMP); - return (0); -} - - -int -_natptBreak() -{ - printf("break"); - - return (0); -} - - -/* - * - */ - -static void -_flushPtrRules(struct _cell **anchor) -{ - struct _cell *p0, *p1; - struct _cSlot *cslt; - - p0 = *anchor; - while (p0) - { - p1 = p0; - p0 = CDR(p0); - - cslt = (struct _cSlot *)CAR(p1); - FREE(cslt, M_TEMP); - LST_free(p1); - } - - *anchor = NULL; -} diff --git a/bsd/netinet6/natpt_soctl.h b/bsd/netinet6/natpt_soctl.h deleted file mode 100644 index 10204316f..000000000 --- a/bsd/netinet6/natpt_soctl.h +++ /dev/null @@ -1,91 +0,0 @@ -/* $KAME: natpt_soctl.h,v 1.8 2000/03/25 07:23:56 sumikawa Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* cmd for use with ioctl at the socket */ -/* _IO() no parameters */ -/* _IOR() copy out parameters */ -/* _IOW() copy in parameters */ -/* _IOWR() copy in/out parameters */ - -#define SIOCSETIF _IOW ('n', 0, struct natpt_msgBox) /* Set interface side */ -#define SIOCGETIF _IOWR('n', 1, struct natpt_msgBox) /* Get interface sidde */ -#define SIOCENBTRANS _IOW ('n', 2, struct natpt_msgBox) /* Enable translation */ -#define SIOCDSBTRANS _IOW ('n', 3, struct natpt_msgBox) /* Disable translation */ -#define SIOCSETRULE _IOW ('n', 4, struct natpt_msgBox) /* Set rule */ -#define SIOCGETRULE _IOWR('n', 5, struct natpt_msgBox) /* Get rule */ -#define SIOCFLUSHRULE _IOW ('n', 6, struct natpt_msgBox) /* Flush rule */ -#define SIOCSETPREFIX _IOW ('n', 8, struct natpt_msgBox) /* Set prefix */ -#define SIOCGETPREFIX _IOWR('n', 9, struct natpt_msgBox) /* Get prefix */ -#define SIOCSETVALUE _IOW ('n', 10, struct natpt_msgBox) /* Set value */ -#define SIOCGETVALUE _IOW ('n', 11, struct natpt_msgBox) /* Get value */ - -#define SIOCTESTLOG _IOW ('n', 12, struct natpt_msgBox) /* Test log */ - -#define SIOCBREAK _IO ('n', 255) /* stop */ - - -typedef struct natpt_msgBox /* sizeof(): 44[byte] */ -{ - int flags; -/* in case SIOC(GET|SET)IF */ -#define IF_EXTERNAL (0x01) -#define IF_INTERNAL (0x02) - -/* in case SIOT(SET|GET)RULE */ -#ifndef NATPT_STATIC -#define NATPT_STATIC (0x01) -#define NATPT_DYNAMIC (0x02) -#define NATPT_FAITH (0x03) -#endif - -/* in case SIOCFLUSHRULE ... bitwise */ -#define FLUSH_STATIC (0x01) -#define FLUSH_DYNAMIC (0x02) - -/* in case SIOC(GET|SET)PREFIX */ -#define PREFIX_FAITH (0x01) -#define PREFIX_NATPT (0x02) - -/* in case SIOC(GET|SET)VALUE */ -#define NATPT_DEBUG (0x01) /* natpt_debug := */ -#define NATPT_DUMP (0x02) /* natpt_dump := */ - - int size; /* sizeof(*freight) */ - char *freight; - union - { - char M_ifName[IFNAMSIZ]; - char M_aux[32]; - } M_dat; -} natpt_msgBox; - -#define m_ifName M_dat.M_ifName -#define m_aux M_dat.M_aux diff --git a/bsd/netinet6/natpt_trans.c b/bsd/netinet6/natpt_trans.c deleted file mode 100644 index 03af7ea2c..000000000 --- a/bsd/netinet6/natpt_trans.c +++ /dev/null @@ -1,1612 +0,0 @@ -/* $KAME: natpt_trans.c,v 1.12 2000/03/25 07:23:56 sumikawa Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include - -#ifdef __FreeBSD__ -# include -#endif - -#include -#ifdef __bsdi__ -#include -#endif - -#include -#include -#include - -#if defined(__bsdi__) || defined(__NetBSD__) -#include /* netinet/in_pcb.h line 71 make happy. */ -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#if !defined(__NetBSD__) && (!defined(__FreeBSD__) || (__FreeBSD__ < 3)) && !defined(__APPLE__) -#include -#endif - -#include -#include -#include - - -#define recalculateTCP4Checksum 1 -#define recalculateTCP6Checksum 1 - - -/* - * - */ - -int errno; -int natpt_initialized; -int ip6_protocol_tr; - -extern struct in6_addr natpt_prefix; -extern struct in6_addr natpt_prefixmask; - -struct mbuf *translatingTCPUDPv4To4 __P((struct _cv *, struct pAddr *, struct _cv *)); - -void tr_icmp4EchoReply __P((struct _cv *, struct _cv *)); -void tr_icmp4Unreach __P((struct _cv *, struct _cv *, struct pAddr *)); -void tr_icmp4Echo __P((struct _cv *, struct _cv *)); -void tr_icmp4Timxceed __P((struct _cv *, struct _cv *, struct pAddr *)); -void tr_icmp4Paramprob __P((struct _cv *, struct _cv *)); -void tr_icmp4MimicPayload __P((struct _cv *, struct _cv *, struct pAddr *)); - -void tr_icmp6DstUnreach __P((struct _cv *, struct _cv *)); -void tr_icmp6PacketTooBig __P((struct _cv *, struct _cv *)); -void tr_icmp6TimeExceed __P((struct _cv *, struct _cv *)); -void tr_icmp6ParamProb __P((struct _cv *, struct _cv *)); -void tr_icmp6EchoRequest __P((struct _cv *, struct _cv *)); -void tr_icmp6EchoReply __P((struct _cv *, struct _cv *)); - -static void _recalculateTCP4Checksum __P((struct _cv *)); - -static int updateTcpStatus __P((struct _cv *)); -static int _natpt_tcpfsm __P((int, int, u_short, u_char)); -static int _natpt_tcpfsmSessOut __P((int, short, u_char)); -static int _natpt_tcpfsmSessIn __P((int, short, u_char)); - -static void adjustUpperLayerChecksum __P((int, int, struct _cv *, struct _cv *)); -static int adjustChecksum __P((int, u_char *, int, u_char *, int)); - - -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -static MALLOC_DEFINE(M_NATPT, "NATPT", "Network Address Translation - Protocol Translation"); -#endif - - -#ifdef NATPT_NAT -/* - * Translating From IPv4 to IPv4 - */ - -struct mbuf * -translatingIPv4To4(struct _cv *cv4, struct pAddr *pad) -{ - struct timeval atv; - struct mbuf *m4 = NULL; - - if (isDump(D_TRANSLATINGIPV4)) - natpt_logIp4(LOG_DEBUG, cv4->_ip._ip4); - - microtime(&atv); - cv4->ats->tstamp = atv.tv_sec; - - switch (cv4->ip_payload) - { - case IPPROTO_ICMP: - m4 = translatingICMPv4To4(cv4, pad); - break; - - case IPPROTO_TCP: - m4 = translatingTCPv4To4(cv4, pad); - break; - - case IPPROTO_UDP: - m4 = translatingUDPv4To4(cv4, pad); - break; - } - - if (m4) - { - struct ip *ip4; - - ip4 = mtod(m4, struct ip *); - ip4->ip_sum = 0; /* Header checksum */ - ip4->ip_sum = in_cksum(m4, sizeof(struct ip)); - m4->m_pkthdr.rcvif = cv4->m->m_pkthdr.rcvif; - - m4->m_pkthdr.len = cv4->m->m_pkthdr.len; - } - - return (m4); -} - - -struct mbuf * -translatingICMPv4To4(struct _cv *cv4from, struct pAddr *pad) -{ - struct _cv cv4to; - struct mbuf *m4; - struct ip *ip4from, *ip4to; - struct icmp *icmp4from; - - ip4from = mtod(cv4from->m, struct ip *); - icmp4from = cv4from->_payload._icmp4; - - m4 = m_copym(cv4from->m,0, M_COPYALL, M_NOWAIT); - ReturnEnobufs(m4); - - bzero(&cv4to, sizeof(struct _cv)); - cv4to.m = m4; - cv4to._ip._ip4 = ip4to = mtod(m4, struct ip *); - cv4to._payload._caddr = (caddr_t)cv4to._ip._ip4 + (ip4from->ip_hl << 2); - - ip4to->ip_src = pad->in4src; /* source address */ - ip4to->ip_dst = pad->in4dst; /* destination address */ - - switch (icmp4from->icmp_type) - { - case ICMP_ECHOREPLY: - case ICMP_ECHO: - break; - - default: - m_freem(m4); - return (NULL); - } - - m4->m_len = cv4from->m->m_len; - return (m4); -} - - -struct mbuf * -translatingTCPv4To4(struct _cv *cv4from, struct pAddr *pad) -{ - struct _cv cv4to; - struct mbuf *m4; - - bzero(&cv4to, sizeof(struct _cv)); - m4 = translatingTCPUDPv4To4(cv4from, pad, &cv4to); - cv4to.ip_p = cv4to.ip_payload = IPPROTO_TCP; - - updateTcpStatus(&cv4to); - adjustUpperLayerChecksum(IPPROTO_IPV4, IPPROTO_TCP, cv4from, &cv4to); - -#ifdef recalculateTCP4Checksum - _recalculateTCP4Checksum(&cv4to); -#endif - - return (m4); -} - - -struct mbuf * -translatingUDPv4To4(struct _cv *cv4from, struct pAddr *pad) -{ - struct _cv cv4to; - struct mbuf *m4; - - bzero(&cv4to, sizeof(struct _cv)); - m4 = translatingTCPUDPv4To4(cv4from, pad, &cv4to); - cv4to.ip_p = cv4to.ip_payload = IPPROTO_UDP; - - adjustUpperLayerChecksum(IPPROTO_IPV4, IPPROTO_UDP, cv4from, &cv4to); - - return (m4); -} - - -struct mbuf * -translatingTCPUDPv4To4(struct _cv *cv4from, struct pAddr *pad, struct _cv *cv4to) -{ - struct mbuf *m4; - struct ip *ip4to; - struct tcphdr *tcp4to; - - m4 = m_copym(cv4from->m,0, M_COPYALL, M_NOWAIT); - ReturnEnobufs(m4); - - ip4to = mtod(m4, struct ip *); - - ip4to->ip_src = pad->in4src; - ip4to->ip_dst = pad->in4dst; - - tcp4to = (struct tcphdr *)((caddr_t)ip4to + (ip4to->ip_hl << 2)); - tcp4to->th_sport = pad->_sport; - tcp4to->th_dport = pad->_dport; - - cv4to->m = m4; - cv4to->_ip._ip4 = ip4to; - cv4to->_payload._tcp4 = tcp4to; - cv4to->ats = cv4from->ats; - - return (m4); -} - -#endif /* ifdef NATPT_NAT */ - - -/* - * Translating From IPv4 To IPv6 - */ - -struct mbuf * -translatingIPv4To6(struct _cv *cv4, struct pAddr *pad) -{ - struct timeval atv; - struct mbuf *m6 = NULL; - - if (isDump(D_TRANSLATINGIPV4)) - natpt_logIp4(LOG_DEBUG, cv4->_ip._ip4); - - microtime(&atv); - cv4->ats->tstamp = atv.tv_sec; - - switch (cv4->ip_payload) - { - case IPPROTO_ICMP: - m6 = translatingICMPv4To6(cv4, pad); - break; - - case IPPROTO_TCP: - m6 = translatingTCPv4To6(cv4, pad); - break; - - case IPPROTO_UDP: - m6 = translatingUDPv4To6(cv4, pad); - break; - } - - if (m6) - m6->m_pkthdr.rcvif = cv4->m->m_pkthdr.rcvif; - - return (m6); -} - - -struct mbuf * -translatingICMPv4To6(struct _cv *cv4, struct pAddr *pad) -{ - struct _cv cv6; - struct mbuf *m6; - struct ip *ip4; - struct ip6_hdr *ip6; - struct icmp *icmp4; - struct icmp6_hdr *icmp6; - - ip4 = mtod(cv4->m, struct ip *); - icmp4 = cv4->_payload._icmp4; - - { - caddr_t icmp4end; - int icmp4len; - - icmp4end = (caddr_t)ip4 + cv4->m->m_pkthdr.len; - icmp4len = icmp4end - (caddr_t)cv4->_payload._icmp4; - - MGETHDR(m6, M_NOWAIT, MT_HEADER); - if (m6 == NULL) - { - errno = ENOBUFS; - return (NULL); - } - if (MHLEN < (sizeof(struct ip6_hdr) + icmp4len)) - MCLGET(m6, M_NOWAIT); - } - - cv6.m = m6; - cv6._ip._ip6 = mtod(m6, struct ip6_hdr *); - cv6._payload._caddr = (caddr_t)cv6._ip._ip6 + sizeof(struct ip6_hdr); - - ip6 = mtod(cv6.m, struct ip6_hdr *); - icmp6 = cv6._payload._icmp6;; - - ip6->ip6_flow = 0; - ip6->ip6_vfc &= ~IPV6_VERSION_MASK; - ip6->ip6_vfc |= IPV6_VERSION; - ip6->ip6_plen = 0; /* XXX */ - ip6->ip6_nxt = IPPROTO_ICMPV6; - ip6->ip6_hlim = ip4->ip_ttl -1; - ip6->ip6_dst = pad->in6dst; - ip6->ip6_src = pad->in6src; - if (natpt_prefix.s6_addr32[0] != 0) - { - ip6->ip6_src.s6_addr32[0] = natpt_prefix.s6_addr32[0]; - ip6->ip6_src.s6_addr32[1] = natpt_prefix.s6_addr32[1]; - ip6->ip6_src.s6_addr32[2] = natpt_prefix.s6_addr32[2]; - } - else - { - ip6->ip6_src.s6_addr32[0] = 0; - ip6->ip6_src.s6_addr32[1] = 0; - ip6->ip6_src.s6_addr32[2] = 0; - } - ip6->ip6_src.s6_addr32[3] = ip4->ip_src.s_addr; - - switch (icmp4->icmp_type) - { - case ICMP_ECHOREPLY: - tr_icmp4EchoReply(cv4, &cv6); - break; - - case ICMP_UNREACH: - tr_icmp4Unreach(cv4, &cv6, pad); - break; - - case ICMP_ECHO: - tr_icmp4Echo(cv4, &cv6); - break; - - case ICMP_TIMXCEED: - tr_icmp4Timxceed(cv4, &cv6, pad); - break; - - case ICMP_PARAMPROB: - tr_icmp4Paramprob(cv4, &cv6); - break; - - case ICMP_REDIRECT: - case ICMP_ROUTERADVERT: - case ICMP_ROUTERSOLICIT: - m_freem(m6); /* Single hop message. Silently drop. */ - return (NULL); - - case ICMP_SOURCEQUENCH: - case ICMP_TSTAMP: - case ICMP_TSTAMPREPLY: - case ICMP_IREQ: - case ICMP_IREQREPLY: - case ICMP_MASKREQ: - case ICMP_MASKREPLY: - m_freem(m6); /* Obsoleted in ICMPv6. Silently drop. */ - return (NULL); - - default: - m_freem(m6); /* Silently drop. */ - return (NULL); - } - - icmp6->icmp6_cksum = 0; - icmp6->icmp6_cksum = in6_cksum(cv6.m, IPPROTO_ICMPV6, - sizeof(struct ip6_hdr), ntohs(ip6->ip6_plen)); - - return (m6); -} - - -void -tr_icmp4EchoReply(struct _cv *cv4, struct _cv *cv6) -{ - struct icmp *icmp4 = cv4->_payload._icmp4; - struct icmp6_hdr *icmp6 = cv6->_payload._icmp6; - - icmp6->icmp6_type = ICMP6_ECHO_REPLY; - icmp6->icmp6_code = 0; - icmp6->icmp6_id = icmp4->icmp_id; - icmp6->icmp6_seq = icmp4->icmp_seq; - - { - int dlen; - struct ip *ip4 = cv4->_ip._ip4; - struct ip6_hdr *ip6 = cv6->_ip._ip6; - caddr_t icmp4off, icmp6off; - caddr_t icmp4end = (caddr_t)ip4 + cv4->m->m_pkthdr.len; - int icmp4len = icmp4end - (caddr_t)cv4->_payload._icmp4; - - dlen = icmp4len - ICMP_MINLEN; - icmp4off = (caddr_t)(cv4->_payload._icmp4) + ICMP_MINLEN; - icmp6off = (caddr_t)(cv6->_payload._icmp6) + sizeof(struct icmp6_hdr); - bcopy(icmp4off, icmp6off, dlen); - - ip6->ip6_plen = ntohs(sizeof(struct icmp6_hdr) + dlen); - cv6->m->m_pkthdr.len - = cv6->m->m_len - = sizeof(struct ip6_hdr) + htons(ip6->ip6_plen); - } -} - - -void -tr_icmp4Unreach(struct _cv *cv4, struct _cv *cv6, struct pAddr *pad) -{ - struct icmp *icmp4 = cv4->_payload._icmp4; - struct icmp6_hdr *icmp6 = cv6->_payload._icmp6; - - icmp6->icmp6_type = ICMP6_DST_UNREACH; - icmp6->icmp6_code = 0; - icmp6->icmp6_id = icmp4->icmp_id; - icmp6->icmp6_seq = icmp4->icmp_seq; - - switch (icmp4->icmp_code) - { - case ICMP_UNREACH_NET: - case ICMP_UNREACH_HOST: - icmp6->icmp6_code = ICMP6_DST_UNREACH_NOROUTE; - break; - - case ICMP_UNREACH_PROTOCOL: /* do more */ - icmp6->icmp6_type = ICMP6_PARAM_PROB; - icmp6->icmp6_code = ICMP6_PARAMPROB_NEXTHEADER; /* xxx */ - break; - - case ICMP_UNREACH_PORT: - icmp6->icmp6_code = ICMP6_DST_UNREACH_NOPORT; - break; - - case ICMP_UNREACH_NEEDFRAG: /* do more */ - icmp6->icmp6_type = ICMP6_PACKET_TOO_BIG; - icmp6->icmp6_code = ICMP6_PARAMPROB_HEADER; - break; - - case ICMP_UNREACH_SRCFAIL: - icmp6->icmp6_code = ICMP6_DST_UNREACH_NOTNEIGHBOR; - break; - - case ICMP_UNREACH_NET_UNKNOWN: - case ICMP_UNREACH_HOST_UNKNOWN: - icmp6->icmp6_code = ICMP6_DST_UNREACH_NOROUTE; - break; - - case ICMP_UNREACH_ISOLATED: - icmp6->icmp6_code = ICMP6_DST_UNREACH_NOROUTE; - break; - - case ICMP_UNREACH_NET_PROHIB: - case ICMP_UNREACH_HOST_PROHIB: - icmp6->icmp6_code = ICMP6_DST_UNREACH_ADMIN; - break; - - case ICMP_UNREACH_TOSNET: - case ICMP_UNREACH_TOSHOST: - icmp6->icmp6_code = ICMP6_DST_UNREACH_NOROUTE; - break; - - default: - break; - } - - tr_icmp4MimicPayload(cv4, cv6, pad); -} - - -void -tr_icmp4Echo(struct _cv *cv4, struct _cv *cv6) -{ - struct icmp *icmp4 = cv4->_payload._icmp4; - struct icmp6_hdr *icmp6 = cv6->_payload._icmp6; - - icmp6->icmp6_type = ICMP6_ECHO_REQUEST; - icmp6->icmp6_code = 0; - icmp6->icmp6_id = icmp4->icmp_id; - icmp6->icmp6_seq = icmp4->icmp_seq; - - { - int dlen; - struct ip *ip4 = cv4->_ip._ip4; - struct ip6_hdr *ip6 = cv6->_ip._ip6; - caddr_t icmp4off, icmp6off; - caddr_t icmp4end = (caddr_t)ip4 + cv4->m->m_pkthdr.len; - int icmp4len = icmp4end - (caddr_t)cv4->_payload._icmp4; - - dlen = icmp4len - ICMP_MINLEN; - icmp4off = (caddr_t)(cv4->_payload._icmp4) + ICMP_MINLEN; - icmp6off = (caddr_t)(cv6->_payload._icmp6) + sizeof(struct icmp6_hdr); - bcopy(icmp4off, icmp6off, dlen); - - ip6->ip6_plen = ntohs(sizeof(struct icmp6_hdr) + dlen); - cv6->m->m_pkthdr.len - = cv6->m->m_len - = sizeof(struct ip6_hdr) + htons(ip6->ip6_plen); - } -} - - -void -tr_icmp4Timxceed(struct _cv *cv4, struct _cv *cv6, struct pAddr *pad) -{ - struct icmp *icmp4 = cv4->_payload._icmp4; - struct icmp6_hdr *icmp6 = cv6->_payload._icmp6; - - icmp6->icmp6_type = ICMP6_TIME_EXCEEDED; - icmp6->icmp6_code = 0; - icmp6->icmp6_id = icmp4->icmp_id; - icmp6->icmp6_seq = icmp4->icmp_seq; - - tr_icmp4MimicPayload(cv4, cv6, pad); -} - - -void -tr_icmp4Paramprob(struct _cv *cv4, struct _cv *cv6) -{ - struct icmp *icmp4 = cv4->_payload._icmp4; - struct icmp6_hdr *icmp6 = cv6->_payload._icmp6; - - icmp6->icmp6_type = ICMP6_PARAM_PROB; - icmp6->icmp6_code = 0; - icmp6->icmp6_id = icmp4->icmp_id; - icmp6->icmp6_seq = icmp4->icmp_seq; -} - - -void -tr_icmp4MimicPayload(struct _cv *cv4, struct _cv *cv6, struct pAddr *pad) -{ - int dgramlen; - int icmp6dlen, icmp6rest; - struct ip *ip4 = cv6->_ip._ip4; - struct ip6_hdr *ip6 = cv6->_ip._ip6; - struct ip6_hdr *icmpip6; - caddr_t icmp4off, icmp4dgramoff; - caddr_t icmp6off, icmp6dgramoff; - caddr_t icmp4end = (caddr_t)ip4 + cv4->m->m_pkthdr.len; - int icmp4len = icmp4end - (caddr_t)cv4->_payload._icmp4; - - icmp6rest = MHLEN - sizeof(struct ip6_hdr) * 2 - sizeof(struct icmp6_hdr); - dgramlen = icmp4len - ICMP_MINLEN - sizeof(struct ip); - dgramlen = min(icmp6rest, dgramlen); - - icmp4off = (caddr_t)(cv4->_payload._icmp4) + ICMP_MINLEN; - icmp6off = (caddr_t)(cv6->_payload._icmp6) + sizeof(struct icmp6_hdr); - icmp4dgramoff = icmp4off + sizeof(struct ip); - icmp6dgramoff = icmp6off + sizeof(struct ip6_hdr); - - icmpip6 = (struct ip6_hdr *)icmp6off; - bzero(icmpip6, sizeof(struct ip6_hdr)); - bcopy(icmp4dgramoff, icmp6dgramoff, dgramlen); - - icmpip6->ip6_flow = 0; - icmpip6->ip6_vfc &= ~IPV6_VERSION_MASK; - icmpip6->ip6_vfc |= IPV6_VERSION; - icmpip6->ip6_plen = 0; - icmpip6->ip6_nxt = IPPROTO_UDP; - icmpip6->ip6_hlim = 0; - icmpip6->ip6_src = pad->in6dst; - icmpip6->ip6_dst = pad->in6src; - - icmp6dlen = sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr) + dgramlen; - ip6->ip6_plen = ntohs(icmp6dlen); - cv6->m->m_pkthdr.len - = cv6->m->m_len - = sizeof(struct ip6_hdr) + htons(ip6->ip6_plen); - - if (cv4->flags & NATPT_TRACEROUTE) - { - struct udphdr *icmpudp6; - - icmpudp6 = (struct udphdr *)((caddr_t)icmpip6 + sizeof(struct ip6_hdr)); - icmpudp6->uh_sport = cv4->ats->local._dport; - icmpudp6->uh_dport = cv4->ats->local._sport; - } -} - - -struct mbuf * -translatingTCPv4To6(struct _cv *cv4, struct pAddr *pad) -{ - int cksumOrg; - struct _cv cv6; - struct mbuf *m6; - - bzero(&cv6, sizeof(struct _cv)); - m6 = translatingTCPUDPv4To6(cv4, pad, &cv6); - cv6.ip_p = cv6.ip_payload = IPPROTO_TCP; - cksumOrg = ntohs(cv4->_payload._tcp4->th_sum); - - updateTcpStatus(cv4); - adjustUpperLayerChecksum(IPPROTO_IPV4, IPPROTO_TCP, &cv6, cv4); - -#ifdef recalculateTCP6Checksum - { - int cksumAdj, cksumCks; - struct tcp6hdr *th; - - cksumAdj = cv6._payload._tcp6->th_sum; - - th = cv6._payload._tcp6; - th->th_sum = 0; - th->th_sum = in6_cksum(cv6.m, IPPROTO_TCP, sizeof(struct ip6_hdr), - cv6.m->m_pkthdr.len - sizeof(struct ip6_hdr)); - - cksumCks = th->th_sum; -#if 0 - printf("translatingTCPv4To6: TCP4->TCP6: %04x, %04x, %04x %d\n", - cksumOrg, cksumAdj, cksumCks, cv6.m->m_pkthdr.len); -#endif - } -#endif - - return (m6); -} - - -struct mbuf * -translatingUDPv4To6(struct _cv *cv4, struct pAddr *pad) -{ - struct _cv cv6; - struct mbuf *m6; - - bzero(&cv6, sizeof(struct _cv)); - m6 = translatingTCPUDPv4To6(cv4, pad, &cv6); - cv6.ip_p = cv6.ip_payload = IPPROTO_UDP; - - return (m6); -} - - -struct mbuf * -translatingTCPUDPv4To6(struct _cv *cv4, struct pAddr *pad, struct _cv *cv6) -{ - struct mbuf *m6; - struct ip *ip4; - struct ip6_hdr *ip6; - struct tcp6hdr *tcp6; - - if (cv4->m->m_flags & M_EXT) - { - if (cv4->plen + sizeof(struct ip6_hdr) > MHLEN) - { - struct mbuf *m6next; - - m6next = m_copym(cv4->m, 0, M_COPYALL, M_NOWAIT); - ReturnEnobufs(m6next); - - m6next->m_data += cv4->poff; - m6next->m_len -= cv4->poff; - - MGETHDR(m6, M_NOWAIT, MT_HEADER); - ReturnEnobufs(m6); - - m6->m_next = m6next; - m6->m_data += (MHLEN - sizeof(struct ip6_hdr)); - m6->m_len = sizeof(struct ip6_hdr); - m6->m_pkthdr.len = sizeof(struct ip6_hdr) + cv4->plen; - ip6 = mtod(m6, struct ip6_hdr *); - - cv6->m = m6; - cv6->_ip._ip6 = mtod(m6, struct ip6_hdr *); - cv6->_payload._caddr = m6next->m_data; - cv6->plen = cv4->plen; - cv6->poff = 0; - } - else /* (sizeof(struct ip6_hdr) + cv4->plen <= MHLEN) */ - { - caddr_t tcp4; - caddr_t tcp6; - - MGETHDR(m6, M_NOWAIT, MT_HEADER); - if (m6 == NULL) - { - errno = ENOBUFS; - return (NULL); - } - - ip6 = mtod(m6, struct ip6_hdr *); - tcp4 = (caddr_t)cv4->_payload._tcp4; - tcp6 = (caddr_t)ip6 + sizeof(struct ip6_hdr); - bcopy(tcp4, tcp6, cv4->plen); - - m6->m_pkthdr.len - = m6->m_len - = sizeof(struct ip6_hdr) + cv4->plen; - - cv6->m = m6; - cv6->_ip._ip6 = mtod(m6, struct ip6_hdr *); - cv6->_payload._caddr = (caddr_t)cv6->_ip._ip6 + sizeof(struct ip6_hdr); - cv6->plen = cv4->plen; - cv6->poff = cv6->_payload._caddr - (caddr_t)cv6->_ip._ip6; - } - } - else if (cv4->plen + sizeof(struct ip6_hdr) > MHLEN) - { - caddr_t tcp4; - caddr_t tcp6; - - MGETHDR(m6, M_NOWAIT, MT_HEADER); - ReturnEnobufs(m6); - MCLGET(m6, M_NOWAIT); - - m6->m_data += 128; /* make struct ether_header{} space. -- too many? */ - m6->m_pkthdr.len = m6->m_len = sizeof(struct ip6_hdr) + cv4->plen; - ip6 = mtod(m6, struct ip6_hdr *); - - tcp4 = (caddr_t)cv4->_payload._tcp4; - tcp6 = (caddr_t)ip6 + sizeof(struct ip6_hdr); - bcopy(tcp4, tcp6, cv4->plen); - - cv6->m = m6; - cv6->_ip._ip6 = mtod(m6, struct ip6_hdr *); - cv6->_payload._caddr = tcp6; - cv6->plen = cv4->plen; - cv6->poff = cv6->_payload._caddr - (caddr_t)cv6->_ip._ip6; - } - else - { - caddr_t tcp4; - caddr_t tcp6; - - MGETHDR(m6, M_NOWAIT, MT_HEADER); - if (m6 == NULL) - { - errno = ENOBUFS; - return (NULL); - } - - cv6->m = m6; - ip6 = mtod(m6, struct ip6_hdr *); - tcp4 = (caddr_t)cv4->_payload._tcp4; - tcp6 = (caddr_t)ip6 + sizeof(struct ip6_hdr); - bcopy(tcp4, tcp6, cv4->plen); - - m6->m_pkthdr.len - = m6->m_len - = sizeof(struct ip6_hdr) + cv4->plen; - - cv6->_ip._ip6 = mtod(m6, struct ip6_hdr *); - cv6->_payload._caddr = (caddr_t)cv6->_ip._ip6 + sizeof(struct ip6_hdr); - cv6->plen = cv4->plen; - cv6->poff = cv6->_payload._caddr - (caddr_t)cv6->_ip._ip6; - } - - cv6->ats = cv4->ats; - - ip4 = mtod(cv4->m, struct ip *); - ip6->ip6_flow = 0; - ip6->ip6_vfc &= ~IPV6_VERSION_MASK; - ip6->ip6_vfc |= IPV6_VERSION; - ip6->ip6_plen = htons(cv4->plen); - ip6->ip6_nxt = IPPROTO_TCP; - ip6->ip6_hlim = ip4->ip_ttl -1; - ip6->ip6_src = pad->in6src; - ip6->ip6_dst = pad->in6dst; - - tcp6 = cv6->_payload._tcp6; - tcp6->th_sport = pad->_sport; - tcp6->th_dport = pad->_dport; - - return (m6); -} - - -/* - * Translating Form IPv6 To IPv4 - */ - -struct mbuf * -translatingIPv6To4(struct _cv *cv6, struct pAddr *pad) -{ - struct timeval atv; - struct mbuf *m4 = NULL; - - if (isDump(D_TRANSLATINGIPV6)) - natpt_logIp6(LOG_DEBUG, cv6->_ip._ip6); - - microtime(&atv); - cv6->ats->tstamp = atv.tv_sec; - - switch (cv6->ip_payload) - { - case IPPROTO_ICMP: - m4 = translatingICMPv6To4(cv6, pad); - break; - - case IPPROTO_TCP: - m4 = translatingTCPv6To4(cv6, pad); - break; - - case IPPROTO_UDP: - m4 = translatingUDPv6To4(cv6, pad); - break; - } - - if (m4) - { - int mlen; - struct mbuf *mm; - struct ip *ip4; - - ip4 = mtod(m4, struct ip *); - ip4->ip_sum = 0; /* Header checksum */ - ip4->ip_sum = in_cksum(m4, sizeof(struct ip)); - m4->m_pkthdr.rcvif = cv6->m->m_pkthdr.rcvif; - - for (mlen = 0, mm = m4; mm; mm = mm->m_next) - { - mlen += mm->m_len; - } - - m4->m_pkthdr.len = mlen; - - if (isDump(D_TRANSLATEDIPV4)) - natpt_logIp4(LOG_DEBUG, ip4); - } - - return (m4); -} - - -struct mbuf * -translatingICMPv6To4(struct _cv *cv6, struct pAddr *pad) -{ - struct _cv cv4; - struct mbuf *m4; - struct ip *ip4; - struct ip6_hdr *ip6; - struct icmp *icmp4; - struct icmp6_hdr *icmp6; - - ip6 = mtod(cv6->m, struct ip6_hdr *); - icmp6 = cv6->_payload._icmp6; - - { - caddr_t icmp6end = (caddr_t)ip6 + cv6->m->m_pkthdr.len; - int icmp6len = icmp6end - (caddr_t)cv6->_payload._icmp6; - - MGETHDR(m4, M_NOWAIT, MT_HEADER); - if (m4 == NULL) - { - errno = ENOBUFS; - return (NULL); - } - if (MHLEN < (sizeof(struct ip) + icmp6len)) - MCLGET(m4, M_NOWAIT); - } - - cv4.m = m4; - cv4._ip._ip4 = mtod(m4, struct ip *); - cv4._payload._caddr = (caddr_t)cv4._ip._ip4 + sizeof(struct ip); - - ip4 = mtod(cv4.m, struct ip *); - icmp4 = cv4._payload._icmp4; - - ip4->ip_v = IPVERSION; /* IP version */ - ip4->ip_hl = 5; /* header length (no IPv4 option) */ - ip4->ip_tos = 0; /* Type Of Service */ - ip4->ip_len = htons(ip6->ip6_plen); /* Payload length */ - ip4->ip_id = 0; /* Identification */ - ip4->ip_off = 0; /* flag and fragment offset */ - ip4->ip_ttl = ip6->ip6_hlim - 1; /* Time To Live */ - ip4->ip_p = cv6->ip_payload; /* Final Payload */ - ip4->ip_src = pad->in4src; /* source addresss */ - ip4->ip_dst = pad->in4dst; /* destination address */ - - switch (icmp6->icmp6_type) - { - case ICMP6_DST_UNREACH: - tr_icmp6DstUnreach(cv6, &cv4); - break; - - case ICMP6_PACKET_TOO_BIG: - tr_icmp6PacketTooBig(cv6, &cv4); - break; - - case ICMP6_TIME_EXCEEDED: - tr_icmp6TimeExceed(cv6, &cv4); - break; - - case ICMP6_PARAM_PROB: - tr_icmp6ParamProb(cv6, &cv4); - break; - - case ICMP6_ECHO_REQUEST: - tr_icmp6EchoRequest(cv6, &cv4); - break; - - case ICMP6_ECHO_REPLY: - tr_icmp6EchoReply(cv6, &cv4); - break; - - case MLD6_LISTENER_QUERY: - case MLD6_LISTENER_REPORT: - case MLD6_LISTENER_DONE: - m_freem(m4); /* Single hop message. Silently drop. */ - return (NULL); - - default: - m_freem(m4); /* Silently drop. */ - return (NULL); - } - - { - int hlen; - struct mbuf *m4 = cv4.m; - struct ip *ip4 = cv4._ip._ip4; - - hlen = ip4->ip_hl << 2; - m4->m_data += hlen; - m4->m_len -= hlen; - icmp4->icmp_cksum = 0; - icmp4->icmp_cksum = in_cksum(cv4.m, ip4->ip_len - hlen); - m4->m_data -= hlen; - m4->m_len += hlen; - } - - return (m4); -} - - -void -tr_icmp6DstUnreach(struct _cv *cv6, struct _cv *cv4) -{ - struct icmp *icmp4 = cv4->_payload._icmp4; - struct icmp6_hdr *icmp6 = cv6->_payload._icmp6; - - icmp4->icmp_type = ICMP_UNREACH; - icmp4->icmp_code = 0; - icmp4->icmp_id = icmp6->icmp6_id; - icmp4->icmp_seq = icmp6->icmp6_seq; - - switch (icmp6->icmp6_code) - { - case ICMP6_DST_UNREACH_NOROUTE: - icmp4->icmp_code = ICMP_UNREACH_HOST; - break; - - case ICMP6_DST_UNREACH_ADMIN: - icmp4->icmp_code = ICMP_UNREACH_HOST_PROHIB; - break; - - case ICMP6_DST_UNREACH_NOTNEIGHBOR: - icmp4->icmp_code = ICMP_UNREACH_SRCFAIL; - break; - - case ICMP6_DST_UNREACH_ADDR: - icmp4->icmp_code = ICMP_UNREACH_HOST; - break; - - case ICMP6_DST_UNREACH_NOPORT: - icmp4->icmp_code = ICMP_UNREACH_PORT; - break; - } -} - - -void -tr_icmp6PacketTooBig(struct _cv *cv6, struct _cv *cv4) -{ - struct icmp *icmp4 = cv4->_payload._icmp4; - struct icmp6_hdr *icmp6 = cv6->_payload._icmp6; - - icmp4->icmp_type = ICMP_UNREACH; - icmp4->icmp_code = ICMP_UNREACH_NEEDFRAG; /* do more */ - icmp4->icmp_id = icmp6->icmp6_id; - icmp4->icmp_seq = icmp6->icmp6_seq; -} - - -void -tr_icmp6TimeExceed(struct _cv *cv6, struct _cv *cv4) -{ - struct icmp *icmp4 = cv4->_payload._icmp4; - struct icmp6_hdr *icmp6 = cv6->_payload._icmp6; - - icmp4->icmp_type = ICMP_TIMXCEED; - icmp4->icmp_code = icmp6->icmp6_code; /* code unchanged. */ - icmp4->icmp_id = icmp6->icmp6_id; - icmp4->icmp_seq = icmp6->icmp6_seq; -} - - -void -tr_icmp6ParamProb(struct _cv *cv6, struct _cv *cv4) -{ - struct icmp *icmp4 = cv4->_payload._icmp4; - struct icmp6_hdr *icmp6 = cv6->_payload._icmp6; - - icmp4->icmp_type = ICMP_PARAMPROB; /* do more */ - icmp4->icmp_code = 0; - icmp4->icmp_id = icmp6->icmp6_id; - icmp4->icmp_seq = icmp6->icmp6_seq; - - if (icmp6->icmp6_code == ICMP6_PARAMPROB_NEXTHEADER) - { - icmp4->icmp_type = ICMP_UNREACH; - icmp4->icmp_code = ICMP_UNREACH_PROTOCOL; - } -} - - -void -tr_icmp6EchoRequest(struct _cv *cv6, struct _cv *cv4) -{ - struct icmp *icmp4 = cv4->_payload._icmp4; - struct icmp6_hdr *icmp6 = cv6->_payload._icmp6; - - icmp4->icmp_type = ICMP_ECHO; - icmp4->icmp_code = 0; - icmp4->icmp_id = icmp6->icmp6_id; - icmp4->icmp_seq = icmp6->icmp6_seq; - - { - int dlen; - struct ip *ip4 = cv4->_ip._ip4; - struct ip6_hdr *ip6 = cv6->_ip._ip6; - caddr_t icmp6off, icmp4off; - caddr_t icmp6end = (caddr_t)ip6 + cv6->m->m_pkthdr.len; - int icmp6len = icmp6end - (caddr_t)cv6->_payload._icmp6; - - dlen = icmp6len - sizeof(struct icmp6_hdr); - icmp6off = (caddr_t)(cv6->_payload._icmp6) + sizeof(struct icmp6_hdr); - icmp4off = (caddr_t)(cv4->_payload._icmp4) + ICMP_MINLEN; - bcopy(icmp6off, icmp4off, dlen); - - ip4->ip_len = cv4->m->m_len = sizeof(struct ip) + ICMP_MINLEN + dlen; - } -} - - -void -tr_icmp6EchoReply(struct _cv *cv6, struct _cv *cv4) -{ - struct icmp *icmp4 = cv4->_payload._icmp4; - struct icmp6_hdr *icmp6 = cv6->_payload._icmp6; - - icmp4->icmp_type = ICMP_ECHOREPLY; - icmp4->icmp_code = 0; - icmp4->icmp_id = icmp6->icmp6_id; - icmp4->icmp_seq = icmp6->icmp6_seq; - - { - int dlen; - struct ip *ip4 = cv4->_ip._ip4; - struct ip6_hdr *ip6 = cv6->_ip._ip6; - caddr_t icmp6off, icmp4off; - caddr_t icmp6end = (caddr_t)ip6 + cv6->m->m_pkthdr.len; - int icmp6len = icmp6end - (caddr_t)cv6->_payload._icmp6; - - dlen = icmp6len - sizeof(struct icmp6_hdr); - icmp6off = (caddr_t)(cv6->_payload._icmp6) + sizeof(struct icmp6_hdr); - icmp4off = (caddr_t)(cv4->_payload._icmp4) + ICMP_MINLEN; - bcopy(icmp6off, icmp4off, dlen); - - ip4->ip_len = cv4->m->m_len = sizeof(struct ip) + ICMP_MINLEN + dlen; - } -} - - -struct mbuf * -translatingTCPv6To4(struct _cv *cv6, struct pAddr *pad) -{ - int cksumOrg; - struct _cv cv4; - struct mbuf *m4; - - bzero(&cv4, sizeof(struct _cv)); - m4 = translatingTCPUDPv6To4(cv6, pad, &cv4); - cv4.ip_p = cv4.ip_payload = IPPROTO_TCP; - cksumOrg = ntohs(cv6->_payload._tcp6->th_sum); - - updateTcpStatus(cv6); - adjustUpperLayerChecksum(IPPROTO_IPV6, IPPROTO_TCP, cv6, &cv4); - -#ifdef recalculateTCP4Checksum - _recalculateTCP4Checksum(&cv4); -#endif - - return (m4); -} - - -struct mbuf * -translatingUDPv6To4(struct _cv *cv6, struct pAddr *pad) -{ - struct _cv cv4; - struct mbuf *m4; - - bzero(&cv4, sizeof(struct _cv)); - m4 = translatingTCPUDPv6To4(cv6, pad, &cv4); - cv4.ip_p = cv4.ip_payload = IPPROTO_UDP; - - adjustUpperLayerChecksum(IPPROTO_IPV6, IPPROTO_UDP, cv6, &cv4); - -#if 1 - { - int cksumAdj, cksumCks; - int iphlen; - struct ip *ip4 = cv4._ip._ip4; - struct ip save_ip; - struct udpiphdr *ui; - - cksumAdj = cv4._payload._tcp4->th_sum; - - ui = mtod(cv4.m, struct udpiphdr *); - iphlen = ip4->ip_hl << 2; - - save_ip = *cv4._ip._ip4; - bzero(ui, sizeof(struct udpiphdr)); - ui->ui_pr = IPPROTO_UDP; - ui->ui_len = htons(cv4.m->m_pkthdr.len - iphlen); - ui->ui_src = save_ip.ip_src; - ui->ui_dst = save_ip.ip_dst; - - ui->ui_sum = 0; - ui->ui_sum = in_cksum(cv4.m, cv4.m->m_pkthdr.len); - *cv4._ip._ip4 = save_ip; - - cksumCks = ui->ui_sum; -#if 0 - printf("translatingUDPv6To4: UDP6->UDP4: %04x, %04x %d\n", - cksumAdj, cksumCks, cv4.m->m_pkthdr.len); -#endif - } -#endif - - return (m4); -} - - -struct mbuf * -translatingTCPUDPv6To4(struct _cv *cv6, struct pAddr *pad, struct _cv *cv4) -{ - struct mbuf *m4; - struct ip *ip4; - struct ip6_hdr *ip6; - struct tcphdr *th; - - m4 = m_copym(cv6->m, 0, M_COPYALL, M_NOWAIT); - ReturnEnobufs(m4); - - m4->m_data += sizeof(struct ip6_hdr) - sizeof(struct ip); - m4->m_pkthdr.len = m4->m_len = sizeof(struct ip) + cv6->plen; - - cv4->m = m4; - cv4->plen = cv6->plen; - cv4->poff = sizeof(struct ip); - cv4->_ip._ip4 = mtod(m4, struct ip *); - cv4->_payload._caddr = (caddr_t)cv4->_ip._ip4 + sizeof(struct ip); - - cv4->ats = cv6->ats; - - ip4 = mtod(m4, struct ip *); - ip6 = mtod(cv6->m, struct ip6_hdr *); - ip4->ip_v = IPVERSION; /* IP version */ - ip4->ip_hl = 5; /* header length (no IPv4 option) */ - ip4->ip_tos = 0; /* Type Of Service */ - ip4->ip_len = sizeof(struct ip) + ntohs(ip6->ip6_plen); - /* Payload length */ - ip4->ip_id = 0; /* Identification */ - ip4->ip_off = 0; /* flag and fragment offset */ - ip4->ip_ttl = ip6->ip6_hlim; /* Time To Live */ - ip4->ip_p = cv6->ip_payload; /* Final Payload */ - ip4->ip_src = pad->in4src; /* source addresss */ - ip4->ip_dst = pad->in4dst; /* destination address */ - - th = (struct tcphdr *)(ip4 + 1); - th->th_sport = pad->_sport; - th->th_dport = pad->_dport; - - return (m4); -} - - -/* - * Itojun said 'code fragment in "#ifdef recalculateTCP4Checksum" - * does not make sense to me'. I agree, but - * adjustUpperLayerChecksum() cause checksum error sometime but - * not always, so I left its code. After I fixed it, this code - * will become vanish. - */ - -static void -_recalculateTCP4Checksum(struct _cv *cv4) -{ - int cksumAdj, cksumCks; - int iphlen; - struct ip *ip4 = cv4->_ip._ip4; - struct ip save_ip; - struct tcpiphdr *ti; - - cksumAdj = cv4->_payload._tcp4->th_sum; - - ti = mtod(cv4->m, struct tcpiphdr *); - iphlen = ip4->ip_hl << 2; - - save_ip = *cv4->_ip._ip4; -#ifdef ti_next - ti->ti_next = ti->ti_prev = 0; - ti->ti_x1 = 0; -#else - bzero(ti->ti_x1, 9); -#endif - ti->ti_pr = IPPROTO_TCP; - ti->ti_len = htons(cv4->m->m_pkthdr.len - iphlen); - ti->ti_src = save_ip.ip_src; - ti->ti_dst = save_ip.ip_dst; - - ti->ti_sum = 0; - ti->ti_sum = in_cksum(cv4->m, cv4->m->m_pkthdr.len); - *cv4->_ip._ip4 = save_ip; - - cksumCks = ti->ti_sum; -#if 0 - printf("translatingTCPv6To4: TCP6->TCP4: %04x, %04x, %04x %d\n", - cksumOrg, cksumAdj, cksumCks, cv4->m->m_pkthdr.len); -#endif -} - - -/* - * - */ - -static int -updateTcpStatus(struct _cv *cv) -{ - struct _tSlot *ats = cv->ats; - struct _tcpstate *ts; - - if (ats->ip_payload != IPPROTO_TCP) - return (0); /* XXX */ - - if ((ts = ats->suit.tcp) == NULL) - { - MALLOC(ts, struct _tcpstate *, sizeof(struct _tcpstate), M_NATPT, M_NOWAIT); - if (ts == NULL) - { - return (0); /* XXX */ - } - - bzero(ts, sizeof(struct _tcpstate)); - - ts->_state = TCPS_CLOSED; - ats->suit.tcp = ts; - } - - ts->_state - = _natpt_tcpfsm(ats->session, cv->inout, ts->_state, cv->_payload._tcp4->th_flags); - - return (0); -} - - -static int -_natpt_tcpfsm(int session, int inout, u_short state, u_char flags) -{ - int rv; - - if (flags & TH_RST) - return (TCPS_CLOSED); - - if (session == NATPT_OUTBOUND) - rv = _natpt_tcpfsmSessOut(inout, state, flags); - else - rv = _natpt_tcpfsmSessIn (inout, state, flags); - - return (rv); -} - - -/* -//## -//#------------------------------------------------------------------------ -//# _natpt_tcpfsmSessOut - - delta(start, eps) -> CLOSED - delta(CLOSED, TH_SYN & !TH_ACK) -> SYN_SENT - delta(SYN_SENT, in TH_SYN & TH_ACK) -> SYN_RCVD - delta(SYN_RCVD, TH_ACK) -> ESTABLISHED - delta(ESTABLISHED, TH_FIN) -> FIN_WAIT_1 - delta(FIN_WAIT_1, in TH_FIN | TH_ACK) -> TIME_WAIT - delta(FIN_WAIT_1, in TH_ACK) -> FIN_WAIT_2 - delta(FIN_WAIT_1, in TH_FIN) -> CLOSING - delta(FIN_WAIT_2, in TH_FIN) -> TIME_WAIT - delta(CLOSING, TH_ACK) -> TIME_WAIT - delta(TIME_WAIT, eps) -> CLOSED - -//#------------------------------------------------------------------------ -*/ - -static int -_natpt_tcpfsmSessOut(int inout, short state, u_char flags) -{ - int rv = state; - - switch (state) - { - case TCPS_CLOSED: - if ((inout == NATPT_OUTBOUND) - && (((flags & TH_SYN) != 0) - && (flags & TH_ACK) == 0)) - rv = TCPS_SYN_SENT; - break; - - case TCPS_SYN_SENT: - if ((inout == NATPT_INBOUND) - && (flags & (TH_SYN | TH_ACK))) - rv = TCPS_SYN_RECEIVED; - break; - - case TCPS_SYN_RECEIVED: - if ((inout == NATPT_OUTBOUND) - && (flags & TH_ACK)) - rv = TCPS_ESTABLISHED; - break; - - case TCPS_ESTABLISHED: - if ((inout == NATPT_OUTBOUND) - && (flags & TH_FIN)) - rv = TCPS_FIN_WAIT_1; - break; - - case TCPS_FIN_WAIT_1: - if (inout == NATPT_INBOUND) - { - if (flags & (TH_FIN | TH_ACK)) rv = TCPS_TIME_WAIT; - else if (flags & TH_ACK) rv = TCPS_FIN_WAIT_2; - else if (flags & TH_FIN) rv = TCPS_CLOSING; - } - break; - - case TCPS_CLOSING: - if ((inout == NATPT_OUTBOUND) - && (flags & TH_ACK)) - rv = TCPS_TIME_WAIT; - break; - - case TCPS_FIN_WAIT_2: - if ((inout == NATPT_INBOUND) - && (flags & TH_FIN)) - rv = TCPS_TIME_WAIT; - break; - } - - return (rv); -} - - -/* -//## -//#------------------------------------------------------------------------ -//# _natpt_tcpfsmSessIn - - delta(start, eps) -> CLOSED - delta(CLOSED, TH_SYN & !TH_ACK) -> SYN_RCVD - delta(SYN_RCVD, TH_ACK) -> ESTABLISHED - delta(ESTABLISHED, in TH_FIN) -> CLOSE_WAIT - delta(ESTABLISHED, out TH_FIN) -> FIN_WAIT_1 - delta(CLOSE_WAIT, out TH_FIN) -> LAST_ACK - delta(FIN_WAIT_1, TH_FIN & TH_ACK) -> TIME_WAIT - delta(FIN_WAIT_1, TH_FIN) -> CLOSING - delta(FIN_WAIT_1, TH_ACK) -> FIN_WAIT_2 - delta(CLOSING, TH_ACK) -> TIME_WAIT - delta(LAST_ACK), TH_ACK) -> CLOSED - delta(FIN_WAIT_2, TH_FIN) -> TIME_WAIT - delta(TIME_WAIT, eps) -> CLOSED - -//#------------------------------------------------------------------------ -*/ - -static int -_natpt_tcpfsmSessIn(int inout, short state, u_char flags) -{ - int rv = state; - - switch (state) - { - case TCPS_CLOSED: - if ((inout == NATPT_INBOUND) - && (((flags & TH_SYN) != 0) - && (flags & TH_ACK) == 0)) - rv = TCPS_SYN_RECEIVED; - break; - - case TCPS_SYN_RECEIVED: - if ((inout == NATPT_INBOUND) - && (flags & TH_ACK)) - rv = TCPS_ESTABLISHED; - break; - - case TCPS_ESTABLISHED: - if ((inout == NATPT_INBOUND) - && (flags & TH_FIN)) - rv = TCPS_CLOSE_WAIT; - if ((inout == NATPT_OUTBOUND) - && (flags & TH_FIN)) - rv = TCPS_FIN_WAIT_1; - break; - - case TCPS_CLOSE_WAIT: - if ((inout == NATPT_OUTBOUND) - && (flags & TH_FIN)) - rv = TCPS_LAST_ACK; - break; - - case TCPS_FIN_WAIT_1: - if (inout == NATPT_INBOUND) - { - if (flags & (TH_FIN | TH_ACK)) rv = TCPS_TIME_WAIT; - else if (flags & TH_FIN) rv = TCPS_CLOSING; - else if (flags & TH_ACK) rv = TCPS_FIN_WAIT_2; - } - break; - - case TCPS_CLOSING: - if ((inout == NATPT_INBOUND) - && (flags & TH_ACK)) - rv = TCPS_TIME_WAIT; - break; - - case TCPS_LAST_ACK: - if ((inout == NATPT_INBOUND) - && (flags & TH_ACK)) - rv = TCPS_CLOSED; - break; - - case TCPS_FIN_WAIT_2: - if ((inout == NATPT_INBOUND) - && (flags & TH_FIN)) - rv = TCPS_TIME_WAIT; - break; - } - - return (rv); -} - - -/* - * - */ - -static void -adjustUpperLayerChecksum(int header, int proto, struct _cv *cv6, struct _cv *cv4) -{ - u_short cksum; - struct ipovly ip4; - struct ulc - { - struct in6_addr ulc_src; - struct in6_addr ulc_dst; - u_long ulc_len; - u_char ulc_zero[3]; - u_char ulc_nxt; - } ulc; - - bzero(&ulc, sizeof(struct ulc)); - bzero(&ip4, sizeof(struct ipovly)); - - ulc.ulc_src = cv6->_ip._ip6->ip6_src; - ulc.ulc_dst = cv6->_ip._ip6->ip6_dst; - ulc.ulc_len = htonl(cv6->plen); - ulc.ulc_nxt = cv6->ip_p; - - ip4.ih_src = cv4->_ip._ip4->ip_src; - ip4.ih_dst = cv4->_ip._ip4->ip_dst; - ip4.ih_len = htons(cv4->plen); - ip4.ih_pr = cv4->ip_p; - - switch (proto) - { - case IPPROTO_TCP: - if (header == IPPROTO_IPV6) - { - cksum = adjustChecksum(ntohs(cv6->_payload._tcp6->th_sum), - (u_char *)&ulc, sizeof(struct ulc), - (u_char *)&ip4, sizeof(struct ipovly)); - cv4->_payload._tcp4->th_sum = htons(cksum); - } - else - { - cksum = adjustChecksum(ntohs(cv4->_payload._tcp4->th_sum), - (u_char *)&ip4, sizeof(struct ipovly), - (u_char *)&ulc, sizeof(struct ulc)); - cv6->_payload._tcp6->th_sum = htons(cksum); - } - break; - - case IPPROTO_UDP: - if (header == IPPROTO_IPV6) - { - cksum = adjustChecksum(ntohs(cv6->_payload._udp->uh_sum), - (u_char *)&ulc, sizeof(struct ulc), - (u_char *)&ip4, sizeof(struct ipovly)); - cv4->_payload._udp->uh_sum = htons(cksum); - } - else - { - cksum = adjustChecksum(ntohs(cv4->_payload._udp->uh_sum), - (u_char *)&ip4, sizeof(struct ipovly), - (u_char *)&ulc, sizeof(struct ulc)); - cv6->_payload._udp->uh_sum = htons(cksum); - } - break; - - default: - } -} - - -static int -adjustChecksum(int cksum, u_char *optr, int olen, u_char *nptr, int nlen) -{ - long x, old, new; - - x = ~cksum & 0xffff; - - while (olen) - { - if (olen == 1) - { - old = optr[0] * 256 + optr[1]; - x -= old & 0xff00; - if ( x <= 0 ) { x--; x &= 0xffff; } - break; - } - else - { - old = optr[0] * 256 + optr[1]; - x -= old & 0xffff; - if ( x <= 0 ) { x--; x &= 0xffff; } - optr += 2; - olen -= 2; - } - } - - while (nlen) - { - if (nlen == 1) - { - new = nptr[0] * 256 + nptr[1]; - x += new & 0xff00; - if (x & 0x10000) { x++; x &= 0xffff; } - break; - } - else - { - new = nptr[0] * 256 + nptr[1]; - x += new & 0xffff; - if (x & 0x10000) { x++; x &= 0xffff; } - nptr += 2; - nlen -= 2; - } - } - - return (~x & 0xffff); -} diff --git a/bsd/netinet6/natpt_tslot.c b/bsd/netinet6/natpt_tslot.c deleted file mode 100644 index b3fd9e937..000000000 --- a/bsd/netinet6/natpt_tslot.c +++ /dev/null @@ -1,1043 +0,0 @@ -/* $KAME: natpt_tslot.c,v 1.8 2000/03/25 07:23:56 sumikawa Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#if !defined(__NetBSD__) && (!defined(__FreeBSD__) || (__FreeBSD__ < 3)) && !defined(__APPLE__) -#include -#endif - -#include -#include -#include -#include - - -/* - * - */ - -static Cell *_insideHash [NATPT_MAXHASH]; -static Cell *_outsideHash[NATPT_MAXHASH]; - -static Cell *tSlotEntry; -static int tSlotEntryMax; -static int tSlotEntryUsed; - -static time_t tSlotTimer; -static time_t maxTTLany; -static time_t maxTTLicmp; -static time_t maxTTLudp; -static time_t maxTTLtcp; - -static time_t _natpt_TCPT_2MSL; -static time_t _natpt_tcp_maxidle; - -extern struct in6_addr natpt_prefix; -extern struct in6_addr natpt_prefixmask; -extern struct in6_addr faith_prefix; -extern struct in6_addr faith_prefixmask; - -static struct pAddr *fillupOutgoingV6local __P((struct _cSlot *, struct _cv *, struct pAddr *)); -static struct pAddr *fillupOutgoingV6Remote __P((struct _cSlot *, struct _cv *, struct pAddr *)); - -static struct _tSlot *registTSlotEntry __P((struct _tSlot *)); -static void _expireTSlot __P((void *)); -static void _expireTSlotEntry __P((struct timeval *)); -static void _removeTSlotEntry __P((struct _cell *, struct _cell *)); -static int _removeHash __P((struct _cell *(*table)[], int, caddr_t)); - -static int _hash_ip4 __P((struct _cv *)); -static int _hash_ip6 __P((struct _cv *)); -static int _hash_pat4 __P((struct pAddr *)); -static int _hash_pat6 __P((struct pAddr *)); -static int _hash_sockaddr4 __P((struct sockaddr_in *)); -static int _hash_sockaddr6 __P((struct sockaddr_in6 *)); -static int _hash_pjw __P((u_char *, int)); - - -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -static MALLOC_DEFINE(M_NATPT, "NATPT", "Network Address Translation - Protocol Translation"); -#endif - - -/* - * - */ - -struct _tSlot * -lookingForIncomingV4Hash(struct _cv *cv) -{ - register Cell *p; - register struct _tSlot *ats; - register struct ip *ip4; - - int hv = _hash_ip4(cv); - - for (p = _outsideHash[hv]; p; p = CDR(p)) - { - ats = (struct _tSlot *)CAR(p); - - if ((ats->remote.ip_p != IPPROTO_IPV4) - || (cv->ip_payload != ats->ip_payload)) continue; - - if ((cv->ip_payload == IPPROTO_TCP) - || (cv->ip_payload == IPPROTO_UDP)) - { - if (cv->_payload._tcp4->th_sport!= ats->remote._dport) continue; - if (cv->_payload._tcp4->th_dport!= ats->remote._sport) continue; - } - - ip4 = cv->_ip._ip4; - if ((ip4->ip_src.s_addr == ats->remote.in4dst.s_addr) - && (ip4->ip_dst.s_addr == ats->remote.in4src.s_addr)) - return (ats); - } - - return (NULL); -} - - -struct _tSlot * -lookingForOutgoingV4Hash(struct _cv *cv) -{ - register Cell *p; - register struct _tSlot *ats; - register struct ip *ip4; - - int hv = _hash_ip4(cv); - - for (p = _insideHash[hv]; p; p = CDR(p)) - { - ats = (struct _tSlot *)CAR(p); - - if ((ats->local.ip_p != IPPROTO_IPV4) - || (cv->ip_payload != ats->ip_payload)) continue; - - if ((cv->ip_payload == IPPROTO_TCP) - || (cv->ip_payload == IPPROTO_UDP)) - { - if (cv->_payload._tcp4->th_sport != ats->local._dport) continue; - if (cv->_payload._tcp4->th_dport != ats->local._sport) continue; - } - - ip4 = cv->_ip._ip4; - if ((ip4->ip_src.s_addr == ats->local.in4dst.s_addr) - && (ip4->ip_dst.s_addr == ats->local.in4src.s_addr)) - return (ats); - } - - return (NULL); -} - - -struct _tSlot * -lookingForIncomingV6Hash(struct _cv *cv) -{ - register Cell *p; - register struct _tSlot *ats; - register struct ip6_hdr *ip6; - - int hv = _hash_ip6(cv); - - for (p = _outsideHash[hv]; p; p = CDR(p)) - { - ats = (struct _tSlot *)CAR(p); - - if ((ats->remote.ip_p != IPPROTO_IPV6) - || (cv->ip_payload != ats->ip_payload)) continue; - - if ((cv->ip_payload == IPPROTO_TCP) - || (cv->ip_payload == IPPROTO_UDP)) - { - if (cv->_payload._tcp6->th_sport != ats->remote._dport) continue; - if (cv->_payload._tcp6->th_dport != ats->remote._sport) continue; - } - - ip6 = cv->_ip._ip6; - if ((IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &ats->remote.in6dst)) - && (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &ats->remote.in6src))) - return (ats); - } - - return (NULL); -} - - -struct _tSlot * -lookingForOutgoingV6Hash(struct _cv *cv) -{ - register Cell *p; - register struct _tSlot *ats; - register struct ip6_hdr *ip6; - - int hv = _hash_ip6(cv); - - for (p = _insideHash[hv]; p; p = CDR(p)) - { - ats = (struct _tSlot *)CAR(p); - - if ((ats->local.ip_p != IPPROTO_IPV6) - || (cv->ip_payload != ats->ip_payload)) continue; - - if ((cv->ip_payload == IPPROTO_TCP) - || (cv->ip_payload == IPPROTO_UDP)) - { - if (cv->_payload._tcp6->th_sport != ats->local._dport) continue; - if (cv->_payload._tcp6->th_dport != ats->local._sport) continue; - } - - ip6 = cv->_ip._ip6; - if ((IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &ats->local.in6dst)) - && (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &ats->local.in6src))) - return (ats); - } - - return (NULL); -} - - -struct _tSlot * -internIncomingV4Hash(int sess, struct _cSlot *acs, struct _cv *cv4) -{ - int s, hv4, hv6; - struct pAddr *local, *remote; - struct _tSlot *ats; - - MALLOC(ats, struct _tSlot *, sizeof(struct _tSlot), M_TEMP, M_NOWAIT); - if (ats == NULL) - { - printf("ENOBUFS in internIncomingV4Hash %d\n", __LINE__); - return (NULL); - } - - bzero(ats, sizeof(struct _tSlot)); - - local = &ats->local; - remote = &ats->remote; - -#ifdef NATPT_NAT - if (acs->local.sa_family == AF_INET) - { - local->ip_p = IPPROTO_IPV4; - local->sa_family = AF_INET; - local->in4src = cv4->_ip._ip4->ip_src; - local->in4dst = acs->local.in4Addr; - if ((cv4->ip_payload == IPPROTO_TCP) - || (cv4->ip_payload == IPPROTO_UDP)) - { - local->_sport = cv4->_payload._tcp4->th_sport; - local->_dport = cv4->_payload._tcp4->th_dport; - if (acs->map & NATPT_PORT_MAP) - { - local->_dport = acs->local._port0; - } - } - } - else -#else - { - local->ip_p = IPPROTO_IPV6; - local->sa_family = AF_INET6; - local->in6src = natpt_prefix; - local->in6src.s6_addr32[3] = cv4->_ip._ip4->ip_src.s_addr; - local->in6dst = acs->local.in6src; - if ((cv4->ip_payload == IPPROTO_TCP) - || (cv4->ip_payload == IPPROTO_UDP)) - { - local->_sport = cv4->_payload._tcp4->th_sport; - local->_dport = cv4->_payload._tcp4->th_dport; - - if (acs->map & NATPT_PORT_MAP) - { - local->_dport = acs->local._port0; - } - } - } -#endif - - remote = &ats->remote; - remote->ip_p = IPPROTO_IPV4; - remote->sa_family = AF_INET; - remote->in4src = acs->remote.in4src; - remote->in4dst = cv4->_ip._ip4->ip_src; - if (acs->remote.ad.type == ADDR_ANY) - { - remote->in4src = cv4->_ip._ip4->ip_dst; - } - - if ((cv4->ip_payload == IPPROTO_TCP) - || (cv4->ip_payload == IPPROTO_UDP)) - { - remote->_sport = cv4->_payload._tcp4->th_dport; - remote->_dport = cv4->_payload._tcp4->th_sport; - } - - ats->ip_payload = cv4->ip_payload; - ats->session = sess; - registTSlotEntry(ats); /* XXX */ - - hv4 = _hash_pat4(remote); -#ifdef NATPT_NAT - if (acs->local.sa_family == AF_INET) - hv6 = _hash_pat4(local); - else -#else - hv6 = _hash_pat6(local); -#endif - - s = splnet(); - LST_hookup_list(&_insideHash [hv6], ats); - LST_hookup_list(&_outsideHash[hv4], ats); - splx(s); - - return (ats); -} - - -struct _tSlot * -internOutgoingV4Hash(int sess, struct _cSlot *acs, struct _cv *cv4) -{ - int s, hv4, hv6; - struct pAddr *local, *remote; - struct _tSlot *ats; - - MALLOC(ats, struct _tSlot *, sizeof(struct _tSlot), M_TEMP, M_NOWAIT); - if (ats == NULL) - { - printf("ENOBUFS in internOutgoingV4Hash %d\n", __LINE__); - return (NULL); - } - - bzero(ats, sizeof(struct _tSlot)); - - local = &ats->local; - local->ip_p = IPPROTO_IPV4; - local->sa_family = AF_INET; - if ((cv4->ip_payload == IPPROTO_TCP) - || (cv4->ip_payload == IPPROTO_UDP)) - { - local->_sport = cv4->_payload._tcp4->th_dport; - local->_dport = cv4->_payload._tcp4->th_sport; - } - - local->in4src = cv4->_ip._ip4->ip_dst; - local->in4dst = cv4->_ip._ip4->ip_src; - - remote = &ats->remote; -#ifdef NATPT_NAT - if (acs->remote.sa_family == AF_INET) - { - remote->ip_p = IPPROTO_IPV4; - remote->sa_family = AF_INET; - if ((cv4->ip_payload == IPPROTO_TCP) - || (cv4->ip_payload == IPPROTO_UDP)) - { - remote->_sport = cv4->_payload._tcp4->th_sport; - remote->_dport = cv4->_payload._tcp4->th_dport; - } - remote->in4src = acs->remote.in4src; - remote->in4dst = cv4->_ip._ip4->ip_dst; - } - else -#else /* need check */ - { - remote->ip_p = IPPROTO_IPV6; - remote->sa_family = AF_INET6; - if ((cv4->ip_payload == IPPROTO_TCP) - || (cv4->ip_payload == IPPROTO_UDP)) - { - remote->_sport = cv4->_payload._tcp4->th_sport; - remote->_dport = cv4->_payload._tcp4->th_dport; - } - - if (acs->flags == NATPT_FAITH) - { - struct in6_ifaddr *ia6; - - remote->in6dst.s6_addr32[0] = faith_prefix.s6_addr32[0]; - remote->in6dst.s6_addr32[1] = faith_prefix.s6_addr32[1]; - remote->in6dst.s6_addr32[3] = cv4->_ip._ip4->ip_dst.s_addr; - - ia6 = in6_ifawithscope(natpt_ip6src, &remote->in6dst); - remote->in6src = ia6->ia_addr.sin6_addr; - } - else - { - remote->in6src.s6_addr32[3] = cv4->_ip._ip4->ip_src.s_addr; - remote->in6dst = acs->remote.in6src; - } - } -#endif - - ats->ip_payload = cv4->ip_payload; - ats->session = sess; - registTSlotEntry(ats); /* XXX */ - - hv4 = _hash_pat4(local); -#ifdef NATPT_NAT - if (acs->remote.sa_family == AF_INET) - hv6 = _hash_pat4(remote); - else -#else - hv6 = _hash_pat6(remote); -#endif - - s = splnet(); - LST_hookup_list(&_insideHash [hv4], ats); - LST_hookup_list(&_outsideHash[hv6], ats); - splx(s); - - return (ats); -} - - -struct _tSlot * -internIncomingV6Hash(int sess, struct _cSlot *acs, struct _cv *cv6) -{ - int s, hv4, hv6; - struct pAddr *local, *remote; - struct _tSlot *ats; - - MALLOC(ats, struct _tSlot *, sizeof(struct _tSlot), M_TEMP, M_NOWAIT); - if (ats == NULL) - { - printf("ENOBUFS in internIncomingV6Hash %d\n", __LINE__); - return (NULL); - } - - bzero(ats, sizeof(struct _tSlot)); - - local = &ats->local; - local->ip_p = IPPROTO_IPV4; - local->sa_family = AF_INET; - if ((cv6->ip_payload == IPPROTO_TCP) - || (cv6->ip_payload == IPPROTO_UDP)) - { - local->_sport = cv6->_payload._tcp6->th_sport; - local->_dport = cv6->_payload._tcp6->th_dport; - } - local->in4src = acs->local.in4src; - local->in4dst.s_addr = cv6->_ip._ip6->ip6_dst.s6_addr32[3]; - local->sa_family = AF_INET; - local->ip_p = IPPROTO_IPV4; - - remote = &ats->remote; - remote->ip_p = IPPROTO_IPV6; - if ((cv6->ip_payload == IPPROTO_TCP) - || (cv6->ip_payload == IPPROTO_UDP)) - { - remote->_sport = cv6->_payload._tcp6->th_dport; - remote->_dport = cv6->_payload._tcp6->th_sport; - } - remote->in6src = cv6->_ip._ip6->ip6_dst; - remote->in6dst = acs->remote.in6dst; - remote->sa_family = AF_INET6; - remote->ip_p = IPPROTO_IPV6; - - ats->ip_payload = cv6->ip_payload; - ats->session = sess; - registTSlotEntry(ats); /* XXX */ - - hv6 = _hash_pat6(remote); - hv4 = _hash_pat4(local); - - s = splnet(); - LST_hookup_list(&_outsideHash[hv6], ats); - LST_hookup_list(&_insideHash [hv4], ats); - splx(s); - - return (ats); -} - - -struct _tSlot * -internOutgoingV6Hash(int sess, struct _cSlot *acs, struct _cv *cv6) -{ - int s, hv4, hv6; - struct pAddr *local, *remote; - struct _tSlot *ats; - - natpt_logIp6(LOG_DEBUG, cv6->_ip._ip6); - - MALLOC(ats, struct _tSlot *, sizeof(struct _tSlot), M_TEMP, M_NOWAIT); - if (ats == NULL) - { - printf("ENOBUFS in internOutgoingV6Hash %d\n", __LINE__); - return (NULL); - } - - bzero(ats, sizeof(struct _tSlot)); - - local = fillupOutgoingV6local(acs, cv6, &ats->local); - if ((remote = fillupOutgoingV6Remote(acs, cv6, &ats->remote)) == 0) - { - FREE(ats, M_TEMP); - return (NULL); - } - - ats->ip_payload = cv6->ip_payload; - ats->session = sess; - registTSlotEntry(ats); /* XXX */ - - hv6 = _hash_pat6(local); - hv4 = _hash_pat4(remote); - - s = splnet(); - LST_hookup_list(&_insideHash [hv6], ats); - LST_hookup_list(&_outsideHash[hv4], ats); - splx(s); - - return (ats); -} - - -struct _tSlot * -checkTraceroute6Return(struct _cv *cv4) -{ - int hv; - Cell *p; - struct ip *icmpip4; - struct udphdr *icmpudp4; - struct sockaddr_in src, dst; - struct _tSlot *ats; - - if ((cv4->ip_payload != IPPROTO_ICMP) - || ((cv4->_payload._icmp4->icmp_type != ICMP_UNREACH) - && (cv4->_payload._icmp4->icmp_type != ICMP_TIMXCEED))) - return (NULL); - - icmpip4 = &cv4->_payload._icmp4->icmp_ip; - if (icmpip4->ip_p != IPPROTO_UDP) - return (NULL); - -#ifdef fixSuMiReICMPBug - icmpip4->ip_src.s_addr = ICMPSRC; /* XXX */ -#endif - - icmpudp4 = (struct udphdr *)((caddr_t)icmpip4 + (icmpip4->ip_hl << 2)); - - bzero(&src, sizeof(struct sockaddr_in)); - bzero(&dst, sizeof(struct sockaddr_in)); - src.sin_addr = icmpip4->ip_src; - src.sin_port = icmpudp4->uh_sport; - dst.sin_addr = icmpip4->ip_dst; - dst.sin_port = icmpudp4->uh_dport; - hv = ((_hash_sockaddr4(&src) + _hash_sockaddr4(&dst)) % NATPT_MAXHASH); - for (p = _outsideHash[hv]; p; p = CDR(p)) - { - ats = (struct _tSlot *)CAR(p); - - if (ats->remote.ip_p != IPPROTO_IPV4) continue; - if (ats->ip_payload != IPPROTO_UDP) continue; - - if (icmpip4->ip_src.s_addr != ats->remote.in4src.s_addr) continue; - if (icmpip4->ip_dst.s_addr != ats->remote.in4dst.s_addr) continue; - - if (icmpudp4->uh_sport != ats->remote._sport) continue; - if (icmpudp4->uh_dport != ats->remote._dport) continue; - - cv4->flags |= NATPT_TRACEROUTE; - return (ats); - } - - return (NULL); -} - - -static struct pAddr * -fillupOutgoingV6local(struct _cSlot *acs, struct _cv *cv6, struct pAddr *local) -{ - local->ip_p = IPPROTO_IPV6; - local->sa_family = AF_INET6; - local->in6src = cv6->_ip._ip6->ip6_dst; - local->in6dst = cv6->_ip._ip6->ip6_src; - - if ((cv6->ip_payload == IPPROTO_TCP) - || (cv6->ip_payload == IPPROTO_UDP)) - { - local->_sport = cv6->_payload._tcp6->th_dport; - local->_dport = cv6->_payload._tcp6->th_sport; - } - - return (local); -} - - -static struct pAddr * -fillupOutgoingV6Remote(struct _cSlot *acs, struct _cv *cv6, struct pAddr *remote) -{ - remote->ip_p = IPPROTO_IPV4; - remote->sa_family = AF_INET; - remote->in4src = acs->remote.in4src; - remote->in4dst.s_addr = cv6->_ip._ip6->ip6_dst.s6_addr32[3]; - - if ((cv6->ip_payload == IPPROTO_TCP) - || (cv6->ip_payload == IPPROTO_UDP)) - { - remote->_sport = cv6->_payload._tcp6->th_sport; - remote->_dport = cv6->_payload._tcp6->th_dport; - - /* - * In case mappoing port number, - * acs->remote.port[0..1] has source port mapping range (from command line). - * remote->port[0..1] has actual translation slot info. - */ - if (acs->map & NATPT_PORT_MAP_DYNAMIC) - { - int firsttime = 0; - u_short cport, sport, eport; - struct pAddr pata; /* pata.{s,d}port hold network byte order */ - - cport = ntohs(acs->cport); - sport = ntohs(acs->remote._sport); - eport = ntohs(acs->remote._eport); - - if (cport == 0) - cport = sport - 1; - - bzero(&pata, sizeof(pata)); - pata.ip_p = IPPROTO_IPV4; - pata.sa_family = AF_INET; - pata.in4src = acs->remote.in4src; - pata.in4dst.s_addr = cv6->_ip._ip6->ip6_dst.s6_addr32[3]; - pata._dport = remote->_dport; - - for (;;) - { - while (++cport <= eport) - { - pata._sport = htons(cport); - if (_outsideHash[_hash_pat4(&pata)] == NULL) - goto found; - } - - if (firsttime == 0) - firsttime++, - cport = sport - 1; - else - return (NULL); - } - - found:; - remote->_sport = acs->cport = htons(cport); - } - } - - return (remote); -} - - -static struct _tSlot * -registTSlotEntry(struct _tSlot *ats) -{ - int s; - Cell *p; - struct timeval atv; - - if (tSlotEntryUsed >= tSlotEntryMax) - return (NULL); - - tSlotEntryUsed++; - - microtime(&atv); - ats->tstamp = atv.tv_sec; - - p = LST_cons(ats, NULL); - - s = splnet(); - - if (tSlotEntry == NULL) - tSlotEntry = p; - else - CDR(p) = tSlotEntry, tSlotEntry = p; - - splx(s); - - return (ats); -} - - -/* - * - */ - -static void -_expireTSlot(void *ignored_arg) -{ - struct timeval atv; -#ifdef __APPLE__ - boolean_t funnel_state; - funnel_state = thread_funnel_set(network_flock, TRUE); -#endif - - timeout(_expireTSlot, (caddr_t)0, tSlotTimer); - microtime(&atv); - - _expireTSlotEntry(&atv); -#ifdef __APPLE__ - (void) thread_funnel_set(network_flock, FALSE); -#endif -} - - -static void -_expireTSlotEntry(struct timeval *atv) -{ - struct _cell *p0, *p1, *q; - struct _tSlot *tsl; - - p0 = tSlotEntry; - q = NULL; - while (p0) - { - tsl = (struct _tSlot *)CAR(p0); - p1 = CDR(p0); - - switch (tsl->ip_payload) - { - case IPPROTO_ICMP: - if ((atv->tv_sec - tsl->tstamp) >= maxTTLicmp) - _removeTSlotEntry(p0, q); - break; - - case IPPROTO_UDP: - if ((atv->tv_sec - tsl->tstamp) >= maxTTLudp) - _removeTSlotEntry(p0, q); - break; - - case IPPROTO_TCP: - switch (tsl->suit.tcp->_state) - { - case TCPS_CLOSED: - if ((atv->tv_sec - tsl->tstamp) >= _natpt_TCPT_2MSL) - _removeTSlotEntry(p0, q); - break; - - case TCPS_SYN_SENT: - case TCPS_SYN_RECEIVED: - if ((atv->tv_sec - tsl->tstamp) >= _natpt_tcp_maxidle) - _removeTSlotEntry(p0, q); - break; - - case TCPS_ESTABLISHED: - if ((atv->tv_sec - tsl->tstamp) >= maxTTLtcp) - _removeTSlotEntry(p0, q); - break; - - case TCPS_FIN_WAIT_1: - case TCPS_FIN_WAIT_2: - if ((atv->tv_sec - tsl->tstamp) >= _natpt_tcp_maxidle) - _removeTSlotEntry(p0, q); - break; - - case TCPS_TIME_WAIT: - if ((atv->tv_sec - tsl->tstamp) >= _natpt_TCPT_2MSL) - _removeTSlotEntry(p0, q); - break; - - default: - if ((atv->tv_sec - tsl->tstamp) >= maxTTLtcp) - _removeTSlotEntry(p0, q); - break; - } - break; - - default: - if ((atv->tv_sec - tsl->tstamp) >= maxTTLany) - _removeTSlotEntry(p0, q); - break; - } - - if (CAR(p0) != CELL_FREE_MARKER) /* p0 may not removed */ - q = p0; - - p0 = p1; - } -} - - -static void -_removeTSlotEntry(struct _cell *p, struct _cell *q) -{ - int s; - int hvin, hvout; - struct _tSlot *tsl = (struct _tSlot *)CAR(p); - - if ((tsl->ip_payload == IPPROTO_TCP) - && (tsl->suit.tcp != NULL)) - { - FREE(tsl->suit.tcp, M_NATPT); - } - - if (tsl->local.ip_p == IPPROTO_IPV4) - hvin = _hash_pat4(&tsl->local); - else - hvin = _hash_pat6(&tsl->local); - - if (tsl->remote.ip_p == IPPROTO_IPV4) - hvout = _hash_pat4(&tsl->remote); - else - hvout = _hash_pat6(&tsl->remote); - - s = splnet(); - - _removeHash(&_insideHash, hvin, (caddr_t)tsl); - _removeHash(&_outsideHash, hvout, (caddr_t)tsl); - - if (q != NULL) - CDR(q) = CDR(p); - else - tSlotEntry = CDR(p); - - splx(s); - - LST_free(p); - FREE(tsl, M_NATPT); - - tSlotEntryUsed--; -} - - -static int -_removeHash(Cell *(*table)[], int hv, caddr_t node) -{ - register Cell *p, *q; - - if ((p = (*table)[hv]) == NULL) - return (0); - - if (CDR(p) == NULL) - { - if (CAR(p) == (Cell *)node) - { - LST_free(p); - (*table)[hv] = NULL; - } - return (0); - } - - for (p = (*table)[hv], q = NULL; p; q = p, p = CDR(p)) - { - if (CAR(p) != (Cell *)node) - continue; - - if (q == NULL) - (*table)[hv] = CDR(p); - else - CDR(q) = CDR(p); - - LST_free(p); - return (0); - } - - return (0); -} - - -/* - * - */ - -static int -_hash_ip4(struct _cv *cv) -{ - struct ip *ip; - struct sockaddr_in src, dst; - - bzero(&src, sizeof(struct sockaddr_in)); - bzero(&dst, sizeof(struct sockaddr_in)); - - ip = cv->_ip._ip4; - src.sin_addr = ip->ip_src; - dst.sin_addr = ip->ip_dst; - - if ((ip->ip_p == IPPROTO_TCP) || (ip->ip_p == IPPROTO_UDP)) - { - struct tcphdr *tcp = cv->_payload._tcp4; - - src.sin_port = tcp->th_sport; - dst.sin_port = tcp->th_dport; - } - - return ((_hash_sockaddr4(&src) + _hash_sockaddr4(&dst)) % NATPT_MAXHASH); -} - - -static int -_hash_ip6(struct _cv *cv) -{ - struct ip6_hdr *ip6; - struct sockaddr_in6 src, dst; - - bzero(&src, sizeof(struct sockaddr_in6)); - bzero(&dst, sizeof(struct sockaddr_in6)); - - ip6 = cv->_ip._ip6; - src.sin6_addr = ip6->ip6_src; - dst.sin6_addr = ip6->ip6_dst; - - if ((cv->ip_payload == IPPROTO_TCP) || (cv->ip_payload == IPPROTO_UDP)) - { - struct tcp6hdr *tcp6 = cv->_payload._tcp6; - - src.sin6_port = tcp6->th_sport; - dst.sin6_port = tcp6->th_dport; - } - - return ((_hash_sockaddr6(&src) + _hash_sockaddr6(&dst)) % NATPT_MAXHASH); -} - - -static int -_hash_pat4(struct pAddr *pat4) -{ - struct sockaddr_in src, dst; - - bzero(&src, sizeof(struct sockaddr_in)); - bzero(&dst, sizeof(struct sockaddr_in)); - - src.sin_port = pat4->_sport; - src.sin_addr = pat4->in4src; - dst.sin_port = pat4->_dport; - dst.sin_addr = pat4->in4dst; - - return ((_hash_sockaddr4(&src) + _hash_sockaddr4(&dst)) % NATPT_MAXHASH); -} - - -static int -_hash_pat6(struct pAddr *pat6) -{ - struct sockaddr_in6 src, dst; - - bzero(&src, sizeof(struct sockaddr_in6)); - bzero(&dst, sizeof(struct sockaddr_in6)); - - src.sin6_port = pat6->_sport; - src.sin6_addr = pat6->in6src; - dst.sin6_port = pat6->_dport; - dst.sin6_addr = pat6->in6dst; - - return ((_hash_sockaddr6(&src) + _hash_sockaddr6(&dst)) % NATPT_MAXHASH); -} - - -static int -_hash_sockaddr4(struct sockaddr_in *sin4) -{ - int byte; - - byte = sizeof(sin4->sin_port) + sizeof(sin4->sin_addr); - return (_hash_pjw((char *)&sin4->sin_port, byte)); -} - - -static int -_hash_sockaddr6(struct sockaddr_in6 *sin6) -{ - int byte; - - sin6->sin6_flowinfo = 0; - byte = sizeof(sin6->sin6_port) - + sizeof(sin6->sin6_flowinfo) - + sizeof(sin6->sin6_addr); - return (_hash_pjw((char *)&sin6->sin6_port, byte)); -} - - -/* CAUTION */ -/* This hash routine is byte order sensitive. Be Careful. */ - -static int -_hash_pjw(register u_char *s, int len) -{ - register u_int c; - register u_int h, g; - - for (c = h = g = 0; c < len; c++, s++) - { - h = (h << 4) + (*s); - if ((g = h & 0xf0000000)) - { - h ^= (g >> 24); - h ^= g; - } - } - return (h % NATPT_MAXHASH); -} - - -/* - * - */ - -void -init_hash() -{ - bzero((caddr_t)_insideHash, sizeof(_insideHash)); - bzero((caddr_t)_outsideHash, sizeof(_outsideHash)); -} - - -void -init_tslot() -{ - tSlotEntry = NULL; - tSlotEntryMax = MAXTSLOTENTRY; - tSlotEntryUsed = 0; - - tSlotTimer = 60 * hz; - timeout(_expireTSlot, (caddr_t)0, tSlotTimer); - - _natpt_TCPT_2MSL = 120; /* [sec] */ - _natpt_tcp_maxidle = 600; /* [sec] */ - - maxTTLicmp = maxTTLudp = _natpt_TCPT_2MSL; - maxTTLtcp = maxTTLany = 86400; /* [sec] */ -} diff --git a/bsd/netinet6/natpt_usrreq.c b/bsd/netinet6/natpt_usrreq.c deleted file mode 100644 index 06e4a3afd..000000000 --- a/bsd/netinet6/natpt_usrreq.c +++ /dev/null @@ -1,581 +0,0 @@ -/* $KAME: natpt_usrreq.c,v 1.9 2000/03/25 07:23:57 sumikawa Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -/* FreeBSD330 compiler complain that do not #include ioctl.h in the kernel, */ -/* Include xxxio.h instead */ -/* #include */ -#include -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) -#include -#endif -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include -#include -#include -#include - - -/* - * - */ - -#define NATPTSNDQ (8192) -#define NATPTRCVQ (8192) - -u_long natpt_sendspace = NATPTSNDQ; -u_long natpt_recvspace = NATPTRCVQ; - -#if defined(__bsdi__) || defined(__FreeBSD__) && __FreeBSD__ <= 2 -static struct rawcb ptrcb; -#else -LIST_HEAD(, rawcb) ptrcb; -#endif - -static struct sockaddr natpt_dst = {2, PF_INET}; -#ifdef notused -static struct sockaddr natpt_src = {2, PF_INET}; -#endif - -#if 0 -int natpt_sosetopt __P((struct socket *, int, struct mbuf *)); -int natpt_sogetopt __P((struct socket *, int, struct mbuf *)); -#endif - -static int _natptSetIf __P((caddr_t)); -static int _natptGetIf __P((caddr_t)); -static int _natptSetValue __P((caddr_t)); -static int _natptTestLog __P((caddr_t)); - -void natpt_init __P((void)); - -#ifdef __bsdi__ -int natpt_usrreq __P((struct socket *, int, - struct mbuf *, struct mbuf *, struct mbuf *)); -#elif defined(__NetBSD__) -int natpt_usrreq __P((struct socket *, int, - struct mbuf *, struct mbuf *, struct mbuf *, struct proc *)); -#endif /* defined(__bsdi__) || defined(__NetBSD__) */ - - -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) -int natpt_uabort __P((struct socket *)); -int natpt_uattach __P((struct socket *, int, struct proc *)); -int natpt_ubind __P((struct socket *, struct sockaddr *, struct proc *)); -int natpt_uconnect __P((struct socket *, struct sockaddr *, struct proc *)); -int natpt_udetach __P((struct socket *)); -int natpt_ucontrol __P((struct socket *, u_long, caddr_t, struct ifnet *, struct proc *)); -#endif /* defined(__FreeBSD__) && __FreeBSD__ >= 3 */ - -int natpt_attach __P((struct socket *, int)); -int natpt_control __P((struct socket *, int, caddr_t, struct ifnet *)); -int natpt_detach __P((struct socket *)); -int natpt_disconnect __P((struct socket *)); - - -#ifdef __FreeBSD__ -#if __FreeBSD__ >= 3 -struct pr_usrreqs natpt_usrreqs = -{ - natpt_uabort, NULL, natpt_uattach, natpt_ubind, - natpt_uconnect, NULL, natpt_ucontrol, natpt_udetach, - natpt_disconnect, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, sosend, soreceive, sopoll -}; -#else -struct pr_usrreqs natpt_usrreqs = -{ - NULL, NULL, natpt_attach, NULL, - NULL, NULL, natpt_control, natpt_detach, - natpt_disconnect, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL -}; -#endif /* __FreeBSD__ >= 3 */ -#endif /* __FreeBSD__ */ - - -/* - * - */ - -void -natpt_init() -{ - natpt_initialized = 0; - ip6_protocol_tr = 0; - - init_tslot(); - -#if defined(__bsdi__) || defined(__FreeBSD__) && __FreeBSD__ <= 2 - ptrcb.rcb_next = ptrcb.rcb_prev = &ptrcb; -#else - LIST_INIT(&ptrcb); -#endif - - printf("NATPT: initialized.\n"); -} - - -void -natpt_input(struct mbuf *m0, struct sockproto *proto, - struct sockaddr *src, struct sockaddr *dst) -{ - struct rawcb *rp; - struct mbuf *m = m0; - struct socket *last; - int sockets; - - last = 0; -#if defined(__bsdi__) || defined(__FreeBSD__) && __FreeBSD__ <= 2 - for (rp = ptrcb.rcb_next; rp != &ptrcb; rp = rp->rcb_next) -#else - for (rp = ptrcb.lh_first; rp != 0; rp = rp->rcb_list.le_next) -#endif - { - 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; - -#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)) != NULL) - { - if (sbappendaddr(&last->so_rcv, src, n, (struct mbuf *)NULL) == 0) - m_freem(n); /* should notify about lost packet */ - else - { - sorwakeup(last); - sockets++; - } - } - } - last = rp->rcb_socket; - } - - if (last) - { - if (sbappendaddr(&last->so_rcv, src, m, (struct mbuf *)NULL) == 0) - m_freem(m); - else - { - sorwakeup(last); - sockets++; - } - } - else - m_freem(m); -} - - -#if defined(__bsdi__) || defined(__NetBSD__) -int -natpt_usrreq(struct socket *so, int req, - struct mbuf *m, struct mbuf *nam, struct mbuf *control -#ifdef __NetBSD__ - ,struct proc *p -#endif - ) -{ - struct rawcb *rp = sotorawcb(so); - int error = 0; - - if ((rp == NULL) && (req != PRU_ATTACH)) - { - m_freem(m); - return (EINVAL); - } - - switch (req) - { - case PRU_ATTACH: - error = natpt_attach(so, (int)nam); - break; - - case PRU_DETACH: - error = natpt_detach(so); - break; - - case PRU_DISCONNECT: - if (rp->rcb_faddr == NULL) - { - error = ENOTCONN; - break; - } - rp->rcb_faddr = NULL; - raw_disconnect(rp); - soisdisconnected(so); - break; - - case PRU_SEND: - case PRU_BIND: - case PRU_LISTEN: - case PRU_CONNECT: - case PRU_ACCEPT: - case PRU_SHUTDOWN: - case PRU_RCVD: - case PRU_ABORT: - error = EOPNOTSUPP; - break; - - case PRU_CONTROL: - error = natpt_control(so, (int)m, (caddr_t)nam, (struct ifnet *)NULL); - return (error); - break; - - case PRU_SENSE: - case PRU_RCVOOB: - case PRU_SENDOOB: - case PRU_SOCKADDR: - case PRU_PEERADDR: - case PRU_CONNECT2: - case PRU_FASTTIMO: - case PRU_SLOWTIMO: - case PRU_PROTORCV: - case PRU_PROTOSEND: - error = EOPNOTSUPP; - break; - - default: - panic("raw_usrreq"); - } - - if (m != NULL) - m_freem(m); - - return (error); -} -#endif /* defined(__bsdi__) || defined(__NetBSD__) */ - - -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) -int -natpt_uabort(struct socket *so) -{ - struct rawcb *rp = sotorawcb(so); - - if (rp == 0) - return (EINVAL); - - raw_disconnect(rp); - sofree(so); - soisdisconnected(so); - - return (0); -} - - -int -natpt_uattach(struct socket *so, int proto, struct proc *p) -{ - int error; - -#if ISFB31 - if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0) - return (error); -#else - if ((so->so_state & SS_PRIV) != 0) - return (EPERM); -#endif - - return (natpt_attach(so, proto)); -} - - -int -natpt_ubind(struct socket *so, struct sockaddr *nam, struct proc *p) -{ - return (EINVAL); -} - - -int -natpt_uconnect(struct socket *so, struct sockaddr *nam, struct proc *p) -{ - return (EINVAL); -} - - -int -natpt_ucontrol(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, - struct proc *p) -{ - return (natpt_control(so, cmd, data, ifp)); -} - - -int -natpt_udetach(struct socket *so) -{ - struct rawcb *rp = sotorawcb(so); - - if (rp == 0) - return (EINVAL); - - return (natpt_detach(so)); -} - -#endif /* defined(__FreeBSD__) && __FreeBSD__ >= 3 */ - - -int -natpt_attach(struct socket *so, int proto) -{ - struct rawcb *rp; - int error; - - if (so->so_pcb == NULL) - { - MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK); - so->so_pcb = (caddr_t)rp; - bzero(rp, sizeof(*rp)); - } - - if ((rp = sotorawcb(so)) == NULL) - return (ENOBUFS); - if ((error = soreserve(so, natpt_sendspace, natpt_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; -#if defined(__bsdi__) || defined(__FreeBSD__) && __FreeBSD__ <= 2 - insque(rp, &ptrcb); -#else - LIST_INSERT_HEAD(&ptrcb, rp, rcb_list); -#endif - - /* The socket is always "connected" because - we always know "where" to send the packet */ - rp->rcb_faddr = &natpt_dst; - soisconnected(so); - - return (0); -} - - -int -natpt_detach(struct socket *so) -{ - struct rawcb *rp = sotorawcb(so); - - if (rp == NULL) - return (ENOTCONN); - - so->so_pcb = NULL; - sofree(so); - -#if defined(__bsdi__) || defined(__FreeBSD__) && __FreeBSD__ <= 2 - remque(rp); -#else - LIST_REMOVE(rp, rcb_list); -#endif - if (rp->rcb_laddr) - m_freem(dtom(rp->rcb_laddr)); - if (rp->rcb_faddr) - m_freem(dtom(rp->rcb_faddr)); - FREE(rp, M_PCB); - - return (0); -} - - -int -natpt_disconnect(struct socket *so) -{ - struct rawcb *rp = sotorawcb(so); - - if (rp == NULL) - return (EINVAL); - - if (rp->rcb_faddr == NULL) - return (ENOTCONN); - - rp->rcb_faddr = NULL; - raw_disconnect(rp); - soisdisconnected(so); - - return (0); -} - - -int -natpt_control(struct socket *so, int cmd, caddr_t data, struct ifnet *ifp) -{ - if (natpt_initialized == 0) - natpt_initialize(); - - switch (cmd) - { - case SIOCSETIF: return (_natptSetIf(data)); - case SIOCGETIF: return (_natptGetIf(data)); - case SIOCENBTRANS: return (_natptEnableTrans(data)); - case SIOCDSBTRANS: return (_natptDisableTrans(data)); - case SIOCSETRULE: return (_natptSetRule(data)); - case SIOCFLUSHRULE: return (_natptFlushRule(data)); - case SIOCSETPREFIX: return (_natptSetPrefix(data)); - case SIOCSETVALUE: return (_natptSetValue(data)); - - case SIOCTESTLOG: return (_natptTestLog(data)); - - case SIOCBREAK: return (_natptBreak()); - } - - return (EINVAL); -} - - -/* - * - */ - -static int -_natptSetIf(caddr_t addr) -{ - struct natpt_msgBox *mbx = (struct natpt_msgBox *)addr; - struct ifBox *ifb; - - if (((ifb = natpt_asIfBox(mbx->m_ifName)) == NULL) - && ((ifb = natpt_setIfBox(mbx->m_ifName)) == NULL)) - return (ENXIO); - - if (ifb->side != noSide) - { - char WoW[LBFSZ]; - - sprintf(WoW, "[natpt]: interface `%s\' already configured.", mbx->m_ifName); - natpt_logMsg(LOG_WARNING, WoW, strlen(WoW)); - return (EALREADY); - } - - { - char WoW[LBFSZ]; - char *s; - - natpt_ip6src = ifb->ifnet; - if (mbx->flags == IF_EXTERNAL) - ifb->side = outSide, s = "outside"; - else - ifb->side = inSide, s = "inside"; - - sprintf(WoW, "[natpt]: interface `%s\' set as %s.", mbx->m_ifName, s); - natpt_logMsg(LOG_INFO, WoW, strlen(WoW)); - } - - return (0); -} - - -static int -_natptGetIf(caddr_t addr) -{ - struct natpt_msgBox *mbx = (struct natpt_msgBox *)addr; - struct ifBox *ifb; - - if (((ifb = natpt_asIfBox(mbx->m_ifName)) == NULL) - && ((ifb = natpt_setIfBox(mbx->m_ifName)) == NULL)) - return (ENXIO); - - { - switch (ifb->side) - { - case outSide: mbx->flags |= IF_EXTERNAL; break; - case inSide: mbx->flags |= IF_INTERNAL; break; - default: mbx->flags = -1; break; - } - } - - return (0); -} - - -static int -_natptSetValue(caddr_t addr) -{ - struct natpt_msgBox *mbx = (struct natpt_msgBox *)addr; - - switch (mbx->flags) - { - case NATPT_DEBUG: - natpt_debug = *((u_int *)mbx->m_aux); - break; - - case NATPT_DUMP: - natpt_dump = *((u_int *)mbx->m_aux); - break; - } - - return (0); -} - - -static int -_natptTestLog(caddr_t addr) -{ - char *fragile; - struct natpt_msgBox *mbox = (struct natpt_msgBox *)addr; - - MALLOC(fragile, char *, mbox->size, M_TEMP, M_WAITOK); - copyin(mbox->freight, fragile, mbox->size); - - natpt_logMsg(LOG_DEBUG, fragile, mbox->size); - - FREE(fragile, M_TEMP); - return (0); -} - diff --git a/bsd/netinet6/natpt_var.h b/bsd/netinet6/natpt_var.h deleted file mode 100644 index 473793907..000000000 --- a/bsd/netinet6/natpt_var.h +++ /dev/null @@ -1,112 +0,0 @@ -/* $KAME: natpt_var.h,v 1.6 2000/03/25 07:23:57 sumikawa Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - - -extern int natpt_initialized; -extern int ip6_protocol_tr; -extern u_int natpt_debug; -extern u_int natpt_dump; - -extern struct ifnet *natpt_ip6src; - -/* natpt_log.c */ -void natpt_logMsg __P((int, void *, size_t)); -void natpt_logMBuf __P((int, struct mbuf *, char *)); -void natpt_logIp4 __P((int, struct ip *)); -void natpt_logIp6 __P((int, struct ip6_hdr *)); -int natpt_log __P((int, int, void *, size_t)); -int natpt_logIN6addr __P((int, char *, struct in6_addr *)); - -void natpt_debugProbe __P((void)); -void natpt_assert __P((const char *, int, const char *)); -void natpt_initialize __P((void)); - - -/* natpt_rule.c */ -struct _cSlot *lookingForIncomingV4Rule __P((struct _cv *)); -struct _cSlot *lookingForOutgoingV4Rule __P((struct _cv *)); -struct _cSlot *lookingForIncomingV6Rule __P((struct _cv *)); -struct _cSlot *lookingForOutgoingV6Rule __P((struct _cv *)); -int _natptEnableTrans __P((caddr_t)); -int _natptDisableTrans __P((caddr_t)); -int _natptSetRule __P((caddr_t)); -int _natptSetFaithRule __P((caddr_t)); -int _natptFlushRule __P((caddr_t)); -int _natptSetPrefix __P((caddr_t)); - -int _natptBreak __P((void)); - - -struct ifBox *natpt_asIfBox __P((char *)); -struct ifBox *natpt_setIfBox __P((char *)); - - -/* natpt_trans.c */ -#ifdef NATPT_NAT -struct mbuf *translatingIPv4To4 __P((struct _cv *, struct pAddr *)); -struct mbuf *translatingICMPv4To4 __P((struct _cv *, struct pAddr *)); -struct mbuf *translatingTCPv4To4 __P((struct _cv *, struct pAddr *)); -struct mbuf *translatingUDPv4To4 __P((struct _cv *, struct pAddr *)); -#endif - -struct mbuf *translatingIPv4To6 __P((struct _cv *, struct pAddr *)); -struct mbuf *translatingICMPv4To6 __P((struct _cv *, struct pAddr *)); -struct mbuf *translatingTCPv4To6 __P((struct _cv *, struct pAddr *)); -struct mbuf *translatingUDPv4To6 __P((struct _cv *, struct pAddr *)); -struct mbuf *translatingTCPUDPv4To6 __P((struct _cv *, struct pAddr *, struct _cv *)); - -struct mbuf *translatingIPv6To4 __P((struct _cv *, struct pAddr *)); -struct mbuf *translatingICMPv6To4 __P((struct _cv *, struct pAddr *)); -struct mbuf *translatingTCPv6To4 __P((struct _cv *, struct pAddr *)); -struct mbuf *translatingUDPv6To4 __P((struct _cv *, struct pAddr *)); -struct mbuf *translatingTCPUDPv6To4 __P((struct _cv *, struct pAddr *, struct _cv *)); - - -/* natpt_tslot.c */ -struct _tSlot *lookingForOutgoingV4Hash __P((struct _cv *)); -struct _tSlot *lookingForIncomingV4Hash __P((struct _cv *)); -struct _tSlot *lookingForOutgoingV6Hash __P((struct _cv *)); -struct _tSlot *lookingForIncomingV6Hash __P((struct _cv *)); -struct _tSlot *internIncomingV4Hash __P((int, struct _cSlot *, struct _cv *)); -struct _tSlot *internOutgoingV4Hash __P((int, struct _cSlot *, struct _cv *)); -struct _tSlot *internIncomingV6Hash __P((int, struct _cSlot *, struct _cv *)); -struct _tSlot *internOutgoingV6Hash __P((int, struct _cSlot *, struct _cv *)); - -struct _tSlot *checkTraceroute6Return __P((struct _cv *)); - -void init_hash __P((void)); -void init_tslot __P((void)); - - -/* natpt_usrreq.c */ -void natpt_input __P((struct mbuf *, struct sockproto *, - struct sockaddr *src, struct sockaddr *dst)); - diff --git a/bsd/netinet6/nd6.c b/bsd/netinet6/nd6.c index 766b6c6e1..60d206276 100644 --- a/bsd/netinet6/nd6.c +++ b/bsd/netinet6/nd6.c @@ -1,4 +1,5 @@ -/* $KAME: nd6.c,v 1.51.2.1 2000/04/13 11:59:29 jinmei Exp $ */ +/* $FreeBSD: src/sys/netinet6/nd6.c,v 1.2.2.9 2001/07/11 09:39:04 ume Exp $ */ +/* $KAME: nd6.c,v 1.144 2001/05/24 07:44:00 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -46,36 +47,21 @@ #include #include #include -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) -#include -#endif #include #include #include +#define DONT_WARN_OBSOLETE #include #include #include -#if !(defined(__bsdi__) && _BSDI_VERSION >= 199802) && !defined(__APPLE__) #include -#endif #include #include #include -#ifndef __NetBSD__ #include -#if __FreeBSD__ #include -#endif -#ifdef __bsdi__ -#include -#endif -#else /* __NetBSD__ */ -#include -#include -#include -#endif /* __NetBSD__ */ #include #include #include @@ -83,12 +69,7 @@ #include #include -#ifndef __bsdi__ #include "loop.h" -#endif -#if defined(__NetBSD__) || defined(__OpenBSD__) -extern struct ifnet loif[NLOOP]; -#endif #include @@ -104,14 +85,24 @@ int nd6_delay = 5; /* delay first probe time 5 second */ int nd6_umaxtries = 3; /* maximum unicast query */ int nd6_mmaxtries = 3; /* maximum multicast query */ int nd6_useloopback = 1; /* use loopback interface for local traffic */ +int nd6_gctimer = (60 * 60 * 24); /* 1 day: garbage collection timer */ /* preventing too many loops in ND option parsing */ int nd6_maxndopt = 10; /* max # of ND options allowed */ +int nd6_maxnudhint = 0; /* max # of subsequent upper layer hints */ + +#if ND6_DEBUG +int nd6_debug = 1; +#else +int nd6_debug = 0; +#endif + /* for debugging? */ static int nd6_inuse, nd6_allocated; struct llinfo_nd6 llinfo_nd6 = {&llinfo_nd6, &llinfo_nd6}; +static size_t nd_ifinfo_indexlim = 8; struct nd_ifinfo *nd_ifinfo = NULL; struct nd_drhead nd_defrouter; struct nd_prhead nd_prefix = { 0 }; @@ -119,12 +110,9 @@ struct nd_prhead nd_prefix = { 0 }; int nd6_recalc_reachtm_interval = ND6_RECALC_REACHTM_INTERVAL; static struct sockaddr_in6 all1_sa; -static void nd6_slowtimo __P((void *)); static void nd6_slowtimo_funneled __P((void *)); +static int regen_tmpaddr __P((struct in6_ifaddr *)); -#if MIP6 -void (*mip6_expired_defrouter_hook)(struct nd_defrouter *dr) = 0; -#endif void nd6_init() @@ -155,31 +143,41 @@ void nd6_ifattach(ifp) struct ifnet *ifp; { - static size_t if_indexlim = 8; /* * We have some arrays that should be indexed by if_index. * since if_index will grow dynamically, they should grow too. */ - if (nd_ifinfo == NULL || if_index >= if_indexlim) { + if (nd_ifinfo == NULL || if_index >= nd_ifinfo_indexlim) { size_t n; caddr_t q; - while (if_index >= if_indexlim) - if_indexlim <<= 1; + while (if_index >= nd_ifinfo_indexlim) + nd_ifinfo_indexlim <<= 1; /* grow nd_ifinfo */ - n = if_indexlim * sizeof(struct nd_ifinfo); + n = nd_ifinfo_indexlim * sizeof(struct nd_ifinfo); q = (caddr_t)_MALLOC(n, M_IP6NDP, M_WAITOK); bzero(q, n); if (nd_ifinfo) { bcopy((caddr_t)nd_ifinfo, q, n/2); - _FREE((caddr_t)nd_ifinfo, M_IP6NDP); + FREE((caddr_t)nd_ifinfo, M_IP6NDP); } nd_ifinfo = (struct nd_ifinfo *)q; } #define ND nd_ifinfo[ifp->if_index] + + /* + * Don't initialize if called twice. + * XXX: to detect this, we should choose a member that is never set + * before initialization of the ND structure itself. We formaly used + * the linkmtu member, which was not suitable because it could be + * initialized via "ifconfig mtu". + */ + if (ND.basereachable) + return; + ND.linkmtu = ifindex2ifnet[ifp->if_index]->if_mtu; ND.chlim = IPV6_DEFHLIM; ND.basereachable = REACHABLE_TIME; @@ -199,30 +197,37 @@ void nd6_setmtu(ifp) struct ifnet *ifp; { +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index]; u_long oldmaxmtu = ndi->maxmtu; u_long oldlinkmtu = ndi->linkmtu; - switch(ifp->if_type) { - case IFT_ARCNET: /* XXX MTU handling needs more work */ - ndi->maxmtu = MIN(60480, ifp->if_mtu); - break; - case IFT_ETHER: - ndi->maxmtu = MIN(ETHERMTU, ifp->if_mtu); - break; -#if defined(__FreeBSD__) || defined(__bsdi__) - case IFT_FDDI: - ndi->maxmtu = MIN(FDDIIPMTU, ifp->if_mtu); - break; -#endif -#if !(defined(__bsdi__) && _BSDI_VERSION >= 199802) && !defined (__APPLE__) - case IFT_ATM: - ndi->maxmtu = MIN(ATMMTU, ifp->if_mtu); - break; + switch (ifp->if_type) { + case IFT_ARCNET: /* XXX MTU handling needs more work */ + ndi->maxmtu = MIN(60480, ifp->if_mtu); + break; + case IFT_ETHER: + ndi->maxmtu = MIN(ETHERMTU, ifp->if_mtu); + break; + case IFT_FDDI: + ndi->maxmtu = MIN(FDDIIPMTU, ifp->if_mtu); + break; + case IFT_ATM: + ndi->maxmtu = MIN(ATMMTU, ifp->if_mtu); + break; + case IFT_IEEE1394: /* XXX should be IEEE1394MTU(1500) */ + ndi->maxmtu = MIN(ETHERMTU, ifp->if_mtu); + break; +#if IFT_IEEE80211 + case IFT_IEEE80211: /* XXX should be IEEE80211MTU(1500) */ + ndi->maxmtu = MIN(ETHERMTU, ifp->if_mtu); + break; #endif - default: - ndi->maxmtu = ifp->if_mtu; - break; + default: + ndi->maxmtu = ifp->if_mtu; + break; } if (oldmaxmtu != ndi->maxmtu) { @@ -244,8 +249,7 @@ nd6_setmtu(ifp) */ if (in6_maxmtu < ndi->linkmtu) in6_maxmtu = ndi->linkmtu; - } - else + } else in6_setmaxmtu(); } } @@ -290,6 +294,12 @@ nd6_option(ndopts) nd_opt = ndopts->nd_opts_search; + /* make sure nd_opt_len is inside the buffer */ + if ((caddr_t)&nd_opt->nd_opt_len >= (caddr_t)ndopts->nd_opts_last) { + bzero(ndopts, sizeof(*ndopts)); + return NULL; + } + olen = nd_opt->nd_opt_len << 3; if (olen == 0) { /* @@ -301,7 +311,12 @@ nd6_option(ndopts) } ndopts->nd_opts_search = (struct nd_opt_hdr *)((caddr_t)nd_opt + olen); - if (!(ndopts->nd_opts_search < ndopts->nd_opts_last)) { + if (ndopts->nd_opts_search > ndopts->nd_opts_last) { + /* option overruns the end of buffer, invalid */ + bzero(ndopts, sizeof(*ndopts)); + return NULL; + } else if (ndopts->nd_opts_search == ndopts->nd_opts_last) { + /* reached the end of options chain */ ndopts->nd_opts_done = 1; ndopts->nd_opts_search = NULL; } @@ -334,6 +349,7 @@ nd6_options(ndopts) * Message validation requires that all included * options have a length that is greater than zero. */ + icmp6stat.icp6s_nd_badopt++; bzero(ndopts, sizeof(*ndopts)); return -1; } @@ -346,10 +362,10 @@ nd6_options(ndopts) case ND_OPT_TARGET_LINKADDR: case ND_OPT_MTU: case ND_OPT_REDIRECTED_HEADER: - case ND_OPT_ADV_INTERVAL: if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) { - printf("duplicated ND6 option found " - "(type=%d)\n", nd_opt->nd_opt_type); + nd6log((LOG_INFO, + "duplicated ND6 option found (type=%d)\n", + nd_opt->nd_opt_type)); /* XXX bark? */ } else { ndopts->nd_opt_array[nd_opt->nd_opt_type] @@ -364,23 +380,21 @@ nd6_options(ndopts) ndopts->nd_opts_pi_end = (struct nd_opt_prefix_info *)nd_opt; break; - case ND_OPT_HA_INFORMATION: - break; default: /* * Unknown options must be silently ignored, * to accomodate future extension to the protocol. */ - log(LOG_DEBUG, + nd6log((LOG_DEBUG, "nd6_options: unsupported option %d - " - "option ignored\n", nd_opt->nd_opt_type); + "option ignored\n", nd_opt->nd_opt_type)); } skip1: i++; if (i > nd6_maxndopt) { icmp6stat.icp6s_nd_toomanyopt++; - printf("too many loop in nd opt\n"); + nd6log((LOG_INFO, "too many loop in nd opt\n")); break; } @@ -412,25 +426,21 @@ nd6_timer(ignored_arg) void *ignored_arg; { int s; - register struct llinfo_nd6 *ln; - register struct nd_defrouter *dr; - register struct nd_prefix *pr; -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined (__APPLE__) - long time_second = time.tv_sec; -#endif + struct llinfo_nd6 *ln; + struct nd_defrouter *dr; + struct nd_prefix *pr; + struct ifnet *ifp; + struct in6_ifaddr *ia6, *nia6; + struct in6_addrlifetime *lt6; -#if __NetBSD__ - s = splsoftnet(); -#else s = splnet(); -#endif + timeout(nd6_timer_funneled, (caddr_t)0, nd6_prune * hz); ln = llinfo_nd6.ln_next; /* XXX BSD/OS separates this code -- itojun */ while (ln && ln != &llinfo_nd6) { struct rtentry *rt; - struct ifnet *ifp; struct sockaddr_in6 *dst; struct llinfo_nd6 *next = ln->ln_next; /* XXX: used for the DELAY case only: */ @@ -486,17 +496,22 @@ nd6_timer(ignored_arg) ICMP6_DST_UNREACH_ADDR, 0); ln->ln_hold = NULL; } - nd6_free(rt); + next = nd6_free(rt); } break; case ND6_LLINFO_REACHABLE: - if (ln->ln_expire) + if (ln->ln_expire) { ln->ln_state = ND6_LLINFO_STALE; + ln->ln_expire = time_second + nd6_gctimer; + } break; - /* - * ND6_LLINFO_STALE state requires nothing for timer - * routine. - */ + + case ND6_LLINFO_STALE: + /* Garbage Collection(RFC 2461 5.3) */ + if (ln->ln_expire) + next = nd6_free(rt); + break; + case ND6_LLINFO_DELAY: if (ndi && (ndi->flags & ND6_IFF_PERFORMNUD) != 0) { /* We need NUD */ @@ -507,9 +522,10 @@ nd6_timer(ignored_arg) nd6_ns_output(ifp, &dst->sin6_addr, &dst->sin6_addr, ln, 0); - } - else + } else { ln->ln_state = ND6_LLINFO_STALE; /* XXX */ + ln->ln_expire = time_second + nd6_gctimer; + } break; case ND6_LLINFO_PROBE: if (ln->ln_asked < nd6_umaxtries) { @@ -519,17 +535,14 @@ nd6_timer(ignored_arg) nd6_ns_output(ifp, &dst->sin6_addr, &dst->sin6_addr, ln, 0); } else { - nd6_free(rt); + next = nd6_free(rt); } break; - case ND6_LLINFO_WAITDELETE: - nd6_free(rt); - break; } ln = next; } - /* expire */ + /* expire default router list */ dr = TAILQ_FIRST(&nd_defrouter); while (dr) { if (dr->expire && dr->expire < time_second) { @@ -538,35 +551,85 @@ nd6_timer(ignored_arg) defrtrlist_del(dr); dr = t; } else { -#if MIP6 - if (mip6_expired_defrouter_hook) - (*mip6_expired_defrouter_hook)(dr); -#endif /* MIP6 */ dr = TAILQ_NEXT(dr, dr_entry); } } - pr = nd_prefix.lh_first; - while (pr) { - struct in6_ifaddr *ia6; - struct in6_addrlifetime *lt6; - if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) - ia6 = NULL; - else - ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr); - - if (ia6) { - /* check address lifetime */ - lt6 = &ia6->ia6_lifetime; - if (lt6->ia6t_preferred && lt6->ia6t_preferred < time_second) - ia6->ia6_flags |= IN6_IFF_DEPRECATED; - if (lt6->ia6t_expire && lt6->ia6t_expire < time_second) { - if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) - in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); - /* xxx ND_OPT_PI_FLAG_ONLINK processing */ + /* + * expire interface addresses. + * in the past the loop was inside prefix expiry processing. + * However, from a stricter speci-confrmance standpoint, we should + * rather separate address lifetimes and prefix lifetimes. + */ + addrloop: + for (ia6 = in6_ifaddr; ia6; ia6 = nia6) { + nia6 = ia6->ia_next; + /* check address lifetime */ + lt6 = &ia6->ia6_lifetime; + if (IFA6_IS_INVALID(ia6)) { + int regen = 0; + + /* + * If the expiring address is temporary, try + * regenerating a new one. This would be useful when + * we suspended a laptop PC, then turned on after a + * period that could invalidate all temporary + * addresses. Although we may have to restart the + * loop (see below), it must be after purging the + * address. Otherwise, we'd see an infinite loop of + * regeneration. + */ + if (ip6_use_tempaddr && + (ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0) { + if (regen_tmpaddr(ia6) == 0) + regen = 1; + } + + in6_purgeaddr(&ia6->ia_ifa); + + if (regen) + goto addrloop; /* XXX: see below */ + } else if (IFA6_IS_DEPRECATED(ia6)) { + int oldflags = ia6->ia6_flags; + + ia6->ia6_flags |= IN6_IFF_DEPRECATED; + + /* + * If a temporary address has just become deprecated, + * regenerate a new one if possible. + */ + if (ip6_use_tempaddr && + (ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0 && + (oldflags & IN6_IFF_DEPRECATED) == 0) { + + if (regen_tmpaddr(ia6) == 0) { + /* + * A new temporary address is + * generated. + * XXX: this means the address chain + * has changed while we are still in + * the loop. Although the change + * would not cause disaster (because + * it's not an addition, but a + * deletion,) we'd rather restart the + * loop just for safety. Or does this + * significantly reduce performance?? + */ + goto addrloop; + } } + } else if (IFA6_IS_DEPRECATED(ia6)) { + /* + * A new RA might have made a deprecated address + * preferred. + */ + ia6->ia6_flags &= ~IN6_IFF_DEPRECATED; } + } + /* expire prefix list */ + pr = nd_prefix.lh_first; + while (pr) { /* * check prefix lifetime. * since pltime is just for autoconf, pltime processing for @@ -576,15 +639,17 @@ nd6_timer(ignored_arg) * can use the old prefix information to validate the * next prefix information to come. See prelist_update() * for actual validation. + * + * I don't think such an offset is necessary. + * (jinmei@kame.net, 20010130). */ - if (pr->ndpr_expire - && pr->ndpr_expire + NDPR_KEEP_EXPIRED < time_second) { + if (pr->ndpr_expire && pr->ndpr_expire < time_second) { struct nd_prefix *t; t = pr->ndpr_next; /* * address expiration and prefix expiration are - * separate. NEVER perform in6_ifdel here. + * separate. NEVER perform in6_purgeaddr here. */ prelist_remove(pr); @@ -595,6 +660,70 @@ nd6_timer(ignored_arg) splx(s); } +static int +regen_tmpaddr(ia6) + struct in6_ifaddr *ia6; /* deprecated/invalidated temporary address */ +{ + struct ifaddr *ifa; + struct ifnet *ifp; + struct in6_ifaddr *public_ifa6 = NULL; + + ifp = ia6->ia_ifa.ifa_ifp; + for (ifa = ifp->if_addrlist.tqh_first; ifa; + ifa = ifa->ifa_list.tqe_next) + { + struct in6_ifaddr *it6; + + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + + it6 = (struct in6_ifaddr *)ifa; + + /* ignore no autoconf addresses. */ + if ((it6->ia6_flags & IN6_IFF_AUTOCONF) == 0) + continue; + + /* ignore autoconf addresses with different prefixes. */ + if (it6->ia6_ndpr == NULL || it6->ia6_ndpr != ia6->ia6_ndpr) + continue; + + /* + * Now we are looking at an autoconf address with the same + * prefix as ours. If the address is temporary and is still + * preferred, do not create another one. It would be rare, but + * could happen, for example, when we resume a laptop PC after + * a long period. + */ + if ((it6->ia6_flags & IN6_IFF_TEMPORARY) != 0 && + !IFA6_IS_DEPRECATED(it6)) { + public_ifa6 = NULL; + break; + } + + /* + * This is a public autoconf address that has the same prefix + * as ours. If it is preferred, keep it. We can't break the + * loop here, because there may be a still-preferred temporary + * address with the prefix. + */ + if (!IFA6_IS_DEPRECATED(it6)) + public_ifa6 = it6; + } + + if (public_ifa6 != NULL) { + int e; + + if ((e = in6_tmpifadd(public_ifa6, 0)) != 0) { + log(LOG_NOTICE, "regen_tmpaddr: failed to create a new" + " tmp addr,errno=%d\n", e); + return(-1); + } + return(0); + } + + return(-1); +} + /* * Nuke neighbor cache/prefix/default router management table, right before * ifp goes away. @@ -627,8 +756,14 @@ nd6_purge(ifp) for (pr = nd_prefix.lh_first; pr; pr = npr) { npr = pr->ndpr_next; if (pr->ndpr_ifp == ifp) { - if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) - in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); + /* + * Previously, pr->ndpr_addr is removed as well, + * but I strongly believe we don't have to do it. + * nd6_purge() is only called from in6_ifdetach(), + * which removes all the associated interface addresses + * by itself. + * (jinmei@kame.net 20010129) + */ prelist_remove(pr); } } @@ -637,10 +772,12 @@ nd6_purge(ifp) if (nd6_defifindex == ifp->if_index) nd6_setdefaultiface(0); - /* refresh default router list */ - bzero(&drany, sizeof(drany)); - defrouter_delreq(&drany, 0); - defrouter_select(); + if (!ip6_forwarding && ip6_accept_rtadv) { /* XXX: too restrictive? */ + /* refresh default router list */ + bzero(&drany, sizeof(drany)); + defrouter_delreq(&drany, 0); + defrouter_select(); + } /* * Nuke neighbor cache entries for the ifp. @@ -659,30 +796,7 @@ nd6_purge(ifp) rt->rt_gateway->sa_family == AF_LINK) { sdl = (struct sockaddr_dl *)rt->rt_gateway; if (sdl->sdl_index == ifp->if_index) - nd6_free(rt); - } - ln = nln; - } - - /* - * Neighbor cache entry for interface route will be retained - * with ND6_LLINFO_WAITDELETE state, by nd6_free(). Nuke it. - */ - ln = llinfo_nd6.ln_next; - while (ln && ln != &llinfo_nd6) { - struct rtentry *rt; - struct sockaddr_dl *sdl; - - nln = ln->ln_next; - rt = ln->ln_rt; - if (rt && rt->rt_gateway && - rt->rt_gateway->sa_family == AF_LINK) { - sdl = (struct sockaddr_dl *)rt->rt_gateway; - if (sdl->sdl_index == ifp->if_index) { - rtrequest(RTM_DELETE, rt_key(rt), - (struct sockaddr *)0, rt_mask(rt), 0, - (struct rtentry **)0); - } + nln = nd6_free(rt); } ln = nln; } @@ -701,11 +815,10 @@ nd6_lookup(addr6, create, ifp) sin6.sin6_len = sizeof(struct sockaddr_in6); sin6.sin6_family = AF_INET6; sin6.sin6_addr = *addr6; - rt = rtalloc1((struct sockaddr *)&sin6, create -#if __FreeBSD__ || defined (__APPLE__) - , 0UL -#endif /*__FreeBSD__*/ - ); +#if SCOPEDROUTING + sin6.sin6_scope_id = in6_addr2scopeid(ifp, addr6); +#endif + rt = rtalloc1((struct sockaddr *)&sin6, create, 0UL); if (rt && (rt->rt_flags & RTF_LLINFO) == 0) { /* * This is the case for the default route. @@ -714,7 +827,7 @@ nd6_lookup(addr6, create, ifp) * interface route. */ if (create) { - RTFREE(rt); + rtfree(rt); rt = 0; } } @@ -758,11 +871,10 @@ nd6_lookup(addr6, create, ifp) (struct llinfo_nd6 *)rt->rt_llinfo; ln->ln_state = ND6_LLINFO_NOSTATE; } - } - else + } else return(NULL); } - rt->rt_refcnt--; + rtunref(rt); /* * Validation for the entry. * XXX: we can't use rt->rt_ifp to check for the interface, since @@ -789,36 +901,38 @@ nd6_lookup(addr6, create, ifp) */ int nd6_is_addr_neighbor(addr, ifp) - struct in6_addr *addr; + struct sockaddr_in6 *addr; struct ifnet *ifp; { - register struct ifaddr *ifa; + struct ifaddr *ifa; int i; #define IFADDR6(a) ((((struct in6_ifaddr *)(a))->ia_addr).sin6_addr) #define IFMASK6(a) ((((struct in6_ifaddr *)(a))->ia_prefixmask).sin6_addr) - /* A link-local address is always a neighbor. */ - if (IN6_IS_ADDR_LINKLOCAL(addr)) + /* + * A link-local address is always a neighbor. + * XXX: we should use the sin6_scope_id field rather than the embedded + * interface index. + */ + if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr) && + ntohs(*(u_int16_t *)&addr->sin6_addr.s6_addr[2]) == ifp->if_index) return(1); /* * If the address matches one of our addresses, * it should be a neighbor. */ -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) -#else for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) -#endif { if (ifa->ifa_addr->sa_family != AF_INET6) next: continue; for (i = 0; i < 4; i++) { - if ((IFADDR6(ifa).s6_addr32[i] ^ addr->s6_addr32[i]) & + if ((IFADDR6(ifa).s6_addr32[i] ^ + addr->sin6_addr.s6_addr32[i]) & IFMASK6(ifa).s6_addr32[i]) goto next; } @@ -829,7 +943,7 @@ nd6_is_addr_neighbor(addr, ifp) * Even if the address matches none of our addresses, it might be * in the neighbor cache. */ - if (nd6_lookup(addr, 0, ifp)) + if (nd6_lookup(&addr->sin6_addr, 0, ifp)) return(1); return(0); @@ -840,30 +954,25 @@ nd6_is_addr_neighbor(addr, ifp) /* * Free an nd6 llinfo entry. */ -void +struct llinfo_nd6 * nd6_free(rt) struct rtentry *rt; { - struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; - struct sockaddr_dl *sdl; + struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo, *next; struct in6_addr in6 = ((struct sockaddr_in6 *)rt_key(rt))->sin6_addr; struct nd_defrouter *dr; /* - * Clear all destination cache entries for the neighbor. - * XXX: is it better to restrict this to hosts? + * we used to have pfctlinput(PRC_HOSTDEAD) here. + * even though it is not harmful, it was not really necessary. */ - pfctlinput(PRC_HOSTDEAD, rt_key(rt)); if (!ip6_forwarding && ip6_accept_rtadv) { /* XXX: too restrictive? */ int s; -#ifdef __NetBSD__ - s = splsoftnet(); -#else s = splnet(); -#endif dr = defrouter_lookup(&((struct sockaddr_in6 *)rt_key(rt))->sin6_addr, rt->rt_ifp); + if (ln->ln_router || dr) { /* * rt6_flush must be called whether or not the neighbor @@ -889,6 +998,14 @@ nd6_free(rt) */ ln->ln_state = ND6_LLINFO_INCOMPLETE; + /* + * Since defrouter_select() does not affect the + * on-link determination and MIP6 needs the check + * before the default router selection, we perform + * the check now. + */ + pfxlist_onlink_check(); + if (dr == TAILQ_FIRST(&nd_defrouter)) { /* * It is used as the current default router, @@ -902,22 +1019,27 @@ nd6_free(rt) defrouter_select(); } - pfxlist_onlink_check(); } splx(s); } - if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) && - sdl->sdl_family == AF_LINK) { - sdl->sdl_alen = 0; - ln->ln_state = ND6_LLINFO_WAITDELETE; - ln->ln_asked = 0; - rt->rt_flags &= ~RTF_REJECT; - return; - } + /* + * Before deleting the entry, remember the next entry as the + * return value. We need this because pfxlist_onlink_check() above + * might have freed other entries (particularly the old next entry) as + * a side effect (XXX). + */ + next = ln->ln_next; + /* + * Detach the route from the routing tree and the list of neighbor + * caches, and disable the route entry not to be used in already + * cached routes. + */ rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt), 0, (struct rtentry **)0); + + return(next); } /* @@ -926,14 +1048,12 @@ nd6_free(rt) * XXX cost-effective metods? */ void -nd6_nud_hint(rt, dst6) +nd6_nud_hint(rt, dst6, force) struct rtentry *rt; struct in6_addr *dst6; + int force; { struct llinfo_nd6 *ln; -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined (__APPLE__) - long time_second = time.tv_sec; -#endif /* * If the caller specified "rt", use that. Otherwise, resolve the @@ -946,11 +1066,10 @@ nd6_nud_hint(rt, dst6) return; } - if ((rt->rt_flags & RTF_GATEWAY) - || (rt->rt_flags & RTF_LLINFO) == 0 - || !rt->rt_llinfo - || !rt->rt_gateway - || rt->rt_gateway->sa_family != AF_LINK) { + if ((rt->rt_flags & RTF_GATEWAY) != 0 || + (rt->rt_flags & RTF_LLINFO) == 0 || + !rt->rt_llinfo || !rt->rt_gateway || + rt->rt_gateway->sa_family != AF_LINK) { /* This is not a host route. */ return; } @@ -959,135 +1078,48 @@ nd6_nud_hint(rt, dst6) if (ln->ln_state < ND6_LLINFO_REACHABLE) return; - ln->ln_state = ND6_LLINFO_REACHABLE; - if (ln->ln_expire && nd_ifinfo) - ln->ln_expire = time_second + - (rt->rt_ifp ? nd_ifinfo[rt->rt_ifp->if_index].reachable : 0) ; -} - -#if OLDIP6OUTPUT -/* - * Resolve an IP6 address into an ethernet address. If success, - * desten is filled in. If there is no entry in ndptab, - * set one up and multicast a solicitation for the IP6 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. - */ -int -nd6_resolve(ifp, rt, m, dst, desten) - struct ifnet *ifp; - struct rtentry *rt; - struct mbuf *m; - struct sockaddr *dst; - u_char *desten; -{ - struct llinfo_nd6 *ln = (struct llinfo_nd6 *)NULL; - struct sockaddr_dl *sdl; -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined (__APPLE__) - long time_second = time.tv_sec; -#endif - - if (m->m_flags & M_MCAST) { - switch (ifp->if_type) { - case IFT_ETHER: - case IFT_FDDI: - ETHER_MAP_IPV6_MULTICAST(&SIN6(dst)->sin6_addr, - desten); - return(1); - break; - case IFT_ARCNET: - *desten = 0; - return(1); - break; - default: - return(0); - } - } - if (rt && (rt->rt_flags & RTF_LLINFO) != 0) - ln = (struct llinfo_nd6 *)rt->rt_llinfo; - else { - if ((rt = nd6_lookup(&(SIN6(dst)->sin6_addr), 1, ifp)) != NULL) - ln = (struct llinfo_nd6 *)rt->rt_llinfo; - } - if (!ln || !rt) { - log(LOG_DEBUG, "nd6_resolve: can't allocate llinfo for %s\n", - ip6_sprintf(&(SIN6(dst)->sin6_addr))); - m_freem(m); - return(0); - } - sdl = SDL(rt->rt_gateway); /* - * Ckeck the address family and length is valid, the address - * is resolved; otherwise, try to resolve. + * if we get upper-layer reachability confirmation many times, + * it is possible we have false information. */ - if (ln->ln_state >= ND6_LLINFO_REACHABLE - && sdl->sdl_family == AF_LINK - && sdl->sdl_alen != 0) { - bcopy(LLADDR(sdl), desten, sdl->sdl_alen); - if (ln->ln_state == ND6_LLINFO_STALE) { - ln->ln_asked = 0; - ln->ln_state = ND6_LLINFO_DELAY; - ln->ln_expire = time_second + nd6_delay; - } - return(1); - } - /* - * There is an ndp entry, but no ethernet address - * response yet. Replace the held mbuf with this - * latest one. - * - * XXX Does the code conform to rate-limiting rule? - * (RFC 2461 7.2.2) - */ - if (ln->ln_state == ND6_LLINFO_WAITDELETE || - ln->ln_state == ND6_LLINFO_NOSTATE) - ln->ln_state = ND6_LLINFO_INCOMPLETE; - if (ln->ln_hold) - m_freem(ln->ln_hold); - ln->ln_hold = m; - if (ln->ln_expire) { - rt->rt_flags &= ~RTF_REJECT; - if (ln->ln_asked < nd6_mmaxtries && - ln->ln_expire < time_second) { - ln->ln_asked++; - ln->ln_expire = time_second + - nd_ifinfo[ifp->if_index].retrans / 1000; - nd6_ns_output(ifp, NULL, &(SIN6(dst)->sin6_addr), - ln, 0); - } + if (!force) { + ln->ln_byhint++; + if (ln->ln_byhint > nd6_maxnudhint) + return; } - return(0); + + ln->ln_state = ND6_LLINFO_REACHABLE; + if (ln->ln_expire) + ln->ln_expire = time_second + + nd_ifinfo[rt->rt_ifp->if_index].reachable; } -#endif /* OLDIP6OUTPUT */ void -#if defined(__bsdi__) && _BSDI_VERSION >= 199802 -nd6_rtrequest(req, rt, info) - int req; - struct rtentry *rt; - struct rt_addrinfo *info; /* xxx unused */ -#else nd6_rtrequest(req, rt, sa) int req; struct rtentry *rt; struct sockaddr *sa; /* xxx unused */ -#endif { struct sockaddr *gate = rt->rt_gateway; struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; struct ifnet *ifp = rt->rt_ifp; struct ifaddr *ifa; -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined (__APPLE__) - long time_second = time.tv_sec; -#endif if (rt->rt_flags & RTF_GATEWAY) return; + if (nd6_need_cache(ifp) == 0 && (rt->rt_flags & RTF_HOST) == 0) { + /* + * This is probably an interface direct route for a link + * which does not need neighbor caches (e.g. fe80::%lo0/64). + * We do not need special treatment below for such a route. + * Moreover, the RTF_LLINFO flag which would be set below + * would annoy the ndp(8) command. + */ + return; + } + switch (req) { case RTM_ADD: /* @@ -1113,7 +1145,7 @@ nd6_rtrequest(req, rt, sa) ln->ln_expire = time_second; #if 1 if (ln && ln->ln_expire == 0) { - /* cludge for desktops */ + /* kludge for desktops */ #if 0 printf("nd6_request: time.tv_sec is zero; " "treat it as 1\n"); @@ -1134,10 +1166,10 @@ nd6_rtrequest(req, rt, sa) * (7.2.6 paragraph 4), however, it also says that we * SHOULD provide a mechanism to prevent multicast NA storm. * we don't have anything like it right now. - * note that the mechanism need a mutual agreement + * note that the mechanism needs a mutual agreement * between proxies, which means that we need to implement - * a new protocol, or new kludge. - * - from RFC2461 6.2.4, host MUST NOT send unsolicited NA. + * a new protocol, or a new kludge. + * - from RFC2461 6.2.4, host MUST NOT send an unsolicited NA. * we need to check ip6forwarding before sending it. * (or should we allow proxy ND configuration only for * routers? there's no mention about proxy ND from hosts) @@ -1153,7 +1185,7 @@ nd6_rtrequest(req, rt, sa) #endif /* FALLTHROUGH */ case RTM_RESOLVE: - if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { + if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) == 0) { /* * Address resolution isn't necessary for a point to * point link, so we can skip this test for a p2p link. @@ -1161,7 +1193,8 @@ nd6_rtrequest(req, rt, sa) if (gate->sa_family != AF_LINK || gate->sa_len < sizeof(null_sdl)) { log(LOG_DEBUG, - "nd6_rtrequest: bad gateway value\n"); + "nd6_rtrequest: bad gateway value: %s\n", + if_name(ifp)); break; } SDL(gate)->sdl_type = ifp->if_type; @@ -1191,6 +1224,7 @@ nd6_rtrequest(req, rt, sa) * which is specified by ndp command. */ ln->ln_state = ND6_LLINFO_REACHABLE; + ln->ln_byhint = 0; } else { /* * When req == RTM_RESOLVE, rt is created and @@ -1215,22 +1249,13 @@ nd6_rtrequest(req, rt, sa) caddr_t macp = nd6_ifptomac(ifp); ln->ln_expire = 0; ln->ln_state = ND6_LLINFO_REACHABLE; + ln->ln_byhint = 0; if (macp) { Bcopy(macp, LLADDR(SDL(gate)), ifp->if_addrlen); SDL(gate)->sdl_alen = ifp->if_addrlen; } if (nd6_useloopback) { -#ifdef __bsdi__ -#if _BSDI_VERSION >= 199802 - extern struct ifnet *loifp; - rt->rt_ifp = loifp; /*XXX*/ -#else - extern struct ifnet loif; - rt->rt_ifp = &loif; /*XXX*/ -#endif -#else /* non-bsdi */ rt->rt_ifp = &loif[0]; /*XXX*/ -#endif /* * Make sure rt_ifa be equal to the ifaddr * corresponding to the address. @@ -1240,14 +1265,13 @@ nd6_rtrequest(req, rt, sa) * of the loopback address. */ if (ifa != rt->rt_ifa) { - rt->rt_ifa->ifa_refcnt--; - ifa->ifa_refcnt++; - rt->rt_ifa = ifa; + rtsetifa(rt, ifa); } } } else if (rt->rt_flags & RTF_ANNOUNCE) { ln->ln_expire = 0; ln->ln_state = ND6_LLINFO_REACHABLE; + ln->ln_byhint = 0; /* join solicited node multicast for proxy ND */ if (ifp->if_flags & IFF_MULTICAST) { @@ -1261,10 +1285,11 @@ nd6_rtrequest(req, rt, sa) llsol.s6_addr32[2] = htonl(1); llsol.s6_addr8[12] = 0xff; - (void)in6_addmulti(&llsol, ifp, &error); - if (error) - printf( -"nd6_rtrequest: could not join solicited node multicast (errno=%d)\n", error); + if (!in6_addmulti(&llsol, ifp, &error)) { + nd6log((LOG_ERR, "%s: failed to join " + "%s (errno=%d)\n", if_name(ifp), + ip6_sprintf(&llsol), error)); + } } } break; @@ -1301,82 +1326,6 @@ nd6_rtrequest(req, rt, sa) } } -void -#if defined(__bsdi__) && _BSDI_VERSION >= 199802 -nd6_p2p_rtrequest(req, rt, info) - int req; - struct rtentry *rt; - struct rt_addrinfo *info; /* xxx unused */ -#else -nd6_p2p_rtrequest(req, rt, sa) - int req; - struct rtentry *rt; - struct sockaddr *sa; /* xxx unused */ -#endif -{ - struct sockaddr *gate = rt->rt_gateway; - static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; - struct ifnet *ifp = rt->rt_ifp; - struct ifaddr *ifa; - - if (rt->rt_flags & RTF_GATEWAY) - return; - - switch (req) { - case RTM_ADD: - /* - * There is no backward compatibility :) - * - * if ((rt->rt_flags & RTF_HOST) == 0 && - * SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) - * rt->rt_flags |= RTF_CLONING; - */ - if (rt->rt_flags & RTF_CLONING) { - /* - * Case 1: This route should come from - * a route to interface. - */ - rt_setgate(rt, rt_key(rt), - (struct sockaddr *)&null_sdl); - gate = rt->rt_gateway; - SDL(gate)->sdl_type = ifp->if_type; - SDL(gate)->sdl_index = ifp->if_index; - break; - } - /* Announce a new entry if requested. */ - if (rt->rt_flags & RTF_ANNOUNCE) - nd6_na_output(ifp, - &SIN6(rt_key(rt))->sin6_addr, - &SIN6(rt_key(rt))->sin6_addr, - ip6_forwarding ? ND_NA_FLAG_ROUTER : 0, - 1, NULL); - /* FALLTHROUGH */ - case RTM_RESOLVE: - /* - * check if rt_key(rt) is one of my address assigned - * to the interface. - */ - ifa = (struct ifaddr *)in6ifa_ifpwithaddr(rt->rt_ifp, - &SIN6(rt_key(rt))->sin6_addr); - if (ifa) { - if (nd6_useloopback) { -#ifdef __bsdi__ -#if _BSDI_VERSION >= 199802 - extern struct ifnet *loifp; - rt->rt_ifp = loifp; /*XXX*/ -#else - extern struct ifnet loif; - rt->rt_ifp = &loif; /*XXX*/ -#endif -#else - rt->rt_ifp = &loif[0]; /*XXX*/ -#endif /*__bsdi__*/ - } - } - break; - } -} - int nd6_ioctl(cmd, data, ifp) u_long cmd; @@ -1396,20 +1345,18 @@ nd6_ioctl(cmd, data, ifp) switch (cmd) { case SIOCGDRLST_IN6: + /* + * obsolete API, use sysctl under net.inet6.icmp6 + */ bzero(drl, sizeof(*drl)); -#ifdef __NetBSD__ - s = splsoftnet(); -#else s = splnet(); -#endif dr = TAILQ_FIRST(&nd_defrouter); while (dr && i < DRLSTSIZ) { drl->defrouter[i].rtaddr = dr->rtaddr; if (IN6_IS_ADDR_LINKLOCAL(&drl->defrouter[i].rtaddr)) { /* XXX: need to this hack for KAME stack */ drl->defrouter[i].rtaddr.s6_addr16[1] = 0; - } - else + } else log(LOG_ERR, "default router list contains a " "non-linklocal address(%s)\n", @@ -1425,23 +1372,23 @@ nd6_ioctl(cmd, data, ifp) splx(s); break; case SIOCGPRLST_IN6: + /* + * obsolete API, use sysctl under net.inet6.icmp6 + */ /* * XXX meaning of fields, especialy "raflags", is very * differnet between RA prefix list and RR/static prefix list. * how about separating ioctls into two? */ bzero(prl, sizeof(*prl)); -#ifdef __NetBSD__ - s = splsoftnet(); -#else s = splnet(); -#endif pr = nd_prefix.lh_first; while (pr && i < PRLSTSIZ) { struct nd_pfxrouter *pfr; int j; - prl->prefix[i].prefix = pr->ndpr_prefix.sin6_addr; + (void)in6_embedscope(&prl->prefix[i].prefix, + &pr->ndpr_prefix, NULL, NULL); prl->prefix[i].raflags = pr->ndpr_raf; prl->prefix[i].prefixlen = pr->ndpr_plen; prl->prefix[i].vltime = pr->ndpr_vltime; @@ -1451,15 +1398,14 @@ nd6_ioctl(cmd, data, ifp) pfr = pr->ndpr_advrtrs.lh_first; j = 0; - while(pfr) { + while (pfr) { if (j < DRLSTSIZ) { #define RTRADDR prl->prefix[i].advrtr[j] RTRADDR = pfr->router->rtaddr; if (IN6_IS_ADDR_LINKLOCAL(&RTRADDR)) { /* XXX: hack for KAME */ RTRADDR.s6_addr16[1] = 0; - } - else + } else log(LOG_ERR, "a router(%s) advertises " "a prefix with " @@ -1483,7 +1429,8 @@ nd6_ioctl(cmd, data, ifp) rpp = LIST_NEXT(rpp, rp_entry)) { if (i >= PRLSTSIZ) break; - prl->prefix[i].prefix = rpp->rp_prefix.sin6_addr; + (void)in6_embedscope(&prl->prefix[i].prefix, + &pr->ndpr_prefix, NULL, NULL); prl->prefix[i].raflags = rpp->rp_raf; prl->prefix[i].prefixlen = rpp->rp_plen; prl->prefix[i].vltime = rpp->rp_vltime; @@ -1497,12 +1444,36 @@ nd6_ioctl(cmd, data, ifp) } splx(s); + break; + case OSIOCGIFINFO_IN6: + if (!nd_ifinfo || i >= nd_ifinfo_indexlim) { + error = EINVAL; + break; + } + ndi->ndi.linkmtu = nd_ifinfo[ifp->if_index].linkmtu; + ndi->ndi.maxmtu = nd_ifinfo[ifp->if_index].maxmtu; + ndi->ndi.basereachable = + nd_ifinfo[ifp->if_index].basereachable; + ndi->ndi.reachable = nd_ifinfo[ifp->if_index].reachable; + ndi->ndi.retrans = nd_ifinfo[ifp->if_index].retrans; + ndi->ndi.flags = nd_ifinfo[ifp->if_index].flags; + ndi->ndi.recalctm = nd_ifinfo[ifp->if_index].recalctm; + ndi->ndi.chlim = nd_ifinfo[ifp->if_index].chlim; + ndi->ndi.receivedra = nd_ifinfo[ifp->if_index].receivedra; break; case SIOCGIFINFO_IN6: + if (!nd_ifinfo || i >= nd_ifinfo_indexlim) { + error = EINVAL; + break; + } ndi->ndi = nd_ifinfo[ifp->if_index]; break; case SIOCSIFINFO_FLAGS: /* XXX: almost all other fields of ndi->ndi is unused */ + if (!nd_ifinfo || i >= nd_ifinfo_indexlim) { + error = EINVAL; + break; + } nd_ifinfo[ifp->if_index].flags = ndi->ndi.flags; break; case SIOCSNDFLUSH_IN6: /* XXX: the ioctl name is confusing... */ @@ -1521,15 +1492,26 @@ nd6_ioctl(cmd, data, ifp) /* flush all the prefix advertised by routers */ struct nd_prefix *pr, *next; -#ifdef __NetBSD__ - s = splsoftnet(); -#else s = splnet(); -#endif for (pr = nd_prefix.lh_first; pr; pr = next) { + struct in6_ifaddr *ia, *ia_next; + next = pr->ndpr_next; - if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) - in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); + + if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) + continue; /* XXX */ + + /* do we really have to remove addresses as well? */ + for (ia = in6_ifaddr; ia; ia = ia_next) { + /* ia might be removed. keep the next ptr. */ + ia_next = ia->ia_next; + + if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0) + continue; + + if (ia->ia6_ndpr == pr) + in6_purgeaddr(&ia->ia_ifa); + } prelist_remove(pr); } splx(s); @@ -1540,11 +1522,7 @@ nd6_ioctl(cmd, data, ifp) /* flush all the default routers */ struct nd_defrouter *dr, *next; -#ifdef __NetBSD__ - s = splsoftnet(); -#else s = splnet(); -#endif if ((dr = TAILQ_FIRST(&nd_defrouter)) != NULL) { /* * The first entry of the list may be stored in @@ -1576,11 +1554,7 @@ nd6_ioctl(cmd, data, ifp) *idp = htons(ifp->if_index); } -#ifdef __NetBSD__ - s = splsoftnet(); -#else s = splnet(); -#endif if ((rt = nd6_lookup(&nb_addr, 0, ifp)) == NULL) { error = EINVAL; splx(s); @@ -1626,9 +1600,6 @@ nd6_cache_lladdr(ifp, from, lladdr, lladdrlen, type, code) int olladdr; int llchange; int newstate = 0; -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined (__APPLE__) - long time_second = time.tv_sec; -#endif if (!ifp) panic("ifp == NULL in nd6_cache_lladdr"); @@ -1659,14 +1630,18 @@ nd6_cache_lladdr(ifp, from, lladdr, lladdrlen, type, code) rt = nd6_lookup(from, 1, ifp); is_newentry = 1; - } else + } else { + /* do nothing if static ndp is set */ + if (rt->rt_flags & RTF_STATIC) + return NULL; is_newentry = 0; + } if (!rt) return NULL; if ((rt->rt_flags & (RTF_GATEWAY | RTF_LLINFO)) != RTF_LLINFO) { fail: - nd6_free(rt); + (void)nd6_free(rt); return NULL; } ln = (struct llinfo_nd6 *)rt->rt_llinfo; @@ -1729,17 +1704,23 @@ fail: ln->ln_state = newstate; if (ln->ln_state == ND6_LLINFO_STALE) { - rt->rt_flags &= ~RTF_REJECT; + /* + * XXX: since nd6_output() below will cause + * state tansition to DELAY and reset the timer, + * we must set the timer now, although it is actually + * meaningless. + */ + ln->ln_expire = time_second + nd6_gctimer; + if (ln->ln_hold) { -#if OLDIP6OUTPUT - (*ifp->if_output)(ifp, ln->ln_hold, - rt_key(rt), rt); -#else - nd6_output(ifp, ln->ln_hold, + /* + * we assume ifp is not a p2p here, so just + * set the 2nd argument as the 1st one. + */ + nd6_output(ifp, ifp, ln->ln_hold, (struct sockaddr_in6 *)rt_key(rt), rt); -#endif - ln->ln_hold = 0; + ln->ln_hold = NULL; } } else if (ln->ln_state == ND6_LLINFO_INCOMPLETE) { /* probe right away */ @@ -1789,7 +1770,6 @@ fail: * If the icmp is a redirect to a better router, always set the * is_router flag. Otherwise, if the entry is newly created, * clear the flag. [RFC 2461, sec 8.3] - * */ if (code == ND_REDIRECT_ROUTER) ln->ln_router = 1; @@ -1813,39 +1793,41 @@ fail: break; } + /* + * When the link-layer address of a router changes, select the + * best router again. In particular, when the neighbor entry is newly + * created, it might affect the selection policy. + * Question: can we restrict the first condition to the "is_newentry" + * case? + * XXX: when we hear an RA from a new router with the link-layer + * address option, defrouter_select() is called twice, since + * defrtrlist_update called the function as well. However, I believe + * we can compromise the overhead, since it only happens the first + * time. + * XXX: although defrouter_select() should not have a bad effect + * for those are not autoconfigured hosts, we explicitly avoid such + * cases for safety. + */ + if (do_update && ln->ln_router && !ip6_forwarding && ip6_accept_rtadv) + defrouter_select(); + return rt; } -static void -nd6_slowtimo_funneled(ignored_arg) - void *ignored_arg; -{ -#ifdef __APPLE__ - boolean_t funnel_state; - funnel_state = thread_funnel_set(network_flock, TRUE); -#endif - nd6_slowtimo(ignored_arg); -#ifdef __APPLE__ - (void) thread_funnel_set(network_flock, FALSE); -#endif -} static void nd6_slowtimo(ignored_arg) void *ignored_arg; { - int s; - register int i; - register struct nd_ifinfo *nd6if; + int s = splnet(); + int i; + struct nd_ifinfo *nd6if; -#ifdef __NetBSD__ - s = splsoftnet(); -#else s = splnet(); -#endif - timeout(nd6_slowtimo_funneled, (caddr_t)0, ND6_SLOWTIMER_INTERVAL * hz); for (i = 1; i < if_index + 1; i++) { + if (!nd_ifinfo || i >= nd_ifinfo_indexlim) + continue; nd6if = &nd_ifinfo[i]; if (nd6if->basereachable && /* already initialized */ (nd6if->recalctm -= ND6_SLOWTIMER_INTERVAL) <= 0) { @@ -1860,47 +1842,41 @@ nd6_slowtimo(ignored_arg) } } splx(s); +} +static void +nd6_slowtimo_funneled(ignored_arg) + void *ignored_arg; +{ +#ifdef __APPLE__ + boolean_t funnel_state; + funnel_state = thread_funnel_set(network_flock, TRUE); +#endif + nd6_slowtimo(ignored_arg); +#ifdef __APPLE__ + (void) thread_funnel_set(network_flock, FALSE); +#endif } #define senderr(e) { error = (e); goto bad;} int -nd6_output(ifp, m0, dst, rt0) - register struct ifnet *ifp; +nd6_output(ifp, origifp, m0, dst, rt0) + struct ifnet *ifp; + struct ifnet *origifp; struct mbuf *m0; struct sockaddr_in6 *dst; struct rtentry *rt0; { - register struct mbuf *m = m0; - register struct rtentry *rt = rt0; + struct mbuf *m = m0; + struct rtentry *rt = rt0; + struct sockaddr_in6 *gw6 = NULL; struct llinfo_nd6 *ln = NULL; int error = 0; -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined (__APPLE__) - long time_second = time.tv_sec; -#endif if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr)) goto sendpkt; - /* - * XXX: we currently do not make neighbor cache on any interface - * other than ARCnet, Ethernet, FDDI and GIF. - * - * draft-ietf-ngtrans-mech-04.txt says: - * - unidirectional tunnels needs no ND - */ - switch (ifp->if_type) { - case IFT_ARCNET: - case IFT_ETHER: - case IFT_FDDI: - case IFT_GIF: /* XXX need more cases? */ - break; - default: - goto sendpkt; - } - - if ((ifp->if_flags & IFF_POINTOPOINT) != 0 && - (nd_ifinfo[ifp->if_index].flags & ND6_IFF_PERFORMNUD) == 0) + if (nd6_need_cache(ifp) == 0) goto sendpkt; /* @@ -1908,45 +1884,53 @@ nd6_output(ifp, m0, dst, rt0) */ if (rt) { if ((rt->rt_flags & RTF_UP) == 0) { -#if __FreeBSD__ || defined (__APPLE__) if ((rt0 = rt = rtalloc1((struct sockaddr *)dst, 1, 0UL)) != NULL) -#else - if ((rt0 = rt = rtalloc1((struct sockaddr *)dst, 1)) != - NULL) -#endif { - rt->rt_refcnt--; - if (rt->rt_ifp != ifp) - return nd6_output(ifp, m0, dst, rt); /* XXX: loop care? */ + rtunref(rt); + if (rt->rt_ifp != ifp) { + /* XXX: loop care? */ + return nd6_output(ifp, origifp, m0, + dst, rt); + } } else senderr(EHOSTUNREACH); } + if (rt->rt_flags & RTF_GATEWAY) { + gw6 = (struct sockaddr_in6 *)rt->rt_gateway; + + /* + * We skip link-layer address resolution and NUD + * if the gateway is not a neighbor from ND point + * of view, regardless the value of the + * nd_ifinfo.flags. + * The second condition is a bit tricky: we skip + * if the gateway is our own address, which is + * sometimes used to install a route to a p2p link. + */ + if (!nd6_is_addr_neighbor(gw6, ifp) || + in6ifa_ifpwithaddr(ifp, &gw6->sin6_addr)) { + /* + * We allow this kind of tricky route only + * when the outgoing interface is p2p. + * XXX: we may need a more generic rule here. + */ + if ((ifp->if_flags & IFF_POINTOPOINT) == 0) + senderr(EHOSTUNREACH); + + goto sendpkt; + } + if (rt->rt_gwroute == 0) goto lookup; if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { rtfree(rt); rt = rt0; -#if __FreeBSD__ || defined (__APPLE__) lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 0UL); -#else - lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1); -#endif if ((rt = rt->rt_gwroute) == 0) senderr(EHOSTUNREACH); -#ifdef __bsdi__ - /* the "G" test below also prevents rt == rt0 */ - if ((rt->rt_flags & RTF_GATEWAY) || - (rt->rt_ifp != ifp)) { - rt->rt_refcnt--; - rt0->rt_gwroute = 0; - senderr(EHOSTUNREACH); - } -#endif } } - if (rt->rt_flags & RTF_REJECT) - senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); } /* @@ -1960,20 +1944,34 @@ nd6_output(ifp, m0, dst, rt0) if (rt && (rt->rt_flags & RTF_LLINFO) != 0) ln = (struct llinfo_nd6 *)rt->rt_llinfo; else { - if ((rt = nd6_lookup(&dst->sin6_addr, 1, ifp)) != NULL) + /* + * Since nd6_is_addr_neighbor() internally calls nd6_lookup(), + * the condition below is not very efficient. But we believe + * it is tolerable, because this should be a rare case. + */ + if (nd6_is_addr_neighbor(dst, ifp) && + (rt = nd6_lookup(&dst->sin6_addr, 1, ifp)) != NULL) ln = (struct llinfo_nd6 *)rt->rt_llinfo; } if (!ln || !rt) { - log(LOG_DEBUG, "nd6_output: can't allocate llinfo for %s " - "(ln=%p, rt=%p)\n", - ip6_sprintf(&dst->sin6_addr), ln, rt); - senderr(EIO); /* XXX: good error? */ + if ((ifp->if_flags & IFF_POINTOPOINT) == 0 && + !(nd_ifinfo[ifp->if_index].flags & ND6_IFF_PERFORMNUD)) { + log(LOG_DEBUG, + "nd6_output: can't allocate llinfo for %s " + "(ln=%p, rt=%p)\n", + ip6_sprintf(&dst->sin6_addr), ln, rt); + senderr(EIO); /* XXX: good error? */ + } + + goto sendpkt; /* send anyway */ } /* We don't have to do link-layer address resolution on a p2p link. */ if ((ifp->if_flags & IFF_POINTOPOINT) != 0 && - ln->ln_state < ND6_LLINFO_REACHABLE) + ln->ln_state < ND6_LLINFO_REACHABLE) { ln->ln_state = ND6_LLINFO_STALE; + ln->ln_expire = time_second + nd6_gctimer; + } /* * The first time we send a packet to a neighbor whose entry is @@ -2004,14 +2002,12 @@ nd6_output(ifp, m0, dst, rt0) * XXX Does the code conform to rate-limiting rule? * (RFC 2461 7.2.2) */ - if (ln->ln_state == ND6_LLINFO_WAITDELETE || - ln->ln_state == ND6_LLINFO_NOSTATE) + if (ln->ln_state == ND6_LLINFO_NOSTATE) ln->ln_state = ND6_LLINFO_INCOMPLETE; if (ln->ln_hold) m_freem(ln->ln_hold); ln->ln_hold = m; if (ln->ln_expire) { - rt->rt_flags &= ~RTF_REJECT; if (ln->ln_asked < nd6_mmaxtries && ln->ln_expire < time_second) { ln->ln_asked++; @@ -2024,8 +2020,23 @@ nd6_output(ifp, m0, dst, rt0) sendpkt: #ifdef __APPLE__ - return (dlil_output(ifptodlt(ifp, PF_INET6), m, rt, (struct sockaddr *)dst, 0)); + + /* Make sure the HW checksum flags are cleaned before sending the packet */ + + m->m_pkthdr.rcvif = (struct ifnet *)0; + m->m_pkthdr.csum_data = 0; + m->m_pkthdr.csum_flags = 0; + + if ((ifp->if_flags & IFF_LOOPBACK) != 0) { + return (dlil_output(ifptodlt(origifp, PF_INET6), m, (caddr_t)rt, (struct sockaddr *)dst,0)); + } + + return (dlil_output(ifptodlt(ifp, PF_INET6), m, (caddr_t)rt, (struct sockaddr *)dst, 0)); #else + if ((ifp->if_flags & IFF_LOOPBACK) != 0) { + return((*ifp->if_output)(origifp, m, (struct sockaddr *)dst, + rt)); + } return((*ifp->if_output)(ifp, m, (struct sockaddr *)dst, rt)); #endif @@ -2036,6 +2047,35 @@ nd6_output(ifp, m0, dst, rt0) } #undef senderr +int +nd6_need_cache(ifp) + struct ifnet *ifp; +{ + /* + * XXX: we currently do not make neighbor cache on any interface + * other than ARCnet, Ethernet, FDDI and GIF. + * + * RFC2893 says: + * - unidirectional tunnels needs no ND + */ + switch (ifp->if_type) { + case IFT_ARCNET: + case IFT_ETHER: + case IFT_FDDI: + case IFT_IEEE1394: +#if IFT_L2VLAN + case IFT_L2VLAN: +#endif +#if IFT_IEEE80211 + case IFT_IEEE80211: +#endif + case IFT_GIF: /* XXX need more cases? */ + return(1); + default: + return(0); + } +} + int nd6_storelladdr(ifp, rt, m, dst, desten) struct ifnet *ifp; @@ -2044,36 +2084,178 @@ nd6_storelladdr(ifp, rt, m, dst, desten) struct sockaddr *dst; u_char *desten; { + int i; struct sockaddr_dl *sdl; if (m->m_flags & M_MCAST) { switch (ifp->if_type) { case IFT_ETHER: - case IFT_FDDI: + case IFT_FDDI: +#if IFT_L2VLAN + case IFT_L2VLAN: +#endif +#if IFT_IEEE80211 + case IFT_IEEE80211: +#endif ETHER_MAP_IPV6_MULTICAST(&SIN6(dst)->sin6_addr, desten); return(1); - break; + case IFT_IEEE1394: + for (i = 0; i < ifp->if_addrlen; i++) + desten[i] = ~0; + return(1); case IFT_ARCNET: *desten = 0; return(1); default: + m_freem(m); return(0); } } - if (rt == NULL || - rt->rt_gateway->sa_family != AF_LINK) { + if (rt == NULL) { + /* this could happen, if we could not allocate memory */ + m_freem(m); + return(0); + } + if (rt->rt_gateway->sa_family != AF_LINK) { printf("nd6_storelladdr: something odd happens\n"); + m_freem(m); return(0); } sdl = SDL(rt->rt_gateway); if (sdl->sdl_alen == 0) { /* this should be impossible, but we bark here for debugging */ printf("nd6_storelladdr: sdl_alen == 0\n"); + m_freem(m); return(0); } bcopy(LLADDR(sdl), desten, sdl->sdl_alen); return(1); } +#ifndef __APPLE__ +static int nd6_sysctl_drlist SYSCTL_HANDLER_ARGS; +static int nd6_sysctl_prlist SYSCTL_HANDLER_ARGS; +SYSCTL_DECL(_net_inet6_icmp6); +SYSCTL_NODE(_net_inet6_icmp6, ICMPV6CTL_ND6_DRLIST, nd6_drlist, + CTLFLAG_RD, nd6_sysctl_drlist, ""); +SYSCTL_NODE(_net_inet6_icmp6, ICMPV6CTL_ND6_PRLIST, nd6_prlist, + CTLFLAG_RD, nd6_sysctl_prlist, ""); + +static int +nd6_sysctl_drlist SYSCTL_HANDLER_ARGS +{ + int error; + char buf[1024]; + struct in6_defrouter *d, *de; + struct nd_defrouter *dr; + + if (req->newptr) + return EPERM; + error = 0; + + for (dr = TAILQ_FIRST(&nd_defrouter); + dr; + dr = TAILQ_NEXT(dr, dr_entry)) { + d = (struct in6_defrouter *)buf; + de = (struct in6_defrouter *)(buf + sizeof(buf)); + + if (d + 1 <= de) { + bzero(d, sizeof(*d)); + d->rtaddr.sin6_family = AF_INET6; + d->rtaddr.sin6_len = sizeof(d->rtaddr); + if (in6_recoverscope(&d->rtaddr, &dr->rtaddr, + dr->ifp) != 0) + log(LOG_ERR, + "scope error in " + "default router list (%s)\n", + ip6_sprintf(&dr->rtaddr)); + d->flags = dr->flags; + d->rtlifetime = dr->rtlifetime; + d->expire = dr->expire; + d->if_index = dr->ifp->if_index; + } else + panic("buffer too short"); + + error = SYSCTL_OUT(req, buf, sizeof(*d)); + if (error) + break; + } + return error; +} + +static int +nd6_sysctl_prlist SYSCTL_HANDLER_ARGS +{ + int error; + char buf[1024]; + struct in6_prefix *p, *pe; + struct nd_prefix *pr; + + if (req->newptr) + return EPERM; + error = 0; + + for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { + u_short advrtrs; + size_t advance; + struct sockaddr_in6 *sin6, *s6; + struct nd_pfxrouter *pfr; + + p = (struct in6_prefix *)buf; + pe = (struct in6_prefix *)(buf + sizeof(buf)); + + if (p + 1 <= pe) { + bzero(p, sizeof(*p)); + sin6 = (struct sockaddr_in6 *)(p + 1); + + p->prefix = pr->ndpr_prefix; + if (in6_recoverscope(&p->prefix, + &p->prefix.sin6_addr, pr->ndpr_ifp) != 0) + log(LOG_ERR, + "scope error in prefix list (%s)\n", + ip6_sprintf(&p->prefix.sin6_addr)); + p->raflags = pr->ndpr_raf; + p->prefixlen = pr->ndpr_plen; + p->vltime = pr->ndpr_vltime; + p->pltime = pr->ndpr_pltime; + p->if_index = pr->ndpr_ifp->if_index; + p->expire = pr->ndpr_expire; + p->refcnt = pr->ndpr_refcnt; + p->flags = pr->ndpr_stateflags; + p->origin = PR_ORIG_RA; + advrtrs = 0; + for (pfr = pr->ndpr_advrtrs.lh_first; + pfr; + pfr = pfr->pfr_next) { + if ((void *)&sin6[advrtrs + 1] > + (void *)pe) { + advrtrs++; + continue; + } + s6 = &sin6[advrtrs]; + bzero(s6, sizeof(*s6)); + s6->sin6_family = AF_INET6; + s6->sin6_len = sizeof(*sin6); + if (in6_recoverscope(s6, + &pfr->router->rtaddr, + pfr->router->ifp) != 0) + log(LOG_ERR, + "scope error in " + "prefix list (%s)\n", + ip6_sprintf(&pfr->router->rtaddr)); + advrtrs++; + } + p->advrtrs = advrtrs; + } else + panic("buffer too short"); + + advance = sizeof(*p) + sizeof(*sin6) * advrtrs; + error = SYSCTL_OUT(req, buf, advance); + if (error) + break; + } + return error; +} +#endif diff --git a/bsd/netinet6/nd6.h b/bsd/netinet6/nd6.h index 687eb6894..a84135d9a 100644 --- a/bsd/netinet6/nd6.h +++ b/bsd/netinet6/nd6.h @@ -1,4 +1,5 @@ -/* $KAME: nd6.h,v 1.18 2000/03/16 11:58:32 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/nd6.h,v 1.2.2.3 2001/08/13 01:10:49 simokawa Exp $ */ +/* $KAME: nd6.h,v 1.55 2001/04/27 15:09:49 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -31,6 +32,7 @@ #ifndef _NETINET6_ND6_H_ #define _NETINET6_ND6_H_ +#include /* see net/route.h, or net/if_inarp.h */ #ifndef RTF_ANNOUNCE @@ -48,10 +50,18 @@ struct llinfo_nd6 { u_long ln_expire; /* lifetime for NDP state transition */ short ln_state; /* reachability state */ short ln_router; /* 2^0: ND6 router bit */ + int ln_byhint; /* # of times we made it reachable by UL hint */ }; #define ND6_LLINFO_NOSTATE -2 -#define ND6_LLINFO_WAITDELETE -1 +/* + * We don't need the WAITDELETE state any more, but we keep the definition + * in a comment line instead of removing it. This is necessary to avoid + * unintentionally reusing the value for another purpose, which might + * affect backward compatibility with old applications. + * (20000711 jinmei@kame.net) + */ +/* #define ND6_LLINFO_WAITDELETE -1 */ #define ND6_LLINFO_INCOMPLETE 0 #define ND6_LLINFO_REACHABLE 1 #define ND6_LLINFO_STALE 2 @@ -70,6 +80,10 @@ struct nd_ifinfo { int recalctm; /* BaseReacable re-calculation timer */ u_int8_t chlim; /* CurHopLimit */ u_int8_t receivedra; + /* the followings are for privacy extension for addrconf */ + u_int8_t randomseed0[8]; /* upper 64 bits of MD5 digest */ + u_int8_t randomseed1[8]; /* lower 64 bits (usually the EUI64 IFID) */ + u_int8_t randomid[8]; /* current random ID */ }; #define ND6_IFF_PERFORMNUD 0x1 @@ -96,6 +110,14 @@ struct in6_drlist { } defrouter[DRLSTSIZ]; }; +struct in6_defrouter { + struct sockaddr_in6 rtaddr; + u_char flags; + u_short rtlifetime; + u_long expire; + u_short if_index; +}; + struct in6_prlist { char ifname[IFNAMSIZ]; struct { @@ -112,6 +134,36 @@ struct in6_prlist { } prefix[PRLSTSIZ]; }; +struct in6_prefix { + struct sockaddr_in6 prefix; + struct prf_ra raflags; + u_char prefixlen; + u_char origin; + u_long vltime; + u_long pltime; + u_long expire; + u_int32_t flags; + int refcnt; + u_short if_index; + u_short advrtrs; /* number of advertisement routers */ + /* struct sockaddr_in6 advrtr[] */ +}; + +struct in6_ondireq { + char ifname[IFNAMSIZ]; + struct { + u_int32_t linkmtu; /* LinkMTU */ + u_int32_t maxmtu; /* Upper bound of LinkMTU */ + u_int32_t basereachable; /* BaseReachableTime */ + u_int32_t reachable; /* Reachable Time */ + u_int32_t retrans; /* Retrans Timer */ + u_int32_t flags; /* Flags */ + int recalctm; /* BaseReacable re-calculation timer */ + u_int8_t chlim; /* CurHopLimit */ + u_int8_t receivedra; + } ndi; +}; + struct in6_ndireq { char ifname[IFNAMSIZ]; struct nd_ifinfo ndi; @@ -122,6 +174,9 @@ struct in6_ndifreq { u_long ifindex; }; +/* Prefix status */ +#define NDPRF_ONLINK 0x1 +#define NDPRF_DETACHED 0x2 /* protocol constants */ #define MAX_RTR_SOLICITATION_DELAY 1 /*1sec*/ @@ -130,22 +185,21 @@ struct in6_ndifreq { #define ND6_INFINITE_LIFETIME 0xffffffff -#if KERNEL +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE /* node constants */ #define MAX_REACHABLE_TIME 3600000 /* msec */ #define REACHABLE_TIME 30000 /* msec */ #define RETRANS_TIMER 1000 /* msec */ #define MIN_RANDOM_FACTOR 512 /* 1024 * 0.5 */ #define MAX_RANDOM_FACTOR 1536 /* 1024 * 1.5 */ -#ifndef __OpenBSD__ +#define DEF_TEMP_VALID_LIFETIME 604800 /* 1 week */ +#define DEF_TEMP_PREFERRED_LIFETIME 86400 /* 1 day */ +#define TEMPADDR_REGEN_ADVANCE 5 /* sec */ +#define MAX_TEMP_DESYNC_FACTOR 600 /* 10 min */ #define ND_COMPUTE_RTIME(x) \ (((MIN_RANDOM_FACTOR * (x >> 10)) + (random() & \ ((MAX_RANDOM_FACTOR - MIN_RANDOM_FACTOR) * (x >> 10)))) /1000) -#else -#define ND_COMPUTE_RTIME(x) \ - (((MIN_RANDOM_FACTOR * (x >> 10)) + (arc4random() & \ - ((MAX_RANDOM_FACTOR - MIN_RANDOM_FACTOR) * (x >> 10)))) /1000) -#endif TAILQ_HEAD(nd_drhead, nd_defrouter); struct nd_defrouter { @@ -171,13 +225,11 @@ struct nd_prefix { time_t ndpr_expire; /* expiration time of the prefix */ time_t ndpr_preferred; /* preferred time of the prefix */ struct prf_ra ndpr_flags; + u_int32_t ndpr_stateflags; /* actual state flags */ /* list of routers that advertise the prefix: */ LIST_HEAD(pr_rtrhead, nd_pfxrouter) ndpr_advrtrs; u_char ndpr_plen; - struct ndpr_stateflags { - /* if this prefix can be regarded as on-link */ - u_char onlink : 1; - } ndpr_stateflags; + int ndpr_refcnt; /* reference couter from addresses */ }; #define ndpr_next ndpr_entry.le_next @@ -186,9 +238,6 @@ struct nd_prefix { #define ndpr_raf_onlink ndpr_flags.onlink #define ndpr_raf_auto ndpr_flags.autonomous -#define ndpr_statef_onlink ndpr_stateflags.onlink -#define ndpr_statef_addmark ndpr_stateflags.addmark - /* * We keep expired prefix for certain amount of time, for validation purposes. * 1800s = MaxRtrAdvInterval @@ -238,14 +287,24 @@ extern int nd6_delay; extern int nd6_umaxtries; extern int nd6_mmaxtries; extern int nd6_useloopback; +extern int nd6_maxnudhint; +extern int nd6_gctimer; extern struct llinfo_nd6 llinfo_nd6; extern struct nd_ifinfo *nd_ifinfo; extern struct nd_drhead nd_defrouter; extern struct nd_prhead nd_prefix; +extern int nd6_debug; + +#define nd6log(x) do { if (nd6_debug) log x; } while (0) + +extern struct callout nd6_timer_ch; /* nd6_rtr.c */ -extern struct ifnet *nd6_defifp; /* XXXYYY */ extern int nd6_defifindex; +extern int ip6_desync_factor; /* seconds */ +extern u_int32_t ip6_temp_preferred_lifetime; /* seconds */ +extern u_int32_t ip6_temp_valid_lifetime; /* seconds */ +extern int ip6_temp_regen_advance; /* seconds */ union nd_opts { struct nd_opt_hdr *nd_opt_array[9]; /*max = home agent info*/ @@ -281,44 +340,38 @@ union nd_opts { /* nd6.c */ void nd6_init __P((void)); void nd6_ifattach __P((struct ifnet *)); -int nd6_is_addr_neighbor __P((struct in6_addr *, struct ifnet *)); +int nd6_is_addr_neighbor __P((struct sockaddr_in6 *, struct ifnet *)); void nd6_option_init __P((void *, int, union nd_opts *)); struct nd_opt_hdr *nd6_option __P((union nd_opts *)); int nd6_options __P((union nd_opts *)); struct rtentry *nd6_lookup __P((struct in6_addr *, int, struct ifnet *)); void nd6_setmtu __P((struct ifnet *)); void nd6_timer __P((void *)); -void nd6_timer_funneled __P((void *)); void nd6_purge __P((struct ifnet *)); -void nd6_free __P((struct rtentry *)); -void nd6_nud_hint __P((struct rtentry *, struct in6_addr *)); +struct llinfo_nd6 *nd6_free __P((struct rtentry *)); +void nd6_nud_hint __P((struct rtentry *, struct in6_addr *, int)); int nd6_resolve __P((struct ifnet *, struct rtentry *, struct mbuf *, struct sockaddr *, u_char *)); -#if defined(__bsdi__) && _BSDI_VERSION >= 199802 -void nd6_rtrequest __P((int, struct rtentry *, struct rt_addrinfo *)); -void nd6_p2p_rtrequest __P((int, struct rtentry *, struct rt_addrinfo *)); -#else void nd6_rtrequest __P((int, struct rtentry *, struct sockaddr *)); -void nd6_p2p_rtrequest __P((int, struct rtentry *, struct sockaddr *)); -#endif int nd6_ioctl __P((u_long, caddr_t, struct ifnet *)); struct rtentry *nd6_cache_lladdr __P((struct ifnet *, struct in6_addr *, char *, int, int, int)); -/* for test */ -int nd6_output __P((struct ifnet *, struct mbuf *, struct sockaddr_in6 *, - struct rtentry *)); +int nd6_output __P((struct ifnet *, struct ifnet *, struct mbuf *, + struct sockaddr_in6 *, struct rtentry *)); int nd6_storelladdr __P((struct ifnet *, struct rtentry *, struct mbuf *, struct sockaddr *, u_char *)); +int nd6_need_cache __P((struct ifnet *)); /* nd6_nbr.c */ void nd6_na_input __P((struct mbuf *, int, int)); -void nd6_na_output __P((struct ifnet *, struct in6_addr *, - struct in6_addr *, u_long, int, struct sockaddr *)); +void nd6_na_output __P((struct ifnet *, const struct in6_addr *, + const struct in6_addr *, u_long, int, struct sockaddr *)); void nd6_ns_input __P((struct mbuf *, int, int)); -void nd6_ns_output __P((struct ifnet *, struct in6_addr *, - struct in6_addr *, struct llinfo_nd6 *, int)); +void nd6_ns_output __P((struct ifnet *, const struct in6_addr *, + const struct in6_addr *, struct llinfo_nd6 *, int)); caddr_t nd6_ifptomac __P((struct ifnet *)); void nd6_dad_start __P((struct ifaddr *, int *)); +void nd6_dad_stop __P((struct ifaddr *)); void nd6_dad_duplicated __P((struct ifaddr *)); /* nd6_rtr.c */ @@ -331,20 +384,21 @@ void defrouter_select __P((void)); void defrtrlist_del __P((struct nd_defrouter *)); void prelist_remove __P((struct nd_prefix *)); int prelist_update __P((struct nd_prefix *, struct nd_defrouter *, - struct mbuf *)); -struct nd_pfxrouter *find_pfxlist_reachable_router __P((struct nd_prefix *)); /* XXXYYY */ + struct mbuf *)); +int nd6_prelist_add __P((struct nd_prefix *, struct nd_defrouter *, + struct nd_prefix **)); +int nd6_prefix_onlink __P((struct nd_prefix *)); +int nd6_prefix_offlink __P((struct nd_prefix *)); void pfxlist_onlink_check __P((void)); -void defrouter_addifreq __P((struct ifnet *)); /* XXXYYY */ struct nd_defrouter *defrouter_lookup __P((struct in6_addr *, struct ifnet *)); -struct nd_prefix *prefix_lookup __P((struct nd_prefix *)); /* XXXYYY */ -int in6_ifdel __P((struct ifnet *, struct in6_addr *)); -struct nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *, - struct nd_defrouter *)); /* XXXYYY */ +struct nd_prefix *nd6_prefix_lookup __P((struct nd_prefix *)); int in6_init_prefix_ltimes __P((struct nd_prefix *ndpr)); void rt6_flush __P((struct in6_addr *, struct ifnet *)); int nd6_setdefaultiface __P((int)); +int in6_tmpifadd __P((const struct in6_ifaddr *, int)); +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ #endif /* _NETINET6_ND6_H_ */ diff --git a/bsd/netinet6/nd6_nbr.c b/bsd/netinet6/nd6_nbr.c index a21dfb189..70fbfef80 100644 --- a/bsd/netinet6/nd6_nbr.c +++ b/bsd/netinet6/nd6_nbr.c @@ -1,4 +1,5 @@ -/* $KAME: nd6_nbr.c,v 1.32 2000/03/21 11:37:30 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/nd6_nbr.c,v 1.4.2.4 2001/07/06 05:32:25 sumikawa Exp $ */ +/* $KAME: nd6_nbr.c,v 1.64 2001/05/17 03:48:30 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -29,13 +30,6 @@ * SUCH DAMAGE. */ -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#if __NetBSD__ /*XXX*/ -#include "opt_ipsec.h" -#endif -#endif - #include #include #include @@ -45,9 +39,6 @@ #include #include #include -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) -#include -#endif #include #include @@ -64,12 +55,12 @@ #include #include -#ifdef __OpenBSD__ /*don't confuse KAME ipsec with OpenBSD ipsec*/ -#undef IPSEC -#endif - #if IPSEC #include +#if INET6 +#include +#endif +extern int ipsec_bypass; #endif #include @@ -78,6 +69,12 @@ struct dadq; static struct dadq *nd6_dad_find __P((struct ifaddr *)); +#ifndef __APPLE__ +static void nd6_dad_starttimer __P((struct dadq *, int)); +static void nd6_dad_stoptimer __P((struct dadq *)); +#else +void nd6_dad_stoptimer __P((struct ifaddr *)); +#endif static void nd6_dad_timer __P((struct ifaddr *)); static void nd6_dad_timer_funnel __P((struct ifaddr *)); static void nd6_dad_ns_output __P((struct dadq *, struct ifaddr *)); @@ -113,10 +110,25 @@ nd6_ns_input(m, off, icmp6len) union nd_opts ndopts; struct sockaddr_dl *proxydl = NULL; +#ifndef PULLDOWN_TEST + IP6_EXTHDR_CHECK(m, off, icmp6len,); + nd_ns = (struct nd_neighbor_solicit *)((caddr_t)ip6 + off); +#else + IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m, off, icmp6len); + if (nd_ns == NULL) { + icmp6stat.icp6s_tooshort++; + return; + } +#endif + ip6 = mtod(m, struct ip6_hdr *); /* adjust pointer for safety */ + taddr6 = nd_ns->nd_ns_target; + if (ip6->ip6_hlim != 255) { - log(LOG_ERR, - "nd6_ns_input: invalid hlim %d\n", ip6->ip6_hlim); - goto freeit; + nd6log((LOG_ERR, + "nd6_ns_input: invalid hlim (%d) from %s to %s on %s\n", + ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src), + ip6_sprintf(&ip6->ip6_dst), if_name(ifp))); + goto bad; } if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) { @@ -128,26 +140,14 @@ nd6_ns_input(m, off, icmp6len) && daddr6.s6_addr8[12] == 0xff) { ; /*good*/ } else { - log(LOG_INFO, "nd6_ns_input: bad DAD packet " - "(wrong ip6 dst)\n"); + nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet " + "(wrong ip6 dst)\n")); goto bad; } } -#ifndef PULLDOWN_TEST - IP6_EXTHDR_CHECK(m, off, icmp6len,); - nd_ns = (struct nd_neighbor_solicit *)((caddr_t)ip6 + off); -#else - IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m, off, icmp6len); - if (nd_ns == NULL) { - icmp6stat.icp6s_tooshort++; - return; - } -#endif - taddr6 = nd_ns->nd_ns_target; - if (IN6_IS_ADDR_MULTICAST(&taddr6)) { - log(LOG_INFO, "nd6_ns_input: bad NS target (multicast)\n"); + nd6log((LOG_INFO, "nd6_ns_input: bad NS target (multicast)\n")); goto bad; } @@ -157,8 +157,10 @@ nd6_ns_input(m, off, icmp6len) icmp6len -= sizeof(*nd_ns); nd6_option_init(nd_ns + 1, icmp6len, &ndopts); if (nd6_options(&ndopts) < 0) { - log(LOG_INFO, "nd6_ns_input: invalid ND option, ignored\n"); - goto bad; + nd6log((LOG_INFO, + "nd6_ns_input: invalid ND option, ignored\n")); + /* nd6_options have incremented stats */ + goto freeit; } if (ndopts.nd_opts_src_lladdr) { @@ -167,8 +169,8 @@ nd6_ns_input(m, off, icmp6len) } if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) && lladdr) { - log(LOG_INFO, "nd6_ns_input: bad DAD packet " - "(link-layer address option)\n"); + nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet " + "(link-layer address option)\n")); goto bad; } @@ -212,11 +214,7 @@ nd6_ns_input(m, off, icmp6len) tsin6.sin6_family = AF_INET6; tsin6.sin6_addr = taddr6; - rt = rtalloc1((struct sockaddr *)&tsin6, 0 -#if __FreeBSD__ || defined (__APPLE__) - , 0 -#endif /* __FreeBSD__ */ - ); + rt = rtalloc1((struct sockaddr *)&tsin6, 0, 0); if (rt && (rt->rt_flags & RTF_ANNOUNCE) != 0 && rt->rt_gateway->sa_family == AF_LINK) { /* @@ -234,7 +232,7 @@ nd6_ns_input(m, off, icmp6len) } if (!ifa) { /* - * We've got a NS packet, and we don't have that adddress + * We've got an NS packet, and we don't have that adddress * assigned for us. We MUST silently ignore it. * See RFC2461 7.2.3. */ @@ -247,10 +245,11 @@ nd6_ns_input(m, off, icmp6len) goto freeit; if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { - log(LOG_INFO, + nd6log((LOG_INFO, "nd6_ns_input: lladdrlen mismatch for %s " "(if %d, NS packet %d)\n", - ip6_sprintf(&taddr6), ifp->if_addrlen, lladdrlen - 2); + ip6_sprintf(&taddr6), ifp->if_addrlen, lladdrlen - 2)); + goto bad; } if (IN6_ARE_ADDR_EQUAL(&myaddr6, &saddr6)) { @@ -317,9 +316,10 @@ nd6_ns_input(m, off, icmp6len) return; bad: - log(LOG_ERR, "nd6_ns_input: src=%s\n", ip6_sprintf(&saddr6)); - log(LOG_ERR, "nd6_ns_input: dst=%s\n", ip6_sprintf(&daddr6)); - log(LOG_ERR, "nd6_ns_input: tgt=%s\n", ip6_sprintf(&taddr6)); + nd6log((LOG_ERR, "nd6_ns_input: src=%s\n", ip6_sprintf(&saddr6))); + nd6log((LOG_ERR, "nd6_ns_input: dst=%s\n", ip6_sprintf(&daddr6))); + nd6log((LOG_ERR, "nd6_ns_input: tgt=%s\n", ip6_sprintf(&taddr6))); + icmp6stat.icp6s_badns++; m_freem(m); } @@ -335,7 +335,7 @@ nd6_ns_input(m, off, icmp6len) void nd6_ns_output(ifp, daddr6, taddr6, ln, dad) struct ifnet *ifp; - struct in6_addr *daddr6, *taddr6; + const struct in6_addr *daddr6, *taddr6; struct llinfo_nd6 *ln; /* for source address determination */ int dad; /* duplicated address detection */ { @@ -356,7 +356,7 @@ nd6_ns_output(ifp, daddr6, taddr6, ln, dad) maxlen = sizeof(*ip6) + sizeof(*nd_ns); maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7; if (max_linkhdr + maxlen >= MCLBYTES) { -#ifdef DIAGNOSTIC +#if DIAGNOSTIC printf("nd6_ns_output: max_linkhdr + maxlen >= MCLBYTES " "(%d + %d > %d)\n", max_linkhdr, maxlen, MCLBYTES); #endif @@ -373,6 +373,7 @@ nd6_ns_output(ifp, daddr6, taddr6, ln, dad) } if (m == NULL) return; + m->m_pkthdr.rcvif = NULL; if (daddr6 == NULL || IN6_IS_ADDR_MULTICAST(daddr6)) { m->m_flags |= M_MCAST; @@ -506,7 +507,8 @@ nd6_ns_output(ifp, daddr6, taddr6, ln, dad) #if IPSEC /* Don't lookup socket */ - ipsec_setsocket(m, NULL); + if (ipsec_bypass == 0) + (void)ipsec_setsocket(m, NULL); #endif ip6_output(m, NULL, NULL, dad ? IPV6_DADOUTPUT : 0, &im6o, &outif); if (outif) { @@ -552,9 +554,11 @@ nd6_na_input(m, off, icmp6len) union nd_opts ndopts; if (ip6->ip6_hlim != 255) { - log(LOG_ERR, - "nd6_na_input: invalid hlim %d\n", ip6->ip6_hlim); - goto freeit; + nd6log((LOG_ERR, + "nd6_na_input: invalid hlim (%d) from %s to %s on %s\n", + ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src), + ip6_sprintf(&ip6->ip6_dst), if_name(ifp))); + goto bad; } #ifndef PULLDOWN_TEST @@ -577,22 +581,24 @@ nd6_na_input(m, off, icmp6len) taddr6.s6_addr16[1] = htons(ifp->if_index); if (IN6_IS_ADDR_MULTICAST(&taddr6)) { - log(LOG_ERR, + nd6log((LOG_ERR, "nd6_na_input: invalid target address %s\n", - ip6_sprintf(&taddr6)); - goto freeit; + ip6_sprintf(&taddr6))); + goto bad; } if (IN6_IS_ADDR_MULTICAST(&daddr6)) if (is_solicited) { - log(LOG_ERR, - "nd6_na_input: a solicited adv is multicasted\n"); - goto freeit; + nd6log((LOG_ERR, + "nd6_na_input: a solicited adv is multicasted\n")); + goto bad; } icmp6len -= sizeof(*nd_na); nd6_option_init(nd_na + 1, icmp6len, &ndopts); if (nd6_options(&ndopts) < 0) { - log(LOG_INFO, "nd6_na_input: invalid ND option, ignored\n"); + nd6log((LOG_INFO, + "nd6_na_input: invalid ND option, ignored\n")); + /* nd6_options have incremented stats */ goto freeit; } @@ -627,10 +633,11 @@ nd6_na_input(m, off, icmp6len) } if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { - log(LOG_INFO, + nd6log((LOG_INFO, "nd6_na_input: lladdrlen mismatch for %s " "(if %d, NA packet %d)\n", - ip6_sprintf(&taddr6), ifp->if_addrlen, lladdrlen - 2); + ip6_sprintf(&taddr6), ifp->if_addrlen, lladdrlen - 2)); + goto bad; } /* @@ -657,16 +664,22 @@ nd6_na_input(m, off, icmp6len) bcopy(lladdr, LLADDR(sdl), ifp->if_addrlen); if (is_solicited) { ln->ln_state = ND6_LLINFO_REACHABLE; + ln->ln_byhint = 0; if (ln->ln_expire) -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__APPLE__) - ln->ln_expire = time.tv_sec + -#else ln->ln_expire = time_second + -#endif - nd_ifinfo[rt->rt_ifp->if_index].reachable; - } else + nd_ifinfo[rt->rt_ifp->if_index].reachable; + } else { ln->ln_state = ND6_LLINFO_STALE; - ln->ln_router = is_router; + ln->ln_expire = time_second + nd6_gctimer; + } + if ((ln->ln_router = is_router) != 0) { + /* + * This means a router's state has changed from + * non-reachable to probably reachable, and might + * affect the status of associated prefixes.. + */ + pfxlist_onlink_check(); + } } else { int llchange; @@ -709,8 +722,10 @@ nd6_na_input(m, off, icmp6len) * If state is REACHABLE, make it STALE. * no other updates should be done. */ - if (ln->ln_state == ND6_LLINFO_REACHABLE) + if (ln->ln_state == ND6_LLINFO_REACHABLE) { ln->ln_state = ND6_LLINFO_STALE; + ln->ln_expire = time_second + nd6_gctimer; + } goto freeit; } else if (is_override /* (2a) */ || (!is_override && (lladdr && !llchange)) /* (2b) */ @@ -730,17 +745,16 @@ nd6_na_input(m, off, icmp6len) */ if (is_solicited) { ln->ln_state = ND6_LLINFO_REACHABLE; + ln->ln_byhint = 0; if (ln->ln_expire) { -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__APPLE__) - ln->ln_expire = time.tv_sec + -#else ln->ln_expire = time_second + -#endif - nd_ifinfo[ifp->if_index].reachable; + nd_ifinfo[ifp->if_index].reachable; } } else { - if (lladdr && llchange) + if (lladdr && llchange) { ln->ln_state = ND6_LLINFO_STALE; + ln->ln_expire = time_second + nd6_gctimer; + } } } @@ -755,11 +769,7 @@ nd6_na_input(m, off, icmp6len) int s; in6 = &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr; -#if __NetBSD__ - s = splsoftnet(); -#else s = splnet(); -#endif dr = defrouter_lookup(in6, rt->rt_ifp); if (dr) defrtrlist_del(dr); @@ -780,17 +790,22 @@ nd6_na_input(m, off, icmp6len) rt->rt_flags &= ~RTF_REJECT; ln->ln_asked = 0; if (ln->ln_hold) { -#if OLDIP6OUTPUT - (*ifp->if_output)(ifp, ln->ln_hold, rt_key(rt), rt); -#else - nd6_output(ifp, ln->ln_hold, + /* + * we assume ifp is not a p2p here, so just set the 2nd + * argument as the 1st one. + */ + nd6_output(ifp, ifp, ln->ln_hold, (struct sockaddr_in6 *)rt_key(rt), rt); -#endif ln->ln_hold = 0; } freeit: m_freem(m); + return; + + bad: + icmp6stat.icp6s_badna++; + m_freem(m); } /* @@ -805,7 +820,7 @@ nd6_na_input(m, off, icmp6len) void nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr, sdl0) struct ifnet *ifp; - struct in6_addr *daddr6, *taddr6; + const struct in6_addr *daddr6, *taddr6; u_long flags; int tlladdr; /* 1 if include target link-layer address */ struct sockaddr *sdl0; /* sockaddr_dl (= proxy NA) or NULL */ @@ -824,7 +839,7 @@ nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr, sdl0) maxlen = sizeof(*ip6) + sizeof(*nd_na); maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7; if (max_linkhdr + maxlen >= MCLBYTES) { -#ifdef DIAGNOSTIC +#if DIAGNOSTIC printf("nd6_na_output: max_linkhdr + maxlen >= MCLBYTES " "(%d + %d > %d)\n", max_linkhdr, maxlen, MCLBYTES); #endif @@ -841,6 +856,7 @@ nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr, sdl0) } if (m == NULL) return; + m->m_pkthdr.rcvif = NULL; if (IN6_IS_ADDR_MULTICAST(daddr6)) { m->m_flags |= M_MCAST; @@ -934,7 +950,8 @@ nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr, sdl0) #if IPSEC /* Don't lookup socket */ - ipsec_setsocket(m, NULL); + if (ipsec_bypass == 0) + (void)ipsec_setsocket(m, NULL); #endif ip6_output(m, NULL, NULL, 0, &im6o, &outif); if (outif) { @@ -952,11 +969,14 @@ nd6_ifptomac(ifp) case IFT_ARCNET: case IFT_ETHER: case IFT_FDDI: -#if __NetBSD__ - return LLADDR(ifp->if_sadl); -#else - return ((caddr_t)(ifp + 1)); + case IFT_IEEE1394: +#if IFT_L2VLAN + case IFT_L2VLAN: #endif +#if IFT_IEEE80211 + case IFT_IEEE80211: +#endif + return ((caddr_t)(ifp + 1)); break; default: return NULL; @@ -978,6 +998,7 @@ struct dadq { }; static struct dadq_head dadq; +static int dad_init = 0; static struct dadq * nd6_dad_find(ifa) @@ -992,6 +1013,33 @@ nd6_dad_find(ifa) return NULL; } +#ifdef __APPLE__ +void +nd6_dad_stoptimer(ifa) + struct ifaddr *ifa; +{ + + untimeout((void (*) __P((void *)))nd6_dad_timer_funnel, (void *)ifa); +} +#else +static void +nd6_dad_starttimer(dp, ticks) + struct dadq *dp; + int ticks; +{ + + callout_reset(&dp->dad_timer_ch, ticks, + (void (*) __P((void *)))nd6_dad_timer, (void *)dp->dad_ifa); +} +static void +nd6_dad_stoptimer(dp) + struct dadq *dp; +{ + + callout_stop(&dp->dad_timer_ch); +} +#endif + /* * Start Duplicated Address Detection (DAD) for specified interface address. */ @@ -1002,7 +1050,6 @@ nd6_dad_start(ifa, tick) { struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; struct dadq *dp; - static int dad_init = 0; if (!dad_init) { TAILQ_INIT(&dadq); @@ -1049,12 +1096,13 @@ nd6_dad_start(ifa, tick) return; } bzero(dp, sizeof(*dp)); +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + callout_init(&dp->dad_timer_ch); +#endif TAILQ_INSERT_TAIL(&dadq, (struct dadq *)dp, dad_list); -#if ND6_DEBUG - log(LOG_DEBUG, "%s: starting DAD for %s\n", if_name(ifa->ifa_ifp), - ip6_sprintf(&ia->ia_addr.sin6_addr)); -#endif + nd6log((LOG_DEBUG, "%s: starting DAD for %s\n", if_name(ifa->ifa_ifp), + ip6_sprintf(&ia->ia_addr.sin6_addr))); /* * Send NS packet for DAD, ip6_dad_count times. @@ -1063,7 +1111,7 @@ nd6_dad_start(ifa, tick) * (re)initialization. */ dp->dad_ifa = ifa; - ifa->ifa_refcnt++; /*just for safety*/ + ifaref(ifa); /*just for safety*/ dp->dad_count = ip6_dad_count; dp->dad_ns_icount = dp->dad_na_icount = 0; dp->dad_ns_ocount = dp->dad_ns_tcount = 0; @@ -1090,6 +1138,32 @@ nd6_dad_start(ifa, tick) } } +/* + * terminate DAD unconditionally. used for address removals. + */ +void +nd6_dad_stop(ifa) + struct ifaddr *ifa; +{ + struct dadq *dp; + + if (!dad_init) + return; + dp = nd6_dad_find(ifa); + if (!dp) { + /* DAD wasn't started yet */ + return; + } + + untimeout((void (*) __P((void *)))nd6_dad_timer_funnel, (void *)ifa); + + TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list); + FREE(dp, M_IP6NDP); + dp = NULL; + ifafree(ifa); +} + + static void nd6_dad_timer_funnel(ifa) struct ifaddr *ifa; @@ -1114,11 +1188,7 @@ nd6_dad_timer(ifa) struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; struct dadq *dp; -#if __NetBSD__ - s = splsoftnet(); /*XXX*/ -#else s = splnet(); /*XXX*/ -#endif /* Sanity check */ if (ia == NULL) { @@ -1147,13 +1217,13 @@ nd6_dad_timer(ifa) /* timeouted with IFF_{RUNNING,UP} check */ if (dp->dad_ns_tcount > dad_maxtry) { - log(LOG_ERR, "%s: could not run DAD, driver problem?\n", - if_name(ifa->ifa_ifp)); + nd6log((LOG_INFO, "%s: could not run DAD, driver problem?\n", + if_name(ifa->ifa_ifp))); TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list); - _FREE(dp, M_IP6NDP); + FREE(dp, M_IP6NDP); dp = NULL; - IFAFREE(ifa); + ifafree(ifa); goto done; } @@ -1226,17 +1296,15 @@ nd6_dad_timer(ifa) */ ia->ia6_flags &= ~IN6_IFF_TENTATIVE; -#if ND6_DEBUG - log(LOG_INFO, + nd6log((LOG_DEBUG, "%s: DAD complete for %s - no duplicates found\n", if_name(ifa->ifa_ifp), - ip6_sprintf(&ia->ia_addr.sin6_addr)); -#endif + ip6_sprintf(&ia->ia_addr.sin6_addr))); TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list); - _FREE(dp, M_IP6NDP); + FREE(dp, M_IP6NDP); dp = NULL; - IFAFREE(ifa); + ifafree(ifa); } } @@ -1257,20 +1325,17 @@ nd6_dad_duplicated(ifa) return; } - log(LOG_ERR, "%s: DAD detected duplicate IPv6 address %s: %d NS, " - "%d NA\n", if_name(ifa->ifa_ifp), - ip6_sprintf(&ia->ia_addr.sin6_addr), - dp->dad_ns_icount, dp->dad_na_icount); + log(LOG_ERR, "%s: DAD detected duplicate IPv6 address %s: " + "NS in/out=%d/%d, NA in=%d\n", + if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr), + dp->dad_ns_icount, dp->dad_ns_ocount, dp->dad_na_icount); ia->ia6_flags &= ~IN6_IFF_TENTATIVE; ia->ia6_flags |= IN6_IFF_DUPLICATED; /* We are done with DAD, with duplicated address found. (failure) */ - untimeout((void (*) __P((void *)))nd6_dad_timer_funnel, (void *)ifa -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 - , dp->dad_timer -#endif - ); + untimeout((void (*) __P((void *)))nd6_dad_timer_funnel, (void *)ifa); + log(LOG_ERR, "%s: DAD complete for %s - duplicate found\n", if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr)); @@ -1278,9 +1343,9 @@ nd6_dad_duplicated(ifa) if_name(ifa->ifa_ifp)); TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list); - _FREE(dp, M_IP6NDP); + FREE(dp, M_IP6NDP); dp = NULL; - IFAFREE(ifa); + ifafree(ifa); } static void @@ -1315,7 +1380,7 @@ nd6_dad_ns_input(ifa) { struct in6_ifaddr *ia; struct ifnet *ifp; - struct in6_addr *taddr6; + const struct in6_addr *taddr6; struct dadq *dp; int duplicate; @@ -1328,17 +1393,12 @@ nd6_dad_ns_input(ifa) duplicate = 0; dp = nd6_dad_find(ifa); - /* - * If it is from myself, ignore this. - */ - if (ifp && (ifp->if_flags & IFF_LOOPBACK)) - return; - /* Quickhack - completely ignore DAD NS packets */ if (dad_ignore_ns) { - log(LOG_INFO, "nd6_dad_ns_input: ignoring DAD NS packet for " + nd6log((LOG_INFO, + "nd6_dad_ns_input: ignoring DAD NS packet for " "address %s(%s)\n", ip6_sprintf(taddr6), - if_name(ifa->ifa_ifp)); + if_name(ifa->ifa_ifp))); return; } diff --git a/bsd/netinet6/nd6_rtr.c b/bsd/netinet6/nd6_rtr.c index d2c6746d5..a99c8a5dd 100644 --- a/bsd/netinet6/nd6_rtr.c +++ b/bsd/netinet6/nd6_rtr.c @@ -1,4 +1,5 @@ -/* $KAME: nd6_rtr.c,v 1.30 2000/03/21 11:37:31 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/nd6_rtr.c,v 1.2.2.3 2001/07/03 11:01:54 ume Exp $ */ +/* $KAME: nd6_rtr.c,v 1.111 2001/04/27 01:37:15 jinmei Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -29,6 +30,7 @@ * SUCH DAMAGE. */ + #include #include #include @@ -38,10 +40,8 @@ #include #include #include -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) -#include -#endif #include +#include #include #include @@ -51,56 +51,50 @@ #include #include +#include #include #include #include #include - -#if MIP6 -#include -#endif +#include #include #define SDL(s) ((struct sockaddr_dl *)s) static struct nd_defrouter *defrtrlist_update __P((struct nd_defrouter *)); -static int prelist_add __P((struct nd_prefix *, struct nd_defrouter *)); -/* static struct nd_prefix *prefix_lookup __P((struct nd_prefix *)); XXXYYY */ -static struct in6_ifaddr *in6_ifadd __P((struct ifnet *, struct in6_addr *, - struct in6_addr *, int)); -/*static struct nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *, - struct nd_defrouter *)); XXXYYYY */ +static struct in6_ifaddr *in6_ifadd __P((struct nd_prefix *, + struct in6_addr *)); +static struct nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *, + struct nd_defrouter *)); static void pfxrtr_add __P((struct nd_prefix *, struct nd_defrouter *)); static void pfxrtr_del __P((struct nd_pfxrouter *)); -/*static struct nd_pfxrouter *find_pfxlist_reachable_router __P((struct nd_prefix *)); XXXYYY */ -static void nd6_detach_prefix __P((struct nd_prefix *)); -static void nd6_attach_prefix __P((struct nd_prefix *)); -/* static void defrouter_addifreq __P((struct ifnet *)); XXXYYY */ +static struct nd_pfxrouter *find_pfxlist_reachable_router + __P((struct nd_prefix *)); +static void defrouter_addifreq __P((struct ifnet *)); +static void nd6_rtmsg __P((int, struct rtentry *)); static void in6_init_address_ltimes __P((struct nd_prefix *ndpr, - struct in6_addrlifetime *lt6, - int update_vltime)); + struct in6_addrlifetime *lt6)); static int rt6_deleteroute __P((struct radix_node *, void *)); extern int nd6_recalc_reachtm_interval; -struct ifnet *nd6_defifp; +static struct ifnet *nd6_defifp; int nd6_defifindex; +int ip6_use_tempaddr = 0; -#if MIP6 -void (*mip6_select_defrtr_hook)(void) = NULL; -struct nd_prefix * (*mip6_get_home_prefix_hook)(void) = NULL; -void (*mip6_prelist_update_hook)(struct nd_prefix *pr, - struct nd_defrouter *dr) = NULL; -void (*mip6_probe_pfxrtrs_hook)(void) = NULL; -void (*mip6_store_advint_hook)(struct nd_opt_advint *ai, - struct nd_defrouter *dr) = NULL; -int (*mip6_get_md_state_hook)(void) = 0; -void (*mip6_minus_a_case_hook)(struct nd_prefix *) = NULL; -#endif /* MIP6 */ +int ip6_desync_factor; +u_int32_t ip6_temp_preferred_lifetime = DEF_TEMP_PREFERRED_LIFETIME; +u_int32_t ip6_temp_valid_lifetime = DEF_TEMP_VALID_LIFETIME; +/* + * shorter lifetimes for debugging purposes. +int ip6_temp_preferred_lifetime = 800; +static int ip6_temp_valid_lifetime = 1800; +*/ +int ip6_temp_regen_advance = TEMPADDR_REGEN_ADVANCE; /* * Receive Router Solicitation Message - just for routers. @@ -137,9 +131,11 @@ nd6_rs_input(m, off, icmp6len) /* Sanity checks */ if (ip6->ip6_hlim != 255) { - log(LOG_ERR, - "nd6_rs_input: invalid hlim %d\n", ip6->ip6_hlim); - goto freeit; + nd6log((LOG_ERR, + "nd6_rs_input: invalid hlim (%d) from %s to %s on %s\n", + ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src), + ip6_sprintf(&ip6->ip6_dst), if_name(ifp))); + goto bad; } /* @@ -163,7 +159,9 @@ nd6_rs_input(m, off, icmp6len) icmp6len -= sizeof(*nd_rs); nd6_option_init(nd_rs + 1, icmp6len, &ndopts); if (nd6_options(&ndopts) < 0) { - log(LOG_INFO, "nd6_rs_input: invalid ND option, ignored\n"); + nd6log((LOG_INFO, + "nd6_rs_input: invalid ND option, ignored\n")); + /* nd6_options have incremented stats */ goto freeit; } @@ -173,16 +171,22 @@ nd6_rs_input(m, off, icmp6len) } if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { - log(LOG_INFO, + nd6log((LOG_INFO, "nd6_rs_input: lladdrlen mismatch for %s " "(if %d, RS packet %d)\n", - ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2); + ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2)); + goto bad; } nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0); freeit: m_freem(m); + return; + + bad: + icmp6stat.icp6s_badrs++; + m_freem(m); } /* @@ -215,16 +219,18 @@ nd6_ra_input(m, off, icmp6len) goto freeit; if (ip6->ip6_hlim != 255) { - log(LOG_ERR, - "nd6_ra_input: invalid hlim %d\n", ip6->ip6_hlim); - goto freeit; + nd6log((LOG_ERR, + "nd6_ra_input: invalid hlim (%d) from %s to %s on %s\n", + ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src), + ip6_sprintf(&ip6->ip6_dst), if_name(ifp))); + goto bad; } if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) { - log(LOG_ERR, + nd6log((LOG_ERR, "nd6_ra_input: src %s is not link-local\n", - ip6_sprintf(&saddr6)); - goto freeit; + ip6_sprintf(&saddr6))); + goto bad; } #ifndef PULLDOWN_TEST @@ -241,16 +247,15 @@ nd6_ra_input(m, off, icmp6len) icmp6len -= sizeof(*nd_ra); nd6_option_init(nd_ra + 1, icmp6len, &ndopts); if (nd6_options(&ndopts) < 0) { - log(LOG_INFO, "nd6_ra_input: invalid ND option, ignored\n"); + nd6log((LOG_INFO, + "nd6_ra_input: invalid ND option, ignored\n")); + /* nd6_options have incremented stats */ goto freeit; } { struct nd_defrouter dr0; u_int32_t advreachable = nd_ra->nd_ra_reachable; -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined (__APPLE__) - long time_second = time.tv_sec; -#endif dr0.rtaddr = saddr6; dr0.flags = nd_ra->nd_ra_flags_reserved; @@ -282,7 +287,7 @@ nd6_ra_input(m, off, icmp6len) */ if (ndopts.nd_opts_pi) { struct nd_opt_hdr *pt; - struct nd_opt_prefix_info *pi; + struct nd_opt_prefix_info *pi = NULL; struct nd_prefix pr; for (pt = (struct nd_opt_hdr *)ndopts.nd_opts_pi; @@ -294,34 +299,38 @@ nd6_ra_input(m, off, icmp6len) pi = (struct nd_opt_prefix_info *)pt; if (pi->nd_opt_pi_len != 4) { - log(LOG_INFO, "nd6_ra_input: invalid option " - "len %d for prefix information option, " - "ignored\n", pi->nd_opt_pi_len); + nd6log((LOG_INFO, + "nd6_ra_input: invalid option " + "len %d for prefix information option, " + "ignored\n", pi->nd_opt_pi_len)); continue; } if (128 < pi->nd_opt_pi_prefix_len) { - log(LOG_INFO, "nd6_ra_input: invalid prefix " - "len %d for prefix information option, " - "ignored\n", pi->nd_opt_pi_prefix_len); + nd6log((LOG_INFO, + "nd6_ra_input: invalid prefix " + "len %d for prefix information option, " + "ignored\n", pi->nd_opt_pi_prefix_len)); continue; } if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix) || IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) { - log(LOG_INFO, "nd6_ra_input: invalid prefix " - "%s, ignored\n", - ip6_sprintf(&pi->nd_opt_pi_prefix)); + nd6log((LOG_INFO, + "nd6_ra_input: invalid prefix " + "%s, ignored\n", + ip6_sprintf(&pi->nd_opt_pi_prefix))); continue; } /* aggregatable unicast address, rfc2374 */ if ((pi->nd_opt_pi_prefix.s6_addr8[0] & 0xe0) == 0x20 && pi->nd_opt_pi_prefix_len != 64) { - log(LOG_INFO, "nd6_ra_input: invalid prefixlen " - "%d for rfc2374 prefix %s, ignored\n", - pi->nd_opt_pi_prefix_len, - ip6_sprintf(&pi->nd_opt_pi_prefix)); + nd6log((LOG_INFO, + "nd6_ra_input: invalid prefixlen " + "%d for rfc2374 prefix %s, ignored\n", + pi->nd_opt_pi_prefix_len, + ip6_sprintf(&pi->nd_opt_pi_prefix))); continue; } @@ -355,9 +364,9 @@ nd6_ra_input(m, off, icmp6len) /* lower bound */ if (mtu < IPV6_MMTU) { - log(LOG_INFO, "nd6_ra_input: bogus mtu option " + nd6log((LOG_INFO, "nd6_ra_input: bogus mtu option " "mtu=%d sent from %s, ignoring\n", - mtu, ip6_sprintf(&ip6->ip6_src)); + mtu, ip6_sprintf(&ip6->ip6_src))); goto skip; } @@ -370,17 +379,17 @@ nd6_ra_input(m, off, icmp6len) if (change) /* in6_maxmtu may change */ in6_setmaxmtu(); } else { - log(LOG_INFO, "nd6_ra_input: bogus mtu " + nd6log((LOG_INFO, "nd6_ra_input: bogus mtu " "mtu=%d sent from %s; " "exceeds maxmtu %d, ignoring\n", mtu, ip6_sprintf(&ip6->ip6_src), - ndi->maxmtu); + ndi->maxmtu)); } } else { - log(LOG_INFO, "nd6_ra_input: mtu option " + nd6log((LOG_INFO, "nd6_ra_input: mtu option " "mtu=%d sent from %s; maxmtu unknown, " "ignoring\n", - mtu, ip6_sprintf(&ip6->ip6_src)); + mtu, ip6_sprintf(&ip6->ip6_src))); } } @@ -399,10 +408,11 @@ nd6_ra_input(m, off, icmp6len) } if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { - log(LOG_INFO, + nd6log((LOG_INFO, "nd6_ra_input: lladdrlen mismatch for %s " "(if %d, RA packet %d)\n", - ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2); + ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2)); + goto bad; } nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_ADVERT, 0); @@ -415,25 +425,44 @@ nd6_ra_input(m, off, icmp6len) pfxlist_onlink_check(); } -#if MIP6 - if (mip6_store_advint_hook) { - if (ndopts.nd_opts_adv) - (*mip6_store_advint_hook)(ndopts.nd_opts_adv, dr); - } -#endif + freeit: + m_freem(m); + return; -freeit: + bad: + icmp6stat.icp6s_badra++; m_freem(m); } /* * default router list proccessing sub routines */ + +/* tell the change to user processes watching the routing socket. */ +static void +nd6_rtmsg(cmd, rt) + int cmd; + struct rtentry *rt; +{ + struct rt_addrinfo info; + + bzero((caddr_t)&info, sizeof(info)); + info.rti_info[RTAX_DST] = rt_key(rt); + info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; + info.rti_info[RTAX_NETMASK] = rt_mask(rt); + info.rti_info[RTAX_IFP] = + (struct sockaddr *)TAILQ_FIRST(&rt->rt_ifp->if_addrlist); + info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; + + rt_missmsg(cmd, &info, rt->rt_flags, 0); +} + void defrouter_addreq(new) struct nd_defrouter *new; { struct sockaddr_in6 def, mask, gate; + struct rtentry *newrt = NULL; int s; Bzero(&def, sizeof(def)); @@ -445,14 +474,14 @@ defrouter_addreq(new) def.sin6_family = mask.sin6_family = gate.sin6_family = AF_INET6; gate.sin6_addr = new->rtaddr; -#ifdef __NetBSD__ - s = splsoftnet(); -#else s = splnet(); -#endif (void)rtrequest(RTM_ADD, (struct sockaddr *)&def, (struct sockaddr *)&gate, (struct sockaddr *)&mask, - RTF_GATEWAY, NULL); + RTF_GATEWAY, &newrt); + if (newrt) { + nd6_rtmsg(RTM_ADD, newrt); /* tell user process */ + rtunref(newrt); + } splx(s); return; } @@ -464,6 +493,7 @@ defrouter_addifreq(ifp) { struct sockaddr_in6 def, mask; struct ifaddr *ifa; + struct rtentry *newrt = NULL; int error, flags; bzero(&def, sizeof(def)); @@ -477,23 +507,30 @@ defrouter_addifreq(ifp) * XXX: An IPv6 address are required to be assigned on the interface. */ if ((ifa = ifaof_ifpforaddr((struct sockaddr *)&def, ifp)) == NULL) { - log(LOG_ERR, /* better error? */ + nd6log((LOG_ERR, /* better error? */ "defrouter_addifreq: failed to find an ifaddr " "to install a route to interface %s\n", - if_name(ifp)); + if_name(ifp))); return; } flags = ifa->ifa_flags; - if ((ifp->if_flags & IFF_POINTOPOINT) != 0) - flags &= ~RTF_CLONING; - if ((error = rtrequest(RTM_ADD, (struct sockaddr *)&def, - ifa->ifa_addr, (struct sockaddr *)&mask, - flags, NULL)) != 0) { - log(LOG_ERR, + error = rtrequest(RTM_ADD, (struct sockaddr *)&def, ifa->ifa_addr, + (struct sockaddr *)&mask, flags, &newrt); + if (error != 0) { + nd6log((LOG_ERR, "defrouter_addifreq: failed to install a route to " "interface %s (errno = %d)\n", - if_name(ifp), error); + if_name(ifp), error)); + + if (newrt) /* maybe unnecessary, but do it for safety */ + rtunref(newrt); + } else { + if (newrt) { + nd6_rtmsg(RTM_ADD, newrt); + rtunref(newrt); + } + in6_post_msg(ifp, KEV_INET6_DEFROUTER, &def); } } @@ -519,6 +556,7 @@ defrouter_delreq(dr, dofree) int dofree; { struct sockaddr_in6 def, mask, gate; + struct rtentry *oldrt = NULL; Bzero(&def, sizeof(def)); Bzero(&mask, sizeof(mask)); @@ -532,10 +570,21 @@ defrouter_delreq(dr, dofree) rtrequest(RTM_DELETE, (struct sockaddr *)&def, (struct sockaddr *)&gate, (struct sockaddr *)&mask, - RTF_GATEWAY, (struct rtentry **)0); + RTF_GATEWAY, &oldrt); + if (oldrt) { + nd6_rtmsg(RTM_DELETE, oldrt); + if (oldrt->rt_refcnt <= 0) { + /* + * XXX: borrowed from the RTM_DELETE case of + * rtrequest(). + */ + rtref(oldrt); + rtfree(oldrt); + } + } if (dofree) /* XXX: necessary? */ - _FREE(dr, M_IP6NDP); + FREE(dr, M_IP6NDP); } void @@ -577,7 +626,7 @@ defrtrlist_del(dr) if (deldr) defrouter_select(); - _FREE(dr, M_IP6NDP); + FREE(dr, M_IP6NDP); } /* @@ -593,25 +642,11 @@ defrtrlist_del(dr) void defrouter_select() { -#ifdef __NetBSD__ - int s = splsoftnet(); -#else int s = splnet(); -#endif struct nd_defrouter *dr, anydr; struct rtentry *rt = NULL; struct llinfo_nd6 *ln = NULL; -#if MIP6 - /* Mobile IPv6 alternative routine */ - if (mip6_select_defrtr_hook) { - (*mip6_select_defrtr_hook)(); /* XXXYYY Temporary? */ - splx(s); - return; - } - /* End of Mobile IPv6 */ -#endif /* MIP6 */ - /* * Search for a (probably) reachable router from the list. */ @@ -658,15 +693,17 @@ defrouter_select() /* * Install a route to the default interface * as default route. + * XXX: we enable this for host only, because + * this may override a default route installed + * a user process (e.g. routing daemon) in a + * router case. */ defrouter_addifreq(nd6_defifp); - } -#if ND6_DEBUG - else /* noisy log? */ - log(LOG_INFO, "defrouter_select: " + } else { + nd6log((LOG_INFO, "defrouter_select: " "there's no default router and no default" - " interface\n"); -#endif + " interface\n")); + } } } @@ -679,11 +716,7 @@ defrtrlist_update(new) struct nd_defrouter *new; { struct nd_defrouter *dr, *n; -#ifdef __NetBSD__ - int s = splsoftnet(); -#else int s = splnet(); -#endif if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) { /* entry exists */ @@ -727,7 +760,7 @@ defrtrlist_update(new) return(n); } -struct nd_pfxrouter * +static struct nd_pfxrouter * pfxrtr_lookup(pr, dr) struct nd_prefix *pr; struct nd_defrouter *dr; @@ -765,11 +798,11 @@ pfxrtr_del(pfr) struct nd_pfxrouter *pfr; { LIST_REMOVE(pfr, pfr_entry); - _FREE(pfr, M_IP6NDP); + FREE(pfr, M_IP6NDP); } struct nd_prefix * -prefix_lookup(pr) +nd6_prefix_lookup(pr) struct nd_prefix *pr; { struct nd_prefix *search; @@ -788,12 +821,12 @@ prefix_lookup(pr) return(search); } -static int -prelist_add(pr, dr) - struct nd_prefix *pr; +int +nd6_prelist_add(pr, dr, newp) + struct nd_prefix *pr, **newp; struct nd_defrouter *dr; { - struct nd_prefix *new; + struct nd_prefix *new = NULL; int i, s; new = (struct nd_prefix *)_MALLOC(sizeof(*new), M_IP6NDP, M_NOWAIT); @@ -801,9 +834,10 @@ prelist_add(pr, dr) return ENOMEM; bzero(new, sizeof(*new)); *new = *pr; + if (newp != NULL) + *newp = new; /* initilization */ - new->ndpr_statef_onlink = pr->ndpr_statef_onlink; LIST_INIT(&new->ndpr_advrtrs); in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen); /* make prefix in the canonical form */ @@ -811,33 +845,26 @@ prelist_add(pr, dr) new->ndpr_prefix.sin6_addr.s6_addr32[i] &= new->ndpr_mask.s6_addr32[i]; - /* xxx ND_OPT_PI_FLAG_ONLINK processing */ - -#ifdef __NetBSD__ - s = splsoftnet(); -#else s = splnet(); -#endif /* link ndpr_entry to nd_prefix list */ LIST_INSERT_HEAD(&nd_prefix, new, ndpr_entry); splx(s); + /* ND_OPT_PI_FLAG_ONLINK processing */ + if (new->ndpr_raf_onlink) { + int e; + + if ((e = nd6_prefix_onlink(new)) != 0) { + nd6log((LOG_ERR, "nd6_prelist_add: failed to make " + "the prefix %s/%d on-link on %s (errno=%d)\n", + ip6_sprintf(&pr->ndpr_prefix.sin6_addr), + pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); + /* proceed anyway. XXX: is it correct? */ + } + } + if (dr) { pfxrtr_add(new, dr); -#if MIP6 - if (mip6_get_md_state_hook) { - /* - * If we are in UNDEFINED state and a router appears, - * select that router and change state. - * This case takes care of transitions from UNDEFINED - * to FOREIGN when the prefix is not known from before. - */ - if ((*mip6_get_md_state_hook)() == MIP6_MD_UNDEFINED) { - if (mip6_select_defrtr_hook) - (*mip6_select_defrtr_hook)(); - } - } -#endif /* MIP6 */ } return 0; @@ -848,51 +875,64 @@ prelist_remove(pr) struct nd_prefix *pr; { struct nd_pfxrouter *pfr, *next; - int s; + int e, s; -#ifdef __NetBSD__ - s = splsoftnet(); -#else - s = splnet(); + /* make sure to invalidate the prefix until it is really freed. */ + pr->ndpr_vltime = 0; + pr->ndpr_pltime = 0; +#if 0 + /* + * Though these flags are now meaningless, we'd rather keep the value + * not to confuse users when executing "ndp -p". + */ + pr->ndpr_raf_onlink = 0; + pr->ndpr_raf_auto = 0; #endif + if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0 && + (e = nd6_prefix_offlink(pr)) != 0) { + nd6log((LOG_ERR, "prelist_remove: failed to make %s/%d offlink " + "on %s, errno=%d\n", + ip6_sprintf(&pr->ndpr_prefix.sin6_addr), + pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); + /* what should we do? */ + } + + if (pr->ndpr_refcnt > 0) + return; /* notice here? */ + + s = splnet(); + /* unlink ndpr_entry from nd_prefix list */ LIST_REMOVE(pr, ndpr_entry); - splx(s); /* free list of routers that adversed the prefix */ for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = next) { next = pfr->pfr_next; - _FREE(pfr, M_IP6NDP); + FREE(pfr, M_IP6NDP); } - _FREE(pr, M_IP6NDP); + splx(s); + + FREE(pr, M_IP6NDP); pfxlist_onlink_check(); } -/* - * NOTE: We set address lifetime to keep - * address lifetime <= prefix lifetime - * invariant. This is to simplify on-link determination code. - * If onlink determination is udated, this routine may have to be updated too. - */ int prelist_update(new, dr, m) struct nd_prefix *new; struct nd_defrouter *dr; /* may be NULL */ struct mbuf *m; { - struct in6_ifaddr *ia6 = NULL; + struct in6_ifaddr *ia6 = NULL, *ia6_match = NULL; + struct ifaddr *ifa; + struct ifnet *ifp = new->ndpr_ifp; struct nd_prefix *pr; -#ifdef __NetBSD__ - int s = splsoftnet(); -#else int s = splnet(); -#endif int error = 0; + int newprefix = 0; int auth; - struct in6_addrlifetime *lt6; - u_char onlink; /* Mobile IPv6 */ + struct in6_addrlifetime lt6_tmp; auth = 0; if (m) { @@ -906,220 +946,259 @@ prelist_update(new, dr, m) #endif } - if ((pr = prefix_lookup(new)) != NULL) { - if (pr->ndpr_ifp != new->ndpr_ifp) { - error = EADDRNOTAVAIL; - goto end; + + if ((pr = nd6_prefix_lookup(new)) != NULL) { + /* + * nd6_prefix_lookup() ensures that pr and new have the same + * prefix on a same interface. + */ + + /* + * Update prefix information. Note that the on-link (L) bit + * and the autonomous (A) bit should NOT be changed from 1 + * to 0. + */ + if (new->ndpr_raf_onlink == 1) + pr->ndpr_raf_onlink = 1; + if (new->ndpr_raf_auto == 1) + pr->ndpr_raf_auto = 1; + if (new->ndpr_raf_onlink) { + pr->ndpr_vltime = new->ndpr_vltime; + pr->ndpr_pltime = new->ndpr_pltime; + pr->ndpr_preferred = new->ndpr_preferred; + pr->ndpr_expire = new->ndpr_expire; } -#if MIP6 - if (mip6_get_home_prefix_hook) { - /* - * The home prefix should be kept away from updates. - * XXXYYY Tunneled RA? New Home Prefix? Unless - * configured, the code below will be executed. - */ - if (pr == (*mip6_get_home_prefix_hook)()) - goto noautoconf1; + if (new->ndpr_raf_onlink && + (pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { + int e; + + if ((e = nd6_prefix_onlink(pr)) != 0) { + nd6log((LOG_ERR, + "prelist_update: failed to make " + "the prefix %s/%d on-link on %s " + "(errno=%d)\n", + ip6_sprintf(&pr->ndpr_prefix.sin6_addr), + pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); + /* proceed anyway. XXX: is it correct? */ + } } -#endif /* MIP6 */ - /* update prefix information */ - pr->ndpr_flags = new->ndpr_flags; - pr->ndpr_vltime = new->ndpr_vltime; - pr->ndpr_pltime = new->ndpr_pltime; - pr->ndpr_preferred = new->ndpr_preferred; - pr->ndpr_expire = new->ndpr_expire; + if (dr && pfxrtr_lookup(pr, dr) == NULL) + pfxrtr_add(pr, dr); + } else { + struct nd_prefix *newpr = NULL; + + newprefix = 1; + + if (new->ndpr_vltime == 0) + goto end; + if (new->ndpr_raf_onlink == 0 && new->ndpr_raf_auto == 0) + goto end; + + bzero(&new->ndpr_addr, sizeof(struct in6_addr)); + + error = nd6_prelist_add(new, dr, &newpr); + if (error != 0 || newpr == NULL) { + nd6log((LOG_NOTICE, "prelist_update: " + "nd6_prelist_add failed for %s/%d on %s " + "errno=%d, returnpr=%p\n", + ip6_sprintf(&new->ndpr_prefix.sin6_addr), + new->ndpr_plen, if_name(new->ndpr_ifp), + error, newpr)); + goto end; /* we should just give up in this case. */ + } /* - * RFC 2462 5.5.3 (d) or (e) - * We got a prefix which we have seen in the past. + * XXX: from the ND point of view, we can ignore a prefix + * with the on-link bit being zero. However, we need a + * prefix structure for references from autoconfigured + * addresses. Thus, we explicitly make suret that the prefix + * itself expires now. */ - if (!new->ndpr_raf_auto) - goto noautoconf1; + if (newpr->ndpr_raf_onlink == 0) { + newpr->ndpr_vltime = 0; + newpr->ndpr_pltime = 0; + in6_init_prefix_ltimes(newpr); + } - if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) - ia6 = NULL; - else - ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr); + pr = newpr; + } - if (ia6 == NULL) { - /* - * Special case: - * (1) We have seen the prefix advertised before, but - * we have never performed autoconfig for this prefix. - * This is because Autonomous bit was 0 previously, or - * autoconfig failed due to some other reasons. - * (2) We have seen the prefix advertised before and - * we have performed autoconfig in the past, but - * we seem to have no interface address right now. - * This is because the interface address have expired. - * - * This prefix is fresh, with respect to autoconfig - * process. - * - * Add an address based on RFC 2462 5.5.3 (d). - */ - ia6 = in6_ifadd(pr->ndpr_ifp, - &pr->ndpr_prefix.sin6_addr, &pr->ndpr_addr, - new->ndpr_plen); - if (!ia6) { - error = EADDRNOTAVAIL; - log(LOG_ERR, "prelist_update: failed to add a " - "new address\n"); - goto noautoconf1; - } + /* + * Address autoconfiguration based on Section 5.5.3 of RFC 2462. + * Note that pr must be non NULL at this point. + */ - lt6 = &ia6->ia6_lifetime; + /* 5.5.3 (a). Ignore the prefix without the A bit set. */ + if (!new->ndpr_raf_auto) + goto afteraddrconf; - /* address lifetime <= prefix lifetime */ - lt6->ia6t_vltime = new->ndpr_vltime; - lt6->ia6t_pltime = new->ndpr_pltime; - in6_init_address_ltimes(new, lt6, 1); - } else { -#define TWOHOUR (120*60) - /* - * We have seen the prefix before, and we have added - * interface address in the past. We still have - * the interface address assigned. - * - * update address lifetime based on RFC 2462 - * 5.5.3 (e). - */ - int update = 0; - - lt6 = &ia6->ia6_lifetime; - -#if 0 /* RFC 2462 5.5.3 (e) */ - lt6->ia6t_pltime = new->ndpr_pltime; - if (TWOHOUR < new->ndpr_vltime - || lt6pr->nd < new->ndpr_vltime) { - lt6->ia6t_vltime = new->ndpr_vltime; - update++; - } else if (auth - && lt6->ia6t_vltime <= TWOHOUR0 - && new->ndpr_vltime <= lt6->ia6t_vltime) { - lt6->ia6t_vltime = new->ndpr_vltime; - update++; - } else { - lt6->ia6t_vltime = TWOHOUR; - update++; - } + /* + * 5.5.3 (b). the link-local prefix should have been ignored in + * nd6_ra_input. + */ - /* 2 hour rule is not imposed for pref lifetime */ - new->ndpr_apltime = new->ndpr_pltime; - lt6->ia6t_pltime = new->ndpr_pltime; -#else /* update from Jim Bound, (ipng 6712) */ - if (TWOHOUR < new->ndpr_vltime - || lt6->ia6t_vltime < new->ndpr_vltime) { - lt6->ia6t_vltime = new->ndpr_vltime; - update++; - } else if (auth) { - lt6->ia6t_vltime = new->ndpr_vltime; - update++; - } + /* + * 5.5.3 (c). Consistency check on lifetimes: pltime <= vltime. + * This should have been done in nd6_ra_input. + */ - /* jim bound rule is not imposed for pref lifetime */ - lt6->ia6t_pltime = new->ndpr_pltime; -#endif - in6_init_address_ltimes(new, lt6, update); - } + /* + * 5.5.3 (d). If the prefix advertised does not match the prefix of an + * address already in the list, and the Valid Lifetime is not 0, + * form an address. Note that even a manually configured address + * should reject autoconfiguration of a new address. + */ + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) + { + struct in6_ifaddr *ifa6; + int ifa_plen; + u_int32_t storedlifetime; - noautoconf1: + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; -#if 0 - /* address lifetime expire processing, RFC 2462 5.5.4. */ - if (pr->ndpr_preferred && pr->ndpr_preferred < time_second) { - struct in6_ifaddr *ia6; + ifa6 = (struct in6_ifaddr *)ifa; - ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr); - if (ia6) - ia6->ia6_flags &= ~IN6_IFF_DEPRECATED; - } -#endif + /* + * Spec is not clear here, but I believe we should concentrate + * on unicast (i.e. not anycast) addresses. + * XXX: other ia6_flags? detached or duplicated? + */ + if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0) + continue; + + ifa_plen = in6_mask2len(&ifa6->ia_prefixmask.sin6_addr, NULL); + if (ifa_plen != new->ndpr_plen || + !in6_are_prefix_equal(&ifa6->ia_addr.sin6_addr, + &new->ndpr_prefix.sin6_addr, + ifa_plen)) + continue; - onlink = pr->ndpr_statef_onlink; /* Mobile IPv6 */ + if (ia6_match == NULL) /* remember the first one */ + ia6_match = ifa6; - if (dr && pfxrtr_lookup(pr, dr) == NULL) - pfxrtr_add(pr, dr); + if ((ifa6->ia6_flags & IN6_IFF_AUTOCONF) == 0) + continue; -#if MIP6 - if (mip6_prelist_update_hook) { - /* - * Check for home prefix. It can't be a fresh prefix - * (since it's static), so check here. - */ - (*mip6_prelist_update_hook)(pr, dr); - } + /* + * An already autoconfigured address matched. Now that we + * are sure there is at least one matched address, we can + * proceed to 5.5.3. (e): update the lifetimes according to the + * "two hours" rule and the privacy extension. + */ +#define TWOHOUR (120*60) + lt6_tmp = ifa6->ia6_lifetime; + + storedlifetime = IFA6_IS_INVALID(ifa6) ? 0 : + (lt6_tmp.ia6t_expire - time_second); - if (mip6_probe_pfxrtrs_hook) { + if (TWOHOUR < new->ndpr_vltime || + storedlifetime < new->ndpr_vltime) { + lt6_tmp.ia6t_vltime = new->ndpr_vltime; + } else if (storedlifetime <= TWOHOUR +#if 0 + /* + * This condition is logically redundant, so we just + * omit it. + * See IPng 6712, 6717, and 6721. + */ + && new->ndpr_vltime <= storedlifetime +#endif + ) { + if (auth) { + lt6_tmp.ia6t_vltime = new->ndpr_vltime; + } + } else { /* - * If this prefix previously was detached, maybe we - * have moved. + * new->ndpr_vltime <= TWOHOUR && + * TWOHOUR < storedlifetime */ - if (!onlink) - (*mip6_probe_pfxrtrs_hook)(); + lt6_tmp.ia6t_vltime = TWOHOUR; } -#endif /* MIP6 */ - } else { - int error_tmp; + /* The 2 hour rule is not imposed for preferred lifetime. */ + lt6_tmp.ia6t_pltime = new->ndpr_pltime; - if (new->ndpr_vltime == 0) goto end; - - bzero(&new->ndpr_addr, sizeof(struct in6_addr)); + in6_init_address_ltimes(pr, <6_tmp); /* - * RFC 2462 5.5.3 (d) - * We got a fresh prefix. Perform some sanity checks - * and add an interface address by appending interface ID - * to the advertised prefix. + * When adjusting the lifetimes of an existing temporary + * address, only lower the lifetimes. + * RFC 3041 3.3. (1). + * XXX: how should we modify ia6t_[pv]ltime? */ - if (!new->ndpr_raf_auto) - goto noautoconf2; - - ia6 = in6_ifadd(new->ndpr_ifp, &new->ndpr_prefix.sin6_addr, - &new->ndpr_addr, new->ndpr_plen); - if (!ia6) { - error = EADDRNOTAVAIL; - log(LOG_ERR, "prelist_update: " - "failed to add a new address\n"); - goto noautoconf2; + if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0) { + if (lt6_tmp.ia6t_expire == 0 || /* no expire */ + lt6_tmp.ia6t_expire > + ifa6->ia6_lifetime.ia6t_expire) { + lt6_tmp.ia6t_expire = + ifa6->ia6_lifetime.ia6t_expire; + } + if (lt6_tmp.ia6t_preferred == 0 || /* no expire */ + lt6_tmp.ia6t_preferred > + ifa6->ia6_lifetime.ia6t_preferred) { + lt6_tmp.ia6t_preferred = + ifa6->ia6_lifetime.ia6t_preferred; + } } - /* set onlink bit if an interface route is configured */ - new->ndpr_statef_onlink = (ia6->ia_flags & IFA_ROUTE) ? 1 : 0; - - lt6 = &ia6->ia6_lifetime; - /* address lifetime <= prefix lifetime */ - lt6->ia6t_vltime = new->ndpr_vltime; - lt6->ia6t_pltime = new->ndpr_pltime; - in6_init_address_ltimes(new, lt6, 1); + ifa6->ia6_lifetime = lt6_tmp; + } + if (ia6_match == NULL && new->ndpr_vltime) { + /* + * No address matched and the valid lifetime is non-zero. + * Create a new address. + */ + if ((ia6 = in6_ifadd(new, NULL)) != NULL) { + /* + * note that we should use pr (not new) for reference. + */ + pr->ndpr_refcnt++; + ia6->ia6_ndpr = pr; - noautoconf2: - error_tmp = prelist_add(new, dr); - error = error_tmp ? error_tmp : error; +#if 0 + /* XXXYYY Don't do this, according to Jinmei. */ + pr->ndpr_addr = new->ndpr_addr; +#endif -#if MIP6 - if (mip6_probe_pfxrtrs_hook) { - /* This is a new prefix, maybe we have moved. */ - (*mip6_probe_pfxrtrs_hook)(); - } + /* + * RFC 3041 3.3 (2). + * When a new public address is created as described + * in RFC2462, also create a new temporary address. + * + * RFC 3041 3.5. + * When an interface connects to a new link, a new + * randomized interface identifier should be generated + * immediately together with a new set of temporary + * addresses. Thus, we specifiy 1 as the 2nd arg of + * in6_tmpifadd(). + */ + if (ip6_use_tempaddr) { + int e; + if ((e = in6_tmpifadd(ia6, 1)) != 0) { + nd6log((LOG_NOTICE, "prelist_update: " + "failed to create a temporary " + "address, errno=%d\n", + e)); + } + } - if (mip6_minus_a_case_hook) { /* - * If we are still looking for an autoconfigured home - * address when we are in "minus a" case, here's a new - * prefix and hopefully we can use the address derived - *from that. + * A newly added address might affect the status + * of other addresses, so we check and update it. + * XXX: what if address duplication happens? */ - if (ia6) - (*mip6_minus_a_case_hook)(new); + pfxlist_onlink_check(); + } else { + /* just set an error. do not bark here. */ + error = EADDRNOTAVAIL; /* XXX: might be unused. */ } -#endif /* MIP6 */ - } + afteraddrconf: + end: splx(s); return error; @@ -1130,7 +1209,7 @@ prelist_update(new, dr, m) * detect if a given prefix has a (probably) reachable advertising router. * XXX: lengthy function name... */ -struct nd_pfxrouter * +static struct nd_pfxrouter * find_pfxlist_reachable_router(pr) struct nd_prefix *pr; { @@ -1153,14 +1232,14 @@ find_pfxlist_reachable_router(pr) /* * Check if each prefix in the prefix list has at least one available router - * that advertised the prefix (A router is "available" if its neighbor cache - * entry has reachable or probably reachable). + * that advertised the prefix (a router is "available" if its neighbor cache + * entry is reachable or probably reachable). * If the check fails, the prefix may be off-link, because, for example, * we have moved from the network but the lifetime of the prefix has not - * been expired yet. So we should not use the prefix if there is another - * prefix that has an available router. - * But if there is no prefix that has an available router, we still regards - * all the prefixes as on-link. This is because we can't tell if all the + * expired yet. So we should not use the prefix if there is another prefix + * that has an available router. + * But, if there is no prefix that has an available router, we still regards + * all the prefixes as on-link. This is because we can't tell if all the * routers are simply dead or if we really moved from the network and there * is no router around us. */ @@ -1168,55 +1247,275 @@ void pfxlist_onlink_check() { struct nd_prefix *pr; + struct in6_ifaddr *ifa; /* * Check if there is a prefix that has a reachable advertising * router. */ for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { - if (find_pfxlist_reachable_router(pr)) + if (pr->ndpr_raf_onlink && find_pfxlist_reachable_router(pr)) break; } if (pr) { /* * There is at least one prefix that has a reachable router. - * First, detach prefixes which has no reachable advertising - * router and then attach other prefixes. - * The order is important since an attached prefix and a - * detached prefix may have a same interface route. + * Detach prefixes which have no reachable advertising + * router, and attach other prefixes. */ for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { - if (find_pfxlist_reachable_router(pr) == NULL && - pr->ndpr_statef_onlink) { - pr->ndpr_statef_onlink = 0; - nd6_detach_prefix(pr); - } + /* XXX: a link-local prefix should never be detached */ + if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) + continue; + + /* + * we aren't interested in prefixes without the L bit + * set. + */ + if (pr->ndpr_raf_onlink == 0) + continue; + + if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && + find_pfxlist_reachable_router(pr) == NULL) + pr->ndpr_stateflags |= NDPRF_DETACHED; + if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 && + find_pfxlist_reachable_router(pr) != 0) + pr->ndpr_stateflags &= ~NDPRF_DETACHED; } + } else { + /* there is no prefix that has a reachable router */ for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { - if (find_pfxlist_reachable_router(pr) && - pr->ndpr_statef_onlink == 0) - nd6_attach_prefix(pr); + if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) + continue; + + if (pr->ndpr_raf_onlink == 0) + continue; + + if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0) + pr->ndpr_stateflags &= ~NDPRF_DETACHED; + } + } + + /* + * Remove each interface route associated with a (just) detached + * prefix, and reinstall the interface route for a (just) attached + * prefix. Note that all attempt of reinstallation does not + * necessarily success, when a same prefix is shared among multiple + * interfaces. Such cases will be handled in nd6_prefix_onlink, + * so we don't have to care about them. + */ + for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { + int e; + + if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) + continue; + + if (pr->ndpr_raf_onlink == 0) + continue; + + if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 && + (pr->ndpr_stateflags & NDPRF_ONLINK) != 0) { + if ((e = nd6_prefix_offlink(pr)) != 0) { + nd6log((LOG_ERR, + "pfxlist_onlink_check: failed to " + "make %s/%d offlink, errno=%d\n", + ip6_sprintf(&pr->ndpr_prefix.sin6_addr), + pr->ndpr_plen, e)); + } + } + if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && + (pr->ndpr_stateflags & NDPRF_ONLINK) == 0 && + pr->ndpr_raf_onlink) { + if ((e = nd6_prefix_onlink(pr)) != 0) { + nd6log((LOG_ERR, + "pfxlist_onlink_check: failed to " + "make %s/%d offlink, errno=%d\n", + ip6_sprintf(&pr->ndpr_prefix.sin6_addr), + pr->ndpr_plen, e)); + } + } + } + + /* + * Changes on the prefix status might affect address status as well. + * Make sure that all addresses derived from an attached prefix are + * attached, and that all addresses derived from a detached prefix are + * detached. Note, however, that a manually configured address should + * always be attached. + * The precise detection logic is same as the one for prefixes. + */ + for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) { + if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) + continue; + + if (ifa->ia6_ndpr == NULL) { + /* + * This can happen when we first configure the address + * (i.e. the address exists, but the prefix does not). + * XXX: complicated relationships... + */ + continue; + } + + if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) + break; + } + if (ifa) { + for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) { + if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) + continue; + + if (ifa->ia6_ndpr == NULL) /* XXX: see above. */ + continue; + + if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) + ifa->ia6_flags &= ~IN6_IFF_DETACHED; + else + ifa->ia6_flags |= IN6_IFF_DETACHED; } } else { - /* there is no prefix that has a reachable router */ - for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) - if (pr->ndpr_statef_onlink == 0) - nd6_attach_prefix(pr); + for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) { + if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) + continue; + + ifa->ia6_flags &= ~IN6_IFF_DETACHED; + } } } -static void -nd6_detach_prefix(pr) +int +nd6_prefix_onlink(pr) struct nd_prefix *pr; { - struct in6_ifaddr *ia6; - struct sockaddr_in6 sa6, mask6; + struct ifaddr *ifa; + struct ifnet *ifp = pr->ndpr_ifp; + struct sockaddr_in6 mask6; + struct nd_prefix *opr; + u_long rtflags; + int error = 0; + struct rtentry *rt = NULL; + + /* sanity check */ + if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) { + nd6log((LOG_ERR, + "nd6_prefix_onlink: %s/%d is already on-link\n", + ip6_sprintf(&pr->ndpr_prefix.sin6_addr), pr->ndpr_plen); + return(EEXIST)); + } + + /* + * Add the interface route associated with the prefix. Before + * installing the route, check if there's the same prefix on another + * interface, and the prefix has already installed the interface route. + * Although such a configuration is expected to be rare, we explicitly + * allow it. + */ + for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) { + if (opr == pr) + continue; + + if ((opr->ndpr_stateflags & NDPRF_ONLINK) == 0) + continue; + + if (opr->ndpr_plen == pr->ndpr_plen && + in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, + &opr->ndpr_prefix.sin6_addr, + pr->ndpr_plen)) + return(0); + } + + /* + * We prefer link-local addresses as the associated interface address. + */ + /* search for a link-local addr */ + ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, + IN6_IFF_NOTREADY| + IN6_IFF_ANYCAST); + if (ifa == NULL) { + /* XXX: freebsd does not have ifa_ifwithaf */ + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) + { + if (ifa->ifa_addr->sa_family == AF_INET6) + break; + } + /* should we care about ia6_flags? */ + } + if (ifa == NULL) { + /* + * This can still happen, when, for example, we receive an RA + * containing a prefix with the L bit set and the A bit clear, + * after removing all IPv6 addresses on the receiving + * interface. This should, of course, be rare though. + */ + nd6log((LOG_NOTICE, + "nd6_prefix_onlink: failed to find any ifaddr" + " to add route for a prefix(%s/%d) on %s\n", + ip6_sprintf(&pr->ndpr_prefix.sin6_addr), + pr->ndpr_plen, if_name(ifp))); + return(0); + } /* - * Delete the interface route associated with the prefix. + * in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs. + * ifa->ifa_rtrequest = nd6_rtrequest; */ + bzero(&mask6, sizeof(mask6)); + mask6.sin6_len = sizeof(mask6); + mask6.sin6_addr = pr->ndpr_mask; + rtflags = ifa->ifa_flags | RTF_CLONING | RTF_UP; + if (nd6_need_cache(ifp)) { + /* explicitly set in case ifa_flags does not set the flag. */ + rtflags |= RTF_CLONING; + } else { + /* + * explicitly clear the cloning bit in case ifa_flags sets it. + */ + rtflags &= ~RTF_CLONING; + } + error = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix, + ifa->ifa_addr, (struct sockaddr *)&mask6, + rtflags, &rt); + if (error == 0) { + if (rt != NULL) /* this should be non NULL, though */ + nd6_rtmsg(RTM_ADD, rt); + pr->ndpr_stateflags |= NDPRF_ONLINK; + } + else { + nd6log((LOG_ERR, "nd6_prefix_onlink: failed to add route for a" + " prefix (%s/%d) on %s, gw=%s, mask=%s, flags=%lx " + "errno = %d\n", + ip6_sprintf(&pr->ndpr_prefix.sin6_addr), + pr->ndpr_plen, if_name(ifp), + ip6_sprintf(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr), + ip6_sprintf(&mask6.sin6_addr), rtflags, error)); + } + + if (rt != NULL) + rtunref(rt); + + return(error); +} + +int +nd6_prefix_offlink(pr) + struct nd_prefix *pr; +{ + int error = 0; + struct ifnet *ifp = pr->ndpr_ifp; + struct nd_prefix *opr; + struct sockaddr_in6 sa6, mask6; + struct rtentry *rt = NULL; + + /* sanity check */ + if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { + nd6log((LOG_ERR, + "nd6_prefix_offlink: %s/%d is already off-link\n", + ip6_sprintf(&pr->ndpr_prefix.sin6_addr), pr->ndpr_plen)); + return(EEXIST); + } + bzero(&sa6, sizeof(sa6)); sa6.sin6_family = AF_INET6; sa6.sin6_len = sizeof(sa6); @@ -1226,109 +1525,113 @@ nd6_detach_prefix(pr) mask6.sin6_family = AF_INET6; mask6.sin6_len = sizeof(sa6); bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr)); - { - int e; + error = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL, + (struct sockaddr *)&mask6, 0, &rt); + if (error == 0) { + pr->ndpr_stateflags &= ~NDPRF_ONLINK; - e = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL, - (struct sockaddr *)&mask6, 0, NULL); - if (e) { - log(LOG_ERR, - "nd6_detach_prefix: failed to delete route: " - "%s/%d (errno = %d)\n", - ip6_sprintf(&sa6.sin6_addr), - pr->ndpr_plen, - e); - } - } + /* report the route deletion to the routing socket. */ + if (rt != NULL) + nd6_rtmsg(RTM_DELETE, rt); - /* - * Mark the address derived from the prefix detached so that - * it won't be used as a source address for a new connection. - */ - if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) - ia6 = NULL; - else - ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr); - if (ia6) -#if MIP6 - if (mip6_get_home_prefix_hook) - if (pr != (*mip6_get_home_prefix_hook)()) - ia6->ia6_flags |= IN6_IFF_DETACHED; -#else - ia6->ia6_flags |= IN6_IFF_DETACHED; -#endif -} + /* + * There might be the same prefix on another interface, + * the prefix which could not be on-link just because we have + * the interface route (see comments in nd6_prefix_onlink). + * If there's one, try to make the prefix on-link on the + * interface. + */ + for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) { + if (opr == pr) + continue; -static void -nd6_attach_prefix(pr) - struct nd_prefix *pr; -{ - struct ifaddr *ifa; - struct in6_ifaddr *ia6; + if ((opr->ndpr_stateflags & NDPRF_ONLINK) != 0) + continue; - /* - * Add the interface route associated with the prefix(if necessary) - * Should we consider if the L bit is set in pr->ndpr_flags? - */ - ifa = ifaof_ifpforaddr((struct sockaddr *)&pr->ndpr_prefix, - pr->ndpr_ifp); - if (ifa == NULL) { - log(LOG_ERR, - "nd6_attach_prefix: failed to find any ifaddr" - " to add route for a prefix(%s/%d)\n", - ip6_sprintf(&pr->ndpr_addr), pr->ndpr_plen); + /* + * KAME specific: detached prefixes should not be + * on-link. + */ + if ((opr->ndpr_stateflags & NDPRF_DETACHED) != 0) + continue; + + if (opr->ndpr_plen == pr->ndpr_plen && + in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, + &opr->ndpr_prefix.sin6_addr, + pr->ndpr_plen)) { + int e; + + if ((e = nd6_prefix_onlink(opr)) != 0) { + nd6log((LOG_ERR, + "nd6_prefix_offlink: failed to " + "recover a prefix %s/%d from %s " + "to %s (errno = %d)\n", + ip6_sprintf(&opr->ndpr_prefix.sin6_addr), + opr->ndpr_plen, if_name(ifp), + if_name(opr->ndpr_ifp), e)); + } + } + } } else { - int e; - struct sockaddr_in6 mask6; - - bzero(&mask6, sizeof(mask6)); - mask6.sin6_family = AF_INET6; - mask6.sin6_len = sizeof(mask6); - mask6.sin6_addr = pr->ndpr_mask; - e = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix, - ifa->ifa_addr, (struct sockaddr *)&mask6, - ifa->ifa_flags, NULL); - if (e == 0) - pr->ndpr_statef_onlink = 1; - else { - log(LOG_ERR, - "nd6_attach_prefix: failed to add route for" - " a prefix(%s/%d), errno = %d\n", - ip6_sprintf(&pr->ndpr_addr), pr->ndpr_plen, e); - } + /* XXX: can we still set the NDPRF_ONLINK flag? */ + nd6log((LOG_ERR, + "nd6_prefix_offlink: failed to delete route: " + "%s/%d on %s (errno = %d)\n", + ip6_sprintf(&sa6.sin6_addr), pr->ndpr_plen, if_name(ifp), + error)); } - /* - * Now the address derived from the prefix can be used as a source - * for a new connection, so clear the detached flag. - */ - if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) - ia6 = NULL; - else - ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr); - if (ia6) { - ia6->ia6_flags &= ~IN6_IFF_DETACHED; - if (pr->ndpr_statef_onlink) - ia6->ia_flags |= IFA_ROUTE; + if (rt != NULL) { + if (rt->rt_refcnt <= 0) { + /* XXX: we should free the entry ourselves. */ + rtref(rt); + rtfree(rt); + } } + + return(error); } static struct in6_ifaddr * -in6_ifadd(ifp, in6, addr, prefixlen) - struct ifnet *ifp; - struct in6_addr *in6; - struct in6_addr *addr; - int prefixlen; /* prefix len of the new prefix in "in6" */ +in6_ifadd(pr, ifid) + struct nd_prefix *pr; + struct in6_addr *ifid; /* Mobile IPv6 addition */ { + struct ifnet *ifp = pr->ndpr_ifp; struct ifaddr *ifa; - struct in6_ifaddr *ia, *ib, *oia; - int s, error; + struct in6_aliasreq ifra; + struct in6_ifaddr *ia, *ib; + int error, plen0; struct in6_addr mask; + int prefixlen = pr->ndpr_plen; in6_len2mask(&mask, prefixlen); - /* find link-local address (will be interface ID) */ + /* + * find a link-local address (will be interface ID). + * Is it really mandatory? Theoretically, a global or a site-local + * address can be configured without a link-local address, if we + * have a unique interface identifier... + * + * it is not mandatory to have a link-local address, we can generate + * interface identifier on the fly. we do this because: + * (1) it should be the easiest way to find interface identifier. + * (2) RFC2462 5.4 suggesting the use of the same interface identifier + * for multiple addresses on a single interface, and possible shortcut + * of DAD. we omitted DAD for this reason in the past. + * (3) a user can prevent autoconfiguration of global address + * by removing link-local address by hand (this is partly because we + * don't have other way to control the use of IPv6 on a interface. + * this has been our design choice - cf. NRL's "ifconfig auto"). + * (4) it is easier to manage when an interface has addresses + * with the same interface identifier, than to have multiple addresses + * with different interface identifiers. + * + * Mobile IPv6 addition: allow for caller to specify a wished interface + * ID. This is to not break connections when moving addresses between + * interfaces. + */ ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0);/* 0 is OK? */ if (ifa) ib = (struct in6_ifaddr *)ifa; @@ -1344,248 +1647,201 @@ in6_ifadd(ifp, in6, addr, prefixlen) #endif /* prefixlen + ifidlen must be equal to 128 */ - if (prefixlen != in6_mask2len(&ib->ia_prefixmask.sin6_addr)) { - log(LOG_ERR, "in6_ifadd: wrong prefixlen for %s" - "(prefix=%d ifid=%d)\n", if_name(ifp), - prefixlen, - 128 - in6_mask2len(&ib->ia_prefixmask.sin6_addr)); + plen0 = in6_mask2len(&ib->ia_prefixmask.sin6_addr, NULL); + if (prefixlen != plen0) { + nd6log((LOG_INFO, "in6_ifadd: wrong prefixlen for %s " + "(prefix=%d ifid=%d)\n", + if_name(ifp), prefixlen, 128 - plen0)); return NULL; } /* make ifaddr */ - ia = (struct in6_ifaddr *)_MALLOC(sizeof(*ia), M_IFADDR, M_NOWAIT); - if (ia == NULL) { - printf("ENOBUFS in in6_ifadd %d\n", __LINE__); - return NULL; - } - bzero((caddr_t)ia, sizeof(*ia)); - ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; - if (ifp->if_flags & IFF_POINTOPOINT) - ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; - else - ia->ia_ifa.ifa_dstaddr = NULL; - ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask; - ia->ia_ifp = ifp; + bzero(&ifra, sizeof(ifra)); + /* + * in6_update_ifa() does not use ifra_name, but we accurately set it + * for safety. + */ + strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); + ifra.ifra_addr.sin6_family = AF_INET6; + ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); + /* prefix */ + bcopy(&pr->ndpr_prefix.sin6_addr, &ifra.ifra_addr.sin6_addr, + sizeof(ifra.ifra_addr.sin6_addr)); + ifra.ifra_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0]; + ifra.ifra_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1]; + ifra.ifra_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2]; + ifra.ifra_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3]; - /* link to in6_ifaddr */ - if ((oia = in6_ifaddr) != NULL) { - for( ; oia->ia_next; oia = oia->ia_next) - continue; - oia->ia_next = ia; - } else - in6_ifaddr = ia; - ia->ia_ifa.ifa_refcnt++; + /* interface ID */ + if (ifid == NULL || IN6_IS_ADDR_UNSPECIFIED(ifid)) + ifid = &ib->ia_addr.sin6_addr; + ifra.ifra_addr.sin6_addr.s6_addr32[0] + |= (ifid->s6_addr32[0] & ~mask.s6_addr32[0]); + ifra.ifra_addr.sin6_addr.s6_addr32[1] + |= (ifid->s6_addr32[1] & ~mask.s6_addr32[1]); + ifra.ifra_addr.sin6_addr.s6_addr32[2] + |= (ifid->s6_addr32[2] & ~mask.s6_addr32[2]); + ifra.ifra_addr.sin6_addr.s6_addr32[3] + |= (ifid->s6_addr32[3] & ~mask.s6_addr32[3]); + + /* new prefix mask. */ + ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); + ifra.ifra_prefixmask.sin6_family = AF_INET6; + bcopy(&mask, &ifra.ifra_prefixmask.sin6_addr, + sizeof(ifra.ifra_prefixmask.sin6_addr)); - /* link to if_addrlist */ -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - if ((ifa = ifp->if_addrlist) != NULL) { - for ( ; ifa->ifa_next; ifa = ifa->ifa_next) - continue; - ifa->ifa_next = (struct ifaddr *)ia; - } -#else - if (ifp->if_addrlist.tqh_first != NULL) { - TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, - ifa_list); - ia->ia_ifa.ifa_refcnt++; - } -#endif -#if 0 - else { - /* - * this should not be the case because there is at least one - * link-local address(see the beginning of the function). - */ - TAILQ_INIT(&ifp->if_addrlist); - } -#endif + /* + * lifetime. + * XXX: in6_init_address_ltimes would override these values later. + * We should reconsider this logic. + */ + ifra.ifra_lifetime.ia6t_vltime = pr->ndpr_vltime; + ifra.ifra_lifetime.ia6t_pltime = pr->ndpr_pltime; - /* new address */ - ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6); - ia->ia_addr.sin6_family = AF_INET6; - /* prefix */ - bcopy(in6, &ia->ia_addr.sin6_addr, sizeof(ia->ia_addr.sin6_addr)); - ia->ia_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0]; - ia->ia_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1]; - ia->ia_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2]; - ia->ia_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3]; - /* interface ID */ - ia->ia_addr.sin6_addr.s6_addr32[0] - |= (ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]); - ia->ia_addr.sin6_addr.s6_addr32[1] - |= (ib->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]); - ia->ia_addr.sin6_addr.s6_addr32[2] - |= (ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]); - ia->ia_addr.sin6_addr.s6_addr32[3] - |= (ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]); - - /* new prefix */ - ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6); - ia->ia_prefixmask.sin6_family = AF_INET6; - bcopy(&mask, &ia->ia_prefixmask.sin6_addr, - sizeof(ia->ia_prefixmask.sin6_addr)); - - /* same routine */ - ia->ia_ifa.ifa_rtrequest = - (ifp->if_type == IFT_PPP) ? nd6_p2p_rtrequest : nd6_rtrequest; - ia->ia_ifa.ifa_flags |= RTF_CLONING; - ia->ia_ifa.ifa_metric = ifp->if_metric; - - /* add interface route */ - if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP|RTF_CLONING))) { - log(LOG_NOTICE, "in6_ifadd: failed to add an interface route " - "for %s/%d on %s, errno = %d\n", - ip6_sprintf(&ia->ia_addr.sin6_addr), prefixlen, - if_name(ifp), error); + /* XXX: scope zone ID? */ + + ifra.ifra_flags |= IN6_IFF_AUTOCONF; /* obey autoconf */ + /* + * temporarily set the nopfx flag to avoid conflict. + * XXX: we should reconsider the entire mechanism about prefix + * manipulation. + */ + ifra.ifra_flags |= IN6_IFF_NOPFX; + + /* + * keep the new address, regardless of the result of in6_update_ifa. + * XXX: this address is now meaningless. + * We should reconsider its role. + */ + pr->ndpr_addr = ifra.ifra_addr.sin6_addr; + + /* allocate ifaddr structure, link into chain, etc. */ + if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) { + nd6log((LOG_ERR, + "in6_ifadd: failed to make ifaddr %s on %s (errno=%d)\n", + ip6_sprintf(&ifra.ifra_addr.sin6_addr), if_name(ifp), + error)); + return(NULL); /* ifaddr must not have been allocated. */ } - else - ia->ia_flags |= IFA_ROUTE; - *addr = ia->ia_addr.sin6_addr; + ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr); - if (ifp->if_flags & IFF_MULTICAST) { - int error; /* not used */ - struct in6_addr sol6; + in6_post_msg(ifp, KEV_INET6_NEW_RTADV_ADDR, ia); -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined (__APPLE__) - /* Restore saved multicast addresses(if any). */ - in6_restoremkludge(ia, ifp); -#endif + return(ia); /* this must NOT be NULL. */ +} - /* join solicited node multicast address */ - bzero(&sol6, sizeof(sol6)); - sol6.s6_addr16[0] = htons(0xff02); - sol6.s6_addr16[1] = htons(ifp->if_index); - sol6.s6_addr32[1] = 0; - sol6.s6_addr32[2] = htonl(1); - sol6.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3]; - sol6.s6_addr8[12] = 0xff; - (void)in6_addmulti(&sol6, ifp, &error); +int +in6_tmpifadd(ia0, forcegen) + const struct in6_ifaddr *ia0; /* corresponding public address */ +{ + struct ifnet *ifp = ia0->ia_ifa.ifa_ifp; + struct in6_ifaddr *newia; + struct in6_aliasreq ifra; + int i, error; + int trylimit = 3; /* XXX: adhoc value */ + u_int32_t randid[2]; + time_t vltime0, pltime0; + + bzero(&ifra, sizeof(ifra)); + strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); + ifra.ifra_addr = ia0->ia_addr; + /* copy prefix mask */ + ifra.ifra_prefixmask = ia0->ia_prefixmask; + /* clear the old IFID */ + for (i = 0; i < 4; i++) { + ifra.ifra_addr.sin6_addr.s6_addr32[i] + &= ifra.ifra_prefixmask.sin6_addr.s6_addr32[i]; } - ia->ia6_flags |= IN6_IFF_TENTATIVE; + again: + in6_get_tmpifid(ifp, (u_int8_t *)randid, + (const u_int8_t *)&ia0->ia_addr.sin6_addr.s6_addr[8], + forcegen); + ifra.ifra_addr.sin6_addr.s6_addr32[2] + |= (randid[0] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[2])); + ifra.ifra_addr.sin6_addr.s6_addr32[3] + |= (randid[1] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[3])); /* - * To make the interface up. Only AF_INET6 in ia is used... + * If by chance the new temporary address is the same as an address + * already assigned to the interface, generate a new randomized + * interface identifier and repeat this step. + * RFC 3041 3.3 (4). */ - s = splimp(); - error = dlil_ioctl(PF_INET6, ifp, SIOCSIFADDR, (caddr_t)ia); - if (error == EOPNOTSUPP) - error = 0; - if (error) { - - splx(s); - return NULL; + if (in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr) != NULL) { + if (trylimit-- == 0) { + nd6log((LOG_NOTICE, "in6_tmpifadd: failed to find " + "a unique random IFID\n")); + return(EEXIST); + } + forcegen = 1; + goto again; } - splx(s); - /* Perform DAD, if needed. */ - nd6_dad_start((struct ifaddr *)ia, NULL); + /* + * The Valid Lifetime is the lower of the Valid Lifetime of the + * public address or TEMP_VALID_LIFETIME. + * The Preferred Lifetime is the lower of the Preferred Lifetime + * of the public address or TEMP_PREFERRED_LIFETIME - + * DESYNC_FACTOR. + */ + if (ia0->ia6_lifetime.ia6t_expire != 0) { + vltime0 = IFA6_IS_INVALID(ia0) ? 0 : + (ia0->ia6_lifetime.ia6t_expire - time_second); + if (vltime0 > ip6_temp_valid_lifetime) + vltime0 = ip6_temp_valid_lifetime; + } else + vltime0 = ip6_temp_valid_lifetime; + if (ia0->ia6_lifetime.ia6t_preferred != 0) { + pltime0 = IFA6_IS_DEPRECATED(ia0) ? 0 : + (ia0->ia6_lifetime.ia6t_preferred - time_second); + if (pltime0 > ip6_temp_preferred_lifetime - ip6_desync_factor){ + pltime0 = ip6_temp_preferred_lifetime - + ip6_desync_factor; + } + } else + pltime0 = ip6_temp_preferred_lifetime - ip6_desync_factor; + ifra.ifra_lifetime.ia6t_vltime = vltime0; + ifra.ifra_lifetime.ia6t_pltime = pltime0; - return ia; -} + /* + * A temporary address is created only if this calculated Preferred + * Lifetime is greater than REGEN_ADVANCE time units. + */ + if (ifra.ifra_lifetime.ia6t_pltime <= ip6_temp_regen_advance) + return(0); -int -in6_ifdel(ifp, in6) - struct ifnet *ifp; - struct in6_addr *in6; -{ -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - struct ifaddr *ifa; -#endif - struct in6_ifaddr *ia = (struct in6_ifaddr *)NULL; - struct in6_ifaddr *oia = (struct in6_ifaddr *)NULL; + /* XXX: scope zone ID? */ - if (!ifp) - return -1; + ifra.ifra_flags |= (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY); - ia = in6ifa_ifpwithaddr(ifp, in6); - if (!ia) - return -1; + /* allocate ifaddr structure, link into chain, etc. */ + if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) + return(error); - if (ifp->if_flags & IFF_MULTICAST) { - /* - * delete solicited multicast addr for deleting host id - */ - struct in6_multi *in6m; - struct in6_addr llsol; - bzero(&llsol, sizeof(struct in6_addr)); - llsol.s6_addr16[0] = htons(0xff02); - llsol.s6_addr16[1] = htons(ifp->if_index); - llsol.s6_addr32[1] = 0; - llsol.s6_addr32[2] = htonl(1); - llsol.s6_addr32[3] = - ia->ia_addr.sin6_addr.s6_addr32[3]; - llsol.s6_addr8[12] = 0xff; - - IN6_LOOKUP_MULTI(llsol, ifp, in6m); - if (in6m) - in6_delmulti(in6m); - } - - if (ia->ia_flags & IFA_ROUTE) { - rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); - ia->ia_flags &= ~IFA_ROUTE; - } - -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - 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 - return -1; + newia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr); + if (newia == NULL) { /* XXX: can it happen? */ + nd6log((LOG_ERR, + "in6_tmpifadd: ifa update succeeded, but we got " + "no ifaddr\n")); + return(EINVAL); /* XXX */ } -#else - TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); -#endif - IFAFREE(&ia->ia_ifa); + newia->ia6_ndpr = ia0->ia6_ndpr; + newia->ia6_ndpr->ndpr_refcnt++; - /* lladdr is never deleted */ - oia = ia; - if (oia == (ia = in6_ifaddr)) - in6_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 - return -1; - } - -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined (__APPLE__) - in6_savemkludge(oia); -#endif - IFAFREE((&oia->ia_ifa)); -/* xxx - rtrequest(RTM_DELETE, - (struct sockaddr *)&ia->ia_addr, - (struct sockaddr *)0 - (struct sockaddr *)&ia->ia_prefixmask, - RTF_UP|RTF_CLONING, - (struct rtentry **)0); -*/ - return 0; -} + return(0); +} int in6_init_prefix_ltimes(struct nd_prefix *ndpr) { -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined (__APPLE__) - long time_second = time.tv_sec; -#endif - - /* check if preferred lifetime > valid lifetime */ + /* check if preferred lifetime > valid lifetime. RFC2462 5.5.3 (c) */ if (ndpr->ndpr_pltime > ndpr->ndpr_vltime) { - log(LOG_INFO, "in6_init_prefix_ltimes: preferred lifetime" + nd6log((LOG_INFO, "in6_init_prefix_ltimes: preferred lifetime" "(%d) is greater than valid lifetime(%d)\n", - (u_int)ndpr->ndpr_pltime, (u_int)ndpr->ndpr_vltime); + (u_int)ndpr->ndpr_pltime, (u_int)ndpr->ndpr_vltime)); return (EINVAL); } if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME) @@ -1601,27 +1857,15 @@ in6_init_prefix_ltimes(struct nd_prefix *ndpr) } static void -in6_init_address_ltimes(struct nd_prefix *new, - struct in6_addrlifetime *lt6, - int update_vltime) +in6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6) { -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined (__APPLE__) - long time_second = time.tv_sec; -#endif - /* Valid lifetime must not be updated unless explicitly specified. */ - if (update_vltime) { - /* init ia6t_expire */ - if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME) - lt6->ia6t_expire = 0; - else { - lt6->ia6t_expire = time_second; - lt6->ia6t_expire += lt6->ia6t_vltime; - } - /* Ensure addr lifetime <= prefix lifetime. */ - if (new->ndpr_expire && lt6->ia6t_expire && - new->ndpr_expire < lt6->ia6t_expire) - lt6->ia6t_expire = new->ndpr_expire; + /* init ia6t_expire */ + if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME) + lt6->ia6t_expire = 0; + else { + lt6->ia6t_expire = time_second; + lt6->ia6t_expire += lt6->ia6t_vltime; } /* init ia6t_preferred */ @@ -1631,10 +1875,6 @@ in6_init_address_ltimes(struct nd_prefix *new, lt6->ia6t_preferred = time_second; lt6->ia6t_preferred += lt6->ia6t_pltime; } - /* Ensure addr lifetime <= prefix lifetime. */ - if (new->ndpr_preferred && lt6->ia6t_preferred - && new->ndpr_preferred < lt6->ia6t_preferred) - lt6->ia6t_preferred = new->ndpr_preferred; } /* @@ -1644,15 +1884,11 @@ in6_init_address_ltimes(struct nd_prefix *new, */ void rt6_flush(gateway, ifp) - struct in6_addr *gateway; - struct ifnet *ifp; + struct in6_addr *gateway; + struct ifnet *ifp; { struct radix_node_head *rnh = rt_tables[AF_INET6]; -#ifdef __NetBSD__ - int s = splsoftnet(); -#else int s = splnet(); -#endif /* We'll care only link-local addresses */ if (!IN6_IS_ADDR_LINKLOCAL(gateway)) { @@ -1681,6 +1917,14 @@ rt6_deleteroute(rn, arg) if (!IN6_ARE_ADDR_EQUAL(gate, &SIN6(rt->rt_gateway)->sin6_addr)) return(0); + /* + * Do not delete a static route. + * XXX: this seems to be a bit ad-hoc. Should we consider the + * 'cloned' bit instead? + */ + if ((rt->rt_flags & RTF_STATIC) != 0) + return(0); + /* * We delete only host route. This means, in particular, we don't * delete default route. @@ -1719,6 +1963,13 @@ nd6_setdefaultiface(ifindex) */ if (TAILQ_FIRST(&nd_defrouter) == NULL) defrouter_select(); + + /* + * Our current implementation assumes one-to-one maping between + * interfaces and links, so it would be natural to use the + * default interface as the default link. + */ + scope6_setdefault(nd6_defifp); } return(error); diff --git a/bsd/netinet6/pim6.h b/bsd/netinet6/pim6.h index 81b2ab6c5..1ae3f1afb 100644 --- a/bsd/netinet6/pim6.h +++ b/bsd/netinet6/pim6.h @@ -1,4 +1,5 @@ -/* $KAME: pim6.h,v 1.2 2000/02/22 14:04:33 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/pim6.h,v 1.1.2.1 2000/07/15 07:14:36 kris Exp $ */ +/* $KAME: pim6.h,v 1.3 2000/03/25 07:23:58 sumikawa Exp $ */ /* * Copyright (C) 1998 WIDE Project. @@ -35,6 +36,7 @@ * * MULTICAST */ +#include /* * PIM packet header diff --git a/bsd/netinet6/pim6_var.h b/bsd/netinet6/pim6_var.h index 4b0530f82..29abc1192 100644 --- a/bsd/netinet6/pim6_var.h +++ b/bsd/netinet6/pim6_var.h @@ -1,4 +1,5 @@ -/* $KAME: pim6_var.h,v 1.5 2000/03/25 07:23:59 sumikawa Exp $ */ +/* $FreeBSD: src/sys/netinet6/pim6_var.h,v 1.2.2.1 2000/07/15 07:14:36 kris Exp $ */ +/* $KAME: pim6_var.h,v 1.8 2000/06/06 08:07:43 jinmei Exp $ */ /* * Copyright (C) 1998 WIDE Project. @@ -31,6 +32,7 @@ #ifndef _NETINET6_PIM6_VAR_H_ #define _NETINET6_PIM6_VAR_H_ +#include /* * Protocol Independent Multicast (PIM), @@ -40,6 +42,7 @@ * Modified by Pavlin Ivanov Radoslavov, USC/ISI, May 1998 */ +#ifdef __APPLE_API_UNSTABLE struct pim6stat { u_quad_t pim6s_rcv_total; /* total PIM messages received */ u_quad_t pim6s_rcv_tooshort; /* received with too few bytes */ @@ -49,22 +52,24 @@ struct pim6stat { u_quad_t pim6s_rcv_badregisters; /* received invalid registers */ u_quad_t pim6s_snd_registers; /* sent registers */ }; +#endif #if (defined(KERNEL)) || (defined(_KERNEL)) +#ifdef __APPLE_API_PRIVATE extern struct pim6stat pim6stat; -int pim6_input __P((struct mbuf **, int*, int)); +int pim6_input __P((struct mbuf **, int*)); +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ /* * Names for PIM sysctl objects */ -#define PIMCTL_STATS 1 /* statistics (read-only) */ -#define PIMCTL_MAXID 2 +#define PIM6CTL_STATS 1 /* statistics (read-only) */ +#define PIM6CTL_MAXID 2 -#define PIMCTL_NAMES { \ +#define PIM6CTL_NAMES { \ { 0, 0 }, \ { 0, 0 }, \ } - #endif /* _NETINET6_PIM6_VAR_H_ */ diff --git a/bsd/netinet6/raw_ip6.c b/bsd/netinet6/raw_ip6.c index 0baf3af82..f49d75e92 100644 --- a/bsd/netinet6/raw_ip6.c +++ b/bsd/netinet6/raw_ip6.c @@ -1,7 +1,7 @@ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -13,7 +13,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -25,6 +25,8 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * $FreeBSD: src/sys/netinet6/raw_ip6.c,v 1.7.2.4 2001/07/29 19:32:40 ume Exp $ */ /* @@ -61,12 +63,6 @@ * * @(#)raw_ip.c 8.2 (Berkeley) 1/4/94 */ -#if BSD310 -#include "opt_inet.h" -#endif - -#include - #include #include #include @@ -88,63 +84,73 @@ #include #include #include -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) #include -#endif #include #include #include +#if ENABLE_DEFAULT_SCOPE +#include +#endif +#include #if IPSEC #include +#include +extern int ipsec_bypass; #endif /*IPSEC*/ #include "faith.h" +#if defined(NFAITH) && 0 < NFAITH +#include +#endif -#define satosin6(sa) ((struct sockaddr_in6 *)(sa)) -#define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa)) +#define satosin6(sa) ((struct sockaddr_in6 *)(sa)) +#define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa)) /* * Raw interface to IP6 protocol. */ -extern struct inpcbhead ripcb; -extern struct inpcbinfo ripcbinfo; +extern struct inpcbhead ripcb; +extern struct inpcbinfo ripcbinfo; extern u_long rip_sendspace; extern u_long rip_recvspace; +struct rip6stat rip6stat; + /* * Setup generic address and protocol structures * for raw_input routine, then pass them along with * mbuf chain. */ int -rip6_input(mp, offp, proto) +rip6_input(mp, offp) struct mbuf **mp; - int *offp, proto; + int *offp; { struct mbuf *m = *mp; register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); register struct inpcb *in6p; struct inpcb *last = 0; - struct ip6_recvpktopts opts; + struct mbuf *opts = NULL; struct sockaddr_in6 rip6src; + int proto = ip6->ip6_nxt; + + rip6stat.rip6s_ipackets++; #if defined(NFAITH) && 0 < NFAITH - if (m->m_pkthdr.rcvif) { - if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) { - /* XXX send icmp6 host/port unreach? */ - m_freem(m); - return IPPROTO_DONE; - } + if (faithprefix(&ip6->ip6_dst)) { + /* XXX send icmp6 host/port unreach? */ + m_freem(m); + return IPPROTO_DONE; } #endif + init_sin6(&rip6src, m); /* general init */ - bzero(&opts, sizeof(opts)); LIST_FOREACH(in6p, &ripcb, inp_list) { - if ((in6p->in6p_vflag & INP_IPV6) == NULL) + if ((in6p->in6p_vflag & INP_IPV6) == 0) continue; if (in6p->in6p_ip6_nxt && in6p->in6p_ip6_nxt != proto) @@ -155,49 +161,76 @@ rip6_input(mp, offp, proto) if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) && !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src)) continue; - if (in6p->in6p_cksum != -1 - && in6_cksum(m, ip6->ip6_nxt, *offp, - m->m_pkthdr.len - *offp)) { - /* XXX bark something */ - continue; + if (in6p->in6p_cksum != -1) { + rip6stat.rip6s_isum++; + if (in6_cksum(m, ip6->ip6_nxt, *offp, + m->m_pkthdr.len - *offp)) { + rip6stat.rip6s_badsum++; + continue; + } } if (last) { struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); + +#if IPSEC + /* + * Check AH/ESP integrity. + */ + if (ipsec_bypass == 0 && n && ipsec6_in_reject_so(n, last->inp_socket)) { + m_freem(n); + ipsec6stat.in_polvio++; + /* do not inject data into pcb */ + } else +#endif /*IPSEC*/ if (n) { if (last->in6p_flags & IN6P_CONTROLOPTS || last->in6p_socket->so_options & SO_TIMESTAMP) - ip6_savecontrol(last, ip6, n, &opts, - NULL); + ip6_savecontrol(last, &opts, ip6, n); /* strip intermediate headers */ m_adj(n, *offp); if (sbappendaddr(&last->in6p_socket->so_rcv, (struct sockaddr *)&rip6src, - n, opts.head) == 0) { - /* should notify about lost packet */ + n, opts) == 0) { m_freem(n); - if (opts.head) - m_freem(opts.head); + if (opts) + m_freem(opts); + rip6stat.rip6s_fullsock++; } else sorwakeup(last->in6p_socket); - bzero(&opts, sizeof(opts)); + opts = NULL; } } last = in6p; } +#if IPSEC + /* + * Check AH/ESP integrity. + */ + if (ipsec_bypass == 0 && last && ipsec6_in_reject_so(m, last->inp_socket)) { + m_freem(m); + ipsec6stat.in_polvio++; + ip6stat.ip6s_delivered--; + /* do not inject data into pcb */ + } else +#endif /*IPSEC*/ if (last) { if (last->in6p_flags & IN6P_CONTROLOPTS || last->in6p_socket->so_options & SO_TIMESTAMP) - ip6_savecontrol(last, ip6, m, &opts, NULL); + ip6_savecontrol(last, &opts, ip6, m); /* strip intermediate headers */ m_adj(m, *offp); if (sbappendaddr(&last->in6p_socket->so_rcv, - (struct sockaddr *)&rip6src, m, opts.head) == 0) { + (struct sockaddr *)&rip6src, m, opts) == 0) { m_freem(m); - if (opts.head) - m_freem(opts.head); + if (opts) + m_freem(opts); + rip6stat.rip6s_fullsock++; } else sorwakeup(last->in6p_socket); } else { + rip6stat.rip6s_nosock++; + if (m->m_flags & M_MCAST) + rip6stat.rip6s_nosockmcast++; if (proto == IPPROTO_NONE) m_freem(m); else { @@ -217,10 +250,11 @@ rip6_ctlinput(cmd, sa, d) struct sockaddr *sa; void *d; { - struct sockaddr_in6 sa6; struct ip6_hdr *ip6; struct mbuf *m; int off = 0; + struct ip6ctlparam *ip6cp = NULL; + const struct sockaddr_in6 *sa6_src = NULL; void (*notify) __P((struct inpcb *, int)) = in6_rtchange; if (sa->sa_family != AF_INET6 || @@ -238,37 +272,19 @@ rip6_ctlinput(cmd, sa, d) /* if the parameter is from icmp6, decode it. */ if (d != NULL) { - struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d; + ip6cp = (struct ip6ctlparam *)d; m = ip6cp->ip6c_m; ip6 = ip6cp->ip6c_ip6; off = ip6cp->ip6c_off; + sa6_src = ip6cp->ip6c_src; } else { m = NULL; ip6 = NULL; + sa6_src = &sa6_any; } - /* translate addresses into internal form */ - sa6 = *(struct sockaddr_in6 *)sa; - if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) && m && m->m_pkthdr.rcvif) - sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); - - if (ip6) { - /* - * XXX: We assume that when IPV6 is non NULL, - * M and OFF are valid. - */ - struct in6_addr s; - - /* translate addresses into internal form */ - memcpy(&s, &ip6->ip6_src, sizeof(s)); - if (IN6_IS_ADDR_LINKLOCAL(&s)) - s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); - - (void) in6_pcbnotify(&ripcb, (struct sockaddr *)&sa6, - 0, &s, 0, cmd, notify); - } else - (void) in6_pcbnotify(&ripcb, (struct sockaddr *)&sa6, 0, - &zeroin6_addr, 0, cmd, notify); + (void) in6_pcbnotify(&ripcb, sa, 0, (struct sockaddr *)sa6_src, + 0, cmd, notify); } /* @@ -295,17 +311,8 @@ rip6_output(m, so, dstsock, control) in6p = sotoin6pcb(so); priv = 0; -#if !defined(__APPLE__) - { - struct proc *p = current_proc(); /* XXX */ - - if (p && !suser(p->p_ucred, &p->p_acflag)) - priv = 1; - } -#else - if ((so->so_state & SS_PRIV) != 0) + if (so->so_uid == 0) priv = 1; -#endif dst = &dstsock->sin6_addr; if (control) { if ((error = ip6_setpktoptions(control, &opt, priv, 0)) != 0) @@ -342,7 +349,7 @@ rip6_output(m, so, dstsock, control) * If the scope of the destination is link-local, embed the interface * index in the address. * - * XXX advanced-api value overrides sin6_scope_id + * XXX advanced-api value overrides sin6_scope_id */ if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { struct in6_pktinfo *pi; @@ -354,15 +361,14 @@ rip6_output(m, so, dstsock, control) if (optp && (pi = optp->ip6po_pktinfo) && pi->ipi6_ifindex) { ip6->ip6_dst.s6_addr16[1] = htons(pi->ipi6_ifindex); oifp = ifindex2ifnet[pi->ipi6_ifindex]; - } - else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) && + } else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) && in6p->in6p_moptions && in6p->in6p_moptions->im6o_multicast_ifp) { oifp = in6p->in6p_moptions->im6o_multicast_ifp; ip6->ip6_dst.s6_addr16[1] = htons(oifp->if_index); } else if (dstsock->sin6_scope_id) { /* boundary check */ - if (dstsock->sin6_scope_id < 0 + if (dstsock->sin6_scope_id < 0 || if_index < dstsock->sin6_scope_id) { error = ENXIO; /* XXX EINVAL? */ goto bad; @@ -391,12 +397,11 @@ rip6_output(m, so, dstsock, control) if (in6p->in6p_route.ro_rt) oifp = ifindex2ifnet[in6p->in6p_route.ro_rt->rt_ifp->if_index]; } - - ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK; - ip6->ip6_vfc |= IPV6_VERSION; -#if 0 /* ip6_plen will be filled in ip6_output. */ - ip6->ip6_plen = htons((u_short)plen); -#endif + ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) | + (in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK); + ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) | + (IPV6_VERSION & IPV6_VERSION_MASK); + /* ip6_plen will be filled in ip6_output, so not fill it here. */ ip6->ip6_nxt = in6p->in6p_ip6_nxt; ip6->ip6_hlim = in6_selecthlim(in6p, oifp); @@ -406,8 +411,6 @@ rip6_output(m, so, dstsock, control) int off; u_int16_t *p; -#define offsetof(type, member) ((size_t)(&((type *)0)->member)) /* XXX */ - /* compute checksum */ if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) off = offsetof(struct icmp6_hdr, icmp6_cksum); @@ -432,16 +435,20 @@ rip6_output(m, so, dstsock, control) } #if IPSEC - ipsec_setsocket(m, so); + if (ipsec_bypass == 0 && ipsec_setsocket(m, so) != 0) { + error = ENOBUFS; + goto bad; + } #endif /*IPSEC*/ - error = ip6_output(m, optp, &in6p->in6p_route, 0, in6p->in6p_moptions, - &oifp); + error = ip6_output(m, optp, &in6p->in6p_route, 0, + in6p->in6p_moptions, &oifp); if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { if (oifp) icmp6_ifoutstat_inc(oifp, type, code); icmp6stat.icp6s_outhist[type]++; - } + } else + rip6stat.rip6s_opackets++; goto freectl; @@ -451,7 +458,7 @@ rip6_output(m, so, dstsock, control) freectl: if (optp == &opt && optp->ip6po_rthdr && optp->ip6po_route.ro_rt) - RTFREE(optp->ip6po_route.ro_rt); + rtfree(optp->ip6po_route.ro_rt); if (control) { if (optp == &opt) ip6_clearpktopts(optp, 0, -1); @@ -532,11 +539,9 @@ rip6_attach(struct socket *so, int proto, struct proc *p) if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0) return error; - if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { - error = soreserve(so, rip_sendspace, rip_recvspace); - if (error) - return error; - } + error = soreserve(so, rip_sendspace, rip_recvspace); + if (error) + return error; s = splnet(); error = in_pcballoc(so, &ripcbinfo, p); splx(s); @@ -547,19 +552,8 @@ rip6_attach(struct socket *so, int proto, struct proc *p) inp->in6p_ip6_nxt = (long)proto; inp->in6p_hops = -1; /* use kernel default */ inp->in6p_cksum = -1; -#if IPSEC - error = ipsec_init_policy(so, &inp->in6p_sp); - if (error != 0) { - in6_pcbdetach(inp); - return (error); - } -#endif /*IPSEC*/ MALLOC(inp->in6p_icmp6filt, struct icmp6_filter *, sizeof(struct icmp6_filter), M_PCB, M_NOWAIT); - - if (inp->in6p_icmp6filt == NULL) - return(ENOBUFS); - ICMP6_FILTER_SETPASSALL(inp->in6p_icmp6filt); return 0; } @@ -572,9 +566,9 @@ rip6_detach(struct socket *so) inp = sotoinpcb(so); if (inp == 0) panic("rip6_detach"); + /* xxx: RSVP */ if (so == ip6_mrouter) ip6_mrouter_done(); - /* xxx: RSVP */ if (inp->in6p_icmp6filt) { FREE(inp->in6p_icmp6filt, M_PCB); inp->in6p_icmp6filt = NULL; @@ -613,6 +607,11 @@ rip6_bind(struct socket *so, struct sockaddr *nam, struct proc *p) if (TAILQ_EMPTY(&ifnet) || addr->sin6_family != AF_INET6) return EADDRNOTAVAIL; +#if ENABLE_DEFAULT_SCOPE + if (addr->sin6_scope_id == 0) { /* not change if specified */ + addr->sin6_scope_id = scope6_addr2default(&addr->sin6_addr); + } +#endif if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) && (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0) return EADDRNOTAVAIL; @@ -633,6 +632,9 @@ rip6_connect(struct socket *so, struct sockaddr *nam, struct proc *p) struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam; struct in6_addr *in6a = NULL; int error = 0; +#if ENABLE_DEFAULT_SCOPE + struct sockaddr_in6 tmp; +#endif if (nam->sa_len != sizeof(*addr)) return EINVAL; @@ -640,7 +642,14 @@ rip6_connect(struct socket *so, struct sockaddr *nam, struct proc *p) return EADDRNOTAVAIL; if (addr->sin6_family != AF_INET6) return EAFNOSUPPORT; - +#if ENABLE_DEFAULT_SCOPE + if (addr->sin6_scope_id == 0) { /* not change if specified */ + /* avoid overwrites */ + tmp = *addr; + addr = &tmp; + addr->sin6_scope_id = scope6_addr2default(&addr->sin6_addr); + } +#endif /* Source address selection. XXX: need pcblookup? */ in6a = in6_selectsrc(addr, inp->in6p_outputopts, inp->in6p_moptions, &inp->in6p_route, @@ -668,6 +677,7 @@ rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, struct sockaddr_in6 tmp; struct sockaddr_in6 *dst; + /* always copy sockaddr to avoid overwrites */ if (so->so_state & SS_ISCONNECTED) { if (nam) { m_freem(m); @@ -685,8 +695,14 @@ rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, m_freem(m); return ENOTCONN; } - dst = (struct sockaddr_in6 *)nam; + tmp = *(struct sockaddr_in6 *)nam; + dst = &tmp; } +#if ENABLE_DEFAULT_SCOPE + if (dst->sin6_scope_id == 0) { /* not change if specified */ + dst->sin6_scope_id = scope6_addr2default(&dst->sin6_addr); + } +#endif return rip6_output(m, so, dst, control); } @@ -694,6 +710,6 @@ struct pr_usrreqs rip6_usrreqs = { rip6_abort, pru_accept_notsupp, rip6_attach, rip6_bind, rip6_connect, pru_connect2_notsupp, in6_control, rip6_detach, rip6_disconnect, pru_listen_notsupp, in6_setpeeraddr, pru_rcvd_notsupp, - pru_rcvoob_notsupp, rip6_send, pru_sense_null, rip6_shutdown, + pru_rcvoob_notsupp, rip6_send, pru_sense_null, rip6_shutdown, in6_setsockaddr, sosend, soreceive, sopoll }; diff --git a/bsd/netinet6/raw_ip6.h b/bsd/netinet6/raw_ip6.h new file mode 100644 index 000000000..879428b11 --- /dev/null +++ b/bsd/netinet6/raw_ip6.h @@ -0,0 +1,57 @@ +/* $FreeBSD: src/sys/netinet6/raw_ip6.h,v 1.1.2.1 2001/07/03 11:01:55 ume Exp $ */ +/* $KAME: raw_ip6.h,v 1.2 2001/05/27 13:28:35 itojun Exp $ */ + +/* + * Copyright (C) 2001 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _NETINET6_RAW_IP6_H_ +#define _NETINET6_RAW_IP6_H_ +#include + +/* + * ICMPv6 stat is counted separately. see netinet/icmp6.h + */ +struct rip6stat { + u_quad_t rip6s_ipackets; /* total input packets */ + u_quad_t rip6s_isum; /* input checksum computations */ + u_quad_t rip6s_badsum; /* of above, checksum error */ + u_quad_t rip6s_nosock; /* no matching socket */ + u_quad_t rip6s_nosockmcast; /* of above, arrived as multicast */ + u_quad_t rip6s_fullsock; /* not delivered, input socket full */ + + u_quad_t rip6s_opackets; /* total output packets */ +}; + +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE +extern struct rip6stat rip6stat; +#endif +#endif + +#endif diff --git a/bsd/netinet6/route6.c b/bsd/netinet6/route6.c index 25d86cf55..7867df06f 100644 --- a/bsd/netinet6/route6.c +++ b/bsd/netinet6/route6.c @@ -1,4 +1,5 @@ -/* $KAME: route6.c,v 1.10 2000/02/22 14:04:34 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/route6.c,v 1.1.2.3 2001/07/03 11:01:55 ume Exp $ */ +/* $KAME: route6.c,v 1.24 2001/03/14 03:07:05 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -32,6 +33,7 @@ #include #include #include +#include #include @@ -42,24 +44,30 @@ #include -#if MIP6 -#include -#include -#endif - static int ip6_rthdr0 __P((struct mbuf *, struct ip6_hdr *, struct ip6_rthdr0 *)); - int route6_input(mp, offp, proto) struct mbuf **mp; int *offp, proto; /* proto is unused */ { - register struct ip6_hdr *ip6; - register struct mbuf *m = *mp; - register struct ip6_rthdr *rh; + struct ip6_hdr *ip6; + struct mbuf *m = *mp; + struct ip6_rthdr *rh; int off = *offp, rhlen; + struct mbuf *n; + + n = ip6_findaux(m); + if (n) { + struct ip6aux *ip6a = mtod(n, struct ip6aux *); + /* XXX reject home-address option before rthdr */ + if (ip6a->ip6a_flags & IP6A_SWAP) { + ip6stat.ip6s_badoptions++; + m_freem(m); + return IPPROTO_DONE; + } + } #ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, sizeof(*rh), IPPROTO_DONE); @@ -74,39 +82,55 @@ route6_input(mp, offp, proto) } #endif - switch(rh->ip6r_type) { - case IPV6_RTHDR_TYPE_0: - rhlen = (rh->ip6r_len + 1) << 3; + switch (rh->ip6r_type) { + case IPV6_RTHDR_TYPE_0: + rhlen = (rh->ip6r_len + 1) << 3; #ifndef PULLDOWN_TEST - IP6_EXTHDR_CHECK(m, off, rhlen, IPPROTO_DONE); + /* + * note on option length: + * due to IP6_EXTHDR_CHECK assumption, we cannot handle + * very big routing header (max rhlen == 2048). + */ + IP6_EXTHDR_CHECK(m, off, rhlen, IPPROTO_DONE); #else - IP6_EXTHDR_GET(rh, struct ip6_rthdr *, m, off, rhlen); - if (rh == NULL) { + /* + * note on option length: + * maximum rhlen: 2048 + * max mbuf m_pulldown can handle: MCLBYTES == usually 2048 + * so, here we are assuming that m_pulldown can handle + * rhlen == 2048 case. this may not be a good thing to + * assume - we may want to avoid pulling it up altogether. + */ + IP6_EXTHDR_GET(rh, struct ip6_rthdr *, m, off, rhlen); + if (rh == NULL) { ip6stat.ip6s_tooshort++; return IPPROTO_DONE; - } + } #endif - if (ip6_rthdr0(m, ip6, (struct ip6_rthdr0 *)rh)) - return(IPPROTO_DONE); - break; - default: - /* unknown routing type */ - if (rh->ip6r_segleft == 0) { - rhlen = (rh->ip6r_len + 1) << 3; - break; /* Final dst. Just ignore the header. */ - } - ip6stat.ip6s_badoptions++; - icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, - (caddr_t)&rh->ip6r_type - (caddr_t)ip6); - return(IPPROTO_DONE); - } - + if (ip6_rthdr0(m, ip6, (struct ip6_rthdr0 *)rh)) + return(IPPROTO_DONE); + break; + default: + /* unknown routing type */ + if (rh->ip6r_segleft == 0) { + rhlen = (rh->ip6r_len + 1) << 3; + break; /* Final dst. Just ignore the header. */ + } + ip6stat.ip6s_badoptions++; + icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, + (caddr_t)&rh->ip6r_type - (caddr_t)ip6); + return(IPPROTO_DONE); + } + *offp += rhlen; return(rh->ip6r_nxt); } /* * Type0 routing header processing + * + * RFC2292 backward compatibility warning: no support for strict/loose bitmap, + * as it was dropped between RFC1883 and RFC2460. */ static int ip6_rthdr0(m, ip6, rh0) @@ -145,7 +169,8 @@ ip6_rthdr0(m, ip6, rh0) index = addrs - rh0->ip6r0_segleft; rh0->ip6r0_segleft--; - nextaddr = ((struct in6_addr *)(rh0 + 1)) + index; + /* note that ip6r0_addr does not exist in RFC2292bis */ + nextaddr = rh0->ip6r0_addr + index; /* * reject invalid addresses. be proactive about malicious use of @@ -163,7 +188,7 @@ ip6_rthdr0(m, ip6, rh0) if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst) || IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst) || - IN6_IS_ADDR_V4COMPAT(nextaddr)) { + IN6_IS_ADDR_V4COMPAT(&ip6->ip6_dst)) { ip6stat.ip6s_badoptions++; m_freem(m); return(-1); diff --git a/bsd/netinet6/scope6.c b/bsd/netinet6/scope6.c new file mode 100644 index 000000000..2a9e9ce0f --- /dev/null +++ b/bsd/netinet6/scope6.c @@ -0,0 +1,303 @@ +/* $FreeBSD: src/sys/netinet6/scope6.c,v 1.1.2.2 2001/07/03 11:01:55 ume Exp $ */ +/* $KAME: scope6.c,v 1.10 2000/07/24 13:29:31 itojun Exp $ */ + +/* + * Copyright (C) 2000 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +struct scope6_id { + /* + * 16 is correspondent to 4bit multicast scope field. + * i.e. from node-local to global with some reserved/unassigned types. + */ + u_int32_t s6id_list[16]; +}; +static size_t if_indexlim = 8; +struct scope6_id *scope6_ids = NULL; + +void +scope6_ifattach(ifp) + struct ifnet *ifp; +{ + int s = splnet(); + + /* + * We have some arrays that should be indexed by if_index. + * since if_index will grow dynamically, they should grow too. + */ + if (scope6_ids == NULL || if_index >= if_indexlim) { + size_t n; + caddr_t q; + + while (if_index >= if_indexlim) + if_indexlim <<= 1; + + /* grow scope index array */ + n = if_indexlim * sizeof(struct scope6_id); + /* XXX: need new malloc type? */ + q = (caddr_t)_MALLOC(n, M_IFADDR, M_WAITOK); + bzero(q, n); + if (scope6_ids) { + bcopy((caddr_t)scope6_ids, q, n/2); + FREE((caddr_t)scope6_ids, M_IFADDR); + } + scope6_ids = (struct scope6_id *)q; + } + +#define SID scope6_ids[ifp->if_index] + + /* don't initialize if called twice */ + if (SID.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL]) { + splx(s); + return; + } + + /* + * XXX: IPV6_ADDR_SCOPE_xxx macros are not standard. + * Should we rather hardcode here? + */ + SID.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = ifp->if_index; +#if MULTI_SCOPE + /* by default, we don't care about scope boundary for these scopes. */ + SID.s6id_list[IPV6_ADDR_SCOPE_SITELOCAL] = 1; + SID.s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL] = 1; +#endif +#undef SID + + splx(s); +} + +int +scope6_set(ifp, idlist) + struct ifnet *ifp; + u_int32_t *idlist; +{ + int i, s; + int error = 0; + + if (scope6_ids == NULL) /* paranoid? */ + return(EINVAL); + + /* + * XXX: We need more consistency checks of the relationship among + * scopes (e.g. an organization should be larger than a site). + */ + + /* + * TODO(XXX): after setting, we should reflect the changes to + * interface addresses, routing table entries, PCB entries... + */ + + s = splnet(); + + for (i = 0; i < 16; i++) { + if (idlist[i] && + idlist[i] != scope6_ids[ifp->if_index].s6id_list[i]) { + if (i == IPV6_ADDR_SCOPE_LINKLOCAL && + idlist[i] > if_index) { + /* + * XXX: theoretically, there should be no + * relationship between link IDs and interface + * IDs, but we check the consistency for + * safety in later use. + */ + splx(s); + return(EINVAL); + } + + /* + * XXX: we must need lots of work in this case, + * but we simply set the new value in this initial + * implementation. + */ + scope6_ids[ifp->if_index].s6id_list[i] = idlist[i]; + } + } + splx(s); + + return(error); +} + +int +scope6_get(ifp, idlist) + struct ifnet *ifp; + u_int32_t *idlist; +{ + if (scope6_ids == NULL) /* paranoid? */ + return(EINVAL); + + bcopy(scope6_ids[ifp->if_index].s6id_list, idlist, + sizeof(scope6_ids[ifp->if_index].s6id_list)); + + return(0); +} + + +/* + * Get a scope of the address. Node-local, link-local, site-local or global. + */ +int +in6_addrscope(addr) +struct in6_addr *addr; +{ + int scope; + + if (addr->s6_addr8[0] == 0xfe) { + scope = addr->s6_addr8[1] & 0xc0; + + switch (scope) { + case 0x80: + return IPV6_ADDR_SCOPE_LINKLOCAL; + break; + case 0xc0: + return IPV6_ADDR_SCOPE_SITELOCAL; + break; + default: + return IPV6_ADDR_SCOPE_GLOBAL; /* just in case */ + break; + } + } + + + if (addr->s6_addr8[0] == 0xff) { + scope = addr->s6_addr8[1] & 0x0f; + + /* + * due to other scope such as reserved, + * return scope doesn't work. + */ + switch (scope) { + case IPV6_ADDR_SCOPE_NODELOCAL: + return IPV6_ADDR_SCOPE_NODELOCAL; + break; + case IPV6_ADDR_SCOPE_LINKLOCAL: + return IPV6_ADDR_SCOPE_LINKLOCAL; + break; + case IPV6_ADDR_SCOPE_SITELOCAL: + return IPV6_ADDR_SCOPE_SITELOCAL; + break; + default: + return IPV6_ADDR_SCOPE_GLOBAL; + break; + } + } + + if (bcmp(&in6addr_loopback, addr, sizeof(addr) - 1) == 0) { + if (addr->s6_addr8[15] == 1) /* loopback */ + return IPV6_ADDR_SCOPE_NODELOCAL; + if (addr->s6_addr8[15] == 0) /* unspecified */ + return IPV6_ADDR_SCOPE_LINKLOCAL; + } + + return IPV6_ADDR_SCOPE_GLOBAL; +} + +int +in6_addr2scopeid(ifp, addr) + struct ifnet *ifp; /* must not be NULL */ + struct in6_addr *addr; /* must not be NULL */ +{ + int scope = in6_addrscope(addr); + + if (scope6_ids == NULL) /* paranoid? */ + return(0); /* XXX */ + if (ifp->if_index >= if_indexlim) + return(0); /* XXX */ + +#define SID scope6_ids[ifp->if_index] + switch(scope) { + case IPV6_ADDR_SCOPE_NODELOCAL: + return(-1); /* XXX: is this an appropriate value? */ + + case IPV6_ADDR_SCOPE_LINKLOCAL: + return(SID.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL]); + + case IPV6_ADDR_SCOPE_SITELOCAL: + return(SID.s6id_list[IPV6_ADDR_SCOPE_SITELOCAL]); + + case IPV6_ADDR_SCOPE_ORGLOCAL: + return(SID.s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL]); + + default: + return(0); /* XXX: treat as global. */ + } +#undef SID +} + +void +scope6_setdefault(ifp) + struct ifnet *ifp; /* note that this might be NULL */ +{ + /* + * Currently, this function just set the default "link" according to + * the given interface. + * We might eventually have to separate the notion of "link" from + * "interface" and provide a user interface to set the default. + */ + if (ifp) { + scope6_ids[0].s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = + ifp->if_index; + } + else + scope6_ids[0].s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = 0; +} + +int +scope6_get_default(idlist) + u_int32_t *idlist; +{ + if (scope6_ids == NULL) /* paranoid? */ + return(EINVAL); + + bcopy(scope6_ids[0].s6id_list, idlist, + sizeof(scope6_ids[0].s6id_list)); + + return(0); +} + +u_int32_t +scope6_addr2default(addr) + struct in6_addr *addr; +{ + return(scope6_ids[0].s6id_list[in6_addrscope(addr)]); +} diff --git a/bsd/netinet6/scope6_var.h b/bsd/netinet6/scope6_var.h new file mode 100644 index 000000000..5831fde09 --- /dev/null +++ b/bsd/netinet6/scope6_var.h @@ -0,0 +1,49 @@ +/* $FreeBSD: src/sys/netinet6/scope6_var.h,v 1.1.2.1 2000/07/15 07:14:38 kris Exp $ */ +/* $KAME: scope6_var.h,v 1.4 2000/05/18 15:03:27 jinmei Exp $ */ + +/* + * Copyright (C) 2000 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _NETINET6_SCOPE6_VAR_H_ +#define _NETINET6_SCOPE6_VAR_H_ +#include + +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE +void scope6_ifattach __P((struct ifnet *)); +int scope6_set __P((struct ifnet *, u_int32_t *)); +int scope6_get __P((struct ifnet *, u_int32_t *)); +void scope6_setdefault __P((struct ifnet *)); +int scope6_get_default __P((u_int32_t *)); +u_int32_t scope6_in6_addrscope __P((struct in6_addr *)); +u_int32_t scope6_addr2default __P((struct in6_addr *)); +#endif /* __APPLE_API_PRIVATE */ +#endif /* KERNEL */ + +#endif /* _NETINET6_SCOPE6_VAR_H_ */ diff --git a/bsd/netinet6/tcp6_var.h b/bsd/netinet6/tcp6_var.h new file mode 100644 index 000000000..8e1fce90a --- /dev/null +++ b/bsd/netinet6/tcp6_var.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/netinet6/tcp6_var.h,v 1.3.2.1 2000/07/15 07:14:38 kris Exp $ + */ + +/* + * Copyright (c) 1982, 1986, 1993, 1994, 1995 + * 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. + * + * @(#)tcp_var.h 8.4 (Berkeley) 5/24/95 + * $FreeBSD: src/sys/netinet6/tcp6_var.h,v 1.3.2.1 2000/07/15 07:14:38 kris Exp $ + */ + +#ifndef _NETINET_TCP6_VAR_H_ +#define _NETINET_TCP6_VAR_H_ +#include + +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE +#ifdef SYSCTL_DECL +SYSCTL_DECL(_net_inet6_tcp6); +#endif + +extern int tcp_v6mssdflt; /* XXX */ + +struct ip6_hdr; +void tcp6_ctlinput __P((int, struct sockaddr *, void *)); +void tcp6_init __P((void)); +int tcp6_input __P((struct mbuf **, int *, int)); +struct rtentry *tcp_rtlookup6 __P((struct inpcb *)); + +extern struct pr_usrreqs tcp6_usrreqs; + +#endif /* __APPLE_API_PRIVATE */ +#endif /* KERNEL */ + +#endif /* _NETINET_TCP6_VAR_H_ */ diff --git a/bsd/netinet6/udp6.h b/bsd/netinet6/udp6.h deleted file mode 100644 index 8e8b9b028..000000000 --- a/bsd/netinet6/udp6.h +++ /dev/null @@ -1,38 +0,0 @@ -/* $KAME: udp6.h,v 1.2 2000/02/22 14:04:37 itojun Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _NETINET6_UDP6_H_ -#define _NETINET6_UDP6_H_ - -#include - -#endif /*_NETINET6_UDP6_H_*/ - diff --git a/bsd/netinet6/udp6_output.c b/bsd/netinet6/udp6_output.c new file mode 100644 index 000000000..8d8c6df34 --- /dev/null +++ b/bsd/netinet6/udp6_output.c @@ -0,0 +1,322 @@ +/* $FreeBSD: src/sys/netinet6/udp6_output.c,v 1.1.2.3 2001/08/31 13:49:58 jlemon Exp $ */ +/* $KAME: udp6_output.c,v 1.31 2001/05/21 16:39:15 jinmei Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 1982, 1986, 1989, 1993 + * 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. + * + * @(#)udp_var.h 8.1 (Berkeley) 6/10/93 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef IPSEC +#include +#ifdef INET6 +#include +#endif +extern int ipsec_bypass; +#endif /*IPSEC*/ + +#include "faith.h" + +#include + +/* + * UDP protocol inplementation. + * Per RFC 768, August, 1980. + */ + +#define in6pcb inpcb +#define udp6stat udpstat +#define udp6s_opackets udps_opackets + +int +udp6_output(in6p, m, addr6, control, p) + struct in6pcb *in6p; + struct mbuf *m; + struct mbuf *control; + struct sockaddr *addr6; + struct proc *p; +{ + u_int32_t ulen = m->m_pkthdr.len; + u_int32_t plen = sizeof(struct udphdr) + ulen; + struct ip6_hdr *ip6; + struct udphdr *udp6; + struct in6_addr *laddr, *faddr; + u_short fport; + int error = 0; + struct ip6_pktopts opt, *stickyopt = in6p->in6p_outputopts; + int priv; + int af = AF_INET6, hlen = sizeof(struct ip6_hdr); + int flags; + struct sockaddr_in6 tmp; + + priv = 0; +#ifdef __APPLE__ + if (p && !suser(p->p_ucred, &p->p_acflag)) +#else + if (p && !suser(p)) +#endif + priv = 1; + if (control) { + if ((error = ip6_setpktoptions(control, &opt, priv, 0)) != 0) + goto release; + in6p->in6p_outputopts = &opt; + } + + if (addr6) { + /* + * IPv4 version of udp_output calls in_pcbconnect in this case, + * which needs splnet and affects performance. + * Since we saw no essential reason for calling in_pcbconnect, + * we get rid of such kind of logic, and call in6_selectsrc + * and in6_pcbsetport in order to fill in the local address + * and the local port. + */ + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr6; + if (sin6->sin6_port == 0) { + error = EADDRNOTAVAIL; + goto release; + } + + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { + /* how about ::ffff:0.0.0.0 case? */ + error = EISCONN; + goto release; + } + + /* protect *sin6 from overwrites */ + tmp = *sin6; + sin6 = &tmp; + + faddr = &sin6->sin6_addr; + fport = sin6->sin6_port; /* allow 0 port */ + + if (IN6_IS_ADDR_V4MAPPED(faddr)) { + if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY)) { + /* + * I believe we should explicitly discard the + * packet when mapped addresses are disabled, + * rather than send the packet as an IPv6 one. + * If we chose the latter approach, the packet + * might be sent out on the wire based on the + * default route, the situation which we'd + * probably want to avoid. + * (20010421 jinmei@kame.net) + */ + error = EINVAL; + goto release; + } else + af = AF_INET; + } + + /* KAME hack: embed scopeid */ + if (in6_embedscope(&sin6->sin6_addr, sin6, in6p, NULL) != 0) { + error = EINVAL; + goto release; + } + + if (!IN6_IS_ADDR_V4MAPPED(faddr)) { + laddr = in6_selectsrc(sin6, in6p->in6p_outputopts, + in6p->in6p_moptions, + &in6p->in6p_route, + &in6p->in6p_laddr, &error); + } else + laddr = &in6p->in6p_laddr; /* XXX */ + if (laddr == NULL) { + if (error == 0) + error = EADDRNOTAVAIL; + goto release; + } + if (in6p->in6p_lport == 0 && + (error = in6_pcbsetport(laddr, in6p, p)) != 0) + goto release; + } else { + if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { + error = ENOTCONN; + goto release; + } + if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_faddr)) { + if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY)) { + /* + * XXX: this case would happen when the + * application sets the V6ONLY flag after + * connecting the foreign address. + * Such applications should be fixed, + * so we bark here. + */ + log(LOG_INFO, "udp6_output: IPV6_V6ONLY " + "option was set for a connected socket\n"); + error = EINVAL; + goto release; + } else + af = AF_INET; + } + laddr = &in6p->in6p_laddr; + faddr = &in6p->in6p_faddr; + fport = in6p->in6p_fport; + } + + if (af == AF_INET) + hlen = sizeof(struct ip); + + /* + * Calculate data length and get a mbuf + * for UDP and IP6 headers. + */ + M_PREPEND(m, hlen + sizeof(struct udphdr), M_DONTWAIT); + if (m == 0) { + error = ENOBUFS; + goto release; + } + + /* + * Stuff checksum and output datagram. + */ + udp6 = (struct udphdr *)(mtod(m, caddr_t) + hlen); + udp6->uh_sport = in6p->in6p_lport; /* lport is always set in the PCB */ + udp6->uh_dport = fport; + if (plen <= 0xffff) + udp6->uh_ulen = htons((u_short)plen); + else + udp6->uh_ulen = 0; + udp6->uh_sum = 0; + + switch (af) { + case AF_INET6: + ip6 = mtod(m, struct ip6_hdr *); + ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK; + ip6->ip6_vfc &= ~IPV6_VERSION_MASK; + ip6->ip6_vfc |= IPV6_VERSION; +#if 0 /* ip6_plen will be filled in ip6_output. */ + ip6->ip6_plen = htons((u_short)plen); +#endif + ip6->ip6_nxt = IPPROTO_UDP; + ip6->ip6_hlim = in6_selecthlim(in6p, + in6p->in6p_route.ro_rt ? + in6p->in6p_route.ro_rt->rt_ifp : NULL); + ip6->ip6_src = *laddr; + ip6->ip6_dst = *faddr; + + if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP, + sizeof(struct ip6_hdr), plen)) == 0) { + udp6->uh_sum = 0xffff; + } + + flags = 0; + + udp6stat.udp6s_opackets++; +#ifdef IPSEC + if (ipsec_bypass == 0 && ipsec_setsocket(m, in6p->in6p_socket) != 0) { + error = ENOBUFS; + goto release; + } +#endif /*IPSEC*/ + error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route, + flags, in6p->in6p_moptions, NULL); + break; + case AF_INET: + error = EAFNOSUPPORT; + goto release; + } + goto releaseopt; + +release: + m_freem(m); + +releaseopt: + if (control) { + ip6_clearpktopts(in6p->in6p_outputopts, 0, -1); + in6p->in6p_outputopts = stickyopt; + m_freem(control); + } + return(error); +} diff --git a/bsd/netinet6/udp6_usrreq.c b/bsd/netinet6/udp6_usrreq.c index c6bfcc685..a6a5951dc 100644 --- a/bsd/netinet6/udp6_usrreq.c +++ b/bsd/netinet6/udp6_usrreq.c @@ -1,4 +1,5 @@ -/* $KAME: udp6_usrreq.c,v 1.25 2000/04/04 11:18:10 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/udp6_usrreq.c,v 1.6.2.6 2001/07/29 19:32:40 ume Exp $ */ +/* $KAME: udp6_usrreq.c,v 1.27 2001/05/21 05:45:10 jinmei Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -63,9 +64,6 @@ * * @(#)udp_var.h 8.1 (Berkeley) 6/10/93 */ -#if BSD310 -#include "opt_inet.h" -#endif #include #include @@ -102,9 +100,14 @@ #if IPSEC #include +#include +extern int ipsec_bypass; #endif /*IPSEC*/ #include "faith.h" +#if defined(NFAITH) && NFAITH > 0 +#include +#endif /* * UDP protocol inplementation. @@ -147,26 +150,25 @@ udp6_input(mp, offp, proto) register struct ip6_hdr *ip6; register struct udphdr *uh; register struct inpcb *in6p; - struct ip6_recvpktopts opts; + struct mbuf *opts = NULL; int off = *offp; int plen, ulen; struct sockaddr_in6 udp_in6; + IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE); + + ip6 = mtod(m, struct ip6_hdr *); + #if defined(NFAITH) && 0 < NFAITH - if (m->m_pkthdr.rcvif) { - if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) { - /* XXX send icmp6 host/port unreach? */ - m_freem(m); - return IPPROTO_DONE; - } + if (faithprefix(&ip6->ip6_dst)) { + /* XXX send icmp6 host/port unreach? */ + m_freem(m); + return IPPROTO_DONE; } #endif - udpstat.udps_ipackets++; - bzero(&opts, sizeof(opts)); - IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE); + udpstat.udps_ipackets++; - ip6 = mtod(m, struct ip6_hdr *); plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6); uh = (struct udphdr *)((caddr_t)ip6 + off); ulen = ntohs((u_short)uh->uh_ulen); @@ -179,8 +181,10 @@ udp6_input(mp, offp, proto) /* * Checksum extended UDP header and data. */ -// if (uh->uh_sum == 0) -// udpstat.udps_nosum++; +#ifndef __APPLE__ + if (uh->uh_sum == 0) + udpstat.udps_nosum++; +#endif else if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) { udpstat.udps_badsum++; goto bad; @@ -256,7 +260,7 @@ udp6_input(mp, offp, proto) /* * Check AH/ESP integrity. */ - if (ipsec6_in_reject_so(m, last->inp_socket)) + if (ipsec_bypass == 0 && ipsec6_in_reject_so(m, last->inp_socket)) ipsec6stat.in_polvio++; /* do not inject data into pcb */ else @@ -271,20 +275,20 @@ udp6_input(mp, offp, proto) */ if (last->in6p_flags & IN6P_CONTROLOPTS || last->in6p_socket->so_options & SO_TIMESTAMP) - ip6_savecontrol(last, ip6, n, - &opts, NULL); + ip6_savecontrol(last, &opts, + ip6, n); m_adj(n, off + sizeof(struct udphdr)); if (sbappendaddr(&last->in6p_socket->so_rcv, (struct sockaddr *)&udp_in6, - n, opts.head) == 0) { + n, opts) == 0) { m_freem(n); - if (opts.head) - m_freem(opts.head); + if (opts) + m_freem(opts); udpstat.udps_fullsock++; } else sorwakeup(last->in6p_socket); - bzero(&opts, sizeof(opts)); + opts = NULL; } } last = in6p; @@ -308,26 +312,28 @@ udp6_input(mp, offp, proto) * for a broadcast or multicast datgram.) */ udpstat.udps_noport++; -// udpstat.udps_noportmcast++; +#ifndef __APPLE__ + udpstat.udps_noportmcast++; +#endif goto bad; } #if IPSEC /* * Check AH/ESP integrity. */ - if (ipsec6_in_reject_so(m, last->inp_socket)) { + if (ipsec_bypass == 0 && ipsec6_in_reject_so(m, last->inp_socket)) { ipsec6stat.in_polvio++; goto bad; } #endif /*IPSEC*/ if (last->in6p_flags & IN6P_CONTROLOPTS || last->in6p_socket->so_options & SO_TIMESTAMP) - ip6_savecontrol(last, ip6, m, &opts, NULL); + ip6_savecontrol(last, &opts, ip6, m); m_adj(m, off + sizeof(struct udphdr)); if (sbappendaddr(&last->in6p_socket->so_rcv, (struct sockaddr *)&udp_in6, - m, opts.head) == 0) { + m, opts) == 0) { udpstat.udps_fullsock++; goto bad; } @@ -353,7 +359,9 @@ udp6_input(mp, offp, proto) udpstat.udps_noport++; if (m->m_flags & M_MCAST) { printf("UDP6: M_MCAST is set in a unicast packet.\n"); -// udpstat.udps_noportmcast++; +#ifndef __APPLE__ + udpstat.udps_noportmcast++; +#endif goto bad; } icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0); @@ -363,7 +371,7 @@ udp6_input(mp, offp, proto) /* * Check AH/ESP integrity. */ - if (ipsec6_in_reject_so(m, in6p->in6p_socket)) { + if (ipsec_bypass == 0 && ipsec6_in_reject_so(m, in6p->in6p_socket)) { ipsec6stat.in_polvio++; goto bad; } @@ -377,11 +385,11 @@ udp6_input(mp, offp, proto) udp_in6.sin6_port = uh->uh_sport; if (in6p->in6p_flags & IN6P_CONTROLOPTS || in6p->in6p_socket->so_options & SO_TIMESTAMP) - ip6_savecontrol(in6p, ip6, m, &opts, NULL); + ip6_savecontrol(in6p, &opts, ip6, m); m_adj(m, off + sizeof(struct udphdr)); if (sbappendaddr(&in6p->in6p_socket->so_rcv, (struct sockaddr *)&udp_in6, - m, opts.head) == 0) { + m, opts) == 0) { udpstat.udps_fullsock++; goto bad; } @@ -390,8 +398,8 @@ udp6_input(mp, offp, proto) bad: if (m) m_freem(m); - if (opts.head) - m_freem(opts.head); + if (opts) + m_freem(opts); return IPPROTO_DONE; } @@ -401,13 +409,17 @@ udp6_ctlinput(cmd, sa, d) struct sockaddr *sa; void *d; { - register struct udphdr *uhp; struct udphdr uh; - struct sockaddr_in6 sa6; struct ip6_hdr *ip6; struct mbuf *m; int off = 0; + struct ip6ctlparam *ip6cp = NULL; + const struct sockaddr_in6 *sa6_src = NULL; void (*notify) __P((struct inpcb *, int)) = udp_notify; + struct udp_portonly { + u_int16_t uh_sport; + u_int16_t uh_dport; + } *uhp; if (sa->sa_family != AF_INET6 || sa->sa_len != sizeof(struct sockaddr_in6)) @@ -424,49 +436,39 @@ udp6_ctlinput(cmd, sa, d) /* if the parameter is from icmp6, decode it. */ if (d != NULL) { - struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d; + ip6cp = (struct ip6ctlparam *)d; m = ip6cp->ip6c_m; ip6 = ip6cp->ip6c_ip6; off = ip6cp->ip6c_off; + sa6_src = ip6cp->ip6c_src; } else { m = NULL; ip6 = NULL; + sa6_src = &sa6_any; } - /* translate addresses into internal form */ - sa6 = *(struct sockaddr_in6 *)sa; - if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) && m && m->m_pkthdr.rcvif) - sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); - if (ip6) { /* * XXX: We assume that when IPV6 is non NULL, * M and OFF are valid. */ - struct in6_addr s; - /* translate addresses into internal form */ - memcpy(&s, &ip6->ip6_src, sizeof(s)); - if (IN6_IS_ADDR_LINKLOCAL(&s)) - s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); + /* check if we can safely examine src and dst ports */ + if (m->m_pkthdr.len < off + sizeof(*uhp)) + return; - if (m->m_len < off + sizeof(uh)) { - /* - * this should be rare case, - * so we compromise on this copy... - */ - m_copydata(m, off, sizeof(uh), (caddr_t)&uh); - uhp = &uh; - } else - uhp = (struct udphdr *)(mtod(m, caddr_t) + off); - (void) in6_pcbnotify(&udb, (struct sockaddr *)&sa6, - uhp->uh_dport, &s, - uhp->uh_sport, cmd, notify); + bzero(&uh, sizeof(uh)); + m_copydata(m, off, sizeof(*uhp), (caddr_t)&uh); + + (void) in6_pcbnotify(&udb, sa, uh.uh_dport, + (struct sockaddr*)ip6cp->ip6c_src, + uh.uh_sport, cmd, notify); } else - (void) in6_pcbnotify(&udb, (struct sockaddr *)&sa6, 0, - &zeroin6_addr, 0, cmd, notify); + (void) in6_pcbnotify(&udb, sa, 0, (struct sockaddr *)&sa6_src, + 0, cmd, notify); } -#if 0 + +#ifndef __APPLE__ static int udp6_getcred SYSCTL_HANDLER_ARGS { @@ -506,128 +508,6 @@ SYSCTL_PROC(_net_inet6_udp6, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW, 0, 0, udp6_getcred, "S,ucred", "Get the ucred of a UDP6 connection"); #endif -int -udp6_output(in6p, m, addr6, control, p) - register struct inpcb *in6p; - register struct mbuf *m; - struct sockaddr *addr6; - struct mbuf *control; - struct proc *p; -{ - register int ulen = m->m_pkthdr.len; - int plen = sizeof(struct udphdr) + ulen; - struct ip6_hdr *ip6; - struct udphdr *udp6; - struct in6_addr laddr6; - int s = 0, error = 0; - struct ip6_pktopts opt, *stickyopt = in6p->in6p_outputopts; - int flags; - - if (control) { - if (error = ip6_setpktoptions(control, &opt, - p && - suser(p->p_ucred, &p->p_acflag), 0)) - goto release; - in6p->in6p_outputopts = &opt; - } - - if (addr6) { - laddr6 = in6p->in6p_laddr; - if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { - error = EISCONN; - goto release; - } - /* - * Must block input while temporarily connected. - */ - s = splnet(); - /* - * XXX: the user might want to overwrite the local address - * via an ancillary data. - */ - bzero(&in6p->in6p_laddr, sizeof(struct in6_addr)); - error = in6_pcbconnect(in6p, addr6, p); - if (error) { - splx(s); - goto release; - } - } else { - if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { - error = ENOTCONN; - goto release; - } - } - /* - * Calculate data length and get a mbuf - * for UDP and IP6 headers. - */ - M_PREPEND(m, sizeof(struct ip6_hdr) + sizeof(struct udphdr), - M_DONTWAIT); - if (m == 0) { - error = ENOBUFS; - if (addr6) - splx(s); - goto release; - } - - /* - * Stuff checksum and output datagram. - */ - ip6 = mtod(m, struct ip6_hdr *); - ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK; - ip6->ip6_vfc |= IPV6_VERSION; -#if 0 /* ip6_plen will be filled in ip6_output. */ - ip6->ip6_plen = htons((u_short)plen); -#endif - ip6->ip6_nxt = IPPROTO_UDP; - ip6->ip6_hlim = in6_selecthlim(in6p, - in6p->in6p_route.ro_rt ? - in6p->in6p_route.ro_rt->rt_ifp : - NULL); - ip6->ip6_src = in6p->in6p_laddr; - ip6->ip6_dst = in6p->in6p_faddr; - - udp6 = (struct udphdr *)(ip6 + 1); - udp6->uh_sport = in6p->in6p_lport; - udp6->uh_dport = in6p->in6p_fport; - udp6->uh_ulen = htons((u_short)plen); - udp6->uh_sum = 0; - - if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP, - sizeof(struct ip6_hdr), plen)) == 0) { - udp6->uh_sum = 0xffff; - } - - flags = 0; - if (in6p->in6p_flags & IN6P_MINMTU) - flags |= IPV6_MINMTU; - - udpstat.udps_opackets++; - -#if IPSEC - ipsec_setsocket(m, in6p->in6p_socket); -#endif /*IPSEC*/ - error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route, - flags, in6p->in6p_moptions, NULL); - - if (addr6) { - in6_pcbdisconnect(in6p); - in6p->in6p_laddr = laddr6; - splx(s); - } - goto releaseopt; - -release: - m_freem(m); - -releaseopt: - if (control) { - ip6_clearpktopts(in6p->in6p_outputopts, 0, -1); - in6p->in6p_outputopts = stickyopt; - m_freem(control); - } - return(error); -} static int udp6_abort(struct socket *so) @@ -669,13 +549,13 @@ udp6_attach(struct socket *so, int proto, struct proc *p) inp->inp_vflag |= INP_IPV6; inp->in6p_hops = -1; /* use kernel default */ inp->in6p_cksum = -1; /* just to be sure */ -#if IPSEC - error = ipsec_init_policy(so, &inp->in6p_sp); - if (error != 0) { - in6_pcbdetach(inp); - return (error); - } -#endif /*IPSEC*/ + /* + * XXX: ugly!! + * IPv4 TTL initialization is necessary for an IPv6 socket as well, + * because the socket may be bound to an IPv6 wildcard address, + * which may match an IPv4-mapped IPv6 address. + */ + inp->inp_ip_ttl = ip_defttl; return 0; } @@ -691,7 +571,7 @@ udp6_bind(struct socket *so, struct sockaddr *nam, struct proc *p) inp->inp_vflag &= ~INP_IPV4; inp->inp_vflag |= INP_IPV6; - if (ip6_mapped_addr_on && (inp->inp_flags & IN6P_BINDV6ONLY) == 0) { + if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) { struct sockaddr_in6 *sin6_p; sin6_p = (struct sockaddr_in6 *)nam; @@ -727,7 +607,7 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct proc *p) if (inp == 0) return EINVAL; - if (ip6_mapped_addr_on) { + if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) { struct sockaddr_in6 *sin6_p; sin6_p = (struct sockaddr_in6 *)nam; @@ -753,11 +633,6 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct proc *p) return EISCONN; s = splnet(); error = in6_pcbconnect(inp, nam, p); - if (ip6_auto_flowlabel) { - inp->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK; - inp->in6p_flowinfo |= - (htonl(ip6_flow_seq++) & IPV6_FLOWLABEL_MASK); - } splx(s); if (error == 0) { if (ip6_mapped_addr_on) { /* should be non mapped addr */ @@ -817,11 +692,23 @@ udp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, struct mbuf *control, struct proc *p) { struct inpcb *inp; + int error = 0; inp = sotoinpcb(so); if (inp == 0) { - m_freem(m); - return EINVAL; + error = EINVAL; + goto bad; + } + + if (addr) { + if (addr->sa_len != sizeof(struct sockaddr_in6)) { + error = EINVAL; + goto bad; + } + if (addr->sa_family != AF_INET6) { + error = EAFNOSUPPORT; + goto bad; + } } if (ip6_mapped_addr_on) { @@ -837,7 +724,6 @@ udp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, } if (hasv4addr) { struct pr_usrreqs *pru; - int error; if (sin6) in6_sin6_2_sin_in_sock(addr); @@ -850,6 +736,10 @@ udp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, } return udp6_output(inp, m, addr, control, p); + + bad: + m_freem(m); + return(error); } struct pr_usrreqs udp6_usrreqs = { diff --git a/bsd/netinet6/udp6_var.h b/bsd/netinet6/udp6_var.h index d779920ec..9b74ea7c7 100644 --- a/bsd/netinet6/udp6_var.h +++ b/bsd/netinet6/udp6_var.h @@ -1,7 +1,7 @@ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -13,7 +13,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -64,8 +64,12 @@ #ifndef _NETINET6_UDP6_VAR_H_ #define _NETINET6_UDP6_VAR_H_ +#include #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE +SYSCTL_DECL(_net_inet6_udp6); + extern struct pr_usrreqs udp6_usrreqs; void udp6_ctlinput __P((int, struct sockaddr *, void *)); @@ -73,6 +77,7 @@ int udp6_input __P((struct mbuf **, int *, int)); int udp6_output __P((struct inpcb *inp, struct mbuf *m, struct sockaddr *addr, struct mbuf *control, struct proc *p)); -#endif /* KERNEL */ +#endif /* __APPLE_API_PRIVATE */ +#endif #endif /*_NETINET6_UDP6_VAR_H_*/ diff --git a/bsd/netiso/Makefile b/bsd/netiso/Makefile deleted file mode 100644 index 9f704c042..000000000 --- a/bsd/netiso/Makefile +++ /dev/null @@ -1,42 +0,0 @@ -export MakeInc_cmd=${SRCROOT}/makedefs/MakeInc.cmd -export MakeInc_def=${SRCROOT}/makedefs/MakeInc.def -export MakeInc_rule=${SRCROOT}/makedefs/MakeInc.rule -export MakeInc_dir=${SRCROOT}/makedefs/MakeInc.dir - - -include $(MakeInc_cmd) -include $(MakeInc_def) - -INSTINC_SUBDIRS = \ - -INSTINC_SUBDIRS_PPC = \ - -INSTINC_SUBDIRS_I386 = \ - -EXPINC_SUBDIRS = \ - -EXPINC_SUBDIRS_PPC = \ - -EXPINC_SUBDIRS_I386 = \ - -DATAFILES = \ - argo_debug.h clnl.h clnp.h clnp_stat.h cltp_var.h cons.h \ - cons_pcb.h eonvar.h esis.h iso.h iso_errno.h iso_pcb.h \ - iso_snpac.h iso_var.h tp_clnp.h tp_events.h tp_ip.h tp_meas.h \ - tp_param.h tp_pcb.h tp_seq.h tp_stat.h tp_states.h tp_timer.h \ - tp_tpdu.h tp_trace.h tp_user.h tuba_table.h - - -INSTALL_MI_LIST = ${DATAFILES} - -INSTALL_MI_DIR = netiso - -EXPORT_MI_LIST = ${DATAFILES} - -EXPORT_MI_DIR = netiso - - -include $(MakeInc_rule) -include $(MakeInc_dir) - - diff --git a/bsd/netiso/argo_debug.h b/bsd/netiso/argo_debug.h deleted file mode 100644 index 90cc23b34..000000000 --- a/bsd/netiso/argo_debug.h +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)argo_debug.h 8.1 (Berkeley) 6/10/93 - */ - -/***************************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ - -#ifndef __ARGO_DEBUG__ -#define __ARGO_DEBUG__ - -#define dump_buf(a, b) Dump_buf((caddr_t)(a), (int)(b)) - -/*********************************************** - * Lint stuff - **********************************************/ -#if defined(lint) -/* - * lint can't handle the flaky vacuous definitions - * of IFDEBUG, ENDDEBUG, etc. - */ -#endif /* defined(lint) */ - -/*********************************************** - * DEBUG ON: - **********************************************/ -#ifndef ARGO_DEBUG -#define ARGO_DEBUG -#endif /* ARGO_DEBUG */ - - -#ifdef ARGO_DEBUG -#if 0 - #ifndef TPPT - #define TPPT - #endif /* TPPT */ - - #ifndef TP_PERF_MEAS - #define TP_PERF_MEAS - #endif /* TP_PERF_MEAS */ -#endif /* 0 */ - -unsigned char argo_debug[128]; - -#define IFDEBUG(ascii) \ - if(argo_debug[ascii]) { -#define ENDDEBUG ; } - -#else /* ARGO_DEBUG */ - -/*********************************************** - * DEBUG OFF: - **********************************************/ - -#ifndef STAR -#define STAR * -#endif /* STAR */ -#define IFDEBUG(ascii) //*beginning of comment*/STAR -#define ENDDEBUG STAR/*end of comment*// - -#endif /* ARGO_DEBUG */ - -/*********************************************** - * ASSERT - **********************************************/ -#ifdef ARGO_DEBUG - -#ifndef lint -#define ASSERT(phrase) \ -if( !(phrase) ) printf("ASSERTION NOT VALID at line %d file %s\n",__LINE__,__FILE__) -#else /* lint */ -#define ASSERT(phrase) /* phrase */ -#endif /* lint */ - -#else /* ARGO_DEBUG */ - -#define ASSERT(phrase) /* phrase */ - -#endif /* ARGO_DEBUG */ - - -/*********************************************** - * CLNP DEBUG OPTIONS - **********************************************/ -#define D_INPUT '\1' -/* clnp input */ -#define D_OUTPUT '\2' -/* clnp output */ -#define D_ROUTE '\3' -/* clnp routing */ -#define D_CTLINPUT '\4' -/* clnp control input */ -#define D_CTLOUTPUT '\5' -/* clnp control output */ -#define D_OPTIONS '\6' -/* clnp options */ -#define D_IOCTL '\7' -/* iso ioctls */ -#define D_ETHER '\10' -/* clnp over ethernet */ -#define D_TOKEN '\11' -/* clnp over token ring */ -#define D_ADCOM '\12' -/* clnp over the adcom */ -#define D_ISO '\13' -/* iso address family */ -#define D_FORWARD '\14' -/* clnp forwarding */ -#define D_DUMPOUT '\15' -/* dump clnp outgoing packets */ -#define D_DUMPIN '\16' -/* dump clnp input packets */ -#define D_DISCARD '\17' -/* debug clnp packet discard/er function */ -#define D_FRAG '\20' -/* clnp fragmentation */ -#define D_REASS '\21' -/* clnp reassembly */ - -char *clnp_iso_addrp(); - -/*********************************************** - * ESIS DEBUG OPTIONS - **********************************************/ -#define D_ESISOUTPUT '\30' -#define D_ESISINPUT '\31' -#define D_SNPA '\32' - -/*********************************************** - * ISIS DEBUG OPTIONS - **********************************************/ -#define D_ISISOUTPUT '\40' -#define D_ISISINPUT '\41' - -/*********************************************** - * EON DEBUG OPTION - **********************************************/ -#define D_EON '\57' - -/*********************************************** - * CONS DEBUG OPTIONS - **********************************************/ - -#define D_ECNWORK '\60' -#define D_ECNOUT '\61' -#define D_ECNFIN '\62' -#define D_ECNDWN '\63' -#define D_ECNUTIL '\64' - -#define D_INCOMING '\70' -#define D_CDATA '\71' -#define D_CFIND '\72' -#define D_CDUMP_REQ '\73' -#define D_CADDR '\74' -#define D_CCONS '\75' -#define D_CCONN '\76' - - -/*********************************************** - * TP DEBUG OPTIONS - **********************************************/ - -#define D_SETPARAMS '\137' -#define D_RTT '\140' - -#define D_ACKRECV '\141' -#define D_ACKSEND '\142' -#define D_CONN '\143' -#define D_CREDIT '\144' -#define D_DATA '\145' -#define D_DRIVER '\146' - -#define D_EMIT '\147' -#define D_ERROR_EMIT '\150' -#define D_TPINPUT '\151' -#define D_INDICATION '\152' -#define D_CHKSUM '\153' - -#define D_RENEG '\154' -#define D_PERF_MEAS '\155' -#define D_MBUF_MEAS '\156' -#define D_RTC '\157' -#define D_SB '\160' - -#define D_DISASTER_CHECK '\161' -#define D_REQUEST '\162' -#define D_STASH '\163' -#define D_NEWSOCK '\164' -#define D_TIMER '\165' - -#define D_TPIOCTL '\166' -#define D_SIZE_CHECK '\167' -#define D_2ER '\170' -#define D_DISASTER_CHECK_W '\171' - -#define D_XPD '\172' -#define D_SYSCALL '\173' -#define D_DROP '\174' -#define D_ZDREF '\175' -#define D_TPISO '\176' -#define D_QUENCH '\177' - -void dump_mbuf(); - -/*********************************************** - * New mbuf types for debugging w/ netstat -m - * This messes up 4.4 malloc for now. need bigger - * mbtypes array for now. - **********************************************/ -#ifdef notdef - -#define TPMT_DATA 0x21 -#define TPMT_RCVRTC 0x42 -#define TPMT_SNDRTC 0x41 -#define TPMT_TPHDR 0x22 -#define TPMT_IPHDR 0x32 -#define TPMT_SONAME 0x28 -#define TPMT_EOT 0x40 -#define TPMT_XPD 0x44 -#define TPMT_PCB 0x23 -#define TPMT_PERF 0x45 - -#else /* ARGO_DEBUG */ - -#define TPMT_DATA MT_DATA -#define TPMT_RCVRTC MT_DATA -#define TPMT_SNDRTC MT_DATA -#define TPMT_IPHDR MT_HEADER -#define TPMT_TPHDR MT_HEADER -#define TPMT_SONAME MT_SONAME -/* MT_EOT and MT_XPD are defined in tp_param.h */ -#define TPMT_XPD MT_OOBDATA -#define TPMT_PCB MT_PCB -#define TPMT_PERF MT_PCB - -#endif /* ARGO_DEBUG */ - -#endif /* __ARGO_DEBUG__ */ diff --git a/bsd/netiso/clnl.h b/bsd/netiso/clnl.h deleted file mode 100644 index 8e00cebfd..000000000 --- a/bsd/netiso/clnl.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)clnl.h 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -struct clnl_protosw { - int (*clnl_input)(); /* input routine */ -}; diff --git a/bsd/netiso/clnp.h b/bsd/netiso/clnp.h deleted file mode 100644 index 265fac8f2..000000000 --- a/bsd/netiso/clnp.h +++ /dev/null @@ -1,482 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993, 1994 - * 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. - * - * @(#)clnp.h 8.2 (Berkeley) 4/16/94 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ - -/* should be config option but cpp breaks with too many #defines */ -#define DECBIT - -/* - * Return true if the mbuf is a cluster mbuf - */ -#define IS_CLUSTER(m) ((m)->m_flags & M_EXT) - -/* - * Move the halfword into the two characters - */ -#define HTOC(msb, lsb, hword)\ - (msb) = (u_char)((hword) >> 8);\ - (lsb) = (u_char)((hword) & 0xff) -/* - * Move the two charcters into the halfword - */ -#define CTOH(msb, lsb, hword)\ - (hword) = ((msb) << 8) | (lsb) - -/* - * Return true if the checksum has been set - ie. the checksum is - * not zero - */ -#define CKSUM_REQUIRED(clnp)\ - (((clnp)->cnf_cksum_msb != 0) || ((clnp)->cnf_cksum_lsb != 0)) - -/* - * Fixed part of clnp header - */ -struct clnp_fixed { - u_char cnf_proto_id; /* network layer protocol identifier */ - u_char cnf_hdr_len; /* length indicator (octets) */ - u_char cnf_vers; /* version/protocol identifier extension */ - u_char cnf_ttl; /* lifetime (500 milliseconds) */ - u_char cnf_type; /* type code */ - /* Includes err_ok, more_segs, and seg_ok */ - u_char cnf_seglen_msb; /* pdu segment length (octets) high byte */ - u_char cnf_seglen_lsb; /* pdu segment length (octets) low byte */ - u_char cnf_cksum_msb; /* checksum high byte */ - u_char cnf_cksum_lsb; /* checksum low byte */ -}; -#define CNF_TYPE 0x1f -#define CNF_ERR_OK 0x20 -#define CNF_MORE_SEGS 0x40 -#define CNF_SEG_OK 0x80 - -#define CLNP_CKSUM_OFF 0x07 /* offset of checksum */ - -#define clnl_fixed clnp_fixed - -/* - * Segmentation part of clnp header - */ -struct clnp_segment { - u_short cng_id; /* data unit identifier */ - u_short cng_off; /* segment offset */ - u_short cng_tot_len; /* total length */ -}; - -/* - * Clnp fragment reassembly structures: - * - * All packets undergoing reassembly are linked together in - * clnp_fragl structures. Each clnp_fragl structure contains a - * pointer to the original clnp packet header, as well as a - * list of packet fragments. Each packet fragment - * is headed by a clnp_frag structure. This structure contains the - * offset of the first and last byte of the fragment, as well as - * a pointer to the data (an mbuf chain) of the fragment. - */ - -/* - * NOTE: - * The clnp_frag structure is stored in an mbuf immedately preceeding - * the fragment data. Since there are words in this struct, - * it must be word aligned. - * - * NOTE: - * All the fragment code assumes that the entire clnp header is - * contained in the first mbuf. - */ -struct clnp_frag { - u_int cfr_first; /* offset of first byte of this frag */ - u_int cfr_last; /* offset of last byte of this frag */ - u_int cfr_bytes; /* bytes to shave to get to data */ - struct mbuf *cfr_data; /* ptr to data for this frag */ - struct clnp_frag *cfr_next; /* next fragment in list */ -}; - -struct clnp_fragl { - struct iso_addr cfl_src; /* source of the pkt */ - struct iso_addr cfl_dst; /* destination of the pkt */ - u_short cfl_id; /* id of the pkt */ - u_char cfl_ttl; /* current ttl of pkt */ - u_short cfl_last; /* offset of last byte of packet */ - struct mbuf *cfl_orighdr; /* ptr to original header */ - struct clnp_frag *cfl_frags; /* linked list of fragments for pkt */ - struct clnp_fragl *cfl_next; /* next pkt being reassembled */ -}; - -/* - * The following structure is used to index into an options section - * of a clnp datagram. These values can be used without worry that - * offset or length fields are invalid or too big, etc. That is, - * the consistancy of the options will be guaranteed before this - * structure is filled in. Any pointer (field ending in p) is - * actually the offset from the beginning of the mbuf the option - * is contained in. A value of NULL for any pointer - * means that the option is not present. The length any option - * does not include the option code or option length fields. - */ -struct clnp_optidx { - u_short cni_securep; /* ptr to beginning of security option */ - char cni_secure_len; /* length of entire security option */ - - u_short cni_srcrt_s; /* offset of start of src rt option */ - u_short cni_srcrt_len; /* length of entire src rt option */ - - u_short cni_recrtp; /* ptr to beginning of recrt option */ - char cni_recrt_len; /* length of entire recrt option */ - - char cni_priorp; /* ptr to priority option */ - - u_short cni_qos_formatp; /* ptr to format of qos option */ - char cni_qos_len; /* length of entire qos option */ - - u_char cni_er_reason; /* reason from ER pdu option */ - - /* ESIS options */ - - u_short cni_esct; /* value from ISH ESCT option */ - - u_short cni_netmaskp; /* ptr to beginning of netmask option */ - char cni_netmask_len; /* length of entire netmask option */ - - u_short cni_snpamaskp; /* ptr to beginning of snpamask option */ - char cni_snpamask_len; /* length of entire snpamask option */ - -}; - -#define ER_INVALREAS 0xff /* code for invalid ER pdu discard reason */ - -/* given an mbuf and addr of option, return offset from data of mbuf */ -#define CLNP_OPTTOOFF(m, opt)\ - ((u_short) (opt - mtod(m, caddr_t))) - -/* given an mbuf and offset of option, return address of option */ -#define CLNP_OFFTOOPT(m, off)\ - ((caddr_t) (mtod(m, caddr_t) + off)) - -/* return true iff src route is valid */ -#define CLNPSRCRT_VALID(oidx)\ - ((oidx) && (oidx->cni_srcrt_s)) - -/* return the offset field of the src rt */ -#define CLNPSRCRT_OFF(oidx, options)\ - (*((u_char *)(CLNP_OFFTOOPT(options, oidx->cni_srcrt_s) + 1))) - -/* return the type field of the src rt */ -#define CLNPSRCRT_TYPE(oidx, options)\ - ((u_char)(*(CLNP_OFFTOOPT(options, oidx->cni_srcrt_s)))) - -/* return the length of the current address */ -#define CLNPSRCRT_CLEN(oidx, options)\ - ((u_char)(*(CLNP_OFFTOOPT(options, oidx->cni_srcrt_s) + CLNPSRCRT_OFF(oidx, options) - 1))) - -/* return the address of the current address */ -#define CLNPSRCRT_CADDR(oidx, options)\ - ((caddr_t)(CLNP_OFFTOOPT(options, oidx->cni_srcrt_s) + CLNPSRCRT_OFF(oidx, options))) - -/* - * return true if the src route has run out of routes - * this is true if the offset of next route is greater than the end of the rt - */ -#define CLNPSRCRT_TERM(oidx, options)\ - (CLNPSRCRT_OFF(oidx, options) > oidx->cni_srcrt_len) - -/* - * Options a user can set/get - */ -#define CLNPOPT_FLAGS 0x01 /* flags: seg permitted, no er xmit, etc */ -#define CLNPOPT_OPTS 0x02 /* datagram options */ - -/* - * Values for particular datagram options - */ -#define CLNPOVAL_PAD 0xcc /* padding */ -#define CLNPOVAL_SECURE 0xc5 /* security */ -#define CLNPOVAL_SRCRT 0xc8 /* source routing */ -#define CLNPOVAL_RECRT 0xcb /* record route */ -#define CLNPOVAL_QOS 0xc3 /* quality of service */ -#define CLNPOVAL_PRIOR 0xcd /* priority */ -#define CLNPOVAL_ERREAS 0xc1 /* ER PDU ONLY: reason for discard */ - -#define CLNPOVAL_SRCSPEC 0x40 /* source address specific */ -#define CLNPOVAL_DSTSPEC 0x80 /* destination address specific */ -#define CLNPOVAL_GLOBAL 0xc0 /* globally unique */ - -/* Globally Unique QOS */ -#define CLNPOVAL_SEQUENCING 0x10 /* sequencing preferred */ -#define CLNPOVAL_CONGESTED 0x08 /* congestion experienced */ -#define CLNPOVAL_LOWDELAY 0x04 /* low transit delay */ - -#define CLNPOVAL_PARTRT 0x00 /* partial source routing */ -#define CLNPOVAL_COMPRT 0x01 /* complete source routing */ - -/* - * Clnp flags used in a control block flags field. - * NOTE: these must be out of the range of bits defined in ../net/raw_cb.h - */ -#define CLNP_NO_SEG 0x010 /* segmentation not permitted */ -#define CLNP_NO_ER 0x020 /* do not generate ERs */ -#define CLNP_SEND_RAW 0x080 /* send pkt as RAW DT rather than TP DT */ -#define CLNP_NO_CKSUM 0x100 /* don't use clnp checksum */ -#define CLNP_ECHO 0x200 /* send echo request */ -#define CLNP_NOCACHE 0x400 /* don't store cache information */ -#define CLNP_ECHOR 0x800 /* send echo reply */ - -/* valid clnp flags */ -#define CLNP_VFLAGS (CLNP_SEND_RAW|CLNP_NO_SEG|CLNP_NO_ER|CLNP_NO_CKSUM\ - |CLNP_ECHO|CLNP_NOCACHE|CLNP_ECHOR) - -/* - * Constants used by clnp - */ -#define CLNP_HDR_MIN (sizeof (struct clnp_fixed)) -#define CLNP_HDR_MAX (254) -#define CLNP_TTL_UNITS 2 /* 500 milliseconds */ -#define CLNP_TTL 15*CLNP_TTL_UNITS /* time to live (seconds) */ -#define ISO8473_V1 0x01 - -/* - * Clnp packet types - * In order to test raw clnp and tp/clnp simultaneously, a third type of - * packet has been defined: CLNP_RAW. This is done so that the input - * routine can switch to the correct input routine (rclnp_input or - * tpclnp_input) based on the type field. If clnp had a higher level protocol - * field, this would not be necessary. - */ -#define CLNP_DT 0x1C /* normal data */ -#define CLNP_ER 0x01 /* error report */ -#define CLNP_RAW 0x1D /* debug only */ -#define CLNP_EC 0x1E /* echo packet */ -#define CLNP_ECR 0x1F /* echo reply */ - -/* - * ER pdu error codes - */ -#define GEN_NOREAS 0x00 /* reason not specified */ -#define GEN_PROTOERR 0x01 /* protocol procedure error */ -#define GEN_BADCSUM 0x02 /* incorrect checksum */ -#define GEN_CONGEST 0x03 /* pdu discarded due to congestion */ -#define GEN_HDRSYNTAX 0x04 /* header syntax error */ -#define GEN_SEGNEEDED 0x05 /* segmentation needed, but not permitted */ -#define GEN_INCOMPLETE 0x06 /* incomplete pdu received */ -#define GEN_DUPOPT 0x07 /* duplicate option */ - -/* address errors */ -#define ADDR_DESTUNREACH 0x80 /* destination address unreachable */ -#define ADDR_DESTUNKNOWN 0x81 /* destination address unknown */ - -/* source routing */ -#define SRCRT_UNSPECERR 0x90 /* unspecified src rt error */ -#define SRCRT_SYNTAX 0x91 /* syntax error in src rt field */ -#define SRCRT_UNKNOWNADDR 0x92 /* unknown addr in src rt field */ -#define SRCRT_BADPATH 0x93 /* path not acceptable */ - -/* lifetime */ -#define TTL_EXPTRANSIT 0xa0 /* lifetime expired during transit */ -#define TTL_EXPREASS 0xa1 /* lifetime expired during reassembly */ - -/* pdu discarded */ -#define DISC_UNSUPPOPT 0xb0 /* unsupported option not specified? */ -#define DISC_UNSUPPVERS 0xb1 /* unsupported protocol version */ -#define DISC_UNSUPPSECURE 0xb2 /* unsupported security option */ -#define DISC_UNSUPPSRCRT 0xb3 /* unsupported src rt option */ -#define DISC_UNSUPPRECRT 0xb4 /* unsupported rec rt option */ - -/* reassembly */ -#define REASS_INTERFERE 0xc0 /* reassembly interference */ -#define CLNP_ERRORS 22 - - -#ifdef KERNEL -int clnp_er_index(); -#endif - -#ifdef CLNP_ER_CODES -u_char clnp_er_codes[CLNP_ERRORS] = { -GEN_NOREAS, GEN_PROTOERR, GEN_BADCSUM, GEN_CONGEST, -GEN_HDRSYNTAX, GEN_SEGNEEDED, GEN_INCOMPLETE, GEN_DUPOPT, -ADDR_DESTUNREACH, ADDR_DESTUNKNOWN, -SRCRT_UNSPECERR, SRCRT_SYNTAX, SRCRT_UNKNOWNADDR, SRCRT_BADPATH, -TTL_EXPTRANSIT, TTL_EXPREASS, -DISC_UNSUPPOPT, DISC_UNSUPPVERS, DISC_UNSUPPSECURE, -DISC_UNSUPPSRCRT, DISC_UNSUPPRECRT, REASS_INTERFERE }; -#endif - -#ifdef TROLL - -#define TR_DUPEND 0x01 /* duplicate end of fragment */ -#define TR_DUPPKT 0x02 /* duplicate entire packet */ -#define TR_DROPPKT 0x04 /* drop packet on output */ -#define TR_TRIM 0x08 /* trim bytes from packet */ -#define TR_CHANGE 0x10 /* change bytes in packet */ -#define TR_MTU 0x20 /* delta to change device mtu */ -#define TR_CHUCK 0x40 /* drop packet in rclnp_input */ -#define TR_BLAST 0x80 /* force rclnp_output to blast many packet */ -#define TR_RAWLOOP 0x100 /* make if_loop call clnpintr directly */ -struct troll { - int tr_ops; /* operations to perform */ - float tr_dup_size; /* % to duplicate */ - float tr_dup_freq; /* frequency to duplicate packets */ - float tr_drop_freq; /* frequence to drop packets */ - int tr_mtu_adj; /* delta to adjust if mtu */ - int tr_blast_cnt; /* # of pkts to blast out */ -}; - -#define SN_OUTPUT(clcp, m)\ - troll_output(clcp->clc_ifp, m, clcp->clc_firsthop, clcp->clc_rt) - -#define SN_MTU(ifp, rt) (((rt && rt->rt_rmx.rmx_mtu) ?\ - rt->rt_rmx.rmx_mtu : clnp_badmtu(ifp, rt, __LINE__, __FILE__))\ - - trollctl.tr_mtu_adj) - -#ifdef KERNEL -extern float troll_random; -#endif - -#else /* NO TROLL */ - -#define SN_OUTPUT(clcp, m)\ - (*clcp->clc_ifp->if_output)(clcp->clc_ifp, m, clcp->clc_firsthop, clcp->clc_rt) - -#define SN_MTU(ifp, rt) (((rt && rt->rt_rmx.rmx_mtu) ?\ - rt->rt_rmx.rmx_mtu : clnp_badmtu(ifp, rt, __LINE__, __FILE__))) - -#endif /* TROLL */ - -/* - * Macro to remove an address from a clnp header - */ -#define CLNP_EXTRACT_ADDR(isoa, hoff, hend)\ - {\ - isoa.isoa_len = (u_char)*hoff;\ - if ((((++hoff) + isoa.isoa_len) > hend) ||\ - (isoa.isoa_len > 20) || (isoa.isoa_len == 0)) {\ - hoff = (caddr_t)0;\ - } else {\ - (void) bcopy(hoff, (caddr_t)isoa.isoa_genaddr, isoa.isoa_len);\ - hoff += isoa.isoa_len;\ - }\ - } - -/* - * Macro to insert an address into a clnp header - */ -#define CLNP_INSERT_ADDR(hoff, isoa)\ - *hoff++ = (isoa).isoa_len;\ - (void) bcopy((caddr_t)((isoa).isoa_genaddr), hoff, (isoa).isoa_len);\ - hoff += (isoa).isoa_len; - -/* - * Clnp hdr cache. Whenever a clnp packet is sent, a copy of the - * header is made and kept in this cache. In addition to a copy of - * the cached clnp hdr, the cache contains - * information necessary to determine whether the new packet - * to send requires a new header to be built. - */ -struct clnp_cache { - /* these fields are used to check the validity of the cache */ - struct iso_addr clc_dst; /* destination of packet */ - struct mbuf *clc_options; /* ptr to options mbuf */ - int clc_flags; /* flags passed to clnp_output */ - - /* these fields are state that clnp_output requires to finish the pkt */ - int clc_segoff; /* offset of seg part of header */ - struct rtentry *clc_rt; /* ptr to rtentry (points into - the route structure) */ - struct sockaddr *clc_firsthop; /* first hop of packet */ - struct ifnet *clc_ifp; /* ptr to interface structure */ - struct iso_ifaddr *clc_ifa; /* ptr to interface address */ - struct mbuf *clc_hdr; /* cached pkt hdr (finally)! */ -}; - -#ifndef satosiso -#define satosiso(sa)\ - ((struct sockaddr_iso *)(sa)) -#endif - -#ifdef KERNEL -caddr_t clnp_insert_addr(); -struct iso_addr *clnp_srcaddr(); -struct mbuf *clnp_reass(); -#ifdef TROLL -struct troll trollctl; -#endif /* TROLL */ -#endif /* KERNEL */ diff --git a/bsd/netiso/clnp_debug.c b/bsd/netiso/clnp_debug.c deleted file mode 100644 index 538cb3006..000000000 --- a/bsd/netiso/clnp_debug.c +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)clnp_debug.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#ifdef ARGO_DEBUG - -#ifdef TESTDEBUG -#ifdef notdef -struct addr_37 u_37 = { - {0x00, 0x02, 0x00, 0x10, 0x20, 0x30, 0x35}, - {0x01, 0x02, 0x03, 0x04, 0x50, 0x60, 0x70, 0x80, 0x90} -}; -struct addr_osinet u_osinet = { - {0x00, 0x04}, - {0x00, 0x02, 0x00, 0x01, 0x23, 0x42, 0x78, 0x20, 0x01, 0x05, 0x00} -}; -#endif /* notdef */ -struct addr_rfc986 u_rfc986 = { - {0x00, 0x06}, - {0x01, 0xc0, 0x0c, 0x0c, 0xab, 0x11} -}; -struct addr_rfc986 u_bad = { - {0x00, 0x01}, - {0x01, 0xc0, 0x0c, 0x0c, 0xab, 0x11} -}; -#include -main() -{ - struct iso_addr a; - - a.isoa_afi = AFI_37; - a.isoa_u.addr_37 = u_37; - a.isoa_len = 17; - printf("type 37: %s\n", clnp_iso_addrp(&a)); - - a.isoa_afi = AFI_OSINET; - a.isoa_u.addr_osinet = u_osinet; - a.isoa_len = 14; - printf("type osinet: %s\n", clnp_iso_addrp(&a)); - - a.isoa_afi = AFI_RFC986; - a.isoa_u.addr_rfc986 = u_rfc986; - a.isoa_len = 9; - printf("type rfc986: %s\n", clnp_iso_addrp(&a)); - - a.isoa_afi = 12; - a.isoa_u.addr_rfc986 = u_rfc986; - a.isoa_len = 9; - printf("type bad afi: %s\n", clnp_iso_addrp(&a)); - - a.isoa_afi = AFI_RFC986; - a.isoa_u.addr_rfc986 = u_bad; - a.isoa_len = 9; - printf("type bad idi: %s\n", clnp_iso_addrp(&a)); -} -#endif /* TESTDEBUG */ - -unsigned int clnp_debug; -static char letters[] = "0123456789abcdef"; - -/* - * Print buffer in hex, return addr of where we left off. - * Do not null terminate. - */ -char * -clnp_hexp(src, len, where) -char *src; /* src of data to print */ -int len; /* lengthof src */ -char *where; /* where to put data */ -{ - int i; - - for (i=0; i> 4]; - *where++ = letters[j & 0x0f]; - } - return where; -} - -/* - * Return a ptr to a human readable form of an iso addr - */ -static char iso_addr_b[50]; -#define DELIM '.'; - -char * -clnp_iso_addrp(isoa) -struct iso_addr *isoa; -{ - char *cp; - - /* print length */ - sprintf(iso_addr_b, "[%d] ", isoa->isoa_len); - - /* set cp to end of what we have */ - cp = iso_addr_b; - while (*cp) - cp++; - - /* print afi */ - cp = clnp_hexp(isoa->isoa_genaddr, (int)isoa->isoa_len, cp); -#ifdef notdef - *cp++ = DELIM; - - /* print type specific part */ - switch(isoa->isoa_afi) { - case AFI_37: - cp = clnp_hexp(isoa->t37_idi, ADDR37_IDI_LEN, cp); - *cp++ = DELIM; - cp = clnp_hexp(isoa->t37_dsp, ADDR37_DSP_LEN, cp); - break; - -/* case AFI_OSINET:*/ - case AFI_RFC986: { - u_short idi; - - /* osinet and rfc986 have idi in the same place */ - /* print idi */ - cp = clnp_hexp(isoa->rfc986_idi, ADDROSINET_IDI_LEN, cp); - *cp++ = DELIM; - CTOH(isoa->rfc986_idi[0], isoa->rfc986_idi[1], idi); - - if (idi == IDI_OSINET) { - struct ovl_osinet *oosi = (struct ovl_osinet *)isoa; - cp = clnp_hexp(oosi->oosi_orgid, OVLOSINET_ORGID_LEN, cp); - *cp++ = DELIM; - cp = clnp_hexp(oosi->oosi_snetid, OVLOSINET_SNETID_LEN, cp); - *cp++ = DELIM; - cp = clnp_hexp(oosi->oosi_snpa, OVLOSINET_SNPA_LEN, cp); - *cp++ = DELIM; - cp = clnp_hexp(oosi->oosi_nsap, OVLOSINET_NSAP_LEN, cp); - } else if (idi == IDI_RFC986) { - struct ovl_rfc986 *o986 = (struct ovl_rfc986 *)isoa; - cp = clnp_hexp(&o986->o986_vers, 1, cp); - *cp++ = DELIM; -#ifdef vax - sprintf(cp, "%d.%d.%d.%d.%d", - o986->o986_inetaddr[0] & 0xff, - o986->o986_inetaddr[1] & 0xff, - o986->o986_inetaddr[2] & 0xff, - o986->o986_inetaddr[3] & 0xff, - o986->o986_upid & 0xff); - return(iso_addr_b); -#else - cp = clnp_hexp(&o986->o986_inetaddr[0], 1, cp); - *cp++ = DELIM; - cp = clnp_hexp(&o986->o986_inetaddr[1], 1, cp); - *cp++ = DELIM; - cp = clnp_hexp(&o986->o986_inetaddr[2], 1, cp); - *cp++ = DELIM; - cp = clnp_hexp(&o986->o986_inetaddr[3], 1, cp); - *cp++ = DELIM; - cp = clnp_hexp(&o986->o986_upid, 1, cp); -#endif /* vax */ - } - - } break; - - default: - *cp++ = '?'; - break; - } -#endif /* notdef */ - *cp = (char)0; - - return(iso_addr_b); -} - -char * -clnp_saddr_isop(s) -register struct sockaddr_iso *s; -{ - register char *cp = clnp_iso_addrp(&s->siso_addr); - - while (*cp) cp++; - *cp++ = '('; - cp = clnp_hexp(TSEL(s), (int)s->siso_tlen, cp); - *cp++ = ')'; - *cp++ = 0; - return (iso_addr_b); -} - -#endif /* ARGO_DEBUG */ diff --git a/bsd/netiso/clnp_er.c b/bsd/netiso/clnp_er.c deleted file mode 100644 index ed8446984..000000000 --- a/bsd/netiso/clnp_er.c +++ /dev/null @@ -1,394 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)clnp_er.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#define CLNP_ER_CODES -#include -#include -#include - -static struct clnp_fixed er_template = { - ISO8473_CLNP, /* network identifier */ - 0, /* length */ - ISO8473_V1, /* version */ - CLNP_TTL, /* ttl */ - CLNP_ER, /* type */ - 0, /* segment length */ - 0 /* checksum */ -}; - -/* - * FUNCTION: clnp_er_input - * - * PURPOSE: Process an ER pdu. - * - * RETURNS: - * - * SIDE EFFECTS: - * - * NOTES: - */ -clnp_er_input(m, src, reason) -struct mbuf *m; /* ptr to packet itself */ -struct iso_addr *src; /* ptr to src of er */ -u_char reason; /* reason code of er */ -{ - int cmd = -1; - extern u_char clnp_protox[]; - - IFDEBUG(D_CTLINPUT) - printf("clnp_er_input: m x%x, src %s, reason x%x\n", m, - clnp_iso_addrp(src), reason); - ENDDEBUG - - INCSTAT(cns_er_inhist[clnp_er_index(reason)]); - switch (reason) { - case GEN_NOREAS: - case GEN_PROTOERR: - break; - case GEN_BADCSUM: - cmd = PRC_PARAMPROB; - break; - case GEN_CONGEST: - cmd = PRC_QUENCH; - break; - case GEN_HDRSYNTAX: - cmd = PRC_PARAMPROB; - break; - case GEN_SEGNEEDED: - cmd = PRC_MSGSIZE; - break; - case GEN_INCOMPLETE: - cmd = PRC_PARAMPROB; - break; - case GEN_DUPOPT: - cmd = PRC_PARAMPROB; - break; - case ADDR_DESTUNREACH: - cmd = PRC_UNREACH_HOST; - break; - case ADDR_DESTUNKNOWN: - cmd = PRC_UNREACH_PROTOCOL; - break; - case SRCRT_UNSPECERR: - case SRCRT_SYNTAX: - case SRCRT_UNKNOWNADDR: - case SRCRT_BADPATH: - cmd = PRC_UNREACH_SRCFAIL; - break; - case TTL_EXPTRANSIT: - cmd = PRC_TIMXCEED_INTRANS; - break; - case TTL_EXPREASS: - cmd = PRC_TIMXCEED_REASS; - break; - case DISC_UNSUPPOPT: - case DISC_UNSUPPVERS: - case DISC_UNSUPPSECURE: - case DISC_UNSUPPSRCRT: - case DISC_UNSUPPRECRT: - cmd = PRC_PARAMPROB; - break; - case REASS_INTERFERE: - cmd = PRC_TIMXCEED_REASS; - break; - } - - /* - * tpclnp_ctlinput1 is called directly so that we don't - * have to build an iso_sockaddr out of src. - */ - if (cmd >= 0) - tpclnp_ctlinput1(cmd, src); - - m_freem(m); -} - -/* - * FUNCTION: clnp_discard - * - * PURPOSE: Discard a clnp datagram - * - * RETURNS: nothing - * - * SIDE EFFECTS: Will emit an ER pdu if possible - * - * NOTES: This code assumes that we have previously tried to pull - * up the header of the datagram into one mbuf. - */ -clnp_discard(m, reason) -struct mbuf *m; /* header of packet to discard */ -char reason; /* reason for discard */ -{ - IFDEBUG(D_DISCARD) - printf("clnp_discard: m x%x, reason x%x\n", m, reason); - ENDDEBUG - - if (m != NULL) { - if (m->m_len >= sizeof(struct clnp_fixed)) { - register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); - - if (((clnp->cnf_type & CNF_TYPE) != CLNP_ER) && - (clnp->cnf_type & CNF_ERR_OK)) { - clnp_emit_er(m, reason); - return; - } - } - m_freem(m); - } -} - -/* - * FUNCTION: clnp_emit_er - * - * PURPOSE: Send an ER pdu. - * The src of the of the ER pdu is the host that is sending - * the ER (ie. us), *not* the original destination of the - * packet. - * - * RETURNS: nothing - * - * SIDE EFFECTS: - * - * NOTES: Takes responsibility for freeing mbuf passed - * This function may be called with a packet that - * was created by us; in this case, do not send - * an ER. - */ -clnp_emit_er(m, reason) -struct mbuf *m; /* header of packet to discard */ -char reason; /* reason for discard */ -{ - register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); - register struct clnp_fixed *er; - struct route_iso route; - struct ifnet *ifp; - struct sockaddr *first_hop; - struct iso_addr src, dst, *our_addr; - caddr_t hoff, hend; - int total_len; /* total len of dg */ - struct mbuf *m0; /* contains er pdu hdr */ - struct iso_ifaddr *ia = 0; - - IFDEBUG(D_DISCARD) - printf("clnp_emit_er: m x%x, hdr len %d\n", m, clnp->cnf_hdr_len); - ENDDEBUG - - bzero((caddr_t)&route, sizeof(route)); - - /* - * If header length is incorrect, or entire header is not contained - * in this mbuf, we punt - */ - if ((clnp->cnf_hdr_len < CLNP_HDR_MIN) || - (clnp->cnf_hdr_len > CLNP_HDR_MAX) || - (clnp->cnf_hdr_len > m->m_len)) - goto bad; - - /* extract src, dest address */ - hend = (caddr_t)clnp + clnp->cnf_hdr_len; - hoff = (caddr_t)clnp + sizeof(struct clnp_fixed); - CLNP_EXTRACT_ADDR(dst, hoff, hend); - if (hoff == (caddr_t)0) { - goto bad; - } - CLNP_EXTRACT_ADDR(src, hoff, hend); - if (hoff == (caddr_t)0) { - goto bad; - } - - /* - * Do not send ER if we generated the packet. - */ - if (clnp_ours(&src)) - goto bad; - - /* - * Trim mbuf to hold only the header. - * This mbuf will be the 'data' of the er pdu - */ - if (m->m_next != NULL) { - m_freem(m->m_next); - m->m_next = NULL; - } - - if (m->m_len > clnp->cnf_hdr_len) - m_adj(m, (int)-(m->m_len - (int)clnp->cnf_hdr_len)); - - /* route er pdu: note we send pkt to src of original packet */ - if (clnp_route(&src, &route, /* flags */0, &first_hop, &ia) != 0) - goto bad; - - /* compute our address based upon firsthop/ifp */ - if (ia) - our_addr = &ia->ia_addr.siso_addr; - else - goto bad; - ifp = ia->ia_ifp; - - IFDEBUG(D_DISCARD) - printf("clnp_emit_er: to %s", clnp_iso_addrp(&src)); - printf(" from %s\n", clnp_iso_addrp(our_addr)); - ENDDEBUG - - IFDEBUG(D_DISCARD) - printf("clnp_emit_er: packet routed to %s\n", - clnp_iso_addrp(&((struct sockaddr_iso *)first_hop)->siso_addr)); - ENDDEBUG - - /* allocate mbuf for er pdu header: punt on no space */ - MGET(m0, M_DONTWAIT, MT_HEADER); - if (m0 == 0) - goto bad; - - m0->m_next = m; - er = mtod(m0, struct clnp_fixed *); - *er = er_template; - - /* setup src/dst on er pdu */ - /* NOTE REVERSAL OF SRC/DST */ - hoff = (caddr_t)er + sizeof(struct clnp_fixed); - CLNP_INSERT_ADDR(hoff, src); - CLNP_INSERT_ADDR(hoff, *our_addr); - - /* - * TODO: if complete src rt was specified, then reverse path, and - * copy into er as option. - */ - - /* add er option */ - *hoff++ = CLNPOVAL_ERREAS; /* code */ - *hoff++ = 2; /* length */ - *hoff++ = reason; /* discard reason */ - *hoff++ = 0; /* error localization = not specified */ - - /* set length */ - er->cnf_hdr_len = m0->m_len = (u_char)(hoff - (caddr_t)er); - total_len = m0->m_len + m->m_len; - HTOC(er->cnf_seglen_msb, er->cnf_seglen_lsb, total_len); - - /* compute checksum (on header only) */ - iso_gen_csum(m0, CLNP_CKSUM_OFF, (int)er->cnf_hdr_len); - - /* trim packet if too large for interface */ - if (total_len > ifp->if_mtu) - m_adj(m0, -(total_len - ifp->if_mtu)); - - /* send packet */ - INCSTAT(cns_er_outhist[clnp_er_index(reason)]); - (void) (*ifp->if_output)(ifp, m0, first_hop, route.ro_rt); - goto done; - -bad: - m_freem(m); - -done: - /* free route if it is a temp */ - if (route.ro_rt != NULL) - RTFREE(route.ro_rt); -} - -clnp_er_index(p) -u_char p; -{ - register u_char *cp = clnp_er_codes + CLNP_ERRORS; - while (cp > clnp_er_codes) { - cp--; - if (*cp == p) - return (cp - clnp_er_codes); - } - return (CLNP_ERRORS + 1); -} diff --git a/bsd/netiso/clnp_frag.c b/bsd/netiso/clnp_frag.c deleted file mode 100644 index f2db3ef1b..000000000 --- a/bsd/netiso/clnp_frag.c +++ /dev/null @@ -1,878 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)clnp_frag.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -/* all fragments are hung off this list */ -struct clnp_fragl *clnp_frags = NULL; - -struct mbuf *clnp_comp_pdu(); - - -/* - * FUNCTION: clnp_fragment - * - * PURPOSE: Fragment a datagram, and send the itty bitty pieces - * out over an interface. - * - * RETURNS: success - 0 - * failure - unix error code - * - * SIDE EFFECTS: - * - * NOTES: If there is an error sending the packet, clnp_discard - * is called to discard the packet and send an ER. If - * clnp_fragment was called from clnp_output, then - * we generated the packet, and should not send an - * ER -- clnp_emit_er will check for this. Otherwise, - * the packet was fragmented during forwarding. In this - * case, we ought to send an ER back. - */ -clnp_fragment(ifp, m, first_hop, total_len, segoff, flags, rt) -struct ifnet *ifp; /* ptr to outgoing interface */ -struct mbuf *m; /* ptr to packet */ -struct sockaddr *first_hop; /* ptr to first hop */ -int total_len; /* length of datagram */ -int segoff; /* offset of segpart in hdr */ -int flags; /* flags passed to clnp_output */ -struct rtentry *rt; /* route if direct ether */ -{ - struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); - int hdr_len = (int)clnp->cnf_hdr_len; - int frag_size = (SN_MTU(ifp, rt) - hdr_len) & ~7; - - total_len -= hdr_len; - if ((clnp->cnf_type & CNF_SEG_OK) && - (total_len >= 8) && - (frag_size > 8 || (frag_size == 8 && !(total_len & 7)))) { - - struct mbuf *hdr = NULL; /* save copy of clnp hdr */ - struct mbuf *frag_hdr = NULL; - struct mbuf *frag_data = NULL; - struct clnp_segment seg_part; /* segmentation header */ - int frag_base; - int error = 0; - - - INCSTAT(cns_fragmented); - (void) bcopy(segoff + mtod(m, caddr_t), (caddr_t)&seg_part, - sizeof(seg_part)); - frag_base = ntohs(seg_part.cng_off); - /* - * Duplicate header, and remove from packet - */ - if ((hdr = m_copy(m, 0, hdr_len)) == NULL) { - clnp_discard(m, GEN_CONGEST); - return(ENOBUFS); - } - m_adj(m, hdr_len); - - while (total_len > 0) { - int remaining, last_frag; - - IFDEBUG(D_FRAG) - struct mbuf *mdump = frag_hdr; - int tot_mlen = 0; - printf("clnp_fragment: total_len %d:\n", total_len); - while (mdump != NULL) { - printf("\tmbuf x%x, m_len %d\n", - mdump, mdump->m_len); - tot_mlen += mdump->m_len; - mdump = mdump->m_next; - } - printf("clnp_fragment: sum of mbuf chain %d:\n", tot_mlen); - ENDDEBUG - - frag_size = min(total_len, frag_size); - if ((remaining = total_len - frag_size) == 0) - last_frag = 1; - else { - /* - * If this fragment will cause the last one to - * be less than 8 bytes, shorten this fragment a bit. - * The obscure test on frag_size above ensures that - * frag_size will be positive. - */ - last_frag = 0; - if (remaining < 8) - frag_size -= 8; - } - - - IFDEBUG(D_FRAG) - printf("clnp_fragment: seg off %d, size %d, remaining %d\n", - ntohs(seg_part.cng_off), frag_size, total_len-frag_size); - if (last_frag) - printf("clnp_fragment: last fragment\n"); - ENDDEBUG - - if (last_frag) { - /* - * this is the last fragment; we don't need to get any other - * mbufs. - */ - frag_hdr = hdr; - frag_data = m; - } else { - /* duplicate header and data mbufs */ - if ((frag_hdr = m_copy(hdr, 0, (int)M_COPYALL)) == NULL) { - clnp_discard(hdr, GEN_CONGEST); - m_freem(m); - return(ENOBUFS); - } - if ((frag_data = m_copy(m, 0, frag_size)) == NULL) { - clnp_discard(hdr, GEN_CONGEST); - m_freem(m); - m_freem(frag_hdr); - return(ENOBUFS); - } - INCSTAT(cns_fragments); - } - clnp = mtod(frag_hdr, struct clnp_fixed *); - - if (!last_frag) - clnp->cnf_type |= CNF_MORE_SEGS; - - /* link together */ - m_cat(frag_hdr, frag_data); - - /* insert segmentation part; updated below */ - bcopy((caddr_t)&seg_part, mtod(frag_hdr, caddr_t) + segoff, - sizeof(struct clnp_segment)); - - { - int derived_len = hdr_len + frag_size; - HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, derived_len); - if ((frag_hdr->m_flags & M_PKTHDR) == 0) - panic("clnp_frag:lost header"); - frag_hdr->m_pkthdr.len = derived_len; - } - /* compute clnp checksum (on header only) */ - if (flags & CLNP_NO_CKSUM) { - HTOC(clnp->cnf_cksum_msb, clnp->cnf_cksum_lsb, 0); - } else { - iso_gen_csum(frag_hdr, CLNP_CKSUM_OFF, hdr_len); - } - - IFDEBUG(D_DUMPOUT) - struct mbuf *mdump = frag_hdr; - printf("clnp_fragment: sending dg:\n"); - while (mdump != NULL) { - printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); - mdump = mdump->m_next; - } - ENDDEBUG - -#ifdef TROLL - error = troll_output(ifp, frag_hdr, first_hop, rt); -#else - error = (*ifp->if_output)(ifp, frag_hdr, first_hop, rt); -#endif /* TROLL */ - - /* - * Tough situation: if the error occured on the last - * fragment, we can not send an ER, as the if_output - * routine consumed the packet. If the error occured - * on any intermediate packets, we can send an ER - * because we still have the original header in (m). - */ - if (error) { - if (frag_hdr != hdr) { - /* - * The error was not on the last fragment. We must - * free hdr and m before returning - */ - clnp_discard(hdr, GEN_NOREAS); - m_freem(m); - } - return(error); - } - - /* bump segment offset, trim data mbuf, and decrement count left */ -#ifdef TROLL - /* - * Decrement frag_size by some fraction. This will cause the - * next fragment to start 'early', thus duplicating the end - * of the current fragment. troll.tr_dup_size controls - * the fraction. If positive, it specifies the fraction. If - * negative, a random fraction is used. - */ - if ((trollctl.tr_ops & TR_DUPEND) && (!last_frag)) { - int num_bytes = frag_size; - - if (trollctl.tr_dup_size > 0) - num_bytes *= trollctl.tr_dup_size; - else - num_bytes *= troll_random(); - frag_size -= num_bytes; - } -#endif /* TROLL */ - total_len -= frag_size; - if (!last_frag) { - frag_base += frag_size; - seg_part.cng_off = htons(frag_base); - m_adj(m, frag_size); - } - } - return(0); - } else { - cantfrag: - INCSTAT(cns_cantfrag); - clnp_discard(m, GEN_SEGNEEDED); - return(EMSGSIZE); - } -} - -/* - * FUNCTION: clnp_reass - * - * PURPOSE: Attempt to reassemble a clnp packet given the current - * fragment. If reassembly succeeds (all the fragments - * are present), then return a pointer to an mbuf chain - * containing the reassembled packet. This packet will - * appear in the mbufs as if it had just arrived in - * one piece. - * - * If reassembly fails, then save this fragment and - * return 0. - * - * RETURNS: Ptr to assembled packet, or 0 - * - * SIDE EFFECTS: - * - * NOTES: - * clnp_slowtimo can not affect this code because clnpintr, and thus - * this code, is called at a higher priority than clnp_slowtimo. - */ -struct mbuf * -clnp_reass(m, src, dst, seg) -struct mbuf *m; /* new fragment */ -struct iso_addr *src; /* src of new fragment */ -struct iso_addr *dst; /* dst of new fragment */ -struct clnp_segment *seg; /* segment part of fragment header */ -{ - register struct clnp_fragl *cfh; - - /* look for other fragments of this datagram */ - for (cfh = clnp_frags; cfh != NULL; cfh = cfh->cfl_next) { - if (seg->cng_id == cfh->cfl_id && - iso_addrmatch1(src, &cfh->cfl_src) && - iso_addrmatch1(dst, &cfh->cfl_dst)) { - IFDEBUG(D_REASS) - printf("clnp_reass: found packet\n"); - ENDDEBUG - /* - * There are other fragments here already. Lets see if - * this fragment is of any help - */ - clnp_insert_frag(cfh, m, seg); - if (m = clnp_comp_pdu(cfh)) { - register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); - HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, - seg->cng_tot_len); - } - return (m); - } - } - - IFDEBUG(D_REASS) - printf("clnp_reass: new packet!\n"); - ENDDEBUG - - /* - * This is the first fragment. If src is not consuming too many - * resources, then create a new fragment list and add - * this fragment to the list. - */ - /* TODO: don't let one src hog all the reassembly buffers */ - if (!clnp_newpkt(m, src, dst, seg) /* || this src is a hog */) { - INCSTAT(cns_fragdropped); - clnp_discard(m, GEN_CONGEST); - } - - return(NULL); -} - -/* - * FUNCTION: clnp_newpkt - * - * PURPOSE: Create the necessary structures to handle a new - * fragmented clnp packet. - * - * RETURNS: non-zero if it succeeds, zero if fails. - * - * SIDE EFFECTS: - * - * NOTES: Failure is only due to insufficient resources. - */ -clnp_newpkt(m, src, dst, seg) -struct mbuf *m; /* new fragment */ -struct iso_addr *src; /* src of new fragment */ -struct iso_addr *dst; /* dst of new fragment */ -struct clnp_segment *seg; /* segment part of fragment header */ -{ - register struct clnp_fragl *cfh; - register struct clnp_fixed *clnp; - struct mbuf *m0; - - clnp = mtod(m, struct clnp_fixed *); - - /* - * Allocate new clnp fragl structure to act as header of all fragments - * for this datagram. - */ - MGET(m0, M_DONTWAIT, MT_FTABLE); - if (m0 == NULL) { - return (0); - } - cfh = mtod(m0, struct clnp_fragl *); - - /* - * Duplicate the header of this fragment, and save in cfh. - * Free m0 and return if m_copy does not succeed. - */ - if ((cfh->cfl_orighdr = m_copy(m, 0, (int)clnp->cnf_hdr_len)) == NULL) { - m_freem(m0); - return (0); - } - - /* Fill in rest of fragl structure */ - bcopy((caddr_t)src, (caddr_t)&cfh->cfl_src, sizeof(struct iso_addr)); - bcopy((caddr_t)dst, (caddr_t)&cfh->cfl_dst, sizeof(struct iso_addr)); - cfh->cfl_id = seg->cng_id; - cfh->cfl_ttl = clnp->cnf_ttl; - cfh->cfl_last = (seg->cng_tot_len - clnp->cnf_hdr_len) - 1; - cfh->cfl_frags = NULL; - cfh->cfl_next = NULL; - - /* Insert into list of packets */ - cfh->cfl_next = clnp_frags; - clnp_frags = cfh; - - /* Insert this fragment into list headed by cfh */ - clnp_insert_frag(cfh, m, seg); - return(1); -} - -/* - * FUNCTION: clnp_insert_frag - * - * PURPOSE: Insert fragment into list headed by 'cf'. - * - * RETURNS: nothing - * - * SIDE EFFECTS: - * - * NOTES: This is the 'guts' of the reassembly algorithm. - * Each fragment in this list contains a clnp_frag - * structure followed by the data of the fragment. - * The clnp_frag structure actually lies on top of - * part of the old clnp header. - */ -clnp_insert_frag(cfh, m, seg) -struct clnp_fragl *cfh; /* header of list of packet fragments */ -struct mbuf *m; /* new fragment */ -struct clnp_segment *seg; /* segment part of fragment header */ -{ - register struct clnp_fixed *clnp; /* clnp hdr of fragment */ - register struct clnp_frag *cf; /* generic fragment ptr */ - register struct clnp_frag *cf_sub = NULL; /* frag subsequent to new one */ - register struct clnp_frag *cf_prev = NULL; /* frag previous to new one */ - u_short first; /* offset of first byte of initial pdu*/ - u_short last; /* offset of last byte of initial pdu */ - u_short fraglen;/* length of fragment */ - - clnp = mtod(m, struct clnp_fixed *); - first = seg->cng_off; - CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, fraglen); - fraglen -= clnp->cnf_hdr_len; - last = (first + fraglen) - 1; - - IFDEBUG(D_REASS) - printf("clnp_insert_frag: New fragment: [%d ... %d], len %d\n", - first, last, fraglen); - printf("clnp_insert_frag: current fragments:\n"); - for (cf = cfh->cfl_frags; cf != NULL; cf = cf->cfr_next) { - printf("\tcf x%x: [%d ... %d]\n", cf, cf->cfr_first, cf->cfr_last); - } - ENDDEBUG - - if (cfh->cfl_frags != NULL) { - /* - * Find fragment which begins after the new one - */ - for (cf = cfh->cfl_frags; cf != NULL; cf_prev = cf, cf = cf->cfr_next) { - if (cf->cfr_first > first) { - cf_sub = cf; - break; - } - } - - IFDEBUG(D_REASS) - printf("clnp_insert_frag: Previous frag is "); - if (cf_prev == NULL) - printf("NULL\n"); - else - printf("[%d ... %d]\n", cf_prev->cfr_first, cf_prev->cfr_last); - printf("clnp_insert_frag: Subsequent frag is "); - if (cf_sub == NULL) - printf("NULL\n"); - else - printf("[%d ... %d]\n", cf_sub->cfr_first, cf_sub->cfr_last); - ENDDEBUG - - /* - * If there is a fragment before the new one, check if it - * overlaps the new one. If so, then trim the end of the - * previous one. - */ - if (cf_prev != NULL) { - if (cf_prev->cfr_last > first) { - u_short overlap = cf_prev->cfr_last - first; - - IFDEBUG(D_REASS) - printf("clnp_insert_frag: previous overlaps by %d\n", - overlap); - ENDDEBUG - - if (overlap > fraglen) { - /* - * The new fragment is entirely contained in the - * preceeding one. We can punt on the new frag - * completely. - */ - m_freem(m); - return; - } else { - /* Trim data off of end of previous fragment */ - /* inc overlap to prevent duplication of last byte */ - overlap++; - m_adj(cf_prev->cfr_data, -(int)overlap); - cf_prev->cfr_last -= overlap; - } - } - } - - /* - * For all fragments past the new one, check if any data on - * the new one overlaps data on existing fragments. If so, - * then trim the extra data off the end of the new one. - */ - for (cf = cf_sub; cf != NULL; cf = cf->cfr_next) { - if (cf->cfr_first < last) { - u_short overlap = last - cf->cfr_first; - - IFDEBUG(D_REASS) - printf("clnp_insert_frag: subsequent overlaps by %d\n", - overlap); - ENDDEBUG - - if (overlap > fraglen) { - /* - * The new fragment is entirely contained in the - * succeeding one. This should not happen, because - * early on in this code we scanned for the fragment - * which started after the new one! - */ - m_freem(m); - printf("clnp_insert_frag: internal error!\n"); - return; - } else { - /* Trim data off of end of new fragment */ - /* inc overlap to prevent duplication of last byte */ - overlap++; - m_adj(m, -(int)overlap); - last -= overlap; - } - } - } - } - - /* - * Insert the new fragment beween cf_prev and cf_sub - * - * Note: the clnp hdr is still in the mbuf. - * If the data of the mbuf is not word aligned, shave off enough - * so that it is. Then, cast the clnp_frag structure on top - * of the clnp header. - * The clnp_hdr will not be used again (as we already have - * saved a copy of it). - * - * Save in cfr_bytes the number of bytes to shave off to get to - * the data of the packet. This is used when we coalesce fragments; - * the clnp_frag structure must be removed before joining mbufs. - */ - { - int pad; - u_int bytes; - - /* determine if header is not word aligned */ - pad = (int)clnp % 4; - if (pad < 0) - pad = -pad; - - /* bytes is number of bytes left in front of data */ - bytes = clnp->cnf_hdr_len - pad; - - IFDEBUG(D_REASS) - printf("clnp_insert_frag: clnp x%x requires %d alignment\n", - clnp, pad); - ENDDEBUG - - /* make it word aligned if necessary */ - if (pad) - m_adj(m, pad); - - cf = mtod(m, struct clnp_frag *); - cf->cfr_bytes = bytes; - - IFDEBUG(D_REASS) - printf("clnp_insert_frag: cf now x%x, cfr_bytes %d\n", cf, - cf->cfr_bytes); - ENDDEBUG - } - cf->cfr_first = first; - cf->cfr_last = last; - - - /* - * The data is the mbuf itself, although we must remember that the - * first few bytes are actually a clnp_frag structure - */ - cf->cfr_data = m; - - /* link into place */ - cf->cfr_next = cf_sub; - if (cf_prev == NULL) - cfh->cfl_frags = cf; - else - cf_prev->cfr_next = cf; -} - -/* - * FUNCTION: clnp_comp_pdu - * - * PURPOSE: Scan the list of fragments headed by cfh. Merge - * any contigious fragments into one. If, after - * traversing all the fragments, it is determined that - * the packet is complete, then return a pointer to - * the packet (with header prepended). Otherwise, - * return NULL. - * - * RETURNS: NULL, or a pointer to the assembled pdu in an mbuf chain. - * - * SIDE EFFECTS: Will colapse contigious fragments into one. - * - * NOTES: This code assumes that there are no overlaps of - * fragment pdus. - */ -struct mbuf * -clnp_comp_pdu(cfh) -struct clnp_fragl *cfh; /* fragment header */ -{ - register struct clnp_frag *cf = cfh->cfl_frags; - - while (cf->cfr_next != NULL) { - register struct clnp_frag *cf_next = cf->cfr_next; - - IFDEBUG(D_REASS) - printf("clnp_comp_pdu: comparing: [%d ... %d] to [%d ... %d]\n", - cf->cfr_first, cf->cfr_last, cf_next->cfr_first, - cf_next->cfr_last); - ENDDEBUG - - if (cf->cfr_last == (cf_next->cfr_first - 1)) { - /* - * Merge fragment cf and cf_next - * - * - update cf header - * - trim clnp_frag structure off of cf_next - * - append cf_next to cf - */ - struct clnp_frag cf_next_hdr; - struct clnp_frag *next_frag; - - cf_next_hdr = *cf_next; - next_frag = cf_next->cfr_next; - - IFDEBUG(D_REASS) - struct mbuf *mdump; - int l; - printf("clnp_comp_pdu: merging fragments\n"); - printf("clnp_comp_pdu: 1st: [%d ... %d] (bytes %d)\n", - cf->cfr_first, cf->cfr_last, cf->cfr_bytes); - mdump = cf->cfr_data; - l = 0; - while (mdump != NULL) { - printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); - l += mdump->m_len; - mdump = mdump->m_next; - } - printf("\ttotal len: %d\n", l); - printf("clnp_comp_pdu: 2nd: [%d ... %d] (bytes %d)\n", - cf_next->cfr_first, cf_next->cfr_last, cf_next->cfr_bytes); - mdump = cf_next->cfr_data; - l = 0; - while (mdump != NULL) { - printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); - l += mdump->m_len; - mdump = mdump->m_next; - } - printf("\ttotal len: %d\n", l); - ENDDEBUG - - cf->cfr_last = cf_next->cfr_last; - /* - * After this m_adj, the cf_next ptr is useless because we - * have adjusted the clnp_frag structure away... - */ - IFDEBUG(D_REASS) - printf("clnp_comp_pdu: shaving off %d bytes\n", - cf_next_hdr.cfr_bytes); - ENDDEBUG - m_adj(cf_next_hdr.cfr_data, (int)cf_next_hdr.cfr_bytes); - m_cat(cf->cfr_data, cf_next_hdr.cfr_data); - cf->cfr_next = next_frag; - } else { - cf = cf->cfr_next; - } - } - - cf = cfh->cfl_frags; - - IFDEBUG(D_REASS) - struct mbuf *mdump = cf->cfr_data; - printf("clnp_comp_pdu: first frag now: [%d ... %d]\n", cf->cfr_first, - cf->cfr_last); - printf("clnp_comp_pdu: data for frag:\n"); - while (mdump != NULL) { - printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len); -/* dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/ - mdump = mdump->m_next; - } - ENDDEBUG - - /* Check if datagram is complete */ - if ((cf->cfr_first == 0) && (cf->cfr_last == cfh->cfl_last)) { - /* - * We have a complete pdu! - * - Remove the frag header from (only) remaining fragment - * (which is not really a fragment anymore, as the datagram is - * complete). - * - Prepend a clnp header - */ - struct mbuf *data = cf->cfr_data; - struct mbuf *hdr = cfh->cfl_orighdr; - struct clnp_fragl *scan; - - IFDEBUG(D_REASS) - printf("clnp_comp_pdu: complete pdu!\n"); - ENDDEBUG - - m_adj(data, (int)cf->cfr_bytes); - m_cat(hdr, data); - - IFDEBUG(D_DUMPIN) - struct mbuf *mdump = hdr; - printf("clnp_comp_pdu: pdu is:\n"); - while (mdump != NULL) { - printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len); -/* dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/ - mdump = mdump->m_next; - } - ENDDEBUG - - /* - * Remove cfh from the list of fragmented pdus - */ - if (clnp_frags == cfh) { - clnp_frags = cfh->cfl_next; - } else { - for (scan = clnp_frags; scan != NULL; scan = scan->cfl_next) { - if (scan->cfl_next == cfh) { - scan->cfl_next = cfh->cfl_next; - break; - } - } - } - - /* free cfh */ - m_freem(dtom(cfh)); - - return(hdr); - } - - return(NULL); -} -#ifdef TROLL -static int troll_cnt; -#include -/* - * FUNCTION: troll_random - * - * PURPOSE: generate a pseudo-random number between 0 and 1 - * - * RETURNS: the random number - * - * SIDE EFFECTS: - * - * NOTES: This is based on the clock. - */ -float troll_random() -{ - extern struct timeval time; - long t = time.tv_usec % 100; - - return((float)t / (float) 100); -} - -/* - * FUNCTION: troll_output - * - * PURPOSE: Do something sneaky with the datagram passed. Possible - * operations are: - * Duplicate the packet - * Drop the packet - * Trim some number of bytes from the packet - * Munge some byte in the packet - * - * RETURNS: 0, or unix error code - * - * SIDE EFFECTS: - * - * NOTES: The operation of this procedure is regulated by the - * troll control structure (Troll). - */ -troll_output(ifp, m, dst, rt) -struct ifnet *ifp; -struct mbuf *m; -struct sockaddr *dst; -struct rtentry *rt; -{ - int err = 0; - troll_cnt++; - - if (trollctl.tr_ops & TR_DUPPKT) { - /* - * Duplicate every Nth packet - * TODO: random? - */ - float f_freq = troll_cnt * trollctl.tr_dup_freq; - int i_freq = troll_cnt * trollctl.tr_dup_freq; - if (i_freq == f_freq) { - struct mbuf *dup = m_copy(m, 0, (int)M_COPYALL); - if (dup != NULL) - err = (*ifp->if_output)(ifp, dup, dst, rt); - } - if (!err) - err = (*ifp->if_output)(ifp, m, dst, rt); - return(err); - } else if (trollctl.tr_ops & TR_DROPPKT) { - } else if (trollctl.tr_ops & TR_CHANGE) { - struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); - clnp->cnf_cksum_msb = 0; - err = (*ifp->if_output)(ifp, m, dst, rt); - return(err); - } else { - err = (*ifp->if_output)(ifp, m, dst, rt); - return(err); - } -} - -#endif /* TROLL */ diff --git a/bsd/netiso/clnp_input.c b/bsd/netiso/clnp_input.c deleted file mode 100644 index 7bf537d7b..000000000 --- a/bsd/netiso/clnp_input.c +++ /dev/null @@ -1,570 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)clnp_input.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if ISO -u_char clnp_protox[ISOPROTO_MAX]; -struct clnl_protosw clnl_protox[256]; -int clnpqmaxlen = IFQ_MAXLEN; /* RAH? why is this a variable */ -struct mbuf *clnp_data_ck(); - -int clnp_input(); - -int esis_input(); - -#ifdef ISO_X25ESIS -int x25esis_input(); -#endif /* ISO_X25ESIS */ - -/* - * FUNCTION: clnp_init - * - * PURPOSE: clnp initialization. Fill in clnp switch tables. - * - * RETURNS: none - * - * SIDE EFFECTS: fills in clnp_protox table with correct offsets into - * the isosw table. - * - * NOTES: - */ -clnp_init() -{ - register struct protosw *pr; - - /* - * CLNP protox initialization - */ - if ((pr = pffindproto(PF_ISO, ISOPROTO_RAW, SOCK_RAW)) == 0) - printf("clnl_init: no raw CLNP\n"); - else - clnp_protox[ISOPROTO_RAW] = pr - isosw; - - if ((pr = pffindproto(PF_ISO, ISOPROTO_TP, SOCK_SEQPACKET)) == 0) - printf("clnl_init: no tp/clnp\n"); - else - clnp_protox[ISOPROTO_TP] = pr - isosw; - - /* - * CLNL protox initialization - */ - clnl_protox[ISO8473_CLNP].clnl_input = clnp_input; - - clnlintrq.ifq_maxlen = clnpqmaxlen; -} - -/* - * FUNCTION: clnlintr - * - * PURPOSE: Process a packet on the clnl input queue - * - * RETURNS: nothing. - * - * SIDE EFFECTS: - * - * NOTES: - */ -clnlintr() -{ - register struct mbuf *m; /* ptr to first mbuf of pkt */ - register struct clnl_fixed *clnl; /* ptr to fixed part of clnl hdr */ - int s; /* save and restore priority */ - struct clnl_protosw *clnlsw;/* ptr to protocol switch */ - struct snpa_hdr sh; /* subnetwork hdr */ - - /* - * Get next datagram off clnl input queue - */ -next: - s = splimp(); - /* IF_DEQUEUESNPAHDR(&clnlintrq, m, sh);*/ - IF_DEQUEUE(&clnlintrq, m); - splx(s); - - - if (m == 0) /* nothing to do */ - return; - if ((m->m_flags & M_PKTHDR) == 0 || m->m_pkthdr.rcvif == 0) { - m_freem(m); - goto next; - } else { - register struct ifaddr *ifa; - for (ifa = m->m_pkthdr.rcvif->if_addrlist; ifa; ifa = ifa->ifa_next) - if (ifa->ifa_addr->sa_family == AF_ISO) - break; - if (ifa == 0) { - m_freem(m); - goto next; - } - } - bzero((caddr_t)&sh, sizeof(sh)); - sh.snh_flags = m->m_flags & (M_MCAST|M_BCAST); - switch((sh.snh_ifp = m->m_pkthdr.rcvif)->if_type) { - extern int ether_output(); - case IFT_EON: - bcopy(mtod(m, caddr_t), (caddr_t)sh.snh_dhost, sizeof(u_long)); - bcopy(sizeof(u_long) + mtod(m, caddr_t), - (caddr_t)sh.snh_shost, sizeof(u_long)); - sh.snh_dhost[4] = mtod(m, u_char *)[sizeof(struct ip) + - _offsetof(struct eon_hdr, eonh_class)]; - m->m_data += EONIPLEN; - m->m_len -= EONIPLEN; - m->m_pkthdr.len -= EONIPLEN; - break; - - default: - if (sh.snh_ifp->if_output == ether_output) { - bcopy((caddr_t)(mtod(m, struct ether_header *)->ether_dhost), - (caddr_t)sh.snh_dhost, 2*sizeof(sh.snh_dhost)); - m->m_data += sizeof (struct ether_header); - m->m_len -= sizeof (struct ether_header); - m->m_pkthdr.len -= sizeof (struct ether_header); - } - } - IFDEBUG(D_INPUT) - int i; - printf("clnlintr: src:"); - for (i=0; i<6; i++) - printf("%x%c", sh.snh_shost[i] & 0xff, (i<5) ? ':' : ' '); - printf(" dst:"); - for (i=0; i<6; i++) - printf("%x%c", sh.snh_dhost[i] & 0xff, (i<5) ? ':' : ' '); - printf("\n"); - ENDDEBUG - - /* - * Get the fixed part of the clnl header into the first mbuf. - * Drop the packet if this fails. - * Do not call m_pullup if we have a cluster mbuf or the - * data is not there. - */ - if ((IS_CLUSTER(m) || (m->m_len < sizeof(struct clnl_fixed))) && - ((m = m_pullup(m, sizeof(struct clnl_fixed))) == 0)) { - INCSTAT(cns_toosmall); /* TODO: use clnl stats */ - goto next; /* m_pullup discards mbuf */ - } - - clnl = mtod(m, struct clnl_fixed *); - - /* - * Drop packet if the length of the header is not reasonable. - */ - if ((clnl->cnf_hdr_len < CLNP_HDR_MIN) || - (clnl->cnf_hdr_len > CLNP_HDR_MAX)) { - INCSTAT(cns_badhlen); /* TODO: use clnl stats */ - m_freem(m); - goto next; - } - - /* - * If the header is not contained in this mbuf, make it so. - * Drop packet if this fails. - * Note: m_pullup will allocate a cluster mbuf if necessary - */ - if (clnl->cnf_hdr_len > m->m_len) { - if ((m = m_pullup(m, (int)clnl->cnf_hdr_len)) == 0) { - INCSTAT(cns_badhlen); /* TODO: use clnl stats */ - goto next; /* m_pullup discards mbuf */ - } - clnl = mtod(m, struct clnl_fixed *); - } - - clnlsw = &clnl_protox[clnl->cnf_proto_id]; - - - if (clnlsw->clnl_input) - (*clnlsw->clnl_input) (m, &sh); - else - m_freem(m); - - goto next; -} - -/* - * FUNCTION: clnp_input - * - * PURPOSE: process an incoming clnp packet - * - * RETURNS: nothing - * - * SIDE EFFECTS: increments fields of clnp_stat structure. - * - * NOTES: - * TODO: I would like to make seg_part a pointer into the mbuf, but - * will it be correctly aligned? - */ -clnp_input(m, shp) -struct mbuf *m; /* ptr to first mbuf of pkt */ -struct snpa_hdr *shp; /* subnetwork header */ -{ - register struct clnp_fixed *clnp; /* ptr to fixed part of header */ - struct sockaddr_iso source; /* source address of pkt */ - struct sockaddr_iso target; /* destination address of pkt */ -#define src source.siso_addr -#define dst target.siso_addr - caddr_t hoff; /* current offset in packet */ - caddr_t hend; /* address of end of header info */ - struct clnp_segment seg_part; /* segment part of hdr */ - int seg_off=0; /* offset of segment part of hdr */ - int seg_len;/* length of packet data&hdr in bytes */ - struct clnp_optidx oidx, *oidxp = NULL; /* option index */ - extern int iso_systype; /* used by ESIS config resp */ - extern struct sockaddr_iso blank_siso; /* used for initializing */ - int need_afrin = 0; - /* true if congestion experienced */ - /* which means you need afrin nose */ - /* spray. How clever! */ - - IFDEBUG(D_INPUT) - printf( - "clnp_input: proccessing dg; First mbuf m_len %d, m_type x%x, %s\n", - m->m_len, m->m_type, IS_CLUSTER(m) ? "cluster" : "normal"); - ENDDEBUG - need_afrin = 0; - - /* - * If no iso addresses have been set, there is nothing - * to do with the packet. - */ - if (iso_ifaddr == NULL) { - clnp_discard(m, ADDR_DESTUNREACH); - return; - } - - INCSTAT(cns_total); - clnp = mtod(m, struct clnp_fixed *); - - IFDEBUG(D_DUMPIN) - struct mbuf *mhead; - int total_len = 0; - printf("clnp_input: clnp header:\n"); - dump_buf(mtod(m, caddr_t), clnp->cnf_hdr_len); - printf("clnp_input: mbuf chain:\n"); - for (mhead = m; mhead != NULL; mhead=mhead->m_next) { - printf("m x%x, len %d\n", mhead, mhead->m_len); - total_len += mhead->m_len; - } - printf("clnp_input: total length of mbuf chain %d:\n", total_len); - ENDDEBUG - - /* - * Compute checksum (if necessary) and drop packet if - * checksum does not match - */ - if (CKSUM_REQUIRED(clnp) && iso_check_csum(m, (int)clnp->cnf_hdr_len)) { - INCSTAT(cns_badcsum); - clnp_discard(m, GEN_BADCSUM); - return; - } - - if (clnp->cnf_vers != ISO8473_V1) { - INCSTAT(cns_badvers); - clnp_discard(m, DISC_UNSUPPVERS); - return; - } - - - /* check mbuf data length: clnp_data_ck will free mbuf upon error */ - CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, seg_len); - if ((m = clnp_data_ck(m, seg_len)) == 0) - return; - - clnp = mtod(m, struct clnp_fixed *); - hend = (caddr_t)clnp + clnp->cnf_hdr_len; - - /* - * extract the source and destination address - * drop packet on failure - */ - source = target = blank_siso; - - hoff = (caddr_t)clnp + sizeof(struct clnp_fixed); - CLNP_EXTRACT_ADDR(dst, hoff, hend); - if (hoff == (caddr_t)0) { - INCSTAT(cns_badaddr); - clnp_discard(m, GEN_INCOMPLETE); - return; - } - CLNP_EXTRACT_ADDR(src, hoff, hend); - if (hoff == (caddr_t)0) { - INCSTAT(cns_badaddr); - clnp_discard(m, GEN_INCOMPLETE); - return; - } - - IFDEBUG(D_INPUT) - printf("clnp_input: from %s", clnp_iso_addrp(&src)); - printf(" to %s\n", clnp_iso_addrp(&dst)); - ENDDEBUG - - /* - * extract the segmentation information, if it is present. - * drop packet on failure - */ - if (((clnp->cnf_type & CNF_TYPE) != CLNP_ER) && - (clnp->cnf_type & CNF_SEG_OK)) { - if (hoff + sizeof(struct clnp_segment) > hend) { - INCSTAT(cns_noseg); - clnp_discard(m, GEN_INCOMPLETE); - return; - } else { - (void) bcopy(hoff, (caddr_t)&seg_part, sizeof(struct clnp_segment)); - /* make sure segmentation fields are in host order */ - seg_part.cng_id = ntohs(seg_part.cng_id); - seg_part.cng_off = ntohs(seg_part.cng_off); - seg_part.cng_tot_len = ntohs(seg_part.cng_tot_len); - seg_off = hoff - (caddr_t)clnp; - hoff += sizeof(struct clnp_segment); - } - } - - /* - * process options if present. If clnp_opt_sanity returns - * false (indicating an error was found in the options) or - * an unsupported option was found - * then drop packet and emit an ER. - */ - if (hoff < hend) { - int errcode; - - oidxp = &oidx; - errcode = clnp_opt_sanity(m, hoff, hend-hoff, oidxp); - - /* we do not support security */ - if ((errcode == 0) && (oidxp->cni_securep)) - errcode = DISC_UNSUPPSECURE; - - /* the er option is valid with ER pdus only */ - if ((errcode == 0) && (oidxp->cni_er_reason != ER_INVALREAS) && - ((clnp->cnf_type & CNF_TYPE) != CLNP_ER)) - errcode = DISC_UNSUPPOPT; - -#ifdef DECBIT - /* check if the congestion experienced bit is set */ - if (oidxp->cni_qos_formatp) { - caddr_t qosp = CLNP_OFFTOOPT(m, oidxp->cni_qos_formatp); - u_char qos = *qosp; - - need_afrin = ((qos & (CLNPOVAL_GLOBAL|CLNPOVAL_CONGESTED)) == - (CLNPOVAL_GLOBAL|CLNPOVAL_CONGESTED)); - if (need_afrin) - INCSTAT(cns_congest_rcvd); - } -#endif /* DECBIT */ - - if (errcode != 0) { - clnp_discard(m, (char)errcode); - IFDEBUG(D_INPUT) - printf("clnp_input: dropped (err x%x) due to bad options\n", - errcode); - ENDDEBUG - return; - } - } - - /* - * check if this packet is for us. if not, then forward - */ - if (clnp_ours(&dst) == 0) { - IFDEBUG(D_INPUT) - printf("clnp_input: forwarding packet not for us\n"); - ENDDEBUG - clnp_forward(m, seg_len, &dst, oidxp, seg_off, shp); - return; - } - - /* - * ESIS Configuration Response Function - * - * If the packet received was sent to the multicast address - * all end systems, then send an esh to the source - */ - if ((shp->snh_flags & M_MCAST) && (iso_systype == SNPA_ES)) { - extern short esis_holding_time; - - esis_shoutput(shp->snh_ifp, ESIS_ESH, esis_holding_time, - shp->snh_shost, 6, &dst); - } - - /* - * If this is a fragment, then try to reassemble it. If clnp_reass - * returns non NULL, the packet has been reassembled, and should - * be give to TP. Otherwise the fragment has been delt with - * by the reassembly code (either stored or deleted). In either case - * we should have nothing more to do with it. - */ - if (((clnp->cnf_type & CNF_TYPE) != CLNP_ER) && - (clnp->cnf_type & CNF_SEG_OK) && - (seg_len != seg_part.cng_tot_len)) { - struct mbuf *m0; - - if ((m0 = clnp_reass(m, &src, &dst, &seg_part)) != NULL) { - m = m0; - clnp = mtod(m, struct clnp_fixed *); - INCSTAT(cns_reassembled); - } else { - return; - } - } - - /* - * give the packet to the higher layer - * - * Note: the total length of packet - * is the total length field of the segmentation part, - * or, if absent, the segment length field of the - * header. - */ - INCSTAT(cns_delivered); - switch (clnp->cnf_type & CNF_TYPE) { - case CLNP_ER: - /* - * This ER must have the er option. - * If the option is not present, discard datagram. - */ - if (oidxp == NULL || oidxp->cni_er_reason == ER_INVALREAS) { - clnp_discard(m, GEN_HDRSYNTAX); - } else { - clnp_er_input(m, &src, oidxp->cni_er_reason); - } - break; - - case CLNP_DT: - (*isosw[clnp_protox[ISOPROTO_TP]].pr_input)(m, &source, &target, - clnp->cnf_hdr_len, need_afrin); - break; - - case CLNP_RAW: - case CLNP_ECR: - IFDEBUG(D_INPUT) - printf("clnp_input: raw input of %d bytes\n", - clnp->cnf_type & CNF_SEG_OK ? seg_part.cng_tot_len : seg_len); - ENDDEBUG - (*isosw[clnp_protox[ISOPROTO_RAW]].pr_input)(m, &source, &target, - clnp->cnf_hdr_len); - break; - - case CLNP_EC: - IFDEBUG(D_INPUT) - printf("clnp_input: echoing packet\n"); - ENDDEBUG - (void)clnp_echoreply(m, - (clnp->cnf_type & CNF_SEG_OK ? (int)seg_part.cng_tot_len : seg_len), - &source, &target, oidxp); - break; - - default: - printf("clnp_input: unknown clnp pkt type %d\n", - clnp->cnf_type & CNF_TYPE); - clnp_stat.cns_delivered--; - clnp_stat.cns_noproto++; - clnp_discard(m, GEN_HDRSYNTAX); - break; - } -} -#endif /* ISO */ diff --git a/bsd/netiso/clnp_options.c b/bsd/netiso/clnp_options.c deleted file mode 100644 index fe9498d22..000000000 --- a/bsd/netiso/clnp_options.c +++ /dev/null @@ -1,551 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)clnp_options.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ - -#if ISO - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -/* - * FUNCTION: clnp_update_srcrt - * - * PURPOSE: Process src rt option accompanying a clnp datagram. - * - bump src route ptr if src routing and - * we appear current in src route list. - * - * RETURNS: none - * - * SIDE EFFECTS: - * - * NOTES: If source routing has been terminated, do nothing. - */ -clnp_update_srcrt(options, oidx) -struct mbuf *options; /* ptr to options mbuf */ -struct clnp_optidx *oidx; /* ptr to option index */ -{ - u_char len; /* length of current address */ - struct iso_addr isoa; /* copy current address into here */ - - if (CLNPSRCRT_TERM(oidx, options)) { - IFDEBUG(D_OPTIONS) - printf("clnp_update_srcrt: src rt terminated\n"); - ENDDEBUG - return; - } - - len = CLNPSRCRT_CLEN(oidx, options); - bcopy(CLNPSRCRT_CADDR(oidx, options), (caddr_t)&isoa, len); - isoa.isoa_len = len; - - IFDEBUG(D_OPTIONS) - printf("clnp_update_srcrt: current src rt: %s\n", - clnp_iso_addrp(&isoa)); - ENDDEBUG - - if (clnp_ours(&isoa)) { - IFDEBUG(D_OPTIONS) - printf("clnp_update_srcrt: updating src rt\n"); - ENDDEBUG - - /* update pointer to next src route */ - len++; /* count length byte too! */ - CLNPSRCRT_OFF(oidx, options) += len; - } -} - -/* - * FUNCTION: clnp_dooptions - * - * PURPOSE: Process options accompanying a clnp datagram. - * Processing includes - * - log our address if recording route - * - * RETURNS: none - * - * SIDE EFFECTS: - * - * NOTES: - */ -clnp_dooptions(options, oidx, ifp, isoa) -struct mbuf *options; /* ptr to options mbuf */ -struct clnp_optidx *oidx; /* ptr to option index */ -struct ifnet *ifp; /* ptr to interface pkt is leaving on */ -struct iso_addr *isoa; /* ptr to our address for this ifp */ -{ - /* - * If record route is specified, move all - * existing records over, and insert the address of - * interface passed - */ - if (oidx->cni_recrtp) { - char *opt; /* ptr to beginning of recrt option */ - u_char off; /* offset from opt of first free byte */ - char *rec_start; /* beginning of new rt recorded */ - - opt = CLNP_OFFTOOPT(options, oidx->cni_recrtp); - off = *(opt + 1); - rec_start = opt + off - 1; - - IFDEBUG(D_OPTIONS) - printf("clnp_dooptions: record route: option x%x for %d bytes\n", - opt, oidx->cni_recrt_len); - printf("\tfree slot offset x%x\n", off); - printf("clnp_dooptions: recording %s\n", clnp_iso_addrp(isoa)); - printf("clnp_dooptions: option dump:\n"); - dump_buf(opt, oidx->cni_recrt_len); - ENDDEBUG - - /* proceed only if recording has not been terminated */ - if (off != 0xff) { - int new_addrlen = isoa->isoa_len + 1; - /* - * if there is insufficient room to store the next address, - * then terminate recording. Plus 1 on isoa_len is for the - * length byte itself - */ - if (oidx->cni_recrt_len - (off - 1) < new_addrlen) { - *(opt + 1) = 0xff; /* terminate recording */ - } else { - IFDEBUG(D_OPTIONS) - printf("clnp_dooptions: new addr at x%x for %d\n", - rec_start, new_addrlen); - ENDDEBUG - - bcopy((caddr_t)isoa, rec_start, new_addrlen); - - /* update offset field */ - *(opt + 1) += new_addrlen; - - IFDEBUG(D_OPTIONS) - printf("clnp_dooptions: new option dump:\n"); - dump_buf(opt, oidx->cni_recrt_len); - ENDDEBUG - } - } - } -} - -/* - * FUNCTION: clnp_set_opts - * - * PURPOSE: Check the data mbuf passed for option sanity. If it is - * ok, then set the options ptr to address the data mbuf. - * If an options mbuf exists, free it. This implies that - * any old options will be lost. If data is NULL, simply - * free any old options. - * - * RETURNS: unix error code - * - * SIDE EFFECTS: - * - * NOTES: - */ -clnp_set_opts(options, data) -struct mbuf **options; /* target for option information */ -struct mbuf **data; /* source of option information */ -{ - int error = 0; /* error return value */ - struct clnp_optidx dummy; /* dummy index - not used */ - - /* - * remove any existing options - */ - if (*options != NULL) { - m_freem(*options); - *options = NULL; - } - - if (*data != NULL) { - /* - * Insure that the options are reasonable. - * - * Also, we do not support security, priority, - * nor do we allow one to send an ER option - * - * The QOS parameter is checked for the DECBIT. - */ - if ((clnp_opt_sanity(*data, mtod(*data, caddr_t), (*data)->m_len, - &dummy) != 0) || - (dummy.cni_securep) || - (dummy.cni_priorp) || - (dummy.cni_er_reason != ER_INVALREAS)) { - error = EINVAL; - } else { - *options = *data; - *data = NULL; /* so caller won't free mbuf @ *data */ - } - } - return error; -} - -/* - * FUNCTION: clnp_opt_sanity - * - * PURPOSE: Check the options (beginning at opts for len bytes) for - * sanity. In addition, fill in the option index structure - * in with information about each option discovered. - * - * RETURNS: success (options check out) - 0 - * failure - an ER pdu error code describing failure - * - * SIDE EFFECTS: - * - * NOTES: Each pointer field of the option index is filled in with - * the offset from the beginning of the mbuf data, not the - * actual address. - */ -clnp_opt_sanity(m, opts, len, oidx) -struct mbuf *m; /* mbuf options reside in */ -caddr_t opts; /* ptr to buffer containing options */ -int len; /* length of buffer */ -struct clnp_optidx *oidx; /* RETURN: filled in with option idx info */ -{ - u_char opcode; /* code of particular option */ - u_char oplen; /* length of a particular option */ - caddr_t opts_end; /* ptr to end of options */ - u_char pad = 0, secure = 0, srcrt = 0, recrt = 0, qos = 0, prior = 0; - /* flags for catching duplicate options */ - - IFDEBUG(D_OPTIONS) - printf("clnp_opt_sanity: checking %d bytes of data:\n", len); - dump_buf(opts, len); - ENDDEBUG - - /* clear option index field if passed */ - bzero((caddr_t)oidx, sizeof(struct clnp_optidx)); - - /* - * We need to indicate whether the ER option is present. This is done - * by overloading the er_reason field to also indicate presense of - * the option along with the option value. I would like ER_INVALREAS - * to have value 0, but alas, 0 is a valid er reason... - */ - oidx->cni_er_reason = ER_INVALREAS; - - opts_end = opts + len; - while (opts < opts_end) { - /* must have at least 2 bytes per option (opcode and len) */ - if (opts + 2 > opts_end) - return(GEN_INCOMPLETE); - - opcode = *opts++; - oplen = *opts++; - IFDEBUG(D_OPTIONS) - printf("clnp_opt_sanity: opcode is %x and oplen %d\n", - opcode, oplen); - printf("clnp_opt_sanity: clnpoval_SRCRT is %x\n", CLNPOVAL_SRCRT); - - switch (opcode) { - case CLNPOVAL_PAD: { - printf("CLNPOVAL_PAD\n"); - } break; - case CLNPOVAL_SECURE: { - printf("CLNPOVAL_SECURE\n"); - } break; - case CLNPOVAL_SRCRT: { - printf("CLNPOVAL_SRCRT\n"); - } break; - case CLNPOVAL_RECRT: { - printf("CLNPOVAL_RECRT\n"); - } break; - case CLNPOVAL_QOS: { - printf("CLNPOVAL_QOS\n"); - } break; - case CLNPOVAL_PRIOR: { - printf("CLNPOVAL_PRIOR\n"); - } break; - case CLNPOVAL_ERREAS: { - printf("CLNPOVAL_ERREAS\n"); - } break; - default: - printf("UKNOWN option %x\n", opcode); - } - ENDDEBUG - - /* don't allow crazy length values */ - if (opts + oplen > opts_end) - return(GEN_INCOMPLETE); - - switch (opcode) { - case CLNPOVAL_PAD: - /* - * Padding: increment pointer by length of padding - */ - if (pad++) /* duplicate ? */ - return(GEN_DUPOPT); - opts += oplen; - break; - - case CLNPOVAL_SECURE: { - u_char format = *opts; - - if (secure++) /* duplicate ? */ - return(GEN_DUPOPT); - /* - * Security: high 2 bits of first octet indicate format - * (00 in high bits is reserved). - * Remaining bits must be 0. Remaining octets indicate - * actual security - */ - if (((format & 0x3f) > 0) || /* low 6 bits set ? */ - ((format & 0xc0) == 0)) /* high 2 bits zero ? */ - return(GEN_HDRSYNTAX); - - oidx->cni_securep = CLNP_OPTTOOFF(m, opts); - oidx->cni_secure_len = oplen; - opts += oplen; - } break; - - case CLNPOVAL_SRCRT: { - u_char type, offset; /* type of rt, offset of start */ - caddr_t route_end; /* address of end of route option */ - - IFDEBUG(D_OPTIONS) - printf("clnp_opt_sanity: SRC RT\n"); - ENDDEBUG - - if (srcrt++) /* duplicate ? */ - return(GEN_DUPOPT); - /* - * source route: There must be 2 bytes following the length - * field: type and offset. The type must be either - * partial route or complete route. The offset field must - * be within the option. A single exception is made, however. - * The offset may be 1 greater than the length. This case - * occurs when the last source route record is consumed. - * In this case, we ignore the source route option. - * RAH? You should be able to set offset to 'ff' like in record - * route! - * Following this is a series of address fields. - * Each address field is composed of a (length, address) pair. - * Insure that the offset and each address length is reasonable - */ - route_end = opts + oplen; - - if (opts + 2 > route_end) - return(SRCRT_SYNTAX); - - type = *opts; - offset = *(opts+1); - - - /* type must be partial or complete */ - if (!((type == CLNPOVAL_PARTRT) || (type == CLNPOVAL_COMPRT))) - return(SRCRT_SYNTAX); - - oidx->cni_srcrt_s = CLNP_OPTTOOFF(m, opts); - oidx->cni_srcrt_len = oplen; - - opts += offset-1; /*set opts to first addr in rt */ - - /* - * Offset must be reasonable: - * less than end of options, or equal to end of options - */ - if (opts >= route_end) { - if (opts == route_end) { - IFDEBUG(D_OPTIONS) - printf("clnp_opt_sanity: end of src route info\n"); - ENDDEBUG - break; - } else - return(SRCRT_SYNTAX); - } - - while (opts < route_end) { - u_char addrlen = *opts++; - if (opts + addrlen > route_end) - return(SRCRT_SYNTAX); - opts += addrlen; - } - } break; - case CLNPOVAL_RECRT: { - u_char type, offset; /* type of rt, offset of start */ - caddr_t record_end; /* address of end of record option */ - - if (recrt++) /* duplicate ? */ - return(GEN_DUPOPT); - /* - * record route: after the length field, expect a - * type and offset. Type must be partial or complete. - * Offset indicates where to start recording. Insure it - * is within the option. All ones for offset means - * recording is terminated. - */ - record_end = opts + oplen; - - oidx->cni_recrtp = CLNP_OPTTOOFF(m, opts); - oidx->cni_recrt_len = oplen; - - if (opts + 2 > record_end) - return(GEN_INCOMPLETE); - - type = *opts; - offset = *(opts+1); - - /* type must be partial or complete */ - if (!((type == CLNPOVAL_PARTRT) || (type == CLNPOVAL_COMPRT))) - return(GEN_HDRSYNTAX); - - /* offset must be reasonable */ - if ((offset < 0xff) && (opts + offset > record_end)) - return(GEN_HDRSYNTAX); - opts += oplen; - } break; - case CLNPOVAL_QOS: { - u_char format = *opts; - - if (qos++) /* duplicate ? */ - return(GEN_DUPOPT); - /* - * qos: high 2 bits of first octet indicate format - * (00 in high bits is reserved). - * Remaining bits must be 0 (unless format indicates - * globally unique qos, in which case remaining bits indicate - * qos (except bit 6 which is reserved)). Otherwise, - * remaining octets indicate actual qos. - */ - if (((format & 0xc0) == 0) || /* high 2 bits zero ? */ - (((format & 0xc0) != CLNPOVAL_GLOBAL) && - ((format & 0x3f) > 0))) /* not global,low bits used ? */ - return(GEN_HDRSYNTAX); - - oidx->cni_qos_formatp = CLNP_OPTTOOFF(m, opts); - oidx->cni_qos_len = oplen; - - opts += oplen; - } break; - - case CLNPOVAL_PRIOR: { - if (prior++) /* duplicate ? */ - return(GEN_DUPOPT); - /* - * priority: value must be one byte long - */ - if (oplen != 1) - return(GEN_HDRSYNTAX); - - oidx->cni_priorp = CLNP_OPTTOOFF(m, opts); - - opts += oplen; - } break; - - case CLNPOVAL_ERREAS: { - /* - * er reason: value must be two bytes long - */ - if (oplen != 2) - return(GEN_HDRSYNTAX); - - oidx->cni_er_reason = *opts; - - opts += oplen; - } break; - - default: { - IFDEBUG(D_OPTIONS) - printf("clnp_opt_sanity: UNKNOWN OPTION 0x%x\n", opcode); - ENDDEBUG - return(DISC_UNSUPPOPT); - } - } - } - IFDEBUG(D_OPTIONS) - printf("clnp_opt_sanity: return(0)\n", opcode); - ENDDEBUG - return(0); -} -#endif /* ISO */ diff --git a/bsd/netiso/clnp_output.c b/bsd/netiso/clnp_output.c deleted file mode 100644 index e425f0b43..000000000 --- a/bsd/netiso/clnp_output.c +++ /dev/null @@ -1,580 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)clnp_output.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -static struct clnp_fixed dt_template = { - ISO8473_CLNP, /* network identifier */ - 0, /* length */ - ISO8473_V1, /* version */ - CLNP_TTL, /* ttl */ - CLNP_DT|CNF_SEG_OK|CNF_ERR_OK, /* type */ - 0, /* segment length */ - 0 /* checksum */ -}; - -static struct clnp_fixed raw_template = { - ISO8473_CLNP, /* network identifier */ - 0, /* length */ - ISO8473_V1, /* version */ - CLNP_TTL, /* ttl */ - CLNP_RAW|CNF_SEG_OK|CNF_ERR_OK, /* type */ - 0, /* segment length */ - 0 /* checksum */ -}; - -static struct clnp_fixed echo_template = { - ISO8473_CLNP, /* network identifier */ - 0, /* length */ - ISO8473_V1, /* version */ - CLNP_TTL, /* ttl */ - CLNP_EC|CNF_SEG_OK|CNF_ERR_OK, /* type */ - 0, /* segment length */ - 0 /* checksum */ -}; - -static struct clnp_fixed echor_template = { - ISO8473_CLNP, /* network identifier */ - 0, /* length */ - ISO8473_V1, /* version */ - CLNP_TTL, /* ttl */ - CLNP_ECR|CNF_SEG_OK|CNF_ERR_OK, /* type */ - 0, /* segment length */ - 0 /* checksum */ -}; - -#ifdef DECBIT -u_char qos_option[] = {CLNPOVAL_QOS, 1, - CLNPOVAL_GLOBAL|CLNPOVAL_SEQUENCING|CLNPOVAL_LOWDELAY}; -#endif /* DECBIT */ - -int clnp_id = 0; /* id for segmented dgrams */ - -/* - * FUNCTION: clnp_output - * - * PURPOSE: output the data in the mbuf as a clnp datagram - * - * The data specified by m0 is sent as a clnp datagram. - * The mbuf chain m0 will be freed when this routine has - * returned. - * - * If options is non-null, it points to an mbuf which contains - * options to be sent with the datagram. The options must - * be formatted in the mbuf according to clnp rules. Options - * will not be freed. - * - * Datalen specifies the length of the data in m0. - * - * Src and dst are the addresses for the packet. - * - * If route is non-null, it is used as the route for - * the packet. - * - * By default, a DT is sent. However, if flags & CNLP_SEND_ER - * then an ER will be sent. If flags & CLNP_SEND_RAW, then - * the packet will be send as raw clnp. - * - * RETURNS: 0 success - * appropriate error code - * - * SIDE EFFECTS: none - * - * NOTES: - * Flags are interpretated as follows: - * CLNP_NO_SEG - do not allow this pkt to be segmented. - * CLNP_NO_ER - have pkt request ER suppression. - * CLNP_SEND_RAW - send pkt as RAW DT rather than TP DT - * CLNP_NO_CKSUM - don't compute clnp checksum - * CLNP_ECHO - send as ECHO packet - * - * When checking for a cached packet, clnp checks - * that the route taken is still up. It does not - * check that the route is still to the same destination. - * This means that any entity that alters an existing - * route for an isopcb (such as when a redirect arrives) - * must invalidate the clnp cache. It might be perferable - * to have clnp check that the route has the same dest, but - * by avoiding this check, we save a call to iso_addrmatch1. - */ -clnp_output(m0, isop, datalen, flags) -struct mbuf *m0; /* data for the packet */ -struct isopcb *isop; /* iso pcb */ -int datalen; /* number of bytes of data in m0 */ -int flags; /* flags */ -{ - int error = 0; /* return value of function */ - register struct mbuf *m = m0; /* mbuf for clnp header chain */ - register struct clnp_fixed *clnp; /* ptr to fixed part of hdr */ - register caddr_t hoff; /* offset into header */ - int total_len; /* total length of packet */ - struct iso_addr *src; /* ptr to source address */ - struct iso_addr *dst; /* ptr to destination address */ - struct clnp_cache clc; /* storage for cache information */ - struct clnp_cache *clcp = NULL; /* ptr to clc */ - int hdrlen = 0; - - dst = &isop->isop_faddr->siso_addr; - if (isop->isop_laddr == 0) { - struct iso_ifaddr *ia = 0; - clnp_route(dst, &isop->isop_route, flags, 0, &ia); - if (ia == 0 || ia->ia_ifa.ifa_addr->sa_family != AF_ISO) - return (ENETUNREACH); - src = &ia->ia_addr.siso_addr; - } else - src = &isop->isop_laddr->siso_addr; - - IFDEBUG(D_OUTPUT) - printf("clnp_output: to %s", clnp_iso_addrp(dst)); - printf(" from %s of %d bytes\n", clnp_iso_addrp(src), datalen); - printf("\toptions x%x, flags x%x, isop_clnpcache x%x\n", - isop->isop_options, flags, isop->isop_clnpcache); - ENDDEBUG - - if (isop->isop_clnpcache != NULL) { - clcp = mtod(isop->isop_clnpcache, struct clnp_cache *); - } - - /* - * Check if cache is valid ... - */ - IFDEBUG(D_OUTPUT) - printf("clnp_output: ck cache: clcp %x\n", clcp); - if (clcp != NULL) { - printf("\tclc_dst %s\n", clnp_iso_addrp(&clcp->clc_dst)); - printf("\tisop_opts x%x, clc_opts x%x\n", isop->isop_options, - clcp->clc_options); - if (isop->isop_route.ro_rt) - printf("\tro_rt x%x, rt_flags x%x\n", - isop->isop_route.ro_rt, isop->isop_route.ro_rt->rt_flags); - printf("\tflags x%x, clc_flags x%x\n", flags, clcp->clc_flags); - printf("\tclc_hdr x%x\n", clcp->clc_hdr); - } - ENDDEBUG - if ((clcp != NULL) && /* cache exists */ - (isop->isop_options == clcp->clc_options) && /* same options */ - (iso_addrmatch1(dst, &clcp->clc_dst)) && /* dst still same */ - (isop->isop_route.ro_rt != NULL) && /* route exists */ - (isop->isop_route.ro_rt == clcp->clc_rt) && /* and is cached */ - (isop->isop_route.ro_rt->rt_flags & RTF_UP) && /* route still up */ - (flags == clcp->clc_flags) && /* same flags */ - (clcp->clc_hdr != NULL)) { /* hdr mbuf exists */ - /* - * The cache is valid - */ - - IFDEBUG(D_OUTPUT) - printf("clnp_output: using cache\n"); - ENDDEBUG - - m = m_copy(clcp->clc_hdr, 0, (int)M_COPYALL); - if (m == NULL) { - /* - * No buffers left to copy cached packet header. Use - * the cached packet header this time, and - * mark the hdr as vacant - */ - m = clcp->clc_hdr; - clcp->clc_hdr = NULL; - } - m->m_next = m0; /* ASSUMES pkt hdr is 1 mbuf long */ - clnp = mtod(m, struct clnp_fixed *); - } else { - struct clnp_optidx *oidx = NULL; /* index to clnp options */ - - /* - * The cache is not valid. Allocate an mbuf (if necessary) - * to hold cached info. If one is not available, then - * don't bother with the cache - */ - INCSTAT(cns_cachemiss); - if (flags & CLNP_NOCACHE) { - clcp = &clc; - } else { - if (isop->isop_clnpcache == NULL) { - /* - * There is no clnpcache. Allocate an mbuf to hold one - */ - if ((isop->isop_clnpcache = m_get(M_DONTWAIT, MT_HEADER)) - == NULL) { - /* - * No mbufs available. Pretend that we don't want - * caching this time. - */ - IFDEBUG(D_OUTPUT) - printf("clnp_output: no mbufs to allocate to cache\n"); - ENDDEBUG - flags |= CLNP_NOCACHE; - clcp = &clc; - } else { - clcp = mtod(isop->isop_clnpcache, struct clnp_cache *); - } - } else { - /* - * A clnpcache mbuf exists. If the clc_hdr is not null, - * we must free it, as a new one is about to be created. - */ - clcp = mtod(isop->isop_clnpcache, struct clnp_cache *); - if (clcp->clc_hdr != NULL) { - /* - * The clc_hdr is not null but a clnpcache mbuf exists. - * This means that there was a cache, but the existing - * copy of the hdr is no longer valid. Free it now - * before we lose the pointer to it. - */ - IFDEBUG(D_OUTPUT) - printf("clnp_output: freeing old clc_hdr 0x%x\n", - clcp->clc_hdr); - ENDDEBUG - m_free(clcp->clc_hdr); - IFDEBUG(D_OUTPUT) - printf("clnp_output: freed old clc_hdr (done)\n"); - ENDDEBUG - } - } - } - IFDEBUG(D_OUTPUT) - printf("clnp_output: NEW clcp x%x\n",clcp); - ENDDEBUG - bzero((caddr_t)clcp, sizeof(struct clnp_cache)); - - if (isop->isop_optindex) - oidx = mtod(isop->isop_optindex, struct clnp_optidx *); - - /* - * Don't allow packets with security, quality of service, - * priority, or error report options to be sent. - */ - if ((isop->isop_options) && (oidx)) { - if ((oidx->cni_securep) || - (oidx->cni_priorp) || - (oidx->cni_qos_formatp) || - (oidx->cni_er_reason != ER_INVALREAS)) { - IFDEBUG(D_OUTPUT) - printf("clnp_output: pkt dropped - option unsupported\n"); - ENDDEBUG - m_freem(m0); - return(EINVAL); - } - } - - /* - * Don't allow any invalid flags to be set - */ - if ((flags & (CLNP_VFLAGS)) != flags) { - IFDEBUG(D_OUTPUT) - printf("clnp_output: packet dropped - flags unsupported\n"); - ENDDEBUG - INCSTAT(cns_odropped); - m_freem(m0); - return(EINVAL); - } - - /* - * Don't allow funny lengths on dst; src may be zero in which - * case we insert the source address based upon the interface - */ - if ((src->isoa_len > sizeof(struct iso_addr)) || - (dst->isoa_len == 0) || - (dst->isoa_len > sizeof(struct iso_addr))) { - m_freem(m0); - INCSTAT(cns_odropped); - return(ENAMETOOLONG); - } - - /* - * Grab mbuf to contain header - */ - MGETHDR(m, M_DONTWAIT, MT_HEADER); - if (m == 0) { - m_freem(m0); - INCSTAT(cns_odropped); - return(ENOBUFS); - } - INCSTAT(cns_sent); - m->m_next = m0; - clnp = mtod(m, struct clnp_fixed *); - clcp->clc_segoff = 0; - - /* - * Fill in all of fixed hdr except lengths and checksum - */ - if (flags & CLNP_SEND_RAW) { - *clnp = raw_template; - } else if (flags & CLNP_ECHO) { - *clnp = echo_template; - } else if (flags & CLNP_ECHOR) { - *clnp = echor_template; - } else { - *clnp = dt_template; - } - if (flags & CLNP_NO_SEG) - clnp->cnf_type &= ~CNF_SEG_OK; - if (flags & CLNP_NO_ER) - clnp->cnf_type &= ~CNF_ERR_OK; - - /* - * Route packet; special case for source rt - */ - if ((isop->isop_options) && CLNPSRCRT_VALID(oidx)) { - IFDEBUG(D_OUTPUT) - printf("clnp_output: calling clnp_srcroute\n"); - ENDDEBUG - error = clnp_srcroute(isop->isop_options, oidx, &isop->isop_route, - &clcp->clc_firsthop, &clcp->clc_ifa, dst); - } else { - IFDEBUG(D_OUTPUT) - ENDDEBUG - error = clnp_route(dst, &isop->isop_route, flags, - &clcp->clc_firsthop, &clcp->clc_ifa); - } - if (error || (clcp->clc_ifa == 0)) { - IFDEBUG(D_OUTPUT) - printf("clnp_output: route failed, errno %d\n", error); - printf("@clcp:\n"); - dump_buf(clcp, sizeof (struct clnp_cache)); - ENDDEBUG - goto bad; - } - clcp->clc_rt = isop->isop_route.ro_rt; /* XXX */ - clcp->clc_ifp = clcp->clc_ifa->ia_ifp; /* XXX */ - - IFDEBUG(D_OUTPUT) - printf("clnp_output: packet routed to %s\n", - clnp_iso_addrp( - &((struct sockaddr_iso *)clcp->clc_firsthop)->siso_addr)); - ENDDEBUG - - /* - * If src address is not yet specified, use address of - * interface. NOTE: this will now update the laddr field in - * the isopcb. Is this desirable? RAH? - */ - if (src->isoa_len == 0) { - src = &(clcp->clc_ifa->ia_addr.siso_addr); - IFDEBUG(D_OUTPUT) - printf("clnp_output: new src %s\n", clnp_iso_addrp(src)); - ENDDEBUG - } - - /* - * Insert the source and destination address, - */ - hoff = (caddr_t)clnp + sizeof(struct clnp_fixed); - CLNP_INSERT_ADDR(hoff, *dst); - CLNP_INSERT_ADDR(hoff, *src); - - /* - * Leave room for the segment part, if segmenting is selected - */ - if (clnp->cnf_type & CNF_SEG_OK) { - clcp->clc_segoff = hoff - (caddr_t)clnp; - hoff += sizeof(struct clnp_segment); - } - - clnp->cnf_hdr_len = m->m_len = (u_char)(hoff - (caddr_t)clnp); - hdrlen = clnp->cnf_hdr_len; - -#ifdef DECBIT - /* - * Add the globally unique QOS (with room for congestion experienced - * bit). I can safely assume that this option is not in the options - * mbuf below because I checked that the option was not specified - * previously - */ - if ((m->m_len + sizeof(qos_option)) < MLEN) { - bcopy((caddr_t)qos_option, hoff, sizeof(qos_option)); - clnp->cnf_hdr_len += sizeof(qos_option); - hdrlen += sizeof(qos_option); - m->m_len += sizeof(qos_option); - } -#endif /* DECBIT */ - - /* - * If an options mbuf is present, concatenate a copy to the hdr mbuf. - */ - if (isop->isop_options) { - struct mbuf *opt_copy = m_copy(isop->isop_options, 0, (int)M_COPYALL); - if (opt_copy == NULL) { - error = ENOBUFS; - goto bad; - } - /* Link in place */ - opt_copy->m_next = m->m_next; - m->m_next = opt_copy; - - /* update size of header */ - clnp->cnf_hdr_len += opt_copy->m_len; - hdrlen += opt_copy->m_len; - } - - if (hdrlen > CLNP_HDR_MAX) { - error = EMSGSIZE; - goto bad; - } - - /* - * Now set up the cache entry in the pcb - */ - if ((flags & CLNP_NOCACHE) == 0) { - if (clcp->clc_hdr = m_copy(m, 0, (int)clnp->cnf_hdr_len)) { - clcp->clc_dst = *dst; - clcp->clc_flags = flags; - clcp->clc_options = isop->isop_options; - } - } - } - /* - * If small enough for interface, send directly - * Fill in segmentation part of hdr if using the full protocol - */ - total_len = clnp->cnf_hdr_len + datalen; - if (clnp->cnf_type & CNF_SEG_OK) { - struct clnp_segment seg_part; /* segment part of hdr */ - seg_part.cng_id = htons(clnp_id++); - seg_part.cng_off = htons(0); - seg_part.cng_tot_len = htons(total_len); - (void) bcopy((caddr_t)&seg_part, (caddr_t) clnp + clcp->clc_segoff, - sizeof(seg_part)); - } - if (total_len <= SN_MTU(clcp->clc_ifp, clcp->clc_rt)) { - HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, total_len); - m->m_pkthdr.len = total_len; - /* - * Compute clnp checksum (on header only) - */ - if (flags & CLNP_NO_CKSUM) { - HTOC(clnp->cnf_cksum_msb, clnp->cnf_cksum_lsb, 0); - } else { - iso_gen_csum(m, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len); - } - - IFDEBUG(D_DUMPOUT) - struct mbuf *mdump = m; - printf("clnp_output: sending dg:\n"); - while (mdump != NULL) { - dump_buf(mtod(mdump, caddr_t), mdump->m_len); - mdump = mdump->m_next; - } - ENDDEBUG - - error = SN_OUTPUT(clcp, m); - goto done; - } else { - /* - * Too large for interface; fragment if possible. - */ - error = clnp_fragment(clcp->clc_ifp, m, clcp->clc_firsthop, - total_len, clcp->clc_segoff, flags, clcp->clc_rt); - goto done; - } -bad: - m_freem(m); -done: - if (error) { - clnp_stat.cns_sent--; - clnp_stat.cns_odropped++; - } - return (error); -} - -int clnp_ctloutput() -{ -} diff --git a/bsd/netiso/clnp_raw.c b/bsd/netiso/clnp_raw.c deleted file mode 100644 index 264196757..000000000 --- a/bsd/netiso/clnp_raw.c +++ /dev/null @@ -1,372 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)clnp_raw.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include /* XXX -- defines SOL_NETWORK */ - -struct sockproto rclnp_proto = { PF_ISO, 0 }; -/* - * FUNCTION: rclnp_input - * - * PURPOSE: Setup generic address an protocol structures for - * raw input routine, then pass them along with the - * mbuf chain. - * - * RETURNS: none - * - * SIDE EFFECTS: - * - * NOTES: The protocol field of rclnp_proto is set to zero indicating - * no protocol. - */ -rclnp_input(m, src, dst, hdrlen) -struct mbuf *m; /* ptr to packet */ -struct sockaddr_iso *src; /* ptr to src address */ -struct sockaddr_iso *dst; /* ptr to dest address */ -int hdrlen; /* length (in bytes) of clnp header */ -{ -#ifdef TROLL - if (trollctl.tr_ops & TR_CHUCK) { - m_freem(m); - return; - } -#endif /* TROLL */ - - raw_input(m, &rclnp_proto, (struct sockaddr *)src, (struct sockaddr *)dst); -} - -/* - * FUNCTION: rclnp_output - * - * PURPOSE: Prepare to send a raw clnp packet. Setup src and dest - * addresses, count the number of bytes to send, and - * call clnp_output. - * - * RETURNS: success - 0 - * failure - an appropriate error code - * - * SIDE EFFECTS: - * - * NOTES: - */ -rclnp_output(m0, so) -struct mbuf *m0; /* packet to send */ -struct socket *so; /* socket to send from */ -{ - register struct mbuf *m; /* used to scan a chain */ - int len = 0; /* store length of chain here */ - struct rawisopcb *rp = sotorawisopcb(so); /* ptr to raw cb */ - int error; /* return value of function */ - int flags; /* flags for clnp_output */ - - if (0 == (m0->m_flags & M_PKTHDR)) - return (EINVAL); - /* - * Set up src address. If user has bound socket to an address, use it. - * Otherwise, do not specify src (clnp_output will fill it in). - */ - if (rp->risop_rcb.rcb_laddr) { - if (rp->risop_isop.isop_sladdr.siso_family != AF_ISO) { -bad: - m_freem(m0); - return(EAFNOSUPPORT); - } - } - /* set up dest address */ - if (rp->risop_rcb.rcb_faddr == 0) - goto bad; - rp->risop_isop.isop_sfaddr = - *(struct sockaddr_iso *)rp->risop_rcb.rcb_faddr; - rp->risop_isop.isop_faddr = &rp->risop_isop.isop_sfaddr; - - /* get flags and ship it off */ - flags = rp->risop_flags & CLNP_VFLAGS; - - error = clnp_output(m0, &rp->risop_isop, m0->m_pkthdr.len, - flags|CLNP_NOCACHE); - - return (error); -} - -/* - * FUNCTION: rclnp_ctloutput - * - * PURPOSE: Raw clnp socket option processing - * All options are stored inside an mbuf. - * - * RETURNS: success - 0 - * failure - unix error code - * - * SIDE EFFECTS: If the options mbuf does not exist, it the mbuf passed - * is used. - * - * NOTES: - */ -rclnp_ctloutput(op, so, level, optname, m) -int op; /* type of operation */ -struct socket *so; /* ptr to socket */ -int level; /* level of option */ -int optname; /* name of option */ -struct mbuf **m; /* ptr to ptr to option data */ -{ - int error = 0; - register struct rawisopcb *rp = sotorawisopcb(so);/* raw cb ptr */ - - IFDEBUG(D_CTLOUTPUT) - printf("rclnp_ctloutput: op = x%x, level = x%x, name = x%x\n", - op, level, optname); - if (*m != NULL) { - printf("rclnp_ctloutput: %d bytes of mbuf data\n", (*m)->m_len); - dump_buf(mtod((*m), caddr_t), (*m)->m_len); - } - ENDDEBUG - -#ifdef SOL_NETWORK - if (level != SOL_NETWORK) - error = EINVAL; - else switch (op) { -#else - switch (op) { -#endif /* SOL_NETWORK */ - case PRCO_SETOPT: - switch (optname) { - case CLNPOPT_FLAGS: { - u_short usr_flags; - /* - * Insure that the data passed has exactly one short in it - */ - if ((*m == NULL) || ((*m)->m_len != sizeof(short))) { - error = EINVAL; - break; - } - - /* - * Don't allow invalid flags to be set - */ - usr_flags = (*mtod((*m), short *)); - - if ((usr_flags & (CLNP_VFLAGS)) != usr_flags) { - error = EINVAL; - } else - rp->risop_flags |= usr_flags; - - } break; - - case CLNPOPT_OPTS: - if (error = clnp_set_opts(&rp->risop_isop.isop_options, m)) - break; - rp->risop_isop.isop_optindex = m_get(M_WAIT, MT_SOOPTS); - (void) clnp_opt_sanity(rp->risop_isop.isop_options, - mtod(rp->risop_isop.isop_options, caddr_t), - rp->risop_isop.isop_options->m_len, - mtod(rp->risop_isop.isop_optindex, - struct clnp_optidx *)); - break; - } - break; - - case PRCO_GETOPT: -#ifdef notdef - /* commented out to keep hi C quiet */ - switch (optname) { - default: - error = EINVAL; - break; - } -#endif /* notdef */ - break; - default: - error = EINVAL; - break; - } - if (op == PRCO_SETOPT) { - /* note: m_freem does not barf is *m is NULL */ - m_freem(*m); - *m = NULL; - } - - return error; -} - -/*ARGSUSED*/ -clnp_usrreq(so, req, m, nam, control) - register struct socket *so; - int req; - struct mbuf *m, *nam, *control; -{ - register int error = 0; - register struct rawisopcb *rp = sotorawisopcb(so); - - rp = sotorawisopcb(so); - switch (req) { - - case PRU_ATTACH: - if (rp) - panic("rip_attach"); - MALLOC(rp, struct rawisopcb *, sizeof *rp, M_PCB, M_WAITOK); - if (rp == 0) - return (ENOBUFS); - bzero((caddr_t)rp, sizeof *rp); - so->so_pcb = (caddr_t)rp; - break; - - case PRU_DETACH: - if (rp == 0) - panic("rip_detach"); - if (rp->risop_isop.isop_options) - m_freem(rp->risop_isop.isop_options); - if (rp->risop_isop.isop_route.ro_rt) - RTFREE(rp->risop_isop.isop_route.ro_rt); - if (rp->risop_rcb.rcb_laddr) - rp->risop_rcb.rcb_laddr = 0; - /* free clnp cached hdr if necessary */ - if (rp->risop_isop.isop_clnpcache != NULL) { - struct clnp_cache *clcp = - mtod(rp->risop_isop.isop_clnpcache, struct clnp_cache *); - if (clcp->clc_hdr != NULL) { - m_free(clcp->clc_hdr); - } - m_free(rp->risop_isop.isop_clnpcache); - } - if (rp->risop_isop.isop_optindex != NULL) - m_free(rp->risop_isop.isop_optindex); - - break; - - case PRU_BIND: - { - struct sockaddr_iso *addr = mtod(nam, struct sockaddr_iso *); - - if (nam->m_len != sizeof(*addr)) - return (EINVAL); - if ((ifnet == 0) || - (addr->siso_family != AF_ISO) || - (addr->siso_addr.isoa_len && - ifa_ifwithaddr((struct sockaddr *)addr) == 0)) - return (EADDRNOTAVAIL); - rp->risop_isop.isop_sladdr = *addr; - rp->risop_rcb.rcb_laddr = (struct sockaddr *) - (rp->risop_isop.isop_laddr = &rp->risop_isop.isop_sladdr); - return (0); - } - case PRU_CONNECT: - { - struct sockaddr_iso *addr = mtod(nam, struct sockaddr_iso *); - - if ((nam->m_len > sizeof(*addr)) || (addr->siso_len > sizeof(*addr))) - return (EINVAL); - if (ifnet == 0) - return (EADDRNOTAVAIL); - if (addr->siso_family != AF_ISO) - rp->risop_isop.isop_sfaddr = *addr; - rp->risop_rcb.rcb_faddr = (struct sockaddr *) - (rp->risop_isop.isop_faddr = &rp->risop_isop.isop_sfaddr); - soisconnected(so); - return (0); - } - } - error = raw_usrreq(so, req, m, nam, control); - - if (error && req == PRU_ATTACH && so->so_pcb) - FREE((caddr_t)rp, M_PCB); - return (error); -} diff --git a/bsd/netiso/clnp_stat.h b/bsd/netiso/clnp_stat.h deleted file mode 100644 index 901840c38..000000000 --- a/bsd/netiso/clnp_stat.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)clnp_stat.h 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ - - -#ifndef __CLNP_STAT__ -#define __CLNP_STAT__ - -struct clnp_stat { - int cns_total; /* total pkts received */ - int cns_toosmall; /* fixed part of header too small */ - int cns_badhlen; /* header length is not reasonable */ - int cns_badcsum; /* checksum on packet failed */ - int cns_badaddr; /* address fields were not reasonable */ - int cns_badvers; /* incorrect version */ - int cns_noseg; /* segment information forgotten */ - int cns_noproto; /* incorrect protocol id */ - int cns_delivered; /* packets consumed by protocol */ - int cns_ttlexpired; /* ttl has expired */ - int cns_forward; /* forwarded packets */ - int cns_sent; /* total packets sent */ - int cns_odropped; /* o.k. packets discarded, e.g. ENOBUFS */ - int cns_cantforward; /* non-forwarded packets */ - int cns_fragmented; /* packets fragmented */ - int cns_fragments; /* fragments received */ - int cns_fragdropped; /* fragments discarded */ - int cns_fragtimeout; /* fragments timed out */ - int cns_ofragments; /* fragments generated */ - int cns_cantfrag; /* fragmentation prohibited */ - int cns_reassembled; /* packets reconstructed */ - int cns_cachemiss; /* cache misses */ - int cns_congest_set; /* congestion experienced bit set */ - int cns_congest_rcvd; /* congestion experienced bit received */ - int cns_er_inhist[CLNP_ERRORS + 1]; - int cns_er_outhist[CLNP_ERRORS + 1]; -} clnp_stat ; - -#ifdef INCSTAT -#undef INCSTAT -#endif /* INCSTAT */ -#define INCSTAT(x) clnp_stat./**/x/**/++ - -#endif /* __CLNP_STAT__ */ diff --git a/bsd/netiso/clnp_subr.c b/bsd/netiso/clnp_subr.c deleted file mode 100644 index 11e1ad742..000000000 --- a/bsd/netiso/clnp_subr.c +++ /dev/null @@ -1,677 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)clnp_subr.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ - -#if ISO - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -/* - * FUNCTION: clnp_data_ck - * - * PURPOSE: Check that the amount of data in the mbuf chain is - * at least as much as the clnp header would have us - * expect. Trim mbufs if longer than expected, drop - * packet if shorter than expected. - * - * RETURNS: success - ptr to mbuf chain - * failure - 0 - * - * SIDE EFFECTS: - * - * NOTES: - */ -struct mbuf * -clnp_data_ck(m, length) -register struct mbuf *m; /* ptr to mbuf chain containing hdr & data */ -int length; /* length (in bytes) of packet */ - { - register int len; /* length of data */ - register struct mbuf *mhead; /* ptr to head of chain */ - - len = -length; - mhead = m; - for (;;) { - len += m->m_len; - if (m->m_next == 0) - break; - m = m->m_next; - } - if (len != 0) { - if (len < 0) { - INCSTAT(cns_toosmall); - clnp_discard(mhead, GEN_INCOMPLETE); - return 0; - } - if (len <= m->m_len) - m->m_len -= len; - else - m_adj(mhead, -len); - } - return mhead; -} - -#ifdef notdef -/* - * FUNCTION: clnp_extract_addr - * - * PURPOSE: Extract the source and destination address from the - * supplied buffer. Place them in the supplied address buffers. - * If insufficient data is supplied, then fail. - * - * RETURNS: success - Address of first byte in the packet past - * the address part. - * failure - 0 - * - * SIDE EFFECTS: - * - * NOTES: - */ -caddr_t -clnp_extract_addr(bufp, buflen, srcp, destp) -caddr_t bufp; /* ptr to buffer containing addresses */ -int buflen; /* length of buffer */ -register struct iso_addr *srcp; /* ptr to source address buffer */ -register struct iso_addr *destp; /* ptr to destination address buffer */ - { - int len; /* argument to bcopy */ - - /* - * check that we have enough data. Plus1 is for length octet - */ - if ((u_char)*bufp + 1 > buflen) { - return((caddr_t)0); - } - len = destp->isoa_len = (u_char)*bufp++; - (void) bcopy(bufp, (caddr_t)destp, len); - buflen -= len; - bufp += len; - - /* - * check that we have enough data. Plus1 is for length octet - */ - if ((u_char)*bufp + 1 > buflen) { - return((caddr_t)0); - } - len = srcp->isoa_len = (u_char)* bufp++; - (void) bcopy(bufp, (caddr_t)srcp, len); - bufp += len; - - /* - * Insure that the addresses make sense - */ - if (iso_ck_addr(srcp) && iso_ck_addr(destp)) - return bufp; - else - return (caddr_t) 0; -} -#endif /* notdef */ - -/* - * FUNCTION: clnp_ours - * - * PURPOSE: Decide whether the supplied packet is destined for - * us, or that it should be forwarded on. - * - * RETURNS: packet is for us - 1 - * packet is not for us - 0 - * - * SIDE EFFECTS: - * - * NOTES: - */ -clnp_ours(dst) -register struct iso_addr *dst; /* ptr to destination address */ -{ - register struct iso_ifaddr *ia; /* scan through interface addresses */ - - for (ia = iso_ifaddr; ia; ia = ia->ia_next) { - IFDEBUG(D_ROUTE) - printf("clnp_ours: ia_sis x%x, dst x%x\n", &ia->ia_addr, - dst); - ENDDEBUG - /* - * XXX Warning: - * We are overloading siso_tlen in the if's address, as an nsel length. - */ - if (dst->isoa_len == ia->ia_addr.siso_nlen && - bcmp((caddr_t)ia->ia_addr.siso_addr.isoa_genaddr, - (caddr_t)dst->isoa_genaddr, - ia->ia_addr.siso_nlen - ia->ia_addr.siso_tlen) == 0) - return 1; - } - return 0; -} - -/* Dec bit set if ifp qlen is greater than congest_threshold */ -int congest_threshold = 0; - -/* - * FUNCTION: clnp_forward - * - * PURPOSE: Forward the datagram passed - * clnpintr guarantees that the header will be - * contigious (a cluster mbuf will be used if necessary). - * - * If oidx is NULL, no options are present. - * - * RETURNS: nothing - * - * SIDE EFFECTS: - * - * NOTES: - */ -clnp_forward(m, len, dst, oidx, seg_off, inbound_shp) -struct mbuf *m; /* pkt to forward */ -int len; /* length of pkt */ -struct iso_addr *dst; /* destination address */ -struct clnp_optidx *oidx; /* option index */ -int seg_off;/* offset of segmentation part */ -struct snpa_hdr *inbound_shp; /* subnetwork header of inbound packet */ -{ - struct clnp_fixed *clnp; /* ptr to fixed part of header */ - int error; /* return value of route function */ - struct sockaddr *next_hop; /* next hop for dgram */ - struct ifnet *ifp; /* ptr to outgoing interface */ - struct iso_ifaddr *ia = 0;/* ptr to iso name for ifp */ - struct route_iso route; /* filled in by clnp_route */ - extern int iso_systype; - - clnp = mtod(m, struct clnp_fixed *); - bzero((caddr_t)&route, sizeof(route)); /* MUST be done before "bad:" */ - - /* - * Don't forward multicast or broadcast packets - */ - if ((inbound_shp) && (IS_MULTICAST(inbound_shp->snh_dhost))) { - IFDEBUG(D_FORWARD) - printf("clnp_forward: dropping multicast packet\n"); - ENDDEBUG - clnp->cnf_type &= ~CNF_ERR_OK; /* so we don't generate an ER */ - clnp_discard(m, 0); - INCSTAT(cns_cantforward); - goto done; - } - - IFDEBUG(D_FORWARD) - printf("clnp_forward: %d bytes, to %s, options x%x\n", len, - clnp_iso_addrp(dst), oidx); - ENDDEBUG - - /* - * Decrement ttl, and if zero drop datagram - * Can't compare ttl as less than zero 'cause its a unsigned - */ - if ((clnp->cnf_ttl == 0) || (--clnp->cnf_ttl == 0)) { - IFDEBUG(D_FORWARD) - printf("clnp_forward: discarding datagram because ttl is zero\n"); - ENDDEBUG - INCSTAT(cns_ttlexpired); - clnp_discard(m, TTL_EXPTRANSIT); - goto done; - } - /* - * Route packet; special case for source rt - */ - if CLNPSRCRT_VALID(oidx) { - /* - * Update src route first - */ - clnp_update_srcrt(m, oidx); - error = clnp_srcroute(m, oidx, &route, &next_hop, &ia, dst); - } else { - error = clnp_route(dst, &route, 0, &next_hop, &ia); - } - if (error || ia == 0) { - IFDEBUG(D_FORWARD) - printf("clnp_forward: can't route packet (errno %d)\n", error); - ENDDEBUG - clnp_discard(m, ADDR_DESTUNREACH); - INCSTAT(cns_cantforward); - goto done; - } - ifp = ia->ia_ifp; - - IFDEBUG(D_FORWARD) - printf("clnp_forward: packet routed to %s\n", - clnp_iso_addrp(&((struct sockaddr_iso *)next_hop)->siso_addr)); - ENDDEBUG - - INCSTAT(cns_forward); - - /* - * If we are an intermediate system and - * we are routing outbound on the same ifp that the packet - * arrived upon, and we know the next hop snpa, - * then generate a redirect request - */ - if ((iso_systype & SNPA_IS) && (inbound_shp) && - (ifp == inbound_shp->snh_ifp)) - esis_rdoutput(inbound_shp, m, oidx, dst, route.ro_rt); - /* - * If options are present, update them - */ - if (oidx) { - struct iso_addr *mysrc = &ia->ia_addr.siso_addr; - if (mysrc == NULL) { - clnp_discard(m, ADDR_DESTUNREACH); - INCSTAT(cns_cantforward); - clnp_stat.cns_forward--; - goto done; - } else { - (void) clnp_dooptions(m, oidx, ifp, mysrc); - } - } - -#ifdef DECBIT - if (ifp->if_snd.ifq_len > congest_threshold) { - /* - * Congestion! Set the Dec Bit and thank Dave Oran - */ - IFDEBUG(D_FORWARD) - printf("clnp_forward: congestion experienced\n"); - ENDDEBUG - if ((oidx) && (oidx->cni_qos_formatp)) { - caddr_t qosp = CLNP_OFFTOOPT(m, oidx->cni_qos_formatp); - u_char qos = *qosp; - IFDEBUG(D_FORWARD) - printf("clnp_forward: setting congestion bit (qos x%x)\n", qos); - ENDDEBUG - if ((qos & CLNPOVAL_GLOBAL) == CLNPOVAL_GLOBAL) { - qos |= CLNPOVAL_CONGESTED; - INCSTAT(cns_congest_set); - *qosp = qos; - } - } - } -#endif /* DECBIT */ - - /* - * Dispatch the datagram if it is small enough, otherwise fragment - */ - if (len <= SN_MTU(ifp, route.ro_rt)) { - iso_gen_csum(m, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len); - (void) (*ifp->if_output)(ifp, m, next_hop, route.ro_rt); - } else { - (void) clnp_fragment(ifp, m, next_hop, len, seg_off, /* flags */0, route.ro_rt); - } - -done: - /* - * Free route - */ - if (route.ro_rt != NULL) { - RTFREE(route.ro_rt); - } -} - -#ifdef notdef -/* - * FUNCTION: clnp_insert_addr - * - * PURPOSE: Insert the address part into a clnp datagram. - * - * RETURNS: Address of first byte after address part in datagram. - * - * SIDE EFFECTS: - * - * NOTES: Assume that there is enough space for the address part. - */ -caddr_t -clnp_insert_addr(bufp, srcp, dstp) -caddr_t bufp; /* address of where addr part goes */ -register struct iso_addr *srcp; /* ptr to src addr */ -register struct iso_addr *dstp; /* ptr to dst addr */ -{ - *bufp++ = dstp->isoa_len; - (void) bcopy((caddr_t)dstp, bufp, dstp->isoa_len); - bufp += dstp->isoa_len; - - *bufp++ = srcp->isoa_len; - (void) bcopy((caddr_t)srcp, bufp, srcp->isoa_len); - bufp += srcp->isoa_len; - - return bufp; -} - -#endif /* notdef */ - -/* - * FUNCTION: clnp_route - * - * PURPOSE: Route a clnp datagram to the first hop toward its - * destination. In many cases, the first hop will be - * the destination. The address of a route - * is specified. If a routing entry is present in - * that route, and it is still up to the same destination, - * then no further action is necessary. Otherwise, a - * new routing entry will be allocated. - * - * RETURNS: route found - 0 - * unix error code - * - * SIDE EFFECTS: - * - * NOTES: It is up to the caller to free the routing entry - * allocated in route. - */ -clnp_route(dst, ro, flags, first_hop, ifa) - struct iso_addr *dst; /* ptr to datagram destination */ - register struct route_iso *ro; /* existing route structure */ - int flags; /* flags for routing */ - struct sockaddr **first_hop; /* result: fill in with ptr to firsthop */ - struct iso_ifaddr **ifa; /* result: fill in with ptr to interface */ -{ - if (flags & SO_DONTROUTE) { - struct iso_ifaddr *ia; - - if (ro->ro_rt) { - RTFREE(ro->ro_rt); - ro->ro_rt = 0; - } - bzero((caddr_t)&ro->ro_dst, sizeof(ro->ro_dst)); - bcopy((caddr_t)dst, (caddr_t)&ro->ro_dst.siso_addr, - 1 + (unsigned)dst->isoa_len); - ro->ro_dst.siso_family = AF_ISO; - ro->ro_dst.siso_len = sizeof(ro->ro_dst); - ia = iso_localifa(&ro->ro_dst); - if (ia == 0) - return EADDRNOTAVAIL; - if (ifa) - *ifa = ia; - if (first_hop) - *first_hop = (struct sockaddr *)&ro->ro_dst; - return 0; - } - /* - * If there is a cached route, check that it is still up and to - * the same destination. If not, free it and try again. - */ - if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 || - (Bcmp(ro->ro_dst.siso_data, dst->isoa_genaddr, dst->isoa_len)))) { - IFDEBUG(D_ROUTE) - printf("clnp_route: freeing old route: ro->ro_rt 0x%x\n", - ro->ro_rt); - printf("clnp_route: old route refcnt: 0x%x\n", - ro->ro_rt->rt_refcnt); - ENDDEBUG - - /* free old route entry */ - RTFREE(ro->ro_rt); - ro->ro_rt = (struct rtentry *)0; - } else { - IFDEBUG(D_ROUTE) - printf("clnp_route: OK route exists\n"); - ENDDEBUG - } - - if (ro->ro_rt == 0) { - /* set up new route structure */ - bzero((caddr_t)&ro->ro_dst, sizeof(ro->ro_dst)); - ro->ro_dst.siso_len = sizeof(ro->ro_dst); - ro->ro_dst.siso_family = AF_ISO; - Bcopy(dst, &ro->ro_dst.siso_addr, 1 + dst->isoa_len); - /* allocate new route */ - IFDEBUG(D_ROUTE) - printf("clnp_route: allocating new route to %s\n", - clnp_iso_addrp(dst)); - ENDDEBUG - rtalloc((struct route *)ro); - } - if (ro->ro_rt == 0) - return(ENETUNREACH); /* rtalloc failed */ - ro->ro_rt->rt_use++; - if (ifa) - if ((*ifa = (struct iso_ifaddr *)ro->ro_rt->rt_ifa) == 0) - panic("clnp_route"); - if (first_hop) { - if (ro->ro_rt->rt_flags & RTF_GATEWAY) - *first_hop = ro->ro_rt->rt_gateway; - else - *first_hop = (struct sockaddr *)&ro->ro_dst; - } - return(0); -} - -/* - * FUNCTION: clnp_srcroute - * - * PURPOSE: Source route the datagram. If complete source - * routing is specified but not possible, then - * return an error. If src routing is terminated, then - * try routing on destination. - * Usage of first_hop, - * ifp, and error return is identical to clnp_route. - * - * RETURNS: 0 or unix error code - * - * SIDE EFFECTS: - * - * NOTES: Remember that option index pointers are really - * offsets from the beginning of the mbuf. - */ -clnp_srcroute(options, oidx, ro, first_hop, ifa, final_dst) -struct mbuf *options; /* ptr to options */ -struct clnp_optidx *oidx; /* index to options */ -struct route_iso *ro; /* route structure */ -struct sockaddr **first_hop; /* RETURN: fill in with ptr to firsthop */ -struct iso_ifaddr **ifa; /* RETURN: fill in with ptr to interface */ -struct iso_addr *final_dst; /* final destination */ -{ - struct iso_addr dst; /* first hop specified by src rt */ - int error = 0; /* return code */ - - /* - * Check if we have run out of routes - * If so, then try to route on destination. - */ - if CLNPSRCRT_TERM(oidx, options) { - dst.isoa_len = final_dst->isoa_len; - bcopy(final_dst->isoa_genaddr, dst.isoa_genaddr, dst.isoa_len); - } else { - /* - * setup dst based on src rt specified - */ - dst.isoa_len = CLNPSRCRT_CLEN(oidx, options); - bcopy(CLNPSRCRT_CADDR(oidx, options), dst.isoa_genaddr, dst.isoa_len); - } - - /* - * try to route it - */ - error = clnp_route(&dst, ro, 0, first_hop, ifa); - if (error != 0) - return error; - - /* - * If complete src rt, first hop must be equal to dst - */ - if ((CLNPSRCRT_TYPE(oidx, options) == CLNPOVAL_COMPRT) && - (!iso_addrmatch1(&(*(struct sockaddr_iso **)first_hop)->siso_addr,&dst))){ - IFDEBUG(D_OPTIONS) - printf("clnp_srcroute: complete src route failed\n"); - ENDDEBUG - return EHOSTUNREACH; /* RAH? would like ESRCRTFAILED */ - } - - return error; -} - -/* - * FUNCTION: clnp_echoreply - * - * PURPOSE: generate an echo reply packet and transmit - * - * RETURNS: result of clnp_output - * - * SIDE EFFECTS: - */ -clnp_echoreply(ec_m, ec_len, ec_src, ec_dst, ec_oidxp) -struct mbuf *ec_m; /* echo request */ -int ec_len; /* length of ec */ -struct sockaddr_iso *ec_src; /* src of ec */ -struct sockaddr_iso *ec_dst; /* destination of ec (i.e., us) */ -struct clnp_optidx *ec_oidxp; /* options index to ec packet */ -{ - struct isopcb isopcb; - int flags = CLNP_NOCACHE|CLNP_ECHOR; - int ret; - - /* fill in fake isopcb to pass to output function */ - bzero(&isopcb, sizeof(isopcb)); - isopcb.isop_laddr = ec_dst; - isopcb.isop_faddr = ec_src; - - /* forget copying the options for now. If implemented, need only - * copy record route option, but it must be reset to zero length */ - - ret = clnp_output(ec_m, &isopcb, ec_len, flags); - - IFDEBUG(D_OUTPUT) - printf("clnp_echoreply: output returns %d\n", ret); - ENDDEBUG - return ret; -} - -/* - * FUNCTION: clnp_badmtu - * - * PURPOSE: print notice of route with mtu not initialized. - * - * RETURNS: mtu of ifp. - * - * SIDE EFFECTS: prints notice, slows down system. - */ -clnp_badmtu(ifp, rt, line, file) -struct ifnet *ifp; /* outgoing interface */ -struct rtentry *rt; /* dst route */ -int line; /* where the dirty deed occured */ -char *file; /* where the dirty deed occured */ -{ - printf("sending on route 0x%x with no mtu, line %d of file %s\n", - rt, line, file); -#ifdef ARGO_DEBUG - printf("route dst is "); - dump_isoaddr(rt_key(rt)); -#endif - return ifp->if_mtu; -} - -/* - * FUNCTION: clnp_ypocb - backwards bcopy - * - * PURPOSE: bcopy starting at end of src rather than beginning. - * - * RETURNS: none - * - * SIDE EFFECTS: - * - * NOTES: No attempt has been made to make this efficient - */ -clnp_ypocb(from, to, len) -caddr_t from; /* src buffer */ -caddr_t to; /* dst buffer */ -u_int len; /* number of bytes */ -{ - while (len--) - *(to + len) = *(from + len); -} -#endif /* ISO */ diff --git a/bsd/netiso/clnp_timer.c b/bsd/netiso/clnp_timer.c deleted file mode 100644 index 5117dfd91..000000000 --- a/bsd/netiso/clnp_timer.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)clnp_timer.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -extern struct clnp_fragl *clnp_frags; - -/* - * FUNCTION: clnp_freefrags - * - * PURPOSE: Free the resources associated with a fragment - * - * RETURNS: pointer to next fragment in list of fragments - * - * SIDE EFFECTS: - * - * NOTES: - * TODO: send ER back to source - */ -struct clnp_fragl * -clnp_freefrags(cfh) -register struct clnp_fragl *cfh; /* fragment header to delete */ -{ - struct clnp_fragl *next = cfh->cfl_next; - struct clnp_frag *cf; - - /* free any frags hanging around */ - cf = cfh->cfl_frags; - while (cf != NULL) { - struct clnp_frag *cf_next = cf->cfr_next; - INCSTAT(cns_fragdropped); - m_freem(cf->cfr_data); - cf = cf_next; - } - - /* free the copy of the header */ - INCSTAT(cns_fragdropped); - m_freem(cfh->cfl_orighdr); - - if (clnp_frags == cfh) { - clnp_frags = cfh->cfl_next; - } else { - struct clnp_fragl *scan; - - for (scan = clnp_frags; scan != NULL; scan = scan->cfl_next) { - if (scan->cfl_next == cfh) { - scan->cfl_next = cfh->cfl_next; - break; - } - } - } - - /* free the fragment header */ - m_freem(dtom(cfh)); - - return(next); -} - -/* - * FUNCTION: clnp_slowtimo - * - * PURPOSE: clnp timer processing; if the ttl expires on a - * packet on the reassembly queue, discard it. - * - * RETURNS: none - * - * SIDE EFFECTS: - * - * NOTES: - */ -clnp_slowtimo() -{ - register struct clnp_fragl *cfh = clnp_frags; - int s = splnet(); - - while (cfh != NULL) { - if (--cfh->cfl_ttl == 0) { - cfh = clnp_freefrags(cfh); - INCSTAT(cns_fragtimeout); - } else { - cfh = cfh->cfl_next; - } - } - splx(s); -} - -/* - * FUNCTION: clnp_drain - * - * PURPOSE: drain off all datagram fragments - * - * RETURNS: none - * - * SIDE EFFECTS: - * - * NOTES: - * TODO: should send back ER - */ -clnp_drain() -{ - register struct clnp_fragl *cfh = clnp_frags; - - while (cfh != NULL) - cfh = clnp_freefrags(cfh); -} diff --git a/bsd/netiso/cltp_usrreq.c b/bsd/netiso/cltp_usrreq.c deleted file mode 100644 index 3f3deff7b..000000000 --- a/bsd/netiso/cltp_usrreq.c +++ /dev/null @@ -1,426 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1989, 1993 - * 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. - * - * @(#)cltp_usrreq.c 8.1 (Berkeley) 6/10/93 - */ - -#ifndef CLTPOVAL_SRC /* XXX -- till files gets changed */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#endif - -/* - * CLTP protocol implementation. - * Per ISO 8602, December, 1987. - */ -cltp_init() -{ - - cltb.isop_next = cltb.isop_prev = &cltb; -} - -int cltp_cksum = 1; - - -/* ARGUSED */ -cltp_input(m0, srcsa, dstsa, cons_channel, output) - struct mbuf *m0; - struct sockaddr *srcsa, *dstsa; - u_int cons_channel; - int (*output)(); -{ - register struct isopcb *isop; - register struct mbuf *m = m0; - register u_char *up = mtod(m, u_char *); - register struct sockaddr_iso *src = (struct sockaddr_iso *)srcsa; - int len, hdrlen = *up + 1, dlen = 0; - u_char *uplim = up + hdrlen; - caddr_t dtsap; - - for (len = 0; m; m = m->m_next) - len += m->m_len; - up += 2; /* skip header */ - while (up < uplim) switch (*up) { /* process options */ - case CLTPOVAL_SRC: - src->siso_tlen = up[1]; - src->siso_len = up[1] + TSEL(src) - (caddr_t)src; - if (src->siso_len < sizeof(*src)) - src->siso_len = sizeof(*src); - else if (src->siso_len > sizeof(*src)) { - MGET(m, M_DONTWAIT, MT_SONAME); - if (m == 0) - goto bad; - m->m_len = src->siso_len; - src = mtod(m, struct sockaddr_iso *); - bcopy((caddr_t)srcsa, (caddr_t)src, srcsa->sa_len); - } - bcopy((caddr_t)up + 2, TSEL(src), up[1]); - up += 2 + src->siso_tlen; - continue; - - case CLTPOVAL_DST: - dtsap = 2 + (caddr_t)up; - dlen = up[1]; - up += 2 + dlen; - continue; - - case CLTPOVAL_CSM: - if (iso_check_csum(m0, len)) { - cltpstat.cltps_badsum++; - goto bad; - } - up += 4; - continue; - - default: - printf("clts: unknown option (%x)\n", up[0]); - cltpstat.cltps_hdrops++; - goto bad; - } - if (dlen == 0 || src->siso_tlen == 0) - goto bad; - for (isop = cltb.isop_next;; isop = isop->isop_next) { - if (isop == &cltb) { - cltpstat.cltps_noport++; - goto bad; - } - if (isop->isop_laddr && - bcmp(TSEL(isop->isop_laddr), dtsap, dlen) == 0) - break; - } - m = m0; - m->m_len -= hdrlen; - m->m_data += hdrlen; - if (sbappendaddr(&isop->isop_socket->so_rcv, (struct sockaddr *)src, - m, (struct mbuf *)0) == 0) - goto bad; - cltpstat.cltps_ipackets++; - sorwakeup(isop->isop_socket); - m0 = 0; -bad: - if (src != (struct sockaddr_iso *)srcsa) - m_freem(dtom(src)); - if (m0) - m_freem(m0); - return 0; -} - -/* - * Notify a cltp user of an asynchronous error; - * just wake up so that he can collect error status. - */ -cltp_notify(isop) - register struct isopcb *isop; -{ - - sorwakeup(isop->isop_socket); - sowwakeup(isop->isop_socket); -} - -cltp_ctlinput(cmd, sa) - int cmd; - struct sockaddr *sa; -{ - extern u_char inetctlerrmap[]; - struct sockaddr_iso *siso; - int iso_rtchange(); - - if ((unsigned)cmd > PRC_NCMDS) - return; - if (sa->sa_family != AF_ISO && sa->sa_family != AF_CCITT) - return; - siso = (struct sockaddr_iso *)sa; - if (siso == 0 || siso->siso_nlen == 0) - return; - - switch (cmd) { - case PRC_ROUTEDEAD: - case PRC_REDIRECT_NET: - case PRC_REDIRECT_HOST: - case PRC_REDIRECT_TOSNET: - case PRC_REDIRECT_TOSHOST: - iso_pcbnotify(&cltb, siso, - (int)inetctlerrmap[cmd], iso_rtchange); - break; - - default: - if (inetctlerrmap[cmd] == 0) - return; /* XXX */ - iso_pcbnotify(&cltb, siso, (int)inetctlerrmap[cmd], - cltp_notify); - } -} - -cltp_output(isop, m) - register struct isopcb *isop; - register struct mbuf *m; -{ - register int len; - register struct sockaddr_iso *siso; - int hdrlen, error = 0, docsum; - register u_char *up; - - if (isop->isop_laddr == 0 || isop->isop_faddr == 0) { - error = ENOTCONN; - goto bad; - } - /* - * Calculate data length and get a mbuf for CLTP header. - */ - hdrlen = 2 + 2 + isop->isop_laddr->siso_tlen - + 2 + isop->isop_faddr->siso_tlen; - if (docsum = /*isop->isop_flags & CLNP_NO_CKSUM*/ cltp_cksum) - hdrlen += 4; - M_PREPEND(m, hdrlen, M_WAIT); - len = m->m_pkthdr.len; - /* - * Fill in mbuf with extended CLTP header - */ - up = mtod(m, u_char *); - up[0] = hdrlen - 1; - up[1] = UD_TPDU_type; - up[2] = CLTPOVAL_SRC; - up[3] = (siso = isop->isop_laddr)->siso_tlen; - up += 4; - bcopy(TSEL(siso), (caddr_t)up, siso->siso_tlen); - up += siso->siso_tlen; - up[0] = CLTPOVAL_DST; - up[1] = (siso = isop->isop_faddr)->siso_tlen; - up += 2; - bcopy(TSEL(siso), (caddr_t)up, siso->siso_tlen); - /* - * Stuff checksum and output datagram. - */ - if (docsum) { - up += siso->siso_tlen; - up[0] = CLTPOVAL_CSM; - up[1] = 2; - iso_gen_csum(m, 2 + up - mtod(m, u_char *), len); - } - cltpstat.cltps_opackets++; - return (tpclnp_output(isop, m, len, !docsum)); -bad: - m_freem(m); - return (error); -} - -u_long cltp_sendspace = 9216; /* really max datagram size */ -u_long cltp_recvspace = 40 * (1024 + sizeof(struct sockaddr_iso)); - /* 40 1K datagrams */ - - -/*ARGSUSED*/ -cltp_usrreq(so, req, m, nam, control) - struct socket *so; - int req; - struct mbuf *m, *nam, *control; -{ - register struct isopcb *isop = sotoisopcb(so); - int s, error = 0; - - if (req == PRU_CONTROL) - return (iso_control(so, (int)m, (caddr_t)nam, - (struct ifnet *)control)); - if ((isop == NULL && req != PRU_ATTACH) || - (control && control->m_len)) { - error = EINVAL; - goto release; - } - switch (req) { - - case PRU_ATTACH: - if (isop != NULL) { - error = EINVAL; - break; - } - error = iso_pcballoc(so, &cltb); - if (error) - break; - error = soreserve(so, cltp_sendspace, cltp_recvspace); - if (error) - break; - break; - - case PRU_DETACH: - iso_pcbdetach(isop); - break; - - case PRU_BIND: - error = iso_pcbbind(isop, nam); - break; - - case PRU_LISTEN: - error = EOPNOTSUPP; - break; - - case PRU_CONNECT: - if (isop->isop_faddr) { - error = EISCONN; - break; - } - error = iso_pcbconnect(isop, nam); - if (error == 0) - soisconnected(so); - break; - - case PRU_CONNECT2: - error = EOPNOTSUPP; - break; - - case PRU_ACCEPT: - error = EOPNOTSUPP; - break; - - case PRU_DISCONNECT: - if (isop->isop_faddr == 0) { - error = ENOTCONN; - break; - } - iso_pcbdisconnect(isop); - so->so_state &= ~SS_ISCONNECTED; /* XXX */ - break; - - case PRU_SHUTDOWN: - socantsendmore(so); - break; - - case PRU_SEND: - if (nam) { - if (isop->isop_faddr) { - error = EISCONN; - break; - } - /* - * Must block input while temporarily connected. - */ - s = splnet(); - error = iso_pcbconnect(isop, nam); - if (error) { - splx(s); - break; - } - } else { - if (isop->isop_faddr == 0) { - error = ENOTCONN; - break; - } - } - error = cltp_output(isop, m); - m = 0; - if (nam) { - iso_pcbdisconnect(isop); - splx(s); - } - break; - - case PRU_ABORT: - soisdisconnected(so); - iso_pcbdetach(isop); - break; - - case PRU_SOCKADDR: - if (isop->isop_laddr) - bcopy((caddr_t)isop->isop_laddr, mtod(m, caddr_t), - nam->m_len = isop->isop_laddr->siso_len); - break; - - case PRU_PEERADDR: - if (isop->isop_faddr) - bcopy((caddr_t)isop->isop_faddr, mtod(m, caddr_t), - nam->m_len = isop->isop_faddr->siso_len); - 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("cltp_usrreq"); - } -release: - if (control != NULL) - m_freem(control); - if (m != NULL) - m_freem(m); - return (error); -} diff --git a/bsd/netiso/cltp_var.h b/bsd/netiso/cltp_var.h deleted file mode 100644 index f0edca949..000000000 --- a/bsd/netiso/cltp_var.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1989, 1993 - * 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. - * - * @(#)cltp_var.h 8.1 (Berkeley) 6/10/93 - */ - -#define UD_TPDU_type 0x40 /* packet type */ - -#define CLTPOVAL_SRC 0xc1 /* Source TSAP -- required */ -#define CLTPOVAL_DST 0xc2 /* Destination TSAP -- required */ -#define CLTPOVAL_CSM 0xc3 /* Checksum parameter -- optional */ - -struct cltpstat { - int cltps_hdrops; - int cltps_badsum; - int cltps_badlen; - int cltps_noport; - int cltps_ipackets; - int cltps_opackets; -}; - -#ifdef KERNEL -struct isopcb cltb; -struct cltpstat cltpstat; -#endif diff --git a/bsd/netiso/cons.h b/bsd/netiso/cons.h deleted file mode 100644 index cb984d302..000000000 --- a/bsd/netiso/cons.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)cons.h 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * - * interface between TP and CONS - */ - -#define CONSOPT_X25CRUD 0x01 /* set x.25 call request user data */ - -struct dte_addr { - u_char dtea_addr[7]; - u_char dtea_niblen; -}; - -#ifdef KERNEL - -#define CONN_OPEN 0x33 -#define CONN_CONFIRM 0x30 -#define CONN_REFUSE 0x31 -#define CONN_CLOSE 0x32 - -#define CONS_IS_DGM 0x1 -#define CONS_NOT_DGM 0x0 - -#ifndef PRC_NCMDS -#include -#endif /* PRC_NCMDS */ - -#define PRC_CONS_SEND_DONE 2 /* something unused in protosw.h */ - -#endif /* KERNEL */ diff --git a/bsd/netiso/cons_pcb.h b/bsd/netiso/cons_pcb.h deleted file mode 100644 index 9a5c9c0e7..000000000 --- a/bsd/netiso/cons_pcb.h +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)cons_pcb.h 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ - -/* - * protocol control block for the connection oriented network service - */ - -/* - * legit port #s for cons "transport" are 0..23 for su users only, and - * 1024..1099 for public users - */ -#define X25_SBSIZE 512 -#define X25_PORT_RESERVED 24 -#define X25_PORT_USERMAX 1099 -#define X25_FACIL_LEN_MAX 109 -#define X25_PARTIAL_PKT_LEN_MAX (MLEN - sizeof(struct cons_pcb)) - -#ifndef ARGO_DEBUG -#define X25_TTL 600 /* 5 min */ -#else /* ARGO_DEBUG */ -#define X25_TTL 120 /* 1 min */ -#endif /* ARGO_DEBUG */ - -struct cons_pcb { - struct isopcb _co_isopcb; -#define co_next _co_isopcb.isop_next -/* prev used for netstat only */ -#define co_prev _co_isopcb.isop_prev -#define co_head _co_isopcb.isop_head -#define co_laddr _co_isopcb.isop_laddr -#define co_faddr _co_isopcb.isop_faddr -#define co_lport _co_isopcb.isop_laddr.siso_tsuffix -#define co_fport _co_isopcb.isop_faddr.siso_tsuffix -#define co_route _co_isopcb.isop_route -#define co_socket _co_isopcb.isop_socket -#define co_chanmask _co_isopcb.isop_chanmask -#define co_negchanmask _co_isopcb.isop_negchanmask -#define co_x25crud _co_isopcb.isop_x25crud -#define co_x25crud_len _co_isopcb.isop_x25crud_len - u_short co_state; - u_char co_flags; - u_short co_ttl; /* time to live timer */ - u_short co_init_ttl; /* initial value of ttl */ - int co_channel; /* logical channel */ - struct ifnet * co_ifp; /* interface */ - struct protosw *co_proto; - - struct ifqueue co_pending; /* queue data to send when connection - completes*/ -#define MAX_DTE_LEN 0x7 /* 17 bcd digits */ - struct dte_addr co_peer_dte; - struct cons_pcb *co_myself; /* DEBUGGING AID */ -}; - -/* - * X.25 Packet types - */ -#define XPKT_DATA 1 -#define XPKT_INTERRUPT 2 -#define XPKT_FLOWCONTROL 3 /* not delivered? */ - -/* - * pcb xtates - */ - -#define CLOSED 0x0 -#define LISTENING 0x1 -#define CLOSING 0x2 -/* USABLE STATES MUST BE LAST */ -#define CONNECTING 0x3 -#define ACKWAIT 0x4 -#define OPEN 0x5 -#define MIN_USABLE_STATE CONNECTING - -#define cons_NSTATES 0x6 - - -/* type */ -#define CONSF_OCRE 0x40 /* created on OUTPUT */ -#define CONSF_ICRE 0x20 /* created on INPUT */ -#define CONSF_unused 0x10 /* not used */ -#define CONSF_unused2 0x08 /* not used */ -#define CONSF_DGM 0x04 /* for dgm use only */ -#define CONSF_XTS 0x02 /* for cons-as-transport-service */ -#define CONSF_LOOPBACK 0x01 /* loopback was on when connection commenced */ - -#define X_NOCHANNEL 0x80 - - -struct cons_stat { - u_int co_intr; /* input from eicon board */ - u_int co_restart; /* ecn_restart() request issued to board */ - u_int co_slowtimo; /* times slowtimo called */ - u_int co_timedout; /* connections closed by slowtimo */ - u_int co_ack; /* ECN_ACK indication came from eicon board */ - u_int co_receive; /* ECN_RECEIVE indication came from eicon board */ - u_int co_send; /* ECN_SEND request issued to board */ - u_int co_reset_in; /* ECN_RESET indication came from eicon board */ - u_int co_reset_out; /* ECN_RESET issued to the eicon board */ - u_int co_clear_in; /* ECN_CLEAR indication came from eicon board */ - u_int co_clear_out; /* ECN_CLEAR request issued to board */ - u_int co_refuse; /* ECN_REFUSE indication came from eicon board */ - u_int co_accept; /* ECN_ACCEPT indication came from eicon board */ - u_int co_connect; /* ECN_CONNECT indication came from eicon board */ - u_int co_call; /* ECN_CALL request issued to board */ - u_int co_Rdrops; /* bad pkt came from ll */ - u_int co_Xdrops; /* can't keep up */ - - u_int co_intrpt_pkts_in; /* interrupt packets in */ - u_int co_avg_qlen; - u_int co_avg_qdrop; - u_int co_active; - - u_int co_noresources; - u_int co_parse_facil_err; - u_int co_addr_proto_consist_err; - u_int co_no_copcb; -} cons_stat; - -u_char x25_error_stats[CONL_ERROR_MAX + 1]; - -struct ifqueue consintrq; - -/* reasons for clear are in a data mbuf chained to a clear ecn_request */ -struct e_clear_data { - u_char ecd_cause; - u_char ecd_diagnostic; -}; - -#ifdef KERNEL -#define IncStat(XYZ) cons_stat.XYZ++ -#endif /* KERNEL */ diff --git a/bsd/netiso/eonvar.h b/bsd/netiso/eonvar.h deleted file mode 100644 index 11a47e88b..000000000 --- a/bsd/netiso/eonvar.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)eonvar.h 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ - -#define EON_986_VERSION 0x3 -#define EON_VERSION 0x1 - -#define EON_CACHESIZE 30 - -#define E_FREE 1 -#define E_LINK 2 -#define E_ES 3 -#define E_IS 4 - - -/* - * this overlays a sockaddr_iso - */ - -struct sockaddr_eon { - u_char seon_len; /* Length */ - u_char seon_family; /* AF_ISO */ - u_char seon_status; /* overlays session suffixlen */ -#define EON_ESLINK_UP 0x1 -#define EON_ESLINK_DOWN 0x2 -#define EON_ISLINK_UP 0x10 -#define EON_ISLINK_DOWN 0x20 -/* no change is neither up or down */ - u_char seon_pad1; /* 0, overlays tsfxlen */ - u_char seon_adrlen; - u_char seon_afi; /* 47 */ - u_char seon_idi[2]; /* 0006 */ - u_char seon_vers; /* 03 */ - u_char seon_glbnum[2]; /* see RFC 1069 */ - u_char seon_RDN[2]; /* see RFC 1070 */ - u_char seon_pad2[3]; /* see RFC 1070 */ - u_char seon_LAREA[2]; /* see RFC 1070 */ - u_char seon_pad3[2]; /* see RFC 1070 */ - /* right now ip addr is aligned -- be careful -- - * future revisions may have it u_char[4] - */ - u_int seon_ipaddr; /* a.b.c.d */ - u_char seon_protoid; /* NSEL */ -}; - -#ifdef EON_TEMPLATE -struct sockaddr_eon eon_template = { - sizeof (eon_template), AF_ISO, 0, 0, 0x14, - 0x47, 0x0, 0x6, 0x3, 0 -}; -#endif - -#define DOWNBITS ( EON_ESLINK_DOWN | EON_ISLINK_DOWN ) -#define UPBITS ( EON_ESLINK_UP | EON_ISLINK_UP ) - -#define SIOCSEONCORE _IOWR('i',10, struct iso_ifreq) /* EON core member */ -#define SIOCGEONCORE _IOWR('i',11, struct iso_ifreq) /* EON core member */ - -struct eon_hdr { - u_char eonh_vers; /* value 1 */ - u_char eonh_class; /* address multicast class, below */ -#define EON_NORMAL_ADDR 0x0 -#define EON_MULTICAST_ES 0x1 -#define EON_MULTICAST_IS 0x2 -#define EON_BROADCAST 0x3 - u_short eonh_csum; /* osi checksum (choke)*/ -}; -struct eon_iphdr { - struct ip ei_ip; - struct eon_hdr ei_eh; -}; -#define EONIPLEN (sizeof(struct eon_hdr) + sizeof(struct ip)) - -/* stole these 2 fields of the flags for I-am-ES and I-am-IS */ -#define IFF_ES 0x400 -#define IFF_IS 0x800 - -struct eon_stat { - int es_in_multi_es; - int es_in_multi_is; - int es_in_broad; - int es_in_normal; - int es_out_multi_es; - int es_out_multi_is; - int es_out_broad; - int es_out_normal; - int es_ipout; - - int es_icmp[PRC_NCMDS]; - /* errors */ - int es_badcsum; - int es_badhdr; -} eonstat; - -#undef IncStat -#define IncStat(xxx) eonstat.xxx++ - -typedef struct qhdr { - struct qhdr *link, *rlink; -} *queue_t; - -struct eon_llinfo { - struct qhdr el_qhdr; /* keep all in a list */ - int el_flags; /* cache valid ? */ - int el_snpaoffset; /* IP address contained in dst nsap */ - struct rtentry *el_rt; /* back pointer to parent route */ - struct eon_iphdr el_ei; /* precomputed portion of hdr */ - struct route el_iproute; /* if direct route cache IP info */ - /* if gateway, cache secondary route */ -}; -#define el_iphdr el_ei.ei_ip -#define el_eonhdr el_ei.ei_eh diff --git a/bsd/netiso/esis.c b/bsd/netiso/esis.c deleted file mode 100644 index a387c075e..000000000 --- a/bsd/netiso/esis.c +++ /dev/null @@ -1,1084 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)esis.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ - -#if ISO - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Global variables to esis implementation - * - * esis_holding_time - the holding time (sec) parameter for outgoing pdus - * esis_config_time - the frequency (sec) that hellos are generated - * esis_esconfig_time - suggested es configuration time placed in the - * ish. - * - */ -struct rawcb esis_pcb; -void esis_config(), snpac_age(); -int esis_sendspace = 2048; -int esis_recvspace = 2048; -short esis_holding_time = ESIS_HT; -short esis_config_time = ESIS_CONFIG; -short esis_esconfig_time = ESIS_CONFIG; -extern int iso_systype; -struct sockaddr_dl esis_dl = { sizeof(esis_dl), AF_LINK }; -extern char all_es_snpa[], all_is_snpa[]; - -#define EXTEND_PACKET(m, mhdr, cp)\ - if (((m)->m_next = m_getclr(M_DONTWAIT, MT_HEADER)) == NULL) {\ - esis_stat.es_nomem++;\ - m_freem(mhdr);\ - return;\ - } else {\ - (m) = (m)->m_next;\ - (cp) = mtod((m), caddr_t);\ - } -/* - * FUNCTION: esis_init - * - * PURPOSE: Initialize the kernel portion of esis protocol - * - * RETURNS: nothing - * - * SIDE EFFECTS: - * - * NOTES: - */ -esis_init() -{ - extern struct clnl_protosw clnl_protox[256]; - int esis_input(), isis_input(); -#ifdef ISO_X25ESIS - int x25esis_input(); -#endif /* ISO_X25ESIS */ - - esis_pcb.rcb_next = esis_pcb.rcb_prev = &esis_pcb; - llinfo_llc.lc_next = llinfo_llc.lc_prev = &llinfo_llc; - - timeout(snpac_age, (caddr_t)0, hz); - timeout(esis_config, (caddr_t)0, hz); - - clnl_protox[ISO9542_ESIS].clnl_input = esis_input; - clnl_protox[ISO10589_ISIS].clnl_input = isis_input; -#ifdef ISO_X25ESIS - clnl_protox[ISO9542X25_ESIS].clnl_input = x25esis_input; -#endif /* ISO_X25ESIS */ -} - -/* - * FUNCTION: esis_usrreq - * - * PURPOSE: Handle user level esis requests - * - * RETURNS: 0 or appropriate errno - * - * SIDE EFFECTS: - * - */ -/*ARGSUSED*/ -esis_usrreq(so, req, m, nam, control) -struct socket *so; /* socket: used only to get to this code */ -int req; /* request */ -struct mbuf *m; /* data for request */ -struct mbuf *nam; /* optional name */ -struct mbuf *control; /* optional control */ -{ - struct rawcb *rp = sotorawcb(so); - int error = 0; - - if ((so->so_state & SS_PRIV) == 0) { - error = EACCES; - goto release; - } - if (rp == NULL && req != PRU_ATTACH) { - error = EINVAL; - goto release; - } - - switch (req) { - case PRU_ATTACH: - if (rp != NULL) { - error = EINVAL; - break; - } - MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK); - if (so->so_pcb = (caddr_t)rp) { - bzero(so->so_pcb, sizeof(*rp)); - insque(rp, &esis_pcb); - rp->rcb_socket = so; - error = soreserve(so, esis_sendspace, esis_recvspace); - } else - error = ENOBUFS; - break; - - case PRU_SEND: - if (nam == NULL) { - error = EINVAL; - break; - } - /* error checking here */ - error = isis_output(mtod(nam,struct sockaddr_dl *), m); - m = NULL; - break; - - case PRU_DETACH: - raw_detach(rp); - break; - - case PRU_SHUTDOWN: - socantsendmore(so); - break; - - case PRU_ABORT: - soisdisconnected(so); - raw_detach(rp); - break; - - case PRU_SENSE: - return (0); - - default: - return (EOPNOTSUPP); - } -release: - if (m != NULL) - m_freem(m); - - return (error); -} - -/* - * FUNCTION: esis_input - * - * PURPOSE: Process an incoming esis packet - * - * RETURNS: nothing - * - * SIDE EFFECTS: - * - * NOTES: - */ -esis_input(m0, shp) -struct mbuf *m0; /* ptr to first mbuf of pkt */ -struct snpa_hdr *shp; /* subnetwork header */ -{ - register struct esis_fixed *pdu = mtod(m0, struct esis_fixed *); - register int type; - - /* - * check checksum if necessary - */ - if (ESIS_CKSUM_REQUIRED(pdu) && iso_check_csum(m0, (int)pdu->esis_hdr_len)) { - esis_stat.es_badcsum++; - goto bad; - } - - /* check version */ - if (pdu->esis_vers != ESIS_VERSION) { - esis_stat.es_badvers++; - goto bad; - } - type = pdu->esis_type & 0x1f; - switch (type) { - case ESIS_ESH: - esis_eshinput(m0, shp); - break; - - case ESIS_ISH: - esis_ishinput(m0, shp); - break; - - case ESIS_RD: - esis_rdinput(m0, shp); - break; - - default: - esis_stat.es_badtype++; - } - -bad: - if (esis_pcb.rcb_next != &esis_pcb) - isis_input(m0, shp); - else - m_freem(m0); -} - -/* - * FUNCTION: esis_rdoutput - * - * PURPOSE: Transmit a redirect pdu - * - * RETURNS: nothing - * - * SIDE EFFECTS: - * - * NOTES: Assumes there is enough space for fixed part of header, - * DA, BSNPA and NET in first mbuf. - */ -esis_rdoutput(inbound_shp, inbound_m, inbound_oidx, rd_dstnsap, rt) -struct snpa_hdr *inbound_shp; /* snpa hdr from incoming packet */ -struct mbuf *inbound_m; /* incoming pkt itself */ -struct clnp_optidx *inbound_oidx; /* clnp options assoc with incoming pkt */ -struct iso_addr *rd_dstnsap; /* ultimate destination of pkt */ -struct rtentry *rt; /* snpa cache info regarding next hop of - pkt */ -{ - struct mbuf *m, *m0; - caddr_t cp; - struct esis_fixed *pdu; - int len, total_len = 0; - struct sockaddr_iso siso; - struct ifnet *ifp = inbound_shp->snh_ifp; - struct sockaddr_dl *sdl; - struct iso_addr *rd_gwnsap; - - if (rt->rt_flags & RTF_GATEWAY) { - rd_gwnsap = &((struct sockaddr_iso *)rt->rt_gateway)->siso_addr; - rt = rtalloc1(rt->rt_gateway, 0); - } else - rd_gwnsap = &((struct sockaddr_iso *)rt_key(rt))->siso_addr; - if (rt == 0 || (sdl = (struct sockaddr_dl *)rt->rt_gateway) == 0 || - sdl->sdl_family != AF_LINK) { - /* maybe we should have a function that you - could put in the iso_ifaddr structure - which could translate iso_addrs into snpa's - where there is a known mapping for that address type */ - esis_stat.es_badtype++; - return; - } - esis_stat.es_rdsent++; - IFDEBUG(D_ESISOUTPUT) - printf("esis_rdoutput: ifp x%x (%s%d), ht %d, m x%x, oidx x%x\n", - ifp, ifp->if_name, ifp->if_unit, esis_holding_time, inbound_m, - inbound_oidx); - printf("\tdestination: %s\n", clnp_iso_addrp(rd_dstnsap)); - printf("\tredirected toward:%s\n", clnp_iso_addrp(rd_gwnsap)); - ENDDEBUG - - if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) { - esis_stat.es_nomem++; - return; - } - bzero(mtod(m, caddr_t), MHLEN); - - pdu = mtod(m, struct esis_fixed *); - cp = (caddr_t)(pdu + 1); /*pointer arith.; 1st byte after header */ - len = sizeof(struct esis_fixed); - - /* - * Build fixed part of header - */ - pdu->esis_proto_id = ISO9542_ESIS; - pdu->esis_vers = ESIS_VERSION; - pdu->esis_type = ESIS_RD; - HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, esis_holding_time); - - /* Insert destination address */ - (void) esis_insert_addr(&cp, &len, rd_dstnsap, m, 0); - - /* Insert the snpa of better next hop */ - *cp++ = sdl->sdl_alen; - bcopy(LLADDR(sdl), cp, sdl->sdl_alen); - cp += sdl->sdl_alen; - len += (sdl->sdl_alen + 1); - - /* - * If the next hop is not the destination, then it ought to be - * an IS and it should be inserted next. Else, set the - * NETL to 0 - */ - /* PHASE2 use mask from ifp of outgoing interface */ - if (!iso_addrmatch1(rd_dstnsap, rd_gwnsap)) { - /* this should not happen: - if ((nhop_sc->sc_flags & SNPA_IS) == 0) { - printf("esis_rdoutput: next hop is not dst and not an IS\n"); - m_freem(m0); - return; - } */ - (void) esis_insert_addr(&cp, &len, rd_gwnsap, m, 0); - } else { - *cp++ = 0; /* NETL */ - len++; - } - m->m_len = len; - - /* - * PHASE2 - * If redirect is to an IS, add an address mask. The mask to be - * used should be the mask present in the routing entry used to - * forward the original data packet. - */ - - /* - * Copy Qos, priority, or security options present in original npdu - */ - if (inbound_oidx) { - /* THIS CODE IS CURRENTLY (mostly) UNTESTED */ - int optlen = 0; - if (inbound_oidx->cni_qos_formatp) - optlen += (inbound_oidx->cni_qos_len + 2); - if (inbound_oidx->cni_priorp) /* priority option is 1 byte long */ - optlen += 3; - if (inbound_oidx->cni_securep) - optlen += (inbound_oidx->cni_secure_len + 2); - if (M_TRAILINGSPACE(m) < optlen) { - EXTEND_PACKET(m, m0, cp); - m->m_len = 0; - /* assumes MLEN > optlen */ - } - /* assume MLEN-len > optlen */ - /* - * When copying options, copy from ptr - 2 in order to grab - * the option code and length - */ - if (inbound_oidx->cni_qos_formatp) { - bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_qos_formatp - 2, - cp, (unsigned)(inbound_oidx->cni_qos_len + 2)); - cp += inbound_oidx->cni_qos_len + 2; - } - if (inbound_oidx->cni_priorp) { - bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_priorp - 2, - cp, 3); - cp += 3; - } - if (inbound_oidx->cni_securep) { - bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_securep - 2, cp, - (unsigned)(inbound_oidx->cni_secure_len + 2)); - cp += inbound_oidx->cni_secure_len + 2; - } - m->m_len += optlen; - len += optlen; - } - - pdu->esis_hdr_len = m0->m_pkthdr.len = len; - iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len); - - bzero((caddr_t)&siso, sizeof(siso)); - siso.siso_family = AF_ISO; - siso.siso_data[0] = AFI_SNA; - siso.siso_nlen = 6 + 1; /* should be taken from snpa_hdr */ - /* +1 is for AFI */ - bcopy(inbound_shp->snh_shost, siso.siso_data + 1, 6); - (ifp->if_output)(ifp, m0, (struct sockaddr *)&siso, 0); -} - -/* - * FUNCTION: esis_insert_addr - * - * PURPOSE: Insert an iso_addr into a buffer - * - * RETURNS: true if buffer was big enough, else false - * - * SIDE EFFECTS: Increment buf & len according to size of iso_addr - * - * NOTES: Plus 1 here is for length byte - */ -esis_insert_addr(buf, len, isoa, m, nsellen) -register caddr_t *buf; /* ptr to buffer to put address into */ -int *len; /* ptr to length of buffer so far */ -register struct iso_addr *isoa; /* ptr to address */ -register struct mbuf *m; /* determine if there remains space */ -int nsellen; -{ - register int newlen, result = 0; - - isoa->isoa_len -= nsellen; - newlen = isoa->isoa_len + 1; - if (newlen <= M_TRAILINGSPACE(m)) { - bcopy((caddr_t)isoa, *buf, newlen); - *len += newlen; - *buf += newlen; - m->m_len += newlen; - result = 1; - } - isoa->isoa_len += nsellen; - return (result); -} - -#define ESIS_EXTRACT_ADDR(d, b) { d = (struct iso_addr *)(b); b += (1 + *b); \ - if (b > buflim) {esis_stat.es_toosmall++; goto bad;}} -#define ESIS_NEXT_OPTION(b) { b += (2 + b[1]); \ - if (b > buflim) {esis_stat.es_toosmall++; goto bad;}} -int ESHonly = 0; -/* - -/* - * FUNCTION: esis_eshinput - * - * PURPOSE: Process an incoming ESH pdu - * - * RETURNS: nothing - * - * SIDE EFFECTS: - * - * NOTES: - */ -esis_eshinput(m, shp) -struct mbuf *m; /* esh pdu */ -struct snpa_hdr *shp; /* subnetwork header */ -{ - struct esis_fixed *pdu = mtod(m, struct esis_fixed *); - u_short ht; /* holding time */ - struct iso_addr *nsap; - int naddr; - u_char *buf = (u_char *)(pdu + 1); - u_char *buflim = pdu->esis_hdr_len + (u_char *)pdu; - int new_entry = 0; - - esis_stat.es_eshrcvd++; - - CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); - - naddr = *buf++; - if (buf >= buflim) - goto bad; - if (naddr == 1) { - ESIS_EXTRACT_ADDR(nsap, buf); - new_entry = snpac_add(shp->snh_ifp, - nsap, shp->snh_shost, SNPA_ES, ht, 0); - } else { - int nsellength = 0, nlen = 0; - { - /* See if we want to compress out multiple nsaps differing - only by nsel */ - register struct ifaddr *ifa = shp->snh_ifp->if_addrlist; - for (; ifa; ifa = ifa->ifa_next) - if (ifa->ifa_addr->sa_family == AF_ISO) { - nsellength = ((struct iso_ifaddr *)ifa)->ia_addr.siso_tlen; - break; - } - } - IFDEBUG(D_ESISINPUT) - printf("esis_eshinput: esh: ht %d, naddr %d nsellength %d\n", - ht, naddr, nsellength); - ENDDEBUG - while (naddr-- > 0) { - struct iso_addr *nsap2; u_char *buf2; - ESIS_EXTRACT_ADDR(nsap, buf); - /* see if there is at least one more nsap in ESH differing - only by nsel */ - if (nsellength != 0) for (buf2 = buf; buf2 < buflim;) { - ESIS_EXTRACT_ADDR(nsap2, buf2); - IFDEBUG(D_ESISINPUT) - printf("esis_eshinput: comparing %s ", - clnp_iso_addrp(nsap)); - printf("and %s\n", clnp_iso_addrp(nsap2)); - ENDDEBUG - if (Bcmp(nsap->isoa_genaddr, nsap2->isoa_genaddr, - nsap->isoa_len - nsellength) == 0) { - nlen = nsellength; - break; - } - } - new_entry |= snpac_add(shp->snh_ifp, - nsap, shp->snh_shost, SNPA_ES, ht, nlen); - nlen = 0; - } - } - IFDEBUG(D_ESISINPUT) - printf("esis_eshinput: nsap %s is %s\n", - clnp_iso_addrp(nsap), new_entry ? "new" : "old"); - ENDDEBUG - if (new_entry && (iso_systype & SNPA_IS)) - esis_shoutput(shp->snh_ifp, ESIS_ISH, esis_holding_time, - shp->snh_shost, 6, (struct iso_addr *)0); -bad: - return; -} - -/* - * FUNCTION: esis_ishinput - * - * PURPOSE: process an incoming ISH pdu - * - * RETURNS: - * - * SIDE EFFECTS: - * - * NOTES: - */ -esis_ishinput(m, shp) -struct mbuf *m; /* esh pdu */ -struct snpa_hdr *shp; /* subnetwork header */ -{ - struct esis_fixed *pdu = mtod(m, struct esis_fixed *); - u_short ht, newct; /* holding time */ - struct iso_addr *nsap; /* Network Entity Title */ - register u_char *buf = (u_char *) (pdu + 1); - register u_char *buflim = pdu->esis_hdr_len + (u_char *)pdu; - int new_entry; - - esis_stat.es_ishrcvd++; - CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); - - IFDEBUG(D_ESISINPUT) - printf("esis_ishinput: ish: ht %d\n", ht); - ENDDEBUG - if (ESHonly) - goto bad; - - ESIS_EXTRACT_ADDR(nsap, buf); - - while (buf < buflim) { - switch (*buf) { - case ESISOVAL_ESCT: - if (iso_systype & SNPA_IS) - break; - if (buf[1] != 2) - goto bad; - CTOH(buf[2], buf[3], newct); - if (esis_config_time != newct) { - untimeout(esis_config,0); - esis_config_time = newct; - esis_config(); - } - break; - - default: - printf("Unknown ISH option: %x\n", *buf); - } - ESIS_NEXT_OPTION(buf); - } - new_entry = snpac_add(shp->snh_ifp, nsap, shp->snh_shost, SNPA_IS, ht, 0); - IFDEBUG(D_ESISINPUT) - printf("esis_ishinput: nsap %s is %s\n", - clnp_iso_addrp(nsap), new_entry ? "new" : "old"); - ENDDEBUG - - if (new_entry) - esis_shoutput(shp->snh_ifp, - iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH, - esis_holding_time, shp->snh_shost, 6, (struct iso_addr *)0); -bad: - return; -} - -/* - * FUNCTION: esis_rdinput - * - * PURPOSE: Process an incoming RD pdu - * - * RETURNS: - * - * SIDE EFFECTS: - * - * NOTES: - */ -esis_rdinput(m0, shp) -struct mbuf *m0; /* esh pdu */ -struct snpa_hdr *shp; /* subnetwork header */ -{ - struct esis_fixed *pdu = mtod(m0, struct esis_fixed *); - u_short ht; /* holding time */ - struct iso_addr *da, *net = 0, *netmask = 0, *snpamask = 0; - register struct iso_addr *bsnpa; - register u_char *buf = (u_char *)(pdu + 1); - register u_char *buflim = pdu->esis_hdr_len + (u_char *)pdu; - - esis_stat.es_rdrcvd++; - - /* intermediate systems ignore redirects */ - if (iso_systype & SNPA_IS) - return; - if (ESHonly) - return; - - CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); - if (buf >= buflim) - return; - - /* Extract DA */ - ESIS_EXTRACT_ADDR(da, buf); - - /* Extract better snpa */ - ESIS_EXTRACT_ADDR(bsnpa, buf); - - /* Extract NET if present */ - if (buf < buflim) { - if (*buf == 0) - buf++; /* no NET present, skip NETL anyway */ - else - ESIS_EXTRACT_ADDR(net, buf); - } - - /* process options */ - while (buf < buflim) { - switch (*buf) { - case ESISOVAL_SNPAMASK: - if (snpamask) /* duplicate */ - return; - snpamask = (struct iso_addr *)(buf + 1); - break; - - case ESISOVAL_NETMASK: - if (netmask) /* duplicate */ - return; - netmask = (struct iso_addr *)(buf + 1); - break; - - default: - printf("Unknown option in ESIS RD (0x%x)\n", buf[-1]); - } - ESIS_NEXT_OPTION(buf); - } - - IFDEBUG(D_ESISINPUT) - printf("esis_rdinput: rd: ht %d, da %s\n", ht, clnp_iso_addrp(da)); - if (net) - printf("\t: net %s\n", clnp_iso_addrp(net)); - ENDDEBUG - /* - * If netl is zero, then redirect is to an ES. We need to add an entry - * to the snpa cache for (destination, better snpa). - * If netl is not zero, then the redirect is to an IS. In this - * case, add an snpa cache entry for (net, better snpa). - * - * If the redirect is to an IS, add a route entry towards that - * IS. - */ - if (net == 0 || net->isoa_len == 0 || snpamask) { - /* redirect to an ES */ - snpac_add(shp->snh_ifp, da, - bsnpa->isoa_genaddr, SNPA_ES, ht, 0); - } else { - snpac_add(shp->snh_ifp, net, - bsnpa->isoa_genaddr, SNPA_IS, ht, 0); - snpac_addrt(shp->snh_ifp, da, net, netmask); - } -bad: ; /* Needed by ESIS_NEXT_OPTION */ -} - -/* - * FUNCTION: esis_config - * - * PURPOSE: Report configuration - * - * RETURNS: - * - * SIDE EFFECTS: - * - * NOTES: Called every esis_config_time seconds - */ -void -esis_config() -{ - register struct ifnet *ifp; - - timeout(esis_config, (caddr_t)0, hz * esis_config_time); - - /* - * Report configuration for each interface that - * - is UP - * - has BROADCAST capability - * - has an ISO address - */ - /* Todo: a better way would be to construct the esh or ish - * once and copy it out for all devices, possibly calling - * a method in the iso_ifaddr structure to encapsulate and - * transmit it. This could work to advantage for non-broadcast media - */ - - for (ifp = ifnet; ifp; ifp = ifp->if_next) { - if ((ifp->if_flags & IFF_UP) && - (ifp->if_flags & IFF_BROADCAST)) { - /* search for an ISO address family */ - struct ifaddr *ia; - - for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) { - if (ia->ifa_addr->sa_family == AF_ISO) { - esis_shoutput(ifp, - iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH, - esis_holding_time, - (caddr_t)(iso_systype & SNPA_ES ? all_is_snpa : - all_es_snpa), 6, (struct iso_addr *)0); - break; - } - } - } - } -} - -/* - * FUNCTION: esis_shoutput - * - * PURPOSE: Transmit an esh or ish pdu - * - * RETURNS: nothing - * - * SIDE EFFECTS: - * - * NOTES: - */ -esis_shoutput(ifp, type, ht, sn_addr, sn_len, isoa) -struct ifnet *ifp; -int type; -short ht; -caddr_t sn_addr; -int sn_len; -struct iso_addr *isoa; -{ - struct mbuf *m, *m0; - caddr_t cp, naddrp; - int naddr = 0; - struct esis_fixed *pdu; - struct iso_ifaddr *ia; - int len; - struct sockaddr_iso siso; - - if (type == ESIS_ESH) - esis_stat.es_eshsent++; - else if (type == ESIS_ISH) - esis_stat.es_ishsent++; - else { - printf("esis_shoutput: bad pdu type\n"); - return; - } - - IFDEBUG(D_ESISOUTPUT) - int i; - printf("esis_shoutput: ifp x%x (%s%d), %s, ht %d, to: [%d] ", - ifp, ifp->if_name, ifp->if_unit, type == ESIS_ESH ? "esh" : "ish", - ht, sn_len); - for (i=0; iesis_proto_id = ISO9542_ESIS; - pdu->esis_vers = ESIS_VERSION; - pdu->esis_type = type; - HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); - - if (type == ESIS_ESH) { - cp++; - len++; - } - - m->m_len = len; - if (isoa) { - /* - * Here we are responding to a clnp packet sent to an NSAP - * that is ours which was sent to the MAC addr all_es's. - * It is possible that we did not specifically advertise this - * NSAP, even though it is ours, so we will respond - * directly to the sender that we are here. If we do have - * multiple NSEL's we'll tack them on so he can compress them out. - */ - (void) esis_insert_addr(&cp, &len, isoa, m, 0); - naddr = 1; - } - for (ia = iso_ifaddr; ia; ia = ia->ia_next) { - int nsellen = (type == ESIS_ISH ? ia->ia_addr.siso_tlen : 0); - int n = ia->ia_addr.siso_nlen; - register struct iso_ifaddr *ia2; - - if (type == ESIS_ISH && naddr > 0) - break; - for (ia2 = iso_ifaddr; ia2 != ia; ia2 = ia2->ia_next) - if (Bcmp(ia->ia_addr.siso_data, ia2->ia_addr.siso_data, n) == 0) - break; - if (ia2 != ia) - continue; /* Means we have previously copied this nsap */ - if (isoa && Bcmp(ia->ia_addr.siso_data, isoa->isoa_genaddr, n) == 0) { - isoa = 0; - continue; /* Ditto */ - } - IFDEBUG(D_ESISOUTPUT) - printf("esis_shoutput: adding NSAP %s\n", - clnp_iso_addrp(&ia->ia_addr.siso_addr)); - ENDDEBUG - if (!esis_insert_addr(&cp, &len, - &ia->ia_addr.siso_addr, m, nsellen)) { - EXTEND_PACKET(m, m0, cp); - (void) esis_insert_addr(&cp, &len, &ia->ia_addr.siso_addr, m, - nsellen); - } - naddr++; - } - - if (type == ESIS_ESH) - *naddrp = naddr; - else { - /* add suggested es config timer option to ISH */ - if (M_TRAILINGSPACE(m) < 4) { - printf("esis_shoutput: extending packet\n"); - EXTEND_PACKET(m, m0, cp); - } - *cp++ = ESISOVAL_ESCT; - *cp++ = 2; - HTOC(*cp, *(cp+1), esis_esconfig_time); - len += 4; - m->m_len += 4; - IFDEBUG(D_ESISOUTPUT) - printf("m0 0x%x, m 0x%x, data 0x%x, len %d, cp 0x%x\n", - m0, m, m->m_data, m->m_len, cp); - ENDDEBUG - } - - m0->m_pkthdr.len = len; - pdu->esis_hdr_len = len; - iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len); - - bzero((caddr_t)&siso, sizeof(siso)); - siso.siso_family = AF_ISO; - siso.siso_data[0] = AFI_SNA; - siso.siso_nlen = sn_len + 1; - bcopy(sn_addr, siso.siso_data + 1, (unsigned)sn_len); - (ifp->if_output)(ifp, m0, (struct sockaddr *)&siso, 0); -} - -/* - * FUNCTION: isis_input - * - * PURPOSE: Process an incoming isis packet - * - * RETURNS: nothing - * - * SIDE EFFECTS: - * - * NOTES: - */ -isis_input(m0, shp) -struct mbuf *m0; /* ptr to first mbuf of pkt */ -struct snpa_hdr *shp; /* subnetwork header */ -{ - register int type; - register struct rawcb *rp, *first_rp = 0; - struct ifnet *ifp = shp->snh_ifp; - char workbuf[16]; - struct mbuf *mm; - - IFDEBUG(D_ISISINPUT) - int i; - - printf("isis_input: pkt on ifp x%x (%s%d): from:", ifp, - ifp->if_name, ifp->if_unit); - for (i=0; i<6; i++) - printf("%x%c", shp->snh_shost[i]&0xff, (i<5) ? ':' : ' '); - printf(" to:"); - for (i=0; i<6; i++) - printf("%x%c", shp->snh_dhost[i]&0xff, (i<5) ? ':' : ' '); - printf("\n"); - ENDDEBUG - esis_dl.sdl_alen = ifp->if_addrlen; - esis_dl.sdl_index = ifp->if_index; - bcopy(shp->snh_shost, (caddr_t)esis_dl.sdl_data, esis_dl.sdl_alen); - for (rp = esis_pcb.rcb_next; rp != &esis_pcb; rp = rp->rcb_next) { - if (first_rp == 0) { - first_rp = rp; - continue; - } - if (mm = m_copy(m0, 0, M_COPYALL)) { /*can't block at interrupt level */ - if (sbappendaddr(&rp->rcb_socket->so_rcv, - &esis_dl, mm, (struct mbuf *)0) != 0) { - sorwakeup(rp->rcb_socket); - } else { - IFDEBUG(D_ISISINPUT) - printf("Error in sbappenaddr, mm = 0x%x\n", mm); - ENDDEBUG - m_freem(mm); - } - } - } - if (first_rp && sbappendaddr(&first_rp->rcb_socket->so_rcv, - &esis_dl, m0, (struct mbuf *)0) != 0) { - sorwakeup(first_rp->rcb_socket); - return; - } - m_freem(m0); -} - -isis_output(sdl, m) -register struct sockaddr_dl *sdl; -struct mbuf *m; -{ - register struct ifnet *ifp; - struct ifaddr *ifa, *ifa_ifwithnet(); - struct sockaddr_iso siso; - int error = 0; - unsigned sn_len; - - ifa = ifa_ifwithnet((struct sockaddr *)sdl); /* get ifp from sdl */ - if (ifa == 0) { - IFDEBUG(D_ISISOUTPUT) - printf("isis_output: interface not found\n"); - ENDDEBUG - error = EINVAL; - goto release; - } - ifp = ifa->ifa_ifp; - sn_len = sdl->sdl_alen; - IFDEBUG(D_ISISOUTPUT) - u_char *cp = (u_char *)LLADDR(sdl), *cplim = cp + sn_len; - printf("isis_output: ifp 0x%x (%s%d), to: ", - ifp, ifp->if_name, ifp->if_unit); - while (cp < cplim) { - printf("%x", *cp++); - printf("%c", (cp < cplim) ? ':' : ' '); - } - printf("\n"); - ENDDEBUG - bzero((caddr_t)&siso, sizeof(siso)); - siso.siso_family = AF_ISO; /* This convention may be useful for X.25 */ - siso.siso_data[0] = AFI_SNA; - siso.siso_nlen = sn_len + 1; - bcopy(LLADDR(sdl), siso.siso_data + 1, sn_len); - error = (ifp->if_output)(ifp, m, (struct sockaddr *)&siso, 0); - if (error) { - IFDEBUG(D_ISISOUTPUT) - printf("isis_output: error from ether_output is %d\n", error); - ENDDEBUG - } - return (error); - -release: - if (m != NULL) - m_freem(m); - return(error); -} - - -/* - * FUNCTION: esis_ctlinput - * - * PURPOSE: Handle the PRC_IFDOWN transition - * - * RETURNS: nothing - * - * SIDE EFFECTS: - * - * NOTES: Calls snpac_flush for interface specified. - * The loop through iso_ifaddr is stupid because - * back in if_down, we knew the ifp... - */ -esis_ctlinput(req, siso) -int req; /* request: we handle only PRC_IFDOWN */ -struct sockaddr_iso *siso; /* address of ifp */ -{ - register struct iso_ifaddr *ia; /* scan through interface addresses */ - - if (req == PRC_IFDOWN) - for (ia = iso_ifaddr; ia; ia = ia->ia_next) { - if (iso_addrmatch(IA_SIS(ia), siso)) - snpac_flushifp(ia->ia_ifp); - } -} - -#endif /* ISO */ diff --git a/bsd/netiso/esis.h b/bsd/netiso/esis.h deleted file mode 100644 index f9a5ad998..000000000 --- a/bsd/netiso/esis.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)esis.h 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ - -#ifndef BYTE_ORDER -/* - * Definitions for byte order, - * according to byte significance from low address to high. - */ -#define LITTLE_ENDIAN 1234 /* least-significant byte first (vax) */ -#define BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */ -#define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp) */ - -#ifdef vax -#define BYTE_ORDER LITTLE_ENDIAN -#else -#define BYTE_ORDER BIG_ENDIAN /* mc68000, tahoe, most others */ -#endif -#endif /* BYTE_ORDER */ - -#define SNPAC_AGE 60 /* seconds */ -#define ESIS_CONFIG 60 /* seconds */ -#define ESIS_HT (ESIS_CONFIG * 2) - -/* - * Fixed part of an ESIS header - */ -struct esis_fixed { - u_char esis_proto_id; /* network layer protocol identifier */ - u_char esis_hdr_len; /* length indicator (octets) */ - u_char esis_vers; /* version/protocol identifier extension */ - u_char esis_res1; /* reserved */ - u_char esis_type; /* type code */ -/* technically, type should be &='d 0x1f */ -#define ESIS_ESH 0x02 /* End System Hello */ -#define ESIS_ISH 0x04 /* Intermediate System Hello */ -#define ESIS_RD 0x06 /* Redirect */ - u_char esis_ht_msb; /* holding time (seconds) high byte */ - u_char esis_ht_lsb; /* holding time (seconds) low byte */ - u_char esis_cksum_msb; /* checksum high byte */ - u_char esis_cksum_lsb; /* checksum low byte */ -}; -/* - * Values for ESIS datagram options - */ -#define ESISOVAL_NETMASK 0xe1 /* address mask option, RD PDU only */ -#define ESISOVAL_SNPAMASK 0xe2 /* snpa mask option, RD PDU only */ -#define ESISOVAL_ESCT 0xc6 /* end system conf. timer, ISH PDU only */ - - -#define ESIS_CKSUM_OFF 0x07 -#define ESIS_CKSUM_REQUIRED(pdu)\ - ((pdu->esis_cksum_msb != 0) || (pdu->esis_cksum_lsb != 0)) - -#define ESIS_VERSION 1 - -struct esis_stat { - u_short es_nomem; /* insufficient memory to send hello */ - u_short es_badcsum; /* incorrect checksum */ - u_short es_badvers; /* incorrect version number */ - u_short es_badtype; /* unknown pdu type field */ - u_short es_toosmall; /* packet too small */ - u_short es_eshsent; /* ESH sent */ - u_short es_eshrcvd; /* ESH rcvd */ - u_short es_ishsent; /* ISH sent */ - u_short es_ishrcvd; /* ISH rcvd */ - u_short es_rdsent; /* RD sent */ - u_short es_rdrcvd; /* RD rcvd */ -}; - -#ifdef KERNEL -struct esis_stat esis_stat; -#endif /* KERNEL */ diff --git a/bsd/netiso/idrp_usrreq.c b/bsd/netiso/idrp_usrreq.c deleted file mode 100644 index 1f57da43f..000000000 --- a/bsd/netiso/idrp_usrreq.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1992, 1993 - * 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. - * - * @(#)idrp_usrreq.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -int idrp_input(); -struct isopcb idrp_isop; -static struct sockaddr_iso idrp_addrs[2] = -{ { sizeof(idrp_addrs), AF_ISO, }, { sizeof(idrp_addrs[1]), AF_ISO, } }; -/* - * IDRP initialization - */ -idrp_init() -{ - extern struct clnl_protosw clnl_protox[256]; - - idrp_isop.isop_next = idrp_isop.isop_prev = &idrp_isop; - idrp_isop.isop_faddr = &idrp_isop.isop_sfaddr; - idrp_isop.isop_laddr = &idrp_isop.isop_sladdr; - idrp_isop.isop_sladdr = idrp_addrs[1]; - idrp_isop.isop_sfaddr = idrp_addrs[1]; - clnl_protox[ISO10747_IDRP].clnl_input = idrp_input; -} - -/* - * CALLED FROM: - * tpclnp_input(). - * FUNCTION and ARGUMENTS: - * Take a packet (m) from clnp, strip off the clnp header - * and mke suitable for the idrp socket. - * No return value. - */ -idrp_input(m, src, dst) - register struct mbuf *m; - struct sockaddr_iso *src, *dst; -{ - if (idrp_isop.isop_socket == 0) { - bad: m_freem(m); - return 0; - } - bzero(idrp_addrs[0].siso_data, sizeof(idrp_addrs[0].siso_data)); - bcopy((caddr_t)&(src->siso_addr), (caddr_t)&idrp_addrs[0].siso_addr, - 1 + src->siso_nlen); - bzero(idrp_addrs[1].siso_data, sizeof(idrp_addrs[1].siso_data)); - bcopy((caddr_t)&(dst->siso_addr), (caddr_t)&idrp_addrs[1].siso_addr, - 1 + dst->siso_nlen); - if (sbappendaddr(&idrp_isop.isop_socket->so_rcv, - (struct sockaddr *)idrp_addrs, m, (struct mbuf *)0) == 0) - goto bad; - sorwakeup(idrp_isop.isop_socket); - return 0; -} - -idrp_output(m, addr) - struct mbuf *m, *addr; -{ - register struct sockaddr_iso *siso = mtod(addr, struct sockaddr_iso *); - int s = splnet(), i; - - bcopy((caddr_t)&(siso->siso_addr), - (caddr_t)&idrp_isop.isop_sfaddr.siso_addr, 1 + siso->siso_nlen); - siso++; - bcopy((caddr_t)&(siso->siso_addr), - (caddr_t)&idrp_isop.isop_sladdr.siso_addr, 1 + siso->siso_nlen); - i = clnp_output(m, idrp_isop, m->m_pkthdr.len, 0); - splx(s); - return (i); -} - -u_long idrp_sendspace = 3072; /* really max datagram size */ -u_long idrp_recvspace = 40 * 1024; /* 40 1K datagrams */ - -/*ARGSUSED*/ -idrp_usrreq(so, req, m, addr, control) - struct socket *so; - int req; - struct mbuf *m, *addr, *control; -{ - int error = 0; - - /* Note: need to block idrp_input while changing - * the udp pcb queue and/or pcb addresses. - */ - switch (req) { - - case PRU_ATTACH: - if (idrp_isop.isop_socket != NULL) { - error = ENXIO; - break; - } - idrp_isop.isop_socket = so; - error = soreserve(so, idrp_sendspace, idrp_recvspace); - break; - - case PRU_SHUTDOWN: - socantsendmore(so); - break; - - case PRU_SEND: - return (idrp_output(m, addr)); - - case PRU_ABORT: - soisdisconnected(so); - case PRU_DETACH: - idrp_isop.isop_socket = 0; - break; - - - case PRU_SENSE: - /* - * stat: don't bother with a blocksize. - */ - return (0); - - default: - return (EOPNOTSUPP); /* do not free mbuf's */ - } - -release: - if (control) { - printf("idrp control data unexpectedly retained\n"); - m_freem(control); - } - if (m) - m_freem(m); - return (error); -} diff --git a/bsd/netiso/if_cons.c b/bsd/netiso/if_cons.c deleted file mode 100644 index 48c289107..000000000 --- a/bsd/netiso/if_cons.c +++ /dev/null @@ -1,978 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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_cons.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * cons.c - Connection Oriented Network Service: - * including support for a) user transport-level service, - * b) COSNS below CLNP, and c) CONS below TP. - */ - -#if TPCONS -#ifdef KERNEL -#ifdef ARGO_DEBUG -#define Static -unsigned LAST_CALL_PCB; -#else /* ARGO_DEBUG */ -#define Static static -#endif /* ARGO_DEBUG */ - -#ifndef SOCK_STREAM -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#endif - -#ifdef ARGO_DEBUG -#define MT_XCONN 0x50 -#define MT_XCLOSE 0x51 -#define MT_XCONFIRM 0x52 -#define MT_XDATA 0x53 -#define MT_XHEADER 0x54 -#else -#define MT_XCONN MT_DATA -#define MT_XCLOSE MT_DATA -#define MT_XCONFIRM MT_DATA -#define MT_XDATA MT_DATA -#define MT_XHEADER MT_HEADER -#endif /* ARGO_DEBUG */ - -#define DONTCLEAR -1 - -/********************************************************************* - * cons.c - CONS interface to the x.25 layer - * - * TODO: figure out what resources we might run out of besides mbufs. - * If we run out of any of them (including mbufs) close and recycle - * lru x% of the connections, for some parameter x. - * - * There are 2 interfaces from above: - * 1) from TP0: - * cons CO network service - * TP associates a transport connection with a network connection. - * cons_output( isop, m, len, isdgm==0 ) - * co_flags == 0 - * 2) from TP4: - * It's a datagram service, like clnp is. - even though it calls - * cons_output( isop, m, len, isdgm==1 ) - * it eventually goes through - * cosns_output(ifp, m, dst). - * TP4 permits multiplexing (reuse, possibly simultaneously) of the - * network connections. - * This means that many sockets (many tpcbs) may be associated with - * this pklcd, hence cannot have a back ptr from pklcd to a tpcb. - * co_flags & CONSF_DGM - * co_socket is null since there may be many sockets that use this pklcd. - * -NOTE: - streams would really be nice. sigh. -NOTE: - PVCs could be handled by config-ing a cons with an address and with the - IFF_POINTTOPOINT flag on. This code would then have to skip the - connection setup stuff for pt-to-pt links. - - - *********************************************************************/ - - -#define CONS_IFQMAXLEN 5 - - -/* protosw pointers for getting to higher layer */ -Static struct protosw *CLNP_proto; -Static struct protosw *TP_proto; -Static struct protosw *X25_proto; -Static int issue_clear_req(); - -#ifndef PHASEONE -extern struct ifaddr *ifa_ifwithnet(); -#endif /* PHASEONE */ - -extern struct ifaddr *ifa_ifwithaddr(); - -extern struct isopcb tp_isopcb; /* chain of all TP pcbs */ - - -Static int parse_facil(), NSAPtoDTE(), make_partial_x25_packet(); -Static int FACILtoNSAP(), DTEtoNSAP(); -Static struct pklcd *cons_chan_to_pcb(); - -#define HIGH_NIBBLE 1 -#define LOW_NIBBLE 0 - -/* - * NAME: nibble_copy() - * FUNCTION and ARGUMENTS: - * copies (len) nibbles from (src_octet), high or low nibble - * to (dst_octet), high or low nibble, - * src_nibble & dst_nibble should be: - * HIGH_NIBBLE (1) if leftmost 4 bits/ most significant nibble - * LOW_NIBBLE (0) if rightmost 4 bits/ least significant nibble - * RETURNS: VOID - */ -void -nibble_copy(src_octet, src_nibble, dst_octet, dst_nibble, len) - register char *src_octet; - register char *dst_octet; - register unsigned src_nibble; - register unsigned dst_nibble; - int len; -{ - - register i; - register unsigned dshift, sshift; - - IFDEBUG(D_CADDR) - printf("nibble_copy ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n", - src_octet, src_nibble, dst_octet, dst_nibble, len); - ENDDEBUG -#define SHIFT 0x4 - - dshift = dst_nibble << 2; - sshift = src_nibble << 2; - - for (i=0; i> sshift))<< dshift; - - dshift ^= SHIFT; - sshift ^= SHIFT; - src_nibble = 1-src_nibble; - dst_nibble = 1-dst_nibble; - src_octet += src_nibble; - dst_octet += dst_nibble; - } - IFDEBUG(D_CADDR) - printf("nibble_copy DONE\n"); - ENDDEBUG -} - -/* - * NAME: nibble_match() - * FUNCTION and ARGUMENTS: - * compares src_octet/src_nibble and dst_octet/dst_nibble for len nibbles. - * RETURNS: 0 if they differ, 1 if they are the same. - */ -int -nibble_match( src_octet, src_nibble, dst_octet, dst_nibble, len) - register char *src_octet; - register char *dst_octet; - register unsigned src_nibble; - register unsigned dst_nibble; - int len; -{ - - register i; - register unsigned dshift, sshift; - u_char nibble_a, nibble_b; - - IFDEBUG(D_CADDR) - printf("nibble_match ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n", - src_octet, src_nibble, dst_octet, dst_nibble, len); - ENDDEBUG -#define SHIFT 0x4 - - dshift = dst_nibble << 2; - sshift = src_nibble << 2; - - for (i=0; i>dshift) & 0xf; - nibble_a = ( 0xf & (*src_octet >> sshift)); - if (nibble_b != nibble_a) - return 0; - - dshift ^= SHIFT; - sshift ^= SHIFT; - src_nibble = 1-src_nibble; - dst_nibble = 1-dst_nibble; - src_octet += src_nibble; - dst_octet += dst_nibble; - } - IFDEBUG(D_CADDR) - printf("nibble_match DONE\n"); - ENDDEBUG - return 1; -} - -/* - **************************** NET PROTOCOL cons *************************** - */ -/* - * NAME: cons_init() - * CALLED FROM: - * autoconf - * FUNCTION: - * initialize the protocol - */ -cons_init() -{ - int tp_incoming(), clnp_incoming(); - - - CLNP_proto = pffindproto(AF_ISO, ISOPROTO_CLNP, SOCK_DGRAM); - X25_proto = pffindproto(AF_ISO, ISOPROTO_X25, SOCK_STREAM); - TP_proto = pffindproto(AF_ISO, ISOPROTO_TP0, SOCK_SEQPACKET); - IFDEBUG(D_CCONS) - printf("cons_init end : cnlp_proto 0x%x cons proto 0x%x tp proto 0x%x\n", - CLNP_proto, X25_proto, TP_proto); - ENDDEBUG -#ifdef notdef - pk_protolisten(0x81, 0, clnp_incoming); - pk_protolisten(0x82, 0, esis_incoming); - pk_protolisten(0x84, 0, tp8878_A_incoming); - pk_protolisten(0, 0, tp_incoming); -#endif -} - -tp_incoming(lcp, m) -struct pklcd *lcp; -register struct mbuf *m; -{ - register struct isopcb *isop; - int cons_tpinput(); - - if (iso_pcballoc((struct socket *)0, &tp_isopcb)) { - pk_close(lcp); - return; - } - isop = tp_isopcb.isop_next; - lcp->lcd_upper = cons_tpinput; - lcp->lcd_upnext = (caddr_t)isop; - lcp->lcd_send(lcp); /* Confirms call */ - isop->isop_chan = (caddr_t)lcp; - isop->isop_laddr = &isop->isop_sladdr; - isop->isop_faddr = &isop->isop_sfaddr; - DTEtoNSAP(isop->isop_laddr, &lcp->lcd_laddr); - DTEtoNSAP(isop->isop_faddr, &lcp->lcd_faddr); - parse_facil(lcp, isop, &(mtod(m, struct x25_packet *)->packet_data), - m->m_pkthdr.len - PKHEADERLN); -} - -cons_tpinput(lcp, m0) -struct mbuf *m0; -struct pklcd *lcp; -{ - register struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext; - register struct x25_packet *xp; - int cmd, ptype = CLEAR; - - if (isop == 0) - return; - if (m0 == 0) - goto dead; - switch(m0->m_type) { - case MT_DATA: - case MT_OOBDATA: - tpcons_input(m0, isop->isop_faddr, isop->isop_laddr, (caddr_t)lcp); - return; - - case MT_CONTROL: - switch (ptype = pk_decode(mtod(m0, struct x25_packet *))) { - - case RR: - cmd = PRC_CONS_SEND_DONE; - break; - - case CALL_ACCEPTED: - if (lcp->lcd_sb.sb_mb) - lcp->lcd_send(lcp); /* XXX - fix this */ - /*FALLTHROUGH*/ - default: - return; - - dead: - case CLEAR: - case CLEAR_CONF: - lcp->lcd_upper = 0; - lcp->lcd_upnext = 0; - isop->isop_chan = 0; - case RESET: - cmd = PRC_ROUTEDEAD; - } - tpcons_ctlinput(cmd, isop->isop_faddr, isop); - if (cmd = PRC_ROUTEDEAD && isop->isop_refcnt == 0) - iso_pcbdetach(isop); - } -} - -/* - * NAME: cons_connect() - * CALLED FROM: - * tpcons_pcbconnect() when opening a new connection. - * FUNCTION anD ARGUMENTS: - * Figures out which device to use, finding a route if one doesn't - * already exist. - * RETURN VALUE: - * returns E* - */ -cons_connect(isop) - register struct isopcb *isop; -{ - register struct pklcd *lcp = (struct pklcd *)isop->isop_chan; - register struct mbuf *m; - struct ifaddr *ifa; - int error; - - IFDEBUG(D_CCONN) - printf("cons_connect(0x%x): ", isop); - dump_isoaddr(isop->isop_faddr); - printf("myaddr: "); - dump_isoaddr(isop->isop_laddr); - printf("\n" ); - ENDDEBUG - NSAPtoDTE(isop->isop_faddr, &lcp->lcd_faddr); - lcp->lcd_upper = cons_tpinput; - lcp->lcd_upnext = (caddr_t)isop; - IFDEBUG(D_CCONN) - printf( - "calling make_partial_x25_packet( 0x%x, 0x%x, 0x%x)\n", - &lcp->lcd_faddr, &lcp->lcd_laddr, - isop->isop_socket->so_proto->pr_protocol); - ENDDEBUG - if ((error = make_partial_x25_packet(isop, lcp, m)) == 0) - error = pk_connect(lcp, &lcp->lcd_faddr); - return error; -} - -/* - **************************** DEVICE cons *************************** - */ - - -/* - * NAME: cons_ctlinput() - * CALLED FROM: - * lower layer when ECN_CLEAR occurs : this routine is here - * for consistency - cons subnet service calls its higher layer - * through the protosw entry. - * FUNCTION & ARGUMENTS: - * cmd is a PRC_* command, list found in ../sys/protosw.h - * copcb is the obvious. - * This serves the higher-layer cons service. - * NOTE: this takes 3rd arg. because cons uses it to inform itself - * of things (timeouts, etc) but has a pcb instead of an address. - */ -cons_ctlinput(cmd, sa, copcb) - int cmd; - struct sockaddr *sa; - register struct pklcd *copcb; -{ -} - - -find_error_reason( xp ) - register struct x25_packet *xp; -{ - extern u_char x25_error_stats[]; - int error, cause; - - if (xp) { - cause = 4[(char *)xp]; - switch (cause) { - case 0x00: - case 0x80: - /* DTE originated; look at the diagnostic */ - error = (CONL_ERROR_MASK | cause); - goto done; - - case 0x01: /* number busy */ - case 0x81: - case 0x09: /* Out of order */ - case 0x89: - case 0x11: /* Remot Procedure Error */ - case 0x91: - case 0x19: /* reverse charging accept not subscribed */ - case 0x99: - case 0x21: /* Incampat destination */ - case 0xa1: - case 0x29: /* fast select accept not subscribed */ - case 0xa9: - case 0x39: /* ship absent */ - case 0xb9: - case 0x03: /* invalid facil request */ - case 0x83: - case 0x0b: /* access barred */ - case 0x8b: - case 0x13: /* local procedure error */ - case 0x93: - case 0x05: /* network congestion */ - case 0x85: - case 0x8d: /* not obtainable */ - case 0x0d: - case 0x95: /* RPOA out of order */ - case 0x15: - /* take out bit 8 - * so we don't have to have so many perror entries - */ - error = (CONL_ERROR_MASK | 0x100 | (cause & ~0x80)); - goto done; - - case 0xc1: /* gateway-detected proc error */ - case 0xc3: /* gateway congestion */ - - error = (CONL_ERROR_MASK | 0x100 | cause); - goto done; - } - } - /* otherwise, a *hopefully* valid perror exists in the e_reason field */ - error = xp->packet_data; - if (error = 0) { - printf("Incoming PKT TYPE 0x%x with reason 0x%x\n", - pk_decode(xp), - cause); - error = E_CO_HLI_DISCA; - } - -done: - return error; -} - - - -#endif /* KERNEL */ - -/* - * NAME: make_partial_x25_packet() - * - * FUNCTION and ARGUMENTS: - * Makes part of an X.25 call packet, for use by x25. - * (src) and (dst) are the NSAP-addresses of source and destination. - * (buf) is a ptr to a buffer into which to write this partial header. - * - * 0 Facility length (in octets) - * 1 Facility field, which is a set of: - * m facil code - * m+1 facil param len (for >2-byte facilities) in octets - * m+2..p facil param field - * q user data (protocol identification octet) - * - * - * RETURNS: - * 0 if OK - * E* if failed. - * - * SIDE EFFECTS: - * Stores facilites mbuf in X.25 control block, where the connect - * routine knows where to look for it. - */ - -#ifdef X25_1984 -int cons_use_facils = 1; -#else /* X25_1984 */ -int cons_use_facils = 0; -#endif /* X25_1984 */ - -int cons_use_udata = 1; /* KLUDGE FOR DEBUGGING */ - -Static int -make_partial_x25_packet(isop, lcp) - struct isopcb *isop; - struct pklcd *lcp; -{ - u_int proto; - int flag; - caddr_t buf; - register caddr_t ptr; - register int len = 0; - int buflen =0; - caddr_t facil_len; - int oddness = 0; - struct mbuf *m; - - - IFDEBUG(D_CCONN) - printf("make_partial_x25_packet(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", - isop->isop_laddr, isop->isop_faddr, proto, m, flag); - ENDDEBUG - if (cons_use_udata) { - if (isop->isop_x25crud_len > 0) { - /* - * The user specified something. Stick it in - */ - bcopy(isop->isop_x25crud, lcp->lcd_faddr.x25_udata, - isop->isop_x25crud_len); - lcp->lcd_faddr.x25_udlen = isop->isop_x25crud_len; - } - } - - if (cons_use_facils == 0) { - lcp->lcd_facilities = 0; - return 0; - } - MGETHDR(m, MT_DATA, M_WAITOK); - if (m == 0) - return ENOBUFS; - buf = mtod(m, caddr_t); - ptr = buf; - - /* ptr now points to facil length (len of whole facil field in OCTETS */ - facil_len = ptr ++; - m->m_len = 0; - pk_build_facilities(m, &lcp->lcd_faddr, 0); - - IFDEBUG(D_CADDR) - printf("make_partial calling: ptr 0x%x, len 0x%x\n", ptr, - isop->isop_laddr->siso_addr.isoa_len); - ENDDEBUG - if (cons_use_facils) { - *ptr++ = 0; /* Marker to separate X.25 facitilies from CCITT ones */ - *ptr++ = 0x0f; - *ptr = 0xcb; /* calling facility code */ - ptr ++; - ptr ++; /* leave room for facil param len (in OCTETS + 1) */ - ptr ++; /* leave room for the facil param len (in nibbles), - * high two bits of which indicate full/partial NSAP - */ - len = isop->isop_laddr->siso_addr.isoa_len; - bcopy( isop->isop_laddr->siso_data, ptr, len); - *(ptr-2) = len+1; /* facil param len in octets */ - *(ptr-1) = len<<1; /* facil param len in nibbles */ - ptr += len; - - IFDEBUG(D_CADDR) - printf("make_partial called: ptr 0x%x, len 0x%x\n", ptr, - isop->isop_faddr->siso_addr.isoa_len); - ENDDEBUG - *ptr = 0xc9; /* called facility code */ - ptr ++; - ptr ++; /* leave room for facil param len (in OCTETS + 1) */ - ptr ++; /* leave room for the facil param len (in nibbles), - * high two bits of which indicate full/partial NSAP - */ - len = isop->isop_faddr->siso_nlen; - bcopy(isop->isop_faddr->siso_data, ptr, len); - *(ptr-2) = len+1; /* facil param len = addr len + 1 for each of these - * two length fields, in octets */ - *(ptr-1) = len<<1; /* facil param len in nibbles */ - ptr += len; - - } - *facil_len = ptr - facil_len - 1; - if (*facil_len > MAX_FACILITIES) - return E_CO_PNA_LONG; - - buflen = (int)(ptr - buf); - - IFDEBUG(D_CDUMP_REQ) - register int i; - - printf("ECN_CONNECT DATA buf 0x%x len %d (0x%x)\n", - buf, buflen, buflen); - for( i=0; i < buflen; ) { - printf("+%d: %x %x %x %x %x %x %x %x\n", - i, - *(buf+i), *(buf+i+1), *(buf+i+2), *(buf+i+3), - *(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7)); - i+=8; - } - ENDDEBUG - IFDEBUG(D_CADDR) - printf("make_partial returns buf 0x%x size 0x%x bytes\n", - mtod(m, caddr_t), buflen); - ENDDEBUG - - if (buflen > MHLEN) - return E_CO_PNA_LONG; - - m->m_pkthdr.len = m->m_len = buflen; - lcp->lcd_facilities = m; - return 0; -} - -/* - * NAME: NSAPtoDTE() - * CALLED FROM: - * make_partial_x25_packet() - * FUNCTION and ARGUMENTS: - * get a DTE address from an NSAP-address (struct sockaddr_iso) - * (dst_octet) is the octet into which to begin stashing the DTE addr - * (dst_nibble) takes 0 or 1. 1 means begin filling in the DTE addr - * in the high-order nibble of dst_octet. 0 means low-order nibble. - * (addr) is the NSAP-address - * (flag) is true if the transport suffix is to become the - * last two digits of the DTE address - * A DTE address is a series of ASCII digits - * - * A DTE address may have leading zeros. The are significant. - * 1 digit per nibble, may be an odd number of nibbles. - * - * An NSAP-address has the DTE address in the IDI. Leading zeros are - * significant. Trailing hex f indicates the end of the DTE address. - * The IDI is a series of BCD digits, one per nibble. - * - * RETURNS - * # significant digits in the DTE address, -1 if error. - */ - -Static int -NSAPtoDTE(siso, sx25) - register struct sockaddr_iso *siso; - register struct sockaddr_x25 *sx25; -{ - int dtelen = -1; - - IFDEBUG(D_CADDR) - printf("NSAPtoDTE: nsap: %s\n", clnp_iso_addrp(&siso->siso_addr)); - ENDDEBUG - - if (siso->siso_data[0] == AFI_37) { - register char *out = sx25->x25_addr; - register char *in = siso->siso_data + 1; - register int nibble; - char *lim = siso->siso_data + siso->siso_nlen; - char *olim = out+15; - int lowNibble = 0; - - while (in < lim) { - nibble = ((lowNibble ? *in++ : (*in >> 4)) & 0xf) | 0x30; - lowNibble ^= 1; - if (nibble != 0x3f && out < olim) - *out++ = nibble; - } - dtelen = out - sx25->x25_addr; - *out++ = 0; - } else { - /* error = iso_8208snparesolve(addr, x121string, &x121strlen);*/ - register struct rtentry *rt; - extern struct sockaddr_iso blank_siso; - struct sockaddr_iso nsiso; - - nsiso = blank_siso; - bcopy(nsiso.siso_data, siso->siso_data, - nsiso.siso_nlen = siso->siso_nlen); - if (rt = rtalloc1(&nsiso, 1)) { - register struct sockaddr_x25 *sxx = - (struct sockaddr_x25 *)rt->rt_gateway; - register char *in = sxx->x25_addr; - - rt->rt_use--; - if (sxx && sxx->x25_family == AF_CCITT) { - bcopy(sx25->x25_addr, sxx->x25_addr, sizeof(sx25->x25_addr)); - while (*in++) {} - dtelen = in - sxx->x25_addr; - } - } - } - return dtelen; -} - -/* - * NAME: FACILtoNSAP() - * CALLED FROM: - * parse_facil() - * FUNCTION and ARGUMENTS: - * Creates and NSAP in the sockaddr_iso (addr) from the - * x.25 facility found at buf - 1. - * RETURNS: - * 0 if ok, -1 if error. - */ - -Static int -FACILtoNSAP(addr, buf) - register u_char *buf; - register struct sockaddr_iso *addr; -{ - int len_in_nibbles = *++buf & 0x3f; - u_char buf_len = (len_in_nibbles + 1) >> 1;; /* in bytes */ - - IFDEBUG(D_CADDR) - printf("FACILtoNSAP( 0x%x, 0x%x, 0x%x )\n", - buf, buf_len, addr ); - ENDDEBUG - - len_in_nibbles = *buf & 0x3f; - /* despite the fact that X.25 makes us put a length in nibbles - * here, the NSAP-addrs are always in full octets - */ - switch (*buf++ & 0xc0) { - case 0: - /* Entire OSI NSAP address */ - bcopy((caddr_t)buf, addr->siso_data, addr->siso_nlen = buf_len); - break; - - case 40: - /* Partial OSI NSAP address, assume trailing */ - if (buf_len + addr->siso_nlen > sizeof(addr->siso_addr)) - return -1; - bcopy((caddr_t)buf, TSEL(addr), buf_len); - addr->siso_nlen += buf_len; - break; - - default: - /* Rather than blow away the connection, just ignore and use - NSAP from DTE */; - } - return 0; -} - -Static -init_siso(siso) -register struct sockaddr_iso *siso; -{ - siso->siso_len = sizeof (*siso); - siso->siso_family = AF_ISO; - siso->siso_data[0] = AFI_37; - siso->siso_nlen = 8; -} - -/* - * NAME: DTEtoNSAP() - * CALLED FROM: - * parse_facil() - * FUNCTION and ARGUMENTS: - * Creates a type 37 NSAP in the sockaddr_iso (addr) - * from a DTE address found in a sockaddr_x25. - * - * RETURNS: - * 0 if ok; E* otherwise. - */ - -Static int -DTEtoNSAP(addr, sx) - struct sockaddr_iso *addr; - struct sockaddr_x25 *sx; -{ - register char *in, *out; - register int first; - int pad_tail = 0; - int src_len; - - - init_siso(addr); - in = sx->x25_addr; - src_len = strlen(in); - addr->siso_nlen = (src_len + 3) / 2; - out = addr->siso_data; - *out++ = 0x37; - if (src_len & 1) { - pad_tail = 0xf; - src_len++; - } - for (first = 0; src_len > 0; src_len--) { - first |= 0xf & *in++; - if (src_len & 1) { - *out++ = first; - first = 0; - } - else first <<= 4; - } - if (pad_tail) - out[-1] |= 0xf; - return 0; /* ok */ -} - -/* - * FUNCTION and ARGUMENTS: - * parses (buf_len) bytes beginning at (buf) and finds - * a called nsap, a calling nsap, and protocol identifier. - * RETURNS: - * 0 if ok, E* otherwise. - */ - -Static int -parse_facil(lcp, isop, buf, buf_len) - caddr_t buf; - u_char buf_len; /* in bytes */ - struct isopcb *isop; - struct pklcd *lcp; -{ - register int i; - register u_char *ptr = (u_char *)buf; - u_char *ptr_lim, *facil_lim; - int facil_param_len, facil_len; - - IFDEBUG(D_CADDR) - printf("parse_facil(0x%x, 0x%x, 0x%x, 0x%x)\n", - lcp, isop, buf, buf_len); - dump_buf(buf, buf_len); - ENDDEBUG - - /* find the beginnings of the facility fields in buf - * by skipping over the called & calling DTE addresses - * i <- # nibbles in called + # nibbles in calling - * i += 1 so that an odd nibble gets rounded up to even - * before dividing by 2, then divide by two to get # octets - */ - i = (int)(*ptr >> 4) + (int)(*ptr&0xf); - i++; - ptr += i >> 1; - ptr ++; /* plus one for the DTE lengths byte */ - - /* ptr now is at facil_length field */ - facil_len = *ptr++; - facil_lim = ptr + facil_len; - IFDEBUG(D_CADDR) - printf("parse_facils: facil length is 0x%x\n", (int) facil_len); - ENDDEBUG - - while (ptr < facil_lim) { - /* get NSAP addresses from facilities */ - switch (*ptr++) { - case 0xcb: - /* calling NSAP */ - facil_param_len = FACILtoNSAP(isop->isop_faddr, ptr); - break; - case 0xc9: - /* called NSAP */ - facil_param_len = FACILtoNSAP(isop->isop_laddr, ptr); - break; - - /* from here to default are legit cases that I ignore */ - /* variable length */ - case 0xca: /* end-to-end transit delay negot */ - case 0xc6: /* network user id */ - case 0xc5: /* charging info : indicating monetary unit */ - case 0xc2: /* charging info : indicating segment count */ - case 0xc1: /* charging info : indicating call duration */ - case 0xc4: /* RPOA extended format */ - case 0xc3: /* call redirection notification */ - facil_param_len = 0; - break; - - /* 1 octet */ - case 0x0a: /* min. throughput class negot */ - case 0x02: /* throughput class */ - case 0x03: case 0x47: /* CUG stuff */ - case 0x0b: /* expedited data negot */ - case 0x01: /* Fast select or reverse charging - (example of intelligent protocol design) */ - case 0x04: /* charging info : requesting service */ - case 0x08: /* called line addr modified notification */ - case 0x00: /* marker to indicate beginning of CCITT facils */ - facil_param_len = 1; - break; - - /* any 2 octets */ - case 0x42: /* pkt size */ - case 0x43: /* win size */ - case 0x44: /* RPOA basic format */ - case 0x41: /* bilateral CUG stuff */ - case 0x49: /* transit delay selection and indication */ - facil_param_len = 2; - break; - - default: - printf( -"BOGUS FACILITY CODE facil_lim 0x%x facil_len %d, ptr 0x%x *ptr 0x%x\n", - facil_lim, facil_len, ptr - 1, ptr[-1]); - /* facil that we don't handle - return E_CO_HLI_REJI; */ - switch (ptr[-1] & 0xc0) { - case 0x00: facil_param_len = 1; break; - case 0x40: facil_param_len = 2; break; - case 0x80: facil_param_len = 3; break; - case 0xc0: facil_param_len = 0; break; - } - } - if (facil_param_len == -1) - return E_CO_REG_ICDA; - if (facil_param_len == 0) /* variable length */ - facil_param_len = (int)*ptr++; /* 1 + the real facil param */ - ptr += facil_param_len; - } - return 0; -} - -#endif /* TPCONS */ diff --git a/bsd/netiso/if_eon.c b/bsd/netiso/if_eon.c deleted file mode 100644 index 40c8716f7..000000000 --- a/bsd/netiso/if_eon.c +++ /dev/null @@ -1,627 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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_eon.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * EON rfc - * Layer between IP and CLNL - * - * TODO: - * Put together a current rfc986 address format and get the right offset - * for the nsel - */ - -#if EON -#define NEON 1 - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -extern struct timeval time; -extern struct ifnet loif; - -#define EOK 0 - -int eoninput(); -int eonoutput(); -int eonioctl(); -int eonattach(); -int eoninit(); -void eonrtrequest(); -struct ifnet eonif[1]; - -eonprotoinit() { - (void) eonattach(); -} - -struct eon_llinfo eon_llinfo; -#define PROBE_OK 0; - - -/* - * FUNCTION: eonattach - * - * PURPOSE: autoconf attach routine - * - * RETURNS: void - */ - -eonattach() -{ - register struct ifnet *ifp = eonif; - - IFDEBUG(D_EON) - printf("eonattach()\n"); - ENDDEBUG - ifp->if_unit = 0; - ifp->if_name = "eon"; - ifp->if_mtu = ETHERMTU; - /* since everything will go out over ether or token ring */ - - ifp->if_init = eoninit; - ifp->if_ioctl = eonioctl; - ifp->if_output = eonoutput; - ifp->if_type = IFT_EON; - ifp->if_addrlen = 5; - ifp->if_hdrlen = EONIPLEN; - ifp->if_flags = IFF_BROADCAST; - if_attach(ifp); - eonioctl(ifp, SIOCSIFADDR, (caddr_t)ifp->if_addrlist); - eon_llinfo.el_qhdr.link = - eon_llinfo.el_qhdr.rlink = &(eon_llinfo.el_qhdr); - - IFDEBUG(D_EON) - printf("eonattach()\n"); - ENDDEBUG -} - - -/* - * FUNCTION: eonioctl - * - * PURPOSE: io controls - ifconfig - * need commands to - * link-UP (core addr) (flags: ES, IS) - * link-DOWN (core addr) (flags: ES, IS) - * must be callable from kernel or user - * - * RETURNS: nothing - */ -eonioctl(ifp, cmd, data) - register struct ifnet *ifp; - int cmd; - register caddr_t data; -{ - int s = splimp(); - register int error = 0; - - IFDEBUG(D_EON) - printf("eonioctl (cmd 0x%x) \n", cmd); - ENDDEBUG - - switch (cmd) { - register struct ifaddr *ifa; - - case SIOCSIFADDR: - if (ifa = (struct ifaddr *)data) { - ifp->if_flags |= IFF_UP; - if (ifa->ifa_addr->sa_family != AF_LINK) - ifa->ifa_rtrequest = eonrtrequest; - } - break; - } - splx(s); - return(error); -} - - -eoniphdr(hdr, loc, ro, class, zero) -struct route *ro; -register struct eon_iphdr *hdr; -caddr_t loc; -{ - struct mbuf mhead; - register struct sockaddr_in *sin = (struct sockaddr_in *)&ro->ro_dst; - if (zero) { - bzero((caddr_t)hdr, sizeof (*hdr)); - bzero((caddr_t)ro, sizeof (*ro)); - } - sin->sin_family = AF_INET; - sin->sin_len = sizeof (*sin); - bcopy(loc, (caddr_t)&sin->sin_addr, sizeof(struct in_addr)); - /* - * 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) { - struct sockaddr_in *dst = - (struct sockaddr_in *)rt_key(ro->ro_rt); - if ((ro->ro_rt->rt_flags & RTF_UP) == 0 || - sin->sin_addr.s_addr != dst->sin_addr.s_addr) { - RTFREE(ro->ro_rt); - ro->ro_rt = (struct rtentry *)0; - } - } - rtalloc(ro); - if (ro->ro_rt) - ro->ro_rt->rt_use++; - hdr->ei_ip.ip_dst = sin->sin_addr; - hdr->ei_ip.ip_p = IPPROTO_EON; - hdr->ei_ip.ip_ttl = MAXTTL; - hdr->ei_eh.eonh_class = class; - hdr->ei_eh.eonh_vers = EON_VERSION; - hdr->ei_eh.eonh_csum = 0; - mhead.m_data = (caddr_t) &hdr->ei_eh; - mhead.m_len = sizeof(struct eon_hdr); - mhead.m_next = 0; - IFDEBUG(D_EON) - printf("eonoutput : gen csum (0x%x, offset %d, datalen %d)\n", - &mhead, - _offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr)); - ENDDEBUG - iso_gen_csum(&mhead, - _offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr)); -} -/* - * FUNCTION: eonrtrequest - * - * PURPOSE: maintains list of direct eon recipients. - * sets up IP route for rest. - * - * RETURNS: nothing - */ -void -eonrtrequest(cmd, rt, gate) -register struct rtentry *rt; -register struct sockaddr *gate; -{ - unsigned long zerodst = 0; - caddr_t ipaddrloc = (caddr_t) &zerodst; - register struct eon_llinfo *el = (struct eon_llinfo *)rt->rt_llinfo; - - /* - * Common Housekeeping - */ - switch (cmd) { - case RTM_DELETE: - if (el) { - remque(&(el->el_qhdr)); - if (el->el_iproute.ro_rt) - RTFREE(el->el_iproute.ro_rt); - Free(el); - rt->rt_llinfo = 0; - } - return; - - case RTM_ADD: - case RTM_RESOLVE: - rt->rt_rmx.rmx_mtu = loif.if_mtu; /* unless better below */ - R_Malloc(el, struct eon_llinfo *, sizeof(*el)); - rt->rt_llinfo = (caddr_t)el; - if (el == 0) - return; - Bzero(el, sizeof(*el)); - insque(&(el->el_qhdr), &eon_llinfo.el_qhdr); - el->el_rt = rt; - break; - } - if (gate || (gate = rt->rt_gateway)) switch (gate->sa_family) { - case AF_LINK: -#define SDL(x) ((struct sockaddr_dl *)x) - if (SDL(gate)->sdl_alen == 1) - el->el_snpaoffset = *(u_char *)LLADDR(SDL(gate)); - else - ipaddrloc = LLADDR(SDL(gate)); - break; - case AF_INET: -#define SIN(x) ((struct sockaddr_in *)x) - ipaddrloc = (caddr_t) &SIN(gate)->sin_addr; - break; - default: - return; - } - el->el_flags |= RTF_UP; - eoniphdr(&el->el_ei, ipaddrloc, &el->el_iproute, EON_NORMAL_ADDR, 0); - if (el->el_iproute.ro_rt) - rt->rt_rmx.rmx_mtu = el->el_iproute.ro_rt->rt_rmx.rmx_mtu - - sizeof(el->el_ei); -} - -/* - * FUNCTION: eoninit - * - * PURPOSE: initialization - * - * RETURNS: nothing - */ - -eoninit(unit) - int unit; -{ - printf("eon driver-init eon%d\n", unit); -} - - -/* - * FUNCTION: eonoutput - * - * PURPOSE: prepend an eon header and hand to IP - * ARGUMENTS: (ifp) is points to the ifnet structure for this unit/device - * (m) is an mbuf *, *m is a CLNL packet - * (dst) is a destination address - have to interp. as - * multicast or broadcast or real address. - * - * RETURNS: unix error code - * - * NOTES: - * - */ -eonoutput(ifp, m, dst, rt) - struct ifnet *ifp; - register struct mbuf *m; /* packet */ - struct sockaddr_iso *dst; /* destination addr */ - struct rtentry *rt; -{ - register struct eon_llinfo *el; - register struct eon_iphdr *ei; - struct route *ro; - int datalen; - struct mbuf *mh; - int error = 0, class = 0, alen = 0; - caddr_t ipaddrloc; - static struct eon_iphdr eon_iphdr; - static struct route route; - - IFDEBUG(D_EON) - printf("eonoutput \n" ); - ENDDEBUG - - ifp->if_lastchange = time; - ifp->if_opackets++; - if (rt == 0 || (el = (struct eon_llinfo *)rt->rt_llinfo) == 0) { - if (dst->siso_family == AF_LINK) { - register struct sockaddr_dl *sdl = (struct sockaddr_dl *)dst; - - ipaddrloc = LLADDR(sdl); - alen = sdl->sdl_alen; - } else if (dst->siso_family == AF_ISO && dst->siso_data[0] == AFI_SNA) { - alen = dst->siso_nlen - 1; - ipaddrloc = (caddr_t) dst->siso_data + 1; - } - switch (alen) { - case 5: - class = 4[(u_char *)ipaddrloc]; - case 4: - ro = &route; - ei = &eon_iphdr; - eoniphdr(ei, ipaddrloc, ro, class, 1); - goto send; - } -einval: - error = EINVAL; - goto flush; - } - if ((el->el_flags & RTF_UP) == 0) { - eonrtrequest(RTM_CHANGE, rt, (struct sockaddr *)0); - if ((el->el_flags & RTF_UP) == 0) { - error = EHOSTUNREACH; - goto flush; - } - } - if ((m->m_flags & M_PKTHDR) == 0) { - printf("eon: got non headered packet\n"); - goto einval; - } - ei = &el->el_ei; - ro = &el->el_iproute; - if (el->el_snpaoffset) { - if (dst->siso_family == AF_ISO) { - bcopy((caddr_t) &dst->siso_data[el->el_snpaoffset], - (caddr_t) &ei->ei_ip.ip_dst, sizeof(ei->ei_ip.ip_dst)); - } else - goto einval; - } -send: - /* put an eon_hdr in the buffer, prepended by an ip header */ - datalen = m->m_pkthdr.len + EONIPLEN; - MGETHDR(mh, M_DONTWAIT, MT_HEADER); - if(mh == (struct mbuf *)0) - goto flush; - mh->m_next = m; - m = mh; - MH_ALIGN(m, sizeof(struct eon_iphdr)); - m->m_len = sizeof(struct eon_iphdr); - ifp->if_obytes += - (ei->ei_ip.ip_len = (u_short)(m->m_pkthdr.len = datalen)); - *mtod(m, struct eon_iphdr *) = *ei; - - IFDEBUG(D_EON) - printf("eonoutput dst ip addr : %x\n", ei->ei_ip.ip_dst.s_addr); - printf("eonoutput ip_output : eonip header:\n"); - dump_buf(ei, sizeof(struct eon_iphdr)); - ENDDEBUG - - error = ip_output(m, (struct mbuf *)0, ro, 0, NULL); - m = 0; - if (error) { - ifp->if_oerrors++; - ifp->if_opackets--; - ifp->if_obytes -= datalen; - } -flush: - if (m) - m_freem(m); - return error; -} - -eoninput(m, iphlen) - register struct mbuf *m; - int iphlen; -{ - register struct eon_hdr *eonhdr; - register struct ip *iphdr; - struct ifnet *eonifp; - int s; - - eonifp = &eonif[0]; /* kludge - really want to give CLNP - * the ifp for eon, not for the real device - */ - - IFDEBUG(D_EON) - printf("eoninput() 0x%x m_data 0x%x m_len 0x%x dequeued\n", - m, m?m->m_data:0, m?m->m_len:0); - ENDDEBUG - - if (m == 0) - return; - if (iphlen > sizeof (struct ip)) - ip_stripoptions(m, (struct mbuf *)0); - if (m->m_len < EONIPLEN) { - if ((m = m_pullup(m, EONIPLEN)) == 0) { - IncStat(es_badhdr); -drop: - IFDEBUG(D_EON) - printf("eoninput: DROP \n" ); - ENDDEBUG - eonifp->if_ierrors ++; - m_freem(m); - return; - } - } - eonif->if_ibytes += m->m_pkthdr.len; - eonif->if_lastchange = time; - iphdr = mtod(m, struct ip *); - /* do a few checks for debugging */ - if( iphdr->ip_p != IPPROTO_EON ) { - IncStat(es_badhdr); - goto drop; - } - /* temporarily drop ip header from the mbuf */ - m->m_data += sizeof(struct ip); - eonhdr = mtod(m, struct eon_hdr *); - if( iso_check_csum( m, sizeof(struct eon_hdr) ) != EOK ) { - IncStat(es_badcsum); - goto drop; - } - m->m_data -= sizeof(struct ip); - - IFDEBUG(D_EON) - printf("eoninput csum ok class 0x%x\n", eonhdr->eonh_class ); - printf("eoninput: eon header:\n"); - dump_buf(eonhdr, sizeof(struct eon_hdr)); - ENDDEBUG - - /* checks for debugging */ - if( eonhdr->eonh_vers != EON_VERSION) { - IncStat(es_badhdr); - goto drop; - } - m->m_flags &= ~(M_BCAST|M_MCAST); - switch( eonhdr->eonh_class) { - case EON_BROADCAST: - IncStat(es_in_broad); - m->m_flags |= M_BCAST; - break; - case EON_NORMAL_ADDR: - IncStat(es_in_normal); - break; - case EON_MULTICAST_ES: - IncStat(es_in_multi_es); - m->m_flags |= M_MCAST; - break; - case EON_MULTICAST_IS: - IncStat(es_in_multi_is); - m->m_flags |= M_MCAST; - break; - } - eonifp->if_ipackets++; - - { - /* put it on the CLNP queue and set soft interrupt */ - struct ifqueue *ifq; - extern struct ifqueue clnlintrq; - - m->m_pkthdr.rcvif = eonifp; /* KLUDGE */ - IFDEBUG(D_EON) - printf("eoninput to clnl IFQ\n"); - ENDDEBUG - ifq = &clnlintrq; - s = splimp(); - if (IF_QFULL(ifq)) { - IF_DROP(ifq); - m_freem(m); - eonifp->if_iqdrops++; - eonifp->if_ipackets--; - splx(s); - return; - } - IF_ENQUEUE(ifq, m); - IFDEBUG(D_EON) - printf( - "0x%x enqueued on clnp Q: m_len 0x%x m_type 0x%x m_data 0x%x\n", - m, m->m_len, m->m_type, m->m_data); - dump_buf(mtod(m, caddr_t), m->m_len); - ENDDEBUG - schednetisr(NETISR_ISO); - splx(s); - } -} - -int -eonctlinput(cmd, sin) - int cmd; - struct sockaddr_in *sin; -{ - extern u_char inetctlerrmap[]; - - IFDEBUG(D_EON) - printf("eonctlinput: cmd 0x%x addr: ", cmd); - dump_isoaddr(sin); - printf("\n"); - ENDDEBUG - - if (cmd < 0 || cmd > PRC_NCMDS) - return 0; - - IncStat(es_icmp[cmd]); - switch (cmd) { - - case PRC_QUENCH: - case PRC_QUENCH2: - /* TODO: set the dec bit */ - break; - case PRC_TIMXCEED_REASS: - case PRC_ROUTEDEAD: - case PRC_HOSTUNREACH: - case PRC_UNREACH_NET: - case PRC_IFDOWN: - case PRC_UNREACH_HOST: - case PRC_HOSTDEAD: - case PRC_TIMXCEED_INTRANS: - /* TODO: mark the link down */ - break; - - case PRC_UNREACH_PROTOCOL: - case PRC_UNREACH_PORT: - case PRC_UNREACH_SRCFAIL: - case PRC_REDIRECT_NET: - case PRC_REDIRECT_HOST: - case PRC_REDIRECT_TOSNET: - case PRC_REDIRECT_TOSHOST: - case PRC_MSGSIZE: - case PRC_PARAMPROB: - /* printf("eonctlinput: ICMP cmd 0x%x\n", cmd );*/ - break; - } - return 0; -} - -#endif diff --git a/bsd/netiso/iso.c b/bsd/netiso/iso.c deleted file mode 100644 index c625d013a..000000000 --- a/bsd/netiso/iso.c +++ /dev/null @@ -1,938 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)iso.c 8.2 (Berkeley) 11/15/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * iso.c: miscellaneous routines to support the iso address family - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#if TUBA -#include -#endif - -#if ISO - -int iso_interfaces = 0; /* number of external interfaces */ -extern struct ifnet loif; /* loopback interface */ -int ether_output(); -void llc_rtrequest(); - -/* - * FUNCTION: iso_addrmatch1 - * - * PURPOSE: decide if the two iso_addrs passed are equal - * - * RETURNS: true if the addrs match, false if they do not - * - * SIDE EFFECTS: - * - * NOTES: - */ -iso_addrmatch1(isoaa, isoab) -register struct iso_addr *isoaa, *isoab; /* addresses to check */ -{ - u_int compare_len; - - IFDEBUG(D_ROUTE) - printf("iso_addrmatch1: comparing lengths: %d to %d\n", isoaa->isoa_len, - isoab->isoa_len); - printf("a:\n"); - dump_buf(isoaa->isoa_genaddr, isoaa->isoa_len); - printf("b:\n"); - dump_buf(isoab->isoa_genaddr, isoab->isoa_len); - ENDDEBUG - - if ((compare_len = isoaa->isoa_len) != isoab->isoa_len) { - IFDEBUG(D_ROUTE) - printf("iso_addrmatch1: returning false because of lengths\n"); - ENDDEBUG - return 0; - } - -#ifdef notdef - /* TODO : generalize this to all afis with masks */ - if( isoaa->isoa_afi == AFI_37 ) { - /* must not compare 2 least significant digits, or for - * that matter, the DSP - */ - compare_len = ADDR37_IDI_LEN - 1; - } -#endif - - IFDEBUG(D_ROUTE) - int i; - char *a, *b; - - a = isoaa->isoa_genaddr; - b = isoab->isoa_genaddr; - - for (i=0; i", a[i]&0xff, b[i]&0xff); - if (a[i] != b[i]) { - printf("\naddrs are not equal at byte %d\n", i); - return(0); - } - } - printf("\n"); - printf("addrs are equal\n"); - return (1); - ENDDEBUG - return (!bcmp(isoaa->isoa_genaddr, isoab->isoa_genaddr, compare_len)); -} - -/* - * FUNCTION: iso_addrmatch - * - * PURPOSE: decide if the two sockadrr_isos passed are equal - * - * RETURNS: true if the addrs match, false if they do not - * - * SIDE EFFECTS: - * - * NOTES: - */ -iso_addrmatch(sisoa, sisob) -struct sockaddr_iso *sisoa, *sisob; /* addresses to check */ -{ - return(iso_addrmatch1(&sisoa->siso_addr, &sisob->siso_addr)); -} -#ifdef notdef -/* - * FUNCTION: iso_netmatch - * - * PURPOSE: similar to iso_addrmatch but takes sockaddr_iso - * as argument. - * - * RETURNS: true if same net, false if not - * - * SIDE EFFECTS: - * - * NOTES: - */ -iso_netmatch(sisoa, sisob) -struct sockaddr_iso *sisoa, *sisob; -{ - u_char bufa[sizeof(struct sockaddr_iso)]; - u_char bufb[sizeof(struct sockaddr_iso)]; - register int lena, lenb; - - lena = iso_netof(&sisoa->siso_addr, bufa); - lenb = iso_netof(&sisob->siso_addr, bufb); - - IFDEBUG(D_ROUTE) - printf("iso_netmatch: comparing lengths: %d to %d\n", lena, lenb); - printf("a:\n"); - dump_buf(bufa, lena); - printf("b:\n"); - dump_buf(bufb, lenb); - ENDDEBUG - - return ((lena == lenb) && (!bcmp(bufa, bufb, lena))); -} -#endif /* notdef */ - -/* - * FUNCTION: iso_hashchar - * - * PURPOSE: Hash all character in the buffer specified into - * a long. Return the long. - * - * RETURNS: The hash value. - * - * SIDE EFFECTS: - * - * NOTES: The hash is achieved by exclusive ORing 4 byte - * quantities. - */ -u_long -iso_hashchar(buf, len) -register caddr_t buf; /* buffer to pack from */ -register int len; /* length of buffer */ -{ - register u_long h = 0; - register int i; - - for (i=0; isiso_addr, buf); - hp->afh_nethash = iso_hashchar((caddr_t)buf, bufsize); - - IFDEBUG(D_ROUTE) - printf("iso_hash: iso_netof: bufsize = %d\n", bufsize); - ENDDEBUG - - hp->afh_hosthash = iso_hashchar((caddr_t)&siso->siso_addr, - siso->siso_addr.isoa_len); - - IFDEBUG(D_ROUTE) - printf("iso_hash: %s: nethash = x%x, hosthash = x%x\n", - clnp_iso_addrp(&siso->siso_addr), hp->afh_nethash, - hp->afh_hosthash); - ENDDEBUG -} -/* - * FUNCTION: iso_netof - * - * PURPOSE: Extract the network portion of the iso address. - * The network portion of the iso address varies depending - * on the type of address. The network portion of the - * address will include the IDP. The network portion is: - * - * TYPE DESC - * t37 The AFI and x.121 (IDI) - * osinet The AFI, orgid, snetid - * rfc986 The AFI, vers and network part of - * internet address. - * - * RETURNS: number of bytes placed into buf. - * - * SIDE EFFECTS: - * - * NOTES: Buf is assumed to be big enough - */ -iso_netof(isoa, buf) -struct iso_addr *isoa; /* address */ -caddr_t buf; /* RESULT: network portion of address here */ -{ - u_int len = 1; /* length of afi */ - - switch (isoa->isoa_afi) { - case AFI_37: - /* - * Due to classic x.25 tunnel vision, there is no - * net portion of an x.121 address. For our purposes - * the AFI will do, so that all x.25 -type addresses - * map to the single x.25 SNPA. (Cannot have more than - * one, obviously). - */ - - break; - -/* case AFI_OSINET:*/ - case AFI_RFC986: { - u_short idi; /* value of idi */ - - /* osinet and rfc986 have idi in the same place */ - CTOH(isoa->rfc986_idi[0], isoa->rfc986_idi[1], idi); - - if (idi == IDI_OSINET) -/* - * Network portion of OSINET address can only be the IDI. Clearly, - * with one x25 interface, one could get to several orgids, and - * several snetids. - len += (ADDROSINET_IDI_LEN + OVLOSINET_ORGID_LEN + - OVLOSINET_SNETID_LEN); - */ - len += ADDROSINET_IDI_LEN; - else if (idi == IDI_RFC986) { - u_long inetaddr; - struct ovl_rfc986 *o986 = (struct ovl_rfc986 *)isoa; - - /* bump len to include idi and version (1 byte) */ - len += ADDRRFC986_IDI_LEN + 1; - - /* get inet addr long aligned */ - bcopy(o986->o986_inetaddr, &inetaddr, sizeof(inetaddr)); - inetaddr = ntohl(inetaddr); /* convert to host byte order */ - - IFDEBUG(D_ROUTE) - printf("iso_netof: isoa "); - dump_buf(isoa, sizeof(*isoa)); - printf("iso_netof: inetaddr 0x%x ", inetaddr); - ENDDEBUG - - /* bump len by size of network portion of inet address */ - if (IN_CLASSA(inetaddr)) { - len += 4-IN_CLASSA_NSHIFT/8; - IFDEBUG(D_ROUTE) - printf("iso_netof: class A net len is now %d\n", len); - ENDDEBUG - } else if (IN_CLASSB(inetaddr)) { - len += 4-IN_CLASSB_NSHIFT/8; - IFDEBUG(D_ROUTE) - printf("iso_netof: class B net len is now %d\n", len); - ENDDEBUG - } else { - len += 4-IN_CLASSC_NSHIFT/8; - IFDEBUG(D_ROUTE) - printf("iso_netof: class C net len is now %d\n", len); - ENDDEBUG - } - } else - len = 0; - } break; - - default: - len = 0; - } - - bcopy((caddr_t)isoa, buf, len); - IFDEBUG(D_ROUTE) - printf("iso_netof: isoa "); - dump_buf(isoa, len); - printf("iso_netof: net "); - dump_buf(buf, len); - ENDDEBUG - return len; -} -#endif /* notdef */ -/* - * Generic iso control operations (ioctl's). - * Ifp is 0 if not an interface-specific ioctl. - */ -/* ARGSUSED */ -iso_control(so, cmd, data, ifp) - struct socket *so; - int cmd; - caddr_t data; - register struct ifnet *ifp; -{ - register struct iso_ifreq *ifr = (struct iso_ifreq *)data; - register struct iso_ifaddr *ia = 0; - register struct ifaddr *ifa; - struct iso_ifaddr *oia; - struct iso_aliasreq *ifra = (struct iso_aliasreq *)data; - int error, hostIsNew, maskIsNew; - - /* - * Find address for this interface, if it exists. - */ - if (ifp) - for (ia = iso_ifaddr; ia; ia = ia->ia_next) - if (ia->ia_ifp == ifp) - break; - - switch (cmd) { - - case SIOCAIFADDR_ISO: - case SIOCDIFADDR_ISO: - if (ifra->ifra_addr.siso_family == AF_ISO) - for (oia = ia; ia; ia = ia->ia_next) { - if (ia->ia_ifp == ifp && - SAME_ISOADDR(&ia->ia_addr, &ifra->ifra_addr)) - break; - } - if ((so->so_state & SS_PRIV) == 0) - return (EPERM); - if (ifp == 0) - panic("iso_control"); - if (ia == (struct iso_ifaddr *)0) { - struct iso_ifaddr *nia; - if (cmd == SIOCDIFADDR_ISO) - return (EADDRNOTAVAIL); -#if TUBA - /* XXXXXX can't be done in the proto init routines */ - if (tuba_tree == 0) - tuba_table_init(); -#endif - MALLOC(nia, struct iso_ifaddr *, sizeof(*nia), - M_IFADDR, M_WAITOK); - if (nia == (struct iso_ifaddr *)0) - return (ENOBUFS); - bzero((caddr_t)nia, sizeof(*nia)); - if (ia = iso_ifaddr) { - for ( ; ia->ia_next; ia = ia->ia_next) - ; - ia->ia_next = nia; - } else - iso_ifaddr = nia; - ia = nia; - 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_ifp = ifp; - if (ifp != &loif) - iso_interfaces++; - } - break; - -#define cmdbyte(x) (((x) >> 8) & 0xff) - default: - if (cmdbyte(cmd) == 'a') - return (snpac_ioctl(so, cmd, data)); - if (ia == (struct iso_ifaddr *)0) - return (EADDRNOTAVAIL); - break; - } - switch (cmd) { - - case SIOCGIFADDR_ISO: - ifr->ifr_Addr = ia->ia_addr; - break; - - case SIOCGIFDSTADDR_ISO: - if ((ifp->if_flags & IFF_POINTOPOINT) == 0) - return (EINVAL); - ifr->ifr_Addr = ia->ia_dstaddr; - break; - - case SIOCGIFNETMASK_ISO: - ifr->ifr_Addr = ia->ia_sockmask; - break; - - case SIOCAIFADDR_ISO: - maskIsNew = 0; hostIsNew = 1; error = 0; - if (ia->ia_addr.siso_family == AF_ISO) { - if (ifra->ifra_addr.siso_len == 0) { - ifra->ifra_addr = ia->ia_addr; - hostIsNew = 0; - } else if (SAME_ISOADDR(&ia->ia_addr, &ifra->ifra_addr)) - hostIsNew = 0; - } - if (ifra->ifra_mask.siso_len) { - iso_ifscrub(ifp, ia); - ia->ia_sockmask = ifra->ifra_mask; - maskIsNew = 1; - } - if ((ifp->if_flags & IFF_POINTOPOINT) && - (ifra->ifra_dstaddr.siso_family == AF_ISO)) { - iso_ifscrub(ifp, ia); - ia->ia_dstaddr = ifra->ifra_dstaddr; - maskIsNew = 1; /* We lie; but the effect's the same */ - } - if (ifra->ifra_addr.siso_family == AF_ISO && - (hostIsNew || maskIsNew)) { - error = iso_ifinit(ifp, ia, &ifra->ifra_addr, 0); - } - if (ifra->ifra_snpaoffset) - ia->ia_snpaoffset = ifra->ifra_snpaoffset; - return (error); - - case SIOCDIFADDR_ISO: - iso_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 isoifaddr from ifp\n"); - } - oia = ia; - if (oia == (ia = iso_ifaddr)) { - iso_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 isoifadr from list\n"); - } - IFAFREE((&oia->ia_ifa)); - 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. - */ -iso_ifscrub(ifp, ia) - register struct ifnet *ifp; - register struct iso_ifaddr *ia; -{ - int nsellength = ia->ia_addr.siso_tlen; - if ((ia->ia_flags & IFA_ROUTE) == 0) - return; - ia->ia_addr.siso_tlen = 0; - if (ifp->if_flags & IFF_LOOPBACK) - rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); - else if (ifp->if_flags & IFF_POINTOPOINT) - rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); - else { - rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); - } - ia->ia_addr.siso_tlen = nsellength; - ia->ia_flags &= ~IFA_ROUTE; -} - -/* - * Initialize an interface's internet address - * and routing table entry. - */ -iso_ifinit(ifp, ia, siso, scrub) - register struct ifnet *ifp; - register struct iso_ifaddr *ia; - struct sockaddr_iso *siso; -{ - struct sockaddr_iso oldaddr; - int s = splimp(), error, nsellength; - - oldaddr = ia->ia_addr; - ia->ia_addr = *siso; - /* - * 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, (caddr_t)ia))) { - splx(s); - ia->ia_addr = oldaddr; - return (error); - } - if (scrub) { - ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr; - iso_ifscrub(ifp, ia); - ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; - } - /* XXX -- The following is here temporarily out of laziness - in not changing every ethernet driver's if_ioctl routine */ - if (ifp->if_output == ether_output) { - ia->ia_ifa.ifa_rtrequest = llc_rtrequest; - ia->ia_ifa.ifa_flags |= RTF_CLONING; - } - /* - * Add route for the network. - */ - nsellength = ia->ia_addr.siso_tlen; - ia->ia_addr.siso_tlen = 0; - if (ifp->if_flags & IFF_LOOPBACK) { - ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr; - error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP); - } else if (ifp->if_flags & IFF_POINTOPOINT && - ia->ia_dstaddr.siso_family == AF_ISO) - error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP); - else { - rt_maskedcopy(ia->ia_ifa.ifa_addr, ia->ia_ifa.ifa_dstaddr, - ia->ia_ifa.ifa_netmask); - ia->ia_dstaddr.siso_nlen = - min(ia->ia_addr.siso_nlen, (ia->ia_sockmask.siso_len - 6)); - error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP); - } - ia->ia_addr.siso_tlen = nsellength; - ia->ia_flags |= IFA_ROUTE; - splx(s); - return (error); -} -#ifdef notdef - -struct ifaddr * -iso_ifwithidi(addr) - register struct sockaddr *addr; -{ - register struct ifnet *ifp; - register struct ifaddr *ifa; - register u_int af = addr->sa_family; - - if (af != AF_ISO) - return (0); - IFDEBUG(D_ROUTE) - printf(">>> iso_ifwithidi addr\n"); - dump_isoaddr( (struct sockaddr_iso *)(addr)); - printf("\n"); - ENDDEBUG - for (ifp = ifnet; ifp; ifp = ifp->if_next) { - IFDEBUG(D_ROUTE) - printf("iso_ifwithidi ifnet %s\n", ifp->if_name); - ENDDEBUG - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { - IFDEBUG(D_ROUTE) - printf("iso_ifwithidi address "); - dump_isoaddr( (struct sockaddr_iso *)(ifa->ifa_addr)); - ENDDEBUG - if (ifa->ifa_addr->sa_family != addr->sa_family) - continue; - -#define IFA_SIS(ifa)\ - ((struct sockaddr_iso *)((ifa)->ifa_addr)) - - IFDEBUG(D_ROUTE) - printf(" af same, args to iso_eqtype:\n"); - printf("0x%x ", IFA_SIS(ifa)->siso_addr); - printf(" 0x%x\n", - &(((struct sockaddr_iso *)addr)->siso_addr)); - ENDDEBUG - - if (iso_eqtype(&(IFA_SIS(ifa)->siso_addr), - &(((struct sockaddr_iso *)addr)->siso_addr))) { - IFDEBUG(D_ROUTE) - printf("ifa_ifwithidi: ifa found\n"); - ENDDEBUG - return (ifa); - } - IFDEBUG(D_ROUTE) - printf(" iso_eqtype failed\n"); - ENDDEBUG - } - } - return ((struct ifaddr *)0); -} - -#endif /* notdef */ -/* - * FUNCTION: iso_ck_addr - * - * PURPOSE: return true if the iso_addr passed is - * within the legal size limit for an iso address. - * - * RETURNS: true or false - * - * SIDE EFFECTS: - * - */ -iso_ck_addr(isoa) -struct iso_addr *isoa; /* address to check */ -{ - return (isoa->isoa_len <= 20); - -} - -#ifdef notdef -/* - * FUNCTION: iso_eqtype - * - * PURPOSE: Determine if two iso addresses are of the same type. - * This is flaky. Really we should consider all type 47 addrs to be the - * same - but there do exist different structures for 47 addrs. - * Gosip adds a 3rd. - * - * RETURNS: true if the addresses are the same type - * - * SIDE EFFECTS: - * - * NOTES: By type, I mean rfc986, t37, or osinet - * - * This will first compare afis. If they match, then - * if the addr is not t37, the idis must be compared. - */ -iso_eqtype(isoaa, isoab) -struct iso_addr *isoaa; /* first addr to check */ -struct iso_addr *isoab; /* other addr to check */ -{ - if (isoaa->isoa_afi == isoab->isoa_afi) { - if (isoaa->isoa_afi == AFI_37) - return(1); - else - return (!bcmp(&isoaa->isoa_u, &isoab->isoa_u, 2)); - } - return(0); -} -#endif /* notdef */ -/* - * FUNCTION: iso_localifa() - * - * PURPOSE: Find an interface addresss having a given destination - * or at least matching the net. - * - * RETURNS: ptr to an interface address - * - * SIDE EFFECTS: - * - * NOTES: - */ -struct iso_ifaddr * -iso_localifa(siso) - register struct sockaddr_iso *siso; -{ - register struct iso_ifaddr *ia; - register char *cp1, *cp2, *cp3; - register struct ifnet *ifp; - struct iso_ifaddr *ia_maybe = 0; - /* - * We make one pass looking for both net matches and an exact - * dst addr. - */ - for (ia = iso_ifaddr; ia; ia = ia->ia_next) { - if ((ifp = ia->ia_ifp) == 0 || ((ifp->if_flags & IFF_UP) == 0)) - continue; - if (ifp->if_flags & IFF_POINTOPOINT) { - if ((ia->ia_dstaddr.siso_family == AF_ISO) && - SAME_ISOADDR(&ia->ia_dstaddr, siso)) - return (ia); - else - if (SAME_ISOADDR(&ia->ia_addr, siso)) - ia_maybe = ia; - continue; - } - if (ia->ia_sockmask.siso_len) { - char *cplim = ia->ia_sockmask.siso_len + (char *)&ia->ia_sockmask; - cp1 = ia->ia_sockmask.siso_data; - cp2 = siso->siso_data; - cp3 = ia->ia_addr.siso_data; - while (cp1 < cplim) - if (*cp1++ & (*cp2++ ^ *cp3++)) - goto next; - ia_maybe = ia; - } - if (SAME_ISOADDR(&ia->ia_addr, siso)) - return ia; - next:; - } - return ia_maybe; -} - -#if TPCONS -#include -#endif /* TPCONS */ -/* - * FUNCTION: iso_nlctloutput - * - * PURPOSE: Set options at the network level - * - * RETURNS: E* - * - * SIDE EFFECTS: - * - * NOTES: This could embody some of the functions of - * rclnp_ctloutput and cons_ctloutput. - */ -iso_nlctloutput(cmd, optname, pcb, m) -int cmd; /* command:set or get */ -int optname; /* option of interest */ -caddr_t pcb; /* nl pcb */ -struct mbuf *m; /* data for set, buffer for get */ -{ - struct isopcb *isop = (struct isopcb *)pcb; - int error = 0; /* return value */ - caddr_t data; /* data for option */ - int data_len; /* data's length */ - - IFDEBUG(D_ISO) - printf("iso_nlctloutput: cmd %x, opt %x, pcb %x, m %x\n", - cmd, optname, pcb, m); - ENDDEBUG - - if ((cmd != PRCO_GETOPT) && (cmd != PRCO_SETOPT)) - return(EOPNOTSUPP); - - data = mtod(m, caddr_t); - data_len = (m)->m_len; - - IFDEBUG(D_ISO) - printf("iso_nlctloutput: data is:\n"); - dump_buf(data, data_len); - ENDDEBUG - - switch (optname) { - -#if TPCONS - case CONSOPT_X25CRUD: - if (cmd == PRCO_GETOPT) { - error = EOPNOTSUPP; - break; - } - - if (data_len > MAXX25CRUDLEN) { - error = EINVAL; - break; - } - - IFDEBUG(D_ISO) - printf("iso_nlctloutput: setting x25 crud\n"); - ENDDEBUG - - bcopy(data, (caddr_t)isop->isop_x25crud, (unsigned)data_len); - isop->isop_x25crud_len = data_len; - break; -#endif /* TPCONS */ - - default: - error = EOPNOTSUPP; - } - if (cmd == PRCO_SETOPT) - m_freem(m); - return error; -} -#endif /* ISO */ - -#ifdef ARGO_DEBUG - -/* - * FUNCTION: dump_isoaddr - * - * PURPOSE: debugging - * - * RETURNS: nada - * - */ -dump_isoaddr(s) - struct sockaddr_iso *s; -{ - char *clnp_saddr_isop(); - register int i; - - if( s->siso_family == AF_ISO) { - printf("ISO address: suffixlen %d, %s\n", - s->siso_tlen, clnp_saddr_isop(s)); - } else if( s->siso_family == AF_INET) { - /* hack */ - struct sockaddr_in *sin = (struct sockaddr_in *)s; - - printf("%d.%d.%d.%d: %d", - (sin->sin_addr.s_addr>>24)&0xff, - (sin->sin_addr.s_addr>>16)&0xff, - (sin->sin_addr.s_addr>>8)&0xff, - (sin->sin_addr.s_addr)&0xff, - sin->sin_port); - } -} - -#endif /* ARGO_DEBUG */ diff --git a/bsd/netiso/iso.h b/bsd/netiso/iso.h deleted file mode 100644 index a1bd2d16b..000000000 --- a/bsd/netiso/iso.h +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)iso.h 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ - -#ifndef __ISO__ -#define __ISO__ - -/* - * Return true if this is a multicast address - * This assumes that the bit transmission is lsb first. This - * assumption is valid for 802.3 but not 802.5. There is a - * kludge to get around this for 802.5 -- see if_lan.c - * where subnetwork header is setup. - */ -#define IS_MULTICAST(snpa)\ - ((snpa)[0] & 0x01) - -/* - * Protocols - */ -#define ISOPROTO_TCP 6 /* IETF experiment */ -#define ISOPROTO_UDP 17 /* IETF experiment */ -#define ISOPROTO_TP0 25 /* connection oriented transport protocol */ -#define ISOPROTO_TP1 26 /* not implemented */ -#define ISOPROTO_TP2 27 /* not implemented */ -#define ISOPROTO_TP3 28 /* not implemented */ -#define ISOPROTO_TP4 29 /* connection oriented transport protocol */ -#define ISOPROTO_TP ISOPROTO_TP4 /* tp-4 with negotiation */ -#define ISOPROTO_CLTP 30 /* connectionless transport (not yet impl.) */ -#define ISOPROTO_CLNP 31 /* connectionless internetworking protocol */ -#define ISOPROTO_X25 32 /* cons */ -#define ISOPROTO_INACT_NL 33 /* inactive network layer! */ -#define ISOPROTO_ESIS 34 /* ES-IS protocol */ -#define ISOPROTO_INTRAISIS 35 /* IS-IS protocol */ -#define ISOPROTO_IDRP 36 /* Interdomain Routing Protocol */ - -#define ISOPROTO_RAW 255 /* raw clnp */ -#define ISOPROTO_MAX 256 - -#define ISO_PORT_RESERVED 1024 -#define ISO_PORT_USERRESERVED 5000 -/* - * Port/socket numbers: standard network functions - * NOT PRESENTLY USED - */ -#define ISO_PORT_MAINT 501 -#define ISO_PORT_ECHO 507 -#define ISO_PORT_DISCARD 509 -#define ISO_PORT_SYSTAT 511 -#define ISO_PORT_NETSTAT 515 -/* - * Port/socket numbers: non-standard application functions - */ -#define ISO_PORT_LOGIN 513 -/* - * Port/socket numbers: public use - */ -#define ISO_PORT_PUBLIC 1024 /* high bit set --> public */ - -/* - * Network layer protocol identifiers - */ -#define ISO8473_CLNP 0x81 -#define ISO9542_ESIS 0x82 -#define ISO9542X25_ESIS 0x8a -#define ISO10589_ISIS 0x83 -#define ISO8878A_CONS 0x84 -#define ISO10747_IDRP 0x85 - - -#ifndef IN_CLASSA_NET -#include -#endif /* IN_CLASSA_NET */ - - - -/* The following looks like a sockaddr - * to facilitate using tree lookup routines */ -struct iso_addr { - u_char isoa_len; /* length (in bytes) */ - char isoa_genaddr[20]; /* general opaque address */ -}; - -struct sockaddr_iso { - u_char siso_len; /* length */ - u_char siso_family; /* family */ - u_char siso_plen; /* presentation selector length */ - u_char siso_slen; /* session selector length */ - u_char siso_tlen; /* transport selector length */ - struct iso_addr siso_addr; /* network address */ - u_char siso_pad[6]; /* space for gosip v2 sels */ - /* makes struct 32 bytes long */ -}; -#define siso_nlen siso_addr.isoa_len -#define siso_data siso_addr.isoa_genaddr - -#define TSEL(s) ((caddr_t)((s)->siso_data + (s)->siso_nlen)) - -#define SAME_ISOADDR(a, b) \ - (bcmp((a)->siso_data, (b)->siso_data, (unsigned)(a)->siso_nlen)==0) -/* - * The following are specific values for siso->siso_data[0], - * otherwise known as the AFI: - */ -#define AFI_37 0x37 /* bcd of "37" */ -#define AFI_OSINET 0x47 /* bcd of "47" */ -#define AFI_RFC986 0x47 /* bcd of "47" */ -#define AFI_SNA 0x00 /* SubNetwork Address; invalid really...*/ - -#ifdef KERNEL - -extern int iso_netmatch(); -extern int iso_hash(); -extern int iso_addrmatch(); -extern struct iso_ifaddr *iso_iaonnetof(); -extern struct domain isodomain; -extern struct protosw isosw[]; - -#else -/* user utilities definitions from the iso library */ - -#include - -__BEGIN_DECLS -struct iso_addr *iso_addr __P((const char *)); -char *iso_ntoa __P((const struct iso_addr *)); - -/* THESE DON'T EXIST YET */ -struct hostent *iso_gethostbyname(), *iso_gethostbyaddr(); -__END_DECLS - -#endif /* KERNEL */ - -#define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m)) -#endif /* __ISO__ */ diff --git a/bsd/netiso/iso_chksum.c b/bsd/netiso/iso_chksum.c deleted file mode 100644 index ab0ac9e65..000000000 --- a/bsd/netiso/iso_chksum.c +++ /dev/null @@ -1,379 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)iso_chksum.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * ISO CHECKSUM - * - * The checksum generation and check routines are here. - * The checksum is 2 bytes such that the sum of all the bytes b(i) == 0 - * and the sum of i * b(i) == 0. - * The whole thing is complicated by the fact that the data are in mbuf - * chains. - * Furthermore, there is the possibility of wraparound in the running - * sums after adding up 4102 octets. In order to avoid doing a mod - * operation after EACH add, we have restricted this implementation to - * negotiating a maximum of 4096-octets per TPDU (for the transport layer). - * The routine iso_check_csum doesn't need to know where the checksum - * octets are. - * The routine iso_gen_csum takes a pointer to an mbuf chain (logically - * a chunk of data), an offset into the chunk at which the 2 octets are to - * be stuffed, and the length of the chunk. The 2 octets have to be - * logically adjacent, but may be physically located in separate mbufs. - */ - -#include -#include - -#if ISO -#include -#include -#endif /* ISO */ - -#ifndef MNULL -#define MNULL (struct mbuf *)0 -#endif /* MNULL */ - -/* - * FUNCTION: iso_check_csum - * - * PURPOSE: To check the checksum of the packet in the mbuf chain (m). - * The total length of the packet is (len). - * Called from tp_input() and clnp_intr() - * - * RETURNS: TRUE (something non-zero) if there is a checksum error, - * FALSE if there was NO checksum error. - * - * SIDE EFFECTS: none - * - * NOTES: It might be possible to gain something by optimizing - * this routine (unrolling loops, etc). But it is such - * a horrible thing to fiddle with anyway, it probably - * isn't worth it. - */ -int -iso_check_csum(m, len) - struct mbuf *m; - int len; -{ - register u_char *p = mtod(m, u_char *); - register u_long c0=0, c1=0; - register int i=0; - int cume = 0; /* cumulative length */ - int l; - - l = len; - len = min(m->m_len, len); - i = 0; - - IFDEBUG(D_CHKSUM) - printf("iso_check_csum: m x%x, l x%x, m->m_len x%x\n", m, l, m->m_len); - ENDDEBUG - - while( im_next; - IFDEBUG(D_CHKSUM) - printf("iso_check_csum: new mbuf\n"); - if(l-i < m->m_len) - printf( - "bad mbuf chain in check csum l 0x%x i 0x%x m_data 0x%x", - l,i,m->m_data); - ENDDEBUG - ASSERT( m != MNULL); - len = min( m->m_len, l-i); - p = mtod(m, u_char *); - } - } - if ( ((int)c0 % 255) || ((int)c1 % 255) ) { - IFDEBUG(D_CHKSUM) - printf("BAD iso_check_csum l 0x%x cume 0x%x len 0x%x, i 0x%x", - l, cume, len, i); - ENDDEBUG - return ((int)c0 % 255)<<8 | ((int)c1 % 255); - } - return 0; -} - -/* - * FUNCTION: iso_gen_csum - * - * PURPOSE: To generate the checksum of the packet in the mbuf chain (m). - * The first of the 2 (logically) adjacent checksum bytes - * (x and y) go at offset (n). - * (n) is an offset relative to the beginning of the data, - * not the beginning of the mbuf. - * (l) is the length of the total mbuf chain's data. - * Called from tp_emit(), tp_error_emit() - * clnp_emit_er(), clnp_forward(), clnp_output(). - * - * RETURNS: Rien - * - * SIDE EFFECTS: Puts the 2 checksum bytes into the packet. - * - * NOTES: Ditto the note for iso_check_csum(). - */ - -void -iso_gen_csum(m,n,l) - struct mbuf *m; - int n; /* offset of 2 checksum bytes */ - int l; -{ - register u_char *p = mtod(m, u_char *); - register int c0=0, c1=0; - register int i=0; - int loc = n++, len=0; /* n is position, loc is offset */ - u_char *xloc; - u_char *yloc; - int cume=0; /* cume == cumulative length */ - - IFDEBUG(D_CHKSUM) - printf("enter gen csum m 0x%x n 0x%x l 0x%x\n",m, n-1 ,l ); - ENDDEBUG - - while(i < l) { - len = min(m->m_len, CLBYTES); - /* RAH: don't cksum more than l bytes */ - len = min(len, l - i); - - cume +=len; - p = mtod(m, u_char *); - - if(loc>=0) { - if (loc < len) { - xloc = loc + mtod(m, u_char *); - IFDEBUG(D_CHKSUM) - printf("1: zeroing xloc 0x%x loc 0x%x\n",xloc, loc ); - ENDDEBUG - *xloc = (u_char)0; - if (loc+1 < len) { - /* both xloc and yloc are in same mbuf */ - yloc = 1 + xloc; - IFDEBUG(D_CHKSUM) - printf("2: zeroing yloc 0x%x loc 0x%x\n",yloc, loc ); - ENDDEBUG - *yloc = (u_char)0; - } else { - /* crosses boundary of mbufs */ - yloc = mtod(m->m_next, u_char *); - IFDEBUG(D_CHKSUM) - printf("3: zeroing yloc 0x%x \n",yloc ); - ENDDEBUG - *yloc = (u_char)0; - } - } - loc -= len; - } - - while(i < cume) { - c0 = (c0 + *p); - c1 += c0 ; - i++; - p++; - } - m = m->m_next; - } - IFDEBUG(D_CHKSUM) - printf("gen csum final xloc 0x%x yloc 0x%x\n",xloc, yloc ); - ENDDEBUG - - c1 = (((c0 * (l-n))-c1)%255) ; - *xloc = (u_char) ((c1 < 0)? c1+255 : c1); - - c1 = (-(int)(c1+c0))%255; - *yloc = (u_char) (c1 < 0? c1 + 255 : c1); - - IFDEBUG(D_CHKSUM) - printf("gen csum end \n"); - ENDDEBUG -} - -/* - * FUNCTION: m_datalen - * - * PURPOSE: returns length of the mbuf chain. - * used all over the iso code. - * - * RETURNS: integer - * - * SIDE EFFECTS: none - * - * NOTES: - */ - -int -m_datalen (m) - register struct mbuf *m; -{ - register int datalen; - - for (datalen = 0; m; m = m->m_next) - datalen += m->m_len; - return datalen; -} - -int -m_compress(in, out) - register struct mbuf *in, **out; -{ - register int datalen = 0; - int s = splimp(); - - if( in->m_next == MNULL ) { - *out = in; - IFDEBUG(D_REQUEST) - printf("m_compress returning 0x%x: A\n", in->m_len); - ENDDEBUG - splx(s); - return in->m_len; - } - MGET((*out), M_DONTWAIT, MT_DATA); - if((*out) == MNULL) { - *out = in; - IFDEBUG(D_REQUEST) - printf("m_compress returning -1: B\n"); - ENDDEBUG - splx(s); - return -1; - } - (*out)->m_len = 0; - (*out)->m_act = MNULL; - - while (in) { - IFDEBUG(D_REQUEST) - printf("m_compress in 0x%x *out 0x%x\n", in, *out); - printf("m_compress in: len 0x%x, off 0x%x\n", in->m_len, in->m_data); - printf("m_compress *out: len 0x%x, off 0x%x\n", (*out)->m_len, - (*out)->m_data); - ENDDEBUG - if (in->m_flags & M_EXT) { - ASSERT(in->m_len == 0); - } - if ( in->m_len == 0) { - in = in->m_next; - continue; - } - if (((*out)->m_flags & M_EXT) == 0) { - int len; - - len = M_TRAILINGSPACE(*out); - len = min(len, in->m_len); - datalen += len; - - IFDEBUG(D_REQUEST) - printf("m_compress copying len %d\n", len); - ENDDEBUG - bcopy(mtod(in, caddr_t), mtod((*out), caddr_t) + (*out)->m_len, - (unsigned)len); - - (*out)->m_len += len; - in->m_len -= len; - continue; - } else { - /* (*out) is full */ - if(( (*out)->m_next = m_get(M_DONTWAIT, MT_DATA) ) == MNULL) { - m_freem(*out); - *out = in; - IFDEBUG(D_REQUEST) - printf("m_compress returning -1: B\n"); - ENDDEBUG - splx(s); - return -1; - } - (*out)->m_len = 0; - (*out)->m_act = MNULL; - *out = (*out)->m_next; - } - } - m_freem(in); - IFDEBUG(D_REQUEST) - printf("m_compress returning 0x%x: A\n", datalen); - ENDDEBUG - splx(s); - return datalen; -} diff --git a/bsd/netiso/iso_errno.h b/bsd/netiso/iso_errno.h deleted file mode 100644 index ed1efb45c..000000000 --- a/bsd/netiso/iso_errno.h +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)iso_errno.h 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ - -#ifndef __ISO_ERRNO__ -#define __ISO_ERRNO__ - -#define ISO_ERROR_MASK 0x8000 -#define BSD_ERROR_MASK 0x0000 -#define TP_ERROR_MASK 0x8800 /* transport layer */ -#define CONL_ERROR_MASK 0x8400 /* co network layer */ -#define CLNL_ERROR_MASK 0x8200 /* cl network layer */ -#define TP_ERROR_SNDC 0x10000 /* kludge to force DC's on certain errors */ - -#define E_CO_NOERROR (CONL_ERROR_MASK | 0x0) /* no add'l info */ - -/******************************************************************************/ -/* */ -/* */ -/* Transport Layer */ -/* */ -/* */ -/******************************************************************************/ - -#define E_TP_DR_NO_REAS (TP_ERROR_MASK | 0x0) /* dr reason not specified*/ -#define E_TP_CONGEST (TP_ERROR_MASK | 0x1) /* dr reason congestion */ -#define E_TP_NO_SESSION (TP_ERROR_MASK | 0x2) /* dr reason no sess ent */ -#define E_TP_ADDR_UNK (TP_ERROR_MASK | 0x3) /* dr reason addr unknown */ - -#define E_TP_ER_NO_REAS (TP_ERROR_MASK | 0x40) /* er reas not specified */ -#define E_TP_INV_PCODE (TP_ERROR_MASK | 0x41) /* er reas invalid parm code */ -#define E_TP_INV_TPDU (TP_ERROR_MASK | 0x42) /* er reas invalid tpdu type */ -#define E_TP_INV_PVAL (TP_ERROR_MASK | 0x43) /* er reas invalid parm value*/ - -#define E_TP_NORMAL_DISC (TP_ERROR_MASK | 0x80) /* dr reas normal disc */ -#define E_TP_CONGEST_2 (TP_ERROR_MASK | 0x81) /* dr reason congestion */ -#define E_TP_NEGOT_FAILED (TP_ERROR_MASK | 0x82) /* dr negotiation failed */ -#define E_TP_DUPL_SRCREF (TP_ERROR_MASK | 0x83) /* dr duplicate src ref */ -#define E_TP_MISM_REFS (TP_ERROR_MASK | 0x84) /* dr mismatched references*/ -#define E_TP_PROTO_ERR (TP_ERROR_MASK | 0x85) /* dr protocol error*/ -/* 0x86 not used */ -#define E_TP_REF_OVERFLOW (TP_ERROR_MASK | 0x87) /* dr reference overflow */ -#define E_TP_NO_CR_ON_NC (TP_ERROR_MASK | 0x88) /* dr cr refused on this nc */ -/* 0x89 not used */ -#define E_TP_LENGTH_INVAL (TP_ERROR_MASK | 0x8a) /* dr inval length in hdr*/ - -/******************************************************************************/ -/* */ -/* */ -/* Connection Less Network Layer */ -/* */ -/* */ -/******************************************************************************/ -#ifdef notdef /* Doesn't look like legal C and is causing - * compiler problems */ -#define E_CLNL_??? (CLNL_ERROR_MASK | 0x1) /* explanation */ -#endif - -/******************************************************************************/ -/* */ -/* */ -/* Connection Oriented Network Layer */ -/* */ -/* */ -/******************************************************************************/ - /* see p. 149 of ISO 8208 */ -#define E_CO_NOERROR (CONL_ERROR_MASK | 0x0) /* no add'l info */ -#define E_CO_INV_PS (CONL_ERROR_MASK | 0x1) /* invalid p(s) */ -#define E_CO_INV_PR (CONL_ERROR_MASK | 0x2) /* invalid p(r) */ - /* dot dot dot */ -#define E_CO_INV_PKT_TYPE (CONL_ERROR_MASK | 0x10) /* packet type invalid*/ -#define E_CO_INV_PKT_R1 (CONL_ERROR_MASK | 0x11) /* for state r1 */ -#define E_CO_INV_PKT_R2 (CONL_ERROR_MASK | 0x12) /* for state r2 */ -#define E_CO_INV_PKT_R3 (CONL_ERROR_MASK | 0x13) /* for state r3 */ -#define E_CO_INV_PKT_P1 (CONL_ERROR_MASK | 0x14) /* for state p1 */ -#define E_CO_INV_PKT_P2 (CONL_ERROR_MASK | 0x15) /* for state p2 */ -#define E_CO_INV_PKT_P3 (CONL_ERROR_MASK | 0x16) /* for state p3 */ -#define E_CO_INV_PKT_P4 (CONL_ERROR_MASK | 0x17) /* for state p4 */ -#define E_CO_INV_PKT_P5 (CONL_ERROR_MASK | 0x18) /* for state p5 */ -#define E_CO_INV_PKT_P6 (CONL_ERROR_MASK | 0x19) /* for state p6 */ -#define E_CO_INV_PKT_P7 (CONL_ERROR_MASK | 0x1a) /* for state p7 */ -#define E_CO_INV_PKT_D1 (CONL_ERROR_MASK | 0x1b) /* for state d1 */ -#define E_CO_INV_PKT_D2 (CONL_ERROR_MASK | 0x1c) /* for state d2 */ -#define E_CO_INV_PKT_D3 (CONL_ERROR_MASK | 0x1d) /* for state d3 */ - /* dot dot dot */ -#define E_CO_PKT_NOT_ALWD (CONL_ERROR_MASK | 0x20) /* packet not allowed */ -#define E_CO_PNA_UNIDENT (CONL_ERROR_MASK | 0x21) /* unidentifiable pkt */ -#define E_CO_PNA_ONEWAY (CONL_ERROR_MASK | 0x22) /* call on 1-way lc */ -#define E_CO_PNA_PVC (CONL_ERROR_MASK | 0x23) /* inv pkt type on a pvc */ -#define E_CO_PNA_UNASSLC (CONL_ERROR_MASK | 0x24) /* pkt on unassigned lc */ -#define E_CO_PNA_REJECT (CONL_ERROR_MASK | 0x25) /* REJ not subscribed to*/ -#define E_CO_PNA_SHORT (CONL_ERROR_MASK | 0x26) /* pkt too short */ -#define E_CO_PNA_LONG (CONL_ERROR_MASK | 0x27) /* pkt too long */ -#define E_CO_PNA_INVGFI (CONL_ERROR_MASK | 0x28) /* inv gen format id */ -#define E_CO_PNA_NZLCI (CONL_ERROR_MASK | 0x29) \ - /* restart or reg pkt with nonzero logical channel identifier */ -#define E_CO_PNA_FACIL (CONL_ERROR_MASK | 0x2a) \ - /* pkt type not compat with facility */ -#define E_CO_PNA_UINTCON (CONL_ERROR_MASK | 0x2b) /* unauthor intrpt conf */ -#define E_CO_PNA_UINTRPT (CONL_ERROR_MASK | 0x2c) /* unauthorized intrpt */ -#define E_CO_PNA_UREJECT (CONL_ERROR_MASK | 0x2d) /* unauthorized reject */ - -#define E_CO_TMR_EXP (CONL_ERROR_MASK | 0x30) /* timer expired */ -#define E_CO_TMR_CALR (CONL_ERROR_MASK | 0x31) /* inc. call or call req */ -#define E_CO_TMR_CLRI (CONL_ERROR_MASK | 0x32) /* clear indication */ -#define E_CO_TMR_RSTI (CONL_ERROR_MASK | 0x33) /* reset indication */ -#define E_CO_TMR_RRTI (CONL_ERROR_MASK | 0x34) /* restart indication */ - -#define E_CO_REG_PROB (CONL_ERROR_MASK | 0x40)\ - /* call setup, clear, or registration problem */ -#define E_CO_REG_CODE (CONL_ERROR_MASK | 0x41) /* code not allowed */ -#define E_CO_REG_PARM (CONL_ERROR_MASK | 0x42) /* parameter not allowed */ -#define E_CO_REG_ICDA (CONL_ERROR_MASK | 0x43) /* invalid called addr */ -#define E_CO_REG_ICGA (CONL_ERROR_MASK | 0x44) /* invalid calling addr */ -#define E_CO_REG_ILEN (CONL_ERROR_MASK | 0x45) /* invalid facil length */ -#define E_CO_REG_IBAR (CONL_ERROR_MASK | 0x46) /* incoming call barred */ -#define E_CO_REG_NOLC (CONL_ERROR_MASK | 0x47) /* no logical chan avail*/ -#define E_CO_REG_COLL (CONL_ERROR_MASK | 0x48) /* call collision */ -#define E_CO_REG_DUPF (CONL_ERROR_MASK | 0x49) /* dupl facil requested */ -#define E_CO_REG_NZAL (CONL_ERROR_MASK | 0x4a) /* non-zero addr length */ -#define E_CO_REG_NZFL (CONL_ERROR_MASK | 0x4b) /* non-zero facil length */ -#define E_CO_REG_EFNP (CONL_ERROR_MASK | 0x4c) \ - /* expected facil not provided */ -#define E_CO_REG_ICCITT (CONL_ERROR_MASK | 0x4d) \ - /* invalid CCITT-specified DTE facil */ - -#define E_CO_MISC (CONL_ERROR_MASK | 0x50) /* miscellaneous */ -#define E_CO_MISC_CAUSE (CONL_ERROR_MASK | 0x51) /* improper cause code */ -#define E_CO_MISC_ALIGN (CONL_ERROR_MASK | 0x52) /* not octet-aligned */ -#define E_CO_MISC_IQBS (CONL_ERROR_MASK | 0x53) \ - /* inconsistent Q bit settings */ - -#define E_CO_INTL (CONL_ERROR_MASK | 0x70) /* international problem */ -#define E_CO_IREMNWK (CONL_ERROR_MASK | 0x71) /* remote network problem */ -#define E_CO_INPROTO (CONL_ERROR_MASK | 0x72) /* int'l protocol problem */ -#define E_CO_ILINKDWN (CONL_ERROR_MASK | 0x73) /* int'l link down */ -#define E_CO_ILINKBSY (CONL_ERROR_MASK | 0x74) /* int'l link busy */ -#define E_CO_IXNETFAC (CONL_ERROR_MASK | 0x75) /* transit netwk facil */ -#define E_CO_IRNETFAC (CONL_ERROR_MASK | 0x76) /* remote netwk facil */ -#define E_CO_IROUTING (CONL_ERROR_MASK | 0x77) /* int'l routing prob */ -#define E_CO_ITMPRTG (CONL_ERROR_MASK | 0x78) /* temporary routing prob */ -#define E_CO_IUNKDNIC (CONL_ERROR_MASK | 0x79) /* unknown called DNIC */ -#define E_CO_IMAINT (CONL_ERROR_MASK | 0x7a) /* maintenance action */ - -#define E_CO_TIMO (CONL_ERROR_MASK | 0x90) \ - /* timer expired or retransmission count surpassed */ -#define E_CO_TIM_INTRP (CONL_ERROR_MASK | 0x91) /* for interrupt */ -#define E_CO_TIM_DATA (CONL_ERROR_MASK | 0x92) /* for data */ -#define E_CO_TIM_REJ (CONL_ERROR_MASK | 0x93) /* for reject */ - -#define E_CO_DTE_SPEC (CONL_ERROR_MASK | 0xa0) /* DTE-specific */ -#define E_CO_DTE_OK (CONL_ERROR_MASK | 0xa1) /* DTE operational */ -#define E_CO_DTE_NOK (CONL_ERROR_MASK | 0xa2) /* DTE not operational */ -#define E_CO_DTE_RSRC (CONL_ERROR_MASK | 0xa3) /* DTE resource constraint*/ -#define E_CO_DTE_FSLCT (CONL_ERROR_MASK | 0xa4) /* fast select not subsc */ -#define E_CO_DTE_PFPKT (CONL_ERROR_MASK | 0xa5) /* partially full pkt */ -#define E_CO_DTE_DBIT (CONL_ERROR_MASK | 0xa6) /* D-bit proc not supp */ -#define E_CO_DTE_RCCON (CONL_ERROR_MASK | 0xa7) /* reg/canell confirmed */ - -#define E_CO_OSI_NSP (CONL_ERROR_MASK | 0xe0) /* OSI net svc problem */ -#define E_CO_OSI_DISCT (CONL_ERROR_MASK | 0xe1) /* disconnect transient */ -#define E_CO_OSI_DISCP (CONL_ERROR_MASK | 0xe2) /* disconnect permanent */ -#define E_CO_OSI_REJT (CONL_ERROR_MASK | 0xe3) /* reject transient */ -#define E_CO_OSI_REJP (CONL_ERROR_MASK | 0xe4) /* reject permanent */ -#define E_CO_OSI_QOST (CONL_ERROR_MASK | 0xe5) /* reject QOS transient */ -#define E_CO_OSI_QOSP (CONL_ERROR_MASK | 0xe6) /* reject QOS permanent */ -#define E_CO_OSI_NSAPT (CONL_ERROR_MASK | 0xe7) /* NSAP unreach transient */ -#define E_CO_OSI_NSAPP (CONL_ERROR_MASK | 0xe8) /* NSAP unreach permanent */ -#define E_CO_OSI_RESET (CONL_ERROR_MASK | 0xe9) /* reset no reason */ -#define E_CO_OSI_CONGEST (CONL_ERROR_MASK | 0xea) /* reset congestion */ -#define E_CO_OSI_UNSAP (CONL_ERROR_MASK | 0xeb) /* unknown NSAP permanent */ - -#define E_CO_HLI_INIT (CONL_ERROR_MASK | 0xf0) /* higher level initiated*/ -#define E_CO_HLI_DISCN (CONL_ERROR_MASK | 0xf1) /* disconnect normal */ -#define E_CO_HLI_DISCA (CONL_ERROR_MASK | 0xf2) /* disconnect abnormal */ -#define E_CO_HLI_DISCI (CONL_ERROR_MASK | 0xf3) /* disconnect incompatible*/ -#define E_CO_HLI_REJT (CONL_ERROR_MASK | 0xf4) /* reject transient */ -#define E_CO_HLI_REJP (CONL_ERROR_MASK | 0xf5) /* reject permanent */ -#define E_CO_HLI_QOST (CONL_ERROR_MASK | 0xf6) /* reject QOS transient */ -#define E_CO_HLI_QOSP (CONL_ERROR_MASK | 0xf7) /* reject QOS permanent */ -#define E_CO_HLI_REJI (CONL_ERROR_MASK | 0xf8) /* reject incompatible */ -#define E_CO_HLI_PROTOID (CONL_ERROR_MASK | 0xf9) /* unrecog proto id */ -#define E_CO_HLI_RESYNC (CONL_ERROR_MASK | 0xfa) /* reset - user resync */ - -/* Cause on 8208 CLEAR field */ -#define E_CO_NUMBERBUSY (CONL_ERROR_MASK | 0x101) /* Number busy */ -#define E_CO_INVFACREQ (CONL_ERROR_MASK | 0x103) /* invalid facil req */ -#define E_CO_NETCONGEST (CONL_ERROR_MASK | 0x105) /* Network congestion */ -#define E_CO_OUTOFORDER (CONL_ERROR_MASK | 0x109) /* Out of order */ -#define E_CO_ACCESSBAR (CONL_ERROR_MASK | 0x10b) /* access barred */ -#define E_CO_NOTOBTAIN (CONL_ERROR_MASK | 0x10d) /* not obtainable */ -#define E_CO_REMPROCERR (CONL_ERROR_MASK | 0x111) /* Remote procedure err */ -#define E_CO_LOCPROCERR (CONL_ERROR_MASK | 0x113) /* Local procedure err */ -#define E_CO_RPOAOOO (CONL_ERROR_MASK | 0x115) /* RPOA out of order */ -#define E_CO_NOREVCHG (CONL_ERROR_MASK | 0x119) /* Revs chg not accepted*/ -#define E_CO_INCOMPAT (CONL_ERROR_MASK | 0x121) /* Incompatible dest */ -#define E_CO_NOFASTSEL (CONL_ERROR_MASK | 0x129) - /* Fast select accpt not subscribed */ -#define E_CO_NOSHIP (CONL_ERROR_MASK | 0x139) /* ship absent */ -#define E_CO_GWPROCERR (CONL_ERROR_MASK | 0x1c1) /* Gateway-detected err*/ -#define E_CO_GWCONGEST (CONL_ERROR_MASK | 0x1c3) /* Gateway congestion*/ - -/* ARGO only */ -#define E_CO_QFULL (CONL_ERROR_MASK | 0x100) /* dropped packet - queue full*/ -#define E_CO_AIWP (CONL_ERROR_MASK | 0x102) /* addr incompat w/proto */ -#define E_CO_CHAN (CONL_ERROR_MASK | 0x104) /* bad channel number */ - -/* ARGO only; driver specific */ -#define E_CO_NORESOURCES (CONL_ERROR_MASK | 0x1b0) /* eicon clogged */ -#define E_CO_PDNDOWN (CONL_ERROR_MASK | 0x1b1) /* physical net down */ -#define E_CO_DRVRCLRESET (CONL_ERROR_MASK | 0x1b2) /* driver clear/reset */ -#define E_CO_PDNCLRESET (CONL_ERROR_MASK | 0x1b3) /* PDN clear/reset */ -#define E_CO_DTECLRESET (CONL_ERROR_MASK | 0x1b4) /* board clear/reset */ -#define E_CO_UNKCLRESET (CONL_ERROR_MASK | 0x1b5) /* unexpected clr/rst */ - -#define CONL_ERROR_MAX 0x1c3 - -#endif /* __ISO_ERRNO__ */ diff --git a/bsd/netiso/iso_pcb.c b/bsd/netiso/iso_pcb.c deleted file mode 100644 index defe1658e..000000000 --- a/bsd/netiso/iso_pcb.c +++ /dev/null @@ -1,635 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)iso_pcb.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * Iso address family net-layer(s) pcb stuff. NEH 1/29/87 - */ - -#if ISO - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if TPCONS -#include -#include -#include -#endif - -#define PCBNULL (struct isopcb *)0 -struct iso_addr zeroiso_addr = { - 0 -}; - - -/* - * FUNCTION: iso_pcballoc - * - * PURPOSE: creates an isopcb structure in an mbuf, - * with socket (so), and - * puts it in the queue with head (head) - * - * RETURNS: 0 if OK, ENOBUFS if can't alloc the necessary mbuf - */ -int -iso_pcballoc(so, head) - struct socket *so; - struct isopcb *head; -{ - register struct isopcb *isop; - - IFDEBUG(D_ISO) - printf("iso_pcballoc(so 0x%x)\n", so); - ENDDEBUG - MALLOC(isop, struct isopcb *, sizeof(*isop), M_PCB, M_NOWAIT); - if (isop == NULL) - return ENOBUFS; - bzero((caddr_t)isop, sizeof(*isop)); - isop->isop_head = head; - isop->isop_socket = so; - insque(isop, head); - if (so) - so->so_pcb = (caddr_t)isop; - return 0; -} - -/* - * FUNCTION: iso_pcbbind - * - * PURPOSE: binds the address given in *(nam) to the socket - * specified by the isopcb in *(isop) - * If the given address is zero, it makes sure the - * address isn't already in use and if it's got a network - * portion, we look for an interface with that network - * address. If the address given is zero, we allocate - * a port and stuff it in the (nam) structure. - * - * RETURNS: errno E* or 0 if ok. - * - * SIDE EFFECTS: increments head->isop_lport if it allocates a port # - * - * NOTES: - */ -#define satosiso(sa) ((struct sockaddr_iso *)(sa)) -int -iso_pcbbind(isop, nam) - register struct isopcb *isop; - struct mbuf *nam; -{ - register struct isopcb *head = isop->isop_head; - register struct sockaddr_iso *siso; - struct iso_ifaddr *ia; - union { - char data[2]; - u_short s; - } suf; - - IFDEBUG(D_ISO) - printf("iso_pcbbind(isop 0x%x, nam 0x%x)\n", isop, nam); - ENDDEBUG - suf.s = 0; - if (iso_ifaddr == 0) /* any interfaces attached? */ - return EADDRNOTAVAIL; - if (isop->isop_laddr) /* already bound */ - return EADDRINUSE; - if(nam == (struct mbuf *)0) { - isop->isop_laddr = &isop->isop_sladdr; - isop->isop_sladdr.siso_len = sizeof(struct sockaddr_iso); - isop->isop_sladdr.siso_family = AF_ISO; - isop->isop_sladdr.siso_tlen = 2; - isop->isop_sladdr.siso_nlen = 0; - isop->isop_sladdr.siso_slen = 0; - isop->isop_sladdr.siso_plen = 0; - goto noname; - } - siso = mtod(nam, struct sockaddr_iso *); - IFDEBUG(D_ISO) - printf("iso_pcbbind(name len 0x%x)\n", nam->m_len); - printf("The address is %s\n", clnp_iso_addrp(&siso->siso_addr)); - ENDDEBUG - /* - * We would like sort of length check but since some OSI addrs - * do not have fixed length, we can't really do much. - * The ONLY thing we can say is that an osi addr has to have - * at LEAST an afi and one more byte and had better fit into - * a struct iso_addr. - * However, in fact the size of the whole thing is a struct - * sockaddr_iso, so probably this is what we should check for. - */ - if( (nam->m_len < 2) || (nam->m_len < siso->siso_len)) { - return ENAMETOOLONG; - } - if (siso->siso_nlen) { - /* non-zero net addr- better match one of our interfaces */ - IFDEBUG(D_ISO) - printf("iso_pcbbind: bind to NOT zeroisoaddr\n"); - ENDDEBUG - for (ia = iso_ifaddr; ia; ia = ia->ia_next) - if (SAME_ISOADDR(siso, &ia->ia_addr)) - break; - if (ia == 0) - return EADDRNOTAVAIL; - } - if (siso->siso_len <= sizeof (isop->isop_sladdr)) { - isop->isop_laddr = &isop->isop_sladdr; - } else { - if ((nam = m_copy(nam, 0, (int)M_COPYALL)) == 0) - return ENOBUFS; - isop->isop_laddr = mtod(nam, struct sockaddr_iso *); - } - bcopy((caddr_t)siso, (caddr_t)isop->isop_laddr, siso->siso_len); - if (siso->siso_tlen == 0) - goto noname; - if ((isop->isop_socket->so_options & SO_REUSEADDR) == 0 && - iso_pcblookup(head, 0, (caddr_t)0, isop->isop_laddr)) - return EADDRINUSE; - if (siso->siso_tlen <= 2) { - bcopy(TSEL(siso), suf.data, sizeof(suf.data)); - suf.s = ntohs(suf.s); - if((suf.s < ISO_PORT_RESERVED) && - (isop->isop_socket->so_state && SS_PRIV) == 0) - return EACCES; - } else { - register char *cp; -noname: - cp = TSEL(isop->isop_laddr); - IFDEBUG(D_ISO) - printf("iso_pcbbind noname\n"); - ENDDEBUG - do { - if (head->isop_lport++ < ISO_PORT_RESERVED || - head->isop_lport > ISO_PORT_USERRESERVED) - head->isop_lport = ISO_PORT_RESERVED; - suf.s = htons(head->isop_lport); - cp[0] = suf.data[0]; - cp[1] = suf.data[1]; - } while (iso_pcblookup(head, 0, (caddr_t)0, isop->isop_laddr)); - } - IFDEBUG(D_ISO) - printf("iso_pcbbind returns 0, suf 0x%x\n", suf); - ENDDEBUG - return 0; -} -/* - * FUNCTION: iso_pcbconnect - * - * PURPOSE: Make the isopcb (isop) look like it's connected. - * In other words, give it the peer address given in - * the mbuf * (nam). Make sure such a combination - * of local, peer addresses doesn't already exist - * for this protocol. Internet mentality prevails here, - * wherein a src,dst pair uniquely identifies a connection. - * Both net address and port must be specified in argument - * (nam). - * If we don't have a local address for this socket yet, - * we pick one by calling iso_pcbbind(). - * - * RETURNS: errno E* or 0 if ok. - * - * SIDE EFFECTS: Looks up a route, which may cause one to be left - * in the isopcb. - * - * NOTES: - */ -int -iso_pcbconnect(isop, nam) - register struct isopcb *isop; - struct mbuf *nam; -{ - register struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *); - int local_zero, error = 0; - struct iso_ifaddr *ia; - - IFDEBUG(D_ISO) - printf("iso_pcbconnect(isop 0x%x sock 0x%x nam 0x%x", - isop, isop->isop_socket, nam); - printf("nam->m_len 0x%x), addr:\n", nam->m_len); - dump_isoaddr(siso); - ENDDEBUG - if (nam->m_len < siso->siso_len) - return EINVAL; - if (siso->siso_family != AF_ISO) - return EAFNOSUPPORT; - if (siso->siso_nlen == 0) { - if (ia = iso_ifaddr) { - int nlen = ia->ia_addr.siso_nlen; - ovbcopy(TSEL(siso), nlen + TSEL(siso), - siso->siso_plen + siso->siso_tlen + siso->siso_slen); - bcopy((caddr_t)&ia->ia_addr.siso_addr, - (caddr_t)&siso->siso_addr, nlen + 1); - /* includes siso->siso_nlen = nlen; */ - } else - return EADDRNOTAVAIL; - } - /* - * Local zero means either not bound, or bound to a TSEL, but no - * particular local interface. So, if we want to send somebody - * we need to choose a return address. - */ - local_zero = - ((isop->isop_laddr == 0) || (isop->isop_laddr->siso_nlen == 0)); - if (local_zero) { - int flags; - - IFDEBUG(D_ISO) - printf("iso_pcbconnect localzero 1\n"); - ENDDEBUG - /* - * If route is known or can be allocated now, - * our src addr is taken from the i/f, else punt. - */ - flags = isop->isop_socket->so_options & SO_DONTROUTE; - if (error = clnp_route(&siso->siso_addr, &isop->isop_route, flags, - (struct sockaddr **)0, &ia)) - return error; - IFDEBUG(D_ISO) - printf("iso_pcbconnect localzero 2, ro->ro_rt 0x%x", - isop->isop_route.ro_rt); - printf(" ia 0x%x\n", ia); - ENDDEBUG - } - IFDEBUG(D_ISO) - printf("in iso_pcbconnect before lookup isop 0x%x isop->sock 0x%x\n", - isop, isop->isop_socket); - ENDDEBUG - if (local_zero) { - int nlen, tlen, totlen; caddr_t oldtsel, newtsel; - siso = isop->isop_laddr; - if (siso == 0 || siso->siso_tlen == 0) - (void)iso_pcbbind(isop, (struct mbuf *)0); - /* - * Here we have problem of squezeing in a definite network address - * into an existing sockaddr_iso, which in fact may not have room - * for it. This gets messy. - */ - siso = isop->isop_laddr; - oldtsel = TSEL(siso); - tlen = siso->siso_tlen; - nlen = ia->ia_addr.siso_nlen; - totlen = tlen + nlen + _offsetof(struct sockaddr_iso, siso_data[0]); - if ((siso == &isop->isop_sladdr) && - (totlen > sizeof(isop->isop_sladdr))) { - struct mbuf *m = m_get(MT_SONAME, M_DONTWAIT); - if (m == 0) - return ENOBUFS; - m->m_len = totlen; - isop->isop_laddr = siso = mtod(m, struct sockaddr_iso *); - } - siso->siso_nlen = ia->ia_addr.siso_nlen; - newtsel = TSEL(siso); - ovbcopy(oldtsel, newtsel, tlen); - bcopy(ia->ia_addr.siso_data, siso->siso_data, nlen); - siso->siso_tlen = tlen; - siso->siso_family = AF_ISO; - siso->siso_len = totlen; - siso = mtod(nam, struct sockaddr_iso *); - } - IFDEBUG(D_ISO) - printf("in iso_pcbconnect before bcopy isop 0x%x isop->sock 0x%x\n", - isop, isop->isop_socket); - ENDDEBUG - /* - * If we had to allocate space to a previous big foreign address, - * and for some reason we didn't free it, we reuse it knowing - * that is going to be big enough, as sockaddrs are delivered in - * 128 byte mbufs. - * If the foreign address is small enough, we use default space; - * otherwise, we grab an mbuf to copy into. - */ - if (isop->isop_faddr == 0 || isop->isop_faddr == &isop->isop_sfaddr) { - if (siso->siso_len <= sizeof(isop->isop_sfaddr)) - isop->isop_faddr = &isop->isop_sfaddr; - else { - struct mbuf *m = m_get(MT_SONAME, M_DONTWAIT); - if (m == 0) - return ENOBUFS; - isop->isop_faddr = mtod(m, struct sockaddr_iso *); - } - } - bcopy((caddr_t)siso, (caddr_t)isop->isop_faddr, siso->siso_len); - IFDEBUG(D_ISO) - printf("in iso_pcbconnect after bcopy isop 0x%x isop->sock 0x%x\n", - isop, isop->isop_socket); - printf("iso_pcbconnect connected to addr:\n"); - dump_isoaddr(isop->isop_faddr); - printf("iso_pcbconnect end: src addr:\n"); - dump_isoaddr(isop->isop_laddr); - ENDDEBUG - return 0; -} - -/* - * FUNCTION: iso_pcbdisconnect() - * - * PURPOSE: washes away the peer address info so the socket - * appears to be disconnected. - * If there's no file descriptor associated with the socket - * it detaches the pcb. - * - * RETURNS: Nada. - * - * SIDE EFFECTS: May detach the pcb. - * - * NOTES: - */ -void -iso_pcbdisconnect(isop) - struct isopcb *isop; -{ - void iso_pcbdetach(); - register struct sockaddr_iso *siso; - - IFDEBUG(D_ISO) - printf("iso_pcbdisconnect(isop 0x%x)\n", isop); - ENDDEBUG - /* - * Preserver binding infnormation if already bound. - */ - if ((siso = isop->isop_laddr) && siso->siso_nlen && siso->siso_tlen) { - caddr_t otsel = TSEL(siso); - siso->siso_nlen = 0; - ovbcopy(otsel, TSEL(siso), siso->siso_tlen); - } - if (isop->isop_faddr && isop->isop_faddr != &isop->isop_sfaddr) - m_freem(dtom(isop->isop_faddr)); - isop->isop_faddr = 0; - if (isop->isop_socket->so_state & SS_NOFDREF) - iso_pcbdetach(isop); -} - -/* - * FUNCTION: iso_pcbdetach - * - * PURPOSE: detach the pcb at *(isop) from it's socket and free - * the mbufs associated with the pcb.. - * Dequeues (isop) from its head. - * - * RETURNS: Nada. - * - * SIDE EFFECTS: - * - * NOTES: - */ -void -iso_pcbdetach(isop) - struct isopcb *isop; -{ - struct socket *so = isop->isop_socket; - - IFDEBUG(D_ISO) - printf("iso_pcbdetach(isop 0x%x socket 0x%x so 0x%x)\n", - isop, isop->isop_socket, so); - ENDDEBUG -#if TPCONS - if (isop->isop_chan) { - register struct pklcd *lcp = (struct pklcd *)isop->isop_chan; - if (--isop->isop_refcnt > 0) - return; - if (lcp && lcp->lcd_state == DATA_TRANSFER) { - lcp->lcd_upper = 0; - lcp->lcd_upnext = 0; - pk_disconnect(lcp); - } - isop->isop_chan = 0; - } -#endif - if (so) { /* in the x.25 domain, we sometimes have no socket */ - so->so_pcb = 0; - sofree(so); - } - IFDEBUG(D_ISO) - printf("iso_pcbdetach 2 \n"); - ENDDEBUG - if (isop->isop_options) - (void)m_free(isop->isop_options); - IFDEBUG(D_ISO) - printf("iso_pcbdetach 3 \n"); - ENDDEBUG - if (isop->isop_route.ro_rt) - rtfree(isop->isop_route.ro_rt); - IFDEBUG(D_ISO) - printf("iso_pcbdetach 3.1\n"); - ENDDEBUG - if (isop->isop_clnpcache != NULL) { - struct clnp_cache *clcp = - mtod(isop->isop_clnpcache, struct clnp_cache *); - IFDEBUG(D_ISO) - printf("iso_pcbdetach 3.2: clcp 0x%x freeing clc_hdr x%x\n", - clcp, clcp->clc_hdr); - ENDDEBUG - if (clcp->clc_hdr != NULL) - m_free(clcp->clc_hdr); - IFDEBUG(D_ISO) - printf("iso_pcbdetach 3.3: freeing cache x%x\n", - isop->isop_clnpcache); - ENDDEBUG - m_free(isop->isop_clnpcache); - } - IFDEBUG(D_ISO) - printf("iso_pcbdetach 4 \n"); - ENDDEBUG - remque(isop); - IFDEBUG(D_ISO) - printf("iso_pcbdetach 5 \n"); - ENDDEBUG - if (isop->isop_laddr && (isop->isop_laddr != &isop->isop_sladdr)) - m_freem(dtom(isop->isop_laddr)); - FREE((caddr_t)isop, M_PCB); -} - - -/* - * FUNCTION: iso_pcbnotify - * - * PURPOSE: notify all connections in this protocol's queue (head) - * that have peer address (dst) of the problem (errno) - * by calling (notify) on the connections' isopcbs. - * - * RETURNS: Rien. - * - * SIDE EFFECTS: - * - * NOTES: (notify) is called at splimp! - */ -void -iso_pcbnotify(head, siso, errno, notify) - struct isopcb *head; - register struct sockaddr_iso *siso; - int errno, (*notify)(); -{ - register struct isopcb *isop; - int s = splimp(); - - IFDEBUG(D_ISO) - printf("iso_pcbnotify(head 0x%x, notify 0x%x) dst:\n", head, notify); - ENDDEBUG - for (isop = head->isop_next; isop != head; isop = isop->isop_next) { - if (isop->isop_socket == 0 || isop->isop_faddr == 0 || - !SAME_ISOADDR(siso, isop->isop_faddr)) { - IFDEBUG(D_ISO) - printf("iso_pcbnotify: CONTINUE isop 0x%x, sock 0x%x\n" , - isop, isop->isop_socket); - printf("addrmatch cmp'd with (0x%x):\n", isop->isop_faddr); - dump_isoaddr(isop->isop_faddr); - ENDDEBUG - continue; - } - if (errno) - isop->isop_socket->so_error = errno; - if (notify) - (*notify)(isop); - } - splx(s); - IFDEBUG(D_ISO) - printf("END OF iso_pcbnotify\n" ); - ENDDEBUG -} - - -/* - * FUNCTION: iso_pcblookup - * - * PURPOSE: looks for a given combination of (faddr), (fport), - * (lport), (laddr) in the queue named by (head). - * Argument (flags) is ignored. - * - * RETURNS: ptr to the isopcb if it finds a connection matching - * these arguments, o.w. returns zero. - * - * SIDE EFFECTS: - * - * NOTES: - */ -struct isopcb * -iso_pcblookup(head, fportlen, fport, laddr) - struct isopcb *head; - register struct sockaddr_iso *laddr; - caddr_t fport; - int fportlen; -{ - register struct isopcb *isop; - register caddr_t lp = TSEL(laddr); - unsigned int llen = laddr->siso_tlen; - - IFDEBUG(D_ISO) - printf("iso_pcblookup(head 0x%x laddr 0x%x fport 0x%x)\n", - head, laddr, fport); - ENDDEBUG - for (isop = head->isop_next; isop != head; isop = isop->isop_next) { - if (isop->isop_laddr == 0 || isop->isop_laddr == laddr) - continue; - if (isop->isop_laddr->siso_tlen != llen) - continue; - if (bcmp(lp, TSEL(isop->isop_laddr), llen)) - continue; - if (fportlen && isop->isop_faddr && - bcmp(fport, TSEL(isop->isop_faddr), (unsigned)fportlen)) - continue; - /* PHASE2 - * addrmatch1 should be iso_addrmatch(a, b, mask) - * where mask is taken from isop->isop_laddrmask (new field) - * isop_lnetmask will also be available in isop - if (laddr != &zeroiso_addr && - !iso_addrmatch1(laddr, &(isop->isop_laddr.siso_addr))) - continue; - */ - if (laddr->siso_nlen && (!SAME_ISOADDR(laddr, isop->isop_laddr))) - continue; - return (isop); - } - return (struct isopcb *)0; -} -#endif /* ISO */ diff --git a/bsd/netiso/iso_pcb.h b/bsd/netiso/iso_pcb.h deleted file mode 100644 index d5cf7d4e1..000000000 --- a/bsd/netiso/iso_pcb.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)iso_pcb.h 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ - -#define MAXX25CRUDLEN 16 /* 16 bytes of call request user data */ - -/* - * Common structure pcb for argo protocol implementation. - */ -struct isopcb { - struct isopcb *isop_next,*isop_prev; /* pointers to other pcb's */ - struct isopcb *isop_head; /* pointer back to chain of pcbs for - this protocol */ - struct socket *isop_socket; /* back pointer to socket */ - struct sockaddr_iso *isop_laddr; - struct sockaddr_iso *isop_faddr; - struct route_iso { - struct rtentry *ro_rt; - struct sockaddr_iso ro_dst; - } isop_route; /* CLNP routing entry */ - struct mbuf *isop_options; /* CLNP options */ - struct mbuf *isop_optindex; /* CLNP options index */ - struct mbuf *isop_clnpcache; /* CLNP cached hdr */ - caddr_t isop_chan; /* actually struct pklcb * */ - u_short isop_refcnt; /* mult TP4 tpcb's -> here */ - u_short isop_lport; /* MISLEADLING work var */ - u_short isop_tuba_cached; /* for tuba address ref cnts */ - int isop_x25crud_len; /* x25 call request ud */ - char isop_x25crud[MAXX25CRUDLEN]; - struct ifaddr *isop_ifa; /* ESIS interface assoc w/sock */ - struct sockaddr_iso isop_sladdr, /* preallocated laddr */ - isop_sfaddr; /* preallocated faddr */ -}; - -#ifdef sotorawcb -/* - * Common structure pcb for raw clnp protocol access. - * Here are clnp specific extensions to the raw control block, - * and space is allocated to the necessary sockaddrs. - */ -struct rawisopcb { - struct rawcb risop_rcb; /* common control block prefix */ - int risop_flags; /* flags, e.g. raw sockopts */ - struct isopcb risop_isop; /* space for bound addresses, routes etc.*/ -}; -#endif - -#define sotoisopcb(so) ((struct isopcb *)(so)->so_pcb) -#define sotorawisopcb(so) ((struct rawisopcb *)(so)->so_pcb) - -#ifdef KERNEL -struct isopcb *iso_pcblookup(); -#endif diff --git a/bsd/netiso/iso_proto.c b/bsd/netiso/iso_proto.c deleted file mode 100644 index 2fba142f3..000000000 --- a/bsd/netiso/iso_proto.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)iso_proto.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * iso_proto.c : protocol switch tables in the ISO domain - * - * ISO protocol family includes TP, CLTP, CLNP, 8208 - * TP and CLNP are implemented here. - */ - -#if ISO -#include -#include -#include -#include -#include - -#include - -#include - -int clnp_output(), clnp_init(),clnp_slowtimo(),clnp_drain(); -int rclnp_input(), rclnp_output(), rclnp_ctloutput(), raw_usrreq(); -int clnp_usrreq(); - -int tp_ctloutput(), tpclnp_ctlinput(), tpclnp_input(), tp_usrreq(); -int tp_init(), tp_fasttimo(), tp_slowtimo(), tp_drain(); -int cons_init(), tpcons_input(); - -int isis_input(); -int esis_input(), esis_ctlinput(), esis_init(), esis_usrreq(); -int idrp_input(), idrp_init(), idrp_usrreq(); -int cltp_input(), cltp_ctlinput(), cltp_init(), cltp_usrreq(), cltp_output(); - -#if TUBA -int tuba_usrreq(), tuba_ctloutput(), tuba_init(), tuba_tcpinput(); -int tuba_slowtimo(), tuba_fasttimo(); -#endif - -struct protosw isosw[] = { -/* - * We need a datagram entry through which net mgmt programs can get - * to the iso_control procedure (iso ioctls). Thus, a minimal - * SOCK_DGRAM interface is provided here. - * THIS ONE MUST BE FIRST: Kludge city : socket() says if(!proto) call - * pffindtype, which gets the first entry that matches the type. - * sigh. - */ -{ SOCK_DGRAM, &isodomain, ISOPROTO_CLTP, PR_ATOMIC|PR_ADDR, - 0, cltp_output, 0, 0, - cltp_usrreq, - cltp_init, 0, 0, 0 -}, - -/* - * A datagram interface for clnp cannot co-exist with TP/CLNP - * because CLNP has no way to discriminate incoming TP packets from - * packets coming in for any other higher layer protocol. - * Old way: set it up so that pffindproto(... dgm, clnp) fails. - * New way: let pffindproto work (for x.25, thank you) but create - * a clnp_usrreq() that returns error on PRU_ATTACH. - */ -{SOCK_DGRAM, &isodomain, ISOPROTO_CLNP, 0, - 0, clnp_output, 0, 0, - clnp_usrreq, - clnp_init, 0, clnp_slowtimo, clnp_drain, -}, - -/* raw clnp */ -{ SOCK_RAW, &isodomain, ISOPROTO_RAW, PR_ATOMIC|PR_ADDR, - rclnp_input, rclnp_output, 0, rclnp_ctloutput, - clnp_usrreq, - 0, 0, 0, 0 -}, - -/* ES-IS protocol */ -{ SOCK_DGRAM, &isodomain, ISOPROTO_ESIS, PR_ATOMIC|PR_ADDR, - esis_input, 0, esis_ctlinput, 0, - esis_usrreq, - esis_init, 0, 0, 0 -}, - -/* ISOPROTO_INTRAISIS */ -{ SOCK_DGRAM, &isodomain, ISOPROTO_INTRAISIS, PR_ATOMIC|PR_ADDR, - isis_input, 0, 0, 0, - esis_usrreq, - 0, 0, 0, 0 -}, - -/* ISOPROTO_IDRP */ -{ SOCK_DGRAM, &isodomain, ISOPROTO_IDRP, PR_ATOMIC|PR_ADDR, - idrp_input, 0, 0, 0, - idrp_usrreq, - idrp_init, 0, 0, 0 -}, - -/* ISOPROTO_TP */ -{ SOCK_SEQPACKET, &isodomain, ISOPROTO_TP, PR_CONNREQUIRED|PR_WANTRCVD, - tpclnp_input, 0, tpclnp_ctlinput, tp_ctloutput, - tp_usrreq, - tp_init, tp_fasttimo, tp_slowtimo, tp_drain, -}, - -#if TUBA -{ SOCK_STREAM, &isodomain, ISOPROTO_TCP, PR_CONNREQUIRED|PR_WANTRCVD, - tuba_tcpinput, 0, 0, tuba_ctloutput, - tuba_usrreq, - tuba_init, tuba_fasttimo, tuba_fasttimo, 0 -}, -#endif - -#if TPCONS -/* ISOPROTO_TP */ -{ SOCK_SEQPACKET, &isodomain, ISOPROTO_TP0, PR_CONNREQUIRED|PR_WANTRCVD, - tpcons_input, 0, 0, tp_ctloutput, - tp_usrreq, - cons_init, 0, 0, 0, -}, -#endif - -}; - - -struct domain isodomain = { - AF_ISO, /* family */ - "iso-domain", /* name */ - 0, /* initialize routine */ - 0, /* externalize access rights */ - 0, /* dispose of internalized rights */ - isosw, /* protosw */ - &isosw[sizeof(isosw)/sizeof(isosw[0])], /* NPROTOSW */ - 0, /* next */ - rn_inithead, /* rtattach */ - 48, /* rtoffset */ - sizeof(struct sockaddr_iso) /* maxkeylen */ -}; -#endif /* ISO */ diff --git a/bsd/netiso/iso_snpac.c b/bsd/netiso/iso_snpac.c deleted file mode 100644 index 23e0edb7c..000000000 --- a/bsd/netiso/iso_snpac.c +++ /dev/null @@ -1,756 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)iso_snpac.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ - -#include -#include - -#if ISO -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -int iso_systype = SNPA_ES; /* default to be an ES */ -extern short esis_holding_time, esis_config_time, esis_esconfig_time; -extern struct timeval time; -extern void esis_config(); -extern int hz; -static void snpac_fixdstandmask(); - -struct sockaddr_iso blank_siso = {sizeof(blank_siso), AF_ISO}; -extern u_long iso_hashchar(); -static struct sockaddr_iso - dst = {sizeof(dst), AF_ISO}, - gte = {sizeof(dst), AF_ISO}, - src = {sizeof(dst), AF_ISO}, - msk = {sizeof(dst), AF_ISO}, - zmk = {0}; -#define zsi blank_siso -#define zero_isoa zsi.siso_addr -#define zap_isoaddr(a, b) {Bzero(&a.siso_addr, sizeof(*r)); r = b; \ - Bcopy(r, &a.siso_addr, 1 + (r)->isoa_len);} -#define S(x) ((struct sockaddr *)&(x)) - -static struct sockaddr_dl blank_dl = {sizeof(blank_dl), AF_LINK}; -static struct sockaddr_dl gte_dl; -#define zap_linkaddr(a, b, c, i) \ - (*a = blank_dl, bcopy(b, a->sdl_data, a->sdl_alen = c), a->sdl_index = i) - -/* - * We only keep track of a single IS at a time. - */ -struct rtentry *known_is; - -/* - * Addresses taken from NBS agreements, December 1987. - * - * These addresses assume on-the-wire transmission of least significant - * bit first. This is the method used by 802.3. When these - * addresses are passed to the token ring driver, (802.5), they - * must be bit-swaped because 802.5 transmission order is MSb first. - * - * Furthermore, according to IBM Austin, these addresses are not - * true token ring multicast addresses. More work is necessary - * to get multicast to work right on token ring. - * - * Currently, the token ring driver does not handle multicast, so - * these addresses are converted into the broadcast address in - * lan_output() That means that if these multicast addresses change - * the token ring driver must be altered. - */ -char all_es_snpa[] = { 0x09, 0x00, 0x2b, 0x00, 0x00, 0x04 }; -char all_is_snpa[] = { 0x09, 0x00, 0x2b, 0x00, 0x00, 0x05 }; -char all_l1is_snpa[] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x14}; -char all_l2is_snpa[] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x15}; - -union sockunion { - struct sockaddr_iso siso; - struct sockaddr_dl sdl; - struct sockaddr sa; -}; - -/* - * FUNCTION: llc_rtrequest - * - * PURPOSE: Manage routing table entries specific to LLC for ISO. - * - * NOTES: This does a lot of obscure magic; - */ -llc_rtrequest(req, rt, sa) -int req; -register struct rtentry *rt; -struct sockaddr *sa; -{ - register union sockunion *gate = (union sockunion *)rt->rt_gateway; - register struct llinfo_llc *lc = (struct llinfo_llc *)rt->rt_llinfo, *lc2; - struct rtentry *rt2; - struct ifnet *ifp = rt->rt_ifp; - int addrlen = ifp->if_addrlen; -#define LLC_SIZE 3 /* XXXXXX do this right later */ - - IFDEBUG (D_SNPA) - printf("llc_rtrequest(%d, %x, %x)\n", req, rt, sa); - ENDDEBUG - if (rt->rt_flags & RTF_GATEWAY) - return; - else switch (req) { - case RTM_ADD: - /* - * Case 1: This route may come from a route to iface with mask - * or from a default route. - */ - if (rt->rt_flags & RTF_CLONING) { - iso_setmcasts(ifp, req); - rt_setgate(rt, rt_key(rt), &blank_dl); - return; - } - if (lc != 0) - return; /* happens on a route change */ - /* FALLTHROUGH */ - case RTM_RESOLVE: - /* - * Case 2: This route may come from cloning, or a manual route - * add with a LL address. - */ - if (gate->sdl.sdl_family != AF_LINK) { - log(LOG_DEBUG, "llc_rtrequest: got non-link non-gateway route\n"); - break; - } - R_Malloc(lc, struct llinfo_llc *, sizeof (*lc)); - rt->rt_llinfo = (caddr_t)lc; - if (lc == 0) { - log(LOG_DEBUG, "llc_rtrequest: malloc failed\n"); - break; - } - Bzero(lc, sizeof(*lc)); - lc->lc_rt = rt; - rt->rt_flags |= RTF_LLINFO; - insque(lc, &llinfo_llc); - if (gate->sdl.sdl_alen == sizeof(struct esis_req) + addrlen) { - gate->sdl.sdl_alen -= sizeof(struct esis_req); - bcopy(addrlen + LLADDR(&gate->sdl), - (caddr_t)&lc->lc_er, sizeof(lc->lc_er)); - } else if (gate->sdl.sdl_alen == addrlen) - lc->lc_flags = (SNPA_ES | SNPA_VALID | SNPA_PERM); - break; - case RTM_DELETE: - if (rt->rt_flags & RTF_CLONING) - iso_setmcasts(ifp, req); - if (lc == 0) - return; - remque(lc); - Free(lc); - rt->rt_llinfo = 0; - rt->rt_flags &= ~RTF_LLINFO; - break; - } - if (rt->rt_rmx.rmx_mtu == 0) { - rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu - LLC_SIZE; - } -} -/* - * FUNCTION: iso_setmcasts - * - * PURPOSE: Enable/Disable ESIS/ISIS multicast reception on interfaces. - * - * NOTES: This also does a lot of obscure magic; - */ -iso_setmcasts(ifp, req) - struct ifnet *ifp; - int req; -{ - static char *addrlist[] = - { all_es_snpa, all_is_snpa, all_l1is_snpa, all_l2is_snpa, 0}; - struct ifreq ifr; - register caddr_t *cpp; - int doreset = 0; - - bzero((caddr_t)&ifr, sizeof(ifr)); - for (cpp = (caddr_t *)addrlist; *cpp; cpp++) { - bcopy(*cpp, (caddr_t)ifr.ifr_addr.sa_data, 6); - if (req == RTM_ADD) - if (ether_addmulti(&ifr, (struct arpcom *)ifp) == ENETRESET) - doreset++; - else - if (ether_delmulti(&ifr, (struct arpcom *)ifp) == ENETRESET) - doreset++; - } - if (doreset) { - if (ifp->if_reset) - (*ifp->if_reset)(ifp->if_unit); - else - printf("iso_setmcasts: %s%d needs reseting to receive iso mcasts\n", - ifp->if_name, ifp->if_unit); - } -} -/* - * FUNCTION: iso_snparesolve - * - * PURPOSE: Resolve an iso address into snpa address - * - * RETURNS: 0 if addr is resolved - * errno if addr is unknown - * - * SIDE EFFECTS: - * - * NOTES: Now that we have folded the snpa cache into the routing - * table, we know there is no snpa address known for this - * destination. If we know of a default IS, then the address - * of the IS is returned. If no IS is known, then return the - * multi-cast address for "all ES" for this interface. - * - * NB: the last case described above constitutes the - * query configuration function 9542, sec 6.5 - * A mechanism is needed to prevent this function from - * being invoked if the system is an IS. - */ -iso_snparesolve(ifp, dest, snpa, snpa_len) -struct ifnet *ifp; /* outgoing interface */ -struct sockaddr_iso *dest; /* destination */ -caddr_t snpa; /* RESULT: snpa to be used */ -int *snpa_len; /* RESULT: length of snpa */ -{ - struct llinfo_llc *sc; /* ptr to snpa table entry */ - caddr_t found_snpa; - int addrlen; - - /* - * This hack allows us to send esis packets that have the destination snpa - * addresss embedded in the destination nsap address - */ - if (dest->siso_data[0] == AFI_SNA) { - /* - * This is a subnetwork address. Return it immediately - */ - IFDEBUG(D_SNPA) - printf("iso_snparesolve: return SN address\n"); - ENDDEBUG - addrlen = dest->siso_nlen - 1; /* subtract size of AFI */ - found_snpa = (caddr_t) dest->siso_data + 1; - /* - * If we are an IS, we can't do much with the packet; - * Check if we know about an IS. - */ - } else if (iso_systype != SNPA_IS && known_is != 0 && - (sc = (struct llinfo_llc *)known_is->rt_llinfo) && - (sc->lc_flags & SNPA_VALID)) { - register struct sockaddr_dl *sdl = - (struct sockaddr_dl *)(known_is->rt_gateway); - found_snpa = LLADDR(sdl); - addrlen = sdl->sdl_alen; - } else if (ifp->if_flags & IFF_BROADCAST) { - /* - * no IS, no match. Return "all es" multicast address for this - * interface, as per Query Configuration Function (9542 sec 6.5) - * - * Note: there is a potential problem here. If the destination - * is on the subnet and it does not respond with a ESH, but - * does send back a TP CC, a connection could be established - * where we always transmit the CLNP packet to "all es" - */ - addrlen = ifp->if_addrlen; - found_snpa = (caddr_t)all_es_snpa; - } else - return (ENETUNREACH); - bcopy(found_snpa, snpa, *snpa_len = addrlen); - return (0); -} - - -/* - * FUNCTION: snpac_free - * - * PURPOSE: free an entry in the iso address map table - * - * RETURNS: nothing - * - * SIDE EFFECTS: - * - * NOTES: If there is a route entry associated with cache - * entry, then delete that as well - */ -snpac_free(lc) -register struct llinfo_llc *lc; /* entry to free */ -{ - register struct rtentry *rt = lc->lc_rt; - register struct iso_addr *r; - - if (known_is == rt) - known_is = 0; - if (rt && (rt->rt_flags & RTF_UP) && - (rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED))) { - RTFREE(rt); - rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt), - rt->rt_flags, (struct rtentry **)0); - RTFREE(rt); - } -} - -/* - * FUNCTION: snpac_add - * - * PURPOSE: Add an entry to the snpa cache - * - * RETURNS: - * - * SIDE EFFECTS: - * - * NOTES: If entry already exists, then update holding time. - */ -snpac_add(ifp, nsap, snpa, type, ht, nsellength) -struct ifnet *ifp; /* interface info is related to */ -struct iso_addr *nsap; /* nsap to add */ -caddr_t snpa; /* translation */ -char type; /* SNPA_IS or SNPA_ES */ -u_short ht; /* holding time (in seconds) */ -int nsellength; /* nsaps may differ only in trailing bytes */ -{ - register struct llinfo_llc *lc; - register struct rtentry *rt; - struct rtentry *mrt = 0; - register struct iso_addr *r; /* for zap_isoaddr macro */ - int snpalen = min(ifp->if_addrlen, MAX_SNPALEN); - int new_entry = 0, index = ifp->if_index, iftype = ifp->if_type; - - IFDEBUG(D_SNPA) - printf("snpac_add(%x, %x, %x, %x, %x, %x)\n", - ifp, nsap, snpa, type, ht, nsellength); - ENDDEBUG - zap_isoaddr(dst, nsap); - rt = rtalloc1(S(dst), 0); - IFDEBUG(D_SNPA) - printf("snpac_add: rtalloc1 returns %x\n", rt); - ENDDEBUG - if (rt == 0) { - struct sockaddr *netmask; - int flags; - add: - if (nsellength) { - netmask = S(msk); flags = RTF_UP; - snpac_fixdstandmask(nsellength); - } else { - netmask = 0; flags = RTF_UP | RTF_HOST; - } - new_entry = 1; - zap_linkaddr((>e_dl), snpa, snpalen, index); - gte_dl.sdl_type = iftype; - if (rtrequest(RTM_ADD, S(dst), S(gte_dl), netmask, flags, &mrt) || - mrt == 0) - return (0); - rt = mrt; - rt->rt_refcnt--; - } else { - register struct sockaddr_dl *sdl = (struct sockaddr_dl *)rt->rt_gateway; - rt->rt_refcnt--; - if ((rt->rt_flags & RTF_LLINFO) == 0) - goto add; - if (nsellength && (rt->rt_flags & RTF_HOST)) { - if (rt->rt_refcnt == 0) { - rtrequest(RTM_DELETE, S(dst), (struct sockaddr *)0, - (struct sockaddr *)0, 0, (struct rtentry *)0); - rt = 0; - goto add; - } else { - static struct iso_addr nsap2; register char *cp; - nsap2 = *nsap; - cp = nsap2.isoa_genaddr + nsap->isoa_len - nsellength; - while (cp < (char *)(1 + &nsap2)) - *cp++ = 0; - (void) snpac_add(ifp, &nsap2, snpa, type, ht, nsellength); - } - } - if (sdl->sdl_family != AF_LINK || sdl->sdl_alen == 0) { - int old_sdl_len = sdl->sdl_len; - if (old_sdl_len < sizeof(*sdl)) { - log(LOG_DEBUG, "snpac_add: cant make room for lladdr\n"); - return (0); - } - zap_linkaddr(sdl, snpa, snpalen, index); - sdl->sdl_len = old_sdl_len; - sdl->sdl_type = iftype; - new_entry = 1; - } - } - if ((lc = (struct llinfo_llc *)rt->rt_llinfo) == 0) - panic("snpac_rtrequest"); - rt->rt_rmx.rmx_expire = ht + time.tv_sec; - lc->lc_flags = SNPA_VALID | type; - if ((type & SNPA_IS) && !(iso_systype & SNPA_IS)) - snpac_logdefis(rt); - return (new_entry); -} - -static void -snpac_fixdstandmask(nsellength) -{ - register char *cp = msk.siso_data, *cplim; - - cplim = cp + (dst.siso_nlen -= nsellength); - msk.siso_len = cplim - (char *)&msk; - msk.siso_nlen = 0; - while (cp < cplim) - *cp++ = -1; - while (cp < (char *)msk.siso_pad) - *cp++ = 0; - for (cp = dst.siso_data + dst.siso_nlen; cp < (char *)dst.siso_pad; ) - *cp++ = 0; -} - -/* - * FUNCTION: snpac_ioctl - * - * PURPOSE: Set/Get the system type and esis parameters - * - * RETURNS: 0 on success, or unix error code - * - * SIDE EFFECTS: - * - * NOTES: - */ -snpac_ioctl (so, cmd, data) -struct socket *so; -int cmd; /* ioctl to process */ -caddr_t data; /* data for the cmd */ -{ - register struct systype_req *rq = (struct systype_req *)data; - - IFDEBUG(D_IOCTL) - if (cmd == SIOCSSTYPE) - printf("snpac_ioctl: cmd set, type x%x, ht %d, ct %d\n", - rq->sr_type, rq->sr_holdt, rq->sr_configt); - else - printf("snpac_ioctl: cmd get\n"); - ENDDEBUG - - if (cmd == SIOCSSTYPE) { - if ((so->so_state & SS_PRIV) == 0) - return (EPERM); - if ((rq->sr_type & (SNPA_ES|SNPA_IS)) == (SNPA_ES|SNPA_IS)) - return(EINVAL); - if (rq->sr_type & SNPA_ES) { - iso_systype = SNPA_ES; - } else if (rq->sr_type & SNPA_IS) { - iso_systype = SNPA_IS; - } else { - return(EINVAL); - } - esis_holding_time = rq->sr_holdt; - esis_config_time = rq->sr_configt; - if (esis_esconfig_time != rq->sr_esconfigt) { - untimeout(esis_config, (caddr_t)0); - esis_esconfig_time = rq->sr_esconfigt; - esis_config(); - } - } else if (cmd == SIOCGSTYPE) { - rq->sr_type = iso_systype; - rq->sr_holdt = esis_holding_time; - rq->sr_configt = esis_config_time; - rq->sr_esconfigt = esis_esconfig_time; - } else { - return (EINVAL); - } - return (0); -} - -/* - * FUNCTION: snpac_logdefis - * - * PURPOSE: Mark the IS passed as the default IS - * - * RETURNS: nothing - * - * SIDE EFFECTS: - * - * NOTES: - */ -snpac_logdefis(sc) -register struct rtentry *sc; -{ - register struct iso_addr *r; - register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sc->rt_gateway; - register struct rtentry *rt; - - if (known_is == sc || !(sc->rt_flags & RTF_HOST)) - return; - if (known_is) { - RTFREE(known_is); - } - known_is = sc; - RTHOLD(sc); - rt = rtalloc1((struct sockaddr *)&zsi, 0); - if (rt == 0) - rtrequest(RTM_ADD, S(zsi), rt_key(sc), S(zmk), - RTF_DYNAMIC|RTF_GATEWAY, 0); - else { - if ((rt->rt_flags & RTF_DYNAMIC) && - (rt->rt_flags & RTF_GATEWAY) && rt_mask(rt)->sa_len == 0) - rt_setgate(rt, rt_key(rt), rt_key(sc)); - } -} - -/* - * FUNCTION: snpac_age - * - * PURPOSE: Time out snpac entries - * - * RETURNS: - * - * SIDE EFFECTS: - * - * NOTES: When encountering an entry for the first time, snpac_age - * may delete up to SNPAC_AGE too many seconds. Ie. - * if the entry is added a moment before snpac_age is - * called, the entry will immediately have SNPAC_AGE - * seconds taken off the holding time, even though - * it has only been held a brief moment. - * - * The proper way to do this is set an expiry timeval - * equal to current time + holding time. Then snpac_age - * would time out entries where expiry date is older - * than the current time. - */ -void -snpac_age() -{ - register struct llinfo_llc *lc, *nlc; - register struct rtentry *rt; - - timeout(snpac_age, (caddr_t)0, SNPAC_AGE * hz); - - for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = nlc) { - nlc = lc->lc_next; - if (lc->lc_flags & SNPA_VALID) { - rt = lc->lc_rt; - if (rt->rt_rmx.rmx_expire && rt->rt_rmx.rmx_expire < time.tv_sec) - snpac_free(lc); - } - } -} - -/* - * FUNCTION: snpac_ownmulti - * - * PURPOSE: Determine if the snpa address is a multicast address - * of the same type as the system. - * - * RETURNS: true or false - * - * SIDE EFFECTS: - * - * NOTES: Used by interface drivers when not in eavesdrop mode - * as interm kludge until - * real multicast addresses can be configured - */ -snpac_ownmulti(snpa, len) -caddr_t snpa; -u_int len; -{ - return (((iso_systype & SNPA_ES) && - (!bcmp(snpa, (caddr_t)all_es_snpa, len))) || - ((iso_systype & SNPA_IS) && - (!bcmp(snpa, (caddr_t)all_is_snpa, len)))); -} - -/* - * FUNCTION: snpac_flushifp - * - * PURPOSE: Flush entries associated with specific ifp - * - * RETURNS: nothing - * - * SIDE EFFECTS: - * - * NOTES: - */ -snpac_flushifp(ifp) -struct ifnet *ifp; -{ - register struct llinfo_llc *lc; - - for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = lc->lc_next) { - if (lc->lc_rt->rt_ifp == ifp && (lc->lc_flags & SNPA_VALID)) - snpac_free(lc); - } -} - -/* - * FUNCTION: snpac_rtrequest - * - * PURPOSE: Make a routing request - * - * RETURNS: nothing - * - * SIDE EFFECTS: - * - * NOTES: In the future, this should make a request of a user - * level routing daemon. - */ -snpac_rtrequest(req, host, gateway, netmask, flags, ret_nrt) -int req; -struct iso_addr *host; -struct iso_addr *gateway; -struct iso_addr *netmask; -short flags; -struct rtentry **ret_nrt; -{ - register struct iso_addr *r; - - IFDEBUG(D_SNPA) - printf("snpac_rtrequest: "); - if (req == RTM_ADD) - printf("add"); - else if (req == RTM_DELETE) - printf("delete"); - else - printf("unknown command"); - printf(" dst: %s\n", clnp_iso_addrp(host)); - printf("\tgateway: %s\n", clnp_iso_addrp(gateway)); - ENDDEBUG - - - zap_isoaddr(dst, host); - zap_isoaddr(gte, gateway); - if (netmask) { - zap_isoaddr(msk, netmask); - msk.siso_nlen = 0; - msk.siso_len = msk.siso_pad - (u_char *)&msk; - } - - rtrequest(req, S(dst), S(gte), (netmask ? S(msk) : (struct sockaddr *)0), - flags, ret_nrt); -} - -/* - * FUNCTION: snpac_addrt - * - * PURPOSE: Associate a routing entry with an snpac entry - * - * RETURNS: nothing - * - * SIDE EFFECTS: - * - * NOTES: If a cache entry exists for gateway, then - * make a routing entry (host, gateway) and associate - * with gateway. - * - * If a route already exists and is different, first delete - * it. - * - * This could be made more efficient by checking - * the existing route before adding a new one. - */ -snpac_addrt(ifp, host, gateway, netmask) -struct ifnet *ifp; -struct iso_addr *host, *gateway, *netmask; -{ - register struct iso_addr *r; - - zap_isoaddr(dst, host); - zap_isoaddr(gte, gateway); - if (netmask) { - zap_isoaddr(msk, netmask); - msk.siso_nlen = 0; - msk.siso_len = msk.siso_pad - (u_char *)&msk; - rtredirect(S(dst), S(gte), S(msk), RTF_DONE, S(gte), 0); - } else - rtredirect(S(dst), S(gte), (struct sockaddr *)0, - RTF_DONE | RTF_HOST, S(gte), 0); -} -#endif /* ISO */ diff --git a/bsd/netiso/iso_snpac.h b/bsd/netiso/iso_snpac.h deleted file mode 100644 index 7f84b777f..000000000 --- a/bsd/netiso/iso_snpac.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)iso_snpac.h 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ - -#define MAX_SNPALEN 8 /* curiously equal to sizeof x.121 ( - plus 1 for nibble len) addr */ -struct snpa_req { - struct iso_addr sr_isoa; /* nsap address */ - u_char sr_len; /* length of snpa */ - u_char sr_snpa[MAX_SNPALEN]; /* snpa associated - with nsap address */ - u_char sr_flags; /* true if entry is valid */ - u_short sr_ht; /* holding time */ -}; - -#define SNPA_VALID 0x01 -#define SNPA_ES 0x02 -#define SNPA_IS 0x04 -#define SNPA_PERM 0x10 - -struct systype_req { - short sr_holdt; /* holding timer */ - short sr_configt; /* configuration timer */ - short sr_esconfigt; /* suggested ES configuration timer */ - char sr_type; /* SNPA_ES or SNPA_IS */ -}; - -struct esis_req { - short er_ht; /* holding time */ - u_char er_flags; /* type and validity */ -}; -/* - * Space for this structure gets added onto the end of a route - * going to an ethernet or other 802.[45x] device. - */ - -struct llinfo_llc { - struct llinfo_llc *lc_next; /* keep all llc routes linked */ - struct llinfo_llc *lc_prev; /* keep all llc routes linked */ - struct rtentry *lc_rt; /* backpointer to route */ - struct esis_req lc_er; /* holding time, etc */ -#define lc_ht lc_er.er_ht -#define lc_flags lc_er.er_flags -}; - - -/* ISO arp IOCTL data structures */ - -#define SIOCSSTYPE _IOW('a', 39, struct systype_req) /* set system type */ -#define SIOCGSTYPE _IOR('a', 40, struct systype_req) /* get system type */ - -#ifdef KERNEL -struct llinfo_llc llinfo_llc; /* head for linked lists */ -#endif /* KERNEL */ diff --git a/bsd/netiso/iso_var.h b/bsd/netiso/iso_var.h deleted file mode 100644 index a7420c08f..000000000 --- a/bsd/netiso/iso_var.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1988, 1991, 1993 - * 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. - * - * @(#)iso_var.h 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ - -/* - * Interface address, iso version. One of these structures is - * allocated for each interface with an osi address. The ifaddr - * structure conatins the protocol-independent part - * of the structure, and is assumed to be first. - */ -struct iso_ifaddr { - struct ifaddr ia_ifa; /* protocol-independent info */ -#define ia_ifp ia_ifa.ifa_ifp -#define ia_flags ia_ifa.ifa_flags - int ia_snpaoffset; - struct iso_ifaddr *ia_next; /* next in list of iso addresses */ - struct sockaddr_iso ia_addr; /* reserve space for interface name */ - struct sockaddr_iso ia_dstaddr; /* reserve space for broadcast addr */ -#define ia_broadaddr ia_dstaddr - struct sockaddr_iso ia_sockmask; /* reserve space for general netmask */ -}; - -struct iso_aliasreq { - char ifra_name[IFNAMSIZ]; /* if name, e.g. "en0" */ - struct sockaddr_iso ifra_addr; - struct sockaddr_iso ifra_dstaddr; - struct sockaddr_iso ifra_mask; - int ifra_snpaoffset; -}; - -struct iso_ifreq { - char ifr_name[IFNAMSIZ]; /* if name, e.g. "en0" */ - struct sockaddr_iso ifr_Addr; -}; - -/* - * Given a pointer to an iso_ifaddr (ifaddr), - * return a pointer to the addr as a sockaddr_iso - */ -/* -#define IA_SIS(ia) ((struct sockaddr_iso *)(ia.ia_ifa->ifa_addr)) - * works if sockaddr_iso becomes variable sized. - */ -#define IA_SIS(ia) (&(((struct iso_ifaddr *)ia)->ia_addr)) - -#define SIOCDIFADDR_ISO _IOW('i',25, struct iso_ifreq) /* delete IF addr */ -#define SIOCAIFADDR_ISO _IOW('i',26, struct iso_aliasreq)/* add/chg IFalias */ -#define SIOCGIFADDR_ISO _IOWR('i',33, struct iso_ifreq) /* get ifnet address */ -#define SIOCGIFDSTADDR_ISO _IOWR('i',34, struct iso_ifreq) /* get dst address */ -#define SIOCGIFNETMASK_ISO _IOWR('i',37, struct iso_ifreq) /* get dst address */ - -/* - * This stuff should go in if.h or if_llc.h or someplace else, - * but for now . . . - */ - -struct llc_etherhdr { - char dst[6]; - char src[6]; - char len[2]; - char llc_dsap; - char llc_ssap; - char llc_ui_byte; -}; - -struct snpa_hdr { - struct ifnet *snh_ifp; - char snh_dhost[6]; - char snh_shost[6]; - short snh_flags; -}; -#ifdef KERNEL -struct iso_ifaddr *iso_ifaddr; /* linked list of iso address ifaces */ -struct iso_ifaddr *iso_localifa(); /* linked list of iso address ifaces */ -struct ifqueue clnlintrq; /* clnl packet input queue */ -#endif /* KERNEL */ diff --git a/bsd/netiso/tp_astring.c b/bsd/netiso/tp_astring.c deleted file mode 100644 index ee70ea369..000000000 --- a/bsd/netiso/tp_astring.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)tp_astring.c 8.1 (Berkeley) 6/10/93 - */ - -char *tp_sstring[] = { -"ST_ERROR(0x0)", -"TP_CLOSED(0x1)", -"TP_CRSENT(0x2)", -"TP_AKWAIT(0x3)", -"TP_OPEN(0x4)", -"TP_CLOSING(0x5)", -"TP_REFWAIT(0x6)", -"TP_LISTENING(0x7)", -"TP_CONFIRMING(0x8)", -}; - -char *tp_estring[] = { -"TM_inact(0x0)", -"TM_retrans(0x1)", -"TM_sendack(0x2)", -"TM_notused(0x3)", -"TM_reference(0x4)", -"TM_data_retrans(0x5)", -"ER_TPDU(0x6)", -"CR_TPDU(0x7)", -"DR_TPDU(0x8)", -"DC_TPDU(0x9)", -"CC_TPDU(0xa)", -"AK_TPDU(0xb)", -"DT_TPDU(0xc)", -"XPD_TPDU(0xd)", -"XAK_TPDU(0xe)", -"T_CONN_req(0xf)", -"T_DISC_req(0x10)", -"T_LISTEN_req(0x11)", -"T_DATA_req(0x12)", -"T_XPD_req(0x13)", -"T_USR_rcvd(0x14)", -"T_USR_Xrcvd(0x15)", -"T_DETACH(0x16)", -"T_NETRESET(0x17)", -"T_ACPT_req(0x18)", -}; diff --git a/bsd/netiso/tp_clnp.h b/bsd/netiso/tp_clnp.h deleted file mode 100644 index 48bd875ae..000000000 --- a/bsd/netiso/tp_clnp.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)tp_clnp.h 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * ARGO TP - * - * AF_ISO net-dependent structures and include files - * - */ - - -#ifndef __TP_CLNP__ -#define __TP_CLNP__ - -#ifndef SOCK_STREAM -#include -#endif /* SOCK_STREAM */ - -#ifndef RTFREE -#include -#endif -#include -#include -#include -#ifndef IF_DEQUEUE -#include -#endif -#include - -struct isopcb tp_isopcb; - /* queue of active inpcbs for tp ; for tp with dod ip */ - -#endif /* __TP_CLNP__ */ diff --git a/bsd/netiso/tp_cons.c b/bsd/netiso/tp_cons.c deleted file mode 100644 index 400acfb60..000000000 --- a/bsd/netiso/tp_cons.c +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)tp_cons.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * ARGO TP - * Here is where you find the iso- and cons-dependent code. We've tried - * keep all net-level and (primarily) address-family-dependent stuff - * out of the tp source, and everthing here is reached indirectly - * through a switch table (struct nl_protosw *) tpcb->tp_nlproto - * (see tp_pcb.c). - * The routines here are: - * tpcons_input: pullup and call tp_input w/ correct arguments - * tpcons_output: package a pkt for cons given an isopcb & some data - * cons_chan_to_tpcb: find a tpcb based on the channel # - */ - -#if ISO -#if TPCONS - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#undef FALSE -#undef TRUE -#include -#include -#include - -#include -int tpcons_output(); - -/* - * CALLED FROM: - * tp_route_to() for PRU_CONNECT - * FUNCTION, ARGUMENTS, SIDE EFFECTS and RETURN VALUE: - * version of the previous procedure for X.25 - */ - -tpcons_pcbconnect(isop, nam) -struct isopcb *isop; -register struct mbuf *nam; -{ - int error; - if (error = iso_pcbconnect(isop, nam)) - return error; - if ((isop->isop_chan = (caddr_t) pk_attach((struct socket *)0)) == 0) { - IFDEBUG(D_CCONS) - printf("tpcons_pcbconnect: no pklcd; returns 0x%x\n", error); - ENDDEBUG - return ENOBUFS; - } - if (error = cons_connect(isop)) { /* if it doesn't work */ - /* oh, dear, throw packet away */ - pk_disconnect((struct pklcd *)isop->isop_chan); - isop->isop_chan = 0; - } else - isop->isop_refcnt = 1; - return error; -} - - -/* - * CALLED FROM: - * cons - * FUNCTION and ARGUMENTS: - * THIS MAYBE BELONGS IN SOME OTHER PLACE??? but i think not - - */ -ProtoHook -tpcons_ctlinput(cmd, siso, isop) - int cmd; - struct sockaddr_iso *siso; - struct isopcb *isop; -{ - register struct tp_pcb *tpcb = 0; - - if (isop->isop_socket) - tpcb = (struct tp_pcb *)isop->isop_socket->so_pcb; - switch (cmd) { - - case PRC_CONS_SEND_DONE: - if (tpcb) { - struct tp_event E; - int error = 0; - - if (tpcb->tp_class == TP_CLASS_0) { - /* only if class is exactly class zero, not - * still in class negotiation - */ - /* fake an ack */ - register SeqNum seq = SEQ_ADD(tpcb, tpcb->tp_snduna, 1); - - IFTRACE(D_DATA) - tptrace(TPPTmisc, "FAKE ACK seq cdt 1", - seq, 0,0,0); - ENDTRACE - IFDEBUG(D_DATA) - printf("FAKE ACK seq 0x%x cdt 1\n", seq ); - ENDDEBUG - E.ATTR(AK_TPDU).e_cdt = 1; - E.ATTR(AK_TPDU).e_seq = seq; - E.ATTR(AK_TPDU).e_subseq = 0; - E.ATTR(AK_TPDU).e_fcc_present = 0; - error = DoEvent(AK_TPDU); - if( error ) { - tpcb->tp_sock->so_error = error; - } - } /* else ignore it */ - } - break; - case PRC_ROUTEDEAD: - if (tpcb && tpcb->tp_class == TP_CLASS_0) { - tpiso_reset(isop); - break; - } /* else drop through */ - default: - (void) tpclnp_ctlinput(cmd, siso); - break; - } - return 0; -} - -/* - * CALLED FROM: - * cons's intr routine - * FUNCTION and ARGUMENTS: - * Take a packet (m) from cons, pullup m as required by tp, - * ignore the socket argument, and call tp_input. - * No return value. - */ -ProtoHook -tpcons_input(m, faddr, laddr, channel) - struct mbuf *m; - struct sockaddr_iso *faddr, *laddr; - caddr_t channel; -{ - if( m == MNULL) - return 0; - - m = (struct mbuf *)tp_inputprep(m); - - IFDEBUG(D_TPINPUT) - printf("tpcons_input before tp_input(m 0x%x)\n", m); - dump_buf( m, 12+ m->m_len); - ENDDEBUG - tp_input(m, faddr, laddr, channel, tpcons_output, 0); - return 0; -} - - -/* - * CALLED FROM: - * tp_emit() - * FUNCTION and ARGUMENTS: - * Take a packet(m0) from tp and package it so that cons will accept it. - * This means filling in a few of the fields. - * inp is the isopcb structure; datalen is the length of the data in the - * mbuf string m0. - * RETURN VALUE: - * whatever (E*) is returned form the net layer output routine. - */ - -int -tpcons_output(isop, m0, datalen, nochksum) - struct isopcb *isop; - struct mbuf *m0; - int datalen; - int nochksum; -{ - register struct mbuf *m = m0; - int error; - - IFDEBUG(D_EMIT) - printf( - "tpcons_output(isop 0x%x, m 0x%x, len 0x%x socket 0x%x\n", - isop, m0, datalen, isop->isop_socket); - ENDDEBUG - if (m == MNULL) - return 0; - if ((m->m_flags & M_PKTHDR) == 0) { - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == 0) - return ENOBUFS; - m->m_next = m0; - } - m->m_pkthdr.len = datalen; - if (isop->isop_chan == 0) { - /* got a restart maybe? */ - if ((isop->isop_chan = (caddr_t) pk_attach((struct socket *)0)) == 0) { - IFDEBUG(D_CCONS) - printf("tpcons_output: no pklcd\n"); - ENDDEBUG - error = ENOBUFS; - } - if (error = cons_connect(isop)) { - pk_disconnect((struct pklcd *)isop->isop_chan); - isop->isop_chan = 0; - IFDEBUG(D_CCONS) - printf("tpcons_output: can't reconnect\n"); - ENDDEBUG - } - } else { - error = pk_send(isop->isop_chan, m); - IncStat(ts_tpdu_sent); - } - return error; -} -/* - * CALLED FROM: - * tp_error_emit() - * FUNCTION and ARGUMENTS: - * Take a packet(m0) from tp and package it so that cons will accept it. - * chan is the cons channel to use; datalen is the length of the data in the - * mbuf string m0. - * RETURN VALUE: - * whatever (E*) is returned form the net layer output routine. - */ - -int -tpcons_dg_output(chan, m0, datalen) - caddr_t chan; - struct mbuf *m0; - int datalen; -{ - return tpcons_output(((struct pklcd *)chan)->lcd_upnext, m0, datalen, 0); -} -#endif /* TPCONS */ -#endif /* ISO */ diff --git a/bsd/netiso/tp_driver.c b/bsd/netiso/tp_driver.c deleted file mode 100644 index f49415a13..000000000 --- a/bsd/netiso/tp_driver.c +++ /dev/null @@ -1,1020 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -#ifndef lint -static char *rcsid = "$Header/**/$"; -#endif lint -#define _XEBEC_PG static - -#include "tp_states.h" - -static struct act_ent { - int a_newstate; - int a_action; -} statetable[] = { {0,0}, -#include "tp_states.init" -}; - -/* @(#)tp.trans 8.1 (Berkeley) 6/10/93 */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRIVERTRACE TPPTdriver -#define sbwakeup(sb) sowakeup(p->tp_sock, sb); -#define MCPY(d, w) (d ? m_copym(d, 0, (int)M_COPYALL, w): 0) - -static trick_hc = 1; - -int tp_emit(), - tp_goodack(), tp_goodXack(), - tp_stash() -; -void tp_indicate(), tp_getoptions(), - tp_soisdisconnecting(), tp_soisdisconnected(), - tp_recycle_tsuffix(), -#ifdef TP_DEBUG_TIMERS - tp_etimeout(), tp_euntimeout(), - tp_ctimeout(), tp_cuntimeout(), - tp_ctimeout_MIN(), -#endif - tp_freeref(), tp_detach(), - tp0_stash(), tp0_send(), - tp_netcmd(), tp_send() -; - -typedef struct tp_pcb tpcb_struct; - - - -typedef tpcb_struct tp_PCB_; - -#include "tp_events.h" - -_XEBEC_PG int _Xebec_action(a,e,p) -int a; -struct tp_event *e; -tp_PCB_ *p; -{ -switch(a) { -case -1: return tp_protocol_error(e,p); -case 0x1: - { - (void) tp_emit(DC_TPDU_type, p, 0, 0, MNULL); - } - break; -case 0x2: - { -# ifdef TP_DEBUG - if( e->ev_number != AK_TPDU ) - printf("TPDU 0x%x in REFWAIT!!!!\n", e->ev_number); -# endif TP_DEBUG - } - break; -case 0x3: - { - /* oh, man is this grotesque or what? */ - (void) tp_goodack(p, e->ev_union.EV_AK_TPDU.e_cdt, e->ev_union.EV_AK_TPDU.e_seq, e->ev_union.EV_AK_TPDU.e_subseq); - /* but it's necessary because this pseudo-ack may happen - * before the CC arrives, but we HAVE to adjust the - * snduna as a result of the ack, WHENEVER it arrives - */ - } - break; -case 0x4: - { - tp_detach(p); - } - break; -case 0x5: - { - p->tp_refstate = REF_OPEN; /* has timers ??? */ - } - break; -case 0x6: - { - IFTRACE(D_CONN) - tptrace(TPPTmisc, "CR datalen data", e->ev_union.EV_CR_TPDU.e_datalen, e->ev_union.EV_CR_TPDU.e_data,0,0); - ENDTRACE - IFDEBUG(D_CONN) - printf("CR datalen 0x%x data 0x%x", e->ev_union.EV_CR_TPDU.e_datalen, e->ev_union.EV_CR_TPDU.e_data); - ENDDEBUG - p->tp_refstate = REF_OPEN; /* has timers */ - p->tp_fcredit = e->ev_union.EV_CR_TPDU.e_cdt; - - if (e->ev_union.EV_CR_TPDU.e_datalen > 0) { - /* n/a for class 0 */ - ASSERT(p->tp_Xrcv.sb_cc == 0); - sbappendrecord(&p->tp_Xrcv, e->ev_union.EV_CR_TPDU.e_data); - e->ev_union.EV_CR_TPDU.e_data = MNULL; - } - } - break; -case 0x7: - { - IncStat(ts_tp0_conn); - IFTRACE(D_CONN) - tptrace(TPPTmisc, "Confiming", p, 0,0,0); - ENDTRACE - IFDEBUG(D_CONN) - printf("Confirming connection: p" ); - ENDDEBUG - soisconnected(p->tp_sock); - (void) tp_emit(CC_TPDU_type, p, 0,0, MNULL) ; - p->tp_fcredit = 1; - } - break; -case 0x8: - { - IncStat(ts_tp4_conn); /* even though not quite open */ - IFTRACE(D_CONN) - tptrace(TPPTmisc, "Confiming", p, 0,0,0); - ENDTRACE - IFDEBUG(D_CONN) - printf("Confirming connection: p" ); - ENDDEBUG - tp_getoptions(p); - soisconnecting(p->tp_sock); - if ((p->tp_rx_strat & TPRX_FASTSTART) && (p->tp_fcredit > 0)) - p->tp_cong_win = p->tp_fcredit * p->tp_l_tpdusize; - p->tp_retrans = p->tp_Nretrans; - tp_ctimeout(p, TM_retrans, (int)p->tp_cc_ticks); - } - break; -case 0x9: - { - IFDEBUG(D_CONN) - printf("event: CR_TPDU emit CC failed done " ); - ENDDEBUG - soisdisconnected(p->tp_sock); - tp_recycle_tsuffix(p); - tp_freeref(p->tp_lref); - tp_detach(p); - } - break; -case 0xa: - { - int error; - struct mbuf *data = MNULL; - - IFTRACE(D_CONN) - tptrace(TPPTmisc, "T_CONN_req flags ucddata", (int)p->tp_flags, - p->tp_ucddata, 0, 0); - ENDTRACE - data = MCPY(p->tp_ucddata, M_WAIT); - if (data) { - IFDEBUG(D_CONN) - printf("T_CONN_req.trans m_copy cc 0x%x\n", - p->tp_ucddata); - dump_mbuf(data, "sosnd @ T_CONN_req"); - ENDDEBUG - } - - if (error = tp_emit(CR_TPDU_type, p, 0, 0, data) ) - return error; /* driver WON'T change state; will return error */ - - p->tp_refstate = REF_OPEN; /* has timers */ - if(p->tp_class != TP_CLASS_0) { - p->tp_retrans = p->tp_Nretrans; - tp_ctimeout(p, TM_retrans, (int)p->tp_cr_ticks); - } - } - break; -case 0xb: - { - sbflush(&p->tp_Xrcv); /* purge non-delivered data data */ - if (e->ev_union.EV_DR_TPDU.e_datalen > 0) { - sbappendrecord(&p->tp_Xrcv, e->ev_union.EV_DR_TPDU.e_data); - e->ev_union.EV_DR_TPDU.e_data = MNULL; - } - if (p->tp_state == TP_OPEN) - tp_indicate(T_DISCONNECT, p, 0); - else { - int so_error = ECONNREFUSED; - if (e->ev_union.EV_DR_TPDU.e_reason != (E_TP_NO_SESSION ^ TP_ERROR_MASK) && - e->ev_union.EV_DR_TPDU.e_reason != (E_TP_NO_CR_ON_NC ^ TP_ERROR_MASK) && - e->ev_union.EV_DR_TPDU.e_reason != (E_TP_REF_OVERFLOW ^ TP_ERROR_MASK)) - so_error = ECONNABORTED; - tp_indicate(T_DISCONNECT, p, so_error); - } - tp_soisdisconnected(p); - if (p->tp_class != TP_CLASS_0) { - if (p->tp_state == TP_OPEN ) { - tp_euntimeout(p, TM_data_retrans); /* all */ - tp_cuntimeout(p, TM_retrans); - tp_cuntimeout(p, TM_inact); - tp_cuntimeout(p, TM_sendack); - p->tp_flags &= ~TPF_DELACK; - } - tp_cuntimeout(p, TM_retrans); - if( e->ev_union.EV_DR_TPDU.e_sref != 0 ) - (void) tp_emit(DC_TPDU_type, p, 0, 0, MNULL); - } - } - break; -case 0xc: - { - if( e->ev_union.EV_DR_TPDU.e_sref != 0 ) - (void) tp_emit(DC_TPDU_type, p, 0, 0, MNULL); - /* reference timer already set - reset it to be safe (???) */ - tp_euntimeout(p, TM_reference); /* all */ - tp_etimeout(p, TM_reference, (int)p->tp_refer_ticks); - } - break; -case 0xd: - { - tp_cuntimeout(p, TM_retrans); - tp_indicate(ER_TPDU, p, e->ev_union.EV_ER_TPDU.e_reason); - tp_soisdisconnected(p); - } - break; -case 0xe: - { - tp_cuntimeout(p, TM_retrans); - tp_soisdisconnected(p); - } - break; -case 0xf: - { - tp_indicate(ER_TPDU, p, e->ev_union.EV_ER_TPDU.e_reason); - tp_cuntimeout(p, TM_retrans); - tp_soisdisconnected(p); - } - break; -case 0x10: - { - tp_cuntimeout(p, TM_retrans); - tp_soisdisconnected(p); - } - break; -case 0x11: - { /* don't ask me why we have to do this - spec says so */ - (void) tp_emit(DR_TPDU_type, p, 0, E_TP_NO_SESSION, MNULL); - /* don't bother with retransmissions of the DR */ - } - break; -case 0x12: - { - tp_soisdisconnecting(p->tp_sock); - tp_indicate(ER_TPDU, p, e->ev_union.EV_ER_TPDU.e_reason); - tp_soisdisconnected(p); - tp_netcmd( p, CONN_CLOSE ); - } - break; -case 0x13: - { - if (p->tp_state == TP_OPEN) { - tp_euntimeout(p, TM_data_retrans); /* all */ - tp_cuntimeout(p, TM_inact); - tp_cuntimeout(p, TM_sendack); - } - tp_soisdisconnecting(p->tp_sock); - tp_indicate(ER_TPDU, p, e->ev_union.EV_ER_TPDU.e_reason); - p->tp_retrans = p->tp_Nretrans; - tp_ctimeout(p, TM_retrans, (int)p->tp_dr_ticks); - (void) tp_emit(DR_TPDU_type, p, 0, E_TP_PROTO_ERR, MNULL); - } - break; -case 0x14: - { - tp_cuntimeout(p, TM_retrans); - IncStat(ts_tp0_conn); - p->tp_fcredit = 1; - soisconnected(p->tp_sock); - } - break; -case 0x15: - { - IFDEBUG(D_CONN) - printf("trans: CC_TPDU in CRSENT state flags 0x%x\n", - (int)p->tp_flags); - ENDDEBUG - IncStat(ts_tp4_conn); - p->tp_fref = e->ev_union.EV_CC_TPDU.e_sref; - p->tp_fcredit = e->ev_union.EV_CC_TPDU.e_cdt; - if ((p->tp_rx_strat & TPRX_FASTSTART) && (e->ev_union.EV_CC_TPDU.e_cdt > 0)) - p->tp_cong_win = e->ev_union.EV_CC_TPDU.e_cdt * p->tp_l_tpdusize; - tp_getoptions(p); - tp_cuntimeout(p, TM_retrans); - if (p->tp_ucddata) { - IFDEBUG(D_CONN) - printf("dropping user connect data cc 0x%x\n", - p->tp_ucddata->m_len); - ENDDEBUG - m_freem(p->tp_ucddata); - p->tp_ucddata = 0; - } - soisconnected(p->tp_sock); - if (e->ev_union.EV_CC_TPDU.e_datalen > 0) { - ASSERT(p->tp_Xrcv.sb_cc == 0); /* should be empty */ - sbappendrecord(&p->tp_Xrcv, e->ev_union.EV_CC_TPDU.e_data); - e->ev_union.EV_CC_TPDU.e_data = MNULL; - } - - (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL); - tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); - } - break; -case 0x16: - { - struct mbuf *data = MNULL; - int error; - - IncStat(ts_retrans_cr); - p->tp_cong_win = 1 * p->tp_l_tpdusize; - data = MCPY(p->tp_ucddata, M_NOWAIT); - if(p->tp_ucddata) { - IFDEBUG(D_CONN) - printf("TM_retrans.trans m_copy cc 0x%x\n", data); - dump_mbuf(p->tp_ucddata, "sosnd @ TM_retrans"); - ENDDEBUG - if( data == MNULL ) - return ENOBUFS; - } - - p->tp_retrans --; - if( error = tp_emit(CR_TPDU_type, p, 0, 0, data) ) { - p->tp_sock->so_error = error; - } - tp_ctimeout(p, TM_retrans, (int)p->tp_cr_ticks); - } - break; -case 0x17: - { - IncStat(ts_conn_gaveup); - p->tp_sock->so_error = ETIMEDOUT; - tp_indicate(T_DISCONNECT, p, ETIMEDOUT); - tp_soisdisconnected(p); - } - break; -case 0x18: - { - int error; - struct mbuf *data = MCPY(p->tp_ucddata, M_WAIT); - - if( error = tp_emit(CC_TPDU_type, p, 0, 0, data) ) { - p->tp_sock->so_error = error; - } - p->tp_retrans = p->tp_Nretrans; - tp_ctimeout(p, TM_retrans, (int)p->tp_cc_ticks); - } - break; -case 0x19: - { - int doack; - - /* - * Get rid of any confirm or connect data, so that if we - * crash or close, it isn't thought of as disconnect data. - */ - if (p->tp_ucddata) { - m_freem(p->tp_ucddata); - p->tp_ucddata = 0; - } - tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); - tp_cuntimeout(p, TM_retrans); - soisconnected(p->tp_sock); - tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); - - /* see also next 2 transitions, if you make any changes */ - - doack = tp_stash(p, e); - IFDEBUG(D_DATA) - printf("tp_stash returns %d\n",doack); - ENDDEBUG - - if (doack) { - (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL ); - tp_ctimeout(p, TM_sendack, (int)p->tp_keepalive_ticks); - } else - tp_ctimeout( p, TM_sendack, (int)p->tp_sendack_ticks); - - IFDEBUG(D_DATA) - printf("after stash calling sbwakeup\n"); - ENDDEBUG - } - break; -case 0x1a: - { - tp0_stash(p, e); - sbwakeup( &p->tp_sock->so_rcv ); - - IFDEBUG(D_DATA) - printf("after stash calling sbwakeup\n"); - ENDDEBUG - } - break; -case 0x1b: - { - int doack; /* tells if we must ack immediately */ - - tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); - sbwakeup( &p->tp_sock->so_rcv ); - - doack = tp_stash(p, e); - IFDEBUG(D_DATA) - printf("tp_stash returns %d\n",doack); - ENDDEBUG - - if(doack) - (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL ); - else - tp_ctimeout_MIN( p, TM_sendack, (int)p->tp_sendack_ticks); - - IFDEBUG(D_DATA) - printf("after stash calling sbwakeup\n"); - ENDDEBUG - } - break; -case 0x1c: - { - IFTRACE(D_DATA) - tptrace(TPPTmisc, "NIW seq rcvnxt lcredit ", - e->ev_union.EV_DT_TPDU.e_seq, p->tp_rcvnxt, p->tp_lcredit, 0); - ENDTRACE - IncStat(ts_dt_niw); - m_freem(e->ev_union.EV_DT_TPDU.e_data); - tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); - (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL ); - } - break; -case 0x1d: - { - if (p->tp_ucddata) { - m_freem(p->tp_ucddata); - p->tp_ucddata = 0; - } - (void) tp_goodack(p, e->ev_union.EV_AK_TPDU.e_cdt, e->ev_union.EV_AK_TPDU.e_seq, e->ev_union.EV_AK_TPDU.e_subseq); - tp_cuntimeout(p, TM_retrans); - - soisconnected(p->tp_sock); - IFTRACE(D_CONN) - struct socket *so = p->tp_sock; - tptrace(TPPTmisc, - "called sosiconn: so so_state rcv.sb_sel rcv.sb_flags", - so, so->so_state, so->so_rcv.sb_sel, so->so_rcv.sb_flags); - tptrace(TPPTmisc, - "called sosiconn 2: so_qlen so_error so_rcv.sb_cc so_head", - so->so_qlen, so->so_error, so->so_rcv.sb_cc, so->so_head); - ENDTRACE - - tp_ctimeout(p, TM_sendack, (int)p->tp_keepalive_ticks); - tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); - } - break; -case 0x1e: - { - if( p->tp_state == TP_AKWAIT ) { - if (p->tp_ucddata) { - m_freem(p->tp_ucddata); - p->tp_ucddata = 0; - } - tp_cuntimeout(p, TM_retrans); - soisconnected(p->tp_sock); - tp_ctimeout(p, TM_sendack, (int)p->tp_keepalive_ticks); - tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); - } - IFTRACE(D_XPD) - tptrace(TPPTmisc, "XPD tpdu accepted Xrcvnxt, e_seq datalen m_len\n", - p->tp_Xrcvnxt,e->ev_union.EV_XPD_TPDU.e_seq, e->ev_union.EV_XPD_TPDU.e_datalen, e->ev_union.EV_XPD_TPDU.e_data->m_len); - ENDTRACE - - p->tp_sock->so_state |= SS_RCVATMARK; - postevent(p->tp_sock, 0, EV_OOB); - e->ev_union.EV_XPD_TPDU.e_data->m_flags |= M_EOR; - sbinsertoob(&p->tp_Xrcv, e->ev_union.EV_XPD_TPDU.e_data); - IFDEBUG(D_XPD) - dump_mbuf(e->ev_union.EV_XPD_TPDU.e_data, "XPD TPDU: tp_Xrcv"); - ENDDEBUG - tp_indicate(T_XDATA, p, 0); - sbwakeup( &p->tp_Xrcv ); - - (void) tp_emit(XAK_TPDU_type, p, p->tp_Xrcvnxt, 0, MNULL); - SEQ_INC(p, p->tp_Xrcvnxt); - } - break; -case 0x1f: - { - if( p->tp_Xrcv.sb_cc == 0 ) { - /* kludge for select(): */ - /* p->tp_sock->so_state &= ~SS_OOBAVAIL; */ - } - } - break; -case 0x20: - { - IFTRACE(D_XPD) - tptrace(TPPTmisc, "XPD tpdu niw (Xrcvnxt, e_seq) or not cdt (cc)\n", - p->tp_Xrcvnxt, e->ev_union.EV_XPD_TPDU.e_seq, p->tp_Xrcv.sb_cc , 0); - ENDTRACE - if( p->tp_Xrcvnxt != e->ev_union.EV_XPD_TPDU.e_seq ) - IncStat(ts_xpd_niw); - if( p->tp_Xrcv.sb_cc ) { - /* might as well kick 'em again */ - tp_indicate(T_XDATA, p, 0); - IncStat(ts_xpd_dup); - } - m_freem(e->ev_union.EV_XPD_TPDU.e_data); - tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); - /* don't send an xack because the xak gives "last one received", not - * "next one i expect" (dumb) - */ - } - break; -case 0x21: - { - struct socket *so = p->tp_sock; - - /* detach from parent socket so it can finish closing */ - if (so->so_head) { - if (!soqremque(so, 0) && !soqremque(so, 1)) - panic("tp: T_DETACH"); - so->so_head = 0; - } - tp_soisdisconnecting(p->tp_sock); - tp_netcmd( p, CONN_CLOSE); - tp_soisdisconnected(p); - } - break; -case 0x22: - { - struct socket *so = p->tp_sock; - struct mbuf *data = MNULL; - - /* detach from parent socket so it can finish closing */ - if (so->so_head) { - if (!soqremque(so, 0) && !soqremque(so, 1)) - panic("tp: T_DETACH"); - so->so_head = 0; - } - if (p->tp_state != TP_CLOSING) { - tp_soisdisconnecting(p->tp_sock); - data = MCPY(p->tp_ucddata, M_NOWAIT); - (void) tp_emit(DR_TPDU_type, p, 0, E_TP_NORMAL_DISC, data); - p->tp_retrans = p->tp_Nretrans; - tp_ctimeout(p, TM_retrans, (int)p->tp_dr_ticks); - } - } - break; -case 0x23: - { - tp_soisdisconnecting(p->tp_sock); - tp_netcmd( p, CONN_CLOSE); - tp_soisdisconnected(p); - } - break; -case 0x24: - { - struct mbuf *data = MCPY(p->tp_ucddata, M_WAIT); - - if(p->tp_state == TP_OPEN) { - tp_euntimeout(p, TM_data_retrans); /* all */ - tp_cuntimeout(p, TM_inact); - tp_cuntimeout(p, TM_sendack); - p->tp_flags &= ~TPF_DELACK; - } - if (data) { - IFDEBUG(D_CONN) - printf("T_DISC_req.trans tp_ucddata 0x%x\n", - p->tp_ucddata); - dump_mbuf(data, "ucddata @ T_DISC_req"); - ENDDEBUG - } - tp_soisdisconnecting(p->tp_sock); - p->tp_retrans = p->tp_Nretrans; - tp_ctimeout(p, TM_retrans, (int)p->tp_dr_ticks); - - if( trick_hc ) - return tp_emit(DR_TPDU_type, p, 0, e->ev_union.EV_T_DISC_req.e_reason, data); - } - break; -case 0x25: - { - int error; - struct mbuf *data = MCPY(p->tp_ucddata, M_WAIT); - - IncStat(ts_retrans_cc); - p->tp_retrans --; - p->tp_cong_win = 1 * p->tp_l_tpdusize; - - if( error = tp_emit(CC_TPDU_type, p, 0, 0, data) ) - p->tp_sock->so_error = error; - tp_ctimeout(p, TM_retrans, (int)p->tp_cc_ticks); - } - break; -case 0x26: - { - IncStat(ts_conn_gaveup); - tp_soisdisconnecting(p->tp_sock); - p->tp_sock->so_error = ETIMEDOUT; - tp_indicate(T_DISCONNECT, p, ETIMEDOUT); - (void) tp_emit(DR_TPDU_type, p, 0, E_TP_CONGEST, MNULL); - p->tp_retrans = p->tp_Nretrans; - tp_ctimeout(p, TM_retrans, (int)p->tp_dr_ticks); - } - break; -case 0x27: - { - tp_euntimeout(p, TM_data_retrans); /* all */ - tp_cuntimeout(p, TM_inact); - tp_cuntimeout(p, TM_sendack); - - IncStat(ts_conn_gaveup); - tp_soisdisconnecting(p->tp_sock); - p->tp_sock->so_error = ETIMEDOUT; - tp_indicate(T_DISCONNECT, p, ETIMEDOUT); - (void) tp_emit(DR_TPDU_type, p, 0, E_TP_CONGEST_2, MNULL); - p->tp_retrans = p->tp_Nretrans; - tp_ctimeout(p, TM_retrans, (int)p->tp_dr_ticks); - } - break; -case 0x28: - { - p->tp_cong_win = 1 * p->tp_l_tpdusize; - /* resume XPD */ - if ( p->tp_Xsnd.sb_mb ) { - struct mbuf *m = m_copy(p->tp_Xsnd.sb_mb, 0, (int)p->tp_Xsnd.sb_cc); - int shift; - - IFTRACE(D_XPD) - tptrace(TPPTmisc, "XPD retrans: Xuna Xsndnxt sndnxt snduna", - p->tp_Xuna, p->tp_Xsndnxt, p->tp_sndnxt, - p->tp_snduna); - ENDTRACE - IFDEBUG(D_XPD) - dump_mbuf(m, "XPD retrans emitting M"); - ENDDEBUG - IncStat(ts_retrans_xpd); - p->tp_retrans --; - shift = max(p->tp_Nretrans - p->tp_retrans, 6); - (void) tp_emit(XPD_TPDU_type, p, p->tp_Xuna, 1, m); - tp_ctimeout(p, TM_retrans, ((int)p->tp_dt_ticks) << shift); - } - } - break; -case 0x29: - { - p->tp_rxtshift++; - (void) tp_data_retrans(p); - } - break; -case 0x2a: - { - p->tp_retrans --; - (void) tp_emit(DR_TPDU_type, p, 0, E_TP_DR_NO_REAS, MNULL); - IncStat(ts_retrans_dr); - tp_ctimeout(p, TM_retrans, (int)p->tp_dr_ticks); - } - break; -case 0x2b: - { - p->tp_sock->so_error = ETIMEDOUT; - p->tp_refstate = REF_FROZEN; - tp_recycle_tsuffix( p ); - tp_etimeout(p, TM_reference, (int)p->tp_refer_ticks); - } - break; -case 0x2c: - { - tp_freeref(p->tp_lref); - tp_detach(p); - } - break; -case 0x2d: - { - if( p->tp_class != TP_CLASS_0) { - tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); - if ( e->ev_number == CC_TPDU ) - (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL); - } - /* ignore it if class 0 - state tables are blank for this */ - } - break; -case 0x2e: - { - IFTRACE(D_DATA) - tptrace(TPPTmisc, "T_DATA_req sndnxt snduna fcredit, tpcb", - p->tp_sndnxt, p->tp_snduna, p->tp_fcredit, p); - ENDTRACE - - tp_send(p); - } - break; -case 0x2f: - { - int error = 0; - - /* resume XPD */ - if ( p->tp_Xsnd.sb_mb ) { - struct mbuf *m = m_copy(p->tp_Xsnd.sb_mb, 0, (int)p->tp_Xsnd.sb_cc); - /* m_copy doesn't preserve the m_xlink field, but at this pt. - * that doesn't matter - */ - - IFTRACE(D_XPD) - tptrace(TPPTmisc, "XPD req: Xuna Xsndnxt sndnxt snduna", - p->tp_Xuna, p->tp_Xsndnxt, p->tp_sndnxt, - p->tp_snduna); - ENDTRACE - IFDEBUG(D_XPD) - printf("T_XPD_req: sb_cc 0x%x\n", p->tp_Xsnd.sb_cc); - dump_mbuf(m, "XPD req emitting M"); - ENDDEBUG - error = - tp_emit(XPD_TPDU_type, p, p->tp_Xuna, 1, m); - p->tp_retrans = p->tp_Nretrans; - - tp_ctimeout(p, TM_retrans, (int)p->tp_rxtcur); - SEQ_INC(p, p->tp_Xsndnxt); - } - if(trick_hc) - return error; - } - break; -case 0x30: - { - struct sockbuf *sb = &p->tp_sock->so_snd; - - IFDEBUG(D_ACKRECV) - printf("GOOD ACK seq 0x%x cdt 0x%x\n", e->ev_union.EV_AK_TPDU.e_seq, e->ev_union.EV_AK_TPDU.e_cdt); - ENDDEBUG - if( p->tp_class != TP_CLASS_0) { - tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); - } - sbwakeup(sb); - IFDEBUG(D_ACKRECV) - printf("GOOD ACK new sndnxt 0x%x\n", p->tp_sndnxt); - ENDDEBUG - } - break; -case 0x31: - { - IFTRACE(D_ACKRECV) - tptrace(TPPTmisc, "BOGUS ACK fcc_present, tp_r_subseq e_subseq", - e->ev_union.EV_AK_TPDU.e_fcc_present, p->tp_r_subseq, e->ev_union.EV_AK_TPDU.e_subseq, 0); - ENDTRACE - if( p->tp_class != TP_CLASS_0 ) { - - if ( !e->ev_union.EV_AK_TPDU.e_fcc_present ) { - /* send ACK with FCC */ - IncStat( ts_ackreason[_ACK_FCC_] ); - (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 1, MNULL); - } - tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); - } - } - break; -case 0x32: - { - tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); - tp_cuntimeout(p, TM_retrans); - - sbwakeup( &p->tp_sock->so_snd ); - - /* resume normal data */ - tp_send(p); - } - break; -case 0x33: - { - IFTRACE(D_ACKRECV) - tptrace(TPPTmisc, "BOGUS XACK eventtype ", e->ev_number, 0, 0,0); - ENDTRACE - if( p->tp_class != TP_CLASS_0 ) { - tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); - } - } - break; -case 0x34: - { - int timo; - IFTRACE(D_TIMER) - tptrace(TPPTsendack, -1, p->tp_lcredit, p->tp_sent_uwe, - p->tp_sent_lcdt, 0); - ENDTRACE - IncPStat(p, tps_n_TMsendack); - (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL); - if (p->tp_fcredit == 0) { - if (p->tp_rxtshift < TP_MAXRXTSHIFT) - p->tp_rxtshift++; - timo = (p->tp_dt_ticks) << p->tp_rxtshift; - } else - timo = p->tp_sendack_ticks; - tp_ctimeout(p, TM_sendack, timo); - } - break; -case 0x35: - { - if (sbspace(&p->tp_sock->so_rcv) > 0) - tp0_openflow(p); - } - break; -case 0x36: - { - if( trick_hc ) { - SeqNum ack_thresh; - /* - * If the upper window edge has advanced a reasonable - * amount beyond what was known, send an ACK. - * A reasonable amount is 2 packets, unless the max window - * is only 1 or 2 packets, in which case we - * should send an ack for any advance in the upper window edge. - */ - LOCAL_CREDIT(p); - ack_thresh = SEQ_SUB(p, p->tp_lcredit + p->tp_rcvnxt, - (p->tp_maxlcredit > 2 ? 2 : 1)); - if (SEQ_GT(p, ack_thresh, p->tp_sent_uwe)) { - IncStat(ts_ackreason[_ACK_USRRCV_]); - p->tp_flags &= ~TPF_DELACK; - return tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL); - } - } - } - break; -case 0x37: - { - if(trick_hc) - return ECONNABORTED; - } - break; -case 0x38: - { - ASSERT( p->tp_state != TP_LISTENING ); - tp_indicate(T_DISCONNECT, p, ECONNRESET); - tp_soisdisconnected(p); - } - break; - } -return 0; -} - -_XEBEC_PG int -_Xebec_index( e,p ) - struct tp_event *e; - tp_PCB_ *p; -{ -switch( (e->ev_number<<4)+(p->tp_state) ) { -case 0x12: - if ( p->tp_retrans > 0 ) return 0x1e; - else return 0x1f; -case 0x13: - if ( p->tp_retrans > 0 ) return 0x2f; - else return 0x30; -case 0x14: - if ( p->tp_retrans > 0 ) return 0x32; - else return 0x31; -case 0x15: - if ( p->tp_retrans > 0 ) return 0x34; - else return 0x35; -case 0x54: - if (p->tp_rxtshift < TP_NRETRANS) return 0x33; - else return 0x31; -case 0x64: - if (p->tp_class == TP_CLASS_0) return 0x1a; - else return 0x1b; -case 0x77: - if ( p->tp_class == TP_CLASS_0) return 0xd; - else return 0xe; -case 0x86: - if ( e->ev_union.EV_DR_TPDU.e_sref != 0 ) return 0x2; - else return 0x3; -case 0xa2: - if (p->tp_class == TP_CLASS_0) return 0x1c; - else return 0x1d; -case 0xb2: - if (p->tp_class == TP_CLASS_0) return 0x5; - else return 0x0; -case 0xb4: - if ( tp_goodack(p, e->ev_union.EV_AK_TPDU.e_cdt, e->ev_union.EV_AK_TPDU.e_seq, e->ev_union.EV_AK_TPDU.e_subseq) ) return 0x3a; - else return 0x3b; -case 0xc3: - if ( IN_RWINDOW( p, e->ev_union.EV_DT_TPDU.e_seq, - p->tp_rcvnxt, SEQ(p, p->tp_rcvnxt + p->tp_lcredit)) ) return 0x21; - else return 0x24; -case 0xc4: - if ( p->tp_class == TP_CLASS_0 ) return 0x22; - else if ( IN_RWINDOW( p, e->ev_union.EV_DT_TPDU.e_seq, - p->tp_rcvnxt, SEQ(p, p->tp_rcvnxt + p->tp_lcredit)) ) return 0x23; - else return 0x25; -case 0xd3: - if (p->tp_Xrcvnxt == e->ev_union.EV_XPD_TPDU.e_seq) return 0x27; - else return 0x2a; -case 0xd4: - if (p->tp_Xrcvnxt == e->ev_union.EV_XPD_TPDU.e_seq) return 0x27; - else return 0x29; -case 0xe4: - if ( tp_goodXack(p, e->ev_union.EV_XAK_TPDU.e_seq) ) return 0x3c; - else return 0x3d; -case 0x102: - if ( p->tp_class == TP_CLASS_0 ) return 0x2d; - else return 0x2e; -case 0x104: - if ( p->tp_class == TP_CLASS_0 ) return 0x2d; - else return 0x2e; -case 0x144: - if (p->tp_class == TP_CLASS_0) return 0x3f; - else return 0x40; -case 0x162: - if (p->tp_class == TP_CLASS_0) return 0x2b; - else return 0x2c; -case 0x172: - if ( p->tp_class != TP_CLASS_4 ) return 0x42; - else return 0x46; -case 0x174: - if ( p->tp_class != TP_CLASS_4 ) return 0x42; - else return 0x47; -case 0x177: - if ( p->tp_class != TP_CLASS_4 ) return 0x42; - else return 0x43; -case 0x188: - if ( p->tp_class == TP_CLASS_0 ) return 0xf; - else if (tp_emit(CC_TPDU_type, p, 0,0, MCPY(p->tp_ucddata, M_NOWAIT)) == 0) return 0x10; - else return 0x11; -default: return 0; -} /* end switch */ -} /* _Xebec_index() */ -static int inx[26][9] = { {0,0,0,0,0,0,0,0,0,}, - {0x0,0x0,0x0,0x0,0x31,0x0,0x0,0x0,0x0, }, - {0x0,0x0,-1,-1,-1,-1,0x0,0x0,0x0, }, - {0x0,0x0,0x0,0x0,0x3e,0x0,0x0,0x0,0x0, }, - {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, }, - {0x0,0x0,0x0,0x0,0x0,0x0,0x36,0x0,0x0, }, - {0x0,0x0,0x0,0x0,-1,0x0,0x0,0x0,0x0, }, - {0x0,0x7,0x15,0x1b,-1,0x17,0x3,0xa,0x0, }, - {0x0,0x19,0x6,0x20,0x37,0x8,0x3,-1,0x0, }, - {0x0,0x14,0x13,0x13,0x13,0x16,-1,0xa,0x0, }, - {0x0,0x7,0x6,0x1,0x9,0x18,0x3,0xa,0x0, }, - {0x0,0x19,-1,0x1,0x37,0x8,0x3,0xa,0x0, }, - {0x0,0x7,-1,0x26,-1,0x8,0x3,0xa,0x0, }, - {0x0,0x7,0x6,-1,-1,0x8,0x3,0xa,0x0, }, - {0x0,0x7,0x6,-1,-1,0x8,0x3,0xa,0x0, }, - {0x0,0x7,0x6,0x1,-1,0x8,0x3,0xa,0x0, }, - {0x0,0x12,0x0,0x0,0x0,0x0,0x0,0x0,0x0, }, - {0x0,0x0,-1,0x2e,-1,0x0,0x4,0x0,0x2e, }, - {0x0,0xb,0x0,0x0,0x0,0x0,0x0,0x0,0x0, }, - {0x0,0x0,0x0,0x0,0x38,0x0,0x0,0x0,0x0, }, - {0x0,0x0,0x0,0x0,0x39,0x0,0x0,0x0,0x0, }, - {0x0,0x0,0x0,0x0,-1,0x0,0x41,0x0,0x0, }, - {0x0,0x0,0x0,0x0,0x28,0x0,0x41,0x0,0x0, }, - {0x0,0xc,-1,0x2c,0x0,0x2c,0x4,0xc,0x2c, }, - {0x0,0x49,-1,0x45,-1,0x44,0x48,-1,0x0, }, - {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,-1, }, -}; -tp_driver(p, e) -register tp_PCB_ *p; -register struct tp_event *e; -{ - register int index, error=0; - struct act_ent *a; - static struct act_ent erroraction = {0,-1}; - - index = inx[1 + e->ev_number][p->tp_state]; - if(index<0) index=_Xebec_index(e, p); - if (index==0) { - a = &erroraction; - } else - a = &statetable[index]; - - if(a->a_action) - error = _Xebec_action( a->a_action, e, p ); - IFTRACE(D_DRIVER) - tptrace(DRIVERTRACE, a->a_newstate, p->tp_state, e->ev_number, a->a_action, 0); - ENDTRACE - if(error==0) - p->tp_state = a->a_newstate; - return error; -} diff --git a/bsd/netiso/tp_emit.c b/bsd/netiso/tp_emit.c deleted file mode 100644 index 07cfdd0d8..000000000 --- a/bsd/netiso/tp_emit.c +++ /dev/null @@ -1,1015 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)tp_emit.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * ARGO TP - * - * This file contains tp_emit() and tp_error_emit(), which - * form TPDUs and hand them to ip. - * They take data in the form of mbuf chain, allocate mbufs as - * necessary for headers, and set the fields as appropriate from - * information found in the tpcb and net-level pcb. - * - * The worst thing about this code is adding the variable-length - * options on a machine that requires alignment for any memory access - * that isn't of size 1. See the macro ADDOPTION() below. - * - * We don't do any concatenation. (There's a kludge to test the - * basic mechanism of separation under the 'w' tpdebug option, that's all.) - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#ifdef TRUE -#undef FALSE -#undef TRUE -#endif -#include -#include -#include - -void iso_gen_csum(); - - -/* Here is a mighty kludge. The token ring misorders packets if you - * fire them at it too fast, and TP sans checksum is "too fast", so - * we have introduced a delay when checksumming isn't used. - */ -char tp_delay = 0x00; /* delay to keep token ring from blowing it */ - -/* - * NAME: tp_emit() - * - * CALLED FROM: tp.trans and from tp_sbsend() - * - * FUNCTION and ARGUMENTS: - * Emits one tpdu of the type (dutype), of the format appropriate - * to the connection described by the pcb (tpcb), with sequence - * number (seq) (where appropriate), end-of-tsdu bit (eot) where - * appropriate, and with the data in the mbuf chain (data). - * For DR and ER tpdus, the argument (eot) is - * the reason for issuing the tpdu rather than an end-of-tsdu indicator. - * - * RETURNS: - * 0 OK - * ENOBUFS - * E* returned from net layer output rtn - * - * SIDE EFFECTS: - * - * NOTES: - * - * WE ASSUME that the tp header + all options will fit in ONE mbuf. - * If mbufs are 256 this will most likely be true, but if they are 128 it's - * possible that they won't. - * If you used every option on the CR + max. user data you'd overrun - * 112 but unless you used > 115 bytes for the security - * parameter, it would fit in a 256-byte mbuf (240 bytes for the header) - * We don't support the security parameter, so this isn't a problem. - * If security is added, we ought to remove this assumption. - * - * We do not implement the flow control confirmation "element of procedure". - * A) it should not affect interoperability, - * B) it should not be necessary - the protocol will eventually - * straighten things out w/o FCC, as long as we don't have severely - * mismatched keepalive and inactivity timers, and - * C) it appears not to be REQUIRED, and - * D) it's incredibly grotesque, and no doubt will lengthen a few - * critical paths. - * HOWEVER, we're thinking about putting it in anyway, for - * completeness, just like we did with ack subsequencing. - */ - -int -tp_emit(dutype, tpcb, seq, eot, data) - int dutype; - struct tp_pcb *tpcb; - SeqNum seq; - u_int eot; - struct mbuf *data; -{ - register struct tpdu *hdr; - register struct mbuf *m; - int csum_offset=0; - int datalen = 0; - int error = 0; - SeqNum olduwe; - int acking_ooo; - - /* NOTE: - * here we treat tpdu_li as if it DID include the li field, up until - * the end, at which time we subtract 1 - * THis is because if we subtract 1 right away, we end up adding - * one every time we add an option. - */ - IFDEBUG(D_EMIT) - printf( - "tp_emit dutype 0x%x, tpcb 0x%x, eot 0x%x, seq 0x%x, data 0x%x", - dutype, tpcb, eot, seq, data); - ENDDEBUG - - if (dutype == CR_TPDU || dutype == CC_TPDU) { -// m = (struct mbuf *) malloc((u_long)256, M_MBUF, M_DONTWAIT); - MALLOC(m, struct mbuf *, 256, M_MBUF, M_NOWAIT); - if (m) { - m->m_type = TPMT_TPHDR; - mbstat.m_mtypes[TPMT_TPHDR]++; - m->m_next = MNULL; - m->m_nextpkt = MNULL; - m->m_data = m->m_pktdat; - m->m_flags = M_PKTHDR; - } - } else { - MGETHDR(m, M_DONTWAIT, TPMT_TPHDR); - } - m->m_data += max_hdr; - if (m == NULL) { - if(data != (struct mbuf *)0) - m_freem(data); - error = ENOBUFS; - goto done; - } - m->m_len = sizeof(struct tpdu); - m->m_act = MNULL; - - hdr = mtod(m, struct tpdu *); - bzero((caddr_t)hdr, sizeof(struct tpdu)); - - { - int tp_headersize(); - - hdr->tpdu_type = dutype; - hdr->tpdu_li = tp_headersize(dutype, tpcb); - /* - * class 0 doesn't use this for DT - * it'll just get overwritten below - */ - hdr->tpdu_dref = htons(tpcb->tp_fref); - if( tpcb->tp_use_checksum || - (dutype == CR_TPDU_type && (tpcb->tp_class & TP_CLASS_4) )) { - csum_offset = hdr->tpdu_li + 2; /* DOESN'T include csum */ - ADDOPTION(TPP_checksum, hdr, 2, eot /* dummy arg */); - IFDEBUG(D_CHKSUM) - printf( - "tp_emit: csum_offset 0x%x, hdr->tpdu_li 0x%x\n", - csum_offset, hdr->tpdu_li); - ENDDEBUG - } - /* - * VARIABLE PARTS... - */ - switch( dutype ) { - - case CR_TPDU_type: - hdr->tpdu_CRdref_0 = 0; /* must be zero */ - case CC_TPDU_type: - if (!tpcb->tp_cebit_off) { - tpcb->tp_win_recv = tp_start_win << 8; - LOCAL_CREDIT(tpcb); - CONG_INIT_SAMPLE(tpcb); - } else - LOCAL_CREDIT(tpcb); - -/* Case CC_TPDU_type used to be here */ - { - u_char x; - - hdr->tpdu_CCsref = htons(tpcb->tp_lref); /* same as CRsref */ - - if( tpcb->tp_class > TP_CLASS_1 ) { - tpcb->tp_sent_uwe = tpcb->tp_lcredit -1; - tpcb->tp_sent_rcvnxt = 1; - tpcb->tp_sent_lcdt = tpcb->tp_lcredit; - hdr->tpdu_cdt = tpcb->tp_lcredit; - } else { -#if TPCONS - if (tpcb->tp_netservice == ISO_CONS) { - struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; - struct pklcd *lcp = (struct pklcd *)(isop->isop_chan); - lcp->lcd_flags &= ~X25_DG_CIRCUIT; - } -#endif - hdr->tpdu_cdt = 0; - } - hdr->tpdu_CCclass = tp_mask_to_num(tpcb->tp_class); - hdr->tpdu_CCoptions = - (tpcb->tp_xtd_format? TPO_XTD_FMT:0) | - (tpcb->tp_use_efc? TPO_USE_EFC:0); - - IFPERF(tpcb) - u_char perf_meas = tpcb->tp_perf_on; - ADDOPTION(TPP_perf_meas, hdr, sizeof(perf_meas), perf_meas); - ENDPERF - - if( dutype == CR_TPDU_type ) { - IncStat(ts_CR_sent); - - ASSERT( tpcb->tp_lsuffixlen > 0 ); - ASSERT( tpcb->tp_fsuffixlen > 0 ); - - ADDOPTION(TPP_calling_sufx, hdr, - tpcb->tp_lsuffixlen, tpcb->tp_lsuffix[0]); - ADDOPTION(TPP_called_sufx, hdr, - tpcb->tp_fsuffixlen, tpcb->tp_fsuffix[0]); - } else { - IncStat(ts_CC_sent); - } - - ADDOPTION(TPP_tpdu_size, hdr, - sizeof(tpcb->tp_tpdusize), tpcb->tp_tpdusize); - - if (tpcb->tp_class != TP_CLASS_0) { - short millisec = 500*(tpcb->tp_sendack_ticks); - - millisec = htons(millisec); - ADDOPTION(TPP_acktime, hdr, sizeof(short), millisec); - - x = (tpcb->tp_use_nxpd? TPAO_USE_NXPD: 0) - | (tpcb->tp_use_rcc? TPAO_USE_RCC : 0) - | (tpcb->tp_use_checksum?0: TPAO_NO_CSUM) - | (tpcb->tp_xpd_service? TPAO_USE_TXPD: 0); - ADDOPTION(TPP_addl_opt, hdr, 1, x); - - if ((tpcb->tp_l_tpdusize ^ (1 << tpcb->tp_tpdusize)) != 0) { - u_short size_s = tpcb->tp_l_tpdusize >> 7; - u_char size_c = size_s; - ASSERT(tpcb->tp_l_tpdusize < 65536 * 128); - if (dutype == CR_TPDU_type) - tpcb->tp_ptpdusize = size_s; - if (size_s < 256) { - ADDOPTION(TPP_ptpdu_size, hdr, 1, size_c); - } else { - size_s = htons(size_s); - ADDOPTION(TPP_ptpdu_size, hdr, 2, size_s); - } - } - } - - if( (dutype == CR_TPDU_type) && (tpcb->tp_class != TP_CLASS_0)){ - - ASSERT( 1 == sizeof(tpcb->tp_vers) ); - ADDOPTION(TPP_vers, hdr, 1, tpcb->tp_vers); - - /* for each alt protocol class x, - * x = x<<4; - * option = concat(option, x); - * Well, for now we only have TP0 for an - * alternative so... this is easy. - * - * HOWEVER... There should be NO alt protocol - * class over CLNS. Need to see if the route suggests - * CONS, and iff so add alt class. - */ - x = 0; - ADDOPTION(TPP_alt_class, hdr, 1, x); - } - - if( hdr->tpdu_li > MLEN) - panic("tp_emit CR/CC"); - } - break; - - case DR_TPDU_type: - if( hdr->tpdu_DRdref == 0 ) { - /* don't issue the DR */ - goto done; - } - hdr->tpdu_cdt = 0; - hdr->tpdu_DRsref = htons(tpcb->tp_lref); - hdr->tpdu_DRreason = (u_char)eot; /* WHICH BYTE OF THIS??? */ - - /* forget the add'l information variable part */ - IncStat(ts_DR_sent); - break; - - case DC_TPDU_type: /* not used in class 0 */ - ASSERT( tpcb->tp_class != TP_CLASS_0); - hdr->tpdu_DCsref = htons(tpcb->tp_lref); - hdr->tpdu_cdt = 0; - data = (struct mbuf *)0; - IncStat(ts_DC_sent); - break; - - case XAK_TPDU_type: /* xak not used in class 0 */ - ASSERT( tpcb->tp_class != TP_CLASS_0); /* fall through */ - hdr->tpdu_cdt = 0; - - IFTRACE(D_XPD) - tptraceTPCB(TPPTXack, seq, 0, 0, 0, 0); - ENDTRACE - data = (struct mbuf *)0; - if (tpcb->tp_xtd_format) { -#ifdef BYTE_ORDER - union seq_type seqeotX; - - seqeotX.s_seq = seq; - seqeotX.s_eot = 1; - hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot); -#else - hdr->tpdu_XAKseqX = seq; -#endif /* BYTE_ORDER */ - } else { - hdr->tpdu_XAKseq = seq; - } - IncStat(ts_XAK_sent); - IncPStat(tpcb, tps_XAK_sent); - break; - - case XPD_TPDU_type: /* xpd not used in class 0 */ - ASSERT( tpcb->tp_class != TP_CLASS_0); /* fall through */ - hdr->tpdu_cdt = 0; - if (tpcb->tp_xtd_format) { -#ifdef BYTE_ORDER - union seq_type seqeotX; - - seqeotX.s_seq = seq; - seqeotX.s_eot = 1; - hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot); -#else - hdr->tpdu_XPDseqX = seq; - hdr->tpdu_XPDeotX = 1; /* always 1 for XPD tpdu */ -#endif /* BYTE_ORDER */ - } else { - hdr->tpdu_XPDseq = seq; - hdr->tpdu_XPDeot = 1; /* always 1 for XPD tpdu */ - } - IncStat(ts_XPD_sent); - IncPStat(tpcb, tps_XPD_sent); - - /* kludge to test the input size checking */ - IFDEBUG(D_SIZE_CHECK) - /*if(data->m_len <= 16 && data->m_off < (MLEN-18) ) { - printf("Sending too much data on XPD: 18 bytes\n"); - data->m_len = 18; - }*/ - ENDDEBUG - break; - - case DT_TPDU_type: - hdr->tpdu_cdt = 0; - IFTRACE(D_DATA) - tptraceTPCB(TPPTmisc, "emit DT: eot seq tpdu_li", eot, seq, - hdr->tpdu_li, 0); - ENDTRACE - if (tpcb->tp_xtd_format) { -#ifdef BYTE_ORDER - union seq_type seqeotX; - - seqeotX.s_seq = seq; - seqeotX.s_eot = eot; - hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot); -#else - hdr->tpdu_DTseqX = seq; - hdr->tpdu_DTeotX = eot; -#endif /* BYTE_ORDER */ - } else if (tpcb->tp_class == TP_CLASS_0) { - IFDEBUG(D_EMIT) - printf("DT tpdu: class 0 m 0x%x hdr 0x%x\n", m, hdr); - dump_buf( hdr, hdr->tpdu_li + 1 ); - ENDDEBUG - ((struct tp0du *)hdr)->tp0du_eot = eot; - ((struct tp0du *)hdr)->tp0du_mbz = 0; - IFDEBUG(D_EMIT) - printf("DT 2 tpdu: class 0 m 0x%x hdr 0x%x\n", m, hdr); - dump_buf( hdr, hdr->tpdu_li + 1 ); - ENDDEBUG - } else { - hdr->tpdu_DTseq = seq; - hdr->tpdu_DTeot = eot; - } - if(eot) { - IncStat(ts_EOT_sent); - } - IncStat(ts_DT_sent); - IncPStat(tpcb, tps_DT_sent); - break; - - case AK_TPDU_type:/* ak not used in class 0 */ - ASSERT( tpcb->tp_class != TP_CLASS_0); - data = (struct mbuf *)0; - olduwe = tpcb->tp_sent_uwe; - - if (seq != tpcb->tp_sent_rcvnxt || tpcb->tp_rsycnt == 0) { - LOCAL_CREDIT( tpcb ); - tpcb->tp_sent_uwe = - SEQ(tpcb,tpcb->tp_rcvnxt + tpcb->tp_lcredit -1); - tpcb->tp_sent_lcdt = tpcb->tp_lcredit; - acking_ooo = 0; - } else - acking_ooo = 1; - - IFDEBUG(D_RENEG) - /* occasionally fake a reneging so - you can test subsequencing */ - if( olduwe & 0x1 ) { - tpcb->tp_reneged = 1; - IncStat(ts_ldebug); - } - ENDDEBUG - /* Are we about to reneg on credit? - * When might we do so? - * a) when using optimistic credit (which we no longer do). - * b) when drain() gets implemented (not in the plans). - * c) when D_RENEG is on. - * d) when DEC BIT response is implemented. - * (not- when we do this, we'll need to implement flow control - * confirmation) - */ - if( SEQ_LT(tpcb, tpcb->tp_sent_uwe, olduwe) ) { - tpcb->tp_reneged = 1; - IncStat(ts_lcdt_reduced); - IFTRACE(D_CREDIT) - tptraceTPCB(TPPTmisc, - "RENEG: olduwe newuwe lcredit rcvnxt", - olduwe, - tpcb->tp_sent_uwe, tpcb->tp_lcredit, - tpcb->tp_rcvnxt); - ENDTRACE - } - IFPERF(tpcb) - /* new lwe is less than old uwe means we're - * acking before we received a whole window full - */ - if( SEQ_LT( tpcb, tpcb->tp_rcvnxt, olduwe) ) { - /* tmp1 = number of pkts fewer than the full window */ - register int tmp1 = - (int) SEQ_SUB( tpcb, olduwe, tpcb->tp_rcvnxt); - - if(tmp1 > TP_PM_MAX) - tmp1 = TP_PM_MAX; - IncPStat( tpcb, tps_ack_early[tmp1] ); - - /* tmp1 = amt of new cdt we're advertising */ - tmp1 = SEQ_SUB( tpcb, seq, tpcb->tp_sent_rcvnxt); - if(tmp1 > TP_PM_MAX ) - tmp1 = TP_PM_MAX; - - IncPStat( tpcb, - tps_cdt_acked [ tmp1 ] - [ ((tpcb->tp_lcredit > TP_PM_MAX)? - TP_PM_MAX:tpcb->tp_lcredit) ] ); - - } - ENDPERF - - IFTRACE(D_ACKSEND) - tptraceTPCB(TPPTack, seq, tpcb->tp_lcredit, tpcb->tp_sent_uwe, - tpcb->tp_r_subseq, 0); - ENDTRACE - if (tpcb->tp_xtd_format) { -#ifdef BYTE_ORDER - union seq_type seqeotX; - - seqeotX.s_seq = seq; - seqeotX.s_eot = 0; - hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot); - hdr->tpdu_AKcdtX = htons(tpcb->tp_lcredit); -#else - hdr->tpdu_cdt = 0; - hdr->tpdu_AKseqX = seq; - hdr->tpdu_AKcdtX = tpcb->tp_lcredit; -#endif /* BYTE_ORDER */ - } else { - hdr->tpdu_AKseq = seq; - hdr->tpdu_AKcdt = tpcb->tp_lcredit; - } - if ((tpcb->tp_class == TP_CLASS_4) && - (tpcb->tp_reneged || acking_ooo)) { - /* - * Ack subsequence parameter req'd if WE reneged on - * credit offered. (ISO 8073, 12.2.3.8.2, p. 74) - */ - IFDEBUG(D_RENEG) - printf("Adding subseq 0x%x\n", tpcb->tp_s_subseq); - ENDDEBUG - tpcb->tp_s_subseq++; - /* - * add tmp subseq and do a htons on it. - */ - ADDOPTION(TPP_subseq, hdr, - sizeof(tpcb->tp_s_subseq), tpcb->tp_s_subseq); - } else - tpcb->tp_s_subseq = 0; - - if ( tpcb->tp_sendfcc || eot ) /* overloaded to mean SEND FCC */ { - /* - * Rules for sending FCC ("should" send when) : - * %a) received an ack from peer with NO NEWS whatsoever, - * and it did not contain an FCC - * b) received an ack from peer that opens its closed window. - * c) received an ack from peer after it reneged on its - * offered credit, AND this ack raises UWE but LWE is same - * and below UWE at time of reneging (reduction) - * Now, ISO 8073 12.2.3.8.3 says - * that a retransmitted AK shall not contain the FCC - * parameter. Now, how the hell you tell the difference - * between a retransmitted ack and an ack that's sent in - * response to a received ack, I don't know, because without - * any local activity, and w/o any received DTs, they - * will contain exactly the same credit/seq# information. - * Anyway, given that the "retransmission of acks" - * procedure (ISO 8073 12.2.3.8.3) is optional, and we - * don't do it (although the peer can't tell that), we - * ignore this last rule. - * - * We send FCC for reasons a) and b) only. - * To add reason c) would require a ridiculous amount of state. - * - */ - u_short bogus[4]; /* lwe(32), subseq(16), cdt(16) */ - SeqNum lwe; - u_short subseq, fcredit; - - tpcb->tp_sendfcc = 0; - - lwe = (SeqNum) htonl(tpcb->tp_snduna); - subseq = htons(tpcb->tp_r_subseq); - fcredit = htons(tpcb->tp_fcredit); - - bcopy((caddr_t) &lwe, (caddr_t)&bogus[0], sizeof(SeqNum)); - bcopy((caddr_t) &subseq, (caddr_t)&bogus[2], sizeof(u_short)); - bcopy((caddr_t) &fcredit, (caddr_t)&bogus[3], sizeof(u_short)); - - IFTRACE(D_ACKSEND) - tptraceTPCB(TPPTmisc, - "emit w/FCC: snduna r_subseq fcredit", - tpcb->tp_snduna, tpcb->tp_r_subseq, - tpcb->tp_fcredit, 0); - ENDTRACE - - IFDEBUG(D_ACKSEND) - printf("Calling ADDOPTION 0x%x, 0x%x, 0x%x,0x%x\n", - TPP_flow_cntl_conf, - hdr, sizeof(bogus), bogus[0]); - ENDDEBUG - ADDOPTION(TPP_flow_cntl_conf, hdr, sizeof(bogus), bogus[0]); - IFDEBUG(D_ACKSEND) - printf("after ADDOPTION hdr 0x%x hdr->tpdu_li 0x%x\n", - hdr, hdr->tpdu_li); - printf( - "after ADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n", - csum_offset, hdr->tpdu_li); - ENDDEBUG - - } - tpcb->tp_reneged = 0; - tpcb->tp_sent_rcvnxt = seq; - if (tpcb->tp_fcredit == 0) { - int timo = tpcb->tp_keepalive_ticks; - if (tpcb->tp_rxtshift < TP_MAXRXTSHIFT) - tpcb->tp_rxtshift++; - timo = min(timo, ((int)tpcb->tp_dt_ticks) << tpcb->tp_rxtshift); - tp_ctimeout(tpcb, TM_sendack, timo); - } else - tp_ctimeout(tpcb, TM_sendack, tpcb->tp_keepalive_ticks); - IncStat(ts_AK_sent); - IncPStat(tpcb, tps_AK_sent); - IFDEBUG(D_ACKSEND) - printf( - "2 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n", - csum_offset, hdr->tpdu_li); - ENDDEBUG - break; - - case ER_TPDU_type: - hdr->tpdu_ERreason = eot; - hdr->tpdu_cdt = 0; - /* no user data */ - data = (struct mbuf *)0; - IncStat(ts_ER_sent); - break; - } - - } - ASSERT( ((int)hdr->tpdu_li > 0) && ((int)hdr->tpdu_li < MLEN) ); - - m->m_next = data; - - ASSERT( hdr->tpdu_li < MLEN ); /* leave this in */ - ASSERT( hdr->tpdu_li != 0 ); /* leave this in */ - - m->m_len = hdr->tpdu_li ; - hdr->tpdu_li --; /* doesn't include the li field */ - - datalen = m_datalen( m ); /* total len */ - - ASSERT( datalen <= tpcb->tp_l_tpdusize ); /* may become a problem - when CLNP is used; leave in here for the time being */ - IFDEBUG(D_ACKSEND) - printf( - "4 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n", - csum_offset, hdr->tpdu_li); - ENDDEBUG - if( datalen > tpcb->tp_l_tpdusize ) { - printf("data len 0x%x tpcb->tp_l_tpdusize 0x%x\n", - datalen, tpcb->tp_l_tpdusize); - } - IFDEBUG(D_EMIT) - printf( - "tp_emit before gen_csum m_len 0x%x, csum_offset 0x%x, datalen 0x%x\n", - m->m_len, csum_offset, datalen); - ENDDEBUG - if( tpcb->tp_use_checksum || - (dutype == CR_TPDU_type && (tpcb->tp_class & TP_CLASS_4)) ) { - iso_gen_csum(m, csum_offset, datalen); - } - - IFDEBUG(D_EMIT) - printf("tp_emit before tpxxx_output tpcb 0x%x, dutype 0x%x, datalen 0x%x\n", - tpcb, dutype, datalen); - dump_buf(mtod(m, caddr_t), datalen); - ENDDEBUG - - IFPERF(tpcb) - if( dutype == DT_TPDU_type ) { - PStat(tpcb, Nb_to_ll) += (datalen - m->m_len); - tpmeas( tpcb->tp_lref, TPtime_to_ll, (struct timeval *)0, - seq, PStat(tpcb, Nb_to_ll), (datalen - m->m_len)); - } - ENDPERF - - IFTRACE(D_EMIT) - tptraceTPCB(TPPTtpduout, dutype, hdr, hdr->tpdu_li+1, datalen, 0); - ENDTRACE - IFDEBUG(D_EMIT) - printf("OUTPUT: tpcb 0x%x, isop 0x%x, so 0x%x\n", - tpcb, tpcb->tp_npcb, tpcb->tp_sock); - ENDDEBUG - - { extern char tp_delay; - - if( tp_delay ) - if( tpcb->tp_use_checksum == 0 ) { - register u_int i = tp_delay; - for (; i!= 0; i--) - (void) iso_check_csum(m, datalen); - } - } - ASSERT( m->m_len > 0 ); - error = (tpcb->tp_nlproto->nlp_output)(tpcb->tp_npcb, m, datalen, - !tpcb->tp_use_checksum); - IFDEBUG(D_EMIT) - printf("OUTPUT: returned 0x%x\n", error); - ENDDEBUG - IFTRACE(D_EMIT) - tptraceTPCB(TPPTmisc, - "tp_emit nlproto->output netservice returns datalen", - tpcb->tp_nlproto->nlp_output, tpcb->tp_netservice, error, datalen); - ENDTRACE -done: - if (error) { - if (dutype == AK_TPDU_type) - tp_ctimeout(tpcb, TM_sendack, 1); - if (error == E_CO_QFULL) { - tp_quench(tpcb, PRC_QUENCH); - return 0; - } - } - return error; -} -/* - * NAME: tp_error_emit() - * CALLED FROM: tp_input() when a DR or ER is to be issued in - * response to an input error. - * FUNCTION and ARGUMENTS: - * The error type is the first argument. - * The argument (sref) is the source reference on the bad incoming tpdu, - * and is used for a destination reference on the outgoing packet. - * (faddr) and (laddr) are the foreign and local addresses for this - * connection. - * (erdata) is a ptr to the errant incoming tpdu, and is copied into the - * outgoing ER, if an ER is to be issued. - * (erlen) is the number of octets of the errant tpdu that we should - * try to copy. - * (tpcb) is the pcb that describes the connection for which the bad tpdu - * arrived. - * RETURN VALUES: - * 0 OK - * ENOBUFS - * E* from net layer datagram output routine - * SIDE EFFECTS: - * - * NOTES: - */ - -int -tp_error_emit(error, sref, faddr, laddr, erdata, erlen, tpcb, cons_channel, - dgout_routine) - int error; - u_long sref; - struct sockaddr_iso *faddr, *laddr; - struct mbuf *erdata; - int erlen; - struct tp_pcb *tpcb; - caddr_t cons_channel; - int (*dgout_routine)(); -{ - int dutype; - int datalen = 0; - register struct tpdu *hdr; - register struct mbuf *m; - int csum_offset; - - IFTRACE(D_ERROR_EMIT) - tptrace(TPPTmisc, "tp_error_emit error sref tpcb erlen", - error, sref, tpcb, erlen); - ENDTRACE - IFDEBUG(D_ERROR_EMIT) - printf( - "tp_error_emit error 0x%x sref 0x%x tpcb 0x%x erlen 0x%x chan 0x%x\n", - error, sref, tpcb, erlen, cons_channel); - ENDDEBUG - - MGET(m, M_DONTWAIT, TPMT_TPHDR); - if (m == NULL) { - return ENOBUFS; - } - m->m_len = sizeof(struct tpdu); - m->m_act = MNULL; - - hdr = mtod(m, struct tpdu *); - - IFDEBUG(D_ERROR_EMIT) - printf("[error 0x%x] [error&0xff 0x%x] [(char)error 0x%x]\n", - error, error&0xff, (char)error); - ENDDEBUG - - - if (error & TP_ERROR_SNDC) - dutype = DC_TPDU_type; - else if (error & 0x40) { - error &= ~0x40; - dutype = ER_TPDU_type; - } else - dutype = DR_TPDU_type; - error &= 0xff; - - hdr->tpdu_type = dutype; - hdr->tpdu_cdt = 0; - - switch( dutype ) { - - case DC_TPDU_type: - IncStat(ts_DC_sent); - hdr->tpdu_li = 6; - hdr->tpdu_DCdref = htons(sref); - hdr->tpdu_DCsref = tpcb ? htons(tpcb->tp_lref) : 0; - IFDEBUG(D_ERROR_EMIT) - printf("DC case:\n"); - dump_buf( hdr, 6); - ENDDEBUG - /* forget the add'l information variable part */ - break; - - case DR_TPDU_type: - IncStat(ts_DR_sent); - hdr->tpdu_li = 7; - hdr->tpdu_DRdref = htons(sref); - hdr->tpdu_DRsref = 0; - hdr->tpdu_DRreason = (char)error; - IFDEBUG(D_ERROR_EMIT) - printf("DR case:\n"); - dump_buf( hdr, 7); - ENDDEBUG - /* forget the add'l information variable part */ - break; - - case ER_TPDU_type: - IncStat(ts_ER_sent); - hdr->tpdu_li = 5; - hdr->tpdu_ERreason = (char)error; - hdr->tpdu_ERdref = htons(sref); - break; - - default: - ASSERT(0); - printf("TP PANIC: bad dutype 0x%x\n", dutype); - } - - if(tpcb) - if( tpcb->tp_use_checksum ) { - ADDOPTION(TPP_checksum, hdr, 2, csum_offset /* dummy argument */); - csum_offset = hdr->tpdu_li - 2; - } - - ASSERT( hdr->tpdu_li < MLEN ); - - if (dutype == ER_TPDU_type) { - /* copy the errant tpdu into another 'variable part' */ - register caddr_t P; - - IFTRACE(D_ERROR_EMIT) - tptrace(TPPTmisc, "error_emit ER len tpduli", erlen, hdr->tpdu_li, - 0,0); - ENDTRACE - IFDEBUG(D_ERROR_EMIT) - printf("error_emit ER len 0x%x tpduli 0x%x\n", erlen, hdr->tpdu_li); - ENDDEBUG - - /* copy at most as many octets for which you have room */ - if (erlen + hdr->tpdu_li + 2 > TP_MAX_HEADER_LEN) - erlen = TP_MAX_HEADER_LEN - hdr->tpdu_li - 2; - - /* add the "invalid tpdu" parameter : required in class 0 */ - P = (caddr_t)hdr + (int)(hdr->tpdu_li); - vbptr(P)->tpv_code = TPP_invalid_tpdu; /* parameter code */ - vbptr(P)->tpv_len = erlen; /* parameter length */ - m->m_len = hdr->tpdu_li + 2; /* 1 for code, 1 for length */ - - /* tp_input very likely handed us an mbuf chain w/ nothing in - * the first mbuf and the data following the empty mbuf - */ - if(erdata->m_len == 0) { - erdata = m_free(erdata); /* returns the next mbuf on the chain */ - } - /* - * copy only up to the bad octet - * (or max that will fit in a header - */ - m->m_next = m_copy(erdata, 0, erlen); - hdr->tpdu_li += erlen + 2; - m_freem(erdata); - } else { - IFDEBUG(D_ERROR_EMIT) - printf("error_emit DR error tpduli 0x%x\n", error, hdr->tpdu_li); - dump_buf( (char *)hdr, hdr->tpdu_li ); - ENDDEBUG - m->m_len = hdr->tpdu_li ; - m_freem(erdata); - } - - hdr->tpdu_li --; - IFTRACE(D_ERROR_EMIT) - tptrace(TPPTtpduout, 2, hdr, hdr->tpdu_li+1, 0, 0); - ENDTRACE - - datalen = m_datalen( m); - if (tpcb) { - if( tpcb->tp_use_checksum ) { - IFTRACE(D_ERROR_EMIT) - tptrace(TPPTmisc, "before gen csum datalen", datalen,0,0,0); - ENDTRACE - IFDEBUG(D_ERROR_EMIT) - printf("before gen csum datalen 0x%x, csum_offset 0x%x\n", - datalen, csum_offset); - ENDDEBUG - - iso_gen_csum(m, csum_offset, datalen); - } - - IFDEBUG(D_ERROR_EMIT) - printf("OUTPUT: tpcb 0x%x, isop 0x%x, so 0x%x\n", - tpcb, tpcb->tp_npcb, tpcb->tp_sock); - ENDDEBUG - } - if (cons_channel) { -#if TPCONS - struct pklcd *lcp = (struct pklcd *)cons_channel; - struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext; - - tpcons_dg_output(cons_channel, m, datalen); - /* was if (tpcb == 0) iso_pcbdetach(isop); */ - /* but other side may want to try again over same VC, - so, we'll depend on him closing it, but in case it gets forgotten - we'll mark it for garbage collection */ - lcp->lcd_flags |= X25_DG_CIRCUIT; - IFDEBUG(D_ERROR_EMIT) - printf("OUTPUT: dutype 0x%x channel 0x%x\n", - dutype, cons_channel); - ENDDEBUG -#else - printf("TP panic! cons channel 0x%x but not cons configured\n", - cons_channel); -#endif - } else if (tpcb) { - - IFDEBUG(D_ERROR_EMIT) - printf("tp_error_emit 1 sending DG: Laddr\n"); - dump_addr((struct sockaddr *)laddr); - printf("Faddr\n"); - dump_addr((struct sockaddr *)faddr); - ENDDEBUG - return (tpcb->tp_nlproto->nlp_dgoutput)( - &laddr->siso_addr, - &faddr->siso_addr, - m, datalen, - /* no route */ (caddr_t)0, !tpcb->tp_use_checksum); - } else if (dgout_routine) { - IFDEBUG(D_ERROR_EMIT) - printf("tp_error_emit sending DG: Laddr\n"); - dump_addr((struct sockaddr *)laddr); - printf("Faddr\n"); - dump_addr((struct sockaddr *)faddr); - ENDDEBUG - return (*dgout_routine)( &laddr->siso_addr, &faddr->siso_addr, - m, datalen, /* no route */ - (caddr_t)0, /* nochecksum==false */0); - } else { - IFDEBUG(D_ERROR_EMIT) - printf("tp_error_emit DROPPING \n", m); - ENDDEBUG - IncStat(ts_send_drop); - m_freem(m); - return 0; - } -} diff --git a/bsd/netiso/tp_events.h b/bsd/netiso/tp_events.h deleted file mode 100644 index 739629b66..000000000 --- a/bsd/netiso/tp_events.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -struct tp_event { - int ev_number; - struct timeval e_time; -#define TM_inact 0x0 -#define TM_retrans 0x1 -#define TM_sendack 0x2 -#define TM_notused 0x3 - - union{ -struct { SeqNum e_low; SeqNum e_high; int e_retrans; } EV_TM_reference; - -#define TM_reference 0x4 -struct { SeqNum e_low; SeqNum e_high; int e_retrans; } EV_TM_data_retrans; - -#define TM_data_retrans 0x5 -struct { - u_char e_reason; - } EV_ER_TPDU; - -#define ER_TPDU 0x6 -struct { struct mbuf *e_data; /* first field */ - int e_datalen; /* 2nd field */ - u_int e_cdt; - } EV_CR_TPDU; - -#define CR_TPDU 0x7 -struct { struct mbuf *e_data; /* first field */ - int e_datalen; /* 2nd field */ - u_short e_sref; - u_char e_reason; - } EV_DR_TPDU; - -#define DR_TPDU 0x8 -#define DC_TPDU 0x9 -struct { struct mbuf *e_data; /* first field */ - int e_datalen; /* 2nd field */ - u_short e_sref; - u_int e_cdt; - } EV_CC_TPDU; - -#define CC_TPDU 0xa -struct { u_int e_cdt; - SeqNum e_seq; - SeqNum e_subseq; - u_char e_fcc_present; - } EV_AK_TPDU; - -#define AK_TPDU 0xb -struct { struct mbuf *e_data; /* first field */ - int e_datalen; /* 2nd field */ - u_int e_eot; - SeqNum e_seq; - } EV_DT_TPDU; - -#define DT_TPDU 0xc -struct { struct mbuf *e_data; /* first field */ - int e_datalen; /* 2nd field */ - SeqNum e_seq; - } EV_XPD_TPDU; - -#define XPD_TPDU 0xd -struct { SeqNum e_seq; } EV_XAK_TPDU; - -#define XAK_TPDU 0xe -#define T_CONN_req 0xf -struct { u_char e_reason; } EV_T_DISC_req; - -#define T_DISC_req 0x10 -#define T_LISTEN_req 0x11 -#define T_DATA_req 0x12 -#define T_XPD_req 0x13 -#define T_USR_rcvd 0x14 -#define T_USR_Xrcvd 0x15 -#define T_DETACH 0x16 -#define T_NETRESET 0x17 -#define T_ACPT_req 0x18 - }ev_union; -};/* end struct event */ - -#define tp_NEVENTS 0x19 - -#define ATTR(X)ev_union.EV_/**/X/**/ diff --git a/bsd/netiso/tp_inet.c b/bsd/netiso/tp_inet.c deleted file mode 100644 index 1c128b47a..000000000 --- a/bsd/netiso/tp_inet.c +++ /dev/null @@ -1,707 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)tp_inet.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * ARGO TP - * - * Here is where you find the inet-dependent code. We've tried - * keep all net-level and (primarily) address-family-dependent stuff - * out of the tp source, and everthing here is reached indirectly - * through a switch table (struct nl_protosw *) tpcb->tp_nlproto - * (see tp_pcb.c). - * The routines here are: - * in_getsufx: gets transport suffix out of an inpcb structure. - * in_putsufx: put transport suffix into an inpcb structure. - * in_putnetaddr: put a whole net addr into an inpcb. - * in_getnetaddr: get a whole net addr from an inpcb. - * in_cmpnetaddr: compare a whole net addr from an isopcb. - * in_recycle_suffix: clear suffix for reuse in inpcb - * tpip_mtu: figure out what size tpdu to use - * tpip_input: take a pkt from ip, strip off its ip header, give to tp - * tpip_output_dg: package a pkt for ip given 2 addresses & some data - * tpip_output: package a pkt for ip given an inpcb & some data - */ - -#if INET - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef ISO -#include -#endif - -/* - * NAME: in_getsufx() - - * CALLED FROM: pr_usrreq() on PRU_BIND, - * PRU_CONNECT, PRU_ACCEPT, and PRU_PEERADDR - * - * FUNCTION, ARGUMENTS, and RETURN VALUE: - * Get a transport suffix from an inpcb structure (inp). - * The argument (which) takes the value TP_LOCAL or TP_FOREIGN. - * - * RETURNS: internet port / transport suffix - * (CAST TO AN INT) - * - * SIDE EFFECTS: - * - * NOTES: - */ -in_getsufx(inp, lenp, data_out, which) - struct inpcb *inp; - u_short *lenp; - caddr_t data_out; - int which; -{ - *lenp = sizeof(u_short); - switch (which) { - case TP_LOCAL: - *(u_short *)data_out = inp->inp_lport; - return; - - case TP_FOREIGN: - *(u_short *)data_out = inp->inp_fport; - } - -} - -/* - * NAME: in_putsufx() - * - * CALLED FROM: tp_newsocket(); i.e., when a connection - * is being established by an incoming CR_TPDU. - * - * FUNCTION, ARGUMENTS: - * Put a transport suffix (found in name) into an inpcb structure (inp). - * The argument (which) takes the value TP_LOCAL or TP_FOREIGN. - * - * RETURNS: Nada - * - * SIDE EFFECTS: - * - * NOTES: - */ -/*ARGSUSED*/ -void -in_putsufx(inp, sufxloc, sufxlen, which) - struct inpcb *inp; - caddr_t sufxloc; - int which; -{ - if (which == TP_FOREIGN) { - bcopy(sufxloc, (caddr_t)&inp->inp_fport, sizeof(inp->inp_fport)); - } -} - -/* - * NAME: in_recycle_tsuffix() - * - * CALLED FROM: tp.trans whenever we go into REFWAIT state. - * - * FUNCTION and ARGUMENT: - * Called when a ref is frozen, to allow the suffix to be reused. - * (inp) is the net level pcb. - * - * RETURNS: Nada - * - * SIDE EFFECTS: - * - * NOTES: This really shouldn't have to be done in a NET level pcb - * but... for the internet world that just the way it is done in BSD... - * The alternative is to have the port unusable until the reference - * timer goes off. - */ -void -in_recycle_tsuffix(inp) - struct inpcb *inp; -{ - inp->inp_fport = inp->inp_lport = 0; -} - -/* - * NAME: in_putnetaddr() - * - * CALLED FROM: - * tp_newsocket(); i.e., when a connection is being established by an - * incoming CR_TPDU. - * - * FUNCTION and ARGUMENTS: - * Copy a whole net addr from a struct sockaddr (name). - * into an inpcb (inp). - * The argument (which) takes values TP_LOCAL or TP_FOREIGN - * - * RETURNS: Nada - * - * SIDE EFFECTS: - * - * NOTES: - */ -void -in_putnetaddr(inp, name, which) - register struct inpcb *inp; - struct sockaddr_in *name; - int which; -{ - switch (which) { - case TP_LOCAL: - bcopy((caddr_t)&name->sin_addr, - (caddr_t)&inp->inp_laddr, sizeof(struct in_addr)); - /* won't work if the dst address (name) is INADDR_ANY */ - - break; - case TP_FOREIGN: - if( name != (struct sockaddr_in *)0 ) { - bcopy((caddr_t)&name->sin_addr, - (caddr_t)&inp->inp_faddr, sizeof(struct in_addr)); - } - } -} - -/* - * NAME: in_putnetaddr() - * - * CALLED FROM: - * tp_input() when a connection is being established by an - * incoming CR_TPDU, and considered for interception. - * - * FUNCTION and ARGUMENTS: - * Compare a whole net addr from a struct sockaddr (name), - * with that implicitly stored in an inpcb (inp). - * The argument (which) takes values TP_LOCAL or TP_FOREIGN - * - * RETURNS: Nada - * - * SIDE EFFECTS: - * - * NOTES: - */ -in_cmpnetaddr(inp, name, which) - register struct inpcb *inp; - register struct sockaddr_in *name; - int which; -{ - if (which == TP_LOCAL) { - if (name->sin_port && name->sin_port != inp->inp_lport) - return 0; - return (name->sin_addr.s_addr == inp->inp_laddr.s_addr); - } - if (name->sin_port && name->sin_port != inp->inp_fport) - return 0; - return (name->sin_addr.s_addr == inp->inp_faddr.s_addr); -} - -/* - * NAME: in_getnetaddr() - * - * CALLED FROM: - * pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR - * FUNCTION and ARGUMENTS: - * Copy a whole net addr from an inpcb (inp) into - * an mbuf (name); - * The argument (which) takes values TP_LOCAL or TP_FOREIGN. - * - * RETURNS: Nada - * - * SIDE EFFECTS: - * - * NOTES: - */ - -void -in_getnetaddr( inp, name, which) - register struct mbuf *name; - struct inpcb *inp; - int which; -{ - register struct sockaddr_in *sin = mtod(name, struct sockaddr_in *); - bzero((caddr_t)sin, sizeof(*sin)); - switch (which) { - case TP_LOCAL: - sin->sin_addr = inp->inp_laddr; - sin->sin_port = inp->inp_lport; - break; - case TP_FOREIGN: - sin->sin_addr = inp->inp_faddr; - sin->sin_port = inp->inp_fport; - break; - default: - return; - } - name->m_len = sin->sin_len = sizeof (*sin); - sin->sin_family = AF_INET; -} - -/* - * NAME: tpip_mtu() - * - * CALLED FROM: - * tp_route_to() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT - * - * FUNCTION, ARGUMENTS, and RETURN VALUE: - * - * Perform subnetwork dependent part of determining MTU information. - * It appears that setting a double pointer to the rtentry associated with - * the destination, and returning the header size for the network protocol - * suffices. - * - * SIDE EFFECTS: - * Sets tp_routep pointer in pcb. - * - * NOTES: - */ - -tpip_mtu(tpcb) -register struct tp_pcb *tpcb; -{ - struct inpcb *inp = (struct inpcb *)tpcb->tp_npcb; - - IFDEBUG(D_CONN) - printf("tpip_mtu(tpcb)\n", tpcb); - printf("tpip_mtu routing to addr 0x%x\n", inp->inp_faddr.s_addr); - ENDDEBUG - tpcb->tp_routep = &(inp->inp_route.ro_rt); - return (sizeof (struct ip)); - -} - -/* - * NAME: tpip_output() - * - * CALLED FROM: tp_emit() - * - * FUNCTION and ARGUMENTS: - * Take a packet(m0) from tp and package it so that ip will accept it. - * This means prepending space for the ip header and filling in a few - * of the fields. - * inp is the inpcb structure; datalen is the length of the data in the - * mbuf string m0. - * RETURNS: - * whatever (E*) is returned form the net layer output routine. - * - * SIDE EFFECTS: - * - * NOTES: - */ - -int -tpip_output(inp, m0, datalen, nochksum) - struct inpcb *inp; - struct mbuf *m0; - int datalen; - int nochksum; -{ - return tpip_output_dg( &inp->inp_laddr, &inp->inp_faddr, m0, datalen, - &inp->inp_route, nochksum); -} - -/* - * NAME: tpip_output_dg() - * - * CALLED FROM: tp_error_emit() - * - * FUNCTION and ARGUMENTS: - * This is a copy of tpip_output that takes the addresses - * instead of a pcb. It's used by the tp_error_emit, when we - * don't have an in_pcb with which to call the normal output rtn. - * - * RETURNS: ENOBUFS or whatever (E*) is - * returned form the net layer output routine. - * - * SIDE EFFECTS: - * - * NOTES: - */ - -/*ARGSUSED*/ -int -tpip_output_dg(laddr, faddr, m0, datalen, ro, nochksum) - struct in_addr *laddr, *faddr; - struct mbuf *m0; - int datalen; - struct route *ro; - int nochksum; -{ - register struct mbuf *m; - register struct ip *ip; - int error; - - IFDEBUG(D_EMIT) - printf("tpip_output_dg datalen 0x%x m0 0x%x\n", datalen, m0); - ENDDEBUG - - - MGETHDR(m, M_DONTWAIT, TPMT_IPHDR); - if (m == 0) { - error = ENOBUFS; - goto bad; - } - m->m_next = m0; - MH_ALIGN(m, sizeof(struct ip)); - m->m_len = sizeof(struct ip); - - ip = mtod(m, struct ip *); - bzero((caddr_t)ip, sizeof *ip); - - ip->ip_p = IPPROTO_TP; - m->m_pkthdr.len = ip->ip_len = sizeof(struct ip) + datalen; - ip->ip_ttl = MAXTTL; - /* don't know why you need to set ttl; - * overlay doesn't even make this available - */ - - ip->ip_src = *laddr; - ip->ip_dst = *faddr; - - IncStat(ts_tpdu_sent); - IFDEBUG(D_EMIT) - dump_mbuf(m, "tpip_output_dg before ip_output\n"); - ENDDEBUG - - error = ip_output(m, (struct mbuf *)0, ro, IP_ALLOWBROADCAST, NULL); - - IFDEBUG(D_EMIT) - printf("tpip_output_dg after ip_output\n"); - ENDDEBUG - - return error; - -bad: - m_freem(m); - IncStat(ts_send_drop); - return error; -} - -/* - * NAME: tpip_input() - * - * CALLED FROM: - * ip's input routine, indirectly through the protosw. - * - * FUNCTION and ARGUMENTS: - * Take a packet (m) from ip, strip off the ip header and give it to tp - * - * RETURNS: No return value. - * - * SIDE EFFECTS: - * - * NOTES: - */ -ProtoHook -tpip_input(m, iplen) - struct mbuf *m; - int iplen; -{ - struct sockaddr_in src, dst; - register struct ip *ip; - int s = splnet(), hdrlen; - - IncStat(ts_pkt_rcvd); - - /* - * IP layer has already pulled up the IP header, - * but the first byte after the IP header may not be there, - * e.g. if you came in via loopback, so you have to do an - * m_pullup to before you can even look to see how much you - * really need. The good news is that m_pullup will round - * up to almost the next mbuf's worth. - */ - - - if((m = m_pullup(m, iplen + 1)) == MNULL) - goto discard; - CHANGE_MTYPE(m, TPMT_DATA); - - /* - * Now pull up the whole tp header: - * Unfortunately, there may be IP options to skip past so we - * just fetch it as an unsigned char. - */ - hdrlen = iplen + 1 + mtod(m, u_char *)[iplen]; - - if( m->m_len < hdrlen ) { - if((m = m_pullup(m, hdrlen)) == MNULL){ - IFDEBUG(D_TPINPUT) - printf("tp_input, pullup 2!\n"); - ENDDEBUG - goto discard; - } - } - /* - * cannot use tp_inputprep() here 'cause you don't - * have quite the same situation - */ - - IFDEBUG(D_TPINPUT) - dump_mbuf(m, "after tpip_input both pullups"); - ENDDEBUG - /* - * m_pullup may have returned a different mbuf - */ - ip = mtod(m, struct ip *); - - /* - * drop the ip header from the front of the mbuf - * this is necessary for the tp checksum - */ - m->m_len -= iplen; - m->m_data += iplen; - - src.sin_addr = *(struct in_addr *)&(ip->ip_src); - src.sin_family = AF_INET; - src.sin_len = sizeof(src); - dst.sin_addr = *(struct in_addr *)&(ip->ip_dst); - dst.sin_family = AF_INET; - dst.sin_len = sizeof(dst); - - (void) tp_input(m, (struct sockaddr *)&src, (struct sockaddr *)&dst, - 0, tpip_output_dg, 0); - return 0; - -discard: - IFDEBUG(D_TPINPUT) - printf("tpip_input DISCARD\n"); - ENDDEBUG - IFTRACE(D_TPINPUT) - tptrace(TPPTmisc, "tpip_input DISCARD m", m,0,0,0); - ENDTRACE - m_freem(m); - IncStat(ts_recv_drop); - splx(s); - return 0; -} - - -#include -#include - -extern void tp_quench(); -/* - * NAME: tpin_quench() - * - * CALLED FROM: tpip_ctlinput() - * - * FUNCTION and ARGUMENTS: find the tpcb pointer and pass it to tp_quench - * - * RETURNS: Nada - * - * SIDE EFFECTS: - * - * NOTES: - */ - -void -tpin_quench(inp) - struct inpcb *inp; -{ - tp_quench((struct tp_pcb *)inp->inp_socket->so_pcb, PRC_QUENCH); -} - -/* - * NAME: tpip_ctlinput() - * - * CALLED FROM: - * The network layer through the protosw table. - * - * FUNCTION and ARGUMENTS: - * When clnp gets an ICMP msg this gets called. - * It either returns an error status to the user or - * causes all connections on this address to be aborted - * by calling the appropriate xx_notify() routine. - * (cmd) is the type of ICMP error. - * (sa) the address of the sender - * - * RETURNS: Nothing - * - * SIDE EFFECTS: - * - * NOTES: - */ -ProtoHook -tpip_ctlinput(cmd, sin) - int cmd; - struct sockaddr_in *sin; -{ - extern u_char inetctlerrmap[]; - extern struct in_addr zeroin_addr; - void tp_quench __P((struct inpcb *,int)); - void tpin_abort __P((struct inpcb *,int)); - - if (sin->sin_family != AF_INET && sin->sin_family != AF_IMPLINK) - return 0; - if (sin->sin_addr.s_addr == INADDR_ANY) - return 0; - if (cmd < 0 || cmd > PRC_NCMDS) - return 0; - switch (cmd) { - - case PRC_QUENCH: - in_pcbnotify(&tp_inpcb, (struct sockaddr *)sin, 0, - zeroin_addr, 0, cmd, tp_quench); - break; - - case PRC_ROUTEDEAD: - case PRC_HOSTUNREACH: - case PRC_UNREACH_NET: - case PRC_IFDOWN: - case PRC_HOSTDEAD: - in_pcbnotify(&tp_inpcb, (struct sockaddr *)sin, 0, - zeroin_addr, 0, cmd, in_rtchange); - break; - - default: - /* - case PRC_MSGSIZE: - case PRC_UNREACH_HOST: - case PRC_UNREACH_PROTOCOL: - case PRC_UNREACH_PORT: - case PRC_UNREACH_NEEDFRAG: - case PRC_UNREACH_SRCFAIL: - case PRC_REDIRECT_NET: - case PRC_REDIRECT_HOST: - case PRC_REDIRECT_TOSNET: - case PRC_REDIRECT_TOSHOST: - case PRC_TIMXCEED_INTRANS: - case PRC_TIMXCEED_REASS: - case PRC_PARAMPROB: - */ - in_pcbnotify(&tp_inpcb, (struct sockaddr *)sin, 0, - zeroin_addr, 0, cmd, tpin_abort); - } - return 0; -} - -/* - * NAME: tpin_abort() - * - * CALLED FROM: - * xxx_notify() from tp_ctlinput() when - * net level gets some ICMP-equiv. type event. - * - * FUNCTION and ARGUMENTS: - * Cause the connection to be aborted with some sort of error - * reason indicating that the network layer caused the abort. - * Fakes an ER TPDU so we can go through the driver. - * - * RETURNS: Nothing - * - * SIDE EFFECTS: - * - * NOTES: - */ - -ProtoHook -tpin_abort(inp) - struct inpcb *inp; -{ - struct tp_event e; - - e.ev_number = ER_TPDU; - e.ATTR(ER_TPDU).e_reason = ENETRESET; - (void) tp_driver((struct tp_pcb *)inp->inp_ppcb, &e); - return 0; -} - -#ifdef ARGO_DEBUG -dump_inaddr(addr) - register struct sockaddr_in *addr; -{ - printf("INET: port 0x%x; addr 0x%x\n", addr->sin_port, addr->sin_addr); -} -#endif /* ARGO_DEBUG */ -#endif /* INET */ diff --git a/bsd/netiso/tp_input.c b/bsd/netiso/tp_input.c deleted file mode 100644 index ceeecf5f1..000000000 --- a/bsd/netiso/tp_input.c +++ /dev/null @@ -1,1642 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)tp_input.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * ARGO TP - * - * tp_input() gets an mbuf chain from ip. Actually, not directly - * from ip, because ip calls a net-level routine that strips off - * the net header and then calls tp_input(), passing the proper type - * of addresses for the address family in use (how it figures out - * which AF is not yet determined.) - * - * Decomposing the tpdu is some of the most laughable code. The variable-length - * parameters and the problem of non-aligned memory references - * necessitates such abominations as the macros WHILE_OPTIONS (q.v. below) - * to loop through the header and decompose it. - * - * The routine tp_newsocket() is called when a CR comes in for a listening - * socket. tp_input calls sonewconn() and tp_newsocket() to set up the - * "child" socket. Most tpcb values are copied from the parent tpcb into - * the child. - * - * Also in here is tp_headersize() (grot) which tells the expected size - * of a tp header, to be used by other layers. It's in here because it - * uses the static structure tpdu_info. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#ifdef TRUE -#undef FALSE -#undef TRUE -#endif -#include -#include -#include - -int iso_check_csum(), tp_driver(), tp_headersize(), tp_error_emit(); - -/* - #ifdef lint - #undef ATTR - #define ATTR(X)ev_number - #endif lint -*/ - -struct mbuf * -tp_inputprep(m) - register struct mbuf *m; -{ - int hdrlen; - - IFDEBUG(D_TPINPUT) - printf("tp_inputprep: m 0x%x\n", m) ; - ENDDEBUG - - while( m->m_len < 1 ) { - /* The "m_free" logic - * if( (m = m_free(m)) == MNULL ) - * return (struct mbuf *)0; - * would cause a system crash if ever executed. - * This logic will be executed if the first mbuf - * in the chain only contains a CLNP header. The m_free routine - * will release the mbuf containing the CLNP header from the - * chain and the new head of the chain will not have the - * M_PKTHDR bit set. This routine, tp_inputprep, will - * eventually call the "sbappendaddr" routine. "sbappendaddr" - * calls "panic" if M_PKTHDR is not set. m_pullup is a cheap - * way of keeping the head of the chain from being freed. - */ - if((m = m_pullup(m, 1)) == MNULL) - return (MNULL); - } - if(((int)m->m_data) & 0x3) { - /* If we are not 4-byte aligned, we have to be - * above the beginning of the mbuf, and it is ok just - * to slide it back. - */ - caddr_t ocp = m->m_data; - - m->m_data = (caddr_t)(((int)m->m_data) & ~0x3); - bcopy(ocp, m->m_data, (unsigned)m->m_len); - } - CHANGE_MTYPE(m, TPMT_DATA); - - /* we KNOW that there is at least 1 byte in this mbuf - and that it is hdr->tpdu_li XXXXXXX! */ - - hdrlen = 1 + *mtod( m, u_char *); - - /* - * now pull up the whole tp header - */ - if ( m->m_len < hdrlen) { - if ((m = m_pullup(m, hdrlen)) == MNULL ) { - IncStat(ts_recv_drop); - return (struct mbuf *)0; - } - } - IFDEBUG(D_INPUT) - printf( - " at end: m 0x%x hdr->tpdu_li 0x%x m_len 0x%x\n",m, - hdrlen, m->m_len); - ENDDEBUG - return m; -} - -/* begin groan - * -- this array and the following macros allow you to step through the - * parameters of the variable part of a header - * note that if for any reason the values of the **_TPDU macros (in tp_events.h) - * should change, this array has to be rearranged - */ - -#define TP_LEN_CLASS_0_INDEX 2 -#define TP_MAX_DATA_INDEX 3 - -static u_char tpdu_info[][4] = -{ -/* length max data len */ -/* reg fmt xtd fmt class 0 */ - /* UNUSED 0x0 */ 0x0 , 0x0, 0x0, 0x0, - /* XPD_TPDU_type 0x1 */ 0x5, 0x8, 0x0, TP_MAX_XPD_DATA, - /* XAK_TPDU_type 0x2 */ 0x5 , 0x8, 0x0, 0x0, - /* GR_TPDU_type 0x3 */ 0x0 , 0x0, 0x0, 0x0, - /* UNUSED 0x4 */ 0x0 , 0x0, 0x0, 0x0, - /* UNUSED 0x5 */ 0x0 , 0x0, 0x0, 0x0, - /* AK_TPDU_type 0x6 */ 0x5, 0xa, 0x0, 0x0, - /* ER_TPDU_type 0x7 */ 0x5, 0x5, 0x0, 0x0, - /* DR_TPDU_type 0x8 */ 0x7, 0x7, 0x7, TP_MAX_DR_DATA, - /* UNUSED 0x9 */ 0x0 , 0x0, 0x0, 0x0, - /* UNUSED 0xa */ 0x0 , 0x0, 0x0, 0x0, - /* UNUSED 0xb */ 0x0 , 0x0, 0x0, 0x0, - /* DC_TPDU_type 0xc */ 0x6, 0x6, 0x0, 0x0, - /* CC_TPDU_type 0xd */ 0x7, 0x7, 0x7, TP_MAX_CC_DATA, - /* CR_TPDU_type 0xe */ 0x7, 0x7, 0x7, TP_MAX_CR_DATA, - /* DT_TPDU_type 0xf */ 0x5, 0x8, 0x3, 0x0, -}; - -#define CHECK(Phrase, Erval, Stat, Whattodo, Loc)\ - if (Phrase) {error = (Erval); errlen = (int)(Loc); IncStat(Stat);\ - goto Whattodo; } - -/* - * WHENEVER YOU USE THE FOLLOWING MACRO, - * BE SURE THE TPDUTYPE IS A LEGIT VALUE FIRST! - */ - -#define WHILE_OPTIONS(P, hdr, format)\ -{ register caddr_t P = tpdu_info[(hdr)->tpdu_type][(format)] + (caddr_t)hdr;\ - caddr_t PLIM = 1 + hdr->tpdu_li + (caddr_t)hdr;\ - for (;; P += 2 + ((struct tp_vbp *)P)->tpv_len) {\ - CHECK((P > PLIM), E_TP_LENGTH_INVAL, ts_inv_length,\ - respond, P - (caddr_t)hdr);\ - if (P == PLIM) break; - -#define END_WHILE_OPTIONS(P) } } - -/* end groan */ - -/* - * NAME: tp_newsocket() - * - * CALLED FROM: - * tp_input() on incoming CR, when a socket w/ the called suffix - * is awaiting a connection request - * - * FUNCTION and ARGUMENTS: - * Create a new socket structure, attach to it a new transport pcb, - * using a copy of the net level pcb for the parent socket. - * (so) is the parent socket. - * (fname) is the foreign address (all that's used is the nsap portion) - * - * RETURN VALUE: - * a new socket structure, being this end of the newly formed connection. - * - * SIDE EFFECTS: - * Sets a few things in the tpcb and net level pcb - * - * NOTES: - */ -static struct socket * -tp_newsocket(so, fname, cons_channel, class_to_use, netservice) - struct socket *so; - struct sockaddr *fname; - caddr_t cons_channel; - u_char class_to_use; - u_int netservice; -{ - register struct tp_pcb *tpcb = sototpcb(so); /* old tpcb, needed below */ - register struct tp_pcb *newtpcb; - - /* - * sonewconn() gets a new socket structure, - * a new lower layer pcb and a new tpcb, - * but the pcbs are unnamed (not bound) - */ - IFTRACE(D_NEWSOCK) - tptraceTPCB(TPPTmisc, "newsock: listg_so, _tpcb, so_head", - so, tpcb, so->so_head, 0); - ENDTRACE - - if ((so = sonewconn(so, SS_ISCONFIRMING)) == (struct socket *)0) - return so; - IFTRACE(D_NEWSOCK) - tptraceTPCB(TPPTmisc, "newsock: after newconn so, so_head", - so, so->so_head, 0, 0); - ENDTRACE - - IFDEBUG(D_NEWSOCK) - printf("tp_newsocket(channel 0x%x) after sonewconn so 0x%x \n", - cons_channel, so); - dump_addr(fname); - { - struct socket *t, *head ; - - head = so->so_head; - t = so; - printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n", - t, t->so_head, t->so_q0, t->so_q0len); - while( (t=t->so_q0) && t!= so && t!= head) - printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n", - t, t->so_head, t->so_q0, t->so_q0len); - } - ENDDEBUG - - /* - * before we clobber the old tpcb ptr, get these items from the parent pcb - */ - newtpcb = sototpcb(so); - newtpcb->_tp_param = tpcb->_tp_param; - newtpcb->tp_flags = tpcb->tp_flags; - newtpcb->tp_lcredit = tpcb->tp_lcredit; - newtpcb->tp_l_tpdusize = tpcb->tp_l_tpdusize; - newtpcb->tp_lsuffixlen = tpcb->tp_lsuffixlen; - bcopy( tpcb->tp_lsuffix, newtpcb->tp_lsuffix, newtpcb->tp_lsuffixlen); - - if( /* old */ tpcb->tp_ucddata) { - /* - * These data are the connect- , confirm- or disconnect- data. - */ - struct mbuf *conndata; - - conndata = m_copy(tpcb->tp_ucddata, 0, (int)M_COPYALL); - IFDEBUG(D_CONN) - dump_mbuf(conndata, "conndata after mcopy"); - ENDDEBUG - newtpcb->tp_ucddata = conndata; - } - - tpcb = newtpcb; - tpcb->tp_state = TP_LISTENING; - tpcb->tp_class = class_to_use; - tpcb->tp_netservice = netservice; - - - ASSERT( fname != 0 ) ; /* just checking */ - if ( fname ) { - /* - * tp_route_to takes its address argument in the form of an mbuf. - */ - struct mbuf *m; - int err; - - MGET(m, M_DONTWAIT, MT_SONAME); /* mbuf type used is confusing */ - if (m) { - /* - * this seems a bit grotesque, but tp_route_to expects - * an mbuf * instead of simply a sockaddr; it calls the ll - * pcb_connect, which expects the name/addr in an mbuf as well. - * sigh. - */ - bcopy((caddr_t)fname, mtod(m, caddr_t), fname->sa_len); - m->m_len = fname->sa_len; - - /* grot : have to say the kernel can override params in - * the passive open case - */ - tpcb->tp_dont_change_params = 0; - err = tp_route_to( m, tpcb, cons_channel); - m_free(m); - - if (!err) - goto ok; - } - IFDEBUG(D_CONN) - printf("tp_route_to FAILED! detaching tpcb 0x%x, so 0x%x\n", - tpcb, so); - ENDDEBUG - (void) tp_detach(tpcb); - return 0; - } -ok: - IFDEBUG(D_TPINPUT) - printf("tp_newsocket returning so 0x%x, sototpcb(so) 0x%x\n", - so, sototpcb(so)); - ENDDEBUG - return so; -} - -#ifndef TPCONS -tpcons_output() -{ - return(0); -} -#endif /* !CONS */ - -/* - * NAME: tp_input() - * - * CALLED FROM: - * net layer input routine - * - * FUNCTION and ARGUMENTS: - * Process an incoming TPDU (m), finding the associated tpcb if there - * is one. Create the appropriate type of event and call the driver. - * (faddr) and (laddr) are the foreign and local addresses. - * - * When tp_input() is called we KNOW that the ENTIRE TP HEADER - * has been m_pullup-ed. - * - * RETURN VALUE: Nada - * - * SIDE EFFECTS: - * When using COSNS it may affect the state of the net-level pcb - * - * NOTE: - * The initial value of acktime is 2 so that we will never - * have a 0 value for tp_peer_acktime. It gets used in the - * computation of the retransmission timer value, and so it - * mustn't be zero. - * 2 seems like a reasonable minimum. - */ -ProtoHook -tp_input(m, faddr, laddr, cons_channel, dgout_routine, ce_bit) - register struct mbuf *m; - struct sockaddr *faddr, *laddr; /* NSAP addresses */ - caddr_t cons_channel; - int (*dgout_routine)(); - int ce_bit; - -{ - register struct tp_pcb *tpcb; - register struct tpdu *hdr; - struct socket *so; - struct tp_event e; - int error; - unsigned dutype; - u_short dref, sref, acktime, subseq; - u_char preferred_class, class_to_use, pdusize; - u_char opt, dusize, addlopt, version; -#ifdef TP_PERF_MEAS - u_char perf_meas; -#endif /* TP_PERF_MEAS */ - u_char fsufxlen, lsufxlen; - caddr_t fsufxloc, lsufxloc; - int tpdu_len; - u_int takes_data; - u_int fcc_present; - int errlen; - struct tp_conn_param tpp; - int tpcons_output(); - -again: - hdr = mtod(m, struct tpdu *); - tpcb = 0; - error = errlen = tpdu_len = 0; - takes_data = fcc_present = FALSE; - acktime = 2; sref = subseq = 0; - fsufxloc = lsufxloc = NULL; - fsufxlen = lsufxlen = - preferred_class = class_to_use = pdusize = addlopt = 0; - dusize = TP_DFL_TPDUSIZE; -#ifdef TP_PERF_MEAS - GET_CUR_TIME( &e.e_time ); perf_meas = 0; -#endif /* TP_PERF_MEAS */ - - IFDEBUG(D_TPINPUT) - printf("tp_input(0x%x, ... 0x%x)\n", m, cons_channel); - ENDDEBUG - - - /* - * get the actual tpdu length - necessary for monitoring - * and for checksumming - * - * Also, maybe measure the mbuf chain lengths and sizes. - */ - - { register struct mbuf *n=m; -# ifdef ARGO_DEBUG - int chain_length = 0; -# endif ARGO_DEBUG - - for(;;) { - tpdu_len += n->m_len; - IFDEBUG(D_MBUF_MEAS) - if( n->m_flags & M_EXT) { - IncStat(ts_mb_cluster); - } else { - IncStat(ts_mb_small); - } - chain_length ++; - ENDDEBUG - if (n->m_next == MNULL ) { - break; - } - n = n->m_next; - } - IFDEBUG(D_MBUF_MEAS) - if(chain_length > 16) - chain_length = 0; /* zero used for anything > 16 */ - tp_stat.ts_mb_len_distr[chain_length] ++; - ENDDEBUG - } - IFTRACE(D_TPINPUT) - tptraceTPCB(TPPTtpduin, hdr->tpdu_type, hdr, hdr->tpdu_li+1, tpdu_len, - 0); - ENDTRACE - - dref = ntohs((short)hdr->tpdu_dref); - sref = ntohs((short)hdr->tpdu_sref); - dutype = (int)hdr->tpdu_type; - - IFDEBUG(D_TPINPUT) - printf("input: dutype 0x%x cons_channel 0x%x dref 0x%x\n", dutype, - cons_channel, dref); - printf("input: dref 0x%x sref 0x%x\n", dref, sref); - ENDDEBUG - IFTRACE(D_TPINPUT) - tptrace(TPPTmisc, "channel dutype dref ", - cons_channel, dutype, dref, 0); - ENDTRACE - - -#ifdef ARGO_DEBUG - if( (dutype < TP_MIN_TPDUTYPE) || (dutype > TP_MAX_TPDUTYPE)) { - printf("BAD dutype! 0x%x, channel 0x%x dref 0x%x\n", - dutype, cons_channel, dref); - dump_buf (m, sizeof( struct mbuf )); - - IncStat(ts_inv_dutype); - goto discard; - } -#endif /* ARGO_DEBUG */ - - CHECK( (dutype < TP_MIN_TPDUTYPE || dutype > TP_MAX_TPDUTYPE), - E_TP_INV_TPDU, ts_inv_dutype, respond, - 2 ); - /* unfortunately we can't take the address of the tpdu_type field, - * since it's a bit field - so we just use the constant offset 2 - */ - - /* Now this isn't very neat but since you locate a pcb one way - * at the beginning of connection establishment, and by - * the dref for each tpdu after that, we have to treat CRs differently - */ - if ( dutype == CR_TPDU_type ) { - u_char alt_classes = 0; - - preferred_class = 1 << hdr->tpdu_CRclass; - opt = hdr->tpdu_CRoptions; - - WHILE_OPTIONS(P, hdr, 1 ) /* { */ - - switch( vbptr(P)->tpv_code ) { - - case TPP_tpdu_size: - vb_getval(P, u_char, dusize); - IFDEBUG(D_TPINPUT) - printf("CR dusize 0x%x\n", dusize); - ENDDEBUG - /* COS tests: NBS IA (Dec. 1987) Sec. 4.5.2.1 */ - if (dusize < TP_MIN_TPDUSIZE || dusize > TP_MAX_TPDUSIZE) - dusize = TP_DFL_TPDUSIZE; - break; - case TPP_ptpdu_size: - switch (vbptr(P)->tpv_len) { - case 1: pdusize = vbval(P, u_char); break; - case 2: pdusize = ntohs(vbval(P, u_short)); break; - default: ; - IFDEBUG(D_TPINPUT) - printf("malformed prefered TPDU option\n"); - ENDDEBUG - } - break; - case TPP_addl_opt: - vb_getval(P, u_char, addlopt); - break; - case TPP_calling_sufx: - /* could use vb_getval, but we want to save the loc & len - * for later use - */ - fsufxloc = (caddr_t) &vbptr(P)->tpv_val; - fsufxlen = vbptr(P)->tpv_len; - IFDEBUG(D_TPINPUT) - printf("CR fsufx:"); - { register int j; - for(j=0; jtpv_val; - lsufxlen = vbptr(P)->tpv_len; - IFDEBUG(D_TPINPUT) - printf("CR lsufx:"); - { register int j; - for(j=0; jtpv_val - (caddr_t)hdr) ); - setversion: - version = vbval(P, u_char); - break; - case TPP_acktime: - vb_getval(P, u_short, acktime); - acktime = ntohs(acktime); - acktime = acktime/500; /* convert to slowtimo ticks */ - if((short)acktime <=0 ) - acktime = 2; /* don't allow a bad peer to foul us up */ - IFDEBUG(D_TPINPUT) - printf("CR acktime 0x%x\n", acktime); - ENDDEBUG - break; - - case TPP_alt_class: - { - u_char *aclass = 0; - register int i; - static u_char bad_alt_classes[5] = - { ~0, ~3, ~5, ~0xf, ~0x1f}; - - aclass = - (u_char *) &(((struct tp_vbp *)P)->tpv_val); - for (i = ((struct tp_vbp *)P)->tpv_len; i>0; i--) { - alt_classes |= (1<<((*aclass++)>>4)); - } - CHECK( (bad_alt_classes[hdr->tpdu_CRclass] & alt_classes), - E_TP_INV_PVAL, ts_inv_aclass, respond, - ((caddr_t)aclass) - (caddr_t)hdr); - IFDEBUG(D_TPINPUT) - printf("alt_classes 0x%x\n", alt_classes); - ENDDEBUG - } - break; - - case TPP_security: - case TPP_residER: - case TPP_priority: - case TPP_transdelay: - case TPP_throughput: - case TPP_addl_info: - case TPP_subseq: - default: - IFDEBUG(D_TPINPUT) - printf("param ignored CR_TPDU code= 0x%x\n", - vbptr(P)->tpv_code); - ENDDEBUG - IncStat(ts_param_ignored); - break; - - case TPP_checksum: - IFDEBUG(D_TPINPUT) - printf("CR before cksum\n"); - ENDDEBUG - - CHECK( iso_check_csum(m, tpdu_len), - E_TP_INV_PVAL, ts_bad_csum, discard, 0) - - IFDEBUG(D_TPINPUT) - printf("CR before cksum\n"); - ENDDEBUG - break; - } - - /* } */ END_WHILE_OPTIONS(P) - - if (lsufxlen == 0) { - /* can't look for a tpcb w/o any called sufx */ - error = E_TP_LENGTH_INVAL; - IncStat(ts_inv_sufx); - goto respond; - } else { - register struct tp_pcb *t; - /* - * The intention here is to trap all CR requests - * to a given nsap, for constructing transport - * service bridges at user level; so these - * intercepts should precede the normal listens. - * Phrasing the logic in this way also allows for - * mop-up listeners, which we don't currently implement. - * We also wish to have a single socket be able to - * listen over any network service provider, - * (cons or clns or ip). - */ - for (t = tp_listeners; t ; t = t->tp_nextlisten) - if ((t->tp_lsuffixlen == 0 || - (lsufxlen == t->tp_lsuffixlen && - bcmp(lsufxloc, t->tp_lsuffix, lsufxlen) == 0)) && - ((t->tp_flags & TPF_GENERAL_ADDR) || - (laddr->sa_family == t->tp_domain && - (*t->tp_nlproto->nlp_cmpnetaddr) - (t->tp_npcb, laddr, TP_LOCAL)))) - break; - - CHECK(t == 0, E_TP_NO_SESSION, ts_inv_sufx, respond, - (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) - /* _tpduf is the fixed part; add 2 to get the dref bits of - * the fixed part (can't take the address of a bit field) - */ - IFDEBUG(D_TPINPUT) - printf("checking if dup CR\n"); - ENDDEBUG - tpcb = t; - for (t = tpcb->tp_next; t != tpcb; t = t->tp_next) { - if (sref != t->tp_fref) - continue; - if ((*tpcb->tp_nlproto->nlp_cmpnetaddr)( - t->tp_npcb, faddr, TP_FOREIGN)) { - IFDEBUG(D_TPINPUT) - printf("duplicate CR discarded\n"); - ENDDEBUG - goto discard; - } - } - IFTRACE(D_TPINPUT) - tptrace(TPPTmisc, "tp_input: tpcb *lsufxloc tpstate", - tpcb, *lsufxloc, tpcb->tp_state, 0); - ENDTRACE - } - - /* - * WE HAVE A TPCB - * already know that the classes in the CR match at least - * one class implemented, but we don't know yet if they - * include any classes permitted by this server. - */ - - IFDEBUG(D_TPINPUT) - printf("HAVE A TPCB 1: 0x%x\n", tpcb); - ENDDEBUG - IFDEBUG(D_CONN) - printf( -"CR: bef CHKS: flags 0x%x class_to_use 0x%x alt 0x%x opt 0x%x tp_class 0x%x\n", - tpcb->tp_flags, class_to_use, alt_classes, opt, tpcb->tp_class); - ENDDEBUG - /* tpcb->tp_class doesn't include any classes not implemented */ - class_to_use = (preferred_class & tpcb->tp_class); - if( (class_to_use = preferred_class & tpcb->tp_class) == 0 ) - class_to_use = alt_classes & tpcb->tp_class; - - class_to_use = 1 << tp_mask_to_num(class_to_use); - - { - tpp = tpcb->_tp_param; - tpp.p_class = class_to_use; - tpp.p_tpdusize = dusize; - tpp.p_ptpdusize = pdusize; - tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT; - tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD; - tpp.p_use_checksum = (tpp.p_class == TP_CLASS_0)?0: - (addlopt & TPAO_NO_CSUM) == 0; - tpp.p_version = version; -#ifdef notdef - tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC; - tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD; - tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC; -#endif /* notdef */ - - CHECK( - tp_consistency(tpcb, 0 /* not force or strict */, &tpp) != 0, - E_TP_NEGOT_FAILED, ts_negotfailed, clear_parent_tcb, - (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) - /* ^ more or less the location of class */ - ) - } - IFTRACE(D_CONN) - tptrace(TPPTmisc, - "after 1 consist class_to_use class, out, tpconsout", - class_to_use, - tpcb->tp_class, dgout_routine, tpcons_output - ); - ENDTRACE - CHECK( - ((class_to_use == TP_CLASS_0)&&(dgout_routine != tpcons_output)), - E_TP_NEGOT_FAILED, ts_negotfailed, clear_parent_tcb, - (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) - /* ^ more or less the location of class */ - ) - IFDEBUG(D_CONN) - printf("CR: after CRCCCHECKS: tpcb 0x%x, flags 0x%x\n", - tpcb, tpcb->tp_flags); - ENDDEBUG - takes_data = TRUE; - e.ATTR(CR_TPDU).e_cdt = hdr->tpdu_CRcdt; - e.ev_number = CR_TPDU; - - so = tpcb->tp_sock; - if (so->so_options & SO_ACCEPTCONN) { - struct tp_pcb *parent_tpcb = tpcb; - /* - * Create a socket, tpcb, ll pcb, etc. - * for this newborn connection, and fill in all the values. - */ - IFDEBUG(D_CONN) - printf("abt to call tp_newsocket(0x%x, 0x%x, 0x%x, 0x%x)\n", - so, laddr, faddr, cons_channel); - ENDDEBUG - if( (so = - tp_newsocket(so, faddr, cons_channel, - class_to_use, - ((tpcb->tp_netservice == IN_CLNS) ? IN_CLNS : - (dgout_routine == tpcons_output)?ISO_CONS:ISO_CLNS)) - ) == (struct socket *)0 ) { - /* note - even if netservice is IN_CLNS, as far as - * the tp entity is concerned, the only differences - * are CO vs CL - */ - IFDEBUG(D_CONN) - printf("tp_newsocket returns 0\n"); - ENDDEBUG - goto discard; - clear_parent_tcb: - tpcb = 0; - goto respond; - } - tpcb = sototpcb(so); - insque(tpcb, parent_tpcb); - - /* - * Stash the addresses in the net level pcb - * kind of like a pcbconnect() but don't need - * or want all those checks. - */ - (tpcb->tp_nlproto->nlp_putnetaddr)(tpcb->tp_npcb, faddr, TP_FOREIGN); - (tpcb->tp_nlproto->nlp_putnetaddr)(tpcb->tp_npcb, laddr, TP_LOCAL); - - /* stash the f suffix in the new tpcb */ - if (tpcb->tp_fsuffixlen = fsufxlen) { - bcopy(fsufxloc, tpcb->tp_fsuffix, fsufxlen); - (tpcb->tp_nlproto->nlp_putsufx) - (tpcb->tp_npcb, fsufxloc, fsufxlen, TP_FOREIGN); - } - /* stash the l suffix in the new tpcb */ - tpcb->tp_lsuffixlen = lsufxlen; - bcopy(lsufxloc, tpcb->tp_lsuffix, lsufxlen); - (tpcb->tp_nlproto->nlp_putsufx) - (tpcb->tp_npcb, lsufxloc, lsufxlen, TP_LOCAL); -#ifdef TP_PERF_MEAS - if( tpcb->tp_perf_on = perf_meas ) { /* assignment */ - /* ok, let's create an mbuf for stashing the - * statistics if one doesn't already exist - */ - (void) tp_setup_perf(tpcb); - } -#endif /* TP_PERF_MEAS */ - tpcb->tp_fref = sref; - - /* We've already checked for consistency with the options - * set in tpp, but we couldn't set them earlier because - * we didn't want to change options in the LISTENING tpcb. - * Now we set the options in the new socket's tpcb. - */ - (void) tp_consistency( tpcb, TP_FORCE, &tpp); - - if(!tpcb->tp_use_checksum) - IncStat(ts_csum_off); - if(tpcb->tp_xpd_service) - IncStat(ts_use_txpd); - if(tpcb->tp_xtd_format) - IncStat(ts_xtd_fmt); - - tpcb->tp_peer_acktime = acktime; - - /* - * The following kludge is used to test retransmissions and - * timeout during connection establishment. - */ - IFDEBUG(D_ZDREF) - IncStat(ts_zdebug); - /*tpcb->tp_fref = 0;*/ - ENDDEBUG - } - LOCAL_CREDIT(tpcb); - IncStat(ts_CR_rcvd); - if (!tpcb->tp_cebit_off) { - tpcb->tp_win_recv = tp_start_win << 8; - tpcb->tp_cong_sample.cs_size = 0; - CONG_INIT_SAMPLE(tpcb); - CONG_UPDATE_SAMPLE(tpcb, ce_bit); - } - } else if ( dutype == ER_TPDU_type ) { - /* - * ER TPDUs have to be recognized separately - * because they don't necessarily have a tpcb - * with them and we don't want err out looking for such - * a beast. - * We could put a bunch of little kludges in the - * next section of code so it would avoid references to tpcb - * if dutype == ER_TPDU_type but we don't want code for ERs to - * mess up code for data transfer. - */ - IncStat(ts_ER_rcvd); - e.ev_number = ER_TPDU; - e.ATTR(ER_TPDU).e_reason = (u_char)hdr->tpdu_ERreason; - CHECK (((int)dref <= 0 || dref >= tp_refinfo.tpr_size || - (tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 || - tpcb->tp_refstate == REF_FREE || - tpcb->tp_refstate == REF_FROZEN), - E_TP_MISM_REFS, ts_inv_dref, discard, 0) - - } else { - /* tpdu type is CC, XPD, XAK, GR, AK, DR, DC, or DT */ - - /* In the next 4 checks, - * _tpduf is the fixed part; add 2 to get the dref bits of - * the fixed part (can't take the address of a bit field) - */ -#if TPCONS - if (cons_channel && dutype == DT_TPDU_type) { - struct isopcb *isop = ((struct isopcb *) - ((struct pklcd *)cons_channel)->lcd_upnext); - if (isop && isop->isop_refcnt == 1 && isop->isop_socket && - (tpcb = sototpcb(isop->isop_socket)) && - (tpcb->tp_class == TP_CLASS_0/* || == CLASS_1 */)) { - IFDEBUG(D_TPINPUT) - printf("tpinput_dt: class 0 short circuit\n"); - ENDDEBUG - dref = tpcb->tp_lref; - sref = tpcb->tp_fref; - CHECK( (tpcb->tp_refstate == REF_FREE), - E_TP_MISM_REFS,ts_inv_dref, nonx_dref, - (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) - goto tp0_data; - } - - } -#endif - { - - CHECK( ((int)dref <= 0 || dref >= tp_refinfo.tpr_size) , - E_TP_MISM_REFS,ts_inv_dref, nonx_dref, - (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) - CHECK( ((tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ), - E_TP_MISM_REFS,ts_inv_dref, nonx_dref, - (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) - CHECK( (tpcb->tp_refstate == REF_FREE), - E_TP_MISM_REFS,ts_inv_dref, nonx_dref, - (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) - } - - IFDEBUG(D_TPINPUT) - printf("HAVE A TPCB 2: 0x%x\n", tpcb); - ENDDEBUG - - /* causes a DR to be sent for CC; ER for all else */ - CHECK( (tpcb->tp_refstate == REF_FROZEN), - (dutype == CC_TPDU_type?E_TP_NO_SESSION:E_TP_MISM_REFS), - ts_inv_dref, respond, - (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) - - IFDEBUG(D_TPINPUT) - printf("state of dref %d ok, tpcb 0x%x\n", dref,tpcb); - ENDDEBUG - /* - * At this point the state of the dref could be - * FROZEN: tpr_pcb == NULL, has ( reference only) timers - * for example, DC may arrive after the close() has detached - * the tpcb (e.g., if user turned off SO_LISTEN option) - * OPENING : a tpcb exists but no timers yet - * OPEN : tpcb exists & timers are outstanding - */ - - if (!tpcb->tp_cebit_off) - CONG_UPDATE_SAMPLE(tpcb, ce_bit); - - dusize = tpcb->tp_tpdusize; - pdusize = tpcb->tp_ptpdusize; - - dutype = hdr->tpdu_type << 8; /* for the switch below */ - - WHILE_OPTIONS(P, hdr, tpcb->tp_xtd_format) /* { */ - -#define caseof(x,y) case (((x)<<8)+(y)) - switch( dutype | vbptr(P)->tpv_code ) { - - caseof( CC_TPDU_type, TPP_addl_opt ): - /* not in class 0; 1 octet */ - vb_getval(P, u_char, addlopt); - break; - caseof( CC_TPDU_type, TPP_tpdu_size ): - { - u_char odusize = dusize; - vb_getval(P, u_char, dusize); - CHECK( (dusize < TP_MIN_TPDUSIZE || - dusize > TP_MAX_TPDUSIZE || dusize > odusize), - E_TP_INV_PVAL, ts_inv_pval, respond, - (1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) ) - IFDEBUG(D_TPINPUT) - printf("CC dusize 0x%x\n", dusize); - ENDDEBUG - } - break; - caseof( CC_TPDU_type, TPP_ptpdu_size ): - { - u_short opdusize = pdusize; - switch (vbptr(P)->tpv_len) { - case 1: pdusize = vbval(P, u_char); break; - case 2: pdusize = ntohs(vbval(P, u_short)); break; - default: ; - IFDEBUG(D_TPINPUT) - printf("malformed prefered TPDU option\n"); - ENDDEBUG - } - CHECK( (pdusize == 0 || - (opdusize && (pdusize > opdusize))), - E_TP_INV_PVAL, ts_inv_pval, respond, - (1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) ) - } - break; - caseof( CC_TPDU_type, TPP_calling_sufx): - IFDEBUG(D_TPINPUT) - printf("CC calling (local) sufxlen 0x%x\n", lsufxlen); - ENDDEBUG - lsufxloc = (caddr_t) &vbptr(P)->tpv_val; - lsufxlen = vbptr(P)->tpv_len; - break; - caseof( CC_TPDU_type, TPP_acktime ): - /* class 4 only, 2 octets */ - vb_getval(P, u_short, acktime); - acktime = ntohs(acktime); - acktime = acktime/500; /* convert to slowtimo ticks */ - if( (short)acktime <=0 ) - acktime = 2; - break; - caseof( CC_TPDU_type, TPP_called_sufx): - fsufxloc = (caddr_t) &vbptr(P)->tpv_val; - fsufxlen = vbptr(P)->tpv_len; - IFDEBUG(D_TPINPUT) - printf("CC called (foreign) sufx len %d\n", fsufxlen); - ENDDEBUG - break; - - caseof( CC_TPDU_type, TPP_checksum): - caseof( DR_TPDU_type, TPP_checksum): - caseof( DT_TPDU_type, TPP_checksum): - caseof( XPD_TPDU_type, TPP_checksum): - if( tpcb->tp_use_checksum ) { - CHECK( iso_check_csum(m, tpdu_len), - E_TP_INV_PVAL, ts_bad_csum, discard, 0) - } - break; - - /* this is different from the above because in the context - * of concat/ sep tpdu_len might not be the same as hdr len - */ - caseof( AK_TPDU_type, TPP_checksum): - caseof( XAK_TPDU_type, TPP_checksum): - caseof( DC_TPDU_type, TPP_checksum): - if( tpcb->tp_use_checksum ) { - CHECK( iso_check_csum(m, (int)hdr->tpdu_li + 1), - E_TP_INV_PVAL, ts_bad_csum, discard, 0) - } - break; -#ifdef notdef - caseof( DR_TPDU_type, TPP_addl_info ): - /* ignore - its length and meaning are - * user defined and there's no way - * to pass this info to the user anyway - */ - break; -#endif /* notdef */ - - caseof( AK_TPDU_type, TPP_subseq ): - /* used after reduction of window */ - vb_getval(P, u_short, subseq); - subseq = ntohs(subseq); - IFDEBUG(D_ACKRECV) - printf("AK dref 0x%x Subseq 0x%x\n", dref, subseq); - ENDDEBUG - break; - - caseof( AK_TPDU_type, TPP_flow_cntl_conf ): - { - u_int ylwe; - u_short ysubseq, ycredit; - - fcc_present = TRUE; - vb_getval(P, u_int, ylwe); - vb_getval(P, u_short, ysubseq); - vb_getval(P, u_short, ycredit); - ylwe = ntohl(ylwe); - ysubseq = ntohs(ysubseq); - ycredit = ntohs(ycredit); - IFDEBUG(D_ACKRECV) - printf("%s%x, subseq 0x%x, cdt 0x%x dref 0x%x\n", - "AK FCC lwe 0x", ylwe, ysubseq, ycredit, dref); - ENDDEBUG - } - break; - - default: - IFDEBUG(D_TPINPUT) - printf("param ignored dutype 0x%x, code 0x%x\n", - dutype, vbptr(P)->tpv_code); - ENDDEBUG - IFTRACE(D_TPINPUT) - tptrace(TPPTmisc, "param ignored dutype code ", - dutype, vbptr(P)->tpv_code ,0,0); - ENDTRACE - IncStat(ts_param_ignored); - break; -#undef caseof - } - /* } */ END_WHILE_OPTIONS(P) - - /* NOTE: the variable dutype has been shifted left! */ - - switch( hdr->tpdu_type ) { - case CC_TPDU_type: - /* If CC comes back with an unacceptable class - * respond with a DR or ER - */ - - opt = hdr->tpdu_CCoptions; /* 1 byte */ - - { - tpp = tpcb->_tp_param; - tpp.p_class = (1<tpdu_CCclass); - tpp.p_tpdusize = dusize; - tpp.p_ptpdusize = pdusize; - tpp.p_dont_change_params = 0; - tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT; - tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD; - tpp.p_use_checksum = (addlopt & TPAO_NO_CSUM) == 0; -#ifdef notdef - tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC; - tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD; - tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC; -#endif /* notdef */ - - CHECK( - tp_consistency(tpcb, TP_FORCE, &tpp) != 0, - E_TP_NEGOT_FAILED, ts_negotfailed, respond, - (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) - /* ^ more or less the location of class */ - ) - IFTRACE(D_CONN) - tptrace(TPPTmisc, - "after 1 consist class, out, tpconsout", - tpcb->tp_class, dgout_routine, tpcons_output, 0 - ); - ENDTRACE - CHECK( - ((class_to_use == TP_CLASS_0)&& - (dgout_routine != tpcons_output)), - E_TP_NEGOT_FAILED, ts_negotfailed, respond, - (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) - /* ^ more or less the location of class */ - ) -#if TPCONS - if (tpcb->tp_netservice == ISO_CONS && - class_to_use == TP_CLASS_0) { - struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; - struct pklcd *lcp = (struct pklcd *)isop->isop_chan; - lcp->lcd_flags &= ~X25_DG_CIRCUIT; - } -#endif - } - if( ! tpcb->tp_use_checksum) - IncStat(ts_csum_off); - if(tpcb->tp_xpd_service) - IncStat(ts_use_txpd); - if(tpcb->tp_xtd_format) - IncStat(ts_xtd_fmt); - - IFTRACE(D_CONN) - tptrace(TPPTmisc, "after CC class flags dusize CCclass", - tpcb->tp_class, tpcb->tp_flags, tpcb->tp_tpdusize, - hdr->tpdu_CCclass); - ENDTRACE - - /* if called or calling suffices appeared on the CC, - * they'd better jive with what's in the pcb - */ - if( fsufxlen ) { - CHECK( ((tpcb->tp_fsuffixlen != fsufxlen) || - bcmp(fsufxloc, tpcb->tp_fsuffix, fsufxlen)), - E_TP_INV_PVAL,ts_inv_sufx, respond, - (1+fsufxloc - (caddr_t)hdr)) - } - if( lsufxlen ) { - CHECK( ((tpcb->tp_lsuffixlen != lsufxlen) || - bcmp(lsufxloc, tpcb->tp_lsuffix, lsufxlen)), - E_TP_INV_PVAL,ts_inv_sufx, respond, - (1+lsufxloc - (caddr_t)hdr)) - } - - e.ATTR(CC_TPDU).e_sref = sref; - e.ATTR(CC_TPDU).e_cdt = hdr->tpdu_CCcdt; - takes_data = TRUE; - e.ev_number = CC_TPDU; - IncStat(ts_CC_rcvd); - break; - - case DC_TPDU_type: - if (sref != tpcb->tp_fref) - printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n", - sref, tpcb->tp_fref); - - CHECK( (sref != tpcb->tp_fref), - E_TP_MISM_REFS, ts_inv_sufx, discard, - (1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr)) - - e.ev_number = DC_TPDU; - IncStat(ts_DC_rcvd); - break; - - case DR_TPDU_type: - IFTRACE(D_TPINPUT) - tptrace(TPPTmisc, "DR recvd", hdr->tpdu_DRreason, 0, 0, 0); - ENDTRACE - if (sref != tpcb->tp_fref) { - printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n", - sref, tpcb->tp_fref); - } - - CHECK( (sref != 0 && sref != tpcb->tp_fref && - tpcb->tp_state != TP_CRSENT), - (TP_ERROR_SNDC | E_TP_MISM_REFS),ts_inv_sufx, respond, - (1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr)) - - e.ATTR(DR_TPDU).e_reason = hdr->tpdu_DRreason; - e.ATTR(DR_TPDU).e_sref = (u_short)sref; - takes_data = TRUE; - e.ev_number = DR_TPDU; - IncStat(ts_DR_rcvd); - break; - - case ER_TPDU_type: - IFTRACE(D_TPINPUT) - tptrace(TPPTmisc, "ER recvd", hdr->tpdu_ERreason,0,0,0); - ENDTRACE - e.ev_number = ER_TPDU; - e.ATTR(ER_TPDU).e_reason = hdr->tpdu_ERreason; - IncStat(ts_ER_rcvd); - break; - - case AK_TPDU_type: - - e.ATTR(AK_TPDU).e_subseq = subseq; - e.ATTR(AK_TPDU).e_fcc_present = fcc_present; - - if (tpcb->tp_xtd_format) { -#ifdef BYTE_ORDER - union seq_type seqeotX; - - seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); - e.ATTR(AK_TPDU).e_seq = seqeotX.s_seq; - e.ATTR(AK_TPDU).e_cdt = ntohs(hdr->tpdu_AKcdtX); -#else - e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdtX; - e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseqX; -#endif /* BYTE_ORDER */ - } else { - e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdt; - e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseq; - } - IFTRACE(D_TPINPUT) - tptrace(TPPTmisc, "AK recvd seq cdt subseq fcc_pres", - e.ATTR(AK_TPDU).e_seq, e.ATTR(AK_TPDU).e_cdt, - subseq, fcc_present); - ENDTRACE - - e.ev_number = AK_TPDU; - IncStat(ts_AK_rcvd); - IncPStat(tpcb, tps_AK_rcvd); - break; - - case XAK_TPDU_type: - if (tpcb->tp_xtd_format) { -#ifdef BYTE_ORDER - union seq_type seqeotX; - - seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); - e.ATTR(XAK_TPDU).e_seq = seqeotX.s_seq; -#else - e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseqX; -#endif /* BYTE_ORDER */ - } else { - e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseq; - } - e.ev_number = XAK_TPDU; - IncStat(ts_XAK_rcvd); - IncPStat(tpcb, tps_XAK_rcvd); - break; - - case XPD_TPDU_type: - if (tpcb->tp_xtd_format) { -#ifdef BYTE_ORDER - union seq_type seqeotX; - - seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); - e.ATTR(XPD_TPDU).e_seq = seqeotX.s_seq; -#else - e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseqX; -#endif /* BYTE_ORDER */ - } else { - e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseq; - } - takes_data = TRUE; - e.ev_number = XPD_TPDU; - IncStat(ts_XPD_rcvd); - IncPStat(tpcb, tps_XPD_rcvd); - break; - - case DT_TPDU_type: - { /* the y option will cause occasional packets to be dropped. - * A little crude but it works. - */ - - IFDEBUG(D_DROP) - if(time.tv_usec & 0x4 && hdr->tpdu_DTseq & 0x1) { - IncStat(ts_ydebug); - goto discard; - } - ENDDEBUG - } - if (tpcb->tp_class == TP_CLASS_0) { - tp0_data: - e.ATTR(DT_TPDU).e_seq = 0; /* actually don't care */ - e.ATTR(DT_TPDU).e_eot = (((struct tp0du *)hdr)->tp0du_eot); - } else if (tpcb->tp_xtd_format) { -#ifdef BYTE_ORDER - union seq_type seqeotX; - - seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); - e.ATTR(DT_TPDU).e_seq = seqeotX.s_seq; - e.ATTR(DT_TPDU).e_eot = seqeotX.s_eot; -#else - e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseqX; - e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeotX; -#endif /* BYTE_ORDER */ - } else { - e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseq; - e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeot; - } - if(e.ATTR(DT_TPDU).e_eot) - IncStat(ts_eot_input); - takes_data = TRUE; - e.ev_number = DT_TPDU; - IncStat(ts_DT_rcvd); - IncPStat(tpcb, tps_DT_rcvd); - break; - - case GR_TPDU_type: - tp_indicate(T_DISCONNECT, tpcb, ECONNABORTED); - /* drop through */ - default: - /* this should NEVER happen because there is a - * check for dutype well above here - */ - error = E_TP_INV_TPDU; /* causes an ER */ - IFDEBUG(D_TPINPUT) - printf("INVALID dutype 0x%x\n", hdr->tpdu_type); - ENDDEBUG - IncStat(ts_inv_dutype); - goto respond; - } - } - /* peel off the tp header; - * remember that the du_li doesn't count itself. - * This may leave us w/ an empty mbuf at the front of a chain. - * We can't just throw away the empty mbuf because hdr still points - * into the mbuf's data area and we're still using hdr (the tpdu header) - */ - m->m_len -= ((int)hdr->tpdu_li + 1); - m->m_data += ((int)hdr->tpdu_li + 1); - - if (takes_data) { - int max = tpdu_info[ hdr->tpdu_type ] [TP_MAX_DATA_INDEX]; - int datalen = tpdu_len - hdr->tpdu_li - 1, mbtype = MT_DATA; - struct { - struct tp_disc_reason dr; - struct cmsghdr x_hdr; - } x; -#define c_hdr x.x_hdr - register struct mbuf *n; - - CHECK( (max && datalen > max), E_TP_LENGTH_INVAL, - ts_inv_length, respond, (max + hdr->tpdu_li + 1) ); - switch( hdr->tpdu_type ) { - - case CR_TPDU_type: - c_hdr.cmsg_type = TPOPT_CONN_DATA; - goto make_control_msg; - - case CC_TPDU_type: - c_hdr.cmsg_type = TPOPT_CFRM_DATA; - goto make_control_msg; - - case DR_TPDU_type: - x.dr.dr_hdr.cmsg_len = sizeof(x) - sizeof(c_hdr); - x.dr.dr_hdr.cmsg_type = TPOPT_DISC_REASON; - x.dr.dr_hdr.cmsg_level = SOL_TRANSPORT; - x.dr.dr_reason = hdr->tpdu_DRreason; - c_hdr.cmsg_type = TPOPT_DISC_DATA; - make_control_msg: - datalen += sizeof(c_hdr); - c_hdr.cmsg_len = datalen; - c_hdr.cmsg_level = SOL_TRANSPORT; - mbtype = MT_CONTROL; - MGET(n, M_DONTWAIT, MT_DATA); - if (n == 0) - {m_freem(m); m = 0; datalen = 0; goto invoke; } - if (hdr->tpdu_type == DR_TPDU_type) { - datalen += sizeof(x) - sizeof(c_hdr); - bcopy((caddr_t)&x, mtod(n, caddr_t), n->m_len = sizeof(x)); - } else - bcopy((caddr_t)&c_hdr, mtod(n, caddr_t), - n->m_len = sizeof(c_hdr)); - n->m_next = m; - m = n; - /* FALLTHROUGH */ - - case XPD_TPDU_type: - if (mbtype != MT_CONTROL) - mbtype = MT_OOBDATA; - m->m_flags |= M_EOR; - /* FALLTHROUGH */ - - case DT_TPDU_type: - for (n = m; n; n = n->m_next) { - MCHTYPE(n, mbtype); - } - invoke: - e.ATTR(DT_TPDU).e_datalen = datalen; - e.ATTR(DT_TPDU).e_data = m; - break; - - default: - printf( - "ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m 0x%x\n", - hdr->tpdu_type, takes_data, m); - break; - } - /* prevent m_freem() after tp_driver() from throwing it all away */ - m = MNULL; - } - - IncStat(ts_tpdu_rcvd); - - IFDEBUG(D_TPINPUT) - printf( "tp_input: before driver, state 0x%x event 0x%x m 0x%x", - tpcb->tp_state, e.ev_number, m ); - printf(" e.e_data 0x%x\n", e.ATTR(DT_TPDU).e_data); - printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n", - takes_data, (m==MNULL)?0:m->m_len, tpdu_len); - ENDDEBUG - - error = tp_driver(tpcb, &e); - - ASSERT(tpcb != (struct tp_pcb *)0); - ASSERT(tpcb->tp_sock != (struct socket *)0); - if( tpcb->tp_sock->so_error == 0 ) - tpcb->tp_sock->so_error = error; - - /* Kludge to keep the state tables under control (adding - * data on connect & disconnect & freeing the mbuf containing - * the data would have exploded the tables and made a big mess ). - */ - switch(e.ev_number) { - case CC_TPDU: - case DR_TPDU: - case CR_TPDU: - m = e.ATTR(CC_TPDU).e_data; /* same field for all three dutypes */ - IFDEBUG(D_TPINPUT) - printf("after driver, restoring m to 0x%x, takes_data 0x%x\n", - m, takes_data); - ENDDEBUG - break; - default: - break; - } - /* Concatenated sequences are terminated by any tpdu that - * carries data: CR, CC, DT, XPD, DR. - * All other tpdu types may be concatenated: AK, XAK, DC, ER. - */ - -separate: - if ( takes_data == 0 ) { - ASSERT( m != MNULL ); - /* - * we already peeled off the prev. tp header so - * we can just pull up some more and repeat - */ - - if( m = tp_inputprep(m) ) { - IFDEBUG(D_TPINPUT) - hdr = mtod(m, struct tpdu *); - printf("tp_input @ separate: hdr 0x%x size %d m 0x%x\n", - hdr, (int) hdr->tpdu_li + 1, m); - dump_mbuf(m, "tp_input after driver, at separate"); - ENDDEBUG - - IncStat(ts_concat_rcvd); - goto again; - } - } - if ( m != MNULL ) { - IFDEBUG(D_TPINPUT) - printf("tp_input : m_freem(0x%x)\n", m); - ENDDEBUG - m_freem(m); - IFDEBUG(D_TPINPUT) - printf("tp_input : after m_freem 0x%x\n", m); - ENDDEBUG - } - return (ProtoHook) tpcb; - -discard: - /* class 4: drop the tpdu */ - /* class 2,0: Should drop the net connection, if you can figure out - * to which connection it applies - */ - IFDEBUG(D_TPINPUT) - printf("tp_input DISCARD\n"); - ENDDEBUG - IFTRACE(D_TPINPUT) - tptrace(TPPTmisc, "tp_input DISCARD m", m,0,0,0); - ENDTRACE - m_freem(m); - IncStat(ts_recv_drop); - return (ProtoHook)0; - -nonx_dref: - switch (dutype) { - default: - goto discard; - case CC_TPDU_type: - /* error = E_TP_MISM_REFS; */ - break; - case DR_TPDU_type: - error |= TP_ERROR_SNDC; - } -respond: - IFDEBUG(D_TPINPUT) - printf("RESPOND: error 0x%x, errlen 0x%x\n", error, errlen); - ENDDEBUG - IFTRACE(D_TPINPUT) - tptrace(TPPTmisc, "tp_input RESPOND m error sref", m, error, sref, 0); - ENDTRACE - if (sref == 0) - goto discard; - (void) tp_error_emit(error, (u_long)sref, (struct sockaddr_iso *)faddr, - (struct sockaddr_iso *)laddr, m, errlen, tpcb, - cons_channel, dgout_routine); - IFDEBUG(D_ERROR_EMIT) - printf("tp_input after error_emit\n"); - ENDDEBUG - -#ifdef lint - printf("",sref,opt); -#endif /* lint */ - IncStat(ts_recv_drop); - return (ProtoHook)0; -} - - -/* - * NAME: tp_headersize() - * - * CALLED FROM: - * tp_emit() and tp_sbsend() - * TP needs to know the header size so it can figure out how - * much data to put in each tpdu. - * - * FUNCTION, ARGUMENTS, and RETURN VALUE: - * For a given connection, represented by (tpcb), and - * tpdu type (dutype), return the size of a tp header. - * - * RETURNS: the expected size of the heade in bytesr - * - * SIDE EFFECTS: - * - * NOTES: It would be nice if it got the network header size as well. - */ -int -tp_headersize(dutype, tpcb) - int dutype; - struct tp_pcb *tpcb; -{ - register int size = 0; - - IFTRACE(D_CONN) - tptrace(TPPTmisc, "tp_headersize dutype class xtd_format", - dutype, tpcb->tp_class, tpcb->tp_xtd_format, 0); - ENDTRACE - if( !( (tpcb->tp_class == TP_CLASS_0) || - (tpcb->tp_class == TP_CLASS_4) || - (dutype == DR_TPDU_type) || - (dutype == CR_TPDU_type) )) { - printf("tp_headersize:dutype 0x%x, class 0x%x", - dutype, tpcb->tp_class); - /* TODO: identify this and GET RID OF IT */ - } - ASSERT( (tpcb->tp_class == TP_CLASS_0) || - (tpcb->tp_class == TP_CLASS_4) || - (dutype == DR_TPDU_type) || - (dutype == CR_TPDU_type) ); - - if( tpcb->tp_class == TP_CLASS_0 ) { - size = tpdu_info[ dutype ] [TP_LEN_CLASS_0_INDEX]; - } else { - size = tpdu_info[ dutype ] [tpcb->tp_xtd_format]; - } - return size; - /* caller must get network level header size separately */ -} diff --git a/bsd/netiso/tp_ip.h b/bsd/netiso/tp_ip.h deleted file mode 100644 index 51b3111b7..000000000 --- a/bsd/netiso/tp_ip.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)tp_ip.h 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * ARGO TP - * - * internet IP-dependent structures and include files - * - */ - - -#ifndef __TP_IP__ -#define __TP_IP__ - -#ifndef SOCK_STREAM -#include -#endif - -#include -#include -#include -#include -#include -#include - - -struct inpcb tp_inpcb; - /* queue of active inpcbs for tp ; for tp with dod ip */ - -#endif /* __TP_IP__ */ diff --git a/bsd/netiso/tp_iso.c b/bsd/netiso/tp_iso.c deleted file mode 100644 index 22a739984..000000000 --- a/bsd/netiso/tp_iso.c +++ /dev/null @@ -1,712 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)tp_iso.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * ARGO TP - * - * Here is where you find the iso-dependent code. We've tried - * keep all net-level and (primarily) address-family-dependent stuff - * out of the tp source, and everthing here is reached indirectly - * through a switch table (struct nl_protosw *) tpcb->tp_nlproto - * (see tp_pcb.c). - * The routines here are: - * iso_getsufx: gets transport suffix out of an isopcb structure. - * iso_putsufx: put transport suffix into an isopcb structure. - * iso_putnetaddr: put a whole net addr into an isopcb. - * iso_getnetaddr: get a whole net addr from an isopcb. - * iso_cmpnetaddr: compare a whole net addr from an isopcb. - * iso_recycle_suffix: clear suffix for reuse in isopcb - * tpclnp_ctlinput: handle ER CNLPdu : icmp-like stuff - * tpclnp_mtu: figure out what size tpdu to use - * tpclnp_input: take a pkt from clnp, strip off its clnp header, - * give to tp - * tpclnp_output_dg: package a pkt for clnp given 2 addresses & some data - * tpclnp_output: package a pkt for clnp given an isopcb & some data - */ - -#if ISO - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * CALLED FROM: - * pr_usrreq() on PRU_BIND, PRU_CONNECT, PRU_ACCEPT, and PRU_PEERADDR - * FUNCTION, ARGUMENTS: - * The argument (which) takes the value TP_LOCAL or TP_FOREIGN. - */ - -iso_getsufx(isop, lenp, data_out, which) - struct isopcb *isop; - u_short *lenp; - caddr_t data_out; - int which; -{ - register struct sockaddr_iso *addr = 0; - - switch (which) { - case TP_LOCAL: - addr = isop->isop_laddr; - break; - - case TP_FOREIGN: - addr = isop->isop_faddr; - } - if (addr) - bcopy(TSEL(addr), data_out, (*lenp = addr->siso_tlen)); -} - -/* CALLED FROM: - * tp_newsocket(); i.e., when a connection is being established by an - * incoming CR_TPDU. - * - * FUNCTION, ARGUMENTS: - * Put a transport suffix (found in name) into an isopcb structure (isop). - * The argument (which) takes the value TP_LOCAL or TP_FOREIGN. - */ -void -iso_putsufx(isop, sufxloc, sufxlen, which) - struct isopcb *isop; - caddr_t sufxloc; - int sufxlen, which; -{ - struct sockaddr_iso **dst, *backup; - register struct sockaddr_iso *addr; - struct mbuf *m; - int len; - - switch (which) { - default: - return; - - case TP_LOCAL: - dst = &isop->isop_laddr; - backup = &isop->isop_sladdr; - break; - - case TP_FOREIGN: - dst = &isop->isop_faddr; - backup = &isop->isop_sfaddr; - } - if ((addr = *dst) == 0) { - addr = *dst = backup; - addr->siso_nlen = 0; - addr->siso_slen = 0; - addr->siso_plen = 0; - printf("iso_putsufx on un-initialized isopcb\n"); - } - len = sufxlen + addr->siso_nlen + - (sizeof(*addr) - sizeof(addr->siso_data)); - if (addr == backup) { - if (len > sizeof(*addr)) { - m = m_getclr(M_DONTWAIT, MT_SONAME); - if (m == 0) - return; - addr = *dst = mtod(m, struct sockaddr_iso *); - *addr = *backup; - m->m_len = len; - } - } - bcopy(sufxloc, TSEL(addr), sufxlen); - addr->siso_tlen = sufxlen; - addr->siso_len = len; -} - -/* - * CALLED FROM: - * tp.trans whenever we go into REFWAIT state. - * FUNCTION and ARGUMENT: - * Called when a ref is frozen, to allow the suffix to be reused. - * (isop) is the net level pcb. This really shouldn't have to be - * done in a NET level pcb but... for the internet world that just - * the way it is done in BSD... - * The alternative is to have the port unusable until the reference - * timer goes off. - */ -void -iso_recycle_tsuffix(isop) - struct isopcb *isop; -{ - isop->isop_laddr->siso_tlen = isop->isop_faddr->siso_tlen = 0; -} - -/* - * CALLED FROM: - * tp_newsocket(); i.e., when a connection is being established by an - * incoming CR_TPDU. - * - * FUNCTION and ARGUMENTS: - * Copy a whole net addr from a struct sockaddr (name). - * into an isopcb (isop). - * The argument (which) takes values TP_LOCAL or TP_FOREIGN - */ -void -iso_putnetaddr(isop, name, which) - register struct isopcb *isop; - struct sockaddr_iso *name; - int which; -{ - struct sockaddr_iso **sisop, *backup; - register struct sockaddr_iso *siso; - - switch (which) { - default: - printf("iso_putnetaddr: should panic\n"); - return; - case TP_LOCAL: - sisop = &isop->isop_laddr; - backup = &isop->isop_sladdr; - break; - case TP_FOREIGN: - sisop = &isop->isop_faddr; - backup = &isop->isop_sfaddr; - } - siso = ((*sisop == 0) ? (*sisop = backup) : *sisop); - IFDEBUG(D_TPISO) - printf("ISO_PUTNETADDR\n"); - dump_isoaddr(isop->isop_faddr); - ENDDEBUG - siso->siso_addr = name->siso_addr; -} - -/* - * CALLED FROM: - * tp_input() when a connection is being established by an - * incoming CR_TPDU, and considered for interception. - * - * FUNCTION and ARGUMENTS: - * compare a whole net addr from a struct sockaddr (name), - * with that implicitly stored in an isopcb (isop). - * The argument (which) takes values TP_LOCAL or TP_FOREIGN. - */ -iso_cmpnetaddr(isop, name, which) - register struct isopcb *isop; - register struct sockaddr_iso *name; - int which; -{ - struct sockaddr_iso **sisop, *backup; - register struct sockaddr_iso *siso; - - switch (which) { - default: - printf("iso_cmpnetaddr: should panic\n"); - return 0; - case TP_LOCAL: - sisop = &isop->isop_laddr; - backup = &isop->isop_sladdr; - break; - case TP_FOREIGN: - sisop = &isop->isop_faddr; - backup = &isop->isop_sfaddr; - } - siso = ((*sisop == 0) ? (*sisop = backup) : *sisop); - IFDEBUG(D_TPISO) - printf("ISO_CMPNETADDR\n"); - dump_isoaddr(siso); - ENDDEBUG - if (name->siso_tlen && bcmp(TSEL(name), TSEL(siso), name->siso_tlen)) - return (0); - return (bcmp((caddr_t)name->siso_data, - (caddr_t)siso->siso_data, name->siso_nlen) == 0); -} - -/* - * CALLED FROM: - * pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR - * FUNCTION and ARGUMENTS: - * Copy a whole net addr from an isopcb (isop) into - * a struct sockaddr (name). - * The argument (which) takes values TP_LOCAL or TP_FOREIGN. - */ - -void -iso_getnetaddr( isop, name, which) - struct isopcb *isop; - struct mbuf *name; - int which; -{ - struct sockaddr_iso *siso = - (which == TP_LOCAL ? isop->isop_laddr : isop->isop_faddr); - if (siso) - bcopy((caddr_t)siso, mtod(name, caddr_t), - (unsigned)(name->m_len = siso->siso_len)); - else - name->m_len = 0; -} -/* - * NAME: tpclnp_mtu() - * - * CALLED FROM: - * tp_route_to() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT - * - * FUNCTION, ARGUMENTS, and RETURN VALUE: - * - * Perform subnetwork dependent part of determining MTU information. - * It appears that setting a double pointer to the rtentry associated with - * the destination, and returning the header size for the network protocol - * suffices. - * - * SIDE EFFECTS: - * Sets tp_routep pointer in pcb. - * - * NOTES: - */ -tpclnp_mtu(tpcb) -register struct tp_pcb *tpcb; -{ - struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; - - IFDEBUG(D_CONN) - printf("tpclnp_mtu(tpcb)\n", tpcb); - ENDDEBUG - tpcb->tp_routep = &(isop->isop_route.ro_rt); - if (tpcb->tp_netservice == ISO_CONS) - return 0; - else - return (sizeof(struct clnp_fixed) + sizeof(struct clnp_segment) + - 2 * sizeof(struct iso_addr)); - -} - -/* - * CALLED FROM: - * tp_emit() - * FUNCTION and ARGUMENTS: - * Take a packet(m0) from tp and package it so that clnp will accept it. - * This means prepending space for the clnp header and filling in a few - * of the fields. - * isop is the isopcb structure; datalen is the length of the data in the - * mbuf string m0. - * RETURN VALUE: - * whatever (E*) is returned form the net layer output routine. - */ - -int -tpclnp_output(isop, m0, datalen, nochksum) - struct isopcb *isop; - struct mbuf *m0; - int datalen; - int nochksum; -{ - register struct mbuf *m = m0; - IncStat(ts_tpdu_sent); - - IFDEBUG(D_TPISO) - struct tpdu *hdr = mtod(m0, struct tpdu *); - - printf( -"abt to call clnp_output: datalen 0x%x, hdr.li 0x%x, hdr.dutype 0x%x nocsum x%x dst addr:\n", - datalen, - (int)hdr->tpdu_li, (int)hdr->tpdu_type, nochksum); - dump_isoaddr(isop->isop_faddr); - printf("\nsrc addr:\n"); - dump_isoaddr(isop->isop_laddr); - dump_mbuf(m0, "at tpclnp_output"); - ENDDEBUG - - return - clnp_output(m0, isop, datalen, /* flags */nochksum ? CLNP_NO_CKSUM : 0); -} - -/* - * CALLED FROM: - * tp_error_emit() - * FUNCTION and ARGUMENTS: - * This is a copy of tpclnp_output that takes the addresses - * instead of a pcb. It's used by the tp_error_emit, when we - * don't have an iso_pcb with which to call the normal output rtn. - * RETURN VALUE: - * ENOBUFS or - * whatever (E*) is returned form the net layer output routine. - */ - -int -tpclnp_output_dg(laddr, faddr, m0, datalen, ro, nochksum) - struct iso_addr *laddr, *faddr; - struct mbuf *m0; - int datalen; - struct route *ro; - int nochksum; -{ - struct isopcb tmppcb; - int err; - int flags; - register struct mbuf *m = m0; - - IFDEBUG(D_TPISO) - printf("tpclnp_output_dg datalen 0x%x m0 0x%x\n", datalen, m0); - ENDDEBUG - - /* - * Fill in minimal portion of isopcb so that clnp can send the - * packet. - */ - bzero((caddr_t)&tmppcb, sizeof(tmppcb)); - tmppcb.isop_laddr = &tmppcb.isop_sladdr; - tmppcb.isop_laddr->siso_addr = *laddr; - tmppcb.isop_faddr = &tmppcb.isop_sfaddr; - tmppcb.isop_faddr->siso_addr = *faddr; - - IFDEBUG(D_TPISO) - printf("tpclnp_output_dg faddr: \n"); - dump_isoaddr(&tmppcb.isop_sfaddr); - printf("\ntpclnp_output_dg laddr: \n"); - dump_isoaddr(&tmppcb.isop_sladdr); - printf("\n"); - ENDDEBUG - - /* - * Do not use packet cache since this is a one shot error packet - */ - flags = (CLNP_NOCACHE|(nochksum?CLNP_NO_CKSUM:0)); - - IncStat(ts_tpdu_sent); - - err = clnp_output(m0, &tmppcb, datalen, flags); - - /* - * Free route allocated by clnp (if the route was indeed allocated) - */ - if (tmppcb.isop_route.ro_rt) - RTFREE(tmppcb.isop_route.ro_rt); - - return(err); -} -/* - * CALLED FROM: - * clnp's input routine, indirectly through the protosw. - * FUNCTION and ARGUMENTS: - * Take a packet (m) from clnp, strip off the clnp header and give it to tp - * No return value. - */ -ProtoHook -tpclnp_input(m, src, dst, clnp_len, ce_bit) - register struct mbuf *m; - struct sockaddr_iso *src, *dst; - int clnp_len, ce_bit; -{ - struct mbuf *tp_inputprep(); - int tp_input(), cltp_input(), (*input)() = tp_input; - - IncStat(ts_pkt_rcvd); - - IFDEBUG(D_TPINPUT) - printf("tpclnp_input: m 0x%x clnp_len 0x%x\n", m, clnp_len); - dump_mbuf(m, "at tpclnp_input"); - ENDDEBUG - /* - * CLNP gives us an mbuf chain WITH the clnp header pulled up, - * and the length of the clnp header. - * First, strip off the Clnp header. leave the mbuf there for the - * pullup that follows. - */ - m->m_len -= clnp_len; - m->m_data += clnp_len; - m->m_pkthdr.len -= clnp_len; - /* XXXX: should probably be in clnp_input */ - switch (dst->siso_data[dst->siso_nlen - 1]) { -#if TUBA - case ISOPROTO_TCP: - return (tuba_tcpinput(m, src, dst)); -#endif - case 0: - if (m->m_len == 0 && (m = m_pullup(m, 1)) == 0) - return 0; - if (*(mtod(m, u_char *)) == ISO10747_IDRP) - return (idrp_input(m, src, dst)); - } - m = tp_inputprep(m); - if (m == 0) - return 0; - if (mtod(m, u_char *)[1] == UD_TPDU_type) - input = cltp_input; - - IFDEBUG(D_TPINPUT) - dump_mbuf(m, "after tpclnp_input both pullups"); - ENDDEBUG - - IFDEBUG(D_TPISO) - printf("calling %sinput : src 0x%x, dst 0x%x, src addr:\n", - (input == tp_input ? "tp_" : "clts_"), src, dst); - dump_isoaddr(src); - printf(" dst addr:\n"); - dump_isoaddr(dst); - ENDDEBUG - - (void) (*input)(m, (struct sockaddr *)src, (struct sockaddr *)dst, - 0, tpclnp_output_dg, ce_bit); - - IFDEBUG(D_QUENCH) - { - if(time.tv_usec & 0x4 && time.tv_usec & 0x40) { - printf("tpclnp_input: FAKING %s\n", - tp_stat.ts_pkt_rcvd & 0x1?"QUENCH":"QUENCH2"); - if(tp_stat.ts_pkt_rcvd & 0x1) { - tpclnp_ctlinput(PRC_QUENCH, &src); - } else { - tpclnp_ctlinput(PRC_QUENCH2, &src); - } - } - } - ENDDEBUG - - return 0; -} - -ProtoHook -iso_rtchange() -{ - return 0; -} - -/* - * CALLED FROM: - * tpclnp_ctlinput() - * FUNCTION and ARGUMENTS: - * find the tpcb pointer and pass it to tp_quench - */ -void -tpiso_decbit(isop) - struct isopcb *isop; -{ - tp_quench((struct tp_pcb *)isop->isop_socket->so_pcb, PRC_QUENCH2); -} -/* - * CALLED FROM: - * tpclnp_ctlinput() - * FUNCTION and ARGUMENTS: - * find the tpcb pointer and pass it to tp_quench - */ -void -tpiso_quench(isop) - struct isopcb *isop; -{ - tp_quench((struct tp_pcb *)isop->isop_socket->so_pcb, PRC_QUENCH); -} - -/* - * CALLED FROM: - * The network layer through the protosw table. - * FUNCTION and ARGUMENTS: - * When clnp an ICMP-like msg this gets called. - * It either returns an error status to the user or - * it causes all connections on this address to be aborted - * by calling the appropriate xx_notify() routine. - * (cmd) is the type of ICMP error. - * (siso) is the address of the guy who sent the ER CLNPDU - */ -ProtoHook -tpclnp_ctlinput(cmd, siso) - int cmd; - struct sockaddr_iso *siso; -{ - extern u_char inetctlerrmap[]; - extern ProtoHook tpiso_abort(); - extern ProtoHook iso_rtchange(); - extern ProtoHook tpiso_reset(); - void iso_pcbnotify(); - - IFDEBUG(D_TPINPUT) - printf("tpclnp_ctlinput1: cmd 0x%x addr: \n", cmd); - dump_isoaddr(siso); - ENDDEBUG - - if (cmd < 0 || cmd > PRC_NCMDS) - return 0; - if (siso->siso_family != AF_ISO) - return 0; - switch (cmd) { - - case PRC_QUENCH2: - iso_pcbnotify(&tp_isopcb, siso, 0, (int (*)())tpiso_decbit); - break; - - case PRC_QUENCH: - iso_pcbnotify(&tp_isopcb, siso, 0, (int (*)())tpiso_quench); - break; - - case PRC_TIMXCEED_REASS: - case PRC_ROUTEDEAD: - iso_pcbnotify(&tp_isopcb, siso, 0, tpiso_reset); - break; - - case PRC_HOSTUNREACH: - case PRC_UNREACH_NET: - case PRC_IFDOWN: - case PRC_HOSTDEAD: - iso_pcbnotify(&tp_isopcb, siso, - (int)inetctlerrmap[cmd], iso_rtchange); - break; - - default: - /* - case PRC_MSGSIZE: - case PRC_UNREACH_HOST: - case PRC_UNREACH_PROTOCOL: - case PRC_UNREACH_PORT: - case PRC_UNREACH_NEEDFRAG: - case PRC_UNREACH_SRCFAIL: - case PRC_REDIRECT_NET: - case PRC_REDIRECT_HOST: - case PRC_REDIRECT_TOSNET: - case PRC_REDIRECT_TOSHOST: - case PRC_TIMXCEED_INTRANS: - case PRC_PARAMPROB: - */ - iso_pcbnotify(&tp_isopcb, siso, (int)inetctlerrmap[cmd], tpiso_abort); - break; - } - return 0; -} -/* - * XXX - Variant which is called by clnp_er.c with an isoaddr rather - * than a sockaddr_iso. - */ - -static struct sockaddr_iso siso = {sizeof(siso), AF_ISO}; -tpclnp_ctlinput1(cmd, isoa) - int cmd; - struct iso_addr *isoa; -{ - bzero((caddr_t)&siso.siso_addr, sizeof(siso.siso_addr)); - bcopy((caddr_t)isoa, (caddr_t)&siso.siso_addr, isoa->isoa_len); - tpclnp_ctlinput(cmd, &siso); -} - -/* - * These next 2 routines are - * CALLED FROM: - * xxx_notify() from tp_ctlinput() when - * net level gets some ICMP-equiv. type event. - * FUNCTION and ARGUMENTS: - * Cause the connection to be aborted with some sort of error - * reason indicating that the network layer caused the abort. - * Fakes an ER TPDU so we can go through the driver. - * abort always aborts the TP connection. - * reset may or may not, depending on the TP class that's in use. - */ -ProtoHook -tpiso_abort(isop) - struct isopcb *isop; -{ - struct tp_event e; - - IFDEBUG(D_CONN) - printf("tpiso_abort 0x%x\n", isop); - ENDDEBUG - e.ev_number = ER_TPDU; - e.ATTR(ER_TPDU).e_reason = ECONNABORTED; - return tp_driver((struct tp_pcb *)isop->isop_socket->so_pcb, &e); -} - -ProtoHook -tpiso_reset(isop) - struct isopcb *isop; -{ - struct tp_event e; - - e.ev_number = T_NETRESET; - return tp_driver((struct tp_pcb *)isop->isop_socket->so_pcb, &e); - -} - -#endif /* ISO */ diff --git a/bsd/netiso/tp_meas.c b/bsd/netiso/tp_meas.c deleted file mode 100644 index a0981f088..000000000 --- a/bsd/netiso/tp_meas.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)tp_meas.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * tp_meas.c : create a performance measurement event - * in the circular buffer tp_Meas[] - */ - -#include -#include - -#include -#include - -extern struct timeval time; - -#ifdef TP_PERF_MEAS -int tp_Measn = 0; -struct tp_Meas tp_Meas[TPMEASN]; - -/* - * NAME: tpmeas() - * - * CALLED FROM: tp_emit(), tp_soisdisconecting(), tp_soisdisconnected() - * tp0_stash(), tp_stash(), tp_send(), tp_goodack(), tp_usrreq() - * - * FUNCTION and ARGUMENTS: - * stashes a performance-measurement event for the given reference (ref) - * (kind) tells which kind of event, timev is the time to be stored - * with this event, (seq), (win), and (size) are integers that usually - * refer to the sequence number, window number (on send) and - * size of tpdu or window. - * - * RETURNS: Nada - * - * SIDE EFFECTS: - * - * NOTES: - */ -void -Tpmeas(ref, kind, timev, seq, win, size) - u_int ref; - u_int kind; - struct timeval *timev; - u_int seq, win, size; -{ - register struct tp_Meas *tpm; - static int mseq; - - tpm = &tp_Meas[tp_Measn++]; - tp_Measn %= TPMEASN; - - tpm->tpm_kind = kind; - tpm->tpm_tseq = mseq++; - tpm->tpm_ref = ref; - if(kind == TPtime_from_ll) - bcopy((caddr_t)timev, (caddr_t)&tpm->tpm_time, sizeof(struct timeval)); - else - bcopy( (caddr_t)&time, - (caddr_t)&tpm->tpm_time, sizeof(struct timeval) ); - tpm->tpm_seq = seq; - tpm->tpm_window = win; - tpm->tpm_size = size; -} - -#endif /* TP_PERF_MEAS */ diff --git a/bsd/netiso/tp_meas.h b/bsd/netiso/tp_meas.h deleted file mode 100644 index b5bcf65c2..000000000 --- a/bsd/netiso/tp_meas.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)tp_meas.h 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -#ifdef TP_PERF_MEAS -#define tpmeas(a, b, t, c, d, e) \ - Tpmeas((u_int)(a), (u_int)(b), t, (u_int)(c), (u_int)(d), (u_int)(e)) - -struct tp_Meas { - int tpm_tseq; - u_char tpm_kind; - u_short tpm_ref; - u_short tpm_size; - u_short tpm_window; - u_int tpm_seq; - struct timeval tpm_time; -}; - -#define TPMEASN 4000 -extern int tp_Measn; -extern struct tp_Meas tp_Meas[]; - -/* - * the kinds of events for packet tracing are: - */ -#define TPtime_from_session 0x01 -#define TPtime_to_session 0x02 -#define TPtime_ack_rcvd 0x03 -#define TPtime_ack_sent 0x04 -#define TPtime_from_ll 0x05 -#define TPtime_to_ll 0x06 -#define TPsbsend 0x07 -#define TPtime_open 0x08 -#define TPtime_open_X 0x28 /* xtd format */ -#define TPtime_close 0x09 - -#endif /* TP_PERF_MEAS */ diff --git a/bsd/netiso/tp_output.c b/bsd/netiso/tp_output.c deleted file mode 100644 index 4f97ba160..000000000 --- a/bsd/netiso/tp_output.c +++ /dev/null @@ -1,730 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)tp_output.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * ARGO TP - * - * In here is tp_ctloutput(), the guy called by [sg]etsockopt(), - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define TPDUSIZESHIFT 24 -#define CLASSHIFT 16 - -/* - * NAME: tp_consistency() - * - * CALLED FROM: - * tp_ctloutput(), tp_input() - * - * FUNCTION and ARGUMENTS: - * Checks the consistency of options and tpdusize with class, - * using the parameters passed in via (param). - * (cmd) may be TP_STRICT or TP_FORCE or both. - * Force means it will set all the values in (tpcb) to those in - * the input arguements iff no errors were encountered. - * Strict means that no inconsistency will be tolerated. If it's - * not used, checksum and tpdusize inconsistencies will be tolerated. - * The reason for this is that in some cases, when we're negotiating down - * from class 4, these options should be changed but should not - * cause negotiation to fail. - * - * RETURNS - * E* or EOK - * E* if the various parms aren't ok for a given class - * EOK if they are ok for a given class - */ - -int -tp_consistency( tpcb, cmd, param ) - u_int cmd; - struct tp_conn_param *param; - struct tp_pcb *tpcb; -{ - register int error = EOK; - int class_to_use = tp_mask_to_num(param->p_class); - - IFTRACE(D_SETPARAMS) - tptrace(TPPTmisc, - "tp_consist enter class_to_use dontchange param.class cmd", - class_to_use, param->p_dont_change_params, param->p_class, cmd); - ENDTRACE - IFDEBUG(D_SETPARAMS) - printf("tp_consistency %s %s\n", - cmd& TP_FORCE? "TP_FORCE": "", - cmd& TP_STRICT? "TP_STRICT":""); - ENDDEBUG - if ((cmd & TP_FORCE) && (param->p_dont_change_params)) { - cmd &= ~TP_FORCE; - } - /* can switch net services within a domain, but - * cannot switch domains - */ - switch( param->p_netservice) { - case ISO_CONS: - case ISO_CLNS: - case ISO_COSNS: - /* param->p_netservice in ISO DOMAIN */ - if(tpcb->tp_domain != AF_ISO ) { - error = EINVAL; goto done; - } - break; - case IN_CLNS: - /* param->p_netservice in INET DOMAIN */ - if( tpcb->tp_domain != AF_INET ) { - error = EINVAL; goto done; - } - break; - /* no others not possible-> netservice is a 2-bit field! */ - } - - IFDEBUG(D_SETPARAMS) - printf("p_class 0x%x, class_to_use 0x%x\n", param->p_class, - class_to_use); - ENDDEBUG - if((param->p_netservice < 0) || (param->p_netservice > TP_MAX_NETSERVICES)){ - error = EINVAL; goto done; - } - if( (param->p_class & TP_CLASSES_IMPLEMENTED) == 0 ) { - error = EINVAL; goto done; - } - IFDEBUG(D_SETPARAMS) - printf("Nretrans 0x%x\n", param->p_Nretrans ); - ENDDEBUG - if( ( param->p_Nretrans < 1 ) || - (param->p_cr_ticks < 1) || (param->p_cc_ticks < 1) ) { - /* bad for any class because negot has to be done a la class 4 */ - error = EINVAL; goto done; - } - IFDEBUG(D_SETPARAMS) - printf("use_csum 0x%x\n", param->p_use_checksum ); - printf("xtd_format 0x%x\n", param->p_xtd_format ); - printf("xpd_service 0x%x\n", param->p_xpd_service ); - printf("tpdusize 0x%x\n", param->p_tpdusize ); - printf("tpcb->flags 0x%x\n", tpcb->tp_flags ); - ENDDEBUG - switch( class_to_use ) { - - case 0: - /* do not use checksums, xtd format, or XPD */ - - if( param->p_use_checksum | param->p_xtd_format | param->p_xpd_service ) { - if(cmd & TP_STRICT) { - error = EINVAL; - } else { - param->p_use_checksum = 0; - param->p_xtd_format = 0; - param->p_xpd_service = 0; - } - break; - } - - if (param->p_tpdusize < TP_MIN_TPDUSIZE) { - if(cmd & TP_STRICT) { - error = EINVAL; - } else { - param->p_tpdusize = TP_MIN_TPDUSIZE; - } - break; - } - if (param->p_tpdusize > TP0_TPDUSIZE) { - if (cmd & TP_STRICT) { - error = EINVAL; - } else { - param->p_tpdusize = TP0_TPDUSIZE; - } - break; - } - - /* connect/disc data not allowed for class 0 */ - if (tpcb->tp_ucddata) { - if(cmd & TP_STRICT) { - error = EINVAL; - } else if(cmd & TP_FORCE) { - m_freem(tpcb->tp_ucddata); - tpcb->tp_ucddata = 0; - } - } - break; - - case 4: - IFDEBUG(D_SETPARAMS) - printf("dt_ticks 0x%x\n", param->p_dt_ticks ); - printf("x_ticks 0x%x\n", param->p_x_ticks ); - printf("dr_ticks 0x%x\n", param->p_dr_ticks ); - printf("keepalive 0x%x\n", param->p_keepalive_ticks ); - printf("sendack 0x%x\n", param->p_sendack_ticks ); - printf("inact 0x%x\n", param->p_inact_ticks ); - printf("ref 0x%x\n", param->p_ref_ticks ); - ENDDEBUG - if( (param->p_class & TP_CLASS_4 ) && ( - (param->p_dt_ticks < 1) || (param->p_dr_ticks < 1) || - (param->p_x_ticks < 1) || (param->p_keepalive_ticks < 1) || - (param->p_sendack_ticks < 1) || (param->p_ref_ticks < 1) || - (param->p_inact_ticks < 1) ) ) { - error = EINVAL; - break; - } - IFDEBUG(D_SETPARAMS) - printf("rx_strat 0x%x\n", param->p_rx_strat ); - ENDDEBUG - if(param->p_rx_strat > - ( TPRX_USE_CW | TPRX_EACH | TPRX_FASTSTART) ) { - if(cmd & TP_STRICT) { - error = EINVAL; - } else { - param->p_rx_strat = TPRX_USE_CW; - } - break; - } - IFDEBUG(D_SETPARAMS) - printf("ack_strat 0x%x\n", param->p_ack_strat ); - ENDDEBUG - if((param->p_ack_strat != 0) && (param->p_ack_strat != 1)) { - if(cmd & TP_STRICT) { - error = EINVAL; - } else { - param->p_ack_strat = TPACK_WINDOW; - } - break; - } - if (param->p_tpdusize < TP_MIN_TPDUSIZE) { - if(cmd & TP_STRICT) { - error = EINVAL; - } else { - param->p_tpdusize = TP_MIN_TPDUSIZE; - } - break; - } - if (param->p_tpdusize > TP_TPDUSIZE) { - if(cmd & TP_STRICT) { - error = EINVAL; - } else { - param->p_tpdusize = TP_TPDUSIZE; - } - break; - } - break; - } - - if ((error==0) && (cmd & TP_FORCE)) { - long dusize = ((long)param->p_ptpdusize) << 7; - /* Enforce Negotation rules below */ - tpcb->tp_class = param->p_class; - if (tpcb->tp_use_checksum || param->p_use_checksum) - tpcb->tp_use_checksum = 1; - if (!tpcb->tp_xpd_service || !param->p_xpd_service) - tpcb->tp_xpd_service = 0; - if (!tpcb->tp_xtd_format || !param->p_xtd_format) - tpcb->tp_xtd_format = 0; - if (dusize) { - if (tpcb->tp_l_tpdusize > dusize) - tpcb->tp_l_tpdusize = dusize; - if (tpcb->tp_ptpdusize == 0 || - tpcb->tp_ptpdusize > param->p_ptpdusize) - tpcb->tp_ptpdusize = param->p_ptpdusize; - } else { - if (param->p_tpdusize != 0 && - tpcb->tp_tpdusize > param->p_tpdusize) - tpcb->tp_tpdusize = param->p_tpdusize; - tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize; - } - } -done: - - IFTRACE(D_CONN) - tptrace(TPPTmisc, "tp_consist returns class xtdfmt cmd", - error, tpcb->tp_class, tpcb->tp_xtd_format, cmd); - ENDTRACE - IFDEBUG(D_CONN) - printf( - "tp_consist rtns 0x%x class 0x%x xtd_fmt 0x%x cmd 0x%x\n", - error, tpcb->tp_class, tpcb->tp_xtd_format, cmd); - ENDDEBUG - return error; -} - -/* - * NAME: tp_ctloutput() - * - * CALLED FROM: - * [sg]etsockopt(), via so[sg]etopt(). - * - * FUNCTION and ARGUMENTS: - * Implements the socket options at transport level. - * (cmd) is either PRCO_SETOPT or PRCO_GETOPT (see ../sys/protosw.h). - * (so) is the socket. - * (level) is SOL_TRANSPORT (see ../sys/socket.h) - * (optname) is the particular command or option to be set. - * (**mp) is an mbuf structure. - * - * RETURN VALUE: - * ENOTSOCK if the socket hasn't got an associated tpcb - * EINVAL if - * trying to set window too big - * trying to set illegal max tpdu size - * trying to set illegal credit fraction - * trying to use unknown or unimplemented class of TP - * structure passed to set timer values is wrong size - * illegal combination of command/GET-SET option, - * e.g., GET w/ TPOPT_CDDATA_CLEAR: - * EOPNOTSUPP if the level isn't transport, or command is neither GET nor SET - * or if the transport-specific command is not implemented - * EISCONN if trying a command that isn't allowed after a connection - * is established - * ENOTCONN if trying a command that is allowed only if a connection is - * established - * EMSGSIZE if trying to give too much data on connect/disconnect - * - * SIDE EFFECTS: - * - * NOTES: - */ -ProtoHook -tp_ctloutput(cmd, so, level, optname, mp) - int cmd, level, optname; - struct socket *so; - struct mbuf **mp; -{ - struct tp_pcb *tpcb = sototpcb(so); - int s = splnet(); - caddr_t value; - unsigned val_len; - int error = 0; - - IFTRACE(D_REQUEST) - tptrace(TPPTmisc, "tp_ctloutput cmd so optname mp", - cmd, so, optname, mp); - ENDTRACE - IFDEBUG(D_REQUEST) - printf( - "tp_ctloutput so 0x%x cmd 0x%x optname 0x%x, mp 0x%x *mp 0x%x tpcb 0x%x\n", - so, cmd, optname, mp, mp?*mp:0, tpcb); - ENDDEBUG - if( tpcb == (struct tp_pcb *)0 ) { - error = ENOTSOCK; goto done; - } - if(*mp == MNULL) { - register struct mbuf *m; - - MGET(m, M_DONTWAIT, TPMT_SONAME); /* does off, type, next */ - if (m == NULL) { - splx(s); - return ENOBUFS; - } - m->m_len = 0; - m->m_act = 0; - *mp = m; - } - - /* - * Hook so one can set network options via a tp socket. - */ - if ( level == SOL_NETWORK ) { - if ((tpcb->tp_nlproto == NULL) || (tpcb->tp_npcb == NULL)) - error = ENOTSOCK; - else if (tpcb->tp_nlproto->nlp_ctloutput == NULL) - error = EOPNOTSUPP; - else - return ((tpcb->tp_nlproto->nlp_ctloutput)(cmd, optname, - tpcb->tp_npcb, *mp)); - goto done; - } else if ( level == SOL_SOCKET) { - if (optname == SO_RCVBUF && cmd == PRCO_SETOPT) { - u_long old_credit = tpcb->tp_maxlcredit; - tp_rsyset(tpcb); - if (tpcb->tp_rhiwat != so->so_rcv.sb_hiwat && - tpcb->tp_state == TP_OPEN && - (old_credit < tpcb->tp_maxlcredit)) - tp_emit(AK_TPDU_type, tpcb, - tpcb->tp_rcvnxt, 0, MNULL); - tpcb->tp_rhiwat = so->so_rcv.sb_hiwat; - } - goto done; - } else if ( level != SOL_TRANSPORT ) { - error = EOPNOTSUPP; goto done; - } - if (cmd != PRCO_GETOPT && cmd != PRCO_SETOPT) { - error = EOPNOTSUPP; goto done; - } - if ( so->so_error ) { - error = so->so_error; goto done; - } - - /* The only options allowed after connection is established - * are GET (anything) and SET DISC DATA and SET PERF MEAS - */ - if ( ((so->so_state & SS_ISCONNECTING)||(so->so_state & SS_ISCONNECTED)) - && - (cmd == PRCO_SETOPT && - optname != TPOPT_DISC_DATA && - optname != TPOPT_CFRM_DATA && - optname != TPOPT_PERF_MEAS && - optname != TPOPT_CDDATA_CLEAR ) ) { - error = EISCONN; goto done; - } - /* The only options allowed after disconnection are GET DISC DATA, - * and TPOPT_PSTATISTICS - * and they're not allowed if the ref timer has gone off, because - * the tpcb is gone - */ - if ((so->so_state & (SS_ISCONNECTED | SS_ISCONFIRMING)) == 0) { - if ( so->so_pcb == (caddr_t)0 ) { - error = ENOTCONN; goto done; - } - if ( (tpcb->tp_state == TP_REFWAIT || tpcb->tp_state == TP_CLOSING) && - (optname != TPOPT_DISC_DATA && optname != TPOPT_PSTATISTICS)) { - error = ENOTCONN; goto done; - } - } - - value = mtod(*mp, caddr_t); /* it's aligned, don't worry, - * but lint complains about it - */ - val_len = (*mp)->m_len; - - switch (optname) { - - case TPOPT_INTERCEPT: -#define INA(t) (((struct inpcb *)(t->tp_npcb))->inp_laddr.s_addr) -#define ISOA(t) (((struct isopcb *)(t->tp_npcb))->isop_laddr->siso_addr) - - if ((so->so_state & SS_PRIV) == 0) { - error = EPERM; - } else if (cmd != PRCO_SETOPT || tpcb->tp_state != TP_CLOSED || - (tpcb->tp_flags & TPF_GENERAL_ADDR) || - tpcb->tp_next == 0) - error = EINVAL; - else { - register struct tp_pcb *t; - error = EADDRINUSE; - for (t = tp_listeners; t; t = t->tp_nextlisten) - if ((t->tp_flags & TPF_GENERAL_ADDR) == 0 && - t->tp_domain == tpcb->tp_domain) - switch (tpcb->tp_domain) { - default: - goto done; -#if INET - case AF_INET: - if (INA(t) == INA(tpcb)) - goto done; - continue; -#endif -#if ISO - case AF_ISO: - if (bcmp(ISOA(t).isoa_genaddr, ISOA(tpcb).isoa_genaddr, - ISOA(t).isoa_len) == 0) - goto done; - continue; -#endif - } - tpcb->tp_lsuffixlen = 0; - tpcb->tp_state = TP_LISTENING; - error = 0; - remque(tpcb); - tpcb->tp_next = tpcb->tp_prev = tpcb; - tpcb->tp_nextlisten = tp_listeners; - tp_listeners = tpcb; - } - break; - - case TPOPT_MY_TSEL: - if ( cmd == PRCO_GETOPT ) { - ASSERT( tpcb->tp_lsuffixlen <= MAX_TSAP_SEL_LEN ); - bcopy((caddr_t)tpcb->tp_lsuffix, value, tpcb->tp_lsuffixlen); - (*mp)->m_len = tpcb->tp_lsuffixlen; - } else /* cmd == PRCO_SETOPT */ { - if( (val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0 )) { - printf("val_len 0x%x (*mp)->m_len 0x%x\n", val_len, (*mp)); - error = EINVAL; - } else { - bcopy(value, (caddr_t)tpcb->tp_lsuffix, val_len); - tpcb->tp_lsuffixlen = val_len; - } - } - break; - - case TPOPT_PEER_TSEL: - if ( cmd == PRCO_GETOPT ) { - ASSERT( tpcb->tp_fsuffixlen <= MAX_TSAP_SEL_LEN ); - bcopy((caddr_t)tpcb->tp_fsuffix, value, tpcb->tp_fsuffixlen); - (*mp)->m_len = tpcb->tp_fsuffixlen; - } else /* cmd == PRCO_SETOPT */ { - if( (val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0 )) { - printf("val_len 0x%x (*mp)->m_len 0x%x\n", val_len, (*mp)); - error = EINVAL; - } else { - bcopy(value, (caddr_t)tpcb->tp_fsuffix, val_len); - tpcb->tp_fsuffixlen = val_len; - } - } - break; - - case TPOPT_FLAGS: - IFDEBUG(D_REQUEST) - printf("%s TPOPT_FLAGS value 0x%x *value 0x%x, flags 0x%x \n", - cmd==PRCO_GETOPT?"GET":"SET", - value, - *value, - tpcb->tp_flags); - ENDDEBUG - - if ( cmd == PRCO_GETOPT ) { - *(int *)value = (int)tpcb->tp_flags; - (*mp)->m_len = sizeof(u_int); - } else /* cmd == PRCO_SETOPT */ { - error = EINVAL; goto done; - } - break; - - case TPOPT_PARAMS: - /* This handles: - * timer values, - * class, use of transport expedited data, - * max tpdu size, checksum, xtd format and - * disconnect indications, and may get rid of connect/disc data - */ - IFDEBUG(D_SETPARAMS) - printf("TPOPT_PARAMS value 0x%x, cmd %s \n", value, - cmd==PRCO_GETOPT?"GET":"SET"); - ENDDEBUG - IFDEBUG(D_REQUEST) - printf("TPOPT_PARAMS value 0x%x, cmd %s \n", value, - cmd==PRCO_GETOPT?"GET":"SET"); - ENDDEBUG - - if ( cmd == PRCO_GETOPT ) { - *(struct tp_conn_param *)value = tpcb->_tp_param; - (*mp)->m_len = sizeof(tpcb->_tp_param); - } else /* cmd == PRCO_SETOPT */ { - if( (error = - tp_consistency(tpcb, TP_STRICT | TP_FORCE, - (struct tp_conn_param *)value))==0) { - /* - * tp_consistency doesn't copy the whole set of params - */ - tpcb->_tp_param = *(struct tp_conn_param *)value; - (*mp)->m_len = sizeof(tpcb->_tp_param); - } - } - break; - - case TPOPT_PSTATISTICS: -#ifdef TP_PERF_MEAS - if (cmd == PRCO_SETOPT) { - error = EINVAL; goto done; - } - IFPERF(tpcb) - if (*mp) { - struct mbuf * n; - do { - MFREE(*mp, n); - *mp = n; - } while (n); - } - *mp = m_copym(tpcb->tp_p_mbuf, (int)M_COPYALL, M_WAITOK); - ENDPERF - else { - error = EINVAL; goto done; - } - break; -#else - error = EOPNOTSUPP; - goto done; -#endif /* TP_PERF_MEAS */ - - case TPOPT_CDDATA_CLEAR: - if (cmd == PRCO_GETOPT) { - error = EINVAL; - } else { - if (tpcb->tp_ucddata) { - m_freem(tpcb->tp_ucddata); - tpcb->tp_ucddata = 0; - } - } - break; - - case TPOPT_CFRM_DATA: - case TPOPT_DISC_DATA: - case TPOPT_CONN_DATA: - if( tpcb->tp_class == TP_CLASS_0 ) { - error = EOPNOTSUPP; - break; - } - IFDEBUG(D_REQUEST) - printf("%s\n", optname==TPOPT_DISC_DATA?"DISC data":"CONN data"); - printf("m_len 0x%x, vallen 0x%x so_snd.cc 0x%x\n", - (*mp)->m_len, val_len, so->so_snd.sb_cc); - dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput: sosnd "); - ENDDEBUG - if (cmd == PRCO_SETOPT) { - int len = tpcb->tp_ucddata ? tpcb->tp_ucddata->m_len : 0; - /* can append connect data in several calls */ - if (len + val_len > - (optname==TPOPT_CONN_DATA?TP_MAX_CR_DATA:TP_MAX_DR_DATA) ) { - error = EMSGSIZE; goto done; - } - (*mp)->m_next = MNULL; - (*mp)->m_act = 0; - if (tpcb->tp_ucddata) - m_cat(tpcb->tp_ucddata, *mp); - else - tpcb->tp_ucddata = *mp; - IFDEBUG(D_REQUEST) - dump_mbuf(tpcb->tp_ucddata, "tp_ctloutput after CONN_DATA"); - ENDDEBUG - IFTRACE(D_REQUEST) - tptrace(TPPTmisc,"C/D DATA: flags snd.sbcc val_len", - tpcb->tp_flags, so->so_snd.sb_cc,val_len,0); - ENDTRACE - *mp = MNULL; - if (optname == TPOPT_CFRM_DATA && (so->so_state & SS_ISCONFIRMING)) - (void) tp_confirm(tpcb); - } - break; - - case TPOPT_PERF_MEAS: -#ifdef TP_PERF_MEAS - if (cmd == PRCO_GETOPT) { - *value = (u_int)tpcb->tp_perf_on; - (*mp)->m_len = sizeof(u_int); - } else if (cmd == PRCO_SETOPT) { - (*mp)->m_len = 0; - if ((*value) != 0 && (*value) != 1 ) - error = EINVAL; - else tpcb->tp_perf_on = (*value); - } - if( tpcb->tp_perf_on ) - error = tp_setup_perf(tpcb); -#else /* TP_PERF_MEAS */ - error = EOPNOTSUPP; -#endif /* TP_PERF_MEAS */ - break; - - default: - error = EOPNOTSUPP; - } - -done: - IFDEBUG(D_REQUEST) - dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput sosnd at end"); - dump_mbuf(*mp, "tp_ctloutput *mp"); - ENDDEBUG - /* - * sigh: getsockopt looks only at m_len : all output data must - * reside in the first mbuf - */ - if (*mp) { - if (cmd == PRCO_SETOPT) { - m_freem(*mp); - *mp = MNULL; - } else { - ASSERT ( m_compress(*mp, mp) <= MLEN ); - if (error) - (*mp)->m_len = 0; - IFDEBUG(D_REQUEST) - dump_mbuf(*mp, "tp_ctloutput *mp after compress"); - ENDDEBUG - } - } - splx(s); - return error; -} diff --git a/bsd/netiso/tp_param.h b/bsd/netiso/tp_param.h deleted file mode 100644 index 59dffc1ca..000000000 --- a/bsd/netiso/tp_param.h +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)tp_param.h 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * ARGO TP - * - */ - -#ifndef __TP_PARAM__ -#define __TP_PARAM__ - - -/****************************************************** - * compile time parameters that can be changed - *****************************************************/ - -#define TP_CLASSES_IMPLEMENTED 0x11 /* zero and 4 */ - -#define TP_DECBIT_CLEAR_COUNT 3 - -/*#define N_TPREF 100 */ -#ifdef KERNEL -extern int N_TPREF; -#endif - -#define TP_SOCKBUFSIZE ((u_long)4096) -#define TP0_SOCKBUFSIZE ((u_long)512) -#define MAX_TSAP_SEL_LEN 64 - -/* maximum tpdu size we'll accept: */ -#define TP_TPDUSIZE 0xc /* 4096 octets for classes 1-4*/ -#define TP0_TPDUSIZE 0xb /* 2048 octets for class 0 */ -#define TP_DFL_TPDUSIZE 0x7 /* 128 octets default */ - /* NOTE: don't ever negotiate 8192 because could get - * wraparound in checksumming - * (No mtu is likely to be larger than 4K anyway...) - */ -#define TP_NRETRANS 12 /* TCP_MAXRXTSHIFT + 1 */ -#define TP_MAXRXTSHIFT 6 /* factor of 64 */ -#define TP_MAXPORT 0xefff - -/* ALPHA: to be used in the context: gain= 1/(2**alpha), or - * put another way, gaintimes(x) (x)>>alpha (forgetting the case alpha==0) - */ -#define TP_RTT_ALPHA 3 -#define TP_RTV_ALPHA 2 -#define TP_REXMTVAL(tpcb)\ - ((tp_rttadd + (tpcb)->tp_rtt + ((tpcb)->tp_rtv) << 2) / tp_rttdiv) -#define TP_RANGESET(tv, value, min, max) \ - ((tv = value) > (max) ? (tv = max) : (tv < min ? tv = min : tv)) - -/* - * not sure how to treat data on disconnect - */ -#define T_CONN_DATA 0x1 -#define T_DISCONNECT 0x2 -#define T_DISC_DATA 0x4 -#define T_XDATA 0x8 - -#define ISO_CLNS 0 -#define IN_CLNS 1 -#define ISO_CONS 2 -#define ISO_COSNS 3 -#define TP_MAX_NETSERVICES 3 - -/* Indices into tp stats ackreason[i] */ -#define _ACK_DONT_ 0 -#define _ACK_STRAT_EACH_ 0x1 -#define _ACK_STRAT_FULLWIN_ 0x2 -#define _ACK_DUP_ 0x3 -#define _ACK_EOT_ 0x4 -#define _ACK_REORDER_ 0x5 -#define _ACK_USRRCV_ 0x6 -#define _ACK_FCC_ 0x7 -#define _ACK_NUM_REASONS_ 0x8 - -/* masks for use in tp_stash() */ -#define ACK_DONT 0 -#define ACK_STRAT_EACH (1<< _ACK_STRAT_EACH_) -#define ACK_STRAT_FULLWIN (1<< _ACK_STRAT_FULLWIN_) -#define ACK_DUP (1<< _ACK_DUP_) -#define ACK_EOT (1<< _ACK_EOT_) -#define ACK_REORDER (1<< _ACK_REORDER_) - -/****************************************************** - * constants used in the protocol - *****************************************************/ - -#define TP_VERSION 0x1 - -#define TP_MAX_HEADER_LEN 256 - -#define TP_MIN_TPDUSIZE 0x7 /* 128 octets */ -#define TP_MAX_TPDUSIZE 0xd /* 8192 octets */ - -#define TP_MAX_XPD_DATA 0x10 /* 16 octets */ -#define TP_MAX_CC_DATA 0x20 /* 32 octets */ -#define TP_MAX_CR_DATA TP_MAX_CC_DATA -#define TP_MAX_DR_DATA 0x40 /* 64 octets */ - -#define TP_XTD_FMT_BIT 0x80000000 -#define TP_XTD_FMT_MASK 0x7fffffff -#define TP_NML_FMT_BIT 0x80 -#define TP_NML_FMT_MASK 0x7f - -/* - * values for the tpdu_type field, 2nd byte in a tpdu - */ - -#define TP_MIN_TPDUTYPE 0x1 - -#define XPD_TPDU_type 0x1 -#define XAK_TPDU_type 0x2 -#define GR_TPDU_type 0x3 -#define AK_TPDU_type 0x6 -#define ER_TPDU_type 0x7 -#define DR_TPDU_type 0x8 -#define DC_TPDU_type 0xc -#define CC_TPDU_type 0xd -#define CR_TPDU_type 0xe -#define DT_TPDU_type 0xf - -#define TP_MAX_TPDUTYPE 0xf - -/* - * identifiers for the variable-length options in tpdus - */ - -#define TPP_acktime 0x85 -#define TPP_residER 0x86 -#define TPP_priority 0x87 -#define TPP_transdelay 0x88 -#define TPP_throughput 0x89 -#define TPP_subseq 0x8a -#define TPP_flow_cntl_conf 0x8c /* not implemented */ -#define TPP_addl_info 0xe0 -#define TPP_tpdu_size 0xc0 -#define TPP_calling_sufx 0xc1 -#define TPP_invalid_tpdu 0xc1 /* the bozos used a value twice */ -#define TPP_called_sufx 0xc2 -#define TPP_checksum 0xc3 -#define TPP_vers 0xc4 -#define TPP_security 0xc5 -#define TPP_addl_opt 0xc6 -#define TPP_alt_class 0xc7 -#define TPP_perf_meas 0xc8 /* local item : perf meas on, svp */ -#define TPP_ptpdu_size 0xf0 /* preferred TPDU size */ -#define TPP_inact_time 0xf2 /* inactivity time exchanged */ - - -/****************************************************** - * Some fundamental data types - *****************************************************/ -#ifndef TRUE -#define TRUE 1 -#endif /* TRUE */ - -#ifndef FALSE -#define FALSE 0 -#endif /* FALSE */ - -#define TP_LOCAL 22 -#define TP_FOREIGN 33 - -#ifndef EOK -#define EOK 0 -#endif /* EOK */ - -#define TP_CLASS_0 (1<<0) -#define TP_CLASS_1 (1<<1) -#define TP_CLASS_2 (1<<2) -#define TP_CLASS_3 (1<<3) -#define TP_CLASS_4 (1<<4) - -#define TP_FORCE 0x1 -#define TP_STRICT 0x2 - -#ifndef MNULL -#define MNULL (struct mbuf *)0 -#endif /* MNULL */ - /* if ../sys/mbuf.h gets MT_types up to 0x40, these will - * have to be changed: - */ -#define MT_XPD 0x44 -#define MT_EOT 0x40 - -#define TP_ENOREF 0x80000000 - -typedef unsigned int SeqNum; -typedef unsigned short RefNum; -typedef int ProtoHook; - -/****************************************************** - * Macro used all over, for driver - *****************************************************/ - -#define DoEvent(x) \ - ((E.ev_number=(x)),(tp_driver(tpcb,&E))) - -/****************************************************** - * Some macros used all over, for timestamping - *****************************************************/ - -#define GET_CUR_TIME(tvalp) ((*tvalp) = time) - -#define GET_TIME_SINCE(oldtvalp, diffp) {\ - (diffp)->tv_sec = time.tv_sec - (oldtvalp)->tv_sec;\ - (diffp)->tv_usec = time.tv_usec - (oldtvalp)->tv_usec;\ - if( (diffp)->tv_usec <0 ) {\ - (diffp)->tv_sec --;\ - (diffp)->tv_usec = 1000000 - (diffp)->tv_usec;\ - }\ -} - -/****************************************************** - * Some macros used for address families - *****************************************************/ - -#define satosiso(ADDR) ((struct sockaddr_iso *)(ADDR)) -#define satosin(ADDR) ((struct sockaddr_in *)(ADDR)) - -/****************************************************** - * Macro used for changing types of mbufs - *****************************************************/ - -#define CHANGE_MTYPE(m, TYPE)\ - if((m)->m_type != TYPE) { \ - mbstat.m_mtypes[(m)->m_type]--; mbstat.m_mtypes[TYPE]++; \ - (m)->m_type = TYPE; \ - } - -/****************************************************** - * Macros used for adding options to a tpdu header and for - * parsing the headers. - * Options are variable-length and must be bcopy-d because on the - * RT your assignments must be N-word aligned for objects of length - * N. Such a drag. - *****************************************************/ - -struct tp_vbp { - u_char tpv_code; - char tpv_len; - char tpv_val; -}; -#define vbptr(x) ((struct tp_vbp *)(x)) -#define vbval(x,type) (*((type *)&(((struct tp_vbp *)(x))->tpv_val))) -#define vbcode(x) (vbptr(x)->tpv_code) -#define vblen(x) (vbptr(x)->tpv_len) - -#define vb_putval(dst,type,src)\ - bcopy((caddr_t)&(src),(caddr_t)&(((struct tp_vbp *)(dst))->tpv_val),\ - sizeof(type)) - -#define vb_getval(src,type,dst)\ -bcopy((caddr_t)&(((struct tp_vbp *)(src))->tpv_val),(caddr_t)&(dst),sizeof(type)) - -#define ADDOPTION(type, DU, len, src)\ -{ register caddr_t P;\ - P = (caddr_t)(DU) + (int)((DU)->tpdu_li);\ - vbptr(P)->tpv_code = type;\ - vbptr(P)->tpv_len = len;\ - bcopy((caddr_t)&src, (caddr_t)&(vbptr(P)->tpv_val), (unsigned)len);\ - DU->tpdu_li += len+2;/* 1 for code, 1 for length */\ -} -/****************************************************** - * Macro for the local credit: - * uses max transmission unit for the ll - * (as modified by the max TPDU size negotiated) - *****************************************************/ - -#if defined(ARGO_DEBUG)&&!defined(LOCAL_CREDIT_EXPAND) -#define LOCAL_CREDIT(tpcb) tp_local_credit(tpcb) -#else -#define LOCAL_CREDIT(tpcb) { if (tpcb->tp_rsycnt == 0) {\ - register struct sockbuf *xxsb = &((tpcb)->tp_sock->so_rcv);\ - register int xxi = sbspace(xxsb);\ - xxi = (xxi<0) ? 0 : ((xxi) / (tpcb)->tp_l_tpdusize);\ - xxi = min(xxi, (tpcb)->tp_maxlcredit); \ - if (!(tpcb->tp_cebit_off)) { \ - (tpcb)->tp_lcredit = ROUND((tpcb)->tp_win_recv); \ - if (xxi < (tpcb)->tp_lcredit) { \ - (tpcb)->tp_lcredit = xxi; \ - } \ - } else \ - (tpcb)->tp_lcredit = xxi; \ -} } -#endif /* ARGO_DEBUG */ - -#ifdef KERNEL -extern int tp_rttadd, tp_rttdiv; -#include -#define printf logpri(LOG_DEBUG),addlog - -#ifndef tp_NSTATES - -#include -#include -#if defined(__STDC__) || defined(__cplusplus) -#undef ATTR -#define ATTR(X) ev_union.EV_ ## X -#endif /* defined(__STDC__) || defined(__cplusplus) */ - -#endif /* tp_NSTATES */ -#endif /* KERNEL */ - -#endif /* __TP_PARAM__ */ diff --git a/bsd/netiso/tp_pcb.c b/bsd/netiso/tp_pcb.c deleted file mode 100644 index a4b91724f..000000000 --- a/bsd/netiso/tp_pcb.c +++ /dev/null @@ -1,1018 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)tp_pcb.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * ARGO TP - * - * - * This is the initialization and cleanup stuff - - * for the tp machine in general as well as for the individual pcbs. - * tp_init() is called at system startup. tp_attach() and tp_getref() are - * called when a socket is created. tp_detach() and tp_freeref() - * are called during the closing stage and/or when the reference timer - * goes off. - * tp_soisdisconnecting() and tp_soisdisconnected() are tp-specific - * versions of soisconnect* - * and are called (obviously) during the closing phase. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* ticks are in units of: - * 500 nano-fortnights ;-) or - * 500 ms or - * 1/2 second - */ - -struct tp_conn_param tp_conn_param[] = { - /* ISO_CLNS: TP4 CONNECTION LESS */ - { - TP_NRETRANS, /* short p_Nretrans; */ - 20, /* 10 sec */ /* short p_dr_ticks; */ - - 20, /* 10 sec */ /* short p_cc_ticks; */ - 20, /* 10 sec */ /* short p_dt_ticks; */ - - 40, /* 20 sec */ /* short p_x_ticks; */ - 80, /* 40 sec */ /* short p_cr_ticks;*/ - - 240, /* 2 min */ /* short p_keepalive_ticks;*/ - 10, /* 5 sec */ /* short p_sendack_ticks; */ - - 600, /* 5 min */ /* short p_ref_ticks; */ - 360, /* 3 min */ /* short p_inact_ticks; */ - - (short) 100, /* short p_lcdtfract */ - (short) TP_SOCKBUFSIZE, /* short p_winsize */ - TP_TPDUSIZE, /* u_char p_tpdusize */ - - TPACK_WINDOW, /* 4 bits p_ack_strat */ - TPRX_USE_CW | TPRX_FASTSTART, - /* 4 bits p_rx_strat*/ - TP_CLASS_4 | TP_CLASS_0,/* 5 bits p_class */ - 1, /* 1 bit xtd format */ - 1, /* 1 bit xpd service */ - 1, /* 1 bit use_checksum */ - 0, /* 1 bit use net xpd */ - 0, /* 1 bit use rcc */ - 0, /* 1 bit use efc */ - 1, /* no disc indications */ - 0, /* don't change params */ - ISO_CLNS, /* p_netservice */ - }, - /* IN_CLNS: TP4 CONNECTION LESS */ - { - TP_NRETRANS, /* short p_Nretrans; */ - 20, /* 10 sec */ /* short p_dr_ticks; */ - - 20, /* 10 sec */ /* short p_cc_ticks; */ - 20, /* 10 sec */ /* short p_dt_ticks; */ - - 40, /* 20 sec */ /* short p_x_ticks; */ - 80, /* 40 sec */ /* short p_cr_ticks;*/ - - 240, /* 2 min */ /* short p_keepalive_ticks;*/ - 10, /* 5 sec */ /* short p_sendack_ticks; */ - - 600, /* 5 min */ /* short p_ref_ticks; */ - 360, /* 3 min */ /* short p_inact_ticks; */ - - (short) 100, /* short p_lcdtfract */ - (short) TP_SOCKBUFSIZE, /* short p_winsize */ - TP_TPDUSIZE, /* u_char p_tpdusize */ - - TPACK_WINDOW, /* 4 bits p_ack_strat */ - TPRX_USE_CW | TPRX_FASTSTART, - /* 4 bits p_rx_strat*/ - TP_CLASS_4, /* 5 bits p_class */ - 1, /* 1 bit xtd format */ - 1, /* 1 bit xpd service */ - 1, /* 1 bit use_checksum */ - 0, /* 1 bit use net xpd */ - 0, /* 1 bit use rcc */ - 0, /* 1 bit use efc */ - 1, /* no disc indications */ - 0, /* don't change params */ - IN_CLNS, /* p_netservice */ - }, - /* ISO_CONS: TP0 CONNECTION MODE */ - { - TP_NRETRANS, /* short p_Nretrans; */ - 0, /* n/a */ /* short p_dr_ticks; */ - - 40, /* 20 sec */ /* short p_cc_ticks; */ - 0, /* n/a */ /* short p_dt_ticks; */ - - 0, /* n/a */ /* short p_x_ticks; */ - 360, /* 3 min */ /* short p_cr_ticks;*/ - - 0, /* n/a */ /* short p_keepalive_ticks;*/ - 0, /* n/a */ /* short p_sendack_ticks; */ - - 600, /* for cr/cc to clear *//* short p_ref_ticks; */ - 0, /* n/a */ /* short p_inact_ticks; */ - - /* Use tp4 defaults just in case the user changes ONLY - * the class - */ - (short) 100, /* short p_lcdtfract */ - (short) TP0_SOCKBUFSIZE, /* short p_winsize */ - TP0_TPDUSIZE, /* 8 bits p_tpdusize */ - - 0, /* 4 bits p_ack_strat */ - 0, /* 4 bits p_rx_strat*/ - TP_CLASS_0, /* 5 bits p_class */ - 0, /* 1 bit xtd format */ - 0, /* 1 bit xpd service */ - 0, /* 1 bit use_checksum */ - 0, /* 1 bit use net xpd */ - 0, /* 1 bit use rcc */ - 0, /* 1 bit use efc */ - 0, /* no disc indications */ - 0, /* don't change params */ - ISO_CONS, /* p_netservice */ - }, - /* ISO_COSNS: TP4 CONNECTION LESS SERVICE over CONSNS */ - { - TP_NRETRANS, /* short p_Nretrans; */ - 40, /* 20 sec */ /* short p_dr_ticks; */ - - 40, /* 20 sec */ /* short p_cc_ticks; */ - 80, /* 40 sec */ /* short p_dt_ticks; */ - - 120, /* 1 min */ /* short p_x_ticks; */ - 360, /* 3 min */ /* short p_cr_ticks;*/ - - 360, /* 3 min */ /* short p_keepalive_ticks;*/ - 20, /* 10 sec */ /* short p_sendack_ticks; */ - - 600, /* 5 min */ /* short p_ref_ticks; */ - 480, /* 4 min */ /* short p_inact_ticks; */ - - (short) 100, /* short p_lcdtfract */ - (short) TP0_SOCKBUFSIZE, /* short p_winsize */ - TP0_TPDUSIZE, /* u_char p_tpdusize */ - - TPACK_WINDOW, /* 4 bits p_ack_strat */ - TPRX_USE_CW , /* No fast start */ - /* 4 bits p_rx_strat*/ - TP_CLASS_4 | TP_CLASS_0,/* 5 bits p_class */ - 0, /* 1 bit xtd format */ - 1, /* 1 bit xpd service */ - 1, /* 1 bit use_checksum */ - 0, /* 1 bit use net xpd */ - 0, /* 1 bit use rcc */ - 0, /* 1 bit use efc */ - 0, /* no disc indications */ - 0, /* don't change params */ - ISO_COSNS, /* p_netservice */ - }, -}; - -#if INET -int in_putnetaddr(); -int in_getnetaddr(); -int in_cmpnetaddr(); -int in_putsufx(); -int in_getsufx(); -int in_recycle_tsuffix(); -int tpip_mtu(); -int in_pcbbind(); -int in_pcbconnect(); -int in_pcbdisconnect(); -int in_pcbdetach(); -int in_pcballoc(); -int tpip_output(); -int tpip_output_dg(); -struct inpcb tp_inpcb; -#endif /* INET */ -#if ISO -int iso_putnetaddr(); -int iso_getnetaddr(); -int iso_cmpnetaddr(); -int iso_putsufx(); -int iso_getsufx(); -int iso_recycle_tsuffix(); -int tpclnp_mtu(); -int iso_pcbbind(); -int iso_pcbconnect(); -int iso_pcbdisconnect(); -int iso_pcbdetach(); -int iso_pcballoc(); -int tpclnp_output(); -int tpclnp_output_dg(); -int iso_nlctloutput(); -struct isopcb tp_isopcb; -#endif /* ISO */ -#if TPCONS -int iso_putnetaddr(); -int iso_getnetaddr(); -int iso_cmpnetaddr(); -int iso_putsufx(); -int iso_getsufx(); -int iso_recycle_tsuffix(); -int iso_pcbbind(); -int tpcons_pcbconnect(); -int tpclnp_mtu(); -int iso_pcbdisconnect(); -int iso_pcbdetach(); -int iso_pcballoc(); -int tpcons_output(); -struct isopcb tp_isopcb; -#endif /* TPCONS */ - - -struct nl_protosw nl_protosw[] = { - /* ISO_CLNS */ -#if ISO - { AF_ISO, iso_putnetaddr, iso_getnetaddr, iso_cmpnetaddr, - iso_putsufx, iso_getsufx, - iso_recycle_tsuffix, - tpclnp_mtu, iso_pcbbind, iso_pcbconnect, - iso_pcbdisconnect, iso_pcbdetach, - iso_pcballoc, - tpclnp_output, tpclnp_output_dg, iso_nlctloutput, - (caddr_t) &tp_isopcb, - }, -#else - { 0 }, -#endif /* ISO */ - /* IN_CLNS */ -#if INET - { AF_INET, in_putnetaddr, in_getnetaddr, in_cmpnetaddr, - in_putsufx, in_getsufx, - in_recycle_tsuffix, - tpip_mtu, in_pcbbind, in_pcbconnect, - in_pcbdisconnect, in_pcbdetach, - in_pcballoc, - tpip_output, tpip_output_dg, /* nl_ctloutput */ NULL, - (caddr_t) &tp_inpcb, - }, -#else - { 0 }, -#endif /* INET */ - /* ISO_CONS */ -#if defined(ISO) && defined(TPCONS) - { AF_ISO, iso_putnetaddr, iso_getnetaddr, iso_cmpnetaddr, - iso_putsufx, iso_getsufx, - iso_recycle_tsuffix, - tpclnp_mtu, iso_pcbbind, tpcons_pcbconnect, - iso_pcbdisconnect, iso_pcbdetach, - iso_pcballoc, - tpcons_output, tpcons_output, iso_nlctloutput, - (caddr_t) &tp_isopcb, - }, -#else - { 0 }, -#endif /* ISO_CONS */ - /* End of protosw marker */ - { 0 } -}; - -u_long tp_sendspace = 1024 * 4; -u_long tp_recvspace = 1024 * 4; - -/* - * NAME: tp_init() - * - * CALLED FROM: - * autoconf through the protosw structure - * - * FUNCTION: - * initialize tp machine - * - * RETURNS: Nada - * - * SIDE EFFECTS: - * - * NOTES: - */ -int -tp_init() -{ - static int init_done=0; - void tp_timerinit(); - - if (init_done++) - return 0; - - - /* FOR INET */ - tp_inpcb.inp_next = tp_inpcb.inp_prev = &tp_inpcb; - /* FOR ISO */ - tp_isopcb.isop_next = tp_isopcb.isop_prev = &tp_isopcb; - - tp_start_win = 2; - - tp_timerinit(); - bzero((caddr_t)&tp_stat, sizeof(struct tp_stat)); - return 0; -} - -/* - * NAME: tp_soisdisconnecting() - * - * CALLED FROM: - * tp.trans - * - * FUNCTION and ARGUMENTS: - * Set state of the socket (so) to reflect that fact that we're disconnectING - * - * RETURNS: Nada - * - * SIDE EFFECTS: - * - * NOTES: - * This differs from the regular soisdisconnecting() in that the latter - * also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags. - * We don't want to set those flags because those flags will cause - * a SIGPIPE to be delivered in sosend() and we don't like that. - * If anyone else is sleeping on this socket, wake 'em up. - */ -void -tp_soisdisconnecting(so) - register struct socket *so; -{ - soisdisconnecting(so); - so->so_state &= ~SS_CANTSENDMORE; - IFPERF(sototpcb(so)) - register struct tp_pcb *tpcb = sototpcb(so); - u_int fsufx, lsufx; - - bcopy ((caddr_t)tpcb->tp_fsuffix, (caddr_t)&fsufx, sizeof(u_int) ); - bcopy ((caddr_t)tpcb->tp_lsuffix, (caddr_t)&lsufx, sizeof(u_int) ); - - tpmeas(tpcb->tp_lref, TPtime_close, &time, fsufx, lsufx, tpcb->tp_fref); - tpcb->tp_perf_on = 0; /* turn perf off */ - ENDPERF -} - - -/* - * NAME: tp_soisdisconnected() - * - * CALLED FROM: - * tp.trans - * - * FUNCTION and ARGUMENTS: - * Set state of the socket (so) to reflect that fact that we're disconnectED - * Set the state of the reference structure to closed, and - * recycle the suffix. - * Start a reference timer. - * - * RETURNS: Nada - * - * SIDE EFFECTS: - * - * NOTES: - * This differs from the regular soisdisconnected() in that the latter - * also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags. - * We don't want to set those flags because those flags will cause - * a SIGPIPE to be delivered in sosend() and we don't like that. - * If anyone else is sleeping on this socket, wake 'em up. - */ -void -tp_soisdisconnected(tpcb) - register struct tp_pcb *tpcb; -{ - register struct socket *so = tpcb->tp_sock; - - soisdisconnecting(so); - so->so_state &= ~SS_CANTSENDMORE; - IFPERF(tpcb) - register struct tp_pcb *ttpcb = sototpcb(so); - u_int fsufx, lsufx; - - /* CHOKE */ - bcopy ((caddr_t)ttpcb->tp_fsuffix, (caddr_t)&fsufx, sizeof(u_int) ); - bcopy ((caddr_t)ttpcb->tp_lsuffix, (caddr_t)&lsufx, sizeof(u_int) ); - - tpmeas(ttpcb->tp_lref, TPtime_close, - &time, &lsufx, &fsufx, ttpcb->tp_fref); - tpcb->tp_perf_on = 0; /* turn perf off */ - ENDPERF - - tpcb->tp_refstate = REF_FROZEN; - tp_recycle_tsuffix(tpcb); - tp_etimeout(tpcb, TM_reference, (int)tpcb->tp_refer_ticks); -} - -/* - * NAME: tp_freeref() - * - * CALLED FROM: - * tp.trans when the reference timer goes off, and - * from tp_attach() and tp_detach() when a tpcb is partially set up but not - * set up enough to have a ref timer set for it, and it's discarded - * due to some sort of error or an early close() - * - * FUNCTION and ARGUMENTS: - * Frees the reference represented by (r) for re-use. - * - * RETURNS: Nothing - * - * SIDE EFFECTS: - * - * NOTES: better be called at clock priority !!!!! - */ -void -tp_freeref(n) -RefNum n; -{ - register struct tp_ref *r = tp_ref + n; - register struct tp_pcb *tpcb; - - tpcb = r->tpr_pcb; - IFDEBUG(D_TIMER) - printf("tp_freeref called for ref %d pcb %x maxrefopen %d\n", - n, tpcb, tp_refinfo.tpr_maxopen); - ENDDEBUG - IFTRACE(D_TIMER) - tptrace(TPPTmisc, "tp_freeref ref maxrefopen pcb", - n, tp_refinfo.tpr_maxopen, tpcb, 0); - ENDTRACE - if (tpcb == 0) - return; - IFDEBUG(D_CONN) - printf("tp_freeref: CLEARING tpr_pcb 0x%x\n", tpcb); - ENDDEBUG - r->tpr_pcb = (struct tp_pcb *)0; - tpcb->tp_refstate = REF_FREE; - - for (r = tp_ref + tp_refinfo.tpr_maxopen; r > tp_ref; r--) - if (r->tpr_pcb) - break; - tp_refinfo.tpr_maxopen = r - tp_ref; - tp_refinfo.tpr_numopen--; - - IFDEBUG(D_TIMER) - printf("tp_freeref ends w/ maxrefopen %d\n", tp_refinfo.tpr_maxopen); - ENDDEBUG -} - -/* - * NAME: tp_getref() - * - * CALLED FROM: - * tp_attach() - * - * FUNCTION and ARGUMENTS: - * obtains the next free reference and allocates the appropriate - * ref structure, links that structure to (tpcb) - * - * RETURN VALUE: - * a reference number - * or TP_ENOREF - * - * SIDE EFFECTS: - * - * NOTES: - */ -u_long -tp_getref(tpcb) - register struct tp_pcb *tpcb; -{ - register struct tp_ref *r, *rlim; - register int i; - caddr_t obase; - unsigned size; - - if (++tp_refinfo.tpr_numopen < tp_refinfo.tpr_size) - for (r = tp_refinfo.tpr_base, rlim = r + tp_refinfo.tpr_size; - ++r < rlim; ) /* tp_ref[0] is never used */ - if (r->tpr_pcb == 0) - goto got_one; - /* else have to allocate more space */ - - obase = (caddr_t)tp_refinfo.tpr_base; - size = tp_refinfo.tpr_size * sizeof(struct tp_ref); -// r = (struct tp_ref *) malloc(size + size, M_PCB, M_NOWAIT); - MALLOC(r, struct tp_ref *, size + size, M_PCB, M_NOWAIT); - if (r == 0) - return (--tp_refinfo.tpr_numopen, TP_ENOREF); - tp_refinfo.tpr_base = tp_ref = r; - tp_refinfo.tpr_size *= 2; - bcopy(obase, (caddr_t)r, size); - FREE(obase, M_PCB); - r = (struct tp_ref *)(size + (caddr_t)r); - bzero((caddr_t)r, size); - -got_one: - r->tpr_pcb = tpcb; - tpcb->tp_refstate = REF_OPENING; - i = r - tp_refinfo.tpr_base; - if (tp_refinfo.tpr_maxopen < i) - tp_refinfo.tpr_maxopen = i; - return (u_long)i; -} - -/* - * NAME: tp_set_npcb() - * - * CALLED FROM: - * tp_attach(), tp_route_to() - * - * FUNCTION and ARGUMENTS: - * given a tpcb, allocate an appropriate lower-lever npcb, freeing - * any old ones that might need re-assigning. - */ -tp_set_npcb(tpcb) -register struct tp_pcb *tpcb; -{ - register struct socket *so = tpcb->tp_sock; - int error; - - if (tpcb->tp_nlproto && tpcb->tp_npcb) { - short so_state = so->so_state; - so->so_state &= ~SS_NOFDREF; - tpcb->tp_nlproto->nlp_pcbdetach(tpcb->tp_npcb); - so->so_state = so_state; - } - tpcb->tp_nlproto = &nl_protosw[tpcb->tp_netservice]; - /* xx_pcballoc sets so_pcb */ - error = tpcb->tp_nlproto->nlp_pcballoc(so, tpcb->tp_nlproto->nlp_pcblist); - tpcb->tp_npcb = so->so_pcb; - so->so_pcb = (caddr_t)tpcb; - return (error); -} -/* - * NAME: tp_attach() - * - * CALLED FROM: - * tp_usrreq, PRU_ATTACH - * - * FUNCTION and ARGUMENTS: - * given a socket (so) and a protocol family (dom), allocate a tpcb - * and ref structure, initialize everything in the structures that - * needs to be initialized. - * - * RETURN VALUE: - * 0 ok - * EINVAL if DEBUG(X) in is on and a disaster has occurred - * ENOPROTOOPT if TP hasn't been configured or if the - * socket wasn't created with tp as its protocol - * EISCONN if this socket is already part of a connection - * ETOOMANYREFS if ran out of tp reference numbers. - * E* whatever error is returned from soreserve() - * for from the network-layer pcb allocation routine - * - * SIDE EFFECTS: - * - * NOTES: - */ -tp_attach(so, protocol) - struct socket *so; - int protocol; -{ - register struct tp_pcb *tpcb; - int error = 0; - int dom = so->so_proto->pr_domain->dom_family; - u_long lref; - extern struct tp_conn_param tp_conn_param[]; - - IFDEBUG(D_CONN) - printf("tp_attach:dom 0x%x so 0x%x ", dom, so); - ENDDEBUG - IFTRACE(D_CONN) - tptrace(TPPTmisc, "tp_attach:dom so", dom, so, 0, 0); - ENDTRACE - - if (so->so_pcb != NULL) { - return EISCONN; /* socket already part of a connection*/ - } - - if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) - error = soreserve(so, tp_sendspace, tp_recvspace); - /* later an ioctl will allow reallocation IF still in closed state */ - - if (error) - goto bad2; - - MALLOC(tpcb, struct tp_pcb *, sizeof(*tpcb), M_PCB, M_NOWAIT); - if (tpcb == NULL) { - error = ENOBUFS; - goto bad2; - } - bzero( (caddr_t)tpcb, sizeof (struct tp_pcb) ); - - if ( ((lref = tp_getref(tpcb)) & TP_ENOREF) != 0 ) { - error = ETOOMANYREFS; - goto bad3; - } - tpcb->tp_lref = lref; - tpcb->tp_sock = so; - tpcb->tp_domain = dom; - tpcb->tp_rhiwat = so->so_rcv.sb_hiwat; - /* tpcb->tp_proto = protocol; someday maybe? */ - if (protocol && protocoltp_netservice = ISO_CONS; - tpcb->tp_snduna = (SeqNum) -1;/* kludge so the pseudo-ack from the CR/CC - * will generate correct fake-ack values - */ - } else { - tpcb->tp_netservice = (dom== AF_INET)?IN_CLNS:ISO_CLNS; - /* the default */ - } - tpcb->_tp_param = tp_conn_param[tpcb->tp_netservice]; - - tpcb->tp_state = TP_CLOSED; - tpcb->tp_vers = TP_VERSION; - tpcb->tp_notdetached = 1; - - /* Spec says default is 128 octets, - * that is, if the tpdusize argument never appears, use 128. - * As the initiator, we will always "propose" the 2048 - * size, that is, we will put this argument in the CR - * always, but accept what the other side sends on the CC. - * If the initiator sends us something larger on a CR, - * we'll respond w/ this. - * Our maximum is 4096. See tp_chksum.c comments. - */ - tpcb->tp_cong_win = - tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize; - - tpcb->tp_seqmask = TP_NML_FMT_MASK; - tpcb->tp_seqbit = TP_NML_FMT_BIT; - tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1; - - /* attach to a network-layer protoswitch */ - if ( error = tp_set_npcb(tpcb)) - goto bad4; - ASSERT( tpcb->tp_nlproto->nlp_afamily == tpcb->tp_domain); - - /* nothing to do for iso case */ - if( dom == AF_INET ) - sotoinpcb(so)->inp_ppcb = (caddr_t) tpcb; - - return 0; - -bad4: - IFDEBUG(D_CONN) - printf("BAD4 in tp_attach, so 0x%x\n", so); - ENDDEBUG - tp_freeref(tpcb->tp_lref); - -bad3: - IFDEBUG(D_CONN) - printf("BAD3 in tp_attach, so 0x%x\n", so); - ENDDEBUG - - FREE((caddr_t)tpcb, M_PCB); /* never a cluster */ - -bad2: - IFDEBUG(D_CONN) - printf("BAD2 in tp_attach, so 0x%x\n", so); - ENDDEBUG - so->so_pcb = 0; - -/*bad:*/ - IFDEBUG(D_CONN) - printf("BAD in tp_attach, so 0x%x\n", so); - ENDDEBUG - return error; -} - -/* - * NAME: tp_detach() - * - * CALLED FROM: - * tp.trans, on behalf of a user close request - * and when the reference timer goes off - * (if the disconnect was initiated by the protocol entity - * rather than by the user) - * - * FUNCTION and ARGUMENTS: - * remove the tpcb structure from the list of active or - * partially active connections, recycle all the mbufs - * associated with the pcb, ref structure, sockbufs, etc. - * Only free the ref structure if you know that a ref timer - * wasn't set for this tpcb. - * - * RETURNS: Nada - * - * SIDE EFFECTS: - * - * NOTES: - * tp_soisdisconnected() was already when this is called - */ -void -tp_detach(tpcb) - register struct tp_pcb *tpcb; -{ - void tp_freeref(), tp_rsyflush(); - register struct socket *so = tpcb->tp_sock; - - IFDEBUG(D_CONN) - printf("tp_detach(tpcb 0x%x, so 0x%x)\n", - tpcb,so); - ENDDEBUG - IFTRACE(D_CONN) - tptraceTPCB(TPPTmisc, "tp_detach tpcb so lsufx", - tpcb, so, *(u_short *)(tpcb->tp_lsuffix), 0); - ENDTRACE - - IFDEBUG(D_CONN) - printf("so_snd at 0x%x so_rcv at 0x%x\n", &so->so_snd, &so->so_rcv); - dump_mbuf(so->so_snd.sb_mb, "so_snd at detach "); - printf("about to call LL detach, nlproto 0x%x, nl_detach 0x%x\n", - tpcb->tp_nlproto, tpcb->tp_nlproto->nlp_pcbdetach); - ENDDEBUG - - if (tpcb->tp_Xsnd.sb_mb) { - printf("Unsent Xdata on detach; would panic"); - sbflush(&tpcb->tp_Xsnd); - } - if (tpcb->tp_ucddata) - m_freem(tpcb->tp_ucddata); - - IFDEBUG(D_CONN) - printf("reassembly info cnt %d rsyq 0x%x\n", - tpcb->tp_rsycnt, tpcb->tp_rsyq); - ENDDEBUG - if (tpcb->tp_rsyq) - tp_rsyflush(tpcb); - - if (tpcb->tp_next) { - remque(tpcb); - tpcb->tp_next = tpcb->tp_prev = 0; - } - tpcb->tp_notdetached = 0; - - IFDEBUG(D_CONN) - printf("calling (...nlproto->...)(0x%x, so 0x%x)\n", - tpcb->tp_npcb, so); - printf("so 0x%x so_head 0x%x, qlen %d q0len %d qlimit %d\n", - so, so->so_head, - so->so_q0len, so->so_qlen, so->so_qlimit); - ENDDEBUG - - (tpcb->tp_nlproto->nlp_pcbdetach)(tpcb->tp_npcb); - /* does an so->so_pcb = 0; sofree(so) */ - - IFDEBUG(D_CONN) - printf("after xxx_pcbdetach\n"); - ENDDEBUG - - if (tpcb->tp_state == TP_LISTENING) { - register struct tp_pcb **tt; - for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten)) - if (*tt == tpcb) - break; - if (*tt) - *tt = tpcb->tp_nextlisten; - else - printf("tp_detach from listen: should panic\n"); - } - if (tpcb->tp_refstate == REF_OPENING ) { - /* no connection existed here so no reference timer will be called */ - IFDEBUG(D_CONN) - printf("SETTING ref %d to REF_FREE\n", tpcb->tp_lref); - ENDDEBUG - - tp_freeref(tpcb->tp_lref); - } -#ifdef TP_PERF_MEAS - /* - * Get rid of the cluster mbuf allocated for performance measurements, if - * there is one. Note that tpcb->tp_perf_on says nothing about whether or - * not a cluster mbuf was allocated, so you have to check for a pointer - * to one (that is, we need the TP_PERF_MEASs around the following section - * of code, not the IFPERFs) - */ - if (tpcb->tp_p_mbuf) { - register struct mbuf *m = tpcb->tp_p_mbuf; - struct mbuf *n; - IFDEBUG(D_PERF_MEAS) - printf("freeing tp_p_meas 0x%x ", tpcb->tp_p_meas); - ENDDEBUG - do { - MFREE(m, n); - m = n; - } while (n); - tpcb->tp_p_meas = 0; - tpcb->tp_p_mbuf = 0; - } -#endif /* TP_PERF_MEAS */ - - IFDEBUG(D_CONN) - printf( "end of detach, NOT single, tpcb 0x%x\n", tpcb); - ENDDEBUG - /* FREE((caddr_t)tpcb, M_PCB); WHere to put this ? */ -} - -struct que { - struct tp_pcb *next; - struct tp_pcb *prev; -} tp_bound_pcbs = -{(struct tp_pcb *)&tp_bound_pcbs, (struct tp_pcb *)&tp_bound_pcbs}; - -u_short tp_unique; - -tp_tselinuse(tlen, tsel, siso, reuseaddr) -caddr_t tsel; -register struct sockaddr_iso *siso; -{ - struct tp_pcb *b = tp_bound_pcbs.next, *l = tp_listeners; - register struct tp_pcb *t; - - for (;;) { - if (b != (struct tp_pcb *)&tp_bound_pcbs) { - t = b; b = t->tp_next; - } else if (l) { - t = l; l = t->tp_nextlisten; - } else - break; - if (tlen == t->tp_lsuffixlen && bcmp(tsel, t->tp_lsuffix, tlen) == 0) { - if (t->tp_flags & TPF_GENERAL_ADDR) { - if (siso == 0 || reuseaddr == 0) - return 1; - } else if (siso) { - if (siso->siso_family == t->tp_domain && - t->tp_nlproto->nlp_cmpnetaddr(t->tp_npcb, siso, TP_LOCAL)) - return 1; - } else if (reuseaddr == 0) - return 1; - } - } - return 0; - -} - - -tp_pcbbind(tpcb, nam) -register struct tp_pcb *tpcb; -register struct mbuf *nam; -{ - register struct sockaddr_iso *siso = 0; - int tlen = 0, wrapped = 0; - caddr_t tsel; - u_short tutil; - - if (tpcb->tp_state != TP_CLOSED) - return (EINVAL); - if (nam) { - siso = mtod(nam, struct sockaddr_iso *); - switch (siso->siso_family) { - default: - return (EAFNOSUPPORT); -#if ISO - case AF_ISO: - tlen = siso->siso_tlen; - tsel = TSEL(siso); - if (siso->siso_nlen == 0) - siso = 0; - break; -#endif -#if INET - case AF_INET: - tsel = (caddr_t)&tutil; - if (tutil = ((struct sockaddr_in *)siso)->sin_port) { - tlen = 2; - } - if (((struct sockaddr_in *)siso)->sin_addr.s_addr == 0) - siso = 0; - } -#endif - } - if (tpcb->tp_lsuffixlen == 0) { - if (tlen) { - if (tp_tselinuse(tlen, tsel, siso, - tpcb->tp_sock->so_options & SO_REUSEADDR)) - return (EINVAL); - } else { - for (tsel = (caddr_t)&tutil, tlen = 2;;){ - if (tp_unique++ < ISO_PORT_RESERVED || - tp_unique > ISO_PORT_USERRESERVED) { - if (wrapped++) - return ESRCH; - tp_unique = ISO_PORT_RESERVED; - } - tutil = htons(tp_unique); - if (tp_tselinuse(tlen, tsel, siso, 0) == 0) - break; - } - if (siso) switch (siso->siso_family) { -#if ISO - case AF_ISO: - bcopy(tsel, TSEL(siso), tlen); - siso->siso_tlen = tlen; - break; -#endif -#if INET - case AF_INET: - ((struct sockaddr_in *)siso)->sin_port = tutil; -#endif - } - } - bcopy(tsel, tpcb->tp_lsuffix, (tpcb->tp_lsuffixlen = tlen)); - insque(tpcb, &tp_bound_pcbs); - } else { - if (tlen || siso == 0) - return (EINVAL); - } - if (siso == 0) { - tpcb->tp_flags |= TPF_GENERAL_ADDR; - return (0); - } - return tpcb->tp_nlproto->nlp_pcbbind(tpcb->tp_npcb, nam); -} diff --git a/bsd/netiso/tp_pcb.h b/bsd/netiso/tp_pcb.h deleted file mode 100644 index 5318883da..000000000 --- a/bsd/netiso/tp_pcb.h +++ /dev/null @@ -1,374 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)tp_pcb.h 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * ARGO TP - * - * - * This file defines the transport protocol control block (tpcb). - * and a bunch of #define values that are used in the tpcb. - */ - -#ifndef __TP_PCB__ -#define __TP_PCB__ - -#include -#include -#include -#ifndef sblock -#include -#endif /* sblock */ - -/* NOTE: the code depends on REF_CLOSED > REF_OPEN > the rest, and - * on REF_FREE being zero - * - * Possible improvement: - * think about merging the tp_ref w/ the tpcb and doing a search - * through the tpcb list, from tpb. This would slow down lookup - * during data transfer - * It would be a little nicer also to have something based on the - * clock (like top n bits of the reference is part of the clock, to - * minimize the likelihood of reuse after a crash) - * also, need to keep the timer servicing part to a minimum (although - * the cost of this is probably independent of whether the timers are - * in the pcb or in an array.. - * Last, would have to make the number of timers a function of the amount of - * mbufs available, plus some for the frozen references. - * - * Possible improvement: - * Might not need the ref_state stuff either... - * REF_FREE could correspond to tp_state == CLOSED or nonexistend tpcb, - * REF_OPEN to tp_state anywhere from AK_WAIT or CR_SENT to CLOSING - * REF_OPENING could correspond to LISTENING, because that's the - * way it's used, not because the correspondence is exact. - * REF_CLOSED could correspond to REFWAIT - */ -#define REF_FROZEN 3 /* has ref timer only */ -#define REF_OPEN 2 /* has timers, possibly active */ -#define REF_OPENING 1 /* in use (has a pcb) but no timers */ -#define REF_FREE 0 /* free to reallocate */ - -#define TM_NTIMERS 6 - -struct tp_ref { - struct tp_pcb *tpr_pcb; /* back ptr to PCB */ -}; - -/* PER system stuff (one static structure instead of a bunch of names) */ -struct tp_refinfo { - struct tp_ref *tpr_base; - int tpr_size; - int tpr_maxopen; - int tpr_numopen; -}; - -struct nl_protosw { - int nlp_afamily; /* address family */ - int (*nlp_putnetaddr)(); /* puts addresses in nl pcb */ - int (*nlp_getnetaddr)(); /* gets addresses from nl pcb */ - int (*nlp_cmpnetaddr)(); /* compares address in pcb with sockaddr */ - int (*nlp_putsufx)(); /* puts transport suffixes in nl pcb */ - int (*nlp_getsufx)(); /* gets transport suffixes from nl pcb */ - int (*nlp_recycle_suffix)();/* clears suffix from nl pcb */ - int (*nlp_mtu)(); /* figures out mtu based on nl used */ - int (*nlp_pcbbind)(); /* bind to pcb for net level */ - int (*nlp_pcbconn)(); /* connect for net level */ - int (*nlp_pcbdisc)(); /* disconnect net level */ - int (*nlp_pcbdetach)(); /* detach net level pcb */ - int (*nlp_pcballoc)(); /* allocate a net level pcb */ - int (*nlp_output)(); /* prepare a packet to give to nl */ - int (*nlp_dgoutput)(); /* prepare a packet to give to nl */ - int (*nlp_ctloutput)(); /* hook for network set/get options */ - caddr_t nlp_pcblist; /* list of xx_pcb's for connections */ -}; - - -struct tp_pcb { - struct tp_pcb *tp_next; - struct tp_pcb *tp_prev; - struct tp_pcb *tp_nextlisten; /* chain all listeners */ - struct socket *tp_sock; /* back ptr */ - u_short tp_state; /* state of fsm */ - short tp_retrans; /* # times can still retrans */ - caddr_t tp_npcb; /* to lower layer pcb */ - struct nl_protosw *tp_nlproto; /* lower-layer dependent routines */ - struct rtentry **tp_routep; /* obtain mtu; inside npcb */ - - - RefNum tp_lref; /* local reference */ - RefNum tp_fref; /* foreign reference */ - - u_int tp_seqmask; /* mask for seq space */ - u_int tp_seqbit; /* bit for seq number wraparound */ - u_int tp_seqhalf; /* half the seq space */ - - struct mbuf *tp_ucddata; /* user connect/disconnect data */ - - /* credit & sequencing info for SENDING */ - u_short tp_fcredit; /* current remote credit in # packets */ - u_short tp_maxfcredit; /* max remote credit in # packets */ - u_short tp_dupacks; /* intuit packet loss before rxt timo */ - u_long tp_cong_win; /* congestion window in bytes. - * see profuse comments in TCP code - */ - u_long tp_ssthresh; /* cong_win threshold for slow start - * exponential to linear switch - */ - SeqNum tp_snduna; /* seq # of lowest unacked DT */ - SeqNum tp_sndnew; /* seq # of lowest unsent DT */ - SeqNum tp_sndnum; /* next seq # to be assigned */ - SeqNum tp_sndnxt; /* what to do next; poss. rxt */ - struct mbuf *tp_sndnxt_m; /* packet corres. to sndnxt*/ - int tp_Nwindow; /* for perf. measurement */ - - /* credit & sequencing info for RECEIVING */ - SeqNum tp_rcvnxt; /* next DT seq # expect to recv */ - SeqNum tp_sent_lcdt; /* cdt according to last ack sent */ - SeqNum tp_sent_uwe; /* uwe according to last ack sent */ - SeqNum tp_sent_rcvnxt; /* rcvnxt according to last ack sent - * needed for perf measurements only - */ - u_short tp_lcredit; /* current local credit in # packets */ - u_short tp_maxlcredit; /* needed for reassembly queue */ - struct mbuf **tp_rsyq; /* unacked stuff recvd out of order */ - int tp_rsycnt; /* number of packets "" "" "" "" */ - u_long tp_rhiwat; /* remember original RCVBUF size */ - - /* receiver congestion state stuff ... */ - u_int tp_win_recv; - - /* receive window as a scaled int (8 bit fraction part) */ - - struct cong_sample { - ushort cs_size; /* current window size */ - ushort cs_received; /* PDUs received in this sample */ - ushort cs_ce_set; /* PDUs received in this sample with CE bit set */ - } tp_cong_sample; - - - /* parameters per-connection controllable by user */ - struct tp_conn_param _tp_param; - -#define tp_Nretrans _tp_param.p_Nretrans -#define tp_dr_ticks _tp_param.p_dr_ticks -#define tp_cc_ticks _tp_param.p_cc_ticks -#define tp_dt_ticks _tp_param.p_dt_ticks -#define tp_xpd_ticks _tp_param.p_x_ticks -#define tp_cr_ticks _tp_param.p_cr_ticks -#define tp_keepalive_ticks _tp_param.p_keepalive_ticks -#define tp_sendack_ticks _tp_param.p_sendack_ticks -#define tp_refer_ticks _tp_param.p_ref_ticks -#define tp_inact_ticks _tp_param.p_inact_ticks -#define tp_xtd_format _tp_param.p_xtd_format -#define tp_xpd_service _tp_param.p_xpd_service -#define tp_ack_strat _tp_param.p_ack_strat -#define tp_rx_strat _tp_param.p_rx_strat -#define tp_use_checksum _tp_param.p_use_checksum -#define tp_use_efc _tp_param.p_use_efc -#define tp_use_nxpd _tp_param.p_use_nxpd -#define tp_use_rcc _tp_param.p_use_rcc -#define tp_tpdusize _tp_param.p_tpdusize -#define tp_class _tp_param.p_class -#define tp_winsize _tp_param.p_winsize -#define tp_no_disc_indications _tp_param.p_no_disc_indications -#define tp_dont_change_params _tp_param.p_dont_change_params -#define tp_netservice _tp_param.p_netservice -#define tp_version _tp_param.p_version -#define tp_ptpdusize _tp_param.p_ptpdusize - - int tp_l_tpdusize; - /* whereas tp_tpdusize is log2(the negotiated max size) - * l_tpdusize is the size we'll use when sending, in # chars - */ - - int tp_rtv; /* max round-trip time variance */ - int tp_rtt; /* smoothed round-trip time */ - SeqNum tp_rttseq; /* packet being timed */ - int tp_rttemit; /* when emitted, in ticks */ - int tp_idle; /* last activity, in ticks */ - short tp_rxtcur; /* current retransmit value */ - short tp_rxtshift; /* log(2) of rexmt exp. backoff */ - u_char tp_cebit_off; /* real DEC bit algorithms not in use */ - u_char tp_oktonagle; /* Last unsent pckt may be append to */ - u_char tp_flags; /* values: */ -#define TPF_NLQOS_PDN TPFLAG_NLQOS_PDN -#define TPF_PEER_ON_SAMENET TPFLAG_PEER_ON_SAMENET -#define TPF_GENERAL_ADDR TPFLAG_GENERAL_ADDR -#define TPF_DELACK 0x8 -#define TPF_ACKNOW 0x10 - -#define PEER_IS_LOCAL(t) (((t)->tp_flags & TPF_PEER_ON_SAME_NET) != 0) -#define USES_PDN(t) (((t)->tp_flags & TPF_NLQOS_PDN) != 0) - - - unsigned - tp_sendfcc:1, /* shall next ack include FCC parameter? */ - tp_trace:1, /* is this pcb being traced? (not used yet) */ - tp_perf_on:1, /* 0/1 -> performance measuring on */ - tp_reneged:1, /* have we reneged on cdt since last ack? */ - tp_decbit:3, /* dec bit was set, we're in reneg mode */ - tp_notdetached:1; /* Call tp_detach before freeing XXXXXXX */ - -#ifdef TP_PERF_MEAS - /* performance stats - see tp_stat.h */ - struct tp_pmeas *tp_p_meas; - struct mbuf *tp_p_mbuf; -#endif /* TP_PERF_MEAS */ - - /* addressing */ - u_short tp_domain; /* domain (INET, ISO) */ - /* for compatibility with the *old* way and with INET, be sure that - * that lsuffix and fsuffix are aligned to a short addr. - * having them follow the u_short *suffixlen should suffice (choke) - */ - u_short tp_fsuffixlen; /* foreign suffix */ - char tp_fsuffix[MAX_TSAP_SEL_LEN]; - u_short tp_lsuffixlen; /* local suffix */ - char tp_lsuffix[MAX_TSAP_SEL_LEN]; -#define SHORT_LSUFXP(tpcb) ((short *)((tpcb)->tp_lsuffix)) -#define SHORT_FSUFXP(tpcb) ((short *)((tpcb)->tp_fsuffix)) - - /* Timer stuff */ - u_char tp_vers; /* protocol version */ - u_char tp_peer_acktime; /* used for DT retrans time */ - u_char tp_refstate; /* values REF_FROZEN, etc. above */ - struct tp_pcb *tp_fasttimeo; /* limit pcbs to examine */ - u_int tp_timer[TM_NTIMERS]; /* C timers */ - - struct sockbuf tp_Xsnd; /* for expedited data */ -/* struct sockbuf tp_Xrcv; /* for expedited data */ -#define tp_Xrcv tp_sock->so_rcv - SeqNum tp_Xsndnxt; /* next XPD seq # to send */ - SeqNum tp_Xuna; /* seq # of unacked XPD */ - SeqNum tp_Xrcvnxt; /* next XPD seq # expect to recv */ - - /* AK subsequencing */ - u_short tp_s_subseq; /* next subseq to send */ - u_short tp_r_subseq; /* highest recv subseq */ - -}; - -u_int tp_start_win; - -#define ROUND(scaled_int) (((scaled_int) >> 8) + (((scaled_int) & 0x80) ? 1:0)) - -/* to round off a scaled int with an 8 bit fraction part */ - -#define CONG_INIT_SAMPLE(pcb) \ - pcb->tp_cong_sample.cs_received = \ - pcb->tp_cong_sample.cs_ce_set = 0; \ - pcb->tp_cong_sample.cs_size = max(pcb->tp_lcredit, 1) << 1; - -#define CONG_UPDATE_SAMPLE(pcb, ce_bit) \ - pcb->tp_cong_sample.cs_received++; \ - if (ce_bit) { \ - pcb->tp_cong_sample.cs_ce_set++; \ - } \ - if (pcb->tp_cong_sample.cs_size <= pcb->tp_cong_sample.cs_received) { \ - if ((pcb->tp_cong_sample.cs_ce_set << 1) >= \ - pcb->tp_cong_sample.cs_size ) { \ - pcb->tp_win_recv -= pcb->tp_win_recv >> 3; /* multiply by .875 */ \ - pcb->tp_win_recv = max(1 << 8, pcb->tp_win_recv); \ - } \ - else { \ - pcb->tp_win_recv += (1 << 8); /* add one to the scaled int */ \ - } \ - pcb->tp_lcredit = ROUND(pcb->tp_win_recv); \ - CONG_INIT_SAMPLE(pcb); \ - } - -#ifdef KERNEL -extern struct tp_refinfo tp_refinfo; -extern struct timeval time; -extern struct tp_ref *tp_ref; -extern struct tp_param tp_param; -extern struct nl_protosw nl_protosw[]; -extern struct tp_pcb *tp_listeners; -extern struct tp_pcb *tp_ftimeolist; -#endif - -#define sototpcb(so) ((struct tp_pcb *)(so->so_pcb)) -#define sototpref(so) ((sototpcb(so)->tp_ref)) -#define tpcbtoso(tp) ((struct socket *)((tp)->tp_sock)) -#define tpcbtoref(tp) ((struct tp_ref *)((tp)->tp_ref)) - -#endif /* __TP_PCB__ */ diff --git a/bsd/netiso/tp_seq.h b/bsd/netiso/tp_seq.h deleted file mode 100644 index c07eea6a4..000000000 --- a/bsd/netiso/tp_seq.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)tp_seq.h 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * ARGO TP - * - * These macros perform sequence number arithmetic modulo (2**7 or 2**31). - * The relevant fields in the tpcb are: - * tp_seqmask : the mask of bits that define the sequence space. - * tp_seqbit : 1 + tp_seqmask - * tp_seqhalf : tp_seqbit / 2 or half the sequence space (rounded up) - * Not exactly fast, but at least it's maintainable. - */ - -#ifndef __TP_SEQ__ -#define __TP_SEQ__ - -#define SEQ(tpcb,x) \ - ((x) & (tpcb)->tp_seqmask) - -#define SEQ_GT(tpcb, seq, operand ) \ -( ((int)((seq)-(operand)) > 0)\ -? ((int)((seq)-(operand)) < (int)(tpcb)->tp_seqhalf)\ -: !(-((int)(seq)-(operand)) < (int)(tpcb)->tp_seqhalf)) - -#define SEQ_GEQ(tpcb, seq, operand ) \ -( ((int)((seq)-(operand)) >= 0)\ -? ((int)((seq)-(operand)) < (int)(tpcb)->tp_seqhalf)\ -: !((-((int)(seq)-(operand))) < (int)(tpcb)->tp_seqhalf)) - -#define SEQ_LEQ(tpcb, seq, operand ) \ -( ((int)((seq)-(operand)) <= 0)\ -? ((-(int)((seq)-(operand))) < (int)(tpcb)->tp_seqhalf)\ -: !(((int)(seq)-(operand)) < (int)(tpcb)->tp_seqhalf)) - -#define SEQ_LT(tpcb, seq, operand ) \ -( ((int)((seq)-(operand)) < 0)\ -? ((-(int)((seq)-(operand))) < (int)(tpcb)->tp_seqhalf)\ -: !(((int)(seq)-(operand)) < (int)(tpcb)->tp_seqhalf)) - -#define SEQ_MIN(tpcb, a, b) ( SEQ_GT(tpcb, a, b) ? b : a) - -#define SEQ_MAX(tpcb, a, b) ( SEQ_GT(tpcb, a, b) ? a : b) - -#define SEQ_INC(tpcb, Seq) ((++Seq), ((Seq) &= (tpcb)->tp_seqmask)) - -#define SEQ_DEC(tpcb, Seq)\ - ((Seq) = (((Seq)+(unsigned)((int)(tpcb)->tp_seqbit - 1))&(tpcb)->tp_seqmask)) - -/* (amt) had better be less than the seq bit ! */ - -#define SEQ_SUB(tpcb, Seq, amt)\ - (((Seq) + (unsigned)((int)(tpcb)->tp_seqbit - amt)) & (tpcb)->tp_seqmask) -#define SEQ_ADD(tpcb, Seq, amt) (((Seq) + (unsigned)amt) & (tpcb)->tp_seqmask) - - -#define IN_RWINDOW(tpcb, seq, lwe, uwe)\ - ( SEQ_GEQ(tpcb, seq, lwe) && SEQ_LT(tpcb, seq, uwe) ) - -#define IN_SWINDOW(tpcb, seq, lwe, uwe)\ - ( SEQ_GT(tpcb, seq, lwe) && SEQ_LEQ(tpcb, seq, uwe) ) - -#endif /* __TP_SEQ__ */ diff --git a/bsd/netiso/tp_stat.h b/bsd/netiso/tp_stat.h deleted file mode 100644 index c22e40850..000000000 --- a/bsd/netiso/tp_stat.h +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)tp_stat.h 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * ARGO TP - * - * Here are the data structures in which the global - * statistics(counters) are gathered. - */ - -#ifndef __TP_STAT__ -#define __TP_STAT__ - -struct tp_stat { - u_long ts_param_ignored; - u_long ts_unused3; - u_long ts_bad_csum; - - u_long ts_inv_length; - u_long ts_inv_pcode; - u_long ts_inv_dutype; - u_long ts_negotfailed; - u_long ts_inv_dref; - u_long ts_inv_pval; - u_long ts_inv_sufx; - u_long ts_inv_aclass; - - u_long ts_xtd_fmt; - u_long ts_use_txpd; - u_long ts_csum_off; - u_long ts_send_drop; - u_long ts_recv_drop; - - u_long ts_xpd_intheway;/* xpd mark caused data flow to stop */ - u_long ts_xpdmark_del; /* xpd markers thrown away */ - u_long ts_dt_ooo; /* dt tpdus received out of order */ - u_long ts_dt_niw; /* dt tpdus received & not in window */ - u_long ts_xpd_niw; /* xpd tpdus received & not in window */ - u_long ts_xpd_dup; - u_long ts_dt_dup; /* dt tpdus received & are duplicates */ - - u_long ts_zfcdt; /* # times f credit went down to 0 */ - u_long ts_lcdt_reduced; /* - # times local cdt reduced on an acknowledgement. - */ - - u_long ts_pkt_rcvd; /* from ip */ - u_long ts_tpdu_rcvd; /* accepted as a TPDU in tp_input */ - u_long ts_tpdu_sent; - u_long ts_unused2; - - u_long ts_retrans_cr; - u_long ts_retrans_cc; - u_long ts_retrans_dr; - u_long ts_retrans_dt; - u_long ts_retrans_xpd; - u_long ts_conn_gaveup; - - u_long ts_ER_sent; - u_long ts_DT_sent; - u_long ts_XPD_sent; - u_long ts_AK_sent; - u_long ts_XAK_sent; - u_long ts_DR_sent; - u_long ts_DC_sent; - u_long ts_CR_sent; - u_long ts_CC_sent; - - u_long ts_ER_rcvd; - u_long ts_DT_rcvd; - u_long ts_XPD_rcvd; - u_long ts_AK_rcvd; - u_long ts_XAK_rcvd; - u_long ts_DR_rcvd; - u_long ts_DC_rcvd; - u_long ts_CR_rcvd; - u_long ts_CC_rcvd; - - u_long ts_Eticks; - u_long ts_Eexpired; - u_long ts_Eset; - u_long ts_Ecan_act; - u_long ts_Cticks; - u_long ts_Cexpired; - u_long ts_Cset; - u_long ts_Ccan_act; - u_long ts_Ccan_inact; - u_long ts_Fdelack; - u_long ts_Fpruned; - - u_long ts_concat_rcvd; - - u_long ts_zdebug; /* zero dref to test timeout on conn estab tp_input.c */ - u_long ts_ydebug; /* throw away pseudo-random pkts tp_input.c */ - u_long ts_unused5; - u_long ts_unused; /* kludged concat to test separation tp_emit.c */ - u_long ts_vdebug; /* kludge to test input size checking tp_emit.c */ - u_long ts_unused4; - u_long ts_ldebug; /* faked a renegging of credit */ - - u_long ts_mb_small; - u_long ts_mb_cluster; - u_long ts_mb_len_distr[17]; - - u_long ts_eot_input; - u_long ts_eot_user; - u_long ts_EOT_sent; - u_long ts_tp0_conn; - u_long ts_tp4_conn; - u_long ts_quench; - u_long ts_rcvdecbit; - -#define NRTT_CATEGORIES 4 - /* The 4 categories are: - * 0 --> tp_flags: ~TPF_PEER_ON_SAMENET | TPF_NL_PDN - * 1 --> tp_flags: ~TPF_PEER_ON_SAMENET | ~TPF_NL_PDN - * 2 --> tp_flags: TPF_PEER_ON_SAMENET | ~TPF_NL_PDN - * 3 --> tp_flags: TPF_PEER_ON_SAMENET | TPF_NL_PDN - */ - int ts_rtt[NRTT_CATEGORIES]; - int ts_rtv[NRTT_CATEGORIES]; - - u_long ts_ackreason[_ACK_NUM_REASONS_]; - /* ACK_DONT 0 / ACK_STRAT_EACH 0x1 / ACK_STRAT_FULLWIN 0x4 - * ACK_DUP 0x8 / ACK_EOT 0x10 / ACK_REORDER 0x20 - * ACK_USRRCV ** - * ACK_FCC ** - */ -} tp_stat ; -#define TP_PM_MAX 0xa /* 10 decimal */ - -#define IncStat(x) tp_stat./**/x/**/++ - -#ifdef TP_PERF_MEAS - -#define PStat(Tpcb, X) (Tpcb)->tp_p_meas->/**/X/**/ -#define IncPStat(Tpcb, X) if((Tpcb)->tp_perf_on) (Tpcb)->tp_p_meas->/**/X/**/++ - -/* BEWARE OF MACROS like this ^^^ must be sure it's surrounded by {} if - * it's used in an if-else statement. - */ - - -/* for perf measurement stuff: maximum window size it can handle */ - -struct tp_pmeas { - /* the first few are distributions as a fn of window size - * only keep enough space for normal format plus 1 slot for - * extended format, in case any windows larger than 15 are used - */ - - /* - * tps_npdusent: for each call to tp_sbsend, we inc the - * element representing the number of pdus sent in this call - */ - int tps_win_lim_by_cdt[TP_PM_MAX+1]; - int tps_win_lim_by_data[TP_PM_MAX+1]; - /* - * tps_sendtime: Each call to tp_sbsend() is timed. For - * Each window size, we keep the running average of the time - * taken by tp_sbsend() for each window size. - */ - int tps_sendtime[TP_PM_MAX+1]; - /* - * n_TMsendack: # times ack sent because timer went off - * n_ack_cuz_eot: # times ack sent due to EOTSDU on incoming packet - * n_ack_cuz_dup: # times ack sent for receiving a duplicate pkt. - * n_ack_cuz_fullwin: # times ack sent for receiving the full window. - * n_ack_cuz_doack: # times ack sent for having just reordered data. - */ - int tps_n_TMsendack; - int tps_n_ack_cuz_eot; - int tps_n_ack_cuz_fullwin; - int tps_n_ack_cuz_reorder; - int tps_n_ack_cuz_dup; - int tps_n_ack_cuz_strat; - /* - * when we send an ack: how much less than the "expected" window - * did we actually ack. For example: if we last sent a credit - * of 10, and we're acking now for whatever reason, and have - * only received 6 since our last credit advertisement, we'll - * keep the difference, 4, in this variable. - */ - int tps_ack_early[TP_PM_MAX+1]; - /* - * when we ack, for the # pkts we actually acked w/ this ack, - * how much cdt are we advertising? - * [ size of window acknowledged ] [ cdt we're giving ] - */ - int tps_cdt_acked[TP_PM_MAX+1][TP_PM_MAX+1]; - - int tps_AK_sent; - int tps_XAK_sent; - int tps_DT_sent; - int tps_XPD_sent; - int tps_AK_rcvd; - int tps_XAK_rcvd; - int tps_DT_rcvd; - int tps_XPD_rcvd; - - int Nb_from_sess; - int Nb_to_sess; - int Nb_to_ll; - int Nb_from_ll; -}; - -#define IFPERF(tpcb) if (tpcb->tp_perf_on && tpcb->tp_p_meas) { -#define ENDPERF } - -#else - -int PStat_Junk; -#define PStat(tpcb, x) PStat_Junk -#define IncPStat(tpcb, x) /* no-op */ -#define tpmeas(a,b,c,d,e,f) 0 - -#define IFPERF(x) if (0) { -#define ENDPERF } - -#endif /* TP_PERF_MEAS */ - -#endif /* __TP_STAT__ */ diff --git a/bsd/netiso/tp_states.h b/bsd/netiso/tp_states.h deleted file mode 100644 index 69b5456f9..000000000 --- a/bsd/netiso/tp_states.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -#define ST_ERROR 0x0 -#define TP_CLOSED 0x1 -#define TP_CRSENT 0x2 -#define TP_AKWAIT 0x3 -#define TP_OPEN 0x4 -#define TP_CLOSING 0x5 -#define TP_REFWAIT 0x6 -#define TP_LISTENING 0x7 -#define TP_CONFIRMING 0x8 - -#define tp_NSTATES 0x9 diff --git a/bsd/netiso/tp_subr.c b/bsd/netiso/tp_subr.c deleted file mode 100644 index da59945ce..000000000 --- a/bsd/netiso/tp_subr.c +++ /dev/null @@ -1,967 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)tp_subr.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * ARGO TP - * - * The main work of data transfer is done here. - * These routines are called from tp.trans. - * They include the routines that check the validity of acks and Xacks, - * (tp_goodack() and tp_goodXack() ) - * take packets from socket buffers and send them (tp_send()), - * drop the data from the socket buffers (tp_sbdrop()), - * and put incoming packet data into socket buffers (tp_stash()). - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int tp_emit(), tp_sbdrop(); -int tprexmtthresh = 3; -extern int ticks; -void tp_send(); - -/* - * CALLED FROM: - * tp.trans, when an XAK arrives - * FUNCTION and ARGUMENTS: - * Determines if the sequence number (seq) from the XAK - * acks anything new. If so, drop the appropriate tpdu - * from the XPD send queue. - * RETURN VALUE: - * Returns 1 if it did this, 0 if the ack caused no action. - */ -int -tp_goodXack(tpcb, seq) - struct tp_pcb *tpcb; - SeqNum seq; -{ - - IFTRACE(D_XPD) - tptraceTPCB(TPPTgotXack, - seq, tpcb->tp_Xuna, tpcb->tp_Xsndnxt, tpcb->tp_sndnew, - tpcb->tp_snduna); - ENDTRACE - - if ( seq == tpcb->tp_Xuna ) { - tpcb->tp_Xuna = tpcb->tp_Xsndnxt; - - /* DROP 1 packet from the Xsnd socket buf - just so happens - * that only one packet can be there at any time - * so drop the whole thing. If you allow > 1 packet - * the socket buffer, then you'll have to keep - * track of how many characters went w/ each XPD tpdu, so this - * will get messier - */ - IFDEBUG(D_XPD) - dump_mbuf(tpcb->tp_Xsnd.sb_mb, - "tp_goodXack Xsnd before sbdrop"); - ENDDEBUG - - IFTRACE(D_XPD) - tptraceTPCB(TPPTmisc, - "goodXack: dropping cc ", - (int)(tpcb->tp_Xsnd.sb_cc), - 0,0,0); - ENDTRACE - sbdroprecord(&tpcb->tp_Xsnd); - return 1; - } - return 0; -} - -/* - * CALLED FROM: - * tp_good_ack() - * FUNCTION and ARGUMENTS: - * updates - * smoothed average round trip time (*rtt) - * roundtrip time variance (*rtv) - actually deviation, not variance - * given the new value (diff) - * RETURN VALUE: - * void - */ - -void -tp_rtt_rtv(tpcb) -register struct tp_pcb *tpcb; -{ - int old = tpcb->tp_rtt; - int delta, elapsed = ticks - tpcb->tp_rttemit; - - if (tpcb->tp_rtt != 0) { - /* - * rtt is the smoothed round trip time in machine clock ticks (hz). - * It is stored as a fixed point number, unscaled (unlike the tcp - * srtt). The rationale here is that it is only significant to the - * nearest unit of slowtimo, which is at least 8 machine clock ticks - * so there is no need to scale. The smoothing is done according - * to the same formula as TCP (rtt = rtt*7/8 + measured_rtt/8). - */ - delta = elapsed - tpcb->tp_rtt; - if ((tpcb->tp_rtt += (delta >> TP_RTT_ALPHA)) <= 0) - tpcb->tp_rtt = 1; - /* - * rtv is a smoothed accumulated mean difference, unscaled - * for reasons expressed above. - * It is smoothed with an alpha of .75, and the round trip timer - * will be set to rtt + 4*rtv, also as TCP does. - */ - if (delta < 0) - delta = -delta; - if ((tpcb->tp_rtv += ((delta - tpcb->tp_rtv) >> TP_RTV_ALPHA)) <= 0) - tpcb->tp_rtv = 1; - } else { - /* - * No rtt measurement yet - use the unsmoothed rtt. - * Set the variance to half the rtt (so our first - * retransmit happens at 3*rtt) - */ - tpcb->tp_rtt = elapsed; - tpcb->tp_rtv = elapsed >> 1; - } - tpcb->tp_rttemit = 0; - tpcb->tp_rxtshift = 0; - /* - * Quoting TCP: "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)." - */ - TP_RANGESET(tpcb->tp_dt_ticks, TP_REXMTVAL(tpcb), - tpcb->tp_peer_acktime, 128 /* XXX */); - IFDEBUG(D_RTT) - printf("%s tpcb 0x%x, elapsed %d, delta %d, rtt %d, rtv %d, old %d\n", - "tp_rtt_rtv:",tpcb,elapsed,delta,tpcb->tp_rtt,tpcb->tp_rtv,old); - ENDDEBUG - tpcb->tp_rxtcur = tpcb->tp_dt_ticks; -} - -/* - * CALLED FROM: - * tp.trans when an AK arrives - * FUNCTION and ARGUMENTS: - * Given (cdt), the credit from the AK tpdu, and - * (seq), the sequence number from the AK tpdu, - * tp_goodack() determines if the AK acknowledges something in the send - * window, and if so, drops the appropriate packets from the retransmission - * list, computes the round trip time, and updates the retransmission timer - * based on the new smoothed round trip time. - * RETURN VALUE: - * Returns 1 if - * EITHER it actually acked something heretofore unacknowledged - * OR no news but the credit should be processed. - * If something heretofore unacked was acked with this sequence number, - * the appropriate tpdus are dropped from the retransmission control list, - * by calling tp_sbdrop(). - * No need to see the tpdu itself. - */ -int -tp_goodack(tpcb, cdt, seq, subseq) - register struct tp_pcb *tpcb; - u_int cdt; - register SeqNum seq; - u_int subseq; -{ - int old_fcredit; - int bang = 0; /* bang --> ack for something heretofore unacked */ - u_int bytes_acked; - - IFDEBUG(D_ACKRECV) - printf("goodack tpcb 0x%x seq 0x%x cdt %d una 0x%x new 0x%x nxt 0x%x\n", - tpcb, seq, cdt, tpcb->tp_snduna, tpcb->tp_sndnew, tpcb->tp_sndnxt); - ENDDEBUG - IFTRACE(D_ACKRECV) - tptraceTPCB(TPPTgotack, - seq,cdt, tpcb->tp_snduna,tpcb->tp_sndnew,subseq); - ENDTRACE - - IFPERF(tpcb) - tpmeas(tpcb->tp_lref, TPtime_ack_rcvd, (struct timeval *)0, seq, 0, 0); - ENDPERF - - if (seq == tpcb->tp_snduna) { - if (subseq < tpcb->tp_r_subseq || - (subseq == tpcb->tp_r_subseq && cdt <= tpcb->tp_fcredit)) { - discard_the_ack: - IFDEBUG(D_ACKRECV) - printf("goodack discard : tpcb 0x%x subseq %d r_subseq %d\n", - tpcb, subseq, tpcb->tp_r_subseq); - ENDDEBUG - goto done; - } - if (cdt == tpcb->tp_fcredit /*&& thus subseq > tpcb->tp_r_subseq */) { - tpcb->tp_r_subseq = subseq; - if (tpcb->tp_timer[TM_data_retrans] == 0) - tpcb->tp_dupacks = 0; - else if (++tpcb->tp_dupacks == tprexmtthresh) { - /* partner went out of his way to signal with different - subsequences that he has the same lack of an expected - packet. This may be an early indiciation of a loss */ - - SeqNum onxt = tpcb->tp_sndnxt; - struct mbuf *onxt_m = tpcb->tp_sndnxt_m; - u_int win = min(tpcb->tp_fcredit, - tpcb->tp_cong_win / tpcb->tp_l_tpdusize) / 2; - IFDEBUG(D_ACKRECV) - printf("%s tpcb 0x%x seq 0x%x rttseq 0x%x onxt 0x%x\n", - "goodack dupacks:", tpcb, seq, tpcb->tp_rttseq, onxt); - ENDDEBUG - if (win < 2) - win = 2; - tpcb->tp_ssthresh = win * tpcb->tp_l_tpdusize; - tpcb->tp_timer[TM_data_retrans] = 0; - tpcb->tp_rttemit = 0; - tpcb->tp_sndnxt = tpcb->tp_snduna; - tpcb->tp_sndnxt_m = 0; - tpcb->tp_cong_win = tpcb->tp_l_tpdusize; - tp_send(tpcb); - tpcb->tp_cong_win = tpcb->tp_ssthresh + - tpcb->tp_dupacks * tpcb->tp_l_tpdusize; - if (SEQ_GT(tpcb, onxt, tpcb->tp_sndnxt)) { - tpcb->tp_sndnxt = onxt; - tpcb->tp_sndnxt_m = onxt_m; - } - - } else if (tpcb->tp_dupacks > tprexmtthresh) { - tpcb->tp_cong_win += tpcb->tp_l_tpdusize; - } - goto done; - } - } else if (SEQ_LT(tpcb, seq, tpcb->tp_snduna)) - goto discard_the_ack; - /* - * If the congestion window was inflated to account - * for the other side's cached packets, retract it. - */ - if (tpcb->tp_dupacks > tprexmtthresh && - tpcb->tp_cong_win > tpcb->tp_ssthresh) - tpcb->tp_cong_win = tpcb->tp_ssthresh; - tpcb->tp_r_subseq = subseq; - old_fcredit = tpcb->tp_fcredit; - tpcb->tp_fcredit = cdt; - if (cdt > tpcb->tp_maxfcredit) - tpcb->tp_maxfcredit = cdt; - tpcb->tp_dupacks = 0; - - if (IN_SWINDOW(tpcb, seq, tpcb->tp_snduna, tpcb->tp_sndnew)) { - - tpsbcheck(tpcb, 0); - bytes_acked = tp_sbdrop(tpcb, seq); - tpsbcheck(tpcb, 1); - /* - * 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 (tpcb->tp_rttemit && SEQ_GT(tpcb, seq, tpcb->tp_rttseq)) - tp_rtt_rtv(tpcb); - /* - * If all outstanding data is acked, stop retransmit timer. - * If there is more data to be acked, restart retransmit - * timer, using current (possibly backed-off) value. - * OSI combines the keepalive and persistance functions. - * So, there is no persistance timer per se, to restart. - */ - if (tpcb->tp_class != TP_CLASS_0) - tpcb->tp_timer[TM_data_retrans] = - (seq == tpcb->tp_sndnew) ? 0 : tpcb->tp_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. - */ - { - u_int cw = tpcb->tp_cong_win, incr = tpcb->tp_l_tpdusize; - - incr = min(incr, bytes_acked); - if (cw > tpcb->tp_ssthresh) - incr = incr * incr / cw + incr / 8; - tpcb->tp_cong_win = - min(cw + incr, tpcb->tp_sock->so_snd.sb_hiwat); - } - tpcb->tp_snduna = seq; - if (SEQ_LT(tpcb, tpcb->tp_sndnxt, seq)) { - tpcb->tp_sndnxt = seq; - tpcb->tp_sndnxt_m = 0; - } - bang++; - } - - if( cdt != 0 && old_fcredit == 0 ) { - tpcb->tp_sendfcc = 1; - } - if (cdt == 0) { - if (old_fcredit != 0) - IncStat(ts_zfcdt); - /* The following might mean that the window shrunk */ - if (tpcb->tp_timer[TM_data_retrans]) { - tpcb->tp_timer[TM_data_retrans] = 0; - tpcb->tp_timer[TM_sendack] = tpcb->tp_dt_ticks; - if (tpcb->tp_sndnxt != tpcb->tp_snduna) { - tpcb->tp_sndnxt = tpcb->tp_snduna; - tpcb->tp_sndnxt_m = 0; - } - } - } - tpcb->tp_fcredit = cdt; - bang |= (old_fcredit < cdt); - -done: - IFDEBUG(D_ACKRECV) - printf("goodack returns 0x%x, cdt 0x%x ocdt 0x%x cwin 0x%x\n", - bang, cdt, old_fcredit, tpcb->tp_cong_win); - ENDDEBUG - /* if (bang) XXXXX Very bad to remove this test, but somethings broken */ - tp_send(tpcb); - return (bang); -} - -/* - * CALLED FROM: - * tp_goodack() - * FUNCTION and ARGUMENTS: - * drops everything up TO but not INCLUDING seq # (seq) - * from the retransmission queue. - */ -tp_sbdrop(tpcb, seq) - register struct tp_pcb *tpcb; - SeqNum seq; -{ - struct sockbuf *sb = &tpcb->tp_sock->so_snd; - register int i = SEQ_SUB(tpcb, seq, tpcb->tp_snduna); - int oldcc = sb->sb_cc, oldi = i; - - if (i >= tpcb->tp_seqhalf) - printf("tp_spdropping too much -- should panic"); - while (i-- > 0) - sbdroprecord(sb); - IFDEBUG(D_ACKRECV) - printf("tp_sbdroping %d pkts %d bytes on %x at 0x%x\n", - oldi, oldcc - sb->sb_cc, tpcb, seq); - ENDDEBUG - if ((sb->sb_flags & SB_NOTIFY) || (sb->sb_sel.si_flags & SI_SBSEL)) - sowwakeup(tpcb->tp_sock); - return (oldcc - sb->sb_cc); -} - -/* - * CALLED FROM: - * tp.trans on user send request, arrival of AK and arrival of XAK - * FUNCTION and ARGUMENTS: - * Emits tpdus starting at sequence number (tpcb->tp_sndnxt). - * Emits until a) runs out of data, or b) runs into an XPD mark, or - * c) it hits seq number (highseq) limited by cong or credit. - * - * If you want XPD to buffer > 1 du per socket buffer, you can - * modifiy this to issue XPD tpdus also, but then it'll have - * to take some argument(s) to distinguish between the type of DU to - * hand tp_emit. - * - * When something is sent for the first time, its time-of-send - * is stashed (in system clock ticks rather than pf_slowtimo ticks). - * When the ack arrives, the smoothed round-trip time is figured - * using this value. - */ -void -tp_send(tpcb) - register struct tp_pcb *tpcb; -{ - register int len; - register struct mbuf *m; - struct mbuf *mb = 0; - struct sockbuf *sb = &tpcb->tp_sock->so_snd; - unsigned int eotsdu = 0; - SeqNum highseq, checkseq; - int idle, idleticks, off, cong_win; -#ifdef TP_PERF_MEAS - int send_start_time = ticks; - SeqNum oldnxt = tpcb->tp_sndnxt; -#endif /* TP_PERF_MEAS */ - - idle = (tpcb->tp_snduna == tpcb->tp_sndnew); - if (idle) { - idleticks = tpcb->tp_inact_ticks - tpcb->tp_timer[TM_inact]; - if (idleticks > tpcb->tp_dt_ticks) - /* - * 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. - */ - tpcb->tp_cong_win = tpcb->tp_l_tpdusize; - } - - cong_win = tpcb->tp_cong_win; - highseq = SEQ(tpcb, tpcb->tp_fcredit + tpcb->tp_snduna); - if (tpcb->tp_Xsnd.sb_mb) - highseq = SEQ_MIN(tpcb, highseq, tpcb->tp_sndnew); - - IFDEBUG(D_DATA) - printf("tp_send enter tpcb 0x%x nxt 0x%x win %d high 0x%x\n", - tpcb, tpcb->tp_sndnxt, cong_win, highseq); - ENDDEBUG - IFTRACE(D_DATA) - tptraceTPCB( TPPTmisc, "tp_send sndnew snduna", - tpcb->tp_sndnew, tpcb->tp_snduna, 0, 0); - tptraceTPCB( TPPTmisc, "tp_send tpcb->tp_sndnxt win fcredit congwin", - tpcb->tp_sndnxt, cong_win, tpcb->tp_fcredit, tpcb->tp_cong_win); - ENDTRACE - IFTRACE(D_DATA) - tptraceTPCB( TPPTmisc, "tp_send 2 nxt high fcredit congwin", - tpcb->tp_sndnxt, highseq, tpcb->tp_fcredit, cong_win); - ENDTRACE - - if (tpcb->tp_sndnxt_m) - m = tpcb->tp_sndnxt_m; - else { - off = SEQ_SUB(tpcb, tpcb->tp_sndnxt, tpcb->tp_snduna); - for (m = sb->sb_mb; m && off > 0; m = m->m_next) - off--; - } -send: - /* - * Avoid silly window syndrome here . . . figure out how! - */ - checkseq = tpcb->tp_sndnum; - if (idle && SEQ_LT(tpcb, tpcb->tp_sndnum, highseq)) - checkseq = highseq; /* i.e. DON'T retain highest assigned packet */ - - while ((SEQ_LT(tpcb, tpcb->tp_sndnxt, highseq)) && m && cong_win > 0) { - - eotsdu = (m->m_flags & M_EOR) != 0; - len = m->m_pkthdr.len; - if (tpcb->tp_sndnxt == checkseq && eotsdu == 0 && - len < (tpcb->tp_l_tpdusize / 2)) - break; /* Nagle . . . . . */ - cong_win -= len; - /* make a copy - mb goes into the retransmission list - * while m gets emitted. m_copy won't copy a zero-length mbuf. - */ - mb = m; - m = m_copy(mb, 0, M_COPYALL); - if (m == MNULL) - break; - IFTRACE(D_STASH) - tptraceTPCB( TPPTmisc, - "tp_send mcopy nxt high eotsdu len", - tpcb->tp_sndnxt, highseq, eotsdu, len); - ENDTRACE - - IFDEBUG(D_DATA) - printf("tp_sending tpcb 0x%x nxt 0x%x\n", - tpcb, tpcb->tp_sndnxt); - ENDDEBUG - /* when headers are precomputed, may need to fill - in checksum here */ - if (tpcb->tp_sock->so_error = - tp_emit(DT_TPDU_type, tpcb, tpcb->tp_sndnxt, eotsdu, m)) { - /* error */ - break; - } - m = mb->m_nextpkt; - tpcb->tp_sndnxt_m = m; - if (tpcb->tp_sndnxt == tpcb->tp_sndnew) { - SEQ_INC(tpcb, tpcb->tp_sndnew); - /* - * Time this transmission if not a retransmission and - * not currently timing anything. - */ - if (tpcb->tp_rttemit == 0) { - tpcb->tp_rttemit = ticks; - tpcb->tp_rttseq = tpcb->tp_sndnxt; - } - tpcb->tp_sndnxt = tpcb->tp_sndnew; - } else - SEQ_INC(tpcb, tpcb->tp_sndnxt); - /* - * Set retransmit timer if not currently set. - * 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 (tpcb->tp_timer[TM_data_retrans] == 0 && - tpcb->tp_class != TP_CLASS_0) { - tpcb->tp_timer[TM_data_retrans] = tpcb->tp_dt_ticks; - tpcb->tp_timer[TM_sendack] = tpcb->tp_keepalive_ticks; - tpcb->tp_rxtshift = 0; - } - } - if (SEQ_GT(tpcb, tpcb->tp_sndnew, tpcb->tp_sndnum)) - tpcb->tp_oktonagle = 0; -#ifdef TP_PERF_MEAS - IFPERF(tpcb) - { - register int npkts; - int elapsed = ticks - send_start_time, *t; - struct timeval now; - - npkts = SEQ_SUB(tpcb, tpcb->tp_sndnxt, oldnxt); - - if (npkts > 0) - tpcb->tp_Nwindow++; - - if (npkts > TP_PM_MAX) - npkts = TP_PM_MAX; - - t = &(tpcb->tp_p_meas->tps_sendtime[npkts]); - *t += (t - elapsed) >> TP_RTT_ALPHA; - - if (mb == 0) { - IncPStat(tpcb, tps_win_lim_by_data[npkts] ); - } else { - IncPStat(tpcb, tps_win_lim_by_cdt[npkts] ); - /* not true with congestion-window being used */ - } - now.tv_sec = elapsed / hz; - now.tv_usec = (elapsed - (hz * now.tv_sec)) * 1000000 / hz; - tpmeas( tpcb->tp_lref, - TPsbsend, &elapsed, newseq, tpcb->tp_Nwindow, npkts); - } - ENDPERF -#endif /* TP_PERF_MEAS */ - - - IFTRACE(D_DATA) - tptraceTPCB( TPPTmisc, - "tp_send at end: new nxt eotsdu error", - tpcb->tp_sndnew, tpcb->tp_sndnxt, eotsdu, tpcb->tp_sock->so_error); - - ENDTRACE -} - -int TPNagleok; -int TPNagled; - -tp_packetize(tpcb, m, eotsdu) -register struct tp_pcb *tpcb; -register struct mbuf *m; -int eotsdu; -{ - register struct mbuf *n; - register struct sockbuf *sb = &tpcb->tp_sock->so_snd; - int maxsize = tpcb->tp_l_tpdusize - - tp_headersize(DT_TPDU_type, tpcb) - - (tpcb->tp_use_checksum?4:0) ; - int totlen = m->m_pkthdr.len; - struct mbuf *m_split(); - /* - * Pre-packetize the data in the sockbuf - * according to negotiated mtu. Do it here - * where we can safely wait for mbufs. - * - * This presumes knowledge of sockbuf conventions. - * TODO: allocate space for header and fill it in (once!). - */ - IFDEBUG(D_DATA) - printf("SEND BF: maxsize %d totlen %d eotsdu %d sndnum 0x%x\n", - maxsize, totlen, eotsdu, tpcb->tp_sndnum); - ENDTRACE - if (tpcb->tp_oktonagle) { - if ((n = sb->sb_mb) == 0) - panic("tp_packetize"); - while (n->m_act) - n = n->m_act; - if (n->m_flags & M_EOR) - panic("tp_packetize 2"); - SEQ_INC(tpcb, tpcb->tp_sndnum); - if (totlen + n->m_pkthdr.len < maxsize) { - /* There is an unsent packet with space, combine data */ - struct mbuf *old_n = n; - tpsbcheck(tpcb,3); - n->m_pkthdr.len += totlen; - while (n->m_next) - n = n->m_next; - sbcompress(sb, m, n); - tpsbcheck(tpcb,4); - n = old_n; - TPNagled++; - goto out; - } - } - while (m) { - n = m; - if (totlen > maxsize) { - if ((m = m_split(n, maxsize, M_WAIT)) == 0) - panic("tp_packetize"); - } else - m = 0; - totlen -= maxsize; - tpsbcheck(tpcb, 5); - sbappendrecord(sb, n); - tpsbcheck(tpcb, 6); - SEQ_INC(tpcb, tpcb->tp_sndnum); - } -out: - if (eotsdu) { - n->m_flags |= M_EOR; /* XXX belongs at end */ - tpcb->tp_oktonagle = 0; - } else { - SEQ_DEC(tpcb, tpcb->tp_sndnum); - tpcb->tp_oktonagle = 1; - TPNagleok++; - } - IFDEBUG(D_DATA) - printf("SEND out: oktonagle %d sndnum 0x%x\n", - tpcb->tp_oktonagle, tpcb->tp_sndnum); - ENDTRACE - return 0; -} - - -/* - * NAME: tp_stash() - * CALLED FROM: - * tp.trans on arrival of a DT tpdu - * FUNCTION, ARGUMENTS, and RETURN VALUE: - * Returns 1 if - * a) something new arrived and it's got eotsdu_reached bit on, - * b) this arrival was caused other out-of-sequence things to be - * accepted, or - * c) this arrival is the highest seq # for which we last gave credit - * (sender just sent a whole window) - * In other words, returns 1 if tp should send an ack immediately, 0 if - * the ack can wait a while. - * - * Note: this implementation no longer renegs on credit, (except - * when debugging option D_RENEG is on, for the purpose of testing - * ack subsequencing), so we don't need to check for incoming tpdus - * being in a reneged portion of the window. - */ - -tp_stash(tpcb, e) - register struct tp_pcb *tpcb; - register struct tp_event *e; -{ - register int ack_reason= tpcb->tp_ack_strat & ACK_STRAT_EACH; - /* 0--> delay acks until full window */ - /* 1--> ack each tpdu */ -#ifndef lint -#define E e->ATTR(DT_TPDU) -#else /* lint */ -#define E e->ev_union.EV_DT_TPDU -#endif /* lint */ - - if ( E.e_eot ) { - register struct mbuf *n = E.e_data; - n->m_flags |= M_EOR; - n->m_act = 0; - } - IFDEBUG(D_STASH) - dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, - "stash: so_rcv before appending"); - dump_mbuf(E.e_data, - "stash: e_data before appending"); - ENDDEBUG - - IFPERF(tpcb) - PStat(tpcb, Nb_from_ll) += E.e_datalen; - tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time, - E.e_seq, (u_int)PStat(tpcb, Nb_from_ll), (u_int)E.e_datalen); - ENDPERF - - if (E.e_seq == tpcb->tp_rcvnxt) { - - IFDEBUG(D_STASH) - printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n", - E.e_seq, E.e_datalen, E.e_eot); - ENDDEBUG - - IFTRACE(D_STASH) - tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", - E.e_seq, E.e_datalen, E.e_eot, 0); - ENDTRACE - - SET_DELACK(tpcb); - - sbappend(&tpcb->tp_sock->so_rcv, E.e_data); - - SEQ_INC( tpcb, tpcb->tp_rcvnxt ); - /* - * move chains from the reassembly queue to the socket buffer - */ - if (tpcb->tp_rsycnt) { - register struct mbuf **mp; - struct mbuf **mplim; - - mp = tpcb->tp_rsyq + (tpcb->tp_rcvnxt % tpcb->tp_maxlcredit); - mplim = tpcb->tp_rsyq + tpcb->tp_maxlcredit; - - while (tpcb->tp_rsycnt && *mp) { - sbappend(&tpcb->tp_sock->so_rcv, *mp); - tpcb->tp_rsycnt--; - *mp = 0; - SEQ_INC(tpcb, tpcb->tp_rcvnxt); - ack_reason |= ACK_REORDER; - if (++mp == mplim) - mp = tpcb->tp_rsyq; - } - } - IFDEBUG(D_STASH) - dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, - "stash: so_rcv after appending"); - ENDDEBUG - - } else { - register struct mbuf **mp; - SeqNum uwe; - - IFTRACE(D_STASH) - tptraceTPCB(TPPTmisc, "stash Reseq: seq rcvnxt lcdt", - E.e_seq, tpcb->tp_rcvnxt, tpcb->tp_lcredit, 0); - ENDTRACE - - if (tpcb->tp_rsyq == 0) - tp_rsyset(tpcb); - uwe = SEQ(tpcb, tpcb->tp_rcvnxt + tpcb->tp_maxlcredit); - if (tpcb->tp_rsyq == 0 || - !IN_RWINDOW(tpcb, E.e_seq, tpcb->tp_rcvnxt, uwe)) { - ack_reason = ACK_DONT; - m_freem(E.e_data); - } else if (*(mp = tpcb->tp_rsyq + (E.e_seq % tpcb->tp_maxlcredit))) { - IFDEBUG(D_STASH) - printf("tp_stash - drop & ack\n"); - ENDDEBUG - - /* retransmission - drop it and force an ack */ - IncStat(ts_dt_dup); - IFPERF(tpcb) - IncPStat(tpcb, tps_n_ack_cuz_dup); - ENDPERF - - m_freem(E.e_data); - ack_reason |= ACK_DUP; - } else { - *mp = E.e_data; - tpcb->tp_rsycnt++; - ack_reason = ACK_DONT; - } - } - /* there were some comments of historical interest here. */ - { - LOCAL_CREDIT(tpcb); - - if ( E.e_seq == tpcb->tp_sent_uwe ) - ack_reason |= ACK_STRAT_FULLWIN; - - IFTRACE(D_STASH) - tptraceTPCB(TPPTmisc, - "end of stash, eot, ack_reason, sent_uwe ", - E.e_eot, ack_reason, tpcb->tp_sent_uwe, 0); - ENDTRACE - - if ( ack_reason == ACK_DONT ) { - IncStat( ts_ackreason[ACK_DONT] ); - return 0; - } else { - IFPERF(tpcb) - if(ack_reason & ACK_STRAT_EACH) { - IncPStat(tpcb, tps_n_ack_cuz_strat); - } else if(ack_reason & ACK_STRAT_FULLWIN) { - IncPStat(tpcb, tps_n_ack_cuz_fullwin); - } else if(ack_reason & ACK_REORDER) { - IncPStat(tpcb, tps_n_ack_cuz_reorder); - } - tpmeas(tpcb->tp_lref, TPtime_ack_sent, 0, - SEQ_ADD(tpcb, E.e_seq, 1), 0, 0); - ENDPERF - { - register int i; - - /* keep track of all reasons that apply */ - for( i=1; i<_ACK_NUM_REASONS_ ;i++) { - if( ack_reason & (1<tp_rsycnt) { - for (mp == tpcb->tp_rsyq + tpcb->tp_maxlcredit; - --mp >= tpcb->tp_rsyq; ) - if (*mp) { - tpcb->tp_rsycnt--; - m_freem(*mp); - } - if (tpcb->tp_rsycnt) { - printf("tp_rsyflush %x\n", tpcb); - tpcb->tp_rsycnt = 0; - } - } - FREE((caddr_t)tpcb->tp_rsyq, M_PCB); - tpcb->tp_rsyq = 0; -} - -tp_rsyset(tpcb) -register struct tp_pcb *tpcb; -{ - register struct socket *so = tpcb->tp_sock; - int maxcredit = tpcb->tp_xtd_format ? 0xffff : 0xf; - int old_credit = tpcb->tp_maxlcredit; - caddr_t rsyq; - - tpcb->tp_maxlcredit = maxcredit = min(maxcredit, - (so->so_rcv.sb_hiwat + tpcb->tp_l_tpdusize)/ tpcb->tp_l_tpdusize); - - if (old_credit == tpcb->tp_maxlcredit && tpcb->tp_rsyq != 0) - return; - maxcredit *= sizeof(struct mbuf *); - if (tpcb->tp_rsyq) - tp_rsyflush(tpcb); -// if (rsyq = (caddr_t)malloc(maxcredit, M_PCB, M_NOWAIT)) - MALLOC(rsyq, caddr_t, maxcredit, M_PCB, M_NOWAIT); - if (rsyq) - bzero(rsyq, maxcredit); - tpcb->tp_rsyq = (struct mbuf **)rsyq; -} - -tpsbcheck(tpcb, i) -struct tp_pcb *tpcb; -{ - register struct mbuf *n, *m; - register int len = 0, mbcnt = 0, pktlen; - struct sockbuf *sb = &tpcb->tp_sock->so_snd; - - for (n = sb->sb_mb; n; n = n->m_nextpkt) { - if ((n->m_flags & M_PKTHDR) == 0) - panic("tpsbcheck nohdr"); - pktlen = len + n->m_pkthdr.len; - for (m = n; m; m = m->m_next) { - len += m->m_len; - mbcnt += MSIZE; - if (m->m_flags & M_EXT) - mbcnt += m->m_ext.ext_size; - } - if (len != pktlen) { - printf("test %d; len %d != pktlen %d on mbuf 0x%x\n", - i, len, pktlen, n); - panic("tpsbcheck short"); - } - } - if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) { - printf("test %d: cc %d != %d || mbcnt %d != %d\n", i, len, sb->sb_cc, - mbcnt, sb->sb_mbcnt); - panic("tpsbcheck"); - } -} diff --git a/bsd/netiso/tp_subr2.c b/bsd/netiso/tp_subr2.c deleted file mode 100644 index 755552db5..000000000 --- a/bsd/netiso/tp_subr2.c +++ /dev/null @@ -1,898 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)tp_subr2.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * ARGO TP - * - * Some auxiliary routines: - * tp_protocol_error: required by xebec- called when a combo of state, - * event, predicate isn't covered for by the transition file. - * tp_indicate: gives indications(signals) to the user process - * tp_getoptions: initializes variables that are affected by the options - * chosen. - */ - -/* this def'n is to cause the expansion of this macro in the - * routine tp_local_credit : - */ -#define LOCAL_CREDIT_EXPAND - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#undef MNULL -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#ifdef TRUE -#undef FALSE -#undef TRUE -#endif -#include -#include -#include - -void tp_rsyset(); - -/* - * NAME: tp_local_credit() - * - * CALLED FROM: - * tp_emit(), tp_usrreq() - * - * FUNCTION and ARGUMENTS: - * Computes the local credit and stashes it in tpcb->tp_lcredit. - * It's a macro in the production system rather than a procdure. - * - * RETURNS: - * - * SIDE EFFECTS: - * - * NOTES: - * This doesn't actually get called in a production system - - * the macro gets expanded instead in place of calls to this proc. - * But for debugging, we call this and that allows us to add - * debugging messages easily here. - */ -void -tp_local_credit(tpcb) - struct tp_pcb *tpcb; -{ - LOCAL_CREDIT(tpcb); - IFDEBUG(D_CREDIT) - printf("ref 0x%x lcdt 0x%x l_tpdusize 0x%x decbit 0x%x\n", - tpcb->tp_lref, - tpcb->tp_lcredit, - tpcb->tp_l_tpdusize, - tpcb->tp_decbit, - tpcb->tp_cong_win - ); - ENDDEBUG - IFTRACE(D_CREDIT) - tptraceTPCB(TPPTmisc, - "lcdt tpdusz \n", - tpcb->tp_lcredit, tpcb->tp_l_tpdusize, 0, 0); - ENDTRACE -} - -/* - * NAME: tp_protocol_error() - * - * CALLED FROM: - * tp_driver(), when it doesn't know what to do with - * a combo of event, state, predicate - * - * FUNCTION and ARGUMENTS: - * print error mesg - * - * RETURN VALUE: - * EIO - always - * - * SIDE EFFECTS: - * - * NOTES: - */ -int -tp_protocol_error(e,tpcb) - struct tp_event *e; - struct tp_pcb *tpcb; -{ - printf("TP PROTOCOL ERROR! tpcb 0x%x event 0x%x, state 0x%x\n", - tpcb, e->ev_number, tpcb->tp_state); - IFTRACE(D_DRIVER) - tptraceTPCB(TPPTmisc, "PROTOCOL ERROR tpcb event state", - tpcb, e->ev_number, tpcb->tp_state, 0 ); - ENDTRACE - return EIO; /* for lack of anything better */ -} - - -/* Not used at the moment */ -ProtoHook -tp_drain() -{ - return 0; -} - - -/* - * NAME: tp_indicate() - * - * CALLED FROM: - * tp.trans when XPD arrive, when a connection is being disconnected by - * the arrival of a DR or ER, and when a connection times out. - * - * FUNCTION and ARGUMENTS: - * (ind) is the type of indication : T_DISCONNECT, T_XPD - * (error) is an E* value that will be put in the socket structure - * to be passed along to the user later. - * Gives a SIGURG to the user process or group indicated by the socket - * attached to the tpcb. - * - * RETURNS: Rien - * - * SIDE EFFECTS: - * - * NOTES: - */ -void -tp_indicate(ind, tpcb, error) - int ind; - u_short error; - register struct tp_pcb *tpcb; -{ - register struct socket *so = tpcb->tp_sock; - IFTRACE(D_INDICATION) - tptraceTPCB(TPPTindicate, ind, *(u_short *)(tpcb->tp_lsuffix), - *(u_short *)(tpcb->tp_fsuffix), error,so->so_pgid); - ENDTRACE - IFDEBUG(D_INDICATION) - char *ls, *fs; - ls = tpcb->tp_lsuffix, - fs = tpcb->tp_fsuffix, - - printf( -"indicate 0x%x lsuf 0x%02x%02x fsuf 0x%02x%02x err 0x%x noind 0x%x ref 0x%x\n", - ind, - *ls, *(ls+1), *fs, *(fs+1), - error, /*so->so_pgrp,*/ - tpcb->tp_no_disc_indications, - tpcb->tp_lref); - ENDDEBUG - - if (ind == ER_TPDU) { - register struct mbuf *m; - struct tp_disc_reason x; - - if ((so->so_state & SS_CANTRCVMORE) == 0 && - (m = m_get(M_DONTWAIT, MT_OOBDATA)) != 0) { - - x.dr_hdr.cmsg_len = m->m_len = sizeof(x); - x.dr_hdr.cmsg_level = SOL_TRANSPORT; - x.dr_hdr.cmsg_type= TPOPT_DISC_REASON; - x.dr_reason = error; - *mtod(m, struct tp_disc_reason *) = x; - sbappendrecord(&tpcb->tp_Xrcv, m); - error = 0; - } else - error = ECONNRESET; - } - so->so_error = error; - - if (ind == T_DISCONNECT) { - if (error == 0) - so->so_error = ENOTCONN; - if ( tpcb->tp_no_disc_indications ) - return; - } - IFTRACE(D_INDICATION) - tptraceTPCB(TPPTmisc, "doing sohasoutofband(so)", so,0,0,0); - ENDTRACE - sohasoutofband(so); -} - -/* - * NAME : tp_getoptions() - * - * CALLED FROM: - * tp.trans whenever we go into OPEN state - * - * FUNCTION and ARGUMENTS: - * sets the proper flags and values in the tpcb, to control - * the appropriate actions for the given class, options, - * sequence space, etc, etc. - * - * RETURNS: Nada - * - * SIDE EFFECTS: - * - * NOTES: - */ -void -tp_getoptions(tpcb) -struct tp_pcb *tpcb; -{ - tpcb->tp_seqmask = - tpcb->tp_xtd_format ? TP_XTD_FMT_MASK : TP_NML_FMT_MASK ; - tpcb->tp_seqbit = - tpcb->tp_xtd_format ? TP_XTD_FMT_BIT : TP_NML_FMT_BIT ; - tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1; - tpcb->tp_dt_ticks = - max(tpcb->tp_dt_ticks, (tpcb->tp_peer_acktime + 2)); - tp_rsyset(tpcb); - -} - -/* - * NAME: tp_recycle_tsuffix() - * - * CALLED FROM: - * Called when a ref is frozen. - * - * FUNCTION and ARGUMENTS: - * allows the suffix to be reused. - * - * RETURNS: zilch - * - * SIDE EFFECTS: - * - * NOTES: - */ -void -tp_recycle_tsuffix(tpcb) - struct tp_pcb *tpcb; -{ - bzero((caddr_t)tpcb->tp_lsuffix, sizeof( tpcb->tp_lsuffix)); - bzero((caddr_t)tpcb->tp_fsuffix, sizeof( tpcb->tp_fsuffix)); - tpcb->tp_fsuffixlen = tpcb->tp_lsuffixlen = 0; - - (tpcb->tp_nlproto->nlp_recycle_suffix)(tpcb->tp_npcb); -} - -/* - * NAME: tp_quench() - * - * CALLED FROM: - * tp{af}_quench() when ICMP source quench or similar thing arrives. - * - * FUNCTION and ARGUMENTS: - * Drop the congestion window back to 1. - * Congestion window scheme: - * Initial value is 1. ("slow start" as Nagle, et. al. call it) - * For each good ack that arrives, the congestion window is increased - * by 1 (up to max size of logical infinity, which is to say, - * it doesn't wrap around). - * Source quench causes it to drop back to 1. - * tp_send() uses the smaller of (regular window, congestion window). - * One retransmission strategy option is to have any retransmission - * cause reset the congestion window back to 1. - * - * (cmd) is either PRC_QUENCH: source quench, or - * PRC_QUENCH2: dest. quench (dec bit) - * - * RETURNS: - * - * SIDE EFFECTS: - * - * NOTES: - */ -void -tp_quench( tpcb, cmd ) - struct tp_pcb *tpcb; - int cmd; -{ - IFDEBUG(D_QUENCH) - printf("tp_quench tpcb 0x%x ref 0x%x sufx 0x%x\n", - tpcb, tpcb->tp_lref, *(u_short *)(tpcb->tp_lsuffix)); - printf("cong_win 0x%x decbit 0x%x \n", - tpcb->tp_cong_win, tpcb->tp_decbit); - ENDDEBUG - switch(cmd) { - case PRC_QUENCH: - tpcb->tp_cong_win = tpcb->tp_l_tpdusize; - IncStat(ts_quench); - break; - case PRC_QUENCH2: - tpcb->tp_cong_win = tpcb->tp_l_tpdusize; /* might as well quench source also */ - tpcb->tp_decbit = TP_DECBIT_CLEAR_COUNT; - IncStat(ts_rcvdecbit); - break; - } -} - - -/* - * NAME: tp_netcmd() - * - * CALLED FROM: - * - * FUNCTION and ARGUMENTS: - * - * RETURNS: - * - * SIDE EFFECTS: - * - * NOTES: - */ -tp_netcmd( tpcb, cmd ) - struct tp_pcb *tpcb; - int cmd; -{ -#if TPCONS - struct isopcb *isop; - struct pklcd *lcp; - - if (tpcb->tp_netservice != ISO_CONS) - return; - isop = (struct isopcb *)tpcb->tp_npcb; - lcp = (struct pklcd *)isop->isop_chan; - switch (cmd) { - - case CONN_CLOSE: - case CONN_REFUSE: - if (isop->isop_refcnt == 1) { - /* This is really superfluous, since it would happen - anyway in iso_pcbdetach, although it is a courtesy - to free up the x.25 channel before the refwait timer - expires. */ - lcp->lcd_upper = 0; - lcp->lcd_upnext = 0; - pk_disconnect(lcp); - isop->isop_chan = 0; - isop->isop_refcnt = 0; - } - break; - - default: - printf("tp_netcmd(0x%x, 0x%x) NOT IMPLEMENTED\n", tpcb, cmd); - break; - } -#else /* TPCONS */ - printf("tp_netcmd(): X25 NOT CONFIGURED!!\n"); -#endif -} -/* - * CALLED FROM: - * tp_ctloutput() and tp_emit() - * FUNCTION and ARGUMENTS: - * Convert a class mask to the highest numeric value it represents. - */ - -int -tp_mask_to_num(x) - u_char x; -{ - register int j; - - for(j = 4; j>=0 ;j--) { - if(x & (1<p_tpdusize = src->p_tpdusize; - dst->p_ack_strat = src->p_ack_strat; - dst->p_rx_strat = src->p_rx_strat; -#undef COPYSIZE -} -/* - * Determine a reasonable value for maxseg size. - * If the route is known, check route for mtu. - * 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. - */ -void -tp_mss(tpcb, nhdr_size) - register struct tp_pcb *tpcb; - int nhdr_size; -{ - register struct rtentry *rt; - struct ifnet *ifp; - register int rtt, mss; - u_long bufsize; - int i, ssthresh = 0, rt_mss; - struct socket *so; - - if (tpcb->tp_ptpdusize) - mss = tpcb->tp_ptpdusize << 7; - else - mss = 1 << tpcb->tp_tpdusize; - so = tpcb->tp_sock; - if ((rt = *(tpcb->tp_routep)) == 0) { - bufsize = so->so_rcv.sb_hiwat; - goto punt_route; - } - ifp = rt->rt_ifp; - -#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 hz ticks for the smoothed timers and slow-timeout units - * for other inital variables. - */ - if (tpcb->tp_rtt == 0 && (rtt = rt->rt_rmx.rmx_rtt)) { - tpcb->tp_rtt = rtt * hz / RTM_RTTUNIT; - if (rt->rt_rmx.rmx_rttvar) - tpcb->tp_rtv = rt->rt_rmx.rmx_rttvar - * hz / RTM_RTTUNIT; - else - tpcb->tp_rtv = tpcb->tp_rtt; - } - /* - * if there's an mtu associated with the route, use it - */ - if (rt->rt_rmx.rmx_mtu) - rt_mss = rt->rt_rmx.rmx_mtu - nhdr_size; - else -#endif /* RTV_MTU */ - rt_mss = (ifp->if_mtu - nhdr_size); - if (tpcb->tp_ptpdusize == 0 || /* assume application doesn't care */ - mss > rt_mss /* network won't support what was asked for */) - mss = rt_mss; - /* can propose mtu which are multiples of 128 */ - mss &= ~0x7f; - /* - * If there's a pipesize, change the socket buffer - * to that size. - */ -#ifdef RTV_SPIPE - if ((bufsize = rt->rt_rmx.rmx_sendpipe) > 0) { -#endif - bufsize = min(bufsize, so->so_snd.sb_hiwat); - (void) sbreserve(&so->so_snd, bufsize); - } -#ifdef RTV_SPIPE - if ((bufsize = rt->rt_rmx.rmx_recvpipe) > 0) { -#endif - bufsize = min(bufsize, so->so_rcv.sb_hiwat); - (void) sbreserve(&so->so_rcv, bufsize); - } else - bufsize = so->so_rcv.sb_hiwat; -#ifdef RTV_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. - */ - ssthresh = rt->rt_rmx.rmx_ssthresh; -punt_route: - /* - * The current mss 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. - * If we received an offer, don't exceed it. - * However, do not accept offers under 128 bytes. - */ - if (tpcb->tp_l_tpdusize) - mss = min(mss, tpcb->tp_l_tpdusize); - /* - * We want a minimum recv window of 4 packets to - * signal packet loss by duplicate acks. - */ - mss = min(mss, bufsize >> 2) & ~0x7f; - mss = max(mss, 128); /* sanity */ - tpcb->tp_cong_win = - (rt == 0 || (rt->rt_flags & RTF_GATEWAY)) ? mss : bufsize; - tpcb->tp_l_tpdusize = mss; - tp_rsyset(tpcb); - tpcb->tp_ssthresh = max(2 * mss, ssthresh); - /* Calculate log2 of mss */ - for (i = TP_MIN_TPDUSIZE + 1; i <= TP_MAX_TPDUSIZE; i++) - if ((1 << i) > mss) - break; - i--; - tpcb->tp_tpdusize = i; -#endif /* RTV_MTU */ -} - -/* - * CALLED FROM: - * tp_usrreq on PRU_CONNECT and tp_input on receipt of CR - * - * FUNCTION and ARGUMENTS: - * -- An mbuf containing the peer's network address. - * -- Our control block, which will be modified - * -- In the case of cons, a control block for that layer. - * - * - * RETURNS: - * errno value : - * EAFNOSUPPORT if can't find an nl_protosw for x.25 (really could panic) - * ECONNREFUSED if trying to run TP0 with non-type 37 address - * possibly other E* returned from cons_netcmd() - * - * SIDE EFFECTS: - * Determines recommended tpdusize, buffering and intial delays - * based on information cached on the route. - */ -int -tp_route_to( m, tpcb, channel) - struct mbuf *m; - register struct tp_pcb *tpcb; - caddr_t channel; -{ - register struct sockaddr_iso *siso; /* NOTE: this may be a sockaddr_in */ - extern struct tp_conn_param tp_conn_param[]; - int error = 0, save_netservice = tpcb->tp_netservice; - register struct rtentry *rt = 0; - int nhdr_size, mtu, bufsize; - - siso = mtod(m, struct sockaddr_iso *); - IFTRACE(D_CONN) - tptraceTPCB(TPPTmisc, - "route_to: so afi netservice class", - tpcb->tp_sock, siso->siso_addr.isoa_genaddr[0], tpcb->tp_netservice, - tpcb->tp_class); - ENDTRACE - IFDEBUG(D_CONN) - printf("tp_route_to( m x%x, channel 0x%x, tpcb 0x%x netserv 0x%x)\n", - m, channel, tpcb, tpcb->tp_netservice); - printf("m->mlen x%x, m->m_data:\n", m->m_len); - dump_buf(mtod(m, caddr_t), m->m_len); - ENDDEBUG - if (channel) { -#if TPCONS - struct pklcd *lcp = (struct pklcd *)channel; - struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext, - *isop_new = (struct isopcb *)tpcb->tp_npcb; - /* The next 2 lines believe that you haven't - set any network level options or done a pcbconnect - and XXXXXXX'edly apply to both inpcb's and isopcb's */ - remque(isop_new); - FREE(isop_new, M_PCB); - tpcb->tp_npcb = (caddr_t)isop; - tpcb->tp_netservice = ISO_CONS; - tpcb->tp_nlproto = nl_protosw + ISO_CONS; - if (isop->isop_refcnt++ == 0) { - iso_putsufx(isop, tpcb->tp_lsuffix, tpcb->tp_lsuffixlen, TP_LOCAL); - isop->isop_socket = tpcb->tp_sock; - } else - /* there are already connections sharing this */; -#endif - } else { - switch (siso->siso_family) { - default: - error = EAFNOSUPPORT; - goto done; -#if ISO - case AF_ISO: - { - struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; - int flags = tpcb->tp_sock->so_options & SO_DONTROUTE; - tpcb->tp_netservice = ISO_CLNS; - if (clnp_route(&siso->siso_addr, &isop->isop_route, - flags, (void **)0, (void **)0) == 0) { - rt = isop->isop_route.ro_rt; - if (rt && rt->rt_flags & RTF_PROTO1) - tpcb->tp_netservice = ISO_CONS; - } - } break; -#endif -#if INET - case AF_INET: - tpcb->tp_netservice = IN_CLNS; -#endif - } - if (tpcb->tp_nlproto->nlp_afamily != siso->siso_family) { - IFDEBUG(D_CONN) - printf("tp_route_to( CHANGING nlproto old 0x%x new 0x%x)\n", - save_netservice, tpcb->tp_netservice); - ENDDEBUG - if (error = tp_set_npcb(tpcb)) - goto done; - } - IFDEBUG(D_CONN) - printf("tp_route_to calling nlp_pcbconn, netserv %d\n", - tpcb->tp_netservice); - ENDDEBUG - tpcb->tp_nlproto = nl_protosw + tpcb->tp_netservice; - error = (tpcb->tp_nlproto->nlp_pcbconn)(tpcb->tp_npcb, m); - } - if (error) - goto done; - nhdr_size = tpcb->tp_nlproto->nlp_mtu(tpcb); /* only gets common info */ - tp_mss(tpcb, nhdr_size); -done: - IFDEBUG(D_CONN) - printf("tp_route_to returns 0x%x\n", error); - ENDDEBUG - IFTRACE(D_CONN) - tptraceTPCB(TPPTmisc, "route_to: returns: error netserv class", error, - tpcb->tp_netservice, tpcb->tp_class, 0); - ENDTRACE - return error; -} - - -/* class zero version */ -void -tp0_stash( tpcb, e ) - register struct tp_pcb *tpcb; - register struct tp_event *e; -{ -#ifndef lint -#define E e->ATTR(DT_TPDU) -#else /* lint */ -#define E e->ev_union.EV_DT_TPDU -#endif /* lint */ - - register struct sockbuf *sb = &tpcb->tp_sock->so_rcv; - register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; - - IFPERF(tpcb) - PStat(tpcb, Nb_from_ll) += E.e_datalen; - tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time, - E.e_seq, PStat(tpcb, Nb_from_ll), E.e_datalen); - ENDPERF - - IFDEBUG(D_STASH) - printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x", - E.e_seq, E.e_datalen, E.e_eot); - ENDDEBUG - - IFTRACE(D_STASH) - tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", - E.e_seq, E.e_datalen, E.e_eot, 0); - ENDTRACE - - if ( E.e_eot ) { - register struct mbuf *n = E.e_data; - n->m_flags |= M_EOR; - n->m_act = MNULL; /* set on tp_input */ - } - sbappend(sb, E.e_data); - IFDEBUG(D_STASH) - dump_mbuf(sb->sb_mb, "stash 0: so_rcv after appending"); - ENDDEBUG - if (tpcb->tp_netservice != ISO_CONS) - printf("tp0_stash: tp running over something wierd\n"); - else { - register struct pklcd *lcp = (struct pklcd *)isop->isop_chan; - pk_flowcontrol(lcp, sbspace(sb) <= 0, 1); - } -} - -void -tp0_openflow(tpcb) -register struct tp_pcb *tpcb; -{ - register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; - if (tpcb->tp_netservice != ISO_CONS) - printf("tp0_openflow: tp running over something wierd\n"); - else { - register struct pklcd *lcp = (struct pklcd *)isop->isop_chan; - if (lcp->lcd_rxrnr_condition) - pk_flowcontrol(lcp, 0, 0); - } -} -#ifndef TPCONS -static -pk_flowcontrol() {} -#endif - -#ifdef TP_PERF_MEAS -/* - * CALLED FROM: - * tp_ctloutput() when the user sets TPOPT_PERF_MEAS on - * and tp_newsocket() when a new connection is made from - * a listening socket with tp_perf_on == true. - * FUNCTION and ARGUMENTS: - * (tpcb) is the usual; this procedure gets a clear cluster mbuf for - * a tp_pmeas structure, and makes tpcb->tp_p_meas point to it. - * RETURN VALUE: - * ENOBUFS if it cannot get a cluster mbuf. - */ - -int -tp_setup_perf(tpcb) - register struct tp_pcb *tpcb; -{ - register struct mbuf *q; - - if( tpcb->tp_p_meas == 0 ) { - MGET(q, M_WAIT, MT_PCB); - if (q == 0) - return ENOBUFS; - MCLGET(q, M_WAIT); - if ((q->m_flags & M_EXT) == 0) { - (void) m_free(q); - return ENOBUFS; - } - q->m_len = sizeof (struct tp_pmeas); - tpcb->tp_p_mbuf = q; - tpcb->tp_p_meas = mtod(q, struct tp_pmeas *); - bzero( (caddr_t)tpcb->tp_p_meas, sizeof (struct tp_pmeas) ); - IFDEBUG(D_PERF_MEAS) - printf( - "tpcb 0x%x so 0x%x ref 0x%x tp_p_meas 0x%x tp_perf_on 0x%x\n", - tpcb, tpcb->tp_sock, tpcb->tp_lref, - tpcb->tp_p_meas, tpcb->tp_perf_on); - ENDDEBUG - tpcb->tp_perf_on = 1; - } - return 0; -} -#endif /* TP_PERF_MEAS */ - -#ifdef ARGO_DEBUG -dump_addr (addr) - register struct sockaddr *addr; -{ - switch( addr->sa_family ) { - case AF_INET: - dump_inaddr((struct sockaddr_in *)addr); - break; -#if ISO - case AF_ISO: - dump_isoaddr((struct sockaddr_iso *)addr); - break; -#endif /* ISO */ - default: - printf("BAD AF: 0x%x\n", addr->sa_family); - break; - } -} - -#define MAX_COLUMNS 8 -/* - * Dump the buffer to the screen in a readable format. Format is: - * - * hex/dec where hex is the hex format, dec is the decimal format. - * columns of hex/dec numbers will be printed, followed by the - * character representations (if printable). - */ -Dump_buf(buf, len) -caddr_t buf; -int len; -{ - int i,j; -#define Buf ((u_char *)buf) - printf("Dump buf 0x%x len 0x%x\n", buf, len); - for (i = 0; i < len; i += MAX_COLUMNS) { - printf("+%d:\t", i); - for (j = 0; j < MAX_COLUMNS; j++) { - if (i + j < len) { - printf("%x/%d\t", Buf[i+j], Buf[i+j]); - } else { - printf(" "); - } - } - - for (j = 0; j < MAX_COLUMNS; j++) { - if (i + j < len) { - if (((Buf[i+j]) > 31) && ((Buf[i+j]) < 128)) - printf("%c", Buf[i+j]); - else - printf("."); - } - } - printf("\n"); - } -} -#endif /* ARGO_DEBUG */ diff --git a/bsd/netiso/tp_timer.c b/bsd/netiso/tp_timer.c deleted file mode 100644 index 34c2738d9..000000000 --- a/bsd/netiso/tp_timer.c +++ /dev/null @@ -1,397 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)tp_timer.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * ARGO TP - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -struct tp_ref *tp_ref; -int tp_rttdiv, tp_rttadd, N_TPREF = 127; -struct tp_refinfo tp_refinfo; -struct tp_pcb *tp_ftimeolist = (struct tp_pcb *)&tp_ftimeolist; - -/* - * CALLED FROM: - * at autoconfig time from tp_init() - * a combo of event, state, predicate - * FUNCTION and ARGUMENTS: - * initialize data structures for the timers - */ -void -tp_timerinit() -{ - register int s; - /* - * Initialize storage - */ - if (tp_refinfo.tpr_base) - return; - tp_refinfo.tpr_size = N_TPREF + 1; /* Need to start somewhere */ - s = sizeof(*tp_ref) * tp_refinfo.tpr_size; -// if ((tp_ref = (struct tp_ref *) malloc(s, M_PCB, M_NOWAIT)) == 0) - MALLOC(tp_ref, struct tp_ref *, s, M_PCB, M_NOWAIT); - if (tp_ref == 0) - panic("tp_timerinit"); - bzero((caddr_t)tp_ref, (unsigned) s); - tp_refinfo.tpr_base = tp_ref; - tp_rttdiv = hz / PR_SLOWHZ; - tp_rttadd = (2 * tp_rttdiv) - 1; -} -#ifdef TP_DEBUG_TIMERS -/********************** e timers *************************/ - -/* - * CALLED FROM: - * tp.trans all over - * FUNCTION and ARGUMENTS: - * Set an E type timer. - */ -void -tp_etimeout(tpcb, fun, ticks) - register struct tp_pcb *tpcb; - int fun; /* function to be called */ - int ticks; -{ - - register u_int *callp; - IFDEBUG(D_TIMER) - printf("etimeout pcb 0x%x state 0x%x\n", tpcb, tpcb->tp_state); - ENDDEBUG - IFTRACE(D_TIMER) - tptrace(TPPTmisc, "tp_etimeout ref refstate tks Etick", tpcb->tp_lref, - tpcb->tp_state, ticks, tp_stat.ts_Eticks); - ENDTRACE - if (tpcb == 0) - return; - IncStat(ts_Eset); - if (ticks == 0) - ticks = 1; - callp = tpcb->tp_timer + fun; - if (*callp == 0 || *callp > ticks) - *callp = ticks; -} - -/* - * CALLED FROM: - * tp.trans all over - * FUNCTION and ARGUMENTS: - * Cancel all occurrences of E-timer function (fun) for reference (refp) - */ -void -tp_euntimeout(tpcb, fun) - register struct tp_pcb *tpcb; - int fun; -{ - IFTRACE(D_TIMER) - tptrace(TPPTmisc, "tp_euntimeout ref", tpcb->tp_lref, 0, 0, 0); - ENDTRACE - - if (tpcb) - tpcb->tp_timer[fun] = 0; -} - -/**************** c timers ********************** - * - * These are not chained together; they sit - * in the tp_ref structure. they are the kind that - * are typically cancelled so it's faster not to - * mess with the chains - */ -#endif -/* - * CALLED FROM: - * the clock, every 500 ms - * FUNCTION and ARGUMENTS: - * Look for open references with active timers. - * If they exist, call the appropriate timer routines to update - * the timers and possibly generate events. - */ -ProtoHook -tp_slowtimo() -{ - register u_int *cp; - register struct tp_ref *rp; - struct tp_pcb *tpcb; - struct tp_event E; - int s = splnet(), t; - - /* check only open reference structures */ - IncStat(ts_Cticks); - /* tp_ref[0] is never used */ - for (rp = tp_ref + tp_refinfo.tpr_maxopen; rp > tp_ref; rp--) { - if ((tpcb = rp->tpr_pcb) == 0 || tpcb->tp_refstate < REF_OPEN) - continue; - /* check the timers */ - for (t = 0; t < TM_NTIMERS; t++) { - cp = tpcb->tp_timer + t; - if (*cp && --(*cp) <= 0 ) { - *cp = 0; - E.ev_number = t; - IFDEBUG(D_TIMER) - printf("tp_slowtimo: pcb 0x%x t %d\n", - tpcb, t); - ENDDEBUG - IncStat(ts_Cexpired); - tp_driver(tpcb, &E); - if (t == TM_reference && tpcb->tp_state == TP_CLOSED) { - if (tpcb->tp_notdetached) { - IFDEBUG(D_CONN) - printf("PRU_DETACH: not detached\n"); - ENDDEBUG - tp_detach(tpcb); - } - /* XXX wart; where else to do it? */ - FREE((caddr_t)tpcb, M_PCB); - } - } - } - } - splx(s); - return 0; -} - -/* - * Called From: tp.trans from tp_slowtimo() -- retransmission timer went off. - */ -tp_data_retrans(tpcb) -register struct tp_pcb *tpcb; -{ - int rexmt, win; - tpcb->tp_rttemit = 0; /* cancel current round trip time */ - tpcb->tp_dupacks = 0; - tpcb->tp_sndnxt = tpcb->tp_snduna; - if (tpcb->tp_fcredit == 0) { - /* - * We transmitted new data, started timing it and the window - * got shrunk under us. This can only happen if all data - * that they wanted us to send got acked, so don't - * bother shrinking the congestion windows, et. al. - * The retransmission timer should have been reset in goodack() - */ - IFDEBUG(D_ACKRECV) - printf("tp_data_retrans: 0 window tpcb 0x%x una 0x%x\n", - tpcb, tpcb->tp_snduna); - ENDDEBUG - tpcb->tp_rxtshift = 0; - tpcb->tp_timer[TM_data_retrans] = 0; - tpcb->tp_timer[TM_sendack] = tpcb->tp_dt_ticks; - return; - } - rexmt = tpcb->tp_dt_ticks << min(tpcb->tp_rxtshift, TP_MAXRXTSHIFT); - win = min(tpcb->tp_fcredit, (tpcb->tp_cong_win / tpcb->tp_l_tpdusize / 2)); - win = max(win, 2); - tpcb->tp_cong_win = tpcb->tp_l_tpdusize; /* slow start again. */ - tpcb->tp_ssthresh = win * tpcb->tp_l_tpdusize; - /* We're losing; our srtt estimate is probably bogus. - * Clobber it so we'll take the next rtt measurement as our srtt; - * Maintain current rxt times until then. - */ - if (++tpcb->tp_rxtshift > TP_NRETRANS / 4) { - /* tpcb->tp_nlprotosw->nlp_losing(tpcb->tp_npcb) someday */ - tpcb->tp_rtt = 0; - } - TP_RANGESET(tpcb->tp_rxtcur, rexmt, tpcb->tp_peer_acktime, 128); - tpcb->tp_timer[TM_data_retrans] = tpcb->tp_rxtcur; - tp_send(tpcb); -} - -int -tp_fasttimo() -{ - register struct tp_pcb *t; - int s = splnet(); - struct tp_event E; - - E.ev_number = TM_sendack; - while ((t = tp_ftimeolist) != (struct tp_pcb *)&tp_ftimeolist) { - if (t == 0) { - printf("tp_fasttimeo: should panic"); - tp_ftimeolist = (struct tp_pcb *)&tp_ftimeolist; - } else { - if (t->tp_flags & TPF_DELACK) { - IncStat(ts_Fdelack); - tp_driver(t, &E); - t->tp_flags &= ~TPF_DELACK; - } else - IncStat(ts_Fpruned); - tp_ftimeolist = t->tp_fasttimeo; - t->tp_fasttimeo = 0; - } - } - splx(s); -} - -#ifdef TP_DEBUG_TIMERS -/* - * CALLED FROM: - * tp.trans, tp_emit() - * FUNCTION and ARGUMENTS: - * Set a C type timer of type (which) to go off after (ticks) time. - */ -void -tp_ctimeout(tpcb, which, ticks) - register struct tp_pcb *tpcb; - int which, ticks; -{ - - IFTRACE(D_TIMER) - tptrace(TPPTmisc, "tp_ctimeout ref which tpcb active", - tpcb->tp_lref, which, tpcb, tpcb->tp_timer[which]); - ENDTRACE - if(tpcb->tp_timer[which]) - IncStat(ts_Ccan_act); - IncStat(ts_Cset); - if (ticks <= 0) - ticks = 1; - tpcb->tp_timer[which] = ticks; -} - -/* - * CALLED FROM: - * tp.trans - * FUNCTION and ARGUMENTS: - * Version of tp_ctimeout that resets the C-type time if the - * parameter (ticks) is > the current value of the timer. - */ -void -tp_ctimeout_MIN(tpcb, which, ticks) - register struct tp_pcb *tpcb; - int which, ticks; -{ - IFTRACE(D_TIMER) - tptrace(TPPTmisc, "tp_ctimeout_MIN ref which tpcb active", - tpcb->tp_lref, which, tpcb, tpcb->tp_timer[which]); - ENDTRACE - IncStat(ts_Cset); - if (tpcb->tp_timer[which]) { - tpcb->tp_timer[which] = min(ticks, tpcb->tp_timer[which]); - IncStat(ts_Ccan_act); - } else - tpcb->tp_timer[which] = ticks; -} - -/* - * CALLED FROM: - * tp.trans - * FUNCTION and ARGUMENTS: - * Cancel the (which) timer in the ref structure indicated by (refp). - */ -void -tp_cuntimeout(tpcb, which) - register struct tp_pcb *tpcb; - int which; -{ - IFDEBUG(D_TIMER) - printf("tp_cuntimeout(0x%x, %d) active %d\n", - tpcb, which, tpcb->tp_timer[which]); - ENDDEBUG - - IFTRACE(D_TIMER) - tptrace(TPPTmisc, "tp_cuntimeout ref which, active", refp-tp_ref, - which, tpcb->tp_timer[which], 0); - ENDTRACE - - if (tpcb->tp_timer[which]) - IncStat(ts_Ccan_act); - else - IncStat(ts_Ccan_inact); - tpcb->tp_timer[which] = 0; -} -#endif diff --git a/bsd/netiso/tp_timer.h b/bsd/netiso/tp_timer.h deleted file mode 100644 index f2b364c38..000000000 --- a/bsd/netiso/tp_timer.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)tp_timer.h 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * ARGO TP - * - * ARGO TP - * The callout structures used by the tp timers. - */ - -#ifndef __TP_TIMER__ -#define __TP_TIMER__ - -#define SET_DELACK(t) {\ - (t)->tp_flags |= TPF_DELACK; \ - if ((t)->tp_fasttimeo == 0)\ - { (t)->tp_fasttimeo = tp_ftimeolist; tp_ftimeolist = (t); } } - -#ifdef ARGO_DEBUG -#define TP_DEBUG_TIMERS -#endif - -#ifndef TP_DEBUG_TIMERS -#define tp_ctimeout(tpcb, which, timo) ((tpcb)->tp_timer[which] = (timo)) -#define tp_cuntimeout(tpcb, which) ((tpcb)->tp_timer[which] = 0) -#define tp_etimeout tp_ctimeout -#define tp_euntimeout tp_cuntimeout -#define tp_ctimeout_MIN(p, w, t) \ - { if((p)->tp_timer[w] > (t)) (p)->tp_timer[w] = (t);} -#endif /* TP_DEBUG_TIMERS */ - -#endif /* __TP_TIMER__ */ diff --git a/bsd/netiso/tp_tpdu.h b/bsd/netiso/tp_tpdu.h deleted file mode 100644 index a94ea8fbc..000000000 --- a/bsd/netiso/tp_tpdu.h +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)tp_tpdu.h 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * ARGO TP - * - * This ghastly set of macros makes it possible to - * refer to tpdu structures without going mad. - */ - -#ifndef __TP_TPDU__ -#define __TP_TPDU__ - -#ifndef BYTE_ORDER -/* - * Definitions for byte order, - * according to byte significance from low address to high. - */ -#define LITTLE_ENDIAN 1234 /* least-significant byte first (vax) */ -#define BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */ -#define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp) */ - -#ifdef vax -#define BYTE_ORDER LITTLE_ENDIAN -#else -#define BYTE_ORDER BIG_ENDIAN /* mc68000, tahoe, most others */ -#endif -#endif /* BYTE_ORDER */ - -/* This much of a tpdu is the same for all types of tpdus (except - * DT tpdus in class 0; their exceptions are handled by the data - * structure below - */ -struct tpdu_fixed { - u_char _tpduf_li:8, /* length indicator */ -#if BYTE_ORDER == LITTLE_ENDIAN - _tpduf_cdt: 4, /* credit */ - _tpduf_type: 4; /* type of tpdu (DT, CR, etc.) */ -#endif -#if BYTE_ORDER == BIG_ENDIAN - _tpduf_type: 4, /* type of tpdu (DT, CR, etc.) */ - _tpduf_cdt: 4; /* credit */ -#endif - u_short _tpduf_dref; /* destination ref; not in DT in class 0 */ -}; - -#define tpdu_li _tpduf._tpduf_li -#define tpdu_type _tpduf._tpduf_type -#define tpdu_cdt _tpduf._tpduf_cdt -#define tpdu_dref _tpduf._tpduf_dref - -struct tp0du { - u_char _tp0_li, - _tp0_cdt_type, /* same as in tpdu_fixed */ -#if BYTE_ORDER == BIG_ENDIAN - _tp0_eot: 1, /* eot */ - _tp0_mbz: 7, /* must be zero */ -#endif -#if BYTE_ORDER == LITTLE_ENDIAN - _tp0_mbz: 7, /* must be zero */ - _tp0_eot: 1, /* eot */ -#endif - _tp0_notused: 8; /* data begins on this octet */ -}; - -#define tp0du_eot _tp0_eot -#define tp0du_mbz _tp0_mbz - -/* - * This is used when the extended format seqence numbers are - * being sent and received. - */ - /* - * the seqeot field is an int that overlays the seq - * and eot fields, this allows the htonl operation - * to be applied to the entire 32 bit quantity, and - * simplifies the structure definitions. - */ -union seq_type { - struct { -#if BYTE_ORDER == BIG_ENDIAN - unsigned int st_eot:1, /* end-of-tsdu */ - st_seq:31; /* 31 bit sequence number */ -#endif -#if BYTE_ORDER == LITTLE_ENDIAN - unsigned int st_seq:31, /* 31 bit sequence number */ - st_eot:1; /* end-of-tsdu */ -#endif - } st; - unsigned int s_seqeot; -#define s_eot st.st_eot -#define s_seq st.st_seq -}; - -/* Then most tpdu types have a portion that is always present but - * differs among the tpdu types : - */ -union tpdu_fixed_rest { - - struct { - u_short _tpdufr_sref, /* source reference */ -#if BYTE_ORDER == BIG_ENDIAN - _tpdufr_class: 4, /* class [ ISO 8073 13.3.3.e ] */ - _tpdufr_opt: 4, /* options [ ISO 8073 13.3.3.e ] */ -#endif -#if BYTE_ORDER == LITTLE_ENDIAN - _tpdufr_opt: 4, /* options [ ISO 8073 13.3.3.e ] */ - _tpdufr_class: 4, /* class [ ISO 8073 13.3.3.e ] */ -#endif - _tpdufr_xx: 8; /* unused */ - } CRCC; - -#define tpdu_CRli _tpduf._tpduf_li -#define tpdu_CRtype _tpduf._tpduf_type -#define tpdu_CRcdt _tpduf._tpduf_cdt -#define tpdu_CRdref_0 _tpduf._tpduf_dref -#define tpdu_CRsref _tpdufr.CRCC._tpdufr_sref -#define tpdu_sref _tpdufr.CRCC._tpdufr_sref -#define tpdu_CRclass _tpdufr.CRCC._tpdufr_class -#define tpdu_CRoptions _tpdufr.CRCC._tpdufr_opt - -#define tpdu_CCli _tpduf._tpduf_li -#define tpdu_CCtype _tpduf._tpduf_type -#define tpdu_CCcdt _tpduf._tpduf_cdt -#define tpdu_CCdref _tpduf._tpduf_dref -#define tpdu_CCsref _tpdufr.CRCC._tpdufr_sref -#define tpdu_CCclass _tpdufr.CRCC._tpdufr_class -#define tpdu_CCoptions _tpdufr.CRCC._tpdufr_opt - -/* OPTIONS and ADDL OPTIONS bits */ -#define TPO_USE_EFC 0x1 -#define TPO_XTD_FMT 0x2 -#define TPAO_USE_TXPD 0x1 -#define TPAO_NO_CSUM 0x2 -#define TPAO_USE_RCC 0x4 -#define TPAO_USE_NXPD 0x8 - - struct { - unsigned short _tpdufr_sref; /* source reference */ - unsigned char _tpdufr_reason; /* [ ISO 8073 13.5.3.d ] */ - } DR; -#define tpdu_DRli _tpduf._tpduf_li -#define tpdu_DRtype _tpduf._tpduf_type -#define tpdu_DRdref _tpduf._tpduf_dref -#define tpdu_DRsref _tpdufr.DR._tpdufr_sref -#define tpdu_DRreason _tpdufr.DR._tpdufr_reason - - unsigned short _tpdufr_sref; /* source reference */ - -#define tpdu_DCli _tpduf._tpduf_li -#define tpdu_DCtype _tpduf._tpduf_type -#define tpdu_DCdref _tpduf._tpduf_dref -#define tpdu_DCsref _tpdufr._tpdufr_sref - - struct { -#if BYTE_ORDER == BIG_ENDIAN - unsigned char _tpdufr_eot:1, /* end-of-tsdu */ - _tpdufr_seq:7; /* 7 bit sequence number */ -#endif -#if BYTE_ORDER == LITTLE_ENDIAN - unsigned char _tpdufr_seq:7, /* 7 bit sequence number */ - _tpdufr_eot:1; /* end-of-tsdu */ -#endif - }SEQEOT; - struct { -#if BYTE_ORDER == BIG_ENDIAN - unsigned int _tpdufr_Xeot:1, /* end-of-tsdu */ - _tpdufr_Xseq:31; /* 31 bit sequence number */ -#endif -#if BYTE_ORDER == LITTLE_ENDIAN - unsigned int _tpdufr_Xseq:31, /* 31 bit sequence number */ - _tpdufr_Xeot:1; /* end-of-tsdu */ -#endif - }SEQEOT31; - unsigned int _tpdufr_Xseqeot; -#define tpdu_seqeotX _tpdufr._tpdufr_Xseqeot - -#define tpdu_DTli _tpduf._tpduf_li -#define tpdu_DTtype _tpduf._tpduf_type -#define tpdu_DTdref _tpduf._tpduf_dref -#define tpdu_DTseq _tpdufr.SEQEOT._tpdufr_seq -#define tpdu_DTeot _tpdufr.SEQEOT._tpdufr_eot -#define tpdu_DTseqX _tpdufr.SEQEOT31._tpdufr_Xseq -#define tpdu_DTeotX _tpdufr.SEQEOT31._tpdufr_Xeot - -#define tpdu_XPDli _tpduf._tpduf_li -#define tpdu_XPDtype _tpduf._tpduf_type -#define tpdu_XPDdref _tpduf._tpduf_dref -#define tpdu_XPDseq _tpdufr.SEQEOT._tpdufr_seq -#define tpdu_XPDeot _tpdufr.SEQEOT._tpdufr_eot -#define tpdu_XPDseqX _tpdufr.SEQEOT31._tpdufr_Xseq -#define tpdu_XPDeotX _tpdufr.SEQEOT31._tpdufr_Xeot - - struct { -#if BYTE_ORDER == BIG_ENDIAN - unsigned _tpdufr_yrseq0:1, /* always zero */ - _tpdufr_yrseq:31; /* [ ISO 8073 13.9.3.d ] */ -#endif -#if BYTE_ORDER == LITTLE_ENDIAN - unsigned _tpdufr_yrseq:31, /* [ ISO 8073 13.9.3.d ] */ - _tpdufr_yrseq0:1; /* always zero */ -#endif - unsigned short _tpdufr_cdt; /* [ ISO 8073 13.9.3.b ] */ - } AK31; - -#define tpdu_AKli _tpduf._tpduf_li -#define tpdu_AKtype _tpduf._tpduf_type -#define tpdu_AKdref _tpduf._tpduf_dref -#define tpdu_AKseq _tpdufr.SEQEOT._tpdufr_seq -#define tpdu_AKseqX _tpdufr.AK31._tpdufr_yrseq -/* location of cdt depends on size of seq. numbers */ -#define tpdu_AKcdt _tpduf._tpduf_cdt -#define tpdu_AKcdtX _tpdufr.AK31._tpdufr_cdt - -#define tpdu_XAKli _tpduf._tpduf_li -#define tpdu_XAKtype _tpduf._tpduf_type -#define tpdu_XAKdref _tpduf._tpduf_dref -#define tpdu_XAKseq _tpdufr.SEQEOT._tpdufr_seq -#define tpdu_XAKseqX _tpdufr.SEQEOT31._tpdufr_Xseq - - unsigned char _tpdu_ERreason; /* [ ISO 8073 13.12.3.c ] */ - -#define tpdu_ERli _tpduf._tpduf_li -#define tpdu_ERtype _tpduf._tpduf_type -#define tpdu_ERdref _tpduf._tpduf_dref -#define tpdu_ERreason _tpdufr._tpdu_ERreason - -}; - -struct tpdu { - struct tpdu_fixed _tpduf; - union tpdu_fixed_rest _tpdufr; -}; - -#endif /* __TP_TPDU__ */ diff --git a/bsd/netiso/tp_trace.c b/bsd/netiso/tp_trace.c deleted file mode 100644 index a2d2f689c..000000000 --- a/bsd/netiso/tp_trace.c +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)tp_trace.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * ARGO TP - * - * The whole protocol trace module. - * We keep a circular buffer of trace structures, which are big - * unions of different structures we might want to see. - * Unfortunately this gets too big pretty easily. Pcbs were removed - * from the tracing when the kernel got too big to boot. - */ - -#define TP_TRACEFILE - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef TPPT -static tp_seq = 0; -u_char tp_traceflags[128]; - -/* - * The argument tpcb is the obvious. - * event here is just the type of trace event - TPPTmisc, etc. - * The rest of the arguments have different uses depending - * on the type of trace event. - */ -/*ARGSUSED*/ -/*VARARGS*/ - -void -tpTrace(tpcb, event, arg, src, len, arg4, arg5) - struct tp_pcb *tpcb; - u_int event, arg; - u_int src; - u_int len; - u_int arg4; - u_int arg5; -{ - register struct tp_Trace *tp; - - tp = &tp_Trace[tp_Tracen++]; - tp_Tracen %= TPTRACEN; - - tp->tpt_event = event; - tp->tpt_tseq = tp_seq++; - tp->tpt_arg = arg; - if(tpcb) - tp->tpt_arg2 = tpcb->tp_lref; - bcopy( (caddr_t)&time, (caddr_t)&tp->tpt_time, sizeof(struct timeval) ); - - switch(event) { - - case TPPTertpdu: - bcopy((caddr_t)src, (caddr_t)&tp->tpt_ertpdu, - (unsigned)MIN((int)len, sizeof(struct tp_Trace))); - break; - - case TPPTusrreq: - case TPPTmisc: - - /* arg is a string */ - bcopy((caddr_t)arg, (caddr_t)tp->tpt_str, - (unsigned)MIN(1+strlen((caddr_t) arg), TPTRACE_STRLEN)); - tp->tpt_m2 = src; - tp->tpt_m3 = len; - tp->tpt_m4 = arg4; - tp->tpt_m1 = arg5; - break; - - case TPPTgotXack: - case TPPTXack: - case TPPTsendack: - case TPPTgotack: - case TPPTack: - case TPPTindicate: - default: - case TPPTdriver: - tp->tpt_m2 = arg; - tp->tpt_m3 = src; - tp->tpt_m4 = len; - tp->tpt_m5 = arg4; - tp->tpt_m1 = arg5; - break; - case TPPTparam: - bcopy((caddr_t)src, (caddr_t)&tp->tpt_param, sizeof(struct tp_param)); - break; - case TPPTref: - bcopy((caddr_t)src, (caddr_t)&tp->tpt_ref, sizeof(struct tp_ref)); - break; - - case TPPTtpduin: - case TPPTtpduout: - tp->tpt_arg2 = arg4; - bcopy((caddr_t)src, (caddr_t)&tp->tpt_tpdu, - (unsigned)MIN((int)len, sizeof(struct tp_Trace))); - break; - } -} -#endif /* TPPT */ diff --git a/bsd/netiso/tp_trace.h b/bsd/netiso/tp_trace.h deleted file mode 100644 index 1e5d96aa1..000000000 --- a/bsd/netiso/tp_trace.h +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)tp_trace.h 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * ARGO TP - * - * Definitions needed for the protocol trace mechanism. - */ - -#ifndef __TP_TRACE__ -#define __TP_TRACE__ - - -#define TPPTsendack 1 -#define TPPTgotack 2 -#define TPPTXack 3 -#define TPPTgotXack 4 -#define TPPTack 5 -#define TPPTindicate 6 -#define TPPTusrreq 7 -#define TPPTmisc 8 -#define TPPTpcb 9 -#define TPPTref 10 -#define TPPTtpduin 11 -#define TPPTparam 12 -#define TPPTertpdu 13 -#define TPPTdriver 14 -#define TPPTtpduout 15 - -#include - -/* this #if is to avoid lint */ - -#if defined(TP_TRACEFILE)||!defined(KERNEL) - -#include - -#define TPTRACE_STRLEN 50 - - -/* for packet tracing */ -struct tp_timeval { - SeqNum tptv_seq; - u_int tptv_kind; - u_int tptv_window; - u_int tptv_size; -}; - -struct tp_Trace { - u_int tpt_event; - u_int tpt_arg; - u_int tpt_arg2; - int tpt_tseq; - struct timeval tpt_time; - union { - struct inpcb tpt_Inpcb; /* protocol control block */ - struct tp_ref tpt_Ref; /* ref part of pcb */ - struct tpdu tpt_Tpdu; /* header*/ - struct tp_refinfo tpt_Param; /* ?? bytes, make sure < 128??*/ - struct tp_timeval tpt_Time; - struct { - u_int tptm_2; - u_int tptm_3; - u_int tptm_4; - u_int tptm_5; - char tpt_Str[TPTRACE_STRLEN]; - u_int tptm_1; - } tptmisc; - u_char tpt_Ertpdu; /* use rest of structure */ - } tpt_stuff; -}; -#define tpt_inpcb tpt_stuff.tpt_Inpcb -#define tpt_pcb tpt_stuff.tpt_Pcb -#define tpt_ref tpt_stuff.tpt_Ref -#define tpt_tpdu tpt_stuff.tpt_Tpdu -#define tpt_param tpt_stuff.tpt_Param -#define tpt_ertpdu tpt_stuff.tpt_Ertpdu -#define tpt_str tpt_stuff.tptmisc.tpt_Str -#define tpt_m1 tpt_stuff.tptmisc.tptm_1 -#define tpt_m2 tpt_stuff.tptmisc.tptm_2 -#define tpt_m3 tpt_stuff.tptmisc.tptm_3 -#define tpt_m4 tpt_stuff.tptmisc.tptm_4 -#define tpt_m5 tpt_stuff.tptmisc.tptm_5 - -#define tpt_seq tpt_stuff.tpt_Time.tptv_seq -#define tpt_kind tpt_stuff.tpt_Time.tptv_kind -#define tpt_window tpt_stuff.tpt_Time.tptv_window -#define tpt_size tpt_stuff.tpt_Time.tptv_size - -#endif /* defined(TP_TRACEFILE)||!defined(KERNEL) */ - - -#ifdef TPPT - -#define TPTRACEN 300 - -#define tptrace(A,B,C,D,E,F) \ - tpTrace((struct tp_pcb *)0,\ - (u_int)(A),(u_int)(B),(u_int)(C),(u_int)(D),(u_int)(E),(u_int)(F)) - -#define tptraceTPCB(A,B,C,D,E,F) \ - tpTrace(tpcb,\ - (u_int)(A),(u_int)(B),(u_int)(C),(u_int)(D),(u_int)(E),(u_int)(F)) - -extern void tpTrace(); -extern struct tp_Trace tp_Trace[]; -extern u_char tp_traceflags[]; -int tp_Tracen = 0; - -#define IFTRACE(ascii)\ - if(tp_traceflags[ascii]) { -/* - * for some reason lint complains about tp_param being undefined no - * matter where or how many times I define it. - */ -#define ENDTRACE } - - -#else /* TPPT */ - -/*********************************************** - * NO TPPT TRACE STUFF - **********************************************/ -#define TPTRACEN 1 - -#define tptrace(A,B,C,D,E,F) 0 -#define tptraceTPCB(A,B,C,D,E,F) 0 - -#define IFTRACE(ascii) if (0) { -#define ENDTRACE } - -#endif /* TPPT */ - - - -#endif /* __TP_TRACE__ */ diff --git a/bsd/netiso/tp_user.h b/bsd/netiso/tp_user.h deleted file mode 100644 index 2468ee10e..000000000 --- a/bsd/netiso/tp_user.h +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)tp_user.h 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * ARGO TP - * - * These are the values a real-live user ;-) needs. - */ - -#ifndef _TYPES_ -#include -#endif - -#ifndef __TP_USER__ -#define __TP_USER__ - -struct tp_conn_param { - /* PER CONNECTION parameters */ - short p_Nretrans; - short p_dr_ticks; - - short p_cc_ticks; - short p_dt_ticks; - - short p_x_ticks; - short p_cr_ticks; - - short p_keepalive_ticks; - short p_sendack_ticks; - - short p_ref_ticks; - short p_inact_ticks; - - short p_ptpdusize; /* preferred tpdusize/128 */ - short p_winsize; - - u_char p_tpdusize; /* log 2 of size */ - - u_char p_ack_strat; /* see comments in tp_pcb.h */ - u_char p_rx_strat; /* see comments in tp_pcb.h */ - u_char p_class; /* class bitmask */ - u_char p_xtd_format; - u_char p_xpd_service; - u_char p_use_checksum; - u_char p_use_nxpd; /* netwk expedited data: not implemented */ - u_char p_use_rcc; /* receipt confirmation: not implemented */ - u_char p_use_efc; /* explicit flow control: not implemented */ - u_char p_no_disc_indications; /* don't deliver indic on disc */ - u_char p_dont_change_params; /* use these params as they are */ - u_char p_netservice; - u_char p_version; /* only here for checking */ -}; - -/* - * These sockopt level definitions should be considered for socket.h - */ -#define SOL_TRANSPORT 0xfffe -#define SOL_NETWORK 0xfffd - -/* get/set socket opt commands */ -#define TPACK_WINDOW 0x0 /* ack only on full window */ -#define TPACK_EACH 0x1 /* ack every packet */ - -#define TPRX_USE_CW 0x8 /* use congestion window transmit */ -#define TPRX_EACH 0x4 /* retrans each packet of a set */ -#define TPRX_FASTSTART 0x1 /* don't use slow start */ - -#define TPOPT_INTERCEPT 0x200 -#define TPOPT_FLAGS 0x300 -#define TPOPT_CONN_DATA 0x400 -#define TPOPT_DISC_DATA 0x500 -#define TPOPT_CFRM_DATA 0x600 -#define TPOPT_CDDATA_CLEAR 0x700 -#define TPOPT_MY_TSEL 0x800 -#define TPOPT_PEER_TSEL 0x900 -#define TPOPT_PERF_MEAS 0xa00 -#define TPOPT_PSTATISTICS 0xb00 -#define TPOPT_PARAMS 0xc00 /* to replace a bunch of the others */ -#define TPOPT_DISC_REASON 0xe00 - -struct tp_disc_reason { - struct cmsghdr dr_hdr; - u_int dr_reason; -}; - -/* - ***********************flags********************************** - */ - -/* read only flags */ -#define TPFLAG_NLQOS_PDN (u_char)0x01 -#define TPFLAG_PEER_ON_SAMENET (u_char)0x02 -#define TPFLAG_GENERAL_ADDR (u_char)0x04 /* bound to wildcard addr */ - - -/* - ***********************end flags****************************** - */ - - -#endif /* __TP_USER__ */ diff --git a/bsd/netiso/tp_usrreq.c b/bsd/netiso/tp_usrreq.c deleted file mode 100644 index 984d52791..000000000 --- a/bsd/netiso/tp_usrreq.c +++ /dev/null @@ -1,774 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * 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. - * - * @(#)tp_usrreq.c 8.1 (Berkeley) 6/10/93 - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * ARGO TP - * - * tp_usrreq(), the fellow that gets called from most of the socket code. - * Pretty straighforward. - * THe only really awful stuff here is the OOB processing, which is done - * wholly here. - * tp_rcvoob() and tp_sendoob() are contained here and called by tp_usrreq(). - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int tp_attach(), tp_driver(), tp_pcbbind(); -int TNew; -int TPNagle1, TPNagle2; -struct tp_pcb *tp_listeners, *tp_intercepts; - -#ifdef ARGO_DEBUG -/* - * CALLED FROM: - * anywhere you want to debug... - * FUNCTION and ARGUMENTS: - * print (str) followed by the control info in the mbufs of an mbuf chain (n) - */ -void -dump_mbuf(n, str) - struct mbuf *n; - char *str; -{ - struct mbuf *nextrecord; - - printf("dump %s\n", str); - - if (n == MNULL) { - printf("EMPTY:\n"); - return; - } - - while (n) { - nextrecord = n->m_act; - printf("RECORD:\n"); - while (n) { - printf("%x : Len %x Data %x A %x Nx %x Tp %x\n", - n, n->m_len, n->m_data, n->m_act, n->m_next, n->m_type); -#ifdef notdef - { - register char *p = mtod(n, char *); - register int i; - - printf("data: "); - for (i = 0; i < n->m_len; i++) { - if (i%8 == 0) - printf("\n"); - printf("0x%x ", *(p+i)); - } - printf("\n"); - } -#endif /* notdef */ - if (n->m_next == n) { - printf("LOOP!\n"); - return; - } - n = n->m_next; - } - n = nextrecord; - } - printf("\n"); -} - -#endif /* ARGO_DEBUG */ - -/* - * CALLED FROM: - * tp_usrreq(), PRU_RCVOOB - * FUNCTION and ARGUMENTS: - * Copy data from the expedited data socket buffer into - * the pre-allocated mbuf m. - * There is an isomorphism between XPD TPDUs and expedited data TSDUs. - * XPD tpdus are limited to 16 bytes of data so they fit in one mbuf. - * RETURN VALUE: - * EINVAL if debugging is on and a disaster has occurred - * ENOTCONN if the socket isn't connected - * EWOULDBLOCK if the socket is in non-blocking mode and there's no - * xpd data in the buffer - * E* whatever is returned from the fsm. - */ -tp_rcvoob(tpcb, so, m, outflags, inflags) - struct tp_pcb *tpcb; - register struct socket *so; - register struct mbuf *m; - int *outflags; - int inflags; -{ - register struct mbuf *n; - register struct sockbuf *sb = &so->so_rcv; - struct tp_event E; - int error = 0; - register struct mbuf **nn; - - IFDEBUG(D_XPD) - printf("PRU_RCVOOB, sostate 0x%x\n", so->so_state); - ENDDEBUG - - /* if you use soreceive */ - if (m == MNULL) - return ENOBUFS; - -restart: - if ((((so->so_state & SS_ISCONNECTED) == 0) - || (so->so_state & SS_ISDISCONNECTING) != 0) && - (so->so_proto->pr_flags & PR_CONNREQUIRED)) { - return ENOTCONN; - } - - /* Take the first mbuf off the chain. - * Each XPD TPDU gives you a complete TSDU so the chains don't get - * coalesced, but one TSDU may span several mbufs. - * Nevertheless, since n should have a most 16 bytes, it - * will fit into m. (size was checked in tp_input() ) - */ - - /* - * Code for excision of OOB data should be added to - * uipc_socket2.c (like sbappend). - */ - - sblock(sb, M_WAIT); - for (nn = &sb->sb_mb; n = *nn; nn = &n->m_act) - if (n->m_type == MT_OOBDATA) - break; - - if (n == 0) { - IFDEBUG(D_XPD) - printf("RCVOOB: empty queue!\n"); - ENDDEBUG - sbunlock(sb); - if (so->so_state & SS_NBIO) { - return EWOULDBLOCK; - } - sbwait(sb); - goto restart; - } - m->m_len = 0; - - /* Assuming at most one xpd tpdu is in the buffer at once */ - while (n != MNULL) { - m->m_len += n->m_len; - bcopy(mtod(n, caddr_t), mtod(m, caddr_t), (unsigned)n->m_len); - m->m_data += n->m_len; /* so mtod() in bcopy() above gives right addr */ - n = n->m_next; - } - m->m_data = m->m_dat; - m->m_flags |= M_EOR; - - IFDEBUG(D_XPD) - printf("tp_rcvoob: xpdlen 0x%x\n", m->m_len); - dump_mbuf(so->so_rcv.sb_mb, "RCVOOB: Rcv socketbuf"); - dump_mbuf(sb->sb_mb, "RCVOOB: Xrcv socketbuf"); - ENDDEBUG - - if ((inflags & MSG_PEEK) == 0) { - n = *nn; - *nn = n->m_act; - for (; n; n = m_free(n)) - sbfree(sb, n); - } - -release: - sbunlock(sb); - - IFTRACE(D_XPD) - tptraceTPCB(TPPTmisc, "PRU_RCVOOB @ release sb_cc m_len", - tpcb->tp_Xrcv.sb_cc, m->m_len, 0, 0); - ENDTRACE - if (error == 0) - error = DoEvent(T_USR_Xrcvd); - return error; -} - -/* - * CALLED FROM: - * tp_usrreq(), PRU_SENDOOB - * FUNCTION and ARGUMENTS: - * Send what's in the mbuf chain (m) as an XPD TPDU. - * The mbuf may not contain more then 16 bytes of data. - * XPD TSDUs aren't segmented, so they translate into - * exactly one XPD TPDU, with EOT bit set. - * RETURN VALUE: - * EWOULDBLOCK if socket is in non-blocking mode and the previous - * xpd data haven't been acked yet. - * EMSGSIZE if trying to send > max-xpd bytes (16) - * ENOBUFS if ran out of mbufs - */ -tp_sendoob(tpcb, so, xdata, outflags) - struct tp_pcb *tpcb; - register struct socket *so; - register struct mbuf *xdata; - int *outflags; /* not used */ -{ - /* - * Each mbuf chain represents a sequence # in the XPD seq space. - * The first one in the queue has sequence # tp_Xuna. - * When we add to the XPD queue, we stuff a zero-length - * mbuf (mark) into the DATA queue, with its sequence number in m_next - * to be assigned to this XPD tpdu, so data xfer can stop - * when it reaches the zero-length mbuf if this XPD TPDU hasn't - * yet been acknowledged. - */ - register struct sockbuf *sb = &(tpcb->tp_Xsnd); - register struct mbuf *xmark; - register int len=0; - struct tp_event E; - - IFDEBUG(D_XPD) - printf("tp_sendoob:"); - if (xdata) - printf("xdata len 0x%x\n", xdata->m_len); - ENDDEBUG - /* DO NOT LOCK the Xsnd buffer!!!! You can have at MOST one - * socket buf locked at any time!!! (otherwise you might - * sleep() in sblock() w/ a signal pending and cause the - * system call to be aborted w/ a locked socketbuf, which - * is a problem. So the so_snd buffer lock - * (done in sosend()) serves as the lock for Xpd. - */ - if (sb->sb_mb) { /* Anything already in eXpedited data sockbuf? */ - if (so->so_state & SS_NBIO) { - return EWOULDBLOCK; - } - while (sb->sb_mb) { - sbunlock(&so->so_snd); /* already locked by sosend */ - sbwait(&so->so_snd); - sblock(&so->so_snd, M_WAIT); /* sosend will unlock on return */ - } - } - - if (xdata == (struct mbuf *)0) { - /* empty xpd packet */ - MGETHDR(xdata, M_WAIT, MT_OOBDATA); - if (xdata == NULL) { - return ENOBUFS; - } - xdata->m_len = 0; - xdata->m_pkthdr.len = 0; - } - IFDEBUG(D_XPD) - printf("tp_sendoob 1:"); - if (xdata) - printf("xdata len 0x%x\n", xdata->m_len); - ENDDEBUG - xmark = xdata; /* temporary use of variable xmark */ - while (xmark) { - len += xmark->m_len; - xmark = xmark->m_next; - } - if (len > TP_MAX_XPD_DATA) { - return EMSGSIZE; - } - IFDEBUG(D_XPD) - printf("tp_sendoob 2:"); - if (xdata) - printf("xdata len 0x%x\n", len); - ENDDEBUG - - - IFTRACE(D_XPD) - tptraceTPCB(TPPTmisc, "XPD mark m_next ", xdata->m_next, 0, 0, 0); - ENDTRACE - - sbappendrecord(sb, xdata); - - IFDEBUG(D_XPD) - printf("tp_sendoob len 0x%x\n", len); - dump_mbuf(so->so_snd.sb_mb, "XPD request Regular sndbuf:"); - dump_mbuf(tpcb->tp_Xsnd.sb_mb, "XPD request Xsndbuf:"); - ENDDEBUG - return DoEvent(T_XPD_req); -} - -/* - * CALLED FROM: - * the socket routines - * FUNCTION and ARGUMENTS: - * Handles all "user requests" except the [gs]ockopts() requests. - * The argument (req) is the request type (PRU*), - * (m) is an mbuf chain, generally used for send and - * receive type requests only. - * (nam) is used for addresses usually, in particular for the bind request. - * - */ -/*ARGSUSED*/ -ProtoHook -tp_usrreq(so, req, m, nam, controlp) - struct socket *so; - u_int req; - struct mbuf *m, *nam, *controlp; -{ - register struct tp_pcb *tpcb = sototpcb(so); - int s = splnet(); - int error = 0; - int flags, *outflags = &flags; - u_long eotsdu = 0; - struct tp_event E; - - IFDEBUG(D_REQUEST) - printf("usrreq(0x%x,%d,0x%x,0x%x,0x%x)\n",so,req,m,nam,outflags); - if (so->so_error) - printf("WARNING!!! so->so_error is 0x%x\n", so->so_error); - ENDDEBUG - IFTRACE(D_REQUEST) - tptraceTPCB(TPPTusrreq, "req so m state [", req, so, m, - tpcb?tpcb->tp_state:0); - ENDTRACE - - if ((u_int)tpcb == 0 && req != PRU_ATTACH) { - IFTRACE(D_REQUEST) - tptraceTPCB(TPPTusrreq, "req failed NO TPCB[", 0, 0, 0, 0); - ENDTRACE - splx(s); - return ENOTCONN; - } - - switch (req) { - - case PRU_ATTACH: - if (tpcb) { - error = EISCONN; - } else if ((error = tp_attach(so, (int)nam)) == 0) - tpcb = sototpcb(so); - break; - - case PRU_ABORT: /* called from close() */ - /* called for each incoming connect queued on the - * parent (accepting) socket - */ - if (tpcb->tp_state == TP_OPEN || tpcb->tp_state == TP_CONFIRMING) { - E.ATTR(T_DISC_req).e_reason = E_TP_NO_SESSION; - error = DoEvent(T_DISC_req); /* pretend it was a close() */ - break; - } /* else DROP THROUGH */ - - case PRU_DETACH: /* called from close() */ - /* called only after disconnect was called */ - error = DoEvent(T_DETACH); - if (tpcb->tp_state == TP_CLOSED) { - if (tpcb->tp_notdetached) { - IFDEBUG(D_CONN) - printf("PRU_DETACH: not detached\n"); - ENDDEBUG - tp_detach(tpcb); - } - FREE((caddr_t)tpcb, M_PCB); - tpcb = 0; - } - break; - - case PRU_SHUTDOWN: - /* recv end may have been released; local credit might be zero */ - case PRU_DISCONNECT: - E.ATTR(T_DISC_req).e_reason = E_TP_NORMAL_DISC; - error = DoEvent(T_DISC_req); - break; - - case PRU_BIND: - error = tp_pcbbind(tpcb, nam); - break; - - case PRU_LISTEN: - if (tpcb->tp_state != TP_CLOSED || tpcb->tp_lsuffixlen == 0 || - tpcb->tp_next == 0) - error = EINVAL; - else { - register struct tp_pcb **tt; - remque(tpcb); - tpcb->tp_next = tpcb->tp_prev = tpcb; - for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten)) - if ((*tt)->tp_lsuffixlen) - break; - tpcb->tp_nextlisten = *tt; - *tt = tpcb; - error = DoEvent(T_LISTEN_req); - } - break; - - case PRU_CONNECT2: - error = EOPNOTSUPP; /* for unix domain sockets */ - break; - - case PRU_CONNECT: - IFTRACE(D_CONN) - tptraceTPCB(TPPTmisc, - "PRU_CONNECT: so 0x%x *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x", - tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen, - tpcb->tp_class); - ENDTRACE - IFDEBUG(D_CONN) - printf("PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x", - tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen, - tpcb->tp_class); - ENDDEBUG - if (tpcb->tp_lsuffixlen == 0) { - if (error = tp_pcbbind(tpcb, MNULL)) { - IFDEBUG(D_CONN) - printf("pcbbind returns error 0x%x\n", error); - ENDDEBUG - break; - } - } - IFDEBUG(D_CONN) - printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb); - dump_buf(tpcb->tp_npcb, 16); - ENDDEBUG - if (error = tp_route_to(nam, tpcb, /* channel */0)) - break; - IFDEBUG(D_CONN) - printf( - "PRU_CONNECT after tpcb 0x%x so 0x%x npcb 0x%x flags 0x%x\n", - tpcb, so, tpcb->tp_npcb, tpcb->tp_flags); - printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb); - dump_buf(tpcb->tp_npcb, 16); - ENDDEBUG - if (tpcb->tp_fsuffixlen == 0) { - /* didn't set peer extended suffix */ - (tpcb->tp_nlproto->nlp_getsufx)(tpcb->tp_npcb, &tpcb->tp_fsuffixlen, - tpcb->tp_fsuffix, TP_FOREIGN); - } - if (tpcb->tp_state == TP_CLOSED) { - soisconnecting(so); - error = DoEvent(T_CONN_req); - } else { - (tpcb->tp_nlproto->nlp_pcbdisc)(tpcb->tp_npcb); - error = EISCONN; - } - IFPERF(tpcb) - u_int lsufx, fsufx; - lsufx = *(u_short *)(tpcb->tp_lsuffix); - fsufx = *(u_short *)(tpcb->tp_fsuffix); - - tpmeas(tpcb->tp_lref, - TPtime_open | (tpcb->tp_xtd_format << 4), - &time, lsufx, fsufx, tpcb->tp_fref); - ENDPERF - break; - - case PRU_ACCEPT: - (tpcb->tp_nlproto->nlp_getnetaddr)(tpcb->tp_npcb, nam, TP_FOREIGN); - IFDEBUG(D_REQUEST) - printf("ACCEPT PEERADDDR:"); - dump_buf(mtod(nam, char *), nam->m_len); - ENDDEBUG - IFPERF(tpcb) - u_int lsufx, fsufx; - lsufx = *(u_short *)(tpcb->tp_lsuffix); - fsufx = *(u_short *)(tpcb->tp_fsuffix); - - tpmeas(tpcb->tp_lref, TPtime_open, - &time, lsufx, fsufx, tpcb->tp_fref); - ENDPERF - break; - - case PRU_RCVD: - if (so->so_state & SS_ISCONFIRMING) { - if (tpcb->tp_state == TP_CONFIRMING) - error = tp_confirm(tpcb); - break; - } - IFTRACE(D_DATA) - tptraceTPCB(TPPTmisc, - "RCVD BF: lcredit sent_lcdt cc hiwat \n", - tpcb->tp_lcredit, tpcb->tp_sent_lcdt, - so->so_rcv.sb_cc, so->so_rcv.sb_hiwat); - LOCAL_CREDIT(tpcb); - tptraceTPCB(TPPTmisc, - "PRU_RCVD AF sbspace lcredit hiwat cc", - sbspace(&so->so_rcv), tpcb->tp_lcredit, - so->so_rcv.sb_cc, so->so_rcv.sb_hiwat); - ENDTRACE - IFDEBUG(D_REQUEST) - printf("RCVD: cc %d space %d hiwat %d\n", - so->so_rcv.sb_cc, sbspace(&so->so_rcv), - so->so_rcv.sb_hiwat); - ENDDEBUG - if (((int)nam) & MSG_OOB) - error = DoEvent(T_USR_Xrcvd); - else - error = DoEvent(T_USR_rcvd); - break; - - case PRU_RCVOOB: - if ((so->so_state & SS_ISCONNECTED) == 0) { - error = ENOTCONN; - break; - } - if (! tpcb->tp_xpd_service) { - error = EOPNOTSUPP; - break; - } - /* kludge - nam is really flags here */ - error = tp_rcvoob(tpcb, so, m, outflags, (int)nam); - break; - - case PRU_SEND: - case PRU_SENDOOB: - if (controlp) { - error = tp_snd_control(controlp, so, &m); - controlp = NULL; - if (error) - break; - } - if ((so->so_state & SS_ISCONFIRMING) && - (tpcb->tp_state == TP_CONFIRMING) && - (error = tp_confirm(tpcb))) - break; - if (req == PRU_SENDOOB) { - error = (tpcb->tp_xpd_service == 0) ? - EOPNOTSUPP : tp_sendoob(tpcb, so, m, outflags); - break; - } - if (m == 0) - break; - if (m->m_flags & M_EOR) { - eotsdu = 1; - m->m_flags &= ~M_EOR; - } - if (eotsdu == 0 && m->m_pkthdr.len == 0) - break; - if (tpcb->tp_state != TP_AKWAIT && tpcb->tp_state != TP_OPEN) { - error = ENOTCONN; - break; - } - /* - * The protocol machine copies mbuf chains, - * prepends headers, assigns seq numbers, and - * puts the packets on the device. - * When they are acked they are removed from the socket buf. - * - * sosend calls this up until sbspace goes negative. - * Sbspace may be made negative by appending this mbuf chain, - * possibly by a whole cluster. - */ - { - /* - * Could have eotsdu and no data.(presently MUST have - * an mbuf though, even if its length == 0) - */ - int totlen = m->m_pkthdr.len; - struct sockbuf *sb = &so->so_snd; - IFPERF(tpcb) - PStat(tpcb, Nb_from_sess) += totlen; - tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0, - PStat(tpcb, Nb_from_sess), totlen); - ENDPERF - IFDEBUG(D_SYSCALL) - printf( - "PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n", - eotsdu, m, totlen, sb); - dump_mbuf(sb->sb_mb, "so_snd.sb_mb"); - dump_mbuf(m, "m : to be added"); - ENDDEBUG - tp_packetize(tpcb, m, eotsdu); - IFDEBUG(D_SYSCALL) - printf("PRU_SEND: eot %d after sbappend 0x%x\n", eotsdu, m); - dump_mbuf(sb->sb_mb, "so_snd.sb_mb"); - ENDDEBUG - if (tpcb->tp_state == TP_OPEN) - error = DoEvent(T_DATA_req); - IFDEBUG(D_SYSCALL) - printf("PRU_SEND: after driver error 0x%x \n",error); - printf("so_snd 0x%x cc 0t%d mbcnt 0t%d\n", - sb, sb->sb_cc, sb->sb_mbcnt); - dump_mbuf(sb->sb_mb, "so_snd.sb_mb after driver"); - ENDDEBUG - } - break; - - case PRU_SOCKADDR: - (tpcb->tp_nlproto->nlp_getnetaddr)(tpcb->tp_npcb, nam, TP_LOCAL); - break; - - case PRU_PEERADDR: - (tpcb->tp_nlproto->nlp_getnetaddr)(tpcb->tp_npcb, nam, TP_FOREIGN); - break; - - case PRU_CONTROL: - error = EOPNOTSUPP; - break; - - case PRU_PROTOSEND: - case PRU_PROTORCV: - case PRU_SENSE: - case PRU_SLOWTIMO: - case PRU_FASTTIMO: - error = EOPNOTSUPP; - break; - - default: -#ifdef ARGO_DEBUG - printf("tp_usrreq UNKNOWN PRU %d\n", req); -#endif /* ARGO_DEBUG */ - error = EOPNOTSUPP; - } - - IFDEBUG(D_REQUEST) - printf("%s, so 0x%x, tpcb 0x%x, error %d, state %d\n", - "returning from tp_usrreq", so, tpcb, error, - tpcb ? tpcb->tp_state : 0); - ENDDEBUG - IFTRACE(D_REQUEST) - tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m, - tpcb ? tpcb->tp_state : 0); - ENDTRACE - if (controlp) { - m_freem(controlp); - printf("control data unexpectedly retained in tp_usrreq()"); - } - splx(s); - return error; -} -tp_ltrace(so, uio) -struct socket *so; -struct uio *uio; -{ - IFTRACE(D_DATA) - register struct tp_pcb *tpcb = sototpcb(so); - if (tpcb) { - tptraceTPCB(TPPTmisc, "sosend so resid iovcnt", so, - uio->uio_resid, uio->uio_iovcnt, 0); - } - ENDTRACE -} - -tp_confirm(tpcb) -register struct tp_pcb *tpcb; -{ - struct tp_event E; - if (tpcb->tp_state == TP_CONFIRMING) - return DoEvent(T_ACPT_req); - printf("Tp confirm called when not confirming; tpcb 0x%x, state 0x%x\n", - tpcb, tpcb->tp_state); - return 0; -} - -/* - * Process control data sent with sendmsg() - */ -tp_snd_control(m, so, data) - struct mbuf *m; - struct socket *so; - register struct mbuf **data; -{ - register struct cmsghdr *ch; - int error = 0; - - if (m && m->m_len) { - ch = mtod(m, struct cmsghdr *); - m->m_len -= sizeof (*ch); - m->m_data += sizeof (*ch); - error = tp_ctloutput(PRCO_SETOPT, - so, ch->cmsg_level, ch->cmsg_type, &m); - if (ch->cmsg_type == TPOPT_DISC_DATA) { - if (data && *data) { - m_freem(*data); - *data = 0; - } - error = tp_usrreq(so, PRU_DISCONNECT, (struct mbuf *)0, - (caddr_t)0, (struct mbuf *)0); - } - } - if (m) - m_freem(m); - return error; -} diff --git a/bsd/netiso/tuba_subr.c b/bsd/netiso/tuba_subr.c deleted file mode 100644 index 00939d742..000000000 --- a/bsd/netiso/tuba_subr.c +++ /dev/null @@ -1,369 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1992, 1993 - * 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. - * - * @(#)tuba_subr.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -static struct sockaddr_iso null_siso = { sizeof(null_siso), AF_ISO, }; -extern int tuba_table_size, tcp_keepidle, tcp_keepintvl, tcp_maxidle; -extern int tcppcbcachemiss, tcppredack, tcppreddat, tcprexmtthresh; -extern struct tcpiphdr tcp_saveti; -struct inpcb tuba_inpcb; -struct inpcb *tuba_last_inpcb = &tuba_inpcb; -struct isopcb tuba_isopcb; -/* - * Tuba initialization - */ -tuba_init() -{ -#define TUBAHDRSIZE (3 /*LLC*/ + 9 /*CLNP Fixed*/ + 42 /*Addresses*/ \ - + 6 /*CLNP Segment*/ + 20 /*TCP*/) - - tuba_inpcb.inp_next = tuba_inpcb.inp_prev = &tuba_inpcb; - tuba_isopcb.isop_next = tuba_isopcb.isop_prev = &tuba_isopcb; - tuba_isopcb.isop_faddr = &tuba_isopcb.isop_sfaddr; - tuba_isopcb.isop_laddr = &tuba_isopcb.isop_sladdr; - if (max_protohdr < TUBAHDRSIZE) - max_protohdr = TUBAHDRSIZE; - if (max_linkhdr + TUBAHDRSIZE > MHLEN) - panic("tuba_init"); -} - -struct addr_arg { - int error; - int offset; - u_long sum; -}; - -/* - * Calculate contribution to fudge factor for TCP checksum, - * and coincidentally set pointer for convenience of clnp_output - * if we are are responding when there is no isopcb around. - */ -static void -tuba_getaddr(arg, siso, index) - register struct addr_arg *arg; - struct sockaddr_iso **siso; - u_long index; -{ - register struct tuba_cache *tc; - if (index <= tuba_table_size && (tc = tuba_table[index])) { - if (siso) - *siso = &tc->tc_siso; - arg->sum += (arg->offset & 1 ? tc->tc_ssum : tc->tc_sum) - + (0xffff ^ index); - arg->offset += tc->tc_siso.siso_nlen + 1; - } else - arg->error = 1; -} - -tuba_output(m, tp) - register struct mbuf *m; - struct tcpcb *tp; -{ - register struct tcpiphdr *n; - struct isopcb *isop; - struct addr_arg arg; - - if (tp == 0 || (n = tp->t_template) == 0 || - (isop = (struct isopcb *)tp->t_tuba_pcb) == 0) { - isop = &tuba_isopcb; - n = mtod(m, struct tcpiphdr *); - arg.error = arg.sum = arg.offset = 0; - tuba_getaddr(&arg, &tuba_isopcb.isop_faddr, n->ti_dst.s_addr); - tuba_getaddr(&arg, &tuba_isopcb.isop_laddr, n->ti_src.s_addr); - REDUCE(arg.sum, arg.sum); - goto adjust; - } - if (n->ti_sum == 0) { - arg.error = arg.sum = arg.offset = 0; - tuba_getaddr(&arg, (struct sockaddr_iso **)0, n->ti_dst.s_addr); - tuba_getaddr(&arg, (struct sockaddr_iso **)0, n->ti_src.s_addr); - REDUCE(arg.sum, arg.sum); - n->ti_sum = arg.sum; - n = mtod(m, struct tcpiphdr *); - adjust: - if (arg.error) { - m_freem(m); - return (EADDRNOTAVAIL); - } - REDUCE(n->ti_sum, n->ti_sum + (0xffff ^ arg.sum)); - } - m->m_len -= sizeof (struct ip); - m->m_pkthdr.len -= sizeof (struct ip); - m->m_data += sizeof (struct ip); - return (clnp_output(m, isop, m->m_pkthdr.len, 0)); -} - -tuba_refcnt(isop, delta) - struct isopcb *isop; -{ - register struct tuba_cache *tc; - unsigned index, sum; - - if (delta != 1) - delta = -1; - if (isop == 0 || isop->isop_faddr == 0 || isop->isop_laddr == 0 || - (delta == -1 && isop->isop_tuba_cached == 0) || - (delta == 1 && isop->isop_tuba_cached != 0)) - return; - isop->isop_tuba_cached = (delta == 1); - if ((index = tuba_lookup(isop->isop_faddr, M_DONTWAIT)) != 0 && - (tc = tuba_table[index]) != 0 && (delta == 1 || tc->tc_refcnt > 0)) - tc->tc_refcnt += delta; - if ((index = tuba_lookup(isop->isop_laddr, M_DONTWAIT)) != 0 && - (tc = tuba_table[index]) != 0 && (delta == 1 || tc->tc_refcnt > 0)) - tc->tc_refcnt += delta; -} - -tuba_pcbdetach(isop) - struct isopcb *isop; -{ - if (isop == 0) - return; - tuba_refcnt(isop, -1); - isop->isop_socket = 0; - iso_pcbdetach(isop); -} - -/* - * Avoid in_pcbconnect in faked out tcp_input() - */ -tuba_pcbconnect(inp, nam) - register struct inpcb *inp; - struct mbuf *nam; -{ - register struct sockaddr_iso *siso; - struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); - struct tcpcb *tp = intotcpcb(inp); - struct isopcb *isop = (struct isopcb *)tp->t_tuba_pcb; - int error; - - /* hardwire iso_pcbbind() here */ - siso = isop->isop_laddr = &isop->isop_sladdr; - *siso = tuba_table[inp->inp_laddr.s_addr]->tc_siso; - siso->siso_tlen = sizeof(inp->inp_lport); - bcopy((caddr_t)&inp->inp_lport, TSEL(siso), sizeof(inp->inp_lport)); - - /* hardwire in_pcbconnect() here without assigning route */ - inp->inp_fport = sin->sin_port; - inp->inp_faddr = sin->sin_addr; - - /* reuse nam argument to call iso_pcbconnect() */ - nam->m_len = sizeof(*siso); - siso = mtod(nam, struct sockaddr_iso *); - *siso = tuba_table[inp->inp_faddr.s_addr]->tc_siso; - siso->siso_tlen = sizeof(inp->inp_fport); - bcopy((caddr_t)&inp->inp_fport, TSEL(siso), sizeof(inp->inp_fport)); - - if ((error = iso_pcbconnect(isop, nam)) == 0) - tuba_refcnt(isop, 1); - return (error); -} - -/* - * CALLED FROM: - * clnp's input routine, indirectly through the protosw. - * FUNCTION and ARGUMENTS: - * Take a packet (m) from clnp, strip off the clnp header - * and do tcp input processing. - * No return value. - */ -tuba_tcpinput(m, src, dst) - register struct mbuf *m; - struct sockaddr_iso *src, *dst; -{ - unsigned long sum, lindex, findex; - register struct tcpiphdr *ti; - register struct inpcb *inp; - caddr_t optp = NULL; - int optlen; - int len, tlen, off; - register struct tcpcb *tp = 0; - int tiflags; - struct socket *so; - int todrop, acked, ourfinisacked, needoutput = 0; - short ostate; - struct in_addr laddr; - int dropsocket = 0, iss = 0; - u_long tiwin, ts_val, ts_ecr; - int ts_present = 0; - - if ((m->m_flags & M_PKTHDR) == 0) - panic("tuba_tcpinput"); - /* - * Do some housekeeping looking up CLNP addresses. - * If we are out of space might as well drop the packet now. - */ - tcpstat.tcps_rcvtotal++; - lindex = tuba_lookup(dst, M_DONTWAIT); - findex = tuba_lookup(src, M_DONTWAIT); - if (lindex == 0 || findex == 0) - goto drop; - /* - * CLNP gave us an mbuf chain WITH the clnp header pulled up, - * but the data pointer pushed past it. - */ - len = m->m_len; - tlen = m->m_pkthdr.len; - m->m_data -= sizeof(struct ip); - m->m_len += sizeof(struct ip); - m->m_pkthdr.len += sizeof(struct ip); - m->m_flags &= ~(M_MCAST|M_BCAST); /* XXX should do this in clnp_input */ - /* - * The reassembly code assumes it will be overwriting a useless - * part of the packet, which is why we need to have it point - * into the packet itself. - * - * Check to see if the data is properly alligned - * so that we can save copying the tcp header. - * This code knows way too much about the structure of mbufs! - */ - off = ((sizeof (long) - 1) & ((m->m_flags & M_EXT) ? - (m->m_data - m->m_ext.ext_buf) : (m->m_data - m->m_pktdat))); - if (off || len < sizeof(struct tcphdr)) { - struct mbuf *m0 = m; - - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == 0) { - m = m0; - goto drop; - } - m->m_next = m0; - m->m_data += max_linkhdr; - m->m_pkthdr = m0->m_pkthdr; - m->m_flags = m0->m_flags & M_COPYFLAGS; - if (len < sizeof(struct tcphdr)) { - m->m_len = 0; - if ((m = m_pullup(m, sizeof(struct tcpiphdr))) == 0) { - tcpstat.tcps_rcvshort++; - return; - } - } else { - bcopy(mtod(m0, caddr_t) + sizeof(struct ip), - mtod(m, caddr_t) + sizeof(struct ip), - sizeof(struct tcphdr)); - m0->m_len -= sizeof(struct tcpiphdr); - m0->m_data += sizeof(struct tcpiphdr); - m->m_len = sizeof(struct tcpiphdr); - } - } - /* - * Calculate checksum of extended TCP header and data, - * replacing what would have been IP addresses by - * the IP checksum of the CLNP addresses. - */ - ti = mtod(m, struct tcpiphdr *); - ti->ti_dst.s_addr = tuba_table[lindex]->tc_sum; - if (dst->siso_nlen & 1) - ti->ti_src.s_addr = tuba_table[findex]->tc_sum; - else - ti->ti_src.s_addr = tuba_table[findex]->tc_ssum; - ti->ti_prev = ti->ti_next = 0; - ti->ti_x1 = 0; ti->ti_pr = ISOPROTO_TCP; - ti->ti_len = htons((u_short)tlen); - if (ti->ti_sum = in_cksum(m, m->m_pkthdr.len)) { - tcpstat.tcps_rcvbadsum++; - goto drop; - } - ti->ti_src.s_addr = findex; - ti->ti_dst.s_addr = lindex; - /* - * Now include the rest of TCP input - */ -#define TUBA_INCLUDE -#define in_pcbconnect tuba_pcbconnect -#define tcb tuba_inpcb -#define tcp_last_inpcb tuba_last_inpcb - -#include -} - -#define tcp_slowtimo tuba_slowtimo -#define tcp_fasttimo tuba_fasttimo - -#include diff --git a/bsd/netiso/tuba_table.c b/bsd/netiso/tuba_table.c deleted file mode 100644 index 3d8a005c2..000000000 --- a/bsd/netiso/tuba_table.c +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1992, 1993 - * 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. - * - * @(#)tuba_table.c 8.2 (Berkeley) 11/15/93 - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -int tuba_table_size; -struct tuba_cache **tuba_table; -struct radix_node_head *tuba_tree; -extern int arpt_keep, arpt_prune; /* use same values as arp cache */ - -void -tuba_timer() -{ - int s = splnet(); - int i; - register struct tuba_cache *tc; - long timelimit = time.tv_sec - arpt_keep; - - timeout(tuba_timer, (caddr_t)0, arpt_prune * hz); - for (i = tuba_table_size; i > 0; i--) - if ((tc = tuba_table[i]) && (tc->tc_refcnt == 0) && - (tc->tc_time < timelimit)) { - tuba_table[i] = 0; - rn_delete(&tc->tc_siso.siso_addr, NULL, tuba_tree); - FREE((caddr_t)tc, M_RTABLE); - } - splx(s); -} - -tuba_table_init() -{ - rn_inithead((void **)&tuba_tree, 40); - timeout(tuba_timer, (caddr_t)0, arpt_prune * hz); -} - -int -tuba_lookup(siso, wait) - register struct sockaddr_iso *siso; -{ - struct radix_node *rn, *rn_match(); - register struct tuba_cache *tc; - struct tuba_cache **new; - int dupentry = 0, sum_a = 0, sum_b = 0, old_size, i; - - if ((rn = rn_match((caddr_t)&siso->siso_addr, tuba_tree->rnh_treetop)) - && ((rn->rn_flags & RNF_ROOT) == 0)) { - tc = (struct tuba_cache *)rn; - tc->tc_time = time.tv_sec; - return (tc->tc_index); - } -// if ((tc = (struct tuba_cache *)malloc(sizeof(*tc), M_RTABLE, wait)) -// == NULL) - if (wait == M_DONTWAIT) - MALLOC(tc, struct tuba_cache *, sizeof(*tc), M_RTABLE, M_NOWAIT); - else - MALLOC(tc, struct tuba_cache *, sizeof(*tc), M_RTABLE, M_WAITOK); - if (tc == NULL) - return (0); - bzero((caddr_t)tc, sizeof (*tc)); - bcopy(siso->siso_data, tc->tc_siso.siso_data, - tc->tc_siso.siso_nlen = siso->siso_nlen); - rn_insert(&tc->tc_siso.siso_addr, tuba_tree, &dupentry, tc->tc_nodes); - if (dupentry) - panic("tuba_lookup 1"); - tc->tc_siso.siso_family = AF_ISO; - tc->tc_siso.siso_len = sizeof(tc->tc_siso); - tc->tc_time = time.tv_sec; - for (i = sum_a = tc->tc_siso.siso_nlen; --i >= 0; ) - (i & 1 ? sum_a : sum_b) += (u_char)tc->tc_siso.siso_data[i]; - REDUCE(tc->tc_sum, (sum_a << 8) + sum_b); - HTONS(tc->tc_sum); - SWAB(tc->tc_ssum, tc->tc_sum); - for (i = tuba_table_size; i > 0; i--) - if (tuba_table[i] == 0) - goto fixup; - old_size = tuba_table_size; - if (tuba_table_size == 0) - tuba_table_size = 15; - if (tuba_table_size > 0x7fff) - return (0); - tuba_table_size = 1 + 2 * tuba_table_size; - i = (tuba_table_size + 1) * sizeof(tc); -// new = (struct tuba_cache **)malloc((unsigned)i, M_RTABLE, wait); - if (wait == M_DONTWAIT) - MALLOC(new, struct tuba_cache **, i, M_RTABLE, M_NOWAIT); - else - MALLOC(new, struct tuba_cache **, i, M_RTABLE, M_WAITOK); - if (new == 0) { - tuba_table_size = old_size; - rn_delete(&tc->tc_siso.siso_addr, NULL, tuba_tree); - FREE((caddr_t)tc, M_RTABLE); - return (0); - } - bzero((caddr_t)new, (unsigned)i); - if (tuba_table) { - bcopy((caddr_t)tuba_table, (caddr_t)new, i >> 1); - FREE((caddr_t)tuba_table, M_RTABLE); - } - tuba_table = new; - i = tuba_table_size; -fixup: - tuba_table[i] = tc; - tc->tc_index = i; - return (tc->tc_index); -} diff --git a/bsd/netiso/tuba_table.h b/bsd/netiso/tuba_table.h deleted file mode 100644 index 9d66ef9c6..000000000 --- a/bsd/netiso/tuba_table.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1992, 1993 - * 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. - * - * @(#)tuba_table.h 8.1 (Berkeley) 6/10/93 - */ - -struct tuba_cache { - struct radix_node tc_nodes[2]; /* convenient lookup */ - int tc_refcnt; - int tc_time; /* last looked up */ - int tc_flags; -#define TCF_PERM 1 - int tc_index; - u_short tc_sum; /* cksum of nsap inc. length */ - u_short tc_ssum; /* swab(tc_sum) */ - struct sockaddr_iso tc_siso; /* for responding */ -}; - -#define ADDCARRY(x) (x >= 65535 ? x -= 65535 : x) -#define REDUCE(a, b) { union { u_short s[2]; long l;} l_util; long x; \ - l_util.l = (b); x = l_util.s[0] + l_util.s[1]; ADDCARRY(x); \ - if (x == 0) x = 0xffff; a = x;} -#define SWAB(a, b) { union { u_char c[2]; u_short s;} s; u_char t; \ - s.s = (b); t = s.c[0]; s.c[0] = s.c[1]; s.c[1] = t; a = s.s;} - -#ifdef KERNEL -extern int tuba_table_size; -extern struct tuba_cache **tuba_table; -extern struct radix_node_head *tuba_tree; -#endif diff --git a/bsd/netiso/tuba_usrreq.c b/bsd/netiso/tuba_usrreq.c deleted file mode 100644 index b3e5b60b1..000000000 --- a/bsd/netiso/tuba_usrreq.c +++ /dev/null @@ -1,333 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1992, 1993 - * 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. - * - * @(#)tuba_usrreq.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -/* - * TCP protocol interface to socket abstraction. - */ -extern char *tcpstates[]; -extern struct inpcb tuba_inpcb; -extern struct isopcb tuba_isopcb; - -/* - * 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*/ -tuba_usrreq(so, req, m, nam, control) - struct socket *so; - int req; - struct mbuf *m, *nam, *control; -{ - register struct inpcb *inp; - register struct isopcb *isop; - register struct tcpcb *tp; - int s; - int error = 0; - int ostate; - struct sockaddr_iso *siso; - - if (req == PRU_CONTROL) - return (iso_control(so, (int)m, (caddr_t)nam, - (struct ifnet *)control)); - - 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); - if (tp == 0) - panic("tuba_usrreq"); - ostate = tp->t_state; - isop = (struct isopcb *)tp->t_tuba_pcb; - if (isop == 0) - panic("tuba_usrreq 2"); - } else - ostate = 0; - switch (req) { - - /* - * TCP attaches to socket via PRU_ATTACH, reserving space, - * and an internet control block. We also need to - * allocate an isopcb and separate the control block from - * tcp/ip ones. - */ - case PRU_ATTACH: - if (error = iso_pcballoc(so, &tuba_isopcb)) - break; - isop = (struct isopcb *)so->so_pcb; - so->so_pcb = 0; - if (error = tcp_usrreq(so, req, m, nam, control)) { - isop->isop_socket = 0; - iso_pcbdetach(isop); - } else { - inp = sotoinpcb(so); - remque(inp); - insque(inp, &tuba_inpcb); - inp->inp_head = &tuba_inpcb; - tp = intotcpcb(inp); - if (tp == 0) - panic("tuba_usrreq 3"); - tp->t_tuba_pcb = (caddr_t) isop; - } - goto notrace; - - /* - * 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); - if (tp == 0) - tuba_pcbdetach(isop); - break; - - /* - * Give the socket an address. - */ - case PRU_BIND: - siso = mtod(nam, struct sockaddr_iso *); - if (siso->siso_tlen && siso->siso_tlen != 2) { - error = EINVAL; - break; - } - if ((error = iso_pcbbind(isop, nam)) || - (siso = isop->isop_laddr) == 0) - break; - bcopy(TSEL(siso), &inp->inp_lport, 2); - if (siso->siso_nlen && - !(inp->inp_laddr.s_addr = tuba_lookup(siso, M_WAITOK))) - error = ENOBUFS; - break; - - /* - * Prepare to accept connections. - */ - case PRU_CONNECT: - case PRU_LISTEN: - if (inp->inp_lport == 0 && - (error = iso_pcbbind(isop, (struct mbuf *)0))) - break; - bcopy(TSEL(isop->isop_laddr), &inp->inp_lport, 2); - if (req == PRU_LISTEN) { - tp->t_state = TCPS_LISTEN; - break; - } - /*FALLTHROUGH*/ - /* - * 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 (error = iso_pcbconnect(isop, nam)) - break; - if ((siso = isop->isop_laddr) && siso->siso_nlen > 1) - siso->siso_data[siso->siso_nlen - 1] = ISOPROTO_TCP; - else - panic("tuba_usrreq: connect"); - siso = mtod(nam, struct sockaddr_iso *); - if (!(inp->inp_faddr.s_addr = tuba_lookup(siso, M_WAITOK))) { - unconnect: - iso_pcbdisconnect(isop); - error = ENOBUFS; - break; - } - bcopy(TSEL(isop->isop_faddr), &inp->inp_fport, 2); - if (inp->inp_laddr.s_addr == 0 && - (inp->inp_laddr.s_addr = - tuba_lookup(isop->isop_laddr, M_WAITOK)) == 0) - goto unconnect; - if ((tp->t_template = tcp_template(tp)) == 0) - goto unconnect; - 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); - tuba_refcnt(isop, 1); - 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: - if ((tp = tcp_disconnect(tp)) == 0) - tuba_pcbdetach(isop); - 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: - bcopy((caddr_t)isop->isop_faddr, mtod(nam, caddr_t), - nam->m_len = isop->isop_faddr->siso_len); - 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); - else - tuba_pcbdetach(isop); - break; - /* - * Abort the TCP. - */ - case PRU_ABORT: - if ((tp = tcp_drop(tp, ECONNABORTED)) == 0) - tuba_pcbdetach(isop); - break; - - - case PRU_SOCKADDR: - if (isop->isop_laddr) - bcopy((caddr_t)isop->isop_laddr, mtod(nam, caddr_t), - nam->m_len = isop->isop_laddr->siso_len); - break; - - case PRU_PEERADDR: - if (isop->isop_faddr) - bcopy((caddr_t)isop->isop_faddr, mtod(nam, caddr_t), - nam->m_len = isop->isop_faddr->siso_len); - break; - - default: - error = tcp_usrreq(so, req, m, nam, control); - goto notrace; - } - if (tp && (so->so_options & SO_DEBUG)) - tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req); -notrace: - splx(s); - return(error); -} - -tuba_ctloutput(op, so, level, optname, mp) - int op; - struct socket *so; - int level, optname; - struct mbuf **mp; -{ - int clnp_ctloutput(), tcp_ctloutput(); - - return ((level != IPPROTO_TCP ? clnp_ctloutput : tcp_ctloutput) - (op, so, level, optname, mp)); -} diff --git a/bsd/netkey/key.c b/bsd/netkey/key.c index 70a9524e6..6d6e92fd1 100644 --- a/bsd/netkey/key.c +++ b/bsd/netkey/key.c @@ -1,4 +1,5 @@ -/* $KAME: key.c,v 1.76 2000/03/27 05:11:04 sumikawa Exp $ */ +/* $FreeBSD: src/sys/netkey/key.c,v 1.16.2.5 2001/07/03 11:01:58 ume Exp $ */ +/* $KAME: key.c,v 1.187 2001/05/24 07:41:22 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -33,17 +34,6 @@ * This code is referd to RFC 2367 */ -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#ifdef __NetBSD__ -#include "opt_ipsec.h" -#endif -#endif - -/* this is for backward compatibility. we should not touch those. */ -#define ss_len __ss_len -#define ss_family __ss_family - #include #include #include @@ -54,9 +44,7 @@ #include #include #include -#if defined(__FreeBSD__) || defined (__APPLE__) #include -#endif #include #include #include @@ -80,9 +68,7 @@ #include #endif #if INET6 -#if !(defined(__bsdi__) && _BSDI_VERSION >= 199802) #include -#endif #endif /* INET6 */ #include @@ -90,16 +76,38 @@ #include #include #include +#include + #include +#if INET6 +#include +#endif #include +#if INET6 +#include +#endif #if IPSEC_ESP #include +#if INET6 +#include +#endif #endif #include +#if INET6 +#include +#endif + + +/* randomness */ +#include #include +#ifndef satosin +#define satosin(s) ((struct sockaddr_in *)s) +#endif + /* * Note on SA reference counting: * - SAs that are not in DEAD state will have (total external reference + 1) @@ -152,12 +160,60 @@ static u_int saorder_state_any[] = { SADB_SASTATE_LARVAL, SADB_SASTATE_DEAD }; -#if defined(__FreeBSD__) || defined (__APPLE__) +static const int minsize[] = { + sizeof(struct sadb_msg), /* SADB_EXT_RESERVED */ + sizeof(struct sadb_sa), /* SADB_EXT_SA */ + sizeof(struct sadb_lifetime), /* SADB_EXT_LIFETIME_CURRENT */ + sizeof(struct sadb_lifetime), /* SADB_EXT_LIFETIME_HARD */ + sizeof(struct sadb_lifetime), /* SADB_EXT_LIFETIME_SOFT */ + sizeof(struct sadb_address), /* SADB_EXT_ADDRESS_SRC */ + sizeof(struct sadb_address), /* SADB_EXT_ADDRESS_DST */ + sizeof(struct sadb_address), /* SADB_EXT_ADDRESS_PROXY */ + sizeof(struct sadb_key), /* SADB_EXT_KEY_AUTH */ + sizeof(struct sadb_key), /* SADB_EXT_KEY_ENCRYPT */ + sizeof(struct sadb_ident), /* SADB_EXT_IDENTITY_SRC */ + sizeof(struct sadb_ident), /* SADB_EXT_IDENTITY_DST */ + sizeof(struct sadb_sens), /* SADB_EXT_SENSITIVITY */ + sizeof(struct sadb_prop), /* SADB_EXT_PROPOSAL */ + sizeof(struct sadb_supported), /* SADB_EXT_SUPPORTED_AUTH */ + sizeof(struct sadb_supported), /* SADB_EXT_SUPPORTED_ENCRYPT */ + sizeof(struct sadb_spirange), /* SADB_EXT_SPIRANGE */ + 0, /* SADB_X_EXT_KMPRIVATE */ + sizeof(struct sadb_x_policy), /* SADB_X_EXT_POLICY */ + sizeof(struct sadb_x_sa2), /* SADB_X_SA2 */ +}; +static const int maxsize[] = { + sizeof(struct sadb_msg), /* SADB_EXT_RESERVED */ + sizeof(struct sadb_sa), /* SADB_EXT_SA */ + sizeof(struct sadb_lifetime), /* SADB_EXT_LIFETIME_CURRENT */ + sizeof(struct sadb_lifetime), /* SADB_EXT_LIFETIME_HARD */ + sizeof(struct sadb_lifetime), /* SADB_EXT_LIFETIME_SOFT */ + 0, /* SADB_EXT_ADDRESS_SRC */ + 0, /* SADB_EXT_ADDRESS_DST */ + 0, /* SADB_EXT_ADDRESS_PROXY */ + 0, /* SADB_EXT_KEY_AUTH */ + 0, /* SADB_EXT_KEY_ENCRYPT */ + 0, /* SADB_EXT_IDENTITY_SRC */ + 0, /* SADB_EXT_IDENTITY_DST */ + 0, /* SADB_EXT_SENSITIVITY */ + 0, /* SADB_EXT_PROPOSAL */ + 0, /* SADB_EXT_SUPPORTED_AUTH */ + 0, /* SADB_EXT_SUPPORTED_ENCRYPT */ + sizeof(struct sadb_spirange), /* SADB_EXT_SPIRANGE */ + 0, /* SADB_X_EXT_KMPRIVATE */ + 0, /* SADB_X_EXT_POLICY */ + sizeof(struct sadb_x_sa2), /* SADB_X_SA2 */ +}; + +static int ipsec_esp_keymin = 256; +static int ipsec_esp_auth = 0; +static int ipsec_ah_keymin = 128; + SYSCTL_DECL(_net_key); -//#if defined(IPSEC_DEBUG) + SYSCTL_INT(_net_key, KEYCTL_DEBUG_LEVEL, debug, CTLFLAG_RW, \ &key_debug_level, 0, ""); -//#endif /* defined(IPSEC_DEBUG) */ + /* max count of trial for the decision of spi value */ SYSCTL_INT(_net_key, KEYCTL_SPI_TRY, spi_trycnt, CTLFLAG_RW, \ @@ -187,7 +243,13 @@ SYSCTL_INT(_net_key, KEYCTL_BLOCKACQ_COUNT, blockacq_count, CTLFLAG_RW, \ SYSCTL_INT(_net_key, KEYCTL_BLOCKACQ_LIFETIME, blockacq_lifetime, CTLFLAG_RW, \ &key_blockacq_lifetime, 0, ""); -#endif /* __FreeBSD__ */ +/* minimum ESP key length */ +SYSCTL_INT(_net_key, KEYCTL_ESP_KEYMIN, esp_keymin, CTLFLAG_RW, \ + &ipsec_esp_keymin, 0, ""); + +/* minimum AH key length */ +SYSCTL_INT(_net_key, KEYCTL_AH_KEYMIN, ah_keymin, CTLFLAG_RW, \ + &ipsec_ah_keymin, 0, ""); #ifndef LIST_FOREACH #define LIST_FOREACH(elm, head, field) \ @@ -264,12 +326,12 @@ do { \ * set parameters into secasindex buffer. * Must allocate secasindex buffer before calling this function. */ -#define KEY_SETSECASIDX(p, m, s, d, idx) \ +#define KEY_SETSECASIDX(p, m, r, s, d, idx) \ do { \ bzero((idx), sizeof(struct secasindex)); \ (idx)->proto = (p); \ - (idx)->mode = (m)->sadb_msg_mode; \ - (idx)->reqid = (m)->sadb_msg_reqid; \ + (idx)->mode = (m); \ + (idx)->reqid = (r); \ bcopy((s), &(idx)->src, ((struct sockaddr *)(s))->sa_len); \ bcopy((d), &(idx)->dst, ((struct sockaddr *)(d))->sa_len); \ } while (0) @@ -279,115 +341,144 @@ struct _keystat { u_long getspi_count; /* the avarage of count to try to get new SPI */ } keystat; -static struct secasvar *key_allocsa_policy __P((struct secasindex *saidx)); -static void key_freesp_so __P((struct secpolicy **sp)); -static struct secasvar *key_do_allocsa_policy __P((struct secashead *sah, - u_int state)); -static void key_delsp __P((struct secpolicy *sp)); -static struct secpolicy *key_getsp __P((struct secpolicyindex *spidx)); -static struct secpolicy *key_getspbyid __P((u_int32_t id)); +struct sadb_msghdr { + struct sadb_msg *msg; + struct sadb_ext *ext[SADB_EXT_MAX + 1]; + int extoff[SADB_EXT_MAX + 1]; + int extlen[SADB_EXT_MAX + 1]; +}; + +static struct secasvar *key_allocsa_policy __P((struct secasindex *)); +static void key_freesp_so __P((struct secpolicy **)); +static struct secasvar *key_do_allocsa_policy __P((struct secashead *, u_int)); +static void key_delsp __P((struct secpolicy *)); +static struct secpolicy *key_getsp __P((struct secpolicyindex *)); +static struct secpolicy *key_getspbyid __P((u_int32_t)); static u_int32_t key_newreqid __P((void)); -static struct sadb_msg *key_spdadd __P((caddr_t *mhp)); +static struct mbuf *key_gather_mbuf __P((struct mbuf *, + const struct sadb_msghdr *, int, int, int *)); +static int key_spdadd __P((struct socket *, struct mbuf *, + const struct sadb_msghdr *)); static u_int32_t key_getnewspid __P((void)); -static struct sadb_msg *key_spddelete __P((caddr_t *mhp)); -static struct sadb_msg *key_spddelete2 __P((caddr_t *mhp)); -static int key_spdget __P((caddr_t *mhp, struct socket *so, int target)); -static struct sadb_msg *key_spdflush __P((caddr_t *mhp)); -static int key_spddump __P((caddr_t *mhp, struct socket *so, int target)); -static struct mbuf *key_setdumpsp __P((struct secpolicy *sp, - u_int8_t type, u_int32_t seq, u_int32_t pid)); -static u_int key_getspmsglen __P((struct secpolicy *sp)); -static u_int key_getspreqmsglen __P((struct secpolicy *sp)); -static struct secashead *key_newsah __P((struct secasindex *saidx)); -static void key_delsah __P((struct secashead *sah)); -static struct secasvar *key_newsav __P((caddr_t *mhp, struct secashead *sah)); -static void key_delsav __P((struct secasvar *sav)); -static struct secashead *key_getsah __P((struct secasindex *saidx)); -static struct secasvar *key_checkspidup __P((struct secasindex *saidx, - u_int32_t spi)); -static struct secasvar *key_getsavbyspi __P((struct secashead *sah, - u_int32_t spi)); -static int key_setsaval __P((struct secasvar *sav, caddr_t *mhp)); -static u_int key_getmsglen __P((struct secasvar *sav)); -static int key_mature __P((struct secasvar *sav)); -static u_int key_setdumpsa __P((struct sadb_msg *newmsg, struct secasvar *sav, - u_int8_t type, u_int8_t satype, - u_int32_t seq, u_int32_t pid)); -#if 1 -static int key_setsadbmsg_m __P((struct mbuf *, u_int8_t type, int tlen, - u_int8_t satype, u_int32_t seq, pid_t pid, - u_int8_t mode, u_int32_t reqid, - u_int8_t reserved1, u_int32_t reserved2)); -#endif -static caddr_t key_setsadbmsg __P((caddr_t buf, u_int8_t type, int tlen, - u_int8_t satype, u_int32_t seq, pid_t pid, - u_int8_t mode, u_int32_t reqid, - u_int8_t reserved1, u_int32_t reserved2)); -static caddr_t key_setsadbsa __P((caddr_t buf, struct secasvar *sav)); -#if 1 -static int key_setsadbaddr_m __P((struct mbuf *m, u_int16_t exttype, - struct sockaddr *saddr, u_int8_t prefixlen, u_int16_t ul_proto)); -#endif -static caddr_t key_setsadbaddr __P((caddr_t buf, u_int16_t exttype, - struct sockaddr *saddr, u_int8_t prefixlen, u_int16_t ul_proto)); -static caddr_t key_setsadbident - __P((caddr_t buf, u_int16_t exttype, u_int16_t idtype, - caddr_t string, int stringlen, u_int64_t id)); -static caddr_t key_setsadbxpolicy - __P((caddr_t buf, u_int16_t type, u_int8_t dir, u_int32_t id)); -static caddr_t key_setsadbext __P((caddr_t p, caddr_t ext)); -static void *key_newbuf __P((void *src, u_int len)); -#if INET6 -static int key_ismyaddr6 __P((caddr_t addr)); -#endif +static int key_spddelete __P((struct socket *, struct mbuf *, + const struct sadb_msghdr *)); +static int key_spddelete2 __P((struct socket *, struct mbuf *, + const struct sadb_msghdr *)); +static int key_spdget __P((struct socket *, struct mbuf *, + const struct sadb_msghdr *)); +static int key_spdflush __P((struct socket *, struct mbuf *, + const struct sadb_msghdr *)); +static int key_spddump __P((struct socket *, struct mbuf *, + const struct sadb_msghdr *)); +static struct mbuf *key_setdumpsp __P((struct secpolicy *, + u_int8_t, u_int32_t, u_int32_t)); +static u_int key_getspreqmsglen __P((struct secpolicy *)); +static int key_spdexpire __P((struct secpolicy *)); +static struct secashead *key_newsah __P((struct secasindex *)); +static void key_delsah __P((struct secashead *)); +static struct secasvar *key_newsav __P((struct mbuf *, + const struct sadb_msghdr *, struct secashead *, int *)); +static void key_delsav __P((struct secasvar *)); +static struct secashead *key_getsah __P((struct secasindex *)); +static struct secasvar *key_checkspidup __P((struct secasindex *, u_int32_t)); +static struct secasvar *key_getsavbyspi __P((struct secashead *, u_int32_t)); +static int key_setsaval __P((struct secasvar *, struct mbuf *, + const struct sadb_msghdr *)); +static int key_mature __P((struct secasvar *)); +static struct mbuf *key_setdumpsa __P((struct secasvar *, u_int8_t, + u_int8_t, u_int32_t, u_int32_t)); +static struct mbuf *key_setsadbmsg __P((u_int8_t, u_int16_t, u_int8_t, + u_int32_t, pid_t, u_int16_t)); +static struct mbuf *key_setsadbsa __P((struct secasvar *)); +static struct mbuf *key_setsadbaddr __P((u_int16_t, + struct sockaddr *, u_int8_t, u_int16_t)); #if 0 -static int key_isloopback __P((u_int family, caddr_t addr)); +static struct mbuf *key_setsadbident __P((u_int16_t, u_int16_t, caddr_t, + int, u_int64_t)); +#endif +static struct mbuf *key_setsadbxsa2(u_int8_t, u_int32_t); +static struct mbuf *key_setsadbxpolicy __P((u_int16_t, u_int8_t, + u_int32_t)); +static void *key_newbuf __P((const void *, u_int)); +#if INET6 +static int key_ismyaddr6 __P((struct sockaddr_in6 *)); #endif static int key_cmpsaidx_exactly - __P((struct secasindex *saidx0, struct secasindex *saidx1)); + __P((struct secasindex *, struct secasindex *)); static int key_cmpsaidx_withmode - __P((struct secasindex *saidx0, struct secasindex *saidx1)); + __P((struct secasindex *, struct secasindex *)); +static int key_cmpsaidx_withoutmode2 + __P((struct secasindex *, struct secasindex *)); +static int key_cmpsaidx_withoutmode + __P((struct secasindex *, struct secasindex *)); static int key_cmpspidx_exactly - __P((struct secpolicyindex *spidx0, struct secpolicyindex *spidx1)); + __P((struct secpolicyindex *, struct secpolicyindex *)); static int key_cmpspidx_withmask - __P((struct secpolicyindex *spidx0, struct secpolicyindex *spidx1)); -static int key_bbcmp __P((caddr_t p1, caddr_t p2, u_int bits)); -static u_int16_t key_satype2proto __P((u_int8_t satype)); -static u_int8_t key_proto2satype __P((u_int16_t proto)); - -static struct sadb_msg *key_getspi __P((caddr_t *mhp)); -static u_int32_t key_do_getnewspi __P((struct sadb_spirange *spirange, - struct secasindex *saidx)); -static struct sadb_msg *key_update __P((caddr_t *mhp)); -#ifdef IPSEC_DOSEQCHECK -static struct secasvar *key_getsavbyseq __P((struct secashead *sah, - u_int32_t seq)); -#endif -static struct sadb_msg *key_add __P((caddr_t *mhp)); -static int key_setident __P((struct secashead *sah, caddr_t *mhp)); -static struct sadb_msg *key_getmsgbuf_x1 __P((caddr_t *mhp)); -static struct sadb_msg *key_delete __P((caddr_t *mhp)); -static struct sadb_msg *key_get __P((caddr_t *mhp)); + __P((struct secpolicyindex *, struct secpolicyindex *)); +static int key_sockaddrcmp __P((struct sockaddr *, struct sockaddr *, int)); +static int key_bbcmp __P((caddr_t, caddr_t, u_int)); +static void key_srandom __P((void)); +static u_int16_t key_satype2proto __P((u_int8_t)); +static u_int8_t key_proto2satype __P((u_int16_t)); + +static int key_getspi __P((struct socket *, struct mbuf *, + const struct sadb_msghdr *)); +static u_int32_t key_do_getnewspi __P((struct sadb_spirange *, + struct secasindex *)); +static int key_update __P((struct socket *, struct mbuf *, + const struct sadb_msghdr *)); +#if IPSEC_DOSEQCHECK +static struct secasvar *key_getsavbyseq __P((struct secashead *, u_int32_t)); +#endif +static int key_add __P((struct socket *, struct mbuf *, + const struct sadb_msghdr *)); +static int key_setident __P((struct secashead *, struct mbuf *, + const struct sadb_msghdr *)); +static struct mbuf *key_getmsgbuf_x1 __P((struct mbuf *, + const struct sadb_msghdr *)); +static int key_delete __P((struct socket *, struct mbuf *, + const struct sadb_msghdr *)); +static int key_get __P((struct socket *, struct mbuf *, + const struct sadb_msghdr *)); + +static void key_getcomb_setlifetime __P((struct sadb_comb *)); +#if IPSEC_ESP +static struct mbuf *key_getcomb_esp __P((void)); +#endif +static struct mbuf *key_getcomb_ah __P((void)); +static struct mbuf *key_getcomb_ipcomp __P((void)); +static struct mbuf *key_getprop __P((const struct secasindex *)); + static int key_acquire __P((struct secasindex *, struct secpolicy *)); -static struct secacq *key_newacq __P((struct secasindex *saidx)); -static struct secacq *key_getacq __P((struct secasindex *saidx)); -static struct secacq *key_getacqbyseq __P((u_int32_t seq)); -static struct secspacq *key_newspacq __P((struct secpolicyindex *spidx)); -static struct secspacq *key_getspacq __P((struct secpolicyindex *spidx)); -static struct sadb_msg *key_acquire2 __P((caddr_t *mhp)); -static struct sadb_msg *key_register __P((caddr_t *mhp, struct socket *so)); -static int key_expire __P((struct secasvar *sav)); -static struct sadb_msg *key_flush __P((caddr_t *mhp)); -static int key_dump __P((caddr_t *mhp, struct socket *so, int target)); -static void key_promisc __P((caddr_t *mhp, struct socket *so)); -static int key_sendall __P((struct sadb_msg *msg, u_int len)); -static int key_align __P((struct sadb_msg *msg, caddr_t *mhp)); +#ifndef IPSEC_NONBLOCK_ACQUIRE +static struct secacq *key_newacq __P((struct secasindex *)); +static struct secacq *key_getacq __P((struct secasindex *)); +static struct secacq *key_getacqbyseq __P((u_int32_t)); +#endif +static struct secspacq *key_newspacq __P((struct secpolicyindex *)); +static struct secspacq *key_getspacq __P((struct secpolicyindex *)); +static int key_acquire2 __P((struct socket *, struct mbuf *, + const struct sadb_msghdr *)); +static int key_register __P((struct socket *, struct mbuf *, + const struct sadb_msghdr *)); +static int key_expire __P((struct secasvar *)); +static int key_flush __P((struct socket *, struct mbuf *, + const struct sadb_msghdr *)); +static int key_dump __P((struct socket *, struct mbuf *, + const struct sadb_msghdr *)); +static int key_promisc __P((struct socket *, struct mbuf *, + const struct sadb_msghdr *)); +static int key_senderror __P((struct socket *, struct mbuf *, int)); +static int key_validate_ext __P((const struct sadb_ext *, int)); +static int key_align __P((struct mbuf *, struct sadb_msghdr *)); #if 0 static const char *key_getfqdn __P((void)); static const char *key_getuserfqdn __P((void)); #endif -static void key_sa_chgstate __P((struct secasvar *sav, u_int8_t state)); -static caddr_t key_appendmbuf __P((struct mbuf *, int)); +static void key_sa_chgstate __P((struct secasvar *, u_int8_t)); +static struct mbuf *key_alloc_mbuf __P((int)); + +extern int ipsec_bypass; /* %%% IPsec policy management */ /* @@ -402,6 +493,7 @@ key_allocsp(spidx, dir) u_int dir; { struct secpolicy *sp; + struct timeval tv; int s; /* sanity check */ @@ -418,11 +510,7 @@ key_allocsp(spidx, dir) } /* get a SP entry */ -#ifdef __NetBSD__ - s = splsoftnet(); /*called from softclock()*/ -#else s = splnet(); /*called from softclock()*/ -#endif KEYDEBUG(KEYDEBUG_IPSEC_DATA, printf("*** objects\n"); kdebug_secpolicyindex(spidx)); @@ -446,6 +534,8 @@ found: KEY_CHKSPDIR(sp->spidx.dir, dir, "key_allocsp"); /* found a SPD entry */ + microtime(&tv); + sp->lastused = tv.tv_sec; sp->refcnt++; splx(s); KEYDEBUG(KEYDEBUG_IPSEC_STAMP, @@ -456,8 +546,75 @@ found: } /* - * allocating a SA entry for a *OUTBOUND* packet. - * checking each request entries in SP, and acquire SA if need. + * return a policy that matches this particular inbound packet. + * XXX slow + */ +struct secpolicy * +key_gettunnel(osrc, odst, isrc, idst) + struct sockaddr *osrc, *odst, *isrc, *idst; +{ + struct secpolicy *sp; + const int dir = IPSEC_DIR_INBOUND; + struct timeval tv; + int s; + struct ipsecrequest *r1, *r2, *p; + struct sockaddr *os, *od, *is, *id; + struct secpolicyindex spidx; + + s = splnet(); /*called from softclock()*/ + LIST_FOREACH(sp, &sptree[dir], chain) { + if (sp->state == IPSEC_SPSTATE_DEAD) + continue; + + r1 = r2 = NULL; + for (p = sp->req; p; p = p->next) { + if (p->saidx.mode != IPSEC_MODE_TUNNEL) + continue; + + r1 = r2; + r2 = p; + + if (!r1) { + /* here we look at address matches only */ + spidx = sp->spidx; + if (isrc->sa_len > sizeof(spidx.src) || + idst->sa_len > sizeof(spidx.dst)) + continue; + bcopy(isrc, &spidx.src, isrc->sa_len); + bcopy(idst, &spidx.dst, idst->sa_len); + if (!key_cmpspidx_withmask(&sp->spidx, &spidx)) + continue; + } else { + is = (struct sockaddr *)&r1->saidx.src; + id = (struct sockaddr *)&r1->saidx.dst; + if (key_sockaddrcmp(is, isrc, 0) || + key_sockaddrcmp(id, idst, 0)) + continue; + } + + os = (struct sockaddr *)&r2->saidx.src; + od = (struct sockaddr *)&r2->saidx.dst; + if (key_sockaddrcmp(os, osrc, 0) || + key_sockaddrcmp(od, odst, 0)) + continue; + + goto found; + } + } + splx(s); + return NULL; + +found: + microtime(&tv); + sp->lastused = tv.tv_sec; + sp->refcnt++; + splx(s); + return sp; +} + +/* + * allocating an SA entry for an *OUTBOUND* packet. + * checking each request entries in SP, and acquire an SA if need. * OUT: 0: there are valid requests. * ENOENT: policy may be valid, but SA with REQUIRE is on acquiring. */ @@ -536,7 +693,7 @@ key_checkrequest(isr, saidx) /* there is no SA */ if ((error = key_acquire(saidx, isr->sp)) != 0) { /* XXX What I do ? */ -#ifdef IPSEC_DEBUG +#if IPSEC_DEBUG printf("key_checkrequest: error %d returned " "from key_acquire.\n", error); #endif @@ -651,7 +808,7 @@ key_do_allocsa_policy(sah, state) * of a Security Parameter Index (SPI), an IP Destination Address, and a * security protocol (AH or ESP) identifier. * Note that, however, we do need to keep source address in IPsec SA. - * IPsec SA. IKE specification and PF_KEY specification do assume that we + * IKE specification and PF_KEY specification do assume that we * keep source address in IPsec SA. We see a tricky situation here. */ struct secasvar * @@ -663,6 +820,8 @@ key_allocsa(family, src, dst, proto, spi) struct secashead *sah; struct secasvar *sav; u_int stateidx, state; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; int s; /* sanity check */ @@ -675,38 +834,95 @@ key_allocsa(family, src, dst, proto, spi) * IPsec tunnel packet is received. But ESP tunnel mode is * encrypted so we can't check internal IP header. */ -#ifdef __NetBSD__ - s = splsoftnet(); /*called from softclock()*/ -#else s = splnet(); /*called from softclock()*/ -#endif LIST_FOREACH(sah, &sahtree, chain) { - /* search valid state */ for (stateidx = 0; stateidx < _ARRAYLEN(saorder_state_valid); stateidx++) { - state = saorder_state_valid[stateidx]; LIST_FOREACH(sav, &sah->savtree[state], chain) { - /* sanity check */ KEY_CHKSASTATE(sav->state, state, "key_allocsav"); if (proto != sav->sah->saidx.proto) continue; if (spi != sav->spi) continue; + if (family != sav->sah->saidx.src.ss_family || + family != sav->sah->saidx.dst.ss_family) + continue; #if 0 /* don't check src */ - if (!key_bbcmp(src, - _INADDRBYSA(&sav->sah->saidx.src), - _INALENBYAF(sav->sah->saidx.src.ss_family) << 3)) + /* check src address */ + switch (family) { + case AF_INET: + bzero(&sin, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_len = sizeof(sin); + bcopy(src, &sin.sin_addr, + sizeof(sin.sin_addr)); + if (key_sockaddrcmp((struct sockaddr*)&sin, + (struct sockaddr *)&sav->sah->saidx.src, 0) != 0) + continue; + + break; + case AF_INET6: + bzero(&sin6, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_len = sizeof(sin6); + bcopy(src, &sin6.sin6_addr, + sizeof(sin6.sin6_addr)); + if (IN6_IS_SCOPE_LINKLOCAL(&sin6.sin6_addr)) { + /* kame fake scopeid */ + sin6.sin6_scope_id = + ntohs(sin6.sin6_addr.s6_addr16[1]); + sin6.sin6_addr.s6_addr16[1] = 0; + } + if (key_sockaddrcmp((struct sockaddr*)&sin6, + (struct sockaddr *)&sav->sah->saidx.src, 0) != 0) + continue; + break; + default: + printf("key_allocsa: unknown address family=%d.\n", + family); continue; + } + #endif - if (!key_bbcmp(dst, - _INADDRBYSA(&sav->sah->saidx.dst), - _INALENBYAF(sav->sah->saidx.dst.ss_family) << 3)) + /* check dst address */ + switch (family) { + case AF_INET: + bzero(&sin, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_len = sizeof(sin); + bcopy(dst, &sin.sin_addr, + sizeof(sin.sin_addr)); + if (key_sockaddrcmp((struct sockaddr*)&sin, + (struct sockaddr *)&sav->sah->saidx.dst, 0) != 0) + continue; + + break; + case AF_INET6: + bzero(&sin6, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_len = sizeof(sin6); + bcopy(dst, &sin6.sin6_addr, + sizeof(sin6.sin6_addr)); + if (IN6_IS_SCOPE_LINKLOCAL(&sin6.sin6_addr)) { + /* kame fake scopeid */ + sin6.sin6_scope_id = + ntohs(sin6.sin6_addr.s6_addr16[1]); + sin6.sin6_addr.s6_addr16[1] = 0; + } + if (key_sockaddrcmp((struct sockaddr*)&sin6, + (struct sockaddr *)&sav->sah->saidx.dst, 0) != 0) + continue; + break; + default: + printf("key_allocsa: unknown address family=%d.\n", + family); continue; + } goto found; } @@ -768,7 +984,7 @@ key_freeso(so) struct inpcb *pcb = sotoinpcb(so); /* Does it have a PCB ? */ - if (pcb == NULL) + if (pcb == NULL || pcb->inp_sp == NULL) return; key_freesp_so(&pcb->inp_sp->sp_in); key_freesp_so(&pcb->inp_sp->sp_out); @@ -782,7 +998,7 @@ key_freeso(so) struct inpcb *pcb = sotoinpcb(so); /* Does it have a PCB ? */ - if (pcb == NULL) + if (pcb == NULL || pcb->inp_sp == NULL) return; key_freesp_so(&pcb->inp_sp->sp_in); key_freesp_so(&pcb->inp_sp->sp_out); @@ -790,7 +1006,7 @@ key_freeso(so) struct in6pcb *pcb = sotoin6pcb(so); /* Does it have a PCB ? */ - if (pcb == NULL) + if (pcb == NULL || pcb->in6p_sp == NULL) return; key_freesp_so(&pcb->in6p_sp->sp_in); key_freesp_so(&pcb->in6p_sp->sp_out); @@ -849,7 +1065,7 @@ key_freesav(sav) sav->refcnt--; KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP freesav cause refcnt--:%d SA:%p SPI %d\n", + printf("DP freesav cause refcnt--:%d SA:%p SPI %u\n", sav->refcnt, sav, (u_int32_t)ntohl(sav->spi))); if (sav->refcnt == 0) @@ -877,11 +1093,7 @@ key_delsp(sp) if (sp->refcnt > 0) return; /* can't free */ -#if __NetBSD__ - s = splsoftnet(); /*called from softclock()*/ -#else s = splnet(); /*called from softclock()*/ -#endif /* remove from SP index */ if (__LIST_CHAINED(sp)) LIST_REMOVE(sp, chain); @@ -1078,9 +1290,7 @@ key_msg2sp(xpl0, len, error) switch (xisr->sadb_x_ipsecrequest_proto) { case IPPROTO_ESP: case IPPROTO_AH: -#if 1 /*nonstandard*/ case IPPROTO_IPCOMP: -#endif break; default: #if IPSEC_DEBUG @@ -1263,21 +1473,10 @@ key_sp2msg(sp) tlen = key_getspreqmsglen(sp); - MGET(m, M_DONTWAIT, MT_DATA); - if (m && MLEN < tlen) { - MCLGET(m, M_DONTWAIT); - if ((m->m_flags & M_EXT) == 0) { - m_free(m); - m = NULL; - } - } - m->m_len = 0; - if (!m || M_TRAILINGSPACE(m) < tlen) { -#if IPSEC_DEBUG - printf("key_sp2msg: No more memory.\n"); -#endif + m = key_alloc_mbuf(tlen); + if (!m || m->m_next) { /*XXX*/ if (m) - m_free(m); + m_freem(m); return NULL; } @@ -1323,57 +1522,146 @@ key_sp2msg(sp) return m; } +/* m will not be freed nor modified */ +static struct mbuf * +key_gather_mbuf(struct mbuf *m, const struct sadb_msghdr *mhp, + int ndeep, int nitem, int *items) +{ + int idx; + int i; + struct mbuf *result = NULL, *n; + int len; + + if (m == NULL || mhp == NULL) + panic("null pointer passed to key_gather"); + + for (i = 0; i < nitem; i++) { + idx = items[i]; + if (idx < 0 || idx > SADB_EXT_MAX) + goto fail; + /* don't attempt to pull empty extension */ + if (idx == SADB_EXT_RESERVED && mhp->msg == NULL) + continue; + if (idx != SADB_EXT_RESERVED && + (mhp->ext[idx] == NULL || mhp->extlen[idx] == 0)) + continue; + + if (idx == SADB_EXT_RESERVED) { + len = PFKEY_ALIGN8(sizeof(struct sadb_msg)); +#if DIAGNOSTIC + if (len > MHLEN) + panic("assumption failed"); +#endif + MGETHDR(n, M_DONTWAIT, MT_DATA); + if (!n) + goto fail; + n->m_len = len; + n->m_next = NULL; + m_copydata(m, 0, sizeof(struct sadb_msg), + mtod(n, caddr_t)); + } else if (i < ndeep) { + len = mhp->extlen[idx]; + n = key_alloc_mbuf(len); + if (!n || n->m_next) { /*XXX*/ + if (n) + m_freem(n); + goto fail; + } + m_copydata(m, mhp->extoff[idx], mhp->extlen[idx], + mtod(n, caddr_t)); + } else { + n = m_copym(m, mhp->extoff[idx], mhp->extlen[idx], + M_DONTWAIT); + } + if (n == NULL) + goto fail; + + if (result) + m_cat(result, n); + else + result = n; + } + + if ((result->m_flags & M_PKTHDR) != 0) { + result->m_pkthdr.len = 0; + for (n = result; n; n = n->m_next) + result->m_pkthdr.len += n->m_len; + } + + return result; + +fail: + m_freem(result); + return NULL; +} + /* * SADB_X_SPDADD, SADB_X_SPDSETIDX or SADB_X_SPDUPDATE processing * add a entry to SP database, when received - * + * * from the user(?). * Adding to SP database, * and send - * + * * to the socket which was send. * * SPDADD set a unique policy entry. * SPDSETIDX like SPDADD without a part of policy requests. * SPDUPDATE replace a unique policy entry. * - * IN: mhp: pointer to the pointer to each header. - * OUT: NULL if fail. - * other if success, return pointer to the message to send. - * + * m will always be freed. */ -static struct sadb_msg * -key_spdadd(mhp) - caddr_t *mhp; +static int +key_spdadd(so, m, mhp) + struct socket *so; + struct mbuf *m; + const struct sadb_msghdr *mhp; { - struct sadb_msg *msg0; struct sadb_address *src0, *dst0; - struct sadb_x_policy *xpl0; + struct sadb_x_policy *xpl0, *xpl; + struct sadb_lifetime *lft = NULL; struct secpolicyindex spidx; struct secpolicy *newsp; + struct timeval tv; int error; /* sanity check */ - if (mhp == NULL || mhp[0] == NULL) + if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_spdadd: NULL pointer is passed.\n"); - msg0 = (struct sadb_msg *)mhp[0]; - - if (mhp[SADB_EXT_ADDRESS_SRC] == NULL - || mhp[SADB_EXT_ADDRESS_DST] == NULL - || mhp[SADB_X_EXT_POLICY] == NULL) { + if (mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL || + mhp->ext[SADB_EXT_ADDRESS_DST] == NULL || + mhp->ext[SADB_X_EXT_POLICY] == NULL) { #if IPSEC_DEBUG printf("key_spdadd: invalid message is passed.\n"); #endif - msg0->sadb_msg_errno = EINVAL; - return NULL; + return key_senderror(so, m, EINVAL); + } + if (mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) || + mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address) || + mhp->extlen[SADB_X_EXT_POLICY] < sizeof(struct sadb_x_policy)) { +#if IPSEC_DEBUG + printf("key_spdadd: invalid message is passed.\n"); +#endif + return key_senderror(so, m, EINVAL); + } + if (mhp->ext[SADB_EXT_LIFETIME_HARD] != NULL) { + if (mhp->extlen[SADB_EXT_LIFETIME_HARD] + < sizeof(struct sadb_lifetime)) { +#if IPSEC_DEBUG + printf("key_spdadd: invalid message is passed.\n"); +#endif + return key_senderror(so, m, EINVAL); + } + lft = (struct sadb_lifetime *)mhp->ext[SADB_EXT_LIFETIME_HARD]; } - src0 = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; - dst0 = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; - xpl0 = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; + src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC]; + dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST]; + xpl0 = (struct sadb_x_policy *)mhp->ext[SADB_X_EXT_POLICY]; /* make secindex */ + /* XXX boundary check against sa_len */ KEY_SETSECSPIDX(xpl0->sadb_x_policy_dir, src0 + 1, dst0 + 1, @@ -1391,8 +1679,8 @@ key_spdadd(mhp) #if IPSEC_DEBUG printf("key_spdadd: Invalid SP direction.\n"); #endif - msg0->sadb_msg_errno = EINVAL; - return NULL; + mhp->msg->sadb_msg_errno = EINVAL; + return 0; } /* check policy */ @@ -1402,19 +1690,17 @@ key_spdadd(mhp) #if IPSEC_DEBUG printf("key_spdadd: Invalid policy type.\n"); #endif - msg0->sadb_msg_errno = EINVAL; - return NULL; + return key_senderror(so, m, EINVAL); } /* policy requests are mandatory when action is ipsec. */ - if (msg0->sadb_msg_type != SADB_X_SPDSETIDX + if (mhp->msg->sadb_msg_type != SADB_X_SPDSETIDX && xpl0->sadb_x_policy_type == IPSEC_POLICY_IPSEC - && PFKEY_EXTLEN(xpl0) <= sizeof(*xpl0)) { + && mhp->extlen[SADB_X_EXT_POLICY] <= sizeof(*xpl0)) { #if IPSEC_DEBUG printf("key_spdadd: some policy requests part required.\n"); #endif - msg0->sadb_msg_errno = EINVAL; - return NULL; + return key_senderror(so, m, EINVAL); } /* @@ -1423,13 +1709,12 @@ key_spdadd(mhp) * If type is either SPDADD or SPDSETIDX and SP found, then error. */ newsp = key_getsp(&spidx); - if (msg0->sadb_msg_type == SADB_X_SPDUPDATE) { + if (mhp->msg->sadb_msg_type == SADB_X_SPDUPDATE) { if (newsp == NULL) { #if IPSEC_DEBUG printf("key_spdadd: no SP found.\n"); #endif - msg0->sadb_msg_errno = ENOENT; - return NULL; + return key_senderror(so, m, ENOENT); } newsp->state = IPSEC_SPSTATE_DEAD; @@ -1440,23 +1725,21 @@ key_spdadd(mhp) #if IPSEC_DEBUG printf("key_spdadd: a SP entry exists already.\n"); #endif - msg0->sadb_msg_errno = EEXIST; - return NULL; + return key_senderror(so, m, EEXIST); } } /* allocation new SP entry */ if ((newsp = key_msg2sp(xpl0, PFKEY_EXTLEN(xpl0), &error)) == NULL) { - msg0->sadb_msg_errno = error; - return NULL; + return key_senderror(so, m, error); } if ((newsp->id = key_getnewspid()) == 0) { - msg0->sadb_msg_errno = ENOBUFS; keydb_delsecpolicy(newsp); - return NULL; + return key_senderror(so, m, ENOBUFS); } + /* XXX boundary check against sa_len */ KEY_SETSECSPIDX(xpl0->sadb_x_policy_dir, src0 + 1, dst0 + 1, @@ -1468,83 +1751,102 @@ key_spdadd(mhp) /* sanity check on addr pair */ if (((struct sockaddr *)(src0 + 1))->sa_family != ((struct sockaddr *)(dst0+ 1))->sa_family) { - msg0->sadb_msg_errno = EINVAL; keydb_delsecpolicy(newsp); - return NULL; + return key_senderror(so, m, EINVAL); + } + if (((struct sockaddr *)(src0 + 1))->sa_len != + ((struct sockaddr *)(dst0+ 1))->sa_len) { + keydb_delsecpolicy(newsp); + return key_senderror(so, m, EINVAL); } #if 1 if (newsp->req && newsp->req->saidx.src.ss_family) { struct sockaddr *sa; sa = (struct sockaddr *)(src0 + 1); if (sa->sa_family != newsp->req->saidx.src.ss_family) { - msg0->sadb_msg_errno = EINVAL; keydb_delsecpolicy(newsp); - return NULL; + return key_senderror(so, m, EINVAL); } } if (newsp->req && newsp->req->saidx.dst.ss_family) { struct sockaddr *sa; sa = (struct sockaddr *)(dst0 + 1); if (sa->sa_family != newsp->req->saidx.dst.ss_family) { - msg0->sadb_msg_errno = EINVAL; keydb_delsecpolicy(newsp); - return NULL; + return key_senderror(so, m, EINVAL); } } #endif + microtime(&tv); + newsp->created = tv.tv_sec; + newsp->lastused = tv.tv_sec; + newsp->lifetime = lft ? lft->sadb_lifetime_addtime : 0; + newsp->validtime = lft ? lft->sadb_lifetime_usetime : 0; + newsp->refcnt = 1; /* do not reclaim until I say I do */ newsp->state = IPSEC_SPSTATE_ALIVE; - LIST_INSERT_HEAD(&sptree[newsp->spidx.dir], newsp, chain); + LIST_INSERT_TAIL(&sptree[newsp->spidx.dir], newsp, secpolicy, chain); + + /* Turn off the ipsec bypass */ + if (ipsec_bypass != 0) + ipsec_bypass = 0; /* delete the entry in spacqtree */ - if (msg0->sadb_msg_type == SADB_X_SPDUPDATE) { + if (mhp->msg->sadb_msg_type == SADB_X_SPDUPDATE) { struct secspacq *spacq; if ((spacq = key_getspacq(&spidx)) != NULL) { - /* reset counter in order to deletion by timehander. */ - spacq->tick = key_blockacq_lifetime; + /* reset counter in order to deletion by timehandler. */ + microtime(&tv); + spacq->created = tv.tv_sec; spacq->count = 0; } } { + struct mbuf *n, *mpolicy; struct sadb_msg *newmsg; - u_int len; - caddr_t p; + int off; /* create new sadb_msg to reply. */ - len = sizeof(struct sadb_msg) - + PFKEY_EXTLEN(mhp[SADB_X_EXT_POLICY]) - + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_SRC]) - + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_DST]); - - KMALLOC(newmsg, struct sadb_msg *, len); - if (newmsg == NULL) { -#if IPSEC_DEBUG - printf("key_spdadd: No more memory.\n"); -#endif - /* newsp persists in the kernel */ - msg0->sadb_msg_errno = ENOBUFS; - return NULL; + if (lft) { + int mbufItems[] = {SADB_EXT_RESERVED, SADB_X_EXT_POLICY, + SADB_EXT_LIFETIME_HARD, SADB_EXT_ADDRESS_SRC, + SADB_EXT_ADDRESS_DST}; + n = key_gather_mbuf(m, mhp, 2, sizeof(mbufItems)/sizeof(int), mbufItems); + } else { + int mbufItems[] = {SADB_EXT_RESERVED, SADB_X_EXT_POLICY, + SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST}; + n = key_gather_mbuf(m, mhp, 2, sizeof(mbufItems)/sizeof(int), mbufItems); } - bzero((caddr_t)newmsg, len); + if (!n) + return key_senderror(so, m, ENOBUFS); - bcopy((caddr_t)msg0, (caddr_t)newmsg, sizeof(*msg0)); + if (n->m_len < sizeof(*newmsg)) { + n = m_pullup(n, sizeof(*newmsg)); + if (!n) + return key_senderror(so, m, ENOBUFS); + } + newmsg = mtod(n, struct sadb_msg *); newmsg->sadb_msg_errno = 0; - newmsg->sadb_msg_len = PFKEY_UNIT64(len); - p = (caddr_t)newmsg + sizeof(*msg0); - - /* - * reqid may had been updated at key_msg2sp() if reqid's - * range violation. - */ - ((struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY])->sadb_x_policy_id = newsp->id; - p = key_setsadbext(p, mhp[SADB_X_EXT_POLICY]); + newmsg->sadb_msg_len = PFKEY_UNIT64(n->m_pkthdr.len); - p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_SRC]); - p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_DST]); + off = 0; + mpolicy = m_pulldown(n, PFKEY_ALIGN8(sizeof(struct sadb_msg)), + sizeof(*xpl), &off); + if (mpolicy == NULL) { + /* n is already freed */ + return key_senderror(so, m, ENOBUFS); + } + xpl = (struct sadb_x_policy *)(mtod(mpolicy, caddr_t) + off); + if (xpl->sadb_x_policy_exttype != SADB_X_EXT_POLICY) { + m_freem(n); + return key_senderror(so, m, EINVAL); + } + xpl->sadb_x_policy_id = newsp->id; - return newmsg; + m_freem(m); + return key_sendup_mbuf(so, n, KEY_SENDUP_ALL); } } @@ -1591,41 +1893,46 @@ key_getnewspid() * to the ikmpd. * policy(*) including direction of policy. * - * IN: mhp: pointer to the pointer to each header. - * OUT: other if success, return pointer to the message to send. - * 0 if fail. + * m will always be freed. */ -static struct sadb_msg * -key_spddelete(mhp) - caddr_t *mhp; +static int +key_spddelete(so, m, mhp) + struct socket *so; + struct mbuf *m; + const struct sadb_msghdr *mhp; { - struct sadb_msg *msg0; struct sadb_address *src0, *dst0; struct sadb_x_policy *xpl0; struct secpolicyindex spidx; struct secpolicy *sp; /* sanity check */ - if (mhp == NULL || mhp[0] == NULL) + if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_spddelete: NULL pointer is passed.\n"); - msg0 = (struct sadb_msg *)mhp[0]; - - if (mhp[SADB_EXT_ADDRESS_SRC] == NULL - || mhp[SADB_EXT_ADDRESS_DST] == NULL - || mhp[SADB_X_EXT_POLICY] == NULL) { + if (mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL || + mhp->ext[SADB_EXT_ADDRESS_DST] == NULL || + mhp->ext[SADB_X_EXT_POLICY] == NULL) { #if IPSEC_DEBUG printf("key_spddelete: invalid message is passed.\n"); #endif - msg0->sadb_msg_errno = EINVAL; - return NULL; + return key_senderror(so, m, EINVAL); + } + if (mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) || + mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address) || + mhp->extlen[SADB_X_EXT_POLICY] < sizeof(struct sadb_x_policy)) { +#if IPSEC_DEBUG + printf("key_spddelete: invalid message is passed.\n"); +#endif + return key_senderror(so, m, EINVAL); } - src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); - dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); - xpl0 = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; + src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC]; + dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST]; + xpl0 = (struct sadb_x_policy *)mhp->ext[SADB_X_EXT_POLICY]; /* make secindex */ + /* XXX boundary check against sa_len */ KEY_SETSECSPIDX(xpl0->sadb_x_policy_dir, src0 + 1, dst0 + 1, @@ -1643,8 +1950,7 @@ key_spddelete(mhp) #if IPSEC_DEBUG printf("key_spddelete: Invalid SP direction.\n"); #endif - msg0->sadb_msg_errno = EINVAL; - return NULL; + return key_senderror(so, m, EINVAL); } /* Is there SP in SPD ? */ @@ -1652,8 +1958,7 @@ key_spddelete(mhp) #if IPSEC_DEBUG printf("key_spddelete: no SP found.\n"); #endif - msg0->sadb_msg_errno = ENOENT; - return NULL; + return key_senderror(so, m, EINVAL); } /* save policy id to buffer to be returned. */ @@ -1663,36 +1968,22 @@ key_spddelete(mhp) key_freesp(sp); { + struct mbuf *n; struct sadb_msg *newmsg; - u_int len; - caddr_t p; + int mbufItems[] = {SADB_EXT_RESERVED, SADB_X_EXT_POLICY, + SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST}; /* create new sadb_msg to reply. */ - len = sizeof(struct sadb_msg) - + PFKEY_EXTLEN(mhp[SADB_X_EXT_POLICY]) - + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_SRC]) - + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_DST]); - - KMALLOC(newmsg, struct sadb_msg *, len); - if (newmsg == NULL) { -#if IPSEC_DEBUG - printf("key_spddelete: No more memory.\n"); -#endif - msg0->sadb_msg_errno = ENOBUFS; - return NULL; - } - bzero((caddr_t)newmsg, len); + n = key_gather_mbuf(m, mhp, 1, sizeof(mbufItems)/sizeof(int), mbufItems); + if (!n) + return key_senderror(so, m, ENOBUFS); - bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0)); + newmsg = mtod(n, struct sadb_msg *); newmsg->sadb_msg_errno = 0; - newmsg->sadb_msg_len = PFKEY_UNIT64(len); - p = (caddr_t)newmsg + sizeof(*msg0); - - p = key_setsadbext(p, mhp[SADB_X_EXT_POLICY]); - p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_SRC]); - p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_DST]); + newmsg->sadb_msg_len = PFKEY_UNIT64(n->m_pkthdr.len); - return newmsg; + m_freem(m); + return key_sendup_mbuf(so, n, KEY_SENDUP_ALL); } } @@ -1706,73 +1997,93 @@ key_spddelete(mhp) * to the ikmpd. * policy(*) including direction of policy. * - * IN: mhp: pointer to the pointer to each header. - * OUT: other if success, return pointer to the message to send. - * 0 if fail. + * m will always be freed. */ -static struct sadb_msg * -key_spddelete2(mhp) - caddr_t *mhp; +static int +key_spddelete2(so, m, mhp) + struct socket *so; + struct mbuf *m; + const struct sadb_msghdr *mhp; { - struct sadb_msg *msg0; u_int32_t id; struct secpolicy *sp; /* sanity check */ - if (mhp == NULL || mhp[0] == NULL) + if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_spddelete2: NULL pointer is passed.\n"); - msg0 = (struct sadb_msg *)mhp[0]; - - if (mhp[SADB_X_EXT_POLICY] == NULL) { + if (mhp->ext[SADB_X_EXT_POLICY] == NULL || + mhp->extlen[SADB_X_EXT_POLICY] < sizeof(struct sadb_x_policy)) { #if IPSEC_DEBUG printf("key_spddelete2: invalid message is passed.\n"); #endif - msg0->sadb_msg_errno = EINVAL; - return NULL; + key_senderror(so, m, EINVAL); + return 0; } - id = ((struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY])->sadb_x_policy_id; + id = ((struct sadb_x_policy *)mhp->ext[SADB_X_EXT_POLICY])->sadb_x_policy_id; /* Is there SP in SPD ? */ if ((sp = key_getspbyid(id)) == NULL) { #if IPSEC_DEBUG printf("key_spddelete2: no SP found id:%u.\n", id); #endif - msg0->sadb_msg_errno = ENOENT; - return NULL; + key_senderror(so, m, EINVAL); } sp->state = IPSEC_SPSTATE_DEAD; key_freesp(sp); { + struct mbuf *n, *nn; struct sadb_msg *newmsg; - u_int len; - caddr_t p; + int off, len; /* create new sadb_msg to reply. */ - len = sizeof(struct sadb_msg) - + PFKEY_EXTLEN(mhp[SADB_X_EXT_POLICY]); + len = PFKEY_ALIGN8(sizeof(struct sadb_msg)); - KMALLOC(newmsg, struct sadb_msg *, len); - if (newmsg == NULL) { -#if IPSEC_DEBUG - printf("key_spddelete2: No more memory.\n"); + if (len > MCLBYTES) + return key_senderror(so, m, ENOBUFS); + MGETHDR(n, M_DONTWAIT, MT_DATA); + if (n && len > MHLEN) { + MCLGET(n, M_DONTWAIT); + if ((n->m_flags & M_EXT) == 0) { + m_freem(n); + n = NULL; + } + } + if (!n) + return key_senderror(so, m, ENOBUFS); + + n->m_len = len; + n->m_next = NULL; + off = 0; + + m_copydata(m, 0, sizeof(struct sadb_msg), mtod(n, caddr_t) + off); + off += PFKEY_ALIGN8(sizeof(struct sadb_msg)); + +#if DIAGNOSTIC + if (off != len) + panic("length inconsistency in key_spddelete2"); #endif - msg0->sadb_msg_errno = ENOBUFS; - return NULL; + + n->m_next = m_copym(m, mhp->extoff[SADB_X_EXT_POLICY], + mhp->extlen[SADB_X_EXT_POLICY], M_DONTWAIT); + if (!n->m_next) { + m_freem(n); + return key_senderror(so, m, ENOBUFS); } - bzero((caddr_t)newmsg, len); - bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0)); - newmsg->sadb_msg_errno = 0; - newmsg->sadb_msg_len = PFKEY_UNIT64(len); - p = (caddr_t)newmsg + sizeof(*msg0); + n->m_pkthdr.len = 0; + for (nn = n; nn; nn = nn->m_next) + n->m_pkthdr.len += nn->m_len; - p = key_setsadbext(p, mhp[SADB_X_EXT_POLICY]); + newmsg = mtod(n, struct sadb_msg *); + newmsg->sadb_msg_errno = 0; + newmsg->sadb_msg_len = PFKEY_UNIT64(n->m_pkthdr.len); - return newmsg; + m_freem(m); + return key_sendup_mbuf(so, n, KEY_SENDUP_ALL); } } @@ -1786,49 +2097,46 @@ key_spddelete2(mhp) * to the ikmpd. * policy(*) including direction of policy. * - * IN: mhp: pointer to the pointer to each header. - * OUT: other if success, return pointer to the message to send. - * 0 if fail. + * m will always be freed. */ static int -key_spdget(mhp, so, target) - caddr_t *mhp; +key_spdget(so, m, mhp) struct socket *so; - int target; + struct mbuf *m; + const struct sadb_msghdr *mhp; { - struct sadb_msg *msg0; u_int32_t id; struct secpolicy *sp; - struct mbuf *m; + struct mbuf *n; /* sanity check */ - if (mhp == NULL || mhp[0] == NULL) + if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_spdget: NULL pointer is passed.\n"); - msg0 = (struct sadb_msg *)mhp[0]; - - if (mhp[SADB_X_EXT_POLICY] == NULL) { + if (mhp->ext[SADB_X_EXT_POLICY] == NULL || + mhp->extlen[SADB_X_EXT_POLICY] < sizeof(struct sadb_x_policy)) { #if IPSEC_DEBUG printf("key_spdget: invalid message is passed.\n"); #endif - return EINVAL; + return key_senderror(so, m, EINVAL); } - id = ((struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY])->sadb_x_policy_id; + id = ((struct sadb_x_policy *)mhp->ext[SADB_X_EXT_POLICY])->sadb_x_policy_id; /* Is there SP in SPD ? */ if ((sp = key_getspbyid(id)) == NULL) { #if IPSEC_DEBUG printf("key_spdget: no SP found id:%u.\n", id); #endif - return ENOENT; + return key_senderror(so, m, ENOENT); } - m = key_setdumpsp(sp, SADB_X_SPDGET, 0, msg0->sadb_msg_pid); - if (m != NULL) - key_sendup_mbuf(so, m, target); - - return 0; + n = key_setdumpsp(sp, SADB_X_SPDGET, 0, mhp->msg->sadb_msg_pid); + if (n != NULL) { + m_freem(m); + return key_sendup_mbuf(so, n, KEY_SENDUP_ONE); + } else + return key_senderror(so, m, ENOBUFS); } /* @@ -1850,6 +2158,7 @@ int key_spdacquire(sp) struct secpolicy *sp; { + struct mbuf *result = NULL, *m; struct secspacq *newspacq; int error; @@ -1880,72 +2189,30 @@ key_spdacquire(sp) LIST_INSERT_HEAD(&spacqtree, newspacq, chain); } - { - struct sadb_msg *newmsg = NULL; - union sadb_x_ident_id id; - u_int len; - caddr_t p; - /* create new sadb_msg to reply. */ - len = sizeof(struct sadb_msg) - + sizeof(struct sadb_ident) - + PFKEY_ALIGN8(sp->spidx.src.ss_len) - + sizeof(struct sadb_ident) - + PFKEY_ALIGN8(sp->spidx.dst.ss_len); - - KMALLOC(newmsg, struct sadb_msg *, len); - if (newmsg == 0) { -#if IPSEC_DEBUG - printf("key_spdacquire: No more memory.\n"); -#endif - return ENOBUFS; + m = key_setsadbmsg(SADB_X_SPDACQUIRE, 0, 0, 0, 0, 0); + if (!m) { + error = ENOBUFS; + goto fail; } - bzero((caddr_t)newmsg, len); + result = m; - newmsg->sadb_msg_version = PF_KEY_V2; - newmsg->sadb_msg_type = SADB_X_SPDACQUIRE; - newmsg->sadb_msg_errno = 0; - newmsg->sadb_msg_satype = 0; - newmsg->sadb_msg_len = PFKEY_UNIT64(len); - newmsg->sadb_msg_mode = 0; - newmsg->sadb_msg_reqid = 0; - newmsg->sadb_msg_seq = 0; - newmsg->sadb_msg_pid = 0; - p = (caddr_t)newmsg + sizeof(struct sadb_msg); - - /* set sadb_address for spidx's. */ - bzero(&id, sizeof(id)); - id.sadb_x_ident_id_addr.prefix = sp->spidx.prefs; - id.sadb_x_ident_id_addr.ul_proto = sp->spidx.ul_proto; - p = key_setsadbident(p, - SADB_EXT_IDENTITY_SRC, - SADB_X_IDENTTYPE_ADDR, - (caddr_t)&sp->spidx.src, - sp->spidx.src.ss_len, - *(u_int64_t *)&id); - - bzero(&id, sizeof(id)); - id.sadb_x_ident_id_addr.prefix = sp->spidx.prefd; - id.sadb_x_ident_id_addr.ul_proto = sp->spidx.ul_proto; - p = key_setsadbident(p, - SADB_EXT_IDENTITY_DST, - SADB_X_IDENTTYPE_ADDR, - (caddr_t)&sp->spidx.dst, - sp->spidx.dst.ss_len, - *(u_int64_t *)&id); - - error = key_sendall(newmsg, len); -#if IPSEC_DEBUG - if (error != 0) - printf("key_spdacquire: key_sendall returned %d\n", error); -#endif - return error; - } + result->m_pkthdr.len = 0; + for (m = result; m; m = m->m_next) + result->m_pkthdr.len += m->m_len; - return 0; -} + mtod(result, struct sadb_msg *)->sadb_msg_len = + PFKEY_UNIT64(result->m_pkthdr.len); -/* + return key_sendup_mbuf(NULL, m, KEY_SENDUP_REGISTERED); + +fail: + if (result) + m_freem(result); + return error; +} + +/* * SADB_SPDFLUSH processing * receive * @@ -1955,23 +2222,24 @@ key_spdacquire(sp) * to the user. * NOTE: what to do is only marking SADB_SASTATE_DEAD. * - * IN: mhp: pointer to the pointer to each header. - * OUT: other if success, return pointer to the message to send. - * 0 if fail. + * m will always be freed. */ -static struct sadb_msg * -key_spdflush(mhp) - caddr_t *mhp; +static int +key_spdflush(so, m, mhp) + struct socket *so; + struct mbuf *m; + const struct sadb_msghdr *mhp; { - struct sadb_msg *msg0; + struct sadb_msg *newmsg; struct secpolicy *sp; u_int dir; /* sanity check */ - if (mhp == NULL || mhp[0] == NULL) + if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_spdflush: NULL pointer is passed.\n"); - msg0 = (struct sadb_msg *)mhp[0]; + if (m->m_len != PFKEY_ALIGN8(sizeof(struct sadb_msg))) + return key_senderror(so, m, EINVAL); for (dir = 0; dir < IPSEC_DIR_MAX; dir++) { LIST_FOREACH(sp, &sptree[dir], chain) { @@ -1979,29 +2247,22 @@ key_spdflush(mhp) } } - { - struct sadb_msg *newmsg; - u_int len; - - /* create new sadb_msg to reply. */ - len = sizeof(struct sadb_msg); - - KMALLOC(newmsg, struct sadb_msg *, len); - if (newmsg == NULL) { + if (sizeof(struct sadb_msg) > m->m_len + M_TRAILINGSPACE(m)) { #if IPSEC_DEBUG printf("key_spdflush: No more memory.\n"); #endif - msg0->sadb_msg_errno = ENOBUFS; - return NULL; + return key_senderror(so, m, ENOBUFS); } - bzero((caddr_t)newmsg, len); - bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0)); + if (m->m_next) + m_freem(m->m_next); + m->m_next = NULL; + m->m_pkthdr.len = m->m_len = PFKEY_ALIGN8(sizeof(struct sadb_msg)); + newmsg = mtod(m, struct sadb_msg *); newmsg->sadb_msg_errno = 0; - newmsg->sadb_msg_len = PFKEY_UNIT64(len); + newmsg->sadb_msg_len = PFKEY_UNIT64(m->m_pkthdr.len); - return(newmsg); - } + return key_sendup_mbuf(so, m, KEY_SENDUP_ALL); } /* @@ -2013,28 +2274,23 @@ key_spdflush(mhp) * ..... * to the ikmpd. * - * IN: mhp: pointer to the pointer to each header. - * OUT: other if success, return pointer to the message to send. - * 0 if fail. + * m will always be freed. */ static int -key_spddump(mhp, so, target) - caddr_t *mhp; +key_spddump(so, m, mhp) struct socket *so; - int target; + struct mbuf *m; + const struct sadb_msghdr *mhp; { - struct sadb_msg *msg0; struct secpolicy *sp; int cnt; u_int dir; - struct mbuf *m; + struct mbuf *n; /* sanity check */ - if (mhp == NULL || mhp[0] == NULL) + if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_spddump: NULL pointer is passed.\n"); - msg0 = (struct sadb_msg *)mhp[0]; - /* search SPD entry and get buffer size. */ cnt = 0; for (dir = 0; dir < IPSEC_DIR_MAX; dir++) { @@ -2044,19 +2300,20 @@ key_spddump(mhp, so, target) } if (cnt == 0) - return ENOENT; + return key_senderror(so, m, ENOENT); for (dir = 0; dir < IPSEC_DIR_MAX; dir++) { LIST_FOREACH(sp, &sptree[dir], chain) { --cnt; - m = key_setdumpsp(sp, SADB_X_SPDDUMP, - cnt, msg0->sadb_msg_pid); + n = key_setdumpsp(sp, SADB_X_SPDDUMP, cnt, + mhp->msg->sadb_msg_pid); - if (m) - key_sendup_mbuf(so, m, target); + if (n) + key_sendup_mbuf(so, n, KEY_SENDUP_ONE); } } + m_freem(m); return 0; } @@ -2066,108 +2323,53 @@ key_setdumpsp(sp, type, seq, pid) u_int8_t type; u_int32_t seq, pid; { - struct mbuf *m; - u_int tlen; - - /* XXX it would be better to avoid pre-computing length */ - tlen = key_getspmsglen(sp); - - /* XXX maybe it's a wrong idea to insist on cluster? */ - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m != NULL) { - MCLGET(m, M_DONTWAIT); - if ((m->m_flags & M_EXT) == 0) { - m_freem(m); - m = NULL; - } - } - if (m == NULL) - return NULL; /*ENOBUFS*/ - - m->m_pkthdr.len = m->m_len = 0; - m->m_next = NULL; - - /* sadb_msg->sadb_msg_len must be filled afterwards */ - if (key_setsadbmsg_m(m, type, 0, SADB_SATYPE_UNSPEC, seq, pid, - IPSEC_MODE_ANY, 0, 0, sp->refcnt) != 0) { - m_freem(m); - return NULL; - } - - if (key_setsadbaddr_m(m, SADB_EXT_ADDRESS_SRC, - (struct sockaddr *)&sp->spidx.src, sp->spidx.prefs, - sp->spidx.ul_proto) != 0) { - m_freem(m); - return NULL; - } + struct mbuf *result = NULL, *m; - if (key_setsadbaddr_m(m, SADB_EXT_ADDRESS_DST, - (struct sockaddr *)&sp->spidx.dst, sp->spidx.prefd, - sp->spidx.ul_proto) != 0) { - m_freem(m); - return NULL; - } + m = key_setsadbmsg(type, 0, SADB_SATYPE_UNSPEC, seq, pid, sp->refcnt); + if (!m) + goto fail; + result = m; - { - struct mbuf *n; - struct sadb_x_policy *tmp; + m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC, + (struct sockaddr *)&sp->spidx.src, sp->spidx.prefs, + sp->spidx.ul_proto); + if (!m) + goto fail; + m_cat(result, m); - n = key_sp2msg(sp); - if (!n || n->m_len < sizeof(*tmp)) { -#if IPSEC_DEBUG - printf("key_setdumpsp: No more memory.\n"); -#endif - m_freem(m); - if (n) - m_freem(n); - return NULL; - } + m = key_setsadbaddr(SADB_EXT_ADDRESS_DST, + (struct sockaddr *)&sp->spidx.dst, sp->spidx.prefd, + sp->spidx.ul_proto); + if (!m) + goto fail; + m_cat(result, m); - tmp = mtod(n, struct sadb_x_policy *); + m = key_sp2msg(sp); + if (!m) + goto fail; + m_cat(result, m); - /* validity check */ - if (key_getspreqmsglen(sp) != PFKEY_UNUNIT64(tmp->sadb_x_policy_len) - || n->m_len != PFKEY_UNUNIT64(tmp->sadb_x_policy_len)) - panic("key_setdumpsp: length mismatch." - "sp:%d msg:%d\n", - key_getspreqmsglen(sp), - PFKEY_UNUNIT64(tmp->sadb_x_policy_len)); - - m_cat(m, n); - m->m_pkthdr.len += n->m_len; - } + if ((result->m_flags & M_PKTHDR) == 0) + goto fail; - if (m->m_len < sizeof(struct sadb_msg)) { - m = m_pullup(m, sizeof(struct sadb_msg)); - if (m == NULL) - return NULL; + if (result->m_len < sizeof(struct sadb_msg)) { + result = m_pullup(result, sizeof(struct sadb_msg)); + if (result == NULL) + goto fail; } - mtod(m, struct sadb_msg *)->sadb_msg_len = - PFKEY_UNIT64(m->m_pkthdr.len); - - return m; -} -/* get sadb message length for a SP. */ -static u_int -key_getspmsglen(sp) - struct secpolicy *sp; -{ - u_int tlen; + result->m_pkthdr.len = 0; + for (m = result; m; m = m->m_next) + result->m_pkthdr.len += m->m_len; - /* sanity check */ - if (sp == NULL) - panic("key_getspmsglen: NULL pointer is passed.\n"); + mtod(result, struct sadb_msg *)->sadb_msg_len = + PFKEY_UNIT64(result->m_pkthdr.len); - tlen = (sizeof(struct sadb_msg) - + sizeof(struct sadb_address) - + PFKEY_ALIGN8(_SALENBYAF(sp->spidx.src.ss_family)) - + sizeof(struct sadb_address) - + PFKEY_ALIGN8(_SALENBYAF(sp->spidx.dst.ss_family))); + return result; - tlen += key_getspreqmsglen(sp); - - return tlen; +fail: + m_freem(result); + return NULL; } /* @@ -2202,6 +2404,123 @@ key_getspreqmsglen(sp) return tlen; } +/* + * SADB_SPDEXPIRE processing + * send + * + * to KMD by PF_KEY. + * + * OUT: 0 : succeed + * others : error number + */ +static int +key_spdexpire(sp) + struct secpolicy *sp; +{ + int s; + struct mbuf *result = NULL, *m; + int len; + int error = -1; + struct sadb_lifetime *lt; + + /* XXX: Why do we lock ? */ + s = splnet(); /*called from softclock()*/ + + /* sanity check */ + if (sp == NULL) + panic("key_spdexpire: NULL pointer is passed.\n"); + + /* set msg header */ + m = key_setsadbmsg(SADB_X_SPDEXPIRE, 0, 0, 0, 0, 0); + if (!m) { + error = ENOBUFS; + goto fail; + } + result = m; + + /* create lifetime extension (current and hard) */ + len = PFKEY_ALIGN8(sizeof(*lt)) * 2; + m = key_alloc_mbuf(len); + if (!m || m->m_next) { /*XXX*/ + if (m) + m_freem(m); + error = ENOBUFS; + goto fail; + } + bzero(mtod(m, caddr_t), len); + lt = mtod(m, struct sadb_lifetime *); + lt->sadb_lifetime_len = PFKEY_UNIT64(sizeof(struct sadb_lifetime)); + lt->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT; + lt->sadb_lifetime_allocations = 0; + lt->sadb_lifetime_bytes = 0; + lt->sadb_lifetime_addtime = sp->created; + lt->sadb_lifetime_usetime = sp->lastused; + lt = (struct sadb_lifetime *)(mtod(m, caddr_t) + len / 2); + lt->sadb_lifetime_len = PFKEY_UNIT64(sizeof(struct sadb_lifetime)); + lt->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; + lt->sadb_lifetime_allocations = 0; + lt->sadb_lifetime_bytes = 0; + lt->sadb_lifetime_addtime = sp->lifetime; + lt->sadb_lifetime_usetime = sp->validtime; + m_cat(result, m); + + /* set sadb_address for source */ + m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC, + (struct sockaddr *)&sp->spidx.src, + sp->spidx.prefs, sp->spidx.ul_proto); + if (!m) { + error = ENOBUFS; + goto fail; + } + m_cat(result, m); + + /* set sadb_address for destination */ + m = key_setsadbaddr(SADB_EXT_ADDRESS_DST, + (struct sockaddr *)&sp->spidx.dst, + sp->spidx.prefd, sp->spidx.ul_proto); + if (!m) { + error = ENOBUFS; + goto fail; + } + m_cat(result, m); + + /* set secpolicy */ + m = key_sp2msg(sp); + if (!m) { + error = ENOBUFS; + goto fail; + } + m_cat(result, m); + + if ((result->m_flags & M_PKTHDR) == 0) { + error = EINVAL; + goto fail; + } + + if (result->m_len < sizeof(struct sadb_msg)) { + result = m_pullup(result, sizeof(struct sadb_msg)); + if (result == NULL) { + error = ENOBUFS; + goto fail; + } + } + + result->m_pkthdr.len = 0; + for (m = result; m; m = m->m_next) + result->m_pkthdr.len += m->m_len; + + mtod(result, struct sadb_msg *)->sadb_msg_len = + PFKEY_UNIT64(result->m_pkthdr.len); + + return key_sendup_mbuf(NULL, result, KEY_SENDUP_REGISTERED); + + fail: + if (result) + m_freem(result); + splx(s); + return error; +} + /* %%% SAD management */ /* * allocating a memory for new SA head, and copy from the values of mhp. @@ -2247,11 +2566,7 @@ key_delsah(sah) if (sah == NULL) panic("key_delsah: NULL pointer is passed.\n"); -#ifdef __NetBSD__ - s = splsoftnet(); /*called from softclock()*/ -#else s = splnet(); /*called from softclock()*/ -#endif /* searching all SA registerd in the secindex. */ for (stateidx = 0; @@ -2289,7 +2604,7 @@ key_delsah(sah) } if (sah->sa_route.ro_rt) { - RTFREE(sah->sa_route.ro_rt); + rtfree(sah->sa_route.ro_rt); sah->sa_route.ro_rt = (struct rtentry *)NULL; } @@ -2312,75 +2627,84 @@ key_delsah(sah) * not to call key_setsava(). * OUT: NULL : fail * others : pointer to new secasvar. + * + * does not modify mbuf. does not free mbuf on error. */ static struct secasvar * -key_newsav(mhp, sah) - caddr_t *mhp; +key_newsav(m, mhp, sah, errp) + struct mbuf *m; + const struct sadb_msghdr *mhp; struct secashead *sah; + int *errp; { struct secasvar *newsav; - struct sadb_msg *msg0; + const struct sadb_sa *xsa; /* sanity check */ - if (mhp == NULL || mhp[0] == NULL || sah == NULL) + if (m == NULL || mhp == NULL || mhp->msg == NULL || sah == NULL) panic("key_newsa: NULL pointer is passed.\n"); - msg0 = (struct sadb_msg *)mhp[0]; - KMALLOC(newsav, struct secasvar *, sizeof(struct secasvar)); if (newsav == NULL) { #if IPSEC_DEBUG printf("key_newsa: No more memory.\n"); #endif - msg0->sadb_msg_errno = ENOBUFS; + *errp = ENOBUFS; return NULL; } bzero((caddr_t)newsav, sizeof(struct secasvar)); - switch (msg0->sadb_msg_type) { + switch (mhp->msg->sadb_msg_type) { case SADB_GETSPI: newsav->spi = 0; #if IPSEC_DOSEQCHECK /* sync sequence number */ - if (msg0->sadb_msg_seq == 0) + if (mhp->msg->sadb_msg_seq == 0) newsav->seq = (acq_seq = (acq_seq == ~0 ? 1 : ++acq_seq)); else #endif - newsav->seq = msg0->sadb_msg_seq; + newsav->seq = mhp->msg->sadb_msg_seq; break; case SADB_ADD: /* sanity check */ - if (mhp[SADB_EXT_SA] == NULL) { + if (mhp->ext[SADB_EXT_SA] == NULL) { KFREE(newsav); #if IPSEC_DEBUG printf("key_newsa: invalid message is passed.\n"); #endif - msg0->sadb_msg_errno = EINVAL; + *errp = EINVAL; return NULL; } - newsav->spi = ((struct sadb_sa *)mhp[SADB_EXT_SA])->sadb_sa_spi; - newsav->seq = msg0->sadb_msg_seq; + xsa = (const struct sadb_sa *)mhp->ext[SADB_EXT_SA]; + newsav->spi = xsa->sadb_sa_spi; + newsav->seq = mhp->msg->sadb_msg_seq; break; default: KFREE(newsav); - msg0->sadb_msg_errno = EINVAL; + *errp = EINVAL; return NULL; } /* copy sav values */ - if (msg0->sadb_msg_type != SADB_GETSPI && key_setsaval(newsav, mhp)) { - KFREE(newsav); - /* msg0->sadb_msg_errno is set at key_setsaval. */ - return NULL; + if (mhp->msg->sadb_msg_type != SADB_GETSPI) { + *errp = key_setsaval(newsav, m, mhp); + if (*errp) { + KFREE(newsav); + return NULL; + } } - /* reset tick */ - newsav->tick = 0; + /* reset created */ + { + struct timeval tv; + microtime(&tv); + newsav->created = tv.tv_sec; + } - newsav->pid = msg0->sadb_msg_pid; + newsav->pid = mhp->msg->sadb_msg_pid; /* add to satree */ newsav->sah = sah; @@ -2410,28 +2734,41 @@ key_delsav(sav) if (__LIST_CHAINED(sav)) LIST_REMOVE(sav, chain); - if (sav->key_auth != NULL) + if (sav->key_auth != NULL) { + bzero(_KEYBUF(sav->key_auth), _KEYLEN(sav->key_auth)); KFREE(sav->key_auth); - if (sav->key_enc != NULL) + sav->key_auth = NULL; + } + if (sav->key_enc != NULL) { + bzero(_KEYBUF(sav->key_enc), _KEYLEN(sav->key_enc)); KFREE(sav->key_enc); - if (sav->replay != NULL) + sav->key_enc = NULL; + } + if (sav->sched) { + bzero(sav->sched, sav->schedlen); + KFREE(sav->sched); + sav->sched = NULL; + } + if (sav->replay != NULL) { keydb_delsecreplay(sav->replay); - if (sav->lft_c != NULL) + sav->replay = NULL; + } + if (sav->lft_c != NULL) { KFREE(sav->lft_c); - if (sav->lft_h != NULL) + sav->lft_c = NULL; + } + if (sav->lft_h != NULL) { KFREE(sav->lft_h); - if (sav->lft_s != NULL) + sav->lft_h = NULL; + } + if (sav->lft_s != NULL) { KFREE(sav->lft_s); - if (sav->iv != NULL) + sav->lft_s = NULL; + } + if (sav->iv != NULL) { KFREE(sav->iv); -#if notyet - if (sav->misc1 != NULL) - KFREE(sav->misc1); - if (sav->misc2 != NULL) - KFREE(sav->misc2); - if (sav->misc3 != NULL) - KFREE(sav->misc3); -#endif + sav->iv = NULL; + } KFREE(sav); @@ -2453,8 +2790,8 @@ key_getsah(saidx) LIST_FOREACH(sah, &sahtree, chain) { if (sah->state == SADB_SASTATE_DEAD) continue; - if (key_cmpsaidx_exactly(&sah->saidx, saidx)) - return(sah); + if (key_cmpsaidx_withoutmode2(&sah->saidx, saidx)) + return sah; } return NULL; @@ -2485,8 +2822,7 @@ key_checkspidup(saidx, spi) /* check all SAD */ LIST_FOREACH(sah, &sahtree, chain) { - if (!key_ismyaddr(sah->saidx.dst.ss_family, - _INADDRBYSA(&sah->saidx.dst))) + if (!key_ismyaddr((struct sockaddr *)&sah->saidx.dst)) continue; sav = key_getsavbyspi(sah, spi); if (sav != NULL) @@ -2541,39 +2877,46 @@ key_getsavbyspi(sah, spi) * copy SA values from PF_KEY message except *SPI, SEQ, PID, STATE and TYPE*. * You must update these if need. * OUT: 0: success. - * 1: failure. set errno to (mhp[0])->sadb_msg_errno. + * !0: failure. + * + * does not modify mbuf. does not free mbuf on error. */ static int -key_setsaval(sav, mhp) +key_setsaval(sav, m, mhp) struct secasvar *sav; - caddr_t *mhp; + struct mbuf *m; + const struct sadb_msghdr *mhp; { - struct sadb_msg *msg0; +#if IPSEC_ESP + const struct esp_algorithm *algo; +#endif int error = 0; + struct timeval tv; /* sanity check */ - if (mhp == NULL || mhp[0] == NULL) + if (m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_setsaval: NULL pointer is passed.\n"); - msg0 = (struct sadb_msg *)mhp[0]; - /* initialization */ sav->replay = NULL; sav->key_auth = NULL; sav->key_enc = NULL; + sav->sched = NULL; + sav->schedlen = 0; sav->iv = NULL; sav->lft_c = NULL; sav->lft_h = NULL; sav->lft_s = NULL; -#if notyet - sav->misc1 = NULL; - sav->misc2 = NULL; - sav->misc3 = NULL; -#endif /* SA */ - if (mhp[SADB_EXT_SA] != NULL) { - struct sadb_sa *sa0 = (struct sadb_sa *)mhp[SADB_EXT_SA]; + if (mhp->ext[SADB_EXT_SA] != NULL) { + const struct sadb_sa *sa0; + + sa0 = (const struct sadb_sa *)mhp->ext[SADB_EXT_SA]; + if (mhp->extlen[SADB_EXT_SA] < sizeof(*sa0)) { + error = EINVAL; + goto fail; + } sav->alg_auth = sa0->sadb_sa_auth; sav->alg_enc = sa0->sadb_sa_encrypt; @@ -2587,33 +2930,32 @@ key_setsaval(sav, mhp) printf("key_setsaval: No more memory.\n"); #endif error = ENOBUFS; - goto err; + goto fail; } } } /* Authentication keys */ - if (mhp[SADB_EXT_KEY_AUTH] != NULL) { - struct sadb_key *key0; - u_int len; + if (mhp->ext[SADB_EXT_KEY_AUTH] != NULL) { + const struct sadb_key *key0; + int len; - key0 = (struct sadb_key *)mhp[SADB_EXT_KEY_AUTH]; - len = PFKEY_UNUNIT64(key0->sadb_key_len); + key0 = (const struct sadb_key *)mhp->ext[SADB_EXT_KEY_AUTH]; + len = mhp->extlen[SADB_EXT_KEY_AUTH]; error = 0; - if (len < sizeof(struct sadb_key)) + if (len < sizeof(*key0)) { error = EINVAL; - switch (msg0->sadb_msg_satype) { + goto fail; + } + switch (mhp->msg->sadb_msg_satype) { case SADB_SATYPE_AH: case SADB_SATYPE_ESP: - if (len == sizeof(struct sadb_key) - && sav->alg_auth != SADB_AALG_NULL) { + if (len == PFKEY_ALIGN8(sizeof(struct sadb_key)) && + sav->alg_auth != SADB_X_AALG_NULL) error = EINVAL; - } break; case SADB_X_SATYPE_IPCOMP: - error = EINVAL; - break; default: error = EINVAL; break; @@ -2622,7 +2964,7 @@ key_setsaval(sav, mhp) #if IPSEC_DEBUG printf("key_setsaval: invalid key_auth values.\n"); #endif - goto err; + goto fail; } sav->key_auth = (struct sadb_key *)key_newbuf(key0, len); @@ -2631,36 +2973,45 @@ key_setsaval(sav, mhp) printf("key_setsaval: No more memory.\n"); #endif error = ENOBUFS; - goto err; + goto fail; } - - /* make length shift up for kernel*/ - sav->key_auth->sadb_key_len = len; } /* Encryption key */ - if (mhp[SADB_EXT_KEY_ENCRYPT] != NULL) { - struct sadb_key *key0; - u_int len; + if (mhp->ext[SADB_EXT_KEY_ENCRYPT] != NULL) { + const struct sadb_key *key0; + int len; - key0 = (struct sadb_key *)mhp[SADB_EXT_KEY_ENCRYPT]; - len = PFKEY_UNUNIT64(key0->sadb_key_len); + key0 = (const struct sadb_key *)mhp->ext[SADB_EXT_KEY_ENCRYPT]; + len = mhp->extlen[SADB_EXT_KEY_ENCRYPT]; error = 0; - if (len < sizeof(struct sadb_key)) + if (len < sizeof(*key0)) { error = EINVAL; - switch (msg0->sadb_msg_satype) { + goto fail; + } + switch (mhp->msg->sadb_msg_satype) { case SADB_SATYPE_ESP: - if (len == sizeof(struct sadb_key) - && sav->alg_enc != SADB_EALG_NULL) { + if (len == PFKEY_ALIGN8(sizeof(struct sadb_key)) && + sav->alg_enc != SADB_EALG_NULL) { error = EINVAL; + break; + } + sav->key_enc = (struct sadb_key *)key_newbuf(key0, len); + if (sav->key_enc == NULL) { +#if IPSEC_DEBUG + printf("key_setsaval: No more memory.\n"); +#endif + error = ENOBUFS; + goto fail; } - break; - case SADB_SATYPE_AH: - error = EINVAL; break; case SADB_X_SATYPE_IPCOMP: + if (len != PFKEY_ALIGN8(sizeof(struct sadb_key))) + error = EINVAL; + sav->key_enc = NULL; /*just in case*/ break; + case SADB_SATYPE_AH: default: error = EINVAL; break; @@ -2669,213 +3020,149 @@ key_setsaval(sav, mhp) #if IPSEC_DEBUG printf("key_setsatval: invalid key_enc value.\n"); #endif - goto err; - } - - sav->key_enc = (struct sadb_key *)key_newbuf(key0, len); - if (sav->key_enc == NULL) { -#if IPSEC_DEBUG - printf("key_setsaval: No more memory.\n"); -#endif - error = ENOBUFS; - goto err; + goto fail; } - - /* make length shift up for kernel*/ - sav->key_enc->sadb_key_len = len; } /* set iv */ sav->ivlen = 0; - switch (msg0->sadb_msg_satype) { + switch (mhp->msg->sadb_msg_satype) { case SADB_SATYPE_ESP: #if IPSEC_ESP - { - struct esp_algorithm *algo; - - algo = &esp_algorithms[sav->alg_enc]; + algo = esp_algorithm_lookup(sav->alg_enc); if (algo && algo->ivlen) - sav->ivlen = (*algo->ivlen)(sav); + sav->ivlen = (*algo->ivlen)(algo, sav); + if (sav->ivlen == 0) + break; KMALLOC(sav->iv, caddr_t, sav->ivlen); if (sav->iv == 0) { #if IPSEC_DEBUG printf("key_setsaval: No more memory.\n"); #endif error = ENOBUFS; - goto err; + goto fail; } - /* initialize ? */ - break; - } -#else - break; + + /* initialize */ + key_randomfill(sav->iv, sav->ivlen); #endif + break; case SADB_SATYPE_AH: -#if 1 /*nonstandard*/ case SADB_X_SATYPE_IPCOMP: -#endif break; default: #if IPSEC_DEBUG printf("key_setsaval: invalid SA type.\n"); #endif error = EINVAL; - goto err; + goto fail; } - /* reset tick */ - sav->tick = 0; + /* reset created */ + microtime(&tv); + sav->created = tv.tv_sec; /* make lifetime for CURRENT */ - { - struct timeval tv; - KMALLOC(sav->lft_c, struct sadb_lifetime *, - sizeof(struct sadb_lifetime)); + sizeof(struct sadb_lifetime)); if (sav->lft_c == NULL) { #if IPSEC_DEBUG printf("key_setsaval: No more memory.\n"); #endif error = ENOBUFS; - goto err; + goto fail; } microtime(&tv); sav->lft_c->sadb_lifetime_len = - PFKEY_UNIT64(sizeof(struct sadb_lifetime)); + PFKEY_UNIT64(sizeof(struct sadb_lifetime)); sav->lft_c->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT; sav->lft_c->sadb_lifetime_allocations = 0; sav->lft_c->sadb_lifetime_bytes = 0; sav->lft_c->sadb_lifetime_addtime = tv.tv_sec; sav->lft_c->sadb_lifetime_usetime = 0; - } /* lifetimes for HARD and SOFT */ { - struct sadb_lifetime *lft0; + const struct sadb_lifetime *lft0; - lft0 = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD]; + lft0 = (struct sadb_lifetime *)mhp->ext[SADB_EXT_LIFETIME_HARD]; if (lft0 != NULL) { + if (mhp->extlen[SADB_EXT_LIFETIME_HARD] < sizeof(*lft0)) { + error = EINVAL; + goto fail; + } sav->lft_h = (struct sadb_lifetime *)key_newbuf(lft0, - sizeof(*lft0)); + sizeof(*lft0)); if (sav->lft_h == NULL) { #if IPSEC_DEBUG printf("key_setsaval: No more memory.\n"); #endif error = ENOBUFS; - goto err; + goto fail; } /* to be initialize ? */ } - lft0 = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT]; + lft0 = (struct sadb_lifetime *)mhp->ext[SADB_EXT_LIFETIME_SOFT]; if (lft0 != NULL) { + if (mhp->extlen[SADB_EXT_LIFETIME_SOFT] < sizeof(*lft0)) { + error = EINVAL; + goto fail; + } sav->lft_s = (struct sadb_lifetime *)key_newbuf(lft0, - sizeof(*lft0)); + sizeof(*lft0)); if (sav->lft_s == NULL) { #if IPSEC_DEBUG printf("key_setsaval: No more memory.\n"); #endif error = ENOBUFS; - goto err; + goto fail; } /* to be initialize ? */ } } -#if notyet - /* pre-processing for DES */ - switch (sav->alg_enc) { - case SADB_EALG_DESCBC: - if (des_key_sched((C_Block *)_KEYBUF(sav->key_enc), - (des_key_schedule)sav->misc1) != 0) { -#if IPSEC_DEBUG - printf("key_setsaval: error des_key_sched.\n"); -#endif - sav->misc1 = NULL; - /* THROUGH */ - } - break; - case SADB_EALG_3DESCBC: - if (des_key_sched((C_Block *)_KEYBUF(sav->key_enc), - (des_key_schedule)sav->misc1) != 0 - || des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 8), - (des_key_schedule)sav->misc2) != 0 - || des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 16), - (des_key_schedule)sav->misc3) != 0) { -#if IPSEC_DEBUG - printf("key_setsaval: error des_key_sched.\n"); -#endif - sav->misc1 = NULL; - sav->misc2 = NULL; - sav->misc3 = NULL; - /* THROUGH */ - } - } -#endif - - msg0->sadb_msg_errno = 0; return 0; - err: + fail: /* initialization */ - if (sav->replay != NULL) + if (sav->replay != NULL) { keydb_delsecreplay(sav->replay); - if (sav->key_auth != NULL) + sav->replay = NULL; + } + if (sav->key_auth != NULL) { KFREE(sav->key_auth); - if (sav->key_enc != NULL) + sav->key_auth = NULL; + } + if (sav->key_enc != NULL) { KFREE(sav->key_enc); - if (sav->iv != NULL) + sav->key_enc = NULL; + } + if (sav->sched) { + KFREE(sav->sched); + sav->sched = NULL; + } + if (sav->iv != NULL) { KFREE(sav->iv); - if (sav->lft_c != NULL) + sav->iv = NULL; + } + if (sav->lft_c != NULL) { KFREE(sav->lft_c); - if (sav->lft_h != NULL) + sav->lft_c = NULL; + } + if (sav->lft_h != NULL) { KFREE(sav->lft_h); - if (sav->lft_s != NULL) + sav->lft_h = NULL; + } + if (sav->lft_s != NULL) { KFREE(sav->lft_s); -#if notyet - if (sav->misc1 != NULL) - KFREE(sav->misc1); - if (sav->misc2 != NULL) - KFREE(sav->misc2); - if (sav->misc3 != NULL) - KFREE(sav->misc3); -#endif - - msg0->sadb_msg_errno = error; - return 1; -} + sav->lft_s = NULL; + } -/* - * get message buffer length. - */ -static u_int -key_getmsglen(sav) - struct secasvar *sav; -{ - int len = sizeof(struct sadb_msg); - - len += sizeof(struct sadb_sa); - len += (sizeof(struct sadb_address) - + PFKEY_ALIGN8(_SALENBYAF(sav->sah->saidx.src.ss_family))); - len += (sizeof(struct sadb_address) - + PFKEY_ALIGN8(_SALENBYAF(sav->sah->saidx.dst.ss_family))); - - if (sav->key_auth != NULL) - len += sav->key_auth->sadb_key_len; - if (sav->key_enc != NULL) - len += sav->key_enc->sadb_key_len; - - if (sav->lft_c != NULL) - len += sizeof(struct sadb_lifetime); - if (sav->lft_h != NULL) - len += sizeof(struct sadb_lifetime); - if (sav->lft_s != NULL) - len += sizeof(struct sadb_lifetime); - - return len; + return error; } /* @@ -2894,11 +3181,17 @@ key_mature(sav) mature = 0; /* check SPI value */ - if (ntohl(sav->spi) >= 0 && ntohl(sav->spi) <= 255) { + switch (sav->sah->saidx.proto) { + case IPPROTO_ESP: + case IPPROTO_AH: + if (ntohl(sav->spi) >= 0 && ntohl(sav->spi) <= 255) { #if IPSEC_DEBUG - printf("key_mature: illegal range of SPI %d.\n", sav->spi); + printf("key_mature: illegal range of SPI %u.\n", + (u_int32_t)ntohl(sav->spi)); #endif - return EINVAL; + return EINVAL; + } + break; } /* check satype */ @@ -2913,7 +3206,10 @@ key_mature(sav) #endif return EINVAL; } - checkmask = 3; + if (sav->alg_auth == SADB_AALG_NONE) + checkmask = 1; + else + checkmask = 3; mustmask = 1; break; case IPPROTO_AH: @@ -2935,7 +3231,6 @@ key_mature(sav) checkmask = 2; mustmask = 2; break; -#if 1 /*nonstandard*/ case IPPROTO_IPCOMP: if (sav->alg_auth != SADB_AALG_NONE) { #if IPSEC_DEBUG @@ -2954,7 +3249,6 @@ key_mature(sav) checkmask = 4; mustmask = 4; break; -#endif default: #if IPSEC_DEBUG printf("key_mature: Invalid satype.\n"); @@ -2964,19 +3258,11 @@ key_mature(sav) /* check authentication algorithm */ if ((checkmask & 2) != 0) { - struct ah_algorithm *algo; + const struct ah_algorithm *algo; int keylen; - /* XXX: should use algorithm map to check. */ - switch (sav->alg_auth) { - case SADB_AALG_NONE: - case SADB_AALG_MD5HMAC: - case SADB_AALG_SHA1HMAC: - case SADB_AALG_MD5: - case SADB_AALG_SHA: - case SADB_AALG_NULL: - break; - default: + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { #if IPSEC_DEBUG printf("key_mature: " "unknown authentication algorithm.\n"); @@ -2985,8 +3271,6 @@ key_mature(sav) } /* algorithm-dependent check */ - algo = &ah_algorithms[sav->alg_auth]; - if (sav->key_auth) keylen = sav->key_auth->sadb_key_bits; else @@ -3019,19 +3303,11 @@ key_mature(sav) /* check encryption algorithm */ if ((checkmask & 1) != 0) { #if IPSEC_ESP - struct esp_algorithm *algo; + const struct esp_algorithm *algo; int keylen; - switch (sav->alg_enc) { - case SADB_EALG_NONE: - case SADB_EALG_DESCBC: - case SADB_EALG_3DESCBC: - case SADB_EALG_NULL: - case SADB_EALG_BLOWFISHCBC: - case SADB_EALG_CAST128CBC: - case SADB_EALG_RC5CBC: - break; - default: + algo = esp_algorithm_lookup(sav->alg_enc); + if (!algo) { #if IPSEC_DEBUG printf("key_mature: unknown encryption algorithm.\n"); #endif @@ -3039,8 +3315,6 @@ key_mature(sav) } /* algorithm-dependent check */ - algo = &esp_algorithms[sav->alg_enc]; - if (sav->key_enc) keylen = sav->key_enc->sadb_key_bits; else @@ -3078,28 +3352,13 @@ key_mature(sav) /* check compression algorithm */ if ((checkmask & 4) != 0) { - struct ipcomp_algorithm *algo; + const struct ipcomp_algorithm *algo; - switch (sav->alg_enc) { - case SADB_X_CALG_NONE: - case SADB_X_CALG_OUI: - case SADB_X_CALG_DEFLATE: - case SADB_X_CALG_LZS: - break; - default: + /* algorithm-dependent check */ + algo = ipcomp_algorithm_lookup(sav->alg_enc); + if (!algo) { #if IPSEC_DEBUG printf("key_mature: unknown compression algorithm.\n"); -#endif - return EINVAL; - } - - /* algorithm-dependent check */ - algo = &ipcomp_algorithms[sav->alg_enc]; - - if (!(algo->compress && algo->decompress)) { -#if IPSEC_DEBUG - printf("key_mature: " - "unsupported compression algorithm.\n"); #endif return EINVAL; } @@ -3112,148 +3371,184 @@ key_mature(sav) /* * subroutine for SADB_GET and SADB_DUMP. - * the buf must be allocated sufficent space. */ -static u_int -key_setdumpsa(newmsg, sav, type, satype, seq, pid) - struct sadb_msg *newmsg; +static struct mbuf * +key_setdumpsa(sav, type, satype, seq, pid) struct secasvar *sav; u_int8_t type, satype; u_int32_t seq, pid; { - u_int tlen; - caddr_t p; + struct mbuf *result = NULL, *tres = NULL, *m; + int l = 0; int i; + void *p; + int dumporder[] = { + SADB_EXT_SA, SADB_X_EXT_SA2, + SADB_EXT_LIFETIME_HARD, SADB_EXT_LIFETIME_SOFT, + SADB_EXT_LIFETIME_CURRENT, SADB_EXT_ADDRESS_SRC, + SADB_EXT_ADDRESS_DST, SADB_EXT_ADDRESS_PROXY, SADB_EXT_KEY_AUTH, + SADB_EXT_KEY_ENCRYPT, SADB_EXT_IDENTITY_SRC, + SADB_EXT_IDENTITY_DST, SADB_EXT_SENSITIVITY, + }; + + m = key_setsadbmsg(type, 0, satype, seq, pid, sav->refcnt); + if (m == NULL) + goto fail; + result = m; - tlen = key_getmsglen(sav); - - p = key_setsadbmsg((caddr_t)newmsg, type, tlen, - satype, seq, pid, - sav->sah->saidx.mode, sav->sah->saidx.reqid, - 0, sav->refcnt); - - for (i = 1; i <= SADB_EXT_MAX; i++) { - switch (i) { + for (i = sizeof(dumporder)/sizeof(dumporder[0]) - 1; i >= 0; i--) { + m = NULL; + p = NULL; + switch (dumporder[i]) { case SADB_EXT_SA: - p = key_setsadbsa(p, sav); + m = key_setsadbsa(sav); + if (!m) + goto fail; + break; + + case SADB_X_EXT_SA2: + m = key_setsadbxsa2(sav->sah->saidx.mode, + sav->sah->saidx.reqid); + if (!m) + goto fail; break; case SADB_EXT_ADDRESS_SRC: - p = key_setsadbaddr(p, - SADB_EXT_ADDRESS_SRC, - (struct sockaddr *)&sav->sah->saidx.src, - _INALENBYAF(sav->sah->saidx.src.ss_family) << 3, - IPSEC_ULPROTO_ANY); + m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC, + (struct sockaddr *)&sav->sah->saidx.src, + sav->sah->saidx.src.ss_len << 3, IPSEC_ULPROTO_ANY); + if (!m) + goto fail; break; case SADB_EXT_ADDRESS_DST: - p = key_setsadbaddr(p, - SADB_EXT_ADDRESS_DST, - (struct sockaddr *)&sav->sah->saidx.dst, - _INALENBYAF(sav->sah->saidx.dst.ss_family) << 3, - IPSEC_ULPROTO_ANY); + m = key_setsadbaddr(SADB_EXT_ADDRESS_DST, + (struct sockaddr *)&sav->sah->saidx.dst, + sav->sah->saidx.dst.ss_len << 3, IPSEC_ULPROTO_ANY); + if (!m) + goto fail; break; case SADB_EXT_KEY_AUTH: - { - u_int len; - if (sav->key_auth == NULL) break; - len = sav->key_auth->sadb_key_len; /* real length */ - bcopy((caddr_t)sav->key_auth, p, len); - ((struct sadb_ext *)p)->sadb_ext_len = PFKEY_UNIT64(len); - p += len; - } + if (!sav->key_auth) + continue; + l = PFKEY_UNUNIT64(sav->key_auth->sadb_key_len); + p = sav->key_auth; break; case SADB_EXT_KEY_ENCRYPT: - { - u_int len; - if (sav->key_enc == NULL) break; - len = sav->key_enc->sadb_key_len; /* real length */ - bcopy((caddr_t)sav->key_enc, p, len); - ((struct sadb_ext *)p)->sadb_ext_len = PFKEY_UNIT64(len); - p += len; - } - break;; + if (!sav->key_enc) + continue; + l = PFKEY_UNUNIT64(sav->key_enc->sadb_key_len); + p = sav->key_enc; + break; case SADB_EXT_LIFETIME_CURRENT: - if (sav->lft_c == NULL) break; - p = key_setsadbext(p, (caddr_t)sav->lft_c); + if (!sav->lft_c) + continue; + l = PFKEY_UNUNIT64(((struct sadb_ext *)sav->lft_c)->sadb_ext_len); + p = sav->lft_c; break; case SADB_EXT_LIFETIME_HARD: - if (sav->lft_h == NULL) break; - p = key_setsadbext(p, (caddr_t)sav->lft_h); + if (!sav->lft_h) + continue; + l = PFKEY_UNUNIT64(((struct sadb_ext *)sav->lft_h)->sadb_ext_len); + p = sav->lft_h; break; case SADB_EXT_LIFETIME_SOFT: - if (sav->lft_s == NULL) break; - p = key_setsadbext(p, (caddr_t)sav->lft_s); + if (!sav->lft_s) + continue; + l = PFKEY_UNUNIT64(((struct sadb_ext *)sav->lft_s)->sadb_ext_len); + p = sav->lft_s; break; + case SADB_EXT_ADDRESS_PROXY: case SADB_EXT_IDENTITY_SRC: case SADB_EXT_IDENTITY_DST: /* XXX: should we brought from SPD ? */ case SADB_EXT_SENSITIVITY: default: - break; + continue; + } + + if ((!m && !p) || (m && p)) + goto fail; + if (p && tres) { + M_PREPEND(tres, l, M_DONTWAIT); + if (!tres) + goto fail; + bcopy(p, mtod(tres, caddr_t), l); + continue; } + if (p) { + m = key_alloc_mbuf(l); + if (!m) + goto fail; + m_copyback(m, 0, l, p); + } + + if (tres) + m_cat(m, tres); + tres = m; } - return tlen; -} + m_cat(result, tres); -#if 1 -static int -key_setsadbmsg_m(m, type, tlen, satype, seq, pid, mode, reqid, - reserved1, reserved2) - struct mbuf *m; - u_int8_t type, satype; - u_int16_t tlen; - u_int32_t seq; - pid_t pid; - u_int8_t mode; - u_int32_t reqid; - u_int8_t reserved1; - u_int32_t reserved2; -{ - caddr_t p; - const size_t len = sizeof(struct sadb_msg); + if (result->m_len < sizeof(struct sadb_msg)) { + result = m_pullup(result, sizeof(struct sadb_msg)); + if (result == NULL) + goto fail; + } - p = key_appendmbuf(m, len); - if (p == NULL) - return ENOBUFS; + result->m_pkthdr.len = 0; + for (m = result; m; m = m->m_next) + result->m_pkthdr.len += m->m_len; - if (key_setsadbmsg(p, type, tlen, satype, seq, pid, mode, reqid, - reserved1, reserved2)) - return 0; - else - return EINVAL; + mtod(result, struct sadb_msg *)->sadb_msg_len = + PFKEY_UNIT64(result->m_pkthdr.len); + + return result; + +fail: + m_freem(result); + m_freem(tres); + return NULL; } -#endif /* * set data into sadb_msg. - * `buf' must has been allocated sufficiently. */ -static caddr_t -key_setsadbmsg(buf, type, tlen, satype, seq, pid, mode, reqid, - reserved1, reserved2) - caddr_t buf; +static struct mbuf * +key_setsadbmsg(type, tlen, satype, seq, pid, reserved) u_int8_t type, satype; u_int16_t tlen; u_int32_t seq; pid_t pid; - u_int8_t mode; - u_int32_t reqid; - u_int8_t reserved1; - u_int32_t reserved2; + u_int16_t reserved; { + struct mbuf *m; struct sadb_msg *p; - u_int len; + int len; + + len = PFKEY_ALIGN8(sizeof(struct sadb_msg)); + if (len > MCLBYTES) + return NULL; + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m && len > MHLEN) { + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) { + m_freem(m); + m = NULL; + } + } + if (!m) + return NULL; + m->m_pkthdr.len = m->m_len = len; + m->m_next = NULL; - p = (struct sadb_msg *)buf; - len = sizeof(struct sadb_msg); + p = mtod(m, struct sadb_msg *); bzero(p, len); p->sadb_msg_version = PF_KEY_V2; @@ -3261,30 +3556,33 @@ key_setsadbmsg(buf, type, tlen, satype, seq, pid, mode, reqid, p->sadb_msg_errno = 0; p->sadb_msg_satype = satype; p->sadb_msg_len = PFKEY_UNIT64(tlen); - p->sadb_msg_mode = mode; - p->sadb_msg_reserved1 = reserved1; + p->sadb_msg_reserved = reserved; p->sadb_msg_seq = seq; p->sadb_msg_pid = (u_int32_t)pid; - p->sadb_msg_reqid = reqid; - p->sadb_msg_reserved2 = reserved2; - return(buf + len); + return m; } /* * copy secasvar data into sadb_address. - * `buf' must has been allocated sufficiently. */ -static caddr_t -key_setsadbsa(buf, sav) - caddr_t buf; +static struct mbuf * +key_setsadbsa(sav) struct secasvar *sav; { + struct mbuf *m; struct sadb_sa *p; - u_int len; + int len; + + len = PFKEY_ALIGN8(sizeof(struct sadb_sa)); + m = key_alloc_mbuf(len); + if (!m || m->m_next) { /*XXX*/ + if (m) + m_freem(m); + return NULL; + } - p = (struct sadb_sa *)buf; - len = sizeof(struct sadb_sa); + p = mtod(m, struct sadb_sa *); bzero(p, len); p->sadb_sa_len = PFKEY_UNIT64(len); @@ -3296,50 +3594,33 @@ key_setsadbsa(buf, sav) p->sadb_sa_encrypt = sav->alg_enc; p->sadb_sa_flags = sav->flags; - return(buf + len); -} - -#if 1 -static int -key_setsadbaddr_m(m, exttype, saddr, prefixlen, ul_proto) - struct mbuf *m; - u_int16_t exttype; - struct sockaddr *saddr; - u_int8_t prefixlen; - u_int16_t ul_proto; -{ - caddr_t p; - const size_t len = - sizeof(struct sadb_address) + PFKEY_ALIGN8(saddr->sa_len); - - p = key_appendmbuf(m, len); - if (p == NULL) - return ENOBUFS; - - if (key_setsadbaddr(p, exttype, saddr, prefixlen, ul_proto)) - return 0; - else - return EINVAL; + return m; } -#endif /* * set data into sadb_address. - * `buf' must has been allocated sufficiently. */ -static caddr_t -key_setsadbaddr(buf, exttype, saddr, prefixlen, ul_proto) - caddr_t buf; +static struct mbuf * +key_setsadbaddr(exttype, saddr, prefixlen, ul_proto) u_int16_t exttype; struct sockaddr *saddr; u_int8_t prefixlen; u_int16_t ul_proto; { + struct mbuf *m; struct sadb_address *p; size_t len; - p = (struct sadb_address *)buf; - len = sizeof(struct sadb_address) + PFKEY_ALIGN8(saddr->sa_len); + len = PFKEY_ALIGN8(sizeof(struct sadb_address)) + + PFKEY_ALIGN8(saddr->sa_len); + m = key_alloc_mbuf(len); + if (!m || m->m_next) { /*XXX*/ + if (m) + m_freem(m); + return NULL; + } + + p = mtod(m, struct sadb_address *); bzero(p, len); p->sadb_address_len = PFKEY_UNIT64(len); @@ -3348,28 +3629,37 @@ key_setsadbaddr(buf, exttype, saddr, prefixlen, ul_proto) p->sadb_address_prefixlen = prefixlen; p->sadb_address_reserved = 0; - bcopy(saddr, p + 1, saddr->sa_len); + bcopy(saddr, + mtod(m, caddr_t) + PFKEY_ALIGN8(sizeof(struct sadb_address)), + saddr->sa_len); - return(buf + len); + return m; } +#if 0 /* * set data into sadb_ident. - * `buf' must has been allocated sufficiently. */ -static caddr_t -key_setsadbident(buf, exttype, idtype, string, stringlen, id) - caddr_t buf; +static struct mbuf * +key_setsadbident(exttype, idtype, string, stringlen, id) u_int16_t exttype, idtype; caddr_t string; int stringlen; u_int64_t id; { + struct mbuf *m; struct sadb_ident *p; - u_int len; + size_t len; + + len = PFKEY_ALIGN8(sizeof(struct sadb_ident)) + PFKEY_ALIGN8(stringlen); + m = key_alloc_mbuf(len); + if (!m || m->m_next) { /*XXX*/ + if (m) + m_freem(m); + return NULL; + } - p = (struct sadb_ident *)buf; - len = sizeof(struct sadb_ident) + PFKEY_ALIGN8(stringlen); + p = mtod(m, struct sadb_ident *); bzero(p, len); p->sadb_ident_len = PFKEY_UNIT64(len); @@ -3378,27 +3668,70 @@ key_setsadbident(buf, exttype, idtype, string, stringlen, id) p->sadb_ident_reserved = 0; p->sadb_ident_id = id; - bcopy(string, p + 1, stringlen); + bcopy(string, + mtod(m, caddr_t) + PFKEY_ALIGN8(sizeof(struct sadb_ident)), + stringlen); + + return m; +} +#endif + +/* + * set data into sadb_x_sa2. + */ +static struct mbuf * +key_setsadbxsa2(mode, reqid) + u_int8_t mode; + u_int32_t reqid; +{ + struct mbuf *m; + struct sadb_x_sa2 *p; + size_t len; + + len = PFKEY_ALIGN8(sizeof(struct sadb_x_sa2)); + m = key_alloc_mbuf(len); + if (!m || m->m_next) { /*XXX*/ + if (m) + m_freem(m); + return NULL; + } + + p = mtod(m, struct sadb_x_sa2 *); + + bzero(p, len); + p->sadb_x_sa2_len = PFKEY_UNIT64(len); + p->sadb_x_sa2_exttype = SADB_X_EXT_SA2; + p->sadb_x_sa2_mode = mode; + p->sadb_x_sa2_reserved1 = 0; + p->sadb_x_sa2_reserved2 = 0; + p->sadb_x_sa2_reserved3 = 0; + p->sadb_x_sa2_reqid = reqid; - return(buf + len); + return m; } /* * set data into sadb_x_policy - * `buf' must has been allocated sufficiently. */ -static caddr_t -key_setsadbxpolicy(buf, type, dir, id) - caddr_t buf; +static struct mbuf * +key_setsadbxpolicy(type, dir, id) u_int16_t type; u_int8_t dir; u_int32_t id; { + struct mbuf *m; struct sadb_x_policy *p; - u_int len; + size_t len; - p = (struct sadb_x_policy *)buf; - len = sizeof(struct sadb_x_policy); + len = PFKEY_ALIGN8(sizeof(struct sadb_x_policy)); + m = key_alloc_mbuf(len); + if (!m || m->m_next) { /*XXX*/ + if (m) + m_freem(m); + return NULL; + } + + p = mtod(m, struct sadb_x_policy *); bzero(p, len); p->sadb_x_policy_len = PFKEY_UNIT64(len); @@ -3407,25 +3740,7 @@ key_setsadbxpolicy(buf, type, dir, id) p->sadb_x_policy_dir = dir; p->sadb_x_policy_id = id; - return(buf + len); -} - -/* - * copy buffer of any sadb extension type into sadb_ext. - * assume that sadb_ext_len shifted down >> 3. - * i.e. shift length up when setting length of extension. - */ -static caddr_t -key_setsadbext(p, ext) - caddr_t p, ext; -{ - u_int len; - - len = PFKEY_UNUNIT64(((struct sadb_ext *)ext)->sadb_ext_len); - - bcopy(ext, p, len); - - return(p + len); + return m; } /* %%% utilities */ @@ -3434,7 +3749,7 @@ key_setsadbext(p, ext) */ static void * key_newbuf(src, len) - void *src; + const void *src; u_int len; { caddr_t new; @@ -3446,7 +3761,7 @@ key_newbuf(src, len) #endif return NULL; } - bcopy((caddr_t)src, new, len); + bcopy(src, new, len); return new; } @@ -3456,36 +3771,37 @@ key_newbuf(src, len) * 0: false */ int -key_ismyaddr(family, addr) - u_int family; - caddr_t addr; +key_ismyaddr(sa) + struct sockaddr *sa; { +#if INET + struct sockaddr_in *sin; + struct in_ifaddr *ia; +#endif + /* sanity check */ - if (addr == NULL) + if (sa == NULL) panic("key_ismyaddr: NULL pointer is passed.\n"); - switch (family) { + switch (sa->sa_family) { +#if INET case AF_INET: - { - struct in_ifaddr *ia; - -#ifdef __NetBSD__ - for (ia = in_ifaddr.tqh_first; ia; ia = ia->ia_list.tqe_next) -#elif defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) + sin = (struct sockaddr_in *)sa; for (ia = in_ifaddrhead.tqh_first; ia; ia = ia->ia_link.tqe_next) -#else - for (ia = in_ifaddr; ia; ia = ia->ia_next) -#endif - if (bcmp(addr, - (caddr_t)&ia->ia_addr.sin_addr, - _INALENBYAF(family)) == 0) + { + if (sin->sin_family == ia->ia_addr.sin_family && + sin->sin_len == ia->ia_addr.sin_len && + sin->sin_addr.s_addr == ia->ia_addr.sin_addr.s_addr) + { return 1; - } + } + } break; +#endif #if INET6 case AF_INET6: - return key_ismyaddr6(addr); + return key_ismyaddr6((struct sockaddr_in6 *)sa); #endif } @@ -3502,87 +3818,37 @@ key_ismyaddr(family, addr) #include static int -key_ismyaddr6(addr) - caddr_t addr; +key_ismyaddr6(sin6) + struct sockaddr_in6 *sin6; { - struct in6_addr *a = (struct in6_addr *)addr; struct in6_ifaddr *ia; + struct in6_multi *in6m; for (ia = in6_ifaddr; ia; ia = ia->ia_next) { - if (bcmp(addr, (caddr_t)&ia->ia_addr.sin6_addr, - _INALENBYAF(AF_INET6)) == 0) { + if (key_sockaddrcmp((struct sockaddr *)&sin6, + (struct sockaddr *)&ia->ia_addr, 0) == 0) return 1; - } - - /* XXX Multicast */ - { - struct in6_multi *in6m = 0; -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) - IN6_LOOKUP_MULTI(*(struct in6_addr *)addr, ia->ia_ifp, in6m); -#else - for ((in6m) = ia->ia6_multiaddrs.lh_first; - (in6m) != NULL && - !IN6_ARE_ADDR_EQUAL(&(in6m)->in6m_addr, a); - (in6m) = in6m->in6m_entry.le_next) - continue; -#endif + /* + * XXX Multicast + * XXX why do we care about multlicast here while we don't care + * about IPv4 multicast?? + * XXX scope + */ + in6m = NULL; + IN6_LOOKUP_MULTI(sin6->sin6_addr, ia->ia_ifp, in6m); if (in6m) return 1; - } } /* loopback, just for safety */ - if (IN6_IS_ADDR_LOOPBACK(a)) - return 1; - -#if 0 - /* FAITH */ - if (ip6_keepfaith && - (a->s6_addr32[0] == ip6_faith_prefix.s6_addr32[0] && - a->s6_addr32[1] == ip6_faith_prefix.s6_addr32[1] && - a->s6_addr32[2] == ip6_faith_prefix.s6_addr32[2])) + if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) return 1; -#endif - - /* XXX anycast */ return 0; } #endif /*INET6*/ -#if 0 -/* checking address is whether loopback or not. - * OUT: 1: true - * 0: false - */ -static int -key_isloopback(family, addr) - u_int family; - caddr_t addr; -{ - switch (family) { - case PF_INET: - if (((caddr_t)addr)[0] == IN_LOOPBACKNET) - return 1; - break; -#if INET6 - case PF_INET6: - if (IN6_IS_ADDR_LOOPBACK((struct in6_addr *)addr)) - return 1; - break; -#endif /* INET6 */ - default: -#if IPSEC_DEBUG - printf("key_isloopback: unknown address family=%d.\n", family); -#endif - return 0; - } - - return 0; -} -#endif - /* * compare two secasindex structure exactly. * IN: @@ -3608,8 +3874,8 @@ key_cmpsaidx_exactly(saidx0, saidx1) || saidx0->reqid != saidx1->reqid) return 0; - if (bcmp(&saidx0->src, &saidx1->src, saidx0->src.ss_len) != 0 - || bcmp(&saidx0->dst, &saidx1->dst, saidx0->dst.ss_len) != 0) + if (bcmp(&saidx0->src, &saidx1->src, saidx0->src.ss_len) != 0 || + bcmp(&saidx0->dst, &saidx1->dst, saidx0->dst.ss_len) != 0) return 0; return 1; @@ -3636,118 +3902,298 @@ key_cmpsaidx_withmode(saidx0, saidx1) if (saidx0 == NULL || saidx1 == NULL) return 0; - if (saidx0->proto != saidx1->proto - || saidx0->src.ss_family != saidx1->src.ss_family - || saidx0->dst.ss_family != saidx1->dst.ss_family) + if (saidx0->proto != saidx1->proto) return 0; /* * If reqid of SPD is non-zero, unique SA is required. * The result must be of same reqid in this case. */ - if (saidx1->reqid != 0 - && saidx0->reqid != saidx1->reqid) + if (saidx1->reqid != 0 && saidx0->reqid != saidx1->reqid) return 0; - if (saidx0->mode != IPSEC_MODE_ANY - && saidx0->mode != saidx1->mode) + if (saidx0->mode != IPSEC_MODE_ANY && saidx0->mode != saidx1->mode) return 0; - { - int sa_len = _INALENBYAF(saidx0->src.ss_family); - - if (bcmp(_INADDRBYSA(&saidx0->src), _INADDRBYSA(&saidx1->src), sa_len) - || bcmp(_INADDRBYSA(&saidx0->dst), _INADDRBYSA(&saidx1->dst), sa_len)) + if (key_sockaddrcmp((struct sockaddr *)&saidx0->src, + (struct sockaddr *)&saidx1->src, 0) != 0) { return 0; - } + } + if (key_sockaddrcmp((struct sockaddr *)&saidx0->dst, + (struct sockaddr *)&saidx1->dst, 0) != 0) { + return 0; + } return 1; } /* - * compare two secindex structure exactly. + * compare two secasindex structure without mode, but think reqid. + * don't compare port. * IN: - * spidx0: source, it is often in SPD. - * spidx1: object, it is often from PFKEY message. + * saidx0: source, it is often in SAD. + * saidx1: object, it is often from user. * OUT: * 1 : equal * 0 : not equal */ static int -key_cmpspidx_exactly(spidx0, spidx1) - struct secpolicyindex *spidx0, *spidx1; +key_cmpsaidx_withoutmode2(saidx0, saidx1) + struct secasindex *saidx0, *saidx1; { /* sanity */ - if (spidx0 == NULL && spidx1 == NULL) + if (saidx0 == NULL && saidx1 == NULL) return 1; - if (spidx0 == NULL || spidx1 == NULL) + if (saidx0 == NULL || saidx1 == NULL) return 0; - if (spidx0->prefs != spidx1->prefs - || spidx0->prefd != spidx1->prefd - || spidx0->ul_proto != spidx1->ul_proto) + if (saidx0->proto != saidx1->proto) + return 0; + + /* + * If reqid of SPD is non-zero, unique SA is required. + * The result must be of same reqid in this case. + */ + if (saidx1->reqid != 0 && saidx0->reqid != saidx1->reqid) return 0; - if (bcmp(&spidx0->src, &spidx1->src, spidx0->src.ss_len) != 0 - || bcmp(&spidx0->dst, &spidx1->dst, spidx0->dst.ss_len) != 0) + if (key_sockaddrcmp((struct sockaddr *)&saidx0->src, + (struct sockaddr *)&saidx1->src, 0) != 0) { + return 0; + } + if (key_sockaddrcmp((struct sockaddr *)&saidx0->dst, + (struct sockaddr *)&saidx1->dst, 0) != 0) { return 0; + } return 1; } /* - * compare two secindex structure with mask. + * compare two secasindex structure without both mode and reqid. + * don't compare port. * IN: - * spidx0: source, it is often in SPD. - * spidx1: object, it is often from IP header. + * saidx0: source, it is often in SAD. + * saidx1: object, it is often from user. * OUT: * 1 : equal * 0 : not equal */ static int -key_cmpspidx_withmask(spidx0, spidx1) - struct secpolicyindex *spidx0, *spidx1; +key_cmpsaidx_withoutmode(saidx0, saidx1) + struct secasindex *saidx0, *saidx1; { /* sanity */ - if (spidx0 == NULL && spidx1 == NULL) + if (saidx0 == NULL && saidx1 == NULL) return 1; - if (spidx0 == NULL || spidx1 == NULL) + if (saidx0 == NULL || saidx1 == NULL) return 0; - if (spidx0->src.ss_family != spidx1->src.ss_family - || spidx0->dst.ss_family != spidx1->dst.ss_family) + if (saidx0->proto != saidx1->proto) return 0; - /* if spidx.ul_proto == IPSEC_ULPROTO_ANY, ignore. */ - if (spidx0->ul_proto != (u_int16_t)IPSEC_ULPROTO_ANY - && spidx0->ul_proto != spidx1->ul_proto) + if (key_sockaddrcmp((struct sockaddr *)&saidx0->src, + (struct sockaddr *)&saidx1->src, 0) != 0) { return 0; - - if (_INPORTBYSA(&spidx0->src) != IPSEC_PORT_ANY - && _INPORTBYSA(&spidx0->src) != _INPORTBYSA(&spidx1->src)) + } + if (key_sockaddrcmp((struct sockaddr *)&saidx0->dst, + (struct sockaddr *)&saidx1->dst, 0) != 0) { + return 0; + } + + return 1; +} + +/* + * compare two secindex structure exactly. + * IN: + * spidx0: source, it is often in SPD. + * spidx1: object, it is often from PFKEY message. + * OUT: + * 1 : equal + * 0 : not equal + */ +static int +key_cmpspidx_exactly(spidx0, spidx1) + struct secpolicyindex *spidx0, *spidx1; +{ + /* sanity */ + if (spidx0 == NULL && spidx1 == NULL) + return 1; + + if (spidx0 == NULL || spidx1 == NULL) + return 0; + + if (spidx0->prefs != spidx1->prefs + || spidx0->prefd != spidx1->prefd + || spidx0->ul_proto != spidx1->ul_proto) + return 0; + + if (key_sockaddrcmp((struct sockaddr *)&spidx0->src, + (struct sockaddr *)&spidx1->src, 1) != 0) { return 0; + } + if (key_sockaddrcmp((struct sockaddr *)&spidx0->dst, + (struct sockaddr *)&spidx1->dst, 1) != 0) { + return 0; + } + + return 1; +} + +/* + * compare two secindex structure with mask. + * IN: + * spidx0: source, it is often in SPD. + * spidx1: object, it is often from IP header. + * OUT: + * 1 : equal + * 0 : not equal + */ +static int +key_cmpspidx_withmask(spidx0, spidx1) + struct secpolicyindex *spidx0, *spidx1; +{ + /* sanity */ + if (spidx0 == NULL && spidx1 == NULL) + return 1; - if (_INPORTBYSA(&spidx0->dst) != IPSEC_PORT_ANY - && _INPORTBYSA(&spidx0->dst) != _INPORTBYSA(&spidx1->dst)) + if (spidx0 == NULL || spidx1 == NULL) return 0; - if (!key_bbcmp(_INADDRBYSA(&spidx0->src), - _INADDRBYSA(&spidx1->src), - spidx0->prefs)) + if (spidx0->src.ss_family != spidx1->src.ss_family || + spidx0->dst.ss_family != spidx1->dst.ss_family || + spidx0->src.ss_len != spidx1->src.ss_len || + spidx0->dst.ss_len != spidx1->dst.ss_len) return 0; - if (!key_bbcmp(_INADDRBYSA(&spidx0->dst), - _INADDRBYSA(&spidx1->dst), - spidx0->prefd)) + /* if spidx.ul_proto == IPSEC_ULPROTO_ANY, ignore. */ + if (spidx0->ul_proto != (u_int16_t)IPSEC_ULPROTO_ANY + && spidx0->ul_proto != spidx1->ul_proto) return 0; - /* XXX Do we check other field ? e.g. flowinfo, scope_id. */ + switch (spidx0->src.ss_family) { + case AF_INET: + if (satosin(&spidx0->src)->sin_port != IPSEC_PORT_ANY + && satosin(&spidx0->src)->sin_port != + satosin(&spidx1->src)->sin_port) + return 0; + if (!key_bbcmp((caddr_t)&satosin(&spidx0->src)->sin_addr, + (caddr_t)&satosin(&spidx1->src)->sin_addr, spidx0->prefs)) + return 0; + break; + case AF_INET6: + if (satosin6(&spidx0->src)->sin6_port != IPSEC_PORT_ANY + && satosin6(&spidx0->src)->sin6_port != + satosin6(&spidx1->src)->sin6_port) + return 0; + /* + * scope_id check. if sin6_scope_id is 0, we regard it + * as a wildcard scope, which matches any scope zone ID. + */ + if (satosin6(&spidx0->src)->sin6_scope_id && + satosin6(&spidx1->src)->sin6_scope_id && + satosin6(&spidx0->src)->sin6_scope_id != + satosin6(&spidx1->src)->sin6_scope_id) + return 0; + if (!key_bbcmp((caddr_t)&satosin6(&spidx0->src)->sin6_addr, + (caddr_t)&satosin6(&spidx1->src)->sin6_addr, spidx0->prefs)) + return 0; + break; + default: + /* XXX */ + if (bcmp(&spidx0->src, &spidx1->src, spidx0->src.ss_len) != 0) + return 0; + break; + } + + switch (spidx0->dst.ss_family) { + case AF_INET: + if (satosin(&spidx0->dst)->sin_port != IPSEC_PORT_ANY + && satosin(&spidx0->dst)->sin_port != + satosin(&spidx1->dst)->sin_port) + return 0; + if (!key_bbcmp((caddr_t)&satosin(&spidx0->dst)->sin_addr, + (caddr_t)&satosin(&spidx1->dst)->sin_addr, spidx0->prefd)) + return 0; + break; + case AF_INET6: + if (satosin6(&spidx0->dst)->sin6_port != IPSEC_PORT_ANY + && satosin6(&spidx0->dst)->sin6_port != + satosin6(&spidx1->dst)->sin6_port) + return 0; + /* + * scope_id check. if sin6_scope_id is 0, we regard it + * as a wildcard scope, which matches any scope zone ID. + */ + if (satosin6(&spidx0->src)->sin6_scope_id && + satosin6(&spidx1->src)->sin6_scope_id && + satosin6(&spidx0->dst)->sin6_scope_id != + satosin6(&spidx1->dst)->sin6_scope_id) + return 0; + if (!key_bbcmp((caddr_t)&satosin6(&spidx0->dst)->sin6_addr, + (caddr_t)&satosin6(&spidx1->dst)->sin6_addr, spidx0->prefd)) + return 0; + break; + default: + /* XXX */ + if (bcmp(&spidx0->dst, &spidx1->dst, spidx0->dst.ss_len) != 0) + return 0; + break; + } + + /* XXX Do we check other field ? e.g. flowinfo */ return 1; } +/* returns 0 on match */ +static int +key_sockaddrcmp(sa1, sa2, port) + struct sockaddr *sa1; + struct sockaddr *sa2; + int port; +{ + if (sa1->sa_family != sa2->sa_family || sa1->sa_len != sa2->sa_len) + return 1; + + switch (sa1->sa_family) { + case AF_INET: + if (sa1->sa_len != sizeof(struct sockaddr_in)) + return 1; + if (satosin(sa1)->sin_addr.s_addr != + satosin(sa2)->sin_addr.s_addr) { + return 1; + } + if (port && satosin(sa1)->sin_port != satosin(sa2)->sin_port) + return 1; + break; + case AF_INET6: + if (sa1->sa_len != sizeof(struct sockaddr_in6)) + return 1; /*EINVAL*/ + if (satosin6(sa1)->sin6_scope_id != + satosin6(sa2)->sin6_scope_id) { + return 1; + } + if (!IN6_ARE_ADDR_EQUAL(&satosin6(sa1)->sin6_addr, + &satosin6(sa2)->sin6_addr)) { + return 1; + } + if (port && + satosin6(sa1)->sin6_port != satosin6(sa2)->sin6_port) { + return 1; + } + default: + if (bcmp(sa1, sa2, sa1->sa_len) != 0) + return 1; + break; + } + + return 0; +} + /* * compare two buffers with mask. * IN: @@ -3760,8 +4206,8 @@ key_cmpspidx_withmask(spidx0, spidx1) */ static int key_bbcmp(p1, p2, bits) - register caddr_t p1, p2; - register u_int bits; + caddr_t p1, p2; + u_int bits; { u_int8_t mask; @@ -3790,14 +4236,19 @@ key_bbcmp(p1, p2, bits) * time handler. * scanning SPD and SAD to check status for each entries, * and do to remove or to expire. + * XXX: year 2038 problem may remain. */ -static void -key_timehandler_funneled(void) +void +key_timehandler_funnel(void) { - boolean_t funnel_state; - funnel_state = thread_funnel_set(network_flock, TRUE); +#ifdef __APPLE__ + boolean_t funnel_state; + funnel_state = thread_funnel_set(network_flock, TRUE); +#endif key_timehandler(); - (void) thread_funnel_set(network_flock, FALSE); +#ifdef __APPLE__ + (void) thread_funnel_set(network_flock, FALSE); +#endif } void @@ -3805,14 +4256,11 @@ key_timehandler(void) { u_int dir; int s; + struct timeval tv; + + microtime(&tv); - boolean_t funnel_state; - funnel_state = thread_funnel_set(network_flock, TRUE); -#if __NetBSD__ - s = splsoftnet(); /*called from softclock()*/ -#else s = splnet(); /*called from softclock()*/ -#endif /* SPD */ { @@ -3825,8 +4273,23 @@ key_timehandler(void) nextsp = LIST_NEXT(sp, chain); - if (sp->state == IPSEC_SPSTATE_DEAD) + if (sp->state == IPSEC_SPSTATE_DEAD) { key_freesp(sp); + continue; + } + + if (sp->lifetime == 0 && sp->validtime == 0) + continue; + + /* the deletion will occur next time */ + if ((sp->lifetime + && tv.tv_sec - sp->created > sp->lifetime) + || (sp->validtime + && tv.tv_sec - sp->lastused > sp->validtime)) { + sp->state = IPSEC_SPSTATE_DEAD; + key_spdexpire(sp); + continue; + } } } } @@ -3855,9 +4318,7 @@ key_timehandler(void) nextsav = LIST_NEXT(sav, chain); - sav->tick++; - - if (key_larval_lifetime < sav->tick) { + if (tv.tv_sec - sav->created > key_larval_lifetime) { key_freesav(sav); } } @@ -3872,8 +4333,6 @@ key_timehandler(void) nextsav = LIST_NEXT(sav, chain); - sav->tick++; - /* we don't need to check. */ if (sav->lft_s == NULL) continue; @@ -3887,9 +4346,9 @@ key_timehandler(void) continue; } - /* compare SOFT lifetime and tick */ + /* check SOFT lifetime */ if (sav->lft_s->sadb_lifetime_addtime != 0 - && sav->lft_s->sadb_lifetime_addtime < sav->tick) { + && tv.tv_sec - sav->created > sav->lft_s->sadb_lifetime_addtime) { /* * check SA to be used whether or not. * when SA hasn't been used, delete it. @@ -3934,8 +4393,6 @@ key_timehandler(void) nextsav = LIST_NEXT(sav, chain); - sav->tick++; - /* we don't need to check. */ if (sav->lft_h == NULL) continue; @@ -3949,9 +4406,8 @@ key_timehandler(void) continue; } - /* compare HARD lifetime and tick */ if (sav->lft_h->sadb_lifetime_addtime != 0 - && sav->lft_h->sadb_lifetime_addtime < sav->tick) { + && tv.tv_sec - sav->created > sav->lft_h->sadb_lifetime_addtime) { key_sa_chgstate(sav, SADB_SASTATE_DEAD); key_freesav(sav); sav = NULL; @@ -3959,7 +4415,7 @@ key_timehandler(void) #if 0 /* XXX Should we keep to send expire message until HARD lifetime ? */ else if (sav->lft_s != NULL && sav->lft_s->sadb_lifetime_addtime != 0 - && sav->lft_s->sadb_lifetime_addtime < sav->tick) { + && tv.tv_sec - sav->created > sav->lft_s->sadb_lifetime_addtime) { /* * XXX: should be checked to be * installed the valid SA. @@ -4020,9 +4476,8 @@ key_timehandler(void) nextacq = LIST_NEXT(acq, chain); - acq->tick++; - - if (key_blockacq_lifetime < acq->tick && __LIST_CHAINED(acq)) { + if (tv.tv_sec - acq->created > key_blockacq_lifetime + && __LIST_CHAINED(acq)) { LIST_REMOVE(acq, chain); KFREE(acq); } @@ -4040,9 +4495,8 @@ key_timehandler(void) nextacq = LIST_NEXT(acq, chain); - acq->tick++; - - if (key_blockacq_lifetime < acq->tick && __LIST_CHAINED(acq)) { + if (tv.tv_sec - acq->created > key_blockacq_lifetime + && __LIST_CHAINED(acq)) { LIST_REMOVE(acq, chain); KFREE(acq); } @@ -4057,7 +4511,7 @@ key_timehandler(void) #ifndef IPSEC_DEBUG2 /* do exchange to tick time !! */ - (void)timeout((void *)key_timehandler_funneled, (void *)0, 100); + (void)timeout((void *)key_timehandler_funnel, (void *)0, hz); #endif /* IPSEC_DEBUG2 */ splx(s); @@ -4067,29 +4521,62 @@ key_timehandler(void) /* * to initialize a seed for random() */ -void +static void key_srandom() { +#ifdef __APPLE__ + /* Our PRNG is based on Yarrow and doesn't need to be seeded */ + random(); +#else struct timeval tv; -#ifdef __bsdi__ - extern long randseed; /* it's defined at i386/i386/random.s */ -#endif /* __bsdi__ */ microtime(&tv); -#if defined(__FreeBSD__) srandom(tv.tv_usec); -#endif /* __FreeBSD__ */ -#if defined(__APPLE__) - random(); #endif -#ifdef __bsdi__ - randseed = tv.tv_usec; -#endif /* __bsdi__ */ return; } +u_long +key_random() +{ + u_long value; + + key_randomfill(&value, sizeof(value)); + return value; +} + +void +key_randomfill(p, l) + void *p; + size_t l; +{ + size_t n; + u_long v; + static int warn = 1; +#ifdef __APPLE__ + + read_random(p, (u_int)l); +#else + n = 0; + n = (size_t)read_random(p, (u_int)l); + /* last resort */ + while (n < l) { + v = random(); + bcopy(&v, (u_int8_t *)p + n, + l - n < sizeof(v) ? l - n : sizeof(v)); + n += sizeof(v); + + if (warn) { + printf("WARNING: pseudo-random number generator " + "used for IPsec processing\n"); + warn = 0; + } + } +#endif +} + /* * map SADB_SATYPE_* to IPPROTO_*. * if satype == SADB_SATYPE then satype is mapped to ~0. @@ -4107,11 +4594,9 @@ key_satype2proto(satype) return IPPROTO_AH; case SADB_SATYPE_ESP: return IPPROTO_ESP; -#if 1 /*nonstandard*/ case SADB_X_SATYPE_IPCOMP: return IPPROTO_IPCOMP; break; -#endif default: return 0; } @@ -4132,11 +4617,9 @@ key_proto2satype(proto) return SADB_SATYPE_AH; case IPPROTO_ESP: return SADB_SATYPE_ESP; -#if 1 /*nonstandard*/ case IPPROTO_IPCOMP: return SADB_X_SATYPE_IPCOMP; break; -#endif default: return 0; } @@ -4146,7 +4629,7 @@ key_proto2satype(proto) /* %%% PF_KEY */ /* * SADB_GETSPI processing is to receive - * + * * from the IKMPd, to assign a unique spi value, to hang on the INBOUND * tree with the status of LARVAL, and send * @@ -4156,73 +4639,119 @@ key_proto2satype(proto) * OUT: NULL if fail. * other if success, return pointer to the message to send. */ -static struct sadb_msg * -key_getspi(mhp) - caddr_t *mhp; +static int +key_getspi(so, m, mhp) + struct socket *so; + struct mbuf *m; + const struct sadb_msghdr *mhp; { - struct sadb_msg *msg0; struct sadb_address *src0, *dst0; struct secasindex saidx; struct secashead *newsah; struct secasvar *newsav; u_int8_t proto; u_int32_t spi; + u_int8_t mode; + u_int32_t reqid; + int error; /* sanity check */ - if (mhp == NULL || mhp[0] == NULL) + if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_getspi: NULL pointer is passed.\n"); - msg0 = (struct sadb_msg *)mhp[0]; - - if (mhp[SADB_EXT_ADDRESS_SRC] == NULL - || mhp[SADB_EXT_ADDRESS_DST] == NULL) { + if (mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL || + mhp->ext[SADB_EXT_ADDRESS_DST] == NULL) { #if IPSEC_DEBUG printf("key_getspi: invalid message is passed.\n"); #endif - msg0->sadb_msg_errno = EINVAL; - return NULL; + return key_senderror(so, m, EINVAL); + } + if (mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) || + mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address)) { +#if IPSEC_DEBUG + printf("key_getspi: invalid message is passed.\n"); +#endif + return key_senderror(so, m, EINVAL); + } + if (mhp->ext[SADB_X_EXT_SA2] != NULL) { + mode = ((struct sadb_x_sa2 *)mhp->ext[SADB_X_EXT_SA2])->sadb_x_sa2_mode; + reqid = ((struct sadb_x_sa2 *)mhp->ext[SADB_X_EXT_SA2])->sadb_x_sa2_reqid; + } else { + mode = IPSEC_MODE_ANY; + reqid = 0; } - src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); - dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); + src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]); + dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]); /* map satype to proto */ - if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { + if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) { #if IPSEC_DEBUG printf("key_getspi: invalid satype is passed.\n"); #endif - msg0->sadb_msg_errno = EINVAL; - return NULL; + return key_senderror(so, m, EINVAL); + } + + /* make sure if port number is zero. */ + switch (((struct sockaddr *)(src0 + 1))->sa_family) { + case AF_INET: + if (((struct sockaddr *)(src0 + 1))->sa_len != + sizeof(struct sockaddr_in)) + return key_senderror(so, m, EINVAL); + ((struct sockaddr_in *)(src0 + 1))->sin_port = 0; + break; + case AF_INET6: + if (((struct sockaddr *)(src0 + 1))->sa_len != + sizeof(struct sockaddr_in6)) + return key_senderror(so, m, EINVAL); + ((struct sockaddr_in6 *)(src0 + 1))->sin6_port = 0; + break; + default: + ; /*???*/ + } + switch (((struct sockaddr *)(dst0 + 1))->sa_family) { + case AF_INET: + if (((struct sockaddr *)(dst0 + 1))->sa_len != + sizeof(struct sockaddr_in)) + return key_senderror(so, m, EINVAL); + ((struct sockaddr_in *)(dst0 + 1))->sin_port = 0; + break; + case AF_INET6: + if (((struct sockaddr *)(dst0 + 1))->sa_len != + sizeof(struct sockaddr_in6)) + return key_senderror(so, m, EINVAL); + ((struct sockaddr_in6 *)(dst0 + 1))->sin6_port = 0; + break; + default: + ; /*???*/ } - KEY_SETSECASIDX(proto, msg0, src0+1, dst0+1, &saidx); + /* XXX boundary check against sa_len */ + KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, &saidx); /* SPI allocation */ - spi = key_do_getnewspi((struct sadb_spirange *)mhp[SADB_EXT_SPIRANGE], + spi = key_do_getnewspi((struct sadb_spirange *)mhp->ext[SADB_EXT_SPIRANGE], &saidx); - if (spi == 0) { - msg0->sadb_msg_errno = EEXIST; - return NULL; - } + if (spi == 0) + return key_senderror(so, m, EINVAL); /* get a SA index */ if ((newsah = key_getsah(&saidx)) == NULL) { - /* create a new SA index */ if ((newsah = key_newsah(&saidx)) == NULL) { #if IPSEC_DEBUG printf("key_getspi: No more memory.\n"); #endif - msg0->sadb_msg_errno = ENOBUFS; - return NULL; + return key_senderror(so, m, ENOBUFS); } } /* get a new SA */ - if ((newsav = key_newsav(mhp, newsah)) == NULL) { - msg0->sadb_msg_errno = ENOBUFS; + /* XXX rewrite */ + newsav = key_newsav(m, mhp, newsah, &error); + if (newsav == NULL) { /* XXX don't free new SA index allocated in above. */ - return NULL; + return key_senderror(so, m, error); } /* set spi */ @@ -4230,56 +4759,84 @@ key_getspi(mhp) #ifndef IPSEC_NONBLOCK_ACQUIRE /* delete the entry in acqtree */ - if (msg0->sadb_msg_seq != 0) { + if (mhp->msg->sadb_msg_seq != 0) { struct secacq *acq; - if ((acq = key_getacqbyseq(msg0->sadb_msg_seq)) != NULL) { - /* reset counter in order to deletion by timehander. */ - acq->tick = key_blockacq_lifetime; + if ((acq = key_getacqbyseq(mhp->msg->sadb_msg_seq)) != NULL) { + /* reset counter in order to deletion by timehandler. */ + struct timeval tv; + microtime(&tv); + acq->created = tv.tv_sec; acq->count = 0; } } #endif { + struct mbuf *n, *nn; + struct sadb_sa *m_sa; struct sadb_msg *newmsg; - u_int len; - caddr_t p; + int off, len; /* create new sadb_msg to reply. */ - len = sizeof(struct sadb_msg) - + sizeof(struct sadb_sa) - + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_SRC]) - + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_DST]); + len = PFKEY_ALIGN8(sizeof(struct sadb_msg)) + + PFKEY_ALIGN8(sizeof(struct sadb_sa)); + if (len > MCLBYTES) + return key_senderror(so, m, ENOBUFS); - KMALLOC(newmsg, struct sadb_msg *, len); - if (newmsg == NULL) { -#if IPSEC_DEBUG - printf("key_getspi: No more memory.\n"); -#endif - msg0->sadb_msg_errno = ENOBUFS; - return NULL; + MGETHDR(n, M_DONTWAIT, MT_DATA); + if (len > MHLEN) { + MCLGET(n, M_DONTWAIT); + if ((n->m_flags & M_EXT) == 0) { + m_freem(n); + n = NULL; + } } - bzero((caddr_t)newmsg, len); + if (!n) + return key_senderror(so, m, ENOBUFS); - bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0)); - newmsg->sadb_msg_seq = newsav->seq; - newmsg->sadb_msg_errno = 0; - newmsg->sadb_msg_len = PFKEY_UNIT64(len); - p = (caddr_t)newmsg + sizeof(*msg0); + n->m_len = len; + n->m_next = NULL; + off = 0; - { - struct sadb_sa *m_sa; - m_sa = (struct sadb_sa *)p; + m_copydata(m, 0, sizeof(struct sadb_msg), mtod(n, caddr_t) + off); + off += PFKEY_ALIGN8(sizeof(struct sadb_msg)); + + m_sa = (struct sadb_sa *)(mtod(n, caddr_t) + off); m_sa->sadb_sa_len = PFKEY_UNIT64(sizeof(struct sadb_sa)); m_sa->sadb_sa_exttype = SADB_EXT_SA; m_sa->sadb_sa_spi = htonl(spi); - p += sizeof(struct sadb_sa); - } + off += PFKEY_ALIGN8(sizeof(struct sadb_sa)); + +#if DIAGNOSTIC + if (off != len) + panic("length inconsistency in key_getspi"); +#endif + { + int mbufItems[] = {SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST}; + n->m_next = key_gather_mbuf(m, mhp, 0, sizeof(mbufItems)/sizeof(int), mbufItems); + if (!n->m_next) { + m_freem(n); + return key_senderror(so, m, ENOBUFS); + } + } + + if (n->m_len < sizeof(struct sadb_msg)) { + n = m_pullup(n, sizeof(struct sadb_msg)); + if (n == NULL) + return key_sendup_mbuf(so, m, KEY_SENDUP_ONE); + } + + n->m_pkthdr.len = 0; + for (nn = n; nn; nn = nn->m_next) + n->m_pkthdr.len += nn->m_len; - p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_SRC]); - p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_DST]); + newmsg = mtod(n, struct sadb_msg *); + newmsg->sadb_msg_seq = newsav->seq; + newmsg->sadb_msg_errno = 0; + newmsg->sadb_msg_len = PFKEY_UNIT64(n->m_pkthdr.len); - return newmsg; + m_freem(m); + return key_sendup_mbuf(so, n, KEY_SENDUP_ONE); } } @@ -4338,7 +4895,7 @@ key_do_getnewspi(spirange, saidx) /* when requesting to allocate spi ranged */ while (count--) { /* generate pseudo-random SPI value ranged. */ - newspi = min + (random() % ( max - min + 1 )); + newspi = min + (key_random() % (max - min + 1)); if (key_checkspidup(saidx, newspi) == NULL) break; @@ -4362,92 +4919,107 @@ key_do_getnewspi(spirange, saidx) /* * SADB_UPDATE processing * receive - * * from the ikmpd, and update a secasvar entry whose status is SADB_SASTATE_LARVAL. * and send - * * to the ikmpd. * - * IN: mhp: pointer to the pointer to each header. - * OUT: NULL if fail. - * other if success, return pointer to the message to send. + * m will always be freed. */ -static struct sadb_msg * -key_update(mhp) - caddr_t *mhp; +static int +key_update(so, m, mhp) + struct socket *so; + struct mbuf *m; + const struct sadb_msghdr *mhp; { - struct sadb_msg *msg0; struct sadb_sa *sa0; struct sadb_address *src0, *dst0; struct secasindex saidx; struct secashead *sah; struct secasvar *sav; u_int16_t proto; + u_int8_t mode; + u_int32_t reqid; + int error; /* sanity check */ - if (mhp == NULL || mhp[0] == NULL) + if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_update: NULL pointer is passed.\n"); - msg0 = (struct sadb_msg *)mhp[0]; - /* map satype to proto */ - if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { + if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) { #if IPSEC_DEBUG printf("key_update: invalid satype is passed.\n"); #endif - msg0->sadb_msg_errno = EINVAL; - return NULL; + return key_senderror(so, m, EINVAL); } - if (mhp[SADB_EXT_SA] == NULL - || mhp[SADB_EXT_ADDRESS_SRC] == NULL - || mhp[SADB_EXT_ADDRESS_DST] == NULL - || (msg0->sadb_msg_satype == SADB_SATYPE_ESP - && mhp[SADB_EXT_KEY_ENCRYPT] == NULL) - || (msg0->sadb_msg_satype == SADB_SATYPE_AH - && mhp[SADB_EXT_KEY_AUTH] == NULL) - || (mhp[SADB_EXT_LIFETIME_HARD] != NULL - && mhp[SADB_EXT_LIFETIME_SOFT] == NULL) - || (mhp[SADB_EXT_LIFETIME_HARD] == NULL - && mhp[SADB_EXT_LIFETIME_SOFT] != NULL)) { + if (mhp->ext[SADB_EXT_SA] == NULL || + mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL || + mhp->ext[SADB_EXT_ADDRESS_DST] == NULL || + (mhp->msg->sadb_msg_satype == SADB_SATYPE_ESP && + mhp->ext[SADB_EXT_KEY_ENCRYPT] == NULL) || + (mhp->msg->sadb_msg_satype == SADB_SATYPE_AH && + mhp->ext[SADB_EXT_KEY_AUTH] == NULL) || + (mhp->ext[SADB_EXT_LIFETIME_HARD] != NULL && + mhp->ext[SADB_EXT_LIFETIME_SOFT] == NULL) || + (mhp->ext[SADB_EXT_LIFETIME_HARD] == NULL && + mhp->ext[SADB_EXT_LIFETIME_SOFT] != NULL)) { #if IPSEC_DEBUG printf("key_update: invalid message is passed.\n"); #endif - msg0->sadb_msg_errno = EINVAL; - return NULL; + return key_senderror(so, m, EINVAL); } + if (mhp->extlen[SADB_EXT_SA] < sizeof(struct sadb_sa) || + mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) || + mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address)) { +#if IPSEC_DEBUG + printf("key_update: invalid message is passed.\n"); +#endif + return key_senderror(so, m, EINVAL); + } + if (mhp->ext[SADB_X_EXT_SA2] != NULL) { + mode = ((struct sadb_x_sa2 *)mhp->ext[SADB_X_EXT_SA2])->sadb_x_sa2_mode; + reqid = ((struct sadb_x_sa2 *)mhp->ext[SADB_X_EXT_SA2])->sadb_x_sa2_reqid; + } else { + mode = IPSEC_MODE_ANY; + reqid = 0; + } + /* XXX boundary checking for other extensions */ - sa0 = (struct sadb_sa *)mhp[SADB_EXT_SA]; - src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); - dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); + sa0 = (struct sadb_sa *)mhp->ext[SADB_EXT_SA]; + src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]); + dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]); - KEY_SETSECASIDX(proto, msg0, src0+1, dst0+1, &saidx); + /* XXX boundary check against sa_len */ + KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, &saidx); /* get a SA header */ if ((sah = key_getsah(&saidx)) == NULL) { #if IPSEC_DEBUG printf("key_update: no SA index found.\n"); #endif - msg0->sadb_msg_errno = ENOENT; - return NULL; + return key_senderror(so, m, ENOENT); } /* set spidx if there */ - if (key_setident(sah, mhp) < 0) - return NULL; + /* XXX rewrite */ + error = key_setident(sah, m, mhp); + if (error) + return key_senderror(so, m, error); /* find a SA with sequence number. */ #if IPSEC_DOSEQCHECK - if (msg0->sadb_msg_seq != 0 - && (sav = key_getsavbyseq(sah, msg0->sadb_msg_seq)) == NULL) { + if (mhp->msg->sadb_msg_seq != 0 + && (sav = key_getsavbyseq(sah, mhp->msg->sadb_msg_seq)) == NULL) { #if IPSEC_DEBUG printf("key_update: no larval SA with sequence %u exists.\n", - msg0->sadb_msg_seq); + mhp->msg->sadb_msg_seq); #endif - msg0->sadb_msg_errno = ENOENT; - return NULL; + return key_senderror(so, m, ENOENT); } #else if ((sav = key_getsavbyspi(sah, sa0->sadb_sa_spi)) == NULL) { @@ -4455,8 +5027,7 @@ key_update(mhp) printf("key_update: no such a SA found (spi:%u)\n", (u_int32_t)ntohl(sa0->sadb_sa_spi)); #endif - msg0->sadb_msg_errno = EINVAL; - return NULL; + return key_senderror(so, m, EINVAL); } #endif @@ -4466,8 +5037,7 @@ key_update(mhp) printf("key_update: protocol mismatched (DB=%u param=%u)\n", sav->sah->saidx.proto, proto); #endif - msg0->sadb_msg_errno = EINVAL; - return NULL; + return key_senderror(so, m, EINVAL); } #if IPSEC_DOSEQCHECK if (sav->spi != sa0->sadb_sa_spi) { @@ -4476,43 +5046,44 @@ key_update(mhp) (u_int32_t)ntohl(sav->spi), (u_int32_t)ntohl(sa0->sadb_sa_spi)); #endif - msg0->sadb_msg_errno = EINVAL; - return NULL; + return key_senderror(so, m, EINVAL); } #endif - if (sav->pid != msg0->sadb_msg_pid) { + if (sav->pid != mhp->msg->sadb_msg_pid) { #if IPSEC_DEBUG printf("key_update: pid mismatched (DB:%u param:%u)\n", - sav->pid, msg0->sadb_msg_pid); + sav->pid, mhp->msg->sadb_msg_pid); #endif - msg0->sadb_msg_errno = EINVAL; - return NULL; + return key_senderror(so, m, EINVAL); } /* copy sav values */ - if (key_setsaval(sav, mhp)) { + error = key_setsaval(sav, m, mhp); + if (error) { key_freesav(sav); - return NULL; + return key_senderror(so, m, error); } /* check SA values to be mature. */ - if ((msg0->sadb_msg_errno = key_mature(sav)) != 0) { + if ((mhp->msg->sadb_msg_errno = key_mature(sav)) != 0) { key_freesav(sav); - return NULL; + return key_senderror(so, m, 0); } { - struct sadb_msg *newmsg; + struct mbuf *n; /* set msg buf from mhp */ - if ((newmsg = key_getmsgbuf_x1(mhp)) == NULL) { + n = key_getmsgbuf_x1(m, mhp); + if (n == NULL) { #if IPSEC_DEBUG printf("key_update: No more memory.\n"); #endif - msg0->sadb_msg_errno = ENOBUFS; - return NULL; + return key_senderror(so, m, ENOBUFS); } - return newmsg; + + m_freem(m); + return key_sendup_mbuf(so, n, KEY_SENDUP_ALL); } } @@ -4556,87 +5127,103 @@ key_getsavbyseq(sah, seq) /* * SADB_ADD processing * add a entry to SA database, when received - * * from the ikmpd, * and send - * * to the ikmpd. * * IGNORE identity and sensitivity messages. * - * IN: mhp: pointer to the pointer to each header. - * OUT: NULL if fail. - * other if success, return pointer to the message to send. + * m will always be freed. */ -static struct sadb_msg * -key_add(mhp) - caddr_t *mhp; -{ - struct sadb_msg *msg0; - struct sadb_sa *sa0; +static int +key_add(so, m, mhp) + struct socket *so; + struct mbuf *m; + const struct sadb_msghdr *mhp; +{ + struct sadb_sa *sa0; struct sadb_address *src0, *dst0; struct secasindex saidx; struct secashead *newsah; struct secasvar *newsav; u_int16_t proto; + u_int8_t mode; + u_int32_t reqid; + int error; /* sanity check */ - if (mhp == NULL || mhp[0] == NULL) + if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_add: NULL pointer is passed.\n"); - msg0 = (struct sadb_msg *)mhp[0]; - /* map satype to proto */ - if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { + if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) { #if IPSEC_DEBUG printf("key_add: invalid satype is passed.\n"); #endif - msg0->sadb_msg_errno = EINVAL; - return NULL; + return key_senderror(so, m, EINVAL); } - if (mhp[SADB_EXT_SA] == NULL - || mhp[SADB_EXT_ADDRESS_SRC] == NULL - || mhp[SADB_EXT_ADDRESS_DST] == NULL - || (msg0->sadb_msg_satype == SADB_SATYPE_ESP - && mhp[SADB_EXT_KEY_ENCRYPT] == NULL) - || (msg0->sadb_msg_satype == SADB_SATYPE_AH - && mhp[SADB_EXT_KEY_AUTH] == NULL) - || (mhp[SADB_EXT_LIFETIME_HARD] != NULL - && mhp[SADB_EXT_LIFETIME_SOFT] == NULL) - || (mhp[SADB_EXT_LIFETIME_HARD] == NULL - && mhp[SADB_EXT_LIFETIME_SOFT] != NULL)) { + if (mhp->ext[SADB_EXT_SA] == NULL || + mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL || + mhp->ext[SADB_EXT_ADDRESS_DST] == NULL || + (mhp->msg->sadb_msg_satype == SADB_SATYPE_ESP && + mhp->ext[SADB_EXT_KEY_ENCRYPT] == NULL) || + (mhp->msg->sadb_msg_satype == SADB_SATYPE_AH && + mhp->ext[SADB_EXT_KEY_AUTH] == NULL) || + (mhp->ext[SADB_EXT_LIFETIME_HARD] != NULL && + mhp->ext[SADB_EXT_LIFETIME_SOFT] == NULL) || + (mhp->ext[SADB_EXT_LIFETIME_HARD] == NULL && + mhp->ext[SADB_EXT_LIFETIME_SOFT] != NULL)) { #if IPSEC_DEBUG printf("key_add: invalid message is passed.\n"); #endif - msg0->sadb_msg_errno = EINVAL; - return NULL; + return key_senderror(so, m, EINVAL); + } + if (mhp->extlen[SADB_EXT_SA] < sizeof(struct sadb_sa) || + mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) || + mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address)) { + /* XXX need more */ +#if IPSEC_DEBUG + printf("key_add: invalid message is passed.\n"); +#endif + return key_senderror(so, m, EINVAL); + } + if (mhp->ext[SADB_X_EXT_SA2] != NULL) { + mode = ((struct sadb_x_sa2 *)mhp->ext[SADB_X_EXT_SA2])->sadb_x_sa2_mode; + reqid = ((struct sadb_x_sa2 *)mhp->ext[SADB_X_EXT_SA2])->sadb_x_sa2_reqid; + } else { + mode = IPSEC_MODE_ANY; + reqid = 0; } - sa0 = (struct sadb_sa *)mhp[SADB_EXT_SA]; - src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); - dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); + sa0 = (struct sadb_sa *)mhp->ext[SADB_EXT_SA]; + src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC]; + dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST]; - KEY_SETSECASIDX(proto, msg0, src0+1, dst0+1, &saidx); + /* XXX boundary check against sa_len */ + KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, &saidx); /* get a SA header */ if ((newsah = key_getsah(&saidx)) == NULL) { - /* create a new SA header */ if ((newsah = key_newsah(&saidx)) == NULL) { #if IPSEC_DEBUG printf("key_add: No more memory.\n"); #endif - msg0->sadb_msg_errno = ENOBUFS; - return NULL; + return key_senderror(so, m, ENOBUFS); } } /* set spidx if there */ - if (key_setident(newsah, mhp) < 0) - return NULL; + /* XXX rewrite */ + error = key_setident(newsah, m, mhp); + if (error) { + return key_senderror(so, m, error); + } /* create new SA entry. */ /* We can create new SA only if SPI is differenct. */ @@ -4644,16 +5231,17 @@ key_add(mhp) #if IPSEC_DEBUG printf("key_add: SA already exists.\n"); #endif - msg0->sadb_msg_errno = EEXIST; - return NULL; + return key_senderror(so, m, EEXIST); + } + newsav = key_newsav(m, mhp, newsah, &error); + if (newsav == NULL) { + return key_senderror(so, m, error); } - if ((newsav = key_newsav(mhp, newsah)) == NULL) - return NULL; /* check SA values to be mature. */ - if ((msg0->sadb_msg_errno = key_mature(newsav)) != NULL) { + if ((error = key_mature(newsav)) != 0) { key_freesav(newsav); - return NULL; + return key_senderror(so, m, error); } /* @@ -4662,100 +5250,66 @@ key_add(mhp) */ { - struct sadb_msg *newmsg; + struct mbuf *n; /* set msg buf from mhp */ - if ((newmsg = key_getmsgbuf_x1(mhp)) == NULL) { + n = key_getmsgbuf_x1(m, mhp); + if (n == NULL) { #if IPSEC_DEBUG - printf("key_add: No more memory.\n"); + printf("key_update: No more memory.\n"); #endif - msg0->sadb_msg_errno = ENOBUFS; - return NULL; + return key_senderror(so, m, ENOBUFS); } - return newmsg; + m_freem(m); + return key_sendup_mbuf(so, n, KEY_SENDUP_ALL); } } +/* m is retained */ static int -key_setident(sah, mhp) +key_setident(sah, m, mhp) struct secashead *sah; - caddr_t *mhp; + struct mbuf *m; + const struct sadb_msghdr *mhp; { - struct sadb_msg *msg0; - struct sadb_ident *idsrc, *iddst; + const struct sadb_ident *idsrc, *iddst; int idsrclen, iddstlen; /* sanity check */ - if (sah == NULL || mhp == NULL || mhp[0] == NULL) + if (sah == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_setident: NULL pointer is passed.\n"); - msg0 = (struct sadb_msg *)mhp[0]; - /* don't make buffer if not there */ - if (mhp[SADB_EXT_IDENTITY_SRC] == NULL - && mhp[SADB_EXT_IDENTITY_DST] == NULL) { + if (mhp->ext[SADB_EXT_IDENTITY_SRC] == NULL && + mhp->ext[SADB_EXT_IDENTITY_DST] == NULL) { sah->idents = NULL; sah->identd = NULL; return 0; } - if (mhp[SADB_EXT_IDENTITY_SRC] == NULL - || mhp[SADB_EXT_IDENTITY_DST] == NULL) { + if (mhp->ext[SADB_EXT_IDENTITY_SRC] == NULL || + mhp->ext[SADB_EXT_IDENTITY_DST] == NULL) { #if IPSEC_DEBUG printf("key_setident: invalid identity.\n"); #endif - msg0->sadb_msg_errno = EINVAL; - return -1; + return EINVAL; } - idsrc = (struct sadb_ident *)mhp[SADB_EXT_IDENTITY_SRC]; - iddst = (struct sadb_ident *)mhp[SADB_EXT_IDENTITY_DST]; - idsrclen = PFKEY_UNUNIT64(idsrc->sadb_ident_len); - iddstlen = PFKEY_UNUNIT64(idsrc->sadb_ident_len); + idsrc = (const struct sadb_ident *)mhp->ext[SADB_EXT_IDENTITY_SRC]; + iddst = (const struct sadb_ident *)mhp->ext[SADB_EXT_IDENTITY_DST]; + idsrclen = mhp->extlen[SADB_EXT_IDENTITY_SRC]; + iddstlen = mhp->extlen[SADB_EXT_IDENTITY_DST]; /* validity check */ if (idsrc->sadb_ident_type != iddst->sadb_ident_type) { #if IPSEC_DEBUG printf("key_setident: ident type mismatch.\n"); #endif - msg0->sadb_msg_errno = EINVAL; - return -1; + return EINVAL; } switch (idsrc->sadb_ident_type) { - case SADB_X_IDENTTYPE_ADDR: - if (idsrclen != - sizeof(*idsrc) + ((struct sockaddr *)(idsrc + 1))->sa_len - || iddstlen != - sizeof(*iddst) + ((struct sockaddr *)(iddst + 1))->sa_len) { -#if IPSEC_DEBUG - printf("key_setident: invalid length is passed.\n"); -#endif - msg0->sadb_msg_errno = EINVAL; - return -1; - } - if (((struct sockaddr *)(idsrc + 1))->sa_len > - sizeof(struct sockaddr_storage) - || ((struct sockaddr *)(iddst + 1))->sa_len > - sizeof(struct sockaddr_storage)) { -#if IPSEC_DEBUG - printf("key_setident: invalid sa_len is passed.\n"); -#endif - msg0->sadb_msg_errno = EINVAL; - return -1; - } -#define __IDENTXID(a) ((union sadb_x_ident_id *)&(a)->sadb_ident_id) - if (__IDENTXID(idsrc)->sadb_x_ident_id_addr.ul_proto - != __IDENTXID(iddst)->sadb_x_ident_id_addr.ul_proto) { -#if IPSEC_DEBUG - printf("key_setident: ul_proto mismatch.\n"); -#endif - msg0->sadb_msg_errno = EINVAL; - return -1; - } -#undef __IDENTXID(a) - break; case SADB_IDENTTYPE_PREFIX: case SADB_IDENTTYPE_FQDN: case SADB_IDENTTYPE_USERFQDN: @@ -4772,17 +5326,16 @@ key_setident(sah, mhp) #if IPSEC_DEBUG printf("key_setident: No more memory.\n"); #endif - msg0->sadb_msg_errno = ENOBUFS; - return -1; + return ENOBUFS; } KMALLOC(sah->identd, struct sadb_ident *, iddstlen); if (sah->identd == NULL) { KFREE(sah->idents); + sah->idents = NULL; #if IPSEC_DEBUG printf("key_setident: No more memory.\n"); #endif - msg0->sadb_msg_errno = ENOBUFS; - return -1; + return ENOBUFS; } bcopy(idsrc, sah->idents, idsrclen); bcopy(iddst, sah->identd, iddstlen); @@ -4790,63 +5343,46 @@ key_setident(sah, mhp) return 0; } -static struct sadb_msg * -key_getmsgbuf_x1(mhp) - caddr_t *mhp; +/* + * m will not be freed on return. + * it is caller's responsibility to free the result. + */ +static struct mbuf * +key_getmsgbuf_x1(m, mhp) + struct mbuf *m; + const struct sadb_msghdr *mhp; { - struct sadb_msg *msg0; - struct sadb_msg *newmsg; - u_int len; - caddr_t p; + struct mbuf *n; + int mbufItems[] = {SADB_EXT_RESERVED, SADB_EXT_SA, + SADB_X_EXT_SA2, SADB_EXT_ADDRESS_SRC, + SADB_EXT_ADDRESS_DST, SADB_EXT_LIFETIME_HARD, + SADB_EXT_LIFETIME_SOFT, SADB_EXT_IDENTITY_SRC, + SADB_EXT_IDENTITY_DST}; /* sanity check */ - if (mhp == NULL || mhp[0] == NULL) + if (m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_getmsgbuf_x1: NULL pointer is passed.\n"); - msg0 = (struct sadb_msg *)mhp[0]; - /* create new sadb_msg to reply. */ - len = sizeof(struct sadb_msg) - + sizeof(struct sadb_sa) - + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_SRC]) - + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_DST]) - + (mhp[SADB_EXT_LIFETIME_HARD] == NULL - ? 0 : sizeof(struct sadb_lifetime)) - + (mhp[SADB_EXT_LIFETIME_SOFT] == NULL - ? 0 : sizeof(struct sadb_lifetime)) - + (mhp[SADB_EXT_IDENTITY_SRC] == NULL - ? 0 : PFKEY_EXTLEN(mhp[SADB_EXT_IDENTITY_SRC])) - + (mhp[SADB_EXT_IDENTITY_DST] == NULL - ? 0 : PFKEY_EXTLEN(mhp[SADB_EXT_IDENTITY_DST])); - - KMALLOC(newmsg, struct sadb_msg *, len); - if (newmsg == NULL) + n = key_gather_mbuf(m, mhp, 1, sizeof(mbufItems)/sizeof(int), mbufItems); + if (!n) return NULL; - bzero((caddr_t)newmsg, len); - - bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0)); - newmsg->sadb_msg_errno = 0; - newmsg->sadb_msg_len = PFKEY_UNIT64(len); - p = (caddr_t)newmsg + sizeof(*msg0); - - p = key_setsadbext(p, mhp[SADB_EXT_SA]); - p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_SRC]); - p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_DST]); - - if (mhp[SADB_EXT_LIFETIME_HARD] != NULL) - p = key_setsadbext(p, mhp[SADB_EXT_LIFETIME_HARD]); - - if (mhp[SADB_EXT_LIFETIME_SOFT] != NULL) - p = key_setsadbext(p, mhp[SADB_EXT_LIFETIME_SOFT]); - if (mhp[SADB_EXT_IDENTITY_SRC] != NULL) - p = key_setsadbext(p, mhp[SADB_EXT_IDENTITY_SRC]); - if (mhp[SADB_EXT_IDENTITY_DST] != NULL) - p = key_setsadbext(p, mhp[SADB_EXT_IDENTITY_DST]); + if (n->m_len < sizeof(struct sadb_msg)) { + n = m_pullup(n, sizeof(struct sadb_msg)); + if (n == NULL) + return NULL; + } + mtod(n, struct sadb_msg *)->sadb_msg_errno = 0; + mtod(n, struct sadb_msg *)->sadb_msg_len = + PFKEY_UNIT64(n->m_pkthdr.len); - return newmsg; + return n; } +static int key_delete_all __P((struct socket *, struct mbuf *, + const struct sadb_msghdr *, u_int16_t)); + /* * SADB_DELETE processing * receive @@ -4856,69 +5392,90 @@ key_getmsgbuf_x1(mhp) * * to the ikmpd. * - * IN: mhp: pointer to the pointer to each header. - * OUT: NULL if fail. - * other if success, return pointer to the message to send. + * m will always be freed. */ -static struct sadb_msg * -key_delete(mhp) - caddr_t *mhp; +static int +key_delete(so, m, mhp) + struct socket *so; + struct mbuf *m; + const struct sadb_msghdr *mhp; { - struct sadb_msg *msg0; struct sadb_sa *sa0; struct sadb_address *src0, *dst0; struct secasindex saidx; struct secashead *sah; - struct secasvar *sav; + struct secasvar *sav = NULL; u_int16_t proto; /* sanity check */ - if (mhp == NULL || mhp[0] == NULL) + if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_delete: NULL pointer is passed.\n"); - msg0 = (struct sadb_msg *)mhp[0]; - /* map satype to proto */ - if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { + if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) { #if IPSEC_DEBUG printf("key_delete: invalid satype is passed.\n"); #endif - msg0->sadb_msg_errno = EINVAL; - return NULL; + return key_senderror(so, m, EINVAL); } - if (mhp[SADB_EXT_SA] == NULL - || mhp[SADB_EXT_ADDRESS_SRC] == NULL - || mhp[SADB_EXT_ADDRESS_DST] == NULL) { + if (mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL || + mhp->ext[SADB_EXT_ADDRESS_DST] == NULL) { #if IPSEC_DEBUG printf("key_delete: invalid message is passed.\n"); #endif - msg0->sadb_msg_errno = EINVAL; - return NULL; + return key_senderror(so, m, EINVAL); } - sa0 = (struct sadb_sa *)mhp[SADB_EXT_SA]; - src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); - dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); - KEY_SETSECASIDX(proto, msg0, src0+1, dst0+1, &saidx); + if (mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) || + mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address)) { +#if IPSEC_DEBUG + printf("key_delete: invalid message is passed.\n"); +#endif + return key_senderror(so, m, EINVAL); + } - /* get a SA header */ - if ((sah = key_getsah(&saidx)) == NULL) { + if (mhp->ext[SADB_EXT_SA] == NULL) { + /* + * Caller wants us to delete all non-LARVAL SAs + * that match the src/dst. This is used during + * IKE INITIAL-CONTACT. + */ #if IPSEC_DEBUG - printf("key_delete: no SA found.\n"); + printf("key_delete: doing delete all.\n"); #endif - msg0->sadb_msg_errno = ENOENT; - return NULL; + return key_delete_all(so, m, mhp, proto); + } else if (mhp->extlen[SADB_EXT_SA] < sizeof(struct sadb_sa)) { +#if IPSEC_DEBUG + printf("key_delete: invalid message is passed.\n"); +#endif + return key_senderror(so, m, EINVAL); } - /* get a SA with SPI. */ - sav = key_getsavbyspi(sah, sa0->sadb_sa_spi); - if (sav == NULL) { + sa0 = (struct sadb_sa *)mhp->ext[SADB_EXT_SA]; + src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]); + dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]); + + /* XXX boundary check against sa_len */ + KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx); + + /* get a SA header */ + LIST_FOREACH(sah, &sahtree, chain) { + if (sah->state == SADB_SASTATE_DEAD) + continue; + if (key_cmpsaidx_withoutmode(&sah->saidx, &saidx) == 0) + continue; + + /* get a SA with SPI. */ + sav = key_getsavbyspi(sah, sa0->sadb_sa_spi); + if (sav) + break; + } + if (sah == NULL) { #if IPSEC_DEBUG - printf("key_delete: no alive SA found.\n"); + printf("key_delete: no SA found.\n"); #endif - msg0->sadb_msg_errno = ENOENT; - return NULL; + return key_senderror(so, m, ENOENT); } key_sa_chgstate(sav, SADB_SASTATE_DEAD); @@ -4926,36 +5483,106 @@ key_delete(mhp) sav = NULL; { + struct mbuf *n; struct sadb_msg *newmsg; - u_int len; - caddr_t p; + int mbufItems[] = {SADB_EXT_RESERVED, SADB_EXT_SA, + SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST}; /* create new sadb_msg to reply. */ - len = sizeof(struct sadb_msg) - + sizeof(struct sadb_sa) - + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_SRC]) - + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_DST]); + n = key_gather_mbuf(m, mhp, 1, sizeof(mbufItems)/sizeof(int), mbufItems); + if (!n) + return key_senderror(so, m, ENOBUFS); - KMALLOC(newmsg, struct sadb_msg *, len); - if (newmsg == NULL) { + if (n->m_len < sizeof(struct sadb_msg)) { + n = m_pullup(n, sizeof(struct sadb_msg)); + if (n == NULL) + return key_senderror(so, m, ENOBUFS); + } + newmsg = mtod(n, struct sadb_msg *); + newmsg->sadb_msg_errno = 0; + newmsg->sadb_msg_len = PFKEY_UNIT64(n->m_pkthdr.len); + + m_freem(m); + return key_sendup_mbuf(so, n, KEY_SENDUP_ALL); + } +} + +/* + * delete all SAs for src/dst. Called from key_delete(). + */ +static int +key_delete_all(so, m, mhp, proto) + struct socket *so; + struct mbuf *m; + const struct sadb_msghdr *mhp; + u_int16_t proto; +{ + struct sadb_address *src0, *dst0; + struct secasindex saidx; + struct secashead *sah; + struct secasvar *sav, *nextsav; + u_int stateidx, state; + + src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]); + dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]); + + /* XXX boundary check against sa_len */ + KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx); + + LIST_FOREACH(sah, &sahtree, chain) { + if (sah->state == SADB_SASTATE_DEAD) + continue; + if (key_cmpsaidx_withoutmode(&sah->saidx, &saidx) == 0) + continue; + + /* Delete all non-LARVAL SAs. */ + for (stateidx = 0; + stateidx < _ARRAYLEN(saorder_state_alive); + stateidx++) { + state = saorder_state_alive[stateidx]; + if (state == SADB_SASTATE_LARVAL) + continue; + for (sav = LIST_FIRST(&sah->savtree[state]); + sav != NULL; sav = nextsav) { + nextsav = LIST_NEXT(sav, chain); + /* sanity check */ + if (sav->state != state) { #if IPSEC_DEBUG - printf("key_delete: No more memory.\n"); + printf("key_delete_all: " + "invalid sav->state " + "(queue: %d SA: %d)\n", + state, sav->state); #endif - msg0->sadb_msg_errno = ENOBUFS; - return NULL; + continue; + } + + key_sa_chgstate(sav, SADB_SASTATE_DEAD); + key_freesav(sav); + } + } } - bzero((caddr_t)newmsg, len); + { + struct mbuf *n; + struct sadb_msg *newmsg; + int mbufItems[] = {SADB_EXT_RESERVED, SADB_EXT_ADDRESS_SRC, + SADB_EXT_ADDRESS_DST}; - bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0)); - newmsg->sadb_msg_errno = 0; - newmsg->sadb_msg_len = PFKEY_UNIT64(len); - p = (caddr_t)newmsg + sizeof(*msg0); + /* create new sadb_msg to reply. */ + n = key_gather_mbuf(m, mhp, 1, sizeof(mbufItems)/sizeof(int), mbufItems); + if (!n) + return key_senderror(so, m, ENOBUFS); - p = key_setsadbext(p, mhp[SADB_EXT_SA]); - p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_SRC]); - p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_DST]); + if (n->m_len < sizeof(struct sadb_msg)) { + n = m_pullup(n, sizeof(struct sadb_msg)); + if (n == NULL) + return key_senderror(so, m, ENOBUFS); + } + newmsg = mtod(n, struct sadb_msg *); + newmsg->sadb_msg_errno = 0; + newmsg->sadb_msg_len = PFKEY_UNIT64(n->m_pkthdr.len); - return newmsg; + m_freem(m); + return key_sendup_mbuf(so, n, KEY_SENDUP_ALL); } } @@ -4969,74 +5596,78 @@ key_delete(mhp) * (identity(SD),) (sensitivity)> * to the ikmpd. * - * IN: mhp: pointer to the pointer to each header. - * OUT: NULL if fail. - * other if success, return pointer to the message to send. + * m will always be freed. */ -static struct sadb_msg * -key_get(mhp) - caddr_t *mhp; +static int +key_get(so, m, mhp) + struct socket *so; + struct mbuf *m; + const struct sadb_msghdr *mhp; { - struct sadb_msg *msg0; struct sadb_sa *sa0; struct sadb_address *src0, *dst0; struct secasindex saidx; struct secashead *sah; - struct secasvar *sav; + struct secasvar *sav = NULL; u_int16_t proto; /* sanity check */ - if (mhp == NULL || mhp[0] == NULL) + if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_get: NULL pointer is passed.\n"); - msg0 = (struct sadb_msg *)mhp[0]; - /* map satype to proto */ - if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { + if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) { #if IPSEC_DEBUG printf("key_get: invalid satype is passed.\n"); #endif - msg0->sadb_msg_errno = EINVAL; - return NULL; + return key_senderror(so, m, EINVAL); } - if (mhp[SADB_EXT_SA] == NULL - || mhp[SADB_EXT_ADDRESS_SRC] == NULL - || mhp[SADB_EXT_ADDRESS_DST] == NULL) { + if (mhp->ext[SADB_EXT_SA] == NULL || + mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL || + mhp->ext[SADB_EXT_ADDRESS_DST] == NULL) { #if IPSEC_DEBUG printf("key_get: invalid message is passed.\n"); #endif - msg0->sadb_msg_errno = EINVAL; - return NULL; + return key_senderror(so, m, EINVAL); } - sa0 = (struct sadb_sa *)mhp[SADB_EXT_SA]; - src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); - dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); - - KEY_SETSECASIDX(proto, msg0, src0+1, dst0+1, &saidx); - - /* get a SA header */ - if ((sah = key_getsah(&saidx)) == NULL) { + if (mhp->extlen[SADB_EXT_SA] < sizeof(struct sadb_sa) || + mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) || + mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address)) { #if IPSEC_DEBUG - printf("key_get: no SA found.\n"); + printf("key_get: invalid message is passed.\n"); #endif - msg0->sadb_msg_errno = ENOENT; - return NULL; + return key_senderror(so, m, EINVAL); } - /* get a SA with SPI. */ - sav = key_getsavbyspi(sah, sa0->sadb_sa_spi); - if (sav == NULL) { + sa0 = (struct sadb_sa *)mhp->ext[SADB_EXT_SA]; + src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC]; + dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST]; + + /* XXX boundary check against sa_len */ + KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx); + + /* get a SA header */ + LIST_FOREACH(sah, &sahtree, chain) { + if (sah->state == SADB_SASTATE_DEAD) + continue; + if (key_cmpsaidx_withoutmode(&sah->saidx, &saidx) == 0) + continue; + + /* get a SA with SPI. */ + sav = key_getsavbyspi(sah, sa0->sadb_sa_spi); + if (sav) + break; + } + if (sah == NULL) { #if IPSEC_DEBUG - printf("key_get: no SA with state of mature found.\n"); + printf("key_get: no SA found.\n"); #endif - msg0->sadb_msg_errno = ENOENT; - return NULL; + return key_senderror(so, m, ENOENT); } { - struct sadb_msg *newmsg; - u_int len; + struct mbuf *n; u_int8_t satype; /* map proto to satype */ @@ -5044,34 +5675,276 @@ key_get(mhp) #if IPSEC_DEBUG printf("key_get: there was invalid proto in SAD.\n"); #endif - msg0->sadb_msg_errno = EINVAL; - return NULL; + return key_senderror(so, m, EINVAL); } - /* calculate a length of message buffer */ - len = key_getmsglen(sav); + /* create new sadb_msg to reply. */ + n = key_setdumpsa(sav, SADB_GET, satype, mhp->msg->sadb_msg_seq, + mhp->msg->sadb_msg_pid); + if (!n) + return key_senderror(so, m, ENOBUFS); - KMALLOC(newmsg, struct sadb_msg *, len); - if (newmsg == NULL) { -#if IPSEC_DEBUG - printf("key_get: No more memory.\n"); + m_freem(m); + return key_sendup_mbuf(so, n, KEY_SENDUP_ONE); + } +} + +/* XXX make it sysctl-configurable? */ +static void +key_getcomb_setlifetime(comb) + struct sadb_comb *comb; +{ + + comb->sadb_comb_soft_allocations = 1; + comb->sadb_comb_hard_allocations = 1; + comb->sadb_comb_soft_bytes = 0; + comb->sadb_comb_hard_bytes = 0; + comb->sadb_comb_hard_addtime = 86400; /* 1 day */ + comb->sadb_comb_soft_addtime = comb->sadb_comb_soft_addtime * 80 / 100; + comb->sadb_comb_soft_usetime = 28800; /* 8 hours */ + comb->sadb_comb_hard_usetime = comb->sadb_comb_hard_usetime * 80 / 100; +} + +#if IPSEC_ESP +/* + * XXX reorder combinations by preference + * XXX no idea if the user wants ESP authentication or not + */ +static struct mbuf * +key_getcomb_esp() +{ + struct sadb_comb *comb; + const struct esp_algorithm *algo; + struct mbuf *result = NULL, *m, *n; + int encmin; + int i, off, o; + int totlen; + const int l = PFKEY_ALIGN8(sizeof(struct sadb_comb)); + + m = NULL; + for (i = 1; i <= SADB_EALG_MAX; i++) { + algo = esp_algorithm_lookup(i); + if (!algo) + continue; + + if (algo->keymax < ipsec_esp_keymin) + continue; + if (algo->keymin < ipsec_esp_keymin) + encmin = ipsec_esp_keymin; + else + encmin = algo->keymin; + + if (ipsec_esp_auth) + m = key_getcomb_ah(); + else { +#if DIAGNOSTIC + if (l > MLEN) + panic("assumption failed in key_getcomb_esp"); +#endif + MGET(m, M_DONTWAIT, MT_DATA); + if (m) { + M_ALIGN(m, l); + m->m_len = l; + m->m_next = NULL; + bzero(mtod(m, caddr_t), m->m_len); + } + } + if (!m) + goto fail; + + totlen = 0; + for (n = m; n; n = n->m_next) + totlen += n->m_len; +#if DIAGNOSTIC + if (totlen % l) + panic("assumption failed in key_getcomb_esp"); +#endif + + for (off = 0; off < totlen; off += l) { + n = m_pulldown(m, off, l, &o); + if (!n) { + /* m is already freed */ + goto fail; + } + comb = (struct sadb_comb *)(mtod(n, caddr_t) + o); + bzero(comb, sizeof(*comb)); + key_getcomb_setlifetime(comb); + comb->sadb_comb_encrypt = i; + comb->sadb_comb_encrypt_minbits = encmin; + comb->sadb_comb_encrypt_maxbits = algo->keymax; + } + + if (!result) + result = m; + else + m_cat(result, m); + } + + return result; + + fail: + if (result) + m_freem(result); + return NULL; +} #endif - msg0->sadb_msg_errno = ENOBUFS; + +/* + * XXX reorder combinations by preference + */ +static struct mbuf * +key_getcomb_ah() +{ + struct sadb_comb *comb; + const struct ah_algorithm *algo; + struct mbuf *m; + int min; + int i; + const int l = PFKEY_ALIGN8(sizeof(struct sadb_comb)); + + m = NULL; + for (i = 1; i <= SADB_AALG_MAX; i++) { +#if 1 + /* we prefer HMAC algorithms, not old algorithms */ + if (i != SADB_AALG_SHA1HMAC && i != SADB_AALG_MD5HMAC) + continue; +#endif + algo = ah_algorithm_lookup(i); + if (!algo) + continue; + + if (algo->keymax < ipsec_ah_keymin) + continue; + if (algo->keymin < ipsec_ah_keymin) + min = ipsec_ah_keymin; + else + min = algo->keymin; + + if (!m) { +#if DIAGNOSTIC + if (l > MLEN) + panic("assumption failed in key_getcomb_ah"); +#endif + MGET(m, M_DONTWAIT, MT_DATA); + if (m) { + M_ALIGN(m, l); + m->m_len = l; + m->m_next = NULL; + } + } else + M_PREPEND(m, l, M_DONTWAIT); + if (!m) + return NULL; + + comb = mtod(m, struct sadb_comb *); + bzero(comb, sizeof(*comb)); + key_getcomb_setlifetime(comb); + comb->sadb_comb_auth = i; + comb->sadb_comb_auth_minbits = min; + comb->sadb_comb_auth_maxbits = algo->keymax; + } + + return m; +} + +/* + * not really an official behavior. discussed in pf_key@inner.net in Sep2000. + * XXX reorder combinations by preference + */ +static struct mbuf * +key_getcomb_ipcomp() +{ + struct sadb_comb *comb; + const struct ipcomp_algorithm *algo; + struct mbuf *m; + int i; + const int l = PFKEY_ALIGN8(sizeof(struct sadb_comb)); + + m = NULL; + for (i = 1; i <= SADB_X_CALG_MAX; i++) { + algo = ipcomp_algorithm_lookup(i); + if (!algo) + continue; + + if (!m) { +#if DIAGNOSTIC + if (l > MLEN) + panic("assumption failed in key_getcomb_ipcomp"); +#endif + MGET(m, M_DONTWAIT, MT_DATA); + if (m) { + M_ALIGN(m, l); + m->m_len = l; + m->m_next = NULL; + } + } else + M_PREPEND(m, l, M_DONTWAIT); + if (!m) + return NULL; + + comb = mtod(m, struct sadb_comb *); + bzero(comb, sizeof(*comb)); + key_getcomb_setlifetime(comb); + comb->sadb_comb_encrypt = i; + /* what should we set into sadb_comb_*_{min,max}bits? */ + } + + return m; +} + +/* + * XXX no way to pass mode (transport/tunnel) to userland + * XXX replay checking? + * XXX sysctl interface to ipsec_{ah,esp}_keymin + */ +static struct mbuf * +key_getprop(saidx) + const struct secasindex *saidx; +{ + struct sadb_prop *prop; + struct mbuf *m, *n; + const int l = PFKEY_ALIGN8(sizeof(struct sadb_prop)); + int totlen; + + switch (saidx->proto) { +#if IPSEC_ESP + case IPPROTO_ESP: + m = key_getcomb_esp(); + break; +#endif + case IPPROTO_AH: + m = key_getcomb_ah(); + break; + case IPPROTO_IPCOMP: + m = key_getcomb_ipcomp(); + break; + default: return NULL; } - /* create new sadb_msg to reply. */ - (void)key_setdumpsa(newmsg, sav, SADB_GET, - satype, msg0->sadb_msg_seq, msg0->sadb_msg_pid); + if (!m) + return NULL; + M_PREPEND(m, l, M_DONTWAIT); + if (!m) + return NULL; - return newmsg; - } + totlen = 0; + for (n = m; n; n = n->m_next) + totlen += n->m_len; + + prop = mtod(m, struct sadb_prop *); + bzero(prop, sizeof(*prop)); + prop->sadb_prop_len = PFKEY_UNIT64(totlen); + prop->sadb_prop_exttype = SADB_EXT_PROPOSAL; + prop->sadb_prop_replay = 32; /* XXX */ + + return m; } /* * SADB_ACQUIRE processing called by key_checkrequest() and key_acquire2(). * send - * * to KMD, and expect to receive * with SADB_ACQUIRE if error occured, @@ -5079,7 +5952,10 @@ key_get(mhp) * with SADB_GETSPI * from KMD by PF_KEY. * - * sensitivity is not supported. + * XXX x_policy is outside of RFC2367 (KAME extension). + * XXX sensitivity is not supported. + * XXX for ipcomp, RFC2367 does not define how to fill in proposal. + * see comment for key_getcomb_ipcomp(). * * OUT: * 0 : succeed @@ -5090,21 +5966,20 @@ key_acquire(saidx, sp) struct secasindex *saidx; struct secpolicy *sp; { + struct mbuf *result = NULL, *m; #ifndef IPSEC_NONBLOCK_ACQUIRE struct secacq *newacq; #endif - struct secpolicyindex *spidx = NULL; u_int8_t satype; - int error; + int error = -1; + u_int32_t seq; /* sanity check */ - if (saidx == NULL || sp == NULL) + if (saidx == NULL) panic("key_acquire: NULL pointer is passed.\n"); if ((satype = key_proto2satype(saidx->proto)) == 0) panic("key_acquire: invalid proto is passed.\n"); - spidx = &sp->spidx; - #ifndef IPSEC_NONBLOCK_ACQUIRE /* * We never do anything about acquirng SA. There is anather @@ -5132,124 +6007,52 @@ key_acquire(saidx, sp) } #endif - { - struct sadb_msg *newmsg = NULL; - union sadb_x_ident_id id; - u_int len; - caddr_t p; - - /* create new sadb_msg to reply. */ - len = sizeof(struct sadb_msg) - + sizeof(struct sadb_address) - + PFKEY_ALIGN8(saidx->src.ss_len) - + sizeof(struct sadb_address) - + PFKEY_ALIGN8(saidx->dst.ss_len) - + sizeof(struct sadb_x_policy) - + sizeof(struct sadb_ident) - + PFKEY_ALIGN8(spidx->src.ss_len) - + sizeof(struct sadb_ident) - + PFKEY_ALIGN8(spidx->dst.ss_len) - + sizeof(struct sadb_prop) - + sizeof(struct sadb_comb); /* XXX to be multiple */ - - KMALLOC(newmsg, struct sadb_msg *, len); - if (newmsg == 0) { -#if IPSEC_DEBUG - printf("key_acquire: No more memory.\n"); -#endif - return ENOBUFS; - } - bzero((caddr_t)newmsg, len); - - newmsg->sadb_msg_version = PF_KEY_V2; - newmsg->sadb_msg_type = SADB_ACQUIRE; - newmsg->sadb_msg_errno = 0; - newmsg->sadb_msg_satype = satype; - newmsg->sadb_msg_len = PFKEY_UNIT64(len); - newmsg->sadb_msg_mode = saidx->mode; - newmsg->sadb_msg_reqid = saidx->reqid; #ifndef IPSEC_NONBLOCK_ACQUIRE - newmsg->sadb_msg_seq = newacq->seq; + seq = newacq->seq; #else - newmsg->sadb_msg_seq = (acq_seq = (acq_seq == ~0 ? 1 : ++acq_seq)); + seq = (acq_seq = (acq_seq == ~0 ? 1 : ++acq_seq)); #endif - - newmsg->sadb_msg_pid = 0; - - p = (caddr_t)newmsg + sizeof(struct sadb_msg); + m = key_setsadbmsg(SADB_ACQUIRE, 0, satype, seq, 0, 0); + if (!m) { + error = ENOBUFS; + goto fail; + } + result = m; /* set sadb_address for saidx's. */ - p = key_setsadbaddr(p, - SADB_EXT_ADDRESS_SRC, - (struct sockaddr *)&saidx->src, - _INALENBYAF(saidx->src.ss_family) << 3, - IPSEC_ULPROTO_ANY); - p = key_setsadbaddr(p, - SADB_EXT_ADDRESS_DST, - (struct sockaddr *)&saidx->dst, - _INALENBYAF(saidx->dst.ss_family) << 3, - IPSEC_ULPROTO_ANY); + m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC, + (struct sockaddr *)&saidx->src, saidx->src.ss_len << 3, + IPSEC_ULPROTO_ANY); + if (!m) { + error = ENOBUFS; + goto fail; + } + m_cat(result, m); - /* set sadb_x_policy */ - p = key_setsadbxpolicy(p, sp->policy, sp->spidx.dir, sp->id); - - /* set sadb_address for spidx's. */ - bzero(&id, sizeof(id)); - id.sadb_x_ident_id_addr.prefix = spidx->prefs; - id.sadb_x_ident_id_addr.ul_proto = spidx->ul_proto; - p = key_setsadbident(p, - SADB_EXT_IDENTITY_SRC, - SADB_X_IDENTTYPE_ADDR, - (caddr_t)&spidx->src, - spidx->src.ss_len, - *(u_int64_t *)&id); - - bzero(&id, sizeof(id)); - id.sadb_x_ident_id_addr.prefix = spidx->prefd; - id.sadb_x_ident_id_addr.ul_proto = spidx->ul_proto; - p = key_setsadbident(p, - SADB_EXT_IDENTITY_DST, - SADB_X_IDENTTYPE_ADDR, - (caddr_t)&spidx->dst, - spidx->dst.ss_len, - *(u_int64_t *)&id); - - /* create proposal extension */ - /* set combination extension */ - /* XXX: to be defined by proposal database */ - { - struct sadb_prop *prop; - struct sadb_comb *comb; + m = key_setsadbaddr(SADB_EXT_ADDRESS_DST, + (struct sockaddr *)&saidx->dst, saidx->dst.ss_len << 3, + IPSEC_ULPROTO_ANY); + if (!m) { + error = ENOBUFS; + goto fail; + } + m_cat(result, m); - prop = (struct sadb_prop *)p; - prop->sadb_prop_len = PFKEY_UNIT64(sizeof(*prop) + sizeof(*comb)); - /* XXX to be multiple */ - prop->sadb_prop_exttype = SADB_EXT_PROPOSAL; - prop->sadb_prop_replay = 32; /* XXX be variable ? */ - p += sizeof(struct sadb_prop); - - comb = (struct sadb_comb *)p; - comb->sadb_comb_auth = SADB_AALG_SHA1HMAC; /* XXX ??? */ - comb->sadb_comb_encrypt = SADB_EALG_DESCBC; /* XXX ??? */ - comb->sadb_comb_flags = 0; - comb->sadb_comb_auth_minbits = 8; /* XXX */ - comb->sadb_comb_auth_maxbits = 1024; /* XXX */ - comb->sadb_comb_encrypt_minbits = 64; /* XXX */ - comb->sadb_comb_encrypt_maxbits = 64; /* XXX */ - comb->sadb_comb_soft_allocations = 0; - comb->sadb_comb_hard_allocations = 0; - comb->sadb_comb_soft_bytes = 0; - comb->sadb_comb_hard_bytes = 0; - comb->sadb_comb_soft_addtime = 0; - comb->sadb_comb_hard_addtime = 0; - comb->sadb_comb_soft_usetime = 0; - comb->sadb_comb_hard_usetime = 0; + /* XXX proxy address (optional) */ - p += sizeof(*comb); - } + /* set sadb_x_policy */ + if (sp) { + m = key_setsadbxpolicy(sp->policy, sp->spidx.dir, sp->id); + if (!m) { + error = ENOBUFS; + goto fail; + } + m_cat(result, m); + } -#if 0 /* XXX Do it ?*/ + /* XXX identity (optional) */ +#if 0 if (idexttype && fqdn) { /* create identity extension (FQDN) */ struct sadb_ident *id; @@ -5289,15 +6092,55 @@ key_acquire(saidx, sp) } #endif - error = key_sendall(newmsg, len); -#if IPSEC_DEBUG - if (error != 0) - printf("key_acquire: key_sendall returned %d\n", error); + /* XXX sensitivity (optional) */ + + /* create proposal/combination extension */ + m = key_getprop(saidx); +#if 0 + /* + * spec conformant: always attach proposal/combination extension, + * the problem is that we have no way to attach it for ipcomp, + * due to the way sadb_comb is declared in RFC2367. + */ + if (!m) { + error = ENOBUFS; + goto fail; + } + m_cat(result, m); +#else + /* + * outside of spec; make proposal/combination extension optional. + */ + if (m) + m_cat(result, m); #endif - return error; - } - return 0; + if ((result->m_flags & M_PKTHDR) == 0) { + error = EINVAL; + goto fail; + } + + if (result->m_len < sizeof(struct sadb_msg)) { + result = m_pullup(result, sizeof(struct sadb_msg)); + if (result == NULL) { + error = ENOBUFS; + goto fail; + } + } + + result->m_pkthdr.len = 0; + for (m = result; m; m = m->m_next) + result->m_pkthdr.len += m->m_len; + + mtod(result, struct sadb_msg *)->sadb_msg_len = + PFKEY_UNIT64(result->m_pkthdr.len); + + return key_sendup_mbuf(NULL, result, KEY_SENDUP_REGISTERED); + + fail: + if (result) + m_freem(result); + return error; } #ifndef IPSEC_NONBLOCK_ACQUIRE @@ -5306,6 +6149,7 @@ key_newacq(saidx) struct secasindex *saidx; { struct secacq *newacq; + struct timeval tv; /* get new entry */ KMALLOC(newacq, struct secacq *, sizeof(struct secacq)); @@ -5320,7 +6164,8 @@ key_newacq(saidx) /* copy secindex */ bcopy(saidx, &newacq->saidx, sizeof(newacq->saidx)); newacq->seq = (acq_seq == ~0 ? 1 : ++acq_seq); - newacq->tick = 0; + microtime(&tv); + newacq->created = tv.tv_sec; newacq->count = 0; return newacq; @@ -5360,6 +6205,7 @@ key_newspacq(spidx) struct secpolicyindex *spidx; { struct secspacq *acq; + struct timeval tv; /* get new entry */ KMALLOC(acq, struct secspacq *, sizeof(struct secspacq)); @@ -5373,7 +6219,8 @@ key_newspacq(spidx) /* copy secindex */ bcopy(spidx, &acq->spidx, sizeof(acq->spidx)); - acq->tick = 0; + microtime(&tv); + acq->created = tv.tv_sec; acq->count = 0; return acq; @@ -5405,59 +6252,60 @@ key_getspacq(spidx) * * to the socket. * - * IN: mhp: pointer to the pointer to each header. - * OUT: NULL if fail. - * other if success, return pointer to the message to send. + * m will always be freed. */ -static struct sadb_msg * -key_acquire2(mhp) - caddr_t *mhp; +static int +key_acquire2(so, m, mhp) + struct socket *so; + struct mbuf *m; + const struct sadb_msghdr *mhp; { - struct sadb_msg *msg0; - struct sadb_address *src0, *dst0; + const struct sadb_address *src0, *dst0; struct secasindex saidx; struct secashead *sah; u_int16_t proto; + int error; /* sanity check */ - if (mhp == NULL || mhp[0] == NULL) + if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_acquire2: NULL pointer is passed.\n"); - msg0 = (struct sadb_msg *)mhp[0]; - /* * Error message from KMd. * We assume that if error was occured in IKEd, the length of PFKEY * message is equal to the size of sadb_msg structure. - * We return ~0 even if error occured in this function. + * We do not raise error even if error occured in this function. */ - if (msg0->sadb_msg_len == PFKEY_UNIT64(sizeof(struct sadb_msg))) { - + if (mhp->msg->sadb_msg_len == PFKEY_UNIT64(sizeof(struct sadb_msg))) { #ifndef IPSEC_NONBLOCK_ACQUIRE struct secacq *acq; + struct timeval tv; /* check sequence number */ - if (msg0->sadb_msg_seq == 0) { + if (mhp->msg->sadb_msg_seq == 0) { #if IPSEC_DEBUG printf("key_acquire2: must specify sequence number.\n"); #endif - return (struct sadb_msg *)~0; + m_freem(m); + return 0; } - if ((acq = key_getacqbyseq(msg0->sadb_msg_seq)) == NULL) { -#if IPSEC_DEBUG - printf("key_acquire2: " - "invalid sequence number is passed.\n"); -#endif - return (struct sadb_msg *)~0; + if ((acq = key_getacqbyseq(mhp->msg->sadb_msg_seq)) == NULL) { + /* + * the specified larval SA is already gone, or we got + * a bogus sequence number. we can silently ignore it. + */ + m_freem(m); + return 0; } /* reset acq counter in order to deletion by timehander. */ - acq->tick = key_blockacq_lifetime; + microtime(&tv); + acq->created = tv.tv_sec; acq->count = 0; #endif - return (struct sadb_msg *)~0; - /* NOTREACHED */ + m_freem(m); + return 0; } /* @@ -5465,68 +6313,62 @@ key_acquire2(mhp) */ /* map satype to proto */ - if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { + if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) { #if IPSEC_DEBUG printf("key_acquire2: invalid satype is passed.\n"); #endif - msg0->sadb_msg_errno = EINVAL; - return NULL; + return key_senderror(so, m, EINVAL); } - if (mhp[SADB_EXT_ADDRESS_SRC] == NULL - || mhp[SADB_EXT_ADDRESS_DST] == NULL - || mhp[SADB_EXT_PROPOSAL] == NULL) { + if (mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL || + mhp->ext[SADB_EXT_ADDRESS_DST] == NULL || + mhp->ext[SADB_EXT_PROPOSAL] == NULL) { /* error */ #if IPSEC_DEBUG printf("key_acquire2: invalid message is passed.\n"); #endif - msg0->sadb_msg_errno = EINVAL; - return NULL; + return key_senderror(so, m, EINVAL); } - src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); - dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); + if (mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) || + mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address) || + mhp->extlen[SADB_EXT_PROPOSAL] < sizeof(struct sadb_prop)) { + /* error */ +#if IPSEC_DEBUG + printf("key_acquire2: invalid message is passed.\n"); +#endif + return key_senderror(so, m, EINVAL); + } + + src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC]; + dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST]; - KEY_SETSECASIDX(proto, msg0, src0+1, dst0+1, &saidx); + /* XXX boundary check against sa_len */ + KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx); /* get a SA index */ - if ((sah = key_getsah(&saidx)) != NULL) { + LIST_FOREACH(sah, &sahtree, chain) { + if (sah->state == SADB_SASTATE_DEAD) + continue; + if (key_cmpsaidx_withmode(&sah->saidx, &saidx)) + break; + } + if (sah != NULL) { #if IPSEC_DEBUG printf("key_acquire2: a SA exists already.\n"); #endif - msg0->sadb_msg_errno = EEXIST; - return NULL; + return key_senderror(so, m, EEXIST); } - msg0->sadb_msg_errno = key_acquire(&saidx, NULL); - if (msg0->sadb_msg_errno != 0) { + error = key_acquire(&saidx, NULL); + if (error != 0) { #if IPSEC_DEBUG printf("key_acquire2: error %d returned " - "from key_acquire.\n", msg0->sadb_msg_errno); -#endif - return NULL; - } - - { - struct sadb_msg *newmsg; - u_int len; - - /* create new sadb_msg to reply. */ - len = PFKEY_UNUNIT64(msg0->sadb_msg_len); - - KMALLOC(newmsg, struct sadb_msg *, len); - if (newmsg == NULL) { -#if IPSEC_DEBUG - printf("key_acquire2: No more memory.\n"); + "from key_acquire.\n", mhp->msg->sadb_msg_errno); #endif - msg0->sadb_msg_errno = ENOBUFS; - return NULL; + return key_senderror(so, m, error); } - bzero((caddr_t)newmsg, len); - bcopy(mhp[0], (caddr_t)newmsg, len); - - return newmsg; - } + return key_sendup_mbuf(so, m, KEY_SENDUP_REGISTERED); } /* @@ -5539,155 +6381,171 @@ key_acquire2(mhp) * * to KMD by PF_KEY. * If socket is detached, must free from regnode. - * OUT: - * 0 : succeed - * others: error number + * + * m will always be freed. */ -static struct sadb_msg * -key_register(mhp, so) - caddr_t *mhp; +static int +key_register(so, m, mhp) struct socket *so; + struct mbuf *m; + const struct sadb_msghdr *mhp; { - struct sadb_msg *msg0; struct secreg *reg, *newreg = 0; /* sanity check */ - if (mhp == NULL || so == NULL || mhp[0] == NULL) + if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_register: NULL pointer is passed.\n"); - msg0 = (struct sadb_msg *)mhp[0]; - /* check for invalid register message */ - if (msg0->sadb_msg_satype >= sizeof(regtree)/sizeof(regtree[0])) { - msg0->sadb_msg_errno = EINVAL; - return NULL; - } + if (mhp->msg->sadb_msg_satype >= sizeof(regtree)/sizeof(regtree[0])) + return key_senderror(so, m, EINVAL); /* When SATYPE_UNSPEC is specified, only return sabd_supported. */ - if (msg0->sadb_msg_satype == SADB_SATYPE_UNSPEC) + if (mhp->msg->sadb_msg_satype == SADB_SATYPE_UNSPEC) goto setmsg; /* check whether existing or not */ - LIST_FOREACH(reg, ®tree[msg0->sadb_msg_satype], chain) { + LIST_FOREACH(reg, ®tree[mhp->msg->sadb_msg_satype], chain) { if (reg->so == so) { #if IPSEC_DEBUG printf("key_register: socket exists already.\n"); #endif - msg0->sadb_msg_errno = EEXIST; - return NULL; + return key_senderror(so, m, EEXIST); } } /* create regnode */ - KMALLOC(newreg, struct secreg *, sizeof(struct secreg)); + KMALLOC(newreg, struct secreg *, sizeof(*newreg)); if (newreg == NULL) { #if IPSEC_DEBUG printf("key_register: No more memory.\n"); #endif - msg0->sadb_msg_errno = ENOBUFS; - return NULL; + return key_senderror(so, m, ENOBUFS); } - bzero((caddr_t)newreg, sizeof(struct secreg)); + bzero((caddr_t)newreg, sizeof(*newreg)); newreg->so = so; ((struct keycb *)sotorawcb(so))->kp_registered++; /* add regnode to regtree. */ - LIST_INSERT_HEAD(®tree[msg0->sadb_msg_satype], newreg, chain); + LIST_INSERT_HEAD(®tree[mhp->msg->sadb_msg_satype], newreg, chain); setmsg: - { + { + struct mbuf *n; struct sadb_msg *newmsg; struct sadb_supported *sup; u_int len, alen, elen; - caddr_t p; + int off; + int i; + struct sadb_alg *alg; /* create new sadb_msg to reply. */ - alen = sizeof(struct sadb_supported) - + ((SADB_AALG_MAX - 1) * sizeof(struct sadb_alg)); - -#if IPSEC_ESP - elen = sizeof(struct sadb_supported) - + ((SADB_EALG_MAX - 1) * sizeof(struct sadb_alg)); -#else + alen = 0; + for (i = 1; i <= SADB_AALG_MAX; i++) { + if (ah_algorithm_lookup(i)) + alen += sizeof(struct sadb_alg); + } + if (alen) + alen += sizeof(struct sadb_supported); elen = 0; +#if IPSEC_ESP + for (i = 1; i <= SADB_EALG_MAX; i++) { + if (esp_algorithm_lookup(i)) + elen += sizeof(struct sadb_alg); + } + if (elen) + elen += sizeof(struct sadb_supported); #endif - len = sizeof(struct sadb_msg) - + alen - + elen; + len = sizeof(struct sadb_msg) + alen + elen; - KMALLOC(newmsg, struct sadb_msg *, len); - if (newmsg == NULL) { -#if IPSEC_DEBUG - printf("key_register: No more memory.\n"); -#endif - msg0->sadb_msg_errno = ENOBUFS; - return NULL; + if (len > MCLBYTES) + return key_senderror(so, m, ENOBUFS); + + MGETHDR(n, M_DONTWAIT, MT_DATA); + if (len > MHLEN) { + MCLGET(n, M_DONTWAIT); + if ((n->m_flags & M_EXT) == 0) { + m_freem(n); + n = NULL; + } } - bzero((caddr_t)newmsg, len); + if (!n) + return key_senderror(so, m, ENOBUFS); + + n->m_pkthdr.len = n->m_len = len; + n->m_next = NULL; + off = 0; - bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0)); + m_copydata(m, 0, sizeof(struct sadb_msg), mtod(n, caddr_t) + off); + newmsg = mtod(n, struct sadb_msg *); newmsg->sadb_msg_errno = 0; newmsg->sadb_msg_len = PFKEY_UNIT64(len); - p = (caddr_t)newmsg + sizeof(*msg0); + off += PFKEY_ALIGN8(sizeof(struct sadb_msg)); /* for authentication algorithm */ - sup = (struct sadb_supported *)p; - sup->sadb_supported_len = PFKEY_UNIT64(alen); - sup->sadb_supported_exttype = SADB_EXT_SUPPORTED_AUTH; - p += sizeof(*sup); + if (alen) { + sup = (struct sadb_supported *)(mtod(n, caddr_t) + off); + sup->sadb_supported_len = PFKEY_UNIT64(alen); + sup->sadb_supported_exttype = SADB_EXT_SUPPORTED_AUTH; + off += PFKEY_ALIGN8(sizeof(*sup)); - { - int i; - struct sadb_alg *alg; - struct ah_algorithm *algo; + for (i = 1; i <= SADB_AALG_MAX; i++) { + const struct ah_algorithm *aalgo; - for (i = 1; i < SADB_AALG_MAX; i++) { - algo = &ah_algorithms[i]; - alg = (struct sadb_alg *)p; - alg->sadb_alg_id = i; - alg->sadb_alg_ivlen = 0; - alg->sadb_alg_minbits = algo->keymin; - alg->sadb_alg_maxbits = algo->keymax; - p += sizeof(struct sadb_alg); + aalgo = ah_algorithm_lookup(i); + if (!aalgo) + continue; + alg = (struct sadb_alg *)(mtod(n, caddr_t) + off); + alg->sadb_alg_id = i; + alg->sadb_alg_ivlen = 0; + alg->sadb_alg_minbits = aalgo->keymin; + alg->sadb_alg_maxbits = aalgo->keymax; + off += PFKEY_ALIGN8(sizeof(*alg)); + } } - } #if IPSEC_ESP /* for encryption algorithm */ - sup = (struct sadb_supported *)p; - sup->sadb_supported_len = PFKEY_UNIT64(elen); - sup->sadb_supported_exttype = SADB_EXT_SUPPORTED_ENCRYPT; - p += sizeof(*sup); - - { - int i; - struct sadb_alg *alg; - struct esp_algorithm *algo; + if (elen) { + sup = (struct sadb_supported *)(mtod(n, caddr_t) + off); + sup->sadb_supported_len = PFKEY_UNIT64(elen); + sup->sadb_supported_exttype = SADB_EXT_SUPPORTED_ENCRYPT; + off += PFKEY_ALIGN8(sizeof(*sup)); - for (i = 1; i < SADB_EALG_MAX; i++) { - algo = &esp_algorithms[i]; + for (i = 1; i <= SADB_EALG_MAX; i++) { + const struct esp_algorithm *ealgo; - alg = (struct sadb_alg *)p; - alg->sadb_alg_id = i; - if (algo && algo->ivlen) { - /* - * give NULL to get the value preferred by algorithm - * XXX SADB_X_EXT_DERIV ? - */ - alg->sadb_alg_ivlen = (*algo->ivlen)(NULL); - } else - alg->sadb_alg_ivlen = 0; - alg->sadb_alg_minbits = algo->keymin; - alg->sadb_alg_maxbits = algo->keymax; - p += sizeof(struct sadb_alg); + ealgo = esp_algorithm_lookup(i); + if (!ealgo) + continue; + alg = (struct sadb_alg *)(mtod(n, caddr_t) + off); + alg->sadb_alg_id = i; + if (ealgo && ealgo->ivlen) { + /* + * give NULL to get the value preferred by + * algorithm XXX SADB_X_EXT_DERIV ? + */ + alg->sadb_alg_ivlen = + (*ealgo->ivlen)(ealgo, NULL); + } else + alg->sadb_alg_ivlen = 0; + alg->sadb_alg_minbits = ealgo->keymin; + alg->sadb_alg_maxbits = ealgo->keymax; + off += PFKEY_ALIGN8(sizeof(struct sadb_alg)); + } } - } #endif - return newmsg; - } +#if DIGAGNOSTIC + if (off != len) + panic("length assumption failed in key_register"); +#endif + + m_freem(m); + return key_sendup_mbuf(so, n, KEY_SENDUP_REGISTERED); + } } /* @@ -5727,7 +6585,7 @@ key_freereg(so) /* * SADB_EXPIRE processing * send - * + * * to KMD by PF_KEY. * NOTE: We send only soft lifetime extension. * @@ -5740,13 +6598,13 @@ key_expire(sav) { int s; int satype; + struct mbuf *result = NULL, *m; + int len; + int error = -1; + struct sadb_lifetime *lt; /* XXX: Why do we lock ? */ -#ifdef __NetBSD__ - s = splsoftnet(); /*called from softclock()*/ -#else s = splnet(); /*called from softclock()*/ -#endif /* sanity check */ if (sav == NULL) @@ -5756,76 +6614,98 @@ key_expire(sav) if ((satype = key_proto2satype(sav->sah->saidx.proto)) == 0) panic("key_expire: invalid proto is passed.\n"); - { - struct sadb_msg *newmsg = NULL; - u_int len; - caddr_t p; - int error; - - /* create new sadb_msg to reply. */ - len = sizeof(struct sadb_msg) - + sizeof(struct sadb_sa) - + sizeof(struct sadb_lifetime) - + sizeof(struct sadb_lifetime) - + sizeof(struct sadb_address) - + PFKEY_ALIGN8(sav->sah->saidx.src.ss_len) - + sizeof(struct sadb_address) - + PFKEY_ALIGN8(sav->sah->saidx.dst.ss_len); - - KMALLOC(newmsg, struct sadb_msg *, len); - if (newmsg == NULL) { -#if IPSEC_DEBUG - printf("key_expire: No more memory.\n"); -#endif - splx(s); - return ENOBUFS; + /* set msg header */ + m = key_setsadbmsg(SADB_EXPIRE, 0, satype, sav->seq, 0, sav->refcnt); + if (!m) { + error = ENOBUFS; + goto fail; } - bzero((caddr_t)newmsg, len); + result = m; - /* set msg header */ - p = key_setsadbmsg((caddr_t)newmsg, SADB_EXPIRE, len, - satype, sav->seq, 0, - sav->sah->saidx.mode, sav->sah->saidx.reqid, - 0, sav->refcnt); + /* create SA extension */ + m = key_setsadbsa(sav); + if (!m) { + error = ENOBUFS; + goto fail; + } + m_cat(result, m); /* create SA extension */ - p = key_setsadbsa(p, sav); + m = key_setsadbxsa2(sav->sah->saidx.mode, sav->sah->saidx.reqid); + if (!m) { + error = ENOBUFS; + goto fail; + } + m_cat(result, m); - /* create lifetime extension */ - { - struct sadb_lifetime *m_lt = (struct sadb_lifetime *)p; - - m_lt->sadb_lifetime_len = PFKEY_UNIT64(sizeof(struct sadb_lifetime)); - m_lt->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT; - m_lt->sadb_lifetime_allocations = sav->lft_c->sadb_lifetime_allocations; - m_lt->sadb_lifetime_bytes = sav->lft_c->sadb_lifetime_bytes; - m_lt->sadb_lifetime_addtime = sav->lft_c->sadb_lifetime_addtime; - m_lt->sadb_lifetime_usetime = sav->lft_c->sadb_lifetime_usetime; - p += sizeof(struct sadb_lifetime); - - /* copy SOFT lifetime extension. */ - bcopy(sav->lft_s, p, sizeof(struct sadb_lifetime)); - p += sizeof(struct sadb_lifetime); - } + /* create lifetime extension (current and soft) */ + len = PFKEY_ALIGN8(sizeof(*lt)) * 2; + m = key_alloc_mbuf(len); + if (!m || m->m_next) { /*XXX*/ + if (m) + m_freem(m); + error = ENOBUFS; + goto fail; + } + bzero(mtod(m, caddr_t), len); + lt = mtod(m, struct sadb_lifetime *); + lt->sadb_lifetime_len = PFKEY_UNIT64(sizeof(struct sadb_lifetime)); + lt->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT; + lt->sadb_lifetime_allocations = sav->lft_c->sadb_lifetime_allocations; + lt->sadb_lifetime_bytes = sav->lft_c->sadb_lifetime_bytes; + lt->sadb_lifetime_addtime = sav->lft_c->sadb_lifetime_addtime; + lt->sadb_lifetime_usetime = sav->lft_c->sadb_lifetime_usetime; + lt = (struct sadb_lifetime *)(mtod(m, caddr_t) + len / 2); + bcopy(sav->lft_s, lt, sizeof(*lt)); + m_cat(result, m); /* set sadb_address for source */ - p = key_setsadbaddr(p, - SADB_EXT_ADDRESS_SRC, - (struct sockaddr *)&sav->sah->saidx.src, - _INALENBYAF(sav->sah->saidx.src.ss_family) << 3, - IPSEC_ULPROTO_ANY); + m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC, + (struct sockaddr *)&sav->sah->saidx.src, + sav->sah->saidx.src.ss_len << 3, IPSEC_ULPROTO_ANY); + if (!m) { + error = ENOBUFS; + goto fail; + } + m_cat(result, m); /* set sadb_address for destination */ - p = key_setsadbaddr(p, - SADB_EXT_ADDRESS_DST, - (struct sockaddr *)&sav->sah->saidx.dst, - _INALENBYAF(sav->sah->saidx.dst.ss_family) << 3, - IPSEC_ULPROTO_ANY); + m = key_setsadbaddr(SADB_EXT_ADDRESS_DST, + (struct sockaddr *)&sav->sah->saidx.dst, + sav->sah->saidx.dst.ss_len << 3, IPSEC_ULPROTO_ANY); + if (!m) { + error = ENOBUFS; + goto fail; + } + m_cat(result, m); + + if ((result->m_flags & M_PKTHDR) == 0) { + error = EINVAL; + goto fail; + } + + if (result->m_len < sizeof(struct sadb_msg)) { + result = m_pullup(result, sizeof(struct sadb_msg)); + if (result == NULL) { + error = ENOBUFS; + goto fail; + } + } + + result->m_pkthdr.len = 0; + for (m = result; m; m = m->m_next) + result->m_pkthdr.len += m->m_len; - error = key_sendall(newmsg, len); + mtod(result, struct sadb_msg *)->sadb_msg_len = + PFKEY_UNIT64(result->m_pkthdr.len); + + return key_sendup_mbuf(NULL, result, KEY_SENDUP_REGISTERED); + + fail: + if (result) + m_freem(result); splx(s); return error; - } } /* @@ -5838,15 +6718,15 @@ key_expire(sav) * to the ikmpd. * NOTE: to do is only marking SADB_SASTATE_DEAD. * - * IN: mhp: pointer to the pointer to each header. - * OUT: NULL if fail. - * other if success, return pointer to the message to send. + * m will always be freed. */ -static struct sadb_msg * -key_flush(mhp) - caddr_t *mhp; +static int +key_flush(so, m, mhp) + struct socket *so; + struct mbuf *m; + const struct sadb_msghdr *mhp; { - struct sadb_msg *msg0; + struct sadb_msg *newmsg; struct secashead *sah, *nextsah; struct secasvar *sav, *nextsav; u_int16_t proto; @@ -5854,35 +6734,30 @@ key_flush(mhp) u_int stateidx; /* sanity check */ - if (mhp == NULL || mhp[0] == NULL) + if (so == NULL || mhp == NULL || mhp->msg == NULL) panic("key_flush: NULL pointer is passed.\n"); - msg0 = (struct sadb_msg *)mhp[0]; - /* map satype to proto */ - if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { + if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) { #if IPSEC_DEBUG printf("key_flush: invalid satype is passed.\n"); #endif - msg0->sadb_msg_errno = EINVAL; - return NULL; + return key_senderror(so, m, EINVAL); } /* no SATYPE specified, i.e. flushing all SA. */ for (sah = LIST_FIRST(&sahtree); sah != NULL; sah = nextsah) { - nextsah = LIST_NEXT(sah, chain); - if (msg0->sadb_msg_satype != SADB_SATYPE_UNSPEC + if (mhp->msg->sadb_msg_satype != SADB_SATYPE_UNSPEC && proto != sah->saidx.proto) continue; for (stateidx = 0; stateidx < _ARRAYLEN(saorder_state_alive); stateidx++) { - state = saorder_state_any[stateidx]; for (sav = LIST_FIRST(&sah->savtree[state]); sav != NULL; @@ -5898,29 +6773,23 @@ key_flush(mhp) sah->state = SADB_SASTATE_DEAD; } - { - struct sadb_msg *newmsg; - u_int len; - - /* create new sadb_msg to reply. */ - len = sizeof(struct sadb_msg); - - KMALLOC(newmsg, struct sadb_msg *, len); - if (newmsg == NULL) { + if (m->m_len < sizeof(struct sadb_msg) || + sizeof(struct sadb_msg) > m->m_len + M_TRAILINGSPACE(m)) { #if IPSEC_DEBUG printf("key_flush: No more memory.\n"); #endif - msg0->sadb_msg_errno = ENOBUFS; - return NULL; + return key_senderror(so, m, ENOBUFS); } - bzero((caddr_t)newmsg, len); - bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0)); + if (m->m_next) + m_freem(m->m_next); + m->m_next = NULL; + m->m_pkthdr.len = m->m_len = sizeof(struct sadb_msg); + newmsg = mtod(m, struct sadb_msg *); newmsg->sadb_msg_errno = 0; - newmsg->sadb_msg_len = PFKEY_UNIT64(len); + newmsg->sadb_msg_len = PFKEY_UNIT64(m->m_pkthdr.len); - return newmsg; - } + return key_sendup_mbuf(so, m, KEY_SENDUP_ALL); } /* @@ -5933,52 +6802,46 @@ key_flush(mhp) * ..... * to the ikmpd. * - * IN: mhp: pointer to the pointer to each header. - * OUT: error code. 0 on success. + * m will always be freed. */ static int -key_dump(mhp, so, target) - caddr_t *mhp; +key_dump(so, m, mhp) struct socket *so; - int target; + struct mbuf *m; + const struct sadb_msghdr *mhp; { - struct sadb_msg *msg0; struct secashead *sah; struct secasvar *sav; u_int16_t proto; u_int stateidx; u_int8_t satype; u_int8_t state; - int len, cnt; + int cnt; struct sadb_msg *newmsg; + struct mbuf *n; /* sanity check */ - if (mhp == NULL || mhp[0] == NULL) + if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_dump: NULL pointer is passed.\n"); - msg0 = (struct sadb_msg *)mhp[0]; - /* map satype to proto */ - if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { + if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) { #if IPSEC_DEBUG printf("key_dump: invalid satype is passed.\n"); #endif - msg0->sadb_msg_errno = EINVAL; - return NULL; + return key_senderror(so, m, EINVAL); } /* count sav entries to be sent to the userland. */ cnt = 0; LIST_FOREACH(sah, &sahtree, chain) { - - if (msg0->sadb_msg_satype != SADB_SATYPE_UNSPEC + if (mhp->msg->sadb_msg_satype != SADB_SATYPE_UNSPEC && proto != sah->saidx.proto) continue; for (stateidx = 0; stateidx < _ARRAYLEN(saorder_state_any); stateidx++) { - state = saorder_state_any[stateidx]; LIST_FOREACH(sav, &sah->savtree[state], chain) { cnt++; @@ -5987,13 +6850,12 @@ key_dump(mhp, so, target) } if (cnt == 0) - return ENOENT; + return key_senderror(so, m, ENOENT); /* send this to the userland, one at a time. */ newmsg = NULL; LIST_FOREACH(sah, &sahtree, chain) { - - if (msg0->sadb_msg_satype != SADB_SATYPE_UNSPEC + if (mhp->msg->sadb_msg_satype != SADB_SATYPE_UNSPEC && proto != sah->saidx.proto) continue; @@ -6002,145 +6864,109 @@ key_dump(mhp, so, target) #if IPSEC_DEBUG printf("key_dump: there was invalid proto in SAD.\n"); #endif - msg0->sadb_msg_errno = EINVAL; - return NULL; + return key_senderror(so, m, EINVAL); } for (stateidx = 0; stateidx < _ARRAYLEN(saorder_state_any); stateidx++) { - state = saorder_state_any[stateidx]; LIST_FOREACH(sav, &sah->savtree[state], chain) { + n = key_setdumpsa(sav, SADB_DUMP, satype, + --cnt, mhp->msg->sadb_msg_pid); + if (!n) + return key_senderror(so, m, ENOBUFS); - len = key_getmsglen(sav); - KMALLOC(newmsg, struct sadb_msg *, len); - if (newmsg == NULL) { -#if IPSEC_DEBUG - printf("key_dump: No more memory.\n"); -#endif - return ENOBUFS; - } - bzero((caddr_t)newmsg, len); - - --cnt; - (void)key_setdumpsa(newmsg, sav, SADB_DUMP, - satype, cnt, msg0->sadb_msg_pid); - - key_sendup(so, newmsg, len, target); - KFREE(newmsg); - newmsg = NULL; + key_sendup_mbuf(so, n, KEY_SENDUP_ONE); } } } + m_freem(m); return 0; } /* * SADB_X_PROMISC processing + * + * m will always be freed. */ -static void -key_promisc(mhp, so) - caddr_t *mhp; +static int +key_promisc(so, m, mhp) struct socket *so; + struct mbuf *m; + const struct sadb_msghdr *mhp; { - struct sadb_msg *msg0; int olen; /* sanity check */ - if (mhp == NULL || mhp[0] == NULL) + if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_promisc: NULL pointer is passed.\n"); - msg0 = (struct sadb_msg *)mhp[0]; - olen = PFKEY_UNUNIT64(msg0->sadb_msg_len); + olen = PFKEY_UNUNIT64(mhp->msg->sadb_msg_len); if (olen < sizeof(struct sadb_msg)) { - return; +#if 1 + return key_senderror(so, m, EINVAL); +#else + m_freem(m); + return 0; +#endif } else if (olen == sizeof(struct sadb_msg)) { /* enable/disable promisc mode */ struct keycb *kp; - int target = 0; - - target = KEY_SENDUP_ONE; - if (so == NULL) { - return; - } - if ((kp = (struct keycb *)sotorawcb(so)) == NULL) { - msg0->sadb_msg_errno = EINVAL; - goto sendorig; - } - msg0->sadb_msg_errno = 0; - if (msg0->sadb_msg_satype == 1 || msg0->sadb_msg_satype == 0) { - kp->kp_promisc = msg0->sadb_msg_satype; - } else { - msg0->sadb_msg_errno = EINVAL; - goto sendorig; + if ((kp = (struct keycb *)sotorawcb(so)) == NULL) + return key_senderror(so, m, EINVAL); + mhp->msg->sadb_msg_errno = 0; + switch (mhp->msg->sadb_msg_satype) { + case 0: + case 1: + kp->kp_promisc = mhp->msg->sadb_msg_satype; + break; + default: + return key_senderror(so, m, EINVAL); } /* send the original message back to everyone */ - msg0->sadb_msg_errno = 0; - target = KEY_SENDUP_ALL; -sendorig: - key_sendup(so, msg0, PFKEY_UNUNIT64(msg0->sadb_msg_len), target); + mhp->msg->sadb_msg_errno = 0; + return key_sendup_mbuf(so, m, KEY_SENDUP_ALL); } else { /* send packet as is */ - struct sadb_msg *msg; - int len; - len = olen - sizeof(struct sadb_msg); - KMALLOC(msg, struct sadb_msg *, len); - if (msg == NULL) { - msg0->sadb_msg_errno = ENOBUFS; - key_sendup(so, msg0, PFKEY_UNUNIT64(msg0->sadb_msg_len), - KEY_SENDUP_ONE); /*XXX*/ - } + m_adj(m, PFKEY_ALIGN8(sizeof(struct sadb_msg))); - /* XXX if sadb_msg_seq is specified, send to specific pid */ - key_sendup(so, msg, len, KEY_SENDUP_ALL); - KFREE(msg); + /* TODO: if sadb_msg_seq is specified, send to specific pid */ + return key_sendup_mbuf(so, m, KEY_SENDUP_ALL); } } -/* - * send message to the socket. - * OUT: - * 0 : success - * others : fail - */ -static int -key_sendall(msg, len) - struct sadb_msg *msg; - u_int len; -{ - struct secreg *reg; - int error = 0; - - /* sanity check */ - if (msg == NULL) - panic("key_sendall: NULL pointer is passed.\n"); - - /* search table registerd socket to send a message. */ - LIST_FOREACH(reg, ®tree[msg->sadb_msg_satype], chain) { - error = key_sendup(reg->so, msg, len, KEY_SENDUP_ONE); - if (error != 0) { -#if IPSEC_DEBUG - if (error == ENOBUFS) - printf("key_sendall: No more memory.\n"); - else { - printf("key_sendall: key_sendup returned %d\n", - error); - } -#endif - KFREE(msg); - return error; - } - } - - KFREE(msg); - return 0; -} +static int (*key_typesw[]) __P((struct socket *, struct mbuf *, + const struct sadb_msghdr *)) = { + NULL, /* SADB_RESERVED */ + key_getspi, /* SADB_GETSPI */ + key_update, /* SADB_UPDATE */ + key_add, /* SADB_ADD */ + key_delete, /* SADB_DELETE */ + key_get, /* SADB_GET */ + key_acquire2, /* SADB_ACQUIRE */ + key_register, /* SADB_REGISTER */ + NULL, /* SADB_EXPIRE */ + key_flush, /* SADB_FLUSH */ + key_dump, /* SADB_DUMP */ + key_promisc, /* SADB_X_PROMISC */ + NULL, /* SADB_X_PCHANGE */ + key_spdadd, /* SADB_X_SPDUPDATE */ + key_spdadd, /* SADB_X_SPDADD */ + key_spddelete, /* SADB_X_SPDDELETE */ + key_spdget, /* SADB_X_SPDGET */ + NULL, /* SADB_X_SPDACQUIRE */ + key_spddump, /* SADB_X_SPDDUMP */ + key_spdflush, /* SADB_X_SPDFLUSH */ + key_spdadd, /* SADB_X_SPDSETIDX */ + NULL, /* SADB_X_SPDEXPIRE */ + key_spddelete2, /* SADB_X_SPDDELETE2 */ +}; /* * parse sadb_msg buffer to process PFKEYv2, @@ -6154,57 +6980,104 @@ key_sendall(msg, len) * length for buffer to send to user process. */ int -key_parse(msgp, so, targetp) - struct sadb_msg **msgp; +key_parse(m, so) + struct mbuf *m; struct socket *so; - int *targetp; { - struct sadb_msg *msg = *msgp, *newmsg = NULL; - caddr_t mhp[SADB_EXT_MAX + 1]; + struct sadb_msg *msg; + struct sadb_msghdr mh; u_int orglen; int error; + int target; /* sanity check */ - if (msg == NULL || so == NULL) + if (m == NULL || so == NULL) panic("key_parse: NULL pointer is passed.\n"); +#if 0 /*kdebug_sadb assumes msg in linear buffer*/ KEYDEBUG(KEYDEBUG_KEY_DUMP, printf("key_parse: passed sadb_msg\n"); kdebug_sadb(msg)); +#endif + if (m->m_len < sizeof(struct sadb_msg)) { + m = m_pullup(m, sizeof(struct sadb_msg)); + if (!m) + return ENOBUFS; + } + msg = mtod(m, struct sadb_msg *); orglen = PFKEY_UNUNIT64(msg->sadb_msg_len); + target = KEY_SENDUP_ONE; - if (targetp) - *targetp = KEY_SENDUP_ONE; + if ((m->m_flags & M_PKTHDR) == 0 || + m->m_pkthdr.len != m->m_pkthdr.len) { +#if IPSEC_DEBUG + printf("key_parse: invalid message length.\n"); +#endif + pfkeystat.out_invlen++; + error = EINVAL; + goto senderror; + } - /* check version */ if (msg->sadb_msg_version != PF_KEY_V2) { #if IPSEC_DEBUG printf("key_parse: PF_KEY version %u is mismatched.\n", msg->sadb_msg_version); #endif pfkeystat.out_invver++; - msg->sadb_msg_errno = EINVAL; - return orglen; + error = EINVAL; + goto senderror; } - /* check type */ if (msg->sadb_msg_type > SADB_MAX) { #if IPSEC_DEBUG printf("key_parse: invalid type %u is passed.\n", msg->sadb_msg_type); #endif - msg->sadb_msg_errno = EINVAL; pfkeystat.out_invmsgtype++; - return orglen; + error = EINVAL; + goto senderror; + } + + /* for old-fashioned code - should be nuked */ + if (m->m_pkthdr.len > MCLBYTES) { + m_freem(m); + return ENOBUFS; + } + if (m->m_next) { + struct mbuf *n; + + MGETHDR(n, M_DONTWAIT, MT_DATA); + if (n && m->m_pkthdr.len > MHLEN) { + MCLGET(n, M_DONTWAIT); + if ((n->m_flags & M_EXT) == 0) { + m_free(n); + n = NULL; + } + } + if (!n) { + m_freem(m); + return ENOBUFS; + } + m_copydata(m, 0, m->m_pkthdr.len, mtod(n, caddr_t)); + n->m_pkthdr.len = n->m_len = m->m_pkthdr.len; + n->m_next = NULL; + m_freem(m); + m = n; } - /* align message. */ - if (key_align(msg, mhp) != 0) { - msg->sadb_msg_errno = EINVAL; - return orglen; + /* align the mbuf chain so that extensions are in contiguous region. */ + error = key_align(m, &mh); + if (error) + return error; + + if (m->m_next) { /*XXX*/ + m_freem(m); + return ENOBUFS; } + msg = mh.msg; + /* check SA type */ switch (msg->sadb_msg_satype) { case SADB_SATYPE_UNSPEC: @@ -6221,16 +7094,14 @@ key_parse(msgp, so, targetp) "when msg type=%u.\n", msg->sadb_msg_type); #endif - msg->sadb_msg_errno = EINVAL; pfkeystat.out_invsatype++; - return orglen; + error = EINVAL; + goto senderror; } break; case SADB_SATYPE_AH: case SADB_SATYPE_ESP: -#if 1 /*nonstandard*/ case SADB_X_SATYPE_IPCOMP: -#endif switch (msg->sadb_msg_type) { case SADB_X_SPDADD: case SADB_X_SPDDELETE: @@ -6244,9 +7115,9 @@ key_parse(msgp, so, targetp) printf("key_parse: illegal satype=%u\n", msg->sadb_msg_type); #endif - msg->sadb_msg_errno = EINVAL; pfkeystat.out_invsatype++; - return orglen; + error = EINVAL; + goto senderror; } break; case SADB_SATYPE_RSVP: @@ -6257,10 +7128,10 @@ key_parse(msgp, so, targetp) printf("key_parse: type %u isn't supported.\n", msg->sadb_msg_satype); #endif - msg->sadb_msg_errno = EOPNOTSUPP; pfkeystat.out_invsatype++; - return orglen; - case 1: /* XXX: What does it do ? */ + error = EOPNOTSUPP; + goto senderror; + case 1: /* XXX: What does it do? */ if (msg->sadb_msg_type == SADB_X_PROMISC) break; /*FALLTHROUGH*/ @@ -6269,288 +7140,182 @@ key_parse(msgp, so, targetp) printf("key_parse: invalid type %u is passed.\n", msg->sadb_msg_satype); #endif - msg->sadb_msg_errno = EINVAL; pfkeystat.out_invsatype++; - return orglen; + error = EINVAL; + goto senderror; } /* check field of upper layer protocol and address family */ - if (mhp[SADB_EXT_ADDRESS_SRC] != NULL - && mhp[SADB_EXT_ADDRESS_DST] != NULL) { + if (mh.ext[SADB_EXT_ADDRESS_SRC] != NULL + && mh.ext[SADB_EXT_ADDRESS_DST] != NULL) { struct sadb_address *src0, *dst0; - u_int prefix; + u_int plen; - src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); - dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); + src0 = (struct sadb_address *)(mh.ext[SADB_EXT_ADDRESS_SRC]); + dst0 = (struct sadb_address *)(mh.ext[SADB_EXT_ADDRESS_DST]); /* check upper layer protocol */ if (src0->sadb_address_proto != dst0->sadb_address_proto) { #if IPSEC_DEBUG printf("key_parse: upper layer protocol mismatched.\n"); #endif - msg->sadb_msg_errno = EINVAL; pfkeystat.out_invaddr++; - return orglen; + error = EINVAL; + goto senderror; } /* check family */ - if (PFKEY_ADDR_SADDR(src0)->sa_family - != PFKEY_ADDR_SADDR(dst0)->sa_family) { + if (PFKEY_ADDR_SADDR(src0)->sa_family != + PFKEY_ADDR_SADDR(dst0)->sa_family) { #if IPSEC_DEBUG printf("key_parse: address family mismatched.\n"); #endif - msg->sadb_msg_errno = EINVAL; pfkeystat.out_invaddr++; - return orglen; + error = EINVAL; + goto senderror; } - - prefix = _INALENBYAF(PFKEY_ADDR_SADDR(src0)->sa_family) << 3; - - /* check max prefixlen */ - if (prefix < src0->sadb_address_prefixlen - || prefix < dst0->sadb_address_prefixlen) { + if (PFKEY_ADDR_SADDR(src0)->sa_len != + PFKEY_ADDR_SADDR(dst0)->sa_len) { #if IPSEC_DEBUG - printf("key_parse: illegal prefixlen.\n"); + printf("key_parse: address struct size mismatched.\n"); #endif - msg->sadb_msg_errno = EINVAL; pfkeystat.out_invaddr++; - return orglen; + error = EINVAL; + goto senderror; } switch (PFKEY_ADDR_SADDR(src0)->sa_family) { case AF_INET: + if (PFKEY_ADDR_SADDR(src0)->sa_len != + sizeof(struct sockaddr_in)) { + pfkeystat.out_invaddr++; + error = EINVAL; + goto senderror; + } + break; case AF_INET6: + if (PFKEY_ADDR_SADDR(src0)->sa_len != + sizeof(struct sockaddr_in6)) { + pfkeystat.out_invaddr++; + error = EINVAL; + goto senderror; + } break; default: #if IPSEC_DEBUG - printf("key_parse: invalid address family.\n"); + printf("key_parse: unsupported address family.\n"); #endif - msg->sadb_msg_errno = EINVAL; pfkeystat.out_invaddr++; - return orglen; + error = EAFNOSUPPORT; + goto senderror; } - /* - * prefixlen == 0 is valid because there can be a case when - * all addresses are matched. - */ - } - - switch (msg->sadb_msg_type) { - case SADB_GETSPI: - if ((newmsg = key_getspi(mhp)) == NULL) - return orglen; - if (targetp) - *targetp = KEY_SENDUP_ALL; - break; - - case SADB_UPDATE: - if ((newmsg = key_update(mhp)) == NULL) - return orglen; - if (targetp) - *targetp = KEY_SENDUP_ALL; - break; - - case SADB_ADD: - if ((newmsg = key_add(mhp)) == NULL) - return orglen; - if (targetp) - *targetp = KEY_SENDUP_ALL; - break; - - case SADB_DELETE: - if ((newmsg = key_delete(mhp)) == NULL) - return orglen; - if (targetp) - *targetp = KEY_SENDUP_ALL; - break; - - case SADB_GET: - if ((newmsg = key_get(mhp)) == NULL) - return orglen; - break; - - case SADB_ACQUIRE: - if ((newmsg = key_acquire2(mhp)) == NULL) - return orglen; - - if (newmsg == (struct sadb_msg *)~0) { - /* - * It's not need to reply because of the message - * that was reporting an error occured from the KMd. - */ - KFREE(msg); - return 0; + switch (PFKEY_ADDR_SADDR(src0)->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + plen = 0; /*fool gcc*/ + break; } - break; - - case SADB_REGISTER: - if ((newmsg = key_register(mhp, so)) == NULL) - return orglen; -#if 1 - if (targetp) - *targetp = KEY_SENDUP_REGISTERED; -#else - /* send result to all registered sockets */ - KFREE(msg); - key_sendall(newmsg, PFKEY_UNUNIT64(newmsg->sadb_msg_len)); - return 0; -#endif - break; - case SADB_EXPIRE: + /* check max prefix length */ + if (src0->sadb_address_prefixlen > plen || + dst0->sadb_address_prefixlen > plen) { #if IPSEC_DEBUG - printf("key_parse: why is SADB_EXPIRE received ?\n"); + printf("key_parse: illegal prefixlen.\n"); #endif - msg->sadb_msg_errno = EINVAL; - if (targetp) - *targetp = KEY_SENDUP_ALL; - pfkeystat.out_invmsgtype++; - return orglen; - - case SADB_FLUSH: - if ((newmsg = key_flush(mhp)) == NULL) - return orglen; - if (targetp) - *targetp = KEY_SENDUP_ALL; - break; - - case SADB_DUMP: - /* key_dump will call key_sendup() on her own */ - error = key_dump(mhp, so, KEY_SENDUP_ONE); - if (error) { - msg->sadb_msg_errno = error; - return orglen; - } else { - KFREE(msg); - return 0; + pfkeystat.out_invaddr++; + error = EINVAL; + goto senderror; } - break; - case SADB_X_PROMISC: - /* everything is handled in key_promisc() */ - key_promisc(mhp, so); - KFREE(msg); - return 0; /*nothing to reply*/ + /* + * prefixlen == 0 is valid because there can be a case when + * all addresses are matched. + */ + } - case SADB_X_PCHANGE: -#if IPSEC_DEBUG - printf("key_parse: SADB_X_PCHANGE isn't supported.\n"); -#endif - msg->sadb_msg_errno = EINVAL; + if (msg->sadb_msg_type >= sizeof(key_typesw)/sizeof(key_typesw[0]) || + key_typesw[msg->sadb_msg_type] == NULL) { pfkeystat.out_invmsgtype++; - return orglen; -#if 0 - if (targetp) - *targetp = KEY_SENDUP_REGISTERED; -#endif - - case SADB_X_SPDADD: - case SADB_X_SPDSETIDX: - case SADB_X_SPDUPDATE: - if ((newmsg = key_spdadd(mhp)) == NULL) - return orglen; - if (targetp) - *targetp = KEY_SENDUP_ALL; - break; - - case SADB_X_SPDDELETE: - if ((newmsg = key_spddelete(mhp)) == NULL) - return orglen; - if (targetp) - *targetp = KEY_SENDUP_ALL; - break; - - case SADB_X_SPDDELETE2: - if ((newmsg = key_spddelete2(mhp)) == NULL) - return orglen; - if (targetp) - *targetp = KEY_SENDUP_ALL; - break; - - case SADB_X_SPDGET: - /* key_spdget will call key_sendup() on her own */ - error = key_spdget(mhp, so, KEY_SENDUP_ONE); - if (error) { - msg->sadb_msg_errno = error; - return orglen; - } else { - KFREE(msg); - return 0; - } - break; + error = EINVAL; + goto senderror; + } - case SADB_X_SPDDUMP: - /* key_spddump will call key_sendup() on her own */ - error = key_spddump(mhp, so, KEY_SENDUP_ONE); - if (error) { - msg->sadb_msg_errno = error; - return orglen; - } else { - KFREE(msg); - return 0; - } - break; + return (*key_typesw[msg->sadb_msg_type])(so, m, &mh); - case SADB_X_SPDFLUSH: - if ((newmsg = key_spdflush(mhp)) == NULL) - return orglen; - if (targetp) - *targetp = KEY_SENDUP_ALL; - break; +senderror: + msg->sadb_msg_errno = error; + return key_sendup_mbuf(so, m, target); +} - default: - msg->sadb_msg_errno = EOPNOTSUPP; - return orglen; - } +static int +key_senderror(so, m, code) + struct socket *so; + struct mbuf *m; + int code; +{ + struct sadb_msg *msg; - /* switch from old sadb_msg to new one if success. */ - KFREE(msg); - *msgp = newmsg; + if (m->m_len < sizeof(struct sadb_msg)) + panic("invalid mbuf passed to key_senderror"); - return PFKEY_UNUNIT64((*msgp)->sadb_msg_len); + msg = mtod(m, struct sadb_msg *); + msg->sadb_msg_errno = code; + return key_sendup_mbuf(so, m, KEY_SENDUP_ONE); } /* * set the pointer to each header into message buffer. - * IN: msg: pointer to message buffer. - * mhp: pointer to the buffer allocated like below: - * caddr_t mhp[SADB_EXT_MAX + 1]; - * OUT: 0: - * EINVAL: + * m will be freed on error. + * XXX larger-than-MCLBYTES extension? */ static int -key_align(msg, mhp) - struct sadb_msg *msg; - caddr_t *mhp; +key_align(m, mhp) + struct mbuf *m; + struct sadb_msghdr *mhp; { + struct mbuf *n; struct sadb_ext *ext; - int tlen, extlen; - int i; + size_t off, end; + int extlen; + int toff; /* sanity check */ - if (msg == NULL || mhp == NULL) + if (m == NULL || mhp == NULL) panic("key_align: NULL pointer is passed.\n"); + if (m->m_len < sizeof(struct sadb_msg)) + panic("invalid mbuf passed to key_align"); /* initialize */ - for (i = 0; i < SADB_EXT_MAX + 1; i++) - mhp[i] = NULL; + bzero(mhp, sizeof(*mhp)); - mhp[0] = (caddr_t)msg; + mhp->msg = mtod(m, struct sadb_msg *); + mhp->ext[0] = (struct sadb_ext *)mhp->msg; /*XXX backward compat */ - tlen = PFKEY_UNUNIT64(msg->sadb_msg_len) - sizeof(struct sadb_msg); - ext = (struct sadb_ext *)((caddr_t)msg + sizeof(struct sadb_msg)); + end = PFKEY_UNUNIT64(mhp->msg->sadb_msg_len); + extlen = end; /*just in case extlen is not updated*/ + for (off = sizeof(struct sadb_msg); off < end; off += extlen) { + n = m_pulldown(m, off, sizeof(struct sadb_ext), &toff); + if (!n) { + /* m is already freed */ + return ENOBUFS; + } + ext = (struct sadb_ext *)(mtod(n, caddr_t) + toff); - while (tlen > 0) { /* set pointer */ switch (ext->sadb_ext_type) { case SADB_EXT_SA: - case SADB_EXT_LIFETIME_CURRENT: - case SADB_EXT_LIFETIME_HARD: - case SADB_EXT_LIFETIME_SOFT: case SADB_EXT_ADDRESS_SRC: case SADB_EXT_ADDRESS_DST: case SADB_EXT_ADDRESS_PROXY: + case SADB_EXT_LIFETIME_CURRENT: + case SADB_EXT_LIFETIME_HARD: + case SADB_EXT_LIFETIME_SOFT: case SADB_EXT_KEY_AUTH: case SADB_EXT_KEY_ENCRYPT: case SADB_EXT_IDENTITY_SRC: @@ -6561,34 +7326,116 @@ key_align(msg, mhp) case SADB_EXT_SUPPORTED_ENCRYPT: case SADB_EXT_SPIRANGE: case SADB_X_EXT_POLICY: + case SADB_X_EXT_SA2: /* duplicate check */ /* * XXX Are there duplication payloads of either * KEY_AUTH or KEY_ENCRYPT ? */ - if (mhp[ext->sadb_ext_type] != NULL) { + if (mhp->ext[ext->sadb_ext_type] != NULL) { #if IPSEC_DEBUG printf("key_align: duplicate ext_type %u " "is passed.\n", ext->sadb_ext_type); #endif + m_freem(m); pfkeystat.out_dupext++; return EINVAL; } - mhp[ext->sadb_ext_type] = (caddr_t)ext; break; default: #if IPSEC_DEBUG printf("key_align: invalid ext_type %u is passed.\n", ext->sadb_ext_type); #endif + m_freem(m); pfkeystat.out_invexttype++; return EINVAL; } extlen = PFKEY_UNUNIT64(ext->sadb_ext_len); - tlen -= extlen; - ext = (struct sadb_ext *)((caddr_t)ext + extlen); + + if (key_validate_ext(ext, extlen)) { + m_freem(m); + pfkeystat.out_invlen++; + return EINVAL; + } + + n = m_pulldown(m, off, extlen, &toff); + if (!n) { + /* m is already freed */ + return ENOBUFS; + } + ext = (struct sadb_ext *)(mtod(n, caddr_t) + toff); + + mhp->ext[ext->sadb_ext_type] = ext; + mhp->extoff[ext->sadb_ext_type] = off; + mhp->extlen[ext->sadb_ext_type] = extlen; + } + + if (off != end) { + m_freem(m); + pfkeystat.out_invlen++; + return EINVAL; + } + + return 0; +} + +static int +key_validate_ext(ext, len) + const struct sadb_ext *ext; + int len; +{ + struct sockaddr *sa; + enum { NONE, ADDR } checktype = NONE; + int baselen; + const int sal = offsetof(struct sockaddr, sa_len) + sizeof(sa->sa_len); + + if (len != PFKEY_UNUNIT64(ext->sadb_ext_len)) + return EINVAL; + + /* if it does not match minimum/maximum length, bail */ + if (ext->sadb_ext_type >= sizeof(minsize) / sizeof(minsize[0]) || + ext->sadb_ext_type >= sizeof(maxsize) / sizeof(maxsize[0])) + return EINVAL; + if (!minsize[ext->sadb_ext_type] || len < minsize[ext->sadb_ext_type]) + return EINVAL; + if (maxsize[ext->sadb_ext_type] && len > maxsize[ext->sadb_ext_type]) + return EINVAL; + + /* more checks based on sadb_ext_type XXX need more */ + switch (ext->sadb_ext_type) { + case SADB_EXT_ADDRESS_SRC: + case SADB_EXT_ADDRESS_DST: + case SADB_EXT_ADDRESS_PROXY: + baselen = PFKEY_ALIGN8(sizeof(struct sadb_address)); + checktype = ADDR; + break; + case SADB_EXT_IDENTITY_SRC: + case SADB_EXT_IDENTITY_DST: + if (((struct sadb_ident *)ext)->sadb_ident_type == + SADB_X_IDENTTYPE_ADDR) { + baselen = PFKEY_ALIGN8(sizeof(struct sadb_ident)); + checktype = ADDR; + } else + checktype = NONE; + break; + default: + checktype = NONE; + break; + } + + switch (checktype) { + case NONE: + break; + case ADDR: + sa = (struct sockaddr *)((caddr_t)ext + baselen); + if (len < baselen + sal) + return EINVAL; + if (baselen + PFKEY_ALIGN8(sa->sa_len) != len) + return EINVAL; + break; } return 0; @@ -6617,21 +7464,25 @@ key_init() LIST_INIT(&spacqtree); /* system default */ +#if INET ip4_def_policy.policy = IPSEC_POLICY_NONE; ip4_def_policy.refcnt++; /*never reclaim this*/ +#endif #if INET6 ip6_def_policy.policy = IPSEC_POLICY_NONE; ip6_def_policy.refcnt++; /*never reclaim this*/ #endif #ifndef IPSEC_DEBUG2 - timeout((void *)key_timehandler_funneled, (void *)0, hz); + timeout((void *)key_timehandler_funnel, (void *)0, hz); #endif /*IPSEC_DEBUG2*/ /* initialize key statistics */ keystat.getspi_count = 1; +#ifndef __APPLE__ printf("IPsec: Initialized Security Association Processing.\n"); +#endif return; } @@ -6661,9 +7512,7 @@ key_checktunnelsanity(sav, family, src, dst) } #if 0 -#ifdef __FreeBSD__ #define hostnamelen strlen(hostname) -#endif /* * Get FQDN for the host. @@ -6787,7 +7636,7 @@ key_sa_routechange(dst) ro = &sah->sa_route; if (ro->ro_rt && dst->sa_len == ro->ro_dst.sa_len && bcmp(dst, &ro->ro_dst, dst->sa_len) == 0) { - RTFREE(ro->ro_rt); + rtfree(ro->ro_rt); ro->ro_rt = (struct rtentry *)NULL; } } @@ -6813,96 +7662,51 @@ key_sa_chgstate(sav, state) LIST_INSERT_HEAD(&sav->sah->savtree[state], sav, chain); } -/* returns NULL on error, m0 will be left unchanged */ -static caddr_t -key_appendmbuf(m0, len) - struct mbuf *m0; - int len; +void +key_sa_stir_iv(sav) + struct secasvar *sav; { - caddr_t p; - struct mbuf *m; - struct mbuf *n; - - if (!m0 || (m0->m_flags & M_PKTHDR) == 0) - return NULL; /*EINVAL*/ - if (len > MCLBYTES) - return NULL; /*EINVAL*/ - for (m = m0; m && m->m_next; m = m->m_next) - ; - if (len <= M_TRAILINGSPACE(m)) { - p = mtod(m, caddr_t) + m->m_len; - m->m_len += len; - m0->m_pkthdr.len += len; - - return p; - } - MGET(n, M_DONTWAIT, m->m_type); - if (n != NULL) { - MCLGET(n, M_DONTWAIT); - if ((n->m_flags & M_EXT) == 0) { - m_freem(n); - n = NULL; - } - } - if (n == NULL) - return NULL; /*ENOBUFS*/ - n->m_next = NULL; - m->m_next = n; - n->m_len = len; - m0->m_pkthdr.len += len; - - return mtod(n, caddr_t); + if (!sav->iv) + panic("key_sa_stir_iv called with sav == NULL"); + key_randomfill(sav->iv, sav->ivlen); } -#ifdef __bsdi__ -#include -#include - -int *key_sysvars[] = KEYCTL_VARS; - -int -key_sysctl(name, namelen, oldp, oldlenp, newp, newlen) - int *name; - u_int namelen; - void *oldp; - size_t *oldlenp; - void *newp; - size_t newlen; +/* XXX too much? */ +static struct mbuf * +key_alloc_mbuf(l) + int l; { - if (name[0] >= KEYCTL_MAXID) - return EOPNOTSUPP; - switch (name[0]) { - default: - return sysctl_int_arr(key_sysvars, name, namelen, - oldp, oldlenp, newp, newlen); - } -} -#endif /*__bsdi__*/ + struct mbuf *m = NULL, *n; + int len, t; + + len = l; + while (len > 0) { + MGET(n, M_DONTWAIT, MT_DATA); + if (n && len > MLEN) + MCLGET(n, M_DONTWAIT); + if (!n) { + m_freem(m); + return NULL; + } -#ifdef __NetBSD__ -#include -#include + n->m_next = NULL; + n->m_len = 0; + n->m_len = M_TRAILINGSPACE(n); + /* use the bottom of mbuf, hoping we can prepend afterwards */ + if (n->m_len > len) { + t = (n->m_len - len) & ~(sizeof(long) - 1); + n->m_data += t; + n->m_len = len; + } -static int *key_sysvars[] = KEYCTL_VARS; + len -= n->m_len; -int -key_sysctl(name, namelen, oldp, oldlenp, newp, newlen) - int *name; - u_int namelen; - void *oldp; - size_t *oldlenp; - void *newp; - size_t newlen; -{ - if (name[0] >= KEYCTL_MAXID) - return EOPNOTSUPP; - if (!key_sysvars[name[0]]) - return EOPNOTSUPP; - switch (name[0]) { - default: - return sysctl_int(oldp, oldlenp, newp, newlen, - key_sysvars[name[0]]); + if (m) + m_cat(m, n); + else + m = n; } + + return m; } -#endif /*__NetBSD__*/ diff --git a/bsd/netkey/key.h b/bsd/netkey/key.h index a8e387c70..99cf8bee4 100644 --- a/bsd/netkey/key.h +++ b/bsd/netkey/key.h @@ -31,8 +31,10 @@ #ifndef _NETKEY_KEY_H_ #define _NETKEY_KEY_H_ +#include #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE extern struct key_cb key_cb; @@ -45,38 +47,34 @@ struct socket; struct sadb_msg; struct sadb_x_policy; -extern struct secpolicy *key_allocsp __P((struct secpolicyindex *spidx, - u_int dir)); +extern struct secpolicy *key_allocsp __P((struct secpolicyindex *, u_int)); +extern struct secpolicy *key_gettunnel __P((struct sockaddr *, + struct sockaddr *, struct sockaddr *, struct sockaddr *)); extern int key_checkrequest - __P((struct ipsecrequest *isr, struct secasindex *saidx)); -extern struct secasvar *key_allocsa __P((u_int family, caddr_t src, caddr_t dst, - u_int proto, u_int32_t spi)); -extern void key_freesp __P((struct secpolicy *sp)); -extern void key_freeso __P((struct socket *so)); -extern void key_freesav __P((struct secasvar *sav)); + __P((struct ipsecrequest *isr, struct secasindex *)); +extern struct secasvar *key_allocsa __P((u_int, caddr_t, caddr_t, + u_int, u_int32_t)); +extern void key_freesp __P((struct secpolicy *)); +extern void key_freeso __P((struct socket *)); +extern void key_freesav __P((struct secasvar *)); extern struct secpolicy *key_newsp __P((void)); -extern struct secpolicy *key_msg2sp __P((struct sadb_x_policy *xpl0, - size_t len, int *error)); -extern struct mbuf *key_sp2msg __P((struct secpolicy *sp)); -extern int key_ismyaddr __P((u_int family, caddr_t addr)); +extern struct secpolicy *key_msg2sp __P((struct sadb_x_policy *, + size_t, int *)); +extern struct mbuf *key_sp2msg __P((struct secpolicy *)); +extern int key_ismyaddr __P((struct sockaddr *)); +extern int key_spdacquire __P((struct secpolicy *)); extern void key_timehandler __P((void)); -extern void key_srandom __P((void)); -extern void key_freereg __P((struct socket *so)); -extern int key_parse __P((struct sadb_msg **msgp, struct socket *so, - int *targetp)); +extern u_long key_random __P((void)); +extern void key_randomfill __P((void *, size_t)); +extern void key_freereg __P((struct socket *)); +extern int key_parse __P((struct mbuf *, struct socket *)); extern void key_init __P((void)); -extern int key_checktunnelsanity __P((struct secasvar *sav, u_int family, - caddr_t src, caddr_t dst)); -extern void key_sa_recordxfer __P((struct secasvar *sav, struct mbuf *m)); -extern void key_sa_routechange __P((struct sockaddr *dst)); +extern int key_checktunnelsanity __P((struct secasvar *, u_int, + caddr_t, caddr_t)); +extern void key_sa_recordxfer __P((struct secasvar *, struct mbuf *)); +extern void key_sa_routechange __P((struct sockaddr *)); +extern void key_sa_stir_iv __P((struct secasvar *)); -#if MALLOC_DECLARE -MALLOC_DECLARE(M_SECA); -#endif /* MALLOC_DECLARE */ - -#if defined(__bsdi__) || defined(__NetBSD__) -extern int key_sysctl __P((int *, u_int, void *, size_t *, void *, size_t)); -#endif - -#endif /* defined(KERNEL) */ +#endif /* __APPLE_API_PRIVATE */ +#endif /* defined(_KERNEL) */ #endif /* _NETKEY_KEY_H_ */ diff --git a/bsd/netkey/key_debug.c b/bsd/netkey/key_debug.c index ee55d4789..2366598b3 100644 --- a/bsd/netkey/key_debug.c +++ b/bsd/netkey/key_debug.c @@ -1,7 +1,7 @@ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -13,7 +13,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -27,23 +27,12 @@ * SUCH DAMAGE. */ -/* KAME @(#)$Id: key_debug.c,v 1.2 2000/09/14 20:35:26 lindak Exp $ */ - -#ifdef KERNEL -# define _KERNEL -#endif - -#ifdef KERNEL -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#endif -#endif - #include #include -#if defined(KERNEL) +#ifdef KERNEL #include #include +#include #endif #include @@ -55,13 +44,13 @@ #include #include -#if !defined(KERNEL) +#ifndef KERNEL #include #include #include -#endif /* defined(KERNEL) */ +#endif /* !KERNEL */ -#if !defined(_KERNEL) || (defined(_KERNEL) && defined(IPSEC_DEBUG)) +#if !defined(KERNEL) || (defined(KERNEL) && defined(IPSEC_DEBUG)) static void kdebug_sadb_prop __P((struct sadb_ext *)); static void kdebug_sadb_identity __P((struct sadb_ext *)); @@ -70,6 +59,7 @@ static void kdebug_sadb_lifetime __P((struct sadb_ext *)); static void kdebug_sadb_sa __P((struct sadb_ext *)); static void kdebug_sadb_address __P((struct sadb_ext *)); static void kdebug_sadb_key __P((struct sadb_ext *)); +static void kdebug_sadb_x_sa2 __P((struct sadb_ext *)); #ifdef KERNEL static void kdebug_secreplay __P((struct secreplay *)); @@ -96,11 +86,9 @@ kdebug_sadb(base) printf("sadb_msg{ version=%u type=%u errno=%u satype=%u\n", base->sadb_msg_version, base->sadb_msg_type, base->sadb_msg_errno, base->sadb_msg_satype); - printf(" len=%u mode=%u seq=%u pid=%u reqid=%u\n", - base->sadb_msg_len, base->sadb_msg_mode, - base->sadb_msg_seq, base->sadb_msg_pid, base->sadb_msg_reqid); - printf(" reserved1=%u reserved2=%u\n", - base->sadb_msg_reserved1, base->sadb_msg_reserved2); + printf(" len=%u reserved=%u seq=%u pid=%u\n", + base->sadb_msg_len, base->sadb_msg_reserved, + base->sadb_msg_seq, base->sadb_msg_pid); tlen = PFKEY_UNUNIT64(base->sadb_msg_len) - sizeof(struct sadb_msg); ext = (struct sadb_ext *)((caddr_t)base + sizeof(struct sadb_msg)); @@ -155,6 +143,9 @@ kdebug_sadb(base) case SADB_X_EXT_POLICY: kdebug_sadb_x_policy(ext); break; + case SADB_X_EXT_SA2: + kdebug_sadb_x_sa2(ext); + break; default: printf("kdebug_sadb: invalid ext_type %u was passed.\n", ext->sadb_ext_type); @@ -225,7 +216,6 @@ kdebug_sadb_identity(ext) { struct sadb_ident *id = (struct sadb_ident *)ext; int len; - union sadb_x_ident_id *aid; /* sanity check */ if (ext == NULL) @@ -235,16 +225,6 @@ kdebug_sadb_identity(ext) printf("sadb_ident_%s{", id->sadb_ident_exttype == SADB_EXT_IDENTITY_SRC ? "src" : "dst"); switch (id->sadb_ident_type) { - case SADB_X_IDENTTYPE_ADDR: - aid = (union sadb_x_ident_id *)&id->sadb_ident_id; - - printf(" type=%d prefix=%u ul_proto=%u\n", - id->sadb_ident_type, - aid->sadb_x_ident_id_addr.prefix, - aid->sadb_x_ident_id_addr.ul_proto); - kdebug_sockaddr((struct sockaddr *)(id + 1)); - break; - default: printf(" type=%d id=%lu", id->sadb_ident_type, (u_long)id->sadb_ident_id); @@ -387,6 +367,25 @@ kdebug_sadb_key(ext) return; } +static void +kdebug_sadb_x_sa2(ext) + struct sadb_ext *ext; +{ + struct sadb_x_sa2 *sa2 = (struct sadb_x_sa2 *)ext; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_x_sa2: NULL pointer was passed.\n"); + + printf("sadb_x_sa2{ mode=%u reqid=%u\n", + sa2->sadb_x_sa2_mode, sa2->sadb_x_sa2_reqid); + printf(" reserved1=%u reserved2=%u reserved3=%u }\n", + sa2->sadb_x_sa2_reserved1, sa2->sadb_x_sa2_reserved1, + sa2->sadb_x_sa2_reserved1); + + return; +} + void kdebug_sadb_x_policy(ext) struct sadb_ext *ext; @@ -398,9 +397,9 @@ kdebug_sadb_x_policy(ext) if (ext == NULL) panic("kdebug_sadb_x_policy: NULL pointer was passed.\n"); - printf("sadb_x_policy{ type=%u dir=%u reserved=%x }\n", + printf("sadb_x_policy{ type=%u dir=%u id=%x }\n", xpl->sadb_x_policy_type, xpl->sadb_x_policy_dir, - xpl->sadb_x_policy_reserved); + xpl->sadb_x_policy_id); if (xpl->sadb_x_policy_type == IPSEC_POLICY_IPSEC) { int tlen; @@ -604,7 +603,7 @@ kdebug_secreplay(rpl) return; } - printf("\n bitmap { "); + printf("\n bitmap { "); for (len = 0; len < rpl->wsize; len++) { for (l = 7; l >= 0; l--) @@ -621,7 +620,7 @@ kdebug_mbufhdr(m) { /* sanity check */ if (m == NULL) - panic("debug_mbufhdr: NULL pointer was passed.\n"); + return; printf("mbuf(%p){ m_next:%p m_nextpkt:%p m_data:%p " "m_len:%d m_type:0x%02x m_flags:0x%02x }\n", @@ -633,14 +632,12 @@ kdebug_mbufhdr(m) m->m_pkthdr.len, m->m_pkthdr.rcvif); } -#ifdef __FreeBSD__ if (m->m_flags & M_EXT) { printf(" m_ext{ ext_buf:%p ext_free:%p " "ext_size:%u ext_ref:%p }\n", m->m_ext.ext_buf, m->m_ext.ext_free, - m->m_ext.ext_size, m->m_ext.ext_ref); + m->m_ext.ext_size, m->m_ext.ext_refs); } -#endif return; } @@ -652,19 +649,20 @@ kdebug_mbuf(m0) struct mbuf *m = m0; int i, j; - kdebug_mbufhdr(m); - printf(" m_data=\n"); for (j = 0; m; m = m->m_next) { + kdebug_mbufhdr(m); + printf(" m_data:\n"); for (i = 0; i < m->m_len; i++) { - if (i != 0 && i % 32 == 0) printf("\n"); - if (i % 4 == 0) printf(" "); + if (i && i % 32 == 0) + printf("\n"); + if (i % 4 == 0) + printf(" "); printf("%02x", mtod(m, u_char *)[i]); j++; } + printf("\n"); } - printf("\n"); - return; } #endif /* KERNEL */ @@ -673,31 +671,41 @@ void kdebug_sockaddr(addr) struct sockaddr *addr; { + struct sockaddr_in *sin; +#ifdef INET6 + struct sockaddr_in6 *sin6; +#endif + /* sanity check */ if (addr == NULL) panic("kdebug_sockaddr: NULL pointer was passed.\n"); /* NOTE: We deal with port number as host byte order. */ - printf("sockaddr{ len=%u family=%u port=%u\n", - addr->sa_len, addr->sa_family, ntohs(_INPORTBYSA(addr))); + printf("sockaddr{ len=%u family=%u", addr->sa_len, addr->sa_family); + switch (addr->sa_family) { + case AF_INET: + sin = (struct sockaddr_in *)addr; + printf(" port=%u\n", ntohs(sin->sin_port)); + ipsec_hexdump((caddr_t)&sin->sin_addr, sizeof(sin->sin_addr)); + break; #ifdef INET6 - if (addr->sa_family == PF_INET6) { - struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)addr; + case AF_INET6: + sin6 = (struct sockaddr_in6 *)addr; + printf(" port=%u\n", ntohs(sin6->sin6_port)); printf(" flowinfo=0x%08x, scope_id=0x%08x\n", - in6->sin6_flowinfo, in6->sin6_scope_id); - } + sin6->sin6_flowinfo, sin6->sin6_scope_id); + ipsec_hexdump((caddr_t)&sin6->sin6_addr, + sizeof(sin6->sin6_addr)); + break; #endif - - ipsec_hexdump(_INADDRBYSA(addr), _INALENBYAF(addr->sa_family)); + } printf(" }\n"); return; } -#endif /* !defined(KERNEL) || (defined(KERNEL) && defined(IPSEC_DEBUG)) */ - void ipsec_bindump(buf, len) caddr_t buf; @@ -731,3 +739,4 @@ ipsec_hexdump(buf, len) return; } +#endif /* !defined(KERNEL) || (defined(KERNEL) && defined(IPSEC_DEBUG)) */ diff --git a/bsd/netkey/key_debug.h b/bsd/netkey/key_debug.h index 750a570d0..5b731f9bf 100644 --- a/bsd/netkey/key_debug.h +++ b/bsd/netkey/key_debug.h @@ -1,4 +1,4 @@ -/* $KAME: key_debug.h,v 1.5 2000/03/25 07:24:12 sumikawa Exp $ */ +/* $KAME: key_debug.h,v 1.7 2000/07/04 04:08:16 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -31,6 +31,7 @@ #ifndef _NETKEY_KEY_DEBUG_H_ #define _NETKEY_KEY_DEBUG_H_ +#include #if !defined(KERNEL) || (defined(KERNEL) && defined(IPSEC_DEBUG)) @@ -55,16 +56,15 @@ #define KEYDEBUG(lev,arg) if ((key_debug_level & (lev)) == (lev)) { arg; } -#ifdef KERNEL -extern u_int32_t key_debug_level; -#endif /*KERNEL*/ - struct sadb_msg; struct sadb_ext; extern void kdebug_sadb __P((struct sadb_msg *)); extern void kdebug_sadb_x_policy __P((struct sadb_ext *)); #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE +extern u_int32_t key_debug_level; + struct secpolicy; struct secpolicyindex; struct secasindex; @@ -77,19 +77,20 @@ extern void kdebug_secasindex __P((struct secasindex *)); extern void kdebug_secasv __P((struct secasvar *)); extern void kdebug_mbufhdr __P((struct mbuf *)); extern void kdebug_mbuf __P((struct mbuf *)); +#endif /* __APPLE_API_PRIVATE */ #endif /*KERNEL*/ struct sockaddr; extern void kdebug_sockaddr __P((struct sockaddr *)); +extern void ipsec_hexdump __P((caddr_t, int)); +extern void ipsec_bindump __P((caddr_t, int)); + #else #define KEYDEBUG(lev,arg) #endif /*!defined(KERNEL) || (defined(KERNEL) && defined(IPSEC_DEBUG))*/ -extern void ipsec_hexdump __P((caddr_t, int)); -extern void ipsec_bindump __P((caddr_t, int)); - #endif /* _NETKEY_KEY_DEBUG_H_ */ diff --git a/bsd/netkey/key_var.h b/bsd/netkey/key_var.h index ac785a140..6efb8dfe7 100644 --- a/bsd/netkey/key_var.h +++ b/bsd/netkey/key_var.h @@ -31,12 +31,8 @@ #ifndef _NETKEY_KEY_VAR_H_ #define _NETKEY_KEY_VAR_H_ - -#ifdef __NetBSD__ -#if defined(_KERNEL) && !defined(_LKM) -#include "opt_inet.h" -#endif -#endif +#include +#ifdef __APPLE_API_PRIVATE /* sysctl */ #define KEYCTL_DEBUG_LEVEL 1 @@ -47,7 +43,10 @@ #define KEYCTL_LARVAL_LIFETIME 6 #define KEYCTL_BLOCKACQ_COUNT 7 #define KEYCTL_BLOCKACQ_LIFETIME 8 -#define KEYCTL_MAXID 9 +#define KEYCTL_ESP_KEYMIN 9 +#define KEYCTL_ESP_AUTH 10 +#define KEYCTL_AH_KEYMIN 11 +#define KEYCTL_MAXID 12 #define KEYCTL_NAMES { \ { 0, 0 }, \ @@ -72,6 +71,8 @@ &key_larval_lifetime, \ &key_blockacq_count, \ &key_blockacq_lifetime, \ + &ipsec_esp_keymin, \ + &ipsec_ah_keymin, \ } //#else //#define KEYCTL_VARS { \ @@ -84,50 +85,17 @@ // &key_larval_lifetime, \ // &key_blockacq_count, \ // &key_blockacq_lifetime, \ +// &ipsec_esp_keymin, \ +// &ipsec_ah_keymin, \ //} //#endif +#ifdef KERNEL #define _ARRAYLEN(p) (sizeof(p)/sizeof(p[0])) #define _KEYLEN(key) ((u_int)((key)->sadb_key_bits >> 3)) #define _KEYBITS(key) ((u_int)((key)->sadb_key_bits)) #define _KEYBUF(key) ((caddr_t)((caddr_t)(key) + sizeof(struct sadb_key))) +#endif /*KERNEL*/ -#define _INADDR(in) ((struct sockaddr_in *)(in)) - -#if defined(INET6) -#define _IN6ADDR(in6) ((struct sockaddr_in6 *)(in6)) -#define _SALENBYAF(family) \ - (((family) == AF_INET) ? \ - (u_int)sizeof(struct sockaddr_in) : \ - (u_int)sizeof(struct sockaddr_in6)) -#define _INALENBYAF(family) \ - (((family) == AF_INET) ? \ - (u_int)sizeof(struct in_addr) : \ - (u_int)sizeof(struct in6_addr)) -#define _INADDRBYSA(saddr) \ - ((((struct sockaddr *)(saddr))->sa_family == AF_INET) ? \ - (caddr_t)&((struct sockaddr_in *)(saddr))->sin_addr : \ - (caddr_t)&((struct sockaddr_in6 *)(saddr))->sin6_addr) -#define _INPORTBYSA(saddr) \ - ((((struct sockaddr *)(saddr))->sa_family == AF_INET) ? \ - ((struct sockaddr_in *)(saddr))->sin_port : \ - ((struct sockaddr_in6 *)(saddr))->sin6_port) -#if 0 -#define _SADDRBYSA(saddr) \ - ((((struct sockaddr *)(saddr))->sa_family == AF_INET) ? \ - (caddr_t)&((struct sockaddr_in *)(saddr))->sin_addr.s_addr : \ - (caddr_t)&((struct sockaddr_in6 *)(saddr))->sin6_addr.s6_addr) -#endif -#else -#define _IN6ADDR(in6) "#error" -#define _SALENBYAF(family) sizeof(struct sockaddr_in) -#define _INALENBYAF(family) sizeof(struct in_addr) -#define _INADDRBYSA(saddr) ((caddr_t)&((struct sockaddr_in *)(saddr))->sin_addr) -#define _INPORTBYSA(saddr) (((struct sockaddr_in *)(saddr))->sin_port) -#if 0 -#define _SADDRBYSA(saddr) \ - ((caddr_t)&((struct sockaddr_in *)(saddr))->sin_addr.s_addr) -#endif -#endif /* defined(INET6) */ - +#endif /* __APPLE_API_PRIVATE */ #endif /* _NETKEY_KEY_VAR_H_ */ diff --git a/bsd/netkey/keydb.c b/bsd/netkey/keydb.c index d9bf27f60..a96589042 100644 --- a/bsd/netkey/keydb.c +++ b/bsd/netkey/keydb.c @@ -29,13 +29,6 @@ * SUCH DAMAGE. */ -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#ifdef __NetBSD__ -#include "opt_ipsec.h" -#endif -#endif - #include #include #include @@ -56,9 +49,7 @@ #include -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 MALLOC_DEFINE(M_SECA, "key mgmt", "security associations, key management"); -#endif static void keydb_delsecasvar __P((struct secasvar *)); @@ -133,11 +124,7 @@ keydb_refsecasvar(p) { int s; -#ifdef __NetBSD__ - s = splsoftnet(); -#else s = splnet(); -#endif p->refcnt++; splx(s); } @@ -148,13 +135,10 @@ keydb_freesecasvar(p) { int s; -#ifdef __NetBSD__ - s = splsoftnet(); -#else s = splnet(); -#endif p->refcnt--; - if (p->refcnt == 0) + /* negative refcnt will cause panic intentionally */ + if (p->refcnt <= 0) keydb_delsecasvar(p); splx(s); } diff --git a/bsd/netkey/keydb.h b/bsd/netkey/keydb.h index 4e2160a75..1d9ef21cb 100644 --- a/bsd/netkey/keydb.h +++ b/bsd/netkey/keydb.h @@ -31,8 +31,10 @@ #ifndef _NETKEY_KEYDB_H_ #define _NETKEY_KEYDB_H_ +#include #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE #include @@ -78,19 +80,14 @@ struct secasvar { u_int32_t flags; /* holder for SADB_KEY_FLAGS */ struct sadb_key *key_auth; /* Key for Authentication */ - /* length has been shifted up to 3. */ struct sadb_key *key_enc; /* Key for Encryption */ - /* length has been shifted up to 3. */ caddr_t iv; /* Initilization Vector */ u_int ivlen; /* length of IV */ -#if 0 - caddr_t misc1; - caddr_t misc2; - caddr_t misc3; -#endif + void *sched; /* intermediate encryption key */ + size_t schedlen; struct secreplay *replay; /* replay prevention */ - u_int32_t tick; /* for lifetime */ + long created; /* for lifetime */ struct sadb_lifetime *lft_c; /* CURRENT lifetime, it's constant. */ struct sadb_lifetime *lft_h; /* HARD lifetime */ @@ -127,7 +124,7 @@ struct secacq { struct secasindex saidx; u_int32_t seq; /* sequence number */ - u_int32_t tick; /* for lifetime */ + long created; /* for lifetime */ int count; /* for lifetime */ }; #endif @@ -159,6 +156,7 @@ extern void keydb_delsecreplay __P((struct secreplay *)); extern struct secreg *keydb_newsecreg __P((void)); extern void keydb_delsecreg __P((struct secreg *)); +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ #endif /* _NETKEY_KEYDB_H_ */ diff --git a/bsd/netkey/keysock.c b/bsd/netkey/keysock.c index ae1bc6203..364473ea0 100644 --- a/bsd/netkey/keysock.c +++ b/bsd/netkey/keysock.c @@ -29,46 +29,21 @@ * SUCH DAMAGE. */ -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -#include "opt_inet.h" -#endif - /* This code has derived from sys/net/rtsock.c on FreeBSD2.2.5 */ -#if defined(__NetBSD__) || defined (__APPLE__) -# ifdef _KERNEL -# define KERNEL -# endif -#endif - #include #include #include #include -#if defined(__FreeBSD__) || defined (__APPLE__) #include -#endif #include -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) #include -#endif #include #include #include #include #include -#ifdef __NetBSD__ -#include -#include -#endif -#ifdef __FreeBSD__ -#if __FreeBSD__ >= 3 -#include -#else -#include -#endif -#endif #include #include @@ -79,141 +54,41 @@ #include #include - struct sockaddr key_dst = { 2, PF_KEY, }; struct sockaddr key_src = { 2, PF_KEY, }; -struct sockproto key_proto = { PF_KEY, PF_KEY_V2 }; static int key_sendup0 __P((struct rawcb *, struct mbuf *, int)); struct pfkeystat pfkeystat; -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__APPLE__) /* - * key_usrreq() - * derived from net/rtsock.c:route_usrreq() + * key_output() */ -#ifndef __NetBSD__ int -key_usrreq(so, req, m, nam, control) - register struct socket *so; - int req; - struct mbuf *m, *nam, *control; +#ifdef __APPLE__ +/* No variable argument support? */ +key_output(struct mbuf *m, struct socket *so) #else -int -key_usrreq(so, req, m, nam, control, p) - register struct socket *so; - int req; - struct mbuf *m, *nam, *control; - struct proc *p; -#endif /*__NetBSD__*/ -{ - register int error = 0; - register struct keycb *kp = (struct keycb *)sotorawcb(so); - int s; - -#ifdef __NetBSD__ - s = splsoftnet(); +#if __STDC__ +key_output(struct mbuf *m, ...) #else - s = splnet(); -#endif - if (req == PRU_ATTACH) { - kp = (struct keycb *)_MALLOC(sizeof(*kp), M_PCB, M_WAITOK); - so->so_pcb = (caddr_t)kp; - if (so->so_pcb) - bzero(so->so_pcb, sizeof(*kp)); - } - if (req == PRU_DETACH && kp) { - int af = kp->kp_raw.rcb_proto.sp_protocol; - if (af == PF_KEY) /* XXX: AF_KEY */ - key_cb.key_count--; - key_cb.any_count--; - - key_freereg(so); - } - -#ifndef __NetBSD__ - error = raw_usrreq(so, req, m, nam, control); -#else - error = raw_usrreq(so, req, m, nam, control, p); -#endif - m = control = NULL; /* reclaimed in raw_usrreq */ - kp = (struct keycb *)sotorawcb(so); - if (req == PRU_ATTACH && kp) { - int af = kp->kp_raw.rcb_proto.sp_protocol; - if (error) { -#if IPSEC_DEBUG - printf("key_usrreq: key_usrreq results %d\n", error); +key_output(m, va_alist) + struct mbuf *m; + va_dcl #endif - pfkeystat.sockerr++; - _FREE((caddr_t)kp, M_PCB); - so->so_pcb = (caddr_t) 0; - splx(s); - return(error); - } - - kp->kp_promisc = kp->kp_registered = 0; - - if (af == PF_KEY) /* XXX: AF_KEY */ - key_cb.key_count++; - key_cb.any_count++; -#ifndef __bsdi__ - kp->kp_raw.rcb_laddr = &key_src; - kp->kp_raw.rcb_faddr = &key_dst; -#else - /* - * XXX rcb_faddr must be dynamically allocated, otherwise - * raw_disconnect() will be angry. - */ - { - struct mbuf *m, *n; - MGET(m, M_WAITOK, MT_DATA); - if (!m) { - error = ENOBUFS; - pfkeystat.in_nomem++; - _FREE((caddr_t)kp, M_PCB); - so->so_pcb = (caddr_t) 0; - splx(s); - return(error); - } - MGET(n, M_WAITOK, MT_DATA); - if (!n) { - error = ENOBUFS; - m_freem(m); - pfkeystat.in_nomem++; - _FREE((caddr_t)kp, M_PCB); - so->so_pcb = (caddr_t) 0; - splx(s); - return(error); - } - m->m_len = sizeof(key_src); - kp->kp_raw.rcb_laddr = mtod(m, struct sockaddr *); - bcopy(&key_src, kp->kp_raw.rcb_laddr, sizeof(key_src)); - n->m_len = sizeof(key_dst); - kp->kp_raw.rcb_faddr = mtod(n, struct sockaddr *); - bcopy(&key_dst, kp->kp_raw.rcb_faddr, sizeof(key_dst)); - } #endif - soisconnected(so); - so->so_options |= SO_USELOOPBACK; - } - splx(s); - return(error); -} -#endif /* other than FreeBSD >= 3 */ - -/* - * key_output() - */ -int -key_output(m, so) - register struct mbuf *m; - struct socket *so; { - struct sadb_msg *msg = NULL; + struct sadb_msg *msg; int len, error = 0; int s; - int target; +#ifndef __APPLE__ + struct socket *so; + va_list ap; + + va_start(ap, m); + so = va_arg(ap, struct socket *); + va_end(ap); +#endif if (m == 0) panic("key_output: NULL pointer was passed.\n"); @@ -245,7 +120,7 @@ key_output(m, so) if ((m->m_flags & M_PKTHDR) == 0) panic("key_output: not M_PKTHDR ??"); -#if defined(IPSEC_DEBUG) +#if IPSEC_DEBUG KEYDEBUG(KEYDEBUG_KEY_DUMP, kdebug_mbuf(m)); #endif /* defined(IPSEC_DEBUG) */ @@ -260,43 +135,15 @@ key_output(m, so) goto end; } - /* - * allocate memory for sadb_msg, and copy to sadb_msg from mbuf - * XXX: To be processed directly without a copy. - */ - msg = (struct sadb_msg *)_MALLOC(len, M_SECA, M_WAITOK); - if (msg == NULL) { -#if IPSEC_DEBUG - printf("key_output: No more memory.\n"); -#endif - error = ENOBUFS; - pfkeystat.out_nomem++; - goto end; - /* or do panic ? */ - } - m_copydata(m, 0, len, (caddr_t)msg); - /*XXX giant lock*/ -#ifdef __NetBSD__ - s = splsoftnet(); -#else s = splnet(); -#endif - if ((len = key_parse(&msg, so, &target)) == 0) { - /* discard. i.e. no need to reply. */ - /* msg has been freed at key_parse() */ - error = 0; - splx(s); - goto end; - } - - /* send up message to the socket */ - error = key_sendup(so, msg, len, target); + error = key_parse(m, so); + m = NULL; splx(s); - _FREE(msg, M_SECA); end: - m_freem(m); - return (error); + if (m) + m_freem(m); + return error; } /* @@ -308,6 +155,8 @@ key_sendup0(rp, m, promisc) struct mbuf *m; int promisc; { + int error; + if (promisc) { struct sadb_msg *pmsg; @@ -318,7 +167,7 @@ key_sendup0(rp, m, promisc) #if IPSEC_DEBUG printf("key_sendup0: cannot pullup\n"); #endif - pfkeystat.in_nomem++; + pfkeystat.in_nomem++; m_freem(m); return ENOBUFS; } @@ -334,17 +183,18 @@ key_sendup0(rp, m, promisc) pfkeystat.in_msgtype[pmsg->sadb_msg_type]++; } - if (!sbappendaddr(&rp->rcb_socket->so_rcv, - (struct sockaddr *)&key_src, m, NULL)) { + if (!sbappendaddr(&rp->rcb_socket->so_rcv, (struct sockaddr *)&key_src, + m, NULL)) { #if IPSEC_DEBUG printf("key_sendup0: sbappendaddr failed\n"); #endif pfkeystat.in_nomem++; m_freem(m); - return ENOBUFS; - } + error = ENOBUFS; + } else + error = 0; sorwakeup(rp->rcb_socket); - return 0; + return error; } /* XXX this interface should be obsoleted. */ @@ -377,7 +227,7 @@ key_sendup(so, msg, len, target) /* * Get mbuf chain whenever possible (not clusters), * to save socket buffer. We'll be generating many SADB_ACQUIRE - * messages to listening key sockets. If we simmply allocate clusters, + * messages to listening key sockets. If we simply allocate clusters, * sbappendaddr() will raise ENOBUFS due to too little sbspace(). * sbspace() computes # of actual data bytes AND mbuf region. * @@ -432,6 +282,7 @@ key_sendup(so, msg, len, target) return key_sendup_mbuf(so, m, target); } +/* so can be NULL if target != KEY_SENDUP_ONE */ int key_sendup_mbuf(so, m, target) struct socket *so; @@ -442,9 +293,11 @@ key_sendup_mbuf(so, m, target) struct keycb *kp; int sendup; struct rawcb *rp; - int error; + int error = 0; - if (so == NULL || m == NULL) + if (m == NULL) + panic("key_sendup_mbuf: NULL pointer was passed.\n"); + if (so == NULL && target == KEY_SENDUP_ONE) panic("key_sendup_mbuf: NULL pointer was passed.\n"); pfkeystat.in_total++; @@ -466,13 +319,7 @@ key_sendup_mbuf(so, m, target) pfkeystat.in_msgtype[msg->sadb_msg_type]++; } -#ifdef __NetBSD__ - for (rp = rawcb.lh_first; rp; rp = rp->rcb_list.le_next) -#elif defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) LIST_FOREACH(rp, &rawcb_list, list) -#else - for (rp = rawcb.rcb_next; rp != &rawcb; rp = rp->rcb_next) -#endif { if (rp->rcb_proto.sp_family != PF_KEY) continue; @@ -496,14 +343,14 @@ key_sendup_mbuf(so, m, target) } /* the exact target will be processed later */ - if (sotorawcb(so) == rp) + if (so && sotorawcb(so) == rp) continue; sendup = 0; switch (target) { case KEY_SENDUP_ONE: /* the statement has no effect */ - if (sotorawcb(so) == rp) + if (so && sotorawcb(so) == rp) sendup++; break; case KEY_SENDUP_ALL: @@ -536,12 +383,16 @@ key_sendup_mbuf(so, m, target) n = NULL; } - error = key_sendup0(sotorawcb(so), m, 0); - m = NULL; + if (so) { + error = key_sendup0(sotorawcb(so), m, 0); + m = NULL; + } else { + error = 0; + m_freem(m); + } return error; } -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) /* * key_abort() * derived from net/rtsock.c:rts_abort() @@ -738,12 +589,9 @@ struct pr_usrreqs key_usrreqs = { pru_rcvoob_notsupp, key_send, pru_sense_null, key_shutdown, key_sockaddr, sosend, soreceive, sopoll }; -#endif /* __FreeBSD__ >= 3 */ -#if __FreeBSD__ || defined (__APPLE__) /* sysctl */ SYSCTL_NODE(_net, PF_KEY, key, CTLFLAG_RW, 0, "Key Family"); -#endif /* * Definitions of protocols supported in the KEY domain. diff --git a/bsd/netkey/keysock.h b/bsd/netkey/keysock.h index 051f059c9..f176d1a20 100644 --- a/bsd/netkey/keysock.h +++ b/bsd/netkey/keysock.h @@ -31,6 +31,7 @@ #ifndef _NETKEY_KEYSOCK_H_ #define _NETKEY_KEYSOCK_H_ +#include /* statistics for pfkey socket */ struct pfkeystat { @@ -62,6 +63,7 @@ struct pfkeystat { #define KEY_SENDUP_REGISTERED 2 #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE struct keycb { struct rawcb kp_raw; /* rawcb */ int kp_promisc; /* promiscuous mode */ @@ -70,17 +72,17 @@ struct keycb { extern struct pfkeystat pfkeystat; -extern int key_output __P((struct mbuf *, struct socket *)); -#ifndef __NetBSD__ -extern int key_usrreq __P((struct socket *, - int, struct mbuf *, struct mbuf *, struct mbuf *)); +#ifdef __APPLE__ +extern int key_output __P((struct mbuf *, struct socket* so)); #else -extern int key_usrreq __P((struct socket *, - int, struct mbuf *, struct mbuf *, struct mbuf *, struct proc *)); +extern int key_output __P((struct mbuf *, ...)); #endif +extern int key_usrreq __P((struct socket *, + int, struct mbuf *, struct mbuf *, struct mbuf *)); extern int key_sendup __P((struct socket *, struct sadb_msg *, u_int, int)); extern int key_sendup_mbuf __P((struct socket *, struct mbuf *, int)); +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ #endif /*_NETKEY_KEYSOCK_H_*/ diff --git a/bsd/netns/Makefile b/bsd/netns/Makefile deleted file mode 100644 index c9a2a65c4..000000000 --- a/bsd/netns/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -export MakeInc_cmd=${SRCROOT}/makedefs/MakeInc.cmd -export MakeInc_def=${SRCROOT}/makedefs/MakeInc.def -export MakeInc_rule=${SRCROOT}/makedefs/MakeInc.rule -export MakeInc_dir=${SRCROOT}/makedefs/MakeInc.dir - - -include $(MakeInc_cmd) -include $(MakeInc_def) - -INSTINC_SUBDIRS = \ - -INSTINC_SUBDIRS_PPC = \ - -INSTINC_SUBDIRS_I386 = \ - -EXPINC_SUBDIRS = \ - -EXPINC_SUBDIRS_PPC = \ - -EXPINC_SUBDIRS_I386 = \ - -DATAFILES = \ - idp.h idp_var.h ns.h ns_error.h ns_if.h ns_pcb.h \ - sp.h spidp.h spp_debug.h spp_timer.h spp_var.h - -INSTALL_MI_LIST = ${DATAFILES} - -INSTALL_MI_DIR = netns - -EXPORT_MI_LIST = ${DATAFILES} - -EXPORT_MI_DIR = netns - - -include $(MakeInc_rule) -include $(MakeInc_dir) - - diff --git a/bsd/netns/idp.h b/bsd/netns/idp.h deleted file mode 100644 index e4cd666ad..000000000 --- a/bsd/netns/idp.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1984, 1985, 1986, 1987, 1993 - * 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. - * - * @(#)idp.h 8.1 (Berkeley) 6/10/93 - */ - -/* - * Definitions for NS(tm) Internet Datagram Protocol - */ -struct idp { - u_short idp_sum; /* Checksum */ - u_short idp_len; /* Length, in bytes, including header */ - u_char idp_tc; /* Transport Crontrol (i.e. hop count) */ - u_char idp_pt; /* Packet Type (i.e. level 2 protocol) */ - struct ns_addr idp_dna; /* Destination Network Address */ - struct ns_addr idp_sna; /* Source Network Address */ -}; diff --git a/bsd/netns/idp_usrreq.c b/bsd/netns/idp_usrreq.c deleted file mode 100644 index 7814c0cc3..000000000 --- a/bsd/netns/idp_usrreq.c +++ /dev/null @@ -1,587 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1984, 1985, 1986, 1987, 1993 - * 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. - * - * @(#)idp_usrreq.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -/* - * IDP protocol implementation. - */ - -struct sockaddr_ns idp_ns = { sizeof(idp_ns), AF_NS }; - -/* - * This may also be called for raw listeners. - */ -idp_input(m, nsp) - struct mbuf *m; - register struct nspcb *nsp; -{ - register struct idp *idp = mtod(m, struct idp *); - struct ifnet *ifp = m->m_pkthdr.rcvif; - - if (nsp==0) - panic("No nspcb"); - /* - * Construct sockaddr format source address. - * Stuff source address and datagram in user buffer. - */ - idp_ns.sns_addr = idp->idp_sna; - if (ns_neteqnn(idp->idp_sna.x_net, ns_zeronet) && ifp) { - register struct ifaddr *ifa; - - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { - if (ifa->ifa_addr->sa_family == AF_NS) { - idp_ns.sns_addr.x_net = - IA_SNS(ifa)->sns_addr.x_net; - break; - } - } - } - nsp->nsp_rpt = idp->idp_pt; - if ( ! (nsp->nsp_flags & NSP_RAWIN) ) { - m->m_len -= sizeof (struct idp); - m->m_pkthdr.len -= sizeof (struct idp); - m->m_data += sizeof (struct idp); - } - if (sbappendaddr(&nsp->nsp_socket->so_rcv, (struct sockaddr *)&idp_ns, - m, (struct mbuf *)0) == 0) - goto bad; - sorwakeup(nsp->nsp_socket); - return; -bad: - m_freem(m); -} - -idp_abort(nsp) - struct nspcb *nsp; -{ - struct socket *so = nsp->nsp_socket; - - ns_pcbdisconnect(nsp); - soisdisconnected(so); -} -/* - * Drop connection, reporting - * the specified error. - */ -struct nspcb * -idp_drop(nsp, errno) - register struct nspcb *nsp; - int errno; -{ - struct socket *so = nsp->nsp_socket; - - /* - * someday, in the xerox world - * we will generate error protocol packets - * announcing that the socket has gone away. - */ - /*if (TCPS_HAVERCVDSYN(tp->t_state)) { - tp->t_state = TCPS_CLOSED; - (void) tcp_output(tp); - }*/ - so->so_error = errno; - ns_pcbdisconnect(nsp); - soisdisconnected(so); -} - -int noIdpRoute; -idp_output(nsp, m0) - struct nspcb *nsp; - struct mbuf *m0; -{ - register struct mbuf *m; - register struct idp *idp; - register struct socket *so; - register int len = 0; - register struct route *ro; - struct mbuf *mprev; - extern int idpcksum; - - /* - * Calculate data length. - */ - for (m = m0; m; m = m->m_next) { - mprev = m; - len += m->m_len; - } - /* - * Make sure packet is actually of even length. - */ - - if (len & 1) { - m = mprev; - if ((m->m_flags & M_EXT) == 0 && - (m->m_len + m->m_data < &m->m_dat[MLEN])) { - m->m_len++; - } else { - struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); - - if (m1 == 0) { - m_freem(m0); - return (ENOBUFS); - } - m1->m_len = 1; - * mtod(m1, char *) = 0; - m->m_next = m1; - } - m0->m_pkthdr.len++; - } - - /* - * Fill in mbuf with extended IDP header - * and addresses and length put into network format. - */ - m = m0; - if (nsp->nsp_flags & NSP_RAWOUT) { - idp = mtod(m, struct idp *); - } else { - M_PREPEND(m, sizeof (struct idp), M_DONTWAIT); - if (m == 0) - return (ENOBUFS); - idp = mtod(m, struct idp *); - idp->idp_tc = 0; - idp->idp_pt = nsp->nsp_dpt; - idp->idp_sna = nsp->nsp_laddr; - idp->idp_dna = nsp->nsp_faddr; - len += sizeof (struct idp); - } - - idp->idp_len = htons((u_short)len); - - if (idpcksum) { - idp->idp_sum = 0; - len = ((len - 1) | 1) + 1; - idp->idp_sum = ns_cksum(m, len); - } else - idp->idp_sum = 0xffff; - - /* - * Output datagram. - */ - so = nsp->nsp_socket; - if (so->so_options & SO_DONTROUTE) - return (ns_output(m, (struct route *)0, - (so->so_options & SO_BROADCAST) | NS_ROUTETOIF)); - /* - * Use cached route for previous datagram if - * possible. If the previous net was the same - * and the interface was a broadcast medium, or - * if the previous destination was identical, - * then we are ok. - * - * NB: We don't handle broadcasts because that - * would require 3 subroutine calls. - */ - ro = &nsp->nsp_route; -#ifdef ancient_history - /* - * I think that this will all be handled in ns_pcbconnect! - */ - if (ro->ro_rt) { - if(ns_neteq(nsp->nsp_lastdst, idp->idp_dna)) { - /* - * This assumes we have no GH type routes - */ - if (ro->ro_rt->rt_flags & RTF_HOST) { - if (!ns_hosteq(nsp->nsp_lastdst, idp->idp_dna)) - goto re_route; - - } - if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) { - register struct ns_addr *dst = - &satons_addr(ro->ro_dst); - dst->x_host = idp->idp_dna.x_host; - } - /* - * Otherwise, we go through the same gateway - * and dst is already set up. - */ - } else { - re_route: - RTFREE(ro->ro_rt); - ro->ro_rt = (struct rtentry *)0; - } - } - nsp->nsp_lastdst = idp->idp_dna; -#endif /* ancient_history */ - if (noIdpRoute) ro = 0; - return (ns_output(m, ro, so->so_options & SO_BROADCAST)); -} -/* ARGSUSED */ -idp_ctloutput(req, so, level, name, value) - int req, level; - struct socket *so; - int name; - struct mbuf **value; -{ - register struct mbuf *m; - struct nspcb *nsp = sotonspcb(so); - int mask, error = 0; - extern long ns_pexseq; - - if (nsp == NULL) - return (EINVAL); - - switch (req) { - - case PRCO_GETOPT: - if (value==NULL) - return (EINVAL); - m = m_get(M_DONTWAIT, MT_DATA); - if (m==NULL) - return (ENOBUFS); - switch (name) { - - case SO_ALL_PACKETS: - mask = NSP_ALL_PACKETS; - goto get_flags; - - case SO_HEADERS_ON_INPUT: - mask = NSP_RAWIN; - goto get_flags; - - case SO_HEADERS_ON_OUTPUT: - mask = NSP_RAWOUT; - get_flags: - m->m_len = sizeof(short); - *mtod(m, short *) = nsp->nsp_flags & mask; - break; - - case SO_DEFAULT_HEADERS: - m->m_len = sizeof(struct idp); - { - register struct idp *idp = mtod(m, struct idp *); - idp->idp_len = 0; - idp->idp_sum = 0; - idp->idp_tc = 0; - idp->idp_pt = nsp->nsp_dpt; - idp->idp_dna = nsp->nsp_faddr; - idp->idp_sna = nsp->nsp_laddr; - } - break; - - case SO_SEQNO: - m->m_len = sizeof(long); - *mtod(m, long *) = ns_pexseq++; - break; - - default: - error = EINVAL; - } - *value = m; - break; - - case PRCO_SETOPT: - switch (name) { - int *ok; - - case SO_ALL_PACKETS: - mask = NSP_ALL_PACKETS; - goto set_head; - - case SO_HEADERS_ON_INPUT: - mask = NSP_RAWIN; - goto set_head; - - case SO_HEADERS_ON_OUTPUT: - mask = NSP_RAWOUT; - set_head: - if (value && *value) { - ok = mtod(*value, int *); - if (*ok) - nsp->nsp_flags |= mask; - else - nsp->nsp_flags &= ~mask; - } else error = EINVAL; - break; - - case SO_DEFAULT_HEADERS: - { - register struct idp *idp - = mtod(*value, struct idp *); - nsp->nsp_dpt = idp->idp_pt; - } - break; -#ifdef NSIP - - case SO_NSIP_ROUTE: - error = nsip_route(*value); - break; -#endif /* NSIP */ - default: - error = EINVAL; - } - if (value && *value) - m_freem(*value); - break; - } - return (error); -} - -/*ARGSUSED*/ -idp_usrreq(so, req, m, nam, control) - struct socket *so; - int req; - struct mbuf *m, *nam, *control; -{ - struct nspcb *nsp = sotonspcb(so); - int error = 0; - - if (req == PRU_CONTROL) - return (ns_control(so, (int)m, (caddr_t)nam, - (struct ifnet *)control)); - if (control && control->m_len) { - error = EINVAL; - goto release; - } - if (nsp == NULL && req != PRU_ATTACH) { - error = EINVAL; - goto release; - } - switch (req) { - - case PRU_ATTACH: - if (nsp != NULL) { - error = EINVAL; - break; - } - error = ns_pcballoc(so, &nspcb); - if (error) - break; - error = soreserve(so, (u_long) 2048, (u_long) 2048); - if (error) - break; - break; - - case PRU_DETACH: - if (nsp == NULL) { - error = ENOTCONN; - break; - } - ns_pcbdetach(nsp); - break; - - case PRU_BIND: - error = ns_pcbbind(nsp, nam); - break; - - case PRU_LISTEN: - error = EOPNOTSUPP; - break; - - case PRU_CONNECT: - if (!ns_nullhost(nsp->nsp_faddr)) { - error = EISCONN; - break; - } - error = ns_pcbconnect(nsp, nam); - if (error == 0) - soisconnected(so); - break; - - case PRU_CONNECT2: - error = EOPNOTSUPP; - break; - - case PRU_ACCEPT: - error = EOPNOTSUPP; - break; - - case PRU_DISCONNECT: - if (ns_nullhost(nsp->nsp_faddr)) { - error = ENOTCONN; - break; - } - ns_pcbdisconnect(nsp); - soisdisconnected(so); - break; - - case PRU_SHUTDOWN: - socantsendmore(so); - break; - - case PRU_SEND: - { - struct ns_addr laddr; - int s; - - if (nam) { - laddr = nsp->nsp_laddr; - if (!ns_nullhost(nsp->nsp_faddr)) { - error = EISCONN; - break; - } - /* - * Must block input while temporarily connected. - */ - s = splnet(); - error = ns_pcbconnect(nsp, nam); - if (error) { - splx(s); - break; - } - } else { - if (ns_nullhost(nsp->nsp_faddr)) { - error = ENOTCONN; - break; - } - } - error = idp_output(nsp, m); - m = NULL; - if (nam) { - ns_pcbdisconnect(nsp); - splx(s); - nsp->nsp_laddr.x_host = laddr.x_host; - nsp->nsp_laddr.x_port = laddr.x_port; - } - } - break; - - case PRU_ABORT: - ns_pcbdetach(nsp); - sofree(so); - soisdisconnected(so); - break; - - case PRU_SOCKADDR: - ns_setsockaddr(nsp, nam); - break; - - case PRU_PEERADDR: - ns_setpeeraddr(nsp, nam); - 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_CONTROL: - case PRU_RCVD: - case PRU_RCVOOB: - return (EOPNOTSUPP); /* do not free mbuf's */ - - default: - panic("idp_usrreq"); - } -release: - if (control != NULL) - m_freem(control); - if (m != NULL) - m_freem(m); - return (error); -} -/*ARGSUSED*/ -idp_raw_usrreq(so, req, m, nam, control) - struct socket *so; - int req; - struct mbuf *m, *nam, *control; -{ - int error = 0; - struct nspcb *nsp = sotonspcb(so); - extern struct nspcb nsrawpcb; - - switch (req) { - - case PRU_ATTACH: - - if (!(so->so_state & SS_PRIV) || (nsp != NULL)) { - error = EINVAL; - break; - } - error = ns_pcballoc(so, &nsrawpcb); - if (error) - break; - error = soreserve(so, (u_long) 2048, (u_long) 2048); - if (error) - break; - nsp = sotonspcb(so); - nsp->nsp_faddr.x_host = ns_broadhost; - nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT; - break; - default: - error = idp_usrreq(so, req, m, nam, control); - } - return (error); -} - diff --git a/bsd/netns/idp_var.h b/bsd/netns/idp_var.h deleted file mode 100644 index d04ad07c7..000000000 --- a/bsd/netns/idp_var.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1984, 1985, 1986, 1987, 1993 - * 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. - * - * @(#)idp_var.h 8.1 (Berkeley) 6/10/93 - */ - -/* - * IDP Kernel Structures and Variables - */ -struct idpstat { - int idps_badsum; /* checksum bad */ - int idps_tooshort; /* packet too short */ - int idps_toosmall; /* not enough data */ - int idps_badhlen; /* ip header length < data size */ - int idps_badlen; /* ip length < ip header length */ -}; - -#ifdef KERNEL -struct idpstat idpstat; -#endif diff --git a/bsd/netns/ns.c b/bsd/netns/ns.c deleted file mode 100644 index 12688f479..000000000 --- a/bsd/netns/ns.c +++ /dev/null @@ -1,390 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1984, 1985, 1986, 1987, 1993 - * 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. - * - * @(#)ns.c 8.2 (Berkeley) 11/15/93 - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#ifdef NS - -struct ns_ifaddr *ns_ifaddr; -int ns_interfaces; -extern struct sockaddr_ns ns_netmask, ns_hostmask; - -/* - * Generic internet control operations (ioctl's). - */ -/* ARGSUSED */ -ns_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 ns_aliasreq *ifra = (struct ns_aliasreq *)data; - register struct ns_ifaddr *ia; - struct ifaddr *ifa; - struct ns_ifaddr *oia; - int error, dstIsNew, hostIsNew; - - /* - * Find address for this interface, if it exists. - */ - if (ifp == 0) - return (EADDRNOTAVAIL); - for (ia = ns_ifaddr; ia; ia = ia->ia_next) - if (ia->ia_ifp == ifp) - break; - - switch (cmd) { - - case SIOCGIFADDR: - if (ia == (struct ns_ifaddr *)0) - return (EADDRNOTAVAIL); - *(struct sockaddr_ns *)&ifr->ifr_addr = ia->ia_addr; - return (0); - - - case SIOCGIFBRDADDR: - if (ia == (struct ns_ifaddr *)0) - return (EADDRNOTAVAIL); - if ((ifp->if_flags & IFF_BROADCAST) == 0) - return (EINVAL); - *(struct sockaddr_ns *)&ifr->ifr_dstaddr = ia->ia_broadaddr; - return (0); - - case SIOCGIFDSTADDR: - if (ia == (struct ns_ifaddr *)0) - return (EADDRNOTAVAIL); - if ((ifp->if_flags & IFF_POINTOPOINT) == 0) - return (EINVAL); - *(struct sockaddr_ns *)&ifr->ifr_dstaddr = ia->ia_dstaddr; - return (0); - } - - if ((so->so_state & SS_PRIV) == 0) - return (EPERM); - - switch (cmd) { - case SIOCAIFADDR: - case SIOCDIFADDR: - if (ifra->ifra_addr.sns_family == AF_NS) - for (oia = ia; ia; ia = ia->ia_next) { - if (ia->ia_ifp == ifp && - ns_neteq(ia->ia_addr.sns_addr, - ifra->ifra_addr.sns_addr)) - break; - } - if (cmd == SIOCDIFADDR && ia == 0) - return (EADDRNOTAVAIL); - /* FALLTHROUGH */ - - case SIOCSIFADDR: - case SIOCSIFDSTADDR: - if (ia == (struct ns_ifaddr *)0) { -// oia = (struct ns_ifaddr *) -// malloc(sizeof *ia, M_IFADDR, M_WAITOK); - MALLOC(oia, struct ns_ifaddr *, sizeof *ia, M_IFADDR, M_WAITOK); - if (oia == (struct ns_ifaddr *)NULL) - return (ENOBUFS); - bzero((caddr_t)oia, sizeof(*oia)); - if (ia = ns_ifaddr) { - for ( ; ia->ia_next; ia = ia->ia_next) - ; - ia->ia_next = oia; - } else - ns_ifaddr = oia; - ia = oia; - 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_ifp = ifp; - ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; - - ia->ia_ifa.ifa_netmask = - (struct sockaddr *)&ns_netmask; - - ia->ia_ifa.ifa_dstaddr = - (struct sockaddr *)&ia->ia_dstaddr; - if (ifp->if_flags & IFF_BROADCAST) { - ia->ia_broadaddr.sns_family = AF_NS; - ia->ia_broadaddr.sns_len = sizeof(ia->ia_addr); - ia->ia_broadaddr.sns_addr.x_host = ns_broadhost; - } - ns_interfaces++; - } - } - - switch (cmd) { - int error; - - case SIOCSIFDSTADDR: - if ((ifp->if_flags & IFF_POINTOPOINT) == 0) - return (EINVAL); - if (ia->ia_flags & IFA_ROUTE) { - rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); - ia->ia_flags &= ~IFA_ROUTE; - } - if (ifp->if_ioctl) { - error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia); - if (error) - return (error); - } - *(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr; - return (0); - - case SIOCSIFADDR: - return (ns_ifinit(ifp, ia, - (struct sockaddr_ns *)&ifr->ifr_addr, 1)); - - case SIOCDIFADDR: - ns_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 nsifaddr from ifp\n"); - } - oia = ia; - if (oia == (ia = ns_ifaddr)) { - ns_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 nsifadr from list\n"); - } - IFAFREE((&oia->ia_ifa)); - if (0 == --ns_interfaces) { - /* - * We reset to virginity and start all over again - */ - ns_thishost = ns_zerohost; - } - return (0); - - case SIOCAIFADDR: - dstIsNew = 0; hostIsNew = 1; - if (ia->ia_addr.sns_family == AF_NS) { - if (ifra->ifra_addr.sns_len == 0) { - ifra->ifra_addr = ia->ia_addr; - hostIsNew = 0; - } else if (ns_neteq(ifra->ifra_addr.sns_addr, - ia->ia_addr.sns_addr)) - hostIsNew = 0; - } - if ((ifp->if_flags & IFF_POINTOPOINT) && - (ifra->ifra_dstaddr.sns_family == AF_NS)) { - if (hostIsNew == 0) - ns_ifscrub(ifp, ia); - ia->ia_dstaddr = ifra->ifra_dstaddr; - dstIsNew = 1; - } - if (ifra->ifra_addr.sns_family == AF_NS && - (hostIsNew || dstIsNew)) - error = ns_ifinit(ifp, ia, &ifra->ifra_addr, 0); - return (error); - - default: - if (ifp->if_ioctl == 0) - return (EOPNOTSUPP); - return ((*ifp->if_ioctl)(ifp, cmd, data)); - } -} - -/* -* Delete any previous route for an old address. -*/ -ns_ifscrub(ifp, ia) - register struct ifnet *ifp; - register struct ns_ifaddr *ia; -{ - if (ia->ia_flags & IFA_ROUTE) { - if (ifp->if_flags & 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. - */ -ns_ifinit(ifp, ia, sns, scrub) - register struct ifnet *ifp; - register struct ns_ifaddr *ia; - register struct sockaddr_ns *sns; -{ - struct sockaddr_ns oldaddr; - register union ns_host *h = &ia->ia_addr.sns_addr.x_host; - int s = splimp(), error; - - /* - * Set up new addresses. - */ - oldaddr = ia->ia_addr; - ia->ia_addr = *sns; - /* - * The convention we shall adopt for naming is that - * a supplied address of zero means that "we don't care". - * if there is a single interface, use the address of that - * interface as our 6 byte host address. - * if there are multiple interfaces, use any address already - * used. - * - * Give the interface a chance to initialize - * if this is its first address, - * and to validate the address if necessary. - */ - if (ns_hosteqnh(ns_thishost, ns_zerohost)) { - if (ifp->if_ioctl && - (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) { - ia->ia_addr = oldaddr; - splx(s); - return (error); - } - ns_thishost = *h; - } else if (ns_hosteqnh(sns->sns_addr.x_host, ns_zerohost) - || ns_hosteqnh(sns->sns_addr.x_host, ns_thishost)) { - *h = ns_thishost; - if (ifp->if_ioctl && - (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) { - ia->ia_addr = oldaddr; - splx(s); - return (error); - } - if (!ns_hosteqnh(ns_thishost,*h)) { - ia->ia_addr = oldaddr; - splx(s); - return (EINVAL); - } - } else { - ia->ia_addr = oldaddr; - splx(s); - return (EINVAL); - } - ia->ia_ifa.ifa_metric = ifp->if_metric; - /* - * Add route for the network. - */ - if (scrub) { - ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr; - ns_ifscrub(ifp, ia); - ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; - } - if (ifp->if_flags & IFF_POINTOPOINT) - rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP); - else { - ia->ia_broadaddr.sns_addr.x_net = ia->ia_addr.sns_addr.x_net; - rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP); - } - ia->ia_flags |= IFA_ROUTE; - return (0); -} - -/* - * Return address info for specified internet network. - */ -struct ns_ifaddr * -ns_iaonnetof(dst) - register struct ns_addr *dst; -{ - register struct ns_ifaddr *ia; - register struct ns_addr *compare; - register struct ifnet *ifp; - struct ns_ifaddr *ia_maybe = 0; - union ns_net net = dst->x_net; - - for (ia = ns_ifaddr; ia; ia = ia->ia_next) { - if (ifp = ia->ia_ifp) { - if (ifp->if_flags & IFF_POINTOPOINT) { - compare = &satons_addr(ia->ia_dstaddr); - if (ns_hosteq(*dst, *compare)) - return (ia); - if (ns_neteqnn(net, ia->ia_addr.sns_addr.x_net)) - ia_maybe = ia; - } else { - if (ns_neteqnn(net, ia->ia_addr.sns_addr.x_net)) - return (ia); - } - } - } - return (ia_maybe); -} -#endif diff --git a/bsd/netns/ns.h b/bsd/netns/ns.h deleted file mode 100644 index acc1a9bca..000000000 --- a/bsd/netns/ns.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1984, 1985, 1986, 1987, 1993 - * 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. - * - * @(#)ns.h 8.1 (Berkeley) 6/10/93 - */ - -/* - * Constants and Structures defined by the Xerox Network Software - * per "Internet Transport Protocols", XSIS 028112, December 1981 - */ - -/* - * Protocols - */ -#define NSPROTO_RI 1 /* Routing Information */ -#define NSPROTO_ECHO 2 /* Echo Protocol */ -#define NSPROTO_ERROR 3 /* Error Protocol */ -#define NSPROTO_PE 4 /* Packet Exchange */ -#define NSPROTO_SPP 5 /* Sequenced Packet */ -#define NSPROTO_RAW 255 /* Placemarker*/ -#define NSPROTO_MAX 256 /* Placemarker*/ - - -/* - * Port/Socket numbers: network standard functions - */ - -#define NSPORT_RI 1 /* Routing Information */ -#define NSPORT_ECHO 2 /* Echo */ -#define NSPORT_RE 3 /* Router Error */ - -/* - * Ports < NSPORT_RESERVED are reserved for priveleged - * processes (e.g. root). - */ -#define NSPORT_RESERVED 3000 - -/* flags passed to ns_output as last parameter */ - -#define NS_FORWARDING 0x1 /* most of idp header exists */ -#define NS_ROUTETOIF 0x10 /* same as SO_DONTROUTE */ -#define NS_ALLOWBROADCAST SO_BROADCAST /* can send broadcast packets */ - -#define NS_MAXHOPS 15 - -/* flags passed to get/set socket option */ -#define SO_HEADERS_ON_INPUT 1 -#define SO_HEADERS_ON_OUTPUT 2 -#define SO_DEFAULT_HEADERS 3 -#define SO_LAST_HEADER 4 -#define SO_NSIP_ROUTE 5 -#define SO_SEQNO 6 -#define SO_ALL_PACKETS 7 -#define SO_MTU 8 - - -/* - * NS addressing - */ -union ns_host { - u_char c_host[6]; - u_short s_host[3]; -}; - -union ns_net { - u_char c_net[4]; - u_short s_net[2]; -}; - -union ns_net_u { - union ns_net net_e; - u_long long_e; -}; - -struct ns_addr { - union ns_net x_net; - union ns_host x_host; - u_short x_port; -}; - -/* - * Socket address, Xerox style - */ -struct sockaddr_ns { - u_char sns_len; - u_char sns_family; - struct ns_addr sns_addr; - char sns_zero[2]; -}; -#define sns_port sns_addr.x_port - -#ifdef vax -#define ns_netof(a) (*(long *) & ((a).x_net)) /* XXX - not needed */ -#endif -#define ns_neteqnn(a,b) (((a).s_net[0]==(b).s_net[0]) && \ - ((a).s_net[1]==(b).s_net[1])) -#define ns_neteq(a,b) ns_neteqnn((a).x_net, (b).x_net) -#define satons_addr(sa) (((struct sockaddr_ns *)&(sa))->sns_addr) -#define ns_hosteqnh(s,t) ((s).s_host[0] == (t).s_host[0] && \ - (s).s_host[1] == (t).s_host[1] && (s).s_host[2] == (t).s_host[2]) -#define ns_hosteq(s,t) (ns_hosteqnh((s).x_host,(t).x_host)) -#define ns_nullhost(x) (((x).x_host.s_host[0]==0) && \ - ((x).x_host.s_host[1]==0) && ((x).x_host.s_host[2]==0)) - -#ifdef KERNEL -extern struct domain nsdomain; -union ns_host ns_thishost; -union ns_host ns_zerohost; -union ns_host ns_broadhost; -union ns_net ns_zeronet; -union ns_net ns_broadnet; -u_short ns_cksum(); -#else - -#include - -__BEGIN_DECLS -extern struct ns_addr ns_addr __P((const char *)); -extern char *ns_ntoa __P((struct ns_addr)); -__END_DECLS - -#endif diff --git a/bsd/netns/ns_cksum.c b/bsd/netns/ns_cksum.c deleted file mode 100644 index 9c13af8c5..000000000 --- a/bsd/netns/ns_cksum.c +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1982, 1992, 1993 - * 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. - * - * @(#)ns_cksum.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include - -/* - * Checksum routine for Network Systems Protocol Packets (Big-Endian). - * - * 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) { if ((x) > 65535) (x) -= 65535; } -#define FOLD(x) {l_util.l = (x); (x) = l_util.s[0] + l_util.s[1]; ADDCARRY(x);} - -u_short -ns_cksum(m, len) - register struct mbuf *m; - register int len; -{ - register u_short *w; - register int sum = 0; - register int mlen = 0; - register int sum2; - - union { - u_short s[2]; - long l; - } l_util; - - for (;m && len; m = m->m_next) { - if (m->m_len == 0) - continue; - /* - * Each trip around loop adds in - * word from one mbuf segment. - */ - w = mtod(m, u_short *); - if (mlen == -1) { - /* - * There is a byte left from the last segment; - * ones-complement add it into the checksum. - */ -#if BYTE_ORDER == BIG_ENDIAN - sum += *(u_char *)w; -#else - sum += *(u_char *)w << 8; -#endif - sum += sum; - w = (u_short *)(1 + (char *)w); - mlen = m->m_len - 1; - len--; - FOLD(sum); - } else - mlen = m->m_len; - if (len < mlen) - mlen = len; - len -= mlen; - /* - * We can do a 16 bit ones complement sum using - * 32 bit arithmetic registers for adding, - * with carries from the low added - * into the high (by normal carry-chaining) - * so long as we fold back before 16 carries have occured. - */ - if (1 & (int) w) - goto uuuuglyy; -#ifndef TINY -/* -DTINY reduces the size from 1250 to 550, but slows it down by 22% */ - while ((mlen -= 32) >= 0) { - sum += w[0]; sum += sum; sum += w[1]; sum += sum; - sum += w[2]; sum += sum; sum += w[3]; sum += sum; - sum += w[4]; sum += sum; sum += w[5]; sum += sum; - sum += w[6]; sum += sum; sum += w[7]; sum += sum; - FOLD(sum); - sum += w[8]; sum += sum; sum += w[9]; sum += sum; - sum += w[10]; sum += sum; sum += w[11]; sum += sum; - sum += w[12]; sum += sum; sum += w[13]; sum += sum; - sum += w[14]; sum += sum; sum += w[15]; sum += sum; - FOLD(sum); - w += 16; - } - mlen += 32; -#endif - while ((mlen -= 8) >= 0) { - sum += w[0]; sum += sum; sum += w[1]; sum += sum; - sum += w[2]; sum += sum; sum += w[3]; sum += sum; - FOLD(sum); - w += 4; - } - mlen += 8; - while ((mlen -= 2) >= 0) { - sum += *w++; sum += sum; - } - goto commoncase; -uuuuglyy: -#if BYTE_ORDER == BIG_ENDIAN -#define ww(n) (((u_char *)w)[n + n + 1]) -#define vv(n) (((u_char *)w)[n + n]) -#else -#if BYTE_ORDER == LITTLE_ENDIAN -#define vv(n) (((u_char *)w)[n + n + 1]) -#define ww(n) (((u_char *)w)[n + n]) -#endif -#endif - sum2 = 0; -#ifndef TINY - while ((mlen -= 32) >= 0) { - sum += ww(0); sum += sum; sum += ww(1); sum += sum; - sum += ww(2); sum += sum; sum += ww(3); sum += sum; - sum += ww(4); sum += sum; sum += ww(5); sum += sum; - sum += ww(6); sum += sum; sum += ww(7); sum += sum; - FOLD(sum); - sum += ww(8); sum += sum; sum += ww(9); sum += sum; - sum += ww(10); sum += sum; sum += ww(11); sum += sum; - sum += ww(12); sum += sum; sum += ww(13); sum += sum; - sum += ww(14); sum += sum; sum += ww(15); sum += sum; - FOLD(sum); - sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2; - sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2; - sum2 += vv(4); sum2 += sum2; sum2 += vv(5); sum2 += sum2; - sum2 += vv(6); sum2 += sum2; sum2 += vv(7); sum2 += sum2; - FOLD(sum2); - sum2 += vv(8); sum2 += sum2; sum2 += vv(9); sum2 += sum2; - sum2 += vv(10); sum2 += sum2; sum2 += vv(11); sum2 += sum2; - sum2 += vv(12); sum2 += sum2; sum2 += vv(13); sum2 += sum2; - sum2 += vv(14); sum2 += sum2; sum2 += vv(15); sum2 += sum2; - FOLD(sum2); - w += 16; - } - mlen += 32; -#endif - while ((mlen -= 8) >= 0) { - sum += ww(0); sum += sum; sum += ww(1); sum += sum; - sum += ww(2); sum += sum; sum += ww(3); sum += sum; - FOLD(sum); - sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2; - sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2; - FOLD(sum2); - w += 4; - } - mlen += 8; - while ((mlen -= 2) >= 0) { - sum += ww(0); sum += sum; - sum2 += vv(0); sum2 += sum2; - w++; - } - sum += (sum2 << 8); -commoncase: - if (mlen == -1) { -#if BYTE_ORDER == BIG_ENDIAN - sum += *(u_char *)w << 8; -#else - sum += *(u_char *)w; -#endif - } - FOLD(sum); - } - if (mlen == -1) { - /* We had an odd number of bytes to sum; assume a garbage - byte of zero and clean up */ - sum += sum; - FOLD(sum); - } - /* - * sum has already been kept to low sixteen bits. - * just examine result and exit. - */ - if(sum==0xffff) sum = 0; - return (sum); -} diff --git a/bsd/netns/ns_error.c b/bsd/netns/ns_error.c deleted file mode 100644 index ea71eee6d..000000000 --- a/bsd/netns/ns_error.c +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1984, 1988, 1993 - * 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. - * - * @(#)ns_error.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#ifdef lint -#define NS_ERRPRINTFS 1 -#endif - -#ifdef NS_ERRPRINTFS -/* - * NS_ERR routines: error generation, receive packet processing, and - * routines to turnaround packets back to the originator. - */ -int ns_errprintfs = 0; -#endif - -ns_err_x(c) -{ - register u_short *w, *lim, *base = ns_errstat.ns_es_codes; - u_short x = c; - - /* - * zero is a legit error code, handle specially - */ - if (x == 0) - return (0); - lim = base + NS_ERR_MAX - 1; - for (w = base + 1; w < lim; w++) { - if (*w == 0) - *w = x; - if (*w == x) - break; - } - return (w - base); -} - -/* - * Generate an error packet of type error - * in response to bad packet. - */ - -ns_error(om, type, param) - struct mbuf *om; - int type; -{ - register struct ns_epidp *ep; - struct mbuf *m; - struct idp *nip; - register struct idp *oip = mtod(om, struct idp *); - extern int idpcksum; - - /* - * If this packet was sent to the echo port, - * and nobody was there, just echo it. - * (Yes, this is a wart!) - */ - if (type == NS_ERR_NOSOCK && - oip->idp_dna.x_port == htons(2) && - (type = ns_echo(om))==0) - return; - -#ifdef NS_ERRPRINTFS - if (ns_errprintfs) - printf("ns_err_error(%x, %d, %d)\n", oip, type, param); -#endif - /* - * Don't Generate error packets in response to multicasts. - */ - if (oip->idp_dna.x_host.c_host[0] & 1) - goto freeit; - - ns_errstat.ns_es_error++; - /* - * Make sure that the old IDP packet had 30 bytes of data to return; - * if not, don't bother. Also don't EVER error if the old - * packet protocol was NS_ERR. - */ - if (oip->idp_len < sizeof(struct idp)) { - ns_errstat.ns_es_oldshort++; - goto freeit; - } - if (oip->idp_pt == NSPROTO_ERROR) { - ns_errstat.ns_es_oldns_err++; - goto freeit; - } - - /* - * First, formulate ns_err message - */ - m = m_gethdr(M_DONTWAIT, MT_HEADER); - if (m == NULL) - goto freeit; - m->m_len = sizeof(*ep); - MH_ALIGN(m, m->m_len); - ep = mtod(m, struct ns_epidp *); - if ((u_int)type > NS_ERR_TOO_BIG) - panic("ns_err_error"); - ns_errstat.ns_es_outhist[ns_err_x(type)]++; - ep->ns_ep_errp.ns_err_num = htons((u_short)type); - ep->ns_ep_errp.ns_err_param = htons((u_short)param); - bcopy((caddr_t)oip, (caddr_t)&ep->ns_ep_errp.ns_err_idp, 42); - nip = &ep->ns_ep_idp; - nip->idp_len = sizeof(*ep); - nip->idp_len = htons((u_short)nip->idp_len); - nip->idp_pt = NSPROTO_ERROR; - nip->idp_tc = 0; - nip->idp_dna = oip->idp_sna; - nip->idp_sna = oip->idp_dna; - if (idpcksum) { - nip->idp_sum = 0; - nip->idp_sum = ns_cksum(m, sizeof(*ep)); - } else - nip->idp_sum = 0xffff; - (void) ns_output(m, (struct route *)0, 0); - -freeit: - m_freem(om); -} - -ns_printhost(p) -register struct ns_addr *p; -{ - - printf("", - p->x_net.s_net[0], - p->x_net.s_net[1], - p->x_host.s_host[0], - p->x_host.s_host[1], - p->x_host.s_host[2], - p->x_port); - -} - -/* - * Process a received NS_ERR message. - */ -ns_err_input(m) - struct mbuf *m; -{ - register struct ns_errp *ep; - register struct ns_epidp *epidp = mtod(m, struct ns_epidp *); - register int i; - int type, code, param; - - /* - * Locate ns_err structure in mbuf, and check - * that not corrupted and of at least minimum length. - */ -#ifdef NS_ERRPRINTFS - if (ns_errprintfs) { - printf("ns_err_input from "); - ns_printhost(&epidp->ns_ep_idp.idp_sna); - printf("len %d\n", ntohs(epidp->ns_ep_idp.idp_len)); - } -#endif - i = sizeof (struct ns_epidp); - if (((m->m_flags & M_EXT) || m->m_len < i) && - (m = m_pullup(m, i)) == 0) { - ns_errstat.ns_es_tooshort++; - return; - } - ep = &(mtod(m, struct ns_epidp *)->ns_ep_errp); - type = ntohs(ep->ns_err_num); - param = ntohs(ep->ns_err_param); - ns_errstat.ns_es_inhist[ns_err_x(type)]++; - -#ifdef NS_ERRPRINTFS - /* - * Message type specific processing. - */ - if (ns_errprintfs) - printf("ns_err_input, type %d param %d\n", type, param); -#endif - if (type >= NS_ERR_TOO_BIG) { - goto badcode; - } - ns_errstat.ns_es_outhist[ns_err_x(type)]++; - switch (type) { - - case NS_ERR_UNREACH_HOST: - code = PRC_UNREACH_NET; - goto deliver; - - case NS_ERR_TOO_OLD: - code = PRC_TIMXCEED_INTRANS; - goto deliver; - - case NS_ERR_TOO_BIG: - code = PRC_MSGSIZE; - goto deliver; - - case NS_ERR_FULLUP: - code = PRC_QUENCH; - goto deliver; - - case NS_ERR_NOSOCK: - code = PRC_UNREACH_PORT; - goto deliver; - - case NS_ERR_UNSPEC_T: - case NS_ERR_BADSUM_T: - case NS_ERR_BADSUM: - case NS_ERR_UNSPEC: - code = PRC_PARAMPROB; - goto deliver; - - deliver: - /* - * Problem with datagram; advise higher level routines. - */ -#ifdef NS_ERRPRINTFS - if (ns_errprintfs) - printf("deliver to protocol %d\n", - ep->ns_err_idp.idp_pt); -#endif - switch(ep->ns_err_idp.idp_pt) { - case NSPROTO_SPP: - spp_ctlinput(code, (caddr_t)ep); - break; - - default: - idp_ctlinput(code, (caddr_t)ep); - } - - goto freeit; - - default: - badcode: - ns_errstat.ns_es_badcode++; - goto freeit; - - } -freeit: - m_freem(m); -} - -#ifdef notdef -u_long -nstime() -{ - int s = splclock(); - u_long t; - - t = (time.tv_sec % (24*60*60)) * 1000 + time.tv_usec / 1000; - splx(s); - return (htonl(t)); -} -#endif - -ns_echo(m) -struct mbuf *m; -{ - register struct idp *idp = mtod(m, struct idp *); - register struct echo { - struct idp ec_idp; - u_short ec_op; /* Operation, 1 = request, 2 = reply */ - } *ec = (struct echo *)idp; - struct ns_addr temp; - - if (idp->idp_pt!=NSPROTO_ECHO) return(NS_ERR_NOSOCK); - if (ec->ec_op!=htons(1)) return(NS_ERR_UNSPEC); - - ec->ec_op = htons(2); - - temp = idp->idp_dna; - idp->idp_dna = idp->idp_sna; - idp->idp_sna = temp; - - if (idp->idp_sum != 0xffff) { - idp->idp_sum = 0; - idp->idp_sum = ns_cksum(m, - (int)(((ntohs(idp->idp_len) - 1)|1)+1)); - } - (void) ns_output(m, (struct route *)0, NS_FORWARDING); - return(0); -} diff --git a/bsd/netns/ns_error.h b/bsd/netns/ns_error.h deleted file mode 100644 index 45de80a93..000000000 --- a/bsd/netns/ns_error.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1984, 1988, 1993 - * 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. - * - * @(#)ns_error.h 8.1 (Berkeley) 6/10/93 - */ - -/* - * Xerox NS error messages - */ - -struct ns_errp { - u_short ns_err_num; /* Error Number */ - u_short ns_err_param; /* Error Parameter */ - struct idp ns_err_idp; /* Initial segment of offending - packet */ - u_char ns_err_lev2[12]; /* at least this much higher - level protocol */ -}; -struct ns_epidp { - struct idp ns_ep_idp; - struct ns_errp ns_ep_errp; -}; - -#define NS_ERR_UNSPEC 0 /* Unspecified Error detected at dest. */ -#define NS_ERR_BADSUM 1 /* Bad Checksum detected at dest */ -#define NS_ERR_NOSOCK 2 /* Specified socket does not exist at dest*/ -#define NS_ERR_FULLUP 3 /* Dest. refuses packet due to resource lim.*/ -#define NS_ERR_UNSPEC_T 0x200 /* Unspec. Error occured before reaching dest*/ -#define NS_ERR_BADSUM_T 0x201 /* Bad Checksum detected in transit */ -#define NS_ERR_UNREACH_HOST 0x202 /* Dest cannot be reached from here*/ -#define NS_ERR_TOO_OLD 0x203 /* Packet x'd 15 routers without delivery*/ -#define NS_ERR_TOO_BIG 0x204 /* Packet too large to be forwarded through - some intermediate gateway. The error - parameter field contains the max packet - size that can be accommodated */ -#define NS_ERR_MAX 20 - -/* - * Variables related to this implementation - * of the network systems error message protocol. - */ -struct ns_errstat { -/* statistics related to ns_err packets generated */ - int ns_es_error; /* # of calls to ns_error */ - int ns_es_oldshort; /* no error 'cuz old ip too short */ - int ns_es_oldns_err; /* no error 'cuz old was ns_err */ - int ns_es_outhist[NS_ERR_MAX]; -/* statistics related to input messages processed */ - int ns_es_badcode; /* ns_err_code out of range */ - int ns_es_tooshort; /* packet < IDP_MINLEN */ - int ns_es_checksum; /* bad checksum */ - int ns_es_badlen; /* calculated bound mismatch */ - int ns_es_reflect; /* number of responses */ - int ns_es_inhist[NS_ERR_MAX]; - u_short ns_es_codes[NS_ERR_MAX];/* which error code for outhist - since we might not know all */ -}; - -#ifdef KERNEL -struct ns_errstat ns_errstat; -#endif diff --git a/bsd/netns/ns_if.h b/bsd/netns/ns_if.h deleted file mode 100644 index 5549575e3..000000000 --- a/bsd/netns/ns_if.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1984, 1985, 1986, 1987, 1993 - * 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. - * - * @(#)ns_if.h 8.1 (Berkeley) 6/10/93 - */ - -/* - * Interface address, xerox 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 ns_ifaddr { - struct ifaddr ia_ifa; /* protocol-independent info */ -#define ia_ifp ia_ifa.ifa_ifp -#define ia_flags ia_ifa.ifa_flags - struct ns_ifaddr *ia_next; /* next in list of xerox addresses */ - struct sockaddr_ns ia_addr; /* reserve space for my address */ - struct sockaddr_ns ia_dstaddr; /* space for my broadcast address */ -#define ia_broadaddr ia_dstaddr - struct sockaddr_ns ia_netmask; /* space for my network mask */ -}; - -struct ns_aliasreq { - char ifra_name[IFNAMSIZ]; /* if name, e.g. "en0" */ - struct sockaddr_ns ifra_addr; - struct sockaddr_ns ifra_broadaddr; -#define ifra_dstaddr ifra_broadaddr -}; -/* - * Given a pointer to an ns_ifaddr (ifaddr), - * return a pointer to the addr as a sockadd_ns. - */ - -#define IA_SNS(ia) (&(((struct ns_ifaddr *)(ia))->ia_addr)) - -/* This is not the right place for this but where is? */ -#define ETHERTYPE_NS 0x0600 - -#ifdef NSIP -struct nsip_req { - struct sockaddr rq_ns; /* must be ns format destination */ - struct sockaddr rq_ip; /* must be ip format gateway */ - short rq_flags; -}; -#endif - -#ifdef KERNEL -struct ns_ifaddr *ns_ifaddr; -struct ns_ifaddr *ns_iaonnetof(); -struct ifqueue nsintrq; /* XNS input packet queue */ -#endif diff --git a/bsd/netns/ns_input.c b/bsd/netns/ns_input.c deleted file mode 100644 index 1f85ee06e..000000000 --- a/bsd/netns/ns_input.c +++ /dev/null @@ -1,506 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1984, 1985, 1986, 1987, 1993 - * 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. - * - * @(#)ns_input.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -/* - * NS initialization. - */ -union ns_host ns_thishost; -union ns_host ns_zerohost; -union ns_host ns_broadhost; -union ns_net ns_zeronet; -union ns_net ns_broadnet; -struct sockaddr_ns ns_netmask, ns_hostmask; - -static u_short allones[] = {-1, -1, -1}; - -struct nspcb nspcb; -struct nspcb nsrawpcb; - -struct ifqueue nsintrq; -int nsqmaxlen = IFQ_MAXLEN; - -int idpcksum = 1; -long ns_pexseq; - -ns_init() -{ - extern struct timeval time; - - ns_broadhost = * (union ns_host *) allones; - ns_broadnet = * (union ns_net *) allones; - nspcb.nsp_next = nspcb.nsp_prev = &nspcb; - nsrawpcb.nsp_next = nsrawpcb.nsp_prev = &nsrawpcb; - nsintrq.ifq_maxlen = nsqmaxlen; - ns_pexseq = time.tv_usec; - ns_netmask.sns_len = 6; - ns_netmask.sns_addr.x_net = ns_broadnet; - ns_hostmask.sns_len = 12; - ns_hostmask.sns_addr.x_net = ns_broadnet; - ns_hostmask.sns_addr.x_host = ns_broadhost; -} - -/* - * Idp input routine. Pass to next level. - */ -int nsintr_getpck = 0; -int nsintr_swtch = 0; -nsintr() -{ - register struct idp *idp; - register struct mbuf *m; - register struct nspcb *nsp; - register int i; - int len, s, error; - char oddpacketp; - -next: - /* - * Get next datagram off input queue and get IDP header - * in first mbuf. - */ - s = splimp(); - IF_DEQUEUE(&nsintrq, m); - splx(s); - nsintr_getpck++; - if (m == 0) - return; - if ((m->m_flags & M_EXT || m->m_len < sizeof (struct idp)) && - (m = m_pullup(m, sizeof (struct idp))) == 0) { - idpstat.idps_toosmall++; - goto next; - } - - /* - * Give any raw listeners a crack at the packet - */ - for (nsp = nsrawpcb.nsp_next; nsp != &nsrawpcb; nsp = nsp->nsp_next) { - struct mbuf *m1 = m_copy(m, 0, (int)M_COPYALL); - if (m1) idp_input(m1, nsp); - } - - idp = mtod(m, struct idp *); - len = ntohs(idp->idp_len); - if (oddpacketp = len & 1) { - len++; /* If this packet is of odd length, - preserve garbage byte for checksum */ - } - - /* - * Check that the amount of data in the buffers - * is as at least much as the IDP header would have us expect. - * Trim mbufs if longer than we expect. - * Drop packet if shorter than we expect. - */ - if (m->m_pkthdr.len < len) { - idpstat.idps_tooshort++; - goto bad; - } - if (m->m_pkthdr.len > len) { - if (m->m_len == m->m_pkthdr.len) { - m->m_len = len; - m->m_pkthdr.len = len; - } else - m_adj(m, len - m->m_pkthdr.len); - } - if (idpcksum && ((i = idp->idp_sum)!=0xffff)) { - idp->idp_sum = 0; - if (i != (idp->idp_sum = ns_cksum(m, len))) { - idpstat.idps_badsum++; - idp->idp_sum = i; - if (ns_hosteqnh(ns_thishost, idp->idp_dna.x_host)) - error = NS_ERR_BADSUM; - else - error = NS_ERR_BADSUM_T; - ns_error(m, error, 0); - goto next; - } - } - /* - * Is this a directed broadcast? - */ - if (ns_hosteqnh(ns_broadhost,idp->idp_dna.x_host)) { - if ((!ns_neteq(idp->idp_dna, idp->idp_sna)) && - (!ns_neteqnn(idp->idp_dna.x_net, ns_broadnet)) && - (!ns_neteqnn(idp->idp_sna.x_net, ns_zeronet)) && - (!ns_neteqnn(idp->idp_dna.x_net, ns_zeronet)) ) { - /* - * Look to see if I need to eat this packet. - * Algorithm is to forward all young packets - * and prematurely age any packets which will - * by physically broadcasted. - * Any very old packets eaten without forwarding - * would die anyway. - * - * Suggestion of Bill Nesheim, Cornell U. - */ - if (idp->idp_tc < NS_MAXHOPS) { - idp_forward(m); - goto next; - } - } - /* - * Is this our packet? If not, forward. - */ - } else if (!ns_hosteqnh(ns_thishost,idp->idp_dna.x_host)) { - idp_forward(m); - goto next; - } - /* - * Locate pcb for datagram. - */ - nsp = ns_pcblookup(&idp->idp_sna, idp->idp_dna.x_port, NS_WILDCARD); - /* - * Switch out to protocol's input routine. - */ - nsintr_swtch++; - if (nsp) { - if (oddpacketp) { - m_adj(m, -1); - } - if ((nsp->nsp_flags & NSP_ALL_PACKETS)==0) - switch (idp->idp_pt) { - - case NSPROTO_SPP: - spp_input(m, nsp); - goto next; - - case NSPROTO_ERROR: - ns_err_input(m); - goto next; - } - idp_input(m, nsp); - } else { - ns_error(m, NS_ERR_NOSOCK, 0); - } - goto next; - -bad: - m_freem(m); - goto next; -} - -u_char nsctlerrmap[PRC_NCMDS] = { - ECONNABORTED, ECONNABORTED, 0, 0, - 0, 0, EHOSTDOWN, EHOSTUNREACH, - ENETUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, - EMSGSIZE, 0, 0, 0, - 0, 0, 0, 0 -}; - -int idp_donosocks = 1; - -idp_ctlinput(cmd, arg) - int cmd; - caddr_t arg; -{ - struct ns_addr *ns; - struct nspcb *nsp; - struct ns_errp *errp; - int idp_abort(); - extern struct nspcb *idp_drop(); - int type; - - if (cmd < 0 || cmd > PRC_NCMDS) - return; - if (nsctlerrmap[cmd] == 0) - return; /* XXX */ - type = NS_ERR_UNREACH_HOST; - switch (cmd) { - struct sockaddr_ns *sns; - - case PRC_IFDOWN: - case PRC_HOSTDEAD: - case PRC_HOSTUNREACH: - sns = (struct sockaddr_ns *)arg; - if (sns->sns_family != AF_NS) - return; - ns = &sns->sns_addr; - break; - - default: - errp = (struct ns_errp *)arg; - ns = &errp->ns_err_idp.idp_dna; - type = errp->ns_err_num; - type = ntohs((u_short)type); - } - switch (type) { - - case NS_ERR_UNREACH_HOST: - ns_pcbnotify(ns, (int)nsctlerrmap[cmd], idp_abort, (long)0); - break; - - case NS_ERR_NOSOCK: - nsp = ns_pcblookup(ns, errp->ns_err_idp.idp_sna.x_port, - NS_WILDCARD); - if(nsp && idp_donosocks && ! ns_nullhost(nsp->nsp_faddr)) - (void) idp_drop(nsp, (int)nsctlerrmap[cmd]); - } -} - -int idpprintfs = 0; -int idpforwarding = 1; -/* - * Forward a packet. If some error occurs return the sender - * an error packet. Note we can't always generate a meaningful - * error message because the NS errors don't have a large enough repetoire - * of codes and types. - */ -struct route idp_droute; -struct route idp_sroute; - -idp_forward(m) -struct mbuf *m; -{ - register struct idp *idp = mtod(m, struct idp *); - register int error, type, code; - struct mbuf *mcopy = NULL; - int agedelta = 1; - int flags = NS_FORWARDING; - int ok_there = 0; - int ok_back = 0; - - if (idpprintfs) { - printf("forward: src "); - ns_printhost(&idp->idp_sna); - printf(", dst "); - ns_printhost(&idp->idp_dna); - printf("hop count %d\n", idp->idp_tc); - } - if (idpforwarding == 0) { - /* can't tell difference between net and host */ - type = NS_ERR_UNREACH_HOST, code = 0; - goto senderror; - } - idp->idp_tc++; - if (idp->idp_tc > NS_MAXHOPS) { - type = NS_ERR_TOO_OLD, code = 0; - goto senderror; - } - /* - * Save at most 42 bytes of the packet in case - * we need to generate an NS error message to the src. - */ - mcopy = m_copy(m, 0, imin((int)ntohs(idp->idp_len), 42)); - - if ((ok_there = idp_do_route(&idp->idp_dna,&idp_droute))==0) { - type = NS_ERR_UNREACH_HOST, code = 0; - goto senderror; - } - /* - * Here we think about forwarding broadcast packets, - * so we try to insure that it doesn't go back out - * on the interface it came in on. Also, if we - * are going to physically broadcast this, let us - * age the packet so we can eat it safely the second time around. - */ - if (idp->idp_dna.x_host.c_host[0] & 0x1) { - struct ns_ifaddr *ia = ns_iaonnetof(&idp->idp_dna); - struct ifnet *ifp; - if (ia) { - /* I'm gonna hafta eat this packet */ - agedelta += NS_MAXHOPS - idp->idp_tc; - idp->idp_tc = NS_MAXHOPS; - } - if ((ok_back = idp_do_route(&idp->idp_sna,&idp_sroute))==0) { - /* error = ENETUNREACH; He'll never get it! */ - m_freem(m); - goto cleanup; - } - if (idp_droute.ro_rt && - (ifp=idp_droute.ro_rt->rt_ifp) && - idp_sroute.ro_rt && - (ifp!=idp_sroute.ro_rt->rt_ifp)) { - flags |= NS_ALLOWBROADCAST; - } else { - type = NS_ERR_UNREACH_HOST, code = 0; - goto senderror; - } - } - /* need to adjust checksum */ - if (idp->idp_sum!=0xffff) { - union bytes { - u_char c[4]; - u_short s[2]; - long l; - } x; - register int shift; - x.l = 0; x.c[0] = agedelta; - shift = (((((int)ntohs(idp->idp_len))+1)>>1)-2) & 0xf; - x.l = idp->idp_sum + (x.s[0] << shift); - x.l = x.s[0] + x.s[1]; - x.l = x.s[0] + x.s[1]; - if (x.l==0xffff) idp->idp_sum = 0; else idp->idp_sum = x.l; - } - if ((error = ns_output(m, &idp_droute, flags)) && - (mcopy!=NULL)) { - idp = mtod(mcopy, struct idp *); - type = NS_ERR_UNSPEC_T, code = 0; - switch (error) { - - case ENETUNREACH: - case EHOSTDOWN: - case EHOSTUNREACH: - case ENETDOWN: - case EPERM: - type = NS_ERR_UNREACH_HOST; - break; - - case EMSGSIZE: - type = NS_ERR_TOO_BIG; - code = 576; /* too hard to figure out mtu here */ - break; - - case ENOBUFS: - type = NS_ERR_UNSPEC_T; - break; - } - mcopy = NULL; - senderror: - ns_error(m, type, code); - } -cleanup: - if (ok_there) - idp_undo_route(&idp_droute); - if (ok_back) - idp_undo_route(&idp_sroute); - if (mcopy != NULL) - m_freem(mcopy); -} - -idp_do_route(src, ro) -struct ns_addr *src; -struct route *ro; -{ - - struct sockaddr_ns *dst; - - bzero((caddr_t)ro, sizeof (*ro)); - dst = (struct sockaddr_ns *)&ro->ro_dst; - - dst->sns_len = sizeof(*dst); - dst->sns_family = AF_NS; - dst->sns_addr = *src; - dst->sns_addr.x_port = 0; - rtalloc(ro); - if (ro->ro_rt == 0 || ro->ro_rt->rt_ifp == 0) { - return (0); - } - ro->ro_rt->rt_use++; - return (1); -} - -idp_undo_route(ro) -register struct route *ro; -{ - if (ro->ro_rt) {RTFREE(ro->ro_rt);} -} - -ns_watch_output(m, ifp) -struct mbuf *m; -struct ifnet *ifp; -{ - register struct nspcb *nsp; - register struct ifaddr *ifa; - /* - * Give any raw listeners a crack at the packet - */ - for (nsp = nsrawpcb.nsp_next; nsp != &nsrawpcb; nsp = nsp->nsp_next) { - struct mbuf *m0 = m_copy(m, 0, (int)M_COPYALL); - if (m0) { - register struct idp *idp; - - M_PREPEND(m0, sizeof (*idp), M_DONTWAIT); - if (m0 == NULL) - continue; - idp = mtod(m0, struct idp *); - idp->idp_sna.x_net = ns_zeronet; - idp->idp_sna.x_host = ns_thishost; - if (ifp && (ifp->if_flags & IFF_POINTOPOINT)) - for(ifa = ifp->if_addrlist; ifa; - ifa = ifa->ifa_next) { - if (ifa->ifa_addr->sa_family==AF_NS) { - idp->idp_sna = IA_SNS(ifa)->sns_addr; - break; - } - } - idp->idp_len = ntohl(m0->m_pkthdr.len); - idp_input(m0, nsp); - } - } -} diff --git a/bsd/netns/ns_ip.c b/bsd/netns/ns_ip.c deleted file mode 100644 index cd093a377..000000000 --- a/bsd/netns/ns_ip.c +++ /dev/null @@ -1,461 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1984, 1985, 1986, 1987, 1993 - * 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. - * - * @(#)ns_ip.c 8.1 (Berkeley) 6/10/93 - */ - -/* - * Software interface driver for encapsulating ns in ip. - */ - -#ifdef NSIP -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -struct ifnet_en { - struct ifnet ifen_ifnet; - struct route ifen_route; - struct in_addr ifen_src; - struct in_addr ifen_dst; - struct ifnet_en *ifen_next; -}; - -int nsipoutput(), nsipioctl(), nsipstart(); -#define LOMTU (1024+512); - -struct ifnet nsipif; -struct ifnet_en *nsip_list; /* list of all hosts and gateways or - broadcast addrs */ - -struct ifnet_en * -nsipattach() -{ - register struct ifnet_en *m; - register struct ifnet *ifp; - - if (nsipif.if_mtu == 0) { - ifp = &nsipif; - ifp->if_name = "nsip"; - ifp->if_mtu = LOMTU; - ifp->if_ioctl = nsipioctl; - ifp->if_output = nsipoutput; - ifp->if_start = nsipstart; - ifp->if_flags = IFF_POINTOPOINT; - } - - MALLOC((m), struct ifnet_en *, sizeof(*m), M_PCB, M_NOWAIT); - if (m == NULL) return (NULL); - m->ifen_next = nsip_list; - nsip_list = m; - ifp = &m->ifen_ifnet; - - ifp->if_name = "nsip"; - ifp->if_mtu = LOMTU; - ifp->if_ioctl = nsipioctl; - ifp->if_output = nsipoutput; - ifp->if_start = nsipstart; - ifp->if_flags = IFF_POINTOPOINT; - ifp->if_unit = nsipif.if_unit++; - if_attach(ifp); - - return (m); -} - - -/* - * Process an ioctl request. - */ -/* ARGSUSED */ -nsipioctl(ifp, cmd, data) - register struct ifnet *ifp; - int cmd; - caddr_t data; -{ - int error = 0; - struct ifreq *ifr; - - switch (cmd) { - - case SIOCSIFADDR: - ifp->if_flags |= IFF_UP; - /* fall into: */ - - case SIOCSIFDSTADDR: - /* - * Everything else is done at a higher level. - */ - break; - - case SIOCSIFFLAGS: - ifr = (struct ifreq *)data; - if ((ifr->ifr_flags & IFF_UP) == 0) - error = nsip_free(ifp); - - - default: - error = EINVAL; - } - return (error); -} - -struct mbuf *nsip_badlen; -struct mbuf *nsip_lastin; -int nsip_hold_input; - -idpip_input(m, ifp) - register struct mbuf *m; - struct ifnet *ifp; -{ - register struct ip *ip; - register struct idp *idp; - register struct ifqueue *ifq = &nsintrq; - int len, s; - - if (nsip_hold_input) { - if (nsip_lastin) { - m_freem(nsip_lastin); - } - nsip_lastin = m_copym(m, 0, (int)M_COPYALL, M_DONTWAIT); - } - /* - * Get IP and IDP header together in first mbuf. - */ - nsipif.if_ipackets++; - s = sizeof (struct ip) + sizeof (struct idp); - if (((m->m_flags & M_EXT) || m->m_len < s) && - (m = m_pullup(m, s)) == 0) { - nsipif.if_ierrors++; - return; - } - ip = mtod(m, struct ip *); - if (ip->ip_hl > (sizeof (struct ip) >> 2)) { - ip_stripoptions(m, (struct mbuf *)0); - if (m->m_len < s) { - if ((m = m_pullup(m, s)) == 0) { - nsipif.if_ierrors++; - return; - } - ip = mtod(m, struct ip *); - } - } - - /* - * Make mbuf data length reflect IDP length. - * If not enough data to reflect IDP length, drop. - */ - m->m_data += sizeof (struct ip); - m->m_len -= sizeof (struct ip); - m->m_pkthdr.len -= sizeof (struct ip); - idp = mtod(m, struct idp *); - len = ntohs(idp->idp_len); - if (len & 1) len++; /* Preserve Garbage Byte */ - if (ip->ip_len != len) { - if (len > ip->ip_len) { - nsipif.if_ierrors++; - if (nsip_badlen) m_freem(nsip_badlen); - nsip_badlen = m; - return; - } - /* Any extra will be trimmed off by the NS routines */ - } - - /* - * Place interface pointer before the data - * for the receiving protocol. - */ - m->m_pkthdr.rcvif = ifp; - /* - * Deliver to NS - */ - s = splimp(); - if (IF_QFULL(ifq)) { - IF_DROP(ifq); -bad: - m_freem(m); - splx(s); - return; - } - IF_ENQUEUE(ifq, m); - schednetisr(NETISR_NS); - splx(s); - return; -} - -/* ARGSUSED */ -nsipoutput(ifn, m, dst) - struct ifnet_en *ifn; - register struct mbuf *m; - struct sockaddr *dst; -{ - - register struct ip *ip; - register struct route *ro = &(ifn->ifen_route); - register int len = 0; - register struct idp *idp = mtod(m, struct idp *); - int error; - - ifn->ifen_ifnet.if_opackets++; - nsipif.if_opackets++; - - - /* - * Calculate data length and make space - * for IP header. - */ - len = ntohs(idp->idp_len); - if (len & 1) len++; /* Preserve Garbage Byte */ - /* following clause not necessary on vax */ - if (3 & (int)m->m_data) { - /* force longword alignment of ip hdr */ - struct mbuf *m0 = m_gethdr(MT_HEADER, M_DONTWAIT); - if (m0 == 0) { - m_freem(m); - return (ENOBUFS); - } - MH_ALIGN(m0, sizeof (struct ip)); - m0->m_flags = m->m_flags & M_COPYFLAGS; - m0->m_next = m; - m0->m_len = sizeof (struct ip); - m0->m_pkthdr.len = m0->m_len + m->m_len; - m->m_flags &= ~M_PKTHDR; - } else { - M_PREPEND(m, sizeof (struct ip), M_DONTWAIT); - if (m == 0) - return (ENOBUFS); - } - /* - * Fill in IP header. - */ - ip = mtod(m, struct ip *); - *(long *)ip = 0; - ip->ip_p = IPPROTO_IDP; - ip->ip_src = ifn->ifen_src; - ip->ip_dst = ifn->ifen_dst; - ip->ip_len = (u_short)len + sizeof (struct ip); - ip->ip_ttl = MAXTTL; - - /* - * Output final datagram. - */ - error = (ip_output(m, (struct mbuf *)0, ro, SO_BROADCAST, NULL)); - if (error) { - ifn->ifen_ifnet.if_oerrors++; - ifn->ifen_ifnet.if_ierrors = error; - } - return (error); -bad: - m_freem(m); - return (ENETUNREACH); -} - -nsipstart(ifp) -struct ifnet *ifp; -{ - panic("nsip_start called\n"); -} - -struct ifreq ifr = {"nsip0"}; - -nsip_route(m) - register struct mbuf *m; -{ - register struct nsip_req *rq = mtod(m, struct nsip_req *); - struct sockaddr_ns *ns_dst = (struct sockaddr_ns *)&rq->rq_ns; - struct sockaddr_in *ip_dst = (struct sockaddr_in *)&rq->rq_ip; - struct route ro; - struct ifnet_en *ifn; - struct sockaddr_in *src; - - /* - * First, make sure we already have an ns address: - */ - if (ns_hosteqnh(ns_thishost, ns_zerohost)) - return (EADDRNOTAVAIL); - /* - * Now, determine if we can get to the destination - */ - bzero((caddr_t)&ro, sizeof (ro)); - ro.ro_dst = *(struct sockaddr *)ip_dst; - rtalloc(&ro); - if (ro.ro_rt == 0 || ro.ro_rt->rt_ifp == 0) { - return (ENETUNREACH); - } - - /* - * And see how he's going to get back to us: - * i.e., what return ip address do we use? - */ - { - register struct in_ifaddr *ia; - struct ifnet *ifp = ro.ro_rt->rt_ifp; - - for (ia = in_ifaddr; ia; ia = ia->ia_next) - if (ia->ia_ifp == ifp) - break; - if (ia == 0) - ia = in_ifaddr; - if (ia == 0) { - RTFREE(ro.ro_rt); - return (EADDRNOTAVAIL); - } - src = (struct sockaddr_in *)&ia->ia_addr; - } - - /* - * Is there a free (pseudo-)interface or space? - */ - for (ifn = nsip_list; ifn; ifn = ifn->ifen_next) { - if ((ifn->ifen_ifnet.if_flags & IFF_UP) == 0) - break; - } - if (ifn == NULL) - ifn = nsipattach(); - if (ifn == NULL) { - RTFREE(ro.ro_rt); - return (ENOBUFS); - } - ifn->ifen_route = ro; - ifn->ifen_dst = ip_dst->sin_addr; - ifn->ifen_src = src->sin_addr; - - /* - * now configure this as a point to point link - */ - ifr.ifr_name[4] = '0' + nsipif.if_unit - 1; - ifr.ifr_dstaddr = * (struct sockaddr *) ns_dst; - (void)ns_control((struct socket *)0, (int)SIOCSIFDSTADDR, (caddr_t)&ifr, - (struct ifnet *)ifn); - satons_addr(ifr.ifr_addr).x_host = ns_thishost; - return (ns_control((struct socket *)0, (int)SIOCSIFADDR, (caddr_t)&ifr, - (struct ifnet *)ifn)); -} - -nsip_free(ifp) -struct ifnet *ifp; -{ - register struct ifnet_en *ifn = (struct ifnet_en *)ifp; - struct route *ro = & ifn->ifen_route; - - if (ro->ro_rt) { - RTFREE(ro->ro_rt); - ro->ro_rt = 0; - } - ifp->if_flags &= ~IFF_UP; - return (0); -} - -nsip_ctlinput(cmd, sa) - int cmd; - struct sockaddr *sa; -{ - extern u_char inetctlerrmap[]; - struct sockaddr_in *sin; - int in_rtchange(); - - if ((unsigned)cmd >= PRC_NCMDS) - return; - if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK) - return; - sin = (struct sockaddr_in *)sa; - if (sin->sin_addr.s_addr == INADDR_ANY) - return; - - switch (cmd) { - - case PRC_ROUTEDEAD: - case PRC_REDIRECT_NET: - case PRC_REDIRECT_HOST: - case PRC_REDIRECT_TOSNET: - case PRC_REDIRECT_TOSHOST: - nsip_rtchange(&sin->sin_addr); - break; - } -} - -nsip_rtchange(dst) - register struct in_addr *dst; -{ - register struct ifnet_en *ifn; - - for (ifn = nsip_list; ifn; ifn = ifn->ifen_next) { - if (ifn->ifen_dst.s_addr == dst->s_addr && - ifn->ifen_route.ro_rt) { - RTFREE(ifn->ifen_route.ro_rt); - ifn->ifen_route.ro_rt = 0; - } - } -} -#endif diff --git a/bsd/netns/ns_output.c b/bsd/netns/ns_output.c deleted file mode 100644 index 276de6c0a..000000000 --- a/bsd/netns/ns_output.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1984, 1985, 1986, 1987, 1993 - * 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. - * - * @(#)ns_output.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#ifdef vax -#include -#endif -int ns_hold_output = 0; -int ns_copy_output = 0; -int ns_output_cnt = 0; -struct mbuf *ns_lastout; - -ns_output(m0, ro, flags) - struct mbuf *m0; - struct route *ro; - int flags; -{ - register struct idp *idp = mtod(m0, struct idp *); - register struct ifnet *ifp = 0; - int error = 0; - struct route idproute; - struct sockaddr_ns *dst; - extern int idpcksum; - - if (ns_hold_output) { - if (ns_lastout) { - (void)m_free(ns_lastout); - } - ns_lastout = m_copy(m0, 0, (int)M_COPYALL); - } - /* - * Route packet. - */ - if (ro == 0) { - ro = &idproute; - bzero((caddr_t)ro, sizeof (*ro)); - } - dst = (struct sockaddr_ns *)&ro->ro_dst; - if (ro->ro_rt == 0) { - dst->sns_family = AF_NS; - dst->sns_len = sizeof (*dst); - dst->sns_addr = idp->idp_dna; - dst->sns_addr.x_port = 0; - /* - * If routing to interface only, - * short circuit routing lookup. - */ - if (flags & NS_ROUTETOIF) { - struct ns_ifaddr *ia = ns_iaonnetof(&idp->idp_dna); - - if (ia == 0) { - error = ENETUNREACH; - goto bad; - } - ifp = ia->ia_ifp; - goto gotif; - } - rtalloc(ro); - } else if ((ro->ro_rt->rt_flags & RTF_UP) == 0) { - /* - * The old route has gone away; try for a new one. - */ - rtfree(ro->ro_rt); - ro->ro_rt = NULL; - rtalloc(ro); - } - if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) { - error = ENETUNREACH; - goto bad; - } - ro->ro_rt->rt_use++; - if (ro->ro_rt->rt_flags & (RTF_GATEWAY|RTF_HOST)) - dst = (struct sockaddr_ns *)ro->ro_rt->rt_gateway; -gotif: - - /* - * Look for multicast addresses and - * and verify user is allowed to send - * such a packet. - */ - if (dst->sns_addr.x_host.c_host[0]&1) { - if ((ifp->if_flags & IFF_BROADCAST) == 0) { - error = EADDRNOTAVAIL; - goto bad; - } - if ((flags & NS_ALLOWBROADCAST) == 0) { - error = EACCES; - goto bad; - } - } - - if (htons(idp->idp_len) <= ifp->if_mtu) { - ns_output_cnt++; - if (ns_copy_output) { - ns_watch_output(m0, ifp); - } - error = (*ifp->if_output)(ifp, m0, - (struct sockaddr *)dst, ro->ro_rt); - goto done; - } else error = EMSGSIZE; - - -bad: - if (ns_copy_output) { - ns_watch_output(m0, ifp); - } - m_freem(m0); -done: - if (ro == &idproute && (flags & NS_ROUTETOIF) == 0 && ro->ro_rt) { - RTFREE(ro->ro_rt); - ro->ro_rt = 0; - } - return (error); -} diff --git a/bsd/netns/ns_pcb.c b/bsd/netns/ns_pcb.c deleted file mode 100644 index c02bb6a5c..000000000 --- a/bsd/netns/ns_pcb.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1984, 1985, 1986, 1987, 1993 - * 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. - * - * @(#)ns_pcb.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -struct ns_addr zerons_addr; - -ns_pcballoc(so, head) - struct socket *so; - struct nspcb *head; -{ - struct mbuf *m; - register struct nspcb *nsp; - - m = m_getclr(M_DONTWAIT, MT_PCB); - if (m == NULL) - return (ENOBUFS); - nsp = mtod(m, struct nspcb *); - nsp->nsp_socket = so; - insque(nsp, head); - so->so_pcb = (caddr_t)nsp; - return (0); -} - -ns_pcbbind(nsp, nam) - register struct nspcb *nsp; - struct mbuf *nam; -{ - register struct sockaddr_ns *sns; - u_short lport = 0; - - if (nsp->nsp_lport || !ns_nullhost(nsp->nsp_laddr)) - return (EINVAL); - if (nam == 0) - goto noname; - sns = mtod(nam, struct sockaddr_ns *); - if (nam->m_len != sizeof (*sns)) - return (EINVAL); - if (!ns_nullhost(sns->sns_addr)) { - int tport = sns->sns_port; - - sns->sns_port = 0; /* yech... */ - if (ifa_ifwithaddr((struct sockaddr *)sns) == 0) - return (EADDRNOTAVAIL); - sns->sns_port = tport; - } - lport = sns->sns_port; - if (lport) { - u_short aport = ntohs(lport); - - if (aport < NSPORT_RESERVED && - (nsp->nsp_socket->so_state & SS_PRIV) == 0) - return (EACCES); - if (ns_pcblookup(&zerons_addr, lport, 0)) - return (EADDRINUSE); - } - nsp->nsp_laddr = sns->sns_addr; -noname: - if (lport == 0) - do { - if (nspcb.nsp_lport++ < NSPORT_RESERVED) - nspcb.nsp_lport = NSPORT_RESERVED; - lport = htons(nspcb.nsp_lport); - } while (ns_pcblookup(&zerons_addr, lport, 0)); - nsp->nsp_lport = lport; - return (0); -} - -/* - * Connect from a socket to a specified address. - * Both address and port must be specified in argument sns. - * If don't have a local address for this socket yet, - * then pick one. - */ -ns_pcbconnect(nsp, nam) - struct nspcb *nsp; - struct mbuf *nam; -{ - struct ns_ifaddr *ia; - register struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); - register struct ns_addr *dst; - register struct route *ro; - struct ifnet *ifp; - - if (nam->m_len != sizeof (*sns)) - return (EINVAL); - if (sns->sns_family != AF_NS) - return (EAFNOSUPPORT); - if (sns->sns_port==0 || ns_nullhost(sns->sns_addr)) - return (EADDRNOTAVAIL); - /* - * If we haven't bound which network number to use as ours, - * we will use the number of the outgoing interface. - * This depends on having done a routing lookup, which - * we will probably have to do anyway, so we might - * as well do it now. On the other hand if we are - * sending to multiple destinations we may have already - * done the lookup, so see if we can use the route - * from before. In any case, we only - * chose a port number once, even if sending to multiple - * destinations. - */ - ro = &nsp->nsp_route; - dst = &satons_addr(ro->ro_dst); - if (nsp->nsp_socket->so_options & SO_DONTROUTE) - goto flush; - if (!ns_neteq(nsp->nsp_lastdst, sns->sns_addr)) - goto flush; - if (!ns_hosteq(nsp->nsp_lastdst, sns->sns_addr)) { - if (ro->ro_rt && ! (ro->ro_rt->rt_flags & RTF_HOST)) { - /* can patch route to avoid rtalloc */ - *dst = sns->sns_addr; - } else { - flush: - if (ro->ro_rt) - RTFREE(ro->ro_rt); - ro->ro_rt = (struct rtentry *)0; - nsp->nsp_laddr.x_net = ns_zeronet; - } - }/* else cached route is ok; do nothing */ - nsp->nsp_lastdst = sns->sns_addr; - if ((nsp->nsp_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_NS; - ro->ro_dst.sa_len = sizeof(ro->ro_dst); - *dst = sns->sns_addr; - dst->x_port = 0; - rtalloc(ro); - } - if (ns_neteqnn(nsp->nsp_laddr.x_net, ns_zeronet)) { - /* - * If route is known or can be allocated now, - * our src addr is taken from the i/f, else punt. - */ - - ia = (struct ns_ifaddr *)0; - /* - * If we found a route, use the address - * corresponding to the outgoing interface - */ - if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp)) - for (ia = ns_ifaddr; ia; ia = ia->ia_next) - if (ia->ia_ifp == ifp) - break; - if (ia == 0) { - u_short fport = sns->sns_addr.x_port; - sns->sns_addr.x_port = 0; - ia = (struct ns_ifaddr *) - ifa_ifwithdstaddr((struct sockaddr *)sns); - sns->sns_addr.x_port = fport; - if (ia == 0) - ia = ns_iaonnetof(&sns->sns_addr); - if (ia == 0) - ia = ns_ifaddr; - if (ia == 0) - return (EADDRNOTAVAIL); - } - nsp->nsp_laddr.x_net = satons_addr(ia->ia_addr).x_net; - } - if (ns_pcblookup(&sns->sns_addr, nsp->nsp_lport, 0)) - return (EADDRINUSE); - if (ns_nullhost(nsp->nsp_laddr)) { - if (nsp->nsp_lport == 0) - (void) ns_pcbbind(nsp, (struct mbuf *)0); - nsp->nsp_laddr.x_host = ns_thishost; - } - nsp->nsp_faddr = sns->sns_addr; - /* Includes nsp->nsp_fport = sns->sns_port; */ - return (0); -} - -ns_pcbdisconnect(nsp) - struct nspcb *nsp; -{ - - nsp->nsp_faddr = zerons_addr; - if (nsp->nsp_socket->so_state & SS_NOFDREF) - ns_pcbdetach(nsp); -} - -ns_pcbdetach(nsp) - struct nspcb *nsp; -{ - struct socket *so = nsp->nsp_socket; - - so->so_pcb = 0; - sofree(so); - if (nsp->nsp_route.ro_rt) - rtfree(nsp->nsp_route.ro_rt); - remque(nsp); - (void) m_free(dtom(nsp)); -} - -ns_setsockaddr(nsp, nam) - register struct nspcb *nsp; - struct mbuf *nam; -{ - register struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); - - nam->m_len = sizeof (*sns); - sns = mtod(nam, struct sockaddr_ns *); - bzero((caddr_t)sns, sizeof (*sns)); - sns->sns_len = sizeof(*sns); - sns->sns_family = AF_NS; - sns->sns_addr = nsp->nsp_laddr; -} - -ns_setpeeraddr(nsp, nam) - register struct nspcb *nsp; - struct mbuf *nam; -{ - register struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); - - nam->m_len = sizeof (*sns); - sns = mtod(nam, struct sockaddr_ns *); - bzero((caddr_t)sns, sizeof (*sns)); - sns->sns_len = sizeof(*sns); - sns->sns_family = AF_NS; - sns->sns_addr = nsp->nsp_faddr; -} - -/* - * Pass some notification to all connections of a protocol - * associated with address dst. Call the - * protocol specific routine to handle each connection. - * Also pass an extra paramter via the nspcb. (which may in fact - * be a parameter list!) - */ -ns_pcbnotify(dst, errno, notify, param) - register struct ns_addr *dst; - long param; - int errno, (*notify)(); -{ - register struct nspcb *nsp, *oinp; - int s = splimp(); - - for (nsp = (&nspcb)->nsp_next; nsp != (&nspcb);) { - if (!ns_hosteq(*dst,nsp->nsp_faddr)) { - next: - nsp = nsp->nsp_next; - continue; - } - if (nsp->nsp_socket == 0) - goto next; - if (errno) - nsp->nsp_socket->so_error = errno; - oinp = nsp; - nsp = nsp->nsp_next; - oinp->nsp_notify_param = param; - (*notify)(oinp); - } - splx(s); -} - -#ifdef notdef -/* - * After a routing change, flush old routing - * and allocate a (hopefully) better one. - */ -ns_rtchange(nsp) - struct nspcb *nsp; -{ - if (nsp->nsp_route.ro_rt) { - rtfree(nsp->nsp_route.ro_rt); - nsp->nsp_route.ro_rt = 0; - /* - * A new route can be allocated the next time - * output is attempted. - */ - } - /* SHOULD NOTIFY HIGHER-LEVEL PROTOCOLS */ -} -#endif - -struct nspcb * -ns_pcblookup(faddr, lport, wildp) - struct ns_addr *faddr; - u_short lport; -{ - register struct nspcb *nsp, *match = 0; - int matchwild = 3, wildcard; - u_short fport; - - fport = faddr->x_port; - for (nsp = (&nspcb)->nsp_next; nsp != (&nspcb); nsp = nsp->nsp_next) { - if (nsp->nsp_lport != lport) - continue; - wildcard = 0; - if (ns_nullhost(nsp->nsp_faddr)) { - if (!ns_nullhost(*faddr)) - wildcard++; - } else { - if (ns_nullhost(*faddr)) - wildcard++; - else { - if (!ns_hosteq(nsp->nsp_faddr, *faddr)) - continue; - if (nsp->nsp_fport != fport) { - if (nsp->nsp_fport != 0) - continue; - else - wildcard++; - } - } - } - if (wildcard && wildp==0) - continue; - if (wildcard < matchwild) { - match = nsp; - matchwild = wildcard; - if (wildcard == 0) - break; - } - } - return (match); -} diff --git a/bsd/netns/ns_pcb.h b/bsd/netns/ns_pcb.h deleted file mode 100644 index 47b2d62e6..000000000 --- a/bsd/netns/ns_pcb.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1984, 1985, 1986, 1987, 1993 - * 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. - * - * @(#)ns_pcb.h 8.1 (Berkeley) 6/10/93 - */ - -/* - * Ns protocol interface control block. - */ -struct nspcb { - struct nspcb *nsp_next; /* doubly linked list */ - struct nspcb *nsp_prev; - struct nspcb *nsp_head; - struct socket *nsp_socket; /* back pointer to socket */ - struct ns_addr nsp_faddr; /* destination address */ - struct ns_addr nsp_laddr; /* socket's address */ - caddr_t nsp_pcb; /* protocol specific stuff */ - struct route nsp_route; /* routing information */ - struct ns_addr nsp_lastdst; /* validate cached route for dg socks*/ - long nsp_notify_param; /* extra info passed via ns_pcbnotify*/ - short nsp_flags; - u_char nsp_dpt; /* default packet type for idp_output*/ - u_char nsp_rpt; /* last received packet type by - idp_input() */ -}; - -/* possible flags */ - -#define NSP_IN_ABORT 0x1 /* calling abort through socket */ -#define NSP_RAWIN 0x2 /* show headers on input */ -#define NSP_RAWOUT 0x4 /* show header on output */ -#define NSP_ALL_PACKETS 0x8 /* Turn off higher proto processing */ - -#define NS_WILDCARD 1 - -#define nsp_lport nsp_laddr.x_port -#define nsp_fport nsp_faddr.x_port - -#define sotonspcb(so) ((struct nspcb *)((so)->so_pcb)) - -/* - * Nominal space allocated to a ns socket. - */ -#define NSSNDQ 2048 -#define NSRCVQ 2048 - - -#ifdef KERNEL -struct nspcb nspcb; /* head of list */ -struct nspcb *ns_pcblookup(); -#endif diff --git a/bsd/netns/ns_proto.c b/bsd/netns/ns_proto.c deleted file mode 100644 index 04068d49c..000000000 --- a/bsd/netns/ns_proto.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1984, 1985, 1986, 1987, 1993 - * 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. - * - * @(#)ns_proto.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include - -#include - -#include - -/* - * NS protocol family: IDP, ERR, PE, SPP, ROUTE. - */ -int ns_init(); -int idp_input(), idp_output(), idp_ctlinput(), idp_usrreq(); -int idp_raw_usrreq(), idp_ctloutput(); -int spp_input(), spp_ctlinput(); -int spp_usrreq(), spp_usrreq_sp(), spp_ctloutput(); -int spp_init(), spp_fasttimo(), spp_slowtimo(); -extern int raw_usrreq(); - -extern struct domain nsdomain; - -struct protosw nssw[] = { -{ 0, &nsdomain, 0, 0, - 0, idp_output, 0, 0, - 0, - ns_init, 0, 0, 0, -}, -{ SOCK_DGRAM, &nsdomain, 0, PR_ATOMIC|PR_ADDR, - 0, 0, idp_ctlinput, idp_ctloutput, - idp_usrreq, - 0, 0, 0, 0, -}, -{ SOCK_STREAM, &nsdomain, NSPROTO_SPP, PR_CONNREQUIRED|PR_WANTRCVD, - spp_input, 0, spp_ctlinput, spp_ctloutput, - spp_usrreq, - spp_init, spp_fasttimo, spp_slowtimo, 0, -}, -{ SOCK_SEQPACKET,&nsdomain, NSPROTO_SPP, PR_CONNREQUIRED|PR_WANTRCVD|PR_ATOMIC, - spp_input, 0, spp_ctlinput, spp_ctloutput, - spp_usrreq_sp, - 0, 0, 0, 0, -}, -{ SOCK_RAW, &nsdomain, NSPROTO_RAW, PR_ATOMIC|PR_ADDR, - idp_input, idp_output, 0, idp_ctloutput, - idp_raw_usrreq, - 0, 0, 0, 0, -}, -{ SOCK_RAW, &nsdomain, NSPROTO_ERROR, PR_ATOMIC|PR_ADDR, - idp_ctlinput, idp_output, 0, idp_ctloutput, - idp_raw_usrreq, - 0, 0, 0, 0, -}, -}; - -#if 0 -/*need to look at other init functions, use net_add_proto() to assure - things are init'd properly*/ -LINK_PROTOS(nssw); -#endif - -struct domain nsdomain = - { AF_NS, "network systems", link_nssw_protos, 0, 0, - nssw, 0, - rn_inithead, 16, sizeof(struct sockaddr_ns)}; - diff --git a/bsd/netns/sp.h b/bsd/netns/sp.h deleted file mode 100644 index e756f5fc8..000000000 --- a/bsd/netns/sp.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1984, 1985, 1986, 1987, 1993 - * 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. - * - * @(#)sp.h 8.1 (Berkeley) 6/10/93 - */ - -/* - * Definitions for Xerox NS style sequenced packet protocol - */ - -struct sphdr { - u_char sp_cc; /* connection control */ - u_char sp_dt; /* datastream type */ -#define SP_SP 0x80 /* system packet */ -#define SP_SA 0x40 /* send acknowledgement */ -#define SP_OB 0x20 /* attention (out of band data) */ -#define SP_EM 0x10 /* end of message */ - u_short sp_sid; /* source connection identifier */ - u_short sp_did; /* destination connection identifier */ - u_short sp_seq; /* sequence number */ - u_short sp_ack; /* acknowledge number */ - u_short sp_alo; /* allocation number */ -}; diff --git a/bsd/netns/spidp.h b/bsd/netns/spidp.h deleted file mode 100644 index 8967590a9..000000000 --- a/bsd/netns/spidp.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1984, 1985, 1986, 1987, 1993 - * 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. - * - * @(#)spidp.h 8.1 (Berkeley) 6/10/93 - */ - -/* - * Definitions for NS(tm) Internet Datagram Protocol - * containing a Sequenced Packet Protocol packet. - */ -struct spidp { - struct idp si_i; - struct sphdr si_s; -}; -struct spidp_q { - struct spidp_q *si_next; - struct spidp_q *si_prev; -}; -#define SI(x) ((struct spidp *)x) -#define si_sum si_i.idp_sum -#define si_len si_i.idp_len -#define si_tc si_i.idp_tc -#define si_pt si_i.idp_pt -#define si_dna si_i.idp_dna -#define si_sna si_i.idp_sna -#define si_sport si_i.idp_sna.x_port -#define si_cc si_s.sp_cc -#define si_dt si_s.sp_dt -#define si_sid si_s.sp_sid -#define si_did si_s.sp_did -#define si_seq si_s.sp_seq -#define si_ack si_s.sp_ack -#define si_alo si_s.sp_alo diff --git a/bsd/netns/spp_debug.c b/bsd/netns/spp_debug.c deleted file mode 100644 index 52e025464..000000000 --- a/bsd/netns/spp_debug.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1984, 1985, 1986, 1987, 1993 - * 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. - * - * @(#)spp_debug.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#define SPPTIMERS -#include -#include -#define SANAMES -#include - -int sppconsdebug = 0; -/* - * spp debug routines - */ -spp_trace(act, ostate, sp, si, req) - short act; - u_char ostate; - struct sppcb *sp; - struct spidp *si; - int req; -{ -#ifdef INET -#ifdef TCPDEBUG - u_short seq, ack, len, alo; - unsigned long iptime(); - int flags; - struct spp_debug *sd = &spp_debug[spp_debx++]; - extern char *prurequests[]; - extern char *sanames[]; - extern char *tcpstates[]; - extern char *spptimers[]; - - if (spp_debx == SPP_NDEBUG) - spp_debx = 0; - sd->sd_time = iptime(); - sd->sd_act = act; - sd->sd_ostate = ostate; - sd->sd_cb = (caddr_t)sp; - if (sp) - sd->sd_sp = *sp; - else - bzero((caddr_t)&sd->sd_sp, sizeof (*sp)); - if (si) - sd->sd_si = *si; - else - bzero((caddr_t)&sd->sd_si, sizeof (*si)); - sd->sd_req = req; - if (sppconsdebug == 0) - return; - if (ostate >= TCP_NSTATES) ostate = 0; - if (act >= SA_DROP) act = SA_DROP; - if (sp) - printf("%x %s:", sp, tcpstates[ostate]); - else - printf("???????? "); - printf("%s ", sanames[act]); - switch (act) { - - case SA_RESPOND: - case SA_INPUT: - case SA_OUTPUT: - case SA_DROP: - if (si == 0) - break; - seq = si->si_seq; - ack = si->si_ack; - alo = si->si_alo; - len = si->si_len; - if (act == SA_OUTPUT) { - seq = ntohs(seq); - ack = ntohs(ack); - alo = ntohs(alo); - len = ntohs(len); - } -#ifndef lint -#define p1(f) { printf("%s = %x, ", "f", f); } - p1(seq); p1(ack); p1(alo); p1(len); -#endif - flags = si->si_cc; - if (flags) { - char *cp = "<"; -#ifndef lint -#define pf(f) { if (flags&SP_/**/f) { printf("%s%s", cp, "f"); cp = ","; } } - pf(SP); pf(SA); pf(OB); pf(EM); -#else - cp = cp; -#endif - printf(">"); - } -#ifndef lint -#define p2(f) { printf("%s = %x, ", "f", si->si_/**/f); } - p2(sid);p2(did);p2(dt);p2(pt); -#endif - ns_printhost(&si->si_sna); - ns_printhost(&si->si_dna); - - if (act==SA_RESPOND) { - printf("idp_len = %x, ", - ((struct idp *)si)->idp_len); - } - break; - - case SA_USER: - printf("%s", prurequests[req&0xff]); - if ((req & 0xff) == PRU_SLOWTIMO) - printf("<%s>", spptimers[req>>8]); - break; - } - if (sp) - printf(" -> %s", tcpstates[sp->s_state]); - /* print out internal state of sp !?! */ - printf("\n"); - if (sp == 0) - return; -#ifndef lint -#define p3(f) { printf("%s = %x, ", "f", sp->s_/**/f); } - printf("\t"); p3(rack);p3(ralo);p3(smax);p3(flags); printf("\n"); -#endif -#endif -#endif -} diff --git a/bsd/netns/spp_debug.h b/bsd/netns/spp_debug.h deleted file mode 100644 index 8e665c622..000000000 --- a/bsd/netns/spp_debug.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1984, 1985, 1986, 1987, 1993 - * 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. - * - * @(#)spp_debug.h 8.1 (Berkeley) 6/10/93 - */ - -struct spp_debug { - u_long sd_time; - short sd_act; - short sd_ostate; - caddr_t sd_cb; - short sd_req; - struct spidp sd_si; - struct sppcb sd_sp; -}; - -#define SA_INPUT 0 -#define SA_OUTPUT 1 -#define SA_USER 2 -#define SA_RESPOND 3 -#define SA_DROP 4 - -#ifdef SANAMES -char *sanames[] = - { "input", "output", "user", "respond", "drop" }; -#endif - -#define SPP_NDEBUG 100 -struct spp_debug spp_debug[SPP_NDEBUG]; -int spp_debx; diff --git a/bsd/netns/spp_timer.h b/bsd/netns/spp_timer.h deleted file mode 100644 index 85c562f4f..000000000 --- a/bsd/netns/spp_timer.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1982, 1986, 1988, 1993 - * 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. - * - * @(#)spp_timer.h 8.1 (Berkeley) 6/10/93 - */ - -/* - * Definitions of the SPP timers. These timers are counted - * down PR_SLOWHZ times a second. - */ -#define SPPT_NTIMERS 4 - -#define SPPT_REXMT 0 /* retransmit */ -#define SPPT_PERSIST 1 /* retransmit persistance */ -#define SPPT_KEEP 2 /* keep alive */ -#define SPPT_2MSL 3 /* 2*msl quiet time timer */ - -/* - * The SPPT_REXMT timer is used to force retransmissions. - * The SPP has the SPPT_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 SPPT_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 SPPT_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 SPPT_PERSMIN time intervals, - * but no more frequently than the current estimate of round-trip - * packet time. The SPPT_PERSIST timer is cleared whenever we receive - * a window update from the peer. - * - * The SPPT_KEEP timer is used to keep connections alive. If an - * connection is idle (no segments received) for SPPTV_KEEP amount of time, - * but not yet established, then we drop the connection. If the connection - * is established, then 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 SPPT_KEEP - * initiated segments we cannot elicit a response from a peer in SPPT_MAXIDLE - * amount of time, then we drop the connection. - */ - -#define SPP_TTL 30 /* default time to live for SPP segs */ -/* - * Time constants. - */ -#define SPPTV_MSL ( 15*PR_SLOWHZ) /* max seg lifetime */ -#define SPPTV_SRTTBASE 0 /* base roundtrip time; - if 0, no idea yet */ -#define SPPTV_SRTTDFLT ( 3*PR_SLOWHZ) /* assumed RTT if no info */ - -#define SPPTV_PERSMIN ( 5*PR_SLOWHZ) /* retransmit persistance */ -#define SPPTV_PERSMAX ( 60*PR_SLOWHZ) /* maximum persist interval */ - -#define SPPTV_KEEP ( 75*PR_SLOWHZ) /* keep alive - 75 secs */ -#define SPPTV_MAXIDLE ( 8*SPPTV_KEEP) /* maximum allowable idle - time before drop conn */ - -#define SPPTV_MIN ( 1*PR_SLOWHZ) /* minimum allowable value */ -#define SPPTV_REXMTMAX ( 64*PR_SLOWHZ) /* max allowable REXMT value */ - -#define SPP_LINGERTIME 120 /* linger at most 2 minutes */ - -#define SPP_MAXRXTSHIFT 12 /* maximum retransmits */ - -#ifdef SPPTIMERS -char *spptimers[] = - { "REXMT", "PERSIST", "KEEP", "2MSL" }; -#endif - -/* - * Force a time value to be in a certain range. - */ -#define SPPT_RANGESET(tv, value, tvmin, tvmax) { \ - (tv) = (value); \ - if ((tv) < (tvmin)) \ - (tv) = (tvmin); \ - else if ((tv) > (tvmax)) \ - (tv) = (tvmax); \ -} - -#ifdef KERNEL -extern int spp_backoff[]; -#endif diff --git a/bsd/netns/spp_usrreq.c b/bsd/netns/spp_usrreq.c deleted file mode 100644 index 2178f9a19..000000000 --- a/bsd/netns/spp_usrreq.c +++ /dev/null @@ -1,1827 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1984, 1985, 1986, 1987, 1993 - * 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. - * - * @(#)spp_usrreq.c 8.1 (Berkeley) 6/10/93 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * SP protocol implementation. - */ -spp_init() -{ - - spp_iss = 1; /* WRONG !! should fish it out of TODR */ -} -struct spidp spp_savesi; -int traceallspps = 0; -extern int sppconsdebug; -int spp_hardnosed; -int spp_use_delack = 0; -u_short spp_newchecks[50]; - -/*ARGSUSED*/ -spp_input(m, nsp) - register struct mbuf *m; - register struct nspcb *nsp; -{ - register struct sppcb *cb; - register struct spidp *si = mtod(m, struct spidp *); - register struct socket *so; - short ostate; - int dropsocket = 0; - - - sppstat.spps_rcvtotal++; - if (nsp == 0) { - panic("No nspcb in spp_input\n"); - return; - } - - cb = nstosppcb(nsp); - if (cb == 0) goto bad; - - if (m->m_len < sizeof(*si)) { - if ((m = m_pullup(m, sizeof(*si))) == 0) { - sppstat.spps_rcvshort++; - return; - } - si = mtod(m, struct spidp *); - } - si->si_seq = ntohs(si->si_seq); - si->si_ack = ntohs(si->si_ack); - si->si_alo = ntohs(si->si_alo); - - so = nsp->nsp_socket; - if (so->so_options & SO_DEBUG || traceallspps) { - ostate = cb->s_state; - spp_savesi = *si; - } - if (so->so_options & SO_ACCEPTCONN) { - struct sppcb *ocb = cb; - - 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++; - nsp = (struct nspcb *)so->so_pcb; - nsp->nsp_laddr = si->si_dna; - cb = nstosppcb(nsp); - cb->s_mtu = ocb->s_mtu; /* preserve sockopts */ - cb->s_flags = ocb->s_flags; /* preserve sockopts */ - cb->s_flags2 = ocb->s_flags2; /* preserve sockopts */ - cb->s_state = TCPS_LISTEN; - } - - /* - * Packet received on connection. - * reset idle time and keep-alive timer; - */ - cb->s_idle = 0; - cb->s_timer[SPPT_KEEP] = SPPTV_KEEP; - - switch (cb->s_state) { - - case TCPS_LISTEN:{ - struct mbuf *am; - register struct sockaddr_ns *sns; - struct ns_addr laddr; - - /* - * If somebody here was carying on a conversation - * and went away, and his pen pal thinks he can - * still talk, we get the misdirected packet. - */ - if (spp_hardnosed && (si->si_did != 0 || si->si_seq != 0)) { - spp_istat.gonawy++; - goto dropwithreset; - } - am = m_get(M_DONTWAIT, MT_SONAME); - if (am == NULL) - goto drop; - am->m_len = sizeof (struct sockaddr_ns); - sns = mtod(am, struct sockaddr_ns *); - sns->sns_len = sizeof(*sns); - sns->sns_family = AF_NS; - sns->sns_addr = si->si_sna; - laddr = nsp->nsp_laddr; - if (ns_nullhost(laddr)) - nsp->nsp_laddr = si->si_dna; - if (ns_pcbconnect(nsp, am)) { - nsp->nsp_laddr = laddr; - (void) m_free(am); - spp_istat.noconn++; - goto drop; - } - (void) m_free(am); - spp_template(cb); - dropsocket = 0; /* committed to socket */ - cb->s_did = si->si_sid; - cb->s_rack = si->si_ack; - cb->s_ralo = si->si_alo; -#define THREEWAYSHAKE -#ifdef THREEWAYSHAKE - cb->s_state = TCPS_SYN_RECEIVED; - cb->s_force = 1 + SPPT_KEEP; - sppstat.spps_accepts++; - cb->s_timer[SPPT_KEEP] = SPPTV_KEEP; - } - break; - /* - * This state means that we have heard a response - * to our acceptance of their connection - * It is probably logically unnecessary in this - * implementation. - */ - case TCPS_SYN_RECEIVED: { - if (si->si_did!=cb->s_sid) { - spp_istat.wrncon++; - goto drop; - } -#endif - nsp->nsp_fport = si->si_sport; - cb->s_timer[SPPT_REXMT] = 0; - cb->s_timer[SPPT_KEEP] = SPPTV_KEEP; - soisconnected(so); - cb->s_state = TCPS_ESTABLISHED; - sppstat.spps_accepts++; - } - break; - - /* - * This state means that we have gotten a response - * to our attempt to establish a connection. - * We fill in the data from the other side, - * telling us which port to respond to, instead of the well- - * known one we might have sent to in the first place. - * We also require that this is a response to our - * connection id. - */ - case TCPS_SYN_SENT: - if (si->si_did!=cb->s_sid) { - spp_istat.notme++; - goto drop; - } - sppstat.spps_connects++; - cb->s_did = si->si_sid; - cb->s_rack = si->si_ack; - cb->s_ralo = si->si_alo; - cb->s_dport = nsp->nsp_fport = si->si_sport; - cb->s_timer[SPPT_REXMT] = 0; - cb->s_flags |= SF_ACKNOW; - soisconnected(so); - cb->s_state = TCPS_ESTABLISHED; - /* Use roundtrip time of connection request for initial rtt */ - if (cb->s_rtt) { - cb->s_srtt = cb->s_rtt << 3; - cb->s_rttvar = cb->s_rtt << 1; - SPPT_RANGESET(cb->s_rxtcur, - ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1, - SPPTV_MIN, SPPTV_REXMTMAX); - cb->s_rtt = 0; - } - } - if (so->so_options & SO_DEBUG || traceallspps) - spp_trace(SA_INPUT, (u_char)ostate, cb, &spp_savesi, 0); - - m->m_len -= sizeof (struct idp); - m->m_pkthdr.len -= sizeof (struct idp); - m->m_data += sizeof (struct idp); - - if (spp_reass(cb, si)) { - (void) m_freem(m); - } - if (cb->s_force || (cb->s_flags & (SF_ACKNOW|SF_WIN|SF_RXT))) - (void) spp_output(cb, (struct mbuf *)0); - cb->s_flags &= ~(SF_WIN|SF_RXT); - return; - -dropwithreset: - if (dropsocket) - (void) soabort(so); - si->si_seq = ntohs(si->si_seq); - si->si_ack = ntohs(si->si_ack); - si->si_alo = ntohs(si->si_alo); - ns_error(dtom(si), NS_ERR_NOSOCK, 0); - if (cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps) - spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0); - return; - -drop: -bad: - if (cb == 0 || cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || - traceallspps) - spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0); - m_freem(m); -} - -int spprexmtthresh = 3; - -/* - * This is structurally similar to the tcp reassembly routine - * but its function is somewhat different: It merely queues - * packets up, and suppresses duplicates. - */ -spp_reass(cb, si) -register struct sppcb *cb; -register struct spidp *si; -{ - register struct spidp_q *q; - register struct mbuf *m; - register struct socket *so = cb->s_nspcb->nsp_socket; - char packetp = cb->s_flags & SF_HI; - int incr; - char wakeup = 0; - - if (si == SI(0)) - goto present; - /* - * Update our news from them. - */ - if (si->si_cc & SP_SA) - cb->s_flags |= (spp_use_delack ? SF_DELACK : SF_ACKNOW); - if (SSEQ_GT(si->si_alo, cb->s_ralo)) - cb->s_flags |= SF_WIN; - if (SSEQ_LEQ(si->si_ack, cb->s_rack)) { - if ((si->si_cc & SP_SP) && cb->s_rack != (cb->s_smax + 1)) { - sppstat.spps_rcvdupack++; - /* - * If this is a completely duplicate ack - * and other conditions hold, we assume - * a packet has been dropped and retransmit - * it exactly as in tcp_input(). - */ - if (si->si_ack != cb->s_rack || - si->si_alo != cb->s_ralo) - cb->s_dupacks = 0; - else if (++cb->s_dupacks == spprexmtthresh) { - u_short onxt = cb->s_snxt; - int cwnd = cb->s_cwnd; - - cb->s_snxt = si->si_ack; - cb->s_cwnd = CUNIT; - cb->s_force = 1 + SPPT_REXMT; - (void) spp_output(cb, (struct mbuf *)0); - cb->s_timer[SPPT_REXMT] = cb->s_rxtcur; - cb->s_rtt = 0; - if (cwnd >= 4 * CUNIT) - cb->s_cwnd = cwnd / 2; - if (SSEQ_GT(onxt, cb->s_snxt)) - cb->s_snxt = onxt; - return (1); - } - } else - cb->s_dupacks = 0; - goto update_window; - } - cb->s_dupacks = 0; - /* - * If our correspondent acknowledges data we haven't sent - * TCP would drop the packet after acking. We'll be a little - * more permissive - */ - if (SSEQ_GT(si->si_ack, (cb->s_smax + 1))) { - sppstat.spps_rcvacktoomuch++; - si->si_ack = cb->s_smax + 1; - } - sppstat.spps_rcvackpack++; - /* - * If transmit timer is running and timed sequence - * number was acked, update smoothed round trip time. - * See discussion of algorithm in tcp_input.c - */ - if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) { - sppstat.spps_rttupdated++; - if (cb->s_srtt != 0) { - register short delta; - delta = cb->s_rtt - (cb->s_srtt >> 3); - if ((cb->s_srtt += delta) <= 0) - cb->s_srtt = 1; - if (delta < 0) - delta = -delta; - delta -= (cb->s_rttvar >> 2); - if ((cb->s_rttvar += delta) <= 0) - cb->s_rttvar = 1; - } else { - /* - * No rtt measurement yet - */ - cb->s_srtt = cb->s_rtt << 3; - cb->s_rttvar = cb->s_rtt << 1; - } - cb->s_rtt = 0; - cb->s_rxtshift = 0; - SPPT_RANGESET(cb->s_rxtcur, - ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1, - SPPTV_MIN, SPPTV_REXMTMAX); - } - /* - * 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 (si->si_ack == cb->s_smax + 1) { - cb->s_timer[SPPT_REXMT] = 0; - cb->s_flags |= SF_RXT; - } else if (cb->s_timer[SPPT_PERSIST] == 0) - cb->s_timer[SPPT_REXMT] = cb->s_rxtcur; - /* - * When new data is acked, open the congestion window. - * If the window gives us less than ssthresh packets - * in flight, open exponentially (maxseg at a time). - * Otherwise open linearly (maxseg^2 / cwnd at a time). - */ - incr = CUNIT; - if (cb->s_cwnd > cb->s_ssthresh) - incr = max(incr * incr / cb->s_cwnd, 1); - cb->s_cwnd = min(cb->s_cwnd + incr, cb->s_cwmx); - /* - * Trim Acked data from output queue. - */ - while ((m = so->so_snd.sb_mb) != NULL) { - if (SSEQ_LT((mtod(m, struct spidp *))->si_seq, si->si_ack)) - sbdroprecord(&so->so_snd); - else - break; - } - sowwakeup(so); - cb->s_rack = si->si_ack; -update_window: - if (SSEQ_LT(cb->s_snxt, cb->s_rack)) - cb->s_snxt = cb->s_rack; - if (SSEQ_LT(cb->s_swl1, si->si_seq) || cb->s_swl1 == si->si_seq && - (SSEQ_LT(cb->s_swl2, si->si_ack) || - cb->s_swl2 == si->si_ack && SSEQ_LT(cb->s_ralo, si->si_alo))) { - /* keep track of pure window updates */ - if ((si->si_cc & SP_SP) && cb->s_swl2 == si->si_ack - && SSEQ_LT(cb->s_ralo, si->si_alo)) { - sppstat.spps_rcvwinupd++; - sppstat.spps_rcvdupack--; - } - cb->s_ralo = si->si_alo; - cb->s_swl1 = si->si_seq; - cb->s_swl2 = si->si_ack; - cb->s_swnd = (1 + si->si_alo - si->si_ack); - if (cb->s_swnd > cb->s_smxw) - cb->s_smxw = cb->s_swnd; - cb->s_flags |= SF_WIN; - } - /* - * If this packet number is higher than that which - * we have allocated refuse it, unless urgent - */ - if (SSEQ_GT(si->si_seq, cb->s_alo)) { - if (si->si_cc & SP_SP) { - sppstat.spps_rcvwinprobe++; - return (1); - } else - sppstat.spps_rcvpackafterwin++; - if (si->si_cc & SP_OB) { - if (SSEQ_GT(si->si_seq, cb->s_alo + 60)) { - ns_error(dtom(si), NS_ERR_FULLUP, 0); - return (0); - } /* else queue this packet; */ - } else { - /*register struct socket *so = cb->s_nspcb->nsp_socket; - if (so->so_state && SS_NOFDREF) { - ns_error(dtom(si), NS_ERR_NOSOCK, 0); - (void)spp_close(cb); - } else - would crash system*/ - spp_istat.notyet++; - ns_error(dtom(si), NS_ERR_FULLUP, 0); - return (0); - } - } - /* - * If this is a system packet, we don't need to - * queue it up, and won't update acknowledge # - */ - if (si->si_cc & SP_SP) { - return (1); - } - /* - * We have already seen this packet, so drop. - */ - if (SSEQ_LT(si->si_seq, cb->s_ack)) { - spp_istat.bdreas++; - sppstat.spps_rcvduppack++; - if (si->si_seq == cb->s_ack - 1) - spp_istat.lstdup++; - return (1); - } - /* - * Loop through all packets queued up to insert in - * appropriate sequence. - */ - for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) { - if (si->si_seq == SI(q)->si_seq) { - sppstat.spps_rcvduppack++; - return (1); - } - if (SSEQ_LT(si->si_seq, SI(q)->si_seq)) { - sppstat.spps_rcvoopack++; - break; - } - } - insque(si, q->si_prev); - /* - * If this packet is urgent, inform process - */ - if (si->si_cc & SP_OB) { - cb->s_iobc = ((char *)si)[1 + sizeof(*si)]; - sohasoutofband(so); - cb->s_oobflags |= SF_IOOB; - } -present: -#define SPINC sizeof(struct sphdr) - /* - * Loop through all packets queued up to update acknowledge - * number, and present all acknowledged data to user; - * If in packet interface mode, show packet headers. - */ - for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) { - if (SI(q)->si_seq == cb->s_ack) { - cb->s_ack++; - m = dtom(q); - if (SI(q)->si_cc & SP_OB) { - cb->s_oobflags &= ~SF_IOOB; - if (so->so_rcv.sb_cc) - so->so_oobmark = so->so_rcv.sb_cc; - else - so->so_state |= SS_RCVATMARK; - postevent(so, 0, EV_OOB); - } - q = q->si_prev; - remque(q->si_next); - wakeup = 1; - sppstat.spps_rcvpack++; -#ifdef SF_NEWCALL - if (cb->s_flags2 & SF_NEWCALL) { - struct sphdr *sp = mtod(m, struct sphdr *); - u_char dt = sp->sp_dt; - spp_newchecks[4]++; - if (dt != cb->s_rhdr.sp_dt) { - struct mbuf *mm = - m_getclr(M_DONTWAIT, MT_CONTROL); - spp_newchecks[0]++; - if (mm != NULL) { - u_short *s = - mtod(mm, u_short *); - cb->s_rhdr.sp_dt = dt; - mm->m_len = 5; /*XXX*/ - s[0] = 5; - s[1] = 1; - *(u_char *)(&s[2]) = dt; - sbappend(&so->so_rcv, mm); - } - } - if (sp->sp_cc & SP_OB) { - MCHTYPE(m, MT_OOBDATA); - spp_newchecks[1]++; - so->so_oobmark = 0; - so->so_state &= ~SS_RCVATMARK; - } - if (packetp == 0) { - m->m_data += SPINC; - m->m_len -= SPINC; - m->m_pkthdr.len -= SPINC; - } - if ((sp->sp_cc & SP_EM) || packetp) { - sbappendrecord(&so->so_rcv, m); - spp_newchecks[9]++; - } else - sbappend(&so->so_rcv, m); - } else -#endif - if (packetp) { - sbappendrecord(&so->so_rcv, m); - } else { - cb->s_rhdr = *mtod(m, struct sphdr *); - m->m_data += SPINC; - m->m_len -= SPINC; - m->m_pkthdr.len -= SPINC; - sbappend(&so->so_rcv, m); - } - } else - break; - } - if (wakeup) sorwakeup(so); - return (0); -} - -spp_ctlinput(cmd, arg) - int cmd; - caddr_t arg; -{ - struct ns_addr *na; - extern u_char nsctlerrmap[]; - extern spp_abort(), spp_quench(); - extern struct nspcb *idp_drop(); - struct ns_errp *errp; - struct nspcb *nsp; - struct sockaddr_ns *sns; - int type; - - if (cmd < 0 || cmd > PRC_NCMDS) - return; - type = NS_ERR_UNREACH_HOST; - - switch (cmd) { - - case PRC_ROUTEDEAD: - return; - - case PRC_IFDOWN: - case PRC_HOSTDEAD: - case PRC_HOSTUNREACH: - sns = (struct sockaddr_ns *)arg; - if (sns->sns_family != AF_NS) - return; - na = &sns->sns_addr; - break; - - default: - errp = (struct ns_errp *)arg; - na = &errp->ns_err_idp.idp_dna; - type = errp->ns_err_num; - type = ntohs((u_short)type); - } - switch (type) { - - case NS_ERR_UNREACH_HOST: - ns_pcbnotify(na, (int)nsctlerrmap[cmd], spp_abort, (long) 0); - break; - - case NS_ERR_TOO_BIG: - case NS_ERR_NOSOCK: - nsp = ns_pcblookup(na, errp->ns_err_idp.idp_sna.x_port, - NS_WILDCARD); - if (nsp) { - if(nsp->nsp_pcb) - (void) spp_drop((struct sppcb *)nsp->nsp_pcb, - (int)nsctlerrmap[cmd]); - else - (void) idp_drop(nsp, (int)nsctlerrmap[cmd]); - } - break; - - case NS_ERR_FULLUP: - ns_pcbnotify(na, 0, spp_quench, (long) 0); - } -} -/* - * When a source quench is received, close congestion window - * to one packet. We will gradually open it again as we proceed. - */ -spp_quench(nsp) - struct nspcb *nsp; -{ - struct sppcb *cb = nstosppcb(nsp); - - if (cb) - cb->s_cwnd = CUNIT; -} - -#ifdef notdef -int -spp_fixmtu(nsp) -register struct nspcb *nsp; -{ - register struct sppcb *cb = (struct sppcb *)(nsp->nsp_pcb); - register struct mbuf *m; - register struct spidp *si; - struct ns_errp *ep; - struct sockbuf *sb; - int badseq, len; - struct mbuf *firstbad, *m0; - - if (cb) { - /* - * The notification that we have sent - * too much is bad news -- we will - * have to go through queued up so far - * splitting ones which are too big and - * reassigning sequence numbers and checksums. - * we should then retransmit all packets from - * one above the offending packet to the last one - * we had sent (or our allocation) - * then the offending one so that the any queued - * data at our destination will be discarded. - */ - ep = (struct ns_errp *)nsp->nsp_notify_param; - sb = &nsp->nsp_socket->so_snd; - cb->s_mtu = ep->ns_err_param; - badseq = SI(&ep->ns_err_idp)->si_seq; - for (m = sb->sb_mb; m; m = m->m_act) { - si = mtod(m, struct spidp *); - if (si->si_seq == badseq) - break; - } - if (m == 0) return; - firstbad = m; - /*for (;;) {*/ - /* calculate length */ - for (m0 = m, len = 0; m ; m = m->m_next) - len += m->m_len; - if (len > cb->s_mtu) { - } - /* FINISH THIS - } */ - } -} -#endif - -spp_output(cb, m0) - register struct sppcb *cb; - struct mbuf *m0; -{ - struct socket *so = cb->s_nspcb->nsp_socket; - register struct mbuf *m; - register struct spidp *si = (struct spidp *) 0; - register struct sockbuf *sb = &so->so_snd; - int len = 0, win, rcv_win; - short span, off, recordp = 0; - u_short alo; - int error = 0, sendalot; -#ifdef notdef - int idle; -#endif - struct mbuf *mprev; - extern int idpcksum; - - if (m0) { - int mtu = cb->s_mtu; - int datalen; - /* - * Make sure that packet isn't too big. - */ - for (m = m0; m ; m = m->m_next) { - mprev = m; - len += m->m_len; - if (m->m_flags & M_EOR) - recordp = 1; - } - datalen = (cb->s_flags & SF_HO) ? - len - sizeof (struct sphdr) : len; - if (datalen > mtu) { - if (cb->s_flags & SF_PI) { - m_freem(m0); - return (EMSGSIZE); - } else { - int oldEM = cb->s_cc & SP_EM; - - cb->s_cc &= ~SP_EM; - while (len > mtu) { - /* - * Here we are only being called - * from usrreq(), so it is OK to - * block. - */ - m = m_copym(m0, 0, mtu, M_WAIT); - if (cb->s_flags & SF_NEWCALL) { - struct mbuf *mm = m; - spp_newchecks[7]++; - while (mm) { - mm->m_flags &= ~M_EOR; - mm = mm->m_next; - } - } - error = spp_output(cb, m); - if (error) { - cb->s_cc |= oldEM; - m_freem(m0); - return(error); - } - m_adj(m0, mtu); - len -= mtu; - } - cb->s_cc |= oldEM; - } - } - /* - * Force length even, by adding a "garbage byte" if - * necessary. - */ - if (len & 1) { - m = mprev; - if (M_TRAILINGSPACE(m) >= 1) - m->m_len++; - else { - struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); - - if (m1 == 0) { - m_freem(m0); - return (ENOBUFS); - } - m1->m_len = 1; - *(mtod(m1, u_char *)) = 0; - m->m_next = m1; - } - } - m = m_gethdr(M_DONTWAIT, MT_HEADER); - if (m == 0) { - m_freem(m0); - return (ENOBUFS); - } - /* - * Fill in mbuf with extended SP header - * and addresses and length put into network format. - */ - MH_ALIGN(m, sizeof (struct spidp)); - m->m_len = sizeof (struct spidp); - m->m_next = m0; - si = mtod(m, struct spidp *); - si->si_i = *cb->s_idp; - si->si_s = cb->s_shdr; - if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) { - register struct sphdr *sh; - if (m0->m_len < sizeof (*sh)) { - if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) { - (void) m_free(m); - m_freem(m0); - return (EINVAL); - } - m->m_next = m0; - } - sh = mtod(m0, struct sphdr *); - si->si_dt = sh->sp_dt; - si->si_cc |= sh->sp_cc & SP_EM; - m0->m_len -= sizeof (*sh); - m0->m_data += sizeof (*sh); - len -= sizeof (*sh); - } - len += sizeof(*si); - if ((cb->s_flags2 & SF_NEWCALL) && recordp) { - si->si_cc |= SP_EM; - spp_newchecks[8]++; - } - if (cb->s_oobflags & SF_SOOB) { - /* - * Per jqj@cornell: - * make sure OB packets convey exactly 1 byte. - * If the packet is 1 byte or larger, we - * have already guaranted there to be at least - * one garbage byte for the checksum, and - * extra bytes shouldn't hurt! - */ - if (len > sizeof(*si)) { - si->si_cc |= SP_OB; - len = (1 + sizeof(*si)); - } - } - si->si_len = htons((u_short)len); - m->m_pkthdr.len = ((len - 1) | 1) + 1; - /* - * queue stuff up for output - */ - sbappendrecord(sb, m); - cb->s_seq++; - } -#ifdef notdef - idle = (cb->s_smax == (cb->s_rack - 1)); -#endif -again: - sendalot = 0; - off = cb->s_snxt - cb->s_rack; - win = min(cb->s_swnd, (cb->s_cwnd/CUNIT)); - - /* - * If in persist timeout with window of 0, send a probe. - * Otherwise, if window is small but nonzero - * and timer expired, send what we can and go into - * transmit state. - */ - if (cb->s_force == 1 + SPPT_PERSIST) { - if (win != 0) { - cb->s_timer[SPPT_PERSIST] = 0; - cb->s_rxtshift = 0; - } - } - span = cb->s_seq - cb->s_rack; - len = min(span, win) - off; - - if (len < 0) { - /* - * Window shrank after we went into it. - * If window shrank to 0, cancel pending - * restransmission and pull s_snxt back - * to (closed) window. We will enter persist - * state below. If the widndow didn't close completely, - * just wait for an ACK. - */ - len = 0; - if (win == 0) { - cb->s_timer[SPPT_REXMT] = 0; - cb->s_snxt = cb->s_rack; - } - } - if (len > 1) - sendalot = 1; - rcv_win = sbspace(&so->so_rcv); - - /* - * Send if we owe peer an ACK. - */ - if (cb->s_oobflags & SF_SOOB) { - /* - * must transmit this out of band packet - */ - cb->s_oobflags &= ~ SF_SOOB; - sendalot = 1; - sppstat.spps_sndurg++; - goto found; - } - if (cb->s_flags & SF_ACKNOW) - goto send; - if (cb->s_state < TCPS_ESTABLISHED) - goto send; - /* - * Silly window can't happen in spp. - * Code from tcp deleted. - */ - if (len) - 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 - * packets or at least 35% of the mximum possible window, - * then want to send a window update to peer. - */ - if (rcv_win > 0) { - u_short delta = 1 + cb->s_alo - cb->s_ack; - int adv = rcv_win - (delta * cb->s_mtu); - - if ((so->so_rcv.sb_cc == 0 && adv >= (2 * cb->s_mtu)) || - (100 * adv / so->so_rcv.sb_hiwat >= 35)) { - sppstat.spps_sndwinup++; - cb->s_flags |= SF_ACKNOW; - goto send; - } - - } - /* - * Many comments from tcp_output.c are appropriate here - * including . . . - * 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 send a probe. - */ - if (so->so_snd.sb_cc && cb->s_timer[SPPT_REXMT] == 0 && - cb->s_timer[SPPT_PERSIST] == 0) { - cb->s_rxtshift = 0; - spp_setpersist(cb); - } - /* - * No reason to send a packet, just return. - */ - cb->s_outx = 1; - return (0); - -send: - /* - * Find requested packet. - */ - si = 0; - if (len > 0) { - cb->s_want = cb->s_snxt; - for (m = sb->sb_mb; m; m = m->m_act) { - si = mtod(m, struct spidp *); - if (SSEQ_LEQ(cb->s_snxt, si->si_seq)) - break; - } - found: - if (si) { - if (si->si_seq == cb->s_snxt) - cb->s_snxt++; - else - sppstat.spps_sndvoid++, si = 0; - } - } - /* - * update window - */ - if (rcv_win < 0) - rcv_win = 0; - alo = cb->s_ack - 1 + (rcv_win / ((short)cb->s_mtu)); - if (SSEQ_LT(alo, cb->s_alo)) - alo = cb->s_alo; - - if (si) { - /* - * must make a copy of this packet for - * idp_output to monkey with - */ - m = m_copy(dtom(si), 0, (int)M_COPYALL); - if (m == NULL) { - return (ENOBUFS); - } - si = mtod(m, struct spidp *); - if (SSEQ_LT(si->si_seq, cb->s_smax)) - sppstat.spps_sndrexmitpack++; - else - sppstat.spps_sndpack++; - } else if (cb->s_force || cb->s_flags & SF_ACKNOW) { - /* - * Must send an acknowledgement or a probe - */ - if (cb->s_force) - sppstat.spps_sndprobe++; - if (cb->s_flags & SF_ACKNOW) - sppstat.spps_sndacks++; - m = m_gethdr(M_DONTWAIT, MT_HEADER); - if (m == 0) - return (ENOBUFS); - /* - * Fill in mbuf with extended SP header - * and addresses and length put into network format. - */ - MH_ALIGN(m, sizeof (struct spidp)); - m->m_len = sizeof (*si); - m->m_pkthdr.len = sizeof (*si); - si = mtod(m, struct spidp *); - si->si_i = *cb->s_idp; - si->si_s = cb->s_shdr; - si->si_seq = cb->s_smax + 1; - si->si_len = htons(sizeof (*si)); - si->si_cc |= SP_SP; - } else { - cb->s_outx = 3; - if (so->so_options & SO_DEBUG || traceallspps) - spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0); - return (0); - } - /* - * Stuff checksum and output datagram. - */ - if ((si->si_cc & SP_SP) == 0) { - if (cb->s_force != (1 + SPPT_PERSIST) || - cb->s_timer[SPPT_PERSIST] == 0) { - /* - * If this is a new packet and we are not currently - * timing anything, time this one. - */ - if (SSEQ_LT(cb->s_smax, si->si_seq)) { - cb->s_smax = si->si_seq; - if (cb->s_rtt == 0) { - sppstat.spps_segstimed++; - cb->s_rtseq = si->si_seq; - cb->s_rtt = 1; - } - } - /* - * Set rexmt timer if not currently set, - * 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 (cb->s_timer[SPPT_REXMT] == 0 && - cb->s_snxt != cb->s_rack) { - cb->s_timer[SPPT_REXMT] = cb->s_rxtcur; - if (cb->s_timer[SPPT_PERSIST]) { - cb->s_timer[SPPT_PERSIST] = 0; - cb->s_rxtshift = 0; - } - } - } else if (SSEQ_LT(cb->s_smax, si->si_seq)) { - cb->s_smax = si->si_seq; - } - } else if (cb->s_state < TCPS_ESTABLISHED) { - if (cb->s_rtt == 0) - cb->s_rtt = 1; /* Time initial handshake */ - if (cb->s_timer[SPPT_REXMT] == 0) - cb->s_timer[SPPT_REXMT] = cb->s_rxtcur; - } - { - /* - * Do not request acks when we ack their data packets or - * when we do a gratuitous window update. - */ - if (((si->si_cc & SP_SP) == 0) || cb->s_force) - si->si_cc |= SP_SA; - si->si_seq = htons(si->si_seq); - si->si_alo = htons(alo); - si->si_ack = htons(cb->s_ack); - - if (idpcksum) { - si->si_sum = 0; - len = ntohs(si->si_len); - if (len & 1) - len++; - si->si_sum = ns_cksum(m, len); - } else - si->si_sum = 0xffff; - - cb->s_outx = 4; - if (so->so_options & SO_DEBUG || traceallspps) - spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0); - - if (so->so_options & SO_DONTROUTE) - error = ns_output(m, (struct route *)0, NS_ROUTETOIF); - else - error = ns_output(m, &cb->s_nspcb->nsp_route, 0); - } - if (error) { - return (error); - } - sppstat.spps_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 advertized window. - * Any pending ACK has now been sent. - */ - cb->s_force = 0; - cb->s_flags &= ~(SF_ACKNOW|SF_DELACK); - if (SSEQ_GT(alo, cb->s_alo)) - cb->s_alo = alo; - if (sendalot) - goto again; - cb->s_outx = 5; - return (0); -} - -int spp_do_persist_panics = 0; - -spp_setpersist(cb) - register struct sppcb *cb; -{ - register t = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1; - extern int spp_backoff[]; - - if (cb->s_timer[SPPT_REXMT] && spp_do_persist_panics) - panic("spp_output REXMT"); - /* - * Start/restart persistance timer. - */ - SPPT_RANGESET(cb->s_timer[SPPT_PERSIST], - t*spp_backoff[cb->s_rxtshift], - SPPTV_PERSMIN, SPPTV_PERSMAX); - if (cb->s_rxtshift < SPP_MAXRXTSHIFT) - cb->s_rxtshift++; -} -/*ARGSUSED*/ -spp_ctloutput(req, so, level, name, value) - int req; - struct socket *so; - int name; - struct mbuf **value; -{ - register struct mbuf *m; - struct nspcb *nsp = sotonspcb(so); - register struct sppcb *cb; - int mask, error = 0; - - if (level != NSPROTO_SPP) { - /* This will have to be changed when we do more general - stacking of protocols */ - return (idp_ctloutput(req, so, level, name, value)); - } - if (nsp == NULL) { - error = EINVAL; - goto release; - } else - cb = nstosppcb(nsp); - - switch (req) { - - case PRCO_GETOPT: - if (value == NULL) - return (EINVAL); - m = m_get(M_DONTWAIT, MT_DATA); - if (m == NULL) - return (ENOBUFS); - switch (name) { - - case SO_HEADERS_ON_INPUT: - mask = SF_HI; - goto get_flags; - - case SO_HEADERS_ON_OUTPUT: - mask = SF_HO; - get_flags: - m->m_len = sizeof(short); - *mtod(m, short *) = cb->s_flags & mask; - break; - - case SO_MTU: - m->m_len = sizeof(u_short); - *mtod(m, short *) = cb->s_mtu; - break; - - case SO_LAST_HEADER: - m->m_len = sizeof(struct sphdr); - *mtod(m, struct sphdr *) = cb->s_rhdr; - break; - - case SO_DEFAULT_HEADERS: - m->m_len = sizeof(struct spidp); - *mtod(m, struct sphdr *) = cb->s_shdr; - break; - - default: - error = EINVAL; - } - *value = m; - break; - - case PRCO_SETOPT: - if (value == 0 || *value == 0) { - error = EINVAL; - break; - } - switch (name) { - int *ok; - - case SO_HEADERS_ON_INPUT: - mask = SF_HI; - goto set_head; - - case SO_HEADERS_ON_OUTPUT: - mask = SF_HO; - set_head: - if (cb->s_flags & SF_PI) { - ok = mtod(*value, int *); - if (*ok) - cb->s_flags |= mask; - else - cb->s_flags &= ~mask; - } else error = EINVAL; - break; - - case SO_MTU: - cb->s_mtu = *(mtod(*value, u_short *)); - break; - -#ifdef SF_NEWCALL - case SO_NEWCALL: - ok = mtod(*value, int *); - if (*ok) { - cb->s_flags2 |= SF_NEWCALL; - spp_newchecks[5]++; - } else { - cb->s_flags2 &= ~SF_NEWCALL; - spp_newchecks[6]++; - } - break; -#endif - - case SO_DEFAULT_HEADERS: - { - register struct sphdr *sp - = mtod(*value, struct sphdr *); - cb->s_dt = sp->sp_dt; - cb->s_cc = sp->sp_cc & SP_EM; - } - break; - - default: - error = EINVAL; - } - m_freem(*value); - break; - } - release: - return (error); -} - -/*ARGSUSED*/ -spp_usrreq(so, req, m, nam, controlp) - struct socket *so; - int req; - struct mbuf *m, *nam, *controlp; -{ - struct nspcb *nsp = sotonspcb(so); - register struct sppcb *cb; - int s = splnet(); - int error = 0, ostate; - struct mbuf *mm; - register struct sockbuf *sb; - - if (req == PRU_CONTROL) - return (ns_control(so, (int)m, (caddr_t)nam, - (struct ifnet *)controlp)); - if (nsp == NULL) { - if (req != PRU_ATTACH) { - error = EINVAL; - goto release; - } - } else - cb = nstosppcb(nsp); - - ostate = cb ? cb->s_state : 0; - - switch (req) { - - case PRU_ATTACH: - if (nsp != NULL) { - error = EISCONN; - break; - } - error = ns_pcballoc(so, &nspcb); - if (error) - break; - if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { - error = soreserve(so, (u_long) 3072, (u_long) 3072); - if (error) - break; - } - nsp = sotonspcb(so); - - mm = m_getclr(M_DONTWAIT, MT_PCB); - sb = &so->so_snd; - - if (mm == NULL) { - error = ENOBUFS; - break; - } - cb = mtod(mm, struct sppcb *); - mm = m_getclr(M_DONTWAIT, MT_HEADER); - if (mm == NULL) { - (void) m_free(dtom(m)); - error = ENOBUFS; - break; - } - cb->s_idp = mtod(mm, struct idp *); - cb->s_state = TCPS_LISTEN; - cb->s_smax = -1; - cb->s_swl1 = -1; - cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q; - cb->s_nspcb = nsp; - cb->s_mtu = 576 - sizeof (struct spidp); - cb->s_cwnd = sbspace(sb) * CUNIT / cb->s_mtu; - cb->s_ssthresh = cb->s_cwnd; - cb->s_cwmx = sbspace(sb) * CUNIT / - (2 * sizeof (struct spidp)); - /* Above is recomputed when connecting to account - for changed buffering or mtu's */ - cb->s_rtt = SPPTV_SRTTBASE; - cb->s_rttvar = SPPTV_SRTTDFLT << 2; - SPPT_RANGESET(cb->s_rxtcur, - ((SPPTV_SRTTBASE >> 2) + (SPPTV_SRTTDFLT << 2)) >> 1, - SPPTV_MIN, SPPTV_REXMTMAX); - nsp->nsp_pcb = (caddr_t) cb; - break; - - case PRU_DETACH: - if (nsp == NULL) { - error = ENOTCONN; - break; - } - if (cb->s_state > TCPS_LISTEN) - cb = spp_disconnect(cb); - else - cb = spp_close(cb); - break; - - case PRU_BIND: - error = ns_pcbbind(nsp, nam); - break; - - case PRU_LISTEN: - if (nsp->nsp_lport == 0) - error = ns_pcbbind(nsp, (struct mbuf *)0); - if (error == 0) - cb->s_state = TCPS_LISTEN; - break; - - /* - * Initiate connection to peer. - * Enter SYN_SENT state, and mark socket as connecting. - * Start keep-alive timer, setup prototype header, - * Send initial system packet requesting connection. - */ - case PRU_CONNECT: - if (nsp->nsp_lport == 0) { - error = ns_pcbbind(nsp, (struct mbuf *)0); - if (error) - break; - } - error = ns_pcbconnect(nsp, nam); - if (error) - break; - soisconnecting(so); - sppstat.spps_connattempt++; - cb->s_state = TCPS_SYN_SENT; - cb->s_did = 0; - spp_template(cb); - cb->s_timer[SPPT_KEEP] = SPPTV_KEEP; - cb->s_force = 1 + SPPTV_KEEP; - /* - * Other party is required to respond to - * the port I send from, but he is not - * required to answer from where I am sending to, - * so allow wildcarding. - * original port I am sending to is still saved in - * cb->s_dport. - */ - nsp->nsp_fport = 0; - error = spp_output(cb, (struct mbuf *) 0); - break; - - case PRU_CONNECT2: - error = EOPNOTSUPP; - break; - - /* - * We may decide later to implement connection closing - * handshaking at the spp level optionally. - * here is the hook to do it: - */ - case PRU_DISCONNECT: - cb = spp_disconnect(cb); - 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_ns *sns = mtod(nam, struct sockaddr_ns *); - - nam->m_len = sizeof (struct sockaddr_ns); - sns->sns_family = AF_NS; - sns->sns_addr = nsp->nsp_faddr; - break; - } - - case PRU_SHUTDOWN: - socantsendmore(so); - cb = spp_usrclosed(cb); - if (cb) - error = spp_output(cb, (struct mbuf *) 0); - break; - - /* - * After a receive, possibly send acknowledgment - * updating allocation. - */ - case PRU_RCVD: - cb->s_flags |= SF_RVD; - (void) spp_output(cb, (struct mbuf *) 0); - cb->s_flags &= ~SF_RVD; - break; - - case PRU_ABORT: - (void) spp_drop(cb, ECONNABORTED); - break; - - case PRU_SENSE: - case PRU_CONTROL: - m = NULL; - error = EOPNOTSUPP; - break; - - case PRU_RCVOOB: - if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark || - (so->so_state & SS_RCVATMARK)) { - m->m_len = 1; - *mtod(m, caddr_t) = cb->s_iobc; - break; - } - error = EINVAL; - break; - - case PRU_SENDOOB: - if (sbspace(&so->so_snd) < -512) { - error = ENOBUFS; - break; - } - cb->s_oobflags |= SF_SOOB; - /* fall into */ - case PRU_SEND: - if (controlp) { - u_short *p = mtod(controlp, u_short *); - spp_newchecks[2]++; - if ((p[0] == 5) && p[1] == 1) { /* XXXX, for testing */ - cb->s_shdr.sp_dt = *(u_char *)(&p[2]); - spp_newchecks[3]++; - } - m_freem(controlp); - } - controlp = NULL; - error = spp_output(cb, m); - m = NULL; - break; - - case PRU_SOCKADDR: - ns_setsockaddr(nsp, nam); - break; - - case PRU_PEERADDR: - ns_setpeeraddr(nsp, nam); - break; - - case PRU_SLOWTIMO: - cb = spp_timers(cb, (int)nam); - req |= ((int)nam) << 8; - break; - - case PRU_FASTTIMO: - case PRU_PROTORCV: - case PRU_PROTOSEND: - error = EOPNOTSUPP; - break; - - default: - panic("sp_usrreq"); - } - if (cb && (so->so_options & SO_DEBUG || traceallspps)) - spp_trace(SA_USER, (u_char)ostate, cb, (struct spidp *)0, req); -release: - if (controlp != NULL) - m_freem(controlp); - if (m != NULL) - m_freem(m); - splx(s); - return (error); -} - -spp_usrreq_sp(so, req, m, nam, controlp) - struct socket *so; - int req; - struct mbuf *m, *nam, *controlp; -{ - int error = spp_usrreq(so, req, m, nam, controlp); - - if (req == PRU_ATTACH && error == 0) { - struct nspcb *nsp = sotonspcb(so); - ((struct sppcb *)nsp->nsp_pcb)->s_flags |= - (SF_HI | SF_HO | SF_PI); - } - return (error); -} - -/* - * Create template to be used to send spp packets on a connection. - * Called after host entry created, fills - * in a skeletal spp header (choosing connection id), - * minimizing the amount of work necessary when the connection is used. - */ -spp_template(cb) - register struct sppcb *cb; -{ - register struct nspcb *nsp = cb->s_nspcb; - register struct idp *idp = cb->s_idp; - register struct sockbuf *sb = &(nsp->nsp_socket->so_snd); - - idp->idp_pt = NSPROTO_SPP; - idp->idp_sna = nsp->nsp_laddr; - idp->idp_dna = nsp->nsp_faddr; - cb->s_sid = htons(spp_iss); - spp_iss += SPP_ISSINCR/2; - cb->s_alo = 1; - cb->s_cwnd = (sbspace(sb) * CUNIT) / cb->s_mtu; - cb->s_ssthresh = cb->s_cwnd; /* Try to expand fast to full complement - of large packets */ - cb->s_cwmx = (sbspace(sb) * CUNIT) / (2 * sizeof(struct spidp)); - cb->s_cwmx = max(cb->s_cwmx, cb->s_cwnd); - /* But allow for lots of little packets as well */ -} - -/* - * Close a SPIP control block: - * discard spp control block itself - * discard ns protocol control block - * wake up any sleepers - */ -struct sppcb * -spp_close(cb) - register struct sppcb *cb; -{ - register struct spidp_q *s; - struct nspcb *nsp = cb->s_nspcb; - struct socket *so = nsp->nsp_socket; - register struct mbuf *m; - - s = cb->s_q.si_next; - while (s != &(cb->s_q)) { - s = s->si_next; - m = dtom(s->si_prev); - remque(s->si_prev); - m_freem(m); - } - (void) m_free(dtom(cb->s_idp)); - (void) m_free(dtom(cb)); - nsp->nsp_pcb = 0; - soisdisconnected(so); - ns_pcbdetach(nsp); - sppstat.spps_closed++; - return ((struct sppcb *)0); -} -/* - * Someday we may do level 3 handshaking - * to close a connection or send a xerox style error. - * For now, just close. - */ -struct sppcb * -spp_usrclosed(cb) - register struct sppcb *cb; -{ - return (spp_close(cb)); -} -struct sppcb * -spp_disconnect(cb) - register struct sppcb *cb; -{ - return (spp_close(cb)); -} -/* - * Drop connection, reporting - * the specified error. - */ -struct sppcb * -spp_drop(cb, errno) - register struct sppcb *cb; - int errno; -{ - struct socket *so = cb->s_nspcb->nsp_socket; - - /* - * someday, in the xerox world - * we will generate error protocol packets - * announcing that the socket has gone away. - */ - if (TCPS_HAVERCVDSYN(cb->s_state)) { - sppstat.spps_drops++; - cb->s_state = TCPS_CLOSED; - /*(void) tcp_output(cb);*/ - } else - sppstat.spps_conndrops++; - so->so_error = errno; - return (spp_close(cb)); -} - -spp_abort(nsp) - struct nspcb *nsp; -{ - - (void) spp_close((struct sppcb *)nsp->nsp_pcb); -} - -int spp_backoff[SPP_MAXRXTSHIFT+1] = - { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; -/* - * Fast timeout routine for processing delayed acks - */ -spp_fasttimo() -{ - register struct nspcb *nsp; - register struct sppcb *cb; - int s = splnet(); - - nsp = nspcb.nsp_next; - if (nsp) - for (; nsp != &nspcb; nsp = nsp->nsp_next) - if ((cb = (struct sppcb *)nsp->nsp_pcb) && - (cb->s_flags & SF_DELACK)) { - cb->s_flags &= ~SF_DELACK; - cb->s_flags |= SF_ACKNOW; - sppstat.spps_delack++; - (void) spp_output(cb, (struct mbuf *) 0); - } - splx(s); -} - -/* - * spp protocol timeout routine called every 500 ms. - * Updates the timers in all active pcb's and - * causes finite state machine actions if timers expire. - */ -spp_slowtimo() -{ - register struct nspcb *ip, *ipnxt; - register struct sppcb *cb; - int s = splnet(); - register int i; - - /* - * Search through tcb's and update active timers. - */ - ip = nspcb.nsp_next; - if (ip == 0) { - splx(s); - return; - } - while (ip != &nspcb) { - cb = nstosppcb(ip); - ipnxt = ip->nsp_next; - if (cb == 0) - goto tpgone; - for (i = 0; i < SPPT_NTIMERS; i++) { - if (cb->s_timer[i] && --cb->s_timer[i] == 0) { - (void) spp_usrreq(cb->s_nspcb->nsp_socket, - PRU_SLOWTIMO, (struct mbuf *)0, - (struct mbuf *)i, (struct mbuf *)0, - (struct mbuf *)0); - if (ipnxt->nsp_prev != ip) - goto tpgone; - } - } - cb->s_idle++; - if (cb->s_rtt) - cb->s_rtt++; -tpgone: - ip = ipnxt; - } - spp_iss += SPP_ISSINCR/PR_SLOWHZ; /* increment iss */ - splx(s); -} -/* - * SPP timer processing. - */ -struct sppcb * -spp_timers(cb, timer) - register struct sppcb *cb; - int timer; -{ - long rexmt; - int win; - - cb->s_force = 1 + timer; - switch (timer) { - - /* - * 2 MSL timeout in shutdown went off. TCP deletes connection - * control block. - */ - case SPPT_2MSL: - printf("spp: SPPT_2MSL went off for no reason\n"); - cb->s_timer[timer] = 0; - break; - - /* - * Retransmission timer went off. Message has not - * been acked within retransmit interval. Back off - * to a longer retransmit interval and retransmit one packet. - */ - case SPPT_REXMT: - if (++cb->s_rxtshift > SPP_MAXRXTSHIFT) { - cb->s_rxtshift = SPP_MAXRXTSHIFT; - sppstat.spps_timeoutdrop++; - cb = spp_drop(cb, ETIMEDOUT); - break; - } - sppstat.spps_rexmttimeo++; - rexmt = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1; - rexmt *= spp_backoff[cb->s_rxtshift]; - SPPT_RANGESET(cb->s_rxtcur, rexmt, SPPTV_MIN, SPPTV_REXMTMAX); - cb->s_timer[SPPT_REXMT] = cb->s_rxtcur; - /* - * If we have backed off fairly 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 (cb->s_rxtshift > SPP_MAXRXTSHIFT / 4 ) { - cb->s_rttvar += (cb->s_srtt >> 2); - cb->s_srtt = 0; - } - cb->s_snxt = cb->s_rack; - /* - * If timing a packet, stop the timer. - */ - cb->s_rtt = 0; - /* - * See very long discussion in tcp_timer.c about congestion - * window and sstrhesh - */ - win = min(cb->s_swnd, (cb->s_cwnd/CUNIT)) / 2; - if (win < 2) - win = 2; - cb->s_cwnd = CUNIT; - cb->s_ssthresh = win * CUNIT; - (void) spp_output(cb, (struct mbuf *) 0); - break; - - /* - * Persistance timer into zero window. - * Force a probe to be sent. - */ - case SPPT_PERSIST: - sppstat.spps_persisttimeo++; - spp_setpersist(cb); - (void) spp_output(cb, (struct mbuf *) 0); - break; - - /* - * Keep-alive timer went off; send something - * or drop connection if idle for too long. - */ - case SPPT_KEEP: - sppstat.spps_keeptimeo++; - if (cb->s_state < TCPS_ESTABLISHED) - goto dropit; - if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) { - if (cb->s_idle >= SPPTV_MAXIDLE) - goto dropit; - sppstat.spps_keepprobe++; - (void) spp_output(cb, (struct mbuf *) 0); - } else - cb->s_idle = 0; - cb->s_timer[SPPT_KEEP] = SPPTV_KEEP; - break; - dropit: - sppstat.spps_keepdrops++; - cb = spp_drop(cb, ETIMEDOUT); - break; - } - return (cb); -} -#ifndef lint -int SppcbSize = sizeof (struct sppcb); -int NspcbSize = sizeof (struct nspcb); -#endif /* lint */ diff --git a/bsd/netns/spp_var.h b/bsd/netns/spp_var.h deleted file mode 100644 index f68a84fec..000000000 --- a/bsd/netns/spp_var.h +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1984, 1985, 1986, 1987, 1993 - * 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. - * - * @(#)spp_var.h 8.1 (Berkeley) 6/10/93 - */ - -/* - * Sp control block, one per connection - */ -struct sppcb { - struct spidp_q s_q; /* queue for out-of-order receipt */ - struct nspcb *s_nspcb; /* backpointer to internet pcb */ - u_char s_state; - u_char s_flags; -#define SF_ACKNOW 0x01 /* Ack peer immediately */ -#define SF_DELACK 0x02 /* Ack, but try to delay it */ -#define SF_HI 0x04 /* Show headers on input */ -#define SF_HO 0x08 /* Show headers on output */ -#define SF_PI 0x10 /* Packet (datagram) interface */ -#define SF_WIN 0x20 /* Window info changed */ -#define SF_RXT 0x40 /* Rxt info changed */ -#define SF_RVD 0x80 /* Calling from read usrreq routine */ - u_short s_mtu; /* Max packet size for this stream */ -/* use sequence fields in headers to store sequence numbers for this - connection */ - struct idp *s_idp; - struct sphdr s_shdr; /* prototype header to transmit */ -#define s_cc s_shdr.sp_cc /* connection control (for EM bit) */ -#define s_dt s_shdr.sp_dt /* datastream type */ -#define s_sid s_shdr.sp_sid /* source connection identifier */ -#define s_did s_shdr.sp_did /* destination connection identifier */ -#define s_seq s_shdr.sp_seq /* sequence number */ -#define s_ack s_shdr.sp_ack /* acknowledge number */ -#define s_alo s_shdr.sp_alo /* allocation number */ -#define s_dport s_idp->idp_dna.x_port /* where we are sending */ - struct sphdr s_rhdr; /* last received header (in effect!)*/ - u_short s_rack; /* their acknowledge number */ - u_short s_ralo; /* their allocation number */ - u_short s_smax; /* highest packet # we have sent */ - u_short s_snxt; /* which packet to send next */ - -/* congestion control */ -#define CUNIT 1024 /* scaling for ... */ - int s_cwnd; /* Congestion-controlled window */ - /* in packets * CUNIT */ - short s_swnd; /* == tcp snd_wnd, in packets */ - short s_smxw; /* == tcp max_sndwnd */ - /* difference of two spp_seq's can be - no bigger than a short */ - u_short s_swl1; /* == tcp snd_wl1 */ - u_short s_swl2; /* == tcp snd_wl2 */ - int s_cwmx; /* max allowable cwnd */ - int s_ssthresh; /* s_cwnd size threshhold for - * slow start exponential-to- - * linear switch */ -/* transmit timing stuff - * srtt and rttvar are stored as fixed point, for convenience in smoothing. - * srtt has 3 bits to the right of the binary point, rttvar has 2. - */ - short s_idle; /* time idle */ - short s_timer[SPPT_NTIMERS]; /* timers */ - short s_rxtshift; /* log(2) of rexmt exp. backoff */ - short s_rxtcur; /* current retransmit value */ - u_short s_rtseq; /* packet being timed */ - short s_rtt; /* timer for round trips */ - short s_srtt; /* averaged timer */ - short s_rttvar; /* variance in round trip time */ - char s_force; /* which timer expired */ - char s_dupacks; /* counter to intuit xmt loss */ - -/* out of band data */ - char s_oobflags; -#define SF_SOOB 0x08 /* sending out of band data */ -#define SF_IOOB 0x10 /* receiving out of band data */ - char s_iobc; /* input characters */ -/* debug stuff */ - u_short s_want; /* Last candidate for sending */ - char s_outx; /* exit taken from spp_output */ - char s_inx; /* exit taken from spp_input */ - u_short s_flags2; /* more flags for testing */ -#define SF_NEWCALL 0x100 /* for new_recvmsg */ -#define SO_NEWCALL 10 /* for new_recvmsg */ -}; - -#define nstosppcb(np) ((struct sppcb *)(np)->nsp_pcb) -#define sotosppcb(so) (nstosppcb(sotonspcb(so))) - -struct sppstat { - long spps_connattempt; /* connections initiated */ - long spps_accepts; /* connections accepted */ - long spps_connects; /* connections established */ - long spps_drops; /* connections dropped */ - long spps_conndrops; /* embryonic connections dropped */ - long spps_closed; /* conn. closed (includes drops) */ - long spps_segstimed; /* segs where we tried to get rtt */ - long spps_rttupdated; /* times we succeeded */ - long spps_delack; /* delayed acks sent */ - long spps_timeoutdrop; /* conn. dropped in rxmt timeout */ - long spps_rexmttimeo; /* retransmit timeouts */ - long spps_persisttimeo; /* persist timeouts */ - long spps_keeptimeo; /* keepalive timeouts */ - long spps_keepprobe; /* keepalive probes sent */ - long spps_keepdrops; /* connections dropped in keepalive */ - - long spps_sndtotal; /* total packets sent */ - long spps_sndpack; /* data packets sent */ - long spps_sndbyte; /* data bytes sent */ - long spps_sndrexmitpack; /* data packets retransmitted */ - long spps_sndrexmitbyte; /* data bytes retransmitted */ - long spps_sndacks; /* ack-only packets sent */ - long spps_sndprobe; /* window probes sent */ - long spps_sndurg; /* packets sent with URG only */ - long spps_sndwinup; /* window update-only packets sent */ - long spps_sndctrl; /* control (SYN|FIN|RST) packets sent */ - long spps_sndvoid; /* couldn't find requested packet*/ - - long spps_rcvtotal; /* total packets received */ - long spps_rcvpack; /* packets received in sequence */ - long spps_rcvbyte; /* bytes received in sequence */ - long spps_rcvbadsum; /* packets received with ccksum errs */ - long spps_rcvbadoff; /* packets received with bad offset */ - long spps_rcvshort; /* packets received too short */ - long spps_rcvduppack; /* duplicate-only packets received */ - long spps_rcvdupbyte; /* duplicate-only bytes received */ - long spps_rcvpartduppack; /* packets with some duplicate data */ - long spps_rcvpartdupbyte; /* dup. bytes in part-dup. packets */ - long spps_rcvoopack; /* out-of-order packets received */ - long spps_rcvoobyte; /* out-of-order bytes received */ - long spps_rcvpackafterwin; /* packets with data after window */ - long spps_rcvbyteafterwin; /* bytes rcvd after window */ - long spps_rcvafterclose; /* packets rcvd after "close" */ - long spps_rcvwinprobe; /* rcvd window probe packets */ - long spps_rcvdupack; /* rcvd duplicate acks */ - long spps_rcvacktoomuch; /* rcvd acks for unsent data */ - long spps_rcvackpack; /* rcvd ack packets */ - long spps_rcvackbyte; /* bytes acked by rcvd acks */ - long spps_rcvwinupd; /* rcvd window update packets */ -}; -struct spp_istat { - short hdrops; - short badsum; - short badlen; - short slotim; - short fastim; - short nonucn; - short noconn; - short notme; - short wrncon; - short bdreas; - short gonawy; - short notyet; - short lstdup; - struct sppstat newstats; -}; - -#ifdef KERNEL -struct spp_istat spp_istat; - -/* Following was struct sppstat sppstat; */ -#ifndef sppstat -#define sppstat spp_istat.newstats -#endif - -u_short spp_iss; -extern struct sppcb *spp_close(), *spp_disconnect(), - *spp_usrclosed(), *spp_timers(), *spp_drop(); -#endif - -#define SPP_ISSINCR 128 -/* - * SPP sequence numbers are 16 bit integers operated - * on with modular arithmetic. These macros can be - * used to compare such integers. - */ -#ifdef sun -short xnsCbug; -#define SSEQ_LT(a,b) ((xnsCbug = (short)((a)-(b))) < 0) -#define SSEQ_LEQ(a,b) ((xnsCbug = (short)((a)-(b))) <= 0) -#define SSEQ_GT(a,b) ((xnsCbug = (short)((a)-(b))) > 0) -#define SSEQ_GEQ(a,b) ((xnsCbug = (short)((a)-(b))) >= 0) -#else -#define SSEQ_LT(a,b) (((short)((a)-(b))) < 0) -#define SSEQ_LEQ(a,b) (((short)((a)-(b))) <= 0) -#define SSEQ_GT(a,b) (((short)((a)-(b))) > 0) -#define SSEQ_GEQ(a,b) (((short)((a)-(b))) >= 0) -#endif diff --git a/bsd/nfs/krpc.h b/bsd/nfs/krpc.h index f4e4701a1..16fe898a8 100644 --- a/bsd/nfs/krpc.h +++ b/bsd/nfs/krpc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -27,8 +27,14 @@ * */ +#ifndef __NFS_KRPC_H__ +#define __NFS_KRPC_H__ + +#include + #include +#ifdef __APPLE_API_PRIVATE int krpc_call __P((struct sockaddr_in *sin, u_int prog, u_int vers, u_int func, struct mbuf **data, struct sockaddr_in **from)); @@ -59,3 +65,5 @@ int krpc_portmap __P((struct sockaddr_in *sin, #define BOOTPARAM_WHOAMI 1 #define BOOTPARAM_GETFILE 2 +#endif /* __APPLE_API_PRIVATE */ +#endif /* __NFS_KRPC_H__ */ diff --git a/bsd/nfs/nfs.h b/bsd/nfs/nfs.h index c98c92458..6d5967414 100644 --- a/bsd/nfs/nfs.h +++ b/bsd/nfs/nfs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -62,6 +62,9 @@ #ifndef _NFS_NFS_H_ #define _NFS_NFS_H_ +#include + +#ifdef __APPLE_API_PRIVATE /* * Tunable constants for nfs */ @@ -842,5 +845,6 @@ extern uint nfstracemask; /* 32 bits - trace points over 31 are unconditional */ #endif /* NFSDIAG */ #endif /* KERNEL */ +#endif /* __APPLE_API_PRIVATE */ #endif diff --git a/bsd/nfs/nfs_bio.c b/bsd/nfs/nfs_bio.c index 3c4473b44..7a7394c78 100644 --- a/bsd/nfs/nfs_bio.c +++ b/bsd/nfs/nfs_bio.c @@ -100,6 +100,7 @@ static struct buf *nfs_getcacheblk __P((struct vnode *vp, daddr_t bn, int size, extern int nfs_numasync; extern struct nfsstats nfsstats; +extern int nbdwrite; /* * Vnode op for read using bio @@ -848,6 +849,22 @@ nfs_getcacheblk(vp, bn, size, p, operation) /*due to getblk/vm interractions, use vm page size or less values */ int biosize = min(vp->v_mount->mnt_stat.f_iosize, PAGE_SIZE); + if (nbdwrite > ((nbuf/4)*3) && operation == BLK_WRITE) { +#define __BUFFERS_RECLAIMED 2 + struct buf *tbp[__BUFFERS_RECLAIMED]; + int i; + + /* too many delayed writes, try to free up some buffers */ + for (i = 0; i < __BUFFERS_RECLAIMED; i++) + tbp[i] = geteblk(512); + + /* Yield to IO thread */ + (void)tsleep((caddr_t)&nbdwrite, PCATCH, "nbdwrite", 1); + + for (i = (__BUFFERS_RECLAIMED - 1); i >= 0; i--) + brelse(tbp[i]); + } + if (nmp->nm_flag & NFSMNT_INT) { bp = getblk(vp, bn, size, PCATCH, 0, operation); while (bp == (struct buf *)0) { @@ -1169,7 +1186,7 @@ nfs_doio(bp, cr, p) bp->b_validend = diff; } else bp->b_validend = bp->b_bcount; -#if 1 /* USV + JOE [ */ + if (bp->b_validend < bp->b_bufsize) { /* * we're about to release a partial buffer after a @@ -1185,7 +1202,6 @@ nfs_doio(bp, cr, p) FSDBG(258, bp->b_validend, bp->b_bufsize - bp->b_validend, 0, 2); } -#endif /* ] USV + JOE */ } if (p && (vp->v_flag & VTEXT) && (((nmp->nm_flag & NFSMNT_NQNFS) && @@ -1279,7 +1295,6 @@ nfs_doio(bp, cr, p) CLR(bp->b_flags, B_INVAL | B_NOCACHE); if (!ISSET(bp->b_flags, B_DELWRI)) { - extern int nbdwrite; SET(bp->b_flags, B_DELWRI); nbdwrite++; } @@ -1304,7 +1319,7 @@ nfs_doio(bp, cr, p) np->n_flag |= NWRITEERR; } bp->b_dirtyoff = bp->b_dirtyend = 0; -#if 1 /* JOE */ + /* * validoff and validend represent the real data present * in this buffer if validoff is non-zero, than we have @@ -1331,11 +1346,9 @@ nfs_doio(bp, cr, p) } else SET(bp->b_flags, B_INVAL); } -#endif } } else { -#if 1 /* JOE */ if (bp->b_validoff || (bp->b_validend < bp->b_bufsize && (off_t)bp->b_blkno * DEV_BSIZE + bp->b_validend != @@ -1346,7 +1359,6 @@ nfs_doio(bp, cr, p) FSDBG(260, bp->b_validoff, bp->b_validend, bp->b_bufsize, bp->b_bcount); } -#endif bp->b_resid = 0; biodone(bp); FSDBG_BOT(256, bp->b_validoff, bp->b_validend, bp->b_bufsize, diff --git a/bsd/nfs/nfs_boot.c b/bsd/nfs/nfs_boot.c index f7849b02d..0590f4c49 100644 --- a/bsd/nfs/nfs_boot.c +++ b/bsd/nfs/nfs_boot.c @@ -152,45 +152,32 @@ int nfs_boot_init(nd, procp) * (This happens to be the way Sun does it too.) */ -extern int bootp(struct ifnet * ifp, struct in_addr * iaddr_p, int max_retry, - struct in_addr * netmask_p, struct in_addr * router_p, - struct proc * procp); - /* bootparam RPC */ static int bp_whoami __P((struct sockaddr_in *bpsin, struct in_addr *my_ip, struct in_addr *gw_ip)); static int bp_getfile __P((struct sockaddr_in *bpsin, char *key, struct sockaddr_in *mdsin, char *servname, char *path)); -static boolean_t path_getfile __P((char * image_path, - struct sockaddr_in * sin_p, - char * serv_name, char * pathname)); - -static __inline__ -u_long iptohl(struct in_addr ip) -{ - return (ntohl(ip.s_addr)); -} - -static __inline__ boolean_t -same_subnet(struct in_addr addr1, struct in_addr addr2, struct in_addr mask) -{ - u_long m = iptohl(mask); - if ((iptohl(addr1) & m) != (iptohl(addr2) & m)) - return (FALSE); - return (TRUE); -} - /* mountd RPC */ static int md_mount __P((struct sockaddr_in *mdsin, char *path, u_char *fh)); /* other helpers */ -static void get_file_handle __P((char *pathname, struct nfs_dlmount *ndmntp)); +static int get_file_handle __P((char *pathname, struct nfs_dlmount *ndmntp)); + #define IP_FORMAT "%d.%d.%d.%d" #define IP_CH(ip) ((u_char *)ip) #define IP_LIST(ip) IP_CH(ip)[0],IP_CH(ip)[1],IP_CH(ip)[2],IP_CH(ip)[3] + +extern boolean_t +netboot_iaddr(struct in_addr * iaddr_p); + +extern boolean_t +netboot_rootpath(struct in_addr * server_ip, + char * name, int name_len, + char * path, int path_len); + /* * Called with an empty nfs_diskless struct to be filled in. */ @@ -199,388 +186,123 @@ nfs_boot_init(nd, procp) struct nfs_diskless *nd; struct proc *procp; { - char * booter_path = NULL; - boolean_t do_bpwhoami = TRUE; - boolean_t do_bpgetfile = TRUE; - struct ifreq ireq; - struct in_addr my_ip; - struct sockaddr_in bp_sin; - struct sockaddr_in *sin; - struct ifnet *ifp; - struct in_addr gw_ip; - struct socket *so; - struct in_addr my_netmask; - int error; - char * root_path = NULL; + struct sockaddr_in bp_sin; + boolean_t do_bpwhoami = TRUE; + boolean_t do_bpgetfile = TRUE; + int error = 0; + struct in_addr my_ip; + char * root_path = NULL; + struct sockaddr_in * sin_p; + + /* by this point, networking must already have been configured */ + if (netboot_iaddr(&my_ip) == FALSE) { + printf("nfs_boot: networking is not initialized\n"); + error = ENXIO; + goto failed; + } - MALLOC(booter_path, char *, MAXPATHLEN, M_TEMP, M_WAITOK); + /* get the root path information */ MALLOC(root_path, char *, MAXPATHLEN, M_TEMP, M_WAITOK); - - /* booter-supplied path */ - if (!PE_parse_boot_arg("rp", booter_path) - && !PE_parse_boot_arg("rootpath", booter_path)) { - booter_path[0] = 0; + sin_p = &nd->nd_root.ndm_saddr; + bzero((caddr_t)sin_p, sizeof(*sin_p)); + sin_p->sin_len = sizeof(*sin_p); + sin_p->sin_family = AF_INET; + if (netboot_rootpath(&sin_p->sin_addr, nd->nd_root.ndm_host, + sizeof(nd->nd_root.ndm_host), + root_path, MAXPATHLEN) == TRUE) { + do_bpgetfile = FALSE; + do_bpwhoami = FALSE; } - - root_path[0] = 0; - - gw_ip.s_addr = 0; - - /* clear out the request structure */ - bzero(&ireq, sizeof(ireq)); - - /* - * Find an interface, rarp for its ip address, stuff it, the - * implied broadcast addr, and netmask into a nfs_diskless struct. - * - * This was moved here from nfs_vfsops.c because this procedure - * would be quite different if someone decides to write (i.e.) a - * BOOTP version of this file (might not use RARP, etc.) - */ + nd->nd_private.ndm_saddr.sin_addr.s_addr = 0; thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); - /* - * Find a network interface. - */ - ifp = NULL; - { /* if the root device is set, use it */ - extern char rootdevice[]; - if (rootdevice[0]) - ifp = ifunit(rootdevice); - } - if (ifp == NULL) { /* search for network device */ - /* for (ifp = ifnet; ifp; ifp = ifp->if_next)*/ - TAILQ_FOREACH(ifp, &ifnet, if_link) - if ((ifp->if_flags & - (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0) - break; - } - if (ifp == NULL) - panic("nfs_boot: no suitable interface"); - sprintf(ireq.ifr_name, "%s%d", ifp->if_name, ifp->if_unit); - printf("nfs_boot: using network interface '%s'\n", ireq.ifr_name); - - /* - * Bring up the interface. - */ - if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0)) != 0) - panic("nfs_boot: socreate, error=%d", error); - ireq.ifr_flags = ifp->if_flags | IFF_UP; - error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)&ireq, procp); - if (error) - panic("nfs_boot: SIFFLAGS, error=%d", error); - -#define DO_BOOTP -#ifdef DO_BOOTP - { /* use BOOTP to retrieve IP address, netmask and router */ - struct sockaddr_in sockin; - struct in_addr router; - struct in_addr netmask; - - my_ip.s_addr = 0; - netmask.s_addr = 0; - router.s_addr = 0; - sockin.sin_family = AF_INET; - sockin.sin_len = sizeof(sockin); - sockin.sin_addr.s_addr = 0; -#define RETRY_COUNT 32 - while ((error = bootp(ifp, &my_ip, RETRY_COUNT, - &netmask, &router, procp))) { - if (error == ETIMEDOUT) - printf("nfs_boot: BOOTP timed out, retrying...\n"); - - else { - printf("nfs_boot: bootp() failed, error = %d\n", error); - panic("nfs_boot"); - } - } - /* clear the netmask */ - ((struct sockaddr_in *)&ireq.ifr_addr)->sin_addr.s_addr = 0; - error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)&ireq, procp); - if (error) - printf("nfs_boot: SIOCSIFNETMASK failed: %d\n", error); - - if (netmask.s_addr) { - /* set our new subnet mask */ - sockin.sin_addr = netmask; - *((struct sockaddr_in *)&ireq.ifr_addr) = sockin; - error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)&ireq, procp); - if (error) - printf("nfs_boot: SIOCSIFNETMASK failed: %d\n", error); - } - - /* set our address */ - sockin.sin_addr = my_ip; - *((struct sockaddr_in *)&ireq.ifr_addr) = sockin; - error = ifioctl(so, SIOCSIFADDR, (caddr_t)&ireq, procp); - if (error) { - printf("SIOCSIFADDR failed: %d\n", error); - panic("nfs_boot.c"); - } - printf("nfs_boot: IP address " IP_FORMAT, IP_LIST(&my_ip)); - if (netmask.s_addr) - printf(" netmask " IP_FORMAT, IP_LIST(&netmask)); - if (router.s_addr) { - gw_ip = router; - printf(" router " IP_FORMAT, IP_LIST(&router)); - } - printf("\n"); - } -#else - /* - * Do RARP for the interface address. - */ - if ((error = revarpwhoami(&my_ip, ifp)) != 0) - panic("revarp failed, error=%d", error); - printf("nfs_boot: client_addr=0x%x\n", ntohl(my_ip.s_addr)); - - /* - * Do enough of ifconfig(8) so that the chosen interface - * can talk to the servers. (just set the address) - */ - sin = (struct sockaddr_in *)&ireq.ifr_addr; - bzero((caddr_t)sin, sizeof(*sin)); - sin->sin_len = sizeof(*sin); - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = my_ip.s_addr; - error = ifioctl(so, SIOCSIFADDR, (caddr_t)&ireq, procp); - if (error) - panic("nfs_boot: set if addr, error=%d", error); -#endif DO_BOOTP - - /* need netmask to determine whether NFS server local */ - sin = (struct sockaddr_in *)&ireq.ifr_addr; - bzero((caddr_t)sin, sizeof(*sin)); - sin->sin_len = sizeof(*sin); - sin->sin_family = AF_INET; - error = ifioctl(so, SIOCGIFNETMASK, (caddr_t)&ireq, procp); - if (error) - panic("nfs_boot: SIOCGIFNETMASK error=%d", error); - my_netmask = sin->sin_addr; - - soclose(so); - - /* check for a booter-specified path */ - if (booter_path[0]) { - nd->nd_root.ndm_saddr.sin_addr.s_addr = 0; - nd->nd_private.ndm_saddr.sin_addr.s_addr = 0; - if (path_getfile(booter_path, &nd->nd_root.ndm_saddr, - nd->nd_root.ndm_host, root_path)) { - do_bpgetfile = FALSE; - printf("nfs_boot: using booter-supplied path '%s'\n", - booter_path); - if (same_subnet(nd->nd_root.ndm_saddr.sin_addr, - my_ip, my_netmask) - || gw_ip.s_addr) { - do_bpwhoami = FALSE; - } - else { - /* do bpwhoami to attempt to get the router */ - } - } - else { - printf("nfs_boot: ignoring badly formed bootpath '%s'\n", - booter_path); - } - } - if (do_bpwhoami) { - /* - * Get client name and gateway address. - * RPC: bootparam/whoami - * Use the old broadcast address for the WHOAMI - * call because we do not yet know our netmask. - * The server address returned by the WHOAMI call - * is used for all subsequent booptaram RPCs. - */ - bzero((caddr_t)&bp_sin, sizeof(bp_sin)); - bp_sin.sin_len = sizeof(bp_sin); - bp_sin.sin_family = AF_INET; - bp_sin.sin_addr.s_addr = INADDR_BROADCAST; - hostnamelen = MAXHOSTNAMELEN; - - { /* bpwhoami also returns gateway IP address */ - struct in_addr router; - + /* + * Get client name and gateway address. + * RPC: bootparam/whoami + * Use the old broadcast address for the WHOAMI + * call because we do not yet know our netmask. + * The server address returned by the WHOAMI call + * is used for all subsequent booptaram RPCs. + */ + bzero((caddr_t)&bp_sin, sizeof(bp_sin)); + bp_sin.sin_len = sizeof(bp_sin); + bp_sin.sin_family = AF_INET; + bp_sin.sin_addr.s_addr = INADDR_BROADCAST; + hostnamelen = MAXHOSTNAMELEN; router.s_addr = 0; error = bp_whoami(&bp_sin, &my_ip, &router); if (error) { - printf("nfs_boot: bootparam whoami, error=%d", error); - panic("nfs_boot: bootparam whoami\n"); + printf("nfs_boot: bootparam whoami, error=%d", error); + goto failed; } - /* if not already set by BOOTP, use the one from BPWHOAMI */ - if (gw_ip.s_addr == 0) - gw_ip = router; - } - printf("nfs_boot: BOOTPARAMS server " IP_FORMAT "\n", - IP_LIST(&bp_sin.sin_addr)); - printf("nfs_boot: hostname %s\n", hostname); - } -#define NFS_BOOT_GATEWAY 1 -#ifdef NFS_BOOT_GATEWAY - /* - * DWS 2/18/1999 - * The comment below does not apply to gw_ip discovered - * via BOOTP (see DO_BOOTP loop above) since BOOTP servers - * are supposed to be more trustworthy. - */ - /* - * XXX - This code is conditionally compiled only because - * many bootparam servers (in particular, SunOS 4.1.3) - * always set the gateway address to their own address. - * The bootparam server is not necessarily the gateway. - * We could just believe the server, and at worst you would - * need to delete the incorrect default route before adding - * the correct one, but for simplicity, ignore the gateway. - * If your server is OK, you can turn on this option. - * - * If the gateway address is set, add a default route. - * (The mountd RPCs may go across a gateway.) - */ - if (gw_ip.s_addr) { - struct sockaddr dst, gw, mask; - /* Destination: (default) */ - bzero((caddr_t)&dst, sizeof(dst)); - dst.sa_len = sizeof(dst); - dst.sa_family = AF_INET; - /* Gateway: */ - bzero((caddr_t)&gw, sizeof(gw)); - sin = (struct sockaddr_in *)&gw; - sin->sin_len = sizeof(gw); - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = gw_ip.s_addr; - /* Mask: (zero length) */ - bzero(&mask, sizeof(mask)); - printf("nfs_boot: adding default route " IP_FORMAT "\n", - IP_LIST(&gw_ip)); - /* add, dest, gw, mask, flags, 0 */ - error = rtrequest(RTM_ADD, &dst, (struct sockaddr *)&gw, - &mask, (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL); - if (error) - printf("nfs_boot: add route, error=%d\n", error); + printf("nfs_boot: BOOTPARAMS server " IP_FORMAT "\n", + IP_LIST(&bp_sin.sin_addr)); + printf("nfs_boot: hostname %s\n", hostname); } -#endif if (do_bpgetfile) { - error = bp_getfile(&bp_sin, "root", &nd->nd_root.ndm_saddr, - nd->nd_root.ndm_host, root_path); - if (error) { - printf("nfs_boot: bootparam get root: %d\n", error); - panic("nfs_boot: bootparam get root"); - } + error = bp_getfile(&bp_sin, "root", &nd->nd_root.ndm_saddr, + nd->nd_root.ndm_host, root_path); + if (error) { + printf("nfs_boot: bootparam get root: %d\n", error); + goto failed; + } + } + + error = get_file_handle(root_path, &nd->nd_root); + if (error) { + printf("nfs_boot: get_file_handle() root failed, %d\n", error); + goto failed; } - - get_file_handle(root_path, &nd->nd_root); #if !defined(NO_MOUNT_PRIVATE) if (do_bpgetfile) { /* get private path */ - char * private_path = NULL; - - MALLOC(private_path, char *, MAXPATHLEN, M_TEMP, M_WAITOK); - error = bp_getfile(&bp_sin, "private", - &nd->nd_private.ndm_saddr, - nd->nd_private.ndm_host, private_path); - if (!error) { - char * check_path = NULL; - - MALLOC(check_path, char *, MAXPATHLEN, M_TEMP, M_WAITOK); - sprintf(check_path, "%s/private", root_path); - if ((nd->nd_root.ndm_saddr.sin_addr.s_addr - == nd->nd_private.ndm_saddr.sin_addr.s_addr) - && (strcmp(check_path, private_path) == 0)) { - /* private path is prefix of root path, don't mount */ - nd->nd_private.ndm_saddr.sin_addr.s_addr = 0; + char * private_path = NULL; + + MALLOC(private_path, char *, MAXPATHLEN, M_TEMP, M_WAITOK); + error = bp_getfile(&bp_sin, "private", + &nd->nd_private.ndm_saddr, + nd->nd_private.ndm_host, private_path); + if (!error) { + char * check_path = NULL; + + MALLOC(check_path, char *, MAXPATHLEN, M_TEMP, M_WAITOK); + sprintf(check_path, "%s/private", root_path); + if ((nd->nd_root.ndm_saddr.sin_addr.s_addr + == nd->nd_private.ndm_saddr.sin_addr.s_addr) + && (strcmp(check_path, private_path) == 0)) { + /* private path is prefix of root path, don't mount */ + nd->nd_private.ndm_saddr.sin_addr.s_addr = 0; + } + else { + error = get_file_handle(private_path, + &nd->nd_private); + if (error) { + printf("nfs_boot: get_file_handle() private failed, %d\n", error); + goto failed; + } + } + _FREE(check_path, M_TEMP); } - else { - get_file_handle(private_path, &nd->nd_private); + else { + /* private key not defined, don't mount */ + nd->nd_private.ndm_saddr.sin_addr.s_addr = 0; } - _FREE(check_path, M_TEMP); - } - else { - /* private key not defined, don't mount */ - nd->nd_private.ndm_saddr.sin_addr.s_addr = 0; - } - _FREE(private_path, M_TEMP); + _FREE(private_path, M_TEMP); + } + else { + error = 0; } #endif NO_MOUNT_PRIVATE + failed: thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); - _FREE(booter_path, M_TEMP); _FREE(root_path, M_TEMP); - return (0); + return (error); } -int -inet_aton(char * cp, struct in_addr * pin) -{ - u_char * b = (char *)pin; - int i; - char * p; - - for (p = cp, i = 0; i < 4; i++) { - u_long l = strtoul(p, 0, 0); - if (l > 255) - return (FALSE); - b[i] = l; - p = strchr(p, '.'); - if (i < 3 && p == NULL) - return (FALSE); - p++; - } - return (TRUE); -} - -/* - * Function: parse_image_path - * Purpose: - * Parse a string of the form "::" into - * the given ip address and host and pathnames. - * Example: - * "17.202.16.17:seaport:/release/.images/Image9/CurrentHera" - */ -static __inline__ boolean_t -parse_image_path(char * c, struct in_addr * iaddr_p, char * hostname, - char * pathname) -{ - char * d; - char * p; -#define TMP_SIZE 128 - char tmp[TMP_SIZE]; - - p = strchr(c, ':'); - if (p == NULL) - return (FALSE); - if ((p - c) >= TMP_SIZE) - return (FALSE); - strncpy(tmp, c, p - c); - tmp[p - c] = 0; - if (inet_aton(tmp, iaddr_p) != 1) - return (FALSE); - p++; - d = strchr(p, ':'); - if (d == NULL) - return (FALSE); - strncpy(hostname, p, d - p); - hostname[d - p] = 0; - d++; - strcpy(pathname, d); - return (TRUE); -} - -static boolean_t -path_getfile(char * image_path, struct sockaddr_in * sin_p, - char * serv_name, char * pathname) -{ - bzero((caddr_t)sin_p, sizeof(*sin_p)); - sin_p->sin_len = sizeof(*sin_p); - sin_p->sin_family = AF_INET; - if (parse_image_path(image_path, &sin_p->sin_addr, serv_name, pathname) - == FALSE) - return (FALSE); - return (TRUE); -} - -static void +static int get_file_handle(pathname, ndmntp) char *pathname; /* path on server */ struct nfs_dlmount *ndmntp; /* output */ @@ -594,7 +316,7 @@ get_file_handle(pathname, ndmntp) */ error = md_mount(&ndmntp->ndm_saddr, pathname, ndmntp->ndm_fh); if (error) - panic("nfs_boot: mountd, error=%d", error); + return (error); /* Construct remote path (for getmntinfo(3)) */ dp = ndmntp->ndm_host; @@ -604,6 +326,7 @@ get_file_handle(pathname, ndmntp) for (sp = pathname; *sp && dp < endp;) *dp++ = *sp++; *dp = '\0'; + return (0); } diff --git a/bsd/nfs/nfs_socket.c b/bsd/nfs/nfs_socket.c index 9aaf35b99..ef42d4683 100644 --- a/bsd/nfs/nfs_socket.c +++ b/bsd/nfs/nfs_socket.c @@ -81,6 +81,7 @@ #include #include +#include #include #include @@ -984,7 +985,7 @@ nfs_reply(myrep) /* * Bailout asap if nfsmount struct gone (unmounted). */ - if (!myrep->r_nmp) { + if (!myrep->r_nmp || !nmp->nm_so) { FSDBG(530, myrep->r_xid, myrep, nmp, -2); return (ECONNABORTED); } @@ -1256,7 +1257,7 @@ kerbauth: m = nfsm_rpchead(cred, nmp->nm_flag, procnum, auth_type, auth_len, auth_str, verf_len, verf_str, mrest, mrest_len, &mheadend, &xid); if (xidp) - *xidp = xid + ((u_int64_t)nfs_xidwrap << 32); + *xidp = ntohl(xid) + ((u_int64_t)nfs_xidwrap << 32); if (auth_str) _FREE(auth_str, M_TEMP); @@ -1918,12 +1919,16 @@ nfs_sigintr(nmp, rep, p) register struct proc *p; { + struct uthread *ut; + + ut = (struct uthread *)get_bsdthread_info(current_act()); + if (rep && (rep->r_flags & R_SOFTTERM)) return (EINTR); if (!(nmp->nm_flag & NFSMNT_INT)) return (0); - if (p && p->p_siglist && - (((p->p_siglist & ~p->p_sigmask) & ~p->p_sigignore) & + if (p && ut && ut->uu_siglist && + (((ut->uu_siglist & ~ut->uu_sigmask) & ~p->p_sigignore) & NFSINT_SIGMASK)) return (EINTR); return (0); diff --git a/bsd/nfs/nfs_subs.c b/bsd/nfs/nfs_subs.c index cea8b0046..fbd22ed2e 100644 --- a/bsd/nfs/nfs_subs.c +++ b/bsd/nfs/nfs_subs.c @@ -1330,7 +1330,7 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper, dontshrink, xidp) * information. */ np = VTONFS(vp); - if (*xidp < np->n_xid) { +if (*xidp < np->n_xid) { /* * We have already updated attributes with a response from * a later request. The attributes we have here are probably diff --git a/bsd/nfs/nfs_syscalls.c b/bsd/nfs/nfs_syscalls.c index 41f1333ad..852257d43 100644 --- a/bsd/nfs/nfs_syscalls.c +++ b/bsd/nfs/nfs_syscalls.c @@ -850,7 +850,7 @@ nfssvc_iod(p) /* stuff myiod into uthread to get off local stack for continuation */ - ut = get_bsdthread_info(current_act()); + ut = (struct uthread *)get_bsdthread_info(current_act()); ut->uu_state.uu_nfs_myiod = myiod; /* squirrel away for continuation */ nfssvc_iod_continue(0); @@ -873,7 +873,7 @@ nfssvc_iod_continue(error) /* * real myiod is stored in uthread, recover it */ - ut = get_bsdthread_info(current_act()); + ut = (struct uthread *)get_bsdthread_info(current_act()); myiod = ut->uu_state.uu_nfs_myiod; p = current_proc(); @@ -901,11 +901,7 @@ nfssvc_iod_continue(error) nfs_numasync--; if (error == EINTR || error == ERESTART) error = 0; -#if defined (__i386__) - return(error); -#else unix_syscall_return(error); -#endif } while ((bp = nmp->nm_bufq.tqh_first) != NULL) { /* Take one off the front of the list */ diff --git a/bsd/nfs/nfs_vfsops.c b/bsd/nfs/nfs_vfsops.c index 8281df111..44faf37c5 100644 --- a/bsd/nfs/nfs_vfsops.c +++ b/bsd/nfs/nfs_vfsops.c @@ -418,10 +418,14 @@ nfs_mountroot() /* * Call nfs_boot_init() to fill in the nfs_diskless struct. - * Side effect: Finds and configures a network interface. + * Note: networking must already have been configured before + * we're called. */ bzero((caddr_t) &nd, sizeof(nd)); - nfs_boot_init(&nd, procp); + error = nfs_boot_init(&nd, procp); + if (error) { + panic("nfs_boot_init failed with %d\n", error); + } /* * Create the root mount point. @@ -431,7 +435,7 @@ nfs_mountroot() #else if (error = nfs_mount_diskless(&nd.nd_root, "/", NULL, &vp, &mp)) { #endif /* NO_MOUNT_PRIVATE */ - return(error); + panic("nfs_mount_diskless failed with %d\n", error); } printf("root on %s\n", (char *)&nd.nd_root.ndm_host); @@ -445,8 +449,9 @@ nfs_mountroot() if (nd.nd_private.ndm_saddr.sin_addr.s_addr) { error = nfs_mount_diskless_private(&nd.nd_private, "/private", NULL, &vppriv, &mppriv); - if (error) - return(error); + if (error) { + panic("nfs_mount_diskless failed with %d\n", error); + } printf("private on %s\n", (char *)&nd.nd_private.ndm_host); simple_lock(&mountlist_slock); @@ -496,7 +501,7 @@ nfs_mount_diskless(ndmntp, mntname, mntflag, vpp, mpp) args.addrlen = args.addr->sa_len; args.sotype = SOCK_DGRAM; args.fh = ndmntp->ndm_fh; - args.fhsize = NFSX_V2FH; + args.fhsize = NFSX_V2FH; /* need to try v3, then v2 */ args.hostname = ndmntp->ndm_host; args.flags = NFSMNT_RESVPORT; diff --git a/bsd/nfs/nfs_vnops.c b/bsd/nfs/nfs_vnops.c index dd87f5401..2d516acf2 100644 --- a/bsd/nfs/nfs_vnops.c +++ b/bsd/nfs/nfs_vnops.c @@ -105,9 +105,11 @@ #include #include #include -#include #include +#include +#include + #include #define FSDBG(A, B, C, D, E) \ @@ -782,8 +784,7 @@ nfs_close(ap) error = nfs_flush(vp, ap->a_cred, MNT_WAIT, ap->a_p, 1); /* * We cannot clear the NMODIFIED bit in np->n_flag due to - * potential races with other processes (and because - * the commit arg is 0 in the nfs_flush call above.) + * potential races with other processes * NMODIFIED is a hint */ /* np->n_flag &= ~NMODIFIED; */ @@ -1904,9 +1905,8 @@ nfs_remove(ap) register struct vnode *dvp = ap->a_dvp; register struct componentname *cnp = ap->a_cnp; register struct nfsnode *np = VTONFS(vp); - int error = 0; + int error = 0, gofree = 0; struct vattr vattr; - int file_deleted = 0; #if DIAGNOSTIC if ((cnp->cn_flags & HASBUF) == 0) @@ -1914,11 +1914,26 @@ nfs_remove(ap) if (vp->v_usecount < 1) panic("nfs_remove: bad v_usecount"); #endif - if (vp->v_usecount == 1 || - (UBCISVALID(vp)&&(vp->v_usecount==2)) || - (np->n_sillyrename && - VOP_GETATTR(vp, &vattr, cnp->cn_cred, cnp->cn_proc) == 0 && - vattr.va_nlink > 1)) { + + if (UBCISVALID(vp)) { + /* regular files */ + if (UBCINFOEXISTS(vp)) + gofree = (ubc_isinuse(vp, 1)) ? 0 : 1; + else { + /* dead or dying vnode.With vnode locking panic instead of error */ + FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI); + vput(dvp); + vput(vp); + return (EIO); + } + } else { + /* UBC not in play */ + if (vp->v_usecount == 1) + gofree = 1; + } + if (gofree || (np->n_sillyrename && + VOP_GETATTR(vp, &vattr, cnp->cn_cred, cnp->cn_proc) == 0 && + vattr.va_nlink > 1)) { /* * Purge the name cache so that the chance of a lookup for * the name succeeding while the remove is in progress is @@ -1946,7 +1961,6 @@ nfs_remove(ap) */ if (error == ENOENT) error = 0; - file_deleted = 1; } else if (!np->n_sillyrename) { error = nfs_sillyrename(dvp, vp, cnp); } @@ -1956,10 +1970,7 @@ nfs_remove(ap) vput(dvp); VOP_UNLOCK(vp, 0, cnp->cn_proc); - - if (file_deleted) - ubc_uncache(vp); - + ubc_uncache(vp); vrele(vp); return (error); @@ -2034,7 +2045,7 @@ nfs_rename(ap) register struct vnode *tdvp = ap->a_tdvp; register struct componentname *tcnp = ap->a_tcnp; register struct componentname *fcnp = ap->a_fcnp; - int error; + int error, purged=0, inuse=0; #if DIAGNOSTIC if ((tcnp->cn_flags & HASBUF) == 0 || @@ -2045,6 +2056,8 @@ nfs_rename(ap) if ((fvp->v_mount != tdvp->v_mount) || (tvp && (fvp->v_mount != tvp->v_mount))) { error = EXDEV; + if (tvp) + VOP_UNLOCK(tvp, 0, tcnp->cn_proc); goto out; } @@ -2052,12 +2065,37 @@ nfs_rename(ap) * If the tvp exists and is in use, sillyrename it before doing the * rename of the new file over it. * XXX Can't sillyrename a directory. + * Don't sillyrename if source and target are same vnode (hard + * links or case-variants) */ - if (tvp && (tvp->v_usecount>(UBCISVALID(tvp) ? 2 : 1)) && - !VTONFS(tvp)->n_sillyrename && - tvp->v_type != VDIR && !nfs_sillyrename(tdvp, tvp, tcnp)) { - vput(tvp); - tvp = NULL; + if (tvp && tvp != fvp) { + if (UBCISVALID(tvp)) { + /* regular files */ + if (UBCINFOEXISTS(tvp)) + inuse = (ubc_isinuse(tvp, 1)) ? 1 : 0; + else { + /* dead or dying vnode.With vnode locking panic instead of error */ + error = EIO; + VOP_UNLOCK(tvp, 0, tcnp->cn_proc); + goto out; + } + } else { + /* UBC not in play */ + if (tvp->v_usecount > 1) + inuse = 1; + } + } + if (inuse && !VTONFS(tvp)->n_sillyrename && tvp->v_type != VDIR) { + if (error = nfs_sillyrename(tdvp, tvp, tcnp)) { + /* sillyrename failed. Instead of pressing on, return error */ + goto out; /* should not be ENOENT. */ + } else { + /* sillyrename succeeded.*/ + VOP_UNLOCK(tvp, 0, tcnp->cn_proc); + ubc_uncache(tvp); /* get the nfs turd file to disappear */ + vrele(tvp); + tvp = NULL; + } } error = nfs_renamerpc(fdvp, fcnp->cn_nameptr, fcnp->cn_namelen, @@ -2065,17 +2103,29 @@ nfs_rename(ap) tcnp->cn_proc); if (fvp->v_type == VDIR) { - if (tvp != NULL && tvp->v_type == VDIR) + if (tvp != NULL && tvp->v_type == VDIR) { cache_purge(tdvp); + if (tvp == tdvp) + purged = 1; + } cache_purge(fdvp); } + + cache_purge(fvp); + if (tvp) { + if (!purged) + cache_purge(tvp); + VOP_UNLOCK(tvp, 0, tcnp->cn_proc); + ubc_uncache(tvp); /* get the nfs turd file to disappear */ + } + out: if (tdvp == tvp) vrele(tdvp); else vput(tdvp); if (tvp) - vput(tvp); + vrele(tvp); /* already unlocked */ vrele(fdvp); vrele(fvp); /* @@ -3304,7 +3354,7 @@ again: for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) { nbp = bp->b_vnbufs.le_next; - /* XXX nbp aok if we sleep in this loop? */ + FSDBG(520, bp, bp->b_flags, bvecpos, bp->b_bufsize); FSDBG(520, bp->b_validoff, bp->b_validend, bp->b_dirtyoff, bp->b_dirtyend); @@ -3313,6 +3363,8 @@ again: if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT)) != (B_DELWRI | B_NEEDCOMMIT)) continue; + + bremfree(bp); SET(bp->b_flags, B_BUSY); /* * we need a upl to see if the page has been @@ -3342,7 +3394,10 @@ again: */ bp->b_dirtyoff = bp->b_validoff; bp->b_dirtyend = bp->b_validend; - CLR(bp->b_flags, B_BUSY | B_NEEDCOMMIT); + CLR(bp->b_flags, B_NEEDCOMMIT); + /* blocking calls were made, re-evaluate nbp */ + nbp = bp->b_vnbufs.le_next; + brelse(bp); /* XXX may block. Is using nbp ok??? */ continue; } if (!ISSET(bp->b_flags, B_PAGELIST)) { @@ -3350,7 +3405,10 @@ again: SET(bp->b_flags, B_PAGELIST); ubc_upl_map(upl, (vm_address_t *)&bp->b_data); } - bremfree(bp); + + /* blocking calls were made, re-evaluate nbp */ + nbp = bp->b_vnbufs.le_next; + /* * Work out if all buffers are using the same cred * so we can deal with them all with one commit. @@ -3421,11 +3479,18 @@ again: if (retv) { brelse(bp); } else { + int oldflags = bp->b_flags; + s = splbio(); vp->v_numoutput++; SET(bp->b_flags, B_ASYNC); CLR(bp->b_flags, (B_READ|B_DONE|B_ERROR|B_DELWRI)); + if (ISSET(oldflags, B_DELWRI)) { + extern int nbdwrite; + nbdwrite--; + wakeup((caddr_t)&nbdwrite); + } bp->b_dirtyoff = bp->b_dirtyend = 0; reassignbuf(bp, vp); splx(s); @@ -3792,6 +3857,7 @@ nfs_writebp(bp, force) if (ISSET(oldflags, B_DELWRI)) { extern int nbdwrite; nbdwrite--; + wakeup((caddr_t)&nbdwrite); } if (ISSET(oldflags, (B_ASYNC|B_DELWRI))) { @@ -4152,6 +4218,7 @@ nfs_pagein(ap) struct ucred *cred; register struct nfsnode *np = VTONFS(vp); register int biosize; + register int iosize; register int xsize; struct vattr vattr; struct proc *p = current_proc(); @@ -4192,8 +4259,6 @@ nfs_pagein(ap) if (cred == NOCRED) cred = ap->a_cred; - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; auio.uio_offset = f_offset; auio.uio_segflg = UIO_SYSSPACE; auio.uio_rw = UIO_READ; @@ -4211,8 +4276,11 @@ nfs_pagein(ap) xsize = size; do { - uio->uio_resid = min(biosize, xsize); - aiov.iov_len = uio->uio_resid; + iosize = min(biosize, xsize); + uio->uio_resid = iosize; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + aiov.iov_len = iosize; aiov.iov_base = (caddr_t)ioaddr; FSDBG(322, uio->uio_offset, uio->uio_resid, ioaddr, xsize); @@ -4225,6 +4293,7 @@ nfs_pagein(ap) upl_ubc_alias_set(pl, current_act(), 2); #endif /* UBC_DEBUG */ nfsstats.pageins++; + error = nfs_readrpc(vp, uio, cred); if (!error) { @@ -4236,16 +4305,17 @@ nfs_pagein(ap) * Just zero fill the rest of the valid area. */ int zcnt = uio->uio_resid; - int zoff = biosize - zcnt; + int zoff = iosize - zcnt; bzero((char *)ioaddr + zoff, zcnt); FSDBG(324, uio->uio_offset, zoff, zcnt, ioaddr); uio->uio_offset += zcnt; } - ioaddr += biosize; - xsize -= biosize; + ioaddr += iosize; + xsize -= iosize; } else FSDBG(322, uio->uio_offset, uio->uio_resid, error, -1); + if (p && (vp->v_flag & VTEXT) && ((nmp->nm_flag & NFSMNT_NQNFS && NQNFS_CKINVALID(vp, np, ND_READ) && diff --git a/bsd/nfs/nfsdiskless.h b/bsd/nfs/nfsdiskless.h index b04ee1dd4..59f987e22 100644 --- a/bsd/nfs/nfsdiskless.h +++ b/bsd/nfs/nfsdiskless.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -63,6 +63,9 @@ #ifndef _NFS_NFSDISKLESS_H_ #define _NFS_NFSDISKLESS_H_ +#include + +#ifdef __APPLE_API_PRIVATE /* * Structure that must be initialized for a diskless nfs client. * This structure is used by nfs_mountroot() to set up the root and swap @@ -137,4 +140,5 @@ struct nfs_diskless { struct nfs_dlmount nd_private; /* Mount info for private */ }; -#endif +#endif /* __APPLE_API_PRIVATE */ +#endif /* _NFS_NFSDISKLESS_H_ */ diff --git a/bsd/nfs/nfsm_subs.h b/bsd/nfs/nfsm_subs.h index 0f31ebb57..e9c810e2b 100644 --- a/bsd/nfs/nfsm_subs.h +++ b/bsd/nfs/nfsm_subs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -63,7 +63,9 @@ #ifndef _NFS_NFSM_SUBS_H_ #define _NFS_NFSM_SUBS_H_ +#include +#ifdef __APPLE_API_PRIVATE /* * These macros do strange and peculiar things to mbuf chains for * the assistance of the nfs code. To attempt to use them for any @@ -484,4 +486,5 @@ struct mbuf *nfsm_rpchead __P((struct ucred *cr, int nmflag, int procid, break; \ }; } -#endif +#endif /* __APPLE_API_PRIVATE */ +#endif /* _NFS_NFSM_SUBS_H_ */ diff --git a/bsd/nfs/nfsmount.h b/bsd/nfs/nfsmount.h index 35af84312..92d69f7a5 100644 --- a/bsd/nfs/nfsmount.h +++ b/bsd/nfs/nfsmount.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -63,6 +63,9 @@ #ifndef _NFS_NFSMOUNT_H_ #define _NFS_NFSMOUNT_H_ +#include + +#ifdef __APPLE_API_PRIVATE /* * Mount structure. * One allocated on every NFS mount. @@ -118,4 +121,5 @@ struct nfsmount { #endif /* KERNEL */ -#endif +#endif /* __APPLE_API_PRIVATE */ +#endif /* _NFS_NFSMOUNT_H_ */ diff --git a/bsd/nfs/nfsnode.h b/bsd/nfs/nfsnode.h index cf37ec795..820c68f79 100644 --- a/bsd/nfs/nfsnode.h +++ b/bsd/nfs/nfsnode.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -63,6 +63,9 @@ #ifndef _NFS_NFSNODE_H_ #define _NFS_NFSNODE_H_ +#include + +#ifdef __APPLE_API_PRIVATE #ifndef _NFS_NFS_H_ #include #endif @@ -218,4 +221,5 @@ void nfs_invaldir __P((struct vnode *)); #endif /* KERNEL */ -#endif +#endif /* __APPLE_API_PRIVATE */ +#endif /* _NFS_NFSNODE_H_ */ diff --git a/bsd/nfs/nfsproto.h b/bsd/nfs/nfsproto.h index 63901cda5..cd63a0996 100644 --- a/bsd/nfs/nfsproto.h +++ b/bsd/nfs/nfsproto.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -62,6 +62,9 @@ #ifndef _NFS_NFSPROTO_H_ #define _NFS_NFSPROTO_H_ +#include + +#ifdef __APPLE_API_PRIVATE /* * nfs definitions as per the Version 2 and 3 specs */ @@ -472,4 +475,5 @@ struct nfsv3_pathconf { u_long pc_casepreserving; }; -#endif +#endif /* __APPLE_API_PRIVATE */ +#endif /* _NFS_NFSPROTO_H_ */ diff --git a/bsd/nfs/nfsrtt.h b/bsd/nfs/nfsrtt.h index 0a58dd9d4..1cebaf787 100644 --- a/bsd/nfs/nfsrtt.h +++ b/bsd/nfs/nfsrtt.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -63,6 +63,9 @@ #ifndef _NFS_NFSRTT_H_ #define _NFS_NFSRTT_H_ +#include + +#ifdef __APPLE_API_PRIVATE /* * Definitions for performance monitor. * The client and server logging are turned on by setting the global @@ -123,4 +126,5 @@ struct nfsdrt { } drt[NFSRTTLOGSIZ]; }; -#endif +#endif /* __APPLE_API_PRIVATE */ +#endif /* _NFS_NFSRTT_H_ */ diff --git a/bsd/nfs/nfsrvcache.h b/bsd/nfs/nfsrvcache.h index 54b93d50f..1e7f97766 100644 --- a/bsd/nfs/nfsrvcache.h +++ b/bsd/nfs/nfsrvcache.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -63,6 +63,9 @@ #ifndef _NFS_NFSRVCACHE_H_ #define _NFS_NFSRVCACHE_H_ +#include + +#ifdef __APPLE_API_PRIVATE /* * Definitions for the server recent request cache */ @@ -108,4 +111,5 @@ struct nfsrvcache { #define RC_INETADDR 0x20 #define RC_NAM 0x40 -#endif +#endif /* __APPLE_API_PRIVATE */ +#endif /* _NFS_NFSRVCACHE_H_ */ diff --git a/bsd/nfs/nqnfs.h b/bsd/nfs/nqnfs.h index 0cbb47564..bb432511a 100644 --- a/bsd/nfs/nqnfs.h +++ b/bsd/nfs/nqnfs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -63,6 +63,9 @@ #ifndef _NFS_NQNFS_H_ #define _NFS_NQNFS_H_ +#include + +#ifdef __APPLE_API_PRIVATE /* * Definitions for NQNFS (Not Quite NFS) cache consistency protocol. */ @@ -237,4 +240,5 @@ int nqnfsrv_getlease __P((struct nfsrv_descript *, struct nfssvc_sock *, struct int nqnfsrv_vacated __P((struct nfsrv_descript *, struct nfssvc_sock *, struct proc *, struct mbuf **)); #endif -#endif +#endif /* __APPLE_API_PRIVATE */ +#endif /* _NFS_NQNFS_H_ */ diff --git a/bsd/nfs/rpcv2.h b/bsd/nfs/rpcv2.h index b1d28ff7e..d8a2618fe 100644 --- a/bsd/nfs/rpcv2.h +++ b/bsd/nfs/rpcv2.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -63,6 +63,9 @@ #ifndef _NFS_RPCV2_H_ #define _NFS_RPCV2_H_ +#include + +#ifdef __APPLE_API_PRIVATE /* * Definitions for Sun RPC Version 2, from * "RPC: Remote Procedure Call Protocol Specification" RFC1057 @@ -162,4 +165,6 @@ typedef u_char NFSKERBKEYSCHED_T[2]; #define NFS_KERBTTL (30 * 60) /* Credential ttl (sec) */ #define NFS_KERBCLOCKSKEW (5 * 60) /* Clock skew (sec) */ #define NFS_KERBW1(t) (*((u_long *)(&((t).dat[((t).length + 3) & ~0x3])))) -#endif + +#endif /* __APPLE_API_PRIVATE */ +#endif /* _NFS_RPCV2_H_ */ diff --git a/bsd/nfs/xdr_subs.h b/bsd/nfs/xdr_subs.h index 5f73c96d8..e786cb8c7 100644 --- a/bsd/nfs/xdr_subs.h +++ b/bsd/nfs/xdr_subs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -66,6 +66,9 @@ #ifndef _NFS_XDR_SUBS_H_ #define _NFS_XDR_SUBS_H_ +#include + +#ifdef __APPLE_API_PRIVATE /* * Macros used for conversion to/from xdr representation by nfs... * These use the MACHINE DEPENDENT routines ntohl, htonl @@ -113,4 +116,5 @@ ((long *)(t))[1] = htonl(((long *)(f))[_QUAD_LOWWORD]); \ } -#endif +#endif /* __APPLE_API_PRIVATE */ +#endif /* _NFS_XDR_SUBS_H_ */ diff --git a/bsd/ppc/Makefile b/bsd/ppc/Makefile index b4bd40dda..790667692 100644 --- a/bsd/ppc/Makefile +++ b/bsd/ppc/Makefile @@ -10,7 +10,7 @@ include $(MakeInc_def) DATAFILES = \ cpu.h disklabel.h endian.h exec.h label_t.h param.h profile.h \ psl.h ptrace.h reboot.h reg.h setjmp.h signal.h spl.h \ - table.h types.h user.h vmparam.h + table.h types.h ucontext.h user.h vmparam.h INSTALL_MD_LIST = ${DATAFILES} diff --git a/bsd/ppc/cpu.h b/bsd/ppc/cpu.h index e7a2dc69e..5aa43232f 100644 --- a/bsd/ppc/cpu.h +++ b/bsd/ppc/cpu.h @@ -1,6 +1,6 @@ /* * Copyright (c) 1993 NeXT Computer, Inc. All rights reserved. - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -27,8 +27,12 @@ #ifndef _BSD_PPC_CPU_H_ #define _BSD_PPC_CPU_H_ - + +#include + +#ifdef __APPLE_API_OBSOLETE #define cpu_number() (0) +#endif /* __APPLE_API_OBSOLETE */ #endif /* _BSD_PPC_CPU_H_ */ diff --git a/bsd/ppc/disklabel.h b/bsd/ppc/disklabel.h index f93d6b294..02a84a604 100644 --- a/bsd/ppc/disklabel.h +++ b/bsd/ppc/disklabel.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -27,9 +27,12 @@ * */ -#ifndef _MACHINE_DISKLABEL_H_ -#define _MACHINE_DISKLABEL_H_ +#ifndef _BSD_PPC_DISKLABEL_H_ +#define _BSD_PPC_DISKLABEL_H_ +#include + +#ifdef __APPLE_API_OBSOLETE #define LABELSECTOR (1024 / DEV_BSIZE) /* sector containing label */ #define LABELOFFSET 0 /* offset of label in sector */ #define MAXPARTITIONS 8 /* number of partitions */ @@ -40,4 +43,6 @@ struct cpu_disklabel { int cd_dummy; /* must have one element. */ }; -#endif /* _MACHINE_DISKLABEL_H_ */ +#endif /* __APPLE_API_OBSOLETE */ + +#endif /* _BSD_PPC_DISKLABEL_H_ */ diff --git a/bsd/ppc/endian.h b/bsd/ppc/endian.h index ea3b815f5..984cdb588 100644 --- a/bsd/ppc/endian.h +++ b/bsd/ppc/endian.h @@ -1,6 +1,6 @@ /* * Copyright (c) 1995 NeXT Computer, Inc. All rights reserved. - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * diff --git a/bsd/ppc/exec.h b/bsd/ppc/exec.h index 9db931975..339bac2c7 100644 --- a/bsd/ppc/exec.h +++ b/bsd/ppc/exec.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -39,6 +39,13 @@ * */ +#ifndef _BSD_PPC_EXEC_H_ +#define _BSD_PPC_EXEC_H_ + + +#include + +#ifdef __APPLE_API_OBSOLETE /* Size of a page in an object file. */ #define __LDPGSZ 4096 @@ -95,3 +102,7 @@ struct exec { #define PS_STRINGS \ ((struct ps_strings *)(USRSTACK - sizeof(struct ps_strings))) +#endif /* __APPLE_API_OBSOLETE */ + +#endif /* _BSD_PPC_EXEC_H_ */ + diff --git a/bsd/ppc/label_t.h b/bsd/ppc/label_t.h index 54e9bbc93..d4a45ac77 100644 --- a/bsd/ppc/label_t.h +++ b/bsd/ppc/label_t.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -31,8 +31,15 @@ #ifndef _BSD_PPC_LABEL_T_H_ #define _BSD_PPC_LABEL_T_H_ +#include + +#ifdef __APPLE_API_OBSOLETE + typedef struct label_t { int val[59]; } label_t; +#endif /* __APPLE_API_OBSOLETE */ + #endif /* _BSD_PPC_LABEL_T_H_ */ + diff --git a/bsd/ppc/param.h b/bsd/ppc/param.h index b0fb62ded..96e29404a 100644 --- a/bsd/ppc/param.h +++ b/bsd/ppc/param.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -56,7 +56,7 @@ #define CLSIZELOG2 0 #define STACKSIZE 4 /* pages in kernel stack */ -#define UPAGES (USIZE+STACKSIZE) /* total pages in u-area */ +#define UPAGES 0 /* total pages in u-area */ /* red zone is beyond this */ /* diff --git a/bsd/ppc/profile.h b/bsd/ppc/profile.h index a6f2b3ca1..a7263bd42 100644 --- a/bsd/ppc/profile.h +++ b/bsd/ppc/profile.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,15 +22,15 @@ /* * Copyright (c) 1997, Apple Computer, Inc. All rights reserved. * - * History : - * 29-Sep-1997 Umesh Vaishampayan - * Created. */ #ifndef _BSD_PPC_PROFILE_H_ #define _BSD_PPC_PROFILE_H_ +#include + #ifdef KERNEL +#ifdef __APPLE_API_UNSTABLE /* * Block interrupts during mcount so that those interrupts can also be * counted (as soon as we get done with the current counting). On the @@ -46,6 +46,7 @@ extern void restore_ee(unsigned long smsr); #define MCOUNT_EXIT restore_ee(smsr); +#endif /* __APPLE_API_UNSTABLE */ #endif /* KERNEL */ #endif /* _BSD_PPC_PROFILE_H_ */ diff --git a/bsd/ppc/psl.h b/bsd/ppc/psl.h index 488e97ecf..7e081d882 100644 --- a/bsd/ppc/psl.h +++ b/bsd/ppc/psl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * diff --git a/bsd/ppc/ptrace.h b/bsd/ppc/ptrace.h index 6fd1d3ed8..769354c3f 100644 --- a/bsd/ppc/ptrace.h +++ b/bsd/ppc/ptrace.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * diff --git a/bsd/ppc/reboot.h b/bsd/ppc/reboot.h index 839e80100..0a47e6a49 100644 --- a/bsd/ppc/reboot.h +++ b/bsd/ppc/reboot.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -19,27 +19,17 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* - * File: next/reboot.h - * Author: Avadis Tevanian, Jr. - * - * NeXT specific reboot flags. - * - * HISTORY - * 28-Feb-90 John Seamons (jks) at NeXT - * Added RB_COMMAND flag that allows a specific reboot command to be used. - * - * 06-Jul-88 Avadis Tevanian (avie) at NeXT, Inc. - * Created. - */ #ifndef _BSD_PPC_REBOOT_H_ #define _BSD_PPC_REBOOT_H_ +#include + /* * Empty file (publicly) */ #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE /* * Use most significant 16 bits to avoid collisions with * machine independent flags. @@ -53,5 +43,9 @@ #define RB_BOOTNEXT 0x00400000 /* reboot into NeXT */ #define RB_BOOTDOS 0x00800000 /* reboot into DOS */ +#endif /* __APPLE_API_PRIVATE */ + #endif /* KERNEL */ + #endif /* _BSD_PPC_REBOOT_H_ */ + diff --git a/bsd/ppc/reg.h b/bsd/ppc/reg.h index c33c3606d..58f1be653 100644 --- a/bsd/ppc/reg.h +++ b/bsd/ppc/reg.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -26,11 +26,18 @@ #ifndef _BSD_PPC_REG_H_ #define _BSD_PPC_REG_H_ +#include + #ifdef KERNEL_PRIVATE +#ifdef __APPLE_API_PRIVATE /* Index into the thread_state */ #define SP 3 #define PC 0 +#endif /* __APPLE_API_PRIVATE */ + #endif /* KERNEL_PRIVATE */ + #endif /* _BSD_PPC_REG_H_ */ + diff --git a/bsd/ppc/setjmp.h b/bsd/ppc/setjmp.h index 08b834ac4..f7b318d92 100644 --- a/bsd/ppc/setjmp.h +++ b/bsd/ppc/setjmp.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * diff --git a/bsd/ppc/signal.h b/bsd/ppc/signal.h index 19c940513..ef4138630 100644 --- a/bsd/ppc/signal.h +++ b/bsd/ppc/signal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,30 +21,14 @@ */ /* * Copyright (c) 1992, 1993 NeXT Computer, Inc. - * - * HISTORY - * - * Machine specific signal information. - * - * HISTORY - * 25-MAR-97 Umesh Vaishampayan (umeshv@NeXT.com) - * Ported from m98k and hppa. - * - * 13-Jan-92 Peter King (king) at NeXT Computer, Inc. - * Filled out struct sigcontext to hold all registers. - * Added regs_saved_t to specify which regs stored in the - * sigcontext are valid. - * - * 09-Nov-92 Ben Fathi (benf) at NeXT, Inc. - * Ported to m98k. - * - * 09-May-91 Mike DeMoney (mike) at NeXT, Inc. - * Ported to m88k. */ #ifndef _PPC_SIGNAL_ #define _PPC_SIGNAL_ 1 +#include + +#ifdef __APPLE_API_OBSOLETE typedef int sig_atomic_t; /* @@ -88,5 +72,7 @@ struct sigcontext { void *sc_regs; /* (kernel private) saved state */ }; +#endif /* __APPLE_API_OBSOLETE */ + #endif /* _PPC_SIGNAL_ */ diff --git a/bsd/ppc/spl.h b/bsd/ppc/spl.h index 4284f241b..01d0c0b21 100644 --- a/bsd/ppc/spl.h +++ b/bsd/ppc/spl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * diff --git a/bsd/ppc/table.h b/bsd/ppc/table.h index 0d0533d90..ff4d1dc34 100644 --- a/bsd/ppc/table.h +++ b/bsd/ppc/table.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -26,8 +26,13 @@ #ifndef _BSD_PPC_TABLE_H_ #define _BSD_PPC_TABLE_H_ +#include + +#ifdef __APPLE_API_OBSOLETE /* * No machine dependent table calls for ppc. */ +#endif /* __APPLE_API_OBSOLETE */ + #endif /* _BSD_PPC_TABLE_H_ */ diff --git a/bsd/ppc/types.h b/bsd/ppc/types.h index 9b5d80b36..f370e9bf1 100644 --- a/bsd/ppc/types.h +++ b/bsd/ppc/types.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -77,9 +77,10 @@ typedef unsigned long long u_int64_t; typedef int32_t register_t; - typedef long int intptr_t; typedef unsigned long int uintptr_t; +#define __offsetof(type, field) ((size_t)(&((type *)0)->field)) + #endif /* __ASSEMBLER__ */ #endif /* _MACHTYPES_H_ */ diff --git a/bsd/ppc/ucontext.h b/bsd/ppc/ucontext.h new file mode 100644 index 000000000..c2d9d31fb --- /dev/null +++ b/bsd/ppc/ucontext.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#ifndef _PPC_UCONTEXT_H_ +#define _PPC_UCONTEXT_H_ + + +#include + +struct mcontext { + ppc_exception_state_t es; + ppc_thread_state_t ss; + ppc_float_state_t fs; + ppc_vector_state_t vs; +}; + +#define PPC_MCONTEXT_SIZE (PPC_THREAD_STATE_COUNT + PPC_FLOAT_STATE_COUNT + PPC_EXCEPTION_STATE_COUNT + PPC_VECTOR_STATE_COUNT) * sizeof(int) + +typedef struct mcontext * mcontext_t; + +#endif /* _PPC_UCONTEXT_H_ */ diff --git a/bsd/ppc/user.h b/bsd/ppc/user.h index 6a7651a71..5914cf757 100644 --- a/bsd/ppc/user.h +++ b/bsd/ppc/user.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * diff --git a/bsd/ppc/vmparam.h b/bsd/ppc/vmparam.h index ce5c25c4e..90db43aba 100644 --- a/bsd/ppc/vmparam.h +++ b/bsd/ppc/vmparam.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -19,14 +19,6 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* - * HISTORY - * 05-Mar-89 Avadis Tevanian, Jr. (avie) at NeXT - * Make MAXDSIZ infinity. - * - * 12-Aug-87 John Seamons (jks) at NeXT - * Ported to NeXT. - */ #ifndef _BSD_PPC_VMPARAM_H_ #define _BSD_PPC_VMPARAM_H_ 1 diff --git a/bsd/sys/Makefile b/bsd/sys/Makefile index be495b68d..e73e39434 100644 --- a/bsd/sys/Makefile +++ b/bsd/sys/Makefile @@ -20,19 +20,20 @@ EXPINC_SUBDIRS_PPC = \ EXPINC_SUBDIRS_I386 = \ DATAFILES = \ - acct.h attr.h buf.h callout.h cdefs.h cdio.h chio.h clist.h conf.h \ - dir.h dirent.h disklabel.h disktab.h dkbad.h dkstat.h dmap.h domain.h \ + appleapiopts.h \ + acct.h attr.h buf.h callout.h cdefs.h clist.h conf.h \ + dir.h dirent.h disk.h disklabel.h disktab.h dkstat.h dmap.h domain.h \ errno.h ev.h exec.h fcntl.h file.h filedesc.h filio.h gmon.h ioccom.h ioctl.h \ ioctl_compat.h ipc.h kernel.h kern_event.h ktrace.h loadable_fs.h lock.h lockf.h mach_swapon.h malloc.h \ - kdebug.h linker_set.h md5.h\ + kdebug.h linker_set.h md5.h kern_control.h \ mbuf.h mman.h mount.h msgbuf.h mtio.h namei.h netport.h param.h paths.h \ - proc.h protosw.h ptrace.h queue.h random.h reboot.h resource.h resourcevar.h \ - select.h semaphore.h shm.h signal.h signalvar.h socket.h socketvar.h sockio.h stat.h \ - syscall.h sysctl.h syslimits.h syslog.h systm.h termios.h time.h \ + proc.h protosw.h ptrace.h queue.h quota.h random.h reboot.h resource.h resourcevar.h \ + select.h sem.h semaphore.h shm.h signal.h signalvar.h socket.h socketvar.h sockio.h stat.h \ + syscall.h sysctl.h syslimits.h syslog.h systm.h sys_domain.h termios.h time.h \ timeb.h times.h tprintf.h trace.h tty.h ttychars.h ttycom.h \ - ttydefaults.h ttydev.h types.h ubc.h ucred.h uio.h un.h unistd.h unpcb.h \ + ttydefaults.h ttydev.h types.h ubc.h ucontext.h ucred.h uio.h un.h unistd.h unpcb.h \ user.h utfconv.h utsname.h ux_exception.h vadvise.h vcmd.h version.h vlimit.h \ - vm.h vmmeter.h vmparam.h vnode.h vnode_if.h vstat.h wait.h + vm.h vmmeter.h vmparam.h vnioctl.h vnode.h vnode_if.h vstat.h wait.h INSTALL_MI_LIST = ${DATAFILES} diff --git a/bsd/sys/acct.h b/bsd/sys/acct.h index 2470ca277..01aa44369 100644 --- a/bsd/sys/acct.h +++ b/bsd/sys/acct.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -62,6 +62,8 @@ #ifndef _SYS_ACCT_H_ #define _SYS_ACCT_H_ +#include + /* * 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 @@ -96,9 +98,10 @@ struct acct { #define AHZ 64 #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE extern struct vnode *acctp; - int acct_process __P((struct proc *p)); -#endif +#endif /* __APPLE_API_PRIVATE */ +#endif /* KERNEL */ #endif /* ! _SYS_ACCT_H_ */ diff --git a/bsd/sys/appleapiopts.h b/bsd/sys/appleapiopts.h new file mode 100644 index 000000000..2ecde9dee --- /dev/null +++ b/bsd/sys/appleapiopts.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#ifndef __SYS_APPLEAPIOPTS_H__ +#define __SYS_APPLEAPIOPTS_H__ + + +#ifndef __APPLE_API_STANDARD +#define __APPLE_API_STANDARD +#endif /* __APPLE_API_STANDARD */ + +#ifndef __APPLE_API_STABLE +#define __APPLE_API_STABLE +#endif /* __APPLE_API_STABLE */ + +#ifndef __APPLE_API_STRICT_CONFORMANCE + +#ifndef __APPLE_API_EVOLVING +#define __APPLE_API_EVOLVING +#endif /* __APPLE_API_EVOLVING */ + +#ifndef __APPLE_API_UNSTABLE +#define __APPLE_API_UNSTABLE +#endif /* __APPLE_API_UNSTABLE */ + +#ifndef __APPLE_API_PRIVATE +#define __APPLE_API_PRIVATE +#endif /* __APPLE_API_PRIVATE */ + +#ifndef __APPLE_API_OBSOLETE +#define __APPLE_API_OBSOLETE +#endif /* __APPLE_API_OBSOLETE */ + +#endif /* __APPLE_API_STRICT_CONFORMANCE */ + +#endif /* __SYS_APPLEAPIOPTS_H__ */ + diff --git a/bsd/sys/attr.h b/bsd/sys/attr.h index 96eead6f7..732410ea6 100644 --- a/bsd/sys/attr.h +++ b/bsd/sys/attr.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -29,6 +29,9 @@ #ifndef _SYS_ATTR_H_ #define _SYS_ATTR_H_ +#include + +#ifdef __APPLE_API_UNSTABLE #ifndef _SYS_TYPES_H_ #include #endif @@ -234,13 +237,7 @@ struct searchstate { }; - #define FST_EOF (-1) /* end-of-file offset */ -__BEGIN_DECLS -/* XXX PPD This should be moved to dirent.h to be with getdirentries(2) et al. */ -//int getdirentriesattr(int fd, const struct attrlist *attrspec, void *attrbuf, size_t bufsize, long //*cookie); - -__END_DECLS - +#endif /* __APPLE_API_UNSTABLE */ #endif /* !_SYS_ATTR_H_ */ diff --git a/bsd/sys/buf.h b/bsd/sys/buf.h index 26e5c1139..fb456c562 100644 --- a/bsd/sys/buf.h +++ b/bsd/sys/buf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -62,14 +62,18 @@ #ifndef _SYS_BUF_H_ #define _SYS_BUF_H_ + +#include + +#ifdef KERNEL #include #include - #include +#include -#define NOLIST ((struct buf *)0x87654321) +#ifdef __APPLE_API_PRIVATE -#include +#define NOLIST ((struct buf *)0x87654321) /* * The buffer header describes an I/O operation in the kernel. @@ -193,15 +197,20 @@ struct buf { #define BLK_CLREAD 0x20 /* buffer for cluster read */ #define BLK_CLWRITE 0x40 /* buffer for cluster write */ -#ifdef KERNEL extern int nbuf; /* The number of buffer headers */ extern struct buf *buf; /* The buffer headers. */ +#endif /* __APPLE_API_PRIVATE */ + + +#ifdef __APPLE_API_UNSTABLE /* Macros to clear/set/test flags. */ #define SET(t, f) (t) |= (f) #define CLR(t, f) (t) &= ~(f) #define ISSET(t, f) ((t) & (f)) +#endif /* __APPLE_API_UNSTABLE */ +#ifdef __APPLE_API_PRIVATE /* * Definitions for the buffer free lists. */ @@ -213,8 +222,10 @@ extern struct buf *buf; /* The buffer headers. */ #define BQ_EMPTY 3 /* buffer headers with no memory */ #define BQ_META 4 /* buffer containing metadata */ #define BQ_LAUNDRY 5 /* buffers that need cleaning */ +#endif /* __APPLE_API_PRIVATE */ __BEGIN_DECLS +#ifdef __APPLE_API_UNSTABLE int allocbuf __P((struct buf *, int)); void bawrite __P((struct buf *)); void bdwrite __P((struct buf *)); @@ -231,6 +242,7 @@ int breadn __P((struct vnode *, daddr_t, int, daddr_t *, int *, int, void brelse __P((struct buf *)); void bremfree __P((struct buf *)); void bufinit __P((void)); +void bwillwrite __P((void)); int bwrite __P((struct buf *)); struct buf *getblk __P((struct vnode *, daddr_t, int, int, int, int)); struct buf *geteblk __P((int)); @@ -240,8 +252,11 @@ int physio __P((void (*)(struct buf *), struct buf *, dev_t, int , u_int (*)(st int count_busy_buffers __P((void)); struct buf *alloc_io_buf __P((struct vnode *, int)); void free_io_buf __P((struct buf *)); +void reassignbuf __P((struct buf *, struct vnode *)); +#endif /* __APPLE_API_UNSTABLE */ __END_DECLS +#ifdef __APPLE_API_PRIVATE /* * Stats on usefulness of the buffer cache */ @@ -256,6 +271,7 @@ struct bufstats { long bufs_iobufinuse; /* number of IO buffers in use */ long bufs_iobufsleeps; /* IO buffer starvation */ }; +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ #endif /* !_SYS_BUF_H_ */ diff --git a/bsd/sys/callout.h b/bsd/sys/callout.h index c3faa8f79..61c4dee0b 100644 --- a/bsd/sys/callout.h +++ b/bsd/sys/callout.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -62,10 +62,12 @@ #ifndef _SYS_CALLOUT_H_ #define _SYS_CALLOUT_H_ -#include +#include +#include +#ifdef __APPLE_API_OBSOLETE #define CALLOUT_PRI_SOFTINT0 0 #define CALLOUT_PRI_SOFTINT1 1 #define CALLOUT_PRI_RETRACE 2 @@ -74,5 +76,5 @@ #define CALLOUT_PRI_NOW 5 /* must be last */ #define N_CALLOUT_PRI 6 - +#endif /* __APPLE_API_OBSOLETE */ #endif /* _SYS_CALLOUT_H_ */ diff --git a/bsd/sys/cdio.h b/bsd/sys/cdio.h deleted file mode 100644 index edbd57b46..000000000 --- a/bsd/sys/cdio.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ -/* - * The NEXTSTEP Software License Agreement specifies the terms - * and conditions for redistribution. - */ - -#ifndef _SYS_CDIO_H_ -#define _SYS_CDIO_H_ - -/* Shared between kernel & process */ - -struct cd_toc_entry { - u_char nothing1; - u_char control:4; - u_char addr_type:4; - u_char track; - u_char nothing2; - u_char addr[4]; -}; - -struct cd_sub_channel_header { - u_char nothing1; - u_char audio_status; -#define CD_AS_AUDIO_INVALID 0x00 -#define CD_AS_PLAY_IN_PROGRESS 0x11 -#define CD_AS_PLAY_PAUSED 0x12 -#define CD_AS_PLAY_COMPLETED 0x13 -#define CD_AS_PLAY_ERROR 0x14 -#define CD_AS_NO_STATUS 0x15 - u_char data_len[2]; -}; - -struct cd_sub_channel_position_data { - u_char data_format; - u_char control:4; - u_char addr_type:4; - u_char track_number; - u_char index_number; - u_char absaddr[4]; - u_char reladdr[4]; -}; - -struct cd_sub_channel_media_catalog { - u_char data_format; - u_char nothing1; - u_char nothing2; - u_char nothing3; - u_char :7; - u_char mc_valid:1; - u_char mc_number[15]; -}; - -struct cd_sub_channel_track_info { - u_char data_format; - u_char nothing1; - u_char track_number; - u_char nothing2; - u_char :7; - u_char ti_valid:1; - u_char ti_number[15]; -}; - -struct cd_sub_channel_info { - struct cd_sub_channel_header header; - union { - struct cd_sub_channel_position_data position; - struct cd_sub_channel_media_catalog media_catalog; - struct cd_sub_channel_track_info track_info; - } what; -}; - -/* - * Ioctls for the CD drive - */ -struct ioc_play_track { - u_char start_track; - u_char start_index; - u_char end_track; - u_char end_index; -}; - -#define CDIOCPLAYTRACKS _IOW('c', 1, struct ioc_play_track) -struct ioc_play_blocks { - int blk; - int len; -}; -#define CDIOCPLAYBLOCKS _IOW('c', 2, struct ioc_play_blocks) - -struct ioc_read_subchannel { - u_char address_format; -#define CD_LBA_FORMAT 1 -#define CD_MSF_FORMAT 2 - u_char data_format; -#define CD_SUBQ_DATA 0 -#define CD_CURRENT_POSITION 1 -#define CD_MEDIA_CATALOG 2 -#define CD_TRACK_INFO 3 - u_char track; - int data_len; - struct cd_sub_channel_info *data; -}; -#define CDIOCREADSUBCHANNEL _IOWR('c', 3, struct ioc_read_subchannel ) - -struct ioc_toc_header { - u_short len; - u_char starting_track; - u_char ending_track; -}; - -#define CDIOREADTOCHEADER _IOR('c', 4, struct ioc_toc_header) - -struct ioc_read_toc_entry { - u_char address_format; - u_char starting_track; - u_short data_len; - struct cd_toc_entry *data; -}; -#define CDIOREADTOCENTRYS _IOWR('c', 5, struct ioc_read_toc_entry) - -struct ioc_patch { - u_char patch[4]; /* one for each channel */ -}; -#define CDIOCSETPATCH _IOW('c', 9, struct ioc_patch) - -struct ioc_vol { - u_char vol[4]; /* one for each channel */ -}; -#define CDIOCGETVOL _IOR('c', 10, struct ioc_vol) -#define CDIOCSETVOL _IOW('c', 11, struct ioc_vol) -#define CDIOCSETMONO _IO('c', 12) -#define CDIOCSETSTEREO _IO('c', 13) -#define CDIOCSETMUTE _IO('c', 14) -#define CDIOCSETLEFT _IO('c', 15) -#define CDIOCSETRIGHT _IO('c', 16) -#define CDIOCSETDEBUG _IO('c', 17) -#define CDIOCCLRDEBUG _IO('c', 18) -#define CDIOCPAUSE _IO('c', 19) -#define CDIOCRESUME _IO('c', 20) -#define CDIOCRESET _IO('c', 21) -#define CDIOCSTART _IO('c', 22) -#define CDIOCSTOP _IO('c', 23) -#define CDIOCEJECT _IO('c', 24) -#define CDIOCALLOW _IO('c', 25) -#define CDIOCPREVENT _IO('c', 26) - -struct ioc_play_msf { - u_char start_m; - u_char start_s; - u_char start_f; - u_char end_m; - u_char end_s; - u_char end_f; -}; -#define CDIOCPLAYMSF _IOW('c', 25, struct ioc_play_msf) - -#endif /* !_SYS_CDIO_H_ */ diff --git a/bsd/sys/chio.h b/bsd/sys/chio.h deleted file mode 100644 index 6d35d8529..000000000 --- a/bsd/sys/chio.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ -/* - * The NEXTSTEP Software License Agreement specifies the terms - * and conditions for redistribution. - */ - -#ifndef _SYS_CHIO_H_ -#define _SYS_CHIO_H_ - -/* - * Structures and definitions for changer io control commands - */ - -#define CH_INVERT 0x10000 -#define CH_ADDR_MASK 0xffff -struct chop { - short ch_op; /* operations defined below */ - short result; /* the result */ - union { - struct { - int chm; /* Transport element */ - int from; - int to; - } move; - struct { - int chm; /* Transport element */ - int to; - } position; - struct { - short chmo; /* Offset of first CHM */ - short chms; /* No. of CHM */ - short slots; /* No. of Storage Elements */ - short sloto; /* Offset of first SE */ - short imexs; /* No. of Import/Export Slots */ - short imexo; /* Offset of first IM/EX */ - short drives; /* No. of CTS */ - short driveo; /* Offset of first CTS */ - short rot; /* CHM can rotate */ - } getparam; - struct { - int type; -#define CH_CHM 1 -#define CH_STOR 2 -#define CH_IMEX 3 -#define CH_CTS 4 - int from; - struct { - u_char elema_1; - u_char elema_0; - u_char full:1; - u_char rsvd:1; - u_char except:1; - u_char :5; - u_char rsvd2; - union { - struct { - u_char add_sense_code; - u_char add_sense_code_qualifier; - } specs; - short add_sense; -/* WARINING LSB only */ -#define CH_CHOLDER 0x0290 /* Cartridge holder is missing */ -#define CH_STATUSQ 0x0390 /* Status is questionable */ -#define CH_CTS_CLOSED 0x0490 /* CTS door is closed */ - } ch_add_sense; - u_char rsvd3[3]; - u_char :6; - u_char invert:1; - u_char svalid:1; - u_char source_1; - u_char source_0; - u_char rsvd4[4]; - } elem_data; - } get_elem_stat; - } u; -}; - -/* operations */ -#define CHMOVE 1 -#define CHPOSITION 2 -#define CHGETPARAM 3 -#define CHGETELEM 4 - - -/* Changer IO control command */ -#define CHIOOP _IOWR('c', 1, struct chop) /* do a mag tape op */ - -#endif /* !_SYS_CHIO_H_ */ diff --git a/bsd/sys/clist.h b/bsd/sys/clist.h index 1ff1e0dbb..64cb2eaea 100644 --- a/bsd/sys/clist.h +++ b/bsd/sys/clist.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -58,16 +58,21 @@ #ifndef _SYS_CLIST_H_ #define _SYS_CLIST_H_ +#include + +#ifdef __APPLE_API_PRIVATE +#ifdef KERNEL + struct cblock { struct cblock *c_next; /* next cblock in queue */ char c_quote[CBQSIZE]; /* quoted characters */ char c_info[CBSIZE]; /* characters */ }; -#ifdef KERNEL extern struct cblock *cfree, *cfreelist; extern int cfreecount, nclist; -#endif +#endif /* KERNEL */ +#endif /* __APPLE_API_PRIVATE */ #endif /* _SYS_CLIST_H_ */ diff --git a/bsd/sys/conf.h b/bsd/sys/conf.h index 690651ab7..d3b213bf0 100644 --- a/bsd/sys/conf.h +++ b/bsd/sys/conf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -63,6 +63,8 @@ #ifndef _SYS_CONF_H_ #define _SYS_CONF_H_ 1 +#include + /* * Definitions of device driver entry switches */ @@ -73,6 +75,7 @@ struct tty; struct uio; struct vnode; +#ifdef __APPLE_API_UNSTABLE /* * Device switch function types. */ @@ -143,13 +146,14 @@ struct bdevsw { int d_type; }; -#ifdef KERNEL +#ifdef KERNEL d_devtotty_t nodevtotty; d_write_t nowrite; - +#ifdef __APPLE_API_PRIVATE extern struct bdevsw bdevsw[]; +#endif /* __APPLE_API_PRIVATE */ /* * Contents of empty bdevsw slot. @@ -158,7 +162,7 @@ extern struct bdevsw bdevsw[]; { eno_opcl, eno_opcl, eno_strat, eno_ioctl, \ eno_dump, eno_psize, 0 } -#endif /* KERNEL */ +#endif /* KERNEL */ /* * Character device switch table @@ -182,7 +186,9 @@ struct cdevsw { #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE extern struct cdevsw cdevsw[]; +#endif /* __APPLE_API_PRIVATE */ /* * Contents of empty cdevsw slot. @@ -195,9 +201,8 @@ extern struct cdevsw cdevsw[]; seltrue, eno_mmap, eno_strat, eno_getc, \ eno_putc, 0 \ } +#endif /* KERNEL */ -#endif /* KERNEL */ - /* * Line discipline switch table */ @@ -216,14 +221,19 @@ struct linesw { }; #ifdef KERNEL + +#ifdef __APPLE_API_PRIVATE extern struct linesw linesw[]; extern int nlinesw; +#endif /* __APPLE_API_PRIVATE */ int ldisc_register __P((int , struct linesw *)); void ldisc_deregister __P((int)); #define LDISC_LOAD -1 /* Loadable line discipline */ -#endif +#endif /* KERNEL */ + +#ifdef __APPLE_API_OBSOLETE /* * Swap device table */ @@ -239,7 +249,10 @@ struct swdevt { #ifdef KERNEL extern struct swdevt swdevt[]; -#endif +#endif /* KERNEL */ + +#endif /* __APPLE_API_OBSOLETE */ + #ifdef KERNEL /* @@ -257,6 +270,8 @@ int cdevsw_isfree __P((int)); int cdevsw_add __P((int, struct cdevsw *)); int cdevsw_remove __P((int, struct cdevsw *)); __END_DECLS -#endif +#endif /* KERNEL */ + +#endif /* __APPLE_API_UNSTABLE */ #endif /* _SYS_CONF_H_ */ diff --git a/bsd/sys/disk.h b/bsd/sys/disk.h new file mode 100644 index 000000000..74b269c58 --- /dev/null +++ b/bsd/sys/disk.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1998-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#ifndef _SYS_DISK_H_ +#define _SYS_DISK_H_ + +#include +#include + +typedef struct +{ + char path[128]; +} dk_firmware_path_t; + +#define DKIOCEJECT _IO('d', 21) +#define DKIOCSYNCHRONIZECACHE _IO('d', 22) + +#define DKIOCGETBLOCKSIZE _IOR('d', 24, u_int32_t) +#define DKIOCGETBLOCKCOUNT _IOR('d', 25, u_int64_t) +#define DKIOCGETBLOCKCOUNT32 _IOR('d', 25, u_int32_t) +#define DKIOCGETFIRMWAREPATH _IOR('d', 28, dk_firmware_path_t) + +#define DKIOCISFORMATTED _IOR('d', 23, u_int32_t) +#define DKIOCISWRITABLE _IOR('d', 29, u_int32_t) + +#define DKIOCGETMAXBLOCKCOUNTREAD _IOR('d', 64, u_int64_t) +#define DKIOCGETMAXBLOCKCOUNTWRITE _IOR('d', 65, u_int64_t) +#define DKIOCGETMAXSEGMENTCOUNTREAD _IOR('d', 66, u_int64_t) +#define DKIOCGETMAXSEGMENTCOUNTWRITE _IOR('d', 67, u_int64_t) + +#ifdef KERNEL +#define DKIOCSETBLOCKSIZE _IOW('d', 24, u_int32_t) +#endif /* KERNEL */ + +#endif /* _SYS_DISK_H_ */ diff --git a/bsd/sys/disklabel.h b/bsd/sys/disklabel.h index 21258ddf0..4fa09f226 100644 --- a/bsd/sys/disklabel.h +++ b/bsd/sys/disklabel.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -57,6 +57,10 @@ #ifndef _SYS_DISKLABEL_H_ #define _SYS_DISKLABEL_H_ +#include + +#ifdef __APPLE_API_OBSOLETE + /* * Disk description table, see disktab(5) */ @@ -358,5 +362,7 @@ __END_DECLS #endif +#endif /* __APPLE_API_OBSOLETE */ + #endif /* ! _SYS_DISKLABEL_H_ */ diff --git a/bsd/sys/disktab.h b/bsd/sys/disktab.h index ef2a6faa5..4df1f84f7 100644 --- a/bsd/sys/disktab.h +++ b/bsd/sys/disktab.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -35,7 +35,11 @@ */ #ifndef _SYS_DISKTAB_ -#define _SYS_DISKTAB_ +#define _SYS_DISKTAB_ + +#include + +#ifdef __APPLE_API_OBSOLETE /* * Disk description table, see disktab(5) @@ -94,4 +98,6 @@ typedef struct disktab { struct disktab *getdiskbyname(), *getdiskbydev(); #endif /* !KERNEL */ +#endif /* __APPLE_API_OBSOLETE */ + #endif /* _SYS_DISKTAB_ */ diff --git a/bsd/sys/dkbad.h b/bsd/sys/dkbad.h deleted file mode 100644 index d4aefd847..000000000 --- a/bsd/sys/dkbad.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ -/*- - * Copyright (c) 1982, 1986, 1993, 1994 - * 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 8.2 (Berkeley) 7/10/94 - */ - -#ifndef _SYS_DKBAD_H_ -#define _SYS_DKBAD_H_ - -/* - * 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 { - int32_t bt_csn; /* cartridge serial number */ - u_int16_t bt_mbz; /* unused; should be 0 */ - u_int16_t bt_flag; /* -1 => alignment cartridge */ - struct bt_bad { - u_int16_t bt_cyl; /* cylinder number of bad sector */ - u_int16_t bt_trksec; /* track and sector number */ - } bt_bad[126]; -}; - -#define ECC 0 -#define SSE 1 -#define BSE 2 -#define CONT 3 - -#endif /* _SYS_DKBAD_H_ */ diff --git a/bsd/sys/dkstat.h b/bsd/sys/dkstat.h index 4abbc3e88..b0b256936 100644 --- a/bsd/sys/dkstat.h +++ b/bsd/sys/dkstat.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -61,31 +61,19 @@ */ #ifndef _SYS_DKSTAT_H_ -#define _SYS_DKSTAT_H_ +#define _SYS_DKSTAT_H_ -#define CP_USER 0 -#define CP_NICE 1 -#define CP_SYS 2 -#define CP_INTR 3 -#define CP_IDLE 4 -#define CPUSTATES 5 +#include -#define DK_NDRIVE 8 +#ifdef __APPLE_API_PRIVATE #ifdef KERNEL -extern long cp_time[CPUSTATES]; -extern long dk_seek[DK_NDRIVE]; -extern long dk_time[DK_NDRIVE]; -extern long dk_wds[DK_NDRIVE]; -extern long dk_wpms[DK_NDRIVE]; -extern long dk_xfer[DK_NDRIVE]; - -extern int dk_busy; -extern int dk_ndrive; - extern long tk_cancc; extern long tk_nin; extern long tk_nout; extern long tk_rawcc; #endif + +#endif /* __APPLE_API_PRIVATE */ + #endif /* _SYS_DKSTAT_H_ */ diff --git a/bsd/sys/dmap.h b/bsd/sys/dmap.h index befe5710f..3234c4d5d 100644 --- a/bsd/sys/dmap.h +++ b/bsd/sys/dmap.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -58,6 +58,9 @@ #ifndef _SYS_DMAP_H_ #define _SYS_DMAP_H_ +#include + +#ifdef __APPLE_API_OBSOLETE /* * Definitions for the mapping of vitual swap space to the physical swap * area - the disk map. @@ -79,4 +82,7 @@ struct dblock { swblk_t db_base; /* base of physical contig drum block */ swblk_t db_size; /* size of block */ }; + +#endif /* __APPLE_API_OBSOLETE */ + #endif /* !_SYS_DMAP_H_ */ diff --git a/bsd/sys/domain.h b/bsd/sys/domain.h index c0e3ad112..e6a75966c 100644 --- a/bsd/sys/domain.h +++ b/bsd/sys/domain.h @@ -54,11 +54,14 @@ * SUCH DAMAGE. * * @(#)domain.h 8.1 (Berkeley) 6/2/93 + * $FreeBSD: src/sys/sys/domain.h,v 1.14 1999/12/29 04:24:40 peter Exp $ */ -#ifndef _SYS_DOMAIN_H_ +#ifndef _SYS_DOMAIN_H_ #define _SYS_DOMAIN_H_ +#include + /* * Structure per communications domain. */ @@ -66,6 +69,7 @@ /* * Forward structure declarations for function prototypes [sic]. */ +#ifdef __APPLE_API_UNSTABLE struct mbuf; struct domain { @@ -102,4 +106,5 @@ extern int net_del_domain(struct domain *); */ #endif +#endif /* __APPLE_API_UNSTABLE */ #endif /* _SYS_DOMAIN_H_ */ diff --git a/bsd/sys/errno.h b/bsd/sys/errno.h index 86abc959c..c82770b59 100644 --- a/bsd/sys/errno.h +++ b/bsd/sys/errno.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -204,7 +204,8 @@ __END_DECLS #define ESHLIBVERS 87 /* Shared library version mismatch */ #define EBADMACHO 88 /* Malformed Macho file */ -#define ELAST 88 /* Must be equal largest errno */ +#define ECANCELED 89 /* Operation canceled */ +#define ELAST 89 /* Must be equal largest errno */ #endif /* _POSIX_SOURCE */ #ifdef KERNEL diff --git a/bsd/sys/ev.h b/bsd/sys/ev.h index 2efddee91..16757b77f 100644 --- a/bsd/sys/ev.h +++ b/bsd/sys/ev.h @@ -24,6 +24,8 @@ #ifndef _SYS_EV_H_ #define _SYS_EV_H_ +#include + #include struct eventreq { @@ -58,6 +60,7 @@ typedef struct eventreq *er_t; #define EV_DMASK 0xffffff00 #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE struct eventqelt { TAILQ_ENTRY(eventqelt) ee_slist; @@ -70,6 +73,7 @@ struct eventqelt { struct socket *ee_sp; }; +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ #endif /* _SYS_EV_H_ */ diff --git a/bsd/sys/exec.h b/bsd/sys/exec.h index 3abf356dd..5d4fb571e 100644 --- a/bsd/sys/exec.h +++ b/bsd/sys/exec.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -63,6 +63,9 @@ #ifndef _SYS_EXEC_H_ #define _SYS_EXEC_H_ +#include + +#ifdef __APPLE_API_OBSOLETE /* * The following structure is found at the top of the user stack of each * user process. The ps program uses it to locate argv and environment @@ -78,9 +81,12 @@ struct ps_strings { int ps_nenvstr; /* the number of environment strings */ }; +#endif /* __APPLE_API_OBSOLETE */ + #include #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE /* * Arguments to the exec system call. */ @@ -89,6 +95,8 @@ struct execve_args { char **argp; char **envp; }; +#endif /*__APPLE_API_PRIVATE */ #endif /* KERNEL */ + #endif /* !_SYS_EXEC_H_ */ diff --git a/bsd/sys/fcntl.h b/bsd/sys/fcntl.h index b54889ea1..6e274f663 100644 --- a/bsd/sys/fcntl.h +++ b/bsd/sys/fcntl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -106,6 +106,7 @@ #define O_EXLOCK 0x0020 /* open with exclusive file lock */ #define O_ASYNC 0x0040 /* signal pgrp when data ready */ #define O_FSYNC 0x0080 /* synchronous writes */ +#define O_NOFOLLOW 0x0100 /* don't follow symlinks */ #endif #define O_CREAT 0x0200 /* create if nonexistant */ #define O_TRUNC 0x0400 /* truncate to zero length */ diff --git a/bsd/sys/file.h b/bsd/sys/file.h index e3c71ed59..7d6ace763 100644 --- a/bsd/sys/file.h +++ b/bsd/sys/file.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -58,6 +58,7 @@ #ifndef _SYS_FILE_H_ #define _SYS_FILE_H_ +#include #include #include @@ -67,6 +68,7 @@ struct proc; struct uio; +#ifdef __APPLE_API_UNSTABLE /* * Kernel descriptor table. @@ -85,30 +87,96 @@ struct file { struct ucred *f_cred; /* credentials associated with descriptor */ struct fileops { int (*fo_read) __P((struct file *fp, struct uio *uio, - struct ucred *cred)); + struct ucred *cred, int flags, + struct proc *p)); int (*fo_write) __P((struct file *fp, struct uio *uio, - struct ucred *cred)); + struct ucred *cred, int flags, + struct proc *p)); +#define FOF_OFFSET 1 int (*fo_ioctl) __P((struct file *fp, u_long com, caddr_t data, struct proc *p)); int (*fo_select) __P((struct file *fp, int which, - void * wql, struct proc *p)); + void *wql, 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 */ }; +#ifdef __APPLE_API_PRIVATE LIST_HEAD(filelist, file); extern struct filelist 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 /* __APPLE_API_PRIVATE */ __BEGIN_DECLS int fref __P((struct file *)); /* take a reference on file pointer */ int frele __P((struct file *)); /* release a reference on file pointer */ int fcount __P((struct file *)); /* returns the reference count */ + +static __inline int fo_read __P((struct file *fp, struct uio *uio, + struct ucred *cred, int flags, struct proc *p)); +static __inline int fo_write __P((struct file *fp, struct uio *uio, + struct ucred *cred, int flags, struct proc *p)); +static __inline int fo_ioctl __P((struct file *fp, u_long com, caddr_t data, + struct proc *p)); +static __inline int fo_select __P((struct file *fp, int which, void *wql, + struct proc *p)); +static __inline int fo_close __P((struct file *fp, struct proc *p)); + +static __inline int +fo_read(struct file *fp, struct uio *uio, struct ucred *cred, int flags, struct proc *p) +{ + int error; + + fref(fp); + error = (*fp->f_ops->fo_read)(fp, uio, cred, flags, p); + frele(fp); + return (error); +} + +static __inline int +fo_write(struct file *fp, struct uio *uio, struct ucred *cred, int flags, struct proc *p) +{ + int error; + + fref(fp); + error = (*fp->f_ops->fo_write)(fp, uio, cred, flags, p); + frele(fp); + return (error); +} + +static __inline int +fo_ioctl(struct file *fp, u_long com, caddr_t data, struct proc *p) +{ + int error; + + fref(fp); + error = (*fp->f_ops->fo_ioctl)(fp, com, data, p); + frele(fp); + return (error); +} + +static __inline int +fo_select(struct file *fp, int which, void *wql, struct proc *p) +{ + int error; + + error = (*fp->f_ops->fo_select)(fp, which, wql, p); + return (error); +} + +static __inline int +fo_close(struct file *fp, struct proc *p) +{ + + return ((*fp->f_ops->fo_close)(fp, p)); +} __END_DECLS +#endif /* __APPLE_API_UNSTABLE */ + #endif /* KERNEL */ #endif /* !_SYS_FILE_H_ */ diff --git a/bsd/sys/filedesc.h b/bsd/sys/filedesc.h index a0f0bc75a..2353a06e2 100644 --- a/bsd/sys/filedesc.h +++ b/bsd/sys/filedesc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -58,6 +58,9 @@ #ifndef _SYS_FILEDESC_H_ #define _SYS_FILEDESC_H_ +#include + +#ifdef __APPLE_API_UNSTABLE /* * This structure is used for the management of descriptors. It may be * shared by multiple processes. @@ -116,10 +119,15 @@ extern int fdgetf __P((struct proc *p, int fd, struct file **resultfp)); extern int falloc __P((struct proc *p, struct file **resultfp, int *resultfd)); extern void ffree __P((struct file *fp)); + +#ifdef __APPLE_API_PRIVATE extern struct filedesc *fdcopy __P((struct proc *p)); extern void fdfree __P((struct proc *p)); extern void fdexec __P((struct proc *p)); +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ +#endif /* __APPLE_API_UNSTABLE */ + #endif /* !_SYS_FILEDESC_H_ */ diff --git a/bsd/sys/filio.h b/bsd/sys/filio.h index 5a29cc8d9..10465cc8e 100644 --- a/bsd/sys/filio.h +++ b/bsd/sys/filio.h @@ -73,5 +73,6 @@ #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 */ +#define FIODTYPE _IOR('f', 122, int) /* get d_type */ #endif /* !_SYS_FILIO_H_ */ diff --git a/bsd/sys/ipc.h b/bsd/sys/ipc.h index 2a3f3169a..5c642955e 100644 --- a/bsd/sys/ipc.h +++ b/bsd/sys/ipc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -64,6 +64,8 @@ * @(#)ipc.h 8.4 (Berkeley) 2/19/95 */ +#include + /* * SVID compatible ipc.h file */ @@ -97,6 +99,8 @@ struct ipc_perm { #define IPC_STAT 2 /* get options */ #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE + /* Macros to convert between ipc ids and array indices or sequence ids */ #define IPCID_TO_IX(id) ((id) & 0xffff) #define IPCID_TO_SEQ(id) (((id) >> 16) & 0xffff) @@ -105,6 +109,7 @@ struct ipc_perm { struct ucred; int ipcperm __P((struct ucred *, struct ipc_perm *, int)); +#endif /* __APPLE_API_PRIVATE */ #else /* ! KERNEL */ /* XXX doesn't really belong here, but has been historical practice in SysV. */ diff --git a/bsd/sys/kdebug.h b/bsd/sys/kdebug.h index b1103b6d7..305ac531d 100644 --- a/bsd/sys/kdebug.h +++ b/bsd/sys/kdebug.h @@ -29,9 +29,12 @@ #ifndef BSD_SYS_KDEBUG_H #define BSD_SYS_KDEBUG_H +#include #include __BEGIN_DECLS +#ifdef __APPLE_API_UNSTABLE + #include #if defined(KERNEL_BUILD) #include @@ -72,6 +75,7 @@ __BEGIN_DECLS #define DBG_TRACE 7 #define DBG_DLIL 8 #define DBG_MISC 20 +#define DBG_DYLD 31 #define DBG_MIG 255 /* **** The Kernel Debug Sub Classes for Mach (DBG_MACH) **** */ @@ -98,6 +102,8 @@ __BEGIN_DECLS #define MACH_CALLOUT 0x4 /* callouts */ #define MACH_STACK_DETACH 0x5 #define MACH_MAKE_RUNNABLE 0x6 /* make thread runnable */ +#define MACH_PROMOTE 0x7 /* promoted due to resource */ +#define MACH_DEMOTE 0x8 /* promotion undone */ /* **** The Kernel Debug Sub Classes for Network (DBG_NETWORK) **** */ #define DBG_NETIP 1 /* Internet Protocol */ @@ -140,6 +146,7 @@ __BEGIN_DECLS #define DBG_IOCMDQ 13 /* Command queue latencies */ #define DBG_IOMCURS 14 /* Memory Cursor */ #define DBG_IOMDESC 15 /* Memory Descriptors */ +#define DBG_IOPOWER 16 /* Power Managerment */ /* **** The Kernel Debug Sub Classes for Device Drivers (DBG_DRIVERS) **** */ #define DBG_DRVSCSI 1 /* SCSI */ @@ -161,6 +168,7 @@ __BEGIN_DECLS /* The Kernel Debug Sub Classes for File System */ #define DBG_FSRW 1 /* reads and writes to the filesystem */ +#define DBG_DKRW 2 /* reads and writes to the disk */ /* The Kernel Debug Sub Classes for BSD */ #define DBG_BSD_EXCP_SC 0x0C /* System Calls */ @@ -169,6 +177,16 @@ __BEGIN_DECLS #define DBG_TRACE_DATA 0 #define DBG_TRACE_STRING 1 +/* The Kernel Debug Sub Classes for DBG_DYLD */ +#define DBG_DYLD_STRING 5 + +/* The Kernel Debug modifiers for the DBG_DKRW sub class */ +#define DKIO_DONE 0x01 +#define DKIO_READ 0x02 +#define DKIO_ASYNC 0x04 +#define DKIO_META 0x08 +#define DKIO_PAGING 0x10 + /**********************************************************************/ #define KDBG_CODE(Class, SubClass, code) (((Class & 0xff) << 24) | ((SubClass & 0xff) << 16) | ((code & 0x3fff) << 2)) @@ -184,6 +202,7 @@ __BEGIN_DECLS #define TRACEDBG_CODE(SubClass,code) KDBG_CODE(DBG_TRACE, SubClass, code) #define MISCDBG_CODE(SubClass,code) KDBG_CODE(DBG_MISC, SubClass, code) #define DLILDBG_CODE(SubClass,code) KDBG_CODE(DBG_DLIL, SubClass, code) +#define DYLDDBG_CODE(SubClass,code) KDBG_CODE(DBG_DYLD, SubClass, code) /* Usage: * kernel_debug((KDBG_CODE(DBG_NETWORK, DNET_PROTOCOL, 51) | DBG_FUNC_START), @@ -213,6 +232,10 @@ __BEGIN_DECLS */ extern unsigned int kdebug_enable; +#define KDEBUG_ENABLE_TRACE 0x1 +#define KDEBUG_ENABLE_ENTROPY 0x2 +#define KDEBUG_ENABLE_CHUD 0x4 + #define KERNEL_DEBUG_CONSTANT(x,a,b,c,d,e) \ do { \ if (kdebug_enable) \ @@ -250,10 +273,12 @@ do { \ #endif +#endif /* __APPLE_API_UNSTABLE */ __END_DECLS #ifdef KERNEL_PRIVATE +#ifdef __APPLE_API_PRIVATE /* * private kernel_debug definitions */ @@ -296,6 +321,7 @@ typedef struct int nolog; int flags; int nkdthreads; + int bufid; } kbufinfo_t; typedef struct @@ -331,6 +357,7 @@ typedef struct #define KDBG_THRMAP 12 #define KDBG_PIDEX 14 #define KDBG_SETRTCDEC 15 +#define KDBG_KDGETENTROPY 16 /* Minimum value allowed when setting decrementer ticks */ #define KDBG_MINRTCDEC 2500 @@ -360,6 +387,7 @@ typedef struct unsigned long pcsample_end; } pcinfo_t; +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL_PRIVATE */ #endif /* !BSD_SYS_KDEBUG_H */ diff --git a/bsd/sys/kern_control.h b/bsd/sys/kern_control.h new file mode 100644 index 000000000..04b37c06a --- /dev/null +++ b/bsd/sys/kern_control.h @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#ifndef SYS_KERN_CONTROL_H +#define SYS_KERN_CONTROL_H + +#include + +#ifdef __APPLE_API_UNSTABLE +/* + * Define Controller event subclass, and associated events. + */ + +/* Subclass of KEV_SYSTEM_CLASS */ +#define KEV_CTL_SUBCLASS 1 + +#define KEV_CTL_REGISTERED 1 /* a new controller appears */ +#define KEV_CTL_DEREGISTERED 2 /* a controller disappears */ + +/* All KEV_CTL_SUBCLASS events share the same header */ +struct ctl_event_data { + u_int32_t ctl_id; + u_int32_t ctl_unit; +}; + + +/* + * Controls destined to the Controller Manager. + */ + +#define CTLIOCGCOUNT _IOR('N', 1, int) /* get number of control structures registered */ + +/* + * Controller address structure + * used to establish contact between user client and kernel controller + * sc_id/sc_unit uniquely identify each controller + * sc_id is a 32-bit "signature" obtained by developers from Apple Computer + * sc_unit is a unit number for this sc_id, and is privately used + * by the developper to identify several instances to control + */ + +struct sockaddr_ctl +{ + u_char sc_len; /* sizeof(struct sockaddr_ctl) */ + u_char sc_family; /* AF_SYSTEM */ + u_int16_t ss_sysaddr; /* AF_SYS_CONTROL */ + u_int32_t sc_id; /* 32-bit "signature" managed by Apple */ + u_int32_t sc_unit; /* Developer private unit number */ + u_int32_t sc_reserved[5]; +}; +#endif /* __APPLE_API_UNSTABLE */ + +#ifdef KERNEL +#ifdef __APPLE_API_UNSTABLE + +/* Reference to a controller object */ +typedef void * kern_ctl_ref; + +/* Support flags for controllers */ +#define CTL_FLAG_PRIVILEGED 0x1 /* user must be root to contact controller */ + +/* Data flags for controllers */ +#define CTL_DATA_NOWAKEUP 0x1 /* don't wake up client yet */ + + +/* + * Controller registration structure, given at registration time + */ +struct kern_ctl_reg +{ + /* control information */ + u_int32_t ctl_id; /* unique id of the controller, provided by DTS */ + u_int32_t ctl_unit; /* unit number for the controller, for the specified id */ + /* a controller can be registered several times with the same id */ + /* but must have a different unit number */ + + /* control settings */ + u_int32_t ctl_flags; /* support flags */ + u_int32_t ctl_sendsize; /* override send/receive buffer size */ + u_int32_t ctl_recvsize; /* 0 = use default values */ + + /* Dispatch functions */ + + int (*ctl_connect) + (kern_ctl_ref ctlref, void *userdata); + /* Make contact, called when user client calls connect */ + /* the socket with the id/unit of the controller */ + + void (*ctl_disconnect) + (kern_ctl_ref ctlref, void *userdata); + /* Break contact, called when user client */ + /* closes the control socket */ + + int (*ctl_write) + (kern_ctl_ref ctlref, void *userdata, struct mbuf *m); + /* Send data to the controller, called when user client */ + /* writes data to the socket */ + + int (*ctl_set) + (kern_ctl_ref ctlref, void *userdata, int opt, void *data, size_t len); + /* set controller configuration, called when user client */ + /* calls setsockopt() for the socket */ + /* opt is the option number */ + /* data points to the data, already copied in kernel space */ + /* len is the lenght of the data buffer */ + + int (*ctl_get) + (kern_ctl_ref ctlref, void *userdata, int opt, void *data, size_t *len); + /* get controller configuration, called when user client */ + /* calls getsockopt() for the socket */ + /* opt is the option number */ + /* data points to the data buffer of max lenght len */ + /* the controller can directly copy data in the buffer space */ + /* and does not need to worry about copying out the data */ + /* as long as it respects the max buffer lenght */ + /* on input, len contains the maximum buffer length */ + /* on output, len contains the actual buffer lenght */ + /* if data is NULL on input, then, by convention, the controller */ + /* should return in len the lenght of the data it would like */ + /* to return in the subsequent call for that option */ + + /* prepare the future */ + u_int32_t ctl_reserved[4]; /* for future use if needed */ +}; + + +/* + * FUNCTION : + * Register the controller to the controller manager + * For example, can be called from a Kernel Extension Start routine + * + * PARAMETERS : + * userctl : Registration structure containing control information + * and callback functions for the controller. + * Callbacks are optional and can be null. + * A controller with all callbacks set to null would not be very useful. + * userdata : This parameter is for use by the controller and + * will be passed to every callback function + * + * RETURN CODE : + * 0 : No error + * ctlref will be filled with a control reference, + * to use in subsequent call to the controller manager + * EINVAL : Invalid registration structure + * ENOMEM : Not enough memory available to register the controller + * EEXIST : Controller id/unit already registered + */ + +int +ctl_register(struct kern_ctl_reg *userctl, void *userdata, kern_ctl_ref *ctlref); + +/* + * FUNCTION : + * Deregister the controller + * For example, can be called from a Kernel Extension Stop routine + * + * PARAMETERS : + * ctlref : Reference to the controller previously registered + * + * RETURN CODE : + * 0 : No error, + * The controller manager no longer knows about the controller + * EINVAL : Invalid reference + */ + +int +ctl_deregister(kern_ctl_ref ctlref); + +/* + * FUNCTION : + * Send data to the application in contact with the controller + * ctl_enqueuedata will allocate a mbuf, copy data and enqueue it. + * + * PARAMETERS : + * ctlref : Reference to the controller previously registered + * data : Data to send + * len : Length of the data (maximum lenght of MCLBYTES) + * flags : Flags used when enqueing + * CTL_DATA_NOWAKEUP = just enqueue, don't wake up client + * + * RETURN CODE : + * 0 : No error + * EINVAL: Invalid reference + * EMSGSIZE: The buffer is too large + * ENOTCONN : No user client is connected + * ENOBUFS : Socket buffer is full, or can't get a new mbuf + * The controller should re-enqueue later + */ + +int +ctl_enqueuedata(kern_ctl_ref ctlref, void *data, size_t len, u_int32_t flags); + +/* + * FUNCTION : + * Send data to the application in contact with the controller + * + * PARAMETERS : + * ctlref : Reference to the controller previously registered + * m : mbuf containing the data to send + * flags : Flags used when enqueing + * CTL_DATA_NOWAKEUP = just enqueue, don't wake up client + * + * RETURN CODE : + * 0 : No error + * EINVAL: Invalid reference + * ENOTCONN : No user client is connected + * ENOBUFS : Socket buffer is full, + * The controller should either free the mbuf or re-enqueue later + */ + +int +ctl_enqueuembuf(kern_ctl_ref ctlref, struct mbuf *m, u_int32_t flags); + +#endif /* __APPLE_API_UNSTABLE */ +#endif /* KERNEL */ + +#endif /* SYS_KERN_CONTROL_H */ + diff --git a/bsd/sys/kern_event.h b/bsd/sys/kern_event.h index 962005cc2..5a232c02a 100644 --- a/bsd/sys/kern_event.h +++ b/bsd/sys/kern_event.h @@ -25,9 +25,9 @@ #ifndef SYS_KERN_EVENT_H #define SYS_KERN_EVENT_H -#define SYSPROTO_EVENT 1 - +#include #include +#include #define KEVENTS_ON 1 #define KEV_SNDSPACE (4 * 1024) @@ -50,6 +50,7 @@ #define KEV_NETWORK_CLASS 1 #define KEV_IOKIT_CLASS 2 +#define KEV_SYSTEM_CLASS 3 struct kern_event_msg { @@ -77,6 +78,7 @@ struct kev_request { #define SIOCGKEVFILT _IOR('e', 3, struct kev_request) #ifdef KERNEL +#ifdef __APPLE_API_UNSTABLE #define N_KEV_VECTORS 5 @@ -95,7 +97,10 @@ struct kev_msg { struct kev_d_vectors dv[N_KEV_VECTORS]; /* Up to n data vectors */ }; +int kev_post_msg(struct kev_msg *event); +#endif /* ___APPLE_API_UNSTABLE */ +#ifdef __APPLE_API_PRIVATE LIST_HEAD(kern_event_head, kern_event_pcb); @@ -109,9 +114,7 @@ struct kern_event_pcb { #define sotoevpcb(so) ((struct kern_event_pcb *)((so)->so_pcb)) - -int kev_post_msg(struct kev_msg *event); - +#endif /* __APPLE_API_PRIVATE */ #endif #endif diff --git a/bsd/sys/kernel.h b/bsd/sys/kernel.h index 91e4c30d7..420f56e2d 100644 --- a/bsd/sys/kernel.h +++ b/bsd/sys/kernel.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -62,10 +62,13 @@ #ifndef _SYS_KERNEL_H_ #define _SYS_KERNEL_H_ +#include + #ifdef KERNEL #include +#ifdef __APPLE_API_PRIVATE /* Global variables for the kernel. */ /* 1.1 */ @@ -76,20 +79,20 @@ extern char domainname[MAXHOSTNAMELEN]; extern int domainnamelen; /* 1.2 */ -// extern volatile struct timeval mono_time; extern struct timeval boottime; -extern struct timeval runtime; +#ifdef __APPLE_API_OBSOLETE extern volatile struct timeval time; extern struct timezone tz; /* XXX */ - +extern int lbolt; /* once a second sleep address */ extern int tick; /* usec per tick (1000000 / hz) */ -extern int tickfix; /* periodic tick adj. tick not integral */ -extern int tickfixinterval; /* interval at which to apply adjustment */ -extern int tickadj; /* "standard" clock skew, us./tick */ extern int hz; /* system clock's frequency */ + extern int stathz; /* statistics clock's frequency */ extern int profhz; /* profiling clock's frequency */ -extern int lbolt; /* once a second sleep address */ +#endif /* __APPLE_API_OBSOLETE */ + +#endif /* __APPLE_API_PRIVATE */ + #endif /* KERNEL */ -#endif /* !_SYS_KERNEL_H_ */ +#endif /* !_SYS_KERNEL_H_ */ diff --git a/bsd/sys/ktrace.h b/bsd/sys/ktrace.h index c10ea539b..ce39adb2d 100644 --- a/bsd/sys/ktrace.h +++ b/bsd/sys/ktrace.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -53,11 +53,24 @@ * SUCH DAMAGE. * * @(#)ktrace.h 8.1 (Berkeley) 6/2/93 + * $FreeBSD: src/sys/sys/ktrace.h,v 1.19.2.3 2001/01/06 09:58:23 alfred Exp $ */ #ifndef _SYS_KTRACE_H_ #define _SYS_KTRACE_H_ +#include + +#if defined(MACH_KERNEL_PRIVATE) + +#ifdef __APPLE_API_PRIVATE +void ktrsyscall(void *, int, int, void *, int); +void ktrsysret(void *, int, int, int, int); +#endif /* __APPLE_API_PRIVATE */ + +#else + +#ifdef __APPLE_API_UNSTABLE /* * operations to ktrace system call (KTROP(op)) */ @@ -97,11 +110,12 @@ struct ktr_header { */ #define KTR_SYSCALL 1 struct ktr_syscall { - int ktr_code; /* syscall number */ - int ktr_argsize; /* size of arguments */ + short ktr_code; /* syscall number */ + short ktr_narg; /* number of arguments */ /* - * followed by ktr_argsize/sizeof(register_t) "register_t"s + * followed by ktr_narg register_t */ + register_t ktr_args[1]; }; /* @@ -112,7 +126,7 @@ struct ktr_sysret { short ktr_code; short ktr_eosys; int ktr_error; - int ktr_retval; + register_t ktr_retval; }; /* @@ -140,8 +154,8 @@ struct ktr_genio { struct ktr_psig { int signo; sig_t action; - int mask; int code; + sigset_t mask; }; /* @@ -153,6 +167,12 @@ struct ktr_csw { int user; /* 1 if usermode (ivcsw), 0 if kernel (vcsw) */ }; +/* + * KTR_USER - data comming from userland + */ +#define KTR_USER_MAXLEN 2048 /* maximum length of passed data */ +#define KTR_USER 7 + /* * kernel trace points (in p_traceflag) */ @@ -163,6 +183,7 @@ struct ktr_csw { #define KTRFAC_GENIO (1< __BEGIN_DECLS int ktrace __P((const char *, int, int, pid_t)); +int utrace __P((const void *, size_t)); __END_DECLS #endif /* !KERNEL */ + +#endif /* __APPLE_API_UNSTABLE */ +#endif /* !MACH_KERNEL_PRIVATE */ #endif /* !_SYS_KTRACE_H_ */ diff --git a/bsd/sys/linker_set.h b/bsd/sys/linker_set.h index e57d1b8d0..25776d91a 100644 --- a/bsd/sys/linker_set.h +++ b/bsd/sys/linker_set.h @@ -49,6 +49,9 @@ #ifndef _SYS_LINKER_SET_H_ #define _SYS_LINKER_SET_H_ +#include + +#if !defined(KERNEL) || defined(__APPLE_API_PRIVATE) /* * The following macros are used to declare global sets of objects, which * are collected by the linker into a `struct linker_set' as defined below. @@ -95,6 +98,7 @@ struct linker_set { const void *ls_items[1]; /* really ls_length of them, * trailing NULL */ }; +#endif /* !KERNEL || __APPLE_API_PRIVATE */ #endif /* _SYS_LINKER_SET_H_ */ diff --git a/bsd/sys/loadable_fs.h b/bsd/sys/loadable_fs.h index 5b57f06e5..1d198c74d 100644 --- a/bsd/sys/loadable_fs.h +++ b/bsd/sys/loadable_fs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -32,20 +32,14 @@ /* * loadable_fs.h - message struct for loading and initializing loadable * file systems. - * - * HISTORY - * 26-Jun-90 Doug Mitchell at NeXT - * Created. - * 5-Nov-91 Lee Boynton at NeXT - * Added support for initialization, labels, and WSM options - * 29-Mar-99 A.Ramesh at Apple - * Added to Mac OS X, removed mach message related defns */ -#ifndef _LOADABLE_FS_ -#define _LOADABLE_FS_ +#ifndef _SYS_LOADABLE_FS_ +#define _SYS_LOADABLE_FS_ +#include +#ifdef __APPLE_API_UNSTABLE /* * Constants for Loadabls FS Utilities (in "/System/Library/Filesystems") * @@ -122,4 +116,5 @@ #define MNTOPT_FS "filesystem=" /* e.g. "filesystem=DOS" */ #define MNTOPT_REMOVABLE "removable" -#endif /* _LOADABLE_FS_ */ +#endif /* __APPLE_API_UNSTABLE */ +#endif /* _SYS_LOADABLE_FS_ */ diff --git a/bsd/sys/lock.h b/bsd/sys/lock.h index 7e7015408..de18dd2d1 100644 --- a/bsd/sys/lock.h +++ b/bsd/sys/lock.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -61,8 +61,11 @@ #ifndef _SYS_LOCK_H_ #define _SYS_LOCK_H_ -#ifdef KERNEL +#include + +#ifdef KERNEL +#ifdef __APPLE_API_UNSTABLE #include #include @@ -86,6 +89,12 @@ #endif #define simple_lock_try(l) 1 +#if defined(thread_sleep_simple_lock) +#undef thread_sleep_simple_lock +#endif +#define thread_sleep_simple_lock(l, e, i) thread_sleep_funnel((e), (i)) + +#endif /* __APPLE_API_UNSTABLE */ #else /* KERNEL */ #ifndef _MACHINE_SIMPLE_LOCK_DATA_ @@ -110,6 +119,8 @@ class simple_lock_data_t name; #endif /* _MACHINE_SIMPLE_LOCK_DATA_ */ #endif /* KERNEL */ + +#ifdef __APPLE_API_UNSTABLE /* * The general lock structure. Provides for multiple shared locks, * upgrading from shared to exclusive, and sleeping until the lock @@ -232,4 +243,6 @@ int lockmgr __P((struct lock__bsd__ *, u_int flags, simple_lock_t, struct proc *p)); int lockstatus __P((struct lock__bsd__ *)); +#endif /* __APPLE_API_UNSTABLE */ + #endif /* _SYS_LOCK_H_ */ diff --git a/bsd/sys/lockf.h b/bsd/sys/lockf.h index 5eaaac6dd..0c3339c78 100644 --- a/bsd/sys/lockf.h +++ b/bsd/sys/lockf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -61,6 +61,9 @@ #ifndef _SYS_LOCKF_H_ #define _SYS_LOCKF_H_ +#include + +#ifdef __APPLE_API_PRIVATE /* * The lockf structure is a kernel structure which contains the information * associated with a byte range lock. The lockf structures are linked into @@ -104,4 +107,7 @@ void lf_print __P((char *, struct lockf *)); void lf_printlist __P((char *, struct lockf *)); __END_DECLS #endif /* LOCKF_DEBUG */ + +#endif /* __APPLE_API_PRIVATE */ + #endif /* !_SYS_LOCKF_H_ */ diff --git a/bsd/sys/mach_swapon.h b/bsd/sys/mach_swapon.h index 8e76ea9da..fcba2d61b 100644 --- a/bsd/sys/mach_swapon.h +++ b/bsd/sys/mach_swapon.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -28,19 +28,15 @@ * */ -/* - * mach_swapon.h - * - * Definitions for the mach_swapon system call. - * - * HISTORY - * 28-Feb-88 Peter King (king) at NeXT, Inc. - * Created - */ - #ifndef _MACH_SWAPON_H #define _MACH_SWAPON_H +#include + +#warning obsolete header file! Please delete the include from your sources. + +#ifdef __APPLE_API_OBSOLETE #define MS_PREFER 0x1 /* This device/file is preferred */ +#endif /* __APPLE_API_OBSOLETE */ #endif /* _MACH_SWAPON_H */ diff --git a/bsd/sys/malloc.h b/bsd/sys/malloc.h index 152058bcb..fb05b8734 100644 --- a/bsd/sys/malloc.h +++ b/bsd/sys/malloc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -59,6 +59,8 @@ #ifndef _SYS_MALLOC_H_ #define _SYS_MALLOC_H_ +#include + #define KMEMSTATS /* @@ -146,21 +148,24 @@ #define M_OFILETABL 73 /* Open file descriptor table */ #define M_MCLUST 74 /* mbuf cluster buffers */ #define M_HFSMNT 75 /* HFS mount structure */ -#define M_HFSNODE 76 /* HFS private node structre */ -#define M_HFSFMETA 77 /* HFS file meta data */ +#define M_HFSNODE 76 /* HFS catalog node */ +#define M_HFSFORK 77 /* HFS file fork */ #define M_VOLFSMNT 78 /* VOLFS mount structure */ #define M_VOLFSNODE 79 /* VOLFS private node part */ #define M_TEMP 80 /* misc temporary data buffers */ +#define M_KTRACE M_TEMP /* ktrace buffers */ #define M_SECA 81 /* security associations, key management */ #define M_DEVFS 82 #define M_IPFW 83 /* IP Forwarding/NAT */ -#define M_UDFNODE 84 /* UDF inodes */ -#define M_UDFMNT 85 /* UDF mount structures */ -#define M_IP6NDP 86 /* IPv6 Neighbour Discovery*/ -#define M_IP6OPT 87 /* IPv6 options management */ -#define M_NATPT 88 /* KAME NAT feature */ +#define M_UDFNODE 84 /* UDF inodes */ +#define M_UDFMNT 85 /* UDF mount structures */ +#define M_IP6NDP 86 /* IPv6 Neighbour Discovery*/ +#define M_IP6OPT 87 /* IPv6 options management */ +#define M_IP6MISC 88 /* IPv6 misc. memory */ +#define M_TSEGQ 89 /* TCP segment queue entry */ +#define M_IGMP 90 -#define M_LAST 89 /* Must be last type + 1 */ +#define M_LAST 91 /* Must be last type + 1 */ /* Strings corresponding to types of memory */ /* Must be in synch with the #defines above */ @@ -241,8 +246,8 @@ "ofile tabl", /* 73 M_OFILETABL */ \ "mbuf clust", /* 74 M_MCLUST */ \ "HFS mount", /* 75 M_HFSMNT */ \ - "HFS node", /* 76 M_HFSNODE */ \ - "HFS fmeta", /* 77 M_HFSFMETA */ \ + "HFS node", /* 76 M_HFSNODE */ \ + "HFS fork", /* 77 M_HFSFORK */ \ "VOLFS mount", /* 78 M_VOLFSMNT */ \ "VOLFS node", /* 79 M_VOLFSNODE */ \ "temp", /* 80 M_TEMP */ \ @@ -253,7 +258,9 @@ "UDF mount" /* 85 M_UDFMNT */ \ "IPv6 NDP", /* 86 M_IP6NDP */ \ "IPv6 options", /* 87 M_IP6OPT */ \ - "NATPT", /* 88 M_NATPT */ \ + "IPv6 Misc" /* 88 M_IP6MISC */\ + "TCP Segment Q" /* 89 M_TSEGQ */\ + "IGMP state" /* 90 M_IGMP */\ } struct kmemstats { @@ -270,7 +277,9 @@ struct kmemstats { }; #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE extern struct kmemstats kmemstats[]; +#endif /* __APPLE_API_PRIVATE */ /* * The malloc/free primatives used diff --git a/bsd/sys/mbuf.h b/bsd/sys/mbuf.h index ba1bf3bcd..360b80d91 100644 --- a/bsd/sys/mbuf.h +++ b/bsd/sys/mbuf.h @@ -72,6 +72,7 @@ #ifndef _SYS_MBUF_H_ #define _SYS_MBUF_H_ +#include #include /* @@ -82,6 +83,7 @@ * at least MINCLSIZE of data must be stored. */ +#ifdef __APPLE_API_UNSTABLE #define MLEN (MSIZE - sizeof(struct m_hdr)) /* normal data len */ #define MHLEN (MLEN - sizeof(struct pkthdr)) /* data len w/pkthdr */ @@ -90,7 +92,6 @@ #define NMBPCL (sizeof(union mcluster) / sizeof(struct mbuf)) - /* * Macros for type conversion * mtod(m,t) - convert mbuf pointer to data pointer of correct type @@ -98,13 +99,13 @@ * 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 *)((u_long)(x) & ~(MSIZE-1))) -#define mtocl(x) ((union mcluster *)(x) - (union mcluster *)mbutl) -#define cltom(x) ((union mcluster *)(mbutl + (x))) +#define mtod(m,t) ((t)m_mtod(m)) +#define dtom(x) m_dtom(x) +#define mtocl(x) m_mtocl(x) +#define cltom(x) m_cltom(x) -#define MCLREF(p) (++mclrefcnt[mtocl(p)]) -#define MCLUNREF(p) (--mclrefcnt[mtocl(p)] == 0) +#define MCLREF(p) m_mclref(p) +#define MCLUNREF(p) m_mclunref(p) /* header at beginning of each mbuf: */ struct m_hdr { @@ -174,23 +175,21 @@ struct mbuf { #define M_PKTHDR 0x0002 /* start of record */ #define M_EOR 0x0004 /* end of record */ #define M_PROTO1 0x0008 /* protocol-specific */ - -#define M_MIP6TUNNEL 0x0010 /* MIP6 temporary use */ +#define M_PROTO2 0x0010 /* protocol-specific */ +#define M_PROTO3 0x0020 /* protocol-specific */ +#define M_PROTO4 0x0040 /* protocol-specific */ +#define M_PROTO5 0x0080 /* protocol-specific */ /* 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 */ -#define M_FRAG 0x0400 /* packet is a fragment of a larger packet */ -#define M_ANYCAST6 0x0800 /* received as IPv6 anycast */ - -/* mbuf pkthdr flags, also in m_flags */ -#define M_AUTHIPHDR 0x1000 /* data origin authentication for IP header */ -#define M_DECRYPTED 0x2000 /* confidentiality */ -#define M_LOOP 0x4000 /* for Mbuf statistics */ -#define M_AUTHIPDGM 0x8000 /* data origin authentication */ +#define M_FRAG 0x0400 /* packet is a fragment of a larger packet */ +#define M_FIRSTFRAG 0x0800 /* packet is first fragment */ +#define M_LASTFRAG 0x1000 /* packet is last fragment */ /* flags copied when copying m_pkthdr */ -#define M_COPYFLAGS (M_PKTHDR|M_EOR|M_BCAST|M_MCAST|M_FRAG|M_ANYCAST6|M_AUTHIPHDR|M_DECRYPTED|M_LOOP|M_AUTHIPDGM) +#define M_COPYFLAGS (M_PKTHDR|M_EOR|M_PROTO1|M_PROTO1|M_PROTO2|M_PROTO3 | \ + M_PROTO4|M_PROTO5|M_BCAST|M_MCAST|M_FRAG) /* flags indicating hw checksum support and sw checksum requirements [freebsd4.1]*/ #define CSUM_IP 0x0001 /* will csum IP */ @@ -234,6 +233,8 @@ struct mbuf { #define M_DONTWAIT M_NOWAIT #define M_WAIT M_WAITOK +#ifdef __APPLE_API_PRIVATE + /* * mbuf utility macros: * @@ -249,6 +250,7 @@ decl_simple_lock_data(, mbuf_slock); #define MBUF_UNLOCK() usimple_unlock(&mbuf_slock); #define MBUF_LOCKINIT() simple_lock_init(&mbuf_slock); +#endif /* __APPLE_API_PRIVATE */ /* * mbuf allocation/deallocation macros: @@ -262,56 +264,20 @@ decl_simple_lock_data(, mbuf_slock); */ #if 1 -#define MCHECK(m) if ((m)->m_type != MT_FREE) panic("mget MCHECK: m_type=%x m=%x", m->m_type, m) +#define MCHECK(m) m_mcheck(m) #else #define MCHECK(m) #endif +#ifdef __APPLE_API_PRIVATE extern struct mbuf *mfree; /* mbuf free list */ extern simple_lock_data_t mbuf_slock; +#endif /* __APPLE_API_PRIVATE */ -#define _MINTGET(m, type) { \ - MBUF_LOCK(); \ - if (((m) = mfree) != 0) { \ - MCHECK(m); \ - ++mclrefcnt[mtocl(m)]; \ - mbstat.m_mtypes[MT_FREE]--; \ - mbstat.m_mtypes[type]++; \ - mfree = (m)->m_next; \ - } \ - MBUF_UNLOCK(); \ -} - -#define MGET(m, how, type) { \ - _MINTGET(m, type); \ - if (m) { \ - (m)->m_next = (m)->m_nextpkt = 0; \ - (m)->m_len = 0; \ - (m)->m_type = (type); \ - (m)->m_data = (m)->m_dat; \ - (m)->m_flags = 0; \ - } else \ - (m) = m_retry((how), (type)); \ -} - -#define MGETHDR(m, how, type) { \ - _MINTGET(m, type); \ - if (m) { \ - (m)->m_next = (m)->m_nextpkt = 0; \ - (m)->m_type = (type); \ - (m)->m_data = (m)->m_pktdat; \ - (m)->m_flags = M_PKTHDR; \ - (m)->m_pkthdr.len = 0; \ - (m)->m_pkthdr.rcvif = NULL; \ - (m)->m_pkthdr.header = NULL; \ - (m)->m_pkthdr.csum_flags = 0; \ - (m)->m_pkthdr.csum_data = 0; \ - (m)->m_pkthdr.aux = (struct mbuf *)NULL; \ - (m)->m_pkthdr.reserved1 = NULL; \ - (m)->m_pkthdr.reserved2 = NULL; \ - } else \ - (m) = m_retryhdr((how), (type)); \ -} + +#define MGET(m, how, type) ((m) = m_get((how), (type))) + +#define MGETHDR(m, how, type) ((m) = m_gethdr((how), (type))) /* * Mbuf cluster macros. @@ -330,40 +296,13 @@ union mcluster { char mcl_buf[MCLBYTES]; }; -#define MCLALLOC(p, how) { \ - (void)m_clalloc(1, (how)); \ - if (((p) = (caddr_t)mclfree)) { \ - ++mclrefcnt[mtocl(p)]; \ - mbstat.m_clfree--; \ - mclfree = ((union mcluster *)(p))->mcl_next; \ - } \ - MBUF_UNLOCK(); \ -} - -#define MCLGET(m, how) { \ - MCLALLOC((m)->m_ext.ext_buf, (how)); \ - if ((m)->m_ext.ext_buf) { \ - (m)->m_data = (m)->m_ext.ext_buf; \ - (m)->m_flags |= M_EXT; \ - (m)->m_ext.ext_size = MCLBYTES; \ - (m)->m_ext.ext_free = 0; \ - (m)->m_ext.ext_refs.forward = (m)->m_ext.ext_refs.backward = \ - &(m)->m_ext.ext_refs; \ - } \ -} - -#define MCLFREE(p) { \ - MBUF_LOCK(); \ - if (--mclrefcnt[mtocl(p)] == 0) { \ - ((union mcluster *)(p))->mcl_next = mclfree; \ - mclfree = (union mcluster *)(p); \ - mbstat.m_clfree++; \ - } \ - MBUF_UNLOCK(); \ -} - -#define MCLHASREFERENCE(m) \ - ((m)->m_ext.ext_refs.forward != &((m)->m_ext.ext_refs)) +#define MCLALLOC(p, how) ((p) = m_mclalloc(how)) + +#define MCLFREE(p) m_mclfree(p) + +#define MCLGET(m, how) ((m) = m_mclget(m, how)) + +#define MCLHASREFERENCE(m) m_mclhasreference(m) /* * MFREE(struct mbuf *m, struct mbuf *n) @@ -371,25 +310,20 @@ union mcluster { * Place the successor, if any, in n. */ -#define MFREE(m, n) (n) = m_free(m) +#define MFREE(m, n) ((n) = m_free(m)) /* * Copy mbuf pkthdr from from to to. * from must have M_PKTHDR set, and to must be empty. * aux pointer will be moved to `to'. */ -#define M_COPY_PKTHDR(to, from) { \ - (to)->m_pkthdr = (from)->m_pkthdr; \ - (from)->m_pkthdr.aux = (struct mbuf *)NULL; \ - (to)->m_flags = (from)->m_flags & M_COPYFLAGS; \ - (to)->m_data = (to)->m_pktdat; \ -} +#define M_COPY_PKTHDR(to, from) m_copy_pkthdr(to, from) /* * 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) \ +#define M_ALIGN(m, len) \ { (m)->m_data += (MLEN - (len)) &~ (sizeof(long) - 1); } /* * As above, for mbufs allocated with m_gethdr/MGETHDR @@ -403,7 +337,6 @@ union mcluster { * before the current start of data in an mbuf. * Subroutine - data not available if certain references. */ -int m_leadingspace(struct mbuf *); #define M_LEADINGSPACE(m) m_leadingspace(m) /* @@ -411,7 +344,6 @@ int m_leadingspace(struct mbuf *); * after the end of data in an mbuf. * Subroutine - data not available if certain references. */ -int m_trailingspace(struct mbuf *); #define M_TRAILINGSPACE(m) m_trailingspace(m) /* @@ -420,24 +352,10 @@ int m_trailingspace(struct mbuf *); * 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); \ -} +#define M_PREPEND(m, plen, how) ((m) = m_prepend_2((m), (plen), (how))) /* change mbuf to new type */ -#define MCHTYPE(m, t) { \ - MBUF_LOCK(); \ - mbstat.m_mtypes[(m)->m_type]--; \ - mbstat.m_mtypes[t]++; \ - (m)->m_type = t; \ - MBUF_UNLOCK(); \ -} +#define MCHTYPE(m, t) m_mchtype(m, t) /* length to m_copy to copy all */ #define M_COPYALL 1000000000 @@ -488,12 +406,14 @@ extern int max_hdr; /* largest link+protocol header */ extern int max_datalen; /* MHLEN - max_hdr */ struct mbuf *m_copym __P((struct mbuf *, int, int, int)); +struct mbuf *m_split __P((struct mbuf *, int, int)); struct mbuf *m_free __P((struct mbuf *)); struct mbuf *m_get __P((int, int)); struct mbuf *m_getpacket __P((void)); struct mbuf *m_getclr __P((int, int)); struct mbuf *m_gethdr __P((int, int)); struct mbuf *m_prepend __P((struct mbuf *, int, int)); +struct mbuf *m_prepend_2 __P((struct mbuf *, int, int)); struct mbuf *m_pullup __P((struct mbuf *, int)); struct mbuf *m_retry __P((int, int)); struct mbuf *m_retryhdr __P((int, int)); @@ -503,8 +423,32 @@ void m_freem __P((struct mbuf *)); int m_freem_list __P((struct mbuf *)); struct mbuf *m_devget __P((char *, int, int, struct ifnet *, void (*)())); char *mcl_to_paddr __P((char *)); +struct mbuf *m_pulldown __P((struct mbuf*, int, int, int*)); struct mbuf *m_aux_add __P((struct mbuf *, int, int)); struct mbuf *m_aux_find __P((struct mbuf *, int, int)); void m_aux_delete __P((struct mbuf *, struct mbuf *)); + +struct mbuf *m_mclget __P((struct mbuf *, int)); +caddr_t m_mclalloc __P((int)); +void m_mclfree __P((caddr_t p)); +int m_mclhasreference __P((struct mbuf *)); +void m_copy_pkthdr __P((struct mbuf *, struct mbuf*)); + +int m_mclref __P((struct mbuf *)); +int m_mclunref __P((struct mbuf *)); + +void * m_mtod __P((struct mbuf *)); +struct mbuf * m_dtom __P((void *)); +int m_mtocl __P((void *)); +union mcluster *m_cltom __P((int )); + +int m_trailingspace __P((struct mbuf *)); +int m_leadingspace __P((struct mbuf *)); + +void m_mchtype __P((struct mbuf *m, int t)); + +void m_mcheck __P((struct mbuf*)); + #endif +#endif /* __APPLE_API_UNSTABLE */ #endif /* !_SYS_MBUF_H_ */ diff --git a/bsd/sys/md5.h b/bsd/sys/md5.h index 14ce796cc..5ae59a40b 100644 --- a/bsd/sys/md5.h +++ b/bsd/sys/md5.h @@ -1,5 +1,4 @@ /* MD5.H - header file for MD5C.C - * $Id: md5.h,v 1.2 2000/09/14 20:35:28 lindak Exp $ */ /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All @@ -26,6 +25,10 @@ documentation and/or software. #ifndef _SYS_MD5_H_ #define _SYS_MD5_H_ + +#include + +#if !defined(KERNEL) || defined(__APPLE_API_PRIVATE) /* MD5 context. */ typedef struct MD5Context { u_int32_t state[4]; /* state (ABCD) */ @@ -47,4 +50,5 @@ char * MD5Data(const unsigned char *, unsigned int, char *); void MD5Transform __P((u_int32_t [4], const unsigned char [64])); #endif __END_DECLS +#endif /* !KERNEL || __APPLE_API_PRIVATE */ #endif /* _SYS_MD5_H_ */ diff --git a/bsd/sys/mman.h b/bsd/sys/mman.h index 3b216759f..57faf0299 100644 --- a/bsd/sys/mman.h +++ b/bsd/sys/mman.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -58,6 +58,7 @@ #ifndef _SYS_MMAN_H_ #define _SYS_MMAN_H_ +#include #include /* @@ -127,6 +128,11 @@ #define MADV_WILLNEED 3 /* will need these pages */ #define MADV_DONTNEED 4 /* dont need these pages */ #define MADV_FREE 5 /* dont need these pages, and junk contents */ +#define POSIX_MADV_NORMAL MADV_NORMAL +#define POSIX_MADV_RANDOM MADV_RANDOM +#define POSIX_MADV_SEQUENTIAL MADV_SEQUENTIAL +#define POSIX_MADV_WILLNEED MADV_WILLNEED +#define POSIX_MADV_DONTNEED MADV_DONTNEED /* * Return bits from mincore @@ -157,9 +163,14 @@ int munlock __P((const void *, size_t)); int munmap __P((void *, size_t)); int shm_open __P((const char *, int, ...)); int shm_unlink __P((const char *)); +int posix_madvise __P((void *, size_t, int)); #ifndef _POSIX_SOURCE -int load_shared_file __P((char *, caddr_t, u_long, caddr_t *, int, sf_mapping_t *, int *)); +#ifdef __APPLE_API_PRIVATE +int load_shared_file __P((char *, caddr_t, u_long, + caddr_t *, int, sf_mapping_t *, int *)); int reset_shared_file __P((caddr_t *, int, sf_mapping_t *)); +int new_system_shared_regions __P((void)); +#endif /* __APPLE_API_PRIVATE */ int madvise __P((void *, size_t, int)); int mincore __P((const void *, size_t, char *)); int minherit __P((void *, size_t, int)); diff --git a/bsd/sys/mount.h b/bsd/sys/mount.h index 61fdd6bb7..a2840d9bc 100644 --- a/bsd/sys/mount.h +++ b/bsd/sys/mount.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -58,6 +58,7 @@ #ifndef _SYS_MOUNT_H_ #define _SYS_MOUNT_H_ +#include #ifndef KERNEL #include #endif @@ -115,6 +116,7 @@ struct statfs { #endif }; +#ifdef __APPLE_API_PRIVATE /* * Structure per mounted file system. Each mounted file system has an * array of operations and an instance record. The file systems are @@ -140,6 +142,7 @@ struct mount { u_int16_t mnt_segreadcnt; /* Max. segment count for read */ u_int16_t mnt_segwritecnt; /* Max. segment count for write */ }; +#endif /* __APPLE_API_PRIVATE */ /* * User specifiable flags. @@ -257,6 +260,7 @@ struct export_args { int ex_masklen; /* and the smask length */ }; +#ifdef __APPLE_API_UNSTABLE /* * Filesystem configuration information. One of these exists for each * type of filesystem supported by the kernel. These are searched at @@ -272,8 +276,10 @@ struct vfsconf { struct vfsconf *vfc_next; /* next in list */ }; -#ifdef KERNEL +#endif /*__APPLE_API_UNSTABLE */ +#ifdef KERNEL +#ifdef __APPLE_API_UNSTABLE extern int maxvfsconf; /* highest defined filesystem type */ extern struct vfsconf *vfsconf; /* head of list of filesystem types */ extern int maxvfsslots; /* Maximum slots available to be used */ @@ -356,13 +362,16 @@ struct netcred *vfs_export_lookup __P((struct mount *, struct netexport *, void vfs_getnewfsid __P((struct mount *)); struct mount *vfs_getvfs __P((fsid_t *)); int vfs_mountedon __P((struct vnode *)); +void vfs_unbusy __P((struct mount *, struct proc *)); +#ifdef __APPLE_API_PRIVATE int vfs_mountroot __P((void)); int vfs_rootmountalloc __P((char *, char *, struct mount **)); -void vfs_unbusy __P((struct mount *, struct proc *)); void vfs_unmountall __P((void)); +#endif /* __APPLE_API_PRIVATE */ extern CIRCLEQ_HEAD(mntlist, mount) mountlist; extern struct slock mountlist_slock; +#endif /* __APPLE_API_UNSTABLE */ #else /* !KERNEL */ #include @@ -375,6 +384,7 @@ int getmntinfo __P((struct statfs **, int)); int mount __P((const char *, const char *, int, void *)); int statfs __P((const char *, struct statfs *)); int unmount __P((const char *, int)); +int getvfsbyname __P((const char *, struct vfsconf *)); __END_DECLS #endif /* KERNEL */ diff --git a/bsd/sys/msg.h b/bsd/sys/msg.h index d639477d8..76e3f1c27 100644 --- a/bsd/sys/msg.h +++ b/bsd/sys/msg.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -43,8 +43,12 @@ #ifndef _SYS_MSG_H_ #define _SYS_MSG_H_ +#include + +#ifdef __APPLE_API_UNSTABLE #include + /* * The MSG_NOERROR identifier value, the msqid_ds struct and the msg struct * are as defined by the SV API Intel 386 Processor Supplement. @@ -175,4 +179,5 @@ int msgrcv __P((int, void*, size_t, long, int)); __END_DECLS #endif /* !KERNEL */ +#endif /* __APPLE_API_UNSTABLE */ #endif /* !_SYS_MSG_H_ */ diff --git a/bsd/sys/mtio.h b/bsd/sys/mtio.h index d7b9006e9..ab2f39e65 100644 --- a/bsd/sys/mtio.h +++ b/bsd/sys/mtio.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -56,7 +56,11 @@ */ #ifndef _SYS_MTIO_H_ -#define _SYS_MTIO_H_ +#define _SYS_MTIO_H_ + +#include + +#ifdef __APPLE_API_OBSOLETE /* * Structures and definitions for mag tape io control commands @@ -160,4 +164,7 @@ struct mtget { #define T_6250BPI 020 /* select 6250 bpi */ #define T_BADBPI 030 /* undefined selection */ #endif + +#endif /* __APPLE_API_OBSOLETE */ + #endif /* !_SYS_MTIO_H_ */ diff --git a/bsd/sys/namei.h b/bsd/sys/namei.h index 1dd8bffad..552dc822b 100644 --- a/bsd/sys/namei.h +++ b/bsd/sys/namei.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -58,6 +58,10 @@ #ifndef _SYS_NAMEI_H_ #define _SYS_NAMEI_H_ +#include + +#ifdef __APPLE_API_UNSTABLE + #include #include @@ -161,7 +165,8 @@ struct nameidata { #define ISSYMLINK 0x010000 /* symlink needs interpretation */ #define ISWHITEOUT 0x020000 /* found whiteout */ #define DOWHITEOUT 0x040000 /* do whiteouts */ -#define NODELETEBUSY 0x800000 /* do not delete busy files (HFS semantic) */ +#define WILLBEDIR 0x080000 /* new files will be dirs; allow trailing / */ +#define NODELETEBUSY 0x800000 /* donot delete busy files (Carbon semantic) */ #define PARAMASK 0x0fff00 /* mask of parameter descriptors */ /* * Initialization of an nameidata structure. @@ -196,6 +201,7 @@ struct namecache { }; #ifdef KERNEL +struct mount; extern u_long nextvnodeid; int namei __P((struct nameidata *ndp)); int lookup __P((struct nameidata *ndp)); @@ -224,4 +230,6 @@ struct nchstats { long ncs_pass2; /* names found with passes == 2 */ long ncs_2passes; /* number of times we attempt it */ }; +#endif /* __APPLE_API_UNSTABLE */ + #endif /* !_SYS_NAMEI_H_ */ diff --git a/bsd/sys/param.h b/bsd/sys/param.h index 6a45fc8a4..f8ee80b46 100644 --- a/bsd/sys/param.h +++ b/bsd/sys/param.h @@ -89,7 +89,7 @@ #define MAXCOMLEN 16 /* max command name remembered */ #define MAXINTERP 64 /* max interpreter file name length */ -#define MAXLOGNAME 12 /* max login name length */ +#define MAXLOGNAME 255 /* max login name length */ #define MAXUPRC CHILD_MAX /* max simultaneous processes */ #define NCARGS ARG_MAX /* max bytes for an exec function */ #define NGROUPS NGROUPS_MAX /* max number groups */ diff --git a/bsd/sys/paths.h b/bsd/sys/paths.h index 3dceb066d..6078c7d7c 100644 --- a/bsd/sys/paths.h +++ b/bsd/sys/paths.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -24,10 +24,15 @@ #ifndef _SYS_PATHS_H_ #define _SYS_PATHS_H_ +#include + +#ifdef __APPLE_API_PRIVATE + /* Provides support for system wide forks */ #define _PATH_FORKSPECIFIER "/..namedfork/" #define _PATH_DATANAME "data" #define _PATH_RSRCNAME "rsrc" #define _PATH_RSRCFORKSPEC "/..namedfork/rsrc" +#endif /* __APPLE_API_PRIVATE */ #endif /* !_SYS_PATHS_H_ */ diff --git a/bsd/sys/poll.h b/bsd/sys/poll.h index 2a8985c32..443469915 100644 --- a/bsd/sys/poll.h +++ b/bsd/sys/poll.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -51,6 +51,9 @@ #ifndef _SYS_POLL_H_ #define _SYS_POLL_H_ +#include + +#ifdef __APPLE_API_PRIVATE /* * This file is intended to be compatable with the traditional poll.h. */ @@ -93,5 +96,6 @@ #define POLLSTANDARD (POLLIN|POLLPRI|POLLOUT|POLLRDNORM|POLLRDBAND|\ POLLWRBAND|POLLERR|POLLHUP|POLLNVAL) +#endif /* __APPLE_API_PRIVATE */ #endif /* !_SYS_POLL_H_ */ diff --git a/bsd/sys/proc.h b/bsd/sys/proc.h index c6ce52227..de6dcb887 100644 --- a/bsd/sys/proc.h +++ b/bsd/sys/proc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -63,13 +63,15 @@ #ifndef _SYS_PROC_H_ #define _SYS_PROC_H_ +#include #include - #include /* For struct selinfo. */ #include #include #include +#ifdef __APPLE_API_PRIVATE + /* * One structure allocated per session. */ @@ -78,6 +80,7 @@ struct session { struct proc *s_leader; /* Session leader. */ struct vnode *s_ttyvp; /* Vnode of controlling terminal. */ struct tty *s_ttyp; /* Controlling terminal. */ + pid_t s_sid; /* Session ID */ char s_login[MAXLOGNAME]; /* Setlogin() name. */ }; @@ -150,7 +153,7 @@ struct proc { int p_traceflag; /* Kernel trace points. */ struct vnode *p_tracep; /* Trace to vnode. */ - sigset_t p_siglist; /* Signals arrived but not delivered. */ + sigset_t p_siglist; /* DEPRECATED. */ struct vnode *p_textvp; /* Vnode of executable. */ @@ -167,7 +170,7 @@ struct proc { /* The following fields are all copied upon creation in fork. */ #define p_startcopy p_sigmask - sigset_t p_sigmask; /* Current signal mask. */ + sigset_t p_sigmask; /* DEPRECATED */ sigset_t p_sigignore; /* Signals being ignored. */ sigset_t p_sigcatch; /* Signals being caught by user. */ @@ -195,9 +198,15 @@ struct proc { caddr_t user_stack; /* where user stack was allocated */ void * exitarg; /* exit arg for proc terminate */ void * vm_shm; /* for sysV shared memory */ - sigset_t p_sigpending; /* pended Signals as traced process is blocked. */ + sigset_t p_xxxsigpending; /* DEPRECATED . */ int p_vforkcnt; /* number of outstanding vforks */ void * p_vforkact; /* activation running this vfork proc */ + TAILQ_HEAD( , uthread) p_uthlist; /* List of uthreads */ + /* Following fields are info from SIGCHLD */ + pid_t si_pid; + u_short si_status; + u_short si_code; + uid_t si_uid; #if DIAGNOSTIC #if SIGNAL_DEBUG unsigned int lockpc[8]; @@ -206,10 +215,25 @@ struct proc { #endif /* DIAGNOSTIC */ }; +#else /* __APPLE_API_PRIVATE */ +struct session; +struct pgrp; +struct proc; +#endif /* __APPLE_API_PRIVATE */ + +#ifdef __APPLE_API_UNSTABLE /* Exported fields for kern sysctls */ struct extern_proc { - struct proc *p_forw; /* Doubly-linked run/sleep queue. */ - struct proc *p_back; + union { + struct { + struct proc *__p_forw; /* Doubly-linked run/sleep queue. */ + struct proc *__p_back; + } p_st1; + struct timeval __p_starttime; /* process start time */ + } p_un; +#define p_forw p_un.p_st1.__p_forw +#define p_back p_un.p_st1.__p_back +#define p_starttime p_un.__p_starttime struct vmspace *p_vmspace; /* Address space. */ struct sigacts *p_sigacts; /* Signal actions, state (PROC ONLY). */ int p_flag; /* P_* flags. */ @@ -237,10 +261,10 @@ struct extern_proc { u_quad_t p_iticks; /* Statclock hits processing intr. */ int p_traceflag; /* Kernel trace points. */ struct vnode *p_tracep; /* Trace to vnode. */ - int p_siglist; /* Signals arrived but not delivered. */ + int p_siglist; /* DEPRECATED */ struct vnode *p_textvp; /* Vnode of executable. */ int p_holdcnt; /* If non-zero, don't swap. */ - sigset_t p_sigmask; /* Current signal mask. */ + sigset_t p_sigmask; /* DEPRECATED. */ sigset_t p_sigignore; /* Signals being ignored. */ sigset_t p_sigcatch; /* Signals being caught by user. */ u_char p_priority; /* Process priority. */ @@ -281,10 +305,6 @@ struct extern_proc { #define P_WEXIT 0x02000 /* Working on exiting. */ #define P_EXEC 0x04000 /* Process called exec. */ -/* Should probably be changed into a hold count. */ -#define P_NOSWAP 0x08000 /* Another flag to prevent swap out. */ -#define P_PHYSIO 0x10000 /* Doing physical I/O. */ - /* Should be moved to machine-dependent areas. */ #define P_OWEUPC 0x08000 /* Owe process an addupc() call at next ast. */ @@ -297,12 +317,18 @@ struct extern_proc { #define P_TTYSLEEP 0x0100000 /* blocked due to SIGTTOU or SIGTTIN */ #define P_REBOOT 0x0200000 /* Process called reboot() */ #define P_TBE 0x0400000 /* Process is TBE */ -#define P_SIGTHR 0x0800000 /* signal pending handling thread scheduled */ +#define P_SIGEXC 0x0800000 /* signal exceptions */ #define P_BTRACE 0x1000000 /* process is being branch traced */ #define P_VFORK 0x2000000 /* process has vfork children */ -#define P_NOATTACH 0x4000000 +#define P_NOATTACH 0x4000000 #define P_INVFORK 0x8000000 /* proc in vfork */ +#define P_NOSHLIB 0x10000000 /* no shared libs are in use for proc */ + /* flag set on exec */ +#define P_FORCEQUOTA 0x20000000 /* Force quota for root */ +#define P_NOCLDWAIT 0x40000000 /* No zombies when chil procs exit */ +#define P_NOSWAP 0 /* Obsolete: retained so that nothing breaks */ +#define P_PHYSIO 0 /* Obsolete: retained so that nothing breaks */ /* * Shareable process credentials (always resident). This includes a reference @@ -325,14 +351,18 @@ struct pcred { LK_EXCLUSIVE, 0, (p)) #define pcred_unlock(p) lockmgr(&(p)->p_cred->pc_lock, \ LK_RELEASE, 0, (p)) +#endif /* __APPLE_API_UNSTABLE */ #ifdef KERNEL __BEGIN_DECLS +#ifdef __APPLE_API_PRIVATE /* * We use process IDs <= PID_MAX; PID_MAX + 1 must also fit in a pid_t, * as it is used to represent "no process group". */ +extern int nprocs, maxproc; /* Current and max number of procs. */ + #define PID_MAX 30000 #define NO_PID 30001 @@ -348,12 +378,16 @@ extern u_long pidhash; extern LIST_HEAD(pgrphashhead, pgrp) *pgrphashtbl; extern u_long pgrphash; -extern int nprocs, maxproc; /* Current and max number of procs. */ - LIST_HEAD(proclist, proc); extern struct proclist allproc; /* List of all processes. */ extern struct proclist zombproc; /* List of zombie processes. */ extern struct proc *initproc, *kernproc; +extern void pgdelete __P((struct pgrp *pgrp)); +extern void sessrele __P((struct session *sess)); +extern void procinit __P((void)); +#endif /* __APPLE_API_PRIVATE */ + +#ifdef __APPLE_API_UNSTABLE extern struct proc *pfind __P((pid_t)); /* Find process by id. */ extern struct pgrp *pgfind __P((pid_t)); /* Find process group by id. */ @@ -363,20 +397,27 @@ extern int enterpgrp __P((struct proc *p, pid_t pgid, int mksess)); extern void fixjobc __P((struct proc *p, struct pgrp *pgrp, int entering)); extern int inferior __P((struct proc *p)); extern int leavepgrp __P((struct proc *p)); +#ifdef __APPLE_API_OBSOLETE extern void mi_switch __P((void)); -extern void pgdelete __P((struct pgrp *pgrp)); -extern void sessrele __P((struct session *sess)); -extern void procinit __P((void)); +#endif /* __APPLE_API_OBSOLETE */ extern void resetpriority __P((struct proc *)); extern void setrunnable __P((struct proc *)); extern void setrunqueue __P((struct proc *)); extern int sleep __P((void *chan, int pri)); extern int tsleep __P((void *chan, int pri, char *wmesg, int timo)); -extern int tsleep0 __P((void *chan, int pri, char *wmesg, int timo, int (*continuation)(int) )); +extern int tsleep0 __P((void *chan, int pri, char *wmesg, int timo, int (*continuation)(int))); +extern int tsleep1 __P((void *chan, int pri, char *wmesg, u_int64_t abstime, int (*continuation)(int))); extern void unsleep __P((struct proc *)); extern void wakeup __P((void *chan)); +#endif /* __APPLE_API_UNSTABLE */ + __END_DECLS +#ifdef __APPLE_API_OBSOLETE +/* FreeBSD source compatibility macro */ +#define PRISON_CHECK(p1, p2) (1) +#endif /* __APPLE_API_OBSOLETE */ + #endif /* KERNEL */ #endif /* !_SYS_PROC_H_ */ diff --git a/bsd/sys/protosw.h b/bsd/sys/protosw.h index 98c00a565..80c1a3120 100644 --- a/bsd/sys/protosw.h +++ b/bsd/sys/protosw.h @@ -54,8 +54,20 @@ * SUCH DAMAGE. * * @(#)protosw.h 8.1 (Berkeley) 6/2/93 + * $FreeBSD: src/sys/sys/protosw.h,v 1.28.2.2 2001/07/03 11:02:01 ume Exp $ */ +#ifndef _SYS_PROTOSW_H_ +#define _SYS_PROTOSW_H_ + +/* Forward declare these structures referenced from prototypes below. */ +struct mbuf; +struct proc; +struct sockaddr; +struct socket; +struct sockopt; + +/*#ifdef _KERNEL*/ /* * Protocol switch table. * @@ -70,7 +82,7 @@ * * 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 + * the users) and pr_output passes it down (towards the interfaces); 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. @@ -79,12 +91,11 @@ * described below. */ -#ifndef _SYS_PROTOSW_H_ -#define _SYS_PROTOSW_H_ - +#include #include #include +#ifdef __APPLE_API_UNSTABLE struct protosw { short pr_type; /* socket type used for */ struct domain *pr_domain; /* domain protocol a member of */ @@ -109,14 +120,16 @@ struct protosw { /* slow timeout (500ms) */ void (*pr_drain) __P((void)); /* flush any excess space possible */ - +#if __APPLE__ int (*pr_sysctl)(); /* sysctl for protocol */ - +#endif struct pr_usrreqs *pr_usrreqs; /* supersedes pr_usrreq() */ +#if __APPLE__ /* Implant hooks */ TAILQ_HEAD(pr_sfilter, NFDescriptor) pr_sfilter; struct protosw *pr_next; /* Chain for domain */ u_long reserved[4]; /* Padding for future use */ +#endif }; #define PR_SLOWHZ 2 /* 2 slow timeouts per second */ @@ -126,6 +139,10 @@ struct protosw { * Values for pr_flags. * PR_ADDR requires PR_ATOMIC; * PR_ADDR and PR_CONNREQUIRED are mutually exclusive. + * PR_IMPLOPCL means that the protocol allows sendto without prior connect, + * and the protocol understands the MSG_EOF flag. The first property is + * is only relevant if PR_CONNREQUIRED is set (otherwise sendto is allowed + * anyhow). */ #define PR_ATOMIC 0x01 /* exchange atomic messages only */ #define PR_ADDR 0x02 /* addresses given with messages */ @@ -133,6 +150,7 @@ struct protosw { #define PR_WANTRCVD 0x08 /* want PRU_RCVD calls */ #define PR_RIGHTS 0x10 /* passes capabilities */ #define PR_IMPLOPCL 0x20 /* implied open/close */ +#define PR_LASTHDR 0x40 /* enforce ipsec policy; last header */ /* * The arguments to usrreq are: @@ -248,7 +266,6 @@ struct pr_usrreqs { struct ucred *cred, void *)); }; - extern int pru_abort_notsupp(struct socket *so); extern int pru_accept_notsupp(struct socket *so, struct sockaddr **nam); extern int pru_attach_notsupp(struct socket *so, int proto, @@ -315,8 +332,9 @@ extern int pru_sopoll_notsupp(struct socket *so, int events, #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_UNREACH_ADMIN_PROHIB 21 /* packet administrativly prohibited */ -#define PRC_NCMDS 21 +#define PRC_NCMDS 22 #define PRC_IS_REDIRECT(cmd) \ ((cmd) >= PRC_REDIRECT_NET && (cmd) <= PRC_REDIRECT_TOSHOST) @@ -328,7 +346,7 @@ char *prcrequests[] = { "NET-UNREACH", "HOST-UNREACH", "PROTO-UNREACH", "PORT-UNREACH", "#12", "SRCFAIL-UNREACH", "NET-REDIRECT", "HOST-REDIRECT", "TOSNET-REDIRECT", "TOSHOST-REDIRECT", "TX-INTRANS", "TX-REASS", - "PARAMPROB" + "PARAMPROB", "ADMIN-UNREACH" }; #endif @@ -358,6 +376,7 @@ char *prcorequests[] = { #ifdef KERNEL void pfctlinput __P((int, struct sockaddr *)); +void pfctlinput2 __P((int, struct sockaddr *, void *)); struct protosw *pffindproto __P((int family, int protocol, int type)); struct protosw *pffindtype __P((int family, int type)); @@ -376,4 +395,5 @@ static void link_ ## psw ## _protos() \ } #endif +#endif /* __APPLE_API_UNSTABLE */ #endif /* !_SYS_PROTOSW_H_ */ diff --git a/bsd/sys/ptrace.h b/bsd/sys/ptrace.h index fa63ab9d8..3ae7cdadb 100644 --- a/bsd/sys/ptrace.h +++ b/bsd/sys/ptrace.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -58,6 +58,8 @@ #ifndef _SYS_PTRACE_H_ #define _SYS_PTRACE_H_ +#include + #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 */ @@ -70,14 +72,21 @@ #define PT_STEP 9 /* single step the child */ #define PT_ATTACH 10 /* trace some running process */ #define PT_DETACH 11 /* stop tracing a process */ -#define PT_DENY_ATTACH 31 +#define PT_SIGEXC 12 /* signals as exceptions for current_proc */ +#define PT_THUPDATE 13 /* signal for thread# */ +#define PT_ATTACHEXC 14 /* attach to running process with signal exception */ + +#define PT_FORCEQUOTA 30 /* Enforce quota for root */ +#define PT_DENY_ATTACH 31 #define PT_FIRSTMACH 32 /* for machine-specific requests */ #include /* machine-specific requests, if any */ #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE void proc_reparent __P((struct proc *child, struct proc *newparent)); +#endif /* __APPLE_API_PRIVATE */ #else /* !KERNEL */ #include diff --git a/bsd/sys/quota.h b/bsd/sys/quota.h new file mode 100644 index 000000000..470d04dc1 --- /dev/null +++ b/bsd/sys/quota.h @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Copyright (c) 1982, 1986, 1993 + * The 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 + * derived from @(#)ufs/ufs/quota.h 8.3 (Berkeley) 8/19/94 + */ + +#ifndef _SYS_QUOTA_H +#define _SYS_QUOTA_H + +#include + +#ifdef __APPLE_API_UNSTABLE +/* + * 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) /* seconds in 1 week */ +#define MAX_DQ_TIME (7*24*60*60) /* seconds in 1 week */ + +/* + * The following constants define the usage of the quota file array in the + * file system mount 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 QUOTAOPSNAME ".quota.ops" +#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 */ +#define Q_QUOTASTAT 0x0700 /* get quota on/off status */ + +/* + * The following two structures define the format of the disk + * quota file (as it appears on disk) - the file contains a + * header followed by a hash table of dqblk entries. To find + * a particular entry, the user or group number (id) is first + * converted to an index into this table by means of the hash + * function dqhash1. If there is a collision at that index + * location then a second hash value is computed which using + * dqhash2. This second hash value is then used as an offset + * to the next location to probe. ID = 0 is used to indicate + * an empty (unused) entry. So there can never be an entry in + * the quota file for user 0 or group 0 (which is OK since disk + * quotas are never enforced for user 0). + * + * The setquota system call establishes the vnode for each quota + * file (a pointer is retained in the filesystem mount structure). + */ +struct dqfilehdr { + u_int32_t dqh_magic; + u_int32_t dqh_version; /* == QF_VERSION */ + u_int32_t dqh_maxentries; /* must be a power of 2 */ + u_int32_t dqh_entrycnt; /* count of active entries */ + u_int32_t dqh_flags; /* reserved for now (0) */ + time_t dqh_chktime; /* time of last quota check */ + time_t dqh_btime; /* time limit for excessive disk use */ + time_t dqh_itime; /* time limit for excessive files */ + char dqh_string[16]; /* tag string */ + u_int32_t dqh_spare[4]; /* pad struct to power of 2 */ +}; + +struct dqblk { + u_int64_t dqb_bhardlimit; /* absolute limit on disk bytes alloc */ + u_int64_t dqb_bsoftlimit; /* preferred limit on disk bytes */ + u_int64_t dqb_curbytes; /* current byte count */ + u_int32_t dqb_ihardlimit; /* maximum # allocated inodes + 1 */ + u_int32_t dqb_isoftlimit; /* preferred inode limit */ + u_int32_t dqb_curinodes; /* current # allocated inodes */ + time_t dqb_btime; /* time limit for excessive disk use */ + time_t dqb_itime; /* time limit for excessive files */ + u_int32_t dqb_id; /* identifier (0 for empty entries) */ + u_int32_t dqb_spare[4]; /* pad struct to power of 2 */ +}; + + +#define INITQMAGICS { \ + 0xff31ff35, /* USRQUOTA */ \ + 0xff31ff27, /* GRPQUOTA */ \ +}; + +#define QF_VERSION 1 +#define QF_STRING_TAG "QUOTA HASH FILE" + +#define QF_USERS_PER_GB 256 +#define QF_MIN_USERS 2048 +#define QF_MAX_USERS (2048*1024) + +#define QF_GROUPS_PER_GB 32 +#define QF_MIN_GROUPS 2048 +#define QF_MAX_GROUPS (256*1024) + + +/* + * The primary and secondary multiplicative hash functions are + * derived from Knuth (vol. 3). They use a prime that is in + * golden ratio to the machine's word size. + */ +#define dqhash1(id, shift, mask) \ + ((((id) * 2654435761UL) >> (shift)) & (mask)) + +#define dqhash2(id, mask) \ + (dqhash1((id), 11, (mask)>>1) | 1) + +/* + * Compute a disk offset into a quota file. + */ +#define dqoffset(index) \ + (sizeof (struct dqfilehdr) + ((index) * sizeof (struct dqblk))) +/* + * Compute the hash shift value. + * It is the word size, in bits, minus the hash table size, in bits. + */ +static __inline int dqhashshift(u_long); + +static __inline int +dqhashshift(u_long size) +{ + int shift; + + for (shift = 32; size > 1; size >>= 1, --shift) + continue; + return (shift); +} + + +#ifndef KERNEL + +#include + +__BEGIN_DECLS +int quotactl __P((char *, int, int, caddr_t)); +__END_DECLS +#endif /* !KERNEL */ + +#ifdef KERNEL +#include + +/* + * Macros to avoid subroutine calls to trivial functions. + */ +#if DIAGNOSTIC +#define DQREF(dq) dqref(dq) +#else +#define DQREF(dq) (dq)->dq_cnt++ +#endif + + +/* Quota file info + */ +struct quotafile { + struct vnode *qf_vp; /* quota file vnode */ + struct ucred *qf_cred; /* quota file access cred */ + int qf_shift; /* primary hash shift */ + int qf_maxentries; /* size of hash table (power of 2) */ + int qf_entrycnt; /* count of active entries */ + time_t qf_btime; /* block quota time limit */ + time_t qf_itime; /* inode quota time limit */ + char qf_qflags; /* quota specific flags */ +}; + +/* + * Flags describing the runtime state of quotas. + * (in qf_qflags) + */ +#define QTF_OPENING 0x01 /* Q_QUOTAON in progress */ +#define QTF_CLOSING 0x02 /* Q_QUOTAOFF in progress */ + + +/* + * 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 { + LIST_ENTRY(dquot) dq_hash; /* hash list */ + TAILQ_ENTRY(dquot) dq_freelist; /* free list */ + u_int16_t dq_flags; /* flags, see below */ + u_int16_t dq_cnt; /* count of active references */ + u_int16_t dq_spare; /* unused spare padding */ + u_int16_t dq_type; /* quota type of this dquot */ + u_int32_t dq_id; /* identifier this applies to */ + u_int32_t dq_index; /* index into quota file */ + struct quotafile *dq_qfile; /* quota file 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_curbytes dq_dqb.dqb_curbytes +#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 NULL + +/* + * Flags to chkdq() and chkiq() + */ +#define FORCE 0x01 /* force usage changes independent of limits */ +#define CHOWN 0x02 /* (advisory) change initiated by chown */ + + +/* + * Functions that manage the in-core dquot and the + * on-disk dqblk data structures. + */ +__BEGIN_DECLS +int dqfileopen(struct quotafile *, int); +void dqfileclose(struct quotafile *, int); +void dqflush(struct vnode *); +int dqget(struct vnode *, u_long, struct quotafile *, int, struct dquot **); +void dqinit(void); +void dqref(struct dquot *); +void dqrele(struct vnode *, struct dquot *); +int dqsync(struct vnode *, struct dquot *); +__END_DECLS + +#endif /* KERNEL */ + +#endif /* __APPLE_API_UNSTABLE */ + +#endif /* !_SYS_QUOTA_H_ */ diff --git a/bsd/sys/random.h b/bsd/sys/random.h index 9e5ba135b..c8976a552 100644 --- a/bsd/sys/random.h +++ b/bsd/sys/random.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2000-2001 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1999, 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -23,7 +23,11 @@ #ifndef __SYS_RANDOM_H__ #define __SYS_RANDOM_H__ -#include +#include + +#ifdef __APPLE_API_UNSTABLE +void read_random(void* buffer, u_int numBytes); +#endif /* __APPLE_API_UNSTABLE */ #endif /* __SYS_RANDOM_H__ */ diff --git a/bsd/sys/reboot.h b/bsd/sys/reboot.h index b7e8a53f2..a312ed635 100644 --- a/bsd/sys/reboot.h +++ b/bsd/sys/reboot.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -58,6 +58,8 @@ #ifndef _SYS_REBOOT_H_ #define _SYS_REBOOT_H_ +#include + #ifdef KERNEL_BUILD #include #endif /* KERNEL_BUILD */ @@ -66,6 +68,7 @@ * Arguments to reboot system call. */ +#ifdef __APPLE_API_PRIVATE #define RB_AUTOBOOT 0 /* flags for system auto-booting itself */ #define RB_ASKNAME 0x01 /* ask for file name to reboot from */ @@ -80,6 +83,9 @@ #define RB_PANIC 0 /* reboot due to panic */ #define RB_BOOT 1 /* reboot due to boot() */ +#endif /* __APPLE_API_PRIVATE */ + +#ifdef __APPLE_API_OBSOLETE /* * Constants for converting boot-style device number to type, * adaptor (uba, mba, etc), unit number and partition number. @@ -115,6 +121,7 @@ ((controller) << B_CONTROLLERSHIFT) | ((unit) << B_UNITSHIFT) | \ ((partition) << B_PARTITIONSHIFT) | B_DEVMAGIC) +#endif /* __APPLE_API_OBSOLETE */ #include #endif /* _SYS_REBOOT_H_ */ diff --git a/bsd/sys/resource.h b/bsd/sys/resource.h index 1087aa342..e2f12be0f 100644 --- a/bsd/sys/resource.h +++ b/bsd/sys/resource.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -58,6 +58,8 @@ #ifndef _SYS_RESOURCE_H_ #define _SYS_RESOURCE_H_ +#include + /* * Process priority specifications to get/setpriority. */ @@ -130,8 +132,10 @@ struct loadavg { }; #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE extern struct loadavg averunnable; #define LSCALE 1000 /* scaling for "fixed point" arithmetic */ +#endif /* __APPLE_API_PRIVATE */ #else #include diff --git a/bsd/sys/resourcevar.h b/bsd/sys/resourcevar.h index 4865dedf7..77b30d6fd 100644 --- a/bsd/sys/resourcevar.h +++ b/bsd/sys/resourcevar.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -58,6 +58,9 @@ #ifndef _SYS_RESOURCEVAR_H_ #define _SYS_RESOURCEVAR_H_ +#include + +#ifdef __APPLE_API_PRIVATE /* * Kernel per-process accounting / statistics * (not necessarily resident except when running). @@ -109,9 +112,10 @@ void addupc_intr __P((struct proc *p, u_long pc, u_int ticks)); void addupc_task __P((struct proc *p, u_long pc, u_int ticks)); void calcru __P((struct proc *p, struct timeval *up, struct timeval *sp, struct timeval *ip)); -struct plimit - *limcopy __P((struct plimit *lim)); void ruadd __P((struct rusage *ru, struct rusage *ru2)); -#endif +struct plimit *limcopy __P((struct plimit *lim)); +#endif /* KERNEL */ + +#endif /* __APPLE_API_PRIVATE */ #endif /* !_SYS_RESOURCEVAR_H_ */ diff --git a/bsd/sys/select.h b/bsd/sys/select.h index 4d8997d36..8c67dc5c5 100644 --- a/bsd/sys/select.h +++ b/bsd/sys/select.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -57,10 +57,14 @@ #ifndef _SYS_SELECT_H_ #define _SYS_SELECT_H_ -#ifdef KERNEL +#include + +#ifdef __APPLE_API_UNSTABLE + __BEGIN_DECLS + +#ifdef KERNEL #include -__END_DECLS #endif /* @@ -87,6 +91,10 @@ struct proc; void selrecord __P((struct proc *selector, struct selinfo *, void *)); void selwakeup __P((struct selinfo *)); void selthreadclear __P((struct selinfo *)); -#endif +#endif /* KERNEL */ + +__END_DECLS + +#endif /* __APPLE_API_UNSTABLE */ #endif /* !_SYS_SELECT_H_ */ diff --git a/bsd/sys/sem.h b/bsd/sys/sem.h index dce2afd8d..ebcb13955 100644 --- a/bsd/sys/sem.h +++ b/bsd/sys/sem.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -26,10 +26,14 @@ * * Author: Daniel Boulet */ +/* + * John Bellardo modified the implementation for Darwin. 12/2000 + */ #ifndef _SYS_SEM_H_ #define _SYS_SEM_H_ +#include #include struct sem { @@ -91,12 +95,47 @@ union semun { #define SEM_R 0400 /* read permission */ #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE /* * Kernel implementation stuff */ #define SEMVMX 32767 /* semaphore maximum value */ #define SEMAEM 16384 /* adjust on exit max value */ +/* + * Configuration parameters. SEMMNI, SEMMNS, and SEMMNU are hard limits. + * The code dynamically allocates enough memory to satisfy the current + * demand in even increments of SEMMNI_INC, SEMMNS_INC, and SEMMNU_INC. + * The code will never allocate more than the hard limits. The *_INC's + * are defined in the kernel section of the header. + */ +/* + * Configuration parameters + */ +#ifndef SEMMNS /* # of semaphores in system */ +#define SEMMNS (1048576/sizeof(struct sem)) +#endif /* no more than 1M of semaphore data */ +#ifndef SEMMNI /* # of semaphore identifiers */ +#define SEMMNI SEMMNS /* max of 1 for each semaphore */ +#endif +#ifndef SEMUME +#define SEMUME 10 /* max # of undo entries per process */ +#endif +#ifndef SEMMNU /* # of undo structures in system */ +#define SEMMNU SEMMNS /* 1 for each semaphore. This is quite large */ +#endif /* This should be max 1 for each process */ + +/* shouldn't need tuning */ +#ifndef SEMMAP +#define SEMMAP 30 /* # of entries in semaphore map */ +#endif +#ifndef SEMMSL +#define SEMMSL SEMMNS /* max # of semaphores per id */ +#endif +#ifndef SEMOPM +#define SEMOPM 100 /* max # of operations per semop call */ +#endif + /* * Undo structure (one per process) @@ -109,7 +148,7 @@ struct sem_undo { short un_adjval; /* adjust on exit values */ short un_num; /* semaphore # */ int un_id; /* semid */ - } un_ent[1]; /* undo entries */ + } un_ent[SEMUME]; /* undo entries */ }; /* @@ -133,51 +172,50 @@ extern struct seminfo seminfo; #define SEM_ALLOC 01000 /* semaphore is allocated */ #define SEM_DEST 02000 /* semaphore will be destroyed on last detach */ -/* - * Configuration parameters - */ -#ifndef SEMMNI -#define SEMMNI 10 /* # of semaphore identifiers */ -#endif -#ifndef SEMMNS -#define SEMMNS 60 /* # of semaphores in system */ -#endif -#ifndef SEMUME -#define SEMUME 10 /* max # of undo entries per process */ -#endif -#ifndef SEMMNU -#define SEMMNU 30 /* # of undo structures in system */ -#endif - -/* shouldn't need tuning */ -#ifndef SEMMAP -#define SEMMAP 30 /* # of entries in semaphore map */ -#endif -#ifndef SEMMSL -#define SEMMSL SEMMNS /* max # of semaphores per id */ -#endif -#ifndef SEMOPM -#define SEMOPM 100 /* max # of operations per semop call */ -#endif +#define SEMMNI_INC 8 /* increment value for semaphore identifiers */ +#define SEMMNS_INC 64 /* increment value for semaphores */ +#define SEMMNU_INC 32 /* increment value for undo structures */ /* * Due to the way semaphore memory is allocated, we have to ensure that * SEMUSZ is properly aligned. + * + * We are not doing strange semaphore memory allocation anymore, so + * these macros are no longer needed. */ -#define SEM_ALIGN(bytes) (((bytes) + (sizeof(long) - 1)) & ~(sizeof(long) - 1)) +/* + * #define SEM_ALIGN(bytes) (((bytes) + (sizeof(long) - 1)) & ~(sizeof(long) - 1)) + */ /* actual size of an undo structure */ -#define SEMUSZ SEM_ALIGN(offsetof(struct sem_undo, un_ent[SEMUME])) +/* + * #define SEMUSZ SEM_ALIGN(offsetof(struct sem_undo, un_ent[SEMUME])) + */ +#define SEMUSZ sizeof(struct sem_undo) extern struct semid_ds *sema; /* semaphore id pool */ extern struct sem *sem; /* semaphore pool */ -extern int *semu; /* undo structure pool */ +/* This is now a struct sem_undo with the new memory allocation + * extern int *semu; /* undo structure pool + */ +extern struct sem_undo *semu; /* undo structure pool */ /* * Macro to find a particular sem_undo vector */ -#define SEMU(ix) ((struct sem_undo *)(((intptr_t)semu)+ix * seminfo.semusz)) +/* Until we can initialize seminfo.semusz to SEMUSZ, we hard code the size macro + * in SEMU. This should be fixed when (if) we implement dynamic pool sizes + * + * #define SEMU(ix) ((struct sem_undo *)(((intptr_t)semu)+ix * seminfo.semusz)) + */ +/* + * This macro doesn't work because we are using a staticly allocated array + * for semu now. + * #define SEMU(ix) ((struct sem_undo *)(((intptr_t)semu)+ix * SEMUSZ)) + */ +#define SEMU(ix) (&semu[ix]) + /* * Process sem_undo vectors at proc exit. @@ -191,6 +229,9 @@ typedef enum { SEM_CONFIG_FREEZE, /* Freeze the semaphore facility. */ SEM_CONFIG_THAW /* Thaw the semaphore facility. */ } semconfig_ctl_t; + +#endif /* __APPLE_API_PRIVATE */ + #endif /* KERNEL */ #ifndef KERNEL @@ -198,7 +239,7 @@ typedef enum { __BEGIN_DECLS int semsys __P((int, ...)); -int semctl __P((int, int, int, ...)); +int semctl __P((int, int, int, union semun)); int semget __P((key_t, int, int)); int semop __P((int, struct sembuf *,unsigned)); __END_DECLS diff --git a/bsd/sys/shm.h b/bsd/sys/shm.h index a1a10f7d5..af9c1f1cc 100644 --- a/bsd/sys/shm.h +++ b/bsd/sys/shm.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -59,6 +59,7 @@ #ifndef _SYS_SHM_H_ #define _SYS_SHM_H_ +#include #include #include @@ -85,7 +86,7 @@ struct shmid_ds { }; #ifdef KERNEL - +#ifdef __APPLE_API_PRIVATE /* * System 5 style catch-all structure for shared memory constants that * might be of interest to user programs. Do we really want/need this? @@ -104,6 +105,7 @@ struct proc; void shmexit __P((struct proc *)); void shmfork __P((struct proc *, struct proc *)); +#endif /* __APPLE_API_PRIVATE */ #else /* !KERNEL */ #include diff --git a/bsd/sys/signal.h b/bsd/sys/signal.h index 136b3d1f0..36d5872eb 100644 --- a/bsd/sys/signal.h +++ b/bsd/sys/signal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -63,6 +63,8 @@ #ifndef _SYS_SIGNAL_H_ #define _SYS_SIGNAL_H_ +#include + #if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE) #define NSIG 32 /* counting 0; could be 33 (mask is 1-32) */ #endif @@ -131,22 +133,113 @@ #ifndef _ANSI_SOURCE typedef unsigned int sigset_t; +union sigval { + /* Members as suggested by Annex C of POSIX 1003.1b. */ + int sigval_int; + void *sigval_ptr; +}; + +#define SIGEV_NONE 0 /* No async notification */ +#ifdef __APPLE_API_PRIVATE +#define SIGEV_SIGNAL 1 /* Generate a queued signal */ +#define SIGEV_THREAD 3 /* A notification function will be called to perfrom notification */ +#endif /*__APPLE_API_PRIVATE */ + +typedef struct __siginfo { + int si_signo; /* signal number */ + int si_errno; /* errno association */ + int si_code; /* signal code */ + int si_pid; /* sending process */ + unsigned int si_uid; /* sender's ruid */ + int si_status; /* exit value */ + void *si_addr; /* faulting instruction */ + union sigval si_value; /* signal value */ + long si_band; /* band event for SIGPOLL */ + int pad[7]; /* RFU */ +} siginfo_t; + +/* + * Incase of SIGILL and SIGFPE, si_addr contains the address of + * faulting instruction. + * Incase of SIGSEGV and SIGBUS, si_addr contains address of + * faulting memory reference. + * Incase of SIGCHLD, si_pid willhave child process ID, + * si_status will contain exit value or signal. + * si_uid contains real user ID of the process that sent the signal + */ + +/* Values for si_code */ + +/* Codes for SIGILL */ +#define ILL_NOOP 0 /* if only I knew... */ +#define ILL_ILLOPC 1 /* illegal opcode */ +#define ILL_ILLTRP 2 /* illegal trap */ +#define ILL_PRVOPC 3 /* privileged opcode */ + +/* Codes for SIGFPE */ +#define FPE_NOOP 0 /* if only I knew... */ +#define FPE_FLTDIV 1 /* floating point divide by zero */ +#define FPE_FLTOVF 2 /* floating point overflow */ +#define FPE_FLTUND 3 /* floating point underflow */ +#define FPE_FLTRES 4 /* floating point inexact result */ +#define FPE_FLTINV 5 /* invalid floating point operation */ + +/* Codes for SIGSEGV */ +#define SEGV_NOOP 0 /* if only I knew... */ +#define SEGV_MAPERR 1 /* address not mapped to object */ +#define SEGV_ACCERR 2 /* invalid permissions for mapped to object */ + +/* Codes for SIGBUS */ +#define BUS_NOOP 0 /* if only I knew... */ +#define BUS_ADRALN 1 /* invalid address alignment */ + +/* Codes for SIGCHLD */ +#define CLD_NOOP 0 /* if only I knew... */ +#define CLD_EXITED 1 /* child has exited */ +#define CLD_KILLED 2 + /* child has terminated abnormally and did not create a core file */ +#define CLD_DUMPED 3 + /* child has terminated abnormally and create a core file */ +#define CLD_TRAPPED 4 /* traced child has trapped */ +#define CLD_STOPPED 5 /* child has stopped */ +#define CLD_CONTINUED 6 /* stopped child has continued */ + +/* union for signal handlers */ +union __sigaction_u { + void (*__sa_handler)(int); + void (*__sa_sigaction)(int, struct __siginfo *, + void *); +}; + +/* Signal vector template for Kernel user boundary */ +struct __sigaction { + union __sigaction_u __sigaction_u; /* signal handler */ + void (*sa_tramp)(void *, int, int, siginfo_t *, void *); + sigset_t sa_mask; /* signal mask to apply */ + int sa_flags; /* see signal options below */ +}; + /* * Signal vector "template" used in sigaction call. */ struct sigaction { -#if defined(__cplusplus) - void (*sa_handler)(int); /* signal handler */ -#else - void (*sa_handler)(); /* signal handler */ -#endif /* __cplusplus */ + union __sigaction_u __sigaction_u; /* signal handler */ sigset_t sa_mask; /* signal mask to apply */ int sa_flags; /* see signal options below */ }; +/* if SA_SIGINFO is set, sa_sigaction is to be used instead of sa_handler. */ +#define sa_handler __sigaction_u.__sa_handler +#define sa_sigaction __sigaction_u.__sa_sigaction + + #if !defined(_POSIX_SOURCE) #define SA_ONSTACK 0x0001 /* take signal on signal stack */ #define SA_RESTART 0x0002 /* restart system on signal return */ #define SA_DISABLE 0x0004 /* disable taking signals on alternate stack */ +#define SA_RESETHAND 0x0004 /* reset to SIG_DFL when taking signal */ +#define SA_NODEFER 0x0010 /* don't mask the signal we're delivering */ +#define SA_NOCLDWAIT 0x0020 /* don't keep zombies around */ +#define SA_SIGINFO 0x0040 /* signal handler with SA_SIGINFO args */ #define SA_USERTRAMP 0x0100 /* do not bounce off kernel's sigtramp */ #endif #define SA_NOCLDSTOP 0x0008 /* do not generate SIGCHLD on child stop */ @@ -158,6 +251,13 @@ struct sigaction { #define SIG_UNBLOCK 2 /* unblock specified signal set */ #define SIG_SETMASK 3 /* set specified signal set */ +/* POSIX 1003.1b required values. */ +#define SI_USER 0x10001 +#define SI_QUEUE 0x10002 +#define SI_TIMER 0x10003 +#define SI_ASYNCIO 0x10004 +#define SI_MESGQ 0x10005 + #if !defined(_POSIX_SOURCE) #include typedef void (*sig_t) __P((int)); /* type of signal function */ @@ -170,6 +270,11 @@ struct sigaltstack { int ss_size; /* signal stack length */ int ss_flags; /* SA_DISABLE and/or SA_ONSTACK */ }; + +typedef struct sigaltstack stack_t; + +#define SS_ONSTACK 0x0001 /* take signal on signal stack */ +#define SS_DISABLE 0x0004 /* disable taking signals on alternate stack */ #define MINSIGSTKSZ 8192 /* minimum allowable stack */ #define SIGSTKSZ (MINSIGSTKSZ + 32768) /* recommended stack size */ @@ -178,13 +283,18 @@ struct sigaltstack { * Signal vector "template" used in sigvec call. */ struct sigvec { - void (*sv_handler)(); /* signal handler */ + void (*sv_handler)(int); /* signal handler */ int sv_mask; /* signal mask to apply */ int sv_flags; /* see signal options below */ }; #define SV_ONSTACK SA_ONSTACK #define SV_INTERRUPT SA_RESTART /* same bit, opposite sense */ +#define SV_RESETHAND SA_RESETHAND +#define SV_NODEFER SA_NODEFER +#define SV_NOCLDSTOP SA_NOCLDSTOP +#define SV_SIGINFO SA_SIGINFO + #define sv_onstack sv_flags /* isn't compatibility wonderful! */ /* @@ -202,14 +312,16 @@ struct sigstack { #define sigmask(m) (1 << ((m)-1)) #ifdef KERNEL - /* - * signals delivered on a per-thread basis. - */ - #define threadmask (sigmask(SIGILL)|sigmask(SIGTRAP)|\ - sigmask(SIGIOT)|sigmask(SIGEMT)|\ - sigmask(SIGFPE)|sigmask(SIGBUS)|\ - sigmask(SIGSEGV)|sigmask(SIGSYS)|\ - sigmask(SIGPIPE)) +#ifdef __APPLE_API_PRIVATE +/* + * signals delivered on a per-thread basis. + */ +#define threadmask (sigmask(SIGILL)|sigmask(SIGTRAP)|\ + sigmask(SIGIOT)|sigmask(SIGEMT)|\ + sigmask(SIGFPE)|sigmask(SIGBUS)|\ + sigmask(SIGSEGV)|sigmask(SIGSYS)|\ + sigmask(SIGPIPE)) +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ #define BADSIG SIG_ERR diff --git a/bsd/sys/signalvar.h b/bsd/sys/signalvar.h index 0b242758d..68199f53e 100644 --- a/bsd/sys/signalvar.h +++ b/bsd/sys/signalvar.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -58,6 +58,9 @@ #ifndef _SYS_SIGNALVAR_H_ /* tmp for user.h */ #define _SYS_SIGNALVAR_H_ +#include + +#ifdef __APPLE_API_PRIVATE /* * Kernel signal definitions and data structures, * not exported to user programs. @@ -69,9 +72,13 @@ */ struct sigacts { sig_t ps_sigact[NSIG]; /* disposition of signals */ + sig_t ps_trampact[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_sigreset; /* signals that reset when caught */ + sigset_t ps_signodefer; /* signals not masked while handled */ + sigset_t ps_siginfo; /* signals that want SA_SIGINFO args */ sigset_t ps_oldmask; /* saved mask from before sigpause */ int ps_flags; /* signal flags, below */ struct sigaltstack ps_sigstk; /* sp & on stack state variable */ @@ -88,7 +95,7 @@ struct sigacts { /* additional signal action values, used only temporarily/internally */ #define SIG_CATCH (void (*)())2 #define SIG_HOLD (void (*)())3 - +#define SIG_WAIT (void (*)())4 #define pgsigio(pgid, sig, notused) \ { \ @@ -99,30 +106,17 @@ struct sigacts { psignal(p, sig); \ } - /* * 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 HAVE_SIGNALS(p) \ - ((p)->p_siglist \ - & ~((((p)->p_sigmask) \ - | (((p)->p_flag & P_TRACED) ? 0 : (p)->p_sigignore)) \ - & ~sigcantmask)) - /* * Check for per-process and per thread signals. */ #define SHOULDissignal(p,uthreadp) \ - (((p)->p_siglist | (uthreadp)->uu_sig) \ - & ~((((p)->p_sigmask) \ + (((uthreadp)->uu_siglist) \ + & ~((((uthreadp)->uu_sigmask) \ | (((p)->p_flag & P_TRACED) ? 0 : (p)->p_sigignore)) \ & ~sigcantmask)) @@ -135,12 +129,6 @@ struct sigacts { (!thread_should_halt(thread) \ && (SHOULDissignal(p,uthreadp))) - -/* - * Clear a pending signal from a process. - */ -#define CLRSIG(p, sig) { (p)->p_siglist &= ~sigmask(sig); } - /* * Signal properties and actions. * The array below categorizes the signals and their default actions @@ -203,14 +191,15 @@ int sigprop[NSIG + 1] = { * Machine-independent functions: */ int coredump __P((struct proc *p)); -void execsigs __P((struct proc *p)); +void execsigs __P((struct proc *p, thread_act_t thr_act)); void gsignal __P((int pgid, int sig)); int issignal __P((struct proc *p)); int CURSIG __P((struct proc *p)); -int clear_sigbits __P((struct proc *p, int bit)); -void pgsignal __P((struct pgrp *pgrp, int sig, int checkctty)); +int clear_procsiglist __P((struct proc *p, int bit)); +int clear_procsigmask __P((struct proc *p, int bit)); +int set_procsigmask __P((struct proc *p, int bit)); +void tty_pgsignal __P((struct pgrp *pgrp, int sig)); void postsig __P((int sig)); -void psignal __P((struct proc *p, int sig)); void siginit __P((struct proc *p)); void trapsignal __P((struct proc *p, int sig, unsigned code)); void pt_setrunnable __P((struct proc *p)); @@ -218,6 +207,16 @@ void pt_setrunnable __P((struct proc *p)); /* * Machine-dependent functions: */ -void sendsig __P((struct proc *, sig_t action, int sig, int returnmask, u_long code)); +void sendsig __P((struct proc *, sig_t action, int sig, + int returnmask, u_long code)); + +#ifdef __APPLE_API_UNSTABLE +void psignal __P((struct proc *p, int sig)); +void pgsignal __P((struct pgrp *pgrp, int sig, int checkctty)); +#endif /* __APPLE_API_UNSTABLE */ + #endif /* KERNEL */ + +#endif /* __APPLE_API_PRIVATE */ + #endif /* !_SYS_SIGNALVAR_H_ */ diff --git a/bsd/sys/socket.h b/bsd/sys/socket.h index 080cc3b7c..3790d7305 100644 --- a/bsd/sys/socket.h +++ b/bsd/sys/socket.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -54,16 +54,32 @@ * SUCH DAMAGE. * * @(#)socket.h 8.4 (Berkeley) 2/21/94 + * $FreeBSD: src/sys/sys/socket.h,v 1.39.2.7 2001/07/03 11:02:01 ume Exp $ */ #ifndef _SYS_SOCKET_H_ #define _SYS_SOCKET_H_ +#ifndef __APPLE__ +#include +#endif +#define _NO_NAMESPACE_POLLUTION +#include +#undef _NO_NAMESPACE_POLLUTION /* * Definitions related to sockets: types, address families, options. */ +/* + * Data types. + */ +typedef u_char sa_family_t; +#ifdef _BSD_SOCKLEN_T_ +typedef _BSD_SOCKLEN_T_ socklen_t; +#undef _BSD_SOCKLEN_T_ +#endif + /* * Types */ @@ -87,11 +103,14 @@ #define SO_OOBINLINE 0x0100 /* leave received OOB data in line */ #define SO_REUSEPORT 0x0200 /* allow local address & port reuse */ #define SO_TIMESTAMP 0x0400 /* timestamp received dgram traffic */ - +#ifndef __APPLE__ +#define SO_ACCEPTFILTER 0x1000 /* there is an accept filter */ +#else #define SO_DONTTRUNC 0x2000 /* APPLE: Retain unread data */ /* (ATOMIC proto) */ -#define SO_WANTMORE 0x4000 /* APPLE: Give hint when more data ready */ -#define SO_WANTOOBFLAG 0x8000 /* APPLE: Want OOB in MSG_FLAG on receive */ +#define SO_WANTMORE 0x4000 /* APPLE: Give hint when more data ready */ +#define SO_WANTOOBFLAG 0x8000 /* APPLE: Want OOB in MSG_FLAG on receive */ +#endif /* * Additional options, not kept in so_options. @@ -104,10 +123,12 @@ #define SO_RCVTIMEO 0x1006 /* receive timeout */ #define SO_ERROR 0x1007 /* get error status and clear */ #define SO_TYPE 0x1008 /* get socket type */ -#define SO_PRIVSTATE 0x1009 /* get/deny privileged state */ +/*efine SO_PRIVSTATE 0x1009 get/deny privileged state */ +#ifdef __APPLE__ #define SO_NREAD 0x1020 /* APPLE: get 1st-packet byte count */ #define SO_NKE 0x1021 /* APPLE: Install socket-level NKE */ - +#define SO_NOSIGPIPE 0x1022 /* APPLE: No SIGPIPE on EPIPE */ +#endif /* * Structure used for manipulating linger option. */ @@ -116,6 +137,13 @@ struct linger { int l_linger; /* linger time */ }; +#ifndef __APPLE__ +struct accept_filter_arg { + char af_name[16]; + char af_arg[256-16]; +}; +#endif + /* * Level number for (get/set)sockopt() to apply to socket itself. */ @@ -125,7 +153,7 @@ struct linger { * Address families. */ #define AF_UNSPEC 0 /* unspecified */ -#define AF_LOCAL 1 /* local to host (pipes, portals) */ +#define AF_LOCAL 1 /* local to host (pipes) */ #define AF_UNIX AF_LOCAL /* backward compatibility */ #define AF_INET 2 /* internetwork: UDP, TCP, etc. */ #define AF_IMPLINK 3 /* arpanet imp addresses */ @@ -134,7 +162,7 @@ struct linger { #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_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 */ @@ -152,21 +180,29 @@ struct linger { #define AF_IPX 23 /* Novell Internet Protocol */ #define AF_SIP 24 /* Simple Internet Protocol */ #define pseudo_AF_PIP 25 /* Help Identify PIP packets */ - /* Sigh - The following 2 should */ - /* be maintained for MacOSX */ - /* binary compatibility */ -#define pseudo_AF_BLUE 26 /* Identify packets for Blue Box */ +#ifdef __APPLE__ +/*define pseudo_AF_BLUE 26 Identify packets for Blue Box - Not used */ #define AF_NDRV 27 /* Network Driver 'raw' access */ +#endif #define AF_ISDN 28 /* Integrated Services Digital Network*/ #define AF_E164 AF_ISDN /* CCITT E.164 recommendation */ #define pseudo_AF_KEY 29 /* Internal key-management function */ #define AF_INET6 30 /* IPv6 */ #define AF_NATM 31 /* native ATM access */ -#define AF_SYSTEM 32 /* Kernel event messages */ +#ifdef __APPLE__ +#define AF_SYSTEM 32 /* Kernel event messages */ #define AF_NETBIOS 33 /* NetBIOS */ #define AF_PPP 34 /* PPP communication protocol */ - -#define AF_MAX 35 +#else +#define AF_ATM 30 /* ATM */ +#endif +#define pseudo_AF_HDRCMPLT 35 /* Used by BPF to not rewrite headers + * in interface output routine + */ +#ifndef __APPLE__ +#define AF_NETGRAPH 32 /* Netgraph sockets */ +#endif +#define AF_MAX 36 /* * Structure used by kernel to store most @@ -175,7 +211,7 @@ struct linger { struct sockaddr { u_char sa_len; /* total length */ u_char sa_family; /* address family */ - char sa_data[14]; /* actually longer; address value */ + char sa_data[14]; /* actually longer; address value */ }; #define SOCK_MAXADDRLEN 255 /* longest possible addresses */ @@ -188,24 +224,22 @@ struct sockproto { u_short sp_protocol; /* protocol */ }; -#if 1 /* - * bsd-api-new-02a: protocol-independent placeholder for socket addresses + * RFC 2553: protocol-independent placeholder for socket addresses */ -#define _SS_MAXSIZE 128 -#define _SS_ALIGNSIZE (sizeof(int64_t)) -#define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof(u_char) * 2) -#define _SS_PAD2SIZE (_SS_MAXSIZE - sizeof(u_char) * 2 - \ +#define _SS_MAXSIZE 128 +#define _SS_ALIGNSIZE (sizeof(int64_t)) +#define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof(u_char) - sizeof(sa_family_t)) +#define _SS_PAD2SIZE (_SS_MAXSIZE - sizeof(u_char) - sizeof(sa_family_t) - \ _SS_PAD1SIZE - _SS_ALIGNSIZE) struct sockaddr_storage { - u_char ss_len; /* address length */ - u_char ss_family; /* address family */ - char _ss_pad1[_SS_PAD1SIZE]; - int64_t _ss_align; /* force desired structure storage alignment */ - char _ss_pad2[_SS_PAD2SIZE]; + u_char ss_len; /* address length */ + sa_family_t ss_family; /* address family */ + char __ss_pad1[_SS_PAD1SIZE]; + int64_t __ss_align; /* force desired structure storage alignment */ + char __ss_pad2[_SS_PAD2SIZE]; }; -#endif /* * Protocol families, same as address families for now. @@ -214,7 +248,6 @@ struct sockaddr_storage { #define PF_LOCAL AF_LOCAL #define PF_UNIX PF_LOCAL /* backward compatibility */ #define PF_INET AF_INET -#define PF_INET6 AF_INET6 #define PF_IMPLINK AF_IMPLINK #define PF_PUP AF_PUP #define PF_CHAOS AF_CHAOS @@ -239,16 +272,21 @@ struct sockaddr_storage { #define PF_IPX AF_IPX /* same format as AF_NS */ #define PF_RTIP pseudo_AF_RTIP /* same format as AF_INET */ #define PF_PIP pseudo_AF_PIP - +#ifdef __APPLE__ #define PF_NDRV AF_NDRV +#endif #define PF_ISDN AF_ISDN #define PF_KEY pseudo_AF_KEY #define PF_INET6 AF_INET6 #define PF_NATM AF_NATM -#define PF_ATM AF_ATM +#ifdef __APPLE__ #define PF_SYSTEM AF_SYSTEM #define PF_NETBIOS AF_NETBIOS #define PF_PPP AF_PPP +#else +#define PF_ATM AF_ATM +#define PF_NETGRAPH AF_NETGRAPH +#endif #define PF_MAX AF_MAX @@ -289,10 +327,16 @@ struct sockaddr_storage { { "ipx", CTLTYPE_NODE }, \ { "sip", CTLTYPE_NODE }, \ { "pip", CTLTYPE_NODE }, \ + { 0, 0 }, \ + { "ndrv", CTLTYPE_NODE }, \ { "isdn", CTLTYPE_NODE }, \ { "key", CTLTYPE_NODE }, \ { "inet6", CTLTYPE_NODE }, \ { "natm", CTLTYPE_NODE }, \ + { "sys", CTLTYPE_NODE }, \ + { "netbios", CTLTYPE_NODE }, \ + { "ppp", CTLTYPE_NODE }, \ + { "hdrcomplete", CTLTYPE_NODE }, \ } /* @@ -343,11 +387,13 @@ struct msghdr { #define MSG_WAITALL 0x40 /* wait for full request or error */ #define MSG_DONTWAIT 0x80 /* this message should be nonblocking */ #define MSG_EOF 0x100 /* data completes connection */ +#ifdef __APPLE__ #define MSG_FLUSH 0x400 /* Start of 'hold' seq; dump so_temp */ #define MSG_HOLD 0x800 /* Hold frag in so_temp */ #define MSG_SEND 0x1000 /* Send the packet in so_temp */ #define MSG_HAVEMORE 0x2000 /* Data ready to be read */ #define MSG_RCVMORE 0x4000 /* Data remains in current pkt */ +#endif #define MSG_COMPAT 0x8000 /* used in sendit() */ /* @@ -363,26 +409,53 @@ struct cmsghdr { /* followed by u_char cmsg_data[]; */ }; -/* given pointer to struct cmsghdr, return pointer to data */ -#define CMSG_DATA(cmsg) ((u_char *)((cmsg) + 1)) +#ifndef __APPLE__ +/* + * While we may have more groups than this, the cmsgcred struct must + * be able to fit in an mbuf, and NGROUPS_MAX is too large to allow + * this. +*/ +#define CMGROUP_MAX 16 -/* Alignment requirement for CMSG struct manipulation. - * This is different from ALIGN() defined in ARCH/include/param.h. - * XXX think again carefully about architecture dependencies. +/* + * Credentials structure, used to verify the identity of a peer + * process that has sent us a message. This is allocated by the + * peer process but filled in by the kernel. This prevents the + * peer from lying about its identity. (Note that cmcred_groups[0] + * is the effective GID.) */ -#define CMSG_ALIGN(n) (((n) + 3) & ~3) +struct cmsgcred { + pid_t cmcred_pid; /* PID of sending process */ + uid_t cmcred_uid; /* real UID of sending process */ + uid_t cmcred_euid; /* effective UID of sending process */ + gid_t cmcred_gid; /* real GID of sending process */ + short cmcred_ngroups; /* number or groups */ + gid_t cmcred_groups[CMGROUP_MAX]; /* groups */ +}; +#endif + +/* given pointer to struct cmsghdr, return pointer to data */ +#define CMSG_DATA(cmsg) ((u_char *)(cmsg) + \ + ALIGN(sizeof(struct cmsghdr))) /* given pointer to struct cmsghdr, return pointer to next cmsghdr */ #define CMSG_NXTHDR(mhdr, cmsg) \ - (((caddr_t)(cmsg) + (cmsg)->cmsg_len + sizeof(struct cmsghdr) > \ - (mhdr)->msg_control + (mhdr)->msg_controllen) ? \ + (((caddr_t)(cmsg) + ALIGN((cmsg)->cmsg_len) + \ + ALIGN(sizeof(struct cmsghdr)) > \ + (caddr_t)(mhdr)->msg_control + (mhdr)->msg_controllen) ? \ (struct cmsghdr *)NULL : \ - (struct cmsghdr *)((caddr_t)(cmsg) + CMSG_ALIGN((cmsg)->cmsg_len))) + (struct cmsghdr *)((caddr_t)(cmsg) + ALIGN((cmsg)->cmsg_len))) #define CMSG_FIRSTHDR(mhdr) ((struct cmsghdr *)(mhdr)->msg_control) -#define CMSG_SPACE(l) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(l)) -#define CMSG_LEN(l) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (l)) +/* RFC 2292 additions */ + +#define CMSG_SPACE(l) (ALIGN(sizeof(struct cmsghdr)) + ALIGN(l)) +#define CMSG_LEN(l) (ALIGN(sizeof(struct cmsghdr)) + (l)) + +#ifdef KERNEL +#define CMSG_ALIGN(n) ALIGN(n) +#endif /* "Socket"-level control message types: */ #define SCM_RIGHTS 0x01 /* access rights (array of int) */ @@ -454,7 +527,10 @@ 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 *)); + +void pfctlinput __P((int, struct sockaddr *)); __END_DECLS #endif /* !KERNEL */ + #endif /* !_SYS_SOCKET_H_ */ diff --git a/bsd/sys/socketvar.h b/bsd/sys/socketvar.h index f4968601b..bf767c249 100644 --- a/bsd/sys/socketvar.h +++ b/bsd/sys/socketvar.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -53,30 +53,29 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)socketvar.h 8.1 (Berkeley) 6/2/93 + * @(#)socketvar.h 8.3 (Berkeley) 2/19/95 + * $FreeBSD: src/sys/sys/socketvar.h,v 1.46.2.6 2001/08/31 13:45:49 jlemon Exp $ */ -#ifndef _SYS_SOCKETVAR_H_ +#ifndef _SYS_SOCKETVAR_H_ #define _SYS_SOCKETVAR_H_ +#include +#include /* for TAILQ macros */ #include /* for struct selinfo */ -#include #include #include /* * Hacks to get around compiler complaints */ struct mbuf; -struct socket; -struct uio; -struct sockbuf; -struct sockaddr; struct kextcb; struct protosw; struct sockif; struct sockutil; /* strings for sleep message: */ +#ifdef __APPLE_API_UNSTABLE extern char netio[], netcon[], netcls[]; #define SOCKET_CACHE_ON #define SO_CACHE_FLUSH_INTERVAL 1 /* Seconds */ @@ -93,22 +92,27 @@ extern char netio[], netcon[], netcls[]; */ typedef u_quad_t so_gen_t; +#ifndef __APPLE__ +/* We don't support BSD style socket filters */ +struct accept_filter; +#endif + struct socket { - int so_zone; /* zone we were allocated from */ - short so_type; /* generic type, see socket.h */ + int so_zone; /* zone we were allocated from */ + 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 */ + 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. + * Variables for connection queuing. * 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. + * For head socket so_incomp queues partially completed connections, + * while so_comp 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. + * it has to be pulled out of either so_incomp or so_comp. * We allow connections to queue up based on current queue lengths * and limit on number of queued connections for this socket. */ @@ -124,6 +128,10 @@ struct socket { u_short so_error; /* error affecting connection */ pid_t so_pgid; /* pgid for signals */ u_long so_oobmark; /* chars to oob mark */ +#ifndef __APPLE__ + /* We don't support AIO ops */ + TAILQ_HEAD(, aiocblist) so_aiojobq; /* AIO ops waiting on socket */ +#endif /* * Variables for socket buffering. */ @@ -134,7 +142,9 @@ struct socket { u_long sb_mbmax; /* max chars of mbufs to use */ long sb_lowat; /* low water mark */ struct mbuf *sb_mb; /* the mbuf chain */ - struct socket *sb_so; /* socket back ptr */ +#if __APPLE__ + struct socket *sb_so; /* socket back ptr for kexts */ +#endif struct selinfo sb_sel; /* process selecting read/write */ short sb_flags; /* flags, see below */ short sb_timeo; /* timeout for read/write */ @@ -146,18 +156,32 @@ struct socket { #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_ASYNC 0x10 /* ASYNC I/O, need signals */ +#define SB_UPCALL 0x20 /* someone wants an upcall */ +#define SB_NOINTR 0x40 /* operations not interruptible */ +#ifndef __APPLE__ +#define SB_AIO 0x80 /* AIO operations queued */ +#define SB_KNOTE 0x100 /* kernel note attached */ +#else #define SB_NOTIFY (SB_WAIT|SB_SEL|SB_ASYNC) -#define SB_UPCALL 0x20 /* someone wants an upcall */ -#define SB_NOINTR 0x40 /* operations not interruptible */ #define SB_RECV 0x8000 /* this is rcv sb */ - caddr_t so_tpcb; /* Wisc. protocol control block XXX */ + caddr_t so_tpcb; /* Wisc. protocol control block - XXX unused? */ +#endif + void (*so_upcall) __P((struct socket *so, caddr_t arg, int waitf)); caddr_t so_upcallarg; /* Arg for above */ uid_t so_uid; /* who opened the socket */ /* NB: generation count must not be first; easiest to make it last. */ so_gen_t so_gencnt; /* generation count */ +#ifndef __APPLE__ + void *so_emuldata; /* private data for emulators */ + struct so_accf { + struct accept_filter *so_accept_filter; + void *so_accept_filter_arg; /* saved filter args */ + char *so_accept_filter_str; /* saved user args */ + } *so_accf; +#else TAILQ_HEAD(,eventqelt) so_evlist; int cached_in_sock_layer; /* Is socket bundled with pcb/pcb.inp_ppcb? */ struct socket *cache_next; @@ -168,11 +192,14 @@ struct socket { /* Plug-in support - make the socket interface overridable */ struct mbuf *so_tail; struct kextcb *so_ext; /* NKE hook */ - void *reserved1; /* for future use if needed */ + u_long so_flags; /* Flags */ +#define SOF_NOSIGPIPE 0x00000001 void *reserved2; void *reserved3; void *reserved4; +#endif }; +#endif /* __APPLE_API_UNSTABLE */ /* * Socket state bits. @@ -191,6 +218,7 @@ struct socket { #define SS_ISCONFIRMING 0x400 /* deciding to accept connection req */ #define SS_INCOMP 0x800 /* Unaccepted, incomplete connection */ #define SS_COMP 0x1000 /* unaccepted, complete connection */ +#define SS_ISDISCONNECTED 0x2000 /* socket disconnected from peer */ /* * Externalized form of struct socket used by the sysctl(3) interface. @@ -227,8 +255,26 @@ struct xsocket { /* * Macros for sockets and socket buffering. */ +#ifdef __APPLE__ +#ifdef __APPLE_API_UNSTABLE #define sbtoso(sb) (sb->sb_so) +/* + * Functions for sockets and socket buffering. + * These are macros on FreeBSD. On Darwin the + * implementation is in bsd/kern/uipc_socket2.c + */ +int sb_notify __P((struct sockbuf *sb)); +long sbspace __P((struct sockbuf *sb)); +int sosendallatonce __P((struct socket *so)); +int soreadable __P((struct socket *so)); +int sowriteable __P((struct socket *so)); +void sballoc __P((struct sockbuf *sb, struct mbuf *m)); +void sbfree __P((struct sockbuf *sb, struct mbuf *m)); +int sblock __P((struct sockbuf *sb, int wf)); +void sbunlock __P((struct sockbuf *sb)); +void sorwakeup __P((struct socket * so)); +void sowwakeup __P((struct socket * so)); /* * Socket extension mechanism: control block hooks: @@ -247,8 +293,10 @@ struct kextcb }; #define EXT_NULL 0x0 /* STATE: Not in use */ #define sotokextcb(so) (so ? so->so_ext : 0) +#endif /* __APPLE___ */ #ifdef KERNEL + /* * Argument structure for sosetopt et seq. This is in the KERNEL * section because it will never be visible to user code. @@ -264,14 +312,12 @@ struct sockopt { }; #if SENDFILE - struct sf_buf { SLIST_ENTRY(sf_buf) free_list; /* list of free buffer slots */ int refcnt; /* reference count */ struct vm_page *m; /* currently mapped page */ vm_offset_t kva; /* va of mapping */ }; - #endif #ifdef MALLOC_DECLARE @@ -291,19 +337,22 @@ struct sockaddr; struct stat; struct ucred; struct uio; +#ifndef __APPLE +struct knote; +#endif /* * 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_read __P((struct file *fp, struct uio *uio, struct ucred *cred, + int flags, struct proc *p)); +int soo_write __P((struct file *fp, struct uio *uio, struct ucred *cred, + int flags, struct proc *p)); +int soo_close __P((struct file *fp, struct proc *p)); int soo_ioctl __P((struct file *fp, u_long cmd, caddr_t data, struct proc *p)); -int soo_select __P((struct file *fp, int which, void * wql, struct proc *p)); int soo_stat __P((struct socket *so, struct stat *ub)); - -int soo_close __P((struct file *fp, struct proc *p)); - +int soo_select __P((struct file *fp, int which, void * wql, struct proc *p)); /* * From uipc_socket and friends @@ -358,6 +407,15 @@ struct socket * int sooptcopyin __P((struct sockopt *sopt, void *buf, size_t len, size_t minlen)); int sooptcopyout __P((struct sockopt *sopt, void *buf, size_t len)); + +/* + * XXX; prepare mbuf for (__FreeBSD__ < 3) routines. + * Used primarily in IPSec and IPv6 code. + */ +int soopt_getm __P((struct sockopt *sopt, struct mbuf **mp)); +int soopt_mcopyin __P((struct sockopt *sopt, struct mbuf *m)); +int soopt_mcopyout __P((struct sockopt *sopt, struct mbuf *m)); + int sopoll __P((struct socket *so, int events, struct ucred *cred, void *wql)); int soreceive __P((struct socket *so, struct sockaddr **paddr, struct uio *uio, struct mbuf **mp0, @@ -368,33 +426,22 @@ int sosend __P((struct socket *so, struct sockaddr *addr, struct uio *uio, struct mbuf *top, struct mbuf *control, int flags)); int sosetopt __P((struct socket *so, struct sockopt *sopt)); - - int soshutdown __P((struct socket *so, int how)); void sotoxsocket __P((struct socket *so, struct xsocket *xso)); void sowakeup __P((struct socket *so, struct sockbuf *sb)); -int sb_notify __P((struct sockbuf *sb)); -long sbspace __P((struct sockbuf *sb)); -int sosendallatonce __P((struct socket *so)); -int soreadable __P((struct socket *so)); -int sowriteable __P((struct socket *so)); -void sballoc __P((struct sockbuf *sb, struct mbuf *m)); -void sbfree __P((struct sockbuf *sb, struct mbuf *m)); -int sblock __P((struct sockbuf *sb, int wf)); -void sbunlock __P((struct sockbuf *sb)); -void sorwakeup __P((struct socket * so)); -void sowwakeup __P((struct socket * so)); - - - - - - - - - - +#ifndef __APPLE__ +/* accept filter functions */ +int accept_filt_add __P((struct accept_filter *filt)); +int accept_filt_del __P((char *name)); +struct accept_filter * accept_filt_get __P((char *name)); +#ifdef ACCEPT_FILTER_MOD +int accept_filt_generic_mod_event __P((module_t mod, int event, void *data)); +SYSCTL_DECL(_net_inet_accf); +#endif /* ACCEPT_FILTER_MOD */ +#endif /* !defined(__APPLE__) */ #endif /* KERNEL */ +#endif /* __APPLE_API_UNSTABLE */ + #endif /* !_SYS_SOCKETVAR_H_ */ diff --git a/bsd/sys/sockio.h b/bsd/sys/sockio.h index de33b3330..964cce9cb 100644 --- a/bsd/sys/sockio.h +++ b/bsd/sys/sockio.h @@ -115,9 +115,20 @@ #define SIOCGIFGENERIC _IOWR('i', 58, struct ifreq) /* generic IF get op */ #define SIOCRSLVMULTI _IOWR('i', 59, struct rslvmulti_req) -#define SIOCSIFPHYADDR _IOW('i', 70, struct ifaliasreq) /* set gif addres */ -#define SIOCGIFPSRCADDR _IOWR('i', 71, struct ifreq) /* get gif psrc addr */ -#define SIOCGIFPDSTADDR _IOWR('i', 72, struct ifreq) /* get gif pdst addr */ +#define SIOCSIFLLADDR _IOW('i', 60, struct ifreq) /* set link level addr */ +#define SIOCGIFSTATUS _IOWR('i', 61, struct ifstat) /* get IF status */ +#define SIOCSIFPHYADDR _IOW('i', 62, struct ifaliasreq) /* set gif addres */ +#define SIOCGIFPSRCADDR _IOWR('i', 63, struct ifreq) /* get gif psrc addr */ +#define SIOCGIFPDSTADDR _IOWR('i', 64, struct ifreq) /* get gif pdst addr */ +#define SIOCDIFPHYADDR _IOW('i', 65, struct ifreq) /* delete gif addrs */ +#define SIOCSLIFPHYADDR _IOW('i', 66, struct if_laddrreq) /* set gif addrs */ +#define SIOCGLIFPHYADDR _IOWR('i', 67, struct if_laddrreq) /* get gif addrs */ + + + + + + #ifdef KERNEL_PRIVATE /* diff --git a/bsd/sys/subr_prf.h b/bsd/sys/subr_prf.h index 8b6950494..830ea6a74 100644 --- a/bsd/sys/subr_prf.h +++ b/bsd/sys/subr_prf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -57,15 +57,16 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * HISTORY - * 23-Oct-1995 Doug Mitchell at NeXT - * Split out from subr_prf.c */ -#ifdef KERNEL_PRIVATE - #ifndef _SYS_SUBRPRF_H_ #define _SYS_SUBRPRF_H_ +#include + +#ifdef KERNEL_PRIVATE + +#ifdef __APPLE_API_PRIVATE + /* * "flags" argument to prf(). */ @@ -76,7 +77,8 @@ extern int prf(const char *fmt, va_list ap, int flags, struct tty *ttyp); -#endif /* ! _SYS_SUBRPRF_H_ */ - +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL_PRIVATE */ +#endif /* ! _SYS_SUBRPRF_H_ */ + diff --git a/bsd/sys/sys_domain.h b/bsd/sys/sys_domain.h new file mode 100644 index 000000000..b9582eca3 --- /dev/null +++ b/bsd/sys/sys_domain.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#ifndef _SYSTEM_DOMAIN_H_ +#define _SYSTEM_DOMAIN_H_ + + +#include + +/* Kernel Events Protocol */ +#define SYSPROTO_EVENT 1 /* kernel events protocol */ + +/* Kernel Control Protocol */ +#define SYSPROTO_CONTROL 2 /* kernel control protocol */ +#define AF_SYS_CONTROL 2 /* corresponding sub address type */ + +/* System family socket address */ +struct sockaddr_sys +{ + u_char ss_len; /* sizeof(struct sockaddr_sys) */ + u_char ss_family; /* AF_SYSTEM */ + u_int16_t ss_sysaddr; /* protocol address in AF_SYSTEM */ + u_int32_t ss_reserved[7]; /* reserved to the protocol use */ +}; + + +#ifdef KERNEL +#ifdef __APPLE_API_PRIVATE + +extern struct domain systemdomain; + +/* built in system domain protocols init function */ +int kern_event_init(); +int kern_control_init(); + +#endif /* __APPLE_API_PRIVATE */ +#endif /* KERNEL */ + +#endif /* _SYSTEM_DOMAIN_H_ */ + + diff --git a/bsd/sys/syscall.h b/bsd/sys/syscall.h index e9a7194a9..ade503bb6 100644 --- a/bsd/sys/syscall.h +++ b/bsd/sys/syscall.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -26,7 +26,9 @@ * and conditions for redistribution. * */ +#include +#ifdef __APPLE_API_PRIVATE #define SYS_syscall 0 #define SYS_exit 1 @@ -170,7 +172,7 @@ #define SYS_mkdir 136 #define SYS_rmdir 137 #define SYS_utimes 138 - /* 139 is unused */ +#define SYS_futimes 139 #define SYS_adjtime 140 /* 141 is old getpeername */ /* 142 is old gethostid */ @@ -182,10 +184,10 @@ /* 148 is obsolete setquota */ /* 149 is obsolete quota */ /* 150 is old getsockname */ - /* 151 is reserved */ +#define SYS_getpgid 151 #define SYS_setprivexec 152 - /* 153 is reserved */ - /* 154 is reserved */ +#define SYS_pread 153 +#define SYS_pwrite 154 #define SYS_nfssvc 155 /* 156 is old getdirentries */ #define SYS_statfs 157 @@ -215,10 +217,10 @@ #define SYS_setgid 181 #define SYS_setegid 182 #define SYS_seteuid 183 -#define SYS_lfs_bmapv 184 -#define SYS_lfs_markv 185 -#define SYS_lfs_segclean 186 -#define SYS_lfs_segwait 187 + /* 184 is unused */ + /* 185 is unused */ + /* 186 is unused */ + /* 187 is unused */ #define SYS_stat 188 #define SYS_fstat 189 #define SYS_lstat 190 @@ -258,8 +260,8 @@ #define SYS_checkuseraccess 224 #define SYS_searchfs 225 - /* 226 - 230 are reserved for HFS expansion */ - /* 231 - 249 are reserved */ + /* 226 - 230 are reserved for HFS expansion */ + /* 231 - 249 are reserved */ #define SYS_minherit 250 #define SYS_semsys 251 #define SYS_msgsys 252 @@ -287,11 +289,19 @@ #define SYS_sem_getvalue 274 #define SYS_sem_init 275 #define SYS_sem_destroy 276 - /* 277 - 295 are reserved */ + /* 277 - 295 are reserved */ #define SYS_load_shared_file 296 #define SYS_reset_shared_file 297 - /* 298 - 323 are reserved */ +#define SYS_new_system_shared_regions 298 + /* 299 - 309 are reserved */ +#define SYS_getsid 310 + /* 311 - 323 are reserved */ #define SYS_mlockall 324 #define SYS_munlockall 325 /* 326 is reserved */ #define SYS_issetugid 327 +#define SYS___pthread_kill 328 +#define SYS_pthread_sigmask 329 +#define SYS_sigwait 330 +#endif /* __APPLE_API_PRIVATE */ + diff --git a/bsd/sys/sysctl.h b/bsd/sys/sysctl.h index 557b4d936..300072522 100644 --- a/bsd/sys/sysctl.h +++ b/bsd/sys/sysctl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -64,11 +64,10 @@ /* * These are for the eproc structure defined below. */ +#include #ifndef KERNEL #include #include - - #endif #include @@ -123,6 +122,7 @@ struct ctlname { #define OID_AUTO (-1) #ifdef KERNEL +#ifdef __APPLE_API_UNSTABLE #define SYSCTL_HANDLER_ARGS (struct sysctl_oid *oidp, void *arg1, int arg2, \ struct sysctl_req *req) @@ -182,7 +182,7 @@ void sysctl_unregister_oid(struct sysctl_oid *oidp); /* This constructs a "raw" MIB oid. */ #define SYSCTL_OID(parent, nbr, name, kind, a1, a2, handler, fmt, descr) \ - struct sysctl_oid sysctl_##parent##_##name## = { \ + struct sysctl_oid sysctl_##parent##_##name = { \ &sysctl_##parent##_children, { 0 }, \ nbr, kind, a1, a2, #name, handler, fmt }; @@ -224,6 +224,7 @@ void sysctl_unregister_oid(struct sysctl_oid *oidp); #define SYSCTL_PROC(parent, nbr, name, access, ptr, arg, handler, fmt, descr) \ SYSCTL_OID(parent, nbr, name, access, \ ptr, arg, handler, fmt, descr) +#endif /* __APPLE_API_UNSTABLE */ #endif /* KERNEL */ /* @@ -294,8 +295,11 @@ void sysctl_unregister_oid(struct sysctl_oid *oidp); #define KERN_LOGSIGEXIT 36 /* int: do we log sigexit procs? */ #define KERN_SYMFILE 37 /* string: kernel symbol filename */ #define KERN_PROCARGS 38 -#define KERN_PCSAMPLES 39 /* int: pc sampling */ -#define KERN_MAXID 40 /* number of valid kern ids */ +#define KERN_PCSAMPLES 39 /* node: pc sampling */ +#define KERN_NETBOOT 40 /* int: are we netbooted? 1=yes,0=no */ +#define KERN_PANICINFO 41 /* node: panic UI information */ +#define KERN_SYSV 42 /* node: panic UI information */ +#define KERN_MAXID 43 /* number of valid kern ids */ /* KERN_KDEBUG types */ @@ -314,6 +318,7 @@ void sysctl_unregister_oid(struct sysctl_oid *oidp); /* Don't use 13 as it is overloaded with KERN_VNODE */ #define KERN_KDPIDEX 14 #define KERN_KDSETRTCDEC 15 +#define KERN_KDGETENTROPY 16 /* KERN_PCSAMPLES types */ #define KERN_PCDISABLE 1 @@ -325,6 +330,21 @@ void sysctl_unregister_oid(struct sysctl_oid *oidp); #define KERN_PCSETREG 7 #define KERN_PCCOMM 8 +/* KERN_PANICINFO types */ +#define KERN_PANICINFO_MAXSIZE 1 /* quad: panic UI image size limit */ +#define KERN_PANICINFO_IMAGE16 2 /* string: path to the panic UI (16 bit) */ +#define KERN_PANICINFO_IMAGE32 3 /* string: path to the panic UI (32 bit) */ + +/* + * KERN_SYSV identifiers + */ +#define KSYSV_SHMMAX 1 /* int: max shared memory segment size (bytes) */ +#define KSYSV_SHMMIN 2 /* int: min shared memory segment size (bytes) */ +#define KSYSV_SHMMNI 3 /* int: max number of shared memory identifiers */ +#define KSYSV_SHMSEG 4 /* int: max shared memory segments per process */ +#define KSYSV_SHMALL 5 /* int: max amount of shared memory (pages) */ + + #define CTL_KERN_NAMES { \ { 0, 0 }, \ { "ostype", CTLTYPE_STRING }, \ @@ -353,7 +373,7 @@ void sysctl_unregister_oid(struct sysctl_oid *oidp); { "kdebug", CTLTYPE_INT }, \ { "update", CTLTYPE_INT }, \ { "osreldate", CTLTYPE_INT }, \ - { "ntp_pll", CTLTYPE_NODE }, \ + { "ntp_pll", CTLTYPE_NODE }, \ { "bootfile", CTLTYPE_STRING }, \ { "maxfilesperproc", CTLTYPE_INT }, \ { "maxprocperuid", CTLTYPE_INT }, \ @@ -363,14 +383,19 @@ void sysctl_unregister_oid(struct sysctl_oid *oidp); { "ps_strings", CTLTYPE_INT }, \ { "usrstack", CTLTYPE_INT }, \ { "logsigexit", CTLTYPE_INT }, \ - { "symfile",CTLTYPE_STRING },\ + { "symfile",CTLTYPE_STRING },\ + { "procargs",CTLTYPE_STRUCT },\ + { "pcsamples",CTLTYPE_STRUCT },\ + { "netboot", CTLTYPE_INT }, \ + { "panicinfo", CTLTYPE_NODE }, \ + { "sysv", CTLTYPE_NODE } \ } /* * CTL_VFS identifiers */ #define CTL_VFS_NAMES { \ - { "vfsconf", CTLTYPE_STRUCT }, \ + { "vfsconf", CTLTYPE_STRUCT } \ } /* @@ -387,6 +412,7 @@ void sysctl_unregister_oid(struct sysctl_oid *oidp); /* * KERN_PROC subtype ops return arrays of augmented proc structures: */ +#ifdef __APPLE_API_UNSTABLE struct kinfo_proc { struct extern_proc kp_proc; /* proc structure */ struct eproc { @@ -394,16 +420,7 @@ struct kinfo_proc { struct session *e_sess; /* session pointer */ struct pcred e_pcred; /* process credentials */ struct ucred e_ucred; /* current credentials */ -#ifdef sparc - struct { - segsz_t vm_rssize; /* resident set size */ - segsz_t vm_tsize; /* text size */ - segsz_t vm_dsize; /* data size */ - segsz_t vm_ssize; /* stack size */ - } e_vm; -#else - struct vmspace e_vm; /* address space */ -#endif + 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 */ @@ -419,10 +436,12 @@ struct kinfo_proc { long e_flag; #define EPROC_CTTY 0x01 /* controlling tty vnode active */ #define EPROC_SLEADER 0x02 /* session leader */ - char e_login[MAXLOGNAME]; /* setlogin() name */ +#define COMAPT_MAXLOGNAME 12 + char e_login[COMAPT_MAXLOGNAME]; /* short setlogin() name */ long e_spare[4]; } kp_eproc; }; +#endif /* __APPLE_API_UNSTABLE */ /* * KERN_IPC identifiers @@ -448,7 +467,7 @@ struct kinfo_proc { #define CTL_VM_NAMES { \ { 0, 0 }, \ { "vmmeter", CTLTYPE_STRUCT }, \ - { "loadavg", CTLTYPE_STRUCT }, \ + { "loadavg", CTLTYPE_STRUCT } \ } /* @@ -501,7 +520,7 @@ struct kinfo_proc { { "l2settings", CTLTYPE_INT }, \ { "l2cachesize", CTLTYPE_INT }, \ { "l3settings", CTLTYPE_INT }, \ - { "l3cachesize", CTLTYPE_INT }, \ + { "l3cachesize", CTLTYPE_INT } \ } /* @@ -550,7 +569,7 @@ struct kinfo_proc { { "posix2_sw_dev", CTLTYPE_INT }, \ { "posix2_upe", CTLTYPE_INT }, \ { "stream_max", CTLTYPE_INT }, \ - { "tzname_max", CTLTYPE_INT }, \ + { "tzname_max", CTLTYPE_INT } \ } @@ -566,6 +585,7 @@ struct kinfo_proc { #define CTL_DEBUG_MAXID 20 #ifdef KERNEL +#ifdef __APPLE_API_UNSTABLE extern struct sysctl_oid_list sysctl__children; SYSCTL_DECL(_kern); @@ -630,11 +650,14 @@ typedef int (sysctlfn) int sysctl_int __P((void *, size_t *, void *, size_t, int *)); int sysctl_rdint __P((void *, size_t *, void *, int)); +int sysctl_quad __P((void *, size_t *, void *, size_t, quad_t *)); +int sysctl_rdquad __P((void *, size_t *, void *, quad_t)); int sysctl_string __P((void *, size_t *, void *, size_t, char *, int)); int sysctl_rdstring __P((void *, size_t *, void *, char *)); int sysctl_rdstruct __P((void *, size_t *, void *, void *, int)); void fill_eproc __P((struct proc *, struct eproc *)); +#endif /* __APPLE_API_UNSTABLE */ #else /* !KERNEL */ #include diff --git a/bsd/sys/syslog.h b/bsd/sys/syslog.h index ce67c44d8..eae10fa0e 100644 --- a/bsd/sys/syslog.h +++ b/bsd/sys/syslog.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -58,6 +58,8 @@ #ifndef _SYS_SYSLOG_H_ #define _SYS_SYSLOG_H_ +#include + #define _PATH_LOG "/var/run/syslog" /* @@ -171,7 +173,9 @@ CODE facilitynames[] = { #endif #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE #define LOG_PRINTF -1 /* pseudo-priority to indicate use of printf */ +#endif /* __APPLE_API_PRIVATE */ #endif /* @@ -215,7 +219,7 @@ void vsyslog __P((int, const char *, _BSD_VA_LIST_)); __END_DECLS #else /* !KERNEL */ - +#ifdef __APPLE_API_OBSOLETE /* * bit field descriptions for printf %r and %R formats */ @@ -295,6 +299,8 @@ struct reg_desc { struct reg_values *rd_values; /* symbolic names of values */ }; +#endif /* __APPLE_API_OBSOLETE */ + void logpri __P((int)); void log __P((int, const char *, ...)); void addlog __P((const char *, ...)); diff --git a/bsd/sys/systm.h b/bsd/sys/systm.h index 88057b052..3110e2679 100644 --- a/bsd/sys/systm.h +++ b/bsd/sys/systm.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -91,8 +91,8 @@ #ifndef _SYS_SYSTM_H_ #define _SYS_SYSTM_H_ +#include #include - #include #include #include @@ -103,19 +103,12 @@ __BEGIN_DECLS #include __END_DECLS -#define KERNEL_FUNNEL 1 -#define NETWORK_FUNNEL 2 - +#ifdef __APPLE_API_PRIVATE extern int securelevel; /* system security level */ extern const 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 dev_t rootdev; /* root device */ -extern struct vnode *rootvp; /* vnode equivalent to above */ extern struct sysent { /* system call table */ int16_t sy_narg; /* number of args */ @@ -128,13 +121,24 @@ extern int nsysent; extern int boothowto; /* reboot flags, from console subsystem */ extern int show_space; +extern int nblkdev; /* number of entries in bdevsw */ +extern int nchrdev; /* number of entries in cdevsw */ +extern dev_t rootdev; /* root device */ +extern struct vnode *rootvp; /* vnode equivalent to above */ +#endif /* __APPLE_API_PRIVATE */ + +#ifdef __APPLE_API_UNSTABLE +#define NO_FUNNEL 0 +#define KERNEL_FUNNEL 1 +#define NETWORK_FUNNEL 2 + extern funnel_t * kernel_flock; extern funnel_t * network_flock; +#endif /* __APPLE_API_UNSTABLE */ #define SYSINIT(a,b,c,d,e) #define MALLOC_DEFINE(a,b,c) - #define getenv_int(a,b) (*b = 0) #define KASSERT(exp,msg) @@ -150,7 +154,11 @@ int enoioctl __P((void)); int enxio __P((void)); int eopnotsupp __P((void)); int einval __P((void)); + +#ifdef __APPLE_API_UNSTABLE int seltrue __P((dev_t dev, int which, struct proc *p)); +#endif /* __APPLE_API_UNSTABLE */ + void *hashinit __P((int count, int type, u_long *hashmask)); int nosys __P((struct proc *, void *, register_t *)); @@ -174,7 +182,6 @@ void vprintf __P((const char *, _BSD_VA_LIST_)); int vsnprintf __P((char *, size_t, const char *, _BSD_VA_LIST_)); int vsprintf __P((char *buf, const char *, _BSD_VA_LIST_)); - void bcopy __P((const void *from, void *to, size_t len)); void ovbcopy __P((const void *from, void *to, size_t len)); void bzero __P((void *buf, size_t len)); @@ -197,12 +204,15 @@ long fuiword __P((void *base)); int suword __P((void *base, long word)); int suiword __P((void *base, long word)); +#ifdef __APPLE_API_UNSTABLE int hzto __P((struct timeval *tv)); typedef void (*timeout_fcn_t)(void *); void timeout __P((void (*)(void *), void *arg, int ticks)); void untimeout __P((void (*)(void *), void *arg)); void realitexpire __P((void *)); +#endif /* __APPLE_API_UNSTABLE */ +#ifdef __APPLE_API_PRIVATE void bsd_hardclock __P((boolean_t usermode, caddr_t pc, int numticks)); void gatherstats __P((boolean_t usermode, caddr_t pc)); @@ -211,7 +221,13 @@ void initclocks __P((void)); void startprofclock __P((struct proc *)); void stopprofclock __P((struct proc *)); void setstatclockrate __P((int hzrate)); +#ifdef DDB +/* debugger entry points */ +int Debugger __P((void)); /* in DDB only */ +#endif + void set_fsblocksize __P((struct vnode *)); +#endif /* __APPLE_API_PRIVATE */ void addlog __P((const char *, ...)); void printf __P((const char *, ...)); @@ -220,11 +236,6 @@ extern boolean_t thread_funnel_switch(int oldfnl, int newfnl); #include -#ifdef DDB -/* debugger entry points */ -int Debugger __P((void)); /* in DDB only */ -#endif - __END_DECLS #endif /* !_SYS_SYSTM_H_ */ diff --git a/bsd/sys/table.h b/bsd/sys/table.h index ec4da3c58..a59713b4e 100644 --- a/bsd/sys/table.h +++ b/bsd/sys/table.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -25,22 +25,17 @@ * All rights reserved. The CMU software License Agreement specifies * the terms and conditions for use and redistribution. */ -/* - * HISTORY - * 27-Apr-97 A.Ramesh - * added limited set to MacOSX - * - * 05-Sep-91 Doug Mitchell at NeXT - * Made entire contents PRIVATE. - * - * - */ - -#ifdef KERNEL_PRIVATE #ifndef _SYS_TABLE_ #define _SYS_TABLE_ +#include + +#warning obsolete header! Please delete the include from your sources. + +#ifdef KERNEL_PRIVATE + +#ifdef __APPLE_API_OBSOLETE #include #include @@ -119,6 +114,8 @@ int machine_table(int id, int index, caddr_t addr, int nel, u_int lel, int set); int machine_table_setokay(int id); #endif /* KERNEL */ -#endif /* _SYS_TABLE_ */ +#endif /* __APPLE_API_OBSOLETE */ #endif /* KERNEL_PRIVATE */ +#endif /* _SYS_TABLE_ */ + diff --git a/bsd/sys/time.h b/bsd/sys/time.h index a3c667ea0..65b5c52db 100644 --- a/bsd/sys/time.h +++ b/bsd/sys/time.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -58,10 +58,9 @@ #ifndef _SYS_TIME_H_ #define _SYS_TIME_H_ +#include #include -#define getmicrouptime(a) microtime(a) -#define getmicrotime(a) microtime(a) /* * Structure returned by gettimeofday(2) system call, * and used in other calls. @@ -74,10 +73,13 @@ struct timeval { /* * Structure defined by POSIX.4 to be like a timeval. */ +#ifndef _TIMESPEC_DECLARED +#define _TIMESPEC_DECLARED struct timespec { time_t tv_sec; /* seconds */ int32_t tv_nsec; /* and nanoseconds */ }; +#endif #define TIMEVAL_TO_TIMESPEC(tv, ts) { \ (ts)->tv_sec = (tv)->tv_sec; \ @@ -155,9 +157,19 @@ struct clockinfo { #include #ifdef KERNEL +void microtime __P((struct timeval *tv)); +void microuptime __P((struct timeval *tv)); +#define getmicrotime(a) microtime(a) +#define getmicrouptime(a) microuptime(a) +void nanotime __P((struct timespec *ts)); +void nanouptime __P((struct timespec *ts)); +#define getnanotime(a) nanotime(a) +#define getnanouptime(a) nanouptime(a) +#ifdef __APPLE_API_PRIVATE int itimerfix __P((struct timeval *tv)); int itimerdecr __P((struct itimerval *itp, int usec)); -void microtime __P((struct timeval *tv)); +#endif /* __APPLE_API_PRIVATE */ + #else /* !KERNEL */ #include @@ -166,6 +178,7 @@ void microtime __P((struct timeval *tv)); __BEGIN_DECLS int adjtime __P((const struct timeval *, struct timeval *)); +int futimes __P((int, const struct timeval *)); int getitimer __P((int, struct itimerval *)); int gettimeofday __P((struct timeval *, struct timezone *)); int setitimer __P((int, const struct itimerval *, struct itimerval *)); diff --git a/bsd/sys/timeb.h b/bsd/sys/timeb.h index 4dd452ddf..9277d37d7 100644 --- a/bsd/sys/timeb.h +++ b/bsd/sys/timeb.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -63,6 +63,10 @@ #ifndef _SYS_TIMEB_H_ #define _SYS_TIMEB_H_ +#include + +#ifdef __APPLE_API_OBSOLETE + /* The ftime(2) system call structure -- deprecated. */ struct timeb { time_t time; /* seconds since the Epoch */ @@ -71,4 +75,6 @@ struct timeb { short dstflag; /* DST == non-zero */ }; +#endif /* __APPLE_API_OBSOLETE */ + #endif /* !_SYS_TIMEB_H_ */ diff --git a/bsd/sys/tprintf.h b/bsd/sys/tprintf.h index 907230180..8eaa93748 100644 --- a/bsd/sys/tprintf.h +++ b/bsd/sys/tprintf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -58,10 +58,16 @@ #ifndef _SYS_TPRINTF_H_ #define _SYS_TPRINTF_H_ +#include + +#ifdef __APPLE_API_UNSTABLE + 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, ...)); +#endif /* __APPLE_API_UNSTABLE */ + #endif /* !_SYS_TPRINTF_H_ */ diff --git a/bsd/sys/trace.h b/bsd/sys/trace.h index 49e230ffd..c77ef1ca8 100644 --- a/bsd/sys/trace.h +++ b/bsd/sys/trace.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -58,6 +58,9 @@ #ifndef _SYS_TRACE_H_ #define _SYS_TRACE_H_ +#include + +#ifdef __APPLE_API_OBSOLETE /* * File system buffer tracing points; all trace */ @@ -139,5 +142,8 @@ extern char traceflags[TR_NFLAGS]; #define trace(a,b,c) #endif #endif /* KERNEL */ + +#endif /* __APPLE_API_OBSOLETE */ + #endif /* !_SYS_TRACE_H_ */ diff --git a/bsd/sys/tty.h b/bsd/sys/tty.h index ba3683a90..c24e3083b 100644 --- a/bsd/sys/tty.h +++ b/bsd/sys/tty.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -63,11 +63,13 @@ #ifndef _SYS_TTY_H_ #define _SYS_TTY_H_ +#include #include - #include #include /* For struct selinfo. */ +#ifdef __APPLE_API_UNSTABLE + #ifndef __APPLE__ /* * Clists are character lists, which is a variable length linked list @@ -155,6 +157,7 @@ struct tty { #define t_ospeed t_termios.c_ospeed #define t_time t_termios.c_time + #define TTIPRI 25 /* Sleep priority for tty reads. */ #define TTOPRI 26 /* Sleep priority for tty writes. */ @@ -214,6 +217,7 @@ struct tty { #define TS_DSR_OFLOW 0x800000 /* For CDSR_OFLOW. */ #endif + /* Character type information. */ #define ORDINARY 0 #define CONTROL 1 @@ -260,6 +264,7 @@ struct speedtab { #define TSA_PTC_WRITE(tp) ((void *)&(tp)->t_rawq.c_cl) #define TSA_PTS_READ(tp) ((void *)&(tp)->t_canq) + #ifdef KERNEL __BEGIN_DECLS @@ -341,4 +346,6 @@ __END_DECLS #endif /* KERNEL */ +#endif /* __APPLE_API_UNSTABLE */ + #endif /* !_SYS_TTY_H_ */ diff --git a/bsd/sys/ttychars.h b/bsd/sys/ttychars.h index 9e7bffd91..15a12df1a 100644 --- a/bsd/sys/ttychars.h +++ b/bsd/sys/ttychars.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -58,6 +58,9 @@ #ifndef _SYS_TTYCHARS_H_ #define _SYS_TTYCHARS_H_ +#include + +#ifdef __APPLE_API_UNSTABLE /* * 4.3 COMPATIBILITY FILE * @@ -83,4 +86,8 @@ struct ttychars { #ifdef USE_OLD_TTY #include /* to pick up character defaults */ #endif + +#endif /* __APPLE_API_UNSTABLE */ + #endif /* !_SYS_TTYCHARS_H_ */ + diff --git a/bsd/sys/ttycom.h b/bsd/sys/ttycom.h index d2a3ef597..5baac4b80 100644 --- a/bsd/sys/ttycom.h +++ b/bsd/sys/ttycom.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * diff --git a/bsd/sys/ttydefaults.h b/bsd/sys/ttydefaults.h index 5e9a33e45..b11fbb6d3 100644 --- a/bsd/sys/ttydefaults.h +++ b/bsd/sys/ttydefaults.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * diff --git a/bsd/sys/ttydev.h b/bsd/sys/ttydev.h index b08a16e8c..82a1ef4b9 100644 --- a/bsd/sys/ttydev.h +++ b/bsd/sys/ttydev.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * diff --git a/bsd/sys/types.h b/bsd/sys/types.h index a2cb5928d..8ff840d65 100644 --- a/bsd/sys/types.h +++ b/bsd/sys/types.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -63,6 +63,8 @@ #ifndef _SYS_TYPES_H_ #define _SYS_TYPES_H_ +#include + #ifndef __ASSEMBLER__ #include @@ -90,6 +92,8 @@ typedef int32_t daddr_t; /* disk address */ typedef int32_t dev_t; /* device number */ typedef u_int32_t fixpt_t; /* fixed point number */ typedef u_int32_t gid_t; /* group id */ +typedef u_int32_t in_addr_t; /* base type for internet address */ +typedef u_int16_t in_port_t; typedef u_int32_t ino_t; /* inode number */ typedef long key_t; /* IPC key (for Sys V IPC) */ typedef u_int16_t mode_t; /* permissions */ @@ -101,7 +105,6 @@ typedef int32_t segsz_t; /* segment size */ typedef int32_t swblk_t; /* swap offset */ typedef u_int32_t uid_t; /* user id */ - #ifndef _POSIX_SOURCE /* Major, minor numbers, dev_t's. */ #define major(x) ((int32_t)(((u_int32_t)(x) >> 24) & 0xff)) @@ -192,6 +195,8 @@ struct _pthread_handler_rec #define __PTHREAD_CONDATTR_SIZE__ 4 #define __PTHREAD_COND_SIZE__ 24 #define __PTHREAD_ONCE_SIZE__ 4 +#define __PTHREAD_RWLOCK_SIZE__ 124 +#define __PTHREAD_RWLOCKATTR_SIZE__ 12 typedef struct _opaque_pthread_t { long sig; struct _pthread_handler_rec *cleanup_stack; char opaque[__PTHREAD_SIZE__];} *pthread_t; @@ -206,6 +211,10 @@ typedef struct _opaque_pthread_condattr_t { long sig; char opaque[__PTHREAD_COND typedef struct _opaque_pthread_cond_t { long sig; char opaque[__PTHREAD_COND_SIZE__]; } pthread_cond_t; +typedef struct _opaque_pthread_rwlockattr_t { long sig; char opaque[__PTHREAD_RWLOCKATTR_SIZE__]; } pthread_rwlockattr_t; + +typedef struct _opaque_pthread_rwlock_t { long sig; char opaque[__PTHREAD_RWLOCK_SIZE__]; } pthread_rwlock_t; + typedef struct { long sig; char opaque[__PTHREAD_ONCE_SIZE__]; } pthread_once_t; #endif /* __POSIX_LIB__ */ diff --git a/bsd/sys/ubc.h b/bsd/sys/ubc.h index db2c18c4a..d243bb97f 100644 --- a/bsd/sys/ubc.h +++ b/bsd/sys/ubc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1999, 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -31,6 +31,7 @@ #ifndef _SYS_UBC_H_ #define _SYS_UBC_H_ +#include #include #include #include @@ -42,6 +43,7 @@ #define UBC_INFO_NULL ((struct ubc_info *) 0) #define UBC_NOINFO ((struct ubc_info *)0xDEADD1ED) +#ifdef __APPLE_API_PRIVATE extern struct zone *ubc_info_zone; /* @@ -68,6 +70,9 @@ struct ubc_info { #define UI_WASMAPPED 0x00000008 /* vnode was mapped */ #define UI_DONTCACHE 0x00000010 /* do not cache object */ +#endif /* __APPLE_API_PRIVATE */ + +#ifdef __APPLE_API_EVOLVING /* * exported primitives for loadable file systems. */ @@ -154,5 +159,7 @@ __END_DECLS #define UBC_FLAGS_NONE 0x0000 #define UBC_HOLDOBJECT 0x0001 +#endif /* __APPLE_API_EVOLVING */ + #endif /* _SYS_UBC_H_ */ diff --git a/bsd/sys/ucontext.h b/bsd/sys/ucontext.h new file mode 100644 index 000000000..e66df1e4c --- /dev/null +++ b/bsd/sys/ucontext.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#ifndef _SYS_UCONTEXT_H_ +#define _SYS_UCONTEXT_H_ + +#include + +struct ucontext { + int uc_onstack; + sigset_t uc_sigmask; /* signal mask used by this context */ + stack_t uc_stack; /* stack used by this context */ + struct ucontext *uc_link; /* pointer to resuming context */ + size_t uc_mcsize; /* size of the machine context passed in */ + mcontext_t uc_mcontext; /* machine specific context */ +}; + +typedef struct ucontext ucontext_t; + +#endif /* _SYS_UCONTEXT_H_ */ diff --git a/bsd/sys/ucred.h b/bsd/sys/ucred.h index 751d9151b..0c5032116 100644 --- a/bsd/sys/ucred.h +++ b/bsd/sys/ucred.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -58,8 +58,10 @@ #ifndef _SYS_UCRED_H_ #define _SYS_UCRED_H_ +#include #include +#ifdef __APPLE_API_UNSTABLE /* * Credentials. */ @@ -85,6 +87,8 @@ struct ucred *crdup __P((struct ucred *cr)); void crfree __P((struct ucred *cr)); struct ucred *crget __P((void)); int suser __P((struct ucred *cred, u_short *acflag)); + #endif /* KERNEL */ +#endif /* __APPLE_API_UNSTABLE */ #endif /* !_SYS_UCRED_H_ */ diff --git a/bsd/sys/un.h b/bsd/sys/un.h index 5cb13ac75..e3e4cdb5c 100644 --- a/bsd/sys/un.h +++ b/bsd/sys/un.h @@ -57,6 +57,8 @@ #ifndef _SYS_UN_H_ #define _SYS_UN_H_ +#include + /* * Definitions for UNIX IPC domain. */ @@ -67,6 +69,7 @@ struct sockaddr_un { }; #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE struct mbuf; struct socket; @@ -77,6 +80,7 @@ void unp_dispose __P((struct mbuf *m)); int unp_externalize __P((struct mbuf *rights)); void unp_init __P((void)); extern struct pr_usrreqs uipc_usrreqs; +#endif /* __APPLE_API_PRIVATE */ #else /* !KERNEL */ /* actual length of an initialized sockaddr_un */ diff --git a/bsd/sys/unpcb.h b/bsd/sys/unpcb.h index bd22c6bee..408cc93d1 100644 --- a/bsd/sys/unpcb.h +++ b/bsd/sys/unpcb.h @@ -57,6 +57,7 @@ #ifndef _SYS_UNPCB_H_ #define _SYS_UNPCB_H_ +#include #include #include @@ -85,6 +86,7 @@ * so that changes in the sockbuf may be computed to modify * back pressure on the sender accordingly. */ +#ifdef __APPLE_API_PRIVATE typedef u_quad_t unp_gen_t; LIST_HEAD(unp_head, unpcb); @@ -103,9 +105,11 @@ struct unpcb { }; #define sotounpcb(so) ((struct unpcb *)((so)->so_pcb)) +#endif /* __APPLE_API_PRIVATE */ /* Hack alert -- this structure depends on . */ #ifdef _SYS_SOCKETVAR_H_ +#ifdef __APPLE_API_UNSTABLE struct xunpcb { size_t xu_len; /* length of this structure */ struct unpcb *xu_unpp; /* to help netstat, fstat */ @@ -130,6 +134,7 @@ struct xunpgen { unp_gen_t xug_gen; so_gen_t xug_sogen; }; +#endif /* __APPLE_API_UNSTABLE */ #endif /* _SYS_SOCKETVAR_H_ */ #endif /* _SYS_UNPCB_H_ */ diff --git a/bsd/sys/user.h b/bsd/sys/user.h index 066d3c8b4..a9c3a236c 100644 --- a/bsd/sys/user.h +++ b/bsd/sys/user.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -58,6 +58,7 @@ #ifndef _SYS_USER_H_ #define _SYS_USER_H_ +#include #ifndef KERNEL /* stuff that *used* to be included by user.h, or is now needed */ #include @@ -72,14 +73,10 @@ #include #ifdef KERNEL + +#ifdef __APPLE_API_PRIVATE /* * Per-thread U area. - * - * It is likely that this structure contains no fields that must be - * saved between system calls. - * - * WARNING: IF THE SIZE OF THIS STRUCT CHANGES YOU MUST CHANGE THE - * CONSTANT IN struct thread_act.bsd_space */ struct uthread { int *uu_ar0; /* address of users saved R0 */ @@ -92,15 +89,14 @@ struct uthread { /* thread exception handling */ int uu_code; /* ``code'' to trap */ char uu_cursig; /* p_cursig for exc. */ - int uu_sig; /* p_sig for exc. */ - + int XXX_dummy; /* NOT USED LEFT FOR COMPATIBILITY. */ /* support for syscalls which use continuations */ union { struct _select { u_int32_t *ibits, *obits; /* bits to select on */ uint nbytes; /* number of bytes in ibits and obits */ - struct timeval atv; - int poll; + u_int64_t abstime; + int poll; int error; int count; int nfcount; @@ -127,9 +123,26 @@ struct uthread { struct proc * uu_proc; void * uu_userstate; wait_queue_sub_t uu_wqsub; + sigset_t uu_siglist; /* signals pending for the thread */ + sigset_t uu_sigwait; /* sigwait on this thread*/ + sigset_t uu_sigmask; /* signal mask for the thread */ + sigset_t uu_oldmask; /* signal mask saved before sigpause */ + thread_act_t uu_act; + sigset_t uu_vforkmask; /* saved signal mask during vfork */ + + TAILQ_ENTRY(uthread) uu_list; /* List of uthreads in proc */ }; typedef struct uthread * uthread_t; + +/* Definition of uu_flag */ +#define USAS_OLDMASK 0x1 /* need to restore mask before pause */ +#define UNO_SIGMASK 0x2 /* exited thread; invalid sigmask */ +/* Kept same as in proc */ +#define P_VFORK 0x2000000 /* process has vfork children */ + +#endif /* __APPLE_API_PRIVATE */ + #endif /* KERNEL */ /* diff --git a/bsd/sys/utfconv.h b/bsd/sys/utfconv.h index f70f42490..0af9b52f4 100644 --- a/bsd/sys/utfconv.h +++ b/bsd/sys/utfconv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -23,7 +23,10 @@ #ifndef _SYS_UTFCONV_H_ #define _SYS_UTFCONV_H_ +#include + #ifdef KERNEL +#ifdef __APPLE_API_UNSTABLE /* * UTF-8 encode/decode flags */ @@ -42,6 +45,7 @@ int utf8_decodestr __P((const u_int8_t *, size_t, u_int16_t *,size_t *, size_t, u_int16_t, int)); __END_DECLS +#endif /* __APPLE_API_UNSTABLE */ #endif /* KERNEL */ #endif /* !_SYS_UTFCONV_H_ */ diff --git a/bsd/sys/ux_exception.h b/bsd/sys/ux_exception.h index 493834456..2b55b6cb5 100644 --- a/bsd/sys/ux_exception.h +++ b/bsd/sys/ux_exception.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -27,40 +27,6 @@ * All rights reserved. The CMU software License Agreement specifies * the terms and conditions for use and redistribution. */ -/* - * HISTORY - * - * Revision 1.2.32.1 1998/11/11 21:54:39 aramesh - * Atlas merge - * - * Revision 1.1.1.1 1997/09/30 02:42:22 wsanchez - * Import of kernel from umeshv/kernel - * - * Revision 2.7 89/10/03 19:23:14 rpd - * Change from NeXT: added EXC_UNIX_ABORT. - * [89/08/20 23:16:13 rpd] - * - * Revision 2.6 89/03/09 19:35:07 rpd - * More cleanup. - * - * Revision 2.5 89/02/25 15:01:07 gm0w - * Changes for cleanup. - * - * Revision 2.4 89/02/07 01:01:10 mwyoung - * Relocated from uxkern/ux_exception.h - * - * Revision 2.3 89/01/15 16:35:44 rpd - * Use decl_simple_lock_data. - * [89/01/15 15:19:58 rpd] - * - * Revision 2.2 88/08/24 02:52:12 mwyoung - * Adjusted include file references. - * [88/08/17 02:27:27 mwyoung] - * - * 29-Sep-87 David Black (dlb) at Carnegie-Mellon University - * Created. - * - */ /* * Codes for Unix software exceptions under EXC_SOFTWARE. @@ -69,13 +35,20 @@ #ifndef _SYS_UX_EXCEPTION_H_ #define _SYS_UX_EXCEPTION_H_ +#include + +#ifdef __APPLE_API_UNSTABLE + #define EXC_UNIX_BAD_SYSCALL 0x10000 /* SIGSYS */ #define EXC_UNIX_BAD_PIPE 0x10001 /* SIGPIPE */ #define EXC_UNIX_ABORT 0x10002 /* SIGABRT */ +#endif /* __APPLE_API_UNSTABLE */ + #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE /* * Kernel data structures for Unix exception handler. */ @@ -84,6 +57,7 @@ extern mach_port_name_t ux_exception_port; +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ #endif /* _SYS_UX_EXCEPTION_H_ */ diff --git a/bsd/sys/vadvise.h b/bsd/sys/vadvise.h index 81c1cee89..09ee127ca 100644 --- a/bsd/sys/vadvise.h +++ b/bsd/sys/vadvise.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -59,6 +59,9 @@ #ifndef _SYS_VADVISE_H_ #define _SYS_VADVISE_H_ +#include + +#ifdef __APPLE_API_OBSOLETE /* * Parameters to vadvise() to tell system of particular paging * behaviour: @@ -74,4 +77,6 @@ #define VA_SEQL 2 #define VA_FLUSH 3 +#endif /* __APPLE_API_OBSOLETE */ + #endif /* !_SYS_VADVISE_H_ */ diff --git a/bsd/sys/vm.h b/bsd/sys/vm.h index 2bb8a30f3..1718e1369 100644 --- a/bsd/sys/vm.h +++ b/bsd/sys/vm.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -62,6 +62,8 @@ #ifndef _SYS_VM_H #define _SYS_VM_H +#include + /* Machine specific config stuff */ #if defined(KERNEL) && !defined(MACH_USER_API) #include @@ -69,6 +71,7 @@ #include #endif +#ifdef __APPLE_API_OBSOLETE /* * Shareable process virtual address space. * May eventually be merged with vm_map. @@ -89,11 +92,20 @@ struct vmspace { caddr_t vm_maxsaddr; /* user VA at max stack growth */ }; +#else /* __APPLE_API_OBSOLETE */ +/* just to keep kinfo_proc happy */ +struct vmspace { + int32_t dummy[10]; +}; +#endif /* __APPLE_API_OBSOLETE */ + #ifdef KERNEL +#ifdef __APPLE_API_PRIVATE #ifdef BSD_BUILD #include #endif /* BSD_BUILD */ +#endif /* __APPLE_API_PRIVATE */ struct proc *current_proc(void); diff --git a/bsd/sys/vmmeter.h b/bsd/sys/vmmeter.h index dba664e8e..0564670bc 100644 --- a/bsd/sys/vmmeter.h +++ b/bsd/sys/vmmeter.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -58,6 +58,9 @@ #ifndef _SYS_VMMETER_H_ #define _SYS_VMMETER_H_ +#include + +#ifdef __APPLE_API_OBSOLETE /* * System wide statistics counters. */ @@ -133,4 +136,6 @@ struct vmtotal extern struct vmtotal total; #endif +#endif /*__APPLE_API_OBSOLETE */ + #endif /* !_SYS_VMMETER_H_ */ diff --git a/bsd/sys/vnioctl.h b/bsd/sys/vnioctl.h new file mode 100644 index 000000000..6e8e15e8c --- /dev/null +++ b/bsd/sys/vnioctl.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1990, 1993 + * 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: fdioctl.h 1.1 90/07/09$ + * + * @(#)vnioctl.h 8.1 (Berkeley) 6/10/93 + * + * $FreeBSD: src/sys/sys/vnioctl.h,v 1.4 1999/09/17 05:33:58 dillon Exp $ + */ + +#ifndef _SYS_VNIOCTL_H_ +#define _SYS_VNIOCTL_H_ + +#include + +#ifdef KERNEL_PRIVATE + +#ifdef __APPLE_API_PRIVATE +/* + * Ioctl definitions for file (vnode) disk pseudo-device. + */ + +#define _PATH_VNTAB "/etc/vntab" /* default config file */ + +typedef enum { + vncontrol_readwrite_io_e = 0, +} vncontrol_t; + +struct vn_ioctl { + char * vn_file; /* pathname of file to mount */ + int vn_size; /* (returned) size of disk */ + vncontrol_t vn_control; +}; + +/* + * Before you can use a unit, it must be configured with VNIOCSET. + * The configuration persists across opens and closes of the device; + * an VNIOCCLR must be used to reset a configuration. An attempt to + * VNIOCSET an already active unit will return EBUSY. + */ +#define VNIOCATTACH _IOWR('F', 0, struct vn_ioctl) /* attach file */ +#define VNIOCDETACH _IOWR('F', 1, struct vn_ioctl) /* detach disk */ +#define VNIOCGSET _IOWR('F', 2, u_long ) /* set global option */ +#define VNIOCGCLEAR _IOWR('F', 3, u_long ) /* reset --//-- */ +#define VNIOCUSET _IOWR('F', 4, u_long ) /* set unit option */ +#define VNIOCUCLEAR _IOWR('F', 5, u_long ) /* reset --//-- */ +#define VNIOCSHADOW _IOWR('F', 6, struct vn_ioctl) /* attach shadow */ + +#define VN_LABELS 0x1 /* Use disk(/slice) labels */ +#define VN_FOLLOW 0x2 /* Debug flow in vn driver */ +#define VN_DEBUG 0x4 /* Debug data in vn driver */ +#define VN_IO 0x8 /* Debug I/O in vn driver */ +#define VN_DONTCLUSTER 0x10 /* Don't cluster */ +#define VN_RESERVE 0x20 /* Pre-reserve swap */ + +#endif /* __APPLE_API_PRIVATE */ + +#endif KERNEL_PRIVATE + +#endif /* _SYS_VNIOCTL_H_*/ diff --git a/bsd/sys/vnode.h b/bsd/sys/vnode.h index 000f1cf5c..5023c875c 100644 --- a/bsd/sys/vnode.h +++ b/bsd/sys/vnode.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -58,6 +58,7 @@ #ifndef _VNODE_H_ #define _VNODE_H_ +#include #include #include #include @@ -69,8 +70,9 @@ #ifdef KERNEL #include #include -#endif +#endif /* KERNEL */ +#ifdef __APPLE_API_PRIVATE /* * The vnode is the focus of all file activity in UNIX. There is a * unique vnode allocated for each active file, each current directory, @@ -100,12 +102,24 @@ enum vtagtype { */ LIST_HEAD(buflists, buf); +#define MAX_CLUSTERS 4 /* maximum number of vfs clusters per vnode */ + +struct v_cluster { + unsigned int start_pg; + unsigned int last_pg; +}; + +struct v_padded_clusters { + long v_pad; + struct v_cluster v_c[MAX_CLUSTERS]; +}; + /* * Reading or writing any of these items requires holding the appropriate lock. * v_freelist is locked by the global vnode_free_list simple lock. * v_mntvnodes is locked by the global mntvnodes simple lock. * v_flag, v_usecount, v_holdcount and v_writecount are - * locked by the v_interlock simple lock. + * locked by the v_interlock simple lock. */ struct vnode { u_long v_flag; /* vnode flags (see below) */ @@ -135,7 +149,13 @@ struct vnode { int v_clen; /* length of current cluster */ int v_ralen; /* Read-ahead length */ daddr_t v_maxra; /* last readahead block */ - simple_lock_data_t v_interlock; /* lock on usecount and flag */ + union { + simple_lock_data_t v_ilk; /* lock on usecount and flag */ + struct v_padded_clusters v_cl; /* vfs cluster IO */ + } v_un1; +#define v_clusters v_un1.v_cl.v_c +#define v_interlock v_un1.v_ilk + struct lock__bsd__ *v_vnlock; /* used for non-locking fs's */ long v_writecount; /* reference count of writers */ enum vtagtype v_tag; /* type of underlying data */ @@ -172,8 +192,10 @@ struct vnode { #define VHASDIRTY 0x100000 /* UBC vnode may have 1 or more */ /* delayed dirty pages that need to be flushed at the next 'sync' */ #define VSWAP 0x200000 /* vnode is being used as swapfile */ -#define VTHROTTLED 0x400000 /* writes or pageouts have been throttled */ - /* wakeup tasks waiting when count falls below threshold */ +#define VTHROTTLED 0x400000 /* writes or pageouts have been throttled */ + /* wakeup tasks waiting when count falls below threshold */ +#define VNOFLUSH 0x800000 /* don't vflush() if SKIPSYSTEM */ + /* * Vnode attributes. A field value of VNOVAL represents a field whose value @@ -215,10 +237,11 @@ struct vattr { #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 */ -#define IO_NOZEROFILL 0x20 /* F_SETSIZE fcntl uses to prevent zero filling */ -#define IO_TAILZEROFILL 0x40 /* zero fills at the tail of write */ -#define IO_HEADZEROFILL 0x80 /* zero fills at the head of write */ -#define IO_NOZEROVALID 0x100 /* do not zero fill if valid page */ +#define IO_NOZEROFILL 0x20 /* F_SETSIZE fcntl uses to prevent zero filling */ +#define IO_TAILZEROFILL 0x40 /* zero fills at the tail of write */ +#define IO_HEADZEROFILL 0x80 /* zero fills at the head of write */ +#define IO_NOZEROVALID 0x100 /* do not zero fill if valid page */ +#define IO_NOZERODIRTY 0x200 /* do not zero fill if page is dirty */ /* * Modes. Some values same as Ixxx entries from inode.h for now. @@ -314,7 +337,6 @@ extern struct vattr va_null; /* predefined null vattr structure */ */ #define LEASE_READ 0x1 /* Check lease for readers */ #define LEASE_WRITE 0x2 /* Check lease for modifiers */ - #endif /* KERNEL */ /* @@ -366,7 +388,11 @@ struct vnodeop_desc { caddr_t *vdesc_transports; }; +#endif /* __APPLE_API_PRIVATE */ + #ifdef KERNEL + +#ifdef __APPLE_API_PRIVATE /* * A list of all the operation descs. */ @@ -433,13 +459,15 @@ struct vop_generic_args { #define VDESC(OP) (& __CONCAT(OP,_desc)) #define VOFFSET(OP) (VDESC(OP)->vdesc_offset) +#endif /* __APPLE_API_PRIVATE */ + /* * Finally, include the default set of vnode operations. */ #include /* - * Public vnode manipulation functions. + * vnode manipulation functions. */ struct file; struct mount; @@ -453,6 +481,7 @@ struct vattr; struct vnode; struct vop_bwrite_args; +#ifdef __APPLE_API_EVOLVING int bdevvp __P((dev_t dev, struct vnode **vpp)); void cvtstat __P((struct stat *st, struct ostat *ost)); int getnewvnode __P((enum vtagtype tag, @@ -471,18 +500,12 @@ int vrecycle __P((struct vnode *vp, struct slock *inter_lkp, int vn_bwrite __P((struct vop_bwrite_args *ap)); int vn_close __P((struct vnode *vp, int flags, struct ucred *cred, struct proc *p)); -int vn_closefile __P((struct file *fp, struct proc *p)); -int vn_ioctl __P((struct file *fp, u_long com, caddr_t data, - struct proc *p)); int vn_lock __P((struct vnode *vp, int flags, struct proc *p)); int vn_open __P((struct nameidata *ndp, int fmode, int cmode)); 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_select __P((struct file *fp, int which, void * wql, struct proc *p)); int vn_stat __P((struct vnode *vp, struct stat *sb, struct proc *p)); -int vn_write __P((struct file *fp, struct uio *uio, struct ucred *cred)); int vop_noislocked __P((struct vop_islocked_args *)); int vop_nolock __P((struct vop_lock_args *)); int vop_nounlock __P((struct vop_unlock_args *)); @@ -494,6 +517,7 @@ void vrele __P((struct vnode *vp)); int vaccess __P((mode_t file_mode, uid_t uid, gid_t gid, mode_t acc_mode, struct ucred *cred)); int getvnode __P((struct proc *p, int fd, struct file **fpp)); +#endif __APPLE_API_EVOLVING #endif /* KERNEL */ diff --git a/bsd/sys/vnode_if.h b/bsd/sys/vnode_if.h index ec4dafa03..5c7ae1a39 100644 --- a/bsd/sys/vnode_if.h +++ b/bsd/sys/vnode_if.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -64,9 +64,12 @@ */ -#ifndef _VNODE_IF_H_ -#define _VNODE_IF_H_ +#ifndef _SYS_VNODE_IF_H_ +#define _SYS_VNODE_IF_H_ +#include + +#ifdef __APPLE_API_UNSTABLE extern struct vnodeop_desc vop_default_desc; @@ -349,8 +352,8 @@ static __inline int _VOP_READ(struct vnode *vp, struct uio *uio, int ioflag, str a.a_cred = cred; { int _err; - extern int ubc_hold(); - extern void ubc_rele(); + extern int ubc_hold(struct vnode *vp); + extern void ubc_rele(struct vnode *vp); int _didhold = ubc_hold(vp); _err = VCALL(vp, VOFFSET(vop_read), &a); if (_didhold) @@ -378,8 +381,8 @@ static __inline int _VOP_WRITE(struct vnode *vp, struct uio *uio, int ioflag, st a.a_cred = cred; { int _err; - extern int ubc_hold(); - extern void ubc_rele(); + extern int ubc_hold(struct vnode *vp); + extern void ubc_rele(struct vnode *vp); int _didhold = ubc_hold(vp); _err = VCALL(vp, VOFFSET(vop_write), &a); if (_didhold) @@ -438,12 +441,12 @@ struct vop_select_args { int a_which; int a_fflags; struct ucred *a_cred; - void * a_wql; + void *a_wql; struct proc *a_p; }; extern struct vnodeop_desc vop_select_desc; #define VOP_SELECT(vp, which, fflags, cred, wql, p) _VOP_SELECT(vp, which, fflags, cred, wql, p) -static __inline int _VOP_SELECT(struct vnode *vp, int which, int fflags, struct ucred *cred, void * wql, struct proc *p) +static __inline int _VOP_SELECT(struct vnode *vp, int which, int fflags, struct ucred *cred, void *wql, struct proc *p) { struct vop_select_args a; a.a_desc = VDESC(vop_select); @@ -531,8 +534,8 @@ static __inline int _VOP_FSYNC(struct vnode *vp, struct ucred *cred, int waitfor a.a_p = p; { int _err; - extern int ubc_hold(); - extern void ubc_rele(); + extern int ubc_hold(struct vnode *vp); + extern void ubc_rele(struct vnode *vp); int _didhold = ubc_hold(vp); _err = VCALL(vp, VOFFSET(vop_fsync), &a); if (_didhold) @@ -1024,8 +1027,8 @@ static __inline int _VOP_TRUNCATE(struct vnode *vp, off_t length, int flags, str a.a_p = p; { int _err; - extern int ubc_hold(); - extern void ubc_rele(); + extern int ubc_hold(struct vnode *vp); + extern void ubc_rele(struct vnode *vp); int _didhold = ubc_hold(vp); _err = VCALL(vp, VOFFSET(vop_truncate), &a); if (_didhold) @@ -1340,4 +1343,5 @@ static __inline int _VOP_BWRITE(struct buf *bp) /* End of special cases. */ -#endif /* !_VNODE_IF_H_ */ +#endif /* __APPLE_API_UNSTABLE */ +#endif /* !_SYS_VNODE_IF_H_ */ diff --git a/bsd/sys/vstat.h b/bsd/sys/vstat.h index 0d8e745a3..83b87ed23 100644 --- a/bsd/sys/vstat.h +++ b/bsd/sys/vstat.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -23,14 +23,16 @@ /*- * @(#)vstat.h */ -/* HISTORY - * 01-27-98 chw at Apple Computer, Inc. - * Created. - */ #ifndef _SYS_VSTAT_H_ #define _SYS_VSTAT_H_ +#include + +#warning obsolete header! delete the include from your sources + +#ifdef __APPLE_API_OBSOLETE + #include #include @@ -39,7 +41,7 @@ struct vstat { fsid_t vst_volid; /* volume identifier */ fsobj_id_t vst_nodeid; /* object's id */ - fsobj_type_t vst_vnodetype; /* vnode type (VREG, VCPLX, VDIR, etc.) */ + fsobj_type_t vst_vnodetype; /* vnode type (VREG, VDIR, etc.) */ fsobj_tag_t vst_vnodetag; /* vnode tag (HFS, UFS, etc.) */ mode_t vst_mode; /* inode protection mode */ nlink_t vst_nlink; /* number of hard links */ @@ -66,5 +68,6 @@ struct vstat { }; #endif /* ! _POSIX_SOURCE */ +#endif /* __APPLE_API_OBSOLETE */ #endif /* !_SYS_VSTAT_H_ */ diff --git a/bsd/ufs/ffs/ffs_alloc.c b/bsd/ufs/ffs/ffs_alloc.c index c6e462097..f14ac29f9 100644 --- a/bsd/ufs/ffs/ffs_alloc.c +++ b/bsd/ufs/ffs/ffs_alloc.c @@ -65,6 +65,7 @@ #include #include #include +#include #include @@ -141,7 +142,7 @@ ffs_alloc(ip, lbn, bpref, size, cred, bnp) goto nospace; VOP_DEVBLOCKSIZE(ip->i_devvp,&devBlockSize); #if QUOTA - if (error = chkdq(ip, (long)btodb(size, devBlockSize), cred, 0)) + if (error = chkdq(ip, (int64_t)size, cred, 0)) return (error); #endif /* QUOTA */ if (bpref >= fs->fs_size) @@ -162,7 +163,7 @@ ffs_alloc(ip, lbn, bpref, size, cred, bnp) /* * Restore user's disk quota because allocation failed. */ - (void) chkdq(ip, (long)-btodb(size, devBlockSize), cred, FORCE); + (void) chkdq(ip, (int64_t)-size, cred, FORCE); #endif /* QUOTA */ nospace: ffs_fserr(fs, cred->cr_uid, "file system full"); @@ -222,7 +223,7 @@ ffs_realloccg(ip, lbprev, bpref, osize, nsize, cred, bpp) VOP_DEVBLOCKSIZE(ip->i_devvp,&devBlockSize); #if QUOTA - if (error = chkdq(ip, (long)btodb(nsize - osize, devBlockSize), cred, 0)) + if (error = chkdq(ip, (int64_t)(nsize - osize), cred, 0)) { brelse(bp); return (error); @@ -311,7 +312,7 @@ ffs_realloccg(ip, lbprev, bpref, osize, nsize, cred, bpp) /* * Restore user's disk quota because allocation failed. */ - (void) chkdq(ip, (long)-btodb(nsize - osize, devBlockSize), cred, FORCE); + (void) chkdq(ip, (int64_t)-(nsize - osize), cred, FORCE); #endif /* QUOTA */ brelse(bp); nospace: diff --git a/bsd/ufs/ffs/ffs_balloc.c b/bsd/ufs/ffs/ffs_balloc.c index a6c61ac8c..38cf2b72a 100644 --- a/bsd/ufs/ffs/ffs_balloc.c +++ b/bsd/ufs/ffs/ffs_balloc.c @@ -63,6 +63,8 @@ #include #include #include +#include + #if REV_ENDIAN_FS #include #endif /* REV_ENDIAN_FS */ @@ -421,7 +423,7 @@ fail: /* * Restore user's disk quota because allocation failed. */ - (void) chkdq(ip, (long)-btodb(deallocated, devBlockSize), cred, FORCE); + (void) chkdq(ip, (int64_t)-deallocated, cred, FORCE); #endif /* QUOTA */ ip->i_blocks -= btodb(deallocated, devBlockSize); ip->i_flag |= IN_CHANGE | IN_UPDATE; @@ -666,7 +668,7 @@ fail: /* * Restore user's disk quota because allocation failed. */ - (void) chkdq(ip, (long)-btodb(deallocated, devBlockSize), cred, FORCE); + (void) chkdq(ip, (int64_t)-deallocated, cred, FORCE); #endif /* QUOTA */ ip->i_blocks -= btodb(deallocated, devBlockSize); ip->i_flag |= IN_CHANGE | IN_UPDATE; diff --git a/bsd/ufs/ffs/ffs_extern.h b/bsd/ufs/ffs/ffs_extern.h index c4e660c43..635f8cb32 100644 --- a/bsd/ufs/ffs/ffs_extern.h +++ b/bsd/ufs/ffs/ffs_extern.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -55,7 +55,12 @@ * * @(#)ffs_extern.h 8.6 (Berkeley) 3/30/95 */ +#ifndef __UFS_FFS_FFS_EXTERN_H__ +#define __UFS_FFS_FFS_EXTERN_H__ +#include + +#ifdef __APPLE_API_UNSTABLE /* * Sysctl values for the fast filesystem. */ @@ -72,6 +77,7 @@ { "doreallocblks", CTLTYPE_INT }, \ { "doasyncfree", CTLTYPE_INT }, \ } +#endif /* __APPLE_API_UNSTABLE */ struct buf; struct fid; @@ -88,6 +94,7 @@ struct vnode; struct mbuf; struct vfsconf; +#ifdef __APPLE_API_PRIVATE __BEGIN_DECLS int ffs_alloc __P((struct inode *, ufs_daddr_t, ufs_daddr_t, int, struct ucred *, ufs_daddr_t *)); @@ -144,3 +151,6 @@ extern int (**ffs_fifoop_p)(void *); #else #define FFS_FIFOOPS NULL #endif + +#endif /* __APPLE_API_PRIVATE */ +#endif /* __UFS_FFS_FFS_EXTERN_H__ */ diff --git a/bsd/ufs/ffs/ffs_inode.c b/bsd/ufs/ffs/ffs_inode.c index 3b7b72985..d4f2c7bde 100644 --- a/bsd/ufs/ffs/ffs_inode.c +++ b/bsd/ufs/ffs/ffs_inode.c @@ -70,6 +70,7 @@ #include #include #include +#include #include @@ -199,6 +200,9 @@ ffs_truncate(ap) int aflags, error, allerror; off_t osize; int devBlockSize=0; +#if QUOTA + int64_t change; /* in bytes */ +#endif /* QUOTA */ if (length < 0) return (EINVAL); @@ -432,7 +436,8 @@ done: oip->i_blocks = 0; oip->i_flag |= IN_CHANGE; #if QUOTA - (void) chkdq(oip, -blocksreleased, NOCRED, 0); + change = dbtob((int64_t)blocksreleased,devBlockSize); + (void) chkdq(oip, -change, NOCRED, 0); #endif return (allerror); } diff --git a/bsd/ufs/ffs/ffs_subr.c b/bsd/ufs/ffs/ffs_subr.c index 2431d8d2b..c023a273d 100644 --- a/bsd/ufs/ffs/ffs_subr.c +++ b/bsd/ufs/ffs/ffs_subr.c @@ -69,6 +69,7 @@ #include #include #include +#include #include #include #include diff --git a/bsd/ufs/ffs/ffs_vfsops.c b/bsd/ufs/ffs/ffs_vfsops.c index 7da3b2a3e..e91a041f7 100644 --- a/bsd/ufs/ffs/ffs_vfsops.c +++ b/bsd/ufs/ffs/ffs_vfsops.c @@ -72,6 +72,7 @@ #include #include #include +#include #include @@ -126,8 +127,10 @@ ffs_mountroot() printf("ffs_mountroot: can't setup bdevvp"); return (error); } - if (error = vfs_rootmountalloc("ufs", "root_device", &mp)) + if (error = vfs_rootmountalloc("ufs", "root_device", &mp)) { + vrele(rootvp); /* release the reference from bdevvp() */ return (error); + } /* Must set the MNT_ROOTFS flag before doing the actual mount */ mp->mnt_flag |= MNT_ROOTFS; @@ -135,6 +138,7 @@ ffs_mountroot() if (error = ffs_mountfs(rootvp, mp, p)) { mp->mnt_vfc->vfc_refcount--; vfs_unbusy(mp, p); + vrele(rootvp); /* release the reference from bdevvp() */ _FREE_ZONE(mp, sizeof (struct mount), M_MOUNT); return (error); } @@ -325,7 +329,7 @@ ffs_reload(mountp, cred, p) { register struct vnode *vp, *nvp, *devvp; struct inode *ip; - struct csum *space; + void *space; struct buf *bp; struct fs *fs, *newfs; int i, blks, size, error; @@ -374,7 +378,7 @@ ffs_reload(mountp, cred, p) * new superblock. These should really be in the ufsmount. XXX * Note that important parameters (eg fs_ncg) are unchanged. */ - bcopy(&fs->fs_csp[0], &newfs->fs_csp[0], sizeof(fs->fs_csp)); + newfs->fs_csp = fs->fs_csp; newfs->fs_maxcluster = fs->fs_maxcluster; bcopy(newfs, fs, (u_int)fs->fs_sbsize); if (fs->fs_sbsize < SBSIZE) @@ -393,7 +397,7 @@ ffs_reload(mountp, cred, p) * Step 3: re-read summary information from disk. */ blks = howmany(fs->fs_cssize, fs->fs_fsize); - space = fs->fs_csp[0]; + space = fs->fs_csp; for (i = 0; i < blks; i += fs->fs_frag) { size = fs->fs_bsize; if (i + fs->fs_frag > blks) @@ -409,7 +413,7 @@ ffs_reload(mountp, cred, p) byte_swap_ints((int *)bp->b_data, size / sizeof(int)); } #endif /* REV_ENDIAN_FS */ - bcopy(bp->b_data, fs->fs_csp[fragstoblks(fs, i)], (u_int)size); + bcopy(bp->b_data, space, (u_int)size); #if REV_ENDIAN_FS if (rev_endian) { /* csum swaps */ @@ -496,7 +500,7 @@ ffs_mountfs(devvp, mp, p) struct buf *cgbp; struct cg *cgp; int32_t clustersumoff; - caddr_t base, space; + void *space; int error, i, blks, size, ronly; int32_t *lp; struct ucred *cred; @@ -683,15 +687,15 @@ ffs_mountfs(devvp, mp, p) blks = howmany(size, fs->fs_fsize); if (fs->fs_contigsumsize > 0) size += fs->fs_ncg * sizeof(int32_t); - base = space = _MALLOC((u_long)size, M_UFSMNT, M_WAITOK); - base = space; + space = _MALLOC((u_long)size, M_UFSMNT, M_WAITOK); + fs->fs_csp = space; for (i = 0; i < blks; i += fs->fs_frag) { size = fs->fs_bsize; if (i + fs->fs_frag > blks) size = (blks - i) * fs->fs_fsize; if (error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, cred, &bp)) { - _FREE(base, M_UFSMNT); + _FREE(fs->fs_csp, M_UFSMNT); goto out; } bcopy(bp->b_data, space, (u_int)size); @@ -699,13 +703,12 @@ ffs_mountfs(devvp, mp, p) if (rev_endian) byte_swap_ints((int *) space, size / sizeof(int)); #endif /* REV_ENDIAN_FS */ - fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; - space += size; + space = (char *)space + size; brelse(bp); bp = NULL; } if (fs->fs_contigsumsize > 0) { - fs->fs_maxcluster = lp = (int32_t *)space; + fs->fs_maxcluster = lp = space; for (i = 0; i < fs->fs_ncg; i++) *lp++ = fs->fs_contigsumsize; } @@ -725,7 +728,7 @@ ffs_mountfs(devvp, mp, p) ump->um_bptrtodb = fs->fs_fsbtodb; ump->um_seqinc = fs->fs_frag; for (i = 0; i < MAXQUOTAS; i++) - ump->um_quotas[i] = NULLVP; + ump->um_qfiles[i].qf_vp = NULLVP; devvp->v_specflags |= SI_MOUNTEDON; ffs_oldfscompat(fs); ump->um_savedmaxfilesize = fs->fs_maxfilesize; /* XXX */ @@ -792,10 +795,15 @@ ffs_unmount(mp, mntflags, p) register struct ufsmount *ump; register struct fs *fs; int error, flags; + int force; + flags = 0; - if (mntflags & MNT_FORCE) + force = 0; + if (mntflags & MNT_FORCE) { flags |= FORCECLOSE; - if (error = ffs_flushfiles(mp, flags, p)) + force = 1; + } + if ( (error = ffs_flushfiles(mp, flags, p)) && !force ) return (error); ump = VFSTOUFS(mp); fs = ump->um_fs; @@ -816,16 +824,18 @@ ffs_unmount(mp, mntflags, p) ump->um_devvp->v_specflags &= ~SI_MOUNTEDON; error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE, NOCRED, p); + if (error && !force) + return (error); vrele(ump->um_devvp); - _FREE(fs->fs_csp[0], M_UFSMNT); + _FREE(fs->fs_csp, M_UFSMNT); _FREE(fs, M_UFSMNT); _FREE(ump, M_UFSMNT); mp->mnt_data = (qaddr_t)0; #if REV_ENDIAN_FS mp->mnt_flag &= ~MNT_REVEND; #endif /* REV_ENDIAN_FS */ - return (error); + return (0); } /* @@ -845,7 +855,7 @@ ffs_flushfiles(mp, flags, p) if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags)) return (error); for (i = 0; i < MAXQUOTAS; i++) { - if (ump->um_quotas[i] == NULLVP) + if (ump->um_qfiles[i].qf_vp == NULLVP) continue; quotaoff(p, mp, i); } @@ -1244,7 +1254,7 @@ ffs_sbupdate(mp, waitfor) register struct fs *dfs, *fs = mp->um_fs; register struct buf *bp; int blks; - caddr_t space; + void *space; int i, size, error, allerror = 0; int devBlockSize=0; #if REV_ENDIAN_FS @@ -1255,7 +1265,7 @@ ffs_sbupdate(mp, waitfor) * First write back the summary information. */ blks = howmany(fs->fs_cssize, fs->fs_fsize); - space = (caddr_t)fs->fs_csp[0]; + space = fs->fs_csp; for (i = 0; i < blks; i += fs->fs_frag) { size = fs->fs_bsize; if (i + fs->fs_frag > blks) @@ -1268,7 +1278,7 @@ ffs_sbupdate(mp, waitfor) byte_swap_ints((int *)bp->b_data, size / sizeof(int)); } #endif /* REV_ENDIAN_FS */ - space += size; + space = (char *)space + size; if (waitfor != MNT_WAIT) bawrite(bp); else if (error = bwrite(bp)) diff --git a/bsd/ufs/ffs/ffs_vnops.c b/bsd/ufs/ffs/ffs_vnops.c index cf6d5ba4d..9e94eb2bd 100644 --- a/bsd/ufs/ffs/ffs_vnops.c +++ b/bsd/ufs/ffs/ffs_vnops.c @@ -69,6 +69,7 @@ #include #include #include +#include #include #include @@ -295,6 +296,7 @@ ffs_fsync(ap) struct buf *nbp; int s; struct inode *ip = VTOI(vp); + int retry = 0; /* * Write out any clusters. @@ -325,8 +327,6 @@ loop: (void) bwrite(bp); goto loop; } - if (vp->v_flag & VHASDIRTY) - ubc_pushdirty(vp); if (ap->a_waitfor == MNT_WAIT) { while (vp->v_numoutput) { @@ -334,12 +334,25 @@ loop: tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "ffs_fsync", 0); } - /* I have seen this happen for swapfile. So it is safer to - * check for dirty buffers again. --Umesh - */ - if (vp->v_dirtyblkhd.lh_first || (vp->v_flag & VHASDIRTY)) { - vprint("ffs_fsync: dirty", vp); - splx(s); + if (vp->v_dirtyblkhd.lh_first) { + /* still have some dirty buffers */ + if (retry++ > 10) { + vprint("ffs_fsync: dirty", vp); + splx(s); + /* + * Looks like the requests are not + * getting queued to the driver. + * Retrying here causes a cpu bound loop. + * Yield to the other threads and hope + * for the best. + */ + (void)tsleep((caddr_t)&vp->v_numoutput, + PRIBIO + 1, "ffs_fsync", hz/10); + retry = 0; + } else { + splx(s); + } + /* try again */ goto loop; } } diff --git a/bsd/ufs/ffs/fs.h b/bsd/ufs/ffs/fs.h index db4436dac..6af966450 100644 --- a/bsd/ufs/ffs/fs.h +++ b/bsd/ufs/ffs/fs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -57,6 +57,9 @@ #ifndef _FFS_FS_H_ #define _FFS_FS_H_ +#include + +#ifdef __APPLE_API_UNSTABLE /* * Each disk drive contains some number of file systems. * A file system consists of a number of cylinder groups. @@ -132,8 +135,18 @@ * 32-bit pointers, and 1 million on 64-bit machines). One pointer * is taken away to point to an array of cluster sizes that is * computed as cylinder groups are inspected. + * There is a 128-byte region in the superblock reserved for in-core + * pointers to summary information. Originally this included an array + * of pointers to blocks of struct csum; now there are just two + * pointers and the remaining space is padded with fs_ocsp[]. + * + * NOCSPTRS determines the size of this padding. One pointer (fs_csp) + * is taken away to point to a contiguous array of struct csum for + * all cylinder groups; a second (fs_maxcluster) points to an array + * of cluster sizes that is computed as cylinder groups are inspected. */ -#define MAXCSBUFS ((128 / sizeof(void *)) - 1) +#define NOCSPTRS ((128 / sizeof(void *)) - 2) + /* * A summary of contiguous blocks of various sizes is maintained @@ -163,9 +176,6 @@ * 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 { int32_t cs_ndir; /* number of directories */ @@ -209,8 +219,8 @@ struct fs { int32_t fs_fragshift; /* block to frag shift */ int32_t fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */ int32_t fs_sbsize; /* actual size of super block */ - int32_t fs_csmask; /* csum block offset */ - int32_t fs_csshift; /* csum block number */ + int32_t fs_csmask; /* csum block offset (now unused) */ + int32_t fs_csshift; /* csum block number (now unused) */ int32_t fs_nindir; /* value of NINDIR */ int32_t fs_inopb; /* value of INOPB */ int32_t fs_nspf; /* value of NSPF */ @@ -246,7 +256,8 @@ struct fs { u_char fs_fsmnt[MAXMNTLEN]; /* name mounted on */ /* these fields retain the current block allocation info */ int32_t fs_cgrotor; /* last cg searched */ - struct csum *fs_csp[MAXCSBUFS];/* list of fs_cs info buffers */ + void *fs_ocsp[NOCSPTRS]; /* list of fs_cs info buffers */ + struct csum *fs_csp; /* list of fs_cs info buffers */ int32_t *fs_maxcluster; /* max cluster in each cyl group */ int32_t fs_cpc; /* cyl per cycle in postbl */ int16_t fs_opostbl[16][8]; /* old rotation block list head */ @@ -319,8 +330,7 @@ struct fs { * * 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] +#define fs_cs(fs, indx) fs_csp[indx] /* * Cylinder group block for a file system. @@ -527,8 +537,10 @@ struct ocg { */ #define BIG_ENDIAN_FS (__LITTLE_ENDIAN__) +#ifdef __APPLE_API_PRIVATE extern int inside[], around[]; extern u_char *fragtbl[]; +#endif /* __APPLE_API_PRIVATE */ /* @@ -551,8 +563,10 @@ struct ufslabel { u_int32_t ul_time; /* creation time */ u_int16_t ul_namelen; /* filesystem name length */ u_char ul_name[UFS_MAX_LABEL_NAME]; /* filesystem name */ - u_char ul_reserved[32];/* reserved for future use */ + u_int64_t ul_uuid; /* filesystem uuid */ + u_char ul_reserved[24];/* reserved for future use */ u_char ul_unused[460]; /* pad out to 1K */ }; +#endif /* __APPLE_API_UNSTABLE */ #endif /* ! _FFS_FS_H_ */ diff --git a/bsd/ufs/mfs/mfs_extern.h b/bsd/ufs/mfs/mfs_extern.h index b8d270fb8..5d402c2b5 100644 --- a/bsd/ufs/mfs/mfs_extern.h +++ b/bsd/ufs/mfs/mfs_extern.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -54,7 +54,12 @@ * * @(#)mfs_extern.h 8.2 (Berkeley) 6/16/94 */ +#ifndef __UFS_MFS_MFS_EXTERN_H__ +#define __UFS_MFS_MFS_EXTERN_H__ +#include + +#ifdef __APPLE_API_OBSOLETE struct buf; struct mount; struct nameidata; @@ -80,3 +85,5 @@ int mfs_start __P((struct mount *mp, int flags, struct proc *p)); int mfs_statfs __P((struct mount *mp, struct statfs *sbp, struct proc *p)); int mfs_strategy __P((struct vop_strategy_args *)); /* XXX */ __END_DECLS +#endif /* __APPLE_API_OBSOLETE */ +#endif /* __UFS_MFS_MFS_EXTERN_H__ */ diff --git a/bsd/ufs/mfs/mfs_vfsops.c b/bsd/ufs/mfs/mfs_vfsops.c index 1ae81a5a1..73c989e87 100644 --- a/bsd/ufs/mfs/mfs_vfsops.c +++ b/bsd/ufs/mfs/mfs_vfsops.c @@ -151,6 +151,7 @@ mfs_mountroot() mfsp->mfs_pid = p->p_pid; mfsp->mfs_buflist = (struct buf *)0; if (error = ffs_mountfs(rootvp, mp, p)) { + vrele(rootvp); /* release the reference from bdevvp() */ _FREE_ZONE(mp, sizeof (struct mount), M_MOUNT); _FREE(mfsp, M_MFSNODE); return (error); diff --git a/bsd/ufs/mfs/mfsiom.h b/bsd/ufs/mfs/mfsiom.h index aaac06b5c..de9788fa4 100644 --- a/bsd/ufs/mfs/mfsiom.h +++ b/bsd/ufs/mfs/mfsiom.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -55,5 +55,13 @@ * @(#)mfsiom.h 8.1 (Berkeley) 6/11/93 */ +#ifndef __UFS_MFS_MFSIOM_H__ +#define __UFS_MFS_MFSIOM_H__ + +#include + +#ifdef __APPLE_API_OBSOLETE #define MFS_MAPREG (MAXPHYS/NBPG + 2) /* Kernel mapping pte's */ #define MFS_MAPSIZE 10 /* Size of alloc map for pte's */ +#endif /* __APPLE_API_OBSOLETE */ +#endif /* __UFS_MFS_MFSIOM_H__ */ diff --git a/bsd/ufs/mfs/mfsnode.h b/bsd/ufs/mfs/mfsnode.h index 309c9bf15..d1e5e9f91 100644 --- a/bsd/ufs/mfs/mfsnode.h +++ b/bsd/ufs/mfs/mfsnode.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -55,6 +55,12 @@ * @(#)mfsnode.h 8.2 (Berkeley) 8/11/93 */ +#ifndef __UFS_MFS_MFSNODE_H__ +#define __UFS_MFS_MFSNODE_H__ + +#include + +#ifdef __APPLE_API_OBSOLETE /* * This structure defines the control data for the memory based file system. */ @@ -106,3 +112,5 @@ struct mfsnode { #define mfs_truncate ((int (*) __P((struct vop_truncate_args *)))mfs_badop) #define mfs_update ((int (*) __P((struct vop_update_args *)))mfs_badop) #define mfs_bwrite ((int (*) __P((struct vop_bwrite_args *)))vn_bwrite) +#endif /* __APPLE_API_OBSOLETE */ +#endif /* __UFS_MFS_MFSNODE_H__ */ diff --git a/bsd/ufs/ufs/dinode.h b/bsd/ufs/ufs/dinode.h index c28034c48..09ff1dfc9 100644 --- a/bsd/ufs/ufs/dinode.h +++ b/bsd/ufs/ufs/dinode.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -62,7 +62,10 @@ #ifndef _UFS_DINODE_H_ #define _UFS_DINODE_H_ +#include + +#ifdef __APPLE_API_UNSTABLE /* * 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 @@ -148,4 +151,5 @@ struct dinode { #define IFSOCK 0140000 /* UNIX domain socket. */ #define IFWHT 0160000 /* Whiteout. */ +#endif /* __APPLE_API_UNSTABLE */ #endif /* ! _UFS_DINODE_H_ */ diff --git a/bsd/ufs/ufs/dir.h b/bsd/ufs/ufs/dir.h index 2b8527ddc..9a86ec824 100644 --- a/bsd/ufs/ufs/dir.h +++ b/bsd/ufs/ufs/dir.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -63,6 +63,9 @@ #ifndef _DIR_H_ #define _DIR_H_ +#include + +#ifdef __APPLE_API_UNSTABLE /* * Theoretically, directories can be more than 2Gb in length, however, in * practice this seems unlikely. So, we define the type doff_t as a 32-bit @@ -178,4 +181,5 @@ struct odirtemplate { u_int16_t dotdot_namlen; char dotdot_name[4]; /* ditto */ }; +#endif /* __APPLE_API_UNSTABLE */ #endif /* !_DIR_H_ */ diff --git a/bsd/ufs/ufs/inode.h b/bsd/ufs/ufs/inode.h index 69d6144c0..f81ae2b19 100644 --- a/bsd/ufs/ufs/inode.h +++ b/bsd/ufs/ufs/inode.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -62,9 +62,13 @@ #ifndef _UFS_INDOE_H_ #define _UFS_INDOE_H_ +#include + +#ifdef __APPLE_API_PRIVATE #include #include #include +#include /* * The inode is used to describe each active (or recently active) file in the @@ -85,14 +89,8 @@ struct inode { union { /* Associated filesystem. */ struct fs *fs; /* FFS */ -#if LFS - struct lfs *lfs; /* LFS */ -#endif } inode_u; #define i_fs inode_u.fs -#if LFS -#define i_lfs inode_u.lfs -#endif struct dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */ u_quad_t i_modrev; /* Revision level for NFS lease. */ @@ -187,4 +185,5 @@ struct ufid { }; #endif /* KERNEL */ +#endif /* __APPLE_API_PRIVATE */ #endif /* ! _UFS_INDOE_H_ */ diff --git a/bsd/ufs/ufs/lockf.h b/bsd/ufs/ufs/lockf.h index a780d93c5..92121a1f5 100644 --- a/bsd/ufs/ufs/lockf.h +++ b/bsd/ufs/ufs/lockf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -60,6 +60,9 @@ #ifndef _UFS_LOCKF_H_ #define _UFS_LOCKF_H_ +#include + +#ifdef __APPLE_API_PRIVATE /* * The lockf structure is a kernel structure which contains the information * associated with a byte range lock. The lockf structures are linked into @@ -105,5 +108,6 @@ void lf_printlist __P((char *, struct lockf *)); __END_DECLS #endif +#endif /* __APPLE_API_PRIVATE */ #endif /* ! _UFS_LOCKF_H_ */ diff --git a/bsd/ufs/ufs/quota.h b/bsd/ufs/ufs/quota.h index 3a718b1c9..13de74d26 100644 --- a/bsd/ufs/ufs/quota.h +++ b/bsd/ufs/ufs/quota.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -19,7 +19,6 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ /* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. @@ -58,175 +57,34 @@ * @(#)quota.h 8.3 (Berkeley) 8/19/94 */ -#ifndef _QUOTA_ -#define _QUOTA_ +#ifndef _UFS_QUOTA_H +#define _UFS_QUOTA_H -/* - * 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) /* seconds in 1 week */ -#define MAX_DQ_TIME (7*24*60*60) /* seconds in 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_int32_t dqb_bhardlimit; /* absolute limit on disk blks alloc */ - u_int32_t dqb_bsoftlimit; /* preferred limit on disk blks */ - u_int32_t dqb_curblocks; /* current block count */ - u_int32_t dqb_ihardlimit; /* maximum # allocated inodes + 1 */ - u_int32_t dqb_isoftlimit; /* preferred inode limit */ - u_int32_t dqb_curinodes; /* current # allocated inodes */ - time_t dqb_btime; /* time limit for excessive disk use */ - time_t dqb_itime; /* time limit for excessive files */ -}; - -#ifndef KERNEL - -#include +#include -__BEGIN_DECLS -int quotactl __P((char *, int, int, caddr_t)); -__END_DECLS -#endif /* !KERNEL */ +#ifdef __APPLE_API_PRIVATE +#include #ifdef KERNEL #include -/* - * 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 { - LIST_ENTRY(dquot) dq_hash; /* hash list */ - TAILQ_ENTRY(dquot) dq_freelist; /* free list */ - u_int16_t dq_flags; /* flags, see below */ - u_int16_t dq_cnt; /* count of active references */ - u_int16_t dq_spare; /* unused spare padding */ - u_int16_t dq_type; /* quota type of this dquot */ - u_int32_t 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 NULL - -/* - * 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. - */ -#if DIAGNOSTIC -#define DQREF(dq) dqref(dq) -#else -#define DQREF(dq) (dq)->dq_cnt++ -#endif #include -struct dquot; struct inode; struct mount; struct proc; struct ucred; -struct ufsmount; -struct vnode; __BEGIN_DECLS -int chkdq __P((struct inode *, long, struct ucred *, int)); -int chkdqchg __P((struct inode *, long, struct ucred *, int)); +int chkdq __P((struct inode *, int64_t, struct ucred *, int)); +int chkdqchg __P((struct inode *, int64_t, struct ucred *, int)); int chkiq __P((struct inode *, long, struct ucred *, int)); int chkiqchg __P((struct inode *, long, struct ucred *, int)); -void dqflush __P((struct vnode *)); -int dqget __P((struct vnode *, - u_long, struct ufsmount *, int, struct dquot **)); -void dqinit __P((void)); -void dqref __P((struct dquot *)); -void dqrele __P((struct vnode *, struct dquot *)); -int dqsync __P((struct vnode *, struct dquot *)); int getinoquota __P((struct inode *)); int getquota __P((struct mount *, u_long, int, caddr_t)); int qsync __P((struct mount *mp)); int quotaoff __P((struct proc *, struct mount *, int)); -int quotaon __P((struct proc *, struct mount *, int, caddr_t)); +int quotaon __P((struct proc *, struct mount *, int, caddr_t, enum uio_seg)); int setquota __P((struct mount *, u_long, int, caddr_t)); int setuse __P((struct mount *, u_long, int, caddr_t)); int ufs_quotactl __P((struct mount *, int, uid_t, caddr_t, struct proc *)); @@ -239,4 +97,5 @@ __END_DECLS #endif #endif /* KERNEL */ -#endif /* _QUOTA_ */ +#endif /* __APPLE_API_PRIVATE */ +#endif /* ! _UFS_QUOTA_H */ diff --git a/bsd/ufs/ufs/ufs_bmap.c b/bsd/ufs/ufs/ufs_bmap.c index 4acc2dd91..86cf8a596 100644 --- a/bsd/ufs/ufs/ufs_bmap.c +++ b/bsd/ufs/ufs/ufs_bmap.c @@ -72,6 +72,7 @@ #include #include #include +#include #include diff --git a/bsd/ufs/ufs/ufs_byte_order.c b/bsd/ufs/ufs/ufs_byte_order.c index 28edd44e2..0dc96b141 100644 --- a/bsd/ufs/ufs/ufs_byte_order.c +++ b/bsd/ufs/ufs/ufs_byte_order.c @@ -32,20 +32,14 @@ #include #include +#include #include #include - - -#if 0 -#define byte_swap_longlong(thing) ((thing) = NXSwapBigLongLongToHost(thing)) -#define byte_swap_int(thing) ((thing) = NXSwapBigLongToHost(thing)) -#define byte_swap_short(thing) ((thing) = NXSwapBigShortToHost(thing)) -#else #define byte_swap_longlong(thing) ((thing) = NXSwapLongLong(thing)) #define byte_swap_int(thing) ((thing) = NXSwapLong(thing)) #define byte_swap_short(thing) ((thing) = NXSwapShort(thing)) -#endif + void byte_swap_longlongs(unsigned long long *array, int count) { @@ -64,7 +58,6 @@ byte_swap_ints(int *array, int count) byte_swap_int(array[i]); } - void byte_swap_shorts(short *array, int count) { @@ -74,7 +67,6 @@ byte_swap_shorts(short *array, int count) byte_swap_short(array[i]); } - void byte_swap_sbin(struct fs *sb) { @@ -119,6 +111,7 @@ byte_swap_sbout(struct fs *sb) byte_swap_longlongs((u_int64_t *)&sb->fs_maxfilesize,3); byte_swap_ints((int32_t *)&sb->fs_state, 6); } + void byte_swap_csum(struct csum *cs) { @@ -173,7 +166,7 @@ byte_swap_cgin(struct cg *cg, struct fs * fs) } -// This is for the new 4.4 cylinder group block +/* This is for the new 4.4 cylinder group block */ void byte_swap_cgout(struct cg *cg, struct fs * fs) { @@ -220,7 +213,7 @@ byte_swap_cgout(struct cg *cg, struct fs * fs) } -/* This value should correspond to the value set in the ffs_mounts */ +/* This value MUST correspond to the value set in the ffs_mounts */ #define RESYMLNKLEN 60 @@ -231,12 +224,8 @@ byte_swap_inode_in(struct dinode *di, struct inode *ip) ip->i_mode = NXSwapShort(di->di_mode); ip->i_nlink = NXSwapShort(di->di_nlink); -#ifdef LFS - ip->i_inumber = NXSwapLong(di->di_u.inumber); -#else ip->i_oldids[0] = NXSwapShort(di->di_u.oldids[0]); ip->i_oldids[1] = NXSwapShort(di->di_u.oldids[1]); -#endif ip->i_size = NXSwapLongLong(di->di_size); ip->i_atime = NXSwapLong(di->di_atime); ip->i_atimensec = NXSwapLong(di->di_atimensec); @@ -259,10 +248,8 @@ byte_swap_inode_in(struct dinode *di, struct inode *ip) ip->i_gid = NXSwapLong(di->di_gid); ip->i_spare[0] = NXSwapLong(di->di_spare[0]); ip->i_spare[1] = NXSwapLong(di->di_spare[1]); - } - void byte_swap_inode_out(struct inode *ip, struct dinode *di) { @@ -274,12 +261,8 @@ byte_swap_inode_out(struct inode *ip, struct dinode *di) di->di_mode = NXSwapShort(ip->i_mode); di->di_nlink = NXSwapShort(ip->i_nlink); -#ifdef LFS - di->di_u.inumber = NXSwapLong(ip->i_inumber); -#else di->di_u.oldids[0] = NXSwapShort(ip->i_oldids[0]); di->di_u.oldids[1] = NXSwapShort(ip->i_oldids[1]); -#endif /* LFS */ di->di_size = NXSwapLongLong(ip->i_size); di->di_atime = NXSwapLong(ip->i_atime); di->di_atimensec = NXSwapLong(ip->i_atimensec); @@ -302,10 +285,8 @@ byte_swap_inode_out(struct inode *ip, struct dinode *di) di->di_gid = NXSwapLong(ip->i_gid); di->di_spare[0] = NXSwapLong(ip->i_spare[0]); di->di_spare[1] = NXSwapLong(ip->i_spare[1]); - } - void byte_swap_direct(struct direct *dirp) { @@ -328,6 +309,7 @@ byte_swap_dir_block_in(char *addr, int count) break; } } + void byte_swap_dir_out(char *addr, int count) { @@ -371,6 +353,7 @@ byte_swap_dirtemplate_in(struct dirtemplate *dirt) byte_swap_int(dirt->dotdot_ino); byte_swap_short(dirt->dotdot_reclen); } + void byte_swap_minidir_in(struct direct *dirp) { @@ -379,7 +362,7 @@ byte_swap_minidir_in(struct direct *dirp) } #if 0 -// This is for the compatability (old) cylinder group block +/* This is for the compatability (old) cylinder group block */ void byte_swap_ocylgroup(struct cg *cg) { @@ -397,5 +380,4 @@ byte_swap_ocylgroup(struct cg *cg) byte_swap_shorts((short *)&cg->cg_b, 32 * 8); byte_swap_int(cg->cg_magic); } - #endif /* 0 */ diff --git a/bsd/ufs/ufs/ufs_byte_order.h b/bsd/ufs/ufs/ufs_byte_order.h index f52e4475c..12dd0badc 100644 --- a/bsd/ufs/ufs/ufs_byte_order.h +++ b/bsd/ufs/ufs/ufs_byte_order.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -24,10 +24,6 @@ * UFS byte swapping routines to make a big endian file system useful on a * little endian machine. * - * HISTORY - * - * 16 Feb 1998 A. Ramesh at Apple - * MacOSX version created. */ #ifdef KERNEL_PRIVATE @@ -35,6 +31,9 @@ #ifndef _UFS_BYTE_ORDER_H_ #define _UFS_BYTE_ORDER_H_ +#include + +#ifdef __APPLE_API_PRIVATE #include #include #include @@ -63,5 +62,6 @@ void byte_swap_direct __P((struct direct *)); void byte_swap_dirtemplate_in __P((struct dirtemplate *)); void byte_swap_minidir_in __P((struct direct *)); +#endif /* __APPLE_API_PRIVATE */ #endif /* _UFS_BYTE_ORDER_H_ */ #endif /* KERNEL_PRIVATE */ diff --git a/bsd/ufs/ufs/ufs_extern.h b/bsd/ufs/ufs/ufs_extern.h index 469d646ed..7e7488fd5 100644 --- a/bsd/ufs/ufs/ufs_extern.h +++ b/bsd/ufs/ufs/ufs_extern.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -57,6 +57,9 @@ #ifndef _UFS_EXTERN_H_ #define _UFS_EXTERN_H_ +#include + +#ifdef __APPLE_API_PRIVATE struct buf; struct direct; struct disklabel; @@ -160,4 +163,5 @@ int ufs_cmap __P((struct vop_cmap_args *)); __END_DECLS +#endif /* __APPLE_API_PRIVATE */ #endif /* ! _UFS_EXTERN_H_ */ diff --git a/bsd/ufs/ufs/ufs_ihash.c b/bsd/ufs/ufs/ufs_ihash.c index a166a450e..a3da69ee5 100644 --- a/bsd/ufs/ufs/ufs_ihash.c +++ b/bsd/ufs/ufs/ufs_ihash.c @@ -60,6 +60,7 @@ #include #include #include +#include #include #include diff --git a/bsd/ufs/ufs/ufs_inode.c b/bsd/ufs/ufs/ufs_inode.c index b51ee0824..90e6d8f93 100644 --- a/bsd/ufs/ufs/ufs_inode.c +++ b/bsd/ufs/ufs/ufs_inode.c @@ -67,6 +67,7 @@ #include #include #include +#include #include #include diff --git a/bsd/ufs/ufs/ufs_lockf.c b/bsd/ufs/ufs/ufs_lockf.c index ec0a50957..4f4a71933 100644 --- a/bsd/ufs/ufs/ufs_lockf.c +++ b/bsd/ufs/ufs/ufs_lockf.c @@ -66,6 +66,7 @@ #include #include #include +#include #include #include diff --git a/bsd/ufs/ufs/ufs_lookup.c b/bsd/ufs/ufs/ufs_lookup.c index a2583678b..1b7fc0cd0 100644 --- a/bsd/ufs/ufs/ufs_lookup.c +++ b/bsd/ufs/ufs/ufs_lookup.c @@ -66,6 +66,7 @@ #include #include #include +#include #include #include diff --git a/bsd/ufs/ufs/ufs_quota.c b/bsd/ufs/ufs/ufs_quota.c index eff293ea1..e17245068 100644 --- a/bsd/ufs/ufs/ufs_quota.c +++ b/bsd/ufs/ufs/ufs_quota.c @@ -19,7 +19,6 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ /* * Copyright (c) 1982, 1986, 1990, 1993, 1995 * The Regents of the University of California. All rights reserved. @@ -61,12 +60,13 @@ #include #include #include -#include #include #include #include #include #include +#include +#include #include #include @@ -101,7 +101,7 @@ getinoquota(ip) */ if (ip->i_dquot[USRQUOTA] == NODQUOT && (error = - dqget(vp, ip->i_uid, ump, USRQUOTA, &ip->i_dquot[USRQUOTA])) && + dqget(vp, ip->i_uid, &ump->um_qfiles[USRQUOTA], USRQUOTA, &ip->i_dquot[USRQUOTA])) && error != EINVAL) return (error); /* @@ -110,7 +110,7 @@ getinoquota(ip) */ if (ip->i_dquot[GRPQUOTA] == NODQUOT && (error = - dqget(vp, ip->i_gid, ump, GRPQUOTA, &ip->i_dquot[GRPQUOTA])) && + dqget(vp, ip->i_gid, &ump->um_qfiles[GRPQUOTA], GRPQUOTA, &ip->i_dquot[GRPQUOTA])) && error != EINVAL) return (error); return (0); @@ -122,13 +122,15 @@ getinoquota(ip) int chkdq(ip, change, cred, flags) register struct inode *ip; - long change; + int64_t change; struct ucred *cred; int flags; { register struct dquot *dq; register int i; - int ncurblocks, error; + int64_t ncurbytes; + int error; + struct proc *p; #if DIAGNOSTIC if ((flags & CHOWN) == 0) @@ -144,17 +146,20 @@ chkdq(ip, change, cred, flags) dq->dq_flags |= DQ_WANT; sleep((caddr_t)dq, PINOD+1); } - ncurblocks = dq->dq_curblocks + change; - if (ncurblocks >= 0) - dq->dq_curblocks = ncurblocks; + ncurbytes = dq->dq_curbytes + change; + if (ncurbytes >= 0) + dq->dq_curbytes = ncurbytes; else - dq->dq_curblocks = 0; + dq->dq_curbytes = 0; dq->dq_flags &= ~DQ_BLKS; dq->dq_flags |= DQ_MOD; } return (0); } - if ((flags & FORCE) == 0 && cred->cr_uid != 0) { + p = current_proc(); + if (cred == NOCRED) + cred = kernproc->p_ucred; + if ((flags & FORCE) == 0 && ((cred->cr_uid != 0) || (p->p_flag & P_FORCEQUOTA))) { for (i = 0; i < MAXQUOTAS; i++) { if ((dq = ip->i_dquot[i]) == NODQUOT) continue; @@ -169,7 +174,7 @@ chkdq(ip, change, cred, flags) dq->dq_flags |= DQ_WANT; sleep((caddr_t)dq, PINOD+1); } - dq->dq_curblocks += change; + dq->dq_curbytes += change; dq->dq_flags |= DQ_MOD; } return (0); @@ -182,22 +187,24 @@ chkdq(ip, change, cred, flags) int chkdqchg(ip, change, cred, type) struct inode *ip; - long change; + int64_t change; struct ucred *cred; int type; { register struct dquot *dq = ip->i_dquot[type]; - long ncurblocks = dq->dq_curblocks + change; + u_int64_t ncurbytes = dq->dq_curbytes + change; /* * If user would exceed their hard limit, disallow space allocation. */ - if (ncurblocks >= dq->dq_bhardlimit && dq->dq_bhardlimit) { + if (ncurbytes >= 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", +#if 1 + printf("\n%s: write failed, %s disk limit reached\n", ITOV(ip)->v_mount->mnt_stat.f_mntonname, quotatypes[type]); +#endif dq->dq_flags |= DQ_BLKS; } return (EDQUOT); @@ -206,23 +213,27 @@ chkdqchg(ip, change, cred, type) * 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) { + if (ncurbytes >= dq->dq_bsoftlimit && dq->dq_bsoftlimit) { + if (dq->dq_curbytes < dq->dq_bsoftlimit) { dq->dq_btime = time.tv_sec + - VFSTOUFS(ITOV(ip)->v_mount)->um_btime[type]; + VFSTOUFS(ITOV(ip)->v_mount)->um_qfiles[type].qf_btime; +#if 1 if (ip->i_uid == cred->cr_uid) - uprintf("\n%s: warning, %s %s\n", + printf("\n%s: warning, %s %s\n", ITOV(ip)->v_mount->mnt_stat.f_mntonname, quotatypes[type], "disk quota exceeded"); +#endif 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", +#if 1 + printf("\n%s: write failed, %s %s\n", ITOV(ip)->v_mount->mnt_stat.f_mntonname, quotatypes[type], "disk quota exceeded for too long"); +#endif dq->dq_flags |= DQ_BLKS; } return (EDQUOT); @@ -244,6 +255,7 @@ chkiq(ip, change, cred, flags) register struct dquot *dq; register int i; int ncurinodes, error; + struct proc *p; #if DIAGNOSTIC if ((flags & CHOWN) == 0) @@ -269,7 +281,10 @@ chkiq(ip, change, cred, flags) } return (0); } - if ((flags & FORCE) == 0 && cred->cr_uid != 0) { + p = current_proc(); + if (cred == NOCRED) + cred = kernproc->p_ucred; + if ((flags & FORCE) == 0 && ((cred->cr_uid != 0) || (p->p_flag & P_FORCEQUOTA))) { for (i = 0; i < MAXQUOTAS; i++) { if ((dq = ip->i_dquot[i]) == NODQUOT) continue; @@ -310,9 +325,11 @@ chkiqchg(ip, change, cred, type) 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", +#if 1 + printf("\n%s: write failed, %s inode limit reached\n", ITOV(ip)->v_mount->mnt_stat.f_mntonname, quotatypes[type]); +#endif dq->dq_flags |= DQ_INODS; } return (EDQUOT); @@ -324,20 +341,24 @@ chkiqchg(ip, change, cred, type) 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]; + VFSTOUFS(ITOV(ip)->v_mount)->um_qfiles[type].qf_itime; +#if 1 if (ip->i_uid == cred->cr_uid) - uprintf("\n%s: warning, %s %s\n", + printf("\n%s: warning, %s %s\n", ITOV(ip)->v_mount->mnt_stat.f_mntonname, quotatypes[type], "inode quota exceeded"); +#endif 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", +#if 1 + printf("\n%s: write failed, %s %s\n", ITOV(ip)->v_mount->mnt_stat.f_mntonname, quotatypes[type], "inode quota exceeded for too long"); +#endif dq->dq_flags |= DQ_INODS; } return (EDQUOT); @@ -359,8 +380,8 @@ chkdquot(ip) register int i; for (i = 0; i < MAXQUOTAS; i++) { - if (ump->um_quotas[i] == NULLVP || - (ump->um_qflags[i] & (QTF_OPENING|QTF_CLOSING))) + if (ump->um_qfiles[i].qf_vp == NULLVP || + (ump->um_qfiles[i].qf_qflags & (QTF_OPENING|QTF_CLOSING))) continue; if (ip->i_dquot[i] == NODQUOT) { vprint("chkdquot: missing dquot", ITOV(ip)); @@ -378,11 +399,12 @@ chkdquot(ip) * Q_QUOTAON - set up a quota file for a particular file system. */ int -quotaon(p, mp, type, fname) +quotaon(p, mp, type, fname, segflg) struct proc *p; struct mount *mp; register int type; caddr_t fname; + enum uio_seg segflg; { struct ufsmount *ump = VFSTOUFS(mp); struct vnode *vp, **vpp; @@ -391,8 +413,8 @@ quotaon(p, mp, type, fname) int error; struct nameidata nd; - vpp = &ump->um_quotas[type]; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, fname, p); + vpp = &ump->um_qfiles[type].qf_vp; + NDINIT(&nd, LOOKUP, FOLLOW, segflg, fname, p); if (error = vn_open(&nd, FREAD|FWRITE, 0)) return (error); vp = nd.ni_vp; @@ -403,25 +425,29 @@ quotaon(p, mp, type, fname) } if (*vpp != vp) quotaoff(p, mp, type); - ump->um_qflags[type] |= QTF_OPENING; + ump->um_qfiles[type].qf_qflags |= QTF_OPENING; mp->mnt_flag |= MNT_QUOTA; - vp->v_flag |= VSYSTEM; + vp->v_flag |= VNOFLUSH; *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) { + ump->um_qfiles[type].qf_cred = p->p_ucred; + /* Finish initializing the quota file */ + if (error = dqfileopen(&ump->um_qfiles[type], type)) + goto exit; +#if 0 + ump->um_qfiles[type].qf_btime = MAX_DQ_TIME; + ump->um_qfiles[type].qf_itime = MAX_IQ_TIME; + if (dqget(NULLVP, 0, &ump->um_qfiles[type], type, &dq) == 0) { if (dq->dq_btime > 0) - ump->um_btime[type] = dq->dq_btime; + ump->um_qfiles[type].qf_btime = dq->dq_btime; if (dq->dq_itime > 0) - ump->um_itime[type] = dq->dq_itime; + ump->um_qfiles[type].qf_itime = dq->dq_itime; dqrele(NULLVP, dq); } +#endif /* * Search vnodes associated with this mount point, * adding references to quota file being opened. @@ -442,7 +468,8 @@ again: if (vp->v_mntvnodes.le_next != nextvp || vp->v_mount != mp) goto again; } - ump->um_qflags[type] &= ~QTF_OPENING; +exit: + ump->um_qfiles[type].qf_qflags &= ~QTF_OPENING; if (error) quotaoff(p, mp, type); return (error); @@ -465,9 +492,9 @@ quotaoff(p, mp, type) int error; struct ucred *cred; - if ((qvp = ump->um_quotas[type]) == NULLVP) + if ((qvp = ump->um_qfiles[type].qf_vp) == NULLVP) return (0); - ump->um_qflags[type] |= QTF_CLOSING; + ump->um_qfiles[type].qf_qflags |= QTF_CLOSING; /* * Search vnodes associated with this mount point, * deleting any references to quota file being closed. @@ -486,17 +513,19 @@ again: goto again; } dqflush(qvp); - qvp->v_flag &= ~VSYSTEM; + /* Finish tearing down the quota file */ + dqfileclose(&ump->um_qfiles[type], type); + qvp->v_flag &= ~VNOFLUSH; error = vn_close(qvp, FREAD|FWRITE, p->p_ucred, p); - ump->um_quotas[type] = NULLVP; - cred = ump->um_cred[type]; + ump->um_qfiles[type].qf_vp = NULLVP; + cred = ump->um_qfiles[type].qf_cred; if (cred != NOCRED) { - ump->um_cred[type] = NOCRED; + ump->um_qfiles[type].qf_cred = NOCRED; crfree(cred); } - ump->um_qflags[type] &= ~QTF_CLOSING; + ump->um_qfiles[type].qf_qflags &= ~QTF_CLOSING; for (type = 0; type < MAXQUOTAS; type++) - if (ump->um_quotas[type] != NULLVP) + if (ump->um_qfiles[type].qf_vp != NULLVP) break; if (type == MAXQUOTAS) mp->mnt_flag &= ~MNT_QUOTA; @@ -516,7 +545,7 @@ getquota(mp, id, type, addr) struct dquot *dq; int error; - if (error = dqget(NULLVP, id, VFSTOUFS(mp), type, &dq)) + if (error = dqget(NULLVP, id, &VFSTOUFS(mp)->um_qfiles[type], type, &dq)) return (error); error = copyout((caddr_t)&dq->dq_dqb, addr, sizeof (struct dqblk)); dqrele(NULLVP, dq); @@ -541,7 +570,7 @@ setquota(mp, id, type, addr) if (error = copyin(addr, (caddr_t)&newlim, sizeof (struct dqblk))) return (error); - if (error = dqget(NULLVP, id, ump, type, &ndq)) + if (error = dqget(NULLVP, id, &ump->um_qfiles[type], type, &ndq)) return (error); dq = ndq; while (dq->dq_flags & DQ_LOCK) { @@ -553,22 +582,22 @@ setquota(mp, id, type, addr) * 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_curbytes = dq->dq_curbytes; 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]; + dq->dq_curbytes >= newlim.dqb_bsoftlimit && + (dq->dq_bsoftlimit == 0 || dq->dq_curbytes < dq->dq_bsoftlimit)) + newlim.dqb_btime = time.tv_sec + ump->um_qfiles[type].qf_btime; 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]; + newlim.dqb_itime = time.tv_sec + ump->um_qfiles[type].qf_itime; dq->dq_dqb = newlim; - if (dq->dq_curblocks < dq->dq_bsoftlimit) + if (dq->dq_curbytes < dq->dq_bsoftlimit) dq->dq_flags &= ~DQ_BLKS; if (dq->dq_curinodes < dq->dq_isoftlimit) dq->dq_flags &= ~DQ_INODS; @@ -583,7 +612,7 @@ setquota(mp, id, type, addr) } /* - * Q_SETUSE - set current inode and block usage. + * Q_SETUSE - set current inode and byte usage. */ int setuse(mp, id, type, addr) @@ -600,7 +629,7 @@ setuse(mp, id, type, addr) if (error = copyin(addr, (caddr_t)&usage, sizeof (struct dqblk))) return (error); - if (error = dqget(NULLVP, id, ump, type, &ndq)) + if (error = dqget(NULLVP, id, &ump->um_qfiles[type], type, &ndq)) return (error); dq = ndq; while (dq->dq_flags & DQ_LOCK) { @@ -611,15 +640,15 @@ setuse(mp, id, type, addr) * 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_bsoftlimit && dq->dq_curbytes < dq->dq_bsoftlimit && + usage.dqb_curbytes >= dq->dq_bsoftlimit) + dq->dq_btime = time.tv_sec + ump->um_qfiles[type].qf_btime; 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_itime = time.tv_sec + ump->um_qfiles[type].qf_itime; + dq->dq_curbytes = usage.dqb_curbytes; dq->dq_curinodes = usage.dqb_curinodes; - if (dq->dq_curblocks < dq->dq_bsoftlimit) + if (dq->dq_curbytes < dq->dq_bsoftlimit) dq->dq_flags &= ~DQ_BLKS; if (dq->dq_curinodes < dq->dq_isoftlimit) dq->dq_flags &= ~DQ_INODS; @@ -646,7 +675,7 @@ qsync(mp) * If not, simply return. */ for (i = 0; i < MAXQUOTAS; i++) - if (ump->um_quotas[i] != NULLVP) + if (ump->um_qfiles[i].qf_vp != NULLVP) break; if (i == MAXQUOTAS) return (0); @@ -684,260 +713,24 @@ again: } /* - * Code pertaining to management of the in-core dquot data structures. - */ -#define DQHASH(dqvp, id) \ - (&dqhashtbl[((((int)(dqvp)) >> 8) + id) & dqhash]) -LIST_HEAD(dqhash, dquot) *dqhashtbl; -u_long dqhash; - -/* - * Dquot free list. - */ -#define DQUOTINC 5 /* minimum free dquots desired */ -TAILQ_HEAD(dqfreelist, dquot) dqfreelist; -long numdquot, desireddquot = DQUOTINC; - -/* - * Initialize the quota system. - */ -void -dqinit() -{ - - dqhashtbl = hashinit(desiredvnodes, M_DQUOT, &dqhash); - TAILQ_INIT(&dqfreelist); -} - -/* - * Obtain a dquot structure for the specified identifier and quota file - * reading the information from the file if necessary. + * Q_QUOTASTAT - get quota on/off status */ int -dqget(vp, id, ump, type, dqp) - struct vnode *vp; - u_long id; - register struct ufsmount *ump; +quotastat(mp, type, addr) + struct mount *mp; register int type; - struct dquot **dqp; -{ - struct proc *p = current_proc(); /* XXX */ - struct dquot *dq; - struct dqhash *dqh; - 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. - */ - dqh = DQHASH(dqvp, id); - for (dq = dqh->lh_first; dq; dq = dq->dq_hash.le_next) { - 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) - TAILQ_REMOVE(&dqfreelist, dq, dq_freelist); - DQREF(dq); - *dqp = dq; - return (0); - } - /* - * Not in cache, allocate a new one. - */ - if (dqfreelist.tqh_first == 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 = dqfreelist.tqh_first) == NULL) { - tablefull("dquot"); - *dqp = NODQUOT; - return (EUSERS); - } - if (dq->dq_cnt || (dq->dq_flags & DQ_MOD)) - panic("free dquot isn't"); - TAILQ_REMOVE(&dqfreelist, dq, dq_freelist); - LIST_REMOVE(dq, dq_hash); - } - /* - * Initialize the contents of the dquot structure. - */ - if (vp != dqvp) - vn_lock(dqvp, LK_EXCLUSIVE | LK_RETRY, p); - LIST_INSERT_HEAD(dqh, dq, dq_hash); - 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, 0, p); - 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) { - LIST_REMOVE(dq, dq_hash); - 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. - */ -void -dqref(dq) - struct dquot *dq; -{ - - dq->dq_cnt++; -} - -/* - * Release a reference to a dquot. - */ -void -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; - TAILQ_INSERT_TAIL(&dqfreelist, dq, dq_freelist); -} - -/* - * Update the disk quota in the quota file. - */ -int -dqsync(vp, dq) - struct vnode *vp; - struct dquot *dq; + caddr_t addr; { - struct proc *p = current_proc(); /* XXX */ - struct vnode *dqvp; - struct iovec aiov; - struct uio auio; - int error; + struct ufsmount *ump = VFSTOUFS(mp); + int error = 0; + int qstat; - 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) - vn_lock(dqvp, LK_EXCLUSIVE | LK_RETRY, p); - 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, 0, p); - 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, 0, p); + if ((mp->mnt_flag & MNT_QUOTA) && (ump->um_qfiles[type].qf_vp != NULLVP)) + qstat = 1; /* quotas are on for this type */ + else + qstat = 0; /* quotas are off for this type */ + + error = copyout ((caddr_t)&qstat, addr, sizeof(qstat)); return (error); } -/* - * Flush all entries from the cache for a particular vnode. - */ -void -dqflush(vp) - register struct vnode *vp; -{ - register struct dquot *dq, *nextdq; - struct dqhash *dqh; - - /* - * 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 (dqh = &dqhashtbl[dqhash]; dqh >= dqhashtbl; dqh--) { - for (dq = dqh->lh_first; dq; dq = nextdq) { - nextdq = dq->dq_hash.le_next; - if (dq->dq_ump->um_quotas[dq->dq_type] != vp) - continue; - if (dq->dq_cnt) - panic("dqflush: stray dquot"); - LIST_REMOVE(dq, dq_hash); - dq->dq_ump = (struct ufsmount *)0; - } - } -} diff --git a/bsd/ufs/ufs/ufs_vfsops.c b/bsd/ufs/ufs/ufs_vfsops.c index 82ca680e8..daebf5e5a 100644 --- a/bsd/ufs/ufs/ufs_vfsops.c +++ b/bsd/ufs/ufs/ufs_vfsops.c @@ -67,6 +67,7 @@ #include #include #include +#include #include @@ -129,6 +130,7 @@ ufs_quotactl(mp, cmds, uid, arg, p) switch (cmd) { case Q_SYNC: + case Q_QUOTASTAT: break; case Q_GETQUOTA: if (uid == p->p_cred->p_ruid) @@ -148,7 +150,7 @@ ufs_quotactl(mp, cmds, uid, arg, p) switch (cmd) { case Q_QUOTAON: - error = quotaon(p, mp, type, arg); + error = quotaon(p, mp, type, arg, UIO_USERSPACE); break; case Q_QUOTAOFF: @@ -171,6 +173,10 @@ ufs_quotactl(mp, cmds, uid, arg, p) error = qsync(mp); break; + case Q_QUOTASTAT: + error = quotastat(mp, type, arg); + break; + default: error = EINVAL; break; diff --git a/bsd/ufs/ufs/ufs_vnops.c b/bsd/ufs/ufs/ufs_vnops.c index c9f3da6c7..1d1e6ec0e 100644 --- a/bsd/ufs/ufs/ufs_vnops.c +++ b/bsd/ufs/ufs/ufs_vnops.c @@ -77,6 +77,7 @@ #include #include #include +#include #include #include @@ -224,7 +225,8 @@ ufs_close(ap) register struct inode *ip = VTOI(vp); simple_lock(&vp->v_interlock); - if (vp->v_usecount > (UBCINFOEXISTS(vp) ? 2 : 1)) + if ((!UBCISVALID(vp) && vp->v_usecount > 1) + || (UBCISVALID(vp) && ubc_isinuse(vp, 1))) ITIMES(ip, &time, &time); simple_unlock(&vp->v_interlock); @@ -522,8 +524,9 @@ ufs_chown(vp, uid, gid, cred, p) int error = 0; #if QUOTA register int i; - long change; -#endif + int64_t change; /* in bytes */ + int devBlockSize=0; +#endif /* QUOTA */ if (uid == (uid_t)VNOVAL) uid = ip->i_uid; @@ -551,7 +554,8 @@ ufs_chown(vp, uid, gid, cred, p) dqrele(vp, ip->i_dquot[GRPQUOTA]); ip->i_dquot[GRPQUOTA] = NODQUOT; } - change = ip->i_blocks; + VOP_DEVBLOCKSIZE(ip->i_devvp, &devBlockSize); + change = dbtob((int64_t)ip->i_blocks, devBlockSize); (void) chkdq(ip, -change, cred, CHOWN); (void) chkiq(ip, -1, cred, CHOWN); for (i = 0; i < MAXQUOTAS; i++) { @@ -734,12 +738,16 @@ ufs_remove(ap) error = EPERM; goto out; } - if ((vp->v_usecount > (UBCINFOEXISTS(vp) ? 2 : 1)) && - (ap->a_cnp->cn_flags & NODELETEBUSY)) { - /* Carbon and Classic clients can't delete busy files */ - error = EBUSY; - goto out; + + if (ap->a_cnp->cn_flags & NODELETEBUSY) { + /* Caller requested Carbon delete semantics */ + if ((!UBCISVALID(vp) && vp->v_usecount > 1) + || (UBCISVALID(vp) && ubc_isinuse(vp, 1))) { + error = EBUSY; + goto out; + } } + if ((error = ufs_dirremove(dvp, ap->a_cnp)) == 0) { ip->i_nlink--; ip->i_flag |= IN_CHANGE; diff --git a/bsd/ufs/ufs/ufsmount.h b/bsd/ufs/ufs/ufsmount.h index ce88c2502..a54746310 100644 --- a/bsd/ufs/ufs/ufsmount.h +++ b/bsd/ufs/ufs/ufsmount.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -57,8 +57,11 @@ #ifndef _UFS_UFSMOUNT_H_ #define _UFS_UFSMOUNT_H_ -#include +#include +#include + +#ifdef __APPLE_API_UNSTABLE /* * Arguments to mount UFS-based filesystems */ @@ -66,7 +69,9 @@ struct ufs_args { char *fspec; /* block special device to mount */ struct export_args export; /* network export information */ }; +#endif /* __APPLE_API_UNSTABLE */ +#ifdef __APPLE_API_OBSOLETE #if MFS /* * Arguments to mount MFS @@ -78,14 +83,12 @@ struct mfs_args { u_long size; /* size of file system */ }; #endif /* MFS */ +#endif /* __APPLE_API_OBSOLETE */ #ifdef KERNEL -struct buf; -struct inode; -struct nameidata; -struct timeval; -struct ucred; -struct uio; +#ifdef __APPLE_API_PRIVATE +struct fs; +struct mount; struct vnode; struct netexport; @@ -96,29 +99,18 @@ struct ufsmount { struct vnode *um_devvp; /* block device mounted vnode */ union { /* pointer to superblock */ - struct lfs *lfs; /* LFS */ struct fs *fs; /* FFS */ } ufsmount_u; #define um_fs ufsmount_u.fs -#define um_lfs ufsmount_u.lfs - struct vnode *um_quotas[MAXQUOTAS]; /* pointer to quota files */ - struct ucred *um_cred[MAXQUOTAS]; /* quota file access cred */ + struct quotafile um_qfiles[MAXQUOTAS]; /* quota files */ u_long um_nindir; /* indirect ptrs per block */ u_long um_bptrtodb; /* indir ptr to disk block */ u_long um_seqinc; /* inc between seq blocks */ - 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 */ struct netexport um_export; /* export information */ int64_t um_savedmaxfilesize; /* XXX - limit maxfilesize */ }; -/* - * Flags describing the state of quotas. - */ -#define QTF_OPENING 0x01 /* Q_QUOTAON in progress */ -#define QTF_CLOSING 0x02 /* Q_QUOTAOFF in progress */ /* Convert mount ptr to ufsmount ptr. */ #define VFSTOUFS(mp) ((struct ufsmount *)((mp)->mnt_data)) @@ -130,6 +122,7 @@ struct ufsmount { #define MNINDIR(ump) ((ump)->um_nindir) #define blkptrtodb(ump, b) ((b) << (ump)->um_bptrtodb) #define is_sequential(ump, a, b) ((b) == (a) + ump->um_seqinc) +#endif /* __APPLE_API_PRIVATE */ #endif /* KERNEL */ #endif /* ! _UFS_UFSMOUNT_H_ */ diff --git a/bsd/uxkern/ux_exception.c b/bsd/uxkern/ux_exception.c index 7a4e53e45..2b6a4750d 100644 --- a/bsd/uxkern/ux_exception.c +++ b/bsd/uxkern/ux_exception.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -166,7 +167,7 @@ ux_handler_init(void) if (ux_exception_port == MACH_PORT_NULL) { simple_unlock(&ux_handler_init_lock); assert_wait(&ux_exception_port, THREAD_UNINT); - thread_block((void (*)(void)) 0); + thread_block(THREAD_CONTINUE_NULL); } else simple_unlock(&ux_handler_init_lock); @@ -198,7 +199,7 @@ catch_exception_raise( (ipc_object_copyin(get_task_ipcspace(self), thread_name, MACH_MSG_TYPE_PORT_SEND, (void *) &thread_port) == MACH_MSG_SUCCESS)) { - if (IPC_OBJECT_VALID(thread_port)) { + if (IPC_PORT_VALID(thread_port)) { th_act = (thread_act_t)convert_port_to_act(thread_port); ipc_port_release(thread_port); } else { @@ -306,6 +307,9 @@ void ux_exception( case EXC_UNIX_ABORT: *ux_signal = SIGABRT; break; + case EXC_SOFT_SIGNAL: + *ux_signal = SIGKILL; + break; } break; diff --git a/bsd/vfs/vfs_bio.c b/bsd/vfs/vfs_bio.c index 573ad97d8..c11c03bea 100644 --- a/bsd/vfs/vfs_bio.c +++ b/bsd/vfs/vfs_bio.c @@ -64,14 +64,12 @@ * @(#)vfs_bio.c 8.6 (Berkeley) 1/11/94 */ - /* * Some references: * Bach: The Design of the UNIX Operating System (Prentice Hall, 1986) * Leffler, et al.: The Design and Implementation of the 4.3BSD * UNIX Operating System (Addison Welley, 1989) */ -#define ZALLOC_METADATA 1 #include #include @@ -92,13 +90,14 @@ #include #include +#include -extern void bufqinc(int q); -extern void bufqdec(int q); -extern void bufq_balance_thread_init(); +static __inline__ void bufqinc(int q); +static __inline__ void bufqdec(int q); -extern void reassignbuf(struct buf *, struct vnode *); static struct buf *getnewbuf(int slpflag, int slptimeo, int *queue); +static int bcleanbuf(struct buf *bp); +extern void vwakeup(); extern int niobuf; /* The number of IO buffer headers for cluster IO */ int blaundrycnt; @@ -167,6 +166,15 @@ static int need_iobuffer; (bp)->b_hash.le_next = (struct buf *)0; \ (bp)->b_hash.le_prev = (struct buf **)0xdeadbeef; +/* + * Insq/Remq for the vnode usage lists. + */ +#define bufinsvn(bp, dp) LIST_INSERT_HEAD(dp, bp, b_vnbufs) +#define bufremvn(bp) { \ + LIST_REMOVE(bp, b_vnbufs); \ + (bp)->b_vnbufs.le_next = NOLIST; \ +} + simple_lock_data_t bufhashlist_slock; /* lock on buffer hash list */ /* number of per vnode, "in flight" buffer writes */ @@ -184,8 +192,8 @@ int lru_is_stale = LRU_IS_STALE; int age_is_stale = AGE_IS_STALE; int meta_is_stale = META_IS_STALE; -#if 1 -void +/* LIST_INSERT_HEAD() with assertions */ +static __inline__ void blistenterhead(struct bufhashhdr * head, struct buf * bp) { if ((bp->b_hash.le_next = (head)->lh_first) != NULL) @@ -194,45 +202,35 @@ blistenterhead(struct bufhashhdr * head, struct buf * bp) bp->b_hash.le_prev = &(head)->lh_first; if (bp->b_hash.le_prev == (struct buf **)0xdeadbeef) panic("blistenterhead: le_prev is deadbeef"); - } -#endif -#if 1 -void +static __inline__ void binshash(struct buf *bp, struct bufhashhdr *dp) { -int s; - -struct buf *nbp; + struct buf *nbp; simple_lock(&bufhashlist_slock); + #if 0 - if(incore(bp->b_vp, bp->b_lblkno)) { - panic("adding to queue already existing element"); - } + if(incore(bp->b_vp, bp->b_lblkno)) + panic("binshash: already incore"); #endif /* 0 */ + BHASHENTCHECK(bp); - + nbp = dp->lh_first; for(; nbp != NULL; nbp = nbp->b_hash.le_next) { if(nbp == bp) panic("buf already in hashlist"); } -#if 0 - LIST_INSERT_HEAD(dp, bp, b_hash); -#else blistenterhead(dp, bp); -#endif simple_unlock(&bufhashlist_slock); } -void +static __inline__ void bremhash(struct buf *bp) { - int s; - simple_lock(&bufhashlist_slock); if (bp->b_hash.le_prev == (struct buf **)0xdeadbeef) panic("bremhash le_prev is deadbeef"); @@ -245,9 +243,6 @@ bremhash(struct buf *bp) simple_unlock(&bufhashlist_slock); } -#endif /* 1 */ - - /* * Remove a buffer from the free list it's on */ @@ -279,6 +274,82 @@ bremfree(bp) bp->b_timestamp = 0; } +/* + * Associate a buffer with a vnode. + */ +static void +bgetvp(vp, bp) + register struct vnode *vp; + register struct buf *bp; +{ + + if (bp->b_vp != 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. + */ + bufinsvn(bp, &vp->v_cleanblkhd); +} + +/* + * Disassociate a buffer from a vnode. + */ +static void +brelvp(bp) + register struct buf *bp; +{ + struct vnode *vp; + + if (bp->b_vp == (struct vnode *) 0) + panic("brelvp: NULL vp"); + /* + * Delete from old vnode list, if on one. + */ + if (bp->b_vnbufs.le_next != NOLIST) + bufremvn(bp); + 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. + */ +void +reassignbuf(bp, newvp) + register struct buf *bp; + register struct vnode *newvp; +{ + register struct buflists *listheadp; + + if (newvp == NULL) { + printf("reassignbuf: NULL"); + return; + } + /* + * Delete from old vnode list, if on one. + */ + if (bp->b_vnbufs.le_next != NOLIST) + bufremvn(bp); + /* + * If dirty, put on list of dirty buffers; + * otherwise insert onto list of clean buffers. + */ + if (ISSET(bp->b_flags, B_DELWRI)) + listheadp = &newvp->v_dirtyblkhd; + else + listheadp = &newvp->v_cleanblkhd; + bufinsvn(bp, listheadp); +} + static __inline__ void bufhdrinit(struct buf *bp) { @@ -295,7 +366,7 @@ bufhdrinit(struct buf *bp) /* * Initialize buffers and hash links for buffers. */ -void +__private_extern__ void bufinit() { register struct buf *bp; @@ -351,13 +422,15 @@ bufinit() bcleanbuf_thread_init(); #if 0 /* notyet */ + { + static void bufq_balance_thread_init(); /* create a thread to do dynamic buffer queue balancing */ bufq_balance_thread_init(); -#endif /* XXX */ + } +#endif /* notyet */ } -/* __inline */ -struct buf * +static struct buf * bio_doread(vp, blkno, size, cred, async, queuetype) struct vnode *vp; daddr_t blkno; @@ -503,18 +576,16 @@ bwrite(bp) { int rv, sync, wasdelayed; struct proc *p = current_proc(); - upl_t upl; - upl_page_info_t *pl; - void * object; - kern_return_t kret; struct vnode *vp = bp->b_vp; /* Remember buffer type, to switch on it later. */ sync = !ISSET(bp->b_flags, B_ASYNC); wasdelayed = ISSET(bp->b_flags, B_DELWRI); CLR(bp->b_flags, (B_READ | B_DONE | B_ERROR | B_DELWRI)); - if (wasdelayed) + if (wasdelayed) { nbdwrite--; + wakeup((caddr_t)&nbdwrite); + } if (!sync) { /* @@ -590,9 +661,10 @@ vn_bwrite(ap) * buffers faster than the disks can service. Doing a bawrite() in * cases were we have "too many" outstanding bdwrite()s avoids that. */ -void -bdwrite(bp) +__private_extern__ int +bdwrite_internal(bp, return_error) struct buf *bp; + int return_error; { struct proc *p = current_proc(); struct vnode *vp = bp->b_vp; @@ -611,12 +683,11 @@ bdwrite(bp) reassignbuf(bp, vp); } - /* If this is a tape block, write it the block now. */ if (ISSET(bp->b_flags, B_TAPE)) { /* bwrite(bp); */ - VOP_BWRITE(bp); - return; + VOP_BWRITE(bp); + return (0); } /* @@ -637,15 +708,27 @@ bdwrite(bp) panic("bdwrite: Negative nbdwrite"); if (nbdwrite > ((nbuf/4)*3)) { - bawrite(bp); - return; + if (return_error) + return (EAGAIN); + else + bawrite(bp); + return (0); } /* Otherwise, the "write" is done, so mark and release the buffer. */ SET(bp->b_flags, B_DONE); brelse(bp); + return (0); } +void +bdwrite(bp) + struct buf *bp; +{ + (void) bdwrite_internal(bp, 0); +} + + /* * Asynchronous block write; just an asynchronous bwrite(). * @@ -656,9 +739,10 @@ bdwrite(bp) * We limit the number of "in flight" writes a vnode can have to * avoid this. */ -void -bawrite(bp) +static int +bawrite_internal(bp, throttle) struct buf *bp; + int throttle; { struct vnode *vp = bp->b_vp; @@ -668,13 +752,41 @@ bawrite(bp) * wait for them to finish the IO */ while (vp->v_numoutput >= BUFWRITE_THROTTLE) { - vp->v_flag |= VTHROTTLED; - (void)tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "bawrite", 0); + if (throttle) { + vp->v_flag |= VTHROTTLED; + (void)tsleep((caddr_t)&vp->v_numoutput, + PRIBIO + 1, "bawrite", 0); + } else + return (EWOULDBLOCK); } } SET(bp->b_flags, B_ASYNC); VOP_BWRITE(bp); + return (0); +} + +void +bawrite(bp) + struct buf *bp; +{ + (void) bawrite_internal(bp, 1); +} + +/* + * bwillwrite: + * + * Called prior to the locking of any vnodes when we are expecting to + * write. We do not want to starve the buffer cache with too many + * dirty buffers so we block here. By blocking prior to the locking + * of any vnodes we attempt to avoid the situation where a locked vnode + * prevents the various system daemons from flushing related buffers. + */ + +void +bwillwrite(void) +{ + /* XXX To be implemented later */ } /* @@ -789,9 +901,12 @@ brelse(bp) if (ISSET(bp->b_flags, B_DELWRI)) { CLR(bp->b_flags, B_DELWRI); nbdwrite--; + wakeup((caddr_t)&nbdwrite); } if (bp->b_bufsize <= 0) whichq = BQ_EMPTY; /* no data */ + else if (ISSET(bp->b_flags, B_META)) + whichq = BQ_META; /* meta-data */ else whichq = BQ_AGE; /* invalid data */ @@ -838,18 +953,14 @@ incore(vp, blkno) daddr_t blkno; { struct buf *bp; - int bufseen = 0; bp = BUFHASH(vp, blkno)->lh_first; /* Search hash chain */ - for (; bp != NULL; bp = bp->b_hash.le_next, bufseen++) { + for (; bp != NULL; bp = bp->b_hash.le_next) { if (bp->b_lblkno == blkno && bp->b_vp == vp && !ISSET(bp->b_flags, B_INVAL)) return (bp); - if(bufseen >= nbuf) - panic("walked more than nbuf in incore"); - } return (0); @@ -884,7 +995,7 @@ getblk(vp, blkno, size, slpflag, slptimeo, operation) start: s = splbio(); - if (bp = incore(vp, blkno)) { + if ((bp = incore(vp, blkno))) { /* Found in the Buffer Cache */ if (ISSET(bp->b_flags, B_BUSY)) { /* but is busy */ @@ -966,11 +1077,11 @@ start: CLR(bp->b_flags, B_WASDIRTY); kret = ubc_upl_map(upl, (vm_address_t *)&(bp->b_data)); - if (kret != KERN_SUCCESS) { + if (kret != KERN_SUCCESS) panic("getblk: ubc_upl_map() failed with (%d)", kret); - } - if (bp->b_data == 0) panic("ubc_upl_map mapped 0"); + if (bp->b_data == 0) + panic("ubc_upl_map mapped 0"); } break; @@ -979,7 +1090,7 @@ start: * VM is not involved in IO for the meta data * buffer already has valid data */ - if(bp->b_data == 0) + if(bp->b_data == 0) panic("bp->b_data null incore buf=%x", bp); break; @@ -1021,36 +1132,29 @@ start: SET(bp->b_flags, B_META); queue = BQ_META; } + + bp->b_blkno = bp->b_lblkno = blkno; + bp->b_vp = vp; + /* * Insert in the hash so that incore() can find it */ binshash(bp, BUFHASH(vp, blkno)); + s = splbio(); + bgetvp(vp, bp); + splx(s); + allocbuf(bp, size); switch (operation) { case BLK_META: /* buffer data is invalid */ -#if !ZALLOC_METADATA - if (bp->b_data) - panic("bp->b_data is not nul; %x",bp); - kret = kmem_alloc(kernel_map, - &bp->b_data, bp->b_bufsize); - if (kret != KERN_SUCCESS) - panic("getblk: kmem_alloc() returned %d", kret); -#endif /* ZALLOC_METADATA */ - if(bp->b_data == 0) panic("bp->b_data is null %x",bp); - bp->b_blkno = bp->b_lblkno = blkno; - s = splbio(); - bgetvp(vp, bp); bufstats.bufs_miss++; - splx(s); - if (bp->b_data == 0) - panic("b_data is 0: 2"); /* wakeup the buffer */ CLR(bp->b_flags, B_WANTED); @@ -1075,7 +1179,6 @@ start: #ifdef UBC_DEBUG upl_ubc_alias_set(upl, bp, 4); #endif /* UBC_DEBUG */ - bp->b_blkno = bp->b_lblkno = blkno; bp->b_pagelist = upl; SET(bp->b_flags, B_PAGELIST); @@ -1129,8 +1232,9 @@ start: bp->b_dirtyend = 0; } } - if (error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL)) { - panic("VOP_BMAP failed in getblk"); + error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL); + if(error) { + panic("getblk: VOP_BMAP failed"); /*NOTREACHED*/ /* * XXX: We probably should invalidate the VM Page @@ -1150,11 +1254,8 @@ start: panic("getblk: ubc_upl_map() " "failed with (%d)", kret); } - if (bp->b_data == 0) panic("kernel_upl_map mapped 0"); - - s = splbio(); - bgetvp(vp, bp); - splx(s); + if (bp->b_data == 0) + panic("kernel_upl_map mapped 0"); break; @@ -1173,9 +1274,7 @@ start: panic("getblk: bp->b_addr is null"); if (bp->b_bufsize & 0xfff) { -#if ZALLOC_METADATA if (ISSET(bp->b_flags, B_META) && (bp->b_bufsize & 0x1ff)) -#endif /* ZALLOC_METADATA */ panic("getblk: bp->b_bufsize = %d", bp->b_bufsize); } @@ -1194,34 +1293,16 @@ geteblk(size) { struct buf *bp; int queue = BQ_EMPTY; -#if !ZALLOC_METADATA - kern_return_t kret; - vm_size_t desired_size = roundup(size, CLBYTES); - - if (desired_size > MAXBSIZE) - panic("geteblk: buffer larger than MAXBSIZE requested"); -#endif /* ZALLOC_METADATA */ while ((bp = getnewbuf(0, 0, &queue)) == 0) ; -#if ZALLOC_METADATA SET(bp->b_flags, (B_META|B_INVAL)); -#else - SET(bp->b_flags, B_INVAL); -#endif /* ZALLOC_METADATA */ #if DIAGNOSTIC assert(queue == BQ_EMPTY); #endif /* DIAGNOSTIC */ /* XXX need to implement logic to deal with other queues */ -#if !ZALLOC_METADATA - /* Empty buffer - allocate pages */ - kret = kmem_alloc_aligned(kernel_map, &bp->b_data, desired_size); - if (kret != KERN_SUCCESS) - panic("geteblk: kmem_alloc_aligned returned %d", kret); -#endif /* ZALLOC_METADATA */ - binshash(bp, &invalhash); allocbuf(bp, size); bufstats.bufs_eblk++; @@ -1229,7 +1310,6 @@ geteblk(size) return (bp); } -#if ZALLOC_METADATA /* * Zones for the meta data buffers */ @@ -1247,15 +1327,10 @@ struct meta_zone_entry { struct meta_zone_entry meta_zones[] = { {NULL, (MINMETA * 1), 128 * (MINMETA * 1), "buf.512" }, {NULL, (MINMETA * 2), 64 * (MINMETA * 2), "buf.1024" }, - {NULL, (MINMETA * 3), 16 * (MINMETA * 3), "buf.1536" }, {NULL, (MINMETA * 4), 16 * (MINMETA * 4), "buf.2048" }, - {NULL, (MINMETA * 5), 16 * (MINMETA * 5), "buf.2560" }, - {NULL, (MINMETA * 6), 16 * (MINMETA * 6), "buf.3072" }, - {NULL, (MINMETA * 7), 16 * (MINMETA * 7), "buf.3584" }, {NULL, (MINMETA * 8), 512 * (MINMETA * 8), "buf.4096" }, {NULL, 0, 0, "" } /* End */ }; -#endif /* ZALLOC_METADATA */ /* * Initialize the meta data zones @@ -1263,7 +1338,6 @@ struct meta_zone_entry meta_zones[] = { static void bufzoneinit(void) { -#if ZALLOC_METADATA int i; for (i = 0; meta_zones[i].mz_size != 0; i++) { @@ -1273,23 +1347,24 @@ bufzoneinit(void) PAGE_SIZE, meta_zones[i].mz_name); } -#endif /* ZALLOC_METADATA */ buf_hdr_zone = zinit(sizeof(struct buf), 32, PAGE_SIZE, "buf headers"); } -#if ZALLOC_METADATA -static zone_t +static __inline__ zone_t getbufzone(size_t size) { int i; - if (size % 512) + if ((size % 512) || (size < MINMETA) || (size > MAXMETA)) panic("getbufzone: incorect size = %d", size); - i = (size / 512) - 1; + for (i = 0; meta_zones[i].mz_size != 0; i++) { + if (meta_zones[i].mz_size >= size) + break; + } + return (meta_zones[i].mz_zone); } -#endif /* ZALLOC_METADATA */ /* * With UBC, there is no need to expand / shrink the file data @@ -1317,7 +1392,6 @@ allocbuf(bp, size) if (desired_size > MAXBSIZE) panic("allocbuf: buffer larger than MAXBSIZE requested"); -#if ZALLOC_METADATA if (ISSET(bp->b_flags, B_META)) { kern_return_t kret; zone_t zprev, z; @@ -1378,10 +1452,10 @@ allocbuf(bp, size) if (ISSET(bp->b_flags, B_META) && (bp->b_data == 0)) panic("allocbuf: bp->b_data is NULL"); -#endif /* ZALLOC_METADATA */ - bp->b_bufsize = desired_size; - bp->b_bcount = size; + bp->b_bufsize = desired_size; + bp->b_bcount = size; + return (0); } /* @@ -1413,7 +1487,6 @@ getnewbuf(slpflag, slptimeo, queue) register struct buf *meta_bp; register int age_time, lru_time, bp_time, meta_time; int s; - struct ucred *cred; int req = *queue; /* save it for restarts */ start: @@ -1437,8 +1510,11 @@ start: lru_bp = bufqueues[BQ_LRU].tqh_first; meta_bp = bufqueues[BQ_META].tqh_first; - if (!age_bp && !lru_bp && !meta_bp) { /* Unavailble on AGE or LRU */ - /* Try the empty list first */ + if (!age_bp && !lru_bp && !meta_bp) { + /* + * Unavailble on AGE or LRU or META queues + * Try the empty list first + */ bp = bufqueues[BQ_EMPTY].tqh_first; if (bp) { *queue = BQ_EMPTY; @@ -1543,8 +1619,10 @@ found: splx(s); return (bp); } + #include #include +#include /* * Clean a buffer. @@ -1552,7 +1630,7 @@ found: * Returns 1 if issued a bawrite() to indicate * that the buffer is not ready. */ -int +static int bcleanbuf(struct buf *bp) { int s; @@ -1583,6 +1661,8 @@ bcleanbuf(struct buf *bp) binstailfree(bp, &bufqueues[BQ_LAUNDRY], BQ_LAUNDRY); blaundrycnt++; wakeup(&blaundrycnt); + /* and give it a chance to run */ + (void)thread_block(THREAD_CONTINUE_NULL); return (1); } @@ -1594,7 +1674,6 @@ bcleanbuf(struct buf *bp) splx(s); if (ISSET(bp->b_flags, B_META)) { -#if ZALLOC_METADATA vm_offset_t elem = (vm_offset_t)bp->b_data; if (elem == 0) panic("bcleanbuf: NULL bp->b_data B_META buffer"); @@ -1613,12 +1692,6 @@ bcleanbuf(struct buf *bp) bp->b_data = (caddr_t)0xdeadbeef; kmem_free(kernel_map, elem, bp->b_bufsize); } -#else - if (bp->b_data == 0) - panic("bcleanbuf: bp->b_data == NULL for B_META buffer"); - - kmem_free(kernel_map, bp->b_data, bp->b_bufsize); -#endif /* ZALLOC_METADATA */ } trace(TR_BRELSE, pack(bp->b_vp, bp->b_bufsize), bp->b_lblkno); @@ -1665,10 +1738,7 @@ int biowait(bp) struct buf *bp; { - upl_t upl; - upl_page_info_t *pl; int s; - kern_return_t kret; s = splbio(); while (!ISSET(bp->b_flags, B_DONE)) @@ -1724,7 +1794,24 @@ biodone(bp) if (!ISSET(bp->b_flags, B_READ) && !ISSET(bp->b_flags, B_RAW)) vwakeup(bp); /* wake up reader */ - + + if (kdebug_enable) { + int code = DKIO_DONE; + + if (bp->b_flags & B_READ) + code |= DKIO_READ; + if (bp->b_flags & B_ASYNC) + code |= DKIO_ASYNC; + + if (bp->b_flags & B_META) + code |= DKIO_META; + else if (bp->b_flags & (B_PGIN | B_PAGEOUT)) + code |= DKIO_PAGING; + + KERNEL_DEBUG_CONSTANT(FSDBG_CODE(DBG_DKRW, code) | DBG_FUNC_NONE, + bp, bp->b_vp, bp->b_resid, bp->b_error, 0); + } + /* Wakeup the throttled write operations as needed */ vp = bp->b_vp; if (vp @@ -1780,7 +1867,7 @@ count_busy_buffers() return (nbusy); } -#if 1 /*DIAGNOSTIC */ +#if DIAGNOSTIC /* * Print out statistics on the current allocation of the buffer pool. * Can be enabled to print out on every ``sync'' by setting "syncprt" @@ -1815,9 +1902,9 @@ vfs_bufstats() } #endif /* DIAGNOSTIC */ -#define NRESERVEDIOBUFS 16 +#define NRESERVEDIOBUFS 64 -struct buf * +__private_extern__ struct buf * alloc_io_buf(vp, priv) struct vnode *vp; int priv; @@ -1864,7 +1951,7 @@ alloc_io_buf(vp, priv) return (bp); } -void +__private_extern__ void free_io_buf(bp) struct buf *bp; { @@ -1886,8 +1973,7 @@ free_io_buf(bp) splx(s); } - -/* not hookedup yet */ +/* disabled for now */ /* XXX move this to a separate file */ /* @@ -1978,19 +2064,18 @@ struct bufqlim { long bufqscanwait = 0; -extern void bufqscan_thread(); -extern int balancebufq(int q); -extern int btrimempty(int n); -extern int initbufqscan(void); -extern int nextbufq(int q); -extern void buqlimprt(int all); +static void bufqscan_thread(); +static int balancebufq(int q); +static int btrimempty(int n); +static __inline__ int initbufqscan(void); +static __inline__ int nextbufq(int q); +static void buqlimprt(int all); -void +static void bufq_balance_thread_init() { if (bufqscanwait++ == 0) { - int i; /* Initalize globals */ MAXNBUF = (mem_size / PAGE_SIZE); @@ -2049,7 +2134,7 @@ bufq_balance_thread_init() } /* The workloop for the buffer balancing thread */ -void +static void bufqscan_thread() { boolean_t funnel_state; @@ -2061,13 +2146,14 @@ bufqscan_thread() do { int q; /* buffer queue to process */ - for (q = initbufqscan(); q; ) { + q = initbufqscan(); + for (; q; ) { moretodo |= balancebufq(q); q = nextbufq(q); } } while (moretodo); -#if 1 || DIAGNOSTIC +#if DIAGNOSTIC vfs_bufstats(); buqlimprt(0); #endif @@ -2079,7 +2165,7 @@ bufqscan_thread() } /* Seed for the buffer queue balancing */ -int +static __inline__ int initbufqscan() { /* Start with AGE queue */ @@ -2087,7 +2173,7 @@ initbufqscan() } /* Pick next buffer queue to balance */ -int +static __inline__ int nextbufq(int q) { int order[] = { BQ_AGE, BQ_LRU, BQ_META, BQ_EMPTY, 0 }; @@ -2098,7 +2184,7 @@ nextbufq(int q) } /* function to balance the buffer queues */ -int +static int balancebufq(int q) { int moretodo = 0; @@ -2154,7 +2240,7 @@ out: return (moretodo); } -int +static int btrimempty(int n) { /* @@ -2165,7 +2251,7 @@ btrimempty(int n) return (0); } -void +static __inline__ void bufqinc(int q) { if ((q < 0) || (q >= BQUEUES)) @@ -2175,7 +2261,7 @@ bufqinc(int q) return; } -void +static __inline__ void bufqdec(int q) { if ((q < 0) || (q >= BQUEUES)) @@ -2185,7 +2271,7 @@ bufqdec(int q) return; } -void +static void buqlimprt(int all) { int i; @@ -2195,16 +2281,16 @@ buqlimprt(int all) if (all) for (i = 0; i < BQUEUES; i++) { printf("%s : ", bname[i]); - printf("min = %d, ", (long)bufqlim[i].bl_nlow); - printf("cur = %d, ", (long)bufqlim[i].bl_num); - printf("max = %d, ", (long)bufqlim[i].bl_nlhigh); - printf("target = %d, ", (long)bufqlim[i].bl_target); - printf("stale after %d seconds\n", bufqlim[i].bl_stale); + printf("min = %ld, ", (long)bufqlim[i].bl_nlow); + printf("cur = %ld, ", (long)bufqlim[i].bl_num); + printf("max = %ld, ", (long)bufqlim[i].bl_nlhigh); + printf("target = %ld, ", (long)bufqlim[i].bl_target); + printf("stale after %ld seconds\n", bufqlim[i].bl_stale); } else for (i = 0; i < BQUEUES; i++) { printf("%s : ", bname[i]); - printf("cur = %d, ", (long)bufqlim[i].bl_num); + printf("cur = %ld, ", (long)bufqlim[i].bl_num); } } @@ -2228,6 +2314,8 @@ bcleanbuf_thread() { boolean_t funnel_state; struct buf *bp; + int error = 0; + int loopcnt = 0; funnel_state = thread_funnel_set(kernel_flock, TRUE); @@ -2239,10 +2327,20 @@ doit: bremfree(bp); blaundrycnt--; /* do the IO */ - bawrite(bp); + error = bawrite_internal(bp, 0); + if (error) { + binstailfree(bp, &bufqueues[BQ_LAUNDRY], BQ_LAUNDRY); + blaundrycnt++; + if (loopcnt > 10) { + (void)tsleep((void *)&blaundrycnt, PRIBIO, "blaundry", 1); + loopcnt = 0; + } else { + (void)thread_block(THREAD_CONTINUE_NULL); + loopcnt++; + } + } /* start again */ goto doit; (void) thread_funnel_set(kernel_flock, funnel_state); } - diff --git a/bsd/vfs/vfs_cluster.c b/bsd/vfs/vfs_cluster.c index 07f0dbbd5..fc7004638 100644 --- a/bsd/vfs/vfs_cluster.c +++ b/bsd/vfs/vfs_cluster.c @@ -1,5 +1,6 @@ + /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -73,7 +74,6 @@ #define CL_READ 0x01 #define CL_ASYNC 0x02 #define CL_COMMIT 0x04 -#define CL_NOMAP 0x08 #define CL_PAGEOUT 0x10 #define CL_AGE 0x20 #define CL_DUMP 0x40 @@ -81,6 +81,24 @@ #define CL_PAGEIN 0x100 #define CL_DEV_MEMORY 0x200 +static void cluster_zero(upl_t upl, vm_offset_t upl_offset, + int size, struct buf *bp); +static int cluster_read_x(struct vnode *vp, struct uio *uio, + off_t filesize, int devblocksize, int flags); +static int cluster_write_x(struct vnode *vp, struct uio *uio, + off_t oldEOF, off_t newEOF, off_t headOff, + off_t tailOff, int devblocksize, int flags); +static int cluster_nocopy_read(struct vnode *vp, struct uio *uio, + off_t filesize, int devblocksize, int flags); +static int cluster_nocopy_write(struct vnode *vp, struct uio *uio, + off_t newEOF, int devblocksize, int flags); +static int cluster_phys_read(struct vnode *vp, struct uio *uio, + off_t filesize); +static int cluster_phys_write(struct vnode *vp, struct uio *uio); +static int cluster_push_x(struct vnode *vp, off_t EOF, daddr_t first, daddr_t last, int can_delay); +static int cluster_try_push(struct vnode *vp, off_t newEOF, int can_delay, int push_all); + + /* * throttle the number of async writes that * can be outstanding on a single vnode @@ -97,6 +115,7 @@ cluster_iodone(bp) int total_size; int total_resid; int upl_offset; + int zero_offset; upl_t upl; struct buf *cbp; struct buf *cbp_head; @@ -110,7 +129,7 @@ cluster_iodone(bp) cbp_head = (struct buf *)(bp->b_trans_head); KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 20)) | DBG_FUNC_START, - cbp_head, bp->b_lblkno, bp->b_bcount, bp->b_flags, 0); + (int)cbp_head, bp->b_lblkno, bp->b_bcount, bp->b_flags, 0); for (cbp = cbp_head; cbp; cbp = cbp->b_trans_next) { /* @@ -120,7 +139,7 @@ cluster_iodone(bp) if ( !(cbp->b_flags & B_DONE)) { KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 20)) | DBG_FUNC_END, - cbp_head, cbp, cbp->b_bcount, cbp->b_flags, 0); + (int)cbp_head, (int)cbp, cbp->b_bcount, cbp->b_flags, 0); return 0; } @@ -135,6 +154,7 @@ cluster_iodone(bp) b_flags = cbp->b_flags; real_bp = cbp->b_real_bp; vp = cbp->b_vp; + zero_offset= cbp->b_validend; while (cbp) { if (cbp->b_vectorcount > 1) @@ -156,6 +176,9 @@ cluster_iodone(bp) vp->v_flag &= ~VTHROTTLED; wakeup((caddr_t)&vp->v_numoutput); } + if (zero_offset) + cluster_zero(upl, zero_offset, PAGE_SIZE - (zero_offset & PAGE_MASK), real_bp); + if ((b_flags & B_NEED_IODONE) && real_bp) { if (error) { real_bp->b_flags |= B_ERROR; @@ -175,7 +198,7 @@ cluster_iodone(bp) if (error || (b_flags & B_NOCACHE)) { int upl_abort_code; - if (b_flags & B_PAGEOUT) + if ((b_flags & B_PAGEOUT) && (error != ENXIO)) /* transient error */ upl_abort_code = UPL_ABORT_FREE_ON_EMPTY; else if (b_flags & B_PGIN) upl_abort_code = UPL_ABORT_FREE_ON_EMPTY | UPL_ABORT_ERROR; @@ -186,7 +209,7 @@ cluster_iodone(bp) upl_abort_code); KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 20)) | DBG_FUNC_END, - upl, upl_offset - pg_offset, commit_size, + (int)upl, upl_offset - pg_offset, commit_size, 0x80000000|upl_abort_code, 0); } else { @@ -201,40 +224,45 @@ cluster_iodone(bp) upl_commit_flags); KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 20)) | DBG_FUNC_END, - upl, upl_offset - pg_offset, commit_size, + (int)upl, upl_offset - pg_offset, commit_size, upl_commit_flags, 0); } } else KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 20)) | DBG_FUNC_END, - upl, upl_offset, 0, error, 0); + (int)upl, upl_offset, 0, error, 0); return (error); } static void -cluster_zero(upl, upl_offset, size, flags, bp) +cluster_zero(upl, upl_offset, size, bp) upl_t upl; vm_offset_t upl_offset; int size; - int flags; struct buf *bp; { vm_offset_t io_addr = 0; + int must_unmap = 0; kern_return_t kret; - if ( !(flags & CL_NOMAP)) { + KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 23)) | DBG_FUNC_NONE, + upl_offset, size, (int)bp, 0, 0); + + if (bp == NULL || bp->b_data == NULL) { kret = ubc_upl_map(upl, &io_addr); if (kret != KERN_SUCCESS) panic("cluster_zero: ubc_upl_map() failed with (%d)", kret); if (io_addr == 0) panic("cluster_zero: ubc_upl_map() mapped 0"); + + must_unmap = 1; } else io_addr = (vm_offset_t)bp->b_data; bzero((caddr_t)(io_addr + upl_offset), size); - if ( !(flags & CL_NOMAP)) { + if (must_unmap) { kret = ubc_upl_unmap(upl); if (kret != KERN_SUCCESS) @@ -243,28 +271,32 @@ cluster_zero(upl, upl_offset, size, flags, bp) } static int -cluster_io(vp, upl, upl_offset, f_offset, size, flags, real_bp) +cluster_io(vp, upl, upl_offset, f_offset, non_rounded_size, devblocksize, flags, real_bp) struct vnode *vp; upl_t upl; vm_offset_t upl_offset; off_t f_offset; - int size; + int non_rounded_size; + int devblocksize; int flags; struct buf *real_bp; { struct buf *cbp; struct iovec *iovp; + u_int size; int io_flags; int error = 0; int retval = 0; struct buf *cbp_head = 0; struct buf *cbp_tail = 0; upl_page_info_t *pl; + int buf_count = 0; int pg_count; int pg_offset; - int max_iosize; - int max_vectors; + u_int max_iosize; + u_int max_vectors; int priv; + int zero_offset = 0; if (flags & CL_READ) { io_flags = (B_VECTORLIST | B_READ); @@ -286,11 +318,16 @@ cluster_io(vp, upl, upl_offset, f_offset, size, flags, real_bp) if (flags & CL_PAGEIN) io_flags |= B_PGIN; + if (devblocksize) + size = (non_rounded_size + (devblocksize - 1)) & ~(devblocksize - 1); + else + size = non_rounded_size; + KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 22)) | DBG_FUNC_START, (int)f_offset, size, upl_offset, flags, 0); - if ((flags & CL_READ) && ((upl_offset + size) & PAGE_MASK) && (!(flags & CL_NOZERO))) { + if ((flags & CL_READ) && ((upl_offset + non_rounded_size) & PAGE_MASK) && (!(flags & CL_NOZERO))) { /* * then we are going to end up * with a page that we can't complete (the file size wasn't a multiple @@ -298,11 +335,7 @@ cluster_io(vp, upl, upl_offset, f_offset, size, flags, real_bp) * so we'll go ahead and zero out the portion of the page we can't * read in from the file */ - cluster_zero(upl, upl_offset + size, PAGE_SIZE - ((upl_offset + size) & PAGE_MASK), flags, real_bp); - - KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 23)) | DBG_FUNC_NONE, - upl_offset + size, PAGE_SIZE - ((upl_offset + size) & PAGE_MASK), - flags, real_bp, 0); + zero_offset = upl_offset + non_rounded_size; } while (size) { size_t io_size; @@ -326,7 +359,7 @@ cluster_io(vp, upl, upl_offset, f_offset, size, flags, real_bp) } KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 24)) | DBG_FUNC_NONE, - (int)f_offset, (int)blkno, io_size, 0, 0); + (int)f_offset, (int)blkno, io_size, zero_offset, 0); if ( (!(flags & CL_READ) && (long)blkno == -1) || io_size == 0) { if (flags & CL_PAGEOUT) { @@ -375,19 +408,56 @@ cluster_io(vp, upl, upl_offset, f_offset, size, flags, real_bp) pg_count = 1; } if ((flags & CL_READ) && (long)blkno == -1) { + int bytes_to_zero; + /* * if we're reading and blkno == -1, then we've got a * 'hole' in the file that we need to deal with by zeroing * out the affected area in the upl */ - cluster_zero(upl, upl_offset, io_size, flags, real_bp); - - KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 23)) | DBG_FUNC_NONE, - upl_offset, io_size, flags, real_bp, 0); + if (zero_offset && io_size == size) { + /* + * if this upl contains the EOF and it is not a multiple of PAGE_SIZE + * than 'zero_offset' will be non-zero + * if the 'hole' returned by VOP_CMAP extends all the way to the eof + * (indicated by the io_size finishing off the I/O request for this UPL) + * than we're not going to issue an I/O for the + * last page in this upl... we need to zero both the hole and the tail + * of the page beyond the EOF, since the delayed zero-fill won't kick in + */ + bytes_to_zero = (((upl_offset + io_size) + (PAGE_SIZE - 1)) & ~PAGE_MASK) - upl_offset; - pg_count = (io_size - pg_offset) / PAGE_SIZE; + zero_offset = 0; + } else + bytes_to_zero = io_size; + cluster_zero(upl, upl_offset, bytes_to_zero, real_bp); + + if (cbp_head) + /* + * if there is a current I/O chain pending + * then the first page of the group we just zero'd + * will be handled by the I/O completion if the zero + * fill started in the middle of the page + */ + pg_count = (io_size - pg_offset) / PAGE_SIZE; + else { + /* + * no pending I/O to pick up that first page + * so, we have to make sure it gets committed + * here. + * set the pg_offset to 0 so that the upl_commit_range + * starts with this page + */ + pg_count = (io_size + pg_offset) / PAGE_SIZE; + pg_offset = 0; + } if (io_size == size && ((upl_offset + io_size) & PAGE_MASK)) + /* + * if we're done with the request for this UPL + * then we have to make sure to commit the last page + * even if we only partially zero-filled it + */ pg_count++; if (pg_count) { @@ -395,9 +465,10 @@ cluster_io(vp, upl, upl_offset, f_offset, size, flags, real_bp) pg_resid = PAGE_SIZE - pg_offset; else pg_resid = 0; + if (flags & CL_COMMIT) ubc_upl_commit_range(upl, - upl_offset + pg_resid, + (upl_offset + pg_resid) & ~PAGE_MASK, pg_count * PAGE_SIZE, UPL_COMMIT_CLEAR_DIRTY | UPL_COMMIT_FREE_ON_EMPTY); } @@ -405,9 +476,10 @@ cluster_io(vp, upl, upl_offset, f_offset, size, flags, real_bp) f_offset += io_size; size -= io_size; - if (cbp_head && pg_count) + if (cbp_head && pg_count) goto start_io; continue; + } else if (real_bp && (real_bp->b_blkno == real_bp->b_lblkno)) { real_bp->b_blkno = blkno; } @@ -541,18 +613,21 @@ cluster_io(vp, upl, upl_offset, f_offset, size, flags, real_bp) cbp_tail = cbp; } (struct buf *)(cbp->b_trans_head) = cbp_head; + buf_count++; upl_offset += io_size; f_offset += io_size; size -= io_size; - if ( (!(upl_offset & PAGE_MASK) && !(flags & CL_DEV_MEMORY)) || size == 0) { + if ( (!(upl_offset & PAGE_MASK) && !(flags & CL_DEV_MEMORY) && ((flags & CL_ASYNC) || buf_count > 8)) || size == 0) { /* * if we have no more I/O to issue or * the current I/O we've prepared fully * completes the last page in this request - * or it's been completed via a zero-fill - * due to a 'hole' in the file + * and it's either an ASYNC request or + * we've already accumulated more than 8 I/O's into + * this transaction and it's not an I/O directed to + * special DEVICE memory * then go ahead and issue the I/O */ start_io: @@ -566,8 +641,20 @@ start_io: if (real_bp) { cbp_head->b_flags |= B_NEED_IODONE; cbp_head->b_real_bp = real_bp; - } + } else + cbp_head->b_real_bp = (struct buf *)NULL; + if (size == 0) { + /* + * we're about to issue the last I/O for this upl + * if this was a read to the eof and the eof doesn't + * finish on a page boundary, than we need to zero-fill + * the rest of the page.... + */ + cbp_head->b_validend = zero_offset; + } else + cbp_head->b_validend = 0; + for (cbp = cbp_head; cbp;) { struct buf * cbp_next; @@ -575,7 +662,7 @@ start_io: cbp->b_vp->v_numoutput++; cbp_next = cbp->b_trans_next; - + (void) VOP_STRATEGY(cbp); cbp = cbp_next; } @@ -584,12 +671,17 @@ start_io: biowait(cbp); if (error = cluster_iodone(cbp_head)) { - retval = error; + if ((flags & CL_PAGEOUT) && (error == ENXIO)) + retval = 0; /* drop the error */ + else + retval = error; error = 0; } } cbp_head = (struct buf *)0; cbp_tail = (struct buf *)0; + + buf_count = 0; } } if (error) { @@ -613,7 +705,7 @@ start_io: if (flags & CL_COMMIT) { int upl_abort_code; - if (flags & CL_PAGEOUT) + if ((flags & CL_PAGEOUT) && (error != ENXIO)) /* transient error */ upl_abort_code = UPL_ABORT_FREE_ON_EMPTY; else if (flags & CL_PAGEIN) upl_abort_code = UPL_ABORT_FREE_ON_EMPTY | UPL_ABORT_ERROR; @@ -624,7 +716,7 @@ start_io: upl_abort_code); KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 28)) | DBG_FUNC_NONE, - upl, upl_offset - pg_offset, abort_size, error, 0); + (int)upl, upl_offset - pg_offset, abort_size, error, 0); } if (real_bp) { real_bp->b_flags |= B_ERROR; @@ -650,14 +742,8 @@ cluster_rd_prefetch(vp, f_offset, size, filesize, devblocksize) off_t filesize; int devblocksize; { - upl_t upl; - upl_page_info_t *pl; - int pages_in_upl; - int start_pg; - int last_pg; - int last_valid; - int io_size; - + int pages_to_fetch; + int skipped_pages; KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 49)) | DBG_FUNC_START, (int)f_offset, size, (int)filesize, 0, 0); @@ -667,108 +753,29 @@ cluster_rd_prefetch(vp, f_offset, size, filesize, devblocksize) (int)f_offset, 0, 0, 0, 0); return(0); } - if (ubc_page_op(vp, f_offset, 0, 0, 0) == KERN_SUCCESS) { - KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 49)) | DBG_FUNC_END, - (int)f_offset, 0, 0, 0, 0); - return(1); - } if (size > (MAX_UPL_TRANSFER * PAGE_SIZE)) size = MAX_UPL_TRANSFER * PAGE_SIZE; else size = (size + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); - if ((off_t)size > (filesize - f_offset)) - size = ((filesize - f_offset) + (devblocksize - 1)) & ~(devblocksize - 1); + if ((off_t)size > (filesize - f_offset)) + size = filesize - f_offset; - pages_in_upl = (size + (PAGE_SIZE - 1)) / PAGE_SIZE; - - ubc_create_upl(vp, - f_offset, - pages_in_upl * PAGE_SIZE, - &upl, - &pl, - UPL_FLAGS_NONE); + pages_to_fetch = (size + (PAGE_SIZE - 1)) / PAGE_SIZE; - if (upl == (upl_t) 0) - return(0); - - /* - * scan from the beginning of the upl looking for the first - * non-valid page.... this will become the first page in - * the request we're going to make to 'cluster_io'... if all - * of the pages are valid, we won't call through to 'cluster_io' - */ - for (start_pg = 0; start_pg < pages_in_upl; start_pg++) { - if (!upl_valid_page(pl, start_pg)) + for (skipped_pages = 0; skipped_pages < pages_to_fetch; skipped_pages++) { + if (ubc_page_op(vp, f_offset, 0, 0, 0) != KERN_SUCCESS) break; + f_offset += PAGE_SIZE; + size -= PAGE_SIZE; } - - /* - * scan from the starting invalid page looking for a valid - * page before the end of the upl is reached, if we - * find one, then it will be the last page of the request to - * 'cluster_io' - */ - for (last_pg = start_pg; last_pg < pages_in_upl; last_pg++) { - if (upl_valid_page(pl, last_pg)) - break; - } - - /* - * if we find any more free valid pages at the tail of the upl - * than update maxra accordingly.... - */ - for (last_valid = last_pg; last_valid < pages_in_upl; last_valid++) { - if (!upl_valid_page(pl, last_valid)) - break; - } - if (start_pg < last_pg) { - vm_offset_t upl_offset; - - /* - * we found a range of 'invalid' pages that must be filled - * 'size' has already been clipped to the LEOF - * make sure it's at least a multiple of the device block size - */ - upl_offset = start_pg * PAGE_SIZE; - io_size = (last_pg - start_pg) * PAGE_SIZE; - - if ((upl_offset + io_size) > size) { - io_size = size - upl_offset; - - KERNEL_DEBUG(0xd001000, upl_offset, size, io_size, 0, 0); - } - cluster_io(vp, upl, upl_offset, f_offset + upl_offset, io_size, - CL_READ | CL_COMMIT | CL_ASYNC | CL_AGE, (struct buf *)0); - } - if (start_pg) { - /* - * start_pg of non-zero indicates we found some already valid pages - * at the beginning of the upl.... we need to release these without - * modifying there state - */ - ubc_upl_abort_range(upl, 0, start_pg * PAGE_SIZE, UPL_ABORT_FREE_ON_EMPTY); - - KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 50)) | DBG_FUNC_NONE, - upl, 0, start_pg * PAGE_SIZE, 0, 0); - } - if (last_pg < pages_in_upl) { - /* - * the set of pages that we issued an I/O for did not extend all the - * way to the end of the upl... so just release them without modifying - * there state - */ - ubc_upl_abort_range(upl, last_pg * PAGE_SIZE, (pages_in_upl - last_pg) * PAGE_SIZE, - UPL_ABORT_FREE_ON_EMPTY); - - KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 50)) | DBG_FUNC_NONE, - upl, last_pg * PAGE_SIZE, (pages_in_upl - last_pg) * PAGE_SIZE, 0, 0); - } + if (skipped_pages < pages_to_fetch) + advisory_read(vp, filesize, f_offset, size, devblocksize); KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 49)) | DBG_FUNC_END, - (int)f_offset + (last_valid * PAGE_SIZE), 0, 0, 0, 0); + (int)f_offset + (pages_to_fetch * PAGE_SIZE), skipped_pages, 0, 1, 0); - return(last_valid); + return (pages_to_fetch); } @@ -795,7 +802,8 @@ cluster_rd_ahead(vp, b_lblkno, e_lblkno, filesize, devblocksize) return; } - if (vp->v_lastr == -1 || (b_lblkno != vp->v_lastr && b_lblkno != (vp->v_lastr + 1) && b_lblkno != (vp->v_maxra + 1))) { + if (vp->v_lastr == -1 || (b_lblkno != vp->v_lastr && b_lblkno != (vp->v_lastr + 1) && + (b_lblkno != (vp->v_maxra + 1) || vp->v_ralen == 0))) { vp->v_ralen = 0; vp->v_maxra = 0; @@ -812,7 +820,7 @@ cluster_rd_ahead(vp, b_lblkno, e_lblkno, filesize, devblocksize) vp->v_ralen = min(max_pages, (e_lblkno + 1) - b_lblkno); if (e_lblkno < vp->v_maxra) { - if ((vp->v_maxra - e_lblkno) > (max_pages / 4)) { + if ((vp->v_maxra - e_lblkno) > max(max_pages / 16, 4)) { KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 48)) | DBG_FUNC_END, vp->v_ralen, vp->v_maxra, vp->v_lastr, 2, 0); @@ -822,16 +830,17 @@ cluster_rd_ahead(vp, b_lblkno, e_lblkno, filesize, devblocksize) r_lblkno = max(e_lblkno, vp->v_maxra) + 1; f_offset = (off_t)r_lblkno * PAGE_SIZE_64; - size_of_prefetch = cluster_rd_prefetch(vp, f_offset, vp->v_ralen * PAGE_SIZE, filesize, devblocksize); - - if (size_of_prefetch) - vp->v_maxra = r_lblkno + (size_of_prefetch - 1); + if (f_offset < filesize) { + size_of_prefetch = cluster_rd_prefetch(vp, f_offset, vp->v_ralen * PAGE_SIZE, filesize, devblocksize); + if (size_of_prefetch) + vp->v_maxra = (r_lblkno + size_of_prefetch) - 1; + } KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 48)) | DBG_FUNC_END, vp->v_ralen, vp->v_maxra, vp->v_lastr, 3, 0); } - +int cluster_pageout(vp, upl, upl_offset, f_offset, size, filesize, devblocksize, flags) struct vnode *vp; upl_t upl; @@ -852,9 +861,6 @@ cluster_pageout(vp, upl, upl_offset, f_offset, size, filesize, devblocksize, fla if ((flags & UPL_NOCOMMIT) == 0) local_flags |= CL_COMMIT; - if (upl == (upl_t) 0) - panic("cluster_pageout: can't handle NULL upl yet\n"); - KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 52)) | DBG_FUNC_NONE, (int)f_offset, size, (int)filesize, local_flags, 0); @@ -869,8 +875,7 @@ cluster_pageout(vp, upl, upl_offset, f_offset, size, filesize, devblocksize, fla if (vp->v_mount->mnt_flag & MNT_RDONLY) { if (local_flags & CL_COMMIT) - ubc_upl_abort_range(upl, upl_offset, size, - UPL_ABORT_FREE_ON_EMPTY); + ubc_upl_abort_range(upl, upl_offset, size, UPL_ABORT_FREE_ON_EMPTY); return (EROFS); } /* @@ -890,7 +895,7 @@ cluster_pageout(vp, upl, upl_offset, f_offset, size, filesize, devblocksize, fla if (size < max_size) io_size = size; else - io_size = (max_size + (devblocksize - 1)) & ~(devblocksize - 1); + io_size = max_size; pg_size = (io_size + (PAGE_SIZE - 1)) & ~PAGE_MASK; @@ -904,11 +909,11 @@ cluster_pageout(vp, upl, upl_offset, f_offset, size, filesize, devblocksize, fla tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "cluster_pageout", 0); } - return (cluster_io(vp, upl, upl_offset, f_offset, io_size, + return (cluster_io(vp, upl, upl_offset, f_offset, io_size, devblocksize, local_flags, (struct buf *)0)); } - +int cluster_pagein(vp, upl, upl_offset, f_offset, size, filesize, devblocksize, flags) struct vnode *vp; upl_t upl; @@ -920,22 +925,19 @@ cluster_pagein(vp, upl, upl_offset, f_offset, size, filesize, devblocksize, flag int flags; { u_int io_size; - int pg_size; + int rounded_size; off_t max_size; int retval; int local_flags = 0; + if (upl == NULL || size < 0) + panic("cluster_pagein: NULL upl passed in"); - /* - * If they didn't ask for any data, then we are done... - * we can't issue an abort because we don't know how - * big the upl really is - */ - if (size <= 0) - return (EINVAL); - + if ((flags & UPL_IOSYNC) == 0) + local_flags |= CL_ASYNC; if ((flags & UPL_NOCOMMIT) == 0) - local_flags = CL_COMMIT; + local_flags |= CL_COMMIT; + KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 56)) | DBG_FUNC_NONE, (int)f_offset, size, (int)filesize, local_flags, 0); @@ -947,10 +949,9 @@ cluster_pagein(vp, upl, upl_offset, f_offset, size, filesize, devblocksize, flag * or the size requested isn't a multiple of PAGE_SIZE */ if (f_offset < 0 || f_offset >= filesize || - (f_offset & PAGE_MASK_64) || (size & PAGE_MASK)) { - if (local_flags & CL_COMMIT) - ubc_upl_abort_range(upl, upl_offset, size, - UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY); + (f_offset & PAGE_MASK_64) || (size & PAGE_MASK) || (upl_offset & PAGE_MASK)) { + if (local_flags & CL_COMMIT) + ubc_upl_abort_range(upl, upl_offset, size, UPL_ABORT_FREE_ON_EMPTY | UPL_ABORT_ERROR); return (EINVAL); } max_size = filesize - f_offset; @@ -958,32 +959,16 @@ cluster_pagein(vp, upl, upl_offset, f_offset, size, filesize, devblocksize, flag if (size < max_size) io_size = size; else - io_size = (max_size + (devblocksize - 1)) & ~(devblocksize - 1); + io_size = max_size; - pg_size = (io_size + (PAGE_SIZE - 1)) & ~PAGE_MASK; + rounded_size = (io_size + (PAGE_SIZE - 1)) & ~PAGE_MASK; - if (upl == (upl_t) 0) { - ubc_create_upl( vp, - f_offset, - pg_size, - &upl, - NULL, - UPL_FLAGS_NONE); - - if (upl == (upl_t) 0) - return (EINVAL); - - upl_offset = (vm_offset_t)0; - size = pg_size; - } - if (size > pg_size) { - if (local_flags & CL_COMMIT) - ubc_upl_abort_range(upl, upl_offset + pg_size, size - pg_size, - UPL_ABORT_FREE_ON_EMPTY); - } - - retval = cluster_io(vp, upl, upl_offset, f_offset, io_size, - local_flags | CL_READ | CL_PAGEIN, (struct buf *)0); + if (size > rounded_size && (local_flags & CL_COMMIT)) + ubc_upl_abort_range(upl, upl_offset + rounded_size, + size - (upl_offset + rounded_size), UPL_ABORT_FREE_ON_EMPTY | UPL_ABORT_ERROR); + + retval = cluster_io(vp, upl, upl_offset, f_offset, io_size, devblocksize, + local_flags | CL_READ | CL_PAGEIN, (struct buf *)0); if (retval == 0) { int b_lblkno; @@ -993,7 +978,7 @@ cluster_pagein(vp, upl, upl_offset, f_offset, size, filesize, devblocksize, flag e_lblkno = (int) ((f_offset + ((off_t)io_size - 1)) / PAGE_SIZE_64); - if (!(flags & UPL_NORDAHEAD) && !(vp->v_flag & VRAOFF)) { + if (!(flags & UPL_NORDAHEAD) && !(vp->v_flag & VRAOFF) && rounded_size == PAGE_SIZE) { /* * we haven't read the last page in of the file yet * so let's try to read ahead if we're in @@ -1006,26 +991,29 @@ cluster_pagein(vp, upl, upl_offset, f_offset, size, filesize, devblocksize, flag return (retval); } - +int cluster_bp(bp) struct buf *bp; { off_t f_offset; int flags; + KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 19)) | DBG_FUNC_START, + (int)bp, bp->b_lblkno, bp->b_bcount, bp->b_flags, 0); + if (bp->b_pagelist == (upl_t) 0) panic("cluster_bp: can't handle NULL upl yet\n"); if (bp->b_flags & B_READ) - flags = CL_ASYNC | CL_NOMAP | CL_READ; + flags = CL_ASYNC | CL_READ; else - flags = CL_ASYNC | CL_NOMAP; + flags = CL_ASYNC; f_offset = ubc_blktooff(bp->b_vp, bp->b_lblkno); - return (cluster_io(bp->b_vp, bp->b_pagelist, 0, f_offset, bp->b_bcount, flags, bp)); + return (cluster_io(bp->b_vp, bp->b_pagelist, 0, f_offset, bp->b_bcount, 0, flags, bp)); } - +int cluster_write(vp, uio, oldEOF, newEOF, headOff, tailOff, devblocksize, flags) struct vnode *vp; struct uio *uio; @@ -1184,7 +1172,7 @@ cluster_write(vp, uio, oldEOF, newEOF, headOff, tailOff, devblocksize, flags) return(retval); } -static +static int cluster_nocopy_write(vp, uio, newEOF, devblocksize, flags) struct vnode *vp; struct uio *uio; @@ -1231,13 +1219,14 @@ cluster_nocopy_write(vp, uio, newEOF, devblocksize, flags) upl_needed_size = (upl_offset + io_size + (PAGE_SIZE -1)) & ~PAGE_MASK; KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 76)) | DBG_FUNC_START, - (int)upl_offset, upl_needed_size, iov->iov_base, io_size, 0); + (int)upl_offset, upl_needed_size, (int)iov->iov_base, io_size, 0); for (force_data_sync = 0; force_data_sync < 3; force_data_sync++) { pages_in_pl = 0; upl_size = upl_needed_size; - upl_flags = UPL_COPYOUT_FROM | UPL_NO_SYNC | UPL_CLEAN_IN_PLACE | UPL_SET_INTERNAL; + upl_flags = UPL_FILE_IO | UPL_COPYOUT_FROM | UPL_NO_SYNC | + UPL_CLEAN_IN_PLACE | UPL_SET_INTERNAL; kret = vm_map_get_upl(current_map(), (vm_offset_t)iov->iov_base & ~PAGE_MASK, @@ -1294,7 +1283,7 @@ cluster_nocopy_write(vp, uio, newEOF, devblocksize, flags) io_size = (upl_size - (int)upl_offset) & ~PAGE_MASK; KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 76)) | DBG_FUNC_END, - (int)upl_offset, upl_size, iov->iov_base, io_size, 0); + (int)upl_offset, upl_size, (int)iov->iov_base, io_size, 0); if (io_size == 0) { @@ -1336,7 +1325,7 @@ cluster_nocopy_write(vp, uio, newEOF, devblocksize, flags) (int)upl_offset, (int)uio->uio_offset, io_size, 0, 0); error = cluster_io(vp, upl, upl_offset, uio->uio_offset, - io_size, 0, (struct buf *)0); + io_size, devblocksize, 0, (struct buf *)0); if (error == 0) { /* @@ -1371,7 +1360,7 @@ cluster_nocopy_write(vp, uio, newEOF, devblocksize, flags) return (error); } -static +static int cluster_phys_write(vp, uio) struct vnode *vp; struct uio *uio; @@ -1400,7 +1389,8 @@ cluster_phys_write(vp, uio) pages_in_pl = 0; upl_size = upl_needed_size; - upl_flags = UPL_COPYOUT_FROM | UPL_NO_SYNC | UPL_CLEAN_IN_PLACE | UPL_SET_INTERNAL; + upl_flags = UPL_FILE_IO | UPL_COPYOUT_FROM | UPL_NO_SYNC | + UPL_CLEAN_IN_PLACE | UPL_SET_INTERNAL; kret = vm_map_get_upl(current_map(), (vm_offset_t)iov->iov_base & ~PAGE_MASK, @@ -1428,7 +1418,7 @@ cluster_phys_write(vp, uio) */ error = cluster_io(vp, upl, upl_offset, uio->uio_offset, - io_size, CL_DEV_MEMORY, (struct buf *)0); + io_size, 0, CL_DEV_MEMORY, (struct buf *)0); if (error == 0) { /* @@ -1449,7 +1439,7 @@ cluster_phys_write(vp, uio) return (error); } -static +static int cluster_write_x(vp, uio, oldEOF, newEOF, headOff, tailOff, devblocksize, flags) struct vnode *vp; struct uio *uio; @@ -1469,7 +1459,6 @@ cluster_write_x(vp, uio, oldEOF, newEOF, headOff, tailOff, devblocksize, flags) int start_offset; int xfer_resid; int io_size; - int io_size_before_rounding; int io_flags; vm_offset_t io_address; int io_offset; @@ -1585,7 +1574,7 @@ cluster_write_x(vp, uio, oldEOF, newEOF, headOff, tailOff, devblocksize, flags) panic("cluster_write: failed to get pagelist"); KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 41)) | DBG_FUNC_NONE, - upl, (int)upl_f_offset, upl_size, start_offset, 0); + (int)upl, (int)upl_f_offset, upl_size, start_offset, 0); if (start_offset && !upl_valid_page(pl, 0)) { int read_size; @@ -1597,11 +1586,10 @@ cluster_write_x(vp, uio, oldEOF, newEOF, headOff, tailOff, devblocksize, flags) */ read_size = PAGE_SIZE; - if ((upl_f_offset + read_size) > newEOF) { + if ((upl_f_offset + read_size) > newEOF) read_size = newEOF - upl_f_offset; - read_size = (read_size + (devblocksize - 1)) & ~(devblocksize - 1); - } - retval = cluster_io(vp, upl, 0, upl_f_offset, read_size, + + retval = cluster_io(vp, upl, 0, upl_f_offset, read_size, devblocksize, CL_READ, (struct buf *)0); if (retval) { /* @@ -1611,10 +1599,10 @@ cluster_write_x(vp, uio, oldEOF, newEOF, headOff, tailOff, devblocksize, flags) * there state and mark the failed page in error */ ubc_upl_abort_range(upl, 0, PAGE_SIZE, UPL_ABORT_DUMP_PAGES); - ubc_upl_abort(upl, 0); + ubc_upl_abort_range(upl, 0, upl_size, UPL_ABORT_FREE_ON_EMPTY); KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 45)) | DBG_FUNC_NONE, - upl, 0, 0, retval, 0); + (int)upl, 0, 0, retval, 0); break; } } @@ -1632,11 +1620,10 @@ cluster_write_x(vp, uio, oldEOF, newEOF, headOff, tailOff, devblocksize, flags) read_size = PAGE_SIZE; - if ((upl_f_offset + upl_offset + read_size) > newEOF) { + if ((upl_f_offset + upl_offset + read_size) > newEOF) read_size = newEOF - (upl_f_offset + upl_offset); - read_size = (read_size + (devblocksize - 1)) & ~(devblocksize - 1); - } - retval = cluster_io(vp, upl, upl_offset, upl_f_offset + upl_offset, read_size, + + retval = cluster_io(vp, upl, upl_offset, upl_f_offset + upl_offset, read_size, devblocksize, CL_READ, (struct buf *)0); if (retval) { /* @@ -1645,12 +1632,11 @@ cluster_write_x(vp, uio, oldEOF, newEOF, headOff, tailOff, devblocksize, flags) * need to release the rest of the pages in the upl without * modifying there state and mark the failed page in error */ - ubc_upl_abort_range(upl, upl_offset, PAGE_SIZE, - UPL_ABORT_DUMP_PAGES); - ubc_upl_abort(upl, 0); + ubc_upl_abort_range(upl, upl_offset, PAGE_SIZE, UPL_ABORT_DUMP_PAGES); + ubc_upl_abort_range(upl, 0, upl_size, UPL_ABORT_FREE_ON_EMPTY); KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 45)) | DBG_FUNC_NONE, - upl, 0, 0, retval, 0); + (int)upl, 0, 0, retval, 0); break; } } @@ -1667,21 +1653,32 @@ cluster_write_x(vp, uio, oldEOF, newEOF, headOff, tailOff, devblocksize, flags) else bytes_to_zero = xfer_resid; - if ( !(flags & IO_NOZEROVALID)) { + if ( !(flags & (IO_NOZEROVALID | IO_NOZERODIRTY))) { bzero((caddr_t)(io_address + io_offset), bytes_to_zero); KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 43)) | DBG_FUNC_NONE, (int)upl_f_offset + io_offset, bytes_to_zero, - (int)zero_cnt, xfer_resid, 0); + (int)io_offset, xfer_resid, 0); } else { + int zero_pg_index; + bytes_to_zero = min(bytes_to_zero, PAGE_SIZE - (int)(zero_off & PAGE_MASK_64)); + zero_pg_index = (int)((zero_off - upl_f_offset) / PAGE_SIZE_64); + + if ( !upl_valid_page(pl, zero_pg_index)) { + bzero((caddr_t)(io_address + io_offset), bytes_to_zero); + + KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 43)) | DBG_FUNC_NONE, + (int)upl_f_offset + io_offset, bytes_to_zero, + (int)io_offset, xfer_resid, 0); - if ( !upl_valid_page(pl, (int)(zero_off / PAGE_SIZE_64))) { + } else if ((flags & (IO_NOZERODIRTY | IO_NOZEROVALID)) == IO_NOZERODIRTY && + !upl_dirty_page(pl, zero_pg_index)) { bzero((caddr_t)(io_address + io_offset), bytes_to_zero); KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 43)) | DBG_FUNC_NONE, (int)upl_f_offset + io_offset, bytes_to_zero, - (int)zero_cnt, xfer_resid, 0); + (int)io_offset, xfer_resid, 0); } } xfer_resid -= bytes_to_zero; @@ -1697,13 +1694,15 @@ cluster_write_x(vp, uio, oldEOF, newEOF, headOff, tailOff, devblocksize, flags) retval = uiomove((caddr_t)(io_address + io_offset), bytes_to_move, uio); + if (retval) { if ((kret = ubc_upl_unmap(upl)) != KERN_SUCCESS) panic("cluster_write: kernel_upl_unmap failed\n"); - ubc_upl_abort(upl, UPL_ABORT_DUMP_PAGES); + + ubc_upl_abort_range(upl, 0, upl_size, UPL_ABORT_DUMP_PAGES | UPL_ABORT_FREE_ON_EMPTY); KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 45)) | DBG_FUNC_NONE, - upl, 0, 0, retval, 0); + (int)upl, 0, 0, retval, 0); } else { uio_resid -= bytes_to_move; xfer_resid -= bytes_to_move; @@ -1717,20 +1716,32 @@ cluster_write_x(vp, uio, oldEOF, newEOF, headOff, tailOff, devblocksize, flags) else bytes_to_zero = xfer_resid; - if ( !(flags & IO_NOZEROVALID)) { + if ( !(flags & (IO_NOZEROVALID | IO_NOZERODIRTY))) { bzero((caddr_t)(io_address + io_offset), bytes_to_zero); KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 43)) | DBG_FUNC_NONE, (int)upl_f_offset + io_offset, - bytes_to_zero, (int)zero_cnt1, xfer_resid, 0); + bytes_to_zero, (int)io_offset, xfer_resid, 0); } else { + int zero_pg_index; + bytes_to_zero = min(bytes_to_zero, PAGE_SIZE - (int)(zero_off1 & PAGE_MASK_64)); - if ( !upl_valid_page(pl, (int)(zero_off1 / PAGE_SIZE_64))) { + zero_pg_index = (int)((zero_off1 - upl_f_offset) / PAGE_SIZE_64); + + if ( !upl_valid_page(pl, zero_pg_index)) { bzero((caddr_t)(io_address + io_offset), bytes_to_zero); KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 43)) | DBG_FUNC_NONE, (int)upl_f_offset + io_offset, - bytes_to_zero, (int)zero_cnt1, xfer_resid, 0); + bytes_to_zero, (int)io_offset, xfer_resid, 0); + + } else if ((flags & (IO_NOZERODIRTY | IO_NOZEROVALID)) == IO_NOZERODIRTY && + !upl_dirty_page(pl, zero_pg_index)) { + bzero((caddr_t)(io_address + io_offset), bytes_to_zero); + + KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 43)) | DBG_FUNC_NONE, + (int)upl_f_offset + io_offset, + bytes_to_zero, (int)io_offset, xfer_resid, 0); } } xfer_resid -= bytes_to_zero; @@ -1740,12 +1751,12 @@ cluster_write_x(vp, uio, oldEOF, newEOF, headOff, tailOff, devblocksize, flags) } if (retval == 0) { - int must_push; + int cl_index; int can_delay; io_size += start_offset; - if ((upl_f_offset + io_size) == newEOF && io_size < upl_size) { + if ((upl_f_offset + io_size) >= newEOF && io_size < upl_size) { /* * if we're extending the file with this write * we'll zero fill the rest of the page so that @@ -1761,138 +1772,181 @@ cluster_write_x(vp, uio, oldEOF, newEOF, headOff, tailOff, devblocksize, flags) if ((kret = ubc_upl_unmap(upl)) != KERN_SUCCESS) panic("cluster_write: kernel_upl_unmap failed\n"); - io_size_before_rounding = io_size; - - if (io_size & (devblocksize - 1)) - io_size = (io_size + (devblocksize - 1)) & ~(devblocksize - 1); + if (flags & IO_SYNC) + /* + * if the IO_SYNC flag is set than we need to + * bypass any clusters and immediately issue + * the I/O + */ + goto issue_io; - must_push = 0; - can_delay = 0; + if (vp->v_clen == 0) + /* + * no clusters currently present + */ + goto start_new_cluster; - if (vp->v_clen) { - int newsize; + /* + * keep track of the overall dirty page + * range we've developed + * in case we have to fall back to the + * VHASDIRTY method of flushing + */ + if (vp->v_flag & VHASDIRTY) + goto delay_io; + for (cl_index = 0; cl_index < vp->v_clen; cl_index++) { /* * we have an existing cluster... see if this write will extend it nicely */ - if (start_blkno >= vp->v_cstart) { - if (last_blkno <= (vp->v_cstart + vp->v_clen)) { + if (start_blkno >= vp->v_clusters[cl_index].start_pg) { + /* + * the current write starts at or after the current cluster + */ + if (last_blkno <= (vp->v_clusters[cl_index].start_pg + MAX_UPL_TRANSFER)) { /* * we have a write that fits entirely * within the existing cluster limits */ - if (last_blkno >= vp->v_lastw) { + if (last_blkno > vp->v_clusters[cl_index].last_pg) /* - * if we're extending the dirty region within the cluster - * we need to update the cluster info... we check for blkno - * equality because we may be extending the file with a - * partial write.... this in turn changes our idea of how - * much data to write out (v_ciosiz) for the last page + * update our idea of where the cluster ends */ - vp->v_lastw = last_blkno; - newsize = io_size + ((start_blkno - vp->v_cstart) * PAGE_SIZE); - - if (newsize > vp->v_ciosiz) - vp->v_ciosiz = newsize; - } - can_delay = 1; - goto finish_io; + vp->v_clusters[cl_index].last_pg = last_blkno; + break; } - if (start_blkno < (vp->v_cstart + vp->v_clen)) { + if (start_blkno < (vp->v_clusters[cl_index].start_pg + MAX_UPL_TRANSFER)) { /* * we have a write that starts in the middle of the current cluster * but extends beyond the cluster's limit * we'll clip the current cluster if we actually - * overlap with the new write and then push it out + * overlap with the new write * and start a new cluster with the current write */ - if (vp->v_lastw > start_blkno) { - vp->v_lastw = start_blkno; - vp->v_ciosiz = (vp->v_lastw - vp->v_cstart) * PAGE_SIZE; - } + if (vp->v_clusters[cl_index].last_pg > start_blkno) + vp->v_clusters[cl_index].last_pg = start_blkno; } /* * we also get here for the case where the current write starts * beyond the limit of the existing cluster + * + * in either case, we'll check the remaining clusters before + * starting a new one */ - must_push = 1; - goto check_delay; - } - /* - * the current write starts in front of the current cluster - */ - if (last_blkno > vp->v_cstart) { + } else { /* - * the current write extends into the existing cluster + * the current write starts in front of the current cluster */ - if ((vp->v_lastw - start_blkno) > vp->v_clen) { + if ((vp->v_clusters[cl_index].last_pg - start_blkno) <= MAX_UPL_TRANSFER) { /* - * if we were to combine this write with the current cluster - * we would exceed the cluster size limit.... - * clip the current cluster by moving the start position - * to where the current write ends, and then push it - */ - vp->v_ciosiz -= (last_blkno - vp->v_cstart) * PAGE_SIZE; - vp->v_cstart = last_blkno; - - /* - * round up the io_size to the nearest page size - * since we've coalesced with at least 1 pre-existing - * page in the current cluster... this write may have ended in the - * middle of the page which would cause io_size to give us an - * inaccurate view of how much I/O we actually need to do + * we can just merge the old cluster + * with the new request and leave it + * in the cache */ - io_size = (io_size + (PAGE_SIZE - 1)) & ~PAGE_MASK; + vp->v_clusters[cl_index].start_pg = start_blkno; - must_push = 1; - goto check_delay; + if (last_blkno > vp->v_clusters[cl_index].last_pg) { + /* + * the current write completely + * envelops the existing cluster + */ + vp->v_clusters[cl_index].last_pg = last_blkno; + } + break; } + /* - * we can coalesce the current write with the existing cluster - * adjust the cluster info to reflect this + * if we were to combine this write with the current cluster + * we would exceed the cluster size limit.... so, + * let's see if there's any overlap of the new I/O with + * the existing cluster... + * */ - if (last_blkno > vp->v_lastw) { + if (last_blkno > vp->v_clusters[cl_index].start_pg) /* - * the current write completey overlaps - * the existing cluster + * the current write extends into the existing cluster + * clip the current cluster by moving the start position + * to where the current write ends */ - vp->v_lastw = last_blkno; - vp->v_ciosiz = io_size; - } else { - vp->v_ciosiz += (vp->v_cstart - start_blkno) * PAGE_SIZE; - - if (io_size > vp->v_ciosiz) - vp->v_ciosiz = io_size; - } - vp->v_cstart = start_blkno; - can_delay = 1; - goto finish_io; + vp->v_clusters[cl_index].start_pg = last_blkno; + /* + * if we get here, there was no way to merge + * the new I/O with this cluster and + * keep it under our maximum cluster length + * we'll check the remaining clusters before starting a new one + */ } - /* - * this I/O range is entirely in front of the current cluster - * so we need to push the current cluster out before beginning + } + if (cl_index < vp->v_clen) + /* + * we found an existing cluster that we + * could merger this I/O into + */ + goto delay_io; + + if (vp->v_clen < MAX_CLUSTERS && !(vp->v_flag & VNOCACHE_DATA)) + /* + * we didn't find an existing cluster to + * merge into, but there's room to start * a new one */ - must_push = 1; - } -check_delay: - if (must_push) - cluster_push(vp); + goto start_new_cluster; - if (io_size_before_rounding < (MAX_UPL_TRANSFER * PAGE_SIZE) && !(flags & IO_SYNC)) { - vp->v_clen = MAX_UPL_TRANSFER; + /* + * no exisitng cluster to merge with and no + * room to start a new one... we'll try + * pushing the existing ones... if none of + * them are able to be pushed, we'll have + * to fall back on the VHASDIRTY mechanism + * cluster_try_push will set v_clen to the + * number of remaining clusters if it is + * unable to push all of them + */ + if (vp->v_flag & VNOCACHE_DATA) + can_delay = 0; + else + can_delay = 1; + + if (cluster_try_push(vp, newEOF, can_delay, 0) == 0) { + vp->v_flag |= VHASDIRTY; + goto delay_io; + } +start_new_cluster: + if (vp->v_clen == 0) { + vp->v_ciosiz = devblocksize; vp->v_cstart = start_blkno; vp->v_lastw = last_blkno; - vp->v_ciosiz = io_size; - - can_delay = 1; } -finish_io: - if (can_delay) { - ubc_upl_commit_range(upl, 0, upl_size, - UPL_COMMIT_SET_DIRTY | UPL_COMMIT_FREE_ON_EMPTY); - continue; + vp->v_clusters[vp->v_clen].start_pg = start_blkno; + vp->v_clusters[vp->v_clen].last_pg = last_blkno; + vp->v_clen++; +delay_io: + /* + * make sure we keep v_cstart and v_lastw up to + * date in case we have to fall back on the + * V_HASDIRTY mechanism (or we've already entered it) + */ + if (start_blkno < vp->v_cstart) + vp->v_cstart = start_blkno; + if (last_blkno > vp->v_lastw) + vp->v_lastw = last_blkno; + + ubc_upl_commit_range(upl, 0, upl_size, UPL_COMMIT_SET_DIRTY | UPL_COMMIT_INACTIVATE | UPL_COMMIT_FREE_ON_EMPTY); + continue; +issue_io: + /* + * in order to maintain some semblance of coherency with mapped writes + * we need to write the cluster back out as a multiple of the PAGESIZE + * unless the cluster encompasses the last page of the file... in this + * case we'll round out to the nearest device block boundary + */ + io_size = upl_size; + + if ((upl_f_offset + io_size) > newEOF) { + io_size = newEOF - upl_f_offset; + io_size = (io_size + (devblocksize - 1)) & ~(devblocksize - 1); } + if (flags & IO_SYNC) io_flags = CL_COMMIT | CL_AGE; else @@ -1905,7 +1959,7 @@ finish_io: vp->v_flag |= VTHROTTLED; tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "cluster_write", 0); } - retval = cluster_io(vp, upl, 0, upl_f_offset, io_size, + retval = cluster_io(vp, upl, 0, upl_f_offset, io_size, devblocksize, io_flags, (struct buf *)0); } } @@ -1915,6 +1969,7 @@ finish_io: return (retval); } +int cluster_read(vp, uio, filesize, devblocksize, flags) struct vnode *vp; struct uio *uio; @@ -2061,7 +2116,7 @@ cluster_read(vp, uio, filesize, devblocksize, flags) return(retval); } -static +static int cluster_read_x(vp, uio, filesize, devblocksize, flags) struct vnode *vp; struct uio *uio; @@ -2108,7 +2163,7 @@ cluster_read_x(vp, uio, filesize, devblocksize, flags) io_size = uio->uio_resid; else io_size = max_size; -#ifdef ppc + if (uio->uio_segflg == UIO_USERSPACE && !(vp->v_flag & VNOCACHE_DATA)) { segflg = uio->uio_segflg; @@ -2170,14 +2225,13 @@ cluster_read_x(vp, uio, filesize, devblocksize, flags) } max_size = filesize - uio->uio_offset; } -#endif upl_size = (start_offset + io_size + (PAGE_SIZE - 1)) & ~PAGE_MASK; if (upl_size > (MAX_UPL_TRANSFER * PAGE_SIZE)) upl_size = MAX_UPL_TRANSFER * PAGE_SIZE; pages_in_upl = upl_size / PAGE_SIZE; KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 33)) | DBG_FUNC_START, - upl, (int)upl_f_offset, upl_size, start_offset, 0); + (int)upl, (int)upl_f_offset, upl_size, start_offset, 0); kret = ubc_create_upl(vp, upl_f_offset, @@ -2189,7 +2243,7 @@ cluster_read_x(vp, uio, filesize, devblocksize, flags) panic("cluster_read: failed to get pagelist"); KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 33)) | DBG_FUNC_END, - upl, (int)upl_f_offset, upl_size, start_offset, 0); + (int)upl, (int)upl_f_offset, upl_size, start_offset, 0); /* * scan from the beginning of the upl looking for the first @@ -2223,16 +2277,15 @@ cluster_read_x(vp, uio, filesize, devblocksize, flags) upl_offset = start_pg * PAGE_SIZE; io_size = (last_pg - start_pg) * PAGE_SIZE; - if ((upl_f_offset + upl_offset + io_size) > filesize) { + if ((upl_f_offset + upl_offset + io_size) > filesize) io_size = filesize - (upl_f_offset + upl_offset); - io_size = (io_size + (devblocksize - 1)) & ~(devblocksize - 1); - } + /* * issue a synchronous read to cluster_io */ error = cluster_io(vp, upl, upl_offset, upl_f_offset + upl_offset, - io_size, CL_READ, (struct buf *)0); + io_size, devblocksize, CL_READ, (struct buf *)0); } if (error == 0) { /* @@ -2279,7 +2332,6 @@ cluster_read_x(vp, uio, filesize, devblocksize, flags) cluster_rd_ahead(vp, b_lblkno, e_lblkno, filesize, devblocksize); vp->v_lastr = e_lblkno; } -#ifdef ppc if (uio->uio_segflg == UIO_USERSPACE) { int offset; @@ -2313,8 +2365,8 @@ cluster_read_x(vp, uio, filesize, devblocksize, flags) (int)uio->uio_offset, val_size, uio->uio_resid, 0, 0); uio->uio_segflg = segflg; - } else -#endif + } + else { if ((kret = ubc_upl_map(upl, &io_address)) != KERN_SUCCESS) panic("cluster_read: ubc_upl_map() failed\n"); @@ -2334,7 +2386,7 @@ cluster_read_x(vp, uio, filesize, devblocksize, flags) io_size = (last_pg - start_pg) * PAGE_SIZE; KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 35)) | DBG_FUNC_START, - upl, start_pg * PAGE_SIZE, io_size, error, 0); + (int)upl, start_pg * PAGE_SIZE, io_size, error, 0); if (error || (vp->v_flag & VNOCACHE_DATA)) ubc_upl_abort_range(upl, start_pg * PAGE_SIZE, io_size, @@ -2346,7 +2398,7 @@ cluster_read_x(vp, uio, filesize, devblocksize, flags) | UPL_COMMIT_INACTIVATE); KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 35)) | DBG_FUNC_END, - upl, start_pg * PAGE_SIZE, io_size, error, 0); + (int)upl, start_pg * PAGE_SIZE, io_size, error, 0); } if ((last_pg - start_pg) < pages_in_upl) { int cur_pg; @@ -2358,10 +2410,10 @@ cluster_read_x(vp, uio, filesize, devblocksize, flags) * there state */ if (error) - ubc_upl_abort(upl, 0); + ubc_upl_abort_range(upl, 0, upl_size, UPL_ABORT_FREE_ON_EMPTY); else { KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 35)) | DBG_FUNC_START, - upl, -1, pages_in_upl - (last_pg - start_pg), 0, 0); + (int)upl, -1, pages_in_upl - (last_pg - start_pg), 0, 0); if (start_pg) { /* @@ -2411,11 +2463,12 @@ cluster_read_x(vp, uio, filesize, devblocksize, flags) * that we didn't issue an I/O for, just release them * unchanged */ - ubc_upl_abort(upl, 0); + ubc_upl_abort_range(upl, uio_last * PAGE_SIZE, + (pages_in_upl - uio_last) * PAGE_SIZE, UPL_ABORT_FREE_ON_EMPTY); } KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 35)) | DBG_FUNC_END, - upl, -1, -1, 0, 0); + (int)upl, -1, -1, 0, 0); } } if (retval == 0) @@ -2425,7 +2478,7 @@ cluster_read_x(vp, uio, filesize, devblocksize, flags) return (retval); } -static +static int cluster_nocopy_read(vp, uio, filesize, devblocksize, flags) struct vnode *vp; struct uio *uio; @@ -2558,13 +2611,13 @@ cluster_nocopy_read(vp, uio, filesize, devblocksize, flags) upl_needed_size = (upl_offset + io_size + (PAGE_SIZE -1)) & ~PAGE_MASK; KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 72)) | DBG_FUNC_START, - (int)upl_offset, upl_needed_size, iov->iov_base, io_size, 0); + (int)upl_offset, upl_needed_size, (int)iov->iov_base, io_size, 0); for (force_data_sync = 0; force_data_sync < 3; force_data_sync++) { pages_in_pl = 0; upl_size = upl_needed_size; - upl_flags = UPL_NO_SYNC | UPL_CLEAN_IN_PLACE | UPL_SET_INTERNAL; + upl_flags = UPL_FILE_IO | UPL_NO_SYNC | UPL_CLEAN_IN_PLACE | UPL_SET_INTERNAL; kret = vm_map_get_upl(current_map(), (vm_offset_t)iov->iov_base & ~PAGE_MASK, @@ -2628,10 +2681,10 @@ cluster_nocopy_read(vp, uio, filesize, devblocksize, flags) */ KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 73)) | DBG_FUNC_START, - upl, (int)upl_offset, (int)start_upl_f_offset, io_size, 0); + (int)upl, (int)upl_offset, (int)start_upl_f_offset, io_size, 0); error = cluster_io(vp, upl, upl_offset, start_upl_f_offset, - io_size, CL_READ| CL_NOZERO, (struct buf *)0); + io_size, devblocksize, CL_READ| CL_NOZERO, (struct buf *)0); if (error == 0) { /* @@ -2653,7 +2706,7 @@ cluster_nocopy_read(vp, uio, filesize, devblocksize, flags) } KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 73)) | DBG_FUNC_END, - upl, (int)uio->uio_offset, (int)uio->uio_resid, error, 0); + (int)upl, (int)uio->uio_offset, (int)uio->uio_resid, error, 0); if (retval == 0) retval = error; @@ -2668,7 +2721,7 @@ cluster_nocopy_read(vp, uio, filesize, devblocksize, flags) } -static +static int cluster_phys_read(vp, uio, filesize) struct vnode *vp; struct uio *uio; @@ -2706,7 +2759,7 @@ cluster_phys_read(vp, uio, filesize) pages_in_pl = 0; upl_size = upl_needed_size; - upl_flags = UPL_NO_SYNC | UPL_CLEAN_IN_PLACE | UPL_SET_INTERNAL; + upl_flags = UPL_FILE_IO | UPL_NO_SYNC | UPL_CLEAN_IN_PLACE | UPL_SET_INTERNAL; kret = vm_map_get_upl(current_map(), (vm_offset_t)iov->iov_base & ~PAGE_MASK, @@ -2732,7 +2785,7 @@ cluster_phys_read(vp, uio, filesize) */ error = cluster_io(vp, upl, upl_offset, uio->uio_offset, - io_size, CL_READ| CL_NOZERO | CL_DEV_MEMORY, (struct buf *)0); + io_size, 0, CL_READ| CL_NOZERO | CL_DEV_MEMORY, (struct buf *)0); if (error == 0) { @@ -2758,6 +2811,7 @@ cluster_phys_read(vp, uio, filesize) * generate advisory I/O's in the largest chunks possible * the completed pages will be released into the VM cache */ +int advisory_read(vp, filesize, f_offset, resid, devblocksize) struct vnode *vp; off_t filesize; @@ -2778,7 +2832,7 @@ advisory_read(vp, filesize, f_offset, resid, devblocksize) int io_size; kern_return_t kret; int retval = 0; - + int issued_io; if (!UBCINFOEXISTS(vp)) return(EINVAL); @@ -2814,88 +2868,83 @@ advisory_read(vp, filesize, f_offset, resid, devblocksize) upl_size, &upl, &pl, - UPL_FLAGS_NONE); + UPL_RET_ONLY_ABSENT); if (kret != KERN_SUCCESS) - panic("advisory_read: failed to get pagelist"); - - - KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 61)) | DBG_FUNC_NONE, - upl, (int)upl_f_offset, upl_size, start_offset, 0); + return(retval); + issued_io = 0; /* - * scan from the beginning of the upl looking for the first - * non-valid page.... this will become the first page in - * the request we're going to make to 'cluster_io'... if all - * of the pages are valid, we won't call through to 'cluster_io' + * before we start marching forward, we must make sure we end on + * a present page, otherwise we will be working with a freed + * upl */ - for (start_pg = 0; start_pg < pages_in_upl; start_pg++) { - if (!upl_valid_page(pl, start_pg)) - break; + for (last_pg = pages_in_upl - 1; last_pg >= 0; last_pg--) { + if (upl_page_present(pl, last_pg)) + break; } + pages_in_upl = last_pg + 1; - /* - * scan from the starting invalid page looking for a valid - * page before the end of the upl is reached, if we - * find one, then it will be the last page of the request to - * 'cluster_io' - */ - for (last_pg = start_pg; last_pg < pages_in_upl; last_pg++) { - if (upl_valid_page(pl, last_pg)) - break; - } - if (start_pg < last_pg) { + KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 61)) | DBG_FUNC_NONE, + (int)upl, (int)upl_f_offset, upl_size, start_offset, 0); + + + for (last_pg = 0; last_pg < pages_in_upl; ) { /* - * we found a range of 'invalid' pages that must be filled - * if the last page in this range is the last page of the file - * we may have to clip the size of it to keep from reading past - * the end of the last physical block associated with the file + * scan from the beginning of the upl looking for the first + * page that is present.... this will become the first page in + * the request we're going to make to 'cluster_io'... if all + * of the pages are absent, we won't call through to 'cluster_io' */ - upl_offset = start_pg * PAGE_SIZE; - io_size = (last_pg - start_pg) * PAGE_SIZE; - - if ((upl_f_offset + upl_offset + io_size) > filesize) { - io_size = filesize - (upl_f_offset + upl_offset); - io_size = (io_size + (devblocksize - 1)) & ~(devblocksize - 1); + for (start_pg = last_pg; start_pg < pages_in_upl; start_pg++) { + if (upl_page_present(pl, start_pg)) + break; } - /* - * issue an asynchronous read to cluster_io - */ - retval = cluster_io(vp, upl, upl_offset, upl_f_offset + upl_offset, io_size, - CL_ASYNC | CL_READ | CL_COMMIT | CL_AGE, (struct buf *)0); - } - if (start_pg) { - /* - * start_pg of non-zero indicates we found some already valid pages - * at the beginning of the upl.... we need to release these without - * modifying there state - */ - ubc_upl_abort_range(upl, 0, start_pg * PAGE_SIZE, - UPL_ABORT_FREE_ON_EMPTY); - KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 62)) | DBG_FUNC_NONE, - upl, 0, start_pg * PAGE_SIZE, 0, 0); - } - if (last_pg < pages_in_upl) { /* - * the set of pages that we issued an I/O for did not extend all the - * way to the end of the upl..so just release them without modifying - * there state + * scan from the starting present page looking for an absent + * page before the end of the upl is reached, if we + * find one, then it will terminate the range of pages being + * presented to 'cluster_io' */ - ubc_upl_abort_range(upl, last_pg * PAGE_SIZE, (pages_in_upl - last_pg) * PAGE_SIZE, - UPL_ABORT_FREE_ON_EMPTY); + for (last_pg = start_pg; last_pg < pages_in_upl; last_pg++) { + if (!upl_page_present(pl, last_pg)) + break; + } + + if (last_pg > start_pg) { + /* + * we found a range of pages that must be filled + * if the last page in this range is the last page of the file + * we may have to clip the size of it to keep from reading past + * the end of the last physical block associated with the file + */ + upl_offset = start_pg * PAGE_SIZE; + io_size = (last_pg - start_pg) * PAGE_SIZE; + + if ((upl_f_offset + upl_offset + io_size) > filesize) + io_size = filesize - (upl_f_offset + upl_offset); + + /* + * issue an asynchronous read to cluster_io + */ + retval = cluster_io(vp, upl, upl_offset, upl_f_offset + upl_offset, io_size, devblocksize, + CL_ASYNC | CL_READ | CL_COMMIT | CL_AGE, (struct buf *)0); - KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 63)) | DBG_FUNC_NONE, - upl, last_pg * PAGE_SIZE, - (pages_in_upl - last_pg) * PAGE_SIZE, 0, 0); + issued_io = 1; + } } - io_size = (last_pg * PAGE_SIZE) - start_offset; + if (issued_io == 0) + ubc_upl_abort(upl, 0); + + io_size = upl_size - start_offset; if (io_size > resid) io_size = resid; f_offset += io_size; resid -= io_size; } + KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 60)) | DBG_FUNC_END, (int)f_offset, resid, retval, 0, 0); @@ -2903,8 +2952,172 @@ advisory_read(vp, filesize, f_offset, resid, devblocksize) } +int cluster_push(vp) struct vnode *vp; +{ + int retval; + + if (!UBCINFOEXISTS(vp) || vp->v_clen == 0) { + vp->v_flag &= ~VHASDIRTY; + return(0); + } + + KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 53)) | DBG_FUNC_START, + vp->v_flag & VHASDIRTY, vp->v_clen, 0, 0, 0); + + if (vp->v_flag & VHASDIRTY) { + daddr_t start_pg; + daddr_t last_pg; + daddr_t end_pg; + + start_pg = vp->v_cstart; + end_pg = vp->v_lastw; + + vp->v_flag &= ~VHASDIRTY; + vp->v_clen = 0; + + while (start_pg < end_pg) { + last_pg = start_pg + MAX_UPL_TRANSFER; + + if (last_pg > end_pg) + last_pg = end_pg; + + cluster_push_x(vp, ubc_getsize(vp), start_pg, last_pg, 0); + + start_pg = last_pg; + } + return (1); + } + retval = cluster_try_push(vp, ubc_getsize(vp), 0, 1); + + KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 53)) | DBG_FUNC_END, + vp->v_flag & VHASDIRTY, vp->v_clen, retval, 0, 0); + + return (retval); +} + + +static int +cluster_try_push(vp, EOF, can_delay, push_all) + struct vnode *vp; + off_t EOF; + int can_delay; + int push_all; +{ + int cl_index; + int cl_index1; + int min_index; + int cl_len; + int cl_total; + int cl_pushed; + struct v_cluster l_clusters[MAX_CLUSTERS]; + + /* + * make a local 'sorted' copy of the clusters + * and clear vp->v_clen so that new clusters can + * be developed + */ + for (cl_index = 0; cl_index < vp->v_clen; cl_index++) { + for (min_index = -1, cl_index1 = 0; cl_index1 < vp->v_clen; cl_index1++) { + if (vp->v_clusters[cl_index1].start_pg == vp->v_clusters[cl_index1].last_pg) + continue; + if (min_index == -1) + min_index = cl_index1; + else if (vp->v_clusters[cl_index1].start_pg < vp->v_clusters[min_index].start_pg) + min_index = cl_index1; + } + if (min_index == -1) + break; + l_clusters[cl_index].start_pg = vp->v_clusters[min_index].start_pg; + l_clusters[cl_index].last_pg = vp->v_clusters[min_index].last_pg; + + vp->v_clusters[min_index].start_pg = vp->v_clusters[min_index].last_pg; + } + cl_len = cl_index; + vp->v_clen = 0; + + for (cl_pushed = 0, cl_index = 0; cl_index < cl_len; cl_index++) { + /* + * try to push each cluster in turn... cluster_push_x may not + * push the cluster if can_delay is TRUE and the cluster doesn't + * meet the critera for an immediate push + */ + if (cluster_push_x(vp, EOF, l_clusters[cl_index].start_pg, l_clusters[cl_index].last_pg, can_delay)) { + l_clusters[cl_index].start_pg = 0; + l_clusters[cl_index].last_pg = 0; + + cl_pushed++; + + if (push_all == 0) + break; + } + } + if (cl_len > cl_pushed) { + /* + * we didn't push all of the clusters, so + * lets try to merge them back in to the vnode + */ + if ((MAX_CLUSTERS - vp->v_clen) < (cl_len - cl_pushed)) { + /* + * we picked up some new clusters while we were trying to + * push the old ones (I don't think this can happen because + * I'm holding the lock, but just in case)... the sum of the + * leftovers plus the new cluster count exceeds our ability + * to represent them, so fall back to the VHASDIRTY mechanism + */ + for (cl_index = 0; cl_index < cl_len; cl_index++) { + if (l_clusters[cl_index].start_pg == l_clusters[cl_index].last_pg) + continue; + + if (l_clusters[cl_index].start_pg < vp->v_cstart) + vp->v_cstart = l_clusters[cl_index].start_pg; + if (l_clusters[cl_index].last_pg > vp->v_lastw) + vp->v_lastw = l_clusters[cl_index].last_pg; + } + vp->v_flag |= VHASDIRTY; + } else { + /* + * we've got room to merge the leftovers back in + * just append them starting at the next 'hole' + * represented by vp->v_clen + */ + for (cl_index = 0, cl_index1 = vp->v_clen; cl_index < cl_len; cl_index++) { + if (l_clusters[cl_index].start_pg == l_clusters[cl_index].last_pg) + continue; + + vp->v_clusters[cl_index1].start_pg = l_clusters[cl_index].start_pg; + vp->v_clusters[cl_index1].last_pg = l_clusters[cl_index].last_pg; + + if (cl_index1 == 0) { + vp->v_cstart = l_clusters[cl_index].start_pg; + vp->v_lastw = l_clusters[cl_index].last_pg; + } else { + if (l_clusters[cl_index].start_pg < vp->v_cstart) + vp->v_cstart = l_clusters[cl_index].start_pg; + if (l_clusters[cl_index].last_pg > vp->v_lastw) + vp->v_lastw = l_clusters[cl_index].last_pg; + } + cl_index1++; + } + /* + * update the cluster count + */ + vp->v_clen = cl_index1; + } + } + return(MAX_CLUSTERS - vp->v_clen); +} + + + +static int +cluster_push_x(vp, EOF, first, last, can_delay) + struct vnode *vp; + off_t EOF; + daddr_t first; + daddr_t last; + int can_delay; { upl_page_info_t *pl; upl_t upl; @@ -2920,28 +3133,62 @@ cluster_push(vp) kern_return_t kret; - if (!UBCINFOEXISTS(vp)) - return(0); + KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 51)) | DBG_FUNC_START, + vp->v_clen, first, last, EOF, 0); + + if ((pages_in_upl = last - first) == 0) { + KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 51)) | DBG_FUNC_END, 1, 0, 0, 0, 0); - if (vp->v_clen == 0 || (pages_in_upl = vp->v_lastw - vp->v_cstart) == 0) - return (0); + return (1); + } upl_size = pages_in_upl * PAGE_SIZE; - upl_f_offset = ((off_t)vp->v_cstart) * PAGE_SIZE_64; - size = vp->v_ciosiz; - vp->v_clen = 0; + upl_f_offset = ((off_t)first) * PAGE_SIZE_64; - if (size > upl_size || (upl_size - size) > PAGE_SIZE) - panic("cluster_push: v_ciosiz doesn't match size of cluster\n"); + if (upl_f_offset + upl_size >= EOF) { + + if (upl_f_offset >= EOF) { + /* + * must have truncated the file and missed + * clearing a dangling cluster (i.e. it's completely + * beyond the new EOF + */ + KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 51)) | DBG_FUNC_END, 1, 1, 0, 0, 0); + + return(1); + } + size = EOF - upl_f_offset; + upl_size = (size + (PAGE_SIZE - 1) ) & ~(PAGE_SIZE - 1); + pages_in_upl = upl_size / PAGE_SIZE; + } else { + if (can_delay && (pages_in_upl < (MAX_UPL_TRANSFER - (MAX_UPL_TRANSFER / 2)))) + return(0); + size = upl_size; + } kret = ubc_create_upl(vp, upl_f_offset, upl_size, &upl, - &pl, - UPL_FLAGS_NONE); + &pl, + UPL_RET_ONLY_DIRTY); if (kret != KERN_SUCCESS) panic("cluster_push: failed to get pagelist"); + if (can_delay) { + int num_of_dirty; + + for (num_of_dirty = 0, start_pg = 0; start_pg < pages_in_upl; start_pg++) { + if (upl_valid_page(pl, start_pg) && upl_dirty_page(pl, start_pg)) + num_of_dirty++; + } + if (num_of_dirty < pages_in_upl / 2) { + ubc_upl_abort_range(upl, 0, upl_size, UPL_ABORT_FREE_ON_EMPTY); + + KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 51)) | DBG_FUNC_END, 0, 2, num_of_dirty, (pages_in_upl / 2), 0); + + return(0); + } + } last_pg = 0; while (size) { @@ -2978,9 +3225,11 @@ cluster_push(vp) vp->v_flag |= VTHROTTLED; tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "cluster_push", 0); } - cluster_io(vp, upl, upl_offset, upl_f_offset + upl_offset, io_size, io_flags, (struct buf *)0); + cluster_io(vp, upl, upl_offset, upl_f_offset + upl_offset, io_size, vp->v_ciosiz, io_flags, (struct buf *)0); size -= io_size; } + KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 51)) | DBG_FUNC_END, 1, 3, 0, 0, 0); + return(1); } diff --git a/bsd/vfs/vfs_conf.c b/bsd/vfs/vfs_conf.c index 0442e9b64..c306b1aa5 100644 --- a/bsd/vfs/vfs_conf.c +++ b/bsd/vfs/vfs_conf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -72,8 +72,6 @@ int (*mountroot)() = NULL; */ extern struct vfsops ufs_vfsops; extern int ffs_mountroot(); -extern struct vfsops lfs_vfsops; -extern int lfs_mountroot(); extern struct vfsops mfs_vfsops; extern int mfs_mountroot(); extern struct vfsops hfs_vfsops; @@ -84,13 +82,9 @@ extern int cd9660_mountroot(); extern struct vfsops nfs_vfsops; extern int nfs_mountroot(); extern struct vfsops afs_vfsops; -extern struct vfsops procfs_vfsops; extern struct vfsops null_vfsops; extern struct vfsops union_vfsops; -extern struct vfsops umap_vfsops; -extern struct vfsops portal_vfsops; extern struct vfsops fdesc_vfsops; -extern struct vfsops kernfs_vfsops; extern struct vfsops devfs_vfsops; /* @@ -112,11 +106,6 @@ static struct vfsconf vfsconflist[] = { { &cd9660_vfsops, "cd9660", 14, 0, MNT_LOCAL | MNT_DOVOLFS, cd9660_mountroot, NULL }, #endif - /* Log-based Filesystem */ -#if LFS - { &lfs_vfsops, "lfs", 5, 0, MNT_LOCAL, lfs_mountroot, NULL }, -#endif - /* Memory-based Filesystem */ #if MFS { &mfs_vfsops, "mfs", 3, 0, MNT_LOCAL, mfs_mountroot, NULL }, @@ -132,11 +121,6 @@ static struct vfsconf vfsconflist[] = { { &afs_vfsops, "andrewfs", 13, 0, 0, afs_mountroot, NULL }, #endif - /* /proc Filesystem */ -#if PROCFS - { &procfs_vfsops, "procfs", 12, 0, 0, NULL, NULL }, -#endif - /* Loopback (Minimal) Filesystem Layer */ #if NULLFS { &null_vfsops, "loopback", 9, 0, 0, NULL, NULL }, @@ -147,34 +131,25 @@ static struct vfsconf vfsconflist[] = { { &union_vfsops, "union", 15, 0, 0, NULL, NULL }, #endif - /* User/Group Identifer Remapping Filesystem */ -#if UMAPFS - { &umap_vfsops, "umap", 10, 0, 0, NULL, NULL }, -#endif - - /* Portal Filesystem */ -#if PORTAL - { &portal_vfsops, "portal", 8, 0, 0, NULL, NULL }, -#endif - /* File Descriptor Filesystem */ #if FDESC { &fdesc_vfsops, "fdesc", 7, 0, 0, NULL, NULL }, #endif - /* Kernel Information Filesystem */ -#if KERNFS - { &kernfs_vfsops, "kernfs", 11, 0, 0, NULL, NULL }, -#endif - /* Volume ID Filesystem */ #if VOLFS { &volfs_vfsops, "volfs", 18, 0, 0, NULL, NULL }, #endif + /* Device Filesystem */ #if DEVFS { &devfs_vfsops, "devfs", 19, 0, 0, NULL, NULL }, #endif + + {0}, + {0}, + {0}, + {0}, {0}, {0}, {0}, @@ -206,9 +181,6 @@ struct vfsconf *vfsconf = vfsconflist; extern struct vnodeopv_desc ffs_vnodeop_opv_desc; extern struct vnodeopv_desc ffs_specop_opv_desc; extern struct vnodeopv_desc ffs_fifoop_opv_desc; -extern struct vnodeopv_desc lfs_vnodeop_opv_desc; -extern struct vnodeopv_desc lfs_specop_opv_desc; -extern struct vnodeopv_desc lfs_fifoop_opv_desc; extern struct vnodeopv_desc mfs_vnodeop_opv_desc; extern struct vnodeopv_desc dead_vnodeop_opv_desc; extern struct vnodeopv_desc fifo_vnodeop_opv_desc; @@ -217,11 +189,7 @@ extern struct vnodeopv_desc nfsv2_vnodeop_opv_desc; extern struct vnodeopv_desc spec_nfsv2nodeop_opv_desc; extern struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc; extern struct vnodeopv_desc fdesc_vnodeop_opv_desc; -extern struct vnodeopv_desc portal_vnodeop_opv_desc; extern struct vnodeopv_desc null_vnodeop_opv_desc; -extern struct vnodeopv_desc umap_vnodeop_opv_desc; -extern struct vnodeopv_desc kernfs_vnodeop_opv_desc; -extern struct vnodeopv_desc procfs_vnodeop_opv_desc; extern struct vnodeopv_desc hfs_vnodeop_opv_desc; extern struct vnodeopv_desc hfs_specop_opv_desc; extern struct vnodeopv_desc hfs_fifoop_opv_desc; @@ -230,7 +198,6 @@ extern struct vnodeopv_desc cd9660_vnodeop_opv_desc; extern struct vnodeopv_desc cd9660_specop_opv_desc; extern struct vnodeopv_desc cd9660_fifoop_opv_desc; extern struct vnodeopv_desc union_vnodeop_opv_desc; -extern struct vnodeopv_desc procfs_vnodeop_opv_desc; extern struct vnodeopv_desc devfs_vnodeop_opv_desc; extern struct vnodeopv_desc devfs_spec_vnodeop_opv_desc; @@ -245,13 +212,6 @@ struct vnodeopv_desc *vfs_opv_descs[] = { &fifo_vnodeop_opv_desc, #endif &spec_vnodeop_opv_desc, -#if LFS - &lfs_vnodeop_opv_desc, - &lfs_specop_opv_desc, -#if FIFO - &lfs_fifoop_opv_desc, -#endif -#endif #if MFS &mfs_vnodeop_opv_desc, #endif @@ -265,21 +225,9 @@ struct vnodeopv_desc *vfs_opv_descs[] = { #if FDESC &fdesc_vnodeop_opv_desc, #endif -#if PORTAL - &portal_vnodeop_opv_desc, -#endif #if NULLFS &null_vnodeop_opv_desc, #endif -#if UMAPFS - &umap_vnodeop_opv_desc, -#endif -#if KERNFS - &kernfs_vnodeop_opv_desc, -#endif -#if PROCFS - &procfs_vnodeop_opv_desc, -#endif #if HFS &hfs_vnodeop_opv_desc, &hfs_specop_opv_desc, diff --git a/bsd/vfs/vfs_lookup.c b/bsd/vfs/vfs_lookup.c index 0626ad15b..9d8aea299 100644 --- a/bsd/vfs/vfs_lookup.c +++ b/bsd/vfs/vfs_lookup.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -292,7 +292,9 @@ lookup(ndp) int namemax = 0; /* maximun number of bytes for filename returned by pathconf() */ int docache; /* == 0 do not cache last component */ int wantparent; /* 1 => wantparent or lockparent flag */ + int dp_unlocked = 0; /* 1 => dp already VOP_UNLOCK()-ed */ int rdonly; /* lookup read-only flag bit */ + int trailing_slash; int error = 0; struct componentname *cnp = &ndp->ni_cnd; struct proc *p = cnp->cn_proc; @@ -344,6 +346,25 @@ dirloop: #endif ndp->ni_pathlen -= cnp->cn_namelen; ndp->ni_next = cp; + + /* + * Replace multiple slashes by a single slash and trailing slashes + * by a null. This must be done before VOP_LOOKUP() because some + * fs's don't know about trailing slashes. Remember if there were + * trailing slashes to handle symlinks, existing non-directories + * and non-existing files that won't be directories specially later. + */ + trailing_slash = 0; + while (*cp == '/' && (cp[1] == '/' || cp[1] == '\0')) { + cp++; + ndp->ni_pathlen--; + if (*cp == '\0') { + trailing_slash = 1; + *ndp->ni_next = '\0'; + } + } + ndp->ni_next = cp; + cnp->cn_flags |= MAKEENTRY; if (*cp == '\0' && docache == 0) cnp->cn_flags &= ~MAKEENTRY; @@ -453,6 +474,11 @@ unionlookup: error = EROFS; goto bad; } + if (*cp == '\0' && trailing_slash && + !(cnp->cn_flags & WILLBEDIR)) { + error = ENOENT; + goto bad; + } /* * We return with ni_vp NULL to indicate that the entry * doesn't currently exist, leaving a pointer to the @@ -490,11 +516,14 @@ unionlookup: (cnp->cn_flags & NOCROSSMOUNT) == 0) { if (vfs_busy(mp, 0, 0, p)) continue; + VOP_UNLOCK(dp, 0, p); error = VFS_ROOT(mp, &tdp); vfs_unbusy(mp, p); - if (error) + if (error) { + dp_unlocked = 1; /* Signal error path 'dp' has already been unlocked */ goto bad2; - vput(dp); + }; + vrele(dp); ndp->ni_vp = dp = tdp; } @@ -502,11 +531,20 @@ unionlookup: * Check for symbolic link */ if ((dp->v_type == VLNK) && - ((cnp->cn_flags & FOLLOW) || *ndp->ni_next == '/')) { + ((cnp->cn_flags & FOLLOW) || trailing_slash || + *ndp->ni_next == '/')) { cnp->cn_flags |= ISSYMLINK; return (0); } + /* + * Check for bogus trailing slashes. + */ + if (trailing_slash && dp->v_type != VDIR) { + error = ENOTDIR; + goto bad2; + } + nextname: /* * Not a symbolic link. If more pathname, @@ -547,7 +585,11 @@ bad2: VOP_UNLOCK(ndp->ni_dvp, 0, p); vrele(ndp->ni_dvp); bad: - vput(dp); + if (dp_unlocked) { + vrele(dp); + } else { + vput(dp); + }; ndp->ni_vp = NULL; if (kdebug_enable) kdebug_lookup(dp, cnp); @@ -752,14 +794,18 @@ kdebug_lookup(dp, cnp) dbg_parms[i++] = 0; } - KERNEL_DEBUG_CONSTANT((FSDBG_CODE(DBG_FSRW,36)) | DBG_FUNC_NONE, + /* + In the event that we collect multiple, consecutive pathname + entries, we must mark the start of the path's string. + */ + KERNEL_DEBUG_CONSTANT((FSDBG_CODE(DBG_FSRW,36)) | DBG_FUNC_START, dp, dbg_parms[0], dbg_parms[1], dbg_parms[2], 0); for (dbg_namelen = save_dbg_namelen-12, i=3; dbg_namelen > 0; - dbg_namelen -=(4 * sizeof(long))) + dbg_namelen -=(4 * sizeof(long)), i+= 4) { KERNEL_DEBUG_CONSTANT((FSDBG_CODE(DBG_FSRW,36)) | DBG_FUNC_NONE, - dbg_parms[i++], dbg_parms[i++], dbg_parms[i++], dbg_parms[i++], 0); + dbg_parms[i], dbg_parms[i+1], dbg_parms[i+2], dbg_parms[i+3], 0); } } diff --git a/bsd/vfs/vfs_quota.c b/bsd/vfs/vfs_quota.c new file mode 100644 index 000000000..36f4fb89a --- /dev/null +++ b/bsd/vfs/vfs_quota.c @@ -0,0 +1,508 @@ +/* + * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Copyright (c) 1982, 1986, 1990, 1993, 1995 + * The 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. + * + * @(#)vfs_quota.c + * derived from @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static u_int32_t quotamagic[MAXQUOTAS] = INITQMAGICS; + + +/* + * Code pertaining to management of the in-core dquot data structures. + */ +#define DQHASH(dqvp, id) \ + (&dqhashtbl[((((int)(dqvp)) >> 8) + id) & dqhash]) +LIST_HEAD(dqhash, dquot) *dqhashtbl; +u_long dqhash; + +/* + * Dquot free list. + */ +#define DQUOTINC 5 /* minimum free dquots desired */ +TAILQ_HEAD(dqfreelist, dquot) dqfreelist; +long numdquot, desireddquot = DQUOTINC; + + +static int dqlookup(struct quotafile *, u_long, struct dqblk *, u_int32_t *); + + +/* + * Initialize the quota system. + */ +void +dqinit() +{ + + dqhashtbl = hashinit(desiredvnodes, M_DQUOT, &dqhash); + TAILQ_INIT(&dqfreelist); +} + + +/* + * Initialize a quota file + */ +int +dqfileopen(qfp, type) + struct quotafile *qfp; + int type; +{ + struct dqfilehdr header; + struct vattr vattr; + struct iovec aiov; + struct uio auio; + int error; + + /* Obtain the file size */ + error = VOP_GETATTR(qfp->qf_vp, &vattr, qfp->qf_cred, current_proc()); + if (error) + return (error); + + /* Read the file header */ + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + aiov.iov_base = (caddr_t)&header; + aiov.iov_len = sizeof (header); + auio.uio_resid = sizeof (header); + auio.uio_offset = (off_t)(0); + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_rw = UIO_READ; + auio.uio_procp = (struct proc *)0; + error = VOP_READ(qfp->qf_vp, &auio, 0, qfp->qf_cred); + if (error) + return (error); + else if (auio.uio_resid) + return (EINVAL); + + /* Sanity check the quota file header. */ + if ((header.dqh_magic != quotamagic[type]) || + (header.dqh_version > QF_VERSION) || + (!powerof2(header.dqh_maxentries)) || + (header.dqh_maxentries > (vattr.va_size / sizeof(struct dqblk)))) + return (EINVAL); + + /* Set up the time limits for this quota. */ + if (header.dqh_btime > 0) + qfp->qf_btime = header.dqh_btime; + else + qfp->qf_btime = MAX_DQ_TIME; + if (header.dqh_itime > 0) + qfp->qf_itime = header.dqh_itime; + else + qfp->qf_itime = MAX_IQ_TIME; + + /* Calculate the hash table constants. */ + qfp->qf_maxentries = header.dqh_maxentries; + qfp->qf_entrycnt = header.dqh_entrycnt; + qfp->qf_shift = dqhashshift(header.dqh_maxentries); + + return (0); +} + +/* + * Close down a quota file + */ +void +dqfileclose(qfp, type) + struct quotafile *qfp; + int type; +{ + struct dqfilehdr header; + struct iovec aiov; + struct uio auio; + + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + aiov.iov_base = (caddr_t)&header; + aiov.iov_len = sizeof (header); + auio.uio_resid = sizeof (header); + auio.uio_offset = (off_t)(0); + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_rw = UIO_READ; + auio.uio_procp = (struct proc *)0; + if (VOP_READ(qfp->qf_vp, &auio, 0, qfp->qf_cred) == 0) { + header.dqh_entrycnt = qfp->qf_entrycnt; + + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + aiov.iov_base = (caddr_t)&header; + aiov.iov_len = sizeof (header); + auio.uio_resid = sizeof (header); + auio.uio_offset = (off_t)(0); + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_rw = UIO_WRITE; + auio.uio_procp = (struct proc *)0; + (void) VOP_WRITE(qfp->qf_vp, &auio, 0, qfp->qf_cred); + } +} + + +/* + * Obtain a dquot structure for the specified identifier and quota file + * reading the information from the file if necessary. + */ +int +dqget(vp, id, qfp, type, dqp) + struct vnode *vp; + u_long id; + struct quotafile *qfp; + register int type; + struct dquot **dqp; +{ + struct proc *p = current_proc(); /* XXX */ + struct dquot *dq; + struct dqhash *dqh; + struct vnode *dqvp; + int error = 0; + + dqvp = qfp->qf_vp; + if (id == 0 || dqvp == NULLVP || (qfp->qf_qflags & QTF_CLOSING)) { + *dqp = NODQUOT; + return (EINVAL); + } + /* + * Check the cache first. + */ + dqh = DQHASH(dqvp, id); + for (dq = dqh->lh_first; dq; dq = dq->dq_hash.le_next) { + if (dq->dq_id != id || + dq->dq_qfile->qf_vp != dqvp) + continue; + /* + * Cache hit with no references. Take + * the structure off the free list. + */ + if (dq->dq_cnt == 0) + TAILQ_REMOVE(&dqfreelist, dq, dq_freelist); + DQREF(dq); + *dqp = dq; + return (0); + } + /* + * Not in cache, allocate a new one. + */ + if (dqfreelist.tqh_first == 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 = dqfreelist.tqh_first) == NULL) { + tablefull("dquot"); + *dqp = NODQUOT; + return (EUSERS); + } + if (dq->dq_cnt || (dq->dq_flags & DQ_MOD)) + panic("free dquot isn't"); + TAILQ_REMOVE(&dqfreelist, dq, dq_freelist); + LIST_REMOVE(dq, dq_hash); + } + /* + * Initialize the contents of the dquot structure. + */ + if (vp != dqvp) + vn_lock(dqvp, LK_EXCLUSIVE | LK_RETRY, p); + LIST_INSERT_HEAD(dqh, dq, dq_hash); + DQREF(dq); + dq->dq_flags = DQ_LOCK; + dq->dq_id = id; + dq->dq_qfile = qfp; + dq->dq_type = type; + error = dqlookup(qfp, id, &dq->dq_dqb, &dq->dq_index); + + if (vp != dqvp) + VOP_UNLOCK(dqvp, 0, p); + 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) { + LIST_REMOVE(dq, dq_hash); + 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 + qfp->qf_btime; + if (dq->dq_itime == 0) + dq->dq_itime = time.tv_sec + qfp->qf_itime; + } + *dqp = dq; + return (0); +} + +/* + * Lookup a dqblk structure for the specified identifier and + * quota file. If there is no enetry for this identifier then + * one is inserted. The actual hash table index is returned. + */ +static int +dqlookup(qfp, id, dqb, index) + struct quotafile *qfp; + u_long id; + struct dqblk *dqb; + u_int32_t *index; +{ + struct vnode *dqvp; + struct ucred *cred; + struct iovec aiov; + struct uio auio; + int i, skip, last; + u_long mask; + int error = 0; + + if (id == 0) + return (EINVAL); + dqvp = qfp->qf_vp; + cred = qfp->qf_cred; + + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_procp = (struct proc *)0; + + mask = qfp->qf_maxentries - 1; + i = dqhash1(id, qfp->qf_shift, mask); + skip = dqhash2(id, mask); + + for (last = (i + (qfp->qf_maxentries-1) * skip) & mask; + i != last; + i = (i + skip) & mask) { + + aiov.iov_base = (caddr_t)dqb; + aiov.iov_len = sizeof (struct dqblk); + auio.uio_resid = sizeof (struct dqblk); + auio.uio_offset = (off_t)dqoffset(i); + auio.uio_rw = UIO_READ; + error = VOP_READ(dqvp, &auio, 0, cred); + if (error) { + printf("dqlookup: error %d looking up id %d at index %d\n", error, id, i); + break; + } else if (auio.uio_resid) { + error = EIO; + printf("dqlookup: error looking up id %d at index %d\n", id, i); + break; + } + /* + * An empty entry means there is no entry + * with that id. In this case a new dqb + * record will be inserted. + */ + if (dqb->dqb_id == 0) { + bzero(dqb, sizeof(struct dqblk)); + dqb->dqb_id = id; + /* + * Write back to reserve entry for this id + */ + aiov.iov_base = (caddr_t)dqb; + aiov.iov_len = sizeof (struct dqblk); + auio.uio_resid = sizeof (struct dqblk); + auio.uio_offset = (off_t)dqoffset(i); + auio.uio_rw = UIO_WRITE; + error = VOP_WRITE(dqvp, &auio, 0, cred); + if (auio.uio_resid && error == 0) + error = EIO; + if (error == 0) + ++qfp->qf_entrycnt; + break; + } + /* An id match means an entry was found. */ + if (dqb->dqb_id == id) + break; + } + + *index = i; /* remember index so we don't have to recompute it later */ + return (error); +} + +/* + * Obtain a reference to a dquot. + */ +void +dqref(dq) + struct dquot *dq; +{ + + dq->dq_cnt++; +} + +/* + * Release a reference to a dquot. + */ +void +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; + TAILQ_INSERT_TAIL(&dqfreelist, dq, dq_freelist); +} + +/* + * Update the disk quota in the quota file. + */ +int +dqsync(vp, dq) + struct vnode *vp; + struct dquot *dq; +{ + struct proc *p = current_proc(); /* XXX */ + 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 (dq->dq_id == 0) + return(0); + if ((dqvp = dq->dq_qfile->qf_vp) == NULLVP) + panic("dqsync: file"); + if (vp != dqvp) + vn_lock(dqvp, LK_EXCLUSIVE | LK_RETRY, p); + 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, 0, p); + 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)dqoffset(dq->dq_index); + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_rw = UIO_WRITE; + auio.uio_procp = (struct proc *)0; + error = VOP_WRITE(dqvp, &auio, 0, dq->dq_qfile->qf_cred); + 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, 0, p); + return (error); +} + +/* + * Flush all entries from the cache for a particular vnode. + */ +void +dqflush(vp) + register struct vnode *vp; +{ + register struct dquot *dq, *nextdq; + struct dqhash *dqh; + + /* + * 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 (dqh = &dqhashtbl[dqhash]; dqh >= dqhashtbl; dqh--) { + for (dq = dqh->lh_first; dq; dq = nextdq) { + nextdq = dq->dq_hash.le_next; + if (dq->dq_qfile->qf_vp != vp) + continue; + if (dq->dq_cnt) + panic("dqflush: stray dquot"); + LIST_REMOVE(dq, dq_hash); + dq->dq_qfile = (struct quotafile *)0; + } + } +} diff --git a/bsd/vfs/vfs_subr.c b/bsd/vfs/vfs_subr.c index be3a4d40c..c49f321c2 100644 --- a/bsd/vfs/vfs_subr.c +++ b/bsd/vfs/vfs_subr.c @@ -64,6 +64,7 @@ * External virtual filesystem routines */ +#undef DIAGNOSTIC #define DIAGNOSTIC 1 #include @@ -108,15 +109,6 @@ static int vnreclaim(int count); extern kern_return_t adjust_vm_object_cache(vm_size_t oval, vm_size_t nval); -/* - * Insq/Remq for the vnode usage lists. - */ -#define bufinsvn(bp, dp) LIST_INSERT_HEAD(dp, bp, b_vnbufs) -#define bufremvn(bp) { \ - LIST_REMOVE(bp, b_vnbufs); \ - (bp)->b_vnbufs.le_next = NOLIST; \ -} - TAILQ_HEAD(freelst, vnode) vnode_free_list; /* vnode free list */ TAILQ_HEAD(inactivelst, vnode) vnode_inactive_list; /* vnode inactive list */ struct mntlist mountlist; /* mounted filesystem list */ @@ -260,7 +252,12 @@ __private_extern__ kern_return_t reset_vmobjectcache(unsigned int val1, unsigned int val2) { vm_size_t oval = val1 - VNODE_FREE_MIN; - vm_size_t nval = val2 - VNODE_FREE_MIN; + vm_size_t nval; + + if(val2 < VNODE_FREE_MIN) + nval = 0; + else + nval = val2 - VNODE_FREE_MIN; return(adjust_vm_object_cache(oval, nval)); } @@ -641,10 +638,9 @@ vpwakeup(struct vnode *vp) if (vp) { if (--vp->v_numoutput < 0) panic("vpwakeup: neg numoutput"); - if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) { - if (vp->v_numoutput < 0) - panic("vpwakeup: neg numoutput 2"); - vp->v_flag &= ~VBWAIT; + if ((vp->v_flag & VBWAIT || vp->v_flag & VTHROTTLED) + && vp->v_numoutput <= 0) { + vp->v_flag &= ~(VBWAIT|VTHROTTLED); wakeup((caddr_t)&vp->v_numoutput); } } @@ -657,8 +653,6 @@ void vwakeup(bp) register struct buf *bp; { - register struct vnode *vp; - CLR(bp->b_flags, B_WRITEINPROG); vpwakeup(bp->b_vp); } @@ -683,7 +677,7 @@ vinvalbuf(vp, flags, cred, p, slpflag, slptimeo) if (error = VOP_FSYNC(vp, cred, MNT_WAIT, p)) { return (error); } - if (vp->v_dirtyblkhd.lh_first != NULL || (vp->v_flag & VHASDIRTY)) + if (vp->v_dirtyblkhd.lh_first) panic("vinvalbuf: dirty bufs"); } @@ -736,82 +730,6 @@ vinvalbuf(vp, flags, cred, p, slpflag, slptimeo) return (0); } -/* - * Associate a buffer with a vnode. - */ -void -bgetvp(vp, bp) - register struct vnode *vp; - register struct buf *bp; -{ - - 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. - */ - bufinsvn(bp, &vp->v_cleanblkhd); -} - -/* - * Disassociate a buffer from a vnode. - */ -void -brelvp(bp) - register struct buf *bp; -{ - struct vnode *vp; - - if (bp->b_vp == (struct vnode *) 0) - panic("brelvp: NULL"); - /* - * Delete from old vnode list, if on one. - */ - if (bp->b_vnbufs.le_next != NOLIST) - bufremvn(bp); - 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. - */ -void -reassignbuf(bp, newvp) - register struct buf *bp; - register struct vnode *newvp; -{ - register struct buflists *listheadp; - - if (newvp == NULL) { - printf("reassignbuf: NULL"); - return; - } - /* - * Delete from old vnode list, if on one. - */ - if (bp->b_vnbufs.le_next != NOLIST) - bufremvn(bp); - /* - * If dirty, put on list of dirty buffers; - * otherwise insert onto list of clean buffers. - */ - if (ISSET(bp->b_flags, B_DELWRI)) - listheadp = &newvp->v_dirtyblkhd; - else - listheadp = &newvp->v_cleanblkhd; - bufinsvn(bp, listheadp); -} - /* * Create a vnode for a block device. * Used for root filesystem, argdev, and swap areas. @@ -940,6 +858,8 @@ vget(vp, flags, p) { int error = 0; +retry: + /* * If the vnode is in the process of being cleaned out for * another use, we wait for the cleaning to finish and then @@ -966,6 +886,19 @@ vget(vp, flags, p) return (ENOENT); } + /* + * if the vnode is being initialized, + * wait for it to finish initialization + */ + if (ISSET(vp->v_flag, VUINIT)) { + if (ISSET(vp->v_flag, VUINIT)) { + SET(vp->v_flag, VUWANT); + simple_unlock(&vp->v_interlock); + (void) tsleep((caddr_t)vp, PINOD, "vget2", 0); + goto retry; + } + } + simple_lock(&vnode_free_list_slock); if (vp->v_usecount == 0) { /* If on the free list, remove it from there */ @@ -1468,9 +1401,9 @@ loop: simple_lock(&vp->v_interlock); /* - * Skip over a vnodes marked VSYSTEM. + * Skip over a vnodes marked VSYSTEM or VNOFLUSH. */ - if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) { + if ((flags & SKIPSYSTEM) && ((vp->v_flag & VSYSTEM) || (vp->v_flag & VNOFLUSH))) { simple_unlock(&vp->v_interlock); continue; } @@ -1525,7 +1458,7 @@ loop: busy++; } simple_unlock(&mntvnode_slock); - if (busy) + if (busy && ((flags & FORCECLOSE)==0)) return (EBUSY); return (0); } @@ -1541,8 +1474,6 @@ vclean(vp, flags, p) struct proc *p; { int active; - void *obj; - kern_return_t kret; int removed = 0; int didhold; @@ -1942,6 +1873,8 @@ vprint(label, vp) strcat(buf, "|VTEXT"); if (vp->v_flag & VSYSTEM) strcat(buf, "|VSYSTEM"); + if (vp->v_flag & VNOFLUSH) + strcat(buf, "|VNOFLUSH"); if (vp->v_flag & VXLOCK) strcat(buf, "|VXLOCK"); if (vp->v_flag & VXWANT) @@ -2006,10 +1939,19 @@ vfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) size_t newlen; struct proc *p; { - struct ctldebug *cdp; struct vfsconf *vfsp; - if (name[0] == VFS_NUMMNTOPS) { + /* + * The VFS_NUMMNTOPS shouldn't be at name[0] since + * is a VFS generic variable. So now we must check + * namelen so we don't end up covering any UFS + * variables (sinc UFS vfc_typenum is 1). + * + * It should have been: + * name[0]: VFS_GENERIC + * name[1]: VFS_NUMMNTOPS + */ + if (namelen == 1 && name[0] == VFS_NUMMNTOPS) { extern unsigned int vfs_nummntops; return (sysctl_rdint(oldp, oldlenp, newp, vfs_nummntops)); } @@ -2364,12 +2306,10 @@ vm_object_cache_reclaim(int count) static int vnreclaim(int count) { - int cnt, i, loopcnt; - void *obj; + int i, loopcnt; struct vnode *vp; int err; struct proc *p; - kern_return_t kret; i = 0; loopcnt = 0; @@ -2621,7 +2561,6 @@ int walk_vnodes_debug=0; void walk_allvnodes() { - struct proc *p = current_proc(); struct mount *mp, *nmp; struct vnode *vp; int cnt = 0; diff --git a/bsd/vfs/vfs_syscalls.c b/bsd/vfs/vfs_syscalls.c index d70d27453..b76cdabb2 100644 --- a/bsd/vfs/vfs_syscalls.c +++ b/bsd/vfs/vfs_syscalls.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995-2001 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1995-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -75,6 +75,7 @@ #include #include #include +#include #include #include @@ -88,6 +89,7 @@ uid_t console_user; static int change_dir __P((struct nameidata *ndp, struct proc *p)); static void checkdirs __P((struct vnode *olddp)); +static void enablequotas __P((struct proc *p, struct mount *mp)); /* counts number of mount and unmount operations */ unsigned int vfs_nummntops=0; @@ -121,6 +123,7 @@ mount(p, uap, retval) struct nameidata nd; char fstypename[MFSNAMELEN]; size_t dummy=0; + /* * Get vnode to be covered */ @@ -303,6 +306,8 @@ update: if (error) mp->mnt_flag = flag; vfs_unbusy(mp, p); + if (!error) + enablequotas(p, mp); return (error); } @@ -328,8 +333,10 @@ update: vrele(vp); /* increment the operations count */ - if (!error) + if (!error) { vfs_nummntops++; + enablequotas(p, mp); + } } else { simple_lock(&vp->v_interlock); CLR(vp->v_flag, VMOUNT); @@ -345,6 +352,48 @@ update: return (error); } +static void +enablequotas(p, mp) + struct proc *p; + struct mount *mp; +{ + struct vnode *vp; + struct nameidata qnd; + int type; + char qfpath[MAXPATHLEN]; + char *qfname = QUOTAFILENAME; + char *qfopsname = QUOTAOPSNAME; + char *qfextension[] = INITQFNAMES; + + + if ((strcmp(mp->mnt_stat.f_fstypename, "hfs") != 0 ) + && (strcmp( mp->mnt_stat.f_fstypename, "ufs") != 0)) + return; + + /* + * Enable filesystem disk quotas if necessary. + * We ignore errors as this should not interfere with final mount + */ + for (type=0; type < MAXQUOTAS; type++) { + sprintf(qfpath, "%s/%s.%s", mp->mnt_stat.f_mntonname, qfopsname, qfextension[type]); + NDINIT(&qnd, LOOKUP, FOLLOW, UIO_SYSSPACE, qfpath, p); + if (namei(&qnd) != 0) + continue; /* option file to trigger quotas is not present */ + vp = qnd.ni_vp; + sprintf(qfpath, "%s/%s.%s", mp->mnt_stat.f_mntonname, qfname, qfextension[type]); + if (vp->v_tag == VT_HFS) { + vrele(vp); + (void)hfs_quotaon(p, mp, type, qfpath, UIO_SYSSPACE); + } else if (vp->v_tag == VT_UFS) { + vrele(vp); + (void)quotaon(p, mp, type, qfpath, UIO_SYSSPACE); + } else { + vrele(vp); + } + } + return; +} + /* * Scan all active processes to see if any of them have a current * or root directory onto which the new filesystem has just been @@ -458,8 +507,25 @@ dounmount(mp, flags, p) int error; simple_lock(&mountlist_slock); + /* XXX post jaguar fix LK_DRAIN - then clean this up */ + if (mp->mnt_kern_flag & MNTK_UNMOUNT) { + simple_unlock(&mountlist_slock); + mp->mnt_kern_flag |= MNTK_MWAIT; + if ((error = tsleep((void *)mp, PRIBIO, "dounmount", 0))) + return (error); + /* + * The prior unmount attempt has probably succeeded. + * Do not dereference mp here - returning EBUSY is safest. + */ + return (EBUSY); + } mp->mnt_kern_flag |= MNTK_UNMOUNT; - lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK, &mountlist_slock, p); + error = lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK, + &mountlist_slock, p); + if (error) { + mp->mnt_kern_flag &= ~MNTK_UNMOUNT; + goto out; + } mp->mnt_flag &=~ MNT_ASYNC; ubc_umount(mp); /* release cached vnodes */ cache_purgevfs(mp); /* remove cache entries for this file sys */ @@ -858,6 +924,7 @@ chroot(p, uap, retval) register struct filedesc *fdp = p->p_fd; int error; struct nameidata nd; + boolean_t shared_regions_active; struct vnode *tvp; if (error = suser(p->p_ucred, &p->p_acflag)) @@ -868,7 +935,13 @@ chroot(p, uap, retval) if (error = change_dir(&nd, p)) return (error); - if(error = clone_system_shared_regions()) { + if(p->p_flag & P_NOSHLIB) { + shared_regions_active = FALSE; + } else { + shared_regions_active = TRUE; + } + + if(error = clone_system_shared_regions(shared_regions_active)) { vrele(nd.ni_vp); return (error); } @@ -1033,6 +1106,7 @@ mknod(p, uap, retval) if (error = suser(p->p_ucred, &p->p_acflag)) return (error); + bwillwrite(); NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); if (error = namei(&nd)) return (error); @@ -1107,6 +1181,7 @@ mkfifo(p, uap, retval) #if !FIFO return (EOPNOTSUPP); #else + bwillwrite(); NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); if (error = namei(&nd)) return (error); @@ -1145,6 +1220,7 @@ link(p, uap, retval) struct nameidata nd; int error; + bwillwrite(); NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); if (error = namei(&nd)) return (error); @@ -1200,6 +1276,7 @@ symlink(p, uap, retval) MALLOC_ZONE(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); if (error = copyinstr(uap->path, path, MAXPATHLEN, &dummy)) goto out; + bwillwrite(); NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->link, p); if (error = namei(&nd)) goto out; @@ -1238,6 +1315,7 @@ undelete(p, uap, retval) int error; struct nameidata nd; + bwillwrite(); NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, uap->path, p); error = namei(&nd); @@ -1280,6 +1358,7 @@ _unlink(p, uap, retval, nodelbusy) int error; struct nameidata nd; + bwillwrite(); NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->path, p); /* with Carbon semantics, busy files cannot be deleted */ if (nodelbusy) @@ -1960,6 +2039,52 @@ fchown(p, uap, retval) return (error); } +static int +getutimes(usrtvp, tsp) + const struct timeval *usrtvp; + struct timespec *tsp; +{ + struct timeval tv[2]; + int error; + + if (usrtvp == NULL) { + microtime(&tv[0]); + TIMEVAL_TO_TIMESPEC(&tv[0], &tsp[0]); + tsp[1] = tsp[0]; + } else { + if ((error = copyin(usrtvp, tv, sizeof (tv))) != 0) + return (error); + TIMEVAL_TO_TIMESPEC(&tv[0], &tsp[0]); + TIMEVAL_TO_TIMESPEC(&tv[1], &tsp[1]); + } + return 0; +} + +static int +setutimes(p, vp, ts, nullflag) + struct proc *p; + struct vnode *vp; + const struct timespec *ts; + int nullflag; +{ + int error; + struct vattr vattr; + + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + if (error) + goto out; + VATTR_NULL(&vattr); + vattr.va_atime = ts[0]; + vattr.va_mtime = ts[1]; + if (nullflag) + vattr.va_vaflags |= VA_UTIMES_NULL; + error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); + VOP_UNLOCK(vp, 0, p); +out: + return error; +} + /* * Set the access and modification times of a file. */ @@ -1974,35 +2099,49 @@ utimes(p, uap, retval) register struct utimes_args *uap; register_t *retval; { - register struct vnode *vp; - struct timeval tv[2]; - struct vattr vattr; + struct timespec ts[2]; + struct timeval *usrtvp; int error; struct nameidata nd; - VATTR_NULL(&vattr); - if (uap->tptr == NULL) { - microtime(&tv[0]); - tv[1] = tv[0]; - vattr.va_vaflags |= VA_UTIMES_NULL; - } else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, - sizeof (tv))) - return (error); + usrtvp = uap->tptr; + if ((error = getutimes(usrtvp, ts)) != 0) + return (error); NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); - if (error = namei(&nd)) + if ((error = namei(&nd)) != 0) return (error); - vp = nd.ni_vp; - VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - vattr.va_atime.tv_sec = tv[0].tv_sec; - vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000; - vattr.va_mtime.tv_sec = tv[1].tv_sec; - vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000; - error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); - vput(vp); + error = setutimes(p, nd.ni_vp, ts, usrtvp == NULL); + vrele(nd.ni_vp); return (error); } +/* + * Set the access and modification times of a file. + */ +struct futimes_args { + int fd; + struct timeval *tptr; +}; +/* ARGSUSED */ +int +futimes(p, uap, retval) + struct proc *p; + register struct futimes_args *uap; + register_t *retval; +{ + struct timespec ts[2]; + struct file *fp; + struct timeval *usrtvp; + int error; + + usrtvp = uap->tptr; + if ((error = getutimes(usrtvp, ts)) != 0) + return (error); + if ((error = getvnode(p, uap->fd, &fp)) != 0) + return (error); + return setutimes(p, (struct vnode *)fp->f_data, ts, usrtvp == NULL); +} + /* * Truncate a file given its path name. */ @@ -2292,6 +2431,7 @@ rename(p, uap, retval) mntrename = FALSE; + bwillwrite(); NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, uap->from, p); if (error = namei(&fromnd)) @@ -2300,7 +2440,12 @@ rename(p, uap, retval) NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, UIO_USERSPACE, uap->to, p); + if (fromnd.ni_vp->v_type == VDIR) + tond.ni_cnd.cn_flags |= WILLBEDIR; if (error = namei(&tond)) { + /* Translate error code for rename("dir1", "dir2/."). */ + if (error == EISDIR && fvp->v_type == VDIR) + error = EINVAL; VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); vrele(fromnd.ni_dvp); vrele(fvp); @@ -2322,37 +2467,34 @@ rename(p, uap, retval) error = EINVAL; /* * If source is the same as the destination (that is the - * same inode number) then there is nothing to do... - * EXCEPT if the - * underlyning file system supports case insensitivity and is case preserving. Then - * a special case is made, i.e. foo -> Foo. + * same inode number) then there is nothing to do... EXCEPT if the + * underlying file system supports case insensitivity and is case + * preserving. Then a special case is made, i.e. foo -> Foo. + * + * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE + * and _PC_CASE_PRESERVING can have this exception, and they need to + * handle the special case of getting the same vnode as target and + * source. NOTE: Then the target is unlocked going into VOP_RENAME, + * so not to cause locking problems. There is a single reference on tvp. * - * Only file systems that support the pathconf selectors _PC_CASE_SENSITIVE and - * _PC_CASE_PRESERVING can have this exception, and then they would need to - * handle the special case of getting the same vnode as target and source. - * NOTE: Then the target is unlocked going into VOP_RENAME, so not to cause - * locking problems. There is a single reference on tvp. + * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE + * that correct behaviour then is just to remove the source (link) */ - if (fvp == tvp) { - error = -1; - /* - * Check to see if just changing case, if: - * - file system is case insensitive - * - and also case preserving - * _ same parent directories (so changing case by different links is not supported) - * For instance: mv a/foo a/Foo - */ - if ((tond.ni_dvp == fromnd.ni_dvp) && - (VOP_PATHCONF(tdvp, _PC_CASE_SENSITIVE, &casesense) == 0) && - (VOP_PATHCONF(tdvp, _PC_CASE_PRESERVING, &casepres) == 0) && - (casesense == 0) && - (casepres == 1)) { - /* Since the target is locked...unlock it and lose a ref */ - vput(tvp); - error = 0; - } + if (fvp == tvp && fromnd.ni_dvp == tdvp) { + if (fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && + !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, + fromnd.ni_cnd.cn_namelen)) { + error = -1; /* Default "unix" behavior */ + } else { /* probe for file system specifics */ + if (VOP_PATHCONF(tdvp, _PC_CASE_SENSITIVE, &casesense)) + casesense = 1; + if (VOP_PATHCONF(tdvp, _PC_CASE_PRESERVING, &casepres)) + casepres = 1; + if (!casesense && casepres) + vput(tvp); /* Unlock target and drop ref */ + } } - + /* * Allow the renaming of mount points. * - target must not exist @@ -2360,7 +2502,8 @@ rename(p, uap, retval) * - union mounts cannot be renamed * - "/" cannot be renamed */ - if ((fvp->v_flag & VROOT) && + if (!error && + (fvp->v_flag & VROOT) && (fvp->v_type == VDIR) && (tvp == NULL) && (fvp->v_mountedhere == NULL) && @@ -2475,7 +2618,9 @@ mkdir(p, uap, retval) int error; struct nameidata nd; + bwillwrite(); NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); + nd.ni_cnd.cn_flags |= WILLBEDIR; if (error = namei(&nd)) return (error); vp = nd.ni_vp; @@ -2515,6 +2660,7 @@ rmdir(p, uap, retval) int error; struct nameidata nd; + bwillwrite(); NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->path, p); if (error = namei(&nd)) @@ -2897,10 +3043,15 @@ getvnode(p, fd, fpp) /* * HFS/HFS PlUS SPECIFIC SYSTEM CALLS - * The following 10 system calls are designed to support features + * The following system calls are designed to support features * which are specific to the HFS & HFS Plus volume formats */ +#ifdef __APPLE_API_OBSOLETE + +/************************************************/ +/* *** Following calls will be deleted soon *** */ +/************************************************/ /* * Make a complex file. A complex file is one with multiple forks (data streams) @@ -2916,7 +3067,6 @@ mkcomplex(p,uap,retval) struct proc *p; register struct mkcomplex_args *uap; register_t *retval; - { struct vnode *vp; struct vattr vattr; @@ -2952,8 +3102,6 @@ mkcomplex(p,uap,retval) } /* end of mkcomplex system call */ - - /* * Extended stat call which returns volumeid and vnodeid as well as other info */ @@ -2973,8 +3121,6 @@ statv(p,uap,retval) } /* end of statv system call */ - - /* * Extended lstat call which returns volumeid and vnodeid as well as other info */ @@ -2993,8 +3139,6 @@ lstatv(p,uap,retval) return (EOPNOTSUPP); /* We'll just return an error for now */ } /* end of lstatv system call */ - - /* * Extended fstat call which returns volumeid and vnodeid as well as other info */ @@ -3014,6 +3158,12 @@ fstatv(p,uap,retval) } /* end of fstatv system call */ +/************************************************/ +/* *** Preceding calls will be deleted soon *** */ +/************************************************/ + +#endif /* __APPLE_API_OBSOLETE */ + /* * Obtain attribute information about a file system object @@ -3328,6 +3478,12 @@ out2: } /* end of exchangedata system call */ +#ifdef __APPLE_API_OBSOLETE + +/************************************************/ +/* *** Following calls will be deleted soon *** */ +/************************************************/ + /* * Check users access to a file */ @@ -3407,6 +3563,13 @@ checkuseraccess (p,uap,retval) } /* end of checkuseraccess system call */ +/************************************************/ +/* *** Preceding calls will be deleted soon *** */ +/************************************************/ + +#endif /* __APPLE_API_OBSOLETE */ + + struct searchfs_args { const char *path; diff --git a/bsd/vfs/vfs_utfconv.c b/bsd/vfs/vfs_utfconv.c index 462966072..d2623589b 100644 --- a/bsd/vfs/vfs_utfconv.c +++ b/bsd/vfs/vfs_utfconv.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -19,6 +19,11 @@ * * @APPLE_LICENSE_HEADER_END@ */ + + /* + Includes Unicode 3.2 decomposition code derived from Core Foundation + */ + #include #include #include @@ -56,12 +61,65 @@ #define SP_HIGH_FIRST 0xD800UL #define SP_HIGH_LAST 0xDBFFUL #define SP_LOW_FIRST 0xDC00UL -#define SP_LOW_LAST 0xDFFFUL +#define SP_LOW_LAST 0xDFFFUL + +#include "vfs_utfconvdata.h" -static u_int16_t ucs_decompose(u_int16_t, u_int16_t *); -static u_int16_t ucs_combine(u_int16_t base, u_int16_t comb); +/* + * Test for a combining character. + * + * Similar to __CFUniCharIsNonBaseCharacter except that + * unicode_combinable also includes Hangul Jamo characters. + */ +static inline int +unicode_combinable(u_int16_t character) +{ + const u_int8_t *bitmap = __CFUniCharCombiningBitmap; + u_int8_t value; + + if (character < 0x0300) + return (0); + + value = bitmap[(character >> 8) & 0xFF]; + + if (value == 0xFF) { + return (1); + } else if (value) { + bitmap = bitmap + ((value - 1) * 32) + 256; + return (bitmap[(character & 0xFF) / 8] & (1 << (character % 8)) ? 1 : 0); + } + return (0); +} + +/* + * Test for a precomposed character. + * + * Similar to __CFUniCharIsDecomposableCharacter. + */ +static inline int +unicode_decomposeable(u_int16_t character) { + const u_int8_t *bitmap = __CFUniCharDecomposableBitmap; + u_int8_t value; + + if (character < 0x00C0) + return (0); + + value = bitmap[(character >> 8) & 0xFF]; + + if (value == 0xFF) { + return (1); + } else if (value) { + bitmap = bitmap + ((value - 1) * 32) + 256; + return (bitmap[(character & 0xFF) / 8] & (1 << (character % 8)) ? 1 : 0); + } + return (0); +} + +static int unicode_decompose(u_int16_t character, u_int16_t *convertedChars); + +static u_int16_t unicode_combine(u_int16_t base, u_int16_t combining); char utf_extrabytes[32] = { @@ -133,7 +191,9 @@ utf8_encodestr(const u_int16_t * ucsp, size_t ucslen, u_int8_t * utf8p, u_int8_t * bufstart; u_int8_t * bufend; u_int16_t ucs_ch; - u_int16_t extra[2] = {0}; + u_int16_t * chp = NULL; + u_int16_t sequence[8]; + int extra = 0; int charcnt; int swapbytes = (flags & UTF_REVERSE_ENDIAN); int nullterm = ((flags & UTF_NO_NULL_TERM) == 0); @@ -147,19 +207,18 @@ utf8_encodestr(const u_int16_t * ucsp, size_t ucslen, u_int8_t * utf8p, charcnt = ucslen / 2; while (charcnt-- > 0) { - if (!decompose) - ucs_ch = swapbytes ? NXSwapShort(*ucsp++) : *ucsp++; - else if (extra[0]) { - ucs_ch = extra[0]; extra[0] = 0; - } else if (extra[1]) { - ucs_ch = extra[1]; extra[1] = 0; + if (extra > 0) { + --extra; + ucs_ch = *chp++; } else { ucs_ch = swapbytes ? NXSwapShort(*ucsp++) : *ucsp++; - ucs_ch = ucs_decompose(ucs_ch, &extra[0]); - if (extra[0]) - charcnt++; - if (extra[1]) - charcnt++; + + if (decompose && unicode_decomposeable(ucs_ch)) { + extra = unicode_decompose(ucs_ch, sequence) - 1; + charcnt += extra; + ucs_ch = sequence[0]; + chp = &sequence[1]; + } } /* Slash and NULL are not permitted */ @@ -323,30 +382,30 @@ utf8_decodestr(const u_int8_t* utf8p, size_t utf8len, u_int16_t* ucsp, goto invalid; } if (decompose) { - u_int16_t comb_ch[2]; + if (unicode_decomposeable(ucs_ch)) { + u_int16_t sequence[8]; + int count, i; - ucs_ch = ucs_decompose(ucs_ch, &comb_ch[0]); + count = unicode_decompose(ucs_ch, sequence); - if (comb_ch[0]) { - *ucsp++ = swapbytes ? NXSwapShort(ucs_ch) : ucs_ch; - if (ucsp >= bufend) - goto toolong; - ucs_ch = comb_ch[0]; - if (comb_ch[1]) { + for (i = 0; i < count; ++i) { + ucs_ch = sequence[i]; *ucsp++ = swapbytes ? NXSwapShort(ucs_ch) : ucs_ch; if (ucsp >= bufend) goto toolong; - ucs_ch = comb_ch[1]; } + continue; } } else if (precompose && (ucsp != bufstart)) { u_int16_t composite, base; - base = swapbytes ? NXSwapShort(*(ucsp - 1)) : *(ucsp - 1); - composite = ucs_combine(base, ucs_ch); - if (composite) { - --ucsp; - ucs_ch = composite; + if (unicode_combinable(ucs_ch)) { + base = swapbytes ? NXSwapShort(*(ucsp - 1)) : *(ucsp - 1); + composite = unicode_combine(base, ucs_ch); + if (composite) { + --ucsp; + ucs_ch = composite; + } } } if (ucs_ch == UCS_ALT_NULL) @@ -373,557 +432,193 @@ toolong: } -/* - * Lookup tables for Unicode chars 0x00C0 thru 0x00FF - * primary_char yields first decomposed char. If this - * char is an alpha char then get the combining char - * from the combining_char table and add 0x0300 to it. - */ + /* + * Unicode 3.2 decomposition code (derived from Core Foundation) + */ -static unsigned char primary_char[8*36] = { - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x00, 0x43, +typedef struct { + u_int32_t _key; + u_int32_t _value; +} unicode_mappings32; - 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, /* CF */ +static inline u_int32_t +getmappedvalue32(const unicode_mappings32 *theTable, u_int32_t numElem, + u_int16_t character) +{ + const unicode_mappings32 *p, *q, *divider; - 0x00, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x00, + if ((character < theTable[0]._key) || (character > theTable[numElem-1]._key)) + return (0); - 0x00, 0x55, 0x55, 0x55, 0x55, 0x59, 0x00, 0x00, /* DF */ + p = theTable; + q = p + (numElem-1); + while (p <= q) { + divider = p + ((q - p) >> 1); /* divide by 2 */ + if (character < divider->_key) { q = divider - 1; } + else if (character > divider->_key) { p = divider + 1; } + else { return (divider->_value); } + } + return (0); +} - 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x00, 0x63, +#define RECURSIVE_DECOMPOSITION (1 << 15) +#define EXTRACT_COUNT(value) (((value) >> 12) & 0x0007) - 0x65, 0x65, 0x65, 0x65, 0x69, 0x69, 0x69, 0x69, /* EF */ +typedef struct { + u_int16_t _key; + u_int16_t _value; +} unicode_mappings16; - 0x00, 0x6E, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x00, +static inline u_int16_t +getmappedvalue16(const unicode_mappings16 *theTable, u_int32_t numElem, + u_int16_t character) +{ + const unicode_mappings16 *p, *q, *divider; - 0x00, 0x75, 0x75, 0x75, 0x75, 0x79, 0x00, 0x79, /* FF */ + if ((character < theTable[0]._key) || (character > theTable[numElem-1]._key)) + return (0); - 0x41, 0x61, 0x41, 0x61, 0x41, 0x61, 0x43, 0x63, - - 0x43, 0x63, 0x43, 0x63, 0x43, 0x63, 0x44, 0x64, /* 10F */ - - 0x00, 0x00, 0x45, 0x65, 0x45, 0x65, 0x45, 0x65, - - 0x45, 0x65, 0x45, 0x65, 0x47, 0x67, 0x47, 0x67, /* 11F */ - - 0x47, 0x67, 0x47, 0x67, 0x48, 0x68, 0x00, 0x00, - - 0x49, 0x69, 0x49, 0x69, 0x49, 0x69, 0x49, 0x69, - - 0x49, 0x00, 0x00, 0x00, 0x4A, 0x6A, 0x4B, 0x6B, - - 0x00, 0x4C, 0x6C, 0x4C, 0x6C, 0x4C, 0x6C, 0x00, /* 13F */ - - 0x00, 0x00, 0x00, 0x4E, 0x6E, 0x4E, 0x6E, 0x4E, - - 0x6E, 0x00, 0x00, 0x00, 0x4F, 0x6F, 0x4F, 0x6F, - - 0x4F, 0x6F, 0x00, 0x00, 0x52, 0x72, 0x52, 0x72, - - 0x52, 0x72, 0x53, 0x73, 0x53, 0x73, 0x53, 0x73, /* 15F */ - - 0x53, 0x73, 0x54, 0x74, 0x54, 0x74, 0x00, 0x00, - - 0x55, 0x75, 0x55, 0x75, 0x55, 0x75, 0x55, 0x75, - - 0x55, 0x75, 0x55, 0x75, 0x57, 0x77, 0x59, 0x79, - - 0x59, 0x5A, 0x7A, 0x5A, 0x7A, 0x5A, 0x7A, 0x00, /* 17F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 19F */ - - 0x4F, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, - - 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1BF */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x61, 0x49, + p = theTable; + q = p + (numElem-1); + while (p <= q) { + divider = p + ((q - p) >> 1); /* divide by 2 */ + if (character < divider->_key) + q = divider - 1; + else if (character > divider->_key) + p = divider + 1; + else + return (divider->_value); + } + return (0); +} + + +static u_int32_t +unicode_recursive_decompose(u_int16_t character, u_int16_t *convertedChars) +{ + u_int16_t value; + u_int32_t length; + u_int16_t firstChar; + u_int16_t theChar; + const u_int16_t *bmpMappings; + u_int32_t usedLength; + + value = getmappedvalue16( + (const unicode_mappings16 *)__CFUniCharDecompositionTable, + __UniCharDecompositionTableLength, character); + length = EXTRACT_COUNT(value); + firstChar = value & 0x0FFF; + theChar = firstChar; + bmpMappings = (length == 1 ? &theChar : __CFUniCharMultipleDecompositionTable + firstChar); + usedLength = 0; + + if (value & RECURSIVE_DECOMPOSITION) { + usedLength = unicode_recursive_decompose((u_int16_t)*bmpMappings, convertedChars); + + --length; /* Decrement for the first char */ + if (!usedLength) + return 0; + ++bmpMappings; + convertedChars += usedLength; + } - 0x69, 0x4F, 0x6F, 0x55, 0x75, 0xDC, 0xFC, 0xDC, + usedLength += length; - 0xFC, 0xDC, 0xFC, 0xDC, 0xFC, 0x00, 0xC4, 0xE4 /* 1DF */ + while (length--) + *(convertedChars++) = *(bmpMappings++); -}; - -static unsigned char combining_char[8*36] = { - 0x00, 0x01, 0x02, 0x03, 0x08, 0x0A, 0xFF, 0x27, - - 0x00, 0x01, 0x02, 0x08, 0x00, 0x01, 0x02, 0x08, /* CF */ - - 0xFF, 0x03, 0x00, 0x01, 0x02, 0x03, 0x08, 0xFF, - - 0xFF, 0x00, 0x01, 0x02, 0x08, 0x01, 0xFF, 0xFF, /* DF */ - - 0x00, 0x01, 0x02, 0x03, 0x08, 0x0A, 0xFF, 0x27, - - 0x00, 0x01, 0x02, 0x08, 0x00, 0x01, 0x02, 0x08, /* EF */ - - 0xFF, 0x03, 0x00, 0x01, 0x02, 0x03, 0x08, 0xFF, - - 0xFF, 0x00, 0x01, 0x02, 0x08, 0x01, 0xFF, 0x08, /* FF */ - - 0x04, 0x04, 0x06, 0x06, 0x28, 0x28, 0x01, 0x01, - - 0x02, 0x02, 0x07, 0x07, 0x0C, 0x0C, 0x0C, 0x0C, - - 0x00, 0x00, 0x04, 0x04, 0x06, 0x06, 0x07, 0x07, - - 0x28, 0x28, 0x0C, 0x0C, 0x02, 0x02, 0x06, 0x06, - - 0x07, 0x07, 0x27, 0x27, 0x02, 0x02, 0x00, 0x00, - - 0x03, 0x03, 0x04, 0x04, 0x06, 0x06, 0x28, 0x28, - - 0x07, 0x00, 0x00, 0x00, 0x02, 0x02, 0x27, 0x27, - - 0x00, 0x01, 0x01, 0x27, 0x27, 0x0C, 0x0C, 0x00, /* 13F */ - - 0x00, 0x00, 0x00, 0x01, 0x01, 0x27, 0x27, 0x0C, - - 0x0C, 0x00, 0x00, 0x00, 0x04, 0x04, 0x06, 0x06, - - 0x0B, 0x0B, 0x00, 0x00, 0x01, 0x01, 0x27, 0x27, - - 0x0C, 0x0C, 0x01, 0x01, 0x02, 0x02, 0x27, 0x27, - - 0x0C, 0x0C, 0x27, 0x27, 0x0C, 0x0C, 0x00, 0x00, - - 0x03, 0x03, 0x04, 0x04, 0x06, 0x06, 0x0A, 0x0A, /* 16F */ - - 0x0B, 0x0B, 0x28, 0x28, 0x02, 0x02, 0x02, 0x02, - - 0x08, 0x01, 0x01, 0x07, 0x07, 0x0C, 0x0C, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 17F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 19F */ - - 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, - - 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x0C, /* 1CF */ - - 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x04, 0x04, 0x01, - - 0x01, 0x0C, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x04 /* 1DF */ -}; - - -/* CYRILLIC codepoints 0x0400 ~ 0x04FF */ -static const unsigned long __CyrillicDecompBitmap[] = { - 0x510A0040, 0x00000040, 0x0000510A, 0x00000000, /* 0x0400 */ - 0x00000000, 0x00000000, 0x00000000, 0x00000000, /* 0x0480 */ -}; - -/* CJK codepoints 0x3000 ~ 0x30FF */ -static const unsigned long __CJKDecompBitmap[] = { - 0x00000000, 0x00000000, 0x000AAAAA, 0xA540DB6C, /* 0x3000 */ - 0x00000802, 0x000AAAAA, 0xA540DB6C, 0x000009E2, /* 0x3080 */ -}; -#define IS_DECOMPOSABLE(table,unicodeVal) \ - (table[(unicodeVal) / 32] & (1 << (31 - ((unicodeVal) % 32)))) + return (usedLength); +} + +#define HANGUL_SBASE 0xAC00 +#define HANGUL_LBASE 0x1100 +#define HANGUL_VBASE 0x1161 +#define HANGUL_TBASE 0x11A7 + +#define HANGUL_SCOUNT 11172 +#define HANGUL_LCOUNT 19 +#define HANGUL_VCOUNT 21 +#define HANGUL_TCOUNT 28 +#define HANGUL_NCOUNT (HANGUL_VCOUNT * HANGUL_TCOUNT) /* - * ucs_decompose - decompose a composed Unicode char + * unicode_decompose - decompose a composed Unicode char * * Composed Unicode characters are forbidden on * HFS Plus volumes. ucs_decompose will convert a * composed character into its correct decomposed * sequence. * - * Currently only Tier-1 and Tier-2 languages - * are handled. Other composed characters are - * passed unchanged. + * Similar to CFUniCharDecomposeCharacter */ -static u_int16_t -ucs_decompose(register u_int16_t ch, u_int16_t *cmb) +static int +unicode_decompose(u_int16_t character, u_int16_t *convertedChars) { - u_int16_t base; - - cmb[0] = 0; - cmb[1] = 0; - - if (ch < 0x00C0) { - base = ch; - } else if (ch <= 0x01DF) { - - base = (u_int16_t) primary_char[ch - 0x00C0]; - - if (base == 0) - base = ch; - else { - if ((base < 0x00C0) || (primary_char[base - 0x00C0] == 0)) - cmb[0] = (u_int16_t)0x0300 + (u_int16_t)combining_char[ch - 0x00C0]; - else { - u_int16_t tch = base; - - base = (u_int16_t)primary_char[tch - 0x00C0]; - cmb[0] = (u_int16_t)0x0300 + (u_int16_t)combining_char[tch - 0x00C0]; - cmb[1] = (u_int16_t)0x0300 + (u_int16_t)combining_char[ch - 0x00C0]; - } - } - } else if ((ch >= 0x0400) && (ch <= 0x04FF) && - IS_DECOMPOSABLE(__CyrillicDecompBitmap, ch - 0x0400)) { - - /* Handle CYRILLIC LETTERs */ - switch(ch) { - case 0x0401: base = 0x0415; cmb[0] = 0x0308; break; /* */ - case 0x0403: base = 0x0413; cmb[0] = 0x0301; break; /* */ - case 0x0407: base = 0x0406; cmb[0] = 0x0308; break; /* */ - case 0x040C: base = 0x041A; cmb[0] = 0x0301; break; /* */ - case 0x040E: base = 0x0423; cmb[0] = 0x0306; break; /* */ - case 0x0419: base = 0x0418; cmb[0] = 0x0306; break; /* */ - case 0x0439: base = 0x0438; cmb[0] = 0x0306; break; /* */ - case 0x0451: base = 0x0435; cmb[0] = 0x0308; break; /* */ - case 0x0453: base = 0x0433; cmb[0] = 0x0301; break; /* */ - case 0x0457: base = 0x0456; cmb[0] = 0x0308; break; /* */ - case 0x045C: base = 0x043A; cmb[0] = 0x0301; break; /* */ - case 0x045E: base = 0x0443; cmb[0] = 0x0306; break; /* */ - - default: - /* Should not be hit from bit map table */ - base = ch; - } - } else if (ch == 0x1E3F) { - base = 0x006D; cmb[0] = 0x0301; /* LATIN SMALL LETTER M WITH ACUTE */ - } else if ((ch > 0x3000) && (ch < 0x3100) && - IS_DECOMPOSABLE(__CJKDecompBitmap, ch - 0x3000)) { - - /* Handle HIRAGANA LETTERs */ - switch(ch) { - case 0x3071: base = 0x306F; cmb[0] = 0x309A; break; /* PA */ - case 0x3074: base = 0x3072; cmb[0] = 0x309A; break; /* PI */ - case 0x3077: base = 0x3075; cmb[0] = 0x309A; break; /* PU */ - case 0x307A: base = 0x3078; cmb[0] = 0x309A; break; /* PE */ - - case 0x307D: base = 0x307B; cmb[0] = 0x309A; break; /* PO */ - case 0x3094: base = 0x3046; cmb[0] = 0x3099; break; /* VU */ - case 0x30D1: base = 0x30CF; cmb[0] = 0x309A; break; /* PA */ - case 0x30D4: base = 0x30D2; cmb[0] = 0x309A; break; /* PI */ - - case 0x30D7: base = 0x30D5; cmb[0] = 0x309A; break; /* PU */ - case 0x30DA: base = 0x30D8; cmb[0] = 0x309A; break; /* PE */ - case 0x30DD: base = 0x30DB; cmb[0] = 0x309A; break; /* PO */ - case 0x30F4: base = 0x30A6; cmb[0] = 0x3099; break; /* VU */ - - case 0x30F7: base = 0x30EF; cmb[0] = 0x3099; break; /* VA */ - case 0x30F8: base = 0x30F0; cmb[0] = 0x3099; break; /* VI */ - case 0x30F9: base = 0x30F1; cmb[0] = 0x3099; break; /* VE */ - case 0x30FA: base = 0x30F2; cmb[0] = 0x3099; break; /* VO */ - - default: - /* the rest (41 of them) have a simple conversion */ - base = ch - 1; - cmb[0] = 0x3099; - } - } else if ((ch >= 0xAC00) && (ch < 0xD7A4)) { - /* Hangul */ - ch -= 0xAC00; - base = 0x1100 + (ch / (21*28)); - cmb[0] = 0x1161 + (ch % (21*28)) / 28; - - if (ch % 28) - cmb[1] = 0x11A7 + (ch % 28); + if ((character >= HANGUL_SBASE) && + (character <= (HANGUL_SBASE + HANGUL_SCOUNT))) { + u_int32_t length; + + character -= HANGUL_SBASE; + length = (character % HANGUL_TCOUNT ? 3 : 2); + + *(convertedChars++) = + character / HANGUL_NCOUNT + HANGUL_LBASE; + *(convertedChars++) = + (character % HANGUL_NCOUNT) / HANGUL_TCOUNT + HANGUL_VBASE; + if (length > 2) + *convertedChars = (character % HANGUL_TCOUNT) + HANGUL_TBASE; + return (length); } else { - base = ch; + return (unicode_recursive_decompose(character, convertedChars)); } - - return (base); } - -static const short diacrit_tbl[8*6] = { - /* 300 - 307 */ 0, 58, 116, 174, 232, -1, 290, 348, - /* 308 - 30F */ 406, -1, 464, 522, 580, -1, -1, -1, - /* 310 - 317 */ -1, -1, -1, -1, -1, -1, -1, -1, - /* 318 - 31F */ -1, -1, -1, 638, -1, -1, -1, -1, - /* 320 - 327 */ -1, -1, -1, -1, -1, -1, -1, 696, - /* 328 - 32F */ 754, -1, -1, -1, -1, -1, -1, -1 -}; - -static const u_int16_t composite_tbl[58*14] = { - /* - * A B C D E F G H I J K L M - * N O P Q R S T U V W X Y Z - * [ \ ] ^ _ ` - * a b c d e f g h i j k l m - * n o p q r s t u v w x y z - */ - - /* - * 0x300 - grave accent - */ - 0x0C0, 0, 0, 0,0x0C8, 0, 0, 0,0x0CC, 0, 0, 0, 0, - 0,0x0D2, 0, 0, 0, 0, 0,0x0D9, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0x0E0, 0, 0, 0,0x0E8, 0, 0, 0,0x0EC, 0, 0, 0, 0, - 0,0x0F2, 0, 0, 0, 0, 0,0x0F9, 0, 0, 0, 0, 0, - /* - * 0x301 - acute accent - */ - 0x0C1, 0,0x106, 0,0x0C9, 0, 0, 0,0x0CD, 0, 0,0x139, 0, - 0x143,0x0D3, 0, 0,0x154,0x15A, 0,0x0DA, 0, 0, 0,0x0DD,0x179, - 0, 0, 0, 0, 0, 0, - 0x0E1, 0,0x107, 0,0x0E9, 0, 0, 0,0x0ED, 0, 0,0x13A,0x1E3F, - 0x144,0x0F3, 0, 0,0x155,0x15B, 0,0x0FA, 0, 0, 0,0x0FD,0x17A, - /* - * 0x302 - circumflex accent - */ - 0x0C2, 0,0x108, 0,0x0CA, 0,0x11C,0x124,0x0CE,0x134, 0, 0, 0, - 0,0x0D4, 0, 0, 0,0x15C, 0,0x0DB, 0,0x174, 0,0x176, 0, - 0, 0, 0, 0, 0, 0, - 0x0E2, 0,0x109, 0,0x0EA, 0,0x11D,0x125,0x0EE,0x135, 0, 0, 0, - 0,0x0F4, 0, 0, 0,0x15D, 0,0x0FB, 0,0x175, 0,0x177, 0, - /* - * 0x303 - tilde - */ - 0x0C3, 0, 0, 0, 0, 0, 0, 0,0x128, 0, 0, 0, 0, - 0x0D1,0x0D5, 0, 0, 0, 0, 0,0x168, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0x0E3, 0, 0, 0, 0, 0, 0, 0,0x129, 0, 0, 0, 0, - 0x0F1,0x0F5, 0, 0, 0, 0, 0,0x169, 0, 0, 0, 0, 0, - /* - * 0x304 - macron - */ - 0x100, 0, 0, 0,0x112, 0, 0, 0,0x12A, 0, 0, 0, 0, - 0,0x14C, 0, 0, 0, 0, 0,0x16A, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0x101, 0, 0, 0,0x113, 0, 0, 0,0x12B, 0, 0, 0, 0, - 0,0x14D, 0, 0, 0, 0, 0,0x16B, 0, 0, 0, 0, 0, - /* - * 0x306 - breve - */ - 0x102, 0, 0, 0,0x114, 0,0x11E, 0,0x12C, 0, 0, 0, 0, - 0,0x14E, 0, 0, 0, 0, 0,0x16C, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0x103, 0, 0, 0,0x115, 0,0x11F, 0,0x12D, 0, 0, 0, 0, - 0,0x14F, 0, 0, 0, 0, 0,0x16D, 0, 0, 0, 0, 0, - /* - * 0x307 - dot above - */ - 0, 0,0x10A, 0,0x116, 0,0x120, 0,0x130, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0x17B, - 0, 0, 0, 0, 0, 0, - 0, 0,0x10B, 0,0x117, 0,0x121, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0x17C, - /* - * 0x308 - diaeresis - */ - 0x0C4, 0, 0, 0,0x0CB, 0, 0, 0,0x0CF, 0, 0, 0, 0, - 0,0x0D6, 0, 0, 0, 0, 0,0x0DC, 0, 0, 0,0x178, 0, - 0, 0, 0, 0, 0, 0, - 0x0E4, 0, 0, 0,0x0EB, 0, 0, 0,0x0EF, 0, 0, 0, 0, - 0,0x0F6, 0, 0, 0, 0, 0,0x0FC, 0, 0, 0,0x0FF, 0, - /* - * 0x30A - ring above - */ - 0x0C5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,0x16E, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0x0E5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,0x16F, 0, 0, 0, 0, 0, - /* - * 0x30B - double aute accent - */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0,0x150, 0, 0, 0, 0, 0,0x170, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0,0x151, 0, 0, 0, 0, 0,0x171, 0, 0, 0, 0, 0, - /* - * 0x30C - caron - */ - 0x1CD, 0,0x10C,0x10E,0x11A, 0, 0, 0,0x1CF, 0, 0,0x13D, 0, - 0x147,0x1D1, 0, 0,0x158,0x160,0x164,0x1D3, 0, 0, 0, 0,0x17D, - 0, 0, 0, 0, 0, 0, - 0x1CE, 0,0x10D,0x10F,0x11B, 0, 0, 0,0x1D0, 0, 0,0x13E, 0, - 0x148,0x1D2, 0, 0,0x159,0x161,0x165,0x1D4, 0, 0, 0, 0,0x17E, - /* - * 0x31B - horn - */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0,0x1A0, 0, 0, 0, 0, 0,0x1AF, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0,0x1A1, 0, 0, 0, 0, 0,0x1B0, 0, 0, 0, 0, 0, - /* - * 0x327 - cedilla - */ - 0, 0,0x0C7, 0, 0, 0,0x122, 0, 0, 0,0x136,0x13B, 0, - 0x145, 0, 0, 0,0x156,0x15E,0x162, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0,0x0E7, 0, 0, 0,0x123, 0, 0, 0,0x137,0x13C, 0, - 0x146, 0, 0, 0,0x157,0x15F,0x163, 0, 0, 0, 0, 0, 0, - /* - * 0x328 - ogonek - */ - 0x104, 0, 0, 0,0x118, 0, 0, 0,0x12E, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,0x172, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0x105, 0, 0, 0,0x119, 0, 0, 0,0x12F, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,0x173, 0, 0, 0, 0, 0, -}; - - -/* CJK codepoints 0x3000 ~ 0x30FF */ -static const unsigned long __CJKCombBitmap[] = { - 0x00000000, 0x00000000, 0x02155555, 0x4A812490, /* 0x3000 */ - 0x00000004, 0x02155555, 0x4A812490, 0x0001E004, /* 0x3080 */ -}; -#define CAN_COMBINE(table,unicodeVal) \ - (table[(unicodeVal) / 32] & (1 << (31 - ((unicodeVal) % 32)))) - - /* - * ucs_combine - generate a precomposed Unicode char + * unicode_combine - generate a precomposed Unicode char * * Precomposed Unicode characters are required for some volume - * formats and network protocols. ucs_combine will combine a - * decomposed character sequence into a single precomposed + * formats and network protocols. unicode_combine will combine + * a decomposed character sequence into a single precomposed * (composite) character. * - * Currently only decomcomposed sequences from Apple's Tier 1 - * and Tier 2 languages are handled. - * - * INPUT: - * base - base character - * comb - combining character - * OUTPUT: - * result - precomposed char or zero if not combinable + * Similar toCFUniCharPrecomposeCharacter but unicode_combine + * also handles Hangul Jamo characters. */ static u_int16_t -ucs_combine(u_int16_t base, u_int16_t comb) +unicode_combine(u_int16_t base, u_int16_t combining) { - /* Get out early if we can */ - if (comb < 0x0300) - return (0); - - /* Try ordinary diacritics (0x300 - 0x32F) */ - if (comb <= 0x032F) { - int index; - - if (base >= 'A' && base <= 'z') { - index = diacrit_tbl[comb - 0x0300]; - if (index < 0 ) return (0); - - return (composite_tbl[index + (base - 'A')]); + u_int32_t value; + + /* Check HANGUL */ + if ((combining >= HANGUL_VBASE) && (combining < (HANGUL_TBASE + HANGUL_TCOUNT))) { + /* 2 char Hangul sequences */ + if ((combining < (HANGUL_VBASE + HANGUL_VCOUNT)) && + (base >= HANGUL_LBASE && base < (HANGUL_LBASE + HANGUL_LCOUNT))) { + return (HANGUL_SBASE + + ((base - HANGUL_LBASE)*(HANGUL_VCOUNT*HANGUL_TCOUNT)) + + ((combining - HANGUL_VBASE)*HANGUL_TCOUNT)); } - - /* Handle Cyrillic and some 3 char latin sequences */ - switch (comb) { - case 0x0300: - switch (base) { - case 0x00DC: return (0x01DB); - case 0x00FC: return (0x01DC); - } break; - case 0x0301: - switch (base) { - case 0x00DC: return (0x01D7); - case 0x00FC: return (0x01D8); - case 0x0413: return (0x0403); - case 0x041A: return (0x040C); - case 0x0433: return (0x0453); - case 0x043A: return (0x045C); - } break; - case 0x0304: - switch (base) { - case 0x00DC: return (0x01D5); - case 0x00FC: return (0x01D6); - case 0x00C4: return (0x01DE); - case 0x00E4: return (0x01DF); - } break; - case 0x0306: - switch (base) { - case 0x0418: return (0x0419); - case 0x0423: return (0x040E); - case 0x0438: return (0x0439); - case 0x0443: return (0x045E); - } break; - case 0x0308: - switch (base) { - case 0x0406: return (0x0407); - case 0x0415: return (0x0401); - case 0x0435: return (0x0451); - case 0x0456: return (0x0457); - } break; - case 0x030C: - switch (base) { - case 0x00DC: return (0x01D9); - case 0x00FC: return (0x01DA); - } break; + + /* 3 char Hangul sequences */ + if ((combining > HANGUL_TBASE) && + (base >= HANGUL_SBASE && base < (HANGUL_SBASE + HANGUL_SCOUNT))) { + if ((base - HANGUL_SBASE) % HANGUL_TCOUNT) + return (0); + else + return (base + (combining - HANGUL_TBASE)); } - return (0); } - /* Now try HANGUL */ - if (comb < 0x1161) - return (0); - - /* 2 char Hangul sequences */ - if ((comb <= 0x1175) && (base >= 0x1100 && base <= 0x1112)) - return (0xAC00 + ((base - 0x1100)*(21*28)) + ((comb - 0x1161)*28)); - - /* 3 char Hangul sequences */ - if ((comb >= 0x11A8 && comb <= 0x11C2) && - (base >= 0xAC00 && base <= 0xD788)) { - if ((base - 0xAC00) % 28) - return (0); - else - return (base + (comb - 0x11A7)); - } + value = getmappedvalue32( + (const unicode_mappings32 *)__CFUniCharPrecompSourceTable, + __CFUniCharPrecompositionTableLength, combining); - /* Now try HIRAGANA and KATAKANA */ - if ((comb == 0x3099 || comb == 0x309A) && - (base > 0x3000 && base < 0x3100) && - CAN_COMBINE(__CJKCombBitmap, base - 0x3000)) { - if (comb == 0x309A) { - switch(base) { - case 0x306F: return (0x3071); /* PA */ - case 0x3072: return (0x3074); /* PI */ - case 0x3075: return (0x3077); /* PU */ - case 0x3078: return (0x307A); /* PE */ - case 0x307B: return (0x307D); /* PO */ - case 0x30CF: return (0x30D1); /* PA */ - case 0x30D2: return (0x30D4); /* PI */ - case 0x30D5: return (0x30D7); /* PU */ - case 0x30D8: return (0x30DA); /* PE */ - case 0x30DB: return (0x30DD); /* PO */ - default: return (0); - } - } else /* 0x3099 */ { - switch (base) { - case 0x3046: return (0x3094); /* VU */ - case 0x30A6: return (0x30F4); /* VU */ - case 0x30EF: return (0x30F7); /* VA */ - case 0x30F0: return (0x30F8); /* VI */ - case 0x30F1: return (0x30F9); /* VE */ - case 0x30F2: return (0x30FA); /* VO */ - default: return (base + 1); /* 41 code points here */ - } - } + if (value) { + value = getmappedvalue16( + (const unicode_mappings16 *) + ((u_int32_t *)__CFUniCharBMPPrecompDestinationTable + (value & 0xFFFF)), + (value >> 16), base); } - - return (0); + return (value); } diff --git a/bsd/vfs/vfs_utfconvdata.h b/bsd/vfs/vfs_utfconvdata.h new file mode 100644 index 000000000..bc0c675fe --- /dev/null +++ b/bsd/vfs/vfs_utfconvdata.h @@ -0,0 +1,1015 @@ +/* + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + Derived from Core Foundation headers: + + CFUniCharDecompData.h + CFUniCharPrecompData.h + CFUniCharNonBaseData.h +*/ + +static const u_int16_t +__CFUniCharDecompositionTable[] = { + 0x00C0, 0x2000, 0x00C1, 0x2002, 0x00C2, 0x2004, 0x00C3, 0x2006, + 0x00C4, 0x2008, 0x00C5, 0x200A, 0x00C7, 0x200C, 0x00C8, 0x200E, + 0x00C9, 0x2010, 0x00CA, 0x2012, 0x00CB, 0x2014, 0x00CC, 0x2016, + 0x00CD, 0x2018, 0x00CE, 0x201A, 0x00CF, 0x201C, 0x00D1, 0x201E, + 0x00D2, 0x2020, 0x00D3, 0x2022, 0x00D4, 0x2024, 0x00D5, 0x2026, + 0x00D6, 0x2028, 0x00D9, 0x202A, 0x00DA, 0x202C, 0x00DB, 0x202E, + 0x00DC, 0x2030, 0x00DD, 0x2032, 0x00E0, 0x2034, 0x00E1, 0x2036, + 0x00E2, 0x2038, 0x00E3, 0x203A, 0x00E4, 0x203C, 0x00E5, 0x203E, + 0x00E7, 0x2040, 0x00E8, 0x2042, 0x00E9, 0x2044, 0x00EA, 0x2046, + 0x00EB, 0x2048, 0x00EC, 0x204A, 0x00ED, 0x204C, 0x00EE, 0x204E, + 0x00EF, 0x2050, 0x00F1, 0x2052, 0x00F2, 0x2054, 0x00F3, 0x2056, + 0x00F4, 0x2058, 0x00F5, 0x205A, 0x00F6, 0x205C, 0x00F9, 0x205E, + 0x00FA, 0x2060, 0x00FB, 0x2062, 0x00FC, 0x2064, 0x00FD, 0x2066, + 0x00FF, 0x2068, 0x0100, 0x206A, 0x0101, 0x206C, 0x0102, 0x206E, + 0x0103, 0x2070, 0x0104, 0x2072, 0x0105, 0x2074, 0x0106, 0x2076, + 0x0107, 0x2078, 0x0108, 0x207A, 0x0109, 0x207C, 0x010A, 0x207E, + 0x010B, 0x2080, 0x010C, 0x2082, 0x010D, 0x2084, 0x010E, 0x2086, + 0x010F, 0x2088, 0x0112, 0x208A, 0x0113, 0x208C, 0x0114, 0x208E, + 0x0115, 0x2090, 0x0116, 0x2092, 0x0117, 0x2094, 0x0118, 0x2096, + 0x0119, 0x2098, 0x011A, 0x209A, 0x011B, 0x209C, 0x011C, 0x209E, + 0x011D, 0x20A0, 0x011E, 0x20A2, 0x011F, 0x20A4, 0x0120, 0x20A6, + 0x0121, 0x20A8, 0x0122, 0x20AA, 0x0123, 0x20AC, 0x0124, 0x20AE, + 0x0125, 0x20B0, 0x0128, 0x20B2, 0x0129, 0x20B4, 0x012A, 0x20B6, + 0x012B, 0x20B8, 0x012C, 0x20BA, 0x012D, 0x20BC, 0x012E, 0x20BE, + 0x012F, 0x20C0, 0x0130, 0x20C2, 0x0134, 0x20C4, 0x0135, 0x20C6, + 0x0136, 0x20C8, 0x0137, 0x20CA, 0x0139, 0x20CC, 0x013A, 0x20CE, + 0x013B, 0x20D0, 0x013C, 0x20D2, 0x013D, 0x20D4, 0x013E, 0x20D6, + 0x0143, 0x20D8, 0x0144, 0x20DA, 0x0145, 0x20DC, 0x0146, 0x20DE, + 0x0147, 0x20E0, 0x0148, 0x20E2, 0x014C, 0x20E4, 0x014D, 0x20E6, + 0x014E, 0x20E8, 0x014F, 0x20EA, 0x0150, 0x20EC, 0x0151, 0x20EE, + 0x0154, 0x20F0, 0x0155, 0x20F2, 0x0156, 0x20F4, 0x0157, 0x20F6, + 0x0158, 0x20F8, 0x0159, 0x20FA, 0x015A, 0x20FC, 0x015B, 0x20FE, + 0x015C, 0x2100, 0x015D, 0x2102, 0x015E, 0x2104, 0x015F, 0x2106, + 0x0160, 0x2108, 0x0161, 0x210A, 0x0162, 0x210C, 0x0163, 0x210E, + 0x0164, 0x2110, 0x0165, 0x2112, 0x0168, 0x2114, 0x0169, 0x2116, + 0x016A, 0x2118, 0x016B, 0x211A, 0x016C, 0x211C, 0x016D, 0x211E, + 0x016E, 0x2120, 0x016F, 0x2122, 0x0170, 0x2124, 0x0171, 0x2126, + 0x0172, 0x2128, 0x0173, 0x212A, 0x0174, 0x212C, 0x0175, 0x212E, + 0x0176, 0x2130, 0x0177, 0x2132, 0x0178, 0x2134, 0x0179, 0x2136, + 0x017A, 0x2138, 0x017B, 0x213A, 0x017C, 0x213C, 0x017D, 0x213E, + 0x017E, 0x2140, 0x01A0, 0x2142, 0x01A1, 0x2144, 0x01AF, 0x2146, + 0x01B0, 0x2148, 0x01CD, 0x214A, 0x01CE, 0x214C, 0x01CF, 0x214E, + 0x01D0, 0x2150, 0x01D1, 0x2152, 0x01D2, 0x2154, 0x01D3, 0x2156, + 0x01D4, 0x2158, 0x01D5, 0xA15A, 0x01D6, 0xA15C, 0x01D7, 0xA15E, + 0x01D8, 0xA160, 0x01D9, 0xA162, 0x01DA, 0xA164, 0x01DB, 0xA166, + 0x01DC, 0xA168, 0x01DE, 0xA16A, 0x01DF, 0xA16C, 0x01E0, 0xA16E, + 0x01E1, 0xA170, 0x01E2, 0x2172, 0x01E3, 0x2174, 0x01E6, 0x2176, + 0x01E7, 0x2178, 0x01E8, 0x217A, 0x01E9, 0x217C, 0x01EA, 0x217E, + 0x01EB, 0x2180, 0x01EC, 0xA182, 0x01ED, 0xA184, 0x01EE, 0x2186, + 0x01EF, 0x2188, 0x01F0, 0x218A, 0x01F4, 0x218C, 0x01F5, 0x218E, + 0x01F8, 0x2190, 0x01F9, 0x2192, 0x01FA, 0xA194, 0x01FB, 0xA196, + 0x01FC, 0x2198, 0x01FD, 0x219A, 0x01FE, 0x219C, 0x01FF, 0x219E, + 0x0200, 0x21A0, 0x0201, 0x21A2, 0x0202, 0x21A4, 0x0203, 0x21A6, + 0x0204, 0x21A8, 0x0205, 0x21AA, 0x0206, 0x21AC, 0x0207, 0x21AE, + 0x0208, 0x21B0, 0x0209, 0x21B2, 0x020A, 0x21B4, 0x020B, 0x21B6, + 0x020C, 0x21B8, 0x020D, 0x21BA, 0x020E, 0x21BC, 0x020F, 0x21BE, + 0x0210, 0x21C0, 0x0211, 0x21C2, 0x0212, 0x21C4, 0x0213, 0x21C6, + 0x0214, 0x21C8, 0x0215, 0x21CA, 0x0216, 0x21CC, 0x0217, 0x21CE, + 0x0218, 0x21D0, 0x0219, 0x21D2, 0x021A, 0x21D4, 0x021B, 0x21D6, + 0x021E, 0x21D8, 0x021F, 0x21DA, 0x0226, 0x21DC, 0x0227, 0x21DE, + 0x0228, 0x21E0, 0x0229, 0x21E2, 0x022A, 0xA1E4, 0x022B, 0xA1E6, + 0x022C, 0xA1E8, 0x022D, 0xA1EA, 0x022E, 0x21EC, 0x022F, 0x21EE, + 0x0230, 0xA1F0, 0x0231, 0xA1F2, 0x0232, 0x21F4, 0x0233, 0x21F6, + 0x0340, 0x1300, 0x0341, 0x1301, 0x0343, 0x1313, 0x0344, 0x21F8, + 0x0374, 0x12B9, 0x037E, 0x103B, 0x0385, 0x21FA, 0x0386, 0x21FC, + 0x0387, 0x10B7, 0x0388, 0x21FE, 0x0389, 0x2200, 0x038A, 0x2202, + 0x038C, 0x2204, 0x038E, 0x2206, 0x038F, 0x2208, 0x0390, 0xA20A, + 0x03AA, 0x220C, 0x03AB, 0x220E, 0x03AC, 0x2210, 0x03AD, 0x2212, + 0x03AE, 0x2214, 0x03AF, 0x2216, 0x03B0, 0xA218, 0x03CA, 0x221A, + 0x03CB, 0x221C, 0x03CC, 0x221E, 0x03CD, 0x2220, 0x03CE, 0x2222, + 0x03D3, 0x2224, 0x03D4, 0x2226, 0x0400, 0x2228, 0x0401, 0x222A, + 0x0403, 0x222C, 0x0407, 0x222E, 0x040C, 0x2230, 0x040D, 0x2232, + 0x040E, 0x2234, 0x0419, 0x2236, 0x0439, 0x2238, 0x0450, 0x223A, + 0x0451, 0x223C, 0x0453, 0x223E, 0x0457, 0x2240, 0x045C, 0x2242, + 0x045D, 0x2244, 0x045E, 0x2246, 0x0476, 0x2248, 0x0477, 0x224A, + 0x04C1, 0x224C, 0x04C2, 0x224E, 0x04D0, 0x2250, 0x04D1, 0x2252, + 0x04D2, 0x2254, 0x04D3, 0x2256, 0x04D6, 0x2258, 0x04D7, 0x225A, + 0x04DA, 0x225C, 0x04DB, 0x225E, 0x04DC, 0x2260, 0x04DD, 0x2262, + 0x04DE, 0x2264, 0x04DF, 0x2266, 0x04E2, 0x2268, 0x04E3, 0x226A, + 0x04E4, 0x226C, 0x04E5, 0x226E, 0x04E6, 0x2270, 0x04E7, 0x2272, + 0x04EA, 0x2274, 0x04EB, 0x2276, 0x04EC, 0x2278, 0x04ED, 0x227A, + 0x04EE, 0x227C, 0x04EF, 0x227E, 0x04F0, 0x2280, 0x04F1, 0x2282, + 0x04F2, 0x2284, 0x04F3, 0x2286, 0x04F4, 0x2288, 0x04F5, 0x228A, + 0x04F8, 0x228C, 0x04F9, 0x228E, 0x0622, 0x2290, 0x0623, 0x2292, + 0x0624, 0x2294, 0x0625, 0x2296, 0x0626, 0x2298, 0x06C0, 0x229A, + 0x06C2, 0x229C, 0x06D3, 0x229E, 0x0929, 0x22A0, 0x0931, 0x22A2, + 0x0934, 0x22A4, 0x0958, 0x22A6, 0x0959, 0x22A8, 0x095A, 0x22AA, + 0x095B, 0x22AC, 0x095C, 0x22AE, 0x095D, 0x22B0, 0x095E, 0x22B2, + 0x095F, 0x22B4, 0x09CB, 0x22B6, 0x09CC, 0x22B8, 0x09DC, 0x22BA, + 0x09DD, 0x22BC, 0x09DF, 0x22BE, 0x0A33, 0x22C0, 0x0A36, 0x22C2, + 0x0A59, 0x22C4, 0x0A5A, 0x22C6, 0x0A5B, 0x22C8, 0x0A5E, 0x22CA, + 0x0B48, 0x22CC, 0x0B4B, 0x22CE, 0x0B4C, 0x22D0, 0x0B5C, 0x22D2, + 0x0B5D, 0x22D4, 0x0B94, 0x22D6, 0x0BCA, 0x22D8, 0x0BCB, 0x22DA, + 0x0BCC, 0x22DC, 0x0C48, 0x22DE, 0x0CC0, 0x22E0, 0x0CC7, 0x22E2, + 0x0CC8, 0x22E4, 0x0CCA, 0x22E6, 0x0CCB, 0xA2E8, 0x0D4A, 0x22EA, + 0x0D4B, 0x22EC, 0x0D4C, 0x22EE, 0x0DDA, 0x22F0, 0x0DDC, 0x22F2, + 0x0DDD, 0xA2F4, 0x0DDE, 0x22F6, 0x0F43, 0x22F8, 0x0F4D, 0x22FA, + 0x0F52, 0x22FC, 0x0F57, 0x22FE, 0x0F5C, 0x2300, 0x0F69, 0x2302, + 0x0F73, 0x2304, 0x0F75, 0x2306, 0x0F76, 0x2308, 0x0F78, 0x230A, + 0x0F81, 0x230C, 0x0F93, 0x230E, 0x0F9D, 0x2310, 0x0FA2, 0x2312, + 0x0FA7, 0x2314, 0x0FAC, 0x2316, 0x0FB9, 0x2318, 0x1026, 0x231A, + 0x1E00, 0x231C, 0x1E01, 0x231E, 0x1E02, 0x2320, 0x1E03, 0x2322, + 0x1E04, 0x2324, 0x1E05, 0x2326, 0x1E06, 0x2328, 0x1E07, 0x232A, + 0x1E08, 0xA32C, 0x1E09, 0xA32E, 0x1E0A, 0x2330, 0x1E0B, 0x2332, + 0x1E0C, 0x2334, 0x1E0D, 0x2336, 0x1E0E, 0x2338, 0x1E0F, 0x233A, + 0x1E10, 0x233C, 0x1E11, 0x233E, 0x1E12, 0x2340, 0x1E13, 0x2342, + 0x1E14, 0xA344, 0x1E15, 0xA346, 0x1E16, 0xA348, 0x1E17, 0xA34A, + 0x1E18, 0x234C, 0x1E19, 0x234E, 0x1E1A, 0x2350, 0x1E1B, 0x2352, + 0x1E1C, 0xA354, 0x1E1D, 0xA356, 0x1E1E, 0x2358, 0x1E1F, 0x235A, + 0x1E20, 0x235C, 0x1E21, 0x235E, 0x1E22, 0x2360, 0x1E23, 0x2362, + 0x1E24, 0x2364, 0x1E25, 0x2366, 0x1E26, 0x2368, 0x1E27, 0x236A, + 0x1E28, 0x236C, 0x1E29, 0x236E, 0x1E2A, 0x2370, 0x1E2B, 0x2372, + 0x1E2C, 0x2374, 0x1E2D, 0x2376, 0x1E2E, 0xA378, 0x1E2F, 0xA37A, + 0x1E30, 0x237C, 0x1E31, 0x237E, 0x1E32, 0x2380, 0x1E33, 0x2382, + 0x1E34, 0x2384, 0x1E35, 0x2386, 0x1E36, 0x2388, 0x1E37, 0x238A, + 0x1E38, 0xA38C, 0x1E39, 0xA38E, 0x1E3A, 0x2390, 0x1E3B, 0x2392, + 0x1E3C, 0x2394, 0x1E3D, 0x2396, 0x1E3E, 0x2398, 0x1E3F, 0x239A, + 0x1E40, 0x239C, 0x1E41, 0x239E, 0x1E42, 0x23A0, 0x1E43, 0x23A2, + 0x1E44, 0x23A4, 0x1E45, 0x23A6, 0x1E46, 0x23A8, 0x1E47, 0x23AA, + 0x1E48, 0x23AC, 0x1E49, 0x23AE, 0x1E4A, 0x23B0, 0x1E4B, 0x23B2, + 0x1E4C, 0xA3B4, 0x1E4D, 0xA3B6, 0x1E4E, 0xA3B8, 0x1E4F, 0xA3BA, + 0x1E50, 0xA3BC, 0x1E51, 0xA3BE, 0x1E52, 0xA3C0, 0x1E53, 0xA3C2, + 0x1E54, 0x23C4, 0x1E55, 0x23C6, 0x1E56, 0x23C8, 0x1E57, 0x23CA, + 0x1E58, 0x23CC, 0x1E59, 0x23CE, 0x1E5A, 0x23D0, 0x1E5B, 0x23D2, + 0x1E5C, 0xA3D4, 0x1E5D, 0xA3D6, 0x1E5E, 0x23D8, 0x1E5F, 0x23DA, + 0x1E60, 0x23DC, 0x1E61, 0x23DE, 0x1E62, 0x23E0, 0x1E63, 0x23E2, + 0x1E64, 0xA3E4, 0x1E65, 0xA3E6, 0x1E66, 0xA3E8, 0x1E67, 0xA3EA, + 0x1E68, 0xA3EC, 0x1E69, 0xA3EE, 0x1E6A, 0x23F0, 0x1E6B, 0x23F2, + 0x1E6C, 0x23F4, 0x1E6D, 0x23F6, 0x1E6E, 0x23F8, 0x1E6F, 0x23FA, + 0x1E70, 0x23FC, 0x1E71, 0x23FE, 0x1E72, 0x2400, 0x1E73, 0x2402, + 0x1E74, 0x2404, 0x1E75, 0x2406, 0x1E76, 0x2408, 0x1E77, 0x240A, + 0x1E78, 0xA40C, 0x1E79, 0xA40E, 0x1E7A, 0xA410, 0x1E7B, 0xA412, + 0x1E7C, 0x2414, 0x1E7D, 0x2416, 0x1E7E, 0x2418, 0x1E7F, 0x241A, + 0x1E80, 0x241C, 0x1E81, 0x241E, 0x1E82, 0x2420, 0x1E83, 0x2422, + 0x1E84, 0x2424, 0x1E85, 0x2426, 0x1E86, 0x2428, 0x1E87, 0x242A, + 0x1E88, 0x242C, 0x1E89, 0x242E, 0x1E8A, 0x2430, 0x1E8B, 0x2432, + 0x1E8C, 0x2434, 0x1E8D, 0x2436, 0x1E8E, 0x2438, 0x1E8F, 0x243A, + 0x1E90, 0x243C, 0x1E91, 0x243E, 0x1E92, 0x2440, 0x1E93, 0x2442, + 0x1E94, 0x2444, 0x1E95, 0x2446, 0x1E96, 0x2448, 0x1E97, 0x244A, + 0x1E98, 0x244C, 0x1E99, 0x244E, 0x1E9B, 0x2450, 0x1EA0, 0x2452, + 0x1EA1, 0x2454, 0x1EA2, 0x2456, 0x1EA3, 0x2458, 0x1EA4, 0xA45A, + 0x1EA5, 0xA45C, 0x1EA6, 0xA45E, 0x1EA7, 0xA460, 0x1EA8, 0xA462, + 0x1EA9, 0xA464, 0x1EAA, 0xA466, 0x1EAB, 0xA468, 0x1EAC, 0xA46A, + 0x1EAD, 0xA46C, 0x1EAE, 0xA46E, 0x1EAF, 0xA470, 0x1EB0, 0xA472, + 0x1EB1, 0xA474, 0x1EB2, 0xA476, 0x1EB3, 0xA478, 0x1EB4, 0xA47A, + 0x1EB5, 0xA47C, 0x1EB6, 0xA47E, 0x1EB7, 0xA480, 0x1EB8, 0x2482, + 0x1EB9, 0x2484, 0x1EBA, 0x2486, 0x1EBB, 0x2488, 0x1EBC, 0x248A, + 0x1EBD, 0x248C, 0x1EBE, 0xA48E, 0x1EBF, 0xA490, 0x1EC0, 0xA492, + 0x1EC1, 0xA494, 0x1EC2, 0xA496, 0x1EC3, 0xA498, 0x1EC4, 0xA49A, + 0x1EC5, 0xA49C, 0x1EC6, 0xA49E, 0x1EC7, 0xA4A0, 0x1EC8, 0x24A2, + 0x1EC9, 0x24A4, 0x1ECA, 0x24A6, 0x1ECB, 0x24A8, 0x1ECC, 0x24AA, + 0x1ECD, 0x24AC, 0x1ECE, 0x24AE, 0x1ECF, 0x24B0, 0x1ED0, 0xA4B2, + 0x1ED1, 0xA4B4, 0x1ED2, 0xA4B6, 0x1ED3, 0xA4B8, 0x1ED4, 0xA4BA, + 0x1ED5, 0xA4BC, 0x1ED6, 0xA4BE, 0x1ED7, 0xA4C0, 0x1ED8, 0xA4C2, + 0x1ED9, 0xA4C4, 0x1EDA, 0xA4C6, 0x1EDB, 0xA4C8, 0x1EDC, 0xA4CA, + 0x1EDD, 0xA4CC, 0x1EDE, 0xA4CE, 0x1EDF, 0xA4D0, 0x1EE0, 0xA4D2, + 0x1EE1, 0xA4D4, 0x1EE2, 0xA4D6, 0x1EE3, 0xA4D8, 0x1EE4, 0x24DA, + 0x1EE5, 0x24DC, 0x1EE6, 0x24DE, 0x1EE7, 0x24E0, 0x1EE8, 0xA4E2, + 0x1EE9, 0xA4E4, 0x1EEA, 0xA4E6, 0x1EEB, 0xA4E8, 0x1EEC, 0xA4EA, + 0x1EED, 0xA4EC, 0x1EEE, 0xA4EE, 0x1EEF, 0xA4F0, 0x1EF0, 0xA4F2, + 0x1EF1, 0xA4F4, 0x1EF2, 0x24F6, 0x1EF3, 0x24F8, 0x1EF4, 0x24FA, + 0x1EF5, 0x24FC, 0x1EF6, 0x24FE, 0x1EF7, 0x2500, 0x1EF8, 0x2502, + 0x1EF9, 0x2504, 0x1F00, 0x2506, 0x1F01, 0x2508, 0x1F02, 0xA50A, + 0x1F03, 0xA50C, 0x1F04, 0xA50E, 0x1F05, 0xA510, 0x1F06, 0xA512, + 0x1F07, 0xA514, 0x1F08, 0x2516, 0x1F09, 0x2518, 0x1F0A, 0xA51A, + 0x1F0B, 0xA51C, 0x1F0C, 0xA51E, 0x1F0D, 0xA520, 0x1F0E, 0xA522, + 0x1F0F, 0xA524, 0x1F10, 0x2526, 0x1F11, 0x2528, 0x1F12, 0xA52A, + 0x1F13, 0xA52C, 0x1F14, 0xA52E, 0x1F15, 0xA530, 0x1F18, 0x2532, + 0x1F19, 0x2534, 0x1F1A, 0xA536, 0x1F1B, 0xA538, 0x1F1C, 0xA53A, + 0x1F1D, 0xA53C, 0x1F20, 0x253E, 0x1F21, 0x2540, 0x1F22, 0xA542, + 0x1F23, 0xA544, 0x1F24, 0xA546, 0x1F25, 0xA548, 0x1F26, 0xA54A, + 0x1F27, 0xA54C, 0x1F28, 0x254E, 0x1F29, 0x2550, 0x1F2A, 0xA552, + 0x1F2B, 0xA554, 0x1F2C, 0xA556, 0x1F2D, 0xA558, 0x1F2E, 0xA55A, + 0x1F2F, 0xA55C, 0x1F30, 0x255E, 0x1F31, 0x2560, 0x1F32, 0xA562, + 0x1F33, 0xA564, 0x1F34, 0xA566, 0x1F35, 0xA568, 0x1F36, 0xA56A, + 0x1F37, 0xA56C, 0x1F38, 0x256E, 0x1F39, 0x2570, 0x1F3A, 0xA572, + 0x1F3B, 0xA574, 0x1F3C, 0xA576, 0x1F3D, 0xA578, 0x1F3E, 0xA57A, + 0x1F3F, 0xA57C, 0x1F40, 0x257E, 0x1F41, 0x2580, 0x1F42, 0xA582, + 0x1F43, 0xA584, 0x1F44, 0xA586, 0x1F45, 0xA588, 0x1F48, 0x258A, + 0x1F49, 0x258C, 0x1F4A, 0xA58E, 0x1F4B, 0xA590, 0x1F4C, 0xA592, + 0x1F4D, 0xA594, 0x1F50, 0x2596, 0x1F51, 0x2598, 0x1F52, 0xA59A, + 0x1F53, 0xA59C, 0x1F54, 0xA59E, 0x1F55, 0xA5A0, 0x1F56, 0xA5A2, + 0x1F57, 0xA5A4, 0x1F59, 0x25A6, 0x1F5B, 0xA5A8, 0x1F5D, 0xA5AA, + 0x1F5F, 0xA5AC, 0x1F60, 0x25AE, 0x1F61, 0x25B0, 0x1F62, 0xA5B2, + 0x1F63, 0xA5B4, 0x1F64, 0xA5B6, 0x1F65, 0xA5B8, 0x1F66, 0xA5BA, + 0x1F67, 0xA5BC, 0x1F68, 0x25BE, 0x1F69, 0x25C0, 0x1F6A, 0xA5C2, + 0x1F6B, 0xA5C4, 0x1F6C, 0xA5C6, 0x1F6D, 0xA5C8, 0x1F6E, 0xA5CA, + 0x1F6F, 0xA5CC, 0x1F70, 0x25CE, 0x1F71, 0x93AC, 0x1F72, 0x25D0, + 0x1F73, 0x93AD, 0x1F74, 0x25D2, 0x1F75, 0x93AE, 0x1F76, 0x25D4, + 0x1F77, 0x93AF, 0x1F78, 0x25D6, 0x1F79, 0x93CC, 0x1F7A, 0x25D8, + 0x1F7B, 0x93CD, 0x1F7C, 0x25DA, 0x1F7D, 0x93CE, 0x1F80, 0xA5DC, + 0x1F81, 0xA5DE, 0x1F82, 0xA5E0, 0x1F83, 0xA5E2, 0x1F84, 0xA5E4, + 0x1F85, 0xA5E6, 0x1F86, 0xA5E8, 0x1F87, 0xA5EA, 0x1F88, 0xA5EC, + 0x1F89, 0xA5EE, 0x1F8A, 0xA5F0, 0x1F8B, 0xA5F2, 0x1F8C, 0xA5F4, + 0x1F8D, 0xA5F6, 0x1F8E, 0xA5F8, 0x1F8F, 0xA5FA, 0x1F90, 0xA5FC, + 0x1F91, 0xA5FE, 0x1F92, 0xA600, 0x1F93, 0xA602, 0x1F94, 0xA604, + 0x1F95, 0xA606, 0x1F96, 0xA608, 0x1F97, 0xA60A, 0x1F98, 0xA60C, + 0x1F99, 0xA60E, 0x1F9A, 0xA610, 0x1F9B, 0xA612, 0x1F9C, 0xA614, + 0x1F9D, 0xA616, 0x1F9E, 0xA618, 0x1F9F, 0xA61A, 0x1FA0, 0xA61C, + 0x1FA1, 0xA61E, 0x1FA2, 0xA620, 0x1FA3, 0xA622, 0x1FA4, 0xA624, + 0x1FA5, 0xA626, 0x1FA6, 0xA628, 0x1FA7, 0xA62A, 0x1FA8, 0xA62C, + 0x1FA9, 0xA62E, 0x1FAA, 0xA630, 0x1FAB, 0xA632, 0x1FAC, 0xA634, + 0x1FAD, 0xA636, 0x1FAE, 0xA638, 0x1FAF, 0xA63A, 0x1FB0, 0x263C, + 0x1FB1, 0x263E, 0x1FB2, 0xA640, 0x1FB3, 0x2642, 0x1FB4, 0xA644, + 0x1FB6, 0x2646, 0x1FB7, 0xA648, 0x1FB8, 0x264A, 0x1FB9, 0x264C, + 0x1FBA, 0x264E, 0x1FBB, 0x9386, 0x1FBC, 0x2650, 0x1FBE, 0x13B9, + 0x1FC1, 0x2652, 0x1FC2, 0xA654, 0x1FC3, 0x2656, 0x1FC4, 0xA658, + 0x1FC6, 0x265A, 0x1FC7, 0xA65C, 0x1FC8, 0x265E, 0x1FC9, 0x9388, + 0x1FCA, 0x2660, 0x1FCB, 0x9389, 0x1FCC, 0x2662, 0x1FCD, 0x2664, + 0x1FCE, 0x2666, 0x1FCF, 0x2668, 0x1FD0, 0x266A, 0x1FD1, 0x266C, + 0x1FD2, 0xA66E, 0x1FD3, 0x9390, 0x1FD6, 0x2670, 0x1FD7, 0xA672, + 0x1FD8, 0x2674, 0x1FD9, 0x2676, 0x1FDA, 0x2678, 0x1FDB, 0x938A, + 0x1FDD, 0x267A, 0x1FDE, 0x267C, 0x1FDF, 0x267E, 0x1FE0, 0x2680, + 0x1FE1, 0x2682, 0x1FE2, 0xA684, 0x1FE3, 0x93B0, 0x1FE4, 0x2686, + 0x1FE5, 0x2688, 0x1FE6, 0x268A, 0x1FE7, 0xA68C, 0x1FE8, 0x268E, + 0x1FE9, 0x2690, 0x1FEA, 0x2692, 0x1FEB, 0x938E, 0x1FEC, 0x2694, + 0x1FED, 0x2696, 0x1FEE, 0x9385, 0x1FEF, 0x1060, 0x1FF2, 0xA698, + 0x1FF3, 0x269A, 0x1FF4, 0xA69C, 0x1FF6, 0x269E, 0x1FF7, 0xA6A0, + 0x1FF8, 0x26A2, 0x1FF9, 0x938C, 0x1FFA, 0x26A4, 0x1FFB, 0x938F, + 0x1FFC, 0x26A6, 0x1FFD, 0x10B4, 0x304C, 0x26A8, 0x304E, 0x26AA, + 0x3050, 0x26AC, 0x3052, 0x26AE, 0x3054, 0x26B0, 0x3056, 0x26B2, + 0x3058, 0x26B4, 0x305A, 0x26B6, 0x305C, 0x26B8, 0x305E, 0x26BA, + 0x3060, 0x26BC, 0x3062, 0x26BE, 0x3065, 0x26C0, 0x3067, 0x26C2, + 0x3069, 0x26C4, 0x3070, 0x26C6, 0x3071, 0x26C8, 0x3073, 0x26CA, + 0x3074, 0x26CC, 0x3076, 0x26CE, 0x3077, 0x26D0, 0x3079, 0x26D2, + 0x307A, 0x26D4, 0x307C, 0x26D6, 0x307D, 0x26D8, 0x3094, 0x26DA, + 0x309E, 0x26DC, 0x30AC, 0x26DE, 0x30AE, 0x26E0, 0x30B0, 0x26E2, + 0x30B2, 0x26E4, 0x30B4, 0x26E6, 0x30B6, 0x26E8, 0x30B8, 0x26EA, + 0x30BA, 0x26EC, 0x30BC, 0x26EE, 0x30BE, 0x26F0, 0x30C0, 0x26F2, + 0x30C2, 0x26F4, 0x30C5, 0x26F6, 0x30C7, 0x26F8, 0x30C9, 0x26FA, + 0x30D0, 0x26FC, 0x30D1, 0x26FE, 0x30D3, 0x2700, 0x30D4, 0x2702, + 0x30D6, 0x2704, 0x30D7, 0x2706, 0x30D9, 0x2708, 0x30DA, 0x270A, + 0x30DC, 0x270C, 0x30DD, 0x270E, 0x30F4, 0x2710, 0x30F7, 0x2712, + 0x30F8, 0x2714, 0x30F9, 0x2716, 0x30FA, 0x2718, 0x30FE, 0x271A, + 0xFB1D, 0x271C, 0xFB1F, 0x271E, 0xFB2A, 0x2720, 0xFB2B, 0x2722, + 0xFB2C, 0xA724, 0xFB2D, 0xA726, 0xFB2E, 0x2728, 0xFB2F, 0x272A, + 0xFB30, 0x272C, 0xFB31, 0x272E, 0xFB32, 0x2730, 0xFB33, 0x2732, + 0xFB34, 0x2734, 0xFB35, 0x2736, 0xFB36, 0x2738, 0xFB38, 0x273A, + 0xFB39, 0x273C, 0xFB3A, 0x273E, 0xFB3B, 0x2740, 0xFB3C, 0x2742, + 0xFB3E, 0x2744, 0xFB40, 0x2746, 0xFB41, 0x2748, 0xFB43, 0x274A, + 0xFB44, 0x274C, 0xFB46, 0x274E, 0xFB47, 0x2750, 0xFB48, 0x2752, + 0xFB49, 0x2754, 0xFB4A, 0x2756, 0xFB4B, 0x2758, 0xFB4C, 0x275A, + 0xFB4D, 0x275C, 0xFB4E, 0x275E +}; + +static const u_int32_t __UniCharDecompositionTableLength = + (sizeof(__CFUniCharDecompositionTable) / (sizeof(u_int16_t) * 2)); + + +static const u_int16_t +__CFUniCharMultipleDecompositionTable[] = { + 0x0041, 0x0300, 0x0041, 0x0301, 0x0041, 0x0302, 0x0041, 0x0303, + 0x0041, 0x0308, 0x0041, 0x030A, 0x0043, 0x0327, 0x0045, 0x0300, + 0x0045, 0x0301, 0x0045, 0x0302, 0x0045, 0x0308, 0x0049, 0x0300, + 0x0049, 0x0301, 0x0049, 0x0302, 0x0049, 0x0308, 0x004E, 0x0303, + 0x004F, 0x0300, 0x004F, 0x0301, 0x004F, 0x0302, 0x004F, 0x0303, + 0x004F, 0x0308, 0x0055, 0x0300, 0x0055, 0x0301, 0x0055, 0x0302, + 0x0055, 0x0308, 0x0059, 0x0301, 0x0061, 0x0300, 0x0061, 0x0301, + 0x0061, 0x0302, 0x0061, 0x0303, 0x0061, 0x0308, 0x0061, 0x030A, + 0x0063, 0x0327, 0x0065, 0x0300, 0x0065, 0x0301, 0x0065, 0x0302, + 0x0065, 0x0308, 0x0069, 0x0300, 0x0069, 0x0301, 0x0069, 0x0302, + 0x0069, 0x0308, 0x006E, 0x0303, 0x006F, 0x0300, 0x006F, 0x0301, + 0x006F, 0x0302, 0x006F, 0x0303, 0x006F, 0x0308, 0x0075, 0x0300, + 0x0075, 0x0301, 0x0075, 0x0302, 0x0075, 0x0308, 0x0079, 0x0301, + 0x0079, 0x0308, 0x0041, 0x0304, 0x0061, 0x0304, 0x0041, 0x0306, + 0x0061, 0x0306, 0x0041, 0x0328, 0x0061, 0x0328, 0x0043, 0x0301, + 0x0063, 0x0301, 0x0043, 0x0302, 0x0063, 0x0302, 0x0043, 0x0307, + 0x0063, 0x0307, 0x0043, 0x030C, 0x0063, 0x030C, 0x0044, 0x030C, + 0x0064, 0x030C, 0x0045, 0x0304, 0x0065, 0x0304, 0x0045, 0x0306, + 0x0065, 0x0306, 0x0045, 0x0307, 0x0065, 0x0307, 0x0045, 0x0328, + 0x0065, 0x0328, 0x0045, 0x030C, 0x0065, 0x030C, 0x0047, 0x0302, + 0x0067, 0x0302, 0x0047, 0x0306, 0x0067, 0x0306, 0x0047, 0x0307, + 0x0067, 0x0307, 0x0047, 0x0327, 0x0067, 0x0327, 0x0048, 0x0302, + 0x0068, 0x0302, 0x0049, 0x0303, 0x0069, 0x0303, 0x0049, 0x0304, + 0x0069, 0x0304, 0x0049, 0x0306, 0x0069, 0x0306, 0x0049, 0x0328, + 0x0069, 0x0328, 0x0049, 0x0307, 0x004A, 0x0302, 0x006A, 0x0302, + 0x004B, 0x0327, 0x006B, 0x0327, 0x004C, 0x0301, 0x006C, 0x0301, + 0x004C, 0x0327, 0x006C, 0x0327, 0x004C, 0x030C, 0x006C, 0x030C, + 0x004E, 0x0301, 0x006E, 0x0301, 0x004E, 0x0327, 0x006E, 0x0327, + 0x004E, 0x030C, 0x006E, 0x030C, 0x004F, 0x0304, 0x006F, 0x0304, + 0x004F, 0x0306, 0x006F, 0x0306, 0x004F, 0x030B, 0x006F, 0x030B, + 0x0052, 0x0301, 0x0072, 0x0301, 0x0052, 0x0327, 0x0072, 0x0327, + 0x0052, 0x030C, 0x0072, 0x030C, 0x0053, 0x0301, 0x0073, 0x0301, + 0x0053, 0x0302, 0x0073, 0x0302, 0x0053, 0x0327, 0x0073, 0x0327, + 0x0053, 0x030C, 0x0073, 0x030C, 0x0054, 0x0327, 0x0074, 0x0327, + 0x0054, 0x030C, 0x0074, 0x030C, 0x0055, 0x0303, 0x0075, 0x0303, + 0x0055, 0x0304, 0x0075, 0x0304, 0x0055, 0x0306, 0x0075, 0x0306, + 0x0055, 0x030A, 0x0075, 0x030A, 0x0055, 0x030B, 0x0075, 0x030B, + 0x0055, 0x0328, 0x0075, 0x0328, 0x0057, 0x0302, 0x0077, 0x0302, + 0x0059, 0x0302, 0x0079, 0x0302, 0x0059, 0x0308, 0x005A, 0x0301, + 0x007A, 0x0301, 0x005A, 0x0307, 0x007A, 0x0307, 0x005A, 0x030C, + 0x007A, 0x030C, 0x004F, 0x031B, 0x006F, 0x031B, 0x0055, 0x031B, + 0x0075, 0x031B, 0x0041, 0x030C, 0x0061, 0x030C, 0x0049, 0x030C, + 0x0069, 0x030C, 0x004F, 0x030C, 0x006F, 0x030C, 0x0055, 0x030C, + 0x0075, 0x030C, 0x00DC, 0x0304, 0x00FC, 0x0304, 0x00DC, 0x0301, + 0x00FC, 0x0301, 0x00DC, 0x030C, 0x00FC, 0x030C, 0x00DC, 0x0300, + 0x00FC, 0x0300, 0x00C4, 0x0304, 0x00E4, 0x0304, 0x0226, 0x0304, + 0x0227, 0x0304, 0x00C6, 0x0304, 0x00E6, 0x0304, 0x0047, 0x030C, + 0x0067, 0x030C, 0x004B, 0x030C, 0x006B, 0x030C, 0x004F, 0x0328, + 0x006F, 0x0328, 0x01EA, 0x0304, 0x01EB, 0x0304, 0x01B7, 0x030C, + 0x0292, 0x030C, 0x006A, 0x030C, 0x0047, 0x0301, 0x0067, 0x0301, + 0x004E, 0x0300, 0x006E, 0x0300, 0x00C5, 0x0301, 0x00E5, 0x0301, + 0x00C6, 0x0301, 0x00E6, 0x0301, 0x00D8, 0x0301, 0x00F8, 0x0301, + 0x0041, 0x030F, 0x0061, 0x030F, 0x0041, 0x0311, 0x0061, 0x0311, + 0x0045, 0x030F, 0x0065, 0x030F, 0x0045, 0x0311, 0x0065, 0x0311, + 0x0049, 0x030F, 0x0069, 0x030F, 0x0049, 0x0311, 0x0069, 0x0311, + 0x004F, 0x030F, 0x006F, 0x030F, 0x004F, 0x0311, 0x006F, 0x0311, + 0x0052, 0x030F, 0x0072, 0x030F, 0x0052, 0x0311, 0x0072, 0x0311, + 0x0055, 0x030F, 0x0075, 0x030F, 0x0055, 0x0311, 0x0075, 0x0311, + 0x0053, 0x0326, 0x0073, 0x0326, 0x0054, 0x0326, 0x0074, 0x0326, + 0x0048, 0x030C, 0x0068, 0x030C, 0x0041, 0x0307, 0x0061, 0x0307, + 0x0045, 0x0327, 0x0065, 0x0327, 0x00D6, 0x0304, 0x00F6, 0x0304, + 0x00D5, 0x0304, 0x00F5, 0x0304, 0x004F, 0x0307, 0x006F, 0x0307, + 0x022E, 0x0304, 0x022F, 0x0304, 0x0059, 0x0304, 0x0079, 0x0304, + 0x0308, 0x0301, 0x00A8, 0x0301, 0x0391, 0x0301, 0x0395, 0x0301, + 0x0397, 0x0301, 0x0399, 0x0301, 0x039F, 0x0301, 0x03A5, 0x0301, + 0x03A9, 0x0301, 0x03CA, 0x0301, 0x0399, 0x0308, 0x03A5, 0x0308, + 0x03B1, 0x0301, 0x03B5, 0x0301, 0x03B7, 0x0301, 0x03B9, 0x0301, + 0x03CB, 0x0301, 0x03B9, 0x0308, 0x03C5, 0x0308, 0x03BF, 0x0301, + 0x03C5, 0x0301, 0x03C9, 0x0301, 0x03D2, 0x0301, 0x03D2, 0x0308, + 0x0415, 0x0300, 0x0415, 0x0308, 0x0413, 0x0301, 0x0406, 0x0308, + 0x041A, 0x0301, 0x0418, 0x0300, 0x0423, 0x0306, 0x0418, 0x0306, + 0x0438, 0x0306, 0x0435, 0x0300, 0x0435, 0x0308, 0x0433, 0x0301, + 0x0456, 0x0308, 0x043A, 0x0301, 0x0438, 0x0300, 0x0443, 0x0306, + 0x0474, 0x030F, 0x0475, 0x030F, 0x0416, 0x0306, 0x0436, 0x0306, + 0x0410, 0x0306, 0x0430, 0x0306, 0x0410, 0x0308, 0x0430, 0x0308, + 0x0415, 0x0306, 0x0435, 0x0306, 0x04D8, 0x0308, 0x04D9, 0x0308, + 0x0416, 0x0308, 0x0436, 0x0308, 0x0417, 0x0308, 0x0437, 0x0308, + 0x0418, 0x0304, 0x0438, 0x0304, 0x0418, 0x0308, 0x0438, 0x0308, + 0x041E, 0x0308, 0x043E, 0x0308, 0x04E8, 0x0308, 0x04E9, 0x0308, + 0x042D, 0x0308, 0x044D, 0x0308, 0x0423, 0x0304, 0x0443, 0x0304, + 0x0423, 0x0308, 0x0443, 0x0308, 0x0423, 0x030B, 0x0443, 0x030B, + 0x0427, 0x0308, 0x0447, 0x0308, 0x042B, 0x0308, 0x044B, 0x0308, + 0x0627, 0x0653, 0x0627, 0x0654, 0x0648, 0x0654, 0x0627, 0x0655, + 0x064A, 0x0654, 0x06D5, 0x0654, 0x06C1, 0x0654, 0x06D2, 0x0654, + 0x0928, 0x093C, 0x0930, 0x093C, 0x0933, 0x093C, 0x0915, 0x093C, + 0x0916, 0x093C, 0x0917, 0x093C, 0x091C, 0x093C, 0x0921, 0x093C, + 0x0922, 0x093C, 0x092B, 0x093C, 0x092F, 0x093C, 0x09C7, 0x09BE, + 0x09C7, 0x09D7, 0x09A1, 0x09BC, 0x09A2, 0x09BC, 0x09AF, 0x09BC, + 0x0A32, 0x0A3C, 0x0A38, 0x0A3C, 0x0A16, 0x0A3C, 0x0A17, 0x0A3C, + 0x0A1C, 0x0A3C, 0x0A2B, 0x0A3C, 0x0B47, 0x0B56, 0x0B47, 0x0B3E, + 0x0B47, 0x0B57, 0x0B21, 0x0B3C, 0x0B22, 0x0B3C, 0x0B92, 0x0BD7, + 0x0BC6, 0x0BBE, 0x0BC7, 0x0BBE, 0x0BC6, 0x0BD7, 0x0C46, 0x0C56, + 0x0CBF, 0x0CD5, 0x0CC6, 0x0CD5, 0x0CC6, 0x0CD6, 0x0CC6, 0x0CC2, + 0x0CCA, 0x0CD5, 0x0D46, 0x0D3E, 0x0D47, 0x0D3E, 0x0D46, 0x0D57, + 0x0DD9, 0x0DCA, 0x0DD9, 0x0DCF, 0x0DDC, 0x0DCA, 0x0DD9, 0x0DDF, + 0x0F42, 0x0FB7, 0x0F4C, 0x0FB7, 0x0F51, 0x0FB7, 0x0F56, 0x0FB7, + 0x0F5B, 0x0FB7, 0x0F40, 0x0FB5, 0x0F71, 0x0F72, 0x0F71, 0x0F74, + 0x0FB2, 0x0F80, 0x0FB3, 0x0F80, 0x0F71, 0x0F80, 0x0F92, 0x0FB7, + 0x0F9C, 0x0FB7, 0x0FA1, 0x0FB7, 0x0FA6, 0x0FB7, 0x0FAB, 0x0FB7, + 0x0F90, 0x0FB5, 0x1025, 0x102E, 0x0041, 0x0325, 0x0061, 0x0325, + 0x0042, 0x0307, 0x0062, 0x0307, 0x0042, 0x0323, 0x0062, 0x0323, + 0x0042, 0x0331, 0x0062, 0x0331, 0x00C7, 0x0301, 0x00E7, 0x0301, + 0x0044, 0x0307, 0x0064, 0x0307, 0x0044, 0x0323, 0x0064, 0x0323, + 0x0044, 0x0331, 0x0064, 0x0331, 0x0044, 0x0327, 0x0064, 0x0327, + 0x0044, 0x032D, 0x0064, 0x032D, 0x0112, 0x0300, 0x0113, 0x0300, + 0x0112, 0x0301, 0x0113, 0x0301, 0x0045, 0x032D, 0x0065, 0x032D, + 0x0045, 0x0330, 0x0065, 0x0330, 0x0228, 0x0306, 0x0229, 0x0306, + 0x0046, 0x0307, 0x0066, 0x0307, 0x0047, 0x0304, 0x0067, 0x0304, + 0x0048, 0x0307, 0x0068, 0x0307, 0x0048, 0x0323, 0x0068, 0x0323, + 0x0048, 0x0308, 0x0068, 0x0308, 0x0048, 0x0327, 0x0068, 0x0327, + 0x0048, 0x032E, 0x0068, 0x032E, 0x0049, 0x0330, 0x0069, 0x0330, + 0x00CF, 0x0301, 0x00EF, 0x0301, 0x004B, 0x0301, 0x006B, 0x0301, + 0x004B, 0x0323, 0x006B, 0x0323, 0x004B, 0x0331, 0x006B, 0x0331, + 0x004C, 0x0323, 0x006C, 0x0323, 0x1E36, 0x0304, 0x1E37, 0x0304, + 0x004C, 0x0331, 0x006C, 0x0331, 0x004C, 0x032D, 0x006C, 0x032D, + 0x004D, 0x0301, 0x006D, 0x0301, 0x004D, 0x0307, 0x006D, 0x0307, + 0x004D, 0x0323, 0x006D, 0x0323, 0x004E, 0x0307, 0x006E, 0x0307, + 0x004E, 0x0323, 0x006E, 0x0323, 0x004E, 0x0331, 0x006E, 0x0331, + 0x004E, 0x032D, 0x006E, 0x032D, 0x00D5, 0x0301, 0x00F5, 0x0301, + 0x00D5, 0x0308, 0x00F5, 0x0308, 0x014C, 0x0300, 0x014D, 0x0300, + 0x014C, 0x0301, 0x014D, 0x0301, 0x0050, 0x0301, 0x0070, 0x0301, + 0x0050, 0x0307, 0x0070, 0x0307, 0x0052, 0x0307, 0x0072, 0x0307, + 0x0052, 0x0323, 0x0072, 0x0323, 0x1E5A, 0x0304, 0x1E5B, 0x0304, + 0x0052, 0x0331, 0x0072, 0x0331, 0x0053, 0x0307, 0x0073, 0x0307, + 0x0053, 0x0323, 0x0073, 0x0323, 0x015A, 0x0307, 0x015B, 0x0307, + 0x0160, 0x0307, 0x0161, 0x0307, 0x1E62, 0x0307, 0x1E63, 0x0307, + 0x0054, 0x0307, 0x0074, 0x0307, 0x0054, 0x0323, 0x0074, 0x0323, + 0x0054, 0x0331, 0x0074, 0x0331, 0x0054, 0x032D, 0x0074, 0x032D, + 0x0055, 0x0324, 0x0075, 0x0324, 0x0055, 0x0330, 0x0075, 0x0330, + 0x0055, 0x032D, 0x0075, 0x032D, 0x0168, 0x0301, 0x0169, 0x0301, + 0x016A, 0x0308, 0x016B, 0x0308, 0x0056, 0x0303, 0x0076, 0x0303, + 0x0056, 0x0323, 0x0076, 0x0323, 0x0057, 0x0300, 0x0077, 0x0300, + 0x0057, 0x0301, 0x0077, 0x0301, 0x0057, 0x0308, 0x0077, 0x0308, + 0x0057, 0x0307, 0x0077, 0x0307, 0x0057, 0x0323, 0x0077, 0x0323, + 0x0058, 0x0307, 0x0078, 0x0307, 0x0058, 0x0308, 0x0078, 0x0308, + 0x0059, 0x0307, 0x0079, 0x0307, 0x005A, 0x0302, 0x007A, 0x0302, + 0x005A, 0x0323, 0x007A, 0x0323, 0x005A, 0x0331, 0x007A, 0x0331, + 0x0068, 0x0331, 0x0074, 0x0308, 0x0077, 0x030A, 0x0079, 0x030A, + 0x017F, 0x0307, 0x0041, 0x0323, 0x0061, 0x0323, 0x0041, 0x0309, + 0x0061, 0x0309, 0x00C2, 0x0301, 0x00E2, 0x0301, 0x00C2, 0x0300, + 0x00E2, 0x0300, 0x00C2, 0x0309, 0x00E2, 0x0309, 0x00C2, 0x0303, + 0x00E2, 0x0303, 0x1EA0, 0x0302, 0x1EA1, 0x0302, 0x0102, 0x0301, + 0x0103, 0x0301, 0x0102, 0x0300, 0x0103, 0x0300, 0x0102, 0x0309, + 0x0103, 0x0309, 0x0102, 0x0303, 0x0103, 0x0303, 0x1EA0, 0x0306, + 0x1EA1, 0x0306, 0x0045, 0x0323, 0x0065, 0x0323, 0x0045, 0x0309, + 0x0065, 0x0309, 0x0045, 0x0303, 0x0065, 0x0303, 0x00CA, 0x0301, + 0x00EA, 0x0301, 0x00CA, 0x0300, 0x00EA, 0x0300, 0x00CA, 0x0309, + 0x00EA, 0x0309, 0x00CA, 0x0303, 0x00EA, 0x0303, 0x1EB8, 0x0302, + 0x1EB9, 0x0302, 0x0049, 0x0309, 0x0069, 0x0309, 0x0049, 0x0323, + 0x0069, 0x0323, 0x004F, 0x0323, 0x006F, 0x0323, 0x004F, 0x0309, + 0x006F, 0x0309, 0x00D4, 0x0301, 0x00F4, 0x0301, 0x00D4, 0x0300, + 0x00F4, 0x0300, 0x00D4, 0x0309, 0x00F4, 0x0309, 0x00D4, 0x0303, + 0x00F4, 0x0303, 0x1ECC, 0x0302, 0x1ECD, 0x0302, 0x01A0, 0x0301, + 0x01A1, 0x0301, 0x01A0, 0x0300, 0x01A1, 0x0300, 0x01A0, 0x0309, + 0x01A1, 0x0309, 0x01A0, 0x0303, 0x01A1, 0x0303, 0x01A0, 0x0323, + 0x01A1, 0x0323, 0x0055, 0x0323, 0x0075, 0x0323, 0x0055, 0x0309, + 0x0075, 0x0309, 0x01AF, 0x0301, 0x01B0, 0x0301, 0x01AF, 0x0300, + 0x01B0, 0x0300, 0x01AF, 0x0309, 0x01B0, 0x0309, 0x01AF, 0x0303, + 0x01B0, 0x0303, 0x01AF, 0x0323, 0x01B0, 0x0323, 0x0059, 0x0300, + 0x0079, 0x0300, 0x0059, 0x0323, 0x0079, 0x0323, 0x0059, 0x0309, + 0x0079, 0x0309, 0x0059, 0x0303, 0x0079, 0x0303, 0x03B1, 0x0313, + 0x03B1, 0x0314, 0x1F00, 0x0300, 0x1F01, 0x0300, 0x1F00, 0x0301, + 0x1F01, 0x0301, 0x1F00, 0x0342, 0x1F01, 0x0342, 0x0391, 0x0313, + 0x0391, 0x0314, 0x1F08, 0x0300, 0x1F09, 0x0300, 0x1F08, 0x0301, + 0x1F09, 0x0301, 0x1F08, 0x0342, 0x1F09, 0x0342, 0x03B5, 0x0313, + 0x03B5, 0x0314, 0x1F10, 0x0300, 0x1F11, 0x0300, 0x1F10, 0x0301, + 0x1F11, 0x0301, 0x0395, 0x0313, 0x0395, 0x0314, 0x1F18, 0x0300, + 0x1F19, 0x0300, 0x1F18, 0x0301, 0x1F19, 0x0301, 0x03B7, 0x0313, + 0x03B7, 0x0314, 0x1F20, 0x0300, 0x1F21, 0x0300, 0x1F20, 0x0301, + 0x1F21, 0x0301, 0x1F20, 0x0342, 0x1F21, 0x0342, 0x0397, 0x0313, + 0x0397, 0x0314, 0x1F28, 0x0300, 0x1F29, 0x0300, 0x1F28, 0x0301, + 0x1F29, 0x0301, 0x1F28, 0x0342, 0x1F29, 0x0342, 0x03B9, 0x0313, + 0x03B9, 0x0314, 0x1F30, 0x0300, 0x1F31, 0x0300, 0x1F30, 0x0301, + 0x1F31, 0x0301, 0x1F30, 0x0342, 0x1F31, 0x0342, 0x0399, 0x0313, + 0x0399, 0x0314, 0x1F38, 0x0300, 0x1F39, 0x0300, 0x1F38, 0x0301, + 0x1F39, 0x0301, 0x1F38, 0x0342, 0x1F39, 0x0342, 0x03BF, 0x0313, + 0x03BF, 0x0314, 0x1F40, 0x0300, 0x1F41, 0x0300, 0x1F40, 0x0301, + 0x1F41, 0x0301, 0x039F, 0x0313, 0x039F, 0x0314, 0x1F48, 0x0300, + 0x1F49, 0x0300, 0x1F48, 0x0301, 0x1F49, 0x0301, 0x03C5, 0x0313, + 0x03C5, 0x0314, 0x1F50, 0x0300, 0x1F51, 0x0300, 0x1F50, 0x0301, + 0x1F51, 0x0301, 0x1F50, 0x0342, 0x1F51, 0x0342, 0x03A5, 0x0314, + 0x1F59, 0x0300, 0x1F59, 0x0301, 0x1F59, 0x0342, 0x03C9, 0x0313, + 0x03C9, 0x0314, 0x1F60, 0x0300, 0x1F61, 0x0300, 0x1F60, 0x0301, + 0x1F61, 0x0301, 0x1F60, 0x0342, 0x1F61, 0x0342, 0x03A9, 0x0313, + 0x03A9, 0x0314, 0x1F68, 0x0300, 0x1F69, 0x0300, 0x1F68, 0x0301, + 0x1F69, 0x0301, 0x1F68, 0x0342, 0x1F69, 0x0342, 0x03B1, 0x0300, + 0x03B5, 0x0300, 0x03B7, 0x0300, 0x03B9, 0x0300, 0x03BF, 0x0300, + 0x03C5, 0x0300, 0x03C9, 0x0300, 0x1F00, 0x0345, 0x1F01, 0x0345, + 0x1F02, 0x0345, 0x1F03, 0x0345, 0x1F04, 0x0345, 0x1F05, 0x0345, + 0x1F06, 0x0345, 0x1F07, 0x0345, 0x1F08, 0x0345, 0x1F09, 0x0345, + 0x1F0A, 0x0345, 0x1F0B, 0x0345, 0x1F0C, 0x0345, 0x1F0D, 0x0345, + 0x1F0E, 0x0345, 0x1F0F, 0x0345, 0x1F20, 0x0345, 0x1F21, 0x0345, + 0x1F22, 0x0345, 0x1F23, 0x0345, 0x1F24, 0x0345, 0x1F25, 0x0345, + 0x1F26, 0x0345, 0x1F27, 0x0345, 0x1F28, 0x0345, 0x1F29, 0x0345, + 0x1F2A, 0x0345, 0x1F2B, 0x0345, 0x1F2C, 0x0345, 0x1F2D, 0x0345, + 0x1F2E, 0x0345, 0x1F2F, 0x0345, 0x1F60, 0x0345, 0x1F61, 0x0345, + 0x1F62, 0x0345, 0x1F63, 0x0345, 0x1F64, 0x0345, 0x1F65, 0x0345, + 0x1F66, 0x0345, 0x1F67, 0x0345, 0x1F68, 0x0345, 0x1F69, 0x0345, + 0x1F6A, 0x0345, 0x1F6B, 0x0345, 0x1F6C, 0x0345, 0x1F6D, 0x0345, + 0x1F6E, 0x0345, 0x1F6F, 0x0345, 0x03B1, 0x0306, 0x03B1, 0x0304, + 0x1F70, 0x0345, 0x03B1, 0x0345, 0x03AC, 0x0345, 0x03B1, 0x0342, + 0x1FB6, 0x0345, 0x0391, 0x0306, 0x0391, 0x0304, 0x0391, 0x0300, + 0x0391, 0x0345, 0x00A8, 0x0342, 0x1F74, 0x0345, 0x03B7, 0x0345, + 0x03AE, 0x0345, 0x03B7, 0x0342, 0x1FC6, 0x0345, 0x0395, 0x0300, + 0x0397, 0x0300, 0x0397, 0x0345, 0x1FBF, 0x0300, 0x1FBF, 0x0301, + 0x1FBF, 0x0342, 0x03B9, 0x0306, 0x03B9, 0x0304, 0x03CA, 0x0300, + 0x03B9, 0x0342, 0x03CA, 0x0342, 0x0399, 0x0306, 0x0399, 0x0304, + 0x0399, 0x0300, 0x1FFE, 0x0300, 0x1FFE, 0x0301, 0x1FFE, 0x0342, + 0x03C5, 0x0306, 0x03C5, 0x0304, 0x03CB, 0x0300, 0x03C1, 0x0313, + 0x03C1, 0x0314, 0x03C5, 0x0342, 0x03CB, 0x0342, 0x03A5, 0x0306, + 0x03A5, 0x0304, 0x03A5, 0x0300, 0x03A1, 0x0314, 0x00A8, 0x0300, + 0x1F7C, 0x0345, 0x03C9, 0x0345, 0x03CE, 0x0345, 0x03C9, 0x0342, + 0x1FF6, 0x0345, 0x039F, 0x0300, 0x03A9, 0x0300, 0x03A9, 0x0345, + 0x304B, 0x3099, 0x304D, 0x3099, 0x304F, 0x3099, 0x3051, 0x3099, + 0x3053, 0x3099, 0x3055, 0x3099, 0x3057, 0x3099, 0x3059, 0x3099, + 0x305B, 0x3099, 0x305D, 0x3099, 0x305F, 0x3099, 0x3061, 0x3099, + 0x3064, 0x3099, 0x3066, 0x3099, 0x3068, 0x3099, 0x306F, 0x3099, + 0x306F, 0x309A, 0x3072, 0x3099, 0x3072, 0x309A, 0x3075, 0x3099, + 0x3075, 0x309A, 0x3078, 0x3099, 0x3078, 0x309A, 0x307B, 0x3099, + 0x307B, 0x309A, 0x3046, 0x3099, 0x309D, 0x3099, 0x30AB, 0x3099, + 0x30AD, 0x3099, 0x30AF, 0x3099, 0x30B1, 0x3099, 0x30B3, 0x3099, + 0x30B5, 0x3099, 0x30B7, 0x3099, 0x30B9, 0x3099, 0x30BB, 0x3099, + 0x30BD, 0x3099, 0x30BF, 0x3099, 0x30C1, 0x3099, 0x30C4, 0x3099, + 0x30C6, 0x3099, 0x30C8, 0x3099, 0x30CF, 0x3099, 0x30CF, 0x309A, + 0x30D2, 0x3099, 0x30D2, 0x309A, 0x30D5, 0x3099, 0x30D5, 0x309A, + 0x30D8, 0x3099, 0x30D8, 0x309A, 0x30DB, 0x3099, 0x30DB, 0x309A, + 0x30A6, 0x3099, 0x30EF, 0x3099, 0x30F0, 0x3099, 0x30F1, 0x3099, + 0x30F2, 0x3099, 0x30FD, 0x3099, 0x05D9, 0x05B4, 0x05F2, 0x05B7, + 0x05E9, 0x05C1, 0x05E9, 0x05C2, 0xFB49, 0x05C1, 0xFB49, 0x05C2, + 0x05D0, 0x05B7, 0x05D0, 0x05B8, 0x05D0, 0x05BC, 0x05D1, 0x05BC, + 0x05D2, 0x05BC, 0x05D3, 0x05BC, 0x05D4, 0x05BC, 0x05D5, 0x05BC, + 0x05D6, 0x05BC, 0x05D8, 0x05BC, 0x05D9, 0x05BC, 0x05DA, 0x05BC, + 0x05DB, 0x05BC, 0x05DC, 0x05BC, 0x05DE, 0x05BC, 0x05E0, 0x05BC, + 0x05E1, 0x05BC, 0x05E3, 0x05BC, 0x05E4, 0x05BC, 0x05E6, 0x05BC, + 0x05E7, 0x05BC, 0x05E8, 0x05BC, 0x05E9, 0x05BC, 0x05EA, 0x05BC, + 0x05D5, 0x05B9, 0x05D1, 0x05BF, 0x05DB, 0x05BF, 0x05E4, 0x05BF +}; + +static const u_int8_t +__CFUniCharDecomposableBitmap[] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x06, 0x00, + 0x00, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x00, 0x0C, + 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x0F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x11, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xBF, 0xFF, 0x7E, 0x3E, 0xBF, 0xFF, 0x7E, 0xBE, + 0xFF, 0xFF, 0xFC, 0xFF, 0x3F, 0xFF, 0xF1, 0x7E, + 0xF8, 0xF1, 0xF3, 0xFF, 0x3F, 0xFF, 0xFF, 0x7F, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x01, 0x00, + 0x00, 0xE0, 0xFF, 0xDF, 0xCF, 0xFF, 0x31, 0xFF, + 0xFF, 0xFF, 0xFF, 0xCF, 0xC0, 0xFF, 0x0F, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, + 0xE0, 0xD7, 0x01, 0x00, 0x00, 0xFC, 0x01, 0x00, + 0x00, 0x7C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x8B, 0x70, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x8B, 0x70, 0x00, 0x00, 0xC0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0xCF, 0xFC, 0xFC, 0xFC, 0x3F, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x12, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x00, 0xB0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, + 0x00, 0x00, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x19, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x81, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x20, 0x84, 0x10, 0x00, 0x02, 0x68, 0x01, + 0x02, 0x00, 0x08, 0x20, 0x84, 0x10, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x0B, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, + 0xFF, 0xFF, 0x3F, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, + 0x3F, 0x3F, 0xFF, 0xAA, 0xFF, 0xFF, 0xFF, 0x3F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0x5F, + 0xDE, 0xFF, 0xCF, 0xEF, 0xFF, 0xFF, 0xDC, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x50, 0x55, 0x55, 0xA5, 0x02, 0xDB, 0x36, + 0x00, 0x00, 0x10, 0x40, 0x00, 0x50, 0x55, 0x55, + 0xA5, 0x02, 0xDB, 0x36, 0x00, 0x00, 0x90, 0x47, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xA0, 0x00, 0xFC, 0x7F, 0x5F, + 0xDB, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const u_int32_t +__CFUniCharPrecompSourceTable[] = { + 0x00000300, 0x00540000, 0x00000301, 0x00750054, + 0x00000302, 0x002000C9, 0x00000303, 0x001C00E9, + 0x00000304, 0x002C0105, 0x00000306, 0x00200131, + 0x00000307, 0x002E0151, 0x00000308, 0x0036017F, + 0x00000309, 0x001801B5, 0x0000030A, 0x000601CD, + 0x0000030B, 0x000601D3, 0x0000030C, 0x002501D9, + 0x0000030F, 0x000E01FE, 0x00000311, 0x000C020C, + 0x00000313, 0x000E0218, 0x00000314, 0x00100226, + 0x0000031B, 0x00040236, 0x00000323, 0x002A023A, + 0x00000324, 0x00020264, 0x00000325, 0x00020266, + 0x00000326, 0x00040268, 0x00000327, 0x0016026C, + 0x00000328, 0x000A0282, 0x0000032D, 0x000C028C, + 0x0000032E, 0x00020298, 0x00000330, 0x0006029A, + 0x00000331, 0x001102A0, 0x00000338, 0x002C02B1, + 0x00000342, 0x001D02DD, 0x00000345, 0x003F02FA, + 0x00000653, 0x00010339, 0x00000654, 0x0006033A, + 0x00000655, 0x00010340, 0x0000093C, 0x00030341, + 0x000009BE, 0x00010344, 0x000009D7, 0x00010345, + 0x00000B3E, 0x00010346, 0x00000B56, 0x00010347, + 0x00000B57, 0x00010348, 0x00000BBE, 0x00020349, + 0x00000BD7, 0x0002034B, 0x00000C56, 0x0001034D, + 0x00000CC2, 0x0001034E, 0x00000CD5, 0x0003034F, + 0x00000CD6, 0x00010352, 0x00000D3E, 0x00020353, + 0x00000D57, 0x00010355, 0x00000DCA, 0x00020356, + 0x00000DCF, 0x00010358, 0x00000DDF, 0x00010359, + 0x0000102E, 0x0001035A, 0x00003099, 0x0030035B, + 0x0000309A, 0x000A038B +}; + +static const u_int32_t __CFUniCharPrecompositionTableLength = + (sizeof(__CFUniCharPrecompSourceTable) / (sizeof(u_int32_t) * 2)); + + +static const u_int16_t +__CFUniCharBMPPrecompDestinationTable[] = { + 0x0041, 0x00C0, 0x0045, 0x00C8, 0x0049, 0x00CC, 0x004E, 0x01F8, + 0x004F, 0x00D2, 0x0055, 0x00D9, 0x0057, 0x1E80, 0x0059, 0x1EF2, + 0x0061, 0x00E0, 0x0065, 0x00E8, 0x0069, 0x00EC, 0x006E, 0x01F9, + 0x006F, 0x00F2, 0x0075, 0x00F9, 0x0077, 0x1E81, 0x0079, 0x1EF3, + 0x00A8, 0x1FED, 0x00C2, 0x1EA6, 0x00CA, 0x1EC0, 0x00D4, 0x1ED2, + 0x00DC, 0x01DB, 0x00E2, 0x1EA7, 0x00EA, 0x1EC1, 0x00F4, 0x1ED3, + 0x00FC, 0x01DC, 0x0102, 0x1EB0, 0x0103, 0x1EB1, 0x0112, 0x1E14, + 0x0113, 0x1E15, 0x014C, 0x1E50, 0x014D, 0x1E51, 0x01A0, 0x1EDC, + 0x01A1, 0x1EDD, 0x01AF, 0x1EEA, 0x01B0, 0x1EEB, 0x0391, 0x1FBA, + 0x0395, 0x1FC8, 0x0397, 0x1FCA, 0x0399, 0x1FDA, 0x039F, 0x1FF8, + 0x03A5, 0x1FEA, 0x03A9, 0x1FFA, 0x03B1, 0x1F70, 0x03B5, 0x1F72, + 0x03B7, 0x1F74, 0x03B9, 0x1F76, 0x03BF, 0x1F78, 0x03C5, 0x1F7A, + 0x03C9, 0x1F7C, 0x03CA, 0x1FD2, 0x03CB, 0x1FE2, 0x0415, 0x0400, + 0x0418, 0x040D, 0x0435, 0x0450, 0x0438, 0x045D, 0x1F00, 0x1F02, + 0x1F01, 0x1F03, 0x1F08, 0x1F0A, 0x1F09, 0x1F0B, 0x1F10, 0x1F12, + 0x1F11, 0x1F13, 0x1F18, 0x1F1A, 0x1F19, 0x1F1B, 0x1F20, 0x1F22, + 0x1F21, 0x1F23, 0x1F28, 0x1F2A, 0x1F29, 0x1F2B, 0x1F30, 0x1F32, + 0x1F31, 0x1F33, 0x1F38, 0x1F3A, 0x1F39, 0x1F3B, 0x1F40, 0x1F42, + 0x1F41, 0x1F43, 0x1F48, 0x1F4A, 0x1F49, 0x1F4B, 0x1F50, 0x1F52, + 0x1F51, 0x1F53, 0x1F59, 0x1F5B, 0x1F60, 0x1F62, 0x1F61, 0x1F63, + 0x1F68, 0x1F6A, 0x1F69, 0x1F6B, 0x1FBF, 0x1FCD, 0x1FFE, 0x1FDD, + 0x0041, 0x00C1, 0x0043, 0x0106, 0x0045, 0x00C9, 0x0047, 0x01F4, + 0x0049, 0x00CD, 0x004B, 0x1E30, 0x004C, 0x0139, 0x004D, 0x1E3E, + 0x004E, 0x0143, 0x004F, 0x00D3, 0x0050, 0x1E54, 0x0052, 0x0154, + 0x0053, 0x015A, 0x0055, 0x00DA, 0x0057, 0x1E82, 0x0059, 0x00DD, + 0x005A, 0x0179, 0x0061, 0x00E1, 0x0063, 0x0107, 0x0065, 0x00E9, + 0x0067, 0x01F5, 0x0069, 0x00ED, 0x006B, 0x1E31, 0x006C, 0x013A, + 0x006D, 0x1E3F, 0x006E, 0x0144, 0x006F, 0x00F3, 0x0070, 0x1E55, + 0x0072, 0x0155, 0x0073, 0x015B, 0x0075, 0x00FA, 0x0077, 0x1E83, + 0x0079, 0x00FD, 0x007A, 0x017A, 0x00A8, 0x0385, 0x00C2, 0x1EA4, + 0x00C5, 0x01FA, 0x00C6, 0x01FC, 0x00C7, 0x1E08, 0x00CA, 0x1EBE, + 0x00CF, 0x1E2E, 0x00D4, 0x1ED0, 0x00D5, 0x1E4C, 0x00D8, 0x01FE, + 0x00DC, 0x01D7, 0x00E2, 0x1EA5, 0x00E5, 0x01FB, 0x00E6, 0x01FD, + 0x00E7, 0x1E09, 0x00EA, 0x1EBF, 0x00EF, 0x1E2F, 0x00F4, 0x1ED1, + 0x00F5, 0x1E4D, 0x00F8, 0x01FF, 0x00FC, 0x01D8, 0x0102, 0x1EAE, + 0x0103, 0x1EAF, 0x0112, 0x1E16, 0x0113, 0x1E17, 0x014C, 0x1E52, + 0x014D, 0x1E53, 0x0168, 0x1E78, 0x0169, 0x1E79, 0x01A0, 0x1EDA, + 0x01A1, 0x1EDB, 0x01AF, 0x1EE8, 0x01B0, 0x1EE9, 0x0391, 0x0386, + 0x0395, 0x0388, 0x0397, 0x0389, 0x0399, 0x038A, 0x039F, 0x038C, + 0x03A5, 0x038E, 0x03A9, 0x038F, 0x03B1, 0x03AC, 0x03B5, 0x03AD, + 0x03B7, 0x03AE, 0x03B9, 0x03AF, 0x03BF, 0x03CC, 0x03C5, 0x03CD, + 0x03C9, 0x03CE, 0x03CA, 0x0390, 0x03CB, 0x03B0, 0x03D2, 0x03D3, + 0x0413, 0x0403, 0x041A, 0x040C, 0x0433, 0x0453, 0x043A, 0x045C, + 0x1F00, 0x1F04, 0x1F01, 0x1F05, 0x1F08, 0x1F0C, 0x1F09, 0x1F0D, + 0x1F10, 0x1F14, 0x1F11, 0x1F15, 0x1F18, 0x1F1C, 0x1F19, 0x1F1D, + 0x1F20, 0x1F24, 0x1F21, 0x1F25, 0x1F28, 0x1F2C, 0x1F29, 0x1F2D, + 0x1F30, 0x1F34, 0x1F31, 0x1F35, 0x1F38, 0x1F3C, 0x1F39, 0x1F3D, + 0x1F40, 0x1F44, 0x1F41, 0x1F45, 0x1F48, 0x1F4C, 0x1F49, 0x1F4D, + 0x1F50, 0x1F54, 0x1F51, 0x1F55, 0x1F59, 0x1F5D, 0x1F60, 0x1F64, + 0x1F61, 0x1F65, 0x1F68, 0x1F6C, 0x1F69, 0x1F6D, 0x1FBF, 0x1FCE, + 0x1FFE, 0x1FDE, 0x0041, 0x00C2, 0x0043, 0x0108, 0x0045, 0x00CA, + 0x0047, 0x011C, 0x0048, 0x0124, 0x0049, 0x00CE, 0x004A, 0x0134, + 0x004F, 0x00D4, 0x0053, 0x015C, 0x0055, 0x00DB, 0x0057, 0x0174, + 0x0059, 0x0176, 0x005A, 0x1E90, 0x0061, 0x00E2, 0x0063, 0x0109, + 0x0065, 0x00EA, 0x0067, 0x011D, 0x0068, 0x0125, 0x0069, 0x00EE, + 0x006A, 0x0135, 0x006F, 0x00F4, 0x0073, 0x015D, 0x0075, 0x00FB, + 0x0077, 0x0175, 0x0079, 0x0177, 0x007A, 0x1E91, 0x1EA0, 0x1EAC, + 0x1EA1, 0x1EAD, 0x1EB8, 0x1EC6, 0x1EB9, 0x1EC7, 0x1ECC, 0x1ED8, + 0x1ECD, 0x1ED9, 0x0041, 0x00C3, 0x0045, 0x1EBC, 0x0049, 0x0128, + 0x004E, 0x00D1, 0x004F, 0x00D5, 0x0055, 0x0168, 0x0056, 0x1E7C, + 0x0059, 0x1EF8, 0x0061, 0x00E3, 0x0065, 0x1EBD, 0x0069, 0x0129, + 0x006E, 0x00F1, 0x006F, 0x00F5, 0x0075, 0x0169, 0x0076, 0x1E7D, + 0x0079, 0x1EF9, 0x00C2, 0x1EAA, 0x00CA, 0x1EC4, 0x00D4, 0x1ED6, + 0x00E2, 0x1EAB, 0x00EA, 0x1EC5, 0x00F4, 0x1ED7, 0x0102, 0x1EB4, + 0x0103, 0x1EB5, 0x01A0, 0x1EE0, 0x01A1, 0x1EE1, 0x01AF, 0x1EEE, + 0x01B0, 0x1EEF, 0x0041, 0x0100, 0x0045, 0x0112, 0x0047, 0x1E20, + 0x0049, 0x012A, 0x004F, 0x014C, 0x0055, 0x016A, 0x0059, 0x0232, + 0x0061, 0x0101, 0x0065, 0x0113, 0x0067, 0x1E21, 0x0069, 0x012B, + 0x006F, 0x014D, 0x0075, 0x016B, 0x0079, 0x0233, 0x00C4, 0x01DE, + 0x00C6, 0x01E2, 0x00D5, 0x022C, 0x00D6, 0x022A, 0x00DC, 0x01D5, + 0x00E4, 0x01DF, 0x00E6, 0x01E3, 0x00F5, 0x022D, 0x00F6, 0x022B, + 0x00FC, 0x01D6, 0x01EA, 0x01EC, 0x01EB, 0x01ED, 0x0226, 0x01E0, + 0x0227, 0x01E1, 0x022E, 0x0230, 0x022F, 0x0231, 0x0391, 0x1FB9, + 0x0399, 0x1FD9, 0x03A5, 0x1FE9, 0x03B1, 0x1FB1, 0x03B9, 0x1FD1, + 0x03C5, 0x1FE1, 0x0418, 0x04E2, 0x0423, 0x04EE, 0x0438, 0x04E3, + 0x0443, 0x04EF, 0x1E36, 0x1E38, 0x1E37, 0x1E39, 0x1E5A, 0x1E5C, + 0x1E5B, 0x1E5D, 0x0041, 0x0102, 0x0045, 0x0114, 0x0047, 0x011E, + 0x0049, 0x012C, 0x004F, 0x014E, 0x0055, 0x016C, 0x0061, 0x0103, + 0x0065, 0x0115, 0x0067, 0x011F, 0x0069, 0x012D, 0x006F, 0x014F, + 0x0075, 0x016D, 0x0228, 0x1E1C, 0x0229, 0x1E1D, 0x0391, 0x1FB8, + 0x0399, 0x1FD8, 0x03A5, 0x1FE8, 0x03B1, 0x1FB0, 0x03B9, 0x1FD0, + 0x03C5, 0x1FE0, 0x0410, 0x04D0, 0x0415, 0x04D6, 0x0416, 0x04C1, + 0x0418, 0x0419, 0x0423, 0x040E, 0x0430, 0x04D1, 0x0435, 0x04D7, + 0x0436, 0x04C2, 0x0438, 0x0439, 0x0443, 0x045E, 0x1EA0, 0x1EB6, + 0x1EA1, 0x1EB7, 0x0041, 0x0226, 0x0042, 0x1E02, 0x0043, 0x010A, + 0x0044, 0x1E0A, 0x0045, 0x0116, 0x0046, 0x1E1E, 0x0047, 0x0120, + 0x0048, 0x1E22, 0x0049, 0x0130, 0x004D, 0x1E40, 0x004E, 0x1E44, + 0x004F, 0x022E, 0x0050, 0x1E56, 0x0052, 0x1E58, 0x0053, 0x1E60, + 0x0054, 0x1E6A, 0x0057, 0x1E86, 0x0058, 0x1E8A, 0x0059, 0x1E8E, + 0x005A, 0x017B, 0x0061, 0x0227, 0x0062, 0x1E03, 0x0063, 0x010B, + 0x0064, 0x1E0B, 0x0065, 0x0117, 0x0066, 0x1E1F, 0x0067, 0x0121, + 0x0068, 0x1E23, 0x006D, 0x1E41, 0x006E, 0x1E45, 0x006F, 0x022F, + 0x0070, 0x1E57, 0x0072, 0x1E59, 0x0073, 0x1E61, 0x0074, 0x1E6B, + 0x0077, 0x1E87, 0x0078, 0x1E8B, 0x0079, 0x1E8F, 0x007A, 0x017C, + 0x015A, 0x1E64, 0x015B, 0x1E65, 0x0160, 0x1E66, 0x0161, 0x1E67, + 0x017F, 0x1E9B, 0x1E62, 0x1E68, 0x1E63, 0x1E69, 0x0041, 0x00C4, + 0x0045, 0x00CB, 0x0048, 0x1E26, 0x0049, 0x00CF, 0x004F, 0x00D6, + 0x0055, 0x00DC, 0x0057, 0x1E84, 0x0058, 0x1E8C, 0x0059, 0x0178, + 0x0061, 0x00E4, 0x0065, 0x00EB, 0x0068, 0x1E27, 0x0069, 0x00EF, + 0x006F, 0x00F6, 0x0074, 0x1E97, 0x0075, 0x00FC, 0x0077, 0x1E85, + 0x0078, 0x1E8D, 0x0079, 0x00FF, 0x00D5, 0x1E4E, 0x00F5, 0x1E4F, + 0x016A, 0x1E7A, 0x016B, 0x1E7B, 0x0399, 0x03AA, 0x03A5, 0x03AB, + 0x03B9, 0x03CA, 0x03C5, 0x03CB, 0x03D2, 0x03D4, 0x0406, 0x0407, + 0x0410, 0x04D2, 0x0415, 0x0401, 0x0416, 0x04DC, 0x0417, 0x04DE, + 0x0418, 0x04E4, 0x041E, 0x04E6, 0x0423, 0x04F0, 0x0427, 0x04F4, + 0x042B, 0x04F8, 0x042D, 0x04EC, 0x0430, 0x04D3, 0x0435, 0x0451, + 0x0436, 0x04DD, 0x0437, 0x04DF, 0x0438, 0x04E5, 0x043E, 0x04E7, + 0x0443, 0x04F1, 0x0447, 0x04F5, 0x044B, 0x04F9, 0x044D, 0x04ED, + 0x0456, 0x0457, 0x04D8, 0x04DA, 0x04D9, 0x04DB, 0x04E8, 0x04EA, + 0x04E9, 0x04EB, 0x0041, 0x1EA2, 0x0045, 0x1EBA, 0x0049, 0x1EC8, + 0x004F, 0x1ECE, 0x0055, 0x1EE6, 0x0059, 0x1EF6, 0x0061, 0x1EA3, + 0x0065, 0x1EBB, 0x0069, 0x1EC9, 0x006F, 0x1ECF, 0x0075, 0x1EE7, + 0x0079, 0x1EF7, 0x00C2, 0x1EA8, 0x00CA, 0x1EC2, 0x00D4, 0x1ED4, + 0x00E2, 0x1EA9, 0x00EA, 0x1EC3, 0x00F4, 0x1ED5, 0x0102, 0x1EB2, + 0x0103, 0x1EB3, 0x01A0, 0x1EDE, 0x01A1, 0x1EDF, 0x01AF, 0x1EEC, + 0x01B0, 0x1EED, 0x0041, 0x00C5, 0x0055, 0x016E, 0x0061, 0x00E5, + 0x0075, 0x016F, 0x0077, 0x1E98, 0x0079, 0x1E99, 0x004F, 0x0150, + 0x0055, 0x0170, 0x006F, 0x0151, 0x0075, 0x0171, 0x0423, 0x04F2, + 0x0443, 0x04F3, 0x0041, 0x01CD, 0x0043, 0x010C, 0x0044, 0x010E, + 0x0045, 0x011A, 0x0047, 0x01E6, 0x0048, 0x021E, 0x0049, 0x01CF, + 0x004B, 0x01E8, 0x004C, 0x013D, 0x004E, 0x0147, 0x004F, 0x01D1, + 0x0052, 0x0158, 0x0053, 0x0160, 0x0054, 0x0164, 0x0055, 0x01D3, + 0x005A, 0x017D, 0x0061, 0x01CE, 0x0063, 0x010D, 0x0064, 0x010F, + 0x0065, 0x011B, 0x0067, 0x01E7, 0x0068, 0x021F, 0x0069, 0x01D0, + 0x006A, 0x01F0, 0x006B, 0x01E9, 0x006C, 0x013E, 0x006E, 0x0148, + 0x006F, 0x01D2, 0x0072, 0x0159, 0x0073, 0x0161, 0x0074, 0x0165, + 0x0075, 0x01D4, 0x007A, 0x017E, 0x00DC, 0x01D9, 0x00FC, 0x01DA, + 0x01B7, 0x01EE, 0x0292, 0x01EF, 0x0041, 0x0200, 0x0045, 0x0204, + 0x0049, 0x0208, 0x004F, 0x020C, 0x0052, 0x0210, 0x0055, 0x0214, + 0x0061, 0x0201, 0x0065, 0x0205, 0x0069, 0x0209, 0x006F, 0x020D, + 0x0072, 0x0211, 0x0075, 0x0215, 0x0474, 0x0476, 0x0475, 0x0477, + 0x0041, 0x0202, 0x0045, 0x0206, 0x0049, 0x020A, 0x004F, 0x020E, + 0x0052, 0x0212, 0x0055, 0x0216, 0x0061, 0x0203, 0x0065, 0x0207, + 0x0069, 0x020B, 0x006F, 0x020F, 0x0072, 0x0213, 0x0075, 0x0217, + 0x0391, 0x1F08, 0x0395, 0x1F18, 0x0397, 0x1F28, 0x0399, 0x1F38, + 0x039F, 0x1F48, 0x03A9, 0x1F68, 0x03B1, 0x1F00, 0x03B5, 0x1F10, + 0x03B7, 0x1F20, 0x03B9, 0x1F30, 0x03BF, 0x1F40, 0x03C1, 0x1FE4, + 0x03C5, 0x1F50, 0x03C9, 0x1F60, 0x0391, 0x1F09, 0x0395, 0x1F19, + 0x0397, 0x1F29, 0x0399, 0x1F39, 0x039F, 0x1F49, 0x03A1, 0x1FEC, + 0x03A5, 0x1F59, 0x03A9, 0x1F69, 0x03B1, 0x1F01, 0x03B5, 0x1F11, + 0x03B7, 0x1F21, 0x03B9, 0x1F31, 0x03BF, 0x1F41, 0x03C1, 0x1FE5, + 0x03C5, 0x1F51, 0x03C9, 0x1F61, 0x004F, 0x01A0, 0x0055, 0x01AF, + 0x006F, 0x01A1, 0x0075, 0x01B0, 0x0041, 0x1EA0, 0x0042, 0x1E04, + 0x0044, 0x1E0C, 0x0045, 0x1EB8, 0x0048, 0x1E24, 0x0049, 0x1ECA, + 0x004B, 0x1E32, 0x004C, 0x1E36, 0x004D, 0x1E42, 0x004E, 0x1E46, + 0x004F, 0x1ECC, 0x0052, 0x1E5A, 0x0053, 0x1E62, 0x0054, 0x1E6C, + 0x0055, 0x1EE4, 0x0056, 0x1E7E, 0x0057, 0x1E88, 0x0059, 0x1EF4, + 0x005A, 0x1E92, 0x0061, 0x1EA1, 0x0062, 0x1E05, 0x0064, 0x1E0D, + 0x0065, 0x1EB9, 0x0068, 0x1E25, 0x0069, 0x1ECB, 0x006B, 0x1E33, + 0x006C, 0x1E37, 0x006D, 0x1E43, 0x006E, 0x1E47, 0x006F, 0x1ECD, + 0x0072, 0x1E5B, 0x0073, 0x1E63, 0x0074, 0x1E6D, 0x0075, 0x1EE5, + 0x0076, 0x1E7F, 0x0077, 0x1E89, 0x0079, 0x1EF5, 0x007A, 0x1E93, + 0x01A0, 0x1EE2, 0x01A1, 0x1EE3, 0x01AF, 0x1EF0, 0x01B0, 0x1EF1, + 0x0055, 0x1E72, 0x0075, 0x1E73, 0x0041, 0x1E00, 0x0061, 0x1E01, + 0x0053, 0x0218, 0x0054, 0x021A, 0x0073, 0x0219, 0x0074, 0x021B, + 0x0043, 0x00C7, 0x0044, 0x1E10, 0x0045, 0x0228, 0x0047, 0x0122, + 0x0048, 0x1E28, 0x004B, 0x0136, 0x004C, 0x013B, 0x004E, 0x0145, + 0x0052, 0x0156, 0x0053, 0x015E, 0x0054, 0x0162, 0x0063, 0x00E7, + 0x0064, 0x1E11, 0x0065, 0x0229, 0x0067, 0x0123, 0x0068, 0x1E29, + 0x006B, 0x0137, 0x006C, 0x013C, 0x006E, 0x0146, 0x0072, 0x0157, + 0x0073, 0x015F, 0x0074, 0x0163, 0x0041, 0x0104, 0x0045, 0x0118, + 0x0049, 0x012E, 0x004F, 0x01EA, 0x0055, 0x0172, 0x0061, 0x0105, + 0x0065, 0x0119, 0x0069, 0x012F, 0x006F, 0x01EB, 0x0075, 0x0173, + 0x0044, 0x1E12, 0x0045, 0x1E18, 0x004C, 0x1E3C, 0x004E, 0x1E4A, + 0x0054, 0x1E70, 0x0055, 0x1E76, 0x0064, 0x1E13, 0x0065, 0x1E19, + 0x006C, 0x1E3D, 0x006E, 0x1E4B, 0x0074, 0x1E71, 0x0075, 0x1E77, + 0x0048, 0x1E2A, 0x0068, 0x1E2B, 0x0045, 0x1E1A, 0x0049, 0x1E2C, + 0x0055, 0x1E74, 0x0065, 0x1E1B, 0x0069, 0x1E2D, 0x0075, 0x1E75, + 0x0042, 0x1E06, 0x0044, 0x1E0E, 0x004B, 0x1E34, 0x004C, 0x1E3A, + 0x004E, 0x1E48, 0x0052, 0x1E5E, 0x0054, 0x1E6E, 0x005A, 0x1E94, + 0x0062, 0x1E07, 0x0064, 0x1E0F, 0x0068, 0x1E96, 0x006B, 0x1E35, + 0x006C, 0x1E3B, 0x006E, 0x1E49, 0x0072, 0x1E5F, 0x0074, 0x1E6F, + 0x007A, 0x1E95, 0x003C, 0x226E, 0x003D, 0x2260, 0x003E, 0x226F, + 0x2190, 0x219A, 0x2192, 0x219B, 0x2194, 0x21AE, 0x21D0, 0x21CD, + 0x21D2, 0x21CF, 0x21D4, 0x21CE, 0x2203, 0x2204, 0x2208, 0x2209, + 0x220B, 0x220C, 0x2223, 0x2224, 0x2225, 0x2226, 0x223C, 0x2241, + 0x2243, 0x2244, 0x2245, 0x2247, 0x2248, 0x2249, 0x224D, 0x226D, + 0x2261, 0x2262, 0x2264, 0x2270, 0x2265, 0x2271, 0x2272, 0x2274, + 0x2273, 0x2275, 0x2276, 0x2278, 0x2277, 0x2279, 0x227A, 0x2280, + 0x227B, 0x2281, 0x227C, 0x22E0, 0x227D, 0x22E1, 0x2282, 0x2284, + 0x2283, 0x2285, 0x2286, 0x2288, 0x2287, 0x2289, 0x2291, 0x22E2, + 0x2292, 0x22E3, 0x22A2, 0x22AC, 0x22A8, 0x22AD, 0x22A9, 0x22AE, + 0x22AB, 0x22AF, 0x22B2, 0x22EA, 0x22B3, 0x22EB, 0x22B4, 0x22EC, + 0x22B5, 0x22ED, 0x00A8, 0x1FC1, 0x03B1, 0x1FB6, 0x03B7, 0x1FC6, + 0x03B9, 0x1FD6, 0x03C5, 0x1FE6, 0x03C9, 0x1FF6, 0x03CA, 0x1FD7, + 0x03CB, 0x1FE7, 0x1F00, 0x1F06, 0x1F01, 0x1F07, 0x1F08, 0x1F0E, + 0x1F09, 0x1F0F, 0x1F20, 0x1F26, 0x1F21, 0x1F27, 0x1F28, 0x1F2E, + 0x1F29, 0x1F2F, 0x1F30, 0x1F36, 0x1F31, 0x1F37, 0x1F38, 0x1F3E, + 0x1F39, 0x1F3F, 0x1F50, 0x1F56, 0x1F51, 0x1F57, 0x1F59, 0x1F5F, + 0x1F60, 0x1F66, 0x1F61, 0x1F67, 0x1F68, 0x1F6E, 0x1F69, 0x1F6F, + 0x1FBF, 0x1FCF, 0x1FFE, 0x1FDF, 0x0391, 0x1FBC, 0x0397, 0x1FCC, + 0x03A9, 0x1FFC, 0x03AC, 0x1FB4, 0x03AE, 0x1FC4, 0x03B1, 0x1FB3, + 0x03B7, 0x1FC3, 0x03C9, 0x1FF3, 0x03CE, 0x1FF4, 0x1F00, 0x1F80, + 0x1F01, 0x1F81, 0x1F02, 0x1F82, 0x1F03, 0x1F83, 0x1F04, 0x1F84, + 0x1F05, 0x1F85, 0x1F06, 0x1F86, 0x1F07, 0x1F87, 0x1F08, 0x1F88, + 0x1F09, 0x1F89, 0x1F0A, 0x1F8A, 0x1F0B, 0x1F8B, 0x1F0C, 0x1F8C, + 0x1F0D, 0x1F8D, 0x1F0E, 0x1F8E, 0x1F0F, 0x1F8F, 0x1F20, 0x1F90, + 0x1F21, 0x1F91, 0x1F22, 0x1F92, 0x1F23, 0x1F93, 0x1F24, 0x1F94, + 0x1F25, 0x1F95, 0x1F26, 0x1F96, 0x1F27, 0x1F97, 0x1F28, 0x1F98, + 0x1F29, 0x1F99, 0x1F2A, 0x1F9A, 0x1F2B, 0x1F9B, 0x1F2C, 0x1F9C, + 0x1F2D, 0x1F9D, 0x1F2E, 0x1F9E, 0x1F2F, 0x1F9F, 0x1F60, 0x1FA0, + 0x1F61, 0x1FA1, 0x1F62, 0x1FA2, 0x1F63, 0x1FA3, 0x1F64, 0x1FA4, + 0x1F65, 0x1FA5, 0x1F66, 0x1FA6, 0x1F67, 0x1FA7, 0x1F68, 0x1FA8, + 0x1F69, 0x1FA9, 0x1F6A, 0x1FAA, 0x1F6B, 0x1FAB, 0x1F6C, 0x1FAC, + 0x1F6D, 0x1FAD, 0x1F6E, 0x1FAE, 0x1F6F, 0x1FAF, 0x1F70, 0x1FB2, + 0x1F74, 0x1FC2, 0x1F7C, 0x1FF2, 0x1FB6, 0x1FB7, 0x1FC6, 0x1FC7, + 0x1FF6, 0x1FF7, 0x0627, 0x0622, 0x0627, 0x0623, 0x0648, 0x0624, + 0x064A, 0x0626, 0x06C1, 0x06C2, 0x06D2, 0x06D3, 0x06D5, 0x06C0, + 0x0627, 0x0625, 0x0928, 0x0929, 0x0930, 0x0931, 0x0933, 0x0934, + 0x09C7, 0x09CB, 0x09C7, 0x09CC, 0x0B47, 0x0B4B, 0x0B47, 0x0B48, + 0x0B47, 0x0B4C, 0x0BC6, 0x0BCA, 0x0BC7, 0x0BCB, 0x0B92, 0x0B94, + 0x0BC6, 0x0BCC, 0x0C46, 0x0C48, 0x0CC6, 0x0CCA, 0x0CBF, 0x0CC0, + 0x0CC6, 0x0CC7, 0x0CCA, 0x0CCB, 0x0CC6, 0x0CC8, 0x0D46, 0x0D4A, + 0x0D47, 0x0D4B, 0x0D46, 0x0D4C, 0x0DD9, 0x0DDA, 0x0DDC, 0x0DDD, + 0x0DD9, 0x0DDC, 0x0DD9, 0x0DDE, 0x1025, 0x1026, 0x3046, 0x3094, + 0x304B, 0x304C, 0x304D, 0x304E, 0x304F, 0x3050, 0x3051, 0x3052, + 0x3053, 0x3054, 0x3055, 0x3056, 0x3057, 0x3058, 0x3059, 0x305A, + 0x305B, 0x305C, 0x305D, 0x305E, 0x305F, 0x3060, 0x3061, 0x3062, + 0x3064, 0x3065, 0x3066, 0x3067, 0x3068, 0x3069, 0x306F, 0x3070, + 0x3072, 0x3073, 0x3075, 0x3076, 0x3078, 0x3079, 0x307B, 0x307C, + 0x309D, 0x309E, 0x30A6, 0x30F4, 0x30AB, 0x30AC, 0x30AD, 0x30AE, + 0x30AF, 0x30B0, 0x30B1, 0x30B2, 0x30B3, 0x30B4, 0x30B5, 0x30B6, + 0x30B7, 0x30B8, 0x30B9, 0x30BA, 0x30BB, 0x30BC, 0x30BD, 0x30BE, + 0x30BF, 0x30C0, 0x30C1, 0x30C2, 0x30C4, 0x30C5, 0x30C6, 0x30C7, + 0x30C8, 0x30C9, 0x30CF, 0x30D0, 0x30D2, 0x30D3, 0x30D5, 0x30D6, + 0x30D8, 0x30D9, 0x30DB, 0x30DC, 0x30EF, 0x30F7, 0x30F0, 0x30F8, + 0x30F1, 0x30F9, 0x30F2, 0x30FA, 0x30FD, 0x30FE, 0x306F, 0x3071, + 0x3072, 0x3074, 0x3075, 0x3077, 0x3078, 0x307A, 0x307B, 0x307D, + 0x30CF, 0x30D1, 0x30D2, 0x30D4, 0x30D5, 0x30D7, 0x30D8, 0x30DA, + 0x30DB, 0x30DD +}; + +static const u_int8_t +__CFUniCharCombiningBitmap[] = { + 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x00, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + 0x0D, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, + 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x13, 0x00, + + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x78, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFE, 0xFF, 0xFB, 0xFF, 0xFF, 0xBB, + 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xF8, 0x3F, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC0, 0xFF, 0x9F, 0x3D, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xFF, 0xFF, + 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, + 0xFF, 0x3F, 0x1E, 0x00, 0x0C, 0x00, 0x00, 0x00, + 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, + 0x9F, 0x39, 0x80, 0x00, 0x0C, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, + 0x87, 0x39, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, + 0xBF, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, + 0x8F, 0x39, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, + 0xC7, 0x3D, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, + 0xDF, 0x3D, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, + 0xDF, 0x3D, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, + 0xCF, 0x3D, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x84, 0x5F, 0xFF, 0x00, 0x00, 0x0C, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF2, 0x07, + 0x80, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF2, 0x1B, + 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0xA0, 0xC2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, + 0xDF, 0x00, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x1F, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xC7, 0x03, + 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x1C, 0x00, + 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, + 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x3F, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; diff --git a/bsd/vfs/vfs_vnops.c b/bsd/vfs/vfs_vnops.c index b351d715b..e186fb484 100644 --- a/bsd/vfs/vfs_vnops.c +++ b/bsd/vfs/vfs_vnops.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -74,6 +74,22 @@ #include #include #include +#include +#include + +#include + +#include + +static int vn_closefile __P((struct file *fp, struct proc *p)); +static int vn_ioctl __P((struct file *fp, u_long com, caddr_t data, + struct proc *p)); +static int vn_read __P((struct file *fp, struct uio *uio, + struct ucred *cred, int flags, struct proc *p)); +static int vn_write __P((struct file *fp, struct uio *uio, + struct ucred *cred, int flags, struct proc *p)); +static int vn_select __P(( struct file *fp, int which, void * wql, + struct proc *p)); struct fileops vnops = { vn_read, vn_write, vn_ioctl, vn_select, vn_closefile }; @@ -82,6 +98,7 @@ struct fileops vnops = * Common code for vnode open operations. * Check permissions, and call the VOP_OPEN or VOP_CREATE routine. */ +int vn_open(ndp, fmode, cmode) register struct nameidata *ndp; int fmode, cmode; @@ -92,12 +109,14 @@ vn_open(ndp, fmode, cmode) struct vattr vat; struct vattr *vap = &vat; int error; + int didhold = 0; if (fmode & O_CREAT) { ndp->ni_cnd.cn_nameiop = CREATE; ndp->ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; if ((fmode & O_EXCL) == 0) ndp->ni_cnd.cn_flags |= FOLLOW; + bwillwrite(); if (error = namei(ndp)) return (error); if (ndp->ni_vp == NULL) { @@ -137,6 +156,17 @@ vn_open(ndp, fmode, cmode) error = EOPNOTSUPP; goto bad; } + +#if DIAGNOSTIC + if (UBCINFOMISSING(vp)) + panic("vn_open: ubc_info_init"); +#endif /* DIAGNOSTIC */ + + if (UBCINFOEXISTS(vp) && ((didhold = ubc_hold(vp)) == 0)) { + error = ENOENT; + goto bad; + } + if ((fmode & O_CREAT) == 0) { if (fmode & FREAD && fmode & (FWRITE | O_TRUNC)) { int err = 0; @@ -172,18 +202,7 @@ vn_open(ndp, fmode, cmode) goto bad; } -#if DIAGNOSTIC - if (UBCINFOMISSING(vp)) - panic("vn_open: ubc_info_init"); -#endif /* DIAGNOSTIC */ - - if (UBCINFOEXISTS(vp) && !ubc_hold(vp)) { - error = ENOENT; - goto bad; - } - if (error = VOP_OPEN(vp, fmode, cred, p)) { - ubc_rele(vp); goto bad; } @@ -192,7 +211,10 @@ vn_open(ndp, fmode, cmode) panic("vn_open: v_writecount"); return (0); bad: - vput(vp); + VOP_UNLOCK(vp, 0, p); + if (didhold) + ubc_rele(vp); + vrele(vp); return (error); } @@ -200,6 +222,7 @@ bad: * Check for write permissions on the specified vnode. * Prototype text segments cannot be written. */ +int vn_writechk(vp) register struct vnode *vp; { @@ -220,6 +243,7 @@ vn_writechk(vp) /* * Vnode close call */ +int vn_close(vp, flags, cred, p) register struct vnode *vp; int flags; @@ -239,6 +263,7 @@ vn_close(vp, flags, cred, p) /* * Package up an I/O request on a vnode into a uio and do it. */ +int vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p) enum uio_rw rw; struct vnode *vp; @@ -286,24 +311,81 @@ vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p) /* * File table vnode read routine. */ -vn_read(fp, uio, cred) +static int +vn_read(fp, uio, cred, flags, p) struct file *fp; struct uio *uio; struct ucred *cred; + int flags; + struct proc *p; { - struct vnode *vp = (struct vnode *)fp->f_data; - struct proc *p = uio->uio_procp; - int error; + struct vnode *vp; + int error, ioflag; off_t count; + if (p != uio->uio_procp) + panic("vn_read: uio_procp does not match p"); + + vp = (struct vnode *)fp->f_data; + ioflag = 0; + if (fp->f_flag & FNONBLOCK) + ioflag |= IO_NDELAY; VOP_LEASE(vp, p, cred, LEASE_READ); - (void)vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - uio->uio_offset = fp->f_offset; + error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + if (error) + return (error); + if ((flags & FOF_OFFSET) == 0) + uio->uio_offset = fp->f_offset; count = uio->uio_resid; - error = VOP_READ(vp, uio, (fp->f_flag & FNONBLOCK) ? IO_NDELAY : 0, cred); - - fp->f_offset += count - uio->uio_resid; + if(UBCINFOEXISTS(vp)) { + memory_object_t pager; + struct iovec *iov; + off_t file_off; + kern_return_t kr = KERN_SUCCESS; + kern_return_t ret = KERN_SUCCESS; + int count; + + pager = (memory_object_t)ubc_getpager(vp); + file_off = uio->uio_offset; + iov = uio->uio_iov; + count = uio->uio_iovcnt; + while(count) { + kr = vm_conflict_check(current_map(), + (vm_offset_t)iov->iov_base, iov->iov_len, + pager, file_off); + if(kr == KERN_ALREADY_WAITING) { + if((count != uio->uio_iovcnt) && + (ret != KERN_ALREADY_WAITING)) { + error = EINVAL; + goto done; + } + ret = KERN_ALREADY_WAITING; + } else if (kr != KERN_SUCCESS) { + error = EINVAL; + goto done; + } + if(kr != ret) { + error = EINVAL; + goto done; + } + file_off += iov->iov_len; + iov++; + count--; + } + if(ret == KERN_ALREADY_WAITING) { + uio->uio_resid = 0; + if ((flags & FOF_OFFSET) == 0) + fp->f_offset += + count - uio->uio_resid; + error = 0; + goto done; + } + } + error = VOP_READ(vp, uio, ioflag, cred); + if ((flags & FOF_OFFSET) == 0) + fp->f_offset += count - uio->uio_resid; +done: VOP_UNLOCK(vp, 0, p); return (error); } @@ -312,16 +394,25 @@ vn_read(fp, uio, cred) /* * File table vnode write routine. */ -vn_write(fp, uio, cred) +static int +vn_write(fp, uio, cred, flags, p) struct file *fp; struct uio *uio; struct ucred *cred; + int flags; + struct proc *p; { - struct vnode *vp = (struct vnode *)fp->f_data; - struct proc *p = uio->uio_procp; - int error, ioflag = IO_UNIT; + struct vnode *vp; + int error, ioflag; off_t count; + if (p != uio->uio_procp) + panic("vn_write: uio_procp does not match p"); + + vp = (struct vnode *)fp->f_data; + ioflag = IO_UNIT; + if (vp->v_type == VREG) + bwillwrite(); if (vp->v_type == VREG && (fp->f_flag & O_APPEND)) ioflag |= IO_APPEND; if (fp->f_flag & FNONBLOCK) @@ -330,16 +421,67 @@ vn_write(fp, uio, cred) (vp->v_mount && (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS))) ioflag |= IO_SYNC; VOP_LEASE(vp, p, cred, LEASE_WRITE); - (void)vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - uio->uio_offset = fp->f_offset; - count = uio->uio_resid; + error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + if (error) + return (error); + if ((flags & FOF_OFFSET) == 0) { + uio->uio_offset = fp->f_offset; + count = uio->uio_resid; + } + if(UBCINFOEXISTS(vp)) { + memory_object_t pager; + struct iovec *iov; + off_t file_off; + kern_return_t kr = KERN_SUCCESS; + kern_return_t ret = KERN_SUCCESS; + int count; + + pager = (memory_object_t)ubc_getpager(vp); + file_off = uio->uio_offset; + iov = uio->uio_iov; + count = uio->uio_iovcnt; + while(count) { + kr = vm_conflict_check(current_map(), + (vm_offset_t)iov->iov_base, + iov->iov_len, pager, file_off); + if(kr == KERN_ALREADY_WAITING) { + if((count != uio->uio_iovcnt) && + (ret != KERN_ALREADY_WAITING)) { + error = EINVAL; + goto done; + } + ret = KERN_ALREADY_WAITING; + } else if (kr != KERN_SUCCESS) { + error = EINVAL; + goto done; + } + if(kr != ret) { + error = EINVAL; + goto done; + } + file_off += iov->iov_len; + iov++; + count--; + } + if(ret == KERN_ALREADY_WAITING) { + uio->uio_resid = 0; + if ((flags & FOF_OFFSET) == 0) + fp->f_offset += + count - uio->uio_resid; + error = 0; + goto done; + } + } error = VOP_WRITE(vp, uio, ioflag, cred); - if (ioflag & IO_APPEND) - fp->f_offset = uio->uio_offset; - else - fp->f_offset += count - uio->uio_resid; + if ((flags & FOF_OFFSET) == 0) { + if (ioflag & IO_APPEND) + fp->f_offset = uio->uio_offset; + else + fp->f_offset += count - uio->uio_resid; + } + /* * Set the credentials on successful writes */ @@ -347,6 +489,7 @@ vn_write(fp, uio, cred) ubc_setcred(vp, p); } +done: VOP_UNLOCK(vp, 0, p); return (error); } @@ -354,6 +497,7 @@ vn_write(fp, uio, cred) /* * File table vnode stat routine. */ +int vn_stat(vp, sb, p) struct vnode *vp; register struct stat *sb; @@ -422,6 +566,7 @@ vn_stat(vp, sb, p) /* * File table vnode ioctl routine. */ +static int vn_ioctl(fp, com, data, p) struct file *fp; u_long com; @@ -432,7 +577,7 @@ vn_ioctl(fp, com, data, p) struct vattr vattr; int error; struct vnode *ttyvp; - + switch (vp->v_type) { case VREG: @@ -453,21 +598,41 @@ vn_ioctl(fp, com, data, p) case VFIFO: case VCHR: case VBLK: - error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p); - if (error == 0 && com == TIOCSCTTY) { - VREF(vp); - ttyvp = p->p_session->s_ttyvp; - p->p_session->s_ttyvp = vp; - if (ttyvp) - vrele(ttyvp); - } - return (error); + + /* Should not be able to set block size from user space */ + if(com == DKIOCSETBLOCKSIZE) + return (EPERM); + + if (com == FIODTYPE) { + if (vp->v_type == VBLK) { + if (major(vp->v_rdev) >= nblkdev) + return (ENXIO); + *(int *)data = bdevsw[major(vp->v_rdev)].d_type; + } else if (vp->v_type == VCHR) { + if (major(vp->v_rdev) >= nchrdev) + return (ENXIO); + *(int *)data = cdevsw[major(vp->v_rdev)].d_type; + } else { + return (ENOTTY); + } + return (0); + } + error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p); + if (error == 0 && com == TIOCSCTTY) { + VREF(vp); + ttyvp = p->p_session->s_ttyvp; + p->p_session->s_ttyvp = vp; + if (ttyvp) + vrele(ttyvp); + } + return (error); } } /* * File table vnode select routine. */ +static int vn_select(fp, which, wql, p) struct file *fp; int which; @@ -514,6 +679,7 @@ vn_lock(vp, flags, p) /* * File table vnode close routine. */ +static int vn_closefile(fp, p) struct file *fp; struct proc *p; diff --git a/bsd/vfs/vnode_if.c b/bsd/vfs/vnode_if.c index 4d72b5069..cfaf2ed72 100644 --- a/bsd/vfs/vnode_if.c +++ b/bsd/vfs/vnode_if.c @@ -1,6 +1,6 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * diff --git a/bsd/vfs/vnode_if.sh b/bsd/vfs/vnode_if.sh index 5a721a17d..574dd9770 100644 --- a/bsd/vfs/vnode_if.sh +++ b/bsd/vfs/vnode_if.sh @@ -1,7 +1,7 @@ #!/bin/sh - copyright=' /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -170,9 +170,12 @@ exec > $out_h echo "$copyright" echo "$warning" echo ' -#ifndef _VNODE_IF_H_ -#define _VNODE_IF_H_ +#ifndef _SYS_VNODE_IF_H_ +#define _SYS_VNODE_IF_H_ +#include + +#ifdef __APPLE_API_UNSTABLE extern struct vnodeop_desc vop_default_desc; ' @@ -214,7 +217,8 @@ function doit() { } if (toupper(ubc) == "UBC") { printf("\t{\n\t\tint _err;\n\t\t" \ - "extern int ubc_hold();\n\t\textern void ubc_rele();\n\t\t" \ + "extern int ubc_hold(struct vnode *vp);\n\t\t" \ + "extern void ubc_rele(struct vnode *vp);\n\t\t" \ "int _didhold = ubc_hold(%s);\n\t\t" \ "_err = VCALL(%s%s, VOFFSET(%s), &a);\n\t\t" \ "if (_didhold)\n\t\t\tubc_rele(%s);\n\t\t" \ @@ -245,7 +249,8 @@ END { echo ' /* End of special cases. */ -#endif /* !_VNODE_IF_H_ */' +#endif /* __APPLE_API_UNSTABLE */ +#endif /* !_SYS_VNODE_IF_H_ */' # # Redirect stdout to the C file. diff --git a/bsd/vm/dp_backing_file.c b/bsd/vm/dp_backing_file.c index 359d95fd1..e1ff49d7b 100644 --- a/bsd/vm/dp_backing_file.c +++ b/bsd/vm/dp_backing_file.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -97,8 +96,6 @@ macx_swapon( if ((error = suser(p->p_ucred, &p->p_acflag))) goto swapon_bailout; - unix_master(); - if(default_pager_init_flag == 0) { start_def_pager(NULL); default_pager_init_flag = 1; @@ -218,7 +215,6 @@ swapon_bailout: if (vp) { vrele(vp); } - unix_release(); (void) thread_funnel_set(kernel_flock, FALSE); return(error); } @@ -250,8 +246,6 @@ macx_swapoff( if ((error = suser(p->p_ucred, &p->p_acflag))) goto swapoff_bailout; - unix_master(); - /* * Get the vnode for the paging area. */ @@ -310,7 +304,6 @@ swapoff_bailout: if (vp) vrele(vp); - unix_release(); (void) thread_funnel_set(kernel_flock, FALSE); return(error); } diff --git a/bsd/vm/vm_unix.c b/bsd/vm/vm_unix.c index 29261f2c8..0656cfdad 100644 --- a/bsd/vm/vm_unix.c +++ b/bsd/vm/vm_unix.c @@ -28,6 +28,8 @@ /* */ + + #include #include @@ -52,14 +54,20 @@ #include #include #include +#include #include -#include #include #include #include + #include +#include + + +extern shared_region_mapping_t system_shared_region; +extern zone_t lsf_zone; useracc(addr, len, prot) caddr_t addr; @@ -302,8 +310,10 @@ task_for_pid(target_tport, pid, t) mutex_pause(); /* temp loss of funnel */ goto restart; } - sright = convert_task_to_port(p->task); - tret = ipc_port_copyout_send(sright, get_task_ipcspace(current_task())); + sright = (void *)convert_task_to_port(p->task); + tret = (void *) + ipc_port_copyout_send(sright, + get_task_ipcspace(current_task())); } else tret = MACH_PORT_NULL; (void ) copyout((char *)&tret, (char *) t, sizeof(mach_port_t)); @@ -359,6 +369,7 @@ load_shared_file( int local_flags; int caller_flags; int i; + int default_regions = 0; vm_size_t dummy; kern_return_t kret; @@ -368,7 +379,6 @@ load_shared_file( ndp = &nd; - unix_master(); /* Retrieve the base address */ if (error = copyin(base_address, &local_base, sizeof (caddr_t))) { @@ -377,6 +387,18 @@ load_shared_file( if (error = copyin(flags, &local_flags, sizeof (int))) { goto lsf_bailout; } + + if(local_flags & QUERY_IS_SYSTEM_REGION) { + vm_get_shared_region(current_task(), &shared_region); + if (shared_region == system_shared_region) { + local_flags = SYSTEM_REGION_BACKED; + } else { + local_flags = 0; + } + error = 0; + error = copyout(&local_flags, flags, sizeof (int)); + goto lsf_bailout; + } caller_flags = local_flags; kret = kmem_alloc(kernel_map, (vm_offset_t *)&filename_str, (vm_size_t)(MAXPATHLEN)); @@ -433,14 +455,48 @@ load_shared_file( goto lsf_bailout_free_vput; } + vm_get_shared_region(current_task(), &shared_region); + if(shared_region == system_shared_region) { + default_regions = 1; + } + if(((vp->v_mount != rootvnode->v_mount) + && (shared_region == system_shared_region)) + && (lsf_mapping_pool_gauge() < 75)) { + /* We don't want to run out of shared memory */ + /* map entries by starting too many private versions */ + /* of the shared library structures */ + int error; + if(p->p_flag & P_NOSHLIB) { + error = clone_system_shared_regions(FALSE); + } else { + error = clone_system_shared_regions(TRUE); + } + if (error) { + goto lsf_bailout_free_vput; + } + local_flags = local_flags & ~NEW_LOCAL_SHARED_REGIONS; + vm_get_shared_region(current_task(), &shared_region); + } #ifdef notdef if(vattr.va_size != mapped_file_size) { error = EINVAL; goto lsf_bailout_free_vput; } #endif + if(p->p_flag & P_NOSHLIB) { + p->p_flag = p->p_flag & ~P_NOSHLIB; + } + + /* load alternate regions if the caller has requested. */ + /* Note: the new regions are "clean slates" */ + if (local_flags & NEW_LOCAL_SHARED_REGIONS) { + error = clone_system_shared_regions(FALSE); + if (error) { + goto lsf_bailout_free_vput; + } + vm_get_shared_region(current_task(), &shared_region); + } - vm_get_shared_region(current_task(), &shared_region); task_mapping_info.self = (vm_offset_t)shared_region; shared_region_mapping_info(shared_region, @@ -480,66 +536,6 @@ load_shared_file( } } - /* load alternate regions if the caller has requested. */ - /* Note: the new regions are "clean slates" */ - - if (local_flags & NEW_LOCAL_SHARED_REGIONS) { - - shared_region_mapping_t new_shared_region; - shared_region_mapping_t old_shared_region; - struct shared_region_task_mappings old_info; - struct shared_region_task_mappings new_info; - - if(shared_file_create_system_region(&new_shared_region)) { - error = ENOMEM; - goto lsf_bailout_free_vput; - } - vm_get_shared_region(current_task(), &old_shared_region); - - old_info.self = (vm_offset_t)old_shared_region; - shared_region_mapping_info(old_shared_region, - &(old_info.text_region), - &(old_info.text_size), - &(old_info.data_region), - &(old_info.data_size), - &(old_info.region_mappings), - &(old_info.client_base), - &(old_info.alternate_base), - &(old_info.alternate_next), - &(old_info.flags), &next); - new_info.self = (vm_offset_t)new_shared_region; - shared_region_mapping_info(new_shared_region, - &(new_info.text_region), - &(new_info.text_size), - &(new_info.data_region), - &(new_info.data_size), - &(new_info.region_mappings), - &(new_info.client_base), - &(new_info.alternate_base), - &(new_info.alternate_next), - &(new_info.flags), &next); - if (vm_map_region_replace(current_map(), old_info.text_region, - new_info.text_region, old_info.client_base, - old_info.client_base+old_info.text_size)) { - panic("load_shared_file: shared region mis-alignment"); - shared_region_mapping_dealloc(new_shared_region); - error = EINVAL; - goto lsf_bailout_free_vput; - } - if(vm_map_region_replace(current_map(), old_info.data_region, - new_info.data_region, - old_info.client_base + old_info.text_size, - old_info.client_base - + old_info.text_size + old_info.data_size)) { - panic("load_shared_file: shared region mis-alignment 1"); - shared_region_mapping_dealloc(new_shared_region); - error = EINVAL; - goto lsf_bailout_free_vput; - } - vm_set_shared_region(current_task(), new_shared_region); - task_mapping_info = new_info; - shared_region_mapping_dealloc(old_shared_region); - } if((kr = copyin_shared_file((vm_offset_t)mapped_file_addr, mapped_file_size, @@ -578,6 +574,8 @@ load_shared_file( } } } else { + if(default_regions) + local_flags |= SYSTEM_REGION_BACKED; if(!(error = copyout(&local_flags, flags, sizeof (int)))) { error = copyout(&local_base, base_address, sizeof (caddr_t)); @@ -594,7 +592,6 @@ lsf_bailout_free: (vm_size_t)(map_cnt*sizeof(sf_mapping_t))); lsf_bailout: - unix_release(); return error; } @@ -622,11 +619,6 @@ reset_shared_file( int i; kern_return_t kret; - - - - unix_master(); - /* Retrieve the base address */ if (error = copyin(base_address, &local_base, sizeof (caddr_t))) { goto rsf_bailout; @@ -676,15 +668,54 @@ reset_shared_file( (vm_size_t)(map_cnt*sizeof(sf_mapping_t))); rsf_bailout: - unix_release(); return error; } +struct new_system_shared_regions_args { + int dummy; +}; + +int +new_system_shared_regions( + struct proc *p, + struct new_system_shared_regions_args *uap, + register *retval) +{ + shared_region_mapping_t regions; + shared_region_mapping_t new_regions; + + if(!(is_suser())) { + *retval = EINVAL; + return EINVAL; + } + + /* get current shared region info for */ + /* restoration after new system shared */ + /* regions are in place */ + vm_get_shared_region(current_task(), ®ions); + + /* usually only called at boot time */ + /* shared_file_boot_time_init creates */ + /* a new set of system shared regions */ + /* and places them as the system */ + /* shared regions. */ + shared_file_boot_time_init(); + + /* set current task back to its */ + /* original regions. */ + vm_get_shared_region(current_task(), &new_regions); + shared_region_mapping_dealloc(new_regions); + + vm_set_shared_region(current_task(), regions); + + *retval = 0; + return 0; +} int -clone_system_shared_regions() +clone_system_shared_regions(shared_regions_active) { shared_region_mapping_t new_shared_region; shared_region_mapping_t next; @@ -692,6 +723,8 @@ clone_system_shared_regions() struct shared_region_task_mappings old_info; struct shared_region_task_mappings new_info; + struct proc *p; + if (shared_file_create_system_region(&new_shared_region)) return (ENOMEM); vm_get_shared_region(current_task(), &old_shared_region); @@ -717,15 +750,19 @@ clone_system_shared_regions() &(new_info.alternate_base), &(new_info.alternate_next), &(new_info.flags), &next); - if(vm_region_clone(old_info.text_region, new_info.text_region)) { - panic("clone_system_shared_regions: shared region mis-alignment 1"); + if(shared_regions_active) { + if(vm_region_clone(old_info.text_region, new_info.text_region)) { + panic("clone_system_shared_regions: shared region mis-alignment 1"); shared_region_mapping_dealloc(new_shared_region); return(EINVAL); - } - if (vm_region_clone(old_info.data_region, new_info.data_region)) { - panic("clone_system_shared_regions: shared region mis-alignment 2"); + } + if (vm_region_clone(old_info.data_region, new_info.data_region)) { + panic("clone_system_shared_regions: shared region mis-alignment 2"); shared_region_mapping_dealloc(new_shared_region); return(EINVAL); + } + shared_region_object_chain_attach( + new_shared_region, old_shared_region); } if (vm_map_region_replace(current_map(), old_info.text_region, new_info.text_region, old_info.client_base, @@ -744,7 +781,982 @@ clone_system_shared_regions() return(EINVAL); } vm_set_shared_region(current_task(), new_shared_region); - shared_region_object_chain_attach(new_shared_region, old_shared_region); + + /* consume the reference which wasn't accounted for in object */ + /* chain attach */ + if(!shared_regions_active) + shared_region_mapping_dealloc(old_shared_region); + return(0); } + +extern vm_map_t bsd_pageable_map; + +/* header for the profile name file. The profiled app info is held */ +/* in the data file and pointed to by elements in the name file */ + +struct profile_names_header { + unsigned int number_of_profiles; + unsigned int user_id; + unsigned int version; + off_t element_array; + unsigned int spare1; + unsigned int spare2; + unsigned int spare3; +}; + +struct profile_element { + off_t addr; + vm_size_t size; + unsigned int mod_date; + unsigned int inode; + char name[12]; +}; + +struct global_profile { + struct vnode *names_vp; + struct vnode *data_vp; + vm_offset_t buf_ptr; + unsigned int user; + unsigned int age; + unsigned int busy; +}; + +struct global_profile_cache { + int max_ele; + unsigned int age; + struct global_profile profiles[3]; +}; + +struct global_profile_cache global_user_profile_cache = + {3, 0, NULL, NULL, NULL, 0, 0, 0, + NULL, NULL, NULL, 0, 0, 0, + NULL, NULL, NULL, 0, 0, 0 }; + +/* BSD_OPEN_PAGE_CACHE_FILES: */ +/* Caller provides a user id. This id was used in */ +/* prepare_profile_database to create two unique absolute */ +/* file paths to the associated profile files. These files */ +/* are either opened or bsd_open_page_cache_files returns an */ +/* error. The header of the names file is then consulted. */ +/* The header and the vnodes for the names and data files are */ +/* returned. */ + +int +bsd_open_page_cache_files( + unsigned int user, + struct global_profile **profile) +{ + char *cache_path = "/var/vm/app_profile/"; + struct proc *p; + int error; + int resid; + off_t resid_off; + unsigned int lru; + vm_size_t size; + + struct vnode *names_vp; + struct vnode *data_vp; + vm_offset_t names_buf; + vm_offset_t buf_ptr; + + int profile_names_length; + int profile_data_length; + char *profile_data_string; + char *profile_names_string; + char *substring; + + struct vattr vattr; + + struct profile_names_header *profile_header; + kern_return_t ret; + + struct nameidata nd_names; + struct nameidata nd_data; + + int i; + + + p = current_proc(); + +restart: + for(i = 0; ibusy) { + /* + * drop funnel and wait + */ + (void)tsleep((void *) + *profile, + PRIBIO, "app_profile", 0); + goto restart; + } + (*profile)->busy = 1; + (*profile)->age = global_user_profile_cache.age; + global_user_profile_cache.age+=1; + return 0; + } + } + + lru = global_user_profile_cache.age; + for(i = 0; iage = global_user_profile_cache.age; + global_user_profile_cache.age+=1; + break; + } + if(global_user_profile_cache.profiles[i].age < lru) { + lru = global_user_profile_cache.profiles[i].age; + *profile = &global_user_profile_cache.profiles[i]; + } + } + + if ((*profile)->busy) { + /* + * drop funnel and wait + */ + (void)tsleep((void *) + &(global_user_profile_cache), + PRIBIO, "app_profile", 0); + goto restart; + } + (*profile)->busy = 1; + (*profile)->user = user; + + if((*profile)->data_vp != NULL) { + kmem_free(kernel_map, + (*profile)->buf_ptr, 4 * PAGE_SIZE); + if ((*profile)->names_vp) { + vrele((*profile)->names_vp); + (*profile)->names_vp = NULL; + } + if ((*profile)->data_vp) { + vrele((*profile)->data_vp); + (*profile)->data_vp = NULL; + } + } + + /* put dummy value in for now to get */ + /* competing request to wait above */ + /* until we are finished */ + (*profile)->data_vp = (struct vnode *)0xFFFFFFFF; + + /* Try to open the appropriate users profile files */ + /* If neither file is present, try to create them */ + /* If one file is present and the other not, fail. */ + /* If the files do exist, check them for the app_file */ + /* requested and read it in if present */ + + + ret = kmem_alloc(kernel_map, + (vm_offset_t *)&profile_data_string, PATH_MAX); + + if(ret) { + (*profile)->data_vp = NULL; + (*profile)->busy = 0; + wakeup(*profile); + return ENOMEM; + } + + /* Split the buffer in half since we know the size of */ + /* our file path and our allocation is adequate for */ + /* both file path names */ + profile_names_string = profile_data_string + (PATH_MAX/2); + + + strcpy(profile_data_string, cache_path); + strcpy(profile_names_string, cache_path); + profile_names_length = profile_data_length + = strlen(profile_data_string); + substring = profile_data_string + profile_data_length; + sprintf(substring, "%x_data", user); + substring = profile_names_string + profile_names_length; + sprintf(substring, "%x_names", user); + + /* We now have the absolute file names */ + + ret = kmem_alloc(kernel_map, + (vm_offset_t *)&names_buf, 4 * PAGE_SIZE); + if(ret) { + kmem_free(kernel_map, + (vm_offset_t)profile_data_string, PATH_MAX); + (*profile)->data_vp = NULL; + (*profile)->busy = 0; + wakeup(*profile); + return ENOMEM; + } + + NDINIT(&nd_names, LOOKUP, FOLLOW | LOCKLEAF, + UIO_SYSSPACE, profile_names_string, p); + NDINIT(&nd_data, LOOKUP, FOLLOW | LOCKLEAF, + UIO_SYSSPACE, profile_data_string, p); + if (error = vn_open(&nd_data, FREAD | FWRITE, 0)) { +#ifdef notdef + printf("bsd_open_page_cache_files: CacheData file not found %s\n", + profile_data_string); +#endif + kmem_free(kernel_map, + (vm_offset_t)names_buf, 4 * PAGE_SIZE); + kmem_free(kernel_map, + (vm_offset_t)profile_data_string, PATH_MAX); + (*profile)->data_vp = NULL; + (*profile)->busy = 0; + wakeup(*profile); + return error; + } + + data_vp = nd_data.ni_vp; + VOP_UNLOCK(data_vp, 0, p); + + if (error = vn_open(&nd_names, FREAD | FWRITE, 0)) { + printf("bsd_open_page_cache_files: NamesData file not found %s\n", + profile_data_string); + kmem_free(kernel_map, + (vm_offset_t)names_buf, 4 * PAGE_SIZE); + kmem_free(kernel_map, + (vm_offset_t)profile_data_string, PATH_MAX); + vrele(data_vp); + (*profile)->data_vp = NULL; + (*profile)->busy = 0; + wakeup(*profile); + return error; + } + names_vp = nd_names.ni_vp; + + if(error = VOP_GETATTR(names_vp, &vattr, p->p_ucred, p)) { + printf("bsd_open_page_cache_files: Can't stat name file %s\n", profile_names_string); + kmem_free(kernel_map, + (vm_offset_t)profile_data_string, PATH_MAX); + kmem_free(kernel_map, + (vm_offset_t)names_buf, 4 * PAGE_SIZE); + vput(names_vp); + vrele(data_vp); + (*profile)->data_vp = NULL; + (*profile)->busy = 0; + wakeup(*profile); + return error; + } + + size = vattr.va_size; + if(size > 4 * PAGE_SIZE) + size = 4 * PAGE_SIZE; + buf_ptr = names_buf; + resid_off = 0; + + while(size) { + error = vn_rdwr(UIO_READ, names_vp, (caddr_t)buf_ptr, + size, resid_off, + UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); + if((error) || (size == resid)) { + if(!error) { + error = EINVAL; + } + kmem_free(kernel_map, + (vm_offset_t)profile_data_string, PATH_MAX); + kmem_free(kernel_map, + (vm_offset_t)names_buf, 4 * PAGE_SIZE); + vput(names_vp); + vrele(data_vp); + (*profile)->data_vp = NULL; + (*profile)->busy = 0; + wakeup(*profile); + return error; + } + buf_ptr += size-resid; + resid_off += size-resid; + size = resid; + } + + VOP_UNLOCK(names_vp, 0, p); + kmem_free(kernel_map, (vm_offset_t)profile_data_string, PATH_MAX); + (*profile)->names_vp = names_vp; + (*profile)->data_vp = data_vp; + (*profile)->buf_ptr = names_buf; + return 0; + +} + +void +bsd_close_page_cache_files( + struct global_profile *profile) +{ + profile->busy = 0; + wakeup(profile); +} + +int +bsd_read_page_cache_file( + unsigned int user, + int *fid, + int *mod, + char *app_name, + struct vnode *app_vp, + vm_offset_t *buffer, + vm_offset_t *buf_size) +{ + + boolean_t funnel_state; + + struct proc *p; + int error; + int resid; + vm_size_t size; + + off_t profile; + unsigned int profile_size; + + vm_offset_t names_buf; + struct vattr vattr; + + kern_return_t ret; + + struct vnode *names_vp; + struct vnode *data_vp; + struct vnode *vp1; + struct vnode *vp2; + + struct global_profile *uid_files; + + funnel_state = thread_funnel_set(kernel_flock, TRUE); + + /* Try to open the appropriate users profile files */ + /* If neither file is present, try to create them */ + /* If one file is present and the other not, fail. */ + /* If the files do exist, check them for the app_file */ + /* requested and read it in if present */ + + + error = bsd_open_page_cache_files(user, &uid_files); + if(error) { + thread_funnel_set(kernel_flock, funnel_state); + return EINVAL; + } + + p = current_proc(); + + names_vp = uid_files->names_vp; + data_vp = uid_files->data_vp; + names_buf = uid_files->buf_ptr; + + + /* + * Get locks on both files, get the vnode with the lowest address first + */ + + if((unsigned int)names_vp < (unsigned int)data_vp) { + vp1 = names_vp; + vp2 = data_vp; + } else { + vp1 = data_vp; + vp2 = names_vp; + } + error = vn_lock(vp1, LK_EXCLUSIVE | LK_RETRY, p); + if(error) { + printf("bsd_read_page_cache_file: Can't lock profile names %x\n", user); + bsd_close_page_cache_files(uid_files); + thread_funnel_set(kernel_flock, funnel_state); + return error; + } + error = vn_lock(vp2, LK_EXCLUSIVE | LK_RETRY, p); + if(error) { + printf("bsd_read_page_cache_file: Can't lock profile data %x\n", user); + VOP_UNLOCK(vp1, 0, p); + bsd_close_page_cache_files(uid_files); + thread_funnel_set(kernel_flock, funnel_state); + return error; + } + + if(error = VOP_GETATTR(app_vp, &vattr, p->p_ucred, p)) { + VOP_UNLOCK(names_vp, 0, p); + VOP_UNLOCK(data_vp, 0, p); + printf("bsd_read_cache_file: Can't stat app file %s\n", app_name); + bsd_close_page_cache_files(uid_files); + thread_funnel_set(kernel_flock, funnel_state); + return error; + } + + *fid = vattr.va_fileid; + *mod = vattr.va_mtime.tv_sec; + + + if (bsd_search_page_cache_data_base(names_vp, names_buf, app_name, + (unsigned int) vattr.va_mtime.tv_sec, + vattr.va_fileid, &profile, &profile_size) == 0) { + /* profile is an offset in the profile data base */ + /* It is zero if no profile data was found */ + + if(profile_size == 0) { + *buffer = NULL; + *buf_size = 0; + VOP_UNLOCK(names_vp, 0, p); + VOP_UNLOCK(data_vp, 0, p); + bsd_close_page_cache_files(uid_files); + thread_funnel_set(kernel_flock, funnel_state); + return 0; + } + ret = (vm_offset_t)(kmem_alloc(kernel_map, buffer, profile_size)); + if(ret) { + VOP_UNLOCK(names_vp, 0, p); + VOP_UNLOCK(data_vp, 0, p); + bsd_close_page_cache_files(uid_files); + thread_funnel_set(kernel_flock, funnel_state); + return ENOMEM; + } + *buf_size = profile_size; + while(profile_size) { + error = vn_rdwr(UIO_READ, data_vp, + (caddr_t) *buffer, profile_size, + profile, UIO_SYSSPACE, IO_NODELOCKED, + p->p_ucred, &resid, p); + if(error) { + VOP_UNLOCK(names_vp, 0, p); + VOP_UNLOCK(data_vp, 0, p); + bsd_close_page_cache_files(uid_files); + kmem_free(kernel_map, (vm_offset_t)*buffer, profile_size); + thread_funnel_set(kernel_flock, funnel_state); + return EINVAL; + } + profile += profile_size - resid; + profile_size = resid; + } + VOP_UNLOCK(names_vp, 0, p); + VOP_UNLOCK(data_vp, 0, p); + bsd_close_page_cache_files(uid_files); + thread_funnel_set(kernel_flock, funnel_state); + return 0; + } else { + VOP_UNLOCK(names_vp, 0, p); + VOP_UNLOCK(data_vp, 0, p); + bsd_close_page_cache_files(uid_files); + thread_funnel_set(kernel_flock, funnel_state); + return EINVAL; + } + +} + +int +bsd_search_page_cache_data_base( + struct vnode *vp, + struct profile_names_header *database, + char *app_name, + unsigned int mod_date, + unsigned int inode, + off_t *profile, + unsigned int *profile_size) +{ + + struct proc *p; + + unsigned int i; + struct profile_element *element; + unsigned int ele_total; + unsigned int extended_list = 0; + off_t file_off = 0; + unsigned int size; + off_t resid_off; + int resid; + vm_offset_t local_buf = NULL; + + int error; + kern_return_t ret; + + p = current_proc(); + + if(((vm_offset_t)database->element_array) != + sizeof(struct profile_names_header)) { + return EINVAL; + } + element = (struct profile_element *)( + (vm_offset_t)database->element_array + + (vm_offset_t)database); + + ele_total = database->number_of_profiles; + + *profile = 0; + *profile_size = 0; + while(ele_total) { + /* note: code assumes header + n*ele comes out on a page boundary */ + if(((local_buf == 0) && (sizeof(struct profile_names_header) + + (ele_total * sizeof(struct profile_element))) + > (PAGE_SIZE * 4)) || + ((local_buf != 0) && + (ele_total * sizeof(struct profile_element)) + > (PAGE_SIZE * 4))) { + extended_list = ele_total; + if(element == (struct profile_element *) + ((vm_offset_t)database->element_array + + (vm_offset_t)database)) { + ele_total = ((PAGE_SIZE * 4)/sizeof(struct profile_element)) - 1; + } else { + ele_total = (PAGE_SIZE * 4)/sizeof(struct profile_element); + } + extended_list -= ele_total; + } + for (i=0; i + (PAGE_SIZE * 4)) { + size = PAGE_SIZE * 4; + } else { + size = ele_total * sizeof(struct profile_element); + } + resid_off = 0; + while(size) { + error = vn_rdwr(UIO_READ, vp, + (caddr_t)(local_buf + resid_off), + size, file_off + resid_off, UIO_SYSSPACE, + IO_NODELOCKED, p->p_ucred, &resid, p); + if(error) { + if(local_buf != NULL) { + kmem_free(kernel_map, + (vm_offset_t)local_buf, + 4 * PAGE_SIZE); + } + return EINVAL; + } + resid_off += size-resid; + size = resid; + } + } + if(local_buf != NULL) { + kmem_free(kernel_map, + (vm_offset_t)local_buf, 4 * PAGE_SIZE); + } + return 0; +} + +int +bsd_write_page_cache_file( + unsigned int user, + char *file_name, + caddr_t buffer, + vm_size_t size, + int mod, + int fid) +{ + struct proc *p; + struct nameidata nd; + struct vnode *vp = 0; + int resid; + off_t resid_off; + int error; + boolean_t funnel_state; + struct vattr vattr; + struct vattr data_vattr; + + off_t profile; + unsigned int profile_size; + + vm_offset_t names_buf; + struct vnode *names_vp; + struct vnode *data_vp; + struct vnode *vp1; + struct vnode *vp2; + + struct profile_names_header *profile_header; + off_t name_offset; + + struct global_profile *uid_files; + + + funnel_state = thread_funnel_set(kernel_flock, TRUE); + + + + error = bsd_open_page_cache_files(user, &uid_files); + if(error) { + thread_funnel_set(kernel_flock, funnel_state); + return EINVAL; + } + + p = current_proc(); + + names_vp = uid_files->names_vp; + data_vp = uid_files->data_vp; + names_buf = uid_files->buf_ptr; + + /* + * Get locks on both files, get the vnode with the lowest address first + */ + + if((unsigned int)names_vp < (unsigned int)data_vp) { + vp1 = names_vp; + vp2 = data_vp; + } else { + vp1 = data_vp; + vp2 = names_vp; + } + + error = vn_lock(vp1, LK_EXCLUSIVE | LK_RETRY, p); + if(error) { + printf("bsd_write_page_cache_file: Can't lock profile names %x\n", user); + bsd_close_page_cache_files(uid_files); + thread_funnel_set(kernel_flock, funnel_state); + return error; + } + error = vn_lock(vp2, LK_EXCLUSIVE | LK_RETRY, p); + if(error) { + printf("bsd_write_page_cache_file: Can't lock profile data %x\n", user); + VOP_UNLOCK(vp1, 0, p); + bsd_close_page_cache_files(uid_files); + thread_funnel_set(kernel_flock, funnel_state); + return error; + } + + /* Stat data file for size */ + + if(error = VOP_GETATTR(data_vp, &data_vattr, p->p_ucred, p)) { + VOP_UNLOCK(names_vp, 0, p); + VOP_UNLOCK(data_vp, 0, p); + printf("bsd_write_page_cache_file: Can't stat profile data %s\n", file_name); + bsd_close_page_cache_files(uid_files); + thread_funnel_set(kernel_flock, funnel_state); + return error; + } + + if (bsd_search_page_cache_data_base(names_vp, + (struct profile_names_header *)names_buf, + file_name, (unsigned int) mod, + fid, &profile, &profile_size) == 0) { + /* profile is an offset in the profile data base */ + /* It is zero if no profile data was found */ + + if(profile_size == 0) { + unsigned int header_size; + vm_offset_t buf_ptr; + + /* Our Write case */ + + /* read header for last entry */ + profile_header = + (struct profile_names_header *)names_buf; + name_offset = sizeof(struct profile_names_header) + + (sizeof(struct profile_element) + * profile_header->number_of_profiles); + profile_header->number_of_profiles += 1; + + if(name_offset < PAGE_SIZE * 4) { + struct profile_element *name; + /* write new entry */ + name = (struct profile_element *) + (names_buf + (vm_offset_t)name_offset); + name->addr = data_vattr.va_size; + name->size = size; + name->mod_date = mod; + name->inode = fid; + strncpy (name->name, file_name, 12); + } else { + unsigned int ele_size; + struct profile_element name; + /* write new entry */ + name.addr = data_vattr.va_size; + name.size = size; + name.mod_date = mod; + name.inode = fid; + strncpy (name.name, file_name, 12); + /* write element out separately */ + ele_size = sizeof(struct profile_element); + buf_ptr = (vm_offset_t)&name; + resid_off = name_offset; + + while(ele_size) { + error = vn_rdwr(UIO_WRITE, names_vp, + (caddr_t)buf_ptr, + ele_size, resid_off, + UIO_SYSSPACE, IO_NODELOCKED, + p->p_ucred, &resid, p); + if(error) { + printf("bsd_write_page_cache_file: Can't write name_element %x\n", user); + VOP_UNLOCK(names_vp, 0, p); + VOP_UNLOCK(data_vp, 0, p); + bsd_close_page_cache_files( + uid_files); + thread_funnel_set( + kernel_flock, + funnel_state); + return error; + } + buf_ptr += (vm_offset_t) + ele_size-resid; + resid_off += ele_size-resid; + ele_size = resid; + } + } + + if(name_offset < PAGE_SIZE * 4) { + header_size = name_offset + + sizeof(struct profile_element); + + } else { + header_size = + sizeof(struct profile_names_header); + } + buf_ptr = (vm_offset_t)profile_header; + resid_off = 0; + + /* write names file header */ + while(header_size) { + error = vn_rdwr(UIO_WRITE, names_vp, + (caddr_t)buf_ptr, + header_size, resid_off, + UIO_SYSSPACE, IO_NODELOCKED, + p->p_ucred, &resid, p); + if(error) { + VOP_UNLOCK(names_vp, 0, p); + VOP_UNLOCK(data_vp, 0, p); + printf("bsd_write_page_cache_file: Can't write header %x\n", user); + bsd_close_page_cache_files( + uid_files); + thread_funnel_set( + kernel_flock, funnel_state); + return error; + } + buf_ptr += (vm_offset_t)header_size-resid; + resid_off += header_size-resid; + header_size = resid; + } + /* write profile to data file */ + resid_off = data_vattr.va_size; + while(size) { + error = vn_rdwr(UIO_WRITE, data_vp, + (caddr_t)buffer, size, resid_off, + UIO_SYSSPACE, IO_NODELOCKED, + p->p_ucred, &resid, p); + if(error) { + VOP_UNLOCK(names_vp, 0, p); + VOP_UNLOCK(data_vp, 0, p); + printf("bsd_write_page_cache_file: Can't write header %x\n", user); + bsd_close_page_cache_files( + uid_files); + thread_funnel_set( + kernel_flock, funnel_state); + return error; + } + buffer += size-resid; + resid_off += size-resid; + size = resid; + } + VOP_UNLOCK(names_vp, 0, p); + VOP_UNLOCK(data_vp, 0, p); + bsd_close_page_cache_files(uid_files); + thread_funnel_set(kernel_flock, funnel_state); + return 0; + } + /* Someone else wrote a twin profile before us */ + VOP_UNLOCK(names_vp, 0, p); + VOP_UNLOCK(data_vp, 0, p); + bsd_close_page_cache_files(uid_files); + thread_funnel_set(kernel_flock, funnel_state); + return 0; + } else { + VOP_UNLOCK(names_vp, 0, p); + VOP_UNLOCK(data_vp, 0, p); + bsd_close_page_cache_files(uid_files); + thread_funnel_set(kernel_flock, funnel_state); + return EINVAL; + } + +} + +int +prepare_profile_database(int user) +{ + char *cache_path = "/var/vm/app_profile/"; + struct proc *p; + int error; + int resid; + off_t resid_off; + unsigned int lru; + vm_size_t size; + + struct vnode *names_vp; + struct vnode *data_vp; + vm_offset_t names_buf; + vm_offset_t buf_ptr; + + int profile_names_length; + int profile_data_length; + char *profile_data_string; + char *profile_names_string; + char *substring; + + struct vattr vattr; + + struct profile_names_header *profile_header; + kern_return_t ret; + + struct nameidata nd_names; + struct nameidata nd_data; + + int i; + + p = current_proc(); + + ret = kmem_alloc(kernel_map, + (vm_offset_t *)&profile_data_string, PATH_MAX); + + if(ret) { + return ENOMEM; + } + + /* Split the buffer in half since we know the size of */ + /* our file path and our allocation is adequate for */ + /* both file path names */ + profile_names_string = profile_data_string + (PATH_MAX/2); + + + strcpy(profile_data_string, cache_path); + strcpy(profile_names_string, cache_path); + profile_names_length = profile_data_length + = strlen(profile_data_string); + substring = profile_data_string + profile_data_length; + sprintf(substring, "%x_data", user); + substring = profile_names_string + profile_names_length; + sprintf(substring, "%x_names", user); + + /* We now have the absolute file names */ + + ret = kmem_alloc(kernel_map, + (vm_offset_t *)&names_buf, 4 * PAGE_SIZE); + if(ret) { + kmem_free(kernel_map, + (vm_offset_t)profile_data_string, PATH_MAX); + return ENOMEM; + } + + NDINIT(&nd_names, LOOKUP, FOLLOW, + UIO_SYSSPACE, profile_names_string, p); + NDINIT(&nd_data, LOOKUP, FOLLOW, + UIO_SYSSPACE, profile_data_string, p); + + if (error = vn_open(&nd_data, + O_CREAT | O_EXCL | FWRITE, S_IRUSR|S_IWUSR)) { + kmem_free(kernel_map, + (vm_offset_t)names_buf, 4 * PAGE_SIZE); + kmem_free(kernel_map, + (vm_offset_t)profile_data_string, PATH_MAX); + return 0; + } + + data_vp = nd_data.ni_vp; + VOP_UNLOCK(data_vp, 0, p); + + if (error = vn_open(&nd_names, + O_CREAT | O_EXCL | FWRITE, S_IRUSR|S_IWUSR)) { + printf("prepare_profile_database: Can't create CacheNames %s\n", + profile_data_string); + kmem_free(kernel_map, + (vm_offset_t)names_buf, 4 * PAGE_SIZE); + kmem_free(kernel_map, + (vm_offset_t)profile_data_string, PATH_MAX); + vrele(data_vp); + return error; + } + + names_vp = nd_names.ni_vp; + + + /* Write Header for new names file */ + + profile_header = (struct profile_names_header *)names_buf; + + profile_header->number_of_profiles = 0; + profile_header->user_id = user; + profile_header->version = 1; + profile_header->element_array = + sizeof(struct profile_names_header); + profile_header->spare1 = 0; + profile_header->spare2 = 0; + profile_header->spare3 = 0; + + size = sizeof(struct profile_names_header); + buf_ptr = (vm_offset_t)profile_header; + resid_off = 0; + + while(size) { + error = vn_rdwr(UIO_WRITE, names_vp, + (caddr_t)buf_ptr, size, resid_off, + UIO_SYSSPACE, IO_NODELOCKED, + p->p_ucred, &resid, p); + if(error) { + printf("prepare_profile_database: Can't write header %s\n", profile_names_string); + kmem_free(kernel_map, + (vm_offset_t)names_buf, 4 * PAGE_SIZE); + kmem_free(kernel_map, + (vm_offset_t)profile_data_string, + PATH_MAX); + vput(names_vp); + vrele(data_vp); + return error; + } + buf_ptr += size-resid; + resid_off += size-resid; + size = resid; + } + + VATTR_NULL(&vattr); + vattr.va_uid = user; + error = VOP_SETATTR(names_vp, &vattr, p->p_cred->pc_ucred, p); + if(error) { + printf("prepare_profile_database: " + "Can't set user %s\n", profile_names_string); + } + vput(names_vp); + + error = vn_lock(data_vp, LK_EXCLUSIVE | LK_RETRY, p); + if(error) { + vrele(data_vp); + printf("prepare_profile_database: cannot lock data file %s\n", + profile_data_string); + kmem_free(kernel_map, + (vm_offset_t)profile_data_string, PATH_MAX); + kmem_free(kernel_map, + (vm_offset_t)names_buf, 4 * PAGE_SIZE); + } + VATTR_NULL(&vattr); + vattr.va_uid = user; + error = VOP_SETATTR(data_vp, &vattr, p->p_cred->pc_ucred, p); + if(error) { + printf("prepare_profile_database: " + "Can't set user %s\n", profile_data_string); + } + + vput(data_vp); + kmem_free(kernel_map, + (vm_offset_t)profile_data_string, PATH_MAX); + kmem_free(kernel_map, + (vm_offset_t)names_buf, 4 * PAGE_SIZE); + return 0; + +} diff --git a/bsd/vm/vnode_pager.c b/bsd/vm/vnode_pager.c index 5cdbf447f..387b0995f 100644 --- a/bsd/vm/vnode_pager.c +++ b/bsd/vm/vnode_pager.c @@ -50,7 +50,6 @@ #include #include -#include #include #include #include @@ -59,6 +58,7 @@ #include #include +#include unsigned int vp_pagein=0; unsigned int vp_pgodirty=0; @@ -102,18 +102,17 @@ vnode_pageout(struct vnode *vp, isize = (int)size; - if (isize < 0) - panic("-ve count in vnode_pageout"); - if (isize == 0) - panic("vnode_pageout: size == 0\n"); - + if (isize <= 0) { + result = error = PAGER_ERROR; + goto out; + } UBCINFOCHECK("vnode_pageout", vp); if (UBCINVALID(vp)) { - result = PAGER_ERROR; - error = PAGER_ERROR; + result = error = PAGER_ERROR; + if (upl && !(flags & UPL_NOCOMMIT)) - ubc_upl_abort(upl, 0); + ubc_upl_abort_range(upl, upl_offset, size, UPL_ABORT_FREE_ON_EMPTY); goto out; } if (upl) { @@ -122,14 +121,31 @@ vnode_pageout(struct vnode *vp, * just go ahead and call VOP_PAGEOUT */ dp_pgouts++; + + KERNEL_DEBUG_CONSTANT((MACHDBG_CODE(DBG_MACH_VM, 1)) | DBG_FUNC_START, + size, 1, 0, 0, 0); + if (error = VOP_PAGEOUT(vp, upl, upl_offset, (off_t)f_offset, (size_t)size, p->p_ucred, flags)) result = error = PAGER_ERROR; + + KERNEL_DEBUG_CONSTANT((MACHDBG_CODE(DBG_MACH_VM, 1)) | DBG_FUNC_END, + size, 1, 0, 0, 0); + goto out; } ubc_create_upl(vp, f_offset, isize, &vpupl, &pl, UPL_COPYOUT_FROM); - if (vpupl == (upl_t) 0) - return PAGER_ABSENT; + + if (vpupl == (upl_t) 0) { + result = error = PAGER_ABSENT; + goto out; + } + /* + * if we get here, we've created the upl and + * are responsible for commiting/aborting it + * regardless of what the caller has passed in + */ + flags &= ~UPL_NOCOMMIT; if (ubc_getsize(vp) == 0) { for (offset = 0; isize; isize -= PAGE_SIZE, @@ -223,11 +239,17 @@ vnode_pageout(struct vnode *vp, } xsize = num_of_pages * PAGE_SIZE; - /* By defn callee will commit or abort upls */ + KERNEL_DEBUG_CONSTANT((MACHDBG_CODE(DBG_MACH_VM, 1)) | DBG_FUNC_START, + xsize, 0, 0, 0, 0); + if (error = VOP_PAGEOUT(vp, vpupl, (vm_offset_t)offset, (off_t)(f_offset + offset), xsize, - p->p_ucred, flags & ~UPL_NOCOMMIT)) + p->p_ucred, flags)) result = error = PAGER_ERROR; + + KERNEL_DEBUG_CONSTANT((MACHDBG_CODE(DBG_MACH_VM, 1)) | DBG_FUNC_END, + xsize, 0, 0, 0, 0); + offset += xsize; isize -= xsize; pg_index += num_of_pages; @@ -245,21 +267,26 @@ out: pager_return_t vnode_pagein( struct vnode *vp, - upl_t pl, - vm_offset_t pl_offset, + upl_t upl, + vm_offset_t upl_offset, vm_object_offset_t f_offset, vm_size_t size, int flags, int *errorp) { - int result = PAGER_SUCCESS; - struct proc *p = current_proc(); + struct proc *p = current_proc(); + upl_page_info_t *pl; + int result = PAGER_SUCCESS; int error = 0; int xfer_size; + int pages_in_upl; + int start_pg; + int last_pg; + int first_pg; + int xsize; + int abort_needed = 1; boolean_t funnel_state; - upl_t vpupl = NULL; - off_t local_offset; - unsigned int ioaddr; + funnel_state = thread_funnel_set(kernel_flock, TRUE); @@ -268,50 +295,129 @@ vnode_pagein( if (UBCINVALID(vp)) { result = PAGER_ERROR; error = PAGER_ERROR; - if (pl && !(flags & UPL_NOCOMMIT)) { - ubc_upl_abort(pl, 0); + if (upl && !(flags & UPL_NOCOMMIT)) { + ubc_upl_abort_range(upl, upl_offset, size, UPL_ABORT_FREE_ON_EMPTY | UPL_ABORT_ERROR); } goto out; } + if (upl == (upl_t)NULL) { + if (size > (MAX_UPL_TRANSFER * PAGE_SIZE)) { + result = PAGER_ERROR; + error = PAGER_ERROR; + goto out; + } + ubc_create_upl(vp, f_offset, size, &upl, &pl, UPL_RET_ONLY_ABSENT); - if (pl) { - dp_pgins++; - if (error = VOP_PAGEIN(vp, pl, pl_offset, (off_t)f_offset, - size, p->p_ucred, flags)) { - result = PAGER_ERROR; + if (upl == (upl_t)NULL) { + result = PAGER_ABSENT; + error = PAGER_ABSENT; + goto out; } + upl_offset = 0; + /* + * if we get here, we've created the upl and + * are responsible for commiting/aborting it + * regardless of what the caller has passed in + */ + flags &= ~UPL_NOCOMMIT; + + vp_pagein++; } else { + pl = ubc_upl_pageinfo(upl); - local_offset = 0; - while (size) { - if(size > 4096 && vp->v_tag == VT_NFS) { - xfer_size = 4096; - size = size - xfer_size; - } else { - xfer_size = size; - size = 0; - } - ubc_create_upl(vp, f_offset + local_offset, xfer_size, - &vpupl, NULL, UPL_FLAGS_NONE); - if (vpupl == (upl_t) 0) { - result = PAGER_ABSENT; - error = PAGER_ABSENT; - goto out; - } + dp_pgins++; + } + pages_in_upl = size / PAGE_SIZE; + first_pg = upl_offset / PAGE_SIZE; + + /* + * before we start marching forward, we must make sure we end on + * a present page, otherwise we will be working with a freed + * upl + */ + for (last_pg = pages_in_upl - 1; last_pg >= first_pg; last_pg--) { + if (upl_page_present(pl, last_pg)) + break; + } + pages_in_upl = last_pg + 1; + + for (last_pg = first_pg; last_pg < pages_in_upl;) { + /* + * scan the upl looking for the next + * page that is present.... if all of the + * pages are absent, we're done + */ + for (start_pg = last_pg; last_pg < pages_in_upl; last_pg++) { + if (upl_page_present(pl, last_pg)) + break; + } + if (last_pg == pages_in_upl) + break; + + /* + * if we get here, we've sitting on a page + * that is present... we want to skip over + * any range of 'valid' pages... if this takes + * us to the end of the request, than we're done + */ + for (start_pg = last_pg; last_pg < pages_in_upl; last_pg++) { + if (!upl_valid_page(pl, last_pg) || !upl_page_present(pl, last_pg)) + break; + } + if (last_pg > start_pg) { + /* + * we've found a range of valid pages + * if we've got COMMIT responsibility + * commit this range of pages back to the + * cache unchanged + */ + xsize = (last_pg - start_pg) * PAGE_SIZE; - vp_pagein++; + if (!(flags & UPL_NOCOMMIT)) + ubc_upl_abort_range(upl, start_pg * PAGE_SIZE, xsize, UPL_ABORT_FREE_ON_EMPTY); - /* By defn callee will commit or abort upls */ - if (error = VOP_PAGEIN(vp, vpupl, (vm_offset_t) 0, - (off_t)f_offset + local_offset, - xfer_size, p->p_ucred, - flags & ~UPL_NOCOMMIT)) { + abort_needed = 0; + } + if (last_pg == pages_in_upl) + break; + + if (!upl_page_present(pl, last_pg)) + /* + * if we found a range of valid pages + * terminated by a non-present page + * than start over + */ + continue; + + /* + * scan from the found invalid page looking for a valid + * or non-present page before the end of the upl is reached, if we + * find one, then it will be the last page of the request to + * 'cluster_io' + */ + for (start_pg = last_pg; last_pg < pages_in_upl; last_pg++) { + if (upl_valid_page(pl, last_pg) || !upl_page_present(pl, last_pg)) + break; + } + if (last_pg > start_pg) { + int xoff; + + xsize = (last_pg - start_pg) * PAGE_SIZE; + xoff = start_pg * PAGE_SIZE; + + if (error = VOP_PAGEIN(vp, upl, (vm_offset_t) xoff, + (off_t)f_offset + xoff, + xsize, p->p_ucred, + flags)) { result = PAGER_ERROR; error = PAGER_ERROR; + } - local_offset += PAGE_SIZE_64; + abort_needed = 0; } - } + } + if (!(flags & UPL_NOCOMMIT) && abort_needed) + ubc_upl_abort_range(upl, upl_offset, size, UPL_ABORT_FREE_ON_EMPTY); out: if (errorp) *errorp = result; diff --git a/iokit/Drivers/ata/drvApplePIIXATA/AppleATAPIIX.cpp b/iokit/Drivers/ata/drvApplePIIXATA/AppleATAPIIX.cpp deleted file mode 100644 index a8a659a8e..000000000 --- a/iokit/Drivers/ata/drvApplePIIXATA/AppleATAPIIX.cpp +++ /dev/null @@ -1,1037 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * AppleATAPIIX.cpp - ATA controller driver for Intel PIIX/PIIX3/PIIX4. - * - * HISTORY - * - */ - -#include -#include -#include -#include "AppleATAPIIX.h" -#include "AppleATAPIIXTiming.h" - -extern pmap_t kernel_pmap; // for pmap_extract() - -// Resources shared between the two IDE channels are protected -// by this mutex. -// -static IOLock * gPIIXLock = 0; -#define PIIX_LOCK IOLockLock(gPIIXLock) -#define PIIX_UNLOCK IOLockUnlock(gPIIXLock) - -#define IOREG(x) (ioBMRange + PIIX_IO_ ## x) - -#define CHECK_UNIT(drv) assert(drv < 2) - -#ifdef DEBUG_XXX -#define DLOG(fmt, args...) IOLog(fmt, ## args) -#else -#define DLOG(fmt, args...) -#endif - -//-------------------------------------------------------------------------- -// Metaclass macro. -// -#undef super -#define super IOATAStandardDriver - -OSDefineMetaClassAndStructorsWithInit( AppleATAPIIX, IOATAStandardDriver, - AppleATAPIIX::initialize() ) - -//-------------------------------------------------------------------------- -// PIIX class initializer. -// -void AppleATAPIIX::initialize() -{ - gPIIXLock = IOLockAlloc(); - assert(gPIIXLock); -} - -//-------------------------------------------------------------------------- -// Defines a table of supported PIIX device types, listing their -// PCI ID, and a name string. Also supply some utility functions -// to locate a table entry based on an arbitrary PCI ID. -// -static struct { - UInt32 CFID; - const char * name; -} piixDeviceTable[] = {{ PCI_ID_PIIX, "PIIX" }, - { PCI_ID_PIIX3, "PIIX3" }, - { PCI_ID_PIIX4, "PIIX4" }, - { PCI_ID_ICH, "ICH" }, - { PCI_ID_ICH0, "ICH0" }, - { PCI_ID_ICH2_M, "ICH2-M" }, - { PCI_ID_ICH2, "ICH2" }, - { PCI_ID_NONE, NULL }}; - -static const char * -PIIXGetName(UInt32 pciID) -{ - for (int i = 0; piixDeviceTable[i].name; i++) { - if (piixDeviceTable[i].CFID == pciID) - return piixDeviceTable[i].name; - } - return 0; -} - -static bool -PIIXVerifyID(UInt32 pciID) -{ - return (PIIXGetName(pciID) == 0) ? false : true; -} - -//-------------------------------------------------------------------------- -// A hack to modify our PCI nub to have two interrupts. -// This code was borrowed from the setupIntelPIC() function -// in iokit/Families/IOPCIBus/IOPCIBridge.cpp. -// -static void setupProviderInterrupts(IOPCIDevice * nub, long irq_p, long irq_s) -{ - OSArray * controller; - OSArray * specifier; - OSData * tmpData; - extern OSSymbol * gIntelPICName; - - do { - // Create the interrupt specifer array. - specifier = OSArray::withCapacity(2); - if (!specifier) - break; - - tmpData = OSData::withBytes(&irq_p, sizeof(irq_p)); - if (tmpData) { - specifier->setObject(tmpData); - tmpData->release(); - } - tmpData = OSData::withBytes(&irq_s, sizeof(irq_s)); - if (tmpData) { - specifier->setObject(tmpData); - tmpData->release(); - } - - controller = OSArray::withCapacity(2); - if (controller) { - controller->setObject(gIntelPICName); - controller->setObject(gIntelPICName); - - // Put the two arrays into the property table. - nub->setProperty(gIOInterruptControllersKey, controller); - controller->release(); - } - nub->setProperty(gIOInterruptSpecifiersKey, specifier); - specifier->release(); - - } while( false ); -} - -//-------------------------------------------------------------------------- -// A static member function that returns the IDE channel for the -// current driver instance, and also registers the interrupts in -// the IOPCIDevice nub. -// -int AppleATAPIIX::PIIXGetChannel(IOPCIDevice * provider) -{ - static bool primaryRegistered = false; - int rc; - extern OSSymbol * gIntelPICName; - - PIIX_LOCK; - - if (primaryRegistered == false) { - rc = PIIX_CHANNEL_PRIMARY; - primaryRegistered = true; - - // Is this necessary? - waitForService(resourceMatching(gIntelPICName)); - - setupProviderInterrupts(provider, PIIX_P_IRQ, PIIX_S_IRQ); - } - else { - rc = PIIX_CHANNEL_SECONDARY; - } - - PIIX_UNLOCK; - - if (rc == PIIX_CHANNEL_SECONDARY) IOSleep(20); - - return rc; -} - -//-------------------------------------------------------------------------- -// Private function: _getIDERanges -// -// Setup the variables that stores the start of the Command and Control -// block in I/O space. The variable 'channel' must have been previously -// set. These ISA I/O ranges are implicit and does not show up in PCI -// config space. -// -bool AppleATAPIIX::_getIDERanges(IOPCIDevice * provider) -{ - ioCmdRange = (channel == PIIX_CHANNEL_PRIMARY) ? - PIIX_P_CMD_ADDR : PIIX_S_CMD_ADDR; - - ioCtlRange = (channel == PIIX_CHANNEL_PRIMARY) ? - PIIX_P_CTL_ADDR : PIIX_S_CTL_ADDR; - - DLOG("%s: ioCmdRange - %04x\n", getName(), ioCmdRange); - DLOG("%s: ioCtlRange - %04x\n", getName(), ioCtlRange); - - return true; -} - -//-------------------------------------------------------------------------- -// Private function: _getBMRange -// -// Determine the start of the I/O mapped Bus-Master registers. -// This range is defined by PCI config space register PIIX_PCI_BMIBA. -// -bool AppleATAPIIX::_getBMRange(IOPCIDevice * provider) -{ - UInt32 bmiba; - - bmiba = provider->configRead32(PIIX_PCI_BMIBA); - if ((bmiba & PIIX_PCI_BMIBA_RTE) == 0) { - IOLog("%s: PCI memory range 0x%02x (0x%08lx) is not an I/O range\n", - getName(), PIIX_PCI_BMIBA, bmiba); - return false; - } - - bmiba &= PIIX_PCI_BMIBA_MASK; // get the address portion - - // If bmiba is zero, it is likely that the user has elected to - // turn off PCI IDE support in the BIOS. - // - if (bmiba == 0) - return false; - - if (channel == PIIX_CHANNEL_SECONDARY) - bmiba += PIIX_IO_BM_OFFSET; - - ioBMRange = (UInt16) bmiba; - - DLOG("%s: ioBMRange - %04x\n", getName(), ioBMRange); - - return true; -} - -//-------------------------------------------------------------------------- -// Private function: _resetTimings() -// -// Reset all timing registers to the slowest (most compatible) timing. -// UDMA modes are disabled. We take a lock to prevent the other IDE -// channel from modifying the shared PCI config space. -// -bool AppleATAPIIX::_resetTimings() -{ - union { - UInt32 b32; - struct { - UInt16 pri; - UInt16 sec; - } b16; - } timing; - - UInt32 udmaControl; - - PIIX_LOCK; - - timing.b32 = provider->configRead32(PIIX_PCI_IDETIM); - udmaControl = provider->configRead32(PIIX_PCI_UDMACTL); - - // Set slowest timing, and disable UDMA. Only modify the flags - // associated with the local channel. - // - switch (channel) { - case PIIX_CHANNEL_PRIMARY: - timing.b16.pri &= PIIX_PCI_IDETIM_IDE; - udmaControl &= ~(PIIX_PCI_UDMACTL_PSDE0 | PIIX_PCI_UDMACTL_PSDE1); - break; - - case PIIX_CHANNEL_SECONDARY: - timing.b16.sec &= PIIX_PCI_IDETIM_IDE; - udmaControl &= ~(PIIX_PCI_UDMACTL_SSDE0 | PIIX_PCI_UDMACTL_SSDE1); - break; - } - - provider->configWrite32(PIIX_PCI_UDMACTL, udmaControl); - provider->configWrite32(PIIX_PCI_IDETIM, timing.b32); - - // FIXME - // No support for ATA/66 or ATA/100 modes. Set this register - // to 0 (new in ICH2) to disable those faster timings. - // - provider->configWrite32(PIIX_PCI_IDECONFIG, 0); - - PIIX_UNLOCK; - - return true; -} - -//-------------------------------------------------------------------------- -// Private function: _allocatePRDTable() -// -// Allocate the physical region descriptor (PRD) table. The physical -// address of this table is stored in 'prdTablePhys'. Look at Intel -// documentation for the alignment requirements. -// -bool AppleATAPIIX::_allocatePRDTable() -{ - prdTable = (prdEntry_t *) IOMallocAligned(PRD_TABLE_SIZE, PAGE_SIZE); - if (!prdTable) - return false; - - prdTablePhys = (UInt32) pmap_extract(kernel_pmap, (vm_offset_t) prdTable); - - bzero(prdTable, PRD_TABLE_SIZE); - - return true; -} - -//-------------------------------------------------------------------------- -// Private function: _deallocatePRDTable() -// -void AppleATAPIIX::_deallocatePRDTable() -{ - IOFreeAligned(prdTable, PRD_TABLE_SIZE); - prdTable = NULL; - prdTablePhys = 0; -} - -//-------------------------------------------------------------------------- -// Function inherited from IOATAController. -// -// Configure the driver/controller. This is the first function called by -// our superclass, in its start() function, to initialize the controller -// hardware. -// -bool -AppleATAPIIX::configure(IOService * forProvider, - ATAControllerInfo * controllerInfo) -{ - UInt32 reg; - -// IOSleep(1000); - - provider = (IOPCIDevice *)forProvider->metaCast("IOPCIDevice"); - if (!provider) - return false; - - // Superclass performs an exclusive open on the provider, we close - // it to allow more than one instance of this driver to attach to - // the same PCI nub. We should maintain an non-exclusive open on - // the provider. - // - provider->close(this); - - // Determine the type of PIIX controller. Save the controller's - // PCI ID in pciCFID. - // - pciCFID = provider->configRead32(PIIX_PCI_CFID); - if (PIIXVerifyID(pciCFID) == false) { - IOLog("%s: Unknown PCI IDE controller (0x%08lx)\n", - getName(), - pciCFID); - return false; - } - - // Determine our IDE channel, primary or secondary. - // - channel = PIIXGetChannel(provider); - - _getIDERanges(provider); - - IOLog("%s: %s %s IDE controller, 0x%x, irq %d\n", - getName(), - (channel == PIIX_CHANNEL_PRIMARY) ? "Primary" : "Secondary", - PIIXGetName(pciCFID), - ioCmdRange, - (channel == PIIX_CHANNEL_PRIMARY) ? PIIX_P_IRQ : PIIX_S_IRQ); - - // Check the I/O Space Enable bit in the PCI command register. - // This is the master enable bit for the PIIX controller. - // Each IDE channel also has its own enable bit, which is - // checked later. - // - reg = provider->configRead32(PIIX_PCI_PCICMD); - if ((reg & PIIX_PCI_PCICMD_IOSE) == 0) { - IOLog("%s: PCI IDE controller is not enabled\n", getName()); - return false; - } - - // Set BME bit to enable bus-master. - // - if ((reg & PIIX_PCI_PCICMD_BME) == 0) { - reg |= PIIX_PCI_PCICMD_BME; - PIIX_LOCK; - provider->configWrite32(PIIX_PCI_PCICMD, reg); - PIIX_UNLOCK; - } - - // Fetch the corresponding primary/secondary IDETIM register and - // check the individual channel enable bit. - // - reg = provider->configRead32(PIIX_PCI_IDETIM); - if (channel == PIIX_CHANNEL_SECONDARY) - reg >>= 16; // PIIX_PCI_IDETIM + 2 for secondary channel - - if ((reg & PIIX_PCI_IDETIM_IDE) == 0) { - IOLog("%s: %s PCI IDE channel is not enabled\n", - getName(), - (channel == PIIX_CHANNEL_PRIMARY) ? "Primary" : "Secondary"); - return false; - } - - // Locate and add the I/O mapped bus-master registers to - // ioRange[] array. - // - if (_getBMRange(provider) == false) { - IOLog("%s: Bus master I/O range is invalid\n", getName()); - return false; - } - - // Allocate page-aligned memory for the PRD table. - // - if (_allocatePRDTable() == false) { - IOLog("%s: unable to allocate descriptor table\n", getName()); - return false; - } - - // Allocate a cursor object to generate the scatter-gather list - // for each transfer request. Maximum segment size is set to 64K. - // However, there is no way to indicate our requirement that each - // memory segment cannot cross a 64K boundary. We have to do this - // manually. - // - prdCursor = IOLittleMemoryCursor::withSpecification(64 * 1024, 0xffffffff); - if (prdCursor == 0) - return false; - - // Attach an interruptEventSource to handle HW interrupts. - // Must do this after PIIXGetChannel(), since thats where the - // provider's interrupt property is set by setupProviderInterrupts(). - - interruptEventSource = IOInterruptEventSource::interruptEventSource( - (OSObject *) this, - (IOInterruptEventAction) &AppleATAPIIX::interruptOccurred, - (IOService *) provider, - (channel == PIIX_CHANNEL_PRIMARY) ? 0 : 1); - if (interruptEventSource == 0) { - IOLog("%s: unable to create an IOInterruptEventSource object\n", - getName()); - return false; - } - - disableControllerInterrupts(); - - getWorkLoop()->addEventSource(interruptEventSource); - - // Revert to default (compatible) timing. - // - _resetTimings(); - - controllerInfo->maxDevicesSupported = 2; - controllerInfo->devicePrivateDataSize = 0; - controllerInfo->commandPrivateDataSize = 0; - controllerInfo->disableCancelCommands = false; - - - DLOG("AppleATAPIIX::%s() completed successfully\n", __FUNCTION__); - - return true; -} - -//-------------------------------------------------------------------------- -// -// -bool AppleATAPIIX::provideProtocols(enum ATAProtocol * protocolsSupported) -{ - return false; -} - -//-------------------------------------------------------------------------- -// -// -bool AppleATAPIIX::provideTimings(UInt32 * numTimings, - ATATiming * timingsSupported) -{ - return false; -} - -//-------------------------------------------------------------------------- -// Determine the timing selection based on the ATATiming structure given. -// -bool AppleATAPIIX::calculateTiming(UInt32 unit, ATATiming * pTiming) -{ - int i; - PIIXProtocol protocol = ataToPIIXProtocol(pTiming->timingProtocol); - - DLOG("AppleATAPIIX::%s() - unit:%ld protocol:%d minCycles:%ld\n", - __FUNCTION__, unit, protocol, pTiming->minDataCycle); - - CHECK_UNIT(unit); - - timings[unit].validTimings[protocol] = 0; - - switch (protocol) { - - case kPIIXProtocolPIO: - - for (i = 0; i < PIIXPIOTimingTableSize; i++) - { - if (PIIXPIOTimingTable[i].pioMode == _NVM_) - continue; - - if (PIIXPIOTimingTable[i].cycle < pTiming->minDataCycle) - break; - - timings[unit].validTimings[protocol] = i; - } - break; - - case kPIIXProtocolDMA: - - for (i = 0; i < PIIXPIOTimingTableSize; i++) - { - if (PIIXPIOTimingTable[i].mwDMAMode == _NVM_) - continue; - - if (PIIXPIOTimingTable[i].cycle < pTiming->minDataCycle) - break; - - timings[unit].validTimings[protocol] = i; - } - break; - - case kPIIXProtocolUDMA33: - - for (i = 0; i < PIIXUDMATimingTableSize; i++) - { - if (PIIXUDMATimingTable[i].strobe < pTiming->minDataCycle) - break; - - timings[unit].validTimings[protocol] = i; - } - break; - - default: - return false; - } - - timings[unit].validFlag |= (1 << protocol); - - return true; -} - -//-------------------------------------------------------------------------- -// Setup the timing register for the given timing protocol. -// -bool AppleATAPIIX::selectTiming(UInt32 unit, - ATATimingProtocol timingProtocol) -{ - bool ret = false; - UInt8 pciConfig[256]; - PIIXProtocol protocol = ataToPIIXProtocol(timingProtocol); - - DLOG("AppleATAPIIX::%s() - unit:%ld protocol:%d\n", - __FUNCTION__, unit, protocol); - - CHECK_UNIT(unit); - - PIIX_LOCK; - - do { - if (protocol >= kPIIXProtocolLast) - break; - - if (PIIX_PROTOCOL_IS_VALID(protocol) == 0) { - - // superclass error, calculateTiming() was not called - // before calling selectTiming(). - - IOLog("%s: timing protocol selected is invalid\n", getName()); - break; - } - - if (!_readPCIConfigSpace(pciConfig) || - !_selectTiming(unit, protocol, pciConfig) || - !_writePCIConfigSpace(pciConfig)) - break; - - ret = true; - } - while (0); - - PIIX_UNLOCK; - - return ret; -} - -//-------------------------------------------------------------------------- -// Setup the timing registers. -// -bool AppleATAPIIX::_selectTiming(UInt32 unit, - PIIXProtocol protocol, - UInt8 * pciConfig) -{ - UInt8 isp, rtc; - UInt8 index, dma, pio; - bool dmaActive; - bool pioActive; - bool useCompatiblePIOTiming = false; - bool ret = true; - UInt16 * idetim; - UInt8 * sidetim = (UInt8 *) &pciConfig[PIIX_PCI_SIDETIM]; - UInt8 * udmactl = (UInt8 *) &pciConfig[PIIX_PCI_UDMACTL]; - UInt16 * udmatim = (UInt16 *) &pciConfig[PIIX_PCI_UDMATIM]; - - idetim = (channel == PIIX_CHANNEL_PRIMARY) ? - (UInt16 *) &pciConfig[PIIX_PCI_IDETIM] : - (UInt16 *) &pciConfig[PIIX_PCI_IDETIM_S]; - - switch (protocol) { - case kPIIXProtocolUDMA66: - // Not yet! - return false; - - case kPIIXProtocolUDMA33: - if ((pciCFID == PCI_ID_PIIX) || (pciCFID == PCI_ID_PIIX3)) { - // Only PIIX4 (and newer devices) supports UDMA. - return false; - } - PIIX_DEACTIVATE_PROTOCOL(kPIIXProtocolDMA); - break; - - case kPIIXProtocolDMA: - PIIX_DEACTIVATE_PROTOCOL(kPIIXProtocolUDMA33); - break; - - case kPIIXProtocolPIO: - break; - - default: - IOLog("%s: PIIX protocol not handled (%d)\n", getName(), - protocol); - return false; - } - PIIX_ACTIVATE_PROTOCOL(protocol); - - - if (PIIX_PROTOCOL_IS_ACTIVE(kPIIXProtocolUDMA33)) { - - index = PIIX_GET_ACTIVE_TIMING(kPIIXProtocolUDMA33); - - if (unit == 0) { - if (channel == PIIX_CHANNEL_PRIMARY) { - *udmactl |= PIIX_PCI_UDMACTL_PSDE0; - SET_REG_FIELD(*udmatim, PIIX_PCI_UDMATIM_PCT0, - PIIXUDMATimingTable[index].bits); - } - else { - *udmactl |= PIIX_PCI_UDMACTL_SSDE0; - SET_REG_FIELD(*udmatim, PIIX_PCI_UDMATIM_SCT0, - PIIXUDMATimingTable[index].bits); - } - } - else { - if (channel == PIIX_CHANNEL_PRIMARY) { - *udmactl |= PIIX_PCI_UDMACTL_PSDE1; - SET_REG_FIELD(*udmatim, PIIX_PCI_UDMATIM_PCT1, - PIIXUDMATimingTable[index].bits); - } - else { - *udmactl |= PIIX_PCI_UDMACTL_SSDE1; - SET_REG_FIELD(*udmatim, PIIX_PCI_UDMATIM_SCT1, - PIIXUDMATimingTable[index].bits); - } - } - } - else { - if (unit == 0) { - if (channel == PIIX_CHANNEL_PRIMARY) { - *udmactl &= ~PIIX_PCI_UDMACTL_PSDE0; - } - else { - *udmactl &= ~PIIX_PCI_UDMACTL_SSDE0; - } - } - else { - if (channel == PIIX_CHANNEL_PRIMARY) { - *udmactl &= ~PIIX_PCI_UDMACTL_PSDE1; - } - else { - *udmactl &= ~PIIX_PCI_UDMACTL_SSDE1; - } - } - } - - dmaActive = PIIX_PROTOCOL_IS_ACTIVE(kPIIXProtocolDMA); - pioActive = PIIX_PROTOCOL_IS_ACTIVE(kPIIXProtocolPIO); - - if (dmaActive || pioActive) { - - dma = PIIX_GET_ACTIVE_TIMING(kPIIXProtocolDMA); - pio = PIIX_GET_ACTIVE_TIMING(kPIIXProtocolPIO); - - // Early PIIX devices does not have a slave timing register. - // Rather than switching timing registers whenever a new - // drive was selected, We program in a (slower) timing that - // is acceptable for both drive0 and drive1. - - if (pciCFID == PCI_ID_PIIX) { - - unit = (unit ^ 1) & 1; // unit <- other drive unit - - if (PIIX_PROTOCOL_IS_ACTIVE(kPIIXProtocolPIO)) { - if (!pioActive || - (PIIX_GET_ACTIVE_TIMING(kPIIXProtocolPIO) < pio)) { - pio = PIIX_GET_ACTIVE_TIMING(kPIIXProtocolPIO); - } - pioActive = true; - } - - if (PIIX_PROTOCOL_IS_ACTIVE(kPIIXProtocolDMA)) { - if (!dmaActive || - (PIIX_GET_ACTIVE_TIMING(kPIIXProtocolDMA) < dma)) { - dma = PIIX_GET_ACTIVE_TIMING(kPIIXProtocolDMA); - } - dmaActive = true; - } - - *idetim &= ~PIIX_PCI_IDETIM_SITRE; // disable slave timing - unit = 0; - } - else { - *idetim |= PIIX_PCI_IDETIM_SITRE; // enable slave timing - } - - // Pick an index to the PIIXPIOTimingTable[] for the new - // timing selection. - // - if (dmaActive && pioActive) { - - // Both PIO and DMA are active, select DMA timing to - // optimize DMA transfer. - - index = dma; // pick DMA timing - - if (pio < dma) - useCompatiblePIOTiming = true; - } - else if (dmaActive) { - index = dma; - } - else { - index = pio; - } - - isp = PIIX_CLK_TO_ISP(PIIXPIOTimingTable[index].isp); - rtc = PIIX_CLK_TO_RTC(PIIXPIOTimingTable[index].rtc); - - if (unit == 0) { - SET_REG_FIELD(*idetim, PIIX_PCI_IDETIM_ISP, isp); - SET_REG_FIELD(*idetim, PIIX_PCI_IDETIM_RTC, rtc); - if (useCompatiblePIOTiming) - *idetim |= PIIX_PCI_IDETIM_DTE0; - else - *idetim &= ~PIIX_PCI_IDETIM_DTE0; - - if (pciCFID == PCI_ID_PIIX) { - if (useCompatiblePIOTiming) - *idetim |= PIIX_PCI_IDETIM_DTE1; - else - *idetim &= ~PIIX_PCI_IDETIM_DTE1; - } - } - else { - if (channel == PIIX_CHANNEL_PRIMARY) { - SET_REG_FIELD(*sidetim, PIIX_PCI_SIDETIM_PISP1, isp); - SET_REG_FIELD(*sidetim, PIIX_PCI_SIDETIM_PRTC1, rtc); - } - else { - SET_REG_FIELD(*sidetim, PIIX_PCI_SIDETIM_SISP1, isp); - SET_REG_FIELD(*sidetim, PIIX_PCI_SIDETIM_SRTC1, rtc); - } - if (useCompatiblePIOTiming) - *idetim |= PIIX_PCI_IDETIM_DTE1; - else - *idetim &= ~PIIX_PCI_IDETIM_DTE1; - } - - *idetim |= (PIIX_PCI_IDETIM_TIME0 | - PIIX_PCI_IDETIM_PPE0 | - PIIX_PCI_IDETIM_IE0 | - PIIX_PCI_IDETIM_TIME1 | - PIIX_PCI_IDETIM_PPE1 | - PIIX_PCI_IDETIM_IE1); - } - -#ifdef DEBUG_XXX - IOLog("\n%s: %s channel\n", getName(), - (channel == PIIX_CHANNEL_PRIMARY) ? "Primary" : "Secondary"); - IOLog("%s: IDETIM : %04x\n", getName(), *idetim); - IOLog("%s: SIDETIM: %02x\n", getName(), *sidetim); - IOLog("%s: UDMACTL: %02x\n", getName(), *udmactl); - IOLog("%s: UDMATIM: %04x\n", getName(), *udmatim); - IOLog("%s: Active : %04lx\n", getName(), timings[unit].activeFlag); - IOLog("%s: Valid : %04lx\n", getName(), timings[unit].validFlag); - IOLog("%s: PIO:%d DMA:%d UDMA:%d\n\n", getName(), - timings[unit].activeTimings[kPIIXProtocolPIO], - timings[unit].activeTimings[kPIIXProtocolDMA], - timings[unit].activeTimings[kPIIXProtocolUDMA33]); -#endif /* DEBUG */ - - return ret; -} - -//-------------------------------------------------------------------------- -// Setup the descriptor table to perform the transfer indicated by the -// IOMemoryDescriptor in the IOATACommand object provided. -// -bool AppleATAPIIX::programDma(IOATAStandardCommand * cmd) -{ - IOPhysicalSegment physSeg; - IOByteCount offset = 0; - IOMemoryDescriptor * memDesc; - prdEntry_t * prd = prdTable; - UInt32 startSeg; - UInt32 endSeg; - UInt32 partialCount; - UInt32 bytesLeft; - - cmd->getPointers(&memDesc, &dmaReqLength, &dmaIsWrite); - - if (dmaReqLength == 0) - return true; - - bytesLeft = dmaReqLength; - - // Setup the PRD entries in the descriptor table in memory. - // - for (UInt32 i = 0; i < (PRD_ENTRIES - 1); i++, prd++) - { - if (prdCursor->getPhysicalSegments(memDesc, offset, &physSeg, 1) != 1) - break; - - startSeg = (physSeg.location & ~0xffff); - endSeg = (physSeg.location + physSeg.length - 1) & ~0xffff; - - prd->base = physSeg.location; - prd->flags = 0; - - if (startSeg == endSeg) { - prd->count = PRD_COUNT(physSeg.length); - } - else { - partialCount = (-physSeg.location & 0xffff); - prd->count = PRD_COUNT(partialCount); - prd++; - i++; - prd->base = physSeg.location + partialCount; - prd->count = physSeg.length - partialCount; - prd->flags = 0; - } - - bytesLeft -= physSeg.length; - offset += physSeg.length; - } - if (bytesLeft != 0) - return false; - - // Set the 'end-of-table' bit on the last PRD entry. - // - prd--; - prd->flags = PRD_FLAG_EOT; - - /* - * Provide the starting address of the PRD table by loading the - * PRD Table Pointer Register. - */ - outl(IOREG(BMIDTPX), prdTablePhys); - - return true; -} - -//-------------------------------------------------------------------------- -// Start the DMA engine. -// -bool AppleATAPIIX::startDma(IOATAStandardCommand * cmd) -{ - /* - * Clear interrupt and error bits in the Status Register. - */ - outb(IOREG(BMISX), PIIX_IO_BMISX_ERROR | - PIIX_IO_BMISX_IDEINTS | - PIIX_IO_BMISX_DMA0CAP | - PIIX_IO_BMISX_DMA1CAP); - - /* - * Engage the bus master by writing 1 to the start bit in the - * Command Register. Also set the RWCON bit for the direction - * of the data transfer. - */ - outb(IOREG(BMICX), (dmaIsWrite ? 0 : PIIX_IO_BMICX_RWCON) | - PIIX_IO_BMICX_SSBM); - - return true; -} - -//-------------------------------------------------------------------------- -// Stop the DMA engine. -// -bool AppleATAPIIX::stopDma(IOATAStandardCommand * cmd, UInt32 * transferCount) -{ - UInt8 bmisx; - - *transferCount = 0; - - if (dmaReqLength == 0) - return true; - - outb(IOREG(BMICX), 0); // stop the bus-master - - bmisx = inb(IOREG(BMISX)); - - if ((bmisx & PIIX_IO_BMISX_STATUS) != PIIX_IO_BMISX_IDEINTS) { - IOLog("AppleATAPIIX::%s() DMA error (0x%02x)\n", __FUNCTION__, bmisx); - return false; - } - - *transferCount = dmaReqLength; - - return true; -} - -//-------------------------------------------------------------------------- -// Perform a write to the ATA block registers. -// -void AppleATAPIIX::writeATAReg(UInt32 regIndex, UInt32 regValue) -{ - if (regIndex == 0) { - outw(ioCmdRange, (UInt16) regValue); - } - else if (regIndex < kATARegDeviceControl) { - outb(ioCmdRange + regIndex, (UInt8) regValue); - } - else { - outb(ioCtlRange + regIndex - kATARegDeviceControl + 2, - (UInt8) regValue); - } -} - -//-------------------------------------------------------------------------- -// Perform a read from the ATA block registers. -// -UInt32 AppleATAPIIX::readATAReg( UInt32 regIndex ) -{ - if (regIndex == 0) { - return inw(ioCmdRange); - } - else if (regIndex < kATARegDeviceControl) { - return inb(ioCmdRange + regIndex); - } - return inb(ioCtlRange + regIndex - kATARegDeviceControl + 2); -} - -//-------------------------------------------------------------------------- -// Frees the drivers instance. Make sure all objects allocated during -// our initialization are freed. -// -void AppleATAPIIX::free() -{ - if (interruptEventSource) { - interruptEventSource->disable(); - interruptEventSource->release(); - } - - if (prdCursor) - prdCursor->release(); - - if (prdTable != 0) - _deallocatePRDTable(); - - return super::free(); -} - -//-------------------------------------------------------------------------- -// This function is called when our interruptEventSource receives an -// interrupt. Simply pass the action to our superclass to advance its -// state machine. -// -void AppleATAPIIX::interruptOccurred() -{ - super::interruptOccurred(); -} - -//-------------------------------------------------------------------------- -// This function is called by our superclass to disable controller -// interrupts. -// -void AppleATAPIIX::disableControllerInterrupts() -{ - interruptEventSource->disable(); -} - -//-------------------------------------------------------------------------- -// This function is called by our superclass to enable controller -// interrupts. -// -void AppleATAPIIX::enableControllerInterrupts() -{ - interruptEventSource->enable(); -} - -//-------------------------------------------------------------------------- -// Private function: _readPCIConfigSpace -// -// Read the entire PCI config space and stores it to the buffer -// pointed by 'configSpace'. -// -bool AppleATAPIIX::_readPCIConfigSpace(UInt8 * configSpace) -{ - UInt32 * dwordPtr = (UInt32 *) configSpace; - - for (int i = 0; i < 64; i++, dwordPtr++) - *dwordPtr = provider->configRead32(i * 4); - - return true; -} - -//-------------------------------------------------------------------------- -// Private function: _writePCIConfigSpace -// -// Write the entire PCI config space from the buffer pointed -// by 'configSpace'. -// -bool AppleATAPIIX::_writePCIConfigSpace(UInt8 * configSpace) -{ - UInt32 * dwordPtr = (UInt32 *) configSpace; - - for (int i = 0; i < 64; i++, dwordPtr++) - provider->configWrite32(i * 4, *dwordPtr); - - return true; -} diff --git a/iokit/Drivers/ata/drvApplePIIXATA/AppleATAPIIX.h b/iokit/Drivers/ata/drvApplePIIXATA/AppleATAPIIX.h deleted file mode 100644 index c5b0241e4..000000000 --- a/iokit/Drivers/ata/drvApplePIIXATA/AppleATAPIIX.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * AppleATAPIIX.h - ATA controller driver for Intel PIIX/PIIX3/PIIX4. - * - * HISTORY - * - */ - -#ifndef _APPLEATAPIIX_H -#define _APPLEATAPIIX_H - -#include -#include -#include -#include - -#include -#include "AppleATAPIIXRegs.h" -#include "AppleATAPIIXTiming.h" - -class AppleATAPIIX : public IOATAStandardDriver -{ - OSDeclareDefaultStructors( AppleATAPIIX ) - -protected: - IOPCIDevice * provider; // our provider - UInt32 pciCFID; // our PCI vendor/device ID - UInt32 channel; // IDE channel - UInt16 ioCmdRange; // command block - UInt16 ioCtlRange; // control block - UInt16 ioBMRange; // bus-master register block - UInt32 dmaReqLength; // transaction state - bool dmaIsWrite; // transaction state - prdEntry_t * prdTable; // physical region descriptor table - IOPhysicalAddress prdTablePhys; // physical address of prdTable - PIIXSelectedTimings timings[2]; // drive0 and drive1 timings - IOLittleMemoryCursor * prdCursor; // request -> scatter-gather list - IOTimerEventSource * timerEventSource; - IOInterruptEventSource * interruptEventSource; - - /* - * Internal (private) functions. - */ - bool _getIDERanges(IOPCIDevice * provider); - bool _getBMRange(IOPCIDevice * provider); - bool _allocatePRDTable(); - void _deallocatePRDTable(); - bool _resetTimings(); - bool _readPCIConfigSpace(UInt8 * configSpace); - bool _writePCIConfigSpace(UInt8 * configSpace); - bool _selectTiming(UInt32 unit, - PIIXProtocol timingProtocol, - UInt8 * pciConfig); - -public: - /* - * Class initializer. - */ - static void initialize(); - - /* - * Returns the IDE channel for the current driver instance. - */ - static int PIIXGetChannel(IOPCIDevice * provider); - - /* - * Functions defined by our superclass that we must override. - */ - void writeATAReg(UInt32 regIndex, UInt32 regValue); - - UInt32 readATAReg(UInt32 regIndex); - - void free(); - - bool configure(IOService * forProvider, - ATAControllerInfo * controllerInfo); - - bool createWorkLoop(IOWorkLoop ** workLoop); - - bool provideProtocols(enum ATAProtocol * protocolsSupported); - - bool provideTimings(UInt32 * numTimings, - ATATiming * timingsSupported); - - bool calculateTiming(UInt32 deviceNum, ATATiming * pTiming); - - bool selectTiming(UInt32 unitNum, - ATATimingProtocol timingProtocol); - - void disableControllerInterrupts(); - void enableControllerInterrupts(); - - void ataTimer(IOTimerEventSource * sender); - - /* - * Functions that must be implemented by a bus-master controller. - */ - bool programDma(IOATAStandardCommand * cmd); - bool startDma(IOATAStandardCommand * cmd); - bool stopDma(IOATAStandardCommand * cmd, UInt32 * transferCount); - - /* - * Miscellaneous functions. - */ - void interruptOccurred(); -}; - -#endif /* !_APPLEATAPIIX_H */ diff --git a/iokit/Drivers/ata/drvApplePIIXATA/AppleATAPIIXRegs.h b/iokit/Drivers/ata/drvApplePIIXATA/AppleATAPIIXRegs.h deleted file mode 100644 index 6f0ca85c5..000000000 --- a/iokit/Drivers/ata/drvApplePIIXATA/AppleATAPIIXRegs.h +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * Intel PIIX/PIIX3/PIIX4 PCI IDE controller. - * PIIX = PCI-ISA-IDE-Xelerator. (also USB on newer controllers) - * - * Notes: - * - * PIIX introduced in the "Triton" chipset. - * PIIX3 supports different timings for Master/Slave devices on both channels. - * PIIX4 adds support for Ultra DMA/33. - * - * Be sure to download and read the PIIX errata from Intel's web site at - * developer.intel.com. - * - * HISTORY: - * - */ - -#ifndef _APPLEATAPIIXREGS_H -#define _APPLEATAPIIXREGS_H - -/* - * PCI ID for supported PIIX variants. - */ -#define PCI_ID_PIIX 0x12308086 -#define PCI_ID_PIIX3 0x70108086 -#define PCI_ID_PIIX4 0x71118086 -#define PCI_ID_ICH 0x24118086 -#define PCI_ID_ICH0 0x24218086 -#define PCI_ID_ICH2_M 0x244a8086 -#define PCI_ID_ICH2 0x244b8086 -#define PCI_ID_NONE 0xffffffff - -/* - * Decoded port addresses. Seems to be hardcoded and it does not - * show up in the PCI configuration space memory ranges. - */ -#define PIIX_P_CMD_ADDR 0x1f0 -#define PIIX_P_CTL_ADDR 0x3f4 -#define PIIX_S_CMD_ADDR 0x170 -#define PIIX_S_CTL_ADDR 0x374 -#define PIIX_CMD_SIZE 8 -#define PIIX_CTL_SIZE 4 - -/* - * IRQ assignment. - */ -#define PIIX_P_IRQ 14 -#define PIIX_S_IRQ 15 - -/* - * PIIX has two IDE channels. - */ -#define PIIX_CHANNEL_PRIMARY 0 -#define PIIX_CHANNEL_SECONDARY 1 - -/* - * PIIX PCI config space registers. - * Register size (bits) in parenthesis. - */ -#define PIIX_PCI_CFID 0x00 - -#define PIIX_PCI_PCICMD 0x04 // (16) PCI command register -#define PIIX_PCI_PCICMD_IOSE 0x01 // I/O space enable -#define PIIX_PCI_PCICMD_BME 0x04 // bus-master enable - -#define PIIX_PCI_PCISTS 0x06 // (16) PCI device status register -#define PIIX_PCI_RID 0x08 // (8) Revision ID register -#define PIIX_PCI_CLASSC 0x09 // (24) Class code register -#define PIIX_PCI_MLT 0x0d // (8) Master latency timer register -#define PIIX_PCI_HEDT 0x0e // (8) Header type register - -#define PIIX_PCI_BMIBA 0x20 // (32) Bus-Master base address -#define PIIX_PCI_BMIBA_RTE 0x01 // resource type indicator (I/O) -#define PIIX_PCI_BMIBA_MASK 0xfff0 // base address mask - -#define PIIX_PCI_IDETIM 0x40 // (16) IDE timing registers (pri) -#define PIIX_PCI_IDETIM_S 0x42 // (16) IDE timing registers (sec) -#define PIIX_PCI_SIDETIM 0x44 // (8) Slave IDE timing register -#define PIIX_PCI_UDMACTL 0x48 // (8) Ultra DMA/33 control register -#define PIIX_PCI_UDMATIM 0x4a // (16) Ultra DMA/33 timing register - -#define PIIX_PCI_IDECONFIG 0x54 // (32) IDE I/O Config register - -/* - * PIIX PCI configuration space register definition. - * - * PIIX_IDETIM - IDE timing register. - * - * Address: - * 0x40:0x41 - Primary channel - * 0x42:0x43 - Secondary channel - */ -#define PIIX_PCI_IDETIM_IDE 0x8000 // IDE decode enable -#define PIIX_PCI_IDETIM_SITRE 0x4000 // slave timing register enable - -#define PIIX_PCI_IDETIM_ISP_MASK 0x3000 -#define PIIX_PCI_IDETIM_ISP_SHIFT 12 -#define PIIX_PCI_IDETIM_ISP_5 0x0000 // IORDY sample point -#define PIIX_PCI_IDETIM_ISP_4 0x1000 // (PCI clocks) -#define PIIX_PCI_IDETIM_ISP_3 0x2000 -#define PIIX_PCI_IDETIM_ISP_2 0x3000 - -#define PIIX_PCI_IDETIM_RTC_MASK 0x0300 -#define PIIX_PCI_IDETIM_RTC_SHIFT 8 -#define PIIX_PCI_IDETIM_RTC_4 0x0000 // receovery time (PCI clocks) -#define PIIX_PCI_IDETIM_RTC_3 0x0100 -#define PIIX_PCI_IDETIM_RTC_2 0x0200 -#define PIIX_PCI_IDETIM_RTC_1 0x0300 - -#define PIIX_PCI_IDETIM_DTE1 0x0080 // DMA timing enable only -#define PIIX_PCI_IDETIM_PPE1 0x0040 // prefetch and posting enabled -#define PIIX_PCI_IDETIM_IE1 0x0020 // IORDY sample point enable -#define PIIX_PCI_IDETIM_TIME1 0x0010 // fast timing enable -#define PIIX_PCI_IDETIM_DTE0 0x0008 // same as above for drive 0 -#define PIIX_PCI_IDETIM_PPE0 0x0004 -#define PIIX_PCI_IDETIM_IE0 0x0002 -#define PIIX_PCI_IDETIM_TIME0 0x0001 - -/* - * PIIX PCI configuration space register definition. - * - * PIIX_SIDETIM - Slave IDE timing register. - * - * Address: 0x44 - */ -#define PIIX_PCI_SIDETIM_SISP1_MASK 0xc0 -#define PIIX_PCI_SIDETIM_SISP1_SHIFT 6 -#define PIIX_PCI_SIDETIM_SRTC1_MASK 0x30 -#define PIIX_PCI_SIDETIM_SRTC1_SHIFT 4 -#define PIIX_PCI_SIDETIM_PISP1_MASK 0x0c -#define PIIX_PCI_SIDETIM_PISP1_SHIFT 2 -#define PIIX_PCI_SIDETIM_PRTC1_MASK 0x03 -#define PIIX_PCI_SIDETIM_PRTC1_SHIFT 0 - -/* - * PIIX PCI configuration space register definition. - * - * PIIX_UDMACTL - Ultra DMA/33 control register - * - * Address: 0x48 - */ -#define PIIX_PCI_UDMACTL_SSDE1 0x08 // Enable UDMA/33 Sec/Drive1 -#define PIIX_PCI_UDMACTL_SSDE0 0x04 // Enable UDMA/33 Sec/Drive0 -#define PIIX_PCI_UDMACTL_PSDE1 0x02 // Enable UDMA/33 Pri/Drive1 -#define PIIX_PCI_UDMACTL_PSDE0 0x01 // Enable UDMA/33 Pri/Drive0 - -/* - * PIIX PCI configuration space register definition. - * - * PIIX_UDMATIM - Ultra DMA/33 timing register - * - * Address: 0x4a-0x4b - */ -#define PIIX_PCI_UDMATIM_PCT0_MASK 0x0003 -#define PIIX_PCI_UDMATIM_PCT0_SHIFT 0 -#define PIIX_PCI_UDMATIM_PCT1_MASK 0x0030 -#define PIIX_PCI_UDMATIM_PCT1_SHIFT 4 -#define PIIX_PCI_UDMATIM_SCT0_MASK 0x0300 -#define PIIX_PCI_UDMATIM_SCT0_SHIFT 8 -#define PIIX_PCI_UDMATIM_SCT1_MASK 0x3000 -#define PIIX_PCI_UDMATIM_SCT1_SHIFT 12 - - -/* - * PIIX IO space register offsets. Base address is set in PIIX_PCI_BMIBA. - * Register size (bits) in parenthesis. - * - * Note: - * For the primary channel, the base address is stored in PIIX_PCI_BMIBA. - * For the secondary channel, an offset (PIIX_IO_BM_OFFSET) is added to - * the value stored in PIIX_PCI_BMIBA. - */ -#define PIIX_IO_BMICX 0x00 // (8) Bus master command register -#define PIIX_IO_BMISX 0x02 // (8) Bus master status register -#define PIIX_IO_BMIDTPX 0x04 // (32) Descriptor table register - -#define PIIX_IO_BM_OFFSET 0x08 // offset to sec channel registers -#define PIIX_IO_BM_SIZE 0x08 // BM registers size for each channel -#define PIIX_IO_BM_MASK 0xfff0 // BMIBA mask to get I/O base address - -/* - * PIIX IO space register definition. - * - * BMICX - Bus master IDE command register - */ -#define PIIX_IO_BMICX_SSBM 0x01 // 1=Start, 0=Stop -#define PIIX_IO_BMICX_RWCON 0x08 // 0=Read, 1=Write - -/* - * PIIX IO space register definition. - * - * PIIX_BMISX - Bus master IDE status register - */ -#define PIIX_IO_BMISX_DMA1CAP 0x40 // drive 1 is capable of DMA transfers -#define PIIX_IO_BMISX_DMA0CAP 0x20 // drive 0 is capable of DMA transfers -#define PIIX_IO_BMISX_IDEINTS 0x04 // IDE device asserted its interrupt -#define PIIX_IO_BMISX_ERROR 0x02 // DMA error (cleared by writing a 1) -#define PIIX_IO_BMISX_BMIDEA 0x01 // bus master active bit - -#define PIIX_IO_BMISX_STATUS (PIIX_IO_BMISX_IDEINTS | \ - PIIX_IO_BMISX_ERROR | \ - PIIX_IO_BMISX_BMIDEA) - -/* - * PIIX Bus Master alignment/boundary requirements. - * - * Intel nomemclature: - * WORD - 16-bit - * DWord - 32-bit - */ -#define PIIX_DT_ALIGN 4 // descriptor table must be DWord aligned. -#define PIIX_DT_BOUND (4 * 1024) // cannot cross 4K boundary. (or 64K ?) - -#define PIIX_BUF_ALIGN 2 // memory buffer must be word aligned. -#define PIIX_BUF_BOUND (64 * 1024) // cannot cross 64K boundary. -#define PIIX_BUF_LIMIT (64 * 1024) // limited to 64K in size - -/* - * PIIX Bus Master Physical Region Descriptor (PRD). - */ -typedef struct { - UInt32 base; // base address - UInt16 count; // byte count - UInt16 flags; // flag bits -} prdEntry_t; - -#define PRD_FLAG_EOT 0x8000 - -#define PRD_COUNT(x) (((x) == PIIX_BUF_LIMIT) ? 0 : (x)) -#define PRD_TABLE_SIZE PAGE_SIZE -#define PRD_ENTRIES (PRD_TABLE_SIZE / sizeof(prdEntry_t)) - -/* - * PIIX Register setting macro. - */ -#define SET_REG_FIELD(reg, field, val) \ -{ \ - reg &= ~(field ## _MASK); \ - reg |= (((val) << field ## _SHIFT) & \ - field ## _MASK); \ -} - -/* - * Convert the "isp" and "rtc" fields in PIIX_IDETIM register from - * PCI clocks to their respective values, and vice-versa. - */ -#define PIIX_CLK_TO_ISP(x) (5 - (x)) -#define PIIX_ISP_TO_CLK(x) PIIX_CLK_TO_ISP(x) -#define PIIX_CLK_TO_RTC(x) (4 - (x)) -#define PIIX_RTC_TO_CLK(x) PIIX_CLK_TO_RTC(x) - -#endif /* !_APPLEATAPIIXREGS_H */ diff --git a/iokit/Drivers/ata/drvApplePIIXATA/AppleATAPIIXTiming.h b/iokit/Drivers/ata/drvApplePIIXATA/AppleATAPIIXTiming.h deleted file mode 100644 index b2ed7dd4d..000000000 --- a/iokit/Drivers/ata/drvApplePIIXATA/AppleATAPIIXTiming.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * AppleATAPIIXTiming.h - Timing tables. - * - * HISTORY - * - */ - -#ifndef _APPLEATAPIIXTIMING_H -#define _APPLEATAPIIXTIMING_H - -/* - * Supported transfer protocols. Entries in this table must map to the - * entries in ATATimingProtocol table. - */ -typedef enum { - kPIIXProtocolPIO = 0, - kPIIXProtocolDMA, - kPIIXProtocolUDMA33, - kPIIXProtocolUDMA66, - kPIIXProtocolLast -} PIIXProtocol; - -/* - * PIIX PIO/DMA timing table. - */ -typedef struct { - UInt8 pioMode; // PIO mode - UInt8 swDMAMode; // single-word DMA mode (obsolete) - UInt8 mwDMAMode; // multiword DMA mode - UInt8 isp; // IORDY sample point in PCI clocks - UInt8 rtc; // Recovery time in PCI clocks - UInt16 cycle; // cycle time in ns -} PIIXTiming; - -#define _NVM_ 0xff // not a valid mode - -static const -PIIXTiming PIIXPIOTimingTable[] = { -/* PIO SW MW ISP RTC CYCLE (ns) */ - {0, 0, 0, 5, 4, 600}, - {1, 1, _NVM_, 5, 4, 600}, - {2, 2, _NVM_, 4, 4, 240}, - {3, _NVM_, 1, 3, 3, 180}, - {4, _NVM_, 2, 3, 1, 120}, - {5, _NVM_, 2, 3, 1, 120}, -}; - -static const UInt8 PIIXPIOTimingTableSize = sizeof(PIIXPIOTimingTable) / - sizeof(PIIXPIOTimingTable[0]); - -/* - * PIIX Ultra-DMA/33 timing table. - */ -typedef struct { - UInt8 mode; // mode number - UInt8 ct; // cycle time in PCI clocks - UInt8 rp; // Ready to Pause time in PCI clocks - UInt8 bits; // register bit setting - UInt16 strobe; // strobe period (cycle) in ns -} PIIXUDMATiming; - -static const -PIIXUDMATiming PIIXUDMATimingTable[] = { -/* MODE CT RP BITS STROBE/CYCLE (ns) */ - {0, 4, 6, 0, 120}, - {1, 3, 5, 1, 90}, - {2, 2, 4, 2, 60}, -}; - -static const UInt8 -PIIXUDMATimingTableSize = sizeof(PIIXUDMATimingTable) / - sizeof(PIIXUDMATimingTable[0]); - -/* - * For each drive, the following table will store the chosen timings - * for each supported protocol. - */ -typedef struct { - UInt8 activeTimings[kPIIXProtocolLast]; // selected timings - UInt8 validTimings[kPIIXProtocolLast]; // calculated timings - UInt32 validFlag; - UInt32 activeFlag; -} PIIXSelectedTimings; - -/* - * Convert from ATATimingProtocol to PIIXProtocol. - */ -inline PIIXProtocol ataToPIIXProtocol(ATATimingProtocol timingProtocol) -{ - int piixProtocol = kPIIXProtocolPIO; - int ataProtocol = timingProtocol; - - while (ataProtocol != 1) { - ataProtocol >>= 1; piixProtocol++; - } - return ((PIIXProtocol) piixProtocol); -} - -/* - * Misc macros to get information from the PIIXSelectedTimings table. - */ -#define PIIX_ACTIVATE_PROTOCOL(p) { \ - timings[unit].activeTimings[p] = timings[unit].validTimings[p]; \ - timings[unit].activeFlag |= (1 << (p)); \ -} - -#define PIIX_DEACTIVATE_PROTOCOL(p) { \ - timings[unit].activeFlag &= ~(1 << (p)); \ -} - -#define PIIX_GET_ACTIVE_TIMING(p) (timings[unit].activeTimings[p]) - -#define PIIX_PROTOCOL_IS_ACTIVE(p) ((bool) \ - (timings[unit].activeFlag & (1 << (p)))) - -#define PIIX_PROTOCOL_IS_VALID(p) ((bool) \ - (timings[unit].validFlag & (1 << (p)))) - -#endif /* !_APPLEATAPIIXTIMING_H */ diff --git a/iokit/Drivers/ata/drvAppleUltra33ATA/AppleUltra33ATA.cpp b/iokit/Drivers/ata/drvAppleUltra33ATA/AppleUltra33ATA.cpp deleted file mode 100644 index c1ebfce56..000000000 --- a/iokit/Drivers/ata/drvAppleUltra33ATA/AppleUltra33ATA.cpp +++ /dev/null @@ -1,747 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * AppleUltra33ATA.cpp - * - */ -#include "AppleUltra33ATA.h" - -#include - -#undef super -#define super IOATAStandardDriver - -extern pmap_t kernel_pmap; - -OSDefineMetaClassAndStructors( AppleUltra33ATA, IOATAStandardDriver ) - - -static struct -{ - UInt32 minDataAccess; - UInt32 minDataCycle; -} pioModes[] = -{ - { 165, 600 }, /* Mode 0 */ - { 125, 383 }, /* 1 */ - { 100, 240 }, /* 2 */ - { 80, 180 }, /* 3 */ - { 70, 120 } /* 4 */ -}; - - -/* - * - * - */ -bool AppleUltra33ATA::configure( IOService *forProvider, ATAControllerInfo *controllerInfo ) -{ - - provider = (IOPCIDevice *)forProvider; - - busNum = 0; - - ioMapATA[0] = provider->mapDeviceMemoryWithRegister( 0x10 + busNum * 8 + 0 ); - if ( ioMapATA[0] == NULL ) return false; - ioBaseATA[0] = (volatile UInt32 *)ioMapATA[0]->getVirtualAddress(); - - ioMapATA[1] = provider->mapDeviceMemoryWithRegister( 0x10 + busNum * 8 + 4 ); - if ( ioMapATA[1] == NULL ) return false; - ioBaseATA[1] = (volatile UInt32 *)ioMapATA[1]->getVirtualAddress(); - - pciWriteLong( 0x04, 0x05 ); - - dmaDescriptors = (Ultra646Descriptor *)kalloc(page_size); - if ( dmaDescriptors == 0 ) - { - return false; - } - - dmaDescriptorsPhys = (UInt32) pmap_extract(kernel_pmap, (vm_offset_t) dmaDescriptors); - - if ( (UInt32)dmaDescriptors & (page_size - 1) ) - { - IOLog("AppleUltra33ATA::%s() - DMA Descriptor memory not page aligned!!", __FUNCTION__); - return false; - } - - bzero( dmaDescriptors, page_size ); - - numDescriptors = page_size/sizeof(Ultra646Descriptor); - - dmaMemoryCursor = IOBigMemoryCursor::withSpecification( 64*1024-2, 0xffffffff ); - if ( dmaMemoryCursor == NULL ) - { - return false; - } - - bitBucketAddr = IOMalloc(32); - if ( bitBucketAddr == 0 ) - { - return false; - } - bitBucketAddrPhys = (UInt32) pmap_extract(kernel_pmap, (vm_offset_t) (((UInt32)bitBucketAddr + 0xf) & ~0x0f)); - - interruptEventSource = IOInterruptEventSource::interruptEventSource( (OSObject *) this, - (IOInterruptEventAction) &AppleUltra33ATA::interruptOccurred, - (IOService *) provider, - (int) 0 ); - - if ( interruptEventSource == NULL ) - { - return false; - } - - disableControllerInterrupts(); - - getWorkLoop()->addEventSource( interruptEventSource ); - - controllerInfo->maxDevicesSupported = 2; - controllerInfo->devicePrivateDataSize = 0; - controllerInfo->commandPrivateDataSize = 0; - controllerInfo->disableCancelCommands = false; - - return true; -} - -/* - * - * - */ -bool AppleUltra33ATA::calculateTiming( UInt32 unit, ATATiming *pTiming ) -{ - bool rc = false; - - ideTimingRegs[unit].arttimReg = 0x40; - ideTimingRegs[unit].cmdtimReg = 0xA9; - - switch ( pTiming->timingProtocol ) - { - case kATATimingPIO: - rc = calculatePIOTiming( unit, pTiming ); - break; - - case kATATimingDMA: - rc = calculateDMATiming( unit, pTiming ); - break; - - case kATATimingUltraDMA33: - rc = calculateUltraDMATiming( unit, pTiming ); - break; - - - default: - ; - } - - return rc; -} - -/* - * - * - */ -bool AppleUltra33ATA::calculatePIOTiming( UInt32 unit, ATATiming *pTiming ) -{ - UInt32 accessTime; - UInt32 drwActClks, drwRecClks; - UInt32 drwActTime, drwRecTime; - - accessTime = pioModes[pTiming->mode].minDataAccess; - - drwActClks = accessTime / IDE_SYSCLK_NS; - drwActClks += (accessTime % IDE_SYSCLK_NS) ? 1 : 0; - drwActTime = drwActClks * IDE_SYSCLK_NS; - - drwRecTime = pioModes[pTiming->mode].minDataCycle - drwActTime; - drwRecClks = drwRecTime / IDE_SYSCLK_NS; - drwRecClks += (drwRecTime % IDE_SYSCLK_NS) ? 1 : 0; - - if ( drwRecClks >= 16 ) - drwRecClks = 1; - else if ( drwRecClks <= 1 ) - drwRecClks = 16; - - ideTimingRegs[unit].drwtimRegPIO = ((drwActClks & 0x0f) << 4) | ((drwRecClks-1) & 0x0f); - - return true; -} - - -/* - * - * - */ -bool AppleUltra33ATA::calculateDMATiming( UInt32 unit, ATATiming *pTiming ) -{ - UInt32 accessTime; - UInt32 drwActClks, drwRecClks; - UInt32 drwActTime, drwRecTime; - - ideTimingRegs[unit].udidetcrReg = 0; - - accessTime = pTiming->minDataAccess; - - drwActClks = accessTime / IDE_SYSCLK_NS; - drwActClks += (accessTime % IDE_SYSCLK_NS) ? 1 : 0; - drwActTime = drwActClks * IDE_SYSCLK_NS; - - drwRecTime = pTiming->minDataCycle - drwActTime; - drwRecClks = drwRecTime / IDE_SYSCLK_NS; - drwRecClks += (drwRecTime % IDE_SYSCLK_NS) ? 1 : 0; - - if ( drwRecClks >= 16 ) - drwRecClks = 1; - else if ( drwRecClks <= 1 ) - drwRecClks = 16; - - ideTimingRegs[unit].drwtimRegDMA = ((drwActClks & 0x0f) << 4) | ((drwRecClks-1) & 0x0f); - - return true; -} - -/* - * - * - */ -bool AppleUltra33ATA::calculateUltraDMATiming( UInt32 unit, ATATiming *pTiming ) -{ - UInt32 cycleClks; - UInt32 cycleTime; - - cycleTime = pTiming->minDataCycle; - - cycleClks = cycleTime / IDE_SYSCLK_NS; - cycleClks += (cycleTime % IDE_SYSCLK_NS) ? 1 : 0; - - ideTimingRegs[unit].udidetcrReg = (0x01 << unit) | ((cycleClks-1) << ((!unit) ? 4 : 6)) ; - - return true; -} - -/* - * - * - */ -void AppleUltra33ATA::newDeviceSelected( IOATADevice *newDevice ) -{ -} - - -/* - * - * - */ -bool AppleUltra33ATA::selectTiming( UInt32 unit, ATATimingProtocol timingProtocol ) -{ - Ultra646Regs *cfgRegs; - UInt32 cfgByte; - - cfgRegs = &ideTimingRegs[unit]; - - if ( busNum == 0 ) - { - pciWriteByte( kUltra646CMDTIM, cfgRegs->cmdtimReg ); - - if ( unit == 0 ) - { - pciWriteByte( kUltra646ARTTIM0, cfgRegs->arttimReg ); - - if ( timingProtocol == kATATimingPIO ) - { - cfgByte = pciReadByte( kUltra646CNTRL ); - cfgByte &= ~kUltra646CNTRL_Drive0ReadAhead; - cfgByte |= cfgRegs->cntrlReg; - pciWriteByte( kUltra646CNTRL, cfgByte ); - - pciWriteByte( kUltra646DRWTIM0, cfgRegs->drwtimRegPIO ); - } - else if ( timingProtocol == kATATimingDMA ) - { - pciWriteByte( kUltra646DRWTIM0, cfgRegs->drwtimRegDMA ); - } - else if ( timingProtocol == kATATimingUltraDMA33 ) - { - cfgByte = pciReadByte( kUltra646UDIDETCR0 ); - cfgByte &= ~(kUltra646UDIDETCR0_Drive0UDMACycleTime | kUltra646UDIDETCR0_Drive0UDMAEnable); - cfgByte |= cfgRegs->udidetcrReg; - pciWriteByte( kUltra646UDIDETCR0, cfgByte ); - } - } - else - { - pciWriteByte( kUltra646ARTTIM1, cfgRegs->arttimReg ); - - if ( timingProtocol == kATATimingPIO ) - { - cfgByte = pciReadByte( kUltra646CNTRL ); - cfgByte &= ~kUltra646CNTRL_Drive1ReadAhead; - cfgByte |= cfgRegs->cntrlReg; - pciWriteByte( kUltra646CNTRL, cfgByte ); - - pciWriteByte( kUltra646DRWTIM1, cfgRegs->drwtimRegPIO ); - } - else if ( timingProtocol == kATATimingDMA ) - { - pciWriteByte( kUltra646DRWTIM1, cfgRegs->drwtimRegDMA ); - } - else if ( timingProtocol == kATATimingUltraDMA33 ) - { - cfgByte = pciReadByte( kUltra646UDIDETCR0 ); - cfgByte &= ~(kUltra646UDIDETCR0_Drive1UDMACycleTime | kUltra646UDIDETCR0_Drive1UDMAEnable); - cfgByte |= cfgRegs->udidetcrReg; - pciWriteByte( kUltra646UDIDETCR0, cfgByte ); - } - } - } - else - { - pciWriteByte( kUltra646CMDTIM, cfgRegs->cmdtimReg ); - - if ( unit == 0 ) - { - cfgByte = pciReadByte( kUltra646ARTTIM23 ); - cfgByte &= ~(kUltra646ARTTIM23_Drive2ReadAhead | kUltra646ARTTIM23_AddrSetup); - cfgByte |= (cfgRegs->cntrlReg >> 4) | cfgRegs->arttimReg; - pciWriteByte( kUltra646ARTTIM23, cfgByte ); - - if ( timingProtocol == kATATimingPIO ) - { - pciWriteByte( kUltra646DRWTIM2, cfgRegs->drwtimRegPIO ); - } - else if ( timingProtocol == kATATimingDMA ) - { - pciWriteByte( kUltra646DRWTIM1, cfgRegs->drwtimRegDMA ); - } - else if ( timingProtocol == kATATimingUltraDMA33 ) - { - cfgByte = pciReadByte( kUltra646UDIDETCR1 ); - cfgByte &= ~(kUltra646UDIDETCR1_Drive2UDMACycleTime | kUltra646UDIDETCR1_Drive2UDMAEnable); - cfgByte |= cfgRegs->udidetcrReg; - pciWriteByte( kUltra646UDIDETCR1, cfgByte ); - } - } - else - { - cfgByte = pciReadByte( kUltra646ARTTIM23 ); - cfgByte &= ~(kUltra646ARTTIM23_Drive3ReadAhead | kUltra646ARTTIM23_AddrSetup); - cfgByte |= (cfgRegs->cntrlReg >> 4) | cfgRegs->arttimReg; - pciWriteByte( kUltra646ARTTIM23, cfgByte ); - - if ( timingProtocol == kATATimingPIO ) - { - pciWriteByte( kUltra646DRWTIM3, cfgRegs->drwtimRegPIO ); - } - else if ( timingProtocol == kATATimingDMA ) - { - pciWriteByte( kUltra646DRWTIM3, cfgRegs->drwtimRegDMA ); - } - else if ( timingProtocol == kATATimingUltraDMA33 ) - { - cfgByte = pciReadByte( kUltra646UDIDETCR1 ); - cfgByte &= ~(kUltra646UDIDETCR1_Drive3UDMACycleTime | kUltra646UDIDETCR1_Drive3UDMAEnable); - cfgByte |= cfgRegs->udidetcrReg; - pciWriteByte( kUltra646UDIDETCR1, cfgByte ); - } - } - } - - return true; -} - - -/* - * - * - */ -void AppleUltra33ATA::interruptOccurred() -{ - UInt32 intReg; - UInt32 cfgReg; - - intReg = (busNum == 0) ? kUltra646CFR : kUltra646ARTTIM23; - cfgReg = pciReadByte( intReg ); - pciWriteByte( intReg, cfgReg ); - - intReg = (busNum == 0) ? kUltra646BMIDESR0 : kUltra646BMIDESR1; - cfgReg = pciReadByte( intReg ); - pciWriteByte( intReg, cfgReg ); - - super::interruptOccurred(); - - enableControllerInterrupts(); -} - -/* - * - * - */ -bool AppleUltra33ATA::programDma( IOATAStandardCommand *cmd ) -{ - IOMemoryDescriptor *memoryDesc; - IOPhysicalSegment physSeg; - IOByteCount offset; - UInt32 i; - UInt32 bytesLeft; - UInt32 len; - Ultra646Descriptor *dmaDesc; - UInt32 startSeg, endSeg; - - cmd->getPointers( &memoryDesc, &dmaReqLength, &dmaIsWrite ); - - if ( dmaReqLength == 0 ) - { - return true; - } - - offset = 0; - - dmaDesc = dmaDescriptors; - - bytesLeft = dmaReqLength; - - for (i = 0; i < numDescriptors-1; i++, dmaDesc++ ) - { - if ( dmaMemoryCursor->getPhysicalSegments( memoryDesc, offset, &physSeg, 1 ) != 1 ) - { - break; - } - - startSeg = (physSeg.location & ~0xffff); - endSeg = (physSeg.location + physSeg.length - 1) & ~0xffff; - - OSWriteSwapInt32( &dmaDesc->start, 0, physSeg.location); - - if ( startSeg == endSeg ) - { - OSWriteSwapInt32( &dmaDesc->length, 0, physSeg.length ); - } - else - { - len = (-physSeg.location & 0xffff); - OSWriteSwapInt32( &dmaDesc->length, 0, len ); - dmaDesc++; - i++; - OSWriteSwapInt32( &dmaDesc->start, 0, physSeg.location + len ); - OSWriteSwapInt32( &dmaDesc->length, 0, physSeg.length - len ); - } - - bytesLeft -= physSeg.length; - offset += physSeg.length; - } - - if ( bytesLeft != 0 ) - { - return false; - } - - /* - * Note: ATAPI always transfers even byte-counts. Send the extra byte to/from the bit-bucket - * if the requested transfer length is odd. - */ - if ( dmaReqLength & 1 ) - { - if ( i == numDescriptors ) return false; - - dmaDesc++; - OSWriteSwapInt32( &dmaDesc->start, 0, bitBucketAddrPhys ); - OSWriteSwapInt32( &dmaDesc->length, 0, 1 ); - } - - - dmaDesc--; - dmaDesc->length |= 0x80; - - pciWriteLong( ((busNum == 0) ? kUltra646DTPR0 : kUltra646DTPR1), dmaDescriptorsPhys ); - - return true; -} - -/* - * - * - */ -bool AppleUltra33ATA::startDma( IOATAStandardCommand * ) -{ - UInt32 reg; - UInt32 cfgReg; - UInt32 startMask; - UInt32 writeMask; - - if ( dmaReqLength != 0 ) - { - reg = (busNum == 0) ? kUltra646BMIDECR0 : kUltra646BMIDECR1; - startMask = (busNum == 0) ? kUltra646BMIDECR0_StartDMAPRI : kUltra646BMIDECR1_StartDMASDY; - writeMask = (busNum == 0) ? kUltra646BMIDECR0_PCIWritePRI : kUltra646BMIDECR1_PCIWriteSDY; - cfgReg = pciReadByte( reg ); - cfgReg &= ~writeMask; - cfgReg |= startMask | ((dmaIsWrite == false) ? writeMask : 0); - pciWriteByte( reg, cfgReg ); - } - return true; -} - -/* - * - * - */ -bool AppleUltra33ATA::stopDma( IOATAStandardCommand *, UInt32 *transferCount ) -{ - UInt32 reg; - UInt32 cfgReg; - UInt32 startMask; - - *transferCount = 0; - - if ( dmaReqLength == 0 ) - { - return true; - } - - reg = (busNum == 0) ? kUltra646BMIDECR0 : kUltra646BMIDECR1; - startMask = (busNum == 0) ? kUltra646BMIDECR0_StartDMAPRI : kUltra646BMIDECR1_StartDMASDY; - cfgReg = pciReadByte( reg ); - cfgReg &= ~startMask; - pciWriteByte( reg, cfgReg ); - - *transferCount = dmaReqLength; - - return true; -} - -/* - * - * - */ -bool AppleUltra33ATA::checkDmaActive() -{ - UInt32 reg; - UInt32 cfgReg; - UInt32 activeMask; - - reg = (busNum == 0) ? kUltra646BMIDESR0 : kUltra646BMIDESR1; - activeMask = (busNum == 0) ? kUltra646BMIDESR0_DMAActivePRI : kUltra646BMIDESR1_DMAActiveSDY; - - cfgReg = pciReadByte( reg ); - - return ((cfgReg & activeMask) != 0); -} - -/* - * - * - */ -bool AppleUltra33ATA::resetDma() -{ - UInt32 reg; - UInt32 cfgReg; - UInt32 startMask; - - reg = (busNum == 0) ? kUltra646BMIDECR0 : kUltra646BMIDECR1; - startMask = (busNum == 0) ? kUltra646BMIDECR0_StartDMAPRI : kUltra646BMIDECR1_StartDMASDY; - - cfgReg = pciReadByte( reg ); - cfgReg &= ~startMask; - pciWriteByte( reg, cfgReg ); - - return true; -} - -/* - * - * - */ -void AppleUltra33ATA::disableControllerInterrupts() -{ - interruptEventSource->disable(); -} - -/* - * - * - */ -void AppleUltra33ATA::enableControllerInterrupts() -{ - interruptEventSource->enable(); -} - -/* - * - * - */ -void AppleUltra33ATA::free() -{ - UInt32 i; - - if ( interruptEventSource != 0 ) - { - interruptEventSource->disable(); - interruptEventSource->release(); - } - - for (i = 0; i < 2; i++ ) - { - if ( ioMapATA[i] != 0 ) ioMapATA[i]->release(); - } - - if ( dmaDescriptors != 0 ) - { - kfree( (vm_offset_t)dmaDescriptors, page_size ); - } -} - -/* - * - * - */ -void AppleUltra33ATA::writeATAReg( UInt32 regIndex, UInt32 regValue ) -{ - if ( regIndex == 0 ) - { - *(volatile UInt16 *)ioBaseATA[0] = regValue; - } - else if ( regIndex < kATARegDeviceControl ) - { - *((volatile UInt8 *)ioBaseATA[0] + regIndex) = regValue; - } - else - { - *((volatile UInt8 *)ioBaseATA[1] + regIndex - kATARegDeviceControl + 2) = regValue; - } - eieio(); -} - -UInt32 AppleUltra33ATA::readATAReg( UInt32 regIndex ) -{ - if ( regIndex == 0 ) - { - return *(volatile UInt16 *)ioBaseATA[0]; - } - else if ( regIndex < kATARegDeviceControl ) - { - return *((volatile UInt8 *)ioBaseATA[0] + regIndex); - } - - return *((volatile UInt8 *)ioBaseATA[1] + regIndex - kATARegDeviceControl + 2); -} - -/* - * - * - */ -UInt32 AppleUltra33ATA::pciReadByte( UInt32 reg ) -{ - volatile union - { - unsigned long word; - unsigned char byte[4]; - } data; - - data.word = provider->configRead32( reg ); - return data.byte[3 - (reg & 0x03)]; -} - -void AppleUltra33ATA::pciWriteByte( UInt32 reg, UInt32 value ) -{ - volatile union - { - unsigned long word; - unsigned char byte[4]; - } data; - - UInt32 regWord; - - regWord = reg & ~0x03; - - data.word = provider->configRead32( regWord ); - data.word = OSReadSwapInt32( &data.word, 0 ); - - switch (regWord) - { - case kUltra646CFR: - data.byte[kUltra646CFR & 0x03] &= ~kUltra646CFR_IDEIntPRI; - break; - case kUltra646DRWTIM0: - data.byte[kUltra646ARTTIM23 & 0x03] &= ~kUltra646ARTTIM23_IDEIntSDY; - break; - case kUltra646BMIDECR0: - data.byte[kUltra646MRDMODE & 0x03 ] &= ~(kUltra646MRDMODE_IDEIntPRI | kUltra646MRDMODE_IDEIntSDY); - data.byte[kUltra646BMIDESR0 & 0x03] &= ~(kUltra646BMIDESR0_DMAIntPRI | kUltra646BMIDESR0_DMAErrorPRI); - break; - case kUltra646BMIDECR1: - data.byte[kUltra646BMIDESR1 & 0x03] &= ~(kUltra646BMIDESR1_DMAIntSDY | kUltra646BMIDESR1_DMAErrorSDY); - break; - } - data.byte[reg & 0x03] = value; - - data.word = OSReadSwapInt32(&data.word, 0); - - provider->configWrite32( regWord, data.word ); -} - -UInt32 AppleUltra33ATA::pciReadLong( UInt32 reg ) -{ - return provider->configRead32( reg ); -} - -void AppleUltra33ATA::pciWriteLong( UInt32 reg, UInt32 value ) -{ - provider->configWrite32( reg, value ); -} - -/* These overrides take care of OpenFirmware referring to the controller - * as a child of the PCI device, "ata-4" */ - -bool AppleUltra33ATA::attach( IOService * provider ) -{ - if ( super::attach(provider) ) - { - // assumes the first child determines the path OF uses to reference the controller - pathProvider = OSDynamicCast(IOService, provider->getChildEntry(gIODTPlane)); - - if ( pathProvider ) - { - setLocation(pathProvider->getLocation(gIODTPlane), gIODTPlane); - setName(pathProvider->getName(gIODTPlane), gIODTPlane); - attachToParent(provider, gIODTPlane); - pathProvider->retain(); - pathProvider->detachFromParent(provider, gIODTPlane); - } - - return true; - } - - return false; -} - -void AppleUltra33ATA::detach( IOService * provider ) -{ - if ( pathProvider ) - { - detachFromParent(provider, gIODTPlane); - pathProvider->attachToParent(provider, gIODTPlane); - pathProvider->release(); - } - - super::detach(provider); -} diff --git a/iokit/Drivers/ata/drvAppleUltra33ATA/AppleUltra33ATA.h b/iokit/Drivers/ata/drvAppleUltra33ATA/AppleUltra33ATA.h deleted file mode 100644 index 71b6d39c9..000000000 --- a/iokit/Drivers/ata/drvAppleUltra33ATA/AppleUltra33ATA.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * AppleUltra33ATA.h - * - */ - -#include -#include -#include -#include - -#include -#include "AppleUltra33ATARegs.h" - -class AppleUltra33ATA : public IOATAStandardDriver -{ - OSDeclareDefaultStructors( AppleUltra33ATA ) - -public: - virtual bool attach( IOService * provider ); - virtual void detach( IOService * provider ); - void free(); - -protected: - bool configure( IOService *provider, ATAControllerInfo *controllerDataSize ); - - void interruptOccurred(); - - void enableControllerInterrupts(); - void disableControllerInterrupts(); - - bool calculateTiming( UInt32 deviceNum, ATATiming *timing ); - bool selectTiming( UInt32 deviceNum, ATATimingProtocol timingProtocol ); - - void newDeviceSelected( IOATADevice *newDevice ); - - void writeATAReg( UInt32 regIndex, UInt32 regValue ); - UInt32 readATAReg( UInt32 regIndex ); - - bool programDma( IOATAStandardCommand *cmd ); - bool startDma( IOATAStandardCommand *cmd ); - bool stopDma( IOATAStandardCommand *cmd, UInt32 *transferCount ); - bool checkDmaActive(); - bool resetDma(); - -private: - bool calculatePIOTiming( UInt32 deviceNum, ATATiming *timing ); - bool calculateDMATiming( UInt32 deviceNum, ATATiming *timing ); - bool calculateUltraDMATiming( UInt32 deviceNum, ATATiming *timing ); - - UInt32 pciReadByte( UInt32 reg ); - void pciWriteByte( UInt32 reg, UInt32 value ); - UInt32 pciReadLong( UInt32 reg ); - void pciWriteLong( UInt32 reg, UInt32 value ); - -private: - IOPCIDevice *provider; - IOService *pathProvider; - - UInt32 busNum; - - IOMemoryMap *ioMapATA[2]; - volatile UInt32 *ioBaseATA[2]; - - IOInterruptEventSource *interruptEventSource; - - Ultra646Regs ideTimingRegs[2]; - - IOBigMemoryCursor *dmaMemoryCursor; - Ultra646Descriptor *dmaDescriptors; - UInt32 dmaDescriptorsPhys; - UInt32 numDescriptors; - - void *bitBucketAddr; - UInt32 bitBucketAddrPhys; - - UInt32 dmaReqLength; - bool dmaIsWrite; -}; - diff --git a/iokit/Drivers/ata/drvAppleUltra33ATA/AppleUltra33ATARegs.h b/iokit/Drivers/ata/drvAppleUltra33ATA/AppleUltra33ATARegs.h deleted file mode 100644 index 7ba0e18a8..000000000 --- a/iokit/Drivers/ata/drvAppleUltra33ATA/AppleUltra33ATARegs.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * PCI Control registers for Cmd646X chipset - * - */ -enum Ultra646RegsValues -{ - kUltra646CFR = 0x50, /* Configuration */ - kUltra646CFR_DSA1 = 0x40, - kUltra646CFR_IDEIntPRI = 0x04, - - kUltra646CNTRL = 0x51, /* Drive 0/1 Control Register */ - kUltra646CNTRL_Drive1ReadAhead = 0x80, - kUltra646CNTRL_Drive0ReadAhead = 0x40, - kUltra646CNTRL_EnableSDY = 0x08, - kUltra646CNTRL_EnablePRI = 0x04, - - kUltra646CMDTIM = 0x52, /* Task file timing (all drives) */ - kUltra646CMDTIM_Drive01CmdActive = 0xF0, - kUltra646CMDTIM_Drive01CmdRecovery = 0x0F, - - kUltra646ARTTIM0 = 0x53, /* Drive 0 Address Setup */ - kUltra646ARTTIM0_Drive0AddrSetup = 0xC0, - - kUltra646DRWTIM0 = 0x54, /* Drive 0 Data Read/Write - DACK Time */ - kUltra646DRWTIM0_Drive0DataActive = 0xF0, - kUltra646DRWTIM0_Drive0DataRecovery = 0x0F, - - kUltra646ARTTIM1 = 0x55, /* Drive 1 Address Setup */ - kUltra646ARTTIM1_Drive1AddrSetup = 0xC0, - - kUltra646DRWTIM1 = 0x56, /* Drive 1 Data Read/Write - DACK Time */ - kUltra646DRWTIM1_Drive1DataActive = 0xF0, - kUltra646DRWTIM1_Drive1DataRecover = 0x0F, - - kUltra646ARTTIM23 = 0x57, /* Drive 2/3 Control/Status */ - kUltra646ARTTIM23_AddrSetup = 0xC0, - kUltra646ARTTIM23_IDEIntSDY = 0x10, - kUltra646ARTTIM23_Drive3ReadAhead = 0x08, - kUltra646ARTTIM23_Drive2ReadAhead = 0x04, - - kUltra646DRWTIM2 = 0x58, /* Drive 2 Read/Write - DACK Time */ - kUltra646DRWTIM2_Drive2DataActive = 0xF0, - kUltra646DRWTIM2_Drive2DataRecovery = 0x0F, - - kUltra646BRST = 0x59, /* Read Ahead Count */ - - kUltra646DRWTIM3 = 0x5B, /* Drive 3 Read/Write - DACK Time */ - kUltra646DRWTIM3_Drive3DataActive = 0xF0, - kUltra646DRWTIM3_Drive3DataRecover = 0x0F, - - kUltra646BMIDECR0 = 0x70, /* BusMaster Command Register - Primary */ - kUltra646BMIDECR0_PCIWritePRI = 0x08, - kUltra646BMIDECR0_StartDMAPRI = 0x01, - - kUltra646MRDMODE = 0x71, /* DMA Master Read Mode Select */ - kUltra646MRDMODE_PCIReadMask = 0x03, - kUltra646MRDMODE_PCIRead = 0x00, - kUltra646MRDMODE_PCIReadMultiple = 0x01, - kUltra646MRDMODE_IDEIntPRI = 0x04, - kUltra646MRDMODE_IDEIntSDY = 0x08, - kUltra646MRDMODE_IntEnablePRI = 0x10, - kUltra646MRDMODE_IntEnableSDY = 0x20, - kUltra646MRDMODE_ResetAll = 0x40, - - kUltra646BMIDESR0 = 0x72, /* BusMaster Status Register - Primary */ - kUltra646BMIDESR0_Simplex = 0x80, - kUltra646BMIDESR0_Drive1DMACap = 0x40, - kUltra646BMIDESR0_Drive0DMACap = 0x20, - kUltra646BMIDESR0_DMAIntPRI = 0x04, - kUltra646BMIDESR0_DMAErrorPRI = 0x02, - kUltra646BMIDESR0_DMAActivePRI = 0x01, - - kUltra646UDIDETCR0 = 0x73, /* Ultra DMA Timing Control Register - Primary */ - kUltra646UDIDETCR0_Drive1UDMACycleTime = 0xC0, - kUltra646UDIDETCR0_Drive0UDMACycleTime = 0x30, - kUltra646UDIDETCR0_Drive1UDMAEnable = 0x02, - kUltra646UDIDETCR0_Drive0UDMAEnable = 0x01, - - kUltra646DTPR0 = 0x74, /* Descriptor Table Pointer - Primary */ - - kUltra646BMIDECR1 = 0x78, /* BusMaster Command Register - Secondary */ - kUltra646BMIDECR1_PCIWriteSDY = 0x08, - kUltra646BMIDECR1_StartDMASDY = 0x01, - - kUltra646BMIDESR1 = 0x7A, /* BusMaster Status Register - Secondary */ - kUltra646BMIDESR1_Simplex = 0x80, - kUltra646BMIDESR1_Drive3DMACap = 0x40, - kUltra646BMIDESR1_Drive2DMACap = 0x20, - kUltra646BMIDESR1_DMAIntSDY = 0x04, - kUltra646BMIDESR1_DMAErrorSDY = 0x02, - kUltra646BMIDESR1_DMAActiveSDY = 0x01, - - kUltra646UDIDETCR1 = 0x7B, /* Ultra DMA Timing Control Register - Secondary */ - kUltra646UDIDETCR1_Drive3UDMACycleTime = 0xC0, - kUltra646UDIDETCR1_Drive2UDMACycleTime = 0x30, - kUltra646UDIDETCR1_Drive3UDMAEnable = 0x02, - kUltra646UDIDETCR1_Drive2UDMAEnable = 0x01, - - kUltra646DTPR1 = 0x7C, /* Descriptor Table Pointer - Secondary */ -}; - -typedef struct -{ - UInt32 cntrlReg; - UInt32 arttimReg; - UInt32 cmdtimReg; - UInt32 drwtimRegPIO; - UInt32 drwtimRegDMA; - UInt32 udidetcrReg; -} Ultra646Regs; - - -typedef struct -{ - UInt32 start; - UInt32 length; -} Ultra646Descriptor; - - -#define IDE_SYSCLK_NS 30 diff --git a/iokit/Drivers/ata/drvAppleUltra66ATA/AppleUltra66ATA.cpp b/iokit/Drivers/ata/drvAppleUltra66ATA/AppleUltra66ATA.cpp deleted file mode 100644 index 403787906..000000000 --- a/iokit/Drivers/ata/drvAppleUltra66ATA/AppleUltra66ATA.cpp +++ /dev/null @@ -1,749 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * AppleUltra66ATA.cpp - * - */ -#include "AppleUltra66ATA.h" - -#undef super -#define super IOATAStandardDriver - -extern pmap_t kernel_pmap; - -OSDefineMetaClassAndStructors( AppleUltra66ATA, IOATAStandardDriver ) - -static inline int rnddiv( int x, int y ) -{ - if ( x < 0 ) - return 0; - else - return ( (x / y) + (( x % y ) ? 1 : 0) ); -} - - -/* - * - * - */ -bool AppleUltra66ATA::configure( IOService *forProvider, ATAControllerInfo *controllerInfo ) -{ - provider = forProvider; - - if ( identifyController() == false ) - { - return false; - } - - ioMapATA = provider->mapDeviceMemoryWithIndex(0); - if ( ioMapATA == NULL ) return false; - ioBaseATA = (volatile UInt32 *)ioMapATA->getVirtualAddress(); - - ioMapDMA = provider->mapDeviceMemoryWithIndex(1); - if ( ioMapDMA == NULL ) return false; - ioBaseDMA = (volatile IODBDMAChannelRegisters *)ioMapDMA->getVirtualAddress(); - - dmaDescriptors = (IODBDMADescriptor *)kalloc(page_size); - if ( dmaDescriptors == 0 ) - { - return false; - } - - dmaDescriptorsPhys = (UInt32) pmap_extract(kernel_pmap, (vm_offset_t) dmaDescriptors); - - if ( (UInt32)dmaDescriptors & (page_size - 1) ) - { - IOLog("AppleUltra66ATA::%s() - DMA Descriptor memory not page aligned!!", __FUNCTION__); - return false; - } - - bzero( dmaDescriptors, page_size ); - - numDescriptors = page_size/sizeof(IODBDMADescriptor); - - dmaMemoryCursor = IOBigMemoryCursor::withSpecification( 64*1024-2, 0xffffffff ); - if ( dmaMemoryCursor == NULL ) - { - return false; - } - - bitBucketAddr = IOMalloc(32); - if ( bitBucketAddr == 0 ) - { - return false; - } - bitBucketAddrPhys = (UInt32) pmap_extract(kernel_pmap, (vm_offset_t) (((UInt32)bitBucketAddr + 0xf) & ~0x0f)); - - interruptEventSource = IOInterruptEventSource::interruptEventSource( (OSObject *) this, - (IOInterruptEventAction) &AppleUltra66ATA::interruptOccurred, - (IOService *) provider, - (int) 0 ); - - if ( interruptEventSource == NULL ) - { - return false; - } - - disableControllerInterrupts(); - - getWorkLoop()->addEventSource( interruptEventSource ); - - controllerInfo->maxDevicesSupported = 2; - controllerInfo->devicePrivateDataSize = 0; - controllerInfo->commandPrivateDataSize = 0; - controllerInfo->disableCancelCommands = false; - - return true; -} - - -/* - * - * - */ -bool AppleUltra66ATA::identifyController() -{ - OSData *compatibleEntry, *modelEntry; - - do - { - controllerType = kControllerTypeDBDMAVersion1; - - compatibleEntry = OSDynamicCast( OSData, provider->getProperty( "compatible" ) ); - if ( compatibleEntry == 0 ) break; - - if ( compatibleEntry->isEqualTo( "keylargo-ata", sizeof("keylargo-ata")-1 ) == true ) - { - controllerType = kControllerTypeDBDMAVersion2; - - modelEntry = OSDynamicCast( OSData, provider->getProperty("model") ); - if ( modelEntry == 0 ) break; - - if ( modelEntry->isEqualTo( "ata-4", sizeof("ata-4")-1 ) == true ) - { - controllerType = kControllerTypeUltra66DBDMA; - } - } - } while ( 0 ); - - return true; -} - - -/* - * - * - */ -bool AppleUltra66ATA::calculateTiming( UInt32 deviceNum, ATATiming *pTiming ) -{ - bool rc = false; - - switch ( controllerType ) - { - case kControllerTypeDBDMAVersion1: - case kControllerTypeDBDMAVersion2: - switch ( pTiming->timingProtocol ) - { - case kATATimingPIO: - rc = calculatePIOTiming( deviceNum, pTiming ); - break; - - case kATATimingDMA: - rc = calculateDMATiming( deviceNum, pTiming ); - break; - - default: - ; - } - break; - - case kControllerTypeUltra66DBDMA: - switch ( pTiming->timingProtocol ) - { - case kATATimingPIO: - rc = calculateUltra66PIOTiming( deviceNum, pTiming ); - break; - - case kATATimingDMA: - rc = calculateUltra66DMATiming( deviceNum, pTiming ); - break; - - case kATATimingUltraDMA66: - rc = calculateUltra66UDMATiming( deviceNum, pTiming ); - break; - - default: - ; - } - break; - - default: - ; - } - - return rc; -} - - -/* - * - * - */ -bool AppleUltra66ATA::calculatePIOTiming( UInt32 unitNum, ATATiming *pTiming ) -{ - int accessTime; - int accessTicks; - int recTime; - int recTicks; - int cycleTime; - - /* - * Calc PIO access time >= minDataAccess in SYSCLK increments - */ - accessTicks = rnddiv(pTiming->minDataAccess, kATASysClkNS); - /* - * Hardware limits access times to >= 120 ns - */ - accessTicks -= kATAPioAccessBase; - if (accessTicks < kATAPioAccessMin ) - { - accessTicks = kATAPioAccessMin; - } - accessTime = (accessTicks + kATAPioAccessBase) * kATASysClkNS; - - /* - * Calc recovery time in SYSCLK increments based on time remaining in cycle - */ - recTime = pTiming->minDataCycle - accessTime; - recTicks = rnddiv( recTime, kATASysClkNS ); - /* - * Hardware limits recovery time to >= 150ns - */ - recTicks -= kATAPioRecoveryBase; - if ( recTicks < kATAPioRecoveryMin ) - { - recTicks = kATAPioRecoveryMin; - } - - cycleTime = (recTicks + kATAPioRecoveryBase + accessTicks + kATAPioAccessBase) * kATASysClkNS; - - ideTimingWord[unitNum] &= ~0x7ff; - ideTimingWord[unitNum] |= accessTicks | (recTicks << 5); - -#if 0 - IOLog("AppleUltra66ATA::%s() Unit %1d PIO Requested Timings: Access: %3dns Cycle: %3dns \n\r", - __FUNCTION__, (int)unitNum, (int)pTiming->minDataAccess, (int)pTiming->minDataCycle); - IOLog("AppleUltra66ATA::%s() PIO Actual Timings: Access: %3dns Cycle: %3dns\n\r", - __FUNCTION__, accessTime, cycleTime ); -#endif - - return true; -} - - -/* - * - * - */ -bool AppleUltra66ATA::calculateDMATiming( UInt32 unitNum, ATATiming *pTiming ) -{ - int accessTime; - int accessTicks; - int recTime; - int recTicks; - int cycleTime; - int cycleTimeOrig; - int halfTick = 0; - - /* - * Calc DMA access time >= minDataAccess in SYSCLK increments - */ - - /* - * OHare II erata - Cant handle write cycle times below 150ns - */ - cycleTimeOrig = pTiming->minDataCycle; -#if 0 - if ( IsPowerStar() ) - { - if ( cycleTimeOrig < 150 ) pTiming->minDataCycle = 150; - } -#endif - - accessTicks = rnddiv(pTiming->minDataAccess, kATASysClkNS); - - accessTicks -= kATADmaAccessBase; - if ( accessTicks < kATADmaAccessMin ) - { - accessTicks = kATADmaAccessMin; - } - accessTime = (accessTicks + kATADmaAccessBase) * kATASysClkNS; - - /* - * Calc recovery time in SYSCLK increments based on time remaining in cycle - */ - recTime = pTiming->minDataCycle - accessTime; - recTicks = rnddiv( recTime, kATASysClkNS ); - - recTicks -= kATADmaRecoveryBase; - if ( recTicks < kATADmaRecoveryMin ) - { - recTicks = kATADmaRecoveryMin; - } - cycleTime = (recTicks + kATADmaRecoveryBase + accessTicks + kATADmaAccessBase) * kATASysClkNS; - - /* - * If our calculated access time is at least SYSCLK/2 > than what the disk requires, - * see if selecting the 1/2 Clock option will help. This adds SYSCLK/2 to - * the access time and subtracts SYSCLK/2 from the recovery time. - * - * By setting the H-bit and subtracting one from the current access tick count, - * we are reducing the current access time by SYSCLK/2 and the current recovery - * time by SYSCLK/2. Now, check if the new cycle time still meets the disk's requirements. - */ - if ( controllerType == kControllerTypeDBDMAVersion1 ) - { - if ( (accessTicks > kATADmaAccessMin) && ((UInt32)(accessTime - kATASysClkNS/2) >= pTiming->minDataAccess) ) - { - if ( (UInt32)(cycleTime - kATASysClkNS) >= pTiming->minDataCycle ) - { - halfTick = 1; - accessTicks--; - accessTime -= kATASysClkNS/2; - cycleTime -= kATASysClkNS; - } - } - } - - ideTimingWord[unitNum] &= ~0xffff800; - ideTimingWord[unitNum] |= (accessTicks | (recTicks << 5) | (halfTick << 10)) << 11; - -#if 0 - IOLog("AppleUltra66ATA::%s() Unit %1d DMA Requested Timings: Access: %3dns Cycle: %3dns \n\r", - __FUNCTION__, (int)unitNum, (int)pTiming->minDataAccess, (int)cycleTimeOrig); - IOLog("AppleUltra66ATA::%s() DMA Actual Timings: Access: %3dns Cycle: %3dns\n\r", - __FUNCTION__, accessTime, cycleTime ); - IOLog("AppleUltra66ATA::%s() Ide DMA Timings = %08lx\n\r", __FUNCTION__, ideTimingWord[unitNum] ); -#endif - - return true; -} - - -/* - * - * - */ -bool AppleUltra66ATA::calculateUltra66PIOTiming( UInt32 unitNum, ATATiming *pTiming ) -{ - int accessTime; - int accessTicks; - int recTime; - int recTicks; - int cycleTime; - - /* - * Calc PIO access time >= pioAccessTime in SYSCLK increments - */ - accessTicks = rnddiv(pTiming->minDataAccess * 1000, kATAUltra66ClockPS ); - accessTime = accessTicks * kATAUltra66ClockPS; - - /* - * Calc recovery time in SYSCLK increments based on time remaining in cycle - */ - recTime = pTiming->minDataCycle * 1000 - accessTime; - recTicks = rnddiv( recTime, kATAUltra66ClockPS ); - - cycleTime = (recTicks + accessTicks ) * kATAUltra66ClockPS; - - ideTimingWord[unitNum] &= ~0xe00003ff; - ideTimingWord[unitNum] |= accessTicks | (recTicks << 5); - -#if 0 - IOLog("AppleUltra66ATA::%s() Unit %1d PIO Requested Timings: Access: %3dns Cycle: %3dns \n\r", - __FUNCTION__, (int)unitNum, (int)pTiming->minDataAccess, (int)pTiming->minDataCycle); - IOLog("AppleUltra66ATA::%s() PIO Actual Timings: Access: %3dns Cycle: %3dns\n\r", - __FUNCTION__, accessTime / 1000, cycleTime / 1000 ); - IOLog("AppleUltra66ATA::%s() Ide PIO Timings = %08lx\n\r", __FUNCTION__, ideTimingWord[unitNum] ); -#endif - - return true; -} - - -/* - * - * - */ -bool AppleUltra66ATA::calculateUltra66DMATiming( UInt32 unitNum, ATATiming *pTiming ) -{ - int accessTime; - int accessTicks; - int recTime; - int recTicks; - int cycleTime; - - /* - * Calc DMA access time >= dmaAccessTime in SYSCLK increments - */ - accessTicks = rnddiv(pTiming->minDataAccess * 1000, kATAUltra66ClockPS); - accessTime = accessTicks * kATAUltra66ClockPS; - - /* - * Calc recovery time in SYSCLK increments based on time remaining in cycle - */ - recTime = pTiming->minDataCycle * 1000 - accessTime; - recTicks = rnddiv( recTime, kATAUltra66ClockPS ); - - cycleTime = (recTicks + accessTicks) * kATAUltra66ClockPS; - - ideTimingWord[unitNum] &= ~0x001ffc00; - ideTimingWord[unitNum] |= (accessTicks | (recTicks << 5)) << 10; - -#if 0 - IOLog("AppleUltra66ATA::%s() Unit %1d DMA Requested Timings: Access: %3dns Cycle: %3dns \n\r", - __FUNCTION__, (int)unitNum, (int)pTiming->minDataAccess, (int)pTiming->minDataCycle); - IOLog("AppleUltra66ATA::%s() DMA Actual Timings: Access: %3dns Cycle: %3dns\n\r", - __FUNCTION__, accessTime / 1000, cycleTime / 1000 ); - IOLog("AppleUltra66ATA::%s() Ide DMA Timings = %08lx\n\r", __FUNCTION__, ideTimingWord[unitNum] ); -#endif - - return true; -} - - -/* - * - * - */ -bool AppleUltra66ATA::calculateUltra66UDMATiming( UInt32 unitNum, ATATiming *pTiming ) -{ - int rdyToPauseTicks; - int rdyToPauseTime; - int cycleTime; - int cycleTicks; - - /* - * Ready to Pause delay in PCI_66_CLOCK / 2 increments - */ - rdyToPauseTicks = rnddiv(pTiming->minDataAccess * 1000, kATAUltra66ClockPS); - rdyToPauseTime = rdyToPauseTicks * kATAUltra66ClockPS; - - /* - * Calculate cycle time in PCI_66_CLOCK / 2 increments - */ - cycleTicks = rnddiv(pTiming->minDataCycle * 1000, kATAUltra66ClockPS); - cycleTime = cycleTicks * kATAUltra66ClockPS; - - ideTimingWord[unitNum] &= ~0x1ff00000; - ideTimingWord[unitNum] |= ((rdyToPauseTicks << 5) | (cycleTicks << 1) | 1) << 20; - -#if 0 - IOLog("AppleUltra66ATA::%s() Unit %1d UDMA66 Requested Timings: ReadyToPause: %3dns Cycle: %3dns \n\r", - __FUNCTION__, (int)unitNum, (int)pTiming->minDataAccess, (int)pTiming->minDataCycle); - IOLog("AppleUltra66ATA::%s() UDMA66 Actual Timings: ReadyToPause: %3dns Cycle: %3dns\n\r", - __FUNCTION__, rdyToPauseTime / 1000, cycleTime / 1000 ); - IOLog("AppleUltra66ATA::%s() Ide DMA Timings = %08lx\n\r", __FUNCTION__, ideTimingWord[unitNum] ); -#endif - - return true; -} - - -/* - * - * - */ -void AppleUltra66ATA::newDeviceSelected( IOATAStandardDevice *newDevice ) -{ - OSWriteSwapInt32( ioBaseATA, 0x200, ideTimingWord[newDevice->getUnit()] ); - eieio(); -} - - -/* - * - * - */ -bool AppleUltra66ATA::selectTiming( UInt32 unitNum, ATATimingProtocol timingProtocol ) -{ - if ( controllerType == kControllerTypeUltra66DBDMA ) - { - switch ( timingProtocol ) - { - case kATATimingUltraDMA66: - ideTimingWord[unitNum] |= 0x00100000; - break; - case kATATimingDMA: - ideTimingWord[unitNum] &= ~0x00100000; - break; - default: - ; - } - } - return true; -} - -/* - * - * - */ -bool AppleUltra66ATA::programDma( IOATAStandardCommand *cmd ) -{ - IOMemoryDescriptor *memoryDesc; - IODBDMADescriptor *dmaDesc; - UInt32 dmaCmd; - bool isWrite; - IOPhysicalSegment physSeg; - IOByteCount offset; - UInt32 i; - - IODBDMAReset( ioBaseDMA ); - - cmd->getPointers( &memoryDesc, &dmaReqLength, &isWrite ); - - if ( dmaReqLength == 0 ) - { - return true; - } - - offset = 0; - - dmaCmd = (isWrite == true) ? kdbdmaOutputMore : kdbdmaInputMore; - dmaDesc = dmaDescriptors; - - for ( i = 0; i < numDescriptors; i++, dmaDesc++ ) - { - if ( dmaMemoryCursor->getPhysicalSegments( memoryDesc, offset, &physSeg, 1 ) != 1 ) - { - break; - } - - IOMakeDBDMADescriptor( dmaDesc, - dmaCmd, - kdbdmaKeyStream0, - kdbdmaIntNever, - kdbdmaBranchNever, - kdbdmaWaitNever, - physSeg.length, - physSeg.location ); - offset += physSeg.length; - } - - if ( i == numDescriptors ) - { - return false; - } - - /* - * Note: ATAPI always transfers even byte-counts. Send the extra byte to/from the bit-bucket - * if the requested transfer length is odd. - */ - if ( dmaReqLength & 1 ) - { - i++; - IOMakeDBDMADescriptor( dmaDesc++, - dmaCmd, - kdbdmaKeyStream0, - kdbdmaIntNever, - kdbdmaBranchNever, - kdbdmaWaitNever, - 1, - bitBucketAddrPhys ); - } - - - if ( i == numDescriptors ) - { - return false; - } - - - IOMakeDBDMADescriptor( dmaDesc, - kdbdmaStop, - kdbdmaKeyStream0, - kdbdmaIntNever, - kdbdmaBranchNever, - kdbdmaWaitNever, - 0, - 0 ); - - IOSetDBDMACommandPtr( ioBaseDMA, dmaDescriptorsPhys ); - - - return true; -} - - -/* - * - * - */ -bool AppleUltra66ATA::startDma( IOATAStandardCommand * ) -{ - if ( dmaReqLength != 0 ) - { - IODBDMAContinue( ioBaseDMA ); - } - return true; -} - - -/* - * - * - */ -bool AppleUltra66ATA::stopDma( IOATAStandardCommand *, UInt32 *transferCount ) -{ - UInt32 i; - UInt32 ccResult; - UInt32 byteCount = 0; - - *transferCount = 0; - - if ( dmaReqLength == 0 ) - { - return true; - } - - IODBDMAStop( ioBaseDMA ); - - for ( i=0; i < numDescriptors; i++ ) - { - ccResult = IOGetCCResult( &dmaDescriptors[i] ); - - if ( (ccResult & (kdbdmaStatusActive | kdbdmaStatusDead)) == 0 ) - { - break; - } - byteCount += (IOGetCCOperation( &dmaDescriptors[i] ) & kdbdmaReqCountMask) - (ccResult & kdbdmaResCountMask); - } - - *transferCount = byteCount; - - return true; -} - -/* - * - * - */ -bool AppleUltra66ATA::resetDma() -{ - IODBDMAReset( ioBaseDMA ); - return true; -} - -/* - * - * - */ -bool AppleUltra66ATA::checkDmaActive() -{ - return ((IOGetDBDMAChannelStatus( ioBaseDMA ) & kdbdmaActive) != 0); -} - - -/* - * - * - */ -void AppleUltra66ATA::disableControllerInterrupts() -{ - interruptEventSource->disable(); -} - -/* - * - * - */ -void AppleUltra66ATA::enableControllerInterrupts() -{ - interruptEventSource->enable(); -} - -/* - * - * - */ -void AppleUltra66ATA::free() -{ - if ( interruptEventSource != 0 ) - { - interruptEventSource->disable(); - interruptEventSource->release(); - } - - if ( ioMapATA != 0 ) - { - ioMapATA->release(); - } - - if ( ioMapDMA != 0 ) - { - ioMapDMA->release(); - } - - if ( bitBucketAddr != 0 ) - { - IOFree( bitBucketAddr, 32 ); - } - - if ( dmaDescriptors != 0 ) - { - kfree( (vm_offset_t)dmaDescriptors, page_size ); - } -} - -/* - * - * - */ -void AppleUltra66ATA::writeATAReg( UInt32 regIndex, UInt32 regValue ) -{ - regIndex += (regIndex >= kATARegDeviceControl ) ? (kATACS3RegBase - kATARegDeviceControl + 6) : 0; - - if ( regIndex ) - { - *((volatile UInt8 *)ioBaseATA + (regIndex<<4)) = regValue; - } - else - { - *(volatile UInt16 *)ioBaseATA = regValue; - } - eieio(); -} - -UInt32 AppleUltra66ATA::readATAReg( UInt32 regIndex ) -{ - regIndex += (regIndex >= kATARegAltStatus ) ? (kATACS3RegBase - kATARegAltStatus + 6) : 0; - - if ( regIndex ) - { - return *((volatile UInt8 *)ioBaseATA + (regIndex<<4)); - } - else - { - return *(volatile UInt16 *)ioBaseATA; - } -} diff --git a/iokit/Drivers/ata/drvAppleUltra66ATA/AppleUltra66ATA.h b/iokit/Drivers/ata/drvAppleUltra66ATA/AppleUltra66ATA.h deleted file mode 100644 index 355ef13cd..000000000 --- a/iokit/Drivers/ata/drvAppleUltra66ATA/AppleUltra66ATA.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * AppleUltra66ATA.h - * - */ - -#include -#include - -#include - -class AppleUltra66ATA : public IOATAStandardDriver -{ - OSDeclareDefaultStructors( AppleUltra66ATA ) - -public: - void free(); - -protected: - bool configure( IOService *provider, ATAControllerInfo *controllerDataSize ); - - void enableControllerInterrupts(); - void disableControllerInterrupts(); - - bool calculateTiming( UInt32 deviceNum, ATATiming *timing ); - bool selectTiming( UInt32 deviceNum, ATATimingProtocol timingProtocol ); - - void newDeviceSelected( IOATAStandardDevice *newDevice ); - - void writeATAReg( UInt32 regIndex, UInt32 regValue ); - UInt32 readATAReg( UInt32 regIndex ); - - bool programDma( IOATAStandardCommand *cmd ); - bool startDma( IOATAStandardCommand *cmd ); - bool stopDma( IOATAStandardCommand *cmd, UInt32 *transferCount ); - bool resetDma(); - bool checkDmaActive(); - -private: - bool identifyController(); - - bool calculatePIOTiming( UInt32 deviceNum, ATATiming *timing ); - bool calculateDMATiming( UInt32 deviceNum, ATATiming *timing ); - - bool calculateUltra66PIOTiming( UInt32 deviceNum, ATATiming *timing ); - bool calculateUltra66DMATiming( UInt32 deviceNum, ATATiming *timing ); - bool calculateUltra66UDMATiming( UInt32 deviceNum, ATATiming *timing ); - -private: - IOService *provider; - - IOMemoryMap *ioMapATA; - volatile UInt32 *ioBaseATA; - - IOMemoryMap *ioMapDMA; - volatile IODBDMAChannelRegisters *ioBaseDMA; - - UInt32 controllerType; - - IOInterruptEventSource *interruptEventSource; - - UInt32 ideTimingWord[2]; - - IOBigMemoryCursor *dmaMemoryCursor; - IODBDMADescriptor *dmaDescriptors; - UInt32 dmaDescriptorsPhys; - UInt32 numDescriptors; - - void *bitBucketAddr; - UInt32 bitBucketAddrPhys; - - UInt32 dmaReqLength; -}; - -/* - * - * - */ -#define kATACS3RegBase (16) - -enum -{ - kATASysClkNS = 30, - kATAUltra66ClockPS = (15 * 1000 / 2), // PCI 66 period / 2 (pS) - - kATAPioAccessBase = 0, - kATAPioAccessMin = 4, - kATAPioRecoveryBase = 4, - kATAPioRecoveryMin = 1, - - kATADmaAccessBase = 0, - kATADmaAccessMin = 1, - kATADmaRecoveryBase = 1, - kATADmaRecoveryMin = 1, -}; - -enum -{ - kControllerTypeDBDMAVersion1 = 1, - kControllerTypeDBDMAVersion2 = 2, - kControllerTypeUltra66DBDMA = 3, -}; diff --git a/iokit/Drivers/platform/drvAppleCuda/AppleCuda.cpp b/iokit/Drivers/platform/drvAppleCuda/AppleCuda.cpp deleted file mode 100644 index 248b41eba..000000000 --- a/iokit/Drivers/platform/drvAppleCuda/AppleCuda.cpp +++ /dev/null @@ -1,1534 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991 - * All Rights Reserved - * - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appears in all copies and - * that both the copyright notice and this permission notice appear in - * supporting documentation. - * - * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, - * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION - * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ -/* - * Copyright 1996 1995 by Apple Computer, Inc. 1997 1996 1995 1994 1993 1992 1991 - * All Rights Reserved - * - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appears in all copies and - * that both the copyright notice and this permission notice appear in - * supporting documentation. - * - * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, - * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION - * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -/* - * MKLINUX-1.0DR2 - */ - -/* 1 April 1997 Simon Douglas: - * Stolen wholesale from MkLinux. - * Added nonblocking adb poll from interrupt level for the debugger. - * Acknowledge before response so polled mode can work from inside the adb handler. - * - * 18 June 1998 sdouglas - * Start IOKit version. Fix errors from kCudaSRQAssertMask. Use ool cmd & reply buffers, - * not fixed len in packet. Does queueing here. - * - * 20 Nov 1998 suurballe - * Port to C++ - */ - - -#include "AppleCuda.h" -#include "AppleCudaUserClient.h" -#include "IOCudaADBController.h" -#include -#include -#include -#include -#include -#include -#include - -#include - -#define super IOService -OSDefineMetaClassAndStructors(AppleCuda,IOService) - -static void cuda_interrupt ( AppleCuda * self ); - -static void cuda_process_response(AppleCuda * self); -static void cuda_transmit_data(AppleCuda * self); -static void cuda_expected_attention(AppleCuda * self); -static void cuda_unexpected_attention(AppleCuda * self); -static void cuda_receive_data(AppleCuda * self); -static void cuda_receive_last_byte(AppleCuda * self); -static void cuda_collision(AppleCuda * self); -static void cuda_idle(AppleCuda * self); - -static void cuda_poll(AppleCuda * self); -static void cuda_error(AppleCuda * self); -static void cuda_send_request(AppleCuda * self); -static IOReturn cuda_do_sync_request( AppleCuda * self, - cuda_request_t * request, bool polled); -static void cuda_do_state_transition_delay(AppleCuda * self); - -static int Cuda_PE_poll_input(unsigned int options, char * c); -static int Cuda_PE_read_write_time_of_day(unsigned int options, long * secs); -static int Cuda_PE_halt_restart(unsigned int type); -static int Cuda_PE_write_IIC(unsigned char addr, unsigned char reg, - unsigned char data); - -static void -autopollArrived ( OSObject *inCuda, IOInterruptEventSource *, int ); - -static int set_cuda_power_message ( int command ); -static int set_cuda_file_server_mode ( int command ); -static int set_cuda_poweruptime(long secs); -static void cuda_async_set_power_message_enable( thread_call_param_t param, thread_call_param_t ); -static void cuda_async_set_file_server_mode( thread_call_param_t param, thread_call_param_t ) ; - -bool CudahasRoot( OSObject * us, void *, IOService * yourDevice ); - - -// -// inline functions -// - -static __inline__ unsigned char cuda_read_data(AppleCuda * self) -{ - volatile unsigned char val; - - val = *self->cuda_via_regs.shift; eieio(); - return val; -} - -static __inline__ int cuda_get_result(cuda_request_t *request) -{ - int status = ADB_RET_OK; - int theStatus = request->a_reply.a_header[1]; - - if ( theStatus & kCudaTimeOutMask ) { - status = ADB_RET_TIMEOUT; -#if 0 - // these are expected before autopoll mask is set - } else if ( theStatus & kCudaSRQAssertMask ) { - status = ADB_RET_UNEXPECTED_RESULT; -#endif - } else if ( theStatus & kCudaSRQErrorMask ) { - status = ADB_RET_REQUEST_ERROR; - } else if ( theStatus & kCudaBusErrorMask ) { - status = ADB_RET_BUS_ERROR; - } - - return status; -} - -static __inline__ void cuda_lock(AppleCuda * self) -{ - if( !self->cuda_polled_mode) - IOSimpleLockLock(self->cuda_request_lock); -} - -static __inline__ void cuda_unlock(AppleCuda * self) -{ - if( !self->cuda_polled_mode) - IOSimpleLockUnlock(self->cuda_request_lock); -} - -// -// -// - - -static AppleCuda * gCuda; -// ********************************************************************************** -// init -// -// ********************************************************************************** -bool AppleCuda::init ( OSDictionary * properties = 0 ) -{ -return super::init(properties); -} - - -// ********************************************************************************** -// start -// -// ********************************************************************************** -bool AppleCuda::start ( IOService * nub ) -{ -int i; -IOMemoryMap * viaMap; -unsigned char * cuda_base; - -if( !super::start(nub)) - return false; - -gCuda = this; - // callPlatformFunction symbols - cuda_check_any_interrupt = OSSymbol::withCString("cuda_check_any_interrupt"); - -workLoop = NULL; -eventSrc = NULL; -ourADBinterface = NULL; -_rootDomain = 0; -_wakeup_from_sleep = false; - -workLoop = IOWorkLoop::workLoop(); -if ( !workLoop ) { - kprintf("Start is bailing\n"); - return false; -} - -eventSrc = IOInterruptEventSource::interruptEventSource(this, autopollArrived); -if (!eventSrc || - kIOReturnSuccess != workLoop->addEventSource(eventSrc) ) { - kprintf("Start is bailing\n"); - return false; -} - -if( 0 == (viaMap = nub->mapDeviceMemoryWithIndex( 0 )) ) { - IOLog("%s: no via memory\n", getName()); - kprintf("Start is bailing\n"); - return false; -} -cuda_base = (unsigned char *)viaMap->getVirtualAddress(); - -kprintf("VIA base = %08x\n", (UInt32)cuda_base); -ourADBinterface = new IOCudaADBController; -if ( !ourADBinterface ) { - kprintf("Start is bailing\n"); - return false; -} -if ( !ourADBinterface->init(0,this) ) { - kprintf("Start is bailing\n"); - return false; -} - -if ( !ourADBinterface->attach( this) ) { - kprintf("Start is bailing\n"); - return false; -} - -cuda_request_lock = IOSimpleLockAlloc(); -IOSimpleLockInit(cuda_request_lock); - -cuda_via_regs.dataB = cuda_base; -cuda_via_regs.handshakeDataA = cuda_base+0x0200; -cuda_via_regs.dataDirectionB = cuda_base+0x0400; -cuda_via_regs.dataDirectionA = cuda_base+0x0600; -cuda_via_regs.timer1CounterLow = cuda_base+0x0800; -cuda_via_regs.timer1CounterHigh = cuda_base+0x0A00; -cuda_via_regs.timer1LatchLow = cuda_base+0x0C00; -cuda_via_regs.timer1LatchHigh = cuda_base+0x0E00; -cuda_via_regs.timer2CounterLow = cuda_base+0x1000; -cuda_via_regs.timer2CounterHigh = cuda_base+0x1200; -cuda_via_regs.shift = cuda_base+0x1400; -cuda_via_regs.auxillaryControl = cuda_base+0x1600; -cuda_via_regs.peripheralControl = cuda_base+0x1800; -cuda_via_regs.interruptFlag = cuda_base+0x1A00; -cuda_via_regs.interruptEnable = cuda_base+0x1C00; -cuda_via_regs.dataA = cuda_base+0x1E00; - -// we require delays of this duration between certain state transitions -clock_interval_to_absolutetime_interval(200, 1, &cuda_state_transition_delay); - -// Set the direction of the cuda signals. ByteACk and TIP are output and -// TREQ is an input - -*cuda_via_regs.dataDirectionB |= (kCudaByteAcknowledgeMask | kCudaTransferInProgressMask); -*cuda_via_regs.dataDirectionB &= ~kCudaTransferRequestMask; - -// Set the clock control. Set to shift data in by external clock CB1. - -*cuda_via_regs.auxillaryControl = (*cuda_via_regs.auxillaryControl | kCudaTransferMode) & - kCudaSystemRecieve; - -// Clear any posible cuda interupt. - -if ( *cuda_via_regs.shift ); - -// Initialize the internal data. - -cuda_interrupt_state = CUDA_STATE_IDLE; -cuda_transaction_state = CUDA_TS_NO_REQUEST; -cuda_is_header_transfer = false; -cuda_is_packet_type = false; -cuda_transfer_count = 0; -cuda_current_response = NULL; -for( i = 0; i < NUM_AP_BUFFERS; i++ ) { - cuda_unsolicited[ i ].a_buffer = cuda_autopoll_buffers[ i ]; -} - -// Terminate transaction and set idle state - -cuda_neg_tip_and_byteack(this); - -// we want to delay 4 mS for ADB reset to complete - -IOSleep( 4 ); - -// Clear pending interrupt if any... - -(void)cuda_read_data(this); - -// Issue a Sync Transaction, ByteAck asserted while TIP is negated. - -cuda_assert_byte_ack(this); - -// Wait for the Sync acknowledgement, cuda to assert TREQ - -cuda_wait_for_transfer_request_assert(this); - -// Wait for the Sync acknowledgement interrupt. - -cuda_wait_for_interrupt(this); - -// Clear pending interrupt - -(void)cuda_read_data(this); - -// Terminate the sync cycle by Negating ByteAck - -cuda_neg_byte_ack(this); - -// Wait for the Sync termination acknowledgement, cuda negates TREQ. - -cuda_wait_for_transfer_request_neg(this); - -// Wait for the Sync termination acknowledgement interrupt. - -cuda_wait_for_interrupt(this); - -// Terminate transaction and set idle state, TIP negate and ByteAck negate. -cuda_neg_transfer_in_progress(this); - -// Clear pending interrupt, if there is one... -(void)cuda_read_data(this); - -#if 0 - cuda_polled_mode = true; -#else -#define VIA_DEV_CUDA 2 -nub->registerInterrupt(VIA_DEV_CUDA, - this, (IOInterruptAction) cuda_interrupt); -nub->enableInterrupt(VIA_DEV_CUDA); -#endif - -PE_poll_input = Cuda_PE_poll_input; -PE_read_write_time_of_day = Cuda_PE_read_write_time_of_day; -PE_halt_restart = Cuda_PE_halt_restart; -PE_write_IIC = Cuda_PE_write_IIC; -publishResource( "IOiic0", this ); -publishResource( "IORTC", this ); - - -//set_cuda_power_message(kADB_powermsg_enable); //won't work on beige G3 -thread_call_func(cuda_async_set_power_message_enable, (thread_call_param_t)this, true); -thread_call_func(cuda_async_set_file_server_mode, (thread_call_param_t)this, true); - - registerService(); //Gossamer needs to find this driver for waking up G3 - - _cuda_power_state = 1; //default is wake state - //We want to know when sleep is about to occur - addNotification( gIOPublishNotification,serviceMatching("IOPMrootDomain"), - (IOServiceNotificationHandler)CudahasRoot, this, 0 ); - -ourADBinterface->start( this ); - -return true; -} - -/* Here are some power management functions so we can tell when system is - going to sleep. */ -bool CudahasRoot( OSObject * us, void *, IOService * yourDevice ) -{ - if (( yourDevice != NULL ) && ((AppleCuda *)us)->_rootDomain == 0) - { - ((AppleCuda *)us)->_rootDomain = (IOPMrootDomain *) yourDevice; - ((IOPMrootDomain *)yourDevice)->registerInterestedDriver((IOService *) us); - } - return true; -} - -IOReturn AppleCuda::powerStateWillChangeTo ( IOPMPowerFlags theFlags, unsigned long unused1, - IOService* unused2) -{ - if ( ! (theFlags & IOPMPowerOn) ) - { - _cuda_power_state = 0; //0 means sleeping - } - return IOPMAckImplied; -} - -IOReturn AppleCuda::powerStateDidChangeTo ( IOPMPowerFlags theFlags, unsigned long unused1, - IOService* unused2) -{ - if (theFlags & IOPMPowerOn) - { - _cuda_power_state = 1; //1 means awake - _wakeup_from_sleep = false; //normally it is false - } - return IOPMAckImplied; -} - - - -// ***************************************************************************** -// getWorkLoop -// -// Return the cuda's workloop. -// -// ***************************************************************************** -IOWorkLoop *AppleCuda::getWorkLoop() const -{ - return workLoop; -} - -// ***************************************************************************** -// free -// -// Release everything we may have allocated. -// -// ***************************************************************************** -void AppleCuda::free ( void ) -{ -if ( workLoop ) { - workLoop->release(); -} -if ( eventSrc ) { - eventSrc->release(); -} -if ( ourADBinterface ) { - ourADBinterface->release(); -} - if (_rootDomain) - { - _rootDomain->deRegisterInterestedDriver((IOService *) this); - _rootDomain = 0; - } -super::free(); -} - - -// ********************************************************************************** -// registerForADBInterrupts -// -// Some driver is calling to say it is prepared to receive "unsolicited" adb -// interrupts (e.g. autopoll keyboard and trackpad data). The parameters identify -// who to call when we get one. -// ********************************************************************************** -void AppleCuda::registerForADBInterrupts ( ADB_callback_func handler, IOService * caller ) -{ -autopoll_handler = handler; -ADBid = caller; -} - - -// ********************************************************************************** -// autopollArrived -// -// ********************************************************************************** -static void autopollArrived ( OSObject * CudaDriver, IOInterruptEventSource *, int ) -{ -((AppleCuda *)CudaDriver)->serviceAutopolls(); -} - -#define RB_BOOT 1 /* Causes reboot, not halt. Is in xnu/bsd/sys/reboot.h */ -extern "C" { - void boot(int paniced, int howto, char * command); -} - - -static void cuda_async_set_power_message_enable( thread_call_param_t param, thread_call_param_t ) -{ - //AppleCuda * me = (AppleCuda *) param; - - set_cuda_power_message(kADB_powermsg_enable); -} - -static void cuda_async_set_file_server_mode( thread_call_param_t param, thread_call_param_t ) -{ - set_cuda_file_server_mode(1); -} - -// ********************************************************************************** -// serviceAutopolls -// We get here just before calling autopollHandler() in IOADBController.cpp -// ********************************************************************************** -void AppleCuda::serviceAutopolls ( void ) -{ -cuda_packet_t * response; - - while( inIndex != outIndex ) { - response = &cuda_unsolicited[ outIndex ]; - - //Check for power messages, which are handled differently from regular - // autopoll data coming from mouse or keyboard. - if (response->a_header[0] == ADB_PACKET_POWER) - { - unsigned char flag, cmd; - - flag = response->a_header[1]; - cmd = response->a_header[2]; - - if ((flag == kADB_powermsg_flag_chassis) - && (cmd == kADB_powermsg_cmd_chassis_off)) - { - thread_call_func(cuda_async_set_power_message_enable, - (thread_call_param_t)this, true); - - if (_rootDomain) - { - if (_cuda_power_state) - { - //Put system to sleep now - _rootDomain->receivePowerNotification (kIOPMSleepNow); - } - else //If asleep, wake up the system - { - //Tickle activity timer in root domain. This will not - // wake up machine that is in demand-sleep, but it will - // wake up an inactive system that dozed - _rootDomain->activityTickle(0,0); - } - } - } - else if ((flag == kADB_powermsg_flag_keyboardpwr) - && (cmd == kADB_powermsg_cmd_keyboardoff)) - { - //set_cuda_power_message(kADB_powermsg_continue); - //This needs to by async so Beige G3 ADB won't lock up - thread_call_func(cuda_async_set_power_message_enable, - (thread_call_param_t)this, true); - } - - } - if ( ADBid != NULL ) { - (*autopoll_handler)(ADBid,response->a_header[2],response->a_bcount,response->a_buffer); - } - - outIndex = (outIndex + 1) & (NUM_AP_BUFFERS - 1); - - } //end of while loop - -} - - -// ********************************************************************************** -// doSyncRequest -// -// ********************************************************************************** -IOReturn AppleCuda::doSyncRequest ( cuda_request_t * request ) -{ -return(cuda_do_sync_request(this, request, false)); -} - - -IOReturn AppleCuda::callPlatformFunction(const OSSymbol *functionName, - bool waitForFunction, - void *param1, void *param2, - void *param3, void *param4) -{ - if (functionName == cuda_check_any_interrupt) - { - bool *hasint; - - hasint = (bool *)param1; - *hasint = false; - - if (inIndex != outIndex) - { - *hasint = true; - } - - if (_wakeup_from_sleep) - { - *hasint = true; - } - return kIOReturnSuccess; - } - - return kIOReturnBadArgument; -} - - -void -AppleCuda::setWakeTime(UInt32 waketime) -{ - //Call this function with waketime=0 in order to allow normal sleep again - _wakeup_from_sleep = false; - if (waketime != 0) { - timerSrc = IOTimerEventSource::timerEventSource((OSObject*)this, WakeupTimeoutHandler); - - if (!timerSrc || (workLoop->addEventSource(timerSrc) != kIOReturnSuccess)) - { - IOLog("Cuda can not register timeout event\n"); - return; - } - - timerSrc->setTimeoutMS(waketime); - } -} - -static void -AppleCuda::WakeupTimeoutHandler(OSObject *object, IOTimerEventSource *timer) -{ - gCuda->_wakeup_from_sleep = true; - if (gCuda->_rootDomain) - { - gCuda->_rootDomain->activityTickle(0,0); - } -} - - -void -AppleCuda::setPowerOnTime(UInt32 newTime) -{ - long long_secs; - - if (newTime != 0) { - Cuda_PE_read_write_time_of_day(kPEReadTOD, &long_secs); - set_cuda_poweruptime((long)newTime + long_secs); - } -} - -void -AppleCuda::setFileServerMode(bool fileServerModeON) -{ - set_cuda_file_server_mode((int) fileServerModeON); -} - -void AppleCuda::demandSleepNow(void) -{ - if (_rootDomain) - { - _rootDomain->receivePowerNotification (kIOPMSleepNow); - } -} - -// -------------------------------------------------------------------------- -// -// Method: newUserClient -// -// Purpose: -// newUserClient is called by the IOKit manager to create the -// kernel receiver of a user request. The "type" is a qualifier -// shared between the kernel and user client class instances.. - -#define kAppleCudaUserClientMagicCookie 0x0C00DA - -IOReturn -AppleCuda::newUserClient(task_t owningTask, - void *securityToken, - UInt32 magicCookie, - IOUserClient **handler) -{ - IOReturn ioReturn = kIOReturnSuccess; - AppleCudaUserClient *client = NULL; - - IOLog("AppleCuda::newUserClient\n"); - - if (IOUserClient::clientHasPrivilege(securityToken, "root") != kIOReturnSuccess) { - IOLog("AppleCuda::newUserClient: Can't create user client, not privileged\n"); - return kIOReturnNotPrivileged; - } - - // Check that this is a user client type that we support. - // type is known only to this driver's user and kernel - // classes. It could be used, for example, to define - // read or write privileges. In this case, we look for - // a private value. - if (magicCookie == kAppleCudaUserClientMagicCookie) { - // Construct a new client instance for the requesting task. - // This is, essentially client = new AppleCudaUserClient; - // ... create metaclasses ... - // client->setTask(owningTask) - client = AppleCudaUserClient::withTask(owningTask); - if (client == NULL) { - ioReturn = kIOReturnNoResources; - IOLog("AppleCuda::newUserClient: Can't create user client\n"); - } - } - else { - ioReturn = kIOReturnInvalid; - IOLog("AppleCuda::newUserClient: bad magic cookie.\n"); - } - - if (ioReturn == kIOReturnSuccess) { - // Attach ourself to the client so that this client instance - // can call us. - if (client->attach(this) == false) { - ioReturn = kIOReturnError; - IOLog("AppleCuda::newUserClient: Can't attach user client\n"); - } - } - - if (ioReturn == kIOReturnSuccess) { - // Start the client so it can accept requests. - if (client->start(this) == false) { - ioReturn = kIOReturnError; - IOLog("AppleCuda::newUserClientt: Can't start user client\n"); - } - } - - if (ioReturn != kIOReturnSuccess && client != NULL) { - client->detach(this); - client->release(); - } - - *handler = client; - return (ioReturn); -} - -// ********************************************************************************** -// cuda_do_sync_request -// -// ********************************************************************************** -IOReturn cuda_do_sync_request ( AppleCuda * self, cuda_request_t * request, bool polled ) -{ - bool wasPolled = false; - IOInterruptState ints; - - if( !polled ) { - request->sync = IOSyncer::create(); - request->needWake = true; - } - - ints = IOSimpleLockLockDisableInterrupt(self->cuda_request_lock); - - if( polled ) { - wasPolled = self->cuda_polled_mode; - self->cuda_polled_mode = polled; - } - - if( self->cuda_last_request ) - self->cuda_last_request->a_next = request; - else - self->cuda_request = request; - - self->cuda_last_request = request; - - if( self->cuda_interrupt_state == CUDA_STATE_IDLE ) - cuda_send_request(self); - - if( polled ) { - cuda_poll(self); - self->cuda_polled_mode = wasPolled; - assert( 0 == self->cuda_request ); - assert( 0 == self->cuda_last_request ); - } - - IOSimpleLockUnlockEnableInterrupt(self->cuda_request_lock, ints); - - if( !polled) - request->sync->wait(); - - return cuda_get_result(request); -} - - -// ********************************************************************************** -// Cuda_PE_read_write_time_of_day -// -// ********************************************************************************** -static int Cuda_PE_read_write_time_of_day ( unsigned int options, long * secs ) -{ -cuda_request_t cmd; - -adb_init_request(&cmd); - -cmd.a_cmd.a_hcount = 2; -cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO; - -switch( options ) { - - case kPEReadTOD: - cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_GET_REAL_TIME; - cmd.a_reply.a_buffer = (UInt8 *)secs; - cmd.a_reply.a_bcount = sizeof(*secs); - break; - - case kPEWriteTOD: - cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_SET_REAL_TIME; - cmd.a_cmd.a_buffer = (UInt8 *)secs; - cmd.a_cmd.a_bcount = sizeof(*secs); - break; - - default: - return 1; -} - -return cuda_do_sync_request(gCuda, &cmd, true); -} - - -// ********************************************************************************** -// Cuda_PE_halt_restart -// -// ********************************************************************************** -static int Cuda_PE_halt_restart ( unsigned int type ) -{ -cuda_request_t cmd; - -adb_init_request(&cmd); - -cmd.a_cmd.a_hcount = 2; -cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO; - -switch( type ) { - - case kPERestartCPU: - cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_RESTART_SYSTEM; - break; - - case kPEHaltCPU: - cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_POWER_DOWN; - break; - - default: - return 1; - } - -return cuda_do_sync_request(gCuda, &cmd, true); -} - -// ********************************************************************************** -// Set the power-on time. 2001 -// ********************************************************************************** -static int set_cuda_poweruptime (long secs) -{ - cuda_request_t cmd; - long localsecs = secs; - - adb_init_request(&cmd); - - cmd.a_cmd.a_hcount = 2; - cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO; - - cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_SET_POWER_UPTIME; - cmd.a_cmd.a_buffer = (UInt8 *)&localsecs; - cmd.a_cmd.a_bcount = 4; - - return cuda_do_sync_request(gCuda, &cmd, true); -} - - -// ********************************************************************************** -// In case this machine loses power, it will automatically reboot when power is -// restored. Only desktop machines have Cuda, so this feature will not affect -// PowerBooks. -// ********************************************************************************** -static int set_cuda_file_server_mode ( int command ) -{ -cuda_request_t cmd; - -adb_init_request(&cmd); - -cmd.a_cmd.a_hcount = 3; -cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO; -cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_FILE_SERVER_FLAG; -cmd.a_cmd.a_header[2] = command; - -return cuda_do_sync_request(gCuda, &cmd, true); -} - -// ********************************************************************************** -// Fix front panel power key (mostly on Yosemites) so that one press won't power -// down the entire machine -// -// ********************************************************************************** -static int set_cuda_power_message ( int command ) -{ -cuda_request_t cmd; - -if (command >= kADB_powermsg_invalid) - return 0; //invalid Cuda power request - -adb_init_request(&cmd); - -cmd.a_cmd.a_hcount = 3; -cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO; -cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_SET_POWER_MESSAGES; -cmd.a_cmd.a_header[2] = command; - -return cuda_do_sync_request(gCuda, &cmd, true); -} - - -// ********************************************************************************** -// Cuda_PE_write_IIC -// -// ********************************************************************************** -static int Cuda_PE_write_IIC ( unsigned char addr, unsigned char reg, unsigned char data ) -{ -cuda_request_t cmd; - -adb_init_request(&cmd); - -cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO; -cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_GET_SET_IIC; -cmd.a_cmd.a_header[2] = addr; -cmd.a_cmd.a_header[3] = reg; -cmd.a_cmd.a_header[4] = data; -cmd.a_cmd.a_hcount = 5; - -return cuda_do_sync_request(gCuda, &cmd, true); -} - -IOReturn -AppleCudaWriteIIC( UInt8 address, const UInt8 * buffer, IOByteCount * count ) -{ - IOReturn ret; - cuda_request_t cmd; - - if( !gCuda) - return( kIOReturnUnsupported ); - - adb_init_request(&cmd); - - cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO; - cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_GET_SET_IIC; - cmd.a_cmd.a_header[2] = address; - cmd.a_cmd.a_hcount = 3; - cmd.a_cmd.a_buffer = (UInt8 *) buffer; - cmd.a_cmd.a_bcount = *count; - - ret = cuda_do_sync_request(gCuda, &cmd, true); - - *count = cmd.a_cmd.a_bcount; - - return( ret ); -} - -IOReturn -AppleCudaReadIIC( UInt8 address, UInt8 * buffer, IOByteCount * count ) -{ - IOReturn ret; - cuda_request_t cmd; - - if( !gCuda) - return( kIOReturnUnsupported ); - - adb_init_request(&cmd); - - cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO; - cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_GET_SET_IIC; - cmd.a_cmd.a_header[2] = address; - cmd.a_cmd.a_hcount = 3; - cmd.a_reply.a_buffer = buffer; - cmd.a_reply.a_bcount = *count; - - ret = cuda_do_sync_request(gCuda, &cmd, true); - *count = cmd.a_reply.a_bcount; - - return( ret ); -} - - -// ********************************************************************************** -// Cuda_PE_poll_input -// -// ********************************************************************************** -static int Cuda_PE_poll_input ( unsigned int, char * c ) -{ -AppleCuda * self = gCuda; -int interruptflag; -UInt8 code; -cuda_packet_t * response; //0123456789abcdef -static char keycodes2ascii[] = "asdfhgzxcv_bqwer" //00 - "yt123465=97-80]o" //10 - "u[ip\nlj'k;_,/nm." //20 - "\t_"; //30 - -*c = 0xff; - -if( !self ) { - return 1; -} - -self->cuda_polled_mode = true; -interruptflag = *self->cuda_via_regs.interruptFlag & kCudaInterruptMask; -eieio(); -if( interruptflag ) { - cuda_interrupt(self); -} - -if( self->inIndex != self->outIndex ) { - response = &self->cuda_unsolicited[ self->outIndex ]; - if( ((response->a_header[2] >> 4) == 2) - && (response->a_bcount > 1) ) { - code = response->a_buffer[0]; - if( code < sizeof(keycodes2ascii) ) { - *c = keycodes2ascii[ code ]; - } - } - self->outIndex = self->inIndex; -} - -self->cuda_polled_mode = false; -return 0; -} - - -// -// internal -// - - -// ********************************************************************************** -// cuda_send_request -// -// ********************************************************************************** -static void cuda_send_request ( AppleCuda * self ) -{ - - // The data register must written with the data byte 25uS - // after examining TREQ or we run the risk of getting out of sync - // with Cuda. So call with disabled interrupts and spinlock held. - - // Check if we can commence with the packet transmission. First, check if - // Cuda can service our request now. Second, check if Cuda wants to send - // a response packet now. - -if( !cuda_is_transfer_in_progress(self) ) { - // Set the shift register direction to output to Cuda by setting - // the direction bit. - - cuda_set_data_direction_to_output(self); - - // Write the first byte to the shift register - cuda_write_data(self, self->cuda_request->a_cmd.a_header[0]); - - // Set up the transfer state info here. - - self->cuda_is_header_transfer = true; - self->cuda_transfer_count = 1; - - // Make sure we're in idle state before transaction, and then - // assert TIP to tell Cuda we're starting command - cuda_neg_byte_ack(self); - cuda_assert_transfer_in_progress(self); - - // The next state is going to be a transmit state, if there is - // no collision. This is a requested response but call it sync. - - self->cuda_interrupt_state = CUDA_STATE_TRANSMIT_EXPECTED; - self->cuda_transaction_state = CUDA_TS_SYNC_RESPONSE; -} - -#if 0 -else { - IOLog("Req = %x, state = %x, TIP = %x\n", self->cuda_request, - self->cuda_interrupt_state, cuda_is_transfer_in_progress(self)); -} -#endif -} - - -// ********************************************************************************** -// cuda_poll -// -// ********************************************************************************** -static void cuda_poll( AppleCuda * self ) -{ - do { - cuda_wait_for_interrupt(self); - cuda_interrupt(self); - } while( self->cuda_interrupt_state != CUDA_STATE_IDLE ); -} - -// -// cuda_process_response -// Execute at secondary interrupt. -// - - -// ********************************************************************************** -// cuda_process_response -// -// ********************************************************************************** -static void cuda_process_response ( AppleCuda * self ) -{ -volatile cuda_request_t * request; -unsigned int newIndex; - - // Almost ready for the next state, which should be a Idle state. - // Just need to notifiy the client. - -if ( self->cuda_transaction_state == CUDA_TS_SYNC_RESPONSE ) { - - // dequeue reqeuest - cuda_lock(self); - request = self->cuda_request; - if( NULL == (self->cuda_request = request->a_next) ) { - self->cuda_last_request = NULL; - } - cuda_unlock(self); - - // wake the sync request thread - if ( ((cuda_request_t *)request)->needWake ) { - ((cuda_request_t *)request)->sync->signal(); - } - -} -else { - if ( self->cuda_transaction_state == CUDA_TS_ASYNC_RESPONSE ) { - newIndex = (self->inIndex + 1) & (NUM_AP_BUFFERS - 1); - if( newIndex != self->outIndex ) { - self->inIndex = newIndex; - } - else { - // drop this packet, and reuse the buffer - } - if ( !self->cuda_polled_mode ) { - // wake thread to service autopolls - self->eventSrc->interruptOccurred(0, 0, 0); - } - } -} -return; -} - - -// ********************************************************************************** -// cuda_interrupt -// -// ********************************************************************************** -static void cuda_interrupt ( AppleCuda * self ) -{ -unsigned char interruptState; - - // Get the relevant signal in determining the cause of the interrupt: - // the shift direction, the transfer request line and the transfer - // request line. - -interruptState = cuda_get_interrupt_state(self); - -//kprintf("%02x",interruptState); - -switch ( interruptState ) { - case kCudaReceiveByte: - cuda_receive_data(self); - break; - - case kCudaReceiveLastByte: - cuda_receive_last_byte(self); - break; - - case kCudaTransmitByte: - cuda_transmit_data(self); - break; - - case kCudaUnexpectedAttention: - cuda_unexpected_attention(self); - break; - - case kCudaExpectedAttention: - cuda_expected_attention(self); - break; - - case kCudaIdleState: - cuda_idle(self); - break; - - case kCudaCollision: - cuda_collision(self); - break; - - // Unknown interrupt, clear it and leave. - default: - cuda_error(self); - break; -} -} - -// -// TransmitCudaData -// Executes at hardware interrupt level. -// - -// ********************************************************************************** -// cuda_transmit_data -// -// ********************************************************************************** -static void cuda_transmit_data ( AppleCuda * self ) -{ - // Clear the pending interrupt by reading the shift register. - -if ( self->cuda_is_header_transfer ) { - // There are more header bytes, write one out. - cuda_write_data(self, self->cuda_request->a_cmd.a_header[self->cuda_transfer_count++]); - - // Toggle the handshake line. - if ( self->cuda_transfer_count >= self->cuda_request->a_cmd.a_hcount ) { - self->cuda_is_header_transfer = FALSE; - self->cuda_transfer_count = 0; - } - - cuda_toggle_byte_ack( self); -} -else { - if ( self->cuda_transfer_count < self->cuda_request->a_cmd.a_bcount ) { - // There are more command bytes, write one out and update the pointer - cuda_write_data( self, - *(self->cuda_request->a_cmd.a_buffer + self->cuda_transfer_count++)); - // Toggle the handshake line. - cuda_toggle_byte_ack(self); - } - else { - (void)cuda_read_data(self); - // There is no more command bytes, terminate the send transaction. - // Cuda should send a expected attention interrupt soon. - - cuda_neg_tip_and_byteack(self); - - // The next interrupt should be a expected attention interrupt. - - self->cuda_interrupt_state = CUDA_STATE_ATTN_EXPECTED; - } -} -} - -// -// cuda_expected_attention -// Executes at hardware interrupt level. -// - - -// ********************************************************************************** -// cuda_expected_attention -// -// ********************************************************************************** -static void cuda_expected_attention ( AppleCuda * self ) -{ - // Clear the pending interrupt by reading the shift register. - -(void)cuda_read_data(self); - - // Allow the VIA to settle directions.. else the possibility of - // data corruption. -cuda_do_state_transition_delay(self); - -if ( self->cuda_transaction_state == CUDA_TS_SYNC_RESPONSE ) { - self->cuda_current_response = (cuda_packet_t*)&self->cuda_request->a_reply; -} -else { - self->cuda_current_response = &self->cuda_unsolicited[ self->inIndex ]; - self->cuda_current_response->a_hcount = 0; - self->cuda_current_response->a_bcount = MAX_AP_RESPONSE; -} - -self->cuda_is_header_transfer = true; -self->cuda_is_packet_type = true; -self->cuda_transfer_count = 0; - - // Set the shift register direction to input. -cuda_set_data_direction_to_input(self); - - // Start the response packet transaction. -cuda_assert_transfer_in_progress(self); - - // The next interrupt should be a receive data interrupt. -self->cuda_interrupt_state = CUDA_STATE_RECEIVE_EXPECTED; -} - -// -// cuda_unexpected_attention -// Executes at hardware interrupt level. -// - - -// ********************************************************************************** -// cuda_expected_attention -// -// ********************************************************************************** -static void cuda_unexpected_attention ( AppleCuda * self ) -{ - // Clear the pending interrupt by reading the shift register. -(void)cuda_read_data(self); - - // Get ready for a unsolicited response. -self->cuda_current_response = &self->cuda_unsolicited[ self->inIndex ]; -self->cuda_current_response->a_hcount = 0; -self->cuda_current_response->a_bcount = MAX_AP_RESPONSE; - -self->cuda_is_header_transfer = TRUE; -self->cuda_is_packet_type = TRUE; -self->cuda_transfer_count = 0; - - // Start the response packet transaction, Transaction In Progress -cuda_assert_transfer_in_progress(self); - - // The next interrupt should be a receive data interrupt and the next - // response should be an async response. - -self->cuda_interrupt_state = CUDA_STATE_RECEIVE_EXPECTED; - -self->cuda_transaction_state = CUDA_TS_ASYNC_RESPONSE; -} - -// -// cuda_receive_data -// Executes at hardware interrupt level. -// - - -// ********************************************************************************** -// cuda_receive_data -// -// ********************************************************************************** -static void cuda_receive_data ( AppleCuda * self ) -{ -if ( self->cuda_is_packet_type ) { - unsigned char packetType; - - packetType = cuda_read_data( self); - self->cuda_current_response->a_header[self->cuda_transfer_count++] = packetType; - - if ( packetType == ADB_PACKET_ERROR) { - self->cuda_current_response->a_hcount = 4; - } - else { - self->cuda_current_response->a_hcount = 3; - } - - self->cuda_is_packet_type = false; - - cuda_toggle_byte_ack(self); - -} -else { - - - if ( self->cuda_is_header_transfer ) { - - self->cuda_current_response->a_header[self->cuda_transfer_count++] = - cuda_read_data(self); - - if (self->cuda_transfer_count >= self->cuda_current_response->a_hcount) { - self->cuda_is_header_transfer = FALSE; - self->cuda_transfer_count = 0; - } - - cuda_toggle_byte_ack(self); - } - else { - if ( self->cuda_transfer_count < self->cuda_current_response->a_bcount ) { - // Still room for more bytes. Get the byte and tell Cuda to continue. - // Toggle the handshake line, ByteAck, to acknowledge receive. - - *(self->cuda_current_response->a_buffer + self->cuda_transfer_count++) = - cuda_read_data(self); - cuda_toggle_byte_ack(self); - - } - else { - // Cuda is still sending data but the buffer is full. - // Normally should not get here. The only exceptions are open ended - // request such as PRAM read... In any event time to exit. - - self->cuda_current_response->a_bcount = self->cuda_transfer_count; - - cuda_read_data(self); - - cuda_process_response(self); - cuda_neg_tip_and_byteack(self); - } - } -} -} - - -// -// cuda_receive_last_byte -// Executes at hardware interrupt level. -// - - -// ********************************************************************************** -// cuda_receive_last_byte -// -// ********************************************************************************** -static void cuda_receive_last_byte ( AppleCuda * self ) -{ - -if ( self->cuda_is_header_transfer ) { - self->cuda_current_response->a_header[self->cuda_transfer_count++] = - cuda_read_data(self); - - self->cuda_transfer_count = 0; - } -else { - if ( self->cuda_transfer_count < self->cuda_current_response->a_bcount ) { - *(self->cuda_current_response->a_buffer + self->cuda_transfer_count++) = - cuda_read_data(self); - } - else { - /* Overrun -- ignore data */ - (void) cuda_read_data(self); - } -} -self->cuda_current_response->a_bcount = self->cuda_transfer_count; - // acknowledge before response so polled mode can work - // from inside the handler -cuda_neg_tip_and_byteack(self); -cuda_process_response(self); -} - - -// -// cuda_collision -// Executes at hardware interrupt level. -// - - -// ********************************************************************************** -// cuda_collision -// -// ********************************************************************************** -static void cuda_collision ( AppleCuda * self ) -{ -// Clear the pending interrupt by reading the shift register. -(void)cuda_read_data(self); - -// Negate TIP to abort the send. Cuda should send a second attention -// interrupt to acknowledge the abort cycle. -cuda_neg_transfer_in_progress(self); - -// The next interrupt should be an expected attention and the next -// response packet should be an async response. - -self->cuda_interrupt_state = CUDA_STATE_ATTN_EXPECTED; -self->cuda_transaction_state = CUDA_TS_ASYNC_RESPONSE; - -/* queue the request */ -self->cuda_is_header_transfer = false; -self->cuda_transfer_count = 0; -} - - -// -// -// Executes at hardware interrupt level. -// - - -// ********************************************************************************** -// cuda_idle -// -// ********************************************************************************** -static void cuda_idle ( AppleCuda * self ) -{ - -// Clear the pending interrupt by reading the shift register. -(void)cuda_read_data(self); - -cuda_lock(self); - // Set to the idle state. -self->cuda_interrupt_state = CUDA_STATE_IDLE; - // See if there are any pending requests. -if( self->cuda_request ) { - cuda_send_request(self); -} -cuda_unlock(self); -} - - -// ********************************************************************************** -// cuda_error -// -// ********************************************************************************** -static void cuda_error ( AppleCuda * self ) -{ -//printf("{Error %d}", self->cuda_transaction_state); - -// Was looking at cuda_transaction_state - doesn't seem right - -switch ( self->cuda_interrupt_state ) { - case CUDA_STATE_IDLE: - cuda_neg_tip_and_byteack(self); - break; - - case CUDA_STATE_TRANSMIT_EXPECTED: - if ( self->cuda_is_header_transfer && self->cuda_transfer_count <= 1 ) { - cuda_do_state_transition_delay(self); - cuda_neg_transfer_in_progress(self); - cuda_set_data_direction_to_input(self); - panic ("CUDA - TODO FORCE COMMAND BACK UP!\n"); - } - else { - self->cuda_interrupt_state = CUDA_STATE_ATTN_EXPECTED; - cuda_neg_tip_and_byteack(self); - } - break; - - case CUDA_STATE_ATTN_EXPECTED: - cuda_assert_transfer_in_progress(self); - - cuda_do_state_transition_delay(self); - cuda_set_data_direction_to_input(self); - cuda_neg_transfer_in_progress(self); - panic("CUDA - TODO CHECK FOR TRANSACTION TYPE AND ERROR"); - break; - - case CUDA_STATE_RECEIVE_EXPECTED: - cuda_neg_tip_and_byteack(self); - panic("Cuda - todo check for transaction type and error"); - break; - - default: - cuda_set_data_direction_to_input(self); - cuda_neg_tip_and_byteack(self); - break; -} -} - -static void cuda_do_state_transition_delay( AppleCuda * self ) -{ - AbsoluteTime deadline; - - clock_absolutetime_interval_to_deadline( - self->cuda_state_transition_delay, &deadline); - clock_delay_until(deadline); -} diff --git a/iokit/Drivers/platform/drvAppleCuda/AppleCuda.h b/iokit/Drivers/platform/drvAppleCuda/AppleCuda.h deleted file mode 100644 index 7c79a6921..000000000 --- a/iokit/Drivers/platform/drvAppleCuda/AppleCuda.h +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991 - * All Rights Reserved - * - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appears in all copies and - * that both the copyright notice and this permission notice appear in - * supporting documentation. - * - * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, - * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION - * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ -/* - * Copyright 1996 1995 by Apple Computer, Inc. 1997 1996 1995 1994 1993 1992 1991 - * All Rights Reserved - * - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appears in all copies and - * that both the copyright notice and this permission notice appear in - * supporting documentation. - * - * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, - * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION - * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -/* - * MKLINUX-1.0DR2 - */ - -/* 1 April 1997 Simon Douglas: - * Stolen wholesale from MkLinux. - * Added nonblocking adb poll from interrupt level for the debugger. - * Acknowledge before response so polled mode can work from inside the adb handler. - * - * 18 June 1998 sdouglas - * Start IOKit version. Fix errors from kCudaSRQAssertMask. Use ool cmd & reply buffers, - * not fixed len in packet. Does queueing here. - * - * 20 Nov 1998 suurballe - * Port to C++ - */ - -#ifndef APPLECUDA_H -#define APPLECUDA_H - -#include - -#include - -extern "C" { -#include -} -#include -#include "AppleCudaCommands.h" -#include "AppleCudaHW.h" -#include -#include -#include - -// -// CudaInterruptState - internal to CudaCore.c -// - -enum CudaInterruptState -{ - CUDA_STATE_INTERRUPT_LIMBO = -1, // - CUDA_STATE_IDLE = 0, // - CUDA_STATE_ATTN_EXPECTED = 1, // - CUDA_STATE_TRANSMIT_EXPECTED = 2, // - CUDA_STATE_RECEIVE_EXPECTED = 3 // -}; - -typedef enum CudaInterruptState CudaInterruptState; - -// -// CudaTransactionFlag - internal to CudaCore.c -// - -enum CudaTransactionFlag -{ - CUDA_TS_NO_REQUEST = 0x0000, - CUDA_TS_SYNC_RESPONSE = 0x0001, - CUDA_TS_ASYNC_RESPONSE = 0x0002 -}; - -typedef enum CudaTransactionFlag CudaTransactionFlag; - -//typedef void (* ADB_input_func)(IOService * obj_id, UInt8 * buffer, UInt32 length, UInt8 command); - -class IOCudaADBController; -class IOInterruptEventSource; -class IOWorkLoop; - - -class AppleCuda: public IOService -{ -OSDeclareDefaultStructors(AppleCuda) - -private: - -IOService * cudaDevice; -IOWorkLoop * workLoop; -IOService * ADBid; -IOCudaADBController * ourADBinterface; -ADB_callback_func autopoll_handler; -UInt8 _cuda_power_state; -IOTimerEventSource * timerSrc; -bool _wakeup_from_sleep; -// callPlatformFunction symbols -const OSSymbol *cuda_check_any_interrupt; - - // number of autopoll buffers between interrupt and thread -#define NUM_AP_BUFFERS (1<<3) - // max adb register size for autopoll -#define MAX_AP_RESPONSE (8) - -unsigned char cuda_autopoll_buffers[ NUM_AP_BUFFERS ] - [ MAX_AP_RESPONSE ]; -static void WakeupTimeoutHandler(OSObject *object, IOTimerEventSource *timer); - -protected: - -virtual void free( void ); - -public: - -VIARegisterAddress cuda_via_regs; -bool cuda_polled_mode; -IOSimpleLock * cuda_request_lock; -volatile cuda_request_t * cuda_request; // head of todo queue -volatile cuda_request_t * cuda_last_request; // tail of todo queue -volatile CudaInterruptState cuda_interrupt_state; -volatile unsigned int inIndex; -volatile unsigned int outIndex; -volatile CudaTransactionFlag cuda_transaction_state; -cuda_packet_t cuda_unsolicited[ NUM_AP_BUFFERS ]; -bool cuda_is_header_transfer; -int cuda_transfer_count; -IOInterruptEventSource * eventSrc; -cuda_packet_t * cuda_current_response; -bool cuda_is_packet_type; -AbsoluteTime cuda_state_transition_delay; -IOPMrootDomain * _rootDomain; - -bool init ( OSDictionary * properties = 0 ); -bool start ( IOService * ); -virtual IOWorkLoop *getWorkLoop() const; -void serviceAutopolls ( void ); -void registerForADBInterrupts ( ADB_callback_func handler, IOService * caller ); -IOReturn doSyncRequest ( cuda_request_t * request ); -IOReturn powerStateWillChangeTo ( IOPMPowerFlags, unsigned long, IOService*); -IOReturn powerStateDidChangeTo ( IOPMPowerFlags, unsigned long, IOService*); -void setWakeTime(UInt32 waketime); -void setPowerOnTime(UInt32 newTime); -void setFileServerMode(bool fileServerModeON); -void demandSleepNow(void); -IOReturn newUserClient(task_t owningTask, void*, // Security id (?!) - UInt32 type, // Magic number - IOUserClient **handler); - -virtual IOReturn callPlatformFunction(const OSSymbol *functionName, - bool waitForFunction, - void *param1, void *param2, - void *param3, void *param4); - -}; - -#endif /* APPLECUDA_H */ - - diff --git a/iokit/Drivers/platform/drvAppleCuda/AppleCudaCommands.h b/iokit/Drivers/platform/drvAppleCuda/AppleCudaCommands.h deleted file mode 100644 index e9a76845f..000000000 --- a/iokit/Drivers/platform/drvAppleCuda/AppleCudaCommands.h +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991 - * All Rights Reserved - * - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appears in all copies and - * that both the copyright notice and this permission notice appear in - * supporting documentation. - * - * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, - * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION - * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ -/* - * Copyright 1996 1995 by Apple Computer, Inc. 1997 1996 1995 1994 1993 1992 1991 - * All Rights Reserved - * - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appears in all copies and - * that both the copyright notice and this permission notice appear in - * supporting documentation. - * - * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, - * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION - * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -/* - * MKLINUX-1.0DR2 - */ - -/* - * 18 June 1998 sdouglas - * Start IOKit version. - */ - -struct cuda_packet { - int a_hcount; - unsigned char a_header[8]; - int a_bcount; /* on entry size, on exit, actual */ - unsigned char * a_buffer; /* ool data */ -}; - -typedef struct cuda_packet cuda_packet_t; - -#ifdef __cplusplus -class IOSyncer; - -struct cuda_request { - cuda_packet_t a_cmd; /* Command packet */ - cuda_packet_t a_reply; /* Reply packet */ - volatile struct cuda_request* a_next; - IOSyncer * sync; - bool needWake; -}; - -typedef struct cuda_request cuda_request_t; - -#else - -struct cuda_request { - cuda_packet_t a_cmd; /* Command packet */ - cuda_packet_t a_reply; /* Reply packet */ - volatile struct cuda_request* a_next; - void * sync; -}; - -typedef struct cuda_request cuda_request_t; - -#endif - - -/* - * ADB Packet Types - */ - -#define ADB_PACKET_ADB 0 -#define ADB_PACKET_PSEUDO 1 -#define ADB_PACKET_ERROR 2 -#define ADB_PACKET_TIMER 3 -#define ADB_PACKET_POWER 4 -#define ADB_PACKET_MACIIC 5 - -/* - * ADB Device Commands - */ - -#define ADB_ADBCMD_RESET_BUS 0x00 -#define ADB_ADBCMD_FLUSH_ADB 0x01 -#define ADB_ADBCMD_WRITE_ADB 0x08 -#define ADB_ADBCMD_READ_ADB 0x0c - -/* - * ADB Pseudo Commands - */ - -#define ADB_PSEUDOCMD_WARM_START 0x00 -#define ADB_PSEUDOCMD_START_STOP_AUTO_POLL 0x01 -#define ADB_PSEUDOCMD_GET_6805_ADDRESS 0x02 -#define ADB_PSEUDOCMD_GET_REAL_TIME 0x03 -#define ADB_PSEUDOCMD_GET_PRAM 0x07 -#define ADB_PSEUDOCMD_SET_6805_ADDRESS 0x08 -#define ADB_PSEUDOCMD_SET_REAL_TIME 0x09 -#define ADB_PSEUDOCMD_POWER_DOWN 0x0a -#define ADB_PSEUDOCMD_SET_POWER_UPTIME 0x0b -#define ADB_PSEUDOCMD_SET_PRAM 0x0c -#define ADB_PSEUDOCMD_MONO_STABLE_RESET 0x0d -#define ADB_PSEUDOCMD_SEND_DFAC 0x0e -#define ADB_PSEUDOCMD_BATTERY_SWAP_SENSE 0x10 -#define ADB_PSEUDOCMD_RESTART_SYSTEM 0x11 -#define ADB_PSEUDOCMD_SET_IPL_LEVEL 0x12 -#define ADB_PSEUDOCMD_FILE_SERVER_FLAG 0x13 -#define ADB_PSEUDOCMD_SET_AUTO_RATE 0x14 -#define ADB_PSEUDOCMD_GET_AUTO_RATE 0x16 -#define ADB_PSEUDOCMD_SET_DEVICE_LIST 0x19 -#define ADB_PSEUDOCMD_GET_DEVICE_LIST 0x1a -#define ADB_PSEUDOCMD_SET_ONE_SECOND_MODE 0x1b -#define ADB_PSEUDOCMD_SET_POWER_MESSAGES 0x21 -#define ADB_PSEUDOCMD_GET_SET_IIC 0x22 -#define ADB_PSEUDOCMD_ENABLE_DISABLE_WAKEUP 0x23 -#define ADB_PSEUDOCMD_TIMER_TICKLE 0x24 -#define ADB_PSEUDOCMD_COMBINED_FORMAT_IIC 0X25 - -/* - * Following values to be used with ADB_PSEUDOCMD_SET_POWER_MESSAGES - */ -enum { - kADB_powermsg_disable = 0, - kADB_powermsg_enable, - kADB_powermsg_suspend, - kADB_powermsg_continue, - kADB_powermsg_debugger, - kADB_powermsg_timed_ADB, - kADB_powermsg_timed_power, - kADB_powermsg_invalid -}; - -//These constants are used to parse Cuda power message response -// packets, to see which selector transitioned -enum { - kADB_powermsg_flag_rotary = 0x20, - kADB_powermsg_flag_chassis = 0x02, - kADB_powermsg_flag_keyboardpwr = 0x04, - kADB_powermsg_cmd_chassis_off = 0x00, - kADB_powermsg_cmd_keyboardoff = 0x04, - kADB_powermsg_cmd_keyboardtimed = 0x00, - kADB_powermsg_cmd_rotary_lock = 0x01, - kADB_powermsg_cmd_rotary_unlock = 0x02 -}; - - -/* - * Macros to help build commands up - */ - -#define ADB_BUILD_CMD1(c, p1) {(c)->a_cmd.a_header[0] = p1; (c)->a_cmd.a_hcount = 1; } -#define ADB_BUILD_CMD2(c, p1, p2) {(c)->a_cmd.a_header[0] = p1; (c)->a_cmd.a_header[1] = p2; (c)->a_cmd.a_hcount = 2; } -#define ADB_BUILD_CMD3(c, p1, p2, p3) {(c)->a_cmd.a_header[0] = p1; (c)->a_cmd.a_header[1] = p2; (c)->a_cmd.a_header[2] = p3; (c)->a_cmd.a_hcount = 3; } - -#define ADB_BUILD_CMD4(c, p1, p2, p3, p4) {(c)->a_cmd.a_header[0] = p1; (c)->a_cmd.a_header[1] = p2; \ - (c)->a_cmd.a_header[2] = p3; (c)->a_cmd.a_header[3] = p4; (c)->a_cmd.a_hcount = 4; } -#if 0 -#define ADB_BUILD_CMD2_BUFFER(c, p1, p2, len, buf) {(c)->a_cmd.a_header[0] = p1; (c)->a_cmd.a_header[1] = p2; (c)->a_cmd.a_hcount = 2;\ - (c)->a_cmd.a_bcount = len;\ - memcpy(&(c)->a_cmd.a_buffer, buf, len); } - -#endif - -#define adb_init_request(a) { bzero((char *) a, sizeof(*a)); } - - - diff --git a/iokit/Drivers/platform/drvAppleCuda/AppleCudaHW.h b/iokit/Drivers/platform/drvAppleCuda/AppleCudaHW.h deleted file mode 100644 index 5c4ceb50a..000000000 --- a/iokit/Drivers/platform/drvAppleCuda/AppleCudaHW.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991 - * All Rights Reserved - * - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appears in all copies and - * that both the copyright notice and this permission notice appear in - * supporting documentation. - * - * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, - * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION - * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ -/* - * Copyright 1996 1995 by Apple Computer, Inc. 1997 1996 1995 1994 1993 1992 1991 - * All Rights Reserved - * - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appears in all copies and - * that both the copyright notice and this permission notice appear in - * supporting documentation. - * - * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, - * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION - * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -/* - * MKLINUX-1.0DR2 - */ -/* - * 18 June 1998 sdouglas - * Start IOKit version. - */ - -#include "AppleVIA6522.h" - -typedef struct VIARegisterAddress VIARegisterAddress; - -struct VIARegisterAddress -{ - volatile unsigned char* dataB; - volatile unsigned char* handshakeDataA; - volatile unsigned char* dataDirectionB; - volatile unsigned char* dataDirectionA; - volatile unsigned char* timer1CounterLow; - volatile unsigned char* timer1CounterHigh; - volatile unsigned char* timer1LatchLow; - volatile unsigned char* timer1LatchHigh; - volatile unsigned char* timer2CounterLow; - volatile unsigned char* timer2CounterHigh; - volatile unsigned char* shift; - volatile unsigned char* auxillaryControl; - volatile unsigned char* peripheralControl; - volatile unsigned char* interruptFlag; - volatile unsigned char* interruptEnable; - volatile unsigned char* dataA; -}; - - - -// Cuda to VIA signal definition. They are all active low. - -enum -{ - kCudaTransferRequestMask = EVRB_XCVR, // TREQ (input) - kCudaNegateTransferRequest = EVRB_XCVR, // TREQ - kCudaAssertTransferRequest = ~EVRB_XCVR, // /TREQ - - kCudaByteAcknowledgeMask = EVRB_FULL, // ByteAck (output) - kCudaNegateByteAcknowledge = EVRB_FULL, // ByteAck - kCudaAssertByteAcknowledge = ~EVRB_FULL, // /ByteAck - - kCudaTransferInProgressMask = EVRB_SYSES, // TIP (output) - kCudaNegateTransferInProgress = EVRB_SYSES, // TIP - kCudaAssertTransferInProgress = ~EVRB_SYSES, // /TIP - - kCudaTransferMode = VAC_SRMD3, // - - kCudaDirectionMask = VAC_SRMD4, // - kCudaSystemSend = VAC_SRMD4, // - kCudaSystemRecieve = ~VAC_SRMD4, // - - kCudaInterruptMask = VIE_SR, - kCudaInterruptDisable = VIE_CLEAR | VIE_SR, - kCudaInterruptEnable = VIE_SET | VIE_SR -}; - -// The bits from Cuda that determines the cause of an interrupt - -enum -{ - kCudaInterruptStateMask = kCudaTransferInProgressMask | - kCudaTransferRequestMask -}; - -// Interrupt states. Determined by kTransferRequest, kTransferInProgress and -// kCudaDirection. The names are from the view of the system. - -enum -{ - kCudaReceiveByte = 0, // 0x00 - kCudaReceiveLastByte = kCudaNegateTransferRequest, // 0x08 - kCudaCollision = kCudaSystemSend, // 0x10 - kCudaTransmitByte = kCudaSystemSend | - kCudaNegateTransferRequest, // 0x18 - kCudaUnexpectedAttention = kCudaNegateTransferInProgress,// 0x20 - kCudaIdleState = kCudaNegateTransferInProgress | - kCudaNegateTransferRequest, // 0x28 - kCudaExpectedAttention = kCudaSystemSend | - kCudaNegateTransferInProgress,// 0x30 - kCudaIllegalState = kCudaSystemSend | - kCudaNegateTransferInProgress | - kCudaNegateTransferRequest // 0x38 -}; - -enum -{ - kCudaSRQAssertMask = 0x01, // inactive device asserted SRQ - kCudaTimeOutMask = 0x02, // active device did not have data available - kCudaSRQErrorMask = 0x04, // device asserted excessive SRQ period - kCudaBusErrorMask = 0x08, // timing error in bit cell was detected - kCudaAutoPollMask = 0x40, // data is from an AutoPoll - kCudaResponseMask = 0x80 // response Packet in progress -}; - -#define cuda_write_data(self,theByte) {*self->cuda_via_regs.shift = theByte; eieio(); } -#define cuda_set_data_direction_to_input(self) {*self->cuda_via_regs.auxillaryControl &= kCudaSystemRecieve; eieio(); } -#define cuda_set_data_direction_to_output(self) {*self->cuda_via_regs.auxillaryControl |= kCudaSystemSend; eieio(); } -#define cuda_assert_transfer_in_progress(self) {*self->cuda_via_regs.dataB &= kCudaAssertTransferInProgress; eieio(); } -#define cuda_neg_transfer_in_progress(self) {*self->cuda_via_regs.dataB |= kCudaNegateTransferInProgress; eieio(); } -#define cuda_neg_tip_and_byteack(self) {*self->cuda_via_regs.dataB |= kCudaNegateByteAcknowledge | kCudaNegateTransferInProgress; eieio(); } -#define cuda_toggle_byte_ack(self) {*self->cuda_via_regs.dataB ^= kCudaByteAcknowledgeMask; eieio(); } -#define cuda_assert_byte_ack(self) {*self->cuda_via_regs.dataB &= kCudaAssertByteAcknowledge; eieio(); } -#define cuda_neg_byte_ack(self) {*self->cuda_via_regs.dataB |= kCudaNegateByteAcknowledge; eieio(); } -#define cuda_is_transfer_in_progress(self) ((*self->cuda_via_regs.dataB & kCudaTransferRequestMask) == 0 ) -#define cuda_disable_interrupt(self) {*self->cuda_via_regs.interruptEnable = kCudaInterruptDisable; eieio(); } -#define cuda_enable_interrupt(self) {*self->cuda_via_regs.interruptEnable = kCudaInterruptEnable; eieio(); } -#define cuda_get_interrupt_state(self) (*self->cuda_via_regs.dataB & kCudaInterruptStateMask) | \ - (*self->cuda_via_regs.auxillaryControl & kCudaDirectionMask) -#define cuda_wait_for_transfer_request_assert(self) while ( (*self->cuda_via_regs.dataB & kCudaTransferRequestMask) != 0 ) { eieio(); } ; eieio() -#define cuda_wait_for_transfer_request_neg(self) while ( (*self->cuda_via_regs.dataB & kCudaTransferRequestMask) == 0 ) { eieio(); } ; eieio() -#define cuda_wait_for_interrupt(self) while ( (*self->cuda_via_regs.interruptFlag & kCudaInterruptMask) == 0 ) { eieio(); } ; eieio() diff --git a/iokit/Drivers/platform/drvAppleCuda/AppleCudaUserClient.cpp b/iokit/Drivers/platform/drvAppleCuda/AppleCudaUserClient.cpp deleted file mode 100644 index 366a04bd4..000000000 --- a/iokit/Drivers/platform/drvAppleCuda/AppleCudaUserClient.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/* -* Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. -* -* @APPLE_LICENSE_HEADER_START@ -* -* The contents of this file constitute Original Code as defined in and -* are subject to the Apple Public Source License Version 1.1 (the -* "License"). You may not use this file except in compliance with the -* License. Please obtain a copy of the License at -* http://www.apple.com/publicsource and read it before using this file. -* -* This Original Code and all software distributed under the License are -* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER -* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, -* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the -* License for the specific language governing rights and limitations -* under the License. -* -* @APPLE_LICENSE_HEADER_END@ -*/ -#include "AppleCudaUserClient.h" - -#ifndef NULL -#define NULL 0 -#endif - -#define super IOUserClient - -OSDefineMetaClassAndStructors(AppleCudaUserClient, IOUserClient) - -AppleCudaUserClient* -AppleCudaUserClient::withTask(task_t owningTask) -{ - AppleCudaUserClient *client; - - client = new AppleCudaUserClient; - if (client != NULL) { - if (client->init() == false) { - client->release(); - client = NULL; - } - } - if (client != NULL) { - client->fTask = owningTask; - } - return (client); -} - -bool -AppleCudaUserClient::start(IOService *provider) -{ - bool result = false; - - theInterface = OSDynamicCast(AppleCuda, provider); - - if (theInterface != NULL) - result = super::start(provider); - else - result = false; - - if (result == false) { - IOLog("AppleCudaUserClient: provider start failed\n"); - } - - return (result); -} - -IOReturn -AppleCudaUserClient::clientClose(void) -{ - detach(theInterface); - return (kIOReturnSuccess); -} - -IOReturn -AppleCudaUserClient::clientDied(void) -{ - return (clientClose()); -} - -IOReturn -AppleCudaUserClient::connectClient(IOUserClient *client) -{ - return (kIOReturnSuccess); -} - -IOReturn -AppleCudaUserClient::registerNotificationPort(mach_port_t port, UInt32 type) -{ - return (kIOReturnUnsupported); -} - -// -------------------------------------------------------------------------- -// Method: setProperties -// -// Purpose: -// sets the property from the dictionary to the airport properties. - -IOReturn -AppleCudaUserClient::setProperties( OSObject * properties ) -{ - OSDictionary * dict; - - dict = OSDynamicCast( OSDictionary, properties ); - if ((dict) && (theInterface != NULL)) { - OSData *data; - - // Sets the wake on ring: - if( (data = OSDynamicCast( OSData, dict->getObject("WakeOnRing")))) { - UInt8 myBool = *((UInt8*)data->getBytesNoCopy()); - //theInterface->setWakeOnRing(myBool); - - IOLog("AppleCudaUserClient::setProperties WakeOnRing %d\n", myBool); - - // returns success: - return kIOReturnSuccess; - } - - // Sets the file-server mode: - if( (data = OSDynamicCast( OSData, dict->getObject("FileServer")))) { - UInt8 myBool = *((UInt8*)data->getBytesNoCopy()); - theInterface->setFileServerMode(myBool); - - IOLog("AppleCudaUserClient::setProperties FileServer %d\n", myBool != 0); - - // returns success: - return kIOReturnSuccess; - } - - //Demand sleep immediately: - if( (data = OSDynamicCast( OSData, dict->getObject("SleepNow")))) { - UInt8 myBool = *((UInt8*)data->getBytesNoCopy()); - - if (myBool) - { - theInterface->demandSleepNow(); - IOLog("AppleCudaUserClient::setProperties SleepNow\n"); - } - return kIOReturnSuccess; - } - - // Sets the self-wake time: - if( (data = OSDynamicCast( OSData, dict->getObject("AutoWake")))) { - UInt32 newTime; - IOByteCount len = data->getLength(); - - if (len == 4) - newTime = *((UInt32*)data->getBytesNoCopy()); - else - newTime = 0; - - theInterface->setWakeTime(newTime * 1000); //convert to milliseconds - - IOLog("AppleCudaUserClient::setProperties AutoWake 0x%08lx\n", newTime); - - // returns success: - return kIOReturnSuccess; - } - - // Sets the self-poweron time: - if( (data = OSDynamicCast( OSData, dict->getObject("AutoPower")))) { - UInt32 newTime; - IOByteCount len = data->getLength(); - - if (len == 4) - newTime = *((UInt32*)data->getBytesNoCopy()); - else - newTime = 0; - - theInterface->setPowerOnTime(newTime); - - IOLog("AppleCudaUserClient::setProperties AutoPower 0x%08lx\n", newTime); - - // returns success: - return kIOReturnSuccess; - } - - } - - return(kIOReturnBadArgument); -} diff --git a/iokit/Drivers/platform/drvAppleCuda/AppleCudaUserClient.h b/iokit/Drivers/platform/drvAppleCuda/AppleCudaUserClient.h deleted file mode 100644 index 8901f6b58..000000000 --- a/iokit/Drivers/platform/drvAppleCuda/AppleCudaUserClient.h +++ /dev/null @@ -1,51 +0,0 @@ -/* -* Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. -* -* @APPLE_LICENSE_HEADER_START@ -* -* The contents of this file constitute Original Code as defined in and -* are subject to the Apple Public Source License Version 1.1 (the -* "License"). You may not use this file except in compliance with the -* License. Please obtain a copy of the License at -* http://www.apple.com/publicsource and read it before using this file. -* -* This Original Code and all software distributed under the License are -* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER -* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, -* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the -* License for the specific language governing rights and limitations -* under the License. -* -* @APPLE_LICENSE_HEADER_END@ -*/ - -#ifndef APPLECUDAUSERCLIENT_H -#define APPLECUDAUSERCLIENT_H - -#include -#include - -#include "AppleCuda.h" - -class AppleCudaUserClient:public IOUserClient -{ - OSDeclareDefaultStructors(AppleCudaUserClient) - -private: - AppleCuda *theInterface; - task_t fTask; - -public: - static AppleCudaUserClient *withTask(task_t owningTask); - virtual IOReturn clientClose(void); - virtual IOReturn clientDied(void); - IOReturn connectClient(IOUserClient *client); - - virtual IOReturn registerNotificationPort(mach_port_t port, UInt32 type); - virtual bool start(IOService *provider); - - IOReturn setProperties( OSObject * properties ); -}; - -#endif /* APPLECUDAUSERCLIENT_H */ diff --git a/iokit/Drivers/platform/drvAppleCuda/AppleVIA6522.h b/iokit/Drivers/platform/drvAppleCuda/AppleVIA6522.h deleted file mode 100644 index a6cd3947c..000000000 --- a/iokit/Drivers/platform/drvAppleCuda/AppleVIA6522.h +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991 - * All Rights Reserved - * - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appears in all copies and - * that both the copyright notice and this permission notice appear in - * supporting documentation. - * - * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, - * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION - * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ -/* - * Copyright 1996 1995 by Apple Computer, Inc. 1997 1996 1995 1994 1993 1992 1991 - * All Rights Reserved - * - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appears in all copies and - * that both the copyright notice and this permission notice appear in - * supporting documentation. - * - * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, - * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION - * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -/* - * MKLINUX-1.0DR2 - */ -/* - * 18 June 1998 sdouglas - * Start IOKit version. - */ - - -/* - File: via6522.h - - Contains: xxx put contents here xxx - - Written by: xxx put writers here xxx - - Copyright: © 1993, 1995 by Apple Computer, Inc., all rights reserved. - - Change History (most recent first): - - <1> 2/22/95 AM First checked in. - <1> 04/04/94 MRN First checked in. - -*/ - -/* - * Copyright 1987-91 Apple Computer, Inc. - * All Rights Reserved. - */ - -#ifndef __VIA6522_H__ -#define __VIA6522_H__ - -/* - * Synertek SY6522 VIA Versatile Interface Adapter - */ - -/* - * This has been modified to address BOTH the via and RBV registers, - * because we know that both chips ignore part of the address, thus - * only responding correctly. It's ugly, but the ROM does it... - */ - -#if defined(powerc) || defined (__powerc) -#pragma options align=mac68k -#endif - -typedef struct via6522Regs /* VIA / RBV address */ - { - volatile unsigned char vBufB; /* 0000/0000 register b */ - volatile unsigned char RvExp; /* 0001 RBV future expansion */ - volatile unsigned char RvSlotIFR; /* 0002 RBV Slot interrupts reg. */ - volatile unsigned char RvIFR; /* 0003 RBV interrupt flag reg. */ - unsigned char jnk0[ 12 ]; - - volatile unsigned char RvMonP; /* xxxx/0010 RBV video monitor type */ - volatile unsigned char RvChpT; /* xxxx/0011 RBV test mode register */ - volatile unsigned char RvSlotIER; /* xxxx/0012 RBV slot interrupt enables */ - volatile unsigned char RvIER; /* xxxx/0013 RBV interrupt flag enable reg */ - unsigned char jnk1[ 0x1FF - 0x13 ]; - - volatile unsigned char vBufAH; /* 0200 buffer a (with handshake). */ - unsigned char jnk2[ 0x1FF ]; /* Dont use! Here only for completeness */ - - volatile unsigned char vDIRB; /* 0400 data direction register B */ - unsigned char jnk25[ 0x1FF ]; - - volatile unsigned char vDIRA; /* 0600 data direction register A */ - unsigned char jnk3[ 0x1FF ]; - - volatile unsigned char vT1C; /* 0800 timer one low */ - unsigned char jnk4[ 0x1FF ]; - - volatile unsigned char vT1CH; /* 0A00 timer one high */ - unsigned char jnk5[ 0x1FF ]; - - volatile unsigned char vT1L; /* 0C00 timer one latches low */ - unsigned char jnk6[ 0x1FF ]; - - volatile unsigned char vT1LH; /* 0E00 timer one latches high */ - unsigned char jnk7[ 0x1FF ]; - - volatile unsigned char vT2C; /* 1000 timer 2 low */ - unsigned char jnk8[ 0x1FF ]; - - volatile unsigned char vT2CH; /* 1200 timer two counter high */ - unsigned char jnk9[ 0x1FF ]; - - volatile unsigned char vSR; /* 1400 shift register */ - unsigned char jnka[ 0x1FF ]; - - volatile unsigned char vACR; /* 1600 auxilary control register */ - unsigned char jnkb[ 0x1FF ]; - - volatile unsigned char vPCR; /* 1800 peripheral control register */ - unsigned char jnkc[ 0x1FF ]; - - volatile unsigned char vIFR; /* 1A00 interrupt flag register */ - unsigned char jnkd[ 0x1FF ]; - - volatile unsigned char vIER; /* 1C00 interrupt enable register */ - unsigned char jnkf[ 0x1FF ]; - - volatile unsigned char vBufA; /* 1E00 register A, read and write */ - } via6522Regs; - -#if defined(powerc) || defined(__powerc) -#pragma options align=reset -#endif - - -/* Register B contents */ - -#define VRB_POWEROFF 0x04 /* disk head select */ -#define RBV_POWEROFF VRB_POWEROFF -#define VRB_BUSLOCK 0x02 /* NuBus Transactions are locked */ - - -/* Register A contents */ - -#define VRA_DRIVE 0x10 /* drive select */ -#define VRA_HEAD 0x20 /* disk head select */ - - -/* Auxillary control register contents */ - -#define VAC_PAENL 0x01 /* Enable latch for PA */ -#define VAC_PADISL 0x00 /* Disable latch for PA */ -#define VAC_PBENL 0x02 /* Enable latch for PA */ -#define VAC_PBDISL 0x00 /* Disable latch for PA */ -#define VAC_SRDIS 0x00 /* Shift Reg Disabled */ -#define VAC_SRMD1 0x04 /* Shift In under control of T2 */ -#define VAC_SRMD2 0x08 /* Shift In under control of Phase 2 */ -#define VAC_SRMD3 0x0C /* Shift in under control of Ext Clk */ -#define VAC_SRMD4 0x10 /* Shift Out free running at T2 rate */ -#define VAC_SRMD5 0x14 /* Shift Out under control of T2 */ -#define VAC_SRMD6 0x18 /* Shift Out under control of theta2 */ -#define VAC_SRMD7 0x1C /* Shift Out under control of Ext Clk */ -#define VAC_T2CTL 0x20 /* Timer two, control */ -#define VAC_T2TI 0x00 /* Timer Two, Timed Interrupt */ -#define VAC_T2CD 0x20 /* Timer Two, count down with pulses on PB6 */ -#define VAC_T1CONT 0x40 /* Timer one, continous counting */ -#define VAC_T11SHOT 0x00 /* Timer One, one shot output */ -#define VAC_T1PB7 0x80 /* Timer one, drives PB7 */ -#define VAC_T1PB7DIS 0x00 /* Timer one, drives PB7 disabled */ - - -/* Interrupt enable register contents */ - -#define VIE_CA2 0x01 /* interrupt on CA2 */ -#define VIE_CA1 0x02 /* interrupt on CA1 */ -#define VIE_SR 0x04 /* Shift Register */ -#define VIE_CB2 0x08 /* interrupt on CB2 */ -#define VIE_CB1 0x10 /* interrupt on CB1 */ -#define VIE_TIM2 0x20 /* timer 2 interrupt */ -#define VIE_TIM1 0x40 /* timer 1 interrupt */ -#define VIE_SET 0x80 /* Set interrupt bits if this is on */ -#define VIE_CLEAR 0x00 /* Clear bits if used */ - -#define VIE_ALL ( VIE_TIM1 | VIE_TIM2 | VIE_CB1 | VIE_CB2 | VIE_SR | VIE_CA1 | VIE_CA2 ) - - -/* VIA Data Direction Register Contents */ - -#define VDR_P7_O 0x80 /* P7 is output */ -#define VDR_P7_I 0x00 /* P7 is input */ -#define VDR_P6_O 0x40 /* P6 is output */ -#define VDR_P6_I 0x00 /* P6 is input */ -#define VDR_P5_O 0x20 /* P5 is output */ -#define VDR_P5_I 0x00 /* P5 is input */ -#define VDR_P4_O 0x10 /* P4 is output */ -#define VDR_P4_I 0x00 /* P4 is input */ -#define VDR_P3_O 0x08 /* P3 is output */ -#define VDR_P3_I 0x00 /* P3 is input */ -#define VDR_P2_O 0x04 /* P2 is output */ -#define VDR_P2_I 0x00 /* P2 is input */ -#define VDR_P1_O 0x02 /* P1 is output */ -#define VDR_P1_I 0x00 /* P1 is input */ -#define VDR_P0_O 0x01 /* P0 is output */ -#define VDR_P0_I 0x00 /* P0 is input */ - - -/* VIA1 Register A contents where they differ from standard VIA1 */ - -#define RBV_BURNIN 0x01 /* burnin flag */ -#define RBV_CPUID0 0x02 /* CPU id bit 0 */ -#define RBV_CPUID1 0x04 /* CPU id bit 1 */ -#define RBV_CPUID2 0x10 /* CPU id bit 2 */ -#define RBV_CPUID3 0x40 /* CPU id bit 3 */ - - -/* VIA1 Register B contents where they differ from standard VIA1 */ - -#define RBV_PARDIS 0x40 /* disable parity */ -#define RBV_PAROK 0x80 /* parity OK */ - -#define EVRB_XCVR 0x08 /* XCVR_SESSION* */ -#define EVRB_FULL 0x10 /* VIA_FULL */ -#define EVRB_SYSES 0x20 /* SYS_SESSION */ -#define EVRB_AUXIE 0x00 /* Enable A/UX Interrupt Scheme */ -#define EVRB_AUXID 0x40 /* Disable A/UX Interrupt Scheme */ -#define EVRB_SFTWRIE 0x00 /* Software Interrupt ReQuest */ -#define EVRB_SFTWRID 0x80 /* Software Interrupt ReQuest */ - - -/* VIA2 Register A contents where they differ from standard VIA2 */ - -#define RBV_SZEROIRQ 0x40 /* slot 0 irq */ -#define EVRA_ENETIRQ 0x01 /* Ethernet irq */ -#define EVRA_VIDIRQ 0x40 /* Video irq */ - - -/* VIA2 Register B contents where they differ from standard VIA2 */ - -#define RBV_CDIS 0x01 /* disable external cache */ -#define RBV_CFLUSH 0x08 /* flush external cache */ -#define EVRB_LED 0x10 /* LED */ -#define RBV_PARODD 0x80 /* 1 for odd, 0 for even */ - - -/* Video monitor parameters: */ -#define RBV_DEPTH 0x07 /* bits per pixel: 000=1,001=2,010=4,011=8 */ -#define RBV_MONID 0x38 /* monitor type as below */ -#define RBV_VIDOFF 0x40 /* 1 turns off onboard video */ - - -/* Supported video monitor types: */ - -#define MON_15BW ( 1 << 3 ) /* 15" BW portrait */ -#define MON_IIGS ( 2 << 3 ) /* modified IIGS monitor */ -#define MON_15RGB ( 5 << 3 ) /* 15" RGB portrait */ -#define MON_12OR13 ( 6 << 3 ) /* 12" BW or 13" RGB */ -#define MON_NONE ( 7 << 3 ) /* No monitor attached */ - -#endif /* __VIA6522_H__ */ diff --git a/iokit/Drivers/platform/drvAppleCuda/IOCudaADBController.cpp b/iokit/Drivers/platform/drvAppleCuda/IOCudaADBController.cpp deleted file mode 100644 index e8a0db837..000000000 --- a/iokit/Drivers/platform/drvAppleCuda/IOCudaADBController.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * 1 Dec 1998 suurballe Created. - */ - -#include "IOCudaADBController.h" -#include "AppleCuda.h" - -#define super IOADBController -OSDefineMetaClassAndStructors(IOCudaADBController, IOADBController) - -// ********************************************************************************** -// init -// -// ********************************************************************************** -bool IOCudaADBController::init ( OSDictionary * properties, AppleCuda * driver ) -{ - -CudaDriver = driver; -pollList = 0; -autopollOn = false; - -return super::init(properties); -} - - -// ********************************************************************************** -// start -// -// ********************************************************************************** -bool IOCudaADBController::start ( IOService *nub ) -{ - - CudaDriver->registerForADBInterrupts ( autopollHandler, this ); - if( !super::start(nub)) - return false; - return true; -} - - -// ********************************************************************************** -// setAutoPollPeriod -// -// ********************************************************************************** -IOReturn IOCudaADBController::setAutoPollPeriod ( int microsecs ) -{ -cuda_request_t cmd; - -adb_init_request(&cmd); -ADB_BUILD_CMD3(&cmd, ADB_PACKET_PSEUDO, ADB_PSEUDOCMD_SET_AUTO_RATE, - ((microsecs + 999) / 1000)); - -return CudaDriver->doSyncRequest(&cmd); -} - - -// ********************************************************************************** -// getAutoPollPeriod -// -// ********************************************************************************** -IOReturn IOCudaADBController::getAutoPollPeriod ( int * microsecs ) -{ -IOReturn err; -cuda_request_t cmd; -UInt8 data; - -adb_init_request(&cmd); -ADB_BUILD_CMD2(&cmd, ADB_PACKET_PSEUDO, ADB_PSEUDOCMD_GET_AUTO_RATE); -cmd.a_reply.a_buffer = &data; -cmd.a_reply.a_bcount = sizeof(UInt8); - -err = CudaDriver->doSyncRequest(&cmd); - -if ( err == kIOReturnSuccess ) { - *microsecs = data * 1000; -} -return err; -} - - -// ********************************************************************************** -// getAutoPollPeriod -// -// ********************************************************************************** -IOReturn IOCudaADBController::setAutoPollList ( UInt16 activeAddressMask ) -{ -cuda_request_t cmd; - -adb_init_request(&cmd); -ADB_BUILD_CMD2(&cmd, ADB_PACKET_PSEUDO, ADB_PSEUDOCMD_SET_DEVICE_LIST) - -cmd.a_cmd.a_buffer = (UInt8 *) &activeAddressMask; -cmd.a_cmd.a_bcount = sizeof(UInt16); - -return CudaDriver->doSyncRequest(&cmd); -} - - -// ********************************************************************************** -// getAutoPollList -// -// ********************************************************************************** -IOReturn IOCudaADBController::getAutoPollList ( UInt16 * activeAddressMask ) -{ -cuda_request_t cmd; - -adb_init_request(&cmd); -ADB_BUILD_CMD2(&cmd, ADB_PACKET_PSEUDO, ADB_PSEUDOCMD_GET_DEVICE_LIST); -cmd.a_reply.a_buffer = (UInt8 *) activeAddressMask; -cmd.a_reply.a_bcount = sizeof(UInt16); - -return CudaDriver->doSyncRequest(&cmd); -} - - -// ********************************************************************************** -// setAutoPollEnable -// -// ********************************************************************************** -IOReturn IOCudaADBController::setAutoPollEnable ( bool enable ) -{ -cuda_request_t cmd; - -adb_init_request(&cmd); -ADB_BUILD_CMD3(&cmd, ADB_PACKET_PSEUDO, ADB_PSEUDOCMD_START_STOP_AUTO_POLL, (enable ? 1 : 0)); - -return CudaDriver->doSyncRequest(&cmd); -} - - -// ********************************************************************************** -// resetBus -// -// ********************************************************************************** -IOReturn IOCudaADBController::resetBus ( void ) -{ -cuda_request_t cmd; - -adb_init_request(&cmd); -ADB_BUILD_CMD2(&cmd, ADB_PACKET_ADB, ADB_ADBCMD_RESET_BUS ); - -return CudaDriver->doSyncRequest(&cmd); -} - - -// ********************************************************************************** -// cancelAllIO -// -// ********************************************************************************** -IOReturn IOCudaADBController::cancelAllIO ( void ) -{ - return kIOReturnSuccess; -} - - -// ********************************************************************************** -// flushDevice -// -// ********************************************************************************** -IOReturn IOCudaADBController::flushDevice ( IOADBAddress address ) -{ -cuda_request_t cmd; - -adb_init_request(&cmd); -ADB_BUILD_CMD2(&cmd, ADB_PACKET_ADB, (ADB_ADBCMD_FLUSH_ADB | (address << 4))); - -return CudaDriver->doSyncRequest(&cmd); -} - - - -// ********************************************************************************** -// readFromDevice -// -// ********************************************************************************** -IOReturn IOCudaADBController::readFromDevice (IOADBAddress address, IOADBRegister adbRegister, - UInt8 * data, IOByteCount * length ) -{ -IOReturn err; -cuda_request_t cmd; - -adb_init_request(&cmd); -ADB_BUILD_CMD2(&cmd, ADB_PACKET_ADB, - (ADB_ADBCMD_READ_ADB | (address << 4) | (adbRegister & 3))); - -cmd.a_reply.a_buffer = data; -cmd.a_reply.a_bcount = *length; - -err = CudaDriver->doSyncRequest(&cmd); - -//IOLog("Read %d, Addr %x Reg %x = %04x\n", err, address, adbRegister, *((UInt16 *)data)); - -if( err == ADB_RET_OK ) { - *length = cmd.a_reply.a_bcount; -} -else { - *length = 0; -} - -return err; -} - - -// ********************************************************************************** -// writeToDevice -// -// ********************************************************************************** -IOReturn IOCudaADBController::writeToDevice ( IOADBAddress address, IOADBRegister adbRegister, - UInt8 * data, IOByteCount * length ) -{ -IOReturn err; -cuda_request_t cmd; - -adb_init_request(&cmd); - -ADB_BUILD_CMD2(&cmd, ADB_PACKET_ADB, - (ADB_ADBCMD_WRITE_ADB | (address << 4) | (adbRegister & 3))); -cmd.a_cmd.a_buffer = data; -cmd.a_cmd.a_bcount = *length; - -err = CudaDriver->doSyncRequest(&cmd); - -//IOLog("Write %d, Addr %x Reg %x = %04x\n", err, address, adbRegister, *((UInt16 *)data)); - -if( err == ADB_RET_OK ) { - *length = cmd.a_reply.a_bcount; -} -else { - *length = 0; -} -return err; -} - diff --git a/iokit/Drivers/platform/drvAppleCuda/IOCudaADBController.h b/iokit/Drivers/platform/drvAppleCuda/IOCudaADBController.h deleted file mode 100644 index 83cef9fa1..000000000 --- a/iokit/Drivers/platform/drvAppleCuda/IOCudaADBController.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * 1 Dec 1998 suurballe Created. - */ - -#include - -class AppleCuda; - - -class IOCudaADBController : public IOADBController -{ -OSDeclareDefaultStructors(IOCudaADBController) - -private: - -AppleCuda * CudaDriver; -UInt32 pollList; // ADB autopoll device bitmap -bool autopollOn; // TRUE: PMU is autopolling - -public: - -bool init ( OSDictionary * properties, AppleCuda * driver ); -bool start ( IOService * ); -IOReturn setAutoPollPeriod ( int microseconds ); -IOReturn getAutoPollPeriod ( int * microseconds ); -IOReturn setAutoPollList ( UInt16 activeAddressMask ); -IOReturn getAutoPollList ( UInt16 * activeAddressMask ); -IOReturn setAutoPollEnable ( bool enable ); -IOReturn resetBus ( void ); -IOReturn cancelAllIO ( void ); -IOReturn flushDevice ( IOADBAddress address ); -IOReturn readFromDevice ( IOADBAddress address, IOADBRegister adbRegister, - UInt8 * data, IOByteCount * length ); -IOReturn writeToDevice ( IOADBAddress address, IOADBRegister adbRegister, - UInt8 * data, IOByteCount * length ); -}; diff --git a/iokit/Drivers/platform/drvAppleGossamerPE/Gossamer.cpp b/iokit/Drivers/platform/drvAppleGossamerPE/Gossamer.cpp deleted file mode 100644 index cefb29212..000000000 --- a/iokit/Drivers/platform/drvAppleGossamerPE/Gossamer.cpp +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * DRI: Josh de Cesare - * - */ - -extern "C" { -#include -} - -#include - -#include -//#include - -#include "Gossamer.h" - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#define super ApplePlatformExpert - -OSDefineMetaClassAndStructors(GossamerPE, ApplePlatformExpert); - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -bool GossamerPE::start(IOService *provider) -{ - unsigned int tmpVal; - long machineType; - long allInOne; - - setChipSetType(kChipSetTypeGossamer); - - // Set the machine type. - if (IODTMatchNubWithKeys(provider, "'AAPL,Gossamer'")) - machineType = kGossamerTypeGossamer; - else if (IODTMatchNubWithKeys(provider, "'AAPL,PowerMac G3'")) - machineType = kGossamerTypeSilk; - else if (IODTMatchNubWithKeys(provider, "'AAPL,PowerBook1998'")) - machineType = kGossamerTypeWallstreet; - else if (IODTMatchNubWithKeys(provider, "'iMac,1'")) - machineType = kGossamerTypeiMac; - else if (IODTMatchNubWithKeys(provider, "('PowerMac1,1', 'PowerMac1,2')")) - machineType = kGossamerTypeYosemite; - else if (IODTMatchNubWithKeys(provider, "'PowerBook1,1'")) - machineType = kGossamerType101; - else return false; - - setMachineType(machineType); - - // Find out if this an all in one. - allInOne = 0; - if (ml_probe_read(kGossamerMachineIDReg, &tmpVal)) { - switch (getMachineType()) { - case kGossamerTypeGossamer : - case kGossamerTypeSilk : - if (!(tmpVal & kGossamerAllInOneMask)) allInOne = 1; - break; - - case kGossamerTypeiMac : - allInOne = 1; - break; - } - } - if (allInOne) setProperty("AllInOne", this); - - // setup default power mgr features per machine - // NOTE: on Core99 and later hardware, this information - // is available from the "prim-info" property in the power-mgt - // node of the device tree. Prior to that, this information - // was just another hard-coded part of the ROM. - - switch (getMachineType()) { - case kGossamerTypeGossamer: - case kGossamerTypeSilk: - case kGossamerTypeiMac: - case kGossamerTypeYosemite: - _pePMFeatures = kStdDesktopPMFeatures; - _pePrivPMFeatures = kStdDesktopPrivPMFeatures; - _peNumBatteriesSupported = kStdDesktopNumBatteries; - break; - - case kGossamerTypeWallstreet: - _pePMFeatures = kWallstreetPMFeatures; - _pePrivPMFeatures = kWallstreetPrivPMFeatures; - _peNumBatteriesSupported = kStdPowerBookNumBatteries; - break; - - case kGossamerType101: - _pePMFeatures = k101PMFeatures; - _pePrivPMFeatures = k101PrivPMFeatures; - _peNumBatteriesSupported = kStdPowerBookNumBatteries; - break; - } - - return super::start(provider); -} - - -bool GossamerPE::platformAdjustService(IOService *service) -{ - long tmpNum; - OSData *tmpData; - - // Add the extra sound properties for Gossamer AIO - if (getProperty("AllInOne") && - ((getMachineType() == kGossamerTypeGossamer) || - (getMachineType() == kGossamerTypeSilk))) { - if (!strcmp(service->getName(), "sound")) { - tmpNum = 3; - tmpData = OSData::withBytes(&tmpNum, sizeof(tmpNum)); - if (tmpData) { - service->setProperty("#-detects", tmpData); - service->setProperty("#-outputs", tmpData); - tmpData->release(); - } - return true; - } - } - - // Set the loop snoop property for Wallstreet or Mainstreet. - if (getMachineType() == kGossamerTypeWallstreet) { - if (IODTMatchNubWithKeys(service, "('grackle', 'MOT,PPC106')")) { - // Add the property for set loop snoop. - service->setProperty("set-loop-snoop", service); - return true; - } - } - - return true; -} - -IOReturn GossamerPE::callPlatformFunction(const OSSymbol *functionName, - bool waitForFunction, - void *param1, void *param2, - void *param3, void *param4) -{ - if (functionName == gGetDefaultBusSpeedsKey) { - getDefaultBusSpeeds((long *)param1, (unsigned long **)param2); - return kIOReturnSuccess; - } - - return super::callPlatformFunction(functionName, waitForFunction, - param1, param2, param3, param4); -} - -static unsigned long gossamerSpeed[] = { 66820000, 1 }; -static unsigned long yosemiteSpeed[] = { 99730000, 1 }; - -void GossamerPE::getDefaultBusSpeeds(long *numSpeeds, - unsigned long **speedList) -{ - if ((numSpeeds == 0) || (speedList == 0)) return; - - switch (getMachineType()) { - case kGossamerTypeGossamer : - case kGossamerTypeSilk : - *numSpeeds = 1; - *speedList = gossamerSpeed; - break; - - case kGossamerTypeYosemite : - *numSpeeds = 1; - *speedList = yosemiteSpeed; - break; - - default : - *numSpeeds = 0; - *speedList = 0; - break; - } -} - - -//********************************************************************************* -// PMInstantiatePowerDomains -// -// This overrides the vanilla implementation in IOPlatformExpert. It instantiates -// a root domain with two children, one for the USB bus (to handle the USB idle -// power budget), and one for the expansions slots on the PCI bus (to handle -// the idle PCI power budget) -//********************************************************************************* - -void GossamerPE::PMInstantiatePowerDomains ( void ) -{ - root = new IOPMrootDomain; - root->init(); - root->attach(this); - root->start(this); - root->youAreRoot(); - -/* All G3s support sleep (or pseudo-sleep) now - if ((getMachineType() == kGossamerType101) || - (getMachineType() == kGossamerTypeWallstreet)) -*/ - root->setSleepSupported(kRootDomainSleepSupported); -} - - -//********************************************************************************* -// PMRegisterDevice -// -// This overrides the vanilla implementation in IOPlatformExpert. -//********************************************************************************* - -//#define DONOTREGISTERATACONTROLLER 1 - -void GossamerPE::PMRegisterDevice(IOService * theNub, IOService * theDevice) -{ -//#ifdef DONOTREGISTERATACONTROLLER - // do not add IOATAStandardDriver to the tree since on this platform they do not need resets -// if (OSDynamicCast(IOATAStandardDriver, theDevice) != NULL) -// return; -//#endif - - // Checks if the nub handles power states, if it does not gets its parent and so - // up until we reach the root, or we do not find anything: - while ((theNub != NULL) && ( theNub->addPowerChild(theDevice) != IOPMNoErr )) { - theNub = theNub->getProvider(); - -//#ifdef DONOTREGISTERATACONTROLLER - // IOATAStandardDriver are detached, and so would be evrething I attach to them so - // their childs go directly on the tree. -// if (OSDynamicCast(IOATAStandardDriver, theNub) != NULL) { -// theNub = theNub->getProvider(); -// } -//#endif - } - - if ( theNub == NULL ) { - root->addPowerChild ( theDevice ); - return; - } -} diff --git a/iokit/Drivers/platform/drvAppleGossamerPE/Gossamer.h b/iokit/Drivers/platform/drvAppleGossamerPE/Gossamer.h deleted file mode 100644 index 32517503b..000000000 --- a/iokit/Drivers/platform/drvAppleGossamerPE/Gossamer.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * DRI: Josh de Cesare - * - */ - - -#ifndef _IOKIT_GOSSAMER_H -#define _IOKIT_GOSSAMER_H - -#include - - -enum { - kGossamerTypeGossamer = 1, - kGossamerTypeSilk, - kGossamerTypeWallstreet, - kGossamerTypeiMac, - kGossamerTypeYosemite, - kGossamerType101 -}; - -#define kGossamerMachineIDReg (0xFF000004) -#define kGossamerAllInOneMask (0x00100000) - -class GossamerPE : public ApplePlatformExpert -{ - OSDeclareDefaultStructors(GossamerPE); - -private: - void getDefaultBusSpeeds(long *numSpeeds, - unsigned long **speedList); - - void PMInstantiatePowerDomains ( void ); - void PMRegisterDevice(IOService * theNub, IOService * theDevice); - -public: - virtual bool start(IOService *provider); - virtual bool platformAdjustService(IOService *service); - virtual IOReturn callPlatformFunction(const OSSymbol *functionName, - bool waitForFunction, - void *param1, void *param2, - void *param3, void *param4); -}; - - -#endif /* ! _IOKIT_GOSSAMER_H */ diff --git a/iokit/Drivers/platform/drvAppleGossamerPE/GossamerCPU.cpp b/iokit/Drivers/platform/drvAppleGossamerPE/GossamerCPU.cpp deleted file mode 100644 index 5a7b11264..000000000 --- a/iokit/Drivers/platform/drvAppleGossamerPE/GossamerCPU.cpp +++ /dev/null @@ -1,495 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1999-2000 Apple Computer, Inc. All rights reserved. - * - */ - -extern "C" { -#include -} - -#include -#include - -#include "GossamerCPU.h" -#include "Gossamer.h" - -extern "C" { -unsigned int ml_throttle(unsigned int step); -int kdp_getc(void); -void machine_idle(void); -} - -// Uncomment the following define to get verbose logs on the sleep/wake cycles -//#define VERBOSE_LOGS_ON - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#define super IOCPU - -OSDefineMetaClassAndStructors(GossamerCPU, IOCPU); - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -UInt32 GossamerCPU::restartAddress = 0x100; - -IOService *GossamerCPU::findIOInterface(char *name) -{ - OSDictionary *dict; - IOService *service; - - heathrow = NULL; - - // find the dictionary of the Heathrow matches. - dict = serviceMatching(name); - if (dict == NULL) { -#ifdef VERBOSE_LOGS_ON - kprintf("GossamerCPU::findIOInterface faild to get a matching dictionary for %s\n", name); -#endif // VERBOSE_LOGS_ON - return NULL; - } - - service = waitForService(dict, NULL); - if (service == NULL) { -#ifdef VERBOSE_LOGS_ON - kprintf("GossamerCPU::findIOInterface failed to get a matching service for %s\n", name); -#endif// VERBOSE_LOGS_ON - return NULL; - } - - return (service); -} - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -bool GossamerCPU::start(IOService *provider) -{ - kern_return_t result; - ml_processor_info_t processor_info; - bool success = super::start(provider); - GossamerPE *gossamerBoard; - - if (!success) - return false; - - // callPlatformFunction symbols - heathrow_sleepState = OSSymbol::withCString("heathrow_sleepState"); - heathrow_set_light = OSSymbol::withCString("heathrow_set_light"); - cuda_check_any_interrupt = OSSymbol::withCString("cuda_check_any_interrupt"); - usb_remote_wakeup = OSSymbol::withCString("usb_remote_wakeup"); - -#ifdef VERBOSE_LOGS_ON - kprintf("GossamerCPU::start start\n"); -#endif // VERBOSE_LOGS_ON - - // Checks the board: - gossamerBoard = OSDynamicCast(GossamerPE, getPlatform()); - if (gossamerBoard == 0) { -#ifdef VERBOSE_LOGS_ON - kprintf("GossamerCPU::start this is not a GossamerPE\n"); -#endif // VERBOSE_LOGS_ON - return false; - } - - cpuIC = new IOCPUInterruptController; - if (cpuIC == 0) - return false; - - if (cpuIC->initCPUInterruptController(1) != kIOReturnSuccess) return false; - cpuIC->attach(this); - - cpuIC->registerCPUInterruptController(); - - processor_info.cpu_id = (cpu_id_t)this; - processor_info.boot_cpu = true; - processor_info.start_paddr = restartAddress; - processor_info.l2cr_value = mfl2cr() & 0x7FFFFFFF; // cache-disabled value - processor_info.supports_nap = false; // doze, do not nap - processor_info.time_base_enable = 0; - - // Register this CPU with mach. - result = ml_processor_register(&processor_info, &machProcessor, - &ipi_handler); - if (result == KERN_FAILURE) - return false; - - setCPUState(kIOCPUStateUninitalized); - - processor_start(machProcessor); - -#ifdef VERBOSE_LOGS_ON - kprintf("GossamerCPU::start end %d \n", success); -#endif // VERBOSE_LOGS_ON - - registerService(); - - return success; -} - -void GossamerCPU::ipiHandler(void *refCon, void *nub, int source) -{ - // Call mach IPI handler for this CPU. - if (ipi_handler) - ipi_handler(); -} - -void GossamerCPU::initCPU(bool boot) -{ -#ifdef VERBOSE_LOGS_ON - kprintf("GossamerCPU::initCPU start\n"); -#endif // VERBOSE_LOGS_ON - - if (grackle != NULL) { - IOPCIAddressSpace grackleSpace; - UInt32 grackleMemConfiguration; - -#ifdef VERBOSE_LOGS_ON - kprintf("GossamerCPU::initCPU AppleGracklePCI sets the ram in autorefresh off\n"); -#endif // VERBOSE_LOGS_ON - - grackleSpace.bits = 0x80000000; - grackleMemConfiguration = grackle->configRead32(grackleSpace, 0x70); - -#ifdef VERBOSE_LOGS_ON - kprintf("GossamerCPU::initCPU AppleGracklePCI current power managment mode :0x%08lx\n", grackleMemConfiguration); -#endif // VERBOSE_LOGS_ON - - // Disables NAP and PM - grackleMemConfiguration &= ~(0x90); -#ifdef VERBOSE_LOGS_ON - kprintf("GossamerCPU::initCPU AppleGracklePCI new power managment mode :0x%08lx\n", grackleMemConfiguration); -#endif // VERBOSE_LOGS_ON - - grackle->configWrite32(grackleSpace, 0x70, grackleMemConfiguration); - - grackle = NULL; - } - else - kprintf("GossamerCPU::initCPU not found AppleGracklePCI\n"); - - if (heathrow != NULL) { - // we are waking up from sleep so: - heathrow->callPlatformFunction(heathrow_sleepState, false, (void *)false, 0, 0, 0); - heathrow = NULL; - } - else - kprintf("GossamerCPU::initCPU not found Heathrow\n"); - - /* - The following code is commented because the only Gossamer machine with a pci 2 pci Bridge - is the BWG3 and in that machine we do not remove power from the bridge. I am however leaving - this code here as reference (and to make clear that it is not running for a reason) - // Restore the PCI-PCI Bridge. - if (pci2pciBridge != NULL) - pci2pciBridge->restoreBridgeState(); */ - - // Restore time base after wake (since CPU's TBR was set to zero during sleep) - if(!boot) - saveTimeBase(false); - - // Init the interrupts. - if (boot) - cpuIC->enableCPUInterrupt(this); - - setCPUState(kIOCPUStateRunning); - - gossamerPE = OSDynamicCast(GossamerPE, getPlatform()); - if (gossamerPE ) { - //Initially Gossamers with Cuda are not in sleep mode - gossamerPE->setProperty("GossamerCudaSleeping", false); - } - -#ifdef VERBOSE_LOGS_ON - kprintf("GossamerCPU::initCPU end\n"); -#endif VERBOSE_LOGS_ON -} - -//extern "C" void _gossamer_cpu_wake(void); -extern UInt32 ResetHandler; - -#ifdef VERBOSE_LOGS_ON -// The following function exist only to check that the wake vector is placed correctly. -static void -cpu_foo_wake() -{ - __asm__ volatile("_gossamer_cpu_wake:"); - //kprintf("_gossamer_cpu_wake going to 0x100\n"); - __asm__ volatile(" ba 0x100"); -} -#endif // VERBOSE_LOGS_ON - -// flushes the cash for a word at the given address. -#define cFlush(addr) __asm__ volatile("dcbf 0, %0" : : "r" (addr)) - -extern "C" { - void gossamer_cpu_wake(void); - extern void cacheInit(void); - extern void cacheDisable(void); -} - -void GossamerCPU::quiesceCPU(void) -{ - UInt32 larsCode = (((UInt32)'L') << 24) | (((UInt32)'a') << 16) | (((UInt32)'r') << 8) | (((UInt32)'s') << 0); - UInt32 restartReferencePhi = pmap_extract(kernel_pmap,(vm_address_t)&restartAddress); - - // disables the interrupts (they should be already disabled, but one more tiem won't hurt): - ml_set_interrupts_enabled(FALSE); - -#ifdef VERBOSE_LOGS_ON - kprintf("GossamerCPU::quiesceCPU BEFORE 0x%08lx 0x%08lx start\n", 0x00000000, ml_phys_read(0x00000000)); - kprintf("GossamerCPU::quiesceCPU BEFORE 0x%08lx 0x%08lx start\n", 0x00000004, ml_phys_read(0x00000004)); - - // Set the wake vector to point to the my checkpoint vector - ml_phys_write(restartReferencePhi, gossamer_cpu_wake); //restartAddress = gossamer_cpu_wake; - eieio(); -#else - // Set the wake vector to point to the reset vector - ml_phys_write(restartReferencePhi, 0x100); //restartAddress = 0x100; - eieio(); -#endif // VERBOSE_LOGS_ON - - ml_phys_write(0x00000000, restartReferencePhi); - eieio(); - - // Set the wake vector to point to the reset vector - ml_phys_write(0x00000004, larsCode); - eieio(); - - // and flushes the data cache: - flush_dcache(restartReferencePhi, 4, true); - flush_dcache(0x00000000, 8, true); - - // Also makes sure that the reset hander is correctly flushed: - flush_dcache(&ResetHandler, 12, true); - - __asm__ volatile("sync"); - __asm__ volatile("isync"); - -#ifdef VERBOSE_LOGS_ON - kprintf("GossamerCPU::quiesceCPU AFTER 0x%08lx 0x%08lx start\n", 0x00000000, ml_phys_read(0x00000000)); - kprintf("GossamerCPU::quiesceCPU AFTER 0x%08lx 0x%08lx start\n", ml_phys_read(0x00000000), ml_phys_read(ml_phys_read(0x00000000))); - kprintf("GossamerCPU::quiesceCPU AFTER 0x%08lx 0x%08lx start\n", 0x00000004, ml_phys_read(0x00000004)); -#endif - - // Send PMU command to shutdown system before io is turned off - if (pmu != 0) - pmu->callPlatformFunction("sleepNow", false, 0, 0, 0, 0); - else - kprintf("GossamerCPU::quiesceCPU can't find ApplePMU\n"); - - if (heathrow != NULL) { - heathrow->callPlatformFunction(heathrow_sleepState, false, (void *)true, 0, 0, 0); - } - else - kprintf("GossamerCPU::quiesceCPU not found Heathrow\n"); - - if (grackle != NULL) { - IOPCIAddressSpace grackleSpace; - UInt32 grackleProcConfiguration, grackleMemConfiguration; - -#ifdef VERBOSE_LOGS_ON - kprintf("GossamerCPU::quiesceCPU AppleGracklePCI sets the ram in autorefresh\n"); - - grackleSpace.bits = 0x80000000; - grackleProcConfiguration = grackle->configRead32(grackleSpace, 0xA8); - kprintf("GossamerCPU::quiesceCPU AppleGracklePCI current processorinterface conf :0x%08lx\n", grackleProcConfiguration); -#endif // VERBOSE_LOGS_ON - - grackleSpace.bits = 0x80000000; - grackleMemConfiguration = grackle->configRead32(grackleSpace, 0x70); -#ifdef VERBOSE_LOGS_ON - kprintf("GossamerCPU::quiesceCPU AppleGracklePCI current power managment mode :0x%08lx\n", grackleMemConfiguration); -#endif // VERBOSE_LOGS_ON - - // Enables NAP and PM - grackleMemConfiguration |= 0x90; -#ifdef VERBOSE_LOGS_ON - kprintf("GossamerCPU::quiesceCPU AppleGracklePCI new power managment mode :0x%08lx\n", grackleMemConfiguration); -#endif // VERBOSE_LOGS_ON - - grackle->configWrite32(grackleSpace, 0x70, grackleMemConfiguration); - } - else - kprintf("GossamerCPU::quiesceCPU not found AppleGracklePCI\n"); - - // Save time base before sleep since CPU's TBR will be set to zero at wake. - saveTimeBase(true); - - // These make all the difference between a succesful wake and a crash, - // however it is still unclear why this happens. I'll leave to B.A. to - // figure it out. - cacheInit(); - cacheDisable(); - -#ifdef VERBOSE_LOGS_ON - kprintf("GossamerCPU::quiesceCPU calling ml_ppc_sleep\n"); -#endif // VERBOSE_LOGS_ON - - // Now we loop here waiting for the PMU to kick in and sleep the machine. - // We do NOT call ml_ppc_sleep because while ml_ppc_sleep works greate for Core99 - // it has some problems with Gossamer CPUS. Also the code in ml_ppc_sleep to - // clear the interrupts (and so keep the processor in its sleep state) is needed - // by the Core99 platform (otherwise the machine does not sleep), but it is totally - // useless for Gossamer CPUs since whatever is the state of the CPU the pmu - // will put the whole system to sleep. - - while(true) { - } - - //ml_ppc_sleep(); -} - -const OSSymbol *GossamerCPU::getCPUName(void) -{ - return OSSymbol::withCStringNoCopy("Primary0"); -} - -kern_return_t GossamerCPU::startCPU(vm_offset_t /*start_paddr*/, - vm_offset_t /*arg_paddr*/) -{ - return KERN_FAILURE; -} - -void GossamerCPU::haltCPU(void) -{ - long machine_type; - grackle = NULL; - - grackle = (IOPCIBridge *)findIOInterface("AppleGracklePCI")->metaCast("IOPCIBridge"); - if (grackle == NULL) - kprintf("GossamerCPU::haltCPU missing grackle\n"); - - pci2pciBridge = NULL; - - // Finds heathrow and pmu because we need them in quienceCPU. We can - // not put the "findIOInterface" code there because it may block and - // quienceCPU runs in interrupt context. - heathrow = OSDynamicCast(IOService, findIOInterface("Heathrow")); - //Actually, pmu find is moved below because it hangs when beige G3 go to sleep - - /* - The following code is commented because the only Gossamer machine with a pci 2 pci Bridge - is the BWG3 and in that machine we do not remove power from the bridge. I am however leaving - this code here as reference (and to make clear that it is not running for a reason) - IORegistryEntry *pci2pciBridgeEntry = fromPath("/pci@80000000/@d", gIODTPlane); - IOService *pci2pciBridgeNub = OSDynamicCast(IOService, pci2pciBridgeEntry); - if (pci2pciBridgeNub != NULL) { - pci2pciBridge = OSDynamicCast(IOPCI2PCIBridge, pci2pciBridgeNub->getClient()); - } - - if (pci2pciBridge != NULL) - pci2pciBridge->saveBridgeState(); - */ -#ifdef VERBOSE_LOGS_ON - kprintf("GossamerCPU::haltCPU Here!\n"); -#endif // VERBOSE_LOGS_ON - - gossamerPE = OSDynamicCast(GossamerPE, getPlatform()); - if (gossamerPE == 0 ) - { - processor_exit(machProcessor); - return; - } - machine_type = gossamerPE->getMachineType(); - - //Isolate only those Gossamers that have a Cuda, not PG&E - if ((machine_type != kGossamerType101) && (machine_type != kGossamerTypeWallstreet)) - { - mach_timespec_t t; - IOService *cudaDriver; - IOService *usbOHCIDriver; - bool anyint = false; - - t.tv_sec = 1; - t.tv_nsec = 0; - cudaDriver = waitForService(serviceMatching("AppleCuda"), &t); - usbOHCIDriver = waitForService(serviceMatching("AppleUSBOHCI"), &t); - - if ((heathrow != NULL) && (machine_type == kGossamerTypeYosemite)) - { - heathrow->callPlatformFunction(heathrow_set_light, false, (void *)false, 0, 0, 0); - } - - gossamerPE->setProperty("GossamerCudaSleeping", true); - ml_throttle(254); //throttle cpu speed as much as possible - - while (true) //sit here in a loop, pretending to be asleep - { - machine_idle(); //Max power savings for G3 CPU, needs interrupts enabled. - // It will return when any interrupt occurs - if (cudaDriver != NULL) - { - anyint = false; - cudaDriver->callPlatformFunction(cuda_check_any_interrupt, false, (void *)&anyint, 0, 0, 0); - if (anyint) - { - break; - } - } - - if (usbOHCIDriver != NULL) - { - anyint = false; - usbOHCIDriver->callPlatformFunction(usb_remote_wakeup, false, (void *)&anyint, 0, 0, 0); - if (anyint) - { - break; - } - } - IOSleep(7); //allows USB thread to run since no more thread scheduling. 1 ms - // is enough for slow Yosemite, 7 is needed for iMacs. - } - - ml_throttle(0); //remove throttle from CPU speed - - gossamerPE->setProperty("GossamerCudaSleeping", false); - - if ((heathrow != NULL) && (machine_type == kGossamerTypeYosemite)) - { - heathrow->callPlatformFunction(heathrow_set_light, false, (void *)true, 0, 0, 0); - } - - } - else - { - pmu = OSDynamicCast(IOService, findIOInterface("ApplePMU")); -processor_exit(machProcessor); - } -} - -void GossamerCPU::saveTimeBase(bool save) -{ - if(save) { // Save time base. - do { - tbHigh = mftbu(); - tbLow = mftb(); - tbHigh2 = mftbu(); - } while (tbHigh != tbHigh2); - } else { // Restore time base - mttb(0); - mttbu(tbHigh); - mttb(tbLow); - } -} - diff --git a/iokit/Drivers/platform/drvAppleGossamerPE/GossamerCPU.h b/iokit/Drivers/platform/drvAppleGossamerPE/GossamerCPU.h deleted file mode 100644 index fa124093e..000000000 --- a/iokit/Drivers/platform/drvAppleGossamerPE/GossamerCPU.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - */ - -#ifndef _IOKIT_GOSSAMERCPU_H -#define _IOKIT_GOSSAMERCPU_H - -#include -#include - -#include "Gossamer.h" - -class GossamerCPU : public IOCPU -{ - OSDeclareDefaultStructors(GossamerCPU); - -private: - IOService *pmu; - IOService *heathrow; - IOCPUInterruptController *cpuIC; - static UInt32 restartAddress; - IOPCIBridge *grackle; - IOPCI2PCIBridge *pci2pciBridge; - unsigned long tbLow, tbHigh, tbHigh2; - GossamerPE *gossamerPE; - - // callPlatformFunction symbols - const OSSymbol *heathrow_sleepState; - const OSSymbol *heathrow_set_light; - const OSSymbol *cuda_check_any_interrupt; - const OSSymbol *usb_remote_wakeup; - -protected: - virtual IOService *findIOInterface(char*); - virtual void ipiHandler(void *refCon, void *nub, int source); - -public: - virtual bool start(IOService *provider); - virtual void initCPU(bool boot); - virtual void quiesceCPU(void); - virtual const OSSymbol* getCPUName(void); - virtual kern_return_t startCPU(vm_offset_t start_paddr, - vm_offset_t arg_paddr); - virtual void haltCPU(void); - virtual void saveTimeBase(bool); -}; - -#endif /* ! _IOKIT_GOSSAMERCPU_H */ diff --git a/iokit/Drivers/platform/drvAppleGrandCentral/GrandCentral.cpp b/iokit/Drivers/platform/drvAppleGrandCentral/GrandCentral.cpp deleted file mode 100644 index 90b1a5c8c..000000000 --- a/iokit/Drivers/platform/drvAppleGrandCentral/GrandCentral.cpp +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * DRI: Josh de Cesare - * - */ - - -#include - -#include -#include -#include -#include - -#include - -#include "GrandCentral.h" - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#define super AppleMacIO - -OSDefineMetaClassAndStructors(GrandCentral, AppleMacIO); - -bool GrandCentral::start(IOService *provider) -{ - IOInterruptAction handler; - IOPhysicalAddress base; - OSData * data; - AppleNMI *appleNMI; - IOService *sixty6; - long nmiSource; - OSData *nmiData; - IOReturn error; - - // Call MacIO's start. - if (!super::start(provider)) - return false; - - // Necessary for Control NDRV. - base = fMemory->getPhysicalAddress(); - data = OSData::withBytes(&base, sizeof(base)); - if (data != 0) provider->setProperty("AAPL,address", data); - - // Make sure the sixty6 node exists. - if (provider->childFromPath("sixty6", gIODTPlane) == 0) { - sixty6 = new IOService; - if(sixty6->init()) { - sixty6->setName("sixty6"); - sixty6->attachToParent(provider, gIODTPlane); - sixty6->registerService(); - } - } - - // Make nubs for the children. - publishBelow( provider ); - - // get the base address of the this GrandCentral. - grandCentralBaseAddress = fMemory->getVirtualAddress(); - - getPlatform()->setCPUInterruptProperties(provider); - - // Allocate the interruptController instance. - interruptController = new GrandCentralInterruptController; - if (interruptController == NULL) return false; - - // call the interruptController's init method. - error = interruptController->initInterruptController(provider, grandCentralBaseAddress); - if (error != kIOReturnSuccess) return false; - - handler = interruptController->getInterruptHandlerAddress(); - provider->registerInterrupt(0, interruptController, handler, 0); - - provider->enableInterrupt(0); - - // Register the interrupt controller so client can find it. - getPlatform()->registerInterruptController(gIODTDefaultInterruptController, - interruptController); - - // Create the NMI Driver. - nmiSource = 20; - nmiData = OSData::withBytes(&nmiSource, sizeof(long)); - appleNMI = new AppleNMI; - if ((nmiData != 0) && (appleNMI != 0)) { - appleNMI->initNMI(interruptController, nmiData); - } - - return true; -} - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#undef super -#define super IOInterruptController - -OSDefineMetaClassAndStructors(GrandCentralInterruptController, IOInterruptController); - -IOReturn GrandCentralInterruptController::initInterruptController(IOService *provider, IOLogicalAddress interruptControllerBase) -{ - int cnt; - - parentNub = provider; - - // Allocate the task lock. - taskLock = IOLockAlloc(); - if (taskLock == 0) return kIOReturnNoResources; - - // Allocate the memory for the vectors - vectors = (IOInterruptVector *)IOMalloc(kNumVectors * sizeof(IOInterruptVector)); - if (vectors == NULL) { - IOLockFree(taskLock); - return kIOReturnNoMemory; - } - bzero(vectors, kNumVectors * sizeof(IOInterruptVector)); - - // Allocate locks for the - for (cnt = 0; cnt < kNumVectors; cnt++) { - vectors[cnt].interruptLock = IOLockAlloc(); - if (vectors[cnt].interruptLock == NULL) { - for (cnt = 0; cnt < kNumVectors; cnt++) { - IOLockFree(taskLock); - if (vectors[cnt].interruptLock != NULL) - IOLockFree(vectors[cnt].interruptLock); - } - return kIOReturnNoResources; - } - } - - // Setup the registers accessors - eventsReg = (unsigned long)(interruptControllerBase + kEventsOffset); - maskReg = (unsigned long)(interruptControllerBase + kMaskOffset); - clearReg = (unsigned long)(interruptControllerBase + kClearOffset); - levelsReg = (unsigned long)(interruptControllerBase + kLevelsOffset); - - // Initialize the registers. - - // Disable all interrupts. - stwbrx(0x00000000, maskReg); - eieio(); - - // Clear all pending interrupts. - stwbrx(0xFFFFFFFF, clearReg); - eieio(); - - // Disable all interrupts. (again?) - stwbrx(0x00000000, maskReg); - eieio(); - - return kIOReturnSuccess; -} - -IOInterruptAction GrandCentralInterruptController::getInterruptHandlerAddress(void) -{ - return (IOInterruptAction)&GrandCentralInterruptController::handleInterrupt; -} - -IOReturn GrandCentralInterruptController::handleInterrupt(void * /*refCon*/, - IOService * /*nub*/, - int /*source*/) -{ - int done; - long events, vectorNumber; - IOInterruptVector *vector; - unsigned long maskTmp; - - do { - done = 1; - - // Do all the sources for events, plus any pending interrupts. - // Also add in the "level" sensitive sources - maskTmp = lwbrx(maskReg); - events = lwbrx(eventsReg) & ~kTypeLevelMask; - events |= lwbrx(levelsReg) & maskTmp & kTypeLevelMask; - events |= pendingEvents & maskTmp; - pendingEvents = 0; - eieio(); - - // Since we have to clear the level'd one clear the current edge's too. - stwbrx(kTypeLevelMask | events, clearReg); - eieio(); - - if (events) done = 0; - - while (events) { - vectorNumber = 31 - cntlzw(events); - events ^= (1 << vectorNumber); - vector = &vectors[vectorNumber]; - - vector->interruptActive = 1; - sync(); - isync(); - if (!vector->interruptDisabledSoft) { - isync(); - - // Call the handler if it exists. - if (vector->interruptRegistered) { - vector->handler(vector->target, vector->refCon, - vector->nub, vector->source); - } - } else { - // Hard disable the source. - vector->interruptDisabledHard = 1; - disableVectorHard(vectorNumber, vector); - } - - vector->interruptActive = 0; - } - } while (!done); - - return kIOReturnSuccess; -} - -bool GrandCentralInterruptController::vectorCanBeShared(long /*vectorNumber*/, IOInterruptVector */*vector*/) -{ - return true; -} - -int GrandCentralInterruptController::getVectorType(long vectorNumber, IOInterruptVector */*vector*/) -{ - int interruptType; - - if (kTypeLevelMask & (1 << vectorNumber)) { - interruptType = kIOInterruptTypeLevel; - } else { - interruptType = kIOInterruptTypeEdge; - } - - return interruptType; -} - -void GrandCentralInterruptController::disableVectorHard(long vectorNumber, IOInterruptVector */*vector*/) -{ - unsigned long maskTmp; - - // Turn the source off at hardware. - maskTmp = lwbrx(maskReg); - maskTmp &= ~(1 << vectorNumber); - stwbrx(maskTmp, maskReg); - eieio(); -} - -void GrandCentralInterruptController::enableVector(long vectorNumber, - IOInterruptVector *vector) -{ - unsigned long maskTmp; - - maskTmp = lwbrx(maskReg); - maskTmp |= (1 << vectorNumber); - stwbrx(maskTmp, maskReg); - eieio(); - if (lwbrx(levelsReg) & (1 << vectorNumber)) { - // lost the interrupt - causeVector(vectorNumber, vector); - } -} - -void GrandCentralInterruptController::causeVector(long vectorNumber, IOInterruptVector */*vector*/) -{ - pendingEvents |= 1 << vectorNumber; - parentNub->causeInterrupt(0); -} diff --git a/iokit/Drivers/platform/drvAppleGrandCentral/GrandCentral.h b/iokit/Drivers/platform/drvAppleGrandCentral/GrandCentral.h deleted file mode 100644 index 77b94974c..000000000 --- a/iokit/Drivers/platform/drvAppleGrandCentral/GrandCentral.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * DRI: Josh de Cesare - * - */ - -#ifndef _IOKIT_GRANDCENTRAL_H -#define _IOKIT_GRANDCENTRAL_H - -#include - -#include -#include - -#define kNumVectors (32) - -#define kTypeLevelMask (0x3FF00000) - -#define kEventsOffset (0x00020) -#define kMaskOffset (0x00024) -#define kClearOffset (0x00028) -#define kLevelsOffset (0x0002C) - - -class GrandCentralInterruptController; - -class GrandCentral : public AppleMacIO -{ - OSDeclareDefaultStructors(GrandCentral); - -private: - IOLogicalAddress grandCentralBaseAddress; - GrandCentralInterruptController *interruptController; - -public: - virtual bool start(IOService *provider); -}; - - -class GrandCentralInterruptController : public IOInterruptController -{ - OSDeclareDefaultStructors(GrandCentralInterruptController); - -private: - IOService *parentNub; - IOLock *taskLock; - unsigned long pendingEvents; - unsigned long eventsReg; - unsigned long maskReg; - unsigned long clearReg; - unsigned long levelsReg; - -public: - virtual IOReturn initInterruptController(IOService *provider, IOLogicalAddress interruptControllerBase); - - virtual IOInterruptAction getInterruptHandlerAddress(void); - virtual IOReturn handleInterrupt(void *refCon, IOService *nub, int source); - - virtual bool vectorCanBeShared(long vectorNumber, IOInterruptVector *vector); - virtual int getVectorType(long vectorNumber, IOInterruptVector *vector); - virtual void disableVectorHard(long vectorNumber, IOInterruptVector *vector); - virtual void enableVector(long vectorNumber, IOInterruptVector *vector); - virtual void causeVector(long vectorNumber, IOInterruptVector *vector); -}; - - -#endif /* ! _IOKIT_GRANDCENTRAL_H */ diff --git a/iokit/Drivers/platform/drvAppleI386Generic/AppleI386PlatformExpert.cpp b/iokit/Drivers/platform/drvAppleI386Generic/AppleI386PlatformExpert.cpp index ddcdbd46b..0eeb0a275 100644 --- a/iokit/Drivers/platform/drvAppleI386Generic/AppleI386PlatformExpert.cpp +++ b/iokit/Drivers/platform/drvAppleI386Generic/AppleI386PlatformExpert.cpp @@ -34,10 +34,14 @@ #include #include +#include #include "AppleI386PlatformExpert.h" #include +__BEGIN_DECLS +extern void kdreboot(void); +__END_DECLS /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define super IOPlatformExpert @@ -58,11 +62,17 @@ bool AppleI386PlatformExpert::start(IOService * provider) { gIntelPICName = (OSSymbol *) OSSymbol::withCStringNoCopy("intel-pic"); + setBootROMType(kBootROMTypeNewWorld); /* hammer to new world for i386 */ + // setupPIC(provider); if (!super::start(provider)) return false; + // Install halt/restart handler. + + PE_halt_restart = handlePEHaltRestart; + return true; } @@ -168,3 +178,24 @@ bool AppleI386PlatformExpert::getModelName( char * name, int maxLength ) return (true); } + +int AppleI386PlatformExpert::handlePEHaltRestart( unsigned int type ) +{ + int ret = 1; + + switch ( type ) + { + case kPERestartCPU: + // Use the pexpert service to reset the system through + // the keyboard controller. + kdreboot(); + break; + + case kPEHaltCPU: + default: + ret = -1; + break; + } + + return ret; +} diff --git a/iokit/Drivers/platform/drvAppleI386Generic/AppleI386PlatformExpert.h b/iokit/Drivers/platform/drvAppleI386Generic/AppleI386PlatformExpert.h index 2334e8796..8abc03e8d 100644 --- a/iokit/Drivers/platform/drvAppleI386Generic/AppleI386PlatformExpert.h +++ b/iokit/Drivers/platform/drvAppleI386Generic/AppleI386PlatformExpert.h @@ -38,6 +38,8 @@ class AppleI386PlatformExpert : public IOPlatformExpert private: void setupPIC(IOService * nub); + static int handlePEHaltRestart(unsigned int type); + public: virtual IOService * probe(IOService * provider, SInt32 * score); diff --git a/iokit/Drivers/platform/drvAppleOHare/OHare.cpp b/iokit/Drivers/platform/drvAppleOHare/OHare.cpp deleted file mode 100644 index bd3ac85d4..000000000 --- a/iokit/Drivers/platform/drvAppleOHare/OHare.cpp +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * DRI: Josh de Cesare - * - */ - - -#include - -#include -#include -#include -#include - -#include - -#include "OHare.h" - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#define super AppleMacIO - -OSDefineMetaClassAndStructors(OHare, AppleMacIO); - -bool OHare::start(IOService *provider) -{ - IOInterruptAction handler; - OSSymbol *interruptControllerName; - AppleNMI *appleNMI; - long nmiSource; - OSData *nmiData; - IOReturn error; - - // Call MacIO's start. - if (!super::start(provider)) - return false; - - // Figure out which ohare this is. - if (IODTMatchNubWithKeys(provider, "ohare")) - ohareNum = kPrimaryOHare; - else if (IODTMatchNubWithKeys(provider, "'pci106b,7'")) - ohareNum = kSecondaryOHare; - else return false; // This should not happen. - - if (ohareNum == kPrimaryOHare) { - getPlatform()->setCPUInterruptProperties(provider); - } - - // Make nubs for the children. - publishBelow( provider ); - - // get the base address of the this OHare. - ohareBaseAddress = fMemory->getVirtualAddress(); - - // get the name of the interrupt controller - interruptControllerName = getInterruptControllerName(); - - // Allocate the interruptController instance. - interruptController = new OHareInterruptController; - if (interruptController == NULL) return false; - - // call the interruptController's init method. - error = interruptController->initInterruptController(provider, ohareBaseAddress); - if (error != kIOReturnSuccess) return false; - - handler = interruptController->getInterruptHandlerAddress(); - provider->registerInterrupt(0, interruptController, handler, 0); - - provider->enableInterrupt(0); - - // Register the interrupt controller so clients can find it. - getPlatform()->registerInterruptController(interruptControllerName, - interruptController); - - if (ohareNum != kPrimaryOHare) return true; - - // Create the NMI Driver. - nmiSource = 20; - nmiData = OSData::withBytes(&nmiSource, sizeof(long)); - appleNMI = new AppleNMI; - if ((nmiData != 0) && (appleNMI != 0)) { - appleNMI->initNMI(interruptController, nmiData); - } - - return true; -} - -OSSymbol *OHare::getInterruptControllerName(void) -{ - OSSymbol *interruptControllerName; - - switch (ohareNum) { - case kPrimaryOHare : - interruptControllerName = gIODTDefaultInterruptController; - break; - - case kSecondaryOHare : - interruptControllerName = OSSymbol::withCStringNoCopy("SecondaryInterruptController"); - break; - - default: - interruptControllerName = OSSymbol::withCStringNoCopy("UnknownInterruptController"); - break; - } - - return interruptControllerName; -} - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#undef super -#define super IOInterruptController - -OSDefineMetaClassAndStructors(OHareInterruptController, IOInterruptController); - -IOReturn OHareInterruptController::initInterruptController(IOService *provider, IOLogicalAddress interruptControllerBase) -{ - int cnt; - - parentNub = provider; - - // Allocate the task lock. - taskLock = IOLockAlloc(); - if (taskLock == 0) return kIOReturnNoResources; - - // Allocate the memory for the vectors - vectors = (IOInterruptVector *)IOMalloc(kNumVectors * sizeof(IOInterruptVector)); - if (vectors == NULL) { - IOLockFree(taskLock); - return kIOReturnNoMemory; - } - bzero(vectors, kNumVectors * sizeof(IOInterruptVector)); - - // Allocate locks for the - for (cnt = 0; cnt < kNumVectors; cnt++) { - vectors[cnt].interruptLock = IOLockAlloc(); - if (vectors[cnt].interruptLock == NULL) { - for (cnt = 0; cnt < kNumVectors; cnt++) { - IOLockFree(taskLock); - if (vectors[cnt].interruptLock != NULL) - IOLockFree(vectors[cnt].interruptLock); - } - return kIOReturnNoResources; - } - } - - // Setup the registers accessors - eventsReg = (unsigned long)(interruptControllerBase + kEventsOffset); - maskReg = (unsigned long)(interruptControllerBase + kMaskOffset); - clearReg = (unsigned long)(interruptControllerBase + kClearOffset); - levelsReg = (unsigned long)(interruptControllerBase + kLevelsOffset); - - // Initialize the registers. - - // Disable all interrupts. - stwbrx(0x00000000, maskReg); - eieio(); - - // Clear all pending interrupts. - stwbrx(0xFFFFFFFF, clearReg); - eieio(); - - // Disable all interrupts. (again?) - stwbrx(0x00000000, maskReg); - eieio(); - - return kIOReturnSuccess; -} - -IOInterruptAction OHareInterruptController::getInterruptHandlerAddress(void) -{ - return (IOInterruptAction)&OHareInterruptController::handleInterrupt; -} - -IOReturn OHareInterruptController::handleInterrupt(void * /*refCon*/, - IOService * /*nub*/, - int /*source*/) -{ - int done; - long events, vectorNumber; - IOInterruptVector *vector; - unsigned long maskTmp; - - do { - done = 1; - - // Do all the sources for events, plus any pending interrupts. - // Also add in the "level" sensitive sources - maskTmp = lwbrx(maskReg); - events = lwbrx(eventsReg) & ~kTypeLevelMask; - events |= lwbrx(levelsReg) & maskTmp & kTypeLevelMask; - events |= pendingEvents & maskTmp; - pendingEvents = 0; - eieio(); - - // Since we have to clear the level'd one clear the current edge's too. - stwbrx(kTypeLevelMask | events, clearReg); - eieio(); - - if (events) done = 0; - - while (events) { - vectorNumber = 31 - cntlzw(events); - events ^= (1 << vectorNumber); - vector = &vectors[vectorNumber]; - - vector->interruptActive = 1; - sync(); - isync(); - if (!vector->interruptDisabledSoft) { - isync(); - - // Call the handler if it exists. - if (vector->interruptRegistered) { - vector->handler(vector->target, vector->refCon, - vector->nub, vector->source); - } - } else { - // Hard disable the source. - vector->interruptDisabledHard = 1; - disableVectorHard(vectorNumber, vector); - } - - vector->interruptActive = 0; - } - } while (!done); - - return kIOReturnSuccess; -} - -bool OHareInterruptController::vectorCanBeShared(long /*vectorNumber*/, IOInterruptVector */*vector*/) -{ - return true; -} - -int OHareInterruptController::getVectorType(long vectorNumber, IOInterruptVector */*vector*/) -{ - int interruptType; - - if (kTypeLevelMask & (1 << vectorNumber)) { - interruptType = kIOInterruptTypeLevel; - } else { - interruptType = kIOInterruptTypeEdge; - } - - return interruptType; -} - -void OHareInterruptController::disableVectorHard(long vectorNumber, IOInterruptVector */*vector*/) -{ - unsigned long maskTmp; - - // Turn the source off at hardware. - maskTmp = lwbrx(maskReg); - maskTmp &= ~(1 << vectorNumber); - stwbrx(maskTmp, maskReg); - eieio(); -} - -void OHareInterruptController::enableVector(long vectorNumber, - IOInterruptVector *vector) -{ - unsigned long maskTmp; - - maskTmp = lwbrx(maskReg); - maskTmp |= (1 << vectorNumber); - stwbrx(maskTmp, maskReg); - eieio(); - if (lwbrx(levelsReg) & (1 << vectorNumber)) { - // lost the interrupt - causeVector(vectorNumber, vector); - } -} - -void OHareInterruptController::causeVector(long vectorNumber, - IOInterruptVector */*vector*/) -{ - pendingEvents |= 1 << vectorNumber; - parentNub->causeInterrupt(0); -} diff --git a/iokit/Drivers/platform/drvAppleOHare/OHare.h b/iokit/Drivers/platform/drvAppleOHare/OHare.h deleted file mode 100644 index 42d672ce6..000000000 --- a/iokit/Drivers/platform/drvAppleOHare/OHare.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * DRI: Josh de Cesare - * - */ - -#ifndef _IOKIT_OHARE_H -#define _IOKIT_OHARE_H - -#include - -#include -#include - -#define kPrimaryOHare (0) -#define kSecondaryOHare (1) - -#define kNumVectors (32) - -#define kTypeLevelMask (0x1FF00000) - -#define kEventsOffset (0x00020) -#define kMaskOffset (0x00024) -#define kClearOffset (0x00028) -#define kLevelsOffset (0x0002C) - - -class OHareInterruptController; - -class OHare : public AppleMacIO -{ - OSDeclareDefaultStructors(OHare); - -private: - IOLogicalAddress ohareBaseAddress; - long ohareNum; - OHareInterruptController *interruptController; - - virtual OSSymbol *getInterruptControllerName(void); - -public: - virtual bool start(IOService *provider); -}; - - -class OHareInterruptController : public IOInterruptController -{ - OSDeclareDefaultStructors(OHareInterruptController); - -private: - IOService *parentNub; - IOLock *taskLock; - unsigned long pendingEvents; - unsigned long eventsReg; - unsigned long maskReg; - unsigned long clearReg; - unsigned long levelsReg; - -public: - virtual IOReturn initInterruptController(IOService *provider, - IOLogicalAddress interruptControllerBase); - - virtual IOInterruptAction getInterruptHandlerAddress(void); - virtual IOReturn handleInterrupt(void *refCon, IOService *nub, int source); - - virtual bool vectorCanBeShared(long vectorNumber, IOInterruptVector *vector); - virtual int getVectorType(long vectorNumber, IOInterruptVector *vector); - virtual void disableVectorHard(long vectorNumber, IOInterruptVector *vector); - virtual void enableVector(long vectorNumber, IOInterruptVector *vector); - virtual void causeVector(long vectorNumber, IOInterruptVector *vector); -}; - - -#endif /* ! _IOKIT_OHARE_H */ diff --git a/iokit/Drivers/platform/drvApplePMU/IOPMUADBController.cpp b/iokit/Drivers/platform/drvApplePMU/IOPMUADBController.cpp index 8220e8511..978cedac4 100644 --- a/iokit/Drivers/platform/drvApplePMU/IOPMUADBController.cpp +++ b/iokit/Drivers/platform/drvApplePMU/IOPMUADBController.cpp @@ -23,6 +23,7 @@ * 12 Nov 1998 suurballe Created. */ +#include #include #include "IOPMUADBController.h" @@ -69,7 +70,7 @@ bool IOPMUADBController::start ( IOService * nub ) waitingForData = NULL; // Registers for the two interrupts that needs to handle: - if (PMUdriver->callPlatformFunction("registerForPMUInterrupts", true, (void*)kPMUADBint, (void*)handleADBInterrupt, (void*)this, NULL) != kIOReturnSuccess) { + if (PMUdriver->callPlatformFunction("registerForPMUInterrupts", true, (void*) (kPMUADBint | kPMUenvironmentInt), (void*)handleADBInterrupt, (void*)this, NULL) != kIOReturnSuccess) { #ifdef VERBOSE_LOGS_ON IOLog("IOPMUADBController::start registerForPMUInterrupts kPMUADBint fails\n"); #endif // VERBOSE_LOGS_ON @@ -83,6 +84,8 @@ bool IOPMUADBController::start ( IOService * nub ) if (!requestMutexLock) return false; + clamshellOpen = true; + // This happens last (while the most common place is the begin) because // trhe superclass may need the services of the functions above. if( !super::start(nub)) @@ -105,7 +108,7 @@ void IOPMUADBController::free ( ) // And removes the interrupt handler: if (PMUdriver != NULL) - PMUdriver->callPlatformFunction("deRegisterClient", true, (void*)this, (void*)kPMUADBint, NULL, NULL); + PMUdriver->callPlatformFunction("deRegisterClient", true, (void*)this, (void*)(kPMUADBint | kPMUenvironmentInt), NULL, NULL); } // ********************************************************************************** @@ -144,7 +147,9 @@ IOReturn IOPMUADBController::localSendMiscCommand(int command, IOByteCount sLeng // ********************************************************************************** // this is the interrupt handler for all ADB interrupts: -// +// A.W. Added code to check for clamshell status, and block all ADB traffic except +// for POWER key scan code from default ADB keyboard or devices that connect +// to that keyboard power button. // ********************************************************************************** /* static */ void @@ -156,8 +161,36 @@ IOPMUADBController::handleADBInterrupt(IOService *client, UInt8 interruptMask, U if (myThis == NULL) return; + if (interruptMask & kPMUenvironmentInt) + { + if (buffer) + { + if (*buffer & kClamshellClosedEventMask) + myThis->clamshellOpen = false; + else + myThis->clamshellOpen = true; + } + if ( !(interruptMask & kPMUautopoll)) + { + return; //Nothing left to do + } + } if ((interruptMask & kPMUautopoll) && (myThis->autopollOn)) - autopollHandler(client, buffer[0], length - 1, buffer + 1); // yes, call adb input handler + { + if (myThis->clamshellOpen) + { + autopollHandler(client, buffer[0], length - 1, buffer + 1); // yes, call adb input handler + } + else if ( (buffer[0] == 0x2c) && (buffer[1] == 0x7f) && (buffer[2] == 0x7f)) + { + autopollHandler(client, buffer[0], length - 1, buffer + 1); // POWER down + } + else if ( (buffer[0] == 0x2c) && (buffer[1] == 0xff) && (buffer[2] == 0xff)) + { + autopollHandler(client, buffer[0], length - 1, buffer + 1); // POWER up + } + + } else { if (myThis->waitingForData != NULL) { // Complets the adb transaction diff --git a/iokit/Drivers/platform/drvApplePMU/IOPMUADBController.h b/iokit/Drivers/platform/drvApplePMU/IOPMUADBController.h index e7e8201d5..697967eff 100644 --- a/iokit/Drivers/platform/drvApplePMU/IOPMUADBController.h +++ b/iokit/Drivers/platform/drvApplePMU/IOPMUADBController.h @@ -62,6 +62,7 @@ private: enum { // when kPMUADBint is set kPMUADBint = 0x10, + kPMUenvironmentInt = 0x40, // Environment changed (clamshell) kPMUwaitinglsc = 0x01, // waiting to listen to charger kPMUautoSRQpolling = 0x02, // auto/SRQ polling is enabled kPMUautopoll = 0x04 // input is autopoll data @@ -81,6 +82,7 @@ private: IOService *PMUdriver; UInt32 pollList; // ADB autopoll device bitmap bool autopollOn; // TRUE: PMU is autopolling + bool clamshellOpen; // Normally TRUE UInt32 dataLen; // data len as result of an interrupt UInt8 dataBuffer[256]; // data as result of an interrupt diff --git a/iokit/Drivers/platform/drvApplePowerExpressPE/PowerExpress.cpp b/iokit/Drivers/platform/drvApplePowerExpressPE/PowerExpress.cpp deleted file mode 100644 index 8559ba80c..000000000 --- a/iokit/Drivers/platform/drvApplePowerExpressPE/PowerExpress.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * DRI: Josh de Cesare - * - */ - -#include - -#include "PowerExpress.h" - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#define super ApplePlatformExpert - -OSDefineMetaClassAndStructors(PowerExpressPE, ApplePlatformExpert); - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -bool PowerExpressPE::start(IOService *provider) -{ - OSData *tmpData; - - setChipSetType(kChipSetTypePowerExpress); - - tmpData = OSDynamicCast(OSData, getProperty("senses")); - if (tmpData) senseArray = (long *)tmpData->getBytesNoCopy(); - - return super::start(provider); -} - -bool PowerExpressPE::platformAdjustService(IOService *service) -{ - long cnt, numInterrupts, sourceNumbers[2]; - OSData *tmpData; - OSArray *controllers, *specifiers; - OSSymbol *controller; - - // Fix up the interrupt data. - controllers = OSDynamicCast(OSArray, service->getProperty(gIOInterruptControllersKey)); - specifiers = OSDynamicCast(OSArray, service->getProperty(gIOInterruptSpecifiersKey)); - if (controllers && specifiers) { - numInterrupts = specifiers->getCount(); - for (cnt = 0; cnt < numInterrupts; cnt++) { - // Only change interrupts for MPIC. - controller = OSDynamicCast(OSSymbol, controllers->getObject(cnt)); - if (controller == gIODTDefaultInterruptController) { - tmpData = OSDynamicCast(OSData, specifiers->getObject(cnt)); - if (tmpData && (tmpData->getLength() == 4)) { - sourceNumbers[0] = *(long *)tmpData->getBytesNoCopy(); - sourceNumbers[1] = senseArray[sourceNumbers[0]]; - tmpData = OSData::withBytes(sourceNumbers, 2 * sizeof(long)); - if (tmpData) { - specifiers->setObject(cnt, tmpData); - tmpData->release(); - } - } - } - } - } - - if (IODTMatchNubWithKeys(service, "open-pic")) { - service->setProperty("InterruptControllerName", - gIODTDefaultInterruptController); - return true; - } - - return true; -} diff --git a/iokit/Drivers/platform/drvApplePowerExpressPE/PowerExpress.h b/iokit/Drivers/platform/drvApplePowerExpressPE/PowerExpress.h deleted file mode 100644 index c6e372383..000000000 --- a/iokit/Drivers/platform/drvApplePowerExpressPE/PowerExpress.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * DRI: Josh de Cesare - * - */ - - -#ifndef _IOKIT_POWEREXPRESS_H -#define _IOKIT_POWEREXPRESS_H - -#include - -class PowerExpressPE : public ApplePlatformExpert -{ - OSDeclareDefaultStructors(PowerExpressPE); - -private: - long *senseArray; - -public: - virtual bool start(IOService *provider); - - virtual bool platformAdjustService(IOService *service); -}; - - -#endif /* ! _IOKIT_POWEREXPRESS_H */ diff --git a/iokit/Drivers/platform/drvApplePowerStarPE/PowerStar.cpp b/iokit/Drivers/platform/drvApplePowerStarPE/PowerStar.cpp deleted file mode 100644 index a8b65211b..000000000 --- a/iokit/Drivers/platform/drvApplePowerStarPE/PowerStar.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * DRI: Josh de Cesare - * - */ - -#include - -#include "PowerStar.h" -#include "../drvAppleOHare/OHare.h" - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#define super ApplePlatformExpert - -OSDefineMetaClassAndStructors(PowerStarPE, ApplePlatformExpert); - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -bool PowerStarPE::start(IOService *provider) -{ - setChipSetType(kChipSetTypePowerStar); - - // See if it is a Hooper or Kanga. - if (IODTMatchNubWithKeys(provider, "('AAPL,3400/2400', 'AAPL,3500')")) { - configureEthernet(provider); - } - - _pePMFeatures = kStdPowerBookPMFeatures; - _pePrivPMFeatures = kStdPowerBookPrivPMFeatures; - _peNumBatteriesSupported = kStdPowerBookNumBatteries; - - return super::start(provider); -} - -bool PowerStarPE::platformAdjustService(IOService *service) -{ - if (!strcmp(service->getName(), "chips65550")) { - service->setProperty("Ignore VBL", "", 0); - return true; - } - - return true; -} - -void PowerStarPE::configureEthernet(IOService *provider) -{ - OSCollectionIterator *nodeList; - IORegistryEntry *node, *enet, *ohare; - OSArray *interruptNames, *interruptSources; - OSSymbol *interruptControllerName; - OSData *tempData; - long tempSource; - - enet = 0; - ohare = 0; - - // Find the node for DEC21041. - nodeList = IODTFindMatchingEntries(provider, kIODTRecursive, - "'pci1011,14'"); - if (nodeList) { - while ((node = (IORegistryEntry *)nodeList->getNextObject())) { - enet = node; - } - nodeList->release(); - } - - if (enet == 0) return; - - // Set the 'Network Connection' property to '10BaseT'. - enet->setProperty("Network Connection", "10BaseT"); - - // Add a 'built-in' property so IONetworkStack will treat it as built in. - enet->setProperty("built-in", "", 0); - - // If it is there, find the node for the second ohare. - nodeList = IODTFindMatchingEntries(provider, kIODTRecursive, - "'pci106b,7'"); - if (nodeList) { - while ((node = (IORegistryEntry *)nodeList->getNextObject())) { - ohare = node; - } - nodeList->release(); - } - - if (ohare == 0) return; - - interruptNames = OSDynamicCast(OSArray, - enet->getProperty(gIOInterruptControllersKey)); - interruptControllerName = (OSSymbol *)OSSymbol::withCStringNoCopy("SecondaryInterruptController"); - interruptNames->setObject(0, interruptControllerName); - interruptControllerName->release(); - - interruptSources = OSDynamicCast(OSArray, - enet->getProperty(gIOInterruptSpecifiersKey)); - tempSource = 28; - tempData = OSData::withBytes(&tempSource, sizeof(tempSource)); - interruptSources->setObject(0, tempData); - tempData->release(); -} diff --git a/iokit/Drivers/platform/drvApplePowerStarPE/PowerStar.h b/iokit/Drivers/platform/drvApplePowerStarPE/PowerStar.h deleted file mode 100644 index 4be509ebf..000000000 --- a/iokit/Drivers/platform/drvApplePowerStarPE/PowerStar.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * DRI: Josh de Cesare - * - */ - - -#ifndef _IOKIT_POWERSTAR_H -#define _IOKIT_POWERSTAR_H - -#include - -class PowerStarPE : public ApplePlatformExpert -{ - OSDeclareDefaultStructors(PowerStarPE); - -private: - virtual void configureEthernet(IOService *provider); - -public: - virtual bool start(IOService *provider); - virtual bool platformAdjustService(IOService *service); -}; - - -#endif /* ! _IOKIT_POWERSTAR_H */ diff --git a/iokit/Drivers/platform/drvApplePowerSurgePE/PowerSurge.cpp b/iokit/Drivers/platform/drvApplePowerSurgePE/PowerSurge.cpp deleted file mode 100644 index 82478bcc5..000000000 --- a/iokit/Drivers/platform/drvApplePowerSurgePE/PowerSurge.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * DRI: Josh de Cesare - * - */ - -#include - -#include "PowerSurge.h" - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#define super ApplePlatformExpert - -OSDefineMetaClassAndStructors(PowerSurgePE, ApplePlatformExpert); - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -bool PowerSurgePE::start(IOService *provider) -{ - setChipSetType(kChipSetTypePowerSurge); - - _pePMFeatures = kStdDesktopPMFeatures; - _pePrivPMFeatures = kStdDesktopPrivPMFeatures; - _peNumBatteriesSupported = kStdDesktopNumBatteries; - - return super::start(provider); -} diff --git a/iokit/Drivers/platform/drvApplePowerSurgePE/PowerSurge.h b/iokit/Drivers/platform/drvApplePowerSurgePE/PowerSurge.h deleted file mode 100644 index 9e31449d5..000000000 --- a/iokit/Drivers/platform/drvApplePowerSurgePE/PowerSurge.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * DRI: Josh de Cesare - * - */ - - -#ifndef _IOKIT_POWERSURGE_H -#define _IOKIT_POWERSURGE_H - -#include - -class PowerSurgePE : public ApplePlatformExpert -{ - OSDeclareDefaultStructors(PowerSurgePE); - -public: - virtual bool start(IOService *provider); -}; - - -#endif /* ! _IOKIT_POWERSURGE_H */ diff --git a/iokit/Drivers/platform/drvAppleRootDomain/RootDomain.cpp b/iokit/Drivers/platform/drvAppleRootDomain/RootDomain.cpp index f9673a3aa..4378b4ee7 100644 --- a/iokit/Drivers/platform/drvAppleRootDomain/RootDomain.cpp +++ b/iokit/Drivers/platform/drvAppleRootDomain/RootDomain.cpp @@ -1,4 +1,4 @@ -/* + /* * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ @@ -20,9 +20,11 @@ * @APPLE_LICENSE_HEADER_END@ */ #include -#include +#include #include #include +#include +#include #include #include #include @@ -33,7 +35,17 @@ extern "C" void kprintf(const char *, ...); extern const IORegistryPlane * gIOPowerPlane; -void PMreceiveCmd ( OSObject *, void *, void *, void *, void * ); +// debug trace function +static inline void +ioSPMTrace(unsigned int csc, + unsigned int a = 0, unsigned int b = 0, + unsigned int c = 0, unsigned int d = 0) +{ + if (gIOKitDebug & kIOLogTracePower) + IOTimeStampConstant(IODBG_POWER(csc), a, b, c, d); +} + +IOReturn broadcast_aggressiveness ( OSObject *, void *, void *, void *, void * ); static void sleepTimerExpired(thread_call_param_t); static void wakeupClamshellTimerExpired ( thread_call_param_t us); @@ -209,11 +221,6 @@ bool IOPMrootDomain::start ( IOService * nub ) tmpDict->release(); pm_vars->PMworkloop = IOWorkLoop::workLoop(); // make the workloop - pm_vars->commandQueue = IOCommandQueue::commandQueue(this, PMreceiveCmd); // make a command queue - if (! pm_vars->commandQueue || - ( pm_vars->PMworkloop->addEventSource( pm_vars->commandQueue) != kIOReturnSuccess) ) { - return IOPMNoErr; - } extraSleepTimer = thread_call_allocate((thread_call_func_t)sleepTimerExpired, (thread_call_param_t) this); clamshellWakeupIgnore = thread_call_allocate((thread_call_func_t)wakeupClamshellTimerExpired, (thread_call_param_t) this); diskSyncCalloutEntry = thread_call_allocate(&disk_sync_callout, (thread_call_param_t) this); @@ -241,6 +248,27 @@ bool IOPMrootDomain::start ( IOService * nub ) return true; } +// ********************************************************************************** +// setProperties +// +// Receive a setProperty call +// The "System Boot" property means the system is completely booted. +// ********************************************************************************** +IOReturn IOPMrootDomain::setProperties ( OSObject *props_obj) +{ + OSDictionary *dict = OSDynamicCast(OSDictionary, props_obj); + + if(!dict) return kIOReturnBadArgument; + + if(dict->getObject(OSString::withCString("System Boot Complete"))) { + systemBooting = false; + kprintf("IOPM: received System Boot Complete property"); + adjustPowerState(); + } + + return kIOReturnSuccess; +} + //********************************************************************************* // youAreRoot @@ -258,46 +286,58 @@ IOReturn IOPMrootDomain::youAreRoot ( void ) // ********************************************************************************** // command_received // -// We have received a command from ourselves on the command queue. -// If it is to send a recently-received aggressiveness factor, do so. -// Otherwise, it's something the superclass enqueued. +// No longer used // ********************************************************************************** -void IOPMrootDomain::command_received ( void * command, void * x, void * y, void * z ) +void IOPMrootDomain::command_received ( void * w, void * x, void * y, void * z ) { - switch ( (int)command ) { - case kIOPMBroadcastAggressiveness: - - super::setAggressiveness((unsigned long)x,(unsigned long)y); + super::command_received(w,x,y,z); +} - // Save user's spin down timer to restore after we replace it for idle sleep - if( (int)x == kPMMinutesToSpinDown ) user_spindown = (unsigned int) y; - // Use longestNonSleepSlider to calculate dimming adjust idle sleep timer - longestNonSleepSlider = pm_vars->current_aggressiveness_values[kPMMinutesToDim]; +// ********************************************************************************** +// broadcast_aggressiveness +// +// ********************************************************************************** +IOReturn broadcast_aggressiveness ( OSObject * root, void * x, void * y, void *, void * ) +{ + ((IOPMrootDomain *)root)->broadcast_it((unsigned long)x,(unsigned long)y); + return IOPMNoErr; +} - if ( (int)x == kPMMinutesToSleep ) { - if ( (sleepSlider == 0) && ((int)y != 0) ) { - sleepSlider = (int)y; - adjustPowerState(); // idle sleep is now enabled, maybe sleep now - } - sleepSlider = (int)y; - if ( sleepSlider == 0 ) { - adjustPowerState(); // idle sleep is now disabled - patriarch->wakeSystem(); // make sure we're powered - } - } - if ( sleepSlider > longestNonSleepSlider ) { - extraSleepDelay = sleepSlider - longestNonSleepSlider ; - } - else { - extraSleepDelay = 0; - } - break; - - default: - super::command_received(command,x,y,z); - break; +// ********************************************************************************** +// broadcast_it +// +// We are behind the command gate to broadcast an aggressiveness factor. We let the +// superclass do it, but we need to snoop on factors that affect idle sleep. +// ********************************************************************************** +void IOPMrootDomain::broadcast_it (unsigned long type, unsigned long value) +{ + super::setAggressiveness(type,value); + + // Save user's spin down timer to restore after we replace it for idle sleep + if( type == kPMMinutesToSpinDown ) user_spindown = value; + + // Use longestNonSleepSlider to calculate dimming adjust idle sleep timer + longestNonSleepSlider = pm_vars->current_aggressiveness_values[kPMMinutesToDim]; + + + if ( type == kPMMinutesToSleep ) { + if ( (sleepSlider == 0) && (value != 0) ) { + sleepSlider = value; + adjustPowerState(); // idle sleep is now enabled, maybe sleep now + } + sleepSlider = value; + if ( sleepSlider == 0 ) { + adjustPowerState(); // idle sleep is now disabled + patriarch->wakeSystem(); // make sure we're powered + } + } + if ( sleepSlider > longestNonSleepSlider ) { + extraSleepDelay = sleepSlider - longestNonSleepSlider ; + } + else { + extraSleepDelay = 0; } } @@ -349,8 +389,7 @@ void IOPMrootDomain::stopIgnoringClamshellEventsDuringWakeup(void) //********************************************************************************* // setAggressiveness // -// Some aggressiveness factor has changed. We put this change on our -// command queue so that we can broadcast it to the hierarchy while on +// Some aggressiveness factor has changed. We broadcast it to the hierarchy while on // the Power Mangement workloop thread. This enables objects in the // hierarchy to successfully alter their idle timers, which are all on the // same thread. @@ -358,14 +397,9 @@ void IOPMrootDomain::stopIgnoringClamshellEventsDuringWakeup(void) IOReturn IOPMrootDomain::setAggressiveness ( unsigned long type, unsigned long newLevel ) { - - if ( systemBooting && (type == kPMMinutesToDim) ) { - systemBooting = false; // when the login window launches, this method gets called -- system booting is done. - IOLog("Root power domain receiving initial preferences\n"); - adjustPowerState(); + if ( pm_vars->PMcommandGate ) { + pm_vars->PMcommandGate->runAction(broadcast_aggressiveness,(void *)type,(void *)newLevel); } - - pm_vars->commandQueue->enqueueCommand(true, (void *)kIOPMBroadcastAggressiveness, (void *) type, (void *) newLevel ); return kIOReturnSuccess; } @@ -436,8 +470,9 @@ void IOPMrootDomain::powerChangeDone ( unsigned long previousState ) idleSleepPending = false; // re-enable this timer for next sleep IOLog("System Sleep\n"); pm_vars->thePlatform->sleepKernel(); // sleep now - - // now we're waking + + ioSPMTrace(IOPOWER_WAKE, * (int *) this); // now we're waking + clock_interval_to_deadline(30, kSecondScale, &deadline); // stay awake for at least 30 seconds thread_call_enter_delayed(extraSleepTimer, deadline); idleSleepPending = true; // this gets turned off when we sleep again @@ -573,6 +608,10 @@ IOReturn IOPMrootDomain::newUserClient( task_t owningTask, void * /* security_ IOReturn IOPMrootDomain::receivePowerNotification (UInt32 msg) { + if (msg & kIOPMOverTemp) { + IOLog("Power Management received emergency overtemp signal. Going to sleep."); + (void) sleepSystem (); + } if (msg & kIOPMSetDesktopMode) { desktopMode = (0 != (msg & kIOPMSetValue)); msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue); @@ -603,11 +642,6 @@ IOReturn IOPMrootDomain::receivePowerNotification (UInt32 msg) (void) sleepSystem (); } - if (msg & kIOPMOverTemp) { - IOLog("Power Management received emergency overtemp signal. Going to sleep."); - (void) sleepSystem (); - } - if (msg & kIOPMClamshellClosed) { if ( !ignoringClamshell && !ignoringClamshellDuringWakeup && (!desktopMode || !acAdaptorConnect) ) { @@ -718,7 +752,7 @@ IOReturn IOPMrootDomain::requestPowerDomainState ( IOPMPowerFlags desiredState, } iter->release(); } - + if ( (extraSleepDelay == 0) && (powerRequestFlag == 0) ) { sleepASAP = true; } @@ -857,6 +891,26 @@ void IOPMrootDomain::restoreUserSpinDownTimeout ( void ) super::setAggressiveness((unsigned long)kPMMinutesToSpinDown,(unsigned long)user_spindown); } +//********************************************************************************* +// changePowerStateTo & changePowerStateToPriv +// +// Override of these methods for logging purposes. +//********************************************************************************* + +IOReturn IOPMrootDomain::changePowerStateTo ( unsigned long ordinal ) +{ + ioSPMTrace(IOPOWER_ROOT, * (int *) this, (int) true, (int) ordinal); + + return super::changePowerStateTo(ordinal); +} + +IOReturn IOPMrootDomain::changePowerStateToPriv ( unsigned long ordinal ) +{ + ioSPMTrace(IOPOWER_ROOT, * (int *) this, (int) false, (int) ordinal); + + return super::changePowerStateToPriv(ordinal); +} + //********************************************************************************* // sysPowerDownHandler @@ -900,7 +954,7 @@ IOReturn IOPMrootDomain::sysPowerDownHandler( void * target, void * refCon, // Another option is not to schedule the thread and wait for // ack timeout... AbsoluteTime deadline; - clock_interval_to_deadline( 15, kSecondScale, &deadline ); + clock_interval_to_deadline( 30, kSecondScale, &deadline ); thread_call_enter1_delayed( rootDomain->diskSyncCalloutEntry, (thread_call_param_t)params->powerRef, deadline ); @@ -970,7 +1024,8 @@ IOReturn IOPMrootDomain::displayWranglerNotification( void * target, void * refC } else { // accelerate disk spin down if spin down timer is non-zero (zero = never spin down) - if(0 != rootDomain->user_spindown) + // and if system sleep is non-Never + if( (0 != rootDomain->user_spindown) && (0 != rootDomain->sleepSlider) ) rootDomain->setQuickSpinDownTimeout(); } diff --git a/iokit/Drivers/platform/drvAppleRootDomain/RootDomain.h b/iokit/Drivers/platform/drvAppleRootDomain/RootDomain.h deleted file mode 100644 index 10dccbd06..000000000 --- a/iokit/Drivers/platform/drvAppleRootDomain/RootDomain.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -#ifndef _IOKIT_ROOTDOMAIN_H -#define _IOKIT_ROOTDOMAIN_H - -#include -#include - -class RootDomainUserClient; - -#define number_of_power_states 2 -#define powerOn 1 - - -class IOPMrootDomain: public IOService -{ -OSDeclareDefaultStructors(IOPMrootDomain) - -public: - - virtual bool start( IOService * provider ); - virtual IOReturn newUserClient ( task_t, void *, UInt32, IOUserClient ** ); - virtual IOReturn setAggressiveness ( unsigned long, unsigned long ); - virtual IOReturn getAggressiveness ( unsigned long, unsigned long * ); - - -private: - - unsigned long current_values[kMaxType+1]; // current values of aggressiveness factors - UInt16 serialNumber; // used to identify sleep/wake notification cycle - OSArray* responseFlags; // points to array of responses from apps - bool doNotSleep; // true if an application vetos sleep notification - - virtual IOReturn setPowerState ( long, IOService* ); - virtual unsigned long maxCapabilityForDomainState ( IOPMPowerFlags ); - virtual unsigned long powerStateForDomainState ( IOPMPowerFlags ); - virtual void notifyApps ( void ); - virtual bool responseValid ( unsigned long refcon ); - virtual void checkForDone ( void ); - unsigned long initialPowerStateForDomainState ( IOPMPowerFlags); - void command_received ( void *, void * , void * , void *); - -}; - -#endif /* _IOKIT_ROOTDOMAIN_H */ diff --git a/iokit/Families/IOADBBus/IOADBController.cpp b/iokit/Families/IOADBBus/IOADBController.cpp index c0c75b0b9..76ff4cdf4 100644 --- a/iokit/Families/IOADBBus/IOADBController.cpp +++ b/iokit/Families/IOADBBus/IOADBController.cpp @@ -521,12 +521,12 @@ bool IOADBController::matchNubWithPropertyTable( IOService * device, OSDictionar keys++; } else { - if( deviceInfo->defaultAddress != strtol(keys, &keys, 16)) { + if( deviceInfo->defaultAddress != strtol(keys, (char **) &keys, 16)) { break; } } if( *keys++ == '-' ) { - if( deviceInfo->defaultHandlerID != strtol(keys, &keys, 16)) { + if( deviceInfo->defaultHandlerID != strtol(keys, (char **) &keys, 16)) { break; } } diff --git a/iokit/Families/IOATAStandard/ATAQueueHelpers.cpp b/iokit/Families/IOATAStandard/ATAQueueHelpers.cpp deleted file mode 100644 index 1f15dd6b9..000000000 --- a/iokit/Families/IOATAStandard/ATAQueueHelpers.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * queueHelpers.cpp - * - */ -#include - -void IOATAStandardDevice::addCommand( queue_head_t *list, IOATAStandardCommand *ataCmd ) -{ - ataCmd->list = list; - - queue_enter( list, ataCmd, IOATAStandardCommand *, nextCommand ); -} - -void IOATAStandardDevice::deleteCommand( queue_head_t *list, IOATAStandardCommand *ataCmd, IOReturn rc = kIOReturnSuccess ) -{ - ataCmd->list = 0; - - if ( rc != kIOReturnSuccess ) - { - if ( ataCmd->results.returnCode == kIOReturnSuccess ) - { - ataCmd->results.returnCode = (IOReturn) rc; - } - } - - queue_remove( list, ataCmd, IOATAStandardCommand *, nextCommand ); -} - -IOATAStandardCommand *IOATAStandardDevice::checkCommand( queue_head_t *list ) -{ - if ( queue_empty( list ) == true ) - { - return 0; - } - - return (IOATAStandardCommand *)queue_first( list ); -} - - -IOATAStandardCommand *IOATAStandardDevice::getCommand( queue_head_t *list ) -{ - IOATAStandardCommand *ataCmd = 0; - - if ( queue_empty( list ) == false ) - { - queue_remove_first( list, ataCmd, IOATAStandardCommand *, nextCommand ); - ataCmd->list = 0; - } - - return ataCmd; -} - -void IOATAStandardDevice::stackCommand( queue_head_t *list, IOATAStandardCommand *ataCmd ) -{ - ataCmd->list = list; - - queue_enter_first( list, ataCmd, IOATAStandardCommand *, nextCommand ); -} - -void IOATAStandardDevice::moveCommand( queue_head_t *fromList, queue_head_t *toList, IOATAStandardCommand *ataCmd, IOReturn rc = kIOReturnSuccess ) -{ - if ( rc != kIOReturnSuccess ) - { - if ( ataCmd->results.returnCode == kIOReturnSuccess ) - { - ataCmd->results.returnCode = (IOReturn) rc; - } - } - - ataCmd->list = toList; - - queue_remove( fromList, ataCmd, IOATAStandardCommand *, nextCommand ); - queue_enter( toList, ataCmd, IOATAStandardCommand *, nextCommand ); -} - -void IOATAStandardDevice::moveAllCommands( queue_head_t *fromList, queue_head_t *toList, IOReturn rc = kIOReturnSuccess ) -{ - IOATAStandardCommand *ataCmd; - - if ( queue_empty( fromList ) == true ) return; - - do - { - ataCmd = (IOATAStandardCommand *)queue_first( fromList ); - - if ( rc != kIOReturnSuccess ) - { - if ( ataCmd->results.returnCode == kIOReturnSuccess ) - { - ataCmd->results.returnCode = (IOReturn) rc; - } - } - - ataCmd->list = toList; - - queue_remove( fromList, ataCmd, IOATAStandardCommand *, nextCommand ); - queue_enter( toList, ataCmd, IOATAStandardCommand *, nextCommand ); - - } while( queue_empty( fromList ) == false ); -} - -bool IOATAStandardDevice::findCommand( queue_head_t *list, IOATAStandardCommand *findATACmd ) -{ - IOATAStandardCommand *ataCmd; - - queue_iterate( list, ataCmd, IOATAStandardCommand *, nextCommand ) - { - if ( ataCmd == findATACmd ) - { - return true; - } - } - return false; -} - -void IOATAStandardDevice::purgeAllCommands( queue_head_t *list, IOReturn rc ) -{ - IOATAStandardCommand *ataCmd; - - if ( queue_empty( list ) == true ) return; - - do - { - ataCmd = (IOATAStandardCommand *)queue_first( list ); - - deleteCommand( list, ataCmd, rc ); - finishCommand( ataCmd ); - - } while( queue_empty( list ) == false ); -} diff --git a/iokit/Families/IOATAStandard/IOATAStandardCommand.cpp b/iokit/Families/IOATAStandard/IOATAStandardCommand.cpp deleted file mode 100644 index adaa5e598..000000000 --- a/iokit/Families/IOATAStandard/IOATAStandardCommand.cpp +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * IOATAStandardCommand.cpp - * - */ - -#include - -#include -#include - -#undef super -#define super IOATACommand - -OSDefineMetaClassAndStructors( IOATAStandardCommand, IOATACommand ) -OSDefineMetaClassAndAbstractStructors( IOATACommand, IOCDBCommand ) - -IOATADevice *IOATAStandardCommand::getDevice(IOATADevice *) -{ - return (IOATADevice *)device; -} - -IOATAStandardDevice *IOATAStandardCommand::getDevice(IOATAStandardDevice *) -{ - return device; -} - -void *IOATAStandardCommand::getClientData() -{ - return clientData; -} - -void *IOATAStandardCommand::getCommandData() -{ - return commandPrivateData; -} - -UInt32 IOATAStandardCommand::getCmdType() -{ - return cmdType; -} - -IOATAStandardCommand *IOATAStandardCommand::getOriginalCmd() -{ - return origCommand; -} - -UInt32 IOATAStandardCommand::getSequenceNumber() -{ - return sequenceNumber; -} - -ATAUnit IOATAStandardCommand::getUnit() -{ - return device->unit; -} - -void IOATAStandardCommand::setTaskfile( ATATaskfile *srcTaskfile ) -{ - taskfile = *srcTaskfile; -} - -void IOATAStandardCommand::getTaskfile( ATATaskfile *dstTaskfile ) -{ - *dstTaskfile = taskfile; -} - -UInt32 IOATAStandardCommand::getFlags() -{ - return taskfile.flags; -} - -ATAProtocol IOATAStandardCommand::getProtocol() -{ - return taskfile.protocol; -} - -UInt32 IOATAStandardCommand::getResultMask() -{ - return taskfile.resultmask; -} - - -void IOATAStandardCommand::setTimeout( UInt32 timeoutMS ) -{ - timeout = timeoutMS; -} - -UInt32 IOATAStandardCommand::getTimeout() -{ - return timeout; -} - - -void IOATAStandardCommand::setResults( ATAResults *srcResults ) -{ - results = *srcResults; - - if ( getCmdType() == kATACommandExecute ) - { - if ( results.bytesTransferred < xferCount ) - { - if ( results.returnCode == kIOReturnSuccess ) - { - results.returnCode = kIOReturnUnderrun; - } - } - } -} - -IOReturn IOATAStandardCommand::getResults( ATAResults *dstResults ) -{ - if ( dstResults != 0 ) - { - *dstResults = results; - } - - return results.returnCode; -} - -void IOATAStandardCommand::setQueueInfo( UInt32 forQueueType, UInt32 forQueuePosition ) -{ - queueType = forQueueType; - queuePosition = forQueuePosition; -} - -void IOATAStandardCommand::getQueueInfo( UInt32 *forQueueType, UInt32 *forQueuePosition = 0 ) -{ - if ( forQueueType != 0 ) *forQueueType = queueType; - if ( forQueuePosition != 0 ) *forQueuePosition = queuePosition; -} - -void IOATAStandardCommand::setPointers( IOMemoryDescriptor *clientDesc, UInt32 transferCount, bool isWrite, bool isSense = false ) -{ - if ( isSense == false ) - { - xferDesc = clientDesc; - xferCount = transferCount; - xferDirection = isWrite; - } - else - { - senseData = clientDesc; - senseLength = transferCount; - } -} - -void IOATAStandardCommand::getPointers( IOMemoryDescriptor **clientDesc, UInt32 *transferCount, bool *isWrite, bool isSense = false ) -{ - if ( clientDesc != NULL ) - { - *clientDesc = (isSense == false) ? xferDesc : senseData; - } - - if ( transferCount != NULL ) - { - *transferCount = (isSense == false) ? xferCount : senseLength; - } - - if ( isWrite != NULL ) - { - *isWrite = (isSense == false) ? xferDirection : false; - } -} - -void IOATAStandardCommand::setCDB( ATACDBInfo *clientATACmd ) -{ - ataCmd = *clientATACmd; -} - -void IOATAStandardCommand::getCDB( ATACDBInfo *clientATACmd ) -{ - *clientATACmd = ataCmd; -} - -void IOATAStandardCommand::setCallback( void *clientTarget, CallbackFn clientATADoneFn, void *clientRefcon ) -{ - completionInfo.async.target = clientTarget; - completionInfo.async.callback = clientATADoneFn; - completionInfo.async.refcon = clientRefcon; -} - -bool IOATAStandardCommand::execute( UInt32 *cmdSequenceNumber ) -{ - bool isSync; - - do - { - sequenceNumber = OSIncrementAtomic( (SInt32 *)&controller->sequenceNumber ); - } - while ( sequenceNumber == 0 ); - - if ( cmdSequenceNumber != 0 ) - { - *cmdSequenceNumber = sequenceNumber; - } - - list = (queue_head_t *)device->deviceGate; - - isSync = (completionInfo.async.callback == 0); - - if ( isSync ) - { - completionInfo.sync.lock = IOSyncer::create(); - } - - device->submitCommand( kATACommandExecute, this ); - - if ( isSync ) - { - completionInfo.sync.lock->wait(); - } - - return true; - -} - -void IOATAStandardCommand::abort( UInt32 sequenceNumber ) -{ - device->submitCommand( kATACommandAbort, this, sequenceNumber ); -} - -void IOATAStandardCommand::complete() -{ - if ( device ) - { - device->completeCommand( this ); - } - else - { - controller->completeCommand( this ); - } -} - -/*------------------- Generic CDB Interface -----------------------------------------------*/ - -void IOATAStandardCommand::getCDB( CDBInfo *cdbInfo ) -{ - ATACDBInfo ataCDBInfo; - - bzero( cdbInfo, sizeof(CDBInfo) ); - - getCDB( &ataCDBInfo ); - cdbInfo->cdb = ataCDBInfo.cdb; - cdbInfo->cdbLength = ataCDBInfo.cdbLength; -} - -void IOATAStandardCommand::setCDB( CDBInfo *cdbInfo ) -{ - IOATAStandardDevice *ataDevice; - ATATimingProtocol ataTimingProtocol; - ATACDBInfo ataCDBInfo; - ATATaskfile ataTaskfile; - - ataDevice = getDevice(kIOATAStandardDevice); - - if ( ataDevice->getDeviceType() != kATADeviceATAPI ) - { - return; - } - - bzero( &ataTaskfile, sizeof(ataTaskfile) ); - - ataDevice->getTimingSelected( &ataTimingProtocol ); - - ataTaskfile.regmask = ATARegtoMask(kATARegATAPIDeviceSelect) - | ATARegtoMask(kATARegATAPICommand) - | ATARegtoMask(kATARegATAPIByteCountLow) - | ATARegtoMask(kATARegATAPIByteCountHigh) - | ATARegtoMask(kATARegATAPIFeatures); - - ataTaskfile.ataRegs[kATARegATAPICommand] = kATACommandATAPIPacket; - ataTaskfile.ataRegs[kATARegATAPIDeviceSelect] = kATAModeLBA | (getUnit() << 4); - - if ( ataTimingProtocol & ~kATATimingPIO ) - { - ataTaskfile.protocol = kATAProtocolATAPIDMA; - ataTaskfile.ataRegs[kATARegATAPIFeatures] = 0x01; - } - else - { - ataTaskfile.protocol = kATAProtocolATAPIPIO; - ataTaskfile.ataRegs[kATARegATAPIByteCountLow] = 0xfe; - ataTaskfile.ataRegs[kATARegATAPIByteCountHigh] = 0xff; - } - - setTaskfile( &ataTaskfile ); - - bzero( &ataCDBInfo, sizeof(ATACDBInfo) ); - - ataCDBInfo.cdbLength = cdbInfo->cdbLength; - ataCDBInfo.cdb = cdbInfo->cdb; - setCDB( &ataCDBInfo ); - - setQueueInfo(); -} - -IOReturn IOATAStandardCommand::getResults( CDBResults *cdbResults ) -{ - ATAResults ataResults; - IOReturn rc; - - rc = getResults( &ataResults ); - - if ( cdbResults != 0 ) - { - bzero( cdbResults, sizeof(CDBResults) ); - - cdbResults->returnCode = ataResults.returnCode; - cdbResults->bytesTransferred = ataResults.bytesTransferred; - cdbResults->requestSenseDone = ataResults.returnCode; - cdbResults->requestSenseLength = ataResults.requestSenseLength; - } - - return rc; -} - - -IOCDBDevice *IOATAStandardCommand::getDevice( IOCDBDevice * ) -{ - return (IOCDBDevice *)device; -} diff --git a/iokit/Families/IOATAStandard/IOATAStandardController.cpp b/iokit/Families/IOATAStandard/IOATAStandardController.cpp deleted file mode 100644 index 3374fbbdd..000000000 --- a/iokit/Families/IOATAStandard/IOATAStandardController.cpp +++ /dev/null @@ -1,956 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * IOATAStandardController.cpp - * - */ - -#include -#include - -#undef super -#define super IOService - -OSDefineMetaClass( IOATAStandardController, IOService ) -OSDefineAbstractStructors( IOATAStandardController, IOService ); - -#define round(x,y) (((int)(x) + (y) - 1) & ~((y)-1)) - -/* - * - * - */ -bool IOATAStandardController::start( IOService *forProvider ) -{ - provider = forProvider; - -// IOSleep( 15000 ); - - if ( provider->open( this ) != true ) - { - return false; - } - - if ( createWorkLoop() != true ) - { - return false; - } - - if ( configureController() != true ) - { - provider->close( this ); - return false; - } - - if ( scanATABus() != true ) - { - provider->close( this ); - return false; - } - - return true; -} - -/* - * - * - * - */ -bool IOATAStandardController::scanATABus() -{ - if ( createDeviceNubs() != true ) - { - return false; - } - - timer( timerEvent ); - - if ( initTimings() == false ) - { - return false; - } - - disableControllerInterrupts(); - - if ( reset() != kIOReturnSuccess ) - { - return false; - } - - enableControllerInterrupts(); - - if ( probeDeviceNubs() != true ) - { - return false; - } - - if ( registerDeviceNubs() != true ) - { - return false; - } - - return true; -} - - -/* - * - * - * - */ -bool IOATAStandardController::createDeviceNubs() -{ - UInt32 i; - IOATAStandardDevice *ataDev; - - for (i = 0; i < controllerInfo.maxDevicesSupported; i++ ) - { - ataDev = targets[i].device = new IOATAStandardDevice; - - if ( ataDev->init( this, i ) != true ) - { - ataDev->release(); - targets[i].device = NULL; - } - } - - resetCmd = allocCommand( 0 ); - resetCmd->cmdType = kATACommandBusReset; - resetCmd->setTimeout( kATAResetTimeoutmS ); - resetCmd->setPointers( 0, 0, false ); - - return true; -} - -/* - * - * - * - */ -bool IOATAStandardController::probeDeviceNubs() -{ - UInt32 i; - IOATAStandardDevice *ataDev; - - for (i = 0; i < controllerInfo.maxDevicesSupported; i++ ) - { - ataDev = targets[i].device; - if ( ataDev->probeDeviceType() == kATADeviceNone ) - { - ataDev->release(); - targets[i].device = NULL; - } - } - - for (i = 0; i < controllerInfo.maxDevicesSupported; i++ ) - { - ataDev = targets[i].device; - if ( ataDev == NULL ) - { - continue; - } - - if ( ataDev->probeDevice() != true ) - { - ataDev->release(); - targets[i].device = NULL; - } - } - - return true; -} - - -/* - * - * - * - */ -bool IOATAStandardController::registerDeviceNubs() -{ - UInt32 i; - IOATAStandardDevice *ataDev; - - for (i = 0; i < controllerInfo.maxDevicesSupported; i++ ) - { - ataDev = targets[i].device; - if ( ataDev != NULL ) - { - ataDev->attach( this ); - ataDev->registerService(); - } - } - - return true; -} - -/* - * - * - * - */ -bool IOATAStandardController::initTimings() -{ - ATATiming initPIOTiming; - - initPIOTiming.timingProtocol = kATATimingPIO; - initPIOTiming.featureSetting = 0; - initPIOTiming.mode = 0; - initPIOTiming.minDataAccess = 165; - initPIOTiming.minDataCycle = 600; - initPIOTiming.minCmdAccess = 290; - initPIOTiming.minCmdCycle = 600; - - if ( calculateTiming( 0, &initPIOTiming ) != true ) - { - return false; - } - - if ( calculateTiming( 1, &initPIOTiming ) != true ) - { - return false; - } - - return true; -} - -/* - * - * - * - */ -bool IOATAStandardController::matchNubWithPropertyTable( IOService *nub, OSDictionary *table ) -{ - bool rc; - - rc = nub->compareProperty( table, kATAPropertyLocation ); - - return rc; -} - - - -/* - * - * - * - */ -void IOATAStandardController::releaseDevice( IOATAStandardDevice *device ) -{ - workLoopRequest( kWorkLoopReleaseDevice, (UInt32) device ); - - device->release(); -} - -/* - * - * - * - */ -bool IOATAStandardController::workLoopRequest( WorkLoopReqType type, UInt32 p1, UInt32 p2, UInt32 p3 ) -{ - WorkLoopRequest workLoopReq; - - bzero( &workLoopReq, sizeof(WorkLoopRequest) ); - workLoopReq.type = type; - workLoopReq.sync = IOSyncer::create(); - - workLoopReqGate->runCommand( &workLoopReq, (void *)p1, (void *)p2, (void *)p3 ); - - workLoopReq.sync->wait(); - - return( workLoopReq.rc ); -} - - -/* - * - * - * - */ -void IOATAStandardController::workLoopProcessRequest( WorkLoopRequest *workLoopReq, void *p1, void *p2, void *p3 ) -{ - bool rc = true; - IOATAStandardDevice *device; - - switch ( workLoopReq->type ) - { - - case kWorkLoopInitDevice: - device = (IOATAStandardDevice *) p1; - addDevice( device ); - rc = allocateDevice( device->unit ); - break; - - case kWorkLoopReleaseDevice: - device = (IOATAStandardDevice *) p1; - deleteDevice( device ); - break; - } - - workLoopReq->rc = rc; - workLoopReq->sync->signal(); -} - -/* - * - * - * - */ -void IOATAStandardController::addDevice( IOATAStandardDevice *forDevice ) -{ - ATAUnit unit; - - unit = forDevice->unit; - - forDevice->target = &targets[unit]; - targets[unit].device = forDevice; -} - -/* - * - * - * - */ -void IOATAStandardController::deleteDevice( IOATAStandardDevice *forDevice ) -{ - ATAUnit unit; - - unit = forDevice->unit; - targets[unit].device = 0; -} - - -/* - * - * - * - */ -bool IOATAStandardController::allocateDevice( ATAUnit unit ) -{ - return true; -} - -/* - * - * - * - */ -void IOATAStandardController::deallocateDevice( ATAUnit unit ) -{ -} - - -/* - * - * - * - */ -void *IOATAStandardController::getDeviceData( ATAUnit unit ) -{ - IOATAStandardDevice *device; - - device = targets[unit].device; - - if ( device == 0 ) return 0; - - return device->devicePrivateData; -} - - -/* - * - * - * - */ -IOReturn IOATAStandardController::reset() -{ - if ( busResetState != kStateIdle ) - { - return kIOReturnNoResources; - } - - busResetState = kStateIssue; - dispatchRequest(); - - while ( busResetState != kStateIdle ) - { - IOSleep( 100 ); - } - - return resetCmd->getResults( (ATAResults *)0 ); -} - -/* - * - * - * - */ -void IOATAStandardController::resetATABus() -{ - if ( busResetState != kStateIssue ) - { - return; - } - - busResetState = kStateActive; - - resetStarted(); - - resetCommand( resetCmd ); -} - -/* - * - * - * - */ -void IOATAStandardController::resetStarted() -{ - IOATAStandardDevice *device; - UInt32 i; - - for (i=0; i < controllerInfo.maxDevicesSupported; i++ ) - { - device = targets[i].device; - - if ( (device != 0) && (device->client != 0) && (device->abortCmdPending != kATACommandDeviceReset) ) - { - device->client->message( kATAClientMsgBusReset, device ); - } - } -} - - -/* - * - * - * - */ -bool IOATAStandardController::checkBusReset() -{ - if ( busResetState == kStateIdle ) - { - return false; - } - if ( busResetState == kStateIssue ) - { - resetATABus(); - } - return true; -} - - -/* - * - * - */ -void IOATAStandardController::timer( IOTimerEventSource * /* timer */ ) -{ - UInt32 i; - IOATAStandardDevice *device; - - - if ( disableTimer ) - { - if ( !--disableTimer ) - { - disableTimeoutOccurred(); - } - } - - for (i=0; i < controllerInfo.maxDevicesSupported; i++ ) - { - device = targets[i].device; - if ( device != 0 ) - { - device->timer(); - } - } - - timerEvent->setTimeoutMS(kATATimerIntervalmS); -} - - -/* - * - * - * - */ -void IOATAStandardController::completeCommand( IOATAStandardCommand *ataCmd ) -{ - switch ( ataCmd->cmdType ) - { - case kATACommandBusReset: - busResetState = kStateIdle; - resetOccurred(); - break; - default: - ; - } -} - -/* - * - * - * - */ -void IOATAStandardController::resetOccurred() -{ - UInt32 i; - IOATAStandardDevice *device; - - for (i=0; i < controllerInfo.maxDevicesSupported; i++ ) - { - device = targets[i].device; - - if ( device == 0 ) continue; - - if ( device->abortCmdPending != kATACommandDeviceReset ) - { - device->resetOccurred( (ATAClientMessage) (kATAClientMsgBusReset | kATAClientMsgDone) ); - } - } -} - -/* - * - * - * - */ -bool IOATAStandardController::createWorkLoop() -{ - workLoop = getWorkLoop(); - if ( workLoop == 0 ) - { - workLoop = new IOWorkLoop; - if ( workLoop == 0 ) - { - return false; - } - } - - if ( workLoop->init() != true ) - { - return false; - } - - timerEvent = IOTimerEventSource::timerEventSource( this, (IOTimerEventSource::Action) &IOATAStandardController::timer ); - if ( timerEvent == NULL ) - { - return false; - } - - if ( workLoop->addEventSource( timerEvent ) != kIOReturnSuccess ) - { - return false; - } - - timer( timerEvent ); - - - dispatchEvent = IOInterruptEventSource::interruptEventSource( this, - (IOInterruptEventAction) &IOATAStandardController::dispatch, - 0 ); - if ( dispatchEvent == 0 ) - { - return false; - } - - if ( workLoop->addEventSource( dispatchEvent ) != kIOReturnSuccess ) - { - return false; - } - - workLoopReqGate = IOCommandGate::commandGate( this, (IOCommandGate::Action) &IOATAStandardController::workLoopProcessRequest ); - if ( workLoopReqGate == NULL ) - { - return false; - } - - if ( workLoop->addEventSource( workLoopReqGate ) != kIOReturnSuccess ) - { - return false; - } - - - return true; -} - -/* - * - * - * - */ -IOATAStandardCommand *IOATAStandardController::findCommandWithNexus( IOATAStandardDevice *device, UInt32 tagValue = (UInt32)-1 ) -{ - return ((IOATAStandardDevice *)device)->findCommandWithNexus( tagValue ); -} - -/* - * - * - * - */ -bool IOATAStandardController::configureController() -{ - UInt32 targetsSize; - - if ( configure( provider, &controllerInfo ) == false ) - { - return false; - } - - controllerInfo.commandPrivateDataSize = round( controllerInfo.commandPrivateDataSize, 16 ); - - targetsSize = controllerInfo.maxDevicesSupported * sizeof(ATATarget); - targets = (ATATarget *)IOMalloc( targetsSize ); - bzero( targets, targetsSize ); - - commandLimit = commandLimitSave = (UInt32)-1; - - return true; -} - -/* - * - * - * - */ -void IOATAStandardController::setCommandLimit( IOATAStandardDevice *device, UInt32 newCommandLimit ) -{ - ((IOATAStandardDevice *)device)->commandLimit = newCommandLimit; -} - - -/* - * - * - * - */ -void IOATAStandardController::disableControllerInterrupts() -{ - workLoop->disableAllInterrupts(); -} - -/* - * - * - * - */ -void IOATAStandardController::enableControllerInterrupts() -{ - workLoop->enableAllInterrupts(); -} - - -/* - * - * - * - */ -IOWorkLoop *IOATAStandardController::getWorkLoop() const -{ - return workLoop; -} - -/* - * - * - * - */ -void IOATAStandardController::disableCommands( UInt32 disableTimeoutmS ) -{ - commandDisable = true; - - disableTimer = ( disableTimeoutmS != 0 ) ? (disableTimeoutmS / kATATimerIntervalmS + 1) : 0; -} - - -/* - * - * - * - */ -void IOATAStandardController::disableCommands() -{ - UInt32 disableTimeout; - - commandDisable = true; - - disableTimeout = kATADisableTimeoutmS; - - if ( noDisconnectCmd != 0 ) - { - disableTimeout = noDisconnectCmd->getTimeout(); - if ( disableTimeout != 0 ) disableTimeout += kATADisableTimeoutmS; - } - - disableTimer = ( disableTimeout != 0 ) ? (disableTimeout / kATATimerIntervalmS + 1) : 0; -} - -/* - * - * - * - */ -void IOATAStandardController::disableTimeoutOccurred() -{ - busResetState = kStateIssue; - dispatchRequest(); -} - - -/* - * - * - * - */ -UInt32 IOATAStandardController::getCommandCount() -{ - return commandCount; -} - -/* - * - * - * - */ -void IOATAStandardController::suspendDevice( IOATAStandardDevice *device ) -{ - ((IOATAStandardDevice *)device)->suspend(); -} - -/* - * - * - * - */ -void IOATAStandardController::resumeDevice( IOATAStandardDevice *device ) -{ - ((IOATAStandardDevice *)device)->resume(); -} - -/* - * - * - * - */ -IOATAStandardDevice *IOATAStandardController::selectDevice() -{ - IOATAStandardDevice *ataDev; - IOATAStandardDevice *selectedDevice = 0; - AbsoluteTime maxSuspendTime; - UInt32 i; - - AbsoluteTime_to_scalar(&maxSuspendTime) = 0; - - for (i = 0; i < controllerInfo.maxDevicesSupported; i++ ) - { - ataDev = targets[i].device; - if ( ataDev != NULL ) - { - if ( ataDev->isSuspended == true ) - { - if ( CMP_ABSOLUTETIME(&ataDev->suspendTime, &maxSuspendTime) > 0 ) - { - selectedDevice = ataDev; - AbsoluteTime_to_scalar( &maxSuspendTime ) = AbsoluteTime_to_scalar( &ataDev->suspendTime ); - } - } - } - } - - return (IOATAStandardDevice *) selectedDevice; -} - - -/* - * - * - * - */ -void IOATAStandardController::rescheduleCommand( IOATAStandardCommand *forATACmd ) -{ - forATACmd->getDevice(kIOATAStandardDevice)->rescheduleCommand( forATACmd ); -} - -/* - * - * - * - */ -void IOATAStandardController::enableCommands() -{ - commandDisable = false; - - disableTimer = 0; - - dispatchRequest(); -} - -/* - * - * - * - */ -void IOATAStandardController::dispatchRequest() -{ - dispatchEvent->interruptOccurred(0, 0, 0); -} - - -/* - * - * - * - */ -void IOATAStandardController::dispatch() -{ - ATATarget *target; - IOATAStandardDevice *device; - UInt32 dispatchAction; - UInt32 i; - - if ( checkBusReset() == true ) - { - goto dispatch_Exit; - } - - for ( i = 0; i < controllerInfo.maxDevicesSupported; i++ ) - { - target = &targets[i]; - - device = target->device; - if ( device == 0 ) continue; - - if ( target->state == kStateActive ) - { - if ( device->dispatch( &dispatchAction ) == false ) - { - target->state = kStateIdle; - } - - switch ( dispatchAction ) - { - case kDispatchNextDevice: - break; - case kDispatchStop: - goto dispatch_Exit; - } - } - } - -dispatch_Exit: - ; -} - -/* - * - * - * - */ -IOATAStandardCommand *IOATAStandardController::allocCommand(UInt32 clientDataSize ) -{ - IOATAStandardCommand *cmd; - UInt32 size; - - size = controllerInfo.commandPrivateDataSize + round(clientDataSize, 16); - - cmd = new IOATAStandardCommand; - if ( !cmd ) - { - return 0; - } - cmd->init(); - - if ( size ) - { - cmd->dataArea = (void *)IOMallocContiguous( (vm_size_t)size, 16, 0 ); - if ( !cmd->dataArea ) - { - cmd->release(); - return 0; - } - - bzero( cmd->dataArea, size ); - - cmd->dataSize = size; - - if ( controllerInfo.commandPrivateDataSize ) - { - cmd->commandPrivateData = cmd->dataArea; - } - if ( clientDataSize ) - { - cmd->clientData = (void *)((UInt8 *)cmd->dataArea + controllerInfo.commandPrivateDataSize); - } - } - - cmd->controller = this; - - return cmd; -} - -/* - * - * - * - */ -void IOATAStandardController::free() -{ - UInt32 targetsSize; - - if ( timerEvent != 0 ) timerEvent->release(); - - if ( workLoopReqGate != 0 ) workLoopReqGate->release(); - - if ( dispatchEvent != 0 ) dispatchEvent->release(); - - if ( resetCmd != 0 ) resetCmd->release(); - - if ( workLoop != 0 ) workLoop->release(); - - if ( targets != 0 ) - { - targetsSize = controllerInfo.maxDevicesSupported * sizeof(ATATarget); - IOFree( targets, targetsSize ); - } - - super::free(); -} - -/* - * - * - * - */ -void IOATAStandardCommand::free() -{ - if ( dataArea ) - { - IOFreeContiguous( dataArea, dataSize ); - } - - OSObject::free(); -} - diff --git a/iokit/Families/IOATAStandard/IOATAStandardData.cpp b/iokit/Families/IOATAStandard/IOATAStandardData.cpp deleted file mode 100644 index 7a9074b5e..000000000 --- a/iokit/Families/IOATAStandard/IOATAStandardData.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * IOATAData.cpp - * - */ - -#include -#include - -static void *x; -#define id ((ATAIdentify *)x) - -EndianTable AppleIdentifyEndianTable[] = -{ - { sizeof(id->generalConfiguration), sizeof(UInt16) }, - { sizeof(id->logicalCylinders), sizeof(UInt16) }, - { sizeof(id->reserved_1), sizeof(UInt16) }, - { sizeof(id->logicalHeads), sizeof(UInt16) }, - { sizeof(id->reserved_2), sizeof(UInt16) }, - { sizeof(id->logicalSectorsPerTrack), sizeof(UInt16) }, - { sizeof(id->reserved_3), sizeof(UInt16) }, - { sizeof(id->serialNumber), sizeof(UInt8) }, - { sizeof(id->reserved_4), sizeof(UInt16) }, - { sizeof(id->firmwareRevision), sizeof(UInt8) }, - { sizeof(id->modelNumber), sizeof(UInt8) }, - { sizeof(id->multipleModeSectors), sizeof(UInt16) }, - { sizeof(id->reserved_5), sizeof(UInt16) }, - { sizeof(id->capabilities1), sizeof(UInt16) }, - { sizeof(id->capabilities2), sizeof(UInt16) }, - { sizeof(id->pioMode), sizeof(UInt16) }, - { sizeof(id->reserved_6), sizeof(UInt16) }, - { sizeof(id->validFields), sizeof(UInt16) }, - { sizeof(id->currentLogicalCylinders), sizeof(UInt16) }, - { sizeof(id->currentLogicalHeads), sizeof(UInt16) }, - { sizeof(id->currentLogicalSectorsPerTrack), sizeof(UInt16) }, - { sizeof(id->currentAddressableSectors), sizeof(UInt32) }, - { sizeof(id->currentMultipleModeSectors), sizeof(UInt16) }, - { sizeof(id->userAddressableSectors), sizeof(UInt32) }, - { sizeof(id->reserved_7), sizeof(UInt16) }, - { sizeof(id->dmaModes), sizeof(UInt16) }, - { sizeof(id->advancedPIOModes), sizeof(UInt16) }, - { sizeof(id->minDMACycleTime), sizeof(UInt16) }, - { sizeof(id->recDMACycleTime), sizeof(UInt16) }, - { sizeof(id->minPIOCycleTimeNoIORDY), sizeof(UInt16) }, - { sizeof(id->minPIOCyclcTimeIORDY), sizeof(UInt16) }, - { sizeof(id->reserved_8), sizeof(UInt16) }, - { sizeof(id->busReleaseLatency), sizeof(UInt16) }, - { sizeof(id->serviceLatency), sizeof(UInt16) }, - { sizeof(id->reserved_9), sizeof(UInt16) }, - { sizeof(id->queueDepth), sizeof(UInt16) }, - { sizeof(id->reserved_10), sizeof(UInt16) }, - { sizeof(id->versionMajor), sizeof(UInt16) }, - { sizeof(id->versionMinor), sizeof(UInt16) }, - { sizeof(id->commandSetsSupported1), sizeof(UInt16) }, - { sizeof(id->commandSetsSupported2), sizeof(UInt16) }, - { sizeof(id->commandSetsSupported3), sizeof(UInt16) }, - { sizeof(id->commandSetsEnabled1), sizeof(UInt16) }, - { sizeof(id->commandSetsEnabled2), sizeof(UInt16) }, - { sizeof(id-> commandSetsDefault), sizeof(UInt16) }, - { sizeof(id->ultraDMAModes), sizeof(UInt16) }, - { sizeof(id->securityEraseTime), sizeof(UInt16) }, - { sizeof(id-> securityEnhancedEraseTime), sizeof(UInt16) }, - { sizeof(id-> currentAdvPowerMgtValue), sizeof(UInt16) }, - { sizeof(id->reserved_11), sizeof(UInt16) }, - { sizeof(id->removableMediaSupported), sizeof(UInt16) }, - { sizeof(id->securityStatus), sizeof(UInt16) }, - { sizeof(id->reserved_12), sizeof(UInt16) }, - { 0, 0 } -}; - -ATAModeTable ApplePIOModes[] = -{ - { 165, 600 }, /* Mode 0 */ - { 125, 383 }, /* 1 */ - { 100, 240 }, /* 2 */ - { 80, 180 }, /* 3 */ - { 70, 120 } /* 4 */ -}; -UInt32 AppleNumPIOModes = (sizeof(ApplePIOModes)/sizeof(ATAModeTable)); - -ATAModeTable AppleDMAModes[] = -{ - { 215, 480 }, /* Mode 0 */ - { 80, 150 }, /* 1 */ - { 70, 120 } /* 2 */ -}; -UInt32 AppleNumDMAModes = (sizeof(AppleDMAModes)/sizeof(ATAModeTable)); - -ATAModeTable AppleUltraModes[] = -{ - { 0, 114 }, /* Mode 0 */ - { 0, 75 }, /* 1 */ - { 0, 55 }, /* 2 */ - { 100, 45 }, /* 3 */ - { 100, 25 } /* 4 */ -}; -UInt32 AppleNumUltraModes = (sizeof(AppleUltraModes)/sizeof(ATAModeTable)); - diff --git a/iokit/Families/IOATAStandard/IOATAStandardDevice.cpp b/iokit/Families/IOATAStandard/IOATAStandardDevice.cpp deleted file mode 100644 index 2d3b5c0be..000000000 --- a/iokit/Families/IOATAStandard/IOATAStandardDevice.cpp +++ /dev/null @@ -1,2370 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * IOATAStandardDevice.cpp - * - */ - -#include -#include -#include - -#undef super -#define super IOATADevice - -#ifndef MIN -#define MIN(a,b) ((a <= b) ? a : b) -#endif - -#define round(x,y) (((int)(x) + (y) - 1) & ~((y)-1)) - -extern EndianTable AppleIdentifyEndianTable[]; - -extern UInt32 AppleNumPIOModes; -extern ATAModeTable ApplePIOModes[]; -extern UInt32 AppleNumDMAModes; -extern ATAModeTable AppleDMAModes[]; -extern UInt32 AppleNumUltraModes; -extern ATAModeTable AppleUltraModes[]; - -OSDefineMetaClassAndAbstractStructors( IOATADevice, IOCDBDevice ) -OSDefineMetaClassAndStructors( IOATAStandardDevice, IOATADevice ) - -/* - * - * - * - */ -bool IOATAStandardDevice::init( IOATAStandardController *forController, ATAUnit forUnit ) -{ - ATATaskfile taskfile; - ATACDBInfo ataCDB; - - controller = forController; - unit = forUnit; - - target = &controller->targets[unit]; - - queue_init( &deviceList ); - queue_init( &bypassList ); - queue_init( &activeList ); - queue_init( &abortList ); - queue_init( &cancelList ); - - clientSem = IORWLockAlloc(); - if ( clientSem == 0 ) - { - return false; - } - - if ( super::init() == false ) - { - return false; - } - - if ( controller->controllerInfo.devicePrivateDataSize != 0 ) - { - devicePrivateData = IOMallocContiguous( controller->controllerInfo.devicePrivateDataSize, 16, 0 ); - if ( devicePrivateData == 0 ) - { - return false; - } - } - - bzero( &ataCDB, sizeof(ataCDB) ); - - probeCmd = allocCommand(kIOATAStandardDevice, 0); - if ( probeCmd == 0 ) - { - return false; - } - - abortCmd = allocCommand(kIOATAStandardDevice, 0); - if ( abortCmd == 0 ) - { - return false; - } - abortCmd->setTimeout( kATAAbortTimeoutmS ); - - cancelCmd = allocCommand(kIOATAStandardDevice, 0); - if ( cancelCmd == 0 ) - { - return false; - } - cancelCmd->setTimeout( 0 ); - cancelCmd->cmdType = kATACommandCancel; - - reqSenseCmd = allocCommand(kIOATAStandardDevice, 0); - if ( reqSenseCmd == 0 ) - { - return false; - } - - bzero( &taskfile, sizeof(taskfile) ); - taskfile.protocol = kATAProtocolATAPIPIO; - taskfile.tagType = kATATagTypeNone; - - taskfile.resultmask = ATARegtoMask( kATARegStatus ); - - taskfile.regmask = ATARegtoMask( kATARegATAPIFeatures ) - | ATARegtoMask( kATARegATAPIByteCountLow ) - | ATARegtoMask( kATARegATAPIByteCountHigh ) - | ATARegtoMask( kATARegATAPIDeviceSelect ) - | ATARegtoMask( kATARegATAPICommand ); - - taskfile.ataRegs[kATARegATAPIFeatures] = 0; - taskfile.ataRegs[kATARegATAPIByteCountLow] = 0xfe; - taskfile.ataRegs[kATARegATAPIByteCountHigh] = 0xff; - taskfile.ataRegs[kATARegATAPIDeviceSelect] = kATAModeLBA | (getUnit() << 4); - taskfile.ataRegs[kATARegATAPICommand] = kATACommandATAPIPacket; - - reqSenseCmd->setTaskfile( &taskfile ); - - ataCDB.cdbLength = 12; - ataCDB.cdb[0] = kATAPICmdRequestSense; - - reqSenseCmd->setTimeout( kATAReqSenseTimeoutmS ); - reqSenseCmd->cmdType = kATACommandReqSense; - reqSenseCmd->setCDB( &ataCDB ); - - deviceGate = IOCommandGate::commandGate( this, (IOCommandGate::Action) &IOATAStandardDevice::receiveCommand ); - if ( deviceGate == 0 ) - { - return false; - } - - if ( controller->workLoop->addEventSource( deviceGate ) != kIOReturnSuccess ) - { - return false; - } - - commandLimitSave = commandLimit = 1; - - idleNotifyActive = false; - - normalQHeld = 0; - bypassQHeld = 0; - - currentTiming = kATATimingPIO; - - return true; -} - -IOReturn IOATAStandardDevice::probeDevice() -{ - OSDictionary *propTable = 0; - - if ( doIdentify( (void **)&identifyData ) != kIOReturnSuccess ) - { - goto probeDevice_error; - } - - if ( deviceType == kATADeviceATA ) - { - doSpinUp(); - } - - else if ( deviceType == kATADeviceATAPI ) - { - atapiPktInt = ((identifyData->generalConfiguration & kATAPIPktProtocolIntDRQ) != 0); - - if ( doInquiry( (void **)&inquiryData ) != kIOReturnSuccess ) - { - goto probeDevice_error; - } - } - - if ( getATATimings() != true ) - { - goto probeDevice_error; - } - - if ( maxTags != 0 ) - { - tagArraySize = round( maxTags, 32 ) / 8; - tagArray = (UInt32 *)IOMalloc( tagArraySize ); - if ( tagArray == 0 ) - { - goto probeDevice_error; - } - bzero( tagArray, tagArraySize ); - } - - propTable = createProperties(); - if ( !propTable ) - { - goto probeDevice_error; - } - - setPropertyTable( propTable ); - - propTable->release(); - - close( this, 0 ); - - return true; - -probeDevice_error: ; - close( this, 0 ); - return false; -} - -/* - * - * - * - */ -ATADeviceType IOATAStandardDevice::probeDeviceType() -{ - ATATaskfile taskfile; - ATAResults results; - - bzero( (void *)&taskfile, sizeof(taskfile) ); - - taskfile.protocol = kATAProtocolSetRegs; - taskfile.regmask = ATARegtoMask(kATARegDriveHead); - - taskfile.resultmask = ATARegtoMask(kATARegSectorCount) - | ATARegtoMask(kATARegSectorNumber) - | ATARegtoMask(kATARegCylinderLow) - | ATARegtoMask(kATARegCylinderHigh) - | ATARegtoMask(kATARegStatus); - - taskfile.flags = kATACmdFlagTimingChanged; - - taskfile.ataRegs[kATARegDriveHead] = kATAModeLBA | (getUnit() << 4); - - probeCmd->setQueueInfo(); - probeCmd->setTaskfile( &taskfile ); - probeCmd->execute(); - - if ( probeCmd->getResults( &results ) != kIOReturnSuccess ) - { - return (deviceType = kATADeviceNone); - } - - if ( results.ataRegs[kATARegSectorCount] == kATASignatureSectorCount - && results.ataRegs[kATARegSectorNumber] == kATASignatureSectorNumber - && results.ataRegs[kATARegCylinderLow] == kATASignatureCylinderLow - && results.ataRegs[kATARegCylinderHigh] == kATASignatureCylinderHigh ) - { - if ( !(results.ataRegs[kATARegStatus] & kATAStatusBSY) - && (results.ataRegs[kATARegStatus] & kATAStatusDRDY) ) - { - return (deviceType = kATADeviceATA); - } - } - - if ( results.ataRegs[kATARegCylinderLow] == kATAPISignatureCylinderLow - && results.ataRegs[kATARegCylinderHigh] == kATAPISignatureCylinderHigh ) - { - return (deviceType = kATADeviceATAPI); - } - - return (deviceType = kATADeviceNone); -} - - -/* - * - * - * - */ -IOReturn IOATAStandardDevice::doSpinUp() -{ - void *buffer = NULL; - IOReturn rc; - - rc = doSectorCommand( kATACommandReadSector, 0, 1, &buffer ); - - if ( rc != kIOReturnSuccess ) - { - return rc; - } - - IOFree( buffer, 512 ); - - return rc ; -} - -/* - * - * - * - */ -IOReturn IOATAStandardDevice::doIdentify( void **dataPtr ) -{ - ATACommand ataCmd; - IOReturn rc; - - ataCmd = (deviceType == kATADeviceATA) ? kATACommandIdentify : kATACommandATAPIIdentify; - - rc = doSectorCommand( ataCmd, 0, 1, dataPtr ); - - if ( rc != kIOReturnSuccess ) - { - return rc; - } - - endianConvertData( *dataPtr, AppleIdentifyEndianTable ); - - return rc; -} - - - -/* - * - * - * - */ -IOReturn IOATAStandardDevice::doSectorCommand( ATACommand ataCmd, UInt32 ataLBA, UInt32 ataCount, void **dataPtr ) -{ - ATATaskfile taskfile; - ATAResults result; - IOMemoryDescriptor *desc; - UInt32 size; - void *data; - UInt32 i; - IOReturn rc; - - *dataPtr = NULL; - - size = ataCount * 512; - - if ( !(data = (void *)IOMalloc(size)) ) - { - return kIOReturnNoMemory; - } - - bzero( &taskfile, sizeof(taskfile) ); - - desc = IOMemoryDescriptor::withAddress( data, size, kIODirectionIn ); - if ( desc == NULL ) - { - rc = kIOReturnNoMemory; - goto doSectorCommand_error; - } - - - taskfile.protocol = kATAProtocolPIO; - taskfile.regmask = ATARegtoMask(kATARegDriveHead) - | ATARegtoMask(kATARegSectorCount) - | ATARegtoMask(kATARegSectorNumber) - | ATARegtoMask(kATARegCylinderLow) - | ATARegtoMask(kATARegCylinderHigh) - | ATARegtoMask(kATARegFeatures) - | ATARegtoMask(kATARegCommand); - - - taskfile.resultmask = ATARegtoMask(kATARegError) - | ATARegtoMask(kATARegStatus); - - taskfile.ataRegs[kATARegSectorCount] = ataCount; - taskfile.ataRegs[kATARegSectorNumber] = ataLBA & 0xff; - taskfile.ataRegs[kATARegCylinderLow] = (ataLBA >> 8) & 0xff; - taskfile.ataRegs[kATARegCylinderHigh] = (ataLBA >> 16) & 0xff; - taskfile.ataRegs[kATARegDriveHead] = (ataLBA >> 24) & 0x0f; - - taskfile.ataRegs[kATARegDriveHead] |= kATAModeLBA | (getUnit() << 4); - taskfile.ataRegs[kATARegCommand] = ataCmd; - - probeCmd->setQueueInfo(); - - for ( i = 0; i < 2; i++ ) - { - probeCmd->setTimeout( 25000 ); - probeCmd->setTaskfile( &taskfile ); - probeCmd->setPointers( desc, size, false ); - probeCmd->execute(); - - rc = probeCmd->getResults( &result ); - if ( rc == kIOReturnSuccess ) - { - break; - } - } - - -doSectorCommand_error: ; - - desc->release(); - - if ( rc != kIOReturnSuccess ) - { - IOFree( data, size ); - return result.returnCode; - } - - *dataPtr = data; - - return kIOReturnSuccess; -} - - -/* - * - * - */ -IOReturn IOATAStandardDevice::doInquiry( void **dataPtr ) -{ - ATATaskfile taskfile; - ATACDBInfo atapiCmd; - ATAResults result; - void *data; - IOMemoryDescriptor *desc; - UInt32 size = sizeof(ATAPIInquiry); - - *dataPtr = 0; - - if ( !(data = (void *)IOMalloc(size)) ) - { - return kIOReturnNoMemory; - } - - bzero( data, size ); - bzero( &taskfile, sizeof(taskfile) ); - bzero( &atapiCmd, sizeof(atapiCmd) ); - - desc = IOMemoryDescriptor::withAddress( data, size, kIODirectionIn ); - - taskfile.protocol = kATAProtocolATAPIPIO; - taskfile.regmask = ATARegtoMask(kATARegATAPIDeviceSelect) - | ATARegtoMask(kATARegATAPICommand) - | ATARegtoMask(kATARegATAPIByteCountLow) - | ATARegtoMask(kATARegATAPIByteCountHigh) - | ATARegtoMask(kATARegATAPIFeatures); - taskfile.ataRegs[kATARegATAPIDeviceSelect] = kATAModeLBA | (getUnit() << 4); - taskfile.ataRegs[kATARegATAPICommand] = kATACommandATAPIPacket; - taskfile.ataRegs[kATARegATAPIFeatures] = 0; - taskfile.ataRegs[kATARegATAPIByteCountLow] = 0xfe; - taskfile.ataRegs[kATARegATAPIByteCountHigh] = 0xff; - - atapiCmd.cdbLength = 12; // Fix 16 byte cmdpkts?? - atapiCmd.cdb[0] = 0x12; - atapiCmd.cdb[4] = size; - - probeCmd->setCDB( &atapiCmd ); - probeCmd->setTaskfile( &taskfile ); - probeCmd->setPointers( desc, size, false ); - probeCmd->setTimeout( 5000 ); - probeCmd->setQueueInfo(); - probeCmd->execute(); - - if ( probeCmd->getResults(&result) == kIOReturnSuccess ) - { - *dataPtr = data; - } - else if ( ( result.returnCode == kIOReturnUnderrun ) && - ( result.bytesTransferred >= 36 ) ) - { - // The standard INQUIRY contain 36 required bytes, - // the rest is optional and vendor specific. - - result.returnCode = kIOReturnSuccess; - *dataPtr = data; - } - else - { - IOFree( data, size ); - } - - desc->release(); - - return result.returnCode; -} - -/* - * - * - */ -bool IOATAStandardDevice::getDeviceCapacity( UInt32 *blockMax, UInt32 *blockSize ) -{ - UInt32 i; - UInt32 data[2]; - - if ( deviceType == kATADeviceATA ) - { - if ( identifyData != NULL ) - { - *blockMax = *(UInt32 *)identifyData->userAddressableSectors - 1; - *blockSize = 512; - return true; - } - } - - if ( deviceType == kATADeviceATAPI ) - { - for ( i=0; i < 8; i++ ) - { - if ( doTestUnitReady() == kIOReturnSuccess ) - { - break; - } - } - - if ( doReadCapacity( data ) == kIOReturnSuccess ) - { - *blockMax = OSSwapBigToHostInt32( data[0] ); - *blockSize = OSSwapBigToHostInt32( data[1] ); - return true; - } - } - - return false; -} - - -IOReturn IOATAStandardDevice::doTestUnitReady() -{ - ATATaskfile taskfile; - ATACDBInfo atapiCmd; - ATAResults result; - - bzero( &taskfile, sizeof(taskfile) ); - bzero( &atapiCmd, sizeof(atapiCmd) ); - - taskfile.protocol = kATAProtocolATAPIPIO; - - taskfile.regmask = ATARegtoMask(kATARegATAPIDeviceSelect) - | ATARegtoMask(kATARegATAPICommand) - | ATARegtoMask(kATARegATAPIByteCountLow) - | ATARegtoMask(kATARegATAPIByteCountHigh) - | ATARegtoMask(kATARegATAPIFeatures); - - taskfile.ataRegs[kATARegATAPIDeviceSelect] = kATAModeLBA | (getUnit() << 4); - taskfile.ataRegs[kATARegATAPICommand] = kATACommandATAPIPacket; - taskfile.ataRegs[kATARegATAPIFeatures] = 0; - taskfile.ataRegs[kATARegATAPIByteCountLow] = 0xfe; - taskfile.ataRegs[kATARegATAPIByteCountHigh] = 0xff; - - atapiCmd.cdbLength = 12; // Fix 16 byte cmdpkts?? - atapiCmd.cdb[0] = 0x00; - - probeCmd->setCDB( &atapiCmd ); - probeCmd->setTaskfile( &taskfile ); - probeCmd->setPointers( (IOMemoryDescriptor *)NULL, 0, false ); - probeCmd->setTimeout( 5000 ); - probeCmd->setQueueInfo(); - probeCmd->execute(); - probeCmd->getResults(&result); - - return result.returnCode; -} - - -/* - * - * - */ -IOReturn IOATAStandardDevice::doReadCapacity( void *data ) -{ - ATATaskfile taskfile; - ATACDBInfo atapiCmd; - ATAResults result; - IOMemoryDescriptor *dataDesc; - UInt32 size = 8; - - - bzero( &taskfile, sizeof(taskfile) ); - bzero( &atapiCmd, sizeof(atapiCmd) ); - - dataDesc = IOMemoryDescriptor::withAddress( data, size, kIODirectionIn ); - if ( dataDesc == NULL ) - { - return kIOReturnNoMemory; - } - - taskfile.protocol = kATAProtocolATAPIPIO; - taskfile.regmask = ATARegtoMask(kATARegATAPIDeviceSelect) - | ATARegtoMask(kATARegATAPICommand) - | ATARegtoMask(kATARegATAPIByteCountLow) - | ATARegtoMask(kATARegATAPIByteCountHigh) - | ATARegtoMask(kATARegATAPIFeatures); - taskfile.ataRegs[kATARegATAPIDeviceSelect] = kATAModeLBA | (getUnit() << 4); - taskfile.ataRegs[kATARegATAPICommand] = kATACommandATAPIPacket; - taskfile.ataRegs[kATARegATAPIFeatures] = 0; - taskfile.ataRegs[kATARegATAPIByteCountLow] = 0xfe; - taskfile.ataRegs[kATARegATAPIByteCountHigh] = 0xff; - - atapiCmd.cdbLength = 12; // Fix 16 byte cmdpkts?? - atapiCmd.cdb[0] = 0x25; - - probeCmd->setCDB( &atapiCmd ); - probeCmd->setTaskfile( &taskfile ); - probeCmd->setPointers( dataDesc, size, false ); - probeCmd->setTimeout( 5000 ); - probeCmd->setQueueInfo(); - probeCmd->execute(); - - probeCmd->getResults(&result); - - dataDesc->release(); - - return result.returnCode; -} - -/* - * - * - */ -bool IOATAStandardDevice::getTimingsSupported( ATATimingProtocol *timingsSupported ) -{ - UInt32 i; - - *(UInt32 *)timingsSupported = 0; - - for ( i=0; i < numTimings; i++ ) - { - *(UInt32 *) timingsSupported |= (UInt32)ataTimings[i].timingProtocol; - } - - return true; -} - -/* - * - * - */ -bool IOATAStandardDevice::getTimingSelected( ATATimingProtocol *timingSelected ) -{ - *timingSelected = currentTiming; - return true; -} - -/* - * - * - */ -bool IOATAStandardDevice::getProtocolsSupported( ATAProtocol *forProtocolsSupported ) -{ - *(UInt32 *)forProtocolsSupported = protocolsSupported; - return true; -} - -/* - * - * - */ -bool IOATAStandardDevice::getTiming( ATATimingProtocol *timingProtocol, ATATiming *timing ) -{ - UInt32 i; - - for ( i=0; i < numTimings; i++ ) - { - if ( ataTimings[i].timingProtocol == *timingProtocol ) - { - bcopy( &ataTimings[i], timing, sizeof(ATATiming) ); - return true; - } - } - - return false; -} - - -/* - * - * - */ -bool IOATAStandardDevice::selectTiming( ATATimingProtocol timingProtocol, bool fNotifyMsg ) -{ - ATATaskfile taskfile; - bool rc = false; - UInt32 i; - IOATAStandardCommand * ataCmd; - - for ( i=0; i < numTimings; i++ ) - { - if ( ataTimings[i].timingProtocol == timingProtocol ) - { - rc = true; - break; - } - } - - if ( rc == false ) - { - return false; - } - - ataCmd = allocCommand(kIOATAStandardDevice, 0); - if ( ataCmd == 0 ) return false; - - currentTiming = timingProtocol; - - bzero( &taskfile, sizeof(taskfile) ); - - taskfile.protocol = kATAProtocolPIO; - taskfile.regmask = ATARegtoMask(kATARegFeatures) - | ATARegtoMask(kATARegSectorCount) - | ATARegtoMask(kATARegDriveHead) - | ATARegtoMask(kATARegCommand); - - taskfile.ataRegs[kATARegSectorCount] = ataTimings[i].featureSetting; - taskfile.ataRegs[kATARegFeatures] = kATAFeatureTransferMode; - taskfile.ataRegs[kATARegDriveHead] = kATAModeLBA | (getUnit() << 4); - taskfile.ataRegs[kATARegCommand] = kATACommandSetFeatures; - - taskfile.flags = kATACmdFlagTimingChanged; - - ataCmd->setTaskfile( &taskfile ); - ataCmd->setPointers( (IOMemoryDescriptor *)NULL, 0, false ); - ataCmd->setTimeout( 5000 ); - ataCmd->setQueueInfo( kATAQTypeBypassQ ); - - if ( fNotifyMsg == false ) - { - ataCmd->setCallback(); - ataCmd->execute(); - if ( ataCmd->getResults( (ATAResults *) 0 ) != kIOReturnSuccess ) - { - rc = false; - } - ataCmd->release(); - } - else - { - ataCmd->setCallback( this, (CallbackFn)&IOATAStandardDevice::selectTimingDone, ataCmd ); - ataCmd->execute(); - } - return rc; -} - -/* - * - * - */ -void IOATAStandardDevice::selectTimingDone( IOATAStandardCommand *ataCmd ) -{ - bool rc; - - rc = (ataCmd->getResults( (ATAResults *)0 ) == kIOReturnSuccess); - - client->message( kATAClientMsgSelectTiming | kATAClientMsgDone, this, (void *)rc ); - - ataCmd->release(); -} - -/* - * - * - */ -bool IOATAStandardDevice::getATATimings() -{ - int i, n; - UInt32 mode = 0; - UInt32 cycleTime = 0; - - ATATiming *pTimings; - - if ( controller->getProtocolsSupported( (ATAProtocol *)&protocolsSupported ) == false ) - { - return false; - } - - pTimings = ataTimings; - - /* - * PIO Cycle timing...... - * - * 1. Try to match Word 51 (pioCycleTime) with cycle timings - * in our pioModes table to get mode/CycleTime. (Valid for Modes 0-2) - * 2. If Words 64-68 are supported and Mode 3 or 4 supported check, - * update CycleTime with Word 68 (CycleTimeWithIORDY). - */ - - cycleTime = identifyData->pioMode; - - if ( cycleTime > 2 ) - { - for ( i=AppleNumPIOModes-1; i != -1; i-- ) - { - if ( cycleTime <= ApplePIOModes[i].minDataCycle ) - { - mode = i; - break; - } - } - - if ( i == -1 ) - { - cycleTime = ApplePIOModes[mode].minDataCycle; - } - } - else - { - mode = cycleTime; - cycleTime = ApplePIOModes[mode].minDataCycle; - } - - - if ( identifyData->validFields & identifyWords_64to70_Valid ) - { - if (identifyData->advancedPIOModes & advPIOModes_Mode4_Supported) - mode = 4; - else if (identifyData->advancedPIOModes & advPIOModes_Mode3_Supported) - mode = 3; - - if ( (mode >= 3) && identifyData->minPIOCyclcTimeIORDY ) - { - cycleTime = identifyData->minPIOCyclcTimeIORDY; - } - } - - pTimings->timingProtocol = kATATimingPIO; - pTimings->mode = mode; - pTimings->featureSetting = mode | kATATransferModePIOwFC; - pTimings->minDataCycle = cycleTime; - pTimings->minDataAccess = ApplePIOModes[mode].minDataAccess; - - if ( ((protocolsSupported & kATAProtocolPIO) == 0) - || (controller->calculateTiming( getUnit(), pTimings ) == false) ) - { - IOLog("IOATAStandardDevice::%s() - Controller driver must support PIO protocol\n\r", __FUNCTION__); - return false; - } - - pTimings++; - numTimings++; - - /* - * Multiword DMA timing..... - * - * 1. Check Word 63(7:0) (Multiword DMA Modes Supported). Lookup - * CycleTime for highest mode we support. - * 2. If Words 64-68 supported, update CycleTime from Word 66 - * (RecommendedMultiWordCycleTime) if specified. - */ - - n = identifyData->dmaModes & dmaModes_Supported; - if ( n ) - { - for ( i=0; n; i++, n>>=1 ) - ; - - mode = i - 1; - if ( mode > AppleNumDMAModes-1 ) - { - mode = AppleNumDMAModes-1; - } - cycleTime = AppleDMAModes[mode].minDataCycle; - - if (identifyData->validFields & identifyWords_64to70_Valid) - { - if ( identifyData->recDMACycleTime ) - { - cycleTime = identifyData->recDMACycleTime; - } - } - pTimings->timingProtocol = kATATimingDMA; - pTimings->mode = mode; - pTimings->featureSetting = mode | kATATransferModeDMA; - pTimings->minDataCycle = cycleTime; - pTimings->minDataAccess = AppleDMAModes[mode].minDataAccess; - - if ( ((protocolsSupported & kATAProtocolDMA) != 0) - && (controller->calculateTiming( getUnit(), pTimings ) == true) ) - { - pTimings++; - numTimings++; - } - } - - /* - * Ultra DMA timing..... - * - */ - if ( identifyData->validFields & identifyWords_88to88_Valid ) - { - n = identifyData->ultraDMAModes & ultraDMAModes_Supported; - if ( n ) - { - for ( i=0; n; i++, n>>=1 ) - ; - - mode = i - 1; - if ( mode > AppleNumUltraModes-1 ) - { - mode = AppleNumUltraModes-1; - } - - /* - * Build a separate timing entry for Ultra DMA/33 (mode <= 2) and Ultra DMA/66 - */ - while ( 1 ) - { - cycleTime = AppleUltraModes[mode].minDataCycle; - - pTimings->timingProtocol = (mode > 2) ? kATATimingUltraDMA66 : kATATimingUltraDMA33; - pTimings->mode = mode; - pTimings->featureSetting = mode | kATATransferModeUltraDMA33; - pTimings->minDataCycle = cycleTime; - pTimings->minDataAccess = AppleUltraModes[mode].minDataAccess; - - if ( ((protocolsSupported & kATAProtocolDMA) != 0) - && (controller->calculateTiming( getUnit(), pTimings ) == true) ) - { - pTimings++; - numTimings++; - } - - if ( mode < 3 ) break; - - mode = 2; - } - } - } - - maxTags = 0; - - if ( deviceType == kATADeviceATA ) - { - if ( ((identifyData->commandSetsSupported2 & commandSetsSupported2_ValidMask) == commandSetsSupported2_Valid) - && ((identifyData->commandSetsSupported3 & commandSetsSupported3_ValidMask) == commandSetsSupported3_Valid) ) - { - if ( ((identifyData->commandSetsSupported2 & commandSetsSupported2_DMAQueued) != 0) - && ((identifyData->commandSetsEnabled2 & commandSetsEnabled2_DMAQueued) != 0) ) - { - maxTags = identifyData->queueDepth + 1; - } - } - } - - if ( maxTags == 0 ) - { - protocolsSupported &= ~(kATAProtocolDMAQueued | kATAProtocolDMAQueuedRelease); - } - - - return true; -} - -/* - * - * - * - */ -ATAUnit IOATAStandardDevice::getUnit() -{ - return unit; -} - -/* - * - * - */ -ATADeviceType IOATAStandardDevice::getDeviceType() -{ - return deviceType; -} - -/* - * - * - */ -bool IOATAStandardDevice::getATAPIPktInt() -{ - return atapiPktInt; -} - -/* - * - * - */ -bool IOATAStandardDevice::getIdentifyData( ATAIdentify *identifyBuffer ) -{ - if ( identifyData == NULL ) - { - bzero( identifyBuffer, sizeof(ATAIdentify) ); - return false; - } - - bcopy( identifyData, identifyBuffer, sizeof(ATAIdentify) ); - return true; -} - -/* - * - * - */ -bool IOATAStandardDevice::getInquiryData( UInt32 inquiryBufLength, ATAPIInquiry *inquiryBuffer ) -{ - bzero( inquiryBuffer, inquiryBufLength ); - - if ( inquiryData == NULL ) - { - return false; - } - - bcopy( inquiryData, inquiryBuffer, inquiryBufLength ); - - return true; -} - - -/* - * - * - * - */ -void IOATAStandardDevice::setupTarget() -{ -} - -/* - * - * - * - */ -void IOATAStandardDevice::getInquiryData( void *clientBuf, UInt32 clientBufSize, UInt32 *clientDataSize ) -{ - UInt32 len; - - bzero( clientBuf, clientBufSize ); - - len = MIN( clientBufSize, inquiryDataSize ); - - bcopy( inquiryData, clientBuf, len ); - - *clientDataSize = len; -} - -/* - * - * - * - */ -void IOATAStandardDevice::abort() -{ - submitCommand( kATACommandAbortAll, 0 ); -} - -/* - * - * - * - */ -void IOATAStandardDevice::reset() -{ - submitCommand( kATACommandDeviceReset, 0 ); -} - -/* - * - * - * - */ -void IOATAStandardDevice::holdQueue( UInt32 queueType ) -{ - if ( getWorkLoop()->inGate() == false ) - { - IOPanic( "IOATAStandardDevice::holdQueue() - must be called from workloop!!\n\r"); - } - - if ( queueType == kATAQTypeBypassQ ) - { - bypassQHeld++; - } - else if ( queueType == kATAQTypeNormalQ ) - { - normalQHeld++; - } -} - -/* - * - * - * - */ -void IOATAStandardDevice::releaseQueue( UInt32 queueType ) -{ - bool doDispatchRequest = false; - - if ( getWorkLoop()->inGate() == false ) - { - IOPanic( "IOATAStandardDevice::releaseQueue() - must be called from workloop!!\n\r"); - } - - if ( queueType == kATAQTypeBypassQ ) - { - if ( bypassQHeld && (--bypassQHeld == 0) ) - doDispatchRequest = true; - } - else if ( queueType == kATAQTypeNormalQ ) - { - if ( normalQHeld && (--normalQHeld == 0) ) - doDispatchRequest = true; - } - - if ( doDispatchRequest ) dispatchRequest(); -} - -/* - * - * - * - */ -void IOATAStandardDevice::notifyIdle( void *target = 0, CallbackFn callback = 0, void *refcon = 0 ) -{ - if ( getWorkLoop()->inGate() == false ) - { - IOPanic( "IOATAStandardDevice:::notifyIdle() - must be called from workloop!!\n\r"); - } - - if ( callback == 0 ) - { - idleNotifyActive = false; - return; - } - - if ( idleNotifyActive == true ) - { - IOPanic( "IOATAStandardDevice:::notifyIdle() - only one idle notify may be active\n\r"); - } - - idleNotifyActive = true; - idleNotifyTarget = target; - idleNotifyCallback = callback; - idleNotifyRefcon = refcon; - - checkIdleNotify(); -} - - -/* - * - * - * - */ -void IOATAStandardDevice::submitCommand( UInt32 cmdType, IOATAStandardCommand *ataCmd, UInt32 cmdSequenceNumber ) -{ - deviceGate->runCommand( (void *)cmdType, (void *)ataCmd, (void *) cmdSequenceNumber, (void *) 0 ); -} - -/* - * - * - * - */ -void IOATAStandardDevice::receiveCommand( UInt32 cmdType, IOATAStandardCommand *ataCmd, UInt32 cmdSequenceNumber, void *p3 ) -{ - queue_head_t *queue; - - switch ( cmdType ) - { - case kATACommandExecute: - ataCmd->cmdType = (ATACommandType) cmdType; - - queue = (ataCmd->queueType == kATAQTypeBypassQ) ? &bypassList : &deviceList; - - if ( ataCmd->queuePosition == kATAQPositionHead ) - { - stackCommand( queue, ataCmd ); - } - else - { - addCommand( queue, ataCmd ); - } - - dispatchRequest(); - break; - - case kATACommandAbortAll: - abortAllCommands( kATACommandAbortAll ); - break; - - case kATACommandAbort: - abortCommand( ataCmd, cmdSequenceNumber ); - break; - - case kATACommandDeviceReset: - abortAllCommands( kATACommandDeviceReset ); - break; - - default: - /* ??? */ - break; - } -} - -/* - * - * - * - */ -void IOATAStandardDevice::abortCommand( IOATAStandardCommand *ataCmd, UInt32 sequenceNumber ) -{ - if ( ataCmd->list == (queue_head_t *)deviceGate ) - { - if ( ataCmd->sequenceNumber != sequenceNumber ) - { - return; - } - ataCmd->results.returnCode = kIOReturnAborted; - } - else if ( ataCmd->list == &deviceList ) - { - if ( ataCmd->sequenceNumber != sequenceNumber ) - { - return; - } - - deleteCommand( &deviceList, ataCmd ); - ataCmd->results.returnCode = kIOReturnAborted; - finishCommand( ataCmd ); - } - else if ( ataCmd->list == &activeList ) - { - if ( ataCmd->sequenceNumber != sequenceNumber ) - { - return; - } - - moveCommand( &activeList, &abortList, ataCmd ); - - dispatchRequest(); - } -} - - -/* - * - * - * - */ -void IOATAStandardDevice::abortAllCommands( ATACommandType cmdType ) -{ - - abortCmdPending = cmdType; - - if ( abortCmdPending == kATACommandAbortAll ) - { - if ( client != 0 ) - { - client->message( kATAClientMsgDeviceAbort, this ); - } - } - else if ( abortCmdPending == kATACommandDeviceReset ) - { - if ( client != 0 ) - { - client->message( kATAClientMsgDeviceReset, this ); - } - } - - dispatchRequest(); -} - -/* - * - * - * - */ -void IOATAStandardDevice::resetOccurred( ATAClientMessage clientMsg ) -{ - moveAllCommands( &activeList, &cancelList, kIOReturnAborted ); - moveAllCommands( &abortList, &cancelList, kIOReturnAborted ); - - abortState = kStateIdle; - reqSenseState = kStateIdle; - commandLimit = 1; - - isSuspended = false; - AbsoluteTime_to_scalar( &suspendTime ) = 0; - - if ( (client != 0) && (clientMsg != kATAClientMsgNone) ) - { - client->message( clientMsg, this ); - } - - dispatchRequest(); -} - -void IOATAStandardDevice::resetComplete() -{ - if ( client != 0 ) - { - client->message( kATAClientMsgBusReset | kATAClientMsgDone, this ); - } -} - - -/* - * - * - * - */ -bool IOATAStandardDevice::checkAbortQueue() -{ - IOATAStandardCommand *origCmd; - - if ( abortState == kStateActive ) - { - return true; - } - - if ( abortCmdPending != kATACommandNone ) - { - abortCmd->origCommand = 0; - abortCmd->taskfile.tagType = kATATagTypeNone; - abortCmd->cmdType = abortCmdPending; - - abortCmd->timer = ( abortCmd->timeout != 0 ) ? - abortCmd->timeout / kATATimerIntervalmS + 1 : 0; - - bzero( &abortCmd->results, sizeof(ATAResults) ); - - abortState = kStateActive; - - addCommand( &activeList, abortCmd ); - - if ( (abortCmdPending == kATACommandDeviceReset) || - (abortCmdPending == kATACommandAbortAll) && (queue_empty( &abortList ) == false) ) - { - controller->abortCommand( abortCmd ); - } - else - { - abortCmd->complete(); - } - } - else if ( queue_empty( &abortList ) == false ) - { - origCmd = (IOATAStandardCommand *)queue_first( &abortList ); - abortCmd->origCommand = origCmd; - - abortCmd->cmdType = kATACommandAbort; - abortCmd->taskfile.tagType = origCmd->taskfile.tagType; - abortCmd->taskfile.tag = origCmd->taskfile.tag; - - abortCmd->timer = ( abortCmd->timeout != 0 ) ? - abortCmd->timeout / kATATimerIntervalmS + 1 : 0; - - bzero( &abortCmd->results, sizeof(ATAResults) ); - - abortState = kStateActive; - - addCommand( &activeList, abortCmd ); - controller->abortCommand( abortCmd ); - } - else - { - return false; - } - - return true; -} - -/* - * - * - * - */ -void IOATAStandardDevice::checkCancelQueue() -{ - if ( cancelState != kStateIdle ) - { - return; - } - - if ( queue_empty( &cancelList ) == true ) - { - return; - } - - if ( controller->controllerInfo.disableCancelCommands == true ) - { - return; - } - - cancelCmd->origCommand = (IOATAStandardCommand *)queue_first( &cancelList ); - bzero( &cancelCmd->results, sizeof(ATAResults) ); - - cancelState = kStateActive; - controller->cancelCommand( cancelCmd ); -} - -/* - * - * - * - */ -bool IOATAStandardDevice::checkReqSense() -{ - IOMemoryDescriptor *senseData; - UInt32 senseLength; - - if ( reqSenseState == kStateIssue ) - { - reqSenseCmd->origCommand = reqSenseOrigCmd; - bzero( &reqSenseCmd->results, sizeof(ATAResults) ); - - reqSenseOrigCmd->getPointers( &senseData, &senseLength, 0, true ); - reqSenseCmd->setPointers( senseData, senseLength, false ); - - reqSenseCmd->timer = ( reqSenseCmd->timeout != 0 ) ? - reqSenseCmd->timeout / kATATimerIntervalmS + 1 : 0; - - reqSenseCmd->ataCmd.cdb[3] = (senseLength >> 8) & 0xff; - reqSenseCmd->ataCmd.cdb[4] = senseLength & 0xff; - - reqSenseState = kStatePending; - } - - if ( reqSenseState == kStatePending ) - { - reqSenseState = kStateActive; - - addCommand( &activeList, reqSenseCmd ); - - commandCount++; - controller->commandCount++; - - controller->executeCommand( reqSenseCmd ); - } - - return (reqSenseState != kStateIdle); -} - - -/* - * - * - * - */ -bool IOATAStandardDevice::checkDeviceQueue( UInt32 *dispatchAction ) -{ - IOATAStandardCommand *ataCmd = 0; - queue_head_t *queue; - UInt32 i; - bool rc = true; - UInt32 queueHeld; - - do - { - if ( isSuspended == true ) - { - *dispatchAction = kDispatchNextDevice; - break; - } - - if ( controller->commandCount >= controller->commandLimit ) - { - *dispatchAction = kDispatchStop; - break; - } - - *dispatchAction = kDispatchNextDevice; - - if ( commandCount >= commandLimit ) - { - break; - } - - for ( i=0; i < 2; i++ ) - { - queueHeld = (i == 0) ? bypassQHeld : normalQHeld; - queue = (i == 0) ? &bypassList : &deviceList; - - if ( queueHeld > 0 ) - { - continue; - } - - ataCmd = checkCommand( queue ); - if ( ataCmd != 0 ) - { - *dispatchAction = kDispatchNextCommand; - break; - } - } - - if ( i == 2 ) - { - rc = false; - break; - } - - - if ( checkTag( ataCmd ) == false ) - { - *dispatchAction = kDispatchNextDevice; - break; - } - - getCommand( queue ); - - ataCmd->timer = ( ataCmd->timeout != 0 ) ? ataCmd->timeout / kATATimerIntervalmS + 1 : 0; - - commandCount++; - controller->commandCount++; - - addCommand( &activeList, ataCmd ); - - controller->executeCommand( ataCmd ); - - } while ( 0 ); - - return rc; -} - -/* - * - * - * - */ -void IOATAStandardDevice::suspend() -{ - if ( AbsoluteTime_to_scalar( &suspendTime ) == 0 ) - { - clock_get_uptime( &suspendTime ); - } - - isSuspended = true; -} - -/* - * - * - * - */ -void IOATAStandardDevice::resume() -{ - AbsoluteTime_to_scalar( &suspendTime ) = 0; - isSuspended = false; - - dispatchRequest(); -} - - -/* - * - * - * - */ -void IOATAStandardDevice::rescheduleCommand( IOATAStandardCommand *ataCmd ) -{ - queue_head_t *queue; - - if ( ataCmd->list != &activeList ) - { - IOLog( "IOATAStandardController::rescheduleCommand() - Command not active. Cmd = %08x\n\r", (int)ataCmd ); - return; - } - - deleteCommand( &activeList, ataCmd ); - - switch ( ataCmd->cmdType ) - { - case kATACommandExecute: - if ( ataCmd->taskfile.tagType != kATATagTypeNone ) - { - freeTag( ataCmd->taskfile.tag ); - ataCmd->taskfile.tag = kATATagTypeNone; - } - - queue = (ataCmd->queueType == kATAQTypeBypassQ) ? &bypassList : &deviceList; - - stackCommand( queue, ataCmd ); - - controller->commandCount--; - commandCount--; - break; - - case kATACommandReqSense: - reqSenseState = kStatePending; - commandCount--; - controller->commandCount--; - break; - - case kATACommandAbortAll: - case kATACommandDeviceReset: - abortCmdPending = ataCmd->cmdType; - - case kATACommandAbort: - abortState = kStateIdle; - break; - - default: - ; - } - - dispatchRequest(); - -} - -/* - * - * - * - */ -bool IOATAStandardDevice::checkTag( IOATAStandardCommand *ataCmd ) -{ - ATACDBInfo ataCDB; - bool rc = true; - ATAProtocol protocol; - - ataCmd->getCDB( &ataCDB ); - - ataCmd->taskfile.tagType = kATATagTypeNone; - - protocol = ataCmd->getProtocol(); - - do - { - if ( protocol != kATAProtocolDMAQueued && protocol != kATAProtocolDMAQueuedRelease ) - { - break; - } - if ( allocTag( &ataCmd->taskfile.tag ) == false ) - { - rc = false; - break; - } - - ataCmd->taskfile.tagType = kATATagTypeSimple; - } - while ( 0 ); - - ataCmd->setCDB( &ataCDB ); - - return rc; -} - -/* - * - * - * - */ -bool IOATAStandardDevice::allocTag( UInt32 *tagId ) -{ - UInt32 i; - UInt32 tagIndex; - UInt32 tagMask; - UInt32 *tags = 0; - - tags = tagArray; - - if ( tags == 0 ) return false; - - for ( i = 0; i < maxTags; i++ ) - { - tagIndex = i / 32; - tagMask = 1 << (i % 32); - if ( !(tags[tagIndex] & tagMask) ) - { - tags[tagIndex] |= tagMask; - *tagId = i; - return true; - } - } - return false; -} - -/* - * - * - * - */ -void IOATAStandardDevice::freeTag( UInt32 tagId ) -{ - UInt32 *tags = 0; - - tags = tagArray; - - if ( tags == 0 ) return; - - tags[tagId/32] &= ~(1 << (tagId % 32)); -} - -/* - * - * - * - */ -IOATAStandardCommand *IOATAStandardDevice::findCommandWithNexus( UInt32 tagValue ) -{ - IOATAStandardCommand *ataCmd; - UInt32 tag; - - queue_iterate( &activeList, ataCmd, IOATAStandardCommand *, nextCommand ) - { - switch ( ataCmd->cmdType ) - { - case kATACommandExecute: - case kATACommandReqSense: - tag = (ataCmd->taskfile.tagType == kATATagTypeNone) ? (UInt32) -1 : ataCmd->taskfile.tag; - if ( tag == tagValue ) - { - return ataCmd; - } - break; - default: - ; - } - } - - queue_iterate( &abortList, ataCmd, IOATAStandardCommand *, nextCommand ) - { - switch ( ataCmd->cmdType ) - { - case kATACommandExecute: - case kATACommandReqSense: - if ( ataCmd->taskfile.tag == tagValue ) - { - return ataCmd; - } - break; - default: - ; - } - } - - return 0; -} - -/* - * - * - * - */ -void IOATAStandardDevice::timer() -{ - IOATAStandardCommand *ataCmd, *tmp = 0; - - queue_iterate( &activeList, ataCmd, IOATAStandardCommand *, nextCommand ) - { - tmp = (IOATAStandardCommand *)queue_prev( &ataCmd->nextCommand ); - - if ( ataCmd->timer ) - { - if ( !--ataCmd->timer ) - { - IOLog("Timeout: Unit = %d Cmd = %08x Cmd Type = %d\n\r", - unit, (int)ataCmd, ataCmd->cmdType ); - - controller->busResetState = kStateIssue; - dispatchRequest(); - } - } - - if ( queue_end( &activeList, (queue_head_t *)ataCmd ) == true ) - { - break; - } - } -} - -/* - * - * - * - */ -void IOATAStandardDevice::dispatchRequest() -{ - target->state = kStateActive; - controller->dispatchRequest(); -} - -/* - * - * - * - */ -bool IOATAStandardDevice::dispatch( UInt32 *dispatchAction ) -{ - bool rc; - - checkCancelQueue(); - - if ( controller->checkBusReset() == true ) - { - *dispatchAction = kDispatchStop; - return true; - } - - if ( checkAbortQueue() == true ) - { - *dispatchAction = kDispatchNextDevice; - return true; - } - - do - { - if ( (rc = controller->commandDisable) == true ) - { - *dispatchAction = kDispatchStop; - break; - } - - if ( isSuspended == true ) - { - *dispatchAction = kDispatchNextDevice; - break; - } - - if ( (rc = checkReqSense()) == true ) - { - *dispatchAction = kDispatchNextDevice; - break; - } - - rc = checkDeviceQueue( dispatchAction ); - - } while ( *dispatchAction == kDispatchNextCommand ); - - return rc; -} - - -/* - * - * - * - */ -void IOATAStandardDevice::completeCommand( IOATAStandardCommand *ataCmd ) -{ - ATACommandType cmdType; - - cmdType = ataCmd->cmdType; - switch ( cmdType ) - { - case kATACommandExecute: - executeCommandDone( ataCmd ); - break; - - case kATACommandReqSense: - executeReqSenseDone( ataCmd ); - break; - - case kATACommandAbort: - case kATACommandAbortAll: - case kATACommandDeviceReset: - abortCommandDone( ataCmd ); - break; - - case kATACommandCancel: - cancelCommandDone( ataCmd ); - break; - - default: - ; - } - - checkIdleNotify(); - - dispatchRequest(); -} - -/* - * - * - * - */ -void IOATAStandardDevice::checkIdleNotify() -{ - if ( idleNotifyActive == false ) - { - return; - } - - if ( (queue_empty( &activeList ) == true) - && (queue_empty( &abortList ) == true) - && (queue_empty( &cancelList ) == true) ) - { - idleNotifyActive = false; - (idleNotifyCallback)( idleNotifyTarget, idleNotifyRefcon ); - } -} - -/* - * - * - * - */ -void IOATAStandardDevice::flushQueue( UInt32 queueType, IOReturn rc ) -{ - queue_head_t *queue; - - queue = (queueType == kATAQTypeBypassQ) ? &bypassList : &deviceList; - purgeAllCommands( queue, rc ); -} - -/* - * - * - * - */ -void IOATAStandardDevice::executeCommandDone( IOATAStandardCommand *ataCmd ) -{ - deleteCommand( ataCmd->list, ataCmd ); - - commandCount--; - controller->commandCount--; - - if ( ataCmd->taskfile.tagType != kATATagTypeNone ) - { - freeTag( ataCmd->taskfile.tag ); - ataCmd->taskfile.tagType = kATATagTypeNone; - } - - if ( deviceType == kATADeviceATAPI - && ataCmd->results.adapterStatus == kATAReturnStatusError - && ataCmd->results.requestSenseDone == false - && ataCmd->senseData != 0 ) - { - reqSenseOrigCmd = ataCmd; - reqSenseState = kStateIssue; - return; - } - - finishCommand( ataCmd ); -} - -/* - * - * - * - */ -void IOATAStandardDevice::executeReqSenseDone( IOATAStandardCommand *ataCmd ) -{ - IOATAStandardCommand *origCommand; - - deleteCommand( ataCmd->list, ataCmd ); - - commandCount--; - controller->commandCount--; - - reqSenseState = kStateIdle; - - reqSenseOrigCmd = 0; - - origCommand = ataCmd->origCommand; - - if ( (ataCmd->results.returnCode == kIOReturnSuccess) || (ataCmd->results.returnCode == kIOReturnUnderrun)) - { - origCommand->results.requestSenseDone = true; - origCommand->results.requestSenseLength = ataCmd->results.bytesTransferred; - } - else - { - origCommand->results.requestSenseDone = false; - origCommand->results.requestSenseLength = 0; - } - - finishCommand( ataCmd->origCommand ); -} - -/* - * - * - * - */ -void IOATAStandardDevice::abortCommandDone( IOATAStandardCommand *ataCmd ) -{ - IOATAStandardCommand *origATACmd; - - deleteCommand( ataCmd->list, ataCmd ); - - if ( ataCmd->cmdType == kATACommandAbortAll ) - { - resetOccurred( (ATAClientMessage) (kATAClientMsgDeviceAbort | kATAClientMsgDone) ); - abortCmdPending = kATACommandNone; - } - if ( ataCmd->cmdType == kATACommandDeviceReset ) - { - resetOccurred( (ATAClientMessage) (kATAClientMsgDeviceReset | kATAClientMsgDone) ); - abortCmdPending = kATACommandNone; - } - else if ( ataCmd->cmdType == kATACommandAbort ) - { - origATACmd = ataCmd->origCommand; - - if ( findCommand( &abortList, origATACmd ) == true ) - { - moveCommand( &abortList, &cancelList, origATACmd, kIOReturnAborted ); - } - } - - abortState = kStateIdle; - - return; -} - -/* - * - * - * - */ -void IOATAStandardDevice::cancelCommandDone( IOATAStandardCommand *ataCmd ) -{ - IOATAStandardCommand *origATACmd; - - cancelState = kStateIdle; - - origATACmd = ataCmd->origCommand; - - if ( findCommand( &cancelList, origATACmd ) == true ) - { - IOLog( "IOATAStandardDevice::cancelCommandDone - Cancelled command not completed - ataCmd = %08x\n\r", (int)origATACmd ); - deleteCommand( &cancelList, origATACmd ); - } -} - -/* - * - * - * - */ -void IOATAStandardDevice::finishCommand( IOATAStandardCommand *ataCmd ) -{ - if ( ataCmd->completionInfo.async.callback ) - { - (*ataCmd->completionInfo.async.callback)( ataCmd->completionInfo.async.target, - ataCmd->completionInfo.async.refcon ); - } - else - { - ataCmd->completionInfo.sync.lock->signal(); - } -} - - -/* - * - * - */ -OSDictionary *IOATAStandardDevice::createProperties() -{ - OSDictionary *propTable = 0; - OSObject *regObj; - char tmpbuf[81]; - const char *s; - char *d; - - - propTable = OSDictionary::withCapacity(kATAMaxProperties); - if ( propTable == NULL ) - { - return NULL; - } - - s = (deviceType == kATADeviceATA) ? kATAPropertyProtocolATA : kATAPropertyProtocolATAPI; - regObj = (OSObject *)OSString::withCString( s ); - if ( addToRegistry( propTable, regObj, kATAPropertyProtocol ) != true ) - { - goto createprop_error; - } - - regObj = (OSObject *)OSNumber::withNumber(unit,32); - if ( addToRegistry( propTable, regObj, kATAPropertyDeviceNumber ) != true ) - { - goto createprop_error; - } - - regObj = (OSObject *)OSNumber::withNumber(unit,32); - if ( addToRegistry( propTable, regObj, kATAPropertyLocation ) != true ) - { - goto createprop_error; - } - - d = tmpbuf; - stripBlanks( d, (char *)identifyData->modelNumber, sizeof(identifyData->modelNumber)); - regObj = (OSObject *)OSString::withCString( d ); - if ( addToRegistry( propTable, regObj, kATAPropertyModelNumber ) != true ) - { - goto createprop_error; - } - - d = tmpbuf; - stripBlanks( d, (char *)identifyData->firmwareRevision, sizeof(identifyData->firmwareRevision)); - regObj = (OSObject *)OSString::withCString( d ); - if ( addToRegistry( propTable, regObj, kATAPropertyFirmwareRev ) != true ) - { - goto createprop_error; - } - - if ( inquiryData ) - { - stripBlanks( d, (char *)inquiryData->vendorName, sizeof(inquiryData->vendorName) ); - regObj = (OSObject *)OSString::withCString( d ); - if ( addToRegistry( propTable, regObj, kATAPropertyVendorName ) != true ) - { - goto createprop_error; - } - - stripBlanks( d, (char *)inquiryData->productName, sizeof(inquiryData->productName) ); - regObj = (OSObject *)OSString::withCString( d ); - if ( addToRegistry( propTable, regObj, kATAPropertyProductName ) != true ) - { - goto createprop_error; - } - - stripBlanks( d, (char *)inquiryData->productRevision, sizeof(inquiryData->productRevision) ); - regObj = (OSObject *)OSString::withCString( d ); - if ( addToRegistry( propTable, regObj, kATAPropertyProductRevision ) != true ) - { - goto createprop_error; - } - } - return propTable; - -createprop_error: ; - propTable->release(); - return NULL; -} - - -/* - * - * - */ -bool IOATAStandardDevice::addToRegistry( OSDictionary *propTable, OSObject *regObj, char *key, - bool doRelease = true ) -{ - bool rc; - - if ( regObj == NULL ) - { - return false; - } - - rc = propTable->setObject( key, regObj ); - - if ( doRelease ) - { - // If 'doRelease' is true, then a reference count is consumed. - regObj->release(); - } - - return rc; -} - - -/* - * - * - * - */ -bool IOATAStandardDevice::matchPropertyTable(OSDictionary * table) -{ - return( controller->matchNubWithPropertyTable( this, table )); -} - - -/* - * - * - * - */ -IOService *IOATAStandardDevice::matchLocation(IOService * client) -{ - return this; -} - - -/* - * - * - * - */ -void IOATAStandardDevice::stripBlanks( char *d, char *s, UInt32 l ) -{ - char *p, c; - - for ( p = d, c = *s; l && c ; l--) - { - c = (*d++ = *s++); - if ( c != ' ' ) - { - p = d; - } - } - *p = 0; -} - -/* - * - * - */ -void IOATAStandardDevice::endianConvertData( void *data, void *endianTable ) -{ - EndianTable *t; - - union EndianPtr - { - void *voidPtr; - UInt8 *bytePtr; - UInt16 *shortPtr; - UInt32 *longPtr; - UInt64 *longlongPtr; - } p; - - UInt32 i,j; - - p.voidPtr = data; - - t = (EndianTable *)endianTable; - - for ( ; t->type; t++ ) - { - i = t->size/t->type; - - switch ( t->type ) - { - - /* Note: - * - * The ATA standard defines identify strings as arrays of short ints, - * with the left-most character of the string as the most significant - * byte of the short int. Strings are not normally affected by the host - * endianess. However, the way ATA defines strings would cause strings - * to appear byte reversed. We do a manditory short int byte-swap here, - * although strictly speaking this is not an endian issue. - * - */ - case sizeof(UInt8): - for ( j = 0; j < i/2; j++ ) - { - *p.shortPtr++ = OSSwapInt16(*p.shortPtr); - } - - break; - - case sizeof(UInt16): - for ( j = 0; j < i; j++ ) - { - *p.shortPtr++ = OSSwapLittleToHostInt16(*p.shortPtr); - } - break; - - case sizeof(UInt32): - for ( j = 0; j < i; j++ ) - { - *p.longPtr++ = OSSwapLittleToHostInt32(*p.longPtr); - } - break; - - case sizeof(UInt64): - for ( j = 0; j < i; j++ ) - { - *p.longlongPtr++ = OSSwapLittleToHostInt64(*p.longlongPtr); - } - break; - - default: - ; - } - } -} - -/* - * - * - * - */ -IOATACommand *IOATAStandardDevice::allocCommand( IOATADevice *, UInt32 clientDataSize ) -{ - return (IOATAStandardCommand *) allocCommand( kIOATAStandardDevice, clientDataSize ); -} - -IOCDBCommand *IOATAStandardDevice::allocCommand( IOCDBDevice *, UInt32 clientDataSize ) -{ - return (IOCDBCommand *) allocCommand( kIOATAStandardDevice, clientDataSize ); -} - -IOATAStandardCommand *IOATAStandardDevice::allocCommand( IOATAStandardDevice *, UInt32 clientDataSize ) -{ - IOATAStandardCommand *cmd; - - if ( (cmd = controller->allocCommand( clientDataSize )) ) - { - cmd->device = this; - } - return cmd; -} - - -/* - * - * - */ -IOWorkLoop *IOATAStandardDevice::getWorkLoop() const -{ - return controller->workLoop; -} - - -/* - * - * - * - */ -bool IOATAStandardDevice::open( IOService *forClient, IOOptionBits options, void *arg ) -{ - if ( client != 0 ) return false; - - client = forClient; - - return super::open( forClient, options, arg ); -} - -/* - * - * - * - */ -void IOATAStandardDevice::close( IOService *forClient, IOOptionBits options ) -{ - client = 0; - - return super::close( forClient, options ); -} - -/* - * - * - * - */ -void IOATAStandardDevice::free() -{ - if ( deviceGate != 0 ) - { - controller->workLoop->removeEventSource( deviceGate ); - deviceGate->release(); - } - - if ( reqSenseCmd != 0 ) reqSenseCmd->release(); - if ( abortCmd != 0 ) abortCmd->release(); - if ( cancelCmd != 0 ) cancelCmd->release(); - if ( probeCmd != 0 ) probeCmd->release(); - - if ( tagArray != 0 ) IOFree( tagArray, tagArraySize ); - if ( inquiryData != 0 ) IOFree( inquiryData, inquiryDataSize ); - if ( devicePrivateData != 0 ) IOFreeContiguous( devicePrivateData, controller->controllerInfo.devicePrivateDataSize ); - if ( clientSem != 0 ) IORWLockFree( clientSem ); - - super::free(); -} - - diff --git a/iokit/Families/IOATAStandard/IOATAStandardDriver.cpp b/iokit/Families/IOATAStandard/IOATAStandardDriver.cpp deleted file mode 100644 index 054405e67..000000000 --- a/iokit/Families/IOATAStandard/IOATAStandardDriver.cpp +++ /dev/null @@ -1,569 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * IOATAStandardDriver.cpp - * - */ -#include - -#undef super -#define super IOATAStandardController - -OSDefineMetaClass( IOATAStandardDriver, IOATAStandardController ); -OSDefineAbstractStructors( IOATAStandardDriver, IOATAStandardController ); - -#if 0 -static UInt32 dropInt=0; -#endif - -/* - * - * - */ -void IOATAStandardDriver::executeCommand( IOATAStandardCommand *cmd ) -{ - IOATAStandardDevice *newDevice; - ATAProtocol newProtocol; - ATATimingProtocol timingProtocol; - ATAResults results; - - newDevice = cmd->getDevice(kIOATAStandardDevice); - newProtocol = cmd->getProtocol(); - -#if 0 - IOLog("IOATAStandardDriver::%s() - Cmd = %08x Device = %08x Count = %d\n\r", - __FUNCTION__, (int) cmd, (int) newDevice, getCommandCount() ); -#endif - - if ( getCommandCount() > 1 ) - { - if ( currentDevice != newDevice || currentProtocol != newProtocol ) - { - suspendDevice( newDevice ); - rescheduleCommand( cmd ); - return; - } - } - - currentProtocol = newProtocol; - - if ( currentDevice != newDevice ) - { - newDeviceSelected( newDevice ); - currentDevice = newDevice; - } - - if ( (cmd->getFlags() & kATACmdFlagTimingChanged) != 0 ) - { - currentDevice->getTimingSelected( &timingProtocol ); - selectTiming( currentDevice->getUnit(), timingProtocol ); - newDeviceSelected( newDevice ); - } - - bzero( &results, sizeof(ATAResults) ); - cmd->setResults( &results ); - - switch ( currentProtocol ) - { - case kATAProtocolSetRegs: - doProtocolSetRegs( cmd ); - break; - - case kATAProtocolPIO: - doATAProtocolPio( cmd ); - break; - - case kATAProtocolDMA: - doATAProtocolDma( cmd ); - break; - - case kATAProtocolDMAQueued: - doATAProtocolDmaQueued( cmd ); - break; - - case kATAProtocolATAPIPIO: - doATAPIProtocolPio( cmd ); - break; - - case kATAProtocolATAPIDMA: - doATAPIProtocolDma( cmd ); - break; - - default: - doProtocolNotSupported( cmd ); - break; - } -} - - -/* - * - * - */ -void IOATAStandardDriver::resetCommand( IOATAStandardCommand *cmd ) -{ - - resetDma(); - dmaActive = false; - - currentProtocol = kATAProtocolNone; - currentDevice = 0; - doATAReset( cmd ); -} - -/* - * - * - */ -void IOATAStandardDriver::abortCommand( IOATAStandardCommand *ataCmd ) -{ - resetStarted(); - doATAReset( ataCmd ); -} - -/* - * - * - */ -void IOATAStandardDriver::cancelCommand( IOATAStandardCommand *ataCmd ) -{ - ATAResults results; - IOATAStandardCommand *origCmd; - - origCmd = ataCmd->getOriginalCmd(); - if ( origCmd != 0 ) - { - completeCmd( origCmd ); - } - - bzero( &results, sizeof(ATAResults) ); - ataCmd->setResults( &results ); - completeCmd( ataCmd ); -} - - -/* - * - * - */ -void IOATAStandardDriver::interruptOccurred() -{ -#if 0 - if ( dropInt++ > 20 ) - { - UInt32 status; - - IOLog("IOATAStandardDriver::%s() - Dropping interrupt\n\r", __FUNCTION__ ); - status = readATAReg( kATARegStatus ); - dropInt = 0; - return; - } -#endif - - if ( currentDevice == 0 ) - { - IOLog( "IOATAStandardDriver::interruptOccurred - Spurious interrupt - ATA Status = %04lx\n\r", readATAReg( kATARegStatus ) ); - return; - } - - switch ( currentProtocol ) - { - case kATAProtocolPIO: - processATAPioInt(); - break; - - case kATAProtocolDMA: - processATADmaInt(); - break; - - case kATAProtocolDMAQueued: - processATADmaQueuedInt(); - break; - - case kATAProtocolATAPIPIO: - processATAPIPioInt(); - break; - - case kATAProtocolATAPIDMA: - processATAPIDmaInt(); - break; - - default: - IOLog( "IOATAStandardDriver::interruptOccurred - Spurious interrupt - ATA Status = %04lx\n\r", readATAReg( kATARegStatus ) ); - } -} - - -/* - * - * - */ -void IOATAStandardDriver::doProtocolNotSupported( IOATAStandardCommand *cmd ) -{ - completeCmd( cmd, kATAReturnNotSupported ); -} - - -/* - * - * - */ -void IOATAStandardDriver::completeCmd( IOATAStandardCommand *cmd, ATAReturnCode returnCode, UInt32 bytesTransferred ) -{ - updateCmdStatus( cmd, returnCode, bytesTransferred ); - completeCmd( cmd ); -} - -/* - * - * - */ -void IOATAStandardDriver::updateCmdStatus( IOATAStandardCommand *cmd, ATAReturnCode returnCode, UInt32 bytesTransferred ) -{ - UInt32 resultmask; - UInt32 i; - ATAResults result; - - bzero( &result, sizeof(result) ); - - resultmask = cmd->getResultMask(); - - if ( cmd->getProtocol() != kATAProtocolSetRegs ) - { - if ( waitForStatus( 0, kATAStatusBSY, kATABusyTimeoutmS ) == false ) - { - if ( returnCode == kATAReturnSuccess ) - { - kprintf("IOATAStandardDriver::updateCmdStatus is going to return kATAReturnBusyError;\n"); - returnCode = kATAReturnBusyError; - } - } - } - - for ( i=0; resultmask; i++ ) - { - if ( resultmask & 1 ) - { - result.ataRegs[i] = readATAReg( i ); - } - resultmask >>= 1; - } - - result.adapterStatus = returnCode; - result.bytesTransferred = bytesTransferred; - cmd->setResults( &result ); -} - -/* - * - * - */ -void IOATAStandardDriver::completeCmd( IOATAStandardCommand *cmd ) -{ - IOATAStandardDevice *device; - ATAResults ataResult; - - cmd->getResults( &ataResult ); - ataResult.returnCode = getIOReturnCode( ataResult.adapterStatus ); - cmd->setResults( &ataResult ); - - if ( getCommandCount() == 1 ) - { - currentProtocol = kATAProtocolNone; - - device = selectDevice(); - if ( device != 0 ) - { - resumeDevice( device ); - } - } - - cmd->complete(); -} - -/* - * - * - */ -IOReturn IOATAStandardDriver::getIOReturnCode( ATAReturnCode code ) -{ - switch (code) - { - case kATAReturnSuccess: - return kIOReturnSuccess; - - case kATAReturnNotSupported: - return kIOReturnUnsupported; - - case kATAReturnNoResource: - return kIOReturnNoResources; - - case kATAReturnBusyError: - return kIOReturnBusy; - - case kATAReturnInterruptTimeout: - return kIOReturnTimeout; - - case kATAReturnRetryPIO: - case kATAReturnStatusError: - case kATAReturnProtocolError: - default: - ; - } - return kIOReturnIOError; -} - -/* - * - * - */ -void IOATAStandardDriver::newDeviceSelected( IOATAStandardDevice * ) -{ -} - - -/* - * - * - */ -bool IOATAStandardDriver::programDma( IOATAStandardCommand * ) -{ - IOLog( "IOATAStandardDriver::%s - Subclass must implement\n\r", __FUNCTION__ ); - return false; -} - - -/* - * - * - */ -bool IOATAStandardDriver::startDma( IOATAStandardCommand * ) -{ - IOLog( "IOATAStandardDriver::%s - Subclass must implement\n\r", __FUNCTION__ ); - return false; -} - - -/* - * - * - */ -bool IOATAStandardDriver::stopDma( IOATAStandardCommand *, UInt32 * ) -{ - IOLog( "IOATAStandardDriver::%s - Subclass must implement\n\r", __FUNCTION__ ); - return false; -} - -/* - * - * - */ -bool IOATAStandardDriver::checkDmaActive() -{ - IOLog( "IOATAStandardDriver::%s - Subclass must implement\n\r", __FUNCTION__ ); - return false; -} - -/* - * - * - */ -bool IOATAStandardDriver::resetDma() -{ - return false; -} - -/* - * - * - */ -bool IOATAStandardDriver::getProtocolsSupported( ATAProtocol *forProtocol ) -{ - *(UInt32 *) forProtocol = ( kATAProtocolSetRegs - | kATAProtocolPIO - | kATAProtocolDMA - | kATAProtocolDMAQueued - | kATAProtocolATAPIPIO - | kATAProtocolATAPIDMA ); - - return true; -} - -/* - * - * - */ -ATAReturnCode IOATAStandardDriver::waitForDRQ( UInt32 timeoutmS ) -{ - AbsoluteTime currentTime, endTime; - UInt32 status; - ATAReturnCode rc = kATAReturnBusyError; - - clock_interval_to_deadline( timeoutmS, 1000000, &endTime ); - do - { - status = readATAReg( kATARegStatus ); - if ( (status & kATAPIStatusBSY) == 0 ) - { - if ( (status & kATAStatusERR) != 0 ) - { - rc = kATAReturnStatusError; - break; - } - if ( (status & kATAStatusDRQ) != 0 ) - { - rc = kATAReturnSuccess; - break; - } - } - clock_get_uptime( ¤tTime ); - } - while ( CMP_ABSOLUTETIME( &endTime, ¤tTime ) > 0 ); - - if (rc == kATAReturnBusyError) - kprintf("IOATAStandardDriver::waitForDRQ is going to return kATAReturnBusyError;\n"); - - return rc; -} - - -/* - * - * - */ -bool IOATAStandardDriver::waitForStatus( UInt32 statusBitsOn, UInt32 statusBitsOff, UInt32 timeoutmS ) -{ - AbsoluteTime currentTime, endTime; - UInt32 status; - - clock_interval_to_deadline( timeoutmS, 1000000, &endTime ); - - do - { - status = readATAReg( kATARegStatus ); - - if ( (status & statusBitsOn) == statusBitsOn - && (status & statusBitsOff) == 0 ) - { - return true; - } - - clock_get_uptime( ¤tTime ); - - } while ( CMP_ABSOLUTETIME( &endTime, ¤tTime ) > 0 ); - - return false; -} - -/* - * - * - */ -bool IOATAStandardDriver::waitForAltStatus( UInt32 statusBitsOn, UInt32 statusBitsOff, UInt32 timeoutmS ) -{ - AbsoluteTime currentTime, endTime; - UInt32 status; - - clock_interval_to_deadline( timeoutmS, 1000000, &endTime ); - - do - { - status = readATAReg( kATARegAltStatus ); - - if ( (status & statusBitsOn) == statusBitsOn - && (status & statusBitsOff) == 0 ) - { - return true; - } - - clock_get_uptime( ¤tTime ); - - } while ( CMP_ABSOLUTETIME( &endTime, ¤tTime ) > 0 ); - - return false; -} - -/* - * - * - */ -bool IOATAStandardDriver::start (IOService *provider) -{ - - PMinit(); // initialize superclass variables - provider->joinPMtree(this); // attach into the power management hierarchy - - #define number_of_power_states 2 - - static IOPMPowerState ourPowerStates[number_of_power_states] = { - {1,0,0,0,0,0,0,0,0,0,0,0}, - {1,IOPMDeviceUsable,IOPMPowerOn,IOPMPowerOn,0,0,0,0,0,0,0,0} - }; - - - // register ourselves with ourself as policy-maker - if (pm_vars != NULL) - registerPowerDriver(this, ourPowerStates, number_of_power_states); - - - // We are starting up, so not waking up: - wakingUpFromSleep = false; - - if (!super::start (provider)) - return false; - - return true; -} - -/* - * - * - */ - -IOReturn IOATAStandardDriver::setPowerState(unsigned long powerStateOrdinal, IOService* whatDevice) -{ - // Do not do anything if the state is inavalid. - if (powerStateOrdinal >= 2) - return IOPMNoSuchState; - - if ( powerStateOrdinal == 0 ) - { - kprintf("IOATAStandardDriver would be powered off here\n"); - wakingUpFromSleep = true; - - // Let's pretend we did something: - return IOPMAckImplied; - } - - if ( ( powerStateOrdinal == 1 ) && ( wakingUpFromSleep ) ) - { - wakingUpFromSleep = false; - disableControllerInterrupts(); - reset(); - enableControllerInterrupts(); - return IOPMAckImplied; - } - - return IOPMCannotRaisePower; -} - diff --git a/iokit/Families/IOATAStandard/IOATAStandardDriverDma.cpp b/iokit/Families/IOATAStandard/IOATAStandardDriverDma.cpp deleted file mode 100644 index a7195b903..000000000 --- a/iokit/Families/IOATAStandard/IOATAStandardDriverDma.cpp +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * IOATAStandardDriverDma.cpp - * - */ -#include - -/*----------------------------------- ATA DMA Protocol ------------------------------*/ - -/* - * - * - */ -void IOATAStandardDriver::doATAProtocolDma( IOATAStandardCommand *cmd ) -{ - ATATaskfile taskfile; - UInt32 regmask; - UInt32 i; - - setCommandLimit( currentDevice, 1 ); - - cmd->getTaskfile( &taskfile ); - - regmask = taskfile.regmask; - - if ( regmask & ATARegtoMask(kATARegDriveHead) ) - { - regmask &= ~ATARegtoMask(kATARegDriveHead); - if ( selectDrive( taskfile.ataRegs[kATARegDriveHead] ) == false ) - { - completeCmd( cmd, kATAReturnBusyError ); - return; - } - } - - programDma( cmd ); - - for ( i = 0; regmask; i++ ) - { - if ( regmask & 1 ) - { - writeATAReg( i, taskfile.ataRegs[i] ); - } - regmask >>= 1; - } - - startDma( cmd ); -} - -/* - * - * - */ -void IOATAStandardDriver::processATADmaInt() -{ - UInt32 status; - UInt32 reqCount; - ATAReturnCode rc = kATAReturnSuccess; - IOATAStandardCommand *ataCmd; - UInt32 xferCount; - - ataCmd = findCommandWithNexus( currentDevice, (UInt32) -1 ); - if ( ataCmd == 0 ) - { - IOLog( "IOATAStandardDriver::processATADmaInt() - ATA Command not found\n\r" ); - return; - } - - if ( waitForStatus( 0, kATAStatusBSY, kATABusyTimeoutmS ) == false ) - { - stopDma( ataCmd, &xferCount ); - completeCmd( ataCmd, kATAReturnBusyError, xferCount ); - return; - } - - status = readATAReg( kATARegStatus ); - - ataCmd->getPointers( 0, &reqCount, 0 ); - - if ( stopDma( ataCmd, &xferCount ) != true ) - { - rc = kATAReturnDMAError; - } - - else if ( status & kATAStatusDRQ ) - { - rc = kATAReturnDMAError; - } - - else if ( status & kATAStatusERR ) - { - rc = kATAReturnStatusError; - } - - else if ( reqCount != xferCount ) - { - rc = kATAReturnProtocolError; - } - - completeCmd( ataCmd, rc, xferCount ); -} - -/*----------------------------------- ATA DMA Queued Protocol ------------------------------*/ - -/* - * - * - */ -void IOATAStandardDriver::doATAProtocolDmaQueued( IOATAStandardCommand *ataCmd ) -{ - ATATaskfile taskfile; - UInt32 regmask; - UInt32 i; - - if ( dmaActive == true ) - { - setCommandLimit( currentDevice, 0 ); - rescheduleCommand( ataCmd ); - return; - } - - setCommandLimit( currentDevice, 31 ); - - ataCmd->getTaskfile( &taskfile ); - - regmask = taskfile.regmask; - - regmask &= ~(ATARegtoMask(kATARegDriveHead) | ATARegtoMask(kATARegCommand)); - - if ( selectDrive( taskfile.ataRegs[kATARegDriveHead] ) == false ) - { - completeCmd( ataCmd, kATAReturnBusyError ); - return; - } - - programDma( ataCmd ); - dmaActive = true; - startDma( ataCmd ); - - taskfile.ataRegs[kATARegSectorCount] = taskfile.tag << 3; - - for ( i = 0; regmask; i++ ) - { - if ( regmask & 1 ) - { - writeATAReg( i, taskfile.ataRegs[i] ); - } - regmask >>= 1; - } - - writeATAReg( kATARegCommand, taskfile.ataRegs[kATARegCommand] ); - -#if 1 - IODelay( 1 ); - waitForAltStatus( 0, kATAStatusBSY, kATABusyTimeoutmS ); -#endif -} - -/* - * - * - */ -void IOATAStandardDriver::processATADmaQueuedInt() -{ - UInt32 status; - UInt32 intReason; - UInt32 tag; - UInt32 xferCount; - IOATAStandardCommand *ataCmd; - ATAReturnCode rc = kATAReturnSuccess; - - while ( 1 ) - { - status = readATAReg( kATARegStatus ); - intReason = readATAReg( kATARegSectorCount ); - tag = intReason / kATATagBit; - - ataCmd = findCommandWithNexus( currentDevice, tag ); - - if ( (intReason & kATAPIIntReasonCD) && (intReason & kATAPIIntReasonIO) && (dmaActive == true) ) - { - if ( ataCmd == 0 ) - { - IOLog( "IOATAStandardDriver::processATADmaQueuedInt() - ATA Command not found\n\r" ); - return; - } - - dmaActive = false; - - if ( stopDma( ataCmd, &xferCount ) != true ) - { - rc = kATAReturnDMAError; - } - - else if ( status & kATAStatusERR ) - { - rc = kATAReturnStatusError; - } - - completeCmd( ataCmd, rc, xferCount ); - } - - if ( (status & kATAStatusDRQ) != 0 ) - { - if ( ataCmd == 0 ) - { - IOLog( "IOATAStandardDriver::processATADmaQueuedInt() - ATA Command not found\n\r" ); - return; - } - - programDma( ataCmd ); - dmaActive = true; - startDma( ataCmd ); - break; - } - - if ( status & kATAStatusSERV ) - { - resetDma(); - - writeATAReg( kATARegCommand, kATACommandService ); - - if ( waitForAltStatus( 0, kATAStatusBSY, 500 ) == false ) - { - return; - } - continue; - } - - if ( dmaActive == false ) - { - setCommandLimit( currentDevice, 31 ); - } - break; - } - -} - -/*----------------------------------- ATAPI DMA Protocols ------------------------------*/ - -/* - * - * - * - */ -void IOATAStandardDriver::doATAPIProtocolDma( IOATAStandardCommand *ataCmd ) -{ - ATATaskfile taskfile; - ATACDBInfo atapiCmd; - ATAReturnCode rc; - UInt32 regmask; - UInt32 i; - - setCommandLimit( currentDevice, 1 ); - - ataCmd->getTaskfile( &taskfile ); - ataCmd->getCDB( &atapiCmd ); - - regmask = taskfile.regmask; - - if ( regmask & ATARegtoMask(kATARegDriveHead) ) - { - regmask &= ~ATARegtoMask(kATARegDriveHead); - if ( selectDrive( taskfile.ataRegs[kATARegDriveHead] ) == false ) - { - completeCmd( ataCmd, kATAReturnBusyError); - return; - } - } - - // Wait for BSY = 0 and DRQ = 0 before issuing a packet command. - - waitForStatus( 0, kATAStatusBSY | kATAStatusDRQ, kATABusyTimeoutmS ); - - for ( i = 0; regmask; i++ ) - { - if ( regmask & 1 ) - { - writeATAReg( i, taskfile.ataRegs[i] ); - } - regmask >>= 1; - } - - programDma( ataCmd ); - - if ( ataCmd->getDevice(kIOATAStandardDevice)->getATAPIPktInt() == false ) - { - rc = sendATAPIPacket( ataCmd ); - - if ( rc != kATAReturnSuccess ) - { - completeCmd( ataCmd, rc ); - return; - } - - startDma( ataCmd ); - } -} - - -/* - * - * - */ -void IOATAStandardDriver::processATAPIDmaInt() -{ - IOATAStandardCommand *ataCmd; - ATAReturnCode rc = kATAReturnProtocolError; - UInt32 status; - UInt32 intReason; - UInt32 xferCount; - - ataCmd = findCommandWithNexus( currentDevice, (UInt32) -1 ); - if ( ataCmd == 0 ) - { - IOLog( "IOATAStandardDriver::processATAPIDmaInt() - ATA Command not found\n\r" ); - return; - } - - if ( waitForStatus( 0, kATAStatusBSY, kATABusyTimeoutmS ) == false ) - { - completeCmd( ataCmd, kATAReturnBusyError, 0 ); - return; - } - - status = readATAReg( kATARegATAPIStatus ); - intReason = readATAReg( kATARegATAPIIntReason ); - - if ( (status & kATAPIStatusDRQ) && (intReason & kATAPIIntReasonCD) && !(intReason & kATAPIIntReasonIO) ) - { - rc = sendATAPIPacket( ataCmd ); - if ( rc != kATAReturnSuccess ) - { - completeCmd( ataCmd, rc ); - } - - else if ( startDma( ataCmd ) != true ) - { - rc = kATAReturnDMAError; - completeCmd( ataCmd, rc ); - } - } - - else if ( !(status & kATAPIStatusDRQ) && (intReason & kATAPIIntReasonCD) && (intReason & kATAPIIntReasonIO) ) - { - if ( stopDma( ataCmd, &xferCount ) != true ) - { - rc = kATAReturnDMAError; - xferCount = 0; - } - else - { - rc = (status & kATAPIStatusCHK) ? kATAReturnStatusError : kATAReturnSuccess; - } - - completeCmd( ataCmd, rc, xferCount ); - } - else - { - stopDma( ataCmd, &xferCount ); - completeCmd( ataCmd, rc, 0 ); - } -} - diff --git a/iokit/Families/IOATAStandard/IOATAStandardDriverPio.cpp b/iokit/Families/IOATAStandard/IOATAStandardDriverPio.cpp deleted file mode 100644 index 6f2c43c7d..000000000 --- a/iokit/Families/IOATAStandard/IOATAStandardDriverPio.cpp +++ /dev/null @@ -1,505 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * IOATAStandardDriverPio.cpp - * - */ -#include - -/*----------------------------------- ATA SetRegs Protocol ------------------------------*/ - -/* - * - * - */ -void IOATAStandardDriver::doProtocolSetRegs( IOATAStandardCommand *ataCmd ) -{ - ATATaskfile taskfile; - UInt32 regmask; - UInt32 i; - - setCommandLimit( currentDevice, 1 ); - - ataCmd->getTaskfile( &taskfile ); - - regmask = taskfile.regmask; - - if ( regmask & ATARegtoMask(kATARegDriveHead) ) - { - regmask &= ~ATARegtoMask(kATARegDriveHead); - if ( selectDrive( taskfile.ataRegs[kATARegDriveHead] ) == false ) - { - completeCmd( ataCmd, kATAReturnBusyError ); - return; - } - } - - for ( i = 0; regmask; i++ ) - { - if ( regmask & 1 ) - { - writeATAReg( i, taskfile.ataRegs[i] ); - } - regmask >>= 1; - } - - IODelay( 100 ); - - completeCmd( ataCmd, kATAReturnSuccess ); -} - -/*----------------------------------- ATA PIO Protocol ------------------------------*/ - -/* - * - * - */ -void IOATAStandardDriver::doATAProtocolPio( IOATAStandardCommand *ataCmd ) -{ - ATATaskfile taskfile; - ATAReturnCode rc; - UInt32 regmask; - UInt32 i; - - setCommandLimit( currentDevice, 1 ); - - ataCmd->getTaskfile( &taskfile ); - - regmask = taskfile.regmask; - - if ( regmask & ATARegtoMask(kATARegDriveHead) ) - { - regmask &= ~ATARegtoMask(kATARegDriveHead); - if ( selectDrive( taskfile.ataRegs[kATARegDriveHead] ) == false ) - { - completeCmd( ataCmd, kATAReturnBusyError ); - return; - } - } - - xferCount = 0; - ataCmd->getPointers( &xferDesc, &xferRemaining, &xferIsWrite ); - - for ( i = 0; regmask; i++ ) - { - if ( regmask & 1 ) - { - writeATAReg( i, taskfile.ataRegs[i] ); - } - regmask >>= 1; - } - - if ( xferIsWrite ) - { - rc = waitForDRQ( kATADRQTimeoutmS ); - if ( rc != kATAReturnSuccess ) - { - completeCmd( ataCmd, rc ); - return; - } - interruptOccurred(); - } -} - - -/* - * - * - */ -void IOATAStandardDriver::processATAPioInt() -{ - IOATAStandardCommand *ataCmd; - UInt16 tmpBuffer[256]; - UInt32 status; - UInt32 i; - ATAReturnCode rc = kATAReturnSuccess; - - ataCmd = findCommandWithNexus( currentDevice, (UInt32) -1 ); - if ( ataCmd == 0 ) - { - IOLog( "IOATAStandardDriver::processATAPioInt() - ATA Command not found\n\r" ); - return; - } - - if ( waitForStatus( 0, kATAStatusBSY, kATABusyTimeoutmS ) == false ) - { - completeCmd( ataCmd, kATAReturnBusyError, xferCount ); - return; - } - - status = readATAReg( kATARegStatus ); - - if ( (status & kATAStatusDRQ) && (xferRemaining != 0) ) - { - if ( xferIsWrite == true ) - { - xferDesc->readBytes( xferCount, tmpBuffer, 512 ); - - for ( i=0; i < 256; i++ ) - { - writeATAReg( kATARegData, tmpBuffer[i] ); - } - } - else - { - for ( i=0; i < 256; i++ ) - { - tmpBuffer[i] = readATAReg( kATARegData ); - } - xferDesc->writeBytes( xferCount, tmpBuffer, 512 ); - } - - xferCount += 512; - xferRemaining -= 512; - } - - if ( status & kATAStatusERR ) - { - completeCmd( ataCmd, kATAReturnStatusError, xferCount ); - } - else if ( !xferRemaining ) - { - completeCmd( ataCmd, rc, xferCount ); - } -} -/*----------------------------------- ATA Reset Protocol ------------------------------*/ - -/* - * - * - * - */ -void IOATAStandardDriver::doATAReset( IOATAStandardCommand *ataCmd ) -{ - - if ( resetCmd != 0 ) - { - completeCmd( ataCmd, kATAReturnNoResource ); - return; - } - - if ( resetPollEvent == 0 ) - { - resetPollEvent = IOTimerEventSource::timerEventSource( this, - (IOTimerEventSource::Action) &IOATAStandardDriver::checkATAResetComplete); - - if ( (resetPollEvent == 0) || (getWorkLoop()->addEventSource( resetPollEvent ) != kIOReturnSuccess) ) - { - completeCmd( ataCmd, kATAReturnNoResource ); - return; - } - } - - resetCmd = ataCmd; - - clock_interval_to_deadline( resetCmd->getTimeout(), 1000000, &resetTimeout ); - - writeATAReg( kATARegDeviceControl, kATADevControlnIEN | kATADevControlSRST ); - IODelay( 25 ); - writeATAReg( kATARegDeviceControl, 0 ); - - IOSleep(5); - - checkATAResetComplete(); - - return; -} - -/* - * - * - * - */ -void IOATAStandardDriver::checkATAResetComplete() -{ - UInt32 status; - IOATAStandardCommand *ataCmd; - AbsoluteTime currentTime; - ATAReturnCode rc = kATAReturnSuccess; - - do - { - status = readATAReg( kATARegStatus ); - - if ( (status & kATAStatusBSY) == 0 ) - { - break; - } - - clock_get_uptime( ¤tTime ); - if ( CMP_ABSOLUTETIME( ¤tTime, &resetTimeout ) > 0 ) - { - rc = kATAReturnBusyError; - break; - } - - resetPollEvent->setTimeoutMS(kATAResetPollIntervalmS); - return; - - } while ( 0 ); - - ataCmd = resetCmd; - resetCmd = 0; - - if ( ataCmd->getCmdType() != kATACommandBusReset ) - { - resetOccurred(); - } - - completeCmd( ataCmd, rc ); -} - - -/*----------------------------------- ATAPI PIO Protocols ------------------------------*/ - -/* - * - * - * - */ -void IOATAStandardDriver::doATAPIProtocolPio( IOATAStandardCommand *ataCmd ) -{ - ATATaskfile taskfile; - ATACDBInfo atapiCmd; - ATAReturnCode rc; - UInt32 regmask; - UInt32 i; - - setCommandLimit( currentDevice, 1 ); - - xferCount = 0; - - ataCmd->getTaskfile( &taskfile ); - ataCmd->getCDB( &atapiCmd ); - - regmask = taskfile.regmask; - - if ( regmask & ATARegtoMask(kATARegDriveHead) ) - { - regmask &= ~ATARegtoMask(kATARegDriveHead); - if ( selectDrive( taskfile.ataRegs[kATARegDriveHead] ) == false ) - { - completeCmd( ataCmd, kATAReturnBusyError ); - return; - } - } - - // Wait for BSY = 0 and DRQ = 0 before issuing a packet command. - - waitForStatus( 0, kATAStatusBSY | kATAStatusDRQ, kATABusyTimeoutmS ); - - for ( i = 0; regmask; i++ ) - { - if ( regmask & 1 ) - { - writeATAReg( i, taskfile.ataRegs[i] ); - } - regmask >>= 1; - } - - xferCount = 0; - ataCmd->getPointers( &xferDesc, &xferRemaining, &xferIsWrite ); - - if ( ataCmd->getDevice(kIOATAStandardDevice)->getATAPIPktInt() == false ) - { - rc = sendATAPIPacket( ataCmd ); - - if ( rc != kATAReturnSuccess ) - { - completeCmd( ataCmd, rc ); - return; - } - } -} - -/* - * - * - */ -void IOATAStandardDriver::processATAPIPioInt() -{ - IOATAStandardCommand *ataCmd; - ATAReturnCode rc = kATAReturnProtocolError; - UInt32 status; - UInt32 intReason; - UInt32 n; - - ataCmd = findCommandWithNexus( currentDevice, (UInt32) -1 ); - if ( ataCmd == 0 ) - { - IOLog( "IOATAStandardDriver::processATAPIPioInt() - ATA Command not found\n\r" ); - return; - } - - if ( waitForStatus( 0, kATAStatusBSY, kATABusyTimeoutmS ) == false ) - { - completeCmd( ataCmd, kATAReturnBusyError, xferCount ); - return; - } - - status = readATAReg( kATARegATAPIStatus ); - intReason = readATAReg( kATARegATAPIIntReason ); - - if ( status & kATAPIStatusDRQ ) - { - if ( intReason & kATAPIIntReasonCD ) - { - if ( !(intReason & kATAPIIntReasonIO) ) - { - rc = sendATAPIPacket( ataCmd ); - } - } - else - { - n = readATAReg( kATARegATAPIByteCountLow ) | (readATAReg( kATARegATAPIByteCountHigh ) << 8); - n = (n+1) & ~0x01; - - if ( !(intReason & kATAPIIntReasonIO) && (xferIsWrite == true) ) - { - rc = writeATAPIDevice( n ); - } - else if ( (intReason & kATAPIIntReasonIO) && (xferIsWrite == false) ) - { - rc = readATAPIDevice( n ); - } - } - } - else if ( (intReason & kATAPIIntReasonCD) && (intReason & kATAPIIntReasonIO) ) - { - rc = (status & kATAPIStatusCHK) ? kATAReturnStatusError : kATAReturnSuccess; - completeCmd( ataCmd, rc, xferCount ); - } -} - -/* - * - * - */ -ATAReturnCode IOATAStandardDriver::sendATAPIPacket( IOATAStandardCommand *ataCmd ) -{ - UInt32 i; - ATACDBInfo atapiCmd; - UInt16 *pCDB; - ATAReturnCode rc; - - ataCmd->getCDB( &atapiCmd ); - - rc = waitForDRQ( kATADRQTimeoutmS ); - if ( rc != kATAReturnSuccess ) return rc; - - pCDB = (UInt16 *)atapiCmd.cdb; - for ( i=0; i < atapiCmd.cdbLength >> 1; i++ ) - { - writeATAReg( kATARegData, *pCDB++ ); - } - - return rc; -} - - -/* - * - * - */ -ATAReturnCode IOATAStandardDriver::readATAPIDevice( UInt32 n ) -{ - UInt16 tmpBuffer[256]; - UInt32 i,j,k; - - while ( n ) - { - j = (n < 512) ? n : 512; - - j >>= 1; - for ( i=0; i < j; i++ ) - { - tmpBuffer[i] = readATAReg( kATARegData ); - } - j <<= 1; - n -= j; - - k = (j > xferRemaining ) ? xferRemaining : j; - - xferDesc->writeBytes( xferCount, tmpBuffer, k ); - - xferCount += k; - xferRemaining -= k; - } - - return kATAReturnSuccess; -} - -/* - * - * - */ -ATAReturnCode IOATAStandardDriver::writeATAPIDevice( UInt32 n ) -{ - UInt16 tmpBuffer[256]; - UInt32 i,j,k; - - - while ( n ) - { - j = (n < 512) ? n : 512; - - k = (j > xferRemaining ) ? xferRemaining : j; - - xferDesc->readBytes( xferCount, tmpBuffer, k ); - - j >>= 1; - for ( i=0; i < j; i++ ) - { - writeATAReg( kATARegData, tmpBuffer[i] ); - } - j <<= 1; - n -= j; - - xferCount += k; - xferRemaining -= k; - } - - return kATAReturnSuccess; -} - - -/* - * - * - */ -bool IOATAStandardDriver::selectDrive( UInt32 driveHeadReg ) -{ - if ( waitForAltStatus( 0, kATAStatusBSY, kATABusyTimeoutmS ) == false ) - { - return false; - } - - writeATAReg( kATARegDriveHead, driveHeadReg ); - - if ( waitForAltStatus( 0, kATAStatusBSY, kATABusyTimeoutmS ) == false ) - { - return false; - } - - return true; -} diff --git a/iokit/Families/IOSCSIParallel/IOSCSIParallelCommand.cpp b/iokit/Families/IOSCSIParallel/IOSCSIParallelCommand.cpp deleted file mode 100644 index 1a7d18c8c..000000000 --- a/iokit/Families/IOSCSIParallel/IOSCSIParallelCommand.cpp +++ /dev/null @@ -1,429 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * IOSCSIParallelCommand.cpp - * - */ - -#include -#include -#include - -#undef super -#define super IOSCSICommand - -OSDefineMetaClassAndStructors( IOSCSIParallelCommand, IOSCSICommand ) -OSDefineMetaClassAndAbstractStructors( IOSCSICommand, IOCDBCommand ) -OSDefineMetaClassAndAbstractStructors( IOCDBCommand, IOCommand ) - -static struct adapterReturnCodes -{ - SCSIAdapterStatus adapterStatus; - IOReturn ioReturnCode; -} -adapterReturnCodes[] = -{ - { kSCSIAdapterStatusSuccess, kIOReturnSuccess }, - { kSCSIAdapterStatusProtocolError, kIOReturnDeviceError }, - { kSCSIAdapterStatusSelectionTimeout, kIOReturnNotResponding }, - { kSCSIAdapterStatusMsgReject, kIOReturnUnsupported }, - { kSCSIAdapterStatusParityError, kIOReturnIOError }, - { kSCSIAdapterStatusOverrun, kIOReturnOverrun } -}; - -#define kNumAdapterReturnCodes (sizeof(adapterReturnCodes)/sizeof(adapterReturnCodes[0])) - -static struct statusReturnCodes -{ - UInt32 scsiStatus; - IOReturn ioReturnCode; -} -statusReturnCodes[] = -{ - { kSCSIStatusGood, kIOReturnSuccess }, - { kSCSIStatusCheckCondition, kIOReturnIOError }, - { kSCSIStatusConditionMet, kIOReturnSuccess }, - { kSCSIStatusBusy, kIOReturnBusy }, - { kSCSIStatusIntermediate, kIOReturnSuccess }, - { kSCSIStatusIntermediateMet, kIOReturnSuccess }, - { kSCSIStatusReservationConfict, kIOReturnAborted }, - { kSCSIStatusCommandTerminated, kIOReturnAborted }, - { kSCSIStatusQueueFull, kIOReturnIOError } -}; - -#define kNumStatusReturnCodes (sizeof(statusReturnCodes)/sizeof(statusReturnCodes[0])) - - -IOSCSIDevice *IOSCSIParallelCommand::getDevice(IOSCSIDevice *) -{ - return (IOSCSIDevice *)getDevice(kIOSCSIParallelDevice); -} - -IOSCSIParallelDevice *IOSCSIParallelCommand::getDevice(IOSCSIParallelDevice *) -{ - return device; -} - - -void *IOSCSIParallelCommand::getClientData() -{ - return clientData; -} - -void *IOSCSIParallelCommand::getCommandData() -{ - return commandPrivateData; -} - -UInt32 IOSCSIParallelCommand::getCmdType() -{ - return cmdType; -} - -IOSCSIParallelCommand *IOSCSIParallelCommand::getOriginalCmd() -{ - return origCommand; -} - -UInt32 IOSCSIParallelCommand::getSequenceNumber() -{ - return sequenceNumber; -} - -void IOSCSIParallelCommand::getTargetLun( SCSITargetLun *forTargetLun ) -{ - if ( device ) - { - *forTargetLun = device->targetLun; - } - else - { - bzero( forTargetLun, sizeof( SCSITargetLun ) ); - } -} - - - -void IOSCSIParallelCommand::setTimeout( UInt32 timeoutMS ) -{ - timeout = timeoutMS; -} - -UInt32 IOSCSIParallelCommand::getTimeout() -{ - return timeout; -} - -void IOSCSIParallelCommand::setResults( SCSIResults *srcResults ) -{ - setResults( srcResults, (SCSINegotiationResults *)0 ); -} - -void IOSCSIParallelCommand::setResults( SCSIResults *srcResults, SCSINegotiationResults *negotiationResult ) -{ - SCSICommandType cmdType; - - if ( srcResults != 0 ) - { - results = *srcResults; - - cmdType = (SCSICommandType) getCmdType(); - - while ( results.returnCode == kIOReturnSuccess ) - { - switch ( cmdType ) - { - case kSCSICommandExecute: - case kSCSICommandReqSense: - case kSCSICommandAbort: - case kSCSICommandAbortAll: - case kSCSICommandDeviceReset: - if ( results.adapterStatus != kSCSIAdapterStatusSuccess ) - { - results.returnCode = adapterStatusToIOReturnCode( results.adapterStatus ); - } - break; - - default: - ; - } - - if ( results.returnCode != kIOReturnSuccess ) break; - - switch ( cmdType ) - { - case kSCSICommandExecute: - case kSCSICommandReqSense: - results.returnCode = scsiStatusToIOReturnCode( results.scsiStatus ); - - if ( results.returnCode != kIOReturnSuccess ) break; - - if ( results.bytesTransferred < xferCount ) - { - results.returnCode = kIOReturnUnderrun; - } - break; - - default: - ; - } - - break; - } - } - - if ( negotiationResult != 0 ) - { - device->target->negotiationResult = *negotiationResult; - } -} - -IOReturn IOSCSIParallelCommand::adapterStatusToIOReturnCode( SCSIAdapterStatus adapterStatus ) -{ - UInt32 i; - - for ( i=0; i < kNumAdapterReturnCodes; i++ ) - { - if ( adapterReturnCodes[i].adapterStatus == adapterStatus ) - { - return adapterReturnCodes[i].ioReturnCode; - } - } - return kIOReturnError; -} - -IOReturn IOSCSIParallelCommand::scsiStatusToIOReturnCode( UInt8 scsiStatus ) -{ - UInt32 i; - - for ( i=0; i < kNumStatusReturnCodes; i++ ) - { - if ( statusReturnCodes[i].scsiStatus == scsiStatus ) - { - return statusReturnCodes[i].ioReturnCode; - } - } - return kIOReturnError; -} - -IOReturn IOSCSIParallelCommand::getResults( SCSIResults *dstResults ) -{ - if ( dstResults != 0 ) - { - *dstResults = results; - } - - return results.returnCode; -} - -void IOSCSIParallelCommand::setQueueInfo( UInt32 forQueueType, UInt32 forQueuePosition ) -{ - queueType = forQueueType; - queuePosition = forQueuePosition; -} - -void IOSCSIParallelCommand::getQueueInfo( UInt32 *forQueueType, UInt32 *forQueuePosition = 0 ) -{ - if ( forQueueType != 0 ) *forQueueType = queueType; - if ( forQueuePosition != 0 ) *forQueuePosition = queuePosition; -} - -void IOSCSIParallelCommand::setPointers( IOMemoryDescriptor *clientDesc, UInt32 transferCount, bool isWrite, bool isSense = false ) -{ - if ( isSense == false ) - { - xferDesc = clientDesc; - xferCount = transferCount; - xferDirection = isWrite; - } - else - { - senseData = clientDesc; - senseLength = transferCount; - } -} - -void IOSCSIParallelCommand::getPointers( IOMemoryDescriptor **clientDesc, UInt32 *transferCount, bool *isWrite, bool isSense = false ) -{ - if ( clientDesc != NULL ) - { - *clientDesc = (isSense == false) ? xferDesc : senseData; - } - - if ( transferCount != NULL ) - { - *transferCount = (isSense == false) ? xferCount : senseLength; - } - - if ( isWrite != NULL ) - { - *isWrite = (isSense == false) ? xferDirection : false; - } -} - -void IOSCSIParallelCommand::setCDB( SCSICDBInfo *clientSCSICmd ) -{ - scsiCmd = *clientSCSICmd; -} - -void IOSCSIParallelCommand::getCDB( SCSICDBInfo *clientSCSICmd ) -{ - *clientSCSICmd = scsiCmd; -} - -void IOSCSIParallelCommand::setCallback( void *clientTarget, CallbackFn clientSCSIDoneFn, void *clientRefcon ) -{ - completionInfo.async.target = clientTarget; - completionInfo.async.callback = clientSCSIDoneFn; - completionInfo.async.refcon = clientRefcon; -} - -bool IOSCSIParallelCommand::execute( UInt32 *cmdSequenceNumber ) -{ - bool isSync; - - do - { - sequenceNumber = OSIncrementAtomic( (SInt32 *)&controller->sequenceNumber ); - } - while ( sequenceNumber == 0 ); - - if ( cmdSequenceNumber != 0 ) - { - *cmdSequenceNumber = sequenceNumber; - } - - list = (queue_head_t *)device->deviceGate; - - isSync = (completionInfo.async.callback == 0); - - if ( isSync ) - { - completionInfo.sync.lock = IOSyncer::create(); - } - - device->submitCommand( kSCSICommandExecute, this ); - - if ( isSync ) - { - completionInfo.sync.lock->wait(); - } - - return true; - -} - -void IOSCSIParallelCommand::abort( UInt32 sequenceNumber ) -{ - device->submitCommand( kSCSICommandAbort, this, sequenceNumber ); -} - -void IOSCSIParallelCommand::complete() -{ - if ( device ) - { - device->completeCommand( this ); - } - else - { - controller->completeCommand( this ); - } -} - -/*------------------- Generic CDB Interface -----------------------------------------------*/ - -void IOSCSIParallelCommand::getCDB( CDBInfo *cdbInfo ) -{ - SCSICDBInfo scsiCDBInfo; - - bzero( cdbInfo, sizeof(CDBInfo) ); - - getCDB( &scsiCDBInfo ); - cdbInfo->cdb = scsiCDBInfo.cdb; - cdbInfo->cdbLength = scsiCDBInfo.cdbLength; -} - -void IOSCSIParallelCommand::setCDB( CDBInfo *cdbInfo ) -{ - SCSICDBInfo scsiCDBInfo; - - bzero( &scsiCDBInfo, sizeof(SCSICDBInfo) ); - - scsiCDBInfo.cdbLength = cdbInfo->cdbLength; - scsiCDBInfo.cdb = cdbInfo->cdb; - setCDB( &scsiCDBInfo ); -} - -IOReturn IOSCSIParallelCommand::getResults( CDBResults *cdbResults ) -{ - SCSIResults scsiResults; - IOReturn rc; - - rc = getResults( &scsiResults ); - - if ( cdbResults != 0 ) - { - bzero( cdbResults, sizeof(CDBResults) ); - - cdbResults->returnCode = scsiResults.returnCode; - cdbResults->bytesTransferred = scsiResults.bytesTransferred; - cdbResults->requestSenseDone = scsiResults.requestSenseDone; - cdbResults->requestSenseLength = scsiResults.requestSenseLength; - } - - return rc; -} - - -IOCDBDevice *IOSCSIParallelCommand::getDevice( IOCDBDevice * ) -{ - return (IOCDBDevice *)device; -} - - -void IOSCSIParallelCommand::zeroCommand() -{ - cmdType = kSCSICommandNone; -// controller = ; -// device = ; - list = 0; - bzero(&nextCommand, sizeof(nextCommand)); - bzero(&scsiCmd, sizeof(scsiCmd)); - bzero(&results, sizeof(results)); - timeout = 0; - timer = 0; - queueType = 0; - queuePosition = 0; - xferDesc = 0; - xferCount = 0; - xferDirection = 0; - senseLength = 0; - senseData = 0; - origCommand = 0; - bzero(&completionInfo, sizeof(completionInfo)); -// if (dataArea && dataSize) -// bzero( dataArea, dataSize ); -// commandPrivateData = ; -// clientData = ; - sequenceNumber = 0; -} diff --git a/iokit/Families/IOSCSIParallel/IOSCSIParallelController.cpp b/iokit/Families/IOSCSIParallel/IOSCSIParallelController.cpp deleted file mode 100644 index a2b386386..000000000 --- a/iokit/Families/IOSCSIParallel/IOSCSIParallelController.cpp +++ /dev/null @@ -1,1079 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * IOSCSIParallelController.cpp - * - */ - -#include -#include - -#undef super -#define super IOService - -OSDefineMetaClass( IOSCSIParallelController, IOService ) -OSDefineAbstractStructors( IOSCSIParallelController, IOService ); - -#define round(x,y) (((int)(x) + (y) - 1) & ~((y)-1)) - -/* - * - * - */ -bool IOSCSIParallelController::start( IOService *forProvider ) -{ - provider = forProvider; - - if ( provider->open( this ) != true ) - { - return false; - } - - if ( createWorkLoop() != true ) - { - return false; - } - - if ( configureController() == false ) - { - provider->close( this ); - return false; - } - - initQueues(); - - if ( scanSCSIBus() == false ) - { - provider->close( this ); - return false; - } - - return true; -} - -/* - * - * - * - */ -bool IOSCSIParallelController::scanSCSIBus() -{ - SCSITargetLun targetLun; - UInt32 i; - - targetLun.lun = 0; - - for ( i=0; i < controllerInfo.maxTargetsSupported; i++ ) - { - targetLun.target = i; - probeTarget( targetLun ); - } - - return true; -} - -/* - * - * - * - */ -bool IOSCSIParallelController::probeTarget( SCSITargetLun targetLun ) -{ - IOSCSIParallelDevice *device; - UInt32 i; - - if ( targetLun.target == controllerInfo.initiatorId ) - { - return false; - } - - if ( initTarget( targetLun ) == false ) - { - releaseTarget( targetLun ); - return false; - } - - for ( i=0; i < controllerInfo.maxLunsSupported; i++ ) - { - targetLun.lun = i; - - device = createDevice(); - if ( device == 0 ) - { - break; - } - - if ( device->init( this, targetLun ) == false ) - { - releaseDevice( device ); - break; - } - - if ( initDevice( device ) == false ) - { - releaseDevice( device ); - continue; - } - - if ( device->probeTargetLun() != kIOReturnSuccess ) - { - releaseDevice( device ); - if ( i == 0 ) break; - } - } - - if ( i == 0 ) - { - releaseTarget( targetLun ); - return false; - } - - queue_iterate( &targets[targetLun.target].deviceList, device, IOSCSIParallelDevice *, nextDevice ) - { - device->setupTarget(); - device->attach( this ); - device->registerService(); - } - - return true; -} - -/* - * - * - * - */ -bool IOSCSIParallelController::initTargetGated( SCSITargetLun *targetLun ) -{ - return initTarget( *targetLun ); -} - -bool IOSCSIParallelController::initTarget( SCSITargetLun targetLun ) -{ - SCSITarget *target; - UInt32 number; - - if ( getWorkLoop()->inGate() == false ) - { - return controllerGate->runAction( (IOCommandGate::Action)&IOSCSIParallelController::initTargetGated, (void *)&targetLun ); - } - - target = &targets[targetLun.target]; - - target->clientSem = IORWLockAlloc(); - target->targetSem = IORWLockAlloc(); - if( (target->targetSem == 0) || (target->clientSem == 0)) - { - return false; - } - target->commandLimitSave = target->commandLimit = 1; - - target->targetParmsCurrent.transferWidth = 1; - - if ( controllerInfo.targetPrivateDataSize != 0 ) - { - target->targetPrivateData = IOMallocContiguous( controllerInfo.targetPrivateDataSize, 16, 0 ); - if ( target->targetPrivateData == 0 ) - { - return false; - } - } - - if ( controllerInfo.tagAllocationMethod == kTagAllocationPerTarget ) - { - target->tagArray = (UInt32 *)IOMalloc( tagArraySize ); - if ( target->tagArray == 0 ) - { - return false; - } - bzero( target->tagArray, tagArraySize ); - } - - number = 0; - target->regObjTransferPeriod = OSNumber::withNumber( number, 32 ); - if ( target->regObjTransferPeriod == 0 ) - { - return false; - } - - number = 0; - target->regObjTransferOffset = OSNumber::withNumber( number, 32 ); - if ( target->regObjTransferOffset == 0 ) - { - return false; - } - - number = 1; - target->regObjTransferWidth = OSNumber::withNumber( number, 32 ); - if ( target->regObjTransferWidth == 0 ) - { - return false; - } - - number = 0; - target->regObjTransferOptions = OSNumber::withNumber( number, 32 ); - if ( target->regObjTransferOptions == 0 ) - { - return false; - } - - number = 0; - target->regObjCmdQueue = OSNumber::withNumber( number, 32 ); - if ( target->regObjCmdQueue == 0 ) - { - return false; - } - - target->targetAllocated = allocateTarget( targetLun ); - - return target->targetAllocated; -} - -/* - * - * - * - */ -void IOSCSIParallelController::releaseTargetGated( SCSITargetLun *targetLun ) -{ - releaseTarget( *targetLun ); -} - -void IOSCSIParallelController::releaseTarget( SCSITargetLun targetLun ) -{ - SCSITarget *target; - - if ( getWorkLoop()->inGate() == false ) - { - controllerGate->runAction( (IOCommandGate::Action)&IOSCSIParallelController::releaseTargetGated, (void *)&targetLun ); - return; - } - - target = &targets[targetLun.target]; - - if ( queue_empty( &target->deviceList ) != true ) - { - IOLog("IOSCSIParallelController()::Target %d deleted with lun(s) active!\n\r", - targetLun.target ); - } - - if ( target->targetAllocated == true ) - { - deallocateTarget( targetLun ); - - target->targetAllocated = false; - } - - if ( target->tagArray != 0 ) - { - IOFree( target->tagArray, tagArraySize ); - target->tagArray = 0; - } - - if ( target->targetPrivateData != 0 ) - { - IOFreeContiguous( target->targetPrivateData, controllerInfo.targetPrivateDataSize ); - target->targetPrivateData = 0; - } - - if ( target->clientSem != 0 ) - { - IORWLockFree( target->clientSem ); - } - if ( target->targetSem != 0 ) - { - IORWLockFree( target->targetSem ); - } - - if ( target->regObjTransferPeriod != 0 ) - { - target->regObjTransferPeriod->release(); - target->regObjTransferPeriod = 0; - } - if ( target->regObjTransferOffset != 0 ) - { - target->regObjTransferOffset->release(); - target->regObjTransferOffset = 0; - } - if ( target->regObjTransferWidth != 0 ) - { - target->regObjTransferWidth->release(); - target->regObjTransferWidth = 0; - } - if ( target->regObjCmdQueue != 0 ) - { - target->regObjCmdQueue->release(); - target->regObjCmdQueue = 0; - } - -} - -/* - * - * - * - */ -bool IOSCSIParallelController::initDeviceGated( IOSCSIParallelDevice *device ) -{ - return initDevice( device ); -} - -bool IOSCSIParallelController::initDevice( IOSCSIParallelDevice *device ) -{ - if ( getWorkLoop()->inGate() == false ) - { - return controllerGate->runAction( (IOCommandGate::Action)&IOSCSIParallelController::initDeviceGated, (void *)device ); - } - - addDevice( device ); - device->lunAllocated = allocateLun( device->targetLun ); - - return device->lunAllocated; -} - -/* - * - * - * - */ -void IOSCSIParallelController::releaseDeviceGated( IOSCSIParallelDevice *device ) -{ - releaseDevice( device ); - return; -} - -void IOSCSIParallelController::releaseDevice( IOSCSIParallelDevice *device ) -{ - if ( getWorkLoop()->inGate() == false ) - { - controllerGate->runAction( (IOCommandGate::Action)&IOSCSIParallelController::releaseDeviceGated, (void *)device ); - return; - } - - deleteDevice( device ); - if ( device->lunAllocated == true ) - { - deallocateLun( device->targetLun ); - } - - device->release(); -} - - -/* - * - * - * - */ -void IOSCSIParallelController::addDevice( IOSCSIParallelDevice *forDevice ) -{ - UInt32 targetID; - - targetID = forDevice->targetLun.target; - - forDevice->target = &targets[targetID]; - queue_enter( &targets[targetID].deviceList, forDevice, IOSCSIParallelDevice *, nextDevice ); -} - -/* - * - * - * - */ -void IOSCSIParallelController::deleteDevice( IOSCSIParallelDevice *forDevice ) -{ - queue_head_t *deviceList; - IOSCSIParallelDevice *device; - UInt32 targetID; - - targetID = forDevice->targetLun.target; - - deviceList = &targets[targetID].deviceList; - - queue_iterate( deviceList, device, IOSCSIParallelDevice *, nextDevice ) - { - if ( device == forDevice ) - { - queue_remove( &targets[targetID].deviceList, device, IOSCSIParallelDevice *, nextDevice ); - break; - } - } -} - -/* - * - * - * - */ -bool IOSCSIParallelController::allocateTarget( SCSITargetLun targetLun ) -{ - return true; -} - -/* - * - * - * - */ -void IOSCSIParallelController::deallocateTarget( SCSITargetLun targetLun ) -{ -} - -/* - * - * - * - */ -bool IOSCSIParallelController::allocateLun( SCSITargetLun targetLun ) -{ - return true; -} - -/* - * - * - * - */ -void IOSCSIParallelController::deallocateLun( SCSITargetLun targetLun ) -{ -} - - -/* - * - * - * - */ -void *IOSCSIParallelController::getTargetData( SCSITargetLun targetLun ) -{ - return targets[targetLun.target].targetPrivateData; -} - -/* - * - * - * - */ -void *IOSCSIParallelController::getLunData( SCSITargetLun targetLun ) -{ - queue_head_t *deviceList; - IOSCSIParallelDevice *device; - - deviceList = &targets[targetLun.target].deviceList; - - queue_iterate( deviceList, device, IOSCSIParallelDevice *, nextDevice ) - { - if ( device->targetLun.lun == targetLun.lun ) - { - return device->devicePrivateData; - } - } - return 0; -} - - - -/* - * - * - * - */ -IOSCSIParallelDevice *IOSCSIParallelController::createDevice() -{ - return new IOSCSIParallelDevice; -} - - -/* - * - * - * - */ -void IOSCSIParallelController::initQueues() -{ - UInt32 i; - - for ( i=0; i < controllerInfo.maxTargetsSupported; i++ ) - { - queue_init( &targets[i].deviceList ); - } - - resetCmd = allocCommand( 0 ); - resetCmd->cmdType = kSCSICommandBusReset; - - timer( timerEvent ); -} - -/* - * - * - * - */ -void IOSCSIParallelController::reset() -{ - IOSCSIParallelDevice *device; - UInt32 i; - - if ( busResetState != kStateIssue ) - { - return; - } - - busResetState = kStateActive; - - for (i=0; i < controllerInfo.maxTargetsSupported; i++ ) - { - queue_iterate( &targets[i].deviceList, device, IOSCSIParallelDevice *, nextDevice ) - { - if ( device->client != 0 ) - { - device->client->message( kSCSIClientMsgBusReset, device ); - } - } - } - - resetCommand( resetCmd ); -} - -/* - * - * - * - */ -bool IOSCSIParallelController::checkBusReset() -{ - if ( busResetState == kStateIdle ) - { - return false; - } - if ( busResetState == kStateIssue ) - { - reset(); - } - return true; -} - - -/* - * - * - * - */ -void IOSCSIParallelController::resetOccurred() -{ - UInt32 i; - IOSCSIParallelDevice *device; - SCSITarget *target; - SCSIClientMessage clientMsg; - - for (i=0; i < controllerInfo.maxTargetsSupported; i++ ) - { - target = &targets[i]; - - target->commandLimit = target->commandLimitSave; - target->reqSenseCount = 0; - target->reqSenseState = kStateIdle; - target->negotiateState = kStateIssue; - - target->targetParmsCurrent.transferPeriodpS = 0; - target->targetParmsCurrent.transferOffset = 0; - target->targetParmsCurrent.transferWidth = 1; - - noDisconnectCmd = 0; - - clientMsg = ( busResetState != kStateActive ) ? kSCSIClientMsgBusReset : kSCSIClientMsgNone; - - queue_iterate( &target->deviceList, device, IOSCSIParallelDevice *, nextDevice ) - { - device->resetOccurred( clientMsg ); - } - } - - resetTimer = (kSCSIResetIntervalmS / kSCSITimerIntervalmS + 1); -} - - -/* - * - * - */ -void IOSCSIParallelController::timer( IOTimerEventSource * /* timer */ ) -{ - UInt32 i; - IOSCSIParallelDevice *device; - - - if ( disableTimer ) - { - if ( !--disableTimer ) - { - disableTimeoutOccurred(); - } - } - - if ( resetTimer ) - { - if ( !--resetTimer ) - { - for (i=0; i < controllerInfo.maxTargetsSupported; i++ ) - { - queue_iterate( &targets[i].deviceList, device, IOSCSIParallelDevice *, nextDevice ) - { - device->resetComplete(); - } - } - - } - } - else - { - for (i=0; i < controllerInfo.maxTargetsSupported; i++ ) - { - queue_iterate( &targets[i].deviceList, device, IOSCSIParallelDevice *, nextDevice ) - { - device->timer(); - } - } - } - - timerEvent->setTimeoutMS(kSCSITimerIntervalmS); -} - - -/* - * - * - * - */ -void IOSCSIParallelController::completeCommand( IOSCSIParallelCommand *scsiCmd ) -{ - switch ( scsiCmd->cmdType ) - { - case kSCSICommandBusReset: - resetOccurred(); - busResetState = kStateIdle; - break; - default: - ; - } -} - - -/* - * - * - * - */ -bool IOSCSIParallelController::createWorkLoop() -{ - workLoop = getWorkLoop(); - if ( workLoop == 0 ) - { - workLoop = IOWorkLoop::workLoop(); - if ( workLoop == 0 ) - { - return false; - } - } - - timerEvent = IOTimerEventSource::timerEventSource( this, (IOTimerEventSource::Action) &IOSCSIParallelController::timer ); - if ( timerEvent == 0 ) - { - return false; - } - - if ( workLoop->addEventSource( timerEvent ) != kIOReturnSuccess ) - { - return false; - } - - - dispatchEvent = IOInterruptEventSource::interruptEventSource( this, - (IOInterruptEventAction) &IOSCSIParallelController::dispatch, - 0 ); - if ( dispatchEvent == 0 ) - { - return false; - } - - if ( workLoop->addEventSource( dispatchEvent ) != kIOReturnSuccess ) - { - return false; - } - - controllerGate = IOCommandGate::commandGate( this, (IOCommandGate::Action) 0 ); - if ( controllerGate == 0 ) - { - return false; - } - - if ( workLoop->addEventSource( controllerGate ) != kIOReturnSuccess ) - { - return false; - } - - return true; -} - -/* - * - * - * - */ -IOSCSIParallelCommand *IOSCSIParallelController::findCommandWithNexus( SCSITargetLun targetLun, UInt32 tagValue = (UInt32)-1 ) -{ - IOSCSIParallelDevice *device; - - device = findDeviceWithTargetLun( targetLun ); - if ( device == 0 ) - { - return 0; - } - - return device->findCommandWithNexus( tagValue ); -} - - -/* - * - * - * - */ -IOSCSIParallelDevice *IOSCSIParallelController::findDeviceWithTargetLun( SCSITargetLun targetLun ) -{ - IOSCSIParallelDevice *device; - - if ( targetLun.target > controllerInfo.maxTargetsSupported || targetLun.lun > controllerInfo.maxLunsSupported ) - { - return 0; - } - - queue_iterate( &targets[targetLun.target].deviceList, device, IOSCSIParallelDevice *, nextDevice ) - { - if ( device->targetLun.lun == targetLun.lun ) - { - return device; - } - } - return 0; -} - - -/* - * - * - * - */ -bool IOSCSIParallelController::configureController() -{ - UInt32 targetsSize; - - if ( configure( provider, &controllerInfo ) == false ) - { - return false; - } - - controllerInfo.commandPrivateDataSize = round( controllerInfo.commandPrivateDataSize, 16 ); - - if ( controllerInfo.maxCommandsPerController == 0 ) controllerInfo.maxCommandsPerController = (UInt32) -1; - if ( controllerInfo.maxCommandsPerTarget == 0 ) controllerInfo.maxCommandsPerTarget = (UInt32) -1; - if ( controllerInfo.maxCommandsPerLun == 0 ) controllerInfo.maxCommandsPerLun = (UInt32) -1; - - targetsSize = controllerInfo.maxTargetsSupported * sizeof(SCSITarget); - targets = (SCSITarget *)IOMalloc( targetsSize ); - bzero( targets, targetsSize ); - - commandLimit = commandLimitSave = controllerInfo.maxCommandsPerController; - - tagArraySize = (controllerInfo.maxTags / 32 + ((controllerInfo.maxTags % 32) ? 1 : 0)) * sizeof(UInt32); - - if ( controllerInfo.tagAllocationMethod == kTagAllocationPerController ) - { - tagArray = (UInt32 *)IOMalloc( tagArraySize ); - bzero( tagArray, tagArraySize ); - } - - return true; -} - -/* - * - * - * - */ -void IOSCSIParallelController::setCommandLimit( UInt32 newCommandLimit ) -{ - if ( newCommandLimit == 0 ) controllerInfo.maxCommandsPerController = (UInt32) -1; - - commandLimit = commandLimitSave = controllerInfo.maxCommandsPerController; -} - -/* - * - * - * - */ -IOWorkLoop *IOSCSIParallelController::getWorkLoop() const -{ - return workLoop; -} - -/* - * - * - * - */ -void IOSCSIParallelController::disableCommands( UInt32 disableTimeoutmS ) -{ - commandDisable = true; - - disableTimer = ( disableTimeoutmS != 0 ) ? (disableTimeoutmS / kSCSITimerIntervalmS + 1) : 0; -} - - -/* - * - * - * - */ -void IOSCSIParallelController::disableCommands() -{ - UInt32 disableTimeout; - - commandDisable = true; - - disableTimeout = kSCSIDisableTimeoutmS; - - if ( noDisconnectCmd != 0 ) - { - disableTimeout = noDisconnectCmd->getTimeout(); - if ( disableTimeout != 0 ) disableTimeout += kSCSIDisableTimeoutmS; - } - - disableTimer = ( disableTimeout != 0 ) ? (disableTimeout / kSCSITimerIntervalmS + 1) : 0; -} - -/* - * - * - * - */ -void IOSCSIParallelController::disableTimeoutOccurred() -{ - busResetState = kStateIssue; - dispatchRequest(); -} - -/* - * - * - * - */ -void IOSCSIParallelController::rescheduleCommand( IOSCSIParallelCommand *forSCSICmd ) -{ - forSCSICmd->getDevice(kIOSCSIParallelDevice)->rescheduleCommand( forSCSICmd ); -} - -/* - * - * - * - */ -void IOSCSIParallelController::enableCommands() -{ - commandDisable = false; - - disableTimer = 0; - - dispatchRequest(); -} - -/* - * - * - * - */ -void IOSCSIParallelController::dispatchRequest() -{ - dispatchEvent->interruptOccurred(0, 0, 0); -} - - -/* - * - * - * - */ -void IOSCSIParallelController::dispatch() -{ - SCSITarget *target; - IOSCSIParallelDevice *device; - UInt32 dispatchAction; - UInt32 lunsActive = 0; - UInt32 i; - - if ( !targets || checkBusReset() ) - { - goto dispatch_Exit; - } - - for ( i = 0; i < controllerInfo.maxTargetsSupported; i++ ) - { - target = &targets[i]; - - if ( target->state == kStateActive ) - { - lunsActive = 0; - - queue_iterate( &target->deviceList, device, IOSCSIParallelDevice *, nextDevice ) - { - if ( device->dispatch( &dispatchAction ) == true ) - { - lunsActive++; - } - - switch ( dispatchAction ) - { - case kDispatchNextLun: - ; - case kDispatchNextTarget: - break; - case kDispatchStop: - goto dispatch_Exit; - } - } - if ( lunsActive == 0 ) - { - target->state = kStateIdle; - } - } - } - -dispatch_Exit: - ; -} - -/* - * - * - * - */ -IOSCSIParallelCommand *IOSCSIParallelController::allocCommand(UInt32 clientDataSize ) -{ - IOSCSIParallelCommand *cmd; - UInt32 size; - - size = controllerInfo.commandPrivateDataSize + round(clientDataSize, 16); - - cmd = new IOSCSIParallelCommand; - if ( !cmd ) - { - return 0; - } - cmd->init(); - - if ( size ) - { - cmd->dataArea = (void *)IOMallocContiguous( (vm_size_t)size, 16, 0 ); - if ( !cmd->dataArea ) - { - cmd->release(); - return 0; - } - - bzero( cmd->dataArea, size ); - - cmd->dataSize = size; - - if ( controllerInfo.commandPrivateDataSize ) - { - cmd->commandPrivateData = cmd->dataArea; - } - if ( clientDataSize ) - { - cmd->clientData = (void *)((UInt8 *)cmd->dataArea + controllerInfo.commandPrivateDataSize); - } - } - - cmd->controller = this; - - return cmd; -} - -/* - * - * - * - */ -void IOSCSIParallelController::free() -{ - UInt32 targetsSize; - UInt32 i; - - if ( controllerGate != 0 ) - { - workLoop->removeEventSource( controllerGate ); - controllerGate->release(); - } - - if ( timerEvent != 0 ) timerEvent->release(); - - if ( dispatchEvent != 0 ) dispatchEvent->release(); - - if ( resetCmd != 0 ) resetCmd->release(); - - if ( workLoop != 0 ) workLoop->release(); - - if ( targets != 0 ) - { - for ( i=0; i < controllerInfo.maxTargetsSupported; i++ ) - { - if ( targets[i].targetPrivateData != 0 ) - { - IOFreeContiguous( targets[i].targetPrivateData, controllerInfo.targetPrivateDataSize ); - } - } - - targetsSize = controllerInfo.maxTargetsSupported * sizeof(SCSITarget); - IOFree( targets, targetsSize ); - } - - if ( tagArray != 0 ) IOFree( tagArray, tagArraySize ); - - super::free(); -} - -/* - * - * - * - */ -void IOSCSIParallelCommand::free() -{ - if ( dataArea ) - { - IOFreeContiguous( dataArea, dataSize ); - } - - OSObject::free(); -} - diff --git a/iokit/Families/IOSCSIParallel/IOSCSIParallelDevice.cpp b/iokit/Families/IOSCSIParallel/IOSCSIParallelDevice.cpp deleted file mode 100644 index dc8c2593c..000000000 --- a/iokit/Families/IOSCSIParallel/IOSCSIParallelDevice.cpp +++ /dev/null @@ -1,2164 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * IOSCSIParallelDevice.cpp - * - */ - -#include -#include - -#include -#include - -#undef super -#define super IOSCSIDevice - -#ifndef MIN -#define MIN(a,b) ((a <= b) ? a : b) -#endif - -OSDefineMetaClassAndAbstractStructors( IOCDBDevice, IOService ) -OSDefineMetaClassAndAbstractStructors( IOSCSIDevice, IOCDBDevice ) -OSDefineMetaClassAndStructors( IOSCSIParallelDevice, IOSCSIDevice ) - -/* - * - * - * - */ -bool IOSCSIParallelDevice::init( IOSCSIParallelController *forController, SCSITargetLun forTargetLun ) -{ - SCSICDBInfo scsiCDB; - - controller = forController; - targetLun = forTargetLun; - - target = &controller->targets[targetLun.target]; - - queue_init( &deviceList ); - queue_init( &bypassList ); - queue_init( &activeList ); - queue_init( &abortList ); - queue_init( &cancelList ); - - clientSem = IORWLockAlloc(); - if ( clientSem == 0 ) - { - return false; - } - - if ( super::init() == false ) - { - return false; - } - - if ( controller->controllerInfo.lunPrivateDataSize != 0 ) - { - devicePrivateData = IOMallocContiguous( controller->controllerInfo.lunPrivateDataSize, 16, 0 ); - if ( devicePrivateData == 0 ) - { - return false; - } - } - - bzero( &scsiCDB, sizeof(scsiCDB) ); - - abortCmd = allocCommand(kIOSCSIParallelDevice, 0); - if ( abortCmd == 0 ) - { - return false; - } - abortCmd->setTimeout( kSCSIAbortTimeoutmS ); - - cancelCmd = allocCommand(kIOSCSIParallelDevice, 0); - if ( cancelCmd == 0 ) - { - return false; - } - cancelCmd->setTimeout( 0 ); - cancelCmd->cmdType = kSCSICommandCancel; - - reqSenseCmd = allocCommand(kIOSCSIParallelDevice, 0); - if ( reqSenseCmd == 0 ) - { - return false; - } - scsiCDB.cdbLength = 6; - scsiCDB.cdb[0] = kSCSICmdRequestSense; - scsiCDB.cdb[1] = targetLun.lun << 4; - scsiCDB.cdbTag = (UInt32) -1; - - reqSenseCmd->setTimeout( kSCSIReqSenseTimeoutmS ); - reqSenseCmd->cmdType = kSCSICommandReqSense; - reqSenseCmd->setCDB( &scsiCDB ); - - if ( controller->controllerInfo.tagAllocationMethod == kTagAllocationPerLun ) - { - tagArray = (UInt32 *)IOMalloc( controller->tagArraySize ); - bzero( tagArray, controller->tagArraySize ); - } - - deviceGate = IOCommandGate::commandGate( this, (IOCommandGate::Action) &IOSCSIParallelDevice::receiveCommand ); - if ( deviceGate == 0 ) - { - return false; - } - - if ( controller->workLoop->addEventSource( deviceGate ) != kIOReturnSuccess ) - { - return false; - } - - commandLimitSave = commandLimit = controller->controllerInfo.maxCommandsPerLun; - - idleNotifyActive = false; - - normalQHeld = false; - bypassQHeld = false; - - return true; -} - -/* - * - * - * - */ -IOReturn IOSCSIParallelDevice::probeTargetLun() -{ - SCSICDBInfo cdb; - SCSIResults result; - IOReturn rc; - IOMemoryDescriptor *desc = 0; - SCSIInquiry *inqData = 0; - UInt32 size = 0; - OSDictionary *propTable; - - probeCmd = allocCommand(kIOSCSIParallelDevice, 0); - - if ( probeCmd == 0 ) - { - rc = kIOReturnNoMemory; - goto probeError; - } - - size = sizeof(SCSIInquiry); - - if ( !(inqData = (SCSIInquiry *)IOMalloc(size)) ) - { - rc = kIOReturnNoMemory; - goto probeError; - } - - desc = IOMemoryDescriptor::withAddress( (void *)inqData, size, kIODirectionIn ); - if ( desc == 0 ) - { - rc = kIOReturnNoMemory; - goto probeError; - } - - if ( open( this ) == false ) - { - rc = kIOReturnError; - goto probeError; - } - - bzero( (void *)&cdb, sizeof(cdb) ); - - cdb.cdbLength = 6; - cdb.cdb[0] = kSCSICmdInquiry; - cdb.cdb[4] = size; - probeCmd->setCDB( &cdb ); - - probeCmd->setPointers( desc, size, false ); - - probeCmd->setTimeout( kSCSIProbeTimeoutmS ); - probeCmd->setCallback(); - - probeCmd->execute(); - - rc = probeCmd->getResults( &result ); - - switch ( rc ) - { - case kIOReturnSuccess: - break; - - case kIOReturnUnderrun: - rc = kIOReturnSuccess; - break; - - default: - goto probeError; - } - - if ( result.bytesTransferred <= (UInt32)(&inqData->flags - &inqData->devType) ) - { - rc = kIOReturnDeviceError; - goto probeError; - } - - switch ( inqData->devType & kSCSIDevTypeQualifierMask ) - { - case kSCSIDevTypeQualifierConnected: - case kSCSIDevTypeQualifierNotConnected: - break; - case kSCSIDevTypeQualifierReserved: - case kSCSIDevTypeQualifierMissing: - rc = kIOReturnNotAttached; - break; - default: - break; - } - - if ( rc != kIOReturnSuccess ) - { - goto probeError; - } - - inquiryData = inqData; - inquiryDataSize = result.bytesTransferred; - - propTable = createProperties(); - if ( !propTable ) goto probeError; - - setPropertyTable( propTable ); - - propTable->release(); - -probeError: ; - - if ( desc ) - { - desc->release(); - } - - if ( inqData ) - { - if ( rc != kIOReturnSuccess ) - { - IOFree( inqData, size ); - } - } - - return rc; -} - -/* - * - * - * - */ -void IOSCSIParallelDevice::setupTarget() -{ - SCSITargetParms targetParms; - UInt32 transferWidth; - - if ( targetLun.lun != 0 ) - { - close( this ); - return; - } - - getTargetParms( &targetParms ); - - if ( ((inquiryData->flags & kSCSIDevCapCmdQue) != 0) && (checkCmdQueEnabled() == true) ) - { - targetParms.enableTagQueuing = true; - } - - if ( inquiryData->flags & kSCSIDevCapSync ) - { - targetParms.transferPeriodpS = controller->controllerInfo.minTransferPeriodpS; - targetParms.transferOffset = controller->controllerInfo.maxTransferOffset; - } - - if ( inquiryData->flags & kSCSIDevCapWBus32 ) - { - transferWidth = 4; - } - else if ( inquiryData->flags & kSCSIDevCapWBus16 ) - { - transferWidth = 2; - } - else - { - transferWidth = 1; - } - - targetParms.transferWidth = MIN( transferWidth, controller->controllerInfo.maxTransferWidth ); - - if ( ((inquiryData->version & 0x07) >= kSCSIInqVersionSCSI3) - && (inquiryDataSize > (UInt32)(&inquiryData->scsi3Options - &inquiryData->devType)) ) - { - if ( inquiryData->scsi3Options & kSCSI3InqOptionClockDT ) - { - targetParms.transferOptions |= kSCSITransferOptionClockDT; - - /* If it's a SCSI-3 target that handles DT clocking, - * assume the HBA can try using the PPR message. - */ - targetParms.transferOptions |= kSCSITransferOptionPPR; - - if ( inquiryData->scsi3Options & kSCSI3InqOptionIUS ) - { - targetParms.transferOptions |= kSCSITransferOptionIUS; - - if ( inquiryData->scsi3Options & kSCSI3InqOptionQAS ) - { - targetParms.transferOptions |= kSCSITransferOptionQAS; - } - } - } - } - - setTargetParms( &targetParms ); - - close( this ); -} - -/* - * - * - * - */ -bool IOSCSIParallelDevice::checkCmdQueEnabled() -{ - SCSICDBInfo scsiCDB; - SCSIResults scsiResult; - IOMemoryDescriptor *desc; - UInt32 size; - UInt8 controlModePage[32]; - IOReturn cmdRc; - bool rc = false; - - bzero( (void *)&scsiCDB, sizeof(scsiCDB) ); - - size = sizeof(controlModePage); - - scsiCDB.cdbLength = 6; - scsiCDB.cdb[0] = kSCSICmdModeSense6; - scsiCDB.cdb[1] = 0x08; - scsiCDB.cdb[2] = 0x0a; // Control Mode Page - scsiCDB.cdb[4] = size; - - probeCmd->setCDB( &scsiCDB ); - - desc = IOMemoryDescriptor::withAddress( (void *)controlModePage, size, kIODirectionIn ); - if ( desc == 0 ) - { - return rc; - } - - probeCmd->setPointers( desc, size, false ); - - probeCmd->setTimeout( kSCSIProbeTimeoutmS ); - probeCmd->setCallback(); - - probeCmd->execute(); - - cmdRc = probeCmd->getResults( &scsiResult ); - - if ( (cmdRc == kIOReturnUnderrun) && (scsiResult.bytesTransferred > 7) ) - { - cmdRc = kIOReturnSuccess; - } - - /* Check DQue bit on ControlMode Page (0x0A) */ - if ( (cmdRc == kIOReturnSuccess) && ((controlModePage[7] & 0x01) == 0) ) - { - rc = true; - } - - desc->release(); - - return rc; -} - -/* - * - * - * - */ -void IOSCSIParallelDevice::getInquiryData( void *clientBuf, UInt32 clientBufSize, UInt32 *clientDataSize ) -{ - UInt32 len; - - bzero( clientBuf, clientBufSize ); - - len = MIN( clientBufSize, inquiryDataSize ); - - bcopy( inquiryData, clientBuf, len ); - - *clientDataSize = len; -} - -/* - * - * - * - */ -void IOSCSIParallelDevice::abort() -{ - submitCommand( kSCSICommandAbortAll, 0 ); -} - -/* - * - * - * - */ -void IOSCSIParallelDevice::reset() -{ - submitCommand( kSCSICommandDeviceReset, 0 ); -} - -/* - * - * - * - */ -void IOSCSIParallelDevice::holdQueue( UInt32 queueType ) -{ - if ( getWorkLoop()->inGate() == false ) - { - IOPanic( "IOSCSIParallelDevice::holdQueue() - must be called from workloop!!\n\r"); - } - - if ( queueType == kQTypeBypassQ ) - { - bypassQHeld = true; - } - else if ( queueType == kQTypeNormalQ ) - { - normalQHeld = true; - } -} - -/* - * - * - * - */ -void IOSCSIParallelDevice::releaseQueue( UInt32 queueType ) -{ - if ( getWorkLoop()->inGate() == false ) - { - IOPanic( "IOSCSIParallelDevice::releaseQueue() - must be called from workloop!!\n\r"); - } - - if ( queueType == kQTypeBypassQ ) - { - bypassQHeld = false; - } - else if ( queueType == kQTypeNormalQ ) - { - normalQHeld = false; - } - - dispatchRequest(); -} - -/* - * - * - * - */ -void IOSCSIParallelDevice::notifyIdle( void *target = 0, CallbackFn callback = 0, void *refcon = 0 ) -{ - if ( getWorkLoop()->inGate() == false ) - { - IOPanic( "IOSCSIParallelDevice:::notifyIdle() - must be called from workloop!!\n\r"); - } - - if ( callback == 0 ) - { - idleNotifyActive = false; - return; - } - - if ( idleNotifyActive == true ) - { - IOPanic( "IOSCSIParallelDevice:::notifyIdle() - only one idle notify may be active\n\r"); - } - - idleNotifyActive = true; - idleNotifyTarget = target; - idleNotifyCallback = callback; - idleNotifyRefcon = refcon; - - checkIdleNotify(); -} - - -/* - * - * - * - */ -void IOSCSIParallelDevice::submitCommand( UInt32 cmdType, IOSCSIParallelCommand *scsiCmd, UInt32 cmdSequenceNumber ) -{ - deviceGate->runCommand( (void *)cmdType, (void *)scsiCmd, (void *) cmdSequenceNumber, (void *) 0 ); -} - -/* - * - * - * - */ -void IOSCSIParallelDevice::receiveCommand( UInt32 cmdType, IOSCSIParallelCommand *scsiCmd, UInt32 cmdSequenceNumber, void *p3 ) -{ - queue_head_t *queue; - - switch ( cmdType ) - { - case kSCSICommandExecute: - scsiCmd->cmdType = (SCSICommandType) cmdType; - - scsiCmd->scsiCmd.cdbFlags &= (kCDBFNoDisconnect); - - queue = (scsiCmd->queueType == kQTypeBypassQ) ? &bypassList : &deviceList; - - if ( scsiCmd->queuePosition == kQPositionHead ) - { - stackCommand( queue, scsiCmd ); - } - else - { - addCommand( queue, scsiCmd ); - } - - dispatchRequest(); - break; - - case kSCSICommandAbortAll: - abortAllCommands( kSCSICommandAbortAll ); - break; - - case kSCSICommandAbort: - abortCommand( scsiCmd, cmdSequenceNumber ); - break; - - case kSCSICommandDeviceReset: - abortAllCommands( kSCSICommandDeviceReset ); - break; - - default: - /* ??? */ - break; - } -} - -/* - * - * - * - */ -void IOSCSIParallelDevice::abortCommand( IOSCSIParallelCommand *scsiCmd, UInt32 sequenceNumber ) -{ - if ( scsiCmd->list == (queue_head_t *)deviceGate ) - { - if ( scsiCmd->sequenceNumber != sequenceNumber ) - { - return; - } - scsiCmd->results.returnCode = kIOReturnAborted; - } - else if ( scsiCmd->list == &deviceList ) - { - if ( scsiCmd->sequenceNumber != sequenceNumber ) - { - return; - } - - deleteCommand( &deviceList, scsiCmd ); - scsiCmd->results.returnCode = kIOReturnAborted; - finishCommand( scsiCmd ); - } - else if ( scsiCmd->list == &activeList ) - { - if ( scsiCmd->sequenceNumber != sequenceNumber ) - { - return; - } - - moveCommand( &activeList, &abortList, scsiCmd ); - - dispatchRequest(); - } -} - - -/* - * - * - * - */ -void IOSCSIParallelDevice::abortAllCommands( SCSICommandType cmdType ) -{ - IOSCSIParallelDevice *abortDev; - - abortCmdPending = cmdType; - - if ( abortCmdPending == kSCSICommandAbortAll ) - { - if ( client != 0 ) - { - client->message( kSCSIClientMsgDeviceAbort, this ); - } - } - else if ( abortCmdPending == kSCSICommandDeviceReset ) - { - queue_iterate( &target->deviceList, abortDev, IOSCSIParallelDevice *, nextDevice ) - { - if ( abortDev->client != 0 ) - { - abortDev->client->message( kSCSIClientMsgDeviceReset, abortDev ); - } - } - } - - dispatchRequest(); -} - -/* - * - * - * - */ -void IOSCSIParallelDevice::resetOccurred( SCSIClientMessage clientMsg ) -{ - if ( client != 0 && clientMsg != kSCSIClientMsgNone ) - { - client->message( clientMsg, this ); - } - - moveAllCommands( &activeList, &cancelList, kIOReturnAborted ); - moveAllCommands( &abortList, &cancelList, kIOReturnAborted ); - - abortState = kStateIdle; - reqSenseState = kStateIdle; - commandLimit = commandLimitSave; - negotiateState = kStateIdle; - - dispatchRequest(); -} - -void IOSCSIParallelDevice::resetComplete() -{ - if ( client != 0 ) - { - client->message( kSCSIClientMsgBusReset | kSCSIClientMsgDone, this ); - } -} - - -/* - * - * - * - */ -bool IOSCSIParallelDevice::checkAbortQueue() -{ - IOSCSIParallelCommand *origCmd; - - if ( abortState == kStateActive ) - { - return true; - } - - if ( abortCmdPending != kSCSICommandNone ) - { - abortCmd->origCommand = 0; - - abortCmd->scsiCmd.cdbTagMsg = 0; - abortCmd->scsiCmd.cdbTag = (UInt32) -1; - - - abortCmd->cmdType = abortCmdPending; - abortCmd->scsiCmd.cdbAbortMsg = (abortCmdPending == kSCSICommandAbortAll) - ? kSCSIMsgAbort : kSCSIMsgBusDeviceReset; - - if ( disableDisconnect == true ) - { - abortCmd->scsiCmd.cdbFlags |= kCDBFlagsNoDisconnect; - } - else - { - abortCmd->scsiCmd.cdbFlags &= ~kCDBFlagsNoDisconnect; - } - - - abortCmd->timer = ( abortCmd->timeout != 0 ) ? - abortCmd->timeout / kSCSITimerIntervalmS + 1 : 0; - - bzero( &abortCmd->results, sizeof(SCSIResults) ); - - abortCmdPending = kSCSICommandNone; - abortState = kStateActive; - - addCommand( &activeList, abortCmd ); - controller->executeCommand( abortCmd ); - } - else if ( queue_empty( &abortList ) == false ) - { - origCmd = (IOSCSIParallelCommand *)queue_first( &abortList ); - abortCmd->origCommand = origCmd; - - abortCmd->cmdType = kSCSICommandAbort; - abortCmd->scsiCmd.cdbTagMsg = origCmd->scsiCmd.cdbTagMsg; - abortCmd->scsiCmd.cdbTag = origCmd->scsiCmd.cdbTag; - abortCmd->scsiCmd.cdbAbortMsg = (abortCmd->scsiCmd.cdbTagMsg != 0) - ? kSCSIMsgAbortTag : kSCSIMsgAbort; - - abortCmd->timer = ( abortCmd->timeout != 0 ) ? - abortCmd->timeout / kSCSITimerIntervalmS + 1 : 0; - - bzero( &abortCmd->results, sizeof(SCSIResults) ); - - abortState = kStateActive; - - addCommand( &activeList, abortCmd ); - controller->executeCommand( abortCmd ); - } - else - { - return false; - } - - return true; -} - -/* - * - * - * - */ -void IOSCSIParallelDevice::checkCancelQueue() -{ - if ( cancelState != kStateIdle ) - { - return; - } - - if ( queue_empty( &cancelList ) == true ) - { - return; - } - - if ( controller->controllerInfo.disableCancelCommands == true ) - { - return; - } - - cancelCmd->origCommand = (IOSCSIParallelCommand *)queue_first( &cancelList ); - bzero( &cancelCmd->results, sizeof(SCSIResults) ); - - cancelState = kStateActive; - controller->cancelCommand( cancelCmd ); -} - -/* - * - * - * - */ -bool IOSCSIParallelDevice::checkReqSense() -{ - IOMemoryDescriptor *senseData; - UInt32 senseLength; - SCSITargetParms *tpCur; - - if ( target->reqSenseState == kStateActive ) - { - return true; - } - - if ( reqSenseState == kStateIssue ) - { - reqSenseCmd->origCommand = reqSenseOrigCmd; - bzero( &reqSenseCmd->results, sizeof(SCSIResults) ); - - reqSenseOrigCmd->getPointers( &senseData, &senseLength, 0, true ); - reqSenseCmd->setPointers( senseData, senseLength, false ); - - reqSenseCmd->scsiCmd.cdbFlags = 0; - - if ( disableDisconnect == true ) - { - reqSenseCmd->scsiCmd.cdbFlags |= kCDBFlagsNoDisconnect; - } - else - { - reqSenseCmd->scsiCmd.cdbFlags &= ~kCDBFlagsNoDisconnect; - } - - tpCur = &target->targetParmsCurrent; - - if ( tpCur->transferWidth > 1 ) - { - reqSenseCmd->scsiCmd.cdbFlags |= kCDBFlagsNegotiateWDTR; - if (tpCur->transferOptions & kSCSITransferOptionPPR) { - reqSenseCmd->scsiCmd.cdbFlags |= kCDBFlagsNegotiatePPR; - } - } - - if ( tpCur->transferOffset != 0 ) - { - reqSenseCmd->scsiCmd.cdbFlags |= kCDBFlagsNegotiateSDTR; - if (tpCur->transferOptions & kSCSITransferOptionPPR) { - reqSenseCmd->scsiCmd.cdbFlags |= kCDBFlagsNegotiatePPR; - } - - } - - reqSenseCmd->timer = ( reqSenseCmd->timeout != 0 ) ? - reqSenseCmd->timeout / kSCSITimerIntervalmS + 1 : 0; - - reqSenseCmd->scsiCmd.cdb[3] = (senseLength >> 8) & 0xff; - reqSenseCmd->scsiCmd.cdb[4] = senseLength & 0xff; - - reqSenseState = kStatePending; - } - - if ( reqSenseState == kStatePending ) - { - target->reqSenseState = reqSenseState = kStateActive; - - addCommand( &activeList, reqSenseCmd ); - - commandCount++; - controller->commandCount++; - - controller->executeCommand( reqSenseCmd ); - } - - return (target->reqSenseCount > 0); -} - - -/* - * - * - * - */ -bool IOSCSIParallelDevice::checkDeviceQueue( UInt32 *dispatchAction ) -{ - IOSCSIParallelCommand *scsiCmd = 0; - queue_head_t *queue; - UInt32 i; - bool rc = true; - bool queueHeld; - - do - { - if ( controller->commandCount >= controller->commandLimit ) - { - *dispatchAction = kDispatchStop; - break; - } - - if ( target->commandCount >= target->commandLimit ) - { - *dispatchAction = kDispatchNextTarget; - break; - } - - *dispatchAction = kDispatchNextLun; - - if ( commandCount >= commandLimit ) - { - break; - } - - for ( i=0; i < 2; i++ ) - { - queueHeld = (i == 0) ? bypassQHeld : normalQHeld; - queue = (i == 0) ? &bypassList : &deviceList; - - if ( queueHeld == true ) - { - continue; - } - - scsiCmd = checkCommand( queue ); - if ( scsiCmd != 0 ) - { - *dispatchAction = kDispatchNextCommand; - break; - } - } - - if ( i == 2 ) - { - rc = false; - break; - } - - if ( disableDisconnect == true || (scsiCmd->scsiCmd.cdbFlags & kCDBFNoDisconnect) ) - { - scsiCmd->scsiCmd.cdbFlags |= kCDBFlagsNoDisconnect; - - if ( controller->commandCount != 0 ) - { - *dispatchAction = kDispatchNextLun; - break; - } - - controller->noDisconnectCmd = scsiCmd; - controller->commandLimitSave = controller->commandLimit; - controller->commandLimit = 1; - } - - else if ( checkTag( scsiCmd ) == false ) - { - switch ( controller->controllerInfo.tagAllocationMethod ) - { - case kTagAllocationPerTarget: - *dispatchAction = kDispatchNextTarget; - break; - case kTagAllocationPerController: - *dispatchAction = kDispatchStop; - break; - case kTagAllocationPerLun: - ; - default: - *dispatchAction = kDispatchNextLun; - } - break; - } - - getCommand( queue ); - - checkNegotiate( scsiCmd ); - - scsiCmd->timer = ( scsiCmd->timeout != 0 ) ? scsiCmd->timeout / kSCSITimerIntervalmS + 1 : 0; - - commandCount++; - target->commandCount++; - controller->commandCount++; - - addCommand( &activeList, scsiCmd ); - - controller->executeCommand( scsiCmd ); - - } while ( 0 ); - - return rc; -} - -/* - * - * - * - */ -void IOSCSIParallelDevice::rescheduleCommand( IOSCSIParallelCommand *scsiCmd ) -{ - if ( scsiCmd->list != &activeList ) - { - IOLog( "IOSCSIParallelController::rescheduleCommand() - Command not active. Cmd = %08x\n\r", (int)scsiCmd ); - return; - } - - deleteCommand( &activeList, scsiCmd ); - - switch ( scsiCmd->cmdType ) - { - case kSCSICommandExecute: - if ( scsiCmd->scsiCmd.cdbTagMsg != 0 ) - { - freeTag( scsiCmd->scsiCmd.cdbTag ); - scsiCmd->scsiCmd.cdbTag = (UInt32) -1; - } - - stackCommand( &deviceList, scsiCmd ); - - if ( scsiCmd->scsiCmd.cdbFlags & kCDBFlagsNoDisconnect ) - { - controller->commandLimit = controller->commandLimitSave; - controller->noDisconnectCmd = 0; - } - - controller->commandCount--; - target->commandCount--; - commandCount--; - break; - - case kSCSICommandReqSense: - reqSenseState = kStatePending; - target->reqSenseState = kStateIdle; - commandCount--; - controller->commandCount--; - break; - - case kSCSICommandAbortAll: - case kSCSICommandDeviceReset: - abortCmdPending = scsiCmd->cmdType; - - case kSCSICommandAbort: - abortState = kStateIdle; - break; - - default: - ; - } - - dispatchRequest(); - -} - -/* - * - * - * - */ -bool IOSCSIParallelDevice::setTargetParms( SCSITargetParms *targetParms ) -{ - IOSCSIParallelCommand *scsiCmd; - SCSICDBInfo scsiCDB; - bool fTagEnable; - bool rc = true; - - IOMemoryDescriptor *senseDesc; - UInt8 senseBuffer[14]; - - - if ( getWorkLoop()->inGate() == true ) - { - IOPanic( "IOSCSIParallelDevice:::setTargetParms() - must not be called from workloop!!\n\r"); - } - - IOWriteLock( target->clientSem ); - IOWriteLock( target->targetSem ); - - while ( target->negotiateState == kStateActive ) - { - IOSleep( 100 ); - } - - target->targetParmsNew = *targetParms; - - if ( targetParms->transferPeriodpS < controller->controllerInfo.minTransferPeriodpS ) - { - target->targetParmsNew.transferPeriodpS = controller->controllerInfo.minTransferPeriodpS; - } - - if ( target->targetParmsNew.transferPeriodpS == 0 - || target->targetParmsNew.transferOffset == 0 - || controller->controllerInfo.minTransferPeriodpS == 0 ) - { - target->targetParmsNew.transferPeriodpS = 0; - target->targetParmsNew.transferOffset = 0; - } - - target->commandLimit = 1; - - fTagEnable = (targetParms->enableTagQueuing == true) - && (controller->controllerInfo.tagAllocationMethod != kTagAllocationNone) - && (controller->controllerInfo.maxTags != 0); - - regObjCmdQueue->setValue( (UInt32)fTagEnable ); - - if ( fTagEnable == true ) - { - target->commandLimitSave = controller->controllerInfo.maxCommandsPerTarget; - } - else - { - target->commandLimitSave = 1; - target->targetParmsNew.enableTagQueuing = false; - } - - scsiCmd = allocCommand(kIOSCSIParallelDevice, 0); - - bzero( &scsiCDB, sizeof( SCSICDBInfo ) ); - - scsiCDB.cdbLength = 6; - scsiCDB.cdb[0] = kSCSICmdTestUnitReady; - scsiCDB.cdb[1] = targetLun.lun << 4; - scsiCmd->setCDB( &scsiCDB ); - - senseDesc = IOMemoryDescriptor::withAddress(senseBuffer, sizeof(senseBuffer), kIODirectionIn); - if ( senseDesc == 0 ) return false; - scsiCmd->setPointers( senseDesc, sizeof(senseBuffer), false, true ); - - target->negotiateState = kStateIssue; - - scsiCmd->execute(); - - IOWriteLock( target->targetSem ); - IORWUnlock( target->targetSem ); - - scsiCmd->release(); - senseDesc->release(); - - rc = (target->negotiationResult.returnCode == kIOReturnSuccess); - - IORWUnlock( target->clientSem ); - - return rc; -} - -/* - * - * - * - */ -void IOSCSIParallelDevice::getTargetParms( SCSITargetParms *targetParms ) -{ - *targetParms = target->targetParmsCurrent; -} - -/* - * - * - * - */ -bool IOSCSIParallelDevice::setLunParms( SCSILunParms *lunParms ) -{ - IOSCSIParallelCommand *scsiCmd; - SCSICDBInfo scsiCDB; - - IOMemoryDescriptor *senseDesc; - UInt8 senseBuffer[14]; - - if ( getWorkLoop()->inGate() == true ) - { - IOPanic( "IOSCSIParallelDevice:::setLunParms() - must not be called from workloop!!\n\r"); - } - - IOWriteLock( clientSem ); - - lunParmsNew = *lunParms; - commandLimitSave = commandLimit; - commandLimit = 1; - - scsiCmd = allocCommand(kIOSCSIParallelDevice, 0); - - bzero( &scsiCDB, sizeof( SCSICDBInfo ) ); - - scsiCDB.cdbLength = 6; - scsiCDB.cdb[0] = kSCSICmdTestUnitReady; - scsiCDB.cdb[1] = targetLun.lun << 4; - scsiCmd->setCDB( &scsiCDB ); - - senseDesc = IOMemoryDescriptor::withAddress(senseBuffer, sizeof(senseBuffer), kIODirectionIn); - if ( senseDesc == 0 ) return false; - scsiCmd->setPointers( senseDesc, sizeof(senseBuffer), false, true ); - - negotiateState = kStateIssue; - - scsiCmd->execute(); - - scsiCmd->release(); - senseDesc->release(); - - while ( negotiateState != kStateIdle ) - { - IOSleep( 100 ); - } - - IORWUnlock( clientSem ); - - return true; -} - -/* - * - * - * - */ -void IOSCSIParallelDevice::getLunParms( SCSILunParms *lunParms ) -{ - lunParms->disableDisconnect = disableDisconnect; -} - -/* - * - * - * - */ -void IOSCSIParallelDevice::checkNegotiate( IOSCSIParallelCommand *scsiCmd ) -{ - SCSITargetParms *tpCur, *tpNew; - - if ( target->negotiateState == kStateIssue ) - { - if ( target->commandCount == 0 ) - { - target->negotiateState = kStateActive; - - tpNew = &target->targetParmsNew; - tpCur = &target->targetParmsCurrent; - - target->negotiationResult.returnCode = kIOReturnError; - - if ((tpCur->transferPeriodpS != tpNew->transferPeriodpS) || - (tpCur->transferOffset != tpNew->transferOffset) || - ((tpCur->transferOptions ^ tpNew->transferOptions) & kSCSITransferOptionsSCSI3) ) - { - scsiCmd->scsiCmd.cdbFlags |= kCDBFlagsNegotiateSDTR; - - if (tpNew->transferOptions & kSCSITransferOptionPPR) { - scsiCmd->scsiCmd.cdbFlags |= kCDBFlagsNegotiatePPR; - } - } - - if ( tpCur->transferWidth != tpNew->transferWidth ) - { - scsiCmd->scsiCmd.cdbFlags |= kCDBFlagsNegotiateWDTR; - } - - if ( tpCur->enableTagQueuing != tpNew->enableTagQueuing ) - { - scsiCmd->scsiCmd.cdbFlags |= kCDBFlagsEnableTagQueuing; - } - - if ( (scsiCmd->scsiCmd.cdbFlags & - (kCDBFlagsNegotiateSDTR | - kCDBFlagsNegotiateWDTR | - kCDBFlagsNegotiatePPR | - kCDBFlagsEnableTagQueuing)) == 0 ) - { - IORWUnlock( target->targetSem ); - target->negotiateState = kStateIdle; - target->commandLimit = target->commandLimitSave; - } - - *tpCur = *tpNew; - } - } - - if ( negotiateState == kStateIssue ) - { - if ( commandCount == 0 ) - { - disableDisconnect = lunParmsNew.disableDisconnect; - negotiateState = kStateIdle; - } - } -} - -/* - * - * - * - */ -void IOSCSIParallelDevice::negotiationComplete() -{ - SCSITargetParms *tpCur, *tpNew; - - tpNew = &target->targetParmsNew; - tpCur = &target->targetParmsCurrent; - - if ( target->negotiationResult.returnCode == kIOReturnSuccess ) - { - tpCur->transferPeriodpS = tpNew->transferPeriodpS = target->negotiationResult.transferPeriodpS; - tpCur->transferOffset = tpNew->transferOffset = target->negotiationResult.transferOffset; - tpCur->transferWidth = tpNew->transferWidth = target->negotiationResult.transferWidth; - tpCur->transferOptions = tpNew->transferOptions = target->negotiationResult.transferOptions; - - target->commandLimit = target->commandLimitSave; - } - else - { - tpNew->transferPeriodpS = 0; - tpNew->transferOffset = 0; - tpNew->transferWidth = 1; - } - - target->regObjTransferPeriod->setValue( tpNew->transferPeriodpS ); - target->regObjTransferOffset->setValue( tpNew->transferOffset ); - target->regObjTransferWidth->setValue( tpNew->transferWidth ); - target->regObjTransferOptions->setValue( tpNew->transferOptions ); - - target->negotiateState = kStateIdle; -} - -/* - * - * - * - */ -bool IOSCSIParallelDevice::checkTag( IOSCSIParallelCommand *scsiCmd ) -{ - SCSICDBInfo scsiCDB; - bool rc = true; - - scsiCmd->getCDB( &scsiCDB ); - - scsiCDB.cdbTagMsg = 0; - scsiCDB.cdbTag = (UInt32)-1; - - do - { - if ( scsiCmd->device->target->targetParmsCurrent.enableTagQueuing == false ) - { - break; - } - - /* If the command is untagged, then don't allocate a tag nor - * send the untagged command as a simple-tagged command. - */ - if ( scsiCDB.cdbTagMsg == 0 ) - { - break; - } - - if ( allocTag( &scsiCDB.cdbTag ) == false ) - { - rc = false; - break; - } - } - while ( 0 ); - - scsiCmd->setCDB( &scsiCDB ); - - return rc; -} - -/* - * - * - * - */ -bool IOSCSIParallelDevice::allocTag( UInt32 *tagId ) -{ - UInt32 i; - UInt32 tagIndex; - UInt32 tagMask; - UInt32 *tags = 0; - - switch ( controller->controllerInfo.tagAllocationMethod ) - { - case kTagAllocationPerLun: - tags = tagArray; - break; - case kTagAllocationPerTarget: - tags = target->tagArray; - break; - case kTagAllocationPerController: - tags = controller->tagArray; - break; - default: - ; - } - - if ( tags == 0 ) return false; - - for ( i = 0; i < controller->controllerInfo.maxTags; i++ ) - { - tagIndex = i / 32; - tagMask = 1 << (i % 32); - if ( !(tags[tagIndex] & tagMask) ) - { - tags[tagIndex] |= tagMask; - *tagId = i; - return true; - } - } - return false; -} - -/* - * - * - * - */ -void IOSCSIParallelDevice::freeTag( UInt32 tagId ) -{ - UInt32 *tags = 0; - - switch ( controller->controllerInfo.tagAllocationMethod ) - { - case kTagAllocationPerLun: - tags = tagArray; - break; - case kTagAllocationPerTarget: - tags = target->tagArray; - break; - case kTagAllocationPerController: - tags = controller->tagArray; - break; - default: - ; - } - - if ( tags == 0 ) return; - - tags[tagId/32] &= ~(1 << (tagId % 32)); -} - -/* - * - * - * - */ -IOSCSIParallelCommand *IOSCSIParallelDevice::findCommandWithNexus( UInt32 tagValue ) -{ - IOSCSIParallelCommand *scsiCmd; - - queue_iterate( &activeList, scsiCmd, IOSCSIParallelCommand *, nextCommand ) - { - switch ( scsiCmd->cmdType ) - { - case kSCSICommandExecute: - case kSCSICommandReqSense: - if ( scsiCmd->scsiCmd.cdbTag == tagValue ) - { - return scsiCmd; - } - break; - default: - ; - } - } - - queue_iterate( &abortList, scsiCmd, IOSCSIParallelCommand *, nextCommand ) - { - switch ( scsiCmd->cmdType ) - { - case kSCSICommandExecute: - case kSCSICommandReqSense: - if ( scsiCmd->scsiCmd.cdbTag == tagValue ) - { - return scsiCmd; - } - break; - default: - ; - } - } - - return 0; -} - -/* - * - * - * - */ -void IOSCSIParallelDevice::timer() -{ - IOSCSIParallelCommand *scsiCmd, *tmp = 0; - SCSITargetLun scsiTargetLun; - - queue_iterate( &activeList, scsiCmd, IOSCSIParallelCommand *, nextCommand ) - { - tmp = (IOSCSIParallelCommand *)queue_prev( &scsiCmd->nextCommand ); - - if ( scsiCmd->timer ) - { - if ( !--scsiCmd->timer ) - { - scsiCmd->getTargetLun( &scsiTargetLun ); - IOLog("Timeout: T/L = %d:%d Cmd = %08x Cmd Type = %d\n\r", - scsiTargetLun.target, scsiTargetLun.lun, (int)scsiCmd, scsiCmd->cmdType ); - - switch ( scsiCmd->cmdType ) - { - case kSCSICommandExecute: - moveCommand( &activeList, &abortList, scsiCmd, kIOReturnTimeout ); - scsiCmd = tmp; - break; - - case kSCSICommandReqSense: - reqSenseState = kStateIdle; - moveCommand( &activeList, &abortList, scsiCmd, kIOReturnTimeout ); - scsiCmd = tmp; - break; - - case kSCSICommandAbort: - case kSCSICommandAbortAll: - case kSCSICommandDeviceReset: - controller->busResetState = kStateIssue; - break; - - default: - ; - } - - dispatchRequest(); - } - } - - if ( queue_end( &activeList, (queue_head_t *)scsiCmd ) == true ) - { - break; - } - } -} - -/* - * - * - * - */ -void IOSCSIParallelDevice::dispatchRequest() -{ - target->state = kStateActive; - controller->dispatchRequest(); -} - -/* - * - * - * - */ -bool IOSCSIParallelDevice::dispatch( UInt32 *dispatchAction ) -{ - bool rc; - - checkCancelQueue(); - - if ( controller->checkBusReset() == true ) - { - *dispatchAction = kDispatchStop; - return true; - } - - if ( (rc = controller->commandDisable) == true ) - { - *dispatchAction = kDispatchNextTarget; - return true; - } - - if ( checkAbortQueue() == true ) - { - *dispatchAction = kDispatchNextTarget; - return true; - } - - do - { - if ( (rc = controller->commandDisable) == true ) - { - *dispatchAction = kDispatchStop; - break; - } - - if ( (rc = checkReqSense()) == true ) - { - *dispatchAction = kDispatchNextTarget; - break; - } - - rc = checkDeviceQueue( dispatchAction ); - - } while ( *dispatchAction == kDispatchNextCommand ); - - return rc; -} - - -/* - * - * - * - */ -void IOSCSIParallelDevice::completeCommand( IOSCSIParallelCommand *scsiCmd ) -{ - SCSICommandType cmdType; - - cmdType = scsiCmd->cmdType; - switch ( cmdType ) - { - case kSCSICommandExecute: - executeCommandDone( scsiCmd ); - break; - - case kSCSICommandReqSense: - executeReqSenseDone( scsiCmd ); - break; - - case kSCSICommandAbort: - case kSCSICommandAbortAll: - case kSCSICommandDeviceReset: - abortCommandDone( scsiCmd ); - break; - - case kSCSICommandCancel: - cancelCommandDone( scsiCmd ); - break; - - default: - ; - } - - checkIdleNotify(); - - dispatchRequest(); -} - -/* - * - * - * - */ -void IOSCSIParallelDevice::checkIdleNotify() -{ - if ( idleNotifyActive == false ) - { - return; - } - - if ( (queue_empty( &activeList ) == true) - && (queue_empty( &abortList ) == true) - && (queue_empty( &cancelList ) == true) - && (target->reqSenseCount == 0) ) - { - idleNotifyActive = false; - (idleNotifyCallback)( idleNotifyTarget, idleNotifyRefcon ); - } -} - -/* - * - * - * - */ -void IOSCSIParallelDevice::flushQueue( UInt32 queueType, IOReturn rc ) -{ - queue_head_t *queue; - - queue = (queueType == kQTypeBypassQ) ? &bypassList : &deviceList; - purgeAllCommands( queue, rc ); -} - -/* - * - * - * - */ -void IOSCSIParallelDevice::executeCommandDone( IOSCSIParallelCommand *scsiCmd ) -{ - deleteCommand( scsiCmd->list, scsiCmd ); - - commandCount--; - controller->commandCount--; - target->commandCount--; - - if ( scsiCmd->scsiCmd.cdbTagMsg != 0 ) - { - freeTag( scsiCmd->scsiCmd.cdbTag ); - scsiCmd->scsiCmd.cdbTag = (UInt32) -1; - } - - if ( scsiCmd->scsiCmd.cdbFlags & (kCDBFlagsNegotiateSDTR | - kCDBFlagsNegotiateWDTR | - kCDBFlagsNegotiatePPR | - kCDBFlagsEnableTagQueuing) ) - { - if ( scsiCmd->scsiCmd.cdbFlags & (kCDBFlagsNegotiateSDTR | - kCDBFlagsNegotiateWDTR | - kCDBFlagsNegotiatePPR) ) - { - negotiationComplete(); - } - else - { - target->negotiationResult.returnCode = kIOReturnSuccess; - } - - IORWUnlock( target->targetSem ); - } - - if ( scsiCmd->scsiCmd.cdbFlags & kCDBFlagsNoDisconnect ) - { - controller->commandLimit = controller->commandLimitSave; - controller->noDisconnectCmd = 0; - } - - if ( scsiCmd->results.scsiStatus == kSCSIStatusCheckCondition - && scsiCmd->results.requestSenseDone == false - && scsiCmd->senseData != 0 ) - { - reqSenseOrigCmd = scsiCmd; - reqSenseState = kStateIssue; - target->reqSenseCount++; - return; - } - - if ( scsiCmd->results.scsiStatus == kSCSIStatusQueueFull ) - { - if ( commandCount > 4 ) - { -// IOLog( "IOSCSI: Q-full - commandCount = %d commandLimit = %d\n\r", commandCount, commandLimit ); - commandLimit = commandCount; - } - - stackCommand( &deviceList, scsiCmd ); - return; - } - - finishCommand( scsiCmd ); -} - -/* - * - * - * - */ -void IOSCSIParallelDevice::executeReqSenseDone( IOSCSIParallelCommand *scsiCmd ) -{ - IOSCSIParallelCommand *origCommand; - - deleteCommand( scsiCmd->list, scsiCmd ); - - target->reqSenseState = reqSenseState = kStateIdle; - target->reqSenseCount--; - - commandCount--; - controller->commandCount--; - - reqSenseOrigCmd = 0; - - origCommand = scsiCmd->origCommand; - - if ( (scsiCmd->results.returnCode == kIOReturnSuccess) || (scsiCmd->results.returnCode == kIOReturnUnderrun) ) - { - origCommand->results.requestSenseDone = true; - origCommand->results.requestSenseLength = scsiCmd->results.bytesTransferred; - } - else - { - origCommand->results.requestSenseDone = false; - origCommand->results.requestSenseLength = 0; - } - - finishCommand( scsiCmd->origCommand ); -} - -/* - * - * - * - */ -void IOSCSIParallelDevice::abortCommandDone( IOSCSIParallelCommand *scsiCmd ) -{ - IOSCSIParallelCommand *origSCSICmd; - IOSCSIParallelDevice *abortDev; - - deleteCommand( scsiCmd->list, scsiCmd ); - - abortState = kStateIdle; - - if ( scsiCmd->cmdType == kSCSICommandAbortAll ) - { - moveAllCommands( &activeList, &cancelList, kIOReturnAborted ); - moveAllCommands( &abortList, &cancelList, kIOReturnAborted ); - - if ( client != 0 ) - { - client->message( kSCSIClientMsgDeviceAbort | kSCSIClientMsgDone, this ); - } - } - if ( scsiCmd->cmdType == kSCSICommandDeviceReset ) - { - target->commandLimit = target->commandLimitSave; - target->reqSenseCount = 0; - target->reqSenseState = kStateIdle; - target->negotiateState = kStateIssue; - - target->targetParmsCurrent.transferPeriodpS = 0; - target->targetParmsCurrent.transferOffset = 0; - target->targetParmsCurrent.transferWidth = 1; - - queue_iterate( &target->deviceList, abortDev, IOSCSIParallelDevice *, nextDevice ) - { - abortDev->resetOccurred( (SCSIClientMessage)(kSCSIClientMsgDeviceReset | kSCSIClientMsgDone) ); - } - } - else if ( scsiCmd->cmdType == kSCSICommandAbort ) - { - origSCSICmd = scsiCmd->origCommand; - - if ( findCommand( &abortList, origSCSICmd ) == true ) - { - moveCommand( &abortList, &cancelList, origSCSICmd, kIOReturnAborted ); - } - } - - return; -} - -/* - * - * - * - */ -void IOSCSIParallelDevice::cancelCommandDone( IOSCSIParallelCommand *scsiCmd ) -{ - IOSCSIParallelCommand *origSCSICmd; - - cancelState = kStateIdle; - - origSCSICmd = scsiCmd->origCommand; - - if ( findCommand( &cancelList, origSCSICmd ) == true ) - { - IOLog( "IOSCSIParallelDevice::cancelCommandDone - Cancelled command not completed - scsiCmd = %08x\n\r", (int)origSCSICmd ); - deleteCommand( &cancelList, origSCSICmd ); - } -} - -/* - * - * - * - */ -void IOSCSIParallelDevice::finishCommand( IOSCSIParallelCommand *scsiCmd ) -{ - if ( scsiCmd->completionInfo.async.callback ) - { - (*scsiCmd->completionInfo.async.callback)( scsiCmd->completionInfo.async.target, - scsiCmd->completionInfo.async.refcon ); - } - else - { - scsiCmd->completionInfo.sync.lock->signal(); - } -} - - -/* - * - * - */ -OSDictionary *IOSCSIParallelDevice::createProperties() -{ - OSDictionary *propTable = 0; - OSObject *regObj; - char tmpbuf[81]; - char *d; - char unit[10]; - - propTable = OSDictionary::withCapacity(kSCSIMaxProperties); - if ( propTable == NULL ) - { - return NULL; - } - - regObj = (OSObject *)OSNumber::withNumber(targetLun.target,32); - if ( addToRegistry( propTable, regObj, kSCSIPropertyTarget ) != true ) - { - goto createprop_error; - } - - regObj = (OSObject *)OSNumber::withNumber(targetLun.target,32); - if ( addToRegistry( propTable, regObj, kSCSIPropertyIOUnit ) != true ) - { - goto createprop_error; - } - - sprintf(unit,"%x",targetLun.target); - setLocation(unit); - - regObj = (OSObject *)OSNumber::withNumber(targetLun.lun,32); - if ( addToRegistry( propTable, regObj, kSCSIPropertyLun ) != true ) - { - goto createprop_error; - } - - d= tmpbuf; - - stripBlanks( d, (char *)inquiryData->vendorName, sizeof(inquiryData->vendorName) ); - regObj = (OSObject *)OSString::withCString( d ); - if ( addToRegistry( propTable, regObj, kSCSIPropertyVendorName ) != true ) - { - goto createprop_error; - } - - stripBlanks( d, (char *)inquiryData->productName, sizeof(inquiryData->productName) ); - regObj = (OSObject *)OSString::withCString( d ); - if ( addToRegistry( propTable, regObj, kSCSIPropertyProductName ) != true ) - { - goto createprop_error; - } - - stripBlanks( d, (char *)inquiryData->productRevision, sizeof(inquiryData->productRevision) ); - regObj = (OSObject *)OSString::withCString( d ); - if ( addToRegistry( propTable, regObj, kSCSIPropertyProductRevision ) != true ) - { - goto createprop_error; - } - - regObj = (OSObject *)OSBoolean::withBoolean( (inquiryData->devTypeMod & kSCSIDevTypeModRemovable) != 0 ); - if ( addToRegistry( propTable, regObj, kSCSIPropertyRemovableMedia ) != true ) - { - goto createprop_error; - } - - regObj = (OSObject *)OSNumber::withNumber( inquiryData->devType & kSCSIDevTypeMask, 32 ); - if ( addToRegistry( propTable, regObj, kSCSIPropertyDeviceTypeID ) != true ) - { - goto createprop_error; - } - - regObj = (OSObject *)target->regObjTransferPeriod; - if ( addToRegistry( propTable, regObj, kSCSIPropertyTransferPeriod, false ) != true ) - { - goto createprop_error; - } - regObjTransferPeriod = (OSNumber *)regObj; - - regObj = (OSObject *)target->regObjTransferOffset; - if ( addToRegistry( propTable, regObj, kSCSIPropertyTransferOffset, false ) != true ) - { - goto createprop_error; - } - regObjTransferOffset = (OSNumber *)regObj; - - - regObj = (OSObject *)target->regObjTransferWidth; - if ( addToRegistry( propTable, regObj, kSCSIPropertyTransferWidth, false ) != true ) - { - goto createprop_error; - } - regObjTransferWidth = (OSNumber *)regObj; - - regObj = (OSObject *)target->regObjTransferOptions; - if ( addToRegistry( propTable, regObj, kSCSIPropertyTransferOptions, false ) != true ) - { - goto createprop_error; - } - regObjTransferOptions = (OSNumber *)regObj; - - regObj = (OSObject *)target->regObjCmdQueue; - if ( addToRegistry( propTable, regObj, kSCSIPropertyCmdQueue, false ) != true ) - { - goto createprop_error; - } - regObjCmdQueue = (OSNumber *)regObj; - - return propTable; - -createprop_error: ; - propTable->release(); - return NULL; -} - - -/* - * - * - */ -bool IOSCSIParallelDevice::addToRegistry( OSDictionary *propTable, OSObject *regObj, char *key, - bool doRelease = true ) -{ - bool rc; - - if ( regObj == NULL ) - { - return false; - } - - rc = propTable->setObject( key, regObj ); - - if ( doRelease ) - { - // If 'doRelease' is true, then a reference count is consumed. - regObj->release(); - } - - return rc; -} - - -/* - * - * - * - */ -bool IOSCSIParallelDevice::matchPropertyTable(OSDictionary * table) -{ - bool match; - - match = compareProperty( table, kSCSIPropertyIOUnit ) && - compareProperty( table, kSCSIPropertyDeviceTypeID ) && - compareProperty( table, kSCSIPropertyRemovableMedia ) && - compareProperty( table, kSCSIPropertyVendorName ) && - compareProperty( table, kSCSIPropertyProductName ) && - compareProperty( table, kSCSIPropertyProductRevision ); - - if ( match == true ) - { - match = super::matchPropertyTable(table); - } - - return match; -} - - -/* - * - * - * - */ -IOService *IOSCSIParallelDevice::matchLocation(IOService * client) -{ - return this; -} - - -/* - * - * - * - */ -void IOSCSIParallelDevice::stripBlanks( char *d, char *s, UInt32 l ) -{ - char *p, c; - - for ( p = d, c = *s; l && c ; l--) - { - c = (*d++ = *s++); - if ( c != ' ' ) - { - p = d; - } - } - *p = 0; -} - -/* - * - * - * - */ -IOSCSICommand *IOSCSIParallelDevice::allocCommand( IOSCSIDevice *, UInt32 clientDataSize ) -{ - - return (IOSCSICommand *) allocCommand( kIOSCSIParallelDevice, clientDataSize ); -} - -IOSCSIParallelCommand *IOSCSIParallelDevice::allocCommand( IOSCSIParallelDevice *, UInt32 clientDataSize ) -{ - IOSCSIParallelCommand *cmd; - - if ( (cmd = controller->allocCommand( clientDataSize )) ) - { - cmd->device = this; - } - return cmd; -} - -IOCDBCommand *IOSCSIParallelDevice::allocCommand( IOCDBDevice *, UInt32 clientDataSize ) -{ - return (IOCDBCommand *) allocCommand( kIOSCSIDevice, clientDataSize ); -} - - -/* - * - * - */ -IOWorkLoop *IOSCSIParallelDevice::getWorkLoop() const -{ - return controller->workLoop; -} - - -/* - * - * - * - */ -bool IOSCSIParallelDevice::open( IOService *forClient, IOOptionBits options, void *arg ) -{ - if ( client != 0 ) return false; - - client = forClient; - - return super::open( forClient, options, arg ); -} - -/* - * - * - * - */ -void IOSCSIParallelDevice::close( IOService *forClient, IOOptionBits options ) -{ - client = 0; - - return super::close( forClient, options ); -} - -/* - * - * - * - */ -IOReturn IOSCSIParallelDevice::message( UInt32 forMsg, IOService *forProvider, void *forArg ) -{ - IOReturn rc = kIOReturnSuccess; - SCSIClientMessage clientMsg; - - clientMsg = (SCSIClientMessage) forMsg; - -// IOLog( "IOSCSIParallelDevice::message() - clientMsg = %08x\n\r", clientMsg ); - - switch( clientMsg ) - { - case kSCSIClientMsgBusReset: - holdQueue( kQTypeNormalQ ); - break; - case kSCSIClientMsgBusReset | kSCSIClientMsgDone: - releaseQueue( kQTypeNormalQ ); - break; - default: - rc = super::message( clientMsg, forProvider, forArg ); - } - - return rc; -} - -/* - * - * - * - */ -void IOSCSIParallelDevice::free() -{ - if ( deviceGate != 0 ) - { - controller->workLoop->removeEventSource( deviceGate ); - deviceGate->release(); - } - - if ( reqSenseCmd != 0 ) reqSenseCmd->release(); - if ( abortCmd != 0 ) abortCmd->release(); - if ( cancelCmd != 0 ) cancelCmd->release(); - if ( probeCmd != 0 ) probeCmd->release(); - - if ( tagArray != 0 ) IOFree( tagArray, controller->tagArraySize ); - if ( inquiryData != 0 ) IOFree( inquiryData, inquiryDataSize ); - if ( devicePrivateData != 0 ) IOFreeContiguous( devicePrivateData, controller->controllerInfo.lunPrivateDataSize ); - if ( clientSem != 0 ) IORWLockFree( clientSem ); - - super::free(); -} - - diff --git a/iokit/Families/IOSCSIParallel/queueHelpers.cpp b/iokit/Families/IOSCSIParallel/queueHelpers.cpp deleted file mode 100644 index 569418feb..000000000 --- a/iokit/Families/IOSCSIParallel/queueHelpers.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * queueHelpers.cpp - * - */ -#include - -void IOSCSIParallelDevice::addCommand( queue_head_t *list, IOSCSIParallelCommand *scsiCmd ) -{ - scsiCmd->list = list; - - queue_enter( list, scsiCmd, IOSCSIParallelCommand *, nextCommand ); -} - -void IOSCSIParallelDevice::deleteCommand( queue_head_t *list, IOSCSIParallelCommand *scsiCmd, IOReturn rc = kIOReturnSuccess ) -{ - scsiCmd->list = 0; - - if ( rc != kIOReturnSuccess ) - { - if ( scsiCmd->results.returnCode == kIOReturnSuccess ) - { - scsiCmd->results.returnCode = (IOReturn) rc; - } - } - - queue_remove( list, scsiCmd, IOSCSIParallelCommand *, nextCommand ); -} - -IOSCSIParallelCommand *IOSCSIParallelDevice::checkCommand( queue_head_t *list ) -{ - if ( queue_empty( list ) == true ) - { - return 0; - } - - return (IOSCSIParallelCommand *)queue_first( list ); -} - - -IOSCSIParallelCommand *IOSCSIParallelDevice::getCommand( queue_head_t *list ) -{ - IOSCSIParallelCommand *scsiCmd = 0; - - if ( queue_empty( list ) == false ) - { - queue_remove_first( list, scsiCmd, IOSCSIParallelCommand *, nextCommand ); - scsiCmd->list = 0; - } - - return scsiCmd; -} - -void IOSCSIParallelDevice::stackCommand( queue_head_t *list, IOSCSIParallelCommand *scsiCmd ) -{ - scsiCmd->list = list; - - queue_enter_first( list, scsiCmd, IOSCSIParallelCommand *, nextCommand ); -} - -void IOSCSIParallelDevice::moveCommand( queue_head_t *fromList, queue_head_t *toList, IOSCSIParallelCommand *scsiCmd, IOReturn rc = kIOReturnSuccess ) -{ - if ( rc != kIOReturnSuccess ) - { - if ( scsiCmd->results.returnCode == kIOReturnSuccess ) - { - scsiCmd->results.returnCode = (IOReturn) rc; - } - } - - scsiCmd->list = toList; - - queue_remove( fromList, scsiCmd, IOSCSIParallelCommand *, nextCommand ); - queue_enter( toList, scsiCmd, IOSCSIParallelCommand *, nextCommand ); -} - -void IOSCSIParallelDevice::moveAllCommands( queue_head_t *fromList, queue_head_t *toList, IOReturn rc = kIOReturnSuccess ) -{ - IOSCSIParallelCommand *scsiCmd; - - if ( queue_empty( fromList ) == true ) return; - - do - { - scsiCmd = (IOSCSIParallelCommand *)queue_first( fromList ); - - if ( rc != kIOReturnSuccess ) - { - if ( scsiCmd->results.returnCode == kIOReturnSuccess ) - { - scsiCmd->results.returnCode = (IOReturn) rc; - } - } - - scsiCmd->list = toList; - - queue_remove( fromList, scsiCmd, IOSCSIParallelCommand *, nextCommand ); - queue_enter( toList, scsiCmd, IOSCSIParallelCommand *, nextCommand ); - - } while( queue_empty( fromList ) == false ); -} - -bool IOSCSIParallelDevice::findCommand( queue_head_t *list, IOSCSIParallelCommand *findSCSICmd ) -{ - IOSCSIParallelCommand *scsiCmd; - - queue_iterate( list, scsiCmd, IOSCSIParallelCommand *, nextCommand ) - { - if ( scsiCmd == findSCSICmd ) - { - return true; - } - } - return false; -} - -void IOSCSIParallelDevice::purgeAllCommands( queue_head_t *list, IOReturn rc ) -{ - IOSCSIParallelCommand *scsiCmd; - - if ( queue_empty( list ) == true ) return; - - do - { - scsiCmd = (IOSCSIParallelCommand *)queue_first( list ); - - deleteCommand( list, scsiCmd, rc ); - finishCommand( scsiCmd ); - - } while( queue_empty( list ) == false ); -} diff --git a/iokit/IOKit/IOBufferMemoryDescriptor.h b/iokit/IOKit/IOBufferMemoryDescriptor.h index 733fa1dd1..4e40b5a8b 100644 --- a/iokit/IOKit/IOBufferMemoryDescriptor.h +++ b/iokit/IOKit/IOBufferMemoryDescriptor.h @@ -33,6 +33,7 @@ enum { kIOMemoryKernelUserShared = 0x00010000, }; +#define _IOBUFFERMEMORYDESCRIPTOR_INTASKWITHOPTIONS_ 1 class IOBufferMemoryDescriptor : public IOGeneralMemoryDescriptor { @@ -42,7 +43,9 @@ protected: /*! @struct ExpansionData @discussion This structure will be used to expand the capablilties of this class in the future. */ - struct ExpansionData { }; + struct ExpansionData { + vm_map_t map; + }; /*! @var reserved Reserved for future use. (Internal use only) */ @@ -57,7 +60,13 @@ protected: unsigned _physSegCount; private: - OSMetaClassDeclareReservedUnused(IOBufferMemoryDescriptor, 0); + virtual bool initWithOptions( + IOOptionBits options, + vm_size_t capacity, + vm_offset_t alignment, + task_t inTask); + + OSMetaClassDeclareReservedUsed(IOBufferMemoryDescriptor, 0); OSMetaClassDeclareReservedUnused(IOBufferMemoryDescriptor, 1); OSMetaClassDeclareReservedUnused(IOBufferMemoryDescriptor, 2); OSMetaClassDeclareReservedUnused(IOBufferMemoryDescriptor, 3); @@ -126,6 +135,24 @@ public: vm_size_t capacity, vm_offset_t alignment = 1); +/*! @function inTaskWithOptions + @abstract Create a memory buffer with memory descriptor for that buffer. Added in Mac OS X 10.2. + @discussion This method allocates a memory buffer with a given size and alignment in the task's address space specified, and returns a memory descriptor instance representing the memory. It is recommended memory allocated for I/O or sharing via mapping be created via IOBufferMemoryDescriptor. Options passed with the request specify the kind of memory to be allocated - pageablity and sharing are specified with option bits. This function may block and so should not be called from interrupt level or while a simple lock is held. + @param inTask The task the buffer will be allocated in. + @param options Options for the allocation: + kIOMemoryPhysicallyContiguous - pass to request memory be physically contiguous. This option is heavily discouraged. The request may fail if memory is fragmented, may cause large amounts of paging activity, and may take a very long time to execute. + kIOMemoryPageable - pass to request memory be non-wired - the default for kernel allocated memory is wired. + kIOMemoryKernelUserShared - pass to request memory that will be mapped into both the kernel and client applications. + @param capacity The number of bytes to allocate. + @param alignment The minimum required alignment of the buffer in bytes - 1 is the default for no required alignment. For example, pass 256 to get memory allocated at an address with bits 0-7 zero. + @result An instance of class IOBufferMemoryDescriptor. To be released by the caller, which will free the memory desriptor and associated buffer. */ + + static IOBufferMemoryDescriptor * inTaskWithOptions( + task_t inTask, + IOOptionBits options, + vm_size_t capacity, + vm_offset_t alignment = 1); + /* * withCapacity: * diff --git a/iokit/IOKit/IOCatalogue.h b/iokit/IOKit/IOCatalogue.h index e81e0f486..9cfa1bf6b 100644 --- a/iokit/IOKit/IOCatalogue.h +++ b/iokit/IOKit/IOCatalogue.h @@ -161,7 +161,7 @@ public: /*! @function terminateDrivers @abstract Terminates all instances of a driver which match the contents of the matching dictionary. Does not unload module. - @param matching Dictionary containing the matching criteria. + @param matching A dictionary whose keys and values are used for matching personalities in the database. For example, a matching dictionary containing a 'IOProviderClass' key with the value 'IOPCIDevice' will cause termination for all instances whose personalities have the key 'IOProviderClass' equal to 'IOPCIDevice'. */ IOReturn terminateDrivers( OSDictionary * matching ); @@ -184,7 +184,7 @@ public: /*! @function startMatching @abstract Starts an IOService matching thread where matching keys and values are provided by the matching dictionary. - @param matching A dictionary containing keys and values to match against. + @param matching A dictionary whose keys and values are used for matching personalities in the database. For example, a matching dictionary containing a 'IOProviderClass' key with the value 'IOPCIDevice' will start matching for all personalities which have the key 'IOProviderClass' equal to 'IOPCIDevice'. */ bool startMatching( OSDictionary * matching ); diff --git a/iokit/IOKit/IOEventSource.h b/iokit/IOKit/IOEventSource.h index e3d37759a..6136c93ae 100644 --- a/iokit/IOKit/IOEventSource.h +++ b/iokit/IOKit/IOEventSource.h @@ -176,14 +176,18 @@ IOWorkLoop that at least reacts to signalWorkAvailable() and onThread functions. protected: // Methods to access the IOWorkLoop exported fields - inline void signalWorkAvailable() { workLoop->signalWorkAvailable(); }; - inline void openGate() { workLoop->openGate(); }; - inline void closeGate() { workLoop->closeGate(); }; - inline bool tryCloseGate() { return workLoop->tryCloseGate(); }; - inline int sleepGate(void *event, UInt32 type) - { return workLoop->sleepGate(event, type); }; - inline void wakeupGate(void *event, bool oneThread) - { workLoop->wakeupGate(event, oneThread); }; + /* inline */ void signalWorkAvailable(); + /* { workLoop->signalWorkAvailable(); }; */ + /* inline */ void openGate(); + /* { workLoop->openGate(); }; */ + /* inline */ void closeGate(); + /* { workLoop->closeGate(); }; */ + /* inline */ bool tryCloseGate(); + /* { return workLoop->tryCloseGate(); }; */ + /* inline */ int sleepGate(void *event, UInt32 type); + /* { return workLoop->sleepGate(event, type); }; */ + /* inline */ void wakeupGate(void *event, bool oneThread); + /* { workLoop->wakeupGate(event, oneThread); }; */ public: /*! @function setAction diff --git a/iokit/IOKit/IOKitDebug.h b/iokit/IOKit/IOKitDebug.h index 325352272..5211cb95f 100644 --- a/iokit/IOKit/IOKitDebug.h +++ b/iokit/IOKit/IOKitDebug.h @@ -69,6 +69,7 @@ enum { kIOLogPower = 0x00000080ULL, kIOLogMapping = 0x00000100ULL, kIOLogCatalogue = 0x00000200ULL, + kIOLogTracePower = 0x00000400ULL, kIOLogServiceTree = 0x00001000ULL, kIOLogDTree = 0x00002000ULL, diff --git a/iokit/IOKit/IOKitKeys.h b/iokit/IOKit/IOKitKeys.h index b0ecbf899..6862e89e9 100644 --- a/iokit/IOKit/IOKitKeys.h +++ b/iokit/IOKit/IOKitKeys.h @@ -64,6 +64,7 @@ #define kIOPropertyMatchKey "IOPropertyMatch" #define kIOPathMatchKey "IOPathMatch" #define kIOLocationMatchKey "IOLocationMatch" +#define kIOParentMatchKey "IOParentMatch" #define kIOResourceMatchKey "IOResourceMatch" #define kIOMatchedServiceCountKey "IOMatchedServiceCountMatch" @@ -100,5 +101,20 @@ #define kIOMaximumSegmentCountReadKey "IOMaximumSegmentCountRead" // (OSNumber) #define kIOMaximumSegmentCountWriteKey "IOMaximumSegmentCountWrite" // (OSNumber) -#endif /* ! _IOKIT_IOKITKEYS_H */ +// properties found in services that wish to describe an icon +// +// IOIcon = +// { +// CFBundleIdentifier = "com.example.driver.example"; +// IOBundleResourceFile = "example.icns"; +// }; +// +// where IOBundleResourceFile is the filename of the resource + +#define kIOIconKey "IOIcon" // (OSDictionary) +#define kIOBundleResourceFileKey "IOBundleResourceFile" // (OSString) +#define kIOBusBadgeKey "IOBusBadge" // (OSDictionary) +#define kIODeviceIconKey "IODeviceIcon" // (OSDictionary) + +#endif /* ! _IOKIT_IOKITKEYS_H */ diff --git a/iokit/IOKit/IOLib.h b/iokit/IOKit/IOLib.h index 1f02f63cd..962443ddc 100644 --- a/iokit/IOKit/IOLib.h +++ b/iokit/IOKit/IOLib.h @@ -33,9 +33,7 @@ #error IOLib.h is for kernel use only #endif -#ifndef IOKIT_DEPRECATED -#define IOKIT_DEPRECATED 1 -#endif +#include #include @@ -272,7 +270,7 @@ static inline IOFixed IOFixedDivide(IOFixed a, IOFixed b) (((value) / (multiple)) * (multiple)); -#if IOKIT_DEPRECATED +#ifdef __APPLE_API_OBSOLETE /* The following API is deprecated */ @@ -289,7 +287,7 @@ void IOGetTime( mach_timespec_t * clock_time); extern mach_timespec_t IOZeroTvalspec; -#endif /* IOKIT_DEPRECATED */ +#endif /* __APPLE_API_OBSOLETE */ #ifdef __cplusplus } /* extern "C" */ diff --git a/iokit/IOKit/IOLocks.h b/iokit/IOKit/IOLocks.h index 4e2e9c22c..c966aba8c 100644 --- a/iokit/IOKit/IOLocks.h +++ b/iokit/IOKit/IOLocks.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1998-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -30,9 +30,7 @@ #error IOLocks.h is for kernel use only #endif -#ifndef IOKIT_DEPRECATED -#define IOKIT_DEPRECATED 1 -#endif +#include #include @@ -45,6 +43,7 @@ extern "C" { #include #include +#include #include /* @@ -101,7 +100,34 @@ void IOLockUnlock( IOLock * lock) mutex_unlock(lock); } -#if IOKIT_DEPRECATED +/*! @function IOLockSleep + @abstract Sleep with mutex unlock and relock +@discussion Prepare to sleep,unlock the mutex, and re-acquire it on wakeup.Results are undefined if the caller has not locked the mutex. This function may block and so should not be called from interrupt level or while a simple lock is held. + @param lock Pointer to the locked lock. + @param event The event to sleep on. + @param interType How can the sleep be interrupted. + @result The wait-result value indicating how the thread was awakened.*/ +static __inline__ +int IOLockSleep( IOLock * lock, void *event, UInt32 interType) +{ + return thread_sleep_mutex((event_t) event, lock, (int) interType); +} + +static __inline__ +int IOLockSleepDeadline( IOLock * lock, void *event, + AbsoluteTime deadline, UInt32 interType) +{ + return thread_sleep_mutex_deadline((event_t) event, lock, + __OSAbsoluteTime(deadline), (int) interType); +} + +static __inline__ +void IOLockWakeup(IOLock * lock, void *event, bool oneThread) +{ + thread_wakeup_prim((event_t) event, oneThread, THREAD_AWAKENED); +} + +#ifdef __APPLE_API_OBSOLETE /* The following API is deprecated */ @@ -117,7 +143,7 @@ static __inline__ void IOTakeLock( IOLock * lock) { IOLockLock(lock); } static __inline__ boolean_t IOTryLock( IOLock * lock) { return(IOLockTryLock(lock)); } static __inline__ void IOUnlock( IOLock * lock) { IOLockUnlock(lock); } -#endif /* IOKIT_DEPRECATED */ +#endif /* __APPLE_API_OBSOLETE */ /* * Recursive lock operations @@ -227,7 +253,7 @@ void IORWLockUnlock( IORWLock * lock) lock_done( lock); } -#if IOKIT_DEPRECATED +#ifdef __APPLE_API_OBSOLETE /* The following API is deprecated */ @@ -235,7 +261,7 @@ static __inline__ void IOReadLock( IORWLock * lock) { IORWLockRead(lock); } static __inline__ void IOWriteLock( IORWLock * lock) { IORWLockWrite(lock); } static __inline__ void IORWUnlock( IORWLock * lock) { IORWLockUnlock(lock); } -#endif /* IOKIT_DEPRECATED */ +#endif /* __APPLE_API_OBSOLETE */ /* diff --git a/iokit/IOKit/IOMemoryDescriptor.h b/iokit/IOKit/IOMemoryDescriptor.h index a23734872..0212d3947 100644 --- a/iokit/IOKit/IOMemoryDescriptor.h +++ b/iokit/IOKit/IOMemoryDescriptor.h @@ -60,9 +60,10 @@ protected: @discussion This structure will be used to expand the capablilties of this class in the future. */ struct ExpansionData { - void * devicePager; - unsigned int pagerContig:1; - unsigned int unused:31; + void * devicePager; + unsigned int pagerContig:1; + unsigned int unused:31; + IOMemoryDescriptor * memory; }; /*! @var reserved @@ -325,8 +326,8 @@ public: @discussion This method returns the physical address of the first byte in the memory. It is most useful on memory known to be physically contiguous. @result A physical address. */ - inline IOPhysicalAddress getPhysicalAddress() - { return( getPhysicalSegment( 0, 0 )); } + /* inline */ IOPhysicalAddress getPhysicalAddress(); + /* { return( getPhysicalSegment( 0, 0 )); } */ /* DEPRECATED */ /* USE INSTEAD: map(), readBytes(), writeBytes() */ /* DEPRECATED */ virtual void * getVirtualSegment(IOByteCount offset, @@ -471,8 +472,8 @@ public: @discussion This method returns the physical address of the first byte in the mapping. It is most useful on mappings known to be physically contiguous. @result A physical address. */ - inline IOPhysicalAddress getPhysicalAddress() - { return( getPhysicalSegment( 0, 0 )); } + /* inline */ IOPhysicalAddress getPhysicalAddress(); + /* { return( getPhysicalSegment( 0, 0 )); } */ /*! @function getLength @abstract Accessor to the length of the mapping. @@ -622,13 +623,14 @@ public: vm_map_t addressMap, IOVirtualAddress logical, IOByteCount length ); + virtual bool serialize(OSSerialize *s) const; }; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ class IOSubMemoryDescriptor : public IOMemoryDescriptor { - friend IOMemoryDescriptor; + friend class IOMemoryDescriptor; OSDeclareDefaultStructors(IOSubMemoryDescriptor); @@ -700,6 +702,8 @@ public: // make virtual IOReturn redirect( task_t safeTask, bool redirect ); + virtual bool serialize(OSSerialize *s) const; + protected: virtual IOMemoryMap * makeMapping( IOMemoryDescriptor * owner, diff --git a/iokit/IOKit/IONVRAM.h b/iokit/IOKit/IONVRAM.h index 866a9b9e1..1e09641a7 100644 --- a/iokit/IOKit/IONVRAM.h +++ b/iokit/IOKit/IONVRAM.h @@ -30,8 +30,11 @@ #define kIODTNVRAMOFPartitionName "common" #define kIODTNVRAMXPRAMPartitionName "APL,MacOS75" +#define kIODTNVRAMPanicInfoPartitonName "APL,OSXPanic" #define kIODTNVRAMFreePartitionName "wwwwwwwwwwww" +#define kIODTNVRAMPanicInfoKey "aapl,panic-info" + enum { kIODTNVRAMImageSize = 0x2000, kIODTNVRAMXPRAMSize = 0x0100, @@ -73,7 +76,12 @@ private: UInt32 _nrPartitionOffset; UInt32 _nrPartitionSize; UInt8 *_nrImage; + UInt32 _piPartitionOffset; + UInt32 _piPartitionSize; + UInt8 *_piImage; + bool _systemPaniced; + virtual UInt8 calculatePartitionChecksum(UInt8 *partitionHeader); virtual IOReturn initOFVariables(void); virtual IOReturn syncOFVariables(void); virtual UInt32 getOFVariableType(const OSSymbol *propSymbol) const; @@ -143,6 +151,8 @@ public: virtual IOReturn writeNVRAMPartition(const OSSymbol *partitionID, IOByteCount offset, UInt8 *buffer, IOByteCount length); + + virtual IOByteCount savePanicInfo(UInt8 *buffer, IOByteCount length); }; #endif /* !_IOKIT_IONVRAM_H */ diff --git a/iokit/IOKit/IOPlatformExpert.h b/iokit/IOKit/IOPlatformExpert.h index 1147780fd..fadb9eea5 100644 --- a/iokit/IOKit/IOPlatformExpert.h +++ b/iokit/IOKit/IOPlatformExpert.h @@ -45,11 +45,15 @@ extern int PEGetPlatformEpoch( void ); enum { kPEHaltCPU, - kPERestartCPU + kPERestartCPU, + kPEHangCPU }; extern int (*PE_halt_restart)(unsigned int type); extern int PEHaltRestart(unsigned int type); +// Save the Panic Info. Returns the number of bytes saved. +extern unsigned long PESavePanicInfo(unsigned char *buffer, unsigned long length); + extern long PEGetGMTTimeOfDay( void ); extern void PESetGMTTimeOfDay( long secs ); @@ -143,7 +147,10 @@ public: virtual bool hasPrivPMFeature (unsigned long privFeatureMask); virtual int numBatteriesSupported (void); - OSMetaClassDeclareReservedUnused(IOPlatformExpert, 0); + virtual IOByteCount savePanicInfo(UInt8 *buffer, IOByteCount length); + + OSMetaClassDeclareReservedUsed(IOPlatformExpert, 0); + OSMetaClassDeclareReservedUnused(IOPlatformExpert, 1); OSMetaClassDeclareReservedUnused(IOPlatformExpert, 2); OSMetaClassDeclareReservedUnused(IOPlatformExpert, 3); @@ -221,6 +228,8 @@ public: IOByteCount offset, UInt8 * buffer, IOByteCount length); + virtual IOByteCount savePanicInfo(UInt8 *buffer, IOByteCount length); + OSMetaClassDeclareReservedUnused(IODTPlatformExpert, 0); OSMetaClassDeclareReservedUnused(IODTPlatformExpert, 1); OSMetaClassDeclareReservedUnused(IODTPlatformExpert, 2); diff --git a/iokit/IOKit/IORegistryEntry.h b/iokit/IOKit/IORegistryEntry.h index 6fa65bf36..315945052 100644 --- a/iokit/IOKit/IORegistryEntry.h +++ b/iokit/IOKit/IORegistryEntry.h @@ -56,7 +56,7 @@ enum { class IORegistryEntry : public OSObject { - friend IORegistryIterator; + friend class IORegistryIterator; OSDeclareDefaultStructors(IORegistryEntry) @@ -424,8 +424,8 @@ public: @discussion This method will return a pointer to the live property table as an OSDictionery. Its use is not recommended in most cases, instead use the synchronized accessors and helper functions of IORegistryEntry to access properties. It can only safely be used by one thread, which usually means it can only be used before a registry entry is entered into the registry. @result A pointer to the property table as an OSDictionary. The pointer is valid while the registry entry is retained, and should not be released by the caller. */ - inline OSDictionary * getPropertyTable( void ) const - { return(fPropertyTable); } + /* inline */ OSDictionary * getPropertyTable( void ) const; + /* { return(fPropertyTable); } */ /* Set properties from user level, to be overridden if supported */ diff --git a/iokit/IOKit/IOService.h b/iokit/IOKit/IOService.h index 9dd414e63..4e7111324 100644 --- a/iokit/IOKit/IOService.h +++ b/iokit/IOKit/IOService.h @@ -99,6 +99,7 @@ extern const OSSymbol * gIONameMatchKey; extern const OSSymbol * gIONameMatchedKey; extern const OSSymbol * gIOPropertyMatchKey; extern const OSSymbol * gIOLocationMatchKey; +extern const OSSymbol * gIOParentMatchKey; extern const OSSymbol * gIOPathMatchKey; extern const OSSymbol * gIOMatchCategoryKey; extern const OSSymbol * gIODefaultMatchCategoryKey; @@ -392,8 +393,7 @@ public: @discussion When an IOService is successfully terminated, it is immediately made inactive, which blocks further attach()es, matching or notifications occuring on the object. It remains inactive until the last client closes, and is then finalized and destroyed. @result Returns true if the IOService has been terminated. */ - inline bool isInactive( void ) const - { return( 0 != (kIOServiceInactiveState & getState())); } + bool isInactive( void ) const; /* Stack creation */ diff --git a/iokit/IOKit/IOTimeStamp.h b/iokit/IOKit/IOTimeStamp.h index 3e193aa77..cf07474f8 100644 --- a/iokit/IOKit/IOTimeStamp.h +++ b/iokit/IOKit/IOTimeStamp.h @@ -22,7 +22,6 @@ #ifndef IOKIT_IOTIMESTAMP_H #define IOKIT_IOTIMESTAMP_H -#include #include static inline void @@ -94,6 +93,7 @@ IOTimeStamp(unsigned int csc, #define IODBG_CMDQ(code) (KDBG_CODE(DBG_IOKIT, DBG_IOCMDQ, code)) #define IODBG_MCURS(code) (KDBG_CODE(DBG_IOKIT, DBG_IOMCURS, code)) #define IODBG_MDESC(code) (KDBG_CODE(DBG_IOKIT, DBG_IOMDESC, code)) +#define IODBG_POWER(code) (KDBG_CODE(DBG_IOKIT, DBG_IOPOWER, code)) /* IOKit specific codes - within each subclass */ @@ -146,4 +146,11 @@ IOTimeStamp(unsigned int csc, /* DBG_IOKIT/DBG_IOMDESC codes */ +/* DBG_IOKIT/DBG_IOPOWER codes */ +#define IOPOWER_ROOT 1 /* 0x05100004 */ +#define IOPOWER_WAKE 2 /* 0x05100008 */ +#define IOPOWER_STATE 3 /* 0x0510000c */ +#define IOPOWER_ACK 4 /* 0x05100010 */ +#define IOPOWER_CLIENT 5 /* 0x05100014 */ + #endif /* ! IOKIT_IOTIMESTAMP_H */ diff --git a/iokit/IOKit/Makefile b/iokit/IOKit/Makefile index ecfdc457f..9368f3eff 100644 --- a/iokit/IOKit/Makefile +++ b/iokit/IOKit/Makefile @@ -12,21 +12,18 @@ include $(MakeInc_def) INSTINC_SUBDIRS = \ adb \ - cdb \ nvram \ pci \ platform \ power \ pwr_mgt \ rtc \ - scsi \ system_management INSTINC_SUBDIRS_PPC = \ ppc INSTINC_SUBDIRS_I386 = \ - ata \ i386 EXPINC_SUBDIRS = ${INSTINC_SUBDIRS} diff --git a/iokit/IOKit/ata/IOATACommand_Reference.h b/iokit/IOKit/ata/IOATACommand_Reference.h deleted file mode 100644 index f6b3af99c..000000000 --- a/iokit/IOKit/ata/IOATACommand_Reference.h +++ /dev/null @@ -1,500 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! -@header IOATACommand_Reference.h - -This header defines the IOATACommand class. - -This class encapsulates an ATA/ATAPI Command. The client driver allocates a -command using IOATADevice::allocCommand() and initializes it using -functions of this class. The client can then submit the command to -the ATA/ATAPI stack by invoking the execute() function. -*/ - -/*! -@typedef ATATaskfile -@discussion -The ATATaskfile structure provides information to be read/written into an IOATACommand. This -information includes the ATA taskfile register settings and the protocol the transport driver -is to use when the corresponding IOATACommand is executed. -@field protocol -Indicates the type of protocol the ATA Controller driver is to use when executing this command. -See enum ATAProtocol in IOATADevice_Reference for allowable values for this field. -@field tagType -Indicates whether an ATA command requires a tag. This field is only used when the protocol -selected for the command supports the Overlap feature set. -@field tag -This field is set by the IOATAController class to tell the host -adapter driver the tag value to assign to this IOATACommand. -@field resultmask -This field is set by the IOATADevice client and is a bit mask indicating the registers to be -returned when the IOATACommand completes. Clients should use ATARegToMask() convert ATA register -index values to bit mask values. -@field regmask -This field is set by the IOATADevice client and is a bit mask indicating the registers to be written -when an IOATACommand is executed. Clients should use ATARegToMask() convert ATA register -index values to bit mask values. -@field ataRegs -This array contains the ATA taskfile register values to be written when an IOATACommand is executed. -The index values for ATA taskfile registers is specified by enum ATARegs. -*/ -typedef struct ATATaskfile { - - ATAProtocol protocol; - - UInt32 flags; - - UInt8 tagType; - UInt32 tag; - - UInt32 resultmask; - - UInt32 regmask; - UInt32 ataRegs[kMaxATARegs]; - -} ATATaskfile; - -/*! -@typedef ATACDBInfo -@discussion -The ATACDBInfo structure provides cdb information to be read/written into an IOATACommand. -@field cdbFlags -Indicates flags to applicable to the CDB to be executed. There are currently no flags defined for -IOATADevice clients. -@field cdbLength -Set by the IOATADevice client to the length of the Command Descriptor -Block (CDB). -@field cdb -Set by the IOATADevice client to command descriptor block the client -wishes the ATAPI device to execute. -*/ -typedef struct ATACDBInfo { - - UInt32 cdbFlags; - - UInt32 cdbLength; - UInt8 cdb[16]; - - UInt32 reserved[16]; - -} ATACDBInfo; - -/*! -@typedef ATAResults -@discussion -The ATAResults structure provides completion information for an IOATACommand. -@field returnCode -The overall return code for the command. See iokit/iokit/IOReturn.h. -This value is also returned as the getResults() return value. -@field bytesTransferred -The total number of bytes transferred to/from the ATA device. -Note: Some ATA controllers are not capable of returning accurate byte counts when -operating in bus-master mode. Clients should use some caution in interpreting the -contents of this field. -@field adapterStatus -This field contains the low-level ATA Controller status for a completed IOATACommand. -Values for this field are defined by enum ATAReturnCode. -@field requestSenseDone -A boolean indicating whether sense data was obtained from the ATAPI -device. -@field requestSenseLength -The number of sense data bytes returned from the ATAPI device. -@field ataRegs -This array contains the ATA taskfile register values to be returned when an IOATACommand completes. -The index values for ATA taskfile registers is specified by enum ATARegs. Registers to be returned -are indicated by the bit mask resultmask. See structure ATATaskfile. -*/ -typedef struct ATAResults { - - IOReturn returnCode; - - UInt32 bytesTransferred; - - ATAReturnCode adapterStatus; - - bool requestSenseDone; - UInt32 requestSenseLength; - - UInt32 ataRegs[kMaxATARegs]; - - UInt32 reserved[16]; - -} ATAResults; - - - -class IOATACommand : public IOCDBCommand -{ -public: - - -/*! -@function setPointers -@abstract -Sets the data buffer component of an ATA/ATAPI Command. -@discussion -The client provides an IOMemoryDescriptor object to corresponding -to the client's data or request sense buffer, the maximum data transfer count -and data transfer direction. -@param desc -Pointer to a IOMemoryDescriptor describing the client's I/O buffer. -@param transferCount -Maximum data transfer count in bytes. -@param isWrite -Data transfer direction. (Defined with respect to the device, i.e. isWrite = true -indicates the host is writing to the device. -@param isSense -If isSense is set to false, the IOATACommand's data buffer information is set. If isSense is -set to true, the IOATACommand's request sense buffer information is set. -*/ - void setPointers( IOMemoryDescriptor *desc, - UInt32 transferCount, - bool isWrite, - bool isSense = false ); -/*! -@function getPointers -@abstract -Gets the data buffer component of an ATA/ATAPI Command. -@discussion -The client provides a set of pointers to fields to receive the IOATACommand's -data/request sense buffer pointers. -@param desc -Pointer to a field (IOMemoryDescriptor *) to receive the IOATACommand's IOMemoryDescriptor pointer. -@param transferCount -Pointer to a field (UInt32) to receive the IOATACommand's maximum transfer count. -@param isWrite -Pointer to a field (bool) to receive the IOATACommand's transfer direction. -@param isSense -If isSense is set to true, the IOATACommand's data buffer information is returned. Otherwise, -the IOATACommand's request sense buffer information is returned. -*/ - void getPointers( IOMemoryDescriptor **desc, - UInt32 *transferCount, - bool *isWrite, - bool isSense = false ); -/*! -@function setTimeout -@abstract -Sets the timeout for the command in milliseconds. -@discussion -The IOATAController class will abort a command which does not -complete with in the time interval specified. The client should -set the timeout parameter to zero if they want to suppress -timing. -@param timeout -Command timeout in milliseconds. -*/ - void setTimeout( UInt32 timeoutmS ); - -/*! -@function getTimeout -@abstract -Gets the timeout for the command in milliseconds. -@discussion -This function returns the command timeout previously set by setTimeout(). -@param timeout -Command timeout in milliseconds. -*/ - UInt32 getTimeout(); - -/*! -@function setCallback -@abstract -Sets the callback routine to be invoked when the ATA/ATAPI Command completes. -@param target -Pointer to the object to be passed to the callback routine. This would usually -be the client's (this) pointer. -@param callback -Pointer to the client's function to process the completed command -@param refcon -Pointer to the information required by the client's callback routine to process -the completed command. -*/ - void setCallback( void *target = 0, CallbackFn callback = 0, void *refcon = 0 ); - -/*! -@function execute -@abstract -Submits a ATA/ATAPI command to be executed. -@discussion -Once the execute() function is called, the client should not -invoke any further functions on the ATA/ATAPI Command with the -exception of abort(). - -The execute() function optionally returns sets a unique sequence -number token for the command. If the client intends to use the abort() -method they must retain this sequence number token. -@param sequenceNumber -Pointer to field (UInt32) to receive the sequence number assigned to the ATA/ATAPI -Command. -*/ - bool execute( UInt32 *sequenceNumber = 0 ); - -/*! -@function abort -@abstract -Aborts an executing ATA/ATAPI Command. -@discussion -The client may invoke the abort() method to force the completion of an -executing ATA/ATAPI Command. The client must pass the sequence number -provided when the execute() function was invoked. - -Note: The abort function provides no status on whether or not a -command has been successfully aborted. The client should wait for the -command to actually complete to determine whether the abort completed -successfully. -@param sequenceNumber -The client must pass the sequence number assigned to the command when -the client called the execute() function. -*/ - void abort( UInt32 sequenceNumber ); - -/*! -@function complete -@abstract -Indicates the IOATAController subclass (host adapter driver) has completed an ATA/ATAPI command. -@discussion -Once the complete() function is called, the controller -subclass should make no further accesses to the IOATACommand -being completed. - -A IOATADevice client would not normally call this function. -*/ - void complete(); - -/*! -@function getClientData -@abstract -Returns a pointer to the ATA/ATAPI Command's client data area. -@discussion -The client may allocate storage in the ATA/ATAPI Command for its own use. -See IOATADevice::allocateCmd(). -*/ - void *getClientData(); - -/* -@function getCommandData -@abstract -Returns a pointer to the ATA Command's controller data area -@discussion -This area is allocated for use by the IOATAController subclass (host adapter -driver). The client should not normally access this area. -*/ - - void *getCommandData(); - -/*! -@function getSequenceNumber -@abstract -Returns the sequence number assigned to an executing command. -@discussion -The caller should check the sequence number for 0. This indicates that -the command has completed or has not been processed to the point where -a sequence number has been assigned. -*/ - UInt32 getSequenceNumber(); - -/*! -@function setTaskfile -@abstract -Sets the ATA taskfile register information and ATA/ATAPI protocol for the IOATACommand. -@discussion -See struct ATATaskfile additional information. -@param ATATaskfile -Pointer to an ATATaskfile structure. -*/ - void setTaskfile( ATATaskfile *taskfile ); - -/*! -@function getTaskfile -@abstract -Sets the ATA taskfile register information and ATA/ATAPI protocol for the IOATACommand. -@param ATATaskfile -Pointer to an ATATaskfile structure. -*/ - void getTaskfile( ATATaskfile *taskfile ); - -/*! -@function getProtocol -@abstract -Returns the protocol specified for the ATA/ATAPI Command. -@discussion -The protocol returned is specified by the client in the ATATaskfile structure. See setTaskfile(). -This function is normally used by subclasses of IOATAController to obtain information about the -ATA command being executed. -*/ - ATAProtocol getProtocol(); - -/*! -@function getResultMask -@abstract -Returns the resultMask specified for the ATA/ATAPI Command. -@discussion -The resultMask is specified by the client in the ATATaskfile structure and indicates the ATA taskfile registers -to be returned when the ATA/ATAPI command completes. See setTaskfile(). This function is normally used by -subclasses of IOATAController to obtain information about the ATA command being executed. -*/ - UInt32 getResultMask(); - -/*! -@function getFlags -@abstract -Returns the flags specified for the ATA/ATAPI Command. -@discussion -The flags are specified by the client in the ATATaskfile structure. See setTaskfile(). This function is -normally used by subclasses of IOATAController to obtain information about the ATA command being executed. -*/ - UInt32 getFlags(); - -/*! -@function setCDB -@abstract -Sets the CDB component of a ATA/ATAPI Command. -@param ataCDB -Pointer to a ATACDBInfo structure. -*/ - void setCDB( ATACDBInfo *ataCmd ); - -/*! -@function getCDB -@abstract -Gets the CDB component of a ATA/ATAPI Command. -@param ataCDB -Pointer to an ATACDBInfo structure to receive the ATA/ATAPI Command's cdb information. -*/ - - void getCDB( ATACDBInfo *ataCmd ); - -/*! -@function getResults -@abstract -Gets results from a completed ATA/ATAPI Command. -@discussion -The getResults() function returns the value of the returnCode field of the command results. If -the client is only interested in a pass/fail indication for the command, the client -can pass (ATAResults *)0 as a parameter. -@param results -Pointer to a ATAResults structure to receive the ATA/ATAPI Command's completion information. -*/ - IOReturn getResults( ATAResults *results ); - -/*! -@function setResults -@abstract -Sets the results component of a ATA/ATAPI Command. -@discussion -The setResults() function is used by the IOATAController subclass (host -adapter driver) return results for a ATA/ATAPI Command about to be completed. -@param ataResults Pointer to a ATAResults structure containing -completion information for the ATA/ATAPI Command. - -Completion information is copied into the command, so the caller may -release the ATAResults structure provided when this function returns. -*/ - void setResults( ATAResults *results ); - -/*! -@function getDevice -@abstract -Returns the IOATADevice this command is targeted to. -@param deviceType -The caller should use value kIOATADeviceType. -@discussion -In some cases a IOATACommand is not associated with a specific ATA Unit. This -would be the case for a ATA Bus Reset. In this case getDevice() returns 0. -*/ - IOATADevice *getDevice( IOATAStandardDevice *deviceType ); - -/*! -@function getUnit -@abstract -Returns the unit number for the IOATADevice this command is associated with. -*/ - ATAUnit getUnit(); - -/*! -@function setQueueInfo -@abstract -Sets queuing information for the ATA/ATAPI Command. -@discussion -Each IOATADevice has two queues, a normal Q and a bypass Q. The treatment of the -queues is essentially identical except that the bypass Q is given preference whenever -it has commands available. - -Usually, the client will use the normal Q for regular I/O commands and the bypass Q -to send error recovery commands to the device. -@param queueType -Set to kATAQTypeNormalQ or kATAQTypeBypassQ to indicate which IOATADevice queue the -ATA/ATAPI Command should be routed to. -@param queuePosition -Set to kATAQPositionTail or kATAQPositionHead to indicate whether the ATA/ATAPI Command should -be added to the head to tail for the selected IOATADevice queue. -*/ - void setQueueInfo( UInt32 forQueueType = kATAQTypeNormalQ, UInt32 forQueuePosition = kATAQPositionTail ); - -/*! -@function getQueueInfo -@abstract -Gets queuing information for the ATA Command. -@param queueType -Pointer to a field (UInt32) to receive the queue type previously set for this ATA Command. -@param queuePosition -Pointer to a field (UInt32) to receive the queue position previously set for this ATA Command. -*/ - void getQueueInfo( UInt32 *forQueueType, UInt32 *forQueuePosition = 0 ); - -/*! -@function getCmdType -@abstract -Obtains the underlying 'intent' of an ATA/ATAPI Command. -@discussion -This function provides information on the intent of a ATA/ATAPI -Command. For example, since Aborts, Request Sense and normal Execute commands are -all sent to the executeCommand() function, invoking getCmdType() -will indicate whether a Request Sense, Abort or Normal I/O request is -being processed. - -This information is not normally meaningful to IOATADevice clients. -*/ - UInt32 getCmdType(); - -/*! -@function getOriginalCmd -@abstract -Obtains a 'related' ATA/ATAPI Command. -@discussion -In cases where a ATA command is related to a previous command, this -function will return the original command. For example, if a -Request Sense command (CmdType = kATACommandReqSense)is processed, -then this function can be used to obtain the original command that -caused the check condition. If an Abort command (CmdType = -kATACommandAbort) then this function can be used to obtain the original -command the abort was issued against. - -It this information is not normally meaningful to IOATADevice clients. -*/ - - IOATAStandardCommand *getOriginalCmd(); - -}; - diff --git a/iokit/IOKit/ata/IOATAController_Reference.h b/iokit/IOKit/ata/IOATAController_Reference.h deleted file mode 100644 index 0bf16366c..000000000 --- a/iokit/IOKit/ata/IOATAController_Reference.h +++ /dev/null @@ -1,410 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -/*! -@header IOATAController_Reference.h - -This header defines the IOATAController class. - -IOATAController provides the superclass for the ATA Family. In most -cases, actual controller drivers should be implemented to IOATAStandardDriver -which converts the relatively high-level commands produced by this class -to low-level ATA register commands. - -This class may be useful in cases where the actual ATA device is connected -by some intermediate bus and it would be more efficient for family for that -bus to deal with high-level commands rather than low-level ATA register I/O. -*/ - -class IOATAStandardController : public IOService -{ - -public: - -/*! -@function reset -@abstract -Perform an ATA bus reset. -@discussion -This function requests the IOATAController class to perform an ATA Bus reset. - -The IOATAController class will convert this request into a reset command and -will call the resetCommand() function. - -The reset() function is synchronous, i.e. it will wait for the reset to complete. -*/ - IOReturn reset(); - -protected: - -/*! -@function enableCommands -@abstract -Resume sending I/O commands to your driver. -@discussion -Resumes sending I/O commands to your driver that were previously suspended -by calling disableCommands(). -*/ - void enableCommands(); - -/*! -@function disableCommands -@abstract -Suspend sending I/O commands to your driver. -@discussion -In cases where your executeCommand() member function cannot accept -commands, you may disable further calls by invoking disableCommands(). -Use enableCommands() to resume receiving commands. - -Note: The resetCommand() and cancelCommands() entry points are not -affected by the use of this function. - -Note: The default timeout for disableCommands() is 5s. If this timeout -is exceeded the IOATAController class will call your driver's -disableTimeoutOccurred() function. The default action of this function -is to issue a ATA Bus Reset by calling your driver's resetCommand() -function. -@param timeoutmS -Your driver may override the default timeout -by specifying a timeout value in milliseconds. -*/ - void disableCommands( UInt32 disableTimeoutmS ); - -/*! -@function rescheduleCommand -@abstract -Return a IOATACommand for rescheduling. -@discussion -If your subclass function cannot start processing an otherwise -acceptable IOATACommand, you may have the IOATACommand rescheduled by -calling rescheduleCommand(). A IOATACommand passed to this function -should be treated as 'complete', i.e. you should make no further -accesses to it. - -Note: If you cannot process further commands, you should call the -disableCommands() function to prevent receiving additional commands -until you are ready to accept them. -@param ataCommand -Pointer to IOATACommand your driver needs to reschedule. -*/ - void rescheduleCommand( IOATAStandardCommand *forATACmd ); - - void resetStarted(); - void resetOccurred(); - - -/*! -@function findCommandWithNexus -@abstract -Locate an active IOATACommand using device/tag values. -@discussion -Your subclass can use this function to search for an active -IOATACommand by providing the device/tag values for the command. In -the case of a non-tagged command the second parameter must either be -omitted or set to -1. - -An unsuccessful search will return 0. -@param forDevice -Pointer to an IOATADevice. -wish to search for. -@param tagValue -Optional tag value you wish to search for. -*/ - IOATAStandardCommand *findCommandWithNexus( IOATAStandardDevice *forDevice, UInt32 tagValue = (UInt32)-1 ); - -/*! -@function getDeviceData -@abstract -Obtains a pointer to per-device data allocated by IOATAController. -@discussion -This function returns a pointer to per-device workarea allocated for -your driver's use. The size of this area must be specified in the -during the configure() function. See struct ATAControllerInfo, -field devicePrivateDataSize. -@param forUnit -The unit number of the ata device. -*/ - void *getDeviceData( ATAUnit forUnit ); - -/*! -@function getWorkLoop -@abstract -Returns/provides the IOWorkLoop object that services your driver. -@discussion -If your driver wishes to create its own workloop, you should implement this -function and return the IOWorkLoop for your subclass. Otherwise, if you -return 0, the IOATAController class will create a workloop for your driver. -*/ - virtual IOWorkLoop *getWorkLoop() const; - -/*! -@function getCommandCount -@abstract -Returns the current active command count for your driver. -@discussion -This indicates the number of executeCommands that have been sent to your -driver and have not been completed. -*/ - UInt32 getCommandCount(); - -/*! -@function setCommandLimit -@abstract -Modifies command limit indicated for the IOATADevice device. -@discussion -If the device currently has more than commands outstanding than the new command limit, -additional commands will not be sent to the device. If the command limit is increased, -the additional commands will be sent until the command limit is met. -@param device -Pointer to an IOATADevice. -@param commandLimit -New limit on outstanding executeCommands. -*/ - void setCommandLimit( IOATAStandardDevice *device, UInt32 commandLimit ); - -/*! -@function suspendDevice -@abstract -Stops sending executeCommands to the indicated device. -@discussion -This function causes the IOATAController class to stop sending executeCommands to the -indicated device. -@param forATADevice -Pointer to an IOATADevice for which executeCommand delivery is to be suspended. -*/ - void suspendDevice( IOATAStandardDevice *forATADevice ); - -/*! -@function resumeDevice -@abstract -Resumes sending executeCommands to the indicated device. -@discussion -This function causes the IOATAController class to resume sending executeCommands to an -IOATADevice that was previously suspended. If the IOATADevice was not previously -suspended, then this call has no effect. -@param forATADevice -Pointer to an IOATADevice for which executeCommand delivery is to be resumed. -*/ - void resumeDevice( IOATAStandardDevice *forATADevice ); - -/*! -@function selectDevice -@abstract -Returns a pointer to the IOATADevice device that was suspended the for the -longest amount of time. -@discussion -This function returns a 'hint' as which device to resume to implement fairness -in servicing IOATADevice contending for access to the ATA bus. -*/ - IOATAStandardDevice *selectDevice(); - -protected: - -/*! -@function configure -@abstract -Driver configuration/initialization request. -@discussion -The configure() member function is the first call your subclass will -receive. You should provide the information requested in the -ATAControllerInfo structure and enable your hardware for operation. -If your driver initialized successfully, you should return true, otherwise, -your driver should return false. -@param provider -Pointer to an object (usually IOPCIDevice) which represents the bus of -your device is attached to . Typically your driver will use functions -supplied by this object to access PCI space on your hardware. See -IOPCIDevice for a description of PCI services. -@param controllerInfo -Pointer to a ATAControllerInfo structure. Your driver should provide -the information requested in this structure prior to returning from -the configure() call. -*/ - virtual bool configure( IOService *provider, ATAControllerInfo *controllerInfo ) = 0; - -/*! -@function getProtocolSupported -@abstract -Returns a bit mask of transport protocols this IOATADevice supports. -@discussion -The subclass of IOATAController must return a bit-mask of transport protocols supported. -@param protocolsSupported -Pointer to a (UInt32) to receive a bit mask of transport protocols supported. See enum -ATAProtocol of a list of transport protocols. -*/ - virtual bool getProtocolsSupported( ATAProtocol *protocolsSupported ) = 0; - -/*! -@function executeCommand -@abstract -Execute an IOATACommand. -@discussion -The executeCommand() function is called for all 'routine' I/O requests. -The driver is passed a pointer to an -IOATACommand object. The driver obtains information about the I/O -request by using function calls provided by the IOATACommand -class. -@param ataCommand -Pointer to an IOATACommand. See IOATACommand_Reference for more information. -*/ - virtual void executeCommand( IOATAStandardCommand *forATACmd ) = 0; - -/*! -@function cancelCommand -@abstract -Cancels a IOATACommand previously submitted. -@discussion -The cancelCommand() function is called to inform your subclass to force -completion of an ATA command. - -Your subclass should call the getOriginalCmd() to determine the command -to complete. - -After calling complete() on the original command, you should complete -the IOATACommand passed to the cancelCommand() function - -Note: When a cancelCommand is issued, your subclass may presume that any -activity to remove an active command has already occurred. -@param ataCommand -Pointer to a IOATACommand. See IOATACommand for more information. -*/ - virtual void cancelCommand( IOATAStandardCommand *forATACmd ) = 0; - -/*! -@function resetCommand -@abstract -Request the IOATAController subclass issue an ATA Bus reset. -@discussion -The resetCommand() function indicates you should do an ATA Bus Reset. -After issuing the reset you should complete to IOATACommand passed. - -Note: After you report the IOATACommand Reset complete, you will -receive cancelCommand() requests for all outstanding commands. -@param ataCommand -Pointer to a IOATACommand. See IOATACommand for more information. -*/ - virtual void resetCommand( IOATAStandardCommand *forATACmd ) = 0; - -/*! -@function abortCommand -@abstract -Requests the IOATAController subclass abort a currently executing command. - -Note: In most cases ATA does not provide semantics to cleanly abort an executing -command. In these cases, the subclass may reset the ATA bus to implement this -function. -@param forATACmd -Pointer to an active IOATACommand to be aborted. -*/ - virtual void abortCommand( IOATAStandardCommand *forATACmd ) = 0; - -/*! -@function calculateTiming -Convert ATA timing parameters to controller register settings. -@discussion -The IOATAController subclass is presented with proposed timings. If the subclass -can support the provided timing parameters, it should calculate the corresponding -controller register settings and make them available for future lookup indexed -by the timingProtocol field of the ATATiming structure. If the controller driver -cannot support the indicated timing it should return false as the calculateTiming() -result. -@param deviceNum -The unit number (0/1) of the IOATADevice the timing is to apply to. -@param timing -A pointer to a ATATiming structure containing the parameters for the selected -timing. -*/ - virtual bool calculateTiming( UInt32 deviceNum, ATATiming *timing ) = 0; - - -/*! -@function allocateDevice -@abstract -The IOATAController class informs its subclass of allocation of an ATA device. -@discussion -The IOATAController subclass will be called at its allocateDevice() function when an -ATA device is about to be probed. The subclass should initialize its per-device data at -this time. If the subclass wishes to prevent probing of this device, it should return false -as the result of this function call. - -Note: This is an optional function. Your driver is not required to implement it. -@param unit -The ATA unit number of the device about to be allocated. -*/ - virtual bool allocateDevice( ATAUnit unit ); - -/*! -@function deallocateDevice -@abstract -The IOATAController class informs its subclass of deallocation of an ATA device. -@discussion -The IOATAController subclass will be called at its deallocateDevice() function when -an ATA device is about to be deallocated. The subclass must insure that there will -be no further access to the per-device data allocated to this device. - -Note: This is an optional function. Your driver is not required to implement it. -@param unit -The ATA unit number of the device about to be deallocated. -*/ - virtual void deallocateDevice( ATAUnit unit ); - -/*! -@function disableTimeoutOccurred -@abstract -Indicates the IOATAController subclass has suspended commands too long. -@discussion -The IOATAController class will timeout disableCommand() requests -to preclude the possibility of a hung ATA bus. If a timeout occurs, -then disableTimeoutOccurred() will be called. The default action of this -routine is to do a ATA Bus Reset by calling resetCommand(). Your -subclass may choose to modify the default behavior of this routine to do -additional adapter specific error recovery. -*/ - virtual void disableTimeoutOccurred(); - -/*! -@function enableControllerInterrupts -@abstract -Indicates the IOATAController subclass should enables its controller interrupt. -@discussion -The default implementation of this function enables all interrupt sources -associated with the current workloop. If the subclass needs more precise -control of its interrupt sources it should replace the implementation of -this function with its own. -*/ - virtual void enableControllerInterrupts(); - -/*! -@function disableControllerInterrupts -@abstract -Indicates the IOATAController subclass should disable its controller interrupt. -@discussion -The default implementation of this function disables all interrupt sources -associated with the current workloop. If the subclass needs more precise -control of its interrupt sources it should replace the implementation of -this function with its own. -*/ - virtual void disableControllerInterrupts(); - -}; - diff --git a/iokit/IOKit/ata/IOATADeviceInterface.h b/iokit/IOKit/ata/IOATADeviceInterface.h deleted file mode 100644 index c4f9c8ed5..000000000 --- a/iokit/IOKit/ata/IOATADeviceInterface.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * IOATADeviceInterface.h - * - */ -#ifndef _IOATADEVICEINTERFACE_H -#define _IOATADEVICEINTERFACE_H - -#include - -#include -#include -#include -#include -#include - -#endif diff --git a/iokit/IOKit/ata/IOATADevice_Reference.h b/iokit/IOKit/ata/IOATADevice_Reference.h deleted file mode 100644 index 266be5d49..000000000 --- a/iokit/IOKit/ata/IOATADevice_Reference.h +++ /dev/null @@ -1,408 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! -@header IOATADevice_Reference.h - -This header defines the IOATADevice class. - -The ATA/ATAPI framework creates instances of this class to -represent each valid ATA/ATAPI device detected during -ATA bus scanning. When an instance of this class is registered with -IOKit, the instance will be presented to clients which -'match' the IOATADevice class. -*/ - -/*! -@enum ATADeviceType -Defines ATA/ATAPI Device types. -@constant kATADeviceNone -Indicates no device installed. -@constant kATADeviceATA -Indicates ATA type device, i.e. packet protocols not supported. -@constant kATADeviceATAPI -Indicates ATAPI type device, i.e. packet protocols supported. -*/ -enum ATADeviceType { - - kATADeviceNone, - kATADeviceATA, - kATADeviceATAPI, - -}; - -/*! -@enum ATATimingProtocol -Defines supported transport timing. See getTimingsSupported(), selectTiming(). -@constant kATATimingPIO -Indicates transport timing is for Programmed I/O. -@constant kATATimingDMA -Indicates transport timing is for DMA. -@constant kATATimingDMA33 -Indicates transport timing is for Ultra DMA/33. -@constant kATATimingDMA66 -Indicates transport timing is for Ultra DMA/66. -@constant kATAMaxTimings -Indicates number of timing protocols defined. -*/ -enum ATATimingProtocol -{ - kATATimingPIO = (1 << 0), - kATATimingDMA = (1 << 1), - kATATimingUltraDMA33 = (1 << 2), - kATATimingUltraDMA66 = (1 << 3), - kATAMaxTimings = 4, - -}; - -/*! -@enum ATAProtocol -Defines supported transport protocols. See getProtocolsSupported(). -@constant kATAProtocolNone -Indicates no transport protocol defined. -@constant kATAProtocolSetRegs -Indicates the transport driver should do a Set ATA Registers operation. For this -protocol, the transport driver sets the requested taskfile registers as indicated -in the ATATaskfile structure and then reads back the taskfile registers requested. -The transport presumes the device will not generate an interrupt as a result -of this operation. -@constant kATAProtocolPIO -Indicates the transport driver should do a Programmed I/O operation. For this -protocol, the transport driver sets the requested taskfile registers, and transfers -data to/from the IOATADevice via Programmed I/O operations. The IOATADevice client -can control the direction/amount data transferred by using setPointers() function. -The client can indicate a zero data transfer length to implement non-data transfer -commands such as power-management and set features. -@constant kATAProtocolDMA -Indicates the transport driver should do a DMA I/O operation to the device. For this -protocol, the transport driver sets the requested taskfile registers, and transfers -data to/from the IOATADevice via DMA operations. -@constant kATAProtocolDMAQueued -Indicates the transport driver should do DMA Queued I/O operations. In this case, -the driver will queue multiple I/O operations at the IOATADevice. Both the device -and the transport driver must support this protocol. -@constant kATAProtocolDMAQueueRelease -Indicates the transport driver should do DMA Queued I/O operations with bus release. -In this case, the driver will queue multiple I/O operations at the IOATADevice. In -addition this protocol allows Overlap between both devices on the ATA Bus. -@constant kATAProtocolATAPIPIO -Indicates the transport driver should send an use ATAPI packet protocol and transfer -data to/from the device via PIO cycles. -@constant kATAProtocolATAPIDMA -Indicates the transport driver should send an use ATAPI packet protocol and transfer -data to/from the device via DMA cycles. -*/ -enum ATAProtocol { - - kATAProtocolNone = 0, - kATAProtocolSetRegs = (1 << 0), - kATAProtocolPIO = (1 << 1), - kATAProtocolDMA = (1 << 2), - kATAProtocolDMAQueued = (1 << 3), - kATAProtocolDMAQueuedRelease = (1 << 4), - - kATAProtocolATAPIPIO = (1 << 16), - kATAProtocolATAPIDMA = (1 << 17), - -}; - -/*! -@typedef ATATiming -@abstract -Provides the low-level cycle times for the transport timing indicated. -@discussion -See enum ATATimingProtocols for a list of transport timing protocols. -@field timingProtocol -Indicates transport timing the structure refers to. See enum ATATimingProtocol -for a list of transport timings. -@field mode -Indicates the ATA DMA/PIO mode supported. The mode is a number indicating preset -timings for a particular set of timings as defined by the ATA specification. -@field minDataAccess -The minimum time (in nS) that IOW-/IOR- indicates that the data is valid for 16-bit -data transfers. This field does not apply for Ultra/33 and Ultra/66 timings. -@field minDataCycle -The minimum time (in nS) that a full 16-bit data transfer will take, i.e. the time -between consecutive assertions of IOW-/IOR-. For Ultra/33 and Ultra/66 timings -this field indicates the average single cycle time. -@field minCmdAccess -The minimum time (in nS) that IOW-/IOR- indicates that the data is valid for 8-bit -pio command transfers. -@field minCmdCycle -The minimum time (in nS) that a full 8-bit pio data transfer will take, i.e. the time -between consecutive assertions of IOW-/IOR-. -*/ -typedef struct ATATiming { - - ATATimingProtocol timingProtocol; - - UInt32 featureSetting; - - UInt32 mode; - UInt32 minDataAccess; - UInt32 minDataCycle; - UInt32 minCmdAccess; - UInt32 minCmdCycle; - UInt32 reserved_3[9]; - -} ATATiming; - -class IOATAStandardDevice : public IOATADevice -{ -public: - -/*! -@function allocCommand -@abstract -Allocates an IOATACommand object for this device. -@discussion -The client uses the allocCommand() member function to allocate IOATACommand(s) -for an IOATADevice. The client then uses the member functions of -the IOATACommand to initialize it and send it to the device. A completed IOATACommand -may be reused for subsequent I/O requests or returned to the ATA/ATAPI Family. -@param deviceType -Always specify kIOATADevice. -@param clientDataSize -The client may indicate the size of a per-command data area for its own -use. -*/ - IOATACommand *allocCommand( IOATADevice *deviceType, UInt32 clientDataSize = 0 ); - -/*! -@function getUnit -@abstract -Returns the ATA unit number corresponding to this device. -*/ - ATAUnit getUnit(); - -/*! -@function getDeviceType -@abstract -Returns the type of the corresponding ATA/ATAPI device. -@discussion -See enum ATADeviceType for return values for this function. -*/ - ATADeviceType getDeviceType(); - -/*! -@function getIdentifyData -@abstract -Returns the ATA/ATAPI Identify data for the IOATADevice -@discussion -Identify data is from the results of the last ATA bus probe. -@param identifyBuffer -Pointer to a 512-byte data buffer to receive the ATA/ATAPI Identify data. -*/ - bool getIdentifyData( ATAIdentify *identifyBuffer ); - -/*! -@function getInquiryData -@abstract -Returns ATAPI Inquiry data for the IOATADevice. -@discussion -Inquiry data returned is from the results of the last ATA bus probe. -@param inquiryBufSize -Size of the buffer supplied. -@param inquiryBuffer -Pointer to a buffer to receive the Inquiry data. -*/ - bool getInquiryData( UInt32 inquiryBufSize, ATAPIInquiry *inquiryBuffer ); - -/*! -@function getDeviceCapacity -@abstract -Returns the block count and block size of the ATA/ATAPI device. -@discussion -This function returns the capacity as returned by the ATA Identify command for ATA devices, -and the Read Device Capacity for ATAPI devices. The client should use caution in interpreting -the results of this function since the results are based on the last ATA bus scan. -@param blockMax -Pointer to a (UInt32) to receive the maximum addressable block on the device. Note: The device -block count is one greater than the maximum addressable block number. -@param blockSize -Pointer to a (UInt32) to receive the block size of the device in bytes. -*/ - bool getDeviceCapacity( UInt32 *blockMax, UInt32 *blockSize ); - - -/*! -@function getProtocolSupported -@abstract -Returns a bit mask of transport protocols this IOATADevice supports. -@discussion -There is no guarantee that a particular device/driver combination will support -all transport protocols defined. The IOATADevice client must use this function -to determine which ATAProtocol values are valid for this device. -@param protocolsSupported -Pointer to a (UInt32) to receive a bit mask of transport protocols supported. See enum -ATAProtocol of a list of transport protocols. -*/ - bool getProtocolsSupported( ATAProtocol *protocolsSupported ); - -/*! -@function getTimingsSupported -@abstract -Returns a bit mask of transport timings this IOATADevice supports -@discussion -There is no guarantee that a particular device/driver combination will support -all transport timings defined. The IOATADevice client must use this function -to determine which ATATimingProtocol values are valid for this device. -@param protocolsSupported -Pointer to a (UInt32) to receive a bit mask of transport timings supported. See enum -ATATimingProtocol of a list of transport timings. -*/ - bool getTimingsSupported( ATATimingProtocol *timingsSupported ); - -/*! -@function getTimingSelected -@abstract -Returns the last transport timing selected for the device -@param timingProtocol -Pointer to a (UInt32) to receive the current timing protocol selected. See enum ATATimingProtocol -for a list of transport timing protocols. -*/ - bool getTimingSelected( ATATimingProtocol *timingProtocol ); - -/*! -@function getTiming -@abstract -Returns the parameters for the transport timing indicated. -@discussion -If the transport/device combination does not support the transport timing -indicated, then this function will return false. See getTimingsSupported() -to obtain a bit mask of supported timings. -@param timingProtocol -Pointer to a (UInt32) which the client has set to the timing protocol whose parameters are -to be obtained. -@param timing -Pointer to a (struct ATATiming) to receive the parameters (cycle timings) for the requested -timing. -*/ - bool getTiming( ATATimingProtocol *timingProtocol, ATATiming *timing ); - -/*! -@function getATAPIPktInt -@abstract -Returns whether the an ATAPI device will generate an Interrupt prior to signal it is ready -to request a command packet. -@discussion -A return value of (true) will indicates the device will generate a packet transfer interrupt. -This function would not normally need to be used by the IOATADevice client. It is for use -by the transport driver. -*/ - bool getATAPIPktInt(); - -/*! -@function selectTiming -@abstract -Selects the transport timing to be used for this IOATADevice. -@discussion -The IOATADevice client must issue the selectTiming() function when initializing an IOATADevice and -after an ATA Bus Reset event. -@param timingProtocol -The transport timing to be selected for the device. See getTimingsSupported() for transport timings -supported by the transport/device combination. -@param fNotifyMsg -If fNotifyMsg is set to false, selectTiming() operates a synchronous call, i.e. it blocks the -client until it completes. If the client needs to call this function during an event such as -an ATA Bus Reset, it must use the asynchronous version of this function by setting fNotifyMsg -to true. In this case the client will be notified via a message when this function has -completed. -*/ - bool selectTiming( ATATimingProtocol timingProtocol, bool fNotifyMsg = false ); - -/*! -@function holdQueue -@abstract -Suspends sending additional IOATACommand to this device. -@discussion -holdQueue() may only be called from the IOATADevice workloop. The client -is guaranteed to be running in this context during a message() notification. - -holdQueue() has no effect on commands already passed to the host adapter. One -or more commands may complete after the queue is held. See notifyIdle() -@param queueType -Perform action on the indicated queue. See enum ATAQueueType in IOATACommand. -*/ - void holdQueue( UInt32 queueType ); - -/*! -@function releaseQueue -@abstract -Resumes sending IOATACommands to the IOATADevice. -@discussion -If the device queue was not held, releaseQueue() has no effect. - -releaseQueue() may only be called from the IOATADevice workloop. This is guaranteed -to be the case after a IOATACommand completion of after a message() notification. -@param queueType -Perform action on the indicated queue. See enum ATAQueueType in IOATACommand. -*/ - void releaseQueue( UInt32 queueType ); - -/*! -@function flushQueue -@abstract -Returns any commands on the IOATADevice's pending work queue. -@discussion -flushQueue() may only be called from the IOATADevice workloop. This is -guaranteed to be the case after a IOATACommand completion of after a -message() notification. - -All pending command are completed prior to flushQueue() returning to the caller. - -flushQueue() has no effect on commands already passed to the host adapter. One -or more commands may complete after the queue is flushed. See notifyIdle(). -@param queueType -Perform action on the indicated queue. See enum ATAQueueType in IOATACommand. -@param rc -The return code of any flushed commands is set to (rc). -*/ - void flushQueue( UInt32 queueType, IOReturn rc ); - -/*! -@function notifyIdle -@abstract -Notifies the client when all active commands on an ATA device have completed. -@discussion -notifyIdle() may only be called from the IOATADevice workloop. This is guaranteed -to be the case after a IOATACommand completion of after a message() notification. - -Only one notifyIdle() call may be active. Any outstanding notifyIdle() calls may -be cancelled by calling notifyIdle() with no parameters. -@param target -Object to receive the notification. Normally the client's (this) pointer. -@param callback -Pointer to a callback routine of type CallbackFn. -@param refcon -Pointer to client's private data. -*/ - void notifyIdle( void *target = 0, CallbackFn callback = 0, void *refcon = 0 ); - -/*! -@function getWorkLoop -@abstract -Returns the IOWorkLoop object that services this IOATADevice. -*/ -IOWorkloop *getWorkLoop(); - -}; diff --git a/iokit/IOKit/ata/IOATADriver_Reference.h b/iokit/IOKit/ata/IOATADriver_Reference.h deleted file mode 100644 index 3cf67c805..000000000 --- a/iokit/IOKit/ata/IOATADriver_Reference.h +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! -@header IOATAStandardDriver_Reference.h - -This header defines the IOATAStandardDriver class. - -This class provides a standard ATA/ATAPI driver implementation. - -In most cases ATA controller drivers should be implemented to this class since -it relieves the controller driver writer from having to implement most of the ATA/ATAPI -protocol. -*/ - -/*! -@typedef ATAControllerInfo -Parameter structure passed for configure() function. -@field maxDevicesSupported -Maximum ATA devices supported per bus. Normally set to (2). -@field devicePrivateDataSize -Size of per unit storage (in bytes) available to the controller driver. See getDeviceData. -@field commandPrivateDataSize -Size of per command storage (in bytes) available to the controller driver. See getCommandData. -@field disableCancelCommands -Normally set to false by the controller driver. -*/ -typedef struct ATAControllerInfo { - - UInt32 maxDevicesSupported; - - UInt32 devicePrivateDataSize; - UInt32 commandPrivateDataSize; - - bool disableCancelCommands; - - UInt32 reserved[64]; - -} ATAControllerInfo; - -class IOATAStandardDriver : public IOATAStandardController -{ -protected: - -/*! -@function writeATAReg -@abstract -ATA taskfile register write function. -@discussion -The controller driver must implement this function by writing the indicated -ATA register. -@param regIndex -Register index values are defined by enum ATARegs. See IOATADevice_Reference. -@param regValue -Register value. For the ATA Data Register this is a 16-bit value. For other registers, -this is an 8-bit value. -*/ - virtual void writeATAReg( UInt32 regIndex, UInt32 regValue ) = 0; - -/*! -@function readATAReg -ATA taskfile register read function. -@discussion -The controller driver must implement this function by reading the indicated ATA register and returning the register value as a (UInt32). -@param regIndex -Register index values are defined by enum ATARegs. See IOATADevice_Reference. -*/ - virtual UInt32 readATAReg( UInt32 regIndex ) = 0; - -/*! -@function selectTiming -Select ATA timing parameters. -@discussion -The controller driver will be called at this entry point to indicate the timing to use -the next time the indicated device is selected. See newDeviceSelected(). -@param deviceNum -The unit number (0/1) of the IOATADevice the timing is to apply to. -@param timingProtocol -The timing protocol to use the next time the device is selected. See enum ATATimingProtocol in -IOATADevice_Reference. - -Note:The controller driver should have calculated and cached the necessary -controller register settings when the timing parameters were presented by the -calculateTiming() function. -*/ - virtual bool selectTiming( ATAUnit deviceNum, ATATimingProtocol timingProtocol ) = 0; - -/*! -@function calculateTiming -Convert ATA timing parameters to controller register settings. -@discussion -The controller driver is presented with proposed timings. If the controller driver -can support the provided timing parameters, it should calculate the corresponding -controller register settings and make them available for future lookup indexed -by the timingProtocol field of the ATATiming structure. If the controller driver -cannot support the indicated timing it should return false as the calculateTiming() -result. -@param deviceNum -The unit number (0/1) of the IOATADevice the timing is to apply to. -@param timing -A pointer to a ATATiming structure containing the parameters for the selected -timing. -*/ - virtual bool calculateTiming( UInt32 deviceNum, ATATiming *timing ) = 0; - -/*! -@function programDMA -Program the controller DMA hardware. -@discussion -The controller driver is presented with an IOATACommand and should use the -IOATACommand's getPointers() function to obtain the command's IOMemoryDescriptor, -transfer length and transfer direction. The controller driver then should -use IOMemoryCursor functions to obtain the physical transfer list for -the data buffer. -@param cmd -Pointer to an IOATACommand. -*/ - virtual bool programDma( IOATAStandardCommand *cmd ); - -/*! -@function startDma -Start the controller DMA hardware. -@discussion -The controller driver should start the controller's DMA hardware with settings -corresponding to the last programDma() function call. -@param cmd -Pointer to an IOATACommand. This will normally be the same command that was previously -presented during the programDma() call. -*/ - virtual bool startDma( IOATAStandardCommand *cmd ); - -/*! -@function stopDma -Stop the controller DMA hardware. -@discussion -The controller driver should stop the controller's DMA hardware and return the -current transfer count. -@param cmd -Pointer to an IOATACommand. This will normally be the same command that was previously -presented during the programDma() call. -*/ - virtual bool stopDma( IOATAStandardCommand *cmd, UInt32 *transferCount ); - -/*! -@function resetDma -Reset the controller DMA hardware. -@discussion -The controller driver should unconditionally stop the controller's DMA hardware. -*/ - virtual bool resetDma(); - -/*! -@function checkDmaActive -Return the state of the controller's DMA hardware. -@discussion -This function should return true if the controller's DMA channel is active, i.e. there -is a non-zero transfer count and false if the transfer count has been met. -*/ - virtual bool checkDmaActive(); - -/*! -@function newDeviceSelected -Indicates that a new ATA unit is to be selected. -@discussion -The controller driver should do any controller operation associated with selecting -a new ata unit. -*/ - virtual void newDeviceSelected( IOATAStandardDevice *newDevice ); - -/*! -@function interruptOccurred -Indicates that a controller interrupt occurred. -@discussion -This function will be called prior to the ATA standard driver begins processing -the interrupt event. A controller which 'latches' interrupt events should clear -the interrupting condition and then call the ATA standard driver interrupt handler -by calling super::interruptOccurred(). -*/ - virtual void interruptOccurred(); - -/*! -@function configure -@abstract -Driver configuration/initialization request. -@discussion -The configure() member function is the first call your subclass will -receive. You should provide the information requested in the -ATAControllerInfo structure and enable your hardware for operation. -If your driver initialized successfully, you should return true, otherwise, -your driver should return false. -@param provider -Pointer to an object (usually IOPCIDevice) which represents the bus of -your device is attached to . Typically your driver will use functions -supplied by this object to access PCI space on your hardware. See -IOPCIDevice for a description of PCI services. -@param controllerInfo -Pointer to a ATAControllerInfo structure. Your driver should provide -the information requested in this structure prior to returning from -the configure() call. -*/ - virtual bool configure( IOService *provider, ATAControllerInfo *controllerInfo ) = 0; - -}; - diff --git a/iokit/IOKit/ata/IOATAStandardInterface.h b/iokit/IOKit/ata/IOATAStandardInterface.h deleted file mode 100644 index c1a9bf6b0..000000000 --- a/iokit/IOKit/ata/IOATAStandardInterface.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * IOATAStandardInterface.h - * - */ -#ifndef _IOATASTANDARDINTERFACE_H -#define _IOATASTANDARDINTERFACE_H - -#include - -#include -#include -#include -#include -#include -#include - -#endif diff --git a/iokit/IOKit/ata/Makefile b/iokit/IOKit/ata/Makefile deleted file mode 100644 index b8ee2c137..000000000 --- a/iokit/IOKit/ata/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -export MakeInc_cmd=${SRCROOT}/makedefs/MakeInc.cmd -export MakeInc_def=${SRCROOT}/makedefs/MakeInc.def -export MakeInc_rule=${SRCROOT}/makedefs/MakeInc.rule -export MakeInc_dir=${SRCROOT}/makedefs/MakeInc.dir - -IOKIT_FRAMEDIR = $(FRAMEDIR)/IOKit.framework/Versions/A -export INCDIR = $(IOKIT_FRAMEDIR)/Headers -export LCLDIR = $(IOKIT_FRAMEDIR)/PrivateHeaders - -include $(MakeInc_cmd) -include $(MakeInc_def) - -MD_DIR = ata -NOT_EXPORT_HEADERS = IOATADevice_Reference.h IOATACommand_Reference.h \ - IOATAController_Reference.h IOATADriver_Reference.h \ - IOATAStandardInterface.h - -INSTINC_SUBDIRS = -INSTINC_SUBDIRS_PPC = -INSTINC_SUBDIRS_I386 = ata-device - -EXPINC_SUBDIRS = ${INSTINC_SUBDIRS} -EXPINC_SUBDIRS_PPC = ${INSTINC_SUBDIRS_PPC} -EXPINC_SUBDIRS_I386 = ${INSTINC_SUBDIRS_I386} - -ALL_HEADERS = $(shell (cd $(SOURCE); echo *.h)) - -INSTALL_MD_LIST = -INSTALL_MD_LCL_LIST = "" -INSTALL_MD_DIR = $(MD_DIR) - -EXPORT_MD_LIST = $(filter-out $(NOT_EXPORT_HEADERS), $(ALL_HEADERS)) -EXPORT_MD_DIR = IOKit/$(MD_DIR) - -include $(MakeInc_rule) -include $(MakeInc_dir) diff --git a/iokit/IOKit/ata/ata-device/ATACommand.h b/iokit/IOKit/ata/ata-device/ATACommand.h deleted file mode 100644 index d1581a2df..000000000 --- a/iokit/IOKit/ata/ata-device/ATACommand.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * ATACommand.h - * - */ - -#ifndef _ATACOMMAND_H -#define _ATACOMMAND_H - - -enum ATADeviceType -{ - kATADeviceNone, - kATADeviceATA, - kATADeviceATAPI, -}; - - -enum ATATimingProtocol -{ - kATATimingPIO = (1 << 0), - kATATimingDMA = (1 << 1), - kATATimingUltraDMA33 = (1 << 2), - kATATimingUltraDMA66 = (1 << 3), - kATAMaxTimings = 4, - -}; - -enum ATAProtocol -{ - kATAProtocolNone = 0, - kATAProtocolSetRegs = (1 << 0), - kATAProtocolPIO = (1 << 1), - kATAProtocolDMA = (1 << 2), - kATAProtocolDMAQueued = (1 << 3), - kATAProtocolDMAQueuedRelease = (1 << 4), - - kATAProtocolATAPIPIO = (1 << 16), - kATAProtocolATAPIDMA = (1 << 17), -}; - - - -typedef struct ATATiming -{ - enum ATATimingProtocol timingProtocol; - - UInt32 featureSetting; - - UInt32 mode; - UInt32 minDataAccess; - UInt32 minDataCycle; - UInt32 minCmdAccess; - UInt32 minCmdCycle; - UInt32 reserved_3[9]; -} ATATiming; - - -enum ATATagType -{ - kATATagTypeNone = 0, - kATATagTypeSimple, -}; - -enum ATAReturnCode -{ - kATAReturnSuccess, - kATAReturnNotSupported, - kATAReturnNoResource, - kATAReturnRetryPIO, - kATAReturnBusyError, - kATAReturnInterruptTimeout, - kATAReturnStatusError, - kATAReturnProtocolError, - kATAReturnDMAError, - kATAReturnBusReset, -}; - -#define ATARegtoMask(reg) (1<<(reg)) - -typedef struct ATATaskfile -{ - enum ATAProtocol protocol; - - UInt32 flags; - - UInt8 tagType; - UInt32 tag; - - UInt32 resultmask; - - UInt32 regmask; - UInt32 ataRegs[kMaxATARegs]; - -} ATATaskfile; - - -enum ATACmdFlags -{ - kATACmdFlagTimingChanged = 0x00000001, -}; - -typedef struct ATACDBInfo -{ - - UInt32 cdbFlags; - - UInt32 cdbLength; - UInt8 cdb[16]; - - UInt32 reserved[16]; -} ATACDBInfo; - - -enum ATACDBFlags -{ -}; - -typedef struct ATAResults -{ - IOReturn returnCode; - - UInt32 bytesTransferred; - - enum ATAReturnCode adapterStatus; - - Boolean requestSenseDone; - UInt32 requestSenseLength; - - UInt32 ataRegs[kMaxATARegs]; - - UInt32 reserved[16]; -} ATAResults; - - -#endif diff --git a/iokit/IOKit/ata/ata-device/ATADevice.h b/iokit/IOKit/ata/ata-device/ATADevice.h deleted file mode 100644 index af79e5404..000000000 --- a/iokit/IOKit/ata/ata-device/ATADevice.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * ATADevice.h - * - */ - -#ifndef _ATADEVICE_H -#define _ATADEVICE_H - -#define kDefaultInquirySize 255 - -typedef UInt32 ATAUnit; - - -enum ATADeviceTimeouts -{ - kATATimerIntervalmS = 500, - kATAProbeTimeoutmS = 5000, - kATAResetIntervalmS = 3000, - kATAAbortTimeoutmS = 5000, - kATAReqSenseTimeoutmS = 5000, - kATADisableTimeoutmS = 5000, - kATAResetPollIntervalmS = 50, - kATAResetTimeoutmS = 25000, - kATABusyTimeoutmS = 10, - kATADRQTimeoutmS = 10, -}; - -enum ATAClientMessage -{ - kATAClientMsgNone = 0x00005000, - kATAClientMsgDeviceAbort, - kATAClientMsgDeviceReset, - kATAClientMsgBusReset, - kATAClientMsgSelectTiming, - - kATAClientMsgDone = 0x80000000, -}; - -enum ATAQueueType -{ - kATAQTypeNormalQ = 0, - kATAQTypeBypassQ = 1, -}; - -enum ATAQueuePosition -{ - kATAQPositionTail = 0, - kATAQPositionHead = 1, -}; - - -#define kATAPropertyProtocol "ATA Protocol" /* IOCString */ -#define kATAPropertyDeviceNumber "ATA Device Number" /* OSNumber */ -#define kATAPropertyDeviceType "ATA Device Type" /* IOCString */ -#define kATAPropertyDeviceId "ATA Device Id" /* OSNumber */ -#define kATAPropertyModelNumber "ATA Device Model Number" /* IOCString */ -#define kATAPropertyFirmwareRev "ATA Device Firmware Revision" /* IOCString */ -#define kATAPropertyVendorName "ATA Device Vendor Name" /* IOCString */ -#define kATAPropertyProductName "ATA Device Product Name" /* IOCString */ -#define kATAPropertyProductRevision "ATA Device Product Revision" /* IOCString */ -#define kATAPropertyLocation "IOUnit" /* OSNumber */ - -#define kATAMaxProperties 9 - -#define kATAPropertyProtocolATA "ATA" -#define kATAPropertyProtocolATAPI "ATAPI" - -#define kATADeviceTypeDisk "Disk" -#define kATADeviceTypeTape "Tape" -#define kATADeviceTypeCDRom "CDRom" -#define kATADeviceTypeScanner "Scanner" -#define kATADeviceTypeOther "Other" - -#endif diff --git a/iokit/IOKit/ata/ata-device/ATAPublic.h b/iokit/IOKit/ata/ata-device/ATAPublic.h deleted file mode 100644 index a7da0c7e6..000000000 --- a/iokit/IOKit/ata/ata-device/ATAPublic.h +++ /dev/null @@ -1,441 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * ATAPublic.h - * - */ - -#ifndef _ATAPUBLIC_H -#define _ATAPUBLIC_H - -typedef struct ATAIdentify -{ - UInt16 generalConfiguration; - UInt16 logicalCylinders; - UInt16 reserved_1[1]; - UInt16 logicalHeads; - UInt16 reserved_2[2]; - UInt16 logicalSectorsPerTrack; - UInt16 reserved_3[3]; - char serialNumber[20]; - UInt16 reserved_4[3]; - char firmwareRevision[8]; - char modelNumber[40]; - UInt16 multipleModeSectors; - UInt16 reserved_5[1]; - UInt16 capabilities1; - UInt16 capabilities2; - UInt16 pioMode; - UInt16 reserved_6[1]; - UInt16 validFields; - UInt16 currentLogicalCylinders; - UInt16 currentLogicalHeads; - UInt16 currentLogicalSectorsPerTrack; - UInt16 currentAddressableSectors[2]; - UInt16 currentMultipleModeSectors; - UInt16 userAddressableSectors[2]; - UInt16 reserved_7[1]; - UInt16 dmaModes; - UInt16 advancedPIOModes; - UInt16 minDMACycleTime; - UInt16 recDMACycleTime; - UInt16 minPIOCycleTimeNoIORDY; - UInt16 minPIOCyclcTimeIORDY; - UInt16 reserved_8[2]; - UInt16 busReleaseLatency; - UInt16 serviceLatency; - UInt16 reserved_9[2]; - UInt16 queueDepth; - UInt16 reserved_10[4]; - UInt16 versionMajor; - UInt16 versionMinor; - UInt16 commandSetsSupported1; - UInt16 commandSetsSupported2; - UInt16 commandSetsSupported3; - UInt16 commandSetsEnabled1; - UInt16 commandSetsEnabled2; - UInt16 commandSetsDefault; - UInt16 ultraDMAModes; - UInt16 securityEraseTime; - UInt16 securityEnhancedEraseTime; - UInt16 currentAdvPowerMgtValue; - UInt16 reserved_11[35]; - UInt16 removableMediaSupported; - UInt16 securityStatus; - UInt16 reserved_12[127]; -} ATAIdentify; - - - -typedef struct ATAPIInquiry -{ - unsigned char devType; /* 0 Device type, */ - unsigned char devTypeMod; /* 1 Device type modifier */ - unsigned char version; /* 2 ISO/ECMA/ANSI version */ - unsigned char format; /* 3 Response data format */ - unsigned char length; /* 4 Additional Length */ - unsigned char reserved5; /* 5 Reserved */ - unsigned char reserved6; /* 6 Reserved */ - unsigned char flags; /* 7 Capability flags */ - unsigned char vendorName[8]; /* 8-15 Vendor-specific */ - unsigned char productName[16]; /* 16-31 Product id */ - unsigned char productRevision[4]; /* 32-35 Product revision */ - unsigned char vendorSpecific[20]; /* 36-55 Vendor stuff */ - unsigned char moreReserved[40]; /* 56-95 Reserved */ -} ATAInquiry; - -/* - * These are device type qualifiers. We need them to distinguish between "unknown" - * and "missing" devices. - */ -enum -{ - kATAPIDevTypeQualifierConnected = 0x00, /* Exists and is connected */ - kATAPIDevTypeQualifierNotConnected = 0x20, /* Logical unit exists */ - kATAPIDevTypeQualifierReserved = 0x40, - kATAPIDevTypeQualifierMissing = 0x60, /* No such logical unit */ - kATAPIDevTypeQualifierVendorSpecific = 0x80, /* Non-standardized */ - kATAPIDevTypeQualifierMask = 0xE0, -}; - -enum ATAPIDevFlags -{ - kATAPIDevCapRelAdr = 0x80, - kATAPIDevCapWBus32 = 0x40, - kATAPIDevCapWBus16 = 0x20, - kATAPIDevCapSync = 0x10, - kATAPIDevCapLinked = 0x08, - kATAPIDevCapCmdQue = 0x02, - kATAPIDevCapSftRe = 0x01, -}; - -typedef struct ATAPISenseData -{ - unsigned char errorCode; /* 0 Result validity */ - unsigned char segmentNumber; /* 1 Segment number */ - unsigned char senseKey; /* 2 Sense code, flags */ - unsigned char info[4]; /* 3-6 Sense-key specific */ - unsigned char additionalSenseLength; /* 7 Sense length info */ - unsigned char reservedForCopy[4]; /* 8-11 Sense-key specific */ - unsigned char additionalSenseCode; /* 12 What kind of error */ - unsigned char additionalSenseQualifier; /* 13 More error info */ - unsigned char fruCode; /* 14 Field replacable */ - unsigned char senseKeySpecific[2]; /* 15-16 Additional info */ - unsigned char additional[101]; /* 17-26 Additional info */ -} ATASenseData; - -/* - * The high-bit of errorCode signals whether there is a logical - * block. The low value signals whether there is a valid sense - */ -enum ATAErrorCode -{ - kATAPISenseHasLBN = 0x80, /* Logical block number set */ - kATAPISenseInfoValid = 0x70, /* Is sense key valid? */ - kATAPISenseInfoMask = 0x70, /* Mask for sense info */ - kATAPISenseCurrentErr = 0x70, /* Error code (byte 0 & 0x7F */ - kATAPISenseDeferredErr = 0x71, /* Error code (byte 0 & 0x7F */ -}; - -/* - * These bits may be set in the sense key - */ -enum ATAPISenseKeyMasks -{ - kATAPISenseKeyMask = 0x0F, - kATAPISenseILI = 0x20, /* Illegal logical Length */ - kATAPISenseEOM = 0x40, /* End of media */ - kATAPISenseFileMark = 0x80, /* End of file mark */ -}; -/* - * ATA sense codes. (Returned after request sense). - */ -enum ATAPISenseKeys -{ - kATAPISenseNone = 0x00, /* No error */ - kATAPISenseRecoveredErr = 0x01, /* Warning */ - kATAPISenseNotReady = 0x02, /* Device not ready */ - kATAPISenseMediumErr = 0x03, /* Device medium error */ - kATAPISenseHardwareErr = 0x04, /* Device hardware error */ - kATAPISenseIllegalReq = 0x05, /* Illegal request for dev. */ - kATAPISenseUnitAtn = 0x06, /* Unit attention (not err) */ - kATAPISenseDataProtect = 0x07, /* Data protection */ - kATAPISenseBlankCheck = 0x08, /* Tape-specific error */ - kATAPISenseVendorSpecific = 0x09, /* Vendor-specific error */ - kATAPISenseCopyAborted = 0x0a, /* Copy request cancelled */ - kATAPISenseAbortedCmd = 0x0b, /* Initiator aborted cmd. */ - kATAPISenseEqual = 0x0c, /* Comparison equal */ - kATAPISenseVolumeOverflow = 0x0d, /* Write past end mark */ - kATAPISenseMiscompare = 0x0e, /* Comparison failed */ -}; - -enum ATAPIStatus -{ - kATAPIStatusGood = 0x00, - kATAPIStatusCheckCondition = 0x02, - kATAPIStatusConditionMet = 0x04, - kATAPIStatusBusy = 0x08, - kATAPIStatusIntermediate = 0x10, - kATAPIStatusIntermediateMet = 0x0a, - kATAPIStatusReservationConfict = 0x18, - kATAPIStatusCommandTerminated = 0x22, - kATAPIStatusQueueFull = 0x28, -}; - - -enum ATAPIDevTypes -{ - kATAPIDevTypeDirect = 0, /* Hard disk (not CD-ROM) */ - kATAPIDevTypeSequential, /* Magtape or DAT */ - kATAPIDevTypePrinter, /* Printer */ - kATAPIDevTypeProcessor, /* Attached processor */ - kATAPIDevTypeWorm, /* Write-once, read multiple */ - kATAPIDevTypeCDROM, /* CD-ROM */ - kATAPIDevTypeScanner, /* Scanner */ - kATAPIDevTypeOptical, /* Optical disk */ - kATAPIDevTypeChanger, /* Jukebox */ - kATAPIDevTypeComm, /* Communication link */ - kATAPIDevTypeGraphicArts0A, - kATAPIDevTypeGraphicArts0B, - kATAPIDevTypeFirstReserved, /* Reserved sequence start */ - kATAPIDevTypeUnknownOrMissing = 0x1F, - kATAPIDevTypeMask = 0x1F, -}; - - -/* - * ATA command codes. Commands defined as ...6, ...10, ...12, are - * six-byte, ten-byte, and twelve-byte variants of the indicated command. - */ - -/* - * These commands are supported for all devices. - */ -enum ATAPICmds -{ - kATAPICmdChangeDefinition = 0x40, - kATAPICmdCompare = 0x39, - kATAPICmdCopy = 0x18, - kATAPICmdCopyAndVerify = 0x3a, - kATAPICmdInquiry = 0x12, - kATAPICmdLogSelect = 0x4c, - kATAPICmdLogSense = 0x4d, - kATAPICmdModeSelect12 = 0x55, - kATAPICmdModeSelect6 = 0x15, - kATAPICmdModeSense12 = 0x5a, - kATAPICmdModeSense6 = 0x1a, - kATAPICmdReadBuffer = 0x3c, - kATAPICmdRecvDiagResult = 0x1c, - kATAPICmdRequestSense = 0x03, - kATAPICmdSendDiagnostic = 0x1d, - kATAPICmdTestUnitReady = 0x00, - kATAPICmdWriteBuffer = 0x3b, - -/* - * These commands are supported by direct-access devices only. - */ - kATAPICmdFormatUnit = 0x04, - kATAPICmdLockUnlockCache = 0x36, - kATAPICmdPrefetch = 0x34, - kATAPICmdPreventAllowRemoval = 0x1e, - kATAPICmdRead6 = 0x08, - kATAPICmdRead10 = 0x28, - kATAPICmdReadCapacity = 0x25, - kATAPICmdReadDefectData = 0x37, - kATAPICmdReadLong = 0x3e, - kATAPICmdReassignBlocks = 0x07, - kATAPICmdRelease = 0x17, - kATAPICmdReserve = 0x16, - kATAPICmdRezeroUnit = 0x01, - kATAPICmdSearchDataEql = 0x31, - kATAPICmdSearchDataHigh = 0x30, - kATAPICmdSearchDataLow = 0x32, - kATAPICmdSeek6 = 0x0b, - kATAPICmdSeek10 = 0x2b, - kATAPICmdSetLimits = 0x33, - kATAPICmdStartStopUnit = 0x1b, - kATAPICmdSynchronizeCache = 0x35, - kATAPICmdVerify = 0x2f, - kATAPICmdWrite6 = 0x0a, - kATAPICmdWrite10 = 0x2a, - kATAPICmdWriteAndVerify = 0x2e, - kATAPICmdWriteLong = 0x3f, - kATAPICmdWriteSame = 0x41, - -/* - * These commands are supported by sequential devices. - */ - kATAPICmdRewind = 0x01, - kATAPICmdWriteFilemarks = 0x10, - kATAPICmdSpace = 0x11, - kATAPICmdLoadUnload = 0x1B, -/* - * ANSI ATA-II for CD-ROM devices. - */ - kATAPICmdReadCDTableOfContents = 0x43, -}; - - -enum ATARegs -{ - /* - * ATA Register ordinals - */ - kATARegData = 0x00, - kATARegFeatures = 0x01, - kATARegSectorCount = 0x02, - kATARegSectorNumber = 0x03, - kATARegCylinderLow = 0x04, - kATARegCylinderHigh = 0x05, - kATARegDriveHead = 0x06, - kATARegCommand = 0x07, - - kATARegError = 0x01, - kATARegStatus = 0x07, - - kATARegDeviceControl = 0x08, - - kATARegAltStatus = 0x08, - - /* - * ATAPI Register ordinals - */ - kATARegATAPIData = 0x00, - kATARegATAPIFeatures = 0x01, - kATARegATAPIIntReason = 0x02, - kATARegATAPIByteCountLow = 0x04, - kATARegATAPIByteCountHigh = 0x05, - kATARegATAPIDeviceSelect = 0x06, - kATARegATAPICommand = 0x07, - - kATARegATAPIError = 0x01, - kATARegATAPIStatus = 0x07, - - kATARegATAPIDeviceControl = 0x08, - - kATARegATAPIAlternateStatus = 0x08, - - kMaxATARegs = 12, -}; - -enum ATASectorCountQDMA -{ - kATATagBit = 0x08, -}; - - -enum ATAPIIntReason -{ - kATAPIIntReasonCD = 0x01, - kATAPIIntReasonIO = 0x02, - kATAPIIntReasonREL = 0x04, - kATAPIIntReasonTagBit = 0x08, - kATAPIIntReasonTagMask = 0xf8, -}; - -enum ATACommand -{ - kATAModeCHS = 0xa0, - kATAModeLBA = 0xe0, - - kATACommandSetFeatures = 0xef, - - kATACommandIdentify = 0xec, - - kATACommandReadSector = 0x20, - - kATACommandService = 0xa2, - - kATACommandATAPIReset = 0x08, - kATACommandATAPIPacket = 0xa0, - kATACommandATAPIIdentify = 0xa1, -}; - -enum ATAFeatures -{ - kATAFeatureTransferMode = 0x03, - kATATransferModePIODefault = 0x00, // SectorCount settings (or'd w/Mode) - kATATransferModePIOwFC = 0x08, - kATATransferModeDMA = 0x20, - kATATransferModeUltraDMA33 = 0x40, - kATATransferModeMask = 0x07, -}; - - -enum ATAStatus -{ - kATAStatusERR = 0x01, - kATAStatusIDX = 0x02, - kATAStatusECC = 0x04, - kATAStatusDRQ = 0x08, - kATAStatusSC = 0x10, - kATAStatusDF = 0x20, - kATAStatusDRDY = 0x40, - kATAStatusBSY = 0x80, - - kATAStatusSERV = 0x10, - kATAStatusREL = 0x20, - - kATAPIStatusCHK = 0x01, - kATAPIStatusDRQ = 0x08, - kATAPIStatusSERV = 0x10, - kATAPIStatusDMRD = 0x20, - kATAPIStatusDRDY = 0x40, - kATAPIStatusBSY = 0x80, -}; - -enum ATAError -{ - kATAErrorNM = 0x02, - kATAErrorABRT = 0x04, - kATAErrorMCR = 0x08, - kATAErrorIDNF = 0x10, - kATAErrorMC = 0x20, - kATAErrorWP = 0x40, - - kATAPIErrorILI = 0x01, - kATAPIErrorEOM = 0x02, - kATAPIErrorABRT = 0x04, - kATAPIErrorSenseKeyBit = 0x10, - kATAPIErrorSenseKeyMask = 0xf0, -}; - -enum ATADeviceControl -{ - kATADevControlnIEN = 0x02, - kATADevControlSRST = 0x04, -}; - -enum ATASignatures -{ - kATASignatureSectorCount = 0x01, - kATASignatureSectorNumber = 0x01, - kATASignatureCylinderLow = 0x00, - kATASignatureCylinderHigh = 0x00, - - kATAPISignatureCylinderLow = 0x14, - kATAPISignatureCylinderHigh = 0xeb, -}; - - -#endif diff --git a/iokit/IOKit/ata/ata-device/IOATACommand.h b/iokit/IOKit/ata/ata-device/IOATACommand.h deleted file mode 100644 index ad7737fca..000000000 --- a/iokit/IOKit/ata/ata-device/IOATACommand.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * IOATACommand.h - * - */ -#ifndef _IOATACOMMAND_H -#define _IOATACOMMAND_H - -class IOATADevice; -class IOATACommand; - -class IOATACommand : public IOCDBCommand -{ - OSDeclareAbstractStructors(IOATACommand) - -/*------------------Methods provided to IOCDBCommand users -------------------------*/ -public: - /* - * Set/Get IOMemoryDescriptor object to I/O data buffer or sense data buffer. - */ - virtual void setPointers( IOMemoryDescriptor *desc, - UInt32 transferCount, - bool isWrite, - bool isSense = false ) = 0; - - virtual void getPointers( IOMemoryDescriptor **desc, - UInt32 *transferCount, - bool *isWrite, - bool isSense = false ) = 0; - /* - * Set/Get command timeout (mS) - */ - virtual void setTimeout( UInt32 timeoutmS ) = 0; - virtual UInt32 getTimeout() = 0; - - /* - * Set async callback routine. Specifying no parameters indicates synchronous call. - */ - virtual void setCallback( void *target = 0, CallbackFn callback = 0, void *refcon = 0 ) = 0; - - /* - * Set/Get CDB information. (Generic CDB version) - */ - virtual void setCDB( CDBInfo *cdbInfo ) = 0; - virtual void getCDB( CDBInfo *cdbInfo ) = 0; - - /* - * Get CDB results. (Generic CDB version) - */ - virtual IOReturn getResults( CDBResults *cdbResults ) = 0; - - /* - * Get CDB Device this command is directed to. - */ - virtual IOCDBDevice *getDevice( IOCDBDevice *deviceType ) = 0; - - /* - * Command verbs - */ - virtual bool execute( UInt32 *sequenceNumber = 0 ) = 0; - virtual void abort( UInt32 sequenceNumber ) = 0; - virtual void complete() = 0; - - /* - * Get pointers to client and command data. - */ - virtual void *getCommandData() = 0; - virtual void *getClientData() = 0; - - /* - * Get unique sequence number assigned to command. - */ - virtual UInt32 getSequenceNumber() = 0; - -/*------------------ Additional methods provided to IOATACommand users -------------------------*/ -public: - /* - * Set/Get ATA taskfile information. - */ - virtual void setTaskfile( ATATaskfile *taskfile ) = 0; - virtual void getTaskfile( ATATaskfile *taskfile ) = 0; - virtual ATAProtocol getProtocol() = 0; - virtual UInt32 getResultMask() = 0; - virtual UInt32 getFlags() = 0; - - /* - * Set/Get CDB information. (ATA specific version). - */ - virtual void setCDB( ATACDBInfo *scsiCmd ) = 0; - virtual void getCDB( ATACDBInfo *scsiCmd ) = 0; - - /* - * Get/Set CDB results. (ATA specific version). - */ - virtual IOReturn getResults( ATAResults *results ) = 0; - virtual void setResults( ATAResults *results ) = 0; - - /* - * Get ATA Device this command is directed to. - */ - virtual IOATADevice *getDevice( IOATADevice *deviceType ) = 0; - - /* - * Get ATA Target/Lun for this command. - */ - virtual ATAUnit getUnit() = 0; - - /* - * Get/Set queue routing for this command. - */ - virtual void setQueueInfo( UInt32 forQueueType = kATAQTypeNormalQ, UInt32 forQueuePosition = kATAQPositionTail ) = 0; - virtual void getQueueInfo( UInt32 *forQueueType, UInt32 *forQueuePosition = 0 ) = 0; - -}; - -#endif diff --git a/iokit/IOKit/ata/ata-device/IOATADevice.h b/iokit/IOKit/ata/ata-device/IOATADevice.h deleted file mode 100644 index 20396c5e2..000000000 --- a/iokit/IOKit/ata/ata-device/IOATADevice.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * IOATADevice.h - * - * - * Methods in this header provide information about the ATA device - * the device client driver is submitting the ATACommand(s) to. - * - * Note: ATACommand(s) are allocated and freed by methods in this class. - * The remaining methods to setup and submit ATACommands are defined in - * IOATACommand.h - */ - -#ifndef _IOATADEVICE_H -#define _IOATADEVICE_H - -class IOATACommand; - -class IOATADevice : public IOCDBDevice -{ - OSDeclareAbstractStructors(IOATADevice) - -/*------------------Methods provided to IOCDBDevice clients-----------------------*/ -public: - - /* - * Allocate a CDB Command - */ - virtual IOCDBCommand *allocCommand( IOCDBDevice *cdbDevice, UInt32 clientDataSize = 0 ) = 0; - - /* - * Abort all outstanding commands on this device - */ - virtual void abort() = 0; - - /* - * Reset device (also aborts all outstanding commands) - */ - virtual void reset() = 0; - - /* - * Obtain information about this device - */ - virtual void getInquiryData( void *inquiryBuffer, - UInt32 inquiryBufSize, - UInt32 *inquiryDataSize ) = 0; - -/*------------------Additional methods provided to IOATADevice clients-----------------------*/ -public: - /* - * Allocate a ATACommand - */ - virtual IOATACommand *allocCommand( IOATADevice *scsiDevice, UInt32 clientDataSize = 0 ) = 0; - - /* - * Obtain information about this device - */ - virtual ATAUnit getUnit() = 0; - virtual ATADeviceType getDeviceType() = 0; - virtual bool getIdentifyData( ATAIdentify *identifyBuffer ) = 0; - virtual bool getInquiryData( UInt32 inquiryBufSize, ATAPIInquiry *inquiryBuffer ) = 0; - virtual bool getDeviceCapacity( UInt32 *blockMax, UInt32 *blockSize ) = 0; - virtual bool getProtocolsSupported( ATAProtocol *protocolsSupported ) = 0; - virtual bool getTimingsSupported( ATATimingProtocol *timingsSupported ) = 0; - virtual bool getTimingSelected( ATATimingProtocol *timingProtocol ) = 0; - virtual bool getTiming( ATATimingProtocol *timingProtocol, ATATiming *timing ) = 0; - virtual bool getATAPIPktInt() = 0; - - /* - * Select default device timing for this device - */ - virtual bool selectTiming( ATATimingProtocol timingProtocol, bool fNotifyMsg = false ) = 0; - - /* - * Queue management commands - */ - virtual void holdQueue( UInt32 queueType ) = 0; - virtual void releaseQueue( UInt32 queueType ) = 0; - virtual void flushQueue( UInt32 queueType, IOReturn rc ) = 0; - virtual void notifyIdle( void *target = 0, CallbackFn callback = 0, void *refcon = 0 ) = 0; - -}; - -#define kIOATADevice ((IOATADevice *)0) - -#endif diff --git a/iokit/IOKit/ata/ata-device/Makefile b/iokit/IOKit/ata/ata-device/Makefile deleted file mode 100644 index c8b895fcf..000000000 --- a/iokit/IOKit/ata/ata-device/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -export MakeInc_cmd=${SRCROOT}/makedefs/MakeInc.cmd -export MakeInc_def=${SRCROOT}/makedefs/MakeInc.def -export MakeInc_rule=${SRCROOT}/makedefs/MakeInc.rule -export MakeInc_dir=${SRCROOT}/makedefs/MakeInc.dir - -IOKIT_FRAMEDIR = $(FRAMEDIR)/IOKit.framework/Versions/A -export INCDIR = $(IOKIT_FRAMEDIR)/Headers -export LCLDIR = $(IOKIT_FRAMEDIR)/PrivateHeaders - -include $(MakeInc_cmd) -include $(MakeInc_def) - -MD_DIR = ata/ata-device -NOT_EXPORT_HEADERS = - -INSTINC_SUBDIRS = -INSTINC_SUBDIRS_PPC = -INSTINC_SUBDIRS_I386 = - -EXPINC_SUBDIRS = ${INSTINC_SUBDIRS} -EXPINC_SUBDIRS_PPC = ${INSTINC_SUBDIRS_PPC} -EXPINC_SUBDIRS_I386 = ${INSTINC_SUBDIRS_I386} - -ALL_HEADERS = $(shell (cd $(SOURCE); echo *.h)) - -INSTALL_MD_LIST = -INSTALL_MD_LCL_LIST = "" -INSTALL_MD_DIR = $(MD_DIR) - -EXPORT_MD_LIST = $(filter-out $(NOT_EXPORT_HEADERS), $(ALL_HEADERS)) -EXPORT_MD_DIR = IOKit/$(MD_DIR) - -include $(MakeInc_rule) -include $(MakeInc_dir) diff --git a/iokit/IOKit/ata/ata-standard/ATAStandardController.h b/iokit/IOKit/ata/ata-standard/ATAStandardController.h deleted file mode 100644 index 548f53e49..000000000 --- a/iokit/IOKit/ata/ata-standard/ATAStandardController.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * ATAParallelController.h - * - */ - -#ifndef _ATASTANDARDCONTROLLER_H -#define _ATASTANDARDCONTROLLER_H - -class IOSyncer; - -typedef struct ATAControllerInfo -{ - UInt32 maxDevicesSupported; - - UInt32 devicePrivateDataSize; - UInt32 commandPrivateDataSize; - - bool disableCancelCommands; - - UInt32 reserved[64]; - -} ATAControllerInfo; - -/* - * Private for IOATAClass - */ -enum WorkLoopReqType -{ - kWorkLoopInitDevice = 1, - kWorkLoopReleaseDevice, -}; - -enum DispatchAction -{ - kDispatchNextCommand = 1, - kDispatchNextDevice, - kDispatchStop, -}; - -typedef struct WorkLoopRequest -{ - WorkLoopReqType type; - IOSyncer * sync; - bool rc; -} WorkLoopRequest; - -#endif - diff --git a/iokit/IOKit/ata/ata-standard/ATAStandardPrivate.h b/iokit/IOKit/ata/ata-standard/ATAStandardPrivate.h deleted file mode 100644 index e18c7d3ea..000000000 --- a/iokit/IOKit/ata/ata-standard/ATAStandardPrivate.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * ATAPrivate.h - * - */ - -typedef struct EndianTable -{ - UInt32 size; - UInt32 type; -} EndianTable; - -enum -{ - identifyWords_54to58_Valid = 0x0001, - identifyWords_64to70_Valid = 0x0002, - identifyWords_88to88_Valid = 0x0004, - - advPIOModes_Mode3_Supported = 0x0001, - advPIOModes_Mode4_Supported = 0x0002, - - dmaModes_Mode0_Supported = 0x0001, - dmaModes_Mode1_Supported = 0x0002, - dmaModes_Mode2_Supported = 0x0004, - dmaModes_Supported = 0x0007, - - ultraDMAModes_Mode0_Supported = 0x0001, - ultraDMAModes_Mode1_Supported = 0x0002, - ultraDMAModes_Mode2_Supported = 0x0004, - ultraDMAModes_Supported = 0x001f, - - commandSetsSupported2_ValidMask = 0xC000, - commandSetsSupported2_Valid = 0x4000, - - commandSetsSupported2_DMAQueued = 0x0002, - - commandSetsSupported3_ValidMask = 0xC000, - commandSetsSupported3_Valid = 0x4000, - - commandSetsEnabled2_DMAQueued = 0x0002, -}; - -enum -{ - kATAPIPktProtocolMask = 0x0060, - kATAPIPktProtocolSlowDRQ = 0x0000, - kATAPIPktProtocolIntDRQ = 0x0020, - kATAPIPktProtocolFastDRQ = 0x0040, -}; - -typedef struct -{ - UInt32 minDataAccess; - UInt32 minDataCycle; - -} ATAModeTable; - diff --git a/iokit/IOKit/ata/ata-standard/ATAStandardTarget.h b/iokit/IOKit/ata/ata-standard/ATAStandardTarget.h deleted file mode 100644 index 1a39c8bce..000000000 --- a/iokit/IOKit/ata/ata-standard/ATAStandardTarget.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * ATAParallelTarget.h - * - */ - -#ifndef _ATASTANDARDTARGET_H -#define _ATASTANDARDTARGET_H - -class IOATAStandardDevice; - -typedef struct ATATarget -{ - IOATAStandardDevice *device; - UInt32 state; - UInt32 flags; -} ATATarget; - -enum -{ - kStateIdle, - kStateIssue, - kStatePending, - kStateActive, -}; - -enum CDBFlagsInternal -{ - kCDBFlagsEnableTagQueuing = 0x80000000, -}; - - -enum ATACommandType -{ - kATACommandNone = 0, - kATACommandExecute, - kATACommandReqSense, - kATACommandAbort, - kATACommandAbortAll, - kATACommandDeviceReset, - kATACommandBusReset, - kATACommandCancel, -}; - - -#endif diff --git a/iokit/IOKit/ata/ata-standard/IOATAStandardCommand.h b/iokit/IOKit/ata/ata-standard/IOATAStandardCommand.h deleted file mode 100644 index a989824e2..000000000 --- a/iokit/IOKit/ata/ata-standard/IOATAStandardCommand.h +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * IOATACommand.h - * - */ -#ifndef _IOATASTANDARDCOMMAND_H -#define _IOATASTANDARDCOMMAND_H - -class IOATAStandardDevice; -class IOATAStandardCommand; -class IOSyncer; -class IOATAStandardDriver; - -class IOATAStandardCommand : public IOATACommand -{ - OSDeclareDefaultStructors(IOATAStandardCommand) - - friend class IOATAStandardController; - friend class IOATAStandardDevice; - friend class IOATAStandardDriver; - -/*------------------Methods provided to IOCDBCommand users -------------------------*/ -public: - /* - * Set/Get IOMemoryDescriptor object to I/O data buffer or sense data buffer. - */ - void setPointers( IOMemoryDescriptor *desc, - UInt32 transferCount, - bool isWrite, - bool isSense = false ); - - void getPointers( IOMemoryDescriptor **desc, - UInt32 *transferCount, - bool *isWrite, - bool isSense = false ); - /* - * Set/Get command timeout (mS) - */ - void setTimeout( UInt32 timeoutmS ); - UInt32 getTimeout(); - - /* - * Set async callback routine. Specifying no parameters indicates synchronous call. - */ - void setCallback( void *target = 0, CallbackFn callback = 0, void *refcon = 0 ); - - /* - * Set/Get CDB information. (Generic CDB version) - */ - void setCDB( CDBInfo *cdbInfo ); - void getCDB( CDBInfo *cdbInfo ); - - /* - * Get CDB results. (Generic CDB version) - */ - IOReturn getResults( CDBResults *cdbResults ); - - /* - * Get CDB Device this command is directed to. - */ - IOCDBDevice *getDevice( IOCDBDevice *deviceType ); -// #define kIOCDBDevice ((IOCDBDevice *)0) - - /* - * Command verbs - */ - bool execute( UInt32 *sequenceNumber = 0 ); - void abort( UInt32 sequenceNumber ); - void complete(); - - /* - * Get pointers to client and command data. - */ - void *getCommandData(); - void *getClientData(); - - /* - * Get unique sequence number assigned to command. - */ - UInt32 getSequenceNumber(); - -/*------------------ Additional methods provided to IOATACommand users -------------------------*/ -public: - /* - * Set/Get ATA taskfile information. - */ - void setTaskfile( ATATaskfile *taskfile ); - void getTaskfile( ATATaskfile *taskfile ); - ATAProtocol getProtocol(); - UInt32 getResultMask(); - UInt32 getFlags(); - - /* - * Set/Get CDB information. (ATA specific version). - */ - void setCDB( ATACDBInfo *ataCmd ); - void getCDB( ATACDBInfo *ataCmd ); - - /* - * Get/Set CDB results. (ATA specific version). - */ - IOReturn getResults( ATAResults *results ); - void setResults( ATAResults *results ); - - /* - * Get ATA Device this command is directed to. - */ - IOATAStandardDevice *getDevice( IOATAStandardDevice *deviceType ); -// #define kIOATADevice ((IOATADevice *)0) - - - /* - * Get ATA Target/Lun for this command. - */ - ATAUnit getUnit(); - - /* - * Get/Set queue routing for this command. - */ - void setQueueInfo( UInt32 forQueueType = kATAQTypeNormalQ, UInt32 forQueuePosition = kATAQPositionTail ); - void getQueueInfo( UInt32 *forQueueType, UInt32 *forQueuePosition = 0 ); - - /* - * Get command type / Get original command. - * - * These methods are provided for the controller class to identify and relate commands. - * They are not usually of interest to the client side. - */ - UInt32 getCmdType(); - IOATAStandardCommand *getOriginalCmd(); - -/*------------------Methods private to the IOATACommand class-------------------------*/ -public: - IOATADevice *getDevice( IOATADevice *deviceType ); - void free(); - -private: - ATACommandType cmdType; - - IOATAStandardController *controller; - IOATAStandardDevice *device; - - queue_head_t *list; - queue_chain_t nextCommand; - - ATATaskfile taskfile; - - ATAResults results; - - ATACDBInfo ataCmd; - - UInt32 timeout; - UInt32 timer; - - UInt8 queueType; - UInt8 queuePosition; - - IOMemoryDescriptor *xferDesc; - UInt32 xferCount; - UInt32 xferDirection; - - UInt32 senseLength; - IOMemoryDescriptor *senseData; - - IOATAStandardCommand *origCommand; - - union - { - struct - { - UInt32 reserved; - IOSyncer * lock; - } sync; - struct - { - CallbackFn callback; - void *target; - void *refcon; - } async; - } completionInfo; - - UInt32 dataSize; - void *dataArea; - void *commandPrivateData; - void *clientData; - - UInt32 sequenceNumber; -}; - -#endif diff --git a/iokit/IOKit/ata/ata-standard/IOATAStandardController.h b/iokit/IOKit/ata/ata-standard/IOATAStandardController.h deleted file mode 100644 index 2f9d54ab4..000000000 --- a/iokit/IOKit/ata/ata-standard/IOATAStandardController.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * IOATAController.h - * - * Methods in this header list the methods an ATA controller driver must implement. - */ -#ifndef _IOATASTANDARDCONTROLLER_H -#define _IOATASTANDARDCONTROLLER_H - -#include -#include -#include -#include -#include -#include - -class IOATAStandardDevice; -class IOATAStandardCommand; -class IOATAStandardDriver; - -class IOATAStandardController : public IOService -{ - OSDeclareDefaultStructors(IOATAStandardController) - - friend class IOATAStandardCommand; - friend class IOATAStandardDevice; - friend class IOATAStandardDriver; - -/*------------------Methods provided by IOATAStandardController---------------------------------*/ -public: - IOReturn reset(); - -protected: - void enableCommands(); - void disableCommands(); - void disableCommands( UInt32 disableTimeoutmS ); - - void rescheduleCommand( IOATAStandardCommand *forATACmd ); - - void resetStarted(); - void resetOccurred(); - - IOATAStandardCommand *findCommandWithNexus( IOATAStandardDevice *forDevice, UInt32 tagValue = (UInt32)-1 ); - - void *getDeviceData( ATAUnit forUnit ); - - virtual IOWorkLoop *getWorkLoop() const; - - UInt32 getCommandCount(); - void setCommandLimit( IOATAStandardDevice *device, UInt32 commandLimit ); - - void suspendDevice( IOATAStandardDevice *forATADevice ); - void resumeDevice( IOATAStandardDevice *forATADevice ); - IOATAStandardDevice *selectDevice(); - - bool getTiming( ATAUnit unit, ATATimingProtocol *timingProtocol ); - - -/*------------------Methods the controller subclass must implement-----------------------*/ -protected: - /* - * Initialize controller hardware. - * - * Note: The controller driver's configure() method will be called prior to any other - * methods. If the controller driver returns successfully from this method it - * should be ready to accept any other method call listed. - */ - virtual bool configure( IOService *provider, ATAControllerInfo *controllerInfo ) = 0; - - /* - * Driver must indicate which ATA protocols it supports. - */ - virtual bool getProtocolsSupported( ATAProtocol *protocolsSupported ) = 0; - - /* - * Bus/target commands - * - */ - virtual void executeCommand( IOATAStandardCommand *forATACmd ) = 0; - virtual void cancelCommand( IOATAStandardCommand *forATACmd ) = 0; - virtual void resetCommand( IOATAStandardCommand *forATACmd ) = 0; - virtual void abortCommand( IOATAStandardCommand *forATACmd ) = 0; - - /* - * Methods to set timing for individual devices - */ - virtual bool calculateTiming( UInt32 deviceNum, ATATiming *timing ) = 0; - -/*------------------Optional methods the controller subclass may implement-----------------------*/ -protected: - /* - * These methods notify the IOATAStandardController subclass, that a target or lun is about to be - * probed. The subclass should initialize its per-target or per-lun data when called at these - * methods. If the subclass (for some reason) wants to prevent probing of a target or lun, it - * can return false to the corresponding allocate*() call. - */ - virtual bool allocateDevice( ATAUnit unit ); - virtual void deallocateDevice( ATAUnit unit ); - - virtual void disableTimeoutOccurred(); - - /* - * - */ - virtual void enableControllerInterrupts(); - virtual void disableControllerInterrupts(); - -/*------------------Methods private to the IOATAStandardController class----------------------*/ - -public: - bool start( IOService *provider ); - void free(); - -private: - void initQueues(); - bool scanATABus(); - void resetATABus(); - - bool createDeviceNubs(); - bool probeDeviceNubs(); - bool registerDeviceNubs(); - bool initTimings(); - bool matchNubWithPropertyTable( IOService *nub, OSDictionary *table ); - - bool resetBus(); - - - bool initDevice( IOATAStandardDevice *device ); - void releaseDevice( IOATAStandardDevice *device ); - - bool workLoopRequest( WorkLoopReqType type, UInt32 p1=0, UInt32 p2=0, UInt32 p3=0 ); - void workLoopProcessRequest( WorkLoopRequest *workLoopReq, void *p1, void *p2, void *p3 ); - - void addDevice( IOATAStandardDevice *forDevice ); - void deleteDevice( IOATAStandardDevice *forDevice ); - - void timer( IOTimerEventSource *); - - void dispatchRequest(); - void dispatch(); - - bool checkBusReset(); - - void completeCommand( IOATAStandardCommand *forATACmd ); - - bool createWorkLoop(); - bool configureController(); - - IOATAStandardCommand *allocCommand( UInt32 clientDataSize ); - -private: - - UInt32 sequenceNumber; - - UInt32 commandCount; - UInt32 commandLimit; - UInt32 commandLimitSave; - - UInt32 disableTimer; - bool commandDisable; - - UInt32 busResetState; - IOATAStandardCommand *resetCmd; - UInt32 resetTimer; - - IOATAStandardCommand *noDisconnectCmd; - - ATAControllerInfo controllerInfo; - ATATarget *targets; - - IOWorkLoop *workLoop; - IOTimerEventSource *timerEvent; - IOInterruptEventSource *dispatchEvent; - IOCommandGate *workLoopReqGate; - - IOService *provider; -}; - -#endif diff --git a/iokit/IOKit/ata/ata-standard/IOATAStandardDevice.h b/iokit/IOKit/ata/ata-standard/IOATAStandardDevice.h deleted file mode 100644 index b630fd40c..000000000 --- a/iokit/IOKit/ata/ata-standard/IOATAStandardDevice.h +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * IOATAStandardDevice.h - * - * - * Methods in this header provide information about the ATA device - * the device client driver is submitting the ATACommand(s) to. - * - * Note: ATACommand(s) are allocated and freed by methods in this class. - * The remaining methods to setup and submit ATACommands are defined in - * IOATACommand.h - */ - -#ifndef _IOATASTANDARDDEVICE_H -#define _IOATASTANDARDDEVICE_H - -class IOATAStandardController; - -class IOATAStandardDevice : public IOATADevice -{ - OSDeclareDefaultStructors(IOATAStandardDevice) - - friend class IOATAStandardCommand; - friend class IOATAStandardController; - -/*------------------Methods provided to IOCDBDevice clients-----------------------*/ -public: - - /* - * Allocate a CDB Command - */ - IOCDBCommand *allocCommand( IOCDBDevice *deviceType, UInt32 clientDataSize = 0 ); - - /* - * Abort all outstanding commands on this device - */ - void abort(); - - /* - * Reset device (also aborts all outstanding commands) - */ - void reset(); - - /* - * Obtain information about this device - */ - void getInquiryData( void *inquiryBuffer, - UInt32 inquiryBufSize, - UInt32 *inquiryDataSize ); - -/*------------------Additional methods provided to IOATADevice clients-----------------------*/ -public: - /* - * Allocate a ATACommand - */ - IOATAStandardCommand *allocCommand( IOATAStandardDevice *deviceType, UInt32 clientDataSize = 0 ); - - /* - * Obtain information about this device - */ - ATAUnit getUnit(); - ATADeviceType getDeviceType(); - bool getIdentifyData( ATAIdentify *identifyBuffer ); - bool getInquiryData( UInt32 inquiryBufSize, ATAPIInquiry *inquiryBuffer ); - bool getDeviceCapacity( UInt32 *blockMax, UInt32 *blockSize ); - bool getProtocolsSupported( ATAProtocol *protocolsSupported ); - bool getTimingsSupported( ATATimingProtocol *timingsSupported ); - bool getTimingSelected( ATATimingProtocol *timingProtocol ); - bool getTiming( ATATimingProtocol *timingProtocol, ATATiming *timing ); - bool getATAPIPktInt(); - - /* - * Select default device timing for this device - */ - bool selectTiming( ATATimingProtocol timingProtocol, bool fNotifyMsg = false ); - - /* - * Queue management commands - */ - void holdQueue( UInt32 queueType ); - void releaseQueue( UInt32 queueType ); - void flushQueue( UInt32 queueType, IOReturn rc ); - void notifyIdle( void *target = 0, CallbackFn callback = 0, void *refcon = 0 ); - - /* - * - */ - IOWorkLoop *getWorkLoop() const; - -/*------------------Methods private to the IOATADevice class----------------*/ -public: - bool open( IOService *forClient, IOOptionBits options, void *arg ); - void close( IOService *forClient, IOOptionBits options ); - bool init( IOATAStandardController *forController, ATAUnit forUnit ); - void free(); - - bool matchPropertyTable( OSDictionary * table ); - IOService *matchLocation( IOService * client ); - - IOATACommand *allocCommand( IOATADevice *deviceType, UInt32 clientDataSize = 0 ); - -private: - void submitCommand( UInt32 cmdType, IOATAStandardCommand *ataCmd, UInt32 cmdSequenceNumber = 0 ); - void receiveCommand( UInt32 cmdType, IOATAStandardCommand *ataCmd, UInt32 cmdSequenceNumber, void *p3 ); - - IOReturn probeDevice(); - ATADeviceType probeDeviceType(); - - IOReturn doSpinUp(); - IOReturn doIdentify( void **dataPtr ); - IOReturn doSectorCommand( ATACommand ataCmd, UInt32 ataLBA, UInt32 ataCount, void **dataPtr ); - IOReturn doInquiry( void **dataPtr ); - IOReturn doTestUnitReady(); - IOReturn doReadCapacity( void *data ); - - bool getATATimings(); - - void selectTimingDone( IOATAStandardCommand *ataCmd ); - - void setupTarget(); - - void dispatchRequest(); - bool dispatch( UInt32 *dispatchAction ); - - void abortAllCommands( ATACommandType abortCmdType ); - - IOATAStandardCommand *findCommandWithNexus( UInt32 tagValue ); - - void abortCommand( IOATAStandardCommand *ataCmd, UInt32 cmdSequenceNumber ); - void completeCommand( IOATAStandardCommand *cmd ); - - void checkIdleNotify(); - - void executeCommandDone( IOATAStandardCommand *ataCmd ); - void executeReqSenseDone( IOATAStandardCommand *ataCmd ); - void abortCommandDone( IOATAStandardCommand *ataCmd ); - void cancelCommandDone( IOATAStandardCommand *ataCmd ); - void finishCommand( IOATAStandardCommand *ataCmd ); - - OSDictionary *createProperties(); - bool addToRegistry( OSDictionary *propTable, OSObject *regObj, char *key, bool doRelease = true ); - void stripBlanks( char *d, char *s, UInt32 l ); - - void endianConvertData( void *data, void *endianTable ); - - bool checkDeviceQueue( UInt32 *dispatchAction ); - void checkNegotiate( IOATAStandardCommand *ataCmd ); - bool checkTag( IOATAStandardCommand *ataCmd ); - bool checkReqSense(); - bool checkAbortQueue(); - void checkCancelQueue(); - - bool allocTag( UInt32 *tagId ); - void freeTag( UInt32 tagId ); - - void timer(); - - void resetOccurred( ATAClientMessage clientMsg = kATAClientMsgNone ); - void resetComplete(); - - void rescheduleCommand( IOATAStandardCommand *ataCmd ); - - void suspend(); - void resume(); - - void addCommand( queue_head_t *list, IOATAStandardCommand *ataCmd ); - void stackCommand( queue_head_t *list, IOATAStandardCommand *ataCmd ); - void deleteCommand( queue_head_t *list, IOATAStandardCommand *ataCmd, IOReturn rc = kIOReturnSuccess ); - IOATAStandardCommand *checkCommand( queue_head_t *list ); - IOATAStandardCommand *getCommand( queue_head_t *list ); - void moveCommand( queue_head_t *fromList, - queue_head_t *toList, - IOATAStandardCommand *ataCmd, - IOReturn rc = kIOReturnSuccess ); - void moveAllCommands( queue_head_t *fromList, queue_head_t *toList, IOReturn rc = kIOReturnSuccess ); - bool findCommand( queue_head_t *list, IOATAStandardCommand *findATACmd ); - void purgeAllCommands( queue_head_t *list, IOReturn rc ); - -private: - ATAUnit unit; - ATATarget *target; - - IOATAStandardController *controller; - IOCommandGate *deviceGate; - - IOService *client; - IORWLock * clientSem; - - queue_head_t deviceList; - queue_head_t bypassList; - queue_head_t activeList; - queue_head_t abortList; - queue_head_t cancelList; - - ATACommandType abortCmdPending; - - UInt32 reqSenseState; - UInt32 abortState; - UInt32 cancelState; - UInt32 negotiateState; - - IOATAStandardCommand *reqSenseOrigCmd; - - IOATAStandardCommand *reqSenseCmd; - IOATAStandardCommand *abortCmd; - IOATAStandardCommand *cancelCmd; - IOATAStandardCommand *probeCmd; - - UInt32 normalQHeld; - UInt32 bypassQHeld; - - bool idleNotifyActive; - CallbackFn idleNotifyCallback; - void *idleNotifyTarget; - void *idleNotifyRefcon; - - bool isSuspended; - AbsoluteTime suspendTime; - - UInt32 commandCount; - UInt32 commandLimit; - UInt32 commandLimitSave; - - UInt32 maxTags; - UInt32 tagArraySize; - UInt32 *tagArray; - - ATADeviceType deviceType; - - UInt32 protocolsSupported; - UInt32 atapiPktInt; - - ATAIdentify *identifyData; - - ATAInquiry *inquiryData; - UInt32 inquiryDataSize; - - ATATimingProtocol currentTiming; - - UInt32 numTimings; - ATATiming ataTimings[kATAMaxTimings]; - - void *devicePrivateData; -}; - -#define kIOATAStandardDevice ((IOATAStandardDevice *)0) - -#endif diff --git a/iokit/IOKit/ata/ata-standard/IOATAStandardDriver.h b/iokit/IOKit/ata/ata-standard/IOATAStandardDriver.h deleted file mode 100644 index a77b51df0..000000000 --- a/iokit/IOKit/ata/ata-standard/IOATAStandardDriver.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * IOATATStandardDriver.h - * - */ -#ifndef _IOATASTANDARDDRIVER_H -#define _IOATASTANDARDDRIVER_H - -class IOATAStandardDriver : public IOATAStandardController -{ - OSDeclareAbstractStructors( IOATAStandardDriver ) - -/* - * Methods that subclasses IOATAStandardDriver must implement. - */ -protected: - virtual void writeATAReg( UInt32 regIndex, UInt32 regValue ) = 0; - virtual UInt32 readATAReg( UInt32 regIndex ) = 0; - - virtual bool selectTiming( ATAUnit deviceNum, ATATimingProtocol timingProtocol ) = 0; - - virtual bool programDma( IOATAStandardCommand *cmd ); - virtual bool startDma( IOATAStandardCommand *cmd ); - virtual bool stopDma( IOATAStandardCommand *cmd, UInt32 *transferCount ); - virtual bool resetDma(); - virtual bool checkDmaActive(); - -/* - * Methods that subclasses of IOATAStandardDriver can optionally implement. - */ - virtual void newDeviceSelected( IOATAStandardDevice *newDevice ); - virtual bool getProtocolsSupported( ATAProtocol *forProtocol ); - -/* - * Methods provided to subclasses of IOATAStandardDriver. - */ - virtual void interruptOccurred(); - - virtual void resetCommand( IOATAStandardCommand *cmd ); - virtual void executeCommand( IOATAStandardCommand *cmd ); - virtual void abortCommand( IOATAStandardCommand *cmd ); - virtual void cancelCommand( IOATAStandardCommand *cmd ); - -/*------------------Methods private to the IOATAStandardDriver class----------------*/ - -private: - void processATAPioInt(); - void processATADmaInt(); - void processATAPIPioInt(); - void processATAPIDmaInt(); - void processATADmaQueuedInt(); - - ATAReturnCode readATAPIDevice( UInt32 n ); - ATAReturnCode writeATAPIDevice( UInt32 n ); - ATAReturnCode sendATAPIPacket( IOATAStandardCommand *cmd ); - - IOReturn getIOReturnCode( ATAReturnCode code ); - - void doProtocolSetRegs( IOATAStandardCommand *cmd ); - void doATAReset( IOATAStandardCommand *cmd ); - void checkATAResetComplete(); - void doATAProtocolPio( IOATAStandardCommand *cmd ); - void doATAProtocolDma( IOATAStandardCommand *cmd ); - void doATAProtocolDmaQueued( IOATAStandardCommand *cmd ); - void doATAPIProtocolPio( IOATAStandardCommand *cmd ); - void doATAPIProtocolDma( IOATAStandardCommand *cmd ); - void doProtocolNotSupported( IOATAStandardCommand *cmd ); - - bool selectDrive( UInt32 driveHeadReg ); - - void completeCmd( IOATAStandardCommand *cmd, ATAReturnCode returnCode, UInt32 bytesTransferred = 0 ); - void completeCmd( IOATAStandardCommand *cmd ); - - void updateCmdStatus( IOATAStandardCommand *cmd, ATAReturnCode returnCode, UInt32 bytesTransferred ); - - bool waitForStatus( UInt32 statusBitsOn, UInt32 statusBitsOff, UInt32 timeoutmS ); - bool waitForAltStatus( UInt32 statusBitsOn, UInt32 statusBitsOff, UInt32 timeoutmS ); - ATAReturnCode waitForDRQ( UInt32 timeoutmS ); - - bool start(IOService *provider); - IOReturn setPowerState(unsigned long powerStateOrdinal, IOService* whatDevice); - -protected: - IOATAStandardDevice *currentDevice; - ATAUnit currentUnit; - ATAProtocol currentProtocol; - -private: - IOMemoryDescriptor *xferDesc; - bool xferIsWrite; - UInt32 xferCount; - UInt32 xferRemaining; - bool dmaActive; - - IOTimerEventSource *resetPollEvent; - IOATAStandardCommand *resetCmd; - AbsoluteTime resetTimeout; - - bool wakingUpFromSleep; -}; - - -#endif diff --git a/iokit/IOKit/ata/ata-standard/Makefile b/iokit/IOKit/ata/ata-standard/Makefile deleted file mode 100644 index 215b89431..000000000 --- a/iokit/IOKit/ata/ata-standard/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -export MakeInc_cmd=${SRCROOT}/makedefs/MakeInc.cmd -export MakeInc_def=${SRCROOT}/makedefs/MakeInc.def -export MakeInc_rule=${SRCROOT}/makedefs/MakeInc.rule -export MakeInc_dir=${SRCROOT}/makedefs/MakeInc.dir - -IOKIT_FRAMEDIR = $(FRAMEDIR)/IOKit.framework/Versions/A -export INCDIR = $(IOKIT_FRAMEDIR)/Headers -export LCLDIR = $(IOKIT_FRAMEDIR)/PrivateHeaders - -include $(MakeInc_cmd) -include $(MakeInc_def) - -MI_DIR = ata/ata-standard -NOT_EXPORT_HEADERS = - -INSTINC_SUBDIRS = -INSTINC_SUBDIRS_PPC = -INSTINC_SUBDIRS_I386 = - -EXPINC_SUBDIRS = ${INSTINC_SUBDIRS} -EXPINC_SUBDIRS_PPC = ${INSTINC_SUBDIRS_PPC} -EXPINC_SUBDIRS_I386 = ${INSTINC_SUBDIRS_I386} - -ALL_HEADERS = $(shell (cd $(SOURCE); echo *.h)) - -INSTALL_MI_LIST = -INSTALL_MI_LCL_LIST = "" - -INSTALL_MI_DIR = $(MI_DIR) - -EXPORT_MI_LIST = $(filter-out $(NOT_EXPORT_HEADERS), $(ALL_HEADERS)) - -EXPORT_MI_DIR = IOKit/$(MI_DIR) - -include $(MakeInc_rule) -include $(MakeInc_dir) diff --git a/iokit/IOKit/cdb/CDBCommand.h b/iokit/IOKit/cdb/CDBCommand.h deleted file mode 100644 index 38e2b3338..000000000 --- a/iokit/IOKit/cdb/CDBCommand.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * CDBCommand.h - * - */ - -#ifndef _CDBCOMMAND_H -#define _CDBCOMMAND_H - -typedef struct CDBInfo -{ - - UInt32 cdbFlags; - - UInt32 cdbLength; - UInt8 cdb[16]; - - UInt32 reserved[16]; -} CDBInfo; - -typedef struct CDBResults -{ - IOReturn returnCode; - - UInt32 bytesTransferred; - - Boolean requestSenseDone; - UInt32 requestSenseLength; - - UInt32 reserved[16]; -} CDBResults; - - -#if __cplusplus -enum _CDBFlags -{ -}; -#endif /* !__cplusplus */ - - -#endif - diff --git a/iokit/IOKit/cdb/CDBPublic.h b/iokit/IOKit/cdb/CDBPublic.h deleted file mode 100644 index 71c493ee3..000000000 --- a/iokit/IOKit/cdb/CDBPublic.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * CDBPublic.h - * - */ - -#ifndef _CDBPUBLIC_H -#define _CDBPUBLIC_H - -#include - -#endif diff --git a/iokit/IOKit/cdb/IOCDBCommand.h b/iokit/IOKit/cdb/IOCDBCommand.h deleted file mode 100644 index c43764a15..000000000 --- a/iokit/IOKit/cdb/IOCDBCommand.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * IOCDBCommand.h - * - */ -#ifndef _IOCDBCOMMAND_H -#define _IOCDBCOMMAND_H - -#include - -typedef void (*CallbackFn)(void *target, void *refcon ); - -class IOCDBDevice; - -class IOCDBCommand : public IOCommand -{ - OSDeclareAbstractStructors(IOCDBCommand) - -/*------------------Methods provided to IOCDBCommand users -------------------------*/ -public: - /* - * Set/Get IOMemoryDescriptor object to I/O data buffer or sense data buffer. - */ - virtual void setPointers( IOMemoryDescriptor *desc, - UInt32 transferCount, - bool isWrite, - bool isSense = false ) = 0; - - virtual void getPointers( IOMemoryDescriptor **desc, - UInt32 *transferCount, - bool *isWrite, - bool isSense = false ) = 0; - /* - * Set/Get command timeout (mS) - */ - virtual void setTimeout( UInt32 timeoutmS ) = 0; - virtual UInt32 getTimeout() = 0; - - /* - * Set async callback routine. Specifying no parameters indicates synchronous call. - */ - virtual void setCallback( void *target = 0, CallbackFn callback = 0, void *refcon = 0 ) = 0; - - /* - * Set/Get CDB information. (Generic CDB version) - */ - virtual void setCDB( CDBInfo *cdbInfo ) = 0; - virtual void getCDB( CDBInfo *cdbInfo ) = 0; - - /* - * Get CDB results. (Generic CDB version) - */ - virtual IOReturn getResults( CDBResults *cdbResults ) = 0; - - /* - * Get CDB Device this command is directed to. - */ - virtual IOCDBDevice *getDevice( IOCDBDevice *deviceType ) = 0; - #define kIOCDBDevice ((IOCDBDevice *)0) - - /* - * Command verbs - */ - virtual bool execute( UInt32 *sequenceNumber = 0 ) = 0; - virtual void abort( UInt32 sequenceNumber ) = 0; - virtual void complete() = 0; - - /* - * Get pointers to client and command data. - */ - virtual void *getCommandData() = 0; - virtual void *getClientData() = 0; - - /* - * Get unique sequence number assigned to command. - */ - virtual UInt32 getSequenceNumber() = 0; -}; - -#endif diff --git a/iokit/IOKit/cdb/IOCDBDevice.h b/iokit/IOKit/cdb/IOCDBDevice.h deleted file mode 100644 index e2eb3d0f5..000000000 --- a/iokit/IOKit/cdb/IOCDBDevice.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * IOCDBDevice.h - * - * - * - * Note: CDBCommand(s) are allocated and freed by methods in this class. - * The remaining methods to setup and submit CDBCommands are defined in - * IOCDBCommand.h - */ -#ifndef _IOCDBDEVICE_H -#define _IOCDBDEVICE_H - -class IOCDBCommand; - -class IOCDBDevice : public IOService -{ - OSDeclareAbstractStructors(IOCDBDevice) - -/*------------------Methods provided to IOCDBDevice clients-----------------------*/ -public: - /* - * Allocate a CDB Command - */ - virtual IOCDBCommand *allocCommand( IOCDBDevice *deviceType, UInt32 clientDataSize = 0 ) = 0; - - /* - * Abort all outstanding commands on this device - */ - virtual void abort() = 0; - - /* - * Reset device (also aborts all outstanding commands) - */ - virtual void reset() = 0; - - /* - * Obtain information about this device - */ - virtual void getInquiryData( void *inquiryBuffer, - UInt32 inquiryBufSize, - UInt32 *inquiryDataSize ) = 0; -}; - -#define kIOCDBDevice ((IOCDBDevice *)0) - - -#endif diff --git a/iokit/IOKit/cdb/IOCDBInterface.h b/iokit/IOKit/cdb/IOCDBInterface.h deleted file mode 100644 index b3579bf48..000000000 --- a/iokit/IOKit/cdb/IOCDBInterface.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * IOCDBInterface - .h - * - */ -#ifndef _IOCDBINTERFACE_H -#define _IOCDBINTERFACE_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#endif diff --git a/iokit/IOKit/cdb/Makefile b/iokit/IOKit/cdb/Makefile deleted file mode 100644 index d402c2d78..000000000 --- a/iokit/IOKit/cdb/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -export MakeInc_cmd=${SRCROOT}/makedefs/MakeInc.cmd -export MakeInc_def=${SRCROOT}/makedefs/MakeInc.def -export MakeInc_rule=${SRCROOT}/makedefs/MakeInc.rule -export MakeInc_dir=${SRCROOT}/makedefs/MakeInc.dir - -IOKIT_FRAMEDIR = $(FRAMEDIR)/IOKit.framework/Versions/A -export INCDIR = $(IOKIT_FRAMEDIR)/Headers -export LCLDIR = $(IOKIT_FRAMEDIR)/PrivateHeaders - -include $(MakeInc_cmd) -include $(MakeInc_def) - -MI_DIR = cdb -NOT_EXPORT_HEADERS = - -INSTINC_SUBDIRS = -INSTINC_SUBDIRS_PPC = -INSTINC_SUBDIRS_I386 = - -EXPINC_SUBDIRS = ${INSTINC_SUBDIRS} -EXPINC_SUBDIRS_PPC = ${INSTINC_SUBDIRS_PPC} -EXPINC_SUBDIRS_I386 = ${INSTINC_SUBDIRS_I386} - -ALL_HEADERS = $(shell (cd $(SOURCE); echo *.h)) - -INSTALL_MI_LIST = CDBCommand.h CDBPublic.h -INSTALL_MI_LCL_LIST = "" - -INSTALL_MI_DIR = $(MI_DIR) - -EXPORT_MI_LIST = $(filter-out $(NOT_EXPORT_HEADERS), $(ALL_HEADERS)) - -EXPORT_MI_DIR = IOKit/$(MI_DIR) - -include $(MakeInc_rule) -include $(MakeInc_dir) diff --git a/iokit/IOKit/pci/IOPCIBridge.h b/iokit/IOKit/pci/IOPCIBridge.h index d6e1f7a1e..9cfe7a8bd 100644 --- a/iokit/IOKit/pci/IOPCIBridge.h +++ b/iokit/IOKit/pci/IOPCIBridge.h @@ -39,7 +39,7 @@ class IOPCIBridge : public IOService { - friend IOPCIDevice; + friend class IOPCIDevice; OSDeclareAbstractStructors(IOPCIBridge) diff --git a/iokit/IOKit/pci/IOPCIDevice.h b/iokit/IOKit/pci/IOPCIDevice.h index 523d6db11..158e85a2a 100644 --- a/iokit/IOKit/pci/IOPCIDevice.h +++ b/iokit/IOKit/pci/IOPCIDevice.h @@ -251,8 +251,6 @@ public: virtual bool attach( IOService * provider ); virtual void detach( IOService * provider ); virtual IOReturn setPowerState( unsigned long, IOService * ); - virtual IOReturn addPowerChild ( IOService * theChild ); - virtual void joinPMtree( IOService * driver ); virtual bool compareName( OSString * name, OSString ** matched = 0 ) const; virtual bool matchPropertyTable( OSDictionary * table, SInt32 * score ); @@ -400,7 +398,8 @@ public: /*! @function mapDeviceMemoryWithRegister @abstract Maps a physical range of the device. @discussion This method will create a mapping for the IODeviceMemory for the physical memory range that was assigned to the configuration space base address register passed in, with IODeviceMemory::map(options). The mapping is represented by the returned instance of IOMemoryMap, which should not be released until the mapping is no longer required. This method is analogous to IOService::mapDeviceMemoryWithIndex. - @param index An index into the array of ranges assigned to the device. + @param reg The 8-bit configuration space register that is the base address register for the desired range. + @param options Options to be passed to the IOMemoryDescriptor::map() method. @result An instance of IOMemoryMap, or zero if the index is beyond the count available. The mapping should be released only when access to it is no longer required. */ virtual IOMemoryMap * mapDeviceMemoryWithRegister( UInt8 reg, diff --git a/iokit/IOKit/ppc/IODBDMA.h b/iokit/IOKit/ppc/IODBDMA.h index 8bcc66c58..496efe363 100644 --- a/iokit/IOKit/ppc/IODBDMA.h +++ b/iokit/IOKit/ppc/IODBDMA.h @@ -35,7 +35,6 @@ #include #include -#include /* DBDMA definitions */ diff --git a/iokit/IOKit/pwr_mgt/IOPM.h b/iokit/IOKit/pwr_mgt/IOPM.h index 9cfe3ea53..9f113545a 100644 --- a/iokit/IOKit/pwr_mgt/IOPM.h +++ b/iokit/IOKit/pwr_mgt/IOPM.h @@ -268,10 +268,17 @@ enum { kPMMinutesToSpinDown, kPMMinutesToSleep, kPMEthernetWakeOnLANSettings, - kPMSetProcessorSpeed + kPMSetProcessorSpeed, + kPMPowerSource }; #define kMaxType kPMEthernetWakeOnLANSettings +// SetAggressiveness values for the kPMPowerSource aggressiveness type +enum { + kIOPMInternalPower = 1, + kIOPMExternalPower +}; + #define kAppleClamshellStateKey "AppleClamshellState" #define kIOREMSleepEnabledKey "REMSleepEnabled" diff --git a/iokit/IOKit/pwr_mgt/Makefile b/iokit/IOKit/pwr_mgt/Makefile index 093e9f94f..64ae04404 100644 --- a/iokit/IOKit/pwr_mgt/Makefile +++ b/iokit/IOKit/pwr_mgt/Makefile @@ -5,7 +5,7 @@ export MakeInc_dir=${SRCROOT}/makedefs/MakeInc.dir IOKIT_FRAMEDIR = $(FRAMEDIR)/IOKit.framework/Versions/A export INCDIR = $(IOKIT_FRAMEDIR)/Headers -export LCLDIR = $(FRAMEDIR)/Kernel.framework/Versions/A/PrivateHeaders/IOKit +export LCLDIR = $(KPINCDIR)/IOKit include $(MakeInc_cmd) include $(MakeInc_def) diff --git a/iokit/IOKit/pwr_mgt/RootDomain.h b/iokit/IOKit/pwr_mgt/RootDomain.h index 4e89c16fc..acbb27fc5 100644 --- a/iokit/IOKit/pwr_mgt/RootDomain.h +++ b/iokit/IOKit/pwr_mgt/RootDomain.h @@ -62,6 +62,7 @@ public: virtual IOReturn setAggressiveness ( unsigned long, unsigned long ); virtual IOReturn youAreRoot ( void ); virtual IOReturn sleepSystem ( void ); + virtual IOReturn setProperties ( OSObject * ); IOReturn shutdownSystem ( void ); IOReturn restartSystem ( void ); virtual IOReturn receivePowerNotification (UInt32 msg); @@ -71,8 +72,13 @@ public: virtual void handleSleepTimerExpiration ( void ); void stopIgnoringClamshellEventsDuringWakeup ( void ); void wakeFromDoze( void ); + void broadcast_it (unsigned long, unsigned long ); void publishFeature( const char *feature ); + // Override of these methods for logging purposes. + virtual IOReturn changePowerStateTo ( unsigned long ordinal ); + virtual IOReturn changePowerStateToPriv ( unsigned long ordinal ); + private: class IORootParent * patriarch; // points to our parent diff --git a/iokit/IOKit/scsi/IOSCSICommand_Reference.h b/iokit/IOKit/scsi/IOSCSICommand_Reference.h deleted file mode 100644 index 68f0c48b7..000000000 --- a/iokit/IOKit/scsi/IOSCSICommand_Reference.h +++ /dev/null @@ -1,538 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -/*! -@header IOSCSICommand_Reference.h - -This header defines the IOSCSICommand class. - -This class encapsulates a SCSI Command. The client driver allocates a -command using IOSCSIDevice::allocCommand() and initializes it using -functions of this class. The client can then submit the command to -the SCSI stack by invoking the execute() function. -*/ - - -/*! -@enum SCSICDBFlags -Defines values for the cdbFlags field in the SCSICDBInfo structure. -@constant kCDBFNoDisconnect -Set by the IOSCSIDevice client to indicate the target may not disconnect -during the execution of this IOSCSICommand. -@constant kCDBFlagsDisableParity -Set by the IOSCSIController class to tell the host adapter driver to disable -parity checking during the execution of this CDB. -@constant kCDBFlagsNoDisconnect -Set by the IOSCSIController class to tell the host adapter driver that the -target may not disconnect during the execution of this IOSCSICommand. -@constant kCDBFlagsNegotiateSDTR -Set by the IOSCSIController class to tell the host adapter driver that it -should initiate synchronous data transfer negotiation during this IOSCSICommand. -@constant kCDBFlagsNegotiateWDTR -Set by the IOSCSIController class to tell the host adapter driver that it -should initiate wide data transfer negotiation during this IOSCSICommand. -*/ -enum SCSICDBFlags { - kCDBFNoDisconnect = 0x00000001, - -/* - * Note: These flags are for IOSCSIController subclasses only - */ - kCDBFlagsDisableParity = 0x08000000, - kCDBFlagsNoDisconnect = 0x10000000, - kCDBFlagsNegotiateSDTR = 0x20000000, - kCDBFlagsNegotiateWDTR = 0x40000000, -}; - - -/*! -@enum SCSIAdapterStatus -Defines the values of the adapterStatus field of the SCSIResults structure. -@constant kSCSIAdapterStatusSuccess -Request completed with no adapter reported errors. -@constant kSCSIAdapterStatusProtocolError -Violation of SCSI protocol detected by host adapter. -@constant kSCSIAdapterStatusSelectionTimeout -Target device did not respond to selection. -@constant kSCSIAdapterStatusMsgReject -Adapter received a msg reject from the target device. -@constant kSCSIAdapterStatusParityError -Adapter detected, or target reported a parity error during the -IOSCSICommand. -@constant kSCSIAdapterStatusOverrun -Target device requested more data than supplied by host. -*/ -enum SCSIAdapterStatus { - kSCSIAdapterStatusSuccess = 0, - kSCSIAdapterStatusProtocolError, - kSCSIAdapterStatusSelectionTimeout, - kSCSIAdapterStatusMsgReject, - kSCSIAdapterStatusParityError, - kSCSIAdapterStatusOverrun, -}; - - -/*! -@typedef SCSICDBInfo -@discussion -Fields specified here are set by IOSCSIDevice client, while others -are set by the IOSCSIController class for use by the host adapter -driver. The client should zero all fields of the structure prior -to use. -@field cdbFlags -See enum SCSICDBFlags for flag definitions. -@field cdbTagMsg -This field should be set to zero by the IOSCSIDevice client. If the -SCSI device supports tag queuing then the IOSCSIController class -will set this field to select simple (unordered) tags. -@field cdbTag -This field is set by the IOSCSIController class to tell the host -adapter driver the SCSI tag value to assign to this IOSCSICommand. -@field cdbLength -Set by the IOSCSIDevice client to the length of the Command Descriptor -Block (CDB). -@field cdb -Set by the IOSCSIDevice client to command descriptor block the client -wishes the target to execute. -*/ -typedef struct SCSICDBInfo { - - UInt32 cdbFlags; - - UInt32 cdbTagMsg; - UInt32 cdbTag; - - UInt32 cdbAbortMsg; - - UInt32 cdbLength; - UInt8 cdb[16]; - - UInt32 reserved[16]; -} SCSICDBInfo; - - -/*! -@typedef SCSIResults -@field returnCode -The overall return code for the command. See iokit/iokit/IOReturn.h. -This value is also returned as the getResults() return value. - -Note: The SCSI Family will automatically generate standard return codes -based on the values in the adapterStatus and scsiStatus fields. Unless -the IOSCSIController subclass needs set a specific return code, it should -leave this field set to zero. -@field bytesTransferred -The total number of bytes transferred to/from the target device. -@field adapterStatus -The IOSCSIController subclass must fill-in this field as appropriate. -See enum SCSIAdapterStatus. -@field scsiStatus -The SCSI Status byte returned from the target device. -@field requestSenseDone -A boolean indicating whether sense data was obtained from the target -device. -@field requestSenseLength -The number of sense data bytes returned from the target device. -*/ -typedef struct SCSIResults { - IOReturn returnCode; - - UInt32 bytesTransferred; - - enum SCSIAdapterStatus adapterStatus; - UInt8 scsiStatus; - - bool requestSenseDone; - UInt32 requestSenseLength; -} SCSIResults; - - -/*! -@enum SCSIQueueType -Each IOSCSIDevice has two queues, a normal Q and a bypass Q. The treatment of the -queues is essentially identical except that the bypass Q is given preference whenever -it has commands available. - -Usually, the client will use the normal Q for regular I/O commands and the bypass Q -to send error recovery commands to the device. -@constant kQTypeNormalQ -Indicates command applies to the normal IOSCSIDevice queue. -@constant kQTypeBypassQ -Indicates command applies to the bypass IOSCSIDevice queue. -*/ -enum SCSIQueueType { - kQTypeNormalQ = 0, - kQTypeBypassQ = 1, -}; - - -/*! -@enum SCSIQueuePosition -Indicates whether a IOSCSICommand should be added to the head or tail -of the queue selected. -@constant kQPositionTail -Queue request at the tail (end) of the selected queue. -@constant kQPositionHead -Queue request at the head (front) of the selected queue. -*/ -enum SCSIQueuePosition { - kQPositionTail = 0, - kQPositionHead = 1, -}; - - -/*! -@struct SCSITargetLun -@field target -The SCSI Id for the SCSI device being selected. -@field lun -The SCSI Lun for the SCSI device being selected. -*/ -typedef struct SCSITargetLun { - UInt8 target; - UInt8 lun; - UInt8 reserved[2]; -} SCSITargetLun; - -/*! -@class IOSCSICommand : public IOCDBCommand -@abstract -Class that describes a SCSI device (target/lun pair). -@discussion -This class encapsulates a SCSI Command. The client driver allocates a -command using IOSCSIDevice::allocCommand() and initializes it using -functions of this class. The client can then submit the command to -the SCSI stack by invoking the execute() function. -*/ -class IOSCSICommand : public IOCDBCommand -{ -public: - - -/*! -@function setPointers -@abstract -Sets the data buffer component of a SCSI Command. -@discussion -The client provides an IOMemoryDescriptor object to corresponding -to the client's data or request sense buffer, the maximum data transfer count -and data transfer direction. -@param desc -Pointer to a IOMemoryDescriptor describing the client's I/O buffer. -@param transferCount -Maximum data transfer count in bytes. -@param isWrite -Data transfer direction. (Defined with respect to the device, i.e. isWrite = true -indicates the host is writing to the device. -@param isSense -If isSense is set to false, the IOSCSICommand's data buffer information is set. Otherwise, -the IOSCSICommand's request sense buffer information is set -*/ -void setPointers( IOMemoryDescriptor *desc, UInt32 transferCount, bool isWrite, bool isSense=false ); - - -/*! -@function getPointers -@abstract -Gets the data buffer component of a SCSI Command. -@discussion -The client provides a set of pointers to fields to receive the IOSCSICommand's -data/request sense buffer pointers. -@param desc -Pointer to a field (IOMemoryDescriptor *) to receive the IOSCSICommand's IOMemoryDescriptor pointer. -@param transferCount -Pointer to a field (UInt32) to receive the IOSCSICommand's maximum transfer count. -@param isWrite -Pointer to a field (bool) to receive the IOSCSICommand's transfer direction. -@param isSense -If isSense is set to true, the IOSCSICommand's data buffer information is returned. Otherwise, -the IOSCSICommand's request sense buffer information is returned. -*/ -void getPointers( IOMemoryDescriptor **desc, UInt32 *transferCount, bool *isWrite, bool isSense = false ); - -/*! -@function setTimeout -@abstract -Sets the timeout for the command in milliseconds. -@discussion -The IOSCSIController class will abort a command which does not -complete with in the time interval specified. The client should -set the timeout parameter to zero if they want to suppress -timing. -@param timeout -Command timeout in milliseconds. -*/ -void setTimeout( UInt32 timeoutmS ); - -/*! -@function getTimeout -@abstract -Gets the timeout for the command in milliseconds. -@discussion -This function returns the command timeout previously set by setTimeout(). -@param timeout -Command timeout in milliseconds. -*/ -UInt32 getTimeout(); - - -/*! -@function setCallback -@abstract -Sets the callback routine to be invoked when the SCSI Command completes. -@param target -Pointer to the object to be passed to the callback routine. This would usually -be the client's (this) pointer. -@param callback -Pointer to the client's function to process the completed command -@param refcon -Pointer to the information required by the client's callback routine to process -the completed command. -*/ -void setCallback( void *target = 0, CallbackFn callback = 0, void *refcon = 0 ); - - -/*! -@function getClientData -@abstract -Returns a pointer to the SCSI Command's client data area. -@discussion -The client may allocate storage in the SCSI Command for its own use. -See IOSCSIDevice::allocateCmd(). -*/ -void *getClientData(); - -/* -@function getCommandData -@abstract -Returns a pointer to the SCSI Command's controller data area -@discussion -This area is allocated for use by the IOSCSIController subclass (host adapter -driver). The client should not normally access this area. -*/ -void *getCommandData(); - - -/*! -@function setCDB -@abstract -Sets the CDB component of a SCSI Command. -@param scsiCDB -Pointer to a SCSICDBInfo structure. -*/ -void setCDB( SCSICDBInfo *scsiCmd ); - - -/*! -@function getCDB -@abstract -Gets the CDB component of a SCSI Command. -@param scsiCDB -Pointer to a SCSICDBInfo structure to receive the SCSI Command's cdb information. -*/ -void getCDB( SCSICDBInfo *scsiCmd ); - - -/*! -@function getResults -@abstract -Gets results from a completed SCSI Command. -@discussion -The getResults() function returns the value of the returnCode field of the command results. If -the client is only interested in a pass/fail indication for the command, the client -can pass (SCSIResult *)0 as a parameter. -@param results -Pointer to a SCSIResults structure to receive the SCSI Commands completion information. -*/ -IOReturn getResults( SCSIResults *results ); - -/*! -@function setResults -@abstract -Sets the results component of a SCSI Command. -@discussion -The setResults() function is used by the IOSCSIController subclass (host -adapter driver) return results for a SCSI Command about to be completed. -@param scsiResults Pointer to a SCSIResults structure containing -completion information for the SCSI Command. - -Completion information is copied into the command, so the caller may -release the SCSIResults structure provided when this function returns. -*/ -void setResults( SCSIResults *results ); - - -/*! -@function getDevice -@abstract -Returns the IOSCSIDevice this command is targeted to. -@param deviceType -The caller should use value kIOSCSIDeviceType. -@discussion -In some cases a IOSCSICommand is not associated with a specific target/lun. This -would be the case for a SCSI Bus Reset. In this case getDevice() returns 0. -*/ -IOSCSIDevice *getDevice( IOSCSIDevice *deviceType ); - - -/*! -@function getTargetLun -@abstract -Returns the target/lun for the IOSCSIDevice this command is associated with. -@param targetLun -Pointer to a SCSITargetLun structure to receive the target/lun information. -*/ -void getTargetLun( SCSITargetLun *targetLun ); - - -/*! -@function execute -@abstract -Submits a SCSI command to be executed. -@discussion -Once the execute() function is called, the client should not -invoke any further functions on the SCSI Command with the -exception of abort(). - -The execute() function optionally returns sets a unique sequence -number token for the command. If the client intends to use the abort() -method they must retain this sequence number token. -@param sequenceNumber -Pointer to field (UInt32) to receive the sequence number assigned to the SCSI -Command. -*/ -bool execute( UInt32 *sequenceNumber = 0 ); - -/*! -@function abort -@abstract -Aborts an executing SCSI Command. -@discussion -The client may invoke the abort() method to force the completion of an -executing SCSI Command. The client must pass the sequence number -provided when the execute() function was invoked. - -Note: The abort function provides no status on whether or not a -command has been successfully aborted. The client should wait for the -command to actually complete to determine whether the abort completed -successfully. -@param sequenceNumber -The client must pass the sequence number assigned to the command when -the client called the execute() function. -*/ -void abort( UInt32 sequenceNumber ); - -/*! -@function complete -@abstract -Indicates the IOSCSIController subclass (host adapter driver) has completed a SCSI command. -@discussion -Once the complete() function is called, the controller -subclass should make no further accesses to the IOSCSICommand -being completed. - -A IOSCSIDevice client would not normally call this function. -*/ -void complete(); - - -/*! -@function getSequenceNumber -@abstract -Returns the sequence number assigned to an executing command. -@discussion -The caller should check the sequence number for 0. This indicates that -the command has completed or has not been processed to the point where -a sequence number has been assigned. -*/ -UInt32 getSequenceNumber(); - - -/*! -@function setQueueInfo -@abstract -Sets queuing information for the SCSI Command. -@discussion -Each IOSCSIDevice has two queues, a normal Q and a bypass Q. The treatment of the -queues is esentially identical except that the bypass Q is given preference whenever -it has commands available. - -Usually, the client will use the normal Q for regular I/O commands and the bypass Q -to send error recovery commands to the device. -@param queueType -Set to kQTypeNormalQ or kQTypeBypassQ to indicate which IOSCSIDevice queue the -SCSI Command should be routed to. -@param queuePosition -Set to kQPositionTail or kQPositionHead to indicate whether the SCSI Command should -be added to the head to tail for the selected IOSCSIDevice queue. -*/ -void setQueueInfo( UInt32 queueType = kQTypeNormalQ, UInt32 queuePosition = kQPositionTail ); - - -/*! -@function getQueueInfo -@abstract -Gets queuing information for the SCSI Command. -@param queueType -Pointer to a field (UInt32) to receive the queue type previously set for this SCSI Command. -@param queuePosition -Pointer to a field (UInt32) to receive the queue position previously set for this SCSI Command. -*/ -void getQueueInfo( UInt32 *queueType, UInt32 *queuePosition = 0 ); - - -/*! -@function getCmdType -@abstract -Obtains the underlying 'intent' of a SCSI Command. -@discussion -This function provides information on the intent of a SCSI -Command. For example, since Aborts, Request Sense and normal Execute commands are -all sent to the executeCommand() function, invoking getCmdType() -will indicate whether a Request Sense, Abort or Normal I/O request is -being processed. - -It this information is not normally meaningful to IOSCSIDevice clients. -*/ -UInt32 getCmdType(); - - -/*! -@function getOriginalCmd -@abstract -Obtains a 'related' SCSI Command. -@discussion -In cases where a SCSI command is related to a previous command, this -function will return the original command. For example, if a -Request Sense command (CmdType = kSCSICommandReqSense)is processed, -then this function can be used to obtain the original command that -caused the check condition. If an Abort command (CmdType = -kSCSICommandAbort) then this function can be used to obtain the original -command the abort was issued against. - - -It this information is not normally meaningful to IOSCSIDevice clients. -*/ -IOSCSICommand *getOriginalCmd(); - -}; diff --git a/iokit/IOKit/scsi/IOSCSIController_Reference.h b/iokit/IOKit/scsi/IOSCSIController_Reference.h deleted file mode 100644 index e8db8729a..000000000 --- a/iokit/IOKit/scsi/IOSCSIController_Reference.h +++ /dev/null @@ -1,475 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -/*! -@header IOSCSIController_Reference.h - -This header defines the IOSCSIController class. - -IOSCSIController provides the superclass for SCSI host -adapter drivers. - -Drivers are instantiated based on their 'personality' entry matching -their adapter's OpenFirmware device tree entry. When a match occurs, -the driver's class is instantiated. Since the driver is written as a -subclass of IOSCSIController, an instance of the SCSI Family is automatically -instantiated. -*/ - - -/*! -@typedef SCSIControllerInfo -Parameter structure passed for configure() function. -@field initiatorId -The SCSI address of your host adapter. Usually 7 (decimal). -@field maxTargetsSupported -The number of targets you controller supports. Typically 8 or 16. -@field maxLunsSupported -The number of logical units per target your controller supports. -Typically 8. -@field minTransferPeriodpS -The minimum synchronous data transfer period in picoseconds your -controller supports. -@field maxTransferOffset -The maximum synchronous data offset your controller supports in bytes. -@field maxTransferWidth -The maximum data SCSI bus width your controller supports in bytes. Must -be a power of 2. -@field maxCommandsPerController -The maximum number of outstanding commands your controller supports -across all targets and luns. Set to 0 if there is no controller limit in -this category. -@field maxCommandsPerTarget -The maximum number of outstanding commands your controller supports on a -given target. Set to 0 if there is no controller limit in this category. -@field maxCommandsPerLun -The maximum number of outstanding commands your controller supports on a -given lun. Set to 0 if there is no controller limit in this category. -@field tagAllocationMethod -Controls whether tags are allocated on a per Lun, per Target or per -Controller basis. See enum SCSITagAllocation. -@field maxTags -The maximum number of tags allocated to each Lun, Target or Controller -depending on the tagAllocationMethod setting. -@field targetPrivateDataSize -IOSCSIController will optionally allocate per-target storage for your -driver based on the setting of this field. The amount of storage needed -is specified in bytes. -@field lunPrivateDataSize -IOSCSIController will optionally allocate per-lun storage for your -driver based on the setting of this field. The amount of storage needed -is specified in bytes. -@field commandPrivateDataSize -IOSCSIController will optionally allocate per-command storage for your -driver based on the setting of this field. The amount of storage needed -is specified in bytes. - -Note: The amount of per-command storage allowed is under review. We -anticipate that typical SCSI controllers will need not more than 1024 -bytes per command. -@field disableCancelCommands -Subclasses of IOSCSIController which do their own management of -aborts/resets can set this field to true to avoid receiving -cancelCommand() requests. -*/ -typedef struct SCSIControllerInfo { - UInt32 initiatorId; - - UInt32 maxTargetsSupported; - UInt32 maxLunsSupported; - - UInt32 minTransferPeriodpS; - UInt32 maxTransferOffset; - UInt32 maxTransferWidth; - - UInt32 maxCommandsPerController; - UInt32 maxCommandsPerTarget; - UInt32 maxCommandsPerLun; - - UInt32 tagAllocationMethod; - UInt32 maxTags; - - UInt32 targetPrivateDataSize; - UInt32 lunPrivateDataSize; - UInt32 commandPrivateDataSize; - - bool disableCancelCommands; - - UInt32 reserved[64]; - -} SCSIControllerInfo; - - -/*! -@enum SCSITagAllocation -@discussion -This enum defines how SCSI tags are allocated. -@constant kTagAllocationNone -This controller does not support tag queuing. -@constant kTagAllocationPerLun -Each SCSI Lun has its own private tag pool containing -(maxTags) SCSI tags. -@constant kTagAllocationPerTarget -Each SCSI Target has its own private tag pool contain -(maxTags) SCSI tags. Luns connected to this target -allocate tags from this pool. -@constant kTagAllocationPerController -The controller has a global tag pool containing (maxTags) -SCSI tags. This pool is shared by all Luns connected to -this controller. -*/ -enum { - kTagAllocationNone = 0, - kTagAllocationPerLun, - kTagAllocationPerTarget, - kTagAllocationPerController, -}; - - -/*! -@class IOSCSIController : public IOService -@abstract -Superclass for SCSI host adapter drivers -@discussion -The IOSCSIController class provides a number of services to simplify -writing a driver for your host adapter. - -Specifically, the class provides the following features: - -1. Complete request scheduling semantics. - -The IOSCSIController class manages request queues on behalf of its -subclasses. It tracks all requests submitted to its subclasses, -including managing timeouts, aborts and request cancellations. - -2. Request Sense scheduling - -Subclasses of IOSCSIController do not need to implement -auto-request-sense functionality. Your driver can use the default -handling in the super class. - -3. Storage management. - -The IOSCSIController subclass provides per-request private storage areas -for your subclass. - -4. Resource management. - -The IOSCSIController subclass will manage the number of outstanding -commands submitted to your subclass on a per-controller and per-lun -basis. -*/ -@class IOSCSIController : public IOService -{ -public: - - -/*! -@function configure -@abstract -Driver configuration/initialization request. -@discussion -The configure() member function is the first call your subclass will -receive. You should provide the information requested in the -SCSIControllerInfo structure and enable your hardware for operation. -If your driver initialized successfully, you should return true, otherwise, -your driver should return false. -@param provider -Pointer to an object (usually IOPCIDevice) which represents the bus of -your device is attached to . Typically your driver will use functions -supplied by this object to access PCI space on your hardware. See -IOPCIDevice for a description of PCI services. -@param controllerInfo -Pointer to a SCSIControllerInfo structure. Your driver should provide -the information requested in this structure prior to returning from -the configure() call. -*/ -bool configure( IOService *provider, SCSIControllerInfo *controllerInfo ); - - -/*! -@function executeCommand -@abstract -Execute a IOSCSICommand. -@discussion -The executeCommand() function is called for all 'routine' I/O requests -including abort requests. The driver is passed a pointer to an -IOSCSICommand object. The driver obtains information about the I/O -request by using function calls provided by the IOSCSICommand -class. -@param scsiCommand -Pointer to a IOSCSICommand. See IOSCSICommand for more information. -*/ -void executeCommand( IOSCSICommand *scsiCommand ); - - -/*! -@function cancelCommand -@abstract -Cancels a IOSCSICommand previously submitted to the driver. -@discussion -The cancelCommand() function is called to inform your subclass to force -completion of a SCSI command. - -Your subclass should call the getOriginalCmd() to determine the command -to complete. - -After calling complete() on the original command, you should complete -the IOSCSICommand passed to the cancelCommand() function - -Note: When a cancelCommand is issued, your subclass may presume that any -activity to remove an active command from the SCSI Target, i.e. (abort -tag/abort) has already occurred. -@param scsiCommand -Pointer to a IOSCSICommand. See IOSCSICommand for more information. -*/ -void cancelCommand( IOSCSICommand *scsiCommand ); - - -/*! -@function resetCommand -@abstract -Request the driver issue a SCSI Bus reset. -@discussion -The resetCommand() function indicates you should do a SCSI Bus Reset. -After issuing the reset you should complete to IOSCSICommand passed. - -Note: After you report the IOSCSICommand Reset complete, you will -receive cancelCommand() requests for all outstanding commands. -@param scsiCommand -Pointer to a IOSCSICommand. See IOSCSICommand for more information. -*/ -void resetCommand( IOSCSICommand *scsiCommand ); - - -/*! -@function resetOccurred -@abstract -Inform the IOSCSIController class of an unsolicited SCSI Bus reset. -@discussion -Your subclass should call this function if -you detect a target initiated bus reset, or need to do an unplanned SCSI -Bus Reset as part of adapter error recovery. - -Note: After you call the resetOccurred() function, you will receive -cancelCommand() requests for all outstanding IOSCSICommand(s). -*/ -void resetOccurred(); - -/*! -@function rescheduleCommand -@abstract -Return a IOSCSICommand for rescheduling. -@discussion -If your subclass function cannot start processing an otherwise -acceptable IOSCSICommand due to resource constraints, i.e. MailBox full, -lost SCSI Bus arbitration, you may have the IOSCSICommand rescheduled by -calling rescheduleCommand(). A IOSCSICommand passed to this function -should be treated as 'complete', i.e. you should make no further -accesses to it. - -Note: If you cannot process further commands, you should call the -disableCommands() function to prevent receiving additional commands -until you are ready to accept them. -@param scsiCommand -Pointer to IOSCSICommand your driver needs to reschedule. -*/ -void rescheduleCommand( IOSCSICommand *scsiCommand ); - - -/*! -@function disableCommands -@abstract -Suspend sending I/O commands to your driver. -@discussion -In cases where your executeCommand() member function cannot accept -commands, you may disable further calls by invoking disableCommands(). -Use enableCommands() to resume receiving commands. - -Note: The resetCommand() and cancelCommands() entry points are not -affected by the use of this function. - -Note: The default timeout for disableCommands() is 5s. If this timeout -is exceeded the IOSCSIController class will call your driver's -disableTimeoutOccurred() function. The default action of this function -is to issue a SCSI Bus Reset by calling your driver's resetCommand() -function. -@param timeoutmS -Your driver may override the default timeout -by specifying a timeout value in milliseconds. -*/ -void disableCommands( UInt32 timeoutmS ); - - -/*! -@function enableCommands -@abstract -Resume sending I/O commands to your driver. -@discussion -Resumes sending I/O commands to your driver that were previously suspended -by calling disableCommands(). -*/ -void enableCommands(); - -/*! -@function disableTimeoutOccurred -@abstract -Indicates your driver has suspended commands too long. -@discussion -The IOSCSIController superclass will timeout disableCommand() requests -to preclude the possibility of a hung SCSI bus. If a timeout occurs, -then disableTimeoutOccurred() will be called. The default action of this -routine is to do a SCSI Bus Reset by calling resetCommand(). Your -subclass may choose to modify the default behavior of this routine to do -additional adapter specific error recovery. -*/ -void disableTimeoutOccurred(); - - -/*! -@function findCommandWithNexus -@abstract -Locate an active IOSCSICommand using target/lun/tag values. -@discussion -Your subclass can use this function to search for an active -IOSCSICommand by providing the target/lun/tag values for the command. In -the case of a non-tagged command the second parameter must either be -omitted or set to -1. - -An unsuccessful search will return 0. -@param targetLun -Structure of type SCSITargetLun, initialized to the target/lun value you -wish to search for. -@param tagValue -Optional tag value you wish to search for. -*/ -IOSCSICommand *findCommandWithNexus( SCSITargetLun targetLun, UInt32 tagValue = (UInt32) -1 ); - -/*! -@function allocateTarget -@abstract -Notifies driver of allocation of per-Target resources. -@discussion -Your driver will be called at its allocateTarget() function when a target is about -to be probed. The your driver should initialize its per-target data at this time. -If the subclass wishes to prevent probing of this target, it should return false -as the result of this function call. - -This is an optional function. Your driver is not required to implement it. -@param targetLun -SCSITargetLun structure containing the SCSI Id of the target that is about to be -allocated. -*/ -bool allocateTarget( SCSITargetLun targetLun ); - - -/*! -@function deallocateTarget -@abstract -Notifies driver that target resources will be deallocated. -@discussion -Your driver will be called at its deallocateTarget() function when a target is about -deallocated. The your driver must insure that there will be no further access to -the per-target data allocated to this target. - -This is an optional function. Your driver is not required to implement it. -@param targetLun -SCSITargetLun structure containing the SCSI Id of the target that is about to be -deallocated. -*/ -bool deallocateTarget( SCSITargetLun targetLun ); - - -/*! -@function allocateLun -@abstract -Notifies driver of allocation of per-Lun resources. -@discussion -Your driver will be called at its allocateLun() function when a Lun is about -to be probed. The your driver should initialize its per-lun data at this time. -If the subclass wishes to prevent probing of this lun, it should return false -as the result of this function call. - -This is an optional function. Your driver is not required to implement it. -@param targetLun -SCSITargetLun structure containing the SCSI Id of the target/lun that is about to be -allocated. -*/ -bool allocateLun( SCSITargetLun targetLun ); - - -/*! -@function deallocateLun -@abstract -Notifies driver of deallocation of per-Lun resources. -@discussion -Your driver will be called at its deallocateLun() function when a Lun is about -deallocated. The your driver must insure that there will be no further access to -the per-lun data allocated to this lun. - -This is an optional function. Your driver is not required to implement it. -@param targetLun -SCSITargetLun structure containing the SCSI Id of the target/lun that is about to be -deallocated. -*/ -bool allocateLun( SCSITargetLun targetLun ); - - -/*! -@function getTargetData -@abstract -Obtains a pointer to per-Target data allocated by IOSCSIController. -@discussion -This function returns a pointer to per-Target workarea allocated for -your driver's use. The size of this area must be specified in the -during the configure() function. See struct SCSIControllerInfo, -field targetDataSize. -@param targetLun -SCSITargetLun structure containing the SCSI Id of the target who's -workarea you are requesting a pointer to. -*/ -void *getTargetData( SCSITargetLun targetLun ); - - -/*! -@function getLunData -@abstract -Obtains a pointer to per-Lun data allocated by IOSCSIController. -@discussion -This function returns a pointer to per-Lun workarea allocated for -your driver's use. The size of this area must be specified -during the configure() function. See struct SCSIControllerInfo, -field lunDataSize. -*/ -void *getLunData( SCSITargetLun targetLun ); - - -/*! -@function getWorkLoop -@abstract -Returns the IOWorkLoop object that services your driver. -*/ -IOWorkloop *getWorkLoop(); - - -} diff --git a/iokit/IOKit/scsi/IOSCSIDeviceInterface.h b/iokit/IOKit/scsi/IOSCSIDeviceInterface.h deleted file mode 100644 index e1533679f..000000000 --- a/iokit/IOKit/scsi/IOSCSIDeviceInterface.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * IOSCSIDeviceInterface.h - * - */ -#ifndef _IOSCSIDEVICEINTERFACE_H -#define _IOSCSIDEVICEINTERFACE_H - -#include - -#include -#include -#include -#include -#include - -#endif diff --git a/iokit/IOKit/scsi/IOSCSIDevice_Reference.h b/iokit/IOKit/scsi/IOSCSIDevice_Reference.h deleted file mode 100644 index e1436ea0d..000000000 --- a/iokit/IOKit/scsi/IOSCSIDevice_Reference.h +++ /dev/null @@ -1,401 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -/*! -@header IOSCSIDevice_Reference.h - -This header defines the IOSCSIDevice class. - -The SCSI framework creates instances of this class to -represent each valid SCSI device (target/lun) detected during -SCSI bus scanning. When an instance of this class is registered with -IOKit, the instance will be presented to clients which -'match' the IOSCSIDevice class. -*/ - -/*! -@typedef SCSITargetParms -Parameter structure for get/setTargetParms -@field transferPeriodpS -Minimum SCSI synchronous transfer period allowed -for this target in picoseconds (10E-12). For asynchronous data transfer, -set this field to 0. -@field transferOffset -Maximum SCSI synchronous transfer offset allowed for this target in -bytes. For asynchronous data transfer, set this field to 0. -@field transferWidth -Maximum SCSI bus width in bytes. Note: must be a -power of 2. -@field enableTagQueuing -Setting enableTagQueuing to true enables tag queuing for SCSI Commands -issued to the target. -@field disableParity -Set to (true) to disable parity checking on the -SCSI bus for this target. -*/ -typedef struct SCSITargetParms { - UInt32 transferPeriodpS; - UInt32 transferOffset; - UInt32 transferWidth; - - bool enableTagQueuing; - bool disableParity; - - UInt32 reserved[16]; - -} SCSITargetParms; - - -/*! -@typedef SCSILunParms -Parameter structure for get/setLunParms -@field disableDisconnect -Setting disableDisconnect to true disables SCSI disconnect for SCSI -Commands issued to the target/lun pair. -*/ -typedef struct SCSILunParms { - bool disableDisconnect; - - UInt32 reserved[16]; - -} SCSILunParms; - - -/*! -@enum SCSIClientMessage -@discussion -IOSCSIDevice notifies its client of significant 'events' by the IOService::message() -api. When possible the client is notified of the event prior to any action taken. The -client is responsible for managing the device queue for the IOSCSIDevice -via the holdQueue(), releaseQueue(), flushQueue() and notifyIdle() api's. The client is also -notified at the end of an 'event' by the corresponding message id with or'd with -kClientMsgDone. -@constant kClientMsgDeviceAbort -A client initiated device abort is beginning. -@constant kClientMsgDeviceReset -A client initiated device reset is beginning. -@constant kClientMsgBusReset -An unsolicited bus reset has occurred. -@constant kClientMsgDone -This constant is or'd with one of the above message ids to indicate the -client should complete processing of the corresponding event. -*/ -enum SCSIClientMessage { - kClientMsgDeviceAbort = 0x00005000, - kClientMsgDeviceReset, - kClientMsgBusReset, - - kClientMsgDone = 0x80000000, -}; - - -/*! -@class IOSCSIDevice : public IOCDBDevice -@abstract -Class that describes a SCSI device (target/lun pair). -@discussion -The IOSCSIDevice class provides basic services -to initialize and supervise a SCSI device. Once the device is -initialized, the client will normally use the allocCommand() member -function to create IOSCSICommand(s) to send SCSI CDBs to the target/lun. -*/ -class IOSCSIDevice : public IOCDBDevice -{ -public: - -/*! -@function allocCommand -@abstract -Allocates a IOSCSICommand object for this device. -@discussion -The client uses the allocCommand() member function to allocate IOSCSICommand(s) -for a IOSCSIDevice. The client then uses the member functions of -the IOSCSICommand to initialize it and send it to the device. A completed IOSCSICommand -may be reused for subsequent I/O requests or returned to the SCSI Family. -@param scsiDevice -Always specify kIOSCSIDevice. -@param clientDataSize -The client may indicate the size of a per-command data area for its own -use. - -Note: The amount of per-command storage allowed is under review. We -anticipate that typical SCSI clients will need not more than 1024 bytes -per command. -*/ -IOSCSICommand *allocCommand( IOSCSIDevice *scsiDevice, UInt32 clientDataSize = 0 ); - - -/*! -@function setTargetParms -@abstract -Sets SCSI parameters that apply to all luns on a SCSI target device. -@discussion -This function will block until we attempt to set the -requested parameters. It may not be called from the device's workloop context. - -The SCSI Family will serialize accesses to the SCSI -target so as not to disrupt commands in progress prior to processing a -change of target parameters. -@param targetParms -Pointer to structure of type SCSITargetParms. -*/ -bool setTargetParms( SCSITargetParms *targetParms ); - - -/*! -@function getTargetParms -@abstract -Gets the current target parameters. -@discussion -Returns the parameters currently in effect for the SCSI target. -See setTargetParms(). -@param targetParms -Pointer to structure of type SCSITargetParms. -*/ -void getTargetParms( SCSITargetParms *targetParms ); - - -/*! -@function setLunParms -@abstract -Sets the logical unit parameters for this device. -@discussion -This function will block until we attempt to set the -requested parameters. It may not be called from the device's workloop context. - -The SCSI Family will serialize accesses to the SCSI -target/lun so as not to disrupt commands in progress prior to processing a -change of lun parameters. -@param lunParms -Pointer to structure of type SCSILunParms -*/ -bool setLunParms( SCSILunParms *lunParms ); - - -/*! -@function getLunParms -@abstract -Gets the current logical unit parameters. -@discussion -Returns the parameters currently in effect for the SCSI target/lun. -@param lunParms -Pointer to structure of type SCSITargetParms -*/ -void getLunParms( SCSILunParms *lunParms ); - - -/*! -@function abort -@abstract -Aborts all outstanding requests for the target/lun pair. -@discussion -If any I/O requests are currently active for the target/lun, an abort -command is sent to the device and any active requests are completed. - -Prior to abort processing beginning, the client will be notified via: - -message( kClientMsgDeviceAbort ); - -When abort processing is completed, the client will be notified via: - -message( kClientMsgDeviceAbort | kClientMsgDone ); - -The client is responsible for managing the pending work queue for -the device when an abort request occurs. See holdQueue(), flushQueue(), -notifyIdle() functions. -*/ -void abort(); - - -/*! -@function reset -@abstract -Resets the SCSI target. -@discussion -Since a SCSI target may have multiple logical units (lun(s)) the -reset() function may affect multiple IOSCSIDevice instances. Processing for -each lun is similar. - -Prior to reset processing beginning, the client will be notified via: - -message( kClientMsgDeviceReset ); - -When reset processing is completed, the client will be notified via: - -message( kClientMsgDeviceReset | kClientMsgDone ); - -The client is responsible for managing the pending work queue for -the device when an abort request occurs. See holdQueue(), flushQueue(), -notifyIdle() functions. -*/ -void reset(); - - -/*! -@function getInquiryData -@abstract Returns SCSI Inquiry data for the IOSCSIDevice. -@discussion -Inquiry data returned is from the results of the last SCSI bus probe. -@param inquiryBuffer -Pointer to a buffer to receive the Inquiry data. -@param inquiryBufSize -Size of the buffer supplied. -@param inquiryDataSize -Pointer to a UInt32 to receive the size of the Inquiry data actually -returned. -*/ -void getInquiryData( void *inquiryBuffer, UInt32 inquiryBufSize, UInt32 *inquiryDataSize ); - - -/*! -@function message -@abstract -IOService message function. -@discussion -IOSCSIDevice notifies its client of significant 'events' by the IOService::message() -api. When possible the client is notified of the event prior to any action taken. The -client is responsible for managing the device queue for the IOSCSIDevice -via the holdQueue(), releaseQueue(), flushQueue() and notifyIdle() api's. - -Any return codes provided by the client are ignored. -@param message-id -Message id's for IOSCSIDevice are defined by enum SCSIClientMessage -@param provider -Pointer to the IOSCSIDevice reporting the event. -@param argument -Unused. -*/ -IOReturn message( UInt32 type, IOService * provider, void * argument = 0 ); - - -/*! -@function open -@abstract -IOService open function -@discussion -A client should open a IOSCSIDevice prior to accessing it. Only one open is allowed -per device. -@param client -Pointer to the IOSCSI device the client is opening. -@param options -There are currently no options defined by the SCSI Family. -@param arg -Unused. Omit or specify 0. -*/ -bool open( IOService *client, IOOptionBits options = 0, void *arg = 0 ); - - -/*! -@function close -@abstract -IOService close function -@discussion -A client must close a IOSCSIDevice if the client plans no further accesses to it. -@param client -Pointer to the IOSCSI device the client is closing. -@param options -There are currently no options defined by the SCSI Family. -*/ -void close( IOService *client, IOOptionBits options = 0 ); - - -/*! -@function holdQueue -@abstract -Suspends sending additional IOSCSICommands to the target/lun. -@discussion -holdQueue() may only be called from the IOSCSIDevice workloop. The client -is guaranteed to be running in this context during a message() notification. - -holdQueue() has no effect on commands already passed to the host adapter. One -or more commands may complete after the queue is held. See notifyIdle() -@param queueType -Perform action on the indicated queue. See enum SCSIQueueType in IOSCSICommand. -*/ -holdQueue( UInt32 queueType ); - - -/*! -@function flushQueue -@abstract -Returns any commands on the IOSCSIDevice's pending work queue. -@discussion -flushQueue() may only be called from the IOSCSIDevice workloop. This is -guaranteed to be the case after a IOSCSICommand completion of after a -message() notification. - -All pending command are completed prior to flushQueue() returning to the caller. - -flushQueue() has no effect on commands already passed to the host adapter. One -or more commands may complete after the queue is flushed. See notifyIdle(). -@param queueType -Perform action on the indicated queue. See enum SCSIQueueType in IOSCSICommand. -@param rc -The return code of any flushed commands is set to (rc). -*/ -void flushQueue( UInt32 queueType, IOReturn rc ); - - -/*! -@function notifyIdle -@abstract -Notifies the client when all active commands on a SCSI device have completed. -@discussion -notifyIdle() may only be called from the IOSCSIDevice workloop. This is guaranteed -to be the case after a IOSCSICommand completion of after a message() notification. - -Only one notifyIdle() call may be active. Any outstanding notifyIdle() calls may -be cancelled by calling notifyIdle() with no parameters. -@param target -Object to receive the notification. Normally the client's (this) pointer. -@param callback -Pointer to a callback routine of type CallbackFn. -@param refcon -Pointer to client's private data. -*/ -void notifyIdle( void *target, Callback callback, void *refcon ); - - -/*! -@function releaseQueue -@abstract -Resumes sending IOSCSICommands to the IOSCSIDevice. -@discussion -If the device queue was not held, releaseQueue() has no effect. - -releaseQueue() may only be called from the IOSCSIDevice workloop. This is guaranteed -to be the case after a IOSCSICommand completion of after a message() notification. -@param queueType -Perform action on the indicated queue. See enum SCSIQueueType in IOSCSICommand. -*/ -void releaseQueue( UInt32 queueType ); - - -/*! -@function getWorkLoop -@abstract -Returns the IOWorkLoop object that services this IOSCSIDevice. -*/ -IOWorkloop *getWorkLoop(); - -} diff --git a/iokit/IOKit/scsi/IOSCSIParallelInterface.h b/iokit/IOKit/scsi/IOSCSIParallelInterface.h deleted file mode 100644 index 4458f2979..000000000 --- a/iokit/IOKit/scsi/IOSCSIParallelInterface.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * IOSCSIParallelInterface.h - * - */ -#ifndef _IOSCSIPARALLELINTERFACE_H -#define _IOSCSIPARALLELINTERFACE_H - -#include - -#include -#include -#include -#include -#include - -#endif diff --git a/iokit/IOKit/scsi/Makefile b/iokit/IOKit/scsi/Makefile deleted file mode 100644 index d5165ee3f..000000000 --- a/iokit/IOKit/scsi/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -export MakeInc_cmd=${SRCROOT}/makedefs/MakeInc.cmd -export MakeInc_def=${SRCROOT}/makedefs/MakeInc.def -export MakeInc_rule=${SRCROOT}/makedefs/MakeInc.rule -export MakeInc_dir=${SRCROOT}/makedefs/MakeInc.dir - -IOKIT_FRAMEDIR = $(FRAMEDIR)/IOKit.framework/Versions/A -export INCDIR = $(IOKIT_FRAMEDIR)/Headers -export LCLDIR = $(IOKIT_FRAMEDIR)/PrivateHeaders - -include $(MakeInc_cmd) -include $(MakeInc_def) - -MI_DIR = scsi -NOT_EXPORT_HEADERS = IOSCSIDevice_Reference.h IOSCSICommand_Reference.h IOSCSIController_Reference.h - -INSTINC_SUBDIRS = scsi-device scsi-parallel -INSTINC_SUBDIRS_PPC = -INSTINC_SUBDIRS_I386 = - -EXPINC_SUBDIRS = ${INSTINC_SUBDIRS} -EXPINC_SUBDIRS_PPC = ${INSTINC_SUBDIRS_PPC} -EXPINC_SUBDIRS_I386 = ${INSTINC_SUBDIRS_I386} - -ALL_HEADERS = $(shell (cd $(SOURCE); echo *.h)) - -INSTALL_MI_LIST = -INSTALL_MI_LCL_LIST = "" - -INSTALL_MI_DIR = $(MI_DIR) - -EXPORT_MI_LIST = $(filter-out $(NOT_EXPORT_HEADERS), $(ALL_HEADERS)) - -EXPORT_MI_DIR = IOKit/$(MI_DIR) - -include $(MakeInc_rule) -include $(MakeInc_dir) diff --git a/iokit/IOKit/scsi/scsi-device/IOSCSICommand.h b/iokit/IOKit/scsi/scsi-device/IOSCSICommand.h deleted file mode 100644 index af8932c45..000000000 --- a/iokit/IOKit/scsi/scsi-device/IOSCSICommand.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * IOSCSICommand.h - * - */ -#ifndef _IOSCSICOMMAND_H -#define _IOSCSICOMMAND_H - -class IOSCSIDevice; -class IOSCSICommand; - -class IOSCSICommand : public IOCDBCommand -{ - OSDeclareAbstractStructors(IOSCSICommand) - -/*------------------Methods provided to IOCDBCommand users -------------------------*/ -public: - /* - * Set/Get IOMemoryDescriptor object to I/O data buffer or sense data buffer. - */ - virtual void setPointers( IOMemoryDescriptor *desc, - UInt32 transferCount, - bool isWrite, - bool isSense = false ) = 0; - - virtual void getPointers( IOMemoryDescriptor **desc, - UInt32 *transferCount, - bool *isWrite, - bool isSense = false ) = 0; - /* - * Set/Get command timeout (mS) - */ - virtual void setTimeout( UInt32 timeoutmS ) = 0; - virtual UInt32 getTimeout() = 0; - - /* - * Set async callback routine. Specifying no parameters indicates synchronous call. - */ - virtual void setCallback( void *target = 0, CallbackFn callback = 0, void *refcon = 0 ) = 0; - - /* - * Set/Get CDB information. (Generic CDB version) - */ - virtual void setCDB( CDBInfo *cdbInfo ) = 0; - virtual void getCDB( CDBInfo *cdbInfo ) = 0; - - /* - * Get CDB results. (Generic CDB version) - */ - virtual IOReturn getResults( CDBResults *cdbResults ) = 0; - - /* - * Get CDB Device this command is directed to. - */ - virtual IOCDBDevice *getDevice( IOCDBDevice *deviceType ) = 0; - - /* - * Command verbs - */ - virtual bool execute( UInt32 *sequenceNumber = 0 ) = 0; - virtual void abort( UInt32 sequenceNumber ) = 0; - virtual void complete() = 0; - - /* - * Get pointers to client and command data. - */ - virtual void *getCommandData() = 0; - virtual void *getClientData() = 0; - - /* - * Get unique sequence number assigned to command. - */ - virtual UInt32 getSequenceNumber() = 0; - -/*------------------ Additional methods provided to IOSCSICommand users -------------------------*/ -public: - /* - * Set/Get CDB information. (SCSI specific version). - */ - virtual void setCDB( SCSICDBInfo *scsiCmd ) = 0; - virtual void getCDB( SCSICDBInfo *scsiCmd ) = 0; - - /* - * Get/Set CDB results. (SCSI specific version). - */ - virtual IOReturn getResults( SCSIResults *results ) = 0; - virtual void setResults( SCSIResults *results ) = 0; - - /* - * Get SCSI Device this command is directed to. - */ - virtual IOSCSIDevice *getDevice( IOSCSIDevice *deviceType ) = 0; - - /* - * Get SCSI Target/Lun for this command. - */ - virtual void getTargetLun( SCSITargetLun *targetLun ) = 0; - - /* - * Get/Set queue routing for this command. - */ - virtual void setQueueInfo( UInt32 forQueueType = kQTypeNormalQ, UInt32 forQueuePosition = kQPositionTail ) = 0; - virtual void getQueueInfo( UInt32 *forQueueType, UInt32 *forQueuePosition = 0 ) = 0; - - /* - * Set to blank state, call prior to re-use of this object. - */ - virtual void zeroCommand() = 0; -}; - -#endif diff --git a/iokit/IOKit/scsi/scsi-device/IOSCSIDevice.h b/iokit/IOKit/scsi/scsi-device/IOSCSIDevice.h deleted file mode 100644 index f542f8915..000000000 --- a/iokit/IOKit/scsi/scsi-device/IOSCSIDevice.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * IOSCSIDevice.h - * - * - * Methods in this header provide information about the SCSI device - * the device client driver is submitting the SCSICommand(s) to. - * - * Note: SCSICommand(s) are allocated and freed by methods in this class. - * The remaining methods to setup and submit SCSICommands are defined in - * IOSCSICommand.h - */ - -#ifndef _IOSCSIDEVICE_H -#define _IOSCSIDEVICE_H - -class IOSCSICommand; - -class IOSCSIDevice : public IOCDBDevice -{ - OSDeclareAbstractStructors(IOSCSIDevice) - -/*------------------Methods provided to IOCDBDevice clients-----------------------*/ -public: - - /* - * Allocate a CDB Command - */ - virtual IOCDBCommand *allocCommand( IOCDBDevice *cdbDevice, UInt32 clientDataSize = 0 ) = 0; - - /* - * Abort all outstanding commands on this device - */ - virtual void abort() = 0; - - /* - * Reset device (also aborts all outstanding commands) - */ - virtual void reset() = 0; - - /* - * Obtain information about this device - */ - virtual void getInquiryData( void *inquiryBuffer, - UInt32 inquiryBufSize, - UInt32 *inquiryDataSize ) = 0; - -/*------------------Additional methods provided to IOSCSIDevice clients-----------------------*/ -public: - /* - * Allocate a SCSICommand - */ - virtual IOSCSICommand *allocCommand( IOSCSIDevice *scsiDevice, UInt32 clientDataSize = 0 ) = 0; - - /* - * Target management commands - */ - virtual bool setTargetParms( SCSITargetParms *targetParms ) = 0; - virtual void getTargetParms( SCSITargetParms *targetParms ) = 0; - - /* - * Lun management commands - */ - virtual bool setLunParms( SCSILunParms *lunParms ) = 0; - virtual void getLunParms( SCSILunParms *lunParms ) = 0; - - /* - * Queue management commands - */ - virtual void holdQueue( UInt32 queueType ) = 0; - virtual void releaseQueue( UInt32 queueType ) = 0; - virtual void flushQueue( UInt32 queueType, IOReturn rc ) = 0; - virtual void notifyIdle( void *target = 0, CallbackFn callback = 0, void *refcon = 0 ) = 0; - -}; - -#define kIOSCSIDevice ((IOSCSIDevice *)0) - -#endif diff --git a/iokit/IOKit/scsi/scsi-device/Makefile b/iokit/IOKit/scsi/scsi-device/Makefile deleted file mode 100644 index a2cad73cc..000000000 --- a/iokit/IOKit/scsi/scsi-device/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -export MakeInc_cmd=${SRCROOT}/makedefs/MakeInc.cmd -export MakeInc_def=${SRCROOT}/makedefs/MakeInc.def -export MakeInc_rule=${SRCROOT}/makedefs/MakeInc.rule -export MakeInc_dir=${SRCROOT}/makedefs/MakeInc.dir - -IOKIT_FRAMEDIR = $(FRAMEDIR)/IOKit.framework/Versions/A -export INCDIR = $(IOKIT_FRAMEDIR)/Headers -export LCLDIR = $(IOKIT_FRAMEDIR)/PrivateHeaders - -include $(MakeInc_cmd) -include $(MakeInc_def) - -MI_DIR = scsi/scsi-device -NOT_EXPORT_HEADERS = - -INSTINC_SUBDIRS = -INSTINC_SUBDIRS_PPC = -INSTINC_SUBDIRS_I386 = - -EXPINC_SUBDIRS = ${INSTINC_SUBDIRS} -EXPINC_SUBDIRS_PPC = ${INSTINC_SUBDIRS_PPC} -EXPINC_SUBDIRS_I386 = ${INSTINC_SUBDIRS_I386} - -ALL_HEADERS = $(shell (cd $(SOURCE); echo *.h)) - -INSTALL_MI_LIST = SCSICommand.h SCSIDevice.h SCSIPublic.h -INSTALL_MI_LCL_LIST = "" - -INSTALL_MI_DIR = $(MI_DIR) - -EXPORT_MI_LIST = $(filter-out $(NOT_EXPORT_HEADERS), $(ALL_HEADERS)) - -EXPORT_MI_DIR = IOKit/$(MI_DIR) - -include $(MakeInc_rule) -include $(MakeInc_dir) diff --git a/iokit/IOKit/scsi/scsi-device/SCSICommand.h b/iokit/IOKit/scsi/scsi-device/SCSICommand.h deleted file mode 100644 index 7b2867df4..000000000 --- a/iokit/IOKit/scsi/scsi-device/SCSICommand.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * SCSICommand.h - * - */ - -#ifndef _SCSICOMMAND_H -#define _SCSICOMMAND_H - -typedef struct SCSICDBInfo -{ - - UInt32 cdbFlags; - - UInt32 cdbTagMsg; - UInt32 cdbTag; - - UInt32 cdbAbortMsg; - - UInt32 cdbLength; - UInt8 cdb[16]; - - UInt32 reserved[16]; -} SCSICDBInfo; - - -enum SCSICDBFlags -{ - kCDBFNoDisconnect = 0x00000001, - -/* - * Note: These flags are for IOSCSIController subclasses only - */ - kCDBFlagsNegotiatePPR = 0x04000000, - kCDBFlagsDisableParity = 0x08000000, - kCDBFlagsNoDisconnect = 0x10000000, - kCDBFlagsNegotiateSDTR = 0x20000000, - kCDBFlagsNegotiateWDTR = 0x40000000, -// = 0x80000000, // reserved -}; - -enum SCSIAdapterStatus -{ - kSCSIAdapterStatusSuccess = 0, - kSCSIAdapterStatusProtocolError, - kSCSIAdapterStatusSelectionTimeout, - kSCSIAdapterStatusMsgReject, - kSCSIAdapterStatusParityError, - kSCSIAdapterStatusOverrun, -}; - -typedef struct SCSIResults -{ - IOReturn returnCode; - - UInt32 bytesTransferred; - - enum SCSIAdapterStatus adapterStatus; - UInt8 scsiStatus; - - Boolean requestSenseDone; - UInt32 requestSenseLength; - - UInt32 reserved[16]; -} SCSIResults; - - -#endif diff --git a/iokit/IOKit/scsi/scsi-device/SCSIDevice.h b/iokit/IOKit/scsi/scsi-device/SCSIDevice.h deleted file mode 100644 index c8e019d0a..000000000 --- a/iokit/IOKit/scsi/scsi-device/SCSIDevice.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * SCSIDevice.h - * - */ - -#ifndef _SCSIDEVICE_H -#define _SCSIDEVICE_H - -#define kDefaultInquirySize 255 - -typedef struct SCSITargetLun -{ - UInt8 target; - UInt8 lun; - UInt8 reserved[2]; -} SCSITargetLun; - -typedef struct SCSILunParms -{ - Boolean disableDisconnect; - - UInt32 reserved[16]; -} SCSILunParms; - -typedef struct SCSITargetParms -{ - UInt32 transferPeriodpS; - UInt32 transferOffset; - UInt32 transferWidth; - UInt32 transferOptions; - - Boolean enableTagQueuing; - Boolean disableParity; - - UInt32 reserved[16]; -} SCSITargetParms; - -enum SCSITransferOptions -{ - kSCSITransferOptionClockDT = 0x00000001, - kSCSITransferOptionQAS = 0x00000100, - kSCSITransferOptionIUS = 0x00000200, - kSCSITransferOptionPPR = 0x00000400, -}; - -#define kSCSITransferOptionsSCSI3 (kSCSITransferOptionClockDT | kSCSITransferOptionQAS | kSCSITransferOptionIUS | kSCSITransferOptionPPR) - - -enum SCSIDeviceTimeouts -{ - kSCSITimerIntervalmS = 500, - kSCSIProbeTimeoutmS = 5000, - kSCSIResetIntervalmS = 3000, - kSCSIAbortTimeoutmS = 5000, - kSCSIReqSenseTimeoutmS = 5000, - kSCSIDisableTimeoutmS = 5000, -}; - -enum SCSIClientMessage -{ - kSCSIClientMsgNone = 0x00005000, - kSCSIClientMsgDeviceAbort, - kSCSIClientMsgDeviceReset, - kSCSIClientMsgBusReset, - - kSCSIClientMsgDone = 0x80000000, -}; - -enum SCSIQueueType -{ - kQTypeNormalQ = 0, - kQTypeBypassQ = 1, -}; - -enum SCSIQueuePosition -{ - kQPositionTail = 0, - kQPositionHead = 1, -}; - - -#define kSCSIMaxProperties 12 - -#define kSCSIPropertyTarget "SCSI Target" /* OSNumber */ -#define kSCSIPropertyLun "SCSI Lun" /* OSNumber */ -#define kSCSIPropertyIOUnit "IOUnit" /* OSNumber */ -#define kSCSIPropertyDeviceTypeID "SCSI Device Type" /* OSNumber */ -#define kSCSIPropertyRemovableMedia "SCSI Removable Media" /* OSBoolean */ -#define kSCSIPropertyVendorName "SCSI Vendor Name" /* OSString */ -#define kSCSIPropertyProductName "SCSI Product Name" /* OSString */ -#define kSCSIPropertyProductRevision "SCSI Product Revision" /* OSString */ -#define kSCSIPropertyTransferPeriod "SCSI Transfer Period" /* OSNumber */ -#define kSCSIPropertyTransferOffset "SCSI Transfer Offset" /* OSNumber */ -#define kSCSIPropertyTransferWidth "SCSI Transfer Width" /* OSNumber */ -#define kSCSIPropertyTransferOptions "SCSI Transfer Options" /* OSNumber */ -#define kSCSIPropertyCmdQueue "SCSI CmdQueue Enabled" /* OSNumber */ - -#endif diff --git a/iokit/IOKit/scsi/scsi-device/SCSIPublic.h b/iokit/IOKit/scsi/scsi-device/SCSIPublic.h deleted file mode 100644 index 7c60f5981..000000000 --- a/iokit/IOKit/scsi/scsi-device/SCSIPublic.h +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * SCSIPublic.h - * - */ - -#ifndef _SCSIPUBLIC_H -#define _SCSIPUBLIC_H - -typedef struct _SCSIInquiry -{ - unsigned char devType; /* 0 Device type, */ - unsigned char devTypeMod; /* 1 Device type modifier */ - unsigned char version; /* 2 ISO/ECMA/ANSI version */ - unsigned char format; /* 3 Response data format */ - unsigned char length; /* 4 Additional Length */ - unsigned char reserved5; /* 5 Reserved */ - unsigned char reserved6; /* 6 Reserved */ - unsigned char flags; /* 7 Capability flags */ - unsigned char vendorName[8]; /* 8-15 Vendor-specific */ - unsigned char productName[16]; /* 16-31 Product id */ - unsigned char productRevision[4]; /* 32-35 Product revision */ - unsigned char vendorSpecific[20]; /* 36-55 Vendor stuff */ - unsigned char scsi3Options; /* 56 SCSI-3 options */ - unsigned char moreReserved[39]; /* 57-95 Reserved */ -} SCSIInquiry; - -/* - * These are device type qualifiers. We need them to distinguish between "unknown" - * and "missing" devices. - */ -enum -{ - kSCSIDevTypeQualifierConnected = 0x00, /* Exists and is connected */ - kSCSIDevTypeQualifierNotConnected = 0x20, /* Logical unit exists */ - kSCSIDevTypeQualifierReserved = 0x40, - kSCSIDevTypeQualifierMissing = 0x60, /* No such logical unit */ - kSCSIDevTypeQualifierVendorSpecific = 0x80, /* Non-standardized */ - kSCSIDevTypeQualifierMask = 0xE0, -}; - -enum -{ - kSCSIDevTypeModRemovable = 0x80, /* Device has removable media */ -}; - -enum _SCSIDevFlags -{ - kSCSIDevCapRelAdr = 0x80, - kSCSIDevCapWBus32 = 0x40, - kSCSIDevCapWBus16 = 0x20, - kSCSIDevCapSync = 0x10, - kSCSIDevCapLinked = 0x08, - kSCSIDevCapCmdQue = 0x02, - kSCSIDevCapSftRe = 0x01, -}; - -typedef struct _SCSISenseData -{ - unsigned char errorCode; /* 0 Result validity */ - unsigned char segmentNumber; /* 1 Segment number */ - unsigned char senseKey; /* 2 Sense code, flags */ - unsigned char info[4]; /* 3-6 Sense-key specific */ - unsigned char additionalSenseLength; /* 7 Sense length info */ - unsigned char reservedForCopy[4]; /* 8-11 Sense-key specific */ - unsigned char additionalSenseCode; /* 12 What kind of error */ - unsigned char additionalSenseQualifier; /* 13 More error info */ - unsigned char fruCode; /* 14 Field replacable */ - unsigned char senseKeySpecific[2]; /* 15-16 Additional info */ - unsigned char additional[101]; /* 17-26 Additional info */ -} SCSISenseData; - -/* - * The high-bit of errorCode signals whether there is a logical - * block. The low value signals whether there is a valid sense - */ -enum _SCSIErrorCode -{ - kSCSISenseHasLBN = 0x80, /* Logical block number set */ - kSCSISenseInfoValid = 0x70, /* Is sense key valid? */ - kSCSISenseInfoMask = 0x70, /* Mask for sense info */ - kSCSISenseCurrentErr = 0x70, /* Error code (byte 0 & 0x7F */ - kSCSISenseDeferredErr = 0x71, /* Error code (byte 0 & 0x7F */ -}; - -/* - * These bits may be set in the sense key - */ -enum _SCSISenseKeyMasks -{ - kSCSISenseKeyMask = 0x0F, - kSCSISenseILI = 0x20, /* Illegal logical Length */ - kSCSISenseEOM = 0x40, /* End of media */ - kSCSISenseFileMark = 0x80, /* End of file mark */ -}; -/* - * SCSI sense codes. (Returned after request sense). - */ -enum _SCSISenseKeys -{ - kSCSISenseNone = 0x00, /* No error */ - kSCSISenseRecoveredErr = 0x01, /* Warning */ - kSCSISenseNotReady = 0x02, /* Device not ready */ - kSCSISenseMediumErr = 0x03, /* Device medium error */ - kSCSISenseHardwareErr = 0x04, /* Device hardware error */ - kSCSISenseIllegalReq = 0x05, /* Illegal request for dev. */ - kSCSISenseUnitAtn = 0x06, /* Unit attention (not err) */ - kSCSISenseDataProtect = 0x07, /* Data protection */ - kSCSISenseBlankCheck = 0x08, /* Tape-specific error */ - kSCSISenseVendorSpecific = 0x09, /* Vendor-specific error */ - kSCSISenseCopyAborted = 0x0a, /* Copy request cancelled */ - kSCSISenseAbortedCmd = 0x0b, /* Initiator aborted cmd. */ - kSCSISenseEqual = 0x0c, /* Comparison equal */ - kSCSISenseVolumeOverflow = 0x0d, /* Write past end mark */ - kSCSISenseMiscompare = 0x0e, /* Comparison failed */ -}; - -enum _SCSIStatus -{ - kSCSIStatusGood = 0x00, - kSCSIStatusCheckCondition = 0x02, - kSCSIStatusConditionMet = 0x04, - kSCSIStatusBusy = 0x08, - kSCSIStatusIntermediate = 0x10, - kSCSIStatusIntermediateMet = 0x0a, - kSCSIStatusReservationConfict = 0x18, - kSCSIStatusCommandTerminated = 0x22, - kSCSIStatusQueueFull = 0x28, -}; - - -enum _SCSIDevTypes -{ - kSCSIDevTypeDirect = 0, /* Hard disk (not CD-ROM) */ - kSCSIDevTypeSequential, /* Magtape or DAT */ - kSCSIDevTypePrinter, /* Printer */ - kSCSIDevTypeProcessor, /* Attached processor */ - kSCSIDevTypeWorm, /* Write-once, read multiple */ - kSCSIDevTypeCDROM, /* CD-ROM */ - kSCSIDevTypeScanner, /* Scanner */ - kSCSIDevTypeOptical, /* Optical disk */ - kSCSIDevTypeChanger, /* Jukebox */ - kSCSIDevTypeComm, /* Communication link */ - kSCSIDevTypeGraphicArts0A, - kSCSIDevTypeGraphicArts0B, - kSCSIDevTypeFirstReserved, /* Reserved sequence start */ - kSCSIDevTypeUnknownOrMissing = 0x1F, - kSCSIDevTypeMask = 0x1F, -}; - -enum _SCSIInqVersion -{ - kSCSIInqVersionSCSI3 = 0x03, -}; - -enum _SCSI3Options -{ - kSCSI3InqOptionIUS = 0x01, - kSCSI3InqOptionQAS = 0x02, - kSCSI3InqOptionClockDT = 0x04, -}; - - -/* - * SCSI command codes. Commands defined as ...6, ...10, ...12, are - * six-byte, ten-byte, and twelve-byte variants of the indicated command. - */ - -/* - * These commands are supported for all devices. - */ -enum _SCSICmds -{ - kSCSICmdChangeDefinition = 0x40, - kSCSICmdCompare = 0x39, - kSCSICmdCopy = 0x18, - kSCSICmdCopyAndVerify = 0x3a, - kSCSICmdInquiry = 0x12, - kSCSICmdLogSelect = 0x4c, - kSCSICmdLogSense = 0x4d, - kSCSICmdModeSelect12 = 0x55, - kSCSICmdModeSelect6 = 0x15, - kSCSICmdModeSense12 = 0x5a, - kSCSICmdModeSense6 = 0x1a, - kSCSICmdReadBuffer = 0x3c, - kSCSICmdRecvDiagResult = 0x1c, - kSCSICmdRequestSense = 0x03, - kSCSICmdSendDiagnostic = 0x1d, - kSCSICmdTestUnitReady = 0x00, - kSCSICmdWriteBuffer = 0x3b, - -/* - * These commands are supported by direct-access devices only. - */ - kSCSICmdFormatUnit = 0x04, - kSCSICmdLockUnlockCache = 0x36, - kSCSICmdPrefetch = 0x34, - kSCSICmdPreventAllowRemoval = 0x1e, - kSCSICmdRead6 = 0x08, - kSCSICmdRead10 = 0x28, - kSCSICmdReadCapacity = 0x25, - kSCSICmdReadDefectData = 0x37, - kSCSICmdReadLong = 0x3e, - kSCSICmdReassignBlocks = 0x07, - kSCSICmdRelease = 0x17, - kSCSICmdReserve = 0x16, - kSCSICmdRezeroUnit = 0x01, - kSCSICmdSearchDataEql = 0x31, - kSCSICmdSearchDataHigh = 0x30, - kSCSICmdSearchDataLow = 0x32, - kSCSICmdSeek6 = 0x0b, - kSCSICmdSeek10 = 0x2b, - kSCSICmdSetLimits = 0x33, - kSCSICmdStartStopUnit = 0x1b, - kSCSICmdSynchronizeCache = 0x35, - kSCSICmdVerify = 0x2f, - kSCSICmdWrite6 = 0x0a, - kSCSICmdWrite10 = 0x2a, - kSCSICmdWriteAndVerify = 0x2e, - kSCSICmdWriteLong = 0x3f, - kSCSICmdWriteSame = 0x41, - -/* - * These commands are supported by sequential devices. - */ - kSCSICmdRewind = 0x01, - kSCSICmdWriteFilemarks = 0x10, - kSCSICmdSpace = 0x11, - kSCSICmdLoadUnload = 0x1B, -/* - * ANSI SCSI-II for CD-ROM devices. - */ - kSCSICmdReadCDTableOfContents = 0x43, -}; - -/* - * Message codes (for Msg In and Msg Out phases). - */ -enum _SCSIMsgs -{ - kSCSIMsgAbort = 0x06, - kSCSIMsgAbortTag = 0x0d, - kSCSIMsgBusDeviceReset = 0x0c, - kSCSIMsgClearQueue = 0x0e, - kSCSIMsgCmdComplete = 0x00, - kSCSIMsgDisconnect = 0x04, - kSCSIMsgIdentify = 0x80, - kSCSIMsgIgnoreWideResdue = 0x23, - kSCSIMsgInitiateRecovery = 0x0f, - kSCSIMsgInitiatorDetectedErr = 0x05, - kSCSIMsgLinkedCmdComplete = 0x0a, - kSCSIMsgLinkedCmdCompleteFlag = 0x0b, - kSCSIMsgParityErr = 0x09, - kSCSIMsgRejectMsg = 0x07, - kSCSIMsgModifyDataPtr = 0x00, /* Extended msg */ - kSCSIMsgNop = 0x08, - kSCSIMsgHeadOfQueueTag = 0x21, /* Two byte msg */ - kSCSIMsgOrderedQueueTag = 0x22, /* Two byte msg */ - kSCSIMsgSimpleQueueTag = 0x20, /* Two byte msg */ - kSCSIMsgReleaseRecovery = 0x10, - kSCSIMsgRestorePointers = 0x03, - kSCSIMsgSaveDataPointers = 0x02, - kSCSIMsgSyncXferReq = 0x01, /* Extended msg */ - kSCSIMsgWideDataXferReq = 0x03, /* Extended msg */ - kSCSIMsgTerminateIOP = 0x11, - kSCSIMsgExtended = 0x01, - kSCSIMsgEnableDisconnectMask = 0x40, -}; - -#endif diff --git a/iokit/IOKit/scsi/scsi-parallel/IOSCSIParallelCommand.h b/iokit/IOKit/scsi/scsi-parallel/IOSCSIParallelCommand.h deleted file mode 100644 index 21a72a1c3..000000000 --- a/iokit/IOKit/scsi/scsi-parallel/IOSCSIParallelCommand.h +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * IOSCSICommand.h - * - */ -#ifndef _IOSCSIPARALLELCOMMAND_H -#define _IOSCSIPARALLELCOMMAND_H - -class IOSCSIParallelDevice; -class IOSCSIParallelCommand; -class IOSyncer; - -class IOSCSIParallelCommand : public IOSCSICommand -{ - OSDeclareDefaultStructors(IOSCSIParallelCommand) - - friend class IOSCSIParallelController; - friend class IOSCSIParallelDevice; - -/*------------------Methods provided to IOCDBCommand users -------------------------*/ -public: - /* - * Set/Get IOMemoryDescriptor object to I/O data buffer or sense data buffer. - */ - void setPointers( IOMemoryDescriptor *desc, - UInt32 transferCount, - bool isWrite, - bool isSense = false ); - - void getPointers( IOMemoryDescriptor **desc, - UInt32 *transferCount, - bool *isWrite, - bool isSense = false ); - /* - * Set/Get command timeout (mS) - */ - void setTimeout( UInt32 timeoutmS ); - UInt32 getTimeout(); - - /* - * Set async callback routine. Specifying no parameters indicates synchronous call. - */ - void setCallback( void *target = 0, CallbackFn callback = 0, void *refcon = 0 ); - - /* - * Set/Get CDB information. (Generic CDB version) - */ - void setCDB( CDBInfo *cdbInfo ); - void getCDB( CDBInfo *cdbInfo ); - - /* - * Get CDB results. (Generic CDB version) - */ - IOReturn getResults( CDBResults *cdbResults ); - - /* - * Get CDB Device this command is directed to. - */ - IOCDBDevice *getDevice( IOCDBDevice *deviceType ); - - /* - * Command verbs - */ - bool execute( UInt32 *sequenceNumber = 0 ); - void abort( UInt32 sequenceNumber ); - void complete(); - - /* - * Get pointers to client and command data. - */ - void *getCommandData(); - void *getClientData(); - - /* - * Get unique sequence number assigned to command. - */ - UInt32 getSequenceNumber(); - -/*------------------ Additional methods provided to IOSCSICommand users -------------------------*/ -public: - /* - * Set/Get CDB information. (SCSI specific version). - */ - void setCDB( SCSICDBInfo *scsiCmd ); - void getCDB( SCSICDBInfo *scsiCmd ); - - /* - * Get/Set CDB results. (SCSI specific version). - */ - IOReturn getResults( SCSIResults *results ); - void setResults( SCSIResults *results, SCSINegotiationResults *negotiationResults ); - - /* - * Get SCSI Device this command is directed to. - */ - IOSCSIParallelDevice *getDevice( IOSCSIParallelDevice *deviceType ); - - - /* - * Get SCSI Target/Lun for this command. - */ - void getTargetLun( SCSITargetLun *targetLun ); - - /* - * Get/Set queue routing for this command. - */ - void setQueueInfo( UInt32 forQueueType = kQTypeNormalQ, UInt32 forQueuePosition = kQPositionTail ); - void getQueueInfo( UInt32 *forQueueType, UInt32 *forQueuePosition = 0 ); - - /* - * Get command type / Get original command. - * - * These methods are provided for the controller class to identify and relate commands. - * They are not usually of interest to the client side. - */ - UInt32 getCmdType(); - IOSCSIParallelCommand *getOriginalCmd(); - - /* - * Set to blank state, call prior to re-use of this object. - */ - void zeroCommand(); - -/*------------------Methods private to the IOSCSICommand class-------------------------*/ -public: - void free(); - - IOSCSIDevice *getDevice( IOSCSIDevice *deviceType ); - void setResults( SCSIResults *results ); - -private: - IOReturn adapterStatusToIOReturnCode( SCSIAdapterStatus adapterStatus ); - IOReturn scsiStatusToIOReturnCode( UInt8 scsiStatus ); - -private: - SCSICommandType cmdType; - - IOSCSIParallelController *controller; - IOSCSIParallelDevice *device; - - queue_head_t *list; - queue_chain_t nextCommand; - - SCSICDBInfo scsiCmd; - SCSIResults results; - - UInt32 timeout; - UInt32 timer; - - UInt8 queueType; - UInt8 queuePosition; - - IOMemoryDescriptor *xferDesc; - UInt32 xferCount; - UInt32 xferDirection; - - UInt32 senseLength; - IOMemoryDescriptor *senseData; - - IOSCSIParallelCommand *origCommand; - - union - { - struct - { - UInt32 reserved; - IOSyncer * lock; - } sync; - struct - { - CallbackFn callback; - void *target; - void *refcon; - } async; - } completionInfo; - - UInt32 dataSize; - void *dataArea; - void *commandPrivateData; - void *clientData; - - UInt32 sequenceNumber; -}; - -#endif diff --git a/iokit/IOKit/scsi/scsi-parallel/IOSCSIParallelController.h b/iokit/IOKit/scsi/scsi-parallel/IOSCSIParallelController.h deleted file mode 100644 index feaa8ecdb..000000000 --- a/iokit/IOKit/scsi/scsi-parallel/IOSCSIParallelController.h +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * IOSCSIController.h - * - * Methods in this header list the methods an SCSI controller driver must implement. - */ -#ifndef _IOSCSIPARALLELCONTROLLER_H -#define _IOSCSIPARALLELCONTROLLER_H - -#include -#include -#include -#include -#include -#include - -class IOSCSIParallelDevice; -class IOSCSIParallelCommand; - -class IOSCSIParallelController : public IOService -{ - OSDeclareDefaultStructors(IOSCSIParallelController) - - friend class IOSCSIParallelCommand; - friend class IOSCSIParallelDevice; - -/*------------------Methods provided by IOSCSIParallelController---------------------------------*/ -public: - bool probeTarget( SCSITargetLun targetLun ); - void reset(); - -protected: - void resetOccurred(); - - void enableCommands(); - void disableCommands(); - void disableCommands( UInt32 disableTimeoutmS ); - - void rescheduleCommand( IOSCSIParallelCommand *forSCSICmd ); - - IOSCSIParallelDevice *findDeviceWithTargetLun( SCSITargetLun targetLun ); - IOSCSIParallelCommand *findCommandWithNexus( SCSITargetLun targetLun, UInt32 tagValue = (UInt32)-1 ); - - void *getTargetData( SCSITargetLun targetLun ); - void *getLunData( SCSITargetLun targetLun ); - - virtual IOWorkLoop *getWorkLoop() const; - - void setCommandLimit( UInt32 commandLimit ); // temp - - -/*------------------Methods the controller subclass must implement-----------------------*/ -protected: - /* - * Initialize controller hardware. - * - * Note: The controller driver's configure() method will be called prior to any other - * methods. If the controller driver returns successfully from this method it - * should be ready to accept any other method call listed. - */ - virtual bool configure( IOService *provider, SCSIControllerInfo *controllerInfo ) = 0; - - /* - * Bus/target commands - * - */ - virtual void executeCommand( IOSCSIParallelCommand *forSCSICmd ) = 0; - virtual void cancelCommand( IOSCSIParallelCommand *forSCSICmd ) = 0; - virtual void resetCommand( IOSCSIParallelCommand *forSCSICmd ) = 0; - -/*------------------Optional methods the controller subclass may implement-----------------------*/ -protected: - /* - * These methods notify the IOSCSIParallelController subclass, that a target or lun is about to be - * probed. The subclass should initialize its per-target or per-lun data when called at these - * methods. If the subclass (for some reason) wants to prevent probing of a target or lun, it - * can return false to the corresponding allocate*() call. - */ - virtual bool allocateTarget( SCSITargetLun targetLun ); - virtual void deallocateTarget( SCSITargetLun targetLun ); - - virtual bool allocateLun( SCSITargetLun targetLun ); - virtual void deallocateLun( SCSITargetLun targetLun ); - - virtual void disableTimeoutOccurred(); - - -/*------------------Methods private to the IOSCSIParallelController class----------------------*/ - -public: - bool start( IOService *provider ); - void free(); - -private: - IOSCSIParallelDevice *createDevice(); - - void initQueues(); - bool scanSCSIBus(); - - bool initTarget( SCSITargetLun targetLun ); - bool initTargetGated( SCSITargetLun *targetLun ); - void releaseTarget( SCSITargetLun targetLun ); - void releaseTargetGated( SCSITargetLun *targetLun ); - bool initDevice( IOSCSIParallelDevice *device ); - bool initDeviceGated( IOSCSIParallelDevice *device ); - void releaseDevice( IOSCSIParallelDevice *device ); - void releaseDeviceGated( IOSCSIParallelDevice *device ); - - - void addDevice( IOSCSIParallelDevice *forDevice ); - void deleteDevice( IOSCSIParallelDevice *forDevice ); - - void timer( IOTimerEventSource *); - - void dispatchRequest(); - void dispatch(); - - bool checkBusReset(); - - void completeCommand( IOSCSIParallelCommand *forSCSICmd ); - - bool createWorkLoop(); - bool configureController(); - - IOSCSIParallelCommand *allocCommand( UInt32 clientDataSize ); - -private: - - UInt32 sequenceNumber; - - UInt32 commandCount; - UInt32 commandLimit; - UInt32 commandLimitSave; - - UInt32 disableTimer; - bool commandDisable; - - UInt32 tagArraySize; - UInt32 *tagArray; - - UInt32 busResetState; - IOSCSIParallelCommand *resetCmd; - UInt32 resetTimer; - - IOSCSIParallelCommand *noDisconnectCmd; - - SCSIControllerInfo controllerInfo; - SCSITarget *targets; - - IOWorkLoop *workLoop; - IOTimerEventSource *timerEvent; - IOInterruptEventSource *dispatchEvent; - - IOCommandGate *controllerGate; - - IOService *provider; -}; - -#endif diff --git a/iokit/IOKit/scsi/scsi-parallel/IOSCSIParallelDevice.h b/iokit/IOKit/scsi/scsi-parallel/IOSCSIParallelDevice.h deleted file mode 100644 index 9b72757ac..000000000 --- a/iokit/IOKit/scsi/scsi-parallel/IOSCSIParallelDevice.h +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * IOSCSIParallelDevice.h - * - * - * Methods in this header provide information about the SCSI device - * the device client driver is submitting the SCSICommand(s) to. - * - * Note: SCSICommand(s) are allocated and freed by methods in this class. - * The remaining methods to setup and submit SCSICommands are defined in - * IOSCSICommand.h - */ - -#ifndef _IOSCSIPARALLELDEVICE_H -#define _IOSCSIPARALLELDEVICE_H - -class IOSCSIParallelController; - -class IOSCSIParallelDevice : public IOSCSIDevice -{ - OSDeclareDefaultStructors(IOSCSIParallelDevice) - - friend class IOSCSIParallelCommand; - friend class IOSCSIParallelController; - -/*------------------Methods provided to IOCDBDevice clients-----------------------*/ -public: - - /* - * Allocate a CDB Command - */ - IOCDBCommand *allocCommand( IOCDBDevice *deviceType, UInt32 clientDataSize = 0 ); - - /* - * Abort all outstanding commands on this device - */ - void abort(); - - /* - * Reset device (also aborts all outstanding commands) - */ - void reset(); - - /* - * Obtain information about this device - */ - void getInquiryData( void *inquiryBuffer, - UInt32 inquiryBufSize, - UInt32 *inquiryDataSize ); - -/*------------------Additional methods provided to IOSCSIDevice clients-----------------------*/ -public: - /* - * Allocate a SCSICommand - */ - IOSCSIParallelCommand *allocCommand( IOSCSIParallelDevice *deviceType, UInt32 clientDataSize = 0 ); - - /* - * Target management commands - */ - bool setTargetParms( SCSITargetParms *targetParms ); - void getTargetParms( SCSITargetParms *targetParms ); - - /* - * Lun management commands - */ - bool setLunParms( SCSILunParms *lunParms ); - void getLunParms( SCSILunParms *lunParms ); - - /* - * Queue management commands - */ - void holdQueue( UInt32 queueType ); - void releaseQueue( UInt32 queueType ); - void flushQueue( UInt32 queueType, IOReturn rc ); - void notifyIdle( void *target = 0, CallbackFn callback = 0, void *refcon = 0 ); - - /* - * - */ - IOWorkLoop *getWorkLoop() const; - -/*------------------Methods private to the IOSCSIDevice class----------------*/ -public: - bool open( IOService *forClient, IOOptionBits options = 0, void *arg = 0 ); - void close( IOService *forClient, IOOptionBits options = 0 ); - IOReturn message( UInt32 clientMsg, IOService *forProvider, void *forArg = 0 ); - bool init( IOSCSIParallelController *forController, SCSITargetLun forTargetLun ); - void free(); - - bool matchPropertyTable( OSDictionary * table ); - IOService *matchLocation( IOService * client ); - - IOSCSICommand *allocCommand( IOSCSIDevice *deviceType, UInt32 clientDataSize = 0 ); - -private: - void submitCommand( UInt32 cmdType, IOSCSIParallelCommand *scsiCmd, UInt32 cmdSequenceNumber = 0 ); - void receiveCommand( UInt32 cmdType, IOSCSIParallelCommand *scsiCmd, UInt32 cmdSequenceNumber, void *p3 ); - - IOReturn probeTargetLun(); - bool checkCmdQueEnabled(); - void setupTarget(); - - void dispatchRequest(); - bool dispatch( UInt32 *dispatchAction ); - - void abortAllCommands( SCSICommandType abortCmdType ); - - IOSCSIParallelCommand *findCommandWithNexus( UInt32 tagValue ); - - void abortCommand( IOSCSIParallelCommand *scsiCmd, UInt32 cmdSequenceNumber ); - void completeCommand( IOSCSIParallelCommand *cmd ); - - void checkIdleNotify(); - - void executeCommandDone( IOSCSIParallelCommand *scsiCmd ); - void executeReqSenseDone( IOSCSIParallelCommand *scsiCmd ); - void abortCommandDone( IOSCSIParallelCommand *scsiCmd ); - void cancelCommandDone( IOSCSIParallelCommand *scsiCmd ); - void finishCommand( IOSCSIParallelCommand *scsiCmd ); - - OSDictionary *createProperties(); - bool addToRegistry( OSDictionary *propTable, OSObject *regObj, char *key, bool doRelease = true ); - void stripBlanks( char *d, char *s, UInt32 l ); - - bool checkDeviceQueue( UInt32 *dispatchAction ); - void checkNegotiate( IOSCSIParallelCommand *scsiCmd ); - bool checkTag( IOSCSIParallelCommand *scsiCmd ); - bool checkReqSense(); - bool checkAbortQueue(); - void checkCancelQueue(); - - void negotiationComplete(); - - bool allocTag( UInt32 *tagId ); - void freeTag( UInt32 tagId ); - - void timer(); - - void resetOccurred( SCSIClientMessage clientMsg ); - void resetComplete(); - - void rescheduleCommand( IOSCSIParallelCommand *scsiCmd ); - - void addCommand( queue_head_t *list, IOSCSIParallelCommand *scsiCmd ); - void stackCommand( queue_head_t *list, IOSCSIParallelCommand *scsiCmd ); - void deleteCommand( queue_head_t *list, IOSCSIParallelCommand *scsiCmd, IOReturn rc = kIOReturnSuccess ); - IOSCSIParallelCommand *checkCommand( queue_head_t *list ); - IOSCSIParallelCommand *getCommand( queue_head_t *list ); - void moveCommand( queue_head_t *fromList, - queue_head_t *toList, - IOSCSIParallelCommand *scsiCmd, - IOReturn rc = kIOReturnSuccess ); - void moveAllCommands( queue_head_t *fromList, queue_head_t *toList, IOReturn rc = kIOReturnSuccess ); - bool findCommand( queue_head_t *list, IOSCSIParallelCommand *findScsiCmd ); - void purgeAllCommands( queue_head_t *list, IOReturn rc ); - -private: - queue_chain_t nextDevice; - - SCSITargetLun targetLun; - - SCSITarget *target; - - IOSCSIParallelController *controller; - IOCommandGate *deviceGate; - - IOService *client; - IORWLock * clientSem; - - queue_head_t deviceList; - queue_head_t bypassList; - queue_head_t activeList; - queue_head_t abortList; - queue_head_t cancelList; - - SCSICommandType abortCmdPending; - - UInt32 reqSenseState; - UInt32 abortState; - UInt32 cancelState; - UInt32 negotiateState; - - IOSCSIParallelCommand *reqSenseOrigCmd; - - IOSCSIParallelCommand *reqSenseCmd; - IOSCSIParallelCommand *abortCmd; - IOSCSIParallelCommand *cancelCmd; - IOSCSIParallelCommand *probeCmd; - - bool normalQHeld; - bool bypassQHeld; - - bool idleNotifyActive; - CallbackFn idleNotifyCallback; - void *idleNotifyTarget; - void *idleNotifyRefcon; - - UInt32 commandCount; - UInt32 commandLimit; - UInt32 commandLimitSave; - - bool disableDisconnect; - - bool lunAllocated; - - OSNumber *regObjTransferPeriod; - OSNumber *regObjTransferOffset; - OSNumber *regObjTransferWidth; - OSNumber *regObjTransferOptions; - OSNumber *regObjCmdQueue; - - UInt32 *tagArray; - - SCSILunParms lunParmsNew; - - SCSIInquiry *inquiryData; - UInt32 inquiryDataSize; - - void *devicePrivateData; -}; - -#define kIOSCSIParallelDevice ((IOSCSIParallelDevice *)0) - -#endif diff --git a/iokit/IOKit/scsi/scsi-parallel/Makefile b/iokit/IOKit/scsi/scsi-parallel/Makefile deleted file mode 100644 index bc17ca9e4..000000000 --- a/iokit/IOKit/scsi/scsi-parallel/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -export MakeInc_cmd=${SRCROOT}/makedefs/MakeInc.cmd -export MakeInc_def=${SRCROOT}/makedefs/MakeInc.def -export MakeInc_rule=${SRCROOT}/makedefs/MakeInc.rule -export MakeInc_dir=${SRCROOT}/makedefs/MakeInc.dir - -IOKIT_FRAMEDIR = $(FRAMEDIR)/IOKit.framework/Versions/A -export INCDIR = $(IOKIT_FRAMEDIR)/Headers -export LCLDIR = $(IOKIT_FRAMEDIR)/PrivateHeaders - -include $(MakeInc_cmd) -include $(MakeInc_def) - -MI_DIR = scsi/scsi-parallel -NOT_EXPORT_HEADERS = - -INSTINC_SUBDIRS = -INSTINC_SUBDIRS_PPC = -INSTINC_SUBDIRS_I386 = - -EXPINC_SUBDIRS = ${INSTINC_SUBDIRS} -EXPINC_SUBDIRS_PPC = ${INSTINC_SUBDIRS_PPC} -EXPINC_SUBDIRS_I386 = ${INSTINC_SUBDIRS_I386} - -ALL_HEADERS = $(shell (cd $(SOURCE); echo *.h)) - -INSTALL_MI_LIST = -INSTALL_MI_LCL_LIST = "" - -INSTALL_MI_DIR = $(MI_DIR) - -EXPORT_MI_LIST = $(filter-out $(NOT_EXPORT_HEADERS), $(ALL_HEADERS)) - -EXPORT_MI_DIR = IOKit/$(MI_DIR) - -include $(MakeInc_rule) -include $(MakeInc_dir) diff --git a/iokit/IOKit/scsi/scsi-parallel/SCSIParallelController.h b/iokit/IOKit/scsi/scsi-parallel/SCSIParallelController.h deleted file mode 100644 index f85aa8a02..000000000 --- a/iokit/IOKit/scsi/scsi-parallel/SCSIParallelController.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * SCSIParallelController.h - * - */ - -#ifndef _SCSIPARALLELCONTROLLER_H -#define _SCSIPARALLELCONTROLLER_H - -class IOSyncer; - -typedef struct SCSIControllerInfo -{ - UInt32 initiatorId; - - UInt32 maxTargetsSupported; - UInt32 maxLunsSupported; - - UInt32 minTransferPeriodpS; - UInt32 maxTransferOffset; - UInt32 maxTransferWidth; - - UInt32 maxCommandsPerController; - UInt32 maxCommandsPerTarget; - UInt32 maxCommandsPerLun; - - UInt32 tagAllocationMethod; - UInt32 maxTags; - - UInt32 targetPrivateDataSize; - UInt32 lunPrivateDataSize; - UInt32 commandPrivateDataSize; - - bool disableCancelCommands; - - UInt32 reserved[64]; - -} SCSIControllerInfo; - -enum SCSITagAllocation -{ - kTagAllocationNone = 0, - kTagAllocationPerLun, - kTagAllocationPerTarget, - kTagAllocationPerController, -}; - -/* - * Private for IOSCSIClass - */ -enum WorkLoopReqType -{ - kWorkLoopInitTarget = 1, - kWorkLoopReleaseTarget, - kWorkLoopInitDevice, - kWorkLoopReleaseDevice, -}; - -enum DispatchAction -{ - kDispatchNextCommand = 1, - kDispatchNextLun, - kDispatchNextTarget, - kDispatchStop, -}; - -typedef struct WorkLoopRequest -{ - WorkLoopReqType type; - IOSyncer * sync; - bool rc; -} WorkLoopRequest; - -#endif - diff --git a/iokit/IOKit/scsi/scsi-parallel/SCSIParallelTarget.h b/iokit/IOKit/scsi/scsi-parallel/SCSIParallelTarget.h deleted file mode 100644 index c27e15387..000000000 --- a/iokit/IOKit/scsi/scsi-parallel/SCSIParallelTarget.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * - * SCSIParallelTarget.h - * - */ - -#ifndef _SCSIPARALLELTARGET_H -#define _SCSIPARALLELTARGET_H - -typedef struct SCSINegotiationResults -{ - IOReturn returnCode; - - UInt32 transferPeriodpS; - UInt32 transferOffset; - UInt32 transferWidth; - UInt32 transferOptions; - -} SCSINegotiationResults; - - -typedef struct SCSITarget -{ - queue_head_t deviceList; - - UInt32 commandCount; - UInt32 commandLimit; - UInt32 commandLimitSave; - - IORWLock * clientSem; - IORWLock * targetSem; - - UInt32 *tagArray; - - UInt32 negotiateState; - SCSINegotiationResults negotiationResult; - - UInt32 state; - - SCSITargetParms targetParmsCurrent; - SCSITargetParms targetParmsNew; - - OSNumber *regObjTransferPeriod; - OSNumber *regObjTransferOffset; - OSNumber *regObjTransferWidth; - OSNumber *regObjTransferOptions; - OSNumber *regObjCmdQueue; - - UInt32 reqSenseCount; - UInt32 reqSenseState; - - void *targetPrivateData; - - bool targetAllocated; - -} SCSITarget; - -enum -{ - kStateIdle, - kStateIssue, - kStatePending, - kStateActive, -}; - -enum _cdbFlagsInternal -{ - kCDBFlagsEnableTagQueuing = 0x80000000, -}; - - -enum SCSICommandType -{ - kSCSICommandNone = 0, - kSCSICommandExecute, - kSCSICommandReqSense, - kSCSICommandAbort, - kSCSICommandAbortAll, - kSCSICommandDeviceReset, - kSCSICommandBusReset, - kSCSICommandCancel, -}; - - -#endif diff --git a/iokit/IOKit/system.h b/iokit/IOKit/system.h index 53e19969a..ce7ba1154 100644 --- a/iokit/IOKit/system.h +++ b/iokit/IOKit/system.h @@ -75,8 +75,6 @@ void panic(const char * msg, ...); /* */ -#ifdef __ppc__ - /* * Really need a set of interfaces from osfmk/pexpert components to do * all that is required to prepare an I/O from a cache management point @@ -86,8 +84,6 @@ void panic(const char * msg, ...); extern void invalidate_icache(vm_offset_t addr, unsigned cnt, int phys); extern void flush_dcache(vm_offset_t addr, unsigned count, int phys); -#endif - __END_DECLS #endif /* !__IOKIT_SYSTEM_H */ diff --git a/iokit/Kernel/IOBufferMemoryDescriptor.cpp b/iokit/Kernel/IOBufferMemoryDescriptor.cpp index 2bf4b50e8..d09defb1e 100644 --- a/iokit/Kernel/IOBufferMemoryDescriptor.cpp +++ b/iokit/Kernel/IOBufferMemoryDescriptor.cpp @@ -27,6 +27,7 @@ __BEGIN_DECLS void ipc_port_release_send(ipc_port_t port); +#include __END_DECLS extern "C" vm_map_t IOPageableMapForAddress( vm_address_t address ); @@ -82,8 +83,11 @@ bool IOBufferMemoryDescriptor::initWithRanges( bool IOBufferMemoryDescriptor::initWithOptions( IOOptionBits options, vm_size_t capacity, - vm_offset_t alignment) + vm_offset_t alignment, + task_t inTask) { + vm_map_t map = 0; + if (!capacity) return false; @@ -96,30 +100,66 @@ bool IOBufferMemoryDescriptor::initWithOptions( if ((options & kIOMemorySharingTypeMask) && (alignment < page_size)) alignment = page_size; + if ((inTask != kernel_task) && !(options & kIOMemoryPageable)) + return false; + _alignment = alignment; if (options & kIOMemoryPageable) - /* Allocate some kernel address space. */ - _buffer = IOMallocPageable(capacity, alignment); - /* Allocate a wired-down buffer inside kernel space. */ - else if (options & kIOMemoryPhysicallyContiguous) - _buffer = IOMallocContiguous(capacity, alignment, 0); - else if (alignment > 1) - _buffer = IOMallocAligned(capacity, alignment); - else - _buffer = IOMalloc(capacity); + { + if (inTask == kernel_task) + { + /* Allocate some kernel address space. */ + _buffer = IOMallocPageable(capacity, alignment); + if (_buffer) + map = IOPageableMapForAddress((vm_address_t) _buffer); + } + else + { + kern_return_t kr; + + if( !reserved) { + reserved = IONew( ExpansionData, 1 ); + if( !reserved) + return( false ); + } + map = get_task_map(inTask); + vm_map_reference(map); + reserved->map = map; + kr = vm_allocate( map, (vm_address_t *) &_buffer, round_page(capacity), + VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_IOKIT) ); + if( KERN_SUCCESS != kr) + return( false ); + + // we have to make sure that these pages don't get copied on fork. + kr = vm_inherit( map, (vm_address_t) _buffer, round_page(capacity), VM_INHERIT_NONE); + if( KERN_SUCCESS != kr) + return( false ); + } + } + else + { + /* Allocate a wired-down buffer inside kernel space. */ + if (options & kIOMemoryPhysicallyContiguous) + _buffer = IOMallocContiguous(capacity, alignment, 0); + else if (alignment > 1) + _buffer = IOMallocAligned(capacity, alignment); + else + _buffer = IOMalloc(capacity); + } if (!_buffer) - return false; + return false; _singleRange.v.address = (vm_address_t) _buffer; _singleRange.v.length = capacity; if (!super::initWithRanges(&_singleRange.v, 1, (IODirection) (options & kIOMemoryDirectionMask), - kernel_task, true)) + inTask, true)) return false; - if (options & kIOMemoryPageable) { + if (options & kIOMemoryPageable) + { _flags |= kIOMemoryRequiresWire; kern_return_t kr; @@ -128,7 +168,7 @@ bool IOBufferMemoryDescriptor::initWithOptions( // must create the entry before any pages are allocated if( 0 == sharedMem) { - kr = mach_make_memory_entry( IOPageableMapForAddress( _ranges.v[0].address ), + kr = mach_make_memory_entry( map, &size, _ranges.v[0].address, VM_PROT_READ | VM_PROT_WRITE, &sharedMem, NULL ); @@ -140,8 +180,9 @@ bool IOBufferMemoryDescriptor::initWithOptions( sharedMem = 0; _memEntry = (void *) sharedMem; } - - } else { + } + else + { /* Precompute virtual-to-physical page mappings. */ vm_address_t inBuffer = (vm_address_t) _buffer; _physSegCount = atop(trunc_page(inBuffer + capacity - 1) - @@ -163,6 +204,29 @@ bool IOBufferMemoryDescriptor::initWithOptions( return true; } +IOBufferMemoryDescriptor * IOBufferMemoryDescriptor::inTaskWithOptions( + task_t inTask, + IOOptionBits options, + vm_size_t capacity, + vm_offset_t alignment = 1) +{ + IOBufferMemoryDescriptor *me = new IOBufferMemoryDescriptor; + + if (me && !me->initWithOptions(options, capacity, alignment, inTask)) { + me->release(); + me = 0; + } + return me; +} + +bool IOBufferMemoryDescriptor::initWithOptions( + IOOptionBits options, + vm_size_t capacity, + vm_offset_t alignment) +{ + return( initWithOptions(options, capacity, alignment, kernel_task) ); +} + IOBufferMemoryDescriptor * IOBufferMemoryDescriptor::withOptions( IOOptionBits options, vm_size_t capacity, @@ -170,7 +234,7 @@ IOBufferMemoryDescriptor * IOBufferMemoryDescriptor::withOptions( { IOBufferMemoryDescriptor *me = new IOBufferMemoryDescriptor; - if (me && !me->initWithOptions(options, capacity, alignment)) { + if (me && !me->initWithOptions(options, capacity, alignment, kernel_task)) { me->release(); me = 0; } @@ -252,18 +316,32 @@ void IOBufferMemoryDescriptor::free() IOOptionBits options = _options; vm_size_t size = _capacity; void * buffer = _buffer; + vm_map_t map = 0; vm_offset_t alignment = _alignment; if (_physAddrs) IODelete(_physAddrs, IOPhysicalAddress, _physSegCount); + if (reserved) + { + map = reserved->map; + IODelete( reserved, ExpansionData, 1 ); + } + /* super::free may unwire - deallocate buffer afterwards */ super::free(); - if (buffer) { + if (buffer) + { if (options & kIOMemoryPageable) - IOFreePageable(buffer, size); - else { + { + if (map) + vm_deallocate(map, (vm_address_t) buffer, round_page(size)); + else + IOFreePageable(buffer, size); + } + else + { if (options & kIOMemoryPhysicallyContiguous) IOFreeContiguous(buffer, size); else if (alignment > 1) @@ -272,6 +350,8 @@ void IOBufferMemoryDescriptor::free() IOFree(buffer, size); } } + if (map) + vm_map_deallocate(map); } /* @@ -407,7 +487,7 @@ IOBufferMemoryDescriptor::getPhysicalSegment(IOByteCount offset, return physAddr; } -OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 0); +OSMetaClassDefineReservedUsed(IOBufferMemoryDescriptor, 0); OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 1); OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 2); OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 3); diff --git a/iokit/Kernel/IOCPU.cpp b/iokit/Kernel/IOCPU.cpp index 5b171c0d2..750bc5fbd 100644 --- a/iokit/Kernel/IOCPU.cpp +++ b/iokit/Kernel/IOCPU.cpp @@ -389,7 +389,7 @@ IOReturn IOCPUInterruptController::registerInterrupt(IOService *nub, if (enabledCPUs != numCPUs) { assert_wait(this, THREAD_UNINT); - thread_block(0); + thread_block(THREAD_CONTINUE_NULL); } return kIOReturnSuccess; diff --git a/iokit/Kernel/IOCatalogue.cpp b/iokit/Kernel/IOCatalogue.cpp index f59e56bab..14dabbd65 100644 --- a/iokit/Kernel/IOCatalogue.cpp +++ b/iokit/Kernel/IOCatalogue.cpp @@ -35,6 +35,7 @@ extern "C" { #include #include #include +#include }; #include @@ -283,6 +284,10 @@ OSOrderedSet * IOCatalogue::findDrivers( OSDictionary * matching, IOTakeLock( lock ); kernelTables->reset(); while ( (dict = (OSDictionary *) kernelTables->getNextObject()) ) { + + /* This comparison must be done with only the keys in the + * "matching" dict to enable general searches. + */ if ( dict->isEqualTo(matching, matching) ) set->setObject(dict); } @@ -340,7 +345,14 @@ bool IOCatalogue::addDrivers(OSArray * drivers, // Be sure not to double up on personalities. driver = (OSDictionary *)array->getObject(count); - if ( dict->isEqualTo(driver, driver) ) { + + /* Unlike in other functions, this comparison must be exact! + * The catalogue must be able to contain personalities that + * are proper supersets of others. + * Do not compare just the properties present in one driver + * pesonality or the other. + */ + if ( dict->isEqualTo(driver) ) { array->removeObject(count); break; } @@ -405,6 +417,10 @@ bool IOCatalogue::removeDrivers( OSDictionary * matching, array->flushCollection(); tables->reset(); while ( (dict = (OSDictionary *)tables->getNextObject()) ) { + + /* This comparison must be done with only the keys in the + * "matching" dict to enable general searches. + */ if ( dict->isEqualTo(matching, matching) ) { AddNewImports( set, dict ); continue; @@ -444,7 +460,7 @@ bool IOCatalogue::isModuleLoaded( const char * moduleName ) const return false; // Is the module already loaded? - k_info = kmod_lookupbyname((char *)moduleName); + k_info = kmod_lookupbyname_locked((char *)moduleName); if ( !k_info ) { kern_return_t ret; @@ -493,6 +509,10 @@ bool IOCatalogue::isModuleLoaded( const char * moduleName ) const return false; } + if (k_info) { + kfree(k_info, sizeof(kmod_info_t)); + } + /* Lock wasn't taken if we get here. */ return true; } @@ -537,22 +557,29 @@ void IOCatalogue::moduleHasLoaded( const char * moduleName ) IOReturn IOCatalogue::unloadModule( OSString * moduleName ) const { - kmod_info_t * k_info; + kmod_info_t * k_info = 0; kern_return_t ret; const char * name; ret = kIOReturnBadArgument; if ( moduleName ) { name = moduleName->getCStringNoCopy(); - k_info = kmod_lookupbyname((char *)name); + k_info = kmod_lookupbyname_locked((char *)name); if ( k_info && (k_info->reference_count < 1) ) { if ( k_info->stop && - !((ret = k_info->stop(k_info, 0)) == kIOReturnSuccess) ) + !((ret = k_info->stop(k_info, 0)) == kIOReturnSuccess) ) { + + kfree(k_info, sizeof(kmod_info_t)); return ret; + } ret = kmod_destroy(host_priv_self(), k_info->id); } } + + if (k_info) { + kfree(k_info, sizeof(kmod_info_t)); + } return ret; } @@ -560,7 +587,6 @@ IOReturn IOCatalogue::unloadModule( OSString * moduleName ) const static IOReturn _terminateDrivers( OSArray * array, OSDictionary * matching ) { OSCollectionIterator * tables; - OSCollectionIterator * props; OSDictionary * dict; OSIterator * iter; OSArray * arrayCopy; @@ -579,12 +605,6 @@ static IOReturn _terminateDrivers( OSArray * array, OSDictionary * matching ) UniqueProperties( matching ); - props = OSCollectionIterator::withCollection(matching); - if ( !props ) { - iter->release(); - return kIOReturnNoMemory; - } - // terminate instances. do { iter->reset(); @@ -593,6 +613,10 @@ static IOReturn _terminateDrivers( OSArray * array, OSDictionary * matching ) if ( !dict ) continue; + /* Terminate only for personalities that match the matching dictionary. + * This comparison must be done with only the keys in the + * "matching" dict to enable general matching. + */ if ( !dict->isEqualTo(matching, matching) ) continue; @@ -621,6 +645,12 @@ static IOReturn _terminateDrivers( OSArray * array, OSDictionary * matching ) array->flushCollection(); tables->reset(); while ( (dict = (OSDictionary *)tables->getNextObject()) ) { + + /* Remove from the catalogue's array any personalities + * that match the matching dictionary. + * This comparison must be done with only the keys in the + * "matching" dict to enable general matching. + */ if ( dict->isEqualTo(matching, matching) ) continue; @@ -657,7 +687,7 @@ IOReturn IOCatalogue::terminateDriversForModule( return kIOReturnNoMemory; dict->setObject(kModuleKey, moduleName); - + IOTakeLock( lock ); ret = _terminateDrivers(array, dict); @@ -689,7 +719,7 @@ IOReturn IOCatalogue::terminateDriversForModule( ret = terminateDriversForModule(name, unload); name->release(); - + return ret; } @@ -710,6 +740,10 @@ bool IOCatalogue::startMatching( OSDictionary * matching ) kernelTables->reset(); while ( (dict = (OSDictionary *)kernelTables->getNextObject()) ) { + + /* This comparison must be done with only the keys in the + * "matching" dict to enable general matching. + */ if ( dict->isEqualTo(matching, matching) ) AddNewImports(set, dict); } @@ -851,6 +885,7 @@ kern_return_t IOCatalogue::removeKernelLinker(void) { segment = getsegbynamefromheader( &_mh_execute_header, "__KLD"); if (!segment) { + IOLog("error removing kernel linker: can't find __KLD segment\n"); result = KERN_FAILURE; goto finish; } @@ -859,6 +894,7 @@ kern_return_t IOCatalogue::removeKernelLinker(void) { segment = getsegbynamefromheader( &_mh_execute_header, "__LINKEDIT"); if (!segment) { + IOLog("error removing kernel linker: can't find __LINKEDIT segment\n"); result = KERN_FAILURE; goto finish; } diff --git a/iokit/Kernel/IOConditionLock.cpp b/iokit/Kernel/IOConditionLock.cpp index d4940b77e..f8fec3768 100644 --- a/iokit/Kernel/IOConditionLock.cpp +++ b/iokit/Kernel/IOConditionLock.cpp @@ -101,7 +101,7 @@ void IOConditionLock::unlock() want_lock = false; if (waiting) { waiting = false; - thread_wakeup(this); // Wakeup everybody + IOLockWakeup(sleep_interlock, this, /* one-thread */ false); // Wakeup everybody } IOUnlock(sleep_interlock); @@ -145,12 +145,7 @@ int IOConditionLock::lock() while (want_lock && thread_res == THREAD_AWAKENED) { waiting = true; - - assert_wait((void *) this, interruptible); /* assert event */ - IOUnlock(sleep_interlock); /* release the lock */ - thread_res = thread_block((void (*)(void)) 0); /* block ourselves */ - - IOTakeLock(sleep_interlock); + thread_res = IOLockSleep(sleep_interlock, (void *) this, interruptible); } if (thread_res == THREAD_AWAKENED) want_lock = true; @@ -191,8 +186,8 @@ int IOConditionLock::lockWhen(int inCondition) * of changes in _condition. */ assert_wait((void *) &condition, interruptible); /* assert event */ - IOUnlock(cond_interlock); /* release the lock */ - thread_res = thread_block((void (*)(void)) 0); /* block ourselves */ + IOUnlock(cond_interlock); /* release the lock */ + thread_res = thread_block(THREAD_CONTINUE_NULL); /* block ourselves */ } while (thread_res == THREAD_AWAKENED); return thread_res; diff --git a/iokit/Kernel/IODataQueue.cpp b/iokit/Kernel/IODataQueue.cpp index b98060e75..f2461d512 100644 --- a/iokit/Kernel/IODataQueue.cpp +++ b/iokit/Kernel/IODataQueue.cpp @@ -105,24 +105,39 @@ Boolean IODataQueue::enqueue(void * data, UInt32 dataSize) const UInt32 tail = dataQueue->tail; const UInt32 entrySize = dataSize + DATA_QUEUE_ENTRY_HEADER_SIZE; IODataQueueEntry * entry; - + if ( tail >= head ) { - if ( (tail + entrySize) < dataQueue->queueSize ) + // Is there enough room at the end for the entry? + if ( (tail + entrySize) <= dataQueue->queueSize ) { entry = (IODataQueueEntry *)((UInt8 *)dataQueue->queue + tail); entry->size = dataSize; memcpy(&entry->data, data, dataSize); + + // The tail can be out of bound when the size of the new entry + // exactly matches the available space at the end of the queue. + // The tail can range from 0 to dataQueue->queueSize inclusive. + dataQueue->tail += entrySize; } - else if ( head > entrySize ) + else if ( head > entrySize ) // Is there enough room at the beginning? { // Wrap around to the beginning, but do not allow the tail to catch // up to the head. dataQueue->queue->size = dataSize; - ((IODataQueueEntry *)((UInt8 *)dataQueue->queue + tail))->size = dataSize; + + // We need to make sure that there is enough room to set the size before + // doing this. The user client checks for this and will look for the size + // at the beginning if there isn't room for it at the end. + + if ( ( dataQueue->queueSize - tail ) >= DATA_QUEUE_ENTRY_HEADER_SIZE ) + { + ((IODataQueueEntry *)((UInt8 *)dataQueue->queue + tail))->size = dataSize; + } + memcpy(&dataQueue->queue->data, data, dataSize); dataQueue->tail = entrySize; } diff --git a/iokit/Kernel/IODeviceTreeSupport.cpp b/iokit/Kernel/IODeviceTreeSupport.cpp index 3c75dceb2..6d9eb7f61 100644 --- a/iokit/Kernel/IODeviceTreeSupport.cpp +++ b/iokit/Kernel/IODeviceTreeSupport.cpp @@ -39,11 +39,11 @@ #include extern "C" { - #include - void DTInit( void * data ); + #include + void DTInit( void * data ); - int IODTGetLoaderInfo( char *key, void **infoAddr, int *infosize ); - void IODTFreeLoaderInfo( char *key, void *infoAddr, int infoSize ); + int IODTGetLoaderInfo( char *key, void **infoAddr, int *infosize ); + void IODTFreeLoaderInfo( char *key, void *infoAddr, int infoSize ); } #include @@ -153,7 +153,7 @@ IODeviceTreeAlloc( void * dtTop ) do { parent = (IORegistryEntry *)stack->getObject( stack->getCount() - 1); - //parent->release(); + //parent->release(); stack->removeObject( stack->getCount() - 1); while( kSuccess == DTIterateEntries( iter, &dtChild) ) { @@ -161,14 +161,14 @@ IODeviceTreeAlloc( void * dtTop ) child = MakeReferenceTable( dtChild, freeDT ); child->attachToParent( parent, gIODTPlane); - AddPHandle( child ); + AddPHandle( child ); if( kSuccess == DTEnterEntry( iter, dtChild)) { stack->setObject( parent); parent = child; } - // only registry holds retain - child->release(); + // only registry holds retain + child->release(); } } while( stack->getCount() @@ -181,8 +181,8 @@ IODeviceTreeAlloc( void * dtTop ) // make root name first compatible entry (purely cosmetic) if( (prop = (OSData *) parent->getProperty( gIODTCompatibleKey))) { - parent->setName( parent->getName(), gIODTPlane ); - parent->setName( (const char *) prop->getBytesNoCopy() ); + parent->setName( parent->getName(), gIODTPlane ); + parent->setName( (const char *) prop->getBytesNoCopy() ); } // attach tree to meta root @@ -190,7 +190,7 @@ IODeviceTreeAlloc( void * dtTop ) parent->release(); if( freeDT ) { - // free original device tree + // free original device tree DTInit(0); IODTFreeLoaderInfo( "DeviceTree", (void *)dtMap[0], round_page(dtMap[1]) ); @@ -202,36 +202,35 @@ IODeviceTreeAlloc( void * dtTop ) kIORegistryIterateRecursively ); assert( regIter ); if( regIter) { - while( (child = regIter->getNextObject())) { - IODTMapInterrupts( child ); - if( !intMap && child->getProperty( gIODTInterruptParentKey)) - intMap = true; - - // Look for a "driver,AAPL,MacOSX,PowerPC" property. - if( (obj = child->getProperty( "driver,AAPL,MacOSX,PowerPC"))) { - gIOCatalogue->addExtensionsFromArchive((OSData *)obj); - - child->removeProperty( "driver,AAPL,MacOSX,PowerPC"); - } - - // some gross pruning - child->removeProperty( "lanLib,AAPL,MacOS,PowerPC"); - - if( (obj = child->getProperty( "driver,AAPL,MacOS,PowerPC"))) { - - if( (0 == (prop = (OSData *)child->getProperty( gIODTTypeKey ))) - || (strcmp( "display", (char *) prop->getBytesNoCopy())) ) { - child->removeProperty( "driver,AAPL,MacOS,PowerPC"); - } - } - } - regIter->release(); + while( (child = regIter->getNextObject())) { + IODTMapInterrupts( child ); + if( !intMap && child->getProperty( gIODTInterruptParentKey)) + intMap = true; + + // Look for a "driver,AAPL,MacOSX,PowerPC" property. + if( (obj = child->getProperty( "driver,AAPL,MacOSX,PowerPC"))) { + gIOCatalogue->addExtensionsFromArchive((OSData *)obj); + child->removeProperty( "driver,AAPL,MacOSX,PowerPC"); + } + + // some gross pruning + child->removeProperty( "lanLib,AAPL,MacOS,PowerPC"); + + if( (obj = child->getProperty( "driver,AAPL,MacOS,PowerPC"))) { + + if( (0 == (prop = (OSData *)child->getProperty( gIODTTypeKey ))) + || (strcmp( "display", (char *) prop->getBytesNoCopy())) ) { + child->removeProperty( "driver,AAPL,MacOS,PowerPC"); + } + } + } + regIter->release(); } if( intMap) - // set a key in the root to indicate we found NW interrupt mapping - parent->setProperty( gIODTNWInterruptMappingKey, - (OSObject *) gIODTNWInterruptMappingKey ); + // set a key in the root to indicate we found NW interrupt mapping + parent->setProperty( gIODTNWInterruptMappingKey, + (OSObject *) gIODTNWInterruptMappingKey ); IOLog("done\n"); @@ -308,57 +307,58 @@ MakeReferenceTable( DTEntry dtEntry, bool copy ) regEntry = new IOService; if( regEntry && (false == regEntry->init())) { - regEntry->release(); - regEntry = 0; + regEntry->release(); + regEntry = 0; } if( regEntry && - (kSuccess == DTCreatePropertyIterator( dtEntry, &dtIter))) { + (kSuccess == DTCreatePropertyIterator( dtEntry, &dtIter))) { propTable = regEntry->getPropertyTable(); - while( kSuccess == DTIterateProperties( dtIter, &name)) { - - if( kSuccess != DTGetProperty( dtEntry, name, &prop, &propSize )) - continue; - - if( copy) { - nameKey = OSSymbol::withCString(name); - data = OSData::withBytes(prop, propSize); - } else { - nameKey = OSSymbol::withCStringNoCopy(name); - data = OSData::withBytesNoCopy(prop, propSize); - } - assert( nameKey && data ); - - propTable->setObject( nameKey, data); - data->release(); - nameKey->release(); - - if( nameKey == gIODTNameKey ) { - if( copy) - sym = OSSymbol::withCString( (const char *) prop); - else - sym = OSSymbol::withCStringNoCopy( (const char *) prop); - regEntry->setName( sym ); - sym->release(); - } else if( nameKey == gIODTUnitKey ) { - // all OF strings are null terminated... except this one - if( propSize >= (int) sizeof( location)) - propSize = sizeof( location) - 1; - strncpy( location, (const char *) prop, propSize ); - location[ propSize ] = 0; - regEntry->setLocation( location ); - propTable->removeObject( gIODTUnitKey ); - noLocation = false; - - } else if( noLocation && (0 == strcmp( name, "reg"))) { - // default location - override later - sprintf( location, "%lX", *((UInt32 *) prop) ); - regEntry->setLocation( location ); - } - } - DTDisposePropertyIterator( dtIter); + while( kSuccess == DTIterateProperties( dtIter, &name)) { + + if( kSuccess != DTGetProperty( dtEntry, name, &prop, &propSize )) + continue; + + if( copy) { + nameKey = OSSymbol::withCString(name); + data = OSData::withBytes(prop, propSize); + } else { + nameKey = OSSymbol::withCStringNoCopy(name); + data = OSData::withBytesNoCopy(prop, propSize); + } + assert( nameKey && data ); + + propTable->setObject( nameKey, data); + data->release(); + nameKey->release(); + + if( nameKey == gIODTNameKey ) { + if( copy) + sym = OSSymbol::withCString( (const char *) prop); + else + sym = OSSymbol::withCStringNoCopy( (const char *) prop); + regEntry->setName( sym ); + sym->release(); + + } else if( nameKey == gIODTUnitKey ) { + // all OF strings are null terminated... except this one + if( propSize >= (int) sizeof( location)) + propSize = sizeof( location) - 1; + strncpy( location, (const char *) prop, propSize ); + location[ propSize ] = 0; + regEntry->setLocation( location ); + propTable->removeObject( gIODTUnitKey ); + noLocation = false; + + } else if( noLocation && (0 == strcmp( name, "reg"))) { + // default location - override later + sprintf( location, "%lX", *((UInt32 *) prop) ); + regEntry->setLocation( location ); + } + } + DTDisposePropertyIterator( dtIter); } return( regEntry); @@ -369,10 +369,10 @@ static void AddPHandle( IORegistryEntry * regEntry ) OSData * data; if( regEntry->getProperty( gIODTInterruptCellKey) - && (data = OSDynamicCast( OSData, regEntry->getProperty( gIODTPHandleKey )))) { - // a possible interrupt-parent - gIODTPHandles->setObject( data ); - gIODTPHandleMap->setObject( regEntry ); + && (data = OSDynamicCast( OSData, regEntry->getProperty( gIODTPHandleKey )))) { + // a possible interrupt-parent + gIODTPHandles->setObject( data ); + gIODTPHandleMap->setObject( regEntry ); } } @@ -383,10 +383,10 @@ static IORegistryEntry * FindPHandle( UInt32 phandle ) int i; for( i = 0; (data = (OSData *)gIODTPHandles->getObject( i )); i++ ) { - if( phandle == *((UInt32 *)data->getBytesNoCopy())) { - regEntry = (IORegistryEntry *) - gIODTPHandleMap->getObject( i ); - break; + if( phandle == *((UInt32 *)data->getBytesNoCopy())) { + regEntry = (IORegistryEntry *) + gIODTPHandleMap->getObject( i ); + break; } } @@ -399,11 +399,11 @@ static bool GetUInt32( IORegistryEntry * regEntry, const OSSymbol * name, OSData *data; if( (data = OSDynamicCast( OSData, regEntry->getProperty( name ))) - && (4 == data->getLength())) { + && (4 == data->getLength())) { *value = *((UInt32 *) data->getBytesNoCopy()); - return( true ); + return( true ); } else - return( false ); + return( false ); } IORegistryEntry * IODTFindInterruptParent( IORegistryEntry * regEntry ) @@ -412,12 +412,12 @@ IORegistryEntry * IODTFindInterruptParent( IORegistryEntry * regEntry ) UInt32 phandle; if( GetUInt32( regEntry, gIODTInterruptParentKey, &phandle)) - parent = FindPHandle( phandle ); + parent = FindPHandle( phandle ); else if( 0 == regEntry->getProperty( "interrupt-controller")) - parent = regEntry->getParentEntry( gIODTPlane); + parent = regEntry->getParentEntry( gIODTPlane); else - parent = 0; + parent = 0; return( parent ); } @@ -425,9 +425,9 @@ IORegistryEntry * IODTFindInterruptParent( IORegistryEntry * regEntry ) const OSSymbol * IODTInterruptControllerName( IORegistryEntry * regEntry ) { const OSSymbol *sym; - UInt32 phandle; - bool ok; - char buf[48]; + UInt32 phandle; + bool ok; + char buf[48]; ok = GetUInt32( regEntry, gIODTPHandleKey, &phandle); assert( ok ); @@ -436,7 +436,7 @@ const OSSymbol * IODTInterruptControllerName( IORegistryEntry * regEntry ) sprintf( buf, "IOInterruptController%08lX", phandle); sym = OSSymbol::withCString( buf ); } else - sym = 0; + sym = 0; return( sym ); } @@ -465,77 +465,76 @@ UInt32 IODTMapOneInterrupt( IORegistryEntry * regEntry, UInt32 * intSpec, UInt32 i, original_icells; bool cmp, ok = false; - parent = IODTFindInterruptParent( regEntry ); IODTGetICellCounts( parent, &icells, &acells ); addrCmp = 0; if( acells) { - data = OSDynamicCast( OSData, regEntry->getProperty( "reg" )); - if( data && (data->getLength() >= (acells * sizeof( UInt32)))) - addrCmp = (UInt32 *) data->getBytesNoCopy(); + data = OSDynamicCast( OSData, regEntry->getProperty( "reg" )); + if( data && (data->getLength() >= (acells * sizeof( UInt32)))) + addrCmp = (UInt32 *) data->getBytesNoCopy(); } original_icells = icells; regEntry = parent; - do { + do { #if IODTSUPPORTDEBUG - kprintf ("IODTMapOneInterrupt: current regEntry name %s\n", regEntry->getName()); - kprintf ("acells - icells: "); - for (i = 0; i < acells; i++) kprintf ("0x%08X ", addrCmp[i]); - kprintf ("- "); - for (i = 0; i < icells; i++) kprintf ("0x%08X ", intSpec[i]); - kprintf ("\n"); + kprintf ("IODTMapOneInterrupt: current regEntry name %s\n", regEntry->getName()); + kprintf ("acells - icells: "); + for (i = 0; i < acells; i++) kprintf ("0x%08X ", addrCmp[i]); + kprintf ("- "); + for (i = 0; i < icells; i++) kprintf ("0x%08X ", intSpec[i]); + kprintf ("\n"); #endif - if( parent && (data = OSDynamicCast( OSData, - regEntry->getProperty( "interrupt-controller")))) { - // found a controller - don't want to follow cascaded controllers + if( parent && (data = OSDynamicCast( OSData, + regEntry->getProperty( "interrupt-controller")))) { + // found a controller - don't want to follow cascaded controllers parent = 0; *spec = OSData::withBytesNoCopy( (void *) intSpec, icells * sizeof( UInt32)); *controller = IODTInterruptControllerName( regEntry ); - ok = (*spec && *controller); - } else if( parent && (data = OSDynamicCast( OSData, - regEntry->getProperty( "interrupt-map")))) { + ok = (*spec && *controller); + } else if( parent && (data = OSDynamicCast( OSData, + regEntry->getProperty( "interrupt-map")))) { // interrupt-map map = (UInt32 *) data->getBytesNoCopy(); endMap = map + (data->getLength() / sizeof(UInt32)); data = OSDynamicCast( OSData, regEntry->getProperty( "interrupt-map-mask" )); if( data && (data->getLength() >= ((acells + icells) * sizeof( UInt32)))) maskCmp = (UInt32 *) data->getBytesNoCopy(); - else - maskCmp = 0; + else + maskCmp = 0; #if IODTSUPPORTDEBUG - if (maskCmp) { - kprintf (" maskCmp: "); - for (i = 0; i < acells + icells; i++) { - if (i == acells) - kprintf ("- "); - kprintf ("0x%08X ", maskCmp[i]); - } - kprintf ("\n"); - kprintf (" masked: "); - for (i = 0; i < acells + icells; i++) { - if (i == acells) - kprintf ("- "); - kprintf ("0x%08X ", ((i < acells) ? addrCmp[i] : intSpec[i-acells]) & maskCmp[i]); - } - kprintf ("\n"); - } else - kprintf ("no maskCmp\n"); + if (maskCmp) { + kprintf (" maskCmp: "); + for (i = 0; i < acells + icells; i++) { + if (i == acells) + kprintf ("- "); + kprintf ("0x%08X ", maskCmp[i]); + } + kprintf ("\n"); + kprintf (" masked: "); + for (i = 0; i < acells + icells; i++) { + if (i == acells) + kprintf ("- "); + kprintf ("0x%08X ", ((i < acells) ? addrCmp[i] : intSpec[i-acells]) & maskCmp[i]); + } + kprintf ("\n"); + } else + kprintf ("no maskCmp\n"); #endif - do { + do { #if IODTSUPPORTDEBUG - kprintf (" map: "); - for (i = 0; i < acells + icells; i++) { - if (i == acells) - kprintf ("- "); - kprintf ("0x%08X ", map[i]); - } - kprintf ("\n"); + kprintf (" map: "); + for (i = 0; i < acells + icells; i++) { + if (i == acells) + kprintf ("- "); + kprintf ("0x%08X ", map[i]); + } + kprintf ("\n"); #endif - for( i = 0, cmp = true; cmp && (i < (acells + icells)); i++) { + for( i = 0, cmp = true; cmp && (i < (acells + icells)); i++) { cell = (i < acells) ? addrCmp[i] : intSpec[ i - acells ]; if( maskCmp) cell &= maskCmp[i]; @@ -546,24 +545,25 @@ UInt32 IODTMapOneInterrupt( IORegistryEntry * regEntry, UInt32 * intSpec, if( 0 == (parent = FindPHandle( *(map++) ))) unexpected(break); - IODTGetICellCounts( parent, &picells, &pacells ); + IODTGetICellCounts( parent, &picells, &pacells ); if( cmp) { addrCmp = map; intSpec = map + pacells; regEntry = parent; - } else { + } else { map += pacells + picells; - } + } } while( !cmp && (map < endMap) ); if (!cmp) - parent = 0; - } + parent = 0; + } - if( parent) { + if( parent) { IODTGetICellCounts( parent, &icells, &acells ); - regEntry = parent; - } - } while( parent); + regEntry = parent; + } + + } while( parent); return( ok ? original_icells : 0 ); } @@ -583,18 +583,18 @@ bool IODTMapInterrupts( IORegistryEntry * regEntry ) bool ok, nw; nw = (0 == (local = OSDynamicCast( OSData, - regEntry->getProperty( gIODTAAPLInterruptsKey)))); + regEntry->getProperty( gIODTAAPLInterruptsKey)))); if( nw && (0 == (local = OSDynamicCast( OSData, - regEntry->getProperty( "interrupts"))))) - return( true ); // nothing to see here + regEntry->getProperty( "interrupts"))))) + return( true ); // nothing to see here if( nw && (parent = regEntry->getParentEntry( gIODTPlane))) { - // check for bridges on old world - if( (local2 = OSDynamicCast( OSData, - parent->getProperty( gIODTAAPLInterruptsKey)))) { - local = local2; - nw = false; - } + // check for bridges on old world + if( (local2 = OSDynamicCast( OSData, + parent->getProperty( gIODTAAPLInterruptsKey)))) { + local = local2; + nw = false; + } } localBits = (UInt32 *) local->getBytesNoCopy(); @@ -609,7 +609,7 @@ bool IODTMapInterrupts( IORegistryEntry * regEntry ) skip = IODTMapOneInterrupt( regEntry, localBits, &map, &controller ); if( 0 == skip) { IOLog("%s: error mapping interrupt[%d]\n", - regEntry->getName(), mapped->getCount()); + regEntry->getName(), mapped->getCount()); break; } } else { @@ -630,7 +630,7 @@ bool IODTMapInterrupts( IORegistryEntry * regEntry ) ok &= (localBits == localEnd); if( ok ) { - // store results + // store results ok = regEntry->setProperty( gIOInterruptControllersKey, controllers); ok &= regEntry->setProperty( gIOInterruptSpecifiersKey, mapped); } @@ -726,7 +726,7 @@ bool IODTMatchNubWithKeys( IORegistryEntry * regEntry, obj->release(); } #ifdef DEBUG - else IOLog("Couldn't unserialize %s\n", keys ); + else IOLog("Couldn't unserialize %s\n", keys ); #endif return( result ); @@ -746,6 +746,7 @@ OSCollectionIterator * IODTFindMatchingEntries( IORegistryEntry * from, iter = IORegistryIterator::iterateOver( from, gIODTPlane, (options & kIODTRecursive) ? kIORegistryIterateRecursively : 0 ); if( iter) { + do { if( result) @@ -759,17 +760,18 @@ OSCollectionIterator * IODTFindMatchingEntries( IORegistryEntry * from, // Look for existence of a debug property to skip if( next->getProperty("AAPL,ignore")) - continue; + continue; - if( keys) { + if( keys) { cmp = IODTMatchNubWithKeys( next, keys ); if( (minus && (false == cmp)) || ((false == minus) && (false != cmp)) ) result->setObject( next); - } else + } else result->setObject( next); } } while( !iter->isValid()); + iter->release(); } @@ -796,7 +798,7 @@ void IODTSetResolving( IORegistryEntry * regEntry, persist.locationFunc = locationFunc; prop = OSData::withBytes( &persist, sizeof( persist)); if( !prop) - return; + return; regEntry->setProperty( gIODTPersistKey, prop); prop->release(); @@ -817,7 +819,7 @@ void IODTGetCellCounts( IORegistryEntry * regEntry, *sizeCount = 1; if( !GetUInt32( regEntry, gIODTAddressCellKey, addressCount)) *addressCount = 2; - return; + return; } // Given addr & len cells from our child, find it in our ranges property, then @@ -830,20 +832,20 @@ bool IODTResolveAddressCell( IORegistryEntry * regEntry, UInt32 cellsIn[], IOPhysicalAddress * phys, IOPhysicalLength * len ) { - IORegistryEntry *parent; - OSData *prop; + IORegistryEntry *parent; + OSData *prop; // cells in addresses at regEntry - UInt32 sizeCells, addressCells; + UInt32 sizeCells, addressCells; // cells in addresses below regEntry - UInt32 childSizeCells, childAddressCells; - UInt32 childCells; - UInt32 cell[ 5 ], offset = 0, length; - UInt32 *range; - UInt32 *endRanges; - bool ok = true; - SInt32 diff; - - IODTPersistent *persist; + UInt32 childSizeCells, childAddressCells; + UInt32 childCells; + UInt32 cell[ 5 ], offset = 0, length; + UInt32 *range; + UInt32 *endRanges; + bool ok = true; + SInt32 diff; + + IODTPersistent *persist; IODTCompareAddressCellFunc compare; IODTGetCellCounts( regEntry, &childSizeCells, &childAddressCells ); @@ -852,20 +854,20 @@ bool IODTResolveAddressCell( IORegistryEntry * regEntry, bcopy( cellsIn, cell, 4 * childCells ); if( childSizeCells > 1) *len = IOPhysical32( cellsIn[ childAddressCells ], - cellsIn[ childAddressCells + 1 ] ); + cellsIn[ childAddressCells + 1 ] ); else *len = IOPhysical32( 0, cellsIn[ childAddressCells ] ); do { prop = OSDynamicCast( OSData, regEntry->getProperty( gIODTRangeKey )); if( 0 == prop) { - /* end of the road */ + /* end of the road */ *phys = IOPhysical32( 0, cell[ childAddressCells - 1 ] + offset); break; } parent = regEntry->getParentEntry( gIODTPlane ); - IODTGetCellCounts( parent, &sizeCells, &addressCells ); + IODTGetCellCounts( parent, &sizeCells, &addressCells ); if( (length = prop->getLength())) { // search @@ -904,10 +906,10 @@ bool IODTResolveAddressCell( IORegistryEntry * regEntry, } /* else zero length range => pass thru to parent */ - regEntry = parent; + regEntry = parent; childSizeCells = sizeCells; childAddressCells = addressCells; - childCells = childAddressCells + childSizeCells; + childCells = childAddressCells + childSizeCells; } while( ok && regEntry); @@ -932,11 +934,11 @@ OSArray * IODTResolveAddressing( IORegistryEntry * regEntry, parentEntry = regEntry->getParentEntry( gIODTPlane ); addressProperty = (OSData *) regEntry->getProperty( addressPropertyName ); if( (0 == addressProperty) || (0 == parentEntry)) - return( 0); + return( 0); IODTGetCellCounts( parentEntry, &sizeCells, &addressCells ); if( 0 == sizeCells) - return( 0); + return( 0); cells = sizeCells + addressCells; reg = (UInt32 *) addressProperty->getBytesNoCopy(); @@ -944,20 +946,20 @@ OSArray * IODTResolveAddressing( IORegistryEntry * regEntry, array = OSArray::withCapacity( 1 ); if( 0 == array) - return( 0); + return( 0); for( i = 0; i < num; i++) { - if( IODTResolveAddressCell( parentEntry, reg, &phys, &len )) { - range = 0; - if( parent) - range = IODeviceMemory::withSubRange( parent, - phys - parent->getPhysicalAddress(), len ); - if( 0 == range) - range = IODeviceMemory::withRange( phys, len ); - if( range) - array->setObject( range ); - } - reg += cells; + if( IODTResolveAddressCell( parentEntry, reg, &phys, &len )) { + range = 0; + if( parent) + range = IODeviceMemory::withSubRange( parent, + phys - parent->getPhysicalAddress(), len ); + if( 0 == range) + range = IODeviceMemory::withRange( phys, len ); + if( range) + array->setObject( range ); + } + reg += cells; } regEntry->setProperty( gIODeviceMemoryKey, array); @@ -979,7 +981,7 @@ static void IODTGetNVLocation( prop = (OSData *) parent->getProperty( gIODTPersistKey ); if( prop) { persist = (IODTPersistent *) prop->getBytesNoCopy(); - (*persist->locationFunc)( regEntry, busNum, deviceNum, functionNum ); + (*persist->locationFunc)( regEntry, busNum, deviceNum, functionNum ); } else { prop = (OSData *) regEntry->getProperty( "reg" ); *functionNum = 0; @@ -990,7 +992,7 @@ static void IODTGetNVLocation( } else { *busNum = 0; *deviceNum = 0; - } + } } return; } @@ -1017,14 +1019,14 @@ IOReturn IODTMakeNVDescriptor( IORegistryEntry * regEntry, IODTGetNVLocation( parent, regEntry, &busNum, &deviceNum, &functionNum ); - if( level) - bridgeDevices |= ((deviceNum & 0x1f) << ((level - 1) * 5)); - else { + if( level) + bridgeDevices |= ((deviceNum & 0x1f) << ((level - 1) * 5)); + else { hdr->busNum = busNum; hdr->deviceNum = deviceNum; hdr->functionNum = functionNum; - } - regEntry = parent; + } + regEntry = parent; } hdr->bridgeCount = level - 2; hdr->bridgeDevices = bridgeDevices; @@ -1045,36 +1047,36 @@ OSData * IODTFindSlotName( IORegistryEntry * regEntry, UInt32 deviceNumber ) data = (OSData *) regEntry->getProperty("AAPL,slot-name"); if( data) - return( data); + return( data); parent = regEntry->getParentEntry( gIODTPlane ); if( !parent) - return( 0 ); + return( 0 ); data = OSDynamicCast( OSData, parent->getProperty("slot-names")); if( !data) - return( 0 ); + return( 0 ); if( data->getLength() <= 4) - return( 0 ); + return( 0 ); bits = (UInt32 *) data->getBytesNoCopy(); mask = *bits; if( (0 == (mask & (1 << deviceNumber)))) - return( 0 ); + return( 0 ); names = (char *)(bits + 1); lastName = names + (data->getLength() - 4); for( i = 0; (i <= deviceNumber) && (names < lastName); i++ ) { - if( mask & (1 << i)) { + if( mask & (1 << i)) { if( i == deviceNumber) { - data = OSData::withBytesNoCopy( names, 1 + strlen( names)); - if( data) { - regEntry->setProperty("AAPL,slot-name", data); - ret = data; - data->release(); - } + data = OSData::withBytesNoCopy( names, 1 + strlen( names)); + if( data) { + regEntry->setProperty("AAPL,slot-name", data); + ret = data; + data->release(); + } } else - names += 1 + strlen( names); + names += 1 + strlen( names); } } diff --git a/iokit/Kernel/IOEventSource.cpp b/iokit/Kernel/IOEventSource.cpp index d90fb2f62..44bdcf52e 100644 --- a/iokit/Kernel/IOEventSource.cpp +++ b/iokit/Kernel/IOEventSource.cpp @@ -43,6 +43,16 @@ OSMetaClassDefineReservedUnused(IOEventSource, 5); OSMetaClassDefineReservedUnused(IOEventSource, 6); OSMetaClassDefineReservedUnused(IOEventSource, 7); +/* inline function implementations */ +void IOEventSource::signalWorkAvailable() { workLoop->signalWorkAvailable(); } +void IOEventSource::openGate() { workLoop->openGate(); } +void IOEventSource::closeGate() { workLoop->closeGate(); } +bool IOEventSource::tryCloseGate() { return workLoop->tryCloseGate(); } +int IOEventSource::sleepGate(void *event, UInt32 type) + { return workLoop->sleepGate(event, type); } +void IOEventSource::wakeupGate(void *event, bool oneThread) + { workLoop->wakeupGate(event, oneThread); } + bool IOEventSource::init(OSObject *inOwner, Action inAction = 0) { diff --git a/iokit/Kernel/IOLib.c b/iokit/Kernel/IOLib.c index 2721732a0..4eb08077e 100644 --- a/iokit/Kernel/IOLib.c +++ b/iokit/Kernel/IOLib.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1998-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -20,8 +20,6 @@ * @APPLE_LICENSE_HEADER_END@ */ /* - * Copyright (c) 1998 Apple Computer, Inc. All rights reserved. - * * HISTORY * * 17-Apr-91 Portions from libIO.m, Doug Mitchell at NeXT. @@ -42,6 +40,19 @@ mach_timespec_t IOZeroTvalspec = { 0, 0 }; + +/* + * Global variables for use by iLogger + * These symbols are for use only by Apple diagnostic code. + * Binary compatibility is not guaranteed for kexts that reference these symbols. + */ + +void *_giDebugLogInternal = NULL; +void *_giDebugLogDataInternal = NULL; +void *_giDebugReserved1 = NULL; +void *_giDebugReserved2 = NULL; + + /* * Static variables for this module. */ @@ -186,16 +197,23 @@ void * IOMallocAligned(vm_size_t size, vm_size_t alignment) if (adjustedSize >= page_size) { kr = kernel_memory_allocate(kernel_map, &address, - size, alignMask, KMA_KOBJECT); - if (KERN_SUCCESS != kr) { - IOLog("Failed %08x, %08x\n", size, alignment); + size, alignMask, 0); + if (KERN_SUCCESS != kr) address = 0; - } } else { adjustedSize += alignMask; - allocationAddress = (vm_address_t) kalloc(adjustedSize); + + if (adjustedSize >= page_size) { + + kr = kernel_memory_allocate(kernel_map, &allocationAddress, + adjustedSize, 0, 0); + if (KERN_SUCCESS != kr) + allocationAddress = 0; + + } else + allocationAddress = (vm_address_t) kalloc(adjustedSize); if (allocationAddress) { address = (allocationAddress + alignMask @@ -241,7 +259,10 @@ void IOFreeAligned(void * address, vm_size_t size) allocationAddress = *((vm_address_t *)( (vm_address_t) address - sizeof(vm_address_t) )); - kfree((vm_offset_t) allocationAddress, adjustedSize); + if (adjustedSize >= page_size) + kmem_free( kernel_map, (vm_address_t) allocationAddress, adjustedSize); + else + kfree((vm_offset_t) allocationAddress, adjustedSize); } #if IOALLOCDEBUG @@ -271,15 +292,15 @@ void * IOMallocContiguous(vm_size_t size, vm_size_t alignment, if (adjustedSize >= page_size) { kr = kmem_alloc_contig(kernel_map, &address, size, - alignMask, KMA_KOBJECT); + alignMask, 0); if (KERN_SUCCESS != kr) address = 0; } else { adjustedSize += alignMask; - allocationAddress = (vm_address_t) - kalloc(adjustedSize); + allocationAddress = (vm_address_t) kalloc(adjustedSize); + if (allocationAddress) { address = (allocationAddress + alignMask @@ -545,12 +566,13 @@ SInt32 OSKernelStackRemaining( void ) void IOSleep(unsigned milliseconds) { - int wait_result; + wait_result_t wait_result; + + wait_result = assert_wait_timeout(milliseconds, THREAD_UNINT); + assert(wait_result == THREAD_WAITING); - assert_wait_timeout(milliseconds, THREAD_INTERRUPTIBLE); - wait_result = thread_block((void (*)(void))0); - if (wait_result != THREAD_TIMED_OUT) - thread_cancel_timer(); + wait_result = thread_block(THREAD_CONTINUE_NULL); + assert(wait_result == THREAD_TIMED_OUT); } /* diff --git a/iokit/Kernel/IOLocks.cpp b/iokit/Kernel/IOLocks.cpp index 2379b069e..43884bfb3 100644 --- a/iokit/Kernel/IOLocks.cpp +++ b/iokit/Kernel/IOLocks.cpp @@ -149,21 +149,16 @@ int IORecursiveLockSleep(IORecursiveLock *_lock, void *event, UInt32 interType) assert(lock->thread == IOThreadSelf()); assert(lock->count == 1 || interType == THREAD_UNINT); - assert_wait((event_t) event, (int) interType); lock->count = 0; lock->thread = 0; - mutex_unlock(lock->mutex); - - res = thread_block(0); + res = thread_sleep_mutex((event_t) event, lock->mutex, (int) interType); // Must re-establish the recursive lock no matter why we woke up // otherwise we would potentially leave the return path corrupted. - mutex_lock(lock->mutex); assert(lock->thread == 0); assert(lock->count == 0); lock->thread = IOThreadSelf(); lock->count = count; - return res; } diff --git a/iokit/Kernel/IOMemoryDescriptor.cpp b/iokit/Kernel/IOMemoryDescriptor.cpp index 007b22d2f..20b05f3e1 100644 --- a/iokit/Kernel/IOMemoryDescriptor.cpp +++ b/iokit/Kernel/IOMemoryDescriptor.cpp @@ -34,6 +34,10 @@ #include #include +#include +#include +#include +#include #include __BEGIN_DECLS @@ -41,7 +45,10 @@ __BEGIN_DECLS #include void bcopy_phys(char *from, char *to, int size); void pmap_enter(pmap_t pmap, vm_offset_t va, vm_offset_t pa, - vm_prot_t prot, boolean_t wired); + vm_prot_t prot, unsigned int flags, boolean_t wired); +#ifndef i386 +struct phys_entry *pmap_find_physentry(vm_offset_t pa); +#endif void ipc_port_release_send(ipc_port_t port); vm_offset_t vm_map_get_phys_page(vm_map_t map, vm_offset_t offset); @@ -51,6 +58,9 @@ device_pager_setup( int device_handle, vm_size_t size, int flags); +void +device_pager_deallocate( + memory_object_t); kern_return_t device_pager_populate_object( memory_object_t pager, @@ -58,12 +68,23 @@ device_pager_populate_object( vm_offset_t phys_addr, vm_size_t size); +/* + * Page fault handling based on vm_map (or entries therein) + */ +extern kern_return_t vm_fault( + vm_map_t map, + vm_offset_t vaddr, + vm_prot_t fault_type, + boolean_t change_wiring, + int interruptible, + pmap_t caller_pmap, + vm_offset_t caller_pmap_addr); + __END_DECLS /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -OSDefineMetaClass( IOMemoryDescriptor, OSObject ) -OSDefineAbstractStructors( IOMemoryDescriptor, OSObject ) +OSDefineMetaClassAndAbstractStructors( IOMemoryDescriptor, OSObject ) #define super IOMemoryDescriptor @@ -82,6 +103,16 @@ kern_return_t IOIteratePageableMaps(vm_size_t size, /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +static IORecursiveLock * gIOMemoryLock; + +#define LOCK IORecursiveLockLock( gIOMemoryLock) +#define UNLOCK IORecursiveLockUnlock( gIOMemoryLock) +#define SLEEP IORecursiveLockSleep( gIOMemoryLock, (void *)this, THREAD_UNINT) +#define WAKEUP \ + IORecursiveLockWakeup( gIOMemoryLock, (void *)this, /* one-thread */ false) + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + inline vm_map_t IOGeneralMemoryDescriptor::getMapForTask( task_t task, vm_address_t address ) { if( (task == kernel_task) && (kIOMemoryRequiresWire & _flags)) @@ -124,22 +155,40 @@ kern_return_t device_data_action( vm_object_offset_t offset, vm_size_t size) { - IOMemoryDescriptor * memDesc = (IOMemoryDescriptor *) device_handle; + struct ExpansionData { + void * devicePager; + unsigned int pagerContig:1; + unsigned int unused:31; + IOMemoryDescriptor * memory; + }; + kern_return_t kr; + ExpansionData * ref = (ExpansionData *) device_handle; + IOMemoryDescriptor * memDesc; - assert( OSDynamicCast( IOMemoryDescriptor, memDesc )); + LOCK; + memDesc = ref->memory; + if( memDesc) + kr = memDesc->handleFault( device_pager, 0, 0, + offset, size, kIOMapDefaultCache /*?*/); + else + kr = KERN_ABORTED; + UNLOCK; - return( memDesc->handleFault( device_pager, 0, 0, - offset, size, kIOMapDefaultCache /*?*/)); + return( kr ); } kern_return_t device_close( int device_handle) { - IOMemoryDescriptor * memDesc = (IOMemoryDescriptor *) device_handle; - - assert( OSDynamicCast( IOMemoryDescriptor, memDesc )); + struct ExpansionData { + void * devicePager; + unsigned int pagerContig:1; + unsigned int unused:31; + IOMemoryDescriptor * memory; + }; + ExpansionData * ref = (ExpansionData *) device_handle; - memDesc->release(); + IODelete( ref, ExpansionData, 1 ); return( kIOReturnSuccess ); } @@ -412,12 +461,23 @@ IOGeneralMemoryDescriptor::initWithPhysicalRanges( IOPhysicalRange * ranges, */ void IOGeneralMemoryDescriptor::free() { + LOCK; + if( reserved) + reserved->memory = 0; + UNLOCK; + while (_wireCount) complete(); if (_kernPtrAligned) unmapFromKernel(); if (_ranges.v && _rangesIsAllocated) IODelete(_ranges.v, IOVirtualRange, _rangesCount); + + if( reserved && reserved->devicePager) + device_pager_deallocate( reserved->devicePager ); + + // memEntry holds a ref on the device pager which owns reserved (ExpansionData) + // so no reserved access after this point if( _memEntry) ipc_port_release_send( (ipc_port_t) _memEntry ); super::free(); @@ -499,6 +559,7 @@ void IOGeneralMemoryDescriptor::free() /* DEPRECATED */ _kernPtrAligned + off, /* DEPRECATED */ phys_addr, /* DEPRECATED */ VM_PROT_READ|VM_PROT_WRITE, +/* DEPRECATED */ VM_WIMG_USE_DEFAULT, /* DEPRECATED */ TRUE); /* DEPRECATED */ } /* DEPRECATED */ _kernPtrAtIndex = rangeIndex; @@ -538,11 +599,12 @@ IOOptionBits IOMemoryDescriptor::getTag( void ) IOPhysicalAddress IOMemoryDescriptor::getSourceSegment( IOByteCount offset, IOByteCount * length ) { - IOPhysicalAddress physAddr; + IOPhysicalAddress physAddr = 0; - prepare(); - physAddr = getPhysicalSegment( offset, length ); - complete(); + if( prepare() == kIOReturnSuccess) { + physAddr = getPhysicalSegment( offset, length ); + complete(); + } return( physAddr ); } @@ -711,6 +773,11 @@ writeBytesErr: return bytesCopied; } +extern "C" { +// osfmk/device/iokit_rpc.c +extern unsigned int IOTranslateCacheBits(struct phys_entry *pp); +}; + /* DEPRECATED */ void IOGeneralMemoryDescriptor::setPosition(IOByteCount position) /* DEPRECATED */ { /* DEPRECATED */ assert(position <= _length); @@ -1104,14 +1171,14 @@ IOReturn IOGeneralMemoryDescriptor::doMap( - trunc_page(_ranges.v[index].address); if( _task) { -#if NOTYET - vm_object_offset_t actualSize = size; - kr = mach_make_memory_entry_64( get_task_map(_task), +#ifndef i386 + vm_size_t actualSize = size; + kr = mach_make_memory_entry( get_task_map(_task), &actualSize, _ranges.v[0].address, VM_PROT_READ | VM_PROT_WRITE, &sharedMem, NULL ); - if( (KERN_SUCCESS == kr) && (actualSize != size)) { + if( (KERN_SUCCESS == kr) && (actualSize != round_page(size))) { #if IOASSERT IOLog("mach_make_memory_entry_64 (%08lx) size (%08lx:%08lx)\n", _ranges.v[0].address, (UInt32)actualSize, size); @@ -1121,12 +1188,18 @@ IOReturn IOGeneralMemoryDescriptor::doMap( } if( KERN_SUCCESS != kr) -#endif /* NOTYET */ +#endif /* i386 */ sharedMem = MACH_PORT_NULL; } else do { memory_object_t pager; + unsigned int flags=0; + struct phys_entry *pp; + IOPhysicalAddress pa; + IOPhysicalLength segLen; + + pa = getPhysicalSegment( sourceOffset, &segLen ); if( !reserved) { reserved = IONew( ExpansionData, 1 ); @@ -1134,32 +1207,77 @@ IOReturn IOGeneralMemoryDescriptor::doMap( continue; } reserved->pagerContig = (1 == _rangesCount); + reserved->memory = this; + +#ifndef i386 + switch(options & kIOMapCacheMask ) { /*What cache mode do we need*/ + + case kIOMapDefaultCache: + default: + if((pp = pmap_find_physentry(pa))) {/* Find physical address */ + /* Use physical attributes as default */ + flags = IOTranslateCacheBits(pp); - pager = device_pager_setup( (memory_object_t) 0, (int) this, size, - reserved->pagerContig ? DEVICE_PAGER_CONTIGUOUS : 0 ); + } + else { /* If no physical, just hard code attributes */ + flags = DEVICE_PAGER_CACHE_INHIB | + DEVICE_PAGER_COHERENT | DEVICE_PAGER_GUARDED; + } + break; + + case kIOMapInhibitCache: + flags = DEVICE_PAGER_CACHE_INHIB | + DEVICE_PAGER_COHERENT | DEVICE_PAGER_GUARDED; + break; + + case kIOMapWriteThruCache: + flags = DEVICE_PAGER_WRITE_THROUGH | + DEVICE_PAGER_COHERENT | DEVICE_PAGER_GUARDED; + break; + + case kIOMapCopybackCache: + flags = DEVICE_PAGER_COHERENT; + break; + } + + flags |= reserved->pagerContig ? DEVICE_PAGER_CONTIGUOUS : 0; +#else + flags = reserved->pagerContig ? DEVICE_PAGER_CONTIGUOUS : 0; +#endif + + pager = device_pager_setup( (memory_object_t) 0, (int) reserved, + size, flags); assert( pager ); if( pager) { - retain(); // pager has a ref kr = mach_memory_object_memory_entry_64( (host_t) 1, false /*internal*/, size, VM_PROT_READ | VM_PROT_WRITE, pager, &sharedMem ); assert( KERN_SUCCESS == kr ); if( KERN_SUCCESS != kr) { -// chris? -// ipc_port_release_send( (ipc_port_t) pager ); + device_pager_deallocate( pager ); pager = MACH_PORT_NULL; sharedMem = MACH_PORT_NULL; } } - reserved->devicePager = pager; + if( pager && sharedMem) + reserved->devicePager = pager; + else { + IODelete( reserved, ExpansionData, 1 ); + reserved = 0; + } } while( false ); _memEntry = (void *) sharedMem; } - kr = super::doMap( addressMap, atAddress, +#ifndef i386 + if( 0 == sharedMem) + kr = kIOReturnVMError; + else +#endif + kr = super::doMap( addressMap, atAddress, options, sourceOffset, length ); return( kr ); @@ -1190,15 +1308,11 @@ extern kern_return_t IOUnmapPages(vm_map_t map, vm_offset_t va, vm_size_t length /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -static IORecursiveLock * gIOMemoryLock; +OSDefineMetaClassAndAbstractStructors( IOMemoryMap, OSObject ) -#define LOCK IORecursiveLockLock( gIOMemoryLock) -#define UNLOCK IORecursiveLockUnlock( gIOMemoryLock) - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -OSDefineMetaClass( IOMemoryMap, OSObject ) -OSDefineAbstractStructors( IOMemoryMap, OSObject ) +/* inline function implementation */ +IOPhysicalAddress IOMemoryMap::getPhysicalAddress() + { return( getPhysicalSegment( 0, 0 )); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ @@ -1215,9 +1329,12 @@ class _IOMemoryMap : public IOMemoryMap vm_map_t addressMap; IOOptionBits options; -public: +protected: + virtual void taggedRelease(const void *tag = 0) const; virtual void free(); +public: + // IOMemoryMap methods virtual IOVirtualAddress getVirtualAddress(); virtual IOByteCount getLength(); @@ -1232,7 +1349,7 @@ public: IOByteCount * length); // for IOMemoryDescriptor use - _IOMemoryMap * isCompatible( + _IOMemoryMap * copyCompatible( IOMemoryDescriptor * owner, task_t intoTask, IOVirtualAddress toAddress, @@ -1240,13 +1357,13 @@ public: IOByteCount offset, IOByteCount length ); - bool init( + bool initCompatible( IOMemoryDescriptor * memory, IOMemoryMap * superMap, IOByteCount offset, IOByteCount length ); - bool init( + bool initWithDescriptor( IOMemoryDescriptor * memory, task_t intoTask, IOVirtualAddress toAddress, @@ -1267,7 +1384,7 @@ OSDefineMetaClassAndStructors(_IOMemoryMap, IOMemoryMap) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -bool _IOMemoryMap::init( +bool _IOMemoryMap::initCompatible( IOMemoryDescriptor * _memory, IOMemoryMap * _superMap, IOByteCount _offset, @@ -1297,7 +1414,7 @@ bool _IOMemoryMap::init( return( true ); } -bool _IOMemoryMap::init( +bool _IOMemoryMap::initWithDescriptor( IOMemoryDescriptor * _memory, task_t intoTask, IOVirtualAddress toAddress, @@ -1316,7 +1433,7 @@ bool _IOMemoryMap::init( addressMap = get_task_map(intoTask); if( !addressMap) return( false); - kernel_vm_map_reference(addressMap); + vm_map_reference(addressMap); _memory->retain(); memory = _memory; @@ -1402,6 +1519,7 @@ static kern_return_t IOMemoryDescriptorMapAlloc(vm_map_t map, void * _ref) return( err ); } + IOReturn IOMemoryDescriptor::doMap( vm_map_t addressMap, IOVirtualAddress * atAddress, @@ -1494,21 +1612,15 @@ IOReturn IOMemoryDescriptor::handleFault( if( !addressMap) { - LOCK; - if( kIOMemoryRedirected & _flags) { #ifdef DEBUG - IOLog("sleep mem redirect %x, %lx\n", address, sourceOffset); + IOLog("sleep mem redirect %p, %lx\n", this, sourceOffset); #endif do { - assert_wait( (event_t) this, THREAD_UNINT ); - UNLOCK; - thread_block((void (*)(void)) 0); - LOCK; + SLEEP; } while( kIOMemoryRedirected & _flags ); } - UNLOCK; return( kIOReturnSuccess ); } @@ -1537,11 +1649,18 @@ IOReturn IOMemoryDescriptor::handleFault( segLen - pageOffset); #endif + + + + +#ifdef i386 + /* i386 doesn't support faulting on device memory yet */ if( addressMap && (kIOReturnSuccess == err)) err = IOMapPages( addressMap, address, physAddr, segLen, options ); assert( KERN_SUCCESS == err ); if( err) break; +#endif if( pager) { if( reserved && reserved->pagerContig) { @@ -1550,7 +1669,7 @@ IOReturn IOMemoryDescriptor::handleFault( allPhys = getPhysicalSegment( 0, &allLen ); assert( allPhys ); - err = device_pager_populate_object( pager, 0, trunc_page(allPhys), round_page(allPhys + allLen) ); + err = device_pager_populate_object( pager, 0, trunc_page(allPhys), round_page(allLen) ); } else { @@ -1565,6 +1684,31 @@ IOReturn IOMemoryDescriptor::handleFault( if( err) break; } +#ifndef i386 + /* *** ALERT *** */ + /* *** Temporary Workaround *** */ + + /* This call to vm_fault causes an early pmap level resolution */ + /* of the mappings created above. Need for this is in absolute */ + /* violation of the basic tenet that the pmap layer is a cache. */ + /* Further, it implies a serious I/O architectural violation on */ + /* the part of some user of the mapping. As of this writing, */ + /* the call to vm_fault is needed because the NVIDIA driver */ + /* makes a call to pmap_extract. The NVIDIA driver needs to be */ + /* fixed as soon as possible. The NVIDIA driver should not */ + /* need to query for this info as it should know from the doMap */ + /* call where the physical memory is mapped. When a query is */ + /* necessary to find a physical mapping, it should be done */ + /* through an iokit call which includes the mapped memory */ + /* handle. This is required for machine architecture independence.*/ + + if(!(kIOMemoryRedirected & _flags)) { + vm_fault(addressMap, address, 3, FALSE, FALSE, NULL, 0); + } + + /* *** Temporary Workaround *** */ + /* *** ALERT *** */ +#endif sourceOffset += segLen - pageOffset; address += segLen; bytes -= segLen; @@ -1626,7 +1770,7 @@ IOReturn IOMemoryDescriptor::redirect( task_t safeTask, bool redirect ) _flags |= kIOMemoryRedirected; else { _flags &= ~kIOMemoryRedirected; - thread_wakeup( (event_t) this); + WAKEUP; } UNLOCK; @@ -1658,7 +1802,7 @@ IOReturn _IOMemoryMap::redirect( task_t safeTask, bool redirect ) if( logical && addressMap && (get_task_map( safeTask) != addressMap) && (0 == (options & kIOMapStatic))) { - + IOUnmapPages( addressMap, logical, length ); if( !redirect) { err = vm_deallocate( addressMap, logical, length ); @@ -1668,7 +1812,7 @@ IOReturn _IOMemoryMap::redirect( task_t safeTask, bool redirect ) } else err = kIOReturnSuccess; #ifdef DEBUG - IOLog("IOMemoryMap::redirect(%d, %x) %x from %p\n", redirect, err, logical, addressMap); + IOLog("IOMemoryMap::redirect(%d, %p) %x:%lx from %p\n", redirect, this, logical, length, addressMap); #endif } UNLOCK; @@ -1712,6 +1856,15 @@ void _IOMemoryMap::taskDied( void ) UNLOCK; } +// Overload the release mechanism. All mappings must be a member +// of a memory descriptors _mappings set. This means that we +// always have 2 references on a mapping. When either of these mappings +// are released we need to free ourselves. +void _IOMemoryMap::taggedRelease(const void *tag = 0) const +{ + super::taggedRelease(tag, 2); +} + void _IOMemoryMap::free() { unmap(); @@ -1757,7 +1910,7 @@ IOMemoryDescriptor * _IOMemoryMap::getMemoryDescriptor() return( memory ); } -_IOMemoryMap * _IOMemoryMap::isCompatible( +_IOMemoryMap * _IOMemoryMap::copyCompatible( IOMemoryDescriptor * owner, task_t task, IOVirtualAddress toAddress, @@ -1769,7 +1922,10 @@ _IOMemoryMap * _IOMemoryMap::isCompatible( if( (!task) || (task != getAddressTask())) return( 0 ); - if( (options ^ _options) & (kIOMapCacheMask | kIOMapReadOnly)) + if( (options ^ _options) & kIOMapReadOnly) + return( 0 ); + if( (kIOMapDefaultCache != (_options & kIOMapCacheMask)) + && ((options ^ _options) & kIOMapCacheMask)) return( 0 ); if( (0 == (_options & kIOMapAnywhere)) && (logical != toAddress)) @@ -1790,7 +1946,7 @@ _IOMemoryMap * _IOMemoryMap::isCompatible( } else { mapping = new _IOMemoryMap; if( mapping - && !mapping->init( owner, this, _offset, _length )) { + && !mapping->initCompatible( owner, this, _offset, _length )) { mapping->release(); mapping = 0; } @@ -1829,9 +1985,6 @@ void IOMemoryDescriptor::free( void ) if( _mappings) _mappings->release(); - if( reserved) - IODelete( reserved, ExpansionData, 1 ); - super::free(); } @@ -1847,7 +2000,7 @@ IOMemoryMap * IOMemoryDescriptor::setMapping( LOCK; if( map - && !map->init( this, intoTask, mapAddress, + && !map->initWithDescriptor( this, intoTask, mapAddress, options | kIOMapStatic, 0, getLength() )) { map->release(); map = 0; @@ -1901,7 +2054,7 @@ IOMemoryMap * IOMemoryDescriptor::makeMapping( while( (mapping = (_IOMemoryMap *) iter->getNextObject())) { - if( (mapping = mapping->isCompatible( + if( (mapping = mapping->copyCompatible( owner, intoTask, toAddress, options | kIOMapReference, offset, length ))) @@ -1920,10 +2073,11 @@ IOMemoryMap * IOMemoryDescriptor::makeMapping( mapping = new _IOMemoryMap; if( mapping - && !mapping->init( owner, intoTask, toAddress, options, + && !mapping->initWithDescriptor( owner, intoTask, toAddress, options, offset, length )) { - +#ifdef DEBUG IOLog("Didn't make map %08lx : %08lx\n", offset, length ); +#endif mapping->release(); mapping = 0; } @@ -1943,19 +2097,16 @@ void IOMemoryDescriptor::addMapping( if( mapping) { if( 0 == _mappings) _mappings = OSSet::withCapacity(1); - if( _mappings && _mappings->setObject( mapping )) - mapping->release(); /* really */ + if( _mappings ) + _mappings->setObject( mapping ); } } void IOMemoryDescriptor::removeMapping( IOMemoryMap * mapping ) { - if( _mappings) { - mapping->retain(); - mapping->retain(); + if( _mappings) _mappings->removeObject( mapping); - } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ @@ -2188,6 +2339,140 @@ IOSubMemoryDescriptor::initWithPhysicalRanges( IOPhysicalRange * ranges, /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +bool IOGeneralMemoryDescriptor::serialize(OSSerialize * s) const +{ + OSSymbol const *keys[2]; + OSObject *values[2]; + OSDictionary *dict; + IOVirtualRange *vcopy; + unsigned int index, nRanges; + bool result; + + if (s == NULL) return false; + if (s->previouslySerialized(this)) return true; + + // Pretend we are an array. + if (!s->addXMLStartTag(this, "array")) return false; + + nRanges = _rangesCount; + vcopy = (IOVirtualRange *) IOMalloc(sizeof(IOVirtualRange) * nRanges); + if (vcopy == 0) return false; + + keys[0] = OSSymbol::withCString("address"); + keys[1] = OSSymbol::withCString("length"); + + result = false; + values[0] = values[1] = 0; + + // From this point on we can go to bail. + + // Copy the volatile data so we don't have to allocate memory + // while the lock is held. + LOCK; + if (nRanges == _rangesCount) { + for (index = 0; index < nRanges; index++) { + vcopy[index] = _ranges.v[index]; + } + } else { + // The descriptor changed out from under us. Give up. + UNLOCK; + result = false; + goto bail; + } + UNLOCK; + + for (index = 0; index < nRanges; index++) + { + values[0] = OSNumber::withNumber(_ranges.v[index].address, sizeof(_ranges.v[index].address) * 8); + if (values[0] == 0) { + result = false; + goto bail; + } + values[1] = OSNumber::withNumber(_ranges.v[index].length, sizeof(_ranges.v[index].length) * 8); + if (values[1] == 0) { + result = false; + goto bail; + } + OSDictionary *dict = OSDictionary::withObjects((const OSObject **)values, (const OSSymbol **)keys, 2); + if (dict == 0) { + result = false; + goto bail; + } + values[0]->release(); + values[1]->release(); + values[0] = values[1] = 0; + + result = dict->serialize(s); + dict->release(); + if (!result) { + goto bail; + } + } + result = s->addXMLEndTag("array"); + + bail: + if (values[0]) + values[0]->release(); + if (values[1]) + values[1]->release(); + if (keys[0]) + keys[0]->release(); + if (keys[1]) + keys[1]->release(); + if (vcopy) + IOFree(vcopy, sizeof(IOVirtualRange) * nRanges); + return result; +} + +bool IOSubMemoryDescriptor::serialize(OSSerialize * s) const +{ + if (!s) { + return (false); + } + if (s->previouslySerialized(this)) return true; + + // Pretend we are a dictionary. + // We must duplicate the functionality of OSDictionary here + // because otherwise object references will not work; + // they are based on the value of the object passed to + // previouslySerialized and addXMLStartTag. + + if (!s->addXMLStartTag(this, "dict")) return false; + + char const *keys[3] = {"offset", "length", "parent"}; + + OSObject *values[3]; + values[0] = OSNumber::withNumber(_start, sizeof(_start) * 8); + if (values[0] == 0) + return false; + values[1] = OSNumber::withNumber(_length, sizeof(_length) * 8); + if (values[1] == 0) { + values[0]->release(); + return false; + } + values[2] = _parent; + + bool result = true; + for (int i=0; i<3; i++) { + if (!s->addString("") || + !s->addString(keys[i]) || + !s->addXMLEndTag("key") || + !values[i]->serialize(s)) { + result = false; + break; + } + } + values[0]->release(); + values[1]->release(); + if (!result) { + return false; + } + + return s->addXMLEndTag("dict"); +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + OSMetaClassDefineReservedUsed(IOMemoryDescriptor, 0); OSMetaClassDefineReservedUnused(IOMemoryDescriptor, 1); OSMetaClassDefineReservedUnused(IOMemoryDescriptor, 2); @@ -2204,3 +2489,7 @@ OSMetaClassDefineReservedUnused(IOMemoryDescriptor, 12); OSMetaClassDefineReservedUnused(IOMemoryDescriptor, 13); OSMetaClassDefineReservedUnused(IOMemoryDescriptor, 14); OSMetaClassDefineReservedUnused(IOMemoryDescriptor, 15); + +/* inline function implementation */ +IOPhysicalAddress IOMemoryDescriptor::getPhysicalAddress() + { return( getPhysicalSegment( 0, 0 )); } diff --git a/iokit/Kernel/IONVRAM.cpp b/iokit/Kernel/IONVRAM.cpp index 017f73c93..738a03cfa 100644 --- a/iokit/Kernel/IONVRAM.cpp +++ b/iokit/Kernel/IONVRAM.cpp @@ -69,10 +69,11 @@ void IODTNVRAM::registerNVRAMController(IONVRAMController *nvram) _nvramController->read(0, _nvramImage, kIODTNVRAMImageSize); - // Find the offsets for the OF, XPRAM, and NameRegistry partitions. + // Find the offsets for the OF, XPRAM, NameRegistry and PanicInfo partitions. _ofPartitionOffset = 0xFFFFFFFF; _xpramPartitionOffset = 0xFFFFFFFF; _nrPartitionOffset = 0xFFFFFFFF; + _piPartitionOffset = 0xFFFFFFFF; freePartitionOffset = 0xFFFFFFFF; freePartitionSize = 0; if (getPlatform()->getBootROMType()) { @@ -93,6 +94,10 @@ void IODTNVRAM::registerNVRAMController(IONVRAMController *nvram) _xpramPartitionSize = kIODTNVRAMXPRAMSize; _nrPartitionOffset = _xpramPartitionOffset + _xpramPartitionSize; _nrPartitionSize = partitionLength - _xpramPartitionSize; + } else if (strncmp((const char *)_nvramImage + currentOffset + 4, + kIODTNVRAMPanicInfoPartitonName, 12) == 0) { + _piPartitionOffset = partitionOffset; + _piPartitionSize = partitionLength; } else if (strncmp((const char *)_nvramImage + currentOffset + 4, kIODTNVRAMFreePartitionName, 12) == 0) { freePartitionOffset = currentOffset; @@ -134,6 +139,60 @@ void IODTNVRAM::registerNVRAMController(IONVRAMController *nvram) if (_nrPartitionOffset != 0xFFFFFFFF) _nrImage = _nvramImage + _nrPartitionOffset; + if (_piPartitionOffset == 0xFFFFFFFF) { + if (freePartitionSize > 0x20) { + // Set the signature to 0xa1. + _nvramImage[freePartitionOffset] = 0xa1; + // Set the checksum to 0. + _nvramImage[freePartitionOffset + 1] = 0; + // Set the name for the Panic Info partition. + strncpy((char *)(_nvramImage + freePartitionOffset + 4), + kIODTNVRAMPanicInfoPartitonName, 12); + + // Calculate the partition offset and size. + _piPartitionOffset = freePartitionOffset + 0x10; + _piPartitionSize = 0x800; + if (_piPartitionSize + 0x20 > freePartitionSize) + _piPartitionSize = freePartitionSize - 0x20; + + _piImage = _nvramImage + _piPartitionOffset; + + // Zero the new partition. + bzero(_piImage, _piPartitionSize); + + // Set the partition size. + *(UInt16 *)(_nvramImage + freePartitionOffset + 2) = + (_piPartitionSize / 0x10) + 1; + + // Set the partition checksum. + _nvramImage[freePartitionOffset + 1] = + calculatePartitionChecksum(_nvramImage + freePartitionOffset); + + // Calculate the free partition offset and size. + freePartitionOffset += _piPartitionSize + 0x10; + freePartitionSize -= _piPartitionSize + 0x10; + + // Set the signature to 0x7f. + _nvramImage[freePartitionOffset] = 0x7f; + // Set the checksum to 0. + _nvramImage[freePartitionOffset + 1] = 0; + // Set the name for the free partition. + strncpy((char *)(_nvramImage + freePartitionOffset + 4), + kIODTNVRAMFreePartitionName, 12); + // Set the partition size. + *(UInt16 *)(_nvramImage + freePartitionOffset + 2) = + freePartitionSize / 0x10; + // Set the partition checksum. + _nvramImage[freePartitionOffset + 1] = + calculatePartitionChecksum(_nvramImage + freePartitionOffset); + + // Set the nvram image as dirty. + _nvramImageDirty = true; + } + } else { + _piImage = _nvramImage + _piPartitionOffset; + } + initOFVariables(); } @@ -141,7 +200,8 @@ void IODTNVRAM::sync(void) { if (!_nvramImageDirty && !_ofImageDirty) return; - syncOFVariables(); + // Don't try to sync OF Variables if the system has already paniced. + if (!_systemPaniced) syncOFVariables(); _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize); _nvramController->sync(); @@ -242,6 +302,9 @@ bool IODTNVRAM::setProperty(const OSSymbol *aKey, OSObject *anObject) if (_ofDict->getObject(aKey) == 0) return false; } + // Don't allow change of 'aapl,panic-info'. + if (aKey->isEqualTo(kIODTNVRAMPanicInfoKey)) return false; + // Make sure the object is of the correct type. propType = getOFVariableType(aKey); switch (propType) { @@ -433,7 +496,40 @@ IOReturn IODTNVRAM::writeNVRAMPartition(const OSSymbol *partitionID, return kIOReturnSuccess; } -// Private methods for Open Firmware variable access. +UInt32 IODTNVRAM::savePanicInfo(UInt8 *buffer, IOByteCount length) +{ + if ((_piImage == 0) || (length <= 0)) return 0; + + if (length > (_piPartitionSize - 4)) + length = _piPartitionSize - 4; + + // Save the Panic Info. + bcopy(buffer, _piImage + 4, length); + + // Save the Panic Info length. + *(UInt32 *)_piImage = length; + + _nvramImageDirty = true; + + _systemPaniced = true; + + return length; +} + +// Private methods + +UInt8 IODTNVRAM::calculatePartitionChecksum(UInt8 *partitionHeader) +{ + UInt8 cnt, isum, csum = 0; + + for (cnt = 0; cnt < 0x10; cnt++) { + isum = csum + partitionHeader[cnt]; + if (isum < csum) isum++; + csum = isum; + } + + return csum; +} struct OWVariablesHeader { UInt16 owMagic; @@ -510,6 +606,20 @@ IOReturn IODTNVRAM::initOFVariables(void) propObject->release(); } } + + // Create the 'aapl,panic-info' property if needed. + if (_piImage != 0) { + propDataLength = *(UInt32 *)_piImage; + if ((propDataLength != 0) && (propDataLength < (_piPartitionSize - 4))) { + propObject = OSData::withBytes(_piImage + 4, propDataLength); + _ofDict->setObject(kIODTNVRAMPanicInfoKey, propObject); + propObject->release(); + + // Clear the length from _piImage and mark dirty. + *(UInt32 *)_piImage = 0; + _nvramImageDirty = true; + } + } } else { owHeader = (OWVariablesHeader *)_ofImage; if (!validateOWChecksum(_ofImage)) { @@ -600,6 +710,9 @@ IOReturn IODTNVRAM::syncOFVariables(void) tmpSymbol = OSDynamicCast(OSSymbol, iter->getNextObject()); if (tmpSymbol == 0) break; + // Don't save 'aapl,panic-info'. + if (tmpSymbol->isEqualTo(kIODTNVRAMPanicInfoKey)) continue; + tmpObject = _ofDict->getObject(tmpSymbol); length = maxLength; diff --git a/iokit/Kernel/IOPMPowerSourceList.cpp b/iokit/Kernel/IOPMPowerSourceList.cpp index 6a6fcb865..dc6c949fe 100644 --- a/iokit/Kernel/IOPMPowerSourceList.cpp +++ b/iokit/Kernel/IOPMPowerSourceList.cpp @@ -19,7 +19,6 @@ * * @APPLE_LICENSE_HEADER_END@ */ -#include #include #include #include diff --git a/iokit/Kernel/IOPMinformeeList.cpp b/iokit/Kernel/IOPMinformeeList.cpp index 888dca936..48a870457 100644 --- a/iokit/Kernel/IOPMinformeeList.cpp +++ b/iokit/Kernel/IOPMinformeeList.cpp @@ -19,7 +19,6 @@ * * @APPLE_LICENSE_HEADER_END@ */ -#include #include #include #include diff --git a/iokit/Kernel/IOPlatformExpert.cpp b/iokit/Kernel/IOPlatformExpert.cpp index 2d4b2d500..e41e3133b 100644 --- a/iokit/Kernel/IOPlatformExpert.cpp +++ b/iokit/Kernel/IOPlatformExpert.cpp @@ -50,7 +50,8 @@ static void getCStringForObject (OSObject * inObj, char * outStr); OSDefineMetaClassAndStructors(IOPlatformExpert, IOService) -OSMetaClassDefineReservedUnused(IOPlatformExpert, 0); +OSMetaClassDefineReservedUsed(IOPlatformExpert, 0); + OSMetaClassDefineReservedUnused(IOPlatformExpert, 1); OSMetaClassDefineReservedUnused(IOPlatformExpert, 2); OSMetaClassDefineReservedUnused(IOPlatformExpert, 3); @@ -211,6 +212,8 @@ int (*PE_halt_restart)(unsigned int type) = 0; int IOPlatformExpert::haltRestart(unsigned int type) { + if (type == kPEHangCPU) while (1); + if (PE_halt_restart) return (*PE_halt_restart)(type); else return -1; } @@ -264,8 +267,9 @@ IOReturn IOPlatformExpert::registerInterruptController(OSSymbol *name, IOInterru gIOInterruptControllers->setObject(name, interruptController); - thread_wakeup(gIOInterruptControllers); - + IOLockWakeup(gIOInterruptControllersLock, + gIOInterruptControllers, /* one-thread */ false); + IOLockUnlock(gIOInterruptControllersLock); return kIOReturnSuccess; @@ -275,20 +279,19 @@ IOInterruptController *IOPlatformExpert::lookUpInterruptController(OSSymbol *nam { OSObject *object; + IOLockLock(gIOInterruptControllersLock); while (1) { - IOLockLock(gIOInterruptControllersLock); object = gIOInterruptControllers->getObject(name); - if (object == 0) assert_wait(gIOInterruptControllers, THREAD_UNINT); - - IOLockUnlock(gIOInterruptControllersLock); + if (object != 0) + break; - if (object != 0) break; - - thread_block(0); + IOLockSleep(gIOInterruptControllersLock, + gIOInterruptControllers, THREAD_UNINT); } + IOLockUnlock(gIOInterruptControllersLock); return OSDynamicCast(IOInterruptController, object); } @@ -697,34 +700,43 @@ int PEHaltRestart(unsigned int type) AbsoluteTime deadline; thread_call_t shutdown_hang; - /* Notify IOKit PM clients of shutdown/restart - Clients subscribe to this message with a call to - IOService::registerInterest() - */ - - /* Spawn a thread that will panic in 30 seconds. - If all goes well the machine will be off by the time - the timer expires. - */ - shutdown_hang = thread_call_allocate( &IOPMPanicOnShutdownHang, (thread_call_param_t) type); - clock_interval_to_deadline( 30, kSecondScale, &deadline ); - thread_call_enter1_delayed( shutdown_hang, 0, deadline ); - - noWaitForResponses = pmRootDomain->tellChangeDown2(type); - /* This notification should have few clients who all do - their work synchronously. - - In this "shutdown notification" context we don't give - drivers the option of working asynchronously and responding - later. PM internals make it very hard to wait for asynchronous - replies. In fact, it's a bad idea to even be calling - tellChangeDown2 from here at all. - */ + if(type == kPEHaltCPU || type == kPERestartCPU) + { + /* Notify IOKit PM clients of shutdown/restart + Clients subscribe to this message with a call to + IOService::registerInterest() + */ + + /* Spawn a thread that will panic in 30 seconds. + If all goes well the machine will be off by the time + the timer expires. + */ + shutdown_hang = thread_call_allocate( &IOPMPanicOnShutdownHang, (thread_call_param_t) type); + clock_interval_to_deadline( 30, kSecondScale, &deadline ); + thread_call_enter1_delayed( shutdown_hang, 0, deadline ); + + noWaitForResponses = pmRootDomain->tellChangeDown2(type); + /* This notification should have few clients who all do + their work synchronously. + + In this "shutdown notification" context we don't give + drivers the option of working asynchronously and responding + later. PM internals make it very hard to wait for asynchronous + replies. In fact, it's a bad idea to even be calling + tellChangeDown2 from here at all. + */ + } if (gIOPlatform) return gIOPlatform->haltRestart(type); else return -1; } +UInt32 PESavePanicInfo(UInt8 *buffer, UInt32 length) +{ + if (gIOPlatform != 0) return gIOPlatform->savePanicInfo(buffer, length); + else return 0; +} + long PEGetGMTTimeOfDay(void) { if( gIOPlatform) @@ -767,6 +779,10 @@ IOReturn IOPlatformExpert::callPlatformFunction(const OSSymbol *functionName, param1, param2, param3, param4); } +IOByteCount IOPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length) +{ + return 0; +} /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ @@ -1019,6 +1035,16 @@ IOReturn IODTPlatformExpert::writeNVRAMPartition(const OSSymbol * partitionID, else return kIOReturnNotReady; } +IOByteCount IODTPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length) +{ + IOByteCount lengthSaved = 0; + + if (dtNVRAM) lengthSaved = dtNVRAM->savePanicInfo(buffer, length); + + if (lengthSaved == 0) lengthSaved = super::savePanicInfo(buffer, length); + + return lengthSaved; +} /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ diff --git a/iokit/Kernel/IORegistryEntry.cpp b/iokit/Kernel/IORegistryEntry.cpp index 4040b3cd0..5d1e530f1 100644 --- a/iokit/Kernel/IORegistryEntry.cpp +++ b/iokit/Kernel/IORegistryEntry.cpp @@ -61,7 +61,7 @@ enum { class IORegistryPlane : public OSObject { - friend IORegistryEntry; + friend class IORegistryEntry; OSDeclareAbstractStructors(IORegistryPlane) @@ -165,8 +165,9 @@ s_lock_write( if (l->can_sleep && l->want_write) { l->waiting = TRUE; thread_sleep_simple_lock((event_t) l, - simple_lock_addr(l->interlock), FALSE); - simple_lock(&l->interlock); + simple_lock_addr(l->interlock), + THREAD_UNINT); + /* interlock relocked */ } } l->want_write = TRUE; @@ -187,8 +188,9 @@ s_lock_write( if (l->can_sleep && (l->read_count != 0 || l->want_upgrade)) { l->waiting = TRUE; thread_sleep_simple_lock((event_t) l, - simple_lock_addr(l->interlock), FALSE); - simple_lock(&l->interlock); + simple_lock_addr(l->interlock), + THREAD_UNINT); + /* interlock relocked */ } } @@ -257,8 +259,9 @@ s_lock_read( (l->want_upgrade || ((0 == l->read_count) && l->want_write ))) { l->waiting = TRUE; thread_sleep_simple_lock((event_t) l, - simple_lock_addr(l->interlock), FALSE); - simple_lock(&l->interlock); + simple_lock_addr(l->interlock), + THREAD_UNINT); + /* interlock relocked */ } } @@ -399,9 +402,11 @@ bool IORegistryEntry::init( OSDictionary * dict = 0 ) if( dict) { dict->retain(); + if( fPropertyTable) + fPropertyTable->release(); fPropertyTable = dict; - } else { + } else if( !fPropertyTable) { fPropertyTable = OSDictionary::withCapacity( kIORegCapacityIncrement ); if( fPropertyTable) fPropertyTable->setCapacityIncrement( kIORegCapacityIncrement ); @@ -411,9 +416,11 @@ bool IORegistryEntry::init( OSDictionary * dict = 0 ) return( false); #ifdef IOREGSPLITTABLES - fRegistryTable = OSDictionary::withCapacity( kIORegCapacityIncrement ); - if( fRegistryTable) - fRegistryTable->setCapacityIncrement( kIORegCapacityIncrement ); + if( !fRegistryTable) { + fRegistryTable = OSDictionary::withCapacity( kIORegCapacityIncrement ); + if( fRegistryTable) + fRegistryTable->setCapacityIncrement( kIORegCapacityIncrement ); + } if( (prop = OSDynamicCast( OSString, getProperty( gIONameKey)))) { OSSymbol * sym = (OSSymbol *)OSSymbol::withString( prop); @@ -513,7 +520,7 @@ void IORegistryEntry::setPropertyTable( OSDictionary * dict ) /* Wrappers to synchronize property table */ -#define wrap1(func,type,constant) \ +#define wrap1(func, type, constant) \ OSObject * \ IORegistryEntry::func ## Property( type * aKey) constant \ { \ @@ -526,14 +533,14 @@ IORegistryEntry::func ## Property( type * aKey) constant \ return( obj ); \ } -#define wrap2(type,constant) \ +#define wrap2(type, constant) \ OSObject * \ IORegistryEntry::copyProperty( type * aKey) constant \ { \ OSObject * obj; \ \ PLOCK; \ - obj = getPropertyTable()->getObject( aKey ); \ + obj = getProperty( aKey ); \ if( obj) \ obj->retain(); \ PUNLOCK; \ @@ -1234,6 +1241,7 @@ IORegistryEntry * IORegistryEntry::fromPath( IORegistryEntry * fromEntry = 0 ) { IORegistryEntry * where = 0; + IORegistryEntry * aliasEntry = 0; IORegistryEntry * next; const char * alias; const char * end; @@ -1263,8 +1271,9 @@ IORegistryEntry * IORegistryEntry::fromPath( if( (alias = dealiasPath( &end, plane))) { if( length) len = *length; - where = IORegistryEntry::fromPath( alias, plane, + aliasEntry = IORegistryEntry::fromPath( alias, plane, opath, &len, fromEntry ); + where = aliasEntry; if( where) path = end; else @@ -1312,6 +1321,8 @@ IORegistryEntry * IORegistryEntry::fromPath( if( where) where->retain(); + if( aliasEntry) + aliasEntry->release(); UNLOCK; @@ -2065,3 +2076,7 @@ OSMetaClassDefineReservedUnused(IORegistryEntry, 28); OSMetaClassDefineReservedUnused(IORegistryEntry, 29); OSMetaClassDefineReservedUnused(IORegistryEntry, 30); OSMetaClassDefineReservedUnused(IORegistryEntry, 31); + +/* inline function implementation */ +OSDictionary * IORegistryEntry::getPropertyTable( void ) const +{ return(fPropertyTable); } diff --git a/iokit/Kernel/IOService.cpp b/iokit/Kernel/IOService.cpp index 4bd1a2afa..919ea16fa 100644 --- a/iokit/Kernel/IOService.cpp +++ b/iokit/Kernel/IOService.cpp @@ -95,6 +95,7 @@ const OSSymbol * gIONameMatchKey; const OSSymbol * gIONameMatchedKey; const OSSymbol * gIOPropertyMatchKey; const OSSymbol * gIOLocationMatchKey; +const OSSymbol * gIOParentMatchKey; const OSSymbol * gIOPathMatchKey; const OSSymbol * gIOMatchCategoryKey; const OSSymbol * gIODefaultMatchCategoryKey; @@ -149,6 +150,10 @@ static OSArray * gIOFinalizeList; #define LOCKWRITE2READNOTIFY() #define UNLOCKNOTIFY() \ IORecursiveLockUnlock( gNotificationLock ) +#define SLEEPNOTIFY(event) \ + IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT ) +#define WAKEUPNOTIFY(event) \ + IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false ) #define randomDelay() \ int del = read_processor_clock(); \ @@ -171,6 +176,9 @@ static queue_head_t gArbitrationLockQueueWaiting; static queue_head_t gArbitrationLockQueueFree; static IOLock * gArbitrationLockQueueLock; +bool IOService::isInactive( void ) const + { return( 0 != (kIOServiceInactiveState & getState())); } + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void IOService::initialize( void ) @@ -185,7 +193,8 @@ void IOService::initialize( void ) gIONameMatchedKey = OSSymbol::withCStringNoCopy( kIONameMatchedKey ); gIOPropertyMatchKey = OSSymbol::withCStringNoCopy( kIOPropertyMatchKey ); gIOPathMatchKey = OSSymbol::withCStringNoCopy( kIOPathMatchKey ); - gIOLocationMatchKey = OSSymbol::withCStringNoCopy( kIOLocationMatchKey ); + gIOLocationMatchKey = OSSymbol::withCStringNoCopy( kIOLocationMatchKey ); + gIOParentMatchKey = OSSymbol::withCStringNoCopy( kIOParentMatchKey ); gIOMatchCategoryKey = OSSymbol::withCStringNoCopy( kIOMatchCategoryKey ); gIODefaultMatchCategoryKey = OSSymbol::withCStringNoCopy( @@ -513,7 +522,7 @@ void IOService::startMatching( IOOptionBits options = 0 ) IOLockUnlock( gIOServiceBusyLock ); if( waitAgain) - thread_block((void (*)(void)) 0); + thread_block(THREAD_CONTINUE_NULL); } while( waitAgain ); } @@ -924,7 +933,9 @@ bool IOService::lockForArbitration( bool isSuccessRequired = true ) link ); // wake the victim - thread_wakeup_one(victim); + IOLockWakeup( gArbitrationLockQueueLock, + victim, + /* one thread */ true ); // allow this thread to proceed (ie. wait) success = true; // (put request on wait queue) @@ -962,15 +973,17 @@ bool IOService::lockForArbitration( bool isSuccessRequired = true ) link ); // declare that this thread will wait for a given event -restart_sleep: assert_wait( element, - element->required ? THREAD_UNINT - : THREAD_INTERRUPTIBLE ); +restart_sleep: wait_result = assert_wait( element, + element->required ? THREAD_UNINT + : THREAD_INTERRUPTIBLE ); // unlock global access IOUnlock( gArbitrationLockQueueLock ); // put thread to sleep, waiting for our event to fire... - wait_result = thread_block((void (*)(void)) 0); + if (wait_result == THREAD_WAITING) + wait_result = thread_block(THREAD_CONTINUE_NULL); + // ...and we've been woken up; we might be in one of two states: // (a) we've been aborted and our queue element is not on @@ -1154,7 +1167,9 @@ void IOService::unlockForArbitration( void ) link ); // wake the waiting thread - thread_wakeup_one(element); + IOLockWakeup( gArbitrationLockQueueLock, + element, + /* one thread */ true ); } } @@ -1219,7 +1234,7 @@ IOReturn IOService::messageClient( UInt32 type, OSObject * client, _IOServiceNotifierInvocation *, link ); if( kIOServiceNotifyWaiter & notify->state) { notify->state &= ~kIOServiceNotifyWaiter; - thread_wakeup( (event_t) notify); + WAKEUPNOTIFY( notify ); } UNLOCKNOTIFY(); @@ -1401,10 +1416,7 @@ void _IOServiceInterestNotifier::wait() } if( doWait) { state |= kIOServiceNotifyWaiter; - assert_wait( this, THREAD_UNINT); - UNLOCKNOTIFY(); - thread_block((void (*)(void)) 0); - LOCKWRITENOTIFY(); + SLEEPNOTIFY(this); } } while( doWait ); @@ -1531,7 +1543,7 @@ bool IOService::terminatePhase1( IOOptionBits options = 0 ) while( victim ) { - didInactive = victim->lockForArbitration( true ); + didInactive = victim->lockForArbitration( true ); if( didInactive) { didInactive = (0 == (victim->__state[0] & kIOServiceInactiveState)); if( didInactive) { @@ -1540,7 +1552,7 @@ bool IOService::terminatePhase1( IOOptionBits options = 0 ) | kIOServiceFirstPublishState | kIOServiceFirstMatchState); victim->_adjustBusy( 1 ); } - victim->unlockForArbitration(); + victim->unlockForArbitration(); } if( victim == this) startPhase2 = didInactive; @@ -1599,10 +1611,7 @@ void IOService::scheduleTerminatePhase2( IOOptionBits options = 0 ) wait = (gIOTerminateThread != 0); if( wait) { // wait to become the terminate thread - assert_wait( (event_t) &gIOTerminateThread, THREAD_UNINT ); - IOLockUnlock( gJobsLock ); - thread_block((void (*)(void)) 0); - IOLockLock( gJobsLock ); + IOLockSleep( gJobsLock, &gIOTerminateThread, THREAD_UNINT); } } while( wait ); @@ -1615,24 +1624,21 @@ void IOService::scheduleTerminatePhase2( IOOptionBits options = 0 ) wait = (0 != (__state[1] & kIOServiceBusyStateMask)); if( wait) { // wait for the victim to go non-busy - assert_wait( (event_t) &gIOTerminateWork, THREAD_UNINT ); if( !haveDeadline) { clock_interval_to_deadline( 15, kSecondScale, &deadline ); haveDeadline = true; } - thread_set_timer_deadline( deadline ); - IOLockUnlock( gJobsLock ); - waitResult = thread_block((void (*)(void)) 0); + waitResult = IOLockSleepDeadline( gJobsLock, &gIOTerminateWork, + deadline, THREAD_UNINT ); if( waitResult == THREAD_TIMED_OUT) { TLOG("%s::terminate(kIOServiceSynchronous) timeout", getName()); } else thread_cancel_timer(); - IOLockLock( gJobsLock ); } } while( wait && (waitResult != THREAD_TIMED_OUT)); gIOTerminateThread = 0; - thread_wakeup( (event_t) &gIOTerminateThread ); + IOLockWakeup( gJobsLock, (event_t) &gIOTerminateThread, /* one-thread */ false); } else { // ! kIOServiceSynchronous @@ -1654,7 +1660,7 @@ void IOService::terminateThread( void * arg ) terminateWorker( (IOOptionBits) arg ); gIOTerminateThread = 0; - thread_wakeup( (event_t) &gIOTerminateThread ); + IOLockWakeup( gJobsLock, (event_t) &gIOTerminateThread, /* one-thread */ false); IOLockUnlock( gJobsLock ); } @@ -1671,7 +1677,7 @@ void IOService::scheduleStop( IOService * provider ) if( !gIOTerminateThread) gIOTerminateThread = IOCreateThread( &terminateThread, (void *) 0 ); else - thread_wakeup( (event_t) &gIOTerminateWork ); + IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false ); } IOLockUnlock( gJobsLock ); @@ -1688,7 +1694,7 @@ void IOService::scheduleFinalize( void ) if( !gIOTerminateThread) gIOTerminateThread = IOCreateThread( &terminateThread, (void *) 0 ); else - thread_wakeup( (event_t) &gIOTerminateWork ); + IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false ); } IOLockUnlock( gJobsLock ); @@ -2234,7 +2240,7 @@ bool IOService::invokeNotifer( _IOServiceNotifier * notify ) _IOServiceNotifierInvocation *, link ); if( kIOServiceNotifyWaiter & notify->state) { notify->state &= ~kIOServiceNotifyWaiter; - thread_wakeup( (event_t) notify); + WAKEUPNOTIFY( notify ); } UNLOCKNOTIFY(); } @@ -2874,7 +2880,7 @@ IOReturn IOService::waitForState( UInt32 mask, UInt32 value, unlockForArbitration(); IOLockUnlock( gIOServiceBusyLock ); if( wait) { - waitResult = thread_block((void (*)(void)) 0); + waitResult = thread_block(THREAD_CONTINUE_NULL); if( timeout && (waitResult != THREAD_TIMED_OUT)) thread_cancel_timer(); } @@ -2956,7 +2962,7 @@ void _IOConfigThread::main( _IOConfigThread * self ) else { if( 0 == --gNumConfigThreads) { // IOLog("MATCH IDLE\n"); - thread_wakeup( (event_t) &gNumConfigThreads); + IOLockWakeup( gJobsLock, (event_t) &gNumConfigThreads, /* one-thread */ false ); } } IOUnlock( gJobsLock ); @@ -2977,11 +2983,10 @@ IOReturn IOService::waitMatchIdle( UInt32 msToWait ) bool computeDeadline = true; AbsoluteTime abstime; + IOLockLock( gJobsLock ); do { - IOLockLock( gJobsLock ); wait = (0 != gNumConfigThreads); if( wait) { - assert_wait( (event_t) &gNumConfigThreads, THREAD_UNINT ); if( msToWait) { if( computeDeadline ) { clock_interval_to_absolutetime_interval( @@ -2990,17 +2995,15 @@ IOReturn IOService::waitMatchIdle( UInt32 msToWait ) abstime, &abstime ); computeDeadline = false; } - thread_set_timer_deadline( abstime ); - } + waitResult = IOLockSleepDeadline( gJobsLock, &gNumConfigThreads, + abstime, THREAD_UNINT ); + } else { + waitResult = IOLockSleep( gJobsLock, &gNumConfigThreads, + THREAD_UNINT ); + } } - IOUnlock( gJobsLock ); - if( wait) { - waitResult = thread_block((void (*)(void)) 0); - if( msToWait && (waitResult != THREAD_TIMED_OUT)) - thread_cancel_timer(); - } - } while( wait && (waitResult != THREAD_TIMED_OUT)); + IOLockUnlock( gJobsLock ); if( waitResult == THREAD_TIMED_OUT) return( kIOReturnTimeout ); @@ -3468,10 +3471,7 @@ void _IOServiceNotifier::wait() } if( doWait) { state |= kIOServiceNotifyWaiter; - assert_wait( this, THREAD_UNINT); - UNLOCKNOTIFY(); - thread_block((void (*)(void)) 0); - LOCKWRITENOTIFY(); + SLEEPNOTIFY(this); } } while( doWait ); @@ -3585,6 +3585,34 @@ bool IOResources::matchPropertyTable( OSDictionary * table ) return( ok ); } +IOReturn IOResources::setProperties( OSObject * properties ) +{ + IOReturn err; + const OSSymbol * key; + OSDictionary * dict; + OSCollectionIterator * iter; + + err = IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator); + if ( kIOReturnSuccess != err) + return( err ); + + dict = OSDynamicCast(OSDictionary, properties); + if( 0 == dict) + return( kIOReturnBadArgument); + + iter = OSCollectionIterator::withCollection( dict); + if( 0 == iter) + return( kIOReturnBadArgument); + + while( (key = OSDynamicCast(OSSymbol, iter->getNextObject()))) { + publishResource( key, dict->getObject(key) ); + } + + iter->release(); + + return( kIOReturnSuccess ); +} + /* * Helpers for matching dictionaries. * Keys existing in matching are checked in properties. @@ -3690,6 +3718,7 @@ bool IOService::passiveMatch( OSDictionary * table, bool changesOK ) SInt32 score; OSNumber * newPri; bool match = true; + bool matchParent = false; UInt32 done; assert( table ); @@ -3697,140 +3726,174 @@ bool IOService::passiveMatch( OSDictionary * table, bool changesOK ) where = this; do { - done = 0; + do { + done = 0; - str = OSDynamicCast( OSString, table->getObject( gIOProviderClassKey)); - if( str) { - done++; - match = (0 != where->metaCast( str )); - if( !match) - break; - } + str = OSDynamicCast( OSString, table->getObject( gIOProviderClassKey)); + if( str) { + done++; + match = (0 != where->metaCast( str )); + if( !match) + break; + } - obj = table->getObject( gIONameMatchKey ); - if( obj) { - done++; - match = compareNames( obj, changesOK ? &matched : 0 ); - if( !match) - break; - if( changesOK && matched) { - // leave a hint as to which name matched - table->setObject( gIONameMatchedKey, matched ); - matched->release(); + obj = table->getObject( gIONameMatchKey ); + if( obj) { + done++; + match = where->compareNames( obj, changesOK ? &matched : 0 ); + if( !match) + break; + if( changesOK && matched) { + // leave a hint as to which name matched + table->setObject( gIONameMatchedKey, matched ); + matched->release(); + } } - } - obj = table->getObject( gIOPropertyMatchKey ); - if( obj) { - - OSDictionary * dict; - OSDictionary * nextDict; - OSIterator * iter; - - done++; - dict = where->dictionaryWithProperties(); - if( dict) { - nextDict = OSDynamicCast( OSDictionary, obj); - if( nextDict) - iter = 0; - else - iter = OSCollectionIterator::withCollection( - OSDynamicCast(OSCollection, obj)); - - while( nextDict - || (iter && (0 != (nextDict = OSDynamicCast(OSDictionary, - iter->getNextObject()))))) { - match = dict->isEqualTo( nextDict, nextDict); - if( match) - break; - nextDict = 0; + + str = OSDynamicCast( OSString, table->getObject( gIOLocationMatchKey )); + if( str) { + + const OSSymbol * sym; + + done++; + match = false; + sym = where->copyLocation(); + if( sym) { + match = sym->isEqualTo( str ); + sym->release(); } - dict->release(); - if( iter) - iter->release(); if( !match) break; } - } - str = OSDynamicCast( OSString, table->getObject( gIOPathMatchKey )); - if( str) { - done++; - entry = IORegistryEntry::fromPath( str->getCStringNoCopy() ); - match = (where == entry); - if( entry) - entry->release(); - if( !match) - break; - } + obj = table->getObject( gIOPropertyMatchKey ); + if( obj) { - num = OSDynamicCast( OSNumber, table->getObject( gIOMatchedServiceCountKey )); - if( num) { + OSDictionary * dict; + OSDictionary * nextDict; + OSIterator * iter; - OSIterator * iter; - IOService * service = 0; - UInt32 serviceCount = 0; + done++; + match = false; + dict = where->dictionaryWithProperties(); + if( dict) { + nextDict = OSDynamicCast( OSDictionary, obj); + if( nextDict) + iter = 0; + else + iter = OSCollectionIterator::withCollection( + OSDynamicCast(OSCollection, obj)); + + while( nextDict + || (iter && (0 != (nextDict = OSDynamicCast(OSDictionary, + iter->getNextObject()))))) { + match = dict->isEqualTo( nextDict, nextDict); + if( match) + break; + nextDict = 0; + } + dict->release(); + if( iter) + iter->release(); + } + if( !match) + break; + } - done++; - iter = getClientIterator(); - if( iter) { - while( (service = (IOService *) iter->getNextObject())) { - if( kIOServiceInactiveState & service->__state[0]) - continue; - if( 0 == service->getProperty( gIOMatchCategoryKey )) - continue; - ++serviceCount; + str = OSDynamicCast( OSString, table->getObject( gIOPathMatchKey )); + if( str) { + done++; + entry = IORegistryEntry::fromPath( str->getCStringNoCopy() ); + match = (where == entry); + if( entry) + entry->release(); + if( !match) + break; + } + + num = OSDynamicCast( OSNumber, table->getObject( gIOMatchedServiceCountKey )); + if( num) { + + OSIterator * iter; + IOService * service = 0; + UInt32 serviceCount = 0; + + done++; + iter = where->getClientIterator(); + if( iter) { + while( (service = (IOService *) iter->getNextObject())) { + if( kIOServiceInactiveState & service->__state[0]) + continue; + if( 0 == service->getProperty( gIOMatchCategoryKey )) + continue; + ++serviceCount; + } + iter->release(); } - iter->release(); + match = (serviceCount == num->unsigned32BitValue()); + if( !match) + break; } - match = (serviceCount == num->unsigned32BitValue()); - if( !match) - break; - } - if( done == table->getCount()) - // don't call family if we've done all the entries in the table - break; + if( done == table->getCount()) { + // don't call family if we've done all the entries in the table + matchParent = false; + break; + } - // pass in score from property table - score = IOServiceObjectOrder( table, (void *) gIOProbeScoreKey); + // pass in score from property table + score = IOServiceObjectOrder( table, (void *) gIOProbeScoreKey); - // do family specific matching - match = where->matchPropertyTable( table, &score ); + // do family specific matching + match = where->matchPropertyTable( table, &score ); - if( !match) { + if( !match) { #if IOMATCHDEBUG - if( kIOLogMatch & getDebugFlags( table )) - LOG("%s: family specific matching fails\n", where->getName()); + if( kIOLogMatch & getDebugFlags( table )) + LOG("%s: family specific matching fails\n", where->getName()); #endif - break; - } + break; + } - if( changesOK) { - // save the score - newPri = OSNumber::withNumber( score, 32 ); - if( newPri) { - table->setObject( gIOProbeScoreKey, newPri ); - newPri->release(); + if( changesOK) { + // save the score + newPri = OSNumber::withNumber( score, 32 ); + if( newPri) { + table->setObject( gIOProbeScoreKey, newPri ); + newPri->release(); + } } - } - if( !(match = where->compareProperty( table, kIOBSDNameKey ))) - break; + if( !(match = where->compareProperty( table, kIOBSDNameKey ))) + break; - table = OSDynamicCast( OSDictionary, - table->getObject( gIOLocationMatchKey )); - if( table) { - match = false; - where = where->getProvider(); - if( where) - where = where->matchLocation( where ); - } + matchParent = false; + + obj = OSDynamicCast( OSDictionary, + table->getObject( gIOParentMatchKey )); + if( obj) { + match = false; + matchParent = true; + table = (OSDictionary *) obj; + break; + } + + table = OSDynamicCast( OSDictionary, + table->getObject( gIOLocationMatchKey )); + if( table) { + match = false; + where = where->getProvider(); + if( where) + where = where->matchLocation( where ); + } + + } while( table && where ); - } while( table && where ); + } while( matchParent && (where = where->getProvider()) ); if( kIOLogMatch & gIOKitDebug) if( where != this) - LOG("match location @ %s = %d\n", + LOG("match parent @ %s = %d\n", where->getName(), match ); return( match ); @@ -4040,7 +4103,7 @@ int IOService::errnoFromReturn( IOReturn rtn ) case kIOReturnBadMedia: case kIOReturnNoMedia: case kIOReturnUnformattedMedia: - return(EIO); // (media error) + return(ENXIO); // (media error) case kIOReturnDMAError: case kIOReturnOverrun: case kIOReturnUnderrun: diff --git a/iokit/Kernel/IOServicePM.cpp b/iokit/Kernel/IOServicePM.cpp index 2e762ef9c..0f381dbfb 100644 --- a/iokit/Kernel/IOServicePM.cpp +++ b/iokit/Kernel/IOServicePM.cpp @@ -22,13 +22,14 @@ #include #include -#include #include #include #include #include #include #include +#include +#include #include #include "IOKit/pwr_mgt/IOPMinformeeList.h" #include "IOKit/pwr_mgt/IOPMchangeNoteList.h" @@ -38,9 +39,38 @@ #define super IORegistryEntry +// Some debug functions +static inline void +ioSPMTrace(unsigned int csc, + unsigned int a = 0, unsigned int b = 0, + unsigned int c = 0, unsigned int d = 0) +{ + if (gIOKitDebug & kIOLogTracePower) + IOTimeStampConstant(IODBG_POWER(csc), a, b, c, d); +} + +static inline void +ioSPMTraceStart(unsigned int csc, + unsigned int a = 0, unsigned int b = 0, + unsigned int c = 0, unsigned int d = 0) +{ + if (gIOKitDebug & kIOLogTracePower) + IOTimeStampConstant(IODBG_POWER(csc)|DBG_FUNC_START, a, b, c, d); +} + +static inline void +ioSPMTraceEnd(unsigned int csc, + unsigned int a = 0, unsigned int b = 0, + unsigned int c = 0, unsigned int d = 0) +{ + if (gIOKitDebug & kIOLogTracePower) + IOTimeStampConstant(IODBG_POWER(csc)|DBG_FUNC_END, a, b, c, d); +} + + static void ack_timer_expired(thread_call_param_t); static void settle_timer_expired(thread_call_param_t); -void PMreceiveCmd ( OSObject *, void *, void *, void *, void * ); +IOReturn unIdleDevice ( OSObject *, void *, void *, void *, void * ); static void PM_idle_timer_expired(OSObject *, IOTimerEventSource *); static void c_PM_Clamp_Timer_Expired (OSObject * client,IOTimerEventSource *); void tellAppWithResponse ( OSObject * object, void * context); @@ -255,7 +285,6 @@ void IOService::PMinit ( void ) priv->previousRequest = 0; priv->device_overrides = false; priv->machine_state = IOPMfinished; - pm_vars->commandQueue = NULL; priv->timerEventSrc = NULL; priv->clampTimerEventSrc = NULL; pm_vars->PMworkloop = NULL; @@ -322,10 +351,6 @@ void IOService::PMfree ( void ) } if ( pm_vars ) { - if ( pm_vars->commandQueue ) { - pm_vars->commandQueue->release(); - pm_vars->commandQueue = NULL; - } if ( pm_vars->PMcommandGate ) { pm_vars->PMcommandGate->release(); pm_vars->PMcommandGate = NULL; @@ -879,6 +904,9 @@ IOReturn IOService::acknowledgeSetPowerState ( void ) if (! acquire_lock() ) { return IOPMNoErr; } + + ioSPMTrace(IOPOWER_ACK, * (int *) this); + if ( priv->driver_timer == -1 ) { priv->driver_timer = 0; // driver is acking instead of using return code } @@ -1396,8 +1424,7 @@ bool IOService::activityTickle ( unsigned long type, unsigned long stateNumber=0 if ( type == kIOPMSuperclassPolicy1 ) { if ( (priv->activityLock == NULL) || - (pm_vars->theControllingDriver == NULL) || - (pm_vars->commandQueue == NULL) ) { + (pm_vars->theControllingDriver == NULL) ) { return true; } IOTakeLock(priv->activityLock); @@ -1410,8 +1437,8 @@ bool IOService::activityTickle ( unsigned long type, unsigned long stateNumber=0 IOUnlock(priv->activityLock); return true; } - IOUnlock(priv->activityLock); // send a message on the command queue - pm_vars->commandQueue->enqueueCommand(true, (void *)kIOPMUnidleDevice, (void *)stateNumber); + IOUnlock(priv->activityLock); + pm_vars->PMcommandGate->runAction(unIdleDevice,(void *)stateNumber); return false; } return true; @@ -1466,14 +1493,6 @@ IOReturn IOService::setIdleTimerPeriod ( unsigned long period ) if ( getPMworkloop() == NULL ) { return kIOReturnError; } - - if (pm_vars->commandQueue == NULL ) { // make the command queue - pm_vars->commandQueue = IOCommandQueue::commandQueue(this, PMreceiveCmd); - if (! pm_vars->commandQueue || - ( pm_vars->PMworkloop->addEventSource( pm_vars->commandQueue) != kIOReturnSuccess) ) { - return kIOReturnError; - } - } // make the timer event if ( priv->timerEventSrc == NULL ) { priv->timerEventSrc = IOTimerEventSource::timerEventSource(this, @@ -1584,34 +1603,31 @@ void IOService::PM_idle_timer_expiration ( void ) // ********************************************************************************** -// PMreceiveCmd -// -// +// unIdleDevice // +// We are behind the command gate. This serializes with respect to timer expiration. // ********************************************************************************** -void PMreceiveCmd ( OSObject * theDriver, void * command, void * param1, void * param2, void *param3 ) +IOReturn unIdleDevice ( OSObject * theDriver, void * param1, void * param2, void * param3, void * param4 ) { - ((IOService *)theDriver)->command_received(command,param1,param2,param3); + ((IOService *)theDriver)->command_received(param1,param2,param3,param4); + return kIOReturnSuccess; } // ********************************************************************************** // command_received // -// We have received a command from ourselves on the command queue. -// This is to prevent races with timer-expiration code. +// We are un-idling a device due to its activity tickle. // ********************************************************************************** -void IOService::command_received ( void * command, void *stateNumber , void * , void *) +void IOService::command_received ( void * stateNumber, void *, void * , void * ) { if ( ! initialized ) { return; // we're unloading } - if ( command == (void *)kIOPMUnidleDevice ) { - if ( (pm_vars->myCurrentState < (unsigned long)stateNumber) && - (priv->imminentState < (unsigned long)stateNumber) ) { - changePowerStateToPriv((unsigned long)stateNumber); - } + if ( (pm_vars->myCurrentState < (unsigned long)stateNumber) && + (priv->imminentState < (unsigned long)stateNumber) ) { + changePowerStateToPriv((unsigned long)stateNumber); } } @@ -3258,7 +3274,10 @@ IOReturn IOService::instruct_driver ( unsigned long newState ) pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogProgramHardware,newState,0); + ioSPMTraceStart(IOPOWER_STATE, * (int *) this, (int) newState); return_code = pm_vars->theControllingDriver->setPowerState( newState,this ); // yes, instruct it + ioSPMTraceEnd(IOPOWER_STATE, * (int *) this, (int) newState, (int) return_code); + if ( return_code == IOPMAckImplied ) { // it finished priv->driver_timer = 0; return IOPMAckImplied; @@ -3824,6 +3843,7 @@ IOReturn IOService::allowCancelCommon ( void ) void IOService::clampPowerOn (unsigned long duration) { +/* changePowerStateToPriv (pm_vars->theNumberOfPowerStates-1); if ( priv->clampTimerEventSrc == NULL ) { @@ -3838,7 +3858,8 @@ void IOService::clampPowerOn (unsigned long duration) } } - priv->clampTimerEventSrc->setTimeout(kFiveMinutesInNanoSeconds, NSEC_PER_SEC); + priv->clampTimerEventSrc->setTimeout(300*USEC_PER_SEC, USEC_PER_SEC); +*/ } //********************************************************************************* diff --git a/iokit/Kernel/IOServicePrivate.h b/iokit/Kernel/IOServicePrivate.h index 3f0f8b505..c74307f6b 100644 --- a/iokit/Kernel/IOServicePrivate.h +++ b/iokit/Kernel/IOServicePrivate.h @@ -69,7 +69,7 @@ struct _IOServiceNotifierInvocation class _IOServiceNotifier : public IONotifier { - friend IOService; + friend class IOService; OSDeclareDefaultStructors(_IOServiceNotifier) @@ -93,7 +93,7 @@ public: class _IOServiceInterestNotifier : public IONotifier { - friend IOService; + friend class IOService; OSDeclareDefaultStructors(_IOServiceInterestNotifier) @@ -115,7 +115,7 @@ public: class _IOConfigThread : public OSObject { - friend IOService; + friend class IOService; OSDeclareDefaultStructors(_IOConfigThread) @@ -142,7 +142,7 @@ enum { class _IOServiceJob : public OSObject { - friend IOService; + friend class IOService; OSDeclareDefaultStructors(_IOServiceJob) @@ -159,7 +159,7 @@ public: class IOResources : public IOService { - friend IOService; + friend class IOService; OSDeclareDefaultStructors(IOResources) @@ -167,11 +167,12 @@ public: static IOService * resources( void ); virtual IOWorkLoop * getWorkLoop( ) const; virtual bool matchPropertyTable( OSDictionary * table ); + virtual IOReturn setProperties( OSObject * properties ); }; class _IOOpenServiceIterator : public OSIterator { - friend IOService; + friend class IOService; OSDeclareDefaultStructors(_IOOpenServiceIterator) diff --git a/iokit/Kernel/IOStartIOKit.cpp b/iokit/Kernel/IOStartIOKit.cpp index ba2387f42..1121d5ef3 100644 --- a/iokit/Kernel/IOStartIOKit.cpp +++ b/iokit/Kernel/IOStartIOKit.cpp @@ -103,7 +103,7 @@ void IOKitResetTime( void ) calend_sleep_wake_call = thread_call_allocate( calend_wakeup_resynch, NULL); - registerSleepWakeInterest(calend_sleep_wake_notif, NULL, NULL); + registerSleepWakeInterest((void *)calend_sleep_wake_notif, NULL, NULL); } clock_initialize_calendar(); diff --git a/iokit/Kernel/IOStringFuncs.c b/iokit/Kernel/IOStringFuncs.c index 0e20f8c50..46e7a246e 100644 --- a/iokit/Kernel/IOStringFuncs.c +++ b/iokit/Kernel/IOStringFuncs.c @@ -71,7 +71,6 @@ #include */ #include -#include #include typedef int BOOL; diff --git a/iokit/Kernel/IOSyncer.cpp b/iokit/Kernel/IOSyncer.cpp index 815cc3b1f..92e1d0741 100644 --- a/iokit/Kernel/IOSyncer.cpp +++ b/iokit/Kernel/IOSyncer.cpp @@ -83,7 +83,7 @@ IOReturn IOSyncer::wait(bool autoRelease = true) if (threadMustStop) { assert_wait((void *) &threadMustStop, false); IOSimpleLockUnlockEnableInterrupt(guardLock, is); - thread_block(0); + thread_block(THREAD_CONTINUE_NULL); } else IOSimpleLockUnlockEnableInterrupt(guardLock, is); diff --git a/iokit/Kernel/IOUserClient.cpp b/iokit/Kernel/IOUserClient.cpp index acdfedc89..06f700f5b 100644 --- a/iokit/Kernel/IOUserClient.cpp +++ b/iokit/Kernel/IOUserClient.cpp @@ -65,6 +65,9 @@ extern io_object_t iokit_lookup_connect_ref_current_task(io_object_t clientRef); extern ipc_port_t master_device_port; +extern void iokit_retain_port( ipc_port_t port ); +extern void iokit_release_port( ipc_port_t port ); + #include } /* extern "C" */ @@ -80,9 +83,12 @@ class IOMachPort : public OSObject public: OSObject * object; ipc_port_t port; + UInt32 mscount; static IOMachPort * portForObject( OSObject * obj, ipc_kobject_type_t type ); + static bool noMoreSendersForObject( OSObject * obj, + ipc_kobject_type_t type, mach_port_mscount_t * mscount ); static void releasePortForObject( OSObject * obj, ipc_kobject_type_t type ); static OSDictionary * dictForType( ipc_kobject_type_t type ); @@ -136,8 +142,11 @@ IOMachPort * IOMachPort::portForObject ( OSObject * obj, continue; if( (inst = (IOMachPort *) - dict->getObject( (const OSSymbol *) obj ))) + dict->getObject( (const OSSymbol *) obj ))) { + inst->mscount++; + inst->retain(); continue; + } inst = new IOMachPort; if( inst && !inst->init()) { @@ -149,7 +158,7 @@ IOMachPort * IOMachPort::portForObject ( OSObject * obj, if( inst->port) { // retains obj dict->setObject( (const OSSymbol *) obj, inst ); - inst->release(); // one more to free port => release obj + inst->mscount++; } else { inst->release(); @@ -163,6 +172,34 @@ IOMachPort * IOMachPort::portForObject ( OSObject * obj, return( inst ); } +bool IOMachPort::noMoreSendersForObject( OSObject * obj, + ipc_kobject_type_t type, mach_port_mscount_t * mscount ) +{ + OSDictionary * dict; + IOMachPort * machPort; + bool destroyed = true; + + IOTakeLock( gIOObjectPortLock); + + if( (dict = dictForType( type ))) { + obj->retain(); + + machPort = (IOMachPort *) dict->getObject( (const OSSymbol *) obj ); + if( machPort) { + destroyed = (machPort->mscount == *mscount); + if( destroyed) + dict->removeObject( (const OSSymbol *) obj ); + else + *mscount = machPort->mscount; + } + obj->release(); + } + + IOUnlock( gIOObjectPortLock); + + return( destroyed ); +} + void IOMachPort::releasePortForObject( OSObject * obj, ipc_kobject_type_t type ) { @@ -222,20 +259,32 @@ ipc_port_t iokit_port_for_object( io_object_t obj, ipc_kobject_type_t type ) { IOMachPort * machPort; + ipc_port_t port; - if( (machPort = IOMachPort::portForObject( obj, type ))) - return( machPort->port ); - else - return( 0 ); + if( (machPort = IOMachPort::portForObject( obj, type ))) { + + port = machPort->port; + if( port) + iokit_retain_port( port ); + + machPort->release(); + + } else + port = NULL; + + return( port ); } kern_return_t iokit_client_died( io_object_t obj, ipc_port_t /* port */, - ipc_kobject_type_t type ) + ipc_kobject_type_t type, mach_port_mscount_t * mscount ) { IOUserClient * client; IOMemoryMap * map; + if( !IOMachPort::noMoreSendersForObject( obj, type, mscount )) + return( kIOReturnNotReady ); + if( (IKOT_IOKIT_CONNECT == type) && (client = OSDynamicCast( IOUserClient, obj ))) client->clientDied(); @@ -243,9 +292,7 @@ iokit_client_died( io_object_t obj, ipc_port_t /* port */, && (map = OSDynamicCast( IOMemoryMap, obj ))) map->taskDied(); - IOMachPort::releasePortForObject( obj, type ); - - return( kIOReturnSuccess); + return( kIOReturnSuccess ); } }; /* extern "C" */ @@ -351,7 +398,7 @@ bool IOUserNotification::init( mach_port_t port, natural_t type, pingMsg->msgHdr.msgh_remote_port = port; pingMsg->msgHdr.msgh_bits = MACH_MSGH_BITS( MACH_MSG_TYPE_COPY_SEND, - MACH_MSG_TYPE_COPY_SEND ); + MACH_MSG_TYPE_MAKE_SEND ); pingMsg->msgHdr.msgh_size = msgSize; pingMsg->msgHdr.msgh_id = kOSNotificationMessageID; @@ -436,7 +483,7 @@ bool IOServiceUserNotification::handler( void * /* ref */, { unsigned int count; kern_return_t kr; - IOMachPort * machPort; + ipc_port_t port = NULL; bool sendPing = false; IOTakeLock( lock ); @@ -452,12 +499,16 @@ bool IOServiceUserNotification::handler( void * /* ref */, IOUnlock( lock ); if( sendPing) { - if( (0 == pingMsg->msgHdr.msgh_local_port) - && (machPort = IOMachPort::portForObject( this, IKOT_IOKIT_OBJECT ) )) - pingMsg->msgHdr.msgh_local_port = machPort->port; + if( (port = iokit_port_for_object( this, IKOT_IOKIT_OBJECT ) )) + pingMsg->msgHdr.msgh_local_port = port; + else + pingMsg->msgHdr.msgh_local_port = NULL; kr = mach_msg_send_from_kernel( &pingMsg->msgHdr, pingMsg->msgHdr.msgh_size); + if( port) + iokit_release_port( port ); + if( KERN_SUCCESS != kr) IOLog("%s: mach_msg_send_from_kernel {%x}\n", __FILE__, kr ); } @@ -522,7 +573,7 @@ IOReturn IOServiceMessageUserNotification::handler( void * ref, void * messageArgument, vm_size_t argSize ) { kern_return_t kr; - IOMachPort * machPort; + ipc_port_t port; IOServiceInterestContent * data = (IOServiceInterestContent *) pingMsg->notifyHeader.content; @@ -540,13 +591,17 @@ IOReturn IOServiceMessageUserNotification::handler( void * ref, - sizeof( data->messageArgument) + argSize; - if( (machPort = IOMachPort::portForObject( provider, IKOT_IOKIT_OBJECT ) )) - pingMsg->msgHdr.msgh_local_port = machPort->port; + if( (port = iokit_port_for_object( provider, IKOT_IOKIT_OBJECT ) )) + pingMsg->msgHdr.msgh_local_port = port; else - pingMsg->msgHdr.msgh_local_port = MACH_PORT_NULL; + pingMsg->msgHdr.msgh_local_port = NULL; kr = mach_msg_send_from_kernel( &pingMsg->msgHdr, pingMsg->msgHdr.msgh_size); + + if( port) + iokit_release_port( port ); + if( KERN_SUCCESS != kr) IOLog("%s: mach_msg_send_from_kernel {%x}\n", __FILE__, kr ); @@ -675,8 +730,8 @@ IOReturn IOUserClient::clientMemoryForType( UInt32 type, IOMemoryMap * IOUserClient::mapClientMemory( IOOptionBits type, task_t task, - IOOptionBits mapFlags = kIOMapAnywhere, - IOVirtualAddress atAddress = 0 ) + IOOptionBits mapFlags, + IOVirtualAddress atAddress ) { IOReturn err; IOOptionBits options = 0; @@ -1311,14 +1366,7 @@ kern_return_t is_io_registry_entry_get_property_bytes( CHECK( IORegistryEntry, registry_entry, entry ); -#if 0 - // need virtual obj = entry->copyProperty(property_name); -#else - obj = entry->getProperty(property_name); - if( obj) - obj->retain(); -#endif if( !obj) return( kIOReturnNoResources ); @@ -1374,14 +1422,7 @@ kern_return_t is_io_registry_entry_get_property( CHECK( IORegistryEntry, registry_entry, entry ); -#if 0 - // need virtual obj = entry->copyProperty(property_name); -#else - obj = entry->getProperty(property_name); - if( obj) - obj->retain(); -#endif if( !obj) return( kIOReturnNotFound ); @@ -1421,15 +1462,8 @@ kern_return_t is_io_registry_entry_get_property_recursively( CHECK( IORegistryEntry, registry_entry, entry ); -#if 0 obj = entry->copyProperty( property_name, IORegistryEntry::getPlane( plane ), options); -#else - obj = entry->getProperty( property_name, - IORegistryEntry::getPlane( plane ), options); - if( obj) - obj->retain(); -#endif if( !obj) return( kIOReturnNotFound ); @@ -2467,6 +2501,8 @@ kern_return_t is_io_catalog_send_data( case kIOCatalogRemoveKernelLinker: { if (gIOCatalogue->removeKernelLinker() != KERN_SUCCESS) { kr = kIOReturnError; + } else { + kr = kIOReturnSuccess; } } break; diff --git a/iokit/Kernel/IOWorkLoop.cpp b/iokit/Kernel/IOWorkLoop.cpp index 1581f38ca..197a09512 100644 --- a/iokit/Kernel/IOWorkLoop.cpp +++ b/iokit/Kernel/IOWorkLoop.cpp @@ -57,6 +57,8 @@ static inline bool ISSETP(void *addr, unsigned int flag) #define fFlags loopRestart +extern "C" extern void stack_privilege( thread_t thread); + void IOWorkLoop::launchThreadMain(void *self) { register thread_t mythread = current_thread(); @@ -298,13 +300,8 @@ void IOWorkLoop::threadMain() assert_wait((void *) &workToDo, false); IOSimpleLockUnlockEnableInterrupt(workToDoLock, is); -#if defined (__i386__) - thread_block(0); - continue; -#else thread_set_cont_arg((int) this); thread_block(&threadMainContinuation); -#endif /* NOTREACHED */ } @@ -321,7 +318,7 @@ void IOWorkLoop::threadMain() exitThread: workThread = 0; // Say we don't have a loop and free ourselves free(); - IOExitThread(0); + IOExitThread(); } IOThread IOWorkLoop::getThread() const @@ -398,43 +395,48 @@ IOReturn IOWorkLoop::_maintRequest(void *inC, void *inD, void *, void *) switch (command) { case mAddEvent: - SETP(&fFlags, kLoopRestart); - inEvent->retain(); - inEvent->setWorkLoop(this); - inEvent->setNext(0); - - if (!eventChain) - eventChain = inEvent; - else { - IOEventSource *event, *next; - - for (event = eventChain; (next = event->getNext()); event = next) - ; - event->setNext(inEvent); + if (!inEvent->getWorkLoop()) { + SETP(&fFlags, kLoopRestart); + + inEvent->retain(); + inEvent->setWorkLoop(this); + inEvent->setNext(0); + + if (!eventChain) + eventChain = inEvent; + else { + IOEventSource *event, *next; + + for (event = eventChain; (next = event->getNext()); event = next) + ; + event->setNext(inEvent); + } } break; case mRemoveEvent: - if (eventChain == inEvent) - eventChain = inEvent->getNext(); - else { - IOEventSource *event, *next; - - event = eventChain; - while ((next = event->getNext()) && next != inEvent) - event = next; - - if (!next) { - res = kIOReturnBadArgument; - break; + if (inEvent->getWorkLoop()) { + if (eventChain == inEvent) + eventChain = inEvent->getNext(); + else { + IOEventSource *event, *next; + + event = eventChain; + while ((next = event->getNext()) && next != inEvent) + event = next; + + if (!next) { + res = kIOReturnBadArgument; + break; + } + event->setNext(inEvent->getNext()); } - event->setNext(inEvent->getNext()); + + inEvent->setWorkLoop(0); + inEvent->setNext(0); + inEvent->release(); + SETP(&fFlags, kLoopRestart); } - - inEvent->setWorkLoop(0); - inEvent->setNext(0); - inEvent->release(); - SETP(&fFlags, kLoopRestart); break; default: diff --git a/iokit/Kernel/ppc/IOAsmSupport.s b/iokit/Kernel/ppc/IOAsmSupport.s index ecc34366b..603f7fd73 100644 --- a/iokit/Kernel/ppc/IOAsmSupport.s +++ b/iokit/Kernel/ppc/IOAsmSupport.s @@ -79,7 +79,7 @@ OSStatus CallTVector_NoRecover( #if 1 stw r2, FM_TOC_SAVE(r1) - lwz r0, 0(r9) + lwz r0, 0(r9) lwz r2, 4(r9) mtspr ctr, r0 bctr diff --git a/iokit/KernelConfigTables.cpp b/iokit/KernelConfigTables.cpp index f06533b63..da3600617 100644 --- a/iokit/KernelConfigTables.cpp +++ b/iokit/KernelConfigTables.cpp @@ -28,11 +28,11 @@ */ const char * gIOKernelKmods = "{ - 'com.apple.kernel' = '5.5'; - 'com.apple.kernel.bsd' = '5.5'; - 'com.apple.kernel.iokit' = '5.5'; - 'com.apple.kernel.libkern' = '5.5'; - 'com.apple.kernel.mach' = '5.5'; + 'com.apple.kernel' = '6.0'; + 'com.apple.kernel.bsd' = '6.0'; + 'com.apple.kernel.iokit' = '6.0'; + 'com.apple.kernel.libkern' = '6.0'; + 'com.apple.kernel.mach' = '6.0'; 'com.apple.iokit.IOADBFamily' = '1.1'; 'com.apple.iokit.IONVRAMFamily' = '1.1'; 'com.apple.iokit.IOSystemManagementFamily' = '1.1'; @@ -57,105 +57,20 @@ const char * gIOKernelConfigTables = 'IONameMatch' = 'cpu'; 'IOProbeScore' = 100:32; }, -" -#if 0 -" - { - 'IOClass' = PowerSurgePE; - 'IOProviderClass' = IOPlatformExpertDevice; - 'IONameMatch' = ('AAPL,7300', 'AAPL,7500', 'AAPL,8500', 'AAPL,9500'); - 'IOProbeScore' = 10000:32; - }, -" -#endif -" -" -#if 0 -" - { - 'IOClass' = PowerStarPE; - 'IOProviderClass' = IOPlatformExpertDevice; - 'IONameMatch' = ('AAPL,3400/2400', 'AAPL,3500'); - 'IOProbeScore' = 10000:32; - }, -" -#endif -" - { - 'IOClass' = GossamerPE; - 'IOProviderClass' = IOPlatformExpertDevice; - 'IONameMatch' = ('AAPL,Gossamer', 'AAPL,PowerMac G3', 'AAPL,PowerBook1998', 'iMac,1', 'PowerMac1,1', 'PowerMac1,2', 'PowerBook1,1'); - 'IOProbeScore' = 10000:32; - }, - { - 'IOClass' = GossamerCPU; - 'IOProviderClass' = IOPlatformDevice; - 'IONameMatch' = 'cpu'; - 'IOProbeScore' = 1000:32; - }, -" -#if 0 -" - { - 'IOClass' = PowerExpressPE; - 'IOProviderClass' = IOPlatformExpertDevice; - 'IONameMatch' = 'AAPL,9700'; - 'IOProbeScore' = 10000:32; - 'senses' = <00000000 00000000 00000000 00000000 " - "00000000 00000000 00000000 00000000 " - "00000000 00000000 00000000 00000000 " - "00000000 00000000 00000000 00000000 " - "00000000 00000000 00000000 00000000 " - "00000000 00000000 00000000 00000000 " - "00000000 00000000 00000001 00000001 " - "00000001 00000001 00000001 00000001 " - "00000001 00000001 00000001 00000001 " - "00000001 00000001>; - }, -" -#endif -#if 0 -" - { - 'IOClass' = GrandCentral; - 'IOProviderClass' = IOPCIDevice; - 'IONameMatch' = gc; - 'IOProbeScore' = 2000:32; - }, -" -#endif -" - { - 'IOClass' = OHare; - 'IOProviderClass' = IOPCIDevice; - 'IONameMatch' = ('ohare', 'pci106b,7'); - }, { 'IOClass' = AppleNMI; 'IOProviderClass' = AppleMacIODevice; 'IONameMatch' = 'programmer-switch'; }, - { - 'IOClass' = AppleCuda; - 'IOProviderClass' = AppleVIADevice; - 'IONameMatch' = cuda; - }," -#if 0 -" { - 'IOClass' = ApplePMU; - 'IOProviderClass' = AppleVIADevice; - 'IONameMatch' = pmu; - }," -#endif - "{ - 'IOClass' = IOPMUADBController; - 'IOProviderClass' = AppleMacIODevice; - 'IONameMatch' = adb; - }, { 'IOClass' = AppleNVRAM; 'IOProviderClass' = AppleMacIODevice; 'IONameMatch' = nvram; + }, + { + 'IOClass' = IOPMUADBController; + 'IOProviderClass' = AppleMacIODevice; + 'IONameMatch' = adb; } " #endif /* PPC */ @@ -190,18 +105,6 @@ const char * gIOKernelConfigTables = 'IOClass' = AppleIntelClock; 'IOProviderClass' = IOPlatformDevice; 'IONameMatch' = intel-clock; - }, - { - 'IOClass' = AppleATAPIIX; - 'IOProviderClass' = IOPCIDevice; - 'IOPCIMatch' = '0x12308086 0x70108086 0x71118086 0x24118086 0x24218086 0x244a8086 0x244b8086'; - 'IOMatchCategory' = AppleATAPIIXChannel0; - }, - { - 'IOClass' = AppleATAPIIX; - 'IOProviderClass' = IOPCIDevice; - 'IOPCIMatch' = '0x12308086 0x70108086 0x71118086 0x24118086 0x24218086 0x244a8086 0x244b8086'; - 'IOMatchCategory' = AppleATAPIIXChannel1; } " #endif /* i386 */ diff --git a/iokit/bsddev/DINetBootHook.cpp b/iokit/bsddev/DINetBootHook.cpp new file mode 100644 index 000000000..f80e35b35 --- /dev/null +++ b/iokit/bsddev/DINetBootHook.cpp @@ -0,0 +1,169 @@ +/* + * DINetBootHook.c + * DiskImages + * + * Created by Byron Han on Sat Apr 13 2002. + * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * + * Revision History + * + * $Log: DINetBootHook.cpp,v $ + * Revision 1.3 2002/06/16 20:36:02 lindak + * Merged PR-2957314 into Jaguar (siegmund: netboot kernel code needs to set + * com.apple.AppleDiskImageController.load to boolean Yes) + * + * Revision 1.2.40.2 2002/06/15 03:50:38 dieter + * - corrected com.apple.AppleDiskImageController.load string + * + * Revision 1.2.40.1 2002/06/15 03:01:08 dieter + * Bug #: 2957314 + * - add call to force IOHDIXController to get loaded/matched + * + * Revision 1.2 2002/05/03 18:08:39 lindak + * Merged PR-2909558 into Jaguar (siegmund POST WWDC: add support for NetBoot + * over IOHDIXController) + * + * Revision 1.1.2.1 2002/04/24 22:29:12 dieter + * Bug #: 2909558 + * - added IOHDIXController netboot stubs + * + * Revision 1.3 2002/04/16 00:41:37 han + * migrated code out of here to IOHDIXController's setProperty method + * + * Revision 1.2 2002/04/14 23:53:53 han + * eliminate qDEBUG=1, use emums instead of hard coded string constants + * + * Revision 1.1 2002/04/14 22:54:42 han + * Renamed from DINetBookHook.c. + * First stab at implementing this code. + * + * Revision 1.1 2002/04/13 19:22:28 han + * added stub file DINetBookHook.c + * + * + */ +#ifndef qDEBUG +#define qDEBUG 0 +#endif + +#if qDEBUG +#warning qDEBUG is 1! +#endif + +#include +#include +#include + +#define kIOHDIXControllerClassName "IOHDIXController" +#define kDIRootImageKey "di-root-image" +#define kDIRootImageResultKey "di-root-image-result" +#define kDIRootImageDevNameKey "di-root-image-devname" +#define kDIRootImageDevTKey "di-root-image-devt" + +extern "C" { +/* + Name: di_root_image + Function: mount the disk image returning the dev node + Parameters: path -> path/url to disk image + devname <- dev node used to set the rootdevice global variable + dev_p <- device number generated from major/minor numbers + Comments: +*/ +int di_root_image(const char *path, char devname[], dev_t *dev_p) +{ + IOReturn res = 0; + OSIterator * controllerIterator = 0; + OSDictionary * matchDictionary = 0; + IOService * controller = 0; + OSString * pathString = 0; + OSNumber * myResult = 0; + OSString * myDevName = 0; + OSNumber * myDevT = 0; + + // sanity check arguments please + if (devname) *devname = 0; + if (dev_p) *dev_p = 0; + + if (!path) return kIOReturnBadArgument; + if (!devname) return kIOReturnBadArgument; + if (!dev_p) return kIOReturnBadArgument; + + (void)IOService::getResourceService()->publishResource("com.apple.AppleDiskImageController.load", kOSBooleanTrue); + IOService::getResourceService()->waitQuiet(); + + // first find IOHDIXController + matchDictionary = IOService::serviceMatching(kIOHDIXControllerClassName); + if (!matchDictionary) { + res = kIOReturnNoMemory; + goto serviceMatching_FAILED; + } + + controllerIterator = IOService::getMatchingServices(matchDictionary); + if (!controllerIterator) { + res = kIOReturnNoMemory; + goto getMatchingServices_FAILED; + } + + // use the "setProperty" method of IOHDIXController to trigger the desired behaviour + controller = OSDynamicCast(IOService, controllerIterator->getNextObject()); + if (!controller) { + res = kIOReturnNotFound; + goto NoIOHDIXController; + } + + // okay create path object + pathString = OSString::withCString(path); + if (!pathString) { + res = kIOReturnNoMemory; + goto CannotCreatePathOSString; + } + + // do it + if (!controller->setProperty(kDIRootImageKey, pathString)) + IOLog("IOHDIXController::setProperty(%s, %s) failed.\n", kDIRootImageKey, pathString->getCStringNoCopy()); + + myResult = OSDynamicCast(OSNumber, controller->getProperty(kDIRootImageResultKey)); + res = kIOReturnError; + if (myResult) + res = myResult->unsigned32BitValue(); + + if (res) { + IOLog("%s is 0x%08X/%d\n", kDIRootImageResultKey, res, res); + goto di_root_image_FAILED; + } + + // success - grab + myDevT = OSDynamicCast(OSNumber, controller->getProperty(kDIRootImageDevTKey)); + if (myDevT) + *dev_p = myDevT->unsigned32BitValue(); + else { + IOLog("could not get %s\n", kDIRootImageDevTKey); + res = kIOReturnError; + goto di_root_image_FAILED; + } + + myDevName = OSDynamicCast(OSString, controller->getProperty(kDIRootImageDevNameKey)); + if (myDevName) + strcpy(devname, myDevName->getCStringNoCopy()); + else { + IOLog("could not get %s\n", kDIRootImageDevNameKey); + res = kIOReturnError; + goto di_root_image_FAILED; + } + + +di_root_image_FAILED: +CannotCreatePathOSString: +serviceMatching_FAILED: +NoIOHDIXController: +getMatchingServices_FAILED: + + // clean up memory allocations + if (pathString) pathString->release(); + if (matchDictionary) matchDictionary->release(); + if (controllerIterator) controllerIterator->release(); + + return res; +} + +}; diff --git a/iokit/bsddev/DINetBootHook.h b/iokit/bsddev/DINetBootHook.h new file mode 100644 index 000000000..b2936edfb --- /dev/null +++ b/iokit/bsddev/DINetBootHook.h @@ -0,0 +1,70 @@ +/* + * DINetBootHook.h + * DiskImages + * + * Created by Byron Han on Sat Apr 13 2002. + * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * + * Revision History + * + * $Log: DINetBootHook.h,v $ + * Revision 1.3 2002/05/22 18:50:49 aramesh + * Kernel API Cleanup + * Bug #: 2853781 + * Changes from Josh(networking), Rick(IOKit), Jim & David(osfmk), Umesh, Dan & Ramesh(BSD) + * Submitted by: Ramesh + * Reviewed by: Vincent + * + * Revision 1.2.12.1 2002/05/21 23:08:14 aramesh + * Kernel API Cleanup + * Bug #: 2853781 + * Submitted by: Josh, Umesh, Jim, Rick and Ramesh + * Reviewed by: Vincent + * + * Revision 1.2 2002/05/03 18:08:39 lindak + * Merged PR-2909558 into Jaguar (siegmund POST WWDC: add support for NetBoot + * over IOHDIXController) + * + * Revision 1.1.2.1 2002/04/24 22:29:12 dieter + * Bug #: 2909558 + * - added IOHDIXController netboot stubs + * + * Revision 1.2 2002/04/14 22:56:47 han + * fixed up comment re dev_t + * + * Revision 1.1 2002/04/13 19:22:28 han + * added stub file DINetBookHook.c + * + * + */ + +#ifndef __DINETBOOKHOOK_H__ +#define __DINETBOOKHOOK_H__ + +#include + +#ifdef __APPLE_API_PRIVATE + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* + Name: di_root_image + Function: mount the disk image returning the dev node + Parameters: path -> path/url to disk image + devname <- dev node used to set the rootdevice global variable + dev_p <- combination of major/minor node + Comments: +*/ +int di_root_image(const char *path, char devname[], dev_t *dev_p); + +#ifdef __cplusplus +}; +#endif + +#endif /* __APPLE_API_PRIVATE */ + +#endif __DINETBOOKHOOK_H__ diff --git a/iokit/bsddev/IOKitBSDInit.cpp b/iokit/bsddev/IOKitBSDInit.cpp index ff860483f..c125eaeae 100644 --- a/iokit/bsddev/IOKitBSDInit.cpp +++ b/iokit/bsddev/IOKitBSDInit.cpp @@ -528,4 +528,35 @@ kern_return_t IOFindBSDRoot( char * rootName, return( kIOReturnSuccess ); } +void * +IOBSDRegistryEntryForDeviceTree(char * path) +{ + return (IORegistryEntry::fromPath(path, gIODTPlane)); +} + +void +IOBSDRegistryEntryRelease(void * entry) +{ + IORegistryEntry * regEntry = (IORegistryEntry *)entry; + + if (regEntry) + regEntry->release(); + return; +} + +const void * +IOBSDRegistryEntryGetData(void * entry, char * property_name, + int * packet_length) +{ + OSData * data; + IORegistryEntry * regEntry = (IORegistryEntry *)entry; + + data = (OSData *) regEntry->getProperty(property_name); + if (data) { + *packet_length = data->getLength(); + return (data->getBytesNoCopy()); + } + return (NULL); +} + } /* extern "C" */ diff --git a/iokit/conf/Makefile b/iokit/conf/Makefile index 42a0c8b7b..970b3246f 100644 --- a/iokit/conf/Makefile +++ b/iokit/conf/Makefile @@ -47,14 +47,13 @@ do_setup_conf: $(OBJROOT)/$(KERNEL_CONFIG)_$(ARCH_CONFIG)/$(COMPONENT)/doconf \ do_all: do_setup_conf @echo "[ $(SOURCE) ] Starting do_all $(COMPONENT) $(IOKIT_KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)"; \ - (cd $(COMPOBJROOT)/$(IOKIT_KERNEL_CONFIG); \ next_source=$(subst conf/,,$(SOURCE)); \ - ${MAKE} MAKEFILES=$(TARGET)/$(IOKIT_KERNEL_CONFIG)/Makefile \ + ${MAKE} -C $(COMPOBJROOT)/$(IOKIT_KERNEL_CONFIG) \ + MAKEFILES=$(TARGET)/$(IOKIT_KERNEL_CONFIG)/Makefile \ SOURCE=$${next_source} \ TARGET=$(TARGET) \ INCL_MAKEDEP=FALSE \ - build_all \ - ); \ + build_all; \ echo "[ $(SOURCE) ] Returning do_all $(COMPONENT) $(IOKIT_KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)"; do_build_all: do_all diff --git a/iokit/conf/files b/iokit/conf/files index 886d822a3..bdaf03c11 100644 --- a/iokit/conf/files +++ b/iokit/conf/files @@ -70,22 +70,8 @@ iokit/KernelConfigTables.cpp optional iokitcpp iokit/bsddev/IOKitBSDInit.cpp optional iokitcpp -# SCSI support -iokit/Families/IOSCSIParallel/IOSCSIParallelController.cpp optional iokitcpp -iokit/Families/IOSCSIParallel/IOSCSIParallelDevice.cpp optional iokitcpp -iokit/Families/IOSCSIParallel/IOSCSIParallelCommand.cpp optional iokitcpp -iokit/Families/IOSCSIParallel/queueHelpers.cpp optional iokitcpp - -# ATA support -#iokit/Families/IOATAStandard/IOATAStandardController.cpp optional iokitcpp -#iokit/Families/IOATAStandard/IOATAStandardDevice.cpp optional iokitcpp -#iokit/Families/IOATAStandard/IOATAStandardCommand.cpp optional iokitcpp -#iokit/Families/IOATAStandard/IOATAStandardData.cpp optional iokitcpp -#iokit/Families/IOATAStandard/ATAQueueHelpers.cpp optional iokitcpp - -#iokit/Families/IOATAStandard/IOATAStandardDriver.cpp optional iokitcpp -#iokit/Families/IOATAStandard/IOATAStandardDriverPio.cpp optional iokitcpp -#iokit/Families/IOATAStandard/IOATAStandardDriverDma.cpp optional iokitcpp +# Disk Image +iokit/bsddev/DINetBootHook.cpp optional iokitcpp # Power Management iokit/Drivers/platform/drvAppleRootDomain/RootDomainUserClient.cpp optional iokitcpp diff --git a/iokit/conf/files.i386 b/iokit/conf/files.i386 index 016060a1f..57bbaba7e 100644 --- a/iokit/conf/files.i386 +++ b/iokit/conf/files.i386 @@ -17,17 +17,3 @@ iokit/Drivers/platform/drvAppleIntelClock/IntelClock.cpp optional iokitcpp # Power Domains iokit/Drivers/platform/drvAppleRootDomain/RootDomain.cpp optional iokitcpp - -# ATA support -iokit/Families/IOATAStandard/IOATAStandardController.cpp optional iokitcpp -iokit/Families/IOATAStandard/IOATAStandardDevice.cpp optional iokitcpp -iokit/Families/IOATAStandard/IOATAStandardCommand.cpp optional iokitcpp -iokit/Families/IOATAStandard/IOATAStandardData.cpp optional iokitcpp -iokit/Families/IOATAStandard/ATAQueueHelpers.cpp optional iokitcpp - -iokit/Families/IOATAStandard/IOATAStandardDriver.cpp optional iokitcpp -iokit/Families/IOATAStandard/IOATAStandardDriverPio.cpp optional iokitcpp -iokit/Families/IOATAStandard/IOATAStandardDriverDma.cpp optional iokitcpp - -# ATA (Intel PIIX IDE) controller driver -iokit/Drivers/ata/drvApplePIIXATA/AppleATAPIIX.cpp optional iokitcpp diff --git a/iokit/conf/files.ppc b/iokit/conf/files.ppc index 67dd7cff1..b2589df0c 100644 --- a/iokit/conf/files.ppc +++ b/iokit/conf/files.ppc @@ -11,17 +11,6 @@ iokit/Families/IOADBBus/IOADBControllerUserClient.cpp optional iokitcpp iokit/Families/IONVRAM/IONVRAMController.cpp optional iokitcpp iokit/Drivers/platform/drvAppleNVRAM/AppleNVRAM.cpp optional iokitcpp -iokit/Drivers/platform/drvAppleCuda/AppleCuda.cpp optional iokitcpp -iokit/Drivers/platform/drvAppleCuda/IOCudaADBController.cpp optional iokitcpp -iokit/Drivers/platform/drvAppleCuda/AppleCudaUserClient.cpp optional iokitcpp - -#iokit/Drivers/platform/drvApplePMU/AppleViaInterface.cpp optional iokitcpp -#iokit/Drivers/platform/drvApplePMU/ApplePMU.cpp optional iokitcpp -#iokit/Drivers/platform/drvApplePMU/ApplePMUUserClient.cpp optional iokitcpp -#iokit/Drivers/platform/drvApplePMU/IOPMURTCController.cpp optional iokitcpp -#iokit/Drivers/platform/drvApplePMU/IOPMUPwrController.cpp optional iokitcpp -#iokit/Drivers/platform/drvApplePMU/IOPMUPowerSource.cpp optional iokitcpp - iokit/Drivers/platform/drvApplePMU/IOPMUADBController.cpp optional iokitcpp # Apple Platform Expert @@ -36,21 +25,3 @@ iokit/Drivers/platform/drvAppleMacIO/AppleMacIO.cpp optional iokitcpp # Apple NMI driver iokit/Drivers/platform/drvAppleNMI/AppleNMI.cpp optional iokitcpp - -# Platform Experts -iokit/Drivers/platform/drvApplePowerSurgePE/PowerSurge.cpp optional disabled-iokitcpp -iokit/Drivers/platform/drvApplePowerStarPE/PowerStar.cpp optional disabled-iokitcpp -iokit/Drivers/platform/drvAppleGossamerPE/Gossamer.cpp optional iokitcpp -iokit/Drivers/platform/drvAppleGossamerPE/GossamerCPU.cpp optional iokitcpp -iokit/Drivers/platform/drvApplePowerExpressPE/PowerExpress.cpp optional iokitcpp - - -# Mac-IO drivers -iokit/Drivers/platform/drvAppleGrandCentral/GrandCentral.cpp optional disabled-iokitcpp -iokit/Drivers/platform/drvAppleOHare/OHare.cpp optional iokitcpp - -# ATA driver -#iokit/Drivers/ata/drvAppleUltra66ATA/AppleUltra66ATA.cpp optional iokitcpp -#iokit/Drivers/ata/drvAppleUltra33ATA/AppleUltra33ATA.cpp optional iokitcpp - - diff --git a/iokit/conf/tools/doconf/doconf.csh b/iokit/conf/tools/doconf/doconf.csh index 43388c11c..ae5ab908b 100755 --- a/iokit/conf/tools/doconf/doconf.csh +++ b/iokit/conf/tools/doconf/doconf.csh @@ -287,7 +287,7 @@ part != 0 {\ # kernel binaries are put). # echo 'builddir "."' >> $SYSCONF.new - set OBJRELDIR=`relpath $OBJROOT $OBJDIR` + set OBJRELDIR=`$RELPATH $OBJROOT $OBJDIR` echo 'objectdir "'$OBJROOT'/'$OBJRELDIR'"' >> $SYSCONF.new set SRCDIR=`dirname $SOURCE` echo 'sourcedir "'$SRCROOT'"' >> $SYSCONF.new diff --git a/iokit/conf/version.major b/iokit/conf/version.major index 7ed6ff82d..1e8b31496 100644 --- a/iokit/conf/version.major +++ b/iokit/conf/version.major @@ -1 +1 @@ -5 +6 diff --git a/iokit/conf/version.minor b/iokit/conf/version.minor index 7ed6ff82d..573541ac9 100644 --- a/iokit/conf/version.minor +++ b/iokit/conf/version.minor @@ -1 +1 @@ -5 +0 diff --git a/iokit/conf/version.variant b/iokit/conf/version.variant index 8b1378917..e69de29bb 100644 --- a/iokit/conf/version.variant +++ b/iokit/conf/version.variant @@ -1 +0,0 @@ - diff --git a/iokit/include/architecture/i386/kernBootStruct.h b/iokit/include/architecture/i386/kernBootStruct.h index 787b62ce2..5afc85d65 100644 --- a/iokit/include/architecture/i386/kernBootStruct.h +++ b/iokit/include/architecture/i386/kernBootStruct.h @@ -19,4 +19,10 @@ * * @APPLE_LICENSE_HEADER_END@ */ +#warning include is going away use instead + +#include + +#ifdef __APPLE_API_OBSOLETE #include +#endif /* __APPLE_API_OBSOLETE */ diff --git a/iokit/include/assert.h b/iokit/include/assert.h index 9ee0085ff..141036a77 100644 --- a/iokit/include/assert.h +++ b/iokit/include/assert.h @@ -21,4 +21,8 @@ */ #warning include is going away use IOKit/assert.h instead +#include + +#ifdef __APPLE_API_OBSOLETE #include +#endif /* __APPLE_API_OBSOLETE */ diff --git a/iokit/include/bsddev/EventShmemLock.h b/iokit/include/bsddev/EventShmemLock.h index 6e7eebdef..4ab305b6c 100644 --- a/iokit/include/bsddev/EventShmemLock.h +++ b/iokit/include/bsddev/EventShmemLock.h @@ -19,4 +19,10 @@ * * @APPLE_LICENSE_HEADER_END@ */ +#warning include is going away use instead + +#include + +#ifdef __APPLE_API_OBSOLETE #include +#endif /* __APPLE_API_OBSOLETE */ diff --git a/iokit/include/bsddev/ev_keymap.h b/iokit/include/bsddev/ev_keymap.h index f2e2b401b..a6f9002a8 100644 --- a/iokit/include/bsddev/ev_keymap.h +++ b/iokit/include/bsddev/ev_keymap.h @@ -19,5 +19,10 @@ * * @APPLE_LICENSE_HEADER_END@ */ -#include +#warning include is going away use instead + +#include +#ifdef __APPLE_API_OBSOLETE +#include +#endif /* __APPLE_API_OBSOLETE */ diff --git a/iokit/include/bsddev/ev_types.h b/iokit/include/bsddev/ev_types.h index fa204d704..91ffc7f01 100644 --- a/iokit/include/bsddev/ev_types.h +++ b/iokit/include/bsddev/ev_types.h @@ -19,5 +19,11 @@ * * @APPLE_LICENSE_HEADER_END@ */ +#warning include is going away use instead + +#include + +#ifdef __APPLE_API_OBSOLETE #include +#endif /* __APPLE_API_OBSOLETE */ diff --git a/iokit/include/bsddev/event.h b/iokit/include/bsddev/event.h index d1a7f61fb..47520fab5 100644 --- a/iokit/include/bsddev/event.h +++ b/iokit/include/bsddev/event.h @@ -19,5 +19,11 @@ * * @APPLE_LICENSE_HEADER_END@ */ +#warning include is going away use instead + +#include + +#ifdef __APPLE_API_OBSOLETE #include +#endif /* __APPLE_API_OBSOLETE */ diff --git a/iokit/include/bsddev/evio.h b/iokit/include/bsddev/evio.h index 5db70f692..e797c040d 100644 --- a/iokit/include/bsddev/evio.h +++ b/iokit/include/bsddev/evio.h @@ -19,5 +19,11 @@ * * @APPLE_LICENSE_HEADER_END@ */ +#warning include is going away use instead + +#include + +#ifdef __APPLE_API_OBSOLETE #include +#endif /* __APPLE_API_OBSOLETE */ diff --git a/iokit/include/bsddev/evsio.h b/iokit/include/bsddev/evsio.h index ebdd5d8cf..e3b799153 100644 --- a/iokit/include/bsddev/evsio.h +++ b/iokit/include/bsddev/evsio.h @@ -19,6 +19,11 @@ * * @APPLE_LICENSE_HEADER_END@ */ +#warning include is going away use instead + +#include + +#ifdef __APPLE_API_OBSOLETE #include /* @@ -27,3 +32,5 @@ #ifndef _NeXT_MACH_EVENT_DRIVER_ #define _NeXT_MACH_EVENT_DRIVER_ (1) #endif /* _NeXT_MACH_EVENT_DRIVER_ */ + +#endif /* __APPLE_API_OBSOLETE */ diff --git a/iokit/include/bsddev/i386/EventShmemLock.h b/iokit/include/bsddev/i386/EventShmemLock.h index 6d6fa7c01..f8d4c1074 100644 --- a/iokit/include/bsddev/i386/EventShmemLock.h +++ b/iokit/include/bsddev/i386/EventShmemLock.h @@ -19,5 +19,11 @@ * * @APPLE_LICENSE_HEADER_END@ */ +#warning include is going away use instead + +#include + +#ifdef __APPLE_API_OBSOLETE #include +#endif /* __APPLE_API_OBSOLETE */ diff --git a/iokit/include/bsddev/i386/event.h b/iokit/include/bsddev/i386/event.h index f40fa9d5f..588b60c12 100644 --- a/iokit/include/bsddev/i386/event.h +++ b/iokit/include/bsddev/i386/event.h @@ -19,5 +19,10 @@ * * @APPLE_LICENSE_HEADER_END@ */ -#include +#warning include is going away use instead + +#include +#ifdef __APPLE_API_OBSOLETE +#include +#endif /* __APPLE_API_OBSOLETE */ diff --git a/iokit/include/bsddev/i386/evio.h b/iokit/include/bsddev/i386/evio.h index 71c52f803..d577d8a9f 100644 --- a/iokit/include/bsddev/i386/evio.h +++ b/iokit/include/bsddev/i386/evio.h @@ -19,5 +19,11 @@ * * @APPLE_LICENSE_HEADER_END@ */ +#warning include is going away use instead + +#include + +#ifdef __APPLE_API_OBSOLETE #include +#endif /* __APPLE_API_OBSOLETE */ diff --git a/iokit/include/bsddev/i386/evsio.h b/iokit/include/bsddev/i386/evsio.h index fffabee74..e70408425 100644 --- a/iokit/include/bsddev/i386/evsio.h +++ b/iokit/include/bsddev/i386/evsio.h @@ -19,5 +19,11 @@ * * @APPLE_LICENSE_HEADER_END@ */ +#warning include is going away use instead + +#include + +#ifdef __APPLE_API_OBSOLETE #include +#endif /* __APPLE_API_OBSOLETE */ diff --git a/iokit/include/bsddev/ppc/EventShmemLock.h b/iokit/include/bsddev/ppc/EventShmemLock.h index 6d6fa7c01..71d5658d3 100644 --- a/iokit/include/bsddev/ppc/EventShmemLock.h +++ b/iokit/include/bsddev/ppc/EventShmemLock.h @@ -19,5 +19,10 @@ * * @APPLE_LICENSE_HEADER_END@ */ -#include +#warning include is going away use instead + +#include +#ifdef __APPLE_API_OBSOLETE +#include +#endif /* __APPLE_API_OBSOLETE */ diff --git a/iokit/include/bsddev/ppc/event.h b/iokit/include/bsddev/ppc/event.h index f40fa9d5f..0abba8c7e 100644 --- a/iokit/include/bsddev/ppc/event.h +++ b/iokit/include/bsddev/ppc/event.h @@ -19,5 +19,11 @@ * * @APPLE_LICENSE_HEADER_END@ */ +#warning include is going away use instead + +#include + +#ifdef __APPLE_API_OBSOLETE #include +#endif /* __APPLE_API_OBSOLETE */ diff --git a/iokit/include/bsddev/ppc/evio.h b/iokit/include/bsddev/ppc/evio.h index 71c52f803..d577d8a9f 100644 --- a/iokit/include/bsddev/ppc/evio.h +++ b/iokit/include/bsddev/ppc/evio.h @@ -19,5 +19,11 @@ * * @APPLE_LICENSE_HEADER_END@ */ +#warning include is going away use instead + +#include + +#ifdef __APPLE_API_OBSOLETE #include +#endif /* __APPLE_API_OBSOLETE */ diff --git a/iokit/include/bsddev/ppc/evsio.h b/iokit/include/bsddev/ppc/evsio.h index fffabee74..e70408425 100644 --- a/iokit/include/bsddev/ppc/evsio.h +++ b/iokit/include/bsddev/ppc/evsio.h @@ -19,5 +19,11 @@ * * @APPLE_LICENSE_HEADER_END@ */ +#warning include is going away use instead + +#include + +#ifdef __APPLE_API_OBSOLETE #include +#endif /* __APPLE_API_OBSOLETE */ diff --git a/iokit/include/mach/mach.h b/iokit/include/mach/mach.h index e5965a497..21fc91eb4 100644 --- a/iokit/include/mach/mach.h +++ b/iokit/include/mach/mach.h @@ -19,3 +19,9 @@ * * @APPLE_LICENSE_HEADER_END@ */ +#warning include is going away, please don't use it anymore. + +#include + +#ifdef __APPLE_API_OBSOLETE +#endif /* __APPLE_API_OBSOLETE */ diff --git a/libkern/c++/OSArray.cpp b/libkern/c++/OSArray.cpp index 3c56bc0d2..fdc847f10 100644 --- a/libkern/c++/OSArray.cpp +++ b/libkern/c++/OSArray.cpp @@ -93,7 +93,7 @@ bool OSArray::initWithObjects(const OSObject *objects[], return false; array[count++] = newObject; - newObject->retain(); + newObject->taggedRetain(OSTypeID(OSCollection)); } return true; @@ -206,7 +206,7 @@ void OSArray::flushCollection() haveUpdated(); for (i = 0; i < count; i++) - array[i]->release(); + array[i]->taggedRelease(OSTypeID(OSCollection)); count = 0; } @@ -233,7 +233,7 @@ bool OSArray::setObject(unsigned int index, const OSMetaClassBase *anObject) array[i] = array[i-1]; } array[index] = anObject; - anObject->retain(); + anObject->taggedRetain(OSTypeID(OSCollection)); count++; return true; @@ -256,7 +256,7 @@ bool OSArray::merge(const OSArray * otherArray) const OSMetaClassBase *newObject = otherArray->getObject(i); array[count++] = newObject; - newObject->retain(); + newObject->taggedRetain(OSTypeID(OSCollection)); } return true; @@ -273,9 +273,9 @@ replaceObject(unsigned int index, const OSMetaClassBase *anObject) haveUpdated(); oldObject = array[index]; array[index] = anObject; - anObject->retain(); + anObject->taggedRetain(OSTypeID(OSCollection)); - oldObject->release(); + oldObject->taggedRelease(OSTypeID(OSCollection)); } void OSArray::removeObject(unsigned int index) @@ -293,7 +293,7 @@ void OSArray::removeObject(unsigned int index) for (i = index; i < count; i++) array[i] = array[i+1]; - oldObject->release(); + oldObject->taggedRelease(OSTypeID(OSCollection)); } bool OSArray::isEqualTo(const OSArray *anArray) const diff --git a/libkern/c++/OSBoolean.cpp b/libkern/c++/OSBoolean.cpp index cd3ba2ef9..42ddc73d2 100644 --- a/libkern/c++/OSBoolean.cpp +++ b/libkern/c++/OSBoolean.cpp @@ -76,15 +76,12 @@ void OSBoolean::free() assert(false); } +void OSBoolean::taggedRetain(const void *tag) const { } +void OSBoolean::taggedRelease(const void *tag, const int when) const { } + OSBoolean *OSBoolean::withBoolean(bool inValue) { - if (inValue) { - kOSBooleanTrue->retain(); - return kOSBooleanTrue; - } else { - kOSBooleanFalse->retain(); - return kOSBooleanFalse; - } + return (inValue) ? kOSBooleanTrue : kOSBooleanFalse; } bool OSBoolean::isTrue() const { return value; } diff --git a/libkern/c++/OSData.cpp b/libkern/c++/OSData.cpp index edfa98243..d4f12fea6 100644 --- a/libkern/c++/OSData.cpp +++ b/libkern/c++/OSData.cpp @@ -21,11 +21,13 @@ */ /* IOData.m created by rsulack on Thu 25-Sep-1997 */ +#include #include #include #include #include +#include #define super OSObject diff --git a/libkern/c++/OSDictionary.cpp b/libkern/c++/OSDictionary.cpp index 04c680f92..b89306f94 100644 --- a/libkern/c++/OSDictionary.cpp +++ b/libkern/c++/OSDictionary.cpp @@ -164,8 +164,8 @@ bool OSDictionary::initWithDictionary(const OSDictionary *dict, count = dict->count; bcopy(dict->dictionary, dictionary, count * sizeof(dictEntry)); for (unsigned int i = 0; i < count; i++) { - dictionary[i].key->retain(); - dictionary[i].value->retain(); + dictionary[i].key->taggedRetain(OSTypeID(OSCollection)); + dictionary[i].value->taggedRetain(OSTypeID(OSCollection)); } return true; @@ -287,8 +287,8 @@ void OSDictionary::flushCollection() haveUpdated(); for (unsigned int i = 0; i < count; i++) { - dictionary[i].key->release(); - dictionary[i].value->release(); + dictionary[i].key->taggedRelease(OSTypeID(OSCollection)); + dictionary[i].value->taggedRelease(OSTypeID(OSCollection)); } count = 0; } @@ -304,12 +304,12 @@ setObject(const OSSymbol *aKey, const OSMetaClassBase *anObject) if (aKey == dictionary[i].key) { const OSMetaClassBase *oldObject = dictionary[i].value; - anObject->retain(); + anObject->taggedRetain(OSTypeID(OSCollection)); dictionary[i].value = anObject; haveUpdated(); - oldObject->release(); + oldObject->taggedRelease(OSTypeID(OSCollection)); return true; } } @@ -318,8 +318,8 @@ setObject(const OSSymbol *aKey, const OSMetaClassBase *anObject) if (count >= capacity && count >= ensureCapacity(count+1)) return 0; - aKey->retain(); - anObject->retain(); + aKey->taggedRetain(OSTypeID(OSCollection)); + anObject->taggedRetain(OSTypeID(OSCollection)); dictionary[count].key = aKey; dictionary[count].value = anObject; count++; @@ -345,30 +345,30 @@ void OSDictionary::removeObject(const OSSymbol *aKey) for (; i < count; i++) dictionary[i] = dictionary[i+1]; - oldEntry.key->release(); - oldEntry.value->release(); + oldEntry.key->taggedRelease(OSTypeID(OSCollection)); + oldEntry.value->taggedRelease(OSTypeID(OSCollection)); return; } } // Returns true on success, false on an error condition. -bool OSDictionary::merge(const OSDictionary *aDictionary) +bool OSDictionary::merge(const OSDictionary *srcDict) { const OSSymbol * sym; OSCollectionIterator * iter; - if ( !OSDynamicCast(OSDictionary, (OSDictionary *) aDictionary) ) + if ( !OSDynamicCast(OSDictionary, srcDict) ) return false; - - iter = OSCollectionIterator::withCollection((OSDictionary *)aDictionary); + + iter = OSCollectionIterator::withCollection((OSDictionary *)srcDict); if ( !iter ) return false; while ( (sym = (const OSSymbol *)iter->getNextObject()) ) { const OSMetaClassBase * obj; - obj = aDictionary->getObject(sym); + obj = srcDict->getObject(sym); if ( !setObject(sym, obj) ) { iter->release(); return false; @@ -435,7 +435,7 @@ void OSDictionary::removeObject(const char *aKey) OBJECT_WRAP_3(removeObject, OSSymbol::withCString(aKey)) bool -OSDictionary::isEqualTo(const OSDictionary *aDictionary, const OSCollection *keys) const +OSDictionary::isEqualTo(const OSDictionary *srcDict, const OSCollection *keys) const { OSCollectionIterator * iter; unsigned int keysCount; @@ -444,11 +444,11 @@ OSDictionary::isEqualTo(const OSDictionary *aDictionary, const OSCollection *key OSString * aKey; bool ret; - if ( this == aDictionary ) + if ( this == srcDict ) return true; keysCount = keys->getCount(); - if ( (count < keysCount) || (aDictionary->getCount() < keysCount) ) + if ( (count < keysCount) || (srcDict->getCount() < keysCount) ) return false; iter = OSCollectionIterator::withCollection(keys); @@ -458,7 +458,7 @@ OSDictionary::isEqualTo(const OSDictionary *aDictionary, const OSCollection *key ret = true; while ( (aKey = OSDynamicCast(OSString, iter->getNextObject())) ) { obj1 = getObject(aKey); - obj2 = aDictionary->getObject(aKey); + obj2 = srcDict->getObject(aKey); if ( !obj1 || !obj2 ) { ret = false; break; @@ -474,19 +474,19 @@ OSDictionary::isEqualTo(const OSDictionary *aDictionary, const OSCollection *key return ret; } -bool OSDictionary::isEqualTo(const OSDictionary *aDictionary) const +bool OSDictionary::isEqualTo(const OSDictionary *srcDict) const { unsigned int i; const OSMetaClassBase * obj; - if ( this == aDictionary ) + if ( this == srcDict ) return true; - if ( count != aDictionary->getCount() ) + if ( count != srcDict->getCount() ) return false; for ( i = 0; i < count; i++ ) { - obj = aDictionary->getObject(dictionary[i].key); + obj = srcDict->getObject(dictionary[i].key); if ( !obj ) return false; diff --git a/libkern/c++/OSMetaClass.cpp b/libkern/c++/OSMetaClass.cpp index 8dbbd30e5..34b5a2d51 100644 --- a/libkern/c++/OSMetaClass.cpp +++ b/libkern/c++/OSMetaClass.cpp @@ -46,6 +46,7 @@ __BEGIN_DECLS #include #include #include +#include #include #include @@ -84,12 +85,16 @@ static unsigned int sConsiderUnloadDelay = 60; /* secs */ static const char OSMetaClassBasePanicMsg[] = "OSMetaClassBase::_RESERVEDOSMetaClassBase%d called\n"; +#if SLOT_USED void OSMetaClassBase::_RESERVEDOSMetaClassBase0() { panic(OSMetaClassBasePanicMsg, 0); } void OSMetaClassBase::_RESERVEDOSMetaClassBase1() { panic(OSMetaClassBasePanicMsg, 1); } void OSMetaClassBase::_RESERVEDOSMetaClassBase2() { panic(OSMetaClassBasePanicMsg, 2); } +#endif /* SLOT_USED */ + +// As these slots are used move them up inside the #if above void OSMetaClassBase::_RESERVEDOSMetaClassBase3() { panic(OSMetaClassBasePanicMsg, 3); } void OSMetaClassBase::_RESERVEDOSMetaClassBase4() @@ -98,6 +103,28 @@ void OSMetaClassBase::_RESERVEDOSMetaClassBase5() { panic(OSMetaClassBasePanicMsg, 5); } void OSMetaClassBase::_RESERVEDOSMetaClassBase6() { panic(OSMetaClassBasePanicMsg, 6); } + +/* + * These used to be inline in the header but gcc didn't believe us + * Now we MUST pull the inline out at least until the compiler is + * repaired. + */ +// Helper inlines for runtime type preprocessor macros +OSMetaClassBase *OSMetaClassBase:: +safeMetaCast(const OSMetaClassBase *me, const OSMetaClass *toType) + { return (me)? me->metaCast(toType) : 0; } + +bool OSMetaClassBase:: +checkTypeInst(const OSMetaClassBase *inst, const OSMetaClassBase *typeinst) +{ + const OSMetaClass *toType = OSTypeIDInst(typeinst); + return typeinst && inst && (0 != inst->metaCast(toType)); +} + + +// If you need this slot you had better setup an IOCTL style interface. +// 'Cause the whole kernel world depends on OSMetaClassBase and YOU +// CANT change the VTABLE size ever. void OSMetaClassBase::_RESERVEDOSMetaClassBase7() { panic(OSMetaClassBasePanicMsg, 7); } @@ -141,7 +168,7 @@ OSMetaClassBase *OSMetaClassBase::metaCast(const OSString *toMetaStr) const OSMetaClassBase *OSMetaClassBase::metaCast(const char *toMetaCStr) const { - const OSSymbol *tempSymb = OSSymbol::withCStringNoCopy(toMetaCStr); + const OSSymbol *tempSymb = OSSymbol::withCString(toMetaCStr); OSMetaClassBase *ret = 0; if (tempSymb) { ret = metaCast(tempSymb); @@ -296,12 +323,13 @@ OSMetaClass::~OSMetaClass() } } -// Don't do anything as these classes must be statically allocated void *OSMetaClass::operator new(size_t size) { return 0; } -void OSMetaClass::operator delete(void *mem, size_t size) { } void OSMetaClass::retain() const { } void OSMetaClass::release() const { } -void OSMetaClass::release(int when) const { }; +void OSMetaClass::release(int when) const { } +void OSMetaClass::taggedRetain(const void *tag) const { } +void OSMetaClass::taggedRelease(const void *tag) const { } +void OSMetaClass::taggedRelease(const void *tag, const int when) const { } int OSMetaClass::getRetainCount() const { return 0; } const char *OSMetaClass::getClassName() const @@ -531,7 +559,7 @@ static void _OSMetaClassConsiderUnloads(thread_call_param_t p0, OSCollectionIterator *kmods; OSCollectionIterator *classes; OSMetaClass *checkClass; - kmod_info_t *ki; + kmod_info_t *ki = 0; kern_return_t ret; bool didUnload; @@ -546,12 +574,18 @@ static void _OSMetaClassConsiderUnloads(thread_call_param_t p0, didUnload = false; while ( (kmodName = (OSSymbol *) kmods->getNextObject()) ) { - ki = kmod_lookupbyname((char *)kmodName->getCStringNoCopy()); + if (ki) { + kfree(ki, sizeof(kmod_info_t)); + ki = 0; + } + + ki = kmod_lookupbyname_locked((char *)kmodName->getCStringNoCopy()); if (!ki) continue; - if (ki->reference_count) - continue; + if (ki->reference_count) { + continue; + } kmodClasses = OSDynamicCast(OSSet, sKModClassesDict->getObject(kmodName)); @@ -570,7 +604,7 @@ static void _OSMetaClassConsiderUnloads(thread_call_param_t p0, didUnload = true; } - } while (false); + } kmods->release(); diff --git a/libkern/c++/OSNumber.cpp b/libkern/c++/OSNumber.cpp index 3a1306a82..5607d1e7e 100644 --- a/libkern/c++/OSNumber.cpp +++ b/libkern/c++/OSNumber.cpp @@ -21,6 +21,12 @@ */ /* IOOffset.m created by rsulack on Wed 17-Sep-1997 */ +#include + +__BEGIN_DECLS +extern int sscanf(const char *input, const char *fmt, ...); +__END_DECLS + #include #include #include @@ -31,6 +37,7 @@ #define super OSObject OSDefineMetaClassAndStructors(OSNumber, OSObject) + OSMetaClassDefineReservedUnused(OSNumber, 0); OSMetaClassDefineReservedUnused(OSNumber, 1); OSMetaClassDefineReservedUnused(OSNumber, 2); diff --git a/libkern/c++/OSObject.cpp b/libkern/c++/OSObject.cpp index 73cf09fd5..4d8122a35 100644 --- a/libkern/c++/OSObject.cpp +++ b/libkern/c++/OSObject.cpp @@ -23,11 +23,12 @@ #include #include -#include #include #include #include +#include + __BEGIN_DECLS int debug_ivars_size; __END_DECLS @@ -91,8 +92,15 @@ OSMetaClassDefineReservedUnused(OSObject, 29); OSMetaClassDefineReservedUnused(OSObject, 30); OSMetaClassDefineReservedUnused(OSObject, 31); +static const char *getClassName(const OSObject *obj) +{ + const OSMetaClass *meta = obj->getMetaClass(); + return (meta) ? meta->getClassName() : "unknown class?"; +} + +bool OSObject::init() + { return true; } -bool OSObject::init() { return true; } void OSObject::free() { const OSMetaClass *meta = getMetaClass(); @@ -104,23 +112,151 @@ void OSObject::free() int OSObject::getRetainCount() const { - return retainCount; + return (int) ((UInt16) retainCount); } -void OSObject::retain() const +void OSObject::taggedRetain(const void *tag) const { - OSIncrementAtomic((SInt32 *) &retainCount); +#if !DEBUG + volatile UInt32 *countP = (volatile UInt32 *) &retainCount; + UInt32 inc = 1; + UInt32 origCount; + UInt32 newCount; + + // Increment the collecion bucket. + if ((const void *) OSTypeID(OSCollection) == tag) + inc |= (1UL<<16); + + do { + origCount = *countP; + if (-1UL == origCount) + // @@@ Pinot: panic("Attempting to retain a freed object"); + return; + + newCount = origCount + inc; + } while (!OSCompareAndSwap(origCount, newCount, (UInt32 *) countP)); +#else + volatile UInt32 *countP = (volatile UInt32 *) &retainCount; + UInt32 inc = 1; + UInt32 origCount; + UInt32 newCount; + + // Increment the collecion bucket. + if ((const void *) OSTypeID(OSCollection) == tag) + inc |= (1UL<<16); + + do { + origCount = *countP; + if (-1UL == origCount) + return; // We are freeing so leave now. + + newCount = origCount + inc; + } while (!OSCompareAndSwap(origCount, newCount, (UInt32 *) countP)); +#endif } -void OSObject::release(int when) const +void OSObject::taggedRelease(const void *tag) const +{ + taggedRelease(tag, 1); +} + +void OSObject::taggedRelease(const void *tag, const int when) const { - if (OSDecrementAtomic((SInt32 *) &retainCount) <= when) +#if !DEBUG + volatile UInt32 *countP = (volatile UInt32 *) &retainCount; + UInt32 dec = 1; + UInt32 origCount; + UInt32 newCount; + UInt32 actualCount; + + // Increment the collecion bucket. + if ((const void *) OSTypeID(OSCollection) == tag) + dec |= (1UL<<16); + + do { + origCount = *countP; + if (-1UL == origCount) + return; // We are freeing already leave now. + + actualCount = origCount - dec; + if ((SInt16) actualCount < when) + newCount = (UInt32) -1; + else + newCount = actualCount; + + } while (!OSCompareAndSwap(origCount, newCount, (UInt32 *) countP)); + + // + // This panic means that we have just attempted to release an object + // who's retain count has gone to less than the number of collections + // it is a member off. Take a panic immediately. + // In Fact the panic MAY not be a registry corruption but it is + // ALWAYS the wrong thing to do. I call it a registry corruption 'cause + // the registry is the biggest single use of a network of collections. + // + if ((UInt16) actualCount < (actualCount >> 16)) + panic("A driver releasing a(n) %s has corrupted the registry\n", + getClassName(this)); + + // Check for a 'free' condition and that if we are first through + if ((UInt32) -1 == newCount) ((OSObject *) this)->free(); +#else + // @@@ Pinot: Need to update the debug build release code. + volatile UInt32 *countP = (volatile UInt32 *) &retainCount; + UInt32 dec = 1; + UInt32 origCount; + UInt32 newCount; + + // Increment the collecion bucket. + if ((const void *) OSTypeID(OSCollection) == tag) + dec |= (1UL<<16); + + do { + origCount = *countP; + if (-1UL == origCount) + return; // We are freeing already leave now. + + newCount = origCount - dec; + } while (!OSCompareAndSwap(origCount, newCount, (UInt32 *) countP)); + + // + // This panic means that we have just attempted to release an object + // who's retain count has gone to less than the number of collections + // it is a member off. Take a panic immediately. + // In Fact the panic MAY not be a registry corruption but it is + // ALWAYS the wrong thing to do. I call it a registry corruption 'cause + // the registry is the biggest single use of a network of collections. + // + if ((UInt16) newCount < (newCount >> 16)) + panic("A driver releasing a(n) %s has corrupted the registry\n", + getClassName(this)); + + // Check for a release too many + if ((SInt16) newCount < 0) + panic("An object has had a release too many\n", + getClassName(this)); + + // Check for a 'free' condition and that if we are first through + if ((SInt16) newCount < when + && OSCompareAndSwap(newCount, -1UL, (UInt32 *) countP)) + ((OSObject *) this)->free(); +#endif } void OSObject::release() const { - release(1); + taggedRelease(0); +} + +void OSObject::retain() const +{ + taggedRetain(0); +} + +void OSObject::release(int when) const +{ + taggedRelease(0, when); } bool OSObject::serialize(OSSerialize *s) const @@ -129,10 +265,7 @@ bool OSObject::serialize(OSSerialize *s) const if (!s->addXMLStartTag(this, "string")) return false; - const OSMetaClass *meta = getMetaClass(); - const char *className = (meta)? meta->getClassName() : "unknown class?"; - - if (!s->addString(className)) return false; + if (!s->addString(getClassName(this))) return false; if (!s->addString(" is not serializable")) return false; return s->addXMLEndTag("string"); diff --git a/libkern/c++/OSOrderedSet.cpp b/libkern/c++/OSOrderedSet.cpp index 1eccf927a..76e1460eb 100644 --- a/libkern/c++/OSOrderedSet.cpp +++ b/libkern/c++/OSOrderedSet.cpp @@ -148,7 +148,7 @@ void OSOrderedSet::flushCollection() haveUpdated(); for (i = 0; i < count; i++) - array[i].obj->release(); + array[i].obj->taggedRelease(OSTypeID(OSCollection)); count = 0; } @@ -176,7 +176,7 @@ bool OSOrderedSet::setObject(unsigned int index, const OSMetaClassBase *anObject } array[index].obj = anObject; // array[index].pri = pri; - anObject->retain(); + anObject->taggedRetain(OSTypeID(OSCollection)); count++; return true; @@ -219,7 +219,7 @@ void OSOrderedSet::removeObject(const OSMetaClassBase *anObject) if( deleted) array[i-1] = array[i]; else if( (array[i].obj == anObject)) { - array[i].obj->release(); + array[i].obj->taggedRelease(OSTypeID(OSCollection)); deleted = true; } } diff --git a/libkern/c++/OSRuntime.cpp b/libkern/c++/OSRuntime.cpp index e5ddca485..7cf2472a0 100644 --- a/libkern/c++/OSRuntime.cpp +++ b/libkern/c++/OSRuntime.cpp @@ -44,13 +44,6 @@ struct mach_header; extern int debug_iomalloc_size; #endif -#define MDECL(reqlen) \ -typedef union { \ - struct _mhead hdr; \ - char _m[(reqlen) + sizeof (struct _mhead)]; \ -} hdr_t; \ -hdr_t - struct _mhead { size_t mlen; char dat[0]; @@ -59,13 +52,13 @@ struct _mhead { void *kern_os_malloc( size_t size) { - MDECL(size) *mem; - size_t memsize = sizeof (*mem); + struct _mhead *mem; + size_t memsize = sizeof (*mem) + size ; if (size == 0) return (0); - mem = (hdr_t *)kalloc(memsize); + mem = (struct _mhead *)kalloc(memsize); if (!mem) return (0); @@ -73,10 +66,10 @@ void *kern_os_malloc( debug_iomalloc_size += memsize; #endif - mem->hdr.mlen = memsize; - (void) memset(mem->hdr.dat, 0, size); + mem->mlen = memsize; + (void) memset(mem->dat, 0, size); - return (mem->hdr.dat); + return (mem->dat); } void kern_os_free( @@ -105,7 +98,7 @@ void *kern_os_realloc( size_t nsize) { struct _mhead *ohdr; - MDECL(nsize) *nmem; + struct _mhead *nmem; size_t nmemsize, osize; if (!addr) @@ -121,8 +114,8 @@ void *kern_os_realloc( return (0); } - nmemsize = sizeof (*nmem); - nmem = (hdr_t *) kalloc(nmemsize); + nmemsize = sizeof (*nmem) + nsize ; + nmem = (struct _mhead *) kalloc(nmemsize); if (!nmem){ kern_os_free(addr); return (0); @@ -132,14 +125,14 @@ void *kern_os_realloc( debug_iomalloc_size += (nmemsize - ohdr->mlen); #endif - nmem->hdr.mlen = nmemsize; + nmem->mlen = nmemsize; if (nsize > osize) - (void) memset(&nmem->hdr.dat[osize], 0, nsize - osize); - (void) memcpy(nmem->hdr.dat, ohdr->dat, + (void) memset(&nmem->dat[osize], 0, nsize - osize); + (void) memcpy(nmem->dat, ohdr->dat, (nsize > osize) ? osize : nsize); kfree((vm_offset_t)ohdr, ohdr->mlen); - return (nmem->hdr.dat); + return (nmem->dat); } size_t kern_os_malloc_size( @@ -154,7 +147,11 @@ size_t kern_os_malloc_size( return( hdr->mlen - sizeof (struct _mhead)); } +#if __GNUC__ >= 3 +void __cxa_pure_virtual( void ) { panic(__FUNCTION__); } +#else void __pure_virtual( void ) { panic(__FUNCTION__); } +#endif typedef void (*structor_t)(void); diff --git a/libkern/c++/OSRuntimeSupport.c b/libkern/c++/OSRuntimeSupport.c new file mode 100644 index 000000000..77bcc2bc4 --- /dev/null +++ b/libkern/c++/OSRuntimeSupport.c @@ -0,0 +1,8 @@ +// These functions have been moved inline but we need to continue +// exporting the mangled functions for loadable drivers compiled on older +// systems. +// Note that I have had to manually mangle the symbols names. +#if __GNUC__ >= 3 + void _ZN11OSMetaClassdlEPvm(void *mem, unsigned long size) { } +#endif + diff --git a/libkern/c++/OSSerialize.cpp b/libkern/c++/OSSerialize.cpp index cfaec1b9c..b84656c48 100644 --- a/libkern/c++/OSSerialize.cpp +++ b/libkern/c++/OSSerialize.cpp @@ -21,6 +21,12 @@ */ /* OSSerialize.cpp created by rsulack on Wen 25-Nov-1998 */ +#include + +__BEGIN_DECLS +#include +__END_DECLS + #include #include #include @@ -142,13 +148,14 @@ bool OSSerialize::initWithCapacity(unsigned int inCapacity) tag = 0; length = 1; - capacity = inCapacity; - capacityIncrement = (capacity)? capacity : 256; - - capacity = (((capacity - 1) / capacityIncrement) + 1) - * capacityIncrement; - data = (char *) kalloc(capacity); - if (!data) { + capacity = (inCapacity) ? round_page(inCapacity) : round_page(1); + capacityIncrement = capacity; + + // allocate from the kernel map so that we can safely map this data + // into user space (the primary use of the OSSerialize object) + + kern_return_t rc = kmem_alloc(kernel_map, (vm_offset_t *)&data, capacity); + if (rc) { tags->release(); tags = 0; return false; @@ -185,25 +192,31 @@ unsigned int OSSerialize::setCapacityIncrement(unsigned int increment) unsigned int OSSerialize::ensureCapacity(unsigned int newCapacity) { char *newData; - unsigned int oldCapacity; if (newCapacity <= capacity) return capacity; // round up - newCapacity = (((newCapacity - 1) / capacityIncrement) + 1) - * capacityIncrement; - newData = (char *) kalloc(newCapacity); - if (newData) { - oldCapacity = capacity; - - ACCUMSIZE(newCapacity - oldCapacity); - - bcopy(data, newData, oldCapacity); - bzero(&newData[capacity], newCapacity - oldCapacity); - kfree((vm_offset_t)data, oldCapacity); - data = newData; - capacity = newCapacity; + newCapacity = round_page(newCapacity); + + kern_return_t rc = kmem_realloc(kernel_map, + (vm_offset_t)data, + capacity, + (vm_offset_t *)&newData, + newCapacity); + if (!rc) { + ACCUMSIZE(newCapacity); + + // kmem realloc does not free the old address range + kmem_free(kernel_map, (vm_offset_t)data, capacity); + ACCUMSIZE(-capacity); + + // kmem realloc does not zero out the new memory + // and this could end up going to user land + bzero(&newData[capacity], newCapacity - capacity); + + data = newData; + capacity = newCapacity; } return capacity; @@ -215,7 +228,7 @@ void OSSerialize::free() tags->release(); if (data) { - kfree((vm_offset_t)data, capacity); + kmem_free(kernel_map, (vm_offset_t)data, capacity); ACCUMSIZE( -capacity ); } super::free(); diff --git a/libkern/c++/OSString.cpp b/libkern/c++/OSString.cpp index 4ad5133c2..77d46d78c 100644 --- a/libkern/c++/OSString.cpp +++ b/libkern/c++/OSString.cpp @@ -22,11 +22,13 @@ /* IOString.m created by rsulack on Wed 17-Sep-1997 */ /* IOString.cpp converted to C++ on Tue 1998-9-22 */ +#include #include #include #include #include +#include #define super OSObject diff --git a/libkern/c++/OSSymbol.cpp b/libkern/c++/OSSymbol.cpp index df7465901..daff36bc8 100644 --- a/libkern/c++/OSSymbol.cpp +++ b/libkern/c++/OSSymbol.cpp @@ -21,6 +21,7 @@ */ /* IOSymbol.cpp created by gvdl on Fri 1998-11-17 */ +#include #include __BEGIN_DECLS @@ -29,6 +30,7 @@ __END_DECLS #include #include +#include #define super OSString @@ -91,9 +93,9 @@ public: inline void closeGate() { mutex_lock(poolGate); }; inline void openGate() { mutex_unlock(poolGate); }; - OSSymbol *findSymbol(const char *cString) const; + OSSymbol *findSymbol(const char *cString, OSSymbol ***replace) const; OSSymbol *insertSymbol(OSSymbol *sym); - void removeSymbol(const char *cString); + void removeSymbol(OSSymbol *sym); OSSymbolPoolState initHashState(); OSSymbol *nextHashState(OSSymbolPoolState *stateP); @@ -208,7 +210,7 @@ void OSSymbolPool::reconstructSymbols() insertSymbol(insert); } -OSSymbol *OSSymbolPool::findSymbol(const char *cString) const +OSSymbol *OSSymbolPool::findSymbol(const char *cString, OSSymbol ***replace) const { Bucket *thisBucket; unsigned int j, inLen, hash; @@ -218,6 +220,8 @@ OSSymbol *OSSymbolPool::findSymbol(const char *cString) const thisBucket = &buckets[hash % nBuckets]; j = thisBucket->count; + *replace = NULL; + if (!j) return 0; @@ -225,19 +229,28 @@ OSSymbol *OSSymbolPool::findSymbol(const char *cString) const probeSymbol = (OSSymbol *) thisBucket->symbolP; if (inLen == probeSymbol->length - && (strcmp(probeSymbol->string, cString) == 0) - && (probeSymbol->getRetainCount() >= 1)) // WRONG need when - return probeSymbol; - else - return 0; + && (strcmp(probeSymbol->string, cString) == 0)) { + probeSymbol->retain(); + if (probeSymbol->getRetainCount() != 0xffff) + return probeSymbol; + else + // replace this one + *replace = (OSSymbol **) &thisBucket->symbolP; + } + return 0; } for (list = thisBucket->symbolP; j--; list++) { probeSymbol = *list; if (inLen == probeSymbol->length - && (strcmp(probeSymbol->string, cString) == 0) - && (probeSymbol->getRetainCount() >= 1)) // WRONG need when - return probeSymbol; + && (strcmp(probeSymbol->string, cString) == 0)) { + probeSymbol->retain(); + if (probeSymbol->getRetainCount() != 0xffff) + return probeSymbol; + else + // replace this one + *replace = list; + } } return 0; @@ -305,13 +318,13 @@ OSSymbol *OSSymbolPool::insertSymbol(OSSymbol *sym) return 0; } -void OSSymbolPool::removeSymbol(const char *cString) +void OSSymbolPool::removeSymbol(OSSymbol *sym) { Bucket *thisBucket; unsigned int j, inLen, hash; OSSymbol *probeSymbol, **list; - hashSymbol(cString, &hash, &inLen); inLen++; + hashSymbol(sym->string, &hash, &inLen); inLen++; thisBucket = &buckets[hash % nBuckets]; j = thisBucket->count; list = thisBucket->symbolP; @@ -322,8 +335,7 @@ void OSSymbolPool::removeSymbol(const char *cString) if (j == 1) { probeSymbol = (OSSymbol *) list; - if (inLen == probeSymbol->length - && strcmp(probeSymbol->string, cString) == 0) { + if (probeSymbol == sym) { thisBucket->symbolP = 0; count--; thisBucket->count--; @@ -334,8 +346,7 @@ void OSSymbolPool::removeSymbol(const char *cString) if (j == 2) { probeSymbol = list[0]; - if (inLen == probeSymbol->length - && strcmp(probeSymbol->string, cString) == 0) { + if (probeSymbol == sym) { thisBucket->symbolP = (OSSymbol **) list[1]; kfree((vm_offset_t)list, 2 * sizeof(OSSymbol *)); ACCUMSIZE(-(2 * sizeof(OSSymbol *))); @@ -345,8 +356,7 @@ void OSSymbolPool::removeSymbol(const char *cString) } probeSymbol = list[1]; - if (inLen == probeSymbol->length - && strcmp(probeSymbol->string, cString) == 0) { + if (probeSymbol == sym) { thisBucket->symbolP = (OSSymbol **) list[0]; kfree((vm_offset_t)list, 2 * sizeof(OSSymbol *)); ACCUMSIZE(-(2 * sizeof(OSSymbol *))); @@ -359,8 +369,7 @@ void OSSymbolPool::removeSymbol(const char *cString) for (; j--; list++) { probeSymbol = *list; - if (inLen == probeSymbol->length - && strcmp(probeSymbol->string, cString) == 0) { + if (probeSymbol == sym) { list = (OSSymbol **) kalloc((thisBucket->count-1) * sizeof(OSSymbol *)); @@ -430,16 +439,19 @@ const OSSymbol *OSSymbol::withString(const OSString *aString) const OSSymbol *OSSymbol::withCString(const char *cString) { + OSSymbol **replace; + pool->closeGate(); - OSSymbol *newSymb = pool->findSymbol(cString); - if (newSymb) - newSymb->retain(); - else if ( (newSymb = new OSSymbol) ) { - if (newSymb->OSString::initWithCString(cString)) - pool->insertSymbol(newSymb); - else { - newSymb->free(); + OSSymbol *newSymb = pool->findSymbol(cString, &replace); + if (!newSymb && (newSymb = new OSSymbol) ) { + if (newSymb->OSString::initWithCString(cString)) { + if (replace) + *replace = newSymb; + else + pool->insertSymbol(newSymb); + } else { + newSymb->OSString::free(); newSymb = 0; } } @@ -450,16 +462,19 @@ const OSSymbol *OSSymbol::withCString(const char *cString) const OSSymbol *OSSymbol::withCStringNoCopy(const char *cString) { + OSSymbol **replace; + pool->closeGate(); - OSSymbol *newSymb = pool->findSymbol(cString); - if (newSymb) - newSymb->retain(); - else if ( (newSymb = new OSSymbol) ) { - if (newSymb->OSString::initWithCStringNoCopy(cString)) - pool->insertSymbol(newSymb); - else { - newSymb->free(); + OSSymbol *newSymb = pool->findSymbol(cString, &replace); + if (!newSymb && (newSymb = new OSSymbol) ) { + if (newSymb->OSString::initWithCStringNoCopy(cString)) { + if (replace) + *replace = newSymb; + else + pool->insertSymbol(newSymb); + } else { + newSymb->OSString::free(); newSymb = 0; } } @@ -491,7 +506,7 @@ void OSSymbol::checkForPageUnload(void *startAddr, void *endAddr) void OSSymbol::free() { pool->closeGate(); - pool->removeSymbol(string); + pool->removeSymbol(this); pool->openGate(); super::free(); diff --git a/libkern/c++/OSUnserialize.cpp b/libkern/c++/OSUnserialize.cpp index 78001bdbe..bec931246 100644 --- a/libkern/c++/OSUnserialize.cpp +++ b/libkern/c++/OSUnserialize.cpp @@ -124,7 +124,6 @@ extern void kern_os_free(void * addr); #ifndef YYSTYPE #define YYSTYPE int #endif -#include #ifndef __cplusplus #ifndef __STDC__ diff --git a/libkern/c++/OSUnserializeXML.cpp b/libkern/c++/OSUnserializeXML.cpp index f169f7720..3a5742ee1 100644 --- a/libkern/c++/OSUnserializeXML.cpp +++ b/libkern/c++/OSUnserializeXML.cpp @@ -134,7 +134,6 @@ extern unsigned long strtoul(const char *, char **, int); #ifndef YYSTYPE #define YYSTYPE int #endif -#include #ifndef __cplusplus #ifndef __STDC__ diff --git a/libkern/conf/Makefile b/libkern/conf/Makefile index 85e1a341a..ffeab35e7 100644 --- a/libkern/conf/Makefile +++ b/libkern/conf/Makefile @@ -47,14 +47,13 @@ do_setup_conf: $(OBJROOT)/$(KERNEL_CONFIG)_$(ARCH_CONFIG)/$(COMPONENT)/doconf \ do_all: do_setup_conf @echo "[ $(SOURCE) ] Starting do_all $(COMPONENT) $(LIBKERN_KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)"; \ - (cd $(COMPOBJROOT)/$(LIBKERN_KERNEL_CONFIG); \ next_source=$(subst conf/,,$(SOURCE)); \ - ${MAKE} MAKEFILES=$(TARGET)/$(LIBKERN_KERNEL_CONFIG)/Makefile \ + ${MAKE} -C $(COMPOBJROOT)/$(LIBKERN_KERNEL_CONFIG) \ + MAKEFILES=$(TARGET)/$(LIBKERN_KERNEL_CONFIG)/Makefile \ SOURCE=$${next_source} \ TARGET=$(TARGET) \ INCL_MAKEDEP=FALSE \ - build_all \ - ); \ + build_all; \ echo "[ $(SOURCE) ] Returning do_all $(COMPONENT) $(LIBKERN_KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)"; do_build_all: do_all diff --git a/libkern/conf/files b/libkern/conf/files index 2bc05b4eb..c65902fad 100644 --- a/libkern/conf/files +++ b/libkern/conf/files @@ -20,6 +20,7 @@ libkern/c++/OSIterator.cpp optional libkerncpp libkern/c++/OSNumber.cpp optional libkerncpp libkern/c++/OSOrderedSet.cpp optional libkerncpp libkern/c++/OSRuntime.cpp optional libkerncpp +libkern/c++/OSRuntimeSupport.c optional libkerncpp libkern/c++/OSSerialize.cpp optional libkerncpp libkern/c++/OSSet.cpp optional libkerncpp libkern/c++/OSString.cpp optional libkerncpp diff --git a/libkern/conf/tools/doconf/doconf.csh b/libkern/conf/tools/doconf/doconf.csh index 43388c11c..ae5ab908b 100755 --- a/libkern/conf/tools/doconf/doconf.csh +++ b/libkern/conf/tools/doconf/doconf.csh @@ -287,7 +287,7 @@ part != 0 {\ # kernel binaries are put). # echo 'builddir "."' >> $SYSCONF.new - set OBJRELDIR=`relpath $OBJROOT $OBJDIR` + set OBJRELDIR=`$RELPATH $OBJROOT $OBJDIR` echo 'objectdir "'$OBJROOT'/'$OBJRELDIR'"' >> $SYSCONF.new set SRCDIR=`dirname $SOURCE` echo 'sourcedir "'$SRCROOT'"' >> $SYSCONF.new diff --git a/libkern/conf/version.major b/libkern/conf/version.major index 7ed6ff82d..1e8b31496 100644 --- a/libkern/conf/version.major +++ b/libkern/conf/version.major @@ -1 +1 @@ -5 +6 diff --git a/libkern/conf/version.minor b/libkern/conf/version.minor index 7ed6ff82d..573541ac9 100644 --- a/libkern/conf/version.minor +++ b/libkern/conf/version.minor @@ -1 +1 @@ -5 +0 diff --git a/libkern/conf/version.variant b/libkern/conf/version.variant index 8b1378917..e69de29bb 100644 --- a/libkern/conf/version.variant +++ b/libkern/conf/version.variant @@ -1 +0,0 @@ - diff --git a/libkern/libkern/Makefile b/libkern/libkern/Makefile index f79a7813c..bd2b5547d 100644 --- a/libkern/libkern/Makefile +++ b/libkern/libkern/Makefile @@ -28,7 +28,7 @@ DATAFILES = \ OSReturn.h \ OSTypes.h -INSTALL_MI_LIST = OSReturn.h OSTypes.h +INSTALL_MI_LIST = OSByteOrder.h OSReturn.h OSTypes.h INSTALL_MI_DIR = libkern diff --git a/libkern/libkern/OSAtomic.h b/libkern/libkern/OSAtomic.h index cb0338156..300bac7df 100644 --- a/libkern/libkern/OSAtomic.h +++ b/libkern/libkern/OSAtomic.h @@ -38,6 +38,8 @@ extern "C" { /*! @function OSCompareAndSwap @abstract Compare and swap operation, performed atomically with respect to all devices that participate in the coherency architecture of the platform. @discussion The OSCompareAndSwap function compares the value at the specified address with oldVal. The value of newValue is written to the address only if oldValue and the value at the address are equal. OSCompareAndSwap returns true if newValue is written to the address; otherwise, it returns false. + + This function guarantees atomicity only with main system memory. It is specifically unsuitable for use on noncacheable memory such as that in devices; this function cannot guarantee atomicity, for example, on memory mapped from a PCI device. @param oldValue The value to compare at address. @param newValue The value to write to address if oldValue compares true. @param address The 4-byte aligned address of the data to update atomically. @@ -48,33 +50,41 @@ extern Boolean OSCompareAndSwap( UInt32 oldValue, UInt32 newValue, UInt32 * addr /*! @function OSAddAtomic @abstract 32-bit add operation, performed atomically with respect to all devices that participate in the coherency architecture of the platform. @discussion The OSAddAtomic function adds the specified amount to the value at the specified address and returns the result. + + This function guarantees atomicity only with main system memory. It is specifically unsuitable for use on noncacheable memory such as that in devices; this function cannot guarantee atomicity, for example, on memory mapped from a PCI device. @param amount The amount to add. @param address The 4-byte aligned address of the value to update atomically. - @result The result of the addition. */ + @result The value before the addition */ extern SInt32 OSAddAtomic(SInt32 amount, SInt32 * address); /*! @function OSAddAtomic16 @abstract 16-bit add operation, performed atomically with respect to all devices that participate in the coherency architecture of the platform. @discussion The OSAddAtomic16 function adds the specified amount to the value at the specified address and returns the result. + + This function guarantees atomicity only with main system memory. It is specifically unsuitable for use on noncacheable memory such as that in devices; this function cannot guarantee atomicity, for example, on memory mapped from a PCI device. @param amount The amount to add. @param address The 2-byte aligned address of the value to update atomically. - @result The result of the addition. */ + @result The value before the addition */ extern SInt16 OSAddAtomic16(SInt32 amount, SInt16 * address); /*! @function OSAddAtomic8 @abstract 8-bit add operation, performed atomically with respect to all devices that participate in the coherency architecture of the platform. @discussion The OSAddAtomic8 function adds the specified amount to the value at the specified address and returns the result. + + This function guarantees atomicity only with main system memory. It is specifically unsuitable for use on noncacheable memory such as that in devices; this function cannot guarantee atomicity, for example, on memory mapped from a PCI device. @param amount The amount to add. @param address The address of the value to update atomically. - @result The result of the addition. */ + @result The value before the addition */ extern SInt8 OSAddAtomic8(SInt32 amount, SInt8 * address); /*! @function OSIncrementAtomic @abstract 32-bit increment operation, performed atomically with respect to all devices that participate in the coherency architecture of the platform. @discussion The OSIncrementAtomic function increments the value at the specified address by one and returns the value as it was before the change. + + This function guarantees atomicity only with main system memory. It is specifically unsuitable for use on noncacheable memory such as that in devices; this function cannot guarantee atomicity, for example, on memory mapped from a PCI device. @param address The 4-byte aligned address of the value to update atomically. @result The value before the increment. */ @@ -83,6 +93,8 @@ extern SInt32 OSIncrementAtomic(SInt32 * address); /*! @function OSIncrementAtomic16 @abstract 16-bit increment operation, performed atomically with respect to all devices that participate in the coherency architecture of the platform. @discussion The OSIncrementAtomic16 function increments the value at the specified address by one and returns the value as it was before the change. + + This function guarantees atomicity only with main system memory. It is specifically unsuitable for use on noncacheable memory such as that in devices; this function cannot guarantee atomicity, for example, on memory mapped from a PCI device. @param address The 2-byte aligned address of the value to update atomically. @result The value before the increment. */ @@ -91,6 +103,8 @@ extern SInt16 OSIncrementAtomic16(SInt16 * address); /*! @function OSIncrementAtomic8 @abstract 8-bit increment operation, performed atomically with respect to all devices that participate in the coherency architecture of the platform. @discussion The OSIncrementAtomic8 function increments the value at the specified address by one and returns the value as it was before the change. + + This function guarantees atomicity only with main system memory. It is specifically unsuitable for use on noncacheable memory such as that in devices; this function cannot guarantee atomicity, for example, on memory mapped from a PCI device. @param address The address of the value to update atomically. @result The value before the increment. */ @@ -99,6 +113,8 @@ extern SInt8 OSIncrementAtomic8(SInt8 * address); /*! @function OSDecrementAtomic @abstract 32-bit decrement operation, performed atomically with respect to all devices that participate in the coherency architecture of the platform. @discussion The OSDecrementAtomic function decrements the value at the specified address by one and returns the value as it was before the change. + + This function guarantees atomicity only with main system memory. It is specifically unsuitable for use on noncacheable memory such as that in devices; this function cannot guarantee atomicity, for example, on memory mapped from a PCI device. @param address The 4-byte aligned address of the value to update atomically. @result The value before the decrement. */ @@ -107,6 +123,8 @@ extern SInt32 OSDecrementAtomic(SInt32 * address); /*! @function OSDecrementAtomic16 @abstract 16-bit decrement operation, performed atomically with respect to all devices that participate in the coherency architecture of the platform. @discussion The OSDecrementAtomic16 function decrements the value at the specified address by one and returns the value as it was before the change. + + This function guarantees atomicity only with main system memory. It is specifically unsuitable for use on noncacheable memory such as that in devices; this function cannot guarantee atomicity, for example, on memory mapped from a PCI device. @param address The 2-byte aligned address of the value to update atomically. @result The value before the decrement. */ @@ -115,6 +133,8 @@ extern SInt16 OSDecrementAtomic16(SInt16 * address); /*! @function OSDecrementAtomic8 @abstract 8-bit decrement operation, performed atomically with respect to all devices that participate in the coherency architecture of the platform. @discussion The OSDecrementAtomic8 function decrements the value at the specified address by one and returns the value as it was before the change. + + This function guarantees atomicity only with main system memory. It is specifically unsuitable for use on noncacheable memory such as that in devices; this function cannot guarantee atomicity, for example, on memory mapped from a PCI device. @param address The address of the value to update atomically. @result The value before the decrement. */ @@ -123,86 +143,106 @@ extern SInt8 OSDecrementAtomic8(SInt8 * address); /*! @function OSBitAndAtomic @abstract 32-bit logical and operation, performed atomically with respect to all devices that participate in the coherency architecture of the platform. @discussion The OSBitAndAtomic function logically ands the bits of the specified mask into the value at the specified address and returns the result. + + This function guarantees atomicity only with main system memory. It is specifically unsuitable for use on noncacheable memory such as that in devices; this function cannot guarantee atomicity, for example, on memory mapped from a PCI device. @param mask The mask to logically and with the value. @param address The 4-byte aligned address of the value to update atomically. - @result The result of the logical and. */ + @result The value before the bitwise operation */ extern UInt32 OSBitAndAtomic(UInt32 mask, UInt32 * address); /*! @function OSBitAndAtomic16 @abstract 16-bit logical and operation, performed atomically with respect to all devices that participate in the coherency architecture of the platform. @discussion The OSBitAndAtomic16 function logically ands the bits of the specified mask into the value at the specified address and returns the result. + + This function guarantees atomicity only with main system memory. It is specifically unsuitable for use on noncacheable memory such as that in devices; this function cannot guarantee atomicity, for example, on memory mapped from a PCI device. @param mask The mask to logically and with the value. @param address The 2-byte aligned address of the value to update atomically. - @result The result of the logical and. */ + @result The value before the bitwise operation. */ extern UInt16 OSBitAndAtomic16(UInt32 mask, UInt16 * address); /*! @function OSBitAndAtomic8 @abstract 8-bit logical and operation, performed atomically with respect to all devices that participate in the coherency architecture of the platform. @discussion The OSBitAndAtomic8 function logically ands the bits of the specified mask into the value at the specified address and returns the result. + + This function guarantees atomicity only with main system memory. It is specifically unsuitable for use on noncacheable memory such as that in devices; this function cannot guarantee atomicity, for example, on memory mapped from a PCI device. @param mask The mask to logically and with the value. @param address The address of the value to update atomically. - @result The result of the logical and. */ + @result The value before the bitwise operation. */ extern UInt8 OSBitAndAtomic8(UInt32 mask, UInt8 * address); /*! @function OSBitOrAtomic @abstract 32-bit logical or operation, performed atomically with respect to all devices that participate in the coherency architecture of the platform. @discussion The OSBitOrAtomic function logically ors the bits of the specified mask into the value at the specified address and returns the result. + + This function guarantees atomicity only with main system memory. It is specifically unsuitable for use on noncacheable memory such as that in devices; this function cannot guarantee atomicity, for example, on memory mapped from a PCI device. @param mask The mask to logically or with the value. @param address The 4-byte aligned address of the value to update atomically. - @result The result of the logical or. */ + @result The value before the bitwise operation. */ extern UInt32 OSBitOrAtomic(UInt32 mask, UInt32 * address); /*! @function OSBitOrAtomic16 @abstract 16-bit logical or operation, performed atomically with respect to all devices that participate in the coherency architecture of the platform. @discussion The OSBitOrAtomic16 function logically ors the bits of the specified mask into the value at the specified address and returns the result. + + This function guarantees atomicity only with main system memory. It is specifically unsuitable for use on noncacheable memory such as that in devices; this function cannot guarantee atomicity, for example, on memory mapped from a PCI device. @param mask The mask to logically or with the value. @param address The 2-byte aligned address of the value to update atomically. - @result The result of the logical or. */ + @result The value before the bitwise operation. */ extern UInt16 OSBitOrAtomic16(UInt32 mask, UInt16 * address); /*! @function OSBitOrAtomic8 @abstract 8-bit logical or operation, performed atomically with respect to all devices that participate in the coherency architecture of the platform. + + This function guarantees atomicity only with main system memory. It is specifically unsuitable for use on noncacheable memory such as that in devices; this function cannot guarantee atomicity, for example, on memory mapped from a PCI device. @discussion The OSBitOrAtomic8 function logically ors the bits of the specified mask into the value at the specified address and returns the result. @param mask The mask to logically or with the value. @param address The address of the value to update atomically. - @result The result of the logical or. */ + @result The value before the bitwise operation. */ extern UInt8 OSBitOrAtomic8(UInt32 mask, UInt8 * address); /*! @function OSBitXorAtomic @abstract 32-bit logical xor operation, performed atomically with respect to all devices that participate in the coherency architecture of the platform. + + This function guarantees atomicity only with main system memory. It is specifically unsuitable for use on noncacheable memory such as that in devices; this function cannot guarantee atomicity, for example, on memory mapped from a PCI device. @discussion The OSBitXorAtomic function logically xors the bits of the specified mask into the value at the specified address and returns the result. @param mask The mask to logically or with the value. @param address The 4-byte aligned address of the value to update atomically. - @result The result of the logical xor. */ + @result The value before the bitwise operation. */ extern UInt32 OSBitXorAtomic(UInt32 mask, UInt32 * address); /*! @function OSBitXorAtomic16 @abstract 16-bit logical xor operation, performed atomically with respect to all devices that participate in the coherency architecture of the platform. @discussion The OSBitXorAtomic16 function logically xors the bits of the specified mask into the value at the specified address and returns the result. + + This function guarantees atomicity only with main system memory. It is specifically unsuitable for use on noncacheable memory such as that in devices; this function cannot guarantee atomicity, for example, on memory mapped from a PCI device. @param mask The mask to logically or with the value. @param address The 2-byte aligned address of the value to update atomically. - @result The result of the logical xor. */ + @result The value before the bitwise operation. */ extern UInt16 OSBitXorAtomic16(UInt32 mask, UInt16 * address); /*! @function OSBitXorAtomic8 @abstract 8-bit logical xor operation, performed atomically with respect to all devices that participate in the coherency architecture of the platform. + + This function guarantees atomicity only with main system memory. It is specifically unsuitable for use on noncacheable memory such as that in devices; this function cannot guarantee atomicity, for example, on memory mapped from a PCI device. @discussion The OSBitXorAtomic8 function logically xors the bits of the specified mask into the value at the specified address and returns the result. @param mask The mask to logically or with the value. @param address The address of the value to update atomically. - @result The result of the logical xor. */ + @result The value before the bitwise operation. */ extern UInt8 OSBitXorAtomic8(UInt32 mask, UInt8 * address); /*! @function OSTestAndSet @abstract Bit test and set operation, performed atomically with respect to all devices that participate in the coherency architecture of the platform. + + This function guarantees atomicity only with main system memory. It is specifically unsuitable for use on noncacheable memory such as that in devices; this function cannot guarantee atomicity, for example, on memory mapped from a PCI device. @discussion The OSTestAndSet function sets a single bit in a byte at a specified address. It returns true if the bit was already set, false otherwise. @param bit The bit number in the range 0 through 7. @param address The address of the byte to update atomically. @@ -213,6 +253,8 @@ extern Boolean OSTestAndSet(UInt32 bit, UInt8 * startAddress); /*! @function OSTestAndClear @abstract Bit test and clear operation, performed atomically with respect to all devices that participate in the coherency architecture of the platform. @discussion The OSTestAndClear function clears a single bit in a byte at a specified address. It returns true if the bit was already clear, false otherwise. + + This function guarantees atomicity only with main system memory. It is specifically unsuitable for use on noncacheable memory such as that in devices; this function cannot guarantee atomicity, for example, on memory mapped from a PCI device. @param bit The bit number in the range 0 through 7. @param address The address of the byte to update atomically. @result true if the bit was already clear, false otherwise. */ @@ -222,6 +264,8 @@ extern Boolean OSTestAndClear(UInt32 bit, UInt8 * startAddress); /*! @function OSEnqueueAtomic @abstract Singly linked list head insertion, performed atomically with respect to all devices that participate in the coherency architecture of the platform. @discussion The OSEnqueueAtomic function places an element at the head of a single linked list, which is specified with the address of a head pointer, listHead. The element structure has a next field whose offset is specified. + + This function guarantees atomicity only with main system memory. It is specifically unsuitable for use on noncacheable memory such as that in devices; this function cannot guarantee atomicity, for example, on memory mapped from a PCI device. @param listHead The address of a head pointer for the list . @param element The list element to insert at the head of the list. @param elementNextFieldOffset The byte offset into the element where a pointer to the next element in the list is stored. */ @@ -232,6 +276,8 @@ extern void OSEnqueueAtomic(void ** listHead, void * element, /*! @function OSDequeueAtomic @abstract Singly linked list element head removal, performed atomically with respect to all devices that participate in the coherency architecture of the platform. @discussion The OSDequeueAtomic function removes an element from the head of a single linked list, which is specified with the address of a head pointer, listHead. The element structure has a next field whose offset is specified. + + This function guarantees atomicity only with main system memory. It is specifically unsuitable for use on noncacheable memory such as that in devices; this function cannot guarantee atomicity, for example, on memory mapped from a PCI device. @param listHead The address of a head pointer for the list . @param elementNextFieldOffset The byte offset into the element where a pointer to the next element in the list is stored. @result A removed element, or zero if the list is empty. */ diff --git a/libkern/libkern/OSBase.h b/libkern/libkern/OSBase.h index 2883836e9..0938bc7bc 100644 --- a/libkern/libkern/OSBase.h +++ b/libkern/libkern/OSBase.h @@ -33,14 +33,6 @@ #include -#if !defined(OS_INLINE) - #if defined(__GNUC__) - #define OS_INLINE static __inline__ - #elif defined(__MWERKS__) || defined(__cplusplus) - #define OS_INLINE static inline - #endif -#endif - #include __BEGIN_DECLS diff --git a/libkern/libkern/OSByteOrder.h b/libkern/libkern/OSByteOrder.h index 24ad759ca..7509cf040 100644 --- a/libkern/libkern/OSByteOrder.h +++ b/libkern/libkern/OSByteOrder.h @@ -29,7 +29,7 @@ #ifndef _OS_OSBYTEORDER_H #define _OS_OSBYTEORDER_H -#include +#include #if defined(__ppc__) #include diff --git a/libkern/libkern/OSTypes.h b/libkern/libkern/OSTypes.h index a57a3fb63..3328250d0 100644 --- a/libkern/libkern/OSTypes.h +++ b/libkern/libkern/OSTypes.h @@ -80,4 +80,12 @@ typedef unsigned char Boolean; #endif /* __TYPES__ */ #endif /* __MACTYPES__ */ +#if !defined(OS_INLINE) + #if defined(__GNUC__) + #define OS_INLINE static __inline__ + #elif defined(__MWERKS__) || defined(__cplusplus) + #define OS_INLINE static inline + #endif +#endif + #endif /* _OS_OSTYPES_H */ diff --git a/libkern/libkern/c++/OSBoolean.h b/libkern/libkern/c++/OSBoolean.h index c228492b5..3934cfeae 100644 --- a/libkern/libkern/c++/OSBoolean.h +++ b/libkern/libkern/c++/OSBoolean.h @@ -39,6 +39,11 @@ class OSBoolean : public OSObject protected: bool value; + /*D @function taggedRelease + @abstract Override tagged release mechanism. + @param when Unused. */ + virtual void taggedRelease(const void *tag, const int when) const; + public: static void initialize(); @@ -57,6 +62,10 @@ public: */ virtual void free(); + /*D @function taggedRetain + @abstract Override tagged retain mechanism. */ + virtual void taggedRetain(const void *tag) const; + /*! @function isTrue @abstract A member function to test if the boolean object is true. diff --git a/libkern/libkern/c++/OSMetaClass.h b/libkern/libkern/c++/OSMetaClass.h index 9bfd3475c..a4ecef036 100644 --- a/libkern/libkern/c++/OSMetaClass.h +++ b/libkern/libkern/c++/OSMetaClass.h @@ -33,13 +33,27 @@ class OSSymbol; class OSDictionary; class OSSerialize; +#if __GNUC__ < 3 +#define APPLE_KEXT_COMPATIBILITY +#else +#define APPLE_KEXT_COMPATIBILITY __attribute__ ((apple_kext_compatibility)) +#endif + class OSMetaClassBase { public: +/*! @function OSTypeAlloc + @abstract Allocate an instance of the desired object. + @discussion The OSTypeAlloc macro can be used to break the binary compatibility difficulties presented by new. The problem is that C++ compiles the knowledge of the size of the class into the cade calling new. If you use the alloc code however the class size is determined by the callee not the caller. + @param type Name of the desired type to be created. + @result 'this' if object cas been successfully created. +*/ +#define OSTypeAlloc(type) ((type *) ((type::metaClass)->alloc())) + /*! @function OSTypeID @abstract Given the name of a class return it's typeID @param type Name of the desired type, eg. OSObject. - @result 'this' if object is of desired type, otherwise 0. + @result A unique Type ID for the class. */ #define OSTypeID(type) (type::metaClass) @@ -160,27 +174,40 @@ public: // Helper inlines for runtime type preprocessor macros static OSMetaClassBase * - safeMetaCast(const OSMetaClassBase *me, const OSMetaClass *toType) - { return (me)? me->metaCast(toType) : 0; } + safeMetaCast(const OSMetaClassBase *me, const OSMetaClass *toType); static bool - checkTypeInst(const OSMetaClassBase *inst, const OSMetaClassBase *typeinst) - { - const OSMetaClass *toType = OSTypeIDInst(typeinst); - return typeinst && inst && (0 != inst->metaCast(toType)); - } + checkTypeInst(const OSMetaClassBase *inst, const OSMetaClassBase *typeinst); + +public: + +/*! @function taggedRetain + @abstract Retain a tagged reference in this object. +*/ + // WAS: virtual void _RESERVEDOSMetaClassBase0(); + virtual void taggedRetain(const void *tag = 0) const = 0; + +/*! @function taggedRelease + @abstract Release a tagged reference to this object +*/ + // WAS: virtual void _RESERVEDOSMetaClassBase1(); + virtual void taggedRelease(const void *tag = 0) const = 0; + +protected: +/*! @function taggedRelease + @abstract Release a tagged reference to this object and free if retainCount == when on entry +*/ + // WAS: virtual void _RESERVEDOSMetaClassBase2(); + virtual void taggedRelease(const void *tag, const int when) const = 0; private: // Virtual Padding - virtual void _RESERVEDOSMetaClassBase0(); - virtual void _RESERVEDOSMetaClassBase1(); - virtual void _RESERVEDOSMetaClassBase2(); virtual void _RESERVEDOSMetaClassBase3(); virtual void _RESERVEDOSMetaClassBase4(); virtual void _RESERVEDOSMetaClassBase5(); virtual void _RESERVEDOSMetaClassBase6(); virtual void _RESERVEDOSMetaClassBase7(); -}; +} APPLE_KEXT_COMPATIBILITY; /*! @class OSMetaClass : OSMetaClassBase @@ -190,6 +217,7 @@ class OSMetaClass : private OSMetaClassBase { private: + // Can never be allocated must be created at compile time static void *operator new(size_t size); struct ExpansionData { }; @@ -239,6 +267,21 @@ protected: @param when ignored. */ virtual void release(int when) const; +/*! @function taggedRetain + @abstract Retain a tagged reference in this object. +*/ + virtual void taggedRetain(const void *tag = 0) const; + +/*! @function release + @abstract Release a tagged reference to this object +*/ + virtual void taggedRelease(const void *tag = 0) const; + +/*! @function release + @abstract Release a tagged reference to this object +*/ + virtual void taggedRelease(const void *tag, const int when) const; + /*! @function getRetainCount @abstract Implement abstract but should no dynamic allocation is allowed */ virtual int getRetainCount() const; @@ -260,7 +303,9 @@ protected: @discussion If this function is called it means that the object code that implemented this class is actually in the process of unloading. The destructor removes all reference's to the subclass from the runtime type information system. */ virtual ~OSMetaClass(); - static void operator delete(void *mem, size_t size); + // Needs to be overriden as NULL as all OSMetaClass objects are allocated + // statically at compile time, don't accidently try to free them. + void operator delete(void *mem, size_t size) { }; public: static const OSMetaClass * const metaClass; @@ -412,11 +457,11 @@ public: MetaClass(); \ virtual OSObject *alloc() const; \ } gMetaClass; \ - friend class className ## ::MetaClass; \ + friend class className ::MetaClass; \ virtual const OSMetaClass * getMetaClass() const; \ protected: \ - className ## (const OSMetaClass *); \ - virtual ~ ## className ## () + className (const OSMetaClass *); \ + virtual ~ className () /*! @function OSDeclareDefaultStructors @@ -426,7 +471,7 @@ public: #define OSDeclareDefaultStructors(className) \ OSDeclareCommonStructors(className); \ public: \ - className ## (); \ + className (); \ protected: @@ -437,7 +482,7 @@ public: #define OSDeclareAbstractStructors(className) \ OSDeclareCommonStructors(className); \ private: \ - className ## (); /* Make primary constructor private in abstract */ \ + className (); /* Make primary constructor private in abstract */ \ protected: /*! @function OSDefineMetaClassWithInit @@ -447,19 +492,19 @@ public: @param init Name of a function to call after the OSMetaClass is constructed. */ #define OSDefineMetaClassWithInit(className, superClassName, init) \ /* Class global data */ \ - className ## ::MetaClass className ## ::gMetaClass; \ - const OSMetaClass * const className ## ::metaClass = \ - & ## className ## ::gMetaClass; \ - const OSMetaClass * const className ## ::superClass = \ - & ## superClassName ## ::gMetaClass; \ + className ::MetaClass className ::gMetaClass; \ + const OSMetaClass * const className ::metaClass = \ + & className ::gMetaClass; \ + const OSMetaClass * const className ::superClass = \ + & superClassName ::gMetaClass; \ /* Class member functions */ \ - className ## :: ## className(const OSMetaClass *meta) \ - : superClassName ## (meta) { } \ - className ## ::~ ## className() { } \ - const OSMetaClass * className ## ::getMetaClass() const \ + className :: className(const OSMetaClass *meta) \ + : superClassName (meta) { } \ + className ::~ className() { } \ + const OSMetaClass * className ::getMetaClass() const \ { return &gMetaClass; } \ /* The ::MetaClass constructor */ \ - className ## ::MetaClass::MetaClass() \ + className ::MetaClass::MetaClass() \ : OSMetaClass(#className, className::superClass, sizeof(className)) \ { init; } @@ -468,16 +513,16 @@ public: @param className Name of class. NO QUOTES and NO MACROS. @param superClassName Name of super class. NO QUOTES and NO MACROS. */ #define OSDefineAbstractStructors(className, superClassName) \ - OSObject * ## className ## ::MetaClass::alloc() const { return 0; } + OSObject * className ::MetaClass::alloc() const { return 0; } /*! @function OSDefineDefaultStructors @abstract Basic helper macro for the OSDefineMetaClass for the default and Abstract macros, qv. DO NOT USE. @param className Name of class. NO QUOTES and NO MACROS. @param superClassName Name of super class. NO QUOTES and NO MACROS. */ #define OSDefineDefaultStructors(className, superClassName) \ - OSObject * ## className ## ::MetaClass::alloc() const \ + OSObject * className ::MetaClass::alloc() const \ { return new className; } \ - className ## :: ## className () : superClassName ## (&gMetaClass) \ + className :: className () : superClassName (&gMetaClass) \ { gMetaClass.instanceConstructed(); } @@ -535,7 +580,7 @@ public: #define OSMetaClassDeclareReservedUsed(classname, index) #define OSMetaClassDefineReservedUnused(classname, index) \ -void classname ## ::_RESERVED ## classname ## index () \ +void classname ::_RESERVED ## classname ## index () \ { gMetaClass.reservedCalled(index); } #define OSMetaClassDefineReservedUsed(classname, index) diff --git a/libkern/libkern/c++/OSObject.h b/libkern/libkern/c++/OSObject.h index a7e0505a9..d7ed685bc 100644 --- a/libkern/libkern/c++/OSObject.h +++ b/libkern/libkern/c++/OSObject.h @@ -63,11 +63,16 @@ private: protected: /*! @function release - @abstract Primary implementation of the release mechanism. - @discussion If $link retainCount <= the when argument then call $link free(). This indirect implementation of $link release allows the developer to break reference circularity. An example of this sort of problem is a parent/child mutual reference, either the parent or child can implement: void release() { release(2); } thus breaking the cirularity. - @param when When retainCount == when then call free(). */ + @abstract untagged release(when) mechansim. + @param when Pass through to taggedRelease. */ virtual void release(int when) const; +/*! @function taggedRelease + @abstract Primary implementation of the tagged release mechanism. + @discussion If $link retainCount <= the when argument then call $link free(). This indirect implementation of $link release allows the developer to break reference circularity. An example of this sort of problem is a parent/child mutual reference, either the parent or child can implement: void taggedRelease(tag) { taggedRelease(tag, 2); } thus breaking the cirularity. + @param when If retainCount == when then call free(). */ + virtual void taggedRelease(const void *tag, const int when) const; + /*! @function init @abstract Mac OS X kernel's primary mechanism for constructing objects. @discussion Your responsibility as a subclass author is to override the init method of your parent. In general most of our implementations call ::init() before doing local initialisation, if the parent fails then return false immediately. If you have a failure during you local initialisation then return false. @@ -110,14 +115,28 @@ public: /*! @function retain @abstract Retain a reference in this object. + @discussion Takes a reference that is NULL tagged. See taggedRetain(). */ virtual void retain() const; /*! @function release @abstract Release a reference to this object + @discussion Removes a reference that is NULL tagged. See taggedRelease(). */ virtual void release() const; +/*! @function taggedRetain + @abstract Retain a tagged reference in this object. + @param tag Retain a reference on this object with this tag, see taggedRelease. +*/ + virtual void taggedRetain(const void *tag = 0) const; + +/*! @function taggedRelease + @abstract Release a tagged reference to this object + @param tag Remove a reference on this object with this tag, if an attempt is made to remove a reference that isn't associated with this tag the kernel will panic immediately. +*/ + virtual void taggedRelease(const void *tag = 0) const; + /*! @function serialize @abstract @discussion diff --git a/libkern/libkern/c++/OSUnserialize.h b/libkern/libkern/c++/OSUnserialize.h index 80827e652..540cf9149 100644 --- a/libkern/libkern/c++/OSUnserialize.h +++ b/libkern/libkern/c++/OSUnserialize.h @@ -24,6 +24,8 @@ #ifndef _OS_OSUNSERIALIZE_H #define _OS_OSUNSERIALIZE_H +#include + class OSObject; class OSString; @@ -35,7 +37,8 @@ class OSString; extern OSObject* OSUnserializeXML(const char *buffer, OSString **errorString = 0); -/* this should no longer be used */ +#ifdef __APPLE_API_OBSOLETE extern OSObject* OSUnserialize(const char *buffer, OSString **errorString = 0); +#endif /* __APPLE_API_OBSOLETE */ #endif /* _OS_OSUNSERIALIZE_H */ diff --git a/libkern/libkern/i386/OSByteOrder.h b/libkern/libkern/i386/OSByteOrder.h index da3d0a459..e650d5c1f 100644 --- a/libkern/libkern/i386/OSByteOrder.h +++ b/libkern/libkern/i386/OSByteOrder.h @@ -29,7 +29,7 @@ #ifndef _OS_OSBYTEORDERI386_H #define _OS_OSBYTEORDERI386_H -#include +#include /* Functions for byte reversed loads. */ diff --git a/libkern/libkern/machine/OSByteOrder.h b/libkern/libkern/machine/OSByteOrder.h index dd4d67331..305f265cf 100644 --- a/libkern/libkern/machine/OSByteOrder.h +++ b/libkern/libkern/machine/OSByteOrder.h @@ -30,7 +30,7 @@ #ifndef _OS_OSBYTEORDERMACHINE_H #define _OS_OSBYTEORDERMACHINE_H -#include +#include /* Functions for byte reversed loads. */ diff --git a/libkern/libkern/ppc/OSByteOrder.h b/libkern/libkern/ppc/OSByteOrder.h index 0a7e75a72..e1f90fb8e 100644 --- a/libkern/libkern/ppc/OSByteOrder.h +++ b/libkern/libkern/ppc/OSByteOrder.h @@ -30,7 +30,7 @@ #ifndef _OS_OSBYTEORDERPPC_H #define _OS_OSBYTEORDERPPC_H -#include +#include /* Functions for byte reversed loads. */ diff --git a/libsa/c++rem3.c b/libsa/c++rem3.c new file mode 100644 index 000000000..dfea38871 --- /dev/null +++ b/libsa/c++rem3.c @@ -0,0 +1,2209 @@ +// 45678901234567890123456789012345678901234567890123456789012345678901234567890 +/* + +Rules specification by +Stan Shebs of Apple Computer, Inc 2002 + +Parse and remangle implemented by +Godfrey van der Linden of Apple Computer, Inc 2002 + +Rules for demangling IOKit symbols + +In Darwin versions 1.0 through at least 5.2, IOKit is compiled using +GCC version 2. GCC 2's C++ symbol mangling algorithm ultimately +derives from the basic scheme described in the Annotated C++ Reference +Manual (ARM), section 7.2.1c, with a number of changes, mostly due to +the expansion of the language since the ARM was published in 1990. + +This description is not complete. It omits RTTI, thunks, and +templates, since they are not allowed in IOKit. The description also +mentions mangled name constructs that are not disallowed in IOKit, but +that as of Jan 2002, did actually appear in any symbol in the base +system. + +A mangled name basically consists of a function name followed +by two underscores, optionally followed by a signature computed +from the function's argument types. (Note that in Darwin, the +compiler adds an additional underscore to all C and C++ symbols. +The description assumes this has been removed.) + + ::= + | + + ::= [ ] + + ::= [ "_GLOBAL_" [ID] "__" ] "__" [ ] + + ::= * + | NULL + +Questions for Stan (@@@Stan@@@) +1> A valid implies a null function name. +2> I wonder if an is mutually exclusive with a perhaps something like :- + ::= [ "_GLOBAL_" ("I"|"D") "__" ] (( "__") | ) +3> Do constructors turn up as an opinfo or a NULL function name? + +The optional "_GLOBAL_"("I"|"D")"__" sequence indicates global constructors +and destructors, but in practice these do not appear with the mach-o Apple 2.95 + +A Null indicates a constructor or an operator. + +Since may include trailing underscores, the demangler +should scan forward until a non-underscore is seen, and then take the +last two as the separator between name and signature. + + may also include any number of leading underscores, so +the demangler needs to add those to and look for the +"__" following the name. + + ::= ("_._"|"_$_" ) ; destructor + | "__vt_" ; virtual table + | "_" ("."|"$") ; Variable + + ::= + | "Q" + | "K" ; ignored and illegal + + ::= + + ::= * + + ::= "type" + | "__op" + | "__" + | "a" + + ::= "aa" # && + | "aad" # &= + | "ad" # & + | "adv" # /= + | "aer" # ^= + | "als" # <<= + | "amd" # %= + | "ami" # -= + | "aml" # *= + | "aor" # |= + | "apl" # += + | "ars" # >>= + | "as" # = + | "cl" # () + | "cm" # , + | "cn" # ?: + | "co" # ~ + | "dl" # delete + | "dv" # / + | "eq" # == + | "er" # ^ + | "ge" # >= + | "gt" # > + | "le" # <= + | "ls" # << + | "lt" # < + | "md" # % + | "mi" # - + | "ml" # * + | "mm" # -- + | "mn" # ? + | "ne" # != + | "nt" # ! + | "nw" # new + | "oo" # || + | "or" # | + | "pl" # + + | "pp" # ++ + | "rf" # -> + | "rm" # ->* + | "rs" # >> + | "sz" # sizeof + | "vc" # [] + | "vd" # delete[] + | "vn" # new[] + +Questions for Stan (@@@Stan@@@) +1> What the hell is The "type" & "__op" stuff? + +IOKit has so far only been observed to use operations new ("nw") and +delete ("dl"). + +The signature is a concatenated list of elements, which are usually +argument types, but may include other sorts of things. + + ::= * + + ::= + | "S" + | "F" [ "_" ] + +Questions for Stan (@@@Stan@@@) +1> I think the 'B' phrase should probably read '| "B" '? +2> Ambiguous productions for signature + OSObject::func(struct timeval fred) => _func__8OSObject7timeval + signature could be parsed as + or + I believe the second one must be the valid production. + + ::= * + + :: + + ::= * + +The is the number of characters in . + +Argument types are a concatenated sequence of types. + + ::= # Empty + | + + ::= [ "n" ] + | "N" + | "T" + +The "N" repeats and "T" references to already-seen typescan only +appear if -fno-squangle (no squashed mangling), and in practice aren't +seen in IOKit symbols. + + ::= | * "_" + +Return types are just like any other sort of type. + + ::= + +Types consist of a variable number of declarators in front of a basic +type. + + ::= * + + ::= "P" ; pointer + | "p" ; pointer (but never occurs?) + | "R" ; reference (&) + | "A" ; array + | "T" + | "O" + | + +The "A" production can produce an ambigous output if it is followed by a counted class name or structure name. + +The "T" reference to a type does not appear in IOKit symbols, nor do +the "M" and "O" declarators. + + ::= ; function + | ; method + | * + + ::= "F" "_" + + ::= "M" + +A qualified name consists of a count of types, followed by all the +types concatenated together. For instance, Namespace::Class is +Q29Namespace5Class. For more than 9 types (which has not yet occurred +in IOKit), the multi-digit count is surrounded by underscores. + +Questions for Stan (@@@Stan@@@) +1> Can the types in a qualified name really be generic types or can the set be restricted to just counted class names? + + ::= | "_" * "_" + +Fundamental types are single letters representing standard built-in +types, optionally preceded by type qualifiers for properties like +signedness and constness. For instance, CUi is a const unsigned int. + + ::= "S" ; signed (chars only) + | "U" ; unsigned (any integral type) + | "J" ; __complex + | + + ::= + | "b" ; bool + | "c" ; char + | "d" ; double + | "f" ; float + | "i" ; int + | "l" ; long + | "r" ; long double + | "s" ; short + | "v" ; void + | "w" ; wchar_t + | "x" ; long long + | "G" ; ????? + | "e" ; ellipsis + +"G" does not appear in IOKit symbols in this context. + + ::= "C" ; const + | "V" ; volatile + | "u" ; restrict (C99) + | "G" ; struct/union/enum unused by gcc3 + +The restrict qualifier has not appeared in IOKit symbols. + +*/ +#if KERNEL + +#include +#include + +#include + +#include + +#include + +enum { false = 0, true = 1 }; + +#else /* !KERNEL */ + +#include + +#include +#include +#include + +#include + +#endif /* KERNEL */ + +#include "c++rem3.h" + +#define STRLEN(s) (sizeof(s)-1) +#define APPENDSTR(c, str) do { appendNStr(c, str, STRLEN(str)); } while (0) + +#define MAX_COMPOUND_TYPES 128 +#define MAX_ENTRIES 256 +#define MAX_SDICT_ENTRIES 256 +#define MAX_BDICT_ENTRIES 64 +#define MAX_RETURN_BUFFER 256 + +// Can't be bigger that 16 entries +typedef enum NameTypes { + kNTUndefined, kNTClass, kNTFunction, kNTFuncEnd, + kNTMethod, kNTBuiltIn, kNTDeclarator, kNTArray, + kNTKName, kNTSubstitute, kNTSubQualClass +} NameTypes; + +typedef struct TypeData { + short fStartEntry, fNumEntries; +} TypeData; + +typedef struct BaseTypeData { + const char *fFundTypeID; // May contain the type itself for kNTBuiltIt + unsigned int fLen:16; + unsigned int fType:4; // Must fit a NameType + unsigned int fVolatile:1; + unsigned int fConst:1; + unsigned int fSigned:1; + unsigned int fUnsigned:1; + unsigned int fPseudo:1; + unsigned int fQualified:1; +} BaseTypeData; + +typedef struct CheckPoint { + const char *fInChar; + unsigned char fNumI, fNumO, fNumT, fNumB, fNumS; +} CheckPoint; + +typedef struct ParseContext { + CheckPoint fP; + BaseTypeData fInEntries[MAX_ENTRIES]; // Input parsed elements + BaseTypeData fOutEntries[MAX_ENTRIES]; // Output parsed elements + TypeData fTypeList[MAX_COMPOUND_TYPES]; // Table of types + TypeData fSubDict[MAX_SDICT_ENTRIES]; + TypeData fBDict[MAX_BDICT_ENTRIES]; // B dictionary types + BaseTypeData *fCurBaseP; + const char *fInStr; + char *fOutStrEnd; + char *fOutChar; + int fInSize; + Rem3Return fRetCode; +} ParseContext; + +// +// The only forward declaration necessary +// +static Boolean parse_type(ParseContext *c); + +// Helper functions for walking through the string +static __inline__ char getNext(ParseContext *c) +{ + return *c->fP.fInChar++; +} + +static __inline__ CheckPoint *checkPoint(ParseContext *c) +{ + return &c->fP; +} + +static __inline__ void resetTo(ParseContext *c, CheckPoint *chk) +{ + c->fP = *chk; +} + +static __inline__ const char *inCharFromCheck(ParseContext *c, CheckPoint *chk) +{ + return chk->fInChar; +} + +static __inline__ void advance(ParseContext *c, int len) +{ + c->fP.fInChar += len; +} + +static __inline__ Boolean retard(ParseContext *c, int len) +{ + const char *cp = c->fP.fInChar - len; + if (cp < c->fInStr) + return false; + + c->fP.fInChar = cp; + return true; +} + +static __inline__ char peekAt(ParseContext *c, int index) +{ + return c->fP.fInChar[index]; +} + +static __inline__ char peekNext(ParseContext *c) +{ + return peekAt(c, 0); +} + +static __inline__ Boolean atEnd(ParseContext *c) +{ + return '\0' == peekNext(c); +} + +static __inline__ Boolean hasRemain(ParseContext *c, int len) +{ + return (c->fP.fInChar - c->fInStr + len <= c->fInSize); +} + +// +// Routines for allocating entries in the various +// +static __inline__ BaseTypeData *newIn(ParseContext *c) +{ + BaseTypeData *iP; + + if (c->fP.fNumI < MAX_ENTRIES) { + iP = &c->fInEntries[c->fP.fNumI++]; + bzero(iP, sizeof(*iP)); + c->fCurBaseP = iP; + return iP; + } + else { + c->fRetCode = kR3InternalNotRemangled; + return NULL; + } +} + +static __inline__ BaseTypeData *newOut(ParseContext *c) +{ + BaseTypeData *oP; + + if (c->fP.fNumO < MAX_ENTRIES) { + oP = &c->fOutEntries[c->fP.fNumO++]; + return oP; + } + else { + c->fRetCode = kR3InternalNotRemangled; + return NULL; + } +} + +static __inline__ TypeData * +newSub(ParseContext *c, int start, int num) +{ + TypeData *sP; + + if (c->fP.fNumS < MAX_SDICT_ENTRIES) { + sP = &c->fSubDict[c->fP.fNumS++]; + sP->fStartEntry = start; + sP->fNumEntries = num; + return sP; + } + else { + c->fRetCode = kR3InternalNotRemangled; + return NULL; + } +} + +static __inline__ TypeData * +newBDict(ParseContext *c, int start, int num) +{ + TypeData *bP; + + if (c->fP.fNumB < MAX_BDICT_ENTRIES) { + bP = &c->fBDict[c->fP.fNumB++]; + bP->fStartEntry = start; + bP->fNumEntries = num; + return bP; + } + else { + c->fRetCode = kR3InternalNotRemangled; + return NULL; + } +} + +static __inline__ TypeData * +newType(ParseContext *c, int start) +{ + TypeData *tP; + + if (c->fP.fNumT < MAX_COMPOUND_TYPES) { + tP = &c->fTypeList[c->fP.fNumT++]; + tP->fStartEntry = start; + return tP; + } + else + return NULL; +} + +static __inline__ TypeData * +dupType(ParseContext *c, TypeData *iTP, int offset) +{ + TypeData *tP = newType(c, iTP->fStartEntry + offset); + if (tP) + tP->fNumEntries = iTP->fNumEntries; + + return tP; +} + +// +// Identifier character recognition helpers, can be optimised +// +static __inline__ Boolean isValidFirstAlphabetic(char c) +{ + if ('a' <= c && c <= 'z') + return true; + else if ('A' <= c && c <= 'Z') + return true; + else + return false; +} + +static __inline__ Boolean isValidFirstChar(char c) +{ + if (isValidFirstAlphabetic(c)) + return true; + else if (c == '_') + return true; + else + return false; +} + +static __inline__ Boolean isValidChar(char c) +{ + if (isValidFirstChar(c)) + return true; + else if ('0' <= c && c <= '9') + return true; + else + return false; +} + +// +// Helper function for recognising characters and strings +// + +// Check the current input is the given character +static __inline__ Boolean isNext(ParseContext *c, char ch) +{ + if (peekNext(c) == ch) { + advance(c, 1); + return true; + } + else + return false; +} + +// Check the current input is ONE of the characters in str +static Boolean charNext(ParseContext *c, char *str) +{ + if (hasRemain(c, 1)) { + char ch = peekNext(c); + char next; + + while ( (next = *str++) ) + if (next == ch) { + advance(c, 1); + return true; + } + } + + return false; +} + +// Check the current input for 'str' +static Boolean strNext(ParseContext *c, const char *str) +{ + const char *cp = c->fP.fInChar; + + do { + if (!*str) { + c->fP.fInChar = (char *) cp; + return true; + } + else if (!*cp) + return false; + + } while (*cp++ == *str++); + + return false; +} + +// +// Qualifier re-encoding +// +static void +decodeQual(BaseTypeData *typeP, int *qualLenP, const char **qualP) +{ + const char *qual; + int qualLen; + + if (typeP->fConst && typeP->fVolatile) + { qual = "VK"; qualLen = 2; } + else if (typeP->fConst) + { qual = "K"; qualLen = 1; } + else if (typeP->fVolatile) + { qual = "V"; qualLen = 1; } + else + { qual = NULL; qualLen = 0; } + + *qualLenP = qualLen; + *qualP = qual; +} + + +// +// Output functions +// + +static void appendChar(ParseContext *c, char ch) +{ + char *outAddr = c->fOutChar++; + if (outAddr < c->fOutStrEnd) + *outAddr = ch; +} + +static void appendNStr(ParseContext *c, const char *str, int len) +{ + char *outAddr = c->fOutChar; + + c->fOutChar += len; + if (c->fOutChar < c->fOutStrEnd) + bcopy(str, outAddr, len); +} + +static __inline__ void appendStr(ParseContext *c, const char *str) +{ + appendNStr(c, str, strlen(str)); +} + +static void appendSub(ParseContext *c, int ls) +{ + appendChar(c, 'S'); + if (ls) { + if (--ls >= 36) { + int ms; + + ms = ls / 36; + appendChar(c, (ms < 10)? '0' + ms : 'A' + ms - 10); + ls -= (ms * 36); + } + appendChar(c, (ls < 10)? '0' + ls : 'A' + ls - 10); + } + appendChar(c, '_'); +} + +static Boolean compareTypes(ParseContext *c, int sub, int entry, int numEntries) +{ + TypeData *subP = &c->fSubDict[sub]; + BaseTypeData *bSP, *bIP; + int i; + + if (subP->fNumEntries != numEntries) + return false; + + bSP = &c->fInEntries[subP->fStartEntry]; + bIP = &c->fInEntries[entry]; + + for (i = 0; i < numEntries; i++, bSP++, bIP++) { + if (bSP->fType != bIP->fType) + return false; + + switch (bSP->fType) { + case kNTClass: + if (bSP->fLen != bIP->fLen) + return false; + else if (strncmp(bSP->fFundTypeID, bIP->fFundTypeID, bSP->fLen)) + return false; + break; + + case kNTArray: + case kNTBuiltIn: + case kNTDeclarator: + if (bSP->fFundTypeID != bIP->fFundTypeID) + return false; + break; + + case kNTMethod: + case kNTFunction: + case kNTUndefined: + case kNTKName: + break; // OK so far + + default: + return false; // Fatal errors + } + } + + return true; +} + +static int searchDict(ParseContext *c, int entry, int numE) +{ + int sub, numSubs = c->fP.fNumS; + + // don't try to substitute the last builtin + if (numE == 1 && kNTBuiltIn == c->fInEntries[entry].fType) + return -1; + + for (sub = 0; sub < numSubs; sub++) + if (compareTypes(c, sub, entry, numE)) + return sub; + + return -1; +} + +static int searchDictClass(ParseContext *c, const char *qname, int len) +{ + TypeData *subP; + int sub, numSubs = c->fP.fNumS; + + for (sub = 0, subP = c->fSubDict; sub < numSubs; sub++, subP++) { + BaseTypeData *iP = &c->fInEntries[subP->fStartEntry]; + + if (kNTClass != iP->fType || iP->fLen != len) + continue; + if (!strncmp(iP->fFundTypeID, qname, len)) + return sub; + } + + return -1; +} + +static Boolean +appendQualifiedClass(ParseContext *c, int entry) +{ + BaseTypeData *iP, *oP, *sP, *endSP; + const char *cp, *typeID; + int sub, subEntry, prefixLen; + int q_count; + + int decodeStart = c->fP.fNumI; + + // Scan through the incom + iP = &c->fInEntries[entry]; + endSP = &c->fInEntries[MAX_ENTRIES]; + sP = &c->fInEntries[decodeStart]; + + prefixLen = iP->fLen; + typeID = cp = iP->fFundTypeID; + for (q_count = 0; sP < endSP && (cp-typeID) < prefixLen; q_count++, sP++) { + int count; + + count = strtoul(cp, (char **) &cp, 10); + cp += count; + + sP->fType = kNTClass; + sP->fFundTypeID = typeID; + sP->fLen = cp - typeID; + } + if (sP >= endSP) + return false; + + // Search backwards until I find the first substitution + sub = -1; + for (subEntry = q_count, sP--; subEntry > 0; subEntry--, sP--) { + sub = searchDictClass(c, sP->fFundTypeID, sP->fLen); + if (-1 != sub) + break; + } + + // Now drop the symbol into the output buffer + oP = newOut(c); + if (!oP) + return false; + + if (sub < 0) + *oP = *iP; // No sub copy original + else { + // Substitution found + prefixLen = sP->fLen; // Length of substitution + + oP->fType = kNTSubstitute; // Assume complete substitution + oP->fLen = sub; + oP->fFundTypeID = 0; + + // We have a partial substitution so tag on the unmatched bit + if (prefixLen != iP->fLen) { + oP->fType = kNTSubQualClass; // Re-characterise as 2 part sub + + oP = newOut(c); + if (!oP) + return false; + + *oP = *iP; // Duplicate the original + oP->fType = kNTSubQualClass; + oP->fFundTypeID += prefixLen; // Skip leading substituted text + oP->fLen -= prefixLen; + } + } + + // Finally insert the qualified class names into the dictionary + for (subEntry++, sP++; subEntry < q_count; subEntry++, decodeStart++) { + c->fInEntries[decodeStart] = *sP++; + if (!newSub(c, decodeStart, 1)) + return false; + } + c->fP.fNumI = decodeStart; + + if (!newSub(c, entry, 1)) + return false; + + return true; +} + +static int +appendType(ParseContext *c, int type) +{ + BaseTypeData *iP, *oP; + TypeData *tP; + int i, sub; + int entry, numE, lastEntry; + Boolean found; + + if (type >= c->fP.fNumT) + return -1; + + tP = &c->fTypeList[type++]; + entry = tP->fStartEntry; + numE = tP->fNumEntries; + lastEntry = entry + numE; + iP = 0; + for (i = 0, found = false, sub = -1; i < numE; i++) { + iP = &c->fInEntries[entry + i]; + switch (iP->fType) { + + // Function & Builtin can't be compressed alone + case kNTFunction: + case kNTBuiltIn: + i++; // Copy the current entry + found = true; + break; + + case kNTClass: + case kNTMethod: + sub = searchDict(c, entry + i, numE - i); + if (sub < 0 && !iP->fQualified) + i++; + found = true; + break; + + case kNTDeclarator: + case kNTArray: + sub = searchDict(c, entry + i, numE - i); + found = (sub >= 0); + break; + + // Internal error's should never occur + case kNTKName: + case kNTSubstitute: + case kNTSubQualClass: + case kNTUndefined: + default: + return -1; + } + if (found) + break; + } + + if (!found) + return -1; // Internal error: no terminal symbol? + + // Copy the already input buffer to the output + oP = &c->fOutEntries[c->fP.fNumO]; + if (i) { + if (c->fP.fNumO + i >= MAX_ENTRIES) + return -1; + + bcopy(&c->fInEntries[entry], oP, i * sizeof(*oP)); + c->fP.fNumO += i; + oP += i; + } + + if (sub >= 0) { + // We found a substitution + oP->fType = kNTSubstitute; + oP->fLen = sub; + c->fP.fNumO++; // Increment output for the substitution + + // Walk over types that have been substituted + while (type < c->fP.fNumT + && c->fTypeList[type].fStartEntry < lastEntry) + type++; + } + else switch (iP->fType) + { + case kNTMethod: + type = appendType(c, type); // Class Name + if (type < 0) + return type; + type = appendType(c, type); // Pointer to function + if (type < 0) + return type; + break; + + case kNTFunction: + type = appendType(c, type); // Return type + if (type < 0) + return type; + + // process the argument list + do { + tP = &c->fTypeList[type]; + if (tP->fStartEntry < lastEntry) { + type = appendType(c, type); + if (type < 0) + return type; + } + else + break; + } while (type < c->fP.fNumT); + oP = newOut(c); + if (!oP) + return -1; + oP->fType = kNTFuncEnd; + break; + + case kNTBuiltIn: + i--; // Do not store the buildit in the dictionary + break; + + case kNTClass: // Nothing more to do + if (!iP->fQualified) + break; + else if (appendQualifiedClass(c, entry + i)) + break; + else + return -1; + } + + // No further substititions to be had update the dictionary + for (i += entry; --i >= entry; ) { + if (!newSub(c, i, lastEntry - i)) + return -1; + } + + return type; +} + +static Boolean appendArgumentList(ParseContext *c) +{ + int i, num; + + c->fRetCode = kR3InternalNotRemangled; + // Setup the output entry array + num = c->fP.fNumT; + for (i = 0; i < num; ) { + i = appendType(c, i); + if (i < 0) + return false; + } + + // First pass output uncompressed types + for (i = 0, num = c->fP.fNumO; i < num; i++) { + BaseTypeData *bP; + + bP = &c->fOutEntries[i]; + + if (bP->fPseudo) + continue; // Pseudo entry do not output; + + switch (bP->fType) { + + case kNTSubstitute: appendSub(c, bP->fLen); break; + + case kNTSubQualClass: + appendChar(c, 'N'); + appendSub(c, bP->fLen); + i++; bP = &c->fOutEntries[i]; + appendNStr(c, bP->fFundTypeID, bP->fLen); + appendChar(c, 'E'); + break; + + case kNTClass: + if (bP->fQualified) { + appendChar(c, 'N'); + appendNStr(c, bP->fFundTypeID, bP->fLen); + appendChar(c, 'E'); + } + else + appendNStr(c, bP->fFundTypeID, bP->fLen); + break; + + case kNTArray: { + char numbuf[16]; // Bigger than MAX_LONG + 3 + int len; + len = snprintf(numbuf, sizeof(numbuf), + "A%lu_", (unsigned long) bP->fFundTypeID); + appendNStr(c, numbuf, len); + break; + } + + case kNTBuiltIn: + case kNTDeclarator: appendChar(c, (int) bP->fFundTypeID); break; + case kNTMethod: appendChar(c, 'M'); break; + case kNTFunction: appendChar(c, 'F'); break; + case kNTFuncEnd: appendChar(c, 'E'); break; + + case kNTUndefined: + case kNTKName: + default: + return false; // Fatal errors + } + } + + // Successful remangle + c->fRetCode = kR3Remangled; + return true; +} + +// +// Parse routines +// + +// ::= * +static Boolean parse_count(ParseContext *c, int *countP) +{ + int count = 0; + char ch; + + ch = peekNext(c); + if (ch < '1' || ch > '9') + return false; + + count = strtol(c->fP.fInChar, (char **) &c->fP.fInChar, 10); + if (countP) + *countP = count; + + return true; +} + + +// "n" can cause the following type to be ambiguous as +// n23_Pc... can be +// "n" ... +// | "n" '_' ... +// However as the class '_Pc' is probably going to be unlikely a quick +// check to see if the next field is a valid type would probably clear +// up the abiguity for the majority of cases. +// +// ::= | * "_" +static Boolean parse_index(ParseContext *c, int *indexP) +{ + CheckPoint chk = *checkPoint(c); + char ch0, ch1; + int index; + + ch0 = peekAt(c, 0); + ch1 = peekAt(c, 1); + + if ( !('0' <= ch0 && ch0 <= '9') ) + goto abandonParse; + if ('0' <= ch1 && ch1 <= '9') { + if (!parse_count(c, &index)) + goto abandonParse; + if (isNext(c, '_')) { + // @@@ gvdl: Ambiguity check one day + if (indexP) + *indexP = index; + return true; + } + else + resetTo(c, &chk); // Must be the one digit case + } + + // One digit case + advance(c, 1); + index = ch0 - '0'; + + if (indexP) + *indexP = index; + return true; + +abandonParse: + return false; +} + + +// ::= "C" ; const +// | "V" ; volatile +// | "u" ; restrict (C99) unsupported +// | "G" ; struct/union/enum ; unused in gcc3 +static Boolean parse_qualifiers(ParseContext *c) +{ + BaseTypeData *bP = c->fCurBaseP; + + for (;;) { + if (isNext(c, 'C')) + bP->fConst = true; // "C" ; const + else if (isNext(c, 'V')) + bP->fVolatile = true; // "V" ; volatile + else if (isNext(c, 'u')) + return false; // "u" ; restrict (C99) + else if (isNext(c, 'G')) + continue; // "G" ; struct/union/enum ; unused + else + break; + } + + return true; +} + +// Assumes we have an open fInEntry in fCurBaseP +static Boolean duplicateEntries(ParseContext *c, int start, int numE) +{ + BaseTypeData *bIP = &c->fInEntries[start]; // First duplicate entry + BaseTypeData *bP = c->fCurBaseP; + int i; + + // Duplicating a method + if (kNTMethod == bIP->fType) { + bP--; // Strip leading 'P' declarator + c->fP.fNumI--; + } + + numE--; + + // do we have room available for duplication + if (c->fP.fNumI + numE >= MAX_ENTRIES) + return false; + + // Copy the parse entries over + bcopy(bIP, bP, (numE + 1) * sizeof(*bP)); + + // Now we have to duplicate the types for the new entry + for (i = 0; i < c->fP.fNumT; i++) { + TypeData *tP = &c->fTypeList[i]; + if (tP->fStartEntry < start) + continue; + else if (tP->fStartEntry <= start + numE) + dupType(c, tP, bP - bIP); + else + break; + } + + c->fP.fNumI += numE; + bP += numE; + c->fCurBaseP = bP; + + return true; +} + +// Must have a valid c->fCurBaseP pointer on entry +// ::= ; plain class name +// | "Q" ; qualified name +// | "B" ; compressed name +// | "K" ; ignored and illegal +// ::= + +// ::= | "_" * "_" +// ::= +// ::= * +static Boolean +parse_class_name(ParseContext *c) +{ + BaseTypeData *bP = c->fCurBaseP; + const char *typeId = c->fP.fInChar; + char ch; + int count; + + if (parse_count(c, &count)) { + + // ::= + if (!hasRemain(c, count)) + goto abandonParse; + + bP->fType = kNTClass; + advance(c, count); + + bP->fFundTypeID = typeId; + bP->fLen = c->fP.fInChar - typeId; + } + else { + switch (peekNext(c)) { + + case 'Q': { + int i, q_count; + + advance(c, 1); + + // | "Q" ; qualified name + // ::= + + // ::= | "_" * "_" + if ('_' == (ch = getNext(c))) { + advance(c, 1); + if (!parse_count(c, &q_count) || !isNext(c, '_')) + goto abandonParse; + } + else if ('1' <= ch && ch <= '9') + q_count = ch - '0'; + + if (!q_count) + goto abandonParse; + + typeId = c->fP.fInChar; + bP->fType = kNTClass; + bP->fQualified = true; + i = 0; + for (i = 0; i < q_count; i++) { + if (parse_count(c, &count)) + advance(c, count); + else + goto abandonParse; + } + bP->fLen = c->fP.fInChar - typeId; + bP->fFundTypeID = typeId; + break; + } + + case 'B': + // | "B" + advance(c, 1); + + if (!parse_index(c, &count) || count >= c->fP.fNumB) + goto abandonParse; + + if (!duplicateEntries(c, c->fBDict[count].fStartEntry, + c->fBDict[count].fNumEntries)) + goto abandonParse; + return true; + + case 'K': default: + goto abandonParse; + } + } + + if (newBDict(c, bP - c->fInEntries, 1)) + return true; + +abandonParse: + return false; +} + +// ::= +// | "b" ; bool +// | "c" ; char +// | "d" ; double +// | "e" ; ellipsis +// | "f" ; float +// | "i" ; int +// | "l" ; long +// | "r" ; long double +// | "s" ; short +// | "v" ; void +// | "w" ; wchar_t +// | "x" ; long long +// | "G" ; ??? +static Boolean parse_fund_type_id(ParseContext *c) +{ + BaseTypeData *bP = c->fCurBaseP; + + if (!parse_class_name(c)) { + // Use the TypeID pointer as a 4 character buffer + char ch = peekNext(c); + + if (bP->fSigned && 'c' != ch) + goto abandonParse; // illegal only chars can be signed + + switch (ch) { + + case 'b': case 'd': case 'f': case 'v': case 'w': // No map types + break; + + case 'c': // character + if (bP->fSigned) ch = 'a'; + else if (bP->fUnsigned) ch = 'h'; + break; + case 'e': // ellipsis + ch = 'z'; + break; + case 'i': // int + if (bP->fUnsigned) ch = 'j'; + break; + case 'l': // long + if (bP->fUnsigned) ch = 'm'; + break; + case 'r': // long double + ch = 'e'; + break; + case 's': // short + if (bP->fUnsigned) ch = 't'; + break; + case 'x': // long long + if (bP->fUnsigned) ch = 'y'; + break; + + case 'G': // Don't understand "G" + default: + goto abandonParse; + } + + advance(c, 1); // Consume the input character + bP->fFundTypeID = (void *) (int) ch; + bP->fLen = 0; + bP->fType = kNTBuiltIn; + } + + return true; + +abandonParse: + return false; +} + +// ::= [ "n" ] +// | "N" ; Not implemented +// | "T" ; Not implemented +static Boolean parse_arg_type(ParseContext *c) +{ + // Don't bother to check point as parse_argument_types does it for us + + TypeData *typeP; + int repeat = 0; + + typeP = &c->fTypeList[c->fP.fNumT]; // Cache type for later repeat + if (!parse_type(c)) + return false; + + // Now check for a repeat count on this type + if (isNext(c, 'n')) { + if (!parse_index(c, &repeat)) + return false; + + do { + c->fCurBaseP = newIn(c); // Duplicate requires a fresh type + if (!c->fCurBaseP) + return false; + if (!duplicateEntries(c, typeP->fStartEntry, typeP->fNumEntries)) + return false; + } while (--repeat); + } + + return true; +} + +// ::= # Empty +// | + +static Boolean parse_argument_types(ParseContext *c) +{ + if (atEnd(c)) + return true; + + if (!parse_arg_type(c)) + goto abandonParse; + + while (!atEnd(c) && parse_arg_type(c)) + ; + + return true; + + // Not a counted class name so reset to checkPoint +abandonParse: + return false; +} + +// leaf function so the copy aside buffer isn't on the primary +// recursion stack. +static Boolean +rotateFunction(ParseContext *c, int argStart, int retStart) +{ + char returnTypeBuffer[MAX_RETURN_BUFFER]; + int numArg, numRet; + int lenArg, lenRet; + char *sArgP, *sRetP; + int i; + + TypeData *argTP = &c->fTypeList[argStart]; + TypeData *retTP = &c->fTypeList[retStart]; + + // Rotate around the entries first + numArg = retTP->fStartEntry - argTP->fStartEntry; + numRet = retTP->fNumEntries; + lenArg = numArg * sizeof(BaseTypeData); + lenRet = numRet * sizeof(BaseTypeData); + + // Copy the return type into a buffer + if (lenRet > sizeof(returnTypeBuffer)) + return false; + + sArgP = (char *) (&c->fInEntries[argTP->fStartEntry]); + sRetP = (char *) (&c->fInEntries[retTP->fStartEntry]); + + bcopy(sRetP, returnTypeBuffer, lenRet); + bcopy(sArgP, sArgP + lenRet, lenArg); + bcopy(returnTypeBuffer, sArgP, lenRet); + + // Retarget the argument and return types for the new entry positions + lenArg = numArg; + lenRet = numRet; + numArg = retStart - argStart; + numRet = c->fP.fNumT - retStart; + for (i = 0; i < numArg; i++) + c->fTypeList[argStart+i].fStartEntry += lenRet; + for (i = 0; i < numRet; i++) + c->fTypeList[retStart+i].fStartEntry -= lenArg; + + // Rotate the BDictionary + for (i = 0; i < c->fP.fNumB; i++) { + TypeData *bDP = &c->fBDict[i]; + int start = bDP->fStartEntry; + + if (start >= argTP->fStartEntry) + bDP->fStartEntry = start + lenRet; + else if (start >= retTP->fStartEntry) + bDP->fStartEntry = start - lenArg; + } + + // Finally rotate the retargeted type structures. + lenArg = numArg * sizeof(TypeData); + lenRet = numRet * sizeof(TypeData); + + sArgP = (char *) (&c->fTypeList[argStart]); + sRetP = (char *) (&c->fTypeList[retStart]); + + bcopy(sRetP, returnTypeBuffer, lenRet); + bcopy(sArgP, sArgP + lenRet, lenArg); + bcopy(returnTypeBuffer, sArgP, lenRet); + + return true; +} + +// ::= "F" "_" +static Boolean parse_function_type(ParseContext *c, Boolean forMethod) +{ + TypeData *bDictP = 0; + BaseTypeData *bP = c->fCurBaseP; + + int argTypeStart, retTypeStart; + + if (!forMethod) { + bDictP = newBDict(c, c->fP.fNumI-1, 0); + if (!bDictP) + goto abandonParse; + } + + if (!isNext(c, 'F')) + goto abandonParse; + + bP->fType = kNTFunction; + + // Note that the argument types will advance the Entry list + argTypeStart = c->fP.fNumT; + if (!parse_argument_types(c)) + goto abandonParse; + + if (!isNext(c, '_')) + goto abandonParse; + + // Parse the return type + retTypeStart = c->fP.fNumT; + if (!parse_type(c)) + goto abandonParse; + + // gcc3 puts the return code just after the 'F' declaration + // as this impacts the order of the compression I need to rotate + // the return type and the argument types. + if (!rotateFunction(c, argTypeStart, retTypeStart)) + goto abandonParse; + + if (!forMethod) + bDictP->fNumEntries = c->fP.fNumI - bDictP->fStartEntry; + + return true; + +abandonParse: + return false; +} + +// To convert 2.95 method to a 3.0 method I need to prune the +// first argument of the function type out of the parse tree. +static Boolean cleanMethodFunction(ParseContext *c, int type) +{ + TypeData *typeP, *startTP, *endTP; + BaseTypeData *bP; + int i, thisStart, thisEnd, thisLen, funcRemain; + + // Get pointer for the return value's type. + startTP = &c->fTypeList[type+1]; + endTP = &c->fTypeList[c->fP.fNumT]; + + // Now look for the first type that starts after the return type + thisEnd = startTP->fStartEntry + startTP->fNumEntries; + for (startTP++; startTP < endTP; startTP++) + if (startTP->fStartEntry >= thisEnd) + break; + + if (startTP >= endTP) { + c->fRetCode = kR3InternalNotRemangled; + return false; // Internal error: should never happen + } + + // We now have a pointer to the 1st argument in the input list + // we will need to excise the entries from the input list and don't forget + // to remove the associated types from the type list. + + thisLen = startTP->fNumEntries; + thisStart = startTP->fStartEntry; + thisEnd = thisStart + thisLen; + funcRemain = c->fP.fNumI - thisEnd; + bP = &c->fInEntries[thisStart]; + + // If we have no arguments then replace the pointer with a void + if (!funcRemain) { + c->fP.fNumI -= (thisLen - 1); + + bP->fFundTypeID = (void *) (int) 'v'; // Void arg list + bP->fLen = 0; + bP->fType = kNTBuiltIn; + + // Update the type entry for the void argument list + startTP->fNumEntries = 1; + return true; + } + + // Move the argument list down to replace the 'this' pointer + bcopy(bP + thisLen, bP, funcRemain * sizeof(*bP)); + c->fP.fNumI -= thisLen; + + // And remove the 'this' pointers type + + // First walk over all of the types that have to be removed + for (typeP = startTP + 1; typeP < endTP; typeP++) + if (typeP->fStartEntry >= thisEnd) + break; + + if (typeP >= endTP) { + c->fRetCode = kR3InternalNotRemangled; + return false; // Internal error Can't be a void argument list. + } + + bcopy(typeP, startTP, (char *) endTP - (char *) typeP); + + c->fP.fNumT -= typeP - startTP; + endTP = &c->fTypeList[c->fP.fNumT]; + for (typeP = startTP ; typeP < endTP; typeP++) + typeP->fStartEntry -= thisLen; + + // Finally we can retarget the BDictionary lists + for (i = 0; i < c->fP.fNumB; i++) { + TypeData *bDP = &c->fBDict[i]; + int start = bDP->fStartEntry; + + if (start < thisStart) + continue; + if (start >= thisEnd) + break; + + bDP->fStartEntry = start - thisLen; + } + + return true; +} + +// ::= "M" +// +// Note this is a very bad function. Gcc3 doesn't doesn't use pointer that +// is immediately before this entry. We will have to delete the 'P' declarator +// that is before the method declaration. +// We will also have to prune the first type in the argument list as Gcc3 +// doesn't register the 'this' pointer within the function list. +static Boolean parse_method_type(ParseContext *c) +{ + TypeData *bDictP; + TypeData *typeP; + BaseTypeData *bP; + + bDictP = newBDict(c, c->fP.fNumI-2, 0); + if (!bDictP) + goto abandonParse; + + // Replace 'P' declarator + c->fP.fNumI--; + bP = c->fCurBaseP - 1; + + if (!isNext(c, 'M')) + goto abandonParse; + + if (bP->fFundTypeID != (void *) (int) 'P') + goto abandonParse; + + // Replace the previous 'Pointer' declarator + bP->fType = kNTMethod; + bP->fFundTypeID = NULL; + bP->fLen = 0; + + // Grab the method's 'this' type specification + typeP = newType(c, c->fP.fNumI); + if (!newIn(c) || !typeP) + goto abandonParse; + + if (!parse_class_name(c)) + goto abandonParse; + typeP->fNumEntries = c->fP.fNumI - typeP->fStartEntry; + + // Grab the specifier + typeP = newType(c, c->fP.fNumI); + if (!newIn(c) || !typeP) + goto abandonParse; + + if (!parse_function_type(c, /* forMethod */ true)) + goto abandonParse; + + if (!cleanMethodFunction(c, typeP - c->fTypeList)) + goto abandonParse; + typeP->fNumEntries = c->fP.fNumI - typeP->fStartEntry; + + // Finally update the dictionary with the M & 'this' + bDictP->fNumEntries = c->fP.fNumI - bDictP->fStartEntry; + + return true; + +abandonParse: + return false; +} + +static Boolean emitQualifiers(ParseContext *c) +{ + BaseTypeData *bP = c->fCurBaseP; + + if (bP->fVolatile || bP->fConst) { + Boolean isConst, isVolatile, isSigned, isUnsigned; + + isVolatile = bP->fVolatile; + isConst = bP->fConst; + isSigned = bP->fSigned; + isUnsigned = bP->fUnsigned; + bP->fConst = bP->fVolatile = bP->fSigned = bP->fUnsigned = 0; + + if (isVolatile) { + bP->fType = kNTDeclarator; + bP->fFundTypeID = (void *) (int) 'V'; + bP->fLen = 0; + bP = newIn(c); + if (!bP) + return false; + } + if (isConst) { + bP->fType = kNTDeclarator; + bP->fFundTypeID = (void *) (int) 'K'; + bP->fLen = 0; + bP = newIn(c); + if (!bP) + return false; + } + bP->fSigned = isSigned; + bP->fUnsigned = isUnsigned; + } + + return true; +} + + +// ::= ; function +// | ; method +// | * +// ::= "S" ; signed (chars only) +// | "U" ; unsigned (any integral type) +// | "J" ; __complex +// | +static Boolean parse_base_type(ParseContext *c) +{ + if ('F' == peekNext(c)) { + if (!parse_function_type(c, /* forMethod */ false)) + goto abandonParse; + } + else if ('M' == peekNext(c)) { + if (!parse_method_type(c)) + goto abandonParse; + } + else { + // | * + BaseTypeData *bP = c->fCurBaseP; + for (;;) { + if (isNext(c, 'S')) + // ::= "S" ; signed (chars only) + { bP->fSigned = true; continue; } + else if (isNext(c, 'U')) + // | "U" ; unsigned (any integral type) + { bP->fUnsigned = true; continue; } + else if (isNext(c, 'C')) + // | + // ::= "C" ; const + { bP->fConst = true; continue; } + else if (isNext(c, 'V')) + // | "V" ; volatile + { bP->fVolatile = true; continue; } + else if (charNext(c, "Ju")) + goto abandonParse; // Don't support these qualifiers + // | "J" ; __complex + // | "u" ; restrict (C99) + else + break; + } + + if (!emitQualifiers(c)) + goto abandonParse; + + if (!parse_fund_type_id(c)) + goto abandonParse; + } + return true; + +abandonParse: + return false; +} + +// Use the top SDict as a stack of declarators. +// parses * +// ::= "P" ; pointer +// | "p" ; pointer (but never occurs?) +// | "R" ; reference (&) +// | "A" ; array +// | "T" +// | "O" +// | +// +// As a side-effect the fCurBaseP is setup with any qualifiers on exit +static Boolean parse_declarators(ParseContext *c) +{ + int count; + BaseTypeData *dP; + + // Note we MUST go through the for loop at least once + for (count = 0; ; count++) { + const char *curDecl; + char ch; + + if (!newIn(c)) + goto abandonParse; + + // ::= production + if (!parse_qualifiers(c) || !emitQualifiers(c)) + goto abandonParse; + + dP = c->fCurBaseP; // Find the current base type pointer + + curDecl = c->fP.fInChar; + + switch (peekNext(c)) { + + case 'P': case 'p': case 'R': + // ::= "P" ; pointer + // | "p" ; pointer (but never occurs?) + // | "R" ; reference (&) + + dP->fType = kNTDeclarator; + advance(c, 1); + + ch = *curDecl; + if ('p' == ch) ch = 'P'; + dP->fFundTypeID = (void *) (int) ch; + dP->fLen = 0; + continue; // Go around again + + case 'A': + // | "A" ; array + dP->fType = kNTArray; + + advance(c, 1); curDecl++; + curDecl = (void *) + strtoul(curDecl, (char **) &c->fP.fInChar, 10); + if (!curDecl) + goto abandonParse; + dP->fFundTypeID = curDecl; + dP->fLen = 0; + continue; // Go around again + + case 'T': case 'O': + // | "T" Unsupported + // | "O" Unsupported + goto abandonParse; + + default: + break; + } + + break; + } + + dP->fLen = 0; + return true; + +abandonParse: + return false; +} + +// ::= * +static Boolean parse_type(ParseContext *c) +{ + CheckPoint chk = *checkPoint(c); + TypeData *typeP = newType(c, c->fP.fNumI); + if (!typeP) + goto abandonParse; + + // As a side-effect the fCurBaseP is setup with any qualifiers on exit + if (!parse_declarators(c)) + goto abandonParse; + + // Merge the last qualifiers into the base type + if (!parse_base_type(c) || kNTUndefined == c->fCurBaseP->fType) + goto abandonParse; + + typeP->fNumEntries = c->fP.fNumI - typeP->fStartEntry; + return true; + +abandonParse: + resetTo(c, &chk); + return false; +} + +// ::= * +// No need to check point as an invalid function name is fatal +// Consumes trailing "__". +static Boolean +parse_function_name(ParseContext *c) +{ + char ch; + + while ( (ch = peekNext(c)) ) + { + advance(c, 1); + if ('_' == ch && '_' == peekNext(c)) { + do { + advance(c, 1); + } while ('_' == peekNext(c)); + return true; + } + } + + return false; +} + +// ::= "type" +// | "__op" +// | "__" ; Implies null function name +// | "a" +// ::= "aa" # && ==> "aa" +// | "aad" # &= ==> "aN" +// | "ad" # & ==> "ad" +// | "adv" # /= ==> "dV" +// | "aer" # ^= ==> "eO" +// | "als" # <<= ==> "lS" +// | "amd" # %= ==> "rM" +// | "ami" # -= ==> "mI" +// | "aml" # *= ==> "mL +// | "aor" # |= ==> "oR +// | "apl" # += ==> "pL +// | "ars" # >>= ==> "rS +// | "as" # = ==> "aS +// | "cl" # () ==> "cl +// | "cm" # , ==> "cm +// | "cn" # ?: ==> "qu +// | "co" # ~ ==> "co +// | "dl" # delete ==> "dl +// | "dv" # / ==> "dv +// | "eq" # == ==> "eq +// | "er" # ^ ==> "eo +// | "ge" # >= ==> "ge +// | "gt" # > ==> "gt +// | "le" # <= ==> "le +// | "ls" # << ==> "ls +// | "lt" # < ==> "lt +// | "md" # % ==> "rm +// | "mi" # - ==> "mi +// | "ml" # * ==> "ml +// | "mm" # -- ==> "mm +// | "mn" # "???????????????? +// | "mx" # >? ==> "???????????????? +// | "ne" # != ==> "ne +// | "nt" # ! ==> "nt +// | "nw" # new ==> "nw +// | "oo" # || ==> "oo" +// | "or" # | ==> "or +// | "pl" # + ==> "pl +// | "pp" # ++ ==> "pp +// | "rf" # -> ==> "pt +// | "rm" # ->* ==> "pm +// | "rs" # >> ==> "rs +// | "sz" # sizeof ==> "sz +// | "vc" # [] ==> "ix +// | "vd" # delete[] ==> "da +// | "vn" # new[] ==> "na +static struct opMap { + const char *op295, *op3; +} opMapTable[] = { + {"aad", "aN" }, {"adv", "dV" }, {"aer", "eO" }, {"als", "lS" }, + {"amd", "rM" }, {"ami", "mI" }, {"aml", "mL" }, {"aor", "oR" }, + {"apl", "pL" }, {"ars", "rS" }, {"aa", "aa" }, {"ad", "ad" }, + {"as", "aS" }, {"cl", "cl" }, {"cm", "cm" }, {"cn", "qu" }, + {"co", "co" }, {"dl", "dl" }, {"dv", "dv" }, {"eq", "eq" }, + {"er", "eo" }, {"ge", "ge" }, {"gt", "gt" }, {"le", "le" }, + {"ls", "ls" }, {"lt", "lt" }, {"md", "rm" }, {"mi", "mi" }, + {"ml", "ml" }, {"mm", "mm" }, {"mn", NULL }, {"mx", NULL }, + {"ne", "ne" }, {"nt", "nt" }, {"nw", "nw" }, {"oo", "oo" }, + {"or", "or" }, {"pl", "pl" }, {"pp", "pp" }, {"rf", "pt" }, + {"rm", "pm" }, {"rs", "rs" }, {"sz", "sz" }, {"vc", "ix" }, + {"vd", "da" }, {"vn", "na" }, +}; + +static Boolean parse_opinfo(ParseContext *c, const char **opInfoP) +{ + CheckPoint chk = *checkPoint(c); + const char *op; + char ch; + int i; + + if ('a' == (ch = peekNext(c))) { + goto abandonParse; + } + else if (strNext(c, "type")) { + goto abandonParse; + } + else if (retard(c, 4) && strNext(c, "____op")) { + // @@@ gvdl: check this out it may change + // ::= "__op" + goto abandonParse; + } + + // Failed till now so reset and see if we have an operator + resetTo(c, &chk); + + // quick check to see if we may have an operator + if (!strrchr("acdeglmnoprsv", peekNext(c))) + goto abandonParse; + + op = NULL; + for (i = 0; i < sizeof(opMapTable)/sizeof(opMapTable[0]); i++) { + if (strNext(c, opMapTable[i].op295)) { + op = opMapTable[i].op3; + break; + } + } + if (!op) + goto abandonParse; + + if (!strNext(c, "__")) // Trailing underbars + goto abandonParse; + + if (opInfoP) + *opInfoP = op; + return true; + +abandonParse: + return false; +} + +// ::= * +// ::= +// | "K" +// | "S" +// | "F" [ "_" ] +// ::= +// Treat the prefix's s_element as a full type +static Boolean +parse_signature(ParseContext *c, + const char *func, int funcLen, const char *op) +{ + BaseTypeData *bP; + TypeData *tP; + + Boolean isFunction = false; + + if (isNext(c, 'F')) { + // | "F" [ "_" ] + + char numbuf[16]; // Bigger than MAX_INT + 4 + int len; + isFunction = true; + if (!funcLen) + goto abandonParse; + + len = snprintf(numbuf, sizeof(numbuf), "__Z%d", funcLen); + + appendNStr(c, numbuf, len); + appendNStr(c, func, funcLen); + } + else if (isNext(c, 'S')) { + // | "S" ; Ignored + goto abandonParse; + } + else { + const char *qual; + int qualLen; + + // See if we can find a qualified class reference + tP = newType(c, c->fP.fNumI); + if (!tP) + goto abandonParse; + + bP = newIn(c); + if (!bP) + goto abandonParse; + + // Parse any qualifiers, store results in *fCurBaseP + bP->fPseudo = true; + if (!parse_qualifiers(c)) + goto abandonParse; + + if (!parse_class_name(c)) + goto abandonParse; + + bP = c->fCurBaseP; // class name may have redifined current + tP->fNumEntries = c->fP.fNumI - tP->fStartEntry; + + APPENDSTR(c, "__ZN"); + decodeQual(bP, &qualLen, &qual); + if (qualLen) + appendNStr(c, qual, qualLen); + appendNStr(c, bP->fFundTypeID, bP->fLen); + + if (funcLen) { + char numbuf[16]; // Bigger than MAX_INT + 1 + int len; + + len = snprintf(numbuf, sizeof(numbuf), "%d", funcLen); + appendNStr(c, numbuf, len); + appendNStr(c, func, funcLen); + } + else if (op) + appendStr(c, op); + else { + // No function & no op means constructor choose one of C1 & C2 + APPENDSTR(c, "C2"); + } + appendChar(c, 'E'); + } + + if (atEnd(c)) { + appendChar(c, 'v'); // void argument list + c->fRetCode = kR3Remangled; + return true; + } + + c->fCurBaseP = NULL; + if (!parse_argument_types(c)) + goto abandonParse; + + if (isFunction) { + if (isNext(c, '_')) { + // && !parse_type(c) @@@ gvdl: Unsupported return + c->fRetCode = kR3InternalNotRemangled; + goto abandonParse; + } + } + + if (!atEnd(c)) + goto abandonParse; + + // OK we have a complete and successful parse now output the + // argument list + return appendArgumentList(c); + +abandonParse: + return false; +} + +// ::= [ ] +// ::= [ "_GLOBAL_" [ID] "__" ] "__" [ ] +static Boolean parse_mangled_name(ParseContext *c) +{ + CheckPoint chk; + CheckPoint dubBarChk; + const char *func; + + // parse + if (strNext(c, "_GLOBAL_")) { // Is this GLOBAL static constructor? + // gvdl: can't deal with _GLOBAL_ + c->fRetCode = kR3InternalNotRemangled; + return false; // Can't deal with these + } + + func = c->fP.fInChar; + for (chk = *checkPoint(c); ; resetTo(c, &dubBarChk)) { + int funcLen; + const char *op = NULL; + + if (!parse_function_name(c)) + goto abandonParse; + dubBarChk = *checkPoint(c); + + // Note that the opInfo may be earlier than the curDoubleBar + // in which case the function name may need to be shrunk later on. + (void) parse_opinfo(c, &op); + + if (atEnd(c)) + goto abandonParse; // No Signature? + + funcLen = inCharFromCheck(c, &dubBarChk) - func - 2; + if (parse_signature(c, func, funcLen, op)) + return true; + + if (kR3NotRemangled != c->fRetCode) + goto abandonParse; + + // If no error then try again maybe another '__' exists + } + +abandonParse: + resetTo(c, &chk); + return false; +} + +// ::= ("_._" | "_$_" ) ; destructor +// | "__vt_" ; virtual table +// | "_" ("."|"$") +static Boolean parse_gnu_special(ParseContext *c) +{ + CheckPoint chk = *checkPoint(c); + BaseTypeData *bP = newIn(c); + + if (!bP) + return false; + + // What do the intel desctructors look like + if (strNext(c, "_._") || strNext(c, "_$_") ) // Is this a destructor + { + if (!parse_class_name(c) || !atEnd(c)) + goto abandonParse; + APPENDSTR(c, "__ZN"); + appendNStr(c, bP->fFundTypeID, bP->fLen); + APPENDSTR(c, "D2Ev"); + c->fRetCode = kR3Remangled; + return true; + } + else if (strNext(c, "__vt_")) // Is it's a vtable? + { + if (!parse_class_name(c) || !atEnd(c)) + goto abandonParse; + + APPENDSTR(c, "__ZTV"); + if (kNTClass != bP->fType) + goto abandonParse; + else if (bP->fQualified) { + appendChar(c, 'N'); + appendNStr(c, bP->fFundTypeID, bP->fLen); + appendChar(c, 'E'); + } + else + appendNStr(c, bP->fFundTypeID, bP->fLen); + + c->fRetCode = kR3Remangled; + return true; + } + else if (isNext(c, '_')) // Maybe it's a variable + { + const char *varname; + int varlen, len; + char numbuf[16]; // Bigger than MAX_INT + 1 + + if (!parse_class_name(c)) // Loads up the bP structure + goto abandonParse; + + if (!isNext(c, '.') && !isNext(c, '$')) + goto abandonParse; + + // Parse the variable name now. + varname = c->fP.fInChar; + if (atEnd(c) || !isValidFirstChar(getNext(c))) + goto abandonParse; + + while ( !atEnd(c) ) + if (!isValidChar(getNext(c))) + goto abandonParse; + + varlen = c->fP.fInChar - varname; + len = snprintf(numbuf, sizeof(numbuf), "%d", varlen); + + APPENDSTR(c, "__ZN"); + appendNStr(c, bP->fFundTypeID, bP->fLen); + + appendNStr(c, numbuf, len); + appendNStr(c, varname, varlen); + appendChar(c, 'E'); + + c->fRetCode = kR3Remangled; + return true; + } + + // Oh well it is none of those so give up but reset scan +abandonParse: + resetTo(c, &chk); + return false; +} + +// ::= +// | +static Boolean parse_special_or_name(ParseContext *c) +{ + Boolean res; + + + res = (parse_gnu_special(c) || parse_mangled_name(c)); + appendChar(c, '\0'); + + return res; +} + +Rem3Return rem3_remangle_name(char *gcc3, int *gcc3size, const char *gcc295) +{ + ParseContext *c; + Rem3Return result; + int size; + + if (!gcc295 || !gcc3 || !gcc3size) + return kR3BadArgument; + + size = strlen(gcc295); + if (size < 2) + return kR3NotRemangled; // Not a valid C++ symbol + else if (*gcc295 != '_') + return kR3NotRemangled; // no leading '_', not valid + + c = (ParseContext *) malloc(sizeof(*c)); + if (!c) + return kR3InternalNotRemangled; + bzero(c, sizeof(*c)); + + c->fInSize = size; + c->fInStr = gcc295 + 1; // Strip leading '_' + c->fP.fInChar = c->fInStr; + + c->fOutStrEnd = gcc3 + *gcc3size; + c->fOutChar = gcc3; + + c->fRetCode = kR3NotRemangled; + (void) parse_special_or_name(c); + + result = c->fRetCode; + if (kR3Remangled == result) { + if (c->fOutChar > c->fOutStrEnd) + result = kR3BufferTooSmallRemangled; + *gcc3size = c->fOutChar - gcc3 - 1; // Remove nul from len + } + + free(c); + + return result; +} diff --git a/libsa/c++rem3.h b/libsa/c++rem3.h new file mode 100644 index 000000000..9f37019d6 --- /dev/null +++ b/libsa/c++rem3.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.0 (the 'License'). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License." + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * History: + * 2002-02-26 gvdl Initial implementation of the gcc 2.95 -> gcc 3.x + * symbol remangler. + */ + +#include + +typedef enum Rem3Return { + kR3NotRemangled = 0, // Wasn't a 2.95 C++ symbol but otherwise OK + kR3Remangled, // Was sucessfully remangled from 2.95 -> 3.x + kR3InternalNotRemangled, // Symbol is too big to be parsed + kR3BufferTooSmallRemangled, // Is 2.95 symbol but insufficent output space + kR3BadArgument, // One of the pointers are NULL +} Rem3Return; + +__BEGIN_DECLS + +extern Rem3Return +rem3_remangle_name(char *gcc3, int *gcc3size, const char *gcc295); + +__END_DECLS diff --git a/libsa/catalogue.cpp b/libsa/catalogue.cpp index 2de5325bd..e9c301939 100644 --- a/libsa/catalogue.cpp +++ b/libsa/catalogue.cpp @@ -425,7 +425,6 @@ OSDictionary * readExtension(OSDictionary * propertyDict, kmod_info_t * loaded_kmod = NULL; - bootxDriverDataObject = OSDynamicCast(OSData, propertyDict->getObject(memory_map_name)); // don't release bootxDriverDataObject @@ -490,7 +489,7 @@ OSDictionary * readExtension(OSDictionary * propertyDict, /* Check if kmod is already loaded and is a real loadable one (has * an address). */ - loaded_kmod = kmod_lookupbyname(driverName->getCStringNoCopy()); + loaded_kmod = kmod_lookupbyname_locked(driverName->getCStringNoCopy()); if (loaded_kmod && loaded_kmod->address) { IOLog("Skipping new extension \"%s\"; an extension named " "\"%s\" is already loaded.\n", @@ -539,6 +538,10 @@ OSDictionary * readExtension(OSDictionary * propertyDict, finish: + if (loaded_kmod) { + kfree(loaded_kmod, sizeof(kmod_info_t)); + } + // do not release bootxDriverDataObject // do not release driverName @@ -623,11 +626,12 @@ static bool uncompressFile(u_int8_t *base_address, mkext_file * fileinfo, result = false; goto finish; } + uncompressed_file[uncompressed_size] = '\0'; } else { bcopy(base_address + offset, uncompressed_file, - compsize); + realsize); + uncompressed_file[realsize] = '\0'; } - uncompressed_file[uncompressed_size] = '\0'; *file = uncompressedFile; @@ -669,6 +673,8 @@ bool extractExtensionsFromArchive(MemoryMapFileInfo * mkext_file_info, mkext_kext * onekext_data = 0; // don't free mkext_file * plist_file = 0; // don't free mkext_file * module_file = 0; // don't free + kmod_info_t * loaded_kmod = 0; // must free + OSData * driverPlistDataObject = 0; // must release OSDictionary * driverPlist = 0; // must release OSData * driverCode = 0; // must release @@ -748,7 +754,10 @@ bool extractExtensionsFromArchive(MemoryMapFileInfo * mkext_file_info, i < OSSwapBigToHostInt32(mkext_data->numkexts); i++) { - kmod_info_t * loaded_kmod = 0; + if (loaded_kmod) { + kfree(loaded_kmod, sizeof(kmod_info_t)); + loaded_kmod = 0; + } if (driverPlistDataObject) { driverPlistDataObject->release(); @@ -830,7 +839,7 @@ bool extractExtensionsFromArchive(MemoryMapFileInfo * mkext_file_info, /* Check if kmod is already loaded and is a real loadable one (has * an address). */ - loaded_kmod = kmod_lookupbyname(moduleName->getCStringNoCopy()); + loaded_kmod = kmod_lookupbyname_locked(moduleName->getCStringNoCopy()); if (loaded_kmod && loaded_kmod->address) { IOLog("Skipping new extension \"%s\"; an extension named " "\"%s\" is already loaded.\n", @@ -922,6 +931,7 @@ bool extractExtensionsFromArchive(MemoryMapFileInfo * mkext_file_info, finish: + if (loaded_kmod) kfree(loaded_kmod, sizeof(kmod_info_t)); if (driverPlistDataObject) driverPlistDataObject->release(); if (driverPlist) driverPlist->release(); if (driverCode) driverCode->release(); @@ -1077,8 +1087,8 @@ bool addExtensionsFromArchive(OSData * mkextDataObject) { startupExtensions = getStartupExtensions(); if (!startupExtensions) { - IOLog("Can't record extension archive; there is no - extensions dictionary.\n"); + IOLog("Can't record extension archive; there is no" + " extensions dictionary.\n"); LOG_DELAY(); result = false; goto finish; @@ -1254,7 +1264,6 @@ bool recordStartupExtensions(void) { while ( (key = OSDynamicCast(OSString, keyIterator->getNextObject())) ) { - /* Clear newDriverDict & mkextExtensions upon entry to the loop, * handling both successful and unsuccessful iterations. */ @@ -1381,7 +1390,7 @@ bool recordStartupExtensions(void) { // Do not release key. - } /* while ( (key = OSDynamicCast(OSString, ... */ + } /* while ( (key = OSDynamicCast(OSString, ...) ) ) */ if (!mergeExtensionDictionaries(existingExtensions, startupExtensions)) { IOLog("Error: Failed to merge new extensions into existing set.\n"); @@ -1483,8 +1492,8 @@ void removeStartupExtension(const char * extensionName) { keyIterator = OSCollectionIterator::withCollection( extensionPersonalities); if (!keyIterator) { - IOLog("Error: Couldn't allocate iterator to scan - personalities for %s.\n", extensionName); + IOLog("Error: Couldn't allocate iterator to scan" + " personalities for %s.\n", extensionName); LOG_DELAY(); } diff --git a/libsa/conf/Makefile b/libsa/conf/Makefile index 85e1a341a..ffeab35e7 100644 --- a/libsa/conf/Makefile +++ b/libsa/conf/Makefile @@ -47,14 +47,13 @@ do_setup_conf: $(OBJROOT)/$(KERNEL_CONFIG)_$(ARCH_CONFIG)/$(COMPONENT)/doconf \ do_all: do_setup_conf @echo "[ $(SOURCE) ] Starting do_all $(COMPONENT) $(LIBKERN_KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)"; \ - (cd $(COMPOBJROOT)/$(LIBKERN_KERNEL_CONFIG); \ next_source=$(subst conf/,,$(SOURCE)); \ - ${MAKE} MAKEFILES=$(TARGET)/$(LIBKERN_KERNEL_CONFIG)/Makefile \ + ${MAKE} -C $(COMPOBJROOT)/$(LIBKERN_KERNEL_CONFIG) \ + MAKEFILES=$(TARGET)/$(LIBKERN_KERNEL_CONFIG)/Makefile \ SOURCE=$${next_source} \ TARGET=$(TARGET) \ INCL_MAKEDEP=FALSE \ - build_all \ - ); \ + build_all; \ echo "[ $(SOURCE) ] Returning do_all $(COMPONENT) $(LIBKERN_KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)"; do_build_all: do_all diff --git a/libsa/conf/files b/libsa/conf/files index 13ac0d965..5bb1c0bad 100644 --- a/libsa/conf/files +++ b/libsa/conf/files @@ -7,6 +7,7 @@ libsa/bootstrap.cpp standard libsa/catalogue.cpp standard +libsa/c++rem3.c standard libsa/kld_patch.c standard libsa/kmod.cpp standard libsa/mach.c standard @@ -19,3 +20,4 @@ libsa/bsearch.c standard libsa/malloc.c standard libsa/sort.c standard libsa/strrchr.c standard +libsa/strstr.c standard diff --git a/libsa/conf/tools/doconf/doconf.csh b/libsa/conf/tools/doconf/doconf.csh index 43388c11c..ae5ab908b 100755 --- a/libsa/conf/tools/doconf/doconf.csh +++ b/libsa/conf/tools/doconf/doconf.csh @@ -287,7 +287,7 @@ part != 0 {\ # kernel binaries are put). # echo 'builddir "."' >> $SYSCONF.new - set OBJRELDIR=`relpath $OBJROOT $OBJDIR` + set OBJRELDIR=`$RELPATH $OBJROOT $OBJDIR` echo 'objectdir "'$OBJROOT'/'$OBJRELDIR'"' >> $SYSCONF.new set SRCDIR=`dirname $SOURCE` echo 'sourcedir "'$SRCROOT'"' >> $SYSCONF.new diff --git a/libsa/conf/version.major b/libsa/conf/version.major index 7ed6ff82d..1e8b31496 100644 --- a/libsa/conf/version.major +++ b/libsa/conf/version.major @@ -1 +1 @@ -5 +6 diff --git a/libsa/conf/version.minor b/libsa/conf/version.minor index 7ed6ff82d..573541ac9 100644 --- a/libsa/conf/version.minor +++ b/libsa/conf/version.minor @@ -1 +1 @@ -5 +0 diff --git a/libsa/conf/version.variant b/libsa/conf/version.variant index 8b1378917..e69de29bb 100644 --- a/libsa/conf/version.variant +++ b/libsa/conf/version.variant @@ -1 +0,0 @@ - diff --git a/libsa/kld_patch.c b/libsa/kld_patch.c index 646bf14d7..862be7f96 100644 --- a/libsa/kld_patch.c +++ b/libsa/kld_patch.c @@ -57,7 +57,10 @@ extern load_return_t fatfile_getarch( vm_offset_t data_ptr, struct fat_arch * archret); +__private_extern__ char *strstr(const char *in, const char *str); + #else /* !KERNEL */ + #include #include @@ -68,6 +71,7 @@ extern load_return_t fatfile_getarch( #include #include #include +#include #include #include @@ -75,16 +79,26 @@ extern load_return_t fatfile_getarch( #include #include - + +#define PAGE_SIZE vm_page_size +#define PAGE_MASK (PAGE_SIZE - 1) + #endif /* KERNEL */ #include "kld_patch.h" +#include "c++rem3.h" #if 0 -static __inline__ void DIE(void) { IODelay(2000000000); } +#define DIE() do { for (;;) ; } while(0) + +#if KERNEL +# define LOG_DELAY() /* IODelay(200000) */ +# define DEBUG_LOG(x) do { IOLog x; LOG_DELAY(); } while(0) +#else +# define LOG_DELAY() +# define DEBUG_LOG(x) do { printf x; } while(0) +#endif -#define LOG_DELAY() IODelay(200000) -#define DEBUG_LOG(x) do { IOLog x; LOG_DELAY(); } while(0) #else #define DIE() @@ -94,10 +108,13 @@ static __inline__ void DIE(void) { IODelay(2000000000); } #endif // OSObject symbol prefixes and suffixes -#define kVTablePrefix "___vt" -#define kReservedPrefix "__RESERVED" -#define kSuperClassSuffix ".superClass" -#define kGMetaSuffix ".gMetaClass" +#define kCPPSymbolPrefix "_Z" +#define kVTablePrefix "_" kCPPSymbolPrefix "TV" +#define kOSObjPrefix "_" kCPPSymbolPrefix "N" +#define kReservedNamePrefix "_RESERVED" +#define k29SuperClassSuffix "superClass" +#define k31SuperClassSuffix "10superClassE" +#define kGMetaSuffix "10gMetaClassE" #define kLinkEditSegName SEG_LINKEDIT // GCC 2.95 drops 2 leading constants in the vtable @@ -181,21 +198,25 @@ struct metaClassRecord { struct fileRecord { size_t fMapSize, fMachOSize; - const char *fPath; unsigned char *fMap, *fMachO, *fPadEnd; DataRef fClassList; DataRef fSectData; - DataRef fNewSymbols, fNewStrings; + DataRef fNewSymbols, fNewStringBlocks; + DataRef fSym2Strings; struct symtab_command *fSymtab; struct sectionRecord *fSections; + struct segment_command *fLinkEditSeg; + const char **fSymbToStringTable; char *fStringBase; struct nlist *fSymbolBase; const struct nlist *fLocalSyms; unsigned int fNSects; int fNLocal; - int fNewStringsLen; Boolean fIsKernel, fNoKernelExecutable, fIsKmem; Boolean fImageDirty, fSymbolsDirty; + Boolean fRemangled, fFoundOSObject; + Boolean fIgnoreFile; + const char fPath[1]; }; static DataRef sFilesTable; @@ -228,17 +249,59 @@ static __inline__ unsigned char *DataGetPtr(DataRef data) return data->fData; } +static __inline__ unsigned char *DataGetEndPtr(DataRef data) +{ + return data->fData + data->fLength; +} + +static __inline__ unsigned long DataRemaining(DataRef data) +{ + return data->fCapacity - data->fLength; +} static __inline__ Boolean DataContainsAddr(DataRef data, void *vAddr) { - unsigned char *addr = vAddr; + vm_offset_t offset = (vm_address_t) vAddr; + + if (!data) + return false; + + offset = (vm_address_t) vAddr - (vm_address_t) data->fData; + return (offset < data->fLength); +} + +static Boolean DataEnsureCapacity(DataRef data, unsigned long capacity) +{ + // Don't bother to ever shrink a data object. + if (capacity > data->fCapacity) { + unsigned char *newData; + + capacity += kDataCapacityIncrement - 1; + capacity &= ~(kDataCapacityIncrement - 1); + newData = (unsigned char *) realloc(data->fData, capacity); + if (!newData) + return false; + + bzero(newData + data->fCapacity, capacity - data->fCapacity); + data->fData = newData; + data->fCapacity = capacity; + } + + return true; +} - return (data->fData <= addr) && (addr < data->fData + data->fLength); +static __inline__ Boolean DataSetLength(DataRef data, unsigned long length) +{ + if (DataEnsureCapacity(data, length)) { + data->fLength = length; + return true; + } + else + return false; } static __inline__ Boolean DataAddLength(DataRef data, unsigned long length) { - static Boolean DataSetLength(DataRef data, unsigned long length); return DataSetLength(data, data->fLength + length); } @@ -259,37 +322,15 @@ static __inline__ Boolean DataAppendData(DataRef dst, DataRef src) return DataAppendBytes(dst, DataGetPtr(src), DataGetLength(src)); } -static Boolean DataSetLength(DataRef data, unsigned long length) -{ - // Don't bother to ever shrink a data object. - if (length > data->fCapacity) { - unsigned char *newData; - unsigned long newCapacity; - - newCapacity = length + kDataCapacityIncrement - 1; - newCapacity &= ~(kDataCapacityIncrement - 1); - newData = (unsigned char *) realloc(data->fData, newCapacity); - if (!newData) - return false; - - bzero(newData + data->fCapacity, newCapacity - data->fCapacity); - data->fData = newData; - data->fCapacity = newCapacity; - } - - data->fLength = length; - return true; -} - -static DataRef DataCreate(unsigned long length) +static DataRef DataCreate(unsigned long capacity) { DataRef data = (DataRef) malloc(sizeof(Data)); if (data) { - if (!length) + if (!capacity) data->fCapacity = kDataCapacityIncrement; else { - data->fCapacity = length + kDataCapacityIncrement - 1; + data->fCapacity = capacity + kDataCapacityIncrement - 1; data->fCapacity &= ~(kDataCapacityIncrement - 1); } @@ -300,7 +341,7 @@ static DataRef DataCreate(unsigned long length) } bzero(data->fData, data->fCapacity); - data->fLength = length; + data->fLength = 0; } return data; } @@ -315,25 +356,34 @@ static void DataRelease(DataRef data) } } -static const char * +static __inline__ const char * +symNameByIndex(const struct fileRecord *file, unsigned int symInd) +{ + return file->fSymbToStringTable[symInd]; +} + +static __inline__ const char * symbolname(const struct fileRecord *file, const struct nlist *sym) { - unsigned long strsize; - long strx = sym->n_un.n_strx; + unsigned int index; - if (strx >= 0) - return file->fStringBase + strx; + index = sym - file->fSymbolBase; + if (index < file->fSymtab->nsyms) + return symNameByIndex(file, index); - strsize = file->fSymtab->strsize; - strx = -strx; - if (strx < strsize) - return file->fStringBase + strx; + if (-1 == sym->n_un.n_strx) + return (const char *) sym->n_value; - strx -= strsize; - return (char *) DataGetPtr(file->fNewStrings) + strx; + // If the preceding tests fail then we have a getNewSymbol patch and + // the file it refers to has already been patched as the n_strx is set + // to -1 temporarily while we are still processing a file. + // Once we have finished with a file then we repair the 'strx' offset + // to be valid for the repaired file's string table. + return file->fStringBase + sym->n_un.n_strx; } -static struct fileRecord *getFile(const char *path) +static struct fileRecord * +getFile(const char *path) { if (sFilesTable) { int i, nfiles; @@ -351,7 +401,8 @@ static struct fileRecord *getFile(const char *path) return NULL; } -static struct fileRecord * addFile(struct fileRecord *file) +static struct fileRecord * +addFile(struct fileRecord *file, const char *path) { struct fileRecord *newFile; @@ -361,7 +412,8 @@ static struct fileRecord * addFile(struct fileRecord *file) return NULL; } - newFile = (struct fileRecord *) malloc(sizeof(struct fileRecord)); + newFile = (struct fileRecord *) + malloc(sizeof(struct fileRecord) + strlen(path)); if (!newFile) return NULL; @@ -370,19 +422,16 @@ static struct fileRecord * addFile(struct fileRecord *file) return NULL; } - bcopy(file, newFile, sizeof(struct fileRecord)); + bcopy(file, newFile, sizeof(struct fileRecord) - 1); + strcpy((char *) newFile->fPath, path); + return newFile; } // @@@ gvdl: need to clean up the sMergeMetaClasses // @@@ gvdl: I had better fix the object file up again -static void removeFile(struct fileRecord *file) +static void unmapFile(struct fileRecord *file) { - if (file->fClassList) { - DataRelease(file->fClassList); - file->fClassList = 0; - } - if (file->fSectData) { struct sectionRecord *section; unsigned int i, nsect; @@ -402,6 +451,11 @@ static void removeFile(struct fileRecord *file) file->fNSects = 0; } + if (file->fSym2Strings) { + DataRelease(file->fSym2Strings); + file->fSym2Strings = 0; + } + if (file->fMap) { #if KERNEL if (file->fIsKmem) @@ -421,16 +475,26 @@ static void removeFile(struct fileRecord *file) #endif /* !KERNEL */ file->fMap = 0; } +} + +static void removeFile(struct fileRecord *file) +{ + if (file->fClassList) { + DataRelease(file->fClassList); + file->fClassList = 0; + } - file->fPath = 0; + unmapFile(file); + + free(file); } #if !KERNEL static Boolean -mapObjectFile(struct fileRecord *file) +mapObjectFile(struct fileRecord *file, const char *pathName) { Boolean result = false; - static unsigned char *sFileMapBaseAddr; + static unsigned char *sFileMapBaseAddr = 0; int fd = 0; @@ -452,9 +516,9 @@ mapObjectFile(struct fileRecord *file) sFileMapBaseAddr = (unsigned char *) probeAddr; } - fd = open(file->fPath, O_RDONLY, 0); + fd = open(pathName, O_RDONLY, 0); return_if(fd == -1, false, ("Can't open %s for reading - %s\n", - file->fPath, strerror(errno))); + pathName, strerror(errno))); do { kern_return_t ret; @@ -501,7 +565,7 @@ mapObjectFile(struct fileRecord *file) munmap(file->fMap, file->fMapSize); break_if(KERN_INVALID_ADDRESS != ret, ("Unable to allocate pad vm for %s - %s\n", - file->fPath, mach_error_string(ret))); + pathName, mach_error_string(ret))); file->fMap = (unsigned char *) padVMEnd; continue; // try again wherever the vm system wants @@ -523,7 +587,7 @@ mapObjectFile(struct fileRecord *file) } #endif /* !KERNEL */ -static Boolean findBestArch(struct fileRecord *file) +static Boolean findBestArch(struct fileRecord *file, const char *pathName) { unsigned long magic; struct fat_header *fat; @@ -536,7 +600,7 @@ static Boolean findBestArch(struct fileRecord *file) // Try to figure out what type of file this is return_if(file->fMapSize < sizeof(unsigned long), false, - ("%s isn't a valid object file - no magic\n", file->fPath)); + ("%s isn't a valid object file - no magic\n", pathName)); #if KERNEL @@ -548,7 +612,7 @@ static Boolean findBestArch(struct fileRecord *file) load_return = fatfile_getarch(NULL, (vm_address_t) fat, &fatinfo); return_if(load_return != LOAD_SUCCESS, false, - ("Extension \"%s\": has no code for this computer\n", file->fPath)); + ("Extension \"%s\": has no code for this computer\n", pathName)); file->fMachO = file->fMap + fatinfo.offset; file->fMachOSize = fatinfo.size; @@ -588,15 +652,15 @@ static Boolean findBestArch(struct fileRecord *file) fatsize = sizeof(struct fat_header) + fat->nfat_arch * sizeof(struct fat_arch); return_if(file->fMapSize < fatsize, - false, ("%s isn't a valid fat file\n", file->fPath)); + false, ("%s isn't a valid fat file\n", pathName)); myArch = NXGetLocalArchInfo(); arch = NXFindBestFatArch(myArch->cputype, myArch->cpusubtype, (struct fat_arch *) &fat[1], fat->nfat_arch); return_if(!arch, - false, ("%s hasn't got arch for %s\n", file->fPath, myArch->name)); + false, ("%s hasn't got arch for %s\n", pathName, myArch->name)); return_if(arch->offset + arch->size > file->fMapSize, - false, ("%s's %s arch is incomplete\n", file->fPath, myArch->name)); + false, ("%s's %s arch is incomplete\n", pathName, myArch->name)); file->fMachO = file->fMap + arch->offset; file->fMachOSize = arch->size; magic = ((const struct mach_header *) file->fMachO)->magic; @@ -605,7 +669,7 @@ static Boolean findBestArch(struct fileRecord *file) #endif /* KERNEL */ return_if(magic != MH_MAGIC, - false, ("%s isn't a valid mach-o\n", file->fPath)); + false, ("%s isn't a valid mach-o\n", pathName)); return true; } @@ -620,19 +684,6 @@ parseSegments(struct fileRecord *file, struct segment_command *seg) const struct section sect[1]; } *segMap; - if (!nsects) { -#if KERNEL - // We don't need to look for the LinkEdit segment unless - // we are running in the kernel environment. - if (!strcmp(kLinkEditSegName, seg->segname)) { - // Grab symbol table from linkedit we will need this later - file->fSymbolBase = (void *) seg; - } -#endif - - return true; // Nothing more to do, so that was easy. - } - if (!file->fSectData) { file->fSectData = DataCreate(0); if (!file->fSectData) @@ -653,6 +704,222 @@ parseSegments(struct fileRecord *file, struct segment_command *seg) return true; } +static Boolean +remangleExternSymbols(struct fileRecord *file, const char *pathName) +{ + const struct nlist *sym; + int i, nsyms, len; + DataRef strings = NULL; + + DEBUG_LOG(("Remangling %s\n", pathName)); + + file->fNewStringBlocks = DataCreate(0); + return_if(!file->fNewStringBlocks, false, + ("Unable to allocate new string table for %s\n", pathName)); + + nsyms = file->fSymtab->nsyms; + for (i = 0, sym = file->fSymbolBase; i < nsyms; i++, sym++) { + Rem3Return ret; + const char *symname; + char *newname; + unsigned char n_type = sym->n_type; + + // Not an external symbol or it is a stab in any case don't bother + if ((n_type ^ N_EXT) & (N_STAB | N_EXT)) + continue; + + symname = symNameByIndex(file, i); + +tryRemangleAgain: + if (!strings) { + strings = DataCreate(16 * 1024); // Arbitrary block size + return_if(!strings, false, + ("Unable to allocate new string block for %s\n", pathName)); + } + + len = DataRemaining(strings); + newname = DataGetEndPtr(strings); + ret = rem3_remangle_name(newname, &len, symname); + switch (ret) { + case kR3InternalNotRemangled: + errprintf("Remangler fails on %s in %s\n", symname, pathName); + /* No break */ + case kR3NotRemangled: + break; + + case kR3Remangled: + file->fSymbToStringTable[i] = newname; + file->fRemangled = file->fSymbolsDirty = true; + DataAddLength(strings, len + 1); // returns strlen + break; + + case kR3BufferTooSmallRemangled: + return_if(!DataAppendBytes + (file->fNewStringBlocks, &strings, sizeof(strings)), + false, ("Unable to allocate string table for %s\n", pathName)); + strings = NULL; + goto tryRemangleAgain; + + case kR3BadArgument: + default: + return_if(true, false, + ("Internal error - remangle of %s\n", pathName)); + } + } + + if (strings) { + return_if(!DataAppendBytes + (file->fNewStringBlocks, &strings, sizeof(strings)), + false, ("Unable to allocate string table for %s\n", pathName)); + } + + return true; +} + +static Boolean parseSymtab(struct fileRecord *file, const char *pathName) +{ + const struct nlist *sym; + unsigned int i, firstlocal, nsyms; + unsigned long strsize; + const char *strbase; + Boolean foundOSObject, found295CPP; + + // we found a link edit segment so recompute the bases + if (file->fLinkEditSeg) { + struct segment_command *link = file->fLinkEditSeg; + + file->fSymbolBase = (struct nlist *) + (link->vmaddr + (file->fSymtab->symoff - link->fileoff)); + file->fStringBase = (char *) + (link->vmaddr + (file->fSymtab->stroff - link->fileoff)); + return_if( ( (caddr_t) file->fStringBase + file->fSymtab->strsize + > (caddr_t) link->vmaddr + link->vmsize ), false, + ("%s isn't a valid mach-o le, bad symbols\n", pathName)); + } + else { + file->fSymbolBase = (struct nlist *) + (file->fMachO + file->fSymtab->symoff); + file->fStringBase = (char *) + (file->fMachO + file->fSymtab->stroff); + return_if( ( file->fSymtab->stroff + file->fSymtab->strsize + > file->fMachOSize ), false, + ("%s isn't a valid mach-o, bad symbols\n", pathName)); + } + + nsyms = file->fSymtab->nsyms; + + // If this file the kernel and do we have an executable image + file->fNoKernelExecutable = (vm_page_size == file->fSymtab->symoff) + && (file->fSections[0].fSection->size == 0); + + // Generate a table of pointers to strings indexed by the symbol number + + file->fSym2Strings = DataCreate(nsyms * sizeof(const char *)); + DataSetLength(file->fSym2Strings, nsyms * sizeof(const char *)); + return_if(!file->fSym2Strings, false, + ("Unable to allocate memory - symbol string trans\n", pathName)); + file->fSymbToStringTable = (const char **) DataGetPtr(file->fSym2Strings); + + // Search for the first non-stab symbol in table + strsize = file->fSymtab->strsize; + strbase = file->fStringBase; + firstlocal = 0; + found295CPP = foundOSObject = false; + for (i = 0, sym = file->fSymbolBase; i < nsyms; i++, sym++) { + long strx = sym->n_un.n_strx; + const char *symname = strbase + strx; + unsigned char n_type; + + return_if(((unsigned long) strx > strsize), false, + ("%s has an illegal string offset in symbol %d\n", pathName, i)); + + // Load up lookup symbol look table with sym names + file->fSymbToStringTable[i] = symname; + + n_type = sym->n_type & (N_TYPE | N_EXT); + + // Find the first exported symbol + if ( !firstlocal && (n_type & N_EXT) ) { + firstlocal = i; + file->fLocalSyms = sym; + } + + // Find the a OSObject based subclass by searching for symbols + // that have a suffix of '10superClassE' + symname++; // Skip leading '_' + + if (!foundOSObject + && (n_type == (N_SECT | N_EXT) || n_type == (N_ABS | N_EXT)) + && strx) { + const char *suffix, *endSym; + + endSym = symname + strlen(symname); + + // Find out if this symbol has the superclass suffix. + if (symname[0] == kCPPSymbolPrefix[0] + && symname[1] == kCPPSymbolPrefix[1]) { + + suffix = endSym - sizeof(k31SuperClassSuffix) + 1; + + // Check for a gcc3 OSObject subclass + if (suffix > symname + && !strcmp(suffix, k31SuperClassSuffix)) + foundOSObject = true; + } + else { + suffix = endSym - sizeof(k29SuperClassSuffix); + + // Check for a gcc295 OSObject subclass + if (suffix > symname + && ('.' == *suffix || '$' == *suffix) + && !strcmp(suffix+1, k29SuperClassSuffix)) { + found295CPP = foundOSObject = true; + } + else if (!found295CPP) { + // Finally just check if we need to remangle + symname++; // skip leading '__' + while (*symname) { + if ('_' == *symname++ && '_' == *symname++) { + found295CPP = true; + break; + } + } + } + } + } + else if (sym->n_type == (N_EXT | N_UNDF)) { + if ( !file->fNLocal) // Find the last local symbol + file->fNLocal = i - firstlocal; + if (!found295CPP) { + symname++; // Skip possible second '_' at start. + while (*symname) { + if ('_' == *symname++ && '_' == *symname++) { + found295CPP = true; + break; + } + } + } + } + // Note symname is trashed at this point + } + return_if(i < nsyms, false, + ("%s isn't a valid mach-o, bad symbol strings\n", pathName)); + + return_if(!file->fLocalSyms, false, ("%s has no symbols?\n", pathName)); + + // If we don't have any undefined symbols then all symbols + // must be local so just compute it now if necessary. + if ( !file->fNLocal ) + file->fNLocal = i - firstlocal; + + file->fFoundOSObject = foundOSObject; + + if (found295CPP && !remangleExternSymbols(file, pathName)) + return false; + + return true; +} + // @@@ gvdl: These functions need to be hashed they are // going to be way too slow for production code. static const struct nlist * @@ -685,7 +952,7 @@ findSymbolByAddress(const struct fileRecord *file, void *entry) struct searchContext { const char *fSymname; - const char *fStrbase; + const struct fileRecord *fFile; }; static int symbolSearch(const void *vKey, const void *vSym) @@ -693,20 +960,34 @@ static int symbolSearch(const void *vKey, const void *vSym) const struct searchContext *key = (const struct searchContext *) vKey; const struct nlist *sym = (const struct nlist *) vSym; - return strcmp(key->fSymname, key->fStrbase + sym->n_un.n_strx); + return strcmp(key->fSymname + 1, symbolname(key->fFile, sym) + 1); } static const struct nlist * findSymbolByName(struct fileRecord *file, const char *symname) { - struct searchContext context; - - context.fSymname = symname; - context.fStrbase = file->fStringBase; - return (struct nlist *) - bsearch(&context, - file->fLocalSyms, file->fNLocal, sizeof(struct nlist), - symbolSearch); + if (file->fRemangled) { + // @@@ gvdl: Performance problem + // Linear search as we don't sort after remangling + const struct nlist *sym; + int i = file->fLocalSyms - file->fSymbolBase; + int nLocal = file->fNLocal + i; + + for (sym = file->fLocalSyms; i < nLocal; i++, sym++) + if (!strcmp(symNameByIndex(file, i) + 1, symname + 1)) + return sym; + return NULL; + } + else { + struct searchContext context; + + context.fSymname = symname; + context.fFile = file; + return (struct nlist *) + bsearch(&context, + file->fLocalSyms, file->fNLocal, sizeof(struct nlist), + symbolSearch); + } } static Boolean @@ -809,6 +1090,7 @@ relocateSection(const struct fileRecord *file, struct sectionRecord *sectionRec) *entry = (void *) rec; // Save pointer to record in object image } + DataSetLength(sectionRec->fRelocCache, i * sizeof(struct relocRecord)); ((struct fileRecord *) file)->fImageDirty = true; return true; @@ -837,14 +1119,11 @@ addClass(struct fileRecord *file, struct metaClassRecord *inClass, const char *cname) { + Boolean result = false; struct metaClassRecord *newClass = NULL; struct metaClassRecord **fileClasses = NULL; int len; -if (!file->fIsKernel) { // @@@ gvdl: - DEBUG_LOG(("Adding Class %s\n", cname)); -} - if (!file->fClassList) { file->fClassList = DataCreate(0); if (!file->fClassList) @@ -864,11 +1143,11 @@ if (!file->fIsKernel) { // @@@ gvdl: fileClasses = (struct metaClassRecord **) (DataGetPtr(file->fClassList) + DataGetLength(file->fClassList)); - // Copy the meta Class structure and string name into newClass - // and insert object at end of the file->fClassList and sMergeMetaClasses + // Copy the meta Class structure and string name into newClass and + // insert object at end of the file->fClassList and sMergeMetaClasses *newClass = *inClass; strcpy(newClass->fClassName, cname); - fileClasses[-1] = newClass; + fileClasses[-1] = newClass; return true; } while (0); @@ -879,7 +1158,7 @@ if (!file->fIsKernel) { // @@@ gvdl: if (newClass) free(newClass); - return false; + return result; } static struct metaClassRecord *getClass(DataRef classList, const char *cname) @@ -901,59 +1180,68 @@ static struct metaClassRecord *getClass(DataRef classList, const char *cname) } // Add the class 'cname' to the list of known OSObject based classes -// Note 'sym' is the .superClass symbol. +// Note 'sym' is the 10superClassE symbol. static Boolean recordClass(struct fileRecord *file, const char *cname, const struct nlist *sym) { + Boolean result = false; char *supername = NULL; const char *classname = NULL; struct metaClassRecord newClass; char strbuffer[1024]; - // Only do the work actual work to find the super class if we are + // Only do the work to find the super class if we are // not currently working on the kernel. The kernel is the end - // of all superclass chains as by definition the kernel is binary + // of all superclass chains by definition as the kernel must be binary // compatible with itself. if (!file->fIsKernel) { - const char *dot; + const char *suffix; const struct nlist *supersym; const struct section *section; struct sectionRecord *sectionRec; unsigned char sectind = sym->n_sect; const char *superstr; void **location; + int snamelen; // We can't resolve anything that isn't in a real section // Note that the sectind is starts at one to make room for the // NO_SECT flag but the fNSects field isn't offset so we have a // '>' test. Which means this isn't an OSObject based class - if (sectind == NO_SECT || sectind > file->fNSects) - return true; - + if (sectind == NO_SECT || sectind > file->fNSects) { + result = true; + goto finish; + } sectionRec = file->fSections + sectind - 1; section = sectionRec->fSection; location = (void **) ( file->fMachO + section->offset + sym->n_value - section->addr ); supersym = findSymbolRefAtLocation(file, sectionRec, location); - if (!supersym) - return true; // No superclass symbol then it isn't an OSObject. + if (!supersym) { + result = true; // No superclass symbol then it isn't an OSObject. + goto finish; + } - // Find string in file and skip leading '_' and find last '.' + // Find string in file and skip leading '_' and then find the suffix superstr = symbolname(file, supersym) + 1; - dot = strrchr(superstr, '.'); - if (!dot || strcmp(dot, kGMetaSuffix)) - return true; // Not an OSObject superclass so ignore it. + suffix = superstr + strlen(superstr) - sizeof(kGMetaSuffix) + 1; + if (suffix <= superstr || strcmp(suffix, kGMetaSuffix)) { + result = true; // Not an OSObject superclass so ignore it.. + goto finish; + } - supername = (char *) malloc(dot - superstr + 1); - strncpy(supername, superstr, dot - superstr); - supername[dot - superstr] = '\0'; + // Got a candidate so hand it over for class processing. + snamelen = suffix - superstr - sizeof(kOSObjPrefix) + 2; + supername = (char *) malloc(snamelen + 1); + bcopy(superstr + sizeof(kOSObjPrefix) - 2, supername, snamelen); + supername[snamelen] = '\0'; } do { break_if(getClass(file->fClassList, cname), ("Duplicate class %s in %s\n", cname, file->fPath)); - + snprintf(strbuffer, sizeof(strbuffer), "%s%s", kVTablePrefix, cname); newClass.fVTableSym = findSymbolByName(file, strbuffer); break_if(!newClass.fVTableSym, @@ -968,22 +1256,24 @@ recordClass(struct fileRecord *file, const char *cname, const struct nlist *sym) // so why don't we use that rather than mallocing a string. classname = symbolname(file, newClass.fVTableSym) + sizeof(kVTablePrefix) - 1; - break_if(!addClass(file, &newClass, classname), + break_if(!addClass(file, &newClass, classname), ("recordClass - no memory?\n")); - return true; + supername = NULL; + result = true; } while (0); - + +finish: if (supername) free(supername); - return false; + return result; } + static Boolean getMetaClassGraph(struct fileRecord *file) { const struct nlist *sym; - const char *strbase; int i, nsyms; // Search the symbol table for the local symbols that are generated @@ -996,35 +1286,40 @@ static Boolean getMetaClassGraph(struct fileRecord *file) // ___vt The VTable for the class . // // In this code I'm going to search for any symbols that - // ends in kSuperClassSuffix as this indicates this class is a conforming + // ends in k31SuperClassSuffix as this indicates this class is a conforming // OSObject subclass and will need to be patched, and it also // contains a pointer to the super class's meta class structure. - strbase = file->fStringBase; sym = file->fLocalSyms; for (i = 0, nsyms = file->fNLocal; i < nsyms; i++, sym++) { const char *symname; - const char *dot; + const char *suffix; char classname[1024]; unsigned char n_type = sym->n_type & (N_TYPE | N_EXT); + int cnamelen; // Check that the symbols is a global and that it has a name. if (((N_SECT | N_EXT) != n_type && (N_ABS | N_EXT) != n_type) || !sym->n_un.n_strx) continue; - // Only search from the last '.' in the symbol. + // Only search from the last *sep* in the symbol. // but skip the leading '_' in all symbols first. - symname = strbase + sym->n_un.n_strx + 1; - dot = strrchr(symname, '.'); - if (!dot || strcmp(dot, kSuperClassSuffix)) + symname = symbolname(file, sym) + 1; + if (symname[0] != kCPPSymbolPrefix[0] + || symname[1] != kCPPSymbolPrefix[1]) + continue; + + suffix = symname + strlen(symname) - sizeof(k31SuperClassSuffix) + 1; + if (suffix <= symname || strcmp(suffix, k31SuperClassSuffix)) continue; // Got a candidate so hand it over for class processing. - return_if(dot - symname >= (int) sizeof(classname), - false, ("Symbol %s is too long\n", symname)); + cnamelen = suffix - symname - sizeof(kOSObjPrefix) + 2; + return_if(cnamelen + 1 >= (int) sizeof(classname), + false, ("Symbol %s is too long", symname)); - bcopy(symname, classname, dot - symname); - classname[dot - symname] = '\0'; + bcopy(symname + sizeof(kOSObjPrefix) - 2, classname, cnamelen); + classname[cnamelen] = '\0'; if (!recordClass(file, classname, sym)) return false; } @@ -1032,7 +1327,7 @@ static Boolean getMetaClassGraph(struct fileRecord *file) return_if(!file->fClassList, false, ("Internal error, " "getMetaClassGraph(%s) found no classes", file->fPath)); - DEBUG_LOG(("Found %d classes in %x for %s\n", + DEBUG_LOG(("Found %ld classes in %p for %s\n", DataGetLength(file->fClassList)/sizeof(void*), file->fClassList, file->fPath)); @@ -1044,7 +1339,7 @@ static Boolean mergeOSObjectsForFile(const struct fileRecord *file) int i, nmerged; Boolean foundDuplicates = false; -DEBUG_LOG(("Merging file %s\n", file->fPath)); // @@@ gvdl: + DEBUG_LOG(("Merging file %s\n", file->fPath)); // @@@ gvdl: if (!file->fClassList) return true; @@ -1155,7 +1450,7 @@ static Boolean resolveKernelVTable(struct metaClassRecord *metaClass) if (metaClass->fPatchedVTable) return true; -DEBUG_LOG(("Kernel vtable %s\n", metaClass->fClassName)); // @@@ gvdl: + DEBUG_LOG(("Kernel vtable %s\n", metaClass->fClassName)); // @@@ gvdl: // Do we have a valid vtable to patch? return_if(!metaClass->fVTableSym, @@ -1209,17 +1504,56 @@ DEBUG_LOG(("Kernel vtable %s\n", metaClass->fClassName)); // @@@ gvdl: return true; } -// reloc->fPatch must contain a valid pointer on entry +static const char *addNewString(struct fileRecord *file, + const char *strname, int namelen) +{ + DataRef strings = 0; + const char *newStr; + + namelen++; // Include terminating '\0'; + + // Make sure we have a string table as well for this symbol + if (file->fNewStringBlocks) { + DataRef *blockTable = (DataRef *) DataGetPtr(file->fNewStringBlocks); + int index = DataGetLength(file->fNewStringBlocks) / sizeof(DataRef*); + strings = blockTable[index - 1]; + if (DataRemaining(strings) < namelen) + strings = 0; + } + else + { + file->fNewStringBlocks = DataCreate(0); + return_if(!file->fNewStringBlocks, NULL, + ("Unable to allocate new string table %s\n", file->fPath)); + } + + if (!strings) { + int size = (namelen + 1023) & ~1023; + if (size < 16 * 1024) + size = 16 * 1024; + strings = DataCreate(size); + return_if(!strings, NULL, + ("Unable to allocate new string block %s\n", file->fPath)); + return_if( + !DataAppendBytes(file->fNewStringBlocks, &strings, sizeof(strings)), + false, ("Unable to allocate string table for %s\n", file->fPath)); + } + + newStr = DataGetEndPtr(strings); + DataAppendBytes(strings, strname, namelen); + return newStr; +} + +// reloc->fPatch must contain a valid pointer static struct nlist * getNewSymbol(struct fileRecord *file, const struct relocRecord *reloc, const char *supername) { - unsigned int size, i, namelen; + unsigned int size, i; struct nlist **sym; struct nlist *msym; - const char *strbase; struct relocation_info *rinfo; - long strx; + const char *newStr; if (!file->fNewSymbols) { file->fNewSymbols = DataCreate(0); @@ -1227,24 +1561,14 @@ getNewSymbol(struct fileRecord *file, ("Unable to allocate new symbol table for %s\n", file->fPath)); } - // Make sure we have a string table as well for the new symbol - if (!file->fNewStrings) { - file->fNewStrings = DataCreate(0); - return_if(!file->fNewStrings, NULL, - ("Unable to allocate string table for %s\n", file->fPath)); - } - rinfo = (struct relocation_info *) reloc->fRInfo; size = DataGetLength(file->fNewSymbols) / sizeof(struct nlist *); - sym = (const struct nlist **) DataGetPtr(file->fNewSymbols); - // remember that the n_strx for new symbols names is negated - strbase = (const char *) - DataGetPtr(file->fNewStrings) - file->fSymtab->strsize; + sym = (struct nlist **) DataGetPtr(file->fNewSymbols); for (i = 0; i < size; i++, sym++) { - const char *symname = strbase - (*sym)->n_un.n_strx; - - if (!strcmp(symname, supername)) { - rinfo->r_symbolnum = i + file->fSymtab->nsyms; + int symnum = i + file->fSymtab->nsyms; + newStr = symNameByIndex(file, symnum); + if (!strcmp(newStr, supername)) { + rinfo->r_symbolnum = symnum; file->fSymbolsDirty = true; return *sym; } @@ -1257,41 +1581,42 @@ getNewSymbol(struct fileRecord *file, ("Undefined symbol entry with non-zero section %s:%s\n", file->fPath, symbolname(file, reloc->fSymbol))); + // If we are here we didn't find the symbol so create a new one now msym = (struct nlist *) malloc(sizeof(struct nlist)); return_if(!msym, - NULL, ("Unable to create symbol table entry for %s\n", file->fPath)); - - // If we are here we didn't find the symbol so create a new one now - if (!DataAppendBytes(file->fNewSymbols, &msym, sizeof(msym))) { - free(msym); - return_if(true, + NULL, ("Unable to create symbol table entry for %s", file->fPath)); + return_if(!DataAppendBytes(file->fNewSymbols, &msym, sizeof(msym)), NULL, ("Unable to grow symbol table for %s\n", file->fPath)); - } - namelen = strlen(supername) + 1; - strx = DataGetLength(file->fNewStrings); - if (!DataAppendBytes(file->fNewStrings, supername, namelen)) { - free(msym); - DataAddLength(file->fNewSymbols, -sizeof(struct nlist)); // Undo harm - return_if(true, NULL, - ("Unable to grow string table for %s\n", file->fPath)); - } + newStr = addNewString(file, supername, strlen(supername)); + if (!newStr) + return NULL; + // If we are here we didn't find the symbol so create a new one now + return_if(!DataAppendBytes(file->fSym2Strings, &newStr, sizeof(newStr)), + NULL, ("Unable to grow symbol table for %s\n", file->fPath)); + file->fSymbToStringTable = (const char **) DataGetPtr(file->fSym2Strings); // Offset the string index by the original string table size // and negate the address to indicate that this is a 'new' symbol - msym->n_un.n_strx = -(strx + file->fSymtab->strsize); + msym->n_un.n_strx = -1; msym->n_type = (N_EXT | N_UNDF); msym->n_sect = NO_SECT; msym->n_desc = 0; - msym->n_value = 0; + msym->n_value = (unsigned long) newStr; // Mark the old symbol as being potentially deletable I can use the // n_sect field as the input symbol must be of type N_UNDF which means // that the n_sect field must be set to NO_SECT otherwise it is an - // in valid input file. - ((struct nlist *) reloc->fSymbol)->n_un.n_strx - = -reloc->fSymbol->n_un.n_strx; - ((struct nlist *) reloc->fSymbol)->n_sect = (unsigned char) -1; + // invalid input file. + // + // However the symbol may have been just inserted by the fixOldSymbol path. + // If this is the case then we know it is in use and we don't have to + // mark it as a deletable symbol. + if (reloc->fSymbol->n_un.n_strx >= 0) { + ((struct nlist *) reloc->fSymbol)->n_un.n_strx + = -reloc->fSymbol->n_un.n_strx; + ((struct nlist *) reloc->fSymbol)->n_sect = (unsigned char) -1; + } rinfo->r_symbolnum = i + file->fSymtab->nsyms; file->fSymbolsDirty = true; @@ -1309,33 +1634,21 @@ fixOldSymbol(struct fileRecord *file, // assert(sym->n_un.n_strx >= 0); namelen = strlen(supername); - if (namelen < strlen(oldname)) { + + sym->n_un.n_strx = -sym->n_un.n_strx; + if (oldname && namelen < strlen(oldname)) + { // Overwrite old string in string table strcpy((char *) oldname, supername); + file->fSymbolsDirty = true; + return sym; } - else { - long strx; - - // Make sure we have a string table as well for this symbol - if (!file->fNewStrings) { - file->fNewStrings = DataCreate(0); - return_if(!file->fNewStrings, NULL, - ("Unable to allocate string table for %s\n", file->fPath)); - } - - // Find the end of the fNewStrings data structure; - strx = DataGetLength(file->fNewStrings); - return_if(!DataAppendBytes(file->fNewStrings, supername, namelen + 1), - NULL, ("Unable to grow string table for %s\n", file->fPath)); - // now add the current table size to the offset - sym->n_un.n_strx = strx + file->fSymtab->strsize; - } + oldname = addNewString(file, supername, namelen); + if (!oldname) + return NULL; - // Mark the symbol as having been processed by negating it. - // Also note that we have dirtied the file and need to repair the - // symbol table. - sym->n_un.n_strx = -sym->n_un.n_strx; + file->fSymbToStringTable[sym - file->fSymbolBase] = oldname; file->fSymbolsDirty = true; return sym; } @@ -1359,17 +1672,17 @@ symbolCompare(const struct fileRecord *file, if (!strcmp(classname, supername)) return kSymbolIdentical; - // Right now we know that the target's vtable entry is different from the + // We know that the target's vtable entry is different from the // superclass' vtable entry. This means that we will have to apply a // patch to the current entry, however before returning lets check to // see if we have a _RESERVEDnnn field 'cause we can use this as a // registration point that must align between vtables. - if (!strncmp(supername, kReservedPrefix, sizeof(kReservedPrefix) - 1)) + if (strstr(supername, kReservedNamePrefix)) return kSymbolMismatch; // OK, we have a superclass difference where the superclass doesn't // reference a pad function so assume that the superclass is correct. - if (!strncmp(classname, kReservedPrefix, sizeof(kReservedPrefix) - 1)) + if (strstr(classname, kReservedNamePrefix)) return kSymbolPadUpdate; else return kSymbolSuperUpdate; @@ -1408,7 +1721,7 @@ static Boolean patchVTable(struct metaClassRecord *metaClass) // The class isn't in the kernel so make sure that the super class // is patched before patching ouselves. super = getClass(sMergeMetaClasses, metaClass->fSuperName); - return_if(!super, false, ("Can't find superclass for %s : %s \n", + return_if(!super, false, ("Can't find superclass for %s : %s\n", metaClass->fClassName, metaClass->fSuperName)); // Superclass recursion if necessary @@ -1423,7 +1736,7 @@ static Boolean patchVTable(struct metaClassRecord *metaClass) return false; } -DEBUG_LOG(("Patching %s\n", metaClass->fClassName)); // @@@ gvdl: + DEBUG_LOG(("Patching %s\n", metaClass->fClassName)); // @@@ gvdl: // We are going to need the base and the end @@ -1481,8 +1794,8 @@ DEBUG_LOG(("Patching %s\n", metaClass->fClassName)); // @@@ gvdl: break; case kSymbolMismatch: - errprintf("%s is not compatible with its %s superclass, " - "broken superclass?\n", + errprintf("%s is not compatible with its superclass, " + "%s superclass changed?\n", metaClass->fClassName, super->fClassName); goto abortPatch; @@ -1529,7 +1842,7 @@ static Boolean growImage(struct fileRecord *file, vm_size_t delta) vm_address_t startMachO, endMachO, endMap; vm_offset_t newMachO; vm_size_t newsize; - unsigned long i, nsect, nclass = 0; + unsigned long i, last = 0; struct metaClassRecord **classes = NULL; struct sectionRecord *section; kern_return_t ret; @@ -1546,6 +1859,8 @@ static Boolean growImage(struct fileRecord *file, vm_size_t delta) newsize = endMachO - startMachO; if (newsize < round_page(file->fMapSize)) { + DEBUG_LOG(("Growing image %s by moving\n", file->fPath)); + // We have room in the map if we shift the macho image within the // current map. We will have to patch up pointers into the object. newMachO = (vm_offset_t) file->fMap; @@ -1567,10 +1882,12 @@ static Boolean growImage(struct fileRecord *file, vm_size_t delta) return true; } + DEBUG_LOG(("Growing image %s by reallocing\n", file->fPath)); // We have relocated the kmem image so we are going to have to // move all of the pointers into the image around. } else { + DEBUG_LOG(("Growing image %s by allocating\n", file->fPath)); // The image doesn't have room for us and I can't kmem_realloc // then I just have to bite the bullet and copy the object code // into a bigger memory segment @@ -1601,41 +1918,48 @@ static Boolean growImage(struct fileRecord *file, vm_size_t delta) #define REBASE(addr, delta) ( ((vm_address_t) (addr)) += (delta) ) delta = newMachO - startMachO; - // Rebase the cached in object 'struct symtab_command' pointer + // Rebase the cached-in object 'struct symtab_command' pointer REBASE(file->fSymtab, delta); - // Rebase the cached in object 'struct nlist' pointer for all symbols + // Rebase the cached-in object 'struct nlist' pointer for all symbols REBASE(file->fSymbolBase, delta); - // Rebase the cached in object 'struct nlist' pointer for local symbols + // Rebase the cached-in object 'struct nlist' pointer for local symbols REBASE(file->fLocalSyms, delta); - // Rebase the cached in object 'char' pointer for the string table + // Rebase the cached-in object 'char' pointer for the string table REBASE(file->fStringBase, delta); // Ok now we have to go over all of the relocs one last time // to clean up the pad updates which had their string index negated // to indicate that we have finished with them. section = file->fSections; - for (i = 0, nsect = file->fNSects; i < nsect; i++, section++) + for (i = 0, last = file->fNSects; i < last; i++, section++) REBASE(section->fSection, delta); // We only ever grow images that contain class lists so dont bother // the check if file->fClassList is non-zero 'cause it can't be // assert(file->fClassList); - nclass = DataGetLength(file->fClassList) + last = DataGetLength(file->fClassList) / sizeof(struct metaClassRecord *); classes = (struct metaClassRecord **) DataGetPtr(file->fClassList); - for (i = 0; i < nclass; i++) { + for (i = 0; i < last; i++) { struct patchRecord *patch; for (patch = classes[i]->fPatchedVTable; patch->fSymbol; patch++) { vm_address_t symAddr = (vm_address_t) patch->fSymbol; + + // Only need to rebase if the symbol is part of the image + // If this is a new symbol then it was independantly allocated if (symAddr >= startMachO && symAddr < endMachO) REBASE(patch->fSymbol, delta); } } + // Finally rebase all of the string table pointers + last = file->fSymtab->nsyms; + for (i = 0; i < last; i++) + REBASE(file->fSymbToStringTable[i], delta); #undef REBASE @@ -1650,6 +1974,7 @@ prepareFileForLink(struct fileRecord *file) unsigned long i, last, numnewsyms, newsymsize, newstrsize; struct sectionRecord *section; struct nlist **symp, *sym; + DataRef newStrings, *stringBlocks; // If we didn't even do a pseudo 'relocate' and dirty the image // then we can just return now. @@ -1685,7 +2010,7 @@ DEBUG_LOG(("Linking 2 %s\n", file->fPath)); // @@@ gvdl: sym = (struct nlist *) rec->fSymbol; if (sym && sym->n_type == (N_EXT | N_UNDF) && sym->n_sect == (unsigned char) -1) { - // clear mark now + // It is in use so we better clear the mark sym->n_un.n_strx = -sym->n_un.n_strx; sym->n_sect = NO_SECT; } @@ -1703,72 +2028,114 @@ DEBUG_LOG(("Linking 2 %s\n", file->fPath)); // @@@ gvdl: return true; // calculate total file size increase and check against padding - numnewsyms = (file->fNewSymbols)? DataGetLength(file->fNewSymbols) : 0; + if (file->fNewSymbols) { + numnewsyms = DataGetLength(file->fNewSymbols); + symp = (struct nlist **) DataGetPtr(file->fNewSymbols); + } + else { + numnewsyms = 0; + symp = 0; + } numnewsyms /= sizeof(struct nlist *); + file->fSymtab->nsyms += numnewsyms; + + // old sting size + 30% rounded up to nearest page + newstrsize = file->fSymtab->strsize * 21 / 16; + newstrsize = (newstrsize + PAGE_MASK) & ~PAGE_MASK; + newStrings = DataCreate(newstrsize); + return_if(!newStrings, false, + ("Unable to allocate a copy aside buffer, no memory\n")); + newsymsize = numnewsyms * sizeof(struct nlist); - newstrsize = (file->fNewStrings)? DataGetLength(file->fNewStrings) : 0; + file->fStringBase += newsymsize; + file->fSymtab->stroff += newsymsize; + + last = file->fSymtab->nsyms - numnewsyms; + newstrsize = 0; + DataAppendBytes(newStrings, &newstrsize, 4); // Leading nuls + sym = file->fSymbolBase; + + // Pre-compute an already offset new symbol pointer. The offset is the + // orignal symbol table. + symp -= last; + for (i = 0; i < file->fSymtab->nsyms; i++, sym++) { + const char *str = symNameByIndex(file, i); + int len = strlen(str) + 1; + unsigned int strx; + + // Rebase sym in the new symbol region + if (i >= last) + sym = symp[i]; + + if (sym->n_un.n_strx < 0 && sym->n_type == (N_EXT | N_UNDF) + && (unsigned char) -1 == sym->n_sect) { + // after patching we find that this symbol is no longer in + // use. So invalidate it by converting it into an N_ABS + // symbol, remove the external bit and null out the name. + bzero(sym, sizeof(*sym)); + sym->n_type = N_ABS; + } + else { + // Repair the symbol for the getNewSymbol case. + if (-1 == sym->n_un.n_strx) + sym->n_value = 0; + + // Record the offset of the string in the new table + strx = DataGetLength(newStrings); + return_if(!DataAppendBytes(newStrings, str, len), false, + ("Unable to append string, no memory\n")); + + sym->n_un.n_strx = strx; + file->fSymbToStringTable[i] = file->fStringBase + strx; + } + } + + // Don't need the new strings any more + last = DataGetLength(file->fNewStringBlocks) / sizeof(DataRef); + stringBlocks = (DataRef *) DataGetPtr(file->fNewStringBlocks); + for (i = 0; i < last; i++) + DataRelease(stringBlocks[i]); + + DataRelease(file->fNewStringBlocks); + file->fNewStringBlocks = 0; + + newstrsize = DataGetLength(newStrings); newstrsize = (newstrsize + 3) & ~3; // Round to nearest word - - return_if(!growImage(file, newsymsize + newstrsize), + return_if( + !growImage(file, newsymsize + newstrsize - file->fSymtab->strsize), false, ("Unable to patch the extension, no memory\n", file->fPath)); // Push out the new symbol table if necessary if (numnewsyms) { caddr_t base; - // Move the string table out of the way of the grown symbol table - // Don't forget the '\0' from end of string table. - base = (caddr_t) file->fStringBase; - bcopy(base, base + newsymsize, file->fSymtab->strsize); - file->fStringBase += newsymsize; - file->fSymtab->stroff += newsymsize; - - // Now append the new symbols to the symbol table. + // Append the new symbols to the original symbol table. base = (caddr_t) file->fSymbolBase - + file->fSymtab->nsyms * sizeof(struct nlist); + + (file->fSymtab->nsyms - numnewsyms) * sizeof(struct nlist); symp = (struct nlist **) DataGetPtr(file->fNewSymbols); for (i = 0; i < numnewsyms; i++, base += sizeof(struct nlist), symp++) bcopy(*symp, base, sizeof(struct nlist)); - file->fSymtab->nsyms += numnewsyms; DataRelease(file->fNewSymbols); file->fNewSymbols = 0; } // Push out the new string table if necessary - if (newstrsize) { - caddr_t base = (caddr_t) file->fStringBase + file->fSymtab->strsize; - unsigned long actuallen = DataGetLength(file->fNewStrings); + if (newStrings) { + unsigned long *base = (unsigned long *) file->fStringBase; + unsigned long actuallen = DataGetLength(newStrings); // Set the last word in string table to zero before copying data - *((unsigned long *) ((char *) base + newstrsize - 4)) = 0; + base[(newstrsize / sizeof(unsigned long)) - 1] = 0; - // Now append the new strings to the end of the file - bcopy((caddr_t) DataGetPtr(file->fNewStrings), base, actuallen); + // Now copy the new strings back to the end of the file + bcopy((caddr_t) DataGetPtr(newStrings), file->fStringBase, actuallen); - file->fSymtab->strsize += newstrsize; + file->fSymtab->strsize = newstrsize; - DataRelease(file->fNewStrings); - file->fNewStrings = 0; + DataRelease(newStrings); } - // Repair the symbol table string index values - // I used negative strx's to indicate symbol has been processed - sym = file->fSymbolBase; - for (i = 0, last = file->fSymtab->nsyms; i < last; i++, sym++) { - if (sym->n_un.n_strx < 0) { - if ( sym->n_type != (N_EXT | N_UNDF) - || (unsigned char) -1 != sym->n_sect) - sym->n_un.n_strx = -sym->n_un.n_strx; - else { - // This symbol isn't being used by any vtable's reloc so - // convert it into an N_ABS style of symbol, remove the - // external bit and null out the symbol name. - bzero(sym, sizeof(*sym)); - sym->n_type = N_ABS; /* type flag, see below */ - } - } - } file->fSymbolsDirty = false; return true; @@ -1792,14 +2159,13 @@ kld_file_map(const char *pathName) return true; bzero(&file, sizeof(file)); - file.fPath = pathName; #if KERNEL file.fMap = map; file.fMapSize = mapSize; file.fIsKmem = isKmem; #else - if (!mapObjectFile(&file)) + if (!mapObjectFile(&file, pathName)) return false; #endif /* KERNEL */ @@ -1809,119 +2175,61 @@ kld_file_map(const char *pathName) struct load_command c[1]; } *machO; const struct load_command *cmd; - const struct nlist *sym; - unsigned int i, firstlocal, nsyms; - unsigned long strsize; - const char *strbase; - Boolean foundOSObject; + int i; - if (!findBestArch(&file)) + if (!findBestArch(&file, pathName)) break; - + machO = (const struct machOMapping *) file.fMachO; if (file.fMachOSize < machO->h.sizeofcmds) break; + file.fIsKernel = (MH_EXECUTE == machO->h.filetype); + // If the file type is MH_EXECUTE then this must be a kernel // as all Kernel extensions must be of type MH_OBJECT for (i = 0, cmd = &machO->c[0]; i < machO->h.ncmds; i++) { - if (cmd->cmd == LC_SEGMENT) { - return_if(!parseSegments(&file, (struct segment_command *) cmd), - false, ("%s isn't a valid mach-o, bad segment\n", - file.fPath)); - } - else if (cmd->cmd == LC_SYMTAB) + if (cmd->cmd == LC_SYMTAB) file.fSymtab = (struct symtab_command *) cmd; + else if (cmd->cmd == LC_SEGMENT) { + struct segment_command *seg = (struct segment_command *) cmd; + int nsects = seg->nsects; + + if (nsects) + return_if(!parseSegments(&file, seg), + false, ("%s isn't a valid mach-o, bad segment", + pathName)); + else if (file.fIsKernel) { +#if KERNEL + // We don't need to look for the LinkEdit segment unless + // we are running in the kernel environment. + if (!strcmp(kLinkEditSegName, seg->segname)) + file.fLinkEditSeg = seg; +#endif + } + } cmd = (struct load_command *) ((UInt8 *) cmd + cmd->cmdsize); } break_if(!file.fSymtab, - ("%s isn't a valid mach-o, no symbols\n", file.fPath)); - - // we found a link edit segment so recompute the bases - if (file.fSymbolBase) { - struct segment_command *link = - (struct segment_command *) file.fSymbolBase; - - file.fSymbolBase = (struct nlist *) - (link->vmaddr + (file.fSymtab->symoff - link->fileoff)); - file.fStringBase = (char *) - (link->vmaddr + (file.fSymtab->stroff - link->fileoff)); - break_if( ( (caddr_t) file.fStringBase + file.fSymtab->strsize - > (caddr_t) link->vmaddr + link->vmsize ), - ("%s isn't a valid mach-o le, bad symbols\n", file.fPath)); - } - else { - file.fSymbolBase = (struct nlist *) - (file.fMachO + file.fSymtab->symoff); - file.fStringBase = (char *) - (file.fMachO + file.fSymtab->stroff); - break_if( ( file.fSymtab->stroff + file.fSymtab->strsize - > file.fMachOSize ), - ("%s isn't a valid mach-o, bad symbols\n", file.fPath)); - } - - // If this file the kernel and do we have an executable image - file.fIsKernel = (MH_EXECUTE == machO->h.filetype); - file.fNoKernelExecutable = (vm_page_size == file.fSymtab->symoff) - && (file.fSections[0].fSection->size == 0); - - // Search for the first non-stab symbol in table - strsize = file.fSymtab->strsize; - strbase = file.fStringBase; - sym = file.fSymbolBase; - firstlocal = 0; - foundOSObject = false; - for (i = 0, nsyms = file.fSymtab->nsyms; i < nsyms; i++, sym++) { - if ((unsigned long) sym->n_un.n_strx > strsize) - break; + ("%s isn't a valid mach-o, no symbols\n", pathName)); - // Find the first exported symbol - if ( !file.fLocalSyms && (sym->n_type & N_EXT) ) { - file.fLocalSyms = sym; - firstlocal = i; - } - - // Find the a OSObject based subclass by searching for symbols - // that have a suffix of '.superClass' - if (!foundOSObject - && ((sym->n_type & (N_TYPE | N_EXT)) == (N_SECT | N_EXT) - || (sym->n_type & (N_TYPE | N_EXT)) == (N_ABS | N_EXT)) - && sym->n_un.n_strx) { - const char *dot; - - // Only search from the last '.' in the symbol. - // but skip the leading '_' in all symbols first. - dot = strrchr(strbase + sym->n_un.n_strx + 1, '.'); - if (dot && !strcmp(dot, kSuperClassSuffix)) - foundOSObject = true; - } - - // Find the last local symbol - if ( !file.fNLocal && sym->n_type == (N_EXT | N_UNDF) ) - file.fNLocal = i - firstlocal; - - } - break_if(i < nsyms, - ("%s isn't a valid mach-o, bad symbol strings\n", file.fPath)); - - break_if(!file.fLocalSyms, ("%s has no symbols?\n", file.fPath)); + if (!parseSymtab(&file, pathName)) + break; - // If we don't have any undefined symbols then all symbols - // must be local so just compute it now if necessary. - if ( !file.fNLocal ) - file.fNLocal = i - firstlocal; - - fp = addFile(&file); + fp = addFile(&file, pathName); if (!fp) break; - if (foundOSObject && !getMetaClassGraph(fp)) + if (file.fFoundOSObject && !getMetaClassGraph(fp)) break; if (file.fIsKernel) sKernelFile = fp; + #if KERNEL + // Automatically load the kernel's link edit segment if we are + // attempting to load a driver. if (!sKernelFile) { extern struct mach_header _mh_execute_header; extern struct segment_command *getsegbyname(char *seg_name); @@ -1944,7 +2252,12 @@ kld_file_map(const char *pathName) return true; } while(0); - removeFile(&file); + // Failure path, then clean up + if (fp) + // @@@ gvdl: for the time being leak the file ref in the file table + removeFile(fp); + else + unmapFile(&file); return false; } @@ -1977,11 +2290,9 @@ void *kld_file_lookupsymbol(const char *pathName, const char *symname) // May be a non-extern symbol so look for it there if (!sym) { - const char *strbase; unsigned int i, nsyms; sym = file->fSymbolBase; - strbase = file->fStringBase; for (i = 0, nsyms = file->fSymtab->nsyms; i < nsyms; i++, sym++) { if ( (sym->n_type & N_EXT) ) { sym = 0; @@ -1989,7 +2300,7 @@ void *kld_file_lookupsymbol(const char *pathName, const char *symname) } if ( (sym->n_type & N_STAB) ) continue; - if ( !strcmp(symname, strbase + sym->n_un.n_strx) ) + if ( !strcmp(symname, symNameByIndex(file, i)) ) break; } } @@ -2028,7 +2339,7 @@ Boolean kld_file_patch_OSObjects(const char *pathName) return_if(!file, false, ("Internal error - unable to find file %s\n", pathName)); -DEBUG_LOG(("Patch file %s\n", pathName)); // @@@ gvdl: + DEBUG_LOG(("Patch file %s\n", pathName)); // @@@ gvdl: // If we don't have any classes we can return now. if (!file->fClassList) @@ -2046,8 +2357,14 @@ DEBUG_LOG(("Patch file %s\n", pathName)); // @@@ gvdl: last = DataGetLength(file->fClassList) / sizeof(void *); classes = (struct metaClassRecord **) DataGetPtr(file->fClassList); for (i = 0; i < last; i++) { - if (!patchVTable(classes[i])) - return false; + if (!patchVTable(classes[i])) { + // RY: Set a flag in the file list to invalidate this data. + // I would remove the file from the list, but that seems to be + // not worth the effort. + file->fIgnoreFile = TRUE; + + return false; + } } return true; @@ -2062,8 +2379,8 @@ Boolean kld_file_prepare_for_link() // Check to see if we have already merged this file nmerged = DataGetLength(sMergedFiles) / sizeof(struct fileRecord *); files = (struct fileRecord **) DataGetPtr(sMergedFiles); - for (i = 0; i < nmerged; i++) { - if (!prepareFileForLink(files[i])) + for (i = 0; i < nmerged; i++) { + if (!files[i]->fIgnoreFile && !prepareFileForLink(files[i])) return false; } } @@ -2092,11 +2409,49 @@ void kld_file_cleanup_all_resources() for (i = 0; i < nfiles; i++) removeFile(((void **) DataGetPtr(sFilesTable))[i]); + DataRelease(sFilesTable); + sFilesTable = NULL; + // Don't really have to clean up anything more as the whole // malloc engine is going to be released and I couldn't be bothered. } + #if !KERNEL +#if 0 +static const struct fileRecord *sortFile; +static int symCompare(const void *vSym1, const void *vSym2) +{ + const struct nlist *sym1 = vSym1; + const struct nlist *sym2 = vSym2; + + { + unsigned int ind1, ind2; + + ind1 = sym1->n_type & N_TYPE; + ind2 = sym2->n_type & N_TYPE; + if (ind1 != ind2) { + // if sym1 is undefined then sym1 must come later than sym2 + if (ind1 == N_UNDF) + return 1; + // if sym2 is undefined then sym1 must come earlier than sym2 + if (ind2 == N_UNDF) + return -1; + /* drop out if neither are undefined */ + } + } + + { + const struct fileRecord *file = sortFile; + const char *name1, *name2; + + name1 = file->fStringBase + sym1->n_un.n_strx; + name2 = file->fStringBase + sym2->n_un.n_strx; + return strcmp(name1, name2); + } +} +#endif /* 0 */ + Boolean kld_file_debug_dump(const char *pathName, const char *outName) { const struct fileRecord *file = getFile(pathName); @@ -2110,6 +2465,17 @@ Boolean kld_file_debug_dump(const char *pathName, const char *outName) outName, strerror(errno), errno)); do { +#if 0 + // Sorting doesn't work until I fix the relocs too? + + // sort the symbol table appropriately + unsigned int nsyms = file->fSymtab->nsyms + - (file->fLocalSyms - file->fSymbolBase); + sortFile = file; + heapsort((void *) file->fLocalSyms, nsyms, sizeof(struct nlist), + symCompare); +#endif + break_if(-1 == write(fd, file->fMachO, file->fMachOSize), ("Can't dump output file %s - %s(%d)\n", outName, strerror(errno), errno)); @@ -2120,5 +2486,6 @@ Boolean kld_file_debug_dump(const char *pathName, const char *outName) return ret; } + #endif /* !KERNEL */ diff --git a/libsa/kmod.cpp b/libsa/kmod.cpp index 4d18d4399..7e2d50a97 100644 --- a/libsa/kmod.cpp +++ b/libsa/kmod.cpp @@ -672,55 +672,51 @@ int map_and_patch(const char * kmod_name) { return 0; } + ret = TRUE; if (!kld_file_patch_OSObjects(kmod_name)) { IOLog("map_and_patch(): " "Extension \"%s\" Error binding OSObjects.\n", kmod_name); LOG_DELAY(); - return 0; + + // RY: Instead of returning here, set the return value. + // We still need to call kld_file_prepare_for_link because + // we might have patched files outside of the driver. Don't + // worry, it will know to ignore the damaged file + ret = FALSE; } // Now repair any damage that the kld patcher may have done to the image kld_file_prepare_for_link(); - return 1; + return ret; } /********************************************************************* *********************************************************************/ -bool verify_kmod(const char * kmod_name, kmod_info_t * kmod_info) { +bool stamp_kmod(const char * kmod_name, kmod_info_t * kmod_info) { bool result = false; OSDictionary * extensionsDict = NULL; // don't release OSDictionary * kmodDict = NULL; // don't release OSDictionary * plist = NULL; // don't release OSString * versionString = NULL; // don't release - UInt32 plist_vers; - UInt32 kmod_vers; - - if (strncmp(kmod_name, kmod_info->name, sizeof(kmod_info->name))) { - IOLog("verify_kmod(): kmod loaded as \"%s\" has different " - "identifier \"%s\".\n", kmod_name, kmod_info->name); - LOG_DELAY(); - result = false; - goto finish; - } - - if (!VERS_parse_string(kmod_info->version, - &kmod_vers)) { + const char * plist_version = NULL; // don't free - IOLog("verify_kmod(): kmod \"%s\" has an invalid " - "version.\n", kmod_info->name); + if (strlen(kmod_name) + 1 > KMOD_MAX_NAME) { + IOLog("stamp_kmod(): Kext identifier \"%s\" is too long.\n", + kmod_name); LOG_DELAY(); result = false; goto finish; } + strcpy(kmod_info->name, kmod_name); /* Get the dictionary of startup extensions. * This is keyed by module name. */ extensionsDict = getStartupExtensions(); if (!extensionsDict) { - IOLog("verify_kmod(): No extensions dictionary.\n"); + IOLog("stamp_kmod(): No extensions dictionary.\n"); LOG_DELAY(); result = false; goto finish; @@ -729,7 +725,7 @@ bool verify_kmod(const char * kmod_name, kmod_info_t * kmod_info) { kmodDict = OSDynamicCast(OSDictionary, extensionsDict->getObject(kmod_name)); if (!kmodDict) { - IOLog("verify_kmod(): Can't find record for kmod \"%s\".\n", + IOLog("stamp_kmod(): Can't find record for kmod \"%s\".\n", kmod_name); LOG_DELAY(); result = false; @@ -739,17 +735,23 @@ bool verify_kmod(const char * kmod_name, kmod_info_t * kmod_info) { plist = OSDynamicCast(OSDictionary, kmodDict->getObject("plist")); if (!kmodDict) { - IOLog("verify_kmod(): Kmod \"%s\" has no property list.\n", + IOLog("stamp_kmod(): Kmod \"%s\" has no property list.\n", kmod_name); LOG_DELAY(); result = false; goto finish; } + /***** + * Get the kext's version and stuff it into the kmod. This used + * to be a check that the kext & kmod had the same version, but + * now we just overwrite the kmod's version. + */ + versionString = OSDynamicCast(OSString, plist->getObject("CFBundleVersion")); if (!versionString) { - IOLog("verify_kmod(): Kmod \"%s\" has no \"CFBundleVersion\" " + IOLog("stamp_kmod(): Kmod \"%s\" has no \"CFBundleVersion\" " "property.\n", kmod_name); LOG_DELAY(); @@ -757,27 +759,24 @@ bool verify_kmod(const char * kmod_name, kmod_info_t * kmod_info) { goto finish; } - if (!VERS_parse_string(versionString->getCStringNoCopy(), - &plist_vers)) { - - IOLog("verify_kmod(): Property list for kmod \"%s\" has " - "an invalid version.\n", kmod_info->name); + plist_version = versionString->getCStringNoCopy(); + if (!plist_version) { + IOLog("stamp_kmod(): Can't get C string for kext version.\n"); LOG_DELAY(); result = false; goto finish; } - if (kmod_vers != plist_vers) { - IOLog("verify_kmod(): Kmod \"%s\" and its property list " - "claim different versions (%s & %s).\n", - kmod_info->name, - kmod_info->version, - versionString->getCStringNoCopy()); + if (strlen(plist_version) + 1 > KMOD_MAX_NAME) { + IOLog("stamp_kmod(): Version \"%s\" of kext \"%s\" is too long.\n", + plist_version, kmod_name); LOG_DELAY(); result = false; goto finish; } + strcpy(kmod_info->version, plist_version); + result = true; finish: @@ -808,7 +807,8 @@ kern_return_t load_kmod(OSArray * dependencyList) { struct mach_header * kmod_header; unsigned long kld_result; int do_kld_unload = 0; - kmod_info_t * kmod_info; + kmod_info_t * kmod_info_freeme = 0; + kmod_info_t * kmod_info = 0; kmod_t kmod_id; @@ -836,8 +836,8 @@ kern_return_t load_kmod(OSArray * dependencyList) { /* If the requested kmod is already loaded, there's no work to do. */ - kmod_info = kmod_lookupbyname(requested_kmod_name); - if (kmod_info) { + kmod_info_freeme = kmod_lookupbyname_locked(requested_kmod_name); + if (kmod_info_freeme) { // FIXME: Need to check for version mismatch if already loaded. result = KERN_SUCCESS; goto finish; @@ -860,6 +860,9 @@ kern_return_t load_kmod(OSArray * dependencyList) { goto finish; } + bzero(kmod_dependencies, num_dependencies * + sizeof(kmod_info_t *)); + for (i = 0; i < num_dependencies; i++) { currentKmodName = OSDynamicCast(OSString, @@ -876,7 +879,7 @@ kern_return_t load_kmod(OSArray * dependencyList) { const char * current_kmod_name = currentKmodName->getCStringNoCopy(); // These globals are needed by the kld_address functions - g_current_kmod_info = kmod_lookupbyname(current_kmod_name); + g_current_kmod_info = kmod_lookupbyname_locked(current_kmod_name); g_current_kmod_name = current_kmod_name; if (!g_current_kmod_info) { @@ -902,7 +905,7 @@ kern_return_t load_kmod(OSArray * dependencyList) { continue; if (!kld_file_merge_OSObjects(current_kmod_name)) { - IOLog("get_text_info_for_kmod(): Can't merge OSObjects \"%s\".\n", + IOLog("load_kmod(): Can't merge OSObjects \"%s\".\n", current_kmod_name); LOG_DELAY(); result = KERN_FAILURE; @@ -913,7 +916,7 @@ kern_return_t load_kmod(OSArray * dependencyList) { kld_file_getaddr(current_kmod_name, (long *) &kmod_size); if (!kmod_address) { - IOLog("get_text_info_for_kmod() failed for dependency kmod " + IOLog("load_kmod() failed for dependency kmod " "\"%s\".\n", current_kmod_name); LOG_DELAY(); result = KERN_FAILURE; @@ -1005,8 +1008,8 @@ kern_return_t load_kmod(OSArray * dependencyList) { } - if (!verify_kmod(requested_kmod_name, kmod_info)) { - // verify_kmod() logs a meaningful message + if (!stamp_kmod(requested_kmod_name, kmod_info)) { + // stamp_kmod() logs a meaningful message result = KERN_FAILURE; goto finish; } @@ -1075,11 +1078,14 @@ kern_return_t load_kmod(OSArray * dependencyList) { finish: + if (kmod_info_freeme) { + kfree(kmod_info_freeme, sizeof(kmod_info_t)); + } + /* Only do a kld_unload_all() if at least one load happened. */ if (do_kld_unload) { kld_unload_all(/* deallocate sets */ 1); - } /* If the link failed, blow away the allocated link buffer. @@ -1089,6 +1095,11 @@ finish: } if (kmod_dependencies) { + for (i = 0; i < num_dependencies; i++) { + if (kmod_dependencies[i]) { + kfree(kmod_dependencies[i], sizeof(kmod_info_t)); + } + } kfree((unsigned int)kmod_dependencies, num_dependencies * sizeof(kmod_info_t *)); } @@ -1117,14 +1128,13 @@ finish: __private_extern__ kern_return_t load_kernel_extension(char * kmod_name) { kern_return_t result = KERN_SUCCESS; - kmod_info_t * kmod_info; + kmod_info_t * kmod_info = 0; // must free OSArray * dependencyList = NULL; // must release OSArray * curDependencyList = NULL; // must release - bool isKernelResource = false; /* See if the kmod is already loaded. */ - kmod_info = kmod_lookupbyname(kmod_name); + kmod_info = kmod_lookupbyname_locked(kmod_name); if (kmod_info) { // NOT checked result = KERN_SUCCESS; goto finish; @@ -1180,6 +1190,10 @@ kern_return_t load_kernel_extension(char * kmod_name) { finish: + if (kmod_info) { + kfree(kmod_info, sizeof(kmod_info_t)); + } + if (dependencyList) { dependencyList->release(); dependencyList = NULL; diff --git a/libsa/strstr.c b/libsa/strstr.c new file mode 100644 index 000000000..b5be864af --- /dev/null +++ b/libsa/strstr.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2001 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.0 (the 'License'). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License." + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Copyright (c) 1988, 1993 + * 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. + */ +/* + * History: + * 2002-01-24 gvdl Initial implementation of strstr + */ + +#include +#include + +__private_extern__ char * +strstr(const char *in, const char *str) +{ + char c; + size_t len; + + c = *str++; + if (!c) + return (char *) in; // Trivial empty string case + + len = strlen(str); + do { + char sc; + + do { + sc = *in++; + if (!sc) + return (char *) 0; + } while (sc != c); + } while (strncmp(in, str, len) != 0); + + return (char *) (in - 1); +} diff --git a/libsa/vers_rsrc.c b/libsa/vers_rsrc.c index 65dc005a1..9f9f52e6e 100644 --- a/libsa/vers_rsrc.c +++ b/libsa/vers_rsrc.c @@ -1,5 +1,6 @@ #include #include +#include int isdigit(char c) { @@ -58,8 +59,8 @@ char BCD_char_for_digit(UInt8 digit) { } -VERS_revision VERS_revision_for_string(char ** string_p) { - char * string; +VERS_revision VERS_revision_for_string(const char ** string_p) { + const char * string; if (!string_p || !*string_p) { return VERS_invalid; @@ -113,7 +114,7 @@ VERS_revision VERS_revision_for_string(char ** string_p) { int VERS_parse_string(const char * vers_string, UInt32 * version_num) { int result = 1; VERS_version vers; - char * current_char_p; + const char * current_char_p; UInt8 scratch; if (!vers_string || *vers_string == '\0') { @@ -293,7 +294,7 @@ release_state: } finish: - *version_num = vers.vnum; + *version_num = OSSwapBigToHostInt32(vers.vnum); return result; } @@ -310,7 +311,7 @@ int VERS_string(char * buffer, UInt32 length, UInt32 vers) { char minor; char bugfix; - version.vnum = vers; + version.vnum = OSSwapHostToBigInt32(vers); /* No buffer, length less than longest possible vers string, * return 0. diff --git a/makedefs/MakeInc.cmd b/makedefs/MakeInc.cmd index 9f2a856e1..b9aa84920 100644 --- a/makedefs/MakeInc.cmd +++ b/makedefs/MakeInc.cmd @@ -16,7 +16,7 @@ STRIP = /usr/bin/strip LIPO = /usr/bin/lipo BASENAME = /usr/bin/basename -RELPATH = $(NEXT_ROOT)/usr/local/bin/relpath +export RELPATH = $(NEXT_ROOT)/usr/local/bin/relpath TR = /usr/bin/tr SEG_HACK = $(NEXT_ROOT)/usr/local/bin/seg_hack diff --git a/makedefs/MakeInc.def b/makedefs/MakeInc.def index c6b1b3f76..83c8b9278 100644 --- a/makedefs/MakeInc.def +++ b/makedefs/MakeInc.def @@ -1,4 +1,3 @@ - export SOURCE=$(shell /bin/pwd) # @@ -96,8 +95,19 @@ export DEFINES = -DAPPLE -DNeXT -DKERNEL_PRIVATE -D__MACHO__=1 -Dvolatile=__vola # # Compiler command # -CC = /usr/bin/cc -KCC = /usr/bin/cc +KCC = /usr/bin/cc +KC++ = /usr/bin/c++ +CC = $(KCC) + + +# +# Setup for parallel sub-makes when doing an RC build +# +ifndef MAKEJOBS +ifeq "YES" "$(RC_XBS)" +export MAKEJOBS = --jobs=3 +endif +endif # # Default CFLAGS @@ -106,7 +116,9 @@ ifdef RC_CFLAGS export OTHER_CFLAGS = $(subst $(addprefix -arch ,$(RC_ARCHS)),,$(RC_CFLAGS)) endif -export CFLAGS_GEN = -static -g -nostdinc -nostdlib -traditional-cpp -fno-builtin -finline -fno-keep-inline-functions -msoft-float -fsigned-bitfields -Wpointer-arith $(OTHER_CFLAGS) -fpermissive +export CFLAGS_GEN = -static -g -nostdinc -nostdlib -no-cpp-precomp \ + -fno-builtin -finline -fno-keep-inline-functions -msoft-float \ + -fsigned-bitfields -Wpointer-arith $(OTHER_CFLAGS) -fpermissive export CFLAGS_RELEASE = export CFLAGS_DEBUG = -fno-omit-frame-pointer @@ -132,9 +144,7 @@ export CFLAGS = $(CFLAGS_GEN) \ # and in gcc: CPPFLAGS is for C Pre-Processor flags. CCFLAGS has precedent # in ProjectBuilder because of the .cc extension) # -CPPFLAGS_GEN = -x c++ -fno-rtti -fno-exceptions -fcheck-new -fvtable-thunks -CPPFLAGS_PPC = -CPPFLAGS_I386 = +CPPFLAGS_GEN = -fno-rtti -fno-exceptions -fcheck-new -fapple-kext CPPFLAGS = $(CPPFLAGS_GEN) \ $($(addsuffix $(ARCH_CONFIG),CCFLAGS_)) \ @@ -213,7 +223,7 @@ export INCFLAGS_GEN = -I$(SRCROOT)/$(COMPONENT) export INCFLAGS_POSIX = -I$(OBJROOT)/EXPORT_HDRS/bsd export INCFLAGS_LOCAL = -I. -export INCFLAGS = -nostdinc $(INCFLAGS_LOCAL) $(INCFLAGS_GEN) $(INCFLAGS_IMPORT) $(INCFLAGS_EXTERN) $(INCFLAGS_MAKEFILE) +export INCFLAGS = $(INCFLAGS_LOCAL) $(INCFLAGS_GEN) $(INCFLAGS_IMPORT) $(INCFLAGS_EXTERN) $(INCFLAGS_MAKEFILE) # # Default MIGFLAGS @@ -269,6 +279,11 @@ export STRIP_FLAGS_PROFILE = -S export STRIP_FLAGS = $($(addsuffix $(KERNEL_CONFIG),STRIP_FLAGS_)) +# +# Man Page destination +# +MANDIR = usr/share/man + # # This must be here before any rules are possibly defined by the # machine dependent makefile fragment so that a plain "make" command diff --git a/makedefs/MakeInc.dir b/makedefs/MakeInc.dir index 77239fec7..dbeb55c17 100644 --- a/makedefs/MakeInc.dir +++ b/makedefs/MakeInc.dir @@ -1,7 +1,7 @@ # # Install kernel header files # -installhdrs: SRCROOT DSTROOT OBJROOT exporthdrs installhdrs_mi installhdrs_md +installhdrs: exporthdrs installhdrs_mi installhdrs_md @echo "[ $(SRCROOT) ] make installhdrs installing Kernel.framework"; \ kincpath=$(DSTROOT)/$(KINCDIR); \ kframepath=$(DSTROOT)/$(KINCFRAME); \ @@ -39,14 +39,13 @@ installhdrs_mi: arch_config=$(INSTALL_ARCH_DEFAULT); \ installinc_dir=${OBJROOT}/$${kernel_config}_$${arch_config}/$${rel_path}; \ $(MKDIR) $${installinc_dir}; \ - (cd $${installinc_dir}; \ - ${MAKE} KERNEL_CONFIG=$${kernel_config} \ + ${MAKE} -C $${installinc_dir} \ + KERNEL_CONFIG=$${kernel_config} \ ARCH_CONFIG=$${arch_config} \ MAKEFILES=${SOURCE}/Makefile \ SOURCE=${SOURCE}/ \ TARGET=${OBJROOT}/$${kernel_config}_$${arch_config}/$${rel_path}/ \ - build_installhdrs_mi \ - ); + build_installhdrs_mi; \ # # Install machine dependent kernel header files @@ -58,14 +57,13 @@ installhdrs_md: for arch_config in $(INSTALL_ARCHS); \ do \ $(MKDIR) ${OBJROOT}/$${kernel_config}_$${arch_config}/$${rel_path}; \ - (cd ${OBJROOT}/$${kernel_config}_$${arch_config}/$${rel_path}; \ - ${MAKE} KERNEL_CONFIG=$${kernel_config} \ + ${MAKE} -C ${OBJROOT}/$${kernel_config}_$${arch_config}/$${rel_path} \ + KERNEL_CONFIG=$${kernel_config} \ ARCH_CONFIG=$${arch_config} \ MAKEFILES=${SOURCE}/Makefile \ SOURCE=${SOURCE}/ \ TARGET=${OBJROOT}/$${kernel_config}_$${arch_config}/$${rel_path}/ \ - build_installhdrs_md \ - ); \ + build_installhdrs_md; \ done; # @@ -78,14 +76,13 @@ build_installhdrs_mi:: for installinc_subdir in $(INSTINC_SUBDIRS); \ do \ $(MKDIR) $${installinc_subdir}; \ - (cd $${installinc_subdir}; \ - ${MAKE} MAKEFILES=$(SOURCE)$${installinc_subdir}/Makefile \ + ${MAKE} -C $${installinc_subdir} \ + MAKEFILES=$(SOURCE)$${installinc_subdir}/Makefile \ SOURCE=$(SOURCE)$${installinc_subdir}/ \ TARGET=$(TARGET)$${installinc_subdir}/ \ - build_installhdrs_mi \ - ); \ + build_installhdrs_mi; \ done; \ - ${MAKE} do_installhdrs_mi; + ${MAKE} ${MAKEJOBS} do_installhdrs_mi; # # Install machine dependent kernel header files @@ -97,19 +94,18 @@ build_installhdrs_md:: for installinc_subdir in $($(addprefix INSTINC_SUBDIRS_, $(ARCH_CONFIG))); \ do \ $(MKDIR) $${installinc_subdir}; \ - (cd $${installinc_subdir}; \ - ${MAKE} MAKEFILES=$(SOURCE)$${installinc_subdir}/Makefile \ + ${MAKE} -C $${installinc_subdir} \ + MAKEFILES=$(SOURCE)$${installinc_subdir}/Makefile \ SOURCE=$(SOURCE)$${installinc_subdir}/ \ TARGET=$(TARGET)$${installinc_subdir}/ \ - build_installhdrs_md \ - ); \ + build_installhdrs_md; \ done; \ - ${MAKE} do_installhdrs_md; + ${MAKE} ${MAKEJOBS} do_installhdrs_md; # # Install kernel header files # -exporthdrs: SRCROOT DSTROOT OBJROOT exporthdrs_mi exporthdrs_md +exporthdrs: exporthdrs_mi exporthdrs_md # # Install header files order @@ -128,14 +124,13 @@ exporthdrs_mi: arch_config=$(INSTALL_ARCH_DEFAULT); \ exportinc_dir=${OBJROOT}/$${kernel_config}_$${arch_config}/$${rel_path}; \ $(MKDIR) $${exportinc_dir}; \ - (cd $${exportinc_dir}; \ - ${MAKE} KERNEL_CONFIG=$${kernel_config} \ + ${MAKE} -C $${exportinc_dir} \ + KERNEL_CONFIG=$${kernel_config} \ ARCH_CONFIG=$${arch_config} \ MAKEFILES=${SOURCE}/Makefile \ SOURCE=${SOURCE}/ \ TARGET=$${exportinc_dir}/ \ - build_exporthdrs_mi \ - ); + build_exporthdrs_mi; \ # # Install machine dependent kernel header files @@ -148,14 +143,13 @@ exporthdrs_md: do \ exportinc_dir=${OBJROOT}/$${kernel_config}_$${arch_config}/$${rel_path}; \ $(MKDIR) $${exportinc_dir}; \ - (cd $${exportinc_dir}; \ - ${MAKE} KERNEL_CONFIG=$${kernel_config} \ + ${MAKE} -C $${exportinc_dir} \ + KERNEL_CONFIG=$${kernel_config} \ ARCH_CONFIG=$${arch_config} \ MAKEFILES=${SOURCE}/Makefile \ SOURCE=${SOURCE}/ \ TARGET=$${exportinc_dir}/ \ - build_exporthdrs_md \ - ); \ + build_exporthdrs_md; \ done; # @@ -165,17 +159,17 @@ do_exporthdrs_mi: build_exporthdrs_mi: @echo "[ $(SOURCE) ] make build_exporthdrs_mi $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)"; \ - for exportinc_subdir in $(EXPINC_SUBDIRS); \ + _TMP_EXPINC_SUBDIRS="$(EXPINC_SUBDIRS)"; \ + for exportinc_subdir in $${_TMP_EXPINC_SUBDIRS}; \ do \ $(MKDIR) $${exportinc_subdir}; \ - (cd $${exportinc_subdir}; \ - ${MAKE} MAKEFILES=$(SOURCE)$${exportinc_subdir}/Makefile \ + ${MAKE} -C $${exportinc_subdir} \ + MAKEFILES=$(SOURCE)$${exportinc_subdir}/Makefile \ SOURCE=$(SOURCE)$${exportinc_subdir}/ \ TARGET=$(TARGET)$${exportinc_subdir}/ \ - build_exporthdrs_mi \ - ); \ + build_exporthdrs_mi; \ done; \ - ${MAKE} do_exporthdrs_mi; + ${MAKE} ${MAKEJOBS} do_exporthdrs_mi; # # Install machine dependent kernel header files @@ -184,22 +178,22 @@ do_exporthdrs_md: build_exporthdrs_md: @echo "[ $(SOURCE) ] make exporthdrs_md $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)"; \ - for exportinc_subdir in $($(addprefix EXPINC_SUBDIRS_, $(ARCH_CONFIG))); \ + _TMP_exportinc_subdir="$($(addprefix EXPINC_SUBDIRS_, $(ARCH_CONFIG)))"; \ + for exportinc_subdir in $${_TMP_exportinc_subdir}; \ do \ $(MKDIR) $${exportinc_subdir}; \ - (cd $${exportinc_subdir}; \ - ${MAKE} MAKEFILES=$(SOURCE)$${exportinc_subdir}/Makefile \ + ${MAKE} -C $${exportinc_subdir} \ + MAKEFILES=$(SOURCE)$${exportinc_subdir}/Makefile \ SOURCE=$(SOURCE)$${exportinc_subdir}/ \ TARGET=$(TARGET)$${exportinc_subdir}/ \ - build_exporthdrs_md \ - ); \ + build_exporthdrs_md; \ done; \ - ${MAKE} do_exporthdrs_md; + ${MAKE} ${MAKEJOBS} do_exporthdrs_md; # # Setup pass for all architectures for all Configuration/Architecture options # -setup: SRCROOT DSTROOT OBJROOT +setup: @echo "[ $(SOURCE) ] make setup"; \ rel_path=$(shell $(RELPATH) $(SRCROOT) $(SOURCE)); \ for kernel_config in $(KERNEL_CONFIGS); \ @@ -208,14 +202,13 @@ setup: SRCROOT DSTROOT OBJROOT do \ setup_subdir=${OBJROOT}/$${kernel_config}_$${arch_config}/$${rel_path}; \ $(MKDIR) $${setup_subdir}; \ - (cd $${setup_subdir}; \ - ${MAKE} KERNEL_CONFIG=$${kernel_config} \ + ${MAKE} -C $${setup_subdir} \ + KERNEL_CONFIG=$${kernel_config} \ ARCH_CONFIG=$${arch_config} \ MAKEFILES=${SOURCE}/Makefile \ SOURCE=${SOURCE}/ \ TARGET=$${setup_subdir}/ \ - build_setup \ - ); \ + build_setup; \ done; \ done; @@ -223,15 +216,15 @@ do_build_setup: build_setup: @echo "[ $(SOURCE) ] make build_setup $(COMPONENT) $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)"; \ - for setup_subdir in $(SETUP_SUBDIRS) $($(addprefix SETUP_SUBDIRS_, $(ARCH_CONFIG))); \ + _TMP_setup_subdir="$(SETUP_SUBDIRS) $($(addprefix SETUP_SUBDIRS_, $(ARCH_CONFIG)))"; \ + for setup_subdir in $${_TMP_setup_subdir}; \ do \ $(MKDIR) $${setup_subdir}; \ - (cd $${setup_subdir}; \ - ${MAKE} MAKEFILES=${SOURCE}/$${setup_subdir}/Makefile \ + ${MAKE} -C $${setup_subdir} \ + MAKEFILES=${SOURCE}/$${setup_subdir}/Makefile \ SOURCE=${SOURCE}/$${setup_subdir}/ \ TARGET=${TARGET}/$${setup_subdir}/ \ - build_setup \ - ); \ + build_setup; \ done; \ ${MAKE} do_build_setup; @@ -239,7 +232,11 @@ build_setup: # # Build all architectures for all Configuration/Architecture options # -all: SRCROOT DSTROOT OBJROOT +ifeq ($(COMPONENT), .) +all: exporthdrs +else +all: +endif @echo "[ $(SOURCE) ] make all"; \ rel_path=$(shell $(RELPATH) $(SRCROOT) $(SOURCE)); \ for kernel_config in $(KERNEL_CONFIGS); \ @@ -248,13 +245,12 @@ all: SRCROOT DSTROOT OBJROOT do \ build_subdir=${OBJROOT}/$${kernel_config}_$${arch_config}/$${rel_path}; \ $(MKDIR) $${build_subdir}; \ - (cd $${build_subdir}; \ - ${MAKE} KERNEL_CONFIG=$${kernel_config} \ + ${MAKE} -C $${build_subdir} \ + KERNEL_CONFIG=$${kernel_config} \ ARCH_CONFIG=$${arch_config} \ MAKEFILES=${SOURCE}/Makefile \ SOURCE=${SOURCE}/ \ - build_all \ - ); \ + build_all; \ done; \ done; @@ -266,22 +262,22 @@ do_build_all: build_all: @TARGET=${OBJROOT}/$(KERNEL_CONFIG)_$(ARCH_CONFIG)/$(COMPONENT); \ echo "[ $(SOURCE) ] make build_all $(COMPONENT) $(KERNEL_CONFIG) $(ARCH_CONFIG) $${TARGET}"; \ - for comp_subdir in $(COMP_SUBDIRS) $($(addprefix COMP_SUBDIRS_, $(ARCH_CONFIG))); \ + _TMP_comp_subdir="$(COMP_SUBDIRS) $($(addprefix COMP_SUBDIRS_, $(ARCH_CONFIG)))"; \ + for comp_subdir in $${_TMP_comp_subdir}; \ do \ $(MKDIR) $${comp_subdir}; \ - (cd $${comp_subdir}; \ - ${MAKE} MAKEFILES=${SOURCE}/$${comp_subdir}/Makefile \ + ${MAKE} -C $${comp_subdir} \ + MAKEFILES=${SOURCE}/$${comp_subdir}/Makefile \ SOURCE=${SOURCE}$${comp_subdir}/ \ TARGET=$${TARGET} \ - build_all \ - ); \ + build_all; \ done; \ - ${MAKE} INCL_MAKEDEP=TRUE TARGET=$${TARGET} do_build_all; + ${MAKE} ${MAKEJOBS} INCL_MAKEDEP=TRUE TARGET=$${TARGET} do_build_all; # # Build all architectures for all Configuration/Architecture options # -mach_kernel: SRCROOT DSTROOT OBJROOT +mach_kernel: @echo "[ $(SOURCE) ] make mach_kernel"; \ for kernel_config in $(KERNEL_CONFIGS); \ do \ @@ -289,14 +285,13 @@ mach_kernel: SRCROOT DSTROOT OBJROOT do \ build_subdir=${OBJROOT}/$${kernel_config}_$${arch_config}; \ $(MKDIR) $${build_subdir}; \ - (cd $${build_subdir}; \ - ${MAKE} KERNEL_CONFIG=$${kernel_config} \ + ${MAKE} -C $${build_subdir} \ + KERNEL_CONFIG=$${kernel_config} \ ARCH_CONFIG=$${arch_config} \ MAKEFILES=${SOURCE}/Makefile \ SOURCE=${SOURCE}/ \ TARGET=$${build_subdir}/ \ - build_mach_kernel \ - ); \ + build_mach_kernel; \ done; \ done; @@ -307,19 +302,19 @@ do_build_mach_kernel: build_mach_kernel: @echo "[ $(SOURCE) ] make build_mach_kernel $(COMPONENT) $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)"; \ - ${MAKE} do_build_mach_kernel; + ${MAKE} ${MAKEJOBS} do_build_mach_kernel; # # # Install dependencies order # -.ORDER: SRCROOT DSTROOT OBJROOT SYMROOT installhdrs exporthdrs all +.ORDER: installhdrs exporthdrs all # # Install kernel based on RC_ARCHS for all INSTALL_TYPES # Install kernel header files based on RC_ARCHS # -install: SRCROOT DSTROOT OBJROOT SYMROOT installhdrs all +install: installhdrs all installman @echo "[ $(SOURCE) ] make install"; \ rel_path=$(shell $(RELPATH) $(SRCROOT) $(SOURCE)); \ for kernel_config in $(INSTALL_TYPE); \ @@ -328,13 +323,12 @@ install: SRCROOT DSTROOT OBJROOT SYMROOT installhdrs all do \ install_subdir=${OBJROOT}/$${kernel_config}_$${arch_config}/$${rel_path}; \ $(MKDIR) $${install_subdir}; \ - (cd $${install_subdir}; \ - ${MAKE} KERNEL_CONFIG=$${kernel_config} \ + ${MAKE} -C $${install_subdir} \ + KERNEL_CONFIG=$${kernel_config} \ ARCH_CONFIG=$${arch_config} \ MAKEFILES=${SOURCE}/Makefile \ SOURCE=${SOURCE}/ \ - build_install \ - ); \ + build_install; \ done; \ done; @@ -353,21 +347,20 @@ build_install: for install_subdir in $(INST_SUBDIRS); \ do \ $(MKDIR) $${install_subdir}; \ - (cd $${install_subdir}; \ - ${MAKE} KERNEL_CONFIG=$${kernel_config} \ + ${MAKE} -C $${install_subdir} \ + KERNEL_CONFIG=$${kernel_config} \ MAKEFILES=${SOURCE}/$${install_subdir}/Makefile \ SOURCE=${SOURCE}$${install_subdir}/ \ TARGET=$${TARGET} \ - build_install \ - ); \ + build_install; \ done; \ - ${MAKE} TARGET=$${TARGET} do_build_install; + ${MAKE} ${MAKEJOBS} TARGET=$${TARGET} do_build_install; # # Install source tree # -installsrc: SRCROOT +installsrc: pax -rw . ${SRCROOT} @@ -375,7 +368,7 @@ installsrc: SRCROOT # # Clean up source tree # -clean: SRCROOT +clean: # # Build source file list for cscope database and tags @@ -412,15 +405,31 @@ tags: cscope.files @echo "Building etags" @-cat cscope.files | etags -l auto -S - 2> /dev/null - -SRCROOT DSTROOT OBJROOT SYMROOT: ALWAYS - @if [ -n "${$@}" ]; \ - then \ - exit 0; \ - else \ - echo Must define $@; \ - exit 1; \ +# +# Install Man Pages +# +installman: + @echo "[ $(SRCROOT) ] Installing man pages"; \ + manpath=$(DSTROOT)/$(MANDIR); \ + $(MKDIR) $$manpath; \ + ${MAKE} MAKEFILES=${SOURCE}/Makefile \ + SOURCE=${SOURCE}/ \ + TARGET=${DSTROOT}/ \ + build_installman + +do_installman: + +build_installman: + @echo "[ $(SOURCE) ] make build_installman"; \ + if [ -n "$(strip $(INSTMAN_SUBDIRS))" ]; then \ + for installman_subdir in $(INSTMAN_SUBDIRS); do \ + ${MAKE} -C $${installman_subdir} -r \ + MAKEFILES=$(SOURCE)$${installman_subdir}/Makefile \ + SOURCE=$(SOURCE)$${installman_subdir}/ \ + TARGET=$(TARGET)$${installman_subdir}/ \ + build_installman; \ + done; \ + fi; \ + if [ -n "$(strip $(INSTALL_MAN_LIST))" ]; then \ + ${MAKE} ${MAKEJOBS} do_installman; \ fi - -ALWAYS: - diff --git a/makedefs/MakeInc.rule b/makedefs/MakeInc.rule index fc63338f6..62c7558ff 100644 --- a/makedefs/MakeInc.rule +++ b/makedefs/MakeInc.rule @@ -24,10 +24,12 @@ endif ifeq ($(INCR_INSTALLHDRS), TRUE) +# +# These are the machine independent headers that end up in /usr/include +# Eventually they're copied to System framework's headers directory +# INSTALL_MI_INC_FILES = $(addprefix $(DSTROOT)/$(INCDIR)/$(INSTALL_MI_DIR)/, $(INSTALL_MI_LIST)) INSTALL_MI_GEN_INC_FILES = $(addprefix $(DSTROOT)/$(INCDIR)/$(INSTALL_MI_DIR)/, $(INSTALL_MI_GEN_LIST)) -INSTALL_MI_LCL_FILES = $(addprefix $(DSTROOT)/$(LCLDIR)/$(INSTALL_MI_DIR)/, $(INSTALL_MI_LCL_LIST)) -INSTALL_MI_GEN_LCL_FILES = $(addprefix $(DSTROOT)/$(LCLDIR)/$(INSTALL_MI_DIR)/, $(INSTALL_MI_LCL_GEN_LIST)) $(INSTALL_MI_INC_FILES) $(INSTALL_MI_GEN_INC_FILES): $(DSTROOT)/$(INCDIR)/$(INSTALL_MI_DIR)/% : % @true echo Installing $< in $(dir $@); \ @@ -50,16 +52,38 @@ $(INSTALL_MI_INC_FILES) $(INSTALL_MI_GEN_INC_FILES): $(DSTROOT)/$(INCDIR)/$(INST fi; \ $(RM) -rf ./incdir; +# +# These are usually machine independent System framework private headers +# Unless LCLDIR is specified as something else +# +INSTALL_MI_LCL_FILES = $(addprefix $(DSTROOT)/$(LCLDIR)/$(INSTALL_MI_DIR)/, $(INSTALL_MI_LCL_LIST)) +INSTALL_MI_GEN_LCL_FILES = $(addprefix $(DSTROOT)/$(LCLDIR)/$(INSTALL_MI_DIR)/, $(INSTALL_MI_LCL_GEN_LIST)) + $(INSTALL_MI_LCL_FILES) $(INSTALL_MI_GEN_LCL_FILES): $(DSTROOT)/$(LCLDIR)/$(INSTALL_MI_DIR)/% : % @true echo Installing $< in $(dir $@); \ $(MKDIR) $(DSTROOT)/$(LCLDIR)/$(INSTALL_MI_DIR); \ $(RM) $(RMFLAGS) $@; \ install $(INSTALL_FLAGS) $< $(dir $@); +# +# These are the Kernel framework's machine independent private headers +# They should be specified in INSTALL_MI_LCL_KERN_LIST and INSTALL_MI_LCL_GEN_KERN_LIST +# +INSTALL_MI_LCL_KERN_FILES = $(addprefix $(DSTROOT)/$(KPINCDIR)/$(INSTALL_MI_DIR)/, $(INSTALL_MI_LCL_KERN_LIST)) +INSTALL_MI_GEN_LCL_KERN_FILES = $(addprefix $(DSTROOT)/$(KPINCDIR)/$(INSTALL_MI_DIR)/, $(INSTALL_MI_LCL_GEN_KERN_LIST)) + +$(INSTALL_MI_LCL_KERN_FILES) $(INSTALL_MI_GEN_LCL_KERN_FILES): $(DSTROOT)/$(KPINCDIR)/$(INSTALL_MI_DIR)/% : % + @true echo Installing $< in $(dir $@); \ + $(MKDIR) $(DSTROOT)/$(KPINCDIR)/$(INSTALL_MI_DIR); \ + $(RM) $(RMFLAGS) $@; \ + install $(INSTALL_FLAGS) $< $(dir $@); + +# +# These are the machine dependent headers that end up in /usr/include +# Eventually they're copied to System framework's headers directory +# INSTALL_MD_INC_FILES = $(addprefix $(DSTROOT)/$(INCDIR)/$(INSTALL_MD_DIR)/, $(INSTALL_MD_LIST)) INSTALL_MD_GEN_INC_FILES = $(addprefix $(DSTROOT)/$(INCDIR)/$(INSTALL_MD_DIR)/, $(INSTALL_MD_GEN_LIST)) -INSTALL_MD_LCL_FILES = $(addprefix $(DSTROOT)/$(LCLDIR)/$(INSTALL_MD_DIR)/, $(INSTALL_MD_LCL_LIST)) -INSTALL_MD_GEN_LCL_FILES = $(addprefix $(DSTROOT)/$(LCLDIR)/$(INSTALL_MD_DIR)/, $(INSTALL_MD_LCL_GEN_LIST)) $(INSTALL_MD_INC_FILES) $(INSTALL_MD_GEN_INC_FILES): $(DSTROOT)/$(INCDIR)/$(INSTALL_MD_DIR)/% : % @true echo Installing $< in $(dir $@); \ @@ -82,33 +106,49 @@ $(INSTALL_MD_INC_FILES) $(INSTALL_MD_GEN_INC_FILES): $(DSTROOT)/$(INCDIR)/$(INST fi; \ $(RM) -rf ./incdir; +# +# These are usually machine dependent System framework private headers +# Unless LCLDIR is specified as something else +# +INSTALL_MD_LCL_FILES = $(addprefix $(DSTROOT)/$(LCLDIR)/$(INSTALL_MD_DIR)/, $(INSTALL_MD_LCL_LIST)) +INSTALL_MD_GEN_LCL_FILES = $(addprefix $(DSTROOT)/$(LCLDIR)/$(INSTALL_MD_DIR)/, $(INSTALL_MD_LCL_GEN_LIST)) + $(INSTALL_MD_LCL_FILES) $(INSTALL_MD_GEN_LCL_FILES): $(DSTROOT)/$(LCLDIR)/$(INSTALL_MD_DIR)/% : % @true echo Installing $< in $(dir $@); \ $(MKDIR) $(DSTROOT)/$(LCLDIR)/$(INSTALL_MD_DIR); \ $(RM) $(RMFLAGS) $@; \ install $(INSTALL_FLAGS) $< $(dir $@); +# +# These are the Kernel framework's machine dependent private headers +# They should be specified in INSTALL_MD_LCL_KERN_LIST and INSTALL_MD_LCL_GEN_KERN_LIST +# +INSTALL_MD_LCL_KERN_FILES = $(addprefix $(DSTROOT)/$(KPINCDIR)/$(INSTALL_MD_DIR)/, $(INSTALL_MD_LCL_KERN_LIST)) +INSTALL_MD_GEN_LCL_KERN_FILES = $(addprefix $(DSTROOT)/$(KPINCDIR)/$(INSTALL_MD_DIR)/, $(INSTALL_MD_LCL_GEN_KERN_LIST)) + +$(INSTALL_MD_LCL_KERN_FILES) $(INSTALL_MD_GEN_LCL_KERN_FILES): $(DSTROOT)/$(KPINCDIR)/$(INSTALL_MD_DIR)/% : % + @true echo Installing $< in $(dir $@); \ + $(MKDIR) $(DSTROOT)/$(KPINCDIR)/$(INSTALL_MD_DIR); \ + $(RM) $(RMFLAGS) $@; \ + install $(INSTALL_FLAGS) $< $(dir $@); + setup_installhdrs_mi: @echo "[ $(SOURCE) ] make setup_installhdrs_mi $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)" -do_installhdrs_mi: $(INSTALL_MI_INC_FILES) $(INSTALL_MI_GEN_INC_FILES) $(INSTALL_MI_LCL_FILES) $(INSTALL_MI_GEN_LCL_FILES) - @echo "[ $(SOURCE) ] make do_installhdrs_mi $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)" +do_installhdrs_mi: $(INSTALL_MI_INC_FILES) $(INSTALL_MI_GEN_INC_FILES) $(INSTALL_MI_LCL_FILES) $(INSTALL_MI_GEN_LCL_FILES) $(INSTALL_MI_LCL_KERN_FILES) $(INSTALL_MI_GEN_LCL_KERN_FILES) + @true echo "[ $(SOURCE) ] make do_installhdrs_mi $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)" setup_installhdrs_md: @echo "[ $(SOURCE) ] make setup_installhdrs_md $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)" -do_installhdrs_md: $(INSTALL_MD_INC_FILES) $(INSTALL_MD_GEN_INC_FILES) $(INSTALL_MD_LCL_FILES) $(INSTALL_MD_GEN_LCL_FILES) - @echo "[ $(SOURCE) ] make do_installhdrs_md $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)" +do_installhdrs_md: $(INSTALL_MD_INC_FILES) $(INSTALL_MD_GEN_INC_FILES) $(INSTALL_MD_LCL_FILES) $(INSTALL_MD_GEN_LCL_FILES) $(INSTALL_MD_LCL_KERN_FILES) $(INSTALL_MD_GEN_LCL_KERN_FILES) + @true echo "[ $(SOURCE) ] make do_installhdrs_md $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)" else INSTALL_MI_INC_FILES = $(addprefix $(SOURCE), $(INSTALL_MI_LIST)) INSTALL_MI_GEN_INC_FILES = $(addprefix $(DSTROOT)/$(INCDIR)/$(INSTALL_MI_DIR)/, $(INSTALL_MI_GEN_LIST)) -INSTALL_MI_LCL_FILES = $(addprefix $(SOURCE), $(INSTALL_MI_LCL_LIST)) -INSTALL_MI_GEN_LCL_FILES = $(addprefix $(DSTROOT)/$(LCLDIR)/$(INSTALL_MI_DIR)/, $(INSTALL_MI_LCL_GEN_LIST)) - - $(INSTALL_MI_GEN_INC_FILES): $(DSTROOT)/$(INCDIR)/$(INSTALL_MI_DIR)/% : % @true echo Installing $< in $(dir $@); \ $(MKDIR) $(DSTROOT)/$(INCDIR)/$(INSTALL_MI_DIR); \ @@ -130,18 +170,27 @@ $(INSTALL_MI_GEN_INC_FILES): $(DSTROOT)/$(INCDIR)/$(INSTALL_MI_DIR)/% : % fi; \ $(RM) -rf ./incdir; +INSTALL_MI_LCL_FILES = $(addprefix $(SOURCE), $(INSTALL_MI_LCL_LIST)) +INSTALL_MI_GEN_LCL_FILES = $(addprefix $(DSTROOT)/$(LCLDIR)/$(INSTALL_MI_DIR)/, $(INSTALL_MI_LCL_GEN_LIST)) + $(INSTALL_MI_GEN_LCL_FILES): $(DSTROOT)/$(LCLDIR)/$(INSTALL_MI_DIR)/% : % @true echo Installing $< in $(dir $@); \ $(MKDIR) $(DSTROOT)/$(LCLDIR)/$(INSTALL_MI_DIR); \ $(RM) $(RMFLAGS) $@; \ install $(INSTALL_FLAGS) $< $(dir $@); +INSTALL_MI_LCL_KERN_FILES = $(addprefix $(SOURCE), $(INSTALL_MI_LCL_KERN_LIST)) +INSTALL_MI_GEN_LCL_KERN_FILES = $(addprefix $(KPINCDIR)/$(LCLDIR)/$(INSTALL_MI_DIR)/, $(INSTALL_MI_LCL_KERN_GEN_LIST)) + +$(INSTALL_MI_GEN_LCL_KERN_FILES): $(DSTROOT)/$(KPINCDIR)/$(INSTALL_MI_DIR)/% : % + @true echo Installing $< in $(dir $@); \ + $(MKDIR) $(DSTROOT)/$(KPINCDIR)/$(INSTALL_MI_DIR); \ + $(RM) $(RMFLAGS) $@; \ + install $(INSTALL_FLAGS) $< $(dir $@); + INSTALL_MD_INC_FILES = $(addprefix $(SOURCE), $(INSTALL_MD_LIST)) INSTALL_MD_GEN_INC_FILES = $(addprefix $(DSTROOT)/$(INCDIR)/$(INSTALL_MD_DIR)/, $(INSTALL_MD_GEN_LIST)) -INSTALL_MD_LCL_FILES = $(addprefix $(SOURCE), $(INSTALL_MD_LCL_LIST)) -INSTALL_MD_GEN_LCL_FILES = $(addprefix $(DSTROOT)/$(LCLDIR)/$(INSTALL_MD_DIR)/, $(INSTALL_MD_LCL_GEN_LIST)) - $(INSTALL_MD_GEN_INC_FILES): $(DSTROOT)/$(INCDIR)/$(INSTALL_MD_DIR)/% : % @true echo Installing $< in $(dir $@); \ $(MKDIR) $(DSTROOT)/$(INCDIR)/$(INSTALL_MD_DIR); \ @@ -163,17 +212,29 @@ $(INSTALL_MD_GEN_INC_FILES): $(DSTROOT)/$(INCDIR)/$(INSTALL_MD_DIR)/% : % fi; \ $(RM) -rf /incdir; +INSTALL_MD_LCL_FILES = $(addprefix $(SOURCE), $(INSTALL_MD_LCL_LIST)) +INSTALL_MD_GEN_LCL_FILES = $(addprefix $(DSTROOT)/$(LCLDIR)/$(INSTALL_MD_DIR)/, $(INSTALL_MD_LCL_GEN_LIST)) + $(INSTALL_MD_GEN_LCL_FILES): $(DSTROOT)/$(LCLDIR)/$(INSTALL_MD_DIR)/% : % @true echo Installing $< in $(dir $@); \ $(MKDIR) $(DSTROOT)/$(LCLDIR)/$(INSTALL_MD_DIR); \ $(RM) $(RMFLAGS) $@; \ install $(INSTALL_FLAGS) $< $(dir $@); +INSTALL_MD_LCL_KERN_FILES = $(addprefix $(SOURCE), $(INSTALL_MD_LCL_KERN_LIST)) +INSTALL_MD_GEN_LCL_KERN_FILES = $(addprefix $(KPINCDIR)/$(LCLDIR)/$(INSTALL_MD_DIR)/, $(INSTALL_MD_LCL_KERN_GEN_LIST)) + +$(INSTALL_MD_GEN_LCL_KERN_FILES): $(DSTROOT)/$(KPINCDIR)/$(INSTALL_MD_DIR)/% : % + @true echo Installing $< in $(dir $@); \ + $(MKDIR) $(DSTROOT)/$(KPINCDIR)/$(INSTALL_MD_DIR); \ + $(RM) $(RMFLAGS) $@; \ + install $(INSTALL_FLAGS) $< $(dir $@); + setup_installhdrs_mi: @echo "[ $(SOURCE) ] make setup_installhdrs_mi $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)" -do_installhdrs_mi: $(INSTALL_MI_GEN_INC_FILES) $(INSTALL_MI_GEN_LCL_FILES) - @echo "[ $(SOURCE) ] make do_installhdrs_mi $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)" +do_installhdrs_mi: $(INSTALL_MI_GEN_INC_FILES) $(INSTALL_MI_GEN_LCL_FILES) $(INSTALL_MI_GEN_LCL_KERN_FILES) + @true echo "[ $(SOURCE) ] make do_installhdrs_mi $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)" @if [ -n "$(strip $(INSTALL_MI_LIST))" ]; then \ if [ -d $(DSTROOT)/$(INCDIR)/$(INSTALL_MI_DIR) ]; then \ (cd $(DSTROOT)/$(INCDIR)/$(INSTALL_MI_DIR);$(RM) $(RMFLAGS) $(INSTALL_MI_LIST) ); \ @@ -206,12 +267,20 @@ do_installhdrs_mi: $(INSTALL_MI_GEN_INC_FILES) $(INSTALL_MI_GEN_LCL_FILES) fi; \ install $(INSTALL_FLAGS) $(INSTALL_MI_LCL_FILES) $(DSTROOT)/$(LCLDIR)/$(INSTALL_MI_DIR); \ fi + @if [ -n "$(strip $(INSTALL_MI_LCL_KERN_LIST))" ]; then \ + if [ -d $(DSTROOT)/$(KPINCDIR)/$(INSTALL_MI_DIR) ]; then \ + (cd $(DSTROOT)/$(KPINCDIR)/$(INSTALL_MI_DIR);$(RM) $(RMFLAGS) $(INSTALL_MI_LCL_KERN_LIST) ); \ + else \ + $(MKDIR) $(DSTROOT)/$(KPINCDIR)/$(INSTALL_MI_DIR); \ + fi; \ + install $(INSTALL_FLAGS) $(INSTALL_MI_LCL_KERN_FILES) $(DSTROOT)/$(KPINCDIR)/$(INSTALL_MI_DIR); \ + fi setup_installhdrs_md: @echo "[ $(SOURCE) ] make setup_installhdrs_md $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)" -do_installhdrs_md: $(INSTALL_MD_GEN_INC_FILES) $(INSTALL_MD_GEN_LCL_FILES) - @echo "[ $(SOURCE) ] make do_installhdrs_md $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)" +do_installhdrs_md: $(INSTALL_MD_GEN_INC_FILES) $(INSTALL_MD_GEN_LCL_FILES) $(INSTALL_MI_GEN_LCL_KERN_FILES) + @true echo "[ $(SOURCE) ] make do_installhdrs_md $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)" @if [ -n "$(strip $(INSTALL_MD_LIST))" ]; then \ if [ -d $(DSTROOT)/$(INCDIR)/$(INSTALL_MD_DIR) ]; then \ (cd $(DSTROOT)/$(INCDIR)/$(INSTALL_MD_DIR);$(RM) $(RMFLAGS) $(INSTALL_MD_LIST) ); \ @@ -244,6 +313,14 @@ do_installhdrs_md: $(INSTALL_MD_GEN_INC_FILES) $(INSTALL_MD_GEN_LCL_FILES) fi; \ install $(INSTALL_FLAGS) $(INSTALL_MD_LCL_FILES) $(DSTROOT)/$(LCLDIR)/$(INSTALL_MD_DIR); \ fi + @if [ -n "$(strip $(INSTALL_MD_LCL_KERN_LIST))" ]; then \ + if [ -d $(DSTROOT)/$(KPINCDIR)/$(INSTALL_MD_DIR) ]; then \ + (cd $(DSTROOT)/$(KPINCDIR)/$(INSTALL_MD_DIR);$(RM) $(RMFLAGS) $(INSTALL_MD_LCL_KERN_LIST) ); \ + else \ + $(MKDIR) $(DSTROOT)/$(KPINCDIR)/$(INSTALL_MD_DIR); \ + fi; \ + install $(INSTALL_FLAGS) $(INSTALL_MD_LCL_KERN_FILES) $(DSTROOT)/$(KPINCDIR)/$(INSTALL_MD_DIR); \ + fi endif @@ -274,13 +351,13 @@ setup_exporthdrs_mi: @echo "[ $(SOURCE) ] make setup_exporthdrs_mi $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)" do_exporthdrs_mi: $(EXPORT_MI_INC_FILES) $(EXPORT_MI_GEN_INC_FILES) - @echo "[ $(SOURCE) ] make do_exporthdrs_mi $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)" + @true echo "[ $(SOURCE) ] make do_exporthdrs_mi $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)" setup_exporthdrs_md: @echo "[ $(SOURCE) ] make setup_exporthdrs_md $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)" do_exporthdrs_md: $(EXPORT_MD_INC_FILES) $(EXPORT_MD_GEN_INC_FILES) - @echo "[ $(SOURCE) ] make do_exporthdrs_md $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)" + @true echo "[ $(SOURCE) ] make do_exporthdrs_md $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)" else @@ -305,7 +382,7 @@ setup_exporthdrs_mi: @echo "[ $(SOURCE) ] make setup_exporthdrs_mi $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)" do_exporthdrs_mi: $(EXPORT_MI_GEN_INC_FILES) - @echo "[ $(SOURCE) ] make do_exporthdrs_mi $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)" + @true echo "[ $(SOURCE) ] make do_exporthdrs_mi $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)" @if [ -n "$(strip $(EXPORT_MI_LIST))" ]; then \ if [ -d $(OBJROOT)/$(EXPDIR)/$(EXPORT_MI_DIR) ]; then \ (cd $(OBJROOT)/$(EXPDIR)/$(EXPORT_MI_DIR);$(RM) $(RMFLAGS) $(EXPORT_MI_LIST) ); \ @@ -319,7 +396,7 @@ setup_exporthdrs_md: @echo "[ $(SOURCE) ] make setup_exporthdrs_md $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)" do_exporthdrs_md: $(EXPORT_MD_GEN_INC_FILES) - @echo "[ $(SOURCE) ] make do_exporthdrs_md $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)" + @true echo "[ $(SOURCE) ] make do_exporthdrs_md $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)" @if [ -n "$(strip $(EXPORT_MD_LIST))" ]; then \ if [ -d $(OBJROOT)/$(EXPDIR)/$(EXPORT_MD_DIR) ]; then \ (cd $(OBJROOT)/$(EXPDIR)/$(EXPORT_MD_DIR);$(RM) $(RMFLAGS) $(EXPORT_MD_LIST) ); \ @@ -395,9 +472,9 @@ M_RULE_4= # The config tool slickly changes the last source filename char to 'o' # for the object filename. # -P_RULE_1A=${KCC} -o $@ -c ${CPPFLAGS} ${CFLAGS} -MD ${${join $@,_CFLAGS}} ${INCFLAGS} ${${join $@,_INCFLAGS}} +P_RULE_1A=${KC++} -o $@ -c ${CPPFLAGS} ${CFLAGS} -MD ${${join $@,_CFLAGS}} ${INCFLAGS} ${${join $@,_INCFLAGS}} P_RULE_1B=$( $(@:.cpo=.d~) && mv $(@:.cpo=.d~) $(@:.cpo=.d) +P_RULE_2=@sed 's/.c.o: /.cpo: /' $(@:.cpo=.d) > $(@:.cpo=.d~) && mv $(@:.cpo=.d~) $(@:.cpo=.d) P_RULE_3= P_RULE_4= @@ -417,7 +494,7 @@ setup_build_all: @echo "[ $(SOURCE) ] make setup_build_all $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)" do_build_all: $(COMP_FILES) $(COMP_COBJ_FILES) $(COMP_SOBJ_FILES) $(COMPONENT_IMAGE_FILE) - @echo "[ $(SOURCE) ] make do_build_all $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)" + @true echo "[ $(SOURCE) ] make do_build_all $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)" ifeq ($(COMPONENT), .) do_build_all: do_build_mach_kernel @@ -484,6 +561,30 @@ setup_build_install: do_build_install: $(INSTALL_FILESYS_FILES) $(INSTALL_FILE_FILES) @echo "[ $(SOURCE) ] make do_build_install $(KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)" +INSTALL_MAN_FILES = $(addprefix $(DSTROOT)/$(MANDIR)/$(INSTALL_MAN_DIR)/, $(INSTALL_MAN_LIST)) + +do_installman: $(INSTALL_MAN_FILES) + @echo "[ $(SOURCE) ] make do_installman" + @if [ -n "$(strip $(INSTALL_MAN_LIST))" ]; then \ + man_dir=$(DSTROOT)/$(MANDIR)/$(INSTALL_MAN_DIR); \ + if [ -d $$man_dir ]; then \ + cur_dir=`pwd`; \ + cd $$man_dir; \ + $(RM) $(RMFLAGS) $(INSTALL_MAN_LIST); \ + cd $$cur_dir; \ + else \ + $(MKDIR) $$man_dir; \ + fi; \ + echo Installing $(INSTALL_MAN_LIST) in $$man_dir; \ + install $(INSTALL_FLAGS) $(INSTALL_MAN_LIST) $$man_dir; \ + fi + +$(INSTALL_MAN_FILES): $(DSTROOT)/$(MANDIR)/$(INSTALL_MAN_DIR)/% : % + @true echo Installing $< in $(dir $@); \ + $(MKDIR) $(DSTROOT)/$(MANDIR)/$(INSTALL_MAN_DIR); \ + $(RM) $(RMFLAGS) $@; \ + install $(INSTALL_FLAGS) $< $(dir $@); + ifeq ($(INCL_MAKEDEP), TRUE) -include Makedep endif diff --git a/osfmk/.gdbinit b/osfmk/.gdbinit index 127a23ae2..c560a9709 100644 --- a/osfmk/.gdbinit +++ b/osfmk/.gdbinit @@ -8,6 +8,9 @@ set $kgm_vers = 2 +set $kgm_dummy = &proc0 +set $kgm_dummy = &kmod + echo Loading Kernel GDB Macros package. Type "help kgm" for more info.\n define kgm @@ -57,6 +60,11 @@ document kgm | showkmodaddr Given an address, display the kernel module and offset | | zprint Display zone information +| paniclog Display the panic log information +| +| switchtoact Switch thread context +| switchtoctx Switch context +| resetctx Reset context | | Type "help " for more specific help on a particular macro. | Type "show user " to see what the macro is really doing. @@ -158,7 +166,7 @@ end define showactint printf " 0x%08x ", $arg0 - set $kgm_actp = *(Thread_Activation *)$arg0 + set $kgm_actp = *(struct thread_activation *)$arg0 if $kgm_actp.thread set $kgm_thread = *$kgm_actp.thread printf "0x%08x ", $kgm_actp.thread @@ -196,7 +204,7 @@ define showactint printf "\n\t\tstack_privilege=0x%08x", $kgm_thread.stack_privilege end printf "\n\t\tkernel_stack=0x%08x", $kgm_thread.kernel_stack - set $mysp = $kgm_actp->mact.pcb.ss.r1 + set $mysp = $kgm_actp->mact.pcb->save_r1 set $prevsp = 0 printf "\n\t\tstacktop=0x%08x", $mysp while ($mysp != 0) && (($mysp & 0xf) == 0) && ($mysp < 0xb0000000) && ($mysp > $prevsp) @@ -246,19 +254,19 @@ end define showallacts set $kgm_head_taskp = &default_pset.tasks - set $kgm_taskp = (Task *)($kgm_head_taskp->next) + set $kgm_taskp = (struct task *)($kgm_head_taskp->next) while $kgm_taskp != $kgm_head_taskp showtaskheader showtaskint $kgm_taskp showactheader set $kgm_head_actp = &($kgm_taskp->thr_acts) - set $kgm_actp = (Thread_Activation *)($kgm_taskp->thr_acts.next) + set $kgm_actp = (struct thread_activation *)($kgm_taskp->thr_acts.next) while $kgm_actp != $kgm_head_actp showactint $kgm_actp 0 - set $kgm_actp = (Thread_Activation *)($kgm_actp->thr_acts.next) + set $kgm_actp = (struct thread_activation *)($kgm_actp->thr_acts.next) end printf "\n" - set $kgm_taskp = (Task *)($kgm_taskp->pset_tasks.next) + set $kgm_taskp = (struct task *)($kgm_taskp->pset_tasks.next) end end document showallacts @@ -270,19 +278,19 @@ end define showallstacks set $kgm_head_taskp = &default_pset.tasks - set $kgm_taskp = (Task *)($kgm_head_taskp->next) + set $kgm_taskp = (struct task *)($kgm_head_taskp->next) while $kgm_taskp != $kgm_head_taskp showtaskheader showtaskint $kgm_taskp set $kgm_head_actp = &($kgm_taskp->thr_acts) - set $kgm_actp = (Thread_Activation *)($kgm_taskp->thr_acts.next) + set $kgm_actp = (struct thread_activation *)($kgm_taskp->thr_acts.next) while $kgm_actp != $kgm_head_actp showactheader showactint $kgm_actp 1 - set $kgm_actp = (Thread_Activation *)($kgm_actp->thr_acts.next) + set $kgm_actp = (struct thread_activation *)($kgm_actp->thr_acts.next) end printf "\n" - set $kgm_taskp = (Task *)($kgm_taskp->pset_tasks.next) + set $kgm_taskp = (struct task *)($kgm_taskp->pset_tasks.next) end end document showallstacks @@ -291,65 +299,160 @@ document showallstacks | (gdb) showallstacks end +define showwaiterheader + printf "waiters activation " + printf "thread pri state wait_queue wait_event\n" +end + +define showwaitqwaiters + set $kgm_w_waitqp = (struct wait_queue *)$arg0 + set $kgm_w_linksp = &($kgm_w_waitqp->wq_queue) + set $kgm_w_wqe = (struct wait_queue_element *)$kgm_w_linksp->next + set $kgm_w_found = 0 + while ( (queue_entry_t)$kgm_w_wqe != (queue_entry_t)$kgm_w_linksp) + if ($kgm_w_wqe->wqe_type != &_wait_queue_link) + if !$kgm_w_found + set $kgm_w_found = 1 + showwaiterheader + end + set $kgm_w_shuttle = (struct thread_shuttle *)$kgm_w_wqe + showactint $kgm_w_shuttle->top_act 0 + end + set $kgm_w_wqe = (struct wait_queue_element *)$kgm_w_wqe->wqe_links.next + end +end + +define showwaitqwaitercount + set $kgm_wc_waitqp = (struct wait_queue *)$arg0 + set $kgm_wc_linksp = &($kgm_wc_waitqp->wq_queue) + set $kgm_wc_wqe = (struct wait_queue_element *)$kgm_wc_linksp->next + set $kgm_wc_count = 0 + while ( (queue_entry_t)$kgm_wc_wqe != (queue_entry_t)$kgm_wc_linksp) + if ($kgm_wc_wqe->wqe_type != &_wait_queue_link) + set $kgm_wc_count = $kgm_wc_count + 1 + end + set $kgm_wc_wqe = (struct wait_queue_element *)$kgm_wc_wqe->wqe_links.next + end + printf "0x%08x ", $kgm_wc_count +end + define showwaitqmembercount - set $kgm_waitqsubp = (wait_queue_sub_t)$arg0 - set $kgm_sublinksp = &($kgm_waitqsubp->wqs_sublinks) - set $kgm_wql = (wait_queue_link_t)$kgm_sublinksp->next - set $kgm_count = 0 - while ( (queue_entry_t)$kgm_wql != (queue_entry_t)$kgm_sublinksp) - set $kgm_waitqp = $kgm_wql->wql_element->wqe_queue - if !$kgm_found - showwaitqmemberheader - set $kgm_found = 1 - end - showwaitqmemberint $kgm_waitqp + set $kgm_mc_waitqsetp = (struct wait_queue_set *)$arg0 + set $kgm_mc_setlinksp = &($kgm_mc_waitqsetp->wqs_setlinks) + set $kgm_mc_wql = (struct wait_queue_link *)$kgm_mc_setlinksp->next + set $kgm_mc_count = 0 + while ( (queue_entry_t)$kgm_mc_wql != (queue_entry_t)$kgm_mc_setlinksp) + set $kgm_mc_count = $kgm_mc_count + 1 + set $kgm_mc_wql = (struct wait_queue_link *)$kgm_mc_wql->wql_setlinks.next end + printf "0x%08x ", $kgm_mc_count end +define showwaitqmemberheader + printf "set-members wait_queue interlock " + printf "pol type member_cnt waiter_cnt\n" +end + define showwaitqmemberint - set $kgm_waitqp = (wait_queue_t)$arg0 - printf " 0x%08x ", $kgm_waitqp - printf "0x%08x ", $kgm_waitqp->wq_interlock - if ($kgm_waitqp->wq_fifo) - printf "Fifo" + set $kgm_m_waitqp = (struct wait_queue *)$arg0 + printf " 0x%08x ", $kgm_m_waitqp + printf "0x%08x ", $kgm_m_waitqp->wq_interlock.lock_data + if ($kgm_m_waitqp->wq_fifo) + printf "Fifo " else - printf "Prio" + printf "Prio " end - if ($kgm_waitqp->wq_issub) - printf "S" + if ($kgm_m_waitqp->wq_type == 0xf1d1) + printf "Set " + showwaitqmembercount $kgm_m_waitqp else - printf " " + printf "Que 0x00000000 " end - printf " " - showwaitqwaitercount $kgm_waitqp - showwaitqmembercount $kgm_waitqp + showwaitqwaitercount $kgm_m_waitqp printf "\n" end +define showwaitqmemberofheader + printf "member-of wait_queue interlock " + printf "pol type member_cnt waiter_cnt\n" +end + +define showwaitqmemberof + set $kgm_mo_waitqp = (struct wait_queue *)$arg0 + set $kgm_mo_linksp = &($kgm_mo_waitqp->wq_queue) + set $kgm_mo_wqe = (struct wait_queue_element *)$kgm_mo_linksp->next + set $kgm_mo_found = 0 + while ( (queue_entry_t)$kgm_mo_wqe != (queue_entry_t)$kgm_mo_linksp) + if ($kgm_mo_wqe->wqe_type == &_wait_queue_link) + if !$kgm_mo_found + set $kgm_mo_found = 1 + showwaitqmemberofheader + end + set $kgm_mo_wqlp = (struct wait_queue_link *)$kgm_mo_wqe + set $kgm_mo_wqsetp = (struct wait_queue *)($kgm_mo_wqlp->wql_setqueue) + showwaitqmemberint $kgm_mo_wqsetp + end + set $kgm_mo_wqe = (struct wait_queue_element *)$kgm_mo_wqe->wqe_links.next + end +end + define showwaitqmembers - set $kgm_waitqsubp = (wait_queue_sub_t)$arg0 - set $kgm_sublinksp = &($kgm_waitqsubp->wqs_sublinks) - set $kgm_wql = (wait_queue_link_t)$kgm_sublinksp->next - set $kgm_found = 0 - while ( (queue_entry_t)$kgm_wql != (queue_entry_t)$kgm_sublinksp) - set $kgm_waitqp = $kgm_wql->wql_element->wqe_queue - if !$kgm_found + set $kgm_ms_waitqsetp = (struct wait_queue_set *)$arg0 + set $kgm_ms_setlinksp = &($kgm_ms_waitqsetp->wqs_setlinks) + set $kgm_ms_wql = (struct wait_queue_link *)$kgm_ms_setlinksp->next + set $kgm_ms_found = 0 + while ( (queue_entry_t)$kgm_ms_wql != (queue_entry_t)$kgm_ms_setlinksp) + set $kgm_ms_waitqp = $kgm_ms_wql->wql_element.wqe_queue + if !$kgm_ms_found showwaitqmemberheader - set $kgm_found = 1 + set $kgm_ms_found = 1 end - showwaitqmemberint $kgm_waitqp + showwaitqmemberint $kgm_ms_waitqp + set $kgm_ms_wql = (struct wait_queue_link *)$kgm_ms_wql->wql_setlinks.next end end +define showwaitqheader + printf "wait_queue ref_count interlock " + printf "pol type member_cnt waiter_cnt\n" +end + +define showwaitqint + set $kgm_waitqp = (struct wait_queue *)$arg0 + printf "0x%08x ", $kgm_waitqp + if ($kgm_waitqp->wq_type == 0xf1d1) + printf "0x%08x ", ((struct wait_queue_set *)$kgm_waitqp)->wqs_refcount + else + printf "0x00000000 " + end + printf "0x%08x ", $kgm_waitqp->wq_interlock.lock_data + if ($kgm_waitqp->wq_fifo) + printf "Fifo " + else + printf "Prio " + end + if ($kgm_waitqp->wq_type == 0xf1d1) + printf "Set " + showwaitqmembercount $kgm_waitqp + else + printf "Que 0x00000000 " + end + showwaitqwaitercount $kgm_waitqp + printf "\n" +end + define showwaitq - set $kgm_waitq = (wait_queue_t)$arg0 + set $kgm_waitq1p = (wait_queue_t)$arg0 showwaitqheader - showwaitqwaiters - if ($kgm_waitq->wq_issub) - showwaitqmembers + showwaitqint $kgm_waitq1p + if ($kgm_waitq1p->wq_type == 0xf1d1) + showwaitqmembers $kgm_waitq1p + else + showwaitqmemberof $kgm_waitq1p end + showwaitqwaiters $kgm_waitq1p end define showmapheader @@ -436,13 +539,13 @@ end define showallvm set $kgm_head_taskp = &default_pset.tasks - set $kgm_taskp = (Task *)($kgm_head_taskp->next) + set $kgm_taskp = (struct task *)($kgm_head_taskp->next) while $kgm_taskp != $kgm_head_taskp showtaskheader showmapheader showtaskint $kgm_taskp showvmint $kgm_taskp->map 0 - set $kgm_taskp = (Task *)($kgm_taskp->pset_tasks.next) + set $kgm_taskp = (struct task *)($kgm_taskp->pset_tasks.next) end end document showallvm @@ -454,13 +557,13 @@ end define showallvme set $kgm_head_taskp = &default_pset.tasks - set $kgm_taskp = (Task *)($kgm_head_taskp->next) + set $kgm_taskp = (struct task *)($kgm_head_taskp->next) while $kgm_taskp != $kgm_head_taskp showtaskheader showmapheader showtaskint $kgm_taskp showvmint $kgm_taskp->map 1 - set $kgm_taskp = (Task *)($kgm_taskp->pset_tasks.next) + set $kgm_taskp = (struct task *)($kgm_taskp->pset_tasks.next) end end document showallvme @@ -620,13 +723,13 @@ end define showallipc set $kgm_head_taskp = &default_pset.tasks - set $kgm_taskp = (Task *)($kgm_head_taskp->next) + set $kgm_taskp = (struct task *)($kgm_head_taskp->next) while $kgm_taskp != $kgm_head_taskp showtaskheader showipcheader showtaskint $kgm_taskp showipcint $kgm_taskp->itk_space 0 - set $kgm_taskp = (Task *)($kgm_taskp->pset_tasks.next) + set $kgm_taskp = (struct task *)($kgm_taskp->pset_tasks.next) end end document showallipc @@ -638,13 +741,13 @@ end define showallrights set $kgm_head_taskp = &default_pset.tasks - set $kgm_taskp = (Task *)($kgm_head_taskp->next) + set $kgm_taskp = (struct task *)($kgm_head_taskp->next) while $kgm_taskp != $kgm_head_taskp showtaskheader showipcheader showtaskint $kgm_taskp showipcint $kgm_taskp->itk_space 1 - set $kgm_taskp = (Task *)($kgm_taskp->pset_tasks.next) + set $kgm_taskp = (struct task *)($kgm_taskp->pset_tasks.next) end end document showallrights @@ -688,7 +791,7 @@ end define showtaskint - set $kgm_task = *(Task *)$arg0 + set $kgm_task = *(struct task *)$arg0 printf "0x%08x ", $arg0 printf "0x%08x ", $kgm_task.map printf "0x%08x ", $kgm_task.itk_space @@ -709,14 +812,14 @@ end define showtaskacts showtaskheader - set $kgm_taskp = (Task *)$arg0 + set $kgm_taskp = (struct task *)$arg0 showtaskint $kgm_taskp showactheader set $kgm_head_actp = &($kgm_taskp->thr_acts) - set $kgm_actp = (Thread_Activation *)($kgm_taskp->thr_acts.next) + set $kgm_actp = (struct thread_activation *)($kgm_taskp->thr_acts.next) while $kgm_actp != $kgm_head_actp showactint $kgm_actp 0 - set $kgm_actp = (Thread_Activation *)($kgm_actp->thr_acts.next) + set $kgm_actp = (struct thread_activation *)($kgm_actp->thr_acts.next) end end document showtaskacts @@ -728,14 +831,14 @@ end define showtaskstacks showtaskheader - set $kgm_taskp = (Task *)$arg0 + set $kgm_taskp = (struct task *)$arg0 showtaskint $kgm_taskp set $kgm_head_actp = &($kgm_taskp->thr_acts) - set $kgm_actp = (Thread_Activation *)($kgm_taskp->thr_acts.next) + set $kgm_actp = (struct thread_activation *)($kgm_taskp->thr_acts.next) while $kgm_actp != $kgm_head_actp showactheader showactint $kgm_actp 1 - set $kgm_actp = (Thread_Activation *)($kgm_actp->thr_acts.next) + set $kgm_actp = (struct thread_activation *)($kgm_actp->thr_acts.next) end end document showtaskstacks @@ -748,10 +851,10 @@ end define showalltasks showtaskheader set $kgm_head_taskp = &default_pset.tasks - set $kgm_taskp = (Task *)($kgm_head_taskp->next) + set $kgm_taskp = (struct task *)($kgm_head_taskp->next) while $kgm_taskp != $kgm_head_taskp showtaskint $kgm_taskp - set $kgm_taskp = (Task *)($kgm_taskp->pset_tasks.next) + set $kgm_taskp = (struct task *)($kgm_taskp->pset_tasks.next) end end document showalltasks @@ -779,14 +882,14 @@ end define showpid showtaskheader set $kgm_head_taskp = &default_pset.tasks - set $kgm_taskp = (Task *)($kgm_head_taskp->next) + set $kgm_taskp = (struct task *)($kgm_head_taskp->next) while $kgm_taskp != $kgm_head_taskp set $kgm_procp = (struct proc *)$kgm_taskp->bsd_info if (($kgm_procp != 0) && ($kgm_procp->p_pid == $arg0)) showtaskint $kgm_taskp set $kgm_taskp = $kgm_head_taskp else - set $kgm_taskp = (Task *)($kgm_taskp->pset_tasks.next) + set $kgm_taskp = (struct task *)($kgm_taskp->pset_tasks.next) end end end @@ -826,12 +929,12 @@ define showportheader end define showportmemberheader - printf " port recvname " + printf "members port recvname " printf "flags refs mqueue msgcount\n" end define showkmsgheader - printf " kmsg size " + printf "messages kmsg size " printf "disp msgid remote-port local-port\n" end @@ -854,7 +957,7 @@ define showkmsgint else printf "s" end - printf "%5d ", $kgm_kmsgh.msgh_msgid + printf "%5d ", $kgm_kmsgh.msgh_id printf "0x%08x ", $kgm_kmsgh.msgh_remote_port printf "0x%08x\n", $kgm_kmsgh.msgh_local_port end @@ -862,7 +965,7 @@ end define showkobject - set $kgm_portp = (ipc_port_t)$arg0 + set $kgm_portp = (struct ipc_port *)$arg0 printf "0x%08x kobject(", $kgm_portp->ip_kobject set $kgm_kotype = ($kgm_portp->ip_object.io_bits & 0x00000fff) if ($kgm_kotype == 1) @@ -962,19 +1065,19 @@ define showkobject end define showportdestproc - set $kgm_portp = (ipc_port_t)$arg0 + set $kgm_portp = (struct ipc_port *)$arg0 set $kgm_spacep = $kgm_portp->data.receiver # check against the previous cached value - this is slow if ($kgm_spacep != $kgm_destspacep) set $kgm_destprocp = (struct proc *)0 set $kgm_head_taskp = &default_pset.tasks - set $kgm_taskp = (Task *)($kgm_head_taskp->next) + set $kgm_taskp = (struct task *)($kgm_head_taskp->next) while (($kgm_destprocp == 0) && ($kgm_taskp != $kgm_head_taskp)) set $kgm_destspacep = $kgm_taskp->itk_space if ($kgm_destspacep == $kgm_spacep) set $kgm_destprocp = (struct proc *)$kgm_taskp->bsd_info else - set $kgm_taskp = (Task *)($kgm_taskp->pset_tasks.next) + set $kgm_taskp = (struct task *)($kgm_taskp->pset_tasks.next) end end end @@ -986,7 +1089,7 @@ define showportdestproc end define showportdest - set $kgm_portp = (ipc_port_t)$arg0 + set $kgm_portp = (struct ipc_port *)$arg0 set $kgm_spacep = $kgm_portp->data.receiver if ($kgm_spacep == ipc_space_kernel) showkobject $kgm_portp @@ -1002,7 +1105,7 @@ end define showportmember printf " 0x%08x ", $arg0 - set $kgm_portp = (ipc_port_t)$arg0 + set $kgm_portp = (struct ipc_port *)$arg0 printf "0x%08x ", $kgm_portp->ip_object.io_receiver_name if ($kgm_portp->ip_object.io_bits & 0x80000000) printf "A" @@ -1021,7 +1124,7 @@ end define showportint printf "0x%08x ", $arg0 - set $kgm_portp = (ipc_port_t)$arg0 + set $kgm_portp = (struct ipc_port *)$arg0 printf "0x%08x ", &($kgm_portp->ip_messages) printf "0x%08x ", $kgm_portp->ip_object.io_receiver_name if ($kgm_portp->ip_object.io_bits & 0x80000000) @@ -1031,7 +1134,7 @@ define showportint end printf "Port" printf "%5d ", $kgm_portp->ip_object.io_references - set $kgm_destspacep = (ipc_space_t)0 + set $kgm_destspacep = (struct ipc_space *)0 showportdest $kgm_portp set $kgm_kmsgp = (ipc_kmsg_t)$kgm_portp->ip_messages.data.port.messages.ikmq_base if $arg1 && $kgm_kmsgp @@ -1048,7 +1151,7 @@ end define showpsetint printf "0x%08x ", $arg0 - set $kgm_psetp = (ipc_pset_t)$arg0 + set $kgm_psetp = (struct ipc_pset *)$arg0 printf "0x%08x ", &($kgm_psetp->ips_messages) printf "0x%08x ", $kgm_psetp->ips_object.io_receiver_name if ($kgm_psetp->ips_object.io_bits & 0x80000000) @@ -1058,22 +1161,23 @@ define showpsetint end printf "Set " printf "%5d ", $kgm_psetp->ips_object.io_references - set $kgm_sublinksp = &($kgm_psetp->ips_messages.data.set_queue.wqs_sublinks) - set $kgm_wql = (wait_queue_link_t)$kgm_sublinksp->next + printf "0x%08x ", $kgm_psetp->ips_object.io_receiver_name + set $kgm_setlinksp = &($kgm_psetp->ips_messages.data.set_queue.wqs_setlinks) + set $kgm_wql = (struct wait_queue_link *)$kgm_setlinksp->next set $kgm_found = 0 - while ( (queue_entry_t)$kgm_wql != (queue_entry_t)$kgm_sublinksp) - set $kgm_portp = (ipc_port_t)((int)($kgm_wql->wql_element->wqe_queue) - ((int)$kgm_portoff)) + while ( (queue_entry_t)$kgm_wql != (queue_entry_t)$kgm_setlinksp) + set $kgm_portp = (struct ipc_port *)((int)($kgm_wql->wql_element->wqe_queue) - ((int)$kgm_portoff)) if !$kgm_found - set $kgm_destspacep = (ipc_space_t)0 - showportdest $kgm_portp + set $kgm_destspacep = (struct ipc_space *)0 + showportdestproc $kgm_portp showportmemberheader set $kgm_found = 1 end showportmember $kgm_portp 0 - set $kgm_wql = (wait_queue_link_t)$kgm_wql->wql_sublinks.next + set $kgm_wql = (struct wait_queue_link *)$kgm_wql->wql_setlinks.next end - if !$kgm_found - printf "--n/e-- --n/e--\n" + if !$kgm_found + printf "--n/e--\n" end end @@ -1097,14 +1201,15 @@ define showipcobject end define showmqueue - set $kgm_mqueue = *(ipc_mqueue_t)$arg0 - set $kgm_psetoff = &(((ipc_pset_t)0)->ips_messages) - set $kgm_portoff = &(((ipc_port_t)0)->ip_messages) - if ($kgm_mqueue.data.set_queue.wqs_wait_queue.wq_issub) + set $kgm_mqueue = *(struct ipc_mqueue *)$arg0 + set $kgm_psetoff = &(((struct ipc_pset *)0)->ips_messages) + set $kgm_portoff = &(((struct ipc_port *)0)->ip_messages) + if ($kgm_mqueue.data.set_queue.wqs_wait_queue.wq_type == 0xf1d1) set $kgm_pset = (((int)$arg0) - ((int)$kgm_psetoff)) showpsetheader showpsetint $kgm_pset 1 - else + end + if ($kgm_mqueue.data.set_queue.wqs_wait_queue.wq_type == 0xf1d0) showportheader set $kgm_port = (((int)$arg0) - ((int)$kgm_portoff)) showportint $kgm_port 1 @@ -1150,3 +1255,96 @@ document zprint | (gdb) zprint end +set $kdp_act_counter = 0 + +define switchtoact + if (machine_slot[0].cpu_type == 18) + if ($kdp_act_counter == 0) + set $kdpstate = (struct savearea *) kdp.saved_state + end + set $kdp_act_counter = $kdp_act_counter + 1 + set $newact = (struct thread_activation *) $arg0 + if (($newact.thread)->kernel_stack == 0) + echo This activation does not have a stack.\n + echo continuation: + output/a $newact.thread.continuation + echo \n + end + set (struct savearea *) kdp.saved_state=$newact->mact->pcb + flush + set $pc=$newact->mact->pcb.save_srr0 + update + else + echo switchtoact not implemented for this architecture.\n + end +end + +document switchtoact +Syntax: switchtoact
+| This command allows gdb to examine the execution context and call +| stack for the specified activation. For example, to view the backtrace +| for an activation issue "switchtoact
", followed by "bt". +| Before resuming execution, issue a "resetctx" command, to +| return to the original execution context. +end + +define switchtoctx + if (machine_slot[0].cpu_type == 18) + if ($kdp_act_counter == 0) + set $kdpstate = (struct savearea *) kdp.saved_state + end + set $kdp_act_counter = $kdp_act_counter + 1 + set (struct savearea *) kdp.saved_state=(struct savearea *) $arg0 + flush + set $pc=((struct savearea *) $arg0)->save_srr0 + update + else + echo switchtoctx not implemented for this architecture.\n + end +end + +document switchtoctx +Syntax: switchtoctx
+| This command allows gdb to examine an execution context and dump the +| backtrace for this execution context. +| Before resuming execution, issue a "resetctx" command, to +| return to the original execution context. +end + +define resetctx + if (machine_slot[0].cpu_type == 18) + set (struct savearea *)kdp.saved_state=$kdpstate + flush + set $pc=((struct savearea *) kdp.saved_state)->save_srr0 + update + set $kdp_act_counter = 0 + else + echo resetctx not implemented for this architecture.\n + end +end + +document resetctx +| Syntax: resetctx +| Returns to the original execution context. This command should be +| issued if you wish to resume execution after using the "switchtoact" +| or "switchtoctx" commands. +end + +define paniclog + set $kgm_panic_bufptr = debug_buf + set $kgm_panic_bufptr_max = debug_buf+debug_buf_size + while *$kgm_panic_bufptr && $kgm_panic_bufptr < $kgm_panic_bufptr_max + if *(char *)$kgm_panic_bufptr == 10 + printf "\n" + else + printf "%c", *$kgm_panic_bufptr + end + set $kgm_panic_bufptr= (char *)$kgm_panic_bufptr + 1 + end +end + +document paniclog +| Syntax: paniclog +| Display the panic log information +| +end diff --git a/osfmk/Makefile b/osfmk/Makefile index 6a4024958..0cf9f4e54 100644 --- a/osfmk/Makefile +++ b/osfmk/Makefile @@ -31,6 +31,7 @@ EXPINC_SUBDIRS = \ profiling \ ddb \ kern \ + kdp \ ipc \ machine \ UserNotification \ diff --git a/osfmk/UserNotification/Makefile b/osfmk/UserNotification/Makefile index 240221383..d1f0b286f 100644 --- a/osfmk/UserNotification/Makefile +++ b/osfmk/UserNotification/Makefile @@ -30,7 +30,9 @@ DATAFILES = \ ${MIG_TYPES} \ ${MIG_DEFS} -INSTALL_MI_LIST = ${DATAFILES} +INSTALL_MI_LIST = + +INSTALL_MI_LCL_LIST = ${DATAFILES} INSTALL_MI_GEN_LIST = diff --git a/osfmk/UserNotification/UNDTypes.h b/osfmk/UserNotification/UNDTypes.h index f80242c42..32581eec0 100644 --- a/osfmk/UserNotification/UNDTypes.h +++ b/osfmk/UserNotification/UNDTypes.h @@ -23,6 +23,10 @@ #ifndef __USERNOTIFICATION_UNDTYPES_H #define __USERNOTIFICATION_UNDTYPES_H +#include + +#ifdef __APPLE_API_PRIVATE + #include typedef char *UNDMessage; @@ -62,5 +66,7 @@ typedef mach_port_t UNDReplyRef; #define UND_REPLY_NULL ((UNDReplyRef)0) #define XML_DATA_NULL ((xmlData_t)0) +#endif /* __APPLE_API_PRIVATE */ + #endif /* __USERNOTIFICATION_UNDTPES_H */ diff --git a/osfmk/conf/MASTER.i386 b/osfmk/conf/MASTER.i386 index f71300ff9..6afea0041 100644 --- a/osfmk/conf/MASTER.i386 +++ b/osfmk/conf/MASTER.i386 @@ -11,12 +11,6 @@ # configuration file for a description of the file format). # ###################################################################### -# HISTORY -# 5-Jun-1998 Umesh Vaishampayan (umeshv@apple.com) -# Deleted obsolete history. Created tagets like RELEASEX, PROFILEX, -# DEBUGX for MacOS X. These in short term will facilitate development -# concurrent to MacOSX. -###################################################################### # # NeXT (PSEUDO-)DEVICES (select any combination) # ex = Excelan EXOS 202 Ethernet interface @@ -52,16 +46,10 @@ # Standard Apple MacOS X Configurations: # -------- ---- -------- --------------- # -# MOSTX = [intel pc mach medium event vol pst gdb kernobjc fixpri simple_clock mdebug kernserv driverkit uxpr kernstack ipc_compat ipc_debug nfsclient nfsserver quota fifo fdesc union portal ffs cd9660 compat_43 revfs] -# RELEASEX = [MOSTX libdriver] -# PROFILEX = [RELEASE profile] -# DEBUGX = [MOSTX libdriver_g debug xpr_debug uxpr diagnostic] -# DEBUG-PROFILEX = [DEBUGX profile] -# osfmk = [intel pc mach small event vol pst gdb kernobjc fixpri simple_clock mkernserv driverkit uxpr kernstack ipc_compat ipc_debug nfsclient nfsserver quota fifo fdesc union portal ffs cd9660 compat_43 revfs mk30 mk30_i386] -# RELEASE = [intel pc iokit mach_pe mach mach_kdp small event vol hd pst gdb kernobjc fixpri simple_clock mkernserv driverkit uxpr kernstack ipc_compat ipc_debug nfsclient nfsserver quota fifo fdesc union portal ffs fb cd9660 compat_43 revfs mk30 mk30_i386] -# DEBUG_KDP = [intel pc iokit mach_pe mach mach_kdp small event vol hd pst gdb kernobjc fixpri simple_clock mkernserv driverkit uxpr kernstack ipc_compat ipc_debug nfsclient nfsserver quota fifo fdesc union portal ffs fb cd9660 compat_43 revfs mk30 mk30_i386 osf_debug debug] -# DEBUG= [intel pc iokit mach_pe mach mach_kdp small event vol hd pst gdb kernobjc fixpri simple_clock mkernserv driverkit uxpr kernstack ipc_compat ipc_debug nfsclient nfsserver quota fifo fdesc union portal ffs fb cd9660 compat_43 revfs mk30 mk30_i386 osf_debug debug] -# RELEASEX = [MOSTX libdriver] +# osfmk = [intel pc mach small event vol pst gdb fixpri simple_clock mkernserv uxpr kernstack ipc_compat ipc_debug mk30 mk30_i386] +# RELEASE = [intel pc iokit mach_pe mach mach_kdp small event vol hd pst gdb fixpri simple_clock mkernserv uxpr kernstack ipc_compat ipc_debug fb mk30 mk30_i386] +# DEBUG_KDP = [intel pc iokit mach_pe mach mach_kdp small event vol hd pst gdb fixpri simple_clock mkernserv uxpr kernstack ipc_compat ipc_debug fb mk30 mk30_i386 osf_debug debug] +# DEBUG= [intel pc iokit mach_pe mach mach_kdp small event vol hd pst gdb fixpri simple_clock mkernserv uxpr kernstack ipc_compat ipc_debug fb mk30 mk30_i386 osf_debug debug] # ###################################################################### # diff --git a/osfmk/conf/Makefile b/osfmk/conf/Makefile index a1d04575e..e9eacc5e9 100644 --- a/osfmk/conf/Makefile +++ b/osfmk/conf/Makefile @@ -52,14 +52,13 @@ do_setup_conf: $(OBJROOT)/$(KERNEL_CONFIG)_$(ARCH_CONFIG)/$(COMPONENT)/doconf \ do_all: do_setup_conf @echo "[ $(SOURCE) ] Starting do_all $(COMPONENT) $(OSFMK_KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)"; \ - (cd $(COMPOBJROOT)/$(OSFMK_KERNEL_CONFIG); \ next_source=$(subst conf/,,$(SOURCE)); \ - ${MAKE} MAKEFILES=$(TARGET)/$(OSFMK_KERNEL_CONFIG)/Makefile \ + ${MAKE} -C $(COMPOBJROOT)/$(OSFMK_KERNEL_CONFIG) \ + MAKEFILES=$(TARGET)/$(OSFMK_KERNEL_CONFIG)/Makefile \ SOURCE=$${next_source} \ TARGET=$(TARGET) \ INCL_MAKEDEP=FALSE \ - build_all \ - ); \ + build_all; \ echo "[ $(SOURCE) ] Returning do_all $(COMPONENT) $(OSFMK_KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)"; do_build_all: do_all diff --git a/osfmk/conf/files b/osfmk/conf/files index dc72c4e15..e4041ccdb 100644 --- a/osfmk/conf/files +++ b/osfmk/conf/files @@ -142,7 +142,6 @@ osfmk/ipc/mig_log.c optional mig_debug osfmk/kern/ast.c standard osfmk/kern/clock.c standard osfmk/kern/counters.c standard -osfmk/kern/cpu_data.c standard osfmk/kern/debug.c standard osfmk/kern/exception.c standard osfmk/kern/etap.c standard @@ -152,7 +151,6 @@ osfmk/kern/ipc_clock.c standard osfmk/kern/ipc_host.c standard osfmk/kern/ipc_kobject.c standard osfmk/kern/ipc_mig.c standard -osfmk/kern/ipc_subsystem.c standard osfmk/kern/ipc_sync.c standard osfmk/kern/ipc_tt.c standard osfmk/kern/kalloc.c standard @@ -172,7 +170,6 @@ osfmk/kern/queue.c standard osfmk/kern/sched_prim.c standard osfmk/kern/sscanf.c standard osfmk/kern/startup.c standard -osfmk/kern/subsystem.c standard osfmk/kern/sync_lock.c standard osfmk/kern/sync_sema.c standard osfmk/kern/syscall_emulation.c standard @@ -185,7 +182,6 @@ osfmk/kern/thread.c standard osfmk/kern/thread_act.c standard osfmk/kern/thread_call.c standard osfmk/kern/thread_policy.c standard -osfmk/kern/thread_pool.c standard osfmk/kern/thread_swap.c standard osfmk/kern/timer.c standard osfmk/kern/timer_call.c standard diff --git a/osfmk/conf/files.ppc b/osfmk/conf/files.ppc index 57f08299e..bef664902 100644 --- a/osfmk/conf/files.ppc +++ b/osfmk/conf/files.ppc @@ -41,10 +41,8 @@ osfmk/ppc/misc_asm.s standard osfmk/ppc/status.c standard osfmk/ppc/io_map.c standard osfmk/ppc/trap.c standard -osfmk/ppc/alignment.c standard osfmk/ppc/pcb.c standard osfmk/ppc/bits.s standard -osfmk/ppc/stubs.c standard osfmk/ppc/cswtch.s standard osfmk/ppc/cache.s standard osfmk/ppc/movc.s standard @@ -60,7 +58,6 @@ osfmk/ppc/machine_routines_asm.s standard #osfmk/ppc/Performance.s standard osfmk/ppc/Emulate.s standard osfmk/ppc/AltiAssist.s standard -osfmk/ppc/bsd_ppc.c optional mach_bsd osfmk/ppc/conf.c standard osfmk/ppc/rtclock.c standard osfmk/ppc/Diagnostics.c standard @@ -76,9 +73,6 @@ osfmk/ppc/POWERMAC/pci_compat.c optional xxx osfmk/ppc/Firmware.s standard osfmk/ppc/FirmwareC.c standard -osfmk/ppc/MPinterfaces.s standard -osfmk/ppc/POWERMAC/mp/MP_2p.s standard -osfmk/ppc/POWERMAC/mp/mp.c standard osfmk/ppc/aligned_data.s standard diff --git a/osfmk/conf/kernelversion.major b/osfmk/conf/kernelversion.major index 7ed6ff82d..1e8b31496 100644 --- a/osfmk/conf/kernelversion.major +++ b/osfmk/conf/kernelversion.major @@ -1 +1 @@ -5 +6 diff --git a/osfmk/conf/kernelversion.minor b/osfmk/conf/kernelversion.minor index 7ed6ff82d..573541ac9 100644 --- a/osfmk/conf/kernelversion.minor +++ b/osfmk/conf/kernelversion.minor @@ -1 +1 @@ -5 +0 diff --git a/osfmk/conf/kernelversion.variant b/osfmk/conf/kernelversion.variant index 8b1378917..e69de29bb 100644 --- a/osfmk/conf/kernelversion.variant +++ b/osfmk/conf/kernelversion.variant @@ -1 +0,0 @@ - diff --git a/osfmk/conf/tools/doconf/doconf.csh b/osfmk/conf/tools/doconf/doconf.csh index 43388c11c..ae5ab908b 100755 --- a/osfmk/conf/tools/doconf/doconf.csh +++ b/osfmk/conf/tools/doconf/doconf.csh @@ -287,7 +287,7 @@ part != 0 {\ # kernel binaries are put). # echo 'builddir "."' >> $SYSCONF.new - set OBJRELDIR=`relpath $OBJROOT $OBJDIR` + set OBJRELDIR=`$RELPATH $OBJROOT $OBJDIR` echo 'objectdir "'$OBJROOT'/'$OBJRELDIR'"' >> $SYSCONF.new set SRCDIR=`dirname $SOURCE` echo 'sourcedir "'$SRCROOT'"' >> $SYSCONF.new diff --git a/osfmk/conf/version.major b/osfmk/conf/version.major index 7ed6ff82d..1e8b31496 100644 --- a/osfmk/conf/version.major +++ b/osfmk/conf/version.major @@ -1 +1 @@ -5 +6 diff --git a/osfmk/conf/version.minor b/osfmk/conf/version.minor index 7ed6ff82d..573541ac9 100644 --- a/osfmk/conf/version.minor +++ b/osfmk/conf/version.minor @@ -1 +1 @@ -5 +0 diff --git a/osfmk/ddb/db_command.c b/osfmk/ddb/db_command.c index 889f447dc..788cb1eeb 100644 --- a/osfmk/ddb/db_command.c +++ b/osfmk/ddb/db_command.c @@ -461,7 +461,6 @@ struct db_command db_show_cmds[] = { { "zone", db_show_one_zone, 0, 0 }, { "simple_lock", db_show_one_simple_lock, 0, 0 }, { "thread_log", (db_func)db_show_thread_log, 0, 0 }, - { "subsystem", db_show_subsystem, 0, 0 }, { "shuttle", db_show_shuttle, 0, 0 }, { "etap_log", db_show_etap_log, 0, 0 }, { (char *)0, } diff --git a/osfmk/ddb/db_print.h b/osfmk/ddb/db_print.h index 469170e37..e3e622889 100644 --- a/osfmk/ddb/db_print.h +++ b/osfmk/ddb/db_print.h @@ -192,12 +192,6 @@ void db_show_one_mutex( db_expr_t count, char * modif); -void db_show_subsystem( - db_expr_t addr, - boolean_t have_addr, - db_expr_t count, - char * modif); - void db_show_runq( db_expr_t addr, boolean_t have_addr, diff --git a/osfmk/default_pager/Makefile b/osfmk/default_pager/Makefile index d0adb5c24..367b888bf 100644 --- a/osfmk/default_pager/Makefile +++ b/osfmk/default_pager/Makefile @@ -131,8 +131,3 @@ ${MIG_KSSRC}: \ include $(MakeInc_rule) include $(MakeInc_dir) - -include $(MakeInc_rule) -include $(MakeInc_dir) - - diff --git a/osfmk/default_pager/default_pager_internal.h b/osfmk/default_pager/default_pager_internal.h index 85699351d..f49036b57 100644 --- a/osfmk/default_pager/default_pager_internal.h +++ b/osfmk/default_pager/default_pager_internal.h @@ -546,6 +546,7 @@ typedef struct vstruct_alias { #define DPT_LOCK_INIT(lock) mutex_init(&(lock), ETAP_DPAGE_VSTRUCT) #define DPT_LOCK(lock) mutex_lock(&(lock)) #define DPT_UNLOCK(lock) mutex_unlock(&(lock)) +#define DPT_SLEEP(lock, e, i) thread_sleep_mutex(&(lock), (event_t)(e), i) #define VS_LOCK_TYPE hw_lock_data_t #define VS_LOCK_INIT(vs) hw_lock_init(&(vs)->vs_lock) #define VS_TRY_LOCK(vs) (VS_LOCK(vs),TRUE) @@ -711,6 +712,7 @@ __private_extern__ void vstruct_list_delete(vstruct_t vs); #define VSL_LOCK() mutex_lock(&vstruct_list.vsl_lock) #define VSL_LOCK_TRY() mutex_try(&vstruct_list.vsl_lock) #define VSL_UNLOCK() mutex_unlock(&vstruct_list.vsl_lock) +#define VSL_SLEEP(e,i) thread_sleep_mutex((e), &vstruct_list.vsl_lock, (i)) #ifdef MACH_KERNEL __private_extern__ zone_t vstruct_zone; diff --git a/osfmk/default_pager/default_pager_types.h b/osfmk/default_pager/default_pager_types.h index 745d22ad2..59d395666 100644 --- a/osfmk/default_pager/default_pager_types.h +++ b/osfmk/default_pager/default_pager_types.h @@ -27,6 +27,10 @@ #ifndef _MACH_DEFAULT_PAGER_TYPES_H_ #define _MACH_DEFAULT_PAGER_TYPES_H_ +#include + +#ifdef __APPLE_API_UNSTABLE + #include #include #include @@ -82,7 +86,6 @@ typedef struct default_pager_object { typedef default_pager_object_t *default_pager_object_array_t; - typedef struct default_pager_page { vm_offset_t dpp_offset; /* offset of the page in its object */ } default_pager_page_t; @@ -96,4 +99,6 @@ typedef default_pager_page_t *default_pager_page_array_t; #define HI_WAT_ALERT 1 #define LO_WAT_ALERT 2 +#endif /* __APPLE_API_UNSTABLE */ + #endif /* _MACH_DEFAULT_PAGER_TYPES_H_ */ diff --git a/osfmk/default_pager/diag.h b/osfmk/default_pager/diag.h index c4c58a688..a6e571cfa 100644 --- a/osfmk/default_pager/diag.h +++ b/osfmk/default_pager/diag.h @@ -26,7 +26,7 @@ #ifndef MACH_KERNEL #ifdef ASSERTIONS #define assert(cond) \ - if (!(cond)) panic("%sassertion: %s", my_name, # cond) + ((void) ((cond) ? 0 : panic("%sassertion: %s", my_name, # cond))) #endif #ifndef ASSERTIONS #define assert(cond) diff --git a/osfmk/default_pager/dp_backing_store.c b/osfmk/default_pager/dp_backing_store.c index e771c10f3..112ced6c6 100644 --- a/osfmk/default_pager/dp_backing_store.c +++ b/osfmk/default_pager/dp_backing_store.c @@ -82,8 +82,8 @@ #define ALLOC_STRIDE (1024 * 1024 * 1024) int physical_transfer_cluster_count = 0; -#define VM_SUPER_CLUSTER 0x20000 -#define VM_SUPER_PAGES 32 +#define VM_SUPER_CLUSTER 0x40000 +#define VM_SUPER_PAGES 64 /* * 0 means no shift to pages, so == 1 page/cluster. 1 would mean @@ -191,9 +191,7 @@ get_read_buffer() return dpt_array[i]; } } - assert_wait(&dpt_array, THREAD_UNINT); - DPT_UNLOCK(dpt_lock); - thread_block((void(*)(void))0); + DPT_SLEEP(dpt_lock, &dpt_array, THREAD_UNINT); } } @@ -650,12 +648,7 @@ ps_delete( while(backing_store_release_trigger_disable != 0) { - assert_wait((event_t) - &backing_store_release_trigger_disable, - THREAD_UNINT); - VSL_UNLOCK(); - thread_block((void (*)(void)) 0); - VSL_LOCK(); + VSL_SLEEP(&backing_store_release_trigger_disable, THREAD_UNINT); } /* we will choose instead to hold a send right */ @@ -701,22 +694,14 @@ ps_delete( UPL_NO_SYNC | UPL_CLEAN_IN_PLACE | UPL_SET_INTERNAL); if(error == KERN_SUCCESS) { -#ifndef ubc_sync_working - upl_commit(upl, NULL); - upl_deallocate(upl); - error = ps_vstruct_transfer_from_segment( - vs, ps, transfer_object); -#else error = ps_vstruct_transfer_from_segment( vs, ps, upl); upl_commit(upl, NULL); upl_deallocate(upl); -#endif - vm_object_deallocate(transfer_object); } else { - vm_object_deallocate(transfer_object); error = KERN_FAILURE; } + vm_object_deallocate(transfer_object); } if(error) { VS_LOCK(vs); @@ -734,12 +719,8 @@ ps_delete( VSL_LOCK(); while(backing_store_release_trigger_disable != 0) { - assert_wait((event_t) - &backing_store_release_trigger_disable, - THREAD_UNINT); - VSL_UNLOCK(); - thread_block((void (*)(void)) 0); - VSL_LOCK(); + VSL_SLEEP(&backing_store_release_trigger_disable, + THREAD_UNINT); } next_vs = (vstruct_t) queue_next(&(vs->vs_links)); @@ -1594,7 +1575,7 @@ ps_deallocate_cluster( &backing_store_release_trigger_disable, THREAD_UNINT); VSL_UNLOCK(); - thread_block((void (*)(void)) 0); + thread_block(THREAD_CONTINUE_NULL); } else { VSL_UNLOCK(); } @@ -2288,7 +2269,7 @@ ps_read_device( (mach_msg_type_number_t *) &bytes_read); if(kr == MIG_NO_REPLY) { assert_wait(&vsa->vsa_lock, THREAD_UNINT); - thread_block((void(*)(void))0); + thread_block(THREAD_CONTINUE_NULL); dev_buffer = vsa->vsa_addr; bytes_read = (unsigned int)vsa->vsa_size; @@ -2561,9 +2542,9 @@ pvs_cluster_read( */ #if USE_PRECIOUS - request_flags = UPL_NO_SYNC | UPL_CLEAN_IN_PLACE | UPL_PRECIOUS; + request_flags = UPL_NO_SYNC | UPL_CLEAN_IN_PLACE | UPL_PRECIOUS | UPL_RET_ONLY_ABSENT; #else - request_flags = UPL_NO_SYNC | UPL_CLEAN_IN_PLACE ; + request_flags = UPL_NO_SYNC | UPL_CLEAN_IN_PLACE | UPL_RET_ONLY_ABSENT; #endif while (cnt && (error == KERN_SUCCESS)) { int ps_info_valid; @@ -3004,8 +2985,8 @@ vs_cluster_write( transfer_size -= seg_size; upl_offset += seg_size; } - must_abort = 0; } + must_abort = 0; } if (must_abort) { boolean_t empty = FALSE; @@ -3191,11 +3172,7 @@ kern_return_t ps_vstruct_transfer_from_segment( vstruct_t vs, paging_segment_t segment, -#ifndef ubc_sync_working - vm_object_t transfer_object) -#else upl_t upl) -#endif { struct vs_map *vsmap; struct vs_map old_vsmap; @@ -3246,11 +3223,7 @@ vs_changed: (vm_page_size * (j << vs->vs_clshift)) + clmap_off, vm_page_size << vs->vs_clshift, -#ifndef ubc_sync_working - transfer_object) -#else upl) -#endif != KERN_SUCCESS) { VS_LOCK(vs); vs->vs_xfer_pending = FALSE; @@ -3292,11 +3265,7 @@ vs_changed: if(vs_cluster_transfer(vs, vm_page_size * (j << vs->vs_clshift), vm_page_size << vs->vs_clshift, -#ifndef ubc_sync_working - transfer_object) != KERN_SUCCESS) { -#else upl) != KERN_SUCCESS) { -#endif VS_LOCK(vs); vs->vs_xfer_pending = FALSE; VS_UNLOCK(vs); @@ -3356,11 +3325,7 @@ vs_cluster_transfer( vstruct_t vs, vm_offset_t offset, vm_size_t cnt, -#ifndef ubc_sync_working - vm_object_t transfer_object) -#else upl_t upl) -#endif { vm_offset_t actual_offset; paging_segment_t ps; @@ -3376,10 +3341,6 @@ vs_cluster_transfer( struct vs_map original_read_vsmap; struct vs_map write_vsmap; upl_t sync_upl; -#ifndef ubc_sync_working - upl_t upl; -#endif - vm_offset_t ioaddr; /* vs_cluster_transfer reads in the pages of a cluster and @@ -3483,30 +3444,15 @@ vs_cluster_transfer( if(ps->ps_segtype == PS_PARTITION) { /* - NEED TO BE WITH SYNC & NO COMMIT + NEED TO ISSUE WITH SYNC & NO COMMIT error = ps_read_device(ps, actual_offset, &buffer, size, &residual, flags); */ } else { -#ifndef ubc_sync_working - int page_list_count = 0; - - error = vm_object_upl_request(transfer_object, -(vm_object_offset_t) (actual_offset & ((vm_page_size << vs->vs_clshift) - 1)), - size, &upl, NULL, &page_list_count, - UPL_NO_SYNC | UPL_CLEAN_IN_PLACE - | UPL_SET_INTERNAL); - if (error == KERN_SUCCESS) { - error = ps_read_file(ps, upl, (vm_offset_t) 0, actual_offset, - size, &residual, 0); - } - -#else - /* NEED TO BE WITH SYNC & NO COMMIT & NO RDAHEAD*/ + /* NEED TO ISSUE WITH SYNC & NO COMMIT */ error = ps_read_file(ps, upl, (vm_offset_t) 0, actual_offset, size, &residual, - (UPL_IOSYNC | UPL_NOCOMMIT | UPL_NORDAHEAD)); -#endif + (UPL_IOSYNC | UPL_NOCOMMIT)); } read_vsmap = *vsmap_ptr; @@ -3535,20 +3481,8 @@ vs_cluster_transfer( /* the vm_map_copy_page_discard call */ *vsmap_ptr = write_vsmap; -#ifndef ubc_sync_working - error = vm_object_upl_request(transfer_object, - (vm_object_offset_t) - (actual_offset & ((vm_page_size << vs->vs_clshift) - 1)), - size, &upl, NULL, &page_list_count, - UPL_NO_SYNC | UPL_CLEAN_IN_PLACE | UPL_SET_INTERNAL); - if(vs_cluster_write(vs, upl, offset, - size, TRUE, 0) != KERN_SUCCESS) { - upl_commit(upl, NULL); - upl_deallocate(upl); -#else if(vs_cluster_write(vs, upl, offset, size, TRUE, UPL_IOSYNC | UPL_NOCOMMIT ) != KERN_SUCCESS) { -#endif error = KERN_FAILURE; if(!(VSM_ISCLR(*vsmap_ptr))) { /* unmap the new backing store object */ diff --git a/osfmk/default_pager/dp_memory_object.c b/osfmk/default_pager/dp_memory_object.c index d9ecaafeb..74c1e12da 100644 --- a/osfmk/default_pager/dp_memory_object.c +++ b/osfmk/default_pager/dp_memory_object.c @@ -116,7 +116,7 @@ vs_async_wait( vs->vs_waiting_async = TRUE; assert_wait(&vs->vs_async_pending, THREAD_UNINT); VS_UNLOCK(vs); - thread_block((void (*)(void))0); + thread_block(THREAD_CONTINUE_NULL); VS_LOCK(vs); } ASSERT(vs->vs_async_pending == 0); @@ -153,7 +153,7 @@ vs_lock( vs->vs_waiting_seqno = TRUE; assert_wait(&vs->vs_seqno, THREAD_UNINT); VS_UNLOCK(vs); - thread_block((void (*)(void))0); + thread_block(THREAD_CONTINUE_NULL); VS_LOCK(vs); } } @@ -196,7 +196,7 @@ vs_wait_for_readers( vs->vs_waiting_read = TRUE; assert_wait(&vs->vs_readers, THREAD_UNINT); VS_UNLOCK(vs); - thread_block((void (*)(void))0); + thread_block(THREAD_CONTINUE_NULL); VS_LOCK(vs); } } @@ -240,7 +240,7 @@ vs_wait_for_writers( vs->vs_waiting_write = TRUE; assert_wait(&vs->vs_writers, THREAD_UNINT); VS_UNLOCK(vs); - thread_block((void (*)(void))0); + thread_block(THREAD_CONTINUE_NULL); VS_LOCK(vs); } vs_async_wait(vs); @@ -261,7 +261,7 @@ vs_wait_for_sync_writers( vs->vs_waiting_write = TRUE; assert_wait(&vs->vs_writers, THREAD_UNINT); VS_UNLOCK(vs); - thread_block((void (*)(void))0); + thread_block(THREAD_CONTINUE_NULL); VS_LOCK(vs); } } @@ -495,7 +495,7 @@ dp_memory_object_deallocate( vs->vs_waiting_seqno = TRUE; assert_wait(&vs->vs_seqno, THREAD_UNINT); VS_UNLOCK(vs); - thread_block((void (*)(void))0); + thread_block(THREAD_CONTINUE_NULL); VS_LOCK(vs); } @@ -549,7 +549,7 @@ dp_memory_object_deallocate( VSL_LOCK(); backing_store_release_trigger_disable -= 1; if(backing_store_release_trigger_disable == 0) { - thread_wakeup((event_t)&vm_page_laundry_count); + thread_wakeup((event_t)&backing_store_release_trigger_disable); } VSL_UNLOCK(); @@ -605,7 +605,7 @@ dp_memory_object_data_request( vs->vs_waiting_write = TRUE; assert_wait(&vs->vs_writers, THREAD_UNINT); VS_UNLOCK(vs); - thread_block((void (*)(void))0); + thread_block(THREAD_CONTINUE_NULL); VS_LOCK(vs); vs_async_wait(vs); } @@ -1158,14 +1158,13 @@ default_pager_object_pages( if (!VS_MAP_TRY_LOCK(entry)) { /* oh well bad luck */ - int wait_result; + int wresult; VS_UNLOCK(entry); - assert_wait_timeout( 1, THREAD_INTERRUPTIBLE); - wait_result = thread_block((void (*)(void)) 0); - if (wait_result != THREAD_TIMED_OUT) - thread_cancel_timer(); + assert_wait_timeout( 1, THREAD_UNINT ); + wresult = thread_block(THREAD_CONTINUE_NULL); + assert(wresult == THREAD_TIMED_OUT); continue; } diff --git a/osfmk/device/device_port.h b/osfmk/device/device_port.h index ba0eda573..1f2bbba59 100644 --- a/osfmk/device/device_port.h +++ b/osfmk/device/device_port.h @@ -64,7 +64,11 @@ */ extern mach_port_t master_device_port; -#define DEVICE_PAGER_CONTIGUOUS 1 -#define DEVICE_PAGER_NOPHYSCACHE 2 +#define DEVICE_PAGER_GUARDED 0x1 +#define DEVICE_PAGER_COHERENT 0x2 +#define DEVICE_PAGER_CACHE_INHIB 0x4 +#define DEVICE_PAGER_WRITE_THROUGH 0x8 +#define DEVICE_PAGER_CONTIGUOUS 0x100 +#define DEVICE_PAGER_NOPHYSCACHE 0x200 #endif /* _DEVICE_DEVICE_PORT_H_ */ diff --git a/osfmk/device/device_types.defs b/osfmk/device/device_types.defs index 9c7dd5183..a42ac7c77 100644 --- a/osfmk/device/device_types.defs +++ b/osfmk/device/device_types.defs @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002,2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -66,9 +66,9 @@ #include #include -type recnum_t = unsigned32; -type dev_mode_t = unsigned32; -type dev_flavor_t = unsigned32; +type recnum_t = uint32_t; +type dev_mode_t = uint32_t; +type dev_flavor_t = uint32_t; type dev_name_t = c_string[*:128]; type dev_status_t = array[*:1024] of int; type io_buf_len_t = integer_t; diff --git a/osfmk/device/iokit_rpc.c b/osfmk/device/iokit_rpc.c index d80e8094a..a61ad9276 100644 --- a/osfmk/device/iokit_rpc.c +++ b/osfmk/device/iokit_rpc.c @@ -57,8 +57,6 @@ #include #include -#include - #include #ifdef __ppc__ @@ -82,7 +80,7 @@ extern ipc_port_t iokit_port_for_object( io_object_t obj, ipc_kobject_type_t type ); extern kern_return_t iokit_client_died( io_object_t obj, - ipc_port_t port, ipc_kobject_type_t type ); + ipc_port_t port, ipc_kobject_type_t type, mach_port_mscount_t mscount ); extern kern_return_t iokit_client_memory_for_type( @@ -172,6 +170,18 @@ iokit_lookup_connect_ref_current_task(io_object_t connectRef) return iokit_lookup_connect_ref(connectRef, current_space()); } +EXTERN void +iokit_retain_port( ipc_port_t port ) +{ + ipc_port_reference( port ); +} + +EXTERN void +iokit_release_port( ipc_port_t port ) +{ + ipc_port_release( port ); +} + /* * Get the port for a device. * Consumes a device reference; produces a naked send right. @@ -181,17 +191,21 @@ iokit_make_object_port( io_object_t obj ) { register ipc_port_t port; + register ipc_port_t sendPort; if( obj == NULL) return IP_NULL; port = iokit_port_for_object( obj, IKOT_IOKIT_OBJECT ); - if( port) - port = ipc_port_make_send( port); + if( port) { + sendPort = ipc_port_make_send( port); + iokit_release_port( port ); + } else + sendPort = IP_NULL; iokit_remove_reference( obj ); - return( port); + return( sendPort); } MIGEXTERN ipc_port_t @@ -199,17 +213,21 @@ iokit_make_connect_port( io_object_t obj ) { register ipc_port_t port; + register ipc_port_t sendPort; if( obj == NULL) return IP_NULL; port = iokit_port_for_object( obj, IKOT_IOKIT_CONNECT ); - if( port) - port = ipc_port_make_send( port); + if( port) { + sendPort = ipc_port_make_send( port); + iokit_release_port( port ); + } else + sendPort = IP_NULL; iokit_remove_reference( obj ); - return( port); + return( sendPort); } @@ -264,24 +282,30 @@ iokit_destroy_object_port( ipc_port_t port ) EXTERN mach_port_name_t iokit_make_send_right( task_t task, io_object_t obj, ipc_kobject_type_t type ) { - kern_return_t kr; ipc_port_t port; + ipc_port_t sendPort; mach_port_name_t name; if( obj == NULL) return MACH_PORT_NULL; port = iokit_port_for_object( obj, type ); - if( port) - port = ipc_port_make_send( port); - if( port == IP_NULL) - return MACH_PORT_NULL; - - kr = ipc_object_copyout( task->itk_space, (ipc_object_t) port, + if( port) { + sendPort = ipc_port_make_send( port); + iokit_release_port( port ); + } else + sendPort = IP_NULL; + + if (IP_VALID( sendPort )) { + kern_return_t kr; + kr = ipc_object_copyout( task->itk_space, (ipc_object_t) sendPort, MACH_MSG_TYPE_PORT_SEND, TRUE, &name); - - if( kr != KERN_SUCCESS) - name = MACH_PORT_NULL; + if ( kr != KERN_SUCCESS) + name = MACH_PORT_NULL; + } else if ( sendPort == IP_NULL) + name = MACH_PORT_NULL; + else if ( sendPort == IP_DEAD) + name = MACH_PORT_DEAD; iokit_remove_reference( obj ); @@ -300,6 +324,7 @@ iokit_no_senders( mach_no_senders_notification_t * notification ) ipc_port_t port; io_object_t obj = NULL; ipc_kobject_type_t type; + ipc_port_t notify; port = (ipc_port_t) notification->not_header.msgh_remote_port; @@ -318,7 +343,17 @@ iokit_no_senders( mach_no_senders_notification_t * notification ) ip_unlock(port); if( obj ) { - (void) iokit_client_died( obj, port, type ); + + mach_port_mscount_t mscount = notification->not_count; + + if( KERN_SUCCESS != iokit_client_died( obj, port, type, &mscount )) + { + /* Re-request no-senders notifications on the port. */ + notify = ipc_port_make_sonce( port); + ip_lock( port); + ipc_port_nsrequest( port, mscount + 1, notify, ¬ify); + assert( notify == IP_NULL); + } iokit_remove_reference( obj ); } } @@ -344,6 +379,21 @@ iokit_notify( mach_msg_header_t * msg ) } } +#ifndef i386 +unsigned int IOTranslateCacheBits(struct phys_entry *pp) +{ + unsigned int flags; + unsigned int memattr; + + /* need to create a pmap function to generalize */ + memattr = ((pp->pte1 & 0x00000078) >> 3); + + /* NOTE: DEVICE_PAGER_FLAGS are made to line up */ + flags = memattr & VM_WIMG_MASK; + return flags; +} +#endif + kern_return_t IOMapPages(vm_map_t map, vm_offset_t va, vm_offset_t pa, vm_size_t length, unsigned int options) { @@ -388,7 +438,7 @@ kern_return_t IOMapPages(vm_map_t map, vm_offset_t va, vm_offset_t pa, #else // enter each page's physical address in the target map for (off = 0; off < length; off += page_size) { /* Loop for the whole length */ - pmap_enter(pmap, va + off, pa + off, prot, TRUE); /* Map it in */ + pmap_enter(pmap, va + off, pa + off, prot, VM_WIMG_USE_DEFAULT, TRUE); /* Map it in */ } #endif @@ -398,17 +448,10 @@ kern_return_t IOMapPages(vm_map_t map, vm_offset_t va, vm_offset_t pa, kern_return_t IOUnmapPages(vm_map_t map, vm_offset_t va, vm_size_t length) { pmap_t pmap = map->pmap; - vm_size_t off; - boolean_t b; -#if __ppc__ - b = mapping_remove(pmap, va); -#else - pmap_remove(pmap, va, va + length); - b = TRUE; -#endif + pmap_remove(pmap, trunc_page(va), round_page(va + length)); - return( b ? KERN_SUCCESS : KERN_INVALID_ADDRESS ); + return( KERN_SUCCESS ); } void IOGetTime( mach_timespec_t * clock_time); diff --git a/osfmk/i386/AT386/bbclock.c b/osfmk/i386/AT386/bbclock.c index 9bad06a13..ffcad7a77 100644 --- a/osfmk/i386/AT386/bbclock.c +++ b/osfmk/i386/AT386/bbclock.c @@ -130,7 +130,7 @@ bbc_gettime( mp_disable_preemption(); if (current_processor() != master_processor) { mp_enable_preemption(); - thread_block((void (*)) 0); + thread_block(THREAD_CONTINUE_NULL); } else { mp_enable_preemption(); } @@ -185,7 +185,7 @@ bbc_settime( mp_disable_preemption(); if (current_processor() != master_processor) { mp_enable_preemption(); - thread_block((void (*)) 0); + thread_block(THREAD_CONTINUE_NULL); } else { mp_enable_preemption(); } diff --git a/osfmk/i386/AT386/himem.c b/osfmk/i386/AT386/himem.c index 1c13d7695..f9abdb912 100644 --- a/osfmk/i386/AT386/himem.c +++ b/osfmk/i386/AT386/himem.c @@ -237,8 +237,9 @@ himem_convert( while (!(h = hil_head)) { printf("WARNING: out of HIMEM pages\n"); thread_sleep_simple_lock((event_t)&hil_head, - simple_lock_addr(hil_lock), FALSE); - simple_lock (&hil_lock); + simple_lock_addr(hil_lock), + THREAD_UNINT); + /* hil_lock relocked */ } hil_head = hil_head->next; simple_unlock(&hil_lock); diff --git a/osfmk/i386/AT386/model_dep.c b/osfmk/i386/AT386/model_dep.c index ebd42a223..c3cb5bc94 100644 --- a/osfmk/i386/AT386/model_dep.c +++ b/osfmk/i386/AT386/model_dep.c @@ -113,6 +113,8 @@ #include #endif /* MP_V1_1 */ +#include + vm_size_t mem_size = 0; vm_offset_t first_addr = 0; /* set by start.s - keep out of bss */ vm_offset_t first_avail = 0;/* first after page tables */ @@ -138,9 +140,6 @@ extern char edata, end; extern char version[]; -int rebootflag = 0; /* exported to kdintr */ - - void parse_arguments(void); const char *getenv(const char *); @@ -208,8 +207,6 @@ machine_startup(void) { #ifdef __MACHO__ - - /* Now copy over various bits.. */ cnvmem = kernBootStruct->convmem; extmem = kernBootStruct->extmem; @@ -234,14 +231,6 @@ machine_startup(void) edata = (vm_offset_t) sectDATAB + sectSizeDATA; #endif - /* - * Parse startup arguments - */ - parse_arguments(); - - disableDebugOuput = FALSE; - debug_mode = TRUE; - printf_init(); /* Init this in case we need debugger */ panic_init(); /* Init this in case we need debugger */ @@ -249,6 +238,18 @@ machine_startup(void) PE_init_kprintf(FALSE); PE_init_printf(FALSE); + /* + * Parse startup arguments + */ + parse_arguments(); + + /* + * Set up initial thread so current_thread() works early on + */ + pageout_thread.top_act = &pageout_act; + pageout_act.thread = &pageout_thread; + thread_machine_set_current(&pageout_thread); + /* * Do basic VM initialization */ @@ -259,7 +260,6 @@ machine_startup(void) PE_init_printf(TRUE); #if MACH_KDB - /* * Initialize the kernel debugger. */ @@ -269,9 +269,6 @@ machine_startup(void) * Cause a breakpoint trap to the debugger before proceeding * any further if the proper option bit was specified in * the boot flags. - * - * XXX use -a switch to invoke kdb, since there's no - * boot-program switch to turn on RB_HALT! */ if (halt_in_debugger) { @@ -279,6 +276,7 @@ machine_startup(void) Debugger("inline call"); } #endif /* MACH_KDB */ + TR_INIT(); printf(version); @@ -314,34 +312,18 @@ vm_size_t env_size = 0; /* size of environment */ void parse_arguments(void) { - char *p = (char *) kern_args_start; - char *endp = (char *) kern_args_start + kern_args_size - 1; - char ch; - - if (kern_args_start == 0) - return; - - /* - * handle switches in exact format of -h or -m64 - */ - while ( (p < endp) && (*p != '\0')) { - if (*p++ != '-') - continue; - switch (*p++) { - case 'h': - halt_in_debugger = 1; - break; - case 'm': - mem_size = atoi_term(p,&p)*1024*1024; - break; - case 'k': - mem_size = atoi_term(p,&p)*1024; - break; - default: - break; - } - } - + unsigned int boot_arg; + + if (PE_parse_boot_arg("maxmem", &boot_arg)) + { + mem_size = boot_arg * (1024 * 1024); + } + + if (PE_parse_boot_arg("debug", &boot_arg)) + { + if (boot_arg & DB_HALT) halt_in_debugger = 1; + if (boot_arg & DB_PRT) disableDebugOuput = FALSE; + } } const char * @@ -423,25 +405,25 @@ int reset_mem_on_reboot = 1; * Halt the system or reboot. */ void -halt_all_cpus( - boolean_t reboot) +halt_all_cpus(boolean_t reboot) { - if (reboot) { - /* - * Tell the BIOS not to clear and test memory. - */ - if (! reset_mem_on_reboot) - *(unsigned short *)phystokv(0x472) = 0x1234; - - kdreboot(); - } - else { - rebootflag = 1; - printf("In tight loop: hit ctl-alt-del to reboot\n"); - (void) spllo(); - } - for (;;) - continue; + if (reboot) + { + /* + * Tell the BIOS not to clear and test memory. + */ + if (!reset_mem_on_reboot) + *(unsigned short *)phystokv(0x472) = 0x1234; + + printf("MACH Reboot\n"); + PEHaltRestart( kPERestartCPU ); + } + else + { + printf("CPU halted\n"); + PEHaltRestart( kPEHaltCPU ); + } + while(1); } /* @@ -499,8 +481,9 @@ i386_init(void) #endif #endif - /* BIOS leaves data in low memory */ + /* BIOS leaves data in low memory */ last_addr = 1024*1024 + extmem*1024; + /* extended memory starts at 1MB */ bios_hole_size = 1024*1024 - trunc_page((vm_offset_t)(1024 * cnvmem)); diff --git a/osfmk/i386/AT386/mp/mp.h b/osfmk/i386/AT386/mp/mp.h index e63593cf1..84339bfcf 100644 --- a/osfmk/i386/AT386/mp/mp.h +++ b/osfmk/i386/AT386/mp/mp.h @@ -67,8 +67,8 @@ #define CPU_NUMBER(r) \ movl EXT(lapic_id), r ; \ movl 0(r),r ; \ - shrl $LAPIC_ID_SHIFT, r; \ - andl $LAPIC_ID_MASK, r + shrl $ LAPIC_ID_SHIFT, r; \ + andl $ LAPIC_ID_MASK, r #define MP_IPL SPL6 /* software interrupt level */ @@ -125,11 +125,11 @@ extern int kdb_active[]; #if MACH_RT #define _DISABLE_PREEMPTION(r) \ - movl $CPD_PREEMPTION_LEVEL,r ; \ + movl $ CPD_PREEMPTION_LEVEL,r ; \ incl %gs:(r) #define _ENABLE_PREEMPTION(r) \ - movl $CPD_PREEMPTION_LEVEL,r ; \ + movl $ CPD_PREEMPTION_LEVEL,r ; \ decl %gs:(r) ; \ jne 9f ; \ pushl %eax ; \ @@ -142,7 +142,7 @@ extern int kdb_active[]; 9: #define _ENABLE_PREEMPTION_NO_CHECK(r) \ - movl $CPD_PREEMPTION_LEVEL,r ; \ + movl $ CPD_PREEMPTION_LEVEL,r ; \ decl %gs:(r) #if MACH_ASSERT diff --git a/osfmk/i386/AT386/mp/mp_v1_1.c b/osfmk/i386/AT386/mp/mp_v1_1.c index 51d1da78b..0f58f2d51 100644 --- a/osfmk/i386/AT386/mp/mp_v1_1.c +++ b/osfmk/i386/AT386/mp/mp_v1_1.c @@ -99,7 +99,7 @@ void validate_cpus(int ncpus) { int i; - for(i=0;i> 3); + index = *dataPtr++; + index *= 3; + + if( alphaPtr && backPtr && (alpha = *alphaPtr++)) { + + data = 0; + if( vc_clut[index + 0] > alpha) + data |= (((vc_clut[index + 0] - alpha) & 0xf8) << 7); + if( vc_clut[index + 1] > alpha) + data |= (((vc_clut[index + 1] - alpha) & 0xf8) << 2); + if( vc_clut[index + 2] > alpha) + data |= (((vc_clut[index + 2] - alpha) & 0xf8) >> 3); + + if( save) { + back = *(dst + col); + alpha >>= 3; + back = (((((back & 0x7c1f) * alpha) + 0x7c1f) >> 5) & 0x7c1f) + | (((((back & 0x03e0) * alpha) + 0x03e0) >> 5) & 0x03e0); + *backPtr++ = back; + } else + back = *backPtr++; + + data += back; + + } else + data = ( (0xf8 & (vc_clut[index + 0])) << 7) + | ( (0xf8 & (vc_clut[index + 1])) << 2) + | ( (0xf8 & (vc_clut[index + 2])) >> 3); + + *(dst + col) = data; } dst = (volatile unsigned short *) (((int)dst) + vinfo.v_rowbytes); } @@ -1682,11 +1682,12 @@ void vc_blit_rect_16( int x, int y, void vc_blit_rect_32( unsigned int x, unsigned int y, unsigned int width, unsigned int height, - int transparent, unsigned char * dataPtr ) + const unsigned char * dataPtr, const unsigned char * alphaPtr, + unsigned int * backPtr, boolean_t save ) { volatile unsigned int * dst; int line, col; - unsigned int data; + unsigned int data, index, alpha, back; dst = (volatile unsigned int *) (vinfo.v_baseaddr + (y * vinfo.v_rowbytes) + @@ -1694,32 +1695,57 @@ void vc_blit_rect_32( unsigned int x, unsigned int y, for( line = 0; line < height; line++) { for( col = 0; col < width; col++) { - data = *dataPtr++; - if( data == transparent) - continue; - - data *= 3; - *(dst + col) = (vc_clut[data + 0] << 16) - | (vc_clut[data + 1] << 8) - | (vc_clut[data + 2]); + index = *dataPtr++; + index *= 3; + if( alphaPtr && backPtr && (alpha = *alphaPtr++)) { + + data = 0; + if( vc_clut[index + 0] > alpha) + data |= ((vc_clut[index + 0] - alpha) << 16); + if( vc_clut[index + 1] > alpha) + data |= ((vc_clut[index + 1] - alpha) << 8); + if( vc_clut[index + 2] > alpha) + data |= ((vc_clut[index + 2] - alpha)); + + if( save) { + back = *(dst + col); + back = (((((back & 0x00ff00ff) * alpha) + 0x00ff00ff) >> 8) & 0x00ff00ff) + | (((((back & 0x0000ff00) * alpha) + 0x0000ff00) >> 8) & 0x0000ff00); + *backPtr++ = back; + } else + back = *backPtr++; + + data += back; + + } else + data = (vc_clut[index + 0] << 16) + | (vc_clut[index + 1] << 8) + | (vc_clut[index + 2]); + + *(dst + col) = data; } dst = (volatile unsigned int *) (((int)dst) + vinfo.v_rowbytes); } } -void vc_blit_rect( int x, int y, - int width, int height, - int transparent, unsigned char * dataPtr ) +void vc_blit_rect( unsigned int x, unsigned int y, + unsigned int width, unsigned int height, + const unsigned char * dataPtr, const unsigned char * alphaPtr, + vm_address_t backBuffer, boolean_t save ) { + if(!vinfo.v_baseaddr) + return; + switch( vinfo.v_depth) { case 8: - vc_blit_rect_8c( x, y, width, height, transparent, dataPtr); + if( vc_clut8 == vc_clut) + vc_blit_rect_8c( x, y, width, height, dataPtr, alphaPtr, (unsigned char *) backBuffer, save ); break; case 16: - vc_blit_rect_16( x, y, width, height, transparent, dataPtr); + vc_blit_rect_16( x, y, width, height, dataPtr, alphaPtr, (unsigned short *) backBuffer, save ); break; case 32: - vc_blit_rect_32( x, y, width, height, transparent, dataPtr); + vc_blit_rect_32( x, y, width, height, dataPtr, alphaPtr, (unsigned int *) backBuffer, save ); break; } } @@ -1729,12 +1755,13 @@ void vc_progress_task( void * arg ) spl_t s; int count = (int) arg; int x, y, width, height; - unsigned char * data; + const unsigned char * data; s = splhigh(); simple_lock(&vc_forward_lock); if( vc_progress_enable) { + count++; if( count >= vc_progress->count) count = 0; @@ -1746,11 +1773,12 @@ void vc_progress_task( void * arg ) data = vc_progress_data; data += count * width * height; if( 1 & vc_progress->flags) { - x += (vinfo.v_width / 2); - x += (vinfo.v_height / 2); + x += ((vinfo.v_width - width) / 2); + y += ((vinfo.v_height - height) / 2); } vc_blit_rect( x, y, width, height, - vc_progress->transparent,data ); + data, vc_progress_alpha, vc_saveunder, vc_needsave ); + vc_needsave = FALSE; timeout( vc_progress_task, (void *) count, vc_progress_tick ); @@ -1760,7 +1788,7 @@ void vc_progress_task( void * arg ) } void vc_display_icon( vc_progress_element * desc, - unsigned char * data ) + const unsigned char * data ) { int x, y, width, height; @@ -1771,51 +1799,80 @@ void vc_display_icon( vc_progress_element * desc, x = desc->dx; y = desc->dy; if( 1 & desc->flags) { - x += (vinfo.v_width / 2); - y += (vinfo.v_height / 2); + x += ((vinfo.v_width - width) / 2); + y += ((vinfo.v_height - height) / 2); } - vc_blit_rect( x, y, width, height, desc->transparent, data ); + vc_blit_rect( x, y, width, height, data, NULL, (vm_address_t) NULL, FALSE ); } } boolean_t -vc_progress_set( boolean_t enable ) +vc_progress_set( boolean_t enable, unsigned int initial_tick ) { spl_t s; + vm_address_t saveBuf = 0; + vm_size_t saveLen = 0; if( !vc_progress) return( FALSE ); + if( enable) { + saveLen = vc_progress->width * vc_progress->height * vinfo.v_depth / 8; + saveBuf = kalloc( saveLen ); + } + s = splhigh(); simple_lock(&vc_forward_lock); if( vc_progress_enable != enable) { vc_progress_enable = enable; - if( enable) + if( enable) { + vc_needsave = TRUE; + vc_saveunder = saveBuf; + vc_saveunder_len = saveLen; + saveBuf = 0; + saveLen = 0; timeout(vc_progress_task, (void *) 0, - vc_progress_tick ); - else + initial_tick ); + } + else { + if( vc_saveunder) { + saveBuf = vc_saveunder; + saveLen = vc_saveunder_len; + vc_saveunder = 0; + vc_saveunder_len = 0; + } untimeout( vc_progress_task, (void *) 0 ); + } } simple_unlock(&vc_forward_lock); splx(s); + if( saveBuf) + kfree( saveBuf, saveLen ); + return( TRUE ); } boolean_t vc_progress_initialize( vc_progress_element * desc, - unsigned char * data, - unsigned char * clut ) + const unsigned char * data, + const unsigned char * clut ) { if( (!clut) || (!desc) || (!data)) return( FALSE ); vc_clut = clut; + vc_clut8 = clut; vc_progress = desc; vc_progress_data = data; + if( 2 & vc_progress->flags) + vc_progress_alpha = vc_progress_data + + vc_progress->count * vc_progress->width * vc_progress->height; + else + vc_progress_alpha = NULL; vc_progress_tick = vc_progress->time * hz / 1000; return( TRUE ); @@ -1894,7 +1951,7 @@ initialize_screen(Boot_Video * boot_vinfo, int op) break; case kPETextScreen: - vc_progress_set( FALSE ); + vc_progress_set( FALSE, 0 ); disableConsoleOutput = FALSE; if( vc_need_clear) { vc_need_clear = FALSE; @@ -1905,20 +1962,20 @@ initialize_screen(Boot_Video * boot_vinfo, int op) case kPEEnableScreen: if ( vc_acquired) { if( vc_graphics_mode) - vc_progress_set( TRUE ); + vc_progress_set( TRUE, vc_progress_tick ); else vc_clear_screen(); } break; case kPEDisableScreen: - vc_progress_set( FALSE ); + vc_progress_set( FALSE, 0 ); break; case kPEAcquireScreen: vc_need_clear = (FALSE == vc_acquired); vc_acquired = TRUE; - vc_progress_set( vc_graphics_mode ); + vc_progress_set( vc_graphics_mode, vc_need_clear ? 2 * hz : 0 ); disableConsoleOutput = vc_graphics_mode; if( vc_need_clear && !vc_graphics_mode) { vc_need_clear = FALSE; @@ -1928,7 +1985,8 @@ initialize_screen(Boot_Video * boot_vinfo, int op) case kPEReleaseScreen: vc_acquired = FALSE; - vc_progress_set( FALSE ); + vc_progress_set( FALSE, 0 ); + vc_clut8 = NULL; disableConsoleOutput = TRUE; break; } diff --git a/osfmk/i386/bsd_i386.c b/osfmk/i386/bsd_i386.c index d7caa5a15..0a96e3cb8 100644 --- a/osfmk/i386/bsd_i386.c +++ b/osfmk/i386/bsd_i386.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -54,7 +53,9 @@ #include #include -#define USRSTACK 0xc0000000 +#include +#include +struct proc; kern_return_t thread_userstack( @@ -111,22 +112,18 @@ thread_userstack( i386_thread_state_t *state25; vm_offset_t uesp; - /* - * Set a default. - */ - if (*user_stack == 0) - *user_stack = USRSTACK; - if (customstack) *customstack = 0; + switch (flavor) { case i386_THREAD_STATE: /* FIXME */ state25 = (i386_thread_state_t *) tstate; - *user_stack = state25->esp ? state25->esp : USRSTACK; - if (customstack && state25->esp) - *customstack = 1; - else - *customstack = 0; + if (state25->esp) + *user_stack = state25->esp; + if (customstack && state25->esp) + *customstack = 1; + else + *customstack = 0; break; case i386_NEW_THREAD_STATE: @@ -137,14 +134,13 @@ thread_userstack( uesp = state->uesp; } - /* - * If a valid user stack is specified, use it. - */ - *user_stack = uesp ? uesp : USRSTACK; - if (customstack && uesp) - *customstack = 1; - else - *customstack = 0; + /* If a valid user stack is specified, use it. */ + if (uesp) + *user_stack = uesp; + if (customstack && uesp) + *customstack = 1; + else + *customstack = 0; break; default : return (KERN_INVALID_ARGUMENT); @@ -302,6 +298,7 @@ struct sysent { /* system call table */ unsigned long (*sy_call)(void *, void *, int *); /* implementing function */ }; +#define NO_FUNNEL 0 #define KERNEL_FUNNEL 1 #define NETWORK_FUNNEL 2 @@ -310,26 +307,39 @@ extern funnel_t * network_flock; extern struct sysent sysent[]; - int set_bsduthreadargs (thread_act_t, struct i386_saved_state *, void *); void * get_bsduthreadarg(thread_act_t); void unix_syscall(struct i386_saved_state *); -/* USED ONLY FROM VFORK/EXIT */ void unix_syscall_return(int error) { thread_act_t thread; volatile int *rval; struct i386_saved_state *regs; + struct proc *p; + struct proc *current_proc(); + unsigned short code; + vm_offset_t params; + struct sysent *callp; + extern int nsysent; thread = current_act(); rval = (int *)get_bsduthreadrval(thread); + p = current_proc(); regs = USER_REGS(thread); + /* reconstruct code for tracing before blasting eax */ + code = regs->eax; + params = (vm_offset_t) ((caddr_t)regs->uesp + sizeof (int)); + callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; + if (callp == sysent) { + code = fuword(params); + } + if (error == ERESTART) { regs->eip -= 7; } @@ -344,7 +354,15 @@ unix_syscall_return(int error) } } - (void) thread_funnel_set(current_thread()->funnel_lock, FALSE); + ktrsysret(p, code, error, rval[0], callp->sy_funnel); + + KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END, + error, rval[0], rval[1], 0, 0); + + if (callp->sy_funnel != NO_FUNNEL) { + assert(thread_funnel_get() == THR_FUNNEL_NULL); + (void) thread_funnel_set(current_thread()->funnel_lock, FALSE); + } thread_exception_return(); /* NOTREACHED */ @@ -355,14 +373,16 @@ void unix_syscall(struct i386_saved_state *regs) { thread_act_t thread; - void *p, *vt; + void *vt; unsigned short code; struct sysent *callp; int nargs, error; volatile int *rval; - int funnel_type; + int funnel_type; vm_offset_t params; extern int nsysent; + struct proc *p; + struct proc *current_proc(); thread = current_act(); p = current_proc(); @@ -391,17 +411,24 @@ unix_syscall(struct i386_saved_state *regs) rval[0] = 0; rval[1] = regs->edx; - if(callp->sy_funnel == NETWORK_FUNNEL) { - (void) thread_funnel_set(network_flock, TRUE); - } - else { - (void) thread_funnel_set(kernel_flock, TRUE); - } + funnel_type = callp->sy_funnel; + if(funnel_type == KERNEL_FUNNEL) + (void) thread_funnel_set(kernel_flock, TRUE); + else if (funnel_type == NETWORK_FUNNEL) + (void) thread_funnel_set(network_flock, TRUE); + set_bsduthreadargs(thread, regs, NULL); if (callp->sy_narg > 8) panic("unix_syscall max arg count exceeded (%d)", callp->sy_narg); + ktrsyscall(p, code, callp->sy_narg, vt, funnel_type); + + { + int *ip = (int *)vt; + KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START, + *ip, *(ip+1), *(ip+2), *(ip+3), 0); + } error = (*(callp->sy_call))(p, (void *) vt, rval); @@ -423,7 +450,13 @@ unix_syscall(struct i386_saved_state *regs) } } - (void) thread_funnel_set(current_thread()->funnel_lock, FALSE); + ktrsysret(p, code, error, rval[0], funnel_type); + + KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END, + error, rval[0], rval[1], 0, 0); + + if(funnel_type != NO_FUNNEL) + (void) thread_funnel_set(current_thread()->funnel_lock, FALSE); thread_exception_return(); /* NOTREACHED */ @@ -436,6 +469,8 @@ machdep_syscall( struct i386_saved_state *regs) int trapno, nargs; machdep_call_t *entry; thread_t thread; + struct proc *p; + struct proc *current_proc(); trapno = regs->eax; if (trapno < 0 || trapno >= machdep_call_count) { @@ -481,7 +516,8 @@ machdep_syscall( struct i386_saved_state *regs) else regs->eax = (unsigned int)(*entry->routine)(); - (void) thread_funnel_set(current_thread()->funnel_lock, FALSE); + if (current_thread()->funnel_lock) + (void) thread_funnel_set(current_thread()->funnel_lock, FALSE); thread_exception_return(); /* NOTREACHED */ @@ -513,7 +549,7 @@ mach25_syscall(struct i386_saved_state *regs) #endif /* MACH_BSD */ #undef current_thread -thread_act_t +thread_t current_thread(void) { return(current_thread_fast()); diff --git a/osfmk/i386/cpu.c b/osfmk/i386/cpu.c index 5d6d05cae..d23ae9e91 100644 --- a/osfmk/i386/cpu.c +++ b/osfmk/i386/cpu.c @@ -27,9 +27,12 @@ #include #include +#include #include #include +cpu_data_t cpu_data[NCPUS]; + /*ARGSUSED*/ kern_return_t cpu_control( diff --git a/osfmk/i386/cpu_data.h b/osfmk/i386/cpu_data.h index 97fb613de..a62fc6170 100644 --- a/osfmk/i386/cpu_data.h +++ b/osfmk/i386/cpu_data.h @@ -41,6 +41,10 @@ #endif #endif +extern cpu_data_t cpu_data[NCPUS]; + +#define get_cpu_data() &cpu_data[cpu_number()] + /* * Everyone within the osfmk part of the kernel can use the fast * inline versions of these routines. Everyone outside, must call diff --git a/osfmk/i386/cpu_number.h b/osfmk/i386/cpu_number.h index 7c15b8526..255bb119a 100644 --- a/osfmk/i386/cpu_number.h +++ b/osfmk/i386/cpu_number.h @@ -58,6 +58,9 @@ #ifndef _I386_CPU_NUMBER_H_ #define _I386_CPU_NUMBER_H_ +#include + +#ifdef __APPLE_API_UNSTABLE extern int cpu_number(void); #ifdef MACH_KERNEL_PRIVATE @@ -118,4 +121,6 @@ extern __inline__ int cpu_number(void) #endif /* MACH_KERNEL_PRIVATE */ +#endif /* __APPLE_API_UNSTABLE */ + #endif /* _I386_CPU_NUMBER_H_ */ diff --git a/osfmk/i386/cswitch.s b/osfmk/i386/cswitch.s index 00f69024d..dd8254390 100644 --- a/osfmk/i386/cswitch.s +++ b/osfmk/i386/cswitch.s @@ -119,7 +119,7 @@ Entry(Switch_context) movl %ecx,TH_KERNEL_STACK(%eax) /* save kernel stack */ movl 8(%esp),%esi /* get new thread */ - movl $CPD_ACTIVE_THREAD,%ecx + movl $ CPD_ACTIVE_THREAD,%ecx movl %esi,%gs:(%ecx) /* new thread is active */ movl TH_KERNEL_STACK(%esi),%ecx /* get its kernel stack */ lea KERNEL_STACK_SIZE-IKS_SIZE-IEL_SIZE(%ecx),%ebx diff --git a/osfmk/i386/genassym.c b/osfmk/i386/genassym.c index 0acd35ea8..302dbe497 100644 --- a/osfmk/i386/genassym.c +++ b/osfmk/i386/genassym.c @@ -62,7 +62,6 @@ #include #include #include -#include #include #include #include @@ -74,7 +73,6 @@ #include #include #include -#include #include #if NCPUS > 1 #include @@ -151,12 +149,6 @@ main( DECLARE("MAP_PMAP", offsetof(vm_map_t, pmap)); - /* XXX Until rpc buffers move from kernel stack to activation */ - DECLARE("RPC_CLIENT_BUF_SIZE", - 2 * RPC_KBUF_SIZE * sizeof(int) + - RPC_DESC_COUNT * sizeof(rpc_copy_state_data_t) + - 40 * sizeof(int)); - DECLARE("HOST_NAME", offsetof(host_t, host_self)); DECLARE("DISP_MIN", offsetof(eml_dispatch_t, disp_min)); diff --git a/osfmk/i386/i386_lock.s b/osfmk/i386/i386_lock.s index 6e58d507e..5e6acea43 100644 --- a/osfmk/i386/i386_lock.s +++ b/osfmk/i386/i386_lock.s @@ -34,9 +34,9 @@ #include #include #include -#include #include +#include "assym.s" /* * When performance isn't the only concern, it's @@ -67,13 +67,14 @@ #endif /* BUILD_STACK_FRAMES */ -#define M_ILK (%edx) -#define M_LOCKED 1(%edx) -#define M_WAITERS 2(%edx) +#define M_ILK (%edx) +#define M_LOCKED 1(%edx) +#define M_WAITERS 2(%edx) +#define M_PROMOTED_PRI 4(%edx) #if MACH_LDEBUG -#define M_TYPE 4(%edx) -#define M_PC 8(%edx) -#define M_THREAD 12(%edx) +#define M_TYPE 6(%edx) +#define M_PC 10(%edx) +#define M_THREAD 14(%edx) #endif /* MACH_LDEBUG */ #include @@ -100,7 +101,7 @@ * type simplelock and vice versa. */ #define CHECK_MUTEX_TYPE() \ - cmpl $MUTEX_TAG, M_TYPE ; \ + cmpl $ MUTEX_TAG,M_TYPE ; \ je 1f ; \ pushl $2f ; \ call EXT(panic) ; \ @@ -111,7 +112,7 @@ 1: #define CHECK_SIMPLE_LOCK_TYPE() \ - cmpl $SIMPLE_LOCK_TAG,S_TYPE ; \ + cmpl $ SIMPLE_LOCK_TAG,S_TYPE ; \ je 1f ; \ pushl $2f ; \ call EXT(panic) ; \ @@ -129,7 +130,7 @@ */ #if 0 /*MACH_RT - 11/12/99 - lion@apple.com disable check for now*/ #define CHECK_PREEMPTION_LEVEL() \ - movl $CPD_PREEMPTION_LEVEL,%eax ; \ + movl $ CPD_PREEMPTION_LEVEL,%eax ; \ cmpl $0,%gs:(%eax) ; \ je 1f ; \ pushl $2f ; \ @@ -144,7 +145,7 @@ #endif /* MACH_RT */ #define CHECK_NO_SIMPLELOCKS() \ - movl $CPD_SIMPLE_LOCK_COUNT,%eax ; \ + movl $ CPD_SIMPLE_LOCK_COUNT,%eax ; \ cmpl $0,%gs:(%eax) ; \ je 1f ; \ pushl $2f ; \ @@ -159,7 +160,7 @@ * Verifies return to the correct thread in "unlock" situations. */ #define CHECK_THREAD(thd) \ - movl $CPD_ACTIVE_THREAD,%eax ; \ + movl $ CPD_ACTIVE_THREAD,%eax ; \ movl %gs:(%eax),%ecx ; \ testl %ecx,%ecx ; \ je 1f ; \ @@ -174,7 +175,7 @@ 1: #define CHECK_MYLOCK(thd) \ - movl $CPD_ACTIVE_THREAD,%eax ; \ + movl $ CPD_ACTIVE_THREAD,%eax ; \ movl %gs:(%eax),%ecx ; \ testl %ecx,%ecx ; \ je 1f ; \ @@ -225,11 +226,13 @@ ENTRY(hw_lock_init) /* * void hw_lock_lock(hw_lock_t) + * unsigned int hw_lock_to(hw_lock_t, unsigned int) * * Acquire lock, spinning until it becomes available. + * XXX: For now, we don't actually implement the timeout. * MACH_RT: also return with preemption disabled. */ -ENTRY(hw_lock_lock) +ENTRY2(hw_lock_lock,hw_lock_to) FRAME movl L_ARG0,%edx /* fetch lock pointer */ @@ -238,7 +241,7 @@ ENTRY(hw_lock_lock) xchgb 0(%edx),%cl /* try to acquire the HW lock */ testb %cl,%cl /* success? */ jne 3f - + movl $1,%eax /* In case this was a timeout call */ EMARF /* if yes, then nothing left to do */ ret @@ -346,7 +349,7 @@ sl_get_hw: #if MACH_LDEBUG movl L_PC,%ecx movl %ecx,S_PC - movl $CPD_ACTIVE_THREAD,%eax + movl $ CPD_ACTIVE_THREAD,%eax movl %gs:(%eax),%ecx movl %ecx,S_THREAD incl CX(EXT(simple_lock_count),%eax) @@ -382,7 +385,7 @@ ENTRY(_simple_lock_try) #if MACH_LDEBUG movl L_PC,%ecx movl %ecx,S_PC - movl $CPD_ACTIVE_THREAD,%eax + movl $ CPD_ACTIVE_THREAD,%eax movl %gs:(%eax),%ecx movl %ecx,S_THREAD incl CX(EXT(simple_lock_count),%eax) @@ -457,9 +460,10 @@ ENTRY(mutex_init) movb %al,M_ILK /* clear interlock */ movb %al,M_LOCKED /* clear locked flag */ movw %ax,M_WAITERS /* init waiter count */ + movw %ax,M_PROMOTED_PRI #if MACH_LDEBUG - movl $MUTEX_TAG,M_TYPE /* set lock type */ + movl $ MUTEX_TAG,M_TYPE /* set lock type */ movl %eax,M_PC /* init caller pc */ movl %eax,M_THREAD /* and owning thread */ #endif @@ -499,21 +503,20 @@ ml_get_hw: testb %cl,%cl /* did we succeed? */ jne ml_get_hw /* no, try again */ -/* -/ Beware of a race between this code path and the inline ASM fast-path locking -/ sequence which attempts to lock a mutex by directly setting the locked flag -/ -*/ - movb $1,%cl xchgb %cl,M_LOCKED /* try to set locked flag */ testb %cl,%cl /* is the mutex locked? */ jne ml_fail /* yes, we lose */ + pushl %edx + call EXT(mutex_lock_acquire) + addl $4,%esp + movl L_ARG0,%edx + #if MACH_LDEBUG movl L_PC,%ecx movl %ecx,M_PC - movl $CPD_ACTIVE_THREAD,%eax + movl $ CPD_ACTIVE_THREAD,%eax movl %gs:(%eax),%ecx movl %ecx,M_THREAD testl %ecx,%ecx @@ -554,9 +557,11 @@ ml_fail: ml_block: CHECK_MYLOCK(M_THREAD) + xorl %eax,%eax + pushl %eax /* no promotion here yet */ pushl %edx /* push mutex address */ call EXT(mutex_lock_wait) /* wait for the lock */ - addl $4,%esp + addl $8,%esp movl L_ARG0,%edx /* refetch lock pointer */ jmp ml_retry /* and try again */ @@ -574,20 +579,67 @@ ENTRY2(mutex_try,_mutex_try) CHECK_MUTEX_TYPE() CHECK_NO_SIMPLELOCKS() - xorl %eax,%eax - movb $1,%al /* locked value for mutex */ - xchgb %al,M_LOCKED /* swap locked values */ - xorb $1,%al /* generate return value */ + DISABLE_PREEMPTION(%eax) + +mt_get_hw: + movb $1,%cl + xchgb %cl,M_ILK + testb %cl,%cl + jne mt_get_hw + + movb $1,%cl + xchgb %cl,M_LOCKED + testb %cl,%cl + jne mt_fail + + pushl %edx + call EXT(mutex_lock_acquire) + addl $4,%esp + movl L_ARG0,%edx + +#if MACH_LDEBUG + movl L_PC,%ecx + movl %ecx,M_PC + movl $ CPD_ACTIVE_THREAD,%ecx + movl %gs:(%ecx),%ecx + movl %ecx,M_THREAD + testl %ecx,%ecx + je 1f + incl TH_MUTEX_COUNT(%ecx) +1: +#endif + + xorb %cl,%cl + xchgb %cl,M_ILK + + ENABLE_PREEMPTION(%eax) + +#if ETAP_LOCK_TRACE + movl L_PC,%eax /* fetch pc */ + pushl SWT_LO /* push wait time (low) */ + pushl SWT_HI /* push wait time (high) */ + pushl %eax /* push pc */ + pushl %edx /* push mutex address */ + call EXT(etap_mutex_hold) /* get start hold timestamp */ + addl $16,%esp /* clean up stack, adjusting for locals */ +#endif /* ETAP_LOCK_TRACE */ + + movl $1,%eax #if MACH_LDEBUG || ETAP_LOCK_TRACE - testl %eax,%eax /* did we succeed? */ - je 2f /* no, skip */ +#if ETAP_LOCK_TRACE + addl $8,%esp /* pop stack claimed on entry */ #endif +#endif + + EMARF + ret +mt_fail: #if MACH_LDEBUG movl L_PC,%ecx movl %ecx,M_PC - movl $CPD_ACTIVE_THREAD,%ecx + movl $ CPD_ACTIVE_THREAD,%ecx movl %gs:(%ecx),%ecx movl %ecx,M_THREAD testl %ecx,%ecx @@ -596,6 +648,11 @@ ENTRY2(mutex_try,_mutex_try) 1: #endif + xorb %cl,%cl + xchgb %cl,M_ILK + + ENABLE_PREEMPTION(%eax) + #if ETAP_LOCK_TRACE movl L_PC,%eax /* fetch pc */ pushl SWT_LO /* push wait time (low) */ @@ -604,11 +661,11 @@ ENTRY2(mutex_try,_mutex_try) pushl %edx /* push mutex address */ call EXT(etap_mutex_hold) /* get start hold timestamp */ addl $16,%esp /* clean up stack, adjusting for locals */ - movl $1,%eax /* put back successful return value */ #endif /* ETAP_LOCK_TRACE */ + xorl %eax,%eax + #if MACH_LDEBUG || ETAP_LOCK_TRACE -2: #if ETAP_LOCK_TRACE addl $8,%esp /* pop stack claimed on entry */ #endif @@ -645,7 +702,7 @@ mu_doit: #if MACH_LDEBUG xorl %eax,%eax movl %eax,M_THREAD /* disown thread */ - movl $CPD_ACTIVE_THREAD,%eax + movl $ CPD_ACTIVE_THREAD,%eax movl %gs:(%eax),%ecx testl %ecx,%ecx je 0f @@ -665,9 +722,11 @@ mu_doit: ret mu_wakeup: + xorl %eax,%eax + pushl %eax /* no promotion here yet */ pushl %edx /* push mutex address */ call EXT(mutex_unlock_wakeup)/* yes, wake a thread */ - addl $4,%esp + addl $8,%esp movl L_ARG0,%edx /* refetch lock pointer */ jmp mu_doit @@ -693,7 +752,7 @@ ENTRY(_disable_preemption) ENTRY(_enable_preemption) #if MACH_RT #if MACH_ASSERT - movl $CPD_PREEMPTION_LEVEL,%eax + movl $ CPD_PREEMPTION_LEVEL,%eax cmpl $0,%gs:(%eax) jg 1f pushl %gs:(%eax) @@ -712,7 +771,7 @@ ENTRY(_enable_preemption) ENTRY(_enable_preemption_no_check) #if MACH_RT #if MACH_ASSERT - movl $CPD_PREEMPTION_LEVEL,%eax + movl $ CPD_PREEMPTION_LEVEL,%eax cmpl $0,%gs:(%eax) jg 1f pushl $2f @@ -737,7 +796,7 @@ ENTRY(_mp_disable_preemption) ENTRY(_mp_enable_preemption) #if MACH_RT && NCPUS > 1 #if MACH_ASSERT - movl $CPD_PREEMPTION_LEVEL,%eax + movl $ CPD_PREEMPTION_LEVEL,%eax cmpl $0,%gs:(%eax) jg 1f pushl %gs:(%eax) @@ -756,7 +815,7 @@ ENTRY(_mp_enable_preemption) ENTRY(_mp_enable_preemption_no_check) #if MACH_RT && NCPUS > 1 #if MACH_ASSERT - movl $CPD_PREEMPTION_LEVEL,%eax + movl $ CPD_PREEMPTION_LEVEL,%eax cmpl $0,%gs:(%eax) jg 1f pushl $2f diff --git a/osfmk/i386/io_map_entries.h b/osfmk/i386/io_map_entries.h index 37b6f6aa0..2335e4db3 100644 --- a/osfmk/i386/io_map_entries.h +++ b/osfmk/i386/io_map_entries.h @@ -23,7 +23,16 @@ * @OSF_COPYRIGHT@ */ +#ifndef _I386_IO_MAP_ENTRIES +#define _I386_IO_MAP_ENTRIES + +#include + +#ifdef __APPLE_API_PRIVATE extern vm_offset_t io_map( vm_offset_t phys_addr, vm_size_t size); +#endif /* __APPLE_API_PRIVATE */ + +#endif /* _I386_IO_MAP_ENTRIES */ diff --git a/osfmk/i386/lock.h b/osfmk/i386/lock.h index f3cdd5241..2f623c68c 100644 --- a/osfmk/i386/lock.h +++ b/osfmk/i386/lock.h @@ -62,12 +62,16 @@ #ifndef _I386_LOCK_H_ #define _I386_LOCK_H_ +#include + +#ifdef __APPLE_API_PRIVATE + +#ifdef MACH_KERNEL_PRIVATE + #include #include #include -#ifdef MACH_KERNEL_PRIVATE - #include #include #include @@ -300,8 +304,10 @@ extern void bit_unlock( #define USIMPLE_LOCK_CALLS #endif /* !(USLOCK_DEBUG || USLOCK_STATS) */ +extern void kernel_preempt_check (void); + #endif /* MACH_KERNEL_PRIVATE */ -extern void kernel_preempt_check (void); +#endif /* __APLE_API_PRIVATE */ #endif /* _I386_LOCK_H_ */ diff --git a/osfmk/i386/locore.s b/osfmk/i386/locore.s index 152fa5a9a..547a233b6 100644 --- a/osfmk/i386/locore.s +++ b/osfmk/i386/locore.s @@ -81,7 +81,7 @@ /* Under ELF and other non-Mach-O formats, the address of * etext represents the last text address */ -#define ETEXT_ADDR $EXT(etext) +#define ETEXT_ADDR $ EXT(etext) #endif #if NCPUS > 1 @@ -342,12 +342,12 @@ Entry(start_timer) leal PCB_ISS(thread),%edi /* point to PCB`s saved state */;\ movl %edi,thread /* save for later */ ;\ movl stkp,%esi /* point to start of frame */ ;\ - movl $R_UESP,%ecx ;\ + movl $ R_UESP,%ecx ;\ sarl $2,%ecx /* word count for transfer */ ;\ cld /* we`re incrementing */ ;\ rep ;\ movsl /* transfer the frame */ ;\ - addl $R_UESP,stkp /* derive true "user" esp */ ;\ + addl $ R_UESP,stkp /* derive true "user" esp */ ;\ movl stkp,R_UESP(thread) /* store in PCB */ ;\ movl $0,%ecx ;\ mov %ss,%cx /* get current ss */ ;\ @@ -373,10 +373,10 @@ Entry(start_timer) movl MAP_PMAP(%ecx),%ecx /* get map's pmap */ ;\ cmpl EXT(kernel_pmap), %ecx /* If kernel loaded task */ ;\ jz 1f /* use kernel data segment */ ;\ - movl $USER_DS,%cx /* else use user data segment */;\ + movl $ USER_DS,%cx /* else use user data segment */;\ mov %cx,%es ;\ 1: ;\ - movl $R_UESP,%ecx ;\ + movl $ R_UESP,%ecx ;\ subl %ecx,%edi /* derive start of frame */ ;\ movl %edi,thread /* save for later */ ;\ sarl $2,%ecx /* word count for transfer */ ;\ @@ -559,15 +559,15 @@ trap_check_kernel_exit: testl $3,12(%esp) /* is trap from kernel mode? */ jne EXT(alltraps) /* if so: */ /* check for the kernel exit sequence */ - cmpl $EXT(kret_iret),8(%esp) /* on IRET? */ + cmpl $ EXT(kret_iret),8(%esp) /* on IRET? */ je fault_iret - cmpl $EXT(kret_popl_ds),8(%esp) /* popping DS? */ + cmpl $ EXT(kret_popl_ds),8(%esp) /* popping DS? */ je fault_popl_ds - cmpl $EXT(kret_popl_es),8(%esp) /* popping ES? */ + cmpl $ EXT(kret_popl_es),8(%esp) /* popping ES? */ je fault_popl_es - cmpl $EXT(kret_popl_fs),8(%esp) /* popping FS? */ + cmpl $ EXT(kret_popl_fs),8(%esp) /* popping FS? */ je fault_popl_fs - cmpl $EXT(kret_popl_gs),8(%esp) /* popping GS? */ + cmpl $ EXT(kret_popl_gs),8(%esp) /* popping GS? */ je fault_popl_gs take_fault: /* if none of the above: */ jmp EXT(alltraps) /* treat as normal trap. */ @@ -713,7 +713,7 @@ trap_from_kloaded: * up a simulated "uesp" manually, since there's none in the * frame. */ - mov $CPU_DATA,%dx + mov $ CPU_DATA,%dx mov %dx,%gs CAH(atstart) CPU_NUMBER(%edx) @@ -725,7 +725,7 @@ trap_from_kloaded: jmp EXT(take_trap) trap_from_user: - mov $CPU_DATA,%ax + mov $ CPU_DATA,%ax mov %ax,%gs CPU_NUMBER(%edx) @@ -769,7 +769,7 @@ LEXT(return_to_user) CPU_NUMBER(%eax) cmpl $0,CX(EXT(active_kloaded),%eax) jnz EXT(return_xfer_stack) - movl $CPD_ACTIVE_THREAD,%ebx + movl $ CPD_ACTIVE_THREAD,%ebx movl %gs:(%ebx),%ebx /* get active thread */ movl TH_TOP_ACT(%ebx),%ebx /* get thread->top_act */ cmpl $0,ACT_KLOADING(%ebx) /* check if kernel-loading */ @@ -777,7 +777,7 @@ LEXT(return_to_user) #if MACH_RT #if MACH_ASSERT - movl $CPD_PREEMPTION_LEVEL,%ebx + movl $ CPD_PREEMPTION_LEVEL,%ebx cmpl $0,%gs:(%ebx) je EXT(return_from_kernel) int $3 @@ -837,7 +837,7 @@ LEXT(return_xfer_stack) LEXT(return_kernel_loading) CPU_NUMBER(%eax) movl CX(EXT(kernel_stack),%eax),%esp - movl $CPD_ACTIVE_THREAD,%ebx + movl $ CPD_ACTIVE_THREAD,%ebx movl %gs:(%ebx),%ebx /* get active thread */ movl TH_TOP_ACT(%ebx),%ebx /* get thread->top_act */ movl %ebx,%edx /* save for later */ @@ -853,7 +853,7 @@ LEXT(return_kernel_loading) */ trap_from_kernel: #if MACH_KDB || MACH_KGDB - mov $CPU_DATA,%ax + mov $ CPU_DATA,%ax mov %ax,%gs movl %esp,%ebx /* save current stack */ @@ -978,11 +978,11 @@ trap_from_kernel: CPU_NUMBER(%edx) movl CX(EXT(need_ast),%edx),%eax /* get pending asts */ - testl $AST_URGENT,%eax /* any urgent preemption? */ + testl $ AST_URGENT,%eax /* any urgent preemption? */ je EXT(return_from_kernel) /* no, nothing to do */ cmpl $0,EXT(preemptable) /* kernel-mode, preemption enabled? */ je EXT(return_from_kernel) /* no, skip it */ - cmpl $T_PREEMPT,48(%esp) /* preempt request? */ + cmpl $ T_PREEMPT,48(%esp) /* preempt request? */ jne EXT(return_from_kernel) /* no, nothing to do */ movl CX(EXT(kernel_stack),%edx),%eax movl %esp,%ecx @@ -1074,12 +1074,13 @@ Entry(all_intrs) mov %ss,%dx /* switch to kernel segments */ mov %dx,%ds mov %dx,%es - mov $CPU_DATA,%dx + mov $ CPU_DATA,%dx mov %dx,%gs CPU_NUMBER(%edx) movl CX(EXT(int_stack_top),%edx),%ecx + movl 20(%esp),%edx /* get eip */ xchgl %ecx,%esp /* switch to interrupt stack */ #if STAT_TIME @@ -1091,26 +1092,28 @@ Entry(all_intrs) TIME_INT_ENTRY /* do timing */ #endif + pushl %edx /* pass eip to pe_incoming_interrupt */ + #if MACH_RT - movl $CPD_PREEMPTION_LEVEL,%edx + movl $ CPD_PREEMPTION_LEVEL,%edx incl %gs:(%edx) #endif /* MACH_RT */ - movl $CPD_INTERRUPT_LEVEL,%edx + movl $ CPD_INTERRUPT_LEVEL,%edx incl %gs:(%edx) pushl %eax /* Push trap number */ call EXT(PE_incoming_interrupt) /* call generic interrupt routine */ - addl $4,%esp /* Pop trap number */ + addl $8,%esp /* Pop trap number and eip */ .globl EXT(return_to_iret) LEXT(return_to_iret) /* (label for kdb_kintr and hardclock) */ - movl $CPD_INTERRUPT_LEVEL,%edx + movl $ CPD_INTERRUPT_LEVEL,%edx decl %gs:(%edx) #if MACH_RT - movl $CPD_PREEMPTION_LEVEL,%edx + movl $ CPD_PREEMPTION_LEVEL,%edx decl %gs:(%edx) #endif /* MACH_RT */ @@ -1138,12 +1141,12 @@ LEXT(return_to_iret) /* (label for kdb_kintr and hardclock) */ #if MACH_RT cmpl $0,EXT(preemptable) /* kernel-mode, preemption enabled? */ je 1f /* no, skip it */ - movl $CPD_PREEMPTION_LEVEL,%ecx + movl $ CPD_PREEMPTION_LEVEL,%ecx cmpl $0,%gs:(%ecx) /* preemption masked? */ jne 1f /* yes, skip it */ - testl $AST_URGENT,%eax /* any urgent requests? */ + testl $ AST_URGENT,%eax /* any urgent requests? */ je 1f /* no, skip it */ - cmpl $LEXT(locore_end),I_EIP(%esp) /* are we in locore code? */ + cmpl $ EXT(locore_end),I_EIP(%esp) /* are we in locore code? */ jb 1f /* yes, skip it */ movl CX(EXT(kernel_stack),%edx),%eax movl %esp,%ecx @@ -1185,26 +1188,30 @@ LEXT(return_to_iret) /* (label for kdb_kintr and hardclock) */ int_from_intstack: #if MACH_RT - movl $CPD_PREEMPTION_LEVEL,%edx + movl $ CPD_PREEMPTION_LEVEL,%edx incl %gs:(%edx) #endif /* MACH_RT */ - movl $CPD_INTERRUPT_LEVEL,%edx + movl $ CPD_INTERRUPT_LEVEL,%edx incl %gs:(%edx) + movl 12(%esp),%edx + pushl %edx /* push eip */ + pushl %eax /* Push trap number */ call EXT(PE_incoming_interrupt) + addl $4,%esp /* pop eip */ LEXT(return_to_iret_i) /* ( label for kdb_kintr) */ addl $4,%esp /* pop trap number */ - movl $CPD_INTERRUPT_LEVEL,%edx + movl $ CPD_INTERRUPT_LEVEL,%edx decl %gs:(%edx) #if MACH_RT - movl $CPD_PREEMPTION_LEVEL,%edx + movl $ CPD_PREEMPTION_LEVEL,%edx decl %gs:(%edx) #endif /* MACH_RT */ @@ -1244,7 +1251,7 @@ ast_from_interrupt: mov %ss,%dx /* switch to kernel segments */ mov %dx,%ds mov %dx,%es - mov $CPU_DATA,%dx + mov $ CPU_DATA,%dx mov %dx,%gs /* @@ -1332,8 +1339,8 @@ Entry(kgdb_kintr) Entry(kdb_kintr) #endif /* MACH_KDB */ movl %ebp,%eax /* save caller`s frame pointer */ - movl $EXT(return_to_iret),%ecx /* interrupt return address 1 */ - movl $EXT(return_to_iret_i),%edx /* interrupt return address 2 */ + movl $ EXT(return_to_iret),%ecx /* interrupt return address 1 */ + movl $ EXT(return_to_iret_i),%edx /* interrupt return address 2 */ 0: cmpl 16(%eax),%ecx /* does this frame return to */ /* interrupt handler (1)? */ @@ -1454,7 +1461,7 @@ Entry(mach_rpc) mov %ss,%dx /* switch to kernel data segment */ mov %dx,%ds mov %dx,%es - mov $CPU_DATA,%dx + mov $ CPU_DATA,%dx mov %dx,%gs /* @@ -1533,7 +1540,7 @@ Entry(mach_rpc) 4: cmpl $(VM_MAX_ADDRESS),%esi /* in user space? */ ja mach_call_addr /* address error if not */ - movl $USER_DS,%edx /* user data segment access */ + movl $ USER_DS,%edx /* user data segment access */ 5: mov %dx,%fs movl %esp,%edx /* save kernel ESP for error recovery */ @@ -1587,7 +1594,7 @@ Entry(syscall_int80) mov %ss,%dx /* switch to kernel data segment */ mov %dx,%ds mov %dx,%es - mov $CPU_DATA,%dx + mov $ CPU_DATA,%dx mov %dx,%gs jmp syscall_entry_3 @@ -1622,7 +1629,7 @@ syscall_entry_2: mov %ss,%dx /* switch to kernel data segment */ mov %dx,%ds mov %dx,%es - mov $CPU_DATA,%dx + mov $ CPU_DATA,%dx mov %dx,%gs /* @@ -1675,7 +1682,7 @@ syscall_entry_3: * ebx points to user regs */ 1: - movl $CPD_ACTIVE_THREAD,%edx + movl $ CPD_ACTIVE_THREAD,%edx movl %gs:(%edx),%edx /* get active thread */ /* point to current thread */ movl TH_TOP_ACT(%edx),%edx /* get thread->top_act */ @@ -1710,51 +1717,20 @@ syscall_native: movl EXT(mach_trap_table)+4(%eax),%edx /* get procedure */ - cmpl $EXT(kern_invalid),%edx /* if not "kern_invalid" */ - jne mach_syscall_native /* go on with Mach syscall */ + cmpl $ EXT(kern_invalid),%edx /* if not "kern_invalid" */ + jne do_native_call /* go on with Mach syscall */ - movl $CPD_ACTIVE_THREAD,%edx + movl $ CPD_ACTIVE_THREAD,%edx movl %gs:(%edx),%edx /* get active thread */ /* point to current thread */ movl TH_TOP_ACT(%edx),%edx /* get thread->top_act */ movl ACT_TASK(%edx),%edx /* point to task */ movl TASK_EMUL(%edx),%edx /* get emulation vector */ orl %edx,%edx /* if it exists, */ - jne mach_syscall_native /* do native system call */ + jne do_native_call /* do native system call */ shrl $4,%eax /* restore syscall number */ jmp mach_call_range /* try it as a "server" syscall */ -mach_syscall_native: - movl $CPD_ACTIVE_THREAD,%edx - movl %gs:(%edx),%edx /* get active thread */ - - movl TH_TOP_ACT(%edx),%edx /* get thread->top_act */ - movl ACT_MACH_EXC_PORT(%edx),%edx - movl $EXT(realhost),%ecx - movl HOST_NAME(%ecx),%ecx - cmpl %edx,%ecx /* act->mach_exc_port = host_name ? */ - je do_native_call /* -> send to kernel, do not collect $200 */ - cmpl $0,%edx /* thread->mach_exc_port = null ? */ - je try_task /* try task */ - jmp mach_syscall_exception - /* NOT REACHED */ - -try_task: - movl $CPD_ACTIVE_THREAD,%edx - movl %gs:(%edx),%edx /* get active thread */ - - movl TH_TOP_ACT(%edx),%edx /* get thread->top_act */ - movl ACT_TASK(%edx),%edx /* point to task */ - movl TASK_MACH_EXC_PORT(%edx),%edx - movl $EXT(realhost),%ecx - movl HOST_NAME(%ecx),%ecx - cmpl %edx,%ecx /* thread->mach_exc_port = host_name ? */ - je do_native_call /* -> send to kernel */ - cmpl $0,%edx /* thread->mach_exc_port = null ? */ - je EXT(syscall_failed) /* try task */ - jmp mach_syscall_exception - /* NOT REACHED */ - /* * Register use on entry: * eax contains syscall number @@ -1777,7 +1753,7 @@ do_native_call: 0: cmpl $(VM_MAX_ADDRESS),%esi /* in user space? */ ja mach_call_addr /* address error if not */ - movl $USER_DS,%edx /* user data segment access */ + movl $ USER_DS,%edx /* user data segment access */ 1: mov %dx,%fs movl %esp,%edx /* save kernel ESP for error recovery */ @@ -1841,22 +1817,6 @@ mach_call_addr: CAH(call_addr) jmp EXT(take_trap) /* treat as a trap */ -/* - * try sending mach system call exception to server - * Register use on entry: - * eax contains syscall number - */ -mach_syscall_exception: - push %eax /* code (syscall no.) */ - movl %esp,%edx - push $1 /* code_cnt = 1 */ - push %edx /* exception_type_t (see i/f docky) */ - push $EXC_MACH_SYSCALL /* exception */ - - CAH(exception) - call EXT(exception) - /* no return */ - /* * System call out of range. Treat as invalid-instruction trap. * (? general protection?) @@ -1864,7 +1824,7 @@ mach_syscall_exception: * eax contains syscall number */ mach_call_range: - movl $CPD_ACTIVE_THREAD,%edx + movl $ CPD_ACTIVE_THREAD,%edx movl %gs:(%edx),%edx /* get active thread */ movl TH_TOP_ACT(%edx),%edx /* get thread->top_act */ @@ -1877,7 +1837,7 @@ mach_call_range: movl %esp,%edx push $1 /* code_cnt = 1 */ push %edx /* exception_type_t (see i/f docky) */ - push $EXC_SYSCALL + push $ EXC_SYSCALL CAH(call_range) call EXT(exception) /* no return */ @@ -1926,7 +1886,7 @@ syscall_emul: subl $8,%edi /* push space for new arguments */ cmpl $(VM_MIN_ADDRESS),%edi /* still in user space? */ jb syscall_addr /* error if not */ - movl $USER_DS,%ax /* user data segment access */ + movl $ USER_DS,%ax /* user data segment access */ 1: mov %ax,%fs movl R_EFLAGS(%ebx),%eax /* move flags */ @@ -1981,14 +1941,14 @@ ENTRY(copyin) lea 0(%esi,%edx),%eax /* get user end address + 1 */ - movl $CPD_ACTIVE_THREAD,%ecx + movl $ CPD_ACTIVE_THREAD,%ecx movl %gs:(%ecx),%ecx /* get active thread */ movl TH_TOP_ACT(%ecx),%ecx /* get thread->top_act */ movl ACT_MAP(%ecx),%ecx /* get act->map */ movl MAP_PMAP(%ecx),%ecx /* get map->pmap */ cmpl EXT(kernel_pmap), %ecx jz 1f - movl $USER_DS,%cx /* user data segment access */ + movl $ USER_DS,%cx /* user data segment access */ mov %cx,%ds 1: cmpl %esi,%eax @@ -2016,7 +1976,7 @@ copy_ret: ret /* and return */ copyin_fail: - movl $EFAULT,%eax /* return error for failure */ + movl $ EFAULT,%eax /* return error for failure */ jmp copy_ret /* pop frame and return */ /* @@ -2036,7 +1996,7 @@ Entry(copyinstr) lea 0(%esi,%edx),%eax /* get user end address + 1 */ - movl $CPD_ACTIVE_THREAD,%ecx + movl $ CPD_ACTIVE_THREAD,%ecx movl %gs:(%ecx),%ecx /* get active thread */ movl TH_TOP_ACT(%ecx),%ecx /* get thread->top_act */ movl ACT_MAP(%ecx),%ecx /* get act->map */ @@ -2046,7 +2006,7 @@ Entry(copyinstr) mov %ds,%cx /* kernel data segment access */ jmp 1f 0: - movl $USER_DS,%cx /* user data segment access */ + movl $ USER_DS,%cx /* user data segment access */ 1: mov %cx,%fs xorl %eax,%eax @@ -2068,7 +2028,7 @@ Entry(copyinstr) jne 2b /* .. a NUL found? */ jmp 4f 5: - movl $ENAMETOOLONG,%eax /* String is too long.. */ + movl $ ENAMETOOLONG,%eax /* String is too long.. */ 4: xorl %eax,%eax /* return zero for success */ movl 8+S_ARG3,%edi /* get OUT len ptr */ @@ -2082,7 +2042,7 @@ copystr_ret: ret /* and return */ copystr_fail: - movl $EFAULT,%eax /* return error for failure */ + movl $ EFAULT,%eax /* return error for failure */ jmp copy_ret /* pop frame and return */ /* @@ -2103,7 +2063,7 @@ ENTRY(copyout) leal 0(%edi,%edx),%eax /* get user end address + 1 */ - movl $CPD_ACTIVE_THREAD,%ecx + movl $ CPD_ACTIVE_THREAD,%ecx movl %gs:(%ecx),%ecx /* get active thread */ movl TH_TOP_ACT(%ecx),%ecx /* get thread->top_act */ movl ACT_MAP(%ecx),%ecx /* get act->map */ @@ -2113,7 +2073,7 @@ ENTRY(copyout) mov %ds,%cx /* else kernel data segment access */ jmp 1f 0: - movl $USER_DS,%cx + movl $ USER_DS,%cx 1: mov %cx,%es @@ -2140,7 +2100,7 @@ copyout_retry: movl %edi,%ebx /* ebx = edi; */ mov %es,%cx - cmpl $USER_DS,%cx /* If kernel data segment */ + cmpl $ USER_DS,%cx /* If kernel data segment */ jnz 0f /* skip check */ cmpb $(CPUID_FAMILY_386), EXT(cpuid_family) @@ -2216,7 +2176,7 @@ copyout_ret: ret /* and return */ copyout_fail: - movl $EFAULT,%eax /* return error for failure */ + movl $ EFAULT,%eax /* return error for failure */ jmp copyout_ret /* pop frame and return */ /* @@ -2838,11 +2798,11 @@ ENTRY(set_cpu_model) pushl %ecx /* push original EFLAGS */ popfl /* restore EFLAGS */ xorl %ecx,%eax /* see what changed */ - testl $EFL_AC,%eax /* test AC bit */ + testl $ EFL_AC,%eax /* test AC bit */ jz 0f /* if AC toggled (486 or higher) */ movb $(CPUID_FAMILY_486),EXT(cpuid_family) - testl $EFL_ID,%eax /* test ID bit */ + testl $ EFL_ID,%eax /* test ID bit */ jz 0f /* if ID toggled use cpuid instruction */ xorl %eax,%eax /* get vendor identification string */ @@ -3136,7 +3096,7 @@ Entry(trap_unix_syscall) mov %ss,%dx /* switch to kernel data segment */ mov %dx,%ds mov %dx,%es - mov $CPU_DATA,%dx + mov $ CPU_DATA,%dx mov %dx,%gs /* @@ -3195,7 +3155,7 @@ Entry(trap_machdep_syscall) mov %ss,%dx /* switch to kernel data segment */ mov %dx,%ds mov %dx,%es - mov $CPU_DATA,%dx + mov $ CPU_DATA,%dx mov %dx,%gs /* @@ -3250,7 +3210,7 @@ Entry(trap_mach25_syscall) mov %ss,%dx /* switch to kernel data segment */ mov %dx,%ds mov %dx,%es - mov $CPU_DATA,%dx + mov $ CPU_DATA,%dx mov %dx,%gs /* diff --git a/osfmk/i386/loose_ends.c b/osfmk/i386/loose_ends.c index abf2750be..e64faedb2 100644 --- a/osfmk/i386/loose_ends.c +++ b/osfmk/i386/loose_ends.c @@ -63,6 +63,20 @@ * Should be rewritten in asm anyway. */ + + +/* + * Copies data from a physical page to a virtual page. This is used to + * move data from the kernel to user state. + * + */ + +kern_return_t +copyp2v(char *from, char *to, unsigned int size) { + + return(copyout(phystokv(from), to, size)); +} + /* * bcopy_phys - like bcopy but copies from/to physical addresses. * this is trivial since all phys mem is mapped into @@ -154,6 +168,85 @@ strlen( return string - 1 - ret; } +#include + +uint32_t +hw_atomic_add( + uint32_t *dest, + uint32_t delt) +{ + uint32_t oldValue; + uint32_t newValue; + + do { + oldValue = *dest; + newValue = (oldValue + delt); + } while (!OSCompareAndSwap((UInt32)oldValue, + (UInt32)newValue, (UInt32 *)dest)); + + return newValue; +} + +uint32_t +hw_atomic_sub( + uint32_t *dest, + uint32_t delt) +{ + uint32_t oldValue; + uint32_t newValue; + + do { + oldValue = *dest; + newValue = (oldValue - delt); + } while (!OSCompareAndSwap((UInt32)oldValue, + (UInt32)newValue, (UInt32 *)dest)); + + return newValue; +} + +uint32_t +hw_atomic_or( + uint32_t *dest, + uint32_t mask) +{ + uint32_t oldValue; + uint32_t newValue; + + do { + oldValue = *dest; + newValue = (oldValue | mask); + } while (!OSCompareAndSwap((UInt32)oldValue, + (UInt32)newValue, (UInt32 *)dest)); + + return newValue; +} + +uint32_t +hw_atomic_and( + uint32_t *dest, + uint32_t mask) +{ + uint32_t oldValue; + uint32_t newValue; + + do { + oldValue = *dest; + newValue = (oldValue & mask); + } while (!OSCompareAndSwap((UInt32)oldValue, + (UInt32)newValue, (UInt32 *)dest)); + + return newValue; +} + +uint32_t +hw_compare_and_store( + uint32_t oldval, + uint32_t newval, + uint32_t *dest) +{ + return OSCompareAndSwap((UInt32)oldval, (UInt32)newval, (UInt32 *)dest); +} + #if MACH_ASSERT /* diff --git a/osfmk/i386/machine_routines.c b/osfmk/i386/machine_routines.c index cd3021564..eb2558169 100644 --- a/osfmk/i386/machine_routines.c +++ b/osfmk/i386/machine_routines.c @@ -22,6 +22,7 @@ #include #include #include +#include /* IO memory map services */ @@ -154,3 +155,10 @@ be_tracing() { return(0); } + +#undef current_act +thread_act_t +current_act(void) +{ + return(current_act_fast()); +} diff --git a/osfmk/i386/machine_routines.h b/osfmk/i386/machine_routines.h index 888686b3c..4908a08f5 100644 --- a/osfmk/i386/machine_routines.h +++ b/osfmk/i386/machine_routines.h @@ -31,32 +31,7 @@ #include #include - -#if defined(PEXPERT_KERNEL_PRIVATE) || defined(MACH_KERNEL_PRIVATE) -/* IO memory map services */ - -/* Map memory map IO space */ -vm_offset_t ml_io_map( - vm_offset_t phys_addr, - vm_size_t size); - -/* boot memory allocation */ -vm_offset_t ml_static_malloc( - vm_size_t size); - -#endif - -vm_offset_t -ml_static_ptovirt( - vm_offset_t); - -void ml_static_mfree( - vm_offset_t, - vm_size_t); - -/* virtual to physical on wired pages */ -vm_offset_t ml_vtophys( - vm_offset_t vaddr); +#include /* Interrupt handling */ @@ -72,15 +47,18 @@ boolean_t ml_at_interrupt_context(void); /* Generate a fake interrupt */ void ml_cause_interrupt(void); -void ml_thread_policy( - thread_t thread, - unsigned policy_id, - unsigned policy_info); +void ml_get_timebase(unsigned long long *timestamp); -#define MACHINE_GROUP 0x00000001 -#define MACHINE_NETWORK_GROUP 0x10000000 -#define MACHINE_NETWORK_WORKLOOP 0x00000001 -#define MACHINE_NETWORK_NETISR 0x00000002 +/* Type for the IPI Hander */ +typedef void (*ipi_handler_t)(void); + +/* Register a processor */ +kern_return_t ml_processor_register( + cpu_id_t cpu_id, + vm_offset_t start_paddr, + processor_t *processor, + ipi_handler_t *ipi_handler, + boolean_t boot_cpu); /* Initialize Interrupts */ void ml_install_interrupt_handler( @@ -90,6 +68,36 @@ void ml_install_interrupt_handler( IOInterruptHandler handler, void *refCon); +#ifdef __APPLE_API_UNSTABLE +vm_offset_t +ml_static_ptovirt( + vm_offset_t); + +void ml_static_mfree( + vm_offset_t, + vm_size_t); + +/* virtual to physical on wired pages */ +vm_offset_t ml_vtophys( + vm_offset_t vaddr); + +#endif /* __APPLE_API_UNSTABLE */ + +#ifdef __APPLE_API_PRIVATE +#if defined(PEXPERT_KERNEL_PRIVATE) || defined(MACH_KERNEL_PRIVATE) +/* IO memory map services */ + +/* Map memory map IO space */ +vm_offset_t ml_io_map( + vm_offset_t phys_addr, + vm_size_t size); + +/* boot memory allocation */ +vm_offset_t ml_static_malloc( + vm_size_t size); + +#endif /* PEXPERT_KERNEL_PRIVATE || MACH_KERNEL_PRIVATE */ + #ifdef MACH_KERNEL_PRIVATE /* check pending timers */ #define machine_clock_assist() @@ -98,19 +106,18 @@ void machine_idle(void); void machine_signal_idle( processor_t processor); -#endif +#endif /* MACH_KERNEL_PRIVATE */ -/* Type for the IPI Hander */ -typedef void (*ipi_handler_t)(void); +void ml_thread_policy( + thread_t thread, + unsigned policy_id, + unsigned policy_info); -/* Register a processor */ -kern_return_t ml_processor_register( - cpu_id_t cpu_id, - vm_offset_t start_paddr, - processor_t *processor, - ipi_handler_t *ipi_handler, - boolean_t boot_cpu); +#define MACHINE_GROUP 0x00000001 +#define MACHINE_NETWORK_GROUP 0x10000000 +#define MACHINE_NETWORK_WORKLOOP 0x00000001 +#define MACHINE_NETWORK_NETISR 0x00000002 -void ml_get_timebase(unsigned long long *timestamp); +#endif /* __APPLE_API_PRIVATE */ #endif /* _I386_MACHINE_ROUTINES_H_ */ diff --git a/osfmk/i386/machine_rpc.h b/osfmk/i386/machine_rpc.h index 73e7bb253..b444de089 100644 --- a/osfmk/i386/machine_rpc.h +++ b/osfmk/i386/machine_rpc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002,2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -25,19 +25,4 @@ #ifndef _MACHINE_RPC_H_ #define _MACHINE_RPC_H_ -#if ETAP_EVENT_MONITOR -#define ETAP_EXCEPTION_PROBE(_f, _th, _ex, _sysnum) \ - if (_ex == EXC_SYSCALL) { \ - ETAP_PROBE_DATA(ETAP_P_SYSCALL_UNIX, \ - _f, \ - _th, \ - _sysnum, \ - sizeof(int)); \ - } -#else /* ETAP_EVENT_MONITOR */ -#define ETAP_EXCEPTION_PROBE(_f, _th, _ex, _sysnum) -#endif /* ETAP_EVENT_MONITOR */ - -extern void exception_return_wrapper( void ); - #endif /* _MACHINE_RPC_H_ */ diff --git a/osfmk/i386/pcb.c b/osfmk/i386/pcb.c index 5f1e65e55..c261f4214 100644 --- a/osfmk/i386/pcb.c +++ b/osfmk/i386/pcb.c @@ -58,7 +58,6 @@ #include #include #include -#include #include #include @@ -360,6 +359,8 @@ switch_context( * Load the rest of the user state for the new thread */ act_machine_switch_pcb(new_act); + KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SCHED,MACH_SCHED) | DBG_FUNC_NONE, + (int)old, (int)new, old->sched_pri, new->sched_pri, 0); return(Switch_context(old, continuation, new)); } @@ -1067,7 +1068,7 @@ thread_machine_create(thread_t thread, thread_act_t thr_act, void (*start_pos)(t * Allocate a kernel stack per shuttle */ thread->kernel_stack = (int)stack_alloc(thread,start_pos); - thread->stack_privilege = thread->kernel_stack; + thread->state &= ~TH_STACK_HANDOFF; assert(thread->kernel_stack != 0); /* @@ -1129,12 +1130,6 @@ void act_machine_init() /* Good to verify this once */ assert( THREAD_MACHINE_STATE_MAX <= THREAD_STATE_MAX ); - - /* - * If we start using kernel activations, - * would normally create kernel_thread_pool here, - * populating it from the act_zone - */ } kern_return_t @@ -1204,67 +1199,6 @@ act_machine_return(int code) assert( code == KERN_TERMINATED ); assert( thr_act ); -#ifdef CALLOUT_RPC_MODEL - /* - * JMM - RPC is not going to be done with a callout/direct- - * stack manipulation mechanism. Instead we will return/ - * unwind normally as if from a continuation. - */ - act_lock_thread(thr_act); - - if (thr_act->thread->top_act != thr_act) { - /* - * this is not the top activation; - * if possible, we should clone the shuttle so that - * both the root RPC-chain and the soon-to-be-orphaned - * RPC-chain have shuttles - * - * JMM - Cloning shuttles isn't the right approach. We - * need to alert the higher up activations to return our - * shuttle (because scheduling attributes may TRUELY be - * unique and not cloneable. - */ - act_unlock_thread(thr_act); - panic("act_machine_return: ORPHAN CASE NOT YET IMPLEMENTED"); - } - - if (thr_act->lower != THR_ACT_NULL) { - thread_t cur_thread = current_thread(); - thread_act_t cur_act; - struct ipc_port *iplock; - - /* send it an appropriate return code */ - thr_act->lower->alerts |= SERVER_TERMINATED; - install_special_handler(thr_act->lower); - - /* Return to previous act with error code */ - act_locked_act_reference(thr_act); /* keep it around */ - act_switch_swapcheck(cur_thread, (ipc_port_t)0); - (void) switch_act(THR_ACT_NULL); - /* assert(thr_act->ref_count == 0); */ /* XXX */ - cur_act = cur_thread->top_act; - MACH_RPC_RET(cur_act) = KERN_RPC_SERVER_TERMINATED; - - machine_kernel_stack_init(cur_thread, mach_rpc_return_error); - /* - * The following unlocks must be done separately since fields - * used by `act_unlock_thread()' have been cleared, meaning - * that it would not release all of the appropriate locks. - */ - iplock = thr_act->pool_port; /* remember for unlock call */ - rpc_unlock(cur_thread); - if (iplock) ip_unlock(iplock); /* must be done separately */ - act_unlock(thr_act); - act_deallocate(thr_act); /* free it */ - Load_context(cur_thread); - /*NOTREACHED*/ - - panic("act_machine_return: TALKING ZOMBIE! (2)"); - } - act_unlock_thread(thr_act); - -#endif /* CALLOUT_RPC_MODEL */ - /* This is the only activation attached to the shuttle... */ /* terminate the entire thread (shuttle plus activation) */ @@ -1341,13 +1275,6 @@ dump_act(thread_act_t thr_act) thr_act->thread, thr_act->thread ? thr_act->thread->ref_count:0, thr_act->task, thr_act->task ? thr_act->task->ref_count : 0); - if (thr_act->pool_port) { - thread_pool_t actpp = &thr_act->pool_port->ip_thread_pool; - printf("\tpool(acts_p=%x, waiting=%d) pool_next %x\n", - actpp->thr_acts, actpp->waiting, thr_act->thread_pool_next); - }else - printf("\tno thread_pool\n"); - printf("\talerts=%x mask=%x susp=%d user_stop=%d active=%x ast=%x\n", thr_act->alerts, thr_act->alert_mask, thr_act->suspend_count, thr_act->user_stop_count, @@ -1462,6 +1389,9 @@ stack_handoff(thread_t old, if (old->top_act->task->map->pmap != new_pmap) PMAP_ACTIVATE_MAP(new->top_act->task->map, cpu_number()); + KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SCHED,MACH_STACK_HANDOFF) | DBG_FUNC_NONE, + (int)old, (int)new, old->sched_pri, new->sched_pri, 0); + thread_machine_set_current(new); active_stacks[cpu_number()] = new->kernel_stack; diff --git a/osfmk/i386/pmap.c b/osfmk/i386/pmap.c index b23cdca1b..a3e6bfa4e 100644 --- a/osfmk/i386/pmap.c +++ b/osfmk/i386/pmap.c @@ -552,7 +552,7 @@ pmap_map( ps = PAGE_SIZE; while (start < end) { - pmap_enter(kernel_pmap, virt, start, prot, FALSE); + pmap_enter(kernel_pmap, virt, start, prot, 0, FALSE); virt += ps; start += ps; } @@ -1415,9 +1415,6 @@ pmap_page_protect( /* * Remove the mapping, collecting any modify bits. */ - if (iswired(*pte)) - panic("pmap_remove_all removing a wired page"); - { register int i = ptes_per_vm_page; @@ -1584,6 +1581,7 @@ pmap_enter( vm_offset_t v, register vm_offset_t pa, vm_prot_t prot, + unsigned int flags, boolean_t wired) { register pt_entry_t *pte; @@ -2026,6 +2024,7 @@ pmap_change_wiring( register int i; spl_t spl; +#if 0 /* * We must grab the pmap system lock because we may * change a pte_page queue. @@ -2058,6 +2057,11 @@ pmap_change_wiring( } PMAP_READ_UNLOCK(map, spl); + +#else + return; +#endif + } /* @@ -2924,7 +2928,7 @@ pmap_movepage(unsigned long from, unsigned long to, vm_size_t size) PMAP_READ_UNLOCK(kernel_pmap, spl); pmap_enter(kernel_pmap, to, i386_trunc_page(*pte), - VM_PROT_READ|VM_PROT_WRITE, *pte & INTEL_PTE_WIRED); + VM_PROT_READ|VM_PROT_WRITE, 0, *pte & INTEL_PTE_WIRED); pmap_remove(kernel_pmap, from, from+PAGE_SIZE); @@ -2975,5 +2979,12 @@ kern_return_t bmapmapr(vm_offset_t va) { } #endif - - +/* temporary workaround */ +boolean_t +coredumpok(vm_map_t map, vm_offset_t va) +{ + pt_entry_t *ptep; + ptep = pmap_pte(map->pmap, va); + if (0 == ptep) return FALSE; + return ((*ptep & (INTEL_PTE_NCACHE|INTEL_PTE_WIRED)) != (INTEL_PTE_NCACHE|INTEL_PTE_WIRED)); +} diff --git a/osfmk/i386/pmap.h b/osfmk/i386/pmap.h index 602ff21ab..0517c243c 100644 --- a/osfmk/i386/pmap.h +++ b/osfmk/i386/pmap.h @@ -105,6 +105,9 @@ typedef unsigned int pt_entry_t; #define PTESHIFT 12 /* page table shift */ #define PTEMASK 0x3ff /* mask for page table index */ + +#define VM_WIMG_DEFAULT VM_MEM_COHERENT + /* * Convert kernel virtual address to linear address */ @@ -150,6 +153,13 @@ typedef unsigned int pt_entry_t; #define pte_to_pa(p) ((p) & INTEL_PTE_PFN) #define pte_increment_pa(p) ((p) += INTEL_OFFMASK+1) +#define PMAP_DEFAULT_CACHE 0 +#define PMAP_INHIBIT_CACHE 1 +#define PMAP_GUARDED_CACHE 2 +#define PMAP_ACTIVATE_CACHE 4 +#define PMAP_NO_GUARD_CACHE 8 + + /* * Convert page table entry to kernel virtual address */ @@ -512,6 +522,8 @@ extern void flush_dcache(vm_offset_t addr, unsigned count, int phys); #define pmap_copy(dst_pmap,src_pmap,dst_addr,len,src_addr) #define pmap_attribute(pmap,addr,size,attr,value) \ (KERN_INVALID_ADDRESS) +#define pmap_attribute_cache_sync(addr,size,attr,value) \ + (KERN_INVALID_ADDRESS) #define pmap_sync_caches_phys(pa) \ (KERN_INVALID_ADDRESS) diff --git a/osfmk/i386/read_fault.c b/osfmk/i386/read_fault.c index 2049a1ff1..1af4a97f2 100644 --- a/osfmk/i386/read_fault.c +++ b/osfmk/i386/read_fault.c @@ -92,6 +92,19 @@ intel_read_fault( register vm_page_t m; vm_map_t pmap_map; vm_map_t original_map = map; + thread_t cur_thread; + boolean_t funnel_set; + funnel_t *curflock; + + cur_thread = current_thread(); + + if ((cur_thread->funnel_state & TH_FN_OWNED) == TH_FN_OWNED) { + funnel_set = TRUE; + curflock = cur_thread->funnel_lock; + thread_funnel_set( curflock , FALSE); + } else { + funnel_set = FALSE; + } RetryFault: @@ -110,7 +123,9 @@ intel_read_fault( vm_map_unlock_read(map); if (result != KERN_SUCCESS) { - return (result); + if (funnel_set) + thread_funnel_set( curflock, TRUE); + return (result); } if(pmap_map != map) { @@ -143,6 +158,8 @@ intel_read_fault( case VM_FAULT_RETRY: goto RetryFault; case VM_FAULT_INTERRUPTED: + if (funnel_set) + thread_funnel_set( curflock, TRUE); return (KERN_SUCCESS); case VM_FAULT_MEMORY_SHORTAGE: VM_PAGE_WAIT(); @@ -209,6 +226,8 @@ intel_read_fault( vm_object_lock(m->object); RELEASE_PAGE(m); UNLOCK_AND_DEALLOCATE; + if (funnel_set) + thread_funnel_set( curflock, TRUE); return (result); } @@ -235,7 +254,7 @@ intel_read_fault( * Put the page in the physical map. */ - PMAP_ENTER(pmap_map->pmap, vaddr, m, VM_PROT_READ, wired); + PMAP_ENTER(pmap_map->pmap, vaddr, m, VM_PROT_READ, PMAP_DEFAULT_CACHE, wired); if(pmap_map != map) { vm_map_unlock_read(pmap_map); @@ -256,6 +275,8 @@ intel_read_fault( #undef UNLOCK_AND_DEALLOCATE #undef RELEASE_PAGE + if (funnel_set) + thread_funnel_set( curflock, TRUE); return (KERN_SUCCESS); } diff --git a/osfmk/i386/rtclock.c b/osfmk/i386/rtclock.c index 3fd52fb11..3a995311d 100644 --- a/osfmk/i386/rtclock.c +++ b/osfmk/i386/rtclock.c @@ -73,6 +73,20 @@ void sysclk_setalarm( extern void (*IOKitRegisterInterruptHook)(void *, int irq, int isclock); +/* + * Inlines to get timestamp counter value. + */ + +static inline void rdtsc_hilo(uint32_t *hi, uint32_t *lo) { + asm volatile("rdtsc": "=a" (*lo), "=d" (*hi)); +} + +static inline uint64_t rdtsc_64(void) { + uint64_t result; + asm volatile("rdtsc": "=A" (result)); + return result; +} + /* * Lists of clock routines. */ @@ -140,6 +154,10 @@ int rtc_intr_hertz; /* interrupts per HZ */ int rtc_intr_freq; /* interrupt frequency */ int rtc_print_lost_tick; /* print lost tick */ +uint32_t rtc_cyc_per_sec; /* processor cycles per seconds */ +uint32_t rtc_last_int_tsc_lo; /* tsc values saved per interupt */ +uint32_t rtc_last_int_tsc_hi; + /* * Macros to lock/unlock real-time clock device. */ @@ -224,6 +242,8 @@ unsigned int microdata = 50; extern int measure_delay(int us); void rtc_setvals( unsigned int, clock_res_t ); +static void rtc_set_cyc_per_sec(); + /* * Initialize non-zero clock structure values. */ @@ -339,6 +359,7 @@ sysclk_init(void) RtcTime = &rtclock.time; rtc_setvals( CLKNUM, RTC_MINRES ); /* compute constants */ + rtc_set_cyc_per_sec(); /* compute number of tsc beats per second */ return (1); } @@ -477,39 +498,67 @@ sysclk_gettime_interrupts_disabled( simple_unlock(&rtclock.lock); } -static -natural_t -get_uptime_ticks(void) -{ - natural_t result = 0; - unsigned int val, val2; +// utility routine +// Code to calculate how many processor cycles are in a second... - if (!RtcTime) - return (result); +static void +rtc_set_cyc_per_sec() +{ - /* - * Inhibit interrupts. Determine the incremental - * time since the last interrupt. (This could be - * done in assembler for a bit more speed). - */ - do { - READ_8254(val); /* read clock */ - READ_8254(val2); /* read clock */ - } while (val2 > val || val2 < val - 10); - if (val > clks_per_int_99) { - outb(0x0a, 0x20); /* see if interrupt pending */ - if (inb(0x20) & 1) - result = rtclock.intr_nsec; /* yes, add a tick */ - } - result += ((clks_per_int - val) * time_per_clk) / ZHZ; - if (result < last_ival) { - if (rtc_print_lost_tick) - printf( "rtclock: missed clock interrupt.\n" ); - } + int x, y; + uint64_t cycles; + uint32_t c[15]; // array for holding sampled cycle counts + mach_timespec_t tst[15]; // array for holding time values. NOTE for some reason tv_sec not work + + for (x=0; x<15; x++) { // quick sample 15 times + tst[x].tv_sec = 0; + tst[x].tv_nsec = 0; + sysclk_gettime_internal(&tst[x]); + rdtsc_hilo(&y, &c[x]); + } + y = 0; + cycles = 0; + for (x=0; x<14; x++) { + // simple formula really. calculate the numerator as the number of elapsed processor + // cycles * 1000 to adjust for the resolution we want. The denominator is the + // elapsed "real" time in nano-seconds. The result will be the processor speed in + // Mhz. any overflows will be discarded before they are added + if ((c[x+1] > c[x]) && (tst[x+1].tv_nsec > tst[x].tv_nsec)) { + cycles += ((uint64_t)(c[x+1]-c[x]) * NSEC_PER_SEC ) / (uint64_t)(tst[x+1].tv_nsec - tst[x].tv_nsec); // elapsed nsecs + y +=1; + } + } + if (y>0) { // we got more than 1 valid sample. This also takes care of the case of if the clock isn't running + cycles = cycles / y; // calc our average + } + rtc_cyc_per_sec = cycles; + rdtsc_hilo(&rtc_last_int_tsc_hi, &rtc_last_int_tsc_lo); +} - return (result); +static +natural_t +get_uptime_cycles(void) +{ + // get the time since the last interupt based on the processors TSC ignoring the + // RTC for speed + + uint32_t a,d,intermediate_lo,intermediate_hi,result; + uint64_t newTime; + + rdtsc_hilo(&d, &a); + if (d != rtc_last_int_tsc_hi) { + newTime = d-rtc_last_int_tsc_hi; + newTime = (newTime<<32) + (a-rtc_last_int_tsc_lo); + result = newTime; + } else { + result = a-rtc_last_int_tsc_lo; + } + __asm__ volatile ( " mul %3 ": "=eax" (intermediate_lo), "=edx" (intermediate_hi): "a"(result), "d"(NSEC_PER_SEC) ); + __asm__ volatile ( " div %3": "=eax" (result): "eax"(intermediate_lo), "edx" (intermediate_hi), "ecx" (rtc_cyc_per_sec) ); + return result; } + /* * Get clock device attributes. */ @@ -860,6 +909,7 @@ rtclock_intr(void) * update in order: mtv_csec, mtv_time.tv_nsec, mtv_time.tv_sec). */ LOCK_RTC(s); + rdtsc_hilo(&rtc_last_int_tsc_hi, &rtc_last_int_tsc_lo); i = rtclock.time.tv_nsec + rtclock.intr_nsec; if (i < NSEC_PER_SEC) rtclock.time.tv_nsec = i; @@ -870,7 +920,7 @@ rtclock_intr(void) /* note time now up to date */ last_ival = 0; - rtclock.abstime += (NSEC_PER_SEC/HZ); + rtclock.abstime += rtclock.intr_nsec; abstime = rtclock.abstime; if ( rtclock.timer_is_set && rtclock.timer_deadline <= abstime ) { @@ -932,7 +982,7 @@ clock_get_uptime( spl_t s; LOCK_RTC(s); - ticks = get_uptime_ticks(); + ticks = get_uptime_cycles(); *result = rtclock.abstime; UNLOCK_RTC(s); diff --git a/osfmk/i386/start.s b/osfmk/i386/start.s index ac9bc3394..41347ee88 100644 --- a/osfmk/i386/start.s +++ b/osfmk/i386/start.s @@ -327,7 +327,7 @@ fix_ldt_ret: movl KERNELBASEPDE(%eax),%ecx movl %ecx,(%eax) - movl $EXT(pag_start),%ebx /* first paged code address */ + movl $ EXT(pag_start),%ebx /* first paged code address */ movl %cr0,%eax orl $(CR0_PG),%eax /* set PG bit in CR0 */ @@ -370,7 +370,7 @@ LEXT(vstart) movw $(KERNEL_TSS),%ax ltr %ax /* set up KTSS */ - mov $CPU_DATA,%ax + mov $ CPU_DATA,%ax mov %ax,%gs lea EXT(eintstack),%esp /* switch to the bootup stack */ @@ -419,7 +419,7 @@ LEXT(slave_start) /* paged mode is enabled */ movl %edx,%cr3 /* use bootstrap PDE to enable paging */ - movl $EXT(spag_start),%edx /* first paged code address */ + movl $ EXT(spag_start),%edx /* first paged code address */ movl %cr0,%eax orl $(CR0_PG),%eax /* set PG bit in CR0 */ @@ -469,13 +469,13 @@ LEXT(svstart) CPU_NUMBER(%eax) movw $(GDTSZ*8-1),0(%esp) /* set GDT size in GDT descriptor */ movl CX(EXT(mp_gdt),%eax),%edx - addl $KVTOLINEAR,%edx + addl $ KVTOLINEAR,%edx movl %edx,2(%esp) /* point to local GDT (linear address) */ lgdt 0(%esp) /* load new GDT */ movw $(IDTSZ*8-1),0(%esp) /* set IDT size in IDT descriptor */ movl CX(EXT(mp_idt),%eax),%edx - addl $KVTOLINEAR,%edx + addl $ KVTOLINEAR,%edx movl %edx,2(%esp) /* point to local IDT (linear address) */ lidt 0(%esp) /* load new IDT */ @@ -485,7 +485,7 @@ LEXT(svstart) movw $(KERNEL_TSS),%ax ltr %ax /* load new KTSS */ - mov $CPU_DATA,%ax + mov $ CPU_DATA,%ax mov %ax,%gs call EXT(slave_main) /* start MACH */ diff --git a/osfmk/i386/thread_act.h b/osfmk/i386/thread_act.h index 2ce689328..ffe762201 100644 --- a/osfmk/i386/thread_act.h +++ b/osfmk/i386/thread_act.h @@ -172,4 +172,11 @@ extern void *act_thread_csave(void); extern void act_thread_catt(void *ctx); extern void act_thread_cfree(void *ctx); +#define current_act_fast() (current_thread()->top_act) +#define current_act_slow() ((current_thread()) ? \ + current_act_fast() : \ + THR_ACT_NULL) + +#define current_act() current_act_slow() /* JMM - til we find the culprit */ + #endif /* _I386_THREAD_ACT_H_ */ diff --git a/osfmk/i386/trap.c b/osfmk/i386/trap.c index a845341d8..5a6b78c20 100644 --- a/osfmk/i386/trap.c +++ b/osfmk/i386/trap.c @@ -355,7 +355,7 @@ kernel_trap( trunc_page((vm_offset_t)subcode), VM_PROT_READ|VM_PROT_WRITE, FALSE, - (map == kernel_map) ? interruptible : THREAD_ABORTSAFE); + (map == kernel_map) ? interruptible : THREAD_ABORTSAFE, NULL, 0); } #if MACH_KDB if (result == KERN_SUCCESS) { @@ -577,7 +577,7 @@ user_trap( trunc_page((vm_offset_t)subcode), prot, FALSE, - THREAD_ABORTSAFE)); + THREAD_ABORTSAFE, NULL, 0)); /* NOTREACHED */ } else { @@ -589,7 +589,7 @@ user_trap( trunc_page((vm_offset_t)subcode), prot, FALSE, - (map == kernel_map) ? THREAD_UNINT : THREAD_ABORTSAFE); + (map == kernel_map) ? THREAD_UNINT : THREAD_ABORTSAFE, NULL, 0); if ((result != KERN_SUCCESS) && (result != KERN_ABORTED)) { /* * Must expand vm_fault by hand, diff --git a/osfmk/ipc/ipc_entry.c b/osfmk/ipc/ipc_entry.c index 106c3add6..9d48e93f9 100644 --- a/osfmk/ipc/ipc_entry.c +++ b/osfmk/ipc/ipc_entry.c @@ -654,10 +654,7 @@ ipc_entry_grow_table( * We just wait for them to finish. */ - assert_wait((event_t) space, THREAD_UNINT); - is_write_unlock(space); - thread_block((void (*)(void)) 0); - is_write_lock(space); + is_write_sleep(space); return KERN_SUCCESS; } diff --git a/osfmk/ipc/ipc_kmsg.c b/osfmk/ipc/ipc_kmsg.c index 3afee2bd4..58a914593 100644 --- a/osfmk/ipc/ipc_kmsg.c +++ b/osfmk/ipc/ipc_kmsg.c @@ -236,7 +236,7 @@ ipc_kmsg_free( ip_unlock(port); return; } - ip_unlock(port); + ip_check_unlock(port); /* May be last reference */ goto free_it; } diff --git a/osfmk/ipc/ipc_kmsg.h b/osfmk/ipc/ipc_kmsg.h index 9ebb1402d..dce03b573 100644 --- a/osfmk/ipc/ipc_kmsg.h +++ b/osfmk/ipc/ipc_kmsg.h @@ -119,13 +119,15 @@ typedef struct ipc_kmsg { #define ikm_prealloc_set_inuse(kmsg, port) \ MACRO_BEGIN \ - assert(port != IP_NULL); \ - (kmsg)->ikm_prealloc = port; \ + assert((port) != IP_NULL); \ + (kmsg)->ikm_prealloc = (port); \ + ip_reference(port); \ MACRO_END #define ikm_prealloc_clear_inuse(kmsg, port) \ MACRO_BEGIN \ (kmsg)->ikm_prealloc = IP_NULL; \ + ip_release(port); \ MACRO_END diff --git a/osfmk/ipc/ipc_mqueue.c b/osfmk/ipc/ipc_mqueue.c index 97f13b62c..81defb81f 100644 --- a/osfmk/ipc/ipc_mqueue.c +++ b/osfmk/ipc/ipc_mqueue.c @@ -94,7 +94,7 @@ ipc_mqueue_init( boolean_t is_set) { if (is_set) { - wait_queue_sub_init(&mqueue->imq_set_queue, SYNC_POLICY_FIFO); + wait_queue_set_init(&mqueue->imq_set_queue, SYNC_POLICY_FIFO); } else { wait_queue_init(&mqueue->imq_wait_queue, SYNC_POLICY_FIFO); ipc_kmsg_queue_init(&mqueue->imq_messages); @@ -133,39 +133,51 @@ ipc_mqueue_member( * Routine: ipc_mqueue_remove * Purpose: * Remove the association between the queue and the specified - * subordinate message queue. + * set message queue. */ kern_return_t ipc_mqueue_remove( ipc_mqueue_t mqueue, - ipc_mqueue_t sub_mqueue) + ipc_mqueue_t set_mqueue) { wait_queue_t mq_waitq = &mqueue->imq_wait_queue; - wait_queue_sub_t sub_waitq = &sub_mqueue->imq_set_queue; + wait_queue_set_t set_waitq = &set_mqueue->imq_set_queue; - if (wait_queue_member(mq_waitq, sub_waitq)) { - wait_queue_unlink(mq_waitq, sub_waitq); - return KERN_SUCCESS; - } - return KERN_NOT_IN_SET; + return wait_queue_unlink(mq_waitq, set_waitq); } /* - * Routine: ipc_mqueue_remove_one + * Routine: ipc_mqueue_remove_from_all * Purpose: - * Find and remove one subqueue from the queue. + * Remove the mqueue from all the sets it is a member of * Conditions: - * Will return the set mqueue that was removed + * Nothing locked. */ void -ipc_mqueue_remove_one( - ipc_mqueue_t mqueue, - ipc_mqueue_t *sub_queuep) +ipc_mqueue_remove_from_all( + ipc_mqueue_t mqueue) { wait_queue_t mq_waitq = &mqueue->imq_wait_queue; - wait_queue_unlink_one(mq_waitq, (wait_queue_sub_t *)sub_queuep); + wait_queue_unlink_all(mq_waitq); + return; +} + +/* + * Routine: ipc_mqueue_remove_all + * Purpose: + * Remove all the member queues from the specified set. + * Conditions: + * Nothing locked. + */ +void +ipc_mqueue_remove_all( + ipc_mqueue_t mqueue) +{ + wait_queue_set_t mq_setq = &mqueue->imq_set_queue; + + wait_queue_set_unlink_all(mq_setq); return; } @@ -187,7 +199,7 @@ ipc_mqueue_add( ipc_mqueue_t set_mqueue) { wait_queue_t port_waitq = &port_mqueue->imq_wait_queue; - wait_queue_sub_t set_waitq = &set_mqueue->imq_set_queue; + wait_queue_set_t set_waitq = &set_mqueue->imq_set_queue; ipc_kmsg_queue_t kmsgq; ipc_kmsg_t kmsg, next; kern_return_t kr; @@ -213,10 +225,11 @@ ipc_mqueue_add( for (;;) { thread_t th; - th = wait_queue_wakeup_identity_locked(port_waitq, - IPC_MQUEUE_RECEIVE, - THREAD_AWAKENED, - FALSE); + th = wait_queue_wakeup64_identity_locked( + port_waitq, + IPC_MQUEUE_RECEIVE, + THREAD_AWAKENED, + FALSE); /* waitq/mqueue still locked, thread locked */ if (th == THREAD_NULL) @@ -279,10 +292,11 @@ void ipc_mqueue_changed( ipc_mqueue_t mqueue) { - wait_queue_wakeup_all_locked(&mqueue->imq_wait_queue, - IPC_MQUEUE_RECEIVE, - THREAD_RESTART, - FALSE); /* unlock waitq? */ + wait_queue_wakeup64_all_locked( + &mqueue->imq_wait_queue, + IPC_MQUEUE_RECEIVE, + THREAD_RESTART, + FALSE); /* unlock waitq? */ } @@ -312,7 +326,7 @@ ipc_mqueue_send( mach_msg_option_t option, mach_msg_timeout_t timeout) { - int save_wait_result; + int wresult; spl_t s; /* @@ -342,33 +356,36 @@ ipc_mqueue_send( return MACH_SEND_TIMED_OUT; } mqueue->imq_fullwaiters = TRUE; - (void)wait_queue_assert_wait_locked(&mqueue->imq_wait_queue, - IPC_MQUEUE_FULL, - THREAD_ABORTSAFE, - TRUE); /* unlock? */ + wresult = wait_queue_assert_wait64_locked( + &mqueue->imq_wait_queue, + IPC_MQUEUE_FULL, + THREAD_ABORTSAFE, + TRUE); /* unlock? */ /* wait/mqueue is unlocked */ splx(s); - if (option & MACH_SEND_TIMEOUT) - thread_set_timer(timeout, 1000*NSEC_PER_USEC); - - counter(c_ipc_mqueue_send_block++); - save_wait_result = thread_block((void (*)(void)) 0); + if (wresult == THREAD_WAITING) { + if (option & MACH_SEND_TIMEOUT) { + thread_set_timer(timeout, 1000*NSEC_PER_USEC); + wresult = thread_block(THREAD_CONTINUE_NULL); + if (wresult != THREAD_TIMED_OUT) + thread_cancel_timer(); + } else { + wresult = thread_block(THREAD_CONTINUE_NULL); + } + counter(c_ipc_mqueue_send_block++); + } - switch (save_wait_result) { + switch (wresult) { case THREAD_TIMED_OUT: assert(option & MACH_SEND_TIMEOUT); return MACH_SEND_TIMED_OUT; case THREAD_AWAKENED: /* we can proceed - inherited msgcount from waker */ - if (option & MACH_SEND_TIMEOUT) - thread_cancel_timer(); break; case THREAD_INTERRUPTED: - if (option & MACH_SEND_TIMEOUT) - thread_cancel_timer(); return MACH_SEND_INTERRUPTED; case THREAD_RESTART: @@ -399,10 +416,11 @@ ipc_mqueue_release_msgcount( mqueue->imq_msgcount--; if (!imq_full(mqueue) && mqueue->imq_fullwaiters) { - if (wait_queue_wakeup_one_locked(&mqueue->imq_wait_queue, - IPC_MQUEUE_FULL, - THREAD_AWAKENED, - FALSE) != KERN_SUCCESS) { + if (wait_queue_wakeup64_one_locked( + &mqueue->imq_wait_queue, + IPC_MQUEUE_FULL, + THREAD_AWAKENED, + FALSE) != KERN_SUCCESS) { mqueue->imq_fullwaiters = FALSE; } else { mqueue->imq_msgcount++; /* gave it away */ @@ -440,10 +458,11 @@ ipc_mqueue_post( wait_queue_t waitq = &mqueue->imq_wait_queue; thread_t receiver; - receiver = wait_queue_wakeup_identity_locked(waitq, - IPC_MQUEUE_RECEIVE, - THREAD_AWAKENED, - FALSE); + receiver = wait_queue_wakeup64_identity_locked( + waitq, + IPC_MQUEUE_RECEIVE, + THREAD_AWAKENED, + FALSE); /* waitq still locked, thread locked */ if (receiver == THREAD_NULL) { @@ -612,11 +631,11 @@ ipc_mqueue_receive( mach_msg_timeout_t timeout, int interruptible) { - ipc_port_t port; - mach_msg_return_t mr, mr2; - ipc_kmsg_queue_t kmsgs; - kern_return_t save_wait_result; - thread_t self; + ipc_port_t port; + mach_msg_return_t mr, mr2; + ipc_kmsg_queue_t kmsgs; + wait_result_t wresult; + thread_t self; ipc_kmsg_t *kmsgp; mach_port_seqno_t *seqnop; spl_t s; @@ -644,7 +663,7 @@ ipc_mqueue_receive( * change will succeed and find us. */ search_set: - queue_iterate(q, wql, wait_queue_link_t, wql_sublinks) { + queue_iterate(q, wql, wait_queue_link_t, wql_setlinks) { port_mq = (ipc_mqueue_t)wql->wql_queue; kmsgs = &port_mq->imq_messages; @@ -671,8 +690,8 @@ ipc_mqueue_receive( imq_unlock(port_mq); continue; } - queue_remove(q, wql, wait_queue_link_t, wql_sublinks); - queue_enter(q, wql, wait_queue_link_t, wql_sublinks); + queue_remove(q, wql, wait_queue_link_t, wql_setlinks); + queue_enter(q, wql, wait_queue_link_t, wql_setlinks); imq_unlock(mqueue); ipc_mqueue_select(port_mq, option, max_size); @@ -715,34 +734,29 @@ ipc_mqueue_receive( self->ith_option = option; self->ith_msize = max_size; - (void)wait_queue_assert_wait_locked(&mqueue->imq_wait_queue, - IPC_MQUEUE_RECEIVE, - interruptible, - TRUE); /* unlock? */ + wresult = wait_queue_assert_wait64_locked(&mqueue->imq_wait_queue, + IPC_MQUEUE_RECEIVE, + interruptible, + TRUE); /* unlock? */ /* mqueue/waitq is unlocked */ splx(s); - if (option & MACH_RCV_TIMEOUT) { - thread_set_timer(timeout, 1000*NSEC_PER_USEC); - } + if (wresult == THREAD_WAITING) { + if (option & MACH_RCV_TIMEOUT) + thread_set_timer(timeout, 1000*NSEC_PER_USEC); - if (interruptible == THREAD_ABORTSAFE) { - counter(c_ipc_mqueue_receive_block_user++); - } else { - counter(c_ipc_mqueue_receive_block_kernel++); - } + if (interruptible == THREAD_ABORTSAFE) + counter(c_ipc_mqueue_receive_block_user++); + else + counter(c_ipc_mqueue_receive_block_kernel++); -#if defined (__i386__) - thread_block((void (*)(void))0); -#else - if (self->ith_continuation) { - thread_block(ipc_mqueue_receive_continue); - } else { - thread_block((void (*)(void))0); - } -#endif + if (self->ith_continuation) + thread_block(ipc_mqueue_receive_continue); + /* NOTREACHED */ - ipc_mqueue_receive_results(); /* if we fell thru */ + thread_block(THREAD_CONTINUE_NULL); + } + ipc_mqueue_receive_results(); } @@ -834,10 +848,11 @@ ipc_mqueue_destroy( * rouse all blocked senders */ mqueue->imq_fullwaiters = FALSE; - wait_queue_wakeup_all_locked(&mqueue->imq_wait_queue, - IPC_MQUEUE_FULL, - THREAD_AWAKENED, - FALSE); + wait_queue_wakeup64_all_locked( + &mqueue->imq_wait_queue, + IPC_MQUEUE_FULL, + THREAD_AWAKENED, + FALSE); kmqueue = &mqueue->imq_messages; @@ -880,10 +895,11 @@ ipc_mqueue_set_qlimit( wakeup = qlimit - mqueue->imq_qlimit; for (i = 0; i < wakeup; i++) { - if (wait_queue_wakeup_one_locked(&mqueue->imq_wait_queue, - IPC_MQUEUE_FULL, - THREAD_AWAKENED, - FALSE) == KERN_NOT_WAITING) { + if (wait_queue_wakeup64_one_locked( + &mqueue->imq_wait_queue, + IPC_MQUEUE_FULL, + THREAD_AWAKENED, + FALSE) == KERN_NOT_WAITING) { mqueue->imq_fullwaiters = FALSE; break; } diff --git a/osfmk/ipc/ipc_mqueue.h b/osfmk/ipc/ipc_mqueue.h index 85e0b1d92..209414666 100644 --- a/osfmk/ipc/ipc_mqueue.h +++ b/osfmk/ipc/ipc_mqueue.h @@ -82,7 +82,7 @@ typedef struct ipc_mqueue { mach_port_seqno_t seqno; boolean_t fullwaiters; } port; - struct wait_queue_sub set_queue; + struct wait_queue_set set_queue; } data; } *ipc_mqueue_t; @@ -96,8 +96,8 @@ typedef struct ipc_mqueue { #define imq_fullwaiters data.port.fullwaiters #define imq_set_queue data.set_queue -#define imq_setlinks data.set_queue.wqs_sublinks -#define imq_is_set(mq) wait_queue_is_sub(&(mq)->imq_set_queue) +#define imq_setlinks data.set_queue.wqs_setlinks +#define imq_is_set(mq) wait_queue_is_set(&(mq)->imq_set_queue) #define imq_lock(mq) wait_queue_lock(&(mq)->imq_wait_queue) #define imq_lock_try(mq) wait_queue_lock_try(&(mq)->imq_wait_queue) @@ -109,8 +109,8 @@ typedef struct ipc_mqueue { extern int ipc_mqueue_full; extern int ipc_mqueue_rcv; -#define IPC_MQUEUE_FULL (event_t)&ipc_mqueue_full -#define IPC_MQUEUE_RECEIVE (event_t)&ipc_mqueue_rcv +#define IPC_MQUEUE_FULL (event64_t)&ipc_mqueue_full +#define IPC_MQUEUE_RECEIVE (event64_t)&ipc_mqueue_rcv /* * Exported interfaces @@ -121,12 +121,6 @@ extern void ipc_mqueue_init( ipc_mqueue_t mqueue, boolean_t is_set); -/* Move messages from one queue to another */ -extern void ipc_mqueue_move( - ipc_mqueue_t dest, - ipc_mqueue_t source, - ipc_port_t port); - /* Wake up receivers waiting in a message queue */ extern void ipc_mqueue_changed( ipc_mqueue_t mqueue); diff --git a/osfmk/ipc/ipc_object.h b/osfmk/ipc/ipc_object.h index 67a0e4910..62a11978a 100644 --- a/osfmk/ipc/ipc_object.h +++ b/osfmk/ipc/ipc_object.h @@ -68,7 +68,6 @@ #include #include #include -#include #include #include @@ -93,7 +92,6 @@ struct ipc_object { ipc_object_refs_t io_references; ipc_object_bits_t io_bits; port_name_t io_receiver_name; - struct thread_pool io_thread_pool; #if NCPUS == 1 usimple_lock_data_t io_lock_data; #else diff --git a/osfmk/ipc/ipc_port.c b/osfmk/ipc/ipc_port.c index 989d73b81..9bb7ed781 100644 --- a/osfmk/ipc/ipc_port.c +++ b/osfmk/ipc/ipc_port.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002,2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -66,9 +66,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -413,8 +411,8 @@ ipc_port_clear_receiver( * pull ourselves from any sets. */ if (port->ip_pset_count != 0) { - ipc_pset_remove_all(port); - port->ip_pset_count = 0; + ipc_pset_remove_from_all(port); + assert(port->ip_pset_count == 0); } /* @@ -459,10 +457,6 @@ ipc_port_init( port->ip_pset_count = 0; port->ip_premsg = IKM_NULL; - thread_pool_init(&port->ip_thread_pool); - - port->ip_subsystem = RPC_SUBSYSTEM_NULL; - #if MACH_ASSERT ipc_port_init_debug(port); #endif /* MACH_ASSERT */ @@ -602,7 +596,6 @@ ipc_port_destroy( ipc_kmsg_queue_t kmqueue; ipc_kmsg_t kmsg; ipc_port_request_t dnrequests; - thread_pool_t thread_pool; assert(ip_active(port)); /* port->ip_receiver_name is garbage */ @@ -653,30 +646,19 @@ ipc_port_destroy( /* * If the port has a preallocated message buffer and that buffer - * is not inuse, free it. If it has and inuse one, then the kmsg + * is not inuse, free it. If it has an inuse one, then the kmsg * free will detect that we freed the association and it can free it * like a normal buffer. */ if (IP_PREALLOC(port)) { kmsg = port->ip_premsg; assert(kmsg != IKM_NULL); - if (!ikm_prealloc_inuse(kmsg)) { - ikm_prealloc_clear_inuse(kmsg, port); - IP_CLEAR_PREALLOC(port, kmsg); + IP_CLEAR_PREALLOC(port, kmsg); + if (!ikm_prealloc_inuse(kmsg)) ipc_kmsg_free(kmsg); - } else { - assert(ikm_prealloc_inuse_port(kmsg) == port); - ikm_prealloc_clear_inuse(kmsg, port); - IP_CLEAR_PREALLOC(port, kmsg); - } } - ip_unlock(port); - /* wakeup any threads waiting on this pool port for an activation */ - if ((thread_pool = &port->ip_thread_pool) != THREAD_POOL_NULL) - thread_pool_wakeup(thread_pool); - /* throw away no-senders request */ nsrequest = port->ip_nsrequest; @@ -694,12 +676,6 @@ ipc_port_destroy( ipc_kobject_destroy(port); - if (port->ip_subsystem != RPC_SUBSYSTEM_NULL) { - subsystem_deallocate((subsystem_t) port->ip_kobject); - } - - /* XXXX Perhaps should verify that ip_thread_pool is empty! */ - ipc_port_release(port); /* consume caller's ref */ } @@ -1352,7 +1328,6 @@ ipc_port_print( ipc_object_print(&port->ip_object); if (ipc_port_print_long) { - iprintf("pool=0x%x", port->ip_thread_pool); printf("\n"); } diff --git a/osfmk/ipc/ipc_port.h b/osfmk/ipc/ipc_port.h index 4231bd026..50bc7ed87 100644 --- a/osfmk/ipc/ipc_port.h +++ b/osfmk/ipc/ipc_port.h @@ -72,7 +72,6 @@ #include #include #include -#include #include #include @@ -115,7 +114,6 @@ struct ipc_port { } data; ipc_kobject_t ip_kobject; - struct rpc_subsystem * ip_subsystem; mach_port_mscount_t ip_mscount; mach_port_rights_t ip_srights; mach_port_rights_t ip_sorights; @@ -155,8 +153,6 @@ struct ipc_port { #define ip_bits ip_object.io_bits #define ip_receiver_name ip_object.io_receiver_name -#define ip_thread_pool ip_object.io_thread_pool - #define ip_receiver data.receiver #define ip_destination data.destination #define ip_timestamp data.timestamp diff --git a/osfmk/ipc/ipc_pset.c b/osfmk/ipc/ipc_pset.c index 01a4cfa55..0befd406c 100644 --- a/osfmk/ipc/ipc_pset.c +++ b/osfmk/ipc/ipc_pset.c @@ -67,7 +67,6 @@ #include #include #include -#include /* * Routine: ipc_pset_alloc @@ -101,9 +100,7 @@ ipc_pset_alloc( /* pset is locked */ pset->ips_local_name = name; - pset->ips_pset_self = pset; ipc_mqueue_init(&pset->ips_messages, TRUE /* set */); - thread_pool_init(&pset->ips_thread_pool); *namep = name; *psetp = pset; @@ -142,9 +139,7 @@ ipc_pset_alloc_name( /* pset is locked */ pset->ips_local_name = name; - pset->ips_pset_self = pset; ipc_mqueue_init(&pset->ips_messages, TRUE /* set */); - thread_pool_init(&pset->ips_thread_pool); *psetp = pset; return KERN_SUCCESS; @@ -173,7 +168,6 @@ ipc_pset_member( * Routine: ipc_pset_add * Purpose: * Puts a port into a port set. - * The port set gains a reference. * Conditions: * Both port and port set are locked and active. * The owner of the port set is also receiver for the port. @@ -184,18 +178,17 @@ ipc_pset_add( ipc_pset_t pset, ipc_port_t port) { + kern_return_t kr; + assert(ips_active(pset)); assert(ip_active(port)); - if (ipc_pset_member(pset, port)) - return KERN_ALREADY_IN_SET; + kr = ipc_mqueue_add(&port->ip_messages, &pset->ips_messages); - ips_reference(pset); - port->ip_pset_count++; + if (kr == KERN_SUCCESS) + port->ip_pset_count++; - ipc_mqueue_add(&port->ip_messages, &pset->ips_messages); - - return KERN_SUCCESS; + return kr; } @@ -215,36 +208,33 @@ ipc_pset_remove( ipc_pset_t pset, ipc_port_t port) { - mach_msg_return_t mr; + kern_return_t kr; assert(ip_active(port)); if (port->ip_pset_count == 0) return KERN_NOT_IN_SET; - mr = ipc_mqueue_remove(&port->ip_messages, &pset->ips_messages); + kr = ipc_mqueue_remove(&port->ip_messages, &pset->ips_messages); - if (mr == MACH_MSG_SUCCESS) { + if (kr == KERN_SUCCESS) port->ip_pset_count--; - ips_release(pset); - } - return mr; + + return kr; } /* - * Routine: ipc_pset_remove_all + * Routine: ipc_pset_remove_from_all * Purpose: * Removes a port from all it's port sets. - * Each port set loses a reference. * Conditions: * port is locked and active. */ kern_return_t -ipc_pset_remove_all( +ipc_pset_remove_from_all( ipc_port_t port) { - ipc_pset_mqueue_t pset_mqueue; ipc_pset_t pset; assert(ip_active(port)); @@ -253,20 +243,10 @@ ipc_pset_remove_all( return KERN_NOT_IN_SET; /* - * Remove each port set's mqueue from the port's (one at a time). + * Remove the port's mqueue from all sets */ - while (port->ip_pset_count > 0) { - ipc_mqueue_remove_one(&port->ip_messages, - (ipc_mqueue_t)&pset_mqueue); - assert(pset_mqueue != (ipc_pset_mqueue_t)0); - port->ip_pset_count--; - - pset = pset_mqueue->ipsm_pset; - ipc_pset_release(pset); /* locks and unlocks pset */ - - } - - assert(port->ip_pset_count == 0); + ipc_mqueue_remove_from_all(&port->ip_messages); + port->ip_pset_count = 0; return KERN_SUCCESS; } @@ -275,9 +255,6 @@ ipc_pset_remove_all( * Routine: ipc_pset_destroy * Purpose: * Destroys a port_set. - * - * Doesn't remove members from the port set; - * that happens lazily. * Conditions: * The port_set is locked and alive. * The caller has a reference, which is consumed. @@ -294,6 +271,11 @@ ipc_pset_destroy( pset->ips_object.io_bits &= ~IO_BITS_ACTIVE; + /* + * remove all the member message queues + */ + ipc_mqueue_remove_all(&pset->ips_messages); + s = splsched(); imq_lock(&pset->ips_messages); ipc_mqueue_changed(&pset->ips_messages); diff --git a/osfmk/ipc/ipc_pset.h b/osfmk/ipc/ipc_pset.h index 0b5b568c3..e673bd8d8 100644 --- a/osfmk/ipc/ipc_pset.h +++ b/osfmk/ipc/ipc_pset.h @@ -65,7 +65,6 @@ #include #include #include -#include #include @@ -75,19 +74,11 @@ typedef struct ipc_pset { * Initial sub-structure in common with all ipc_objects. */ struct ipc_object ips_object; - struct ipc_mqueue ips_messages; - struct ipc_pset *ips_pset_self; /* self (used from ipsm) */ } *ipc_pset_t; -typedef struct ipc_pset_mqueue { - struct ipc_mqueue ipsm_messages; - struct ipc_pset *ipsm_pset; -} *ipc_pset_mqueue_t; - #define ips_references ips_object.io_references #define ips_local_name ips_object.io_receiver_name -#define ips_thread_pool ips_object.io_thread_pool #define IPS_NULL ((ipc_pset_t) IO_NULL) @@ -122,7 +113,7 @@ extern kern_return_t ipc_pset_remove( ipc_port_t port); /* Remove a port from all its current port sets */ -extern kern_return_t ipc_pset_remove_all( +extern kern_return_t ipc_pset_remove_from_all( ipc_port_t port); /* Destroy a port_set */ diff --git a/osfmk/ipc/ipc_right.c b/osfmk/ipc/ipc_right.c index f94bcc903..b2822ebe9 100644 --- a/osfmk/ipc/ipc_right.c +++ b/osfmk/ipc/ipc_right.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002,2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -63,7 +63,6 @@ #include #include #include -#include #include #include #include @@ -657,8 +656,6 @@ ipc_right_destroy( assert(pset != IPS_NULL); entry->ie_object = IO_NULL; - /* port sets are not sharable entries on a subspace basis */ - /* so there is no need to check the subspace array here */ ipc_entry_dealloc(space, name, entry); ips_lock(pset); @@ -717,9 +714,6 @@ ipc_right_destroy( assert(ip_active(port)); assert(port->ip_receiver == space); - if (port->ip_subsystem) - subsystem_deallocate( - port->ip_subsystem->subsystem); ipc_port_clear_receiver(port); ipc_port_destroy(port); /* consumes our ref, unlocks */ } else if (type & MACH_PORT_TYPE_SEND_ONCE) { diff --git a/osfmk/ipc/ipc_space.c b/osfmk/ipc/ipc_space.c index c5b207a22..b51b02999 100644 --- a/osfmk/ipc/ipc_space.c +++ b/osfmk/ipc/ipc_space.c @@ -233,12 +233,8 @@ ipc_space_clean( * out the space died. */ is_write_lock(space); - while (space->is_growing) { - assert_wait((event_t) space, THREAD_UNINT); - is_write_unlock(space); - thread_block((void (*)(void)) 0); - is_write_lock(space); - } + while (space->is_growing) + is_write_sleep(space); /* * Now we can futz with it since we have the write lock. @@ -328,12 +324,8 @@ ipc_space_destroy( * out the space died. */ is_read_lock(space); - while (space->is_growing) { - assert_wait((event_t) space, THREAD_UNINT); - is_read_unlock(space); - thread_block((void (*)(void)) 0); - is_read_lock(space); - } + while (space->is_growing) + is_read_sleep(space); is_read_unlock(space); /* diff --git a/osfmk/ipc/ipc_space.h b/osfmk/ipc/ipc_space.h index 33431cf9b..6ac534951 100644 --- a/osfmk/ipc/ipc_space.h +++ b/osfmk/ipc/ipc_space.h @@ -66,9 +66,13 @@ #include #include +#include + +#ifdef __APPLE_API_PRIVATE #ifdef MACH_KERNEL_PRIVATE #include #include +#include #include #include #include @@ -157,10 +161,16 @@ MACRO_END #define is_read_lock(is) mutex_lock(&(is)->is_lock_data) #define is_read_unlock(is) mutex_unlock(&(is)->is_lock_data) +#define is_read_sleep(is) thread_sleep_mutex((event_t)(is), \ + &(is)->is_lock_data, \ + THREAD_UNINT) #define is_write_lock(is) mutex_lock(&(is)->is_lock_data) #define is_write_lock_try(is) mutex_try(&(is)->is_lock_data) #define is_write_unlock(is) mutex_unlock(&(is)->is_lock_data) +#define is_write_sleep(is) thread_sleep_mutex((event_t)(is), \ + &(is)->is_lock_data, \ + THREAD_UNINT) #define is_reference(is) ipc_space_reference(is) #define is_release(is) ipc_space_release(is) @@ -170,11 +180,29 @@ MACRO_END #define current_space_fast() (current_task_fast()->itk_space) #define current_space() (current_space_fast()) -#else /* !MACH_KERNEL_PRIVATE */ +/* Create a special IPC space */ +extern kern_return_t ipc_space_create_special( + ipc_space_t *spacep); -extern ipc_space_t current_space(void); +/* Create new IPC space */ +extern kern_return_t ipc_space_create( + ipc_table_size_t initial, + ipc_space_t *spacep); + +/* Mark a space as dead and cleans up the entries*/ +extern void ipc_space_destroy( + ipc_space_t space); #endif /* MACH_KERNEL_PRIVATE */ +#endif /* __APPLE_API_PRIVATE */ + +#ifdef __APPLE_API_UNSTABLE +#ifndef MACH_KERNEL_PRIVATE + +extern ipc_space_t current_space(void); + +#endif /* !MACH_KERNEL_PRIVATE */ +#endif /* __APPLE_API_UNSTABLE */ /* Take a reference on a space */ extern void ipc_space_reference( @@ -184,18 +212,4 @@ extern void ipc_space_reference( extern void ipc_space_release( ipc_space_t space); - -/* Create new IPC space */ -extern kern_return_t ipc_space_create( - ipc_table_size_t initial, - ipc_space_t *spacep); - -/* Create a special IPC space */ -extern kern_return_t ipc_space_create_special( - ipc_space_t *spacep); - -/* Mark a space as dead and cleans up the entries*/ -extern void ipc_space_destroy( - ipc_space_t space); - #endif /* _IPC_IPC_SPACE_H_ */ diff --git a/osfmk/ipc/ipc_types.h b/osfmk/ipc/ipc_types.h index cebbc57f7..935d44b9e 100644 --- a/osfmk/ipc/ipc_types.h +++ b/osfmk/ipc/ipc_types.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002,2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -31,7 +31,9 @@ #ifndef _IPC_TYPES_H_ #define _IPC_TYPES_H_ -#ifdef KERNEL_PRIVATE +#include +#include +#include #if !defined(MACH_KERNEL_PRIVATE) @@ -42,27 +44,16 @@ * implementation details. */ struct ipc_object ; -struct ipc_space ; -struct ipc_port ; #endif /* !MACH_KERNEL_PRIVATE */ typedef struct ipc_object *ipc_object_t; -typedef struct ipc_space *ipc_space_t; -typedef struct ipc_port *ipc_port_t; #define IPC_OBJECT_NULL ((ipc_object_t) 0) #define IPC_OBJECT_DEAD ((ipc_object_t)~0) #define IPC_OBJECT_VALID(io) (((io) != IPC_OBJECT_NULL) && \ ((io) != IPC_OBJECT_DEAD)) -#define IPC_PORT_NULL ((ipc_port_t) 0) -#define IPC_PORT_DEAD ((ipc_port_t)~0) -#define IPC_PORT_VALID(port) (((port) != IPC_PORT_NULL) && \ - ((port) != IPC_PORT_DEAD)) - -#define IPC_SPACE_NULL ((ipc_space_t) 0) - -#endif /* KERNEL_PRIVATE */ +typedef void (*mach_msg_continue_t)(mach_msg_return_t); /* after wakeup */ #endif /* _IPC_TYPES_H_ */ diff --git a/osfmk/ipc/mach_msg.c b/osfmk/ipc/mach_msg.c index 4af874090..2e3e11493 100644 --- a/osfmk/ipc/mach_msg.c +++ b/osfmk/ipc/mach_msg.c @@ -118,12 +118,6 @@ mach_msg_return_t msg_receive_error( mach_port_seqno_t seqno, ipc_space_t space); -/* the size of each trailer has to be listed here for copyout purposes */ -mach_msg_trailer_size_t trailer_size[] = { - sizeof(mach_msg_trailer_t), - sizeof(mach_msg_seqno_trailer_t), - sizeof(mach_msg_security_trailer_t) }; - security_token_t KERNEL_SECURITY_TOKEN = KERNEL_SECURITY_TOKEN_VALUE; mach_msg_format_0_trailer_t trailer_template = { @@ -1070,7 +1064,7 @@ mach_msg_overwrite_trap( waitq = &dest_mqueue->imq_wait_queue; imq_lock(dest_mqueue); - wait_queue_peek_locked(waitq, IPC_MQUEUE_RECEIVE, &receiver, &waitq); + wait_queue_peek64_locked(waitq, IPC_MQUEUE_RECEIVE, &receiver, &waitq); /* queue still locked, thread locked - but still on q */ if (receiver == THREAD_NULL) { @@ -1097,7 +1091,7 @@ mach_msg_overwrite_trap( * slow receive for ourselves. Only his RECEIVE_TOO_LARGE handling * runs afoul of that. Clean this up! */ - if ((receiver->state & TH_RUN|TH_WAIT) != TH_WAIT) { + if ((receiver->state & (TH_RUN|TH_WAIT)) != TH_WAIT) { assert(NCPUS > 1); HOT(c_mmot_cold_033++); fall_off: @@ -1123,11 +1117,9 @@ mach_msg_overwrite_trap( /* * Receiver looks okay -- is it swapped in? */ - rpc_lock(receiver); rcv_act = receiver->top_act; if (rcv_act->swap_state != TH_SW_IN && rcv_act->swap_state != TH_SW_UNSWAPPABLE) { - rpc_unlock(receiver); HOT(c_mmot_rcvr_swapped++); goto fall_off; } @@ -1136,7 +1128,6 @@ mach_msg_overwrite_trap( * Make sure receiver stays swapped in (if we can). */ if (!act_lock_try(rcv_act)) { /* out of order! */ - rpc_unlock(receiver); HOT(c_mmot_rcvr_locked++); goto fall_off; } @@ -1151,7 +1142,6 @@ mach_msg_overwrite_trap( rcv_act->swap_state != TH_SW_UNSWAPPABLE) || rcv_act->ast & AST_SWAPOUT) { act_unlock(rcv_act); - rpc_unlock(receiver); HOT(c_mmot_rcvr_tswapped++); goto fall_off; } @@ -1164,7 +1154,6 @@ mach_msg_overwrite_trap( * is consistent. Its task may then be marked for swapout, * but that's life. */ - rpc_unlock(receiver); /* * NB: act_lock(rcv_act) still held */ @@ -1218,10 +1207,12 @@ mach_msg_overwrite_trap( */ { receiver->state &= ~(TH_WAIT|TH_UNINT); + hw_atomic_add(&receiver->processor_set->run_count, 1); receiver->state |= TH_RUN; receiver->wait_result = THREAD_AWAKENED; - receiver->metered_computation = 0; + receiver->computation_metered = 0; + receiver->reason = AST_NONE; } thread_unlock(receiver); @@ -1248,58 +1239,17 @@ mach_msg_overwrite_trap( self->ith_continuation = thread_syscall_return; waitq = &rcv_mqueue->imq_wait_queue; - (void)wait_queue_assert_wait_locked(waitq, + (void)wait_queue_assert_wait64_locked(waitq, IPC_MQUEUE_RECEIVE, THREAD_ABORTSAFE, TRUE); /* unlock? */ /* rcv_mqueue is unlocked */ - /* Inline thread_block_reason (except don't select a new - * new thread (we already have one), and don't turn off ASTs - * (we don't want two threads to hog all the CPU by handing - * off to each other). + /* + * Switch directly to receiving thread, and block + * this thread as though it had called ipc_mqueue_receive. */ - { - if (self->funnel_state & TH_FN_OWNED) { - self->funnel_state = TH_FN_REFUNNEL; - KERNEL_DEBUG(0x603242c | DBG_FUNC_NONE, self->funnel_lock, 3, 0, 0, 0); - funnel_unlock(self->funnel_lock); - - } - - machine_clock_assist(); - - thread_lock(self); - if (self->state & TH_ABORT) - clear_wait_internal(self, THREAD_INTERRUPTED); - thread_unlock(self); - - /* - * Switch directly to receiving thread, and block - * this thread as though it had called ipc_mqueue_receive. - */ -#if defined (__i386__) - thread_run(self, (void (*)(void))0, receiver); -#else - thread_run(self, ipc_mqueue_receive_continue, receiver); -#endif - - /* if we fell thru */ - if (self->funnel_state & TH_FN_REFUNNEL) { - kern_return_t wait_result2; - - wait_result2 = self->wait_result; - self->funnel_state = 0; - KERNEL_DEBUG(0x6032428 | DBG_FUNC_NONE, self->funnel_lock, 6, 0, 0, 0); - funnel_lock(self->funnel_lock); - KERNEL_DEBUG(0x6032430 | DBG_FUNC_NONE, self->funnel_lock, 6, 0, 0, 0); - self->funnel_state = TH_FN_OWNED; - self->wait_result = wait_result2; - } - splx(s); - } - - ipc_mqueue_receive_continue(); + thread_run(self, ipc_mqueue_receive_continue, receiver); /* NOTREACHED */ } @@ -1880,6 +1830,38 @@ mach_msg_overwrite_trap( return MACH_MSG_SUCCESS; } +/* + * Routine: mach_msg_trap [mach trap] + * Purpose: + * Possibly send a message; possibly receive a message. + * Conditions: + * Nothing locked. + * Returns: + * All of mach_msg_send and mach_msg_receive error codes. + */ + +mach_msg_return_t +mach_msg_trap( + mach_msg_header_t *msg, + mach_msg_option_t option, + mach_msg_size_t send_size, + mach_msg_size_t rcv_size, + mach_port_name_t rcv_name, + mach_msg_timeout_t timeout, + mach_port_name_t notify) +{ + return mach_msg_overwrite_trap(msg, + option, + send_size, + rcv_size, + rcv_name, + timeout, + notify, + (mach_msg_header_t *)0, + (mach_msg_size_t)0); +} + + /* * Routine: msg_receive_error [internal] * Purpose: diff --git a/osfmk/ipc/mach_port.c b/osfmk/ipc/mach_port.c index 78afb8353..e2a75b692 100644 --- a/osfmk/ipc/mach_port.c +++ b/osfmk/ipc/mach_port.c @@ -70,7 +70,6 @@ #include #include #include -#include #include #include #include @@ -265,11 +264,20 @@ mach_port_names( kr = vm_map_wire(ipc_kernel_map, addr1, addr1 + size, VM_PROT_READ|VM_PROT_WRITE, FALSE); - assert(kr == KERN_SUCCESS); + if (kr != KERN_SUCCESS) { + kmem_free(ipc_kernel_map, addr1, size); + kmem_free(ipc_kernel_map, addr2, size); + return KERN_RESOURCE_SHORTAGE; + } kr = vm_map_wire(ipc_kernel_map, addr2, addr2 + size, VM_PROT_READ|VM_PROT_WRITE, FALSE); - assert(kr == KERN_SUCCESS); + if (kr != KERN_SUCCESS) { + kmem_free(ipc_kernel_map, addr1, size); + kmem_free(ipc_kernel_map, addr2, size); + return KERN_RESOURCE_SHORTAGE; + } + } /* space is read-locked and active */ @@ -499,7 +507,7 @@ mach_port_allocate_name( if (!MACH_PORT_VALID(name)) return KERN_INVALID_VALUE; - kr = mach_port_allocate_full (space, right, SUBSYSTEM_NULL, + kr = mach_port_allocate_full (space, right, MACH_PORT_NULL, &qos, &name); return (kr); } @@ -531,7 +539,7 @@ mach_port_allocate( kern_return_t kr; mach_port_qos_t qos = qos_template; - kr = mach_port_allocate_full (space, right, SUBSYSTEM_NULL, + kr = mach_port_allocate_full (space, right, MACH_PORT_NULL, &qos, namep); return (kr); } @@ -564,50 +572,13 @@ mach_port_allocate_qos( { kern_return_t kr; - if (qosp->name == TRUE) + if (qosp->name) return KERN_INVALID_ARGUMENT; - kr = mach_port_allocate_full (space, right, SUBSYSTEM_NULL, + kr = mach_port_allocate_full (space, right, MACH_PORT_NULL, qosp, namep); return (kr); } -/* - * Routine: mach_port_allocate_subsystem [kernel call] - * Purpose: - * Allocates a receive right in a space. Like - * mach_port_allocate, except that the caller specifies an - * RPC subsystem that is to be used to implement RPC's to the - * port. When possible, allocate rpc subsystem ports without - * nms, since within RPC ports are intended to be used for - * identity only (i.e. nms is painful in the distributed case - * and we don't need or want it for RPC anyway). - * Conditions: - * Nothing locked. - * Returns: - * KERN_SUCCESS The right is allocated. - * KERN_INVALID_TASK The space is null. - * KERN_INVALID_TASK The space is dead. - * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. - * KERN_NO_SPACE No room in space for another right. - * KERN_INVALID_ARGUMENT bogus subsystem - */ - -kern_return_t -mach_port_allocate_subsystem( - ipc_space_t space, - subsystem_t subsystem, - mach_port_name_t *namep) -{ - kern_return_t kr; - ipc_port_t port; - mach_port_qos_t qos = qos_template; - - kr = mach_port_allocate_full (space, - MACH_PORT_RIGHT_RECEIVE, - subsystem, &qos, namep); - return (kr); -} - /* * Routine: mach_port_allocate_full [kernel call] * Purpose: @@ -631,7 +602,7 @@ kern_return_t mach_port_allocate_full( ipc_space_t space, mach_port_right_t right, - subsystem_t subsystem, + mach_port_t proto, mach_port_qos_t *qosp, mach_port_name_t *namep) { @@ -641,6 +612,9 @@ mach_port_allocate_full( if (space == IS_NULL) return (KERN_INVALID_TASK); + if (proto != MACH_PORT_NULL) + return (KERN_INVALID_VALUE); + if (qosp->name) { if (!MACH_PORT_VALID (*namep)) return (KERN_INVALID_VALUE); @@ -648,11 +622,6 @@ mach_port_allocate_full( return (KERN_FAILURE); } - if (subsystem != SUBSYSTEM_NULL) { - if (right != MACH_PORT_RIGHT_RECEIVE) - return (KERN_INVALID_VALUE); - } - if (qosp->prealloc) { mach_msg_size_t size = qosp->len + MAX_TRAILER_SIZE; if (right != MACH_PORT_RIGHT_RECEIVE) @@ -676,10 +645,6 @@ mach_port_allocate_full( if (qosp->prealloc) ipc_kmsg_set_prealloc(kmsg, port); - if (subsystem != SUBSYSTEM_NULL) { - port->ip_subsystem = &subsystem->user; - subsystem_reference (subsystem); - } ip_unlock(port); } else if (qosp->prealloc) @@ -1269,7 +1234,7 @@ mach_port_move_member( assert(nset != IPS_NULL); } ip_lock(port); - ipc_pset_remove_all(port); + ipc_pset_remove_from_all(port); if (nset != IPS_NULL) { ips_lock(nset); diff --git a/osfmk/kdp/Makefile b/osfmk/kdp/Makefile new file mode 100644 index 000000000..a71bf45c6 --- /dev/null +++ b/osfmk/kdp/Makefile @@ -0,0 +1,33 @@ +export MakeInc_cmd=${SRCROOT}/makedefs/MakeInc.cmd +export MakeInc_def=${SRCROOT}/makedefs/MakeInc.def +export MakeInc_rule=${SRCROOT}/makedefs/MakeInc.rule +export MakeInc_dir=${SRCROOT}/makedefs/MakeInc.dir + + +include $(MakeInc_cmd) +include $(MakeInc_def) + +INSTINC_SUBDIRS = \ + +INSTINC_SUBDIRS_PPC = \ + +INSTINC_SUBDIRS_I386 = \ + +EXPINC_SUBDIRS = \ + +EXPINC_SUBDIRS_PPC = \ + +EXPINC_SUBDIRS_I386 = \ + +DATAFILES = \ + kdp_en_debugger.h + +EXPORT_MI_LIST = ${DATAFILES} + +EXPORT_MI_DIR = kdp + + +include $(MakeInc_rule) +include $(MakeInc_dir) + + diff --git a/osfmk/kdp/kdp.c b/osfmk/kdp/kdp.c index a6e8abc71..2c22fa44c 100644 --- a/osfmk/kdp/kdp.c +++ b/osfmk/kdp/kdp.c @@ -19,12 +19,6 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* - * Copyright (c) 1993 NeXT Computer, Inc. All rights reserved. - * - * kdp.c -- Kernel Debugging Protocol. - * - */ #include #include @@ -32,6 +26,8 @@ #include #include +#include + int kdp_vm_read( caddr_t, caddr_t, unsigned int); int kdp_vm_write( caddr_t, caddr_t, unsigned int); @@ -45,27 +41,48 @@ int kdp_vm_write( caddr_t, caddr_t, unsigned int); #endif static kdp_dispatch_t - dispatch_table[KDP_TERMINATION - KDP_CONNECT + 1] = + dispatch_table[KDP_REATTACH - KDP_CONNECT +1] = { /* 0 */ kdp_connect, /* 1 */ kdp_disconnect, /* 2 */ kdp_hostinfo, -/* 3 */ kdp_regions, +/* 3 */ kdp_version, /* 4 */ kdp_maxbytes, /* 5 */ kdp_readmem, /* 6 */ kdp_writemem, /* 7 */ kdp_readregs, /* 8 */ kdp_writeregs, -/* 9 */ kdp_unknown, -/* A */ kdp_unknown, +/* 9 */ kdp_unknown, +/* A */ kdp_unknown, /* B */ kdp_suspend, /* C */ kdp_resumecpus, /* D */ kdp_unknown, -/* E */ kdp_unknown, +/* E */ kdp_unknown, +/* F */ kdp_breakpoint_set, +/*10 */ kdp_breakpoint_remove, +/*11 */ kdp_regions, +/*12 */ kdp_reattach }; kdp_glob_t kdp; -int kdp_flag=0; + + +#define MAX_BREAKPOINTS 100 +#define KDP_MAX_BREAKPOINTS 100 + +#define BREAKPOINT_NOT_FOUND 101 +#define BREAKPOINT_ALREADY_SET 102 + +#define KDP_VERSION 10 + +typedef struct{ + unsigned int address; + unsigned int old_instruction; +} kdp_breakpoint_record_t; + +static kdp_breakpoint_record_t breakpoint_list[MAX_BREAKPOINTS]; +static unsigned int breakpoints_initialized = 0; +int reattach_wait = 0; boolean_t kdp_packet( @@ -99,7 +116,7 @@ kdp_packet( } req = rd->hdr.request; - if (req < KDP_CONNECT || req > KDP_TERMINATION) { + if ((req < KDP_CONNECT) || (req > KDP_REATTACH)) { printf("kdp_packet bad request %x len %d seq %x key %x\n", rd->hdr.request, rd->hdr.len, rd->hdr.seq, rd->hdr.key); @@ -207,6 +224,23 @@ kdp_disconnect( return (TRUE); } +static boolean_t +kdp_reattach( + kdp_pkt_t *pkt, + int *len, + unsigned short *reply_port +) +{ + kdp_reattach_req_t *rq = &pkt->reattach_req; + kdp_disconnect_reply_t *rp = &pkt->disconnect_reply; + + kdp.is_conn = TRUE; + kdp_disconnect(pkt, len, reply_port); + *reply_port = rq->req_reply_port; + reattach_wait = 1; + return (TRUE); +} + static boolean_t kdp_hostinfo( kdp_pkt_t *pkt, @@ -225,7 +259,7 @@ kdp_hostinfo( rp->hdr.len = sizeof (*rp); kdp_machine_hostinfo(&rp->hostinfo); - + *reply_port = kdp.reply_port; *len = rp->hdr.len; @@ -277,7 +311,7 @@ kdp_resumecpus( rp->hdr.len = sizeof (*rp); dprintf(("kdp_resumecpus %x\n", rq->cpu_mask)); - + kdp.is_halted = FALSE; *reply_port = kdp.reply_port; @@ -383,6 +417,42 @@ kdp_maxbytes( return (TRUE); } +static boolean_t +kdp_version( + kdp_pkt_t *pkt, + int *len, + unsigned short *reply_port +) +{ + kdp_version_req_t *rq = &pkt->version_req; + int plen = *len; + kdp_version_reply_t *rp = &pkt->version_reply; + kdp_region_t *r; + + if (plen < sizeof (*rq)) + return (FALSE); + + rp->hdr.is_reply = 1; + rp->hdr.len = sizeof (*rp); + + dprintf(("kdp_version\n")); + + rp->version = KDP_VERSION; +#ifdef __ppc__ + if (!(kdp_flag & KDP_BP_DIS)) + rp->feature = KDP_FEATURE_BP; + else + rp->feature = 0; +#else + rp->feature = 0; +#endif + + *reply_port = kdp.reply_port; + *len = rp->hdr.len; + + return (TRUE); +} + static boolean_t kdp_regions( kdp_pkt_t *pkt, @@ -472,3 +542,127 @@ kdp_readregs( return (TRUE); } + +static boolean_t +kdp_breakpoint_set( + kdp_pkt_t *pkt, + int *len, + unsigned short *reply_port +) +{ + kdp_breakpoint_req_t *rq = &pkt->breakpoint_req; + kdp_breakpoint_reply_t *rp = &pkt->breakpoint_reply; + int plen = *len; + int cnt, i; + unsigned int old_instruction = 0; + unsigned int breakinstr = kdp_ml_get_breakinsn(); + + if(breakpoints_initialized == 0) + { + for(i=0;(i < MAX_BREAKPOINTS); breakpoint_list[i].address=0, i++); + breakpoints_initialized++; + } + if (plen < sizeof (*rq)) + return (FALSE); + cnt = kdp_vm_read((caddr_t)rq->address, (caddr_t)(&old_instruction), sizeof(int)); + + if (old_instruction==breakinstr) + { + printf("A trap was already set at that address, not setting new breakpoint\n"); + rp->error = BREAKPOINT_ALREADY_SET; + + rp->hdr.is_reply = 1; + rp->hdr.len = sizeof (*rp); + *reply_port = kdp.reply_port; + *len = rp->hdr.len; + + return (TRUE); + } + + for(i=0;(i < MAX_BREAKPOINTS) && (breakpoint_list[i].address != 0); i++); + + if (i == MAX_BREAKPOINTS) + { + rp->error = KDP_MAX_BREAKPOINTS; + + rp->hdr.is_reply = 1; + rp->hdr.len = sizeof (*rp); + *reply_port = kdp.reply_port; + *len = rp->hdr.len; + + return (TRUE); + } + breakpoint_list[i].address = rq->address; + breakpoint_list[i].old_instruction = old_instruction; + + cnt = kdp_vm_write((caddr_t)&breakinstr, (caddr_t)rq->address, sizeof(&breakinstr)); + + rp->error = KDPERR_NO_ERROR; + rp->hdr.is_reply = 1; + rp->hdr.len = sizeof (*rp); + *reply_port = kdp.reply_port; + *len = rp->hdr.len; + + return (TRUE); +} + +static boolean_t +kdp_breakpoint_remove( + kdp_pkt_t *pkt, + int *len, + unsigned short *reply_port +) +{ + kdp_breakpoint_req_t *rq = &pkt->breakpoint_req; + kdp_breakpoint_reply_t *rp = &pkt->breakpoint_reply; + int plen = *len; + int cnt,i; + + if (plen < sizeof (*rq)) + return (FALSE); + + for(i=0;(i < MAX_BREAKPOINTS) && (breakpoint_list[i].address != rq->address); i++); + if (i == MAX_BREAKPOINTS) + { + rp->error = BREAKPOINT_NOT_FOUND; + rp->hdr.is_reply = 1; + rp->hdr.len = sizeof (*rp); + *reply_port = kdp.reply_port; + *len = rp->hdr.len; + + return (TRUE); /* Check if it needs to be FALSE in case of error */ + } + + breakpoint_list[i].address = 0; + cnt = kdp_vm_write((caddr_t)&(breakpoint_list[i].old_instruction), (caddr_t)rq->address, sizeof(int)); + rp->error = KDPERR_NO_ERROR; + rp->hdr.is_reply = 1; + rp->hdr.len = sizeof (*rp); + *reply_port = kdp.reply_port; + *len = rp->hdr.len; + + return (TRUE); +} + +boolean_t +kdp_remove_all_breakpoints() +{ + int i; + boolean_t breakpoint_found = FALSE; + + if (breakpoints_initialized) + { + for(i=0;i < MAX_BREAKPOINTS; i++) + { + if (breakpoint_list[i].address) + { + kdp_vm_write((caddr_t)&(breakpoint_list[i].old_instruction), (caddr_t)breakpoint_list[i].address, sizeof(int)); + breakpoint_found = TRUE; + breakpoint_list[i].address = 0; + } + } + if (breakpoint_found) + printf("kdp_remove_all_breakpoints: found extant breakpoints, removing them.\n"); + } + return breakpoint_found; +} diff --git a/osfmk/kdp/kdp.h b/osfmk/kdp/kdp.h index a13ef5f08..da4991194 100644 --- a/osfmk/kdp/kdp.h +++ b/osfmk/kdp/kdp.h @@ -19,11 +19,9 @@ * * @APPLE_LICENSE_HEADER_END@ */ + /* - * Copyright (c) 1993 NeXT Computer, Inc. All rights reserved. - * - * kdp.h -- exported interface to kdp module - * + * Exported interface to kdp module */ /* Raise exception in debugger. */ diff --git a/osfmk/kdp/kdp_en_debugger.h b/osfmk/kdp/kdp_en_debugger.h index 9edc1069d..6904c399d 100644 --- a/osfmk/kdp/kdp_en_debugger.h +++ b/osfmk/kdp/kdp_en_debugger.h @@ -19,15 +19,9 @@ * * @APPLE_LICENSE_HEADER_END@ */ + /* - * Copyright (c) 1997 Apple Computer, Inc. - * * Ethernet debugger header file - * - * HISTORY - * - * 29 May 97 Dieter Siegmund at Apple. - * Created. */ typedef void (*kdp_send_t)(void * pkt, unsigned int pkt_len); @@ -35,3 +29,7 @@ typedef void (*kdp_receive_t)(void * pkt, unsigned int * pkt_len, unsigned int timeout); void kdp_register_send_receive(kdp_send_t send, kdp_receive_t receive); + +void +kdp_unregister_send_receive(kdp_send_t send, kdp_receive_t receive); + diff --git a/osfmk/kdp/kdp_internal.h b/osfmk/kdp/kdp_internal.h index eedbcd1f0..d3d45b7e7 100644 --- a/osfmk/kdp/kdp_internal.h +++ b/osfmk/kdp/kdp_internal.h @@ -19,11 +19,9 @@ * * @APPLE_LICENSE_HEADER_END@ */ + /* - * Copyright (c) 1993 NeXT Computer, Inc. All rights reserved. - * - * kdp_internal.h -- internal definitions for kdp module - * + * Internal definitions for kdp module */ #include @@ -41,7 +39,12 @@ typedef struct { } kdp_glob_t; extern kdp_glob_t kdp; + extern int kdp_flag; +#define KDP_READY 0x1 +#define KDP_ARP 0x2 +#define KDP_BP_DIS 0x4 + typedef boolean_t (*kdp_dispatch_t) ( @@ -57,6 +60,9 @@ kdp_packet( unsigned short * ); +boolean_t +kdp_remove_all_breakpoints (); + void kdp_exception( unsigned char *, @@ -129,4 +135,3 @@ kdp_sync_cache( void ); - diff --git a/osfmk/kdp/kdp_private.h b/osfmk/kdp/kdp_private.h index 021758873..e9399002a 100644 --- a/osfmk/kdp/kdp_private.h +++ b/osfmk/kdp/kdp_private.h @@ -19,11 +19,9 @@ * * @APPLE_LICENSE_HEADER_END@ */ + /* - * Copyright (c) 1993 NeXT Computer, Inc. All rights reserved. - * - * kdp_private.h -- private functions for kdp.c - * + * Private functions for kdp.c */ static boolean_t @@ -47,6 +45,13 @@ kdp_disconnect( unsigned short * ); +static boolean_t +kdp_reattach( + kdp_pkt_t *, + int *, + unsigned short * +); + static boolean_t kdp_hostinfo( kdp_pkt_t *, @@ -75,6 +80,13 @@ kdp_writeregs( unsigned short * ); +static boolean_t +kdp_version( + kdp_pkt_t *, + int *, + unsigned short * +); + static boolean_t kdp_regions( kdp_pkt_t *, @@ -110,3 +122,17 @@ kdp_resumecpus( unsigned short * ); +static boolean_t +kdp_breakpoint_set( + kdp_pkt_t *, + int *, + unsigned short *t +); + +static boolean_t +kdp_breakpoint_remove( + kdp_pkt_t *, + int *, + unsigned short * +); + diff --git a/osfmk/kdp/kdp_protocol.h b/osfmk/kdp/kdp_protocol.h index 31fe7a3f5..8768c9c87 100644 --- a/osfmk/kdp/kdp_protocol.h +++ b/osfmk/kdp/kdp_protocol.h @@ -19,15 +19,9 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* Copyright (c) 1991 by NeXT Computer, Inc. - * - * File: services/kdp.h - * - * Definition of remote debugger protocol. - * - * HISTORY - * 27-Oct-91 Mike DeMoney (mike@next.com) - * Created + +/* + * Definition of remote debugger protocol. */ #include @@ -71,7 +65,7 @@ typedef enum { KDP_CONNECT, KDP_DISCONNECT, /* obtaining client info */ - KDP_HOSTINFO, KDP_REGIONS, KDP_MAXBYTES, + KDP_HOSTINFO, KDP_VERSION, KDP_MAXBYTES, /* memory access */ KDP_READMEM, KDP_WRITEMEM, @@ -88,6 +82,15 @@ typedef enum { /* exception and termination notification, NOT true requests */ KDP_EXCEPTION, KDP_TERMINATION, + /* breakpoint control */ + KDP_BREAKPOINT_SET, KDP_BREAKPOINT_REMOVE, + + /* vm regions */ + KDP_REGIONS, + + /* reattach to a connected host */ + KDP_REATTACH, + /* remote reboot request */ KDP_HOSTREBOOT } kdp_req_t; @@ -143,6 +146,14 @@ typedef struct { /* KDP_DISCONNECT reply */ kdp_hdr_t hdr; } kdp_disconnect_reply_t; +/* + * KDP_REATTACH + */ +typedef struct { + kdp_hdr_t hdr; + unsigned short req_reply_port; /* udp port which to send replies */ +} kdp_reattach_req_t; + /* * KDP_HOSTINFO */ @@ -161,6 +172,23 @@ typedef struct { /* KDP_HOSTINFO reply */ kdp_hostinfo_t hostinfo; } kdp_hostinfo_reply_t; +/* + * KDP_VERSION + */ +typedef struct { /* KDP_VERSION request */ + kdp_hdr_t hdr; +} kdp_version_req_t; + +#define KDP_FEATURE_BP 0x1 /* local breakpoint support */ + +typedef struct { /* KDP_REGIONS reply */ + kdp_hdr_t hdr; + unsigned version; + unsigned feature; + unsigned pad0; + unsigned pad1; +} kdp_version_reply_t; + /* * KDP_REGIONS */ @@ -303,6 +331,16 @@ typedef struct { /* KDP_RESUMECPUS reply */ kdp_hdr_t hdr; } kdp_resumecpus_reply_t; +typedef struct { + kdp_hdr_t hdr; + unsigned long address; +} kdp_breakpoint_req_t; + +typedef struct { + kdp_hdr_t hdr; + kdp_error_t error; +} kdp_breakpoint_reply_t; + /* * Exception notifications * (Exception notifications are not requests, and in fact travel from @@ -358,8 +396,8 @@ typedef union { kdp_disconnect_reply_t disconnect_reply; kdp_hostinfo_req_t hostinfo_req; kdp_hostinfo_reply_t hostinfo_reply; - kdp_regions_req_t regions_req; - kdp_regions_reply_t regions_reply; + kdp_version_req_t version_req; + kdp_version_reply_t version_reply; kdp_maxbytes_req_t maxbytes_req; kdp_maxbytes_reply_t maxbytes_reply; kdp_readmem_req_t readmem_req; @@ -382,6 +420,11 @@ typedef union { kdp_exception_ack_t exception_ack; kdp_termination_t termination; kdp_termination_ack_t termination_ack; + kdp_breakpoint_req_t breakpoint_req; + kdp_breakpoint_reply_t breakpoint_reply; + kdp_reattach_req_t reattach_req; + kdp_regions_req_t regions_req; + kdp_regions_reply_t regions_reply; } kdp_pkt_t; #define MAX_KDP_PKT_SIZE 1200 /* max packet size */ diff --git a/osfmk/kdp/kdp_udp.c b/osfmk/kdp/kdp_udp.c index 15b416c3d..78b33b16d 100644 --- a/osfmk/kdp/kdp_udp.c +++ b/osfmk/kdp/kdp_udp.c @@ -20,16 +20,19 @@ * @APPLE_LICENSE_HEADER_END@ */ /* - * Copyright (c) 1993 NeXT Computer, Inc. All rights reserved. - * - * kdp_udp.c -- Kernel Debugging Protocol UDP implementation. - * + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + */ + +/* + * Kernel Debugging Protocol UDP implementation. */ #include #include #include #include +#include #include #include @@ -39,9 +42,9 @@ #define DO_ALIGN 1 /* align all packet data accesses */ extern int kdp_getc(void); +extern int reattach_wait; -static -u_short ip_id; /* ip packet ctr, for ids */ +static u_short ip_id; /* ip packet ctr, for ids */ /* @(#)udp_usrreq.c 2.2 88/05/23 4.0NFSSRC SMI; from UCB 7.1 6/5/86 */ @@ -81,18 +84,32 @@ static char "Breakpoint" /* EXC_BREAKPOINT */ }; +int kdp_flag = 0; + static kdp_send_t kdp_en_send_pkt = 0; static kdp_receive_t kdp_en_recv_pkt = 0; + +static unsigned int kdp_current_ip_address = 0; +static struct ether_addr kdp_current_mac_address = {{0, 0, 0, 0, 0, 0}}; +static char kdp_arp_init = 0; + static void kdp_handler( void *); void -kdp_register_send_receive(kdp_send_t send, kdp_receive_t receive) +kdp_register_send_receive( + kdp_send_t send, + kdp_receive_t receive) { -#define KDP_READY 0x1 + unsigned int debug; kdp_en_send_pkt = send; kdp_en_recv_pkt = receive; + debug_log_init(); + PE_parse_boot_arg("debug", &debug); + if (debug & DB_KDP_BP_DIS) + kdp_flag |= KDP_BP_DIS; + kdp_flag |= KDP_READY; if (current_debugger == NO_CUR_DB) current_debugger = KDP_CUR_DB; @@ -102,21 +119,31 @@ kdp_register_send_receive(kdp_send_t send, kdp_receive_t receive) } } -static void +kdp_unregister_send_receive( + kdp_send_t send, + kdp_receive_t receive) +{ + if (current_debugger == KDP_CUR_DB) + current_debugger = NO_CUR_DB; + kdp_flag &= ~KDP_READY; + kdp_en_send_pkt = NULL; + kdp_en_recv_pkt = NULL; +} + +static void enaddr_copy( - void *src, - void *dst + void *src, + void *dst ) { - bcopy((char *)src, (char *)dst, sizeof (struct ether_addr)); + bcopy((char *)src, (char *)dst, sizeof (struct ether_addr)); } -static -unsigned short +static unsigned short ip_sum( - unsigned char *c, - unsigned int hlen + unsigned char *c, + unsigned int hlen ) { unsigned int high, low, sum; @@ -135,10 +162,9 @@ ip_sum( return (sum > 65535 ? sum - 65535 : sum); } -static -void +static void kdp_reply( - unsigned short reply_port + unsigned short reply_port ) { struct udpiphdr aligned_ui, *ui = &aligned_ui; @@ -207,8 +233,7 @@ kdp_reply( exception_seq++; } -static -void +static void kdp_send( unsigned short remote_port ) @@ -264,20 +289,100 @@ kdp_send( eh->ether_type = htons(ETHERTYPE_IP); pkt.len += sizeof (struct ether_header); - (*kdp_en_send_pkt)(&pkt.data[pkt.off], pkt.len); } -static -void -kdp_poll( - void -) + +void +kdp_set_ip_and_mac_addresses( + struct in_addr *ipaddr, + struct ether_addr *macaddr) { - struct ether_header *eh; - struct udpiphdr aligned_ui, *ui = &aligned_ui; - struct ip aligned_ip, *ip = &aligned_ip; - static int msg_printed; + unsigned int debug = 0; + + kdp_current_ip_address = ipaddr->s_addr; + kdp_current_mac_address = *macaddr; + + /* Get the debug boot-arg to decide if ARP replies are allowed */ + if (kdp_arp_init == 0) { + PE_parse_boot_arg("debug", &debug); + if (debug & DB_ARP) + kdp_flag |= KDP_ARP; + kdp_arp_init = 1; + } +} + +struct ether_addr +kdp_get_mac_addr(void) +{ + return kdp_current_mac_address; +} + +unsigned int +kdp_get_ip_address(void) +{ + return kdp_current_ip_address; +} + +/* ARP responses are enabled when the DB_ARP bit of the debug boot arg + is set. A workaround if you don't want to reboot is to set + kdpDEBUGFlag &= DB_ARP when connected (but that certainly isn't a published + interface!) +*/ + +static void +kdp_arp_reply(void) +{ + struct ether_header *eh; + struct ether_arp aligned_ea, *ea = &aligned_ea; + + struct in_addr isaddr, itaddr, myaddr; + struct ether_addr my_enaddr; + + eh = (struct ether_header *)&pkt.data[pkt.off]; + pkt.off += sizeof(struct ether_header); + + memcpy((void *)ea, (void *)&pkt.data[pkt.off],sizeof(*ea)); + + if(ntohs(ea->arp_op) != ARPOP_REQUEST) + return; + + myaddr.s_addr = kdp_get_ip_address(); + my_enaddr = kdp_get_mac_addr(); + + if (!(myaddr.s_addr) || !(my_enaddr.ether_addr_octet[1])) + return; + + (void)memcpy((void *)&isaddr, (void *)ea->arp_spa, sizeof (isaddr)); + (void)memcpy((void *)&itaddr, (void *)ea->arp_tpa, sizeof (itaddr)); + + if (itaddr.s_addr == myaddr.s_addr) { + (void)memcpy((void *)ea->arp_tha, (void *)ea->arp_sha, sizeof(ea->arp_sha)); + (void)memcpy((void *)ea->arp_sha, (void *)&my_enaddr, sizeof(ea->arp_sha)); + + (void)memcpy((void *)ea->arp_tpa, (void *) ea->arp_spa, sizeof(ea->arp_spa)); + (void)memcpy((void *)ea->arp_spa, (void *) &itaddr, sizeof(ea->arp_spa)); + + ea->arp_op = htons(ARPOP_REPLY); + ea->arp_pro = htons(ETHERTYPE_IP); + (void)memcpy(eh->ether_dhost, ea->arp_tha, sizeof(eh->ether_dhost)); + (void)memcpy(eh->ether_shost, &my_enaddr, sizeof(eh->ether_shost)); + eh->ether_type = htons(ETHERTYPE_ARP); + (void)memcpy(&pkt.data[pkt.off], ea, sizeof(*ea)); + pkt.off -= sizeof (struct ether_header); + /* pkt.len is still the length we want, ether_header+ether_arp */ + (*kdp_en_send_pkt)(&pkt.data[pkt.off], pkt.len); + } +} + +static void +kdp_poll(void) +{ + struct ether_header *eh; + struct udpiphdr aligned_ui, *ui = &aligned_ui; + struct ip aligned_ip, *ip = &aligned_ip; + static int msg_printed; + if (pkt.input) kdp_panic("kdp_poll"); @@ -290,16 +395,29 @@ kdp_poll( return; } - pkt.off = 0; + pkt.off = pkt.len = 0; (*kdp_en_recv_pkt)(pkt.data, &pkt.len, 3/* ms */); - + if (pkt.len == 0) return; - + + if (pkt.len >= sizeof(struct ether_header)) + { + eh = (struct ether_header *)&pkt.data[pkt.off]; + + if (kdp_flag & KDP_ARP) + { + if (ntohs(eh->ether_type) == ETHERTYPE_ARP) + { + kdp_arp_reply(); + return; + } + } + } + if (pkt.len < (sizeof (struct ether_header) + sizeof (struct udpiphdr))) return; - - eh = (struct ether_header *)&pkt.data[pkt.off]; + pkt.off += sizeof (struct ether_header); if (ntohs(eh->ether_type) != ETHERTYPE_IP) { return; @@ -342,10 +460,9 @@ kdp_poll( } -static -void +static void kdp_handler( - void *saved_state + void *saved_state ) { unsigned short reply_port; @@ -369,6 +486,9 @@ kdp_handler( goto again; } + if (hdr->request == KDP_REATTACH) + exception_seq = hdr->seq; + // check for retransmitted request if (hdr->seq == (exception_seq - 1)) { /* retransmit last reply */ @@ -392,29 +512,48 @@ again: } while (kdp.is_halted); } -static -void -kdp_connection_wait( - void -) +static void +kdp_connection_wait(void) { unsigned short reply_port; boolean_t kdp_call_kdb(); - + struct ether_addr kdp_mac_addr = kdp_get_mac_addr(); + unsigned int ip_addr = kdp_get_ip_address(); + + printf( "ethernet MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", + kdp_mac_addr.ether_addr_octet[0] & 0xff, + kdp_mac_addr.ether_addr_octet[1] & 0xff, + kdp_mac_addr.ether_addr_octet[2] & 0xff, + kdp_mac_addr.ether_addr_octet[3] & 0xff, + kdp_mac_addr.ether_addr_octet[4] & 0xff, + kdp_mac_addr.ether_addr_octet[5] & 0xff); + + printf( "ip address: %d.%d.%d.%d\n", + (ip_addr & 0xff000000) >> 24, + (ip_addr & 0xff0000) >> 16, + (ip_addr & 0xff00) >> 8, + (ip_addr & 0xff)); + printf("\nWaiting for remote debugger connection.\n"); + + if (reattach_wait == 0) + { #ifdef MACH_PE - if( 0 != kdp_getc()) + if( 0 != kdp_getc()) #endif - { - printf("Options..... Type\n"); - printf("------------ ----\n"); - printf("continue.... 'c'\n"); - printf("reboot...... 'r'\n"); + { + printf("Options..... Type\n"); + printf("------------ ----\n"); + printf("continue.... 'c'\n"); + printf("reboot...... 'r'\n"); #if MACH_KDB - printf("enter kdb... 'k'\n"); + printf("enter kdb... 'k'\n"); #endif - } - + } + } + else + reattach_wait = 0; + exception_seq = 0; do { kdp_hdr_t aligned_hdr, *hdr = &aligned_hdr; @@ -454,12 +593,18 @@ kdp_connection_wait( kdp_reboot(); /* should not return! */ } - if ((hdr->request == KDP_CONNECT) && + if (((hdr->request == KDP_CONNECT) || (hdr->request == KDP_REATTACH)) && !hdr->is_reply && (hdr->seq == exception_seq)) { if (kdp_packet((unsigned char *)&pkt.data[pkt.off], (int *)&pkt.len, (unsigned short *)&reply_port)) kdp_reply(reply_port); + if (hdr->request == KDP_REATTACH) + { + reattach_wait = 0; + hdr->request=KDP_DISCONNECT; + exception_seq = 0; + } } pkt.input = FALSE; @@ -470,8 +615,7 @@ kdp_connection_wait( printf("Connected to remote debugger.\n"); } -static -void +static void kdp_send_exception( unsigned int exception, unsigned int code, @@ -479,9 +623,9 @@ kdp_send_exception( ) { unsigned short remote_port; - unsigned int timeout_count; + unsigned int timeout_count = 100; + unsigned int poll_timeout; - timeout_count = 300; // should be about 30 seconds do { pkt.off = sizeof (struct ether_header) + sizeof (struct udpiphdr); kdp_exception((unsigned char *)&pkt.data[pkt.off], @@ -490,30 +634,34 @@ kdp_send_exception( (unsigned int)exception, (unsigned int)code, (unsigned int)subcode); - + kdp_send(remote_port); -again: - kdp_poll(); - + poll_timeout = 50; + while(!pkt.input && poll_timeout) + { + kdp_poll(); + poll_timeout--; + } + if (pkt.input) { if (!kdp_exception_ack(&pkt.data[pkt.off], pkt.len)) { pkt.input = FALSE; - goto again; } - } else { - pkt.input = FALSE; - goto again; } + pkt.input = FALSE; + if (kdp.exception_ack_needed) - kdp_us_spin(100000); // 1/10 sec + kdp_us_spin(250000); } while (kdp.exception_ack_needed && timeout_count--); if (kdp.exception_ack_needed) { // give up & disconnect printf("kdp: exception ack timeout\n"); + if (current_debugger == KDP_CUR_DB) + active_debugger=0; kdp_reset(); } } @@ -526,9 +674,10 @@ kdp_raise_exception( void *saved_state ) { - int s; int index; + disable_preemption(); + if (saved_state == 0) printf("kdp_raise_exception with NULL state\n"); @@ -551,27 +700,43 @@ kdp_raise_exception( if (pkt.input) kdp_panic("kdp_raise_exception"); - + again: if (!kdp.is_conn) kdp_connection_wait(); else + { kdp_send_exception(exception, code, subcode); + if (kdp.exception_ack_needed) + { + kdp.exception_ack_needed = FALSE; + kdp_remove_all_breakpoints(); + printf("Remote debugger disconnected.\n"); + } + } if (kdp.is_conn) { kdp.is_halted = TRUE; /* XXX */ kdp_handler(saved_state); if (!kdp.is_conn) + { + kdp_remove_all_breakpoints(); printf("Remote debugger disconnected.\n"); + } } kdp_sync_cache(); + + if (reattach_wait == 1) + goto again; + + enable_preemption(); } void kdp_reset(void) { - kdp.reply_port = kdp.exception_port = 0; - kdp.is_halted = kdp.is_conn = FALSE; - kdp.exception_seq = kdp.conn_seq = 0; + kdp.reply_port = kdp.exception_port = 0; + kdp.is_halted = kdp.is_conn = FALSE; + kdp.exception_seq = kdp.conn_seq = 0; } diff --git a/osfmk/kdp/kdp_udp.h b/osfmk/kdp/kdp_udp.h index f8db005d4..ce34cde00 100644 --- a/osfmk/kdp/kdp_udp.h +++ b/osfmk/kdp/kdp_udp.h @@ -19,7 +19,12 @@ * * @APPLE_LICENSE_HEADER_END@ */ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + */ +#include #include /* OSSwap functions */ #define ETHERMTU 1500 @@ -37,6 +42,9 @@ struct ether_addr { typedef struct ether_addr enet_addr_t; +extern struct ether_addr kdp_get_mac_addr(void); +unsigned int kdp_get_ip_address(void); + struct ipovly { caddr_t ih_next, ih_prev; /* for protocol sequence q's */ u_char ih_x1; /* (unused) */ @@ -118,3 +126,44 @@ typedef struct ether_header ether_header_t; #define ntohs(x) OSSwapBigToHostInt16(x) #define htons(x) OSSwapHostToBigInt16(x) + +/* + * 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. + */ + +#define ETHERTYPE_ARP 0x0806 /* Addr. resolution protocol */ + +struct arphdr { + u_short ar_hrd; /* format of hardware address */ +#define ARPHRD_ETHER 1 /* ethernet hardware format */ +#define ARPHRD_FRELAY 15 /* frame relay hardware format */ + 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 */ +#define ARPOP_REVREQUEST 3 /* request protocol address given hardware */ +#define ARPOP_REVREPLY 4 /* response giving protocol address */ +#define ARPOP_INVREQUEST 8 /* request to identify peer */ +#define ARPOP_INVREPLY 9 /* response identifying peer */ +}; + +#define ETHER_ADDR_LEN 6 + +struct ether_arp { + struct arphdr ea_hdr; /* fixed-size header */ + u_char arp_sha[ETHER_ADDR_LEN]; /* sender hardware address */ + u_char arp_spa[4]; /* sender protocol address */ + u_char arp_tha[ETHER_ADDR_LEN]; /* 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 diff --git a/osfmk/kdp/ml/i386/kdp_machdep.c b/osfmk/kdp/ml/i386/kdp_machdep.c index 77182fb97..b5990a653 100644 --- a/osfmk/kdp/ml/i386/kdp_machdep.c +++ b/osfmk/kdp/ml/i386/kdp_machdep.c @@ -19,17 +19,6 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* - * Copyright (c) 1997 Apple Computer, Inc. All rights reserved. - * Copyright (c) 1994 NeXT Computer, Inc. All rights reserved. - * - * machdep/ppc/kdp_machdep.c - * - * Machine-dependent code for Remote Debugging Protocol - * - * March, 1997 Created. Umesh Vaishampayan [umeshv@NeXT.com] - * - */ #include #include @@ -427,7 +416,7 @@ kdp_i386_trap( break; } -// kdp_i386_backtrace((void *) saved_state->ebp, 10); + kdp_i386_backtrace((void *) saved_state->ebp, 10); kdp_raise_exception(exception, code, subcode, saved_state); } @@ -438,3 +427,8 @@ kdp_call_kdb( { return(FALSE); } + +unsigned int kdp_ml_get_breakinsn() +{ + return 0xcc; +} diff --git a/osfmk/kdp/ml/i386/kdp_vm.c b/osfmk/kdp/ml/i386/kdp_vm.c index 2d870d71a..c5315aea0 100644 --- a/osfmk/kdp/ml/i386/kdp_vm.c +++ b/osfmk/kdp/ml/i386/kdp_vm.c @@ -22,6 +22,7 @@ #include #include #include +#include unsigned kdp_vm_read( caddr_t, caddr_t, unsigned); unsigned kdp_vm_write( caddr_t, caddr_t, unsigned); diff --git a/osfmk/kdp/ml/ppc/kdp_asm.s b/osfmk/kdp/ml/ppc/kdp_asm.s index 4f1ecd207..c01b2e5de 100644 --- a/osfmk/kdp/ml/ppc/kdp_asm.s +++ b/osfmk/kdp/ml/ppc/kdp_asm.s @@ -41,7 +41,10 @@ ENTRY(kdp_call_with_ctx, TAG_NO_FRAME_USED) mfmsr r7 /* Get the MSR */ mflr r0 rlwinm r7,r7,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Turn off interruptions enable bit */ + rlwinm r7,r7,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r7,r7,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off mtmsr r7 + isync ; Need this because we may have ditched fp/vec mfsprg r8,0 /* Get the per_proc block address */ stw r0, FM_LR_SAVE(r1) /* save lr in the current frame */ @@ -69,7 +72,10 @@ ENTRY(kdp_call_with_ctx, TAG_NO_FRAME_USED) mfmsr r0 /* Get the MSR */ addi r1, r1, FM_SIZE rlwinm r0,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Turn off interruptions enable bit */ + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off mtmsr r0 + isync ; Need this because we may have ditched fp/vec mfsprg r8,0 /* Get the per_proc block address */ diff --git a/osfmk/kdp/ml/ppc/kdp_machdep.c b/osfmk/kdp/ml/ppc/kdp_machdep.c index f84e6a832..d315e6a91 100644 --- a/osfmk/kdp/ml/ppc/kdp_machdep.c +++ b/osfmk/kdp/ml/ppc/kdp_machdep.c @@ -19,17 +19,6 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* - * Copyright (c) 1997 Apple Computer, Inc. All rights reserved. - * Copyright (c) 1994 NeXT Computer, Inc. All rights reserved. - * - * machdep/ppc/kdp_machdep.c - * - * Machine-dependent code for Remote Debugging Protocol - * - * March, 1997 Created. Umesh Vaishampayan [umeshv@NeXT.com] - * - */ #include #include @@ -48,7 +37,7 @@ void print_saved_state(void *); void kdp_call(void); -void kdp_trap( unsigned int, struct ppc_thread_state *); +void kdp_trap( unsigned int, struct savearea *saved_state); int kdp_getc(void); boolean_t kdp_call_kdb(void); @@ -122,51 +111,50 @@ kdp_getintegerstate( struct ppc_thread_state *state ) { - struct ppc_thread_state *saved_state; + struct savearea *saved_state; saved_state = kdp.saved_state; bzero((char *)state,sizeof (struct ppc_thread_state)) ; - state->srr0 = saved_state->srr0; - state->srr1 = saved_state->srr1; - state->r0 = saved_state->r0; - state->r1 = saved_state->r1; - state->r2 = saved_state->r2; - state->r3 = saved_state->r3; - state->r4 = saved_state->r4; - state->r5 = saved_state->r5; - state->r6 = saved_state->r6; - state->r7 = saved_state->r7; - state->r8 = saved_state->r8; - state->r9 = saved_state->r9; - state->r10 = saved_state->r10; - state->r11 = saved_state->r11; - state->r12 = saved_state->r12; - state->r13 = saved_state->r13; - state->r14 = saved_state->r14; - state->r15 = saved_state->r15; - state->r16 = saved_state->r16; - state->r17 = saved_state->r17; - state->r18 = saved_state->r18; - state->r19 = saved_state->r19; - state->r20 = saved_state->r20; - state->r21 = saved_state->r21; - state->r22 = saved_state->r22; - state->r23 = saved_state->r23; - state->r24 = saved_state->r24; - state->r25 = saved_state->r25; - state->r26 = saved_state->r26; - state->r27 = saved_state->r27; - state->r28 = saved_state->r28; - state->r29 = saved_state->r29; - state->r30 = saved_state->r30; - state->r31 = saved_state->r31; - state->cr = saved_state->cr; - state->xer = saved_state->xer; - state->lr = saved_state->lr; - state->ctr = saved_state->ctr; - state->mq = saved_state->mq; /* This is BOGUS ! (601) ONLY */ + state->srr0 = saved_state->save_srr0; + state->srr1 = saved_state->save_srr1; + state->r0 = saved_state->save_r0; + state->r1 = saved_state->save_r1; + state->r2 = saved_state->save_r2; + state->r3 = saved_state->save_r3; + state->r4 = saved_state->save_r4; + state->r5 = saved_state->save_r5; + state->r6 = saved_state->save_r6; + state->r7 = saved_state->save_r7; + state->r8 = saved_state->save_r8; + state->r9 = saved_state->save_r9; + state->r10 = saved_state->save_r10; + state->r11 = saved_state->save_r11; + state->r12 = saved_state->save_r12; + state->r13 = saved_state->save_r13; + state->r14 = saved_state->save_r14; + state->r15 = saved_state->save_r15; + state->r16 = saved_state->save_r16; + state->r17 = saved_state->save_r17; + state->r18 = saved_state->save_r18; + state->r19 = saved_state->save_r19; + state->r20 = saved_state->save_r20; + state->r21 = saved_state->save_r21; + state->r22 = saved_state->save_r22; + state->r23 = saved_state->save_r23; + state->r24 = saved_state->save_r24; + state->r25 = saved_state->save_r25; + state->r26 = saved_state->save_r26; + state->r27 = saved_state->save_r27; + state->r28 = saved_state->save_r28; + state->r29 = saved_state->save_r29; + state->r30 = saved_state->save_r30; + state->r31 = saved_state->save_r31; + state->cr = saved_state->save_cr; + state->xer = saved_state->save_xer; + state->lr = saved_state->save_lr; + state->ctr = saved_state->save_ctr; } kdp_error_t @@ -202,49 +190,48 @@ kdp_setintegerstate( struct ppc_thread_state *state ) { - struct ppc_thread_state *saved_state; + struct savearea *saved_state; saved_state = kdp.saved_state; - saved_state->srr0 = state->srr0; - saved_state->srr1 = state->srr1; - saved_state->r0 = state->r0; - saved_state->r1 = state->r1; - saved_state->r2 = state->r2; - saved_state->r3 = state->r3; - saved_state->r4 = state->r4; - saved_state->r5 = state->r5; - saved_state->r6 = state->r6; - saved_state->r7 = state->r7; - saved_state->r8 = state->r8; - saved_state->r9 = state->r9; - saved_state->r10 = state->r10; - saved_state->r11 = state->r11; - saved_state->r12 = state->r12; - saved_state->r13 = state->r13; - saved_state->r14 = state->r14; - saved_state->r15 = state->r15; - saved_state->r16 = state->r16; - saved_state->r17 = state->r17; - saved_state->r18 = state->r18; - saved_state->r19 = state->r19; - saved_state->r20 = state->r20; - saved_state->r21 = state->r21; - saved_state->r22 = state->r22; - saved_state->r23 = state->r23; - saved_state->r24 = state->r24; - saved_state->r25 = state->r25; - saved_state->r26 = state->r26; - saved_state->r27 = state->r27; - saved_state->r28 = state->r28; - saved_state->r29 = state->r29; - saved_state->r30 = state->r30; - saved_state->r31 = state->r31; - saved_state->cr = state->cr; - saved_state->xer = state->xer; - saved_state->lr = state->lr; - saved_state->ctr = state->ctr; - saved_state->mq = state->mq; /* BOGUS! (601)ONLY */ + saved_state->save_srr0 = state->srr0; + saved_state->save_srr1 = state->srr1; + saved_state->save_r0 = state->r0; + saved_state->save_r1 = state->r1; + saved_state->save_r2 = state->r2; + saved_state->save_r3 = state->r3; + saved_state->save_r4 = state->r4; + saved_state->save_r5 = state->r5; + saved_state->save_r6 = state->r6; + saved_state->save_r7 = state->r7; + saved_state->save_r8 = state->r8; + saved_state->save_r9 = state->r9; + saved_state->save_r10 = state->r10; + saved_state->save_r11 = state->r11; + saved_state->save_r12 = state->r12; + saved_state->save_r13 = state->r13; + saved_state->save_r14 = state->r14; + saved_state->save_r15 = state->r15; + saved_state->save_r16 = state->r16; + saved_state->save_r17 = state->r17; + saved_state->save_r18 = state->r18; + saved_state->save_r19 = state->r19; + saved_state->save_r20 = state->r20; + saved_state->save_r21 = state->r21; + saved_state->save_r22 = state->r22; + saved_state->save_r23 = state->r23; + saved_state->save_r24 = state->r24; + saved_state->save_r25 = state->r25; + saved_state->save_r26 = state->r26; + saved_state->save_r27 = state->r27; + saved_state->save_r28 = state->r28; + saved_state->save_r29 = state->r29; + saved_state->save_r30 = state->r30; + saved_state->save_r31 = state->r31; + saved_state->save_cr = state->cr; + saved_state->save_xer = state->xer; + saved_state->save_lr = state->lr; + saved_state->save_ctr = state->ctr; } kdp_error_t @@ -427,20 +414,17 @@ int kdp_noisy; void kdp_trap( unsigned int exception, - struct ppc_thread_state *saved_state + struct savearea *saved_state ) { unsigned int *fp; - unsigned int register sp; - struct ppc_thread_state *state; + unsigned int register sp; + struct savearea *state; if (kdp_noisy) { if (kdp_backtrace) { printf("\nvector=%x, \n", exception/4); -#ifdef XXX - regDump(saved_state); -#endif - sp = saved_state->r1; + sp = saved_state->save_r1; printf("stack backtrace - sp(%x) ", sp); fp = (unsigned int *) *((unsigned int *)sp); while (fp) { @@ -455,23 +439,21 @@ kdp_trap( } #endif - printf("vector=%d ", exception/4); + printf("vector=%d ", exception/4); } - kdp_raise_exception(kdp_code(exception), 0, 0, saved_state); if (kdp_noisy) printf("kdp_trap: kdp_raise_exception() ret\n"); - if (*((int *)saved_state->srr0) == 0x7c800008) - saved_state->srr0 += 4; /* BKPT_SIZE */ - - if(saved_state->srr1 & (MASK(MSR_SE) | MASK(MSR_BE))) { /* Are we just stepping or continuing */ + if (*((int *)saved_state->save_srr0) == 0x7c800008) + saved_state->save_srr0 += 4; /* BKPT_SIZE */ + + if(saved_state->save_srr1 & (MASK(MSR_SE) | MASK(MSR_BE))) { /* Are we just stepping or continuing */ db_run_mode = STEP_ONCE; /* We are stepping */ } else db_run_mode = STEP_CONTINUE; /* Otherwise we are continuing */ - - + #ifdef XXX mtspr(dabr, kdp_dabr); #endif @@ -485,35 +467,33 @@ kdp_call_kdb( return(TRUE); } -void kdp_print_registers(struct ppc_saved_state *state) +void kdp_print_registers(struct savearea *state) { int i; for (i=0; i<32; i++) { if ((i % 8) == 0) printf("\n%4d :",i); - printf(" %08x",*(&state->r0+i)); + printf(" %08x",*(&state->save_r0+i)); } printf("\n"); - printf("cr = 0x%08x\t\t",state->cr); - printf("xer = 0x%08x\n",state->xer); - printf("lr = 0x%08x\t\t",state->lr); - printf("ctr = 0x%08x\n",state->ctr); - printf("srr0(iar) = 0x%08x\t\t",state->srr0); - printf("srr1(msr) = 0x%08B\n",state->srr1, + printf("cr = 0x%08x\t\t",state->save_cr); + printf("xer = 0x%08x\n",state->save_xer); + printf("lr = 0x%08x\t\t",state->save_lr); + printf("ctr = 0x%08x\n",state->save_ctr); + printf("srr0(iar) = 0x%08x\t\t",state->save_srr0); + printf("srr1(msr) = 0x%08B\n",state->save_srr1, "\x10\x11""EE\x12PR\x13""FP\x14ME\x15""FE0\x16SE\x18" "FE1\x19""AL\x1a""EP\x1bIT\x1c""DT"); - printf("mq = 0x%08x\t\t",state->mq); - printf("sr_copyin = 0x%08x\n",state->sr_copyin); printf("\n"); } void kdp_print_backtrace( unsigned int exception, - struct ppc_saved_state *saved_state) + struct savearea *saved_state) { - extern void kdp_print_registers(struct ppc_saved_state *); - extern void print_backtrace(struct ppc_saved_state *); + extern void kdp_print_registers(struct savearea *); + extern void print_backtrace(struct savearea *); extern unsigned int debug_mode, disableDebugOuput; disableDebugOuput = FALSE; @@ -525,3 +505,8 @@ kdp_print_backtrace( printf("panic: We are hanging here...\n"); while(1); } + +unsigned int kdp_ml_get_breakinsn() +{ + return 0x7fe00008; +} diff --git a/osfmk/kdp/ml/ppc/kdp_misc.s b/osfmk/kdp/ml/ppc/kdp_misc.s index 7ddbf68c1..850b3c232 100644 --- a/osfmk/kdp/ml/ppc/kdp_misc.s +++ b/osfmk/kdp/ml/ppc/kdp_misc.s @@ -69,6 +69,8 @@ ENTRY(kdp_sync_cache, TAG_NO_FRAME_USED) ENTRY(kdp_xlate_off, TAG_NO_FRAME_USED) mfmsr r3 + rlwinm r3,r3,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r3,r3,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r4, r3, 0, MSR_DR_BIT+1, MSR_IR_BIT-1 mtmsr r4 isync diff --git a/osfmk/kern/Makefile b/osfmk/kern/Makefile index 7c9e1f38f..16361eef0 100644 --- a/osfmk/kern/Makefile +++ b/osfmk/kern/Makefile @@ -19,6 +19,7 @@ EXPORT_ONLY_FILES = \ kalloc.h \ kern_types.h \ lock.h \ + ledger.h \ host.h \ mach_param.h \ macro_help.h \ diff --git a/osfmk/kern/assert.h b/osfmk/kern/assert.h index b7c9317e7..42718d5ca 100644 --- a/osfmk/kern/assert.h +++ b/osfmk/kern/assert.h @@ -69,11 +69,8 @@ extern void Assert( #if MACH_ASSERT -#define assert(ex) \ -MACRO_BEGIN \ - if (!(ex)) \ - Assert(__FILE__, __LINE__, # ex); \ -MACRO_END +#define assert(ex) \ + ((ex) ? (void)0 : Assert(__FILE__, __LINE__, # ex)) #define assert_static(x) assert(x) #else /* MACH_ASSERT */ diff --git a/osfmk/kern/ast.c b/osfmk/kern/ast.c index df5409005..848c13caf 100644 --- a/osfmk/kern/ast.c +++ b/osfmk/kern/ast.c @@ -134,7 +134,7 @@ ast_taken( #ifdef MACH_BSD /* - * Check for BSD hardcoded hooks + * Check for BSD hook */ if (reasons & AST_BSD) { extern void bsd_ast(thread_act_t act); @@ -143,12 +143,6 @@ ast_taken( thread_ast_clear(act, AST_BSD); bsd_ast(act); } - if (reasons & AST_BSD_INIT) { - extern void bsdinit_task(void); - - thread_ast_clear(self->top_act, AST_BSD_INIT); - bsdinit_task(); - } #endif /* @@ -184,40 +178,20 @@ just_return: return; } +/* + * Called at splsched. + */ void -ast_check(void) +ast_check( + processor_t processor) { - register int mycpu; - register processor_t myprocessor; - register thread_t self = current_thread(); - spl_t s; - - s = splsched(); - mycpu = cpu_number(); + register thread_t self = processor->cpu_data->active_thread; - /* - * Check processor state for ast conditions. - */ - myprocessor = cpu_to_processor(mycpu); - switch (myprocessor->state) { - - case PROCESSOR_OFF_LINE: - case PROCESSOR_IDLE: - case PROCESSOR_DISPATCHING: - /* - * No ast. - */ - break; - - case PROCESSOR_ASSIGN: - /* - * Need ast to force action thread onto processor. - */ - ast_on(AST_BLOCK); - break; + processor->current_pri = self->sched_pri; + if (processor->state == PROCESSOR_RUNNING) { + register ast_t preempt; +processor_running: - case PROCESSOR_RUNNING: - case PROCESSOR_SHUTDOWN: /* * Propagate thread ast to processor. */ @@ -226,35 +200,18 @@ ast_check(void) /* * Context switch check. */ - if (csw_needed(self, myprocessor)) - ast_on(AST_BLOCK); - break; - - default: - panic("ast_check: Bad processor state"); + if ((preempt = csw_check(self, processor)) != AST_NONE) + ast_on(preempt); } - - splx(s); -} - -/* - * JMM - Temporary exports to other components - */ -#undef ast_on -#undef ast_off - -void -ast_on(ast_t reason) -{ - boolean_t enable; - - enable = ml_set_interrupts_enabled(FALSE); - ast_on_fast(reason); - (void)ml_set_interrupts_enabled(enable); -} - -void -ast_off(ast_t reason) -{ - ast_off_fast(reason); + else + if ( processor->state == PROCESSOR_DISPATCHING || + processor->state == PROCESSOR_IDLE ) { + return; + } + else + if (processor->state == PROCESSOR_SHUTDOWN) + goto processor_running; + else + if (processor->state == PROCESSOR_ASSIGN) + ast_on(AST_BLOCK); } diff --git a/osfmk/kern/ast.h b/osfmk/kern/ast.h index 3512b4593..9d2a912c0 100644 --- a/osfmk/kern/ast.h +++ b/osfmk/kern/ast.h @@ -68,20 +68,21 @@ #include /* - * A CPU takes an AST when it is about to return to user code. - * Instead of going back to user code, it calls ast_taken. - * Machine-dependent code is responsible for maintaining - * a set of reasons for an AST, and passing this set to ast_taken. + * A processor takes an AST when it is about to return from an + * interrupt context, and calls ast_taken. + * + * Machine-dependent code is responsible for maintaining + * a set of reasons for an AST, and passing this set to ast_taken. */ -typedef unsigned int ast_t; +typedef uint32_t ast_t; /* * Bits for reasons */ -#define AST_HALT 0x01 -#define AST_TERMINATE 0x02 -#define AST_BLOCK 0x04 -#define AST_QUANTUM 0x08 +#define AST_BLOCK 0x01 +#define AST_QUANTUM 0x02 +#define AST_HANDOFF 0x04 +#define AST_YIELD 0x08 #define AST_URGENT 0x10 #define AST_APC 0x20 /* migration APC hook */ /* @@ -90,12 +91,11 @@ typedef unsigned int ast_t; * from the outside. */ #define AST_BSD 0x80 -#define AST_BSD_INIT 0x100 #define AST_NONE 0x00 #define AST_ALL (~AST_NONE) -#define AST_SCHEDULING (AST_HALT | AST_TERMINATE | AST_BLOCK) +#define AST_SCHEDULING (AST_PREEMPT | AST_YIELD | AST_HANDOFF) #define AST_PREEMPT (AST_BLOCK | AST_QUANTUM | AST_URGENT) extern volatile ast_t need_ast[NCPUS]; @@ -120,7 +120,8 @@ extern void ast_taken( boolean_t enable); /* Check for pending ASTs */ -extern void ast_check(void); +extern void ast_check( + processor_t processor); /* * Per-thread ASTs are reset at context-switch time. @@ -129,13 +130,12 @@ extern void ast_check(void); #define MACHINE_AST_PER_THREAD 0 #endif -#define AST_PER_THREAD ( AST_HALT | AST_TERMINATE | AST_APC | AST_BSD | \ - MACHINE_AST_PER_THREAD ) +#define AST_PER_THREAD (AST_APC | AST_BSD | MACHINE_AST_PER_THREAD) /* * ast_needed(), ast_on(), ast_off(), ast_context(), and ast_propagate() * assume splsched. */ -#define ast_needed(mycpu) need_ast[mycpu] +#define ast_needed(mycpu) (need_ast[mycpu] != AST_NONE) #define ast_on_fast(reasons) \ MACRO_BEGIN \ @@ -166,9 +166,12 @@ MACRO_END #define ast_on(reason) ast_on_fast(reason) #define ast_off(reason) ast_off_fast(reason) -#define thread_ast_set(act, reason) ((act)->ast |= (reason)) -#define thread_ast_clear(act, reason) ((act)->ast &= ~(reason)) -#define thread_ast_clear_all(act) ((act)->ast = AST_NONE) +#define thread_ast_set(act, reason) \ + (hw_atomic_or(&(act)->ast, (reason))) +#define thread_ast_clear(act, reason) \ + (hw_atomic_and(&(act)->ast, ~(reason))) +#define thread_ast_clear_all(act) \ + (hw_atomic_and(&(act)->ast, AST_NONE)) /* * NOTE: if thread is the current thread, thread_ast_set() should diff --git a/osfmk/kern/bsd_kern.c b/osfmk/kern/bsd_kern.c index 5648cb387..6b27ea5a9 100644 --- a/osfmk/kern/bsd_kern.c +++ b/osfmk/kern/bsd_kern.c @@ -34,15 +34,13 @@ #undef thread_should_halt #undef ipc_port_release -#undef thread_ast_set -#undef thread_ast_clear decl_simple_lock_data(extern,reaper_lock) extern queue_head_t reaper_queue; /* BSD KERN COMPONENT INTERFACE */ -vm_address_t bsd_init_task = 0; +task_t bsd_init_task = TASK_NULL; char init_task_failure_data[1024]; thread_act_t get_firstthread(task_t); @@ -50,28 +48,25 @@ vm_map_t get_task_map(task_t); ipc_space_t get_task_ipcspace(task_t); boolean_t is_kerneltask(task_t); boolean_t is_thread_idle(thread_t); -boolean_t is_thread_running(thread_t); +boolean_t is_thread_running(thread_act_t); thread_shuttle_t getshuttle_thread( thread_act_t); thread_act_t getact_thread( thread_shuttle_t); vm_offset_t get_map_min( vm_map_t); vm_offset_t get_map_max( vm_map_t); int get_task_userstop(task_t); int get_thread_userstop(thread_act_t); -int inc_task_userstop(task_t); boolean_t thread_should_abort(thread_shuttle_t); boolean_t current_thread_aborted(void); void task_act_iterate_wth_args(task_t, void(*)(thread_act_t, void *), void *); void ipc_port_release(ipc_port_t); -void thread_ast_set(thread_act_t, ast_t); -void thread_ast_clear(thread_act_t, ast_t); boolean_t is_thread_active(thread_t); -event_t get_thread_waitevent(thread_t); kern_return_t get_thread_waitresult(thread_t); vm_size_t get_vmmap_size(vm_map_t); int get_vmmap_entries(vm_map_t); int get_task_numacts(task_t); thread_act_t get_firstthread(task_t task); kern_return_t get_signalact(task_t , thread_act_t *, thread_t *, int); +void astbsd_on(void); /* * @@ -134,7 +129,8 @@ kern_return_t get_signalact(task_t task,thread_act_t * thact, thread_t * thshut, inc != (thread_act_t)&task->thr_acts; inc = ninc) { th = act_lock_thread(inc); - if ((inc->active) && ((th->state & TH_ABORT) != TH_ABORT)) { + if ((inc->active) && + ((th->state & (TH_ABORT|TH_ABORT_SAFELY)) != TH_ABORT)) { thr_act = inc; break; } @@ -148,11 +144,9 @@ out: if (thshut) *thshut = thr_act? thr_act->thread: THREAD_NULL ; if (thr_act) { - if (setast) { - thread_ast_set(thr_act, AST_BSD); - if (current_act() == thr_act) - ast_on(AST_BSD); - } + if (setast) + act_set_astbsd(thr_act); + act_unlock_thread(thr_act); } task_unlock(task); @@ -164,7 +158,7 @@ out: } -kern_return_t check_actforsig(task_t task, thread_act_t * thact, thread_t * thshut, int setast) +kern_return_t check_actforsig(task_t task, thread_act_t thact, thread_t * thshut, int setast) { thread_act_t inc; @@ -189,7 +183,8 @@ kern_return_t check_actforsig(task_t task, thread_act_t * thact, thread_t * thsh continue; } th = act_lock_thread(inc); - if ((inc->active) && ((th->state & TH_ABORT) != TH_ABORT)) { + if ((inc->active) && + ((th->state & (TH_ABORT|TH_ABORT_SAFELY)) != TH_ABORT)) { found = 1; thr_act = inc; break; @@ -202,11 +197,9 @@ out: if (found) { if (thshut) *thshut = thr_act? thr_act->thread: THREAD_NULL ; - if (setast) { - thread_ast_set(thr_act, AST_BSD); - if (current_act() == thr_act) - ast_on(AST_BSD); - } + if (setast) + act_set_astbsd(thr_act); + act_unlock_thread(thr_act); } task_unlock(task); @@ -307,8 +300,9 @@ boolean_t is_thread_idle(thread_t th) /* * */ -boolean_t is_thread_running(thread_t th) +boolean_t is_thread_running(thread_act_t thact) { + thread_t th = thact->thread; return((th->state & TH_RUN) == TH_RUN); } @@ -444,20 +438,6 @@ get_thread_userstop( return(th->user_stop_count); } -/* - * - */ -int -inc_task_userstop( - task_t task) -{ - int i=0; - i = task->user_stop_count; - task->user_stop_count++; - return(i); -} - - /* * */ @@ -465,21 +445,38 @@ boolean_t thread_should_abort( thread_shuttle_t th) { - return( (!th->top_act || !th->top_act->active || - th->state & TH_ABORT)); + return(!th->top_act || !th->top_act->active || + (th->state & (TH_ABORT|TH_ABORT_SAFELY)) == TH_ABORT); } /* - * + * This routine is like thread_should_abort() above. It checks to + * see if the current thread is aborted. But unlike above, it also + * checks to see if thread is safely aborted. If so, it returns + * that fact, and clears the condition (safe aborts only should + * have a single effect, and a poll of the abort status + * qualifies. */ boolean_t current_thread_aborted ( void) { thread_t th = current_thread(); - - return(!th->top_act || - ((th->state & TH_ABORT) && (th->interruptible))); + spl_t s; + + if (!th->top_act || + ((th->state & (TH_ABORT|TH_ABORT_SAFELY)) == TH_ABORT && + th->interrupt_level != THREAD_UNINT)) + return (TRUE); + if (th->state & TH_ABORT_SAFELY) { + s = splsched(); + thread_lock(th); + if (th->state & TH_ABORT_SAFELY) + th->state &= ~(TH_ABORT|TH_ABORT_SAFELY); + thread_unlock(th); + splx(s); + } + return FALSE; } /* @@ -510,21 +507,6 @@ ipc_port_release( ipc_object_release(&(port)->ip_object); } -void -thread_ast_set( - thread_act_t act, - ast_t reason) -{ - act->ast |= reason; -} -void -thread_ast_clear( - thread_act_t act, - ast_t reason) -{ - act->ast &= ~(reason); -} - boolean_t is_thread_active( thread_shuttle_t th) @@ -532,13 +514,6 @@ is_thread_active( return(th->active); } -event_t -get_thread_waitevent( - thread_shuttle_t th) -{ - return(th->wait_event); -} - kern_return_t get_thread_waitresult( thread_shuttle_t th) @@ -546,4 +521,12 @@ get_thread_waitresult( return(th->wait_result); } +void +astbsd_on(void) +{ + boolean_t reenable; + reenable = ml_set_interrupts_enabled(FALSE); + ast_on_fast(AST_BSD); + (void)ml_set_interrupts_enabled(reenable); +} diff --git a/osfmk/kern/clock.c b/osfmk/kern/clock.c index 1aab8196c..b6a263b70 100644 --- a/osfmk/kern/clock.c +++ b/osfmk/kern/clock.c @@ -70,6 +70,13 @@ static struct alarm *alrmdone; /* alarm done list pointer */ static long alrm_seqno; /* uniquely identifies alarms */ static thread_call_data_t alarm_deliver; +decl_simple_lock_data(static,calend_adjlock) +static int64_t calend_adjtotal; +static uint32_t calend_adjdelta; + +static timer_call_data_t calend_adjcall; +static uint64_t calend_adjinterval, calend_adjdeadline; + /* backwards compatibility */ int hz = HZ; /* GET RID OF THIS !!! */ int tick = (1000000 / HZ); /* GET RID OF THIS !!! */ @@ -99,6 +106,11 @@ void clock_alarm_deliver( thread_call_param_t p0, thread_call_param_t p1); +static +void clock_calend_adjust( + timer_call_param_t p0, + timer_call_param_t p1); + /* * Macros to lock/unlock clock system. */ @@ -126,6 +138,7 @@ clock_config(void) /* * Configure clock devices. */ + simple_lock_init(&calend_adjlock, ETAP_MISC_CLOCK); simple_lock_init(&ClockLock, ETAP_MISC_CLOCK); for (i = 0; i < clock_count; i++) { clock = &clock_list[i]; @@ -180,15 +193,14 @@ clock_service_create(void) } } + timer_call_setup(&calend_adjcall, clock_calend_adjust, NULL); + /* * Initialize clock service alarms. */ i = sizeof(struct alarm); alarm_zone = zinit(i, (4096/i)*i, 10*i, "alarms"); - /* - * Initialize the clock alarm delivery mechanism. - */ thread_call_setup(&alarm_deliver, clock_alarm_deliver, NULL); } @@ -279,11 +291,16 @@ clock_set_time( mach_timespec_t *clock_time; kern_return_t (*settime)( mach_timespec_t *clock_time); + extern kern_return_t + calend_settime( + mach_timespec_t *clock_time); if (clock == CLOCK_NULL) return (KERN_INVALID_ARGUMENT); if ((settime = clock->cl_ops->c_settime) == 0) return (KERN_FAILURE); + if (settime == calend_settime) + return (KERN_FAILURE); clock_time = &new_time; if (BAD_MACH_TIMESPEC(clock_time)) return (KERN_INVALID_VALUE); @@ -463,6 +480,8 @@ clock_sleep_internal( return (KERN_INVALID_VALUE); rvalue = KERN_SUCCESS; if (chkstat > 0) { + wait_result_t wait_result; + /* * Get alarm and add to clock alarm list. */ @@ -478,34 +497,37 @@ clock_sleep_internal( else alrmfree = alarm->al_next; - alarm->al_time = *sleep_time; - alarm->al_status = ALARM_SLEEP; - post_alarm(clock, alarm); - /* * Wait for alarm to occur. */ - assert_wait((event_t)alarm, THREAD_ABORTSAFE); - UNLOCK_CLOCK(s); - /* should we force spl(0) at this point? */ - thread_block((void (*)(void)) 0); - /* we should return here at ipl0 */ + wait_result = assert_wait((event_t)alarm, THREAD_ABORTSAFE); + if (wait_result == THREAD_WAITING) { + alarm->al_time = *sleep_time; + alarm->al_status = ALARM_SLEEP; + post_alarm(clock, alarm); + UNLOCK_CLOCK(s); - /* - * Note if alarm expired normally or whether it - * was aborted. If aborted, delete alarm from - * clock alarm list. Return alarm to free list. - */ - LOCK_CLOCK(s); - if (alarm->al_status != ALARM_DONE) { - /* This means we were interrupted and that - thread->wait_result != THREAD_AWAKENED. */ - if ((alarm->al_prev)->al_next = alarm->al_next) - (alarm->al_next)->al_prev = alarm->al_prev; + wait_result = thread_block(THREAD_CONTINUE_NULL); + + /* + * Note if alarm expired normally or whether it + * was aborted. If aborted, delete alarm from + * clock alarm list. Return alarm to free list. + */ + LOCK_CLOCK(s); + if (alarm->al_status != ALARM_DONE) { + assert(wait_result != THREAD_AWAKENED); + if ((alarm->al_prev)->al_next = alarm->al_next) + (alarm->al_next)->al_prev = alarm->al_prev; + rvalue = KERN_ABORTED; + } + *sleep_time = alarm->al_time; + alarm->al_status = ALARM_FREE; + } else { + assert(wait_result == THREAD_INTERRUPTED); + assert(alarm->al_status == ALARM_FREE); rvalue = KERN_ABORTED; } - *sleep_time = alarm->al_time; - alarm->al_status = ALARM_FREE; alarm->al_next = alrmfree; alrmfree = alarm; UNLOCK_CLOCK(s); @@ -852,11 +874,105 @@ mach_wait_until( { int wait_result; - assert_wait((event_t)&mach_wait_until, THREAD_ABORTSAFE); - thread_set_timer_deadline(deadline); - wait_result = thread_block((void (*)) 0); - if (wait_result != THREAD_TIMED_OUT) - thread_cancel_timer(); + wait_result = assert_wait((event_t)&mach_wait_until, THREAD_ABORTSAFE); + if (wait_result == THREAD_WAITING) { + thread_set_timer_deadline(deadline); + wait_result = thread_block(THREAD_CONTINUE_NULL); + if (wait_result != THREAD_TIMED_OUT) + thread_cancel_timer(); + } return ((wait_result == THREAD_INTERRUPTED)? KERN_ABORTED: KERN_SUCCESS); } + +int64_t +clock_set_calendar_adjtime( + int64_t total, + uint32_t delta) +{ + int64_t ototal; + spl_t s; + + s = splclock(); + simple_lock(&calend_adjlock); + + if (calend_adjinterval == 0) + clock_interval_to_absolutetime_interval(10000, NSEC_PER_USEC, + &calend_adjinterval); + + ototal = calend_adjtotal; + + if (total != 0) { + uint64_t abstime; + + if (total > 0) { + if (delta > total) + delta = total; + } + else { + if (delta > -total) + delta = -total; + } + + calend_adjtotal = total; + calend_adjdelta = delta; + + if (calend_adjdeadline >= calend_adjinterval) + calend_adjdeadline -= calend_adjinterval; + clock_get_uptime(&abstime); + clock_deadline_for_periodic_event(calend_adjinterval, abstime, + &calend_adjdeadline); + + timer_call_enter(&calend_adjcall, calend_adjdeadline); + } + else { + calend_adjtotal = 0; + + timer_call_cancel(&calend_adjcall); + } + + simple_unlock(&calend_adjlock); + splx(s); + + return (ototal); +} + +static void +clock_calend_adjust( + timer_call_param_t p0, + timer_call_param_t p1) +{ + spl_t s; + + s = splclock(); + simple_lock(&calend_adjlock); + + if (calend_adjtotal > 0) { + clock_adjust_calendar((clock_res_t)calend_adjdelta); + calend_adjtotal -= calend_adjdelta; + + if (calend_adjdelta > calend_adjtotal) + calend_adjdelta = calend_adjtotal; + } + else + if (calend_adjtotal < 0) { + clock_adjust_calendar(-(clock_res_t)calend_adjdelta); + calend_adjtotal += calend_adjdelta; + + if (calend_adjdelta > -calend_adjtotal) + calend_adjdelta = -calend_adjtotal; + } + + if (calend_adjtotal != 0) { + uint64_t abstime; + + clock_get_uptime(&abstime); + clock_deadline_for_periodic_event(calend_adjinterval, abstime, + &calend_adjdeadline); + + timer_call_enter(&calend_adjcall, calend_adjdeadline); + } + + simple_unlock(&calend_adjlock); + splx(s); +} diff --git a/osfmk/kern/clock.h b/osfmk/kern/clock.h index 58c78efd5..26cefa13c 100644 --- a/osfmk/kern/clock.h +++ b/osfmk/kern/clock.h @@ -36,7 +36,12 @@ #include #include -#ifdef MACH_KERNEL_PRIVATE +#include + +#ifdef __APPLE_API_PRIVATE + +#ifdef MACH_KERNEL_PRIVATE + #include /* @@ -164,8 +169,27 @@ extern void mk_timebase_info( uint32_t *proc_to_abs_numer, uint32_t *proc_to_abs_denom); +extern void clock_adjust_calendar( + clock_res_t nsec); + +extern mach_timespec_t + clock_get_calendar_offset(void); + #endif /* MACH_KERNEL_PRIVATE */ +extern void clock_set_calendar_value( + mach_timespec_t value); + +extern int64_t clock_set_calendar_adjtime( + int64_t total, + uint32_t delta); + +extern void clock_initialize_calendar(void); + +#endif /* __APPLE_API_PRIVATE */ + +#ifdef __APPLE_API_UNSTABLE + #define MACH_TIMESPEC_SEC_MAX (0 - 1) #define MACH_TIMESPEC_NSEC_MAX (NSEC_PER_SEC - 1) @@ -189,20 +213,12 @@ extern void mk_timebase_info( } \ } while (0) +#endif /* __APPLE_API_UNSTABLE */ + extern mach_timespec_t clock_get_system_value(void); extern mach_timespec_t clock_get_calendar_value(void); -extern void clock_set_calendar_value( - mach_timespec_t value); - -extern void clock_adjust_calendar( - clock_res_t nsec); - -extern void clock_initialize_calendar(void); - -extern mach_timespec_t clock_get_calendar_offset(void); - extern void clock_timebase_info( mach_timebase_info_t info); diff --git a/osfmk/kern/cpu_data.c b/osfmk/kern/cpu_data.c index 9051e7b27..10d1afb1f 100644 --- a/osfmk/kern/cpu_data.c +++ b/osfmk/kern/cpu_data.c @@ -31,20 +31,3 @@ #include #include #include - -int master_cpu = 0; - -#ifdef PPC - -cpu_data_t cpu_data[NCPUS] = - { { THREAD_NULL, /* active_thread */ - 0, /* preemption_level */ - 0, /* simple_lock_cout */ - 0 /* interrupt_level */ - }, }; - -#else /* PPC */ - -cpu_data_t cpu_data[NCPUS]; - -#endif /* PPC */ diff --git a/osfmk/kern/cpu_data.h b/osfmk/kern/cpu_data.h index 7ff974ca3..1bd1c9e16 100644 --- a/osfmk/kern/cpu_data.h +++ b/osfmk/kern/cpu_data.h @@ -26,7 +26,12 @@ #ifndef _CPU_DATA_H_ #define _CPU_DATA_H_ -#ifdef MACH_KERNEL_PRIVATE +#include + +#ifdef __APPLE_API_PRIVATE + +#ifdef MACH_KERNEL_PRIVATE + #include #include @@ -42,22 +47,26 @@ typedef struct #endif } cpu_data_t; -extern cpu_data_t cpu_data[NCPUS]; - #include -#else /* !MACH_KERNEL_PRIVATE */ +#else /* MACH_KERNEL_PRIVATE */ -extern thread_t current_thread(void); -#define get_preemption_level() _get_preeption_level() -#define get_simple_lock_count() _get_simple_lock_count() #define disable_preemption() _disable_preemption() #define enable_preemption() _enable_preemption() #define enable_preemption_no_check() _enable_preemption_no_check() -#define mp_disable_preemption() _mp_disable_preemption() -#define mp_enable_preemption() _mp_enable_preemption() -#define mp_enable_preemption_no_check() _mp_enable_preemption_no_check() -#endif /* !MACH_KERNEL_PRIVATE */ +#endif /* MACH_KERNEL_PRIVATE */ + +#endif /* __APPLE_API_PRIVATE */ + +#ifdef __APPLE_API_UNSTABLE + +#if !defined(MACH_KERNEL_PRIVATE) + +extern thread_t current_thread(void); + +#endif /* MACH_KERNEL_PRIVATE */ + +#endif /* __APPLE_API_UNSTABLE */ #endif /* _CPU_DATA_H_ */ diff --git a/osfmk/kern/cpu_number.h b/osfmk/kern/cpu_number.h index afcc656f7..59d1f50c4 100644 --- a/osfmk/kern/cpu_number.h +++ b/osfmk/kern/cpu_number.h @@ -47,18 +47,22 @@ * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ -/* - */ #ifndef _KERN_CPU_NUMBER_H_ #define _KERN_CPU_NUMBER_H_ -#include +#include -/* - * Definitions for cpu identification in multi-processors. - */ +#ifdef __APPLE_API_PRIVATE -extern int master_cpu; /* 'master' processor - keeps time */ +#ifdef MACH_KERNEL_PRIVATE + +extern int master_cpu; + +#endif /* MACH_KERNEL_PRIVATE */ + +#endif /* __APPLE_API_PRIVATE */ + +#include #endif /* _KERN_CPU_NUMBER_H_ */ diff --git a/osfmk/kern/debug.c b/osfmk/kern/debug.c index b0e7f043d..7793cb8c2 100644 --- a/osfmk/kern/debug.c +++ b/osfmk/kern/debug.c @@ -61,8 +61,14 @@ #include #include #include +#include #include +#ifdef __ppc__ +#include +#include +#endif + unsigned int halt_in_debugger = 0; unsigned int switch_debugger = 0; unsigned int current_debugger = 0; @@ -70,6 +76,12 @@ unsigned int active_debugger = 0; unsigned int debug_mode=0; unsigned int disableDebugOuput = TRUE; unsigned int systemLogDiags = FALSE; +unsigned int panicDebugging = FALSE; +#ifdef __ppc__ + unsigned int logPanicDataToScreen = FALSE; +#else + unsigned int logPanicDataToScreen = TRUE; +#endif int mach_assert = 1; @@ -82,6 +94,10 @@ unsigned int panic_is_inited = 0; unsigned int return_on_panic = 0; wait_queue_t save_waits[NCPUS]; +char *debug_buf; +char *debug_buf_ptr; +unsigned int debug_buf_size = 0; + void Assert( const char *file, @@ -130,12 +146,19 @@ panic(const char *str, ...) s = splhigh(); +#ifdef __ppc__ + lastTrace = LLTraceSet(0); /* Disable low-level tracing */ +#endif + thread = current_thread(); /* Get failing thread */ save_waits[cpu_number()] = thread->wait_queue; /* Save the old value */ thread->wait_queue = 0; /* Clear the wait so we do not get double panics when we try locks */ mp_disable_preemption(); - disableDebugOuput = FALSE; + + if( logPanicDataToScreen ) + disableDebugOuput = FALSE; + debug_mode = TRUE; restart: PANIC_LOCK(); @@ -165,11 +188,11 @@ restart: panicwait = 1; PANIC_UNLOCK(); - printf("panic(cpu %d): ", (unsigned) paniccpu); + kdb_printf("panic(cpu %d): ", (unsigned) paniccpu); va_start(listp, str); - _doprnt(str, &listp, cnputc, 0); + _doprnt(str, &listp, consdebug_putc, 0); va_end(listp); - printf("\n"); + kdb_printf("\n"); /* * Release panicwait indicator so that other cpus may call Debugger(). @@ -187,7 +210,7 @@ restart: thread->wait_queue = save_waits[cpu_number()]; /* Restore the wait queue */ if (return_on_panic) return; - printf("panic: We are hanging here...\n"); + kdb_printf("panic: We are hanging here...\n"); while(1); /* NOTREACHED */ } @@ -196,7 +219,6 @@ void log(int level, char *fmt, ...) { va_list listp; - extern void conslog_putc(char); #ifdef lint level++; @@ -209,3 +231,23 @@ log(int level, char *fmt, ...) enable_preemption(); #endif } + +void +debug_log_init(void) +{ + if (debug_buf_size != 0) + return; + if (kmem_alloc(kernel_map, (vm_offset_t *) &debug_buf, PAGE_SIZE) != KERN_SUCCESS) + panic("cannot allocate debug_buf \n"); + debug_buf_ptr = debug_buf; + debug_buf_size = PAGE_SIZE; +} + +void +debug_putc(char c) +{ + if ((debug_buf_size != 0) && ((debug_buf_ptr-debug_buf) < debug_buf_size)) { + *debug_buf_ptr=c; + debug_buf_ptr++; + } +} diff --git a/osfmk/kern/debug.h b/osfmk/kern/debug.h index e5c63e642..990b10f95 100644 --- a/osfmk/kern/debug.h +++ b/osfmk/kern/debug.h @@ -19,9 +19,13 @@ * * @APPLE_LICENSE_HEADER_END@ */ + #ifndef _KERN_DEBUG_H_ #define _KERN_DEBUG_H_ +#include + +#ifdef __APPLE_API_PRIVATE extern unsigned int systemLogDiags; @@ -38,7 +42,10 @@ extern unsigned int current_debugger; extern unsigned int active_debugger; extern unsigned int debug_mode; -extern unsigned int disableDebugOuput; +extern unsigned int disableDebugOuput; + +extern unsigned int panicDebugging; +extern unsigned int logPanicDataToScreen; extern int db_run_mode; @@ -57,6 +64,13 @@ extern char *panicstr; extern unsigned int nestedpanic; +extern char *debug_buf; +extern char *debug_buf_ptr; +extern unsigned int debug_buf_size; + +extern void debug_log_init(void); +extern void debug_putc(char); + #endif /* MACH_KERNEL_PRIVATE */ #define DB_HALT 0x1 @@ -65,5 +79,10 @@ extern unsigned int nestedpanic; #define DB_KPRT 0x8 #define DB_KDB 0x10 #define DB_SLOG 0x20 +#define DB_ARP 0x40 +#define DB_KDP_BP_DIS 0x80 +#define DB_LOG_PI_SCRN 0x100 + +#endif /* __APPLE_API_PRIVATE */ #endif /* _KERN_DEBUG_H_ */ diff --git a/osfmk/kern/etap_macros.h b/osfmk/kern/etap_macros.h index 7935b6276..530522648 100644 --- a/osfmk/kern/etap_macros.h +++ b/osfmk/kern/etap_macros.h @@ -55,11 +55,11 @@ #if ETAP -#include #include -#include #include +#include + extern void etap_init_phase1(void); extern void etap_init_phase2(void); extern void etap_event_table_assign(struct event_table_chain *, etap_event_t); @@ -261,6 +261,22 @@ MACRO_END #endif /* ETAP_LOCK_MONITOR */ +#if ETAP_EVENT_MONITOR + +#include + +#define ETAP_EXCEPTION_PROBE(_f, _th, _ex, _sysnum) \ + if (_ex == EXC_SYSCALL) { \ + ETAP_PROBE_DATA(ETAP_P_SYSCALL_UNIX, \ + _f, \ + _th, \ + _sysnum, \ + sizeof(int)); \ + } +#else /* ETAP_EVENT_MONITOR */ +#define ETAP_EXCEPTION_PROBE(_f, _th, _ex, _sysnum) +#endif /* ETAP_EVENT_MONITOR */ + #if ETAP_EVENT_MONITOR #define ETAP_PROBE_DATA_COND(_event, _flags, _thread, _data, _size, _cond) \ diff --git a/osfmk/kern/etap_pool.c b/osfmk/kern/etap_pool.c index 2e3971ace..afb69bdd7 100644 --- a/osfmk/kern/etap_pool.c +++ b/osfmk/kern/etap_pool.c @@ -173,7 +173,7 @@ get_start_data_node(void) pool_unlock(s); printf ("DEBUG-KERNEL: empty start_data_pool\n"); - thread_block((void (*)(void)) 0); + thread_block(THREAD_CONTINUE_NULL); pool_lock(s); sd_sleepers--; diff --git a/osfmk/kern/exception.c b/osfmk/kern/exception.c index 70c1d0e0a..b99139fc2 100644 --- a/osfmk/kern/exception.c +++ b/osfmk/kern/exception.c @@ -78,8 +78,7 @@ #include #include #include -#include /* JMM - will become exception.h */ -#include +#include #if MACH_KDB #include @@ -315,3 +314,138 @@ exception( thread_exception_return(); /*NOTREACHED*/ } + +kern_return_t +bsd_exception( + exception_type_t exception, + exception_data_t code, + mach_msg_type_number_t codeCnt) +{ + task_t task; + host_priv_t host_priv; + struct exception_action *excp; + mutex_t *mutex; + thread_act_t a_self = current_act(); + ipc_port_t exc_port; + int behavior; + int flavor; + kern_return_t kr; + + /* + * Maybe the task level will handle it. + */ + task = current_task(); + mutex = mutex_addr(task->lock); + excp = &task->exc_actions[exception]; + + /* + * Save work if we are terminating. + * Just go back to our AST handler. + */ + if (!a_self->active) { + return(KERN_FAILURE); + } + + /* + * Snapshot the exception action data under lock for consistency. + * Hold a reference to the port over the exception_raise_* calls + * so it can't be destroyed. This seems like overkill, but keeps + * the port from disappearing between now and when + * ipc_object_copyin_from_kernel is finally called. + */ + mutex_lock(mutex); + exc_port = excp->port; + if (!IP_VALID(exc_port)) { + mutex_unlock(mutex); + return(KERN_FAILURE); + } + ip_lock(exc_port); + if (!ip_active(exc_port)) { + ip_unlock(exc_port); + mutex_unlock(mutex); + return(KERN_FAILURE); + } + ip_reference(exc_port); + exc_port->ip_srights++; + ip_unlock(exc_port); + + flavor = excp->flavor; + behavior = excp->behavior; + mutex_unlock(mutex); + + switch (behavior) { + case EXCEPTION_STATE: { + mach_msg_type_number_t state_cnt; + natural_t state[ THREAD_MACHINE_STATE_MAX ]; + + c_thr_exc_raise_state++; + state_cnt = state_count[flavor]; + kr = thread_getstatus(a_self, flavor, + (thread_state_t)state, + &state_cnt); + if (kr == KERN_SUCCESS) { + kr = exception_raise_state(exc_port, exception, + code, codeCnt, + &flavor, + state, state_cnt, + state, &state_cnt); + if (kr == MACH_MSG_SUCCESS) + kr = thread_setstatus(a_self, flavor, + (thread_state_t)state, + state_cnt); + } + + if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED) + return(KERN_SUCCESS); + + return(KERN_FAILURE); + } + + case EXCEPTION_DEFAULT: + c_thr_exc_raise++; + kr = exception_raise(exc_port, + retrieve_act_self_fast(a_self), + retrieve_task_self_fast(a_self->task), + exception, + code, codeCnt); + + if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED) + return(KERN_SUCCESS); + return(KERN_FAILURE); + + case EXCEPTION_STATE_IDENTITY: { + mach_msg_type_number_t state_cnt; + natural_t state[ THREAD_MACHINE_STATE_MAX ]; + + c_thr_exc_raise_state_id++; + state_cnt = state_count[flavor]; + kr = thread_getstatus(a_self, flavor, + (thread_state_t)state, + &state_cnt); + if (kr == KERN_SUCCESS) { + kr = exception_raise_state_identity(exc_port, + retrieve_act_self_fast(a_self), + retrieve_task_self_fast(a_self->task), + exception, + code, codeCnt, + &flavor, + state, state_cnt, + state, &state_cnt); + if (kr == MACH_MSG_SUCCESS) + kr = thread_setstatus(a_self, flavor, + (thread_state_t)state, + state_cnt); + } + + if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED) + return(KERN_SUCCESS); + return(KERN_FAILURE); + } + + default: + + return(KERN_FAILURE); + }/* switch */ + return(KERN_FAILURE); +} + diff --git a/osfmk/kern/host.c b/osfmk/kern/host.c index 283dfa4cf..2d13930a1 100644 --- a/osfmk/kern/host.c +++ b/osfmk/kern/host.c @@ -229,16 +229,9 @@ host_info( } /* - * JMM - Temporary check to see if semaphore traps are - * supported on this machine. Sadly, just trying to call - * the traps gets your process terminated instead of - * returning an error, so we have to query during mach_init - * to see if the machine supports them. - * - * KERN_INVALID_ARGUMENT - kernel has no semaphore traps - * KERN_SUCCESS - kernel has sema traps (up to semaphore_signal_wait) - * KERN_SEMAPHORE_DESTROYED - kernel has the latest semaphore traps + * Gestalt for various trap facilities. */ + case HOST_MACH_MSG_TRAP: case HOST_SEMAPHORE_TRAPS: { *count = 0; @@ -265,7 +258,7 @@ host_statistics( case HOST_LOAD_INFO: { register host_load_info_t load_info; - extern integer_t avenrun[3], mach_factor[3]; + extern uint32_t avenrun[3], mach_factor[3]; if (*count < HOST_LOAD_INFO_COUNT) return(KERN_FAILURE); diff --git a/osfmk/kern/host.h b/osfmk/kern/host.h index de71e5790..1318ec508 100644 --- a/osfmk/kern/host.h +++ b/osfmk/kern/host.h @@ -47,8 +47,6 @@ * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ -/* - */ /* * kern/host.h @@ -61,12 +59,17 @@ #define _KERN_HOST_H_ #include -#include -#include + +#include + +#ifdef __APPLE_API_PRIVATE #ifdef MACH_KERNEL_PRIVATE #include #include +#include +#include + struct host { decl_mutex_data(,lock) /* lock to protect exceptions */ @@ -86,6 +89,8 @@ extern host_data_t realhost; #endif /* MACH_KERNEL_PRIVATE */ +#endif /* __APPLE_API_PRIVATE */ + /* * Access routines for inside the kernel. */ diff --git a/osfmk/kern/ipc_kobject.c b/osfmk/kern/ipc_kobject.c index 4aeba476a..95fbf3885 100644 --- a/osfmk/kern/ipc_kobject.c +++ b/osfmk/kern/ipc_kobject.c @@ -64,29 +64,23 @@ #include #include -#include +#include #include #include #include #include #include + #include #include #include #include #include -#include #include #include #include -void pager_mux_hash_delete( - ipc_port_t port); -rpc_subsystem_t pager_mux_hash_lookup( - ipc_port_t port); - - /* * Routine: ipc_kobject_notify * Purpose: @@ -150,40 +144,40 @@ mach_msg_size_t mig_reply_size; #endif /* XK_PROXY */ -rpc_subsystem_t mig_e[] = { - (rpc_subsystem_t)&mach_port_subsystem, - (rpc_subsystem_t)&mach_host_subsystem, - (rpc_subsystem_t)&host_priv_subsystem, - (rpc_subsystem_t)&host_security_subsystem, - (rpc_subsystem_t)&clock_subsystem, - (rpc_subsystem_t)&clock_priv_subsystem, - (rpc_subsystem_t)&processor_subsystem, - (rpc_subsystem_t)&processor_set_subsystem, - (rpc_subsystem_t)&is_iokit_subsystem, - (rpc_subsystem_t)&memory_object_name_subsystem, - (rpc_subsystem_t)&lock_set_subsystem, - (rpc_subsystem_t)&ledger_subsystem, - (rpc_subsystem_t)&semaphore_subsystem, - (rpc_subsystem_t)&task_subsystem, - (rpc_subsystem_t)&thread_act_subsystem, - (rpc_subsystem_t)&vm_map_subsystem, - (rpc_subsystem_t)&UNDReply_subsystem, +mig_subsystem_t mig_e[] = { + (mig_subsystem_t)&mach_port_subsystem, + (mig_subsystem_t)&mach_host_subsystem, + (mig_subsystem_t)&host_priv_subsystem, + (mig_subsystem_t)&host_security_subsystem, + (mig_subsystem_t)&clock_subsystem, + (mig_subsystem_t)&clock_priv_subsystem, + (mig_subsystem_t)&processor_subsystem, + (mig_subsystem_t)&processor_set_subsystem, + (mig_subsystem_t)&is_iokit_subsystem, + (mig_subsystem_t)&memory_object_name_subsystem, + (mig_subsystem_t)&lock_set_subsystem, + (mig_subsystem_t)&ledger_subsystem, + (mig_subsystem_t)&semaphore_subsystem, + (mig_subsystem_t)&task_subsystem, + (mig_subsystem_t)&thread_act_subsystem, + (mig_subsystem_t)&vm_map_subsystem, + (mig_subsystem_t)&UNDReply_subsystem, #if XK_PROXY - (rpc_subsystem_t)&do_uproxy_xk_uproxy_subsystem, + (mig_subsystem_t)&do_uproxy_xk_uproxy_subsystem, #endif /* XK_PROXY */ #if MACH_MACHINE_ROUTINES - (rpc_subsystem_t)&MACHINE_SUBSYSTEM, + (mig_subsystem_t)&MACHINE_SUBSYSTEM, #endif /* MACH_MACHINE_ROUTINES */ #if MCMSG && iPSC860 - (rpc_subsystem_t)&mcmsg_info_subsystem, + (mig_subsystem_t)&mcmsg_info_subsystem, #endif /* MCMSG && iPSC860 */ }; void mig_init(void) { - register unsigned int i, n = sizeof(mig_e)/sizeof(rpc_subsystem_t); + register unsigned int i, n = sizeof(mig_e)/sizeof(mig_subsystem_t); register unsigned int howmany; register mach_msg_id_t j, pos, nentry, range; @@ -354,7 +348,7 @@ ipc_kobject_server( break; default: - panic("ipc_object_destroy: strange destination rights"); + panic("ipc_kobject_server: strange destination rights"); } *destp = IP_NULL; @@ -509,7 +503,7 @@ ipc_kobject_notify( mach_msg_header_t *reply_header) { ipc_port_t port = (ipc_port_t) request_header->msgh_remote_port; - rpc_subsystem_t paging_subsystem_object; + mig_subsystem_t paging_subsystem_object; mach_port_seqno_t seqno; ((mig_reply_error_t *) reply_header)->RetCode = MIG_NO_REPLY; @@ -594,7 +588,7 @@ kobjserver_stats_clear(void) void kobjserver_stats(void) { - register unsigned int i, n = sizeof(mig_e)/sizeof(rpc_subsystem_t); + register unsigned int i, n = sizeof(mig_e)/sizeof(mig_subsystem_t); register unsigned int howmany; register mach_msg_id_t j, pos, nentry, range; diff --git a/osfmk/kern/ipc_mig.c b/osfmk/kern/ipc_mig.c index 2b22fcf1f..903215823 100644 --- a/osfmk/kern/ipc_mig.c +++ b/osfmk/kern/ipc_mig.c @@ -50,9 +50,6 @@ /* */ -#include -#include - #include #include #include @@ -148,13 +145,9 @@ mach_msg_rpc_from_kernel( if (mr != MACH_MSG_SUCCESS) return mr; - rpc_lock(self); - reply = self->ith_rpc_reply; if (reply == IP_NULL) { - rpc_unlock(self); reply = ipc_port_alloc_reply(); - rpc_lock(self); if ((reply == IP_NULL) || (self->ith_rpc_reply != IP_NULL)) panic("mach_msg_rpc_from_kernel"); @@ -167,7 +160,6 @@ mach_msg_rpc_from_kernel( MACH_MSGH_BITS(0, MACH_MSG_TYPE_MAKE_SEND_ONCE); ipc_port_reference(reply); - rpc_unlock(self); ipc_kmsg_copyin_from_kernel(kmsg); @@ -439,9 +431,9 @@ mig_put_reply_port( */ int mig_strncpy( - char *dest, - char *src, - int len) + char *dest, + const char *src, + int len) { int i = 0; @@ -589,9 +581,8 @@ convert_mig_object_to_port( assert(previous == IP_NULL); - if (OSCompareAndSwap((UInt32)IP_NULL, - (UInt32)port, - (UInt32 *)&mig_object->port)) { + if (hw_compare_and_store((uint32_t)IP_NULL, (uint32_t)port, + (uint32_t *)&mig_object->port)) { deallocate = FALSE; } else { ipc_port_dealloc_kernel(port); diff --git a/osfmk/kern/ipc_mig.h b/osfmk/kern/ipc_mig.h index 72a7afa13..e962d46f1 100644 --- a/osfmk/kern/ipc_mig.h +++ b/osfmk/kern/ipc_mig.h @@ -126,6 +126,9 @@ extern mach_msg_return_t mach_msg_rpc_from_kernel( extern void mach_msg_receive_continue(void); +#include + +#ifdef __APPLE_API_EVOLVING /* * Kernel implementation of the MIG object base class * @@ -151,5 +154,6 @@ typedef struct mig_notify_object { mach_port_t port; /* our port pointer */ } mig_notify_object_data_t; +#endif /* __APPLE_API_EVOLVING */ #endif /* _IPC_MIG_H_ */ diff --git a/osfmk/kern/ipc_subsystem.c b/osfmk/kern/ipc_subsystem.c deleted file mode 100644 index 125a0b6f5..000000000 --- a/osfmk/kern/ipc_subsystem.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * @OSF_COPYRIGHT@ - */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:34 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.2 1998/04/29 17:35:56 mburg - * MK7.3 merger - * - * Revision 1.1.10.1 1998/02/03 09:28:28 gdt - * Merge up to MK7.3 - * [1998/02/03 09:13:40 gdt] - * - * Revision 1.1.8.1 1997/06/17 02:57:46 devrcs - * Added `ipc_subsystem_terminate().' - * [1997/03/18 18:25:52 rkc] - * - * Revision 1.1.5.1 1994/09/23 02:19:57 ezf - * change marker to not FREE - * [1994/09/22 21:33:39 ezf] - * - * Revision 1.1.3.1 1994/01/20 11:05:46 emcmanus - * Copied for submission. - * [1994/01/20 11:04:25 emcmanus] - * - * Revision 1.1.1.2 1994/01/13 02:40:32 condict - * IPC support for the RPC subsytem object (server co-location). - * - * $EndLog$ - */ - -/* - * File: kern/ipc_subsystem.c - * Purpose: Routines to support ipc semantics of new kernel - * RPC subsystem descriptions - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Routine: ipc_subsystem_init - * Purpose: - * Initialize ipc control of a subsystem. - */ -void -ipc_subsystem_init( - subsystem_t subsystem) -{ - ipc_port_t port; - - port = ipc_port_alloc_kernel(); - if (port == IP_NULL) - panic("ipc_subsystem_init"); - subsystem->ipc_self = port; -} - -/* - * Routine: ipc_subsystem_enable - * Purpose: - * Enable ipc access to a subsystem. - */ -void -ipc_subsystem_enable( - subsystem_t subsystem) -{ - ipc_kobject_set(subsystem->ipc_self, - (ipc_kobject_t) subsystem, IKOT_SUBSYSTEM); -} - - -/* - * Routine: ipc_subsystem_disable - * Purpose: - * Disable IPC access to a subsystem. - * Conditions: - * Nothing locked. - */ - -void -ipc_subsystem_disable( - subsystem_t subsystem) -{ - ipc_port_t kport; - - kport = subsystem->ipc_self; - if (kport != IP_NULL) - ipc_kobject_set(kport, IKO_NULL, IKOT_NONE); -} - -/* - * Routine: ipc_subsystem_terminate - * Purpose: - * Clean up and destroy a subsystem's IPC state. - */ -void -ipc_subsystem_terminate( - subsystem_t subsystem) -{ - ipc_port_dealloc_kernel(subsystem->ipc_self); -} - - -/* - * Routine: convert_port_to_subsystem - * Purpose: - * Convert from a port to a subsystem. - * Doesn't consume the port ref; produces a subsystem ref, - * which may be null. - * Conditions: - * Nothing locked. - */ -subsystem_t -convert_port_to_subsystem( - ipc_port_t port) -{ - subsystem_t subsystem = SUBSYSTEM_NULL; - - if (IP_VALID(port)) { - ip_lock(port); - if (ip_active(port) && - (ip_kotype(port) == IKOT_SUBSYSTEM)) { - subsystem = (subsystem_t) port->ip_kobject; - } - ip_unlock(port); - } - return (subsystem); -} - - -/* - * Routine: convert_subsystem_to_port - * Purpose: - * Convert from a subsystem to a port. - * Produces a naked send right which may be invalid. - * Conditions: - * Nothing locked. - */ -ipc_port_t -convert_subsystem_to_port( - subsystem_t subsystem) -{ - ipc_port_t port; - - port = ipc_port_make_send(subsystem->ipc_self); - return (port); -} - diff --git a/osfmk/kern/ipc_subsystem.h b/osfmk/kern/ipc_subsystem.h deleted file mode 100644 index bcd7cf284..000000000 --- a/osfmk/kern/ipc_subsystem.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * @OSF_COPYRIGHT@ - */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:34 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.1.1.1 1998/03/07 02:25:55 wsanchez - * Import of OSF Mach kernel (~mburg) - * - * Revision 1.1.5.1 1994/09/23 02:20:11 ezf - * change marker to not FREE - * [1994/09/22 21:33:42 ezf] - * - * Revision 1.1.3.1 1994/01/20 11:05:50 emcmanus - * Copied for submission. - * [1994/01/20 11:04:35 emcmanus] - * - * Revision 1.1.1.2 1994/01/13 02:41:12 condict - * Declarations for kern/ipc_subsystem.c - * - * $EndLog$ - */ - -#ifndef _KERN_IPC_SUBSYSTEM_H_ -#define _KERN_IPC_SUBSYSTEM_H_ - -#include -#include -#include -#include -#include - - -/* Initialize a subsystem's IPC state */ -extern void ipc_subsystem_init( - subsystem_t subsystem); - -/* Enable a subsystem for IPC access */ -extern void ipc_subsystem_enable( - subsystem_t subsystem); - -/* Disable IPC access to a subsystem */ -extern void ipc_subsystem_disable( - subsystem_t subsystem); - -/* Clean up and destroy a subsystem's IPC state */ -extern void ipc_subsystem_terminate( - subsystem_t subsystem); - -/* Convert from a port to a subsystem */ -extern subsystem_t convert_port_to_subsystem( - ipc_port_t port); - -/* Convert from a subsystem to a port */ -extern ipc_port_t convert_subsystem_to_port( - subsystem_t subsystem); - -#endif /* _KERN_IPC_SUBSYSTEM_H_ */ diff --git a/osfmk/kern/ipc_tt.c b/osfmk/kern/ipc_tt.c index 4fc95a8bc..f387287a5 100644 --- a/osfmk/kern/ipc_tt.c +++ b/osfmk/kern/ipc_tt.c @@ -116,8 +116,6 @@ ipc_task_init( for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { task->exc_actions[i].port = IP_NULL; }/* for */ - task->exc_actions[EXC_MACH_SYSCALL].port = - ipc_port_make_send(realhost.host_self); task->itk_host = ipc_port_make_send(realhost.host_self); task->itk_bootstrap = IP_NULL; for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) @@ -309,9 +307,6 @@ ipc_thr_act_init(task_t task, thread_act_t thr_act) for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) thr_act->exc_actions[i].port = IP_NULL; - thr_act->exc_actions[EXC_MACH_SYSCALL].port = - ipc_port_make_send(realhost.host_self); - ipc_kobject_set(kport, (ipc_kobject_t) thr_act, IKOT_ACT); } diff --git a/osfmk/kern/kalloc.h b/osfmk/kern/kalloc.h index df89dd686..657848b41 100644 --- a/osfmk/kern/kalloc.h +++ b/osfmk/kern/kalloc.h @@ -47,42 +47,44 @@ * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ -/* - */ #ifndef _KERN_KALLOC_H_ #define _KERN_KALLOC_H_ - #include #define KALLOC_MINSIZE 16 extern vm_offset_t kalloc( - vm_size_t size); + vm_size_t size); -extern vm_offset_t kalloc_noblock( - vm_size_t size); +extern vm_offset_t kalloc_noblock( + vm_size_t size); extern vm_offset_t kget( - vm_size_t size); + vm_size_t size); -extern void kfree( - vm_offset_t data, - vm_size_t size); +extern void kfree( + vm_offset_t data, + vm_size_t size); + +#include + +#ifdef __APPLE_API_PRIVATE #ifdef MACH_KERNEL_PRIVATE #include -extern void kalloc_init( - void); +extern void kalloc_init(void); extern void krealloc( - vm_offset_t *addrp, - vm_size_t old_size, - vm_size_t new_size, - simple_lock_t lock); + vm_offset_t *addrp, + vm_size_t old_size, + vm_size_t new_size, + simple_lock_t lock); #endif /* MACH_KERNEL_PRIVATE */ +#endif /* __APPLE_APPI_PRIVATE */ + #endif /* _KERN_KALLOC_H_ */ diff --git a/osfmk/kern/kern_types.h b/osfmk/kern/kern_types.h index 8d0ab03d2..13f58fb74 100644 --- a/osfmk/kern/kern_types.h +++ b/osfmk/kern/kern_types.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002,2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -26,12 +26,11 @@ #ifndef _KERN_KERN_TYPES_H_ #define _KERN_KERN_TYPES_H_ -#ifdef KERNEL_PRIVATE - #include - +#include #include -#include + +#include #if !defined(MACH_KERNEL_PRIVATE) @@ -41,67 +40,100 @@ * of type checking, without exposing our internal data * structures. */ -struct thread_shuttle ; -struct task ; -struct host ; -struct processor ; -struct processor_set ; -struct thread_activation ; -struct subsystem ; -struct semaphore ; -struct lock_set ; -struct ledger ; -struct alarm ; -struct clock ; + struct zone ; -struct wait_queue_sub ; -struct wait_queue_link; +struct wait_queue { unsigned int opaque[2]; uintptr_t opaquep[2]; } ; + + +#endif /* MACH_KERNEL_PRIVATE */ + -#else /* MACH_KERNEL_PRIVATE */ +typedef struct zone *zone_t; +#define ZONE_NULL ((zone_t) 0) + +typedef struct wait_queue *wait_queue_t; +#define WAIT_QUEUE_NULL ((wait_queue_t) 0) +#define SIZEOF_WAITQUEUE sizeof(struct wait_queue) + +typedef vm_offset_t ipc_kobject_t; +#define IKO_NULL ((ipc_kobject_t) 0) + +typedef void *event_t; /* wait event */ +#define NO_EVENT ((event_t) 0) + +typedef uint64_t event64_t; /* 64 bit wait event */ +#define NO_EVENT64 ((event64_t) 0) + +/* + * Possible wait_result_t values. + */ +typedef int wait_result_t; +#define THREAD_WAITING -1 /* thread is waiting */ +#define THREAD_AWAKENED 0 /* normal wakeup */ +#define THREAD_TIMED_OUT 1 /* timeout expired */ +#define THREAD_INTERRUPTED 2 /* aborted/interrupted */ +#define THREAD_RESTART 3 /* restart operation entirely */ + + +typedef void (*thread_continue_t)(void); /* where to resume it */ +#define THREAD_CONTINUE_NULL ((thread_continue_t) 0) + +/* + * Interruptible flag for waits. + */ +typedef int wait_interrupt_t; +#define THREAD_UNINT 0 /* not interruptible */ +#define THREAD_INTERRUPTIBLE 1 /* may not be restartable */ +#define THREAD_ABORTSAFE 2 /* abortable safely */ + +#ifdef __APPLE_API_PRIVATE + +#ifdef MACH_KERNEL_PRIVATE #include -typedef struct clock *clock_t; /* Internal use only */ +typedef struct clock *clock_t; -#endif /* MACH_KERNEL_PRIVATE */ +#endif /* MACH_KERNEL_PRIVATE */ + +#ifdef __APPLE_API_EVOLVING + +#ifndef MACH_KERNEL_PRIVATE +struct wait_queue_set ; +struct wait_queue_link ; +#endif + +typedef struct wait_queue_set *wait_queue_set_t; +#define WAIT_QUEUE_SET_NULL ((wait_queue_set_t)0) +#define SIZEOF_WAITQUEUE_SET wait_queue_set_size() + +typedef struct wait_queue_link *wait_queue_link_t; +#define WAIT_QUEUE_LINK_NULL ((wait_queue_link_t)0) +#define SIZEOF_WAITQUEUE_LINK wait_queue_link_size() typedef struct mig_object *mig_object_t; +#define MIG_OBJECT_NULL ((mig_object_t) 0) + typedef struct mig_notify *mig_notify_t; -typedef struct thread_shuttle *thread_t; -typedef struct thread_shuttle *thread_shuttle_t; -typedef struct task *task_t; -typedef struct host *host_t; -typedef struct processor *processor_t; -typedef struct processor_set *processor_set_t; -typedef struct thread_activation *thread_act_t; -typedef struct subsystem *subsystem_t; -typedef struct semaphore *semaphore_t; -typedef struct lock_set *lock_set_t; -typedef struct ledger *ledger_t; -typedef struct alarm *alarm_t; -typedef struct clock *clock_serv_t; -typedef struct clock *clock_ctrl_t; -typedef struct zone *zone_t; -typedef struct wait_queue *wait_queue_t; -typedef struct wait_queue_sub *wait_queue_sub_t; -typedef struct wait_queue_link *wait_queue_link_t; +#define MIG_NOTIFY_NULL ((mig_notify_t) 0) -typedef host_t host_priv_t; -typedef host_t host_security_t; -typedef processor_set_t processor_set_name_t; -typedef vm_offset_t ipc_kobject_t; +typedef boolean_t (*thread_roust_t)(wait_result_t); /* how to roust it */ +#define THREAD_ROUST_NULL ((thread_roust_t) 0) -typedef void *event_t; /* wait event */ -typedef void (*continuation_t)(void); /* continuation */ +#endif /* __APPLE_API_EVOLVING */ -#define ZONE_NULL ((zone_t) 0) +#ifdef __APPLE_API_UNSTABLE -#define NO_EVENT ((event_t) 0) -#define WAIT_QUEUE_NULL ((wait_queue_t) 0) +typedef struct thread_shuttle *thread_shuttle_t; +#define THREAD_SHUTTLE_NULL ((thread_shuttle_t)0) + +/* legacy definitions - going away */ +struct wait_queue_sub ; +typedef struct wait_queue_sub *wait_queue_sub_t; +#define WAIT_QUEUE_SUB_NULL ((wait_queue_sub_t)0) +#define SIZEOF_WAITQUEUE_SUB wait_queue_set_size() -#define IKO_NULL ((ipc_kobject_t) 0) -#define MIG_OBJECT_NULL ((mig_object_t) 0) -#define MIG_NOTIFY_NULL ((mig_notify_t) 0) +#endif /* __APPLE_API_UNSTABLE */ -#endif /* KERNEL_PRIVATE */ +#endif /* __APPLE_API_PRIVATE */ #endif /* _KERN_KERN_TYPES_H_ */ diff --git a/osfmk/kern/kmod.c b/osfmk/kern/kmod.c index 4aa0f1037..0de60c5ce 100644 --- a/osfmk/kern/kmod.c +++ b/osfmk/kern/kmod.c @@ -33,9 +33,12 @@ #include #include #include +#include #include +#define WRITE_PROTECT_MODULE_TEXT (0) + kmod_info_t *kmod = 0; static int kmod_index = 1; @@ -43,47 +46,95 @@ decl_simple_lock_data(,kmod_lock) decl_simple_lock_data(,kmod_queue_lock) typedef struct cmd_queue_entry { - queue_chain_t links; - vm_address_t data; - vm_size_t size; + queue_chain_t links; + vm_address_t data; + vm_size_t size; } cmd_queue_entry_t; -queue_head_t kmod_cmd_queue; +queue_head_t kmod_cmd_queue; void kmod_init() { - simple_lock_init(&kmod_lock, ETAP_MISC_Q); - simple_lock_init(&kmod_queue_lock, ETAP_MISC_Q); - queue_init(&kmod_cmd_queue); + simple_lock_init(&kmod_lock, ETAP_MISC_Q); + simple_lock_init(&kmod_queue_lock, ETAP_MISC_Q); + queue_init(&kmod_cmd_queue); } kmod_info_t * kmod_lookupbyid(kmod_t id) { - kmod_info_t *k = 0; + kmod_info_t *k = 0; - k = kmod; - while (k) { - if (k->id == id) break; - k = k->next; - } + k = kmod; + while (k) { + if (k->id == id) break; + k = k->next; + } - return k; + return k; } kmod_info_t * kmod_lookupbyname(const char * name) { - kmod_info_t *k = 0; + kmod_info_t *k = 0; - k = kmod; - while (k) { - if (!strcmp(k->name, name)) break; - k = k->next; - } + k = kmod; + while (k) { + if (!strcmp(k->name, name)) break; + k = k->next; + } - return k; + return k; +} + +kmod_info_t * +kmod_lookupbyid_locked(kmod_t id) +{ + kmod_info_t *k = 0; + kmod_info_t *kc = 0; + + kc = (kmod_info_t *)kalloc(sizeof(kmod_info_t)); + if (!kc) return kc; + + simple_lock(&kmod_queue_lock); + k = kmod_lookupbyid(id); + if (k) { + bcopy((char*)k, (char *)kc, sizeof(kmod_info_t)); + } +finish: + simple_unlock(&kmod_queue_lock); + + if (k == 0) { + kfree((vm_offset_t)kc, sizeof(kmod_info_t)); + kc = 0; + } + return kc; +} + +kmod_info_t * +kmod_lookupbyname_locked(const char * name) +{ + kmod_info_t *k = 0; + kmod_info_t *kc = 0; + + kc = (kmod_info_t *)kalloc(sizeof(kmod_info_t)); + if (!kc) return kc; + + simple_lock(&kmod_queue_lock); + k = kmod_lookupbyname(name); + if (k) { + bcopy((char *)k, (char *)kc, sizeof(kmod_info_t)); + } +finish: + simple_unlock(&kmod_queue_lock); + + if (k == 0) { + kfree((vm_offset_t)kc, sizeof(kmod_info_t)); + kc = 0; + } + return kc; } // XXX add a nocopy flag?? @@ -91,252 +142,263 @@ kmod_lookupbyname(const char * name) kern_return_t kmod_queue_cmd(vm_address_t data, vm_size_t size) { - kern_return_t rc; - cmd_queue_entry_t *e = (cmd_queue_entry_t *)kalloc(sizeof(struct cmd_queue_entry)); - if (!e) return KERN_RESOURCE_SHORTAGE; - - rc = kmem_alloc(kernel_map, &e->data, size); - if (rc != KERN_SUCCESS) { - kfree((vm_offset_t)e, sizeof(struct cmd_queue_entry)); - return rc; - } - e->size = size; - bcopy((void *)data, (void *)e->data, size); + kern_return_t rc; + cmd_queue_entry_t *e = (cmd_queue_entry_t *)kalloc(sizeof(struct cmd_queue_entry)); + if (!e) return KERN_RESOURCE_SHORTAGE; + + rc = kmem_alloc(kernel_map, &e->data, size); + if (rc != KERN_SUCCESS) { + kfree((vm_offset_t)e, sizeof(struct cmd_queue_entry)); + return rc; + } + e->size = size; + bcopy((void *)data, (void *)e->data, size); - simple_lock(&kmod_queue_lock); - enqueue_tail(&kmod_cmd_queue, (queue_entry_t)e); - simple_unlock(&kmod_queue_lock); + simple_lock(&kmod_queue_lock); + enqueue_tail(&kmod_cmd_queue, (queue_entry_t)e); + simple_unlock(&kmod_queue_lock); - thread_wakeup_one((event_t)&kmod_cmd_queue); - - return KERN_SUCCESS; + thread_wakeup_one((event_t)&kmod_cmd_queue); + + return KERN_SUCCESS; } kern_return_t kmod_load_extension(char *name) { - kmod_load_extension_cmd_t *data; - vm_size_t size; + kmod_load_extension_cmd_t *data; + vm_size_t size; - size = sizeof(kmod_load_extension_cmd_t); - data = (kmod_load_extension_cmd_t *)kalloc(size); - if (!data) return KERN_RESOURCE_SHORTAGE; + size = sizeof(kmod_load_extension_cmd_t); + data = (kmod_load_extension_cmd_t *)kalloc(size); + if (!data) return KERN_RESOURCE_SHORTAGE; - data->type = KMOD_LOAD_EXTENSION_PACKET; - strncpy(data->name, name, KMOD_MAX_NAME); + data->type = KMOD_LOAD_EXTENSION_PACKET; + strncpy(data->name, name, KMOD_MAX_NAME); - return kmod_queue_cmd((vm_address_t)data, size); + return kmod_queue_cmd((vm_address_t)data, size); } kern_return_t kmod_load_extension_with_dependencies(char *name, char **dependencies) { - kmod_load_with_dependencies_cmd_t *data; - vm_size_t size; - char **c; - int i, count = 0; - - c = dependencies; - if (c) { - while (*c) { - count++; c++; - } - } - size = sizeof(int) + KMOD_MAX_NAME * (count + 1) + 1; - data = (kmod_load_with_dependencies_cmd_t *)kalloc(size); - if (!data) return KERN_RESOURCE_SHORTAGE; + kmod_load_with_dependencies_cmd_t *data; + vm_size_t size; + char **c; + int i, count = 0; + + c = dependencies; + if (c) { + while (*c) { + count++; c++; + } + } + size = sizeof(int) + KMOD_MAX_NAME * (count + 1) + 1; + data = (kmod_load_with_dependencies_cmd_t *)kalloc(size); + if (!data) return KERN_RESOURCE_SHORTAGE; - data->type = KMOD_LOAD_WITH_DEPENDENCIES_PACKET; - strncpy(data->name, name, KMOD_MAX_NAME); + data->type = KMOD_LOAD_WITH_DEPENDENCIES_PACKET; + strncpy(data->name, name, KMOD_MAX_NAME); - c = dependencies; - for (i=0; i < count; i++) { - strncpy(data->dependencies[i], *c, KMOD_MAX_NAME); - c++; - } - data->dependencies[count][0] = 0; + c = dependencies; + for (i=0; i < count; i++) { + strncpy(data->dependencies[i], *c, KMOD_MAX_NAME); + c++; + } + data->dependencies[count][0] = 0; - return kmod_queue_cmd((vm_address_t)data, size); + return kmod_queue_cmd((vm_address_t)data, size); } kern_return_t kmod_send_generic(int type, void *generic_data, int size) { - kmod_generic_cmd_t *data; + kmod_generic_cmd_t *data; - data = (kmod_generic_cmd_t *)kalloc(size + sizeof(int)); - if (!data) return KERN_RESOURCE_SHORTAGE; + data = (kmod_generic_cmd_t *)kalloc(size + sizeof(int)); + if (!data) return KERN_RESOURCE_SHORTAGE; - data->type = type; - bcopy(data->data, generic_data, size); + data->type = type; + bcopy(data->data, generic_data, size); - return kmod_queue_cmd((vm_address_t)data, size + sizeof(int)); + return kmod_queue_cmd((vm_address_t)data, size + sizeof(int)); } kern_return_t kmod_create_internal(kmod_info_t *info, kmod_t *id) { - kern_return_t rc; + kern_return_t rc; - if (!info) return KERN_INVALID_ADDRESS; + if (!info) return KERN_INVALID_ADDRESS; - // double check for page alignment - if ((info->address | info->hdr_size) & (PAGE_SIZE - 1)) { - return KERN_INVALID_ADDRESS; - } + // double check for page alignment + if ((info->address | info->hdr_size) & (PAGE_SIZE - 1)) { + return KERN_INVALID_ADDRESS; + } - rc = vm_map_wire(kernel_map, info->address + info->hdr_size, - info->address + info->size, VM_PROT_DEFAULT, FALSE); - if (rc != KERN_SUCCESS) { - return rc; + rc = vm_map_wire(kernel_map, info->address + info->hdr_size, + info->address + info->size, VM_PROT_DEFAULT, FALSE); + if (rc != KERN_SUCCESS) { + return rc; + } +#if WRITE_PROTECT_MODULE_TEXT + { + struct section * sect = getsectbynamefromheader( + (struct mach_header*) info->address, "__TEXT", "__text"); + + if(sect) { + (void) vm_map_protect(kernel_map, round_page(sect->addr), trunc_page(sect->addr + sect->size), + VM_PROT_READ|VM_PROT_EXECUTE, TRUE); } + } +#endif - simple_lock(&kmod_lock); + simple_lock(&kmod_lock); - // check to see if already loaded - if (kmod_lookupbyname(info->name)) { - simple_unlock(&kmod_lock); - rc = vm_map_unwire(kernel_map, info->address + info->hdr_size, - info->address + info->size, FALSE); - assert(rc == KERN_SUCCESS); - return KERN_INVALID_ARGUMENT; - } + // check to see if already loaded + if (kmod_lookupbyname(info->name)) { + simple_unlock(&kmod_lock); + rc = vm_map_unwire(kernel_map, info->address + info->hdr_size, + info->address + info->size, FALSE); + assert(rc == KERN_SUCCESS); + return KERN_INVALID_ARGUMENT; + } - info->id = kmod_index++; - info->reference_count = 0; + info->id = kmod_index++; + info->reference_count = 0; - info->next = kmod; - kmod = info; + info->next = kmod; + kmod = info; - *id = info->id; + *id = info->id; - simple_unlock(&kmod_lock); + simple_unlock(&kmod_lock); #if DEBUG - printf("kmod_create: %s (id %d), %d pages loaded at 0x%x, header size 0x%x\n", - info->name, info->id, info->size / PAGE_SIZE, info->address, info->hdr_size); + printf("kmod_create: %s (id %d), %d pages loaded at 0x%x, header size 0x%x\n", + info->name, info->id, info->size / PAGE_SIZE, info->address, info->hdr_size); #endif DEBUG - return KERN_SUCCESS; + return KERN_SUCCESS; } kern_return_t kmod_create(host_priv_t host_priv, - kmod_info_t *info, - kmod_t *id) + kmod_info_t *info, + kmod_t *id) { - if (host_priv == HOST_PRIV_NULL) return KERN_INVALID_HOST; - return kmod_create_internal(info, id); + if (host_priv == HOST_PRIV_NULL) return KERN_INVALID_HOST; + return kmod_create_internal(info, id); } kern_return_t -kmod_create_fake(char *name, char *version) +kmod_create_fake(const char *name, const char *version) { - kmod_info_t *info; + kmod_info_t *info; - if (!name || ! version || - (1 + strlen(name) > KMOD_MAX_NAME) || - (1 + strlen(version) > KMOD_MAX_NAME)) { + if (!name || ! version || + (1 + strlen(name) > KMOD_MAX_NAME) || + (1 + strlen(version) > KMOD_MAX_NAME)) { - return KERN_INVALID_ARGUMENT; - } + return KERN_INVALID_ARGUMENT; + } - info = (kmod_info_t *)kalloc(sizeof(kmod_info_t)); - if (!info) { - return KERN_RESOURCE_SHORTAGE; - } + info = (kmod_info_t *)kalloc(sizeof(kmod_info_t)); + if (!info) { + return KERN_RESOURCE_SHORTAGE; + } - // make de fake - info->info_version = KMOD_INFO_VERSION; - bcopy(name, info->name, 1 + strlen(name)); - bcopy(version, info->version, 1 + strlen(version)); //NIK fixed this part - info->reference_count = 1; // keep it from unloading, starting, stopping - info->reference_list = 0; - info->address = info->size = info->hdr_size = 0; - info->start = info->stop = 0; - - simple_lock(&kmod_lock); - - // check to see if already "loaded" - if (kmod_lookupbyname(info->name)) { - simple_unlock(&kmod_lock); - return KERN_INVALID_ARGUMENT; - } + // make de fake + info->info_version = KMOD_INFO_VERSION; + bcopy(name, info->name, 1 + strlen(name)); + bcopy(version, info->version, 1 + strlen(version)); //NIK fixed this part + info->reference_count = 1; // keep it from unloading, starting, stopping + info->reference_list = 0; + info->address = info->size = info->hdr_size = 0; + info->start = info->stop = 0; + + simple_lock(&kmod_lock); - info->id = kmod_index++; + // check to see if already "loaded" + if (kmod_lookupbyname(info->name)) { + simple_unlock(&kmod_lock); + return KERN_INVALID_ARGUMENT; + } - info->next = kmod; - kmod = info; + info->id = kmod_index++; - simple_unlock(&kmod_lock); + info->next = kmod; + kmod = info; - return KERN_SUCCESS; + simple_unlock(&kmod_lock); + + return KERN_SUCCESS; } kern_return_t kmod_destroy_internal(kmod_t id) { - kern_return_t rc; - kmod_info_t *k; - kmod_info_t *p; - - simple_lock(&kmod_lock); - - k = p = kmod; - while (k) { - if (k->id == id) { - kmod_reference_t *r, *t; - - if (k->reference_count != 0) { - simple_unlock(&kmod_lock); - return KERN_INVALID_ARGUMENT; - } - - if (k == p) { // first element - kmod = k->next; - } else { - p->next = k->next; - } - simple_unlock(&kmod_lock); - - r = k->reference_list; - while (r) { - r->info->reference_count--; - t = r; - r = r->next; - kfree((vm_offset_t)t, sizeof(struct kmod_reference)); - } + kern_return_t rc; + kmod_info_t *k; + kmod_info_t *p; + + simple_lock(&kmod_lock); + + k = p = kmod; + while (k) { + if (k->id == id) { + kmod_reference_t *r, *t; + + if (k->reference_count != 0) { + simple_unlock(&kmod_lock); + return KERN_INVALID_ARGUMENT; + } + + if (k == p) { // first element + kmod = k->next; + } else { + p->next = k->next; + } + simple_unlock(&kmod_lock); + + r = k->reference_list; + while (r) { + r->info->reference_count--; + t = r; + r = r->next; + kfree((vm_offset_t)t, sizeof(struct kmod_reference)); + } #if DEBUG - printf("kmod_destroy: %s (id %d), deallocating %d pages starting at 0x%x\n", - k->name, k->id, k->size / PAGE_SIZE, k->address); + printf("kmod_destroy: %s (id %d), deallocating %d pages starting at 0x%x\n", + k->name, k->id, k->size / PAGE_SIZE, k->address); #endif DEBUG - rc = vm_map_unwire(kernel_map, k->address + k->hdr_size, - k->address + k->size, FALSE); - assert(rc == KERN_SUCCESS); + rc = vm_map_unwire(kernel_map, k->address + k->hdr_size, + k->address + k->size, FALSE); + assert(rc == KERN_SUCCESS); - rc = vm_deallocate(kernel_map, k->address, k->size); - assert(rc == KERN_SUCCESS); + rc = vm_deallocate(kernel_map, k->address, k->size); + assert(rc == KERN_SUCCESS); - return KERN_SUCCESS; - } - p = k; - k = k->next; - } + return KERN_SUCCESS; + } + p = k; + k = k->next; + } - simple_unlock(&kmod_lock); + simple_unlock(&kmod_lock); - return KERN_INVALID_ARGUMENT; + return KERN_INVALID_ARGUMENT; } kern_return_t kmod_destroy(host_priv_t host_priv, - kmod_t id) + kmod_t id) { - if (host_priv == HOST_PRIV_NULL) return KERN_INVALID_HOST; - return kmod_destroy_internal(id); + if (host_priv == HOST_PRIV_NULL) return KERN_INVALID_HOST; + return kmod_destroy_internal(id); } @@ -458,16 +520,16 @@ kmod_release(kmod_t id) p = r = f->reference_list; while (r) { if (r->info == t) { - if (p == r) { // first element + if (p == r) { // first element f->reference_list = r->next; } else { p->next = r->next; } r->info->reference_count--; - simple_unlock(&kmod_lock); + simple_unlock(&kmod_lock); kfree((vm_offset_t)r, sizeof(struct kmod_reference)); - rc = KERN_SUCCESS; + rc = KERN_SUCCESS; goto finish; } p = r; @@ -484,325 +546,294 @@ finish: kern_return_t kmod_control(host_priv_t host_priv, - kmod_t id, - kmod_control_flavor_t flavor, - kmod_args_t *data, - mach_msg_type_number_t *dataCount) + kmod_t id, + kmod_control_flavor_t flavor, + kmod_args_t *data, + mach_msg_type_number_t *dataCount) { - kern_return_t rc = KERN_SUCCESS; + kern_return_t rc = KERN_SUCCESS; - if (host_priv == HOST_PRIV_NULL) return KERN_INVALID_HOST; + if (host_priv == HOST_PRIV_NULL) return KERN_INVALID_HOST; - switch (flavor) { + switch (flavor) { - case KMOD_CNTL_START: - case KMOD_CNTL_STOP: - { + case KMOD_CNTL_START: + case KMOD_CNTL_STOP: + { rc = kmod_start_or_stop(id, (flavor == KMOD_CNTL_START), data, dataCount); break; - } + } - case KMOD_CNTL_RETAIN: + case KMOD_CNTL_RETAIN: { rc = kmod_retain(id); break; } - case KMOD_CNTL_RELEASE: + case KMOD_CNTL_RELEASE: { rc = kmod_release(id); break; } - case KMOD_CNTL_GET_CMD: { - - cmd_queue_entry_t *e; - - /* - * Throw away any data the user may have sent in error. - * We must do this, because we are likely to return to - * some data for these commands (thus causing a leak of - * whatever data the user sent us in error). - */ - if (*data && *dataCount) { - vm_map_copy_discard(*data); - *data = 0; - *dataCount = 0; - } - - simple_lock(&kmod_queue_lock); - - if (queue_empty(&kmod_cmd_queue)) { - assert_wait((event_t)&kmod_cmd_queue, THREAD_ABORTSAFE); - simple_unlock(&kmod_queue_lock); - thread_block((void(*)(void))0); - simple_lock(&kmod_queue_lock); - if (queue_empty(&kmod_cmd_queue)) { - // we must have been interrupted! - simple_unlock(&kmod_queue_lock); - return KERN_ABORTED; - } - } - e = (cmd_queue_entry_t *)dequeue_head(&kmod_cmd_queue); - - simple_unlock(&kmod_queue_lock); - - rc = vm_map_copyin(kernel_map, e->data, e->size, TRUE, (vm_map_copy_t *)data); - if (rc) { - simple_lock(&kmod_queue_lock); - enqueue_head(&kmod_cmd_queue, (queue_entry_t)e); - simple_unlock(&kmod_queue_lock); - *data = 0; - *dataCount = 0; - return rc; - } - *dataCount = e->size; - - kfree((vm_offset_t)e, sizeof(struct cmd_queue_entry)); - - break; - } + case KMOD_CNTL_GET_CMD: + { - default: - rc = KERN_INVALID_ARGUMENT; - } + cmd_queue_entry_t *e; + + /* + * Throw away any data the user may have sent in error. + * We must do this, because we are likely to return to + * some data for these commands (thus causing a leak of + * whatever data the user sent us in error). + */ + if (*data && *dataCount) { + vm_map_copy_discard(*data); + *data = 0; + *dataCount = 0; + } + + simple_lock(&kmod_queue_lock); + + if (queue_empty(&kmod_cmd_queue)) { + wait_result_t res; + + res = thread_sleep_simple_lock((event_t)&kmod_cmd_queue, + &kmod_queue_lock, + THREAD_ABORTSAFE); + if (queue_empty(&kmod_cmd_queue)) { + // we must have been interrupted! + simple_unlock(&kmod_queue_lock); + assert(res == THREAD_INTERRUPTED); + return KERN_ABORTED; + } + } + e = (cmd_queue_entry_t *)dequeue_head(&kmod_cmd_queue); + + simple_unlock(&kmod_queue_lock); + + rc = vm_map_copyin(kernel_map, e->data, e->size, TRUE, (vm_map_copy_t *)data); + if (rc) { + simple_lock(&kmod_queue_lock); + enqueue_head(&kmod_cmd_queue, (queue_entry_t)e); + simple_unlock(&kmod_queue_lock); + *data = 0; + *dataCount = 0; + return rc; + } + *dataCount = e->size; + + kfree((vm_offset_t)e, sizeof(struct cmd_queue_entry)); + + break; + } - return rc; + default: + rc = KERN_INVALID_ARGUMENT; + } + + return rc; }; kern_return_t kmod_get_info(host_t host, - kmod_info_array_t *kmods, - mach_msg_type_number_t *kmodCount) + kmod_info_array_t *kmods, + mach_msg_type_number_t *kmodCount) { - vm_offset_t data; - kmod_info_t *k, *p1; - kmod_reference_t *r, *p2; - int ref_count; - unsigned size = 0; - kern_return_t rc = KERN_SUCCESS; + vm_offset_t data; + kmod_info_t *k, *p1; + kmod_reference_t *r, *p2; + int ref_count; + unsigned size = 0; + kern_return_t rc = KERN_SUCCESS; - *kmods = (void *)0; - *kmodCount = 0; + *kmods = (void *)0; + *kmodCount = 0; retry: - simple_lock(&kmod_lock); - size = 0; - k = kmod; - while (k) { - size += sizeof(kmod_info_t); - r = k->reference_list; - while (r) { - size +=sizeof(kmod_reference_t); - r = r->next; - } - k = k->next; - } - simple_unlock(&kmod_lock); - if (!size) return KERN_SUCCESS; - - rc = kmem_alloc(kernel_map, &data, size); - if (rc) return rc; - - // copy kmod into data, retry if kmod's size has changed (grown) - // the copied out data is tweeked to figure what's what at user level - // change the copied out k->next pointers to point to themselves - // change the k->reference into a count, tack the references on - // the end of the data packet in the order they are found - - simple_lock(&kmod_lock); - k = kmod; p1 = (kmod_info_t *)data; - while (k) { - if ((p1 + 1) > (kmod_info_t *)(data + size)) { - simple_unlock(&kmod_lock); - kmem_free(kernel_map, data, size); - goto retry; - } - - *p1 = *k; - if (k->next) p1->next = k; - p1++; k = k->next; - } + simple_lock(&kmod_lock); + size = 0; + k = kmod; + while (k) { + size += sizeof(kmod_info_t); + r = k->reference_list; + while (r) { + size +=sizeof(kmod_reference_t); + r = r->next; + } + k = k->next; + } + simple_unlock(&kmod_lock); + if (!size) return KERN_SUCCESS; - p2 = (kmod_reference_t *)p1; - k = kmod; p1 = (kmod_info_t *)data; - while (k) { - r = k->reference_list; ref_count = 0; - while (r) { - if ((p2 + 1) > (kmod_reference_t *)(data + size)) { - simple_unlock(&kmod_lock); - kmem_free(kernel_map, data, size); - goto retry; - } - // note the last 'k' in the chain has its next == 0 - // since there can only be one like that, - // this case is handled by the caller - *p2 = *r; - p2++; r = r->next; ref_count++; - } - p1->reference_list = (kmod_reference_t *)ref_count; - p1++; k = k->next; - } - simple_unlock(&kmod_lock); - - rc = vm_map_copyin(kernel_map, data, size, TRUE, (vm_map_copy_t *)kmods); - if (rc) { - kmem_free(kernel_map, data, size); - *kmods = 0; - *kmodCount = 0; - return rc; - } - *kmodCount = size; + rc = kmem_alloc(kernel_map, &data, size); + if (rc) return rc; - return KERN_SUCCESS; -} + // copy kmod into data, retry if kmod's size has changed (grown) + // the copied out data is tweeked to figure what's what at user level + // change the copied out k->next pointers to point to themselves + // change the k->reference into a count, tack the references on + // the end of the data packet in the order they are found -#include + simple_lock(&kmod_lock); + k = kmod; p1 = (kmod_info_t *)data; + while (k) { + if ((p1 + 1) > (kmod_info_t *)(data + size)) { + simple_unlock(&kmod_lock); + kmem_free(kernel_map, data, size); + goto retry; + } -extern void *getsectdatafromheader(struct mach_header *mhp, - const char *segname, - const char *sectname, - int *size); + *p1 = *k; + if (k->next) p1->next = k; + p1++; k = k->next; + } + + p2 = (kmod_reference_t *)p1; + k = kmod; p1 = (kmod_info_t *)data; + while (k) { + r = k->reference_list; ref_count = 0; + while (r) { + if ((p2 + 1) > (kmod_reference_t *)(data + size)) { + simple_unlock(&kmod_lock); + kmem_free(kernel_map, data, size); + goto retry; + } + // note the last 'k' in the chain has its next == 0 + // since there can only be one like that, + // this case is handled by the caller + *p2 = *r; + p2++; r = r->next; ref_count++; + } + p1->reference_list = (kmod_reference_t *)ref_count; + p1++; k = k->next; + } + simple_unlock(&kmod_lock); + + rc = vm_map_copyin(kernel_map, data, size, TRUE, (vm_map_copy_t *)kmods); + if (rc) { + kmem_free(kernel_map, data, size); + *kmods = 0; + *kmodCount = 0; + return rc; + } + *kmodCount = size; + + return KERN_SUCCESS; +} static kern_return_t kmod_call_funcs_in_section(struct mach_header *header, const char *sectName) { - typedef void (*Routine)(void); - Routine * routines; - int size, i; + typedef void (*Routine)(void); + Routine * routines; + int size, i; - if (header->magic != MH_MAGIC) { - return KERN_INVALID_ARGUMENT; - } + if (header->magic != MH_MAGIC) { + return KERN_INVALID_ARGUMENT; + } - routines = (Routine *) getsectdatafromheader(header, SEG_TEXT, sectName, &size); - if (!routines) return KERN_SUCCESS; + routines = (Routine *) getsectdatafromheader(header, SEG_TEXT, (char *) sectName, &size); + if (!routines) return KERN_SUCCESS; - size /= sizeof(Routine); - for (i = 0; i < size; i++) { - (*routines[i])(); - } + size /= sizeof(Routine); + for (i = 0; i < size; i++) { + (*routines[i])(); + } - return KERN_SUCCESS; + return KERN_SUCCESS; } kern_return_t kmod_initialize_cpp(kmod_info_t *info) { - return kmod_call_funcs_in_section((struct mach_header *)info->address, "__constructor"); + return kmod_call_funcs_in_section((struct mach_header *)info->address, "__constructor"); } kern_return_t kmod_finalize_cpp(kmod_info_t *info) { - return kmod_call_funcs_in_section((struct mach_header *)info->address, "__destructor"); + return kmod_call_funcs_in_section((struct mach_header *)info->address, "__destructor"); } kern_return_t kmod_default_start(struct kmod_info *ki, void *data) { - return KMOD_RETURN_SUCCESS; + return KMOD_RETURN_SUCCESS; } kern_return_t kmod_default_stop(struct kmod_info *ki, void *data) { - return KMOD_RETURN_SUCCESS; + return KMOD_RETURN_SUCCESS; } -#define IS_IN_BACKTRACE 0xdeadbeef -#define IS_A_DEPENDENCY 0xbeefdead - void kmod_dump(vm_offset_t *addr, unsigned int cnt) { - kmod_info_t *k; - kmod_reference_t *r; - int i, found_one = 0; - - // find backtrace addresses that are inside a kmod - for (i=0; i < cnt; i++, addr++) { - k = kmod; - while (k) { - // XXX - validate page(s) that k points to - if(pmap_extract(kernel_pmap, (vm_offset_t)k) == 0) { /* Exit loop if page not mapped */ - printf(" kmod scan stopped due to missing page: %08X\n", k); - break; - } - if ((*addr >= k->address) && (*addr < (k->address + k->size))) { - // got one, blast info_version, we don't need it at this point - k->info_version = IS_IN_BACKTRACE; - found_one++; - break; - } - k = k->next; - } + vm_offset_t * kscan_addr = 0; + vm_offset_t * rscan_addr = 0; + kmod_info_t * k; + kmod_reference_t * r; + int i, j; + int found_kmod = 0; + int kmod_scan_stopped = 0; + kmod_info_t * stop_kmod = 0; + int ref_scan_stopped = 0; + kmod_reference_t * stop_ref = 0; + + for (k = kmod; k; k = k->next) { + if (!k->address) { + continue; // skip fake entries for built-in kernel components + } + if (pmap_extract(kernel_pmap, (vm_offset_t)k) == 0) { + kdb_printf(" kmod scan stopped due to missing " + "kmod page: %08x\n", stop_kmod); + break; + } + for (i = 0, kscan_addr = addr; i < cnt; i++, kscan_addr++) { + if ((*kscan_addr >= k->address) && + (*kscan_addr < (k->address + k->size))) { + + if (!found_kmod) { + kdb_printf(" Kernel loadable modules in backtrace " + "(with dependencies):\n"); + } + found_kmod = 1; + kdb_printf(" %s(%s)@0x%x\n", + k->name, k->version, k->address); + + for (r = k->reference_list; r; r = r->next) { + kmod_info_t * rinfo; + + if (pmap_extract(kernel_pmap, (vm_offset_t)r) == 0) { + kdb_printf(" kmod dependency scan stopped " + "due to missing dependency page: %08x\n", r); + break; + } + + rinfo = r->info; + + if (!rinfo->address) { + continue; // skip fake entries for built-ins + } + + if (pmap_extract(kernel_pmap, (vm_offset_t)rinfo) == 0) { + kdb_printf(" kmod dependency scan stopped " + "due to missing kmod page: %08x\n", rinfo); + break; + } + + kdb_printf(" dependency: %s(%s)@0x%x\n", + rinfo->name, rinfo->version, rinfo->address); + } + + break; // only report this kmod for one backtrace address + } + } } - if (!found_one) return; - printf(" Kernel loadable modules in backtrace:\n"); - k = kmod; - while (k) { - if(pmap_extract(kernel_pmap, (vm_offset_t)k) == 0) { /* Exit loop if page not mapped */ - printf(" kmod scan stopped due to missing page: %08X\n", k); - break; - } - if (k->info_version == IS_IN_BACKTRACE) { - printf(" %s(%s)@0x%x\n", k->name, k->version, k->address); - } - k = k->next; - } - - // look for dependencies - k = kmod; found_one = 0; - while (k) { - if(pmap_extract(kernel_pmap, (vm_offset_t)k) == 0) { /* Exit loop if page not mapped */ - printf(" kmod dependency scan stopped due to missing page: %08X\n", k); - break; - } - if (k->info_version == IS_IN_BACKTRACE) { - r = k->reference_list; - while (r) { - // XXX - validate page(s) that r and r->info point to - if(pmap_extract(kernel_pmap, (vm_offset_t)r) == 0) { /* Exit loop if page not mapped */ - printf(" kmod validation scan stopped due to missing page: %08X\n", r); - break; - } - if (r->info->info_version != IS_IN_BACKTRACE) { - r->info->info_version = IS_A_DEPENDENCY; - found_one++; - } - r = r->next; - } - } - k = k->next; - } - if (!found_one) goto cleanup; - - printf(" Kernel loadable module dependencies:\n"); - k = kmod; - while (k) { - if(pmap_extract(kernel_pmap, (vm_offset_t)k) == 0) { /* Exit loop if page not mapped */ - printf(" kmod dependency print stopped due to missing page: %08X\n", k); - break; - } - if (k->info_version == IS_A_DEPENDENCY) { - printf(" %s(%s)@0x%x\n", k->name, k->version, k->address); - } - k = k->next; - } - - cleanup: - // in case we double panic - k = kmod; - while (k) { - if(pmap_extract(kernel_pmap, (vm_offset_t)k) == 0) { /* Exit loop if page not mapped */ - printf(" kmod dump cleanup stopped due to missing page: %08X\n", k); - break; - } - k->info_version = KMOD_INFO_VERSION; - k = k->next; - } + return; } diff --git a/osfmk/kern/ledger.h b/osfmk/kern/ledger.h index 9fdd5077b..afad3b628 100644 --- a/osfmk/kern/ledger.h +++ b/osfmk/kern/ledger.h @@ -25,9 +25,18 @@ #ifndef _KERN_LEDGER_H_ #define _KERN_LEDGER_H_ -#include -#include + #include +#include + +#include + +#ifdef __APPLE_API_PRIVATE + +#ifdef MACH_KERNEL_PRIVATE + +#include +#include #define LEDGER_ITEM_INFINITY (~0) @@ -43,8 +52,6 @@ struct ledger { typedef struct ledger ledger_data_t; -#define LEDGER_NULL ((ledger_t)0) - #define ledger_lock(ledger) simple_lock(&(ledger)->lock) #define ledger_unlock(ledger) simple_unlock(&(ledger)->lock) #define ledger_lock_init(ledger) \ @@ -56,10 +63,18 @@ extern ledger_t root_paged_ledger; #define root_wired_ledger_port root_wired_ledger->ledger_self #define root_paged_ledger_port root_paged_ledger->ledger_self -extern ipc_port_t convert_ledger_to_port(ledger_t); +extern void ledger_init(void); + extern ipc_port_t ledger_copy(ledger_t); extern kern_return_t ledger_enter(ledger_t, ledger_item_t); -extern void ledger_init(void); + +#endif /* MACH_KERNEL_PRIVATE */ + +#endif /* __APPLE_API_PRIVATE */ + +extern ledger_t convert_port_to_ledger(ipc_port_t); + +extern ipc_port_t convert_ledger_to_port(ledger_t); #endif /* _KERN_LEDGER_H_ */ diff --git a/osfmk/kern/lock.c b/osfmk/kern/lock.c index 383bf774b..0475b12b0 100644 --- a/osfmk/kern/lock.c +++ b/osfmk/kern/lock.c @@ -63,6 +63,7 @@ #include #include #include +#include #include #include #include @@ -80,6 +81,8 @@ #include #endif +#include + #define ANY_LOCK_DEBUG (USLOCK_DEBUG || LOCK_DEBUG || MUTEX_DEBUG) /* @@ -243,43 +246,9 @@ usimple_lock( ETAP_TIME_CLEAR(start_wait_time); #endif /* ETAP_LOCK_TRACE */ -#ifdef __ppc__ - if(!hw_lock_to(&l->interlock, LockTimeOut)) { /* Try to get the lock with a timeout */ - + if(!hw_lock_to(&l->interlock, LockTimeOut)) /* Try to get the lock with a timeout */ panic("simple lock deadlock detection - l=%08X, cpu=%d, ret=%08X", l, cpu_number(), pc); -#else /* __ppc__ */ - while (!hw_lock_try(&l->interlock)) { - ETAPCALL(if (no_miss_info++ == 0) - start_wait_time = etap_simplelock_miss(l)); - while (hw_lock_held(&l->interlock)) { - /* - * Spin watching the lock value in cache, - * without consuming external bus cycles. - * On most SMP architectures, the atomic - * instruction(s) used by hw_lock_try - * cost much, much more than an ordinary - * memory read. - */ -#if USLOCK_DEBUG - if (count++ > max_lock_loops -#if MACH_KDB && NCPUS > 1 - && l != &kdb_lock -#endif /* MACH_KDB && NCPUS > 1 */ - ) { - if (l == &printf_lock) { - return; - } - mp_disable_preemption(); - panic("simple lock deadlock detection - l=%08X (=%08X), cpu=%d, ret=%08X", - l, *hw_lock_addr(l->interlock), cpu_number(), pc); - count = 0; - mp_enable_preemption(); - } -#endif /* USLOCK_DEBUG */ - } -#endif /* 0 */ - } ETAPCALL(etap_simplelock_hold(l, pc, start_wait_time)); USLDBG(usld_lock_post(l, pc)); } @@ -1084,8 +1053,9 @@ lock_write( ETAP_SET_REASON(current_thread(), BLOCKED_ON_COMPLEX_LOCK); thread_sleep_simple_lock((event_t) l, - simple_lock_addr(l->interlock), FALSE); - simple_lock(&l->interlock); + simple_lock_addr(l->interlock), + THREAD_UNINT); + /* interlock relocked */ } } l->want_write = TRUE; @@ -1119,8 +1089,9 @@ lock_write( ETAP_SET_REASON(current_thread(), BLOCKED_ON_COMPLEX_LOCK); thread_sleep_simple_lock((event_t) l, - simple_lock_addr(l->interlock), FALSE); - simple_lock(&l->interlock); + simple_lock_addr(l->interlock), + THREAD_UNINT); + /* interlock relocked */ } } @@ -1303,8 +1274,9 @@ lock_read( if (l->can_sleep && (l->want_write || l->want_upgrade)) { l->waiting = TRUE; thread_sleep_simple_lock((event_t) l, - simple_lock_addr(l->interlock), FALSE); - simple_lock(&l->interlock); + simple_lock_addr(l->interlock), + THREAD_UNINT); + /* interlock relocked */ } } @@ -1454,8 +1426,9 @@ lock_read_to_write( if (l->can_sleep && l->read_count != 0) { l->waiting = TRUE; thread_sleep_simple_lock((event_t) l, - simple_lock_addr(l->interlock), FALSE); - simple_lock(&l->interlock); + simple_lock_addr(l->interlock), + THREAD_UNINT); + /* interlock relocked */ } } @@ -1715,35 +1688,173 @@ mutex_free( kfree((vm_offset_t)m, sizeof(mutex_t)); } - /* - * mutex_lock_wait: Invoked if the assembler routine mutex_lock () fails - * because the mutex is already held by another thread. Called with the - * interlock locked and returns with the interlock unlocked. + * mutex_lock_wait + * + * Invoked in order to wait on contention. + * + * Called with the interlock locked and + * returns it unlocked. */ - void mutex_lock_wait ( - mutex_t * m) + mutex_t *mutex, + thread_act_t holder) { - m->waiters++; - ETAP_SET_REASON(current_thread(), BLOCKED_ON_MUTEX_LOCK); - thread_sleep_interlock ((event_t) m, &m->interlock, THREAD_UNINT); + thread_t thread, self = current_thread(); +#if !defined(i386) + integer_t priority; + spl_t s = splsched(); + + priority = self->last_processor->current_pri; + if (priority < self->priority) + priority = self->priority; + if (priority > MINPRI_KERNEL) + priority = MINPRI_KERNEL; + else + if (priority < BASEPRI_DEFAULT) + priority = BASEPRI_DEFAULT; + + thread = holder->thread; + assert(thread->top_act == holder); /* XXX */ + thread_lock(thread); + if (mutex->promoted_pri == 0) + thread->promotions++; + if (thread->priority < MINPRI_KERNEL) { + thread->sched_mode |= TH_MODE_PROMOTED; + if ( mutex->promoted_pri < priority && + thread->sched_pri < priority ) { + KERNEL_DEBUG_CONSTANT( + MACHDBG_CODE(DBG_MACH_SCHED,MACH_PROMOTE) | DBG_FUNC_NONE, + thread->sched_pri, priority, (int)thread, (int)mutex, 0); + + set_sched_pri(thread, priority); + } + } + thread_unlock(thread); + splx(s); + + if (mutex->promoted_pri < priority) + mutex->promoted_pri = priority; +#endif + + if (self->pending_promoter[self->pending_promoter_index] == NULL) { + self->pending_promoter[self->pending_promoter_index] = mutex; + mutex->waiters++; + } + else + if (self->pending_promoter[self->pending_promoter_index] != mutex) { + self->pending_promoter[++self->pending_promoter_index] = mutex; + mutex->waiters++; + } + + assert_wait(mutex, THREAD_UNINT); + interlock_unlock(&mutex->interlock); + + thread_block(THREAD_CONTINUE_NULL); } /* - * mutex_unlock_wakeup: Invoked if the assembler routine mutex_unlock () - * fails because there are thread(s) waiting for this mutex. Called and - * returns with the interlock locked. + * mutex_lock_acquire + * + * Invoked on acquiring the mutex when there is + * contention. + * + * Returns the current number of waiters. + * + * Called with the interlock locked. */ +int +mutex_lock_acquire( + mutex_t *mutex) +{ + thread_t thread = current_thread(); + + if (thread->pending_promoter[thread->pending_promoter_index] == mutex) { + thread->pending_promoter[thread->pending_promoter_index] = NULL; + if (thread->pending_promoter_index > 0) + thread->pending_promoter_index--; + mutex->waiters--; + } + +#if !defined(i386) + if (mutex->waiters > 0) { + integer_t priority = mutex->promoted_pri; + spl_t s = splsched(); + + thread_lock(thread); + thread->promotions++; + if (thread->priority < MINPRI_KERNEL) { + thread->sched_mode |= TH_MODE_PROMOTED; + if (thread->sched_pri < priority) { + KERNEL_DEBUG_CONSTANT( + MACHDBG_CODE(DBG_MACH_SCHED,MACH_PROMOTE) | DBG_FUNC_NONE, + thread->sched_pri, priority, 0, (int)mutex, 0); + + set_sched_pri(thread, priority); + } + } + thread_unlock(thread); + splx(s); + } + else + mutex->promoted_pri = 0; +#endif + + return (mutex->waiters); +} +/* + * mutex_unlock_wakeup + * + * Invoked on unlock when there is contention. + * + * Called with the interlock locked. + */ void mutex_unlock_wakeup ( - mutex_t * m) + mutex_t *mutex, + thread_act_t holder) { - assert(m->waiters); - m->waiters--; - thread_wakeup_one ((event_t) m); +#if !defined(i386) + thread_t thread = current_thread(); + + if (thread->top_act != holder) + panic("mutex_unlock_wakeup: mutex %x holder %x\n", mutex, holder); + + if (thread->promotions > 0) { + spl_t s = splsched(); + + thread_lock(thread); + if ( --thread->promotions == 0 && + (thread->sched_mode & TH_MODE_PROMOTED) ) { + thread->sched_mode &= ~TH_MODE_PROMOTED; + if (thread->sched_mode & TH_MODE_ISDEPRESSED) { + KERNEL_DEBUG_CONSTANT( + MACHDBG_CODE(DBG_MACH_SCHED,MACH_DEMOTE) | DBG_FUNC_NONE, + thread->sched_pri, DEPRESSPRI, 0, (int)mutex, 0); + + set_sched_pri(thread, DEPRESSPRI); + } + else { + if (thread->priority < thread->sched_pri) { + KERNEL_DEBUG_CONSTANT( + MACHDBG_CODE(DBG_MACH_SCHED,MACH_DEMOTE) | + DBG_FUNC_NONE, + thread->sched_pri, thread->priority, + 0, (int)mutex, 0); + } + + compute_priority(thread, FALSE); + } + } + thread_unlock(thread); + splx(s); + } +#endif + + assert(mutex->waiters > 0); + thread_wakeup_one(mutex); } /* @@ -1753,13 +1864,15 @@ mutex_unlock_wakeup ( void mutex_pause(void) { - int wait_result; + wait_result_t wait_result; + + wait_result = assert_wait_timeout( 1, THREAD_UNINT); + assert(wait_result == THREAD_WAITING); - assert_wait_timeout( 1, THREAD_INTERRUPTIBLE); ETAP_SET_REASON(current_thread(), BLOCKED_ON_MUTEX_LOCK); - wait_result = thread_block((void (*)(void))0); - if (wait_result != THREAD_TIMED_OUT) - thread_cancel_timer(); + + wait_result = thread_block(THREAD_CONTINUE_NULL); + assert(wait_result == THREAD_TIMED_OUT); } #if MACH_KDB diff --git a/osfmk/kern/lock.h b/osfmk/kern/lock.h index e1143bf86..5119b8959 100644 --- a/osfmk/kern/lock.h +++ b/osfmk/kern/lock.h @@ -19,10 +19,6 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* - * Copyright (C) 1998 Apple Computer - * All Rights Reserved - */ /* * @OSF_COPYRIGHT@ */ @@ -108,13 +104,19 @@ * */ +#include + +#ifdef __APPLE_API_PRIVATE + +#ifdef MACH_KERNEL_PRIVATE + /* * A simple mutex lock. * Do not change the order of the fields in this structure without * changing the machine-dependent assembler routines which depend * on them. */ -#ifdef MACH_KERNEL_PRIVATE + #include #include #include @@ -122,7 +124,8 @@ typedef struct { hw_lock_data_t interlock; hw_lock_data_t locked; - short waiters; + uint16_t waiters; + uint16_t promoted_pri; #if MACH_LDEBUG int type; #define MUTEX_TAG 0x4d4d @@ -151,19 +154,22 @@ typedef struct { #define mutex_addr(m) (&(m)) extern void mutex_init (mutex_t*, etap_event_t); -extern void mutex_lock_wait (mutex_t*); -extern void mutex_unlock_wakeup (mutex_t*); +extern void mutex_lock_wait (mutex_t *, thread_act_t); +extern int mutex_lock_acquire (mutex_t *); +extern void mutex_unlock_wakeup (mutex_t*, thread_act_t); extern void interlock_unlock (hw_lock_t); -#else /* MACH_KERNEL_PRIVATE */ +#endif /* MACH_KERNEL_PRIVATE */ -typedef struct __mutex__ mutex_t; +extern void mutex_pause (void); + +#endif /* __APPLE_API_PRIVATE */ -/* going away */ -extern void _mutex_lock (mutex_t*); -extern boolean_t _mutex_try (mutex_t*); +#if !defined(MACH_KERNEL_PRIVATE) -#endif /* !MACH_KERNEL_PRIVATE */ +typedef struct __mutex__ mutex_t; + +#endif /* MACH_KERNEL_PRIVATE */ extern mutex_t *mutex_alloc (etap_event_t); extern void mutex_free (mutex_t*); @@ -171,7 +177,9 @@ extern void mutex_lock (mutex_t*); extern void mutex_unlock (mutex_t*); extern boolean_t mutex_try (mutex_t*); -extern void mutex_pause (void); +#ifdef __APPLE_API_PRIVATE + +#ifdef MACH_KERNEL_PRIVATE /* * The general lock structure. Provides for multiple readers, @@ -186,7 +194,7 @@ extern void mutex_pause (void); * other fields are modified with normal instructions after * acquiring the interlock bit. */ -#ifdef MACH_KERNEL_PRIVATE + typedef struct { decl_simple_lock_data(,interlock) /* "hardware" interlock field */ volatile unsigned int @@ -249,13 +257,19 @@ extern void lock_init (lock_t*, etap_event_t, etap_event_t); -#else /* MACH_KERNEL_PRIVATE */ +#endif /* MACH_KERNEL_PRIVATE */ + +extern unsigned int LockTimeOut; /* Standard lock timeout value */ + +#endif /* __APPLE_API_PRIVATE */ + +#if !defined(MACH_KERNEL_PRIVATE) typedef struct __lock__ lock_t; extern lock_t *lock_alloc(boolean_t, etap_event_t, etap_event_t); void lock_free(lock_t *); -#endif /* !MACH_KERNEL_PRIVATE */ +#endif /* MACH_KERNEL_PRIVATE */ extern void lock_write (lock_t*); extern void lock_read (lock_t*); @@ -266,6 +280,5 @@ extern void lock_write_to_read (lock_t*); #define lock_write_done(l) lock_done(l) extern boolean_t lock_read_to_write (lock_t*); /* vm_map is only user */ -extern unsigned int LockTimeOut; /* Standard lock timeout value */ #endif /* _KERN_LOCK_H_ */ diff --git a/osfmk/kern/mach_clock.c b/osfmk/kern/mach_clock.c index b7c7d8835..1d922cac4 100644 --- a/osfmk/kern/mach_clock.c +++ b/osfmk/kern/mach_clock.c @@ -161,11 +161,9 @@ hertz_tick( if (usermode) { TICKBUMP(&thread->user_timer); -#if 0 if (thread->priority < BASEPRI_DEFAULT) state = CPU_STATE_NICE; else -#endif state = CPU_STATE_USER; #if GPROF if (pv->active) diff --git a/osfmk/kern/mach_factor.c b/osfmk/kern/mach_factor.c index 14eba5e2b..3b86b6970 100644 --- a/osfmk/kern/mach_factor.c +++ b/osfmk/kern/mach_factor.c @@ -70,8 +70,8 @@ #include #endif /* MACH_KERNEL */ -integer_t avenrun[3] = {0, 0, 0}; -integer_t mach_factor[3] = {0, 0, 0}; +uint32_t avenrun[3] = {0, 0, 0}; +uint32_t mach_factor[3] = {0, 0, 0}; /* * Values are scaled by LOAD_SCALE, defined in processor_info.h @@ -79,11 +79,12 @@ integer_t mach_factor[3] = {0, 0, 0}; #define base(n) ((n) << SCHED_TICK_SHIFT) #define frac(n) (((base(n) - 1) * LOAD_SCALE) / base(n)) -static long fract[3] = { +static uint32_t fract[3] = { frac(5), /* 5 second average */ frac(30), /* 30 second average */ frac(60), /* 1 minute average */ }; + #undef base #undef frac @@ -91,31 +92,18 @@ void compute_mach_factor(void) { register processor_set_t pset; - register processor_t processor; register int ncpus; register int nthreads; - register long factor_now = 0L; - register long average_now = 0L; - register long load_now = 0L; + register uint32_t factor_now = 0; + register uint32_t average_now = 0; + register uint32_t load_now = 0; pset = &default_pset; - simple_lock(&pset->processors_lock); if ((ncpus = pset->processor_count) > 0) { /* - * Count number of threads. - */ - nthreads = pset->runq.count; - processor = (processor_t)queue_first(&pset->processors); - while (!queue_end(&pset->processors, (queue_entry_t)processor)) { - nthreads += processor->runq.count; - - processor = (processor_t)queue_next(&processor->processors); - } - - /* - * account for threads on cpus. + * Number of threads running in pset. */ - nthreads += ncpus - pset->idle_count; + nthreads = pset->run_count; /* * The current thread (running this calculation) @@ -124,28 +112,24 @@ compute_mach_factor(void) if (pset == &default_pset) nthreads -= 1; - if (nthreads >= ncpus) + if (nthreads > ncpus) { factor_now = (ncpus * LOAD_SCALE) / (nthreads + 1); - else - factor_now = (ncpus - nthreads) * LOAD_SCALE; - - if (nthreads > ncpus) load_now = (nthreads << SCHED_SHIFT) / ncpus; + } else - load_now = 0; + factor_now = (ncpus - nthreads) * LOAD_SCALE; /* * Load average and mach factor calculations for * those that ask about these things. */ - - average_now = (nthreads * LOAD_SCALE) / ncpus; + average_now = nthreads * LOAD_SCALE; pset->mach_factor = ((pset->mach_factor << 2) + factor_now) / 5; pset->load_average = ((pset->load_average << 2) + average_now) / 5; /* - * sched_load is the only thing used by scheduler. + * sched_load is used by the timesharing algorithm. */ pset->sched_load = (pset->sched_load + load_now) >> 1; } @@ -154,13 +138,11 @@ compute_mach_factor(void) pset->sched_load = 0; } - simple_unlock(&pset->processors_lock); - /* - * And some ugly stuff to keep w happy. + * Compute old-style Mach load averages. */ { - register int i; + register int i; for (i = 0; i < 3; i++) { mach_factor[i] = ((mach_factor[i] * fract[i]) + @@ -170,4 +152,20 @@ compute_mach_factor(void) (average_now * (LOAD_SCALE - fract[i]))) / LOAD_SCALE; } } + + /* + * Call out to BSD for averunnable. + */ + { +#define AVGTICK_PERIOD (5 << SCHED_TICK_SHIFT) + static uint32_t avgtick_count; + extern void compute_averunnable( + int nrun); + + if (++avgtick_count == 1) + compute_averunnable(nthreads); + else + if (avgtick_count >= AVGTICK_PERIOD) + avgtick_count = 0; + } } diff --git a/osfmk/kern/mach_param.h b/osfmk/kern/mach_param.h index ce2e9d27c..db780aca1 100644 --- a/osfmk/kern/mach_param.h +++ b/osfmk/kern/mach_param.h @@ -22,62 +22,6 @@ /* * @OSF_COPYRIGHT@ */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:34 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.1.1.1 1998/03/07 02:25:55 wsanchez - * Import of OSF Mach kernel (~mburg) - * - * Revision 1.1.9.1 1994/09/23 02:22:28 ezf - * change marker to not FREE - * [1994/09/22 21:34:35 ezf] - * - * Revision 1.1.7.1 1994/01/12 17:54:33 dwm - * Coloc: initial restructuring to follow Utah model. - * added various maxima for act/thread_pool zones - * [1994/01/12 17:29:08 dwm] - * - * Revision 1.1.3.3 1993/06/07 22:13:58 jeffc - * CR9176 - ANSI C violations: trailing tokens on CPP - * directives, extra semicolons after decl_ ..., asm keywords - * [1993/06/07 19:06:04 jeffc] - * - * Revision 1.1.3.2 1993/06/02 23:38:46 jeffc - * Added to OSF/1 R1.3 from NMK15.0. - * [1993/06/02 21:13:30 jeffc] - * - * Revision 1.1 1992/09/30 02:29:52 robert - * Initial revision - * - * $EndLog$ - */ -/* CMU_HIST */ -/* - * Revision 2.5.2.1 92/03/03 16:20:11 jeffreyh - * 19-Feb-92 David L. Black (dlb) at Open Software Foundation - * Double object slop in PORT_MAX, allow for extra (non-task) - * ipc spaces (e.g. ipc_space_remote) in SPACE_MAX - * [92/02/26 11:54:50 jeffreyh] - * - * Revision 2.5 91/05/14 16:44:25 mrt - * Correcting copyright - * - * Revision 2.4 91/02/05 17:27:56 mrt - * Changed to new Mach copyright - * [91/02/01 16:15:07 mrt] - * - * Revision 2.3 90/06/02 14:55:13 rpd - * Added new IPC parameters. - * [90/03/26 22:11:55 rpd] - * - * - * Condensed history: - * Moved TASK_MAX, PORT_MAX, etc. here from mach/mach_param.h (rpd). - */ -/* CMU_ENDHIST */ /* * Mach Operating System * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University @@ -117,6 +61,11 @@ #ifndef _KERN_MACH_PARAM_H_ #define _KERN_MACH_PARAM_H_ +#include + +#ifdef __APPLE_API_PRIVATE +#ifdef __APPLE_API_EVOLVING + #define THREAD_MAX 1024 /* Max number of threads */ #define THREAD_CHUNK 64 /* Allocation chunk */ @@ -143,4 +92,7 @@ #define SEMAPHORE_MAX (PORT_MAX >> 1) /* Maximum number of semaphores */ +#endif /* __APPLE_API_EVOLVING */ +#endif /* __APPLE_API_PRIVATE */ + #endif /* _KERN_MACH_PARAM_H_ */ diff --git a/osfmk/kern/machine.c b/osfmk/kern/machine.c index b1a1ee73a..0ef1b7e90 100644 --- a/osfmk/kern/machine.c +++ b/osfmk/kern/machine.c @@ -119,6 +119,7 @@ cpu_up( int cpu) { processor_t processor = cpu_to_processor(cpu); + processor_set_t pset = &default_pset; struct machine_slot *ms; spl_t s; @@ -126,7 +127,7 @@ cpu_up( * Just twiddle our thumbs; we've got nothing better to do * yet, anyway. */ - while (!simple_lock_try(&default_pset.processors_lock)) + while (!simple_lock_try(&pset->processors_lock)) continue; s = splsched(); @@ -135,12 +136,15 @@ cpu_up( ms = &machine_slot[cpu]; ms->running = TRUE; machine_info.avail_cpus++; - pset_add_processor(&default_pset, processor); + pset_add_processor(pset, processor); + simple_lock(&pset->sched_lock); + enqueue_tail(&pset->active_queue, (queue_entry_t)processor); processor->state = PROCESSOR_RUNNING; + simple_unlock(&pset->sched_lock); processor_unlock(processor); splx(s); - simple_unlock(&default_pset.processors_lock); + simple_unlock(&pset->processors_lock); } /* @@ -207,81 +211,75 @@ processor_request_action( processor_t processor, processor_set_t new_pset) { - processor_set_t pset, old_next_pset; + processor_set_t pset, old_pset; /* * Processor must be in a processor set. Must lock its idle lock to * get at processor state. */ pset = processor->processor_set; - simple_lock(&pset->idle_lock); + simple_lock(&pset->sched_lock); /* * If the processor is dispatching, let it finish - it will set its * state to running very soon. */ while (*(volatile int *)&processor->state == PROCESSOR_DISPATCHING) { - simple_unlock(&pset->idle_lock); - simple_lock(&pset->idle_lock); + simple_unlock(&pset->sched_lock); + + simple_lock(&pset->sched_lock); } + assert( processor->state == PROCESSOR_IDLE || + processor->state == PROCESSOR_RUNNING || + processor->state == PROCESSOR_ASSIGN ); + /* * Now lock the action queue and do the dirty work. */ simple_lock(&processor_action_lock); - switch (processor->state) { - - case PROCESSOR_IDLE: - /* - * Remove from idle queue. - */ - queue_remove(&pset->idle_queue, processor, - processor_t, processor_queue); + if (processor->state == PROCESSOR_IDLE) { + remqueue(&pset->idle_queue, (queue_entry_t)processor); pset->idle_count--; + } + else + if (processor->state == PROCESSOR_RUNNING) + remqueue(&pset->active_queue, (queue_entry_t)processor); - /* fall through ... */ - case PROCESSOR_RUNNING: - /* - * Put it on the action queue. - */ - queue_enter(&processor_action_queue, processor, - processor_t,processor_queue); - - /* Fall through ... */ - case PROCESSOR_ASSIGN: - /* - * And ask the action_thread to do the work. - */ + if (processor->state != PROCESSOR_ASSIGN) + enqueue_tail(&processor_action_queue, (queue_entry_t)processor); - if (new_pset == PROCESSOR_SET_NULL) { - processor->state = PROCESSOR_SHUTDOWN; - old_next_pset = PROCESSOR_SET_NULL; - } else { - processor->state = PROCESSOR_ASSIGN; - old_next_pset = processor->processor_set_next; - processor->processor_set_next = new_pset; - } - break; - - default: - printf("state: %d\n", processor->state); - panic("processor_request_action: bad state"); + /* + * And ask the action_thread to do the work. + */ + if (new_pset != PROCESSOR_SET_NULL) { + processor->state = PROCESSOR_ASSIGN; + old_pset = processor->processor_set_next; + processor->processor_set_next = new_pset; + } + else { + processor->state = PROCESSOR_SHUTDOWN; + old_pset = PROCESSOR_SET_NULL; } - if (processor_action_active == FALSE) { - processor_action_active = TRUE; - simple_unlock(&processor_action_lock); - simple_unlock(&pset->idle_lock); - processor_unlock(processor); - thread_call_enter(processor_action_call); - processor_lock(processor); - } else { + simple_unlock(&pset->sched_lock); + + if (processor_action_active) { simple_unlock(&processor_action_lock); - simple_unlock(&pset->idle_lock); + + return (old_pset); } - return (old_next_pset); + processor_action_active = TRUE; + simple_unlock(&processor_action_lock); + + processor_unlock(processor); + + thread_call_enter(processor_action_call); + processor_lock(processor); + + return (old_pset); } kern_return_t @@ -308,8 +306,8 @@ processor_shutdown( s = splsched(); processor_lock(processor); - if ((processor->state == PROCESSOR_OFF_LINE) || - (processor->state == PROCESSOR_SHUTDOWN)) { + if ( processor->state == PROCESSOR_OFF_LINE || + processor->state == PROCESSOR_SHUTDOWN ) { /* * Already shutdown or being shutdown -- nothing to do. */ @@ -319,14 +317,14 @@ processor_shutdown( return (KERN_SUCCESS); } - (void) processor_request_action(processor, PROCESSOR_SET_NULL); + processor_request_action(processor, PROCESSOR_SET_NULL); assert_wait((event_t)processor, THREAD_UNINT); processor_unlock(processor); splx(s); - thread_block((void (*)(void)) 0); + thread_block(THREAD_CONTINUE_NULL); return (KERN_SUCCESS); } @@ -346,9 +344,7 @@ _processor_action( simple_lock(&processor_action_lock); while (!queue_empty(&processor_action_queue)) { - processor = (processor_t) queue_first(&processor_action_queue); - queue_remove(&processor_action_queue, processor, - processor_t, processor_queue); + processor = (processor_t)dequeue_head(&processor_action_queue); simple_unlock(&processor_action_lock); splx(s); @@ -392,7 +388,7 @@ processor_doaction( * Get onto the processor to shutdown */ thread_bind(self, processor); - thread_block((void (*)(void)) 0); + thread_block(THREAD_CONTINUE_NULL); pset = processor->processor_set; simple_lock(&pset->processors_lock); @@ -414,10 +410,9 @@ processor_doaction( s = splsched(); thread_lock(thread); - thread->state |= TH_RUN; - _mk_sp_thread_unblock(thread); - (void)rem_runq(thread); machine_wake_thread = thread; + thread_go_locked(thread, THREAD_AWAKENED); + (void)rem_runq(thread); thread_unlock(thread); splx(s); @@ -446,6 +441,8 @@ processor_doaction( self->continuation = 0; old_thread = switch_to_shutdown_context(self, processor_doshutdown, processor); + if (processor != current_processor()) + timer_call_shutdown(processor); thread_dispatch(old_thread); thread_wakeup((event_t)processor); splx(s); @@ -470,8 +467,7 @@ processor_doshutdown( * OK, now exit this cpu. */ PMAP_DEACTIVATE_KERNEL(cpu); - cpu_data[cpu].active_thread = THREAD_NULL; - active_kloaded[cpu] = THR_ACT_NULL; + thread_machine_set_current(processor->idle_thread); cpu_down(cpu); cpu_sleep(); panic("zombie processor"); diff --git a/osfmk/kern/macro_help.h b/osfmk/kern/macro_help.h index be1a48e14..eeaf1ae97 100644 --- a/osfmk/kern/macro_help.h +++ b/osfmk/kern/macro_help.h @@ -22,58 +22,6 @@ /* * @OSF_COPYRIGHT@ */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:34 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.1.1.1 1998/03/07 02:25:55 wsanchez - * Import of OSF Mach kernel (~mburg) - * - * Revision 1.1.6.1 1994/09/23 02:23:07 ezf - * change marker to not FREE - * [1994/09/22 21:34:48 ezf] - * - * Revision 1.1.2.3 1993/06/07 22:14:06 jeffc - * CR9176 - ANSI C violations: trailing tokens on CPP - * directives, extra semicolons after decl_ ..., asm keywords - * [1993/06/07 19:06:13 jeffc] - * - * Revision 1.1.2.2 1993/06/02 23:39:03 jeffc - * Added to OSF/1 R1.3 from NMK15.0. - * [1993/06/02 21:13:38 jeffc] - * - * Revision 1.1 1992/09/30 02:29:53 robert - * Initial revision - * - * $EndLog$ - */ -/* CMU_HIST */ -/* - * Revision 2.3 91/05/14 16:44:49 mrt - * Correcting copyright - * - * Revision 2.2 91/02/05 17:28:09 mrt - * Changed to new Mach copyright - * [91/02/01 16:15:31 mrt] - * - * Revision 2.1 89/08/03 15:53:45 rwd - * Created. - * - * Revision 2.2 88/10/18 03:36:20 mwyoung - * Added a form of return that can be used within macros that - * does not result in "statement not reached" noise. - * [88/10/17 mwyoung] - * - * Add MACRO_BEGIN, MACRO_END. - * [88/10/11 mwyoung] - * - * Created. - * [88/10/08 mwyoung] - * - */ -/* CMU_ENDHIST */ /* * Mach Operating System * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University diff --git a/osfmk/kern/misc_protos.h b/osfmk/kern/misc_protos.h index 329bc4db7..181bb0fed 100644 --- a/osfmk/kern/misc_protos.h +++ b/osfmk/kern/misc_protos.h @@ -117,6 +117,8 @@ extern integer_t sprintf(char *buf, const char *fmt, ...); extern void printf(const char *format, ...); +extern void kdp_printf(const char *format, ...); + extern void printf_init(void); extern void panic(const char *string, ...); @@ -131,6 +133,13 @@ _doprnt( va_list *argp, void (*putc)(char), int radix); +int +__doprnt( + register const char *fmt, + va_list *argp, + void (*putc)(int, void *), + void *arg, + int radix); extern void safe_gets( char *str, @@ -138,6 +147,10 @@ extern void safe_gets( extern void cnputcusr(char); +extern void conslog_putc(char); + +extern void consdebug_putc(char); + extern void cnputc(char); extern int cngetc(void); diff --git a/osfmk/kern/mk_sp.c b/osfmk/kern/mk_sp.c index 18c326ab0..384d1bf79 100644 --- a/osfmk/kern/mk_sp.c +++ b/osfmk/kern/mk_sp.c @@ -76,11 +76,10 @@ void _mk_sp_thread_unblock( thread_t thread) { - if (!(thread->state & TH_IDLE)) - thread_setrun(thread, TRUE, TAIL_Q); + thread_setrun(thread, TAIL_Q); thread->current_quantum = 0; - thread->metered_computation = 0; + thread->computation_metered = 0; thread->reason = AST_NONE; KERNEL_DEBUG_CONSTANT( @@ -90,42 +89,63 @@ _mk_sp_thread_unblock( void _mk_sp_thread_done( - thread_t thread) + thread_t old_thread, + thread_t new_thread, + processor_t processor) { - processor_t myprocessor = cpu_to_processor(cpu_number()); - /* * A running thread is being taken off a processor: */ - clock_get_uptime(&myprocessor->last_dispatch); - if (!(thread->state & TH_IDLE)) { - if ( first_quantum(myprocessor) && - myprocessor->quantum_end > myprocessor->last_dispatch ) - thread->current_quantum = - (myprocessor->quantum_end - myprocessor->last_dispatch); + clock_get_uptime(&processor->last_dispatch); + if (!(old_thread->state & TH_IDLE)) { + /* + * Compute remainder of current quantum. + */ + if ( first_quantum(processor) && + processor->quantum_end > processor->last_dispatch ) + old_thread->current_quantum = + (processor->quantum_end - processor->last_dispatch); else - thread->current_quantum = 0; + old_thread->current_quantum = 0; - if (!(thread->sched_mode & TH_MODE_REALTIME)) { - if (thread->current_quantum < min_std_quantum) { - thread->reason |= AST_QUANTUM; - thread->current_quantum += std_quantum; + /* + * For non-realtime threads treat a tiny + * remaining quantum as an expired quantum + * but include what's left next time. + */ + if (!(old_thread->sched_mode & TH_MODE_REALTIME)) { + if (old_thread->current_quantum < min_std_quantum) { + old_thread->reason |= AST_QUANTUM; + old_thread->current_quantum += std_quantum; } } else - if (thread->current_quantum == 0) - thread->reason |= AST_QUANTUM; + if (old_thread->current_quantum == 0) + old_thread->reason |= AST_QUANTUM; - thread->metered_computation += - (myprocessor->last_dispatch - thread->computation_epoch); + /* + * If we are doing a direct handoff then + * give the remainder of our quantum to + * the next guy. + */ + if ((old_thread->reason & (AST_HANDOFF|AST_QUANTUM)) == AST_HANDOFF) { + new_thread->current_quantum = old_thread->current_quantum; + old_thread->reason |= AST_QUANTUM; + old_thread->current_quantum = 0; + } + + old_thread->last_switch = processor->last_dispatch; + + old_thread->computation_metered += + (old_thread->last_switch - old_thread->computation_epoch); } } void _mk_sp_thread_begin( - thread_t thread) + thread_t thread, + processor_t processor) { - processor_t myprocessor = cpu_to_processor(cpu_number()); /* * The designated thread is beginning execution: @@ -136,34 +156,36 @@ _mk_sp_thread_begin( (thread->sched_mode & TH_MODE_REALTIME)? thread->realtime.computation: std_quantum; - myprocessor->quantum_end = - (myprocessor->last_dispatch + thread->current_quantum); - timer_call_enter1(&myprocessor->quantum_timer, - thread, myprocessor->quantum_end); + processor->quantum_end = + (processor->last_dispatch + thread->current_quantum); + timer_call_enter1(&processor->quantum_timer, + thread, processor->quantum_end); - myprocessor->slice_quanta = + processor->slice_quanta = (thread->sched_mode & TH_MODE_TIMESHARE)? - myprocessor->processor_set->set_quanta: 1; + processor->processor_set->set_quanta: 1; - thread->computation_epoch = myprocessor->last_dispatch; + thread->last_switch = processor->last_dispatch; + + thread->computation_epoch = thread->last_switch; } else { - timer_call_cancel(&myprocessor->quantum_timer); + timer_call_cancel(&processor->quantum_timer); - myprocessor->slice_quanta = 1; + processor->slice_quanta = 1; } } void _mk_sp_thread_dispatch( - thread_t old_thread) + thread_t thread) { - if (old_thread->reason & AST_QUANTUM) - thread_setrun(old_thread, FALSE, TAIL_Q); + if (thread->reason & AST_QUANTUM) + thread_setrun(thread, TAIL_Q); else - thread_setrun(old_thread, FALSE, HEAD_Q); + thread_setrun(thread, HEAD_Q); - old_thread->reason = AST_NONE; + thread->reason = AST_NONE; } /* @@ -216,27 +238,13 @@ thread_policy_common( if (priority > thread->max_priority) priority = thread->max_priority; + else + if (priority < MINPRI) + priority = MINPRI; thread->importance = priority - thread->task_priority; - /* - * Set priorities. If a depression is in progress, - * change the priority to restore. - */ - if (thread->depress_priority >= 0) - thread->depress_priority = priority; - else { - thread->priority = priority; - compute_priority(thread, TRUE); - - /* - * If the current thread has changed its - * priority let the ast code decide whether - * a different thread should run. - */ - if (thread == current_thread()) - ast_on(AST_BLOCK); - } + set_priority(thread, priority); } thread_unlock(thread); @@ -621,55 +629,64 @@ shift_data_t wait_shift[32] = { MACRO_END #endif /* defined(PRI_SHIFT_2) */ +void +set_priority( + register thread_t thread, + register int priority) +{ + thread->priority = priority; + compute_priority(thread, FALSE); +} + /* * compute_priority: * - * Compute the effective priority of the specified thread. - * The effective priority computation is as follows: + * Reset the current scheduled priority of the + * thread according to its base priority if the + * thread has not been promoted or depressed. * - * Take the base priority for this thread and add - * to it an increment derived from its cpu_usage. + * If the thread is timesharing, adjust according + * to recent cpu usage. * - * The thread *must* be locked by the caller. + * The thread *must* be locked by the caller. */ - void compute_priority( register thread_t thread, - boolean_t resched) + boolean_t override_depress) { - register int pri; - - if (thread->sched_mode & TH_MODE_TIMESHARE) { - do_priority_computation(thread, pri); - if (thread->depress_priority < 0) - set_pri(thread, pri, resched); - else - thread->depress_priority = pri; + register int priority; + + if ( !(thread->sched_mode & TH_MODE_PROMOTED) && + (!(thread->sched_mode & TH_MODE_ISDEPRESSED) || + override_depress ) ) { + if (thread->sched_mode & TH_MODE_TIMESHARE) + do_priority_computation(thread, priority); + else + priority = thread->priority; + + set_sched_pri(thread, priority); } - else - set_pri(thread, thread->priority, resched); } /* * compute_my_priority: * - * Version of compute priority for current thread or thread - * being manipulated by scheduler (going on or off a runq). - * Only used for priority updates. Policy or priority changes - * must call compute_priority above. Caller must have thread - * locked and know it is timesharing and not depressed. + * Version of compute priority for current thread. + * Caller must have thread locked and thread must + * be timesharing and not depressed. + * + * Only used for priority updates. */ - void compute_my_priority( register thread_t thread) { - register int pri; + register int priority; - do_priority_computation(thread, pri); + do_priority_computation(thread, priority); assert(thread->runq == RUN_QUEUE_NULL); - thread->sched_pri = pri; + thread->sched_pri = priority; } /* @@ -728,29 +745,22 @@ update_priority( thread->cpu_delta = 0; thread->sched_delta = 0; + /* + * Check for fail-safe release. + */ if ( (thread->sched_mode & TH_MODE_FAILSAFE) && thread->sched_stamp >= thread->safe_release ) { if (!(thread->safe_mode & TH_MODE_TIMESHARE)) { if (thread->safe_mode & TH_MODE_REALTIME) { - if (thread->depress_priority < 0) - thread->priority = BASEPRI_REALTIME; - else - thread->depress_priority = BASEPRI_REALTIME; + thread->priority = BASEPRI_REALTIME; thread->sched_mode |= TH_MODE_REALTIME; } - if ( thread->depress_priority < 0 && - thread->sched_pri != thread->priority ) { - run_queue_t runq; - - runq = rem_runq(thread); - thread->sched_pri = thread->priority; - if (runq != RUN_QUEUE_NULL) - thread_setrun(thread, TRUE, TAIL_Q); - } - thread->sched_mode &= ~TH_MODE_TIMESHARE; + + if (!(thread->sched_mode & TH_MODE_ISDEPRESSED)) + set_sched_pri(thread, thread->priority); } thread->safe_mode = 0; @@ -758,10 +768,11 @@ update_priority( } /* - * Recompute priority if appropriate. + * Recompute scheduled priority if appropriate. */ if ( (thread->sched_mode & TH_MODE_TIMESHARE) && - thread->depress_priority < 0 ) { + !(thread->sched_mode & TH_MODE_PROMOTED) && + !(thread->sched_mode & TH_MODE_ISDEPRESSED) ) { register int new_pri; do_priority_computation(thread, new_pri); @@ -771,7 +782,7 @@ update_priority( runq = rem_runq(thread); thread->sched_pri = new_pri; if (runq != RUN_QUEUE_NULL) - thread_setrun(thread, TRUE, TAIL_Q); + thread_setrun(thread, TAIL_Q); } } } @@ -857,9 +868,7 @@ _mk_sp_thread_switch( self->saved.swtch.option = option; thread_run(self, _mk_sp_thread_switch_continue, thread); - splx(s); - - goto out; + /* NOTREACHED */ } thread_unlock(thread); @@ -893,7 +902,9 @@ _mk_sp_thread_switch( self->saved.swtch.option = option; - thread_block(_mk_sp_thread_switch_continue); + thread_block_reason(_mk_sp_thread_switch_continue, + (option == SWITCH_OPTION_DEPRESS)? + AST_YIELD: AST_NONE); } else mp_enable_preemption(); @@ -923,9 +934,13 @@ _mk_sp_thread_depress_abstime( s = splsched(); wake_lock(self); thread_lock(self); - if (self->depress_priority < 0) { - self->depress_priority = self->priority; - self->sched_pri = self->priority = DEPRESSPRI; + if (!(self->sched_mode & TH_MODE_ISDEPRESSED)) { + processor_t myprocessor = self->last_processor; + + self->sched_pri = DEPRESSPRI; + myprocessor->current_pri = self->sched_pri; + self->sched_mode &= ~TH_MODE_PREEMPT; + self->sched_mode |= TH_MODE_DEPRESS; thread_unlock(self); if (interval != 0) { @@ -966,22 +981,8 @@ thread_depress_expire( wake_lock(thread); if (--thread->depress_timer_active == 1) { thread_lock(thread); - if (thread->depress_priority >= 0) { - thread->priority = thread->depress_priority; - thread->depress_priority = -1; - compute_priority(thread, TRUE); - } - else - if (thread->depress_priority == -2) { - /* - * Thread was temporarily undepressed by thread_suspend, to - * be redepressed in special_handler as it blocks. We need to - * prevent special_handler from redepressing it, since depression - * has timed out: - */ - thread->depress_priority = -1; - } - thread->sched_mode &= ~TH_MODE_POLLDEPRESS; + thread->sched_mode &= ~TH_MODE_ISDEPRESSED; + compute_priority(thread, FALSE); thread_unlock(thread); } else @@ -1006,14 +1007,12 @@ _mk_sp_thread_depress_abort( wake_lock(thread); thread_lock(thread); if (abortall || !(thread->sched_mode & TH_MODE_POLLDEPRESS)) { - if (thread->depress_priority >= 0) { - thread->priority = thread->depress_priority; - thread->depress_priority = -1; - compute_priority(thread, TRUE); + if (thread->sched_mode & TH_MODE_ISDEPRESSED) { + thread->sched_mode &= ~TH_MODE_ISDEPRESSED; + compute_priority(thread, FALSE); result = KERN_SUCCESS; } - thread->sched_mode &= ~TH_MODE_POLLDEPRESS; thread_unlock(thread); if (timer_call_cancel(&thread->depress_timer)) @@ -1036,7 +1035,6 @@ _mk_sp_thread_perhaps_yield( assert(self == current_thread()); s = splsched(); - thread_lock(self); if (!(self->sched_mode & (TH_MODE_REALTIME|TH_MODE_TIMESHARE))) { extern uint64_t max_poll_computation; extern int sched_poll_yield_shift; @@ -1044,20 +1042,20 @@ _mk_sp_thread_perhaps_yield( clock_get_uptime(&abstime); total_computation = abstime - self->computation_epoch; - total_computation += self->metered_computation; + total_computation += self->computation_metered; if (total_computation >= max_poll_computation) { - processor_t myprocessor; - - thread_unlock(self); + processor_t myprocessor = current_processor(); + ast_t preempt; wake_lock(self); thread_lock(self); - if (self->depress_priority < 0) { - self->depress_priority = self->priority; - self->sched_pri = self->priority = DEPRESSPRI; + if (!(self->sched_mode & TH_MODE_ISDEPRESSED)) { + self->sched_pri = DEPRESSPRI; + myprocessor->current_pri = self->sched_pri; + self->sched_mode &= ~TH_MODE_PREEMPT; } self->computation_epoch = abstime; - self->metered_computation = 0; + self->computation_metered = 0; self->sched_mode |= TH_MODE_POLLDEPRESS; thread_unlock(self); @@ -1066,15 +1064,9 @@ _mk_sp_thread_perhaps_yield( self->depress_timer_active++; wake_unlock(self); - myprocessor = current_processor(); - if (csw_needed(self, myprocessor)) - ast_on(AST_BLOCK); + if ((preempt = csw_check(self, myprocessor)) != AST_NONE) + ast_on(preempt); } - else - thread_unlock(self); } - else - thread_unlock(self); - splx(s); } diff --git a/osfmk/kern/mk_sp.h b/osfmk/kern/mk_sp.h index a7a2db358..fe78f7808 100644 --- a/osfmk/kern/mk_sp.h +++ b/osfmk/kern/mk_sp.h @@ -35,13 +35,16 @@ void _mk_sp_thread_unblock( thread_t thread); void _mk_sp_thread_done( - thread_t old_thread); + thread_t old_thread, + thread_t new_thread, + processor_t processor); void _mk_sp_thread_begin( - thread_t new_thread); + thread_t new_thread, + processor_t processor); void _mk_sp_thread_dispatch( - thread_t old_thread); + thread_t thread); kern_return_t _mk_sp_thread_switch( thread_act_t hint_act, diff --git a/osfmk/kern/printf.c b/osfmk/kern/printf.c index bf870083e..472ab86c2 100644 --- a/osfmk/kern/printf.c +++ b/osfmk/kern/printf.c @@ -78,6 +78,8 @@ * %u unsigned conversion * %x hexadecimal conversion * %X hexadecimal conversion with capital letters + * %D hexdump, ptr & separator string ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX + * if you use, "%*D" then there's a length, the data ptr and then the separator * %o octal conversion * %c character * %s string @@ -89,8 +91,6 @@ * This version does not implement %f, %e, or %g. It accepts, but * ignores, an `l' as in %ld, %lo, %lx, and %lu, and therefore will not * work correctly on machines for which sizeof(long) != sizeof(int). - * It does not even parse %D, %O, or %U; you should be using %ld, %o and - * %lu if you mean long conversion. * * As mentioned, this version does not return any reasonable value. * @@ -98,6 +98,9 @@ * long as this notice is incorporated. * * Steve Summit 3/25/87 + * + * Tweaked for long long support and extended to support the hexdump %D + * specifier by dbg 05/02/02. */ /* @@ -141,6 +144,11 @@ * D,U,O,Z same as corresponding lower-case versions * (compatibility) */ +/* + * Added support for print long long (64-bit) integers. + * Use %lld, %Ld or %qd to print a 64-bit int. Other + * output bases such as x, X, u, U, o, and O also work. + */ #include #include @@ -161,72 +169,73 @@ #include #endif -/* - * Forward declarations - */ -void printnum( - register unsigned int u, - register int base, - void (*putc)(char)); - - #define isdigit(d) ((d) >= '0' && (d) <= '9') #define Ctod(c) ((c) - '0') -#define MAXBUF (sizeof(long int) * 8) /* enough for binary */ +#define MAXBUF (sizeof(long long int) * 8) /* enough for binary */ +static char digs[] = "0123456789abcdef"; -void +static int printnum( - register unsigned int u, /* number to print */ + register unsigned long long int u, /* number to print */ register int base, - void (*putc)(char)) + void (*putc)(int, void *), + void *arg) { char buf[MAXBUF]; /* build number here */ register char * p = &buf[MAXBUF-1]; - static char digs[] = "0123456789abcdef"; + int nprinted = 0; do { *p-- = digs[u % base]; u /= base; } while (u != 0); - while (++p != &buf[MAXBUF]) - (*putc)(*p); + while (++p != &buf[MAXBUF]) { + (*putc)(*p, arg); + nprinted++; + } + return nprinted; } boolean_t _doprnt_truncates = FALSE; -void -_doprnt( +int +__doprnt( register const char *fmt, va_list *argp, /* character output routine */ - void (*putc)(char), + void (*putc)(int, void *arg), + void *arg, int radix) /* default radix - for '%r' */ { int length; int prec; boolean_t ladjust; char padc; - long n; - unsigned long u; + long long n; + unsigned long long u; int plus_sign; int sign_char; boolean_t altfmt, truncate; int base; register char c; int capitals; + int long_long; + int nprinted = 0; while ((c = *fmt) != '\0') { if (c != '%') { - (*putc)(c); + (*putc)(c, arg); + nprinted++; fmt++; continue; } fmt++; + long_long = 0; length = 0; prec = -1; ladjust = FALSE; @@ -290,8 +299,16 @@ _doprnt( } } - if (c == 'l') + if (c == 'l') { c = *++fmt; /* need it if sizeof(int) < sizeof(long) */ + if (c == 'l') { + long_long = 1; + c = *++fmt; + } + } else if (c == 'q' || c == 'L') { + long_long = 1; + c = *++fmt; + } truncate = FALSE; capitals=0; /* Assume lower case printing */ @@ -304,10 +321,14 @@ _doprnt( boolean_t any; register int i; - u = va_arg(*argp, unsigned long); + if (long_long) { + u = va_arg(*argp, unsigned long long); + } else { + u = va_arg(*argp, unsigned long); + } p = va_arg(*argp, char *); base = *p++; - printnum(u, base, putc); + nprinted += printnum(u, base, putc, arg); if (u == 0) break; @@ -322,42 +343,51 @@ _doprnt( */ register int j; if (any) - (*putc)(','); + (*putc)(',', arg); else { - (*putc)('<'); + (*putc)('<', arg); any = TRUE; } + nprinted++; j = *p++; if (*fmt == 'B') j = 32 - j; - for (; (c = *p) > 32; p++) - (*putc)(c); - printnum((unsigned)( (u>>(j-1)) & ((2<<(i-j))-1)), - base, putc); + for (; (c = *p) > 32; p++) { + (*putc)(c, arg); + nprinted++; + } + nprinted += printnum((unsigned)( (u>>(j-1)) & ((2<<(i-j))-1)), + base, putc, arg); } else if (u & (1<<(i-1))) { if (any) - (*putc)(','); + (*putc)(',', arg); else { - (*putc)('<'); + (*putc)('<', arg); any = TRUE; } - for (; (c = *p) > 32; p++) - (*putc)(c); + nprinted++; + for (; (c = *p) > 32; p++) { + (*putc)(c, arg); + nprinted++; + } } else { for (; *p > 32; p++) continue; } } - if (any) - (*putc)('>'); + if (any) { + (*putc)('>', arg); + nprinted++; + } break; } case 'c': c = va_arg(*argp, int); - (*putc)(c); + (*putc)(c, arg); + nprinted++; break; case 's': @@ -383,8 +413,9 @@ _doprnt( p = p2; while (n < length) { - (*putc)(' '); + (*putc)(' ', arg); n++; + nprinted++; } } @@ -394,13 +425,15 @@ _doprnt( if (++n > prec || (length > 0 && n > length)) break; - (*putc)(*p++); + (*putc)(*p++, arg); + nprinted++; } if (n < length && ladjust) { while (n < length) { - (*putc)(' '); + (*putc)(' ', arg); n++; + nprinted++; } } @@ -413,9 +446,31 @@ _doprnt( base = 8; goto print_unsigned; + case 'D': { + unsigned char *up; + char *q, *p; + + up = (unsigned char *)va_arg(*argp, unsigned char *); + p = (char *)va_arg(*argp, char *); + if (length == -1) + length = 16; + while(length--) { + (*putc)(digs[(*up >> 4)], arg); + (*putc)(digs[(*up & 0x0f)], arg); + nprinted += 2; + up++; + if (length) { + for (q=p;*q;q++) { + (*putc)(*q, arg); + nprinted++; + } + } + } + break; + } + case 'd': truncate = _doprnt_truncates; - case 'D': base = 10; goto print_signed; @@ -460,7 +515,11 @@ _doprnt( goto print_unsigned; print_signed: - n = va_arg(*argp, long); + if (long_long) { + n = va_arg(*argp, long long); + } else { + n = va_arg(*argp, long); + } if (n >= 0) { u = n; sign_char = plus_sign; @@ -472,7 +531,11 @@ _doprnt( goto print_num; print_unsigned: - u = va_arg(*argp, unsigned long); + if (long_long) { + u = va_arg(*argp, unsigned long long); + } else { + u = va_arg(*argp, unsigned long); + } goto print_num; print_num: @@ -482,7 +545,7 @@ _doprnt( static char digits[] = "0123456789abcdef0123456789ABCDEF"; char *prefix = 0; - if (truncate) u = (long)((int)(u)); + if (truncate) u = (long long)((int)(u)); if (u != 0 && altfmt) { if (base == 8) @@ -505,25 +568,38 @@ _doprnt( if (padc == ' ' && !ladjust) { /* blank padding goes before prefix */ - while (--length >= 0) - (*putc)(' '); + while (--length >= 0) { + (*putc)(' ', arg); + nprinted++; + } + } + if (sign_char) { + (*putc)(sign_char, arg); + nprinted++; + } + if (prefix) { + while (*prefix) { + (*putc)(*prefix++, arg); + nprinted++; + } } - if (sign_char) - (*putc)(sign_char); - if (prefix) - while (*prefix) - (*putc)(*prefix++); if (padc == '0') { /* zero padding goes after sign and prefix */ - while (--length >= 0) - (*putc)('0'); + while (--length >= 0) { + (*putc)('0', arg); + nprinted++; + } } - while (++p != &buf[MAXBUF]) - (*putc)(*p); - + while (++p != &buf[MAXBUF]) { + (*putc)(*p, arg); + nprinted++; + } + if (ladjust) { - while (--length >= 0) - (*putc)(' '); + while (--length >= 0) { + (*putc)(' ', arg); + nprinted++; + } } break; } @@ -533,10 +609,32 @@ _doprnt( break; default: - (*putc)(c); + (*putc)(c, arg); + nprinted++; } fmt++; } + + return nprinted; +} + +static void +dummy_putc(int ch, void *arg) +{ + void (*real_putc)(char) = arg; + + real_putc(ch); +} + +void +_doprnt( + register const char *fmt, + va_list *argp, + /* character output routine */ + void (*putc)(char), + int radix) /* default radix - for '%r' */ +{ + __doprnt(fmt, argp, dummy_putc, putc, radix); } #if MP_PRINTF @@ -632,6 +730,28 @@ printf(const char *fmt, ...) enable_preemption(); } +void +consdebug_putc( + char c) +{ + extern unsigned int debug_mode, disableDebugOuput, disableConsoleOutput; + + if ((debug_mode && !disableDebugOuput) || !disableConsoleOutput) + cnputc(c); + + debug_putc(c); +} + +void +kdb_printf(const char *fmt, ...) +{ + va_list listp; + + va_start(listp, fmt); + _doprnt(fmt, &listp, consdebug_putc, 16); + va_end(listp); +} + static char *copybyte_str; static void diff --git a/osfmk/kern/priority.c b/osfmk/kern/priority.c index 31caeb97a..084e8fe2c 100644 --- a/osfmk/kern/priority.c +++ b/osfmk/kern/priority.c @@ -83,23 +83,13 @@ thread_quantum_expire( { register processor_t myprocessor = p0; register thread_t thread = p1; - register processor_set_t pset; spl_t s; - pset = myprocessor->processor_set; - - /* - * Update set_quanta for timesharing. - */ - pset->set_quanta = pset->machine_quanta[ - (pset->runq.count > pset->processor_count) ? - pset->processor_count : pset->runq.count]; - s = splsched(); thread_lock(thread); /* - * Check for failsafe trip. + * Check for fail-safe trip. */ if (!(thread->sched_mode & TH_MODE_TIMESHARE)) { extern uint64_t max_unsafe_computation; @@ -107,15 +97,12 @@ thread_quantum_expire( new_computation = myprocessor->quantum_end; new_computation -= thread->computation_epoch; - if (new_computation + thread->metered_computation > + if (new_computation + thread->computation_metered > max_unsafe_computation) { extern uint32_t sched_safe_duration; if (thread->sched_mode & TH_MODE_REALTIME) { - if (thread->depress_priority < 0) - thread->priority = MINPRI; - else - thread->depress_priority = MINPRI; + thread->priority = DEPRESSPRI; thread->safe_mode |= TH_MODE_REALTIME; thread->sched_mode &= ~TH_MODE_REALTIME; @@ -123,21 +110,29 @@ thread_quantum_expire( thread->safe_release = sched_tick + sched_safe_duration; thread->sched_mode |= (TH_MODE_FAILSAFE|TH_MODE_TIMESHARE); + thread->sched_mode &= ~TH_MODE_PREEMPT; } } /* - * Now recompute the priority of the thread if appropriate. + * Recompute scheduled priority if appropriate. */ if (thread->sched_stamp != sched_tick) update_priority(thread); else - if ( (thread->sched_mode & TH_MODE_TIMESHARE) && - thread->depress_priority < 0 ) { + if (thread->sched_mode & TH_MODE_TIMESHARE) { thread_timer_delta(thread); thread->sched_usage += thread->sched_delta; thread->sched_delta = 0; - compute_my_priority(thread); + + /* + * Adjust the scheduled priority if + * the thread has not been promoted + * and is not depressed. + */ + if ( !(thread->sched_mode & TH_MODE_PROMOTED) && + !(thread->sched_mode & TH_MODE_ISDEPRESSED) ) + compute_my_priority(thread); } /* @@ -153,10 +148,11 @@ thread_quantum_expire( thread, myprocessor->quantum_end); thread_unlock(thread); - splx(s); /* * Check for and schedule ast if needed. */ - ast_check(); + ast_check(myprocessor); + + splx(s); } diff --git a/osfmk/kern/processor.c b/osfmk/kern/processor.c index a37913b15..243afa7af 100644 --- a/osfmk/kern/processor.c +++ b/osfmk/kern/processor.c @@ -84,6 +84,8 @@ struct processor_set default_pset; struct processor processor_array[NCPUS]; +int master_cpu = 0; + processor_t master_processor; processor_t processor_ptr[NCPUS]; @@ -135,6 +137,7 @@ pset_sys_bootstrap(void) processor_init(processor_ptr[i], i); } master_processor = cpu_to_processor(master_cpu); + master_processor->cpu_data = get_cpu_data(); default_pset.active = TRUE; } @@ -145,23 +148,23 @@ pset_sys_bootstrap(void) void pset_init( register processor_set_t pset) { - int i; + register int i; - /* setup run-queues */ + /* setup run queue */ simple_lock_init(&pset->runq.lock, ETAP_THREAD_PSET_RUNQ); - pset->runq.count = 0; - for (i = 0; i < NRQBM; i++) { + for (i = 0; i < NRQBM; i++) pset->runq.bitmap[i] = 0; - } setbit(MAXPRI - IDLEPRI, pset->runq.bitmap); pset->runq.highq = IDLEPRI; - for (i = 0; i < NRQS; i++) { - queue_init(&(pset->runq.queues[i])); - } + pset->runq.urgency = pset->runq.count = 0; + for (i = 0; i < NRQS; i++) + queue_init(&pset->runq.queues[i]); queue_init(&pset->idle_queue); pset->idle_count = 0; - simple_lock_init(&pset->idle_lock, ETAP_THREAD_PSET_IDLE); + queue_init(&pset->active_queue); + simple_lock_init(&pset->sched_lock, ETAP_THREAD_PSET_IDLE); + pset->run_count = 0; pset->mach_factor = pset->load_average = 0; pset->sched_load = 0; queue_init(&pset->processors); @@ -188,37 +191,65 @@ void pset_init( */ void processor_init( - register processor_t pr, - int slot_num) + register processor_t p, + int slot_num) { - int i; + register int i; - /* setup run-queues */ - simple_lock_init(&pr->runq.lock, ETAP_THREAD_PROC_RUNQ); - pr->runq.count = 0; - for (i = 0; i < NRQBM; i++) { - pr->runq.bitmap[i] = 0; - } - setbit(MAXPRI - IDLEPRI, pr->runq.bitmap); - pr->runq.highq = IDLEPRI; - for (i = 0; i < NRQS; i++) { - queue_init(&(pr->runq.queues[i])); - } + /* setup run queue */ + simple_lock_init(&p->runq.lock, ETAP_THREAD_PROC_RUNQ); + for (i = 0; i < NRQBM; i++) + p->runq.bitmap[i] = 0; + setbit(MAXPRI - IDLEPRI, p->runq.bitmap); + p->runq.highq = IDLEPRI; + p->runq.urgency = p->runq.count = 0; + for (i = 0; i < NRQS; i++) + queue_init(&p->runq.queues[i]); + + p->state = PROCESSOR_OFF_LINE; + p->current_pri = MINPRI; + p->next_thread = THREAD_NULL; + p->idle_thread = THREAD_NULL; + timer_call_setup(&p->quantum_timer, thread_quantum_expire, p); + p->slice_quanta = 0; + p->processor_set = PROCESSOR_SET_NULL; + p->processor_set_next = PROCESSOR_SET_NULL; + simple_lock_init(&p->lock, ETAP_THREAD_PROC); + p->processor_self = IP_NULL; + p->slot_num = slot_num; +} - queue_init(&pr->processor_queue); - pr->state = PROCESSOR_OFF_LINE; - pr->next_thread = THREAD_NULL; - pr->idle_thread = THREAD_NULL; - timer_call_setup(&pr->quantum_timer, thread_quantum_expire, pr); - pr->slice_quanta = 0; - pr->processor_set = PROCESSOR_SET_NULL; - pr->processor_set_next = PROCESSOR_SET_NULL; - queue_init(&pr->processors); - simple_lock_init(&pr->lock, ETAP_THREAD_PROC); - pr->processor_self = IP_NULL; - pr->slot_num = slot_num; +/* + * pset_deallocate: + * + * Remove one reference to the processor set. Destroy processor_set + * if this was the last reference. + */ +void +pset_deallocate( + processor_set_t pset) +{ + if (pset == PROCESSOR_SET_NULL) + return; + + assert(pset == &default_pset); + return; } +/* + * pset_reference: + * + * Add one reference to the processor set. + */ +void +pset_reference( + processor_set_t pset) +{ + assert(pset == &default_pset); +} + +#define pset_reference_locked(pset) assert(pset == &default_pset) + /* * pset_remove_processor() removes a processor from a processor_set. * It can only be called on the current processor. Caller must @@ -257,8 +288,10 @@ pset_add_processor( /* * pset_remove_task() removes a task from a processor_set. - * Caller must hold locks on pset and task. Pset reference count - * is not decremented; caller must explicitly pset_deallocate. + * Caller must hold locks on pset and task (unless task has + * no references left, in which case just the pset lock is + * needed). Pset reference count is not decremented; + * caller must explicitly pset_deallocate. */ void pset_remove_task( @@ -286,13 +319,15 @@ pset_add_task( queue_enter(&pset->tasks, task, task_t, pset_tasks); task->processor_set = pset; pset->task_count++; - pset->ref_count++; + pset_reference_locked(pset); } /* * pset_remove_thread() removes a thread from a processor_set. - * Caller must hold locks on pset and thread. Pset reference count - * is not decremented; caller must explicitly pset_deallocate. + * Caller must hold locks on pset and thread (but only if thread + * has outstanding references that could be used to lookup the pset). + * The pset reference count is not decremented; caller must explicitly + * pset_deallocate. */ void pset_remove_thread( @@ -317,7 +352,7 @@ pset_add_thread( queue_enter(&pset->threads, thread, thread_t, pset_threads); thread->processor_set = pset; pset->thread_count++; - pset->ref_count++; + pset_reference_locked(pset); } /* @@ -336,45 +371,9 @@ thread_change_psets( queue_enter(&new_pset->threads, thread, thread_t, pset_threads); thread->processor_set = new_pset; new_pset->thread_count++; - new_pset->ref_count++; + pset_reference_locked(new_pset); } -/* - * pset_deallocate: - * - * Remove one reference to the processor set. Destroy processor_set - * if this was the last reference. - */ -void -pset_deallocate( - processor_set_t pset) -{ - if (pset == PROCESSOR_SET_NULL) - return; - - pset_lock(pset); - if (--pset->ref_count > 0) { - pset_unlock(pset); - return; - } - - panic("pset_deallocate: default_pset destroyed"); -} - -/* - * pset_reference: - * - * Add one reference to the processor set. - */ -void -pset_reference( - processor_set_t pset) -{ - pset_lock(pset); - pset->ref_count++; - pset_unlock(pset); -} - kern_return_t processor_info_count( @@ -476,7 +475,7 @@ processor_start( if (processor == master_processor) { thread_bind(current_thread(), processor); - thread_block((void (*)(void)) 0); + thread_block(THREAD_CONTINUE_NULL); kr = cpu_start(processor->slot_num); thread_bind(current_thread(), PROCESSOR_NULL); @@ -560,17 +559,14 @@ void pset_quanta_set( processor_set_t pset) { - register int i, ncpus; - - ncpus = pset->processor_count; + register int i, count = pset->processor_count; - for (i=1; i <= ncpus; i++) - pset->machine_quanta[i] = (ncpus + (i / 2)) / i; + for (i = 1; i <= count; i++) + pset->machine_quanta[i] = (count + (i / 2)) / i; pset->machine_quanta[0] = pset->machine_quanta[1]; - i = (pset->runq.count > ncpus)? ncpus: pset->runq.count; - pset->set_quanta = pset->machine_quanta[i]; + pset_quanta_update(pset); } kern_return_t @@ -760,10 +756,8 @@ processor_set_statistics( pset_lock(pset); load_info->task_count = pset->task_count; load_info->thread_count = pset->thread_count; - simple_lock(&pset->processors_lock); load_info->mach_factor = pset->mach_factor; load_info->load_average = pset->load_average; - simple_unlock(&pset->processors_lock); pset_unlock(pset); *count = PROCESSOR_SET_LOAD_INFO_COUNT; @@ -884,13 +878,17 @@ processor_set_things( task_t task; for (i = 0, task = (task_t) queue_first(&pset->tasks); - i < actual; - i++, task = (task_t) queue_next(&task->pset_tasks)) { - /* take ref for convert_task_to_port */ - task_reference(task); - tasks[i] = task; + !queue_end(&pset->tasks, (queue_entry_t) task); + task = (task_t) queue_next(&task->pset_tasks)) { + + task_lock(task); + if (task->ref_count > 0) { + /* take ref for convert_task_to_port */ + task_reference_locked(task); + tasks[i++] = task; + } + task_unlock(task); } - assert(queue_end(&pset->tasks, (queue_entry_t) task)); break; } @@ -898,33 +896,32 @@ processor_set_things( thread_act_t *thr_acts = (thread_act_t *) addr; thread_t thread; thread_act_t thr_act; - queue_head_t *list; - list = &pset->threads; - thread = (thread_t) queue_first(list); - i = 0; - while (i < actual && !queue_end(list, (queue_entry_t)thread)) { + for (i = 0, thread = (thread_t) queue_first(&pset->threads); + !queue_end(&pset->threads, (queue_entry_t)thread); + thread = (thread_t) queue_next(&thread->pset_threads)) { + thr_act = thread_lock_act(thread); if (thr_act && thr_act->ref_count > 0) { /* take ref for convert_act_to_port */ act_locked_act_reference(thr_act); - thr_acts[i] = thr_act; - i++; + thr_acts[i++] = thr_act; } thread_unlock_act(thread); - thread = (thread_t) queue_next(&thread->pset_threads); - } - if (i < actual) { - actual = i; - size_needed = actual * sizeof(mach_port_t); } break; - } + } } - + /* can unlock processor set now that we have the task/thread refs */ pset_unlock(pset); + if (i < actual) { + actual = i; + size_needed = actual * sizeof(mach_port_t); + } + assert(i == actual); + if (actual == 0) { /* no things, so return null pointer and deallocate memory */ *thing_list = 0; @@ -950,10 +947,10 @@ processor_set_things( } case THING_THREAD: { - thread_t *threads = (thread_t *) addr; + thread_act_t *acts = (thread_act_t *) addr; for (i = 0; i < actual; i++) - thread_deallocate(threads[i]); + act_deallocate(acts[i]); break; } } diff --git a/osfmk/kern/processor.h b/osfmk/kern/processor.h index cc236cac8..be99fc1e7 100644 --- a/osfmk/kern/processor.h +++ b/osfmk/kern/processor.h @@ -64,10 +64,11 @@ #include #include -extern struct processor_set default_pset; -extern processor_t master_processor; +#include + +#ifdef __APPLE_API_PRIVATE -#ifdef MACH_KERNEL_PRIVATE +#ifdef MACH_KERNEL_PRIVATE #include @@ -76,37 +77,48 @@ extern processor_t master_processor; #include #include #include +#include #include struct processor_set { - struct run_queue runq; /* runq for this set */ queue_head_t idle_queue; /* idle processors */ int idle_count; /* how many ? */ - decl_simple_lock_data(,idle_lock) /* lock for above */ + queue_head_t active_queue; /* active processors */ + decl_simple_lock_data(,sched_lock) /* lock for above */ + queue_head_t processors; /* all processors here */ int processor_count;/* how many ? */ decl_simple_lock_data(,processors_lock) /* lock for above */ + + struct run_queue runq; /* runq for this set */ + queue_head_t tasks; /* tasks assigned */ int task_count; /* how many */ queue_head_t threads; /* threads in this set */ int thread_count; /* how many */ int ref_count; /* structure ref count */ boolean_t active; /* is pset in use */ - decl_mutex_data(, lock) /* lock for everything else */ - struct ipc_port * pset_self; /* port for operations */ - struct ipc_port * pset_name_self; /* port for information */ + decl_mutex_data(, lock) /* lock for above */ + int set_quanta; /* timeslice quanta for timesharing */ int machine_quanta[NCPUS+1]; + + struct ipc_port * pset_self; /* port for operations */ + struct ipc_port * pset_name_self; /* port for information */ + + uint32_t run_count; /* number of threads running in set */ + integer_t mach_factor; /* mach_factor */ integer_t load_average; /* load_average */ - long sched_load; /* load avg for scheduler */ + uint32_t sched_load; /* load avg for scheduler */ }; struct processor { - struct run_queue runq; /* local runq for this processor */ - queue_chain_t processor_queue;/* idle/assign/shutdown queue link */ + queue_chain_t processor_queue;/* idle/active/action queue link, + * MUST remain the first element */ int state; /* See below */ + int current_pri; /* priority of current thread */ struct thread_shuttle *next_thread, /* next thread to run if dispatched */ *idle_thread; /* this processor's idle thread. */ @@ -115,14 +127,20 @@ struct processor { uint64_t quantum_end; /* time when current quantum ends */ uint64_t last_dispatch; /* time of last dispatch */ - processor_set_t processor_set; /* processor set I belong to */ - processor_set_t processor_set_next; /* set I will belong to */ + struct run_queue runq; /* local runq for this processor */ + + processor_set_t processor_set; /* current membership */ + processor_set_t processor_set_next; /* set to join in progress */ queue_chain_t processors; /* all processors in set */ decl_simple_lock_data(,lock) struct ipc_port *processor_self;/* port for operations */ + cpu_data_t *cpu_data; /* machine-dep per-cpu data */ int slot_num; /* machine-indep slot number */ }; +extern struct processor_set default_pset; +extern processor_t master_processor; + extern struct processor processor_array[NCPUS]; /* @@ -144,8 +162,8 @@ extern struct processor processor_array[NCPUS]; * Values for the processor state are defined below. If the processor * is off-line or being shutdown, then it is only necessary to lock * the processor to change its state. Otherwise it is only necessary - * to lock its processor set's idle_lock. Scheduler code will - * typically lock only the idle_lock, but processor manipulation code + * to lock its processor set's sched_lock. Scheduler code will + * typically lock only the sched_lock, but processor manipulation code * will often lock both. */ @@ -185,9 +203,18 @@ extern processor_t processor_ptr[NCPUS]; #define processor_lock(pr) simple_lock(&(pr)->lock) #define processor_unlock(pr) simple_unlock(&(pr)->lock) - extern void pset_sys_bootstrap(void); +#define pset_quanta_update(pset) \ +MACRO_BEGIN \ + int proc_count = (pset)->processor_count; \ + int runq_count = (pset)->runq.count; \ + \ + (pset)->set_quanta = (pset)->machine_quanta[ \ + (runq_count > proc_count)? \ + proc_count: runq_count]; \ +MACRO_END + /* Implemented by MD layer */ extern void cpu_up( @@ -225,12 +252,6 @@ extern void thread_change_psets( processor_set_t old_pset, processor_set_t new_pset); -extern void pset_deallocate( - processor_set_t pset); - -extern void pset_reference( - processor_set_t pset); - extern kern_return_t processor_assign( processor_t processor, processor_set_t new_pset, @@ -239,7 +260,8 @@ extern kern_return_t processor_assign( extern kern_return_t processor_info_count( processor_flavor_t flavor, mach_msg_type_number_t *count); -#endif /* MACH_KERNEL_PRIVATE */ + +#endif /* MACH_KERNEL_PRIVATE */ extern kern_return_t processor_start( processor_t processor); @@ -247,4 +269,12 @@ extern kern_return_t processor_start( extern kern_return_t processor_exit( processor_t processor); +#endif /* __APPLE_API_PRIVATE */ + +extern void pset_deallocate( + processor_set_t pset); + +extern void pset_reference( + processor_set_t pset); + #endif /* _KERN_PROCESSOR_H_ */ diff --git a/osfmk/kern/profile.c b/osfmk/kern/profile.c index ab210613c..599765fc8 100644 --- a/osfmk/kern/profile.c +++ b/osfmk/kern/profile.c @@ -115,7 +115,7 @@ profile_thread(void) if ((buf_entry = (buffer_t) prof_queue_entry) == NULLPBUF) { assert_wait((event_t) profile_thread, THREAD_UNINT); - thread_block((void (*)(void)) 0); + thread_block(THREAD_CONTINUE_NULL); if (current_thread()->wait_result != THREAD_AWAKENED) break; } else @@ -201,7 +201,7 @@ send_last_sample_buf(prof_data_t pbuf) thread_wakeup((event_t) profile_thread); assert_wait((event_t) &buf_entry->p_wakeme, THREAD_ABORTSAFE); splx(s); - thread_block((void (*)(void)) 0); + thread_block(THREAD_CONTINUE_NULL); } } diff --git a/osfmk/kern/queue.h b/osfmk/kern/queue.h index 541eef456..bdb700fb3 100644 --- a/osfmk/kern/queue.h +++ b/osfmk/kern/queue.h @@ -575,8 +575,12 @@ MACRO_END !queue_end((head), (queue_entry_t)(elt)); \ (elt) = (type) queue_next(&(elt)->field)) +#include + +#ifdef __APPLE_API_PRIVATE + +#ifdef MACH_KERNEL_PRIVATE -#ifdef MACH_KERNEL_PRIVATE /*----------------------------------------------------------------*/ /* * Define macros for queues with locks. @@ -613,6 +617,8 @@ MACRO_BEGIN \ simple_unlock(&(q)->lock); \ MACRO_END -#endif /* MACH_KERNEL_PRIVATE */ +#endif /* MACH_KERNEL_PRIVATE */ + +#endif /* __APPLE_API_PRIVATE */ #endif /* _KERN_QUEUE_H_ */ diff --git a/osfmk/kern/sched.h b/osfmk/kern/sched.h index 01f2d3ada..62c06f5ed 100644 --- a/osfmk/kern/sched.h +++ b/osfmk/kern/sched.h @@ -70,6 +70,7 @@ #include #include #include +#include #if STAT_TIME @@ -87,8 +88,8 @@ #endif /* STAT_TIME */ -#define NRQS 128 /* 128 run queues per cpu */ -#define NRQBM (NRQS / 32) /* number of run queue bit maps */ +#define NRQS 128 /* 128 levels per run queue */ +#define NRQBM (NRQS / 32) /* number of words per bit map */ #define MAXPRI (NRQS-1) #define MINPRI IDLEPRI /* lowest legal priority schedulable */ @@ -164,6 +165,9 @@ #define MINPRI_SYSTEM (MAXPRI_SYSTEM - (NRQS / 8) + 1) /* 64 */ #define MAXPRI_USER (MINPRI_SYSTEM - 1) /* 63 */ +#define BASEPRI_CONTROL (BASEPRI_DEFAULT + 17) /* 48 */ +#define BASEPRI_FOREGROUND (BASEPRI_DEFAULT + 16) /* 47 */ +#define BASEPRI_BACKGROUND (BASEPRI_DEFAULT + 15) /* 46 */ #define BASEPRI_DEFAULT (MAXPRI_USER - (NRQS / 4)) /* 31 */ #define MINPRI_USER MINPRI /* 0 */ @@ -179,7 +183,8 @@ struct run_queue { decl_simple_lock_data(,lock) /* one lock for all queues */ int bitmap[NRQBM]; /* run queue bitmap array */ int highq; /* highest runnable queue */ - int count; /* # of runnable threads */ + int urgency; /* level of preemption urgency */ + int count; /* # of threads in queue */ }; typedef struct run_queue *run_queue_t; @@ -187,6 +192,7 @@ typedef struct run_queue *run_queue_t; #define first_quantum(processor) ((processor)->slice_quanta > 0) +/* Invoked at splsched by a thread on itself */ #define csw_needed(thread, processor) ( \ ((thread)->state & TH_SUSP) || \ (first_quantum(processor)? \ @@ -211,6 +217,11 @@ extern void thread_quantum_expire( timer_call_param_t processor, timer_call_param_t thread); +/* Called at splsched by a thread on itself */ +extern ast_t csw_check( + thread_t thread, + processor_t processor); + extern uint32_t std_quantum, min_std_quantum; extern uint32_t std_quantum_us; @@ -242,10 +253,9 @@ extern unsigned sched_tick; /* * thread_timer_delta macro takes care of both thread timers. */ - #define thread_timer_delta(thread) \ MACRO_BEGIN \ - register unsigned delta; \ + register uint32_t delta; \ \ delta = 0; \ TIMER_DELTA((thread)->system_timer, \ diff --git a/osfmk/kern/sched_prim.c b/osfmk/kern/sched_prim.c index b4f351d41..c45c31048 100644 --- a/osfmk/kern/sched_prim.c +++ b/osfmk/kern/sched_prim.c @@ -114,10 +114,6 @@ int max_poll_quanta = MAX_POLL_QUANTA; #define SCHED_POLL_YIELD_SHIFT 4 /* 1/16 */ int sched_poll_yield_shift = SCHED_POLL_YIELD_SHIFT; -#define NO_KERNEL_PREEMPT 0 -#define KERNEL_PREEMPT 1 -int kernel_preemption_mode = KERNEL_PREEMPT; - uint32_t std_quantum_us; unsigned sched_tick; @@ -127,15 +123,8 @@ int sched_usec; #endif /* SIMPLE_CLOCK */ /* Forwards */ -void thread_continue(thread_t); - void wait_queues_init(void); -void set_pri( - thread_t thread, - int pri, - int resched); - thread_t choose_pset_thread( processor_t myprocessor, processor_set_t pset); @@ -143,18 +132,13 @@ thread_t choose_pset_thread( thread_t choose_thread( processor_t myprocessor); -int run_queue_enqueue( +boolean_t run_queue_enqueue( run_queue_t runq, thread_t thread, boolean_t tail); -void idle_thread_continue(void); void do_thread_scan(void); -void clear_wait_internal( - thread_t thread, - int result); - #if DEBUG void dump_run_queues( run_queue_t rq); @@ -395,6 +379,7 @@ void thread_timer_terminate(void) { thread_t thread = current_thread(); + wait_result_t res; spl_t s; s = splsched(); @@ -408,11 +393,13 @@ thread_timer_terminate(void) thread->wait_timer_active--; while (thread->wait_timer_active > 0) { - assert_wait((event_t)&thread->wait_timer_active, THREAD_UNINT); + res = assert_wait((event_t)&thread->wait_timer_active, THREAD_UNINT); + assert(res == THREAD_WAITING); wake_unlock(thread); splx(s); - thread_block((void (*)(void)) 0); + res = thread_block(THREAD_CONTINUE_NULL); + assert(res == THREAD_AWAKENED); s = splsched(); wake_lock(thread); @@ -421,11 +408,13 @@ thread_timer_terminate(void) thread->depress_timer_active--; while (thread->depress_timer_active > 0) { - assert_wait((event_t)&thread->depress_timer_active, THREAD_UNINT); + res = assert_wait((event_t)&thread->depress_timer_active, THREAD_UNINT); + assert(res == THREAD_WAITING); wake_unlock(thread); splx(s); - thread_block((void (*)(void)) 0); + res = thread_block(THREAD_CONTINUE_NULL); + assert(res == THREAD_AWAKENED); s = splsched(); wake_lock(thread); @@ -444,44 +433,107 @@ thread_timer_terminate(void) * Conditions: * thread lock held, IPC locks may be held. * thread must have been pulled from wait queue under same lock hold. + * Returns: + * KERN_SUCCESS - Thread was set running + * KERN_NOT_WAITING - Thread was not waiting */ -void +kern_return_t thread_go_locked( thread_t thread, - int result) + wait_result_t result) { assert(thread->at_safe_point == FALSE); - assert(thread->wait_event == NO_EVENT); + assert(thread->wait_event == NO_EVENT64); assert(thread->wait_queue == WAIT_QUEUE_NULL); - if (thread->state & TH_WAIT) { + if ((thread->state & (TH_WAIT|TH_TERMINATE)) == TH_WAIT) { thread->state &= ~(TH_WAIT|TH_UNINT); if (!(thread->state & TH_RUN)) { thread->state |= TH_RUN; - _mk_sp_thread_unblock(thread); + if (thread->active_callout) + call_thread_unblock(); + + if (!(thread->state & TH_IDLE)) { + _mk_sp_thread_unblock(thread); + hw_atomic_add(&thread->processor_set->run_count, 1); + } } thread->wait_result = result; + return KERN_SUCCESS; } + return KERN_NOT_WAITING; } -void +/* + * Routine: thread_mark_wait_locked + * Purpose: + * Mark a thread as waiting. If, given the circumstances, + * it doesn't want to wait (i.e. already aborted), then + * indicate that in the return value. + * Conditions: + * at splsched() and thread is locked. + */ +__private_extern__ +wait_result_t thread_mark_wait_locked( - thread_t thread, - int interruptible) + thread_t thread, + wait_interrupt_t interruptible) { + wait_result_t wait_result; + boolean_t at_safe_point; assert(thread == current_thread()); - thread->wait_result = -1; /* JMM - Needed for non-assert kernel */ - thread->state |= (interruptible && thread->interruptible) ? - TH_WAIT : (TH_WAIT | TH_UNINT); - thread->at_safe_point = (interruptible == THREAD_ABORTSAFE) && (thread->interruptible); - thread->sleep_stamp = sched_tick; + /* + * The thread may have certain types of interrupts/aborts masked + * off. Even if the wait location says these types of interrupts + * are OK, we have to honor mask settings (outer-scoped code may + * not be able to handle aborts at the moment). + */ + if (interruptible > thread->interrupt_level) + interruptible = thread->interrupt_level; + + at_safe_point = (interruptible == THREAD_ABORTSAFE); + + if ((interruptible == THREAD_UNINT) || + !(thread->state & TH_ABORT) || + (!at_safe_point && (thread->state & TH_ABORT_SAFELY))) { + thread->state |= (interruptible) ? TH_WAIT : (TH_WAIT | TH_UNINT); + thread->at_safe_point = at_safe_point; + thread->sleep_stamp = sched_tick; + return (thread->wait_result = THREAD_WAITING); + } else if (thread->state & TH_ABORT_SAFELY) { + thread->state &= ~(TH_ABORT|TH_ABORT_SAFELY); + } + return (thread->wait_result = THREAD_INTERRUPTED); } +/* + * Routine: thread_interrupt_level + * Purpose: + * Set the maximum interruptible state for the + * current thread. The effective value of any + * interruptible flag passed into assert_wait + * will never exceed this. + * + * Useful for code that must not be interrupted, + * but which calls code that doesn't know that. + * Returns: + * The old interrupt level for the thread. + */ +__private_extern__ +wait_interrupt_t +thread_interrupt_level( + wait_interrupt_t new_level) +{ + thread_t thread = current_thread(); + wait_interrupt_t result = thread->interrupt_level; + thread->interrupt_level = new_level; + return result; +} /* * Routine: assert_wait_timeout @@ -491,15 +543,17 @@ thread_mark_wait_locked( */ unsigned int assert_wait_timeout_event; -void +wait_result_t assert_wait_timeout( - mach_msg_timeout_t msecs, - int interruptible) + mach_msg_timeout_t msecs, + wait_interrupt_t interruptible) { - spl_t s; + wait_result_t res; - assert_wait((event_t)&assert_wait_timeout_event, interruptible); - thread_set_timer(msecs, 1000*NSEC_PER_USEC); + res = assert_wait((event_t)&assert_wait_timeout_event, interruptible); + if (res == THREAD_WAITING) + thread_set_timer(msecs, 1000*NSEC_PER_USEC); + return res; } /* @@ -531,10 +585,10 @@ assert_wait_possible(void) * Assert that the current thread is about to go to * sleep until the specified event occurs. */ -void +wait_result_t assert_wait( event_t event, - int interruptible) + wait_interrupt_t interruptible) { register wait_queue_t wq; register int index; @@ -544,12 +598,172 @@ assert_wait( index = wait_hash(event); wq = &wait_queues[index]; - (void)wait_queue_assert_wait(wq, - event, - interruptible); + return wait_queue_assert_wait(wq, event, interruptible); +} + + +/* + * thread_sleep_fast_usimple_lock: + * + * Cause the current thread to wait until the specified event + * occurs. The specified simple_lock is unlocked before releasing + * the cpu and re-acquired as part of waking up. + * + * This is the simple lock sleep interface for components that use a + * faster version of simple_lock() than is provided by usimple_lock(). + */ +__private_extern__ wait_result_t +thread_sleep_fast_usimple_lock( + event_t event, + simple_lock_t lock, + wait_interrupt_t interruptible) +{ + wait_result_t res; + + res = assert_wait(event, interruptible); + if (res == THREAD_WAITING) { + simple_unlock(lock); + res = thread_block(THREAD_CONTINUE_NULL); + simple_lock(lock); + } + return res; } + +/* + * thread_sleep_usimple_lock: + * + * Cause the current thread to wait until the specified event + * occurs. The specified usimple_lock is unlocked before releasing + * the cpu and re-acquired as part of waking up. + * + * This is the simple lock sleep interface for components where + * simple_lock() is defined in terms of usimple_lock(). + */ +wait_result_t +thread_sleep_usimple_lock( + event_t event, + usimple_lock_t lock, + wait_interrupt_t interruptible) +{ + wait_result_t res; + + res = assert_wait(event, interruptible); + if (res == THREAD_WAITING) { + usimple_unlock(lock); + res = thread_block(THREAD_CONTINUE_NULL); + usimple_lock(lock); + } + return res; +} + +/* + * thread_sleep_mutex: + * + * Cause the current thread to wait until the specified event + * occurs. The specified mutex is unlocked before releasing + * the cpu. The mutex will be re-acquired before returning. + * + * JMM - Add hint to make sure mutex is available before rousting + */ +wait_result_t +thread_sleep_mutex( + event_t event, + mutex_t *mutex, + wait_interrupt_t interruptible) +{ + wait_result_t res; + + res = assert_wait(event, interruptible); + if (res == THREAD_WAITING) { + mutex_unlock(mutex); + res = thread_block(THREAD_CONTINUE_NULL); + mutex_lock(mutex); + } + return res; +} +/* + * thread_sleep_mutex_deadline: + * + * Cause the current thread to wait until the specified event + * (or deadline) occurs. The specified mutex is unlocked before + * releasing the cpu. The mutex will be re-acquired before returning. + * + * JMM - Add hint to make sure mutex is available before rousting + */ +wait_result_t +thread_sleep_mutex_deadline( + event_t event, + mutex_t *mutex, + uint64_t deadline, + wait_interrupt_t interruptible) +{ + wait_result_t res; + + res = assert_wait(event, interruptible); + if (res == THREAD_WAITING) { + mutex_unlock(mutex); + thread_set_timer_deadline(deadline); + res = thread_block(THREAD_CONTINUE_NULL); + if (res != THREAD_TIMED_OUT) + thread_cancel_timer(); + mutex_lock(mutex); + } + return res; +} + +/* + * thread_sleep_lock_write: + * + * Cause the current thread to wait until the specified event + * occurs. The specified (write) lock is unlocked before releasing + * the cpu. The (write) lock will be re-acquired before returning. + * + * JMM - Add hint to make sure mutex is available before rousting + */ +wait_result_t +thread_sleep_lock_write( + event_t event, + lock_t *lock, + wait_interrupt_t interruptible) +{ + wait_result_t res; + + res = assert_wait(event, interruptible); + if (res == THREAD_WAITING) { + lock_write_done(lock); + res = thread_block(THREAD_CONTINUE_NULL); + lock_write(lock); + } + return res; +} + + +/* + * thread_sleep_funnel: + * + * Cause the current thread to wait until the specified event + * occurs. If the thread is funnelled, the funnel will be released + * before giving up the cpu. The funnel will be re-acquired before returning. + * + * JMM - Right now the funnel is dropped and re-acquired inside + * thread_block(). At some point, this may give thread_block() a hint. + */ +wait_result_t +thread_sleep_funnel( + event_t event, + wait_interrupt_t interruptible) +{ + wait_result_t res; + + res = assert_wait(event, interruptible); + if (res == THREAD_WAITING) { + res = thread_block(THREAD_CONTINUE_NULL); + } + return res; +} + /* * thread_[un]stop(thread) * Once a thread has blocked interruptibly (via assert_wait) prevent @@ -568,32 +782,62 @@ assert_wait( */ boolean_t thread_stop( - thread_t thread) + thread_t thread) { - spl_t s; + spl_t s = splsched(); - s = splsched(); wake_lock(thread); while (thread->state & TH_SUSP) { - int wait_result; + wait_result_t result; thread->wake_active = TRUE; - assert_wait((event_t)&thread->wake_active, THREAD_ABORTSAFE); + result = assert_wait(&thread->wake_active, THREAD_ABORTSAFE); wake_unlock(thread); splx(s); - wait_result = thread_block((void (*)(void)) 0); - if (wait_result != THREAD_AWAKENED) + if (result == THREAD_WAITING) + result = thread_block(THREAD_CONTINUE_NULL); + + if (result != THREAD_AWAKENED) return (FALSE); s = splsched(); wake_lock(thread); } + thread_lock(thread); thread->state |= TH_SUSP; - thread_unlock(thread); + while (thread->state & TH_RUN) { + wait_result_t result; + processor_t processor = thread->last_processor; + + if ( processor != PROCESSOR_NULL && + processor->state == PROCESSOR_RUNNING && + processor->cpu_data->active_thread == thread ) + cause_ast_check(processor); + thread_unlock(thread); + + thread->wake_active = TRUE; + result = assert_wait(&thread->wake_active, THREAD_ABORTSAFE); + wake_unlock(thread); + splx(s); + + if (result == THREAD_WAITING) + result = thread_block(THREAD_CONTINUE_NULL); + + if (result != THREAD_AWAKENED) { + thread_unstop(thread); + return (FALSE); + } + + s = splsched(); + wake_lock(thread); + thread_lock(thread); + } + + thread_unlock(thread); wake_unlock(thread); splx(s); @@ -606,19 +850,20 @@ thread_stop( */ void thread_unstop( - thread_t thread) + thread_t thread) { - spl_t s; + spl_t s = splsched(); - s = splsched(); wake_lock(thread); thread_lock(thread); - if ((thread->state & (TH_RUN|TH_WAIT|TH_SUSP/*|TH_UNINT*/)) == TH_SUSP) { + if ((thread->state & (TH_RUN|TH_WAIT|TH_SUSP)) == TH_SUSP) { thread->state &= ~TH_SUSP; thread->state |= TH_RUN; + assert(!(thread->state & TH_IDLE)); _mk_sp_thread_unblock(thread); + hw_atomic_add(&thread->processor_set->run_count, 1); } else if (thread->state & TH_SUSP) { @@ -629,8 +874,8 @@ thread_unstop( thread_unlock(thread); wake_unlock(thread); splx(s); - thread_wakeup((event_t)&thread->wake_active); + thread_wakeup(&thread->wake_active); return; } } @@ -645,58 +890,46 @@ thread_unstop( */ boolean_t thread_wait( - thread_t thread) + thread_t thread) { - spl_t s; + spl_t s = splsched(); - s = splsched(); wake_lock(thread); + thread_lock(thread); - while (thread->state & (TH_RUN/*|TH_UNINT*/)) { - int wait_result; + while (thread->state & TH_RUN) { + wait_result_t result; + processor_t processor = thread->last_processor; - if (thread->last_processor != PROCESSOR_NULL) - cause_ast_check(thread->last_processor); + if ( processor != PROCESSOR_NULL && + processor->state == PROCESSOR_RUNNING && + processor->cpu_data->active_thread == thread ) + cause_ast_check(processor); + thread_unlock(thread); thread->wake_active = TRUE; - assert_wait((event_t)&thread->wake_active, THREAD_ABORTSAFE); + result = assert_wait(&thread->wake_active, THREAD_ABORTSAFE); wake_unlock(thread); splx(s); - wait_result = thread_block((void (*)(void))0); - if (wait_result != THREAD_AWAKENED) - return FALSE; + if (result == THREAD_WAITING) + result = thread_block(THREAD_CONTINUE_NULL); + + if (result != THREAD_AWAKENED) + return (FALSE); s = splsched(); wake_lock(thread); + thread_lock(thread); } + thread_unlock(thread); wake_unlock(thread); splx(s); return (TRUE); } - -/* - * thread_stop_wait(thread) - * Stop the thread then wait for it to block interruptibly - */ -boolean_t -thread_stop_wait( - thread_t thread) -{ - if (thread_stop(thread)) { - if (thread_wait(thread)) - return (TRUE); - - thread_unstop(thread); - } - - return (FALSE); -} - - /* * Routine: clear_wait_internal * @@ -708,23 +941,46 @@ thread_stop_wait( * Conditions: * At splsched * the thread is locked. + * Returns: + * KERN_SUCCESS thread was rousted out a wait + * KERN_FAILURE thread was waiting but could not be rousted + * KERN_NOT_WAITING thread was not waiting */ -void +__private_extern__ kern_return_t clear_wait_internal( - thread_t thread, - int result) + thread_t thread, + wait_result_t result) { - /* - * If the thread isn't in a wait queue, just set it running. Otherwise, - * try to remove it from the queue and, if successful, then set it - * running. NEVER interrupt an uninterruptible thread. - */ - if (!((result == THREAD_INTERRUPTED) && (thread->state & TH_UNINT))) { - if (wait_queue_assert_possible(thread) || - (wait_queue_remove(thread) == KERN_SUCCESS)) { - thread_go_locked(thread, result); + wait_queue_t wq = thread->wait_queue; + kern_return_t ret; + int loop_count; + + loop_count = 0; + do { + if ((result == THREAD_INTERRUPTED) && (thread->state & TH_UNINT)) + return KERN_FAILURE; + + if (wq != WAIT_QUEUE_NULL) { + if (wait_queue_lock_try(wq)) { + wait_queue_pull_thread_locked(wq, thread, TRUE); + /* wait queue unlocked, thread still locked */ + } else { + thread_unlock(thread); + delay(1); + thread_lock(thread); + + if (wq != thread->wait_queue) { + return KERN_NOT_WAITING; /* we know it moved */ + } + continue; + } } - } + ret = thread_go_locked(thread, result); + return ret; + } while (++loop_count < LockTimeOut); + panic("clear_wait_internal: deadlock: thread=0x%x, wq=0x%x, cpu=%d\n", + thread, wq, cpu_number()); + return KERN_FAILURE; } @@ -738,18 +994,20 @@ clear_wait_internal( * thread thread to awaken * result Wakeup result the thread should see */ -void +kern_return_t clear_wait( - thread_t thread, - int result) + thread_t thread, + wait_result_t result) { + kern_return_t ret; spl_t s; s = splsched(); thread_lock(thread); - clear_wait_internal(thread, result); + ret = clear_wait_internal(thread, result); thread_unlock(thread); splx(s); + return ret; } @@ -760,11 +1018,11 @@ clear_wait( * and thread_wakeup_one. * */ -void +kern_return_t thread_wakeup_prim( event_t event, boolean_t one_thread, - int result) + wait_result_t result) { register wait_queue_t wq; register int index; @@ -772,9 +1030,9 @@ thread_wakeup_prim( index = wait_hash(event); wq = &wait_queues[index]; if (one_thread) - wait_queue_wakeup_one(wq, event, result); + return (wait_queue_wakeup_one(wq, event, result)); else - wait_queue_wakeup_all(wq, event, result); + return (wait_queue_wakeup_all(wq, event, result)); } /* @@ -818,19 +1076,14 @@ thread_select( * Check for other non-idle runnable threads. */ pset = myprocessor->processor_set; - thread = current_thread(); - - /* - * Update set_quanta for timesharing. - */ - pset->set_quanta = pset->machine_quanta[ - (pset->runq.count > pset->processor_count) ? - pset->processor_count : pset->runq.count]; + thread = myprocessor->cpu_data->active_thread; /* Update the thread's priority */ if (thread->sched_stamp != sched_tick) update_priority(thread); + myprocessor->current_pri = thread->sched_pri; + simple_lock(&runq->lock); simple_lock(&pset->runq.lock); @@ -852,11 +1105,8 @@ thread_select( (thread->sched_mode & TH_MODE_TIMESHARE)? pset->set_quanta: 1; } else - if (other_runnable) { - simple_unlock(&pset->runq.lock); - simple_unlock(&runq->lock); + if (other_runnable) thread = choose_thread(myprocessor); - } else { simple_unlock(&pset->runq.lock); simple_unlock(&runq->lock); @@ -866,23 +1116,19 @@ thread_select( * was running. If it was in an assignment or shutdown, * leave it alone. Return its idle thread. */ - simple_lock(&pset->idle_lock); + simple_lock(&pset->sched_lock); if (myprocessor->state == PROCESSOR_RUNNING) { + remqueue(&pset->active_queue, (queue_entry_t)myprocessor); myprocessor->state = PROCESSOR_IDLE; - /* - * XXX Until it goes away, put master on end of queue, others - * XXX on front so master gets used last. - */ + if (myprocessor == master_processor) - queue_enter(&(pset->idle_queue), myprocessor, - processor_t, processor_queue); + enqueue_tail(&pset->idle_queue, (queue_entry_t)myprocessor); else - queue_enter_first(&(pset->idle_queue), myprocessor, - processor_t, processor_queue); + enqueue_head(&pset->idle_queue, (queue_entry_t)myprocessor); pset->idle_count++; } - simple_unlock(&pset->idle_lock); + simple_unlock(&pset->sched_lock); thread = myprocessor->idle_thread; } @@ -896,8 +1142,7 @@ thread_select( * If continuation is non-zero, and the current thread is blocked, * then it will resume by executing continuation on a new stack. * Returns TRUE if the hand-off succeeds. - * The reason parameter contains | AST_QUANTUM if the thread blocked - * because its quantum expired. + * * Assumes splsched. */ @@ -912,297 +1157,300 @@ thread_invoke( register thread_t old_thread, register thread_t new_thread, int reason, - void (*continuation)(void)) + thread_continue_t old_cont) { - void (*lcont)(void); + thread_continue_t new_cont; + processor_t processor; - if (cpu_data[cpu_number()].preemption_level != 0) + if (get_preemption_level() != 0) panic("thread_invoke: preemption_level %d\n", - cpu_data[cpu_number()].preemption_level); + get_preemption_level()); /* - * Mark thread interruptible. + * Mark thread interruptible. */ thread_lock(new_thread); new_thread->state &= ~TH_UNINT; assert(thread_runnable(new_thread)); - assert(old_thread->continuation == (void (*)(void))0); + assert(old_thread->continuation == NULL); + /* + * Allow time constraint threads to hang onto + * a stack. + */ if ( (old_thread->sched_mode & TH_MODE_REALTIME) && !old_thread->stack_privilege ) { old_thread->stack_privilege = old_thread->kernel_stack; } - if (continuation != (void (*)()) 0) { - switch (new_thread->state & TH_STACK_STATE) { - case TH_STACK_HANDOFF: - - /* - * If the old thread has stack privilege, we can't give - * his stack away. So go and get him one and treat this - * as a traditional context switch. - */ - if (old_thread->stack_privilege == current_stack()) - goto get_new_stack; + if (old_cont != NULL) { + if (new_thread->state & TH_STACK_HANDOFF) { + /* + * If the old thread is using a privileged stack, + * check to see whether we can exchange it with + * that of the new thread. + */ + if ( old_thread->kernel_stack == old_thread->stack_privilege && + !new_thread->stack_privilege) + goto need_stack; - /* - * Make the whole handoff/dispatch atomic to match the - * non-handoff case. - */ - disable_preemption(); + new_thread->state &= ~TH_STACK_HANDOFF; + new_cont = new_thread->continuation; + new_thread->continuation = NULL; - /* - * Set up ast context of new thread and switch to its timer. - */ - new_thread->state &= ~(TH_STACK_HANDOFF|TH_UNINT); - new_thread->last_processor = current_processor(); - ast_context(new_thread->top_act, cpu_number()); - timer_switch(&new_thread->system_timer); - thread_unlock(new_thread); + /* + * Set up ast context of new thread and switch + * to its timer. + */ + processor = current_processor(); + new_thread->last_processor = processor; + processor->current_pri = new_thread->sched_pri; + ast_context(new_thread->top_act, processor->slot_num); + timer_switch(&new_thread->system_timer); + thread_unlock(new_thread); - current_task()->csw++; + current_task()->csw++; - old_thread->continuation = continuation; - stack_handoff(old_thread, new_thread); - - wake_lock(old_thread); - thread_lock(old_thread); - act_machine_sv_free(old_thread->top_act); + old_thread->reason = reason; + old_thread->continuation = old_cont; - _mk_sp_thread_done(old_thread); + _mk_sp_thread_done(old_thread, new_thread, processor); - /* - * inline thread_dispatch but don't free stack - */ + stack_handoff(old_thread, new_thread); + + _mk_sp_thread_begin(new_thread, processor); - switch (old_thread->state & (TH_RUN|TH_WAIT|TH_UNINT|TH_IDLE)) { - - case TH_RUN | TH_UNINT: - case TH_RUN: - /* - * No reason to stop. Put back on a run queue. - */ - old_thread->state |= TH_STACK_HANDOFF; - _mk_sp_thread_dispatch(old_thread); - break; - - case TH_RUN | TH_WAIT | TH_UNINT: - case TH_RUN | TH_WAIT: - old_thread->sleep_stamp = sched_tick; - /* fallthrough */ - - case TH_WAIT: /* this happens! */ - /* - * Waiting - */ - old_thread->state |= TH_STACK_HANDOFF; - old_thread->state &= ~TH_RUN; - if (old_thread->state & TH_TERMINATE) - thread_reaper_enqueue(old_thread); - - if (old_thread->wake_active) { - old_thread->wake_active = FALSE; - thread_unlock(old_thread); - wake_unlock(old_thread); - thread_wakeup((event_t)&old_thread->wake_active); wake_lock(old_thread); thread_lock(old_thread); - } - break; - - case TH_RUN | TH_IDLE: - /* - * Drop idle thread -- it is already in - * idle_thread_array. - */ - old_thread->state |= TH_STACK_HANDOFF; - break; - - default: - panic("State 0x%x \n",old_thread->state); - } - thread_unlock(old_thread); - wake_unlock(old_thread); + /* + * Inline thread_dispatch but + * don't free stack. + */ + + switch (old_thread->state & (TH_RUN|TH_WAIT|TH_UNINT|TH_IDLE)) { + + case TH_RUN | TH_UNINT: + case TH_RUN: + /* + * Still running, put back + * onto a run queue. + */ + old_thread->state |= TH_STACK_HANDOFF; + _mk_sp_thread_dispatch(old_thread); + + thread_unlock(old_thread); + wake_unlock(old_thread); + break; - thread_lock(new_thread); - assert(thread_runnable(new_thread)); - _mk_sp_thread_begin(new_thread); + case TH_RUN | TH_WAIT | TH_UNINT: + case TH_RUN | TH_WAIT: + { + boolean_t reap, wake, callblock; - lcont = new_thread->continuation; - new_thread->continuation = (void(*)(void))0; + /* + * Waiting. + */ + old_thread->sleep_stamp = sched_tick; + old_thread->state |= TH_STACK_HANDOFF; + old_thread->state &= ~TH_RUN; + hw_atomic_sub(&old_thread->processor_set->run_count, 1); + callblock = old_thread->active_callout; + wake = old_thread->wake_active; + old_thread->wake_active = FALSE; + reap = (old_thread->state & TH_TERMINATE)? TRUE: FALSE; + + thread_unlock(old_thread); + wake_unlock(old_thread); + + if (callblock) + call_thread_block(); + + if (wake) + thread_wakeup((event_t)&old_thread->wake_active); + + if (reap) + thread_reaper_enqueue(old_thread); + break; + } - thread_unlock(new_thread); - enable_preemption(); + case TH_RUN | TH_IDLE: + /* + * The idle threads don't go + * onto a run queue. + */ + old_thread->state |= TH_STACK_HANDOFF; + thread_unlock(old_thread); + wake_unlock(old_thread); + break; - counter_always(c_thread_invoke_hits++); + default: + panic("thread_invoke: state 0x%x\n", old_thread->state); + } - if (new_thread->funnel_state & TH_FN_REFUNNEL) { - kern_return_t save_wait_result; - new_thread->funnel_state = 0; - save_wait_result = new_thread->wait_result; - KERNEL_DEBUG(0x6032428 | DBG_FUNC_NONE, new_thread->funnel_lock, 2, 0, 0, 0); - //mutex_lock(new_thread->funnel_lock); - funnel_lock(new_thread->funnel_lock); - KERNEL_DEBUG(0x6032430 | DBG_FUNC_NONE, new_thread->funnel_lock, 2, 0, 0, 0); - new_thread->funnel_state = TH_FN_OWNED; - new_thread->wait_result = save_wait_result; - } - (void) spllo(); + counter_always(c_thread_invoke_hits++); - assert(lcont); - call_continuation(lcont); - /*NOTREACHED*/ - return TRUE; + if (new_thread->funnel_state & TH_FN_REFUNNEL) { + kern_return_t wait_result = new_thread->wait_result; - case TH_STACK_ALLOC: - /* - * waiting for a stack - */ - thread_swapin(new_thread); - thread_unlock(new_thread); - counter_always(c_thread_invoke_misses++); - return FALSE; - - case 0: - /* - * already has a stack - can't handoff - */ - if (new_thread == old_thread) { + new_thread->funnel_state = 0; + KERNEL_DEBUG(0x6032428 | DBG_FUNC_NONE, + new_thread->funnel_lock, 2, 0, 0, 0); + funnel_lock(new_thread->funnel_lock); + KERNEL_DEBUG(0x6032430 | DBG_FUNC_NONE, + new_thread->funnel_lock, 2, 0, 0, 0); + new_thread->funnel_state = TH_FN_OWNED; + new_thread->wait_result = wait_result; + } + (void) spllo(); - /* same thread but with continuation */ - counter(++c_thread_invoke_same); - thread_unlock(new_thread); - - if (old_thread->funnel_state & TH_FN_REFUNNEL) { - kern_return_t save_wait_result; - - old_thread->funnel_state = 0; - save_wait_result = old_thread->wait_result; - KERNEL_DEBUG(0x6032428 | DBG_FUNC_NONE, old_thread->funnel_lock, 3, 0, 0, 0); - funnel_lock(old_thread->funnel_lock); - KERNEL_DEBUG(0x6032430 | DBG_FUNC_NONE, old_thread->funnel_lock, 3, 0, 0, 0); - old_thread->funnel_state = TH_FN_OWNED; - old_thread->wait_result = save_wait_result; - } - (void) spllo(); - call_continuation(continuation); - /*NOTREACHED*/ + assert(new_cont); + call_continuation(new_cont); + /*NOTREACHED*/ + return (TRUE); } - break; - } - } else { - /* - * check that the new thread has a stack - */ - if (new_thread->state & TH_STACK_STATE) { - get_new_stack: - /* has no stack. if not already waiting for one try to get one */ - if ((new_thread->state & TH_STACK_ALLOC) || - /* not already waiting. nonblocking try to get one */ - !stack_alloc_try(new_thread, thread_continue)) - { - /* couldn't get one. schedule new thread to get a stack and - return failure so we can try another thread. */ - thread_swapin(new_thread); - thread_unlock(new_thread); + else + if (new_thread->state & TH_STACK_ALLOC) { + /* + * Waiting for a stack + */ counter_always(c_thread_invoke_misses++); - return FALSE; - } - } else if (old_thread == new_thread) { - counter(++c_thread_invoke_same); - thread_unlock(new_thread); - return TRUE; - } - - /* new thread now has a stack. it has been setup to resume in - thread_continue so it can dispatch the old thread, deal with - funnelling and then go to it's true continuation point */ + thread_unlock(new_thread); + return (FALSE); + } + else + if (new_thread == old_thread) { + /* same thread but with continuation */ + counter(++c_thread_invoke_same); + thread_unlock(new_thread); + + if (new_thread->funnel_state & TH_FN_REFUNNEL) { + kern_return_t wait_result = new_thread->wait_result; + + new_thread->funnel_state = 0; + KERNEL_DEBUG(0x6032428 | DBG_FUNC_NONE, + new_thread->funnel_lock, 3, 0, 0, 0); + funnel_lock(new_thread->funnel_lock); + KERNEL_DEBUG(0x6032430 | DBG_FUNC_NONE, + new_thread->funnel_lock, 3, 0, 0, 0); + new_thread->funnel_state = TH_FN_OWNED; + new_thread->wait_result = wait_result; + } + (void) spllo(); + call_continuation(old_cont); + /*NOTREACHED*/ + } } + else { + /* + * Check that the new thread has a stack + */ + if (new_thread->state & TH_STACK_HANDOFF) { +need_stack: + if (!stack_alloc_try(new_thread, thread_continue)) { + counter_always(c_thread_invoke_misses++); + thread_swapin(new_thread); + return (FALSE); + } - new_thread->state &= ~(TH_STACK_HANDOFF | TH_UNINT); + new_thread->state &= ~TH_STACK_HANDOFF; + } + else + if (new_thread->state & TH_STACK_ALLOC) { + /* + * Waiting for a stack + */ + counter_always(c_thread_invoke_misses++); + thread_unlock(new_thread); + return (FALSE); + } + else + if (old_thread == new_thread) { + counter(++c_thread_invoke_same); + thread_unlock(new_thread); + return (TRUE); + } + } /* - * Set up ast context of new thread and switch to its timer. + * Set up ast context of new thread and switch to its timer. */ - new_thread->last_processor = current_processor(); - ast_context(new_thread->top_act, cpu_number()); + processor = current_processor(); + new_thread->last_processor = processor; + processor->current_pri = new_thread->sched_pri; + ast_context(new_thread->top_act, processor->slot_num); timer_switch(&new_thread->system_timer); assert(thread_runnable(new_thread)); - - /* - * N.B. On return from the call to switch_context, 'old_thread' - * points at the thread that yielded to us. Unfortunately, at - * this point, there are no simple_locks held, so if we are preempted - * before the call to thread_dispatch blocks preemption, it is - * possible for 'old_thread' to terminate, leaving us with a - * stale thread pointer. - */ - disable_preemption(); - thread_unlock(new_thread); counter_always(c_thread_invoke_csw++); current_task()->csw++; - thread_lock(old_thread); - old_thread->reason = reason; assert(old_thread->runq == RUN_QUEUE_NULL); + old_thread->reason = reason; + old_thread->continuation = old_cont; - if (continuation != (void (*)(void))0) - old_thread->continuation = continuation; - - _mk_sp_thread_done(old_thread); - thread_unlock(old_thread); + _mk_sp_thread_done(old_thread, new_thread, processor); /* * switch_context is machine-dependent. It does the * machine-dependent components of a context-switch, like * changing address spaces. It updates active_threads. */ - old_thread = switch_context(old_thread, continuation, new_thread); + old_thread = switch_context(old_thread, old_cont, new_thread); /* Now on new thread's stack. Set a local variable to refer to it. */ new_thread = __current_thread(); assert(old_thread != new_thread); - thread_lock(new_thread); assert(thread_runnable(new_thread)); - _mk_sp_thread_begin(new_thread); - thread_unlock(new_thread); + _mk_sp_thread_begin(new_thread, new_thread->last_processor); /* * We're back. Now old_thread is the thread that resumed * us, and we have to dispatch it. */ - thread_dispatch(old_thread); - enable_preemption(); - - /* if we get here and 'continuation' is set that means the - * switch_context() path returned and did not call out - * to the continuation. we will do it manually here */ - if (continuation) { - call_continuation(continuation); - /* NOTREACHED */ + + if (old_cont) { + if (new_thread->funnel_state & TH_FN_REFUNNEL) { + kern_return_t wait_result = new_thread->wait_result; + + new_thread->funnel_state = 0; + KERNEL_DEBUG(0x6032428 | DBG_FUNC_NONE, + new_thread->funnel_lock, 3, 0, 0, 0); + funnel_lock(new_thread->funnel_lock); + KERNEL_DEBUG(0x6032430 | DBG_FUNC_NONE, + new_thread->funnel_lock, 3, 0, 0, 0); + new_thread->funnel_state = TH_FN_OWNED; + new_thread->wait_result = wait_result; + } + (void) spllo(); + call_continuation(old_cont); + /*NOTREACHED*/ } - return TRUE; + return (TRUE); } /* * thread_continue: * - * Called when the launching a new thread, at splsched(); + * Called when a thread gets a new stack, at splsched(); */ void thread_continue( register thread_t old_thread) { - register thread_t self = current_thread(); - register void (*continuation)(); + register thread_t self = current_thread(); + register thread_continue_t continuation; + + continuation = self->continuation; + self->continuation = NULL; + + _mk_sp_thread_begin(self, self->last_processor); /* * We must dispatch the old thread and then @@ -1212,39 +1460,20 @@ thread_continue( */ if (old_thread != THREAD_NULL) thread_dispatch(old_thread); - - thread_lock(self); - continuation = self->continuation; - self->continuation = (void (*)(void))0; - - _mk_sp_thread_begin(self); - thread_unlock(self); - - /* - * N.B. - the following is necessary, since thread_invoke() - * inhibits preemption on entry and reenables before it - * returns. Unfortunately, the first time a newly-created - * thread executes, it magically appears here, and never - * executes the enable_preemption() call in thread_invoke(). - */ - enable_preemption(); if (self->funnel_state & TH_FN_REFUNNEL) { - kern_return_t save_wait_result; + kern_return_t wait_result = self->wait_result; self->funnel_state = 0; - save_wait_result = self->wait_result; KERNEL_DEBUG(0x6032428 | DBG_FUNC_NONE, self->funnel_lock, 4, 0, 0, 0); funnel_lock(self->funnel_lock); KERNEL_DEBUG(0x6032430 | DBG_FUNC_NONE, self->funnel_lock, 4, 0, 0, 0); - self->wait_result = save_wait_result; self->funnel_state = TH_FN_OWNED; + self->wait_result = wait_result; } - - spllo(); - + (void)spllo(); assert(continuation); - (*continuation)(); + call_continuation(continuation); /*NOTREACHED*/ } @@ -1357,8 +1586,8 @@ counter(mach_counter_t c_thread_block_calls = 0;) int thread_block_reason( - void (*continuation)(void), - int reason) + thread_continue_t continuation, + ast_t reason) { register thread_t thread = current_thread(); register processor_t myprocessor; @@ -1374,61 +1603,58 @@ thread_block_reason( s = splsched(); if ((thread->funnel_state & TH_FN_OWNED) && !(reason & AST_PREEMPT)) { - thread->funnel_state = TH_FN_REFUNNEL; - KERNEL_DEBUG(0x603242c | DBG_FUNC_NONE, thread->funnel_lock, 2, 0, 0, 0); - funnel_unlock(thread->funnel_lock); + thread->funnel_state = TH_FN_REFUNNEL; + KERNEL_DEBUG( + 0x603242c | DBG_FUNC_NONE, thread->funnel_lock, 2, 0, 0, 0); + funnel_unlock(thread->funnel_lock); } myprocessor = current_processor(); - thread_lock(thread); - if (thread->state & TH_ABORT) - clear_wait_internal(thread, THREAD_INTERRUPTED); - - if (!(reason & AST_BLOCK)) + /* If we're explicitly yielding, force a subsequent quantum */ + if (reason & AST_YIELD) myprocessor->slice_quanta = 0; - /* Unconditionally remove either | both */ - ast_off(AST_PREEMPT); + /* We're handling all scheduling AST's */ + ast_off(AST_SCHEDULING); + thread_lock(thread); new_thread = thread_select(myprocessor); - assert(new_thread); - assert(thread_runnable(new_thread)); + assert(new_thread && thread_runnable(new_thread)); thread_unlock(thread); while (!thread_invoke(thread, new_thread, reason, continuation)) { thread_lock(thread); new_thread = thread_select(myprocessor); - assert(new_thread); - assert(thread_runnable(new_thread)); + assert(new_thread && thread_runnable(new_thread)); thread_unlock(thread); } if (thread->funnel_state & TH_FN_REFUNNEL) { - kern_return_t save_wait_result; + kern_return_t wait_result = thread->wait_result; - save_wait_result = thread->wait_result; thread->funnel_state = 0; - KERNEL_DEBUG(0x6032428 | DBG_FUNC_NONE, thread->funnel_lock, 5, 0, 0, 0); + KERNEL_DEBUG( + 0x6032428 | DBG_FUNC_NONE, thread->funnel_lock, 5, 0, 0, 0); funnel_lock(thread->funnel_lock); - KERNEL_DEBUG(0x6032430 | DBG_FUNC_NONE, thread->funnel_lock, 5, 0, 0, 0); + KERNEL_DEBUG( + 0x6032430 | DBG_FUNC_NONE, thread->funnel_lock, 5, 0, 0, 0); thread->funnel_state = TH_FN_OWNED; - thread->wait_result = save_wait_result; + thread->wait_result = wait_result; } splx(s); - return thread->wait_result; + return (thread->wait_result); } /* * thread_block: * - * Block the current thread if a wait has been asserted, - * otherwise yield the remainder of the current quantum. + * Block the current thread if a wait has been asserted. */ int thread_block( - void (*continuation)(void)) + thread_continue_t continuation) { return thread_block_reason(continuation, AST_NONE); } @@ -1436,26 +1662,57 @@ thread_block( /* * thread_run: * - * Switch directly from the current thread to a specified - * thread. Both the current and new threads must be - * runnable. + * Switch directly from the current (old) thread to the + * specified thread, handing off our quantum if possible. + * + * New thread must be runnable, and not on a run queue. * * Assumption: * at splsched. */ int thread_run( - thread_t old_thread, - void (*continuation)(void), - thread_t new_thread) + thread_t old_thread, + thread_continue_t continuation, + thread_t new_thread) { - while (!thread_invoke(old_thread, new_thread, 0, continuation)) { - register processor_t myprocessor = current_processor(); + ast_t handoff = AST_HANDOFF; + + assert(old_thread == current_thread()); + + machine_clock_assist(); + + if (old_thread->funnel_state & TH_FN_OWNED) { + old_thread->funnel_state = TH_FN_REFUNNEL; + KERNEL_DEBUG( + 0x603242c | DBG_FUNC_NONE, old_thread->funnel_lock, 3, 0, 0, 0); + funnel_unlock(old_thread->funnel_lock); + } + + while (!thread_invoke(old_thread, new_thread, handoff, continuation)) { + register processor_t myprocessor = current_processor(); + thread_lock(old_thread); new_thread = thread_select(myprocessor); thread_unlock(old_thread); + handoff = AST_NONE; + } + + /* if we fell thru */ + if (old_thread->funnel_state & TH_FN_REFUNNEL) { + kern_return_t wait_result = old_thread->wait_result; + + old_thread->funnel_state = 0; + KERNEL_DEBUG( + 0x6032428 | DBG_FUNC_NONE, old_thread->funnel_lock, 6, 0, 0, 0); + funnel_lock(old_thread->funnel_lock); + KERNEL_DEBUG( + 0x6032430 | DBG_FUNC_NONE, old_thread->funnel_lock, 6, 0, 0, 0); + old_thread->funnel_state = TH_FN_OWNED; + old_thread->wait_result = wait_result; } - return old_thread->wait_result; + + return (old_thread->wait_result); } /* @@ -1466,23 +1723,19 @@ void thread_dispatch( register thread_t thread) { + wake_lock(thread); + thread_lock(thread); + /* * If we are discarding the thread's stack, we must do it * before the thread has a chance to run. */ - wake_lock(thread); - thread_lock(thread); - #ifndef i386 - /* no continuations on i386 for now */ - if (thread->continuation != (void (*)())0) { - assert((thread->state & TH_STACK_STATE) == 0); - thread->state |= TH_STACK_HANDOFF; - stack_free(thread); - if (thread->top_act) { - act_machine_sv_free(thread->top_act); - } - } + if (thread->continuation != NULL) { + assert((thread->state & TH_STACK_STATE) == 0); + thread->state |= TH_STACK_HANDOFF; + stack_free(thread); + } #endif switch (thread->state & (TH_RUN|TH_WAIT|TH_UNINT|TH_IDLE)) { @@ -1497,101 +1750,128 @@ thread_dispatch( case TH_RUN | TH_WAIT | TH_UNINT: case TH_RUN | TH_WAIT: - thread->sleep_stamp = sched_tick; - /* fallthrough */ - case TH_WAIT: /* this happens! */ + { + boolean_t reap, wake, callblock; /* * Waiting */ + thread->sleep_stamp = sched_tick; thread->state &= ~TH_RUN; - if (thread->state & TH_TERMINATE) - thread_reaper_enqueue(thread); + hw_atomic_sub(&thread->processor_set->run_count, 1); + callblock = thread->active_callout; + wake = thread->wake_active; + thread->wake_active = FALSE; + reap = (thread->state & TH_TERMINATE)? TRUE: FALSE; - if (thread->wake_active) { - thread->wake_active = FALSE; - thread_unlock(thread); - wake_unlock(thread); + thread_unlock(thread); + wake_unlock(thread); + + if (callblock) + call_thread_block(); + + if (wake) thread_wakeup((event_t)&thread->wake_active); - return; - } - break; + + if (reap) + thread_reaper_enqueue(thread); + + return; + } case TH_RUN | TH_IDLE: /* - * Drop idle thread -- it is already in - * idle_thread_array. + * The idle threads don't go + * onto a run queue. */ break; default: - panic("State 0x%x \n",thread->state); + panic("thread_dispatch: bad thread state 0x%x\n", thread->state); } + thread_unlock(thread); wake_unlock(thread); } /* * Enqueue thread on run queue. Thread must be locked, - * and not already be on a run queue. + * and not already be on a run queue. Returns TRUE iff + * the particular queue level was empty beforehand. */ -int +boolean_t run_queue_enqueue( register run_queue_t rq, register thread_t thread, boolean_t tail) { - register int whichq; - int oldrqcount; + register int whichq = thread->sched_pri; + register queue_t queue = &rq->queues[whichq]; + boolean_t result = FALSE; - whichq = thread->sched_pri; assert(whichq >= MINPRI && whichq <= MAXPRI); - simple_lock(&rq->lock); /* lock the run queue */ + simple_lock(&rq->lock); assert(thread->runq == RUN_QUEUE_NULL); + if (queue_empty(queue)) { + enqueue_tail(queue, (queue_entry_t)thread); + + setbit(MAXPRI - whichq, rq->bitmap); + if (whichq > rq->highq) + rq->highq = whichq; + result = TRUE; + } + else if (tail) - enqueue_tail(&rq->queues[whichq], (queue_entry_t)thread); + enqueue_tail(queue, (queue_entry_t)thread); else - enqueue_head(&rq->queues[whichq], (queue_entry_t)thread); - - setbit(MAXPRI - whichq, rq->bitmap); - if (whichq > rq->highq) - rq->highq = whichq; + enqueue_head(queue, (queue_entry_t)thread); - oldrqcount = rq->count++; thread->runq = rq; - thread->whichq = whichq; + if (thread->sched_mode & TH_MODE_PREEMPT) + rq->urgency++; + rq->count++; #if DEBUG thread_check(thread, rq); #endif /* DEBUG */ simple_unlock(&rq->lock); - return (oldrqcount); + return (result); } +struct { + uint32_t pset_idle_last, + pset_idle_any, + pset_self, + pset_last, + pset_other, + bound_idle, + bound_self, + bound_other; +} dispatch_counts; + /* * thread_setrun: * - * Make thread runnable; dispatch directly onto an idle processor - * if possible. Else put on appropriate run queue (processor - * if bound, else processor set. Caller must have lock on thread. - * This is always called at splsched. - * The tail parameter, if TRUE || TAIL_Q, indicates that the - * thread should be placed at the tail of the runq. If - * FALSE || HEAD_Q the thread will be placed at the head of the - * appropriate runq. + * Dispatch thread for execution, directly onto an idle + * processor if possible. Else put on appropriate run + * queue. (local if bound, else processor set) + * + * Thread must be locked. + * + * The tail parameter indicates the proper placement of + * the thread on a run queue. */ void thread_setrun( register thread_t new_thread, - boolean_t may_preempt, boolean_t tail) { register processor_t processor; - register run_queue_t runq; register processor_set_t pset; - thread_t thread; - ast_t ast_flags = AST_BLOCK; + register thread_t thread; + boolean_t try_preempt = FALSE; + ast_t preempt = AST_BLOCK; assert(thread_runnable(new_thread)); @@ -1601,135 +1881,301 @@ thread_setrun( if (new_thread->sched_stamp != sched_tick) update_priority(new_thread); - if ( new_thread->sched_pri >= BASEPRI_PREEMPT && - kernel_preemption_mode == KERNEL_PREEMPT ) - ast_flags |= AST_URGENT; - - assert(new_thread->runq == RUN_QUEUE_NULL); - /* - * Try to dispatch the thread directly onto an idle processor. + * Check for urgent preemption. */ + if (new_thread->sched_mode & TH_MODE_PREEMPT) + preempt |= AST_URGENT; + + assert(new_thread->runq == RUN_QUEUE_NULL); + if ((processor = new_thread->bound_processor) == PROCESSOR_NULL) { /* - * Not bound, any processor in the processor set is ok. + * First try to dispatch on + * the last processor. */ pset = new_thread->processor_set; - if (pset->idle_count > 0) { - simple_lock(&pset->idle_lock); - if (pset->idle_count > 0) { - processor = (processor_t) queue_first(&pset->idle_queue); - queue_remove(&(pset->idle_queue), processor, processor_t, - processor_queue); + processor = new_thread->last_processor; + if ( pset->processor_count > 1 && + processor != PROCESSOR_NULL && + processor->state == PROCESSOR_IDLE ) { + simple_lock(&processor->lock); + simple_lock(&pset->sched_lock); + if ( processor->processor_set == pset && + processor->state == PROCESSOR_IDLE ) { + remqueue(&pset->idle_queue, (queue_entry_t)processor); pset->idle_count--; processor->next_thread = new_thread; processor->state = PROCESSOR_DISPATCHING; - simple_unlock(&pset->idle_lock); - if(processor->slot_num != cpu_number()) + simple_unlock(&pset->sched_lock); + simple_unlock(&processor->lock); + if (processor != current_processor()) machine_signal_idle(processor); + dispatch_counts.pset_idle_last++; return; } - simple_unlock(&pset->idle_lock); - } + simple_unlock(&processor->lock); + } + else + simple_lock(&pset->sched_lock); + + /* + * Next pick any idle processor + * in the processor set. + */ + if (pset->idle_count > 0) { + processor = (processor_t)dequeue_head(&pset->idle_queue); + pset->idle_count--; + processor->next_thread = new_thread; + processor->state = PROCESSOR_DISPATCHING; + simple_unlock(&pset->sched_lock); + if (processor != current_processor()) + machine_signal_idle(processor); + dispatch_counts.pset_idle_any++; + return; + } /* - * Place thread on processor set run queue. + * Place thread on run queue. */ - runq = &pset->runq; - run_queue_enqueue(runq, new_thread, tail); + if (run_queue_enqueue(&pset->runq, new_thread, tail)) + try_preempt = TRUE; + + /* + * Update the timesharing quanta. + */ + pset_quanta_update(pset); /* - * Preempt check + * Preempt check. */ - thread = current_thread(); processor = current_processor(); - if ( may_preempt && - pset == processor->processor_set ) { - /* - * XXX if we have a non-empty local runq or are - * XXX running a bound thread, ought to check for - * XXX another cpu running lower-pri thread to preempt. + thread = processor->cpu_data->active_thread; + if (try_preempt) { + /* + * First try the current processor + * if it is a member of the correct + * processor set. */ - if (csw_needed(thread, processor)) - ast_on(ast_flags); + if ( pset == processor->processor_set && + csw_needed(thread, processor) ) { + simple_unlock(&pset->sched_lock); + + ast_on(preempt); + dispatch_counts.pset_self++; + return; + } + + /* + * If that failed and we have other + * processors available keep trying. + */ + if ( pset->processor_count > 1 || + pset != processor->processor_set ) { + queue_t active = &pset->active_queue; + processor_t myprocessor, lastprocessor; + queue_entry_t next; + + /* + * Next try the last processor + * dispatched on. + */ + myprocessor = processor; + processor = new_thread->last_processor; + if ( processor != myprocessor && + processor != PROCESSOR_NULL && + processor->processor_set == pset && + processor->state == PROCESSOR_RUNNING && + new_thread->sched_pri > processor->current_pri ) { + cause_ast_check(processor); + simple_unlock(&pset->sched_lock); + dispatch_counts.pset_last++; + return; + } + + /* + * Lastly, pick any other + * available processor. + */ + lastprocessor = processor; + processor = (processor_t)queue_first(active); + while (!queue_end(active, (queue_entry_t)processor)) { + next = queue_next((queue_entry_t)processor); + + if ( processor != myprocessor && + processor != lastprocessor && + new_thread->sched_pri > processor->current_pri ) { + if (!queue_end(active, next)) { + remqueue(active, (queue_entry_t)processor); + enqueue_tail(active, (queue_entry_t)processor); + } + cause_ast_check(processor); + simple_unlock(&pset->sched_lock); + dispatch_counts.pset_other++; + return; + } + + processor = (processor_t)next; + } + } } + + simple_unlock(&pset->sched_lock); } else { /* * Bound, can only run on bound processor. Have to lock * processor here because it may not be the current one. */ - if (processor->state == PROCESSOR_IDLE) { + if (processor->state == PROCESSOR_IDLE) { simple_lock(&processor->lock); pset = processor->processor_set; - simple_lock(&pset->idle_lock); + simple_lock(&pset->sched_lock); if (processor->state == PROCESSOR_IDLE) { - queue_remove(&pset->idle_queue, processor, - processor_t, processor_queue); + remqueue(&pset->idle_queue, (queue_entry_t)processor); pset->idle_count--; processor->next_thread = new_thread; processor->state = PROCESSOR_DISPATCHING; - simple_unlock(&pset->idle_lock); + simple_unlock(&pset->sched_lock); simple_unlock(&processor->lock); - if(processor->slot_num != cpu_number()) + if (processor != current_processor()) machine_signal_idle(processor); + dispatch_counts.bound_idle++; return; } - simple_unlock(&pset->idle_lock); + simple_unlock(&pset->sched_lock); simple_unlock(&processor->lock); } - /* - * Cause ast on processor if processor is on line, and the - * currently executing thread is not bound to that processor - * (bound threads have implicit priority over non-bound threads). - * We also avoid sending the AST to the idle thread (if it got - * scheduled in the window between the 'if' above and here), - * since the idle_thread is bound. - */ - runq = &processor->runq; - if (processor == current_processor()) { - run_queue_enqueue(runq, new_thread, tail); - - thread = current_thread(); - if ( thread->bound_processor == PROCESSOR_NULL || - csw_needed(thread, processor)) - ast_on(ast_flags); - } + if (run_queue_enqueue(&processor->runq, new_thread, tail)) + try_preempt = TRUE; + + if (processor == current_processor()) { + if (try_preempt) { + thread = processor->cpu_data->active_thread; + if (csw_needed(thread, processor)) { + ast_on(preempt); + dispatch_counts.bound_self++; + } + } + } else { - thread = cpu_data[processor->slot_num].active_thread; - if ( run_queue_enqueue(runq, new_thread, tail) == 0 && - processor->state != PROCESSOR_OFF_LINE && - thread && thread->bound_processor != processor ) - cause_ast_check(processor); - } + if (try_preempt) { + if ( processor->state == PROCESSOR_RUNNING && + new_thread->sched_pri > processor->current_pri ) { + cause_ast_check(processor); + dispatch_counts.bound_other++; + return; + } + } + + if (processor->state == PROCESSOR_IDLE) { + machine_signal_idle(processor); + dispatch_counts.bound_idle++; + } + } + } +} + +/* + * Called at splsched by a thread on itself. + */ +ast_t +csw_check( + thread_t thread, + processor_t processor) +{ + int current_pri = thread->sched_pri; + ast_t result = AST_NONE; + run_queue_t runq; + + if (first_quantum(processor)) { + runq = &processor->processor_set->runq; + if (runq->highq > current_pri) { + if (runq->urgency > 0) + return (AST_BLOCK | AST_URGENT); + + result |= AST_BLOCK; + } + + runq = &processor->runq; + if (runq->highq > current_pri) { + if (runq->urgency > 0) + return (AST_BLOCK | AST_URGENT); + + result |= AST_BLOCK; + } + } + else { + runq = &processor->processor_set->runq; + if (runq->highq >= current_pri) { + if (runq->urgency > 0) + return (AST_BLOCK | AST_URGENT); + + result |= AST_BLOCK; + } + + runq = &processor->runq; + if (runq->highq >= current_pri) { + if (runq->urgency > 0) + return (AST_BLOCK | AST_URGENT); + + result |= AST_BLOCK; + } } + + if (result != AST_NONE) + return (result); + + if (thread->state & TH_SUSP) + result |= AST_BLOCK; + + return (result); } /* - * set_pri: + * set_sched_pri: * - * Set the priority of the specified thread to the specified - * priority. This may cause the thread to change queues. + * Set the current scheduled priority of the specified thread. + * This may cause the thread to change queues. * * The thread *must* be locked by the caller. */ void -set_pri( +set_sched_pri( thread_t thread, - int pri, - boolean_t resched) + int priority) { - register struct run_queue *rq; + register struct run_queue *rq = rem_runq(thread); + + if ( !(thread->sched_mode & TH_MODE_TIMESHARE) && + (priority >= BASEPRI_PREEMPT || + (thread->task_priority < MINPRI_KERNEL && + thread->task_priority >= BASEPRI_BACKGROUND && + priority > thread->task_priority) || + (thread->sched_mode & TH_MODE_FORCEDPREEMPT) ) ) + thread->sched_mode |= TH_MODE_PREEMPT; + else + thread->sched_mode &= ~TH_MODE_PREEMPT; - rq = rem_runq(thread); - assert(thread->runq == RUN_QUEUE_NULL); - thread->sched_pri = pri; - if (rq != RUN_QUEUE_NULL) { - if (resched) - thread_setrun(thread, TRUE, TAIL_Q); - else - run_queue_enqueue(rq, thread, TAIL_Q); + thread->sched_pri = priority; + if (rq != RUN_QUEUE_NULL) + thread_setrun(thread, TAIL_Q); + else + if ((thread->state & (TH_RUN|TH_WAIT)) == TH_RUN) { + processor_t processor = thread->last_processor; + + if (thread == current_thread()) { + ast_t preempt = csw_check(thread, processor); + + if (preempt != AST_NONE) + ast_on(preempt); + processor->current_pri = priority; + } + else + if ( processor != PROCESSOR_NULL && + processor->cpu_data->active_thread == thread ) + cause_ast_check(processor); } } @@ -1766,6 +2212,9 @@ rem_runq( #endif /* DEBUG */ remqueue(&rq->queues[0], (queue_entry_t)thread); rq->count--; + if (thread->sched_mode & TH_MODE_PREEMPT) + rq->urgency--; + assert(rq->urgency >= 0); if (queue_empty(rq->queues + thread->sched_pri)) { /* update run queue status */ @@ -1792,7 +2241,6 @@ rem_runq( return (rq); } - /* * choose_thread: * @@ -1805,8 +2253,9 @@ rem_runq( * Else check pset runq; if nothing found, return idle thread. * * Second line of strategy is implemented by choose_pset_thread. - * This is only called on processor startup and when thread_block - * thinks there's something in the processor runq. + * + * Called with both the local & pset run queues locked, returned + * unlocked. */ thread_t choose_thread( @@ -1820,8 +2269,8 @@ choose_thread( runq = &myprocessor->runq; pset = myprocessor->processor_set; - simple_lock(&runq->lock); if (runq->count > 0 && runq->highq >= pset->runq.highq) { + simple_unlock(&pset->runq.lock); q = runq->queues + runq->highq; #if MACH_ASSERT if (!queue_empty(q)) { @@ -1831,6 +2280,9 @@ choose_thread( q->next = ((queue_entry_t)thread)->next; thread->runq = RUN_QUEUE_NULL; runq->count--; + if (thread->sched_mode & TH_MODE_PREEMPT) + runq->urgency--; + assert(runq->urgency >= 0); if (queue_empty(q)) { if (runq->highq != IDLEPRI) clrbit(MAXPRI - runq->highq, runq->bitmap); @@ -1844,23 +2296,21 @@ choose_thread( #endif /*MACH_ASSERT*/ /*NOTREACHED*/ } + simple_unlock(&myprocessor->runq.lock); - simple_unlock(&runq->lock); - simple_lock(&pset->runq.lock); return (choose_pset_thread(myprocessor, pset)); } - /* * choose_pset_thread: choose a thread from processor_set runq or * set processor idle and choose its idle thread. * - * Caller must be at splsched and have a lock on the runq. This - * lock is released by this routine. myprocessor is always the current - * processor, and pset must be its processor set. * This routine chooses and removes a thread from the runq if there * is one (and returns it), else it sets the processor idle and * returns its idle thread. + * + * Called with both local & pset run queues locked, returned + * unlocked. */ thread_t choose_pset_thread( @@ -1882,11 +2332,15 @@ choose_pset_thread( q->next = ((queue_entry_t)thread)->next; thread->runq = RUN_QUEUE_NULL; runq->count--; + if (thread->sched_mode & TH_MODE_PREEMPT) + runq->urgency--; + assert(runq->urgency >= 0); if (queue_empty(q)) { if (runq->highq != IDLEPRI) clrbit(MAXPRI - runq->highq, runq->bitmap); runq->highq = MAXPRI - ffsbit(runq->bitmap); } + pset_quanta_update(pset); simple_unlock(&runq->lock); return (thread); #if MACH_ASSERT @@ -1902,23 +2356,19 @@ choose_pset_thread( * was running. If it was in an assignment or shutdown, * leave it alone. Return its idle thread. */ - simple_lock(&pset->idle_lock); + simple_lock(&pset->sched_lock); if (myprocessor->state == PROCESSOR_RUNNING) { + remqueue(&pset->active_queue, (queue_entry_t)myprocessor); myprocessor->state = PROCESSOR_IDLE; - /* - * XXX Until it goes away, put master on end of queue, others - * XXX on front so master gets used last. - */ + if (myprocessor == master_processor) - queue_enter(&(pset->idle_queue), myprocessor, - processor_t, processor_queue); + enqueue_tail(&pset->idle_queue, (queue_entry_t)myprocessor); else - queue_enter_first(&(pset->idle_queue), myprocessor, - processor_t, processor_queue); + enqueue_head(&pset->idle_queue, (queue_entry_t)myprocessor); pset->idle_count++; } - simple_unlock(&pset->idle_lock); + simple_unlock(&pset->sched_lock); return (myprocessor->idle_thread); } @@ -1946,15 +2396,11 @@ idle_thread_continue(void) int mycpu; mycpu = cpu_number(); - myprocessor = current_processor(); + myprocessor = cpu_to_processor(mycpu); threadp = (volatile thread_t *) &myprocessor->next_thread; lcount = (volatile int *) &myprocessor->runq.count; for (;;) { -#ifdef MARK_CPU_IDLE - MARK_CPU_IDLE(mycpu); -#endif /* MARK_CPU_IDLE */ - gcount = (volatile int *)&myprocessor->processor_set->runq.count; (void)splsched(); @@ -1962,11 +2408,9 @@ idle_thread_continue(void) (*gcount == 0) && (*lcount == 0) ) { /* check for ASTs while we wait */ - if (need_ast[mycpu] &~ ( AST_SCHEDULING | AST_PREEMPT | - AST_BSD | AST_BSD_INIT )) { + if (need_ast[mycpu] &~ ( AST_SCHEDULING | AST_BSD )) { /* don't allow scheduling ASTs */ - need_ast[mycpu] &= ~( AST_SCHEDULING | AST_PREEMPT | - AST_BSD | AST_BSD_INIT ); + need_ast[mycpu] &= ~( AST_SCHEDULING | AST_BSD ); ast_taken(AST_ALL, TRUE); /* back at spllo */ } else @@ -1980,18 +2424,12 @@ idle_thread_continue(void) (void)splsched(); } -#ifdef MARK_CPU_ACTIVE - (void)spllo(); - MARK_CPU_ACTIVE(mycpu); - (void)splsched(); -#endif /* MARK_CPU_ACTIVE */ - /* * This is not a switch statement to avoid the * bounds checking code in the common case. */ pset = myprocessor->processor_set; - simple_lock(&pset->idle_lock); + simple_lock(&pset->sched_lock); retry: state = myprocessor->state; if (state == PROCESSOR_DISPATCHING) { @@ -2001,33 +2439,24 @@ retry: new_thread = *threadp; *threadp = (volatile thread_t) THREAD_NULL; myprocessor->state = PROCESSOR_RUNNING; - simple_unlock(&pset->idle_lock); + enqueue_tail(&pset->active_queue, (queue_entry_t)myprocessor); + simple_unlock(&pset->sched_lock); - thread_lock(new_thread); - simple_lock(&myprocessor->runq.lock); - simple_lock(&pset->runq.lock); if ( myprocessor->runq.highq > new_thread->sched_pri || pset->runq.highq > new_thread->sched_pri ) { - simple_unlock(&pset->runq.lock); - simple_unlock(&myprocessor->runq.lock); - - if (new_thread->bound_processor != PROCESSOR_NULL) - run_queue_enqueue(&myprocessor->runq, new_thread, HEAD_Q); - else - run_queue_enqueue(&pset->runq, new_thread, HEAD_Q); + thread_lock(new_thread); + thread_setrun(new_thread, HEAD_Q); thread_unlock(new_thread); counter(c_idle_thread_block++); thread_block(idle_thread_continue); + /* NOTREACHED */ } else { - simple_unlock(&pset->runq.lock); - simple_unlock(&myprocessor->runq.lock); - thread_unlock(new_thread); - counter(c_idle_thread_handoff++); thread_run(myprocessor->idle_thread, idle_thread_continue, new_thread); + /* NOTREACHED */ } } else @@ -2044,13 +2473,14 @@ retry: */ no_dispatch_count++; pset->idle_count--; - queue_remove(&pset->idle_queue, myprocessor, - processor_t, processor_queue); + remqueue(&pset->idle_queue, (queue_entry_t)myprocessor); myprocessor->state = PROCESSOR_RUNNING; - simple_unlock(&pset->idle_lock); + enqueue_tail(&pset->active_queue, (queue_entry_t)myprocessor); + simple_unlock(&pset->sched_lock); counter(c_idle_thread_block++); thread_block(idle_thread_continue); + /* NOTREACHED */ } else if ( state == PROCESSOR_ASSIGN || @@ -2062,22 +2492,23 @@ retry: */ if ((new_thread = (thread_t)*threadp) != THREAD_NULL) { *threadp = (volatile thread_t) THREAD_NULL; - simple_unlock(&pset->idle_lock); + simple_unlock(&pset->sched_lock); + thread_lock(new_thread); - thread_setrun(new_thread, FALSE, TAIL_Q); + thread_setrun(new_thread, TAIL_Q); thread_unlock(new_thread); - } else - simple_unlock(&pset->idle_lock); + } + else + simple_unlock(&pset->sched_lock); counter(c_idle_thread_block++); thread_block(idle_thread_continue); + /* NOTREACHED */ } else { - simple_unlock(&pset->idle_lock); - printf("Bad processor state %d (Cpu %d)\n", - cpu_state(mycpu), mycpu); - panic("idle_thread"); + simple_unlock(&pset->sched_lock); + panic("idle_thread: bad processor state %d\n", cpu_state(mycpu)); } (void)spllo(); @@ -2094,16 +2525,13 @@ idle_thread(void) s = splsched(); thread_lock(self); - self->priority = IDLEPRI; - self->sched_pri = self->priority; - + set_sched_pri(self, self->priority); thread_unlock(self); splx(s); counter(c_idle_thread_block++); - thread_block((void(*)(void))0); - idle_thread_continue(); + thread_block(idle_thread_continue); /*NOTREACHED*/ } @@ -2196,10 +2624,10 @@ sched_tick_thread(void) * thread ids away in an array (takes out references for them). * Pass two does the priority updates. This is necessary because * the run queue lock is required for the candidate scan, but - * cannot be held during updates [set_pri will deadlock]. + * cannot be held during updates. * * Array length should be enough so that restart isn't necessary, - * but restart logic is included. Does not scan processor runqs. + * but restart logic is included. * */ thread_t stuck_threads[MAX_STUCK_THREADS]; @@ -2250,7 +2678,7 @@ do_runq_scan( * and ignore this thread if we fail, we might * have better luck next time. */ - if (simple_lock_try(&thread->lock)) { + if (thread_lock_try(thread)) { thread->ref_count++; thread_unlock(thread); stuck_threads[stuck_count++] = thread; @@ -2329,6 +2757,9 @@ do_thread_scan(void) if (!(thread->state & TH_IDLE)) thread_deallocate(thread); } + + if (restart_needed) + delay(1); /* XXX */ } while (restart_needed); } @@ -2348,6 +2779,7 @@ thread_wakeup( thread_wakeup_with_result(x, THREAD_AWAKENED); } + #if DEBUG static boolean_t @@ -2513,9 +2945,6 @@ thread_check( if (whichq < MINPRI || whichq > MAXPRI) panic("thread_check: bad pri"); - if (whichq != thread->whichq) - panic("thread_check: whichq"); - queue = &rq->queues[whichq]; entry = queue_first(queue); while (!queue_end(queue, entry)) { diff --git a/osfmk/kern/sched_prim.h b/osfmk/kern/sched_prim.h index cd9e8e8d4..758c22e20 100644 --- a/osfmk/kern/sched_prim.h +++ b/osfmk/kern/sched_prim.h @@ -69,9 +69,12 @@ #include #include /*** ??? temp - remove me soon ***/ #include -#include -#ifdef MACH_KERNEL_PRIVATE +#include + +#ifdef __APPLE_API_PRIVATE + +#ifdef MACH_KERNEL_PRIVATE #include /* @@ -95,13 +98,13 @@ extern void thread_timer_terminate(void); (thread)->bound_processor = (processor) /* - * Prevent a thread from restarting after it blocks interruptibly + * Stop a thread and wait for it to stop running. */ extern boolean_t thread_stop( thread_t thread); /* - * wait for a thread to stop + * Wait for a thread to stop running. */ extern boolean_t thread_wait( thread_t thread); @@ -110,74 +113,66 @@ extern boolean_t thread_wait( extern thread_t thread_select( processor_t myprocessor); -extern void thread_go_locked( - thread_t thread, - int result); +extern kern_return_t thread_go_locked( + thread_t thread, + wait_result_t result); /* Stop old thread and run new thread */ extern boolean_t thread_invoke( - thread_t old_thread, - thread_t new_thread, - int reason, - void (*continuation)(void)); + thread_t old_thread, + thread_t new_thread, + int reason, + thread_continue_t continuation); /* Called when current thread is given new stack */ extern void thread_continue( - thread_t old_thread); + thread_t old_thread); /* Switch directly to a particular thread */ extern int thread_run( - thread_t old_thread, - void (*continuation)(void), - thread_t new_thread); + thread_t old_thread, + thread_continue_t continuation, + thread_t new_thread); /* Dispatch a thread not on a run queue */ extern void thread_dispatch( - thread_t thread); + thread_t thread); /* Invoke continuation */ extern void call_continuation( - void (*continuation)(void)); + thread_continue_t continuation); + +/* Set the current scheduled priority */ +extern void set_sched_pri( + thread_t thread, + int priority); -/* Compute effective priority of the specified thread */ +/* Set base priority of the specified thread */ +extern void set_priority( + thread_t thread, + int priority); + +/* Reset scheduled priority of thread */ extern void compute_priority( - thread_t thread, - int resched); + thread_t thread, + boolean_t override_depress); -/* Version of compute_priority for current thread or - * thread being manipuldated by scheduler. - */ +/* Adjust scheduled priority of thread during execution */ extern void compute_my_priority( - thread_t thread); + thread_t thread); /* Periodic scheduler activity */ extern void sched_tick_init(void); -/* Update priority of thread that has been sleeping or suspended. - * Used to "catch up" with the system. +/* + * Update thread to the current scheduler tick. */ extern void update_priority( - thread_t thread); + thread_t thread); /* Idle thread loop */ extern void idle_thread(void); -/* - * thread_sleep_interlock: - * - * Cause the current thread to wait until the specified event - * occurs. The specified HW interlock is unlocked before releasing - * the cpu. (This is a convenient way to sleep without manually - * calling assert_wait). - */ - -#define thread_sleep_interlock(event, lock, interruptible) \ -MACRO_BEGIN \ - assert_wait(event, interruptible); \ - interlock_unlock(lock); \ - thread_block((void (*)(void)) 0); \ -MACRO_END - /* * Machine-dependent code must define these functions. */ @@ -194,7 +189,7 @@ extern void thread_syscall_return( extern thread_t switch_context( thread_t old_thread, - void (*continuation)(void), + thread_continue_t continuation, thread_t new_thread); /* Attach stack to thread */ @@ -228,36 +223,42 @@ extern void stack_free(thread_t thread); /* Collect excess kernel stacks */ extern void stack_collect(void); -extern void set_pri( - thread_t thread, - int pri, - boolean_t resched); - -/* Block current thread, indicating reason (Block or Quantum expiration) */ -extern int thread_block_reason( - void (*continuation)(void), - int reason); +/* Block current thread, indicating reason */ +extern wait_result_t thread_block_reason( + thread_continue_t continuation, + ast_t reason); -/* Make thread runnable */ +/* Dispatch a thread for execution */ extern void thread_setrun( - thread_t thread, - boolean_t may_preempt, - boolean_t tail); -/* - * Flags for thread_setrun() - */ + thread_t thread, + boolean_t tail); #define HEAD_Q 0 /* FALSE */ #define TAIL_Q 1 /* TRUE */ /* Bind thread to a particular processor */ extern void thread_bind( - thread_t thread, - processor_t processor); + thread_t thread, + processor_t processor); -extern void thread_mark_wait_locked( - thread_t thread, - int interruptible); +/* Set the maximum interrupt level for the thread */ +__private_extern__ wait_interrupt_t thread_interrupt_level( + wait_interrupt_t interruptible); + +__private_extern__ wait_result_t thread_mark_wait_locked( + thread_t thread, + wait_interrupt_t interruptible); + +/* Sleep, unlocking and then relocking a usimple_lock in the process */ +__private_extern__ wait_result_t thread_sleep_fast_usimple_lock( + event_t event, + simple_lock_t lock, + wait_interrupt_t interruptible); + +/* Wake up locked thread directly, passing result */ +__private_extern__ kern_return_t clear_wait_internal( + thread_t thread, + wait_result_t result); #endif /* MACH_KERNEL_PRIVATE */ @@ -266,21 +267,17 @@ extern void thread_mark_wait_locked( */ /* - * Cancel a stop and continue the thread if necessary. + * Cancel a stop and unblock the thread if already stopped. */ extern void thread_unstop( - thread_t thread); + thread_t thread); /* Wake up thread directly, passing result */ -extern void clear_wait( - thread_t thread, - int result); - -/* Bind thread to a particular processor */ -extern void thread_bind( - thread_t thread, - processor_t processor); +extern kern_return_t clear_wait( + thread_t thread, + wait_result_t result); +#endif /* __APPLE_API_PRIVATE */ /* * ********************* PUBLIC APIs ************************************ @@ -296,32 +293,59 @@ extern void thread_set_timer_deadline( extern void thread_cancel_timer(void); -/* - * thread_stop a thread then wait for it to stop (both of the above) - */ -extern boolean_t thread_stop_wait( - thread_t thread); - /* Declare thread will wait on a particular event */ -extern void assert_wait( - event_t event, - int interruptflag); +extern wait_result_t assert_wait( + event_t event, + wait_interrupt_t interruptflag); /* Assert that the thread intends to wait for a timeout */ -extern void assert_wait_timeout( - natural_t msecs, - int interruptflags); +extern wait_result_t assert_wait_timeout( + natural_t msecs, + wait_interrupt_t interruptflags); + +/* Sleep, unlocking and then relocking a usimple_lock in the process */ +extern wait_result_t thread_sleep_usimple_lock( + event_t event, + usimple_lock_t lock, + wait_interrupt_t interruptible); + +/* Sleep, unlocking and then relocking a mutex in the process */ +extern wait_result_t thread_sleep_mutex( + event_t event, + mutex_t *mutex, + wait_interrupt_t interruptible); + +/* Sleep with a deadline, unlocking and then relocking a mutex in the process */ +extern wait_result_t thread_sleep_mutex_deadline( + event_t event, + mutex_t *mutex, + uint64_t deadline, + wait_interrupt_t interruptible); + +/* Sleep, unlocking and then relocking a write lock in the process */ +extern wait_result_t thread_sleep_lock_write( + event_t event, + lock_t *lock, + wait_interrupt_t interruptible); + +/* Sleep, hinting that a thread funnel may be involved in the process */ +extern wait_result_t thread_sleep_funnel( + event_t event, + wait_interrupt_t interruptible); /* Wake up thread (or threads) waiting on a particular event */ -extern void thread_wakeup_prim( - event_t event, - boolean_t one_thread, - int result); +extern kern_return_t thread_wakeup_prim( + event_t event, + boolean_t one_thread, + wait_result_t result); + +#ifdef __APPLE_API_UNSTABLE /* Block current thread (Block reason) */ -extern int thread_block( - void (*continuation)(void)); +extern wait_result_t thread_block( + thread_continue_t continuation); +#endif /* __APPLE_API_UNSTABLE */ /* * Routines defined as macros @@ -334,38 +358,6 @@ extern int thread_block( #define thread_wakeup_one(x) \ thread_wakeup_prim((x), TRUE, THREAD_AWAKENED) -/* - * thread_sleep_mutex: - * - * Cause the current thread to wait until the specified event - * occurs. The specified mutex is unlocked before releasing - * the cpu. (This is a convenient way to sleep without manually - * calling assert_wait). - */ - -#define thread_sleep_mutex(event, lock, interruptible) \ -MACRO_BEGIN \ - assert_wait(event, interruptible); \ - mutex_unlock(lock); \ - thread_block((void (*)(void)) 0); \ -MACRO_END - -/* - * thread_sleep_simple_lock: - * - * Cause the current thread to wait until the specified event - * occurs. The specified simple_lock is unlocked before releasing - * the cpu. (This is a convenient way to sleep without manually - * calling assert_wait). - */ - -#define thread_sleep_simple_lock(event, lock, interruptible) \ -MACRO_BEGIN \ - assert_wait(event, interruptible); \ - simple_unlock(lock); \ - thread_block((void (*)(void)) 0); \ -MACRO_END - #if !defined(MACH_KERNEL_PRIVATE) && !defined(ABSOLUTETIME_SCALAR_TYPE) #include diff --git a/osfmk/kern/simple_lock.h b/osfmk/kern/simple_lock.h index f22979f3b..708998e56 100644 --- a/osfmk/kern/simple_lock.h +++ b/osfmk/kern/simple_lock.h @@ -120,7 +120,12 @@ * and use the portable lock package for everything else. */ -#ifdef MACH_KERNEL_PRIVATE +#include + +#ifdef __APPLE_API_PRIVATE + +#ifdef MACH_KERNEL_PRIVATE + /* * Mach always initializes locks, even those statically * allocated. @@ -141,10 +146,13 @@ extern void hw_lock_unlock(hw_lock_t); extern unsigned int hw_lock_to(hw_lock_t, unsigned int); extern unsigned int hw_lock_try(hw_lock_t); extern unsigned int hw_lock_held(hw_lock_t); -#endif /* MACH_KERNEL_PRIVATE */ + +#endif /* MACH_KERNEL_PRIVATE */ + +#endif /* __APPLE_API_PRIVATE */ /* - * Machine dependent atomic ops. Probably should be in their own header. + * Machine dependent ops. */ extern unsigned int hw_lock_bit(unsigned int *, unsigned int, unsigned int); extern unsigned int hw_cpu_sync(unsigned int *, unsigned int); @@ -152,11 +160,28 @@ extern unsigned int hw_cpu_wcng(unsigned int *, unsigned int, unsigned int); extern unsigned int hw_lock_mbits(unsigned int *, unsigned int, unsigned int, unsigned int, unsigned int); void hw_unlock_bit(unsigned int *, unsigned int); -extern int hw_atomic_add(int *area, int inc); -extern int hw_atomic_sub(int *area, int dec); -extern int hw_atomic_or(int *area, int val); -extern int hw_atomic_and(int *area, int mask); -extern unsigned int hw_compare_and_store(unsigned int oldValue, unsigned int newValue, unsigned int *area); + +extern uint32_t hw_atomic_add( + uint32_t *dest, + uint32_t delt); + +extern uint32_t hw_atomic_sub( + uint32_t *dest, + uint32_t delt); + +extern uint32_t hw_atomic_or( + uint32_t *dest, + uint32_t mask); + +extern uint32_t hw_atomic_and( + uint32_t *dest, + uint32_t mask); + +extern uint32_t hw_compare_and_store( + uint32_t oldval, + uint32_t newval, + uint32_t *dest); + extern void hw_queue_atomic(unsigned int *anchor, unsigned int *elem, unsigned int disp); extern void hw_queue_atomic_list(unsigned int *anchor, unsigned int *first, unsigned int *last, unsigned int disp); extern unsigned int *hw_dequeue_atomic(unsigned int *anchor, unsigned int disp); @@ -248,7 +273,10 @@ extern void usimple_lock_none_held(void); * Otherwise, deadlock may result. */ -#if MACH_KERNEL_PRIVATE +#ifdef __APPLE_API_PRIVATE + +#ifdef MACH_KERNEL_PRIVATE + #include #include @@ -288,7 +316,9 @@ extern int simple_lock_try_no_trace(simple_lock_t l); extern void simple_unlock_no_trace(simple_lock_t l); #endif /* ETAP_LOCK_TRACE */ -#endif /* MACH_KERNEL_PRIVATE */ +#endif /* MACH_KERNEL_PRIVATE */ + +#endif /* __APPLE_API_PRIVATE */ /* * If we got to here and we still don't have simple_lock_init @@ -302,6 +332,8 @@ extern void simple_unlock_no_trace(simple_lock_t l); #define simple_lock_try(l) usimple_lock_try(l) #define simple_lock_addr(l) (&(l)) #define __slock_held_func__(l) usimple_lock_held(l) +#define thread_sleep_simple_lock(l, e, i) \ + thread_sleep_usimple_lock((l), (e), (i)) #endif / * !defined(simple_lock_init) */ #if USLOCK_DEBUG @@ -324,9 +356,12 @@ extern void simple_unlock_no_trace(simple_lock_t l); */ #define simple_lock_held(l) __slock_held_func__(l) #define check_simple_locks() usimple_lock_none_held() + #else /* USLOCK_DEBUG */ + #define simple_lock_held(l) #define check_simple_locks() + #endif /* USLOCK_DEBUG */ #endif /*!_SIMPLE_LOCK_H_*/ diff --git a/osfmk/kern/simple_lock_types.h b/osfmk/kern/simple_lock_types.h index ef864cc8c..72b0a2f50 100644 --- a/osfmk/kern/simple_lock_types.h +++ b/osfmk/kern/simple_lock_types.h @@ -89,7 +89,6 @@ * and use the portable lock package for everything else. */ - /* * All of the remaining locking constructs may have two versions. * One version is machine-independent, built in C on top of the @@ -241,9 +240,13 @@ typedef struct slock { * decl_simple_lock_data(static,foo) static * decl_simple_lock_data(,foo) ordinary */ -typedef usimple_lock_data_t *simple_lock_t; -#ifdef MACH_KERNEL_PRIVATE +#include + +#ifdef __APPLE_API_PRIVATE + +#ifdef MACH_KERNEL_PRIVATE + #include #include @@ -258,18 +261,25 @@ typedef usimple_lock_data_t *simple_lock_t; #endif #if (defined(LOCK_SIMPLE_DATA) || ((NCPUS == 1) && !USLOCK_DEBUG )) +typedef usimple_lock_data_t *simple_lock_t; #define decl_simple_lock_data(class,name) #endif -#endif /* MACH_KERNEL_PRIVATE */ + +#endif /* MACH_KERNEL_PRIVATE */ + +#endif /* __APPLE_API_PRIVATE */ /* * Outside the mach kernel component, and even within it on SMP or * debug systems, simple locks are the same as usimple locks. */ #if !defined(decl_simple_lock_data) +typedef usimple_lock_data_t *simple_lock_t; typedef usimple_lock_data_t simple_lock_data_t; + #define decl_simple_lock_data(class,name) \ -class simple_lock_data_t name; + class simple_lock_data_t name; + #endif /* !defined(decl_simple_lock_data) */ #endif /* !_SIMPLE_LOCK_TYPES_H_ */ diff --git a/osfmk/kern/startup.c b/osfmk/kern/startup.c index b3a5b0094..0972af8e1 100644 --- a/osfmk/kern/startup.c +++ b/osfmk/kern/startup.c @@ -153,7 +153,6 @@ setup_main(void) task_init(); act_init(); thread_init(); - subsystem_init(); /* * Initialize the Event Trace Analysis Package. @@ -163,24 +162,20 @@ setup_main(void) /* * Create a kernel thread to start the other kernel - * threads. Thread_resume (from kernel_thread) calls - * thread_setrun, which may look at current thread; - * we must avoid this, since there is no current thread. + * threads. */ startup_thread = kernel_thread_with_priority( kernel_task, MAXPRI_KERNEL, start_kernel_threads, TRUE, FALSE); - /* - * Pretend it is already running, and resume it. - * Since it looks as if it is running, thread_resume - * will not try to put it on the run queues. + * Pretend it is already running. * - * We can do all of this without locking, because nothing + * We can do this without locking, because nothing * else is running yet. */ startup_thread->state = TH_RUN; - (void) thread_resume(startup_thread->top_act); + hw_atomic_add(&startup_thread->processor_set->run_count, 1); + /* * Start the thread. */ @@ -223,6 +218,11 @@ start_kernel_threads(void) splx(s); } + /* + * Initialize the thread reaper mechanism. + */ + thread_reaper_init(); + /* * Initialize the stack swapin mechanism. */ @@ -245,11 +245,6 @@ start_kernel_threads(void) mapping_adjust(); #endif - /* - * Initialize the thread reaper mechanism. - */ - thread_reaper(); - /* * Create the clock service. */ @@ -297,13 +292,17 @@ slave_main(void) processor_t myprocessor = current_processor(); thread_t thread; + myprocessor->cpu_data = get_cpu_data(); thread = myprocessor->next_thread; myprocessor->next_thread = THREAD_NULL; if (thread == THREAD_NULL) { thread = machine_wake_thread; machine_wake_thread = THREAD_NULL; - thread_bind(thread, myprocessor); } + thread_machine_set_current(thread); + if (thread == machine_wake_thread) + thread_bind(thread, myprocessor); + cpu_launch_first_thread(thread); /*NOTREACHED*/ panic("slave_main"); @@ -337,19 +336,16 @@ cpu_launch_first_thread( thread_t thread) { register int mycpu = cpu_number(); + processor_t processor = cpu_to_processor(mycpu); - /* initialize preemption disabled */ - cpu_data[mycpu].preemption_level = 1; + processor->cpu_data->preemption_level = 0; cpu_up(mycpu); start_timer(&kernel_timer[mycpu]); - clock_get_uptime(&cpu_to_processor(mycpu)->last_dispatch); + clock_get_uptime(&processor->last_dispatch); - if (thread == THREAD_NULL) { - thread = cpu_to_processor(mycpu)->idle_thread; - if (thread == THREAD_NULL) - panic("cpu_launch_first_thread"); - } + if (thread == THREAD_NULL || thread == processor->idle_thread) + panic("cpu_launch_first_thread"); rtclock_reset(); /* start realtime clock ticking */ PMAP_ACTIVATE_KERNEL(mycpu); @@ -357,7 +353,9 @@ cpu_launch_first_thread( thread_machine_set_current(thread); thread_lock(thread); thread->state &= ~TH_UNINT; - _mk_sp_thread_begin(thread); + thread->last_processor = processor; + processor->current_pri = thread->sched_pri; + _mk_sp_thread_begin(thread, processor); thread_unlock(thread); timer_switch(&thread->system_timer); diff --git a/osfmk/kern/subsystem.c b/osfmk/kern/subsystem.c deleted file mode 100644 index abf1f146c..000000000 --- a/osfmk/kern/subsystem.c +++ /dev/null @@ -1,492 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * @OSF_COPYRIGHT@ - */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:32 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.2 1998/04/29 17:36:19 mburg - * MK7.3 merger - * - * Revision 1.1.18.1 1998/02/03 09:30:24 gdt - * Merge up to MK7.3 - * [1998/02/03 09:15:10 gdt] - * - * Revision 1.1.16.1 1997/06/17 02:59:23 devrcs - * Added call to `ipc_subsystem_terminate()' to `subsystem_deallocate()' - * to close port leak. - * [1997/03/18 18:25:55 rkc] - * - * Revision 1.1.7.4 1995/01/10 05:14:19 devrcs - * mk6 CR801 - merge up from nmk18b4 to nmk18b7 - * * Rev 1.1.7.3 1994/10/19 16:24:57 watkins - * Define subsystem_print if mach_debug. - * [1994/12/09 21:01:02 dwm] - * - * mk6 CR668 - 1.3b26 merge - * splx is void. - * [1994/11/04 09:32:40 dwm] - * - * Revision 1.1.7.2 1994/09/23 02:27:05 ezf - * change marker to not FREE - * [1994/09/22 21:36:22 ezf] - * - * Revision 1.1.7.1 1994/09/16 15:30:10 emcmanus - * Implement "show subsystem" command. - * [1994/09/16 15:29:11 emcmanus] - * - * Revision 1.1.3.4 1994/06/02 01:53:14 bolinger - * mk6 CR125: Initialize subsystem_lock(). - * [1994/06/01 22:30:18 bolinger] - * - * Revision 1.1.3.3 1994/01/21 01:22:58 condict - * Fix too stringent error checking. Change subsys from ool to in-line. - * [1994/01/21 01:19:32 condict] - * - * Revision 1.1.3.2 1994/01/20 16:25:29 condict - * Testing bsubmit. - * [1994/01/20 16:24:32 condict] - * - * Revision 1.1.3.1 1994/01/20 11:09:26 emcmanus - * Copied for submission. - * [1994/01/20 11:08:20 emcmanus] - * - * Revision 1.1.1.4 1994/01/20 02:45:10 condict - * Make user subsystem point at containing system subsytem struct. - * - * Revision 1.1.1.3 1994/01/15 22:01:19 condict - * Validate user subsystem data, convert user ptrs to kernel ptrs. - * - * Revision 1.1.1.2 1994/01/13 02:39:58 condict - * Implementation of RPC subsystem object, for server co-location. - * - * $EndLog$ - */ -/* - * Functions to manipulate RPC subsystem descriptions. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define SUBSYSTEM_MIN_SIZE 12 -#define SUBSYSTEM_MAX_SIZE (2*1024*1024) /* What value is correct? */ - -void -subsystem_init( - void) -{ - /* Nothing to do on bootstrap, at the moment. */ -} - -/* - * Routine: mach_subsystem_create - * Purpose: - * Create a new RPC subsystem. - * Conditions: - * Nothing locked. If successful, the subsystem is returned - * unlocked. (The caller has a reference.) - * Returns: - * KERN_SUCCESS The subsystem is allocated. - * KERN_INVALID_TASK The task is dead. - * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. - */ - -kern_return_t -mach_subsystem_create( - register task_t parent_task, - user_subsystem_t user_subsys, - mach_msg_type_number_t user_subsysCount, - subsystem_t *subsystem_p) -{ - int i; - subsystem_t new_subsystem; - kern_return_t kr; - boolean_t deallocate = FALSE; - vm_size_t size; - vm_offset_t offset; - int num_routines; - boolean_t bad_arg = FALSE; - - if (parent_task == TASK_NULL) - return(KERN_INVALID_ARGUMENT); - - if (user_subsysCount < SUBSYSTEM_MIN_SIZE || - user_subsysCount > SUBSYSTEM_MAX_SIZE) - return(KERN_INVALID_ARGUMENT); - - /* - * Allocate a subsystem and initialize: - */ - - size = (vm_size_t)user_subsysCount + sizeof(struct subsystem) - - sizeof(struct rpc_subsystem); - new_subsystem = (subsystem_t) kalloc(size); - - if (new_subsystem == 0) - return(KERN_RESOURCE_SHORTAGE); - - new_subsystem->task = parent_task; - new_subsystem->ref_count = 1; /* A reference for our caller */ - new_subsystem->size = size; - subsystem_lock_init(new_subsystem); - - /* Copy the user subsystem data to a permanent place: */ - bcopy((char *)user_subsys, (char *)&(new_subsystem->user), - (int)user_subsysCount); - - /* Validate the user-specified fields of the subsystem: */ - - num_routines = new_subsystem->user.end - new_subsystem->user.start; - if (num_routines < 0 || - (char *)&new_subsystem->user.routine[num_routines] > - (char *)&new_subsystem->user + (int)user_subsysCount - ) { - kfree((vm_offset_t)new_subsystem, size); - return(KERN_INVALID_ADDRESS); - } - - /* The following is for converting the user pointers in the - * subsystem struct to kernel pointers: - */ - offset = (char *)&new_subsystem->user - - (char *)new_subsystem->user.base_addr; /* The user addr */ - - for (i = 0; i < num_routines; i++) { - routine_descriptor_t routine = &new_subsystem->user.routine[i]; - - /* If this is a "skip" routine, ignore it: */ - if (!routine->impl_routine) - continue; - - /* Convert the user arg_descr pointer to a kernel pointer: */ - routine->arg_descr = (routine_arg_descriptor_t) - ((char *)routine->arg_descr + offset); - - if (routine->argc > 1000000 || - routine->argc < routine->descr_count) { - bad_arg = TRUE; - break; - } - /* Validate that the arg_descr field is within the part of - * the struct that follows the routine array: */ - if ((char *)&routine->arg_descr[0] < - (char *)&new_subsystem->user.routine[num_routines] - || - (char *)&routine->arg_descr[routine->descr_count] > - (char *)&new_subsystem->user + (int)user_subsysCount - ) { - printf("Arg descr out of bounds: arg_descr=%x, &routine.num_routines=%x\n", - &routine->arg_descr[0], &new_subsystem->user.routine[num_routines]); - printf(" new_subsys->user + subsysCount = %x\n", - (char *)&new_subsystem->user + (int)user_subsysCount); -#if MACH_DEBUG && MACH_KDB - subsystem_print(new_subsystem); - /* Not all of the arg_descr pointers have necessarily - been corrected, but this just means that we print - the arg_descr from the user's input subsystem - instead of the copy we are building. */ -#endif /* MACH_DEBUG && MACH_KDB */ - bad_arg = TRUE; - break; - } - } - if (bad_arg) { - kfree((vm_offset_t)new_subsystem, size); - return(KERN_INVALID_ADDRESS); - } - - /* Convert the user base address to a kernel address: */ - new_subsystem->user.base_addr = (vm_address_t)&new_subsystem->user; - - /* Make the user subsystem point at the containing system data - * structure, so we can get from a port (which points to the user - * subsystem data) to the system subsystem struct: - */ - new_subsystem->user.subsystem = new_subsystem; - - ipc_subsystem_init(new_subsystem); - - task_lock(parent_task); - if (parent_task->active) { - parent_task->subsystem_count++; - queue_enter(&parent_task->subsystem_list, new_subsystem, - subsystem_t, subsystem_list); - } else - deallocate = TRUE; - task_unlock(parent_task); - - if (deallocate) { - /* release ref we would have given our caller */ - subsystem_deallocate(new_subsystem); - return(KERN_INVALID_TASK); - } - - ipc_subsystem_enable(new_subsystem); - - *subsystem_p = new_subsystem; - return(KERN_SUCCESS); -} - -/* - * Routine: subsystem_reference - * Purpose: - * Increments the reference count on a subsystem. - * Conditions: - * Nothing is locked. - */ -void -subsystem_reference( - register subsystem_t subsystem) -{ - spl_t s; - - if (subsystem == SUBSYSTEM_NULL) - return; - - s = splsched(); - subsystem_lock(subsystem); - subsystem->ref_count++; - subsystem_unlock(subsystem); - splx(s); -} - - - -/* - * Routine: subsystem_deallocate - * Purpose: - * Decrements the reference count on a subsystem. If 0, - * destroys the subsystem. Must have no ports registered on it - * when it is destroyed. - * Conditions: - * The subsystem is locked, and - * the caller has a reference, which is consumed. - */ - -void -subsystem_deallocate( - subsystem_t subsystem) -{ - task_t task; - spl_t s; - - if (subsystem == SUBSYSTEM_NULL) - return; - - s = splsched(); - subsystem_lock(subsystem); - if (--subsystem->ref_count > 0) { - subsystem_unlock(subsystem); - splx(s); - return; - } - - /* - * Count is 0, so destroy the subsystem. Need to restore the - * reference temporarily, and lock the task first: - */ - ipc_subsystem_disable(subsystem); - - subsystem->ref_count = 1; - subsystem_unlock(subsystem); - splx(s); - - task = subsystem->task; - task_lock(task); - s = splsched(); - subsystem_lock(subsystem); - - /* Check again, since we temporarily unlocked the subsystem: */ - if (--subsystem->ref_count == 0) { - - task->subsystem_count--; - queue_remove(&task->subsystem_list, subsystem, subsystem_t, - subsystem_list); - ipc_subsystem_terminate(subsystem); - subsystem_unlock(subsystem); - splx(s); - kfree((vm_offset_t) subsystem, subsystem->size); - task_unlock(task); - return; - } - - ipc_subsystem_enable(subsystem); - - subsystem_unlock(subsystem); - splx(s); - task_unlock(task); -} - - -#include -#if MACH_KDB - -#include -#include -#include -#include - -#define printf kdbprintf - -/* - * Routine: subsystem_print - * Purpose: - * Pretty-print a subsystem for kdb. - */ - -void rpc_subsystem_print(rpc_subsystem_t subsys); - -void -subsystem_print( - subsystem_t subsystem) -{ - extern int db_indent; - - iprintf("subsystem 0x%x\n", subsystem); - - db_indent += 2; - - iprintf("ref %d size %x task %x port %x\n", subsystem->ref_count, - subsystem->size, subsystem->task, subsystem->ipc_self); - rpc_subsystem_print(&subsystem->user); - -/* ipc_object_print(&port->ip_object); - * iprintf("receiver=0x%x", port->ip_receiver); - * printf(", receiver_name=0x%x\n", port->ip_receiver_name); - */ - db_indent -=2; -} - -struct flagnames { - char *name; - int bit; -} arg_type_names[] = { - "port", MACH_RPC_PORT, "array", MACH_RPC_ARRAY, - "variable", MACH_RPC_VARIABLE, "in", MACH_RPC_IN, "out", MACH_RPC_OUT, - "pointer", MACH_RPC_POINTER, "phys_copy", MACH_RPC_PHYSICAL_COPY, - "virt_copy", MACH_RPC_VIRTUAL_COPY, "deallocate", MACH_RPC_DEALLOCATE, - "onstack", MACH_RPC_ONSTACK, "bounded", MACH_RPC_BOUND, -}; - -void -rpc_subsystem_print( - rpc_subsystem_t subsys) -{ - int i, num_routines; - - iprintf("rpc_subsystem 0x%x\n", subsys); - - db_indent += 2; - - num_routines = subsys->end - subsys->start; - iprintf("start %d end %d (%d routines) maxsize %x base %x\n", - subsys->start, subsys->end, num_routines, subsys->maxsize, - subsys->base_addr); - for (i = 0; i < num_routines; i++) { - routine_descriptor_t routine = subsys->routine + i; - routine_arg_descriptor_t args = routine->arg_descr; - int j, type, disposition; - struct flagnames *n; - char *sep; - - iprintf("%x #%d:", routine, subsys->start + i); - if (routine->impl_routine == 0) { - printf(" skip\n"); - continue; - } - printf("\n"); - db_indent += 2; - iprintf("impl "); - db_printsym((db_expr_t) routine->impl_routine, DB_STGY_PROC); - printf("\n"); - iprintf("stub "); - db_printsym((db_expr_t) routine->stub_routine, DB_STGY_PROC); - printf("\n"); - iprintf("argc %d descr_count %d max_reply %x\n", - routine->argc, routine->descr_count, routine->max_reply_msg); - for (j = 0; j < routine->descr_count; j++) { - iprintf("%x desc %d: size %d count %d offset %x type", &args[j], j, - args[j].size, args[j].count, args[j].offset); - sep = " "; - type = args[j].type; - for (n = arg_type_names; n->name != 0; n++) { - if (type & n->bit) { - printf("%s%s", sep, n->name); - sep = "|"; - type &= ~n->bit; /* Might have an alias */ - } - } -#define NAME_MASK (3 << NAME_SHIFT) /* XXX magic numbers */ -#define ACTION_MASK (3 << ACTION_SHIFT) -#define DISPOSITION_MASK (NAME_MASK | ACTION_MASK) - disposition = type & DISPOSITION_MASK; - type &= ~DISPOSITION_MASK; - if (sep[0] != '|' || type != 0) - printf("%s%x", sep, type); - switch (disposition & ACTION_MASK) { - case MACH_RPC_MOVE: printf(" move"); break; - case MACH_RPC_COPY: printf(" copy"); break; - case MACH_RPC_MAKE: printf(" make"); break; - } - switch (disposition & NAME_MASK) { - case MACH_RPC_RECEIVE: printf(" receive"); break; - case MACH_RPC_SEND: printf(" send"); break; - case MACH_RPC_SEND_ONCE: printf(" send-once"); break; - } - printf("\n"); - } - db_indent -= 2; - } - - db_indent -= 2; -} - -void -db_show_subsystem( - db_expr_t addr, - boolean_t have_addr, - db_expr_t count, - char *modif) -{ - if (!have_addr || addr == 0) { - db_printf("No subsystem\n"); - return; - } - if (db_option(modif, 'r')) - rpc_subsystem_print((rpc_subsystem_t) addr); - else - subsystem_print((subsystem_t) addr); -} - -#endif /* MACH_KDB || MACH_DEBUG */ diff --git a/osfmk/kern/subsystem.h b/osfmk/kern/subsystem.h deleted file mode 100644 index 13e0959ad..000000000 --- a/osfmk/kern/subsystem.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * @OSF_COPYRIGHT@ - */ -/* - * Definitions for RPC subsystems. - */ - -#ifndef _IPC_IPC_SUBSYSTEM_H_ -#define _IPC_IPC_SUBSYSTEM_H_ - -#include -#include -#include -#include - -#ifdef MACH_KERNEL_PRIVATE -#include -#include - -#define subsystem_lock_init(subsys) \ - simple_lock_init(&(subsys)->lock, ETAP_MISC_RPC_SUBSYS) -#define subsystem_lock(subsys) simple_lock(&(subsys)->lock) -#define subsystem_unlock(subsys) simple_unlock(&(subsys)->lock) - -/* - * A subsystem describes a set of server routines that can be invoked by - * mach_rpc() on the ports that are registered with the subsystem. - * See struct rpc_subsystem in mach/rpc.h, for more details. - */ -struct subsystem { - /* Synchronization/destruction information */ - decl_simple_lock_data(,lock) /* Subsystem lock */ - int ref_count; /* Number of references to me */ - vm_size_t size; /* Number of bytes in this structure */ - /* including the variable length */ - /* user_susbystem description */ - /* Task information */ - task_t task; /* Task to which I belong */ - queue_chain_t subsystem_list; /* list of subsystems in task */ - - /* IPC stuff: */ - struct ipc_port *ipc_self; /* Port naming this subsystem */ - - struct rpc_subsystem user; /* MIG-generated subsystem descr */ -}; - -extern void subsystem_init(void); - -#endif /* MACH_KERNEL_PRIVATE */ - -/* Subsystem create, with 1 reference. */ -extern kern_return_t mach_subsystem_create( - task_t parent_task, - user_subsystem_t user_subsys, - mach_msg_type_number_t user_subsysCount, - subsystem_t *subsystem); - -/* Take additional reference on subsystem (make sure it doesn't go away) */ -extern void subsystem_reference( - subsystem_t subsystem); - -/* Remove one reference on subsystem (it is destroyed if 0 refs remain) */ -extern void subsystem_deallocate( - subsystem_t subsystem); - -#if MACH_KDB -extern void subsystem_print( - subsystem_t subsystem); -#endif /* MACH_KDB */ - -#endif /* _IPC_IPC_SUBSYSTEM_H_ */ diff --git a/osfmk/kern/sync_lock.c b/osfmk/kern/sync_lock.c index c6b997e54..9acae3739 100644 --- a/osfmk/kern/sync_lock.c +++ b/osfmk/kern/sync_lock.c @@ -97,10 +97,10 @@ MACRO_END unsigned int lock_set_event; -#define LOCK_SET_EVENT ((event_t)&lock_set_event) +#define LOCK_SET_EVENT ((event64_t)&lock_set_event) unsigned int lock_set_handoff; -#define LOCK_SET_HANDOFF ((event_t)&lock_set_handoff) +#define LOCK_SET_HANDOFF ((event64_t)&lock_set_handoff) /* * ROUTINE: lock_set_init [private] @@ -240,7 +240,7 @@ lock_set_destroy (task_t task, lock_set_t lock_set) if (ulock->accept_wait) { ulock->accept_wait = FALSE; - wait_queue_wakeup_one(&ulock->wait_queue, + wait_queue_wakeup64_one(&ulock->wait_queue, LOCK_SET_HANDOFF, THREAD_RESTART); } @@ -248,13 +248,13 @@ lock_set_destroy (task_t task, lock_set_t lock_set) if (ulock->holder) { if (ulock->blocked) { ulock->blocked = FALSE; - wait_queue_wakeup_all(&ulock->wait_queue, + wait_queue_wakeup64_all(&ulock->wait_queue, LOCK_SET_EVENT, THREAD_RESTART); } if (ulock->ho_wait) { ulock->ho_wait = FALSE; - wait_queue_wakeup_one(&ulock->wait_queue, + wait_queue_wakeup64_one(&ulock->wait_queue, LOCK_SET_HANDOFF, THREAD_RESTART); } @@ -309,15 +309,13 @@ lock_acquire (lock_set_t lock_set, int lock_id) if (ulock->holder != THR_ACT_NULL) { int wait_result; - lock_set_unlock(lock_set); - if (ulock->holder == current_act()) { ulock_unlock(ulock); return KERN_LOCK_OWNED_SELF; } ulock->blocked = TRUE; - (void)wait_queue_assert_wait(&ulock->wait_queue, + wait_result = wait_queue_assert_wait64(&ulock->wait_queue, LOCK_SET_EVENT, THREAD_ABORTSAFE); ulock_unlock(ulock); @@ -325,8 +323,8 @@ lock_acquire (lock_set_t lock_set, int lock_id) /* * Block - Wait for lock to become available. */ - - wait_result = thread_block((void (*)(void))0); + if (wait_result == THREAD_WAITING) + wait_result = thread_block(THREAD_CONTINUE_NULL); /* * Check the result status: @@ -526,7 +524,6 @@ lock_release_internal (ulock_t ulock, thread_act_t thr_act) if (ulock->holder != thr_act) { ulock_unlock(ulock); - lock_set_unlock(lock_set); return KERN_INVALID_RIGHT; } @@ -542,7 +539,7 @@ lock_release_internal (ulock_t ulock, thread_act_t thr_act) s = splsched(); wait_queue_lock(wq); - thread = wait_queue_wakeup_identity_locked(wq, + thread = wait_queue_wakeup64_identity_locked(wq, LOCK_SET_EVENT, THREAD_AWAKENED, TRUE); @@ -613,7 +610,6 @@ lock_handoff (lock_set_t lock_set, int lock_id) if (ulock->holder != current_act()) { ulock_unlock(ulock); - lock_set_unlock(lock_set); return KERN_INVALID_RIGHT; } @@ -633,7 +629,7 @@ lock_handoff (lock_set_t lock_set, int lock_id) */ s = splsched(); wait_queue_lock(wq); - thread = wait_queue_wakeup_identity_locked( + thread = wait_queue_wakeup64_identity_locked( wq, LOCK_SET_HANDOFF, THREAD_AWAKENED, @@ -681,13 +677,13 @@ lock_handoff (lock_set_t lock_set, int lock_id) * for an accepting thread. */ ulock->ho_wait = TRUE; - (void)wait_queue_assert_wait(&ulock->wait_queue, + wait_result = wait_queue_assert_wait64(&ulock->wait_queue, LOCK_SET_HANDOFF, THREAD_ABORTSAFE); ulock_unlock(ulock); - ETAP_SET_REASON(current_thread(), BLOCKED_ON_LOCK_HANDOFF); - wait_result = thread_block((void (*)(void))0); + if (wait_result == THREAD_WAITING) + wait_result = thread_block(THREAD_CONTINUE_NULL); /* * If the thread was woken-up via some action other than @@ -767,7 +763,7 @@ lock_handoff_accept (lock_set_t lock_set, int lock_id) assert(ulock->holder != THR_ACT_NULL); thread = ulock->holder->thread; - if (wait_queue_wakeup_thread(wq, + if (wait_queue_wakeup64_thread(wq, LOCK_SET_HANDOFF, thread, THREAD_AWAKENED) == KERN_SUCCESS) { @@ -792,13 +788,13 @@ lock_handoff_accept (lock_set_t lock_set, int lock_id) } ulock->accept_wait = TRUE; - (void)wait_queue_assert_wait(&ulock->wait_queue, + wait_result = wait_queue_assert_wait64(&ulock->wait_queue, LOCK_SET_HANDOFF, THREAD_ABORTSAFE); ulock_unlock(ulock); - ETAP_SET_REASON(current_thread(), BLOCKED_ON_LOCK_HANDOFF); - wait_result = thread_block((void (*)(void))0); + if (wait_result == THREAD_WAITING) + wait_result = thread_block(THREAD_CONTINUE_NULL); /* * If the thread was woken-up via some action other than diff --git a/osfmk/kern/sync_lock.h b/osfmk/kern/sync_lock.h index 040594f8c..99f2d098c 100644 --- a/osfmk/kern/sync_lock.h +++ b/osfmk/kern/sync_lock.h @@ -35,7 +35,11 @@ #include -#ifdef MACH_KERNEL_PRIVATE +#include + +#ifdef __APPLE_API_PRIVATE + +#ifdef MACH_KERNEL_PRIVATE #include #include @@ -81,9 +85,6 @@ typedef struct lock_set { #define ULOCK_FREE 0 #define ULOCK_HELD 1 -#define LOCK_OPERATION_ABORTED(th) ((th)->wait_link.prev != (queue_entry_t) 0) -#define LOCK_OPERATION_COMPLETE(th) ((th)->wait_link.prev = (queue_entry_t) 0) - /* * Data structure internal lock macros */ @@ -100,7 +101,13 @@ typedef struct lock_set { extern void lock_set_init(void); -#endif /* MACH_KERNEL_PRIVATE */ +extern kern_return_t lock_release_internal (ulock_t ulock, + thread_act_t thr_act); + +#endif /* MACH_KERNEL_PRIVATE */ + +#endif /* __APPLE_API_PRIVATE */ + /* * Forward Declarations @@ -129,9 +136,6 @@ extern kern_return_t lock_make_stable (lock_set_t lock_set, extern kern_return_t lock_make_unstable (ulock_t ulock, thread_act_t thr_act); -extern kern_return_t lock_release_internal (ulock_t ulock, - thread_act_t thr_act); - extern kern_return_t lock_handoff (lock_set_t lock_set, int lock_id); diff --git a/osfmk/kern/sync_sema.c b/osfmk/kern/sync_sema.c index d7bc25187..34618b4b5 100644 --- a/osfmk/kern/sync_sema.c +++ b/osfmk/kern/sync_sema.c @@ -50,8 +50,8 @@ #include #include -unsigned int semaphore_event; -#define SEMAPHORE_EVENT ((event_t)&semaphore_event) +static unsigned int semaphore_event; +#define SEMAPHORE_EVENT ((event64_t)&semaphore_event) zone_t semaphore_zone; unsigned int semaphore_max = SEMAPHORE_MAX; @@ -188,7 +188,7 @@ semaphore_destroy( semaphore->count = 0; if (old_count < 0) { - wait_queue_wakeup_all_locked(&semaphore->wait_queue, + wait_queue_wakeup64_all_locked(&semaphore->wait_queue, SEMAPHORE_EVENT, THREAD_RESTART, TRUE); /* unlock? */ @@ -235,7 +235,7 @@ semaphore_signal_internal( if (thread_act != THR_ACT_NULL) { if (semaphore->count < 0) { - kr = wait_queue_wakeup_thread_locked( + kr = wait_queue_wakeup64_thread_locked( &semaphore->wait_queue, SEMAPHORE_EVENT, thread_act->thread, @@ -254,7 +254,7 @@ semaphore_signal_internal( if (old_count < 0) { semaphore->count = 0; /* always reset */ - kr = wait_queue_wakeup_all_locked( + kr = wait_queue_wakeup64_all_locked( &semaphore->wait_queue, SEMAPHORE_EVENT, THREAD_AWAKENED, @@ -270,7 +270,7 @@ semaphore_signal_internal( } if (semaphore->count < 0) { - if (wait_queue_wakeup_one_locked( + if (wait_queue_wakeup64_one_locked( &semaphore->wait_queue, SEMAPHORE_EVENT, THREAD_AWAKENED, @@ -582,10 +582,11 @@ semaphore_wait_internal( kr = KERN_OPERATION_TIMED_OUT; } else { wait_semaphore->count = -1; /* we don't keep an actual count */ - (void)wait_queue_assert_wait_locked(&wait_semaphore->wait_queue, - SEMAPHORE_EVENT, - THREAD_ABORTSAFE, - FALSE); /* unlock? */ + (void)wait_queue_assert_wait64_locked( + &wait_semaphore->wait_queue, + SEMAPHORE_EVENT, + THREAD_ABORTSAFE, + FALSE); /* unlock? */ } semaphore_unlock(wait_semaphore); splx(spl_level); @@ -671,7 +672,7 @@ semaphore_wait_internal( self->sth_signalsemaphore = signal_semaphore; wait_result = thread_block(continuation); } else { - wait_result = thread_block((void (*)(void))0); + wait_result = thread_block(THREAD_CONTINUE_NULL); } /* diff --git a/osfmk/kern/syscall_subr.c b/osfmk/kern/syscall_subr.c index b5ff64c69..886f49f00 100644 --- a/osfmk/kern/syscall_subr.c +++ b/osfmk/kern/syscall_subr.c @@ -120,7 +120,7 @@ swtch(void) counter(c_swtch_block++); - thread_block(swtch_continue); + thread_block_reason(swtch_continue, AST_YIELD); mp_disable_preemption(); myprocessor = current_processor(); @@ -170,7 +170,7 @@ swtch_pri( _mk_sp_thread_depress_abstime(std_quantum); - thread_block(swtch_pri_continue); + thread_block_reason(swtch_pri_continue, AST_YIELD); _mk_sp_thread_depress_abort(current_thread(), FALSE); diff --git a/osfmk/kern/syscall_sw.c b/osfmk/kern/syscall_sw.c index 2bfbd3b90..bd96882de 100644 --- a/osfmk/kern/syscall_sw.c +++ b/osfmk/kern/syscall_sw.c @@ -120,7 +120,7 @@ mach_trap_t mach_trap_table[] = { MACH_TRAP(task_self_trap, 0), /* 28 */ MACH_TRAP(host_self_trap, 0), /* 29 */ MACH_TRAP(kern_invalid, 0), /* 30 */ - MACH_TRAP(kern_invalid, 0), /* 31 */ + MACH_TRAP(mach_msg_trap, 7), /* 31 */ MACH_TRAP(mach_msg_overwrite_trap, 9), /* 32 */ MACH_TRAP(semaphore_signal_trap, 1), /* 33 */ MACH_TRAP(semaphore_signal_all_trap, 1), /* 34 */ diff --git a/osfmk/kern/task.c b/osfmk/kern/task.c index aa8b142f6..ea12d7b39 100644 --- a/osfmk/kern/task.c +++ b/osfmk/kern/task.c @@ -87,7 +87,6 @@ #include #include #include -#include #include #include #include @@ -138,8 +137,6 @@ void task_free( task_t task ); void task_synchronizer_destroy_all( task_t task); -void task_subsystem_destroy_all( - task_t task); kern_return_t task_set_ledger( task_t task, @@ -176,7 +173,9 @@ task_init(void) } #if MACH_HOST -void + +#if 0 +static void task_freeze( task_t task) { @@ -186,18 +185,23 @@ task_freeze( * wait for that to finish. */ while (task->may_assign == FALSE) { + wait_result_t res; + task->assign_active = TRUE; - thread_sleep_mutex((event_t) &task->assign_active, - &task->lock, THREAD_INTERRUPTIBLE); - task_lock(task); + res = thread_sleep_mutex((event_t) &task->assign_active, + &task->lock, THREAD_UNINT); + assert(res == THREAD_AWAKENED); } task->may_assign = FALSE; task_unlock(task); - return; } +#else +#define thread_freeze(thread) assert(task->processor_set == &default_pset) +#endif -void +#if 0 +static void task_unfreeze( task_t task) { @@ -209,9 +213,12 @@ task_unfreeze( thread_wakeup((event_t)&task->assign_active); } task_unlock(task); - return; } +#else +#define thread_unfreeze(thread) assert(task->processor_set == &default_pset) +#endif + #endif /* MACH_HOST */ /* @@ -346,7 +353,6 @@ task_create_local( trunc_page(VM_MAX_ADDRESS), TRUE); mutex_init(&new_task->lock, ETAP_THREAD_TASK_NEW); - queue_init(&new_task->subsystem_list); queue_init(&new_task->thr_acts); new_task->suspend_count = 0; new_task->thr_act_count = 0; @@ -477,23 +483,27 @@ task_create_local( } /* - * task_free: + * task_deallocate * - * Called by task_deallocate when the task's reference count drops to zero. + * Drop a reference on a task * Task is locked. */ void -task_free( +task_deallocate( task_t task) { processor_set_t pset; + int refs; -#if MACH_ASSERT - assert(task != 0); - if (watchacts & (WA_EXIT|WA_TASK)) - printf("task_free(%x(%d)) map ref %d\n", task, task->ref_count, - task->map->ref_count); -#endif /* MACH_ASSERT */ + if (task == TASK_NULL) + return; + + task_lock(task); + refs = --task->ref_count; + task_unlock(task); + + if (refs > 0) + return; #if TASK_SWAPPER /* task_terminate guarantees that this task is off the list */ @@ -502,46 +512,21 @@ task_free( eml_task_deallocate(task); - /* - * Temporarily restore the reference we dropped above, then - * freeze the task so that the task->processor_set field - * cannot change. In the !MACH_HOST case, the logic can be - * simplified, since the default_pset is the only pset. - */ - ++task->ref_count; - task_unlock(task); -#if MACH_HOST + ipc_task_terminate(task); + +#if MACH_HOST task_freeze(task); -#endif /* MACH_HOST */ - +#endif + pset = task->processor_set; pset_lock(pset); - task_lock(task); - if (--task->ref_count > 0) { - /* - * A new reference appeared (probably from the pset). - * Back out. Must unfreeze inline since we'already - * dropped our reference. - */ -#if MACH_HOST - assert(task->may_assign == FALSE); - task->may_assign = TRUE; - if (task->assign_active == TRUE) { - task->assign_active = FALSE; - thread_wakeup((event_t)&task->assign_active); - } -#endif /* MACH_HOST */ - task_unlock(task); - pset_unlock(pset); - return; - } pset_remove_task(pset,task); - task_unlock(task); pset_unlock(pset); pset_deallocate(pset); - ipc_task_terminate(task); - shared_region_mapping_dealloc(task->system_shared_region); +#if MACH_HOST + task_unfreeze(task); +#endif if (task->kernel_loaded) vm_map_remove(kernel_map, task->map->min_offset, @@ -549,27 +534,9 @@ task_free( vm_map_deallocate(task->map); is_release(task->itk_space); task_prof_deallocate(task); - if(task->dynamic_working_set) - tws_hash_destroy((tws_hash_t) - task->dynamic_working_set); zfree(task_zone, (vm_offset_t) task); } -void -task_deallocate( - task_t task) -{ - if (task != TASK_NULL) { - int c; - - task_lock(task); - c = --task->ref_count; - if (c == 0) - task_free(task); /* unlocks task */ - else - task_unlock(task); - } -} void task_reference( @@ -620,7 +587,6 @@ task_terminate_internal( { thread_act_t thr_act, cur_thr_act; task_t cur_task; - thread_t cur_thread; boolean_t interrupt_save; assert(task != kernel_task); @@ -679,9 +645,7 @@ task_terminate_internal( * Make sure the current thread does not get aborted out of * the waits inside these operations. */ - cur_thread = current_thread(); - interrupt_save = cur_thread->interruptible; - cur_thread->interruptible = FALSE; + interrupt_save = thread_interrupt_level(THREAD_UNINT); /* * Indicate that we want all the threads to stop executing @@ -724,11 +688,6 @@ task_terminate_internal( */ task_synchronizer_destroy_all(task); - /* - * Deallocate all subsystems owned by the task. - */ - task_subsystem_destroy_all(task); - /* * Destroy the IPC space, leaving just a reference for it. */ @@ -747,11 +706,16 @@ task_terminate_internal( task->map->min_offset, task->map->max_offset, VM_MAP_NO_FLAGS); + shared_region_mapping_dealloc(task->system_shared_region); + + if(task->dynamic_working_set) + tws_hash_destroy((tws_hash_t)task->dynamic_working_set); + /* * We no longer need to guard against being aborted, so restore * the previous interruptible state. */ - cur_thread->interruptible = interrupt_save; + thread_interrupt_level(interrupt_save); /* * Get rid of the task active reference on itself. @@ -847,25 +811,11 @@ task_halt( task_synchronizer_destroy_all(task); /* - * Deallocate all subsystems owned by the task. - */ - task_subsystem_destroy_all(task); - -#if 0 - /* - * Destroy the IPC space, leaving just a reference for it. - */ - /* - * Lookupd will break if we enable this cleaning, because it - * uses a slimey trick that depends upon the portspace not - * being cleaned up across exec (it passes the lookupd server - * port to the child after a restart using knowledge of this - * bug in past implementations). We need to fix lookupd to - * keep from leaking ports across exec. + * Destroy the contents of the IPC space, leaving just + * a reference for it. */ if (!task->kernel_loaded) ipc_space_clean(task->itk_space); -#endif /* * Clean out the address space, as we are going to be @@ -895,7 +845,8 @@ task_hold_locked( assert(task->active); - task->suspend_count++; + if (task->suspend_count++ > 0) + return; /* * Iterate through all the thread_act's and hold them. @@ -983,9 +934,10 @@ task_release_locked( register thread_act_t thr_act; assert(task->active); + assert(task->suspend_count > 0); - task->suspend_count--; - assert(task->suspend_count >= 0); + if (--task->suspend_count > 0) + return; /* * Iterate through all the thread_act's and hold them. @@ -1374,14 +1326,11 @@ task_info( thread = act_lock_thread(thr_act); - /* Skip empty threads and threads that have migrated - * into this task: + /* JMM - add logic to skip threads that have migrated + * into this task? */ - if (!thread || thr_act->pool_port) { - act_unlock_thread(thr_act); - continue; - } - assert(thread); /* Must have thread, if no thread_pool*/ + + assert(thread); /* Must have thread */ s = splsched(); thread_lock(thread); @@ -1610,30 +1559,48 @@ task_collect_scan(void) register task_t task, prev_task; processor_set_t pset = &default_pset; - prev_task = TASK_NULL; - pset_lock(pset); pset->ref_count++; task = (task_t) queue_first(&pset->tasks); while (!queue_end(&pset->tasks, (queue_entry_t) task)) { - task_reference(task); - pset_unlock(pset); + task_lock(task); + if (task->ref_count > 0) { - pmap_collect(task->map->pmap); + task_reference_locked(task); + task_unlock(task); - if (prev_task != TASK_NULL) - task_deallocate(prev_task); - prev_task = task; +#if MACH_HOST + /* + * While we still have the pset locked, freeze the task in + * this pset. That way, when we get back from collecting + * it, we can dereference the pset_tasks chain for the task + * and be assured that we are still in this chain. + */ + task_freeze(task); +#endif + + pset_unlock(pset); - pset_lock(pset); - task = (task_t) queue_next(&task->pset_tasks); + pmap_collect(task->map->pmap); + + pset_lock(pset); + prev_task = task; + task = (task_t) queue_next(&task->pset_tasks); + +#if MACH_HOST + task_unfreeze(prev_task); +#endif + + task_deallocate(prev_task); + } else { + task_unlock(task); + task = (task_t) queue_next(&task->pset_tasks); + } } + pset_unlock(pset); pset_deallocate(pset); - - if (prev_task != TASK_NULL) - task_deallocate(prev_task); } /* Also disabled in vm/vm_pageout.c */ @@ -1721,21 +1688,6 @@ task_synchronizer_destroy_all(task_t task) } } -void -task_subsystem_destroy_all(task_t task) -{ - subsystem_t subsystem; - - /* - * Destroy owned subsystems - */ - - while (!queue_empty(&task->subsystem_list)) { - subsystem = (subsystem_t) queue_first(&task->subsystem_list); - subsystem_deallocate(subsystem); - } -} - /* * task_set_port_space: * diff --git a/osfmk/kern/task.h b/osfmk/kern/task.h index 569fa0292..e59bcbc4a 100644 --- a/osfmk/kern/task.h +++ b/osfmk/kern/task.h @@ -82,7 +82,10 @@ #include #include -#ifdef MACH_KERNEL_PRIVATE +#ifdef __APPLE_API_PRIVATE + +#ifdef MACH_KERNEL_PRIVATE + #include #include #include @@ -172,10 +175,6 @@ typedef struct task { struct ipc_space *itk_space; - /* RPC subsystem information */ - queue_head_t subsystem_list; /* list of subsystems */ - int subsystem_count;/* number of subsystems */ - /* Synchronizer ownership information */ queue_head_t semaphore_list; /* list of owned semaphores */ queue_head_t lock_set_list; /* list of owned lock sets */ @@ -212,7 +211,6 @@ typedef struct task { vm_offset_t dynamic_working_set; } Task; - #define task_lock(task) mutex_lock(&(task)->lock) #define task_lock_try(task) mutex_try(&(task)->lock) #define task_unlock(task) mutex_unlock(&(task)->lock) @@ -222,6 +220,8 @@ typedef struct task { #define itk_lock(task) mutex_lock(&(task)->itk_lock_data) #define itk_unlock(task) mutex_unlock(&(task)->itk_lock_data) +#define task_reference_locked(task) ((task)->ref_count++) + /* * Internal only routines */ @@ -236,28 +236,14 @@ extern kern_return_t task_create_local( boolean_t kernel_loaded, task_t *child_task); /* OUT */ -#if MACH_HOST -/* Freeze and unfreeze task from being reassigned processor sets */ -extern void task_freeze( - task_t task); - -extern void task_unfreeze( - task_t task); -#endif /* MACH_HOST */ - extern void consider_task_collect(void); #define current_task_fast() (current_act_fast()->task) #define current_task() current_task_fast() -#else /* !MACH_KERNEL_PRIVATE */ - -extern task_t current_task(void); - -#endif /* !MACH_KERNEL_PRIVATE */ +#endif /* MACH_KERNEL_PRIVATE */ extern task_t kernel_task; -extern boolean_t is_kerneltask(task_t); /* Temporarily hold all threads in a task */ extern kern_return_t task_hold( @@ -271,15 +257,6 @@ extern kern_return_t task_release( extern kern_return_t task_halt( task_t task); -/* Take reference on task (make sure it doesn't go away) */ -extern void task_reference(task_t task); - -/* Try to take a reference on task, return false if it would block */ -extern boolean_t task_reference_try(task_t task); - -/* Remove reference to task */ -extern void task_deallocate(task_t task); - #if defined(MACH_KERNEL_PRIVATE) || defined(BSD_BUILD) extern kern_return_t task_importance( task_t task, @@ -292,4 +269,21 @@ extern void set_bsdtask_info(task_t,void *); extern vm_map_t get_task_map(task_t); extern vm_map_t swap_task_map(task_t, vm_map_t); extern pmap_t get_task_pmap(task_t); + +extern boolean_t task_reference_try(task_t task); + +#endif /* __APPLE_API_PRIVATE */ + +#if !defined(MACH_KERNEL_PRIVATE) + +extern task_t current_task(void); + +#endif /* MACH_KERNEL_TASK */ + +/* Take reference on task (make sure it doesn't go away) */ +extern void task_reference(task_t task); + +/* Remove reference to task */ +extern void task_deallocate(task_t task); + #endif /* _KERN_TASK_H_ */ diff --git a/osfmk/kern/task_policy.c b/osfmk/kern/task_policy.c index 42e38211e..a0f9672ae 100644 --- a/osfmk/kern/task_policy.c +++ b/osfmk/kern/task_policy.c @@ -66,8 +66,9 @@ task_policy_set( case TASK_FOREGROUND_APPLICATION: case TASK_BACKGROUND_APPLICATION: case TASK_UNSPECIFIED: - task_priority(task, BASEPRI_DEFAULT + - ((info->role == TASK_FOREGROUND_APPLICATION)? +16: +15), + task_priority(task, + ((info->role == TASK_FOREGROUND_APPLICATION)? + BASEPRI_FOREGROUND: BASEPRI_BACKGROUND), task->max_priority); task->role = info->role; break; @@ -88,7 +89,7 @@ task_policy_set( task->sec_token.val[0] != 0 ) result = KERN_INVALID_ARGUMENT; else { - task_priority(task, BASEPRI_DEFAULT + 17, task->max_priority); + task_priority(task, BASEPRI_CONTROL, task->max_priority); task->role = info->role; } } diff --git a/osfmk/kern/task_swap.c b/osfmk/kern/task_swap.c index 6744ce3bc..7d69ca1e4 100644 --- a/osfmk/kern/task_swap.c +++ b/osfmk/kern/task_swap.c @@ -67,6 +67,11 @@ mutex_t task_swapper_lock; /* protects above queue */ #define task_swapper_lock() mutex_lock(&task_swapper_lock) #define task_swapper_unlock() mutex_unlock(&task_swapper_lock) +#define task_swapper_wakeup() thread_wakeup((event_t)&swapout_thread_q) +#define task_swapper_sleep() thread_sleep_mutex((event_t)&swapout_thread_q, \ + &task_swapper_lock, \ + THREAD_UNINT) + queue_head_t eligible_tasks; /* tasks eligible for swapout */ mutex_t task_swapout_list_lock; /* protects above queue */ @@ -450,7 +455,7 @@ thread_swapout_enqueue(thread_act_t thr_act) } else { queue_enter(&swapout_thread_q, thr_act, thread_act_t, swap_queue); - thread_wakeup((event_t)&swapout_thread_q); + task_swapper_wakeup(); } act_unlock(thr_act); task_swapper_unlock(); @@ -475,8 +480,8 @@ task_swap_swapout_thread(void) spllo(); + task_swapper_lock(); while (TRUE) { - task_swapper_lock(); while (! queue_empty(&swapout_thread_q)) { queue_remove_first(&swapout_thread_q, thr_act, @@ -584,9 +589,7 @@ task_swap_swapout_thread(void) act_deallocate(thr_act); task_swapper_lock(); } - assert_wait((event_t)&swapout_thread_q, THREAD_UNINT); - task_swapper_unlock(); - thread_block((void (*)(void)) 0); + task_swapper_sleep(); } } @@ -685,7 +688,7 @@ task_swapin(task_t task, boolean_t make_unswappable) task->swap_flags |= TASK_SW_WANT_IN; assert_wait((event_t)&task->swap_state, THREAD_UNINT); task_unlock(task); - thread_block((void (*)(void)) 0); + thread_block(THREAD_CONTINUE_NULL); TASK_STATS_INCR(task_sw_race_coming_in); return(KERN_SUCCESS); case TASK_SW_UNSWAPPABLE: @@ -1213,7 +1216,7 @@ task_swapper(void) } if (task_swap_debug) printf("task_swapper: blocking\n"); - thread_block((void (*)(void)) 0); + thread_block(THREAD_CONTINUE_NULL); if (timeout) { thread_cancel_timeout(current_thread()); } diff --git a/osfmk/kern/thread.c b/osfmk/kern/thread.c index 7237be096..98c7a90c1 100644 --- a/osfmk/kern/thread.c +++ b/osfmk/kern/thread.c @@ -129,17 +129,19 @@ vm_offset_t active_stacks[NCPUS]; /* per-cpu active stacks */ vm_offset_t kernel_stack[NCPUS]; /* top of active stacks */ thread_act_t active_kloaded[NCPUS]; /* + act if kernel loaded */ +boolean_t first_thread; struct zone *thread_shuttle_zone; queue_head_t reaper_queue; decl_simple_lock_data(,reaper_lock) -thread_call_t thread_reaper_call; extern int tick; extern void pcb_module_init(void); +struct thread_shuttle pageout_thread; + /* private */ static struct thread_shuttle thr_sh_template; @@ -505,15 +507,18 @@ thread_init(void) /* thr_sh_template.thread_list (later) */ /* thr_sh_template.pset_threads (later) */ - /* one ref for pset, one for activation */ - thr_sh_template.ref_count = 2; + /* reference for activation */ + thr_sh_template.ref_count = 1; - thr_sh_template.wait_event = NO_EVENT; - thr_sh_template.wait_result = KERN_SUCCESS; + thr_sh_template.reason = AST_NONE; + thr_sh_template.at_safe_point = FALSE; + thr_sh_template.wait_event = NO_EVENT64; thr_sh_template.wait_queue = WAIT_QUEUE_NULL; - thr_sh_template.wake_active = FALSE; + thr_sh_template.wait_result = THREAD_WAITING; + thr_sh_template.interrupt_level = THREAD_ABORTSAFE; thr_sh_template.state = TH_STACK_HANDOFF | TH_WAIT | TH_UNINT; - thr_sh_template.interruptible = TRUE; + thr_sh_template.wake_active = FALSE; + thr_sh_template.active_callout = FALSE; thr_sh_template.continuation = (void (*)(void))0; thr_sh_template.top_act = THR_ACT_NULL; @@ -523,13 +528,16 @@ thread_init(void) thr_sh_template.priority = 0; thr_sh_template.sched_pri = 0; - thr_sh_template.depress_priority = -1; thr_sh_template.max_priority = 0; thr_sh_template.task_priority = 0; + thr_sh_template.promotions = 0; + thr_sh_template.pending_promoter_index = 0; + thr_sh_template.pending_promoter[0] = + thr_sh_template.pending_promoter[1] = NULL; thr_sh_template.current_quantum = 0; - thr_sh_template.metered_computation = 0; + thr_sh_template.computation_metered = 0; thr_sh_template.computation_epoch = 0; thr_sh_template.cpu_usage = 0; @@ -540,6 +548,10 @@ thread_init(void) thr_sh_template.sleep_stamp = 0; thr_sh_template.safe_release = 0; + thr_sh_template.bound_processor = PROCESSOR_NULL; + thr_sh_template.last_processor = PROCESSOR_NULL; + thr_sh_template.last_switch = 0; + thr_sh_template.vm_privilege = FALSE; timer_init(&(thr_sh_template.user_timer)); @@ -551,20 +563,13 @@ thread_init(void) thr_sh_template.active = FALSE; /* reset */ - /* thr_sh_template.processor_set (later) */ -#if NCPUS > 1 - thr_sh_template.bound_processor = PROCESSOR_NULL; -#endif /*NCPUS > 1*/ + thr_sh_template.processor_set = PROCESSOR_SET_NULL; #if MACH_HOST thr_sh_template.may_assign = TRUE; thr_sh_template.assign_active = FALSE; #endif /* MACH_HOST */ thr_sh_template.funnel_state = 0; -#if NCPUS > 1 - /* thr_sh_template.last_processor (later) */ -#endif /* NCPUS > 1 */ - /* * Initialize other data structures used in * this module. @@ -611,7 +616,6 @@ thread_init(void) #endif /* MACHINE_STACK */ #if MACH_LDEBUG - thr_sh_template.kthread = FALSE; thr_sh_template.mutex_count = 0; #endif /* MACH_LDEBUG */ @@ -647,6 +651,7 @@ thread_init(void) (1 << SCHED_TICK_SHIFT); } + first_thread = TRUE; /* * Initialize any machine-dependent * per-thread structures necessary. @@ -654,21 +659,26 @@ thread_init(void) thread_machine_init(); } +/* + * Called at splsched. + */ void thread_reaper_enqueue( thread_t thread) { - /* - * thread lock is already held, splsched() - * not necessary here. - */ simple_lock(&reaper_lock); enqueue_tail(&reaper_queue, (queue_entry_t)thread); simple_unlock(&reaper_lock); - thread_call_enter(thread_reaper_call); + thread_wakeup((event_t)&reaper_queue); } +void +thread_termination_continue(void) +{ + panic("thread_termination_continue"); + /*NOTREACHED*/ +} /* * Routine: thread_terminate_self @@ -690,17 +700,28 @@ thread_reaper_enqueue( void thread_terminate_self(void) { - register thread_t thread = current_thread(); - thread_act_t thr_act = thread->top_act; + thread_act_t thr_act = current_act(); + thread_t thread; task_t task = thr_act->task; - int active_acts; + long active_acts; spl_t s; /* * We should be at the base of the inheritance chain. */ + thread = act_lock_thread(thr_act); assert(thr_act->thread == thread); + /* This will allow no more control ops on this thr_act. */ + ipc_thr_act_disable(thr_act); + + /* Clean-up any ulocks that are still owned by the thread + * activation (acquired but not released or handed-off). + */ + act_ulock_release_all(thr_act); + + act_unlock_thread(thr_act); + _mk_sp_thread_depress_abort(thread, TRUE); /* @@ -709,46 +730,14 @@ thread_terminate_self(void) * If so, and the task is associated with a BSD process, we * need to call BSD and let them clean up. */ - task_lock(task); - active_acts = --task->active_act_count; - task_unlock(task); - if (!active_acts && task->bsd_info) - proc_exit(task->bsd_info); - -#ifdef CALLOUT_RPC_MODEL - if (thr_act->lower) { - /* - * JMM - RPC will not be using a callout/stack manipulation - * mechanism. instead we will let it return normally as if - * from a continuation. Accordingly, these need to be cleaned - * up a bit. - */ - act_switch_swapcheck(thread, (ipc_port_t)0); - act_lock(thr_act); /* hierarchy violation XXX */ - (void) switch_act(THR_ACT_NULL); - assert(thr_act->ref_count == 1); /* XXX */ - /* act_deallocate(thr_act); XXX */ - prev_act = thread->top_act; - /* - * disable preemption to protect kernel stack changes - * disable_preemption(); - * MACH_RPC_RET(prev_act) = KERN_RPC_SERVER_TERMINATED; - * machine_kernel_stack_init(thread, mach_rpc_return_error); - */ - act_unlock(thr_act); + active_acts = hw_atomic_sub(&task->active_act_count, 1); - /* - * Load_context(thread); - */ - /* NOTREACHED */ - } - -#else /* !CALLOUT_RPC_MODEL */ + if (active_acts == 0 && task->bsd_info) + proc_exit(task->bsd_info); + /* JMM - for now, no migration */ assert(!thr_act->lower); -#endif /* CALLOUT_RPC_MODEL */ - s = splsched(); thread_lock(thread); thread->active = FALSE; @@ -764,19 +753,18 @@ thread_terminate_self(void) s = splsched(); thread_lock(thread); - thread->state |= (TH_HALTED|TH_TERMINATE); + thread->state |= TH_TERMINATE; assert((thread->state & TH_UNINT) == 0); thread_mark_wait_locked(thread, THREAD_UNINT); + assert(thread->promotions == 0); thread_unlock(thread); /* splx(s); */ ETAP_SET_REASON(thread, BLOCKED_ON_TERMINATION); - thread_block((void (*)(void)) 0); - panic("the zombie walks!"); + thread_block(thread_termination_continue); /*NOTREACHED*/ } - /* * Create a new thread. * Doesn't start the thread running; It first must be attached to @@ -789,26 +777,30 @@ thread_create_shuttle( void (*start)(void), thread_t *new_thread) { + kern_return_t result; thread_t new_shuttle; task_t parent_task = thr_act->task; processor_set_t pset; - kern_return_t result; - int suspcnt; - - assert(!thr_act->thread); - assert(!thr_act->pool_port); /* * Allocate a thread and initialize static fields */ - new_shuttle = (thread_t)zalloc(thread_shuttle_zone); + if (first_thread) { + new_shuttle = &pageout_thread; + first_thread = FALSE; + } else + new_shuttle = (thread_t)zalloc(thread_shuttle_zone); if (new_shuttle == THREAD_NULL) return (KERN_RESOURCE_SHORTAGE); +#ifdef DEBUG + if (new_shuttle != &pageout_thread) + assert(!thr_act->thread); +#endif + *new_shuttle = thr_sh_template; thread_lock_init(new_shuttle); - rpc_lock_init(new_shuttle); wake_lock_init(new_shuttle); new_shuttle->sleep_stamp = sched_tick; @@ -824,12 +816,11 @@ thread_create_shuttle( ipc_thread_init(new_shuttle); pset = parent_task->processor_set; - if (!pset->active) { - pset = &default_pset; - } + assert(pset == &default_pset); pset_lock(pset); task_lock(parent_task); + assert(parent_task->processor_set == pset); /* * Don't need to initialize because the context switch @@ -849,7 +840,9 @@ thread_create_shuttle( queue_enter(&parent_task->thr_acts, thr_act, thread_act_t, thr_acts); parent_task->thr_act_count++; parent_task->res_act_count++; - parent_task->active_act_count++; + + /* So terminating threads don't need to take the task lock to decrement */ + hw_atomic_add(&parent_task->active_act_count, 1); /* Associate the thread with the processor set */ pset_add_thread(pset, new_shuttle); @@ -865,7 +858,7 @@ thread_create_shuttle( new_shuttle->importance = new_shuttle->priority - new_shuttle->task_priority; new_shuttle->sched_stamp = sched_tick; - compute_priority(new_shuttle, TRUE); + compute_priority(new_shuttle, FALSE); #if ETAP_EVENT_MONITOR new_thread->etap_reason = 0; @@ -874,114 +867,108 @@ thread_create_shuttle( new_shuttle->active = TRUE; thr_act->active = TRUE; - pset_unlock(pset); - - /* - * No need to lock thr_act, since it can't be known to anyone -- - * we set its suspend_count to one more than the task suspend_count - * by calling thread_hold. - */ - thr_act->user_stop_count = 1; - for (suspcnt = thr_act->task->suspend_count + 1; suspcnt; --suspcnt) - thread_hold(thr_act); - task_unlock(parent_task); *new_thread = new_shuttle; { - long dbg_arg1, dbg_arg2, dbg_arg3, dbg_arg4; + long dbg_arg1, dbg_arg2, dbg_arg3, dbg_arg4; - KERNEL_DEBUG_CONSTANT((TRACEDBG_CODE(DBG_TRACE_DATA, 1)) | DBG_FUNC_NONE, - (vm_address_t)new_shuttle, 0,0,0,0); + KERNEL_DEBUG_CONSTANT( + TRACEDBG_CODE(DBG_TRACE_DATA, 1) | DBG_FUNC_NONE, + (vm_address_t)new_shuttle, 0, 0, 0, 0); - kdbg_trace_string(parent_task->bsd_info, &dbg_arg1, &dbg_arg2, &dbg_arg3, - &dbg_arg4); - KERNEL_DEBUG_CONSTANT((TRACEDBG_CODE(DBG_TRACE_STRING, 1)) | DBG_FUNC_NONE, - dbg_arg1, dbg_arg2, dbg_arg3, dbg_arg4, 0); + kdbg_trace_string(parent_task->bsd_info, + &dbg_arg1, &dbg_arg2, &dbg_arg3, &dbg_arg4); + + KERNEL_DEBUG_CONSTANT( + TRACEDBG_CODE(DBG_TRACE_STRING, 1) | DBG_FUNC_NONE, + dbg_arg1, dbg_arg2, dbg_arg3, dbg_arg4, 0); } return (KERN_SUCCESS); } +extern void thread_bootstrap_return(void); + kern_return_t thread_create( task_t task, thread_act_t *new_act) { - thread_act_t thr_act; - thread_t thread; kern_return_t result; - spl_t s; - extern void thread_bootstrap_return(void); + thread_t thread; + thread_act_t act; if (task == TASK_NULL) return KERN_INVALID_ARGUMENT; - result = act_create(task, &thr_act); + result = act_create(task, &act); if (result != KERN_SUCCESS) return (result); - result = thread_create_shuttle(thr_act, -1, thread_bootstrap_return, &thread); + result = thread_create_shuttle(act, -1, thread_bootstrap_return, &thread); if (result != KERN_SUCCESS) { - act_deallocate(thr_act); + act_deallocate(act); return (result); } - if (task->kernel_loaded) - thread_user_to_kernel(thread); + act->user_stop_count = 1; + thread_hold(act); + if (task->suspend_count > 0) + thread_hold(act); - /* Start the thread running (it will immediately suspend itself). */ - s = splsched(); - thread_ast_set(thr_act, AST_APC); - thread_lock(thread); - thread_go_locked(thread, THREAD_AWAKENED); - thread_unlock(thread); - splx(s); + pset_unlock(task->processor_set); + task_unlock(task); - *new_act = thr_act; + *new_act = act; return (KERN_SUCCESS); } -/* - * Update thread that belongs to a task created via kernel_task_create(). - */ -void -thread_user_to_kernel( - thread_t thread) -{ - /* - * Used to set special swap_func here... - */ -} - kern_return_t thread_create_running( - register task_t parent_task, + register task_t task, int flavor, thread_state_t new_state, mach_msg_type_number_t new_state_count, - thread_act_t *child_act) /* OUT */ + thread_act_t *new_act) /* OUT */ { register kern_return_t result; + thread_t thread; + thread_act_t act; + + if (task == TASK_NULL) + return KERN_INVALID_ARGUMENT; - result = thread_create(parent_task, child_act); + result = act_create(task, &act); if (result != KERN_SUCCESS) return (result); - result = act_machine_set_state(*child_act, flavor, - new_state, new_state_count); + result = thread_create_shuttle(act, -1, thread_bootstrap_return, &thread); if (result != KERN_SUCCESS) { - (void) thread_terminate(*child_act); + act_deallocate(act); return (result); } - result = thread_resume(*child_act); + act_lock(act); + result = act_machine_set_state(act, flavor, new_state, new_state_count); if (result != KERN_SUCCESS) { - (void) thread_terminate(*child_act); + act_unlock(act); + pset_unlock(task->processor_set); + task_unlock(task); + + (void)thread_terminate(act); return (result); } + clear_wait(thread, THREAD_AWAKENED); + act->inited = TRUE; + act_unlock(act); + pset_unlock(task->processor_set); + task_unlock(task); + + *new_act = act; + return (result); } @@ -1001,41 +988,32 @@ kernel_thread_with_priority( { kern_return_t result; thread_t thread; - thread_act_t thr_act; - spl_t s; + thread_act_t act; - result = act_create(task, &thr_act); - if (result != KERN_SUCCESS) { - return THREAD_NULL; - } + result = act_create(task, &act); + if (result != KERN_SUCCESS) + return (THREAD_NULL); - result = thread_create_shuttle(thr_act, priority, start, &thread); + result = thread_create_shuttle(act, priority, start, &thread); if (result != KERN_SUCCESS) { - act_deallocate(thr_act); - return THREAD_NULL; + act_deallocate(act); + return (THREAD_NULL); } + pset_unlock(task->processor_set); + task_unlock(task); + if (alloc_stack) thread_doswapin(thread); - s = splsched(); - thread_lock(thread); - - thr_act = thread->top_act; -#if MACH_LDEBUG - thread->kthread = TRUE; -#endif /* MACH_LDEBUG */ - + act_lock(act); if (start_running) - thread_go_locked(thread, THREAD_AWAKENED); + clear_wait(thread, THREAD_AWAKENED); + act->inited = TRUE; + act_unlock(act); - thread_unlock(thread); - splx(s); - - if (start_running) - thread_resume(thr_act); + act_deallocate(act); - act_deallocate(thr_act); return (thread); } @@ -1049,90 +1027,65 @@ kernel_thread( unsigned int c_weird_pset_ref_exit = 0; /* pset code raced us */ +#if MACH_HOST +/* Preclude thread processor set assignement */ +#define thread_freeze(thread) assert((thread)->processor_set == &default_pset) + +/* Allow thread processor set assignement */ +#define thread_unfreeze(thread) assert((thread)->processor_set == &default_pset) + +#endif /* MACH_HOST */ + void thread_deallocate( thread_t thread) { task_t task; processor_set_t pset; + int refs; spl_t s; if (thread == THREAD_NULL) return; /* - * First, check for new count > 1 (the common case). + * First, check for new count > 0 (the common case). * Only the thread needs to be locked. */ s = splsched(); thread_lock(thread); - if (--thread->ref_count > 1) { - thread_unlock(thread); - splx(s); + refs = --thread->ref_count; + thread_unlock(thread); + splx(s); + + if (refs > 0) return; - } + + if (thread == current_thread()) + panic("thread deallocating itself"); /* - * Down to pset reference, lets try to clean up. - * However, the processor set may make more. Its lock - * also dominate the thread lock. So, reverse the - * order of the locks and see if its still the last - * reference; + * There is a dangling pointer to the thread from the + * processor_set. To clean it up, we freeze the thread + * in the pset (because pset destruction can cause even + * reference-less threads to be reassigned to the default + * pset) and then remove it. */ - assert(thread->ref_count == 1); /* Else this is an extra dealloc! */ - thread_unlock(thread); - splx(s); -#if MACH_HOST +#if MACH_HOST thread_freeze(thread); -#endif /* MACH_HOST */ +#endif pset = thread->processor_set; pset_lock(pset); - - s = splsched(); - thread_lock(thread); - - if (thread->ref_count > 1) { -#if MACH_HOST - boolean_t need_wakeup = FALSE; - /* - * processor_set made extra reference. - */ - /* Inline the unfreeze */ - thread->may_assign = TRUE; - if (thread->assign_active) { - need_wakeup = TRUE; - thread->assign_active = FALSE; - } -#endif /* MACH_HOST */ - thread_unlock(thread); - splx(s); - pset_unlock(pset); -#if MACH_HOST - if (need_wakeup) - thread_wakeup((event_t)&thread->assign_active); -#endif /* MACH_HOST */ - c_weird_pset_ref_exit++; - return; - } -#if MACH_HOST - assert(thread->assign_active == FALSE); -#endif /* MACH_HOST */ - - /* - * Thread only had pset reference - we can remove it. - */ - if (thread == current_thread()) - panic("thread deallocating itself"); - pset_remove_thread(pset, thread); - thread->ref_count = 0; - thread_unlock(thread); /* no more references - safe */ - splx(s); pset_unlock(pset); - pset_deallocate(thread->processor_set); +#if MACH_HOST + thread_unfreeze(thread); +#endif + + pset_deallocate(pset); if (thread->stack_privilege != 0) { if (thread->stack_privilege != thread->kernel_stack) @@ -1156,7 +1109,7 @@ thread_reference( s = splsched(); thread_lock(thread); - thread->ref_count++; + thread_reference_locked(thread); thread_unlock(thread); splx(s); } @@ -1230,7 +1183,7 @@ thread_info_shuttle( flags |= TH_FLAGS_SWAPPED; state = 0; - if (thread->state & TH_HALTED) + if (thread->state & TH_TERMINATE) state = TH_STATE_HALTED; else if (thread->state & TH_RUN) @@ -1276,12 +1229,18 @@ thread_info_shuttle( return (KERN_INVALID_POLICY); } - ts_info->base_priority = thread->priority; - ts_info->max_priority = thread->max_priority; - ts_info->cur_priority = thread->sched_pri; + ts_info->depressed = (thread->sched_mode & TH_MODE_ISDEPRESSED) != 0; + if (ts_info->depressed) { + ts_info->base_priority = DEPRESSPRI; + ts_info->depress_priority = thread->priority; + } + else { + ts_info->base_priority = thread->priority; + ts_info->depress_priority = -1; + } - ts_info->depressed = (thread->depress_priority >= 0); - ts_info->depress_priority = thread->depress_priority; + ts_info->cur_priority = thread->sched_pri; + ts_info->max_priority = thread->max_priority; thread_unlock(thread); splx(s); @@ -1316,13 +1275,19 @@ thread_info_shuttle( return (KERN_INVALID_POLICY); } - rr_info->base_priority = thread->priority; + rr_info->depressed = (thread->sched_mode & TH_MODE_ISDEPRESSED) != 0; + if (rr_info->depressed) { + rr_info->base_priority = DEPRESSPRI; + rr_info->depress_priority = thread->priority; + } + else { + rr_info->base_priority = thread->priority; + rr_info->depress_priority = -1; + } + rr_info->max_priority = thread->max_priority; rr_info->quantum = std_quantum_us / 1000; - rr_info->depressed = (thread->depress_priority >= 0); - rr_info->depress_priority = thread->depress_priority; - thread_unlock(thread); splx(s); @@ -1339,14 +1304,12 @@ thread_doreap( register thread_t thread) { thread_act_t thr_act; - struct ipc_port *pool_port; thr_act = thread_lock_act(thread); assert(thr_act && thr_act->thread == thread); act_locked_act_reference(thr_act); - pool_port = thr_act->pool_port; /* * Replace `act_unlock_thread()' with individual @@ -1354,70 +1317,62 @@ thread_doreap( * to determine which locks are held, confusing * `act_unlock_thread()'.) */ - rpc_unlock(thread); - if (pool_port != IP_NULL) - ip_unlock(pool_port); act_unlock(thr_act); /* Remove the reference held by a rooted thread */ - if (pool_port == IP_NULL) - act_deallocate(thr_act); + act_deallocate(thr_act); /* Remove the reference held by the thread: */ act_deallocate(thr_act); } -static thread_call_data_t thread_reaper_call_data; - /* * reaper_thread: * - * This kernel thread runs forever looking for threads to destroy - * (when they request that they be destroyed, of course). - * - * The reaper thread will disappear in the next revision of thread - * control when it's function will be moved into thread_dispatch. + * This kernel thread runs forever looking for terminating + * threads, releasing their "self" references. */ static void -_thread_reaper( - thread_call_param_t p0, - thread_call_param_t p1) +reaper_thread_continue(void) { register thread_t thread; - spl_t s; - s = splsched(); + (void)splsched(); simple_lock(&reaper_lock); while ((thread = (thread_t) dequeue_head(&reaper_queue)) != THREAD_NULL) { simple_unlock(&reaper_lock); - - /* - * wait for run bit to clear - */ - thread_lock(thread); - if (thread->state & TH_RUN) - panic("thread reaper: TH_RUN"); - thread_unlock(thread); - splx(s); + (void)spllo(); thread_doreap(thread); - s = splsched(); + (void)splsched(); simple_lock(&reaper_lock); } + assert_wait((event_t)&reaper_queue, THREAD_UNINT); simple_unlock(&reaper_lock); - splx(s); + (void)spllo(); + + thread_block(reaper_thread_continue); + /*NOTREACHED*/ } -void -thread_reaper(void) +static void +reaper_thread(void) { - thread_call_setup(&thread_reaper_call_data, _thread_reaper, NULL); - thread_reaper_call = &thread_reaper_call_data; + thread_t self = current_thread(); + + stack_privilege(self); - _thread_reaper(NULL, NULL); + reaper_thread_continue(); + /*NOTREACHED*/ +} + +void +thread_reaper_init(void) +{ + kernel_thread(kernel_task, reaper_thread); } kern_return_t @@ -1425,9 +1380,6 @@ thread_assign( thread_act_t thr_act, processor_set_t new_pset) { -#ifdef lint - thread++; new_pset++; -#endif /* lint */ return(KERN_FAILURE); } @@ -1626,6 +1578,8 @@ processor_set_stack_usage( vm_size_t size, size_needed; vm_offset_t addr; + spl_t s; + if (pset == PROCESSOR_SET_NULL) return KERN_INVALID_ARGUMENT; @@ -1661,16 +1615,20 @@ processor_set_stack_usage( } /* OK, have memory and the processor_set is locked & active */ - + s = splsched(); threads = (thread_t *) addr; for (i = 0, thread = (thread_t) queue_first(&pset->threads); - i < actual; - i++, + !queue_end(&pset->threads, (queue_entry_t) thread); thread = (thread_t) queue_next(&thread->pset_threads)) { - thread_reference(thread); - threads[i] = thread; + thread_lock(thread); + if (thread->ref_count > 0) { + thread_reference_locked(thread); + threads[i++] = thread; + } + thread_unlock(thread); } - assert(queue_end(&pset->threads, (queue_entry_t) thread)); + splx(s); + assert(i <= actual); /* can unlock processor set now that we have the thread refs */ pset_unlock(pset); @@ -1680,9 +1638,9 @@ processor_set_stack_usage( total = 0; maxusage = 0; maxstack = 0; - for (i = 0; i < actual; i++) { + while (i > 0) { int cpu; - thread_t thread = threads[i]; + thread_t thread = threads[--i]; vm_offset_t stack = 0; /* @@ -1696,7 +1654,7 @@ processor_set_stack_usage( stack = thread->kernel_stack; for (cpu = 0; cpu < NCPUS; cpu++) - if (cpu_data[cpu].active_thread == thread) { + if (cpu_to_processor(cpu)->cpu_data->active_thread == thread) { stack = active_stacks[cpu]; break; } @@ -1720,7 +1678,7 @@ processor_set_stack_usage( #endif /* MACH_DEBUG */ } -static int split_funnel_off = 0; +int split_funnel_off = 0; funnel_t * funnel_alloc( int type) @@ -1898,4 +1856,3 @@ thread_should_halt( { return(thread_should_halt_fast(th)); } - diff --git a/osfmk/kern/thread.h b/osfmk/kern/thread.h index 559a640e0..511803644 100644 --- a/osfmk/kern/thread.h +++ b/osfmk/kern/thread.h @@ -86,15 +86,20 @@ #include #include #include + #include /* for current_thread */ #include +#include + /* * Logically, a thread of control consists of two parts: - * a thread_shuttle, which may migrate during an RPC, and + * + * a thread_shuttle, which may migrate due to resource contention + * and * a thread_activation, which remains attached to a task. - * The thread_shuttle is the larger portion of the two-part thread, - * and contains scheduling info, messaging support, accounting info, + * + * The thread_shuttle contains scheduling info, accounting info, * and links to the thread_activation within which the shuttle is * currently operating. * @@ -106,36 +111,13 @@ * * User accesses to threads always come in via the user's thread port, * which gets translated to a pointer to the target thread_activation. - * Kernel accesses intended to effect the entire thread, typically use - * a pointer to the thread_shuttle (current_thread()) as the target of - * their operations. This makes sense given that we have subsumed the - * shuttle into the thread_shuttle, eliminating one set of linkages. - * Operations effecting only the shuttle may use a thread_shuttle_t - * to indicate this. - * - * The current_act() macro returns a pointer to the current thread_act, while - * the current_thread() macro returns a pointer to the currently active - * thread_shuttle (representing the thread in its entirety). */ +#include -/* - * Possible results of thread_block - returned in - * current_thread()->wait_result. - */ -#define THREAD_AWAKENED 0 /* normal wakeup */ -#define THREAD_TIMED_OUT 1 /* timeout expired */ -#define THREAD_INTERRUPTED 2 /* interrupted by clear_wait */ -#define THREAD_RESTART 3 /* restart operation entirely */ +#ifdef __APPLE_API_PRIVATE -/* - * Interruptible flags for assert_wait - * - */ -#define THREAD_UNINT 0 /* not interruptible */ -#define THREAD_INTERRUPTIBLE 1 /* may not be restartable */ -#define THREAD_ABORTSAFE 2 /* abortable safely */ +#ifdef MACH_KERNEL_PRIVATE -#ifdef MACH_KERNEL_PRIVATE #include #include #include @@ -152,129 +134,159 @@ #include #include #include -#include #include #include #include #include #include +/* + * Kernel accesses intended to effect the entire thread, typically use + * a pointer to the thread_shuttle (current_thread()) as the target of + * their operations. This makes sense given that we have subsumed the + * shuttle into the thread_shuttle, eliminating one set of linkages. + * Operations effecting only the shuttle may use a thread_shuttle_t + * to indicate this. + * + * The current_act() macro returns a pointer to the current thread_act, while + * the current_thread() macro returns a pointer to the currently active + * thread_shuttle (representing the thread in its entirety). + */ struct thread_shuttle { /* - * Beginning of thread_shuttle proper. When the thread is on - * a wait queue, these three fields are in treated as an un- - * official union with a wait_queue_element. If you change - * these, you must change that definition as well. + * NOTE: The runq field in the thread structure has an unusual + * locking protocol. If its value is RUN_QUEUE_NULL, then it is + * locked by the thread_lock, but if its value is something else + * (i.e. a run_queue) then it is locked by that run_queue's lock. + * + * Beginning of thread_shuttle proper. When the thread is on + * a wait queue, these first three fields are treated as an un- + * official union with a wait_queue_element. If you change + * these, you must change that definition as well (wait_queue.h). */ - queue_chain_t links; /* current run/wait queue links */ - run_queue_t runq; /* run queue p is on SEE BELOW */ - int whichq; /* which queue level p is on */ -/* - * NOTE: The runq field in the thread structure has an unusual - * locking protocol. If its value is RUN_QUEUE_NULL, then it is - * locked by the thread_lock, but if its value is something else - * (i.e. a run_queue) then it is locked by that run_queue's lock. - */ + /* Items examined often, modified infrequently */ + queue_chain_t links; /* run/wait queue links */ + run_queue_t runq; /* run queue thread is on SEE BELOW */ + wait_queue_t wait_queue; /* wait queue we are currently on */ + event64_t wait_event; /* wait queue event */ + thread_act_t top_act; /* "current" thr_act */ + uint32_t /* Only set by thread itself */ + interrupt_level:2, /* interrupts/aborts allowed */ + vm_privilege:1, /* can use reserved memory? */ + active_callout:1, /* an active callout */ + :0; - /* Thread bookkeeping */ - queue_chain_t pset_threads; /* list of all shuttles in proc set */ - /* Synchronization */ + /* Data updated during assert_wait/thread_wakeup */ decl_simple_lock_data(,lock) /* scheduling lock (thread_lock()) */ decl_simple_lock_data(,wake_lock) /* covers wake_active (wake_lock())*/ - decl_mutex_data(,rpc_lock) /* RPC lock (rpc_lock()) */ - int ref_count; /* number of references to me */ - - vm_offset_t kernel_stack; - vm_offset_t stack_privilege; /* reserved kernel stack */ - - /* Blocking information */ - int reason; /* why we blocked */ - - event_t wait_event; /* event we are waiting on */ - kern_return_t wait_result; /* outcome of wait - + boolean_t wake_active; /* Someone is waiting for this */ + int at_safe_point; /* thread_abort_safely allowed */ + ast_t reason; /* why we blocked */ + wait_result_t wait_result; /* outcome of wait - * may be examined by this thread * WITHOUT locking */ + thread_roust_t roust; /* routine to roust it after wait */ + thread_continue_t continuation; /* resume here next dispatch */ - wait_queue_t wait_queue; /* wait queue we are currently on */ - queue_chain_t wait_link; /* event's wait queue link */ - - boolean_t wake_active; /* Someone is waiting for this - * thread to become suspended */ + /* Data updated/used in thread_invoke */ + struct funnel_lock *funnel_lock; /* Non-reentrancy funnel */ + int funnel_state; +#define TH_FN_OWNED 0x1 /* we own the funnel */ +#define TH_FN_REFUNNEL 0x2 /* re-acquire funnel on dispatch */ - boolean_t interruptible; /* Thread is "interruptible" */ + vm_offset_t kernel_stack; /* current kernel stack */ + vm_offset_t stack_privilege; /* reserved kernel stack */ /* Thread state: */ - int state; + int state; /* * Thread states [bits or'ed] */ -#define TH_WAIT 0x01 /* thread is queued for waiting */ -#define TH_SUSP 0x02 /* thread has been asked to stop */ -#define TH_RUN 0x04 /* thread is running or on runq */ -#define TH_UNINT 0x08 /* thread is waiting uninteruptibly */ -#define TH_HALTED 0x10 /* thread is halted at clean point ? */ +#define TH_WAIT 0x01 /* thread is queued for waiting */ +#define TH_SUSP 0x02 /* thread has been asked to stop */ +#define TH_RUN 0x04 /* thread is running or on runq */ +#define TH_UNINT 0x08 /* thread is waiting uninteruptibly */ +#define TH_TERMINATE 0x10 /* thread is halting at termination */ #define TH_ABORT 0x20 /* abort interruptible waits */ +#define TH_ABORT_SAFELY 0x40 /* ... but only those at safe point */ -#define TH_IDLE 0x80 /* thread is an idle thread */ +#define TH_IDLE 0x80 /* thread is an idle thread */ #define TH_SCHED_STATE (TH_WAIT|TH_SUSP|TH_RUN|TH_UNINT) -#define TH_STACK_HANDOFF 0x0100 /* thread has no kernel stack */ -#define TH_STACK_ALLOC 0x0200 /* thread is waiting for kernel stack */ +#define TH_STACK_HANDOFF 0x0100 /* thread has no kernel stack */ +#define TH_STACK_ALLOC 0x0200 /* waiting for stack allocation */ #define TH_STACK_STATE (TH_STACK_HANDOFF | TH_STACK_ALLOC) -#define TH_TERMINATE 0x0400 /* thread is terminating */ + /* Scheduling information */ + integer_t sched_mode; /* scheduling mode bits */ +#define TH_MODE_REALTIME 0x0001 /* time constraints supplied */ +#define TH_MODE_TIMESHARE 0x0002 /* use timesharing algorithm */ +#define TH_MODE_PREEMPT 0x0004 /* can preempt kernel contexts */ +#define TH_MODE_FAILSAFE 0x0008 /* fail-safe has tripped */ +#define TH_MODE_PROMOTED 0x0010 /* sched pri has been promoted */ +#define TH_MODE_FORCEDPREEMPT 0x0020 /* force setting of mode PREEMPT */ +#define TH_MODE_DEPRESS 0x0040 /* normal depress yield */ +#define TH_MODE_POLLDEPRESS 0x0080 /* polled depress yield */ +#define TH_MODE_ISDEPRESSED (TH_MODE_DEPRESS | TH_MODE_POLLDEPRESS) + + integer_t sched_pri; /* scheduled (current) priority */ + integer_t priority; /* base priority */ + integer_t max_priority; /* max base priority */ + integer_t task_priority; /* copy of task base priority */ + + integer_t promotions; /* level of promotion */ + integer_t pending_promoter_index; + void *pending_promoter[2]; - /* Stack handoff information */ - void (*continuation)(void); /* re-start here next dispatch */ + integer_t importance; /* task-relative importance */ - /* Scheduling information */ - integer_t importance; /* task-relative importance */ - integer_t sched_mode; /* scheduling mode bits */ -#define TH_MODE_REALTIME 0x0001 -#define TH_MODE_TIMESHARE 0x0002 -#define TH_MODE_FAILSAFE 0x0004 -#define TH_MODE_POLLDEPRESS 0x0008 - integer_t safe_mode; /* saved mode during fail-safe */ - struct { /* see mach/thread_policy.h */ + /* time constraint parameters */ + struct { /* see mach/thread_policy.h */ uint32_t period; uint32_t computation; uint32_t constraint; boolean_t preemptible; } realtime; - integer_t priority; /* base priority */ - integer_t sched_pri; /* scheduled (current) priority */ - integer_t depress_priority; /* priority to restore */ - integer_t max_priority; - integer_t task_priority; /* copy of task base priority */ - uint32_t current_quantum; /* duration of current quantum */ + /* Data used during setrun/dispatch */ + timer_data_t system_timer; /* system mode timer */ + processor_set_t processor_set; /* assigned processor set */ + processor_t bound_processor; /* bound to a processor? */ + processor_t last_processor; /* processor last dispatched on */ + uint64_t last_switch; /* time of last context switch */ + /* Fail-safe computation since last unblock or qualifying yield */ - uint64_t metered_computation; + uint64_t computation_metered; uint64_t computation_epoch; + integer_t safe_mode; /* saved mode during fail-safe */ + natural_t safe_release; /* when to release fail-safe */ + /* Used in priority computations */ + natural_t sched_stamp; /* when priority was updated */ natural_t cpu_usage; /* exp. decaying cpu usage [%cpu] */ natural_t cpu_delta; /* cpu usage since last update */ natural_t sched_usage; /* load-weighted cpu usage [sched] */ natural_t sched_delta; /* weighted cpu usage since update */ - natural_t sched_stamp; /* when priority was updated */ natural_t sleep_stamp; /* when entered TH_WAIT state */ - natural_t safe_release; /* when to release fail-safe */ - /* VM global variables */ - boolean_t vm_privilege; /* can use reserved memory? */ - vm_offset_t recover; /* page fault recovery (copyin/out) */ - - /* IPC data structures */ + /* Timing data structures */ + timer_data_t user_timer; /* user mode timer */ + timer_save_data_t system_timer_save; /* saved system timer value */ + timer_save_data_t user_timer_save; /* saved user timer value */ - struct ipc_kmsg_queue ith_messages; + /* Timed wait expiration */ + timer_call_data_t wait_timer; + integer_t wait_timer_active; + boolean_t wait_timer_is_set; - mach_port_t ith_mig_reply; /* reply port for mig */ - mach_port_t ith_rpc_reply; /* reply port for kernel RPCs */ + /* Priority depression expiration */ + timer_call_data_t depress_timer; + integer_t depress_timer_active; /* Various bits of stashed state */ union { @@ -287,57 +299,38 @@ struct thread_shuttle { mach_msg_size_t slist_size; /* scatter list size */ struct ipc_kmsg *kmsg; /* received message */ mach_port_seqno_t seqno; /* seqno of recvd message */ - void (*continuation)(mach_msg_return_t); - } receive; + mach_msg_continue_t continuation; + } receive; struct { struct semaphore *waitsemaphore; /* semaphore ref */ struct semaphore *signalsemaphore; /* semaphore ref */ int options; /* semaphore options */ kern_return_t result; /* primary result */ - void (*continuation)(kern_return_t); - } sema; + mach_msg_continue_t continuation; + } sema; struct { - int option; /* switch option */ - } swtch; - int misc; /* catch-all for other state */ - } saved; - - /* Timing data structures */ - timer_data_t user_timer; /* user mode timer */ - timer_data_t system_timer; /* system mode timer */ - timer_save_data_t user_timer_save; /* saved user timer value */ - timer_save_data_t system_timer_save; /* saved system timer value */ - - /* Timed wait expiration */ - timer_call_data_t wait_timer; - integer_t wait_timer_active; - boolean_t wait_timer_is_set; + int option; /* switch option */ + } swtch; + int misc; /* catch-all for other state */ + } saved; - /* Priority depression expiration */ - timer_call_data_t depress_timer; - integer_t depress_timer_active; + /* IPC data structures */ + struct ipc_kmsg_queue ith_messages; + mach_port_t ith_mig_reply; /* reply port for mig */ + mach_port_t ith_rpc_reply; /* reply port for kernel RPCs */ /* Ast/Halt data structures */ - boolean_t active; /* thread is active */ - - int at_safe_point; /* thread_abort_safely allowed */ + boolean_t active; /* thread is active */ + vm_offset_t recover; /* page fault recover(copyin/out) */ + int ref_count; /* number of references to me */ - /* Processor data structures */ - processor_set_t processor_set; /* assigned processor set */ - processor_t bound_processor; /* bound to processor ?*/ + /* Processor set info */ + queue_chain_t pset_threads; /* list of all shuttles in pset */ #if MACH_HOST - boolean_t may_assign; /* may assignment change? */ - boolean_t assign_active; /* waiting for may_assign */ + boolean_t may_assign; /* may assignment change? */ + boolean_t assign_active; /* waiting for may_assign */ #endif /* MACH_HOST */ - processor_t last_processor; /* processor last ran on */ - - /* Non-reentrancy funnel */ - struct funnel_lock *funnel_lock; - int funnel_state; -#define TH_FN_OWNED 0x1 /* we own the funnel */ -#define TH_FN_REFUNNEL 0x2 /* re-acquire funnel on dispatch */ - /* BEGIN TRACING/DEBUG */ #if MACH_LOCK_MON @@ -363,17 +356,11 @@ struct thread_shuttle { unsigned int mutex_stack_index; unsigned int lock_stack_index; unsigned mutex_count; /* XXX to be deleted XXX */ - boolean_t kthread; /* thread is a kernel thread */ #endif /* MACH_LDEBUG */ - /* END TRACING/DEBUG */ - /* Migration and thread_activation linkage */ - struct thread_activation *top_act; /* "current" thr_act */ }; -#define THREAD_SHUTTLE_NULL ((thread_shuttle_t)0) - #define ith_state saved.receive.state #define ith_object saved.receive.object #define ith_msg saved.receive.msg @@ -404,6 +391,8 @@ extern thread_act_t active_kloaded[NCPUS]; /* "" kernel-loaded acts */ extern vm_offset_t active_stacks[NCPUS]; /* active kernel stacks */ extern vm_offset_t kernel_stack[NCPUS]; +extern struct thread_shuttle pageout_thread; + #ifndef MACHINE_STACK_STASH /* * MD Macro to fill up global stack state, @@ -443,27 +432,9 @@ extern void thread_task_priority( #define thread_start(thread, start) \ (thread)->continuation = (start) - /* Reaps threads waiting to be destroyed */ -extern void thread_reaper(void); - - -#if MACH_HOST -/* Preclude thread processor set assignement */ -extern void thread_freeze( - thread_t thread); - -/* Assign thread to a processor set */ -extern void thread_doassign( - thread_t thread, - processor_set_t new_pset, - boolean_t release_freeze); - -/* Allow thread processor set assignement */ -extern void thread_unfreeze( - thread_t thread); +extern void thread_reaper_init(void); -#endif /* MACH_HOST */ /* Insure thread always has a kernel stack */ extern void stack_privilege( @@ -483,24 +454,19 @@ extern void consider_thread_collect(void); * Macro-defined routines */ -#define thread_pcb(th) ((th)->pcb) +#define thread_pcb(th) ((th)->pcb) -#define thread_lock_init(th) \ - simple_lock_init(&(th)->lock, ETAP_THREAD_LOCK) -#define thread_lock(th) simple_lock(&(th)->lock) -#define thread_unlock(th) simple_unlock(&(th)->lock) +#define thread_lock_init(th) simple_lock_init(&(th)->lock, ETAP_THREAD_LOCK) +#define thread_lock(th) simple_lock(&(th)->lock) +#define thread_unlock(th) simple_unlock(&(th)->lock) +#define thread_lock_try(th) simple_lock_try(&(th)->lock) #define thread_should_halt_fast(thread) \ - (!(thread)->top_act || \ - !(thread)->top_act->active || \ - (thread)->top_act->ast & (AST_HALT|AST_TERMINATE)) + (!(thread)->top_act || !(thread)->top_act->active) #define thread_should_halt(thread) thread_should_halt_fast(thread) -#define rpc_lock_init(th) mutex_init(&(th)->rpc_lock, ETAP_THREAD_RPC) -#define rpc_lock(th) mutex_lock(&(th)->rpc_lock) -#define rpc_lock_try(th) mutex_try(&(th)->rpc_lock) -#define rpc_unlock(th) mutex_unlock(&(th)->rpc_lock) +#define thread_reference_locked(thread) ((thread)->ref_count++) /* * Lock to cover wake_active only; like thread_lock(), is taken @@ -512,6 +478,7 @@ extern void consider_thread_collect(void); simple_lock_init(&(th)->wake_lock, ETAP_THREAD_WAKE) #define wake_lock(th) simple_lock(&(th)->wake_lock) #define wake_unlock(th) simple_unlock(&(th)->wake_lock) +#define wake_lock_try(th) simple_lock_try(&(th)->wake_lock) static __inline__ vm_offset_t current_stack(void); static __inline__ vm_offset_t @@ -525,7 +492,6 @@ current_stack(void) return ret; } - extern void pcb_module_init(void); extern void pcb_init( @@ -563,9 +529,6 @@ extern kern_return_t thread_info_shuttle( thread_info_t thread_info_out, mach_msg_type_number_t *thread_info_count); -extern void thread_user_to_kernel( - thread_t thread); - /* Machine-dependent routines */ extern void thread_machine_init(void); @@ -594,25 +557,38 @@ extern thread_t kernel_thread_with_priority( boolean_t alloc_stack, boolean_t start_running); +extern void thread_terminate_self(void); + extern void funnel_lock(funnel_t *); extern void funnel_unlock(funnel_t *); -#else /* !MACH_KERNEL_PRIVATE */ +#else /* MACH_KERNEL_PRIVATE */ typedef struct funnel_lock funnel_t; extern boolean_t thread_should_halt(thread_t); -#endif /* !MACH_KERNEL_PRIVATE */ - -#define THR_FUNNEL_NULL (funnel_t *)0 +#endif /* MACH_KERNEL_PRIVATE */ extern thread_t kernel_thread( - task_t task, - void (*start)(void)); + task_t task, + void (*start)(void)); -extern void thread_terminate_self(void); +extern void thread_set_cont_arg(int); + +extern int thread_get_cont_arg(void); + +/* JMM - These are only temporary */ +extern boolean_t is_thread_running(thread_act_t); /* True is TH_RUN */ +extern boolean_t is_thread_idle(thread_t); /* True is TH_IDLE */ +extern kern_return_t get_thread_waitresult(thread_t); + +#endif /* __APPLE_API_PRIVATE */ + +#ifdef __APPLE_API_EVOLVING + +#define THR_FUNNEL_NULL (funnel_t *)0 extern funnel_t * funnel_alloc(int); @@ -622,14 +598,6 @@ extern boolean_t thread_funnel_set(funnel_t * fnl, boolean_t funneled); extern boolean_t thread_funnel_merge(funnel_t * fnl, funnel_t * otherfnl); -extern void thread_set_cont_arg(int); - -extern int thread_get_cont_arg(void); - -/* JMM - These are only temporary */ -extern boolean_t is_thread_running(thread_t); /* True is TH_RUN */ -extern boolean_t is_thread_idle(thread_t); /* True is TH_IDLE */ -extern event_t get_thread_waitevent(thread_t); -extern kern_return_t get_thread_waitresult(thread_t); +#endif /* __APPLE_API_EVOLVING */ #endif /* _KERN_THREAD_H_ */ diff --git a/osfmk/kern/thread_act.c b/osfmk/kern/thread_act.c index 4320b05dd..f7e5000ec 100644 --- a/osfmk/kern/thread_act.c +++ b/osfmk/kern/thread_act.c @@ -56,7 +56,6 @@ #include #include #include -#include #include #include #include @@ -85,26 +84,30 @@ unsigned int watchacts = 0 /* WA_ALL */ * Track the number of times we need to swapin a thread to deallocate it. */ int act_free_swapin = 0; +boolean_t first_act; /* * Forward declarations for functions local to this file. */ -kern_return_t act_abort( thread_act_t, int); +kern_return_t act_abort( thread_act_t, boolean_t); void special_handler(ReturnHandler *, thread_act_t); -void nudge(thread_act_t); kern_return_t act_set_state_locked(thread_act_t, int, thread_state_t, mach_msg_type_number_t); kern_return_t act_get_state_locked(thread_act_t, int, thread_state_t, mach_msg_type_number_t *); +void act_set_astbsd(thread_act_t); void act_set_apc(thread_act_t); -void act_clr_apc(thread_act_t); void act_user_to_kernel(thread_act_t); void act_ulock_release_all(thread_act_t thr_act); void install_special_handler_locked(thread_act_t); +static void act_disable(thread_act_t); + +struct thread_activation pageout_act; + static zone_t thr_act_zone; /* @@ -114,79 +117,65 @@ static zone_t thr_act_zone; /* * Internal routine to terminate a thread. - * Called with task locked. + * Sometimes called with task already locked. */ kern_return_t thread_terminate_internal( - register thread_act_t thr_act) + register thread_act_t act) { - thread_t thread; - task_t task; - struct ipc_port *iplock; - kern_return_t ret; + kern_return_t result; + thread_t thread; -#if THREAD_SWAPPER - thread_swap_disable(thr_act); -#endif /* THREAD_SWAPPER */ + thread = act_lock_thread(act); - thread = act_lock_thread(thr_act); - if (!thr_act->active) { - act_unlock_thread(thr_act); - return(KERN_TERMINATED); + if (!act->active) { + act_unlock_thread(act); + return (KERN_TERMINATED); } - act_disable_task_locked(thr_act); - ret = act_abort(thr_act,FALSE); + act_disable(act); + result = act_abort(act, FALSE); -#if NCPUS > 1 /* * Make sure this thread enters the kernel + * Must unlock the act, but leave the shuttle + * captured in this act. */ if (thread != current_thread()) { - thread_hold(thr_act); - act_unlock_thread(thr_act); + act_unlock(act); - if (thread_stop_wait(thread)) + if (thread_stop(thread)) thread_unstop(thread); else - ret = KERN_ABORTED; + result = KERN_ABORTED; - (void)act_lock_thread(thr_act); - thread_release(thr_act); + act_lock(act); } -#endif /* NCPUS > 1 */ - act_unlock_thread(thr_act); - return(ret); + clear_wait(thread, act->inited? THREAD_INTERRUPTED: THREAD_AWAKENED); + act_unlock_thread(act); + + return (result); } /* - * Terminate a thread. Called with nothing locked. - * Returns same way. + * Terminate a thread. */ kern_return_t thread_terminate( - register thread_act_t thr_act) + register thread_act_t act) { - task_t task; - kern_return_t ret; + kern_return_t result; - if (thr_act == THR_ACT_NULL) - return KERN_INVALID_ARGUMENT; + if (act == THR_ACT_NULL) + return (KERN_INVALID_ARGUMENT); - task = thr_act->task; - if (((task == kernel_task) || (thr_act->kernel_loaded == TRUE)) - && (current_act() != thr_act)) { - return(KERN_FAILURE); - } + if ( (act->task == kernel_task || + act->kernel_loaded ) && + act != current_act() ) + return (KERN_FAILURE); - /* - * Take the task lock and then call the internal routine - * that terminates a thread (it needs the task locked). - */ - task_lock(task); - ret = thread_terminate_internal(thr_act); - task_unlock(task); + result = thread_terminate_internal(act); /* * If a kernel thread is terminating itself, force an AST here. @@ -194,33 +183,35 @@ thread_terminate( * code - and all threads finish their own termination in the * special handler APC. */ - if ( ( thr_act->task == kernel_task || - thr_act->kernel_loaded == TRUE ) && - current_act() == thr_act ) { + if ( act->task == kernel_task || + act->kernel_loaded ) { + assert(act == current_act()); ast_taken(AST_APC, FALSE); - panic("thread_terminate(): returning from ast_taken() for %x kernel activation\n", thr_act); - } + panic("thread_terminate"); + } - return ret; + return (result); } /* - * thread_hold: - * - * Suspend execution of the specified thread. - * This is a recursive-style suspension of the thread, a count of - * suspends is maintained. + * Suspend execution of the specified thread. + * This is a recursive-style suspension of the thread, a count of + * suspends is maintained. * - * Called with thr_act locked "appropriately" for synchrony with - * RPC (see act_lock_thread()). Returns same way. + * Called with act_lock held. */ void thread_hold( - register thread_act_t thr_act) + register thread_act_t act) { - if (thr_act->suspend_count++ == 0) { - install_special_handler(thr_act); - nudge(thr_act); + thread_t thread = act->thread; + + if (act->suspend_count++ == 0) { + install_special_handler(act); + if ( act->inited && + thread != THREAD_NULL && + thread->top_act == act ) + thread_wakeup_one(&act->suspend_count); } } @@ -228,84 +219,99 @@ thread_hold( * Decrement internal suspension count for thr_act, setting thread * runnable when count falls to zero. * - * Called with thr_act locked "appropriately" for synchrony - * with RPC (see act_lock_thread()). + * Called with act_lock held. */ void thread_release( - register thread_act_t thr_act) + register thread_act_t act) { - if( thr_act->suspend_count && - (--thr_act->suspend_count == 0) ) - nudge( thr_act ); + thread_t thread = act->thread; + + if ( act->suspend_count > 0 && + --act->suspend_count == 0 && + thread != THREAD_NULL && + thread->top_act == act ) { + if (!act->inited) { + clear_wait(thread, THREAD_AWAKENED); + act->inited = TRUE; + } + else + thread_wakeup_one(&act->suspend_count); + } } kern_return_t thread_suspend( - register thread_act_t thr_act) + register thread_act_t act) { - thread_t thread; + thread_t thread; - if (thr_act == THR_ACT_NULL) { - return(KERN_INVALID_ARGUMENT); - } - thread = act_lock_thread(thr_act); - if (!thr_act->active) { - act_unlock_thread(thr_act); - return(KERN_TERMINATED); + if (act == THR_ACT_NULL) + return (KERN_INVALID_ARGUMENT); + + thread = act_lock_thread(act); + + if (!act->active) { + act_unlock_thread(act); + return (KERN_TERMINATED); } - if (thr_act->user_stop_count++ == 0 && - thr_act->suspend_count++ == 0 ) { - install_special_handler(thr_act); - if (thread && - thr_act == thread->top_act && thread != current_thread()) { - nudge(thr_act); - act_unlock_thread(thr_act); - (void)thread_wait(thread); - } - else { - /* - * No need to wait for target thread - */ - act_unlock_thread(thr_act); + + if ( act->user_stop_count++ == 0 && + act->suspend_count++ == 0 ) { + install_special_handler(act); + if ( thread != current_thread() && + thread != THREAD_NULL && + thread->top_act == act ) { + assert(act->inited); + thread_wakeup_one(&act->suspend_count); + act_unlock_thread(act); + + thread_wait(thread); } + else + act_unlock_thread(act); } - else { - /* - * Thread is already suspended - */ - act_unlock_thread(thr_act); - } - return(KERN_SUCCESS); + else + act_unlock_thread(act); + + return (KERN_SUCCESS); } kern_return_t thread_resume( - register thread_act_t thr_act) + register thread_act_t act) { - register kern_return_t ret; - spl_t s; + kern_return_t result = KERN_SUCCESS; thread_t thread; - if (thr_act == THR_ACT_NULL) - return(KERN_INVALID_ARGUMENT); - thread = act_lock_thread(thr_act); - ret = KERN_SUCCESS; + if (act == THR_ACT_NULL) + return (KERN_INVALID_ARGUMENT); - if (thr_act->active) { - if (thr_act->user_stop_count > 0) { - if( --thr_act->user_stop_count == 0 ) { - --thr_act->suspend_count; - nudge( thr_act ); + thread = act_lock_thread(act); + + if (act->active) { + if (act->user_stop_count > 0) { + if ( --act->user_stop_count == 0 && + --act->suspend_count == 0 && + thread != THREAD_NULL && + thread->top_act == act ) { + if (!act->inited) { + clear_wait(thread, THREAD_AWAKENED); + act->inited = TRUE; + } + else + thread_wakeup_one(&act->suspend_count); } } else - ret = KERN_FAILURE; + result = KERN_FAILURE; } else - ret = KERN_TERMINATED; - act_unlock_thread( thr_act ); - return ret; + result = KERN_TERMINATED; + + act_unlock_thread(act); + + return (result); } /* @@ -317,24 +323,10 @@ thread_resume( */ kern_return_t post_alert( - register thread_act_t thr_act, - unsigned alert_bits ) + register thread_act_t act, + unsigned alert_bits) { - thread_act_t next; - thread_t thread; - - /* - * Chase the chain, setting alert bits and installing - * special handlers for each thread act. - */ - /*** Not yet SMP safe ***/ - /*** Worse, where's the activation locking as the chain is walked? ***/ - for (next = thr_act; next != THR_ACT_NULL; next = next->higher) { - next->alerts |= alert_bits; - install_special_handler_locked(next); - } - - return(KERN_SUCCESS); + panic("post_alert"); } /* @@ -369,196 +361,91 @@ thread_depress_abort( /* - * Already locked: all RPC-related locks for thr_act (see - * act_lock_thread()). + * Indicate that the activation should run its + * special handler to detect the condition. + * + * Called with act_lock held. */ kern_return_t -act_abort( thread_act_t thr_act, int chain_break ) +act_abort( + thread_act_t act, + boolean_t chain_break ) { - spl_t spl; - thread_t thread; - struct ipc_port *iplock = thr_act->pool_port; - thread_act_t orphan; - kern_return_t kr; - etap_data_t probe_data; - - ETAP_DATA_LOAD(probe_data[0], thr_act); - ETAP_DATA_LOAD(probe_data[1], thr_act->thread); - ETAP_PROBE_DATA(ETAP_P_ACT_ABORT, - 0, - current_thread(), - &probe_data, - ETAP_DATA_ENTRY*2); + thread_t thread = act->thread; + spl_t s = splsched(); - /* - * If the target thread activation is not the head... - */ - if ( thr_act->thread->top_act != thr_act ) { - /* - * mark the activation for abort, - * update the suspend count, - * always install the special handler - */ - install_special_handler(thr_act); + assert(thread->top_act == act); -#ifdef AGRESSIVE_ABORT - /* release state buffer for target's outstanding invocation */ - if (unwind_invoke_state(thr_act) != KERN_SUCCESS) { - panic("unwind_invoke_state failure"); - } - - /* release state buffer for target's incoming invocation */ - if (thr_act->lower != THR_ACT_NULL) { - if (unwind_invoke_state(thr_act->lower) - != KERN_SUCCESS) { - panic("unwind_invoke_state failure"); - } - } - - /* unlink target thread activation from shuttle chain */ - if ( thr_act->lower == THR_ACT_NULL ) { - /* - * This is the root thread activation of the chain. - * Unlink the root thread act from the bottom of - * the chain. - */ - thr_act->higher->lower = THR_ACT_NULL; - } else { - /* - * This thread act is in the middle of the chain. - * Unlink the thread act from the middle of the chain. - */ - thr_act->higher->lower = thr_act->lower; - thr_act->lower->higher = thr_act->higher; - - /* set the terminated bit for RPC return processing */ - thr_act->lower->alerts |= SERVER_TERMINATED; - } - - orphan = thr_act->higher; - - /* remove the activation from its thread pool */ - /* (note: this is okay for "rooted threads," too) */ - act_locked_act_set_thread_pool(thr_act, IP_NULL); - - /* (just to be thorough) release the IP lock */ - if (iplock != IP_NULL) ip_unlock(iplock); - - /* release one more reference for a rooted thread */ - if (iplock == IP_NULL) act_locked_act_deallocate(thr_act); - - /* Presumably, the only reference to this activation is - * now held by the caller of this routine. */ - assert(thr_act->ref_count == 1); -#else /*AGRESSIVE_ABORT*/ - /* If there is a lower activation in the RPC chain... */ - if (thr_act->lower != THR_ACT_NULL) { - /* ...indicate the server activation was terminated */ - thr_act->lower->alerts |= SERVER_TERMINATED; - } - /* Mark (and process) any orphaned activations */ - orphan = thr_act->higher; -#endif /*AGRESSIVE_ABORT*/ - - /* indicate client of orphaned chain has been terminated */ - orphan->alerts |= CLIENT_TERMINATED; - - /* - * Set up posting of alert to headward portion of - * the RPC chain. - */ - /*** fix me -- orphan act is not locked ***/ - post_alert(orphan, ORPHANED); - - /* - * Get attention of head of RPC chain. - */ - nudge(thr_act->thread->top_act); - return (KERN_SUCCESS); + thread_lock(thread); + if (!(thread->state & TH_ABORT)) { + thread->state |= TH_ABORT; + install_special_handler_locked(act); + } else { + thread->state &= ~TH_ABORT_SAFELY; } + thread_unlock(thread); + splx(s); - /* - * If the target thread is the end of the chain, the thread - * has to be marked for abort and rip it out of any wait. - */ - spl = splsched(); - thread_lock(thr_act->thread); - if (thr_act->thread->top_act == thr_act) { - thr_act->thread->state |= TH_ABORT; - clear_wait_internal(thr_act->thread, THREAD_INTERRUPTED); - thread_unlock(thr_act->thread); - splx(spl); - install_special_handler(thr_act); - nudge( thr_act ); - } - return KERN_SUCCESS; + return (KERN_SUCCESS); } kern_return_t thread_abort( - register thread_act_t thr_act) + register thread_act_t act) { - int ret; + kern_return_t result; thread_t thread; - if (thr_act == THR_ACT_NULL || thr_act == current_act()) + if (act == THR_ACT_NULL) return (KERN_INVALID_ARGUMENT); - /* - * Lock the target thread and the current thread now, - * in case thread_halt() ends up being called below. - */ - thread = act_lock_thread(thr_act); - if (!thr_act->active) { - act_unlock_thread(thr_act); - return(KERN_TERMINATED); + + thread = act_lock_thread(act); + + if (!act->active) { + act_unlock_thread(act); + return (KERN_TERMINATED); } - ret = act_abort( thr_act, FALSE ); - act_unlock_thread( thr_act ); - return ret; + result = act_abort(act, FALSE); + clear_wait(thread, THREAD_INTERRUPTED); + act_unlock_thread(act); + + return (result); } kern_return_t thread_abort_safely( - register thread_act_t thr_act) + thread_act_t act) { thread_t thread; + kern_return_t ret; spl_t s; - if (thr_act == THR_ACT_NULL || thr_act == current_act()) - return(KERN_INVALID_ARGUMENT); + if ( act == THR_ACT_NULL ) + return (KERN_INVALID_ARGUMENT); - thread = act_lock_thread(thr_act); - if (!thr_act->active) { - act_unlock_thread(thr_act); - return(KERN_TERMINATED); - } - if (thread->top_act != thr_act) { - act_unlock_thread(thr_act); - return(KERN_FAILURE); + thread = act_lock_thread(act); + + if (!act->active) { + act_unlock_thread(act); + return (KERN_TERMINATED); } + s = splsched(); thread_lock(thread); - - if ( thread->at_safe_point ) { - /* - * It's an abortable wait, clear it, then - * let the thread go and return successfully. - */ - clear_wait_internal(thread, THREAD_INTERRUPTED); - thread_unlock(thread); - act_unlock_thread(thr_act); - splx(s); - return KERN_SUCCESS; + if (!thread->at_safe_point || + clear_wait_internal(thread, THREAD_INTERRUPTED) != KERN_SUCCESS) { + if (!(thread->state & TH_ABORT)) { + thread->state |= (TH_ABORT|TH_ABORT_SAFELY); + install_special_handler_locked(act); + } } - - /* - * if not stopped at a safepoint, just let it go and return failure. - */ thread_unlock(thread); - act_unlock_thread(thr_act); splx(s); - return KERN_FAILURE; + + act_unlock_thread(act); + + return (KERN_SUCCESS); } /*** backward compatibility hacks ***/ @@ -717,43 +604,60 @@ thread_set_special_port( */ kern_return_t thread_get_state( - register thread_act_t thr_act, - int flavor, - thread_state_t state, /* pointer to OUT array */ + register thread_act_t act, + int flavor, + thread_state_t state, /* pointer to OUT array */ mach_msg_type_number_t *state_count) /*IN/OUT*/ { - kern_return_t ret; - thread_t thread, nthread; + kern_return_t result = KERN_SUCCESS; + thread_t thread; - if (thr_act == THR_ACT_NULL || thr_act == current_act()) + if (act == THR_ACT_NULL || act == current_act()) return (KERN_INVALID_ARGUMENT); - thread = act_lock_thread(thr_act); - if (!thr_act->active) { - act_unlock_thread(thr_act); - return(KERN_TERMINATED); + thread = act_lock_thread(act); + + if (!act->active) { + act_unlock_thread(act); + return (KERN_TERMINATED); } - thread_hold(thr_act); - while (1) { - if (!thread || thr_act != thread->top_act) + thread_hold(act); + + for (;;) { + thread_t thread1; + + if ( thread == THREAD_NULL || + thread->top_act != act ) break; - act_unlock_thread(thr_act); - (void)thread_stop_wait(thread); - nthread = act_lock_thread(thr_act); - if (nthread == thread) + act_unlock_thread(act); + + if (!thread_stop(thread)) { + result = KERN_ABORTED; + (void)act_lock_thread(act); + thread = THREAD_NULL; + break; + } + + thread1 = act_lock_thread(act); + if (thread1 == thread) break; + thread_unstop(thread); - thread = nthread; + thread = thread1; } - ret = act_machine_get_state(thr_act, flavor, - state, state_count); - if (thread && thr_act == thread->top_act) - thread_unstop(thread); - thread_release(thr_act); - act_unlock_thread(thr_act); - return(ret); + if (result == KERN_SUCCESS) + result = act_machine_get_state(act, flavor, state, state_count); + + if ( thread != THREAD_NULL && + thread->top_act == act ) + thread_unstop(thread); + + thread_release(act); + act_unlock_thread(act); + + return (result); } /* @@ -762,49 +666,60 @@ thread_get_state( */ kern_return_t thread_set_state( - register thread_act_t thr_act, - int flavor, - thread_state_t state, + register thread_act_t act, + int flavor, + thread_state_t state, mach_msg_type_number_t state_count) { - kern_return_t ret; - thread_t thread, nthread; + kern_return_t result = KERN_SUCCESS; + thread_t thread; - if (thr_act == THR_ACT_NULL || thr_act == current_act()) + if (act == THR_ACT_NULL || act == current_act()) return (KERN_INVALID_ARGUMENT); - /* - * We have no kernel activations, so Utah's MO fails for signals etc. - * - * If we're blocked in the kernel, use non-blocking method, else - * pass locked thr_act+thread in to "normal" act_[gs]et_state(). - */ - thread = act_lock_thread(thr_act); - if (!thr_act->active) { - act_unlock_thread(thr_act); - return(KERN_TERMINATED); + thread = act_lock_thread(act); + + if (!act->active) { + act_unlock_thread(act); + return (KERN_TERMINATED); } - thread_hold(thr_act); - while (1) { - if (!thread || thr_act != thread->top_act) + thread_hold(act); + + for (;;) { + thread_t thread1; + + if ( thread == THREAD_NULL || + thread->top_act != act ) break; - act_unlock_thread(thr_act); - (void)thread_stop_wait(thread); - nthread = act_lock_thread(thr_act); - if (nthread == thread) + act_unlock_thread(act); + + if (!thread_stop(thread)) { + result = KERN_ABORTED; + (void)act_lock_thread(act); + thread = THREAD_NULL; break; + } + + thread1 = act_lock_thread(act); + if (thread1 == thread) + break; + thread_unstop(thread); - thread = nthread; + thread = thread1; } - ret = act_machine_set_state(thr_act, flavor, - state, state_count); - if (thread && thr_act == thread->top_act) + + if (result == KERN_SUCCESS) + result = act_machine_set_state(act, flavor, state, state_count); + + if ( thread != THREAD_NULL && + thread->top_act == act ) thread_unstop(thread); - thread_release(thr_act); - act_unlock_thread(thr_act); - return(ret); + thread_release(act); + act_unlock_thread(act); + + return (result); } /* @@ -813,40 +728,58 @@ thread_set_state( kern_return_t thread_dup( - thread_act_t source_thr_act, - thread_act_t target_thr_act) + register thread_act_t target) { - kern_return_t ret; - thread_t thread, nthread; + kern_return_t result = KERN_SUCCESS; + thread_act_t self = current_act(); + thread_t thread; - if (target_thr_act == THR_ACT_NULL || target_thr_act == current_act()) + if (target == THR_ACT_NULL || target == self) return (KERN_INVALID_ARGUMENT); - thread = act_lock_thread(target_thr_act); - if (!target_thr_act->active) { - act_unlock_thread(target_thr_act); - return(KERN_TERMINATED); + thread = act_lock_thread(target); + + if (!target->active) { + act_unlock_thread(target); + return (KERN_TERMINATED); } - thread_hold(target_thr_act); - while (1) { - if (!thread || target_thr_act != thread->top_act) + thread_hold(target); + + for (;;) { + thread_t thread1; + + if ( thread == THREAD_NULL || + thread->top_act != target ) + break; + act_unlock_thread(target); + + if (!thread_stop(thread)) { + result = KERN_ABORTED; + (void)act_lock_thread(target); + thread = THREAD_NULL; break; - act_unlock_thread(target_thr_act); - (void)thread_stop_wait(thread); - nthread = act_lock_thread(target_thr_act); - if (nthread == thread) + } + + thread1 = act_lock_thread(target); + if (thread1 == thread) break; + thread_unstop(thread); - thread = nthread; + thread = thread1; } - ret = act_thread_dup(source_thr_act, target_thr_act); - if (thread && target_thr_act == thread->top_act) + + if (result == KERN_SUCCESS) + result = act_thread_dup(self, target); + + if ( thread != THREAD_NULL && + thread->top_act == target ) thread_unstop(thread); - thread_release(target_thr_act); - act_unlock_thread(target_thr_act); - return(ret); + thread_release(target); + act_unlock_thread(target); + + return (result); } @@ -858,20 +791,29 @@ thread_dup( */ kern_return_t thread_setstatus( - thread_act_t thr_act, - int flavor, - thread_state_t tstate, + register thread_act_t act, + int flavor, + thread_state_t tstate, mach_msg_type_number_t count) { - kern_return_t kr; - thread_t thread; + kern_return_t result = KERN_SUCCESS; + thread_t thread; - thread = act_lock_thread(thr_act); - assert(thread); - assert(thread->top_act == thr_act); - kr = act_machine_set_state(thr_act, flavor, tstate, count); - act_unlock_thread(thr_act); - return(kr); + thread = act_lock_thread(act); + + if ( act != current_act() && + (act->suspend_count == 0 || + thread == THREAD_NULL || + (thread->state & TH_RUN) || + thread->top_act != act) ) + result = KERN_FAILURE; + + if (result == KERN_SUCCESS) + result = act_machine_set_state(act, flavor, tstate, count); + + act_unlock_thread(act); + + return (result); } /* @@ -881,20 +823,29 @@ thread_setstatus( */ kern_return_t thread_getstatus( - thread_act_t thr_act, - int flavor, - thread_state_t tstate, + register thread_act_t act, + int flavor, + thread_state_t tstate, mach_msg_type_number_t *count) { - kern_return_t kr; - thread_t thread; + kern_return_t result = KERN_SUCCESS; + thread_t thread; - thread = act_lock_thread(thr_act); - assert(thread); - assert(thread->top_act == thr_act); - kr = act_machine_get_state(thr_act, flavor, tstate, count); - act_unlock_thread(thr_act); - return(kr); + thread = act_lock_thread(act); + + if ( act != current_act() && + (act->suspend_count == 0 || + thread == THREAD_NULL || + (thread->state & TH_RUN) || + thread->top_act != act) ) + result = KERN_FAILURE; + + if (result == KERN_SUCCESS) + result = act_machine_get_state(act, flavor, tstate, count); + + act_unlock_thread(act); + + return (result); } /* @@ -912,6 +863,7 @@ act_init() ACT_MAX * sizeof(struct thread_activation), /* XXX */ ACT_CHUNK * sizeof(struct thread_activation), "activations"); + first_act = TRUE; act_machine_init(); } @@ -927,7 +879,11 @@ act_create(task_t task, int rc; vm_map_t map; - thr_act = (thread_act_t)zalloc(thr_act_zone); + if (first_act) { + thr_act = &pageout_act; + first_act = FALSE; + } else + thr_act = (thread_act_t)zalloc(thr_act_zone); if (thr_act == 0) return(KERN_RESOURCE_SHORTAGE); @@ -940,6 +896,9 @@ act_create(task_t task, /* Start by zeroing everything; then init non-zero items only */ bzero((char *)thr_act, sizeof(*thr_act)); + if (thr_act == &pageout_act) + thr_act->thread = &pageout_thread; + #ifdef MACH_BSD { /* @@ -948,8 +907,9 @@ act_create(task_t task, * handling trivial * uthread_alloc() will bzero the storage allocated. */ - extern void *uthread_alloc(void); - thr_act->uthread = uthread_alloc(); + extern void *uthread_alloc(task_t, thread_act_t); + + thr_act->uthread = uthread_alloc(task, thr_act); if(thr_act->uthread == 0) { /* Put the thr_act back on the thr_act zone */ zfree(thr_act_zone, (vm_offset_t)thr_act); @@ -969,17 +929,6 @@ act_create(task_t task, thr_act->task = task; task_reference(task); - /* Initialize sigbufp for High-Watermark buffer allocation */ - thr_act->r_sigbufp = (routine_descriptor_t) &thr_act->r_sigbuf; - thr_act->r_sigbuf_size = sizeof(thr_act->r_sigbuf); - -#if THREAD_SWAPPER - thr_act->swap_state = TH_SW_IN; -#if MACH_ASSERT - thr_act->kernel_stack_swapped_in = TRUE; -#endif /* MACH_ASSERT */ -#endif /* THREAD_SWAPPER */ - /* special_handler will always be last on the returnhandlers list. */ thr_act->special_handler.next = 0; thr_act->special_handler.handler = special_handler; @@ -1013,10 +962,6 @@ act_create(task_t task, /* Inline vm_map_reference cause we don't want to increment res_count */ mutex_lock(&map->s_lock); -#if TASK_SWAPPER - assert(map->res_count > 0); - assert(map->ref_count >= map->res_count); -#endif /* TASK_SWAPPER */ map->ref_count++; mutex_unlock(&map->s_lock); @@ -1045,28 +990,23 @@ act_free(thread_act_t thr_act) thread_t thr; vm_map_t map; unsigned int ref; + void * task_proc; #if MACH_ASSERT if (watchacts & WA_EXIT) - printf("act_free(%x(%d)) thr=%x tsk=%x(%d) pport=%x%sactive\n", + printf("act_free(%x(%d)) thr=%x tsk=%x(%d) %sactive\n", thr_act, thr_act->ref_count, thr_act->thread, thr_act->task, thr_act->task ? thr_act->task->ref_count : 0, - thr_act->pool_port, thr_act->active ? " " : " !"); #endif /* MACH_ASSERT */ - -#if THREAD_SWAPPER - assert(thr_act->kernel_stack_swapped_in); -#endif /* THREAD_SWAPPER */ - assert(!thr_act->active); - assert(!thr_act->pool_port); task = thr_act->task; task_lock(task); + task_proc = task->bsd_info; if (thr = thr_act->thread) { time_value_t user_time, system_time; @@ -1081,15 +1021,6 @@ act_free(thread_act_t thr_act) queue_remove(&task->thr_acts, thr_act, thread_act_t, thr_acts); thr_act->thr_acts.next = NULL; task->thr_act_count--; - -#if THREAD_SWAPPER - /* - * Thread is supposed to be unswappable by now... - */ - assert(thr_act->swap_state == TH_SW_UNSWAPPABLE || - !thread_swap_unwire_stack); -#endif /* THREAD_SWAPPER */ - task->res_act_count--; task_unlock(task); task_deallocate(task); @@ -1105,7 +1036,6 @@ act_free(thread_act_t thr_act) task_deallocate(task); } - sigbuf_dealloc(thr_act); act_prof_deallocate(thr_act); ipc_thr_act_terminate(thr_act); @@ -1116,10 +1046,6 @@ act_free(thread_act_t thr_act) */ map = thr_act->map; mutex_lock(&map->s_lock); -#if TASK_SWAPPER - assert(map->res_count >= 0); - assert(map->ref_count > map->res_count); -#endif /* TASK_SWAPPER */ ref = --map->ref_count; mutex_unlock(&map->s_lock); if (ref == 0) @@ -1131,10 +1057,11 @@ act_free(thread_act_t thr_act) * Free uthread BEFORE the bzero. * Not doing so will result in a leak. */ - extern void uthread_free(void *); + extern void uthread_free(task_t, void *, void *); + void *ut = thr_act->uthread; thr_act->uthread = 0; - uthread_free(ut); + uthread_free(task, ut, task_proc); } #endif /* MACH_BSD */ @@ -1151,9 +1078,7 @@ act_free(thread_act_t thr_act) * act_attach - Attach an thr_act to the top of a thread ("push the stack"). * * The thread_shuttle must be either the current one or a brand-new one. - * Assumes the thr_act is active but not in use, also, that if it is - * attached to an thread_pool (i.e. the thread_pool pointer is nonzero), - * the thr_act has already been taken off the thread_pool's list. + * Assumes the thr_act is active but not in use. * * Already locked: thr_act plus "appropriate" thread-related locks * (see act_lock_thread()). @@ -1221,8 +1146,6 @@ act_detach( cur_act->ref_count--; assert(cur_act->ref_count > 0); - thread_pool_put_act(cur_act); - #if MACH_ASSERT cur_act->lower = cur_act->higher = THR_ACT_NULL; if (cur_thread->top_act) @@ -1234,65 +1157,39 @@ act_detach( /* - * Synchronize a thread operation with RPC. Called with nothing - * locked. Returns with thr_act locked, plus one of four - * combinations of other locks held: - * none - for new activation not yet associated with thread_pool - * or shuttle - * rpc_lock(thr_act->thread) only - for base activation (one - * without pool_port) - * ip_lock(thr_act->pool_port) only - for empty activation (one - * with no associated shuttle) - * both locks - for "active" activation (has shuttle, lives - * on thread_pool) - * If thr_act has an associated shuttle, this function returns - * its address. Otherwise it returns zero. + * Synchronize a thread operation with migration. + * Called with nothing locked. + * Returns with thr_act locked. */ thread_t act_lock_thread( thread_act_t thr_act) { - ipc_port_t pport; /* - * Allow the shuttle cloning code (q.v., when it - * exists :-}) to obtain ip_lock()'s while holding - * an rpc_lock(). + * JMM - We have moved away from explicit RPC locks + * and towards a generic migration approach. The wait + * queue lock will be the point of synchronization for + * the shuttle linkage when this is rolled out. Until + * then, just lock the act. */ - while (1) { - act_lock(thr_act); - pport = thr_act->pool_port; - if (!pport || ip_lock_try(pport)) { - if (!thr_act->thread) - break; - if (rpc_lock_try(thr_act->thread)) - break; - if (pport) - ip_unlock(pport); - } - act_unlock(thr_act); - mutex_pause(); - } + act_lock(thr_act); return (thr_act->thread); } /* - * Unsynchronize with RPC (i.e., undo an act_lock_thread() call). + * Unsynchronize with migration (i.e., undo an act_lock_thread() call). * Called with thr_act locked, plus thread locks held that are * "correct" for thr_act's state. Returns with nothing locked. */ void act_unlock_thread(thread_act_t thr_act) { - if (thr_act->thread) - rpc_unlock(thr_act->thread); - if (thr_act->pool_port) - ip_unlock(thr_act->pool_port); act_unlock(thr_act); } /* - * Synchronize with RPC given a pointer to a shuttle (instead of an + * Synchronize with migration given a pointer to a shuttle (instead of an * activation). Called with nothing locked; returns with all * "appropriate" thread-related locks held (see act_lock_thread()). */ @@ -1303,19 +1200,10 @@ thread_lock_act( thread_act_t thr_act; while (1) { - rpc_lock(thread); thr_act = thread->top_act; if (!thr_act) break; if (!act_lock_try(thr_act)) { - rpc_unlock(thread); - mutex_pause(); - continue; - } - if (thr_act->pool_port && - !ip_lock_try(thr_act->pool_port)) { - rpc_unlock(thread); - act_unlock(thr_act); mutex_pause(); continue; } @@ -1325,9 +1213,8 @@ thread_lock_act( } /* - * Unsynchronize with RPC starting from a pointer to a shuttle. - * Called with RPC-related locks held that are appropriate to - * shuttle's state; any activation is also locked. + * Unsynchronize with an activation starting from a pointer to + * a shuttle. */ void thread_unlock_act( @@ -1336,11 +1223,8 @@ thread_unlock_act( thread_act_t thr_act; if (thr_act = thread->top_act) { - if (thr_act->pool_port) - ip_unlock(thr_act->pool_port); act_unlock(thr_act); } - rpc_unlock(thread); } /* @@ -1348,7 +1232,7 @@ thread_unlock_act( * * If a new activation is given, switch to it. If not, * switch to the lower activation (pop). Returns the old - * activation. This is for RPC support. + * activation. This is for migration support. */ thread_act_t switch_act( @@ -1379,12 +1263,7 @@ switch_act( } assert(new != THR_ACT_NULL); -#if THREAD_SWAPPER - assert(new->swap_state != TH_SW_OUT && - new->swap_state != TH_SW_COMING_IN); -#endif /* THREAD_SWAPPER */ - - assert(cpu_data[cpu].active_thread == thread); + assert(cpu_to_processor(cpu)->cpu_data->active_thread == thread); active_kloaded[cpu] = (new->kernel_loaded) ? new : 0; /* This is where all the work happens */ @@ -1441,221 +1320,61 @@ install_special_handler( */ void install_special_handler_locked( - thread_act_t thr_act) + thread_act_t act) { + thread_t thread = act->thread; ReturnHandler **rh; - thread_t thread = thr_act->thread; /* The work handler must always be the last ReturnHandler on the list, because it can do tricky things like detach the thr_act. */ - for (rh = &thr_act->handlers; *rh; rh = &(*rh)->next) - /* */ ; - if (rh != &thr_act->special_handler.next) { - *rh = &thr_act->special_handler; - } - if (thread && thr_act == thread->top_act) { + for (rh = &act->handlers; *rh; rh = &(*rh)->next) + continue; + if (rh != &act->special_handler.next) + *rh = &act->special_handler; + + if (act == thread->top_act) { /* * Temporarily undepress, so target has * a chance to do locking required to * block itself in special_handler(). */ - if (thread->depress_priority >= 0) { - thread->priority = thread->depress_priority; - - /* - * Use special value -2 to indicate need - * to redepress priority in special_handler - * as thread blocks - */ - thread->depress_priority = -2; - compute_priority(thread, FALSE); - } + if (thread->sched_mode & TH_MODE_ISDEPRESSED) + compute_priority(thread, TRUE); } - act_set_apc(thr_act); -} -/* - * JMM - - * These two routines will be enhanced over time to call the general handler registration - * mechanism used by special handlers and alerts. They are hack in for now to avoid - * having to export the gory details of ASTs to the BSD code right now. - */ -extern thread_apc_handler_t bsd_ast; + thread_ast_set(act, AST_APC); + if (act == current_act()) + ast_propagate(act->ast); + else { + processor_t processor = thread->last_processor; + + if ( processor != PROCESSOR_NULL && + processor->state == PROCESSOR_RUNNING && + processor->cpu_data->active_thread == thread ) + cause_ast_check(processor); + } +} kern_return_t thread_apc_set( - thread_act_t thr_act, - thread_apc_handler_t apc) + thread_act_t act, + thread_apc_handler_t apc) { + extern thread_apc_handler_t bsd_ast; + assert(apc == bsd_ast); - thread_ast_set(thr_act, AST_BSD); - if (thr_act == current_act()) - ast_propagate(thr_act->ast); - return KERN_SUCCESS; + return (KERN_FAILURE); } kern_return_t thread_apc_clear( - thread_act_t thr_act, - thread_apc_handler_t apc) -{ - assert(apc == bsd_ast); - thread_ast_clear(thr_act, AST_BSD); - if (thr_act == current_act()) - ast_off(AST_BSD); - return KERN_SUCCESS; -} - -/* - * act_set_thread_pool - Assign an activation to a specific thread_pool. - * Fails if the activation is already assigned to another pool. - * If thread_pool == 0, we remove the thr_act from its thread_pool. - * - * Called the port containing thread_pool already locked. - * Returns the same way. - */ -kern_return_t act_set_thread_pool( - thread_act_t thr_act, - ipc_port_t pool_port) + thread_act_t act, + thread_apc_handler_t apc) { - thread_pool_t thread_pool; - -#if MACH_ASSERT - if (watchacts & WA_ACT_LNK) - printf("act_set_thread_pool: %x(%d) -> %x\n", - thr_act, thr_act->ref_count, thread_pool); -#endif /* MACH_ASSERT */ - - if (pool_port == 0) { - thread_act_t *lact; - - if (thr_act->pool_port == 0) - return KERN_SUCCESS; - thread_pool = &thr_act->pool_port->ip_thread_pool; - - for (lact = &thread_pool->thr_acts; *lact; - lact = &((*lact)->thread_pool_next)) { - if (thr_act == *lact) { - *lact = thr_act->thread_pool_next; - break; - } - } - act_lock(thr_act); - thr_act->pool_port = 0; - thr_act->thread_pool_next = 0; - act_unlock(thr_act); - act_deallocate(thr_act); - return KERN_SUCCESS; - } - if (thr_act->pool_port != pool_port) { - thread_pool = &pool_port->ip_thread_pool; - if (thr_act->pool_port != 0) { -#if MACH_ASSERT - if (watchacts & WA_ACT_LNK) - printf("act_set_thread_pool found %x!\n", - thr_act->pool_port); -#endif /* MACH_ASSERT */ - return(KERN_FAILURE); - } - act_lock(thr_act); - thr_act->pool_port = pool_port; - - /* The pool gets a ref to the activation -- have - * to inline operation because thr_act is already - * locked. - */ - act_locked_act_reference(thr_act); - - /* If it is available, - * add it to the thread_pool's available-activation list. - */ - if ((thr_act->thread == 0) && (thr_act->suspend_count == 0)) { - thr_act->thread_pool_next = thread_pool->thr_acts; - pool_port->ip_thread_pool.thr_acts = thr_act; - if (thread_pool->waiting) - thread_pool_wakeup(thread_pool); - } - act_unlock(thr_act); - } - - return KERN_SUCCESS; -} - -/* - * act_locked_act_set_thread_pool- Assign activation to a specific thread_pool. - * Fails if the activation is already assigned to another pool. - * If thread_pool == 0, we remove the thr_act from its thread_pool. - * - * Called the port containing thread_pool already locked. - * Also called with the thread activation locked. - * Returns the same way. - * - * This routine is the same as `act_set_thread_pool()' except that it does - * not call `act_deallocate(),' which unconditionally tries to obtain the - * thread activation lock. - */ -kern_return_t act_locked_act_set_thread_pool( - thread_act_t thr_act, - ipc_port_t pool_port) -{ - thread_pool_t thread_pool; - -#if MACH_ASSERT - if (watchacts & WA_ACT_LNK) - printf("act_set_thread_pool: %x(%d) -> %x\n", - thr_act, thr_act->ref_count, thread_pool); -#endif /* MACH_ASSERT */ - - if (pool_port == 0) { - thread_act_t *lact; - - if (thr_act->pool_port == 0) - return KERN_SUCCESS; - thread_pool = &thr_act->pool_port->ip_thread_pool; - - for (lact = &thread_pool->thr_acts; *lact; - lact = &((*lact)->thread_pool_next)) { - if (thr_act == *lact) { - *lact = thr_act->thread_pool_next; - break; - } - } - - thr_act->pool_port = 0; - thr_act->thread_pool_next = 0; - act_locked_act_deallocate(thr_act); - return KERN_SUCCESS; - } - if (thr_act->pool_port != pool_port) { - thread_pool = &pool_port->ip_thread_pool; - if (thr_act->pool_port != 0) { -#if MACH_ASSERT - if (watchacts & WA_ACT_LNK) - printf("act_set_thread_pool found %x!\n", - thr_act->pool_port); -#endif /* MACH_ASSERT */ - return(KERN_FAILURE); - } - thr_act->pool_port = pool_port; - - /* The pool gets a ref to the activation -- have - * to inline operation because thr_act is already - * locked. - */ - act_locked_act_reference(thr_act); - - /* If it is available, - * add it to the thread_pool's available-activation list. - */ - if ((thr_act->thread == 0) && (thr_act->suspend_count == 0)) { - thr_act->thread_pool_next = thread_pool->thr_acts; - pool_port->ip_thread_pool.thr_acts = thr_act; - if (thread_pool->waiting) - thread_pool_wakeup(thread_pool); - } - } + extern thread_apc_handler_t bsd_ast; - return KERN_SUCCESS; + assert(apc == bsd_ast); + return (KERN_FAILURE); } /* @@ -1667,52 +1386,46 @@ kern_return_t act_locked_act_set_thread_pool( * * This is called by system-dependent code when it detects that * thr_act->handlers is non-null while returning into user mode. - * Activations linked onto an thread_pool always have null thr_act->handlers, - * so RPC entry paths need not check it. */ -void act_execute_returnhandlers( - void) +void +act_execute_returnhandlers(void) { - spl_t s; - thread_t thread; - thread_act_t thr_act = current_act(); + thread_act_t act = current_act(); #if MACH_ASSERT if (watchacts & WA_ACT_HDLR) - printf("execute_rtn_hdlrs: thr_act=%x\n", thr_act); + printf("execute_rtn_hdlrs: act=%x\n", act); #endif /* MACH_ASSERT */ - s = splsched(); - act_clr_apc(thr_act); + thread_ast_clear(act, AST_APC); spllo(); - while (1) { - ReturnHandler *rh; - /* Grab the next returnhandler */ - thread = act_lock_thread(thr_act); + for (;;) { + ReturnHandler *rh; + thread_t thread = act_lock_thread(act); + (void)splsched(); thread_lock(thread); - rh = thr_act->handlers; + rh = act->handlers; if (!rh) { thread_unlock(thread); - splx(s); - act_unlock_thread(thr_act); + spllo(); + act_unlock_thread(act); return; } - thr_act->handlers = rh->next; + act->handlers = rh->next; thread_unlock(thread); spllo(); - act_unlock_thread(thr_act); + act_unlock_thread(act); #if MACH_ASSERT if (watchacts & WA_ACT_HDLR) - printf( (rh == &thr_act->special_handler) ? - "\tspecial_handler\n" : "\thandler=%x\n", - rh->handler); + printf( (rh == &act->special_handler) ? + "\tspecial_handler\n" : "\thandler=%x\n", rh->handler); #endif /* MACH_ASSERT */ /* Execute it */ - (*rh->handler)(rh, thr_act); + (*rh->handler)(rh, act); } } @@ -1728,28 +1441,28 @@ void act_execute_returnhandlers( void special_handler_continue(void) { - thread_act_t cur_act = current_act(); - thread_t thread = cur_act->thread; - spl_t s; + thread_act_t self = current_act(); - if (cur_act->suspend_count) - install_special_handler(cur_act); + if (self->suspend_count > 0) + install_special_handler(self); else { - s = splsched(); + thread_t thread = self->thread; + spl_t s = splsched(); + thread_lock(thread); - if (thread->depress_priority == -2) { - /* - * We were temporarily undepressed by - * install_special_handler; restore priority - * depression. - */ - thread->depress_priority = thread->priority; - thread->priority = thread->sched_pri = DEPRESSPRI; + if (thread->sched_mode & TH_MODE_ISDEPRESSED) { + processor_t myprocessor = thread->last_processor; + + thread->sched_pri = DEPRESSPRI; + myprocessor->current_pri = thread->sched_pri; + thread->sched_mode &= ~TH_MODE_PREEMPT; } thread_unlock(thread); splx(s); } + thread_exception_return(); + /*NOTREACHED*/ } /* @@ -1759,28 +1472,16 @@ special_handler_continue(void) void special_handler( ReturnHandler *rh, - thread_act_t cur_act) + thread_act_t self) { - spl_t s; - thread_t lthread; - thread_t thread = act_lock_thread(cur_act); - unsigned alert_bits; - exception_data_type_t - codes[EXCEPTION_CODE_MAX]; - kern_return_t kr; - kern_return_t exc_kr; + thread_t thread = act_lock_thread(self); + spl_t s; assert(thread != THREAD_NULL); -#if MACH_ASSERT - if (watchacts & WA_ACT_HDLR) - printf("\t\tspecial_handler(thr_act=%x(%d))\n", cur_act, - (cur_act ? cur_act->ref_count : 0)); -#endif /* MACH_ASSERT */ s = splsched(); - thread_lock(thread); - thread->state &= ~TH_ABORT; /* clear any aborts */ + thread->state &= ~(TH_ABORT|TH_ABORT_SAFELY); /* clear any aborts */ thread_unlock(thread); splx(s); @@ -1788,144 +1489,29 @@ special_handler( * If someone has killed this invocation, * invoke the return path with a terminated exception. */ - if (!cur_act->active) { - act_unlock_thread(cur_act); + if (!self->active) { + act_unlock_thread(self); act_machine_return(KERN_TERMINATED); } -#ifdef CALLOUT_RPC_MODEL - /* - * JMM - We don't intend to support this RPC model in Darwin. - * We will support inheritance through chains of activations - * on shuttles, but it will be universal and not just for RPC. - * As such, each activation will always have a base shuttle. - * Our RPC model will probably even support the notion of - * alerts (thrown up the chain of activations to affect the - * work done on our behalf), but the unlinking of the shuttles - * will be completely difference because we will never have - * to clone them. - */ - - /* strip server terminated bit */ - alert_bits = cur_act->alerts & (~SERVER_TERMINATED); - - /* clear server terminated bit */ - cur_act->alerts &= ~SERVER_TERMINATED; - - if ( alert_bits ) { - /* - * currently necessary to coordinate with the exception - * code -fdr - */ - act_unlock_thread(cur_act); - - /* upcall exception/alert port */ - codes[0] = alert_bits; - - /* - * Exception makes a lot of assumptions. If there is no - * exception handler or the exception reply is broken, the - * thread will be terminated and exception will not return. If - * we decide we don't like that behavior, we need to check - * for the existence of an exception port before we call - * exception. - */ - exc_kr = exception( EXC_RPC_ALERT, codes, 1 ); - - /* clear the orphaned and time constraint indications */ - cur_act->alerts &= ~(ORPHANED | TIME_CONSTRAINT_UNSATISFIED); - - /* if this orphaned activation should be terminated... */ - if (exc_kr == KERN_RPC_TERMINATE_ORPHAN) { - /* - * ... terminate the activation - * - * This is done in two steps. First, the activation is - * disabled (prepared for termination); second, the - * `special_handler()' is executed again -- this time - * to terminate the activation. - * (`act_disable_task_locked()' arranges for the - * additional execution of the `special_handler().') - */ - -#if THREAD_SWAPPER - thread_swap_disable(cur_act); -#endif /* THREAD_SWAPPER */ - - /* acquire appropriate locks */ - task_lock(cur_act->task); - act_lock_thread(cur_act); - - /* detach the activation from its task */ - kr = act_disable_task_locked(cur_act); - assert( kr == KERN_SUCCESS ); - - /* release locks */ - task_unlock(cur_act->task); - } - else { - /* acquire activation lock again (released below) */ - act_lock_thread(cur_act); - s = splsched(); - thread_lock(thread); - if (thread->depress_priority == -2) { - /* - * We were temporarily undepressed by - * install_special_handler; restore priority - * depression. - */ - thread->depress_priority = thread->priority; - thread->priority = thread->sched_pri = DEPRESSPRI; - } - thread_unlock(thread); - splx(s); - } - } -#endif /* CALLOUT_RPC_MODEL */ - /* * If we're suspended, go to sleep and wait for someone to wake us up. */ - if (cur_act->suspend_count) { - if( cur_act->handlers == NULL ) { - assert_wait((event_t)&cur_act->suspend_count, - THREAD_ABORTSAFE); - act_unlock_thread(cur_act); + if (self->suspend_count > 0) { + if (self->handlers == NULL) { + assert_wait(&self->suspend_count, THREAD_ABORTSAFE); + act_unlock_thread(self); thread_block(special_handler_continue); /* NOTREACHED */ } - special_handler_continue(); - } - act_unlock_thread(cur_act); -} + act_unlock_thread(self); -/* - * Try to nudge a thr_act into executing its returnhandler chain. - * Ensures that the activation will execute its returnhandlers - * before it next executes any of its user-level code. - * - * Called with thr_act's act_lock() and "appropriate" thread-related - * locks held. (See act_lock_thread().) Returns same way. - */ -void -nudge(thread_act_t thr_act) -{ -#if MACH_ASSERT - if (watchacts & WA_ACT_HDLR) - printf("\tact_%x: nudge(%x)\n", current_act(), thr_act); -#endif /* MACH_ASSERT */ - - /* - * Don't need to do anything at all if this thr_act isn't the topmost. - */ - if (thr_act->thread && thr_act->thread->top_act == thr_act) { - /* - * If it's suspended, wake it up. - * This should nudge it even on another CPU. - */ - thread_wakeup((event_t)&thr_act->suspend_count); + special_handler_continue(); + /*NOTREACHED*/ } + + act_unlock_thread(self); } /* @@ -1940,52 +1526,27 @@ act_user_to_kernel( } /* - * Already locked: thr_act->task, RPC-related locks for thr_act + * Already locked: activation (shuttle frozen within) * - * Detach an activation from its task, and prepare it to terminate + * Mark an activation inactive, and prepare it to terminate * itself. */ -kern_return_t -act_disable_task_locked( +static void +act_disable( thread_act_t thr_act) { - thread_t thread = thr_act->thread; - task_t task = thr_act->task; #if MACH_ASSERT if (watchacts & WA_EXIT) { - printf("act_%x: act_disable_tl(thr_act=%x(%d))%sactive task=%x(%d)", + printf("act_%x: act_disable_tl(thr_act=%x(%d))%sactive", current_act(), thr_act, thr_act->ref_count, - (thr_act->active ? " " : " !"), - thr_act->task, thr_act->task? thr_act->task->ref_count : 0); - if (thr_act->pool_port) - printf(", pool_port %x", thr_act->pool_port); + (thr_act->active ? " " : " !")); printf("\n"); (void) dump_act(thr_act); } #endif /* MACH_ASSERT */ - /* This will allow no more control ops on this thr_act. */ thr_act->active = 0; - ipc_thr_act_disable(thr_act); - - /* Clean-up any ulocks that are still owned by the thread - * activation (acquired but not released or handed-off). - */ - act_ulock_release_all(thr_act); - - /* When the special_handler gets executed, - * it will see the terminated condition and exit - * immediately. - */ - install_special_handler(thr_act); - - - /* If the target happens to be suspended, - * give it a nudge so it can exit. - */ - if (thr_act->suspend_count) - nudge(thr_act); /* Drop the thr_act reference taken for being active. * (There is still at least one reference left: @@ -1993,8 +1554,6 @@ act_disable_task_locked( * Inline the deallocate because thr_act is locked. */ act_locked_act_deallocate(thr_act); - - return(KERN_SUCCESS); } /* @@ -2060,11 +1619,16 @@ void set_state_handler(ReturnHandler *rh, thread_act_t thr_act); * thread-related locks held. (See act_lock_thread().) */ kern_return_t -get_set_state(thread_act_t thr_act, int flavor, thread_state_t state, int *pcount, - void (*handler)(ReturnHandler *rh, thread_act_t thr_act)) +get_set_state( + thread_act_t act, + int flavor, + thread_state_t state, + int *pcount, + void (*handler)( + ReturnHandler *rh, + thread_act_t act)) { - GetSetState gss; - spl_t s; + GetSetState gss; /* Initialize a small parameter structure */ gss.rh.handler = handler; @@ -2074,17 +1638,15 @@ get_set_state(thread_act_t thr_act, int flavor, thread_state_t state, int *pcoun gss.result = KERN_ABORTED; /* iff wait below is interrupted */ /* Add it to the thr_act's return handler list */ - gss.rh.next = thr_act->handlers; - thr_act->handlers = &gss.rh; + gss.rh.next = act->handlers; + act->handlers = &gss.rh; - s = splsched(); - act_set_apc(thr_act); - splx(s); + act_set_apc(act); #if MACH_ASSERT if (watchacts & WA_ACT_HDLR) { - printf("act_%x: get_set_state(thr_act=%x flv=%x state=%x ptr@%x=%x)", - current_act(), thr_act, flavor, state, + printf("act_%x: get_set_state(act=%x flv=%x state=%x ptr@%x=%x)", + current_act(), act, flavor, state, pcount, (pcount ? *pcount : 0)); printf((handler == get_state_handler ? "get_state_hdlr\n" : (handler == set_state_handler ? "set_state_hdlr\n" : @@ -2092,23 +1654,39 @@ get_set_state(thread_act_t thr_act, int flavor, thread_state_t state, int *pcoun } #endif /* MACH_ASSERT */ - assert(thr_act->thread); /* Callers must ensure these */ - assert(thr_act != current_act()); + assert(act->thread); + assert(act != current_act()); + for (;;) { - nudge(thr_act); + wait_result_t result; + + if ( act->inited && + act->thread->top_act == act ) + thread_wakeup_one(&act->suspend_count); + /* * Wait must be interruptible to avoid deadlock (e.g.) with * task_suspend() when caller and target of get_set_state() * are in same task. */ - assert_wait((event_t)&gss, THREAD_ABORTSAFE); - act_unlock_thread(thr_act); - thread_block((void (*)(void))0); - if (gss.result != KERN_ABORTED) + result = assert_wait(&gss, THREAD_ABORTSAFE); + act_unlock_thread(act); + + if (result == THREAD_WAITING) + result = thread_block(THREAD_CONTINUE_NULL); + + assert(result != THREAD_WAITING); + + if (gss.result != KERN_ABORTED) { + assert(result != THREAD_INTERRUPTED); break; + } + + /* JMM - What about other aborts (like BSD signals)? */ if (current_act()->handlers) act_execute_returnhandlers(); - act_lock_thread(thr_act); + + act_lock_thread(act); } #if MACH_ASSERT @@ -2117,7 +1695,7 @@ get_set_state(thread_act_t thr_act, int flavor, thread_state_t state, int *pcoun current_act(), gss.result); #endif /* MACH_ASSERT */ - return gss.result; + return (gss.result); } void @@ -2203,47 +1781,58 @@ act_get_state(thread_act_t thr_act, int flavor, thread_state_t state, return(act_get_state_locked(thr_act, flavor, state, pcount)); } -/* - * These two should be called at splsched() - * Set/clear indicator to run APC (layered on ASTs) - */ void -act_set_apc(thread_act_t thr_act) +act_set_astbsd( + thread_act_t act) { - - processor_t prssr; - thread_t thread; - - mp_disable_preemption(); + spl_t s = splsched(); - thread_ast_set(thr_act, AST_APC); - if (thr_act == current_act()) { - ast_propagate(thr_act->ast); - mp_enable_preemption(); - return; /* If we are current act, we can't be on the other processor so leave now */ + if (act == current_act()) { + thread_ast_set(act, AST_BSD); + ast_propagate(act->ast); } + else { + thread_t thread = act->thread; + processor_t processor; -/* - * Here we want to make sure that the apc is taken quickly. Therefore, we check - * if, and where, the activation is running. If it is not running, we don't need to do - * anything. If it is, we need to signal the other processor to trigger it to - * check the asts. Note that there is a race here and we may end up sending a signal - * after the thread has been switched off. Hopefully this is no big deal. - */ - - thread = thr_act->thread; /* Get the thread for the signaled activation */ - prssr = thread->last_processor; /* get the processor it was last on */ - if(prssr && (cpu_data[prssr->slot_num].active_thread == thread)) { /* Is the thread active on its processor? */ - cause_ast_check(prssr); /* Yes, kick it */ + thread_lock(thread); + thread_ast_set(act, AST_BSD); + processor = thread->last_processor; + if ( processor != PROCESSOR_NULL && + processor->state == PROCESSOR_RUNNING && + processor->cpu_data->active_thread == thread ) + cause_ast_check(processor); + thread_unlock(thread); } - mp_enable_preemption(); + splx(s); } void -act_clr_apc(thread_act_t thr_act) +act_set_apc( + thread_act_t act) { - thread_ast_clear(thr_act, AST_APC); + spl_t s = splsched(); + + if (act == current_act()) { + thread_ast_set(act, AST_APC); + ast_propagate(act->ast); + } + else { + thread_t thread = act->thread; + processor_t processor; + + thread_lock(thread); + thread_ast_set(act, AST_APC); + processor = thread->last_processor; + if ( processor != PROCESSOR_NULL && + processor->state == PROCESSOR_RUNNING && + processor->cpu_data->active_thread == thread ) + cause_ast_check(processor); + thread_unlock(thread); + } + + splx(s); } void @@ -2262,13 +1851,6 @@ act_ulock_release_all(thread_act_t thr_act) * Provide routines (for export to other components) of things that * are implemented as macros insternally. */ -#undef current_act -thread_act_t -current_act(void) -{ - return(current_act_fast()); -} - thread_act_t thread_self(void) { @@ -2302,4 +1884,3 @@ act_deallocate( { act_deallocate_fast(thr_act); } - diff --git a/osfmk/kern/thread_act.h b/osfmk/kern/thread_act.h index 40fe85fcf..0d7a102da 100644 --- a/osfmk/kern/thread_act.h +++ b/osfmk/kern/thread_act.h @@ -49,13 +49,16 @@ #define _KERN_THREAD_ACT_H_ #include -#include #include #include #include +#include + +#ifdef __APPLE_API_PRIVATE + +#ifdef MACH_KERNEL_PRIVATE -#ifdef MACH_KERNEL_PRIVATE #include #include #include @@ -65,41 +68,31 @@ #include #include #include -#include #include #include -/* Here is a description of the states an thread_activation may be in. +/* + * Here is a description of the states an thread_activation may be in. * * An activation always has a valid task pointer, and it is always constant. * The activation is only linked onto the task's activation list until * the activation is terminated. * - * An activation is in use or not, depending on whether its thread - * pointer is nonzero. If it is not in use, it is just sitting idly - * waiting to be used by a thread. The thread holds a reference on - * the activation while using it. - * - * An activation lives on an thread_pool if its pool_port pointer is nonzero. - * When in use, it can still live on an thread_pool, but it is not actually - * linked onto the thread_pool's list of available activations. In this case, - * the act will return to its thread_pool as soon as it becomes unused. + * The thread holds a reference on the activation while using it. * * An activation is active until thread_terminate is called on it; * then it is inactive, waiting for all references to be dropped. * Future control operations on the terminated activation will fail, * with the exception that act_yank still works if the activation is - * still on an RPC chain. A terminated activation always has null - * thread and pool_port pointers. + * still on an RPC chain. A terminated activation always has a null + * thread pointer. * * An activation is suspended when suspend_count > 0. - * A suspended activation can live on an thread_pool, but it is not - * actually linked onto the thread_pool while suspended. * * Locking note: access to data relevant to scheduling state (user_stop_count, * suspend_count, handlers, special_handler) is controlled by the combination * of locks acquired by act_lock_thread(). That is, not only must act_lock() - * be held, but RPC through the activation must be frozen (so that the + * be held, but migration through the activation must be frozen (so that the * thread pointer doesn't change). If a shuttle is associated with the * activation, then its thread_lock() must also be acquired to change these * data. Regardless of whether a shuttle is present, the data must be @@ -130,6 +123,8 @@ typedef struct thread_activation { boolean_t kernel_loaded; /* running in kernel-loaded task */ boolean_t kernel_loading; /* about to run kernel-loaded */ + boolean_t inited; + /*** Machine-dependent state ***/ struct MachineThrAct mact; @@ -144,58 +139,6 @@ typedef struct thread_activation { struct task *task; vm_map_t map; /* cached current map */ - /*** thread_pool-related stuff ***/ - /* Port containing the thread_pool this activation normally lives - * on, zero if none. The port (really the thread_pool) holds a - * reference to the activation as long as this is nonzero (even when - * the activation isn't actually on the thread_pool's list). - */ - struct ipc_port *pool_port; - - /* Link on the thread_pool's list of activations. - * The activation is only actually on the thread_pool's list - * (and hence this is valid) when not in use (thread == 0) and - * not suspended (suspend_count == 0). - */ - struct thread_activation *thread_pool_next; - - /* RPC state */ - union { - struct { - rpc_subsystem_t r_subsystem; -#if 0 /* Grenoble */ - mach_rpc_id_t r_routine_num; - mach_rpc_signature_t r_sig_ptr; - mach_rpc_size_t r_sig_size; -#else - rpc_id_t r_routine_num; - rpc_signature_t r_sig_ptr; /* Stored Client Sig Ptr */ - rpc_size_t r_sig_size; /* Size of Sig stored */ - struct rpc_signature r_sigbuf; /* Static Reservation of Sig Mem */ - routine_descriptor_t r_sigbufp; /* For dynamic storage of Sig */ - vm_size_t r_sigbuf_size; /* Size of buffer allocated for sig */ -#endif - vm_offset_t r_new_argv; - vm_offset_t *r_arg_buf; - vm_offset_t r_arg_buf_data[RPC_KBUF_SIZE]; - rpc_copy_state_t r_state; - rpc_copy_state_data_t r_state_data[RPC_DESC_COUNT]; - unsigned int r_port_flags; - ipc_port_t r_local_port; - void *r_kkt_args; - } regular; - struct { - ipc_port_t r_port; - ipc_port_t r_exc_port; - int r_exc_flavor; - mach_msg_type_number_t r_ostate_cnt; - exception_data_type_t r_code[EXCEPTION_CODE_MAX]; -#if ETAP_EVENT_MONITOR - exception_type_t r_exception; -#endif - } exception; - } rpc_state; - /*** Thread linkage ***/ /* Shuttle using this activation, zero if not in use. The shuttle * holds a reference on the activation while this is nonzero. @@ -219,18 +162,6 @@ typedef struct thread_activation { */ unsigned alert_mask; -#if 0 /* Grenoble */ - /* Saved policy and priority of shuttle if changed to migrate into - * higher-priority or more real-time task. Only valid if - * saved_sched_stamp is nonzero and equal to the sched_change_stamp - * in the thread_shuttle. (Otherwise, the policy or priority has - * been explicitly changed in the meantime, and the saved values - * are invalid.) - */ - policy_t saved_policy; - integer_t saved_base_priority; - unsigned int saved_sched_change_stamp; -#endif /*** Control information ***/ /* Number of outstanding suspensions on this activation. */ @@ -240,17 +171,7 @@ typedef struct thread_activation { int user_stop_count; /* outstanding stops */ /* ast is needed - see ast.h */ - int ast; - -#if THREAD_SWAPPER - /* task swapper */ - int swap_state; /* swap state (or unswappable flag)*/ - queue_chain_t swap_queue; /* links on swap queues */ -#if MACH_ASSERT - boolean_t kernel_stack_swapped_in; - /* debug for thread swapping */ -#endif /* MACH_ASSERT */ -#endif /* THREAD_SWAPPER */ + ast_t ast; /* This is normally true, but is set to false when the * activation is terminated. @@ -291,72 +212,12 @@ typedef struct thread_activation { } Thread_Activation; -/* RPC state fields */ -#define r_subsystem rpc_state.regular.r_subsystem -#define r_routine_num rpc_state.regular.r_routine_num -#define r_sig_ptr rpc_state.regular.r_sig_ptr -#define r_sig_size rpc_state.regular.r_sig_size -#define r_sigbuf rpc_state.regular.r_sigbuf -#define r_sigbufp rpc_state.regular.r_sigbufp -#define r_sigbuf_size rpc_state.regular.r_sigbuf_size -#define r_new_argv rpc_state.regular.r_new_argv -#define r_arg_buf rpc_state.regular.r_arg_buf -#define r_arg_buf_data rpc_state.regular.r_arg_buf_data -#define r_state rpc_state.regular.r_state -#define r_state_data rpc_state.regular.r_state_data -#define r_port_flags rpc_state.regular.r_port_flags -#define r_local_port rpc_state.regular.r_local_port -#define r_kkt_args rpc_state.regular.r_kkt_args -#define r_port rpc_state.exception.r_port -#define r_exc_port rpc_state.exception.r_exc_port -#define r_exc_flavor rpc_state.exception.r_exc_flavor -#define r_ostate_cnt rpc_state.exception.r_ostate_cnt -#define r_code rpc_state.exception.r_code -#define r_exception rpc_state.exception.r_exception - /* Alert bits */ #define SERVER_TERMINATED 0x01 #define ORPHANED 0x02 #define CLIENT_TERMINATED 0x04 #define TIME_CONSTRAINT_UNSATISFIED 0x08 -#if THREAD_SWAPPER -/* - * Encapsulate the actions needed to ensure that next lower act on - * RPC chain is swapped in. Used at base spl; assumes rpc_lock() - * of thread is held; if port is non-null, assumes its ip_lock() - * is also held. - */ -#define act_switch_swapcheck(thread, port) \ -MACRO_BEGIN \ - thread_act_t __act__ = thread->top_act; \ - \ - while (__act__->lower) { \ - thread_act_t __l__ = __act__->lower; \ - \ - if (__l__->swap_state == TH_SW_IN || \ - __l__->swap_state == TH_SW_UNSWAPPABLE) \ - break; \ - /* \ - * XXX - Do we need to reference __l__? \ - */ \ - if (port) \ - ip_unlock(port); \ - if (!thread_swapin_blocking(__l__)) \ - panic("act_switch_swapcheck: !active"); \ - if (port) \ - ip_lock(port); \ - if (__act__->lower == __l__) \ - break; \ - } \ -MACRO_END - -#else /* !THREAD_SWAPPER */ - -#define act_switch_swapcheck(thread, port) - -#endif /* !THREAD_SWAPPER */ - #define act_lock_init(thr_act) mutex_init(&(thr_act)->lock, ETAP_THREAD_ACT) #define act_lock(thr_act) mutex_lock(&(thr_act)->lock) #define act_lock_try(thr_act) mutex_try(&(thr_act)->lock) @@ -390,15 +251,6 @@ MACRO_END } \ MACRO_END -#define sigbuf_dealloc(thr_act) \ - if ((thr_act->r_sigbufp) && (thr_act->r_sigbuf_size > \ - sizeof(thr_act->r_sigbuf))) \ - { \ - kfree((vm_offset_t)thr_act->r_sigbufp, \ - thr_act->r_sigbuf_size); \ - thr_act->r_sigbuf_size = 0; \ - } - #define act_deallocate_fast(thr_act) \ MACRO_BEGIN \ if (thr_act) { \ @@ -428,16 +280,13 @@ MACRO_END } \ MACRO_END +extern struct thread_activation pageout_act; extern void act_init(void); -extern kern_return_t act_disable_task_locked(thread_act_t); extern void thread_release(thread_act_t); extern kern_return_t thread_dowait(thread_act_t, boolean_t); extern void thread_hold(thread_act_t); -extern void nudge(thread_act_t); -extern kern_return_t act_set_thread_pool(thread_act_t, ipc_port_t); -extern kern_return_t act_locked_act_set_thread_pool(thread_act_t, ipc_port_t); extern kern_return_t thread_get_special_port(thread_act_t, int, ipc_port_t *); extern kern_return_t thread_set_special_port(thread_act_t, int, @@ -474,41 +323,63 @@ extern kern_return_t act_set_state(thread_act_t, int, thread_state_t, extern int dump_act(thread_act_t); /* debugging */ -#define current_act_fast() (current_thread()->top_act) -#define current_act_slow() ((current_thread()) ? \ - current_act_fast() : \ - THR_ACT_NULL) - -#define current_act() current_act_slow() /* JMM - til we find the culprit */ +#if MACH_ASSERT +/* + * Debugging support - "watchacts", a patchable selective trigger + */ +extern unsigned int watchacts; /* debug printf trigger */ +#define WA_SCHED 0x001 /* kern/sched_prim.c */ +#define WA_THR 0x002 /* kern/thread.c */ +#define WA_ACT_LNK 0x004 /* kern/thread_act.c act mgmt */ +#define WA_ACT_HDLR 0x008 /* kern/thread_act.c act hldrs */ +#define WA_TASK 0x010 /* kern/task.c */ +#define WA_BOOT 0x020 /* bootstrap,startup.c */ +#define WA_PCB 0x040 /* machine/pcb.c */ +#define WA_PORT 0x080 /* ports + port sets */ +#define WA_EXIT 0x100 /* exit path */ +#define WA_SWITCH 0x200 /* context switch (!!) */ +#define WA_STATE 0x400 /* get/set state (!!) */ +#define WA_ALL (~0) +#endif /* MACH_ASSERT */ -#else /* !MACH_KERNEL_PRIVATE */ +#else /* MACH_KERNEL_PRIVATE */ -extern thread_act_t current_act(void); extern void act_reference(thread_act_t); extern void act_deallocate(thread_act_t); -#endif /* !MACH_KERNEL_PRIVATE */ +#endif /* MACH_KERNEL_PRIVATE */ -/* Exported to world */ extern kern_return_t act_alert(thread_act_t, unsigned); extern kern_return_t act_alert_mask(thread_act_t, unsigned ); extern kern_return_t post_alert(thread_act_t, unsigned); -extern kern_return_t thread_abort(thread_act_t); -extern kern_return_t thread_abort_safely(thread_act_t); -extern kern_return_t thread_resume(thread_act_t); -extern kern_return_t thread_suspend(thread_act_t); -extern kern_return_t thread_terminate(thread_act_t); - -typedef void (thread_apc_handler_t)(thread_act_t); +typedef void (thread_apc_handler_t)(thread_act_t); extern kern_return_t thread_apc_set(thread_act_t, thread_apc_handler_t); extern kern_return_t thread_apc_clear(thread_act_t, thread_apc_handler_t); -extern vm_map_t swap_act_map(thread_act_t, vm_map_t); +extern vm_map_t swap_act_map(thread_act_t, vm_map_t); extern void *get_bsdthread_info(thread_act_t); extern void set_bsdthread_info(thread_act_t, void *); -extern task_t get_threadtask(thread_act_t); +extern task_t get_threadtask(thread_act_t); + +#endif /* __APPLE_API_PRIVATE */ + +#ifdef __APPLE_API_UNSTABLE + +#if !defined(MACH_KERNEL_PRIVATE) + +extern thread_act_t current_act(void); + +#endif /* MACH_KERNEL_PRIVATE */ + +#endif /* __APPLE_API_UNSTABLE */ + +extern kern_return_t thread_abort(thread_act_t); +extern kern_return_t thread_abort_safely(thread_act_t); +extern kern_return_t thread_resume(thread_act_t); +extern kern_return_t thread_suspend(thread_act_t); +extern kern_return_t thread_terminate(thread_act_t); #endif /* _KERN_THREAD_ACT_H_ */ diff --git a/osfmk/kern/thread_call.c b/osfmk/kern/thread_call.c index 2a0004215..b69dcdd30 100644 --- a/osfmk/kern/thread_call.c +++ b/osfmk/kern/thread_call.c @@ -56,7 +56,7 @@ decl_simple_lock_data(static,thread_call_lock) static timer_call_data_t - thread_call_delayed_timers[NCPUS]; + thread_call_delayed_timer; static queue_head_t @@ -64,8 +64,8 @@ queue_head_t pending_call_queue, delayed_call_queue; static -queue_head_t - idle_thread_queue; +struct wait_queue + call_thread_idle_queue; static thread_t @@ -79,7 +79,8 @@ static struct { int pending_num, pending_hiwat; int active_num, - active_hiwat; + active_hiwat, + active_lowat; int delayed_num, delayed_hiwat; int idle_thread_num; @@ -162,7 +163,6 @@ thread_call_initialize(void) { thread_call_t call; spl_t s; - int i; if (thread_call_initialized) panic("thread_call_initialize"); @@ -184,12 +184,9 @@ thread_call_initialize(void) enqueue_tail(&internal_call_free_queue, qe(call)); } - for (i = 0; i < NCPUS; i++) { - timer_call_setup(&thread_call_delayed_timers[i], - _delayed_call_timer, NULL); - } + timer_call_setup(&thread_call_delayed_timer, _delayed_call_timer, NULL); - queue_init(&idle_thread_queue); + wait_queue_init(&call_thread_idle_queue, SYNC_POLICY_FIFO); thread_calls.thread_lowat = thread_call_thread_min; activate_thread_awake = TRUE; @@ -383,9 +380,7 @@ _set_delayed_call_timer( thread_call_t call ) { - timer_call_t timer = &thread_call_delayed_timers[cpu_number()]; - - timer_call_enter(timer, call->deadline); + timer_call_enter(&thread_call_delayed_timer, call->deadline); } /* @@ -534,7 +529,8 @@ thread_call_func( _pending_call_enqueue(call); - _call_thread_wake(); + if (thread_calls.active_num <= 0) + _call_thread_wake(); } simple_unlock(&thread_call_lock); @@ -722,8 +718,9 @@ thread_call_enter( result = FALSE; _pending_call_enqueue(call); - - _call_thread_wake(); + + if (thread_calls.active_num <= 0) + _call_thread_wake(); } call->param1 = 0; @@ -754,7 +751,8 @@ thread_call_enter1( _pending_call_enqueue(call); - _call_thread_wake(); + if (thread_calls.active_num <= 0) + _call_thread_wake(); } call->param1 = param1; @@ -922,11 +920,11 @@ thread_call_is_delayed( } /* - * Routine: _call_thread_wake [private] + * Routine: _call_thread_wake [private, inline] * * Purpose: Wake a callout thread to service - * newly pending callout entries. May wake - * the activate thread to either wake or + * pending callout entries. May wake + * the activate thread in order to * create additional callout threads. * * Preconditions: thread_call_lock held. @@ -938,30 +936,68 @@ static __inline__ void _call_thread_wake(void) { - thread_t thread_to_wake; - - if (!queue_empty(&idle_thread_queue)) { - queue_remove_first( - &idle_thread_queue, thread_to_wake, thread_t, wait_link); - clear_wait(thread_to_wake, THREAD_AWAKENED); + if (wait_queue_wakeup_one( + &call_thread_idle_queue, &call_thread_idle_queue, + THREAD_AWAKENED) == KERN_SUCCESS) { thread_calls.idle_thread_num--; + + if (++thread_calls.active_num > thread_calls.active_hiwat) + thread_calls.active_hiwat = thread_calls.active_num; } else - thread_to_wake = THREAD_NULL; - - if (!activate_thread_awake && - (thread_to_wake == THREAD_NULL || thread_calls.thread_num < - (thread_calls.active_num + thread_calls.pending_num))) { + if (!activate_thread_awake) { clear_wait(activate_thread, THREAD_AWAKENED); activate_thread_awake = TRUE; } } -#if defined (__i386__) -#define NO_CONTINUATIONS (1) -#else -#define NO_CONTINUATIONS (0) -#endif +/* + * Routine: call_thread_block [private] + * + * Purpose: Hook via thread dispatch on + * the occasion of a callout blocking. + * + * Preconditions: splsched. + * + * Postconditions: None. + */ + +void +call_thread_block(void) +{ + simple_lock(&thread_call_lock); + + if (--thread_calls.active_num < thread_calls.active_lowat) + thread_calls.active_lowat = thread_calls.active_num; + + if ( thread_calls.active_num <= 0 && + thread_calls.pending_num > 0 ) + _call_thread_wake(); + + simple_unlock(&thread_call_lock); +} + +/* + * Routine: call_thread_unblock [private] + * + * Purpose: Hook via thread wakeup on + * the occasion of a callout unblocking. + * + * Preconditions: splsched. + * + * Postconditions: None. + */ + +void +call_thread_unblock(void) +{ + simple_lock(&thread_call_lock); + + if (++thread_calls.active_num > thread_calls.active_hiwat) + thread_calls.active_hiwat = thread_calls.active_num; + + simple_unlock(&thread_call_lock); +} /* * Routine: _call_thread [private] @@ -979,12 +1015,11 @@ _call_thread_continue(void) { thread_t self = current_thread(); -#if NO_CONTINUATIONS - loop: -#endif (void) splsched(); simple_lock(&thread_call_lock); + self->active_callout = TRUE; + while (thread_calls.pending_num > 0) { thread_call_t call; thread_call_func_t func; @@ -1001,12 +1036,6 @@ _call_thread_continue(void) _internal_call_release(call); - if (++thread_calls.active_num > thread_calls.active_hiwat) - thread_calls.active_hiwat = thread_calls.active_num; - - if (thread_calls.pending_num > 0) - _call_thread_wake(); - simple_unlock(&thread_call_lock); (void) spllo(); @@ -1016,26 +1045,24 @@ _call_thread_continue(void) (void) splsched(); simple_lock(&thread_call_lock); - - thread_calls.active_num--; } + + self->active_callout = FALSE; + + if (--thread_calls.active_num < thread_calls.active_lowat) + thread_calls.active_lowat = thread_calls.active_num; - if ((thread_calls.thread_num - thread_calls.active_num) <= - thread_calls.thread_lowat) { - queue_enter(&idle_thread_queue, self, thread_t, wait_link); + if (thread_calls.idle_thread_num < thread_calls.thread_lowat) { thread_calls.idle_thread_num++; - assert_wait(&idle_thread_queue, THREAD_INTERRUPTIBLE); + wait_queue_assert_wait( + &call_thread_idle_queue, &call_thread_idle_queue, + THREAD_INTERRUPTIBLE); simple_unlock(&thread_call_lock); (void) spllo(); -#if NO_CONTINUATIONS - thread_block((void (*)(void)) 0); - goto loop; -#else thread_block(_call_thread_continue); -#endif /* NOTREACHED */ } @@ -1074,14 +1101,14 @@ static void _activate_thread_continue(void) { -#if NO_CONTINUATIONS - loop: -#endif (void) splsched(); simple_lock(&thread_call_lock); - if (thread_calls.thread_num < - (thread_calls.active_num + thread_calls.pending_num)) { + while ( thread_calls.active_num <= 0 && + thread_calls.pending_num > 0 ) { + + if (++thread_calls.active_num > thread_calls.active_hiwat) + thread_calls.active_hiwat = thread_calls.active_num; if (++thread_calls.thread_num > thread_calls.thread_hiwat) thread_calls.thread_hiwat = thread_calls.thread_num; @@ -1092,28 +1119,9 @@ _activate_thread_continue(void) (void) kernel_thread_with_priority( kernel_task, MAXPRI_KERNEL - 1, _call_thread, TRUE, TRUE); -#if NO_CONTINUATIONS - thread_block((void (*)(void)) 0); - goto loop; -#else - thread_block(_activate_thread_continue); -#endif - /* NOTREACHED */ + (void) splsched(); + simple_lock(&thread_call_lock); } - else if (thread_calls.pending_num > 0) { - _call_thread_wake(); - - simple_unlock(&thread_call_lock); - (void) spllo(); - -#if NO_CONTINUATIONS - thread_block((void (*)(void)) 0); - goto loop; -#else - thread_block(_activate_thread_continue); -#endif - /* NOTREACHED */ - } assert_wait(&activate_thread_awake, THREAD_INTERRUPTIBLE); activate_thread_awake = FALSE; @@ -1121,12 +1129,7 @@ _activate_thread_continue(void) simple_unlock(&thread_call_lock); (void) spllo(); -#if NO_CONTINUATIONS - thread_block((void (*)(void)) 0); - goto loop; -#else thread_block(_activate_thread_continue); -#endif /* NOTREACHED */ } @@ -1179,7 +1182,7 @@ _delayed_call_timer( if (!queue_end(&delayed_call_queue, qe(call))) _set_delayed_call_timer(call); - if (new_pending) + if (new_pending && thread_calls.active_num <= 0) _call_thread_wake(); simple_unlock(&thread_call_lock); diff --git a/osfmk/kern/thread_call.h b/osfmk/kern/thread_call.h index 19649709d..952265dd9 100644 --- a/osfmk/kern/thread_call.h +++ b/osfmk/kern/thread_call.h @@ -35,6 +35,8 @@ #ifndef _KERN_THREAD_CALL_H_ #define _KERN_THREAD_CALL_H_ +#include + #include #include @@ -85,11 +87,16 @@ thread_call_free( thread_call_t call ); +#ifdef __APPLE_API_PRIVATE + +#ifdef __APPLE_API_OBSOLETE + /* * This portion of the interface * is OBSOLETE and DEPRECATED. It * will disappear shortly. */ + void thread_call_func( thread_call_func_t func, @@ -109,8 +116,11 @@ thread_call_func_cancel( thread_call_param_t param, boolean_t cancel_all ); + /* End OBSOLETE and DEPRECATED */ +#endif /* __APPLE_API_OBSOLETE */ + #ifdef MACH_KERNEL_PRIVATE #include @@ -126,8 +136,14 @@ thread_call_setup( thread_call_param_t param0 ); +void +call_thread_block(void), +call_thread_unblock(void); + #endif /* MACH_KERNEL_PRIVATE */ +#endif /* __APPLE_API_PRIVATE */ + #if !defined(MACH_KERNEL_PRIVATE) && !defined(ABSOLUTETIME_SCALAR_TYPE) #include diff --git a/osfmk/kern/thread_policy.c b/osfmk/kern/thread_policy.c index e9eacf91b..d7e2c311a 100644 --- a/osfmk/kern/thread_policy.c +++ b/osfmk/kern/thread_policy.c @@ -198,15 +198,7 @@ thread_recompute_priority( priority = MINPRI; } - if (thread->depress_priority >= 0) - thread->depress_priority = priority; - else { - thread->priority = priority; - compute_priority(thread, TRUE); - - if (thread == current_thread()) - ast_on(AST_BLOCK); - } + set_priority(thread, priority); } void diff --git a/osfmk/kern/thread_pool.c b/osfmk/kern/thread_pool.c deleted file mode 100644 index 8ee6b2334..000000000 --- a/osfmk/kern/thread_pool.c +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * @OSF_FREE_COPYRIGHT@ - */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:32 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.1.1.1 1998/03/07 02:25:57 wsanchez - * Import of OSF Mach kernel (~mburg) - * - * Revision 1.1.7.6 1995/08/21 20:44:57 devrcs - * Fix ri-osc CR1405: Zero act->thread_pool_next when act not on pool. - * [1995/07/25 20:19:06 bolinger] - * - * Revision 1.1.7.5 1995/01/18 18:35:00 ezf - * updated Utah CR notice - * [1995/01/18 18:30:33 ezf] - * - * Revision 1.1.7.4 1995/01/10 05:15:20 devrcs - * mk6 CR801 - merge up from nmk18b4 to nmk18b7 - * Comments from merged code below, as marked - * [1994/12/09 21:10:54 dwm] - * - * mk6 CR668 - 1.3b26 merge - * event_t casts - * [1994/11/04 09:39:15 dwm] - * - * Revision 1.1.7.3 1994/11/23 16:01:15 devrcs - * BEGIN comments from merge of nmk18b4 - nmk18b7 - * Cleared `handlers' field of activation when returning - * it to thread pool. - * [1994/11/23 03:48:31 burke] - * - * Added an assert to `thread_pool_put_act()' to check - * for presence of handlers when returning an activation - * to its pool. - * [1994/11/18 13:36:29 rkc] - * - * Changed `thread_pool_put_act()'s call to `act_set_thread_pool()' to - * be a call to `act_locked_act_set_thread_pool()' to obey locking - * assumptions. - * [1994/11/10 23:29:51 rkc] - * - * Cosmetic changes to thread_pool_put_act. - * [1994/11/09 21:49:57 watkins] - * - * Check out for merge. - * [1994/11/09 14:16:43 watkins] - * - * Revision 1.1.9.2 1994/11/08 15:32:42 watkins - * Add thread_pool_put_act. - * END comments from merge of nmk18b4 - nmk18b7 - * [1994/11/09 14:16:33 watkins] - * - * Revision 1.1.7.2 1994/09/23 02:31:05 ezf - * change marker to not FREE - * [1994/09/22 21:38:01 ezf] - * - * Revision 1.1.7.1 1994/09/02 02:40:54 watkins - * Check for destroyed thread pool port after thread_pool_get_act - * blocks. - * [1994/09/02 02:37:46 watkins] - * - * Revision 1.1.2.8 1994/06/09 14:14:04 dswartz - * Preemption merge. - * [1994/06/09 14:08:35 dswartz] - * - * Revision 1.1.2.7 1994/06/01 19:30:10 bolinger - * mk6 CR125: Update to reflect new naming for thread_pool of - * thread_act. - * [1994/06/01 19:14:46 bolinger] - * - * Revision 1.1.2.6 1994/03/17 22:38:34 dwm - * The infamous name change: thread_activation + thread_shuttle = thread. - * [1994/03/17 21:28:15 dwm] - * - * Revision 1.1.2.5 1994/02/09 00:42:29 dwm - * Put a variety of debugging code under MACH_ASSERT, - * to enhance PROD performance a bit. - * [1994/02/09 00:35:07 dwm] - * - * Revision 1.1.2.4 1994/02/04 03:46:25 condict - * Put if MACH_ASSERT around debugging printfs. - * [1994/02/04 03:44:10 condict] - * - * Revision 1.1.2.3 1994/01/21 23:45:15 dwm - * Thread_pools now embedded directly in port/pset. - * Adjust thread_pool_create. - * [1994/01/21 23:43:18 dwm] - * - * Revision 1.1.2.2 1994/01/14 18:42:01 bolinger - * Rename thread_pool_block() to thread_pool_get_act() [sic], to - * better reflect its function. Add leading comment and assertion - * checks. - * [1994/01/14 18:18:11 bolinger] - * - * Revision 1.1.2.1 1994/01/12 17:53:17 dwm - * Coloc: initial restructuring to follow Utah model. - * [1994/01/12 17:15:21 dwm] - * - * $EndLog$ - */ -/* - * Copyright (c) 1993 The University of Utah and - * the Computer Systems Laboratory (CSL). All rights reserved. - * - * 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. - * - * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS - * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF - * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * CSL requests users of this software to return to csl-dist@cs.utah.edu any - * improvements that they make and grant CSL redistribution rights. - * - * Author: Bryan Ford, University of Utah CSL - * - * File: thread_pool.c - * - * thread_pool management routines - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - - -/* Initialize a new EMPTY thread_pool. */ -kern_return_t -thread_pool_init(thread_pool_t new_thread_pool) -{ - assert(new_thread_pool != THREAD_POOL_NULL); - - /* Start with one reference for the caller */ - new_thread_pool->thr_acts = (struct thread_activation *)0; - return KERN_SUCCESS; -} - - -/* - * Obtain an activation from a thread pool, blocking if - * necessary. Return the activation locked, since it's - * in an inconsistent state (not in a pool, not attached - * to a thread). - * - * Called with ip_lock() held for pool_port. Returns - * the same way. - * - * If the thread pool port is destroyed while we are blocked, - * then return a null activation. Callers must check for this - * error case. - */ -thread_act_t -thread_pool_get_act(ipc_port_t pool_port) -{ - thread_pool_t thread_pool = &pool_port->ip_thread_pool; - thread_act_t thr_act; - -#if MACH_ASSERT - assert(thread_pool != THREAD_POOL_NULL); - if (watchacts & WA_ACT_LNK) - printf("thread_pool_block: %x, waiting=%d\n", - thread_pool, thread_pool->waiting); -#endif - - while ((thr_act = thread_pool->thr_acts) == THR_ACT_NULL) { - if (!ip_active(pool_port)) - return THR_ACT_NULL; - thread_pool->waiting = 1; - assert_wait((event_t)thread_pool, THREAD_INTERRUPTIBLE); - ip_unlock(pool_port); - thread_block((void (*)(void)) 0); /* block self */ - ip_lock(pool_port); - } - assert(thr_act->thread == THREAD_NULL); - assert(thr_act->suspend_count == 0); - thread_pool->thr_acts = thr_act->thread_pool_next; - act_lock(thr_act); - thr_act->thread_pool_next = 0; - -#if MACH_ASSERT - if (watchacts & WA_ACT_LNK) - printf("thread_pool_block: return %x, next=%x\n", - thr_act, thread_pool->thr_acts); -#endif - return thr_act; -} - -/* - * thread_pool_put_act - * - * Return an activation to its pool. Assumes the activation - * and pool (if it exists) are locked. - */ -void -thread_pool_put_act( thread_act_t thr_act ) -{ - thread_pool_t thr_pool; - - /* - * Find the thread pool for this activation. - */ - if (thr_act->pool_port) - thr_pool = &thr_act->pool_port->ip_thread_pool; - else - thr_pool = THREAD_POOL_NULL; - - /* - * Return act to the thread_pool's list, if it is still - * alive. Otherwise, remove it from its thread_pool, which - * will deallocate it and destroy it. - */ - if (thr_act->active) { - assert(thr_pool); - thr_act->handlers = NULL; - thr_act->thread_pool_next = thr_pool->thr_acts; - thr_pool->thr_acts = thr_act; - if (thr_pool->waiting) - thread_pool_wakeup(thr_pool); - } else if (thr_pool) { - assert(thr_act->pool_port); - act_locked_act_set_thread_pool(thr_act, IP_NULL); - } - - return; -} - - -/* - * Called with ip_lock() held for port containing thread_pool. - * Returns same way. - */ -void -thread_pool_wakeup(thread_pool_t thread_pool) -{ -#if MACH_ASSERT - assert(thread_pool != THREAD_POOL_NULL); - if (watchacts & WA_ACT_LNK) - printf("thread_pool_wakeup: %x, waiting=%d, head=%x\n", - thread_pool, thread_pool->waiting, thread_pool->thr_acts); -#endif /* MACH_ASSERT */ - - if (thread_pool->waiting) { - thread_wakeup((event_t)thread_pool); - thread_pool->waiting = 0; - } -} diff --git a/osfmk/kern/thread_pool.h b/osfmk/kern/thread_pool.h deleted file mode 100644 index d0bf54fc8..000000000 --- a/osfmk/kern/thread_pool.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * @OSF_FREE_COPYRIGHT@ - */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:32 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.1.1.1 1998/03/07 02:25:57 wsanchez - * Import of OSF Mach kernel (~mburg) - * - * Revision 1.1.7.4 1995/01/18 18:35:03 ezf - * updated Utah CR notice - * [1995/01/18 18:30:36 ezf] - * - * Revision 1.1.7.3 1995/01/10 05:15:24 devrcs - * mk6 CR801 - merge up from nmk18b4 to nmk18b7 - * * Rev 1.1.8.2 1994/11/08 15:33:03 watkins - * Add declaration for thread_pool_put_act. - * [1994/12/09 21:10:56 dwm] - * - * Revision 1.1.7.1 1994/09/23 02:31:15 ezf - * change marker to not FREE - * [1994/09/22 21:38:04 ezf] - * - * Revision 1.1.2.9 1994/06/09 14:14:07 dswartz - * Preemption merge. - * [1994/06/09 14:08:37 dswartz] - * - * Revision 1.1.2.8 1994/06/01 19:30:14 bolinger - * mk6 CR125: Update to reflect changes in access to thread_pool - * of a thread_act. - * [1994/06/01 19:18:25 bolinger] - * - * Revision 1.1.2.7 1994/03/17 22:38:37 dwm - * The infamous name change: thread_activation + thread_shuttle = thread. - * [1994/03/17 21:28:18 dwm] - * - * Revision 1.1.2.6 1994/02/09 00:42:42 dwm - * Put a variety of debugging code under MACH_ASSERT, - * to enhance PROD performance a bit. - * [1994/02/09 00:35:13 dwm] - * - * Revision 1.1.2.5 1994/01/21 23:45:08 dwm - * Thread_pools now embedded directly in port/pset, - * delete refcount, modify protos. - * [1994/01/21 23:43:13 dwm] - * - * Revision 1.1.2.4 1994/01/17 19:09:32 dwm - * Fix ref/dealloc macros, missing semicolon. - * [1994/01/17 19:09:16 dwm] - * - * Revision 1.1.2.3 1994/01/17 18:08:57 dwm - * Add finer grained act tracing. - * [1994/01/17 16:06:54 dwm] - * - * Revision 1.1.2.2 1994/01/14 18:42:05 bolinger - * Update to reflect thread_pool_block() -> thread_pool_get_act() name - * change. - * [1994/01/14 18:18:40 bolinger] - * - * Revision 1.1.2.1 1994/01/12 17:53:21 dwm - * Coloc: initial restructuring to follow Utah model. - * [1994/01/12 17:15:24 dwm] - * - * $EndLog$ - */ -/* - * Copyright (c) 1993 The University of Utah and - * the Computer Systems Laboratory (CSL). All rights reserved. - * - * 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. - * - * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS - * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF - * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * CSL requests users of this software to return to csl-dist@cs.utah.edu any - * improvements that they make and grant CSL redistribution rights. - * - * Author: Bryan Ford, University of Utah CSL - * - * File: thread_pool.h - * - * Defines the thread_pool: a pool of available activations. - * - */ - -#ifndef _KERN_THREAD_POOL_H_ -#define _KERN_THREAD_POOL_H_ - -#include -#include -#include - -typedef struct thread_pool { - - /* List of available activations, all active but not in use. */ - struct thread_activation *thr_acts; - - /* true if somebody is waiting for an activation from this pool */ - int waiting; - -} thread_pool, *thread_pool_t; -#define THREAD_POOL_NULL ((thread_pool_t)0) - -/* Exported to kern/startup.c only */ -kern_return_t thread_pool_init(thread_pool_t new_thread_pool); - -/* Get an activation from a thread_pool, blocking if need be */ -extern struct thread_activation *thread_pool_get_act( ipc_port_t ); -extern void thread_pool_put_act( thread_act_t ); - -/* Wake up a waiter upon return to thread_pool */ -extern void thread_pool_wakeup( thread_pool_t ); - -#if MACH_ASSERT -/* - * Debugging support - "watchacts", a patchable selective trigger - */ -extern unsigned int watchacts; /* debug printf trigger */ -#define WA_SCHED 0x001 /* kern/sched_prim.c */ -#define WA_THR 0x002 /* kern/thread.c */ -#define WA_ACT_LNK 0x004 /* kern/thread_act.c act mgmt */ -#define WA_ACT_HDLR 0x008 /* kern/thread_act.c act hldrs */ -#define WA_TASK 0x010 /* kern/task.c */ -#define WA_BOOT 0x020 /* bootstrap,startup.c */ -#define WA_PCB 0x040 /* machine/pcb.c */ -#define WA_PORT 0x080 /* ports + port sets */ -#define WA_EXIT 0x100 /* exit path */ -#define WA_SWITCH 0x200 /* context switch (!!) */ -#define WA_STATE 0x400 /* get/set state (!!) */ -#define WA_ALL (~0) -#endif /* MACH_ASSERT */ - -#endif /* _KERN_THREAD_POOL_H_ */ diff --git a/osfmk/kern/thread_swap.c b/osfmk/kern/thread_swap.c index 6ca031df2..845b98dd4 100644 --- a/osfmk/kern/thread_swap.c +++ b/osfmk/kern/thread_swap.c @@ -64,10 +64,7 @@ #include queue_head_t swapin_queue; -decl_simple_lock_data(,swapin_lock_data) - -#define swapin_lock() simple_lock(&swapin_lock_data) -#define swapin_unlock() simple_unlock(&swapin_lock_data) +decl_simple_lock_data(,swapin_lock) mach_counter_t c_swapin_thread_block; @@ -82,7 +79,7 @@ void swapin_init(void) { queue_init(&swapin_queue); - simple_lock_init(&swapin_lock_data, ETAP_THREAD_SWAPPER); + simple_lock_init(&swapin_lock, ETAP_THREAD_SWAPPER); kernel_thread_with_priority( kernel_task, BASEPRI_PREEMPT - 2, swapin_thread, TRUE, TRUE); @@ -91,11 +88,8 @@ swapin_init(void) /* * thread_swapin: [exported] * - * Place the specified thread in the list of threads to swapin. It - * is assumed that the thread is locked, therefore we are at splsched. - * - * We don't bother with stack_alloc_try to optimize swapin; - * our callers have already tried that route. + * Place the specified thread in the list of threads to swapin. + * Called with thread locked, returned unlocked. */ void @@ -106,23 +100,24 @@ thread_swapin( case TH_STACK_HANDOFF: /* - * Swapped out - queue for swapin thread. + * Swapped out. */ thread->state = (thread->state & ~TH_STACK_STATE) | TH_STACK_ALLOC; - swapin_lock(); + thread_unlock(thread); + simple_lock(&swapin_lock); enqueue_tail(&swapin_queue, (queue_entry_t) thread); - swapin_unlock(); - thread_wakeup((event_t) &swapin_queue); + simple_unlock(&swapin_lock); + thread_wakeup((event_t)&swapin_queue); break; - case TH_STACK_ALLOC: + case TH_STACK_ALLOC: /* - * Already queued for swapin thread, or being - * swapped in. + * Already queued. */ + thread_unlock(thread); break; - default: + default: /* * Already swapped in. */ @@ -134,8 +129,7 @@ thread_swapin( * thread_doswapin: * * Swapin the specified thread, if it should be runnable, then put - * it on a run queue. No locks should be held on entry, as it is - * likely that this routine will sleep (waiting for stack allocation). + * it on a run queue. */ void thread_doswapin( @@ -153,12 +147,11 @@ thread_doswapin( /* * Place on run queue. */ - s = splsched(); thread_lock(thread); thread->state &= ~(TH_STACK_HANDOFF | TH_STACK_ALLOC); if (thread->state & TH_RUN) - thread_setrun(thread, TRUE, FALSE); + thread_setrun(thread, HEAD_Q); thread_unlock(thread); (void) splx(s); } @@ -174,33 +167,25 @@ swapin_thread_continue(void) { register thread_t thread; -#if defined(__i386__) -loop: -#endif (void)splsched(); - swapin_lock(); + simple_lock(&swapin_lock); while ((thread = (thread_t)dequeue_head(&swapin_queue)) != THREAD_NULL) { - swapin_unlock(); + simple_unlock(&swapin_lock); (void)spllo(); thread_doswapin(thread); (void)splsched(); - swapin_lock(); + simple_lock(&swapin_lock); } - assert_wait((event_t) &swapin_queue, THREAD_UNINT); - swapin_unlock(); + assert_wait((event_t)&swapin_queue, THREAD_UNINT); + simple_unlock(&swapin_lock); (void)spllo(); counter(c_swapin_thread_block++); -#if defined (__i386__) - thread_block((void (*)(void)) 0); - goto loop; -#else thread_block(swapin_thread_continue); -#endif /*NOTREACHED*/ } diff --git a/osfmk/kern/time_out.h b/osfmk/kern/time_out.h index 66b105af0..f5ec5c019 100644 --- a/osfmk/kern/time_out.h +++ b/osfmk/kern/time_out.h @@ -60,10 +60,14 @@ #include #include +#include + +#ifdef __APPLE_API_PRIVATE + extern int hz; /* num of ticks per second */ extern int tick; /* num of usec per tick */ -#ifdef MACH_KERNEL_PRIVATE +#ifdef MACH_KERNEL_PRIVATE extern void hertz_tick( boolean_t usermode, /* executing user code */ @@ -84,4 +88,6 @@ extern void untimeout( #endif /* MACH_KERNEL_PRIVATE */ +#endif /* __APPLE_API_PRIVATE */ + #endif /* _KERN_TIME_OUT_H_ */ diff --git a/osfmk/kern/timer_call.c b/osfmk/kern/timer_call.c index 66d69a833..b65df6b25 100644 --- a/osfmk/kern/timer_call.c +++ b/osfmk/kern/timer_call.c @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -43,8 +44,6 @@ queue_head_t delayed_call_queues[NCPUS]; static struct { - int pending_num, - pending_hiwat; int delayed_num, delayed_hiwat; } timer_calls; @@ -131,30 +130,6 @@ _delayed_call_dequeue( call->state = IDLE; } -static __inline__ -void -_pending_call_enqueue( - queue_t queue, - timer_call_t call) -{ - enqueue_tail(queue, qe(call)); - if (++timer_calls.pending_num > timer_calls.pending_hiwat) - timer_calls.pending_hiwat = timer_calls.pending_num; - - call->state = PENDING; -} - -static __inline__ -void -_pending_call_dequeue( - timer_call_t call) -{ - (void)remque(qe(call)); - timer_calls.pending_num--; - - call->state = IDLE; -} - static __inline__ void _set_delayed_call_timer( @@ -175,11 +150,9 @@ timer_call_enter( s = splclock(); simple_lock(&timer_call_lock); - if (call->state == PENDING) - _pending_call_dequeue(call); - else if (call->state == DELAYED) + if (call->state == DELAYED) _delayed_call_dequeue(call); - else if (call->state == IDLE) + else result = FALSE; call->param1 = 0; @@ -211,11 +184,9 @@ timer_call_enter1( s = splclock(); simple_lock(&timer_call_lock); - if (call->state == PENDING) - _pending_call_dequeue(call); - else if (call->state == DELAYED) + if (call->state == DELAYED) _delayed_call_dequeue(call); - else if (call->state == IDLE) + else result = FALSE; call->param1 = param1; @@ -244,9 +215,7 @@ timer_call_cancel( s = splclock(); simple_lock(&timer_call_lock); - if (call->state == PENDING) - _pending_call_dequeue(call); - else if (call->state == DELAYED) + if (call->state == DELAYED) _delayed_call_dequeue(call); else result = FALSE; @@ -280,6 +249,42 @@ timer_call_is_delayed( return (result); } +/* + * Called at splclock. + */ + +void +timer_call_shutdown( + processor_t processor) +{ + timer_call_t call; + queue_t delayed, delayed1; + + assert(processor != current_processor()); + + delayed = &delayed_call_queues[processor->slot_num]; + delayed1 = &delayed_call_queues[cpu_number()]; + + simple_lock(&timer_call_lock); + + call = TC(queue_first(delayed)); + + while (!queue_end(delayed, qe(call))) { + _delayed_call_dequeue(call); + + _delayed_call_enqueue(delayed1, call); + + call = TC(queue_first(delayed)); + } + + call = TC(queue_first(delayed1)); + + if (!queue_end(delayed1, qe(call))) + _set_delayed_call_timer(call); + + simple_unlock(&timer_call_lock); +} + static void timer_call_interrupt( diff --git a/osfmk/kern/timer_call.h b/osfmk/kern/timer_call.h index 632dcb5a4..bc5ef3773 100644 --- a/osfmk/kern/timer_call.h +++ b/osfmk/kern/timer_call.h @@ -75,6 +75,10 @@ timer_call_setup( timer_call_func_t func, timer_call_param_t param0); +void +timer_call_shutdown( + processor_t processor); + #endif /* MACH_KERNEL_PRIVATE */ #endif /* _KERN_TIMER_CALL_H_ */ diff --git a/osfmk/kern/wait_queue.c b/osfmk/kern/wait_queue.c index fc08865c4..d44cd9ec9 100644 --- a/osfmk/kern/wait_queue.c +++ b/osfmk/kern/wait_queue.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -65,197 +65,283 @@ #include #include #include - #include + #include -void +/* + * Routine: wait_queue_init + * Purpose: + * Initialize a previously allocated wait queue. + * Returns: + * KERN_SUCCESS - The wait_queue_t was initialized + * KERN_INVALID_ARGUMENT - The policy parameter was invalid + */ +kern_return_t wait_queue_init( - wait_queue_t wq, + wait_queue_t wq, int policy) { - wq->wq_fifo = (policy == SYNC_POLICY_FIFO); - wq->wq_issub = FALSE; + if (!((policy & SYNC_POLICY_ORDER_MASK) == SYNC_POLICY_FIFO)) + return KERN_INVALID_ARGUMENT; + + wq->wq_fifo = TRUE; + wq->wq_type = _WAIT_QUEUE_inited; queue_init(&wq->wq_queue); hw_lock_init(&wq->wq_interlock); -} - -void -wait_queue_sub_init( - wait_queue_sub_t wqsub, - int policy) -{ - wait_queue_init(&wqsub->wqs_wait_queue, policy); - wqsub->wqs_wait_queue.wq_issub = TRUE; - if ( policy & SYNC_POLICY_PREPOST) { - wqsub->wqs_wait_queue.wq_isprepost = TRUE; - wqsub->wqs_refcount = 0; - } else - wqsub->wqs_wait_queue.wq_isprepost = FALSE; - queue_init(&wqsub->wqs_sublinks); -} - -void -wait_queue_sub_clearrefs( - wait_queue_sub_t wq_sub) -{ - assert(wait_queue_is_sub(wq_sub)); - - wqs_lock(wq_sub); - - wq_sub->wqs_refcount = 0; - - wqs_unlock(wq_sub); - -} - -void -wait_queue_link_init( - wait_queue_link_t wql) -{ - queue_init(&wql->wql_links); - queue_init(&wql->wql_sublinks); - wql->wql_queue = WAIT_QUEUE_NULL; - wql->wql_subqueue = WAIT_QUEUE_SUB_NULL; - wql->wql_event = NO_EVENT; + return KERN_SUCCESS; } /* - * Routine: wait_queue_alloc - * Purpose: - * Allocate and initialize a wait queue for use outside of - * of the mach part of the kernel. - * - * Conditions: - * Nothing locked - can block. - * - * Returns: - * The allocated and initialized wait queue - * WAIT_QUEUE_NULL if there is a resource shortage + * Routine: wait_queue_alloc + * Purpose: + * Allocate and initialize a wait queue for use outside of + * of the mach part of the kernel. + * Conditions: + * Nothing locked - can block. + * Returns: + * The allocated and initialized wait queue + * WAIT_QUEUE_NULL if there is a resource shortage */ wait_queue_t wait_queue_alloc( - int policy) + int policy) { wait_queue_t wq; + kern_return_t ret; wq = (wait_queue_t) kalloc(sizeof(struct wait_queue)); - if (wq != WAIT_QUEUE_NULL) - wait_queue_init(wq, policy); + if (wq != WAIT_QUEUE_NULL) { + ret = wait_queue_init(wq, policy); + if (ret != KERN_SUCCESS) { + kfree((vm_offset_t)wq, sizeof(struct wait_queue)); + wq = WAIT_QUEUE_NULL; + } + } return wq; } /* - * Routine: wait_queue_free - * Purpose: - * Free an allocated wait queue. - * - * Conditions: - * Nothing locked - can block. + * Routine: wait_queue_free + * Purpose: + * Free an allocated wait queue. + * Conditions: + * May block. */ -void +kern_return_t wait_queue_free( wait_queue_t wq) { - assert(queue_empty(&wq->wq_queue)); + if (!wait_queue_is_queue(wq)) + return KERN_INVALID_ARGUMENT; + if (!queue_empty(&wq->wq_queue)) + return KERN_FAILURE; kfree((vm_offset_t)wq, sizeof(struct wait_queue)); + return KERN_SUCCESS; } - /* - * Routine: wait_queue_lock + * Routine: wait_queue_set_init * Purpose: - * Lock the wait queue. - * Conditions: - * the appropriate spl level (if any) is already raised. + * Initialize a previously allocated wait queue set. + * Returns: + * KERN_SUCCESS - The wait_queue_set_t was initialized + * KERN_INVALID_ARGUMENT - The policy parameter was invalid */ -void -wait_queue_lock( - wait_queue_t wq) +kern_return_t +wait_queue_set_init( + wait_queue_set_t wqset, + int policy) { -#ifdef __ppc__ - vm_offset_t pc; - - /* - * Double the standard lock timeout, because wait queues tend - * to iterate over a number of threads - locking each. If there is - * a problem with a thread lock, it normally times out at the wait - * queue level first, hiding the real problem. - */ - pc = GET_RETURN_PC(&wq); - if (!hw_lock_to(&wq->wq_interlock, LockTimeOut * 2)) { - panic("wait queue deadlock detection - wq=0x%x, cpu=%d, ret=0x%x\n", wq, cpu_number(), pc); - } -#else - hw_lock_lock(&wq->wq_interlock); -#endif + kern_return_t ret; + + ret = wait_queue_init(&wqset->wqs_wait_queue, policy); + if (ret != KERN_SUCCESS) + return ret; + + wqset->wqs_wait_queue.wq_type = _WAIT_QUEUE_SET_inited; + if (policy & SYNC_POLICY_PREPOST) + wqset->wqs_wait_queue.wq_isprepost = TRUE; + else + wqset->wqs_wait_queue.wq_isprepost = FALSE; + queue_init(&wqset->wqs_setlinks); + wqset->wqs_refcount = 0; + return KERN_SUCCESS; +} + +/* legacy API */ +kern_return_t +wait_queue_sub_init( + wait_queue_set_t wqset, + int policy) +{ + return wait_queue_set_init(wqset, policy); } /* - * Routine: wait_queue_lock_try + * Routine: wait_queue_set_alloc * Purpose: - * Try to lock the wait queue without waiting + * Allocate and initialize a wait queue set for + * use outside of the mach part of the kernel. * Conditions: - * the appropriate spl level (if any) is already raised. - * Returns: - * TRUE if the lock was acquired - * FALSE if we would have needed to wait + * May block. + * Returns: + * The allocated and initialized wait queue set + * WAIT_QUEUE_SET_NULL if there is a resource shortage */ -boolean_t -wait_queue_lock_try( - wait_queue_t wq) +wait_queue_set_t +wait_queue_set_alloc( + int policy) { - return hw_lock_try(&wq->wq_interlock); + wait_queue_set_t wq_set; + + wq_set = (wait_queue_set_t) kalloc(sizeof(struct wait_queue_set)); + if (wq_set != WAIT_QUEUE_SET_NULL) { + kern_return_t ret; + + ret = wait_queue_set_init(wq_set, policy); + if (ret != KERN_SUCCESS) { + kfree((vm_offset_t)wq_set, sizeof(struct wait_queue_set)); + wq_set = WAIT_QUEUE_SET_NULL; + } + } + return wq_set; } /* - * Routine: wait_queue_unlock - * Purpose: - * unlock the wait queue - * Conditions: - * The wait queue is assumed locked. - * appropriate spl level is still maintained + * Routine: wait_queue_set_free + * Purpose: + * Free an allocated wait queue set + * Conditions: + * May block. */ -void -wait_queue_unlock( - wait_queue_t wq) +kern_return_t +wait_queue_set_free( + wait_queue_set_t wq_set) { - assert(hw_lock_held(&wq->wq_interlock)); + if (!wait_queue_is_set(wq_set)) + return KERN_INVALID_ARGUMENT; - hw_lock_unlock(&wq->wq_interlock); + if (!queue_empty(&wq_set->wqs_wait_queue.wq_queue)) + return KERN_FAILURE; + + kfree((vm_offset_t)wq_set, sizeof(struct wait_queue_set)); + return KERN_SUCCESS; } -int _wait_queue_subordinate; /* phoney event for subordinate wait q elements */ +kern_return_t +wait_queue_sub_clearrefs( + wait_queue_set_t wq_set) +{ + if (!wait_queue_is_set(wq_set)) + return KERN_INVALID_ARGUMENT; + + wqs_lock(wq_set); + wq_set->wqs_refcount = 0; + wqs_unlock(wq_set); + return KERN_SUCCESS; +} + +/* + * + * Routine: wait_queue_set_size + * Routine: wait_queue_link_size + * Purpose: + * Return the size of opaque wait queue structures + */ +unsigned int wait_queue_set_size(void) { return sizeof(WaitQueueSet); } +unsigned int wait_queue_link_size(void) { return sizeof(WaitQueueLink); } + +/* declare a unique type for wait queue link structures */ +static unsigned int _wait_queue_link; +static unsigned int _wait_queue_unlinked; + +#define WAIT_QUEUE_LINK ((void *)&_wait_queue_link) +#define WAIT_QUEUE_UNLINKED ((void *)&_wait_queue_unlinked) + +#define WAIT_QUEUE_ELEMENT_CHECK(wq, wqe) \ + WQASSERT(((wqe)->wqe_queue == (wq) && \ + queue_next(queue_prev((queue_t) (wqe))) == (queue_t)(wqe)), \ + "wait queue element list corruption: wq=%#x, wqe=%#x", \ + (wq), (wqe)) + +#define WQSPREV(wqs, wql) ((wait_queue_link_t)queue_prev( \ + ((&(wqs)->wqs_setlinks == (queue_t)(wql)) ? \ + (queue_t)(wql) : &(wql)->wql_setlinks))) + +#define WQSNEXT(wqs, wql) ((wait_queue_link_t)queue_next( \ + ((&(wqs)->wqs_setlinks == (queue_t)(wql)) ? \ + (queue_t)(wql) : &(wql)->wql_setlinks))) + +#define WAIT_QUEUE_SET_LINK_CHECK(wqs, wql) \ + WQASSERT((((wql)->wql_type == WAIT_QUEUE_LINK) && \ + ((wql)->wql_setqueue == (wqs)) && \ + ((wql)->wql_queue->wq_type == _WAIT_QUEUE_inited) && \ + (WQSNEXT((wqs), WQSPREV((wqs),(wql))) == (wql))), \ + "wait queue set links corruption: wqs=%#x, wql=%#x", \ + (wqs), (wql)) + +#if defined(_WAIT_QUEUE_DEBUG_) + +#define WQASSERT(e, s, p0, p1) ((e) ? 0 : panic(s, p0, p1)) + +#define WAIT_QUEUE_CHECK(wq) \ +MACRO_BEGIN \ + queue_t q2 = &(wq)->wq_queue; \ + wait_queue_element_t wqe2 = (wait_queue_element_t) queue_first(q2); \ + while (!queue_end(q2, (queue_entry_t)wqe2)) { \ + WAIT_QUEUE_ELEMENT_CHECK((wq), wqe2); \ + wqe2 = (wait_queue_element_t) queue_next((queue_t) wqe2); \ + } \ +MACRO_END + +#define WAIT_QUEUE_SET_CHECK(wqs) \ +MACRO_BEGIN \ + queue_t q2 = &(wqs)->wqs_setlinks; \ + wait_queue_link_t wql2 = (wait_queue_link_t) queue_first(q2); \ + while (!queue_end(q2, (queue_entry_t)wql2)) { \ + WAIT_QUEUE_SET_LINK_CHECK((wqs), wql2); \ + wql2 = (wait_queue_link_t) wql2->wql_setlinks.next; \ + } \ +MACRO_END + +#else /* !_WAIT_QUEUE_DEBUG_ */ + +#define WQASSERT(e, s, p0, p1) assert(e) + +#define WAIT_QUEUE_CHECK(wq) +#define WAIT_QUEUE_SET_CHECK(wqs) + +#endif /* !_WAIT_QUEUE_DEBUG_ */ - /* * Routine: wait_queue_member_locked * Purpose: - * Indicate if this sub queue is a member of the queue + * Indicate if this set queue is a member of the queue * Conditions: * The wait queue is locked - * The sub queue is just that, a sub queue + * The set queue is just that, a set queue */ -boolean_t +__private_extern__ boolean_t wait_queue_member_locked( wait_queue_t wq, - wait_queue_sub_t wq_sub) + wait_queue_set_t wq_set) { wait_queue_element_t wq_element; queue_t q; assert(wait_queue_held(wq)); - assert(wait_queue_is_sub(wq_sub)); + assert(wait_queue_is_set(wq_set)); q = &wq->wq_queue; wq_element = (wait_queue_element_t) queue_first(q); while (!queue_end(q, (queue_entry_t)wq_element)) { - - if ((wq_element->wqe_event == WAIT_QUEUE_SUBORDINATE)) { + WAIT_QUEUE_ELEMENT_CHECK(wq, wq_element); + if ((wq_element->wqe_type == WAIT_QUEUE_LINK)) { wait_queue_link_t wql = (wait_queue_link_t)wq_element; - if (wql->wql_subqueue == wq_sub) + if (wql->wql_setqueue == wq_set) return TRUE; } wq_element = (wait_queue_element_t) @@ -268,217 +354,323 @@ wait_queue_member_locked( /* * Routine: wait_queue_member * Purpose: - * Indicate if this sub queue is a member of the queue + * Indicate if this set queue is a member of the queue * Conditions: - * The sub queue is just that, a sub queue + * The set queue is just that, a set queue */ boolean_t wait_queue_member( wait_queue_t wq, - wait_queue_sub_t wq_sub) + wait_queue_set_t wq_set) { boolean_t ret; spl_t s; - assert(wait_queue_is_sub(wq_sub)); + if (!wait_queue_is_set(wq_set)) + return FALSE; s = splsched(); wait_queue_lock(wq); - ret = wait_queue_member_locked(wq, wq_sub); + ret = wait_queue_member_locked(wq, wq_set); wait_queue_unlock(wq); splx(s); return ret; } + /* - * Routine: wait_queue_link + * Routine: wait_queue_link_noalloc * Purpose: - * Insert a subordinate wait queue into a wait queue. This + * Insert a set wait queue into a wait queue. This * requires us to link the two together using a wait_queue_link * structure that we allocate. * Conditions: - * The wait queue being inserted must be inited as a sub queue - * The sub waitq is not already linked - * + * The wait queue being inserted must be inited as a set queue */ kern_return_t -wait_queue_link( +wait_queue_link_noalloc( wait_queue_t wq, - wait_queue_sub_t wq_sub) + wait_queue_set_t wq_set, + wait_queue_link_t wql) { - wait_queue_link_t wql; + wait_queue_element_t wq_element; + queue_t q; spl_t s; - assert(wait_queue_is_sub(wq_sub)); - assert(!wait_queue_member(wq, wq_sub)); - - wql = (wait_queue_link_t) kalloc(sizeof(struct wait_queue_link)); - if (wql == WAIT_QUEUE_LINK_NULL) - return KERN_RESOURCE_SHORTAGE; - - wait_queue_link_init(wql); + if (!wait_queue_is_queue(wq) || !wait_queue_is_set(wq_set)) + return KERN_INVALID_ARGUMENT; + /* + * There are probably less threads and sets associated with + * the wait queue, then there are wait queues associated with + * the set. So lets validate it that way. + */ s = splsched(); wait_queue_lock(wq); - wqs_lock(wq_sub); + q = &wq->wq_queue; + wq_element = (wait_queue_element_t) queue_first(q); + while (!queue_end(q, (queue_entry_t)wq_element)) { + WAIT_QUEUE_ELEMENT_CHECK(wq, wq_element); + if (wq_element->wqe_type == WAIT_QUEUE_LINK && + ((wait_queue_link_t)wq_element)->wql_setqueue == wq_set) { + wait_queue_unlock(wq); + splx(s); + return KERN_ALREADY_IN_SET; + } + wq_element = (wait_queue_element_t) + queue_next((queue_t) wq_element); + } + + /* + * Not already a member, so we can add it. + */ + wqs_lock(wq_set); + + WAIT_QUEUE_SET_CHECK(wq_set); wql->wql_queue = wq; - wql->wql_subqueue = wq_sub; - wql->wql_event = WAIT_QUEUE_SUBORDINATE; queue_enter(&wq->wq_queue, wql, wait_queue_link_t, wql_links); - queue_enter(&wq_sub->wqs_sublinks, wql, wait_queue_link_t, wql_sublinks); - - wqs_unlock(wq_sub); + wql->wql_setqueue = wq_set; + queue_enter(&wq_set->wqs_setlinks, wql, wait_queue_link_t, wql_setlinks); + wql->wql_type = WAIT_QUEUE_LINK; + + wqs_unlock(wq_set); wait_queue_unlock(wq); splx(s); return KERN_SUCCESS; } + /* - * Routine: wait_queue_link_noalloc + * Routine: wait_queue_link * Purpose: - * Insert a subordinate wait queue into a wait queue. This + * Insert a set wait queue into a wait queue. This * requires us to link the two together using a wait_queue_link * structure that we allocate. * Conditions: - * The wait queue being inserted must be inited as a sub queue - * The sub waitq is not already linked - * + * The wait queue being inserted must be inited as a set queue */ kern_return_t -wait_queue_link_noalloc( +wait_queue_link( wait_queue_t wq, - wait_queue_sub_t wq_sub, - wait_queue_link_t wql) + wait_queue_set_t wq_set) { - spl_t s; + wait_queue_link_t wql; + kern_return_t ret; - assert(wait_queue_is_sub(wq_sub)); - assert(!wait_queue_member(wq, wq_sub)); + wql = (wait_queue_link_t) kalloc(sizeof(struct wait_queue_link)); + if (wql == WAIT_QUEUE_LINK_NULL) + return KERN_RESOURCE_SHORTAGE; - wait_queue_link_init(wql); + ret = wait_queue_link_noalloc(wq, wq_set, wql); + if (ret != KERN_SUCCESS) + kfree((vm_offset_t)wql, sizeof(struct wait_queue_link)); - s = splsched(); - wait_queue_lock(wq); - wqs_lock(wq_sub); + return ret; +} - wql->wql_queue = wq; - wql->wql_subqueue = wq_sub; - wql->wql_event = WAIT_QUEUE_SUBORDINATE; - queue_enter(&wq->wq_queue, wql, wait_queue_link_t, wql_links); - queue_enter(&wq_sub->wqs_sublinks, wql, wait_queue_link_t, wql_sublinks); - - wqs_unlock(wq_sub); - wait_queue_unlock(wq); - splx(s); - return KERN_SUCCESS; -} +/* + * Routine: wait_queue_unlink_nofree + * Purpose: + * Undo the linkage between a wait queue and a set. + */ +static void +wait_queue_unlink_locked( + wait_queue_t wq, + wait_queue_set_t wq_set, + wait_queue_link_t wql) +{ + assert(wait_queue_held(wq)); + assert(wait_queue_held(&wq_set->wqs_wait_queue)); + + wql->wql_queue = WAIT_QUEUE_NULL; + queue_remove(&wq->wq_queue, wql, wait_queue_link_t, wql_links); + wql->wql_setqueue = WAIT_QUEUE_SET_NULL; + queue_remove(&wq_set->wqs_setlinks, wql, wait_queue_link_t, wql_setlinks); + wql->wql_type = WAIT_QUEUE_UNLINKED; + + WAIT_QUEUE_CHECK(wq); + WAIT_QUEUE_SET_CHECK(wq_set); +} /* * Routine: wait_queue_unlink * Purpose: - * Remove the linkage between a wait queue and its subordinate. + * Remove the linkage between a wait queue and a set, + * freeing the linkage structure. * Conditions: - * The wait queue being must be a member sub queue + * The wait queue being must be a member set queue */ kern_return_t wait_queue_unlink( wait_queue_t wq, - wait_queue_sub_t wq_sub) + wait_queue_set_t wq_set) { wait_queue_element_t wq_element; + wait_queue_link_t wql; queue_t q; spl_t s; - assert(wait_queue_is_sub(wq_sub)); - assert(wait_queue_member(wq, wq_sub)); - + if (!wait_queue_is_queue(wq) || !wait_queue_is_set(wq_set)) { + return KERN_INVALID_ARGUMENT; + } s = splsched(); wait_queue_lock(wq); - wqs_lock(wq_sub); q = &wq->wq_queue; - wq_element = (wait_queue_element_t) queue_first(q); while (!queue_end(q, (queue_entry_t)wq_element)) { - - if (wq_element->wqe_event == WAIT_QUEUE_SUBORDINATE) { - wait_queue_link_t wql = (wait_queue_link_t)wq_element; - queue_t sq; + WAIT_QUEUE_ELEMENT_CHECK(wq, wq_element); + if (wq_element->wqe_type == WAIT_QUEUE_LINK) { + wql = (wait_queue_link_t)wq_element; - if (wql->wql_subqueue == wq_sub) { - sq = &wq_sub->wqs_sublinks; - queue_remove(q, wql, wait_queue_link_t, wql_links); - queue_remove(sq, wql, wait_queue_link_t, wql_sublinks); - wqs_unlock(wq_sub); + if (wql->wql_setqueue == wq_set) { + wqs_lock(wq_set); + wait_queue_unlink_locked(wq, wq_set, wql); + wqs_unlock(wq_set); wait_queue_unlock(wq); splx(s); - kfree((vm_offset_t)wql,sizeof(struct wait_queue_link)); - return; + kfree((vm_offset_t)wql, sizeof(struct wait_queue_link)); + return KERN_SUCCESS; } } - wq_element = (wait_queue_element_t) + queue_next((queue_t) wq_element); + } + wait_queue_unlock(wq); + splx(s); + return KERN_NOT_IN_SET; +} + + +/* + * Routine: wait_queue_unlinkall_nofree + * Purpose: + * Remove the linkage between a wait queue and all its + * sets. The caller is responsible for freeing + * the wait queue link structures. + */ + +kern_return_t +wait_queue_unlinkall_nofree( + wait_queue_t wq) +{ + wait_queue_element_t wq_element; + wait_queue_element_t wq_next_element; + wait_queue_set_t wq_set; + wait_queue_link_t wql; + queue_head_t links_queue_head; + queue_t links = &links_queue_head; + queue_t q; + spl_t s; + + if (!wait_queue_is_queue(wq)) { + return KERN_INVALID_ARGUMENT; + } + + queue_init(links); + + s = splsched(); + wait_queue_lock(wq); + + q = &wq->wq_queue; + + wq_element = (wait_queue_element_t) queue_first(q); + while (!queue_end(q, (queue_entry_t)wq_element)) { + WAIT_QUEUE_ELEMENT_CHECK(wq, wq_element); + wq_next_element = (wait_queue_element_t) queue_next((queue_t) wq_element); + + if (wq_element->wqe_type == WAIT_QUEUE_LINK) { + wql = (wait_queue_link_t)wq_element; + wq_set = wql->wql_setqueue; + wqs_lock(wq_set); + wait_queue_unlink_locked(wq, wq_set, wql); + wqs_unlock(wq_set); + } + wq_element = wq_next_element; } - panic("wait_queue_unlink"); + wait_queue_unlock(wq); + splx(s); + return(KERN_SUCCESS); } + /* - * Routine: wait_queue_unlink_nofree + * Routine: wait_queue_unlink_all * Purpose: - * Remove the linkage between a wait queue and its subordinate. Do not deallcoate the wql + * Remove the linkage between a wait queue and all its sets. + * All the linkage structures are freed. * Conditions: - * The wait queue being must be a member sub queue + * Nothing of interest locked. */ + kern_return_t -wait_queue_unlink_nofree( - wait_queue_t wq, - wait_queue_sub_t wq_sub) +wait_queue_unlink_all( + wait_queue_t wq) { wait_queue_element_t wq_element; + wait_queue_element_t wq_next_element; + wait_queue_set_t wq_set; + wait_queue_link_t wql; + queue_head_t links_queue_head; + queue_t links = &links_queue_head; queue_t q; + spl_t s; - assert(wait_queue_is_sub(wq_sub)); + if (!wait_queue_is_queue(wq)) { + return KERN_INVALID_ARGUMENT; + } + + queue_init(links); + + s = splsched(); + wait_queue_lock(wq); q = &wq->wq_queue; wq_element = (wait_queue_element_t) queue_first(q); while (!queue_end(q, (queue_entry_t)wq_element)) { + WAIT_QUEUE_ELEMENT_CHECK(wq, wq_element); + wq_next_element = (wait_queue_element_t) + queue_next((queue_t) wq_element); - if (wq_element->wqe_event == WAIT_QUEUE_SUBORDINATE) { - wait_queue_link_t wql = (wait_queue_link_t)wq_element; - queue_t sq; - - if (wql->wql_subqueue == wq_sub) { - sq = &wq_sub->wqs_sublinks; - queue_remove(q, wql, wait_queue_link_t, wql_links); - queue_remove(sq, wql, wait_queue_link_t, wql_sublinks); - return(KERN_SUCCESS); - } + if (wq_element->wqe_type == WAIT_QUEUE_LINK) { + wql = (wait_queue_link_t)wq_element; + wq_set = wql->wql_setqueue; + wqs_lock(wq_set); + wait_queue_unlink_locked(wq, wq_set, wql); + wqs_unlock(wq_set); + enqueue(links, &wql->wql_links); } + wq_element = wq_next_element; + } + wait_queue_unlock(wq); + splx(s); - wq_element = (wait_queue_element_t) - queue_next((queue_t) wq_element); + while(!queue_empty(links)) { + wql = (wait_queue_link_t) dequeue(links); + kfree((vm_offset_t) wql, sizeof(struct wait_queue_link)); } - /* due to dropping the sub's lock to get to this routine we can see - * no entries in waitqueue. It is valid case, so we should just return - */ - return(KERN_FAILURE); -} + + return(KERN_SUCCESS); +} /* - * Routine: wait_subqueue_unlink_all + * Routine: wait_queue_set_unlink_all_nofree * Purpose: - * Remove the linkage between a wait queue and its subordinate. + * Remove the linkage between a set wait queue and all its + * member wait queues. The link structures are not freed, nor + * returned. It is the caller's responsibility to track and free + * them. * Conditions: - * The wait queue being must be a member sub queue + * The wait queue being must be a member set queue */ kern_return_t -wait_subqueue_unlink_all( - wait_queue_sub_t wq_sub) +wait_queue_set_unlink_all_nofree( + wait_queue_set_t wq_set) { wait_queue_link_t wql; wait_queue_t wq; @@ -486,103 +678,116 @@ wait_subqueue_unlink_all( kern_return_t kret; spl_t s; - assert(wait_queue_is_sub(wq_sub)); + if (!wait_queue_is_set(wq_set)) { + return KERN_INVALID_ARGUMENT; + } retry: s = splsched(); - wqs_lock(wq_sub); + wqs_lock(wq_set); - q = &wq_sub->wqs_sublinks; + q = &wq_set->wqs_setlinks; wql = (wait_queue_link_t)queue_first(q); while (!queue_end(q, (queue_entry_t)wql)) { + WAIT_QUEUE_SET_LINK_CHECK(wq_set, wql); wq = wql->wql_queue; if (wait_queue_lock_try(wq)) { -#if 0 - queue_t q1; - - q1 = &wq->wq_queue; - - queue_remove(q1, wql, wait_queue_link_t, wql_links); - queue_remove(q, wql, wait_queue_link_t, wql_sublinks); -#else - if ((kret = wait_queue_unlink_nofree(wq, wq_sub)) != KERN_SUCCESS) { - queue_remove(q, wql, wait_queue_link_t, wql_sublinks); - -} -#endif - wait_queue_unlock(wq); - wql = (wait_queue_link_t)queue_first(q); + wait_queue_unlink_locked(wq, wq_set, wql); + wait_queue_unlock(wq); + wql = (wait_queue_link_t)queue_first(q); } else { - wqs_unlock(wq_sub); + wqs_unlock(wq_set); splx(s); - mutex_pause(); + delay(1); goto retry; } } - wqs_unlock(wq_sub); + wqs_unlock(wq_set); splx(s); + return(KERN_SUCCESS); } +/* legacy interface naming */ +kern_return_t +wait_subqueue_unlink_all( + wait_queue_set_t wq_set) +{ + return wait_queue_set_unlink_all_nofree(wq_set); +} + /* - * Routine: wait_queue_unlinkall_nofree + * Routine: wait_queue_set_unlink_all * Purpose: - * Remove the linkage between a wait queue and all subordinates. + * Remove the linkage between a set wait queue and all its + * member wait queues. The link structures are freed. + * Conditions: + * The wait queue must be a set */ - kern_return_t -wait_queue_unlinkall_nofree( - wait_queue_t wq) +wait_queue_set_unlink_all( + wait_queue_set_t wq_set) { - wait_queue_element_t wq_element; - wait_queue_sub_t wq_sub; + wait_queue_link_t wql; + wait_queue_t wq; queue_t q; + queue_head_t links_queue_head; + queue_t links = &links_queue_head; + kern_return_t kret; spl_t s; + if (!wait_queue_is_set(wq_set)) { + return KERN_INVALID_ARGUMENT; + } + + queue_init(links); +retry: s = splsched(); - wait_queue_lock(wq); + wqs_lock(wq_set); - q = &wq->wq_queue; + q = &wq_set->wqs_setlinks; - wq_element = (wait_queue_element_t) queue_first(q); - while (!queue_end(q, (queue_entry_t)wq_element)) { - - if (wq_element->wqe_event == WAIT_QUEUE_SUBORDINATE) { - wait_queue_link_t wql = (wait_queue_link_t)wq_element; - queue_t sq; - - wq_sub = wql->wql_subqueue; - wqs_lock(wq_sub); - sq = &wq_sub->wqs_sublinks; - queue_remove(q, wql, wait_queue_link_t, wql_links); - queue_remove(sq, wql, wait_queue_link_t, wql_sublinks); - wqs_unlock(wq_sub); - wq_element = (wait_queue_element_t) queue_first(q); + wql = (wait_queue_link_t)queue_first(q); + while (!queue_end(q, (queue_entry_t)wql)) { + WAIT_QUEUE_SET_LINK_CHECK(wq_set, wql); + wq = wql->wql_queue; + if (wait_queue_lock_try(wq)) { + wait_queue_unlink_locked(wq, wq_set, wql); + wait_queue_unlock(wq); + enqueue(links, &wql->wql_links); + wql = (wait_queue_link_t)queue_first(q); } else { - wq_element = (wait_queue_element_t) - queue_next((queue_t) wq_element); + wqs_unlock(wq_set); + splx(s); + delay(1); + goto retry; } - } - wait_queue_unlock(wq); + wqs_unlock(wq_set); splx(s); + while (!queue_empty (links)) { + wql = (wait_queue_link_t) dequeue(links); + kfree((vm_offset_t)wql, sizeof(struct wait_queue_link)); + } return(KERN_SUCCESS); } + + /* * Routine: wait_queue_unlink_one * Purpose: - * Find and unlink one subordinate wait queue + * Find and unlink one set wait queue * Conditions: * Nothing of interest locked. */ void wait_queue_unlink_one( wait_queue_t wq, - wait_queue_sub_t *wq_subp) + wait_queue_set_t *wq_setp) { wait_queue_element_t wq_element; queue_t q; @@ -592,37 +797,35 @@ wait_queue_unlink_one( wait_queue_lock(wq); q = &wq->wq_queue; - + wq_element = (wait_queue_element_t) queue_first(q); while (!queue_end(q, (queue_entry_t)wq_element)) { - if (wq_element->wqe_event == WAIT_QUEUE_SUBORDINATE) { + if (wq_element->wqe_type == WAIT_QUEUE_LINK) { wait_queue_link_t wql = (wait_queue_link_t)wq_element; - wait_queue_sub_t wq_sub = wql->wql_subqueue; - queue_t sq; - - wqs_lock(wq_sub); - sq = &wq_sub->wqs_sublinks; - queue_remove(q, wql, wait_queue_link_t, wql_links); - queue_remove(sq, wql, wait_queue_link_t, wql_sublinks); - wqs_unlock(wq_sub); + wait_queue_set_t wq_set = wql->wql_setqueue; + + wqs_lock(wq_set); + wait_queue_unlink_locked(wq, wq_set, wql); + wqs_unlock(wq_set); wait_queue_unlock(wq); splx(s); kfree((vm_offset_t)wql,sizeof(struct wait_queue_link)); - *wq_subp = wq_sub; + *wq_setp = wq_set; return; } wq_element = (wait_queue_element_t) - queue_next((queue_t) wq_element); + queue_next((queue_t) wq_element); } wait_queue_unlock(wq); splx(s); - *wq_subp = WAIT_QUEUE_SUB_NULL; -} + *wq_setp = WAIT_QUEUE_SET_NULL; +} + /* - * Routine: wait_queue_assert_wait_locked + * Routine: wait_queue_assert_wait64_locked * Purpose: * Insert the current thread into the supplied wait queue * waiting for a particular event to be posted to that queue. @@ -631,46 +834,46 @@ wait_queue_unlink_one( * The wait queue is assumed locked. * */ -boolean_t -wait_queue_assert_wait_locked( +__private_extern__ wait_result_t +wait_queue_assert_wait64_locked( wait_queue_t wq, - event_t event, - int interruptible, + event64_t event, + wait_interrupt_t interruptible, boolean_t unlock) { - thread_t thread = current_thread(); - boolean_t ret; - - - if (wq->wq_issub && wq->wq_isprepost) { - wait_queue_sub_t wqs = (wait_queue_sub_t)wq; + thread_t thread; + wait_result_t wait_result; - if (wqs->wqs_refcount > 0) { + if (wq->wq_type == _WAIT_QUEUE_SET_inited) { + wait_queue_set_t wqs = (wait_queue_set_t)wq; + if (wqs->wqs_isprepost && wqs->wqs_refcount > 0) { if (unlock) wait_queue_unlock(wq); - return(FALSE); + return(THREAD_AWAKENED); } } - - thread_lock(thread); - + /* * This is the extent to which we currently take scheduling attributes * into account. If the thread is vm priviledged, we stick it at * the front of the queue. Later, these queues will honor the policy * value set at wait_queue_init time. */ - if (thread->vm_privilege) - enqueue_head(&wq->wq_queue, (queue_entry_t) thread); - else - enqueue_tail(&wq->wq_queue, (queue_entry_t) thread); - thread->wait_event = event; - thread->wait_queue = wq; - thread_mark_wait_locked(thread, interruptible); + thread = current_thread(); + thread_lock(thread); + wait_result = thread_mark_wait_locked(thread, interruptible); + if (wait_result == THREAD_WAITING) { + if (thread->vm_privilege) + enqueue_head(&wq->wq_queue, (queue_entry_t) thread); + else + enqueue_tail(&wq->wq_queue, (queue_entry_t) thread); + thread->wait_event = event; + thread->wait_queue = wq; + } thread_unlock(thread); if (unlock) wait_queue_unlock(wq); - return(TRUE); + return(wait_result); } /* @@ -682,18 +885,57 @@ wait_queue_assert_wait_locked( * Conditions: * nothing of interest locked. */ -boolean_t +wait_result_t wait_queue_assert_wait( wait_queue_t wq, event_t event, - int interruptible) + wait_interrupt_t interruptible) { spl_t s; - boolean_t ret; + wait_result_t ret; + + /* If it is an invalid wait queue, you can't wait on it */ + if (!wait_queue_is_valid(wq)) { + thread_t thread = current_thread(); + return (thread->wait_result = THREAD_RESTART); + } + + s = splsched(); + wait_queue_lock(wq); + ret = wait_queue_assert_wait64_locked( + wq, (event64_t)((uint32_t)event), + interruptible, TRUE); + /* wait queue unlocked */ + splx(s); + return(ret); +} + +/* + * Routine: wait_queue_assert_wait64 + * Purpose: + * Insert the current thread into the supplied wait queue + * waiting for a particular event to be posted to that queue. + * Conditions: + * nothing of interest locked. + */ +wait_result_t +wait_queue_assert_wait64( + wait_queue_t wq, + event64_t event, + wait_interrupt_t interruptible) +{ + spl_t s; + wait_result_t ret; + + /* If it is an invalid wait queue, you cant wait on it */ + if (!wait_queue_is_valid(wq)) { + thread_t thread = current_thread(); + return (thread->wait_result = THREAD_RESTART); + } s = splsched(); wait_queue_lock(wq); - ret = wait_queue_assert_wait_locked(wq, event, interruptible, TRUE); + ret = wait_queue_assert_wait64_locked(wq, event, interruptible, TRUE); /* wait queue unlocked */ splx(s); return(ret); @@ -701,24 +943,22 @@ wait_queue_assert_wait( /* - * Routine: wait_queue_select_all + * Routine: _wait_queue_select64_all * Purpose: * Select all threads off a wait queue that meet the * supplied criteria. - * * Conditions: * at splsched * wait queue locked * wake_queue initialized and ready for insertion * possibly recursive - * * Returns: * a queue of locked threads */ -void -_wait_queue_select_all( +static void +_wait_queue_select64_all( wait_queue_t wq, - event_t event, + event64_t event, queue_t wake_queue) { wait_queue_element_t wq_element; @@ -729,33 +969,34 @@ _wait_queue_select_all( wq_element = (wait_queue_element_t) queue_first(q); while (!queue_end(q, (queue_entry_t)wq_element)) { + WAIT_QUEUE_ELEMENT_CHECK(wq, wq_element); wqe_next = (wait_queue_element_t) queue_next((queue_t) wq_element); /* * We may have to recurse if this is a compound wait queue. */ - if (wq_element->wqe_event == WAIT_QUEUE_SUBORDINATE) { + if (wq_element->wqe_type == WAIT_QUEUE_LINK) { wait_queue_link_t wql = (wait_queue_link_t)wq_element; - wait_queue_t sub_queue; + wait_queue_t set_queue; /* - * We have to check the subordinate wait queue. + * We have to check the set wait queue. */ - sub_queue = (wait_queue_t)wql->wql_subqueue; - wait_queue_lock(sub_queue); - if (sub_queue->wq_isprepost) { - wait_queue_sub_t wqs = (wait_queue_sub_t)sub_queue; + set_queue = (wait_queue_t)wql->wql_setqueue; + wait_queue_lock(set_queue); + if (set_queue->wq_isprepost) { + wait_queue_set_t wqs = (wait_queue_set_t)set_queue; /* - * Preposting is only for subordinates and wait queue - * is the first element of subordinate + * Preposting is only for sets and wait queue + * is the first element of set */ wqs->wqs_refcount++; } - if (! wait_queue_empty(sub_queue)) - _wait_queue_select_all(sub_queue, event, wake_queue); - wait_queue_unlock(sub_queue); + if (! wait_queue_empty(set_queue)) + _wait_queue_select64_all(set_queue, event, wake_queue); + wait_queue_unlock(set_queue); } else { /* @@ -770,7 +1011,7 @@ _wait_queue_select_all( remqueue(q, (queue_entry_t) t); enqueue (wake_queue, (queue_entry_t) t); t->wait_queue = WAIT_QUEUE_NULL; - t->wait_event = NO_EVENT; + t->wait_event = NO_EVENT64; t->at_safe_point = FALSE; /* returned locked */ } @@ -780,86 +1021,121 @@ _wait_queue_select_all( } /* - * Routine: wait_queue_wakeup_all_locked - * Purpose: - * Wakeup some number of threads that are in the specified - * wait queue and waiting on the specified event. - * Conditions: - * wait queue already locked (may be released). - * Returns: - * KERN_SUCCESS - Threads were woken up - * KERN_NOT_WAITING - No threads were waiting pair + * Routine: wait_queue_wakeup64_all_locked + * Purpose: + * Wakeup some number of threads that are in the specified + * wait queue and waiting on the specified event. + * Conditions: + * wait queue already locked (may be released). + * Returns: + * KERN_SUCCESS - Threads were woken up + * KERN_NOT_WAITING - No threads were waiting pair */ -kern_return_t -wait_queue_wakeup_all_locked( - wait_queue_t wq, - event_t event, - int result, - boolean_t unlock) +__private_extern__ kern_return_t +wait_queue_wakeup64_all_locked( + wait_queue_t wq, + event64_t event, + wait_result_t result, + boolean_t unlock) { - queue_head_t wake_queue_head; - queue_t q = &wake_queue_head; - kern_return_t ret = KERN_NOT_WAITING; - - assert(wait_queue_held(wq)); - - queue_init(q); - - /* - * Select the threads that we will wake up. The threads - * are returned to us locked and cleanly removed from the - * wait queue. - */ - _wait_queue_select_all(wq, event, q); - if (unlock) - wait_queue_unlock(wq); - - /* - * For each thread, set it running. - */ - while (!queue_empty (q)) { - thread_t thread = (thread_t) dequeue(q); - thread_go_locked(thread, result); - thread_unlock(thread); - ret = KERN_SUCCESS; - } - return ret; + queue_head_t wake_queue_head; + queue_t q = &wake_queue_head; + kern_return_t res; + + assert(wait_queue_held(wq)); + queue_init(q); + + /* + * Select the threads that we will wake up. The threads + * are returned to us locked and cleanly removed from the + * wait queue. + */ + _wait_queue_select64_all(wq, event, q); + if (unlock) + wait_queue_unlock(wq); + + /* + * For each thread, set it running. + */ + res = KERN_NOT_WAITING; + while (!queue_empty (q)) { + thread_t thread = (thread_t) dequeue(q); + res = thread_go_locked(thread, result); + assert(res == KERN_SUCCESS); + thread_unlock(thread); + } + return res; } /* - * Routine: wait_queue_wakeup_all - * Purpose: - * Wakeup some number of threads that are in the specified - * wait queue and waiting on the specified event. - * - * Conditions: - * Nothing locked - * - * Returns: - * KERN_SUCCESS - Threads were woken up - * KERN_NOT_WAITING - No threads were waiting pair + * Routine: wait_queue_wakeup_all + * Purpose: + * Wakeup some number of threads that are in the specified + * wait queue and waiting on the specified event. + * Conditions: + * Nothing locked + * Returns: + * KERN_SUCCESS - Threads were woken up + * KERN_NOT_WAITING - No threads were waiting pair */ kern_return_t wait_queue_wakeup_all( - wait_queue_t wq, - event_t event, - int result) + wait_queue_t wq, + event_t event, + wait_result_t result) +{ + kern_return_t ret; + spl_t s; + + if (!wait_queue_is_valid(wq)) { + return KERN_INVALID_ARGUMENT; + } + + s = splsched(); + wait_queue_lock(wq); + ret = wait_queue_wakeup64_all_locked( + wq, (event64_t)((uint32_t)event), + result, TRUE); + /* lock released */ + splx(s); + return ret; +} + +/* + * Routine: wait_queue_wakeup64_all + * Purpose: + * Wakeup some number of threads that are in the specified + * wait queue and waiting on the specified event. + * Conditions: + * Nothing locked + * Returns: + * KERN_SUCCESS - Threads were woken up + * KERN_NOT_WAITING - No threads were waiting pair + */ +kern_return_t +wait_queue_wakeup64_all( + wait_queue_t wq, + event64_t event, + wait_result_t result) { - kern_return_t ret; - spl_t s; + kern_return_t ret; + spl_t s; - s = splsched(); - wait_queue_lock(wq); - ret = wait_queue_wakeup_all_locked(wq, event, result, TRUE); - /* lock released */ - splx(s); + if (!wait_queue_is_valid(wq)) { + return KERN_INVALID_ARGUMENT; + } - return ret; + s = splsched(); + wait_queue_lock(wq); + ret = wait_queue_wakeup64_all_locked(wq, event, result, TRUE); + /* lock released */ + splx(s); + return ret; } /* - * Routine: wait_queue_select_one + * Routine: _wait_queue_select64_one * Purpose: * Select the best thread off a wait queue that meet the * supplied criteria. @@ -873,10 +1149,10 @@ wait_queue_wakeup_all( * This is where the sync policy of the wait queue comes * into effect. For now, we just assume FIFO. */ -thread_t -_wait_queue_select_one( +static thread_t +_wait_queue_select64_one( wait_queue_t wq, - event_t event) + event64_t event) { wait_queue_element_t wq_element; wait_queue_element_t wqe_next; @@ -889,25 +1165,26 @@ _wait_queue_select_one( wq_element = (wait_queue_element_t) queue_first(q); while (!queue_end(q, (queue_entry_t)wq_element)) { + WAIT_QUEUE_ELEMENT_CHECK(wq, wq_element); wqe_next = (wait_queue_element_t) queue_next((queue_t) wq_element); /* * We may have to recurse if this is a compound wait queue. */ - if (wq_element->wqe_event == WAIT_QUEUE_SUBORDINATE) { + if (wq_element->wqe_type == WAIT_QUEUE_LINK) { wait_queue_link_t wql = (wait_queue_link_t)wq_element; - wait_queue_t sub_queue; + wait_queue_t set_queue; /* - * We have to check the subordinate wait queue. + * We have to check the set wait queue. */ - sub_queue = (wait_queue_t)wql->wql_subqueue; - wait_queue_lock(sub_queue); - if (! wait_queue_empty(sub_queue)) { - t = _wait_queue_select_one(sub_queue, event); + set_queue = (wait_queue_t)wql->wql_setqueue; + wait_queue_lock(set_queue); + if (! wait_queue_empty(set_queue)) { + t = _wait_queue_select64_one(set_queue, event); } - wait_queue_unlock(sub_queue); + wait_queue_unlock(set_queue); if (t != THREAD_NULL) return t; } else { @@ -923,7 +1200,7 @@ _wait_queue_select_one( thread_lock(t); remqueue(q, (queue_entry_t) t); t->wait_queue = WAIT_QUEUE_NULL; - t->wait_event = NO_EVENT; + t->wait_event = NO_EVENT64; t->at_safe_point = FALSE; return t; /* still locked */ } @@ -934,10 +1211,10 @@ _wait_queue_select_one( } /* - * Routine: wait_queue_peek_locked + * Routine: wait_queue_peek64_locked * Purpose: * Select the best thread from a wait queue that meet the - * supplied criteria, but leave it on the queue you it was + * supplied criteria, but leave it on the queue it was * found on. The thread, and the actual wait_queue the * thread was found on are identified. * Conditions: @@ -948,13 +1225,13 @@ _wait_queue_select_one( * a locked thread - if one found * a locked waitq - the one the thread was found on * Note: - * Only the waitq the thread was actually found on is locked - * after this. + * Both the waitq the thread was actually found on, and + * the supplied wait queue, are locked after this. */ -void -wait_queue_peek_locked( +__private_extern__ void +wait_queue_peek64_locked( wait_queue_t wq, - event_t event, + event64_t event, thread_t *tp, wait_queue_t *wqp) { @@ -971,28 +1248,32 @@ wait_queue_peek_locked( wq_element = (wait_queue_element_t) queue_first(q); while (!queue_end(q, (queue_entry_t)wq_element)) { + WAIT_QUEUE_ELEMENT_CHECK(wq, wq_element); wqe_next = (wait_queue_element_t) queue_next((queue_t) wq_element); /* * We may have to recurse if this is a compound wait queue. */ - if (wq_element->wqe_event == WAIT_QUEUE_SUBORDINATE) { + if (wq_element->wqe_type == WAIT_QUEUE_LINK) { wait_queue_link_t wql = (wait_queue_link_t)wq_element; - wait_queue_t sub_queue; + wait_queue_t set_queue; /* - * We have to check the subordinate wait queue. + * We have to check the set wait queue. */ - sub_queue = (wait_queue_t)wql->wql_subqueue; - wait_queue_lock(sub_queue); - if (! wait_queue_empty(sub_queue)) { - wait_queue_peek_locked(sub_queue, event, tp, wqp); + set_queue = (wait_queue_t)wql->wql_setqueue; + wait_queue_lock(set_queue); + if (! wait_queue_empty(set_queue)) { + wait_queue_peek64_locked(set_queue, event, tp, wqp); } - if (*tp != THREAD_NULL) + if (*tp != THREAD_NULL) { + if (*wqp != set_queue) + wait_queue_unlock(set_queue); return; /* thread and its waitq locked */ + } - wait_queue_unlock(sub_queue); + wait_queue_unlock(set_queue); } else { /* @@ -1036,7 +1317,7 @@ wait_queue_pull_thread_locked( remqueue(&waitq->wq_queue, (queue_entry_t)thread ); thread->wait_queue = WAIT_QUEUE_NULL; - thread->wait_event = NO_EVENT; + thread->wait_event = NO_EVENT64; thread->at_safe_point = FALSE; if (unlock) wait_queue_unlock(waitq); @@ -1044,7 +1325,7 @@ wait_queue_pull_thread_locked( /* - * Routine: wait_queue_select_thread + * Routine: wait_queue_select64_thread * Purpose: * Look for a thread and remove it from the queues, if * (and only if) the thread is waiting on the supplied @@ -1057,10 +1338,10 @@ wait_queue_pull_thread_locked( * KERN_NOT_WAITING: Thread is not waiting here. * KERN_SUCCESS: It was, and is now removed (returned locked) */ -kern_return_t -_wait_queue_select_thread( +static kern_return_t +_wait_queue_select64_thread( wait_queue_t wq, - event_t event, + event64_t event, thread_t thread) { wait_queue_element_t wq_element; @@ -1068,13 +1349,11 @@ _wait_queue_select_thread( kern_return_t res = KERN_NOT_WAITING; queue_t q = &wq->wq_queue; - assert(wq->wq_fifo); - thread_lock(thread); if ((thread->wait_queue == wq) && (thread->wait_event == event)) { remqueue(q, (queue_entry_t) thread); thread->at_safe_point = FALSE; - thread->wait_event = NO_EVENT; + thread->wait_event = NO_EVENT64; thread->wait_queue = WAIT_QUEUE_NULL; /* thread still locked */ return KERN_SUCCESS; @@ -1083,26 +1362,27 @@ _wait_queue_select_thread( /* * The wait_queue associated with the thread may be one of this - * wait queue's subordinates. Go see. If so, removing it from + * wait queue's sets. Go see. If so, removing it from * there is like removing it from here. */ wq_element = (wait_queue_element_t) queue_first(q); while (!queue_end(q, (queue_entry_t)wq_element)) { + WAIT_QUEUE_ELEMENT_CHECK(wq, wq_element); wqe_next = (wait_queue_element_t) queue_next((queue_t) wq_element); - if (wq_element->wqe_event == WAIT_QUEUE_SUBORDINATE) { + if (wq_element->wqe_type == WAIT_QUEUE_LINK) { wait_queue_link_t wql = (wait_queue_link_t)wq_element; - wait_queue_t sub_queue; + wait_queue_t set_queue; - sub_queue = (wait_queue_t)wql->wql_subqueue; - wait_queue_lock(sub_queue); - if (! wait_queue_empty(sub_queue)) { - res = _wait_queue_select_thread(sub_queue, + set_queue = (wait_queue_t)wql->wql_setqueue; + wait_queue_lock(set_queue); + if (! wait_queue_empty(set_queue)) { + res = _wait_queue_select64_thread(set_queue, event, thread); } - wait_queue_unlock(sub_queue); + wait_queue_unlock(set_queue); if (res == KERN_SUCCESS) return KERN_SUCCESS; } @@ -1113,7 +1393,7 @@ _wait_queue_select_thread( /* - * Routine: wait_queue_wakeup_identity_locked + * Routine: wait_queue_wakeup64_identity_locked * Purpose: * Select a single thread that is most-eligible to run and set * set it running. But return the thread locked. @@ -1125,29 +1405,33 @@ _wait_queue_select_thread( * Returns: * a pointer to the locked thread that was awakened */ -thread_t -wait_queue_wakeup_identity_locked( +__private_extern__ thread_t +wait_queue_wakeup64_identity_locked( wait_queue_t wq, - event_t event, - int result, + event64_t event, + wait_result_t result, boolean_t unlock) { + kern_return_t res; thread_t thread; assert(wait_queue_held(wq)); - thread = _wait_queue_select_one(wq, event); + + thread = _wait_queue_select64_one(wq, event); if (unlock) wait_queue_unlock(wq); - if (thread) - thread_go_locked(thread, result); + if (thread) { + res = thread_go_locked(thread, result); + assert(res == KERN_SUCCESS); + } return thread; /* still locked if not NULL */ } /* - * Routine: wait_queue_wakeup_one_locked + * Routine: wait_queue_wakeup64_one_locked * Purpose: * Select a single thread that is most-eligible to run and set * set it runnings. @@ -1160,25 +1444,28 @@ wait_queue_wakeup_identity_locked( * KERN_SUCCESS: It was, and is, now removed. * KERN_NOT_WAITING - No thread was waiting pair */ -kern_return_t -wait_queue_wakeup_one_locked( +__private_extern__ kern_return_t +wait_queue_wakeup64_one_locked( wait_queue_t wq, - event_t event, - int result, + event64_t event, + wait_result_t result, boolean_t unlock) { thread_t thread; assert(wait_queue_held(wq)); - thread = _wait_queue_select_one(wq, event); + thread = _wait_queue_select64_one(wq, event); if (unlock) wait_queue_unlock(wq); if (thread) { - thread_go_locked(thread, result); + kern_return_t res; + + res = thread_go_locked(thread, result); + assert(res == KERN_SUCCESS); thread_unlock(thread); - return KERN_SUCCESS; + return res; } return KERN_NOT_WAITING; @@ -1189,10 +1476,8 @@ wait_queue_wakeup_one_locked( * Purpose: * Wakeup the most appropriate thread that is in the specified * wait queue for the specified event. - * * Conditions: * Nothing locked - * * Returns: * KERN_SUCCESS - Thread was woken up * KERN_NOT_WAITING - No thread was waiting pair @@ -1201,34 +1486,82 @@ kern_return_t wait_queue_wakeup_one( wait_queue_t wq, event_t event, - int result) + wait_result_t result) { thread_t thread; spl_t s; + if (!wait_queue_is_valid(wq)) { + return KERN_INVALID_ARGUMENT; + } + s = splsched(); wait_queue_lock(wq); - thread = _wait_queue_select_one(wq, event); + thread = _wait_queue_select64_one(wq, (event64_t)((uint32_t)event)); wait_queue_unlock(wq); if (thread) { - thread_go_locked(thread, result); + kern_return_t res; + + res = thread_go_locked(thread, result); + assert(res == KERN_SUCCESS); thread_unlock(thread); splx(s); - return KERN_SUCCESS; + return res; } splx(s); return KERN_NOT_WAITING; } +/* + * Routine: wait_queue_wakeup64_one + * Purpose: + * Wakeup the most appropriate thread that is in the specified + * wait queue for the specified event. + * Conditions: + * Nothing locked + * Returns: + * KERN_SUCCESS - Thread was woken up + * KERN_NOT_WAITING - No thread was waiting pair + */ +kern_return_t +wait_queue_wakeup64_one( + wait_queue_t wq, + event64_t event, + wait_result_t result) +{ + thread_t thread; + spl_t s; + + if (!wait_queue_is_valid(wq)) { + return KERN_INVALID_ARGUMENT; + } + s = splsched(); + wait_queue_lock(wq); + thread = _wait_queue_select64_one(wq, event); + wait_queue_unlock(wq); + + if (thread) { + kern_return_t res; + + res = thread_go_locked(thread, result); + assert(res == KERN_SUCCESS); + thread_unlock(thread); + splx(s); + return res; + } + + splx(s); + return KERN_NOT_WAITING; +} /* - * Routine: wait_queue_wakeup_thread_locked + * Routine: wait_queue_wakeup64_thread_locked * Purpose: * Wakeup the particular thread that was specified if and only - * it was in this wait queue (or one of it's subordinate queues) + * it was in this wait queue (or one of it's set queues) * and waiting on the specified event. * * This is much safer than just removing the thread from @@ -1243,12 +1576,12 @@ wait_queue_wakeup_one( * KERN_SUCCESS - the thread was found waiting and awakened * KERN_NOT_WAITING - the thread was not waiting here */ -kern_return_t -wait_queue_wakeup_thread_locked( +__private_extern__ kern_return_t +wait_queue_wakeup64_thread_locked( wait_queue_t wq, - event_t event, + event64_t event, thread_t thread, - int result, + wait_result_t result, boolean_t unlock) { kern_return_t res; @@ -1259,23 +1592,24 @@ wait_queue_wakeup_thread_locked( * See if the thread was still waiting there. If so, it got * dequeued and returned locked. */ - res = _wait_queue_select_thread(wq, event, thread); + res = _wait_queue_select64_thread(wq, event, thread); if (unlock) wait_queue_unlock(wq); if (res != KERN_SUCCESS) return KERN_NOT_WAITING; - thread_go_locked(thread, result); + res = thread_go_locked(thread, result); + assert(res == KERN_SUCCESS); thread_unlock(thread); - return KERN_SUCCESS; + return res; } /* * Routine: wait_queue_wakeup_thread * Purpose: * Wakeup the particular thread that was specified if and only - * it was in this wait queue (or one of it's subordinate queues) + * it was in this wait queue (or one of it's set queues) * and waiting on the specified event. * * This is much safer than just removing the thread from @@ -1295,69 +1629,76 @@ wait_queue_wakeup_thread( wait_queue_t wq, event_t event, thread_t thread, - int result) + wait_result_t result) { kern_return_t res; spl_t s; + if (!wait_queue_is_valid(wq)) { + return KERN_INVALID_ARGUMENT; + } + s = splsched(); wait_queue_lock(wq); - res = _wait_queue_select_thread(wq, event, thread); + res = _wait_queue_select64_thread(wq, (event64_t)((uint32_t)event), thread); wait_queue_unlock(wq); if (res == KERN_SUCCESS) { - thread_go_locked(thread, result); + res = thread_go_locked(thread, result); + assert(res == KERN_SUCCESS); thread_unlock(thread); splx(s); - return KERN_SUCCESS; + return res; } splx(s); return KERN_NOT_WAITING; } - /* - * Routine: wait_queue_remove + * Routine: wait_queue_wakeup64_thread * Purpose: - * Normal removal operations from wait queues drive from the - * wait queue to select a thread. However, if a thread is - * interrupted out of a wait, this routine is called to - * remove it from whatever wait queue it may be in. + * Wakeup the particular thread that was specified if and only + * it was in this wait queue (or one of it's set's queues) + * and waiting on the specified event. * + * This is much safer than just removing the thread from + * whatever wait queue it happens to be on. For instance, it + * may have already been awoken from the wait you intended to + * interrupt and waited on something else (like another + * semaphore). * Conditions: - * splsched - * thread locked on entry and exit, but may be dropped. - * + * nothing of interest locked + * we need to assume spl needs to be raised * Returns: - * KERN_SUCCESS - if thread was in a wait queue - * KERN_NOT_WAITING - it was not + * KERN_SUCCESS - the thread was found waiting and awakened + * KERN_NOT_WAITING - the thread was not waiting here */ kern_return_t -wait_queue_remove( - thread_t thread) +wait_queue_wakeup64_thread( + wait_queue_t wq, + event64_t event, + thread_t thread, + wait_result_t result) { - wait_queue_t wq = thread->wait_queue; + kern_return_t res; + spl_t s; - if (wq == WAIT_QUEUE_NULL) - return KERN_NOT_WAITING; + if (!wait_queue_is_valid(wq)) { + return KERN_INVALID_ARGUMENT; + } - /* - * have to get the locks again in the right order. - */ - thread_unlock(thread); + s = splsched(); wait_queue_lock(wq); - thread_lock(thread); - - if (thread->wait_queue == wq) { - remqueue(&wq->wq_queue, (queue_entry_t)thread); - thread->wait_queue = WAIT_QUEUE_NULL; - thread->wait_event = NO_EVENT; - thread->at_safe_point = FALSE; - wait_queue_unlock(wq); - return KERN_SUCCESS; - } else { - wait_queue_unlock(wq); - return KERN_NOT_WAITING; /* anymore */ + res = _wait_queue_select64_thread(wq, event, thread); + wait_queue_unlock(wq); + + if (res == KERN_SUCCESS) { + res = thread_go_locked(thread, result); + assert(res == KERN_SUCCESS); + thread_unlock(thread); + splx(s); + return res; } + splx(s); + return KERN_NOT_WAITING; } - diff --git a/osfmk/kern/wait_queue.h b/osfmk/kern/wait_queue.h index edfb02799..960a07b8d 100644 --- a/osfmk/kern/wait_queue.h +++ b/osfmk/kern/wait_queue.h @@ -22,14 +22,21 @@ #ifndef _KERN_WAIT_QUEUE_H_ #define _KERN_WAIT_QUEUE_H_ -#include /* for wait_queue_t */ +#include + +#ifdef __APPLE_API_PRIVATE + #include #include /* for kern_return_t */ +#include /* for wait_queue_t */ + +#ifdef MACH_KERNEL_PRIVATE #include #include + /* * wait_queue_t * This is the definition of the common event wait queue @@ -44,42 +51,34 @@ * NOTE: Hardware locks are used to protect event wait * queues since interrupt code is free to post events to * them. - * WARNING: Cannot change this data structure without updating SIZEOF_WAITQUEUE */ typedef struct wait_queue { + unsigned int /* flags */ + /* boolean_t */ wq_type:16, /* only public field */ + wq_fifo:1, /* fifo wakeup policy? */ + wq_isprepost:1, /* is waitq preposted? set only */ + :0; /* force to long boundary */ hw_lock_data_t wq_interlock; /* interlock */ - unsigned int /* flags */ - /* boolean_t */ wq_fifo:1, /* fifo wakeup policy? */ - wq_issub:1, /* is waitq linked? */ - wq_isprepost:1, /* is waitq preposted? sub only */ - :0; /* force to long boundary */ - queue_head_t wq_queue; /* queue of elements */ + queue_head_t wq_queue; /* queue of elements */ } WaitQueue; -#define SIZEOF_WAITQUEUE 16 /* 16 bytes for wq */ -#define SIZEOF_WAITQUEUE_SUB 28 /* 24 byets for wqs */ -#define SIZEOF_WAITQUEUE_ELEMENT 16 /* 16 byets per wqe */ -#define SIZEOF_WAITQUEUE_LINK 28 /* 28 byets per wqe */ - -#ifdef MACH_KERNEL_PRIVATE - /* - * wait_queue_sub_t - * This is the common definition for a subordinate wait queue. + * wait_queue_set_t + * This is the common definition for a set wait queue. * These can be linked as members/elements of multiple regular * wait queues. They have an additional set of linkages to * identify the linkage structures that point to them. - * WARNING: Cannot change this data structure without updating SIZEOF_WAITQUEUE_SUB */ -typedef struct wait_queue_sub { - WaitQueue wqs_wait_queue; /* our wait queue */ - queue_head_t wqs_sublinks; /* links from sub perspective */ +typedef struct wait_queue_set { + WaitQueue wqs_wait_queue; /* our wait queue */ + queue_head_t wqs_setlinks; /* links from set perspective */ unsigned int wqs_refcount; /* refcount for preposting */ -} WaitQueueSub; - - -#define WAIT_QUEUE_SUB_NULL ((wait_queue_sub_t)0) +} WaitQueueSet; +#define wqs_type wqs_wait_queue.wq_type +#define wqs_fifo wqs_wait_queue.wq_fifo +#define wqs_isprepost wqs_wait_queue.wq_isprepost +#define wqs_queue wqs_wait_queue.wq_queue /* * wait_queue_element_t @@ -87,23 +86,23 @@ typedef struct wait_queue_sub { * queue. It is the common first fields in a thread shuttle * and wait_queue_link_t. In that way, a wait queue can * consist of both thread shuttle elements and links off of - * to other (subordinate) wait queues. + * to other (set) wait queues. * - * WARNING: The first three fields of the thread shuttle - * definition does not use this definition yet. Any change in + * WARNING: These fields correspond to fields in the thread + * shuttle (run queue links and run queue pointer). Any change in * the layout here will have to be matched with a change there. - * WARNING: Cannot change this data structure without updating SIZEOF_WAITQUEUE_ELEMENT */ typedef struct wait_queue_element { queue_chain_t wqe_links; /* link of elements on this queue */ + void * wqe_type; /* Identifies link vs. thread */ wait_queue_t wqe_queue; /* queue this element is on */ - event_t wqe_event; /* event this element is waiting for */ -} *wait_queue_element_t; +} WaitQueueElement; +typedef WaitQueueElement *wait_queue_element_t; /* * wait_queue_link_t - * Specialized wait queue element type for linking subordinate + * Specialized wait queue element type for linking set * event waits queues onto a wait queue. In this way, an event * can be constructed so that any thread waiting on any number * of associated wait queues can handle the event, while letting @@ -115,162 +114,207 @@ typedef struct wait_queue_element { * event queues of which it is a member. An IPC event post associated * with that port may wake up any thread from any of those portsets, * or one that was waiting locally on the port itself. - * WARNING: Cannot change this data structure without updating SIZEOF_WAITQUEUE_LINK */ typedef struct wait_queue_link { - struct wait_queue_element wql_element; /* element on master */ - queue_chain_t wql_sublinks; /* element on sub */ - wait_queue_sub_t wql_subqueue; /* sub queue */ + WaitQueueElement wql_element; /* element on master */ + queue_chain_t wql_setlinks; /* element on set */ + wait_queue_set_t wql_setqueue; /* set queue */ } WaitQueueLink; - -#define WAIT_QUEUE_LINK_NULL ((wait_queue_link_t)0) - #define wql_links wql_element.wqe_links +#define wql_type wql_element.wqe_type #define wql_queue wql_element.wqe_queue -#define wql_event wql_element.wqe_event - -#define wait_queue_empty(wq) (queue_empty(&(wq)->wq_queue)) - -#define wait_queue_held(wq) (hw_lock_held(&(wq)->wq_interlock)) -#define wait_queue_is_sub(wqs) ((wqs)->wqs_wait_queue.wq_issub) -#define wqs_lock(wqs) wait_queue_lock(&(wqs)->wqs_wait_queue) -#define wqs_unlock(wqs) wait_queue_unlock(&(wqs)->wqs_wait_queue) -#define wqs_lock_try(wqs) wait_queue__try_lock(&(wqs)->wqs_wait_queue) +#define _WAIT_QUEUE_inited 0xf1d0 +#define _WAIT_QUEUE_SET_inited 0xf1d1 -extern int wait_queue_subordinate; -#define WAIT_QUEUE_SUBORDINATE &_wait_queue_subordinate +#define wait_queue_is_queue(wq) \ + ((wq)->wq_type == _WAIT_QUEUE_inited) -extern void wait_queue_init( - wait_queue_t wait_queue, - int policy); +#define wait_queue_is_set(wqs) \ + ((wqs)->wqs_type == _WAIT_QUEUE_SET_inited) -extern kern_return_t wait_queue_link( - wait_queue_t wait_queue, - wait_queue_sub_t subordinate_queue); +#define wait_queue_is_valid(wq) \ + (((wq)->wq_type & ~1) == _WAIT_QUEUE_inited) -extern kern_return_t wait_queue_unlink( - wait_queue_t wait_queue, - wait_queue_sub_t subordinate_queue); -extern void wait_queue_unlink_one( - wait_queue_t wait_queue, - wait_queue_sub_t *subordinate_queue_pointer); +#define wait_queue_empty(wq) (queue_empty(&(wq)->wq_queue)) +#define wait_queue_held(wq) (hw_lock_held(&(wq)->wq_interlock)) +#define wait_queue_lock_try(wq) (hw_lock_try(&(wq)->wq_interlock)) -extern boolean_t wait_queue_member_queue( - wait_queue_t wait_queue, - wait_queue_sub_t subordinate_queue); +/* + * Double the standard lock timeout, because wait queues tend + * to iterate over a number of threads - locking each. If there is + * a problem with a thread lock, it normally times out at the wait + * queue level first, hiding the real problem. + */ +#define wait_queue_lock(wq) \ + ((void) (!hw_lock_to(&(wq)->wq_interlock, LockTimeOut * 2) ? \ + panic("wait queue deadlock - wq=0x%x, cpu=%d\n", \ + wq, cpu_number()) : 0)) -extern kern_return_t clear_wait_queue_internal( - thread_t thread, - int result); +#define wait_queue_unlock(wq) \ + (assert(wait_queue_held(wq)), hw_lock_unlock(&(wq)->wq_interlock)) -extern kern_return_t wait_queue_remove( - thread_t thread); +#define wqs_lock(wqs) wait_queue_lock(&(wqs)->wqs_wait_queue) +#define wqs_unlock(wqs) wait_queue_unlock(&(wqs)->wqs_wait_queue) +#define wqs_lock_try(wqs) wait_queue__try_lock(&(wqs)->wqs_wait_queue) #define wait_queue_assert_possible(thread) \ ((thread)->wait_queue == WAIT_QUEUE_NULL) - - /******** Decomposed interfaces (to build higher level constructs) ***********/ -extern void wait_queue_lock( - wait_queue_t wait_queue); - -extern void wait_queue_unlock( - wait_queue_t wait_queue); - -extern boolean_t wait_queue_lock_try( - wait_queue_t wait_queue); - /* assert intent to wait on a locked wait queue */ -extern boolean_t wait_queue_assert_wait_locked( +__private_extern__ wait_result_t wait_queue_assert_wait64_locked( wait_queue_t wait_queue, - event_t wait_event, - int interruptible, + event64_t wait_event, + wait_interrupt_t interruptible, boolean_t unlock); /* peek to see which thread would be chosen for a wakeup - but keep on queue */ -extern void wait_queue_peek_locked( +__private_extern__ void wait_queue_peek64_locked( wait_queue_t wait_queue, - event_t event, + event64_t event, thread_t *thread, wait_queue_t *found_queue); /* peek to see which thread would be chosen for a wakeup - but keep on queue */ -extern void wait_queue_pull_thread_locked( +__private_extern__ void wait_queue_pull_thread_locked( wait_queue_t wait_queue, thread_t thread, boolean_t unlock); /* wakeup all threads waiting for a particular event on locked queue */ -extern kern_return_t wait_queue_wakeup_one_locked( +__private_extern__ kern_return_t wait_queue_wakeup64_all_locked( wait_queue_t wait_queue, - event_t wake_event, - int result, + event64_t wake_event, + wait_result_t result, boolean_t unlock); /* wakeup one thread waiting for a particular event on locked queue */ -extern kern_return_t wait_queue_wakeup_one_locked( +__private_extern__ kern_return_t wait_queue_wakeup64_one_locked( wait_queue_t wait_queue, - event_t wake_event, - int result, + event64_t wake_event, + wait_result_t result, boolean_t unlock); -/* return the identity of a thread that is waiting for */ -extern thread_t wait_queue_recommend_locked( - wait_queue_t wait_queue, - event_t wake_event); - /* return identity of a thread awakened for a particular */ -extern thread_t wait_queue_wakeup_identity_locked( +__private_extern__ thread_t wait_queue_wakeup64_identity_locked( wait_queue_t wait_queue, - event_t wake_event, - int result, + event64_t wake_event, + wait_result_t result, boolean_t unlock); /* wakeup thread iff its still waiting for a particular event on locked queue */ -extern kern_return_t wait_queue_wakeup_thread_locked( +__private_extern__ kern_return_t wait_queue_wakeup64_thread_locked( wait_queue_t wait_queue, - event_t wake_event, + event64_t wake_event, thread_t thread, - int result, + wait_result_t result, boolean_t unlock); #endif /* MACH_KERNEL_PRIVATE */ +#ifdef __APPLE_API_UNSTABLE +/******** Semi-Public interfaces (not a part of a higher construct) ************/ + +extern kern_return_t wait_queue_init( + wait_queue_t wait_queue, + int policy); + +extern wait_queue_set_t wait_queue_set_alloc( + int policy); + +extern kern_return_t wait_queue_set_free( + wait_queue_set_t set_queue); + +extern wait_queue_link_t wait_queue_link_alloc( + int policy); + +extern kern_return_t wait_queue_link_free( + wait_queue_link_t link_element); + +#endif /* __APPLE_API_UNSTABLE */ + +#ifdef __APPLE_API_EVOLVING + extern wait_queue_t wait_queue_alloc( - int policy); + int policy); + +extern kern_return_t wait_queue_free( + wait_queue_t wait_queue); -extern void wait_queue_free( +extern kern_return_t wait_queue_link( + wait_queue_t wait_queue, + wait_queue_set_t set_queue); + +extern kern_return_t wait_queue_unlink( + wait_queue_t wait_queue, + wait_queue_set_t set_queue); + +extern kern_return_t wait_queue_unlink_all( wait_queue_t wait_queue); -/******** Standalone interfaces (not a part of a higher construct) ************/ +extern kern_return_t wait_queue_set_unlink_all( + wait_queue_set_t set_queue); + +/* assert intent to wait on pair */ +extern wait_result_t wait_queue_assert_wait64( + wait_queue_t wait_queue, + event64_t wait_event, + wait_interrupt_t interruptible); + +/* wakeup the most appropriate thread waiting on pair */ +extern kern_return_t wait_queue_wakeup64_one( + wait_queue_t wait_queue, + event64_t wake_event, + wait_result_t result); + +/* wakeup all the threads waiting on pair */ +extern kern_return_t wait_queue_wakeup64_all( + wait_queue_t wait_queue, + event64_t wake_event, + wait_result_t result); + +/* wakeup a specified thread waiting iff waiting on pair */ +extern kern_return_t wait_queue_wakeup64_thread( + wait_queue_t wait_queue, + event64_t wake_event, + thread_t thread, + wait_result_t result); + +#endif /* __APPLE_API_EVOLVING */ + +/* + * Compatibility Wait Queue APIs based on pointer events instead of 64bit + * integer events. + */ /* assert intent to wait on pair */ -extern boolean_t wait_queue_assert_wait( +extern wait_result_t wait_queue_assert_wait( wait_queue_t wait_queue, event_t wait_event, - int interruptible); + wait_interrupt_t interruptible); /* wakeup the most appropriate thread waiting on pair */ -extern kern_return_t wait_queue_wakeup_one( +extern kern_return_t wait_queue_wakeup_one( wait_queue_t wait_queue, event_t wake_event, - int result); + wait_result_t result); /* wakeup all the threads waiting on pair */ -extern kern_return_t wait_queue_wakeup_all( +extern kern_return_t wait_queue_wakeup_all( wait_queue_t wait_queue, event_t wake_event, - int result); + wait_result_t result); /* wakeup a specified thread waiting iff waiting on pair */ -extern kern_return_t wait_queue_wakeup_thread( +extern kern_return_t wait_queue_wakeup_thread( wait_queue_t wait_queue, event_t wake_event, thread_t thread, - int result); + wait_result_t result); + +#endif /* __APPLE_API_PRIVATE */ #endif /* _KERN_WAIT_QUEUE_H_ */ diff --git a/osfmk/kern/zalloc.c b/osfmk/kern/zalloc.c index 0020560ea..66e36c016 100644 --- a/osfmk/kern/zalloc.c +++ b/osfmk/kern/zalloc.c @@ -224,14 +224,20 @@ vm_size_t zdata_size; #define lock_zone(zone) \ MACRO_BEGIN \ - simple_lock(&zone->lock); \ + simple_lock(&(zone)->lock); \ MACRO_END #define unlock_zone(zone) \ MACRO_BEGIN \ - simple_unlock(&zone->lock); \ + simple_unlock(&(zone)->lock); \ MACRO_END +#define zone_wakeup(zone) thread_wakeup((event_t)(zone)) +#define zone_sleep(zone) \ + thread_sleep_simple_lock((event_t)(zone), \ + &(zone)->lock, \ + THREAD_UNINT) + #define lock_zone_init(zone) \ MACRO_BEGIN \ simple_lock_init(&zone->lock, ETAP_MISC_ZONE); \ @@ -624,11 +630,8 @@ zalloc_canblock( * Someone is allocating memory for this zone. * Wait for it to show up, then try again. */ - assert_wait((event_t)zone, THREAD_UNINT); zone->waiting = TRUE; - unlock_zone(zone); - thread_block((void (*)(void)) 0); - lock_zone(zone); + zone_sleep(zone); } else { if ((zone->cur_size + zone->elem_size) > @@ -682,7 +685,7 @@ zalloc_canblock( zone->doing_alloc = FALSE; if (zone->waiting) { zone->waiting = FALSE; - thread_wakeup((event_t)zone); + zone_wakeup(zone); } REMOVE_FROM_ZONE(zone, addr, vm_offset_t); if (addr == 0 && diff --git a/osfmk/kern/zalloc.h b/osfmk/kern/zalloc.h index c2554d815..74aeab881 100644 --- a/osfmk/kern/zalloc.h +++ b/osfmk/kern/zalloc.h @@ -62,7 +62,12 @@ #include #include -#ifdef MACH_KERNEL_PRIVATE +#include + +#ifdef __APPLE_API_PRIVATE + +#ifdef MACH_KERNEL_PRIVATE + #include #include #include @@ -101,7 +106,6 @@ struct zone { decl_simple_lock_data(,lock) /* generic lock */ }; - extern void zone_gc(void); extern void consider_zone_gc(void); @@ -114,8 +118,9 @@ extern void zone_bootstrap(void); /* Init zone module */ extern void zone_init(vm_size_t); -#endif /* ! MACH_KERNEL_PRIVATE */ +#endif /* MACH_KERNEL_PRIVATE */ +#endif /* __APPLE_API_PRIVATE */ /* Allocate from zone */ extern vm_offset_t zalloc( @@ -179,22 +184,34 @@ extern integer_t zone_free_count(zone_t zone); #define Z_EXPAND 3 /* Make zone expandable */ #define Z_FOREIGN 4 /* Allow collectable zone to contain foreign */ /* (not allocated via zalloc) elements. */ -#ifdef MACH_KERNEL_PRIVATE + +#ifdef __APPLE_API_PRIVATE + +#ifdef MACH_KERNEL_PRIVATE + #if ZONE_DEBUG + #if MACH_KDB + extern vm_offset_t next_element( zone_t z, vm_offset_t elt); extern vm_offset_t first_element( zone_t z); + #endif /* MACH_KDB */ + extern void zone_debug_enable( zone_t z); extern void zone_debug_disable( zone_t z); + #endif /* ZONE_DEBUG */ -#endif MACH_KERNEL_PRIVATE + +#endif MACH_KERNEL_PRIVATE + +#endif /* __APPLE_API_PRIVATE */ #endif /* _KERN_ZALLOC_H_ */ diff --git a/osfmk/mach/Makefile b/osfmk/mach/Makefile index 697fcae44..147a0c962 100644 --- a/osfmk/mach/Makefile +++ b/osfmk/mach/Makefile @@ -31,7 +31,6 @@ MIG_TYPES = \ std_types.defs MIG_DEFS = \ - bootstrap.defs \ clock.defs \ clock_priv.defs \ clock_reply.defs \ @@ -68,7 +67,6 @@ MIG_USHDRS = \ notify_server.h MIG_UUHDRS = \ - bootstrap.h \ clock.h \ clock_priv.h \ host_priv.h \ @@ -91,6 +89,7 @@ MIGINCLUDES = ${MIG_UUHDRS} ${MIG_USHDRS} DATAFILES = \ boolean.h \ boot_info.h \ + bootstrap.h \ clock_types.h \ error.h \ exception.h \ @@ -99,7 +98,6 @@ DATAFILES = \ host_reboot.h \ kern_return.h \ kmod.h \ - mach_ioctl.h \ mach_param.h \ mach_time.h \ mach_traps.h \ @@ -110,7 +108,6 @@ DATAFILES = \ message.h \ mig.h \ mig_errors.h \ - mig_log.h \ ndr.h \ notify.h \ policy.h \ diff --git a/osfmk/mach/bootstrap.defs b/osfmk/mach/bootstrap.defs deleted file mode 100644 index 3edee9df0..000000000 --- a/osfmk/mach/bootstrap.defs +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * @OSF_COPYRIGHT@ - */ -subsystem -#if KERNEL_SERVER - KernelServer -#endif /* KERNEL_SERVER */ - bootstrap 1000001; /* 999999 + 2 skips */ - -#include -#include - -ServerPrefix do_; - -/* - * Objects to references of type bootstrap_t are returned by: - * task_get_special_port(task_t,...); - * task_get_bootstrap(task_t,...); - */ - -/* - * A task can make this call on its bootstrap port - * to get its privileged ports. - */ -routine bootstrap_ports( - bootstrap : bootstrap_t; - out priv_host : mach_port_t; - out device_master : mach_port_t; - out wired_ledger : mach_port_t; - out paged_ledger : mach_port_t; - out host_security : mach_port_t); - -/* - * A task can use this call to get its argument strings. - */ -routine bootstrap_arguments( - bootstrap : bootstrap_t; - task : task_t; - out arguments : pointer_t, Dealloc); - -/* - * A task can use this call to get its environment strings. - */ -routine bootstrap_environment( - bootstrap : bootstrap_t; - task : task_t; - out environment : pointer_t, Dealloc); - -/* - * A task can use this call to indicate to its bootstrapper that it - * is done with its startup processing. This call is used when the - * task is important enough so that the bootstrap process wants to - * wait for it to come up before continuing with other things. - */ -simpleroutine bootstrap_completed( - bootstrap : bootstrap_t; - task : task_t); - diff --git a/osfmk/mach/bootstrap.h b/osfmk/mach/bootstrap.h new file mode 100644 index 000000000..045645938 --- /dev/null +++ b/osfmk/mach/bootstrap.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Mach bootstrap interfaces (obsolete: header included only for compatibility) + */ +#ifndef _MACH_BOOTSTRAP_H_ +#define _MACH_BOOTSTRAP_H_ + +#endif /* _MACH_BOOTSTRAP_H_ */ diff --git a/osfmk/mach/clock_types.h b/osfmk/mach/clock_types.h index 701bf84c7..93687e944 100644 --- a/osfmk/mach/clock_types.h +++ b/osfmk/mach/clock_types.h @@ -38,6 +38,28 @@ #define _MACH_CLOCK_TYPES_H_ #include +#include + +/* + * Type definitions. + */ +typedef int alarm_type_t; /* alarm time type */ +typedef int sleep_type_t; /* sleep time type */ +typedef int clock_id_t; /* clock identification type */ +typedef int clock_flavor_t; /* clock flavor type */ +typedef int *clock_attr_t; /* clock attribute type */ +typedef int clock_res_t; /* clock resolution type */ + +/* + * Normal time specification used by the kernel clock facility. + */ +struct mach_timespec { + unsigned int tv_sec; /* seconds */ + clock_res_t tv_nsec; /* nanoseconds */ +}; +typedef struct mach_timespec mach_timespec_t; + +#ifdef __APPLE_API_UNSTABLE /* * Reserved clock id values for default clocks. @@ -51,16 +73,6 @@ * clock depending on particular * requirements */ -/* - * Type definitions. - */ -typedef int alarm_type_t; /* alarm time type */ -typedef int sleep_type_t; /* sleep time type */ -typedef int clock_id_t; /* clock identification type */ -typedef int clock_flavor_t; /* clock flavor type */ -typedef int *clock_attr_t; /* clock attribute type */ -typedef int clock_res_t; /* clock resolution type */ - /* * Attribute names. */ @@ -70,15 +82,6 @@ typedef int clock_res_t; /* clock resolution type */ #define CLOCK_ALARM_MINRES 4 /* minimum alarm resolution */ #define CLOCK_ALARM_MAXRES 5 /* maximum alarm resolution */ -/* - * Normal time specification used by the kernel clock facility. - */ -struct mach_timespec { - unsigned int tv_sec; /* seconds */ - clock_res_t tv_nsec; /* nanoseconds */ -}; -typedef struct mach_timespec mach_timespec_t; - #define NSEC_PER_USEC 1000 /* nanoseconds per microsecond */ #define USEC_PER_SEC 1000000 /* microseconds per second */ #define NSEC_PER_SEC 1000000000 /* nanoseconds per second */ @@ -121,4 +124,6 @@ typedef struct mach_timespec mach_timespec_t; #define BAD_ALRMTYPE(t) (((t) &~ TIME_RELATIVE) != 0) +#endif /* __APPLE_API_UNSTABLE */ + #endif /* _MACH_CLOCK_TYPES_H_ */ diff --git a/osfmk/mach/etap_events.h b/osfmk/mach/etap_events.h index 298a465e1..29dced2f9 100644 --- a/osfmk/mach/etap_events.h +++ b/osfmk/mach/etap_events.h @@ -36,6 +36,9 @@ #ifndef _MACH_ETAP_EVENTS_H_ #define _MACH_ETAP_EVENTS_H_ +#include + +#ifdef __APPLE_API_UNSTABLE /* ============================ * ETAP Subsystem Definitions @@ -318,6 +321,9 @@ #define ETAP_P_MISC (ETAP_SUBS_PROBE + ETAP_SYS_BASE + 10) #define ETAP_P_DETAP (ETAP_SUBS_PROBE + ETAP_SYS_BASE + 11) +#endif /* __APPLE_API_UNSTABLE */ + +#ifdef __APPLE_API_OBSOLETE /* =========================== * ETAP Thread block reasons * =========================== @@ -335,5 +341,7 @@ #define BLOCKED_ON_REAPER_DONE 7 #define BLOCKED_ON_IDLE_DONE 8 #define BLOCKED_ON_TERMINATION 9 - + +#endif /* __APPLE_API_OBSOLETE */ + #endif /* _MACH_ETAP_EVENTS_H_ */ diff --git a/osfmk/mach/exception_types.h b/osfmk/mach/exception_types.h index 8f341357b..014349674 100644 --- a/osfmk/mach/exception_types.h +++ b/osfmk/mach/exception_types.h @@ -135,6 +135,13 @@ #define FIRST_EXCEPTION 1 /* ZERO is illegal */ +/* + * Machine independent codes for EXC_SOFTWARE + * Codes 0x10000 - 0x1FFFF reserved for OS emulation (Unix) + * 0x10000 - 0x10002 in use for unix signals + */ +#define EXC_SOFT_SIGNAL 0x10003 /* Unix signal exceptions */ + #ifndef ASSEMBLER #include #include diff --git a/osfmk/mach/host_info.h b/osfmk/mach/host_info.h index b5554be32..28cdb19fe 100644 --- a/osfmk/mach/host_info.h +++ b/osfmk/mach/host_info.h @@ -89,7 +89,8 @@ typedef integer_t host_flavor_t; #define HOST_SCHED_INFO 3 /* scheduling info */ #define HOST_RESOURCE_SIZES 4 /* kernel struct sizes */ #define HOST_PRIORITY_INFO 5 /* priority information */ -#define HOST_SEMAPHORE_TRAPS 7 /* Has semaphore traps - temporary */ +#define HOST_SEMAPHORE_TRAPS 7 /* Has semaphore traps */ +#define HOST_MACH_MSG_TRAP 8 /* Has mach_msg_trap */ struct host_basic_info { integer_t max_cpus; /* max number of cpus possible */ diff --git a/osfmk/mach/i386/Makefile b/osfmk/mach/i386/Makefile index c31a0f391..10a2c5410 100644 --- a/osfmk/mach/i386/Makefile +++ b/osfmk/mach/i386/Makefile @@ -13,7 +13,7 @@ MIG_DEFS = mach_i386.defs MIGINCLUDES = mach_i386_server.h DATAFILES = \ - boolean.h exception.h fp_reg.h flipc_dep.h \ + boolean.h exception.h fp_reg.h \ processor_info.h kern_return.h mach_i386_types.h ndr_def.h syscall_sw.h \ thread_status.h thread_state.h vm_param.h \ vm_types.h rpc.h \ diff --git a/osfmk/mach/i386/exception.h b/osfmk/mach/i386/exception.h index b96b76def..aa45d06dd 100644 --- a/osfmk/mach/i386/exception.h +++ b/osfmk/mach/i386/exception.h @@ -159,6 +159,7 @@ /* * EXC_SOFTWARE + * Note: 0x10000-0x10003 in use for unix signal */ /* diff --git a/osfmk/mach/i386/machine_types.defs b/osfmk/mach/i386/machine_types.defs index 7a4258c61..109f98a21 100644 --- a/osfmk/mach/i386/machine_types.defs +++ b/osfmk/mach/i386/machine_types.defs @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002,2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,26 +22,6 @@ /* * @OSF_COPYRIGHT@ */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:31 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.1.1.1 1998/03/07 02:25:47 wsanchez - * Import of OSF Mach kernel (~mburg) - * - * Revision 1.1.5.1 1995/01/06 19:50:37 devrcs - * mk6 CR668 - 1.3b26 merge - * new file for mk6 - * [1994/11/02 18:18:29 dwm] - * - * Revision 1.1.2.1 1994/05/06 18:54:50 tmt - * New Mig definition file to describe required machine types. - * [1994/05/05 21:08:57 tmt] - * - * $EndLog$ - */ /* * Header file for basic, machine-dependent data types. i386 version. */ @@ -49,28 +29,40 @@ #ifndef _MACHINE_VM_TYPES_DEFS_ #define _MACHINE_VM_TYPES_DEFS_ 1 +type short = int16_t; +type int = int32_t; +type unsigned = uint32_t; + +type float = MACH_MSG_TYPE_REAL_32; +type double = MACH_MSG_TYPE_REAL_64; + + +/* from ISO/IEC 988:1999 spec */ +/* 7.18.1.4 Integer types capable of hgolding object pointers */ /* - * A natural_t is the type for the native + * The [u]intptr_t types for the native * integer type, e.g. 32 or 64 or.. whatever - * register size the machine has. Unsigned, it is + * register size the machine has. They are * used for entities that might be either - * unsigned integers or pointers, and for + * [unsigned] integers or pointers, and for * type-casting between the two. + * * For instance, the IPC system represents * a port in user space as an integer and * in kernel space as a pointer. */ -type natural_t = unsigned32; +type uintptr_t = MACH_MSG_TYPE_INTEGER_32; +type intptr_t = MACH_MSG_TYPE_INTEGER_32; /* - * An integer_t is the signed counterpart - * of the natural_t type. Both types are - * only supposed to be used to define - * other types in a machine-independent - * way. + * These are the legacy Mach types that are + * the [rough] equivalents of the standards above. + * They were defined in terms of int, not + * long int, so they remain separate. */ -type integer_t = int32; - +type register_t = int32_t; +type integer_t = int32_t; +type natural_t = uint32_t; #if MACH_IPC_COMPAT /* diff --git a/osfmk/mach/i386/rpc.h b/osfmk/mach/i386/rpc.h index 002549ae8..1f8b879b8 100644 --- a/osfmk/mach/i386/rpc.h +++ b/osfmk/mach/i386/rpc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002,2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -25,27 +25,4 @@ #ifndef _MACH_I386_RPC_H_ #define _MACH_I386_RPC_H_ -/* - * Just temporary until all vestiges of short-circuit can be - * removed. - */ -#define CAN_SHCIRCUIT(name) (0) - -/* - * Kernel machine dependent macros for mach rpc - * - * User args (argv) begin two words above the frame pointer (past saved ebp - * and return address) on the user stack. Return code is stored in register - * ecx, by convention (must be a caller-saves register, to survive return - * from server work function). The user space instruction pointer is eip, - * and the user stack pointer is uesp. - */ -#define MACH_RPC_ARGV(act) ( (char *)(USER_REGS(act)->ebp + 8) ) -#define MACH_RPC_RET(act) ( USER_REGS(act)->ecx ) -#define MACH_RPC_FUNC(act) ( USER_REGS(act)->edx ) -#define MACH_RPC_SIG(act) ( USER_REGS(act)->edi ) -#define MACH_RPC_UIP(act) ( USER_REGS(act)->eip ) -#define MACH_RPC_USP(act) ( USER_REGS(act)->uesp ) -#define MACH_RPC_RETADDR(sp) ( *((int *)sp - 1) ) - #endif /* _MACH_I386_RPC_H_ */ diff --git a/osfmk/mach/i386/syscall_sw.h b/osfmk/mach/i386/syscall_sw.h index 4a7a17b3f..16104a874 100644 --- a/osfmk/mach/i386/syscall_sw.h +++ b/osfmk/mach/i386/syscall_sw.h @@ -143,26 +143,26 @@ #include -#define MACHCALLSEL 0x07 -#define RPCCALLSEL 0x0f +#define MACHCALLSEL $0x07 +#define RPCCALLSEL $0x0f #define kernel_trap(trap_name,trap_number,number_args) \ LEAF(_##trap_name,0) ;\ movl $##trap_number,%eax ;\ - lcall $##MACHCALLSEL, $0 ;\ + lcall MACHCALLSEL, $0 ;\ END(_##trap_name) #define rpc_trap(trap_name,trap_number,number_args) \ LEAF(_##trap_name,0) ;\ movl $##trap_number,%eax; \ - lcall $##RPCCALLSEL, $0 ;\ + lcall RPCCALLSEL, $0 ;\ END(_##trap_name) #define rpc_return_trap(trap_name,trap_number,number_args) \ LEAF(_##trap_name,0) ;\ movl %eax, %ecx; \ movl $##trap_number,%eax; \ - lcall $##RPCCALLSEL, $0 ;\ + lcall RPCCALLSEL, $0 ;\ END(_##trap_name) #endif /* _MACH_I386_SYSCALL_SW_H_ */ diff --git a/osfmk/mach/i386/vm_param.h b/osfmk/mach/i386/vm_param.h index f5b0c0536..0f18100e6 100644 --- a/osfmk/mach/i386/vm_param.h +++ b/osfmk/mach/i386/vm_param.h @@ -188,7 +188,7 @@ /*#endif*/ -#define PMAP_ENTER(pmap, virtual_address, page, protection, wired) \ +#define PMAP_ENTER(pmap, virtual_address, page, protection, flags, wired) \ MACRO_BEGIN \ vm_prot_t __prot__ = \ (protection) & ~(page)->page_lock; \ @@ -201,6 +201,7 @@ (virtual_address), \ (page)->phys_addr, \ __prot__, \ + flags, \ (wired) \ ); \ MACRO_END diff --git a/osfmk/mach/i386/vm_types.h b/osfmk/mach/i386/vm_types.h index ae562ea62..0ad257fcb 100644 --- a/osfmk/mach/i386/vm_types.h +++ b/osfmk/mach/i386/vm_types.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002,2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,63 +22,6 @@ /* * @OSF_COPYRIGHT@ */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:31 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.1.1.1 1998/03/07 02:25:47 wsanchez - * Import of OSF Mach kernel (~mburg) - * - * Revision 1.2.8.2 1995/01/06 19:50:48 devrcs - * mk6 CR668 - 1.3b26 merge - * 64bit cleanup - * [1994/10/14 03:42:42 dwm] - * - * Revision 1.2.8.1 1994/09/23 02:38:01 ezf - * change marker to not FREE - * [1994/09/22 21:40:30 ezf] - * - * Revision 1.2.2.2 1993/06/09 02:41:01 gm - * Added to OSF/1 R1.3 from NMK15.0. - * [1993/06/02 21:16:38 jeffc] - * - * Revision 1.2 1993/04/19 16:34:37 devrcs - * ansi C conformance changes - * [1993/02/02 18:56:34 david] - * - * Revision 1.1 1992/09/30 02:30:57 robert - * Initial revision - * - * $EndLog$ - */ -/* CMU_HIST */ -/* - * Revision 2.4 91/05/14 16:53:00 mrt - * Correcting copyright - * - * Revision 2.3 91/02/05 17:32:34 mrt - * Changed to new Mach copyright - * [91/02/01 17:10:49 mrt] - * - * Revision 2.2 90/05/03 15:48:32 dbg - * First checkin. - * - * Revision 1.3 89/03/09 20:20:12 rpd - * More cleanup. - * - * Revision 1.2 89/02/26 13:01:20 gm0w - * Changes for cleanup. - * - * 31-Dec-88 Robert Baron (rvb) at Carnegie-Mellon University - * Derived from MACH2.0 vax release. - * - * 23-Apr-87 Michael Young (mwyoung) at Carnegie-Mellon University - * Changed things to "unsigned int" to appease the user community :-). - * - */ -/* CMU_ENDHIST */ /* * Mach Operating System * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University @@ -143,14 +86,6 @@ typedef unsigned int natural_t; */ typedef int integer_t; -#ifdef MACH_KERNEL_PRIVATE -/* - * An int32 is an integer that is at least 32 bits wide - */ -typedef int int32; -typedef unsigned int uint32; -#endif - /* * A vm_offset_t is a type-neutral pointer, * e.g. an offset into a virtual memory space. diff --git a/osfmk/mach/kmod.h b/osfmk/mach/kmod.h index c582f5e39..49d0f0103 100644 --- a/osfmk/mach/kmod.h +++ b/osfmk/mach/kmod.h @@ -30,8 +30,11 @@ #ifndef _MACH_KMOD_H_ #define _MACH_KMOD_H_ +#include #include +#ifdef __APPLE_API_PRIVATE + #define KMOD_CNTL_START 1 // call kmod's start routine #define KMOD_CNTL_STOP 2 // call kmod's stop routine #define KMOD_CNTL_RETAIN 3 // increase a kmod's reference count @@ -42,17 +45,24 @@ #define KMOD_UNPACK_FROM_ID(i) ((unsigned long)i >> 16) #define KMOD_UNPACK_TO_ID(i) ((unsigned long)i & 0xffff) +#endif /* __APPLE_API_PRIVATE */ + #define KMOD_MAX_NAME 64 +#ifdef __APPLE_API_PRIVATE + typedef int kmod_t; typedef int kmod_control_flavor_t; typedef void* kmod_args_t; +#endif /* __APPLE_API_PRIVATE */ + typedef struct kmod_reference { struct kmod_reference *next; struct kmod_info *info; } kmod_reference_t; + /**************************************************************************************/ /* warning any changes to this structure affect the following macros. */ /**************************************************************************************/ @@ -78,8 +88,12 @@ typedef struct kmod_info { kmod_stop_func_t *stop; } kmod_info_t; +#ifdef __APPLE_API_PRIVATE + typedef kmod_info_t *kmod_info_array_t; +#endif /* __APPLE_API_PRIVATE */ + #define KMOD_INFO_NAME kmod_info #define KMOD_INFO_VERSION 1 @@ -108,6 +122,8 @@ typedef kmod_info_t *kmod_info_array_t; // kmod kernel to user commands // ************************************************************************************* +#ifdef __APPLE_API_PRIVATE + #define KMOD_LOAD_EXTENSION_PACKET 1 #define KMOD_LOAD_WITH_DEPENDENCIES_PACKET 2 @@ -135,11 +151,14 @@ typedef struct kmod_generic_cmd { extern void kmod_init(); -extern kern_return_t kmod_create_fake(char *name, char *version); +extern kern_return_t kmod_create_fake(const char *name, const char *version); extern kmod_info_t *kmod_lookupbyname(const char * name); extern kmod_info_t *kmod_lookupbyid(kmod_t id); +extern kmod_info_t *kmod_lookupbyname_locked(const char * name); +extern kmod_info_t *kmod_lookupbyid_locked(kmod_t id); + extern kern_return_t kmod_load_extension(char *name); extern kern_return_t kmod_load_extension_with_dependencies(char *name, char **dependencies); extern kern_return_t kmod_send_generic(int type, void *data, int size); @@ -154,4 +173,7 @@ extern void kmod_dump(vm_offset_t *addr, unsigned int cnt); #endif /* KERNEL_PRIVATE */ +#endif /* __APPLE_API_PRIVATE */ + + #endif /* _MACH_KMOD_H_ */ diff --git a/osfmk/mach/mach_ioctl.h b/osfmk/mach/mach_ioctl.h deleted file mode 100644 index 167e37bae..000000000 --- a/osfmk/mach/mach_ioctl.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * @OSF_COPYRIGHT@ - */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:30 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.1.1.1 1998/03/07 02:25:45 wsanchez - * Import of OSF Mach kernel (~mburg) - * - * Revision 1.1.4.2 1997/02/07 12:12:35 barbou - * Fixed the defines (some were missing the "MACH_" prefixes). - * [1997/02/07 12:06:38 barbou] - * - * Revision 1.1.4.1 1996/11/29 16:59:20 stephen - * nmklinux_1.0b3_shared into pmk1.1 - * Contents of sys/ioctl.h. Prefixed the definitions with "MACH" to avoid - * conflicts with UNIX servers. - * [96/09/18 barbou] - * [1996/11/29 16:33:15 stephen] - * - * $EndLog$ - */ -/* - * Mach Operating System - * Copyright (c) 1991 Carnegie Mellon University - * All Rights Reserved. - * - * 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 - * -CS.CMU.EDU -* School of Computer Science -* Carnegie Mellon University -* Pittsburgh PA 15213-3890 -* -* any improvements or extensions that they make and grant Carnegie Mellon rights -* to redistribute these changes. -*/ -/* - */ -/* - * Format definitions for 'ioctl' commands in device definitions. - * - * From BSD4.4. - */ - -#ifndef _MACH_MACH_IOCTL_H_ -#define _MACH_MACH_IOCTL_H_ - -/* - * 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 MACH_IOCPARM_MASK 0x1fff /* parameter length, at most 13 bits */ -#define MACH_IOC_VOID 0x20000000 /* no parameters */ -#define MACH_IOC_OUT 0x40000000 /* copy out parameters */ -#define MACH_IOC_IN 0x80000000 /* copy in parameters */ -#define MACH_IOC_INOUT (MACH_IOC_IN|MACH_IOC_OUT) - -#define _MACH_IOC(inout,group,num,len) \ - (inout | ((len & MACH_IOCPARM_MASK) << 16) | ((group) << 8) | (num)) -#define _MACH_IO(g,n) _MACH_IOC(MACH_IOC_VOID, (g), (n), 0) -#define _MACH_IOR(g,n,t) _MACH_IOC(MACH_IOC_OUT, (g), (n), sizeof(t)) -#define _MACH_IOW(g,n,t) _MACH_IOC(MACH_IOC_IN, (g), (n), sizeof(t)) -#define _MACH_IOWR(g,n,t) _MACH_IOC(MACH_IOC_INOUT, (g), (n), sizeof(t)) - -#ifdef MACH_KERNEL - /* - * to avoid changing the references in the micro-kernel sources... - */ -#define IOCPARM_MASK MACH_IOCPARM_MASK -#define IOC_VOID MACH_IOC_VOID -#define IOC_OUT MACH_IOC_OUT -#define IOC_IN MACH_IOC_IN -#define IOC_INOUT MACH_IOC_INOUT -#define _IOC _MACH_IOC -#define _IO _MACH_IO -#define _IOR _MACH_IOR -#define _IOW _MACH_IOW -#define _IOWR _MACH_IOWR -#endif /* MACH_KERNEL */ - -#endif /* _MACH_MACH_IOCTL_H_ */ diff --git a/osfmk/mach/mach_port.defs b/osfmk/mach/mach_port.defs index dffabb668..60ee11f1c 100644 --- a/osfmk/mach/mach_port.defs +++ b/osfmk/mach/mach_port.defs @@ -195,14 +195,7 @@ routine mach_port_mod_refs( right : mach_port_right_t; delta : mach_port_delta_t); -/* - * Allocates a new receive right, and associates it with the - * specified RPC subsystem attributes. - */ -routine mach_port_allocate_subsystem( - task : ipc_space_t; - subsys : subsystem_t; - out name : mach_port_name_t); +skip; /* * Only valid for receive rights. @@ -343,6 +336,7 @@ routine mach_port_allocate_qos( inout qos : mach_port_qos_t; out name : mach_port_name_t); + /* * Generic interface to allocation various kinds of ports. * Should never be called directly by users (at least not @@ -352,7 +346,7 @@ routine mach_port_allocate_qos( routine mach_port_allocate_full( task : ipc_space_t; right : mach_port_right_t; - subs : subsystem_t; + proto : mach_port_t; inout qos : mach_port_qos_t; inout name : mach_port_name_t); diff --git a/osfmk/mach/mach_syscalls.h b/osfmk/mach/mach_syscalls.h index ec44601d0..9b9eb91cb 100644 --- a/osfmk/mach/mach_syscalls.h +++ b/osfmk/mach/mach_syscalls.h @@ -26,9 +26,10 @@ #ifndef _MACH_MACH_SYSCALLS_H_ #define _MACH_MACH_SYSCALLS_H_ -#include #include -#include +#include +#include +#include #include extern kern_return_t clock_sleep_trap( diff --git a/osfmk/mach/mach_traps.h b/osfmk/mach/mach_traps.h index faa547080..d87b2869e 100644 --- a/osfmk/mach/mach_traps.h +++ b/osfmk/mach/mach_traps.h @@ -63,7 +63,6 @@ #include #include #include -#include mach_port_name_t mach_reply_port(void); diff --git a/osfmk/mach/mach_types.defs b/osfmk/mach/mach_types.defs index 48c7f668b..5a7897eb0 100644 --- a/osfmk/mach/mach_types.defs +++ b/osfmk/mach/mach_types.defs @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002,2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -62,8 +62,8 @@ type upl_page_info_t = struct[2] of integer_t; type upl_page_info_array_t = array[*:20] of upl_page_info_t; -type memory_object_offset_t = struct[2] of integer_t; -type memory_object_size_t = struct[2] of integer_t; +type memory_object_offset_t = uint64_t; +type memory_object_size_t = uint64_t; @@ -331,15 +331,6 @@ type kernel_boot_info_t = c_string[*:4096]; type time_value_t = struct[2] of integer_t; -type user_subsystem_t = array[*:16384] of char; - -type subsystem_t = mach_port_t -#if KERNEL_SERVER - intran: subsystem_t convert_port_to_subsystem(mach_port_t) - outtran: mach_port_t convert_subsystem_to_port(subsystem_t) -#endif /* KERNEL_SERVER */ - ; - type mach_port_qos_t = struct[2] of integer_t; type emulation_vector_t = ^array[] of vm_offset_t; @@ -444,13 +435,13 @@ type kmod_args_t = ^array[] of MACH_MSG_TYPE_BYTE type io_master_t = mach_port_t; type UNDServerRef = mach_port_t; -#ifdef KERNEL_SERVER +#if KERNEL_SERVER #ifdef MACH_KERNEL_PRIVATE simport ; /* for null conversion */ simport ; /* for task/thread conversion */ simport ; /* for host/processor/pset conversions */ -simport ; /* for subsystem conversions */ simport ; /* for lock_set and semaphore conversions */ +simport ; /* for ledger conversions */ simport ; /* for memory object type conversions */ #endif /* MACH_KERNEL_PRIVATE */ @@ -458,6 +449,7 @@ simport ; /* pick up kernel-specific MIG things */ #endif /* KERNEL_SERVER */ +import ; import ; #endif /* _MACH_MACH_TYPES_DEFS_ */ diff --git a/osfmk/mach/mach_types.h b/osfmk/mach/mach_types.h index 60591de17..04f9bd114 100644 --- a/osfmk/mach/mach_types.h +++ b/osfmk/mach/mach_types.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002,2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -97,9 +97,44 @@ * If we are in the kernel, then pick up the kernel definitions for * the basic mach types. */ -#include +typedef struct task *task_t; +typedef struct thread_shuttle *thread_t; +typedef struct thread_activation *thread_act_t; +typedef struct ipc_space *ipc_space_t; +typedef struct host *host_t; +typedef struct host *host_priv_t; +typedef struct host *host_security_t; +typedef struct processor *processor_t; +typedef struct processor_set *processor_set_t; +typedef struct processor_set *processor_set_control_t; +typedef struct semaphore *semaphore_t; +typedef struct lock_set *lock_set_t; +typedef struct ledger *ledger_t; +typedef struct alarm *alarm_t; +typedef struct clock *clock_serv_t; +typedef struct clock *clock_ctrl_t; -extern ledger_t convert_port_to_ledger(ipc_port_t); /* JMM - Hack */ +#if !defined(MACH_KERNEL_PRIVATE) + +/* + * Declare empty structure definitions for export to other + * kernel components. This lets us still provide some level + * of type checking, without exposing our internal data + * structures. + */ +struct task ; +struct thread_shuttle ; +struct thread_activation ; +struct host ; +struct processor ; +struct processor_set ; +struct semaphore ; +struct lock_set ; +struct ledger ; +struct alarm ; +struct clock ; + +#endif /* !MACH_KERNEL_PRIVATE */ #else /* !KERNEL_PRIVATE */ @@ -109,16 +144,14 @@ extern ledger_t convert_port_to_ledger(ipc_port_t); /* JMM - Hack */ */ typedef mach_port_t task_t; typedef mach_port_t thread_t; +typedef mach_port_t thread_act_t; typedef mach_port_t ipc_space_t; typedef mach_port_t host_t; typedef mach_port_t host_priv_t; typedef mach_port_t host_security_t; +typedef mach_port_t processor_t; typedef mach_port_t processor_set_t; -typedef mach_port_t processor_set_name_t; typedef mach_port_t processor_set_control_t; -typedef mach_port_t processor_t; -typedef mach_port_t thread_act_t; -typedef mach_port_t subsystem_t; typedef mach_port_t semaphore_t; typedef mach_port_t lock_set_t; typedef mach_port_t ledger_t; @@ -128,6 +161,12 @@ typedef mach_port_t clock_ctrl_t; #endif /* !KERNEL_PRIVATE */ +/* + * These aren't really unique types. They are just called + * out as unique types at one point in history. So we list + * them here for compatibility. + */ +typedef processor_set_t processor_set_name_t; /* * JMM - These types are just hard-coded as ports for now @@ -156,6 +195,7 @@ typedef processor_t *processor_array_t; typedef thread_act_t *thread_act_array_t; typedef ledger_t *ledger_array_t; + /* * However the real mach_types got declared, we also have to declare * types with "port" in the name for compatability with the way OSF @@ -187,17 +227,19 @@ typedef clock_ctrl_t clock_ctrl_port_t; typedef exception_handler_t exception_port_t; typedef exception_handler_array_t exception_port_arrary_t; + #define TASK_NULL ((task_t) 0) #define THREAD_NULL ((thread_t) 0) +#define THR_ACT_NULL ((thread_act_t) 0) +#define IPC_SPACE_NULL ((ipc_space_t) 0) #define HOST_NULL ((host_t) 0) #define HOST_PRIV_NULL ((host_priv_t)0) #define HOST_SECURITY_NULL ((host_security_t)0) #define PROCESSOR_SET_NULL ((processor_set_t) 0) #define PROCESSOR_NULL ((processor_t) 0) -#define THR_ACT_NULL ((thread_act_t) 0) -#define SUBSYSTEM_NULL ((subsystem_t) 0) #define SEMAPHORE_NULL ((semaphore_t) 0) #define LOCK_SET_NULL ((lock_set_t) 0) +#define LEDGER_NULL ((ledger_t) 0) #define ALARM_NULL ((alarm_t) 0) #define CLOCK_NULL ((clock_t) 0) #define UND_SERVER_NULL ((UNDServerRef) 0) diff --git a/osfmk/mach/machine.h b/osfmk/mach/machine.h index d54b7d1e1..40f6ac7dd 100644 --- a/osfmk/mach/machine.h +++ b/osfmk/mach/machine.h @@ -54,10 +54,8 @@ #ifndef _MACH_MACHINE_H_ #define _MACH_MACHINE_H_ -#ifdef MACH_KERNEL_PRIVATE -#include -#endif /* MACH_KERNEL_PRIVATE */ - +#include + #include #include @@ -91,6 +89,9 @@ typedef integer_t cpu_subtype_t; #define CPU_STATE_IDLE 2 #define CPU_STATE_NICE 3 +#ifdef KERNEL_PRIVATE +#ifdef __APPLE_API_UNSTABLE + struct machine_slot { /*boolean_t*/integer_t is_cpu; /* is there a cpu in this slot? */ cpu_type_t cpu_type; /* type of cpu */ @@ -103,10 +104,11 @@ struct machine_slot { typedef struct machine_slot *machine_slot_t; typedef struct machine_slot machine_slot_data_t; /* bogus */ -#ifdef KERNEL_PRIVATE extern struct machine_info machine_info; extern struct machine_slot machine_slot[]; -#endif + +#endif /* __APPLE_API_UNSTABLE */ +#endif /* KERNEL_PRIVATE */ /* * Machine types known by all. diff --git a/osfmk/mach/memory_object_types.h b/osfmk/mach/memory_object_types.h index 1e744897f..7592100f1 100644 --- a/osfmk/mach/memory_object_types.h +++ b/osfmk/mach/memory_object_types.h @@ -68,11 +68,14 @@ #include #include +#include + #define VM_64_BIT_DATA_OBJECTS typedef unsigned long long memory_object_offset_t; typedef unsigned long long memory_object_size_t; +#ifdef __APPLE_API_EVOLVING /* * Temporary until real EMMI version gets re-implemented */ @@ -179,12 +182,13 @@ typedef int memory_object_flavor_t; typedef int memory_object_info_data_t[MEMORY_OBJECT_INFO_MAX]; -#define OLD_MEMORY_OBJECT_BEHAVIOR_INFO 10 #define MEMORY_OBJECT_PERFORMANCE_INFO 11 -#define OLD_MEMORY_OBJECT_ATTRIBUTE_INFO 12 #define MEMORY_OBJECT_ATTRIBUTE_INFO 14 #define MEMORY_OBJECT_BEHAVIOR_INFO 15 +#ifdef __APPLE_API_UNSTABLE +#define OLD_MEMORY_OBJECT_BEHAVIOR_INFO 10 +#define OLD_MEMORY_OBJECT_ATTRIBUTE_INFO 12 struct old_memory_object_behave_info { memory_object_copy_strategy_t copy_strategy; @@ -192,17 +196,28 @@ struct old_memory_object_behave_info { boolean_t invalidate; }; -struct memory_object_perf_info { - vm_size_t cluster_size; - boolean_t may_cache; -}; - struct old_memory_object_attr_info { /* old attr list */ boolean_t object_ready; boolean_t may_cache; memory_object_copy_strategy_t copy_strategy; }; +typedef struct old_memory_object_behave_info *old_memory_object_behave_info_t; +typedef struct old_memory_object_behave_info old_memory_object_behave_info_data_t; +typedef struct old_memory_object_attr_info *old_memory_object_attr_info_t; +typedef struct old_memory_object_attr_info old_memory_object_attr_info_data_t; + +#define OLD_MEMORY_OBJECT_BEHAVE_INFO_COUNT \ + (sizeof(old_memory_object_behave_info_data_t)/sizeof(int)) +#define OLD_MEMORY_OBJECT_ATTR_INFO_COUNT \ + (sizeof(old_memory_object_attr_info_data_t)/sizeof(int)) +#endif /* __APPLE_API_UNSTABLE */ + +struct memory_object_perf_info { + vm_size_t cluster_size; + boolean_t may_cache; +}; + struct memory_object_attr_info { memory_object_copy_strategy_t copy_strategy; vm_offset_t cluster_size; @@ -218,8 +233,6 @@ struct memory_object_behave_info { boolean_t advisory_pageout; }; -typedef struct old_memory_object_behave_info *old_memory_object_behave_info_t; -typedef struct old_memory_object_behave_info old_memory_object_behave_info_data_t; typedef struct memory_object_behave_info *memory_object_behave_info_t; typedef struct memory_object_behave_info memory_object_behave_info_data_t; @@ -227,20 +240,13 @@ typedef struct memory_object_behave_info memory_object_behave_info_data_t; typedef struct memory_object_perf_info *memory_object_perf_info_t; typedef struct memory_object_perf_info memory_object_perf_info_data_t; -typedef struct old_memory_object_attr_info *old_memory_object_attr_info_t; -typedef struct old_memory_object_attr_info old_memory_object_attr_info_data_t; - typedef struct memory_object_attr_info *memory_object_attr_info_t; typedef struct memory_object_attr_info memory_object_attr_info_data_t; -#define OLD_MEMORY_OBJECT_BEHAVE_INFO_COUNT \ - (sizeof(old_memory_object_behave_info_data_t)/sizeof(int)) #define MEMORY_OBJECT_BEHAVE_INFO_COUNT \ (sizeof(memory_object_behave_info_data_t)/sizeof(int)) #define MEMORY_OBJECT_PERF_INFO_COUNT \ (sizeof(memory_object_perf_info_data_t)/sizeof(int)) -#define OLD_MEMORY_OBJECT_ATTR_INFO_COUNT \ - (sizeof(old_memory_object_attr_info_data_t)/sizeof(int)) #define MEMORY_OBJECT_ATTR_INFO_COUNT \ (sizeof(memory_object_attr_info_data_t)/sizeof(int)) @@ -293,6 +299,8 @@ typedef upl_page_info_array_t upl_page_list_ptr_t; #define UPL_RET_ONLY_DIRTY 0x20 #define UPL_SET_INTERNAL 0x40 #define UPL_QUERY_OBJECT_TYPE 0x80 +#define UPL_RET_ONLY_ABSENT 0x100 /* used only for COPY_FROM = FALSE */ +#define UPL_FILE_IO 0x200 /* upl abort error flags */ #define UPL_ABORT_RESTART 0x1 @@ -409,6 +417,8 @@ extern void upl_set_dirty(upl_t upl); extern void upl_clear_dirty(upl_t upl); -#endif /* KERNEL_PRIVATE */ +#endif /* KERNEL_PRIVATE */ + +#endif /* __APPLE_API_EVOLVING */ #endif /* _MACH_MEMORY_OBJECT_TYPES_H_ */ diff --git a/osfmk/mach/message.h b/osfmk/mach/message.h index acf2f7eff..a346aa327 100644 --- a/osfmk/mach/message.h +++ b/osfmk/mach/message.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -67,9 +67,13 @@ /* static templates are slower and bigger */ /* #define UseStaticTemplates 0 */ -#include -#include +#include +#include +#include +#include +#include +#include /* * The timeout mechanism uses mach_msg_timeout_t values, @@ -337,18 +341,16 @@ typedef union #define MACH_MSG_SIZE_MAX ((mach_msg_size_t) ~0) +#ifdef __APPLE_API_OBSOLETE /* * Compatibility definitions, for code written * when there was a msgh_kind instead of msgh_seqno. */ - #define MACH_MSGH_KIND_NORMAL 0x00000000 -#if 0 -/* code using this is likely to break, so better not to have it defined */ #define MACH_MSGH_KIND_NOTIFICATION 0x00000001 -#endif #define msgh_kind msgh_seqno #define mach_msg_kind_t mach_port_seqno_t +#endif /* __APPLE_API_OBSOLETE */ /* * The msgt_number field specifies the number of data elements. @@ -451,11 +453,14 @@ typedef integer_t mach_msg_option_t; #define MACH_RCV_TRAILER_ELEMENTS(x) (((x) & 0xf) << 24) #define MACH_RCV_TRAILER_MASK ((0xff << 24)) -extern mach_msg_trailer_size_t trailer_size[]; - #define GET_RCV_ELEMENTS(y) (((y) >> 24) & 0xf) -#define REQUESTED_TRAILER_SIZE(y) (trailer_size[GET_RCV_ELEMENTS(y)]) - +#define REQUESTED_TRAILER_SIZE(y) \ + ((mach_msg_trailer_size_t) \ + ((GET_RCV_ELEMENTS(y) == MACH_RCV_TRAILER_NULL) ? \ + sizeof(mach_msg_trailer_t) : \ + ((GET_RCV_ELEMENTS(y) == MACH_RCV_TRAILER_SEQNO) ? \ + sizeof(mach_msg_seqno_trailer_t) : \ + sizeof(mach_msg_security_trailer_t)))) /* * Much code assumes that mach_msg_return_t == kern_return_t. * This definition is useful for descriptive purposes. @@ -514,7 +519,7 @@ typedef kern_return_t mach_msg_return_t; #define MACH_SEND_INVALID_TRAILER 0x10000011 /* The trailer to be sent does not match kernel format. */ #define MACH_SEND_INVALID_RT_OOL_SIZE 0x10000015 - /* The OOL buffer size is too large for RT behavior */ + /* compatibility: no longer a returned error */ #define MACH_RCV_IN_PROGRESS 0x10004001 /* Thread is waiting for receive. (Internal use only.) */ @@ -527,7 +532,7 @@ typedef kern_return_t mach_msg_return_t; #define MACH_RCV_INTERRUPTED 0x10004005 /* Software interrupt. */ #define MACH_RCV_PORT_CHANGED 0x10004006 - /* Port moved into a set during the receive. */ + /* compatibility: no longer a returned error */ #define MACH_RCV_INVALID_NOTIFY 0x10004007 /* Bogus notify port argument. */ #define MACH_RCV_INVALID_DATA 0x10004008 @@ -535,7 +540,7 @@ typedef kern_return_t mach_msg_return_t; #define MACH_RCV_PORT_DIED 0x10004009 /* Port/set was sent away/died during receive. */ #define MACH_RCV_IN_SET 0x1000400a - /* Port is a member of a port set. */ + /* compatibility: no longer a returned error */ #define MACH_RCV_HEADER_ERROR 0x1000400b /* Error receiving message header. See special bits. */ #define MACH_RCV_BODY_ERROR 0x1000400c @@ -549,6 +554,23 @@ typedef kern_return_t mach_msg_return_t; #define MACH_RCV_IN_PROGRESS_TIMED 0x10004011 /* Waiting for receive with timeout. (Internal use only.) */ +/* + * Routine: mach_msg_overwrite + * Purpose: + * Send and/or receive a message. If the message operation + * is interrupted, and the user did not request an indication + * of that fact, then restart the appropriate parts of the + * operation silently (trap version does not restart). + * + * Distinct send and receive buffers may be specified. If + * no separate receive buffer is specified, the msg parameter + * will be used for both send and receive operations. + * + * In addition to a distinct receive buffer, that buffer may + * already contain scatter control information to direct the + * receiving of the message. + */ +#ifdef __APPLE_API_PRIVATE extern mach_msg_return_t mach_msg_overwrite_trap( mach_msg_header_t *msg, mach_msg_option_t option, @@ -559,6 +581,7 @@ extern mach_msg_return_t mach_msg_overwrite_trap( mach_port_name_t notify, mach_msg_header_t *rcv_msg, mach_msg_size_t rcv_limit); +#endif /* __APPLE_API_PRIVATE */ extern mach_msg_return_t mach_msg_overwrite( mach_msg_header_t *msg, @@ -571,6 +594,15 @@ extern mach_msg_return_t mach_msg_overwrite( mach_msg_header_t *rcv_msg, mach_msg_size_t rcv_limit); +/* + * Routine: mach_msg + * Purpose: + * Send and/or receive a message. If the message operation + * is interrupted, and the user did not request an indication + * of that fact, then restart the appropriate parts of the + * operation silently (trap version does not restart). + */ +#ifdef __APPLE_API_PRIVATE extern mach_msg_return_t mach_msg_trap( mach_msg_header_t *msg, mach_msg_option_t option, @@ -579,6 +611,7 @@ extern mach_msg_return_t mach_msg_trap( mach_port_name_t rcv_name, mach_msg_timeout_t timeout, mach_port_name_t notify); +#endif /* __APPLE_API_PRIVATE */ extern mach_msg_return_t mach_msg( mach_msg_header_t *msg, diff --git a/osfmk/mach/mig.h b/osfmk/mach/mig.h index 8bc149230..fa6ac0b03 100644 --- a/osfmk/mach/mig.h +++ b/osfmk/mach/mig.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -30,9 +30,10 @@ #ifndef _MACH_MIG_H_ #define _MACH_MIG_H_ +#include #include #include -#include +#include /* * Definition for MIG-generated server stub routines. These routines @@ -58,22 +59,72 @@ typedef mig_routine_t (*mig_server_routine_t) (mach_msg_header_t *InHeadP); */ typedef kern_return_t (*mig_impl_routine_t)(void); -typedef struct mig_routine_descriptor { - mig_stub_routine_t stub_routine; /* Unmarshalling function */ - mach_msg_size_t max_reply_msg; /* Max size for this reply */ -} mig_routine_descriptor; -typedef mig_routine_descriptor *mig_routine_descriptor_t; +typedef mach_msg_type_descriptor_t routine_arg_descriptor; +typedef mach_msg_type_descriptor_t *routine_arg_descriptor_t; +typedef mach_msg_type_descriptor_t *mig_routine_arg_descriptor_t; + +#define MIG_ROUTINE_ARG_DESCRIPTOR_NULL ((mig_routine_arg_descriptor_t)0) + +struct routine_descriptor { + mig_impl_routine_t impl_routine; /* Server work func pointer */ + mig_stub_routine_t stub_routine; /* Unmarshalling func pointer */ + unsigned int argc; /* Number of argument words */ + unsigned int descr_count; /* Number complex descriptors */ + routine_arg_descriptor_t + arg_descr; /* pointer to descriptor array*/ + unsigned int max_reply_msg; /* Max size for reply msg */ +}; +typedef struct routine_descriptor *routine_descriptor_t; + +typedef struct routine_descriptor mig_routine_descriptor; +typedef mig_routine_descriptor *mig_routine_descriptor_t; + +#define MIG_ROUTINE_DESCRIPTOR_NULL ((mig_routine_descriptor_t)0) typedef struct mig_subsystem { - mig_server_routine_t server; /* server routine */ - mach_msg_id_t start; /* Min routine number */ - mach_msg_id_t end; /* Max routine number + 1 */ - mach_msg_size_t max_reply; /* Max reply message size */ - mach_msg_size_t max_request; /* Max request msg size */ - mig_routine_descriptor routine[1]; /* Routine descriptor array */ + mig_server_routine_t server; /* pointer to demux routine */ + mach_msg_id_t start; /* Min routine number */ + mach_msg_id_t end; /* Max routine number + 1 */ + mach_msg_size_t maxsize; /* Max reply message size */ + vm_address_t reserved; /* reserved for MIG use */ + mig_routine_descriptor + routine[1]; /* Routine descriptor array */ } *mig_subsystem_t; +#define MIG_SUBSYSTEM_NULL ((mig_subsystem_t)0) + +typedef struct mig_symtab { + char *ms_routine_name; + int ms_routine_number; + void (*ms_routine)(void); /* Since the functions in the + * symbol table have unknown + * signatures, this is the best + * we can do... + */ +} mig_symtab_t; + +/* Client side reply port allocate */ +extern mach_port_t mig_get_reply_port(void); + +/* Client side reply port deallocate */ +extern void mig_dealloc_reply_port(mach_port_t reply_port); + +/* Client side reply port "deallocation" */ +extern void mig_put_reply_port(mach_port_t reply_port); + +/* Bounded string copy */ +extern int mig_strncpy(char *dest, const char *src, int len); + #ifdef KERNEL_PRIVATE +#include + +/* Allocate memory for out-of-stack mig structures */ +extern char *mig_user_allocate(vm_size_t size); + +/* Deallocate memory used for out-of-stack mig structures */ +extern void mig_user_deallocate(char *data, vm_size_t size); + +#ifdef __APPLE_API_EVOLVING /* * MIG object runtime definitions * @@ -92,7 +143,7 @@ typedef struct mig_subsystem { * Coming soon: * - User-level support */ -typedef unsigned int mig_notify_type_t; +typedef unsigned int mig_notify_type_t; typedef struct MIGIID { unsigned long data1; @@ -185,6 +236,8 @@ struct IMIGNotifyObjectVtbl { mig_notify_type_t notify_type); }; +#endif /* __APPLE_API_EVOLVING */ + #endif /* KERNEL_PRIVATE */ #endif /* _MACH_MIG_H_ */ diff --git a/osfmk/mach/mig_errors.h b/osfmk/mach/mig_errors.h index 6a08cffa9..680054f57 100644 --- a/osfmk/mach/mig_errors.h +++ b/osfmk/mach/mig_errors.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -57,10 +57,10 @@ #ifndef _MACH_MIG_ERRORS_H_ #define _MACH_MIG_ERRORS_H_ -#include +#include +#include #include -#include -#include +#include /* * These error codes should be specified as system 4, subsytem 2. @@ -82,43 +82,15 @@ #define MIG_SERVER_DIED -308 /* server died */ #define MIG_TRAILER_ERROR -309 /* trailer has an unknown format */ -#include - +/* + * Whenever MIG detects an error, it sends back a generic + * mig_reply_error_t format message. Clients must accept + * these in addition to the expected reply message format. + */ typedef struct { mach_msg_header_t Head; NDR_record_t NDR; kern_return_t RetCode; } mig_reply_error_t; -typedef struct mig_symtab { - char *ms_routine_name; - int ms_routine_number; - void (*ms_routine)(void); /* Since the functions in the - * symbol table have unknown - * signatures, this is the best - * we can do... - */ -} mig_symtab_t; - -/* Client side reply port allocate */ -extern mach_port_t mig_get_reply_port(void); - -/* Client side reply port deallocate */ -extern void mig_dealloc_reply_port(mach_port_t reply_port); - -/* Client side reply port "deallocation" */ -extern void mig_put_reply_port(mach_port_t reply_port); - -/* Allocate memory for out-of-stack mig structures */ -extern char *mig_user_allocate(vm_size_t size); - -/* Deallocate memory used for out-of-stack mig structures */ -extern void mig_user_deallocate(char *data, vm_size_t size); - -/* Bounded string copy */ -extern int mig_strncpy( - char *dest, - char *src, - int len); - #endif /* _MACH_MIG_ERRORS_H_ */ diff --git a/osfmk/mach/mig_log.h b/osfmk/mach/mig_log.h index 923c0b51e..c8f1e7190 100644 --- a/osfmk/mach/mig_log.h +++ b/osfmk/mach/mig_log.h @@ -22,35 +22,14 @@ /* * @OSF_COPYRIGHT@ */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:30 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.1.1.1 1998/03/07 02:25:46 wsanchez - * Import of OSF Mach kernel (~mburg) - * - * Revision 1.2.6.1 1994/09/23 02:40:32 ezf - * change marker to not FREE - * [1994/09/22 21:41:53 ezf] - * - * Revision 1.2.2.2 1993/06/09 02:42:27 gm - * Added to OSF/1 R1.3 from NMK15.0. - * [1993/06/02 21:17:28 jeffc] - * - * Revision 1.2 1993/04/19 16:36:32 devrcs - * Merge untyped ipc: - * Support for logging and tracing within the MIG stubs - * [1993/02/24 14:47:01 travos] - * [1993/03/16 13:19:16 rod] - * - * $EndLog$ - */ #ifndef _mig_log_ #define _mig_log_ +#include + +#ifdef __APPLE_API_OBSOLETE + typedef enum { MACH_MSG_LOG_USER, MACH_MSG_LOG_SERVER @@ -106,5 +85,7 @@ extern int mig_tracing; #define LOG_ERRORS if (mig_errors) MigEventErrors #define LOG_TRACE if (mig_tracing) MigEventTracer +#endif /* __APPLE_API_OBSOLETE */ + #endif /* _mach_log_ */ diff --git a/osfmk/mach/norma_task.defs b/osfmk/mach/norma_task.defs deleted file mode 100644 index 462442bd3..000000000 --- a/osfmk/mach/norma_task.defs +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * @OSF_COPYRIGHT@ - */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:30 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.1.1.1 1998/03/07 02:25:46 wsanchez - * Import of OSF Mach kernel (~mburg) - * - * Revision 1.1.6.1 1994/09/23 02:41:09 ezf - * change marker to not FREE - * [1994/09/22 21:42:07 ezf] - * - * Revision 1.1.2.2 1993/06/02 23:47:12 jeffc - * Added to OSF/1 R1.3 from NMK15.0. - * [1993/06/02 21:17:42 jeffc] - * - * Revision 1.1 1992/09/30 02:22:57 robert - * Initial revision - * - * $EndLog$ - */ -/* CMU_HIST */ -/* CMU_ENDHIST */ diff --git a/osfmk/mach/notify.h b/osfmk/mach/notify.h index 259ab0942..716f3e4fe 100644 --- a/osfmk/mach/notify.h +++ b/osfmk/mach/notify.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,97 +22,6 @@ /* * @OSF_COPYRIGHT@ */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:30 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.1.1.1 1998/03/07 02:25:46 wsanchez - * Import of OSF Mach kernel (~mburg) - * - * Revision 1.2.12.2 1996/01/09 19:22:05 devrcs - * Made not_count in mach_no_senders_notification_t - * a mach_msg_type_number_t. - * [1995/12/01 19:49:21 jfraser] - * - * Merged '64-bit safe' changes from DEC alpha port. - * [1995/11/21 18:09:14 jfraser] - * - * Revision 1.2.12.1 1994/09/23 02:41:27 ezf - * change marker to not FREE - * [1994/09/22 21:42:15 ezf] - * - * Revision 1.2.6.5 1993/09/09 16:07:46 jeffc - * CR9745 - delete message accepted notifications - * [1993/09/03 22:15:11 jeffc] - * - * Revision 1.2.6.4 1993/08/05 19:09:35 jeffc - * CR9508 - Delete dead code. Remove MACH_IPC_TYPED - * [1993/08/03 20:18:41 jeffc] - * - * CR9508 - Delete dead code. Remove MACH_IPC_COMPAT - * [1993/08/03 17:09:19 jeffc] - * - * Revision 1.2.6.3 1993/08/03 18:29:46 gm - * CR9596: Change KERNEL to MACH_KERNEL. - * [1993/08/02 18:24:51 gm] - * - * Revision 1.2.6.2 1993/06/09 02:42:49 gm - * Fix untyped notifications. CR #8969 - * [1993/04/27 11:29:30 rod] - * - * Revision 1.2 1993/04/19 16:38:19 devrcs - * Added trailer support to untyped ipc. [travos@osf.org, fdr@osf.org] - * [1993/04/06 18:28:00 travos] - * Merge untyped ipc: - * Remove the NDR format label from messages with no untyped data - * [1993/03/12 22:50:02 travos] - * changed msgh_body to not_body in the notification message structures. - * [1993/02/25 21:50:38 fdr] - * New definitions for notifications (via compile option MACH_IPC_TYPED) - * [1993/02/24 19:25:42 travos] - * - * ansi C conformance changes - * [1993/02/02 18:54:03 david] - * Revision 1.1 1992/09/30 02:31:55 robert - * Initial revision - * [1993/02/02 19:05:08 david] - * - * $EndLog$ - */ -/* CMU_HIST */ -/* - * Revision 2.4.2.1 92/03/03 16:22:23 jeffreyh - * Changes form TRUNK - * [92/02/26 12:12:10 jeffreyh] - * - * Revision 2.5 92/01/15 13:44:41 rpd - * Changed MACH_IPC_COMPAT conditionals to default to not present. - * - * Revision 2.4 91/05/14 16:58:21 mrt - * Correcting copyright - * - * Revision 2.3 91/02/05 17:35:18 mrt - * Changed to new Mach copyright - * [91/02/01 17:20:02 mrt] - * - * Revision 2.2 90/06/02 14:59:32 rpd - * Converted to new IPC. - * [90/03/26 22:38:14 rpd] - * - * Revision 2.7.7.1 90/02/20 22:24:32 rpd - * Revised for new IPC. - * [90/02/19 23:38:57 rpd] - * - * - * Condensed history: - * Moved ownership rights under MACH_IPC_XXXHACK (rpd). - * Added NOTIFY_PORT_DESTROYED (rpd). - * Added notification message structure definition (mwyoung). - * Created, based on Accent values (mwyoung). - */ -/* CMU_ENDHIST */ /* * Mach Operating System * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University diff --git a/osfmk/mach/policy.h b/osfmk/mach/policy.h index fdc6f0ecf..12df6e4f5 100644 --- a/osfmk/mach/policy.h +++ b/osfmk/mach/policy.h @@ -64,6 +64,18 @@ #include #include +#include + +/* + * Old scheduling control interface + */ +typedef int policy_t; +typedef integer_t *policy_info_t; +typedef integer_t *policy_base_t; +typedef integer_t *policy_limit_t; + +#ifdef __APPLE_API_UNSTABLE + /* * Policy definitions. Policies should be powers of 2, * but cannot be or'd together other than to test for a @@ -90,15 +102,6 @@ (policy) != POLICY_FIFO) -/* - * New scheduling control interface - */ -typedef int policy_t; -typedef integer_t *policy_info_t; -typedef integer_t *policy_base_t; -typedef integer_t *policy_limit_t; - - /* * Types for TIMESHARE policy */ @@ -224,4 +227,6 @@ typedef struct policy_bases policy_base_data_t; typedef struct policy_limits policy_limit_data_t; typedef struct policy_infos policy_info_data_t; +#endif /* __APPLE_API_UNSTABLE */ + #endif /* _MACH_POLICY_H_ */ diff --git a/osfmk/mach/port.h b/osfmk/mach/port.h index 42c182000..df7d75142 100644 --- a/osfmk/mach/port.h +++ b/osfmk/mach/port.h @@ -61,9 +61,12 @@ #ifndef _MACH_PORT_H_ #define _MACH_PORT_H_ +#include #include #include +#include + /* * A port_name_t is a 32 bit value which represents a name of a * port right within some ipc space. This is a constant definition @@ -80,18 +83,38 @@ * are naked rights) these rights are represented by passing a * pointer to the specific ipc_object_t subclass (typically * ipc_port_t) that got altered/is to be altered. + * + * JMM - Because of this pointer/integer overloading, port names + * should be defined as uintptr_t types. But that would make + * message headers and descriptors pointer-length dependent. */ typedef natural_t port_name_t; typedef port_name_t *port_name_array_t; #ifdef KERNEL_PRIVATE -#include -typedef ipc_port_t port_t; +#if !defined(__APPLE_API_PRIVATE) || !defined(MACH_KERNEL_PRIVATE) +/* + * For kernel code that resides outside of mach + * we define empty structs so that everything will + * remain strongly typed, without giving out + * implementation details. + */ +struct ipc_port ; + +#endif /* !__APPLE_API_PRIVATE || !MACH_KERNEL_PRIVATE */ + +typedef struct ipc_port *ipc_port_t; +typedef ipc_port_t port_t; + +#define IPC_PORT_NULL ((ipc_port_t) 0) +#define IPC_PORT_DEAD ((ipc_port_t)~0) +#define IPC_PORT_VALID(port) (((port) != IPC_PORT_NULL) && \ + ((port) != IPC_PORT_DEAD)) #else /* ! KERNEL_PRIVATE */ -typedef port_name_t port_t; +typedef port_name_t port_t; #endif /* KERNEL_PRIVATE */ @@ -214,16 +237,10 @@ typedef natural_t mach_port_msgcount_t; /* number of msgs */ typedef natural_t mach_port_rights_t; /* number of rights */ /* - * A port may have NMS detection enabled, in which case - * it tracks outstanding send rights. Otherwise, there - * is no information available about outstanding srights. - * The return values are deliberately chosen to match - * the old boolean (0=FALSE=no srights, 1=TRUE=srights, - * 2=xxx=no information available). + * Are there outstanding send rights for a given port? */ -#define MACH_PORT_SRIGHTS_NONE 0 /* NMS: no srights */ -#define MACH_PORT_SRIGHTS_PRESENT 1 /* NMS: srights */ -#define MACH_PORT_SRIGHTS_NO_INFO 2 /* no NMS */ +#define MACH_PORT_SRIGHTS_NONE 0 /* no srights */ +#define MACH_PORT_SRIGHTS_PRESENT 1 /* srights */ typedef unsigned int mach_port_srights_t; /* status of send rights */ typedef struct mach_port_status { diff --git a/osfmk/mach/ppc/exception.h b/osfmk/mach/ppc/exception.h index fbb1dadd4..480c56edf 100644 --- a/osfmk/mach/ppc/exception.h +++ b/osfmk/mach/ppc/exception.h @@ -95,6 +95,7 @@ /* * EXC_SOFTWARE + * Note: 0x10000-0x10003 in use for unix signal */ #define EXC_PPC_TRAP 1 /* Program trap */ #define EXC_PPC_MIGRATE 0x10100 /* Time to bolt */ diff --git a/osfmk/mach/ppc/machine_types.defs b/osfmk/mach/ppc/machine_types.defs index 59c1c916e..022702abd 100644 --- a/osfmk/mach/ppc/machine_types.defs +++ b/osfmk/mach/ppc/machine_types.defs @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002,2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,41 +22,6 @@ /* * @OSF_COPYRIGHT@ */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:31 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.1.1.1 1998/03/07 02:25:46 wsanchez - * Import of OSF Mach kernel (~mburg) - * - * Revision 1.1.8.1 1996/12/09 16:50:08 stephen - * nmklinux_1.0b3_shared into pmk1.1 - * [1996/12/09 10:51:04 stephen] - * - * Revision 1.1.6.1 1996/04/11 11:19:58 emcmanus - * Copied from mainline.ppc. - * [1996/04/10 16:56:50 emcmanus] - * - * mk6 CR668 - 1.3b26 merge - * new file for mk6 - * [1994/11/02 18:18:29 dwm] - * - * Revision 1.1.4.1 1995/11/23 17:36:53 stephen - * first powerpc checkin to mainline.ppc - * [1995/11/23 16:45:00 stephen] - * - * Revision 1.1.2.1 1995/08/25 06:49:44 stephen - * Initial checkin of files for PowerPC port - * [1995/08/23 15:04:13 stephen] - * - * Revision 1.1.2.1 1994/05/06 18:54:50 tmt - * New Mig definition file to describe required machine types. - * [1994/05/05 21:08:57 tmt] - * - * $EndLog$ - */ /* * Header file for basic, machine-dependent data types. i386 version. */ @@ -64,27 +29,40 @@ #ifndef _MACHINE_VM_TYPES_DEFS_ #define _MACHINE_VM_TYPES_DEFS_ 1 +type short = int16_t; +type int = int32_t; +type unsigned = uint32_t; + +type float = MACH_MSG_TYPE_REAL_32; +type double = MACH_MSG_TYPE_REAL_64; + + +/* from ISO/IEC 988:1999 spec */ +/* 7.18.1.4 Integer types capable of hgolding object pointers */ /* - * A natural_t is the type for the native + * The [u]intptr_t types for the native * integer type, e.g. 32 or 64 or.. whatever - * register size the machine has. Unsigned, it is + * register size the machine has. They are * used for entities that might be either - * unsigned integers or pointers, and for + * [unsigned] integers or pointers, and for * type-casting between the two. + * * For instance, the IPC system represents * a port in user space as an integer and * in kernel space as a pointer. */ -type natural_t = unsigned32; +type uintptr_t = MACH_MSG_TYPE_INTEGER_32; +type intptr_t = MACH_MSG_TYPE_INTEGER_32; /* - * An integer_t is the signed counterpart - * of the natural_t type. Both types are - * only supposed to be used to define - * other types in a machine-independent - * way. + * These are the legacy Mach types that are + * the [rough] equivalents of the standards above. + * They were defined in terms of int, not + * long int, so they remain separate. */ -type integer_t = int32; +type integer_t = int32_t; +type natural_t = uint32_t; +type register_t = int32_t; #if MACH_IPC_COMPAT diff --git a/osfmk/mach/ppc/rpc.h b/osfmk/mach/ppc/rpc.h index f0283ec31..1ceb410c3 100644 --- a/osfmk/mach/ppc/rpc.h +++ b/osfmk/mach/ppc/rpc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002,2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -26,27 +26,6 @@ #ifndef _MACH_PPC_RPC_H_ #define _MACH_PPC_RPC_H_ -#include - -/* - * Just temporary until all vestiges of short-curcuiting can be removed. - */ -#define CAN_SHCIRCUIT(name) (0) - -/* - * Note, these don't quite work for PowerPC, because there are different - * ABIs that lay the parameters out some in registers and some in memory - * with slightly different results. We need to change MIG to assure a - * consistent layout regardless of ABI. - */ -#define MACH_RPC_ARGV(act) (char*)(USER_REGS(act)->r3) -#define MACH_RPC_RET(act) ( USER_REGS(act)->lr ) -#define MACH_RPC_UIP(act) ( USER_REGS(act)->srr0 ) -#define MACH_RPC_USP(act) ( USER_REGS(act)->r1 ) -/* FIXME!! */ -#define MACH_RPC_FUNC(act) ( USER_REGS(act)->r2 ) -#define MACH_RPC_SIG(act) ( USER_REGS(act)->r2 ) - #endif /* _MACH_PPC_RPC_H_ */ diff --git a/osfmk/mach/ppc/syscall_sw.h b/osfmk/mach/ppc/syscall_sw.h index 72d4151e4..1af2369d8 100644 --- a/osfmk/mach/ppc/syscall_sw.h +++ b/osfmk/mach/ppc/syscall_sw.h @@ -70,6 +70,7 @@ ppc_trap(bb_enable_bluebox,0x6005) ppc_trap(bb_disable_bluebox,0x6006) ppc_trap(bb_settaskenv,0x6007) ppc_trap(vmm_stop_vm,0x6008) +ppc_trap(CHUDCall,0x6009) #endif /* _MACH_SYSCALL_SW_H_ */ #endif /* _MACH_PPC_SYSCALL_SW_H_ */ diff --git a/osfmk/mach/ppc/thread_status.h b/osfmk/mach/ppc/thread_status.h index 6dd8ba95d..5f95da004 100644 --- a/osfmk/mach/ppc/thread_status.h +++ b/osfmk/mach/ppc/thread_status.h @@ -26,6 +26,11 @@ #ifndef _MACH_PPC_THREAD_STATUS_H_ #define _MACH_PPC_THREAD_STATUS_H_ +#include + +#ifdef MACH_KERNEL_PRIVATE +#include +#endif /* * ppc_thread_state is the structure that is exported to user threads for * use in status/mutate calls. This structure should never change. @@ -117,61 +122,15 @@ typedef struct ppc_vector_state { /* * saved state structure * - * This structure corresponds to the state of the user registers as saved - * on the stack upon kernel entry (saved in pcb). On interrupts and exceptions - * we save all registers. On system calls we only save the registers not - * saved by the caller. + * This structure corresponds to the saved state. * */ -typedef struct ppc_saved_state { - unsigned int srr0; /* Instruction address register (PC) */ - unsigned int srr1; /* Machine state register (supervisor) */ - unsigned int r0; - unsigned int r1; - unsigned int r2; - unsigned int r3; - unsigned int r4; - unsigned int r5; - unsigned int r6; - unsigned int r7; - unsigned int r8; - unsigned int r9; - unsigned int r10; - unsigned int r11; - unsigned int r12; - unsigned int r13; - unsigned int r14; - unsigned int r15; - unsigned int r16; - unsigned int r17; - unsigned int r18; - unsigned int r19; - unsigned int r20; - unsigned int r21; - unsigned int r22; - unsigned int r23; - unsigned int r24; - unsigned int r25; - unsigned int r26; - unsigned int r27; - unsigned int r28; - unsigned int r29; - unsigned int r30; - unsigned int r31; - - unsigned int cr; /* Condition register */ - unsigned int xer; /* User's integer exception register */ - unsigned int lr; /* Link register */ - unsigned int ctr; /* Count register */ - unsigned int mq; /* MQ register (601 only) */ - unsigned int vrsave; /* Vector Register Save */ - -/* These are extra. Remove them from the count */ - - unsigned int sr_copyin; /* SR_COPYIN is used for remapping */ - unsigned int pad2[7]; /* struct alignment */ -} ppc_saved_state_t; +#if defined(__APPLE_API_PRIVATE) && defined(MACH_KERNEL_PRIVATE) +typedef struct savearea ppc_saved_state_t; +#else +typedef struct ppc_thread_state ppc_saved_state_t; +#endif /* __APPLE_API_PRIVATE && MACH_KERNEL_PRIVATE */ /* * ppc_exception_state diff --git a/osfmk/mach/ppc/vm_types.h b/osfmk/mach/ppc/vm_types.h index 855c1da16..157684e16 100644 --- a/osfmk/mach/ppc/vm_types.h +++ b/osfmk/mach/ppc/vm_types.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002,2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,79 +22,6 @@ /* * @OSF_COPYRIGHT@ */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:31 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.1.1.1 1998/03/07 02:25:46 wsanchez - * Import of OSF Mach kernel (~mburg) - * - * Revision 1.1.8.1 1996/12/09 16:50:19 stephen - * nmklinux_1.0b3_shared into pmk1.1 - * [1996/12/09 10:51:34 stephen] - * - * Revision 1.1.6.1 1996/04/11 11:20:26 emcmanus - * Copied from mainline.ppc. - * [1996/04/10 16:57:16 emcmanus] - * - * Revision 1.1.4.1 1995/11/23 17:37:13 stephen - * first powerpc checkin to mainline.ppc - * [1995/11/23 16:45:52 stephen] - * - * Revision 1.1.2.1 1995/08/25 06:50:05 stephen - * Initial checkin of files for PowerPC port - * [1995/08/23 15:05:11 stephen] - * - * Revision 1.2.8.2 1995/01/06 19:50:48 devrcs - * mk6 CR668 - 1.3b26 merge - * 64bit cleanup - * [1994/10/14 03:42:42 dwm] - * - * Revision 1.2.8.1 1994/09/23 02:38:01 ezf - * change marker to not FREE - * [1994/09/22 21:40:30 ezf] - * - * Revision 1.2.2.2 1993/06/09 02:41:01 gm - * Added to OSF/1 R1.3 from NMK15.0. - * [1993/06/02 21:16:38 jeffc] - * - * Revision 1.2 1993/04/19 16:34:37 devrcs - * ansi C conformance changes - * [1993/02/02 18:56:34 david] - * - * Revision 1.1 1992/09/30 02:30:57 robert - * Initial revision - * - * $EndLog$ - */ -/* CMU_HIST */ -/* - * Revision 2.4 91/05/14 16:53:00 mrt - * Correcting copyright - * - * Revision 2.3 91/02/05 17:32:34 mrt - * Changed to new Mach copyright - * [91/02/01 17:10:49 mrt] - * - * Revision 2.2 90/05/03 15:48:32 dbg - * First checkin. - * - * Revision 1.3 89/03/09 20:20:12 rpd - * More cleanup. - * - * Revision 1.2 89/02/26 13:01:20 gm0w - * Changes for cleanup. - * - * 31-Dec-88 Robert Baron (rvb) at Carnegie-Mellon University - * Derived from MACH2.0 vax release. - * - * 23-Apr-87 Michael Young (mwyoung) at Carnegie-Mellon University - * Changed things to "unsigned int" to appease the user community :-). - * - */ -/* CMU_ENDHIST */ /* * Mach Operating System * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University @@ -158,14 +85,6 @@ typedef unsigned int natural_t; */ typedef int integer_t; -#ifdef MACH_KERNEL_PRIVATE -/* - * An int32 is an integer that is at least 32 bits wide - */ -typedef int int32; -typedef unsigned int uint32; -#endif - /* * A vm_offset_t is a type-neutral pointer, * e.g. an offset into a virtual memory space. @@ -178,7 +97,6 @@ typedef natural_t vm_offset_t; * vm_offset_t entities. */ typedef natural_t vm_size_t; -typedef unsigned long long vm_double_size_t; /* * space_t is used in the pmap system diff --git a/osfmk/mach/rpc.h b/osfmk/mach/rpc.h index 2794e4dd9..29d511d22 100644 --- a/osfmk/mach/rpc.h +++ b/osfmk/mach/rpc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002,2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -40,95 +40,17 @@ #include #include -#ifdef MACH_KERNEL_PRIVATE -#include -#endif /* MACH_KERNEL_PRIVATE */ +#include + +#ifdef __APPLE_API_OBSOLETE /* - * The various bits of the type field of the routine_arg_descriptor + * These are the types for RPC-specific variants of the MIG routine + * descriptor and subsystem data types. + * + * THIS IS ONLY FOR COMPATIBILITY. WE WILL NOT BE IMPLEMENTING THIS. */ -/* The basic types */ - -#define TYPE_SHIFT 0 -#define MACH_RPC_PORT (1 << TYPE_SHIFT) -#define MACH_RPC_ARRAY (1 << (TYPE_SHIFT + 1)) -#define MACH_RPC_VARIABLE (1 << (TYPE_SHIFT + 2)) -#define LAST_TYPE_BIT (TYPE_SHIFT+3) - -/* XXX Port arrays need not be variable arrays, as assumed below. Fixme. */ -#define MACH_RPC_ARRAY_FIX (MACH_RPC_ARRAY) -#define MACH_RPC_ARRAY_FIXED (MACH_RPC_ARRAY) -#define MACH_RPC_ARRAY_VAR (MACH_RPC_ARRAY | MACH_RPC_VARIABLE) -#define MACH_RPC_ARRAY_VARIABLE (MACH_RPC_ARRAY | MACH_RPC_VARIABLE) -#define MACH_RPC_PORT_ARRAY (MACH_RPC_PORT | MACH_RPC_ARRAY_VAR) - -/* Argument direction bits */ - -#define DIRECT_SHIFT LAST_TYPE_BIT -#define DIRECTION_SHIFT LAST_TYPE_BIT -#define MACH_RPC_IN (1 << DIRECTION_SHIFT) -#define MACH_RPC_OUT (1 << (DIRECTION_SHIFT + 1)) -#define LAST_DIRECT_BIT (DIRECTION_SHIFT + 2) -#define LAST_DIRECTION_BIT (DIRECTION_SHIFT + 2) - -#define MACH_RPC_INOUT (MACH_RPC_IN | MACH_RPC_OUT) - -/* Persist and pointer bit */ - -#define POINTER_SHIFT LAST_DIRECTION_BIT -#define MACH_RPC_POINTER (1 << POINTER_SHIFT) -#define LAST_POINTER_BIT (POINTER_SHIFT + 1) - -/* Port disposition bits */ - -#define NAME_SHIFT LAST_POINTER_BIT -#define MACH_RPC_RECEIVE (1 << NAME_SHIFT) -#define MACH_RPC_SEND (2 << NAME_SHIFT) -#define MACH_RPC_SEND_ONCE (3 << NAME_SHIFT) -#define LAST_NAME_BIT (NAME_SHIFT + 2) - -#define ACTION_SHIFT LAST_NAME_BIT -#define MACH_RPC_MOVE (1 << ACTION_SHIFT) -#define MACH_RPC_COPY (2 << ACTION_SHIFT) -#define MACH_RPC_MAKE (3 << ACTION_SHIFT) -#define LAST_ACTION_BIT (ACTION_SHIFT + 2) - -#define MACH_RPC_MOVE_RECEIVE (MACH_RPC_MOVE | MACH_RPC_RECEIVE) -#define MACH_RPC_MOVE_SEND (MACH_RPC_MOVE | MACH_RPC_SEND) -#define MACH_RPC_COPY_SEND (MACH_RPC_COPY | MACH_RPC_SEND) -#define MACH_RPC_MAKE_SEND (MACH_RPC_MAKE | MACH_RPC_SEND) -#define MACH_RPC_MOVE_SEND_ONCE (MACH_RPC_MOVE | MACH_RPC_SEND_ONCE) -#define MACH_RPC_MAKE_SEND_ONCE (MACH_RPC_MAKE | MACH_RPC_SEND_ONCE) - -/* Hint for virtual vs. physical copy */ - -#define OPTION_SHIFT LAST_ACTION_BIT -#define MACH_RPC_PHYSICAL_COPY (1 << OPTION_SHIFT) -#define MACH_RPC_VIRTUAL_COPY (1 << (OPTION_SHIFT + 1)) -#define LAST_OPTION_BIT (OPTION_SHIFT + 2) - -/* Deallocate? */ - -#define DEALLOCATE_SHIFT LAST_OPTION_BIT -#define MACH_RPC_DEALLOCATE (1 << DEALLOCATE_SHIFT) -#define LAST_DEALLOCATE_BIT (DEALLOCATE_SHIFT + 1) - -/* Argument is already on the stack */ - -#define ONSTACK_SHIFT LAST_DEALLOCATE_BIT -#define MACH_RPC_ONSTACK (1 << ONSTACK_SHIFT) -#define LAST_ONSTACK_BIT (ONSTACK_SHIFT + 1) - -/* Is variable array bounded? Derived from type and arg.size */ - -#define BOUND_SHIFT LAST_ONSTACK_BIT -#define MACH_RPC_BOUND (1 << BOUND_SHIFT) -#define MACH_RPC_UNBOUND (0) -#define BOUND MACH_RPC_BOUND -#define UNBND MACH_RPC_UNBOUND -#define LAST_BOUND_BIT (BOUND_SHIFT + 1) - /* * Basic mach rpc types. */ @@ -139,41 +61,37 @@ typedef unsigned int routine_arg_size; /* * Definitions for a signature's argument and routine descriptor's. */ -struct routine_arg_descriptor { +struct rpc_routine_arg_descriptor { routine_arg_type type; /* Port, Array, etc. */ routine_arg_size size; /* element size in bytes */ routine_arg_size count; /* number of elements */ routine_arg_offset offset; /* Offset in list of routine args */ }; -typedef struct routine_arg_descriptor *routine_arg_descriptor_t; +typedef struct rpc_routine_arg_descriptor *rpc_routine_arg_descriptor_t; -struct routine_descriptor { +struct rpc_routine_descriptor { mig_impl_routine_t impl_routine; /* Server work func pointer */ mig_stub_routine_t stub_routine; /* Unmarshalling func pointer */ unsigned int argc; /* Number of argument words */ unsigned int descr_count; /* Number of complex argument */ /* descriptors */ - struct routine_arg_descriptor * + rpc_routine_arg_descriptor_t arg_descr; /* Pointer to beginning of */ /* the arg_descr array */ unsigned int max_reply_msg; /* Max size for reply msg */ }; -typedef struct routine_descriptor *routine_descriptor_t; +typedef struct rpc_routine_descriptor *rpc_routine_descriptor_t; -#define DESCR_SIZE(x) ((x)->descr_count * sizeof(struct routine_arg_descriptor)) +#define RPC_DESCR_SIZE(x) ((x)->descr_count * \ + sizeof(struct rpc_routine_arg_descriptor)) struct rpc_signature { - struct routine_descriptor rd; - struct routine_arg_descriptor rad[1]; + struct rpc_routine_descriptor rd; + struct rpc_routine_arg_descriptor rad[1]; }; -#ifdef MACH_KERNEL_PRIVATE - -typedef struct rpc_signature *rpc_signature_t; - -#endif - #define RPC_SIGBUF_SIZE 8 + /* * A subsystem describes a set of server routines that can be invoked by * mach_rpc() on the ports that are registered with the subsystem. For @@ -193,18 +111,18 @@ typedef struct rpc_signature *rpc_signature_t; * contiguous. */ struct rpc_subsystem { - struct subsystem *subsystem; /* Reserved for system use */ + void *reserved; /* Reserved for system use */ mach_msg_id_t start; /* Min routine number */ mach_msg_id_t end; /* Max routine number + 1 */ unsigned int maxsize; /* Max mach_msg size */ vm_address_t base_addr; /* Address of this struct in user */ - struct routine_descriptor /* Array of routine descriptors */ + struct rpc_routine_descriptor /* Array of routine descriptors */ routine[1 /* Actually, (start-end+1) */ ]; - struct routine_arg_descriptor + struct rpc_routine_arg_descriptor arg_descriptor[1 /* Actually, the sum of the descr_ */ ]; /* count fields for all routines */ }; @@ -212,213 +130,6 @@ typedef struct rpc_subsystem *rpc_subsystem_t; #define RPC_SUBSYSTEM_NULL ((rpc_subsystem_t) 0) -/* - * New RPC declarations - * - * First pass at definitions and types for the new rpc service. - * This is subject to revision. - */ - -/* - * RPC macros - */ - -#define RPC_MASK(shift,last) \ - ( ((1 << ((last)-(shift)))-1) << (shift) ) - -#define RPC_FIELD(field,shift,last) \ - ( (field) & (((1 << ((last)-(shift)))-1) << (shift)) ) - -#define RPC_BOUND(dsc) \ - (((RPC_FIELD((dsc).type,TYPE_SHIFT+1,TYPE_SHIFT+3) == \ - MACH_RPC_ARRAY_VARIABLE) && (dsc).count != 0) ? MACH_RPC_BOUND : 0) - -#define ROUNDUP2(x,n) ((((unsigned)(x)) + (n) - 1) & ~((n)-1)) -#define ROUNDWORD(x) ROUNDUP2(x,sizeof(int)) - -/* - * RPC errors - * - * Display and process errors of different severity, from just for - * information only to fatal (panic). Error code colors indicate how - * difficult it is for the subsystem to handle the error correctly. - * The implication is that, for example, early versions of the code may - * not be handling code red errors properly. The code should use this - * facility instead of regular printf's. - */ - -#define MACH_RPC_DEBUG 1 - -#define ERR_INFO 1 /* purely informational */ -#define ERR_GREEN 2 /* easily handled error */ -#define ERR_YELLOW 3 /* medium difficult error */ -#define ERR_RED 4 /* difficult to handle error */ -#define ERR_FATAL 5 /* unrecoverable error, panic */ - -#if MACH_RPC_DEBUG > 1 -#define rpc_error(E,S) \ - printf("RPC error "); \ - rpc_error_show_severity(S); \ - printf("in file \"%s\", line %d: ", __FILE__, __LINE__); \ - printf E ; \ - printf("\n"); \ - rpc_error_severity(S) -#else -#define rpc_error(E,S) \ - if ((S) == ERR_FATAL || (S) == ERR_RED) { \ - printf("RPC error "); \ - rpc_error_show_severity(S); \ - printf("in file \"%s\", line %d: ", __FILE__, __LINE__); \ - printf E ; \ - printf("\n"); \ - rpc_error_severity(S); \ - } -#endif /* MACH_RPC_DEBUG */ - -/* - * RPC buffer size and break points - * - * These values define the rpc buffer size on the kernel stack, - * and break point values for switching to virtual copy (cow). - * This should be in a machine dependent include file. All sizes - * are in word (sizeof(int)) units. - */ - -#define RPC_KBUF_SIZE 16 /* kernel stack buffer size (ints) */ -#define RPC_COW_SIZE 1024 /* size where COW is a win (ints) */ -#define RPC_DESC_COUNT 4 /* default descriptor count */ - - -/* - * RPC copy state - * - * Record the rpc copy state for arrays, so we can unwind our state - * during error processing. There is one entry per complex (signatured) - * argument. The first entry is marked COPY_TYPE_ALLOC_KRN if this record - * itself was kalloc'd because the number of complex arg descriptors - * exceeded the default value (RPC_DESC_COUNT). This is not a conflict - * since the first argument is always the destination port, never an array. - */ - -#define COPY_TYPE_NO_COPY 0 /* nothing special */ -#define COPY_TYPE_ON_KSTACK 1 /* array is on kernel stack */ -#define COPY_TYPE_ON_SSTACK 2 /* array is on server stack */ -#define COPY_TYPE_VIRTUAL_IN 3 /* vm_map_copyin part of cow */ -#define COPY_TYPE_VIRTUAL_OUT_SVR 4 /* map cpyout svr part of cow */ -#define COPY_TYPE_VIRTUAL_OUT_CLN 5 /* map cpyout cln part of cow */ -#define COPY_TYPE_ALLOC_KRN 6 /* kernel kalloc'd for array */ -#define COPY_TYPE_ALLOC_SVR 7 /* vm_alloc'd in server space */ -#define COPY_TYPE_ALLOC_CLN 8 /* vm_alloc'd in client space */ -#define COPY_TYPE_PORT 9 /* plain port translated */ -#define COPY_TYPE_PORT_ARRAY 10 /* port array translated */ - - -/* - * RPC types - */ -typedef int rpc_id_t; -typedef int rpc_return_t; -typedef unsigned int rpc_size_t; -typedef unsigned int rpc_offset_t; - -struct rpc_copy_state { - unsigned copy_type; /* what kind of copy */ - vm_offset_t alloc_addr; /* address to free */ -}; -typedef struct rpc_copy_state *rpc_copy_state_t; -typedef struct rpc_copy_state rpc_copy_state_data_t; - -typedef boolean_t (*copyfunc_t)(const char *, char *, vm_size_t); - - -/* - * RPC function declarations - */ - -#ifdef CALLOUT_RPC_MODEL - -extern -void rpc_bootstrap( void ); - -extern -void rpc_remote_bootstrap( void ); - -extern -rpc_return_t mach_rpc_trap( - mach_port_name_t dest_port, - rpc_id_t routine_num, - rpc_signature_t signature_ptr, - rpc_size_t signature_size ); - -extern -rpc_return_t mach_rpc_return_trap( void ); - -extern -rpc_return_t mach_rpc_return_error( void ); - -void mach_rpc_return_wrapper( void ); - -void rpc_upcall( - vm_offset_t stack, - vm_offset_t new_stack, - vm_offset_t server_func, - int return_code ); - -void rpc_error_severity( int severity ); -void rpc_error_show_severity( int severity ); -unsigned int name_rpc_to_ipc( unsigned int action ); - -void clean_port_array( - ipc_object_t * array, - unsigned count, - unsigned cooked, - unsigned direct ); - -void unwind_rpc_state( - routine_descriptor_t routine, - rpc_copy_state_t state, - int * arg_buf ); - -kern_return_t unwind_invoke_state( - thread_act_t thr_act ); - -kern_return_t rpc_invke_args_in( - routine_descriptor_t routine, - rpc_copy_state_t state, - int * arg_buf, - copyfunc_t infunc ); - -kern_return_t rpc_invke_args_out( - routine_descriptor_t routine, - rpc_copy_state_t state, - int * arg_buf, - int ** new_sp, - copyfunc_t outfunc ); - -kern_return_t rpc_reply_args_in( - routine_descriptor_t routine, - rpc_copy_state_t state, - int * svr_buf, - copyfunc_t infunc ); - -kern_return_t rpc_reply_args_out( - routine_descriptor_t routine, - rpc_copy_state_t state, - int * svr_buf, - int * cln_buf, - copyfunc_t outfunc ); - -#endif /* CALLOUT_RPC_MODEL */ - -/* - * libmach helper functions: - */ -extern rpc_subsystem_t mach_subsystem_join( - rpc_subsystem_t, - rpc_subsystem_t, - unsigned int *, - void *(* )(int)); +#endif /* __APPLE_API_OBSOLETE */ #endif /* _MACH_RPC_H_ */ - - diff --git a/osfmk/mach/semaphore.h b/osfmk/mach/semaphore.h index fe21aa9fb..55a4a39ab 100644 --- a/osfmk/mach/semaphore.h +++ b/osfmk/mach/semaphore.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -28,27 +28,6 @@ #include #include -#define SEMAPHORE_OPTION_NONE 0x00000000 - -#define SEMAPHORE_SIGNAL 0x00000001 -#define SEMAPHORE_WAIT 0x00000002 -#define SEMAPHORE_WAIT_ON_SIGNAL 0x00000008 - -#define SEMAPHORE_SIGNAL_TIMEOUT 0x00000010 -#define SEMAPHORE_SIGNAL_ALL 0x00000020 -#define SEMAPHORE_SIGNAL_INTERRUPT 0x00000040 /* libmach implements */ -#define SEMAPHORE_SIGNAL_PREPOST 0x00000080 - -#define SEMAPHORE_WAIT_TIMEOUT 0x00000100 -#define SEMAPHORE_WAIT_INTERRUPT 0x00000400 /* libmach implements */ - -#define SEMAPHORE_TIMEOUT_NOBLOCK 0x00100000 -#define SEMAPHORE_TIMEOUT_RELATIVE 0x00200000 - -#define SEMAPHORE_USE_SAVED_RESULT 0x01000000 /* internal use only */ -#define SEMAPHORE_SIGNAL_RELEASE 0x02000000 /* internal use only */ - - /* * Forward Declarations * @@ -80,10 +59,39 @@ extern kern_return_t semaphore_timedwait_signal(semaphore_t wait_semaphore, semaphore_t signal_semaphore, mach_timespec_t wait_time); +#include + +#ifdef __APPLE_API_PRIVATE +#ifdef __APPLE_API_EVOLVING + +#define SEMAPHORE_OPTION_NONE 0x00000000 + +#define SEMAPHORE_SIGNAL 0x00000001 +#define SEMAPHORE_WAIT 0x00000002 +#define SEMAPHORE_WAIT_ON_SIGNAL 0x00000008 + +#define SEMAPHORE_SIGNAL_TIMEOUT 0x00000010 +#define SEMAPHORE_SIGNAL_ALL 0x00000020 +#define SEMAPHORE_SIGNAL_INTERRUPT 0x00000040 /* libmach implements */ +#define SEMAPHORE_SIGNAL_PREPOST 0x00000080 + +#define SEMAPHORE_WAIT_TIMEOUT 0x00000100 +#define SEMAPHORE_WAIT_INTERRUPT 0x00000400 /* libmach implements */ + +#define SEMAPHORE_TIMEOUT_NOBLOCK 0x00100000 +#define SEMAPHORE_TIMEOUT_RELATIVE 0x00200000 + +#define SEMAPHORE_USE_SAVED_RESULT 0x01000000 /* internal use only */ +#define SEMAPHORE_SIGNAL_RELEASE 0x02000000 /* internal use only */ + extern kern_return_t semaphore_operator (int options, semaphore_t wait_semaphore, semaphore_t signal_semaphore, thread_act_t thread, mach_timespec_t wait_time); +#endif /* __APPLE_API_EVOLVING */ + +#endif /* __APPLE_API_PRIVATE */ + #endif /* _MACH_SEMAPHORE_H_ */ diff --git a/osfmk/mach/shared_memory_server.h b/osfmk/mach/shared_memory_server.h index 2f31ef1fc..4f44265d9 100644 --- a/osfmk/mach/shared_memory_server.h +++ b/osfmk/mach/shared_memory_server.h @@ -21,17 +21,17 @@ */ /* * - * File: kern/shared_memory_server.h + * File: mach/shared_memory_server.h * * protos and struct definitions for shared library * server and interface */ -#ifndef _SHARED_MEMORY_SERVER_H_ -#define _SHARED_MEMORY_SERVER_H_ +#ifndef _MACH_SHARED_MEMORY_SERVER_H_ +#define _MACH_SHARED_MEMORY_SERVER_H_ #define SHARED_LIBRARY_SERVER_SUPPORTED -#define GLOBAL_SHARED_TEXT_SEGMENT 0x70000000 -#define GLOBAL_SHARED_DATA_SEGMENT 0x80000000 +#define GLOBAL_SHARED_TEXT_SEGMENT 0x90000000 +#define GLOBAL_SHARED_DATA_SEGMENT 0xA0000000 #define GLOBAL_SHARED_SEGMENT_MASK 0xF0000000 #define SHARED_TEXT_REGION_SIZE 0x10000000 @@ -49,52 +49,7 @@ #include -#ifndef MACH_KERNEL -#include -#else -#include -#endif - -#ifdef MACH_KERNEL_PRIVATE - -#include -#include -#include - -extern ipc_port_t shared_text_region_handle; -extern ipc_port_t shared_data_region_handle; -#else /* MACH_KERNEL_PRIVATE */ - -#ifdef KERNEL_PRIVATE -extern mach_port_t shared_text_region_handle; -extern mach_port_t shared_data_region_handle; -#endif -#endif /* MACH_KERNEL_PRIVATE*/ - -#ifdef KERNEL_PRIVATE - -extern vm_offset_t shared_file_mapping_array; - - -struct shared_region_task_mappings { - ipc_port_t text_region; - vm_size_t text_size; - ipc_port_t data_region; - vm_size_t data_size; - vm_offset_t region_mappings; - vm_offset_t client_base; - vm_offset_t alternate_base; - vm_offset_t alternate_next; - int flags; - vm_offset_t self; -}; - -#define SHARED_REGION_SYSTEM 0x1 -#define SHARED_REGION_FULL 0x2 - -typedef struct shared_region_task_mappings *shared_region_task_mappings_t; -#endif /* KERNEL_PRIVATE */ - +#include #define SHARED_LIB_ALIAS 0x10 @@ -104,9 +59,11 @@ typedef struct shared_region_task_mappings *shared_region_task_mappings_t; /* IN */ #define ALTERNATE_LOAD_SITE 0x1 #define NEW_LOCAL_SHARED_REGIONS 0x2 +#define QUERY_IS_SYSTEM_REGION 0x4 /* OUT */ #define SF_PREV_LOADED 0x1 +#define SYSTEM_REGION_BACKED 0x2 #define load_file_hash(file_object, size) \ @@ -125,107 +82,4 @@ struct sf_mapping { typedef struct sf_mapping sf_mapping_t; - -#ifdef MACH_KERNEL_PRIVATE - -struct loaded_mapping { - vm_offset_t mapping_offset; - vm_size_t size; - vm_offset_t file_offset; - vm_prot_t protection; /* read/write/execute/COW/ZF */ - - struct loaded_mapping *next; -}; - -typedef struct loaded_mapping loaded_mapping_t; - -struct load_struct { - queue_chain_t links; - shared_region_mapping_t regions_instance; - int depth; - int file_object; - vm_offset_t base_address; - int mapping_cnt; - loaded_mapping_t *mappings; -}; - -#endif /* MACH_KERNEL_PRIVATE */ - -typedef struct load_struct load_struct_t; -typedef struct load_struct *load_struct_ptr_t; - -#ifdef MACH_KERNEL_PRIVATE - -struct load_file_ele { - union { - sf_mapping_t mapping; - load_struct_t element; - } u; -}; - -struct shared_file_info { - mutex_t lock; /* lock for the structure */ - queue_head_t *hash; /* for later perf enhance */ - int hash_size; - boolean_t hash_init; -}; - -typedef struct shared_file_info shared_file_info_t; - -extern kern_return_t -copyin_shared_file( - vm_offset_t mapped_file, - vm_size_t mapped_file_size, - vm_offset_t *base_address, - int map_cnt, - sf_mapping_t *mappings, - memory_object_control_t file_control, - shared_region_task_mappings_t shared_region, - int *flags); - -extern kern_return_t -shared_file_init( - ipc_port_t *shared_text_region_handle, - vm_size_t text_region_size, - ipc_port_t *shared_data_region_handle, - vm_size_t data_region_size, - vm_offset_t *shared_file_mapping_array); - -extern load_struct_t * -lsf_hash_lookup( - queue_head_t *hash_table, - void *file_object, - int size, - boolean_t alternate, - shared_region_task_mappings_t sm_info); - -extern load_struct_t * -lsf_hash_delete( - void *file_object, - vm_offset_t base_offset, - shared_region_task_mappings_t sm_info); - -extern void -lsf_hash_insert( - load_struct_t *entry, - shared_region_task_mappings_t sm_info); - -extern kern_return_t -lsf_load( - vm_offset_t mapped_file, - vm_size_t mapped_file_size, - vm_offset_t *base_address, - sf_mapping_t *mappings, - int map_cnt, - void *file_object, - int flags, - shared_region_task_mappings_t sm_info); - -extern void -lsf_unload( - void *file_object, - vm_offset_t base_offset, - shared_region_task_mappings_t sm_info); - -#endif /* MACH_KERNEL_PRIVATE */ -#endif /* _SHARED_MEMORY_SERVER_H_ */ +#endif /* _MACH_SHARED_MEMORY_SERVER_H_ */ diff --git a/osfmk/mach/std_types.defs b/osfmk/mach/std_types.defs index c5e101ef7..23b1d49f5 100644 --- a/osfmk/mach/std_types.defs +++ b/osfmk/mach/std_types.defs @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002,2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -56,15 +56,33 @@ #ifndef _MACH_STD_TYPES_DEFS_ #define _MACH_STD_TYPES_DEFS_ -type char = MACH_MSG_TYPE_CHAR; -type short = MACH_MSG_TYPE_INTEGER_16; -type int = MACH_MSG_TYPE_INTEGER_32; +/* from ISO/IEC 988:1999 spec */ +/* 7.18.1.1 Exact-width integer types */ + +type int8_t = MACH_MSG_TYPE_INTEGER_8; +type uint8_t = MACH_MSG_TYPE_INTEGER_8; +type int16_t = MACH_MSG_TYPE_INTEGER_16; +type uint16_t = MACH_MSG_TYPE_INTEGER_16; +type int32_t = MACH_MSG_TYPE_INTEGER_32; +type uint32_t = MACH_MSG_TYPE_INTEGER_32; +type int64_t = MACH_MSG_TYPE_INTEGER_64; +type uint64_t = MACH_MSG_TYPE_INTEGER_64; + +/* + * Legacy fixed-length Mach types which should + * be replaced with the Standard types from above. + */ type int32 = MACH_MSG_TYPE_INTEGER_32; -type boolean_t = MACH_MSG_TYPE_BOOLEAN; -type unsigned = MACH_MSG_TYPE_INTEGER_32; type unsigned32 = MACH_MSG_TYPE_INTEGER_32; type int64 = MACH_MSG_TYPE_INTEGER_64; type unsigned64 = MACH_MSG_TYPE_INTEGER_64; + +/* + * Other fixed length Mach types. + */ +type char = MACH_MSG_TYPE_CHAR; +type boolean_t = MACH_MSG_TYPE_BOOLEAN; + #include type kern_return_t = int; @@ -76,10 +94,8 @@ type pointer_t = ^array[] of MACH_MSG_TYPE_BYTE type mach_port_t = MACH_MSG_TYPE_COPY_SEND; type mach_port_array_t = array[] of mach_port_t; -type mach_port_name_t = MACH_MSG_TYPE_PORT_NAME - ctype: mach_port_name_t; -type mach_port_name_array_t = array[] of mach_port_name_t - ctype: mach_port_name_array_t; +type mach_port_name_t = MACH_MSG_TYPE_PORT_NAME; +type mach_port_name_array_t = array[] of mach_port_name_t; type mach_port_right_t = natural_t; @@ -121,5 +137,6 @@ type mach_port_poly_t = polymorphic ctype: mach_port_t; import ; +import ; #endif _MACH_STD_TYPES_DEFS_ diff --git a/osfmk/mach/std_types.h b/osfmk/mach/std_types.h index 864dc86f6..c002d05fe 100644 --- a/osfmk/mach/std_types.h +++ b/osfmk/mach/std_types.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002,2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -57,13 +57,10 @@ #ifndef STD_TYPES_H_ #define STD_TYPES_H_ +#include #include #include #include #include -#ifdef MACH_KERNEL_PRIVATE -#include -#endif /* MACH_KERNEL_PRIVATE */ - #endif /* STD_TYPES_H_ */ diff --git a/osfmk/mach/sync_policy.h b/osfmk/mach/sync_policy.h index 263770e0a..bca61a6d8 100644 --- a/osfmk/mach/sync_policy.h +++ b/osfmk/mach/sync_policy.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -28,9 +28,29 @@ typedef int sync_policy_t; -#define SYNC_POLICY_FIFO 0 -#define SYNC_POLICY_FIXED_PRIORITY 1 -#define SYNC_POLICY_PREPOST 2 -#define SYNC_POLICY_MAX 2 +/* + * These options define the wait ordering of the synchronizers + */ +#define SYNC_POLICY_FIFO 0x0 +#define SYNC_POLICY_FIXED_PRIORITY 0x1 +#define SYNC_POLICY_REVERSED 0x2 +#define SYNC_POLICY_ORDER_MASK 0x3 +#define SYNC_POLICY_LIFO (SYNC_POLICY_FIFO|SYNC_POLICY_REVERSED) + +/* + * These options provide addition (kernel-private) behaviors + */ +#ifdef KERNEL_PRIVATE +#include + +#ifdef __APPLE_API_EVOLVING + +#define SYNC_POLICY_PREPOST 0x4 + +#endif /* __APPLE_API_EVOLVING */ + +#endif /* KERNEL_PRIVATE */ + +#define SYNC_POLICY_MAX 0x7 #endif /*_SYNC_POLICY_H_*/ diff --git a/osfmk/mach/syscall_sw.h b/osfmk/mach/syscall_sw.h index 6ec412ae9..c939b8050 100644 --- a/osfmk/mach/syscall_sw.h +++ b/osfmk/mach/syscall_sw.h @@ -72,6 +72,7 @@ kernel_trap(mach_reply_port,-26,0) kernel_trap(thread_self_trap,-27,0) kernel_trap(task_self_trap,-28,0) kernel_trap(host_self_trap,-29,0) +kernel_trap(mach_msg_trap,-31,7) kernel_trap(mach_msg_overwrite_trap,-32,9) kernel_trap(semaphore_signal_trap, -33, 1) kernel_trap(semaphore_signal_all_trap, -34, 1) diff --git a/osfmk/mach/task.defs b/osfmk/mach/task.defs index efc244f15..45e9519e2 100644 --- a/osfmk/mach/task.defs +++ b/osfmk/mach/task.defs @@ -370,11 +370,3 @@ routine task_set_policy( limit : policy_limit_t; change : boolean_t); -/* - * Registers the caller-specified RPC subsystem attributes - * as a new object. - */ -routine mach_subsystem_create( - task : task_t; - user_subsys : user_subsystem_t; - out subsys : subsystem_t); diff --git a/osfmk/mach/task_info.h b/osfmk/mach/task_info.h index c42cbd84f..d9750ddd8 100644 --- a/osfmk/mach/task_info.h +++ b/osfmk/mach/task_info.h @@ -22,102 +22,6 @@ /* * @OSF_COPYRIGHT@ */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:30 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.2 1998/04/29 17:36:54 mburg - * MK7.3 merger - * - * Revision 1.2.31.1 1998/02/03 09:33:56 gdt - * Merge up to MK7.3 - * [1998/02/03 09:17:49 gdt] - * - * Revision 1.2.29.1 1997/06/17 03:01:26 devrcs - * Added `TASK_SCHED_INFO.' - * [1996/03/18 15:24:59 rkc] - * - * Revision 1.2.21.3 1995/01/06 19:51:51 devrcs - * mk6 CR668 - 1.3b26 merge - * 64bit cleanup, ledgers, security, flavors. - * [1994/10/14 03:43:10 dwm] - * - * Revision 1.2.21.2 1994/09/23 02:42:46 ezf - * change marker to not FREE - * [1994/09/22 21:42:56 ezf] - * - * Revision 1.2.21.1 1994/08/07 20:50:07 bolinger - * Merge up to colo_b7. - * [1994/08/01 21:02:06 bolinger] - * - * Revision 1.2.17.4 1994/06/25 03:47:20 dwm - * mk6 CR98 - add flavor interface typedefs (task_flavor_t). - * [1994/06/24 21:54:58 dwm] - * - * Revision 1.2.17.3 1994/05/02 21:36:04 dwm - * Remove nmk15_compat support. - * [1994/05/02 21:09:10 dwm] - * - * Revision 1.2.17.2 1994/01/14 18:42:23 bolinger - * Add TASK_USER_DATA flavor of task_info() (and task_set_info()). - * [1994/01/14 18:20:52 bolinger] - * - * Revision 1.2.17.1 1994/01/12 17:57:26 dwm - * Fix "ifdef" NMK15_COMPAT to "if" - * [1994/01/12 17:31:13 dwm] - * - * Revision 1.2.3.5 1993/08/03 18:29:52 gm - * CR9596: Change KERNEL to MACH_KERNEL. - * [1993/08/02 18:33:57 gm] - * - * Revision 1.2.3.4 1993/07/08 19:04:52 watkins - * New version of task_basic_info structure; old version - * is now under nmk15_compat. - * [1993/07/07 21:04:11 watkins] - * - * Revision 1.2.3.3 1993/06/29 21:55:50 watkins - * New definitions for scheduling control interfaces. - * [1993/06/29 20:50:59 watkins] - * - * Revision 1.2.3.2 1993/06/09 02:43:32 gm - * Added to OSF/1 R1.3 from NMK15.0. - * [1993/06/02 21:18:18 jeffc] - * - * Revision 1.2 1993/04/19 16:39:27 devrcs - * ansi C conformance changes - * [1993/02/02 18:54:59 david] - * - * Revision 1.1 1992/09/30 02:32:09 robert - * Initial revision - * - * $EndLog$ - */ -/* CMU_HIST */ -/* - * Revision 2.4 91/05/14 17:00:41 mrt - * Correcting copyright - * - * Revision 2.3 91/02/05 17:36:25 mrt - * Changed to new Mach copyright - * [91/02/01 17:21:17 mrt] - * - * Revision 2.2 90/05/03 15:48:36 dbg - * Added TASK_THREAD_TIMES_INFO flavor. - * [90/04/03 dbg] - * - * Revision 2.1 89/08/03 16:04:49 rwd - * Created. - * - * Revision 2.3 89/02/25 18:41:06 gm0w - * Changes for cleanup. - * - * 15-Jan-88 David Golub (dbg) at Carnegie-Mellon University - * Created, based on old task_statistics. - * - */ -/* CMU_ENDHIST */ /* * Mach Operating System * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University @@ -161,6 +65,8 @@ #include #include +#include + /* * Generic information structure to allow for expansion. */ @@ -225,14 +131,18 @@ typedef struct task_thread_times_info *task_thread_times_info_t; #define TASK_THREAD_TIMES_INFO_COUNT \ (sizeof(task_thread_times_info_data_t) / sizeof(natural_t)) +#ifdef __APPLE_API_UNSTABLE + #define TASK_SCHED_TIMESHARE_INFO 10 #define TASK_SCHED_RR_INFO 11 #define TASK_SCHED_FIFO_INFO 12 +#define TASK_SCHED_INFO 14 + +#endif /* __APPLE_API_UNSTABLE */ + #define TASK_SECURITY_TOKEN 13 #define TASK_SECURITY_TOKEN_COUNT \ (sizeof(security_token_t) / sizeof(natural_t)) -#define TASK_SCHED_INFO 14 - #endif /* TASK_INFO_H_ */ diff --git a/osfmk/mach/task_ledger.h b/osfmk/mach/task_ledger.h index 874776fab..cf68eded1 100644 --- a/osfmk/mach/task_ledger.h +++ b/osfmk/mach/task_ledger.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,44 +22,12 @@ /* * @OSF_COPYRIGHT@ */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:30 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.1.1.1 1998/03/07 02:25:46 wsanchez - * Import of OSF Mach kernel (~mburg) - * - * Revision 1.1.8.2 1995/01/06 19:51:54 devrcs - * mk6 CR668 - 1.3b26 merge - * [1994/10/14 03:43:13 dwm] - * - * Revision 1.1.8.1 1994/09/23 02:42:55 ezf - * change marker to not FREE - * [1994/09/22 21:43:00 ezf] - * - * Revision 1.1.4.3 1993/09/17 21:35:29 robert - * change marker to OSF_FREE_COPYRIGHT - * [1993/09/17 21:28:49 robert] - * - * Revision 1.1.4.2 1993/06/04 15:13:57 jeffc - * CR9193 - MK5.0 merge. - * [1993/05/18 02:38:04 gm] - * - * Revision 3.0.2.2 1993/05/15 15:42:19 jph - * Merge MK5.0: change LEDGER_REAL_ITEMS to be LEDGER_N_ITEMS. - * [1993/05/15 15:21:21 jph] - * - * Revision 3.0 1992/12/31 22:13:53 ede - * Initial revision for OSF/1 R1.3 - * - * Revision 1.2 1991/08/15 19:16:53 devrcs - * Ledgers: indices for task_ledger exported routines. - * [91/07/18 11:04:31 dwm] - * - * $EndLog$ - */ +#include + +#ifndef _MACH_TASK_LEDGER_H_ +#define _MACH_TASK_LEDGER_H_ + +#ifdef __APPLE_API_EVOLVING /* * Definitions for task ledger line items @@ -72,3 +40,7 @@ #define LEDGER_N_ITEMS 3 /* Total line items */ #define LEDGER_UNLIMITED 0 /* ignored item.maximum */ + +#endif /* __APPLE_API_EVOLVING */ + +#endif /* _MACH_TASK_LEDGER_H_ */ diff --git a/osfmk/mach/task_special_ports.h b/osfmk/mach/task_special_ports.h index f658d5b43..b3384f50e 100644 --- a/osfmk/mach/task_special_ports.h +++ b/osfmk/mach/task_special_ports.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,80 +22,6 @@ /* * @OSF_COPYRIGHT@ */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:30 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.1.1.1 1998/03/07 02:25:46 wsanchez - * Import of OSF Mach kernel (~mburg) - * - * Revision 1.2.7.2 1995/01/06 19:51:58 devrcs - * mk6 CR668 - 1.3b26 merge - * [1994/10/14 03:43:15 dwm] - * - * Revision 1.2.7.1 1994/09/23 02:43:04 ezf - * change marker to not FREE - * [1994/09/22 21:43:04 ezf] - * - * Revision 1.2.2.5 1993/09/03 15:53:54 jeffc - * CR9255 - Remove MACH_EXC_COMPAT - * [1993/08/26 15:10:56 jeffc] - * - * Revision 1.2.2.4 1993/08/05 19:09:45 jeffc - * CR9508 - Delete dead code. Remove MACH_IPC_COMPAT - * [1993/08/03 17:09:30 jeffc] - * - * Revision 1.2.2.3 1993/08/03 19:05:13 gm - * CR9596: Change KERNEL to MACH_KERNEL. - * CR9600: Add task_special_port_t typedef. - * [1993/08/02 18:34:37 gm] - * - * Revision 1.2.2.2 1993/06/09 02:43:37 gm - * Added to OSF/1 R1.3 from NMK15.0. - * [1993/06/02 21:18:21 jeffc] - * - * Revision 1.2 1993/04/19 16:39:36 devrcs - * ansi C conformance changes - * [1993/02/02 18:55:14 david] - * - * Revision 1.1 1992/09/30 02:32:11 robert - * Initial revision - * - * $EndLog$ - */ -/* CMU_HIST */ -/* - * Revision 2.4.2.1 92/03/03 16:22:36 jeffreyh - * Changes from TRUNK - * [92/02/26 12:20:27 jeffreyh] - * - * Revision 2.5 92/01/15 13:44:54 rpd - * Changed MACH_IPC_COMPAT conditionals to default to not present. - * - * Revision 2.4 91/05/14 17:00:57 mrt - * Correcting copyright - * - * Revision 2.3 91/02/05 17:36:29 mrt - * Changed to new Mach copyright - * [91/02/01 17:21:29 mrt] - * - * Revision 2.2 90/06/02 15:00:03 rpd - * Converted to new IPC. - * [90/03/26 22:40:08 rpd] - * - * Revision 2.1 89/08/03 16:06:01 rwd - * Created. - * - * Revision 2.3 89/02/25 18:41:12 gm0w - * Changes for cleanup. - * - * 17-Jan-88 David Golub (dbg) at Carnegie-Mellon University - * Created. - * - */ -/* CMU_ENDHIST */ /* * Mach Operating System * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University @@ -135,6 +61,8 @@ #ifndef _MACH_TASK_SPECIAL_PORTS_H_ #define _MACH_TASK_SPECIAL_PORTS_H_ +#include + typedef int task_special_port_t; #define TASK_KERNEL_PORT 1 /* Represents task to the outside @@ -144,10 +72,26 @@ typedef int task_special_port_t; #define TASK_BOOTSTRAP_PORT 4 /* Bootstrap environment for task. */ +#ifdef __APPLE_API_EVOLVING + #define TASK_WIRED_LEDGER_PORT 5 /* Wired resource ledger for task. */ #define TASK_PAGED_LEDGER_PORT 6 /* Paged resource ledger for task. */ +#define task_get_wired_ledger_port(task, port) \ + (task_get_special_port((task), TASK_WIRED_LEDGER_PORT, (port))) + +#define task_set_wired_ledger_port(task, port) \ + (task_set_special_port((task), TASK_WIRED_LEDGER_PORT, (port))) + +#define task_get_paged_ledger_port(task, port) \ + (task_get_special_port((task), TASK_PAGED_LEDGER_PORT, (port))) + +#define task_set_paged_ledger_port(task, port) \ + (task_set_special_port((task), TASK_PAGED_LEDGER_PORT, (port))) + +#endif /* __APPLE_API_EVOLVING */ + /* * Definitions for ease of use */ @@ -170,16 +114,4 @@ typedef int task_special_port_t; #define task_set_bootstrap_port(task, port) \ (task_set_special_port((task), TASK_BOOTSTRAP_PORT, (port))) -#define task_get_wired_ledger_port(task, port) \ - (task_get_special_port((task), TASK_WIRED_LEDGER_PORT, (port))) - -#define task_set_wired_ledger_port(task, port) \ - (task_set_special_port((task), TASK_WIRED_LEDGER_PORT, (port))) - -#define task_get_paged_ledger_port(task, port) \ - (task_get_special_port((task), TASK_PAGED_LEDGER_PORT, (port))) - -#define task_set_paged_ledger_port(task, port) \ - (task_set_special_port((task), TASK_PAGED_LEDGER_PORT, (port))) - #endif /* _MACH_TASK_SPECIAL_PORTS_H_ */ diff --git a/osfmk/mach/thread_info.h b/osfmk/mach/thread_info.h index e55723193..7b99b9f59 100644 --- a/osfmk/mach/thread_info.h +++ b/osfmk/mach/thread_info.h @@ -22,97 +22,6 @@ /* * @OSF_COPYRIGHT@ */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:30 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.1.1.1 1998/03/07 02:25:46 wsanchez - * Import of OSF Mach kernel (~mburg) - * - * Revision 1.2.17.3 1995/01/06 19:52:05 devrcs - * mk6 CR668 - 1.3b26 merge - * 64bit cleanup, flavor typedefs - * [1994/10/14 03:43:17 dwm] - * - * Revision 1.2.17.2 1994/09/23 02:43:16 ezf - * change marker to not FREE - * [1994/09/22 21:43:12 ezf] - * - * Revision 1.2.17.1 1994/08/07 20:50:11 bolinger - * Merge up to colo_b7. - * [1994/08/01 21:02:09 bolinger] - * - * Revision 1.2.13.3 1994/06/25 03:47:23 dwm - * mk6 CR98 - add flavor interface typedefs. - * [1994/06/24 21:55:01 dwm] - * - * Revision 1.2.13.2 1994/05/02 21:36:08 dwm - * Remove nmk15_compat support. - * [1994/05/02 21:09:13 dwm] - * - * Revision 1.2.13.1 1994/01/12 17:57:31 dwm - * Fix "ifdef" NMK15_COMPAT to "if" - * [1994/01/12 17:31:16 dwm] - * - * Revision 1.2.3.5 1993/08/03 18:29:54 gm - * CR9596: Change KERNEL to MACH_KERNEL. - * [1993/08/02 18:56:17 gm] - * - * Revision 1.2.3.4 1993/07/08 19:04:54 watkins - * New version of thread_basic_info structure; old version - * is now under nmk15_compat. - * [1993/07/07 21:04:15 watkins] - * - * Revision 1.2.3.3 1993/06/29 21:55:52 watkins - * New definitions for scheduling control interfaces. - * [1993/06/29 20:51:04 watkins] - * - * Revision 1.2.3.2 1993/06/09 02:43:43 gm - * Added to OSF/1 R1.3 from NMK15.0. - * [1993/06/02 21:18:25 jeffc] - * - * Revision 1.2 1993/04/19 16:39:43 devrcs - * ansi C conformance changes - * [1993/02/02 18:55:07 david] - * - * Revision 1.1 1992/09/30 02:32:13 robert - * Initial revision - * - * $EndLog$ - */ -/* CMU_HIST */ -/* - * Revision 2.4 91/05/14 17:01:06 mrt - * Correcting copyright - * - * Revision 2.3 91/02/05 17:36:34 mrt - * Changed to new Mach copyright - * [91/02/01 17:21:39 mrt] - * - * Revision 2.2 90/06/02 15:00:08 rpd - * Updated for new scheduling info. - * [90/03/26 22:40:55 rpd] - * - * Revision 2.1 89/08/03 16:06:07 rwd - * Created. - * - * Revision 2.4 89/02/25 18:41:18 gm0w - * Changes for cleanup. - * - * 4-Mar-88 David Black (dlb) at Carnegie-Mellon University - * Added TH_USAGE_SCALE for cpu_usage field. - * - * 15-Jan-88 David Golub (dbg) at Carnegie-Mellon University - * Changed to generic interface (variable-length array) to allow - * for expansion. Renamed to thread_info. - * - * 1-Jun-87 Avadis Tevanian (avie) at Carnegie-Mellon University - * Created. - * - */ -/* CMU_ENDHIST */ /* * Mach Operating System * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University @@ -154,6 +63,8 @@ #ifndef _MACH_THREAD_INFO_H_ #define _MACH_THREAD_INFO_H_ +#include + #include #include #include @@ -214,8 +125,12 @@ typedef struct thread_basic_info *thread_basic_info_t; #define TH_FLAGS_SWAPPED 0x1 /* thread is swapped out */ #define TH_FLAGS_IDLE 0x2 /* thread is an idle thread */ +#ifdef __APPLE_API_UNSTABLE + #define THREAD_SCHED_TIMESHARE_INFO 10 #define THREAD_SCHED_RR_INFO 11 #define THREAD_SCHED_FIFO_INFO 12 +#endif /* __APPLE_API_UNSTABLE */ + #endif /* _MACH_THREAD_INFO_H_ */ diff --git a/osfmk/mach/thread_special_ports.h b/osfmk/mach/thread_special_ports.h index da895b69a..a7e7a3193 100644 --- a/osfmk/mach/thread_special_ports.h +++ b/osfmk/mach/thread_special_ports.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,75 +22,6 @@ /* * @OSF_COPYRIGHT@ */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:30 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.1.1.1 1998/03/07 02:25:46 wsanchez - * Import of OSF Mach kernel (~mburg) - * - * Revision 1.2.6.1 1994/09/23 02:43:25 ezf - * change marker to not FREE - * [1994/09/22 21:43:16 ezf] - * - * Revision 1.2.2.5 1993/09/03 15:53:56 jeffc - * CR9255 - Remove MACH_EXC_COMPAT - * [1993/08/26 15:57:00 jeffc] - * - * Revision 1.2.2.4 1993/08/05 19:09:47 jeffc - * CR9508 - Delete dead code. Remove MACH_IPC_COMPAT - * [1993/08/03 17:09:33 jeffc] - * - * Revision 1.2.2.3 1993/08/03 18:29:57 gm - * CR9596: Change KERNEL to MACH_KERNEL. - * [1993/08/02 18:56:38 gm] - * - * Revision 1.2.2.2 1993/06/09 02:43:48 gm - * Added to OSF/1 R1.3 from NMK15.0. - * [1993/06/02 21:18:28 jeffc] - * - * Revision 1.2 1993/04/19 16:39:50 devrcs - * make endif tags ansi compliant/include files - * [1993/02/20 21:45:05 david] - * - * Revision 1.1 1992/09/30 02:32:15 robert - * Initial revision - * - * $EndLog$ - */ -/* CMU_HIST */ -/* - * Revision 2.4.2.1 92/03/03 16:22:38 jeffreyh - * Changes from TRUNK - * [92/02/26 12:20:46 jeffreyh] - * - * Revision 2.5 92/01/15 13:44:57 rpd - * Changed MACH_IPC_COMPAT conditionals to default to not present. - * - * Revision 2.4 91/05/14 17:01:15 mrt - * Correcting copyright - * - * Revision 2.3 91/02/05 17:36:38 mrt - * Changed to new Mach copyright - * [91/02/01 17:21:48 mrt] - * - * Revision 2.2 90/06/02 15:00:15 rpd - * Converted to new IPC. - * [90/03/26 22:41:20 rpd] - * - * Revision 2.1 89/08/03 16:06:13 rwd - * Created. - * - * Revision 2.3 89/02/25 18:41:23 gm0w - * Changes for cleanup. - * - * 17-Jan-88 David Golub (dbg) at Carnegie-Mellon University - * Created. - * - */ -/* CMU_ENDHIST */ /* * Mach Operating System * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University diff --git a/osfmk/mach/thread_status.h b/osfmk/mach/thread_status.h index 1e2940d48..49903043b 100644 --- a/osfmk/mach/thread_status.h +++ b/osfmk/mach/thread_status.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,90 +22,6 @@ /* * @OSF_COPYRIGHT@ */ -/* - * HISTORY - * Revision 1.2.14.4 1995/01/06 19:52:10 devrcs - * mk6 CR668 - 1.3b26 merge - * [1994/10/14 03:43:20 dwm] - * - * Revision 1.2.14.3 1994/09/23 02:43:32 ezf - * change marker to not FREE - * [1994/09/22 21:43:20 ezf] - * - * Revision 1.2.14.2 1994/08/07 20:50:16 bolinger - * Merge up to colo_b7. - * [1994/08/01 21:02:13 bolinger] - * - * Revision 1.2.14.1 1994/06/26 22:59:09 bolinger - * Temporary patch to enable thread state large enough to suit 860. - * [1994/06/26 22:55:25 bolinger] - * - * Revision 1.2.11.2 1994/06/25 03:47:26 dwm - * mk6 CR98 - use new MD THREAD_STATE_MAX - * [1994/06/24 21:55:03 dwm] - * - * Revision 1.2.11.1 1993/12/10 19:37:05 dwm - * Re-hack of workaround: KERNEL_STACK_SIZE back to 1 page; - * lower THREAD_STATE_MAX to 64 ints instead. - * [1993/12/10 19:36:37 dwm] - * - * Revision 1.2.3.3 1993/08/03 18:54:25 gm - * CR9600: Change thread_state_flavor_t typedef from unsigned int to int. - * [1993/08/02 18:57:55 gm] - * - * Revision 1.2.3.2 1993/06/09 02:43:53 gm - * Added to OSF/1 R1.3 from NMK15.0. - * [1993/06/02 21:18:31 jeffc] - * - * Revision 1.2 1993/04/19 16:39:58 devrcs - * ansi C conformance changes - * [1993/02/02 18:54:42 david] - * - * Add new thread_state types. [sp@gr.osf.org] - * [1992/12/23 13:12:08 david] - * - * Revision 1.1 1992/09/30 02:32:17 robert - * Initial revision - * - * $EndLog$ - */ -/* CMU_HIST */ -/* - * Revision 2.3 91/05/14 17:01:22 mrt - * Correcting copyright - * - * Revision 2.2 91/02/05 17:36:42 mrt - * Changed to new Mach copyright - * [91/02/01 17:21:56 mrt] - * - * Revision 2.1 89/08/03 16:06:18 rwd - * Created. - * - * Revision 2.4 89/02/25 18:41:29 gm0w - * Changes for cleanup. - * - * Revision 2.3 89/02/07 00:53:47 mwyoung - * Relocated from mach/thread_status.h - * - * Revision 2.2 88/08/25 18:21:12 mwyoung - * Adjusted include file references. - * [88/08/16 04:16:13 mwyoung] - * - * Add THREAD_STATE_FLAVOR_LIST; remove old stuff. - * [88/08/11 18:49:48 mwyoung] - * - * - * 15-Jan-88 David Golub (dbg) at Carnegie-Mellon University - * Replaced with variable-length array for flexibile interface. - * - * 28-Apr-87 Avadis Tevanian (avie) at Carnegie-Mellon University - * Latest hacks to keep MiG happy wrt refarrays. - * - * 27-Mar-87 Avadis Tevanian (avie) at Carnegie-Mellon University - * Created. - * - */ -/* CMU_ENDHIST */ /* * Mach Operating System * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University diff --git a/osfmk/mach/time_value.h b/osfmk/mach/time_value.h index c4a1aea7a..afaff9eee 100644 --- a/osfmk/mach/time_value.h +++ b/osfmk/mach/time_value.h @@ -22,68 +22,6 @@ /* * @OSF_COPYRIGHT@ */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:31 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.1.1.1 1998/03/07 02:25:46 wsanchez - * Import of OSF Mach kernel (~mburg) - * - * Revision 1.2.11.2 1995/01/06 19:52:17 devrcs - * mk6 CR668 - 1.3b26 merge - * 64bit cleanup - * [1994/10/14 03:43:25 dwm] - * - * Revision 1.2.11.1 1994/09/23 02:43:49 ezf - * change marker to not FREE - * [1994/09/22 21:43:27 ezf] - * - * Revision 1.2.3.2 1993/06/09 02:44:03 gm - * Added to OSF/1 R1.3 from NMK15.0. - * [1993/06/02 21:18:38 jeffc] - * - * Revision 1.2 1993/04/19 16:40:14 devrcs - * ansi C conformance changes - * [1993/02/02 18:55:30 david] - * - * Revision 1.1 1992/09/30 02:32:21 robert - * Initial revision - * - * $EndLog$ - */ -/* CMU_HIST */ -/* - * Revision 2.4 91/05/18 14:35:13 rpd - * Added mapped_time_value_t. - * [91/03/21 rpd] - * - * Revision 2.3 91/05/14 17:01:40 mrt - * Correcting copyright - * - * Revision 2.2 91/02/05 17:36:49 mrt - * Changed to new Mach copyright - * [91/02/01 17:22:07 mrt] - * - * Revision 2.1 89/08/03 16:06:24 rwd - * Created. - * - * Revision 2.4 89/02/25 18:41:34 gm0w - * Changes for cleanup. - * - * Revision 2.3 89/02/07 00:53:58 mwyoung - * Relocated from sys/time_value.h - * - * Revision 2.2 89/01/31 01:21:58 rpd - * TIME_MICROS_MAX should be 1 Million, not 10 Million. - * [88/10/12 dlb] - * - * 4-Jan-88 David Golub (dbg) at Carnegie-Mellon University - * Created. - * - */ -/* CMU_ENDHIST */ /* * Mach Operating System * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University @@ -109,12 +47,12 @@ * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ -/* - */ #ifndef TIME_VALUE_H_ #define TIME_VALUE_H_ +#include + #include /* @@ -127,6 +65,8 @@ struct time_value { }; typedef struct time_value time_value_t; +#ifdef __APPLE_API_UNSTABLE + /* * Macros to manipulate time values. Assume that time values * are normalized (microseconds <= 999999). @@ -150,6 +90,10 @@ typedef struct time_value time_value_t; } \ } +#endif /* __APPLE_API_UNSTABLE */ + +#ifdef __APPLE_API_OBSOLETE + /* * Time value available through the mapped-time interface. * Read this mapped value with @@ -165,4 +109,6 @@ typedef struct mapped_time_value { integer_t check_seconds; } mapped_time_value_t; +#endif /* __APPLE_API_OBSOLETE */ + #endif /* TIME_VALUE_H_ */ diff --git a/osfmk/mach/vm_attributes.h b/osfmk/mach/vm_attributes.h index 6782a5324..595c8b926 100644 --- a/osfmk/mach/vm_attributes.h +++ b/osfmk/mach/vm_attributes.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,59 +22,6 @@ /* * @OSF_COPYRIGHT@ */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:31 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.1.1.1 1998/03/07 02:25:46 wsanchez - * Import of OSF Mach kernel (~mburg) - * - * Revision 1.2.9.2 1998/02/02 09:22:22 gdt - * Add new function "MATTR_VAL_GET_INFO" to get shared/resident information - * about a page. This lets Linux display better statistics (e.g. 'top'). - * [1998/02/02 09:21:30 gdt] - * - * Revision 1.2.9.1 1997/09/12 17:16:06 stephen - * Add new MATTR_VAL_CACHE_SYNC which - * syncs I+D caches without necessarily - * flushing them. - * [1997/09/12 16:32:45 stephen] - * - * Revision 1.2.6.1 1994/09/23 02:43:58 ezf - * change marker to not FREE - * [1994/09/22 21:43:31 ezf] - * - * Revision 1.2.2.2 1993/06/09 02:44:08 gm - * Added to OSF/1 R1.3 from NMK15.0. - * [1993/06/02 21:18:41 jeffc] - * - * Revision 1.2 1993/04/19 16:40:21 devrcs - * ansi C conformance changes - * [1993/02/02 18:55:22 david] - * - * Revision 1.1 1992/09/30 02:32:22 robert - * Initial revision - * - * $EndLog$ - */ -/* CMU_HIST */ -/* - * Revision 2.4 91/05/14 17:02:37 mrt - * Correcting copyright - * - * Revision 2.3 91/02/05 17:37:24 mrt - * Changed to new Mach copyright - * [91/02/01 17:22:17 mrt] - * - * Revision 2.2 90/01/22 23:05:53 af - * Created. - * [89/12/08 af] - * - * - */ -/* CMU_ENDHIST */ /* * Mach Operating System * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University diff --git a/osfmk/mach/vm_behavior.h b/osfmk/mach/vm_behavior.h index 1fe81758c..6b2eee6d6 100644 --- a/osfmk/mach/vm_behavior.h +++ b/osfmk/mach/vm_behavior.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,40 +22,6 @@ /* * @OSF_COPYRIGHT@ */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:31 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.1.1.1 1998/03/07 02:25:46 wsanchez - * Import of OSF Mach kernel (~mburg) - * - * Revision 1.1.10.2 1994/09/23 02:44:05 ezf - * change marker to not FREE - * [1994/09/22 21:43:34 ezf] - * - * Revision 1.1.10.1 1994/08/07 20:50:20 bolinger - * Import colo_shared revision into NMK18. - * [1994/08/02 16:41:42 bolinger] - * - * Revision 1.1.8.1 1994/07/08 20:09:11 dwm - * mk6 CR227 - bring vm_behavior constants up to spec. - * [1994/07/08 20:02:37 dwm] - * - * Revision 1.1.4.3 1993/09/17 21:35:31 robert - * change marker to OSF_FREE_COPYRIGHT - * [1993/09/17 21:28:53 robert] - * - * Revision 1.1.4.2 1993/06/04 15:14:02 jeffc - * CR9193 - MK5.0 merge. - * [1993/06/04 13:54:38 jeffc] - * - * Revision 3.0 92/12/31 22:14:09 ede - * Initial revision for OSF/1 R1.3 - * - * $EndLog$ - */ /* * File: mach/vm_behavior.h * @@ -86,5 +52,7 @@ typedef int vm_behavior_t; #define VM_BEHAVIOR_RANDOM ((vm_behavior_t) 1) /* random */ #define VM_BEHAVIOR_SEQUENTIAL ((vm_behavior_t) 2) /* forward sequential */ #define VM_BEHAVIOR_RSEQNTL ((vm_behavior_t) 3) /* reverse sequential */ +#define VM_BEHAVIOR_WILLNEED ((vm_behavior_t) 4) /* will need in near future */ +#define VM_BEHAVIOR_DONTNEED ((vm_behavior_t) 5) /* dont need in near future */ #endif /*_MACH_VM_BEHAVIOR_H_*/ diff --git a/osfmk/mach/vm_inherit.h b/osfmk/mach/vm_inherit.h index 944c852b5..d6efd9b57 100644 --- a/osfmk/mach/vm_inherit.h +++ b/osfmk/mach/vm_inherit.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,56 +22,6 @@ /* * @OSF_COPYRIGHT@ */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:31 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.1.1.1 1998/03/07 02:25:46 wsanchez - * Import of OSF Mach kernel (~mburg) - * - * Revision 1.2.9.1 1994/09/23 02:44:12 ezf - * change marker to not FREE - * [1994/09/22 21:43:38 ezf] - * - * Revision 1.2.6.1 1994/02/17 16:25:09 rwd - * Add VM_INHERIT_LAST_VALID - * [94/02/16 rwd] - * - * Revision 1.2.2.2 1993/06/09 02:44:13 gm - * Added to OSF/1 R1.3 from NMK15.0. - * [1993/06/02 21:18:44 jeffc] - * - * Revision 1.2 1993/04/19 16:40:30 devrcs - * ansi C conformance changes - * [1993/02/02 18:55:45 david] - * - * Revision 1.1 1992/09/30 02:32:24 robert - * Initial revision - * - * $EndLog$ - */ -/* CMU_HIST */ -/* - * Revision 2.3 91/05/14 17:02:47 mrt - * Correcting copyright - * - * Revision 2.2 91/02/05 17:37:31 mrt - * Changed to new Mach copyright - * [91/02/01 17:22:24 mrt] - * - * Revision 2.1 89/08/03 16:06:30 rwd - * Created. - * - * Revision 2.3 89/02/25 18:42:18 gm0w - * Changes for cleanup. - * - * 16-Sep-85 Avadis Tevanian (avie) at Carnegie-Mellon University - * Created. - * - */ -/* CMU_ENDHIST */ /* * Mach Operating System * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University diff --git a/osfmk/mach/vm_prot.h b/osfmk/mach/vm_prot.h index 9c6678214..9980336e4 100644 --- a/osfmk/mach/vm_prot.h +++ b/osfmk/mach/vm_prot.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,70 +22,6 @@ /* * @OSF_COPYRIGHT@ */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:31 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.1.1.1 1998/03/07 02:25:46 wsanchez - * Import of OSF Mach kernel (~mburg) - * - * Revision 1.3.8.1 1994/09/23 02:44:31 ezf - * change marker to not FREE - * [1994/09/22 21:43:46 ezf] - * - * Revision 1.3.2.2 1993/06/09 02:44:23 gm - * Added to OSF/1 R1.3 from NMK15.0. - * [1993/06/02 21:18:51 jeffc] - * - * Revision 1.3 1993/04/19 16:40:48 devrcs - * make endif tags ansi compliant/include files - * [1993/02/20 21:45:25 david] - * - * Revision 1.2 1992/12/07 21:29:28 robert - * integrate any changes below for 14.0 (branch from 13.16 base) - * - * Joseph Barrera (jsb) at Carnegie-Mellon University 05-Aug-92 - * Added VM_PROT_WANTS_COPY to solve copy-call race condition. - * [1992/12/06 20:25:47 robert] - * - * Revision 1.1 1992/09/30 02:32:28 robert - * Initial revision - * - * $EndLog$ - */ -/* CMU_HIST */ -/* - * Revision 2.4.3.1 92/03/03 16:22:41 jeffreyh - * [David L. Black 92/02/22 17:03:43 dlb@osf.org] - * Add no change protection value for memory_object_lock_request. - * - * Revision 2.4 91/05/14 17:03:00 mrt - * Correcting copyright - * - * Revision 2.3 91/02/05 17:37:38 mrt - * Changed to new Mach copyright - * [91/02/01 17:22:39 mrt] - * - * Revision 2.2 90/01/22 23:05:57 af - * Removed execute permission from default protection. - * On the only machine that cares for execute permission (mips) - * this is an expensive liability: it requires keeping - * Icache consistent memory that never contains code. - * [89/12/15 af] - * - * Revision 2.1 89/08/03 16:06:47 rwd - * Created. - * - * Revision 2.3 89/02/25 18:42:29 gm0w - * Changes for cleanup. - * - * 6-Jun-85 Avadis Tevanian (avie) at Carnegie-Mellon University - * Created. - * - */ -/* CMU_ENDHIST */ /* * Mach Operating System * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University diff --git a/osfmk/mach/vm_region.h b/osfmk/mach/vm_region.h index 6d48c380a..1fd3e2492 100644 --- a/osfmk/mach/vm_region.h +++ b/osfmk/mach/vm_region.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002,2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,28 +22,6 @@ /* * @OSF_COPYRIGHT@ */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:31 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.1.1.1 1998/03/07 02:25:46 wsanchez - * Import of OSF Mach kernel (~mburg) - * - * Revision 1.1.5.1 1995/01/16 17:22:27 bolinger - * Import files unchanged from osc1.3b11 into cnmk_shared. - * [1995/01/16 17:20:37 bolinger] - * - * Revision 1.1.3.2 1993/10/05 22:23:22 watkins - * Merge forward. - * [1993/10/05 22:05:05 watkins] - * - * Revision 1.1.1.2 1993/09/28 19:42:50 watkins - * Created to comply with spec. - * - * $EndLog$ - */ /* * File: mach/vm_region.h * diff --git a/osfmk/mach/vm_statistics.h b/osfmk/mach/vm_statistics.h index b86d0c51f..f2667b9c5 100644 --- a/osfmk/mach/vm_statistics.h +++ b/osfmk/mach/vm_statistics.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,85 +22,6 @@ /* * @OSF_COPYRIGHT@ */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:31 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.1.1.1 1998/03/07 02:25:46 wsanchez - * Import of OSF Mach kernel (~mburg) - * - * Revision 1.2.12.2 1995/01/06 19:52:25 devrcs - * mk6 CR668 - 1.3b26 merge - * added vm stats - * [1994/10/14 03:43:30 dwm] - * - * Revision 1.2.12.1 1994/09/23 02:44:40 ezf - * change marker to not FREE - * [1994/09/22 21:43:49 ezf] - * - * Revision 1.2.4.4 1993/08/03 18:30:01 gm - * CR9596: Change KERNEL to MACH_KERNEL. - * [1993/08/02 18:58:32 gm] - * - * Revision 1.2.4.3 1993/06/15 20:28:27 brezak - * Make xxx_vm_statistic for now. - * [1993/06/14 14:11:07 brezak] - * - * Revision 1.2.2.2 1993/06/08 19:03:02 brezak - * Remove page_size from vm_statistics. - * - * Revision 1.1.4.2 1993/06/02 23:49:41 jeffc - * Added to OSF/1 R1.3 from NMK15.0. - * [1993/06/02 21:18:54 jeffc] - * - * Revision 1.2 1993/04/19 16:40:55 devrcs - * ansi C conformance changes - * [1993/02/02 18:55:38 david] - * - * Revision 1.1 1992/09/30 02:32:30 robert - * Initial revision - * - * $EndLog$ - */ -/* CMU_HIST */ -/* - * Revision 2.3 91/05/14 17:03:07 mrt - * Correcting copyright - * - * Revision 2.2 91/02/05 17:37:41 mrt - * Changed to new Mach copyright - * [91/02/01 17:22:49 mrt] - * - * Revision 2.1 89/08/03 16:06:55 rwd - * Created. - * - * Revision 2.4 89/02/25 18:42:35 gm0w - * Changes for cleanup. - * - * Revision 2.3 89/02/07 00:54:39 mwyoung - * Relocated from sys/vm_statistics.h - * - * Revision 2.2 89/01/30 22:08:54 rpd - * Made variable declarations use "extern". - * [89/01/25 15:26:30 rpd] - * - * 30-Sep-86 Avadis Tevanian (avie) at Carnegie-Mellon University - * Changed "reclaim" to "inactive." - * - * 22-Aug-86 Michael Young (mwyoung) at Carnegie-Mellon University - * Made vm_stat structure kernel-only. - * - * 22-May-86 Avadis Tevanian (avie) at Carnegie-Mellon University - * Defined vm_statistics_data_t as a real typedef so that - * MatchMaker can deal with it. - * - * 14-Feb-86 Avadis Tevanian (avie) at Carnegie-Mellon University - * Created. - * - */ -/* CMU_ENDHIST */ /* * Mach Operating System * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University @@ -213,6 +134,7 @@ typedef struct pmap_statistics *pmap_statistics_t; #define VM_MEMORY_FOUNDATION 41 #define VM_MEMORY_COREGRAPHICS 42 #define VM_MEMORY_CARBON 43 +#define VM_MEMORY_JAVA 44 #define VM_MEMORY_ATS 50 diff --git a/osfmk/mach/vm_sync.h b/osfmk/mach/vm_sync.h index e1bbc3fa3..af5562372 100644 --- a/osfmk/mach/vm_sync.h +++ b/osfmk/mach/vm_sync.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -47,36 +47,6 @@ * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:31 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.1.1.1 1998/03/07 02:25:46 wsanchez - * Import of OSF Mach kernel (~mburg) - * - * Revision 1.2.7.1 1994/09/23 02:44:50 ezf - * change marker to not FREE - * [1994/09/22 21:43:54 ezf] - * - * Revision 1.2.3.3 1993/06/22 15:18:34 sp - * Add definition of VM_SYNC_SYNCHRONOUS [david@gr.osf.org] - * [1993/06/21 13:00:18 sp] - * - * Revision 1.2.3.2 1993/06/09 02:44:33 gm - * Added to OSF/1 R1.3 from NMK15.0. - * [1993/06/02 21:18:58 jeffc] - * - * Revision 1.2 1993/04/19 16:41:03 devrcs - * Made compatible with other mach .h files. - * [1993/03/15 17:34:44 david] - * - * New for vm_sync definitions. - * [1993/03/03 12:39:16 david] - * - * $EndLog$ - */ /* * File: mach/vm_sync.h * diff --git a/osfmk/mach/vm_types.h b/osfmk/mach/vm_types.h index cd69b3b78..0e7470124 100644 --- a/osfmk/mach/vm_types.h +++ b/osfmk/mach/vm_types.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002,2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -26,16 +26,19 @@ #ifndef MACH_VM_TYPES_H_ #define MACH_VM_TYPES_H_ +#include +#include + #include #include typedef vm_offset_t pointer_t; typedef vm_offset_t vm_address_t; -typedef unsigned long long vm_object_offset_t; +typedef uint64_t vm_object_offset_t; #ifdef KERNEL_PRIVATE -#if !defined(MACH_KERNEL_PRIVATE) +#if !defined(__APPLE_API_PRIVATE) || !defined(MACH_KERNEL_PRIVATE) /* * Use specifically typed null structures for these in @@ -43,35 +46,52 @@ typedef unsigned long long vm_object_offset_t; * about type mismatches, etc... Otherwise, these would * be void*. */ -struct upl ; struct vm_map ; struct vm_object ; + +#endif /* !__APPLE_API_PRIVATE || !MACH_KERNEL_PRIVATE */ + +typedef struct vm_map *vm_map_t; +typedef struct vm_object *vm_object_t; +#define VM_OBJECT_NULL ((vm_object_t) 0) + +#else /* KERNEL_PRIVATE */ + +typedef mach_port_t vm_map_t; + +#endif /* KERNEL_PRIVATE */ + +#define VM_MAP_NULL ((vm_map_t) 0) + + +#ifdef __APPLE_API_EVOLVING + +#ifdef KERNEL_PRIVATE + +#ifndef MACH_KERNEL_PRIVATE +struct upl ; struct vm_map_copy ; struct vm_named_entry ; - #endif /* !MACH_KERNEL_PRIVATE */ typedef struct upl *upl_t; -typedef struct vm_map *vm_map_t; +typedef struct vm_map_copy *vm_map_copy_t; typedef struct vm_named_entry *vm_named_entry_t; -typedef struct vm_object *vm_object_t; -typedef struct vm_map_copy *vm_map_copy_t; -#define VM_OBJECT_NULL ((vm_object_t) 0) #define VM_MAP_COPY_NULL ((vm_map_copy_t) 0) #else /* !KERNEL_PRIVATE */ typedef mach_port_t upl_t; -typedef mach_port_t vm_map_t; typedef mach_port_t vm_named_entry_t; #endif /* !KERNEL_PRIVATE */ #define UPL_NULL ((upl_t) 0) -#define VM_MAP_NULL ((vm_map_t) 0) #define VM_NAMED_ENTRY_NULL ((vm_named_entry_t) 0) +#endif /* __APPLE_API_EVOLVING */ + #endif /* MACH_VM_TYPES_H_ */ diff --git a/osfmk/machine/machine_routines.h b/osfmk/machine/machine_routines.h index 779340d4e..57481db5a 100644 --- a/osfmk/machine/machine_routines.h +++ b/osfmk/machine/machine_routines.h @@ -4,7 +4,7 @@ * @APPLE_LICENSE_HEADER_START@ * * The contents of this file constitute Original Code as defined in and - * are subject to`the Apple Public Source License Version 1.1 (the + * are subject to the Apple Public Source License Version 1.1 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. diff --git a/osfmk/man/DMN_port_deleted.html b/osfmk/man/DMN_port_deleted.html new file mode 100755 index 000000000..357e0e008 --- /dev/null +++ b/osfmk/man/DMN_port_deleted.html @@ -0,0 +1 @@ +

do_mach_notify_port_deleted


Server Interface - Handle the current instance of a port-deleted notification.

SYNOPSIS

kern_return_t   do_mach_notify_port_deleted
                (notify_port_t                           notify,
                 mach_port_name_t                          name);


kern_return_t   do_seqnos_mach_notify_port_deleted
                (notify_port_t                           notify,
                 mach_port_seqno_t                        seqno,
                 mach_port_name_t                          name);

PARAMETERS

notify
[in notify (receive) right] The port to which the notification was sent.

seqno
[in scalar] The sequence number of this message relative to the notification port.

name
[in scalar] The invalid name.

DESCRIPTION

A do_mach_notify_port_deleted function is called by notify_server as the result of a kernel message indicating that a port name is no longer usable (that is, it no longer names a valid right), typically as a result of the right so named being consumed or moved. In contrast, a dead-name notification indicates that the port name is now dead as the result of the associated receive right having died. notify is the port named via mach_port_request_notification or mach_msg.

NOTES

This interface is machine word length specific because of the port name parameter.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: notify_server, seqnos_notify_server, mach_msg, mach_port_request_notification, do_mach_notify_dead_name, do_mach_notify_no_senders, do_mach_notify_send_once. \ No newline at end of file diff --git a/osfmk/man/DMN_port_destroyed.html b/osfmk/man/DMN_port_destroyed.html new file mode 100755 index 000000000..9caab669c --- /dev/null +++ b/osfmk/man/DMN_port_destroyed.html @@ -0,0 +1 @@ +

do_mach_notify_port_destroyed


Server Interface - Handle the current instance of a port-destroyed notification.

SYNOPSIS

kern_return_t   do_mach_notify_port_destroyed
                (notify_port_t                           notify,
                 mach_port_receive_t                       name);


kern_return_t   do_seqnos_mach_notify_port_destroyed
                (mach_port_t                             notify,
                 mach_port_seqno_t                        seqno,
                 mach_port_receive_t                       name);

PARAMETERS

notify
[in notify (receive) right] The port to which the notification was sent.

seqno
[in scalar] The sequence number of this message relative to the notification port.

name
[in scalar] The invalid name.

DESCRIPTION

A do_mach_notify_port_destroyed function is called by notify_server as the result of a kernel message indicating that a receive right would have been destroyed. notify is the port named via mach_port_request_notification or mach_msg.

NOTES

This interface is machine word length specific because of the port name parameter.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: notify_server, seqnos_notify_server, mach_msg, mach_port_request_notification, do_mach_notify_dead_name, do_mach_notify_no_senders, do_mach_notify_send_once. \ No newline at end of file diff --git a/osfmk/man/DP_backing_store_create.html b/osfmk/man/DP_backing_store_create.html new file mode 100755 index 000000000..ba58934eb --- /dev/null +++ b/osfmk/man/DP_backing_store_create.html @@ -0,0 +1 @@ +

default_pager_backing_store_create


Server Interface - Create a backing storage object.

SYNOPSIS

#include< mach/default_pager_object.h>

kern_return_t   default_pager_backing_store_create
                (mach_port_t                              pager,
                 int                                   priority,
                 int                                     clsize,
                 mach_port_t                      backing_store);

PARAMETERS

pager
[in default pager (receive) right] The default pager service port.

priority
[in scalar] The scheduling priority for the backing store service thread(s).

clsize
[in scalar] The preferred cluster size (in bytes) for the backing store object.

backing_store
[out backing store (receive) right] The port used to manipulate the created backing store.

DESCRIPTION

The default_pager_backing_store_create function is called to create a new backing storage object. The kernel does not make this call itself (which is why it can be a synchronous call); this request is only issued by tasks (privileged) holding the default pager service port.

RETURN VALUES

KERN_FAILURE
The default pager does not support this operation.

KERN_INVALID_ARGUMENT
The pager port does not represent a valid default pager.

KERN_SUCCESS
The operation was successful.

RELATED INFORMATION

Functions: default_pager_backing_store_delete, default_pager_backing_store_info. \ No newline at end of file diff --git a/osfmk/man/DP_backing_store_delete.html b/osfmk/man/DP_backing_store_delete.html new file mode 100755 index 000000000..a4018cb6a --- /dev/null +++ b/osfmk/man/DP_backing_store_delete.html @@ -0,0 +1 @@ +

default_pager_backing_store_delete


Server Interface - Delete a backing storage object.

SYNOPSIS

#include< mach/default_pager_object.h>

kern_return_t   default_pager_backing_store_delete
                (mach_port_t                      backing_store);

PARAMETERS

backing_store
[in backing store (receive) right] The backing store port created by default_pager_backing_store_create.

DESCRIPTION

The default_pager_backing_store_delete function is called to destroy a backing storage object created by default_pager_backing_store_create. The kernel does not make this call itself (which is why it can be a synchronous call); this request is only issued by tasks holding the backing store port, created with default_pager_backing_store_create, for a default memory manager.

RETURN VALUES

KERN_FAILURE
The default pager does not support this operation.

KERN_INVALID_ARGUMENT
The backing_store port does not represent a valid backing store or the specified segment overlaps an existing partition.

KERN_SUCCESS
The operation was successful.

RELATED INFORMATION

Functions: default_pager_backing_store_create, default_pager_backing_store_info. \ No newline at end of file diff --git a/osfmk/man/DP_backing_store_info.html b/osfmk/man/DP_backing_store_info.html new file mode 100755 index 000000000..21da7ae5c --- /dev/null +++ b/osfmk/man/DP_backing_store_info.html @@ -0,0 +1 @@ +

default_pager_backing_store_info


Server Interface - Return information about a backing storage object.

SYNOPSIS

#include< default_pager/mach/default_pager_types.h>

kern_return_t   default_pager_backing_store_info
                (mach_port_t                      backing_store,
                 backing_store_flavor_t                  flavor,
                 backing_store_info_t                      info,
                 mach_msg_type_number_t                    size);

PARAMETERS

backing_store
[in backing store (receive) right] The backing store port for which information is desired.

flavor
[in scalar] The type of information to be returned. Valid values are:

BACKING_STORE_BASIC_INFO
Statistical and space used/available information. It includes the priority and cluster size that was provided in the default_pager_backing_store_create call.

info
[pointer to in structure] The data structure that will be filled in with the information provided for the requested flavor.

size
[pointer to in/out scalar] On input, the maximum size of the info data structure; on output, the actual size of the returned data.

DESCRIPTION

The default_pager_backing_store_info function is called to obtain information about a backing storage object created by default_pager_backing_store_create. The kernel does not make this call itself (which is why it can be a synchronous call); this request is only issued by tasks holding the backing store port, created with default_pager_backing_store_create, for a default memory manager.

RETURN VALUES

KERN_FAILURE
The default pager does not support this operation.

KERN_INVALID_ARGUMENT
The backing_store port does not represent a valid backing store, flavor is not valid, or size is not the size for the requested flavor.

KERN_SUCCESS
The operation was successful.

RELATED INFORMATION

Functions: default_pager_backing_store_create, default_pager_backing_store_delete.

Data Structures: backing_store_basic_info. \ No newline at end of file diff --git a/osfmk/man/DP_object_create.html b/osfmk/man/DP_object_create.html new file mode 100755 index 000000000..9f94b814a --- /dev/null +++ b/osfmk/man/DP_object_create.html @@ -0,0 +1 @@ +

default_pager_object_create


Server Interface - Initialize a non-persistent memory object suitable for sharing between tasks.

SYNOPSIS

kern_return_t   default_pager_object_create
                (mach_port_t                              pager,
                 memory_object_t                 *memory_object,
                 vm_size_t                          object_size);


kern_return_t   seqnos_default_pager_object_create
                (mach_port_t                              pager,
                 mach_port_seqno_t                        seqno,
                 memory_object_t                 *memory_object,
                 vm_size_t                          object_size);

PARAMETERS

pager
[in default-pager (receive) right] The default memory manager service port.

seqno
[in scalar] The sequence number of this message relative to the pager port.

memory_object
[out memory-object send right] A memory object port (with full access) for the memory object.

object_size
[in scalar] The maximum size for the memory object.

DESCRIPTION

A default_pager_object_create function is called as the result of a message requesting that the default memory manager create and return a (shared) memory object which is suitable for use with vm_map. This memory object has the same properties as does a memory object provided by vm_allocate: its initial contents are zero and the backing contents are temporary in that they do not persist after the memory object is destroyed. The memory object is suitable for use as non-permanent shared memory. The kernel does not make this call itself (which is why it can be a synchronous call); this request is only issued by (privileged) tasks holding the default memory manager port. This call should be contrasted with the kernel's memory_object_create message, in which the memory cache object is already created and the identity of the abstract memory object is made known to the default manager.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: vm_map, host_default_memory_manager, memory_object_create, memory_object_default_server, seqnos_memory_object_default_server. \ No newline at end of file diff --git a/osfmk/man/DR_overwrite_async.html b/osfmk/man/DR_overwrite_async.html new file mode 100755 index 000000000..a583d9b58 --- /dev/null +++ b/osfmk/man/DR_overwrite_async.html @@ -0,0 +1 @@ +

device_read_overwrite_async


System Trap - Read a sequence of bytes from a device object into the caller's

SYNOPSIS

kern_return_t   device_read_overwrite_async
                (mach_port_t                             device,
                 mach_port_t                              queue,
                 mach_port_t                         request_id,
                 dev_mode_t                                mode,
                 recnum_t                                recnum,
                 io_buf_len_t                      bytes_wanted,
                 io_buf_ptr_t                            buffer);

PARAMETERS

device
[in device send right] A device port to the device to be read.

queue
[in io_done queue send right] The port returned from the io_done_queue_create call.

request_id
[in send right] An unique request identifier that will be passed back as part of the io_done_result structure.

mode
[in scalar] I/O mode value. Meaningful options are:

D_NOWAIT
Do not wait if data is unavailable.

recnum
[in scalar] Record number to be read.

bytes_wanted
[in scalar] Size of data transfer.

buffer
[pointer to in array of bytes] Data buffer to be overwritten.

DESCRIPTION

The device_read_overwrite system trap enqueues a read operation for a sequence of bytes from a device object to be placed directly into the caller's address space. The meaning of recnum as well as the specific operation performed is device dependent.

RETURN VALUES

device_read_overwrite_async returns only invalid parameter errors.

RELATED INFORMATION

Functions: device_read_async, device_read_async_inband, device_write_async, device_write_async_inband, io_done_queue_create. \ No newline at end of file diff --git a/osfmk/man/HD_memory_manager.html b/osfmk/man/HD_memory_manager.html new file mode 100755 index 000000000..36a1b5ea1 --- /dev/null +++ b/osfmk/man/HD_memory_manager.html @@ -0,0 +1 @@ +

host_default_memory_manager


Function - Establish the official connection between the kernel and its default pager task.

SYNOPSIS

kern_return_t   host_default_memory_manager
                (host_priv_t                          host_priv,
                 mach_port_make_send_t          default_manager,
                 vm_size_t                         cluster_size);

PARAMETERS

host_priv
[in host-control send right] The control port naming the host for which the default memory manager is to be set.

default_manager
[pointer to in/out default-pager send right] A memory manager port to the new default memory manager. If this value is MACH_PORT_NULL, the old memory manager is not changed. The old memory manager port is returned in this variable.

cluster_size
[in scalar] The preferred cluster size (in bytes) for temporary memory objects.

DESCRIPTION

The host_default_memory_manager function establishes the default memory manager for a host. The named manager will be the target for future memory_object_create calls.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: memory_object_create, vm_allocate. \ No newline at end of file diff --git a/osfmk/man/MO_SY_completed.html b/osfmk/man/MO_SY_completed.html new file mode 100755 index 000000000..da5828394 --- /dev/null +++ b/osfmk/man/MO_SY_completed.html @@ -0,0 +1 @@ +

memory_object_synchronize_completed


Function - Inform the kernel that synchronized data has been processed.

SYNOPSIS

kern_return_t   memory_object_synchronize_completed 
                (memory_object_control_t         memory_control,
                 vm_offset_t                             offset,
                 vm_offset_t                             length);

PARAMETERS

memory_control
[in memory-cache-control send right] The memory cache control port to be used by the memory manager for cache management requests. This port is provided by the kernel in a memory_object_init call.

offset
[in scalar] The offset within the memory object, in bytes.

length
[in scalar] The amount of data processed. The number must be an integral number of memory object pages.

DESCRIPTION

The memory_object_synchronize_completed function informs the kernel that previously synchronized data (memory_object_synchronize) has been queued or placed on backing storage. This reply causes the issuing client to return from its vm_msync call. The offset and length must match that of the corresponding memory_object_synchronize call. There may be multiple synchronize requests for a given memory object outstanding but they will not overlap.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: memory_object_data_return, memory_object_synchronize, vm_msync. \ No newline at end of file diff --git a/osfmk/man/MO_change_attributes.html b/osfmk/man/MO_change_attributes.html new file mode 100755 index 000000000..1bca01076 --- /dev/null +++ b/osfmk/man/MO_change_attributes.html @@ -0,0 +1 @@ +

memory_object_change_attributes


Function - Modify caller-specified subset of attributes representing target memory object.

SYNOPSIS

kern_return_t   memory_object_change_attributes
                (memory_object_control_t         memory_control,
                 memory_object_flavor_t                  flavor,
                 memory_object_info_t                attributes,
                 attributes                    attributes_count,
                 mach_port_t                           reply_to);

PARAMETERS

memory_control
[in memory-cache-control send right] The memory cache control port to be used by the memory manager for cache management requests. This port is provided by the kernel in a memory_object_init or memory_object_create call.

flavor
[in scalar] The type of information to be changed. Valid values are:

MEMORY_OBJECT_PERFORMANCE_INFO
Performance related attributes such as the cache indicator and the cluster size. attributes should specify a structure of type memory_object_perf_info.

MEMORY_OBJECT_BEHAVIOR_INFO
Behavior related attributes such as the copy strategy and sync invalidate flag. attributes should specify a structure of type memory_object_behavior_info.

MEMORY_OBJECT_ATTRIBUTES_INFO
Behavior and performance related attributes such as the copy strategy, cache indicator, and cluster size. attributes should specify a structure of type memory_object_attr_info.

attributes
[pointer to in structure] New attributes.

attributes_count
[in scalar] The size of the buffer (in natural-sized units).

reply_port
[in reply receive (to be converted to send) right] A port to which a reply (memory_object_change_completed) is to be sent indicating the completion of the attribute change. Such a reply would be useful if the cache attribute is turned off, since such a change, if the memory object is no longer mapped, may result in the object being terminated.

DESCRIPTION

The memory_object_change_attributes function sets various attributes of the specified memory object.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: memory_object_change_completed, memory_object_get_attributes, memory_object_create.

Data Structures: memory_object_perf_info, memory_object_attr_info. \ No newline at end of file diff --git a/osfmk/man/MO_change_completed.html b/osfmk/man/MO_change_completed.html new file mode 100755 index 000000000..51ec47a8a --- /dev/null +++ b/osfmk/man/MO_change_completed.html @@ -0,0 +1 @@ +

memory_object_change_completed


Server Interface - Notify memory manager that kernel has updated memory object attributes as requested.

SYNOPSIS

kern_return_t   memory_object_change_completed
                (memory_object_t                     reply_port,
                 memory_object_control_t         memory_control,
                 memory_object_flavor_t                  flavor);


kern_return_t   seqnos_memory_object_change_completed
                (memory_object_t                     reply_port,
                 mach_port_seqno_t                        seqno,
                 memory_object_control_t         memory_control,
                 memory_object_flavor_t                  flavor);

PARAMETERS

reply_port
[in reply (receive) right] The port supplied in the corresponding memory_object_change_attributes call.

seqno
[in scalar] The sequence number of this message relative to the port named in the memory_object_change_attributes call.

memory_control
[in memory-cache-control send right] The memory cache control port to be used for a response by the memory manager. If the memory object has been supplied to more than one kernel, this parameter identifies the kernel that is making the call.

flavor
[in scalar] The flavor of attributes changed by the corresponding memory_object_change_attributes call.

DESCRIPTION

A memory_object_change_completed function is called as the result of a kernel message confirming the kernel's action in response to a memory_object_change_attributes call from the memory manager.

When the kernel completes the requested changes, it calls memory_object_change_completed (asynchronously) using the port explicitly provided in the memory_object_change_attributes call.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: memory_object_change_attributes, memory_object_server, seqnos_memory_object_server. \ No newline at end of file diff --git a/osfmk/man/MO_data_initialize.html b/osfmk/man/MO_data_initialize.html new file mode 100755 index 000000000..e391ae77f --- /dev/null +++ b/osfmk/man/MO_data_initialize.html @@ -0,0 +1 @@ +

memory_object_data_initialize


Server Interface - Request that the default pager record initialization information for specified memory object.

SYNOPSIS

kern_return_t   memory_object_data_initialize
                (memory_object_t                  memory_object,
                 memory_object_control_t         memory_control,
                 vm_offset_t                             offset,
                 pointer_t                                 data);


kern_return_t   seqnos_memory_object_data_initialize
                (memory_object_t                  memory_object,
                 mach_port_seqno_t                        seqno,
                 memory_object_control_t         memory_control,
                 vm_offset_t                             offset,
                 pointer_t                                 data);

PARAMETERS

memory_object
[in abstract-memory-object (receive) right] The abstract memory object port that represents the memory object data, as supplied by the kernel in a memory_object_create call.

seqno
[in scalar] The sequence number of this message relative to the abstract memory object port.

memory_control
[in memory-cache-control send right] The memory cache control port to be used for a response by the memory manager. If the memory object has been supplied to more than one kernel, this parameter identifies the kernel that is making the call.

offset
[in scalar] The offset within the memory object.

data
[in pointer to dynamic array of bytes] The data that has been modified while cached in physical memory.

DESCRIPTION

A memory_object_data_initialize function is called as the result of a kernel message providing the default memory manager with initial data for a kernel-created memory object. If the memory manager already has supplied data (by a previous memory_object_data_initialize or memory_object_data_return), it should ignore this call. Otherwise, the call behaves the same as the memory_object_data_return call.

The kernel makes this call only to the default memory manager and only on temporary memory objects that it has created with memory_object_create.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: memory_object_create, memory_object_data_return, memory_object_default_server, seqnos_memory_object_default_server. \ No newline at end of file diff --git a/osfmk/man/MO_data_unavailable.html b/osfmk/man/MO_data_unavailable.html new file mode 100755 index 000000000..d74aeca7d --- /dev/null +++ b/osfmk/man/MO_data_unavailable.html @@ -0,0 +1 @@ +

memory_object_data_unavailable


Function - Instruct kernel to zero-fill pages as requested data does not exist.

SYNOPSIS

kern_return_t   memory_object_data_unavailable
                (memory_object_control_t         memory_control,
                 vm_offset_t                             offset,
                 vm_size_t                                 size);

PARAMETERS

memory_control
[in memory-cache-control send right] The memory cache control port to be used by the memory manager for cache management requests. This port is provided by the kernel in a memory_object_init or a memory_object_create call.

offset
[in scalar] The offset within the memory object, in bytes.

size
[in scalar] The number of bytes of data (starting at offset). The number must convert to an integral number of memory object pages.

DESCRIPTION

The memory_object_data_unavailable function indicates that the memory manager cannot provide the kernel with the data requested for the given region. Instead, the kernel should provide the data for this region.

A memory manager can use this call in any of the following situations:

  • When the object was created by the kernel (via memory_object_create) and the kernel has not yet provided data for the region (via either memory_object_data_initialize or memory_object_data_return). In this case, the object is a temporary memory object; the memory manager is the default memory manager; and the kernel should provide zero-filled pages for the object.

  • When the object is a normal user-created memory object. In this case, the kernel should provide zero-filled pages for the region.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: memory_object_create, memory_object_data_error, memory_object_data_request, memory_object_data_supply. \ No newline at end of file diff --git a/osfmk/man/MO_default_server.html b/osfmk/man/MO_default_server.html new file mode 100755 index 000000000..8d9a552c5 --- /dev/null +++ b/osfmk/man/MO_default_server.html @@ -0,0 +1 @@ +

memory_object_default_server


Function - Handle kernel operation request targeted for the default pager.

SYNOPSIS

boolean_t	memory_object_default_server
		(mach_msg_header_t	request_msg,
		mach_msg_header_t	reply_ms);

PARAMETERS

in_msg
[pointer to in structure] The memory manager message received from the kernel.

out_msg
[out structure] A reply message. Note that no kernel messages to a memory manager expect a direct reply.

DESCRIPTION

The memory_object_default_server function is the MIG generated server handling function to handle messages from the kernel targeted to the default memory manager. This server function only handles messages unique to the default memory manager. Messages that are common to all memory managers are handled by memory_object_server.

A \*Vmemory manager\*O is a server task that responds to specific messages from the kernel in order to handle memory management functions for the kernel. The memory_object_default_server function performs all necessary argument handling for a kernel message and calls one of the default memory manager functions.

RETURN VALUES

TRUE
The message was handled and the appropriate function was called.

FALSE
The message did not apply to this memory management interface and no other action was taken.

RELATED INFORMATION

Functions: seqnos_memory_object_default_server, memory_object_server, memory_object_create, memory_object_data_initialize, default_pager_object_create, default_pager_info. \ No newline at end of file diff --git a/osfmk/man/MO_get_attributes.html b/osfmk/man/MO_get_attributes.html new file mode 100755 index 000000000..15d33f797 --- /dev/null +++ b/osfmk/man/MO_get_attributes.html @@ -0,0 +1 @@ +

memory_object_get_attributes


Function - Return current attributes for a memory object.

SYNOPSIS

kern_return_t   memory_object_get_attributes
                (memory_object_control_t         memory_control,
                 memory_object_flavor_t                  flavor,
                 memory_object_info_t                attributes,
                 mach_msg_type_number_t        attributes_count);

PARAMETERS

memory_control
[in memory-cache-control send right] The memory cache control port to be used by the memory manager for cache management requests. This port is provided by the kernel in a memory_object_notify call.

flavor
[in scalar] The type of information to be returned. Valid values are:

MEMORY_OBJECT_PERFORMANCE_INFO
Performance related attributes such as the cache indicator and the cluster size. attributes should specify a structure of type memory_object_perf_info.

MEMORY_OBJECT_BEHAVIOR_INFO
Behavior related attributes such as the copy strategy and sync invalidate flag. attributes should specify a structure of type memory_object_behavior_info.
MEMORY_OBJECT_ATTRIBUTES_INFO
Behavior and performance related attributes such as the copy strategy, cache indicator, and cluster size. attributes should specify a structure of type memory_object_attr_info.

attributes
[out structure] Current attributes.

attributes_count
[in/out scalar] On input, the maximum size of the buffer; on output, the size returned (in natural-sized units).

DESCRIPTION

The memory_object_get_attributes function retrieves the current attributes for the specified memory object.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: memory_object_change_attributes.

Data Structures: memory_object_perf_info, memory_object_attr_info. \ No newline at end of file diff --git a/osfmk/man/MO_lock_completed.html b/osfmk/man/MO_lock_completed.html new file mode 100755 index 000000000..aa62805c2 --- /dev/null +++ b/osfmk/man/MO_lock_completed.html @@ -0,0 +1 @@ +

memory_object_lock_completed


Server Interface - Report to memory manager that a previous consistency control request has been handled.

SYNOPSIS

kern_return_t   memory_object_lock_completed
                (memory_object_t                     reply_port,
                 memory_object_control_t         memory_control,
                 vm_offset_t                             offset,
                 vm_size_t                               length);


kern_return_t   seqnos_memory_object_lock_completed
                (memory_object_t                     reply_port,
                 mach_port_seqno_t                        seqno,
                 memory_object_control_t         memory_control,
                 vm_offset_t                             offset,
                 vm_size_t                               length);

PARAMETERS

reply_port
[in reply (receive) right] The port supplied in the corresponding memory_object_lock_request call.

seqno
[in scalar] The sequence number of this message relative to the port named in the memory_object_lock_completed message.

memory_control
[in memory-cache-control send right] The memory cache control port to be used for a response by the memory manager. If the memory object has been supplied to more than one kernel, this parameter identifies the kernel that is making the call.

offset
[in scalar] The offset within the memory object.

length
[in scalar] The number of bytes to which the call refers, starting at offset. The number converts to an integral number of memory object pages.

DESCRIPTION

A memory_object_lock_completed function is called as the result of a kernel message confirming the kernel's action in response to a memory_object_lock_request call from the memory manager. The memory manager can use the memory_object_lock_request call to:

  • Alter access restrictions specified in the memory_object_data_supply call or a previous memory_object_lock_request call.

  • Write back modifications made in memory.

  • Invalidate its cached data.

When the kernel completes the requested actions, it calls memory_object_lock_completed (asynchronously) using the port explicitly provided in the memory_object_lock_request call. Because the memory manager cannot know which pages have been modified, or even which pages remain in the cache, it cannot know how many pages will be written back in response to a memory_object_lock_request call. Receiving the memory_object_lock_completed call is the only sure means of detecting completion. The completion call includes the offset and length values from the consistency request to distinguish it from other consistency requests.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: memory_object_lock_request, memory_object_server, seqnos_memory_object_server. \ No newline at end of file diff --git a/osfmk/man/MO_supply_completed.html b/osfmk/man/MO_supply_completed.html new file mode 100755 index 000000000..087304456 --- /dev/null +++ b/osfmk/man/MO_supply_completed.html @@ -0,0 +1 @@ +

memory_object_supply_completed


Server Interface - Return results associated with the kernel's handling of a particular memory manager request.

SYNOPSIS

kern_return_t   memory_object_supply_completed
                (memory_object_t                     reply_port,
                 memory_object_control_t         memory_control,
                 vm_offset_t                             offset,
                 vm_size_t                               length,
                 kern_return_t                           result,
                 vm_offset_t                       error_offset);


kern_return_t   seqnos_memory_object_supply_completed
                (memory_object_t                     reply_port,
                 mach_port_seqno_t                        seqno,
                 memory_object_control_t         memory_control,
                 vm_offset_t                             offset,
                 vm_size_t                               length,
                 kern_return_t                           result,
                 vm_offset_t                       error_offset);

PARAMETERS

reply_port
[in reply (receive) right] The port supplied in the corresponding memory_object_data_supply call.

seqno
[in scalar] The sequence number of this message relative to the port named in the memory_object_data_supply call.

memory_control
[in memory-cache-control send right] The memory cache control port to be used for a response by the memory manager. If the memory object has been supplied to more than one kernel, this parameter identifies the kernel that is making the call.

offset
[in scalar] The offset within the memory object from the corresponding data supply call.

length
[in scalar] The number of bytes accepted. The number converts to an integral number of memory object pages.

result
[in scalar] A kernel return code indicating the result of the supply operation, possibly KERN_SUCCESS. KERN_MEMORY_PRESENT is currently the only error returned; other errors (invalid arguments, for example) abort the data supply operation.

error_offset
[in scalar] The offset within the memory object where the first error occurred.

DESCRIPTION

A memory_object_supply_completed function is called as the result of a kernel message confirming the kernel's action in response to a memory_object_data_supply call from the memory manager.

When the kernel accepts the pages, it calls memory_object_supply_completed (asynchronously) using the port explicitly provided in the memory_object_data_supply call. Because the data supply call can provide multiple pages, not all of which the kernel may necessarily accept and some of which the kernel may have to return to the manager (if precious), the kernel provides this response. If the kernel does not accept all of the pages in the data supply message, it will indicate so in the completion response. If the pages not accepted are precious, they will be returned (in memory_object_data_return messages) before it sends this completion message. The completion call includes the offset and length values from the supply request to distinguish it from other supply requests.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: memory_object_data_supply, memory_object_server, seqnos_memory_object_server. \ No newline at end of file diff --git a/osfmk/man/MP_allocate_subsystem.html b/osfmk/man/MP_allocate_subsystem.html new file mode 100755 index 000000000..195094e9e --- /dev/null +++ b/osfmk/man/MP_allocate_subsystem.html @@ -0,0 +1 @@ +

mach_port_allocate_subsystem


Function - Create a port right associated with the caller-specified subsystem.

SYNOPSIS

kern_return_t   mach_port_allocate_subsystem
                (ipc_space_t                               task,
                 subsystem_t                             subsys,
                 mach_port_name_t              mach_port_name_t);

PARAMETERS

task
[in task send right] The task acquiring the port right.

subsys
[in scalar] The port right naming the subsystem the newly created port is to be associated with.

name
[out scalar] The task's name for the port right. This can be any name that wasn't in use.

DESCRIPTION

The mach_port_allocate_subsystem function creates a new right and associates it with the specifed subsystem (specified via the subsys parameter) previously registered via a call to the mach_subsystem_create interface. The new right's name is returned in the name parameter. The association of this port with the subsystem is immutable for the life of the port.

Any RPC targeted at the new port will cause the kernel glue-code to locate the server function address and argument signature in the associated subsystem.

NOTES

This interface is machine word length specific because of the port name parameter.

RETURN VALUES

KERN_SUCCESS
The right is allocated.

KERN_INVALID_TASK
The space is null.

KERN_INVALID_TASK
The space is dead.

KERN_RESOURCE_SHORTAGE
Couldn't allocate memory.

KERN_NO_SPACE
No room in space for another right.

RELATED INFORMATION

Functions: mach_subsystem_create, thread_activation_create. \ No newline at end of file diff --git a/osfmk/man/MP_request_notification.html b/osfmk/man/MP_request_notification.html new file mode 100755 index 000000000..1d41e4b74 --- /dev/null +++ b/osfmk/man/MP_request_notification.html @@ -0,0 +1 @@ +

mach_port_request_notification


Function - Request notification of the specified port event type.

SYNOPSIS

kern_return_t   mach_port_request_notification
                (ipc_space_t                               task,
                 mach_port_name_t                          name,
                 mach_msg_id_t                          variant,
                 mach_port_mscount_t                       sync,
                 mach_port_send_once_t                   notify,
                 mach_msg_type_name_t               notify_type,
                 mach_port_send_once_t                *previous);

PARAMETERS

task
[in task send right] The task holding the specified right.

name
[in scalar] The task's name for the right.

variant
[in scalar] The type of notification.

sync
[in scalar] Some variants use this value to overcome race conditions.

notify
[in notify send-once or receive (to be converted to send-once) right] A send-once right, to which the notification will be sent.

notify_type
[in scalar] IPC type of the notify right; either MACH_MSG_TYPE_MAKE_SEND_ONCE or MACH_MSG_TYPE_MOVE_SEND_ONCE.

previous
[out notify send-once right] The previously registered send-once right.

DESCRIPTION

The mach_port_request_notification function registers a request for a notification and supplies a send-once right that the notification will use. It is an atomic swap, returning the previously registered send-once right (or MACH_PORT_NULL for none). A notification request may be cancelled by providing MACH_PORT_NULL.

The variant argument takes the following values:

MACH_NOTIFY_PORT_DESTROYED
sync must be zero. The name must specify a receive right, and the call requests a port-destroyed notification for the receive right. If the receive right were to have been destroyed, for instance by mach_port_destroy, then instead the receive right will be sent in a port-destroyed notification to the registered send-once right.

MACH_NOTIFY_DEAD_NAME
The call requests a dead-name notification. name specifies send, receive, or send-once rights for a port. If the port is destroyed (and the right remains, becoming a dead name), then a dead-name notification which carries the name of the right will be sent to the registered send-once right. If sync is non-zero, the name may specify a dead name, and a dead-name notification is immediately generated.

Whenever a dead-name notification is generated, the user reference count of the dead name is incremented. For example, a send right with two user refs has a registered dead-name request. If the port is destroyed, the send right turns into a dead name with three user refs (instead of two), and a dead-name notification is generated.

If the name is made available for reuse, perhaps because of mach_port_destroy or mach_port_mod_refs, or the name denotes a send-once right which has a message sent to it, then the registered send-once right is used to generate a port-deleted notification instead.

MACH_NOTIFY_NO_SENDERS
The call requests a no-senders notification. name must specify a receive right. If the receive right's make-send count is greater than or equal to the sync value, and it has no extant send rights, than an immediate no-senders notification is generated. Otherwise the notification is generated when the receive right next loses its last extant send right. In either case, any previously registered send-once right is returned.

The no-senders notification carries the value the port's make-send count had when it was generated. The make-send count is incremented whenever a send right is made directly from a receive right. The make-send count is reset to zero when the receive right is carried in a message.

When moving a receive right, no-senders notifications are canceled, with a send-once notification sent to indicate the cancelation.

NOTES

This interface is machine word length specific because of the port name parameter.

RETURN VALUES

KERN_INVALID_NAME
name did not denote a right.

KERN_INVALID_RIGHT
name denoted an invalid right.

KERN_INVALID_CAPABILITY
notify was invalid.

When using MACH_NOTIFY_DEAD_NAME:

KERN_UREFS_OVERFLOW
name denotes a dead name, but generating an immediate dead-name notification would overflow the name's user-reference count.

RELATED INFORMATION

Functions: mach_msg, mach_port_get_attributes. \ No newline at end of file diff --git a/osfmk/man/P_set_policy_control.html b/osfmk/man/P_set_policy_control.html new file mode 100755 index 000000000..763cf3b88 --- /dev/null +++ b/osfmk/man/P_set_policy_control.html @@ -0,0 +1 @@ +

processor_set_policy_control


Function - Set target processor set's scheduling policy state.

SYNOPSIS

kern_return_t	processor_set_policy_control
		(processor_set_t	processor_set_control,
		processor_set_flavor_t	flavor,
		processor_set_info_t	policy_info,
		mach_msg_type_number_t*	policy_info_count,
		boolean_t	change_tasks_threads);

PARAMETERS

processor_set_control
[in processor-set-control send right] A processor set control port.
flavor
[in scalar] The type of policy change to make.
PROCESSOR_SET_TIMESHARE_DEFAULT
Change the base attributes for the timeshare scheduling policy, making timeshare the default policy. The structure is policy_timeshare_base.
PROCESSOR_SET_FIFO_DEFAULT
Change the base attributes for the FIFO (first-in, first-out) scheduling policy, making FIFO the default policy. The structure is policy_fifo_base.
PROCESSOR_SET_RR_DEFAULT
Changed the base attributes for the round-robin scheduling policy, making round robin the default policy. The structure is policy_rr_base.
PROCESSOR_SET_TIMESHARE_LIMITS
Change the limits on the allowed timeshare policy attributes. The structure is defined by policy_timeshare_limit.
PROCESSOR_SET_RR_LIMITS
Change the limits on the allowed round robin policy attributes. The structure is defined by policy_rr_limit.
PROCESSOR_SET_FIFO_LIMITS
Change the limits on the allowed first-in, first-out policy attributes. The structure is defined by policy_fifo_limit.
PROCESSOR_SET_ENABLED_POLICIES
Change the set of enabled policies. The data is a bit-vector.
policy_info
[in structure] The relevant policy information.
policy_info_count
[in scalar] The size of the buffer (in natural-sized units).
change_tasks_threads
[in scalar] If true, any assigned task or thread whose policy is no longer enabled or whose scheduling attributes exceed the current limits will have their limits adjusted or their policy set to the default as appropriate.

DESCRIPTION

The processor_set_policy_control function controls scheduling attributes governing the processor set.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: processor_set_statistics, processor_set_create, processor_set_default, processor_assign, processor_set_info.

Data Structures: policy_timeshare_info, policy_rr_info, policy_fifo_info. \ No newline at end of file diff --git a/osfmk/man/P_set_policy_disable.html b/osfmk/man/P_set_policy_disable.html new file mode 100755 index 000000000..5c391db21 --- /dev/null +++ b/osfmk/man/P_set_policy_disable.html @@ -0,0 +1 @@ +

processor_set_policy_disable


Function - Disables a scheduling policy for a processor set.

SYNOPSIS

#include< mach/mach_host.h>

kern_return_t	processor_set_policy_disable
		(processor_set_t	processor_set,
		int	policy,
		boolean_t	change_threads);

PARAMETERS

processor_set
[in processor-set-control port] The control port for the processor set for which a scheduling policy is to be disabled.
policy
[in scalar] Policy to be disabled. The values currently defined are POLICY_TIMESHARE and POLICY_FIXEDPRI.
change_threads
[in scalar] If true, causes the scheduling policy for all threads currently running with policy to POLICY_TIMESHARE.

DESCRIPTION

The processor_set_policy_disable function restricts the set of scheduling policies allowed for processor_set. The set of scheduling policies allowed for a processor set is the set of policies allowed to be set for threads assigned to that processor set. The current set of permitted policies can be obtained from processor_set_info. Timesharing may not be forbidden for any processor set. This is a compromise to reduce the complexity of the assign operation; any thread whose policy is forbidden by its target processor set has its policy reset to timesharing. Disabling a scheduling policy for a processor set has no effect on threads currently assigned to that processor set unless change_threads is TRUE, in which case their policies will be reset to timesharing.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: processor_set_policy_enable, processor_set_info, thread_policy. \ No newline at end of file diff --git a/osfmk/man/P_set_policy_enable.html b/osfmk/man/P_set_policy_enable.html new file mode 100755 index 000000000..8bb760d6a --- /dev/null +++ b/osfmk/man/P_set_policy_enable.html @@ -0,0 +1 @@ +

processor_set_policy_enable


Function - Enables a scheduling policy for a processor set.

SYNOPSIS

#include< mach/mach_host.h>

kern_return_t	processor_set_policy_enable
		(processor_set_t	processor_set,
		int	policy);

PARAMETERS

processor_set
[in processor-set-control port] The control port for the processor set for which a scheduling policy is to be enabled.
policy
[in scalar] Policy to be enabled. The values currently defined are POLICY_TIMESHARE and POLICY_FIXEDPRI.

DESCRIPTION

The processor_set_policy_enable function extends the set of scheduling policies allowed for processor_set. The set of scheduling policies allowed for a processor set is the set of policies allowed to be set for threads assigned to that processor set. The current set of permitted policies can be obtained from processor_set_info.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: processor_set_info, processor_set_policy_disable, thread_policy. \ No newline at end of file diff --git a/osfmk/man/SMO_default_server.html b/osfmk/man/SMO_default_server.html new file mode 100755 index 000000000..d3da6bbd7 --- /dev/null +++ b/osfmk/man/SMO_default_server.html @@ -0,0 +1 @@ +

seqnos_memory_object_default_server


Function - Handle kernel operation request targeted for the default pager.

SYNOPSIS

boolean_t	seqnos_memory_object_default_server
		(mach_msg_header_t	request_msg,
		mach_msg_header_t	reply_ms);

PARAMETERS

in_msg
[pointer to in structure] The memory manager message received from the kernel.

out_msg
[out structure] A reply message. Note that no kernel messages to a memory manager expect a direct reply.

DESCRIPTION

The seqnos_memory_object_default_server function is the MIG generated server handling function to handle messages from the kernel targeted to the default memory manager. This server function only handles messages unique to the default memory manager. Messages that are common to all memory managers are handled by seqnos_memory_object_server.

A \*Vmemory manager\*O is a server task that responds to specific messages from the kernel in order to handle memory management functions for the kernel. The seqnos_memory_object_default_server function performs all necessary argument handling for a kernel message and calls one of the default memory manager functions.

NOTES

seqnos_memory_object_default_server differs from memory_object_default_server in that it supplies message sequence numbers to the server interfaces it calls.

RETURN VALUES

TRUE
The message was handled and the appropriate function was called.

FALSE
The message did not apply to this memory management interface and no other action was taken.

RELATED INFORMATION

Functions: memory_object_default_server, seqnos_memory_object_server, seqnos_memory_object_create, seqnos_memory_object_data_initialize, seqnos_default_pager_object_create, seqnos_default_pager_info. \ No newline at end of file diff --git a/osfmk/man/SMO_server.html b/osfmk/man/SMO_server.html new file mode 100755 index 000000000..6f3aaf971 --- /dev/null +++ b/osfmk/man/SMO_server.html @@ -0,0 +1 @@ +

seqnos_memory_object_server


Function - Handle kernel operation request aimed at a given memory manager.

SYNOPSIS

boolean_t	seqnos_memory_object_server
		(mach_msg_header_t	request_msg,
		mach_msg_header_t	reply_ms);

PARAMETERS

in_msg
[pointer to in structure] The memory manager message received from the kernel.

out_msg
[out structure] A reply message. No messages to a memory manager expect a direct reply, so this field is not used.

DESCRIPTION

The seqnos_memory_object_server function is the MIG generated server handling function to handle messages from the kernel targeted to a memory manager.

A \*Vmemory manager\*O is a server task that responds to specific messages from the kernel in order to handle memory management functions for the kernel. The seqnos_memory_object_server function performs all necessary argument handling for a kernel message and calls one of the memory manager functions to interpret the message.

NOTES

seqnos_memory_object_server differs from memory_object_server in that it supplies message sequence numbers to the server interfaces.

RETURN VALUES

TRUE
The message was handled and the appropriate function was called.

FALSE
The message did not apply to this memory management interface and no other action was taken.

RELATED INFORMATION

Functions: seqnos_memory_object_default_server, seqnos_memory_object_data_request, seqnos_memory_object_data_unlock, seqnos_memory_object_data_return, seqnos_memory_object_supply_completed, seqnos_memory_object_lock_completed, seqnos_seqnos_memory_object_change_completed, seqnos_memory_object_terminate, seqnos_memory_object_synchronize, memory_object_server. \ No newline at end of file diff --git a/osfmk/man/TS_exception_ports.html b/osfmk/man/TS_exception_ports.html new file mode 100755 index 000000000..b6b26f7cc --- /dev/null +++ b/osfmk/man/TS_exception_ports.html @@ -0,0 +1 @@ +

thread_swap_exception_ports


Function - Swap exception ports for a thread.

SYNOPSIS

kern_return_t   thread_swap_exception_ports
                (thread_act_t                            thread,
                 exception_mask_t               exception_types,
                 mach_port_t                     exception_port,
                 exception_behavior_t                  behavior,
                 thread_state_flavor_t                   flavor,
                 exception_mask_array_t     old_exception_masks,
                 old_exception_masks        old_exception_count,
                 exception_port_array_t     old_exception_ports,
                 exception_behavior_array_t       old_behaviors,
                 exception_flavor_array_t           old_flavors);

PARAMETERS

thread
[in thread send right] The thread for which to set the ports.

exception_types
[in scalar] A flag word indicating the types of exceptions for which the exception port applies:

EXC_MASK_BAD_ACCESS
Could not access memory.

EXC_MASK_BAD_INSTRUCTION
Instruction failed. Illegal or undefined instruction or operand.

EXC_MASK_ARITHMETIC
Arithmetic exception

EXC_MASK_EMULATION
Emulation instruction. Emulation support instruction encountered.

EXC_MASK_SOFTWARE
Software generated exception.

EXC_MASK_BREAKPOINT
Trace, breakpoint, etc.

EXC_MASK_SYSCALL
System call requested.

EXC_MASK_MACH_SYSCALL
System call with a number in the Mach call range requested.

exception_port
[in exception send right] The exception port for all selected exception types.

behavior
[in scalar] Control of the behavior of the exception processing. Defined types are:

EXCEPTION_DEFAULT
Send a catch_exception_raise message including the thread identity.

EXCEPTION_DEFAULT_PROTECTED
Send a catch_exception_raise message including the thread identity. Mark the exception port (and associated exceptions) as protected.

EXCEPTION_STATE
Send a catch_exception_raise_state message including the thread state.

EXCEPTION_STATE_PROTECTED
Send a catch_exception_raise_state message including the thread state. Mark the exception port (and associated exceptions) as protected.

EXCEPTION_STATE_IDENTITY
Send a catch_exception_raise_state_identity message including the thread identity and state.

EXCEPTION_STATE_IDENTITY_PROTECTED
Send a catch_exception_raise_state_identity message including the thread identity and state. Mark the exception port (and associated exceptions) as protected.

flavor
[in scalar] The type of state to be sent with the exception message. These types are defined in \*L\*O.

old_exception_masks
[out array of exception_mask_t] An array, each element being a mask specifying for which exception types the corresponding element of the other arrays apply.

old_exception_count
[pointer to in/out scalar] On input, the maximum size of the array buffers; on output, the number of returned sets returned.

old_exception_ports
[out array of exception send rights] The returned exception ports.

old_behaviors
[out array of exception_behavior_t] The type of exception message to be sent as with behavior.

old_flavors
[out array of thread_state_flavor_t] The type of state to be sent with the exception message. These types are defined in \*L\*O.

DESCRIPTION

The thread_swap_exception_ports function sets a specified set of exception ports belonging to thread, returning the old set.

NOTES

If the value of the EXC_MACH_SYSCALL exception class exception port is the host name port, Mach kernel traps are executed by the kernel as expected; any other value causes the attempted execution of these system call numbers to be considered an exception.

A "protected" exception port is one which cannot be fetched and for which exception processing cannot be aborted (thread_abort).

RETURN VALUES

KERN_EXCEPTION_PROTECTED
One of the requested exception ports is protected and cannot be returned.

RELATED INFORMATION

Functions: mach_thread_self, task_get_exception_ports, task_set_exception_ports, task_swap_exception_ports, thread_create, thread_get_exception_ports, thread_set_exception_ports, catch_exception_raise, thread_abort. \ No newline at end of file diff --git a/osfmk/man/VSD_memory_manager.html b/osfmk/man/VSD_memory_manager.html new file mode 100755 index 000000000..7a1043334 --- /dev/null +++ b/osfmk/man/VSD_memory_manager.html @@ -0,0 +1 @@ +

vm_set_default_memory_manager


Function - Obsolete interface. Functionality now provided via host_set_default_memory_manager interface.

SYNOPSIS

kern_return_t   vm_set_default_memory_manager
                (host_priv_t                          host_priv,
                 mach_port_move_send_t          default_manager);

PARAMETERS

host_priv
[in host-control send right] The control port naming the host for which the default memory manager is to be set.

default_manager
[pointer to in/out default-pager send right] A memory manager port to the new default memory manager. If this value is MACH_PORT_NULL, the old memory manager is not changed. The old memory manager port is returned in this variable.

DESCRIPTION

The vm_set_default_memory_manager function establishes the default memory manager for a host. The named manager will be the target for future memory_object_create calls.

NOTES

The vm_set_default_memory_manager interface has been renamed to host_default_memory_manager. The old vm_set_default_memory_manager interface has been retained for backward compatibility, without the cluster_size parameter.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: memory_object_create, vm_allocate. \ No newline at end of file diff --git a/osfmk/man/bootstrap_arguments.html b/osfmk/man/bootstrap_arguments.html new file mode 100755 index 000000000..0b62fd7f8 --- /dev/null +++ b/osfmk/man/bootstrap_arguments.html @@ -0,0 +1 @@ +

bootstrap_arguments


Function - Return a set of arguments to the bootstrap task.

SYNOPSIS

kern_return_t   bootstrap_arguments
                (mach_port_t                          bootstrap,
                 task_t                                    task,
                 pointer_t                            pointer_t,
                 mach_msg_type_number_t  mach_msg_type_number_t);

PARAMETERS

bootstrap
[in bootstrap send right] The bootstrap port for the task, obtained from task_get_special_ports.

task
[in task send right] The task port for the task whose argument strings are requested.

arguments
[pointer to dynamic out array of characters] The argument strings for the task. This is an array of argumentCnt bytes, containing NUL characters separating the strings.

argumentsCnt
[out pointer to scalar] Number of bytes contained in arguments.

DESCRIPTION

The kernel will respond to the bootstrap task (task 1) with the arguments and environment specified to the boot loader. The bootstrap task can act as a server on this interface for the tasks that it creates in order to pass arguments to them. The libsa_mach.a standalone Mach C runtime startup code uses bootstrap_arguments and bootstrap_environment to initialize argc, argv, and envp for main.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: bootstrap_ports, bootstrap_environment. \ No newline at end of file diff --git a/osfmk/man/bootstrap_completed.html b/osfmk/man/bootstrap_completed.html new file mode 100755 index 000000000..74da3ed71 --- /dev/null +++ b/osfmk/man/bootstrap_completed.html @@ -0,0 +1 @@ +

bootstrap_completed


Server Interface - Inform bootstrap server that initialization is complete.

SYNOPSIS

kern_return_t   bootstrap_completed
                (mach_port_t                     bootstrap_port,
                 task_t                                    task);

PARAMETERS

bootstrap_port
The port representing the calling task's bootstrap server.

task
This parameter represents the calling task.

DESCRIPTION

This interface allows a given server task to inform the bootstrap server that it is fully initialized and ready to handle requests. Upon receiving such notification, the bootstrap server can initialize any additional servers that may require services provided by the previously initialized server.

Note the following: not all servers that may be invoked by the bootstrap server send this message upon startup. If the bootstrap server is told to wait for this message before spawning further servers (via setting a flag in the bootstrap.conf file) and the server just invoked never sends this message, the bootstrap server will wait forever.

NOTES

Currently, this interface is used exclusively by the default pager server so that the bootstrap server can defer initializing the OS server until the default pager is in place. (In small memory configurations, an OS server may not be able to initialize successfully unless the default pager is ready to handle paging requests.)

RETURN VALUES

KERN_SUCCESS
The bootstrap server has updated the calling server's state with respect to bootstrap completion.

KERN_INVALID_ARGUMENT
The bootstrap server does not recognize the calling server (the task specified by the task parameter).

RELATED INFORMATION

Functions: \ No newline at end of file diff --git a/osfmk/man/bootstrap_environment.html b/osfmk/man/bootstrap_environment.html new file mode 100755 index 000000000..1b06e73c7 --- /dev/null +++ b/osfmk/man/bootstrap_environment.html @@ -0,0 +1 @@ +

bootstrap_environment


Function - Return to the bootstrap task an array of strings specifying the task's environment.

SYNOPSIS

kern_return_t   bootstrap_environment
                (mach_port_t                          bootstrap,
                 task_t                                    task,
                 pointer_t                            pointer_t,
                 mach_msg_type_number_t  mach_msg_type_number_t);

PARAMETERS

bootstrap
[in bootstrap send right] The bootstrap port for the task, obtained from task_get_special_ports.

task
[in task send right] The task port for the task whose argument strings are requested.

environment
[pointer to dynamic out array of characters] The environment strings for the task. This is an array of \*V*_environmentCnt_\*O bytes, containing NUL characters separating the strings.

environmentCnt
[out pointer to scalar] Number of bytes contained in _environment_.

DESCRIPTION

The kernel will respond to the bootstrap task (task 1) with the arguments and environment specified to the boot loader. The bootstrap task can act as a server on this interface for the tasks that it creates in order to pass an environment to them. The \*Llibsa_mach.a\*O standalone Mach C runtime startup code uses bootstrap_arguments and bootstrap_environment to initialize argc, argv, and envp for main.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: bootstrap_ports, bootstrap_arguments. \ No newline at end of file diff --git a/osfmk/man/bootstrap_ports.html b/osfmk/man/bootstrap_ports.html new file mode 100755 index 000000000..3d5030e00 --- /dev/null +++ b/osfmk/man/bootstrap_ports.html @@ -0,0 +1 @@ +

bootstrap_ports


Function - Return send rights to the system's control ports.

SYNOPSIS

kern_return_t   bootstrap_ports
                (mach_port_t                          bootstrap,
                 bootstrap                         host_control,
                 host_control                     device_master,
                 device_master                root_wired_ledger,
                 root_wired_ledger            root_paged_ledger,
                 bootstrap                             security);

PARAMETERS

bootstrap
[in bootstrap send right] The bootstrap port obtained from \*Ltask_get_special_ports()\*O.

host_priv
[out host-control send right] The control port for the host.

device_master
[out device-master send right] The device master port.

root_wired_ledger
[out ledger send right] The root wired kernel memory ledger port.

root_paged_ledger
[out ledger send right] The root default memory managed space ledger port.

security
[out security send right] The host security port, used for setting task identity.

DESCRIPTION

The bootstrap_ports function returns a send right to the host control, root ledger, host security and device master ports. The kernel will respond to this message on the TASK_BOOTSTRAP_PORT given to the system bootstrap task (task 1) with the system privileged ports. It is the responsibility of the bootstrap task to manage the distribution of these rights to other servers.

An OS personality can serve as a server on the TASK_BOOTSTRAP_PORT for tasks or servers that it manages, and can regulate or interpose on the ports in any way it deems necessary.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: device_open, host_get_clock_control, host_get_clock_service, host_processor_set_priv, host_processors, ledger_create, task_set_security_token. \ No newline at end of file diff --git a/osfmk/man/catch_exception_raise.html b/osfmk/man/catch_exception_raise.html new file mode 100755 index 000000000..9a1c3b19a --- /dev/null +++ b/osfmk/man/catch_exception_raise.html @@ -0,0 +1 @@ +

catch_exception_raise


Server Interface - Handles the occurrence of an exception within a thread.

SYNOPSIS

kern_return_t   catch_exception_raise
                (mach_port_t                          exception_port,
                 mach_port_t                                  thread,
                 mach_port_t                                    task,
                 exception_type_t                          exception,
                 exception_data_t                               code,
                 mach_msg_type_number_t                   code_count);

catch_exception_raise_state expanded form:

kern_return_t   catch_exception_raise_state
                (mach_port_t                          exception_port,
                 exception_type_t                          exception,
                 exception_data_t                               code,
                 mach_msg_type_number_t                   code_count,
                 int *                                        flavor,
                 thread_state_t                             in_state,
                 mach_msg_type_number_t               in_state_count,
                 thread_state_t                            out_state,
                 mach_msg_type_number_t *            out_state_count);

catch_exception_raise_state_identity expanded form:

kern_return_t   catch_exception_raise_state_identity
                (mach_port_t                          exception_port,
                 mach_port_t                                  thread,
                 mach_port_t                                    task,
                 exception_type_t                          exception,
                 exception_data_t                               code,
                 mach_msg_type_number_t                   code_count,
                 int *                                        flavor,
                 thread_state_t                             in_state,
                 mach_msg_type_number_t               in_state_count,
                 thread_state_t                            out_state,
                 mach_msg_type_number_t *            out_state_count);

PARAMETERS

exception_port
[in exception (receive) right] The port to which the exception notification was sent.

thread
[in thread-self send right] The thread self port for the thread taking the exception.

task
[in task-self send right] The task self port for the task containing the thread taking the exception.

exception
[in scalar] The type of the exception. The machine independent values raised by all implementations are:

EXC_BAD_ACCESS
Could not access memory. subcode contains the bad memory address.

EXC_BAD_INSTRUCTION
Instruction failed. Illegal or undefined instruction or operand.

EXC_ARITHMETIC
Arithmetic exception; exact nature of exception is in subcode field.

EXC_EMULATION
Emulation instruction. Emulation support instruction encountered. Details in subcode field.

EXC_SOFTWARE
Software generated exception; exact exception is in subcode field. Codes 0 - 0xFFFF reserved to hardware; codes 0x10000 - 0x1FFFF reserved for OS emulation.

EXC_BREAKPOINT
Trace, breakpoint, etc. Details in subcode field.

EXC_SYSCALL
System call requested. Details in subcode field.

EXC_MACH_SYSCALL
System call with a number in the Mach call range requested. Details in subcode field.
code
[in scalar] A machine dependent array indicating a particular instance of exception.

code_count
[in scalar] The size of the buffer (in natural-sized units).

flavor
[pointer to in/out scalar] On input, the type of state included as selected when the exception port was set. On output, the type of state being returned.

in_state
[pointer to in structure] State information of the thread at the time of the exception.

in_state_count
[in scalar] The size of the in state buffer (in natural-sized units).

out_state
[out structure] The state the thread will have if continued from the point of the exception. The maximum size of this array is THREAD_STATE_MAX.

out_state_count
[pointer to out scalar] The size of the out state buffer (in natural-sized units).

DESCRIPTION

A catch_exception_raise function is called by exc_server as the result of a kernel message indicating that an exception occurred within a thread. The exception_port parameter specifies the port named via a previous call to thread_set_exception_ports or task_set_exception_ports as the port that responds when the thread takes an exception.

The alternate message forms (the format being selected when the exception port was set) allow for selected thread state to be included.

NOTES

When an exception occurs in a thread, the thread sends an exception message to its exception port, blocking in the kernel waiting for the receipt of a reply. It is assumed that some task is listening (most likely with mach_msg_server) to this port, using the exc_server function to decode the messages and then call the linked in catch_exception_raise. It is the job of catch_exception_raise to handle the exception and decide the course of action for thread.

If the thread should continue from the point of exception, catch_exception_raise would return KERN_SUCCESS. This causes a reply message to be sent to the kernel, which will allow the thread to continue from the point of the exception. If some other action should be taken by thread, the following actions should be performed by catch_exception_raise:

thread_suspend
This keeps the thread from proceeding after the next step.

thread_abort
This aborts the message receive operation currently blocking the thread.

thread_set_state
(if using the catch_exception_raise form). Set the thread's state so that it continues doing something else.

thread_resume
Let the thread start running from its new state.
Returning a value other than KERN_SUCCESS insures that no reply message will be sent. sent. (Actually, the kernel uses a send once right to send the exception message, which thread_abort destroys, so replying to the message is harmless.) The thread can always be destroyed with thread_terminate.

A thread can have two exception ports active for it: its thread type specific exception port and the task type specific exception port. The kernel will try sending an exception message to both ports looking for a reply message with a return value of KERN_SUCCESS. The kernel tries the thread specific port first, then the task specific port. If the return value from the first exception message the kernel sends has a return value of KERN_SUCCESS, the thread continues (with a possibly modified state). If the return value is not KERN_SUCCESS, the kernel tries the second port. If that return value is KERN_SUCCESS, the thread continues; otherwise, the thread is terminated.

To get the effect of a non-success return value, the server interface should return MIG_DESTROY_REQUEST. This causes exc_server and mach_msg_server to destroy the kernel's request (as opposed to sending a reply with a KERN_SUCCESS value).

RETURN VALUES

A return value of KERN_SUCCESS indicates that the thread is to continue from the point of exception. A return value of MIG_NO_REPLY indicates that the exception was handled directly and the thread was restarted or terminated by the exception handler. A return value of MIG_DESTROY_REQUEST causes the kernel to try another exception handler (or terminate the thread). Any other value will cause mach_msg_server to remove the task and thread port references.

RELATED INFORMATION

Functions: exc_server, thread_abort, task_get_exception_ports, thread_get_exception_ports, thread_get_state, thread_resume, task_set_exception_ports, thread_set_exception_ports, task_swap_exception_ports, thread_swap_exception_ports, thread_set_state, thread_suspend, thread_terminate. \ No newline at end of file diff --git a/osfmk/man/clock_alarm.html b/osfmk/man/clock_alarm.html new file mode 100755 index 000000000..0c94b5803 --- /dev/null +++ b/osfmk/man/clock_alarm.html @@ -0,0 +1 @@ +

clock_alarm


Function - Set off an alarm.

SYNOPSIS

kern_return_t   clock_alarm
                (clock_t                             clock_name,
                 alarm_type_t                        alarm_type,
                 tvalspec_t                          alarm_time,
                 mach_port_t                   alarm_reply_port);

PARAMETERS

clock_name
[in clock-name send right] The name (or control) port for the clock.

alarm_type
[in scalar] How to interpret the alarm_time value:

TIME_RELATIVE
Interpret the alarm time as relative to the current time.

TIME_ABSOLUTE
Interpret the alarm time as an absolute time.

alarm_time
[in structure] The time when the alarm is to be sent.

alarm_reply_port
[in alarm receive (to be converted to send-once) right] A port into which the alarm message is to be sent.

DESCRIPTION

The clock_alarm function requests that a clock send an alarm message to a specified port at a given future time. The alarm message is specified by the clock_alarm_reply server interface.

NOTES

If the specified alarm time is in the past, the alarm message is sent immediately and time-stamped with the current time. Otherwise, the alarm is queued and delivered at the specified alarm time and time-stamped at that time.

The alarm will be serviced at the service time nearest the specified alarm time as governed by the current clock alarm resolution.

Not all clocks implement this service, but the REALTIME clock must. If the clock does not provide this service, this call is ignored.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: host_get_clock_service, clock_get_attributes, clock_get_time, clock_sleep, clock_alarm_reply.

Data Structures: tvalspec. \ No newline at end of file diff --git a/osfmk/man/clock_alarm_reply.html b/osfmk/man/clock_alarm_reply.html new file mode 100755 index 000000000..0b951e7c8 --- /dev/null +++ b/osfmk/man/clock_alarm_reply.html @@ -0,0 +1 @@ +

clock_alarm_reply


Function - Ring a preset alarm.

SYNOPSIS

kern_return_t   clock_alarm_reply
                (reply_port_t                  alarm_reply_port,
                 kern_return_t                       reply_code,
                 alarm_type_t                        alarm_type,
                 tvalspec_t                           wake_time);

PARAMETERS

alarm_reply_port
[in alarm (receive) right] The reply port named in the corresponding clock_alarm call.

reply_code
[in scalar] The reply status code from the alarm. The possible values are:

KERN_SUCCESS
The alarm was delivered without problem.

KERN_INVALID_VALUE
The alarm_type and/or alarm_time values supplied to clock_alarm were invalid.

KERN_INVALID_LEDGER
The ledger supplied to clock_alarm was not a ledger.

KERN_ABORTED
The alarm was terminated via use of clock_set_time.

alarm_type
[in scalar] The alarm type value supplied to the clock_alarm call. Only the low order bits of this value are used by the kernel so the high order bits are available for application use as an alarm identifier.

wake_time
[in structure] The time when the alarm message was sent.

DESCRIPTION

A clock_alarm_reply function is called as the result of a message from the kernel indicating that a previously requested alarm time (clock_alarm) has arrived.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: host_get_clock_service, clock_get_attributes, clock_get_time, clock_sleep, clock_alarm, clock_reply_server, clock_set_time.

Data Structures: tvalspec. \ No newline at end of file diff --git a/osfmk/man/clock_get_attributes.html b/osfmk/man/clock_get_attributes.html new file mode 100755 index 000000000..62fecf084 --- /dev/null +++ b/osfmk/man/clock_get_attributes.html @@ -0,0 +1 @@ +

clock_get_attributes


Function - Return attributes of a clock.

SYNOPSIS

kern_return_t   clock_get_attributes
                (clock_t                             clock_name,
                 clock_flavor_t                          flavor,
                 clock_attr_t                         attribute,
                 mach_msg_type_number_t         attribute_count);

PARAMETERS

clock_name
[in clock-name send right] The name (or control) port for the clock.

flavor
[in scalar] Type of information desired. Defined values are:

CLOCK_GET_TIME_RES
The resolution, in nanoseconds, with which the value returned by clock_get_time is updated.

CLOCK_MAP_TIME_RES
The resolution, in nanoseconds, with which the value visible via clock_map_time is updated.

CLOCK_ALARM_CURRES
The resolution, in nanoseconds, at which clock alarm and sleep timers are currently serviced.

CLOCK_ALARM_MINRES
The minimum resolution, in nanoseconds, at which clock alarm and sleep timers can be serviced.

CLOCK_ALARM_MAXRES
The maximum resolution, in nanoseconds, at which clock alarm and sleep timers can be serviced.

attribute
[out scalar] The returned attribute.

attribute_count
[in/out scalar] On input, the maximum size of the buffer; on output, the size returned (in natural-sized units).

DESCRIPTION

The clock_get_attributes function returns attributes of a clock's implementation or operation.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: host_get_clock_service, clock_get_time, clock_map_time, clock_sleep, clock_alarm, clock_set_attributes. \ No newline at end of file diff --git a/osfmk/man/clock_get_time.html b/osfmk/man/clock_get_time.html new file mode 100755 index 000000000..f1329d21f --- /dev/null +++ b/osfmk/man/clock_get_time.html @@ -0,0 +1 @@ +

clock_get_time


Function - Return the current time.

SYNOPSIS

kern_return_t   clock_get_time
                (clock_t                             clock_name,
                 tvalspec_t                            cur_time);

PARAMETERS

clock_name
[in clock-name send right] The name (or control) port for the clock.

cur_time
[out structure] Current time

DESCRIPTION

The clock_get_time function returns the current time kept by a clock. The value returned is a monotonically increasing value (unless tampered with via the clock_set_time function).

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: host_get_clock_service, clock_get_attributes, clock_map_time, clock_sleep, clock_alarm, clock_set_time.

Data Structures: tvalspec. \ No newline at end of file diff --git a/osfmk/man/clock_map_time.html b/osfmk/man/clock_map_time.html new file mode 100755 index 000000000..ce8fa4430 --- /dev/null +++ b/osfmk/man/clock_map_time.html @@ -0,0 +1 @@ +

clock_map_time


Function - Return a memory object that maps a clock.

SYNOPSIS

kern_return_t   clock_map_time
                (clock_t                             clock_name,
                 memory_object_t                   clock_memory);

PARAMETERS

clock_name
[in clock-name send right] The name (or control) port for the clock.

clock_memory
[out memory-object-representative send right] Mapped clock time memory object representative.

DESCRIPTION

The clock_map_time function returns a memory object representative port representing read access to a memory object that contains (at offset zero) a mapped version of the clock time (structure mapped_tvalspec). The returned right is suitable as an argument for vm_map.

NOTES

Not all clocks provide this service, but the REALTIME clock must.

RETURN VALUES

KERN_FAILURE
The specified clock does not provide this service.

RELATED INFORMATION

Functions: host_get_clock_service, clock_get_attributes, clock_get_time, clock_sleep, clock_alarm.

Data Structures: mapped_tvalspec. \ No newline at end of file diff --git a/osfmk/man/clock_reply_server.html b/osfmk/man/clock_reply_server.html new file mode 100755 index 000000000..08599b141 --- /dev/null +++ b/osfmk/man/clock_reply_server.html @@ -0,0 +1 @@ +

clock_reply_server


Function - Handle kernel-generated alarm.

SYNOPSIS

boolean_t	clock_reply_server
		(mach_msg_header_t	request_msg,
		mach_msg_header_t	reply_ms);

PARAMETERS

in_msg
[pointer to in structure] The alarm message received from the kernel.

out_msg
[out structure] Not used.

DESCRIPTION

The clock_reply_server function is the MIG generated server handling function to handle messages from the kernel corresponding to clock alarms. Such messages are delivered to the alarm reply port named in a clock_alarm call. The clock_reply_server function performs all necessary argument handling for this kernel message and calls the appropriate handling function. These functions must be supplied by the caller.

RETURN VALUES

TRUE
The message was handled and the appropriate function was called.

FALSE
The message did not apply to the alarm mechanism and no other action was taken.

RELATED INFORMATION

Functions: clock_alarm_reply. \ No newline at end of file diff --git a/osfmk/man/clock_set_attributes.html b/osfmk/man/clock_set_attributes.html new file mode 100755 index 000000000..ecfec911b --- /dev/null +++ b/osfmk/man/clock_set_attributes.html @@ -0,0 +1 @@ +

clock_set_attributes


Function - Set a particular clock's attributes.

SYNOPSIS

kern_return_t   clock_set_attributes
                (clock_ctrl_t                     clock_control,
                 clock_flavor_t                          flavor,
                 clock_attr_t                         attribute,
                 clock_control                  attribute_count);

PARAMETERS

clock_control
[in clock-control send right] The control port for the clock.

flavor
[in scalar] Type of information to be set. Defined values are:

CLOCK_ALARM_CURRES
The resolution, in nanoseconds, at which clock alarm and sleep timers are currently serviced. Increasing the current resolution will have no impact on any pending clock alarms (i.e. they will go off as originally scheduled). Decreasing the current resolution will truncate any pending alarms to the granularity of the new current resolution. This value must be a multiple of the minimum resolution and not greater than the maximum resolution of the clock.

attribute
[pointer to in scalar] New attribute.

attribute_count
[in scalar] The size of the buffer (in natural-sized units).

DESCRIPTION

The clock_set_attributes function sets attributes of a clock's operation.

NOTES

The main reason a clock's current resolution would not always equal its minimum resolution is because the overhead of sustaining the minimum resolution, when it is not needed by any existing alarm service client, may be prohibitive for a given hardware platform and underlying clock device.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: host_get_clock_control, clock_set_time, clock_get_attributes. \ No newline at end of file diff --git a/osfmk/man/clock_set_time.html b/osfmk/man/clock_set_time.html new file mode 100755 index 000000000..410a83251 --- /dev/null +++ b/osfmk/man/clock_set_time.html @@ -0,0 +1 @@ +

clock_set_time


Function - Set the current time.

SYNOPSIS

kern_return_t   clock_set_time
                (clock_ctrl_t                     clock_control,
                 tvalspec_t                            new_time);

PARAMETERS

clock_control
[in clock-control send right] The control port for the clock.

new_time
[in structure] New time

DESCRIPTION

The clock_set_time function sets the time kept by a clock. Setting the clock time will cause all pending clock alarms and sleeps to be terminated with timestamps set to the current clock time just prior to the new time being set with a return code of KERN_ABORTED.

CAUTIONS

The use of this function is \*Vstrongly discouraged\*O since it could affect the monotonically increasing nature of the clock.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: host_get_clock_control, clock_set_attributes, clock_get_time, clock_alarm, clock_sleep.

Data Structures: tvalspec. \ No newline at end of file diff --git a/osfmk/man/clock_sleep.html b/osfmk/man/clock_sleep.html new file mode 100755 index 000000000..4354f0a3c --- /dev/null +++ b/osfmk/man/clock_sleep.html @@ -0,0 +1 @@ +

clock_sleep


System Trap - Sleep until a given time.

SYNOPSIS

kern_return_t   clock_sleep
                (mach_port_t                         clock_name,
                 sleep_type_t                        sleep_type,
                 tvalspec_t                          sleep_time,
                 clock_name                           wake_time);

PARAMETERS

clock_name
[in clock-name send right] The name (or control) port for the clock.

sleep_type
[in scalar] How to interpret the sleep_time value:

TIME_RELATIVE
Interpret the sleep time as relative to the current time.

TIME_ABSOLUTE
Interpret the sleep time as an absolute time.

sleep_time
[in structure] The time when the sleep is to terminate.

wake_time
[out structure] The actual (absolute) time at which the sleep terminated.

DESCRIPTION

The clock_sleep system trap delays the invoking thread until a specified time. This sleep may be aborted by thread_abort. Not all clocks provide this service but the REALTIME clock must.

If the specified time is in the past, the call returns immediately with the wake time being the current time. If the clock's time is changed (clock_set_time), the sleep will be interrupted. The thread will waken at the service time nearest the specified sleep time as governed by the current clock alarm resolution.

RETURN VALUES

KERN_FAILURE
The clock does not support a sleep service.

KERN_ABORTED
The sleep was interrupted by thread_abort or terminated via use of clock_set_time.

RELATED INFORMATION

Functions: host_get_clock_service, clock_get_attributes, clock_get_time, clock_alarm, clock_set_time, thread_abort,

Data Structures: tvalspec. \ No newline at end of file diff --git a/osfmk/man/default_pager_add_segment.html b/osfmk/man/default_pager_add_segment.html new file mode 100755 index 000000000..ad7028b1a --- /dev/null +++ b/osfmk/man/default_pager_add_segment.html @@ -0,0 +1 @@ +

default_pager_add_segment


Server Interface - Add additional backing storage for a default pager.

SYNOPSIS

#include< mach/default_pager_object.h>

kern_return_t   default_pager_add_segment
                (mach_port_t                      backing_store,
                 mach_port_t                             device,
                 recnum_t                                offset,
                 recnum_t                                 count,
                 int                                record_size);

PARAMETERS

backing_store
[in backing store (receive) right] The backing store port.

device
[in device port] The port for the device containing the backing storage partition.

offset
[in scalar] The offset, in record_size units, to the beginning of the backing storage on the device.

count
[in scalar] The number of record_size units in the partition/segment.

record_size
[in scalar] The size, in bytes, of the storage device record.

DESCRIPTION

The default_pager_add_segment function is called to add a partition to a default pager's backing storage (i.e. expand the amount of backing storage available to a memory manager). The kernel does not make this call itself (which is why it can be a synchronous call); this request is only issued by tasks holding the backing store port, created with default_pager_backing_store_create, for a default memory manager. The result is that the pager may use count records on device starting at offset for paging, and each record is record_size bytes in length (note that the device_* calls are, or can be, record oriented).

RETURN VALUES

KERN_FAILURE
The default pager does not support this operation.

KERN_INVALID_ARGUMENT
The backing_store port does not represent a valid backing store or the specified segment overlaps an existing partition.

KERN_RESOURCE_SHORTAGE
The default pager is unable to allocate internal resources to manage the new backing storage.

KERN_SUCCESS
The operation was successful.

RELATED INFORMATION

Functions: default_pager_backing_store_create, default_pager_backing_store_delete, default_pager_backing_store_info. \ No newline at end of file diff --git a/osfmk/man/default_pager_info.html b/osfmk/man/default_pager_info.html new file mode 100755 index 000000000..70f15d831 --- /dev/null +++ b/osfmk/man/default_pager_info.html @@ -0,0 +1 @@ +

default_pager_info


Server Interface - Furnish caller with information about the pager's paging partition.

SYNOPSIS

kern_return_t   default_pager_info
                (mach_port_t                              pager,
                 default_pager_info_t                      info);


kern_return_t   seqnos_default_pager_info
                (mach_port_t                              pager,
                 mach_port_seqno_t                        seqno,
                 default_pager_info_t                     *info);

PARAMETERS

pager
[in default-pager (receive) right] The default memory manager service port.

seqno
[in scalar] The sequence number of this message relative to the pager port.

info
[out structure] Total and free space consumption.

DESCRIPTION

A default_pager_info function is called as the result of a message requesting that the default memory manager return information concerning the default pager's paging partitions. The kernel does not make this call itself (which is why it can be a synchronous call); this request is only issued by (privileged) tasks holding the default memory manager port.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: vm_set_default_memory_manager, memory_object_default_server, seqnos_memory_object_default_server.

Data Structures: default_pager_info. \ No newline at end of file diff --git a/osfmk/man/device_close.html b/osfmk/man/device_close.html new file mode 100755 index 000000000..570ae7111 --- /dev/null +++ b/osfmk/man/device_close.html @@ -0,0 +1 @@ +

device_close


Function - De-establish a connection to a device.

SYNOPSIS

#include< device/device.h>

kern_return_t	device_close
		(mach_port_t	device);

PARAMETERS

device
[in device send right] A device port to the device to be closed.

DESCRIPTION

The device_close function destroys the associated device port. The open count for the named device is decremented. If this count reaches zero, the close operation of the device driver is invoked, closing the device.

NOTES

device_close will destroy any mapped device windows obtained through this device port.

RETURN VALUES

D_NO_SUCH_DEVICE
No device with that name, or the device is not operational.

RELATED INFORMATION

Functions: device_open. \ No newline at end of file diff --git a/osfmk/man/device_get_status.html b/osfmk/man/device_get_status.html new file mode 100755 index 000000000..6d69a8ab4 --- /dev/null +++ b/osfmk/man/device_get_status.html @@ -0,0 +1 @@ +

device_get_status


Function - Return the current device status.

SYNOPSIS

#include< device/device.h>

kern_return_t   device_get_status
                (mach_port_t                             device,
                 dev_flavor_t                            flavor,
                 dev_status_t                            status,
                 mach_msg_type_number_t           *status_count);

PARAMETERS

device
[in device send right] A device port to the device to be interrogated.

flavor
[in scalar] The type of status information requested.

status
[out array of natural-sized units] The returned device status.

status_count
[pointer to in/out scalar] On input, the reserved size of status; on output, the size of the returned device status (in natural-sized units).

DESCRIPTION

The device_get_status function returns status information pertaining to an open device. The possible values for flavor as well as the meaning of the returned status information is device dependent.

RETURN VALUES

D_DEVICE_DOWN
Device has been shut down

D_NO_SUCH_DEVICE
No device with that name, or the device is not operational.

D_OUT_OF_BAND
Out-of-band condition occurred on device (such as typing \*L-C\*O)

RELATED INFORMATION

Functions: device_set_status. \ No newline at end of file diff --git a/osfmk/man/device_map.html b/osfmk/man/device_map.html new file mode 100755 index 000000000..ebd314198 --- /dev/null +++ b/osfmk/man/device_map.html @@ -0,0 +1 @@ +

device_map


Function - Establish the specified device's memory manager.

SYNOPSIS

#include< device/device.h>

kern_return_t   device_map
                (mach_port_t                             device,
                 vm_prot_t                                 prot,
                 vm_offset_t                             offset,
                 vm_size_t                                 size,
                 mach_port_t                          mem_obj_t,
                 boolean_t                                unmap);

PARAMETERS

device
[in device send right] A device port to the device to be mapped.

prot
[in scalar] Protection for the device memory.

offset
[in scalar] 15~Offset in memory object.

size
[in scalar] The size of the device memory object.

pager
[out memory-object send right] The returned memory object representative port to a memory manager that represents the device.

unmap
Unused.

DESCRIPTION

The device_map function establishes a memory manager that presents a memory object representing a device. The resulting port is suitable for use as the memory manager port in a vm_map call. This call is device dependent.

NOTES

Port rights are maintained as follows:

  • Memory object port: the device memory manager has all rights.
  • Memory cache control port: the device memory manager has only send rights.

Regardless of how the object is created, the control port is created by the kernel and passed through the memory management interface.

If the device port used is restricted to use by a single identity, the generated representative port will be likewise restricted.

CAUTIONS

The device memory manager assumes that access to its memory objects will not be propagated to more that one host, and therefore provides no consistency guarantees beyond those made by the kernel.

In the event that more than one host attempts to use a device memory object, the device memory manager will only record the last set of port names. Currently, the device memory manager assumes that its clients adhere to the initialization and termination protocols in the memory management interface; otherwise, port rights or out-of-line memory from erroneous messages may be allowed to accumulate.

RETURN VALUES

D_DEVICE_DOWN
Device has been shut down

D_NO_SUCH_DEVICE
No device with that name, or the device is not operational.

D_READ_ONLY
Data cannot be written to this device.

RELATED INFORMATION

Functions: vm_map. \ No newline at end of file diff --git a/osfmk/man/device_open.html b/osfmk/man/device_open.html new file mode 100755 index 000000000..3fd4c350e --- /dev/null +++ b/osfmk/man/device_open.html @@ -0,0 +1 @@ +

device_open


Function - Establish a connection to a device.

SYNOPSIS

#include<device/device.h>

kern_return_t   device_open
                (mach_port_t                        master_port,
                 mach_port_t                             ledger,
                 dev_mode_t                                mode,
                 security_token_t                   security_id,
                 dev_name_t                                name,
                 mach_port_t                             device);


#include<device/device_request.h>

kern_return_t   device_open_request
                (mach_port_t                        master_port,
                 mach_port_t                         reply_port,
                 mach_port_t                             ledger,
                 dev_mode_t                                mode,
                 security_token_t                   security_id,
                 dev_name_t                                name);


kern_return_t   ds_device_open_reply
                (mach_port_t                         reply_port,
                 kern_return_t                      return_code,
                 mach_port_t                             device);

PARAMETERS

master_port
[in device-master send right] The master device port. This port is provided to the bootstrap task.

reply_port
[in reply receive (to be converted to send-once) right] The port to which a reply is to be sent when the device is open.

ledger
[pointer to a ledger send right] Resource ledger from which the device will draw its resources.

mode
[in scalar] Opening mode. This is the bit-wise OR of the following values:

D_READ
Read access

D_WRITE
Write access

D_NODELAY
Do not delay on open

security_id
[in scalar] The security ID that tasks attempting to use this device port must have. A zero value indicates all identities.

name
[pointer to in array of char] Name of the device to open.

return_code
[in scalar] Status of the open.

device
[out device send right, in for asynchronous form] The returned device port.

DESCRIPTION

The device_open function opens a device object. The open operation of the device is invoked, if the device is not already open. The open count for the device is incremented. Each open for a device returns a port, the allowed operations upon which being governed by mode. The port is not distinct.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: device_close, device_reply_server. \ No newline at end of file diff --git a/osfmk/man/device_read.html b/osfmk/man/device_read.html new file mode 100755 index 000000000..56d3b776e --- /dev/null +++ b/osfmk/man/device_read.html @@ -0,0 +1 @@ +

device_read


Function - Read a sequence of bytes from a specific device.

SYNOPSIS

#include<device/device.h>

kern_return_t   device_read
                (device_t                                device,
                 mach_port_t                         reply_port,
                 dev_mode_t                                mode,
                 recnum_t                                recnum,
                 io_buf_len_t                      bytes_wanted,
                 io_buf_ptr_t                      io_buf_ptr_t,
                 mach_msg_type_number_t  mach_msg_type_number_t);


#include<device/device_request.h>

kern_return_t   device_read_request
                (mach_port_t                            device,
                 mach_port_t                        reply_port,
                 dev_mode_t                                mode,
                 recnum_t                                recnum,
                 io_buf_len_t                      bytes_wanted);



kern_return_t   ds_device_read_reply
                (mach_port_t                         reply_port,
                 kern_return_t                      return_code,
                 io_buf_ptr_t                              data,
                 mach_msg_type_number_t              data_count);

PARAMETERS

device
[in device send right] A device port to the device to be read.

reply_port
[in reply receive (to be converted to send-once) right] The port to which the reply message is to be sent.

mode
[in scalar] I/O mode value. Meaningful options are:

D_NOWAIT
Do not wait if data is unavailable.

recnum
[in scalar] Record number to be read.

bytes_wanted
[in scalar] Size of data transfer.

return_code
[in scalar] The return status code from the read.

data
[out pointer to dynamic array of bytes, in for asynchronous form] Returned data bytes.

data_count
[out scalar, in for asynchronous form] Number of returned data bytes.

DESCRIPTION

The device_read function reads a sequence of bytes from a device object. The meaning of recnum as well as the specific operation performed is device dependent.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: device_read_inband, device_read_overwrite, device_reply_server. \ No newline at end of file diff --git a/osfmk/man/device_read_async.html b/osfmk/man/device_read_async.html new file mode 100755 index 000000000..bef750fab --- /dev/null +++ b/osfmk/man/device_read_async.html @@ -0,0 +1 @@ +

device_read_async


System Trap - Read a sequence of bytes from a device object.

SYNOPSIS

kern_return_t   device_read_async
                (mach_port_t                             device,
                 mach_port_t                              queue,
                 mach_port_t                         request_id,
                 dev_mode_t                                mode,
                 recnum_t                                recnum,
                 io_buf_len_t                      bytes_wanted);

PARAMETERS

device
[in device send right] A device port to the device to be read.

queue
[in io_done queue send right] The port returned from io_done_queue_create.

request_id
[in send right] An unique request identifier that will be passed back as part of the io_done_result structure.

mode
[in scalar] I/O mode value. Meaningful options are:

D_NOWAIT
Do not wait if data is unavailable.

recnum
[in scalar] Record number to be read.

bytes_wanted
[in scalar] Size of data transfer.

DESCRIPTION

The device_read_async interface enqueues a read operation for a sequence of bytes from a device object. The meaning of recnum as well as the specific operation performed is device dependent.

RETURN VALUES

device_read_async returns only invalid parameter errors.

RELATED INFORMATION

Functions: device_read_async_inband, device_read_overwrite_async, device_write_async, device_write_async_inband, io_done_queue_create. \ No newline at end of file diff --git a/osfmk/man/device_read_async_inband.html b/osfmk/man/device_read_async_inband.html new file mode 100755 index 000000000..13b556b6b --- /dev/null +++ b/osfmk/man/device_read_async_inband.html @@ -0,0 +1 @@ +

device_read_async_inband


System Trap - Read a sequence of bytes "inband" from a device object.

SYNOPSIS

kern_return_t   device_read_async_inband
                (mach_port_t                             device,
                 mach_port_t                              queue,
                 mach_port_t                         request_id,
                 dev_mode_t                                mode,
                 recnum_t                                recnum,
                 io_buf_len_t                      bytes_wanted);

PARAMETERS

device
[in device send right] A device port to the device to be read.

queue
[in io_done queue send right] The port returned from io_done_queue_create.

request_id
[in send right] An unique request identifier that will be passed back as part of the io_done_result structure.

mode
[in scalar] I/O mode value. Meaningful options are:

D_NOWAIT
Do not wait if data is unavailable.

recnum
[in scalar] Record number to be read.

bytes_wanted
[in scalar] Size of data transfer.

DESCRIPTION

The device_read_async_inband function enqueues a read operation for a sequence of bytes from a device object. The meaning of recnum as well as the specific operation performed is device dependent. This call differs from device_read_async in that the returned bytes are returned "inband" in the completion IPC message (in io_done_result.qd_inline).

RETURN VALUES

device_read_async_inband returns only invalid parameter errors.

RELATED INFORMATION

Functions: device_read_async, device_read_overwrite_async, device_write_async, device_write_async_inband, io_done_queue_create. \ No newline at end of file diff --git a/osfmk/man/device_read_inband.html b/osfmk/man/device_read_inband.html new file mode 100755 index 000000000..d7467eef3 --- /dev/null +++ b/osfmk/man/device_read_inband.html @@ -0,0 +1 @@ +

device_read_inband


Function - Read a sequence of bytes "inband" from a device object.

SYNOPSIS

#include<device/device.h>

kern_return_t   device_read_inband
                (mach_port_t                             device,
                 dev_mode_t                                mode,
                 recnum_t                                recnum,
                 io_buf_len_t                      bytes_wanted,
                 io_buf_ptr_inband_t                       data,
                 mach_msg_type_number_t             *data_count);


#include<device/device_request.h>

kern_return_t   device_read_request_inband
                (mach_port_t                             device,
                 mach_port_t                         reply_port,
                 dev_mode_t                                mode,
                 recnum_t                                recnum,
                 io_buf_len_t                      bytes_wanted);


kern_return_t   ds_device_read_reply_inband
                (mach_port_t                         reply_port,
                 kern_return_t                      return_code,
                 io_buf_ptr_inband_t                       data,
                 mach_msg_type_number_t              data_count);

PARAMETERS

device
[in device send right] A device port to the device to be read.

reply_port
[in reply receive (to be converted to send-once) right] The port to which the reply message is to be sent.

mode
[in scalar] I/O mode value. Meaningful options are:

D_NOWAIT
Do not wait if data is unavailable.

recnum
[in scalar] Record number to be read.

bytes_wanted
[in scalar] Size of data transfer.

return_code
[in scalar] The return status code from the read.

data
[out array of bytes, in for asynchronous form] Returned data bytes.

data_count
[out scalar, in for asynchronous form] Number of returned data bytes.

DESCRIPTION

The device_read_inband function reads a sequence of bytes from a device object. The meaning of recnum as well as the specific operation performed is device dependent. This call differs from device_read in that the returned bytes are returned "inband" in the reply IPC message.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: device_read, device_read_overwrite, device_reply_server. \ No newline at end of file diff --git a/osfmk/man/device_read_overwrite.html b/osfmk/man/device_read_overwrite.html new file mode 100755 index 000000000..8551c9144 --- /dev/null +++ b/osfmk/man/device_read_overwrite.html @@ -0,0 +1 @@ +

device_read_overwrite


System Trap -- Read a sequence of bytes from a specific device into my address space.

SYNOPSIS


kern_return_t   device_read_overwrite
                (mach_port_t                               device,
                 dev_mode_t                                mode,
                 recnum_t                                recnum,
                 io_buf_len_t                      bytes_wanted,
                 io_buf_pointer_t                          data,
                 mach_msg_type_number_t              data_count);



kern_return_t   device_read_overwrite_request
                (mach_port_t                             device,
                 mach_port_t                         reply_port,
                 dev_mode_t                                mode,
                 recnum_t                                recnum,
                 io_buf_len_t                      bytes_wanted,
                 io_buf_pointer_t                          data);



kern_return_t   ds_device_read_reply_overwrite
                (mach_port_t                        reply_port,
                 kern_return_t                      return_code,
                 io_buf_len_t                        data_count);

PARAMETERS

device
[in device send right] A device port to the device to be read.

reply_port
[in reply receive (to be converted to send-once) right] The port to which the reply message is to be sent.

mode
[in scalar] I/O mode value. Meaningful options are:

D_NOWAIT
Do not wait if data is unavailable.

recnum
[in scalar] Record number to be read.

bytes_wanted
[in scalar] Size of data transfer.

return_code
[in scalar] The return status code from the read.

data
[pointer to in array of bytes] Data buffer to be overwritten.

data_count
[out scalar, in for asynchronous form] Number of returned data bytes.

DESCRIPTION

The device_read_overwrite system trap reads a sequence of bytes from a device object directly into the caller's address space. The meaning of recnum as well as the specific operation performed is device dependent.

NOTES

The device_read_overwrite_request and device_read_reply_overwrite calls may be removed from the interface in favor of new asynchronous support.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: device_read, device_read_inband, device_reply_server. \ No newline at end of file diff --git a/osfmk/man/device_reply_server.html b/osfmk/man/device_reply_server.html new file mode 100755 index 000000000..344b45bc2 --- /dev/null +++ b/osfmk/man/device_reply_server.html @@ -0,0 +1 @@ +

device_reply_server


Function - Handle incoming data from kernel device driver.

SYNOPSIS

boolean_t	device_reply_server
		(mach_msg_header_t	request_msg,
		mach_msg_header_t	reply_msg);

PARAMETERS

request_msg
[pointer to in structure] The device driver message received from the kernel.

reply_msg
[out structure] A reply message. No messages from a device driver expect a direct reply, so this field is not used.

DESCRIPTION

The device_reply_server function is the MIG generated server handling function to handle messages from kernel device drivers. Such messages were sent in response to the various device_..._request... calls. It is assumed when using those calls that some task is listening for reply messages on the port named as a reply port to those calls. The device_reply_server function performs all necessary argument handling for a kernel message and calls one of the device server functions to interpret the message.

RETURN VALUES

TRUE
The message was handled and the appropriate function was called.

FALSE
The message did not apply to this device handler interface and no other action was taken.

RELATED INFORMATION

Functions: ds_device_open_reply, ds_device_write_reply, ds_device_write_reply_inband, ds_device_read_reply, ds_device_read_reply_inband, ds_device_read_reply_overwrite. \ No newline at end of file diff --git a/osfmk/man/device_set_filter.html b/osfmk/man/device_set_filter.html new file mode 100755 index 000000000..1f3ff8245 --- /dev/null +++ b/osfmk/man/device_set_filter.html @@ -0,0 +1 @@ +

device_set_filter


Function - Name an input filter for a device.

SYNOPSIS

#include< device/device.h>
#include< device/net_status.h>

kern_return_t   device_set_filter
                (mach_port_t                             device,
                 mach_port_t                       receive_port,
                 mach_msg_type_name_t         receive_port_type,
                 int                                   priority,
                 filter_array_t                          filter,
                 mach_msg_type_number_t             filter_count);

PARAMETERS

device
[in device send right] A device port

receive_port
[in filter send or receive (to be converted to send) right] The port to receive the input data that is selected by the filter.

receive_port_type
[in scalar] IPC type of the send right provided to the device; either MACH_MSG_TYPE_MAKE_SEND, MACH_MSG_TYPE_MOVE_SEND, or MACH_MSG_TYPE_COPY_SEND.

priority
[in scalar] Used to order multiple receivers in an implementation dependent way.

filter
[pointer to in array of filter_t] The address of an array of filter values.

filter_count
[in scalar] The size of the filter array (in 16-bit values).

DESCRIPTION

The device_set_filter function provides a means by which selected data appearing at a device interface can be selected and routed to a port. This service is provided in support of network devices.

The filter command list consists of an array of up to NET_MAX_FILTER (16-bit) values to be applied to incoming data "messages" to determine if that data should be given to a particular input filter.

Each filter command list specifies a sequence of actions which leave a boolean value on the top of an internal stack. Each 16-bit value of the command list specifies a data (push) operation (high order NETF_NBPO bits) as well as a binary operator (low order NETF_NBPA bits).

The value to be pushed onto the stack is chosen as follows:

NETF_PUSHLIT
Use the next 16-bit value of the filter as the value.
NETF_PUSHZERO
Use 0 as the value.
NETF_PUSHWORD+N
Use 16-bit value N of the "data" portion of the message as the value.
NETF_PUSHHDR+N
Use 16-bit value N of the "header" portion of the message as the value.
NETF_PUSHIND
Pops the top 32-bit value from the stack and then uses it to index the 16-bit value of the "data" portion of the message to be used as the value.
NETF_PUSHHDRIND
Pops the top 32-bit value from the stack and then uses it to index the 16-bit value of the "header" portion of the message to be used as the value.
NETF_PUSHSTK+N
Use 32-bit value N of the stack (where the top of stack is value 0) as the value.
NETF_NOPUSH
Don't push a value.
The unsigned value so chosen is promoted to a 32-bit value before being pushed.

Once a value is pushed (except for the case of NETF_NOPUSH), the top two 32-bit values of the stack are popped and a binary operator applied to them (with the old top of stack as the second operand). The result of the operator is pushed on the stack. These operators are:

NETF_NOP
Don't pop off any values and do no operation.
NETF_EQ
Perform an equal comparison.
NETF_LT
Perform a less than comparison.
NETF_LE
Perform a less than or equal comparison.
NETF_GT
Perform a greater than comparison.
NETF_GE
Perform a greater than or equal comparison.
NETF_AND
Perform a bit-wise boolean AND operation.
NETF_OR
Perform a bit-wise boolean inclusive OR operation.
NETF_XOR
Perform a bit-wise boolean exclusive OR operation.
NETF_NEQ
Perform a not equal comparison.
NETF_LSH
Perform a left shift operation.
NETF_RSH
Perform a right shift operation.
NETF_ADD
Perform an addition.
NETF_SUB
Perform a subtraction.
NETF_COR
Perform an equal comparison. If the comparison is TRUE, terminate the filter list. Otherwise, pop the result of the comparison off the stack.
NETF_CAND
Perform an equal comparison. If the comparison is FALSE, terminate the filter list. Otherwise, pop the result of the comparison off the stack.
NETF_CNOR
Perform a not equal comparison. If the comparison is FALSE, terminate the filter list. Otherwise, pop the result of the comparison off the stack.
NETF_CNAND
Perform a not equal comparison. If the comparison is TRUE, terminate the filter list. Otherwise, pop the result of the comparison off the stack.
The scan of the filter list terminates when the filter list is emptied, or a NETF_C operation terminates the list. At this time, if the final value of the top of the stack is TRUE, then the message is accepted for the filter.

RETURN VALUES

D_DEVICE_DOWN
Device has been shut down

D_INVALID_OPERATION
No filter port was supplied.

D_NO_SUCH_DEVICE
No device with that name, or the device is not operational.

RELATED INFORMATION

Currently no references. \ No newline at end of file diff --git a/osfmk/man/device_set_status.html b/osfmk/man/device_set_status.html new file mode 100755 index 000000000..a55a2347a --- /dev/null +++ b/osfmk/man/device_set_status.html @@ -0,0 +1 @@ +

device_set_status


Function - Set device status.

SYNOPSIS

#include< device/device.h>

kern_return_t   device_set_status
                (mach_port_t                             device,
                 dev_flavor_t                            flavor,
                 dev_status_t                            status,
                 mach_msg_type_number_t            status_count);

PARAMETERS

device
[in device send right] A device port to the device to be manipulated.

flavor
[in scalar] The type of status information to set.

status
[pointer to in array of natural-sized units] The status information to set.

status_count
[in scalar] The size of the status information (in natural-sized units).

DESCRIPTION

The device_set_status function sets device status. The possible values of flavor as well as the corresponding meanings are device dependent.

RETURN VALUES

D_DEVICE_DOWN
Device has been shut down

D_IO_ERROR
Hardware I/O error

D_NO_SUCH_DEVICE
No device with that name, or the device is not operational.

D_OUT_OF_BAND
Out-of-band condition occurred on device (such as typing <Ctrl>-C).

D_READ_ONLY
Data cannot be written to this device.

RELATED INFORMATION

Functions: device_get_status. \ No newline at end of file diff --git a/osfmk/man/device_write.html b/osfmk/man/device_write.html new file mode 100755 index 000000000..20007edd7 --- /dev/null +++ b/osfmk/man/device_write.html @@ -0,0 +1 @@ +

device_write


Function - Write a sequence of bytes to a specific device.

SYNOPSIS

#include<device/device.h>

kern_return_t   device_write
                (device_t                                device,
                 mach_port_t                         reply_port,
                 dev_mode_t                                mode,
                 recnum_t                                recnum,
                 io_buf_ptr_t                              data,
                 mach_msg_type_number_t              data_count,
                 io_buf_len_t                      io_buf_len_t);


#include<device/device_request.h>

kern_return_t   device_write_request
                (mach_port_t                             device,
                 mach_port_t                         reply_port,
                 dev_mode_t                                mode,
                 recnum_t                                recnum,
                 io_buf_ptr_t                              data,
                 mach_msg_type_number_t              data_count);


kern_return_t   ds_device_write_reply
                (mach_port_t                         reply_port,
                 kern_return_t                      return_code,
                 io_buf_len_t                     bytes_written);

PARAMETERS

device
[in device send right] A device port to the device to be written.

reply_port
[in reply receive (to be converted to send-once) right] The port to which the reply message is to be sent.

mode
[in scalar] I/O mode value. Meaningful options are:

D_NOWAIT
Do not wait for I/O completion.

recnum
[in scalar] Record number to be written.

data
[pointer to in array of bytes] Data bytes to be written.

data_count
[in scalar] Number of data bytes to be written.

return_code
[in scalar] The return status code from the write.

bytes_written
[out scalar, in for asynchronous form] Size of data transfer.

DESCRIPTION

The device_write function writes a sequence of bytes to a device object. The meaning of recnum as well as the specific operation performed is device dependent.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: device_write_inband, device_reply_server. \ No newline at end of file diff --git a/osfmk/man/device_write_async.html b/osfmk/man/device_write_async.html new file mode 100755 index 000000000..84b077dca --- /dev/null +++ b/osfmk/man/device_write_async.html @@ -0,0 +1 @@ +

device_write_async


System Trap - Write a sequence of bytes to a device object.

SYNOPSIS

kern_return_t   device_write_async
                (mach_port_t                             device,
                 mach_port_t                              queue,
                 mach_port_t                         request_id,
                 dev_mode_t                                mode,
                 recnum_t                                recnum,
                 io_buf_ptr_t                              data,
                 io_buf_len_t                      bytes_wanted);

PARAMETERS

device
[in device send right] A device port to the device to be read.

queue
[in io_done queue send right] The port returned from io_done_queue_create.

request_id
[in send right] An unique request identifier that will be passed back as part of the io_done_result structure.

mode
[in scalar] I/O mode value. Meaningful options are:

D_NOWAIT
Do not wait if data is unavailable.

recnum
[in scalar] Record number to be read.

data
[pointer to in array of bytes] Data bytes to be written.

bytes_wanted
[in scalar] Size of data transfer.

DESCRIPTION

The device_write_async function enqueues a write operation for a sequence of bytes to a device object. The meaning of recnum as well as the specific operation performed is device dependent.

RETURN VALUES

device_write_async returns only invalid parameter errors.

RELATED INFORMATION

Functions: device_read_async_inband, device_read_overwrite_async, device_write_async_inband, io_done_queue_create. \ No newline at end of file diff --git a/osfmk/man/device_write_async_inband.html b/osfmk/man/device_write_async_inband.html new file mode 100755 index 000000000..ff119ba66 --- /dev/null +++ b/osfmk/man/device_write_async_inband.html @@ -0,0 +1 @@ +

device_write_async_inband


System Trap - Write a sequence of bytes "inband" to a device object.

SYNOPSIS

kern_return_t   device_write_async_inband
                (mach_port_t                             device,
                 mach_port_t                              queue,
                 mach_port_t                         request_id,
                 dev_mode_t                                mode,
                 recnum_t                                recnum,
                 io_buf_ptr_t                              data,
                 io_buf_len_t                      bytes_wanted);

PARAMETERS

device
[in device send right] A device port to the device to be read.

queue
[in io_done queue send right] The port returned from io_done_queue_create.

request_id
[in send right] An unique request identifier that will be passed back as part of the io_done_result structure.

mode
[in scalar] I/O mode value. Meaningful options are:

D_NOWAIT
Do not wait if data is unavailable.

recnum
[in scalar] Record number to be read.

data
[pointer to in array of bytes] Data bytes to be written.

bytes_wanted
[in scalar] Size of data transfer.

DESCRIPTION

The device_write_async_inband function enqueues a write operation for a sequence of bytes to a device object. The meaning of recnum as well as the specific operation performed is device dependent. This call differs from device_write_async in that the bytes to be written are sent "inband" in the request IPC message.

RETURN VALUES

device_write_async_inband returns only invalid parameter errors.

RELATED INFORMATION

Functions: device_read_async_inband, device_read_overwrite_async, device_write_async, io_done_queue_create. \ No newline at end of file diff --git a/osfmk/man/device_write_inband.html b/osfmk/man/device_write_inband.html new file mode 100755 index 000000000..f7ff44b2f --- /dev/null +++ b/osfmk/man/device_write_inband.html @@ -0,0 +1 @@ +

device_write_inband


Function - Write a sequence of bytes "inband" to a device object.

SYNOPSIS

#include<device/device.h (device_write_inband)>

kern_return_t   device_write_inband
                (mach_port_t                             device,
                 dev_mode_t                                mode,
                 recnum_t                                recnum,
                 io_buf_ptr_inband_t                       data,
                 mach_msg_type_number_t              data_count,
                 io_buf_len_t                      io_buf_len_t);


#include<device/device_request.h>

kern_return_t   device_write_request_inband
                (mach_port_t                             device,
                 mach_port_t                         reply_port,
                 dev_mode_t                                mode,
                 recnum_t                                recnum,
                 io_buf_ptr_inband_t                       data,
                 mach_msg_type_number_t              data_count);


kern_return_t   ds_device_write_reply_inband
                (mach_port_t                         reply_port,
                 kern_return_t                      return_code,
                 io_buf_len_t                      bytes_writte);

PARAMETERS

device
[in device send right] A device port to the device to be written.

reply_port
[in reply receive (to be converted to send-once) right] The port to which the reply message is to be sent.

mode
[in scalar] I/O mode value. Meaningful options are:

D_NOWAIT
Do not wait for I/O completion.

recnum
[in scalar] Record number to be written.

data
[pointer to in array of bytes] Data bytes to be written.

data_count
[in scalar] Number of data bytes to be written.

return_code
[in scalar] The return status code from the write.

bytes_written
[out scalar, in for asynchronous form] Size of data transfer.

DESCRIPTION

The device_write_inband function writes a sequence of bytes to a device object. The meaning of recnum as well as the specific operation performed is device dependent. This call differs from device_write in that the bytes to be written are sent "inband" in the request IPC message.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: device_write, device_reply_server. \ No newline at end of file diff --git a/osfmk/man/do_mach_notify_dead_name.html b/osfmk/man/do_mach_notify_dead_name.html new file mode 100755 index 000000000..ffc3c74f4 --- /dev/null +++ b/osfmk/man/do_mach_notify_dead_name.html @@ -0,0 +1 @@ +

do_mach_notify_dead_name


Server Interface - Handle the current instance of a dead-name notification.

SYNOPSIS

kern_return_t   do_mach_notify_dead_name
                (notify_port_t                           notify,
                 mach_port_name_t                          name);


kern_return_t   do_seqnos_mach_notify_dead_name
                (notify_port_t                           notify,
                 mach_port_seqno_t                        seqno,
                 mach_port_name_t                          name);

PARAMETERS

notify
[in notify (receive) right] The port to which the notification was sent.

seqno
[in scalar] The sequence number of this message relative to the notification port.

name
[in scalar] The dead name.

DESCRIPTION

A do_mach_notify_dead_name function is called by notify_server as the result of a kernel message indicating that the port name is now dead as the result of the associated receive right having died. In contrast, a port-deleted notification indicates that the port name is no longer usable (that is, it no longer names a valid right), typically as a result of the right so named being consumed or moved. notify is the port named via mach_port_request_notification or mach_msg.

NOTES

This interface is machine word length specific because of the port name parameter.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: notify_server, seqnos_notify_server, mach_msg, mach_port_request_notification, do_mach_notify_no_senders, do_mach_notify_port_deleted, do_mach_notify_send_once. \ No newline at end of file diff --git a/osfmk/man/do_mach_notify_no_senders.html b/osfmk/man/do_mach_notify_no_senders.html new file mode 100755 index 000000000..cf19bea13 --- /dev/null +++ b/osfmk/man/do_mach_notify_no_senders.html @@ -0,0 +1 @@ +

do_mach_notify_no_senders


Server Interface - Handle the current instance of a no-more-senders notification.

SYNOPSIS

kern_return_t   do_mach_notify_no_senders
                (notify_port_t                           notify,
                 mach_port_mscount_t                    mscount);


kern_return_t   do_seqnos_mach_notify_no_senders
                (notify_port_t                           notify,
                 mach_port_seqno_t                        seqno,
                 mach_port_mscount_t                    mscount);

PARAMETERS

notify
[in notify (receive) right] The port to which the notification was sent.

seqno
[in scalar] The sequence number of this message relative to the notification port.

mscount
[in scalar] The value the port's make-send count had when the notification was generated.

DESCRIPTION

A do_mach_notify_no_senders function is called by notify_server as the result of a kernel message indicating that a receive right has no more senders. notify is the port named via mach_port_request_notification.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: notify_server, seqnos_notify_server, mach_msg, mach_port_request_notification, do_mach_notify_dead_name, do_mach_notify_port_deleted, do_mach_notify_send_once. \ No newline at end of file diff --git a/osfmk/man/do_mach_notify_send_once.html b/osfmk/man/do_mach_notify_send_once.html new file mode 100755 index 000000000..d5a8242f0 --- /dev/null +++ b/osfmk/man/do_mach_notify_send_once.html @@ -0,0 +1 @@ +

do_mach_notify_send_once


Server Interface - Handle the current instance of a send-once notification.

SYNOPSIS

kern_return_t   do_mach_notify_send_once
                (notify_port_t                          notify)


kern_return_t   do_seqnos_mach_notify_send_once
                (notify_port_t                           notify,
                 mach_port_seqno_t                        seqno);

PARAMETERS

notify
[in notify (receive) right] The port to which the notification was sent.

seqno
[in scalar] The sequence number of this message relative to the notification port.

DESCRIPTION

A do_mach_notify_send_once function is called by notify_server as the result of a kernel message indicating that a send-once right was in any way destroyed. notify is the port for which a send-once right was destroyed.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: notify_server, seqnos_notify_server, mach_msg, mach_port_request_notification, do_mach_notify_no_senders, do_mach_notify_port_deleted, do_mach_notify_dead_name. \ No newline at end of file diff --git a/osfmk/man/etap_get_info.html b/osfmk/man/etap_get_info.html new file mode 100755 index 000000000..0814833ae --- /dev/null +++ b/osfmk/man/etap_get_info.html @@ -0,0 +1 @@ +

etap_get_info


Function - Map ETAP buffers and tables into server's address space.

SYNOPSIS

#include<mach/etap.h>

kern_return_t   etap_get_info
                (host_priv_t                          priv_port,
                 int                                        int,
                 int                                        int,
                 vm_offset_t                        vm_offset_t,
                 vm_offset_t                        vm_offset_t,
                 int                                        int,
                 int                                        int,
                 int                                        int,
                 int                                        int);

PARAMETERS

priv_port
the name of the Server's privileged device port (server_device_port), granting the Server access to this service.

et_entries
used to return number of entries in the event table.

st_entries
used to return number of entries in the subsystem table.

et_offset
used to return the event table's page offset.

st_offset
used to return the subsystem table's page offset.

cb_width
returns the current cumulative buffer interval width.

mb_size
returns the size of the monitored buffers,

mb_entries
returns the maximum number of entries in a monitored buffer.

mb_cpus
returns the number of allocated monitored buffers (or supported CPUs).

DESCRIPTION

The etap_get_info interface provides the user space etap server or daemon with configuration and location information pertaining to the kernel's internal ETAP buffers; this information enables the caller to properly map the ETAP buffers and tables into its address space. When mapping is successfully completed, the Server displays the ETAP configuration on the console. The configuration output will resemble the following:

    ETAP configuration [ee:108 se:8 eo:a60 so:acc cw:0 ms:1008008 me:36 mc:1]
    ETAP event table mapped
    ETAP subsystem table mapped
    ETAP monitored buffer #0 mapped

The values between the brackets correspond with the arguments returned by the etap_get_info call (listed above). For example, "ee:108" indicates that the event table contains 108 ETAP event types and "mc:1" indicates that one monitored buffer has been allocated.

RETURN VALUES

KERN_SUCCESS
The call was performed successfully.

RELATED INFORMATION

Functions: etap_probe, etap_trace_thread, etap_trace_event, etap_get_info. \ No newline at end of file diff --git a/osfmk/man/etap_probe.html b/osfmk/man/etap_probe.html new file mode 100755 index 000000000..9d105f15b --- /dev/null +++ b/osfmk/man/etap_probe.html @@ -0,0 +1 @@ +

etap_probe


System Trap - Record event data in the kernel's ETAP buffer(s).

SYNOPSIS

#include<mach/etap.h>

kern_return_t   etap_probe
                (int                                   event_id,
                 event_id                             data_size,
                 etap_data_t                        etap_data_t);

PARAMETERS

event_id
A user defined value used to identify the event.

data_size
The size (in bytes) of the data being passed. Note: The data size is limited to ETAP_DATA_SIZE, (defined in mach/etap.h).

data
A pointer to the event data being passed.

DESCRIPTION

Application programmers may instrument their applications with user-level probes, using the etap_probe system call. All event data passed to the kernel via etap_probe is recorded in the kernel's ETAP monitored buffer(s). Each record includes a time stamp.

RETURN VALUES

KERN_SUCCESS
The call was performed successfully.

KERN_INVALID_ARGUMENT
The specified data size exceeds ETAP_DATA_SIZE.

KERN_NO_ACCESS
The tracing of user events is currently enabled.

KERN_FAILURE
ETAP is not configured in the kernel.

RELATED INFORMATION

Functions: etap_trace_thread, etap_trace_event, etap_get_info. \ No newline at end of file diff --git a/osfmk/man/etap_trace_event.html b/osfmk/man/etap_trace_event.html new file mode 100755 index 000000000..46f16dc25 --- /dev/null +++ b/osfmk/man/etap_trace_event.html @@ -0,0 +1 @@ +

etap_trace_event


System Trap - manipulate event probes and lock event tracing.

SYNOPSIS

#include<mach/etap.h>

kern_return_t   etap_trace_event
                (etap_data_t                               mode,
                 mode                                      type,
                 boolean_t                               enable,
                 enable                                   nargs,
                 mode                                      mode);

PARAMETERS

mode
indicates the desired trace flavor or reset option and may be one, or more, of the following:

  • ETAP_CUMULATIVE: cumulative lock event trace mode.

  • ETAP_MONITORED: monitored event trace mode (for probes or locks)

  • ETAP_RESET: reset mode, clears all trace status and cumulative buffer entries

type
used when measuring lock event contention or durations and may be one, or more, of the following:

  • ETAP_CONTENT

  • ETAP_DURATION

enable
a boolean value indicattin whether the event trace operation is to be enabled (TRUE) or disabled (FALSE).

nargs
specifies how many arguments are passed in the args array.

args
an array, each element of which is a character string representing a specific subsystem or event type. These values must correspond to the ones the kernel uses to represent the same subsystems and event types. The maximum length of a character string is EVENT_NAME_LENGTH (defined in mach/etap.h).

DESCRIPTION

The etap_trace_event system call is used to enable and disable kernel event probes (of a specified type) and all modes of lock event tracing. The call also supports a reset option, where the cumulative buffer data and all event type tracing is reset to zero. When the reset option is used, a new interval width can also be defined, using the nargs parameter.

To reset the ETAP instrumentation, the system call would utilize the mode parameter, passing the value of ETAP_RESET (All other parameters may equal NULL). If, at the time of reset, the nargs parameter is assigned a value, then the cumulative buffer interval width will be adjusted to be the size of that value. For example, the following system call would reset the ETAP instrumentation and adjust the cumulative buffer's interval width to 100ms:

         etap_trace_event(ETAP_RESET, 0, 0, 100, 0);

RETURN VALUES

KERN_SUCCESS
The call was performed successfully.

KERN_NO_SPACE
A shortage of kernel resources prevented the operation from completing; the kernel has cleaned up all residual state (the error indicates a "clean" failure).

KERN_FAILURE
ETAP is not configured in the kernel.

RELATED INFORMATION

Functions: etap_probe, etap_trace_thread, etap_get_info. \ No newline at end of file diff --git a/osfmk/man/etap_trace_thread.html b/osfmk/man/etap_trace_thread.html new file mode 100755 index 000000000..2a5b356f9 --- /dev/null +++ b/osfmk/man/etap_trace_thread.html @@ -0,0 +1 @@ +

etap_trace_thread


Function - Set a thread's ETAP trace status.

SYNOPSIS

#include<mach/etap.h>

kern_return_t   etap_trace_thread
                (thread_act_t                     target_thread,
                 boolean_t                               active);

PARAMETERS

target_thread
The port of the thread who's ETAP trace status will be toggled.

active
The boolean value (either TRUE or FALSE) stating whether the thread's ETAP trace status will be activated or not. Passing TRUE will enable the thread's trace status and FALSE will deactivate it.

DESCRIPTION

The etap_trace_thread system call is used to toggle the ETAP trace status of a thread.

RETURN VALUES

KERN_SUCCESS
The call was performed successfully.

KERN_INVALID_ARGUMENT
The value of target_thread does not name a valid thread.

KERN_FAILURE
ETAP is not configured in the kernel.

RELATED INFORMATION

Functions: etap_probe, etap_trace_event, etap_get_info. \ No newline at end of file diff --git a/osfmk/man/evc_wait.html b/osfmk/man/evc_wait.html new file mode 100755 index 000000000..18fe88d58 --- /dev/null +++ b/osfmk/man/evc_wait.html @@ -0,0 +1 @@ +

evc_wait


System Trap - Wait for a kernel (device) signalled event.

SYNOPSIS

kern_return_t	evc_wait
		(unsigned int	event);

PARAMETERS

event
[in scalar] The task local event ID of the kernel event object.

DESCRIPTION

The evc_wait function causes the invoking thread to wait until the specified kernel (device) generated event occurs. Device drivers (typically mapped devices intended to be supported by user space drivers) may supply an event service. The event service defines one or more event objects, named by task local event IDs. Each of these event objects has an associated event count, initially zero. Whenever the associated event occurs (typically a device interrupt), the event count is incremented. If this count is zero when evc_wait is called, the calling thread waits for the next event to occur. Only one thread may be waiting for the event to occur. If the count is non-zero when evc_wait is called, the count is simply decremented without causing the thread to wait. The event count guarantees that no events are lost.

NOTES

The typical use of this service is within user space device drivers. When a device interrupt occurs, the (in this case, simple) kernel device driver would place device status in a shared (with the user device driver) memory window (established by device_map) and signal the associated event. The user space device driver would normally be waiting with evc_wait. The user thread then wakes, processes the device status, typically interacting with the device via its shared memory window, then waits for the next interrupt.

RETURN VALUES

KERN_NO_SPACE
There is already a thread waiting for this event.

RELATED INFORMATION

Functions: device_map. \ No newline at end of file diff --git a/osfmk/man/exc_server.html b/osfmk/man/exc_server.html new file mode 100755 index 000000000..3bc56b110 --- /dev/null +++ b/osfmk/man/exc_server.html @@ -0,0 +1 @@ +

exc_server


Function - Handle kernel-reported thread exception.

SYNOPSIS

boolean_t	exc_server
		(mach_msg_header_t	request_msg,
		mach_msg_header_t	reply_ms);

PARAMETERS

in_msg
[pointer to in structure] The exception message received from the kernel.

out_msg
[out structure] A reply message.

DESCRIPTION

The exc_server function is the MIG generated server handling function to handle messages from the kernel relating to the occurrence of an exception in a thread. Such messages are delivered to the exception port set via thread_set_exception_ports or task_set_exception_ports. When an exception occurs in a thread, the thread sends an exception message to its exception port, blocking in the kernel waiting for the receipt of a reply. The exc_server function performs all necessary argument handling for this kernel message and calls catch_exception_raise, catch_exception_raise_state or catch_exception_raise_state_identity, which should handle the exception. If the called routine returns KERN_SUCCESS, a reply message will be sent, allowing the thread to continue from the point of the exception; otherwise, no reply message is sent and the called routine must have dealt with the exception thread directly.

RETURN VALUES

TRUE
The message was handled and the appropriate function was called.

FALSE
The message did not apply to the exception mechanism and no other action was taken.

RELATED INFORMATION

Functions: catch_exception_raise. \ No newline at end of file diff --git a/osfmk/man/host_adjust_time.html b/osfmk/man/host_adjust_time.html new file mode 100755 index 000000000..8912859af --- /dev/null +++ b/osfmk/man/host_adjust_time.html @@ -0,0 +1 @@ +

host_adjust_time


Function - Gradually change the time.

SYNOPSIS

#include< mach/mach_host.h>

kern_return_t   host_adjust_time
                (host_priv_t                          host_priv,
                 time_value_t                    new_adjustment,
                 time_value_t                    old_adjustment);

PARAMETERS

host_priv
[in host-control port] The control port the host for which the time is to be set.

new_adjustment
[in structure] New adjustment value.

old_adjustment
[out structure] Old adjustment value.

DESCRIPTION

The host_adjust_time function arranges for the time on a specified host to be gradually changed by an adjustment value.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: host_get_time, host_set_time.

Data Structures: time_value. \ No newline at end of file diff --git a/osfmk/man/host_basic_info.html b/osfmk/man/host_basic_info.html new file mode 100755 index 000000000..0e359f0f2 --- /dev/null +++ b/osfmk/man/host_basic_info.html @@ -0,0 +1 @@ +

host_basic_info


Structure - Used to present basic information about a host.

SYNOPSIS

struct host_basic_info
{
       integer_t            max_cpus;
       integer_t          avail_cpus;
       vm_size_t         memory_size;
       cpu_type_t           cpu_type;
       cpu_subtype_t     cpu_subtype;
};

typedef struct host_basic_info* host_basic_info_t;

FIELDS

max_cpus
Maximum possible CPUs for which kernel is configured

avail_cpus
Number of CPUs now available

memory_size
Size of memory, in bytes

cpu_type
CPU type

cpu_subtype
CPU sub-type

DESCRIPTION

The host_basic_info structure defines the basic information available about a host.

NOTES

This structure is machine word length specific because of the memory size returned.

RELATED INFORMATION

Functions: host_info.

Data Structures: host_load_info, host_sched_info. \ No newline at end of file diff --git a/osfmk/man/host_get_boot_info.html b/osfmk/man/host_get_boot_info.html new file mode 100755 index 000000000..e86db863d --- /dev/null +++ b/osfmk/man/host_get_boot_info.html @@ -0,0 +1 @@ +

host_get_boot_info


Function - Return operator boot information.

SYNOPSIS

kern_return_t   host_get_boot_info
                (host_priv_t                          priv_host,
                 kernel_boot_info_t                   boot_info);

PARAMETERS

priv_host
[in host-control send right] The control port for the host for which information is to be obtained.

boot_info
[out array of char] Character string providing the operator boot info

DESCRIPTION

The host_get_boot_info function returns the boot-time information string supplied by the operator when priv_host was initialized. The constant KERNEL_BOOT_INFO_MAX (in \*L\*O) should be used to dimension storage for the returned string.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: host_info. \ No newline at end of file diff --git a/osfmk/man/host_get_clock_control.html b/osfmk/man/host_get_clock_control.html new file mode 100755 index 000000000..4d47043bb --- /dev/null +++ b/osfmk/man/host_get_clock_control.html @@ -0,0 +1 @@ +

host_get_clock_control


Function - Return a send right to a kernel clock's control port.

SYNOPSIS

kern_return_t   host_get_clock_control
                (host_priv_t                          host_priv,
                 clock_id_t                                  id,
                 clock_ctrl_t                     clock_control);

PARAMETERS

host_priv
[in host-control send right] The control port for the host owning the clock.

id
[in scalar] The identification of the desired kernel clock. These values are defined in \*L\*O. Although an implementation may define additional values, the following values are always defined (although only the REALTIME clock is required to be implemented):

REALTIME_CLOCK
A moderate resolution clock service that (typically) tracks time since the system last boot.

BATTERY_CLOCK
A (typically) low resolution clock (to the second) that survives power failures or service outages.

HIGHRES_CLOCK
A high resolution clock.

clock_control
[out clock-control send right] Control port for the clock.

DESCRIPTION

The host_get_clock_control function returns a send right to the control port for a kernel clock object. This right is used to set the clock's resolution and time.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: clock_set_time, clock_set_attributes, host_get_clock_service. \ No newline at end of file diff --git a/osfmk/man/host_get_clock_service.html b/osfmk/man/host_get_clock_service.html new file mode 100755 index 000000000..b9c9ea09e --- /dev/null +++ b/osfmk/man/host_get_clock_service.html @@ -0,0 +1 @@ +

host_get_clock_service


Function - Return a send right to a kernel clock's service port.

SYNOPSIS

kern_return_t   host_get_clock_service
                (host_t                                    host,
                 clock_id_t                                  id,
                 clock_t                             clock_name);

PARAMETERS

host
[in host-name send right] The name (or control) port for the host owning the clock.

id
[in scalar] The identification of the desired kernel clock. These values are defined in \*L\*O. Although an implementation may define additional values, the following values are always defined (although only the REALTIME clock is required to be implemented):

REALTIME_CLOCK
A moderate resolution clock service that (typically) tracks time since the system last boot.

BATTERY_CLOCK
A (typically) low resolution clock (to the second) that survives power failures or service outages.

HIGHRES_CLOCK
A high resolution clock.

clock_name
[out clock-name send right] Name port for the clock.

DESCRIPTION

The host_get_clock_service function returns a send right to the name port for a kernel clock object. This right is used to get the time and resolutions of the clock and to set clock alarms.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: clock_get_time, clock_get_attributes, clock_map_time, clock_sleep, clock_alarm, host_get_clock_control. \ No newline at end of file diff --git a/osfmk/man/host_get_time.html b/osfmk/man/host_get_time.html new file mode 100755 index 000000000..27002bf51 --- /dev/null +++ b/osfmk/man/host_get_time.html @@ -0,0 +1 @@ +

host_get_time


Function - Return the current time.

SYNOPSIS

#include< mach/mach_host.h>

kern_return_t   host_get_time
                (host_t                                    host,
                 time_value_t                      current_time);

PARAMETERS

host
[in host-name port] The name port the host for which the time is to be set.

current_time
[out structure] Returned time value.

DESCRIPTION

The host_get_time function returns the current time as seen by that host.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: host_adjust_time, host_set_time.

Data Structures: time_value. \ No newline at end of file diff --git a/osfmk/man/host_info.html b/osfmk/man/host_info.html new file mode 100755 index 000000000..8bafeb2a4 --- /dev/null +++ b/osfmk/man/host_info.html @@ -0,0 +1 @@ +

host_info


Function - Return information about a host.

SYNOPSIS

kern_return_t   host_info
                (host_t                                    host,
                 host_flavor_t                           flavor,
                 host_info_t                          host_info,
                 mach_msg_type_number_t         host_info_count);

PARAMETERS

host
[in host-name send right] The name (or control) port for the host for which information is to be obtained.

flavor
[in scalar] The type of statistics desired:

HOST_BASIC_INFO
Basic information (number of processors, amount of memory). The returned structure is host_basic_info.

HOST_SCHED_INFO
Basic restrictions of the kernel's scheduling, minimum quantum and time-out value. The returned structure is host_sched_info.

HOST_RESOURCE_SIZES
This interface feature is not implemented in OSF/1 R1.3. Size of significant kernel structures, as a ledger would consider them when limiting kernel resource consumption. The returned structure is kernel_resource_sizes.

host_info
[out structure] Statistics about the specified host.

host_info_count
[in/out scalar] On input, the maximum size of the buffer; on output, the size returned (in natural-sized units).

DESCRIPTION

The host_info function returns selected information about a host, as specified by flavor.

NOTES

This interface is machine word length specific because of the memory size returned by HOST_BASIC_INFO.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: host_get_boot_info, host_kernel_version, host_statistics.

Data Structures: host_basic_info, host_sched_info, kernel_resource_sizes. \ No newline at end of file diff --git a/osfmk/man/host_kernel_version.html b/osfmk/man/host_kernel_version.html new file mode 100755 index 000000000..00d7f9e46 --- /dev/null +++ b/osfmk/man/host_kernel_version.html @@ -0,0 +1 @@ +

host_kernel_version


Function - Return kernel version information for a host.

SYNOPSIS

kern_return_t   host_kernel_version
                (host_t                                    host,
                 kernel_version_t                       version);

PARAMETERS

host
[in host-name send right] The name (or control) port for the host for which information is to be obtained.

version
[out array of char] Character string describing the kernel version executing on host.

DESCRIPTION

The host_kernel_version function returns the version string compiled into the kernel executing on host at the time it was built. This describes the version of the kernel. The constant KERNEL_VERSION_MAX (in \*L\*O) should be used to dimension storage for the returned string if the kernel_version_t declaration is not used.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: host_info. \ No newline at end of file diff --git a/osfmk/man/host_load_info.html b/osfmk/man/host_load_info.html new file mode 100755 index 000000000..ab61fa27b --- /dev/null +++ b/osfmk/man/host_load_info.html @@ -0,0 +1 @@ +

host_load_info


Structure - Used to present a host's processor load information.

SYNOPSIS

#define CPU_STATE_USER     0

#define CPU_STATE_SYSTEM   1

#define CPU_STATE_IDLE     2

struct host_load_info
{
       integer_t        avenrun[3];
       integer_t    mach_factor[3];
};

typedef struct host_load_info* host_load_info_t;

FIELDS

avenrun
load average--average number of runnable processes divided by number of CPUs

mach_factor
The processing resources available to a new thread--the number of CPUs divided by (1 + the number of threads)

DESCRIPTION

The host_load_info structure defines the loading information available about a host. The information returned is exponential averages over three periods of time: 5, 30 and 60 seconds.

RELATED INFORMATION

Functions: host_statistics.

Data Structures: host_basic_info, host_sched_info. \ No newline at end of file diff --git a/osfmk/man/host_page_size.html b/osfmk/man/host_page_size.html new file mode 100755 index 000000000..38fca4546 --- /dev/null +++ b/osfmk/man/host_page_size.html @@ -0,0 +1 @@ +

host_page_size


Function - Provide the system's virtual page size.

SYNOPSIS

kern_return_t   host_page_size
                (host_t                                    host,
                 vm_size_t                            page_size);

PARAMETERS

host
[in host-name send right] The name (or control) port for the host for which the page size is desired.

page_size
[out scalar] The host's page size (in bytes).

DESCRIPTION

The host_page_size function returns the page size for the given host.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: mach_host_self. \ No newline at end of file diff --git a/osfmk/man/host_processor_set_priv.html b/osfmk/man/host_processor_set_priv.html new file mode 100755 index 000000000..c8ec25271 --- /dev/null +++ b/osfmk/man/host_processor_set_priv.html @@ -0,0 +1 @@ +

host_processor_set_priv


Function - Translate a processor set name port into a processor set control port.

SYNOPSIS

kern_return_t   host_processor_set_priv
                (host_priv_t                          host_priv,
                 processor_set_name_t                  set_name,
                 processor_set_t                  processor_set);

PARAMETERS

host_priv
[in host-control send right] The control port for the host for which the processor set is desired.

set_name
[in processor-set-name send right] The name port for the processor set desired.

processor_set
[out processor-set-control send right] The returned processor set control port.

DESCRIPTION

The host_processor_set_priv function returns send rights for the control port for a specified processor set currently existing on host_priv.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: host_processor_sets, processor_set_create, processor_set_tasks, processor_set_threads. \ No newline at end of file diff --git a/osfmk/man/host_processor_sets.html b/osfmk/man/host_processor_sets.html new file mode 100755 index 000000000..41811d358 --- /dev/null +++ b/osfmk/man/host_processor_sets.html @@ -0,0 +1 @@ +

host_processor_sets


Function - Return a list of send rights representing all processor set name ports.

SYNOPSIS

kern_return_t   host_processor_sets
                (host_priv_t                          host_priv,
                 processor_set_name_port_array_tprocessor_set_name_list,
                 host_priv             processor_set_name_count);

PARAMETERS

host_priv
[in host-control send right] The control port for the host for which the processor sets are desired.

processor_set_name_list
[out pointer to dynamic array of processor-set-name send rights] The set of processor set name ports for those currently existing on host_priv; no particular order is guaranteed.

processor_set_name_count
[out scalar] The number of processor set names returned.

DESCRIPTION

The host_processor_sets function returns send rights for the name ports for each processor set currently existing on host.

NOTES

If control ports to the processor sets are needed, use host_processor_set_priv.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: host_processor_set_priv, processor_set_create, processor_set_tasks, processor_set_threads. \ No newline at end of file diff --git a/osfmk/man/host_processor_slots.html b/osfmk/man/host_processor_slots.html new file mode 100755 index 000000000..89ec2a170 --- /dev/null +++ b/osfmk/man/host_processor_slots.html @@ -0,0 +1 @@ +

host_processor_slots


Function - Return a list of numbers that map processor slots to active processors.

SYNOPSIS

kern_return_t   host_processor_slots
                (host_t                                    host,
                 processor_slot_t                         slots,
                 host                                     count);

PARAMETERS

host
[in host-name send right] The name (or control) port for the host for which information is to be obtained.

slots
[out array of processor_slot_t] An array of the processor slot numbers for active processors.

count
[pointer to in/out scalar] On input, the maximum size of the slots buffer; on output, the number of returned slot numbers.

DESCRIPTION

The host_processor_slots function returns an array of the processor slots defined for the host.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: host_info, host_processors, processor_info. \ No newline at end of file diff --git a/osfmk/man/host_processors.html b/osfmk/man/host_processors.html new file mode 100755 index 000000000..4f0d57a13 --- /dev/null +++ b/osfmk/man/host_processors.html @@ -0,0 +1 @@ +

host_processors


Function - Return a list of send rights representing all processor ports.

SYNOPSIS

kern_return_t   host_processors
                (host_t                               host_priv,
                 processor_port_array_t          processor_list,
                 host_priv                      processor_count);

PARAMETERS

host_priv
[in host-control send right] The control port for the desired host.

processor_list
[out pointer to dynamic array of processor send rights] The set of processors existing on host_priv; no particular order is guaranteed.

processor_count
[out scalar] The number of ports returned in processor_list.

DESCRIPTION

The host_processors function returns an array of send right ports for each processor existing on host_priv.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: processor_start, processor_exit, processor_info, processor_control, host_processor_slots. \ No newline at end of file diff --git a/osfmk/man/host_reboot.html b/osfmk/man/host_reboot.html new file mode 100755 index 000000000..7a7fa6159 --- /dev/null +++ b/osfmk/man/host_reboot.html @@ -0,0 +1 @@ +

host_reboot


Function - Reboot this host.

SYNOPSIS

kern_return_t   host_reboot
                (host_priv_t                          host_priv,
                 int                                    options);

PARAMETERS

host_priv
[in host-control send right] The control port the host to be re-booted.

options
[in scalar] Reboot options. See \*L\*O for details.

DESCRIPTION

The host_reboot function reboots the specified host.

NOTES

If successful, this call will not return.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

None. \ No newline at end of file diff --git a/osfmk/man/host_sched_info.html b/osfmk/man/host_sched_info.html new file mode 100755 index 000000000..581af5261 --- /dev/null +++ b/osfmk/man/host_sched_info.html @@ -0,0 +1 @@ +

host_sched_info


Structure - Used to present the set of scheduler limits associated with the host.

SYNOPSIS

struct host_sched_info
{
       integer_t       min_timeout;
       integer_t       min_quantum;
};

typedef struct host_sched_info* host_sched_info_t;

FIELDS

min_timeout
Minimum time-out, in milliseconds

min_quantum
Minimum quantum (period for which a thread can be scheduled if uninterrupted), in milliseconds

DESCRIPTION

The host_sched_info structure defines the limiting scheduling information available about a host.

RELATED INFORMATION

Functions: host_info.

Data Structures: host_basic_info, host_load_info. \ No newline at end of file diff --git a/osfmk/man/host_set_time.html b/osfmk/man/host_set_time.html new file mode 100755 index 000000000..cbe6cf580 --- /dev/null +++ b/osfmk/man/host_set_time.html @@ -0,0 +1 @@ +

host_set_time


Function - Sets the time.

SYNOPSIS

#include< mach/mach_host.h>

kern_return_t   host_set_time
                (host_priv_t                          host_priv,
                 time_value_t                          new_time);

PARAMETERS

host_priv
[in host-control port] The control port for the host for which the time is to be set.

new_time
[in structure] Time to be set.

DESCRIPTION

The host_set_time function establishes the time on the specified host.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: host_adjust_time, host_get_time.

Data Structures: time_value. \ No newline at end of file diff --git a/osfmk/man/host_statistics.html b/osfmk/man/host_statistics.html new file mode 100755 index 000000000..45ba471aa --- /dev/null +++ b/osfmk/man/host_statistics.html @@ -0,0 +1 @@ +

host_statistics


Function - Return statistics for a host.

SYNOPSIS

kern_return_t   host_statistics
                (host_priv_t                          host_priv,
                 host_flavor_t                           flavor,
                 host_info_t                          host_info,
                 mach_msg_type_number_t         host_info_count);

PARAMETERS

host_priv
[in host-control send right] The control port for the host for which information is to be obtained.

flavor
[in scalar] The type of statistics desired.

HOST_LOAD_INFO
System loading statistics. The returned structure is host_load_info.

HOST_VM_INFO
Virtual memory statistics. The returned structure is vm_statistics.

host_info
[out structure] Statistics about the specified host.

host_info_count
[in/out scalar] On input, the maximum size of the buffer; on output, the size returned (in natural-sized units).

DESCRIPTION

The host_statistics function returns scheduling and virtual memory statistics concerning the host as specified by flavor.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: host_info, processor_set_statistics.

Data Structures: host_load_info, vm_statistics. \ No newline at end of file diff --git a/osfmk/man/i386_get_ldt.html b/osfmk/man/i386_get_ldt.html new file mode 100755 index 000000000..a00080de0 --- /dev/null +++ b/osfmk/man/i386_get_ldt.html @@ -0,0 +1 @@ +

i386_get_ldt


Function - Return per-thread segment descriptors.

SYNOPSIS

kern_return_t   i386_get_ldt
                (thread_act_t                        target_act,
                 int                             first_selector,
                 int                              desired_count,
                 descriptor_list_t                    desc_list);

PARAMETERS

target_act
[in thread send right] Thread whose segment descriptors are to be returned.

first_selector
[in scalar] Selector value (segment register value) corresponding to the first segment whose descriptor is to be returned.

desired_count
[in scalar] Number of returned descriptors desired.

desc_list
[out pointer to dynamic array of descriptor_t] Array of segment descriptors.

DESCRIPTION

The i386_get_ldt function returns per-thread segment descriptors from the thread's local descriptor table (LDT).

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: i386_set_ldt. \ No newline at end of file diff --git a/osfmk/man/i386_io_port_add.html b/osfmk/man/i386_io_port_add.html new file mode 100755 index 000000000..241c4d872 --- /dev/null +++ b/osfmk/man/i386_io_port_add.html @@ -0,0 +1 @@ +

i386_io_port_add


Function - Permit target thread to invoke operations on the specified device.

SYNOPSIS

kern_return_t   i386_io_port_add
                (thread_act_t                        target_act,
                 device_t                                device);

PARAMETERS

target_act
[in thread send right] Thread whose permission bitmap is to be set.

device
[in device send right] The device to which I/O instructions are to be permitted.

DESCRIPTION

The i386_io_port_add function adds a device to the I/O permission bitmap for a thread, thereby permitting the thread to execute I/O instructions against the device.

NOTES

Normally, the thread must have called i386_io_port_add for all devices to which it will execute I/O instructions. However, possessing send rights to the iopl device port will cause the iopl device to be automatically added to the thread's I/O map upon first attempted access. This is a backward compatibility feature for the DOS emulator.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: i386_io_port_list, i386_io_port_remove. \ No newline at end of file diff --git a/osfmk/man/i386_io_port_list.html b/osfmk/man/i386_io_port_list.html new file mode 100755 index 000000000..304aca085 --- /dev/null +++ b/osfmk/man/i386_io_port_list.html @@ -0,0 +1 @@ +

i386_io_port_list


Function - List the devices that permit target thread to invoke operations.

SYNOPSIS

kern_return_t   i386_io_port_list
                (thread_act_t                        target_act,
                 device_list_t                      device_list);

PARAMETERS

target_act
[in thread send right] Thread whose permission list is to be returned.

device_list
[out pointer to dynamic array of device send rights] Device ports permitting I/O.

DESCRIPTION

The i386_io_port_list function returns a list of the devices named in the thread's I/O permission bitmap, namely those permitting I/O instructions to be executed against them.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: i386_io_port_add, i386_io_port_remove. \ No newline at end of file diff --git a/osfmk/man/i386_io_port_remove.html b/osfmk/man/i386_io_port_remove.html new file mode 100755 index 000000000..31ead08a0 --- /dev/null +++ b/osfmk/man/i386_io_port_remove.html @@ -0,0 +1 @@ +

i386_io_port_remove


Function - Disable target thread's ability to invoke operations on the specified device.

SYNOPSIS

kern_return_t   i386_io_port_remove
                (thread_act_t                        target_act,
                 device_t                                device);

PARAMETERS

target_act
[in thread send right] Thread whose permission bitmap is to be cleared

device
[in device send right] Device whose permission is to be revoked

DESCRIPTION

The i386_io_port_remove function removes the specified device from the thread's I/O permission bitmap, thereby prohibiting I/O instructions being executed against the device.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: i386_io_port_add, i386_io_port_list. \ No newline at end of file diff --git a/osfmk/man/i386_set_ldt.html b/osfmk/man/i386_set_ldt.html new file mode 100755 index 000000000..4ae173510 --- /dev/null +++ b/osfmk/man/i386_set_ldt.html @@ -0,0 +1 @@ +

i386_set_ldt


Function - Set per-thread segment descriptors.

SYNOPSIS

kern_return_t   i386_set_ldt
                (thread_act_t                        target_act,
                 int                             first_selector,
                 descriptor_list_t                    desc_list);

PARAMETERS

target_act
[in thread send right] Thread whose segment descriptors are to be set.

first_selector
[in scalar] Selector value (segment register value) corresponding to the first segment whose descriptor is to be set.

desc_list
[pointer to in array of descriptor_t] Array of segment descriptors. The following forms are permitted:

  • Empty descriptor. The ACC_P flag (segment present) may or may not be set.

  • ACC_CALL_GATE--Converted into a system call gate. The ACC_P flag must be set.

All other descriptors must have both the ACC_P flag set and specify user mode access (ACC_PL_U).

  • ACC_DATA.

  • ACC_DATA_W.

  • ACC_DATA_E.

  • ACC_DATA_EW.

  • ACC_CODE.

  • ACC_CODE_R.

  • ACC_CODE_C.

  • ACC_CODE_CR.

  • ACC_CALL_GATE_16.

  • ACC_CALL_GATE.

DESCRIPTION

The i386_set_ldt function allows a thread to have a private local descriptor table (LDT) which allows its local segments to map various ranges of its address space.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: i386_get_ldt. \ No newline at end of file diff --git a/osfmk/man/index.html b/osfmk/man/index.html new file mode 100755 index 000000000..86568bf81 --- /dev/null +++ b/osfmk/man/index.html @@ -0,0 +1 @@ + Mach Kernel Interface Reference Manual

Mach IPC Interface

Mach IPC presents itself in a few forms: message queues, lock-sets, and semaphores (more may be added in the future).  All share one common charateristic: the capabilities presented by each are represented through a handle known as a Mach port.  Specific rights represented in these Mach port capability handles allow the underlying IPC object to be used and manipulated in consistent ways.

Mach Message Queue Interface

mach_msg - Send and/or receive a message from the target port.
mach_msg_overwrite - Send and/or receive messages with possible overwrite.

Mach Message Queue Data Structures

mach_msg_descriptor - Specifies an element of a complex IPC message.
mach_msg_header - Specifies the content of an IPC message header.

Mach Lock-Set Interface

lock_acquire - Acquire ownership a lock
lock_handoff - Hand-off ownership of a lock.
lock_handoff_accept - Accept lock ownership from a handoff.
lock_make_stable - Stabilize the state of the specified lock.
lock_release - Release ownership of a lock.
lock_set_create - Create a new lock set.
lock_set_destroy - Destroy a lock set and its associated locks.
lock_try - Attempt to acquire access rights to a lock.

Mach Semaphore Interface

semaphore_create - Create a new semaphore.
semaphore_destroy - Destroy a semaphore.
semaphore_signal - Increments the semaphore count.
semaphore_signal_all - Wake up all threads blocked on a semaphore.
semaphore_wait - Wait on the specified semaphore.

Mach Port Management Interface

mach_port_allocate - Create caller-specified type of port right.
mach_port_allocate_full - Create a port right with full Mach port semantics.
mach_port_allocate_name - Create a port right with the caller-specified name.
mach_port_allocate_qos - Allocate a port with specified "quality of service".
mach_port_allocate_subsystem - Create a port right associated with the caller-specified subsystem.
mach_port_deallocate - Decrement the target port right's user reference count.
mach_port_destroy - Deallocate all port rights associated with specified name.
mach_port_extract_right - Remove the specified right from the target task and return it to the caller.
mach_port_get_attributes - Return information about target port as specified by the caller.
mach_port_get_refs - Return the current count of user references on the target port right.
mach_port_get_set_status - Return the port right names contained in the target port set.
mach_port_insert_right - Insert the specified port right into the target task.
mach_port_mod_refs - Modify the specified port right's count of user references.
mach_port_move_member - Move the specified receive right into or out of the specified port set.
mach_port_names - Return information about a task's port name space.
mach_port_request_notification - Request notification of the specified port event type.
mach_port_set_attributes - Set the target port's attributes.
mach_port_set_mscount - Change the target port's make-send count.
mach_port_set_seqno - Change the current value of the target port's sequence number.
mach_port_type - Return the characteristics of the target port name.
mach_reply_port - Allocate a new port and insert corresponding receive right in the calling task.
mach_subsystem_create - Used by a server to register information about an RPC subsystem with the kernel.

Mach Port Data Structures

mach_port_limits - Specifies a port's resource and message queue limits.
mach_port_qos - Specifies a port's attributes with respect to "Quality Of Service."
mach_port_status - Used to present a port's current status with respect to various important attributes.

Mach Port Notification Callbacks

do_mach_notify_dead_name - Handle the current instance of a dead-name notification.
do_mach_notify_no_senders - Handle the current instance of a no-more-senders notification.
do_mach_notify_port_deleted - Handle the current instance of a port-deleted notification.
do_mach_notify_port_destroyed - Handle the current instance of a port-destroyed notification.
do_mach_notify_send_once - Handle the current instance of a send-once notification.

Mach Port Notification Callback Server Helpers

notify_server - Detect and handle a kernel-generated IPC notification.

Mach Virtual Memory Interface

Mach Virtual Memory Address Space Manipulation Interface

host_page_size - Provide the system's virtual page size.
vm_allocate - Allocate a region of virtual memory.
vm_behavior_set - Specify expected access patterns for the target VM region.
vm_copy - Copy a region of virtual memory.
vm_deallocate - Deallocate a region of virtual memory.
vm_inherit - Set a VM region's inheritance attribute.
vm_machine_attribute - Get/set the target memory region's special attributes.
vm_map - Map the specified memory object to a region of virtual memory.
vm_msync - Synchronize the specified region of virtual memory.
vm_protect - Set access privilege attribute for a region of virtual memory.
vm_read - Read the specified range of target task's address space.
vm_region - Return description of a virtual memory region.
vm_remap - Map memory objects in one address space to that of another's.
vm_wire - Modify the target region's paging characteristics.
vm_write - Write data to the specified address in the target address space.

Data Structures

vm_region_basic_info - Defines the attributes of a task's memory region.
vm_statistics - Defines statistics for the kernel's use of virtual memory.

External Memory Management Interface

The External Memory Management Interface (EMMI) is undergoing significant change in the Darwin system. For this reason, the interface is not currently available to user-level programs. Even for kernel extensions, use of these interfaces in not supported. Instead, the BSD filesystem's Universal Buffer Cache (UBC) mechanism should be used.

memory_object_change_attributes - Modify subset of memory object attributes.
memory_object_destroy - Shut down a memory object.
memory_object_get_attributes - Return current attributes for a memory object.
memory_object_lock_request - Restrict access to memory object data.
memory_object_synchronize_completed - Synchronized data has been processed.

Data Structures

memory_object_attr_info - Defines memory object attributes.
memory_object_perf_info- Specifies performance-related memory object attributes.

External Memory Manager Interface Callbacks

memory_object_create - Assign a new memory object to the default memory manager.
memory_object_data_initialize - Provide initial data for a new memory object.
memory_object_data_request - Request that memory manager page-in specified data.
memory_object_data_return - Return memory object data to the appropriate memory manager.
memory_object_data_unlock - Request a memory manager release the lock on specific data.
memory_object_init - Inform a memory manager on first use of a memory object.
memory_object_synchronize - Request synchronization of data with backing store.
memory_object_terminate - Relinquish access to a memory object.

EMMI Callback Server Helpers

memory_object_default_server - Handle kernel operation request targeted for the default pager.
memory_object_server - Handle kernel operation request aimed at a given memory manager.

Default Memory Management Interface

default_pager_add_segment - Add additional backing storage for a default pager.
default_pager_backing_store_create - Create a backing storage object.
default_pager_backing_store_delete - Delete a backing storage object.
default_pager_backing_store_info - Return information about a backing storage object.
default_pager_info - Furnish caller with information about the default pager.
default_pager_object_create - Initialize a non-persistent memory object.
host_default_memory_manager - Register/Lookup the host's default pager.

Process Management Interface

Task Interface

mach_ports_lookup - Provide caller with an array of the target task's well-known ports.
mach_ports_register - Register an array of well-known ports on behalf of the target task.
mach_task_self - Return a send right to the caller's task_self port.
task_create - Create a new task.
task_get_emulation_vector - Return an array identifying the target task's user-level system call handlers.
task_get_exception_ports - Return send rights to the target task's exception ports.
task_get_special_port - Return a send write to the indicated special port.
task_info - Return per-task information according to specified flavor.
task_resume - Decrement the target task's suspend count.
task_sample - Sample the target task's thread program counters periodically.
task_set_emulation - Establish a user-level handler for a system call.
task_set_emulation_vector - Establish the target task's user-level system call handlers.
task_set_exception_ports - Set target task's exception ports.
task_set_info - Set task-specific information state.
task_set_port_space - Set the size of the target task's port name space table.
task_set_special_port - Set the indicated special port.
task_suspend - Suspend the target task.
task_swap_exception_ports - Set target task's exception ports, returning the previous exception ports.
task_terminate - Terminate the target task and deallocate its resources.
task_threads - Return the target task's list of threads.

Task Data Structures

task_basic_info - Defines basic information for a task.
task_thread_times_info - Defines thread execution times information for tasks.

Thread Interface

mach_thread_self - Returns the thread self port.
thread_abort - Abort a thread.
thread_abort_safely - Abort a thread, restartably.
thread_create - Create a thread within a task.
thread_create_running - Optimized creation of a running thread.
thread_depress_abort - Cancel thread scheduling depression.
thread_get_exception_ports - Return a send right to an exception port.
thread_get_special_port - Return a send right to the caller-specified special port.
thread_get_state - Return the execution state for a thread.
thread_info - Return information about a thread.
thread_resume - Resume a thread.
thread_sample - Perform periodic PC sampling for a thread.
thread_set_exception_ports - Set exception ports for a thread.
thread_set_special_port - Set caller-specified special port belonging to the target thread.
thread_set_state - Set the target thread's user-mode execution state.
thread_suspend - Suspend a thread.
thread_swap_exception_ports - Swap exception ports for a thread.
thread_terminate - Destroy a thread.
thread_wire - Mark the thread as privileged with respect to kernel resources.

Thread Data Structures

thread_basic_info - Defines basic information for a thread.

Thread Exception Callbacks

catch_exception_raise - Handles the occurrence of an exception within a thread.

Thread Exception Callback Server Helpers

exc_server - Handle kernel-reported thread exception.

Scheduling Interface

task_policy - Set target task's default scheduling policy state.
task_set_policy - Set target task's default scheduling policy state.
thread_policy - Set target thread's scheduling policy state.
thread_set_policy - Set target thread's scheduling policy state.
thread_switch - Cause context switch with options.

Scheduling Data Structures

policy_fifo_info - Specifies information associated with the system's First-In-First-Out scheduling policy.
policy_rr_info - Specifies information associated with the system's Round Robin scheduling policy.
policy_timeshare_info - Specifies information associated with the system's Timeshare scheduling policy.

System Management Interface

Host Interface

host_get_clock_service - Return a send right to a kernel clock's service port.
host_get_time - Returns the current time as seen by that host.
host_info - Return information about a host.
host_kernel_version - Return kernel version information for a host.
host_statistics - Return statistics for a host.
mach_host_self - Returns send rights to the task's host self port.

Data Structures

host_basic_info - Used to present basic information about a host.
host_load_info - Used to present a host's processor load information.
host_sched_info - - Used to present the set of scheduler limits associated with the host.
kernel_resource_sizes - Used to present the sizes of kernel's major structures.

Host Control Interface

host_adjust_time - Arranges for the time on a specified host to be gradually changed by an adjustment value.
host_default_memory_manager - Set the default memory manager.
host_get_boot_info - Return operator boot information.
host_get_clock_control - Return a send right to a kernel clock's control port.
host_processor_slots - Return a list of numbers that map processor slots to active processors.
host_processors - Return a list of send rights representing all processor ports.
host_reboot - Reboot this host.
host_set_time - Establishes the time on the specified host.

Host Security Interface

task_create_security_token - Create a new task with an explicit security token.
task_set_security_token - Change the target task's security token.

Resource Accounting Interface

The Mach resource accounting mechanism is not functional in the current Mac OS X/Darwin system. It will become functional in a future release.

ledger_create - Create a subordinate ledger.
ledger_read - Return the ledger limit and balance.
ledger_terminate - Destroy a ledger.
ledger_transfer - Transfer resources from a parent ledger to a child.

Processor Management Interface

processor_control - Perform caller-specified operation on target processor.
processor_exit - Exit a processor.
processor_info - Return information about a processor.
processor_start - Start a processor.

Processor Data Structures

processor_basic_info - Defines the basic information about a processor.

Processor Set Interface

The processor set interface allows for the grouping of tasks and processors for the purpose of exclusive scheduling. These interface are deprecated and should not be used in code that isn't tied to a particular release of Mac OS X/Darwin. These will likely change or disappear in a future release.

host_processor_sets - Return a list of send rights representing all processor set name ports.
host_processor_set_priv - Translate a processor set name port into a processor set control port.
processor_assign - Assign a processor to a processor set.
processor_get_assignment - Get current assignment for a processor.
processor_set_create - Create a new processor set.
processor_set_default - Return the default processor set.
processor_set_destroy - Destroy the target processor set.
processor_set_info - Return processor set state according to caller-specified flavor.
processor_set_max_priority - Sets the maximum scheduling priority for a processor set.
processor_set_policy_control - Set target processor set's scheduling policy state.
processor_set_policy_disable - Enables a scheduling policy for a processor set.
processor_set_policy_enable - Enables a scheduling policy for a processor set.
processor_set_statistics - Return scheduling statistics for a processor set.
processor_set_tasks - Return all tasks currently assigned to the target processor set.
processor_set_threads - Return all threads currently assigned to the target processor set.
task_assign - Assign a task to a processor set.
task_assign_default - Assign a task to the default processor set.
task_get_assignment - Create a new task with an explicit security token.
thread_assign - Assign a thread to a processor set.
thread_assign_default - Assign a thread to the default processor set.
thread_get_assignment - Return the processor set to which a thread is assigned.

Processor Set Data Structures

processor_set_basic_info - Defines the basic information about a processor set.
processor_set_load_info - Defines the scheduling statistics for a processor set.

Clock Interface

clock_alarm - Set up an alarm.
clock_get_attributes - Return attributes of a clock.
clock_get_time - Return the current time.
clock_map_time - Return a memory object that maps a clock.
clock_set_attributes - Set a particular clock's attributes.
clock_set_time - Set the current time.
clock_sleep - Delay the invoking thread until a specified time.

Clock Data Structures

mapped_tvalspec - Specifies the format the kernel uses to maintain a mapped clock's time.
tvalspec - Defines format of system time values.

Clock Interface Callbacks

clock_alarm_reply - Ring a preset alarm.

Clock Callback Server Helpers

clock_reply_server - Handle kernel-generated alarm.

Multi-Computer Support Interface

These multi-computer support interfaces are no longer supported by the Mac OS X/Darwin kernel. If and when multi-computer support is added back in, something like these will likely be added.

host_page_size - Returns the page size for the given host.
ledger_get_remote - Return send right to specified host's remote ledger port.
ledger_set_remote - Set this host's remote ledger port.
norma_get_special_port - Returns a send right for a specified node-specific special port.
norma_node_self - Return the node index of the current host.
norma_port_location_hint - Guess a port's current location.
norma_set_special_port - Set node-specific special port.
norma_task_clone - Create a remote task that shares access to parent task's memory.
norma_task_create - Create a remote task using task_create semantics.
norma_task_teleport - "Clone" a task on a specified node.

Machine Specific Interface

Intel 386 Support

i386_get_ldt - Returns per-thread segment descriptors from the local descriptor table (LDT).
i386_io_port_add - Adds a device to the I/O permission bitmap for a thread.
i386_io_port_list - Returns a list of the devices named in the thread's I/O permission bitmap.
i386_io_port_remove - Removes the specified device from the thread's I/O permission bitmap.
i386_set_ldt - Allows a thread to have a private local descriptor table (LDT).

PowerPC Support

\ No newline at end of file diff --git a/osfmk/man/io_done_queue_create.html b/osfmk/man/io_done_queue_create.html new file mode 100755 index 000000000..ee33ffffb --- /dev/null +++ b/osfmk/man/io_done_queue_create.html @@ -0,0 +1 @@ +

io_done_queue_create


Function - Create an io_done_queue kernel object.

SYNOPSIS

kern_return_t   io_done_queue_create
                (mach_port_t                               host,
                 mach_port_t                               queue);

PARAMETERS

host
[in host-name send right] The name (or control) port for the host on which the io_done_queue should be created.

queue
[out io-done-queue send right] The port referencing the created io_done_queue.

DESCRIPTION

The io_done_queue_create function is called to create a new instatiation of the kernel object supporting asynchronous read/write operations on a device.

RETURN VALUES

KERN_INVALID_ARGUMENT
Invalid host parameter.

KERN_RESOURCE_SHORTAGE
Insufficient kernel resources to allocate kernel object.

RELATED INFORMATION

Functions: io_done_queue_terminate, io_done_queue_wait, device_read_async, device_read_async_inband, device_read_overwrite_async, device_write_async, device_write_async_inband. \ No newline at end of file diff --git a/osfmk/man/io_done_queue_terminate.html b/osfmk/man/io_done_queue_terminate.html new file mode 100755 index 000000000..67245742c --- /dev/null +++ b/osfmk/man/io_done_queue_terminate.html @@ -0,0 +1 @@ +

io_done_queue_terminate


Function - Terminate an io_done_queue kernel object.

SYNOPSIS

#include<device/device.h>

kern_return_t	io_done_queue_terminate
		(mach_port_t	queue);

PARAMETERS

queue
[in io-done-queue send right] The port referencing the io_done_queue to be destroyed.

DESCRIPTION

The io_done_queue_terminate function is called to destroy a previous instatiation of the kernel object supporting asynchronous read/write operations on a device.

RETURN VALUES

KERN_INVALID_ARGUMENT
Invalid queue parameter.

RELATED INFORMATION

Functions: io_done_queue_create, io_done_queue_wait, device_read_async, device_read_async_inband, device_read_overwrite_async, device_write_async, device_write_async_inband. \ No newline at end of file diff --git a/osfmk/man/io_done_queue_wait.html b/osfmk/man/io_done_queue_wait.html new file mode 100755 index 000000000..494c06c23 --- /dev/null +++ b/osfmk/man/io_done_queue_wait.html @@ -0,0 +1 @@ +

io_done_queue_wait


System Trap - Wait on an io_done_queue kernel object.

SYNOPSIS

kern_return_t	io_done_queue_wait
		(mach_port_t             queue,
		io_done_result_t       *result);

PARAMETERS

queue
[in io-done-queue send right] The port referencing the io_done_queue to be destroyed.

result
[out structure] The data structure to be filled in with the completion status of the I/O operation.

DESCRIPTION

The io_done_queue_wait interface is called to obtain the results of a previously requested asynchronous I/O operation. For each io_done_queue_wait invocation, the status of one I/O request is returned. If there are no pending I/O completions, io_done_queue_wait blocks in the kernel on the address of the completion queue. The mKernel, from interrupt context, enqueues (in FIFO order) completions (struct io_done_result's) on the completion queue and posts a wakeup on the queue for each I/O completion. Completion processing previously done by the mKernel io_done thread is now done by the task thread when it awakens.

RETURN VALUES

KERN_TERMINATED
Stale io_done_queue handle.

KERN_INVALID_ARGUMENT
Invalid queue parameter.

KERN_INVALID_ARGUMENT
The result parameter is a bad address.

RELATED INFORMATION

Functions: io_done_queue_create, io_done_queue_wait, device_read_async, device_read_async_inband, device_read_overwrite_async, device_write_async, device_write_async_inband. \ No newline at end of file diff --git a/osfmk/man/kernel_resource_sizes.html b/osfmk/man/kernel_resource_sizes.html new file mode 100755 index 000000000..0404ab2ea --- /dev/null +++ b/osfmk/man/kernel_resource_sizes.html @@ -0,0 +1 @@ +

kernel_resource_sizes


Structure - Used to present the sizes of kernel's major structures.

SYNOPSIS

struct kernel_resource_sizes
{
       vm_size_t               task;
       vm_size_t             thread;
       vm_size_t               port;
       vm_size_t      memory_region;
       vm_size_t      memory_object;
};

typedef struct kernel_resource_sizes* kernel_resource_sizes_t;

FIELDS

task
Space consumed by an empty task.

thread
Space consumed by a thread.

port
Space consumed by a port with an empty message queue.

memory_region
Space consumed by each distinct memory region (as reported by vm_region) in a task's address space.

memory_object
Space consumed to manage a memory object with no resident pages or copy objects.

DESCRIPTION

The kernel_resource_sizes structure defines the sizes of significant kernel structures.

RELATED INFORMATION

Functions: host_info. \ No newline at end of file diff --git a/osfmk/man/ledger_create.html b/osfmk/man/ledger_create.html new file mode 100755 index 000000000..6971798f0 --- /dev/null +++ b/osfmk/man/ledger_create.html @@ -0,0 +1 @@ +

ledger_create


Function - Create a subordinate ledger.

SYNOPSIS

kern_return_t   ledger_create
                (ledger_port_t                    parent_ledger,
                 ledger_port_t                    ledger_ledger,
                 ledger_port_t                     child_ledger,
                 ledger_item_t                         transfer);

PARAMETERS

parent_ledger
[in ledger send right] The parent ledger.

ledger_ledger
[in ledger send right] The wired kernel memory ledger providing the space from which the ledger itself is drawn.

child_ledger
[out ledger send right] The new child ledger, of the same resource type as the parent ledger.

transfer
[in scalar] The resource amount to transfer to the new ledger.

DESCRIPTION

The ledger_create function creates a subordinate ledger. Resource limits can be transferred from the parent ledger. The child ledger itself is accounted against the ledger_ledger. A new ledger inherits the remote service port.

NOTES

This interface is not implemented in OSF/1 R1.3.

A ledger limit of LEDGER_ITEM_INFINITE allows any amount (even infinity) to be withdrawn. The root ledger has such a limit.

RETURN VALUES

KERN_RESOURCE_SHORTAGE
Transferring the resources would cause the parent ledger to exceed its limits.

KERN_INVALID_LEDGER
ledger_ledger is not a wired kernel memory ledger.

RELATED INFORMATION

Functions: ledger_transfer, ledger_terminate, ledger_read, ledger_set_remote. \ No newline at end of file diff --git a/osfmk/man/ledger_get_remote.html b/osfmk/man/ledger_get_remote.html new file mode 100755 index 000000000..7b9a49315 --- /dev/null +++ b/osfmk/man/ledger_get_remote.html @@ -0,0 +1 @@ +

ledger_get_remote


Function - Return send right to specified host's remote ledger port.

SYNOPSIS

kern_return_t   ledger_get_remote
                (ledger_port_t                           ledger,
                 host_t                               host_name,
                 ledger                            service_port);


kern_return_t   ledger_return_remote
                (ledger_port_t                           ledger,
                 host_t                               host_name,
                 ledger                            service_port);

PARAMETERS

ledger
[in ledger send right] The ledger whose service port is desired.

host_name
[in host-name send right] The name for the host requesting the service port.

service_port
[out ledger-service send right] The ledger service port.

DESCRIPTION

The ledger_get_remote function returns the remote ledger service port for the ledger

NOTES

This interface is not implemented in OSF/1 R1.3.

This mechanism supports distributed resource ledgers in the following way:

With ledger_set_remote, a ledger is assigned a remote ledger service port.
This ledger is used as the ledger for a create operation. If the ledger is local to the target kernel, all is fine.
For a non-local creation, the target kernel sees that the supplied ledger is not a local ledger. The kernel sends a ledger_get_remote message to it, including the host name.
The (remote) ledger receives this message, ignores the host name and returns the remote ledger service port.
Assuming that the remote ledger service port is not a local ledger, the kernel sends a ledger_get_remote message to this service port.
A server receives this request (with the ledger_return_remote server interface) and uses the identity of the service port as well as the host name of the target kernel to locate or create a suitable ledger on that kernel.
The port for a ledger on the target kernel is sent to that kernel and used.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: ledger_create, ledger_set_remote. \ No newline at end of file diff --git a/osfmk/man/ledger_read.html b/osfmk/man/ledger_read.html new file mode 100755 index 000000000..fa283565a --- /dev/null +++ b/osfmk/man/ledger_read.html @@ -0,0 +1 @@ +

ledger_read


Function - Return the ledger limit and balance.

SYNOPSIS

kern_return_t   ledger_read
                (ledger_port_t                           ledger,
                 ledger_item_t                          balance,
                 ledger_item_t                          maximum);

PARAMETERS

ledger
[in ledger send right] The ledger to read

balance
[out scalar] The current usage

maximum
[out scalar] The resource limit

DESCRIPTION

The ledger_read function returns the current balance and limit in a ledger.

NOTES

This interface is not implemented in OSF/1 R1.3.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: ledger_create, ledger_terminate, ledger_transfer. \ No newline at end of file diff --git a/osfmk/man/ledger_set_remote.html b/osfmk/man/ledger_set_remote.html new file mode 100755 index 000000000..43a4edb1f --- /dev/null +++ b/osfmk/man/ledger_set_remote.html @@ -0,0 +1 @@ +

ledger_set_remote


Function - Set this host's remote ledger port.

SYNOPSIS

kern_return_t   ledger_set_remote
                (ledger_port_t                           ledger,
                 ledger_port_t                     service_port);

PARAMETERS

ledger
[in ledger send right] The ledger whose service port is to be set.

service_port
[in ledger-service send right] The ledger service port

DESCRIPTION

The ledger_set_remote function sets the remote ledger service port for the ledger. This is the port the ledger will return for ledger_get_remote requests.

NOTES

This interface is not implemented in OSF/1 R1.3.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: ledger_create, ledger_get_remote. \ No newline at end of file diff --git a/osfmk/man/ledger_terminate.html b/osfmk/man/ledger_terminate.html new file mode 100755 index 000000000..a8dd384fd --- /dev/null +++ b/osfmk/man/ledger_terminate.html @@ -0,0 +1 @@ +

ledger_terminate


Function - Destroy a ledger.

SYNOPSIS

kern_return_t   ledger_terminate
                (ledger_port_t                           ledger);

PARAMETERS

ledger
[in ledger send right] The ledger to destroy

DESCRIPTION

The ledger_terminate function destroys a ledger. All resources drawn from this ledger will also be destroyed. The resource limits in the ledger are returned to the ledger's parent.

NOTES

This interface is not implemented in OSF/1 R1.3.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: ledger_create, ledger_read, ledger_transfer. \ No newline at end of file diff --git a/osfmk/man/ledger_transfer.html b/osfmk/man/ledger_transfer.html new file mode 100755 index 000000000..60676a29c --- /dev/null +++ b/osfmk/man/ledger_transfer.html @@ -0,0 +1 @@ +

ledger_transfer


Function - Transfer resources from a parent ledger to a child.

SYNOPSIS

kern_return_t   ledger_transfer
                (ledger_port_t                    parent_ledger,
                 ledger_port_t                     child_ledger,
                 ledger_item_t                         transfer);

PARAMETERS

parent_ledger
[in ledger send right] The parent ledger

child_ledger
[in ledger send right] The child ledger

transfer
[in scalar] The resource amount to transfer. A positive amount moves the resource allocation from the parent to the child; a negative amount moves the reverse.

DESCRIPTION

The ledger_transfer function transfers resources from a parent to a child ledger.

NOTES

This interface is not implemented in OSF/1 R1.3.

RETURN VALUES

KERN_RESOURCE_SHORTAGE
Transferring the resources would cause one ledger to exceed its limit.

RELATED INFORMATION

Functions: ledger_create, ledger_terminate, ledger_read. \ No newline at end of file diff --git a/osfmk/man/lock_acquire.html b/osfmk/man/lock_acquire.html new file mode 100755 index 000000000..7bfc0f91f --- /dev/null +++ b/osfmk/man/lock_acquire.html @@ -0,0 +1 @@ +

lock_acquire


Function - Acquire access rights to a lock.

SYNOPSIS

kern_return_t   lock_acquire
                (lock_set_t                            lock_set,
                 int                                    lock_id);

PARAMETERS

lock_set
[in send right] The port naming the lock set which represents the lock.

lock_id
[in scalar] The lock, represented by the lock set, to be acquired.

DESCRIPTION

The lock_acquire function acquires access rights to a specific lock being represented by a given lock set. If the lock is already controlled by another thread then the calling thread will block.

RETURN VALUES

KERN_SUCCESS
The lock was acquired.

KERN_INVALID_ARGUMENT
The specified lock set is invalid, or the lock id is out of range.

KERN_LOCK_UNSTABLE
The acquired lock has an unstable state.

KERN_LOCK_SET_DESTROYED
The specified lock has been destroyed.

KERN_ABORTED
While blocked to wait for the specified lock to become available, the calling thread was awoken by an unrelated event, such as thread termination.

RELATED INFORMATION

Functions: lock_release, lock_try, lock_handoff, lock_handoff_accept, lock_make_stable, lock_set_create, lock_set_destroy. \ No newline at end of file diff --git a/osfmk/man/lock_handoff.html b/osfmk/man/lock_handoff.html new file mode 100755 index 000000000..9c6e84b87 --- /dev/null +++ b/osfmk/man/lock_handoff.html @@ -0,0 +1 @@ +

lock_handoff


Function - Hand-off ownership of a lock.

SYNOPSIS

kern_return_t   lock_handoff
                (lock_set_t                            lock_set,
                 int                                    lock_id);

PARAMETERS

lock_set
[in send right] The port naming the lock set which represents the lock.

lock_id
[in scalar] The lock, represented by the lock set, to be handed off.

DESCRIPTION

The lock_handoff function passes lock ownership from the calling thread to an anonymous accepting thread. The lock must be owned by the calling thread. If the accepting thread is not waiting to receive the lock, the calling thread will block until the hand-off is accepted.

RETURN VALUES

KERN_INVALID_ARGUMENT
The specified lock_set is invalid, or the lock_id is out of range.

KERN_INVALID_RIGHT
The calling thread does not own the lock being handed off.

KERN_SUCCESS
The lock hand-off was successful.

KERN_LOCK_SET_DESTROYED
The specified lock has been destroyed.

KERN_ABORTED
While blocked to wait for the accepting thread to assume the lock's ownership, the calling thread was awoken by an unrelated event; the lock's handoff state is cleared.

RELATED INFORMATION

Functions: lock_acquire, lock_release, lock_try, lock_handoff_accept, lock_make_stable, lock_set_create, lock_set_destroy. \ No newline at end of file diff --git a/osfmk/man/lock_handoff_accept.html b/osfmk/man/lock_handoff_accept.html new file mode 100755 index 000000000..21519d2fd --- /dev/null +++ b/osfmk/man/lock_handoff_accept.html @@ -0,0 +1 @@ +

lock_handoff_accept


Function - Accept a lock hand-off.

SYNOPSIS

kern_return_t   lock_handoff_accept
                (lock_set_t                            lock_set,
                 int                                    lock_id);

PARAMETERS

lock_set
[in send right] The port naming the lock set which represents the lock.

lock_id
[in scalar] The lock, represented by the lock set, that is the object of the handoff operation.

DESCRIPTION

The lock_handoff_accept function accepts a lock hand-off from an anonymous sending thread. If the sending thread is not waiting to hand-off the lock, the calling thread will block until the lock handoff is completed. Only one thread may be waiting to accept a lock handoff at any given time.

RETURN VALUES

KERN_ALREADY_WAITING
Another thread is already waiting for a hand-off of this lock.

KERN_INVALID_ARGUMENT
The specified lock_set is invalid, or the lock_id is out of range.

KERN_SUCCESS
The lock hand-off was successful.

KERN_LOCK_UNSTABLE
The acquired lock has an unstable state.

KERN_LOCK_SET_DESTROYED
The specified lock has been destroyed.

KERN_ABORTED
While blocked to wait for the sending thread to transfer the lock's ownership, the calling thread was awoken by an unrelated event; the lock's handoff state is cleared.

RELATED INFORMATION

Functions: lock_acquire, lock_release, lock_try, lock_handoff. \ No newline at end of file diff --git a/osfmk/man/lock_make_stable.html b/osfmk/man/lock_make_stable.html new file mode 100755 index 000000000..53a306df6 --- /dev/null +++ b/osfmk/man/lock_make_stable.html @@ -0,0 +1 @@ +

lock_make_stable


Function - Stabilize the state of the specified lock.

SYNOPSIS

kern_return_t   lock_make_stable
                (lock_set_t                            lock_set,
                 int                                    lock_id);

PARAMETERS

lock_set
[in send right] The port naming the lock set which represents the lock.

lock_id
[in scalar] The lock, represented by the lock set, to be stabilized.

DESCRIPTION

The lock_make_stable function clears the specified lock's unstable state, making the lock's state stable again.

RETURN VALUES

KERN_INVALID_ARGUMENT
The specified lock set is invalid, or the lock id is out of range.

KERN_INVALID_RIGHT
The caller does not own the specified lock.

KERN_SUCCESS
The lock's state was stabilized.

KERN_LOCK_SET_DESTROYED
The specified lock has been destroyed.

RELATED INFORMATION

Functions: lock_acquire, lock_release, lock_try, lock_handoff, lock_handoff_accept, lock_set_create, lock_set_destroy. \ No newline at end of file diff --git a/osfmk/man/lock_release.html b/osfmk/man/lock_release.html new file mode 100755 index 000000000..2fc3d3f13 --- /dev/null +++ b/osfmk/man/lock_release.html @@ -0,0 +1 @@ +

lock_release


Function - Release ownership of a lock.

SYNOPSIS

kern_return_t   lock_release
                (lock_set_t                            lock_set,
                 int                                    lock_id);

PARAMETERS

lock_set
[in send right] The port naming the lock set which represents the lock.

lock_id
[in scalar] The lock, represented by the lock set, to be released.

DESCRIPTION

The lock_release function release the ownership of the specified lock. If the calling thread does not own the lock then the call will fail.

RETURN VALUES

KERN_INVALID_ARGUMENT
The specified lock_set is invalid, or the lock_id is out of range.

KERN_INVALID_RIGHT
The specified task does not own the specified lock.

KERN_SUCCESS
The ownership of the lock was released.

KERN_LOCK_SET_DESTROYED
The specified lock has been destroyed.

RELATED INFORMATION

Functions: lock_acquire, lock_make_stable, lock_try, lock_handoff, lock_handoff_accept, lock_set_create, lock_set_destroy. \ No newline at end of file diff --git a/osfmk/man/lock_set_create.html b/osfmk/man/lock_set_create.html new file mode 100755 index 000000000..f87df20ee --- /dev/null +++ b/osfmk/man/lock_set_create.html @@ -0,0 +1 @@ +

lock_set_create


Function - Create a new lock set.

SYNOPSIS

kern_return_t   lock_set_create
                (task_t                                    task,
                 lock_set_t                            lock_set,
                 int                                      locks,
                 int                                     policy);

PARAMETERS

task
The task receiving the send right to the newly created lock set.

lock_set
[out send right] The port naming the lock set which represents the lock.

locks
[in scalar] The number of locks the lock set will represent (must be a positive value).

policy
[in scalar] The blocked thread wakeup policy for the newly created lock set. Valid policies are:

SYNC_POLICY_FIFO
a first-in-first-out policy for scheduling thread wakeup.

SYNC_POLICY_FIXED_PRIORITY
a fixed priority policy for scheduling thread wakeup.

DESCRIPTION

The lock_set_create function creates a new lock set representing a collection of associated locks. The lock set is associated with the specified task. A send right naming the lock set is returned to the caller.

RETURN VALUES

KERN_SUCCESS
The lock set was created.

KERN_INVALID_ARGUMENT
Either the task or policy argument is invalid, or the locks argument has a value that is less than or equal to zero.

KERN_RESOURCE_SHORTAGE
The kernel could not allocate the lock set.

RELATED INFORMATION

Functions: lock_acquire, lock_make_stable, lock_try, lock_handoff, lock_handoff_accept, lock_try, lock_set_destroy. \ No newline at end of file diff --git a/osfmk/man/lock_set_destroy.html b/osfmk/man/lock_set_destroy.html new file mode 100755 index 000000000..aa81470ea --- /dev/null +++ b/osfmk/man/lock_set_destroy.html @@ -0,0 +1 @@ +

lock_set_destroy


Function - Destroy a lock set and its associated locks.

SYNOPSIS

kern_return_t   lock_set_destroy
                (task_t                                    task,
                 lock_set_t                            lock_set);

PARAMETERS

task
The task associated with the lock set.

lock_set
[in send right] The port naming the lock set being destroyed.

DESCRIPTION

The lock_set_destroy function will destroy a lock set and all of its associated locks. Threads that are blocked on locks represented by the destroyed lock set are unblocked and will receive a KERN_LOCK_SET_DESTROYED error message indicating that the lock set was destroyed. The lock_set_destroy function will only succeed if the specified task is associated with the specified lock set.

RETURN VALUES

KERN_INVALID_ARGUMENT
The specified lock set or task is invalid.

KERN_INVALID_RIGHT
The specified task does not own the specified lock set.

KERN_LOCK_SET_DESTROYED
The specified lock set does not exist.

KERN_SUCCESS
The lock set was destroyed.

RELATED INFORMATION

Functions: lock_acquire, lock_make_stable, lock_try, lock_handoff, lock_handoff_accept, lock_try, lock_set_create. \ No newline at end of file diff --git a/osfmk/man/lock_try.html b/osfmk/man/lock_try.html new file mode 100755 index 000000000..2fe0a676b --- /dev/null +++ b/osfmk/man/lock_try.html @@ -0,0 +1 @@ +

lock_try


Function - Attempt to acquire access rights to a lock.

SYNOPSIS

kern_return_t   lock_try
                (lock_set_t                            lock_set,
                 int                                    lock_id);

PARAMETERS

lock_set
[in send right] The port naming the lock set which represents the lock.

lock_id
[in scalar] The lock, represented by the lock set, to be acquired.

DESCRIPTION

The lock_try function attempts to acquire the specified lock without blocking. The return value indicates whether the lock was acquired.

RETURN VALUES

KERN_INVALID_ARGUMENT
The specified lock_set is invalid, or the lock_id is out of range.

KERN_SUCCESS
The lock was acquired.

KERN_LOCK_UNSTABLE
The acquired lock has an unstable state.

KERN_LOCK_SET_DESTROYED
The specified lock has been destroyed.

KERN_LOCK_OWNED
Another thread currently owns the requested lock.

KERN_LOCK_OWNED_SELF
The calling thread already owns the lock.

RELATED INFORMATION

Functions: lock_acquire, lock_make_stable, lock_release, lock_handoff, lock_handoff_accept, lock_set_create, lock_set_destroy. \ No newline at end of file diff --git a/osfmk/man/mach_host_self.html b/osfmk/man/mach_host_self.html new file mode 100755 index 000000000..7294f4794 --- /dev/null +++ b/osfmk/man/mach_host_self.html @@ -0,0 +1 @@ +

mach_host_self


System Trap - Returns the host self port

SYNOPSIS

host_name_port_t   mach_host_self( void );

PARAMETERS

None.

DESCRIPTION

The mach_host_self function returns send rights to the task's host self port. By default, this is the name port for the current host but can be a different value if so set.

RETURN VALUES

[host-self send right] Send rights to the host's name port.

RELATED INFORMATION

Functions: host_info, task_set_special_port. \ No newline at end of file diff --git a/osfmk/man/mach_msg.html b/osfmk/man/mach_msg.html new file mode 100755 index 000000000..bf700cd34 --- /dev/null +++ b/osfmk/man/mach_msg.html @@ -0,0 +1 @@ +

mach_msg


System Trap / Function - Send and/or receive a message from the target port.

SYNOPSIS

mach_msg_return_t   mach_msg
                    (mach_msg_header_t                msg,
                     mach_msg_option_t             option,
                     mach_msg_size_t            send_size,
                     mach_msg_size_t        receive_limit,
                     mach_port_t             receive_name,
                     mach_msg_timeout_t           timeout,
                     mach_port_t                   notify);

mach_msg_return_t   mach_msg_overwrite
                    (mach_msg_header_t*          send_msg,
                     mach_msg_option_t             option,
                     mach_msg_size_t            send_size,
                     mach_msg_size_t        receive_limit,
                     mach_port_t             receive_name,
                     mach_msg_timeout_t           timeout,
                     mach_port_t                   notify,
                     mach_msg_header_t       *receive_msg,
                     mach_msg_size_t     receive_msg_size);

PARAMETERS

msg
[pointer to in/out structure containing random and reply rights] A message buffer used by mach_msg both for send and receive. This must be naturally aligned.

send_msg
[pointer to in structure containing random and reply rights] The mes- sage buffer to be sent. This must be naturally aligned.

option
[in scalar] Message options are bit values, combined with bitwise-or. One or both of MACH_SEND_MSG and MACH_RCV_MSG should be used. Other options act as modifiers.

send_size
[in scalar] When sending a message, specifies the size of the message buffer to be sent (the size of the header and body) in bytes. Otherwise zero should be supplied.

receive_limit
[in scalar] When receiving a message, specifies the maximum size of the msg or receive_msg buffer in bytes. Otherwise zero should be sup- plied.

receive_name
[in random right] When receiving a message, specifies the port or port set. Otherwise MACH_PORT_NULL should be supplied.

timeout
[in scalar] When using the MACH_SEND_TIMEOUT and MACH_RCV_TIMEOUT options, specifies the time in milliseconds to wait before giving up. Otherwise MACH_MSG_TIMEOUT_NONE should be supplied.

notify
[in notify receive right] When using the MACH_SEND_CANCEL and MACH_RCV_NOTIFY options, specifies the port used for the notification. Otherwise MACH_PORT_NULL should be supplied.

receive_msg
[pointer to in/out structure] A message buffer into which a message (header and body) will be received. This must be naturally aligned. By default (mach_msg), any received message will overwrite the send message buffer. This buffer is in/out only if the MACH_RCV_OVERWRITE option is used; otherwise this buffer is out only.

receive_msg_size
[in scalar] When using the MACH_RCV_OVERWRITE option, specifies the size (in bytes) of the receive "message" that is to be used by mach_msg to indicate the disposition of received out-of-line regions.

DESCRIPTION

The mach_msg system call sends and receives Mach messages. Mach messages contain data, which can include port rights and addresses of large regions of memory. mach_msg uses the same buffer for sending and receiving a message; the other calls permit separate send and receive buffers (although they may be specified to be the same). If the option argument contains MACH_SEND_MSG, the call sends a message. The send_size argument specifies the size of the message buffer (header and body) to send. The msgh_remote_port field of the message header specifies the destination of the message. If the option argument contains MACH_RCV_MSG, it receives a message. The receive_limit argument specifies the size of a buffer that will receive the message; messages that are larger are not received. The receive_name argument specifies the port or port set from which to receive.

If the option argument contains both MACH_SEND_MSG and MACH_RCV_MSG, then mach_msg does both send and receive operations (in that order). If the send operation encounters an error (any return code other than MACH_MSG_SUCCESS), the call returns immediately without attempting the receive operation. Semantically the combined call is equivalent to separate send and receive calls, but it saves a system call and enables other internal optimizations. If the option argument specifies neither MACH_SEND_MSG nor MACH_RCV_MSG, mach_msg does nothing. Some options, like MACH_SEND_TIMEOUT and MACH_RCV_TIMEOUT, share a supporting argument. If these options are used together, they make independent use of the supporting argument's value.

NOTES

The Mach kernel provides message-oriented, capability-based inter-process communication. The inter-process communication (IPC) primitives efficiently support many different styles of interaction, including remote procedure calls, object-oriented distributed programming, streaming of data, and sending very large amounts of data.

Major Concepts

The IPC primitives operate on three abstractions: messages, ports, and port sets. User tasks access all other kernel services and abstractions via the IPC primitives.

The message primitives let tasks send and receive messages. Tasks send messages to ports. Messages sent to a port are delivered reliably (messages may not be lost) and are received in the order in which they were sent via send rights by a given sending task (or a given kernel). (Messages sent to send-once rights are unordered.)

Messages contain a fixed-size header and a variable-sized message body containing kernel and user data, and a variable-size trailer of kernel appended message attributes. The header describes the destination and the size of the message (header plus body). The message body contains descriptions of additional port rights to be transmitted, descriptions of "out-of-line" memory regions to be sent and a variable amount of user data, which typically includes type conversion information. The out-of-line memory regions (including out-of-line port arrays) are (typically) disjoint from the message body. The IPC implementation makes use of the VM system to efficiently transfer large amounts of data. The message can contain the addresses of regions of the sender's address space which should be transferred as part of the message.

When a task receives a message containing such out-of-line regions of data, the data can appear in unused portions or overwrite an existing portion of the receiver's address space (depending on the requested receive options). Under favorable circumstances, the transmission of out-of-line data is optimized so that sender and receiver share the physical pages of data copy-on-write, and no actual data copy occurs unless the pages are written. Regions of memory up to 4 gigabytes may be sent in this manner.

Ports hold a queue of messages. Tasks operate on a port to send and receive messages by exercising capabilities (rights) for the port. Multiple tasks can hold send rights for a port. Tasks can also hold send-once rights, which grant the ability to send a single message. Only one task can hold the receive capability (receive right) for a port.

Port rights can be transferred between tasks via messages. The sender of a message can specify in the message that the message contains a port right. If a message contains a receive right for a port, the receive right is removed from the sender of the message and transferred to the receiver of the message. While the receive right is in transit, tasks holding send rights can still send messages to the port, and they are queued until a task acquires the receive right and uses it to receive the messages.

Tasks can receive messages from ports and port sets. The port set abstraction allows a single thread to wait for a message from any of several ports. Tasks manipulate port sets with a port set name, which is taken from the same name space as are the port rights. The port-set name may not be transferred in a message. A port set holds receive rights, and a receive operation on a port set blocks waiting for a message sent to any of the constituent ports. A port may not be- long to more than one port set, and if a port is a member of a port set, the holder of the receive right can't receive directly from the port.

Port rights are a secure, location-independent way of naming ports. The port queue is a protected data structure, only accessible via the kernel's exported message primitives. Rights are also protected by the kernel; there is no way for a malicious user task to guess a port's internal name and send a message to a port to which it shouldn't have access. Port rights do not carry any location in- formation. When a receive right for a port moves from task to task, and even between tasks on different machines, the send rights for the port remain unchanged and continue to function.

Port Rights

Each task has its own space of port rights. Port rights are named with positive (unsigned) integers. For all architectures, sizeof (mach_port_t) = sizeof (mach_port_name_t) = sizeof (void*) and so user space addresses may be used as port names, except for the reserved values MACH_PORT_NULL (0) and MACH_PORT_DEAD (all 1 bits). When the kernel chooses a name for a new right, however, it is free to pick any unused name (one which denotes no right) in the space.

There are three basic kinds of rights: receive rights, send rights and send-once rights. A port name can name any of these types of rights, or name a port-set, be a dead name, or name nothing. Dead names are not capabilities. They act as place-holders to prevent a name from being otherwise used.

A port is destroyed, or dies, when its receive right is de-allocated. When a port dies, send and send-once rights for the port turn into dead names. Any messages queued at the port are destroyed, which de-allocates the port rights and out-of-line memory in the messages.

Each send-once right held by a task has a different name. In contrast, when a task holds send rights or a receive right for a port, the rights share a single name.

Tasks may hold multiple user-references for send rights. When a task receives a send right which it already holds, the kernel increments the right's user-reference count. When a task de-allocates a send right, the kernel decrements its user-reference count, and the task only loses the send right when the count goes to zero.

Send-once rights always have a user reference count of one. Tasks may hold multiple user references for dead names. Each send-once right generated guarantees the receipt of a single message, either a message sent to that send-once right or, if the send-once right is in any way destroyed, a send-once notification.

A message can carry port rights; the msgh_remote or msgh_local fields in the message header or the disposition field in a message body descriptor specify the type of port right and how the port right is to be extracted from the caller. The values MACH_PORT_NULL and MACH_PORT_DEAD are valid in place of a port right in a message body.

In a sent message, the following mach_msg_type_name_t values denote port rights:

MACH_MSG_TYPE_MAKE_SEND
The message will carry a send right, but the caller must supply a receive right. The send right is created from the receive right, and the receive right's make-send count is incremented.
MACH_MSG_TYPE_COPY_SEND
The message will carry a send right, and the caller must supply a send right. The user reference count for the supplied send right is not changed. The caller may also supply a dead name and the receiving task will get MACH_PORT_DEAD.
MACH_MSG_TYPE_MOVE_SEND
The message will carry a send right, and the caller must supply a send right. The user reference count for the supplied send right is decremented, and the right is destroyed if the count becomes zero. Unless a receive right remains, the name becomes available for recycling. The caller may also supply a dead name, which loses a user reference, and the receiving task will get MACH_PORT_DEAD.
MACH_MSG_TYPE_MAKE_SEND_ONCE
The message will carry a send-once right, but the caller must supply a receive right. The send-once right is created from the receive right. Note that send once rights can only be created from the receive right.
MACH_MSG_TYPE_MOVE_SEND_ONCE
The message will carry a send-once right, and the caller must supply a send-once right. The caller loses the supplied send-once right. The caller may also supply a dead name, which loses a user reference, and the receiving task will get MACH_PORT_DEAD.
MACH_MSG_TYPE_MOVE_RECEIVE
The message will carry a receive right, and the caller must supply a receive right. The caller loses the supplied receive right, but retains any send rights with the same name. The make-send count and sequence number of the receive right are reset to zero and no-more-senders notification requests are cancelled (with a send-once notification being sent to the no-more-senders notification right), but the port retains other attributes like queued messages and extant send and send-once rights. If a message carries a send or send-once right, and the port dies while the message is in transit, then the receiving task will get MACH_PORT_DEAD instead of a right.

The following mach_msg_type_name_t values in a received message indicate that it carries port rights:

MACH_MSG_TYPE_PORT_SEND
This value is an alias for MACH_MSG_TYPE_MOVE_SEND. The message carried a send right. If the receiving task already has send and/ or receive rights for the port, then that name for the port will be reused. Otherwise, the right will have a new, previously unused, name. If the task already has send rights, it gains a user reference for the right (un- less this would cause the user-reference count to overflow). Otherwise, it acquires send rights, with a user-reference count of one.
MACH_MSG_TYPE_PORT_SEND_ONCE
This value is an alias for MACH_MSG_TYPE_MOVE_SEND_ONCE. The message carried a send-once right. The right will have a new, previously unused, name.
MACH_MSG_TYPE_PORT_RECEIVE
This value is an alias for MACH_MSG_TYPE_MOVE_RECEIVE. The message carried a receive right. If the receiving task already has send rights for the port, then that name for the port will be reused; otherwise, the right will have a new, previously unused name.

It is also possible to send a (nearly unbounded) array of port rights "out-of-line". All of the rights named by the array must be of the same type. The array is physically copied with the message body proper. The array of port right (names) can be received by the receiver using the same options available for out-of-line data reception described below.

Memory

A message can contain one or more regions of the sender's address space which are to be transferred as part of the message. The message carries a logical copy of the memory. For this "out-of-line" memory, the kernel can copy the data or use virtual memory techniques to defer any actual page copies unless the sender or the receiver modifies the data, the physical pages remain shared.

The sender of the message must explicitly request an out-of-line transfer. Such a region is described as an arbitrary region of the sender's address space. The sender always sees this memory as being copied to the receiver.

For each region, the sender has a de-allocate option. If the option is set and the out-of-line memory region is not null, then the region is implicitly de-allocated from the sender, as if by vm_deallocate. In particular, the start address is truncated down and the end address rounded up so that every page overlapped by the memory region is de-allocated (thereby possibly de-allocating more memory than is effectively transmitted). The use of this option effectively changes the memory copy to a memory movement. Aside from possibly optimizing the sender's use of memory, the de-allocation option allows the kernel to more efficiently handle the transfer of memory.

For each region, the sender has the choice of permitting the kernel to choose a transmission strategy or the choice of requiring physical copy:

MACH_MSG_VIRTUAL_COPY
In a sent message, this flag allows the kernel to choose any mechanism to transmit the data. For large regions, this involves constructing a virtual copy of the pages containing the region. The portion of the first page preceding the data and the portion of the last page following the data are not copied (and will appear as zero if the virtual copy is dynamically allocated in the receiver).

In a received message, this flag indicates that the kernel transmitted a virtual copy. Access to the received memory may involve interactions with the memory manager managing the sender's original data. Integri- ty-conscious receivers should exercise caution when dealing with out- of-line memory from un-trustworthy sources. Receivers concerned about deterministic access time should also exercise caution. The dynamic allocation option guarantees that the virtual copy will not be di- rectly referenced during the act of receiving the message.

MACH_MSG_PHYSICAL_COPY
In a sent message, this flag requires that the kernel construct an actual copy of the memory (either into wired kernel memory or default memory managed space). There is a (fairly large) limit on the amount of data that can be physically copied in a message. Port arrays always assume this option when sent.

In a received message, this flag indicates that the kernel did transmit a physical copy.

The receiver has two options for the reception of out-of-line memory (or "out-of-line" port arrays): allocation and overwrite. In the absence of the MACH_RCV_OVERWRITE option, all out-of-line re- gions are dynamically allocated. Allocated out-of-line memory arrives somewhere in the receiver's address space as new memory. It has the same inheritance and protection attributes as newly vm_allocate'ed memory. The receiver has the responsibility of de-allocating (with vm_deallocate) the memory when it is no longer needed. If the message contains more than one region, each will be allocated its own region, not necessarily contiguously. If the sender's data was transmitted as a virtual copy the allocated region will have the same data alignment within the page; otherwise, the received data will appear starting at the beginning of a page.

If the MACH_RCV_OVERWRITE option is set, the receiver can specify how each received region is to be processed (dynamically allocated as described above, or written over existing memory). With this option, the contents of the receive buffer (receive_msg) are examined by the kernel. The kernel scans the descriptors in the receive buffer "message" to determine how to handle each out-of-line region. (Note: whereas receive_limit is the maximum size of the receive buffer, receive_msg_size is the amount filled in with this "message".) The kernel uses each out-of-line data descriptor (in order) to specify the processing for each received data region in turn, each out-of-line port array descriptor is used correspondingly. (Intermingled port descriptors are ignored when matching descriptors between the incoming message and the receive buffer list.)

The copy option in the matching descriptor specifies the processing:

MACH_MSG_OVERWRITE
This flag indicates that the region should write over a specified region of the receiver's address space, as indicated by the address and size/ count fields of the descriptor. The full range overwritten must already exist (be allocated or mapped) in the receiver's address space. Depending on the nature of the data transmission this overwrite may involve virtual memory manipulations or it may involve actual data copy.
MACH_MSG_ALLOCATE
This flag indicates that the region is to be dynamically allocated. No other descriptor values are relevant.

If not enough descriptors appear in the receive buffer to describe all received regions, additional regions are dynamically allocated. If the receiver specifies more descriptors than there are regions in the received message, the additional descriptors are ignored (and do not appear in the final received message).

Note that the receive buffer descriptors will be overwritten: The size fields in descriptors will be updated (when scanned, they specified the maximum sizes of regions, when received, they specify the actual sizes of received regions). The copy fields in descriptors will be updated (when scanned, they specified allocate versus overwrite, when received, they indicate whether the region was physically or virtually copied). The descriptors may appear in different positions (given intermingled port descriptors). Descriptors that were not used (because there were not that many received regions) will be discarded.

Null out-of-line memory is legal. If the out-of-line region size is zero, then the region's specified address is ignored. A receive allocated null out-of-line memory region always has a zero address. Unaligned addresses and region sizes that are not page multiples are legal. A received message can also contain regions with unaligned addresses and sizes which are not multiples of the page size.

Message Send

The send operation queues a message to a port. The message carries a copy of the caller's data. After the send, the caller can freely modify the message buffer or the out-of-line memory regions and the message contents will remain unchanged.

The message carries with it the security ID of the sender, which the receiver can request in the message trailer.

Message delivery is reliable and sequenced. Reception of a message guarantees that all messages previously sent to the port by a single task (or a single kernel) via send rights have been received and that they are received in the order in which they were sent. Messages sent to send-once rights are unordered.

If the destination port's queue is full, several things can happen. If the message is sent to a send-once right (msgh_remote_port carries a send-once right), then the kernel ignores the queue limit and delivers the message. Otherwise the caller blocks until there is room in the queue, unless the MACH_SEND_TIMEOUT option is used. If a port has several blocked senders, then any of them may queue the next message when space in the queue becomes available, with the proviso that a blocked sender will not be indefinitely starved. These options modify MACH_SEND_MSG. If MACH_SEND_MSG is not also specified, they are ignored.

MACH_SEND_TIMEOUT
The timeout argument should specify a maximum time (in milliseconds) for the call to block before giving up. If the message can't be queued before the timeout interval elapses, then the call returns MACH_SEND_TIMED_OUT. A zero timeout is legitimate.
MACH_SEND_INTERRUPT
If specified, the mach_msg call will return MACH_SEND_INTERRUPTED if a software interrupt aborts the call. Otherwise, the send operation will be retried.
MACH_SEND_TRAILER
If set, the kernel, instead of determining the message attributes itself, will accept a formatted message trailer from the sender. The supplied trailer must be of the latest version supported by the kernel, and must contain all message attributes defined by the kernel. Only tasks with a security ID of KERNEL_SECURITY_ID can use this option; the intended use of this option is in support of the Net Message server. The trailer must follow the message in memory as it would appear in a received message. (The send_size argument to mach_msg still indicates the size of the message proper, not including this trailer.)

The queueing of a message carrying receive rights may create a circular loop of receive rights and messages, which can never be received. For example, a message carrying a receive right can be sent to that receive right. This situation is not an error, but the kernel will garbage-collect such loops, destroying the messages. Some return codes, like MACH_SEND_TIMED_OUT, imply that the message was almost sent, but could not be queued. In these situations, the kernel tries to return the message contents to the caller with a pseudo-receive operation. This prevents the loss of port rights or memory which only exist in the message, for example, a receive right which was moved into the message, or out-of-line memory sent with the de-allocate option.

The intent of the pseudo-receive operation is to restore, as best as possible, the state prior to attempting the send. This involves restoring the port rights and out-of-line memory regions contained in the message. The port right names and out-of-line addresses in the message send buffer are updated to reflect the new values resulting from their effective reception. The pseudo-receive handles the des- tination and reply rights as any other rights; they are not reversed as is the appearance in a normal received message. Also, no trailer is appended to the message. After the pseudo-receive, the message is ready to be resent. If the message is not resent, note that out-of-line memory regions may have moved and some port rights may have changed names.

Although unlikely, the pseudo-receive operation may encounter resource shortages. This is similar to a MACH_RCV_BODY_ERROR return code from a receive operation. When this happens, the normal send return codes are augmented with the MACH_MSG_IPC_SPACE, MACH_MSG_VM_SPACE, MACH_MSG_IPC_KERNEL and MACH_MSG_VM_KERNEL bits to indicate the nature of the resource shortage.

Message Receive

The receive operation de-queues a message from a port. The receiving task acquires the port rights and out-of-line memory regions carried in the message. The receive_name argument specifies a port or port set from which to receive. If a port is specified, the caller must possess the receive right for the port and the port must not be a member of a port set. If no message is present, the call blocks, subject to the MACH_RCV_TIMEOUT option.

If a port set is specified, the call will receive a message sent to any of the member ports. It is permissible for the port set to have no member ports, and ports may be added and removed while a receive from the port set is in progress. The received message can come from any of the member ports which have messages, with the proviso that a member port with messages will not be indefinitely starved. The msgh_local_port field in the received message header specifies from which port in the port set the message came.

The receive_limit argument specifies the size of the caller's message buffer (which must be big enough for the message header, body and trailer); the msgh_size field of the received message indicates the actual size of the received message header and body. The mach_msg call will not receive a message larger than receive_limit. Messages that are too large are destroyed, unless the MACH_RCV_LARGE option is used. Following the received data, at the next natural boundary, is a message trailer. The msgh_size field of the received message does not include the length of this trailer; the trailer's length is given by the msgh_trailer_size field within the trailer. The receiver of a message is given a choice as to what trailer format is desired, and, within that format, which of the leading trailer attributes are desired (that is, to get trailer element three, the receiver must also accept elements one and two). For any given trailer format (of which there is currently only one), the trailer is compatibly extended by adding additional elements to the end.

Received messages are stamped (in the trailer) with a sequence number, taken from the port from which the message was received. (Messages received from a port set are stamped with a sequence number from the appropriate member port.) Newly created ports start with a zero sequence number, and the sequence number is reset to zero whenever the port's receive right moves between tasks. When a message is de-queued from the port, it is stamped with the port's sequence number and the port's sequence number is then incremented. (Note that this occurs whether or not the receiver requests the sequence number in the trail- er.) The de-queue and increment operations are atomic, so that multiple threads receiving messages from a port can use the msgh_seqno field to reconstruct the original order of the messages.

The destination and reply ports are reversed in a received message header. The msgh_local_port field carries the name of the destination port, from which the message was received, and the msgh_remote_port field carries the reply port right. The bits in msgh_bits are also reversed. The MACH_MSGH_BITS_LOCAL bits have a value of MACH_MSG_TYPE_PORT_SEND_ONCE or MACH_MSG_TYPE_PORT_SEND depending on the type of right to which the message was sent. The MACH_MSGH_BITS_REMOTE bits describe the reply port right.

A received message can contain port rights and out-of-line memory. The msgh_local_port field does not carry a port right; the act of receiving the message consumes the send or send-once right for the destination port. The msgh_remote_port field does carry a port right, and the message can carry additional port rights and memory if the MACH_MSGH_BITS_COMPLEX bit is set. Received port rights and memory should be consumed or de-allocated in some fashion. In almost all cases, msgh_local_port will specify the name of a receive right, either receive_name, or, if receive_name is a port set, a member of receive_name.

If other threads are concurrently manipulating the receive right, the situation is more complicated. If the receive right is renamed during the call, then msgh_local_port specifies the right's new name. If the caller loses the receive right after the message was de-queued from it, then mach_msg will proceed instead of returning MACH_RCV_PORT_DIED. If the receive right was destroyed, then msgh_local_port specifies MACH_PORT_DEAD. If the receive right still exists, but isn't held by the caller, then msgh_local_port specifies MACH_PORT_NULL.

The following options modify MACH_RCV_MSG. If MACH_RCV_MSG is not also specified, they are ignored.

MACH_RCV_TIMEOUT
The timeout argument should specify a maximum time (in milliseconds) for the call to block before giving up. If no message arrives before the timeout interval elapses, then the call returns MACH_RCV_TIMED_OUT. A zero timeout is legitimate.
MACH_RCV_NOTIFY
The notify argument should specify a receive right for a notify port. If receiving the reply port creates a new port right in the caller, then the notify port is used to request a dead-name notification for the new port right.
MACH_RCV_INTERRUPT
If specified, the mach_msg call will return MACH_RCV_INTERRUPTED if a software interrupt aborts the call. Otherwise, the receive operation will be retried.
MACH_RCV_OVERWRITE
If specified, the message buffer specified by receive_msg (or msg), of length receive_msg_size, will be scanned for out-of-line descriptors to specify the processing to be done when receiving out-of-line regions. This option is only allowed for mach_msg_overwrite.
MACH_RCV_LARGE
If the message is larger than receive_limit or an out-of-line region is larger than the size allowed by a corresponding receive descriptor (MACH_RCV_OVERWRITE), the message remains queued instead of being destroyed. If the header, trailer and body would not fit into receive_limit, only the message header (mach_msg_header) and trailer header (mach_msg_trailer) are returned with the actual size of the message returned in the msgh_size field, the actual size of the trailer returned in the msgh_trailer_size field and an error return value of MACH_RCV_TOO_LARGE. If receive_limit is sufficient but an out-of-line descriptor is not, the message header, trailer and body are received, with out-of-line descriptors set to indicate the nature and size of the out-of-line regions, with an error return of MACH_RCV_SCATTER_SMALL. No out-of-line regions or port rights (including the reply right) will be received. If this option is not specified, messages too large will be de-queued and then destroyed; the caller receives the message header, with all fields correct, including the destination port but excepting the reply port, which is MACH_PORT_NULL and an empty (no additional element) message trailer.
MACH_RCV_TRAILER_TYPE(value)
This macro encodes the type of trailer the kernel must return with the message. If the kernel does not recognize this type, it returns MACH_RCV_INVALID_TRAILER. Currently, only MACH_MSG_TRAILER_FORMAT_0 is supported.
MACH_RCV_TRAILER_ELEMENTS(value)
This macro encodes the number of trailer elements desired. If the ker- nel does not support this number for the requested trailer type, the kernel returns MACH_RCV_INVALID_TRAILER. Zero is a legal value.

The following trailer elements are supported:

MACH_RCV_TRAILER_SEQNO
Returns the sequence number of the message relative to its port. This value is of type mach_port_seqno_t.
MACH_RCV_TRAILER_SENDER
Returns the security ID of the task that sent the message. This value is of type security_id_t.

If a resource shortage prevents the reception of a port right, the port right is destroyed and the caller sees the name MACH_PORT_NULL. If a resource shortage prevents the reception of an out-of-line memory region, the region is destroyed and the caller sees a zero address. In addition, the corresponding element in the size array is set to zero. A task never receives port rights or memory for which it is not told.

The MACH_RCV_HEADER_ERROR return code indicates a resource shortage in the reception of the message header. The reply port and all port rights and memory in the message are destroyed. The caller receives the message header with all fields correct except for the reply port.

The MACH_RCV_BODY_ERROR return code indicates a resource shortage in the reception of the message body. The message header, including the reply port, is correct. The kernel attempts to transfer all port rights and memory regions in the body, and only destroys those that can't be transferred.

Atomicity

The mach_msg call handles port rights in the message header atomically. Out-of-line memory and port rights in the message body do not enjoy this atomicity guarantee. These elements may be processed front-to-back, back-to-front, in some random order, or even atomically.

For example, consider sending a message with the destination port specified as MACH_MSG_TYPE_MOVE_SEND and the reply port specified as MACH_MSG_TYPE_COPY_SEND. The same send right, with one user-refer- ence, is supplied for both the msgh_remote_port and msgh_local_port fields. Because mach_msg processes the port rights atomically, this succeeds. If msgh_remote_port were processed before msgh_local_port, then mach_msg would return MACH_SEND_INVALID_REPLY in this situation.

On the other hand, suppose the destination and reply port are both specified as MACH_MSG_TYPE_MOVE_SEND, and again the same send right with one user-reference is supplied for both. Now the send operation fails, but because it processes the rights atomically, mach_msg can return either MACH_SEND_INVALID_DEST or MACH_SEND_INVALID_REPLY.

For example, consider receiving a message at the same time another thread is deallocating the destination receive right. Suppose the reply port field carries a send right for the destination port. If the de-allocation happens before the dequeuing, the receiver gets MACH_RCV_PORT_DIED. If the de-allocation happens after the receive, the msgh_local_port and the msgh_remote_port fields both specify the same right, which becomes a dead name when the receive right is de-allocated. If the de-allocation happens between the de-queue and the receive, the msgh_local_port and msgh_remote_port fields both specify MACH_PORT_DEAD. Because the rights are processed atomically, it is not possible for just one of the two fields to hold MACH_PORT_DEAD.

The MACH_RCV_NOTIFY option provides a more likely example. Suppose a message carrying a send-once right reply port is received with MACH_RCV_NOTIFY at the same time the reply port is destroyed. If the reply port is destroyed first, then msgh_remote_port specifies MACH_PORT_DEAD and the kernel does not generate a dead-name notification. If the reply port is destroyed after it is received, then msgh_remote_port specifies a dead name for which the kernel generates a dead-name notification. Either the reply port is dead on arrival or notification is requested.

Implementation

mach_msg and mach_msg_overwrite are wrappers for a system call. They have the responsibility for repeating the interrupted system call.

CAUTIONS

If MACH_RCV_TIMEOUT is used without MACH_RCV_INTERRUPT, then the timeout duration might not be accurate. When the call is interrupted and automatically retried, the original timeout is used. If interrupts occur frequently enough, the timeout interval might never expire. MACH_SEND_TIMEOUT without MACH_SEND_INTERRUPT suffers from the same problem.

RETURN VALUES

The send operation can generate the following return codes. These return codes imply that the call did nothing:

MACH_SEND_MSG_TOO_SMALL
The specified send_size was smaller than the minimum size for a message.

MACH_SEND_NO_BUFFER
A resource shortage prevented the kernel from allocating a message buffer.

MACH_SEND_INVALID_DATA
The supplied message buffer was not readable.

MACH_SEND_INVALID_HEADER
The msgh_bits value was invalid.

MACH_SEND_INVALID_DEST
The msgh_remote_port value was invalid.

MACH_SEND_INVALID_NOTIFY
When using MACH_SEND_CANCEL, the notify argument did not denote a valid receive right.

MACH_SEND_INVALID_REPLY
The msgh_local_port value was invalid.

MACH_SEND_INVALID_TRAILER
The trailer to be sent does not correspond to the current kernel format, or the sending task does not have the privilege to supply the message attributes.

These return codes imply that some or all of the message was destroyed:

MACH_SEND_INVALID_MEMORY
The message body specified out-of-line data that was not readable.

MACH_SEND_INVALID_RIGHT
The message body specified a port right which the caller didn't possess.

MACH_SEND_INVALID_TYPE
A kernel processed descriptor was invalid.

MACH_SEND_MSG_TOO_SMALL
The last data item in the message ran over the end of the message.

These return codes imply that the message was returned to the caller with a pseudo-receive operation:

MACH_SEND_TIMED_OUT
The timeout interval expired.

MACH_SEND_INTERRUPTED
A software interrupt occurred.

This return code implies that the message was queued:

MACH_MSG_SUCCESS
The message was queued.

The receive operation can generate the following return codes. These return codes imply that the call did not de-queue a message:

MACH_RCV_INVALID_NAME
The specified receive_name was invalid.

MACH_RCV_IN_SET
The specified port was a member of a port set.

MACH_RCV_TIMED_OUT
The timeout interval expired.

MACH_RCV_INTERRUPTED
A software interrupt occurred.

MACH_RCV_PORT_DIED
The caller lost the rights specified by receive_name.

MACH_RCV_PORT_CHANGED
receive_name specified a receive right which was moved into a port set during the call.

MACH_RCV_TOO_LARGE
When using MACH_RCV_LARGE, the message was larger than receive_limit. The message is left queued, and its actual size is returned in the message header/message body.

MACH_RCV_SCATTER_SMALL
When using MACH_RCV_LARGE with MACH_RCV_OVERWRITE, one or more scatter list descriptors specified an overwrite region smaller than the corresponding incoming region. The message is left queued, and the proper descriptors are returned in the message header/message body.

MACH_RCV_INVALID_TRAILER
The trailer type desired, or the number of trailer elements desired, is not supported by the kernel.

These return codes imply that a message was de-queued and destroyed:

MACH_RCV_HEADER_ERROR
A resource shortage prevented the reception of the port rights in the message header.

MACH_RCV_INVALID_NOTIFY
When using MACH_RCV_NOTIFY, the notify argument did not denote a valid receive right.

MACH_RCV_INVALID_DATA
The specified message buffer was not writable.

MACH_RCV_TOO_LARGE
When not using MACH_RCV_LARGE, a message larger than receive_limit was de-queued and destroyed.

MACH_RCV_SCATTER_SMALL
When not using MACH_RCV_LARGE with MACH_RCV_OVERWRITE, one or more scatter list descriptors specified an overwrite region smaller than the corresponding incoming region. The message was de-queued and destroyed.

MACH_RCV_OVERWRITE_ERROR
A region specified by a receive overwrite descriptor (MACH_RCV_OVERWRITE) was not allocated or could not be written.

MACH_RCV_INVALID_TYPE
When using MACH_RCV_OVERWRITE, one or more scatter list descriptors did not have the type matching the corresponding incoming message descriptor or had an invalid copy (disposition) field.

MACH_RCV_LIMITS
The combined size of all out-of-line memory regions or the total num- ber of port rights in the message exceeds the limit set for the port. These return codes imply that a message was received:

MACH_RCV_BODY_ERROR
A resource shortage prevented the reception of a port right or out-of- line memory region in the message body.

MACH_MSG_SUCCESS
A message was received.

Resource shortages can occur after a message is de-queued, while transferring port rights and out-of-line memory regions to the receiving task. The mach_msg call returns MACH_RCV_HEADER_ERROR or MACH_RCV_BODY_ERROR in this situation. These return codes always carry extra bits (bitwise-or'ed) that indicate the nature of the resource shortage:

MACH_MSG_IPC_SPACE
There was no room in the task's IPC name space for another port name.

MACH_MSG_VM_SPACE
There was no room in the task's VM address space for an out-of-line memory region.

MACH_MSG_IPC_KERNEL
A kernel resource shortage prevented the reception of a port right.

MACH_MSG_VM_KERNEL
A kernel resource shortage prevented the reception of an out-of-line memory region.

RELATED INFORMATION

Functions: vm_allocate, vm_deallocate, vm_write, mach_port_request_notification,

Data Structures: mach_msg_header. \ No newline at end of file diff --git a/osfmk/man/mach_msg_descriptor.html b/osfmk/man/mach_msg_descriptor.html new file mode 100755 index 000000000..a44bf90bb --- /dev/null +++ b/osfmk/man/mach_msg_descriptor.html @@ -0,0 +1 @@ +

mach_msg_descriptor


Structure - Specifies operations that must be performed on a given IPC message element.

SYNOPSIS

typedef struct
{
       void*                             pad1;
       mach_msg_size_t                   pad2;
       unsigned int                      pad3 : 24;
       mach_msg_descriptor_type_t        type : 8;
} mach_msg_type_descriptor_t;

typedef struct
{
       mach_port_t                       name;
       mach_msg_size_t                   pad1;
       unsigned int                      pad2 : 16;
       mach_msg_type_name_t       disposition : 8;
       mach_msg_descriptor_type_t        type : 8;
} mach_msg_port_descriptor_t;

typedef struct
{
       void*                          address;
       mach_msg_size_t                   size;
       boolean_t                   deallocate : 8;
       mach_msg_copy_options_t           copy : 8;
       unsigned int                      pad1 : 8;
       mach_msg_descriptor_type_t        type : 8;
} mach_msg_ool_descriptor_t;

typedef struct
{
       void*                           address;
       mach_msg_size_t                   count;
       boolean_t                    deallocate : 8;
       mach_msg_copy_options_t            copy : 8;
       mach_msg_type_name_t        disposition : 8;
       mach_msg_descriptor_type_t         type : 8;
} mach_msg_ool_ports_descriptor_t;

typedef union
{
       mach_msg_port_descriptor_t             port;
       mach_msg_ool_descriptor_t       out_of_line;
       mach_msg_ool_ports_descriptor_t   ool_ports;
       mach_msg_type_descriptor_t             type;
} mach_msg_descriptor_t;

FIELDS

name
For single port descriptors, the name of the port whose right is being sent.

disposition
For single port or out-of-line port array descriptors, the IPC processing to be done for the rights for the named ports.

address
For out-of-line data or port array descriptors, the address of the out-of-line data or port (name) array.

size
For out-of-line data descriptors, the size of the out-of-line region, in bytes.

deallocate
For out-of-line data descriptors, true if the set of pages containing the array should be de-allocated when the message is sent.

copy
For out-of-line descriptors, a description of the method by which the data should be copied.

count
For out-of-line port array descriptors, the number of port names in the array.

type
For any type of descriptor, the type of descriptor.

port
A descriptor that describes a single port right.

out_of_line
A descriptor that describes an out-of-line data array.

ool_ports
A descriptor that describes an out-of-line port array.

DESCRIPTION

A mach_msg_descriptor structure describes the processing to be performed for an element of kernel-processed data in a Mach message.

RELATED INFORMATION

Functions: mach_msg.

Data Structures: mach_msg_header. \ No newline at end of file diff --git a/osfmk/man/mach_msg_header.html b/osfmk/man/mach_msg_header.html new file mode 100755 index 000000000..891598f1b --- /dev/null +++ b/osfmk/man/mach_msg_header.html @@ -0,0 +1 @@ +

mach_msg_header


Structure - Specifies the content of an IPC message header.

SYNOPSIS

typedef struct
{
       mach_msg_bits_t                     msgh_bits;
       mach_msg_size_t                     msgh_size;
       mach_port_t                  msgh_remote_port;
       mach_port_t                   msgh_local_port;
       mach_msg_size_t                 msgh_reserved;
       mach_msg_id_t                         msgh_id;
} mach_msg_header_t;

typedef struct
{
       mach_msg_size_t         msgh_descriptor_count;
} mach_msg_body_t;

typedef struct
{
       mach_msg_trailer_type_t     msgh_trailer_type;
       mach_msg_trailer_size_t     msgh_trailer_size;
} mach_msg_trailer_t;

typedef struct
{
       mach_msg_trailer_type_t     msgh_trailer_type;
       mach_msg_trailer_size_t     msgh_trailer_size;
       mach_port_seqno_t                  msgh_seqno;
} mach_msg_seqno_trailer_t;

typedef struct
{
       mach_msg_trailer_type_t    msgh_trailer_type;
       mach_msg_trailer_size_t    msgh_trailer_size;
       mach_port_seqno_t                 msgh_seqno;
       security_token_t                 msgh_sender;
} mach_msg_security_trailer_t;

typedef struct
{
       mach_msg_trailer_type_t    msgh_trailer_type;
       mach_msg_trailer_size_t    msgh_trailer_size;
       mach_port_seqno_t                 msgh_seqno;
       security_token_t                  msgh_sender;
       unsigned int                 dipc_sender_kmsg;
} mach_msg_dipc_trailer_t;

FIELDS

msgh_bits
This field specifies the following properties of the message:

MACH_MSGH_BITS_REMOTE_MASK
Encodes mach_msg_type_name_t values that specify the port rights in the msgh_remote_port field. The value must specify a send or send-once right for the destination of the message.

MACH_MSGH_BITS_LOCAL_MASK
Encodes mach_msg_type_name_t values that specify the port rights in the msgh_local_port field. If the value doesn't specify a send or send-once right for the message's reply port, it must be zero and msgh_local_port must be MACH_PORT_NULL.

MACH_MSGH_BITS_COMPLEX
The complex bit must be specified if the message body contains additional port rights or out-of-line memory regions.

MACH_MSGH_BITS_REMOTE(bits)
This macro returns the appropriate mach_msg_type_name_t values, given a msgh_bits value.

MACH_MSGH_BITS_LOCAL(bits)
This macro returns the appropriate mach_msg_type_name_t values, given a msgh_bits value.

MACH_MSGH_BITS(remote, local)
This macro constructs a value for msgh_bits, given two mach_msg_type_name_t values.

msgh_size
This field is ignored on send (the size to send is specified by the send_size parameter to mach_msg); the field is set on receive to the sum of the message header and body sizes (in bytes). Note that this value may be different from the send size specified by the sender if the sender and receiver machines have differing sizes for port names, memory addresses or memory range sizes.

msgh_remote_port
When sending, specifies the destination port of the message. The field must carry a legitimate send or send-once right for a port. When received, this field is swapped with msgh_local_port.

msgh_local_port
When sending, specifies an auxiliary port right, which is conventionally used as a reply port by the recipient of the message. The field must carry a send right, a send-once right, MACH_PORT_NULL, or MACH_PORT_DEAD. When received, this field is swapped with msgh_remote_port.

msgh_id
Not set or read by the mach_msg call. The conventional meaning is to convey an operation or function ID.

msgh_descriptor_count
The number of descriptors of kernel processed data (port rights and out-of-line data).

msgh_trailer_type
An identifier of the trailer version. Different values indicate not necessarily compatible trailer formats. The current (and only) trailer format is MACH_MSG_TRAILER_FORMAT_0. There is currently only one attribute defined within this trailer type: the sender's identity.

msgh_trailer_size
The length, in bytes, of the message trailer, including the trailer type and length fields.

msgh_seqno
The sequence number of this message relative to the port from which it is received.

msgh_sender
The security ID of the sender of the message.

DESCRIPTION

The mach_msg_header structure defines the fixed size header of a Mach message. The header is followed by a message body containing data and port descriptors and zero or more data bytes.

If the MACH_MSGH_BITS_COMPLEX flag in the msgh_bits field is not set, then this is a simple message described by mach_msg_header_t. In this case, the header is immediately followed by untyped data.

If the complex flag is set, then this is a "complex" message consisting of a mach_msg_header_t structure followed by a mach_msg_body_t structure containing a count followed by an array of descriptors specifying the disposition (processing) to be performed for the out-of-line memory regions and additional port rights.

Following the header (and any kernel processed descriptors), at natural alignment can be additional (un-typed) data, up to the size of the message (msgh_size). This extra data typically carries information used to decode the data stream and out-of-line data.

At the next natural boundary following the message data is the message trailer (mach_msg_trailer_t). This structure indicates the type and length of the trailer. If the length is greater than sizeof (mach_msg_trailer_t), additional fields follow providing kernel-generated message attributes.

RELATED INFORMATION

Functions: mach_msg.

Data Structures: mach_msg_descriptor. \ No newline at end of file diff --git a/osfmk/man/mach_port_allocate.html b/osfmk/man/mach_port_allocate.html new file mode 100755 index 000000000..997830684 --- /dev/null +++ b/osfmk/man/mach_port_allocate.html @@ -0,0 +1 @@ +

mach_port_allocate


Function - Create caller-specified type of port right.

SYNOPSIS

kern_return_t   mach_port_allocate
                (ipc_space_t                               task,
                 mach_port_right_t                        right,
                 mach_port_name_t                         *name);

PARAMETERS

task
[in task send right] The task acquiring the port right.

right
[in scalar] The kind of entity to be created. This is one of the following:

MACH_PORT_RIGHT_RECEIVE
mach_port_allocate creates a port. The new port is not a member of any port set. It doesn't have any extant send or send-once rights. Its make-send count is zero, its sequence number is zero, its queue limit is MACH_PORT_QLIMIT_DEFAULT, and it has no queued messages. name denotes the receive right for the new port. task does not hold send rights for the new port, only the receive right. mach_port_insert_right and mach_port_extract_right can be used to convert the receive right into a combined send/receive right.

MACH_PORT_RIGHT_PORT_SET
mach_port_allocate creates a port set. The new port set has no members.

MACH_PORT_RIGHT_DEAD_NAME
mach_port_allocate creates a dead name. The new dead name has one user reference.

name
[out scalar] The task's name for the port right. This can be any name that wasn't in use.

DESCRIPTION

The mach_port_allocate function creates a new right in the specified task. The new right's name is returned in name.

Ports that are allocated via this call do not support the full set of Mach port semantics; in particular, the kernel will not provide no-more-senders notification service requests on such ports. Any attempt to request no-more-senders notification service will generate an error. Use the mach_port_allocate_full interface to allocate ports that support the full set of Mach port semantics.

NOTES

This interface is machine word length specific because of the port name parameter.

RETURN VALUES

KERN_NO_SPACE
There was no room in task's IPC name space for another right.

RELATED INFORMATION

Functions: mach_port_allocate_name, mach_port_deallocate, mach_port_insert_right, mach_port_extract_right. \ No newline at end of file diff --git a/osfmk/man/mach_port_allocate_full.html b/osfmk/man/mach_port_allocate_full.html new file mode 100755 index 000000000..4cde74291 --- /dev/null +++ b/osfmk/man/mach_port_allocate_full.html @@ -0,0 +1 @@ +

mach_port_allocate_full


Function - Create a port right with full Mach port semantics.

SYNOPSIS

kern_return_t   mach_port_allocate_full
                (ipc_space_t                               task,
                 mach_port_right_t                        right,
                 subsystem_t                          subsystem,
                 mach_port_qos_t                            qos,
                 task                                      name);

PARAMETERS

task
[in task send right] The task acquiring the port right.

right
[in scalar] The kind of entity to be created. This is one of the following:

MACH_PORT_RIGHT_RECEIVE
mach_port_allocate_full creates a port. The new port is not a member of any port set. It doesn't have any extant send or send-once rights. Its make-send count is zero, its sequence number is zero, its queue limit is MACH_PORT_QLIMIT_DEFAULT, and it has no queued messages. The name parameter denotes the receive right for the new port. The owning task does not hold send rights for the new port, only the receive right. The mach_port_insert_right and mach_port_extract_right interfaces can be used to convert the receive right to a combined send/receive right.

MACH_PORT_RIGHT_PORT_SET
mach_port_allocate_full creates a port set. The new port set has no members.

MACH_PORT_RIGHT_DEAD_NAME
mach_port_allocate_full creates a dead name. The new dead name has one user reference.

subsystem
[in scalar] The port right naming the subsystem the newly created port is to be associated with.

qos
[pointer to an in/out structure] Structure used to specify the desired "quality of service." This structure may be used to mandate the name of the returned port right and/or the port's "quality of service" attribute. The current implementation recognizes two such attributes: regular and realtime.
name
[out scalar] The task's name for the port right. This can be any name that wasn't in use.

DESCRIPTION

The mach_port_allocate_full function creates a new right in the specified task. The new right's name is returned via the name parameter. The new port supports the full set of Mach port semantics (i.e. no_more_senders detection will work, if requested).

NOTES

This interface is machine word length specific because of the port name parameter.

RETURN VALUES

KERN_NO_SPACE
There was no room in task's IPC name space for another right.

RELATED INFORMATION

Functions: mach_port_allocate, mach_port_allocate_qos, mach_port_allocate_name, mach_port_deallocate, mach_port_insert_right, mach_port_extract_right.

Structures: mach_port_qos. \ No newline at end of file diff --git a/osfmk/man/mach_port_allocate_name.html b/osfmk/man/mach_port_allocate_name.html new file mode 100755 index 000000000..abdc831ec --- /dev/null +++ b/osfmk/man/mach_port_allocate_name.html @@ -0,0 +1 @@ +

mach_port_allocate_name


Function - Create a port right with the caller-specified name.

SYNOPSIS

kern_return_t   mach_port_allocate_name
                (ipc_space_t                               task,
                 mach_port_right_t                        right,
                 mach_port_name_t                          name);

PARAMETERS

task
[in task send right] The task acquiring the port right.

right
[in scalar] The kind of entity to be created. This is one of the following:

MACH_PORT_RIGHT_RECEIVE
mach_port_allocate_name creates a port. The new port is not a member of any port set. It doesn't have any extant send or send-once rights. Its make-send count is zero, its sequence number is zero, its queue limit is MACH_PORT_QLIMIT_DEFAULT, and it has no queued messages. name denotes the receive right for the new port. task does not hold send rights for the new port, only the receive right. mach_port_insert_right and mach_port_extract_right can be used to convert the receive right into a combined send/receive right.

MACH_PORT_RIGHT_PORT_SET
mach_port_allocate_name creates a port set. The new port set has no members.

MACH_PORT_RIGHT_DEAD_NAME
mach_port_allocate_name creates a dead name. The new dead name has one user reference.

name
[in scalar] The task's name for the port right. name must not already be in use for some right, and it can't be the reserved values MACH_PORT_NULL and MACH_PORT_DEAD.

DESCRIPTION

The mach_port_allocate_name function creates a new right in the specified task, with a specified name for the new right.

NOTES

This interface is machine word length specific because of the port name parameter.

RETURN VALUES

KERN_NAME_EXISTS
name was already in use for a port right.

RELATED INFORMATION

Functions: mach_port_allocate, mach_port_deallocate, mach_port_insert_right, mach_port_extract_right. \ No newline at end of file diff --git a/osfmk/man/mach_port_allocate_qos.html b/osfmk/man/mach_port_allocate_qos.html new file mode 100755 index 000000000..8887bf9fb --- /dev/null +++ b/osfmk/man/mach_port_allocate_qos.html @@ -0,0 +1 @@ +

mach_port_allocate_qos


Function - Allocate a port with specified "quality of service."

SYNOPSIS

kern_return_t	mach_port_allocate_qos
		(ipc_space_t	task,
		mach_port_right_t	right,
		mach_port_qos_t	qos,
		mach_port_name_t*	name);

PARAMETERS

task
[in task send right] The task acquiring the port right to the allocated port.
right
[in scalar] The type of port right to map to the allocated port.
qos
[pointer to an in/out structure] Structure used to specify the desired "quality of service." This structure indicates whether or not the caller is providing a name for the port and whether or not the port will exhibit realtime behavior.
name
[in/out scalar] The name of the installed port right, either specified by the caller or chosen by the system.

DESCRIPTION

The mach_port_allocate_qos function allocates a port with caller-specified "quality of service" characteristics with or without a caller-specified name; in other words, the caller may specify a desired name or it may let the kernel generate the name. The new port is capable of supporting full Mach port semantics (i.e no-more-senders notification can be requested on the port).

NOTES

This interface is machine word length specific because of the port name parameter.

RETURN VALUES

KERN_NO_SPACE
There was no room in task's IPC name space for another right.
KERN_INVALID_VALUE
The type of right specified by right is either invalid or conflicts with the requested "quality of service" as specified via qos.

RELATED INFORMATION

Functions: mach_port_allocate, mach_port_allocate_full, mach_port_allocate_name, mach_port_deallocate, mach_port_insert_right, mach_port_extract_right.

Structures: mach_port_qos. \ No newline at end of file diff --git a/osfmk/man/mach_port_deallocate.html b/osfmk/man/mach_port_deallocate.html new file mode 100755 index 000000000..524e25a82 --- /dev/null +++ b/osfmk/man/mach_port_deallocate.html @@ -0,0 +1 @@ +

mach_port_deallocate


Function - Decrement the target port right's user reference count.

SYNOPSIS

kern_return_t   mach_port_deallocate
                (ipc_space_t                               task,
                 mach_port_name_t                          name);

PARAMETERS

task
[in task send right] The task holding the right.

name
[in scalar] The task's name for the right.

DESCRIPTION

The mach_port_deallocate function releases a user reference for a right. It is an alternate form of mach_port_mod_refs that allows a task to release a user reference for a send or send-once right without failing if the port has died and the right is now actually a dead name.

If name denotes a dead name, send right, or send-once right, then the right loses one user reference. If it only had one user reference, then the right is destroyed. If name does not denote an element in the port name space, the function returns success.

NOTES

This interface is machine word length specific because of the port name parameter.

RETURN VALUES

KERN_INVALID_RIGHT
The name parameter denoted an invalid right.

RELATED INFORMATION

Functions: mach_port_allocate, mach_port_allocate_name, mach_port_mod_refs. \ No newline at end of file diff --git a/osfmk/man/mach_port_destroy.html b/osfmk/man/mach_port_destroy.html new file mode 100755 index 000000000..4a0a4ba0e --- /dev/null +++ b/osfmk/man/mach_port_destroy.html @@ -0,0 +1 @@ +

mach_port_destroy


Function - Deallocate all port rights associated with specified name.

SYNOPSIS

kern_return_t   mach_port_destroy
                (ipc_space_t                               task,
                 mach_port_name_t                          name);

PARAMETERS

task
[in task send right] The task holding the right.

name
[in scalar] The task's name for the right.

DESCRIPTION

The mach_port_destroy function de-allocates all rights denoted by a name. The name becomes immediately available for reuse.

For most purposes, mach_port_mod_refs and mach_port_deallocate are preferable.

If name denotes a port set, then all members of the port set are implicitly removed from the port set.

If name denotes a receive right that is a member of a port set, the receive right is implicitly removed from the port set. Remaining messages queued to the port are destroyed and extant send and send-once rights turn into dead names. If those send and send-once rights have dead-name requests registered, then dead-name notifications are generated for them.

If name denotes a send-once right, then the destruction of the send-once right produces a send-once notification for the port.

If name denotes a send-once, send, and/or receive right, and it has a dead-name request registered, then a port-deleted notification is generated (as opposed to a dead-name notification).

NOTES

This interface is machine word length specific because of the port name parameter.

RETURN VALUES

KERN_INVALID_NAME
The name parameter did not denote a right.

RELATED INFORMATION

Functions: mach_port_allocate, mach_port_allocate_name, mach_port_mod_refs, mach_port_deallocate, mach_port_request_notification. \ No newline at end of file diff --git a/osfmk/man/mach_port_extract_member.html b/osfmk/man/mach_port_extract_member.html new file mode 100755 index 000000000..b23ef935a --- /dev/null +++ b/osfmk/man/mach_port_extract_member.html @@ -0,0 +1 @@ + mach_port_insert_member.html

mach_port_extract_member


Function - Extract the specified receive right from the specified port set.

SYNOPSIS

kern_return_t   mach_port_extract_member
                (ipc_space_t                               task,
                 mach_port_name_t                        member,
                 mach_port_name_t                         set);

PARAMETERS

task
[in task send right] The task holding the port set and receive right.
member
[in scalar] The task's name for the receive right.
set
[in scalar] The task's name for the port set.

DESCRIPTION

The mach_port_extract_member function removes a receive right from a port set. Any other port set memberships for the receive right are not affected.  A receive right can be a member of any number of portsets simultaneously.

NOTES

This interface is machine word length specific because of the port name parameter.

RETURN VALUES

KERN_INVALID_NAME
member or set did not denote a right.
KERN_INVALID_RIGHT
member denoted a right, but not a receive right, or set denoted a right, but not a port set.
KERN_NOT_IN_SET
member was not in set.

RELATED INFORMATION

Functions: mach_port_extract_member, mach_port_move_member, mach_port_get_set_status, mach_port_get_attributes. \ No newline at end of file diff --git a/osfmk/man/mach_port_extract_right.html b/osfmk/man/mach_port_extract_right.html new file mode 100755 index 000000000..2bb9cd0aa --- /dev/null +++ b/osfmk/man/mach_port_extract_right.html @@ -0,0 +1 @@ +

mach_port_extract_right


Function - Remove the specified right from the target task and return it to the caller.

SYNOPSIS

kern_return_t   mach_port_extract_right
                (ipc_space_t                               task,
                 mach_port_name_t                          name,
                 mach_msg_type_name_t              desired_type,
                 mach_port_poly_t                        *right,
                 mach_msg_type_name_             *acquired_type);

PARAMETERS

task
[in task send right] The task holding the port right.

name
[in scalar] The task's name for the port right.

desired_type
[in scalar] IPC type, specifying how the right should be extracted.

right
[out random right] The extracted right.

acquired_type
[out scalar] The type of the extracted right.

DESCRIPTION

The mach_port_extract_right function extracts a port right from the target task and returns it to the caller as if the task sent the right voluntarily, using desired_type as the disposition for the right. See mach_msg.

The returned value of acquired_type will be MACH_MSG_TYPE_PORT_SEND if a send right is extracted, MACH_MSG_TYPE_PORT_RECEIVE if a receive right is extracted, and MACH_MSG_TYPE_PORT_SEND_ONCE if a send-once right is extracted.

NOTES

This interface is machine word length specific because of the port name parameter.

RETURN VALUES

KERN_INVALID_NAME
name did not denote a right.

KERN_INVALID_RIGHT
name denoted an invalid right.

RELATED INFORMATION

Functions: mach_port_insert_right, mach_msg. \ No newline at end of file diff --git a/osfmk/man/mach_port_get_attributes.html b/osfmk/man/mach_port_get_attributes.html new file mode 100755 index 000000000..4b115988b --- /dev/null +++ b/osfmk/man/mach_port_get_attributes.html @@ -0,0 +1 @@ +

mach_port_get_attributes


Function - Return information about target port as specified by the caller.

SYNOPSIS

kern_return_t   mach_port_get_attributes
                (ipc_space_t                               task,
                 mach_port_name_t                          name,
                 mach_port_flavor_t                      flavor,
                 mach_port_info_t                     port_info,
                 mach_msg_type_number_t        *port_info_count);

PARAMETERS

task
[in task send right] The task holding a receive right to the port in question.

name
[in scalar] task's name for the port.

flavor
[in scalar] The type of information to be returned. Valid values are:

MACH_PORT_LIMITS_INFO
Returns the resource limits for the port. The declaration of this data is found in structure mach_port_limits.

MACH_PORT_RECEIVE_STATUS
Returns random information about the rights and messages associated with the port. The declaration of this data is found in structure mach_port_status.

port_info
[out structure] Information about the specified port.

port_info_count
[in/out scalar] On input, the maximum size of the buffer; on output, the size returned (in natural-sized units).

DESCRIPTION

The mach_port_get_attributes function returns an information structure of type flavor.

NOTES

This interface is machine word length specific because of the port name parameter in the MACH_PORT_RECEIVE_STATUS structure return.

RETURN VALUES

KERN_INVALID_NAME
name did not denote a right.

KERN_INVALID_RIGHT
name denoted a right, but not a receive right.

RELATED INFORMATION

Functions: mach_port_allocate, mach_port_allocate_name, mach_port_set_attributes.

Data Structures: mach_port_limits, mach_port_status. \ No newline at end of file diff --git a/osfmk/man/mach_port_get_refs.html b/osfmk/man/mach_port_get_refs.html new file mode 100755 index 000000000..8768383fe --- /dev/null +++ b/osfmk/man/mach_port_get_refs.html @@ -0,0 +1 @@ +

mach_port_get_refs


Function - Return the current count of user references on the target port right.

SYNOPSIS

kern_return_t   mach_port_get_refs
                (ipc_space_t                               task,
                 mach_port_name_t                          name,
                 mach_port_right_t                        right,
                 mach_port_urefs_t                        *refs);

PARAMETERS

task
[in task send right] The task holding the right.

name
[in scalar] The task's name for the right.

right
[in scalar] The type of right/entity being examined:

MACH_PORT_RIGHT_SEND

MACH_PORT_RIGHT_RECEIVE

MACH_PORT_RIGHT_SEND_ONCE

MACH_PORT_RIGHT_PORT_SET

MACH_PORT_RIGHT_DEAD_NAME

refs
[out scalar] Number of user references.

DESCRIPTION

The mach_port_get_refs function returns the number of user references a task has for a right.

If name denotes a right, but not the type of right specified, then zero is returned. Otherwise a positive number of user references is returned. Note a name may simultaneously denote send and receive rights. The number of references for send-once rights is always one.

NOTES

This interface is machine word length specific because of the port name parameter.

RETURN VALUES

KERN_INVALID_NAME
name did not denote a right.

RELATED INFORMATION

Functions: mach_port_mod_refs. \ No newline at end of file diff --git a/osfmk/man/mach_port_get_set_status.html b/osfmk/man/mach_port_get_set_status.html new file mode 100755 index 000000000..3860a761c --- /dev/null +++ b/osfmk/man/mach_port_get_set_status.html @@ -0,0 +1 @@ +

mach_port_get_set_status


Function - Return the port right names contained in the target port set.

SYNOPSIS

kern_return_t   mach_port_get_set_status
                (ipc_space_t                               task,
                 mach_port_name_t                          name,
                 mach_port_name_array_t                *members,
                 task                                     count);

PARAMETERS

task
[in task send right] The task holding the port set.

name
[in scalar] The task's name for the port set.

members
[out pointer to dynamic array of mach_port_name_t] The task's names for the port set's members.

count
[out scalar] The number of member names returned.

DESCRIPTION

The mach_port_get_set_status function returns the individual port right names for all port rights contained in the specified port set. The members parameter is an array that is automatically allocated when the reply message is received. Note that vm_deallocate should be used to free the array.

Note that this interface, unlike others such as task_threads, returns a collection of port right names, NOT a collection of port rights themselves. In other words, this function does not insert port rights into the caller's port right name space; consequently, a call to mach_port_get_set_status does not affect the reference count of each port right within the target port set.

NOTES

This interface is machine word length specific because of the port name parameter and the returned port names.

RETURN VALUES

KERN_INVALID_NAME
name did not denote a right.

KERN_INVALID_RIGHT
name denoted a right, but not a port set.

RELATED INFORMATION

Functions: mach_port_insert_member, mach_port_extract_member, mach_port_move_member, vm_deallocate. \ No newline at end of file diff --git a/osfmk/man/mach_port_insert_member.html b/osfmk/man/mach_port_insert_member.html new file mode 100755 index 000000000..76cf957d3 --- /dev/null +++ b/osfmk/man/mach_port_insert_member.html @@ -0,0 +1 @@ + mach_port_insert_member.html

mach_port_insert_member


Function - Move the specified receive right into or out of the specified port set.

SYNOPSIS

kern_return_t   mach_port_insert_member
                (ipc_space_t                               task,
                 mach_port_name_t                        member,
                 mach_port_name_t                         set);

PARAMETERS

task
[in task send right] The task holding the port set and receive right.
member
[in scalar] The task's name for the receive right.
set
[in scalar] The task's name for the port set.

DESCRIPTION

The mach_port_insert_member function adds a receive right to a port set. If the receive right is already a member of another port set, that relationship is unafected by this operation.  A receive right can be in multiple port sets simultaneously.

NOTES

This interface is machine word length specific because of the port name parameter.

RETURN VALUES

KERN_INVALID_NAME
member or set did not denote a right.
KERN_INVALID_RIGHT
member denoted a right, but not a receive right, or set denoted a right, but not a port set.

RELATED INFORMATION

Functions: mach_port_extract_member, mach_port_move_member, mach_port_get_set_status, mach_port_get_attributes. \ No newline at end of file diff --git a/osfmk/man/mach_port_insert_right.html b/osfmk/man/mach_port_insert_right.html new file mode 100755 index 000000000..3cda5863e --- /dev/null +++ b/osfmk/man/mach_port_insert_right.html @@ -0,0 +1 @@ +

mach_port_insert_right


Function - Insert the specified port right into the target task.

SYNOPSIS

kern_return_t   mach_port_insert_right
                (ipc_space_t                               task,
                 mach_port_name_t                          name,
                 mach_port_poly_t                         right,
                 mach_msg_type_name_t                right_type);

PARAMETERS

task
[in task send right] The task which gets the caller's right.

name
[in scalar] The name by which task will know the right.

right
[in random right] The port right.

right_type
[in scalar] IPC type of the sent right; e.g., MACH_MSG_TYPE_COPY_SEND or MACH_MSG_TYPE_MOVE_RECEIVE.

DESCRIPTION

The mach_port_insert_right function inserts into task the caller's right for a port, using a specified name for the right in the target task.

The specified name can't be one of the reserved values MACH_PORT_NULL or MACH_PORT_DEAD. The right can't be MACH_PORT_NULL or MACH_PORT_DEAD.

The argument right_type specifies a right to be inserted and how that right should be extracted from the caller. It should be a value appropriate for mach_msg.

If right_type is MACH_MSG_TYPE_MAKE_SEND, MACH_MSG_TYPE_MOVE_SEND, or MACH_MSG_TYPE_COPY_SEND, then a send right is inserted. If the target already holds send or receive rights for the port, then name should denote those rights in the target. Otherwise, name should be unused in the target. If the target already has send rights, then those send rights gain an additional user reference. Otherwise, the target gains a send right, with a user reference count of one.

If right_type is MACH_MSG_TYPE_MAKE_SEND_ONCE or MACH_MSG_TYPE_MOVE_SEND_ONCE, then a send-once right is inserted. The name should be unused in the target. The target gains a send-once right.

If right_type is MACH_MSG_TYPE_MOVE_RECEIVE, then a receive right is inserted. If the target already holds send rights for the port, then name should denote those rights in the target. Otherwise, name should be unused in the target. The receive right is moved into the target task.

NOTES

This interface is machine word length specific because of the port name parameter.

RETURN VALUES

KERN_NAME_EXISTS
name already denoted a right.

KERN_INVALID_CAPABILITY
right was null or dead.

KERN_UREFS_OVERFLOW
Inserting the right would overflow name's user-reference count.

KERN_RIGHT_EXISTS
task already had rights for the port, with a different name.

RELATED INFORMATION

Functions: mach_port_extract_right, mach_msg. \ No newline at end of file diff --git a/osfmk/man/mach_port_limits.html b/osfmk/man/mach_port_limits.html new file mode 100755 index 000000000..1c2b811eb --- /dev/null +++ b/osfmk/man/mach_port_limits.html @@ -0,0 +1 @@ +

mach_port_limits


Structure - Specifies a port's resource and message queue limits.

SYNOPSIS

struct mach_port_limits
{
       mach_port_msgcount_t      queue_limit;
};

typedef struct mach_port_limits* mach_port_limits_t;

FIELDS

queue_limit
Number of messages allowed to be on the message queue at any given time. Attempts to queue more messages than this limit will block.

DESCRIPTION

The mach_port_limits structure defines various limits governing the messages that can be sent through the port. (In the current implementation, the structure maintains only a queue length limit.)

RELATED INFORMATION

Functions: mach_port_get_attributes, mach_port_set_attributes.

Structures: mach_port_qos. \ No newline at end of file diff --git a/osfmk/man/mach_port_mod_refs.html b/osfmk/man/mach_port_mod_refs.html new file mode 100755 index 000000000..9ec947f45 --- /dev/null +++ b/osfmk/man/mach_port_mod_refs.html @@ -0,0 +1 @@ +

mach_port_mod_refs


Function - Modify the specified port right's count of user references.

SYNOPSIS

kern_return_t   mach_port_mod_refs
                (ipc_space_t                               task,
                 mach_port_name_t                          name,
                 mach_port_right_t                        right,
                 mach_port_delta_t                        delta);

PARAMETERS

task
[in task send right] The task holding the right.

name
[in scalar] The task's name for the right.

right
[in scalar] The type of right/entity being modified:

MACH_PORT_RIGHT_SEND

MACH_PORT_RIGHT_RECEIVE

MACH_PORT_RIGHT_SEND_ONCE

MACH_PORT_RIGHT_PORT_SET

MACH_PORT_RIGHT_DEAD_NAME

delta
[in scalar] Signed change to the number of user references.

DESCRIPTION

The mach_port_mod_refs function requests that the number of user references a task has for a right be changed. This results in the right being destroyed, if the number of user references is changed to zero.

The name parameter should denote the specified right. The number of user references for the right is changed by the amount delta, subject to the following restrictions: port sets, receive rights, and send-once rights may only have one user reference. The resulting number of user references can't be negative. If the resulting number of user references is zero, the effect is to de-allocate the right. For dead names and send rights, there is an implementation-defined maximum number of user references.

If the call destroys the right, then the effect is as described for mach_port_destroy, with the exception that mach_port_destroy simultaneously destroys all the rights denoted by a name, while mach_port_mod_refs can only destroy one right. The name will be available for reuse if it only denoted the one right.

NOTES

This interface is machine word length specific because of the port name parameter.

RETURN VALUES

KERN_INVALID_NAME
name did not denote a right.

KERN_INVALID_RIGHT
name denoted a right, but not the specified right.

KERN_INVALID_VALUE
The user-reference count would become negative.

KERN_UREFS_OVERFLOW
The user-reference count would overflow.

RELATED INFORMATION

Functions: mach_port_destroy, mach_port_get_refs. \ No newline at end of file diff --git a/osfmk/man/mach_port_move_member.html b/osfmk/man/mach_port_move_member.html new file mode 100755 index 000000000..c21248329 --- /dev/null +++ b/osfmk/man/mach_port_move_member.html @@ -0,0 +1 @@ + mach_port_insert_member.html

mach_port_move_member


Function - Move the specified receive right into or out of the specified port set.

SYNOPSIS

kern_return_t   mach_port_move_member
                (ipc_space_t                               task,
                 mach_port_name_t                        member,
                 mach_port_name_t                         after);

PARAMETERS

task
[in task send right] The task holding the port set and receive right.
member
[in scalar] The task's name for the receive right.
after
[in scalar] The task's name for the port set.

DESCRIPTION

The mach_port_move_member function moves a receive right into a port set. If the receive right is already a member of any other port sets, it is removed from those sets first. If the port set is MACH_PORT_NULL, then the receive right is not put into a port set, but removed from all its current port sets.

NOTES

This interface is machine word length specific because of the port name parameter.

RETURN VALUES

KERN_INVALID_NAME
member or after did not denote a right.
KERN_INVALID_RIGHT
member denoted a right, but not a receive right, or after denoted a right, but not a port set.
KERN_NOT_IN_SET
after was MACH_PORT_NULL, but member wasn't currently in a port set.

RELATED INFORMATION

Functions: mach_port_insert_member, mach_port_extract_member, mach_port_get_set_status, mach_port_get_attributes.

\ No newline at end of file diff --git a/osfmk/man/mach_port_names.html b/osfmk/man/mach_port_names.html new file mode 100755 index 000000000..daf43359a --- /dev/null +++ b/osfmk/man/mach_port_names.html @@ -0,0 +1 @@ +

mach_port_names


Function - Return information about a task's port name space.

SYNOPSIS

kern_return_t   mach_port_names
                (ipc_space_t                               task,
                 mach_port_name_array_t                  *names,
                 mach_msg_type_number_t               *namesCnt,
                 mach_port_type_array_                   *types,
                 mach_msg_type_number_t               *typesCnt);

PARAMETERS

task
[in task send right] The task whose port name space is queried.

names
[out pointer to dynamic array of mach_port_name_t] The names of the ports, port sets, and dead names in the task's port name space, in no particular order.

namesCnt
[out scalar] The number of names returned.

types
[out pointer to dynamic array of mach_port_type_t] The type of each corresponding name. Indicates what kind of rights the task holds with that name.

typesCnt
[out scalar] The number of types returned.

DESCRIPTION

The mach_port_names returns information about task's port name space. It returns task's currently active names, which represent some port, port set, or dead name right. For each name, it also returns what type of rights task holds (the same information returned by mach_port_type).

Note that when a call to mach_port_names returns, the number of entries in the two output arrays (names and types) are equal (namesCnt equals typesCnt). The fact that this interface returns two separate counts is an artifact of the Mach Interface Generator.

NOTES

This interface is machine word length specific because of the port name parameter and the returned port names.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: mach_port_type. \ No newline at end of file diff --git a/osfmk/man/mach_port_qos.html b/osfmk/man/mach_port_qos.html new file mode 100755 index 000000000..3011ab78a --- /dev/null +++ b/osfmk/man/mach_port_qos.html @@ -0,0 +1 @@ +

mach_port_qos


Structure - Specifies a port's attributes with respect to "Quality Of Service."

SYNOPSIS

typedef struct mach_port_qos
        {
               boolean_t      name;
               boolean_t      rt;
               boolean_t      pad1;
               boolean_t      pad2;
        } mach_port_qos_t;

FIELDS

name
If TRUE, the system will bestow the user-specified name on the newly allocated port. Otherwise, the system will choose the port's name.

rt
If TRUE, this field causes a realtime port to be allocated. Otherwise, a regular port will be allocated.

pad1
A 30 bit padding field.

pad2
A 32 bit padding field; with the pad1 field, lengthens the structure to 64 bits.

DESCRIPTION

The mach_port_qos structure is used to specify a port's "quality of service" attributes when allocating the port via the mach_port_allocate_qos interface.

RELATED INFORMATION

Functions: mach_port_allocate_qos, mach_port_get_attributes, mach_port_set_attributes. \ No newline at end of file diff --git a/osfmk/man/mach_port_set_attributes.html b/osfmk/man/mach_port_set_attributes.html new file mode 100755 index 000000000..9b3f9c183 --- /dev/null +++ b/osfmk/man/mach_port_set_attributes.html @@ -0,0 +1 @@ +

mach_port_set_attributes


Function - Set the target port's attributes.

SYNOPSIS

kern_return_t   mach_port_set_attributes
                (ipc_space_t                               task,
                 mach_port_name_t                          name,
                 mach_port_flavor_t                      flavor,
                 mach_port_info_t                     port_info,
                 mach_msg_type_number_t         port_info_count);

PARAMETERS

task
[in task send right] The task holding a receive right to the port in question.

name
[in scalar] task's name for the port.

flavor
[in scalar] The type of attributes to be set. Valid values are:

MACH_PORT_LIMITS_INFO
Sets resource limits (queue limits) for the port. The declaration of this data is found in structure mach_port_limits.

port_info
[pointer to in structure] Attributes for the specified port.

port_info_count
[in scalar] The size of the buffer (in natural-sized units).

DESCRIPTION

The mach_port_set_attributes function sets attributes of type flavor.

NOTES

This interface is machine word length specific because of the port name parameter.

RETURN VALUES

KERN_INVALID_NAME
name did not denote a right.

KERN_INVALID_RIGHT
name denoted a right, but not a receive right.

RELATED INFORMATION

Functions: mach_port_allocate, mach_port_allocate_name, mach_port_get_attributes.

Data Structures: mach_port_limits. \ No newline at end of file diff --git a/osfmk/man/mach_port_set_mscount.html b/osfmk/man/mach_port_set_mscount.html new file mode 100755 index 000000000..d42f8eb82 --- /dev/null +++ b/osfmk/man/mach_port_set_mscount.html @@ -0,0 +1 @@ +

mach_port_set_mscount


Function - Change the target port's make-send count.

SYNOPSIS

kern_return_t   mach_port_set_mscount
                (ipc_space_t                               task,
                 mach_port_name_t                          name,
                 mach_port_mscount_t                    mscount);

PARAMETERS

task
[in task send right] The task owning the receive right.

name
[in scalar] task's name for the receive right.

mscount
[in scalar] New value for the make-send count for the receive right.

DESCRIPTION

The mach_port_set_mscount function changes the make-send count of task's receive right named name. A port's make-send count specifies the number of send rights that have been generated via the port's receive right. A port's make-send count is set to zero when the port is first allocated; the count is reset to zero each time the port's receive right is transferred via a Mach message.

NOTES

This interface is machine word length specific because of the port name parameter.

RETURN VALUES

KERN_INVALID_NAME
name did not denote a right.

KERN_INVALID_RIGHT
name denoted a right, but not a receive right.

RELATED INFORMATION

Functions: mach_port_get_attributes. \ No newline at end of file diff --git a/osfmk/man/mach_port_set_seqno.html b/osfmk/man/mach_port_set_seqno.html new file mode 100755 index 000000000..4871b1fac --- /dev/null +++ b/osfmk/man/mach_port_set_seqno.html @@ -0,0 +1 @@ +

mach_port_set_seqno


Function - Change the current value of the target port's sequence number.

SYNOPSIS

kern_return_t   mach_port_set_seqno
                (ipc_space_t                               task,
                 mach_port_name_t                          name,
                 mach_port_seqno_t                        seqno);

PARAMETERS

task
[in task send right] The task owning the receive right.

name
[in scalar] task's name for the receive right.

seqno
[in scalar] The sequence number that the next message received from the port will have.

DESCRIPTION

The mach_port_set_seqno function changes the sequence number of task's receive right named name.

(Each port is associated with a sequence number attribute that can be used to track the order in which messages sent to the port are received. A port's sequence number is initially set to zero and is incremented each time a message is received from the port. A port's sequence number is automatically reset to zero each time the port's receive right migrates.)

NOTES

This interface is machine word length specific because of the port name parameter.

RETURN VALUES

KERN_INVALID_NAME
name did not denote a right.

KERN_INVALID_RIGHT
name denoted a right, but not a receive right.

RELATED INFORMATION

Functions: mach_port_get_attributes. \ No newline at end of file diff --git a/osfmk/man/mach_port_status.html b/osfmk/man/mach_port_status.html new file mode 100755 index 000000000..649a4132a --- /dev/null +++ b/osfmk/man/mach_port_status.html @@ -0,0 +1 @@ +

mach_port_status


Structure - Used to present a port's current status with respect to various important attributes.

SYNOPSIS

struct mach_port_status
{
       natural_t                mps_pset_count;
       mach_port_seqno_t         mps_seqno;
       mach_port_mscount_t     mps_mscount;
       mach_port_msgcount_t     mps_qlimit;
       mach_port_msgcount_t   mps_msgcount;
       mach_port_rights_t     mps_sorights;
       mach_port_srights_t     mps_srights;
       boolean_t             mps_pdrequest;
       boolean_t             mps_nsrequest;
       unsigned int              mps_flags;
};

typedef struct mach_port_status mach_port_status_t;

FIELDS

mps_pset
Containing port set.

mps_seqno
Current sequence number for the port.

mps_mscount
Make-send count.

mps_msgcount
Upper limit for the number of messages that may be queued to the port before the system blocks send operations.

mps_msgcount
Number of messages currently queued on the port.

mps_sorights
How many send-once rights.

mps_srights
Specifies whether or not send rights exist. Valid values are as follows:

MPS_FALSE
No send rights currently in existence.

MPS_TRUE
Send rights exist and no-more-senders notification is enabled.

MPS_UNKNOWN
The port does not permit no-more-senders notification requests; consequently, the system does not know whether or not send rights exist.

mps_pdrequest
Specifies whether or not a port-deleted notification has been requested.

mps_nsrequest
True if no-senders requested.

mps_flags
Flags associated with the port.

DESCRIPTION

The mach_port_status structure is used to provide information about a port in response to an invocation of the mach_port_get_attributes interface.

NOTES

This structure is machine word length sensitive due to the presence of the port set name.

RELATED INFORMATION

Functions: mach_port_get_attributes. \ No newline at end of file diff --git a/osfmk/man/mach_port_type.html b/osfmk/man/mach_port_type.html new file mode 100755 index 000000000..524828e16 --- /dev/null +++ b/osfmk/man/mach_port_type.html @@ -0,0 +1 @@ +

mach_port_type


Function - Return the characteristics of the target port name.

SYNOPSIS

kern_return_t   mach_port_type
                (ipc_space_t                               task,
                 mach_port_name_t                          name,
                 mach_port_type_t                         ptype);

PARAMETERS

task
[in task send right] The task whose port name space is queried.

name
[in scalar] The name being queried.

ptype
[out scalar] The type of the name. Indicates what kind of right the task holds for the port, port set, or dead name.

DESCRIPTION

The mach_port_type function returns information about task's rights for a specific name in its port name space. The returned ptype is a bit-mask indicating what rights task holds with this name. The bit-mask is composed of the following bits:

MACH_PORT_TYPE_SEND
The name denotes send rights.

MACH_PORT_TYPE_RECEIVE
The name denotes a receive right.

MACH_PORT_TYPE_SEND_ONCE
The name denotes a send-once right.

MACH_PORT_TYPE_PORT_SET
The name denotes a port set.

MACH_PORT_TYPE_DEAD_NAME
The name is a dead name.

MACH_PORT_TYPE_DNREQUEST
A dead-name request has been registered for the right.

NOTES

This interface is machine word length specific because of the port name parameter.

RETURN VALUES

KERN_INVALID_NAME
name did not denote a right.

RELATED INFORMATION

Functions: mach_port_names, mach_port_get_attributes, mach_port_get_set_status. \ No newline at end of file diff --git a/osfmk/man/mach_ports_lookup.html b/osfmk/man/mach_ports_lookup.html new file mode 100755 index 000000000..907e81cd7 --- /dev/null +++ b/osfmk/man/mach_ports_lookup.html @@ -0,0 +1 @@ +

mach_ports_lookup


Function - Provide caller with an array of the target task's well-known ports.

SYNOPSIS

kern_return_t   mach_ports_lookup
                (task_t                             target_task,
                 mach_port_array_t                init_port_set,
                 mach_msg_type_number_t         init_port_count);

PARAMETERS

target_task
[in task send right] The task whose currently registered ports are to be returned.

init_port_set
[out pointer to dynamic array of registered send rights] The returned array of ports.

init_port_count
[out scalar] The number of returned port rights.

DESCRIPTION

The mach_ports_lookup function returns an array of the well-known system ports that are currently registered for the specified task. Note that the task holds only send rights for the ports.

Registered ports are those ports that are used by the run-time system to initialize a task. To register system ports for a task, use the mach_ports_register function.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: mach_ports_register. \ No newline at end of file diff --git a/osfmk/man/mach_ports_register.html b/osfmk/man/mach_ports_register.html new file mode 100755 index 000000000..03f21b5e5 --- /dev/null +++ b/osfmk/man/mach_ports_register.html @@ -0,0 +1 @@ +

mach_ports_register


Function - Register an array of well-known ports on behalf of the target task.

SYNOPSIS

kern_return_t   mach_ports_register
                (task_t                             target_task,
                 mach_port_array_t                init_port_set,
                 target_task              init_port_array_count);

PARAMETERS

target_task
[in task send right] The task for which the ports are to be registered.

init_port_set
[in pointer to array of registered send rights] The array of ports to register.

init_port_array_count
[in scalar] The number of ports in the array. Note that while this is a variable, the kernel accepts only a limited number of ports. The maximum number of ports is defined by the global constant MACH_PORTS_SLOTS_USED.

DESCRIPTION

The mach_ports_register function registers an array of well-known system ports for the specified task. The task holds only send rights for the registered ports. The valid well-known system ports are:

  • The port for the Name Server
  • The port for the Environment Manager
  • The port for the Service server

Each port must be placed in a specific slot in the array. The slot numbers are defined (in mach.h) by the global constants NAME_SERVER_SLOT, ENVIRONMENT_SLOT, and SERVICE_SLOT.

A task can retrieve the currently registered ports by using the mach_ports_lookup function.

NOTES

When a new task is created (with task_create), the child task can inherit the parent's registered ports. Note that child tasks do not automatically acquire rights to these ports. They must use mach_ports_lookup to get them. It is intended that port registration be used only for task initialization, and then only by run-time support modules.

A parent task has three choices when passing registered ports to child tasks:

  • The parent task can do nothing. In this case, all child tasks inherit access to the same ports that the parent has.
  • The parent task can use mach_ports_register to modify its set of registered ports before creating child tasks. In this case, the child tasks get access to the modified set of ports. After creating its child tasks. the parent can use mach_ports_register again to reset its registered ports.
  • The parent task can first create a specific child task and then use mach_ports_register to modify the child's inherited set of ports, before starting the child's thread(s). The parent must specify the child's task port, rather than its own, on the call to mach_ports_register.

Tasks other than the Name Server and the Environment Manager should not need access to the Service port. The Name Server port is the same for all tasks on a given machine. The Environment port is the only port likely to have different values for different tasks.

Registered ports are restricted to those ports that are used by the run-time system to initialize a task. A parent task can pass other ports to its child tasks through:

  • An initial message (see mach_msg).
  • The Name Server, for public ports.
  • The Environment Manager, for private ports.
  • The task bootstrap port (see task_get_special_port).

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: mach_msg, mach_ports_lookup. \ No newline at end of file diff --git a/osfmk/man/mach_reply_port.html b/osfmk/man/mach_reply_port.html new file mode 100755 index 000000000..f2355b72a --- /dev/null +++ b/osfmk/man/mach_reply_port.html @@ -0,0 +1 @@ +

mach_reply_port


System Trap - Allocate a new port and insert corresponding receive right in the calling task.

SYNOPSIS

#include<mach/mach_traps.h>

mach_port_t   mach_reply_port( void )

PARAMETERS

None.

DESCRIPTION

The mach_reply_port function creates a new port for the current task and returns the name assigned by the kernel. The kernel records the name in the task's port name space and grants the task receive rights for the port. The new port is not a member of any port set.

This function is an optimized version of mach_port_allocate that uses no port references. Its main purpose is to allocate a reply port for the task when the task is starting, for example, before it has any ports to use as reply ports for any IPC-based system functions.

If the task's task self port is null (thereby deactivating basic Mach manipulations by the task), this call returns null.

CAUTIONS

Although the created port can be used for any purpose, the implementation may optimize its use as a reply port.

RETURN VALUES

MACH_PORT_NULL
No port was allocated.

[reply receive right]
Any other value indicates success.

RELATED INFORMATION

Functions: mach_port_allocate. \ No newline at end of file diff --git a/osfmk/man/mach_rpc_return_trap.html b/osfmk/man/mach_rpc_return_trap.html new file mode 100755 index 000000000..3202fee17 --- /dev/null +++ b/osfmk/man/mach_rpc_return_trap.html @@ -0,0 +1 @@ +

mach_rpc_return_trap


System Trap - Real-Time RPC trap return location.

SYNOPSIS

#include<mach/rpc.h>

mach_rpc_return_t   mach_rpc_return_trap( void )

PARAMETERS

None.

DESCRIPTION

The mach_rpc_return_trap is the system entry point used by the reply side of the Mach RPC service and is used by RPC servers to return control to invoking clients. For a complete description of this functionality, refer to: Burke, Edward, Michael Condict, David Mitchell, Franklin Reynolds, Peter Watkins, William Willcox, "RPC Design for Real-Time Mach," OSF Research Institute, Cambridge, MA.

NOTES

This interface is experimental and therefore subject to change.

RETURN VALUES

The return value is specific to the server function actually executed via the mach_rpc_return_trap call.

RELATED INFORMATION

Functions: mach_rpc_trap. \ No newline at end of file diff --git a/osfmk/man/mach_rpc_trap.html b/osfmk/man/mach_rpc_trap.html new file mode 100755 index 000000000..5a0038229 --- /dev/null +++ b/osfmk/man/mach_rpc_trap.html @@ -0,0 +1 @@ +

mach_rpc_trap


System Trap - Real-Time RPC trap.

SYNOPSIS

#include<mach/rpc.h>

mach_rpc_return_t   mach_rpc_trap
                     (mach_port_t                    dest_port,
                      mach_rpc_id_t                routine_num,
                      mach_rpc_signature_t       signature_ptr,
                      mach_rpc_size_t           signature_size);

PARAMETERS

dest_port
[in send right] The port representing the destination of the RPC (usually a registered subsystem established by a call to mach_port_allocate_subsystem).

routine_num
[in scalar] Identifier of the server work function.

signature_ptr
[in pointer] Pointer to the call's mach_rpc_signature structure.

signature_size
[in scalar] Size, in bytes, of the call's mach_rpc_signature structure.

DESCRIPTION

The mach_rpc_trap system trap is the entry point for the invoke side of the Mach RPC service used to transfer control to an RPC server. The trap is accessed via the MIG generated MACH_RPC macro which is invoked transparently when the mach_rpc feature is enabled. This function is not designed for use directly by the user. It is automatically generated by MIG to handle a function call.

For a complete description of this functionality, refer to: Burke, Edward, Michael Condict, David Mitchell, Franklin Reynolds, Peter Watkins, William Willcox, "RPC Design for Real-Time Mach," OSF Research Institute, Cambridge, MA.

NOTES

This interface is experimental and therefore subject to change.

RETURN VALUES

KERN_FAILURE
Either the argument copyin failed, there were too many arguments, or the argument copyout failed.

KERN_INVALID_ARGUMENT
The dest_port, signature_ptr, and/or the subsystem associated with the dest_port is invalid; the siganture_size is less than, or equal to, zero.

KERN_NO_ACCESS
The kernel port associated with the dest_port name is a norma proxy port.

KERN_RESOURCE_SHORTAGE
The kernel could not allocate storage for an internal rpc state structure.

RELATED INFORMATION

Functions: mach_rpc_return_trap, thread_activation_create, mach_port_allocate_subsystem, mach_subsystem_create. \ No newline at end of file diff --git a/osfmk/man/mach_subsystem_create.html b/osfmk/man/mach_subsystem_create.html new file mode 100755 index 000000000..9f13b905f --- /dev/null +++ b/osfmk/man/mach_subsystem_create.html @@ -0,0 +1 @@ +

mach_subsystem_create


Function - Register information about an RPC subsystem.

SYNOPSIS

kern_return_t   mach_subsystem_create
                (task_t                             target_task,
                 user_subsystem_t                   user_subsys,
                 mach_msg_type_number_t          user_subsysCnt,
                 subsystem_t                        subsystem_t);

PARAMETERS

target_task
The task for which the subsystem is registered; normally the calling task, but not necessarily.

user_subsys
The MIG-generated data structure describing the exported routines and their input/output characteristics (e.g. arguments and return values).

user_subsysCnt
The size of the user_subsys data structure argument, in bytes.

subsys
The port returned that names the registered subsystem.

DESCRIPTION

The mach_subsystem_create function is used by a server to register information about an RPC subsystem with the kernel. MIG automatically generates, in the server source file, a user_subsystem_t data structure that is appropriate for registering the subsystem. This data structure includes a per-routine array that specifies:

  • The address of the server function that performs the work.
  • The address of the MIG-generated server-side marshalling stub, to be used with mach_msg.
  • The argument signature (i.e. NDR-style argument format) of the routine.

Upon successful completion, mach_subsystem_create returns, via the subsys parameter, a port naming the registered subsystem.

Each port on which the server is to receive short-circuited RPC's (or a mach_rpc call) must be associated with a registered subsystem, by calling mach_port_allocate_subsystem.

RETURN VALUES

KERN_INVALD_ADDRESS
One or more of the addresses in the range specified by the subsystem address and size are not valid addresses in the caller, or some of the internal pointers in the subsystem do not point to places within the address range (all of the data of the subsystem is required to be contiguous, even the parts that are pointed to by other parts).

KERN_INVALID_ARGUMENT
The port name specified by target_task is not a send right naming a task, or the subsystem size is too small to be valid.

KERN_INVALID_TASK
The target task is dead.

KERN_RESOURCE_SHORTAGE
The kernel cannot allocate the subsystem due to insufficient available memory.

RELATED INFORMATION

Functions: mach_port_allocate_subsystem, thread_activation_create. \ No newline at end of file diff --git a/osfmk/man/mach_task_self.html b/osfmk/man/mach_task_self.html new file mode 100755 index 000000000..130c7e264 --- /dev/null +++ b/osfmk/man/mach_task_self.html @@ -0,0 +1 @@ +

mach_task_self


System Trap - Return a send right to the caller's task_self port.

SYNOPSIS

#include<mach/mach_traps.h>

mach_port_t   mach_task_self (void)

PARAMETERS

None.

DESCRIPTION

The mach_task_self function returns send rights to the task's kernel port.

NOTES

This function call is redefined in the mach_init.h file to return the caller's mach_task_self_ environment variable, which is cached on behalf of the caller's task at runtime. (The mach_init.h file is itself included via the mach.h file.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: task_set_special_port. \ No newline at end of file diff --git a/osfmk/man/mach_thread_self.html b/osfmk/man/mach_thread_self.html new file mode 100755 index 000000000..6472709d7 --- /dev/null +++ b/osfmk/man/mach_thread_self.html @@ -0,0 +1 @@ +

mach_thread_self


System Trap - Returns the thread self port.

SYNOPSIS

#include

thread_port_t   mach_thread_self( void );

PARAMETERS

None.

DESCRIPTION

The mach_thread_self function returns send rights to the thread's own kernel port.

RETURN VALUES

[thread-self send right] Send rights to the thread's port.

RELATED INFORMATION

Functions: thread_info, thread_set_special_port. \ No newline at end of file diff --git a/osfmk/man/mapped_tvalspec.html b/osfmk/man/mapped_tvalspec.html new file mode 100755 index 000000000..972941b15 --- /dev/null +++ b/osfmk/man/mapped_tvalspec.html @@ -0,0 +1 @@ +

mapped_tvalspec


Structure - Specifies the format the kernel uses to maintain a mapped clock's time.

SYNOPSIS

struct mapped_tvalspec
{
       tvalspec_t          mtv_time;
       unsigned int        mtv_csec;
};

typedef struct mapped_tvalspec mapped_tvalspec_t;

FIELDS

mtv_time
Clock time.

mtv_csec
A field used to synchronize with the kernel's setting of the time.

DESCRIPTION

The mapped_tvalspec structure defines the format of the current-time structure maintained by the kernel and visible through a mapped clock (clock_map_time). The data in this structure is updated at the clock's current resolution and contains the same tvalspec value that would be returned by clock_get_time.

NOTES

Because of the race between the referencing of the multiple fields in the clock value and the kernel's setting them, they should be referenced as follows:

   tvalspec_t* ts;
   do
   {
              ts-> tv_sec = mtime -> mtv_time.tv_sec;
              ts  -> tv_nsec = mtime -> mtv_time.tv_nsec;
   } while (ts  -> tv_sec != mtime -> mtv_csec);

RELATED INFORMATION

Functions: clock_map_time, clock_get_time.

Data Structures: tvalspec. \ No newline at end of file diff --git a/osfmk/man/memory_object_attr_info.html b/osfmk/man/memory_object_attr_info.html new file mode 100755 index 000000000..dcd0d42c0 --- /dev/null +++ b/osfmk/man/memory_object_attr_info.html @@ -0,0 +1 @@ +

memory_object_attr_info


Structure - Specifies memory object's behavior attributes.

SYNOPSIS

struct  memory_object_attr_info
{
        memory_object_copy_strategy_t    copy_strategy;
        vm_offset_t                       cluster_size;
        boolean_t                            may_cache;
        boolean_t                            temporary;
};

typedef struct memory_object_attr_info* memory_object_attr_info_t;

FIELDS

copy_strategy
How the kernel should handle copying of regions associated with the memory object. The copy strategy cannot be changed once an object is initialized. Valid values are:

MEMORY_OBJECT_COPY_NONE
Use normal procedure when copying the memory object's data. Normally, the kernel requests each page with read access, copies the data, and then (optionally) flushes the data.

MEMORY_OBJECT_COPY_CALL
Call the memory manager when a copy operation is necessary.

MEMORY_OBJECT_COPY_DELAY
Use copy-on-write technique. This strategy allows the kernel to efficiently copy large amounts of data and guarantees that the memory manager will not externally modify the data. It is the most commonly used copy strategy.

MEMORY_OBJECT_COPY_TEMPORARY
All changes are made in memory and the memory manager does not need to see them.

MEMORY_OBJECT_COPY_SYMMETRIC
The memory manager does not change the data, does not need to see any changes to the data, and will prevent the object from being mapped more than once. Currently, this strategy should be restricted to use by the kernel.

cluster_size
The memory object's perferred cluster size (in bytes). This value may affect the number of pages transferred in a given paging operation.

may_cache
Cache indicator. If true, the kernel can cache data associated with the memory object (keep the memory object active) even if no virtual memory references to it remain.

temporary
If TRUE, when the last mapping to the object is released, the kernel destroys the object without returning any resident pages.

DESCRIPTION

The memory_object_attr_info structure defines behavior and performance relevant memory object attributes.

RELATED INFORMATION

Functions: memory_object_get_attributes, memory_object_change_attributes, vm_region, memory_object_synchronize, vm_set_default_memory_manager, vm_msync. \ No newline at end of file diff --git a/osfmk/man/memory_object_create.html b/osfmk/man/memory_object_create.html new file mode 100755 index 000000000..89ebee320 --- /dev/null +++ b/osfmk/man/memory_object_create.html @@ -0,0 +1 @@ +

memory_object_create


Function - Request that the default pager handle management requests on the specified memory object.

SYNOPSIS

kern_return_t   memory_object_create
                (memory_object_t                          pager,
                 memory_object_t              new_memory_object,
                 vm_size_t                      new_object_size,
                 memory_object_control_t            new_control,
                 vm_size_t                        new_page_size);


kern_return_t   seqnos_memory_object_create
                (memory_object_t                          pager,
                 mach_port_seqno_t                        seqno,
                 memory_object_t              new_memory_object,
                 vm_size_t                      new_object_size,
                 memory_object_control_t            new_control,
                 vm_size_t                        new_page_size);

PARAMETERS

pager
[in default-pager (receive) right] The default memory manager service port.

seqno
[in scalar] The sequence number of this message relative to the pager port.

new_memory_object
[in abstract-memory-object receive right] The port representing the new abstract memory object created by the kernel.

new_object_size
[in scalar] The expected size for the new object, in bytes.

new_control
[in memory-cache-control send right] The memory cache control port to be used by the memory manager when making cache management requests for the new object.

new_page_size
[in scalar] The page size used by the kernel. All calls involving this kernel must use data sizes that are integral multiples of this page size.

DESCRIPTION

A memory_object_create function is called as the result of a message from the kernel requesting that the default memory manager accept responsibility for the new memory object created by the kernel. The kernel makes this call only to the system default memory manager.

The new memory object initially consists of zero-filled pages. Only memory pages that are actually written are provided to the memory manager. When processing memory_object_data_request calls from the kernel, the default memory manager must use memory_object_data_unavailable for any pages that have not been written previously.

The kernel does not expect a reply to this call. The kernel assumes that the default memory manager will be ready to handle data requests to this object and does not need the confirmation of a memory_object_change_attributes call.

NOTES

The kernel requires memory objects to provide temporary backing storage for zero-filled memory created by vm_allocate calls, issued by both user tasks and the kernel itself. The kernel allocates an abstract memory object port to represent the temporary backing storage and uses memory_object_create to pass the new memory object to the default memory manager, which provides the storage.

The default memory manager is a trusted system component that is identified to the kernel at system initialization time. The default memory manager can also be changed at run time using the host_default_memory_manager call.

The contents of a kernel-created (as opposed to a user-created) memory object can be modified only in main memory. The default memory manager must not change the contents of a temporary memory object, or allow unrelated tasks to access the memory object, control, or name port.

The kernel provides the size of a temporary memory object based on the allocated size. Since the object is not mapped by other tasks, the object will not grow by explicit action. However, the kernel may coalesce adjacent temporary objects in such a way that this object may appear to grow. As such, the supplied object size is merely a hint as to the maximum size.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: default_pager_object_create, memory_object_data_initialize, memory_object_data_unavailable, memory_object_default_server, seqnos_memory_object_default_server. \ No newline at end of file diff --git a/osfmk/man/memory_object_data_error.html b/osfmk/man/memory_object_data_error.html new file mode 100755 index 000000000..804b3027a --- /dev/null +++ b/osfmk/man/memory_object_data_error.html @@ -0,0 +1 @@ +

memory_object_data_error


Function - An error prevents the supply of previously requested data.

SYNOPSIS

kern_return_t   memory_object_data_error
                (memory_object_control_t         memory_control,
                 vm_offset_t                             offset,
                 vm_size_t                                 size,
                 kern_return_t                           reason);

PARAMETERS

memory_control
[in memory-cache-control send right] The memory cache control port to be used by the memory manager for cache management requests. This port is provided by the kernel in a memory_object_create call.

offset
[in scalar] The offset within the memory object, in bytes.

size
[in scalar] The number of bytes of data (starting at offset). The number must convert to an integral number of memory object pages.

reason
[in scalar] Reason for the error.

DESCRIPTION

The memory_object_data_error function indicates that the memory manager cannot provide the kernel with the data requested for the given region, specifying a reason for the error.

When the kernel issues a memory_object_data_request call, the memory manager can respond with a memory_object_data_error call to indicate that the page cannot be retrieved, and that a memory failure exception should be raised in any client threads that are waiting for the page. Clients are permitted to catch these exceptions and retry their page faults. As a result, this call can be used to report transient errors as well as permanent ones. A memory manager can use this call for both hardware errors (for example, disk failures) and software errors (for example, accessing data that does not exist or is protected).

NOTES

If reason has a system code of err_kern, the kernel will substitute an error value of KERN_MEMORY_ERROR.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: memory_object_data_request, memory_object_data_supply, memory_object_data_unavailable. \ No newline at end of file diff --git a/osfmk/man/memory_object_data_request.html b/osfmk/man/memory_object_data_request.html new file mode 100755 index 000000000..2b3dbcb88 --- /dev/null +++ b/osfmk/man/memory_object_data_request.html @@ -0,0 +1 @@ +

memory_object_data_request


Server Interface - Request that memory manager page-in specified data.

SYNOPSIS

kern_return_t   memory_object_data_request
                (memory_object_t                  memory_object,
                 memory_object_control_t         memory_control,
                 vm_offset_t                             offset,
                 vm_size_t                               length,
                 vm_prot_t                       desired_access);


kern_return_t   seqnos_memory_object_data_request
                (memory_object_t                  memory_object,
                 mach_port_seqno_t                        seqno,
                 memory_object_control_t         memory_control,
                 vm_offset_t                             offset,
                 vm_size_t                               length,
                 vm_prot_t                       desired_access);

PARAMETERS

memory_object
[in abstract-memory-object (receive) right] The abstract memory object port that represents the memory object data.

seqno
[in scalar] The sequence number of this message relative to the abstract memory object port.

memory_control
[in memory-cache-control send right] The memory cache control port to be used for a response by the memory manager. If the memory object has been supplied to more than one kernel, this parameter identifies the kernel that is making the call.

offset
[in scalar] The offset within the memory object.

length
[in scalar] The number of bytes requested, starting at offset. The number converts to an integral number of virtual pages.

desired_access
[in scalar] The memory access modes to be allowed for the cached data. Possible values are obtained by or'ing together the following values:

VM_PROT_READ
Allows read access.

VM_PROT_WRITE
Allows write access.

VM_PROT_EXECUTE
Allows execute access.

DESCRIPTION

A memory_object_data_request function is called as the result of a kernel message requesting data from the specified memory object, for at least the access specified.

The kernel issues this call after a cache miss (that is, a page fault for which the kernel does not have the data). The kernel requests only amounts of data that are multiples of the page size included in the memory_object_init or memory_object_create call.

The memory manager is expected to use memory_object_data_supply to return at least the specified data, with as much access as it can allow. If the memory manager cannot provide the data (for example, because of a hardware error), it can use the memory_object_data_error call. The memory manager can also use memory_object_data_unavailable to tell the kernel to supply zero-filled memory for the region.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: memory_object_data_error, memory_object_data_supply, memory_object_data_unavailable, memory_object_server, seqnos_memory_object_server. \ No newline at end of file diff --git a/osfmk/man/memory_object_data_return.html b/osfmk/man/memory_object_data_return.html new file mode 100755 index 000000000..38abcef38 --- /dev/null +++ b/osfmk/man/memory_object_data_return.html @@ -0,0 +1 @@ +

memory_object_data_return


Server Interface - Return memory object data to the appropriate memory manager.

SYNOPSIS

kern_return_t   memory_object_data_return
                (memory_object_t                  memory_object,
                 memory_object_control_t         memory_control,
                 vm_offset_t                             offset,
                 pointer_t                                 data,
                 boolean_t                                dirty,
                 boolean_t                          kernel_copy);


kern_return_t   seqnos_memory_object_data_return
                (memory_object_t                  memory_object,
                 mach_port_seqno_t                        seqno,
                 memory_object_control_t         memory_control,
                 vm_offset_t                             offset,
                 pointer_t                                 data,
                 boolean_t                                dirty,
                 boolean_t                          kernel_copy);

PARAMETERS

memory_object
[in abstract-memory-object (receive) right] The abstract memory object port that represents the memory object data.

seqno
[in scalar] The sequence number of this message relative to the abstract memory object port.

memory_control
[in memory-cache-control send right] The memory cache control port to be used for a response by the memory manager. If the memory object has been supplied to more than one kernel, this parameter identifies the kernel that is making the call.

offset
[in scalar] The offset within the memory object.

data
[in pointer to dynamic array of bytes] The data that has been evicted from the physical memory cache.

dirty
[in scalar] If TRUE, the pages returned have been modified.

kernel_copy
[in scalar] If TRUE, the kernel has kept a copy of the page.

DESCRIPTION

A memory_object_data_return function is called as the result of a kernel message providing the memory manager with data that has been evicted from the physical memory cache.

The kernel writes back only data that has been modified or is precious. When the memory manager no longer needs the data (for example, after the data has been written to permanent storage), it should use vm_deallocate to release the memory resources.

NOTES

The kernel can flush clean (that is, un-modified) non-precious pages at its own discretion. As a result, the memory manager cannot rely on the kernel to keep a copy of its data or even to provide notification that its data has been discarded.

The kernel may re-request the returned data at any time following this message (including immediately).

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: memory_object_data_supply, vm_deallocate, memory_object_synchronize, memory_object_server, seqnos_memory_object_server. \ No newline at end of file diff --git a/osfmk/man/memory_object_data_supply.html b/osfmk/man/memory_object_data_supply.html new file mode 100755 index 000000000..961d523f0 --- /dev/null +++ b/osfmk/man/memory_object_data_supply.html @@ -0,0 +1 @@ +

memory_object_data_supply


Function - Provide kernel with data previously requested by the kernel's Memory Management facility.

SYNOPSIS

kern_return_t   memory_object_data_supply
                (mem_object_control_port_t       memory_control,
                 vm_offset_t                             offset,
                 pointer_t                                 data,
                 mach_msg_type_number_t              data_count,
                 boolean_t                           deallocate,
                 vm_prot_t                           lock_value,
                 boolean_t                             precious,
                 mach_port_t                         reply_port);

PARAMETERS

memory_control
[in memory-cache-control send right] The memory cache control port to be used by the memory manager for cache management requests. This port is provided by the kernel in a memory_object_init or memory_object_create call.

offset
[in scalar] The offset within the memory object, in bytes.

data
[pointer to page aligned in array of bytes] The address of the data being provided to the kernel.

data_count
[in scalar] The amount of data to be provided. The number must be an integral number of memory object pages.

deallocate
[in scalar] If TRUE, the pages to be copied (starting at data) will be deallocated from the memory manager's address space as a result of being copied into the message, allowing the pages to be moved into the kernel instead of being physically copied.

lock_value
[in scalar] One or more forms of access not permitted for the specified data. Valid values are:

VM_PROT_NONE
Prohibits no access (that is, all forms of access are permitted).

VM_PROT_READ
Prohibits read access.

VM_PROT_WRITE
Prohibits write access.

VM_PROT_EXECUTE
Prohibits execute access.

VM_PROT_ALL
Prohibits all forms of access.

precious
[in scalar] If TRUE, the pages being supplied are "precious," that is, the memory manager is not (necessarily) retaining its own copy. These pages must be returned to the manager when evicted from memory, even if not modified.

reply_port
[in reply receive (to be converted to send) right] A port to which the kernel should send a memory_object_supply_completed to indicate the status of the accepted data. MACH_PORT_NULL is allowed. The reply message indicates which pages have been accepted.

DESCRIPTION

The memory_object_data_supply function supplies the kernel with a range of data for the specified memory object. A memory manager can only provide data that was requested by a memory_object_data_request call from the kernel.

NOTES

The kernel accepts only integral numbers of pages. It discards any partial pages without notification.

CAUTIONS

A memory manager must be careful that it not attempt to provide data that has not been explicitly requested. In particular, a memory manager must ensure that it does not provide writable data again before it receives back modifications from the kernel. This may require that the memory manager remember which pages it has provided, or that it exercise other cache control functions (via memory_object_lock_request) before proceeding. The kernel prohibits the overwriting of live data pages and will not accept pages it has not requested.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: memory_object_data_error, memory_object_data_request, memory_object_data_unavailable, memory_object_lock_request, memory_object_supply_completed. \ No newline at end of file diff --git a/osfmk/man/memory_object_data_unlock.html b/osfmk/man/memory_object_data_unlock.html new file mode 100755 index 000000000..13a440c9a --- /dev/null +++ b/osfmk/man/memory_object_data_unlock.html @@ -0,0 +1 @@ +

memory_object_data_unlock


Server Interface - Request that the memory manager change current access permission on the specified memory object's data.

SYNOPSIS

kern_return_t   memory_object_data_unlock
                (memory_object_t                  memory_object,
                 memory_object_control_t         memory_control,
                 vm_offset_t                             offset,
                 vm_size_t                               length,
                 vm_prot_t                       desired_access);


kern_return_t   seqnos_memory_object_data_unlock
                (memory_object_t                  memory_object,
                 mach_port_seqno_t                        seqno,
                 memory_object_control_t         memory_control,
                 vm_offset_t                             offset,
                 vm_size_t                               length,
                 vm_prot_t                       desired_access);

PARAMETERS

memory_object
[in abstract-memory-object (receive) right] The abstract memory object port that represents the memory object data.

seqno
[in scalar] The sequence number of this message relative to the abstract memory object port.

memory_control
[in memory-cache-control send right] The memory cache control port to be used for a response by the memory manager. If the memory object has been supplied to more than one kernel, this parameter identifies the kernel that is making the call.

offset
[in scalar] The offset within the memory object.

length
[in scalar] The number of bytes to which the access applies, starting at offset. The number converts to an integral number of memory object pages.

desired_access
[in scalar] The memory access modes requested for the cached data. Possible values are obtained by or'ing together the following values:

VM_PROT_READ
Allows read access.

VM_PROT_WRITE
Allows write access.

VM_PROT_EXECUTE
Allows execute access.

DESCRIPTION

A memory_object_data_unlock function is called as the result of a kernel message requesting the memory manager to permit at least the desired access to the specified data cached by the kernel. The memory manager is expected to use the memory_object_lock_request call in response.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: memory_object_lock_completed, memory_object_lock_request, memory_object_server, seqnos_memory_object_server. \ No newline at end of file diff --git a/osfmk/man/memory_object_destroy.html b/osfmk/man/memory_object_destroy.html new file mode 100755 index 000000000..8352832ee --- /dev/null +++ b/osfmk/man/memory_object_destroy.html @@ -0,0 +1 @@ +

memory_object_destroy


Function - Shut down a memory object.

SYNOPSIS

kern_return_t   memory_object_destroy
                (memory_object_control_t         memory_control,
                 kern_return_t                           reason);

PARAMETERS

memory_control
[in memory-cache-control send right] The memory cache control port to be used by the memory manager for cache management requests. This port is provided by the kernel in a memory_object_init call.

reason
[in scalar] An error code indicating when the object must be destroyed.

DESCRIPTION

The memory_object_destroy function tells the kernel to shut down the specified memory object. As a result of this call, the kernel no longer supports paging activity or any memory object calls on the memory object. The kernel issues a memory_object_terminate call to pass to the memory manager all rights to the memory object port and the memory control port.

To ensure that any modified cached data is returned before the object is terminated, the memory manager should call memory_object_lock_request with should_flush set and a lock value of VM_PROT_WRITE before it makes the memory_object_destroy call.

NOTES

The reason code is currently ignored by the kernel.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: memory_object_lock_request, memory_object_terminate. \ No newline at end of file diff --git a/osfmk/man/memory_object_init.html b/osfmk/man/memory_object_init.html new file mode 100755 index 000000000..8ca621968 --- /dev/null +++ b/osfmk/man/memory_object_init.html @@ -0,0 +1 @@ +

memory_object_init


Server Interface - Initializes a memory object.

SYNOPSIS

kern_return_t   memory_object_init
		(memory_object_t                memory_object,
		 memory_object_control_t       memory_control,
		 vm_size_t            memory_object_page_size);


kern_return_t   seqnos_memory_object_init
		(memory_object_t                memory_object,
		 mach_port_seqno_t                      seqno,
		 memory_object_control_t       memory_control,
		 vm_size_t            memory_object_page_size);

PARAMETERS

memory_object
[in abstract-memory-object port] The abstract memory object port that represents the memory object data, as supplied to the kernel in a vm_map call.

seqno
[in scalar] The sequence number of this message relative to the abstract memory object port.

memory_control
[in memory-cache-control port] The memory cache control port to be used by the memory manager. If the memory object has been supplied to more than one kernel, this parameter identifies the kernel that is making the call.

memory_object_page_size
[in scalar] The page size used by the kernel. All calls involving this kernel must use data sizes that are integral multiples of this page size.

DESCRIPTION

A memory_object_init function is called as the result of a kernel message notifying a memory manager that the kernel has been asked to map the specified memory object into a task's virtual address space. When asked to map a memory object for the first time, the kernel responds by making a memory_object_init call on the abstract memory object. This call is provided as a convenience to the memory manager, to allow it to initialize data structures and prepare to receive other requests.

In addition to the abstract memory object port itself, the call provides a memory cache control port that the memory manager can use to control use of its data by the kernel. The memory manager gets send rights for this port.

The kernel holds send rights for the abstract memory object port, and both send and receive rights for the memory cache control port. The call also supplies the virtual page size to be used for the memory mapping. The memory manager can use this size to detect mappings that use different data structures at initialization time, or to allocate buffers for use in reading data.

If a memory object is mapped into the address space of more than one task on different hosts (with independent kernels), the memory manager will receive a memory_object_init call from each kernel, containing a unique set of control and name ports. Note that each kernel may also use a different page size.

RETURN VALUES

Any return value other than KERN_SUCCESS or MIG_NO_REPLYwill cause mach_msg_server to remove the memory cache control reference.

RELATED INFORMATION

Functions: memory_object_terminate. \ No newline at end of file diff --git a/osfmk/man/memory_object_lock_request.html b/osfmk/man/memory_object_lock_request.html new file mode 100755 index 000000000..4adc569e2 --- /dev/null +++ b/osfmk/man/memory_object_lock_request.html @@ -0,0 +1 @@ +

memory_object_lock_request


Function - Restrict access to memory object data.

SYNOPSIS

kern_return_t   memory_object_lock_request
                (memory_object_control_t         memory_control,
                 vm_offset_t                             offset,
                 vm_size_t                                 size,
                 memory_object_return_t           should_return,
                 boolean_t                         should_flush,
                 vm_prot_t                           lock_value,
                 mach_port_t                         reply_port);

PARAMETERS

memory_control
[in memory-cache-control send right] The memory cache control port to be used by the memory manager for cache management requests. This port is provided by the kernel in a memory_object_init call.

offset
[in scalar] The offset within the memory object, in bytes.

size
[in scalar] The number of bytes of data (starting at offset) to be affected. The number must convert to an integral number of memory object pages.

should_return
[in scalar] Clean indicator. Values are:

MEMORY_OBJECT_RETURN_NONE
Don't return any pages. If should_flush is TRUE, pages will be discarded.

MEMORY_OBJECT_RETURN_DIRTY
Return only dirty (modified) pages. If should_flush is TRUE, precious pages will be discarded; otherwise, the kernel maintains responsibility for precious pages.

MEMORY_OBJECT_RETURN_ALL
Both dirty and precious pages are returned. If should_flush is FALSE, the kernel maintains responsibility for the precious pages.

MEMORY_OBJECT_RETURN_ANYTHING
Any resident pages are returned. If should_flush is TRUE, precious pages will be discarded; otherwise, the kernel maintains responsibility for precious pages.

should_flush
[in scalar] Flush indicator. If true, the kernel discards all pages within the range.

lock_value
[in scalar] One or more forms of access not permitted for the specified data. Valid values are:

VM_PROT_NO_CHANGE
Do not change the protection of any pages.

VM_PROT_NONE
Prohibits no access (that is, all forms of access are permitted).

VM_PROT_READ
Prohibits read access.

VM_PROT_WRITE
Prohibits write access.

VM_PROT_EXECUTE
Prohibits execute access.

VM_PROT_ALL
Prohibits all forms of access.

reply_port
[in reply receive (to be converted to send) right] The response port to be used by the kernel on a call to memory_object_lock_completed, or MACH_PORT_NULL if no response is required.

DESCRIPTION

The memory_object_lock_request function allows the memory manager to make the following requests of the kernel:

  • Clean the pages within the specified range by writing back all changed (that is, dirty) and precious pages. The kernel uses the memory_object_data_return call to write back the data. The should_return parameter must be set to non-zero.

  • Flush all cached data within the specified range. The kernel invalidates the range of data and revokes all uses of that data. The should_flush parameter must be set to true.

  • Alter access restrictions specified in the memory_object_data_supply call or a previous memory_object_lock_request call. The lock_value parameter must specify the new access restrictions. Note that this parameter can be used to unlock previously locked data.

Once the kernel performs all of the actions requested by this call, it issues a memory_object_lock_completed call using the reply_to port.

NOTES

The memory_object_lock_request call affects only data that is cached at the time of the call. Access restrictions cannot be applied to pages for which data has not been provided.

When a running thread requires an access that is currently prohibited, the kernel issues a memory_object_data_unlock call specifying the access required. The memory manager can then use memory_object_lock_request to relax its access restrictions on the data.

To indicate that an unlock request is invalid (that is, requires permission that can never be granted), the memory manager must first flush the page. When the kernel requests the data again with the higher permission, the memory manager can indicate the error by responding with a call to memory_object_data_error.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: memory_object_data_supply, memory_object_data_unlock, memory_object_lock_completed. \ No newline at end of file diff --git a/osfmk/man/memory_object_perf_info.html b/osfmk/man/memory_object_perf_info.html new file mode 100755 index 000000000..4af60607f --- /dev/null +++ b/osfmk/man/memory_object_perf_info.html @@ -0,0 +1 @@ +

memory_object_perf_info


Structure - Specifies a memory object's attributes with respect to performance.

SYNOPSIS

struct  memory_object_perf_info
{
        vm_offset_t      cluster_size;
        boolean_t    may_cache_object;
};

typedef struct memory_object_perf_info* memory_object_perf_info_t;

FIELDS

cluster_size
Preferred cluster size (in bytes) for the memory object. This helps to determine how many pages are transferred in individual data request and return messages.

may_cache_object
Cache indicator. If true, the kernel can cache data associated with the memory object (keep the memory object active) even if no virtual memory references to it remain.

DESCRIPTION

The memory_object_perf_info structure defines a memory object's character with respect to performance.

NOTES

Sharing cached data among all the clients of a memory object can have a major impact on performance, especially if it can be extended across successive, as well as concurrent, uses. For example, the memory objects that represent program images can be used regularly by different programs. By retaining the data for these memory objects in cache, the number of secondary storage accesses can be reduced significantly.

RELATED INFORMATION

Functions: memory_object_get_attributes, memory_object_change_attributes, vm_region, memory_object_synchronize, vm_set_default_memory_manager, vm_msync.

Structures: memory_object_attr_info. \ No newline at end of file diff --git a/osfmk/man/memory_object_server.html b/osfmk/man/memory_object_server.html new file mode 100755 index 000000000..7e10a7894 --- /dev/null +++ b/osfmk/man/memory_object_server.html @@ -0,0 +1 @@ +

memory_object_server


Function - Handle kernel operation request aimed at a given memory manager.

SYNOPSIS

boolean_t	memory_object_server
		(mach_msg_header_t	request_msg,
		mach_msg_header_t	reply_ms);

PARAMETERS

in_msg
[pointer to in structure] The memory manager message received from the kernel.

out_msg
[out structure] A reply message. No messages to a memory manager expect a direct reply, so this field is not used.

DESCRIPTION

The memory_object_server function is the MIG generated server handling function to handle messages from the kernel targeted to a memory manager.

A \*Vmemory manager\*O is a server task that responds to specific messages from the kernel in order to handle memory management functions for the kernel. The memory_object_server function performs all necessary argument handling for a kernel message and calls one of the memory manager functions to interpret the message.

RETURN VALUES

TRUE
The message was handled and the appropriate function was called.

FALSE
The message did not apply to this memory management interface and no other action was taken.

RELATED INFORMATION

Functions: memory_object_default_server, memory_object_data_request, memory_object_data_return, memory_object_data_unlock, memory_object_lock_completed, memory_object_change_completed, memory_object_supply_completed, memory_object_terminate, memory_object_synchronize, seqnos_memory_object_server. \ No newline at end of file diff --git a/osfmk/man/memory_object_synchronize.html b/osfmk/man/memory_object_synchronize.html new file mode 100755 index 000000000..d446307a0 --- /dev/null +++ b/osfmk/man/memory_object_synchronize.html @@ -0,0 +1 @@ +

memory_object_synchronize


Server Interface - Forward a client's request to synchronize data with its image in backing store.

SYNOPSIS

kern_return_t   memory_object_synchronize
                (memory_object_t                  memory_object,
                 memory_object_control_t         memory_control,
                 vm_offset_t                             offset,
                 vm_offset_t                             length,
                 memory_object                       sync_flags);


kern_return_t   seqnos_memory_object_synchronize
                (memory_object_t                  memory_object,
                 mach_port_seqno_t                        seqno,
                 memory_object_control_t         memory_control,
                 vm_offset_t                             offset,
                 vm_offset_t                             length,
                 memory_object                       sync_flags);

PARAMETERS

memory_object
[in abstract-memory-object (receive) right] The abstract memory object port that represents the memory object data.

seqno
[in scalar] The sequence number of this message relative to the abstract memory object port.

memory_control
[in memory-cache-control send right] The memory cache control port to be used for a response by the memory manager. If the memory object has been supplied to more than one kernel, this parameter identifies the kernel that is making the call.

offset
[in scalar] The offset within the memory object.

length
[in scalar] The number of bytes cleaned or flushed, starting at offset. The number converts to an integral number of virtual pages.

sync_flags
[in scalar] The bit-wise OR of flags affecting the synchronization.

VM_SYNC_INVALIDATE
Flushes pages in the range. Only precious pages are returned to the memory manager.

VM_SYNC_SYNCHRONOUS
Writes dirty and precious pages back to the memory manager, waits for pages to reach backing storage.

VM_SYNC_ASYNCHRONOUS
Writes dirty and precious pages back to the memory manager, returns without waiting for pages to reach backing storage.

DESCRIPTION

A memory_object_synchronize function is called as the result of a kernel message indicating that a client wishes to synchronize the contents of a range of a memory object with its backing storage image. This message would have been preceded by memory_object_data_return messages cleaning or flushing the specified range.

Depending on the client's supplied sync_flags, the manager waits for the pages to reach the desired state and then replies with memory_object_synchronize_completed at which time the client returns from its vm_msync call. Multiple synchronize requests may be outstanding at a time but they will not overlap.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: vm_msync, memory_object_synchronize_completed, memory_object_data_return, memory_object_server, seqnos_memory_object_server. \ No newline at end of file diff --git a/osfmk/man/memory_object_terminate.html b/osfmk/man/memory_object_terminate.html new file mode 100755 index 000000000..a635d3331 --- /dev/null +++ b/osfmk/man/memory_object_terminate.html @@ -0,0 +1 @@ +

memory_object_terminate


Server Interface - Relinquish access to a memory object.

SYNOPSIS

kern_return_t   memory_object_terminate
                (memory_object_t                  memory_object,
                 memory_object_control_t         memory_control);



kern_return_t   seqnos_memory_object_terminate
                (memory_object_t                  memory_object,
                 mach_port_seqno_t                        seqno,
                 memory_object_control_t         memory_control);

PARAMETERS

memory_object
[in abstract-memory-object (receive) right] The abstract memory object port that represents the memory object data.

seqno
[in scalar] The sequence number of this message relative to the abstract memory object port.

memory_control
[in memory-cache-control receive right] The memory cache control port to be used for a response by the memory manager. If the memory object has been supplied to more than one kernel, this parameter identifies the kernel that is making the call.

DESCRIPTION

A memory_object_terminate function is called as the result of a kernel message notifying a memory manager that no mappings of the specified memory object remain. The kernel makes this call to allow the memory manager to clean up data structures associated with the deallocated mappings. The call provides receive rights to the memory cache control port so that the memory manager can retrieve any messages it sent into this port before knowing the memory object was being terminated and then destroy the port. The kernel also relinquishes its rights for all memory object ports.

The kernel terminates a memory object only after all address space mappings of the object have been deallocated, or upon explicit request by the memory manager.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: memory_object_destroy, mach_port_deallocate, memory_object_server, seqnos_memory_object_server. \ No newline at end of file diff --git a/osfmk/man/norma_get_special_port.html b/osfmk/man/norma_get_special_port.html new file mode 100755 index 000000000..4a1416d7f --- /dev/null +++ b/osfmk/man/norma_get_special_port.html @@ -0,0 +1 @@ +

norma_get_special_port


Function - Acquire a send right for a specified node-specific special port.

SYNOPSIS

kern_return_t   norma_get_special_port
                (host_priv_t                          host_priv,
                 int                                       node,
                 int                                 which_port,
                 mach_port_t                       special_port);

Macro forms:


#include<mach/norma_special_ports.h>

kern_return_t   norma_get_device_port
                (host_priv_t                          host_priv,
                 int                                       node,
                 mach_port_t                       special_port);

kern_return_t   norma_get_host_port
                (host_priv_t                          host_priv,
                 int                                       node,
                 mach_port_t                       special_port);

kern_return_t   norma_get_host_priv_port
                (host_priv_t                          host_priv,
                 int                                       node,
                 mach_port_t                       special_port);

kern_return_t   norma_get_nameserver_port
                (host_priv_t                          host_priv,
                 int                                       node,
                 mach_port_t                       special_port);

PARAMETERS

host_priv
[in host-control send right] The control port for the host for which to return the special port's send right.

node
[in scalar] The index of the node for which the port is desired.

which_port
[in scalar] The index of the special port for which the send right is requested. Valid values are:

NORMA_DEVICE_PORT
[device-master send right] The device master port for the node.

NORMA_HOST_PORT
[host-name send right] The host name port for the node.

NORMA_HOST_PRIV_PORT
[host-control send right] The host control port for the node.

NORMA_NAMESERVER_PORT
[name-server send right] The registered name server port for the node.

special_port
[out norma-special send right] The returned value for the port.

DESCRIPTION

The norma_get_special_port function returns a send right for a special port belonging to node on host_priv.

Each node maintains a (small) set of node specific ports. The device master port, host name, and host control ports are maintained by the kernel. The kernel also permits a small set of server specified node specific ports; the name server port is an example and is given (by convention) an assigned special port index.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: mach_host_self, norma_get_special_port, bootstrap_ports. \ No newline at end of file diff --git a/osfmk/man/norma_node_self.html b/osfmk/man/norma_node_self.html new file mode 100755 index 000000000..caa6cfae4 --- /dev/null +++ b/osfmk/man/norma_node_self.html @@ -0,0 +1 @@ +

norma_node_self


Function - Return the node index of the current host.

SYNOPSIS

kern_return_t   norma_node_self
                (host_t                                    host,
                 int                                        int);

PARAMETERS

host
[in host send-right] Name of the host.

node
[out scalar] Node index of the host.

DESCRIPTION

The norma_node_self function returns the node index of the current host.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: norma_task_create, norma_task_clone, \ No newline at end of file diff --git a/osfmk/man/norma_port_location_hint.html b/osfmk/man/norma_port_location_hint.html new file mode 100755 index 000000000..99ecc9217 --- /dev/null +++ b/osfmk/man/norma_port_location_hint.html @@ -0,0 +1 @@ +

norma_port_location_hint


Function - Guess a port's current location.

SYNOPSIS

kern_return_t   norma_port_location_hint
                (task_t                                    task,
                 mach_port_t                               name,
                 int                                       node);

PARAMETERS

task
[in task send right] Task containing the right to locate

name
[in scalar] Name of the right to locate

node
[out scalar] Port location hint

DESCRIPTION

The norma_port_location_hint function returns the best guess of name's current location. The hint is guaranteed to be a node where the port once was; it is guaranteed to be accurate if port has never moved. This can be used to determine residence node for hosts, tasks, threads, etc.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: norma_task_create. \ No newline at end of file diff --git a/osfmk/man/norma_set_special_port.html b/osfmk/man/norma_set_special_port.html new file mode 100755 index 000000000..2624fe432 --- /dev/null +++ b/osfmk/man/norma_set_special_port.html @@ -0,0 +1 @@ +

norma_set_special_port


Function - Set node-specific special port.

SYNOPSIS

kern_return_t   norma_set_special_port
                (host_priv_t                          host_priv,
                 int                                 which_port,
                 mach_port_t                       special_port);

Macro forms:


#include<mach/norma_special_ports.h>

kern_return_t   norma_set_device_port
                (host_priv_t                          host_priv,
                 mach_port_t                       special_port);

kern_return_t   norma_set_host_port
                (host_priv_t                          host_priv,
                 mach_port_t                       special_port);

kern_return_t   norma_set_host_priv_port
                (host_priv_t                          host_priv,
                 int                                       node,
                 mach_port_t                       special_port);

kern_return_t   norma_set_nameserver_port
                (host_priv_t                          host_priv,
                 mach_port_t                       special_port);

PARAMETERS

host_priv
[in host-control send right] The host for which to set the special port. Currently, this must be the per-node host control port.

node
[in scalar] The index of the node for which the port is to be set.

which_port
[in scalar] The index of the special port to be set. Valid values are:

NORMA_DEVICE_PORT
[device-master send right] The device master port for the node.

NORMA_HOST_PORT
[host-name send right] The host name port for the node.

NORMA_HOST_PRIV_PORT
[host-control send right] The host control port for the node.

NORMA_NAMESERVER_PORT
[name-server send right] The registered name server port for the node.

special_port
[in norma-special send right] Send right to the new special port.

DESCRIPTION

The norma_set_special_port function sets the special port belonging to node on host_priv.

Each node maintains a (small) set of node specific ports. The device master port, host name, and host control ports are maintained by the kernel. The kernel also permits a small set of server specified node specific ports; the name server port is an example and is given (by convention) an assigned special port index.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: mach_host_self, norma_get_special_port. \ No newline at end of file diff --git a/osfmk/man/norma_task_clone.html b/osfmk/man/norma_task_clone.html new file mode 100755 index 000000000..129835dab --- /dev/null +++ b/osfmk/man/norma_task_clone.html @@ -0,0 +1 @@ +

norma_task_clone


Function - Create a remote task that shares access to parent task's memory regardless of inheritance attributes.

SYNOPSIS

kern_return_t   norma_task_clone
                (task_t                             parent_task,
                 boolean_t                       inherit_memory,
                 int                                 child_node,
                 task_t                              child_task);

PARAMETERS

parent_task
[in task send right] The port for the task from which to draw the child task's port rights, resource limits, and address space.

inherit_memory
[in scalar] Address space inheritance indicator. If true, the child task inherits the address space of the parent task. If false, the kernel assigns the child task an empty address space.

child_node
[in scalar] The node index of the node on which to create the child.

child_task
[out task send right] The kernel-assigned port name for the new task.

DESCRIPTION

The norma_task_clone function "clones" a new task from parent_task on the specified node and returns the name of the new task in child_task. The child task acquires shared parts of the parent's address space (see vm_inherit) regardless of the inheritance set for the parent's memory regions, although the inheritance for the child's regions will be set to that of the parent's regions. The child task initially contains no threads.

By way of comparison, tasks created by the standard task_create primitive are created on the same node as the parent.

Other than being created on a different node, the new task has the same properties as if created by task_create.

NOTES

This call differs from norma_task_create in that the inheritance set for the parent's memory regions is ignored; the child always shares memory with the parent.

This call is intended to support process migration, where the inheritance semantics of norma_task_create would break migrated programs that depended upon sharing relationships remaining after migration.

This call is not a true task migration call, in that it does not migrate the port space, threads, and other non-address-space attributes of the task.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: task_create, norma_task_create. \ No newline at end of file diff --git a/osfmk/man/norma_task_create.html b/osfmk/man/norma_task_create.html new file mode 100755 index 000000000..09e57be8e --- /dev/null +++ b/osfmk/man/norma_task_create.html @@ -0,0 +1 @@ +

norma_task_create


Function - Create a remote task using task_create semantics.

SYNOPSIS

kern_return_t   norma_task_create
                (task_t                             parent_task,
                 boolean_t                       inherit_memory,
                 int                                 child_node,
                 task_t                              child_task);

PARAMETERS

parent_task
[in task send right] The port for the task from which to draw the child task's port rights, resource limits, and address space.

inherit_memory
[in scalar] Address space inheritance indicator. If true, the child task inherits the address space of the parent task. If false, the kernel assigns the child task an empty address space.

child_node
[in scalar] The node index of the node on which to create the child.

child_task
[out task send right] The kernel-assigned port name for the new task.

DESCRIPTION

The norma_task_create function creates a new task from parent_task on the specified node and returns the name of the new task in child_task. The child task acquires shared or copied parts of the parent's address space (see vm_inherit). The child task initially contains no threads.

By way of comparison, tasks created by the standard task_create primitive are created on the same node as the parent.

Other than being created on a different node, the new task has the same properties as if created by task_create.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: task_create, norma_task_clone. \ No newline at end of file diff --git a/osfmk/man/norma_task_teleport.html b/osfmk/man/norma_task_teleport.html new file mode 100755 index 000000000..698839391 --- /dev/null +++ b/osfmk/man/norma_task_teleport.html @@ -0,0 +1 @@ +

norma_task_teleport


Function - "Clone" a task on a specified node.

SYNOPSIS

kern_return_t   norma_task_teleport
                (task_t                             parent_task,
                 boolean_t                       inherit_memory,
                 int                                 child_node,
                 task_t                              child_task);

PARAMETERS

parent_task
[in task send right] The port for the task from which to draw the child task's port rights, resource limits, and address space.

inherit_memory
[in scalar] Address space inheritance indicator. If true, the child task in- herits the address space of the parent task. If false, the kernel assigns the child task an empty address space.

child_node
[in scalar] The node index of the node on which to create the child.

child_task
[out task send right] The kernel-assigned port name for the new task.

DESCRIPTION

The norma_task_clone function "clones" a new task from parent_task on the specified node and returns the name of the new task in child_task. The child task acquires shared parts of the parent's address space (see vm_inherit) regardless of the inheritance set for the parent's memory regions, although the inheritance for the child's regions will be set to that of the parent's regions. The child task initially contains no threads. The parent_task is then terminated. By way of comparison, tasks created by the standard task_create primitive are created on the same node as the parent. Other than being created on a different node, the new task has the same properties as if created by task_create.

NOTES

This call differs from norma_task_clone in that the parent task is terminated as part of the teleport call. This call differs from norma_task_create in that the inheritance set for the parent's memory regions is ignored; the child always shares memory with the parent. This call is intended to support process migration, where the inheritance semantics of norma_task_create would break migrated programs that depended upon sharing relationships remaining after migration. This call is not a true task migration call, in that it does not migrate the port space, threads, and other non-address-space attributes of the task.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: norma_task_clone, task_create, norma_task_create, \ No newline at end of file diff --git a/osfmk/man/notify_server.html b/osfmk/man/notify_server.html new file mode 100755 index 000000000..0984e5122 --- /dev/null +++ b/osfmk/man/notify_server.html @@ -0,0 +1 @@ +

notify_server


Function - Handle the next kernel-generated IPC notification.

SYNOPSIS

boolean_t	notify_server
		(mach_msg_header_t	request_msg,
		mach_msg_header_t	reply_ms);

PARAMETERS

in_msg
[pointer to in structure] The notification message received from the kernel.

out_msg
[out structure] Not used.

DESCRIPTION

The notify_server function is the MIG generated server handling function to handle messages from the kernel corresponding to IPC notifications. Such messages are delivered to the notification port named in a mach_msg or mach_port_request_notification call. The notify_server function performs all necessary argument handling for this kernel message and calls the appropriate handling function. These functions must be supplied by the caller.

RETURN VALUES

TRUE
The message was handled and the appropriate function was called.

FALSE
The message did not apply to the notification mechanism and no other action was taken.

RELATED INFORMATION

Functions: seqnos_notify_server, do_mach_notify_dead_name, do_mach_notify_no_senders, do_mach_notify_port_deleted, do_mach_notify_send_once. \ No newline at end of file diff --git a/osfmk/man/policy_fifo_info.html b/osfmk/man/policy_fifo_info.html new file mode 100755 index 000000000..2e8acea7e --- /dev/null +++ b/osfmk/man/policy_fifo_info.html @@ -0,0 +1 @@ +

policy_fifo_info


Structure - Specifies information associated with the system's First-In-First-Out scheduling policy.

SYNOPSIS

struct policy_fifo_limit
{
       int                    max_priority;
};

struct policy_fifo_base
{
       int                  base_priority;
};

struct policy_fifo_info
{
       int                   max_priority;
       int                  base_priority;
       boolean_t                depressed;
       int               depress_priority;
};

FIELDS

max_priority
Maximum scheduling priority

base_priority
Scheduling priority

depressed
True if scheduling priority is depressed

depress_priority
Scheduling priority from which depressed

DESCRIPTION

The policy_fifo_info structure defines the first-in-first-out scheduling policy information. FIFO threads have two priorities associated with them by the system:

  • A maximum priority value which can be raised only via privileged operation so that users may not unfairly compete with other users in their processor set. Newly created threads obtain their maximum priority from that of their assigned processor set.

  • A priority value which can be set by the thread to any value up to a maximum priority. Newly created threads obtain their priority from their task.

RELATED INFORMATION

Functions: thread_info, task_info, processor_set_info, processor_set_policy_control, processor_set_policy_disable, processor_set_policy_enable, task_policy, thread_policy, thread_set_policy.

Data Structures: policy_rr_info, policy_timeshare_info. \ No newline at end of file diff --git a/osfmk/man/policy_rr_info.html b/osfmk/man/policy_rr_info.html new file mode 100755 index 000000000..a1c44df58 --- /dev/null +++ b/osfmk/man/policy_rr_info.html @@ -0,0 +1 @@ +

policy_rr_info


Structure - Specifies information associated with the system's Round Robin scheduling policy.

SYNOPSIS

struct policy_rr_limit
{
       int          max_priority;
};

struct policy_rr_base
{
       int         base_priority;
       int               quantum;
};

struct policy_rr_info
{
       int          max_priority;
       int         base_priority;
       int               quantum;
       boolean_t       depressed;
       int      depress_priority;
};

FIELDS

max_priority
Maximum scheduling priority

base_priority
Scheduling priority

quantum
Scheduling quantum (in milliseconds)

depressed
True if scheduling priority is depressed

depress_priority
Scheduling priority from which depressed

DESCRIPTION

The policy_rr_info structure defines the round-robin scheduling policy information. Round-robin threads have two priorities associated with them by the system:

  • A maximum priority value which can be raised only via privileged operation so that users may not unfairly compete with other users in their processor set. Newly created threads obtain their maximum priority from that of their assigned processor set.

  • A priority value which can be set by the thread to any value up to a maximum priority. Newly created threads obtain their priority from their task.

RELATED INFORMATION

Functions: thread_info, task_info, processor_set_info, processor_set_policy_control, processor_set_policy_disable, processor_set_policy_enable, task_policy, thread_policy, thread_set_policy.

Data Structures: policy_fifo_info, policy_timeshare_info. \ No newline at end of file diff --git a/osfmk/man/policy_timeshare_info.html b/osfmk/man/policy_timeshare_info.html new file mode 100755 index 000000000..6682c025b --- /dev/null +++ b/osfmk/man/policy_timeshare_info.html @@ -0,0 +1 @@ +

policy_timeshare_info


Structure - Specifies information associated with the system's Timeshare scheduling policy.

SYNOPSIS

struct policy_timeshare_limit
{
       int            max_priority;
};

struct policy_timeshare_base
{
       int           base_priority;
};

struct policy_timeshare_info
{
       int            max_priority;
       int           base_priority;
       int            cur_priority;
       boolean_t         depressed;
       int        depress_priority;
};

FIELDS

max_priority
Maximum scheduling priority.

base_priority
Base scheduling priority.

cur_priority
Current scheduling priority.

depressed
True if scheduling priority is depressed.

depress_priority
Scheduling priority from which depressed.

DESCRIPTION

The policy_timeshare_info structure defines the timeshare scheduling policy information. Timeshare threads have three priorities associated with them by the system:

  • A maximum priority value which can be raised only via privileged operation so that users may not unfairly compete with other users in their processor set. Newly created threads obtain their maximum priority from that of their assigned processor set.

  • A priority value which can be set by the thread to any value up to a maximum priority. Newly created threads obtain their priority from their task.

  • A scheduled priority value which is used to make scheduling decisions for the thread. This value is determined on the basis of the user priority value by the scheduling policy (for time-sharing, this means adding an increment derived from CPU usage).

RELATED INFORMATION

Functions: thread_info, task_info, processor_set_info, processor_set_policy_control, processor_set_policy_disable, processor_set_policy_enable, task_policy, thread_policy, thread_set_policy.

Data Structures: policy_fifo_info, policy_rr_info. \ No newline at end of file diff --git a/osfmk/man/processor_assign.html b/osfmk/man/processor_assign.html new file mode 100755 index 000000000..61e07d89c --- /dev/null +++ b/osfmk/man/processor_assign.html @@ -0,0 +1 @@ +

processor_assign


Function - Assign a processor to a processor set.

SYNOPSIS

kern_return_t	processor_assign
		(processor_t	processor,
		processor_set_t	new_set,
		boolean_t	wait);

PARAMETERS

processor
[in processor send right] The processor to be assigned.
new_set
[in processor-set-control send right] The control port for the processor set into which the processor is to be assigned.
wait
[in scalar] True if the call should wait for the completion of the assignment.

DESCRIPTION

The processor_assign function assigns processor to the set new_set. After the assignment is completed, the processor only executes threads that are assigned to that processor set. Any previous assignment of the processor is nullified. The master processor cannot be re-assigned.

The wait argument indicates whether the caller should wait for the assignment to be completed or should return immediately. Dedicated kernel threads are used to perform processor assignment, so setting wait to FALSE allows assignment requests to be queued and performed more quickly, especially if the kernel has more than one dedicated internal thread for processor assignment.

All processors take clock interrupts at all times. Redirection of other device interrupts away from processors assigned to other than the default processor set is machine dependent.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: processor_set_create, processor_set_info, task_assign, thread_assign. \ No newline at end of file diff --git a/osfmk/man/processor_basic_info.html b/osfmk/man/processor_basic_info.html new file mode 100755 index 000000000..aa0a0395d --- /dev/null +++ b/osfmk/man/processor_basic_info.html @@ -0,0 +1 @@ +

processor_basic_info


Structure - Defines the basic information about a processor.

SYNOPSIS

struct processor_basic_info
{
       cpu_type_t        cpu_type;
       cpu_subtype_t  cpu_subtype;
       boolean_t          running;
       int               slot_num;
       boolean_t        is_master;
};

typedef struct processor_basic_info* processor_basic_info_t;

FIELDS

cpu_type
Type of CPU

cpu_subtype
Sub-type of CPU

running
True if the CPU is running

slot_num
Slot number of the CPU

is_master
True if this is the master processor

DESCRIPTION

The processor_basic_info structure defines the information available about a processor slot.

RELATED INFORMATION

Functions: processor_info. \ No newline at end of file diff --git a/osfmk/man/processor_control.html b/osfmk/man/processor_control.html new file mode 100755 index 000000000..faa83aabd --- /dev/null +++ b/osfmk/man/processor_control.html @@ -0,0 +1 @@ +

processor_control


Function - Perform caller-specified operation on target processor. (Protected Interface.)

SYNOPSIS

kern_return_t	processor_control
		(processor_t	processor,
		processor_info_t	cmd,
		mach_msg_type_number_t*	count);

PARAMETERS

processor
[in processor send right] The processor to be controlled.
cmd
[pointer to in array of natural-sized units] An array containing the command to be applied to the processor.
count
[in scalar] The size of the cmd array (in natural-sized units).

DESCRIPTION

The processor_control function allows privileged software to control a processor in a multi-processor that so allows it. The interpretation of cmd is machine dependent.

NOTES

These operations are machine dependent. They may do nothing.

RETURN VALUES

KERN_FAILURE
The operation was not performed. A likely reason is that it is not supported on this processor.

RELATED INFORMATION

Functions: processor_start, processor_exit, processor_info, host_processors. \ No newline at end of file diff --git a/osfmk/man/processor_exit.html b/osfmk/man/processor_exit.html new file mode 100755 index 000000000..0e8cd75e7 --- /dev/null +++ b/osfmk/man/processor_exit.html @@ -0,0 +1 @@ +

processor_exit


Function - Exit a processor.

SYNOPSIS

kern_return_t	processor_exit
		(processor_t	processor);

PARAMETERS

processor
[in processor send right] The processor to be controlled.

DESCRIPTION

The processor_exit function allows privileged software to exit a processor in a multi-processor that so allows it. An exited processor is removed from the processor set to which it was assigned and ceases to be active. The interpretation of this operation is machine dependent.

NOTES

This operation is machine dependent. It may do nothing.

CAUTIONS

The ability to restart an exited processor is machine dependent.

RETURN VALUES

KERN_FAILURE
The operation was not performed. A likely reason is that it is not supported on this processor.

RELATED INFORMATION

Functions: processor_control, processor_start, processor_info, host_processors. \ No newline at end of file diff --git a/osfmk/man/processor_get_assignment.html b/osfmk/man/processor_get_assignment.html new file mode 100755 index 000000000..d733ed364 --- /dev/null +++ b/osfmk/man/processor_get_assignment.html @@ -0,0 +1 @@ +

processor_get_assignment


Function - Get current assignment for a processor.

SYNOPSIS

kern_return_t	processor_get_assignment
		(processor_t	processor,
		processor_set_name_t	assigned_set);

PARAMETERS

processor
[in processor send right] The processor whose assignment is desired.
new_set
[out processor-set-name send right] The name port for the processor set to which processor is currently assigned.

DESCRIPTION

The processor_get_assignment function returns the name port for the processor set to which a desired processor is currently assigned.

RETURN VALUES

KERN_FAILURE
Processor is either shut down of off-line.

RELATED INFORMATION

Functions: processor_assign, processor_set_create, processor_info, task_assign, thread_assign. \ No newline at end of file diff --git a/osfmk/man/processor_info.html b/osfmk/man/processor_info.html new file mode 100755 index 000000000..ed7828020 --- /dev/null +++ b/osfmk/man/processor_info.html @@ -0,0 +1 @@ +

processor_info


Function - Return information about a processor.

SYNOPSIS

kern_return_t	processor_info
		(processor_t	processor,
		processor_flavor_t	flavor,
		host_t	host,
		processor_info_t	processor_info,
		mach_msg_type_number_t	processor_info_count);

PARAMETERS

processor
[in processor send right] A processor port for which information is desired.
flavor
[in scalar] The type of information requested.
PROCESSOR_BASIC_INFO
Basic information, slot number, running status, etc. The returned structure is processor_basic_info.
host
[out host-name send right] The host on which the processor resides. This is the host name port.
processor_info
[out structure] Information about the processor.
processor_info_count
[in/out scalar] On input, the maximum size of the buffer; on output, the size returned (in natural-sized units).

DESCRIPTION

The processor_info function returns selected information for a processor, as specified by flavor.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: processor_start, processor_exit, processor_control, host_processors.

Data Structures: processor_basic_info. \ No newline at end of file diff --git a/osfmk/man/processor_set_basic_info.html b/osfmk/man/processor_set_basic_info.html new file mode 100755 index 000000000..a530b9f44 --- /dev/null +++ b/osfmk/man/processor_set_basic_info.html @@ -0,0 +1 @@ +

processor_set_basic_info


Structure - Defines the basic information about a processor set.

SYNOPSIS

struct processor_set_basic_info
{
       int        processor_count;
       int         default_policy;
};

typedef struct processor_set_basic_info* processor_set_basic_info_t;

FIELDS

processor_count
Number of processors in this set.

default_policy
Default policy to assign to threads whose otherwise assigned policy is not enabled.

DESCRIPTION

The processor_set_basic_info structure defines the basic information available about a processor set.

RELATED INFORMATION

Functions: processor_set_info.

Data Structures: processor_set_load_info. \ No newline at end of file diff --git a/osfmk/man/processor_set_create.html b/osfmk/man/processor_set_create.html new file mode 100755 index 000000000..28942b00d --- /dev/null +++ b/osfmk/man/processor_set_create.html @@ -0,0 +1 @@ +

processor_set_create


Function - Create a new processor set object.

SYNOPSIS

kern_return_t	processor_set_create
		(host_t	host_name,
		processor_set_t	new_set,
		processor_set_name_t	new_name);

PARAMETERS

host_name
[in host-name send right] The name (or control) port for the host on which the set is to be created.
new_set
[out processor-set-control send right] Control port used for performing operations on the new set.
new_name
[out processor-set-name send right] Name port used to identify the new set and obtain information about it.

DESCRIPTION

The processor_set_create function creates a new processor set and returns the two ports associated with it. The port returned in new_set is the control port representing the set. It is used to perform operations such as assigning processors, tasks or threads. The port returned in new_name is the name port which identifies the set, and is used to obtain information about the set.

RETURN VALUES

Only generic values apply.

RELATED INFORMATION

Functions: processor_set_destroy, processor_set_info, processor_assign, task_assign, thread_assign. \ No newline at end of file diff --git a/osfmk/man/processor_set_default.html b/osfmk/man/processor_set_default.html new file mode 100755 index 000000000..6dee1b195 --- /dev/null +++ b/osfmk/man/processor_set_default.html @@ -0,0 +1 @@ +

processor_set_default


Function - Return the default processor set.

SYNOPSIS

kern_return_t	processor_set_default
		(host_t	host,
		processor_set_name_t	default_set_name);

PARAMETERS

host
[in host-name send right] The name (or control) port for the host for which the default processor set is desired.
default_set_name
[out processor-set-name send right] The returned name port for the default processor set.

DESCRIPTION

The processor_set_default function returns the name port for the default processor set for the specified host. The default processor set is used by all threads, tasks and processors that are not explicitly assigned to other sets.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: processor_set_info, thread_assign, task_assign. \ No newline at end of file diff --git a/osfmk/man/processor_set_destroy.html b/osfmk/man/processor_set_destroy.html new file mode 100755 index 000000000..4ee623e85 --- /dev/null +++ b/osfmk/man/processor_set_destroy.html @@ -0,0 +1 @@ +

processor_set_destroy


Function - Destroy the target processor set object.

SYNOPSIS

kern_return_t	processor_set_destroy
		(processor_set_t	processor_set);

PARAMETERS

processor_set
[in processor-set-control send right] The control port for the processor set to be destroyed.

DESCRIPTION

The processor_set_destroy function destroys the specified processor set. Any assigned processors, tasks or threads are re-assigned to the default set. The object port (not the name port) for the processor set is required.

RETURN VALUES

KERN_DEFAULT_SET
An attempt was made to destroy the default processor set.

RELATED INFORMATION

Functions: processor_set_create, processor_assign, task_assign, thread_assign. \ No newline at end of file diff --git a/osfmk/man/processor_set_info.html b/osfmk/man/processor_set_info.html new file mode 100755 index 000000000..b3d08803e --- /dev/null +++ b/osfmk/man/processor_set_info.html @@ -0,0 +1 @@ +

processor_set_info


Function - Return processor set state according to caller-specified flavor.

SYNOPSIS

kern_return_t	processor_set_info
		(processor_set_name_t	processor_set_name,
		int	flavor,
		host_t	host,
		processor_set_info_t	processor_set_info,
		mach_msg_type_number_t	processor_set_info_count);

PARAMETERS

processor_set_name
[in processor-set-name send right] A processor set name (or control) port for which information is desired.
flavor
[in scalar] The type of information requested.
PROCESSOR_SET_BASIC_INFO
Basic information concerning the processor set (number of assigned processors and default policy). The returned structure is defined by processor_set_basic_info.
PROCESSOR_SET_TIMESHARE_DEFAULT
The base attributes for the timeshare scheduling policy. The returned structure is policy_timeshare_base.
PROCESSOR_SET_FIFO_DEFAULT
The base attributes for the FIFO scheduling policy. The returned structure is policy_fifo_base.
PROCESSOR_SET_RR_DEFAULT
The base attributes for the round-robin scheduling policy. The returned structure is policy_rr_base.
PROCESSOR_SET_TIMESHARE_LIMITS
Limits on the allowed timeshare policy attributes. The returned structure is defined by policy_timeshare_limit.
PROCESSOR_SET_RR_LIMITS
Limits on the allowed round robin policy attributes. The returned structure is defined by policy_rr_limit.
PROCESSOR_SET_FIFO_LIMITS
Limits on the allowed first-in, first-out policy attributes. The returned structure is defined by policy_fifo_limit.
PROCESSOR_SET_ENABLED_POLICIES
The set of enabled policies. The returned data is a bit-vector.
host
[out host-name send right] The name port for the host on which the processor set resides.
processor_set_info
[out structure] Information about the processor set.
processor_set_info_count
[in/out scalar] On input, the maximum size of the buffer; on output, the size returned (in natural-sized units).

DESCRIPTION

The processor_set_info function returns selected information for a processor set, as specified by flavor.

NOTES

A processor set has a single default scheduling policy in effect for it (as returned by PROCESSOR_SET_BASIC_INFO), so only one of the default scheduling structures has valid information. On the other hand, a processor set maintains limits for all defined scheduling policies, so all of the scheduling limit structures return valid values.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: processor_set_statistics, processor_set_create, processor_set_default, processor_assign, processor_set_policy_control.

Data Structures: processor_set_basic_info, policy_timeshare_info, policy_rr_info, policy_fifo_info. \ No newline at end of file diff --git a/osfmk/man/processor_set_load_info.html b/osfmk/man/processor_set_load_info.html new file mode 100755 index 000000000..feda7f32e --- /dev/null +++ b/osfmk/man/processor_set_load_info.html @@ -0,0 +1 @@ +

processor_set_load_info


Structure - Defines the scheduling statistics for a processor set.

SYNOPSIS

struct processor_set_load_info
{
       int            task_count;
       int          thread_count;
       integer_t    load_average;
       integer_t     mach_factor;
};

typedef struct processor_set_load_info* processor_set_load_info_t;

FIELDS

task_count
Number of tasks currently assigned to this processor set

thread_count
Number of threads currently assigned to this processor set

load_average
Average number of runnable processes divided by number of CPUs

mach_factor
The processing resources available to a new thread\(emthe number of CPUs divided by (1 + the number of threads)

DESCRIPTION

The processor_set_load_info structure defines the scheduling statistics maintained for a processor set.

RELATED INFORMATION

Data Structures: processor_set_basic_info. \ No newline at end of file diff --git a/osfmk/man/processor_set_max_priority.html b/osfmk/man/processor_set_max_priority.html new file mode 100755 index 000000000..804cbc21c --- /dev/null +++ b/osfmk/man/processor_set_max_priority.html @@ -0,0 +1 @@ +

processor_set_max_priority


Function - Sets the maximum scheduling priority for a processor set.

SYNOPSIS

#include< mach/mach_host.h>

kern_return_t	processor_set_max_priority
		(processor_set_t	processor_set,
		int	priority,
		boolean_t	change_threads);

PARAMETERS

processor_set
[in processor-set-control port] The control port for the processor set whose maximum scheduling priority is to be set.
priority
[in scalar] The new priority for the processor set.
change_threads
[in scalar] True if the maximum priority of existing threads assigned to this processor set should also be changed.

DESCRIPTION

The processor_set_max_priority function sets the maximum scheduling priority for processor_set. The maximum priority of a processor set is used only when creating new threads. A new thread's maximum priority is set to that of its assigned processor set. When assigned to a processor set, a thread's maximum priority is reduced, if necessary, to that of its new processor set; its current priority is also reduced, as needed. Changing the maximum priority of a processor set does not affect the priority of the currently assigned threads unless change_threads is TRUE. If this priority change violates the maximum priority of some threads, their maximum priorities will be reduced to match.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: thread_assign. \ No newline at end of file diff --git a/osfmk/man/processor_set_statistics.html b/osfmk/man/processor_set_statistics.html new file mode 100755 index 000000000..5bd65369d --- /dev/null +++ b/osfmk/man/processor_set_statistics.html @@ -0,0 +1 @@ +

processor_set_statistics


Function - Return scheduling statistics for a processor set.

SYNOPSIS

kern_return_t	processor_set_statistics
		(processor_set_t	processor_set_control,
		processor_set_flavor_t	flavor,
		processor_set_info_t	processor_set_info,
		mach_msg_type_number_t	processor_set_info_count);

PARAMETERS

processor_set_control
[in processor-set-control send right] A processor set control port for which information is desired.
flavor
[in scalar] The type of information requested.
PROCESSOR_SET_LOAD_INFO
Load statistics for the processor set. The returned structure is processor_set_load_info.
processor_set_info
[out structure] Information about the processor set.
processor_set_info_count
[in/out scalar] On input, the maximum size of the buffer; on output, the size returned (in natural-sized units).

DESCRIPTION

The processor_set_statistics function returns statistics for a processor set as specified by flavor.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: processor_set_info.

Data Structures: processor_set_load_info. \ No newline at end of file diff --git a/osfmk/man/processor_set_tasks.html b/osfmk/man/processor_set_tasks.html new file mode 100755 index 000000000..7f2827eed --- /dev/null +++ b/osfmk/man/processor_set_tasks.html @@ -0,0 +1 @@ +

processor_set_tasks


Function - Return a list of pointers to all tasks currently assigned to the target processor set.

SYNOPSIS

kern_return_t	processor_set_tasks
		(processor_set_t	processor_set,
		task_port_array_t	task_list,
		mach_msg_type_number_t*	task_count);

PARAMETERS

processor_set
[in processor-set-control send right] A processor set control port for which information is desired.
task_list
[out pointer to dynamic array of task send rights] The returned set of ports naming the tasks currently assigned to processor_set.
task_count
[out scalar] The number of tasks returned in task_list.

DESCRIPTION

The processor_set_tasks function returns send rights to the kernel ports for each task currently assigned to processor_set.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: processor_set_threads, task_assign, thread_assign. \ No newline at end of file diff --git a/osfmk/man/processor_set_threads.html b/osfmk/man/processor_set_threads.html new file mode 100755 index 000000000..7bdfb6626 --- /dev/null +++ b/osfmk/man/processor_set_threads.html @@ -0,0 +1 @@ +

processor_set_threads


Function - Return a list of pointers to all threads currently assigned to the target processor set.

SYNOPSIS

kern_return_t	processor_set_threads
		(processor_set_t	processor_set,
		thread_port_array_t	thread_list,
		mach_msg_type_number_t*	thread_count);

PARAMETERS

processor_set
[in processor-set-control send right] A processor set control port for which information is desired.
thread_list
[out pointer to dynamic array of thread send rights] The returned set of ports naming the threads currently assigned to processor_set.
thread_count
[out scalar] The number of threads returned in thread_list.

DESCRIPTION

The processor_set_threads function returns send rights to the kernel ports for each thread currently assigned to processor_set.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: processor_set_tasks, task_assign, thread_assign. \ No newline at end of file diff --git a/osfmk/man/processor_start.html b/osfmk/man/processor_start.html new file mode 100755 index 000000000..0c9f4b087 --- /dev/null +++ b/osfmk/man/processor_start.html @@ -0,0 +1 @@ +

processor_start


Function - Start a processor.

SYNOPSIS

#include<mach/mach_host.h>

kern_return_t	processor_start
		(processor_t	processor);

PARAMETERS

processor
[in processor send right] The processor to be controlled.

DESCRIPTION

The processor_start function allows privileged software to start a processor in a multi-processor that so allows it. A newly started processor is assigned to the default processor set. The interpretation of this operation is machine dependent.

NOTES

This operation is machine dependent. It may do nothing.

CAUTIONS

The ability to restart an exited processor is machine dependent.

RETURN VALUES

KERN_FAILURE
The operation was not performed. A likely reason is that it is not supported on this processor.

RELATED INFORMATION

Functions: processor_control, processor_exit, processor_info, host_processors. \ No newline at end of file diff --git a/osfmk/man/prof_server.html b/osfmk/man/prof_server.html new file mode 100755 index 000000000..44d09f1e9 --- /dev/null +++ b/osfmk/man/prof_server.html @@ -0,0 +1 @@ +

prof_server


Function - Handle the next kernel-generated PC sample message.

SYNOPSIS

boolean_t	prof_server
		(mach_msg_header_t	request_msg,
		mach_msg_header_t	reply_ms);

PARAMETERS

in_msg
[pointer to in structure] The sample message received from the kernel.

out_msg
[out structure] Not used.

DESCRIPTION

The prof_server function is the MIG generated server handling function to handle messages from the kernel corresponding to program counter (profiling) samples. Such messages are delivered to the task or thread sample port set by task_sample or thread_sample. The prof_server function performs all necessary argument handling for this kernel message and calls the appropriate handling function. These functions must be supplied by the caller.

RETURN VALUES

TRUE
The message was handled and the appropriate function was called.

FALSE
The message did not apply to the sample mechanism and no other action was taken.

RELATED INFORMATION

Functions: receive_samples. \ No newline at end of file diff --git a/osfmk/man/receive_samples.html b/osfmk/man/receive_samples.html new file mode 100755 index 000000000..9268ac683 --- /dev/null +++ b/osfmk/man/receive_samples.html @@ -0,0 +1 @@ +

receive_samples

Server Interface - Handles the occurrence of a PC sampling message

SYNOPSIS

kern_return_t   receive_samples
                (mach_port_t                     sample_port,
                 sample_array_t                      samples,
                 mach_msg_type_number_t         sample_count);

PARAMETERS

sample_port
[in sample (receive) right] The port to which the sample message was sent.
samples
[pointer to in array of vm_address_t] An array of PC sample values.
sample_count
[in scalar] The number of values in samples.

DESCRIPTION

A receive_samples function is called by prof_server as the result of a kernel message indicating that a set of program counter samples has been gathered. The parameter sample_port specifies the port named via a previous call to task_sample or thread_sample.

NOTES

This interface is machine word length specific because of the virtual addresses in the samples parameter.

RETURN VALUE

Irrelevant.

RELATED INFORMATION

Functions: task_sample, thread_sample, prof_server. \ No newline at end of file diff --git a/osfmk/man/semaphore_create.html b/osfmk/man/semaphore_create.html new file mode 100755 index 000000000..2d552c2bd --- /dev/null +++ b/osfmk/man/semaphore_create.html @@ -0,0 +1 @@ +

semaphore_create


Function - Create a new semaphore.

SYNOPSIS

kern_return_t	semaphore_create
		(task_t                   task,
		 semaphore_t        *semaphore,
		 int                    policy,
		 int                     value);

PARAMETERS

task
[in task port] The task receiving the send right of the newly created semaphore.

semaphore
[out send right] The port naming the created semaphore.

policy
[in scalar] The blocked thread wakeup policy for the newly created semaphore. Valid policies are:

SYNC_POLICY_FIFO
a first-in-first-out policy for scheduling thread wakeup.

SYNC_POLICY_FIXED_PRIORITY
a fixed priority policy for scheduling thread wakeup.

value
[in scalar] The initial value of the semaphore count.

DESCRIPTION

The semaphore_create function creates a new semaphore, associates the created semaphore with the specified task, and returns a send right naming the new semaphore. In order to support a robust producer/consumer communication service, Interrupt Service Routines (ISR) must be able to signal semaphores. The semaphore synchronizer service is designed to allow user-level device drivers to perform signal operations, eliminating the need for event counters. Device drivers which utilize semaphores are responsible for creating (via semaphore_create) and exporting (via device_get_status) semaphores for user level access. Device driver semaphore creation is done at device initialization time. Device drivers may support multiple semaphores.

RETURN VALUES

KERN_INVALID_ARGUMENT
The task argument or the policy argument was invalid, or the initial value of the semaphore was invalid.

KERN_RESOURCE_SHORTAGE
The kernel could not allocate the semaphore.

KERN_SUCCESS
The semaphore was successfully created.

RELATED INFORMATION

Functions: semaphore_destroy, semaphore_signal, semaphore_signal_all, semaphore_wait, device_get_status. \ No newline at end of file diff --git a/osfmk/man/semaphore_destroy.html b/osfmk/man/semaphore_destroy.html new file mode 100755 index 000000000..42202ec53 --- /dev/null +++ b/osfmk/man/semaphore_destroy.html @@ -0,0 +1 @@ +

semaphore_destroy


Function - Destroy a semaphore.

SYNOPSIS

kern_return_t   semaphore_destroy
                (task_t                                    task,
                 semaphore_t                          semaphore);

PARAMETERS

task
[in task port] The task associated with the target semaphore.

semaphore
[in send right] The port naming the semaphore to be destroyed.

DESCRIPTION

The semaphore_destroy function destroys a semaphore. All send rights naming the semaphore become dead names. Threads waiting on the semaphore become unblocked with the return from the semaphore_wait call indicating that the semaphore was destroyed. A call to semaphore_destroy succeeds only if the semaphore is associated with the specified task.

RETURN VALUES

KERN_INVALID_ARGUMENT
Either, or both, the task or semaphore arguments were invalid.

KERN_INVALID_RIGHT
The specified task does not own the specified semaphore.

KERN_TERMINATED
The specified semaphore was previously destroyed.

KERN_SUCCESS
The semaphore was destroyed.

RELATED INFORMATION

Functions: semaphore_create, semaphore_signal, semaphore_signal_all, semaphore_wait, device_get_status. \ No newline at end of file diff --git a/osfmk/man/semaphore_signal.html b/osfmk/man/semaphore_signal.html new file mode 100755 index 000000000..c3691eb67 --- /dev/null +++ b/osfmk/man/semaphore_signal.html @@ -0,0 +1 @@ +

semaphore_signal


Function - Increments the semaphore count.

SYNOPSIS

kern_return_t   semaphore_signal
                (semaphore_t                          semaphore);

PARAMETERS

semaphore
[in send right] The port naming the semaphore to be signalled.

DESCRIPTION

The semaphore_signal function increments the semaphore count. If the count goes non-negative (i.e. greater than or equal to 0) and a thread is blocked on the semaphore, then the waiting thread is scheduled to execute. If multiple threads are blocked on the semaphore, the thread scheduled to execute is selected according to the wakeup policy of the semaphore (set when the semaphore was created via semaphore_create). Device driver interrupt service routines may safely execute semaphore_signal operations without causing a deadlock.

RETURN VALUES

KERN_INVALID_ARGUMENT
The specified semaphore is invalid.

KERN_TERMINATED
The specified semaphore has been destroyed.

KERN_SUCCESS
The semaphore has been signalled.

RELATED INFORMATION

Functions: semaphore_create, semaphore_destroy, semaphore_signal_all, semaphore_wait, device_get_status. \ No newline at end of file diff --git a/osfmk/man/semaphore_signal_all.html b/osfmk/man/semaphore_signal_all.html new file mode 100755 index 000000000..1bbf86bb3 --- /dev/null +++ b/osfmk/man/semaphore_signal_all.html @@ -0,0 +1 @@ +

semaphore_signal_all


Function - Wake up all threads blocked on a semaphore.

SYNOPSIS

kern_return_t   semaphore_signal_all
                (semaphore_t                          semaphore);

PARAMETERS

semaphore
[in send right] The port naming the semaphore to be signalled.

DESCRIPTION

The semaphore_signal_all function wakes up all of the threads blocked on the semaphore. The semaphore count is reset to zero.

RETURN VALUES

KERN_INVALID_ARGUMENT
The specified semaphore is invalid.

KERN_TERMINATED
The specified semaphore has been destroyed.

KERN_SUCCESS
The semaphore has been signalled.

RELATED INFORMATION

Functions: semaphore_create, semaphore_destroy, semaphore_signal, \ No newline at end of file diff --git a/osfmk/man/semaphore_wait.html b/osfmk/man/semaphore_wait.html new file mode 100755 index 000000000..04a8df9d8 --- /dev/null +++ b/osfmk/man/semaphore_wait.html @@ -0,0 +1 @@ +

semaphore_wait


Function - Wait on the specified semaphore.

SYNOPSIS

kern_return_t   semaphore_wait
                (semaphore_t                          semaphore);

PARAMETERS

semaphore
[in send right] The port naming the semaphore that the wait operation is being performed upon.

DESCRIPTION

The semaphore_wait function decrements the semaphore count. If the semaphore count is negative after decrementing, the calling thread blocks. Device driver interrupt service routines (ISR) should never execute semaphore_wait, since waiting on a semaphore at the ISR level may, and often will, lead to a deadlock.

RETURN VALUES

KERN_INVALID_ARGUMENT
The specified semaphore is invalid.

KERN_TERMINATED
The specified semaphore has been destroyed.

KERN_ABORTED
The caller was blocked due to a negative count on the semaphore, and was awoken for a reason not related to the semaphore subsystem (e.g. thread_terminate).

KERN_SUCCESS
The semaphore wait operation was successful.

RELATED INFORMATION

Functions: semaphore_create, semaphore_destroy, semaphore_signal, semaphore_signal_all, device_get_status. \ No newline at end of file diff --git a/osfmk/man/seqnos_notify_server.html b/osfmk/man/seqnos_notify_server.html new file mode 100755 index 000000000..fadc27a3d --- /dev/null +++ b/osfmk/man/seqnos_notify_server.html @@ -0,0 +1 @@ +

seqnos_notify_server


Function - Handle the next kernel-generated IPC notification.

SYNOPSIS

boolean_t	seqnos_notify_server
		(mach_msg_header_t	request_msg,
		mach_msg_header_t	reply_ms);

PARAMETERS

in_msg
[pointer to in structure] The notification message received from the kernel.

out_msg
[out structure] Not used.

DESCRIPTION

The seqnos_notify_server function is the MIG generated server handling function to handle messages from the kernel corresponding to IPC notifications. Such messages are delivered to the notification port named in a mach_msg or mach_port_request_notification call. The seqnos_notify_server function performs all necessary argument handling for this kernel message and calls the appropriate handling function. These functions must be supplied by the caller.

NOTES

seqnos_notify_server differs from notify_server in that it supplies message sequence numbers to the server interfaces.

RETURN VALUES

TRUE
The message was handled and the appropriate function was called.

FALSE
The message did not apply to the notification mechanism and no other action was taken.

RELATED INFORMATION

Functions: notify_server, do_seqnos_mach_notify_dead_name, do_seqnos_mach_notify_no_senders, do_seqnos_mach_notify_port_deleted, do_seqnos_mach_notify_send_once. \ No newline at end of file diff --git a/osfmk/man/task_assign.html b/osfmk/man/task_assign.html new file mode 100755 index 000000000..f46671800 --- /dev/null +++ b/osfmk/man/task_assign.html @@ -0,0 +1 @@ +

task_assign


Function - Assign a task to a processor set.

SYNOPSIS

kern_return_t   task_assign
                (task_t                                    task,
                 processor_set_t                  processor_set,
                 boolean_t                       assign_threads);

PARAMETERS

task
[in task send right] The port for the task to be assigned.
processor_set
[in processor-set-control send right] The control port for the processor set into which the task is to be assigned.
assign_threads
[in scalar] True if this assignment should apply as well to the threads within the task.

DESCRIPTION

The task_assign function assigns task to the set processor_set. After the assignment is completed, newly created threads within this task will be assigned to this processor set. Any previous assignment of the task is nullified.

If assign_threads is TRUE, existing threads within the task will also be assigned to the processor set.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: task_assign_default, task_get_assignment, processor_set_create, processor_set_info, thread_assign. \ No newline at end of file diff --git a/osfmk/man/task_assign_default.html b/osfmk/man/task_assign_default.html new file mode 100755 index 000000000..d5b66da69 --- /dev/null +++ b/osfmk/man/task_assign_default.html @@ -0,0 +1 @@ +

task_assign_default


Function - Assign a task to the default processor set.

SYNOPSIS

kern_return_t   task_assign_default
                (task_t                                    task,
                 boolean_t                       assign_threads);

PARAMETERS

task
[in task send right] The port for the task to be assigned.
assign_threads
[in scalar] True if this assignment should apply as well to the threads within the task.

DESCRIPTION

The task_assign_default function assigns task to the default processor set. After the assignment is completed, newly created threads within this task will be assigned to this processor set. Any previous assignment of the task is nullified.

If assign_threads is TRUE, existing threads within the task will also be assigned to the processor set.

NOTES

This variant of task_assign exists because the control port for the default processor set is privileged, and therefore not available to most tasks.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: task_assign, task_get_assignment, processor_set_create, processor_set_info, thread_assign. \ No newline at end of file diff --git a/osfmk/man/task_basic_info.html b/osfmk/man/task_basic_info.html new file mode 100755 index 000000000..a65b55036 --- /dev/null +++ b/osfmk/man/task_basic_info.html @@ -0,0 +1 @@ +

task_basic_info


Structure - Defines basic information for a task.

SYNOPSIS

struct task_basic_info
{
       integer_t      suspend_count;
       vm_size_t       virtual_size;
       vm_size_t      resident_size;
       time_value_t       user_time;
       time_value_t     system_time;
       policy_t              policy;
};

typedef struct task_basic_info* task_basic_info_t;

FIELDS

suspend_count
The current suspend count for the task.

virtual_size
The number of virtual pages for the task.

resident_size
The number of resident pages for the task

user_time
The total user run time for terminated threads within the task.

system_time
The total system run time for terminated threads within the task.

policy
Default scheduling policy to apply to new threads.

DESCRIPTION

The task_basic_info structure defines the basic information array for tasks. The task_info function returns this array for a specified task.

NOTES

This structure is machine word length sensitive due to the presence of the virtual address sizes.

RELATED INFORMATION

Functions: task_info.

Data Structures: task_thread_times_info, policy_fifo_info, policy_rr_info, policy_timeshare_info. \ No newline at end of file diff --git a/osfmk/man/task_create.html b/osfmk/man/task_create.html new file mode 100755 index 000000000..c2e5e7c78 --- /dev/null +++ b/osfmk/man/task_create.html @@ -0,0 +1 @@ +

task_create


Function - Create a new task.

SYNOPSIS

kern_return_t   task_create
                (task_t                             parent_task,
                 ledger_port_array_t                    ledgers,
                 int                               ledger_count,
                 boolean_t                       inherit_memory,
                 task_t                              child_task);

PARAMETERS

parent_task
[in task send right] The port for the task from which to draw the child task's port rights and address space.

ledgers
[pointer to in array of ledger send rights] Resource ledgers (on the destination host) from which the task will draw its resources. The first element of this array is the wired kernel ledger, the second the paged space ledger. If the number of ledgers supplied does not match the required number or one or more is null, the parent task's ledger is used.

ledger_count
[in scalar] The number of ledger ports in the ledgers array.

inherit_memory
[in scalar] Address space inheritance indicator. If true, the child task inherits the (inheritable) address space of the parent task. If false, the kernel assigns the child task an empty address space.

child_task
[out task send right] The kernel-assigned port for the new task.

DESCRIPTION

The task_create function creates a new task from parent_task and returns the name of the new task in child_task. The child task acquires shared or copied parts of the parent's address space (see vm_inherit). The child task initially contains no threads. The child task inherits the parent's security ID.

The child task receives the following "special" ports, which are created or copied for it at task creation:

[task-self send right]
The port by which the kernel knows the new child task and allows it to be manipulated. The child task holds a send right for this port. The port name is also returned to the calling task.

[bootstrap send right]
The port to which the child task can send a message requesting return of any system service ports that it needs (for example, a port to the Network Name Server or the Environment Manager). The child task inherits a send right for this port from the parent task. The task can use task_set_special_port to change this port.

[host-self send right]
The port by which the child task requests information about its host. The child task inherits a send right for this port from the parent task.

[ledger send rights]
The ports naming the ledgers from which the task draws its resources.

The child task also inherits the following ports:

[sample send right]
The port to which PC sampling messages are to be sent.

[exception send rights]
Ports to which exception messages are sent.

[registered send rights]
Ports to system services.

NOTES

The ledgers functionality mentioned above is not currently implemented.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: task_create_security_token, task_resume, task_set_special_port, task_suspend, task_terminate, task_threads, thread_create, thread_resume, vm_inherit, task_sample, task_set_exception_ports, mach_ports_register, norma_task_create, task_set_security_token. \ No newline at end of file diff --git a/osfmk/man/task_create_security_token.html b/osfmk/man/task_create_security_token.html new file mode 100755 index 000000000..00d489a88 --- /dev/null +++ b/osfmk/man/task_create_security_token.html @@ -0,0 +1 @@ +

task_create_security_token


Function - Create a new task with an explicit security token.

SYNOPSIS

kern_return_t   task_create_security_token
                (task_t                                    task,
                 security_port_t                  host_security,
                 security_token_t                security_token,
                 ledger_port_array_t                    ledgers,
                 boolean_t                       inherit_memory,
                 task_t                                  task_t);

PARAMETERS

parent_task
[in task send right] The port for the task from which to draw the child task's port rights and address space.

host_security
[in security send right] The host's security port.

security_token
[in scalar] The task's security token.

ledgers
[pointer to in array of ledger send rights] The set of ledgers from which the task will draw its resources.

inherit_memory
[in scalar] Address space inheritance indicator. If true, the child task in- herits the address space of the parent task. If false, the kernel assigns the child task an empty address space.

child_task
[out task send right] The kernel-assigned port name for the new task.

DESCRIPTION

The task_create_security_token function creates a new task from parent_task with an explicit security token, returning the name of the new task in the parameter specified by child_task. Other than the security token, the child task is as if created by task_create.

NOTES

The host security port is a privileged port given to the system bootstrap task for the use of this call.

RETURN VALUES

KERN_INVALID_SECURITY
The value of host_security does not specify the security port for the host on which task lies.

RELATED INFORMATION

Functions: task_create, task_set_security_token, mach_msg. \ No newline at end of file diff --git a/osfmk/man/task_get_assignment.html b/osfmk/man/task_get_assignment.html new file mode 100755 index 000000000..4cdaecff4 --- /dev/null +++ b/osfmk/man/task_get_assignment.html @@ -0,0 +1 @@ +

task_get_assignment


Function - Return the processor set to which a task is assigned.

SYNOPSIS

kern_return_t   task_get_assignment
                (task_t                                    task,
                 processor_set_name_t             processor_set);

PARAMETERS

task
[in task send right] The port for the task whose assignment is desired.
processor_set
[out processor-set-name send right] The name port for the processor set into which the task is assigned.

DESCRIPTION

The task_get_assignment function returns the name port to the processor set to which task is currently assigned. This port can only be used to obtain information about the processor set.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: task_assign, task_assign_default, processor_set_create, processor_set_info, thread_assign. \ No newline at end of file diff --git a/osfmk/man/task_get_emulation_vector.html b/osfmk/man/task_get_emulation_vector.html new file mode 100755 index 000000000..46281cdb3 --- /dev/null +++ b/osfmk/man/task_get_emulation_vector.html @@ -0,0 +1 @@ +

task_get_emulation_vector


Function - Return an array identifying the target task's user-level system call handlers.

SYNOPSIS

kern_return_t   task_get_emulation_vector
                (task_t                                    task,
                 int                               vector_start,
                 emulation_vector_t            emulation_vector,
                 mach_msg_type_number_t* emulation_vector_count);

PARAMETERS

task
[in task send right] The port for the task for which the system call handler addresses are desired.

vector_start
[out scalar] The syscall number corresponding to the first element of emulation_vector.

emulation_vector
[out pointer to dynamic array of vm_address_t] Pointer to the returned array of routine entrypoints for the system calls starting with syscall number vector_start.

emulation_vector_count
[out scalar] The number of entries filled by the kernel.

DESCRIPTION

The task_get_emulation_vector function returns the user-level syscall handler entrypoint addresses.

NOTES

This interface is machine word length specific because of the virtual addresses in the emulation_vector parameter.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: task_set_emulation_vector. \ No newline at end of file diff --git a/osfmk/man/task_get_exception_ports.html b/osfmk/man/task_get_exception_ports.html new file mode 100755 index 000000000..31da03ec0 --- /dev/null +++ b/osfmk/man/task_get_exception_ports.html @@ -0,0 +1 @@ +

task_get_exception_ports


Function - Return send rights to the target task's exception ports.

SYNOPSIS

kern_return_t   task_get_exception_ports
                (task_t                                    task,
                 exception_mask_t               exception_types,
                 exception_mask_array_t     old_exception_masks,
                 old_exception_masks        old_exception_count,
                 exception_port_array_t     old_exception_ports,
                 exception_behavior_array_t       old_behaviors,
                 exception_flavor_array_t           old_flavors);

PARAMETERS

task
[in task send right] The task for which to return the exception ports.

exception_types
[in scalar] A flag word indicating the types of exceptions for which the exception ports are desired:

EXC_MASK_BAD_ACCESS
Could not access memory.

EXC_MASK_BAD_INSTRUCTION
Instruction failed. Illegal or undefined instruction or operand.

EXC_MASK_ARITHMETIC
Arithmetic exception

EXC_MASK_EMULATION
Emulation instruction. Emulation support instruction encountered.

EXC_MASK_SOFTWARE
Software generated exception.

EXC_MASK_BREAKPOINT
Trace, breakpoint, etc.

EXC_MASK_SYSCALL
System call requested.

EXC_MASK_MACH_SYSCALL
System call with a number in the Mach call range requested.

EXC_MASK_RPC_ALERT
Exceptional condition encountered during execution of RPC.

old_exception_masks
[out array of exception_mask_t] An array, each element being a mask specifying for which exception types the corresponding element of the other arrays apply.

old_exception_count
[pointer to in/out scalar] On input, the maximum size of the array buffers; on output, the number of returned sets returned.

old_exception_ports
[out array of exception send rights] The returned exception ports.

old_behaviors
[out array of exception_behavior_t] The type of exception message to be sent. Defined types are:

EXCEPTION_DEFAULT
Send a catch_exception_raise message including the thread identity.

EXCEPTION_STATE
Send a catch_exception_raise_state message including the thread state.

EXCEPTION_STATE_IDENTITY
Send a catch_exception_raise_state_identity message including the thread identity and state.

old_flavors
[out array of thread_state_flavor_t] The type of state to be sent with the exception message. These types are defined in <mach/thread_states.h>.

DESCRIPTION

The task_get_exception_ports function returns send rights for a specified set of exception ports belonging to task. A task exception port is used when a thread specific exception port returns a non-success reply. The call returns a set of quadruples for each unique set of in effect for the task where the exception type mask indicates for which exception types the other values apply.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: mach_task_self, thread_get_exception_ports, task_set_exception_ports, task_swap_exception_ports, thread_create, thread_set_exception_ports, thread_swap_exception_ports, catch_exception_raise. \ No newline at end of file diff --git a/osfmk/man/task_get_special_port.html b/osfmk/man/task_get_special_port.html new file mode 100755 index 000000000..589e644e8 --- /dev/null +++ b/osfmk/man/task_get_special_port.html @@ -0,0 +1 @@ +

task_get_special_port


Function - Return a send write to the indicated special port.

SYNOPSIS

kern_return_t   task_get_special_port
                (task_t                                    task,
                 int                                 which_port,
                 task                              special_port);


Macro Forms:


kern_return_t   task_get_bootstrap_port
                (task_t                                    task,
                 task                              special_port);


kern_return_t   task_get_kernel_port
                (task_t                                    task,
                 task                              special_port);


kern_return_t   task_get_host_name_port
                (task_t                                    task,
                 task                              special_port);

PARAMETERS

task
[in task send right] The port for the task for which to return the port's send right.

which_port
[in scalar] The special port for which the send right is requested. Valid values are:

TASK_KERNEL_PORT
[task-self send right] The port used to control this task. Used to send messages that affect the task. This is the port returned by mach_task_self.

TASK_BOOTSTRAP_PORT
[bootstrap send right] The task's bootstrap port. Used to send messages requesting return of other system service ports.

TASK_HOST_NAME_PORT
[host-self send right] The port used to request information of the containing host. This is the port returned by mach_host_self.

TASK_WIRED_LEDGER_PORT
[ledger send right] The port naming the source from which this task draws its wired kernel memory.

TASK_PAGED_LEDGER_PORT
[ledger send right] The port naming the source from which this task draws its default memory managed memory.

special_port
[out task-special send right] The returned value for the port.

DESCRIPTION

The task_get_special_port function returns a send right for a special port belonging to task.

If one task has a send right for the kernel port of another task, it can use the port to perform kernel operations for the other task. Send rights for a kernel port normally are held only by the task to which the port belongs, or by the task's parent task. Using the mach_msg function, however, any task can pass a send right for its kernel port to another task.

NOTES

The current implementation does not support the TASK_HOST_NAME_PORT features associated with this interface.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: mach_task_self, task_create, task_set_special_port, thread_get_special_port, thread_set_special_port, mach_host_self. \ No newline at end of file diff --git a/osfmk/man/task_info.html b/osfmk/man/task_info.html new file mode 100755 index 000000000..dbf418fed --- /dev/null +++ b/osfmk/man/task_info.html @@ -0,0 +1 @@ +

task_info


Function - Return per-task information according to specified flavor.

SYNOPSIS

kern_return_t   task_info
                (task_t                                    task,
                 task_flavor_t                           flavor,
                 task_info_t                          task_info,
                 mach_msg_type_number_t         task_info_count);

PARAMETERS

task
[in task send right] The port for the task for which the information is to be returned.

flavor
[in scalar] The type of information to be returned. Valid values are:

TASK_BASIC_INFO
Returns basic information about the task, such as the task's suspend count and number of resident pages. The structure returned is task_basic_info.

TASK_THREAD_TIMES_INFO
Returns system and user space run-times for live threads. The structure returned is task_thread_times_info.

TASK_SCHED_FIFO_INFO
Returns default FIFO scheduling policy attributes to be assigned to new threads. The structure returned is policy_fifo_base.

TASK_SCHED_RR_INFO
Returns default round-robin scheduling policy attributes to be assigned to new threads. The structure returned is policy_rr_base.

TASK_SCHED_TIMESHARE_INFO
Returns default timeshare scheduling policy attributes to be assigned to new threads. The structure returned is policy_timeshare_base.

TASK_SECURITY_TOKEN
Returns the security token for the task. The value returned is of type security_token_t.

TASK_USER_DATA
Returns user-specified information previously established via the task_set_info interface. The structure returned is task_user_data.

task_info
[out structure] Information about the specified task.

task_info_count
[in/out scalar] On input, the maximum size of the buffer; on output, the size returned (in natural-sized units).

DESCRIPTION

The task_info function returns an information structure of type flavor.

NOTES

At any given time, a task has one default scheduling policy assigned to it (as returned by TASK_BASIC_INFO). As such, only one of the scheduling flavors will return valid information.

RETURN VALUES

KERN_INVALID_POLICY
A request was made for the default scheduling policy attributes for the task but the requested policy is not the task's default policy.

RELATED INFORMATION

Functions: task_get_special_port, task_set_special_port, task_set_info, task_threads, thread_info, thread_get_state, thread_set_state.

Data Structures: task_basic_info, policy_timeshare_info, policy_fifo_info, policy_rr_info, task_thread_times_info. \ No newline at end of file diff --git a/osfmk/man/task_policy.html b/osfmk/man/task_policy.html new file mode 100755 index 000000000..1e3535b03 --- /dev/null +++ b/osfmk/man/task_policy.html @@ -0,0 +1 @@ +

task_policy


Function - Set target task's default scheduling policy state.

SYNOPSIS

kern_return_t   task_policy
                (task_t                                    task,
                 policy_t                                policy,
                 policy_base_t                             base,
                 base                                base_count,
                 boolean_t                            set_limit,
                 boolean_t                       change_threads);

PARAMETERS

task
[in task send right] The port for the task whose scheduling attributes are to be set.
policy
[in scalar] Default policy. The values currently defined are POLICY_TIMESHARE, POLICY_RR (round robin) and POLICY_FIFO (firstin, first-out).
base
[pointer to in structure] Base scheduling policy data, policy_fifo_base, policy_rr_base or policy_timeshare_base.
base_count
[in scalar] The size of the buffer (in natural-sized units).
set_limit
[in scalar] True if the scheduling limits for the task should be restricted to allow no more service than specified by base.
change_threads
[in scalar] True if the attributes (and limits, if set_limit is true) of existing threads within the task should also be changed.

DESCRIPTION

The task_policy function sets the default scheduling attributes for task. These attributes are used when creating new threads. Changing the default attributes for a task does not affect the attributes of the contained threads unless change_threads is TRUE. At no time will a thread ever have scheduling attributes that exceed the thread's limits.

RETURN VALUES

KERN_INVALID_POLICY
The processor set does not currently enable policy.
KERN_POLICY_LIMIT
The specified scheduling attributes exceeds the thread's limits.

RELATED INFORMATION

Functions: thread_policy, thread_set_policy, task_set_policy, processor_set_policy_control.

Data Structures: policy_fifo_info, policy_rr_info, policy_timeshare_info. \ No newline at end of file diff --git a/osfmk/man/task_resume.html b/osfmk/man/task_resume.html new file mode 100755 index 000000000..78fcdf022 --- /dev/null +++ b/osfmk/man/task_resume.html @@ -0,0 +1 @@ +

task_resume


Function - Decrement the target task's suspend count.

SYNOPSIS

kern_return_t   task_resume
                (task_t         task);

PARAMETERS

task
[in task send right] The port to the task to be resumed.

DESCRIPTION

The task_resume function decrements the suspend count for task. If the task's suspend count goes to zero, the function resumes any suspended threads within the task. To resume a given thread, the thread's own suspend count must also be zero.

NOTES

An attempt to lower the suspend count below zero is ignored.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: task_create, task_info, task_suspend, task_terminate, thread_info, thread_resume, thread_suspend. \ No newline at end of file diff --git a/osfmk/man/task_sample.html b/osfmk/man/task_sample.html new file mode 100755 index 000000000..ab5e9dc24 --- /dev/null +++ b/osfmk/man/task_sample.html @@ -0,0 +1 @@ +

task_sample


Function - Sample the target task's thread program counters periodically.

SYNOPSIS

kern_return_t   task_sample
                (task_t                             sample_task,
                 mach_port_make_send_t               reply_port);

PARAMETERS

sample_task
[in task send right] Port for the task whose threads' PC are to be sampled.

reply_port
[in sample receive (to be converted to send) right] Port to which PC sample buffers are sent. A value of MACH_PORT_NULL stops PC sampling for the task.

DESCRIPTION

The task_sample function causes the program counter (PC) of the specified sample_task (actually, all of the threads within sample_task) to be sampled periodically (whenever one of the threads happens to be running at the time of the kernel's "hardclock" interrupt). The set of PC sample values obtained are saved in buffers which are sent to the specified reply_port in receive_samples messages.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: thread_sample, receive_samples. \ No newline at end of file diff --git a/osfmk/man/task_set_emulation.html b/osfmk/man/task_set_emulation.html new file mode 100755 index 000000000..a9b8e9fe6 --- /dev/null +++ b/osfmk/man/task_set_emulation.html @@ -0,0 +1 @@ +

task_set_emulation


Function - Establish a user-level handler for a system call.

SYNOPSIS

kern_return_t   task_set_emulation
                (task_t                                    task,
                 vm_address_t                  routine_entry_pt,
                 int                             syscall_number);

PARAMETERS

task
[in task port] The port for the task for which to establish the system call handler.

routine_entry_pt
[in scalar] The address within the task of the handler for this particular system call.

syscall_number
[in scalar] The number of the system call to be handled by this handler.

DESCRIPTION

The task_set_emulation function establishes a handler within the task for a particular system call. When a thread executes a system call with this particular number, the system call will be redirected to the specified routine within the task's address space. This is expected to be an address within the transparent emulation library. These emulation handler addresses are inherited by child processes.

NOTES

This interface is machine word length specific because of the virtual address parameter.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: task_set_emulation_vector, task_get_emulation_vector. \ No newline at end of file diff --git a/osfmk/man/task_set_emulation_vector.html b/osfmk/man/task_set_emulation_vector.html new file mode 100755 index 000000000..f496042d7 --- /dev/null +++ b/osfmk/man/task_set_emulation_vector.html @@ -0,0 +1 @@ +

task_set_emulation_vector


Function - Establish the target task's user-level system call handlers.

SYNOPSIS

kern_return_t   task_set_emulation_vector
                (task_t                                    task,
                 int                               vector_start,
                 emulation_vector_t            emulation_vector,
                 mach_msg_type_number_t  emulation_vector_count);

PARAMETERS

task
[in task send right] The port for the task for which to establish the system call handler.

vector_start
[in scalar] The syscall number corresponding to the first element of emulation_vector.

emulation_vector
[pointer to in array of vm_address_t] An array of routine entrypoints for the system calls starting with syscall number vector_start.

emulation_vector_count
[in scalar] The number of elements in emulation_vector.

DESCRIPTION

The task_set_emulation_vector function establishes a handler within the task for a set of system calls. When a thread executes a system call with one of these numbers, the system call will be redirected to the corresponding routine within the task's address space.

These emulation handler addresses are inherited by child processes.

NOTES

This interface is machine word length specific because of the virtual addresses in the emulation_vector parameter.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: task_get_emulation_vector. \ No newline at end of file diff --git a/osfmk/man/task_set_exception_ports.html b/osfmk/man/task_set_exception_ports.html new file mode 100755 index 000000000..a8f79fbd7 --- /dev/null +++ b/osfmk/man/task_set_exception_ports.html @@ -0,0 +1 @@ +

task_set_exception_ports


Function - Set target task's exception ports.

SYNOPSIS

kern_return_t   task_set_exception_ports
                (task_t                                    task,
                 exception_mask_t               exception_types,
                 mach_port_t                     exception_port,
                 exception_behavior_t                  behavior,
                 thread_state_flavor_t                   flavor);

PARAMETERS

task
[in task send right] The task for which to set the ports.

exception_types
[in scalar] A flag word indicating the types of exceptions for which the exception port applies:

EXC_MASK_BAD_ACCESS
Could not access memory.

EXC_MASK_BAD_INSTRUCTION
Instruction failed. Illegal or undefined instruction or operand.

EXC_MASK_ARITHMETIC
Arithmetic exception

EXC_MASK_EMULATION
Emulation instruction. Emulation support instruction encountered.

EXC_MASK_SOFTWARE
Software generated exception.

EXC_MASK_BREAKPOINT
Trace, breakpoint, etc.

EXC_MASK_SYSCALL
System call requested.

EXC_MASK_MACH_SYSCALL
System call with a number in the Mach call range requested.

EXC_MASK_RPC_ALERT
Exceptional condition encountered during execution of RPC.

exception_port
[in exception send right] The exception port for all selected exception types.

behavior
[in scalar] The type of exception message to be sent. Defined types are:

EXCEPTION_DEFAULT
Send a catch_exception_raise message including the thread identity.

EXCEPTION_STATE
Send a catch_exception_raise_state message including the thread state.

EXCEPTION_STATE_PROTECTED
Send a catch_exception_raise_state message including the thread state. Mark the exception port (and associated exceptions) as protected.

EXCEPTION_STATE_IDENTITY
Send a catch_exception_raise_state_identity message including the thread identity and state.

EXCEPTION_STATE_IDENTITY_PROTECTED
Send a catch_exception_raise_state_identity message including the thread identity and state. Mark the exception port (and associated exceptions) as protected.

flavor
[in scalar] The type of state to be sent with the exception message. These types are defined in <mach/thread_states.h>.

DESCRIPTION

The task_set_exception_ports function sets a specified set of exception ports belonging to task. A task exception port is used when a thread specific exception port returns a non-success reply.

NOTES

If the value of the EXC_MACH_SYSCALL exception class exception port is the host name port, Mach kernel traps are executed by the kernel as expected; any other value causes the attempted execution of these system call numbers to be considered an exception.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: mach_task_self, task_get_exception_ports, task_swap_exception_ports, thread_set_exception_ports, thread_create, thread_get_exception_ports, thread_swap_exception_ports, catch_exception_raise, thread_abort. \ No newline at end of file diff --git a/osfmk/man/task_set_info.html b/osfmk/man/task_set_info.html new file mode 100755 index 000000000..935cc2c66 --- /dev/null +++ b/osfmk/man/task_set_info.html @@ -0,0 +1 @@ +

task_set_info


Function - Set task-specific information state.

SYNOPSIS

#include<task_info.h>

kern_return_t   task_set_info
                (task_t                             target_task,
                 task_flavor_t                           flavor,
                 task_info_t                          task_info);

PARAMETERS

target_task
The task whose information is to be set.

flavor
Specifies the type of information to be set. Currently the interface supports the setting of a single flavor: TASK_USER_DATA.

task_info
Specifies the information to be set.

DESCRIPTION

The task_set_info interface provides the caller with the means to set the target task's user_data field. This field may be used to specify arbitrarily task-specific data.

NOTES

Currently, this interface is used exclusively to provide freshly colocated user tasks with the short-circuited RPC glue vector.

RETURN VALUES

Only generic values apply.

RELATED INFORMATION

\ No newline at end of file diff --git a/osfmk/man/task_set_policy.html b/osfmk/man/task_set_policy.html new file mode 100755 index 000000000..8b4607689 --- /dev/null +++ b/osfmk/man/task_set_policy.html @@ -0,0 +1 @@ +

task_set_policy


Function - Set target task's default scheduling policy state. (Protected Interface.)

SYNOPSIS

kern_return_t   task_set_policy
                (task_t                                    task,
                 processor_set_t                  processor_set,
                 policy_t                                policy,
                 policy_base_t                             base,
                 mach_msg_type_number_t              base_count,
                 policy_limit_t                           limit,
                 mach_msg_type_number_t             limit_count,
                 boolean_t                       change_threads);

PARAMETERS

task
[in task send right] The task whose scheduling policy is to be set.
processor_set
[in processor-set-control send right] The control port for the processor set to which the task is currently assigned.
policy
[in scalar] Policy to be set. The values currently defined are POLICY_TIMESHARE, POLICY_RR (round robin) and POLICY_FIFO (firstin, first-out).
base
[pointer to in structure] Base policy specific data, policy_fifo_base, policy_rr_base or policy_timeshare_base.
base_count
[in scalar] The size of the buffer (in natural-sized units).
limit
[pointer to in structure] Policy specific limits, policy_fifo_limit, policy_rr_limit or policy_timeshare_limit.
limit_count
[in scalar] The size of the buffer (in natural-sized units).
change_threads
[in scalar] True if the scheduling attributes for all contained threads should be changed as well.

DESCRIPTION

The task_set_policy function sets the scheduling attributes, both base and limit, for task. policy may be any policy implemented by the processor set whether or not it is enabled.

RETURN VALUES

KERN_INVALID_PROCESSOR_SET
processor_set is not the task's processor set control port.

RELATED INFORMATION

Functions: processor_set_policy_control, thread_policy, thread_set_policy, task_policy.

Data Structures: policy_fifo_info, policy_rr_info, policy_timeshare_info. \ No newline at end of file diff --git a/osfmk/man/task_set_port_space.html b/osfmk/man/task_set_port_space.html new file mode 100755 index 000000000..b1408ccfe --- /dev/null +++ b/osfmk/man/task_set_port_space.html @@ -0,0 +1 @@ +

task_set_port_space


Function - Set the size of the target task's port name space table.

SYNOPSIS

kern_return_t   task_set_port_space
                (task_t                                    task,
                 int                              table_entries);

PARAMETERS

task
[in send right] The port referencing the task whose port name space is to be set.

table_entries
[in scalar] The number of entries in the port name space table.

DESCRIPTION

The task_set_port_space function preallocates the specified number of entries in the specified task's IPC name space.

RETURN VALUES

KERN_NO_SPACE
The requested table size exceeds the maximum allowable table size.

RELATED INFORMATION

Functions: mach_port_allocate. \ No newline at end of file diff --git a/osfmk/man/task_set_security_token.html b/osfmk/man/task_set_security_token.html new file mode 100755 index 000000000..1c9ace457 --- /dev/null +++ b/osfmk/man/task_set_security_token.html @@ -0,0 +1 @@ +

task_set_security_token


Function - Change the target task's security token.

SYNOPSIS

kern_return_t   task_set_security_token
                (task_t                                    task,
                 security_port_t                  host_security,
                 security_token_t                security_token);

PARAMETERS

task
[in task send right] The port for the task for which the token is to be set.

host_security
[in security send right] The host's security port.

security_token
[in scalar] The new security token.

DESCRIPTION

The task_set_security_token function changes the specified task's security token; the new token will be included in all subsequent messages sent from the task. The initial value of a task's security token is that of its parent.

NOTES

The host security port is a privileged port given to the system bootstrap task for the use of this call.

RETURN VALUES

KERN_INVALID_SECURITY
The value of host_security does not specify the security port for the host on which task lies.

RELATED INFORMATION

Functions: task_create, task_info, mach_msg. \ No newline at end of file diff --git a/osfmk/man/task_set_special_port.html b/osfmk/man/task_set_special_port.html new file mode 100755 index 000000000..7fe7bf6a7 --- /dev/null +++ b/osfmk/man/task_set_special_port.html @@ -0,0 +1 @@ +

task_set_special_port


Function - Set the indicated special port.

SYNOPSIS

kern_return_t   task_set_special_port
                (task_t                                    task,
                 int                                 which_port,
                 mach_port_t                       special_port);


Macro forms:


kern_return_t   task_set_bootstrap_port
                (task_t                                    task,
                 int                                 which_port,
                 mach_port_t                       special_port);


kern_return_t   task_set_kernel_port
                (task_t                                    task,
                 int                                 which_port,
                 mach_port_t                       special_port);


kern_return_t   task_set_host_name_port
                (task_t                                    task,
                 mach_port_t                       special_port);

PARAMETERS

task
[in task send right] The port for the task for which to set the port.

which_port
[in scalar] The special port to be set. Valid values are:

TASK_BOOTSTRAP_PORT
[bootstrap send right] The task's bootstrap port. Used to send messages requesting return of other system service ports.

TASK_KERNEL_PORT
[task-self send right] The task's kernel port. Used by the kernel to receive messages to manipulate the task. This is the port returned by mach_task_self. Setting this special port does not change the identity of the kernel port that names the task; this simply changes the value returned as the kernel special port.

TASK_HOST_NAME_PORT
[host-self send right] The task's host self port. Used by the task to request information about its containing host. This is the port returned by mach_host_self. Setting this special port does not change the identity of the kernel port that names the host; this simply changes the value returned as the host special port.

TASK_WIRED_LEDGER_PORT
[ledger send right] The resource ledger from which the task draws its wired kernel memory. Setting this special port does not change the ledger from which the task draws its resources; this simply changes the value returned as the ledger special port.

TASK_PAGED_LEDGER_PORT
[ledger send right] The resource ledger from which the task draws its default memory managed memory. Setting this special port does not change the ledger from which the task draws its resources; this simply changes the value returned as the ledger special port.

special_port
[in task-special send right] The value for the port.

DESCRIPTION

The task_set_special_port function sets a special port belonging to task.

NOTES

The current implementation does not support the TASK_HOST_NAME_PORT features associated with this interface.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: task_create, task_get_special_port, mach_task_self, thread_get_special_port, thread_set_special_port, mach_host_self. \ No newline at end of file diff --git a/osfmk/man/task_suspend.html b/osfmk/man/task_suspend.html new file mode 100755 index 000000000..9e6979b98 --- /dev/null +++ b/osfmk/man/task_suspend.html @@ -0,0 +1 @@ +

task_suspend


Function - Suspend the target task.

SYNOPSIS

kern_return_t   task_suspend
                (task_t          task);

PARAMETERS

task
[in task send right] The port for the task to be suspended.

DESCRIPTION

The task_suspend function increments the suspend count for task and stops all threads within the task. As long as the suspend count is positive, no newly-created threads can execute. The function does not return until all of the task's threads have been suspended.

NOTES

To resume a suspended task and its threads, use task_resume. If the suspend count is greater than one, task_resume must be repeated that number of times.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: task_create, task_info, task_resume, task_terminate, thread_suspend. \ No newline at end of file diff --git a/osfmk/man/task_swap_exception_ports.html b/osfmk/man/task_swap_exception_ports.html new file mode 100755 index 000000000..481cd7790 --- /dev/null +++ b/osfmk/man/task_swap_exception_ports.html @@ -0,0 +1 @@ +

task_swap_exception_ports


Function - Set target task's exception ports, returning the previous exception ports.

SYNOPSIS

kern_return_t   task_swap_exception_ports
                (task_t                                    task,
                 exception_mask_t               exception_types,
                 mach_port_t                     exception_port,
                 exception_behavior_t                  behavior,
                 thread_state_flavor_t                   flavor,
                 exception_mask_array_t     old_exception_masks,
                 old_exception_masks        old_exception_count,
                 exception_port_array_t     old_exception_ports,
                 exception_behavior_array_t       old_behaviors,
                 exception_flavor_array_t           old_flavors);

PARAMETERS

task
[in task send right] The task for which to set the ports.

exception_types
[in scalar] A flag word indicating the types of exceptions for which the exception port applies:

EXC_MASK_BAD_ACCESS
Could not access memory.

EXC_MASK_BAD_INSTRUCTION
Instruction failed. Illegal or undefined instruction or operand.

EXC_MASK_ARITHMETIC
Arithmetic exception

EXC_MASK_EMULATION
Emulation instruction. Emulation support instruction encountered.

EXC_MASK_SOFTWARE
Software generated exception.

EXC_MASK_BREAKPOINT
Trace, breakpoint, etc.

EXC_MASK_SYSCALL
System call requested.

EXC_MASK_MACH_SYSCALL
System call with a number in the Mach call range requested.

EXC_MASK_RPC_ALERT
Exceptional condition encountered during execution of RPC.

exception_port
[in exception send right] The exception port for all selected exception types.

behavior
[in scalar] The type of exception message to be sent. Defined types are:

EXCEPTION_DEFAULT
Send a catch_exception_raise message including the thread identity.

EXCEPTION_STATE
Send a catch_exception_raise_state message including the thread state.

EXCEPTION_STATE_PROTECTED
Send a catch_exception_raise_state message including the thread state. Mark the exception port (and associated exceptions) as protected.

EXCEPTION_STATE_IDENTITY
Send a catch_exception_raise_state_identity message including the thread identity and state.

EXCEPTION_STATE_IDENTITY_PROTECTED
Send a catch_exception_raise_state_identity message including the thread identity and state. Mark the exception port (and associated exceptions) as protected.

flavor
[in scalar] The type of state to be sent with the exception message. These types are defined in <mach/thread_states.h>.

old_exception_masks
[out array of exception_mask_t] An array, each element being a mask specifying for which exception types the corresponding element of the other arrays apply.

old_exception_count
[pointer to in/out scalar] On input, the maximum size of the array buffers; on output, the number of returned sets returned.

old_exception_ports
[out array of exception send rights] The returned exception ports.

old_behaviors
[out array of exception_behavior_t] The type of exception message to be sent as with behavior.

old_flavors
[out array of thread_state_flavor_t] The type of state to be sent with the exception message. These types are defined in <mach/thread_states.h>.

DESCRIPTION

The task_swap_exception_ports function sets a specified set of exception ports belonging to task, returning the old set. A task exception port is used when a thread specific exception port returns a non-success reply.

NOTES

If the value of the EXC_MACH_SYSCALL exception class exception port is the host name port, Mach kernel traps are executed by the kernel as expected; any other value causes the attempted execution of these system call numbers to be considered an exception.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: mach_task_self, task_get_exception_ports, task_set_exception_ports, thread_create, thread_get_exception_ports, thread_set_exception_ports, thread_swap_exception_ports, catch_exception_raise, thread_abort. \ No newline at end of file diff --git a/osfmk/man/task_terminate.html b/osfmk/man/task_terminate.html new file mode 100755 index 000000000..6e340f57e --- /dev/null +++ b/osfmk/man/task_terminate.html @@ -0,0 +1 @@ +

task_terminate


Function - Terminate the target task and deallocate its resources.

SYNOPSIS

kern_return_t   task_terminate
                (task_t            task);

PARAMETERS

task
[in task send right] The port for the task to be destroyed.

DESCRIPTION

The task_terminate function kills task and all its threads, if any. The kernel frees all resources that are in use by the task. The kernel destroys any port for which the task holds the receive right.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: task_create, task_suspend, task_resume, thread_terminate, thread_suspend. \ No newline at end of file diff --git a/osfmk/man/task_thread_times_info.html b/osfmk/man/task_thread_times_info.html new file mode 100755 index 000000000..50867b4ab --- /dev/null +++ b/osfmk/man/task_thread_times_info.html @@ -0,0 +1 @@ +

task_thread_times_info


Structure - Defines thread execution times information for tasks.

SYNOPSIS

struct task_thread_times_info
{
       time_value_t         user_time;
       time_value_t       system_time;
};

typedef struct task_thread_times_info* task_thread_times_info_t;

FIELDS

user_time
Total user run time for live threads.

system_time
Total system run time for live threads.

DESCRIPTION

The task_thread_times_info structure defines thread execution time statistics for tasks. The task_info function returns these times for a specified task. The thread_info function returns this information for a specific thread.

RELATED INFORMATION

Functions: task_info, thread_info.

Data Structures: task_basic_info, thread_basic_info. \ No newline at end of file diff --git a/osfmk/man/task_threads.html b/osfmk/man/task_threads.html new file mode 100755 index 000000000..7321c1a30 --- /dev/null +++ b/osfmk/man/task_threads.html @@ -0,0 +1 @@ +

task_threads


Function - Return the target task's list of threads.

SYNOPSIS

kern_return_t   task_threads
                (task_t                                    task,
                 thread_act_port_array_t            thread_list,
                 mach_msg_type_number_t*           thread_count);

PARAMETERS

task
[in task send right] The port for the task for which the thread list is to be returned.

thread_list
[out pointer to dynamic array of thread send rights] The returned list of threads within task, in no particular order.

thread_count
[out scalar] The returned count of threads in thread_list.

DESCRIPTION

The task_threads function returns a list of the threads within task. The calling task or thread also receives a send right to the kernel port for each listed thread.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: thread_create, thread_terminate, thread_suspend. \ No newline at end of file diff --git a/osfmk/man/thread_abort.html b/osfmk/man/thread_abort.html new file mode 100755 index 000000000..3f541fb58 --- /dev/null +++ b/osfmk/man/thread_abort.html @@ -0,0 +1 @@ +

thread_abort


Function - Abort a thread.

SYNOPSIS

kern_return_t   thread_abort
                (thread_act_t                     target_thread);

PARAMETERS

target_thread
[in thread send right] The thread to be aborted.

DESCRIPTION

The thread_abort function aborts page faults and any message primitive calls in use by target_thread. Scheduling depressions and clock sleeps are also aborted. The call returns a code indicating that it was interrupted. The call is interrupted even if the thread (or the task containing it) is suspended. If it is suspended, the thread receives the interrupt when it resumes.

If its state is not modified before it resumes, the thread will retry an aborted page fault. The Mach message trap returns either MACH_SEND_INTERRUPTED or MACH_RCV_INTERRUPTED, depending on whether the send or the receive side was interrupted. Note, though, that the Mach message trap is contained within the mach_msg library routine, which, by default, retries interrupted message calls.

The basic purpose of thread_abort is to let one thread cleanly stop another thread (target_thread). The target thread is stopped in such a manner that its future execution can be controlled in a predictable way. When thread_abort returns, the target thread will appear to have just returned from the kernel (if it had been in kernel mode).

NOTES

By way of comparison, the thread_suspend function keeps the target thread from executing any further instructions at the user level, including the return from a system call. The thread_get_state function returns the thread's user state, while thread_set_state allows modification of the user state.

A problem occurs if a suspended thread had been executing within a system call. In this case, the thread has, not only a user state, but an associated kernel state. (The kernel state cannot be changed with thread_set_state.) As a result, when the thread resumes, the system call can return, producing a change in the user state and, possibly, user memory.

For a thread executing within a system call, thread_abort aborts the kernel call from the thread's point of view. Specifically, it resets the kernel state so that the thread will resume execution at the system call return, with the return code value set to one of the interrupted codes. The system call itself may be completed entirely, aborted entirely or be partially completed, depending on when the abort is received. As a result, if the thread's user state has been modified by thread_set_state, it will not be altered un-predictably by any unexpected system call side effects.

For example, to simulate a POSIX signal, use the following sequence of calls:

thread_suspend\(emTo stop the thread.
thread_abort\(emTo interrupt any system call in progress and set the return value to "interrupted". Because the thread is already stopped, it will not return to user code.
thread_set_state\(emTo modify the thread's user state to simulate a procedure call to the signal handler.
thread_resume\(emTo resume execution at the signal handler. If the thread's stack is set up correctly, the thread can return to the interrupted system call. Note that the code to push an extra stack frame and change the registers is highly machine dependent.

CAUTIONS

As a rule, do not use thread_abort on a non-suspended thread. This operation is very risky because it is difficult to know which system trap, if any, is executing and whether an interrupt return will result in some useful action by the thread.

thread_abort will abort any non-atomic operation (such as a multi-page memory_object_data_supply) at an arbitrary point in a non-restartable way. Such problems can be avoided by using thread_abort_safely.

RETURN VALUES

KERN_EXCEPTION_PROTECTED
The thread is processing a protected exception.

RELATED INFORMATION

Functions: mach_msg, thread_get_state, thread_info, thread_set_state, thread_suspend, thread_terminate, thread_abort_safely, thread_set_exception_ports. \ No newline at end of file diff --git a/osfmk/man/thread_abort_safely.html b/osfmk/man/thread_abort_safely.html new file mode 100755 index 000000000..7dc47fc15 --- /dev/null +++ b/osfmk/man/thread_abort_safely.html @@ -0,0 +1 @@ +

thread_abort_safely


Function - Abort a thread, restartably.

SYNOPSIS

kern_return_t   thread_abort_safely
                (thread_act_t                     target_thread);

PARAMETERS

target_thread
[in thread send right] The thread to be aborted.

DESCRIPTION

The thread_abort_safely function aborts page faults and any message primitive calls in use by target_thread. Scheduling depressions and clock sleeps are also aborted. The call returns a code indicating that it was interrupted. The call is interrupted even if the thread (or the task containing it) is suspended. If it is suspended, the thread receives the interrupt when it resumes.

If its state is not modified before it resumes, the thread will retry an aborted page fault. The Mach message trap returns either MACH_SEND_INTERRUPTED or MACH_RCV_INTERRUPTED, depending on whether the send or the receive side was interrupted. Note, though, that the Mach message trap is contained within the mach_msg library routine, which, by default, retries interrupted message calls.

The basic purpose of thread_abort_safely is to let one thread cleanly stop another thread (target_thread). The target thread is stopped in such a manner that its future execution can be controlled in a predictable way. When thread_abort_safely returns (if successful), the target thread will appear to have just returned from the kernel (if it had been in kernel mode).

NOTES

By way of comparison, the thread_suspend function keeps the target thread from executing any further instructions at the user level, including the return from a system call. The thread_get_state function returns the thread's user state, while thread_set_state allows modification of the user state.

A problem occurs if a suspended thread had been executing within a system call. In this case, the thread has, not only a user state, but an associated kernel state. (The kernel state cannot be changed with thread_set_state.) As a result, when the thread resumes, the system call can return, producing a change in the user state and, possibly, user memory.

For a thread executing within a system call, thread_abort_safely aborts the kernel call from the thread's point of view. Specifically, it resets the kernel state so that the thread will resume execution at the system call return, with the return code value set to one of the interrupted codes. The system call itself may completed entirely, aborted entirely or be partially completed, depending on when the abort is received. As a result, if the thread's user state has been modified by thread_set_state, it will not be altered un-predictably by any unexpected system call side effects.

For example, to simulate a POSIX signal, use the following sequence of calls:

thread_suspend\(emTo stop the thread.
thread_abort_safely\(emTo interrupt any system call in progress and set the return value to "interrupted". Because the thread is already stopped, it will not return to user code.
thread_set_state\(emTo modify the thread's user state to simulate a procedure call to the signal handler.
thread_resume\(emTo resume execution at the signal handler. If the thread's stack is set up correctly, the thread can return to the interrupted system call. Note that the code to push an extra stack frame and change the registers is highly machine dependent.

CAUTIONS

As a rule, do not use thread_abort_safely on a non-suspended thread. This operation is very risky because it is difficult to know which system trap, if any, is executing and whether an interrupt return will result in some useful action by the thread.

thread_abort_safely will not abort any non-atomic operation (such as a multi-page memory_object_data_supply or exception processing) but will return an error instead. The caller of this function must then allow the thread to resume and attempt to abort it later. If the thread must be aborted, even if doing so would abort any non-atomic operations, thread_abort would be used.

RETURN VALUES

KERN_FAILURE
The thread is in the middle of a non-restartable operation.

RELATED INFORMATION

Functions: mach_msg, thread_get_state, thread_info, thread_set_state, thread_suspend, thread_terminate, thread_abort. \ No newline at end of file diff --git a/osfmk/man/thread_activation_create.html b/osfmk/man/thread_activation_create.html new file mode 100755 index 000000000..3907322d5 --- /dev/null +++ b/osfmk/man/thread_activation_create.html @@ -0,0 +1 @@ +

thread_activation_create


Function - Create a thread activation.

SYNOPSIS

kern_return_t   thread_activation_create
                (task_t                                    task,
                 mach_port_name_t                      RPC_port,
                 vm_offset_t                         user_stack,
                 vm_size_t                           stack_size,
                 thread_act_t                      thread_act_t);

PARAMETERS

task
[in task send right] The port for the task that is to contain the new thread activation.

RPC_port
[in receive right] A receive right held by the task, or a port set in the task.

user_stack
[in scalar] The virtual address in the task to be used as the starting ad- dress of the user-level stack.

new_act
[out thread send right] The kernel-assigned name for the new thread ac- tivation.

DESCRIPTION

The thread_activation_create function creates a thread activation, or "empty thread", into which a client thread shuttle can migrate during RPC. The RPC_port must name ei- ther a receive right held by the task, or a port set in the task. The new thread activation will be added to a pool of activations attached to this port (or port set). Incoming RPC's targeted at the port (or one of the ports in the set) can use any of the activations in the pool. That is, the client thread shuttle will migrate into the specified server task, take one of the thread activations out of the pool, and join up with it for the duration of the RPC. The shuttle will migrate back to the original client activation at the end of the RPC. If no thread activations are in the pool, RPC will be blocked until one is created in the pool, or an existing one finishes its RPC and returns to the pool. The new thread activation will begin each RPC using the stack pointer specified by user_stack. The kernel neither knows nor cares how big the specified stack is. When a short-circuited RPC (or mach_rpc) is invoked on a port created with mach_port_allocate_subsystem, the RPC will begin execution in the subsystem server at the work function address specified by the port and routine number and looked up in the associated subsystem data.

NOTES

The following calls targeted at a thread_act port may _not_ be called on an empty thread_act (and will return KERN_INVALID_ARGUMENT if they are called with one): thread_abort thread_abort_safely thread_depress_abort thread_info thread_wire In addition, if thread_switch is called with an empty thread_act as its first argument, the argument will be ignored (i.e., the function will behave as if a zero-valued argument had been given).

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: task_create, mach_port_allocate_subsystem, \ No newline at end of file diff --git a/osfmk/man/thread_assign.html b/osfmk/man/thread_assign.html new file mode 100755 index 000000000..a5e767eb0 --- /dev/null +++ b/osfmk/man/thread_assign.html @@ -0,0 +1 @@ +

thread_assign


Function - Assign a thread to a processor set.

SYNOPSIS

kern_return_t   thread_assign
                (thread_act_t                            thread,
                 processor_set_t                  processor_set);

PARAMETERS

thread
[in thread send right] The thread to be assigned.

processor_set
[in processor-set-control send right] The control port for the processor set into which the thread is to be assigned.

DESCRIPTION

The thread_assign function assigns thread to the set processor_set. After the assignment is completed, the thread executes only on processors that are assigned to that processor set. Any previous assignment of the thread is nullified.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: thread_assign_default, thread_get_assignment, processor_set_create, processor_set_info, task_assign. \ No newline at end of file diff --git a/osfmk/man/thread_assign_default.html b/osfmk/man/thread_assign_default.html new file mode 100755 index 000000000..76e8114f5 --- /dev/null +++ b/osfmk/man/thread_assign_default.html @@ -0,0 +1 @@ +

thread_assign_default


Function - Assign a thread to the default processor set.

SYNOPSIS

kern_return_t   thread_assign_default
                (thread_act_t                            thread);

PARAMETERS

thread
[in thread send right] The thread to be assigned.

DESCRIPTION

The thread_assign_default function assigns thread to the default processor set. After the assignment is completed, the thread executes only on processors that are assigned to that processor set. Any previous assignment of the thread is nullified.

NOTES

This variant of thread_assign exists because the control port for the default processor set is privileged, and therefore not available to most tasks.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: thread_assign, thread_get_assignment, processor_set_create, processor_set_info, task_assign. \ No newline at end of file diff --git a/osfmk/man/thread_basic_info.html b/osfmk/man/thread_basic_info.html new file mode 100755 index 000000000..c852420d0 --- /dev/null +++ b/osfmk/man/thread_basic_info.html @@ -0,0 +1 @@ +

thread_basic_info


Structure - Defines basic information for a thread.

SYNOPSIS

struct thread_basic_info
{
       time_value_t     user_time;
       time_value_t   system_time;
       integer_t        cpu_usage;
       policy_t            policy;
       integer_t        run_state;
       integer_t            flags;
       integer_t    suspend_count;
       integer_t       sleep_time;
};

typedef struct thread_basic_info* thread_basic_info_t;

FIELDS

user_time
The total user run time for the thread.

system_time
The total system run time for the thread.

cpu_usage
Scaled CPU usage percentage for the thread.

policy
Scheduling policy in effect

run_state
The thread's run state. Possible values are:

TH_STATE_RUNNING
The thread is running normally.

TH_STATE_STOPPED
The thread is stopped.

TH_STATE_WAITING
The thread is waiting normally.

TH_STATE_UNINTERRUPTIBLE
The thread is in an un-interruptible wait state.

TH_STATE_HALTED
The thread is halted at a clean point.

flags
Swap/idle flags for the thread. Possible values are:

TH_FLAGS_SWAPPED
The thread is swapped out.

TH_FLAGS_IDLE
The thread is an idle thread.

suspend_count
The current suspend count for the thread.

sleep_time
The number of seconds that the thread has been sleeping.

DESCRIPTION

The thread_basic_info structure defines the basic information array for threads. The thread_info function returns this array for a specified thread.

RELATED INFORMATION

Functions: thread_info.

Data Structures: policy_fifo_info, policy_rr_info, policy_timeshare_info. \ No newline at end of file diff --git a/osfmk/man/thread_create.html b/osfmk/man/thread_create.html new file mode 100755 index 000000000..135b1c5bd --- /dev/null +++ b/osfmk/man/thread_create.html @@ -0,0 +1 @@ +

thread_create


Function - Create a thread within a task.

SYNOPSIS

kern_return_t   thread_create
                (task_t                             parent_task,
                 thread_act_t                      child_thread);

PARAMETERS

parent_task
[in task send right] The port for the task that is to contain the new thread.

child_thread
[out thread send right] The kernel-assigned name for the new thread.

DESCRIPTION

The thread_create function creates a new thread within parent_task. The new thread has a suspend count of one and no processor state.

The new thread holds a send right for its thread kernel port. A send right for the thread's kernel port is also returned to the calling task or thread in child_thread. The new thread's exception ports are set to MACH_PORT_NULL.

NOTES

To get a new thread running, first use thread_set_state to set a processor state for the thread. Then, use thread_resume to schedule the thread for execution. Alternately, use thread_create_running.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: task_create, task_threads, thread_get_special_port, thread_get_state, thread_resume, thread_set_special_port, thread_set_state, thread_suspend, thread_terminate, thread_create_running. \ No newline at end of file diff --git a/osfmk/man/thread_create_running.html b/osfmk/man/thread_create_running.html new file mode 100755 index 000000000..bab1033a7 --- /dev/null +++ b/osfmk/man/thread_create_running.html @@ -0,0 +1 @@ +

thread_create_running


Function - Optimized creation of a running thread.

SYNOPSIS

kern_return_t   thread_create_running
                (task_t                             parent_task,
                 thread_state_flavor_t                   flavor,
                 thread_state_t                           state,
                 thread_act_t                      child_thread);

PARAMETERS

parent_task
[in task send right] The port for the task that is to contain the new thread.

flavor
[in scalar] The type of state to establish. Valid values correspond to supported machine architecture features.

state
[pointer to in structure] State information for the specified thread.

child_thread
[out thread send right] The kernel-assigned name for the new thread.

DESCRIPTION

The thread_create_running function creates a new thread within parent_task. The new thread has is not suspended. Its initial state is given by state. flavor specifies the type of state to set.

The format of the state to set is machine specific; it is defined in \*L\*O.

The new thread holds a send right for its thread kernel port. A send right for the thread's kernel port is also returned to the calling task or thread in child_thread. The new thread's exception ports are set to MACH_PORT_NULL.

NOTES

This is an optimized form of the sequence: thread_create, thread_set_state and thread_resume.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: task_create, task_threads, thread_get_special_port, thread_get_state, thread_resume, thread_set_special_port, thread_set_state, thread_suspend, thread_terminate, thread_create. \ No newline at end of file diff --git a/osfmk/man/thread_depress_abort.html b/osfmk/man/thread_depress_abort.html new file mode 100755 index 000000000..498d93a3e --- /dev/null +++ b/osfmk/man/thread_depress_abort.html @@ -0,0 +1 @@ +

thread_depress_abort


Function - Cancel thread scheduling depression.

SYNOPSIS

kern_return_t   thread_depress_abort
                (thread_act_t                            thread);

PARAMETERS

thread
[in thread send right] Thread whose scheduling depression is canceled.

DESCRIPTION

The thread_depress_abort function cancels any scheduling depression effective for thread caused by a thread_switch call.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: thread_abort, thread_switch. \ No newline at end of file diff --git a/osfmk/man/thread_get_assignment.html b/osfmk/man/thread_get_assignment.html new file mode 100755 index 000000000..ad6c4171c --- /dev/null +++ b/osfmk/man/thread_get_assignment.html @@ -0,0 +1 @@ +

thread_get_assignment


Function - Return the processor set to which a thread is assigned.

SYNOPSIS

kern_return_t   thread_get_assignment
                (thread_act_t                            thread,
                 processor_set_name_t             processor_set);

PARAMETERS

thread
[in thread send right] The thread whose assignment is desired.

processor_set
[out processor-set-name send right] The name port for the processor set into which the thread is assigned.

DESCRIPTION

The thread_get_assignment function returns the name port to the processor set to which thread is currently assigned. This port can only be used to obtain information about the processor set.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: thread_assign, thread_assign_default, processor_set_create, processor_set_info, task_assign. \ No newline at end of file diff --git a/osfmk/man/thread_get_exception_ports.html b/osfmk/man/thread_get_exception_ports.html new file mode 100755 index 000000000..70fbb6726 --- /dev/null +++ b/osfmk/man/thread_get_exception_ports.html @@ -0,0 +1 @@ +

thread_get_exception_ports


Function - Return a send right to an exception port.

SYNOPSIS

kern_return_t   thread_get_exception_ports
                (thread_act_t                            thread,
                 exception_mask_t               exception_types,
                 exception_mask_array_t     old_exception_masks,
                 old_exception_masks        old_exception_count,
                 exception_port_array_t     old_exception_ports,
                 exception_behavior_array_t       old_behaviors,
                 exception_flavor_array_t           old_flavors);

PARAMETERS

thread
[in thread send right] The thread for which to return the exception ports.

exception_types
[in scalar] A flag word indicating the types of exceptions for which the exception ports are desired:

EXC_MASK_BAD_ACCESS
Could not access memory.

EXC_MASK_BAD_INSTRUCTION
Instruction failed. Illegal or undefined instruction or operand.

EXC_MASK_ARITHMETIC
Arithmetic exception.

EXC_MASK_EMULATION
Emulation instruction. Emulation support instruction encountered.

EXC_MASK_SOFTWARE
Software generated exception.

EXC_MASK_BREAKPOINT
Trace, breakpoint, etc.

EXC_MASK_SYSCALL
System call requested.

EXC_MASK_MACH_SYSCALL
System call with a number in the Mach call range requested.

old_exception_masks
[out array of exception_mask_t] An array, each element being a mask specifying for which exception types the corresponding element of the other arrays apply.

old_exception_count
[pointer to in/out scalar] On input, the maximum size of the array buffers; on output, the number of returned sets returned.

old_exception_ports
[out array of exception send rights] The returned exception ports.

old_behaviors
[out array of exception_behavior_t] The type of exception message to be sent. Defined types are:

EXCEPTION_DEFAULT
Send a catch_exception_raise message including the thread identity.

EXCEPTION_STATE
Send a catch_exception_raise_state message including the thread state.

EXCEPTION_STATE_IDENTITY
Send a catch_exception_raise_state_identity message including the thread identity and state.

old_flavors
[out array of thread_state_flavor_t] The type of state to be sent with the exception message. These types are defined in \*L\*O.

DESCRIPTION

The thread_get_exception_ports function returns send rights for a specified set of exception ports belonging to thread. The call returns a set of quadruples for each unique set of in effect for the thread where the exception type mask indicates for which exception types the other values apply.

RETURN VALUES

KERN_EXCEPTION_PROTECTED
One of the requested exception ports is protected and cannot be returned.

RELATED INFORMATION

Functions: mach_thread_self, task_get_exception_ports, task_set_exception_ports, task_swap_exception_ports, thread_create, thread_set_exception_ports, thread_swap_exception_ports, catch_exception_raise. \ No newline at end of file diff --git a/osfmk/man/thread_get_special_port.html b/osfmk/man/thread_get_special_port.html new file mode 100755 index 000000000..2acf05b9c --- /dev/null +++ b/osfmk/man/thread_get_special_port.html @@ -0,0 +1 @@ +

thread_get_special_port


Function - Return a send right to the caller-specified special port.

SYNOPSIS

kern_return_t   thread_get_special_port
                (thread_act_t                            thread,
                 int                                 which_port,
                 thread                            special_port);

Macro form:

kern_return_t   thread_get_kernel_port
                (thread_act_t                            thread,
                 thread                            special_port);

PARAMETERS

thread
[in thread send right] The thread for which to return the port's send right.

which_port
[in scalar] The special port for which the send right is requested. Valid values are:

THREAD_KERNEL_PORT
[thread-self send right] The port used to name the thread. Used to invoke operations that affect the thread. This is the port returned by mach_thread_self.

special_port
[out thread-special send right] The returned value for the port.

DESCRIPTION

The thread_get_special_port function returns a send right for a special port belonging to thread.

The thread kernel port is a port for which the kernel holds the receive right. The kernel uses this port to identify the thread.

If one thread has a send right for the kernel port of another thread, it can use the port to perform kernel operations for the other thread. Send rights for a kernel port normally are held only by the thread to which the port belongs, or by the task that contains the thread. Using the mach_msg function, however, any thread can pass a send right for its kernel port to another thread.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: mach_thread_self, task_get_special_port, task_set_special_port, thread_create, thread_set_special_port. \ No newline at end of file diff --git a/osfmk/man/thread_get_state.html b/osfmk/man/thread_get_state.html new file mode 100755 index 000000000..f081bbf02 --- /dev/null +++ b/osfmk/man/thread_get_state.html @@ -0,0 +1 @@ +

thread_get_state


Function - Return the execution state for a thread.

SYNOPSIS

kern_return_t   thread_get_state
                (thread_act_t                     target_thread,
                 thread_state_flavor_t                   flavor,
                 thread_state_t                       old_state,
                 mach_msg_type_number_t         old_state_count);

PARAMETERS

target_thread
[in thread send right] The thread for which the execution state is to be returned. The calling thread cannot specify itself.

flavor
[in scalar] The type of execution state to be returned. Valid values correspond to supported machined architectures.

old_state
[out structure] State information for the specified thread.

old_state_count
[in/out scalar] On input, the maximum size of the buffer; on output, the size returned (in natural-sized units).

DESCRIPTION

The thread_get_state function returns the execution state (for example, the machine registers) for target_thread. flavor specifies the type of state information returned.

The format of the data returned is machine specific; it is defined in \*L\*O.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: task_info, thread_info, thread_set_state. \ No newline at end of file diff --git a/osfmk/man/thread_info.html b/osfmk/man/thread_info.html new file mode 100755 index 000000000..150b51ed3 --- /dev/null +++ b/osfmk/man/thread_info.html @@ -0,0 +1 @@ +

thread_info


Function - Return information about a thread.

SYNOPSIS

kern_return_t   thread_info
                (thread_act_t                     target_thread,
                 thread_flavor_t                         flavor,
                 thread_info_t                      thread_info,
                 mach_msg_type_number_t       thread_info_count);

PARAMETERS

target_thread
[in thread send right] The thread for which the information is to be returned.

flavor
[in scalar] The type of information to be returned. Valid values are:

THREAD_BASIC_INFO
Returns basic information about the thread, such as the thread's run state and suspend count. The returned structure is thread_basic_info.

THREAD_SCHED_FIFO_INFO
Returns FIFO scheduling policy information about the thread. The returned structure is policy_fifo_info.

THREAD_SCHED_RR_INFO
Returns round-robin scheduling policy information about the thread. The returned structure is policy_rr_info.

THREAD_SCHED_TIMESHARE_INFO
Returns timeshare scheduling policy information about the thread. The returned structure is policy_timeshare_info.

thread_info
[out structure] Information about the specified thread.

thread_info_count
[in/out scalar] On input, the maximum size of the buffer; on output, the size returned (in natural-sized units).

DESCRIPTION

The thread_info function returns an information structure of type flavor.

NOTES

At any given time, a thread has only one scheduling policy in effect for it. Thus, only one of the scheduling information structures will be valid, that so indicated by the policy value returned by THREAD_BASIC_INFO.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: task_info, task_threads, thread_get_state, thread_set_special_port, thread_set_state.

Data Structures: thread_basic_info, policy_timeshare_info, policy_fifo_info, policy_rr_info. \ No newline at end of file diff --git a/osfmk/man/thread_policy.html b/osfmk/man/thread_policy.html new file mode 100755 index 000000000..c8534fda9 --- /dev/null +++ b/osfmk/man/thread_policy.html @@ -0,0 +1 @@ +

thread_policy


Function - Set target thread's scheduling policy state.

SYNOPSIS

kern_return_t   thread_policy
                (thread_act_t                            thread,
                 policy_t                                policy,
                 policy_base_t                             base,
                 base                                base_count,
                 boolean_t                            set_limit);

PARAMETERS

thread
[in thread send right] The thread scheduling policy is to be set.

policy
[in scalar] Policy to be set. The values currently defined are POLICY_TIMESHARE, POLICY_RR (round robin) and POLICY_FIFO (firstin, first-out).

base
[pointer to in structure] Base scheduling policy specific data, policy_fifo_base, policy_rr_base or policy_timeshare_base.

base_count
[in scalar] The size of the buffer (in natural-sized units).

set_limit
[in scalar] True if the thread's scheduling limits should be restricted to allow no more service than specified by base.

DESCRIPTION

The thread_policy function sets the scheduling policy to be applied to thread. policy must be a scheduling policy currently "enabled" for the thread's assigned processor set.

RETURN VALUES

KERN_INVALID_POLICY
The processor set to which thread is currently assigned does not currently enable policy.

KERN_POLICY_LIMIT
The specified scheduling attributes exceeds the thread's limits.

RELATED INFORMATION

Functions: processor_set_policy_control, thread_set_policy, task_policy, task_set_policy.

Data Structures: policy_fifo_info, policy_rr_info, policy_timeshare_info. \ No newline at end of file diff --git a/osfmk/man/thread_resume.html b/osfmk/man/thread_resume.html new file mode 100755 index 000000000..93d51331f --- /dev/null +++ b/osfmk/man/thread_resume.html @@ -0,0 +1 @@ +

thread_resume


Function - Resume a thread.

SYNOPSIS

kern_return_t   thread_resume
                (thread_act_t                     target_thread);

PARAMETERS

target_thread
[in thread send right] The thread to be resumed.

DESCRIPTION

The thread_resume function decrements the suspend count for target_thread by one. The thread is resumed if its suspend count goes to zero. If the suspend count is still positive, thread_resume must be repeated until the count reaches zero.

NOTES

An attempt to lower the suspend count below zero is ignored.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: task_resume, task_suspend, thread_create, thread_info, thread_suspend, thread_terminate. \ No newline at end of file diff --git a/osfmk/man/thread_sample.html b/osfmk/man/thread_sample.html new file mode 100755 index 000000000..2e2eae6be --- /dev/null +++ b/osfmk/man/thread_sample.html @@ -0,0 +1 @@ +

thread_sample


Function - Perform periodic PC sampling for a thread.

SYNOPSIS

kern_return_t   thread_sample
                (thread_act_t                     sample_thread,
                 mach_port_make_send_t               reply_port);

PARAMETERS

sample_thread
[in thread send right] Thread whose PC is to be sampled

reply_port
[in sample receive (to be converted to send) right] Port to which PC sample buffers are sent. A value of MACH_PORT_NULL stops PC sampling for the thread.

DESCRIPTION

The thread_sample function causes the program counter (PC) of the specified sample_thread to be sampled periodically (whenever the thread happens to be running at the time of the kernel's "hardclock" interrupt). The set of PC sample values obtained are saved in buffers which are sent to the specified reply_port in receive_samples messages.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: task_sample, receive_samples. \ No newline at end of file diff --git a/osfmk/man/thread_set_exception_ports.html b/osfmk/man/thread_set_exception_ports.html new file mode 100755 index 000000000..39bc5a5a1 --- /dev/null +++ b/osfmk/man/thread_set_exception_ports.html @@ -0,0 +1 @@ +

thread_set_exception_ports


Function - Set exception ports for a thread.

SYNOPSIS

kern_return_t   thread_set_exception_ports
                (thread_act_t                            thread,
                 exception_mask_t               exception_types,
                 mach_port_t                     exception_port,
                 exception_behavior_t                  behavior,
                 thread_state_flavor_t                   flavor);

PARAMETERS

thread
[in thread send right] The thread for which to set the ports.

exception_types
[in scalar] A flag word indicating the types of exceptions for which the exception port applies:

EXC_MASK_BAD_ACCESS
Could not access memory.

EXC_MASK_BAD_INSTRUCTION
Instruction failed. Illegal or undefined instruction or operand.

EXC_MASK_ARITHMETIC
Arithmetic exception.

EXC_MASK_EMULATION
Emulation instruction. Emulation support instruction encountered.

EXC_MASK_SOFTWARE
Software generated exception.

EXC_MASK_BREAKPOINT
Trace, breakpoint, etc.

EXC_MASK_SYSCALL
System call requested.

EXC_MASK_MACH_SYSCALL
System call with a number in the Mach call range requested.

exception_port
[in exception send right] The exception port for all selected exception types.

behavior
[in scalar] The type of exception message to be sent. Defined types are:

EXCEPTION_DEFAULT
Send a catch_exception_raise message including the thread identity.

EXCEPTION_DEFAULT_PROTECTED
Send a catch_exception_raise message including the thread identity. Mark the exception port (and associated exceptions) as protected.

EXCEPTION_STATE
Send a catch_exception_raise_state message including the thread state.

EXCEPTION_STATE_PROTECTED
Send a catch_exception_raise_state message including the thread state. Mark the exception port (and associated exceptions) as protected.

EXCEPTION_STATE_IDENTITY
Send a catch_exception_raise_state_identity message including the thread identity and state.

EXCEPTION_STATE_IDENTITY_PROTECTED
Send a catch_exception_raise_state_identity message including the thread identity and state. Mark the exception port (and associated exceptions) as protected.

flavor
[in scalar] The type of state to be sent with the exception message. These types are defined in \*L\*O.

DESCRIPTION

The thread_set_exception_ports function sets a specified set of exception ports belonging to thread.

NOTES

If the value of the EXC_MACH_SYSCALL exception class exception port is the host name port, Mach kernel traps are executed by the kernel as expected; any other value causes the attempted execution of these system call numbers to be considered an exception.

A "protected" exception port is one which cannot be fetched and for which exception processing cannot be aborted (thread_abort).

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: mach_thread_self, task_get_exception_ports, task_set_exception_ports, task_swap_exception_ports, thread_create, thread_get_exception_ports, thread_swap_exception_ports, catch_exception_raise, thread_abort. \ No newline at end of file diff --git a/osfmk/man/thread_set_policy.html b/osfmk/man/thread_set_policy.html new file mode 100755 index 000000000..ea36db885 --- /dev/null +++ b/osfmk/man/thread_set_policy.html @@ -0,0 +1 @@ +

thread_set_policy


Function - Set target thread's scheduling policy state. (Protected Interface.)

SYNOPSIS

kern_return_t   thread_set_policy
                (thread_act_t                            thread,
                 processor_set_t                  processor_set,
                 policy_t                                policy,
                 policy_base_t                             base,
                 mach_msg_type_number_t              base_count,
                 policy_limit_t                           limit,
                 mach_msg_type_number_              limit_count);

PARAMETERS

thread
[in thread send right] The thread scheduling policy is to be set.

processor_set
[in processor-set-control send right] The control port for the processor set to which the thread is currently assigned.

policy
[in scalar] Policy to be set. The values currently defined are POLICY_TIMESHARE, POLICY_RR (round robin) and POLICY_FIFO (firstin, first-out).

base
[pointer to in structure] Base policy specific data, policy_fifo_base, policy_rr_base or policy_timeshare_base.

base_count
[in scalar] The size of the buffer (in natural-sized units).

limit
[pointer to in structure] Policy specific limits, policy_fifo_limit, policy_rr_limit or policy_timeshare_limit.

limit_count
[in scalar] The size of the buffer (in natural-sized units).

DESCRIPTION

The thread_set_policy function sets the scheduling attributes, both base and limit, for thread. policy may be any policy implemented by the processor set whether or not it is enabled.

RETURN VALUES

KERN_INVALID_PROCESSOR_SET
processor_set is not the thread's processor set control port.

RELATED INFORMATION

Functions: processor_set_policy_control, thread_policy, task_policy, task_set_policy.

Data Structures: policy_fifo_info, policy_rr_info, policy_timeshare_info. \ No newline at end of file diff --git a/osfmk/man/thread_set_special_port.html b/osfmk/man/thread_set_special_port.html new file mode 100755 index 000000000..5359a6fae --- /dev/null +++ b/osfmk/man/thread_set_special_port.html @@ -0,0 +1 @@ +

thread_set_special_port


Function - Set caller-specified special port belonging to the target thread.

SYNOPSIS

kern_return_t   thread_set_special_port
                (thread_act_t                            thread,
                 int                                 which_port,
                 mach_port_t                       special_port);

Macro form:

kern_return_t   thread_set_kernel_port
                (thread_act_t                            thread,
                 mach_port_t                       special_port);

PARAMETERS

thread
[in thread send right] The thread for which to set the port.

which_port
[in scalar] The special port to be set. Valid values are:

THREAD_KERNEL_PORT
[thread-self port] The thread's kernel port. Used by the kernel to receive messages from the thread. This is the port returned by mach_thread_self.

special_port
[in thread-special send right] The value for the port.

DESCRIPTION

The thread_set_special_port function sets a special port belonging to thread.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: mach_thread_self, task_get_special_port, task_set_special_port, thread_create, thread_get_special_port. \ No newline at end of file diff --git a/osfmk/man/thread_set_state.html b/osfmk/man/thread_set_state.html new file mode 100755 index 000000000..3e64d6ca9 --- /dev/null +++ b/osfmk/man/thread_set_state.html @@ -0,0 +1 @@ +

thread_set_state


Function - Set the target thread's user-mode execution state.

SYNOPSIS

kern_return_t   thread_set_state
                (thread_act_t                     target_thread,
                 thread_state_flavor_t                   flavor,
                 thread_state_t                       new_state,
                 target_thread                  new_state_count);

PARAMETERS

target_thread
[in thread send right] The thread for which to set the execution state. The calling thread cannot specify itself.

flavor
[in scalar] The type of state to set. Valid values correspond to supported machine architecture features.

new_state
[pointer to in structure] State information for the specified thread.

new_state_count
[in scalar] The size of the buffer (in natural-sized units).

DESCRIPTION

The thread_set_state function sets the execution state (for example, the machine registers) for target_thread. flavor specifies the type of state to set.

The format of the state to set is machine specific; it is defined in mach/thread_status.h.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: task_info, thread_get_state, thread_info. \ No newline at end of file diff --git a/osfmk/man/thread_suspend.html b/osfmk/man/thread_suspend.html new file mode 100755 index 000000000..78c2dba35 --- /dev/null +++ b/osfmk/man/thread_suspend.html @@ -0,0 +1 @@ +

thread_suspend


Function - Suspend a thread.

SYNOPSIS

kern_return_t   thread_suspend
                (thread_act_t                     target_thread);

PARAMETERS

target_thread
[in thread send right] The thread to be suspended.

DESCRIPTION

The thread_suspend function increments the suspend count for target_thread and prevents the thread from executing any more user-level instructions.

In this context, a user-level instruction can be either a machine instruction executed in user mode or a system trap instruction, including a page fault. If a thread is currently executing within a system trap, the kernel code may continue to execute until it reaches the system return code or it may suspend within the kernel code. In either case, the system trap returns when the thread resumes.

To resume a suspended thread, use thread_resume. If the suspend count is greater than one, thread_resume must be repeated that number of times.

CAUTIONS

Unpredictable results may occur if a program suspends a thread and alters its user state so that its direction is changed upon resuming. Note that the thread_abort function allows a system call to be aborted only if it is progressing in a predictable way.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: task_resume, task_suspend, thread_abort, thread_get_state, thread_info, thread_resume, thread_set_state, thread_terminate. \ No newline at end of file diff --git a/osfmk/man/thread_switch.html b/osfmk/man/thread_switch.html new file mode 100755 index 000000000..8e4d67ffa --- /dev/null +++ b/osfmk/man/thread_switch.html @@ -0,0 +1 @@ +

thread_switch


Function - Cause context switch with options.

SYNOPSIS

kern_return_t   thread_switch
                (mach_port_t                         new_thread,
                 int                                     option,
                 mach_msg_timeout_t                        time);

PARAMETERS

new_thread
[in thread send right] Thread to which the processor should switch context.

option
[in scalar] Options applicable to the context switch.

time
[in scalar] Time duration during which the thread should be affected by option.

DESCRIPTION

The thread_switch function provides low-level access to the scheduler's context switching code. new_thread is a hint that implements hand-off scheduling. The operating system will attempt to switch directly to the new thread (bypassing the normal logic that selects the next thread to run) if possible. Since this is a hint, it may be incorrect; it is ignored if it doesn't specify a thread on the same host as the current thread or if the scheduler cannot switch to that thread (i.e., not runable or already running on another processor). In this case, the normal logic to select the next thread to run is used; the current thread may continue running if there is no other appropriate thread to run.

The option argument specifies the interpretation and use of time. The possible values (from \*L\*O) are:

SWITCH_OPTION_NONE
The time argument is ignored.
SWITCH_OPTION_WAIT
The thread is blocked for the specified time. This wait cannot be canceled by thread_resume; only thread_abort can terminate this wait.
SWITCH_OPTION_DEPRESS
The thread's scheduling attributes are temporarily set so as to provide it with the lowest possible service for duration time. The scheduling depression is aborted when time has passed, when the current thread is next run (either via hand-off scheduling or because the processor set has nothing better to do), or when thread_abort or thread_depress_abort is applied to the current thread. Changing the thread's scheduling attributes (via thread_policy) will not affect this depression.
SWITCH_OPTION_IDLE
This option is similar to SWITCH_OPTION_DEPRESS however, the thread's scheduling attributes are temporarily set so as to place it at a service level that is below all runnable threads for duration time. The scheduling depression is aborted when time has passed, when the current thread is next run (either via hand-off scheduling or because the processor set has nothing better to do), or when thread_abort or thread_depress_abort is applied to the current thread. Changing the thread's scheduling attributes (via thread_policy) will not affect this depression.

The minimum time and units of time can be obtained as the min_timeout value from the HOST_SCHED_INFO flavor of host_info.

NOTES

thread_switch is often called when the current thread can proceed no further for some reason; the various options and arguments allow information about this reason to be transmitted to the kernel. The new_thread argument (hand-off scheduling) is useful when the identity of the thread that must make progress before the current thread runs again is known. The SWITCH_OPTION_WAIT option is used when the amount of time that the current thread must wait before it can do anything useful can be estimated and is fairly short, especially when the identity of the thread for which this thread must wait is not known.

CAUTIONS

Users should beware of calling thread_switch with an invalid hint (e.g., THREAD_NULL) and no option. Because the time-sharing scheduler varies the priority of threads based on usage, this may result in a waste of CPU time if the thread that must be run is of lower priority. The use of the SWITCH_OPTION_DEPRESS option in this situation is highly recommended.

thread_switch ignores policies. Users relying on the preemption semantics of a fixed time policy should be aware that thread_switch ignores these semantics; it will run the specified new_thread independent of its scheduling attributes and those of any threads that could run instead.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: thread_abort, thread_depress_abort. \ No newline at end of file diff --git a/osfmk/man/thread_terminate.html b/osfmk/man/thread_terminate.html new file mode 100755 index 000000000..6852997e0 --- /dev/null +++ b/osfmk/man/thread_terminate.html @@ -0,0 +1 @@ +

thread_terminate


Function - Destroy a thread.

SYNOPSIS

kern_return_t   thread_terminate
                (thread_act_t                     target_thread);

PARAMETERS

target_thread
[in thread send right] The thread to be destroyed.

DESCRIPTION

The thread_terminate function kills target_thread.

RETURN VALUES

Only generic errors apply.

RELATED INFORMATION

Functions: task_terminate, task_threads, thread_create, thread_resume, thread_suspend. \ No newline at end of file diff --git a/osfmk/man/thread_wire.html b/osfmk/man/thread_wire.html new file mode 100755 index 000000000..f52f7a984 --- /dev/null +++ b/osfmk/man/thread_wire.html @@ -0,0 +1 @@ +

thread_wire


Function - Mark the thread as privileged with respect to kernel resources.

SYNOPSIS

kern_return_t   thread_wire
                (host_priv_t                          host_priv,
                 thread_act_t                            thread,
                 boolean_t                                wired);

PARAMETERS

host_priv
[in host-control send right] The privileged control port for the host on which the thread executes.

thread
[in thread send right] The thread to be wired.

wired
[in scalar] TRUE if the thread is to be wired.

DESCRIPTION

The thread_wire function marks the thread as "wired". A "wired" thread is always eligible to be scheduled and can consume physical memory even when free memory is scarce. This property should be assigned to threads in the default page-out path. Threads not in the default page-out path should not have this property to prevent the kernel's free list of pages from being exhausted.

RETURN VALUES

KERN_INVALID_ARGUMENT
thread is not a thread port. .P host_priv is not the control port for the host on which thread executes.

RELATED INFORMATION

Functions: vm_wire. \ No newline at end of file diff --git a/osfmk/man/tvalspec.html b/osfmk/man/tvalspec.html new file mode 100755 index 000000000..cdb56a439 --- /dev/null +++ b/osfmk/man/tvalspec.html @@ -0,0 +1 @@ +

tvalspec


Structure - Defines format of system time values.

SYNOPSIS

struct tvalspec
{
       unsigned int       tv_sec;
       clock_res_t       tv_nsec;
};

typedef struct tvalspec tvalspec_t;

FIELDS

tv_sec
Seconds.

tv_nsec
Nanoseconds.

DESCRIPTION

The tvalspec structure defines the format of the time structure supplied to or returned from the kernel. This definition conforms to the Posix 1003.4 timespec definition where the tv_nsec structure member is valid if (0 =< tv_nsec < 109) and the time period described is ((tv_sec * 109) + tv_nsec) nanoseconds.

RELATED INFORMATION

Functions: clock_get_time, clock_set_time, clock_sleep, clock_alarm, clock_alarm_reply.

Data Structures: mapped_tvalspec. \ No newline at end of file diff --git a/osfmk/man/vm_allocate.html b/osfmk/man/vm_allocate.html new file mode 100755 index 000000000..dacfe2fd7 --- /dev/null +++ b/osfmk/man/vm_allocate.html @@ -0,0 +1 @@ +

vm_allocate


Function - Allocate a region of virtual memory.

SYNOPSIS

kern_return_t   vm_allocate
                (vm_task_t                          target_task,
                 vm_address_t                           address,
                 vm_size_t                                 size,
                 boolean_t                             anywhere);

PARAMETERS

target_task
[in task send right] The port for the task in whose address space the region is to be allocated.

address
[pointer to in/out scalar] The starting address for the region. If the region as specified by the given starting address and size would not lie within the task's un-allocated memory, the kernel does not allocate the region. If allocated, the kernel returns the starting address actually used for the allocated region.

size
[in scalar] The number of bytes to allocate.

anywhere
[in scalar] Placement indicator. The valid values are:

TRUE
The kernel allocates the region in the next unused space that is sufficient within the address space. The kernel returns the starting address actually used in address.

FALSE
The kernel allocates the region starting at address unless that space is already allocated.

DESCRIPTION

The vm_allocate function allocates a region of virtual memory in the specified task's address space. A new region is always zero filled.

If anywhere is TRUE, the returned address will be at a page boundary; otherwise, the region starts at the beginning of the virtual page containing address. size is always rounded up to an integral number of pages. Because of this rounding to virtual page boundaries, the amount of memory allocated may be greater than size. Use host_page_size to find the current virtual page size.

Initially, there are no access restrictions on any of the pages of the newly allocated region. Child tasks inherit the new region as a copy.

NOTES

To establish different protections or inheritance for the new region, use the vm_protect and vm_inherit functions.

A task's address space can contain both explicitly allocated memory and automatically allocated memory. The vm_allocate function explicitly allocates memory. The kernel automatically allocates memory to hold out-of-line data passed in a message (and received with mach_msg). The kernel allocates memory for the passed data as an integral number of pages.

This interface is machine word length dependent because of the virtual address parameter.

RETURN VALUES

KERN_INVALID_ADDRESS
The specified address is illegal or reserved.

KERN_NO_SPACE
There is not enough space in the task's address space to allocate the new region.

RELATED INFORMATION

Functions: vm_deallocate, vm_inherit, vm_protect, vm_region, host_page_size. \ No newline at end of file diff --git a/osfmk/man/vm_behavior_set.html b/osfmk/man/vm_behavior_set.html new file mode 100755 index 000000000..77087b889 --- /dev/null +++ b/osfmk/man/vm_behavior_set.html @@ -0,0 +1 @@ +

vm_behavior_set


Function - Specify expected access patterns for the target VM region.

SYNOPSIS

kern_return_t   vm_behavior_set
                (vm_task_t                          target_task,
                 vm_address_t                           address,
                 vm_size_t                                 size,
                 vm_behavior_t                         behavior);

PARAMETERS

target_task
[in task send right] The port for the task in whose address space the memory object behavior is to be set.

address
[in scalar] The starting address for the memory region.

size
[in scalar] The number of bytes in the region.

behavior
[in scalar] The expected reference pattern for the memory. Possible values are:

VM_BEHAVIOR_DEFAULT
The system's default behavior. Assumes strong locality of reference, so LRU page replacement, possibly with pre-fetch, would be appropriate.

VM_BEHAVIOR_RANDOM
No particular order expected. Assumes weak locality of reference, so LRU page replacement may be ineffective.

VM_BEHAVIOR_SEQUENTIAL
Forward sequential order.

VM_BEHAVIOR_RSEQNTL
Reverse sequential order.

DESCRIPTION

The vm_behavior_set function informs the kernel of the expected access pattern for a region of memory. The kernel uses this information to bias its prefetch and page replacement algorithms.

The region starts at the beginning of the virtual page containing address; it ends at the end of the virtual page containing address + size - 1. Because of this rounding to virtual page boundaries, the amount of memory affected may be greater than size. Use host_page_size to find the current virtual page size.

NOTES

This interface is machine word length specific because of the virtual address parameter.

RETURN VALUES

KERN_INVALID_ADDRESS
The specified address is illegal or reserved.

RELATED INFORMATION

Functions: vm_region, host_page_size. \ No newline at end of file diff --git a/osfmk/man/vm_copy.html b/osfmk/man/vm_copy.html new file mode 100755 index 000000000..21f579bed --- /dev/null +++ b/osfmk/man/vm_copy.html @@ -0,0 +1 @@ +

vm_copy


Function - Copy a region of virtual memory.

SYNOPSIS

kern_return_t   vm_copy
                (vm_task_t            target_task,
                 vm_address_t      source_address,
                 vm_size_t                  count,
                 vm_address_t        dest_address);

PARAMETERS

target_task
[in task send right] The port for the task whose memory is to be copied.

source_address
[in scalar] The starting address for the source region. The address must be on a page boundary.

count
[in scalar] The number of bytes in the source region. The number of bytes must convert to an integral number of virtual pages.

dest_address
[in scalar] The starting address for the destination region. The address must be on a page boundary.

DESCRIPTION

The vm_copy function copies a source region to a destination region within the same task's virtual memory. It is semantically equivalent to vm_read followed by vm_write. The destination region can overlap the source region.

The destination region must already be allocated. The source region must be readable, and the destination region must be writable.

NOTES

This interface is machine word length specific because of the virtual address parameter.

RETURN VALUES

KERN_PROTECTION_FAILURE
The source region is protected against reading, or the destination region is protected against writing.

KERN_INVALID_ADDRESS
An address is illegal or specifies a non-allocated region, or there is not enough memory following one of the addresses.

RELATED INFORMATION

Functions: vm_protect, vm_read, vm_write, host_page_size. \ No newline at end of file diff --git a/osfmk/man/vm_deallocate.html b/osfmk/man/vm_deallocate.html new file mode 100755 index 000000000..f7e6c3f2a --- /dev/null +++ b/osfmk/man/vm_deallocate.html @@ -0,0 +1 @@ +

vm_deallocate


Function - Deallocate a region of virtual memory.

SYNOPSIS

kern_return_t   vm_deallocate
                (vm_task_t                          target_task,
                 vm_address_t                           address,
                 vm_size_t                                 size);

PARAMETERS

target_task
[in task send right] The port for the task in whose address space the region is to be deallocated.

address
[in scalar] The starting address for the region.

size
[in scalar] The number of bytes to deallocate.

DESCRIPTION

The vm_deallocate function deallocates a region of virtual memory in the specified task's address space. The region starts at the beginning of the virtual page containing address and ends at the end of the virtual page containing address + size - 1. Because of this rounding to virtual page boundaries, the amount of memory deallocated may be greater than size. Use host_page_size to find the current virtual page size.

vm_deallocate affects only target_task. Other tasks that have access to the deallocated memory can continue to reference it.

NOTES

vm_deallocate can be used to deallocate memory passed as out-of-line data in a message.

This interface is machine word length specific because of the virtual address parameter.

RETURN VALUES

KERN_INVALID_ADDRESS
The address is illegal or specifies a non-allocated region.

RELATED INFORMATION

Functions: mach_msg, vm_allocate, vm_map, host_page_size. \ No newline at end of file diff --git a/osfmk/man/vm_inherit.html b/osfmk/man/vm_inherit.html new file mode 100755 index 000000000..a7546e0e6 --- /dev/null +++ b/osfmk/man/vm_inherit.html @@ -0,0 +1 @@ +

vm_inherit


Function - Set a VM region's inheritance attribute.

SYNOPSIS

kern_return_t   vm_inherit
                 (vm_task_t                   target_task,
                  vm_address_t                    address,
                  vm_size_t                          size,
                  vm_inherit_t            new_inheritance);

PARAMETERS

target_task
[in task send right] The port for the task whose address space contains the region.

address
[in scalar] The starting address for the region.

size
[in scalar] The number of bytes in the region.

new_inheritance
[in scalar] The new inheritance attribute for the region. Valid values are:

VM_INHERIT_SHARE
Allows child tasks to share the region.

VM_INHERIT_COPY
Gives child tasks a copy of the region.

VM_INHERIT_NONE
Provides no access to the region for child tasks.

DESCRIPTION

The vm_inherit function sets the inheritance attribute for a region within the specified task's address space. The inheritance attribute determines the type of access established for child tasks at task creation.

Because inheritance applies to virtual pages, the specified address and size are rounded to page boundaries, as follows: the region starts at the beginning of the virtual page containing address; it ends at the end of the virtual page containing address + size - 1. Because of this rounding to virtual page boundaries, the amount of memory affected may be greater than size. Use host_page_size to find the current virtual page size.

A parent and a child task can share the same physical memory only if the inheritance for the memory is set to VM_INHERIT_SHARE before the child task is created. Other than through the use of an external memory manager (see vm_map), this is the only way that two tasks can share memory.

Note that all the threads within a task share the task's memory.

NOTES

This interface is machine word length specific because of the virtual address parameter.

RETURN VALUES

KERN_INVALID_ADDRESS
The address is illegal or specifies a non-allocated region.

RELATED INFORMATION

Functions: task_create, vm_map, vm_region, norma_task_create. \ No newline at end of file diff --git a/osfmk/man/vm_machine_attribute.html b/osfmk/man/vm_machine_attribute.html new file mode 100755 index 000000000..d12ff4331 --- /dev/null +++ b/osfmk/man/vm_machine_attribute.html @@ -0,0 +1 @@ +

vm_machine_attribute


Function - Get/set the target memory region's special attributes.

SYNOPSIS

kern_return_t   vm_machine_attribute
                (vm_task_t                          target_task,
                 vm_address_t                           address,
                 vm_size_t                                 size,
                 vm_machine_attribute_t               attribute,
                 vm_machine_attribute_val_t               value);

PARAMETERS

target_task
[in task send right] The port for the task in whose address space the memory object is to be manipulated.

address
[in scalar] The starting address for the memory region. The granularity of rounding of this value to page boundaries is implementation dependent.

size
[in scalar] The number of bytes in the region. The granularity of rounding of this value to page boundaries is implementation dependent.

attribute
[in scalar] The name of the attribute to be get/set. Possible values are:

MATTR_CACHE
Cachability. Aside from the generic values listed below, the following special values are defined:

MATTR_VAL_CACHE_FLUSH
Flush from all caches

MATTR_VAL_DCACHE_FLUSH
Flush from data caches

MATTR_VAL_ICACHE_FLUSH
Flush from instruction caches

MATTR_MIGRATE
Migratability.

MATTR_REPLICATE
Replicability.

value
[pointer to in/out scalar] The new value for the attribute. The old value is also returned in this variable. The new value can be a specific value listed above, or one of the following generic values:

MATTR_VAL_OFF
Turn attribute off.

MATTR_VAL_ON
Turn attribute on.

MATTR_VAL_GET
No change, just return current value.

DESCRIPTION

The vm_machine_attribute function gets and sets special attributes of the memory region implemented by the underlying pmap module. These attributes are properties such as cachability, migratability and replicability. The behavior of this function is machine dependent.

NOTES

This interface is machine word length specific because of the virtual address parameter.

RETURN VALUES

KERN_INVALID_ADDRESS
The address is illegal or specifies a non-allocated region.

RELATED INFORMATION

Functions: vm_wire. \ No newline at end of file diff --git a/osfmk/man/vm_map.html b/osfmk/man/vm_map.html new file mode 100755 index 000000000..ce59762cd --- /dev/null +++ b/osfmk/man/vm_map.html @@ -0,0 +1 @@ +

vm_map


Function - Map the specified memory object to a region of virtual memory.

SYNOPSIS

kern_return_t   vm_map
                (vm_task_t                          target_task,
                 vm_address_t                           address,
                 vm_size_t                                 size,
                 vm_address_t                              mask,
                 boolean_t                             anywhere,
                 memory_object_t                  memory_object,
                 vm_offset_t                             offset,
                 boolean_t                                 copy,
                 vm_prot_t                       cur_protection,
                 vm_prot_t                       max_protection,
                 vm_inherit_t                       inheritance);

PARAMETERS

target_task
[in task send right] The port for the task in whose address space the memory object is to be mapped.

address
[pointer to in/out scalar] The starting address for the mapped object. The mapped object will start at the beginning of the page containing address. If there is not enough room following the address, the kernel does not map the object. The kernel returns the starting address actually used for the mapped object.

size
[in scalar] The number of bytes to allocate for the object. The kernel rounds this number up to an integral number of virtual pages.

mask
[in scalar] Alignment restrictions for starting address. Bits turned on in the mask will not be turned on in the starting address.

anywhere
[in scalar] Placement indicator. The valid values are:

TRUE
The kernel allocates the region in the next unused space that is sufficient within the address space. The kernel returns the starting address actually used in address.

FALSE
The kernel allocates the region starting at address unless that space is already allocated.

memory_object
[in memory-object send right] The port naming the memory object. If MEMORY_OBJECT_NULL is specified, the kernel allocates zero-filled memory, as with vm_allocate.

offset
[in scalar] An offset within the memory object, in bytes. The kernel maps address to the specified offset.

copy
[in scalar] Copy indicator. If true, the kernel copies the region of the memory object to the specified task's address space. If false, the region is directly mapped.

cur_protection
[in scalar] The initial current protection for the region. Valid values are obtained by or'ing together the following values:

VM_PROT_READ
Allows read access.

VM_PROT_WRITE
Allows write access.

VM_PROT_EXECUTE
Allows execute access.

max_protection
[in scalar] The maximum protection for the region. Values are the same as for cur_protection.

inheritance
[in scalar] The initial inheritance attribute for the region. Valid values are:

VM_INHERIT_SHARE
Allows child tasks to share the region.

VM_INHERIT_COPY
Gives child tasks a copy of the region.

VM_INHERIT_NONE
Provides no access to the region for child tasks.

DESCRIPTION

The vm_map function maps a portion of the specified memory object into the virtual address space belonging to target_task. The target task can be the calling task or another task, identified by its task kernel port.

The portion of the memory object mapped is determined by offset and size. The kernel maps address to the offset, so that an access to the memory starts at the offset in the object.

The mask parameter specifies additional alignment restrictions on the kernel's selection of the starting address. Uses for this mask include:

  • Forcing the memory address alignment for a mapping to be the same as the alignment within the memory object.
  • Quickly finding the beginning of an allocated region by performing bit arithmetic on an address known to be in the region.
  • Emulating a larger virtual page size.

The cur_protection, max_protection, and inheritance parameters set the protection and inheritance attributes for the mapped object. As a rule, at least the maximum protection should be specified so that a server can make a restricted (for example, read-only) mapping in a client atomically. The current protection and inheritance parameters are provided for convenience so that the caller does not have to call vm_inherit and vm_protect separately.

The same memory object can be mapped more than once and by more than one task. If an object is mapped by multiple tasks, the kernel maintains consistency for all the mappings if they use the same page alignment for offset and are on the same host. In this case, the virtual memory to which the object is mapped is shared by all the tasks. Changes made by one task in its address space are visible to all the other tasks. The call will not return until the memory object is ready for use.

NOTES

vm_map allocates a region in a task's address space and maps the specified memory object to this region. vm_allocate allocates a zero-filled temporary region in a task's address space.

Before a memory object can be mapped, a port naming it must be acquired from the memory manager serving it.

This interface is machine word length specific because of the virtual address parameter.

CAUTIONS

Do not attempt to map a memory object unless it has been provided by a memory manager that implements the memory object interface. If another type of port is specified, a thread that accesses the mapped virtual memory may become permanently hung or may receive a memory exception.

RETURN VALUES

KERN_NO_SPACE
There is not enough space in the task's address space to allocate the new region for the memory object.

KERN_PROTECTION_FAILURE
max_protection or cur_protection exceeds that permitted by memory_object.

KERN_INVALID_OBJECT
The memory manager failed to map the memory object.

RELATED INFORMATION

Functions: vm_allocate, vm_remap. \ No newline at end of file diff --git a/osfmk/man/vm_msync.html b/osfmk/man/vm_msync.html new file mode 100755 index 000000000..e3d0fd6d1 --- /dev/null +++ b/osfmk/man/vm_msync.html @@ -0,0 +1 @@ +

vm_msync


Function - Synchronize the specified region of virtual memory.

SYNOPSIS

kern_return_t   vm_msync
                (vm_task_t                          target_task,
                 vm_address_t                           address,
                 vm_size_t                                 size,
                 target_task                         sync_flags);

PARAMETERS

target_task
[in task send right] The port for the task whose address space contains the region.

address
[in scalar] The starting address for the region.

size
[in scalar] The number of bytes in the region.

sync_flags
[in scalar] The bit-wise OR of flags affecting the synchronization. Specifying both VM_SYNC_SYNCHRONOUS and VM_SYNC_ASYNCHRONOUS is invalid.

VM_SYNC_INVALIDATE
Flushes pages in the range. Only precious pages are returned to the memory manager unless either VM_SYNC_SYNCHRONOUS or VM_SYNC_ASYNCHRONOUS is also set.

VM_SYNC_SYNCHRONOUS
Writes dirty and precious pages back to the memory manager, waits for pages to reach backing storage.

VM_SYNC_ASYNCHRONOUS
Writes dirty and precious pages back to the memory manager, returns without waiting for pages to reach backing storage.

DESCRIPTION

The vm_msync function synchronizes the contents of a memory range with its backing store image by flushing or cleaning the contents of the specified range to the range's memory manager, engaging in a synchronization protocol with the manager (memory_object_synchronize). The client does not return from this call until the memory manager responds (to the kernel) with memory_object_synchronize_completed.

NOTES

This interface is machine word length specific because of the virtual address parameter.

RETURN VALUES

KERN_INVALID_ADDRESS
The address is illegal or specifies a non-allocated region.

RELATED INFORMATION

Functions: memory_object_synchronize, memory_object_synchronize_completed. \ No newline at end of file diff --git a/osfmk/man/vm_protect.html b/osfmk/man/vm_protect.html new file mode 100755 index 000000000..af0327ecf --- /dev/null +++ b/osfmk/man/vm_protect.html @@ -0,0 +1 @@ +

vm_protect


Function - Set access privilege attribute for a region of virtual memory.

SYNOPSIS

kern_return_t   vm_protect
                 (vm_task_t           target_task,
                  vm_address_t            address,
                  vm_size_t                  size,
                  boolean_t           set_maximum,
                  vm_prot_t        new_protection);

PARAMETERS

target_task
[in task send right] The port for the task whose address space contains the region.

address
[in scalar] The starting address for the region.

size
[in scalar] The number of bytes in the region.

set_maximum
[in scalar] Maximum/current indicator. If true, the new protection sets the maximum protection for the region. If false, the new protection sets the current protection for the region. If the maximum protection is set below the current protection, the current protection is also reset to the new maximum.

new_protection
[in scalar] The new protection for the region. Valid values are obtained by or'ing together the following values:

VM_PROT_READ
Allows read access.

VM_PROT_WRITE
Allows write access.

VM_PROT_EXECUTE
Allows execute access.

DESCRIPTION

The vm_protect function sets access privileges for a region within the specified task's address space. The new_protection parameter specifies a combination of read, write, and execute accesses that are allowed (rather than prohibited).

The region starts at the beginning of the virtual page containing address; it ends at the end of the virtual page containing address + size - 1. Because of this rounding to virtual page boundaries, the amount of memory protected may be greater than size. Use host_page_size to find the current virtual page size.

The enforcement of virtual memory protection is machine-dependent. Nominally read access requires VM_PROT_READ permission, write access requires VM_PROT_WRITE permission, and execute access requires VM_PROT_EXECUTE permission. However, some combinations of access rights may not be supported. In particular, the kernel interface allows write access to require VM_PROT_READ and VM_PROT_WRITE permission and execute access to require VM_PROT_READ permission.

NOTES

This interface is machine word length specific because of the virtual address parameter.

RETURN VALUES

KERN_PROTECTION_FAILURE
The new protection increased the current or maximum protection beyond the existing maximum protection.

KERN_INVALID_ADDRESS
The address is illegal or specifies a non-allocated region.

RELATED INFORMATION

Functions: host_page_size, vm_inherit, vm_region. \ No newline at end of file diff --git a/osfmk/man/vm_read.html b/osfmk/man/vm_read.html new file mode 100755 index 000000000..008f43ac6 --- /dev/null +++ b/osfmk/man/vm_read.html @@ -0,0 +1 @@ +

vm_read


Function - Read the specified range of target task's address space.

SYNOPSIS

kern_return_t   vm_read
                (vm_task_t                          target_task,
                 vm_address_t                           address,
                 vm_size_t                                 size,
                 size                                  data_out,
                 target_task                         data_count);

Overwrite form:

kern_return_t   vm_read_overwrite
                (vm_task_t                          target_task,
                 vm_address_t                           address,
                 vm_size_t                                 size,
                 pointer_t                              data_in,
                 target_task                         data_count);

PARAMETERS

target_task
[in task send right] The port for the task whose memory is to be read.

address
[in scalar] The address at which to start the read.

size
[in scalar] The number of bytes to read.

data_out
Out-pointer to dynamic array of bytes returned by the read.

data_in
In-pointer to array of bytes that will be overwritten with the data returned by the read.

data_count
[in/out scalar] On input, the maximum size of the buffer; on output, the size returned (in natural-sized units).

DESCRIPTION

The vm_read and vm_read_overwrite functions read a portion of a task's virtual memory (they enable tasks to read other tasks' memory). The vm_read function returns the data in a dynamically allocated array of bytes; the vm_read_overwrite function places the data into a caller-specified buffer (the data_in parameter).

NOTES

This interface is machine word length specific because of the virtual address parameter.

RETURN VALUES

KERN_PROTECTION_FAILURE
Specified memory is valid, but does not permit reading.

KERN_INVALID_ADDRESS
The address is illegal or specifies a non-allocated region, or there are less than size bytes of data following the address, or the region specified by the data_in parameter cannot be written to.

RELATED INFORMATION

Functions: vm_copy, vm_deallocate, vm_write. \ No newline at end of file diff --git a/osfmk/man/vm_region.html b/osfmk/man/vm_region.html new file mode 100755 index 000000000..c36fd60f1 --- /dev/null +++ b/osfmk/man/vm_region.html @@ -0,0 +1 @@ +

vm_region


Function - Return description of a virtual memory region.

SYNOPSIS

kern_return_t   vm_region
                 (vm_task_t                    target_task,
                  vm_address_t                     address,
                  vm_size_t                           size,
                  vm_region_flavor_t                flavor,
                  vm_region_info_t                    info,
                  mach_msg_type_number_t        info_count,
                  memory_object_name_t         object_name);

PARAMETERS

target_task
[in task send right] The port for the task whose address space contains the region.

address
[pointer to in/out scalar] The address at which to start looking for a region. The function returns the starting address actually used.

size
[out scalar] The number of bytes in the located region. The number converts to an integral number of virtual pages.

flavor
[in scalar] The type of information to be returned. Valid values are:

VM_REGION_BASIC_INFO
Basic information about the region (size, inheritance, etc.). This information is declared by the vm_region_basic_info structure.

info
[out structure] Returned region information.

info_count
[in/out scalar] On input, the maximum size of the buffer; on output, the size returned (in natural-sized units).

object_name
This parameter is no longer used.

DESCRIPTION

The vm_region function returns information on a region within the specified task's address space. The function begins looking at address and continues until it finds an allocated region. If the input address is within a region, the function uses the start of that region. The starting address for the located region is returned in address.

NOTES

This interface is machine word length specific because of the virtual address parameter.

RETURN VALUES

KERN_INVALID_ADDRESS
There is no region at or beyond the specified starting address.

RELATED INFORMATION

Functions: vm_allocate, vm_deallocate, vm_inherit, vm_protect, vm_behavior_set.

Data Structures: vm_region_basic_info. \ No newline at end of file diff --git a/osfmk/man/vm_region_basic_info.html b/osfmk/man/vm_region_basic_info.html new file mode 100755 index 000000000..85fcd3058 --- /dev/null +++ b/osfmk/man/vm_region_basic_info.html @@ -0,0 +1 @@ +

vm_region_basic_info


Structure - Defines the attributes of a task's memory region.

SYNOPSIS

struct vm_region_basic_info
{
       vm_prot_t             protection;
       vm_prot_t         max_protection;
       vm_inherit_t         inheritance;
       boolean_t                 shared;
       boolean_t               reserved;
       vm_offset_t               offset;
       vm_behavior_t           behavior;
       unsigned short  user_wired_count;
};

typedef struct vm_region_basic_info* vm_region_basic_info_t;

FIELDS

protection
The current protection for the region.

max_protection
The maximum protection allowed for the region.

inheritance
The inheritance attribute for the region.

shared
Shared indicator. If true, the region is shared by another task. If false, the region is not shared.

reserved
If true the region is protected from random allocation.

offset
The region's offset into the memory object. The region begins at this offset.

behavior
Expected reference pattern for the memory. Valid values are:

VM_BEHAVIOR_DEFAULT
The system's default behavior.

VM_BEHAVIOR_RANDOM
No particular order expected.

VM_BEHAVIOR_SEQUENTIAL
Forward sequential order.

VM_BEHAVIOR_RSEQNTL
Reverse sequential order.

DESCRIPTION

The vm_region_basic_info structure defines the attributes of a memory region returned by vm_region.

RELATED INFORMATION

Functions: vm_region, vm_inherit, vm_protect. \ No newline at end of file diff --git a/osfmk/man/vm_remap.html b/osfmk/man/vm_remap.html new file mode 100755 index 000000000..000f17103 --- /dev/null +++ b/osfmk/man/vm_remap.html @@ -0,0 +1 @@ +

vm_remap


Function - Map memory objects in one task's address space to that of another task's.

SYNOPSIS

kern_return_t   vm_remap
                 (mach_port_t	           target_task,
                  vm_address_t	        target_address,
                  vm_size_t	                  size,
                  vm_address_t	                  mask,
                  boolean_t	              anywhere,
                  mach_port_t	           source_task,
                  vm_address_t	        source_address,
                  boolean_t	                  copy,
                  vm_prot_t	        cur_protection,
                  vm_prot_t	        max_protection,
                  vm_inherit_t            inheritance);

PARAMETERS

target_task
[in task send right] The port for the task in whose address space the memory is to be mapped.

target_address
[pointer to in/out scalar] The starting address for the mapped memory in the target task. The mapped memory will start at the beginning of the page containing target_address. If there is not enough room following the address, the kernel does not map the memory. The kernel returns the starting address actually used for the mapped memory.

size
[in scalar] The number of bytes to map. The kernel rounds this number up to an integral number of virtual pages.

mask
[in scalar] Alignment restrictions for starting address. Bits turned on in the mask will not be turned on in the starting address.

anywhere
[in scalar] Placement indicator. The valid values are:

TRUE
The kernel allocates the region in the next unused space that is sufficient within the address space. The kernel returns the starting address actually used in address.

FALSE
The kernel allocates the region starting at address unless that space is already allocated.

source_task
[in task send right] The port for the task whose address space is to be mapped.

source_address
[in scalar] The starting address for the memory to be mapped from the source task. The memory to be mapped will start at the beginning of the page containing source_address. If not enough memory exists following the address, the kernel does not map the memory.

copy
[in scalar] Copy indicator. If true, the kernel copies the region for the memory to the specified task's address space. If false, the region is mapped read-write.

cur_protection
[out scalar] The most restrictive current protection for the memory in the region. Valid values are obtained by or'ing together the following values:

VM_PROT_READ
Allows read access.

VM_PROT_WRITE
Allows write access.

VM_PROT_EXECUTE
Allows execute access.

max_protection
[out scalar] The most restrictive maximum protection for the memory in the region. Values are the same as for cur_protection.

inheritance
[in scalar] The initial inheritance attribute for the region. Valid values are:

VM_INHERIT_SHARE
Allows child tasks to share the region.

VM_INHERIT_COPY
Gives child tasks a copy of the region.

VM_INHERIT_NONE
Provides no access to the region for child tasks.

DESCRIPTION

The vm_remap function maps the memory objects underlying a portion of the specified source_task's virtual address space into the address space belonging to target_task. The target task can be the calling task or another task, identified by its task kernel port. The effect is as if the target task performed a vm_map call given the same memory object, maximum protection, current protection, and inheritance as the source task. However, the two tasks must reside on the same host. The kernel maps the memory objects starting at target_address, so that access to target_address is as if the source task accessed its source_address.

The mask parameter specifies additional alignment restrictions on the kernel's selection of the starting address. Uses for this mask include:

  • Forcing the memory address alignment for a mapping to be the same as the alignment within the source task.
  • Quickly finding the beginning of an allocated region by performing bit arithmetic on an address known to be in the region.
  • Emulating a larger virtual page size.
The cur_protection and max_protection parameters return the protection attributes for the mapped memory. If all memory within the range had the same attributes, these attributes are returned; otherwise the call returns the most restrictive values for any memory in the region.

NOTES

This interface is machine word length specific because of the virtual address parameter.

RETURN VALUES

KERN_NO_SPACE
There is not enough space in the task's address space to allocate the new region for the memory object.

KERN_PROTECTION_FAILURE
Specified memory is valid, but the backing memory manager is not permitted by the requesting task.

RELATED INFORMATION

Functions: vm_map, vm_read, vm_write. \ No newline at end of file diff --git a/osfmk/man/vm_statistics.html b/osfmk/man/vm_statistics.html new file mode 100755 index 000000000..cc72acccf --- /dev/null +++ b/osfmk/man/vm_statistics.html @@ -0,0 +1 @@ +

vm_statistics


Structure - Defines statistics for the kernel's use of virtual memory.

SYNOPSIS

struct vm_statistics
{
       integer_t       free_count;
       integer_t       active_count;
       integer_t       inactive_count;
       integer_t       wire_count;
       integer_t       zero_fill_count;
       integer_t       reactivations;
       integer_t       pageins;
       integer_t       pageouts;
       integer_t       faults;
       integer_t       cow_faults;
       integer_t       lookups;
       integer_t       hits;
};

typedef struct vm_statistics* vm_statistics_t;

FIELDS

free_count
The total number of free pages in the system.

active_count
The total number of pages currently in use and pageable.

inactive_count
The number of inactive pages.

wire_count
The number of pages that are wired in memory and cannot be paged out.

zero_fill_count
The number of zero-fill pages.

reactivations
The number of reactivated pages.

pageins
The number of requests for pages from a pager (such as the i-node pager).

pageouts
The number of pages that have been paged out.

faults
The number of times the vm_fault routine has been called.

cow_faults
The number of copy-on-write faults.

lookups
The number of object cache lookups.

hits
The number of object cache hits.

DESCRIPTION

The vm_statistics structure defines the statistics available on the kernel's use of virtual memory. The statistics record virtual memory usage since the kernel was booted.

For related information for a specific task, see the task_basic_info structure.

NOTES

This structure is machine word length specific because of the memory sizes returned.

RELATED INFORMATION

Functions: task_info, host_page_size.

Data Structures: task_basic_info. \ No newline at end of file diff --git a/osfmk/man/vm_wire.html b/osfmk/man/vm_wire.html new file mode 100755 index 000000000..5a4e25952 --- /dev/null +++ b/osfmk/man/vm_wire.html @@ -0,0 +1 @@ +

vm_wire


Function - Modify the target region's paging characteristics.

SYNOPSIS

kern_return_t   vm_wire
                (host_priv_t                               host,
                 vm_task_t                          target_task,
                 vm_address_t                           address,
                 vm_size_t                                 size,
                 vm_prot_t                         wired_access);

PARAMETERS

host
[in host-control send right] The control port for the host for which information is to be obtained.

target_task
[in task send right] The port for the task whose address space contains the region.

address
[in scalar] The starting address for the region.

size
[in scalar] The number of bytes in the region.

wired_access
[in scalar] The pageability of the region. The following values cause the region to be wired and protected as specified (values may be combined):
VM_PROT_READ
VM_PROT_WRITE
VM_PROT_execute

The following value causes the region to be unwired (made pageable):

VM_PROT_NONE

DESCRIPTION

The vm_wire function sets the pageability privileges for a region within the specified task's address space. wired_access specifies the types of accesses to the memory region which must not suffer from (internal) faults of any kind after this call returns. A non-null wired_access value indicates that the page is to be "wired" into memory; a null value indicates "un-wiring". The kernel maintains for the region a count of the number of times the region is wired. A page is wired into physical memory if any task accessing it has a non-zero wired count for the page.

The region starts at the beginning of the virtual page containing address; it ends at the end of the virtual page containing address + size - 1. Because of this rounding to virtual page boundaries, the amount of memory affected may be greater than size. Use host_page_size to find the current virtual page size.

NOTES

This interface is machine word length specific because of the virtual address parameter.

RETURN VALUES

KERN_INVALID_ADDRESS
The address is illegal or specifies a non-allocated region.

RELATED INFORMATION

Functions: thread_wire. \ No newline at end of file diff --git a/osfmk/man/vm_write.html b/osfmk/man/vm_write.html new file mode 100755 index 000000000..6fe7f28e8 --- /dev/null +++ b/osfmk/man/vm_write.html @@ -0,0 +1 @@ +

vm_write


Function - Write data to the specified address in the target task's address space.

SYNOPSIS

kern_return_t   vm_write
                (vm_task_t                          target_task,
                 vm_address_t                           address,
                 pointer_t                                 data,
                 mach_msg_type_number_t              data_count);

PARAMETERS

target_task
[in task send right] The port for the task whose memory is to be written.

address
[in scalar] The address at which to start the write.

data
[pointer to page aligned in array of bytes] An array of data to be written.

data_count
[in scalar] The number of bytes in the array.

DESCRIPTION

The vm_write function writes an array of data to a task's virtual memory. It allows one task to write to another task's memory.

The result of vm_write is as if target_task had directly written into the set of pages. Hence, target_task must have write permission to the pages.

NOTES

This interface is machine word length specific because of the virtual address parameter.

RETURN VALUES

KERN_PROTECTION_FAILURE
Specified memory is valid, but does not permit writing.

KERN_INVALID_ADDRESS
The address is illegal or specifies a non-allocated region.

RELATED INFORMATION

Functions: vm_copy, vm_protect, vm_read, host_page_size. \ No newline at end of file diff --git a/osfmk/ppc/AltiAssist.s b/osfmk/ppc/AltiAssist.s index 40adf070a..5d194389b 100644 --- a/osfmk/ppc/AltiAssist.s +++ b/osfmk/ppc/AltiAssist.s @@ -36,6 +36,8 @@ #include #include +#define kernAccess 31 + ; ; ; General stuff what happens here: diff --git a/osfmk/ppc/Diagnostics.c b/osfmk/ppc/Diagnostics.c index 454b878bc..ffa7e0f64 100644 --- a/osfmk/ppc/Diagnostics.c +++ b/osfmk/ppc/Diagnostics.c @@ -60,9 +60,13 @@ #include #include #include +#include extern struct vc_info vinfo; +kern_return_t testPerfTrap(int trapno, struct savearea *ss, + unsigned int dsisr, unsigned int dar); + int diagCall(struct savearea *save) { union { @@ -72,7 +76,7 @@ int diagCall(struct savearea *save) { natural_t tbu, tbu2, tbl; struct per_proc_info *per_proc; /* Area for my per_proc address */ int cpu; - unsigned int tstrt, tend; + unsigned int tstrt, tend, temp, temp2; if(!(dgWork.dgFlags & enaDiagSCs)) return 0; /* If not enabled, cause an exception */ @@ -153,7 +157,7 @@ int diagCall(struct savearea *save) { /* * Force cache flush */ - case dgflush: + case dgFlush: #if 1 cacheInit(); /* Blow cache */ @@ -172,7 +176,8 @@ int diagCall(struct savearea *save) { */ case dgtest: - pmap_remove(kernel_pmap, save->save_r4, save->save_r4 + 4096); + if(save->save_r4) perfTrapHook = testPerfTrap; + else perfTrapHook = 0; return 1; /* Return and check for ASTs... */ @@ -200,6 +205,35 @@ int diagCall(struct savearea *save) { (void)mapping_remove(current_act()->map->pmap, save->save_r4); /* Remove mapping */ return 1; /* Return and check for ASTs... */ + + +/* + * Allows direct control of alignment handling. + * + * The bottom two bits of the parameter are used to set the two control bits: + * 0b00 - !trapUnalignbit - !notifyUnalignbit - default - instruction is emulated + * 0b01 - !trapUnalignbit - notifyUnalignbit - emulation is done, but traps afterwards + * 0b10 - trapUnalignbit - !notifyUnalignbit - no emulation - causes exception + * 0b11 - trapUnalignbit - notifyUnalignbit - no emulation - causes exception + */ + case dgAlign: + + temp = current_act()->mact.specFlags; /* Save the old values */ + + temp = ((current_act()->mact.specFlags >> (31 - trapUnalignbit - 1)) /* Reformat them to pass back */ + | (current_act()->mact.specFlags >> (31 - notifyUnalignbit))) & 3; + + temp2 = ((save->save_r4 << (31 - trapUnalignbit - 1)) & trapUnalign) /* Move parms into flag format */ + | ((save->save_r4 << (31 - notifyUnalignbit)) & notifyUnalign); + + current_act()->mact.specFlags &= ~(trapUnalign | notifyUnalign); /* Clean the old ones */ + current_act()->mact.specFlags |= temp2; /* Set the new ones */ + + per_proc_info[cpu_number()].spcFlags = current_act()->mact.specFlags; + + save->save_r3 = temp; + + return 1; /* Return and check for ASTs... */ /* * Return info for boot screen @@ -217,6 +251,18 @@ int diagCall(struct savearea *save) { default: /* Handle invalid ones */ return 0; /* Return an exception */ - }; + } + +}; + +kern_return_t testPerfTrap(int trapno, struct savearea *ss, + unsigned int dsisr, unsigned int dar) { + + if(trapno != T_ALIGNMENT) return KERN_FAILURE; + + kprintf("alignment exception at %08X, srr1 = %08X, dsisr = %08X, dar = %08X\n", ss->save_srr0, + ss->save_srr1, dsisr, dar); + + return KERN_SUCCESS; } diff --git a/osfmk/ppc/Diagnostics.h b/osfmk/ppc/Diagnostics.h index 4c344be85..6837f338f 100644 --- a/osfmk/ppc/Diagnostics.h +++ b/osfmk/ppc/Diagnostics.h @@ -50,7 +50,8 @@ int diagCall(struct savearea *save); #define dgBMphys 5 #define dgUnMap 6 #define dgBootScreen 7 -#define dgflush 8 +#define dgFlush 8 +#define dgAlign 9 typedef struct diagWork { /* Diagnostic work area */ @@ -67,6 +68,8 @@ typedef struct diagWork { /* Diagnostic work area */ #define enaDiagSCsb 28 #define enaDiagDM 0x00000010 #define enaDiagSDMb 27 +#define enaDiagEM 0x00000020 +#define enaDiagEMb 26 /* Suppress lock checks */ #define disLkType 0x80000000 #define disLktypeb 0 diff --git a/osfmk/ppc/Emulate.s b/osfmk/ppc/Emulate.s index 813b689d5..419b24747 100644 --- a/osfmk/ppc/Emulate.s +++ b/osfmk/ppc/Emulate.s @@ -36,6 +36,9 @@ #include #include +#define kernAccess 31 +#define traceInst 30 +#define dssAllDone 29 ; General stuff what happens here: ; 1) All general context saved, interrupts off, translation off @@ -61,5 +64,1514 @@ LEXT(Emulate) + + mfsprg r31,0 ; Get the per_proc + lis r30,hi16(EXT(dgWork)) ; Get the high half of diagnostic work area + lwz r12,savesrr1(r13) ; Get the exception info + ori r30,r30,lo16(EXT(dgWork)) ; And the low half + rlwinm. r0,r12,0,SRR1_PRG_ILL_INS_BIT,SRR1_PRG_ILL_INS_BIT ; Emulation candidate? + lwz r30,dgFlags(r30) ; Get the flags + beq+ eExit ; Nope, do not try to emulate... + + rlwinm. r0,r30,0,enaDiagEMb,enaDiagEMb ; Do we want to try to emulate something? + mfsprg r28,2 ; Get the processor features + beq+ eExit ; No emulation allowed... + + rlwinm. r28,r28,0,pfAltivecb,pfAltivecb ; Do we have Altivec on this machine? + beq eNoVect ; Nope, no Altivec... + + dssall ; We need to kill streams because we are going to flip to problem state + sync + +eNoVect: bl eIFetch ; Get the instruction image + bne- eRedriveAsISI ; Go redrive this as an ISI... + + rlwinm. r0,r10,0,0,5 ; See if we have the "special" op code here + rlwinm r20,r10,16,22,31 ; Set rS/rD and rA + bne+ eExit ; Not special op, ignore... + + rlwinm r0,r10,31,22,31 ; Extract the sub op code + crclr cr1_eq ; Clear + rlwimi r20,r10,14,15,16 ; Move bits 29 and 30 of instruction to 15 and 16 of DSISR + cmplwi r0,790 ; lhbrx? + rlwimi r20,r10,8,17,17 ; Move bit 25 to bit 17 + cror cr1_eq,cr1_eq,cr0_eq ; Remember + cmplwi r0,534 ; lwbrx? + rlwimi r20,r10,3,18,21 ; Move bit 21-24 to bit 18-21 + cror cr1_eq,cr1_eq,cr0_eq ; Remember + cmplwi r0,918 ; sthbrx? + cror cr1_eq,cr1_eq,cr0_eq ; Remember + cmplwi r0,662 ; stwbrx? + cror cr1_eq,cr1_eq,cr0_eq ; Remember + cmplwi r0,1014 ; dcbz? + cror cr1_eq,cr1_eq,cr0_eq ; Remember + cmplwi r0,533 ; lswx? + cror cr1_eq,cr1_eq,cr0_eq ; Remember + cmplwi r0,661 ; stswx? + cror cr1_eq,cr1_eq,cr0_eq ; Remember + bne cr1_eq,eNotIndex ; Go check non-index forms... + + rlwinm. r21,r10,18,25,29 ; Extract index to rA to build EA + rlwinm r22,r10,23,25,29 ; Extract index to rB + addi r24,r13,saver0 ; Point to the start of registers + li r19,0 ; Assume 0 base + beq eZeroBase ; Yes... + lwzx r19,r24,r21 ; Get the base register value + +eZeroBase: lwzx r22,r24,r22 ; Get the index value + add r22,r22,r19 ; Get DAR + b eFinishUp ; Done, go finish up... + +eNotIndex: cmplwi r0,725 ; stswi? + cror cr1_eq,cr1_eq,cr0_eq ; Remember + cmplwi r0,597 ; lswi? + cror cr1_eq,cr1_eq,cr0_eq ; Remember + bne cr1,eExit ; Not one we handle... + + rlwinm. r21,r10,18,25,29 ; Extract index to rA to build EA + addi r24,r13,saver0 ; Point to the start of registers + li r22,0 ; Assume 0 base + beq eFinishUp ; Yes, it is... + lwzx r22,r24,r21 ; Get the base register value + +eFinishUp: stw r20,savedsisr(r13) ; Set the DSISR + li r11,T_ALIGNMENT ; Get the exception code + stw r22,savedar(r13) ; Save the DAR + stw r11,saveexception(r13) ; Set the exception code + b EXT(AlignAssist) ; Go emulate the handler... + + +eExit: b EXT(EmulExit) ; Just return for now... + + +; +; Fetch the failing instruction. +; Image returned in R10 if CR0_EQ is false, otherwise, an ISI should be generated/ +; The cr bit kernAccess is set if this was a kernel access. +; R1 has the DSISR if access failed. +; + + .align 5 + +eIFetch: lwz r23,savesrr1(r13) ; Get old MSR + mflr r28 ; Save return + + rlwinm. r22,r23,0,MSR_PR_BIT,MSR_PR_BIT ; Within kernel? + + mfmsr r30 ; Save the MSR for now + lwz r23,savesrr0(r13) ; Get instruction address + crmove kernAccess,cr0_eq ; Remember if fault was in kernel + li r25,4 ; Set access length + or r22,r22,r30 ; Add PR to access MSR + + bfl+ kernAccess,aaSetSegs ; Go set SRs if we are in user and need to + + ori r22,r22,lo16(MASK(MSR_DR)|MASK(MSR_RI)) ; Set RI onto access MSR + + crset cr0_eq ; Set this to see if we failed + mtmsr r22 ; Flip DR, RI, and maybe PR on + isync + + lwz r10,0(r23) ; Fetch the instruction + + crmove 28,cr0_eq ; Remember if we failed + li r0,loadMSR ; Set the magic "get back to supervisor" SC + mr r3,r30 ; Get MSR to load + sc ; Get back to supervisor state + + bfl+ kernAccess,aaUnSetSegs ; Go set SRs if we are in user and need to + + mtlr r28 ; Restore the LR + crmove cr0_eq,28 ; Set CR0_EQ if the fetch succeeded + blr ; Return with instruction image in R10 + + +; +; Redrive as an ISI +; + +eRedriveAsISI: + lwz r6,savesrr1(r13) ; Get the srr1 value + lwz r4,SAVflags(r13) ; Pick up the flags + li r11,T_INSTRUCTION_ACCESS ; Set failing instruction fetch code + rlwimi r6,r1,0,0,4 ; Move the DSISR bits to the SRR1 + oris r4,r4,hi16(SAVredrive) ; Set the redrive bit + stw r11,saveexception(r13) ; Set the replacement code + stw r4,SAVflags(r13) ; Set redrive request + stw r6,savesrr1(r13) ; Set the srr1 value + b EXT(EmulExit) ; Bail out to handle ISI... + + +; +; This code emulates instructions that have failed because of operand +; alignment. We decode the DSISR to figure out what we need to do. +; +; DSISR: +; 0001FC00 - Instruction designation +#define iFloat 12 +#define iOptype1 15 +#define iOptype2 16 +#define iOptype3 18 +#define iOptype4 19 +#define iUpdate 17 +#define iStore 20 +#define iDouble 21 +#define iNotify 22 +; 000003E0 - Target/Source register +; 0000001F - Register to update if update form +; + + .align 5 + .globl EXT(AlignAssist) + +LEXT(AlignAssist) + +#if 0 b EXT(EmulExit) ; Just return for now... +#endif + + + mfsprg r31,0 ; Get the per_proc + lwz r20,savedsisr(r13) ; Get the DSISR + lwz r21,spcFlags(r31) ; Grab the special flags + mtcrf 0x1C,r20 ; Put instruction ID in CR for later + rlwinm. r0,r21,0,runningVMbit,runningVMbit ; Are we running a VM? + lwz r22,savesrr1(r13) ; Get the SRR1 + bne- aaPassAlong ; We are in a VM, no emulation for alignment exceptions... + rlwinm. r0,r21,0,trapUnalignbit,trapUnalignbit ; Should we trap alignment exceptions? + crxor iFloat,iOptype1,iOptype2 ; Set this to 0 if both bits are either 0 or 1 + mr r26,r20 ; Save the DSISR + bne- aaPassAlong ; No alignment exceptions allowed... + rlwinm. r0,r22,0,MSR_SE_BIT,MSR_SE_BIT ; Were we single stepping? + lwz r23,savedar(r13) ; Pick up the address that we want to access + crnot traceInst,cr0_eq ; Remember if trace is on + rlwinm. r0,r21,0,notifyUnalignbit,notifyUnalignbit ; Should we notify that an alignment exception happened? + mfsprg r28,2 ; Get the processor features + crnot iNotify,cr0_eq ; Remember to tell someone we did this + rlwinm. r22,r22,0,MSR_PR_BIT,MSR_PR_BIT ; Did we take the exception in the kernel and isolate PR? + mfmsr r30 ; Save the MSR for now + li r29,emfp0 ; Point to work area + crxor iFloat,iFloat,iOptype3 ; Set true if we have a floating point instruction + or r22,r22,r30 ; Add PR to access MSR + dcbz r29,r31 ; Clear and allocate a cache line for us to work in + rlwinm r24,r20,2,25,29 ; Get displacement to register to update if update form + rlwimi r20,r20,24,28,28 ; Move load/store indication to the bottom of index + ori r22,r22,lo16(MASK(MSR_DR)|MASK(MSR_RI)) ; Set RI onto access MSR + crmove kernAccess,cr0_eq ; Remember if fault was in kernel + rlwinm. r28,r28,0,pfAltivecb,pfAltivecb ; Do we have Altivec on this machine? + rlwimi r20,r20,26,27,27 ; Move single/double indication to just above the bottom + beq aaNoVect ; Nope, no Altivec... + + dssall ; We need to kill streams because we are going to flip to problem state + sync + +aaNoVect: lis r29,hi16(aaFPopTable) ; High part of FP branch table + bf- iFloat,aaNotFloat ; This is not a floating point instruction... + li r25,8 ; Assume 8-byte access for now + ori r29,r29,lo16(aaFPopTable) ; Low part of FP branch table + bt iDouble,aaFPis8 ; So far, we think we are a double... + li r25,4 ; Set word access + +aaFPis8: rlwimi r29,r20,0,22,28 ; Index into table based upon register||iDouble||iStore + ori r0,r30,lo16(MASK(MSR_FP)) ; Turn on floating point + mtctr r29 ; Get set to call the function + bt iStore,aaFPstore ; This is an FP store... + +; +; Here we handle floating point loads +; + +aaFPload: bfl+ kernAccess,aaSetSegs ; Go set SRs if we are in user and need to + + crset cr0_eq ; Set this to see if we failed + ori r3,r30,lo16(MASK(MSR_FP)) ; We will need FP on in a bit, so turn on when we ditch problem state + mtmsr r22 ; Flip DR, RI, and maybe PR on + isync + + lwz r10,0(r23) ; Get the first word + bf- cr0_eq,aaLdNotDbl ; Jump out if we DSIed... + bf iDouble,aaLdNotDbl ; this is not a double... + lwz r11,4(r23) ; Get the second half + +aaLdNotDbl: mr r4,r0 ; Save the DAR if we failed the access + li r0,loadMSR ; Set the magic "get back to supervisor" SC + sc ; Get back to supervisor state and turn on FP + + bf- cr0_eq,aaRedriveAsDSI ; Go redrive this as a DSI... + + stw r10,emfp0(r31) ; Save the first half + stw r11,emfp0+4(r31) ; Save the second half, just in case we need it + + bctrl ; Go set the target FP register + + b aaComExit ; All done, go exit... + +; +; Here we handle floating point stores +; + + .align 5 + +aaFPstore: mtmsr r0 ; We need floating point on for the first phase + isync + + bctrl ; Go save the source FP register + + lwz r10,emfp0(r31) ; Get first word + crandc iDouble,iDouble,iOptype4 ; Change to 4-byte access if stfiwx + lwz r11,emfp0+4(r31) ; and the second + bf+ iOptype4,aaNotstfiwx ; This is not a stfiwx... + li r25,4 ; Set this is a word + mr r10,r11 ; The stfiwx wants to store the second half + +aaNotstfiwx: + bfl+ kernAccess,aaSetSegs ; Go set SRs if we are in user and need to + + crset cr0_eq ; Set this to see if we failed + mr r3,r30 ; Set the normal MSR + mtmsr r22 ; Flip DR, RI, and maybe PR on + isync + + stw r10,0(r23) ; Save the first word + bf- cr0_eq,aaStNotDbl ; Jump out if we DSIed... + bf iDouble,aaStNotDbl ; this is not a double... + stw r11,4(r23) ; Save the second half + +aaStNotDbl: mr r4,r0 ; Save the DAR if we failed the access + li r0,loadMSR ; Set the magic "get back to supervisor" SC + sc ; Get back to supervisor state + + + bf- cr0_eq,aaRedriveAsDSI ; Go redrive this as a DSI... + + + +; +; Common exit routines +; + +aaComExit: lwz r10,savesrr0(r13) ; Get the failing instruction address + add r24,r24,r13 ; Offset to update register + li r11,T_IN_VAIN ; Assume we are all done + addi r10,r10,4 ; Step to the next instruction + bf iUpdate,aaComExNU ; Skip if not an update form... + stw r23,saver0(r24) ; Update the target + +aaComExNU: lwz r9,SAVflags(r13) ; Get the flags + stw r10,savesrr0(r13) ; Set new PC + bt- traceInst,aaComExitrd ; We are tracing, go emulate trace... + bf+ iNotify,aaComExGo ; Nothing special here, go... + + bfl+ kernAccess,aaUnSetSegs ; Go set SRs if we are in user and need to + + li r11,T_ALIGNMENT ; Set the we just did an alignment exception.... + +aaComExGo: b EXT(EmulExit) ; We are done, no tracing on... + + +; +; This is not a floating point operation +; +; The emulation routines for these are positioned every 64 bytes (16 instructions) +; in a 1024-byte aligned table. It is indexed by taking the low order 4 bits of +; the instruction code in the DSISR and subtracting 7. If this comes up negative, +; the instruction is not to be emulated. Then we add bit 0 of the code * 4. This +; gives us a fairly compact and almost unique index. Both lwm and stmw map to 0 so +; that one needs to be further reduced, and we end up with holes at index 6, 8, and 10. +; +; If the emulation routine takes more than 16 instructions, it must branch elsewhere +; to finish up. +; + + .align 5 + +aaNotFloat: + lis r19,hi16(aaEmTable) ; Point to high part of table address + rlwinm r3,r26,24,26,29 ; Isolate last 4 bits of op type * 4 + rlwimi r19,r26,20,27,27 ; Get bit 0 of instruction code * 4 into bottom of table base + addic. r3,r3,-28 ; Subtract 7*4 to adjust index + ori r19,r19,lo16(aaEmTable) ; Low part of table address + blt- aaPassAlong ; We do not handle any of these (lwarx, stwcx., eciwx, ecowx)... + add r19,r19,r3 ; Point to emulation routine + rlwinm r18,r26,29,25,29 ; Get the target/source register displacement + + mtctr r19 ; Set the routine address + + bctr ; Go emulate the instruction... + +; +; This is the table of non-floating point emulation routines. +; It is indexed by low 4 bits of DSISR op type - 7 + bit 0 of +; op type * 4 +; + + .align 5 + +aaEmTable: + b aaLmwStmw ; This for lmw/stmw + b aaLswx ; This for lwwx + b aaLswi ; This for lswi + b aaStswx ; This for stswx + b aaStswi ; This for stswi + b aaLwbrx ; This for lwbrx + b aaPassAlong ; This an invalid index (6) + b aaStwbrx ; This for stwbrx + b aaPassAlong ; This an invalid index (8) + b aaLhbrx ; This for lhbrx + b aaPassAlong ; This an invalid index (A) + b aaSthbrx ; This for sthbrx + b aaDcbz ; This for dcbz + b aaPassAlong ; This an invalid index (D) + b aaPassAlong ; This an invalid index (E) + b aaPassAlong ; This an invalid index (F) + + +; +; Here we handle the set up for the lmw and stmw. After that, we split off to the +; individual routines. +; +; Note also that after some set up, all of the string instructions come through here as well. +; + .align 5 + +aaLmwStmw: + subfic r25,r18,32*4 ; Calculate the length of the transfer + li r28,0 ; Set no extra bytes to move (used for string instructions) + mr r17,r25 ; Save the word transfer length here + +aaLSComm: addi r19,r13,saver0 ; Offset to registers in savearea + mr r16,r23 ; Make a hunk pointer + + bfl+ kernAccess,aaSetSegs ; Go set SRs if we are in user and need to + + bt iUpdate,aaStmw ; This is the stmw... + +; +; Load multiple word +; + +aaLmwNxt: cmplwi cr1,r17,8*4 ; Is there enough to move 8? + blt- cr1,aaLmwNxtH ; Not enough for a full hunk... + subi r17,r17,8*4 ; Back off for another hunk + + crset cr0_eq ; Set this to see if we failed + mtmsr r22 ; Flip DR, RI, and maybe PR on + isync + + lwz r2,0(r16) ; Load word 0 + bf- cr0_eq,aaLmwB1 ; Error, bail... + lwz r15,4(r16) ; Load word 1 + bf- cr0_eq,aaLmwB1 ; Error, bail... + lwz r14,8(r16) ; Load word 2 + bf- cr0_eq,aaLmwB1 ; Error, bail... + lwz r5,12(r16) ; Load word 3 + bf- cr0_eq,aaLmwB1 ; Error, bail... + lwz r6,16(r16) ; Load word 4 + bf- cr0_eq,aaLmwB1 ; Error, bail... + lwz r7,20(r16) ; Load word 5 + bf- cr0_eq,aaLmwB1 ; Error, bail... + lwz r8,24(r16) ; Load word 6 + bf- cr0_eq,aaLmwB1 ; Error, bail... + lwz r9,28(r16) ; Load word 7 + +aaLmwB1: mr r4,r0 ; Remember DAR, jus in case we failed the access + mr r3,r30 ; Set the normal MSR + li r0,loadMSR ; Set the magic "get back to supervisor" SC + sc ; Get back to supervisor state + + bf- cr0_eq,aaRedriveAsDSI ; We failed, go redrive this as a DSI... + + addi r16,r16,8*4 ; Point up to next input aread + + stwx r2,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + stwx r15,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + stwx r14,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + stwx r5,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + stwx r6,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + stwx r7,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + stwx r8,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + stwx r9,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + + b aaLmwNxt ; Do the next hunk... + + .align 5 + +aaLmwNxtH: cmplwi cr1,r17,4*4 ; Do we have 4 left? + blt cr1,aaLmwL4 ; Nope... + + subi r17,r17,4*4 ; Set count properly + + crset cr0_eq ; Set this to see if we failed + mtmsr r22 ; Flip DR, RI, and maybe PR on + isync + + lwz r2,0(r16) ; Load word 0 + bf- cr0_eq,aaLmwB2 ; Error, bail... + lwz r15,4(r16) ; Load word 1 + bf- cr0_eq,aaLmwB2 ; Error, bail... + lwz r14,8(r16) ; Load word 2 + bf- cr0_eq,aaLmwB2 ; Error, bail... + lwz r5,12(r16) ; Load word 3 + +aaLmwB2: mr r4,r0 ; Remember DAR, jus in case we failed the access + mr r3,r30 ; Set the normal MSR + li r0,loadMSR ; Set the magic "get back to supervisor" SC + sc ; Get back to supervisor state + + bf- cr0_eq,aaRedriveAsDSI ; We failed, go redrive this as a DSI... + + addi r16,r16,4*4 ; Point up to next input aread + + stwx r2,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + stwx r15,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + stwx r14,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + stwx r5,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + +aaLmwL4: or. r5,r17,r28 ; Do we have anything left? + cmplwi cr1,r17,(2*4) ; Do we have one, two, or three full words left? + cmplwi cr2,r17,0 ; Do we have no full words left? + beq aaComExit ; Nothing left... + + crset cr0_eq ; Set this to see if we failed + mtmsr r22 ; Flip DR, RI, and maybe PR on + isync + + beq- cr2,aaLmwBy ; No full words, get bytes... + + lwz r2,0(r16) ; Pick up first word + bf- cr0_eq,aaLmwDn ; Read failed, escape... + addi r16,r16,4 ; Next input location + blt cr1,aaLmwBy ; We only had one, we are done... + + lwz r15,0(r16) ; Pick up second word + bf- cr0_eq,aaLmwDn ; Read failed, escape... + addi r16,r16,4 ; Next input location + beq cr1,aaLmwBy ; We had two, we are done... + + lwz r14,0(r16) ; Load word 3 + addi r16,r16,4 ; Next input location + +aaLmwBy: cmplwi cr2,r28,0 ; Any trailing bytes to do? + li r8,0 ; Clear second trailing byte + cmplwi cr1,r28,2 ; Check for 1, 2, or 3 + li r9,0 ; Clear third trailing byte + beq+ cr2,aaLmwDn ; No trailing bytes... + + lbz r5,0(r16) ; Pick up first trailing byte + bf- cr0_eq,aaLmwDn ; Read failed, escape... + blt cr1,aaLmwDn ; We only had one, we are done... + + lbz r8,1(r16) ; Pick up second trailing byte + bf- cr0_eq,aaLmwDn ; Read failed, escape... + beq cr1,aaLmwDn ; We had two, we are done... + + lbz r9,2(r16) ; Get last trailing byte + + +aaLmwDn: rlwinm r5,r5,24,0,7 ; Move first byte to top + cmplwi cr2,r17,0 ; Any full words to do? + mr r4,r0 ; Remember DAR, just in case we failed the access + rlwimi r9,r8,8,16,23 ; Move second byte above third byte + cmplwi cr1,r17,(2*4) ; Do we have one, two, or three full words left? + mr r3,r30 ; Set the normal MSR + rlwimi r5,r9,8,8,23 ; Move bytes 1 and 2 after 0 + li r0,loadMSR ; Set the magic "get back to supervisor" SC + sc ; Get back to supervisor state + + bf- cr0_eq,aaRedriveAsDSI ; We failed, go redrive this as a DSI... + + beq- cr2,aaLmwCb ; No full words, copy bytes... + + stwx r2,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + blt cr1,aaLmwCb ; We only had one, we are done... + + stwx r15,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + beq cr1,aaLmwCb ; We had two, we are done... + + stwx r14,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + +aaLmwCb: mr. r28,r28 ; Any trailing bytes to do? + beq+ aaComExit ; Nope, leave... + + stwx r5,r19,r18 ; Store register + + b aaComExit ; We are done.... + +; +; Store multiple word +; + + .align 5 + +aaStmw: + crclr iUpdate ; Make sure we do not think this is an update form + +aaStmwNxt: cmplwi cr1,r17,8*4 ; Is there enough to move 8? + blt- cr1,aaStmwNxtH ; Not enough for a full hunk... + subi r17,r17,8*4 ; Back off for another hunk + + lwzx r2,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + lwzx r15,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + lwzx r14,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + lwzx r5,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + lwzx r6,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + lwzx r7,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + lwzx r8,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + lwzx r9,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + + crset cr0_eq ; Set this to see if we failed + mtmsr r22 ; Flip DR, RI, and maybe PR on + isync + + stw r2,0(r16) ; Store word 0 + bf- cr0_eq,aaStmwB1 ; Error, bail... + stw r15,4(r16) ; Store word 1 + bf- cr0_eq,aaStmwB1 ; Error, bail... + stw r14,8(r16) ; Store word 2 + bf- cr0_eq,aaStmwB1 ; Error, bail... + stw r5,12(r16) ; Store word 3 + bf- cr0_eq,aaStmwB1 ; Error, bail... + stw r6,16(r16) ; Store word 4 + bf- cr0_eq,aaStmwB1 ; Error, bail... + stw r7,20(r16) ; Store word 5 + bf- cr0_eq,aaStmwB1 ; Error, bail... + stw r8,24(r16) ; Store word 6 + bf- cr0_eq,aaStmwB1 ; Error, bail... + stw r9,28(r16) ; Store word 7 + + addi r16,r16,8*4 ; Point up to next output aread + + +aaStmwB1: mr r4,r0 ; Remember DAR, jus in case we failed the access + mr r3,r30 ; Set the normal MSR + li r0,loadMSR ; Set the magic "get back to supervisor" SC + sc ; Get back to supervisor state + + bt- cr0_eq,aaStmwNxt ; We have more to do and no failed access... + b aaRedriveAsDSI ; We failed, go redrive this as a DSI... + + .align 5 + +aaStmwNxtH: cmplwi cr1,r17,(4*4) ; Do we have at least 4 left? + blt cr1,aaStmwL4 ; Nope... + subi r17,r17,4*4 ; Set count properly + + lwzx r2,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + lwzx r15,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + lwzx r14,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + lwzx r5,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + + crset cr0_eq ; Set this to see if we failed + mtmsr r22 ; Flip DR, RI, and maybe PR on + isync + + stw r2,0(r16) ; Store word 0 + bf- cr0_eq,aaStmwB2 ; Error, bail... + stw r15,4(r16) ; Store word 1 + bf- cr0_eq,aaStmwB2 ; Error, bail... + stw r14,8(r16) ; Store word 2 + bf- cr0_eq,aaStmwB2 ; Error, bail... + stw r5,12(r16) ; Store word 3 + + addi r16,r16,4*4 ; Point up to next input aread + +aaStmwB2: mr r4,r0 ; Remember DAR, jus in case we failed the access + mr r3,r30 ; Set the normal MSR + li r0,loadMSR ; Set the magic "get back to supervisor" SC + sc ; Get back to supervisor state + + bf- cr0_eq,aaRedriveAsDSI ; We failed, go redrive this as a DSI... + +aaStmwL4: or. r5,r17,r28 ; Do we have anything left to do? + cmplwi cr1,r17,(2*4) ; Do we have one, two, or three left? + cmplwi cr2,r17,0 ; Do we have no full words left? + beq aaComExit ; Nothing left... + + beq- cr2,aaStmwBy1 ; No full words, check out bytes + + lwzx r2,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + blt cr1,aaStmwBy1 ; We only had one, go save it... + + lwzx r15,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + beq cr1,aaStmwBy1 ; We had two, go save it... + + lwzx r14,r19,r18 ; Store register + addi r18,r18,4 ; Next register + rlwinm r18,r18,0,25,29 ; Wrap back to 0 if needed + +aaStmwBy1: mr. r28,r28 ; Do we have any trailing bytes? + beq+ aaStmwSt ; Nope... + + lwzx r5,r19,r18 ; Yes, pick up one extra register + +aaStmwSt: crset cr0_eq ; Set this to see if we failed + mtmsr r22 ; Flip DR, RI, and maybe PR on + isync + + beq- cr2,aaStmwBy2 ; No words, check trailing bytes... + + stw r2,0(r16) ; Save first word + bf- cr0_eq,aaStmwDn ; Read failed, escape... + addi r16,r16,4 ; Bump sink + blt cr1,aaStmwBy2 ; We only had one, we are done... + + stw r15,0(r16) ; Save second word + bf- cr0_eq,aaStmwDn ; Read failed, escape... + addi r16,r16,4 ; Bump sink + beq cr1,aaStmwBy2 ; We had two, we are done... + + stw r14,0(r16) ; Save third word + addi r16,r16,4 ; Bump sink + +aaStmwBy2: rlwinm r2,r5,8,24,31 ; Get byte 0 + cmplwi cr2,r28,0 ; Any trailing bytes to do? + rlwinm r14,r5,24,24,31 ; Get byte 3 + li r8,0 ; Clear second trailing byte + cmplwi cr1,r28,2 ; Check for 1, 2, or 3 + li r9,0 ; Clear third trailing byte + beq+ cr2,aaStmwDn ; No trailing bytes... + rlwinm r15,r5,16,24,31 ; Get byte 1 + + stb r2,0(r16) ; Save first byte + bf- cr0_eq,aaStmwDn ; Read failed, escape... + blt cr1,aaStmwDn ; We only had one, we are done... + + stb r15,1(r16) ; Save second byte + bf- cr0_eq,aaStmwDn ; Read failed, escape... + beq cr1,aaStmwDn ; We had two, we are done... + + stb r14,2(r16) ; Save third byte + +aaStmwDn: mr r4,r0 ; Remember DAR, jus in case we failed the access + mr r3,r30 ; Set the normal MSR + li r0,loadMSR ; Set the magic "get back to supervisor" SC + sc ; Get back to supervisor state + + bf- cr0_eq,aaRedriveAsDSI ; We failed, go redrive this as a DSI... + + b aaComExit ; We are done.... + + +; +; Load String Indexed +; + + .align 5 + +aaLswx: lwz r17,savexer(r13) ; Pick up the XER + crclr iUpdate ; Make sure we think this the load form + rlwinm. r25,r17,0,25,31 ; Get the number of bytes to load + rlwinm r28,r17,0,30,31 ; Get the number of bytes past an even word + beq- aaComExit ; Do nothing if 0 length... + xor r17,r25,r28 ; Round down to an even word boundary + b aaLSComm ; Join up with common load/store code... + + +; +; Load String Immediate +; + + .align 5 + +aaLswi: mr r9,r23 ; Save the DAR + bl eIFetch ; Get the instruction image + bne- eRedriveAsISI ; Go redrive this as an ISI... + rlwinm r25,r10,21,27,31 ; Get the number of bytes to load + crclr iUpdate ; Make sure we think this the load form + subi r25,r25,1 ; Back off by 1 + rlwinm r25,r25,0,27,31 ; Clear back down + addi r25,r25,1 ; Add back the 1 to convert 0 to 32 + rlwinm r28,r25,0,30,31 ; Get the number of bytes past an even word + xor r17,r25,r28 ; Round down to an even word boundary + mr r23,r9 ; Move back the DAR + b aaLSComm ; Join up with common load/store code... + +; +; Store String Indexed +; + + .align 5 + +aaStswx: lwz r17,savexer(r13) ; Pick up the XER + crclr iUpdate ; Make sure this is clear in case we have 0 length + rlwinm. r25,r17,0,25,31 ; Get the number of bytes to load + rlwinm r28,r17,0,30,31 ; Get the number of bytes past an even word + beq- aaComExit ; Do nothing if 0 length... + xor r17,r25,r28 ; Round down to an even word boundary + crset iUpdate ; Make sure we think this the store form + b aaLSComm ; Join up with common load/store code... + + +; +; Store String Immediate +; + + .align 5 + +aaStswi: mr r9,r23 ; Save the DAR + bl eIFetch ; Get the instruction image + bne- eRedriveAsISI ; Go redrive this as an ISI... + rlwinm r25,r10,21,27,31 ; Get the number of bytes to load + crclr iUpdate ; Make sure we think this the load form + subi r25,r25,1 ; Back off by 1 + rlwinm r25,r25,0,27,31 ; Clear back down + addi r25,r25,1 ; Add back the 1 to convert 0 to 32 + rlwinm r28,r25,21,30,31 ; Get the number of bytes past an even word + xor r17,r25,r28 ; Round down to an even word boundary + mr r23,r9 ; Move back the DAR + b aaLSComm ; Join up with common load/store code... + + +; +; Load byte-reversed word +; + + .align 5 + +aaLwbrx: + add r18,r18,r13 ; Index to source register + li r25,4 ; Set the length + + bfl+ kernAccess,aaSetSegs ; Go set SRs if we are in user and need to + + crset cr0_eq ; Set this to see if we failed + mr r3,r30 ; Set the normal MSR + mtmsr r22 ; Flip DR, RI, and maybe PR on + isync + + lwz r11,0(r23) ; Load the word + + mr r4,r0 ; Save the DAR if we failed the access + li r0,loadMSR ; Set the magic "get back to supervisor" SC + sc ; Get back to supervisor state + + bf- cr0_eq,aaRedriveAsDSI ; We failed, go redrive this as a DSI... + + rlwinm r10,r11,8,0,31 ; Get byte 0 to 3 and byte 2 to 1 + rlwimi r10,r11,24,16,23 ; Move byte 1 to byte 2 + rlwimi r10,r11,24,0,7 ; Move byte 3 to byte 0 + + stw r10,saver0(r18) ; Set the register + + b aaComExit ; All done, go exit... + + + +; +; Store byte-reversed word +; + + .align 5 + +aaStwbrx: + add r18,r18,r13 ; Index to source register + li r25,4 ; Set the length + lwz r11,saver0(r18) ; Get the register to store + + rlwinm r10,r11,8,0,31 ; Get byte 0 to 3 and byte 2 to 1 + rlwimi r10,r11,24,16,23 ; Move byte 1 to byte 2 + rlwimi r10,r11,24,0,7 ; Move byte 3 to byte 0 + + bfl+ kernAccess,aaSetSegs ; Go set SRs if we are in user and need to + + crset cr0_eq ; Set this to see if we failed + mr r3,r30 ; Set the normal MSR + mtmsr r22 ; Flip DR, RI, and maybe PR on + isync + + stw r10,0(r23) ; Store the reversed halfword + + mr r4,r0 ; Save the DAR if we failed the access + li r0,loadMSR ; Set the magic "get back to supervisor" SC + sc ; Get back to supervisor state + + bt+ cr0_eq,aaComExit ; All done, go exit... + b aaRedriveAsDSI ; We failed, go redrive this as a DSI... + + + +; +; Load byte-reversed halfword +; + + .align 5 + +aaLhbrx: + add r18,r18,r13 ; Index to source register + li r25,2 ; Set the length + + bfl+ kernAccess,aaSetSegs ; Go set SRs if we are in user and need to + + crset cr0_eq ; Set this to see if we failed + mr r3,r30 ; Set the normal MSR + mtmsr r22 ; Flip DR, RI, and maybe PR on + isync + + lhz r11,0(r23) ; Load the halfword + + mr r4,r0 ; Save the DAR if we failed the access + li r0,loadMSR ; Set the magic "get back to supervisor" SC + sc ; Get back to supervisor state + + bf- cr0_eq,aaRedriveAsDSI ; We failed, go redrive this as a DSI... + + rlwinm r10,r11,8,16,23 ; Rotate bottom byte up one and clear everything else + rlwimi r10,r11,24,24,31 ; Put old second from bottom into bottom + + stw r10,saver0(r18) ; Set the register + + b aaComExit ; All done, go exit... + + +; +; Store byte-reversed halfword +; + + .align 5 + +aaSthbrx: + add r18,r18,r13 ; Index to source register + li r25,2 ; Set the length + lwz r10,saver0(r18) ; Get the register to store + rlwinm r10,r10,8,0,31 ; Rotate bottom byte up one + rlwimi r10,r10,16,24,31 ; Put old second from bottom into bottom + + bfl+ kernAccess,aaSetSegs ; Go set SRs if we are in user and need to + + crset cr0_eq ; Set this to see if we failed + mr r3,r30 ; Set the normal MSR + mtmsr r22 ; Flip DR, RI, and maybe PR on + isync + + sth r10,0(r23) ; Store the reversed halfword + + mr r4,r0 ; Save the DAR if we failed the access + li r0,loadMSR ; Set the magic "get back to supervisor" SC + sc ; Get back to supervisor state + + bt+ cr0_eq,aaComExit ; All done, go exit... + b aaRedriveAsDSI ; We failed, go redrive this as a DSI... + +; +; Data cache block zero +; + + .align 5 + +aaDcbz: + li r25,32 ; Set the length + rlwinm r23,r23,0,0,26 ; Round back to a 32-byte boundary + + bfl+ kernAccess,aaSetSegs ; Go set SRs if we are in user and need to + + crset cr0_eq ; Set this to see if we failed + mr r3,r30 ; Set the normal MSR + li r0,0 ; Clear this out + mtmsr r22 ; Flip DR, RI, and maybe PR on + isync + + stw r0,0(r23) ; Clear word + bne- aaDcbzXit ; Got DSI, we are stopping... + stw r0,4(r23) ; Clear word + bne- aaDcbzXit ; Got DSI, we are stopping... + stw r0,8(r23) ; Clear word + bne- aaDcbzXit ; Got DSI, we are stopping... + stw r0,12(r23) ; Clear word + bne- aaDcbzXit ; Got DSI, we are stopping... + stw r0,16(r23) ; Clear word + bne- aaDcbzXit ; Got DSI, we are stopping... + stw r0,20(r23) ; Clear word + bne- aaDcbzXit ; Got DSI, we are stopping... + stw r0,24(r23) ; Clear word + bne- aaDcbzXit ; Got DSI, we are stopping... + stw r0,28(r23) ; Clear word + +aaDcbzXit: mr r4,r0 ; Save the DAR if we failed the access + li r0,loadMSR ; Set the magic "get back to supervisor" SC + sc ; Get back to supervisor state + + crclr iUpdate ; Make sure we do not think this is an update form + + bt+ cr0_eq,aaComExit ; All done, go exit... + b aaRedriveAsDSI ; We failed, go redrive this as a DSI... + + +; +; Unhandled alignment exception, pass it along +; + +aaPassAlongUnMap: + bfl+ kernAccess,aaUnSetSegs ; Go set SRs if we are in user and need to + + +aaPassAlong: + b EXT(EmulExit) + + + + +; +; We go here to emulate a trace exception after we have handled alignment error +; + + .align 5 + +aaComExitrd: + bfl+ kernAccess,aaUnSetSegs ; Go set SRs back if we need to because we are not going back to user yet + oris r9,r9,hi16(SAVredrive) ; Set the redrive bit + li r11,T_TRACE ; Set trace interrupt + rlwinm r12,r12,0,16,31 ; Clear top half of SRR1 + stw r9,SAVflags(r13) ; Set the flags + stw r11,saveexception(r13) ; Set the exception code + b EXT(EmulExit) ; Exit and do trace interrupt... + + + +; +; Redrive as a DSI + +aaRedriveAsDSI: + mr r20,r1 ; Save the DSISR + mr r21,r4 + bfl+ kernAccess,aaUnSetSegs ; Go set SRs back if we need to because we are not going back to user yet + lwz r4,SAVflags(r13) ; Pick up the flags + li r11,T_DATA_ACCESS ; Set failing data access code + oris r4,r4,hi16(SAVredrive) ; Set the redrive bit + stw r20,savedsisr(r13) ; Set the DSISR of failed access + stw r21,savedar(r13) ; Set the address of the failed access + stw r11,saveexception(r13) ; Set the replacement code + stw r4,SAVflags(r13) ; Set redrive request + b EXT(EmulExit) ; Bail out to handle ISI... + +; +; Set segment registers for user access. Do not call this if we are trying to get +; supervisor state memory. We do not need this. +; +; Performance-wise, we will usually be setting one SR here. Most memory will be +; allocated before the 1GB mark. Since the kernel maps the first GB, the exception +; handler always sets the SRs before we get here. Therefore, we will usually +; have to remap it. +; +; Also, we need to un-do these mapping ONLY if we take a non-standard +; exit, e.g., emulate DSI, emulate trace exception, etc. This is because +; translation will never be turned on until we return and at that point, +; normal exception exit code will restore the first 4 SRs if needed. +; + + .align 5 + + .globl EXT(aaSetSegsX) + +LEXT(aaSetSegsX) + +aaSetSegs: addi r3,r25,-1 ; Point at last accessed offset in range + lwz r7,PP_USERPMAP(r31) ; Get the current user pmap + lis r0,0x4000 ; This is the address of the first segment outside of the kernel + rlwinm r5,r23,6,26,29 ; Get index into pmap table + add r4,r23,r3 ; Point to the last byte accessed + addi r5,r5,PMAP_SEGS ; Point to the segment slot + cmplw r23,r0 ; See if first segment register needs to be reloaded + cmplw cr2,r4,r0 ; Do we need to set the second (if any) SR? + xor r0,r4,r23 ; See if we are in the same segment as first + bge aaSetS1ok ; Nope, we are in a pure user range + + lwzx r6,r5,r7 ; Get the user address space SR value + mtsrin r6,r23 ; Load the corresponding SR register + +aaSetS1ok: rlwinm. r0,r0,0,0,3 ; Any change in segment? + bgelr- cr2 ; We are in user only space, we do not need to mess with SR + rlwinm r5,r4,6,26,29 ; Get index into pmap table + beqlr+ ; No change in segment, we are done... + + lwzx r6,r5,r7 ; Get the user address space SR value + mtsrin r6,r4 ; Load the corresponding SR register + blr ; Leave... + +; +; Unset segment registers for user access. Do not call unless we had a user access. +; + + .align 5 + + .globl EXT(aaUnSetSegsX) + +LEXT(aaUnSetSegsX) + +aaUnSetSegs: + addi r3,r25,-1 ; Point at last accessed offset in range + lis r0,0x4000 ; This is the address of the first segment outside of the kernel + lis r5,hi16(KERNEL_SEG_REG0_VALUE) ; Get the high half of the kernel SR0 value + add r4,r23,r3 ; Point to the last byte accessed + cmplw r23,r0 ; See if first segment register needs to be reloaded + rlwimi r5,r23,24,8,11 ; Make the correct kernel segment + cmplw cr2,r4,r0 ; Do we need to set the second (if any) SR? + xor r0,r4,r23 ; See if we are in the same segment as first + bge aaUnSetS1ok ; Nope, we are in a pure user range + + mtsrin r5,r23 ; Load the corresponding SR register + +aaUnSetS1ok: + rlwinm. r0,r0,0,0,3 ; Any change in segment? + bgelr cr2 ; We are in user only space, we do not need to mess with SR + rlwimi r5,r4,24,8,11 ; Make the correct kernel segment + beqlr+ ; No change in segment, we are done... + + mtsrin r5,r4 ; Load the corresponding SR register + blr ; Leave... + + + +; +; Table of functions to load or store floating point registers +; This table is indexed reg||size||dir. That means that each +; like load/store pair (e.g., lfd f31/stfd f31) are within the same +; quadword, which is the current ifetch size. We expect most of the +; unaligned accesses to be part of copies, therefore, with this +; organization, we will save the ifetch of the store after the load. +; + + .align 10 ; Make sure we are on a 1k boundary + +aaFPopTable: + lfs f0,emfp0(r31) ; Load single variant + blr + + stfs f0,emfp0(r31) ; Store single variant + blr + + lfd f0,emfp0(r31) ; Load double variant + blr + + stfd f0,emfp0(r31) ; Store double variant + blr + + lfs f1,emfp0(r31) ; Load single variant + blr + + stfs f1,emfp0(r31) ; Store single variant + blr + + lfd f1,emfp0(r31) ; Load double variant + blr + + stfd f1,emfp0(r31) ; Store double variant + blr + + lfs f2,emfp0(r31) ; Load single variant + blr + + stfs f2,emfp0(r31) ; Store single variant + blr + + lfd f2,emfp0(r31) ; Load double variant + blr + + stfd f2,emfp0(r31) ; Store double variant + blr + + lfs f3,emfp0(r31) ; Load single variant + blr + + stfs f3,emfp0(r31) ; Store single variant + blr + + lfd f3,emfp0(r31) ; Load double variant + blr + + stfd f3,emfp0(r31) ; Store double variant + blr + + lfs f4,emfp0(r31) ; Load single variant + blr + + stfs f4,emfp0(r31) ; Store single variant + blr + + lfd f4,emfp0(r31) ; Load double variant + blr + + stfd f4,emfp0(r31) ; Store double variant + blr + + lfs f5,emfp0(r31) ; Load single variant + blr + + stfs f5,emfp0(r31) ; Store single variant + blr + + lfd f5,emfp0(r31) ; Load double variant + blr + + stfd f5,emfp0(r31) ; Store double variant + blr + + lfs f6,emfp0(r31) ; Load single variant + blr + + stfs f6,emfp0(r31) ; Store single variant + blr + + lfd f6,emfp0(r31) ; Load double variant + blr + + stfd f6,emfp0(r31) ; Store double variant + blr + + lfs f7,emfp0(r31) ; Load single variant + blr + + stfs f7,emfp0(r31) ; Store single variant + blr + + lfd f7,emfp0(r31) ; Load double variant + blr + + stfd f7,emfp0(r31) ; Store double variant + blr + + lfs f8,emfp0(r31) ; Load single variant + blr + + stfs f8,emfp0(r31) ; Store single variant + blr + + lfd f8,emfp0(r31) ; Load double variant + blr + + stfd f8,emfp0(r31) ; Store double variant + blr + + lfs f9,emfp0(r31) ; Load single variant + blr + + stfs f9,emfp0(r31) ; Store single variant + blr + + lfd f9,emfp0(r31) ; Load double variant + blr + + stfd f9,emfp0(r31) ; Store double variant + blr + + lfs f10,emfp0(r31) ; Load single variant + blr + + stfs f10,emfp0(r31) ; Store single variant + blr + + lfd f10,emfp0(r31) ; Load double variant + blr + + stfd f10,emfp0(r31) ; Store double variant + blr + + lfs f11,emfp0(r31) ; Load single variant + blr + + stfs f11,emfp0(r31) ; Store single variant + blr + + lfd f11,emfp0(r31) ; Load double variant + blr + + stfd f11,emfp0(r31) ; Store double variant + blr + + lfs f12,emfp0(r31) ; Load single variant + blr + + stfs f12,emfp0(r31) ; Store single variant + blr + + lfd f12,emfp0(r31) ; Load double variant + blr + + stfd f12,emfp0(r31) ; Store double variant + blr + + lfs f13,emfp0(r31) ; Load single variant + blr + + stfs f13,emfp0(r31) ; Store single variant + blr + + lfd f13,emfp0(r31) ; Load double variant + blr + + stfd f13,emfp0(r31) ; Store double variant + blr + + lfs f14,emfp0(r31) ; Load single variant + blr + + stfs f14,emfp0(r31) ; Store single variant + blr + + lfd f14,emfp0(r31) ; Load double variant + blr + + stfd f14,emfp0(r31) ; Store double variant + blr + + lfs f15,emfp0(r31) ; Load single variant + blr + + stfs f15,emfp0(r31) ; Store single variant + blr + + lfd f15,emfp0(r31) ; Load double variant + blr + + stfd f15,emfp0(r31) ; Store double variant + blr + + lfs f16,emfp0(r31) ; Load single variant + blr + + stfs f16,emfp0(r31) ; Store single variant + blr + + lfd f16,emfp0(r31) ; Load double variant + blr + + stfd f16,emfp0(r31) ; Store double variant + blr + + lfs f17,emfp0(r31) ; Load single variant + blr + + stfs f17,emfp0(r31) ; Store single variant + blr + + lfd f17,emfp0(r31) ; Load double variant + blr + + stfd f17,emfp0(r31) ; Store double variant + blr + + lfs f18,emfp0(r31) ; Load single variant + blr + + stfs f18,emfp0(r31) ; Store single variant + blr + + lfd f18,emfp0(r31) ; Load double variant + blr + + stfd f18,emfp0(r31) ; Store double variant + blr + + lfs f19,emfp0(r31) ; Load single variant + blr + + stfs f19,emfp0(r31) ; Store single variant + blr + + lfd f19,emfp0(r31) ; Load double variant + blr + + stfd f19,emfp0(r31) ; Store double variant + blr + + lfs f20,emfp0(r31) ; Load single variant + blr + + stfs f20,emfp0(r31) ; Store single variant + blr + + lfd f20,emfp0(r31) ; Load double variant + blr + + stfd f20,emfp0(r31) ; Store double variant + blr + + lfs f21,emfp0(r31) ; Load single variant + blr + + stfs f21,emfp0(r31) ; Store single variant + blr + + lfd f21,emfp0(r31) ; Load double variant + blr + + stfd f21,emfp0(r31) ; Store double variant + blr + + lfs f22,emfp0(r31) ; Load single variant + blr + + stfs f22,emfp0(r31) ; Store single variant + blr + + lfd f22,emfp0(r31) ; Load double variant + blr + + stfd f22,emfp0(r31) ; Store double variant + blr + + lfs f23,emfp0(r31) ; Load single variant + blr + + stfs f23,emfp0(r31) ; Store single variant + blr + + lfd f23,emfp0(r31) ; Load double variant + blr + + stfd f23,emfp0(r31) ; Store double variant + blr + + lfs f24,emfp0(r31) ; Load single variant + blr + + stfs f24,emfp0(r31) ; Store single variant + blr + + lfd f24,emfp0(r31) ; Load double variant + blr + + stfd f24,emfp0(r31) ; Store double variant + blr + + lfs f25,emfp0(r31) ; Load single variant + blr + + stfs f25,emfp0(r31) ; Store single variant + blr + + lfd f25,emfp0(r31) ; Load double variant + blr + + stfd f25,emfp0(r31) ; Store double variant + blr + + lfs f26,emfp0(r31) ; Load single variant + blr + + stfs f26,emfp0(r31) ; Store single variant + blr + + lfd f26,emfp0(r31) ; Load double variant + blr + + stfd f26,emfp0(r31) ; Store double variant + blr + + lfs f27,emfp0(r31) ; Load single variant + blr + + stfs f27,emfp0(r31) ; Store single variant + blr + + lfd f27,emfp0(r31) ; Load double variant + blr + + stfd f27,emfp0(r31) ; Store double variant + blr + + lfs f28,emfp0(r31) ; Load single variant + blr + + stfs f28,emfp0(r31) ; Store single variant + blr + + lfd f28,emfp0(r31) ; Load double variant + blr + + stfd f28,emfp0(r31) ; Store double variant + blr + + lfs f29,emfp0(r31) ; Load single variant + blr + + stfs f29,emfp0(r31) ; Store single variant + blr + + lfd f29,emfp0(r31) ; Load double variant + blr + + stfd f29,emfp0(r31) ; Store double variant + blr + + lfs f30,emfp0(r31) ; Load single variant + blr + + stfs f30,emfp0(r31) ; Store single variant + blr + + lfd f30,emfp0(r31) ; Load double variant + blr + + stfd f30,emfp0(r31) ; Store double variant + blr + + lfs f31,emfp0(r31) ; Load single variant + blr + + stfs f31,emfp0(r31) ; Store single variant + blr + + lfd f31,emfp0(r31) ; Load double variant + blr + + stfd f31,emfp0(r31) ; Store double variant + blr diff --git a/osfmk/ppc/Firmware.s b/osfmk/ppc/Firmware.s index fc040ffe2..3c16dd1df 100644 --- a/osfmk/ppc/Firmware.s +++ b/osfmk/ppc/Firmware.s @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -184,8 +185,10 @@ ENTRY(ReadReal, TAG_NO_FRAME_USED) lwz r6,4(r3) /* Get word 1 */ lwz r7,8(r3) /* Get word 2 */ lwz r8,12(r3) /* Get word 3 */ + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off lwz r9,16(r3) /* Get word 4 */ lwz r10,20(r3) /* Get word 5 */ + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off lwz r11,24(r3) /* Get word 6 */ lwz r12,28(r3) /* Get word 7 */ @@ -227,7 +230,7 @@ ENTRY(xLoadDBATsLL, TAG_NO_FRAME_USED) lwz r10,24(r3) /* Get DBAT 3 high */ lwz r11,28(r3) /* Get DBAT 3 low */ - sync /* Common decency and the state law require you to wash your hands */ + sync /* Common decency and the state law require that you wash your hands */ mtdbatu 0,r4 /* Load DBAT 0 high */ mtdbatl 0,r5 /* Load DBAT 0 low */ mtdbatu 1,r6 /* Load DBAT 1 high */ @@ -247,7 +250,7 @@ ENTRY(xLoadDBATsLL, TAG_NO_FRAME_USED) ENTRY(LoadIBATs, TAG_NO_FRAME_USED) - lis r0,HIGH_ADDR(LoadIBATsCall) /* Top half of CreateFakeIO firmware call number */ + lis r0,HIGH_ADDR(LoadIBATsCall) /* Top half of LoadIBATsCall firmware call number */ ori r0,r0,LOW_ADDR(LoadIBATsCall) /* Bottom half */ sc /* Do it to it */ blr /* Bye bye, Birdie... */ @@ -263,7 +266,7 @@ ENTRY(xLoadIBATsLL, TAG_NO_FRAME_USED) lwz r10,24(r3) /* Get IBAT 3 high */ lwz r11,28(r3) /* Get IBAT 3 low */ - sync /* Common decency and the state law require you to wash your hands */ + sync /* Common decency and the state law require that you wash your hands */ mtibatu 0,r4 /* Load IBAT 0 high */ mtibatl 0,r5 /* Load IBAT 0 low */ mtibatu 1,r6 /* Load IBAT 1 high */ @@ -306,6 +309,11 @@ ENTRY(CreateFakeIO, TAG_NO_FRAME_USED) ENTRY(CreateFakeDEC, TAG_NO_FRAME_USED) +#if 0 + mflr r4 ; (TEST/DEBUG) + bl EXT(ml_sense_nmi) ; (TEST/DEBUG) + mtlr r4 ; (TEST/DEBUG) +#endif lis r0,HIGH_ADDR(CreateFakeDECCall) /* Top half of CreateFakeDEC firmware call number */ ori r0,r0,LOW_ADDR(CreateFakeDECCall) /* Bottom half */ sc /* Do it to it */ @@ -1650,9 +1658,11 @@ ltsNoMSR: li r0,loadMSR ; Get the MSR setter SC ltsNoMSRx: lis r5,hi16(EXT(trcWork)) ; Get trace area + rlwinm r12,r12,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off ori r5,r5,lo16(EXT(trcWork)) ; again lwz r3,traceMask(r5) /* Get the old trace flags to pass back */ + rlwinm r12,r12,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off stw r4,traceMask(r5) /* Replace with the new ones */ mtmsr r12 /* Restore the MSR */ @@ -1846,10 +1856,12 @@ ENTRY(checkNMI,TAG_NO_FRAME_USED) ori r7,r7,0x0020 /* Find it */ dcbi 0,r7 /* Toss it */ sync /* Sync it */ + rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off eieio /* Get it */ lwz r6,0x000C(r7) /* Check it */ eieio /* Fence it */ dcbi 0,r7 /* Toss it */ + rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm. r4,r6,0,19,19 /* Check it */ rlwinm r6,r6,0,20,18 /* Clear it */ sync /* Sync it */ @@ -2069,6 +2081,8 @@ waytoofar2: mtmsr r10 ; Back to normal LEXT(stFloat) mfmsr r0 ; Save the MSR + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r4,r0,0,MSR_EE_BIT,MSR_EE_BIT ; Turn off interruptions ori r4,r4,lo16(MASK(MSR_FP)) ; Enable floating point mtmsr r4 @@ -2122,16 +2136,17 @@ LEXT(stFloat) .globl EXT(stVectors) LEXT(stVectors) -#if 0 - mfpvr r6 ; Get machine type + + mfsprg r6,2 ; Get features mr r5,r3 ; Save area address - rlwinm r6,r6,16,17,31 ; Rotate on it + rlwinm. r6,r6,0,pfAltivecb,pfAltivecb ; Do we have Altivec? li r3,0 ; Assume failure - cmplwi r6,PROCESSOR_VERSION_7400 ; Do we have Altivec? - bltlr+ ; No... + beqlr- ; No... mfmsr r0 ; Save the MSR + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r4,r0,0,MSR_EE_BIT,MSR_EE_BIT ; Turn off interruptions oris r4,r4,hi16(MASK(MSR_VEC)) ; Enable vectors mtmsr r4 @@ -2208,7 +2223,6 @@ LEXT(stVectors) mtmsr r0 isync -#endif blr @@ -2220,9 +2234,10 @@ LEXT(stVectors) .globl EXT(stSpecrs) LEXT(stSpecrs) -#if 0 mfmsr r0 ; Save the MSR + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r4,r0,0,MSR_EE_BIT,MSR_EE_BIT ; Turn off interruptions mtmsr r4 isync @@ -2352,5 +2367,4 @@ nnmax: stw r4,(48*4)(r3) mtmsr r0 isync -#endif blr diff --git a/osfmk/ppc/FirmwareCalls.h b/osfmk/ppc/FirmwareCalls.h index dd600c625..61fdb6b52 100644 --- a/osfmk/ppc/FirmwareCalls.h +++ b/osfmk/ppc/FirmwareCalls.h @@ -47,12 +47,6 @@ * */ - fwCallEnt(MPgetProcCountCall, MPgetProcCountLL) /* Call the MPgetProcCount routine */ - fwCallEnt(MPstartCall, MPstartLL) /* Call the MPstart routine */ - fwCallEnt(MPexternalHookCall, MPexternalHookLL) /* Get the address of the external interrupt handler */ - fwCallEnt(MPsignalCall, MPsignalLL) /* Call the MPsignal routine */ - fwCallEnt(MPstopCall, MPstopLL) /* Call the MPstop routine */ - fwCallEnt(dbgDispCall, dbgDispLL) /* Write stuff to printer or modem port */ fwCallEnt(dbgCkptCall, dbgCkptLL) /* Save 128 bytes from r3 to 0x380 V=R mapping */ fwCallEnt(StoreRealCall, StoreRealLL) /* Save one word in real storage */ @@ -70,17 +64,6 @@ fwCallEnt(PerfCtlCall, PerfCtlLL) /* Control performance monitor */ #endif -#if 0 - fwCallEnt(MPCPUAddressCall, 0) /* Call the MPCPUAddress routine */ - fwCallEnt(MPresumeCall, 0) /* Call the MPresume routine */ - fwCallEnt(MPresetCall, 0) /* Call the MPreset routine */ - fwCallEnt(MPSenseCall, 0) /* Call the MPSense routine */ - fwCallEnt(MPstoreStatusCall, 0) /* Call the MPstoreStatus routine */ - fwCallEnt(MPSetStatusCall, 0) /* Call the MPSetStatus routine */ - fwCallEnt(MPgetSignalCall, 0) /* Call the MPgetSignal routine */ - fwCallEnt(MPsyncTBCall, 0) /* Call the MPsyncTB routine */ - fwCallEnt(MPcheckPendingCall, 0) /* Call the MPcheckPending routine */ -#endif #endif /* _FIRMWARECALLS_H_ */ #else /* ASSEMBLER */ diff --git a/osfmk/ppc/Makefile b/osfmk/ppc/Makefile index 501264040..e9bdc4758 100644 --- a/osfmk/ppc/Makefile +++ b/osfmk/ppc/Makefile @@ -20,6 +20,7 @@ EXPORT_ONLY_FILES = \ proc_reg.h \ machine_routines.h \ Diagnostics.h \ + savearea.h \ mappings.h INSTALL_MD_LIST = ${DATAFILES} diff --git a/osfmk/ppc/POWERMAC/panic_image.c b/osfmk/ppc/POWERMAC/panic_image.c new file mode 100644 index 000000000..c130da354 --- /dev/null +++ b/osfmk/ppc/POWERMAC/panic_image.c @@ -0,0 +1,269 @@ + +//image_pixel_data +static const struct { + unsigned int pd_width; + unsigned int pd_height; + unsigned int bytes_per_pixel; /* 3:RGB, 4:RGBA */ + unsigned char image_pixel_data[0xbf62]; +} panic_dialog = { + 471, 258, 3, +0xff, 0xf3, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xf3, 0x8a, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4b, 0xe0, 0x03, 0x8c, 0x03, 0x7c, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0x8c, 0x90, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0xff, 0xe0, 0xfc, 0xe0, 0x03, 0xbd, 0x03, 0x60, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0x7c, 0x1e, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x12, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x21, 0xe0, 0x03, 00, 0x03, 0x9c, 0x6c, 0xe0, 0x03, 0x9c, 0x03, 00, 0x36, 0xe0, 0x0c, 0x60, 0x03, 0xad, 0x6f, 0xe0, 0x03, 00, 0x03, 0x9c, 0xe1, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4b, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xad, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0xad, 0x90, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0xad, 0x03, 0xbd, 0x66, 0xe0, 0x03, 0xbd, 0x03, 0xad, 0x30, 0xe0, 0x03, 0x9c, 0x03, 0xcf, 0xf6, 0xe0, 0x03, 0xad, 0x03, 0xbd, 0x45, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x1e, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x12, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x21, 0xe0, 0x03, 00, 0x03, 0x9c, 0x5d, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x36, 0xe0, 0x03, 00, 0x03, 0x45, 0x03, 0x60, 0x03, 0x38, 0x03, 00, 0x03, 0x8c, 0x6c, 0xe0, 0x03, 00, 0x03, 0x9c, 0x2a, 0xe0, 0x03, 0xad, 0x03, 0xbd, 0x09, 0xe0, 0x03, 0x9c, 0x03, 0xcf, 0xa2, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x45, 0x03, 0x2c, 0x06, 0xe0, 0x06, 0x52, 0x0c, 0xe0, 0x06, 0x9c, 0x39, 0xe0, 0x06, 0xad, 0x0f, 0xe0, 0x06, 0xad, 0x0f, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x0f, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x03, 0x60, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x0f, 0xe0, 0x06, 0x9c, 0x21, 0xe0, 0x03, 0x9c, 0x09, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x0f, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x0c, 0xe0, 0x03, 0xcf, 0x06, 0x9c, 0x12, 0xe0, 0x03, 0xad, 0x03, 0xcf, 0x03, 0xe0, 0x03, 00, 0x03, 0x9c, 0x2d, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xbd, 0x2a, 0xe0, 0x06, 0xbd, 0x15, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xbd, 0x09, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xbd, 0x12, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x0f, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xbd, 0x21, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x0c, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x12, 0xe0, 0x03, 0x9c, 0x1b, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x0c, 0xe0, 0x06, 0x9c, 0x0c, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x03, 0x60, 0x03, 0x2c, 0x18, 0xe0, 0x06, 0xad, 0x03, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xcf, 0x30, 0xe0, 0x06, 0xad, 0x15, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x0f, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x18, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x45, 0x03, 0x2c, 0x09, 0xe0, 0x06, 0x9c, 0x30, 0xe0, 0x03, 0x9c, 0x03, 0xbd, 0x12, 0xe0, 0x03, 0xad, 0x03, 0xcf, 0x0f, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xbd, 0x21, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x0c, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xad, 0x12, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x72, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0x9c, 0x03, 0xbd, 0x03, 0x0c, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x06, 0x20, 0x03, 0x16, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0x45, 0x03, 0x20, 0x03, 0x0c, 0x03, 0x52, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0x20, 0x03, 0x16, 0x03, 0x45, 0x09, 0xe0, 0x03, 0x45, 0x03, 0x16, 0x06, 0x20, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x7c, 0x03, 00, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x20, 0x03, 0x2c, 0x0f, 0xe0, 0x03, 0x60, 0x09, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x06, 0x20, 0x03, 0x16, 0x03, 0xad, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x03, 0x20, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x45, 0x03, 0x16, 0x06, 0x20, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x20, 0x03, 0x16, 0x03, 0x2c, 0x03, 0x38, 0x03, 0xe0, 0x03, 0x9c, 0x09, 00, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x6e, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x20, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0x38, 0x03, 0x2c, 0x03, 0xad, 0x03, 0x2c, 0x09, 00, 0x0c, 0xe0, 0x03, 0x8c, 0x03, 0x0c, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x52, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x52, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0x6e, 0x03, 0x20, 0x03, 0x7c, 0x0f, 0xe0, 0x03, 0xad, 0x06, 0x16, 0x03, 0x2c, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x52, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0x7c, 0x06, 0x16, 0x03, 0x20, 0x03, 0xad, 0x03, 0x16, 0x03, 0x20, 0x03, 0x0c, 0x03, 0xbd, 0x06, 0xe0, 0x03, 00, 0x03, 0x6e, 0x03, 0x16, 0x03, 0x2c, 0x03, 00, 0x03, 0x7c, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x60, 0x09, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x03, 0x20, 0x03, 0x2c, 0x1b, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x06, 0x20, 0x03, 0x16, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x7c, 0x03, 00, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x20, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 0x16, 0x03, 0x20, 0x03, 0x2c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x7c, 0x03, 0xe0, 0x06, 0x45, 0x06, 0xe0, 0x03, 0x52, 0x03, 00, 0x03, 0xbd, 0x06, 0xe0, 0x03, 0x0c, 0x03, 0xcf, 0x03, 0x60, 0x03, 0x2c, 0x03, 0x45, 0x03, 0x20, 0x03, 0x0c, 0x03, 0x52, 0x12, 0xe0, 0x09, 00, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0x7c, 0x06, 0x16, 0x03, 0x20, 0x09, 0xe0, 0x03, 0x45, 0x03, 0x16, 0x06, 0x20, 0x03, 0xcf, 0x12, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x06, 0x20, 0x03, 0x16, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x16, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x20, 0x03, 0x16, 0x06, 0xe0, 0x03, 0xad, 0x03, 0x20, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0x38, 0x03, 0x2c, 0x03, 0xad, 0x0f, 0xe0, 0x03, 00, 0x03, 0x6e, 0x03, 0x16, 0x03, 0x2c, 0x03, 00, 0x03, 0x7c, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x60, 0x09, 00, 0x03, 0x9c, 0x03, 0x2c, 0x09, 00, 0x06, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x2c, 0x03, 0xcf, 0x06, 0xe0, 0x03, 00, 0x03, 0x6e, 0x03, 0x16, 0x03, 0x20, 0x03, 0x0c, 0x03, 0xbd, 0x6f, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x51, 0xe0, 0x03, 0x52, 0x03, 0x20, 0x03, 0x2c, 0x03, 0x7c, 0x09, 0xe0, 0x03, 0x16, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0x60, 0x03, 00, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x8c, 0x03, 00, 0x06, 0xe0, 0x06, 0x45, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x6e, 0x03, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x38, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x16, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xbd, 0x06, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x6e, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xcf, 0x0c, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x60, 0x03, 00, 0x03, 0x8c, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x12, 0xe0, 0x03, 0x16, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x45, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0x52, 0x15, 0xe0, 0x03, 0x16, 0x03, 0x45, 0x0c, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0x45, 0x03, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0x20, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x20, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x2c, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x6e, 0x03, 0x0c, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x38, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xbd, 0x1e, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0x60, 0x06, 0x2c, 0x06, 0xe0, 0x03, 0x16, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x38, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0x52, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x45, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xbd, 0x03, 0x7c, 0x03, 0x16, 0x06, 0xe0, 0x06, 0x16, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x8c, 0x03, 0x38, 0x03, 0xe0, 0x03, 0x60, 0x03, 00, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x8c, 0x03, 00, 0x12, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0x45, 0x03, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x6e, 0x12, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x16, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x03, 0xe0, 0x06, 0x45, 0x03, 0xe0, 0x03, 0xbd, 0x03, 0x16, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x52, 0x03, 0x6e, 0x03, 0xe0, 0x03, 0x16, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0x06, 0xe0, 0x03, 0x60, 0x03, 00, 0x03, 0x8c, 0x15, 0xe0, 0x03, 00, 0x03, 0x2c, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x6e, 0x03, 0x0c, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x45, 0x06, 0xe0, 0x03, 00, 0x03, 0x20, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x20, 0x03, 0x60, 0x6f, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x51, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0x60, 0x03, 0x20, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x0c, 0x03, 0x6e, 0x06, 0x9c, 0x03, 0x20, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x38, 0x03, 0x45, 0x06, 0x9c, 0x03, 0x45, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0xad, 0x0f, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x38, 0x03, 0x45, 0x06, 0x9c, 0x03, 0x45, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0x45, 0x03, 0xcf, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x0f, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x0c, 0xe0, 0x03, 00, 0x03, 0x9c, 0x12, 0xe0, 0x03, 0x52, 0x03, 0x20, 0x06, 0xe0, 0x03, 0x16, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x38, 0x03, 0x52, 0x09, 0xe0, 0x03, 0x52, 0x03, 0x38, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x15, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0xbd, 0x0c, 0xe0, 0x03, 0x38, 0x03, 0x52, 0x09, 0xe0, 0x03, 0x52, 0x03, 0x38, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x6e, 0x03, 0x20, 0x06, 0x9c, 0x03, 0x6e, 0x03, 00, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x21, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0x60, 0x06, 0x2c, 0x03, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0x16, 0x03, 0x7c, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x0c, 0x03, 0x8c, 0x09, 0xe0, 0x03, 0x20, 0x03, 0x6e, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x03, 0xad, 0x03, 0x20, 0x06, 0x45, 0x03, 0xe0, 0x03, 0x45, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x20, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x12, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xcf, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x38, 0x03, 0x45, 0x06, 0x9c, 0x03, 0x45, 0x03, 0x2c, 0x12, 0xe0, 0x03, 00, 0x03, 0x20, 0x03, 0x2c, 0x03, 00, 0x03, 0x52, 0x03, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0xad, 0x03, 0x7c, 0x03, 0x16, 0x03, 0xe0, 0x03, 0x6e, 0x03, 0x52, 0x03, 0x16, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x16, 0x03, 0xbd, 0x03, 0xad, 0x03, 00, 0x09, 0x9c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x18, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x6e, 0x03, 0x20, 0x09, 0xe0, 0x03, 0x8c, 0x03, 0x0c, 0x06, 0xe0, 0x03, 00, 0x03, 0x8c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x6f, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x54, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 00, 0x03, 0x20, 0x09, 0x2c, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x16, 0x09, 0x2c, 0x03, 0x52, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0xe0, 0x03, 00, 0x03, 0x9c, 0x0f, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x16, 0x09, 0x2c, 0x03, 0x52, 0x06, 0xe0, 0x03, 0x9c, 0x03, 0x16, 0x03, 00, 0x03, 0x6e, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0xad, 0x06, 0x16, 0x03, 0x2c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x0c, 0xe0, 0x03, 00, 0x03, 0x9c, 0x12, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xad, 0x03, 0x7c, 0x03, 0x38, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x15, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0f, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x0c, 0x0c, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x21, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x12, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x16, 0x03, 0x7c, 0x03, 0x60, 0x03, 0x52, 0x03, 0x7c, 0x03, 0x16, 0x03, 0xe0, 0x03, 0x0c, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x12, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x16, 0x09, 0x2c, 0x03, 0x52, 0x12, 0xe0, 0x03, 00, 0x03, 0x6e, 0x03, 0x9c, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x03, 0x2c, 0x03, 0x8c, 0x06, 0x45, 0x03, 0xad, 0x03, 0x20, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0x2c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x18, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x6f, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x54, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x16, 0x03, 0x7c, 0x0f, 0xe0, 0x06, 0x45, 0x0f, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0xad, 0x0f, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x06, 0x45, 0x18, 0xe0, 0x03, 0x7c, 0x03, 00, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x16, 0x03, 0x52, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x0c, 0xe0, 0x03, 00, 0x03, 0x9c, 0x15, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x03, 0x20, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x38, 0x03, 0x52, 0x09, 0xe0, 0x03, 0x52, 0x03, 0x38, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x15, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x0c, 0xe0, 0x03, 0x38, 0x03, 0x52, 0x09, 0xe0, 0x03, 0x52, 0x03, 0x38, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x20, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x21, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x12, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x0c, 0x03, 0x8c, 0x09, 0xe0, 0x03, 0x20, 0x03, 0x6e, 0x03, 0xe0, 0x06, 0x45, 0x03, 0x20, 0x03, 0xad, 0x03, 0xbd, 0x03, 00, 0x03, 0x6e, 0x03, 0x38, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x12, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x06, 0x45, 0x1e, 0xe0, 0x03, 00, 0x03, 0x9c, 0x0c, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x16, 0x03, 0x6e, 0x03, 0x0c, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x03, 0x52, 0x03, 0x6e, 0x03, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x0f, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x18, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x20, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x6e, 0x03, 0x20, 0x09, 0xe0, 0x03, 0x8c, 0x03, 0x0c, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x6f, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x54, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x0c, 0xe0, 0x03, 0x16, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xad, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0xad, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x45, 0x09, 0xe0, 0x03, 0x16, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xad, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x09, 0xe0, 0x03, 00, 0x03, 0x8c, 0x03, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x0c, 0xe0, 0x03, 00, 0x03, 0x7c, 0x15, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0x16, 0x09, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x45, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x18, 0xe0, 0x03, 0x2c, 0x03, 0x45, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x03, 0xdf, 0x03, 0xe0, 0x03, 00, 0x03, 0x8b, 0x03, 0xdd, 0x03, 0x7b, 0x03, 00, 0x03, 0x5d, 0x03, 0xd7, 0x03, 0xd6, 0x03, 0x2a, 0x03, 0x41, 0x03, 0xd0, 0x03, 0xcf, 0x03, 0xbe, 0x03, 0x0c, 0x03, 0x65, 0x06, 0xcb, 0x03, 0xbd, 0x06, 0xce, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xd3, 0x03, 0xd4, 0x03, 0xd6, 0x03, 0x96, 0x03, 0x5d, 0x03, 0xdb, 0x03, 0xdc, 0x03, 0xdd, 0x06, 0xdf, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x16, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0xad, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x03, 0x2c, 0x12, 0xe0, 0x06, 0x38, 0x06, 0xe0, 0x03, 0x52, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x45, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x6e, 0x06, 0x16, 0x06, 0xe0, 0x06, 0x16, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x12, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xbd, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xad, 0x06, 0xe0, 0x03, 0xcf, 0x12, 0xe0, 0x03, 00, 0x03, 0x9c, 0x0f, 0xe0, 0x03, 0x16, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x38, 0x03, 0x16, 0x03, 0x45, 0x03, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0x16, 0x03, 0xbd, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x38, 0x09, 0xe0, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x18, 0xe0, 0x03, 00, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x06, 0xe0, 0x03, 00, 0x03, 0x8c, 0x03, 0xe0, 0x03, 0x7c, 0x03, 00, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x45, 0x09, 0xe0, 0x03, 00, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x45, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x6f, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x54, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x0c, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x06, 0x20, 0x03, 0x16, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x8c, 0x03, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x52, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x38, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x6e, 0x06, 0xe0, 0x03, 0x6e, 0x03, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x38, 0x06, 0xe0, 0x03, 0x45, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x52, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0x8c, 0x03, 00, 0x03, 0x2c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x06, 0x20, 0x03, 0x16, 0x03, 0xad, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x0c, 0xe0, 0x03, 0x6e, 0x03, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x38, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x45, 0x06, 0xe0, 0x03, 0xbd, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x52, 0x03, 0x0c, 0x09, 0x2c, 0x03, 0x16, 0x03, 0xad, 0x03, 0x60, 0x03, 0x2c, 0x0c, 0xe0, 0x03, 0x52, 0x03, 0x0c, 0x03, 0x2c, 0x15, 0xe0, 0x03, 0x0c, 0x03, 0x7c, 0x0c, 0xe0, 0x03, 0x52, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x52, 0x09, 0xe0, 0x03, 0x20, 0x06, 0x16, 0x03, 0x7c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x18, 0xe0, 0x03, 0xad, 0x06, 0x16, 0x03, 0x2c, 0x03, 0x0c, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x52, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x20, 0x03, 0x0c, 0x03, 0xab, 0x06, 0xdd, 0x03, 0x51, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x42, 0x03, 0x2a, 0x03, 0x5c, 0x03, 0xd4, 0x03, 0xd3, 0x03, 0x84, 0x03, 00, 0x03, 0x29, 0x03, 0x9f, 0x03, 0xce, 0x03, 0x90, 0x03, 0x0c, 0x03, 0x1e, 0x03, 0x29, 0x03, 0x0c, 0x06, 0xce, 0x03, 0x29, 0x03, 0x59, 0x03, 0xd0, 0x03, 0xd1, 0x03, 0xd3, 0x03, 0x5b, 0x03, 00, 0x03, 0xd7, 0x03, 0xda, 0x06, 0xdb, 0x03, 0xdc, 0x03, 0xdd, 0x03, 0x9b, 0x03, 00, 0x06, 0xdf, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x06, 0x20, 0x03, 0x16, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x45, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x52, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x16, 0x03, 0x7c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0x52, 0x06, 0xe0, 0x03, 0x45, 0x03, 00, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x15, 0xe0, 0x03, 0x20, 0x03, 0x16, 0x03, 0x52, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x6e, 0x03, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x38, 0x12, 0xe0, 0x03, 00, 0x03, 0x9c, 0x0f, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x06, 0x20, 0x03, 0x16, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x6e, 0x03, 00, 0x03, 0x8c, 0x06, 0xe0, 0x03, 0x16, 0x03, 0x20, 0x09, 0xe0, 0x03, 0xbd, 0x03, 0x20, 0x03, 0x16, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x18, 0xe0, 0x03, 00, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x20, 0x03, 0x0c, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x45, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x8c, 0x03, 00, 0x03, 0x2c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x52, 0x03, 0x0c, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x2c, 0x03, 0xcf, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x6f, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x6c, 0xe0, 0x06, 0x9c, 0x0f, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x39, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xcf, 0x0c, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xbd, 0x0c, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x1e, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x0c, 0xe0, 0x06, 0x9c, 0x2d, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xbd, 0x09, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xad, 0x0c, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x06, 0xe0, 0x06, 0xad, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x18, 0xe0, 0x06, 0xad, 0x12, 0xe0, 0x03, 0xbd, 0x03, 0x0c, 0x12, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xbd, 0x0f, 0xe0, 0x03, 0x9c, 0x03, 0xbd, 0x30, 0xe0, 0x06, 0x9c, 0x0c, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xbd, 0x30, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xbb, 0x03, 0x9a, 0x03, 0xda, 0x03, 0xd7, 0x06, 0xd6, 0x03, 0xd4, 0x06, 0xa4, 0x06, 0xd3, 0x06, 0xd1, 0x06, 0xd0, 0x03, 0xb0, 0x03, 0x92, 0x0c, 0xd0, 0x03, 0x91, 0x03, 0x9f, 0x18, 0xd0, 0x06, 0xd1, 0x06, 0xd3, 0x09, 0xd4, 0x06, 0xd6, 0x03, 0xd7, 0x03, 0xda, 0x03, 0xdc, 0x03, 0xdd, 0x03, 0xdf, 0x12, 0xe0, 0x06, 0x9c, 0x1b, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x1e, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xbd, 0x12, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xcf, 0x51, 0xe0, 0x03, 0x9c, 0x03, 0xbd, 0x21, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xbd, 0x30, 0xe0, 0x06, 0x9c, 0x30, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x27, 0xe0, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x0f, 0xe0, 0x06, 0xad, 0x12, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x09, 0xe0, 0x06, 0xad, 0x09, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xad, 0x8d, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xc9, 0xe0, 0x03, 0x52, 0x03, 0x60, 0x9f, 0xe0, 0x06, 0xdf, 0x03, 0xdd, 0x03, 0xdc, 0x03, 00, 0x03, 0x99, 0x03, 0xd9, 0x03, 0xd6, 0x03, 0xd4, 0x03, 0xd1, 0x03, 0xce, 0x06, 0xcd, 0x09, 0xce, 0x09, 0xcf, 0x0c, 0xd0, 0x1e, 0xd1, 0x0c, 0xd0, 0x09, 0xcf, 0x09, 0xce, 0x06, 0xcd, 0x03, 0xce, 0x03, 0xd1, 0x03, 0xd4, 0x03, 0xd6, 0x03, 0xd9, 0x03, 0xdb, 0x06, 0xdc, 0x03, 0xdd, 0x06, 0xdf, 0xff, 0xe0, 0xff, 0xe0, 0x69, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xc9, 0xe0, 0x03, 0x6e, 0x03, 0xcf, 0x9c, 0xe0, 0x03, 0xdf, 0x03, 0xdd, 0x03, 0xdb, 0x03, 0xd7, 0x03, 0xd4, 0x03, 0x5a, 0x03, 0xb0, 0x3f, 0xd0, 0x06, 0xd1, 0x45, 0xd0, 0x03, 0xd4, 0x03, 0xd7, 0x03, 0xdb, 0x03, 0xdd, 0x03, 0xdf, 0xff, 0xe0, 0xff, 0xe0, 0x66, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0x60, 0xe0, 0x03, 0xdf, 0x06, 0xdd, 0x03, 0xdb, 0x03, 0xd9, 0x03, 0xd5, 0x03, 0xd4, 0x03, 0xd1, 0x03, 0xcf, 0x03, 0xcd, 0x06, 0xce, 0x03, 0xcf, 0x06, 0xd0, 0x12, 0xd1, 0x48, 0xd0, 0x12, 0xd1, 0x06, 0xd0, 0x03, 0xcf, 0x06, 0xce, 0x03, 0xcd, 0x03, 0xcf, 0x03, 0xd1, 0x03, 0xd4, 0x03, 0xd5, 0x03, 0xd9, 0x03, 0xdb, 0x06, 0xdd, 0x03, 0xdf, 0xff, 0xe0, 0xff, 0xe0, 0x5a, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0x5a, 0xe0, 0x06, 0xdf, 0x03, 0xdc, 0x03, 0xd9, 0x03, 0xd4, 0x03, 0xcf, 0x06, 0xcd, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd0, 0x09, 0xd1, 0x7e, 0xd0, 0x09, 0xd1, 0x03, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x06, 0xcd, 0x03, 0xcf, 0x03, 0xd4, 0x03, 0xd9, 0x03, 0xdc, 0x06, 0xdf, 0xff, 0xe0, 0xff, 0xe0, 0x54, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x54, 0xe0, 0x03, 0x9c, 0x03, 0xad, 0xff, 0xe0, 0xf9, 0xe0, 0x03, 0xdf, 0x03, 0xdc, 0x03, 0xd7, 0x03, 0xd5, 0x03, 0xd3, 0x03, 0xd1, 0x03, 0xd0, 0x03, 0xcf, 0xae, 0xd0, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xd1, 0x03, 0xd3, 0x03, 0xd5, 0x03, 0xd7, 0x03, 0xdc, 0x03, 0xdf, 0xff, 0xe0, 0xff, 0xe0, 0x4e, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x06, 0x20, 0x03, 0x9c, 0xab, 0xe0, 0x03, 0x9c, 0x03, 00, 0x8d, 0xe0, 0x03, 0x9c, 0x03, 00, 0xab, 0xe0, 0x03, 0xdf, 0x03, 0xdc, 0x03, 0xda, 0x03, 0xd6, 0x03, 0xd3, 0x09, 0xcf, 0x18, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x36, 0xd0, 0x0c, 0x5a, 0x03, 0xa0, 0x57, 0xd0, 0x09, 0xcf, 0x03, 0xd3, 0x03, 0xd6, 0x03, 0xda, 0x03, 0xdc, 0x03, 0xdf, 0x12, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0xff, 0xe0, 0xff, 0xe0, 0x30, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x6e, 0x03, 0x20, 0xb4, 0xe0, 0x03, 0x9c, 0x03, 00, 0x8d, 0xe0, 0x03, 0x9c, 0x03, 00, 0xa2, 0xe0, 0x06, 0xdf, 0x03, 0xdc, 0x03, 0xd9, 0x03, 0xd3, 0x1b, 0xd0, 0x03, 0xbf, 0x03, 0x92, 0x09, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x36, 0xd0, 0x03, 00, 0x03, 0x41, 0x03, 0x5a, 0x03, 0x34, 0x03, 00, 0x03, 0x83, 0x30, 0xd0, 0x03, 0x92, 0x03, 0xbf, 0x2d, 0xd0, 0x03, 0xb0, 0x03, 0xa3, 0x03, 0xd9, 0x03, 0xdc, 0x06, 0xdf, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x2a, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x09, 0xe0, 0x03, 0xbd, 0x03, 0xad, 0xff, 0xe0, 0xf0, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x0c, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xad, 0x12, 0xe0, 0x03, 0xcf, 0x03, 0xad, 0x12, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xad, 0x0c, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x21, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x12, 0xe0, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0x9c, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x18, 0xe0, 0x06, 0x9c, 0x0f, 0xe0, 0x03, 0x9c, 0x03, 0xbd, 0x0f, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xad, 0x0c, 0xe0, 0x06, 0x9c, 0x15, 0xe0, 0x03, 0x9c, 0x03, 0xbd, 0x0f, 0xe0, 0x03, 0x9c, 0x03, 0xbd, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xad, 0x1b, 0xe0, 0x06, 0x9c, 0x15, 0xe0, 0x03, 0x9c, 0x18, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x12, 0xe0, 0x06, 0xbd, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x0c, 0xe0, 0x03, 0xbc, 0x03, 0x9c, 0x03, 0xbb, 0x03, 0xd9, 0x03, 0xd5, 0x03, 0xd0, 0x03, 0xce, 0x03, 0x9f, 0x03, 0x91, 0x03, 0xbf, 0x12, 0xd0, 0x03, 0x92, 0x03, 00, 0x09, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x03, 0xd0, 0x06, 0xa0, 0x0f, 0xd0, 0x06, 0xa0, 0x18, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x41, 0x03, 0x29, 0x0c, 0xd0, 0x03, 0x92, 0x03, 0xb0, 0x0c, 0xd0, 0x03, 0xbf, 0x03, 0x92, 0x03, 0xa0, 0x09, 0xd0, 0x03, 00, 0x03, 0x92, 0x0c, 0xd0, 0x03, 0xa0, 0x03, 0x92, 0x03, 0xb0, 0x0f, 0xd0, 0x03, 0xbf, 0x03, 0xa0, 0x03, 0xcf, 0x03, 0x59, 0x03, 0x29, 0x03, 0xd0, 0x03, 0xd5, 0x03, 0xd9, 0x03, 0xdd, 0x06, 0xdf, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x21, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x0f, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xcf, 0x12, 0xe0, 0x03, 0x9c, 0x03, 0xbd, 0xff, 0xe0, 0xc0, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4b, 0xe0, 0x03, 0x60, 0x09, 00, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x2c, 0x03, 0xcf, 0x06, 0xe0, 0x03, 00, 0x03, 0x60, 0x03, 0x20, 0x03, 0x52, 0x0f, 0xe0, 0x03, 0x8c, 0x03, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x20, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x52, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x03, 0x20, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x6e, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x20, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x12, 0xe0, 0x03, 0xbd, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x06, 0x20, 0x03, 0x16, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x03, 0x20, 0x03, 0x2c, 0x03, 00, 0x03, 0x8c, 0x06, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x16, 0x03, 0x2c, 0x03, 00, 0x06, 0xe0, 0x03, 0x8c, 0x03, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x9c, 0x12, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x06, 0x20, 0x03, 0x16, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x03, 0x20, 0x03, 0x2c, 0x0f, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0x45, 0x03, 0x20, 0x03, 0x16, 0x03, 0x20, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0x6e, 0x03, 0x20, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x51, 0x03, 0x0c, 0x03, 0x2a, 0x03, 0x15, 0x03, 0xd0, 0x06, 0xcf, 0x03, 0x1f, 0x03, 0x15, 0x03, 0x29, 0x03, 0x34, 0x12, 0xd0, 0x09, 00, 0x03, 0x29, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x03, 0x41, 0x03, 0x1f, 0x03, 0x0c, 0x03, 0x4c, 0x06, 0xd0, 0x03, 0xbf, 0x06, 0x1f, 0x03, 0x15, 0x03, 0x41, 0x15, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x4c, 0x03, 0x34, 0x06, 0xd0, 0x03, 0xa0, 0x03, 0x0c, 0x03, 0x29, 0x03, 0x0c, 0x03, 0x74, 0x06, 0xd0, 0x03, 0x83, 0x03, 00, 0x03, 0x29, 0x03, 0x1f, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x29, 0x09, 00, 0x06, 0xd0, 0x03, 0x0c, 0x03, 0x1f, 0x03, 0x29, 0x03, 00, 0x03, 0x83, 0x06, 0xd0, 0x03, 00, 0x03, 0x5a, 0x03, 0x1f, 0x03, 0x4c, 0x03, 0x92, 0x09, 00, 0x03, 0x59, 0x03, 0xd0, 0x03, 0xd5, 0x03, 0xda, 0x03, 0xdc, 0x03, 0xdd, 0x03, 0x60, 0x03, 0x2c, 0x03, 0x45, 0x03, 0x20, 0x03, 0x16, 0x03, 0x20, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x09, 00, 0x03, 0x2c, 0x03, 0x9c, 0x09, 00, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x03, 0x20, 0x03, 0x2c, 0x03, 00, 0x03, 0x8c, 0xff, 0xe0, 0xbd, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x45, 0x06, 0xe0, 0x03, 00, 0x03, 0x2c, 0x03, 0xcf, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x0c, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x38, 0x03, 0xe0, 0x03, 0x6e, 0x03, 0x16, 0x09, 0xe0, 0x03, 0x0c, 0x06, 0xbd, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x38, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xbd, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x12, 0xe0, 0x03, 0x60, 0x03, 0x20, 0x0f, 0xe0, 0x03, 0x16, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0x06, 0xe0, 0x03, 0x45, 0x03, 0x20, 0x03, 0xcf, 0x0c, 0xe0, 0x03, 0x16, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x52, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x20, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 00, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x1b, 0xe0, 0x03, 0x16, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xbd, 0x12, 0xe0, 0x03, 0x60, 0x03, 00, 0x03, 0x8c, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x16, 0x03, 0x6e, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0x52, 0x06, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x38, 0x03, 0xdf, 0x03, 0xdc, 0x03, 00, 0x03, 0x85, 0x03, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xcf, 0x03, 0x92, 0x03, 00, 0x03, 0xc1, 0x03, 0xd1, 0x15, 0xd0, 0x03, 0x92, 0x03, 00, 0x09, 0xd0, 0x03, 0x5a, 0x03, 00, 0x03, 0x74, 0x03, 0xd0, 0x03, 0x83, 0x03, 00, 0x06, 0xd0, 0x06, 0x41, 0x03, 0xd0, 0x03, 0xbf, 0x03, 0x0c, 0x03, 0xa0, 0x12, 0xd0, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x74, 0x03, 0x15, 0x03, 0xa0, 0x06, 0xd0, 0x03, 0x15, 0x03, 0x74, 0x03, 0xd0, 0x03, 0x92, 0x03, 0x0c, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x4c, 0x0f, 0xd0, 0x03, 00, 0x03, 0x92, 0x09, 0xd0, 0x03, 0xbf, 0x06, 0xd0, 0x03, 0x4c, 0x03, 0x29, 0x06, 0xd0, 0x03, 00, 0x03, 0x29, 0x03, 0xbf, 0x03, 0xd0, 0x03, 0xd1, 0x03, 0x5a, 0x03, 0x29, 0x03, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xd4, 0x03, 0xd7, 0x03, 0x5f, 0x03, 00, 0x03, 0x8c, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x16, 0x03, 0x6e, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x45, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x52, 0x03, 0x2c, 0xff, 0xe0, 0xbd, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x6e, 0x03, 0x20, 0x09, 0xe0, 0x03, 0x8c, 0x03, 0x0c, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x15, 0xe0, 0x03, 0x45, 0x03, 0x0c, 0x03, 0x9c, 0x09, 0xe0, 0x03, 0x6e, 0x03, 0x20, 0x06, 0x9c, 0x03, 0x6e, 0x03, 00, 0x03, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x38, 0x03, 0xe0, 0x03, 0x6e, 0x03, 0x20, 0x06, 0x9c, 0x03, 0x6e, 0x03, 00, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x0f, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x12, 0xe0, 0x03, 0x7c, 0x03, 00, 0x03, 0x6e, 0x09, 0xe0, 0x03, 0xad, 0x03, 00, 0x09, 0x9c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x0c, 0x03, 0x7c, 0x0c, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x45, 0x03, 0x0c, 0x03, 0x9c, 0x15, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x15, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x6e, 0x03, 0x20, 0x06, 0x9c, 0x03, 0x6d, 0x03, 00, 0x03, 0xdc, 0x03, 0xd6, 0x03, 0x15, 0x03, 0x1e, 0x03, 0xae, 0x03, 0xd0, 0x03, 0xd1, 0x03, 0xd0, 0x03, 0xb0, 0x03, 00, 0x03, 0x41, 0x03, 0xbf, 0x15, 0xd0, 0x03, 0x92, 0x03, 00, 0x09, 0xd0, 0x03, 0x5a, 0x03, 0x1f, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0x0c, 0x03, 0x67, 0x06, 0x92, 0x03, 0x1f, 0x03, 0x5a, 0x12, 0xd0, 0x09, 00, 0x03, 0x0c, 0x03, 0xb0, 0x06, 0xd0, 0x03, 0xa0, 0x03, 00, 0x09, 0x92, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x41, 0x03, 0x0c, 0x03, 0x92, 0x0c, 0xd0, 0x03, 00, 0x03, 0x92, 0x0c, 0xd0, 0x03, 0xbf, 0x03, 0x92, 0x03, 0x41, 0x03, 0x29, 0x06, 0xd0, 0x03, 00, 0x03, 0x92, 0x09, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0xd1, 0x03, 0xd0, 0x06, 0xce, 0x03, 0xd0, 0x03, 0x5c, 0x03, 0x2b, 0x03, 0xdd, 0x03, 0xdf, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x0c, 0x03, 0x8c, 0x09, 0xe0, 0x03, 0x20, 0x03, 0x6e, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0xff, 0xe0, 0xbd, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x15, 0xe0, 0x03, 0xcf, 0x03, 0x52, 0x03, 00, 0x03, 0x20, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x0c, 0x0c, 0x2c, 0x06, 0xe0, 0x03, 0x38, 0x03, 0x45, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x8c, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x0c, 0x0c, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0xad, 0x06, 0x16, 0x03, 0x2c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x15, 0xe0, 0x03, 0x6e, 0x06, 0x0c, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0x2c, 0x03, 0xad, 0x03, 0xe0, 0x03, 00, 0x03, 0x9c, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x52, 0x03, 00, 0x03, 0x20, 0x03, 0xbd, 0x0f, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x15, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x0c, 0x06, 0x2c, 0x03, 0x2b, 0x03, 0x2a, 0x03, 0xd1, 0x03, 0xd0, 0x03, 0xb0, 0x03, 0x29, 0x03, 00, 0x03, 0x34, 0x09, 0xd0, 0x03, 0x92, 0x03, 0x15, 0x03, 00, 0x03, 0x67, 0x12, 0xd0, 0x03, 0x92, 0x03, 00, 0x09, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 00, 0x03, 0x1f, 0x09, 0x29, 0x03, 0x74, 0x12, 0xd0, 0x03, 00, 0x03, 0x92, 0x03, 0xa0, 0x03, 0x0c, 0x03, 0x74, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x0c, 0x29, 0x03, 0xa0, 0x03, 0xd0, 0x03, 0xbf, 0x03, 0x4c, 0x03, 00, 0x03, 0x1f, 0x03, 0xb0, 0x06, 0xd0, 0x03, 00, 0x03, 0x92, 0x09, 0xd0, 0x03, 0x4c, 0x03, 00, 0x03, 0x29, 0x03, 0x15, 0x03, 0x29, 0x06, 0xd0, 0x03, 00, 0x03, 0x92, 0x09, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x15, 0xd0, 0x03, 0x5a, 0x03, 0x2a, 0x03, 0xd7, 0x03, 0xdc, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0xff, 0xe0, 0xbd, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x6e, 0x03, 0x20, 0x09, 0xe0, 0x03, 0x8c, 0x03, 0x0c, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x1b, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 0x38, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x12, 0xe0, 0x03, 0x8c, 0x03, 0x0c, 0x03, 0xad, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x16, 0x03, 0x52, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x1b, 0xe0, 0x03, 0x45, 0x03, 0x0c, 0x03, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x0f, 0xe0, 0x03, 0x16, 0x03, 0x7c, 0x0c, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 0x38, 0x0f, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x15, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x06, 0x45, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x03, 0xdf, 0x03, 0xdb, 0x03, 0xd5, 0x03, 0xd1, 0x06, 0xcf, 0x06, 0xd0, 0x03, 0xa0, 0x03, 0x0c, 0x03, 0x67, 0x0c, 0xd0, 0x03, 0x74, 0x03, 00, 0x03, 0xa0, 0x0f, 0xd0, 0x03, 0x92, 0x03, 00, 0x09, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0x15, 0x03, 0x74, 0x1e, 0xd0, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x74, 0x03, 0x0c, 0x03, 0xa0, 0x03, 0xd0, 0x03, 0xb0, 0x03, 00, 0x03, 0xb0, 0x15, 0xd0, 0x03, 0xbf, 0x03, 0x1f, 0x03, 0x34, 0x06, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x74, 0x03, 0x0c, 0x03, 0xb0, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 00, 0x03, 0x92, 0x09, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x15, 0xd0, 0x03, 0x59, 0x03, 0x29, 0x03, 0xd1, 0x03, 0xd5, 0x03, 0xdb, 0x03, 0x44, 0x03, 0x45, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x8c, 0x03, 00, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x0c, 0x03, 0x8c, 0x09, 0xe0, 0x03, 0x20, 0x03, 0x6e, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0xff, 0xe0, 0xbd, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x45, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x15, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x38, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0x6e, 0x06, 0xe0, 0x03, 0xcf, 0x09, 0xe0, 0x03, 0x0c, 0x03, 0x16, 0x03, 0x60, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0x6e, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 00, 0x03, 0x8c, 0x03, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x12, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x8c, 0x03, 0x0c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x38, 0x09, 0xe0, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x20, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x16, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x0c, 0x03, 0x6e, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x2c, 0x03, 00, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x38, 0x12, 0xe0, 0x03, 0x16, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x15, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0xce, 0x03, 0x0c, 0x03, 0x6b, 0x03, 0xd1, 0x03, 0xce, 0x03, 0xbe, 0x06, 0xd0, 0x03, 0xbf, 0x06, 0xd0, 0x03, 0x1f, 0x03, 0x67, 0x03, 0xd0, 0x03, 0xbf, 0x06, 0xd0, 0x03, 0xbf, 0x03, 00, 0x03, 0xa0, 0x0f, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0xb0, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x15, 0x03, 0xbf, 0x06, 0xd0, 0x03, 0xbf, 0x12, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x41, 0x03, 0x1f, 0x03, 0xbf, 0x03, 0xd0, 0x03, 0x29, 0x03, 0x34, 0x09, 0xd0, 0x03, 0xbf, 0x03, 0xd0, 0x03, 0xbf, 0x06, 0xd0, 0x03, 0x4c, 0x03, 0x34, 0x06, 0xd0, 0x03, 00, 0x03, 0x74, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x1f, 0x06, 0xd0, 0x03, 0x41, 0x03, 0x29, 0x06, 0xd0, 0x03, 00, 0x03, 0x92, 0x09, 0xd0, 0x03, 0x5a, 0x03, 0x15, 0x15, 0xd0, 0x03, 0x5a, 0x03, 0x15, 0x03, 0xaf, 0x03, 0xce, 0x03, 0xc1, 0x03, 0x0c, 0x03, 0x7b, 0x03, 0xdf, 0x03, 0x60, 0x03, 0x20, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 00, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xbd, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x09, 0xe0, 0x03, 0x45, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 0x60, 0xff, 0xe0, 0xb1, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x2c, 0x03, 0xcf, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x15, 0xe0, 0x03, 0x38, 0x06, 0x20, 0x03, 0x0c, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x2c, 0x03, 0x0c, 0x09, 0xe0, 0x03, 0x52, 0x03, 00, 0x03, 0xcf, 0x09, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x2c, 0x03, 0x0c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x52, 0x03, 0x0c, 0x09, 0x2c, 0x03, 0x16, 0x03, 0xad, 0x03, 0x9c, 0x03, 00, 0x12, 0xe0, 0x03, 0x6e, 0x03, 0x16, 0x03, 0x2c, 0x03, 00, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0xbd, 0x03, 0x20, 0x03, 0x16, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x06, 0x20, 0x03, 0x16, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x7c, 0x03, 00, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x6e, 0x03, 00, 0x06, 0xe0, 0x03, 0x38, 0x06, 0x20, 0x03, 0x0c, 0x03, 0xad, 0x12, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x06, 0x20, 0x03, 0x16, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x15, 0xe0, 0x03, 0x60, 0x06, 0x16, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x45, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0xdd, 0x03, 0xdb, 0x03, 0x95, 0x03, 0x0c, 0x03, 0x1f, 0x03, 0x29, 0x03, 0x0c, 0x06, 0xd0, 0x03, 0x0c, 0x03, 0x29, 0x03, 0x15, 0x03, 0x1f, 0x03, 0xbf, 0x03, 0xd0, 0x03, 0xa0, 0x03, 0x0c, 0x03, 0x29, 0x03, 0x0c, 0x03, 0x41, 0x15, 0xd0, 0x03, 0x1f, 0x03, 0x15, 0x03, 0x4c, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x09, 0xd0, 0x03, 0x34, 0x03, 0x0c, 0x03, 0x29, 0x03, 0x15, 0x03, 0x67, 0x12, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0xbf, 0x03, 0x1f, 0x03, 0x41, 0x03, 0xd0, 0x03, 0xb0, 0x03, 0x1f, 0x03, 0x15, 0x03, 0x29, 0x03, 0x0c, 0x03, 0xa0, 0x03, 0xd0, 0x03, 0x34, 0x06, 0x1f, 0x03, 0x0c, 0x03, 0xa0, 0x06, 0xd0, 0x03, 0x4c, 0x03, 0x0c, 0x03, 0x29, 0x03, 0xd0, 0x03, 0xb0, 0x03, 0x0c, 0x06, 0x1f, 0x03, 0x4c, 0x03, 00, 0x03, 0x4c, 0x03, 0xd0, 0x03, 00, 0x03, 0x92, 0x09, 0xd0, 0x03, 0xb0, 0x03, 0x0c, 0x03, 0x1f, 0x03, 0x74, 0x0f, 0xd0, 0x03, 0x5a, 0x06, 0x15, 0x03, 0x29, 0x03, 0x0c, 0x03, 0x41, 0x03, 0xd5, 0x03, 0xdb, 0x03, 0xbb, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x16, 0x03, 0x6e, 0x03, 00, 0x09, 0xe0, 0x03, 0x20, 0x03, 0x16, 0x03, 0x52, 0x03, 0xe0, 0x03, 0xbd, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x60, 0x03, 00, 0xff, 0xe0, 0xb1, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x60, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xad, 0x2a, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xcf, 0x0f, 0xe0, 0x03, 0x9c, 0x03, 0xad, 0x24, 0xe0, 0x03, 0x9c, 0x03, 0xad, 0x1b, 0xe0, 0x06, 0xad, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x1e, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xbd, 0x0f, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x0f, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xcf, 0x0c, 0xe0, 0x06, 0x9c, 0x27, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xcf, 0x0f, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xcf, 0x1b, 0xe0, 0x06, 0x9c, 0x27, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 0xbd, 0x0f, 0xe0, 0x03, 0xdf, 0x03, 0xdd, 0x03, 0xd9, 0x03, 0xd4, 0x03, 0xd0, 0x03, 0xcf, 0x03, 0x92, 0x03, 0xa0, 0x0c, 0xd0, 0x06, 0x92, 0x0c, 0xd0, 0x03, 0xbf, 0x03, 0x92, 0x03, 0xa0, 0x1b, 0xd0, 0x03, 0x92, 0x03, 0xb0, 0x21, 0xd0, 0x03, 0xb0, 0x03, 0x92, 0x03, 0xbf, 0x33, 0xd0, 0x03, 0xa0, 0x03, 0x92, 0x0c, 0xd0, 0x03, 0xa0, 0x03, 0x92, 0x03, 0xbf, 0x0c, 0xd0, 0x06, 0xa0, 0x06, 0xd0, 0x03, 0xbf, 0x03, 0x92, 0x03, 0xbf, 0x03, 0xd0, 0x03, 0xa0, 0x03, 0xb0, 0x15, 0xd0, 0x03, 0xbf, 0x03, 0x92, 0x03, 0xbf, 0x0f, 0xd0, 0x06, 0xb0, 0x03, 0xd0, 0x03, 0x92, 0x03, 0xb0, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xd4, 0x03, 0xd9, 0x03, 0xcd, 0x03, 0x9c, 0x03, 0xcf, 0x12, 0xe0, 0x03, 0x9c, 0x03, 0xbd, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x09, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xcf, 0xff, 0xe0, 0xd8, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xfc, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x15, 0xe0, 0x03, 0xdf, 0x03, 0xdc, 0x03, 0xd6, 0x03, 0xd1, 0x03, 0xce, 0x03, 0xcf, 0xff, 0xd0, 0x33, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xd1, 0x03, 0xd6, 0x03, 0xdc, 0x03, 0xdf, 0xff, 0xe0, 0xff, 0xe0, 0x12, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xfc, 0xe0, 0x03, 0x9c, 0x03, 0x7c, 0x12, 0xe0, 0x03, 0xdf, 0x03, 0xdc, 0x03, 0xd5, 0x03, 0xd0, 0x03, 0xce, 0x03, 0xcf, 0x93, 0xd0, 0x12, 0xcf, 0x93, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xd5, 0x03, 0xdc, 0x03, 0xdf, 0xff, 0xe0, 0xff, 0xe0, 0x0f, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0x12, 0xe0, 0x03, 0xdf, 0x03, 0xdb, 0x03, 0xd4, 0x06, 0xcf, 0x96, 0xd0, 0x06, 0xcf, 0x0c, 0xd0, 0x06, 0xcf, 0x96, 0xd0, 0x06, 0xcf, 0x03, 0xd4, 0x03, 0xdb, 0x03, 0xdf, 0xff, 0xe0, 0xff, 0xe0, 0x0c, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0x0f, 0xe0, 0x03, 0xdf, 0x03, 0xd9, 0x03, 0xd4, 0x06, 0xcf, 0x93, 0xd0, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd3, 0x03, 0xd6, 0x03, 0xda, 0x06, 0xdc, 0x03, 0xda, 0x03, 0xd6, 0x03, 0xd3, 0x03, 0xcf, 0x03, 0xce, 0x93, 0xd0, 0x06, 0xcf, 0x03, 0xd4, 0x03, 0xd9, 0x03, 0xdf, 0xff, 0xe0, 0xff, 0xe0, 0x09, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0x09, 0xe0, 0x03, 0xdf, 0x03, 0xdd, 0x03, 0xd9, 0x03, 0xd1, 0x03, 0xcf, 0x96, 0xd0, 0x06, 0xcf, 0x03, 0xd4, 0x03, 0xda, 0x03, 0xe0, 0x03, 0xe4, 0x06, 0xe6, 0x03, 0xe4, 0x03, 0xe0, 0x03, 0xda, 0x03, 0xd4, 0x06, 0xcf, 0x96, 0xd0, 0x03, 0xcf, 0x03, 0xd1, 0x03, 0xd9, 0x03, 0xdd, 0x03, 0xdf, 0xff, 0xe0, 0xff, 0xe0, 0x03, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0x09, 0xe0, 0x03, 0xdd, 0x03, 0xd7, 0x9c, 0xd0, 0x06, 0xcf, 0x03, 0xd4, 0x03, 0xda, 0x03, 0xe2, 0x03, 0xe6, 0x0c, 0xe5, 0x03, 0xe6, 0x03, 0xe2, 0x03, 0xda, 0x03, 0xd4, 0x06, 0xcf, 0x9c, 0xd0, 0x03, 0xd7, 0x03, 0xdd, 0xff, 0xe0, 0xff, 0xe0, 0x03, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0x06, 0xe0, 0x03, 0xdd, 0x03, 0xd7, 0x03, 0xd1, 0x03, 0xcf, 0x99, 0xd0, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xd6, 0x03, 0xdd, 0x03, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x06, 0xe5, 0x03, 0xe6, 0x03, 0xe7, 0x03, 0xe5, 0x03, 0xdd, 0x03, 0xd6, 0x03, 0xd0, 0x03, 0xcf, 0x99, 0xd0, 0x03, 0xcf, 0x03, 0xd1, 0x03, 0xd7, 0x03, 0xdd, 0xff, 0xe0, 0xff, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0x03, 0xe0, 0x03, 0xdd, 0x03, 0xd7, 0x03, 0xd1, 0x9f, 0xd0, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xda, 0x03, 0xe2, 0x09, 0xe6, 0x06, 0xe5, 0x09, 0xe6, 0x03, 0xe2, 0x03, 0xda, 0x03, 0xd0, 0x03, 0xce, 0x9f, 0xd0, 0x03, 0xd1, 0x03, 0xd7, 0x03, 0xdd, 0xff, 0xe0, 0xfc, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xfc, 0xe0, 0x03, 0xdf, 0x03, 0xdd, 0x03, 0xd7, 0x03, 0xd0, 0x03, 0xcf, 0x9f, 0xd0, 0x03, 0xcd, 0x03, 0xd0, 0x03, 0xdc, 0x03, 0xe5, 0x03, 0xe6, 0x12, 0xe5, 0x03, 0xe6, 0x03, 0xe5, 0x03, 0xdc, 0x03, 0xd0, 0x03, 0xcd, 0x9f, 0xd0, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xd7, 0x03, 0xdd, 0x03, 0xdf, 0xff, 0xe0, 0xf6, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xfc, 0xe0, 0x03, 0xdd, 0x03, 0xd7, 0x03, 0xd1, 0x03, 0xcf, 0xa2, 0xd0, 0x03, 0xcd, 0x03, 0xd0, 0x03, 0xdd, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdd, 0x03, 0xd0, 0x03, 0xcd, 0xa2, 0xd0, 0x03, 0xcf, 0x03, 0xd1, 0x03, 0xd7, 0x03, 0xdd, 0xff, 0xe0, 0xf6, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xf9, 0xe0, 0x03, 0xdd, 0x03, 0xd7, 0x03, 0xd1, 0x03, 0xcf, 0xa5, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0xa5, 0xd0, 0x03, 0xcf, 0x03, 0xd1, 0x03, 0xd7, 0x03, 0xdd, 0xff, 0xe0, 0xf3, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xf6, 0xe0, 0x03, 0xdd, 0x03, 0xd9, 0x03, 0xd1, 0x03, 0xcf, 0xa8, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0xa8, 0xd0, 0x03, 0xcf, 0x03, 0xd1, 0x03, 0xd9, 0x03, 0xdd, 0xff, 0xe0, 0xf0, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xf3, 0xe0, 0x03, 0xdf, 0x03, 0xd9, 0x03, 0xd1, 0xae, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0xae, 0xd0, 0x03, 0xd1, 0x03, 0xd9, 0x03, 0xdf, 0xff, 0xe0, 0xed, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xf0, 0xe0, 0x03, 0xdf, 0x03, 0xdb, 0x03, 0xd4, 0x03, 0xcf, 0xae, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0xae, 0xd0, 0x03, 0xcf, 0x03, 0xd4, 0x03, 0xdb, 0x03, 0xdf, 0xff, 0xe0, 0xea, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xed, 0xe0, 0x03, 0xdf, 0x03, 0xdc, 0x03, 0xd4, 0xb4, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0xb4, 0xd0, 0x03, 0xd4, 0x03, 0xdc, 0x03, 0xdf, 0xff, 0xe0, 0xe7, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xed, 0xe0, 0x03, 0xdc, 0x03, 0xd6, 0x06, 0xcf, 0xb1, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0xb1, 0xd0, 0x06, 0xcf, 0x03, 0xd6, 0x03, 0xdc, 0xff, 0xe0, 0xe7, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xea, 0xe0, 0x03, 0xdd, 0x03, 0xd6, 0x03, 0xd0, 0x03, 0xcf, 0xb4, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0xb4, 0xd0, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xd6, 0x03, 0xdd, 0xff, 0xe0, 0xe4, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xe7, 0xe0, 0x03, 0xdf, 0x03, 0xd9, 0x03, 0xd0, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xd1, 0xb1, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0xb1, 0xd0, 0x03, 0xd1, 0x03, 0xd0, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xd9, 0x03, 0xdf, 0xff, 0xe0, 0xe1, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xe4, 0xe0, 0x03, 0xdf, 0x03, 0xdb, 0x03, 0xd3, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xd1, 0xb1, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0xb1, 0xd0, 0x03, 0xd1, 0x03, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xd3, 0x03, 0xdb, 0x03, 0xdf, 0xff, 0xe0, 0xde, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0x36, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0xa5, 0xe0, 0x03, 0xdc, 0x03, 0xd4, 0x06, 0xcf, 0xba, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0xba, 0xd0, 0x06, 0xcf, 0x03, 0xd4, 0x03, 0xdc, 0xff, 0xe0, 0xde, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4b, 0xe0, 0x06, 0x8c, 0x0f, 0xe0, 0x03, 0x8c, 0x03, 0xad, 0x30, 0xe0, 0x03, 0x60, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x72, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x0c, 0xe0, 0x03, 0x20, 0x03, 0x45, 0xa5, 0xe0, 0x03, 0xdf, 0x03, 0xd9, 0x03, 0xd1, 0x03, 0xcf, 0x7e, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0x90, 0x03, 00, 0x06, 0xcf, 0x03, 0x90, 0x03, 0x73, 0x03, 0xce, 0x03, 0xcf, 0x21, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x21, 0xd0, 0x03, 0xcf, 0x09, 0xce, 0x06, 0xcf, 0x09, 0xce, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0x74, 0x03, 0x5a, 0x03, 0xb0, 0x0c, 0xd0, 0x03, 0x74, 0x03, 0x5a, 0x1b, 0xd0, 0x03, 0x92, 0x03, 0x74, 0x3f, 0xd0, 0x03, 0xcf, 0x03, 0xd1, 0x03, 0xd9, 0x03, 0xdf, 0x48, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x7b, 0xe0, 0x03, 00, 0x03, 0x9c, 0x42, 0xe0, 0x03, 00, 0x03, 0x9c, 0xc3, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4b, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x0f, 0xe0, 0x03, 0x16, 0x03, 0xbd, 0x30, 0xe0, 0x03, 0x2c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x72, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x7c, 0x03, 0x52, 0xa8, 0xe0, 0x03, 0xdb, 0x03, 0xd3, 0x03, 0xcf, 0x12, 0xd0, 0x03, 0xb0, 0x03, 0xa0, 0x60, 0xd0, 0x09, 0xcf, 0x03, 0xd0, 0x03, 0xd4, 0x03, 0x95, 0x03, 00, 0x06, 0xda, 0x03, 0x79, 0x03, 0x4f, 0x03, 0xd3, 0x06, 0xcf, 0x1e, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xc3, 0x03, 0xb0, 0x0f, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x1e, 0xd0, 0x06, 0xcf, 0x03, 0xd3, 0x03, 0xd6, 0x03, 0xd9, 0x06, 0xda, 0x03, 0xd9, 0x03, 0xd6, 0x03, 0xd4, 0x03, 0xd0, 0x03, 0xcf, 0x03, 0x29, 0x03, 00, 0x03, 0x4c, 0x09, 0xd0, 0x03, 0xbf, 0x06, 00, 0x1b, 0xd0, 0x03, 0x74, 0x03, 0x4c, 0x1e, 0xd0, 0x03, 0xb0, 0x03, 0xa0, 0x1e, 0xd0, 0x03, 0xcf, 0x03, 0xd3, 0x03, 0xdb, 0x48, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x27, 0xe0, 0x03, 0xbd, 0x03, 0xad, 0x4e, 0xe0, 0x03, 00, 0x03, 0x9c, 0x42, 0xe0, 0x03, 00, 0x03, 0x9c, 0xc3, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4b, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0x7c, 0x09, 0xe0, 0x03, 0x9c, 0x03, 0x20, 0x09, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x2d, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0xbd, 0x36, 0xe0, 0x03, 0x9c, 0x09, 0xe0, 0x06, 0xad, 0x0f, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x12, 0xe0, 0x03, 0x9c, 0x03, 0xbd, 0x06, 0xe0, 0x06, 0xad, 0x0c, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xad, 0x12, 0xe0, 0x03, 0xad, 0x03, 0xcf, 0x09, 0xe0, 0x06, 0xbd, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x12, 0xe0, 0x03, 0x9c, 0x1b, 0xe0, 0x03, 0xdf, 0x03, 0xdc, 0x03, 0xd5, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xa0, 0x03, 0x92, 0x03, 0xbf, 0x09, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x12, 0xd0, 0x03, 0x92, 0x09, 0xd0, 0x03, 0xb0, 0x03, 0x92, 0x1b, 0xd0, 0x03, 0xbf, 0x03, 0x92, 0x03, 0xa0, 0x12, 0xd0, 0x03, 0xbf, 0x03, 0x9f, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd3, 0x03, 0x96, 0x03, 0xbb, 0x03, 0x9d, 0x03, 00, 0x09, 0xe5, 0x03, 0xe1, 0x03, 0xda, 0x03, 0xd4, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xd0, 0x03, 0x92, 0x03, 0xb0, 0x0c, 0xd0, 0x03, 0xb0, 0x03, 0x92, 0x03, 0x9e, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0x63, 0x03, 0x2d, 0x0f, 0xe5, 0x03, 0xa1, 0x03, 0xc3, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x1b, 0xd0, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xb3, 0x03, 0xb8, 0x03, 0xe1, 0x09, 0xe5, 0x03, 0xe4, 0x03, 0xe1, 0x03, 0xdd, 0x03, 0xd7, 0x03, 0xd3, 0x03, 0x29, 0x03, 0x0c, 0x03, 0x15, 0x09, 0xd0, 0x03, 0x74, 0x03, 0x15, 0x03, 00, 0x09, 0xd0, 0x03, 0xbf, 0x06, 0x92, 0x1e, 0xd0, 0x03, 0x92, 0x03, 0xb0, 0x09, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x0f, 0xd0, 0x03, 0x92, 0x03, 0xb0, 0x09, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xd5, 0x03, 0xa9, 0x03, 0xac, 0x0f, 0xe0, 0x06, 0xad, 0x2d, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xad, 0x15, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x0f, 0xe0, 0x06, 0x9c, 0x2a, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xbd, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x0c, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x1b, 0xe0, 0x06, 0xad, 0x03, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0xb4, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x45, 0x03, 0x38, 0x09, 0xe0, 0x03, 0x45, 0x03, 0x6e, 0x06, 0xe0, 0x03, 0x45, 0x03, 0x16, 0x06, 0x20, 0x03, 0xcf, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x2c, 0x0c, 00, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x03, 0x20, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xcf, 0x06, 0x20, 0x03, 0x16, 0x03, 0x45, 0x09, 0xe0, 0x03, 0x45, 0x03, 0x0c, 0x03, 0x2c, 0x06, 0x16, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x03, 0x20, 0x03, 0x2c, 0x03, 00, 0x03, 0x8c, 0x03, 0x45, 0x03, 0x20, 0x03, 0x0c, 0x03, 0x52, 0x06, 0xe0, 0x03, 0x38, 0x03, 0x16, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x52, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0x38, 0x03, 0x2c, 0x03, 0xad, 0x03, 0x9c, 0x03, 00, 0x03, 0x6e, 0x03, 0x20, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x03, 0x20, 0x03, 0x2c, 0x0c, 0xe0, 0x03, 0x8c, 0x03, 0x0c, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcd, 0x03, 0x0c, 0x03, 0xbf, 0x03, 0xbe, 0x03, 0x29, 0x03, 0x15, 0x03, 0x29, 0x03, 0x0c, 0x03, 0x74, 0x03, 0xd0, 0x03, 0x92, 0x09, 00, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0x29, 0x03, 0x4c, 0x03, 0x1f, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x41, 0x03, 0x15, 0x06, 0x1f, 0x03, 0xbf, 0x12, 0xd0, 0x03, 0x74, 0x03, 0x0c, 0x03, 0x29, 0x03, 0x15, 0x03, 0x29, 0x03, 0xbf, 0x06, 0xd0, 0x03, 00, 0x03, 0x59, 0x03, 0x1e, 0x03, 0x4c, 0x03, 0xd1, 0x03, 0xa5, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x16, 0x03, 0x2d, 0x03, 00, 0x06, 0xe6, 0x03, 0x63, 0x03, 0x2d, 0x03, 0xe1, 0x03, 0xda, 0x03, 0x2a, 0x03, 0x4c, 0x03, 0x1f, 0x03, 0x29, 0x03, 00, 0x03, 0x83, 0x06, 0xd0, 0x03, 0x34, 0x03, 0x15, 0x03, 0x29, 0x03, 0x0c, 0x03, 0x4d, 0x03, 0xdf, 0x03, 0xa0, 0x09, 00, 0x03, 0x62, 0x03, 0xe5, 0x03, 0xb0, 0x03, 0x0d, 0x03, 0x2d, 0x03, 0x0d, 0x03, 0x7c, 0x03, 0xd1, 0x03, 0xcd, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0x68, 0x03, 0x1f, 0x03, 0x7d, 0x03, 0xe5, 0x0c, 0xe6, 0x03, 0xe5, 0x03, 0xe4, 0x03, 0xe0, 0x03, 0xdb, 0x03, 0x2a, 0x03, 0x41, 0x03, 00, 0x03, 0x9f, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0x1f, 0x03, 0x4c, 0x03, 00, 0x06, 0xd0, 0x03, 0x67, 0x03, 0x0c, 0x03, 0x29, 0x03, 0x15, 0x03, 0x1f, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x4c, 0x03, 0x1f, 0x03, 0x29, 0x03, 00, 0x03, 0x83, 0x03, 0xd0, 0x03, 0x92, 0x09, 00, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0xa0, 0x03, 0x0c, 0x03, 0x29, 0x03, 0x0c, 0x03, 0x74, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x03, 0x41, 0x03, 0x1f, 0x03, 0x0c, 0x03, 0x52, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0x20, 0x03, 0x16, 0x03, 0x45, 0x06, 0xe0, 0x03, 0x60, 0x0f, 00, 0x12, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x38, 0x03, 0x16, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x52, 0x0f, 0xe0, 0x03, 0x9c, 0x09, 00, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x06, 0x20, 0x03, 0x16, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0xad, 0x06, 0x16, 0x03, 0x2c, 0x03, 0x16, 0x06, 0xe0, 0x03, 00, 0x03, 0x6e, 0x03, 0x16, 0x03, 0x20, 0x03, 0x0c, 0x03, 0xbd, 0x06, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x12, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 0x16, 0x03, 0x20, 0x03, 0x2c, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x45, 0x03, 0x16, 0x06, 0x20, 0x03, 0xcf, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0xbd, 0x06, 0xe0, 0x03, 0x0c, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x6e, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x16, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0x0f, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0x7c, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xbd, 0x06, 0xe0, 0x06, 0x45, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x8c, 0x03, 0x0c, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0xbd, 0x03, 0x16, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x38, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x52, 0x03, 00, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x8c, 0x03, 00, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x8c, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 00, 0x03, 0x8c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0x52, 0x06, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x38, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xbd, 0x12, 0xe0, 0x03, 0x0c, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0xdf, 0x03, 0x6c, 0x03, 0x41, 0x03, 0xcf, 0x03, 0x41, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0xb0, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x09, 0xd0, 0x03, 0x29, 0x03, 0x0c, 0x03, 0xb0, 0x06, 0xd0, 0x03, 0x74, 0x03, 0x15, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x67, 0x0f, 0xd0, 0x03, 0xb0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x41, 0x06, 0xd0, 0x03, 00, 0x03, 0x29, 0x03, 0xbf, 0x03, 0xd4, 0x03, 0xd9, 0x03, 0x20, 0x03, 0x61, 0x06, 0xe6, 0x03, 0x63, 0x03, 00, 0x06, 0xe6, 0x03, 0x63, 0x03, 0x2d, 0x03, 0xe5, 0x03, 0xdf, 0x03, 0x2a, 0x03, 0x0c, 0x03, 0x9f, 0x03, 0xd0, 0x03, 0x4c, 0x03, 0x29, 0x06, 0xd0, 0x03, 0xbf, 0x06, 0xd0, 0x03, 0x81, 0x03, 00, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0x63, 0x03, 0x2d, 0x09, 0xe5, 0x03, 0x16, 0x03, 0x80, 0x03, 0xe7, 0x03, 0xa0, 0x03, 0x0c, 0x03, 0xd1, 0x03, 0xcd, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0x91, 0x03, 00, 0x03, 0x4f, 0x03, 0xdf, 0x03, 0xe5, 0x18, 0xe6, 0x03, 0xe2, 0x03, 0x2b, 0x03, 0x5d, 0x03, 0x1f, 0x03, 0x4c, 0x03, 0xce, 0x03, 0xae, 0x03, 0x15, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0xbf, 0x06, 0xd0, 0x03, 0xbf, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x0c, 0x03, 0xa0, 0x03, 0xd0, 0x03, 0x4c, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x09, 0xd0, 0x03, 0x15, 0x03, 0x74, 0x03, 0xd0, 0x03, 0x92, 0x03, 0x0c, 0x06, 0xd0, 0x03, 0x5a, 0x03, 00, 0x03, 0x74, 0x03, 0xd1, 0x03, 0x89, 0x03, 00, 0x06, 0xe0, 0x06, 0x45, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0xad, 0x0c, 0xe0, 0x03, 0xcf, 0x03, 0x16, 0x03, 0x45, 0x12, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x8c, 0x03, 00, 0x12, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x16, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x16, 0x03, 0x45, 0x0f, 0xe0, 0x03, 00, 0x03, 0x20, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x20, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x38, 0x12, 0xe0, 0x03, 0x52, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x6e, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x51, 0xe0, 0x03, 0x16, 0x03, 0x6e, 0x03, 0xe0, 0x03, 0x8c, 0x03, 0x38, 0x06, 0xe0, 0x03, 0x38, 0x03, 0x45, 0x06, 0x9c, 0x03, 0x45, 0x03, 0x2c, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xad, 0x03, 00, 0x09, 0x9c, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x60, 0x15, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x0c, 0x03, 0x6e, 0x06, 0x9c, 0x03, 0x20, 0x03, 0x60, 0x03, 0xe0, 0x06, 0x45, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x6e, 0x03, 0x20, 0x06, 0x9c, 0x03, 0x6e, 0x03, 00, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0x6e, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x6e, 0x03, 0x20, 0x06, 0x9c, 0x03, 0x6e, 0x03, 00, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x15, 0xe0, 0x03, 0x52, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xdc, 0x03, 0x15, 0x03, 0x9f, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0x83, 0x09, 0xd0, 0x03, 0x1f, 0x03, 0x67, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x09, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x09, 0xd0, 0x03, 0x34, 0x03, 0x41, 0x06, 0x92, 0x03, 0x41, 0x03, 0x29, 0x0f, 0xd0, 0x03, 0x67, 0x03, 0x1f, 0x09, 0xd0, 0x03, 0x83, 0x03, 0x0c, 0x03, 0xd0, 0x03, 0xcf, 0x03, 00, 0x03, 0x92, 0x03, 0xd6, 0x03, 0xdc, 0x03, 0xbe, 0x03, 00, 0x03, 0xc3, 0x06, 0xe6, 0x03, 0xa0, 0x03, 00, 0x06, 0xe5, 0x03, 0x62, 0x03, 0x2d, 0x03, 0xe6, 0x03, 0xe2, 0x03, 0x2b, 0x03, 0x4e, 0x03, 0xce, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x0c, 0xd0, 0x03, 0x92, 0x03, 0x65, 0x03, 00, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0x63, 0x03, 0x2d, 0x06, 0xe5, 0x03, 0xb0, 0x03, 00, 0x03, 0x9f, 0x03, 0xa1, 0x03, 0xa0, 0x03, 00, 0x03, 0x92, 0x03, 0xcd, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0x90, 0x03, 00, 0x03, 0xdb, 0x03, 0xe2, 0x06, 0xe6, 0x0c, 0xe5, 0x0c, 0xe6, 0x03, 0x2c, 0x03, 0x61, 0x03, 0x6c, 0x03, 0x15, 0x03, 0xd0, 0x03, 0x4b, 0x03, 0x4c, 0x03, 0x92, 0x03, 00, 0x0c, 0xd0, 0x03, 0xa0, 0x03, 0x92, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x4c, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0xa0, 0x03, 00, 0x09, 0x92, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x1f, 0x06, 0xcf, 0x03, 0x95, 0x03, 00, 0x06, 0xe0, 0x03, 0x0c, 0x03, 0x6e, 0x06, 0x9c, 0x03, 0x20, 0x03, 0x60, 0x09, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 0x2c, 0x15, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0x6e, 0x03, 00, 0x12, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0xbd, 0x0f, 0xe0, 0x03, 00, 0x03, 0x8c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x6e, 0x03, 0x20, 0x06, 0x9c, 0x03, 0x6e, 0x03, 00, 0x12, 0xe0, 0x03, 0x16, 0x03, 0x7c, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x38, 0x03, 0x45, 0x06, 0x9c, 0x03, 0x45, 0x03, 0x2c, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x51, 0xe0, 0x03, 0x6e, 0x03, 0x16, 0x03, 0xe0, 0x03, 0x45, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x16, 0x09, 0x2c, 0x03, 0x52, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0x2c, 0x03, 0xad, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 0x45, 0x18, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 00, 0x03, 0x20, 0x09, 0x2c, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x0c, 0x0c, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x06, 0x20, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x0c, 0x0c, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x15, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0xbc, 0x03, 0x96, 0x03, 0x1f, 0x06, 0xd0, 0x03, 00, 0x03, 0x92, 0x09, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x09, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x09, 0xd0, 0x03, 0x29, 0x03, 0x15, 0x09, 0x29, 0x03, 0x4c, 0x0f, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x09, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0xcf, 0x03, 0xd0, 0x03, 00, 0x03, 0x96, 0x03, 0xe0, 0x03, 0xe4, 0x03, 0xa0, 0x03, 00, 0x03, 0xe6, 0x06, 0xe5, 0x03, 0x9f, 0x03, 00, 0x06, 0xe5, 0x03, 0x62, 0x03, 0x2d, 0x03, 0xe5, 0x03, 0xe4, 0x03, 0x2b, 0x03, 0x5c, 0x03, 0xce, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x74, 0x03, 0x0c, 0x03, 0x1f, 0x03, 0x1e, 0x03, 00, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0x63, 0x03, 0x2d, 0x06, 0xe5, 0x03, 0x9f, 0x03, 00, 0x09, 0x2d, 0x03, 0x2b, 0x03, 0xa1, 0x03, 0xcd, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0x90, 0x03, 00, 0x03, 0xdf, 0x03, 0xe4, 0x03, 0xe5, 0x03, 0xe6, 0x15, 0xe5, 0x03, 0xe6, 0x03, 0x2d, 0x03, 0x63, 0x03, 0xc1, 0x03, 00, 0x03, 0xa6, 0x03, 0x15, 0x03, 0xb0, 0x03, 0x91, 0x03, 00, 0x06, 0xd0, 0x03, 0xa0, 0x06, 0x15, 0x03, 0x29, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x0c, 0x29, 0x03, 0xa0, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0xdf, 0x03, 0xe0, 0x03, 00, 0x03, 0x20, 0x09, 0x2c, 0x03, 0x7c, 0x09, 0xe0, 0x03, 0x45, 0x03, 0x20, 0x03, 0xcf, 0x15, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x06, 0x20, 0x03, 00, 0x12, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x12, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x0c, 0x0c, 0x2c, 0x12, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x16, 0x09, 0x2c, 0x03, 0x52, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x51, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0x8c, 0x03, 00, 0x03, 0xcf, 0x06, 0xe0, 0x06, 0x45, 0x12, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x20, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x20, 0x03, 0xcf, 0x18, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x16, 0x03, 0x7c, 0x0f, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0x8c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x18, 0xe0, 0x03, 0x20, 0x03, 0x6c, 0x03, 0x35, 0x03, 0x72, 0x03, 0xd0, 0x03, 0xd1, 0x03, 0x0c, 0x03, 0x83, 0x09, 0xd0, 0x03, 0x1f, 0x03, 0x67, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x09, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x09, 0xd0, 0x06, 0x41, 0x1b, 0xd0, 0x03, 0x67, 0x03, 0x1f, 0x09, 0xd0, 0x03, 0x83, 0x03, 0x0c, 0x03, 0xd0, 0x03, 0xd3, 0x03, 00, 0x03, 0x9c, 0x03, 0xe5, 0x03, 0xe6, 0x03, 0x9f, 0x03, 00, 0x09, 0xe5, 0x03, 0x9f, 0x03, 00, 0x06, 0xe5, 0x03, 0x62, 0x03, 0x2d, 0x03, 0xe6, 0x03, 0xe4, 0x03, 0x2b, 0x03, 0x5c, 0x03, 0xce, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x03, 0xd0, 0x03, 0xb0, 0x03, 00, 0x03, 0x83, 0x03, 0xd0, 0x03, 0x8f, 0x03, 00, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0x63, 0x03, 0x2d, 0x06, 0xe5, 0x03, 0xc2, 0x03, 00, 0x03, 0xc2, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x83, 0x03, 00, 0x06, 0xd0, 0x03, 0x90, 0x03, 00, 0x03, 0xdf, 0x03, 0xe4, 0x06, 0xe6, 0x18, 0xe5, 0x03, 0x2d, 0x03, 0x62, 0x03, 0xe6, 0x03, 0x21, 0x03, 0x20, 0x03, 0x1f, 0x03, 0xd3, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0x15, 0x03, 0x4c, 0x06, 0xd0, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0xb0, 0x03, 00, 0x03, 0xb0, 0x0f, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x03, 0xd1, 0x03, 0xd0, 0x03, 0x8f, 0x03, 00, 0x03, 0xdc, 0x03, 0xe0, 0x03, 0x16, 0x03, 0x7c, 0x12, 0xe0, 0x03, 0x60, 0x03, 0x0c, 0x03, 0xad, 0x18, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0x8c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x12, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x0f, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x1e, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x06, 0x45, 0xba, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x54, 0xe0, 0x03, 0x38, 0x03, 0x16, 0x03, 0x38, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xad, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 00, 0x03, 0x8c, 0x03, 0xe0, 0x03, 0x7c, 0x03, 00, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x38, 0x09, 0xe0, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x45, 0x03, 0x16, 0x03, 0xcf, 0x1b, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x6e, 0x03, 0x16, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x8c, 0x03, 00, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0x6e, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x7c, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0x6e, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x18, 0xe0, 0x03, 0x6d, 0x03, 0x15, 0x03, 0x0c, 0x03, 0xbe, 0x03, 0xd0, 0x03, 0xd1, 0x03, 0x41, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0xb0, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x15, 0x09, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x09, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0xa0, 0x06, 0xd0, 0x03, 0xbf, 0x0f, 0xd0, 0x03, 0xb0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x41, 0x03, 0xd4, 0x03, 0xda, 0x03, 00, 0x03, 0x9f, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0x0d, 0x03, 0x70, 0x03, 0xe5, 0x03, 0xd3, 0x03, 0x2d, 0x03, 00, 0x06, 0xe5, 0x03, 0x62, 0x03, 0x2d, 0x03, 0xe6, 0x03, 0xe4, 0x03, 0x2b, 0x03, 0x5c, 0x03, 0xce, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0xbf, 0x03, 0xd0, 0x03, 0x72, 0x03, 00, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0x63, 0x03, 0x16, 0x09, 0xe5, 0x03, 0x2d, 0x03, 0x39, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xc1, 0x03, 0xcd, 0x03, 0x5a, 0x03, 0x1f, 0x03, 0xd0, 0x03, 0xbf, 0x03, 0x1f, 0x03, 00, 0x06, 0xd0, 0x03, 0x90, 0x03, 00, 0x03, 0xdf, 0x03, 0xe4, 0x06, 0xe6, 0x03, 0x62, 0x03, 0x9f, 0x12, 0xe5, 0x03, 0x2d, 0x03, 0x62, 0x03, 0xe6, 0x03, 0x71, 0x03, 00, 0x03, 0x7d, 0x03, 0xda, 0x03, 0x94, 0x03, 00, 0x03, 0xce, 0x03, 0xd0, 0x03, 00, 0x03, 0x83, 0x03, 0xd0, 0x03, 0xb0, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x15, 0x09, 0xd0, 0x03, 0x29, 0x03, 0x34, 0x09, 0xd0, 0x03, 0xbf, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x03, 0xd1, 0x03, 0xd0, 0x03, 0x90, 0x03, 00, 0x03, 0xd9, 0x03, 0xdf, 0x03, 0x60, 0x03, 0x16, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x7c, 0x03, 00, 0x03, 0xad, 0x1b, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x7c, 0x03, 00, 0x12, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x09, 0xe0, 0x03, 0x16, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x45, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0x6e, 0x06, 0xe0, 0x03, 0xcf, 0x12, 0xe0, 0x06, 0x38, 0x06, 0xe0, 0x03, 0x52, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xad, 0x06, 0xe0, 0x03, 0xcf, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x54, 0xe0, 0x03, 0x8c, 0x03, 00, 0x03, 0x8c, 0x0c, 0xe0, 0x03, 0x6e, 0x03, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x38, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x45, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0xbd, 0x03, 0x20, 0x03, 0x16, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x03, 0xe0, 0x0f, 00, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x0c, 0xe0, 0x03, 0x38, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x6e, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 0x16, 0x03, 0x20, 0x03, 0x45, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x2c, 0x03, 0x0c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x20, 0x03, 0x16, 0x03, 0x20, 0x03, 0x52, 0x03, 0x0c, 0x03, 0x20, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x2c, 0x03, 0x0c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x18, 0xe0, 0x03, 0xcb, 0x03, 00, 0x03, 0x4c, 0x09, 0xd0, 0x03, 0xbf, 0x03, 0x29, 0x03, 0x15, 0x03, 0x29, 0x03, 0x0c, 0x03, 0x74, 0x06, 0xd0, 0x03, 0xb0, 0x03, 0x0c, 0x03, 0x1f, 0x03, 0x74, 0x03, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x0c, 0xd0, 0x03, 0x67, 0x03, 00, 0x03, 0x29, 0x03, 0x1f, 0x03, 0x34, 0x12, 0xd0, 0x03, 0x74, 0x03, 0x0c, 0x03, 0x29, 0x03, 0x15, 0x03, 0x29, 0x03, 0xc4, 0x03, 0xdc, 0x03, 0xe1, 0x03, 00, 0x03, 0xa0, 0x09, 0xe5, 0x03, 0x80, 0x03, 00, 0x03, 0x2d, 0x03, 0x16, 0x03, 0x70, 0x03, 00, 0x06, 0xe5, 0x03, 0x62, 0x03, 0x2d, 0x03, 0xe6, 0x03, 0xe4, 0x03, 0x2b, 0x03, 0x5b, 0x03, 0xce, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x1f, 0x03, 0x15, 0x03, 0x1f, 0x03, 0x4b, 0x03, 0x0c, 0x03, 0x20, 0x03, 0xe6, 0x03, 0xc3, 0x03, 0x0d, 0x03, 0x21, 0x03, 0x80, 0x03, 0xe5, 0x03, 0xc2, 0x03, 0x21, 0x03, 0x17, 0x03, 0x2d, 0x03, 0x0c, 0x03, 0xa1, 0x03, 0xcd, 0x03, 0xb0, 0x03, 0x0c, 0x03, 0x1f, 0x03, 0x15, 0x03, 0x67, 0x03, 00, 0x06, 0xd0, 0x03, 0x90, 0x03, 00, 0x03, 0xdc, 0x03, 0xe4, 0x06, 0xe6, 0x03, 00, 0x03, 0x62, 0x12, 0xe5, 0x03, 0x2d, 0x03, 0x62, 0x03, 0xe5, 0x03, 0xd3, 0x03, 0xa0, 0x03, 0xd4, 0x03, 0xe1, 0x03, 0x9a, 0x03, 00, 0x03, 0xd0, 0x03, 0xcf, 0x03, 0x4c, 0x03, 0x0c, 0x09, 0x29, 0x03, 0x15, 0x03, 0xa0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0xb0, 0x03, 0x0c, 0x03, 0x1f, 0x03, 0x74, 0x03, 0xd0, 0x03, 0xb0, 0x03, 0x1f, 0x03, 0x15, 0x03, 0x29, 0x03, 0x0c, 0x03, 0xa0, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0xd4, 0x03, 0xdc, 0x03, 0xe0, 0x03, 0x38, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x6e, 0x03, 0xe0, 0x03, 0x2c, 0x0f, 00, 0x12, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x20, 0x03, 0x16, 0x03, 0x20, 0x03, 0x52, 0x03, 0x0c, 0x03, 0x20, 0x0f, 0xe0, 0x03, 0xbd, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x06, 0x20, 0x03, 0x16, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x8c, 0x03, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x52, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0xad, 0x06, 0x16, 0x03, 0x2c, 0x03, 0x0c, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x2c, 0x03, 0x0c, 0x12, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x16, 0x03, 0x7c, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x6e, 0x03, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x38, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x6c, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xbd, 0x0c, 0xe0, 0x06, 0xad, 0x36, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x42, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xcf, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0xad, 0x15, 0xe0, 0x03, 0x9c, 0x03, 0xad, 0x30, 0xe0, 0x03, 0x9c, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0xbd, 0x03, 0xad, 0x2a, 0xe0, 0x03, 0x9c, 0x03, 0xad, 0x24, 0xe0, 0x03, 0xdf, 0x03, 0xd7, 0x06, 0xcf, 0x03, 0xd1, 0x0c, 0xd0, 0x03, 0xa0, 0x03, 0x92, 0x03, 0xbf, 0x0c, 0xd0, 0x03, 0xbf, 0x03, 0x92, 0x03, 0xbf, 0x18, 0xd0, 0x03, 0xbf, 0x03, 0x92, 0x03, 0xb0, 0x18, 0xd0, 0x03, 0xbf, 0x03, 0x91, 0x03, 0xa0, 0x03, 0xd5, 0x03, 0xdc, 0x03, 0xe2, 0x03, 0xe5, 0x03, 0xe6, 0x0f, 0xe5, 0x03, 0xc2, 0x03, 0x9f, 0x03, 0xd3, 0x0f, 0xe5, 0x03, 0xe6, 0x03, 0xe5, 0x03, 0xe0, 0x03, 0xd7, 0x03, 0xd0, 0x03, 0xcf, 0x12, 0xd0, 0x03, 0x92, 0x03, 0xb0, 0x03, 0xcd, 0x03, 0xb2, 0x03, 0xac, 0x03, 0xe6, 0x03, 0xe7, 0x03, 0xd3, 0x03, 0x9f, 0x03, 0xd3, 0x09, 0xe5, 0x03, 0xb3, 0x03, 0xa0, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x03, 0xd0, 0x03, 0xbf, 0x03, 0x92, 0x03, 0xbf, 0x0c, 0xd0, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xd7, 0x03, 0xe0, 0x03, 0xe5, 0x03, 0xe6, 0x27, 0xe5, 0x03, 0xe6, 0x03, 0xe5, 0x03, 0xe2, 0x03, 0xdc, 0x03, 0xd5, 0x03, 0xd0, 0x03, 0xcf, 0x06, 0xa0, 0x03, 0xd0, 0x03, 0xbf, 0x03, 0x92, 0x2a, 0xd0, 0x03, 0xbf, 0x03, 0x92, 0x03, 0xbf, 0x09, 0xd0, 0x03, 0xa0, 0x03, 0x92, 0x15, 0xd0, 0x03, 0xd1, 0x06, 0xcf, 0x03, 0xd7, 0x03, 0xdf, 0x03, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xcf, 0x39, 0xe0, 0x03, 0x9c, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0xbd, 0x03, 0xad, 0x12, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x09, 0xe0, 0x06, 0x9c, 0x0f, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x15, 0xe0, 0x06, 0x9c, 0x27, 0xe0, 0x03, 0x9c, 0x03, 0xad, 0x18, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xbd, 0x12, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xbd, 0xb1, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xcf, 0xe0, 0x03, 0xdc, 0x03, 0xd4, 0x06, 0xcf, 0x03, 0xd1, 0x63, 0xd0, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xd5, 0x03, 0xdb, 0x03, 0xe1, 0x06, 0xe6, 0x24, 0xe5, 0x03, 0xe6, 0x06, 0xe7, 0x03, 0xe1, 0x03, 0xda, 0x03, 0xd3, 0x06, 0xcf, 0x18, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x18, 0xd0, 0x06, 0xcf, 0x03, 0xd3, 0x03, 0xda, 0x03, 0xe1, 0x06, 0xe7, 0x03, 0xe6, 0x24, 0xe5, 0x06, 0xe6, 0x03, 0xe1, 0x03, 0xdb, 0x03, 0xd5, 0x03, 0xd0, 0x03, 0xcf, 0x63, 0xd0, 0x03, 0xd1, 0x06, 0xcf, 0x03, 0xd4, 0x03, 0xdc, 0xff, 0xe0, 0xc9, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xcc, 0xe0, 0x03, 0xdf, 0x03, 0xd9, 0x03, 0xd0, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xd1, 0x60, 0xd0, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xd4, 0x03, 0xdc, 0x03, 0xe2, 0x09, 0xe6, 0x21, 0xe5, 0x09, 0xe6, 0x03, 0xe2, 0x03, 0xda, 0x03, 0xd3, 0x06, 0xcf, 0x1b, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x1b, 0xd0, 0x06, 0xcf, 0x03, 0xd3, 0x03, 0xda, 0x03, 0xe2, 0x09, 0xe6, 0x21, 0xe5, 0x09, 0xe6, 0x03, 0xe2, 0x03, 0xdc, 0x03, 0xd4, 0x03, 0xd0, 0x03, 0xcf, 0x60, 0xd0, 0x03, 0xd1, 0x03, 0xd0, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xd9, 0x03, 0xdf, 0xff, 0xe0, 0xc6, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xcc, 0xe0, 0x03, 0xdc, 0x03, 0xd3, 0x03, 0xcf, 0x66, 0xd0, 0x06, 0xcf, 0x03, 0xd4, 0x03, 0xdc, 0x03, 0xe1, 0x03, 0xe5, 0x06, 0xe6, 0x21, 0xe5, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0xe1, 0x03, 0xda, 0x03, 0xd1, 0x03, 0xcf, 0x03, 0xce, 0x1e, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x1e, 0xd0, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd1, 0x03, 0xda, 0x03, 0xe1, 0x03, 0xe5, 0x06, 0xe6, 0x21, 0xe5, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0xe1, 0x03, 0xdc, 0x03, 0xd4, 0x06, 0xcf, 0x66, 0xd0, 0x03, 0xcf, 0x03, 0xd3, 0x03, 0xdc, 0xff, 0xe0, 0xc6, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xc9, 0xe0, 0x03, 0xdf, 0x03, 0xd9, 0x06, 0xcf, 0x03, 0xd0, 0x03, 0xd1, 0x5d, 0xd0, 0x06, 0xcf, 0x03, 0xd3, 0x03, 0xda, 0x03, 0xe2, 0x03, 0xe5, 0x06, 0xe6, 0x1b, 0xe5, 0x0c, 0xe6, 0x03, 0xe4, 0x03, 0xe0, 0x03, 0xda, 0x03, 0xd3, 0x03, 0xce, 0x03, 0xcf, 0x21, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x21, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xd3, 0x03, 0xda, 0x03, 0xe0, 0x03, 0xe4, 0x0c, 0xe6, 0x1b, 0xe5, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0xe2, 0x03, 0xda, 0x03, 0xd3, 0x06, 0xcf, 0x5d, 0xd0, 0x03, 0xd1, 0x03, 0xd0, 0x06, 0xcf, 0x03, 0xd9, 0x03, 0xdf, 0xff, 0xe0, 0xc3, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x6f, 0xe0, 0x06, 0xad, 0xe4, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x4e, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x12, 0xe0, 0x03, 0xdc, 0x03, 0xd5, 0x03, 0xcf, 0x06, 0xd0, 0x03, 0xd1, 0x5a, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xd1, 0x03, 0xda, 0x03, 0xe1, 0x09, 0xe6, 0x1e, 0xe5, 0x09, 0xe6, 0x03, 0xe4, 0x03, 0xdf, 0x03, 0xd9, 0x03, 0xd3, 0x06, 0xce, 0x24, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x24, 0xd0, 0x06, 0xce, 0x03, 0xd3, 0x03, 0xd9, 0x03, 0xdf, 0x03, 0xe4, 0x09, 0xe6, 0x1e, 0xe5, 0x09, 0xe6, 0x03, 0xe1, 0x03, 0xda, 0x03, 0xd1, 0x03, 0xce, 0x03, 0xcf, 0x5a, 0xd0, 0x03, 0xd1, 0x06, 0xd0, 0x03, 0xcf, 0x03, 0xd5, 0x03, 0xdc, 0xff, 0xe0, 0xc3, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x5a, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0xe0, 0x03, 0x8c, 0x03, 0x0c, 0x03, 0xad, 0xe1, 0xe0, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x2c, 0x03, 0x60, 0x4b, 0xe0, 0x03, 0x20, 0x03, 0x45, 0x12, 0xe0, 0x03, 0xdf, 0x03, 0xd9, 0x03, 0xd1, 0x63, 0xd0, 0x03, 0x91, 0x03, 00, 0x03, 0xd0, 0x03, 0xd7, 0x03, 0xe0, 0x06, 0xe6, 0x21, 0xe5, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0xe1, 0x03, 0xdc, 0x03, 0xd6, 0x03, 0xd1, 0x03, 0xcf, 0x03, 0xce, 0x1b, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0x72, 0x03, 0x92, 0x24, 0xd0, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd1, 0x03, 0xd6, 0x03, 0xdc, 0x03, 0xe1, 0x03, 0xe5, 0x06, 0xe6, 0x21, 0xe5, 0x06, 0xe6, 0x03, 0xe0, 0x03, 0xd7, 0x03, 0xd0, 0x03, 0xce, 0x03, 0xcf, 0x63, 0xd0, 0x03, 0xd1, 0x03, 0xd9, 0x03, 0x60, 0x03, 0x2c, 0x78, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x12, 0xe0, 0x03, 0x9c, 0x03, 0x7c, 0xff, 0xe0, 0x27, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x5a, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0xcf, 0x03, 0x38, 0x03, 0xad, 0xe1, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0xcf, 0x4e, 0xe0, 0x03, 0x7c, 0x03, 0x52, 0x15, 0xe0, 0x03, 0xdd, 0x03, 0xd4, 0x03, 0xcf, 0x63, 0xd0, 0x03, 0x90, 0x03, 00, 0x03, 0xd6, 0x03, 0xe0, 0x03, 0xe5, 0x03, 0xe6, 0x24, 0xe5, 0x03, 0xe6, 0x03, 0xc3, 0x03, 0xae, 0x03, 0xda, 0x03, 0xd4, 0x03, 0xd0, 0x03, 0xcf, 0x21, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0x4b, 0x03, 0x74, 0x2a, 0xd0, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xd4, 0x03, 0xda, 0x03, 0xe1, 0x06, 0xe6, 0x24, 0xe5, 0x03, 0xe6, 0x03, 0xe5, 0x03, 0xe0, 0x03, 0xd6, 0x03, 0xd0, 0x03, 0xce, 0x63, 0xd0, 0x03, 0xcf, 0x03, 0xd4, 0x03, 0x5f, 0x03, 0x2c, 0x78, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x12, 0xe0, 0x03, 0x7c, 0x03, 0x52, 0xff, 0xe0, 0x27, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x54, 0xe0, 0x03, 0x9c, 0x03, 0xbd, 0x03, 0x9c, 0x03, 00, 0x0c, 0xe0, 0x06, 0xad, 0x12, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x0c, 0xe0, 0x06, 0x9c, 0x03, 0xcf, 0x0f, 0xe0, 0x03, 0xcf, 0x03, 0xad, 0x0c, 0xe0, 0x03, 0x9c, 0x09, 0xe0, 0x06, 0x9c, 0x03, 0xcf, 0x0c, 0xe0, 0x06, 0xad, 0x12, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x1b, 0xe0, 0x03, 0x9c, 0x03, 0xbd, 0x12, 0xe0, 0x06, 0xad, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0f, 0xe0, 0x06, 0x9c, 0x15, 0xe0, 0x03, 0x9c, 0x03, 0xbd, 0x0f, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xad, 0x09, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x0f, 0xe0, 0x03, 0x9c, 0x03, 0xbb, 0x03, 0xd3, 0x03, 0xce, 0x18, 0xd0, 0x03, 0xb0, 0x03, 0x92, 0x03, 0xbf, 0x0c, 0xd0, 0x03, 0xb0, 0x03, 0x92, 0x12, 0xd0, 0x03, 0xbf, 0x03, 0x92, 0x03, 0xbf, 0x0f, 0xd0, 0x03, 0x92, 0x03, 0xaf, 0x03, 0x91, 0x03, 00, 0x03, 0xdc, 0x03, 0xe2, 0x03, 0xe6, 0x03, 0xc3, 0x03, 0x9f, 0x03, 0xb0, 0x12, 0xe5, 0x06, 0xb0, 0x09, 0xe6, 0x03, 0x61, 0x03, 0x2a, 0x03, 0xd3, 0x03, 0xd0, 0x06, 0xcf, 0x12, 0xd0, 0x03, 0xa0, 0x03, 0x92, 0x09, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x0c, 0xe5, 0x03, 0xd3, 0x03, 0x9f, 0x03, 0xb3, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x0c, 0xd0, 0x03, 0xbf, 0x03, 0x92, 0x03, 0xbf, 0x18, 0xd0, 0x06, 0xcf, 0x03, 0xd0, 0x03, 0xd3, 0x03, 0xd9, 0x03, 0xe1, 0x03, 0xa0, 0x06, 0xe6, 0x03, 0xd3, 0x03, 0x9f, 0x03, 0xb0, 0x15, 0xe5, 0x03, 0xe6, 0x03, 0xc3, 0x03, 0x9e, 0x03, 0xbb, 0x03, 0xd4, 0x06, 0xcf, 0x03, 0xd0, 0x03, 0xbf, 0x03, 0x92, 0x03, 0xbf, 0x0f, 0xd0, 0x03, 0xa0, 0x03, 0x92, 0x03, 0xb0, 0x09, 0xd0, 0x03, 0xb0, 0x03, 0x92, 0x03, 0xb0, 0x12, 0xd0, 0x03, 0xb0, 0x03, 0x92, 0x0f, 0xd0, 0x03, 0xbf, 0x03, 0x90, 0x03, 0xc2, 0x03, 0x5f, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x0c, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xbd, 0x18, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xad, 0x30, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x9c, 0x03, 0xad, 0x1b, 0xe0, 0x03, 0x9c, 0x03, 0xbd, 0x12, 0xe0, 0x06, 0xad, 0x18, 0xe0, 0x03, 0xcf, 0x06, 0x9c, 0x12, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xcf, 0x0f, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xbd, 0x39, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x66, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x16, 0x03, 0x2c, 0x03, 00, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0x20, 0x03, 0x16, 0x03, 0x45, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0x7c, 0x06, 0x16, 0x03, 0x20, 0x03, 0xad, 0x03, 0x16, 0x03, 0x20, 0x03, 0x0c, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x0c, 0x03, 0xbd, 0x06, 0xe0, 0x03, 00, 0x03, 0x60, 0x03, 0x20, 0x03, 0x52, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x03, 0x20, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x0c, 0x03, 0xbd, 0x06, 0xe0, 0x03, 0x45, 0x03, 0x0c, 0x06, 0x2c, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x12, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0x45, 0x03, 0x20, 0x03, 0x0c, 0x03, 0x52, 0x03, 0xe0, 0x03, 0x9c, 0x09, 00, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x06, 0x20, 0x03, 0x16, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x03, 0x20, 0x03, 0x2c, 0x03, 00, 0x03, 0x8c, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x06, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x2b, 0x03, 0x0c, 0x03, 0x75, 0x03, 0xcf, 0x0f, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0x74, 0x03, 0x15, 0x03, 0x1f, 0x03, 0x0c, 0x03, 0xa0, 0x06, 0xd0, 0x03, 0x41, 0x03, 0x15, 0x06, 0x1f, 0x03, 0xbf, 0x06, 0xd0, 0x03, 00, 0x03, 0x67, 0x03, 0x15, 0x03, 0x1f, 0x03, 0x0c, 0x03, 0xb0, 0x06, 0xd0, 0x03, 0xa0, 0x03, 0x0c, 0x03, 0x1f, 0x03, 0x15, 0x03, 0x2a, 0x03, 00, 0x03, 0xe1, 0x03, 0xe5, 0x03, 0x39, 0x03, 0x16, 0x03, 0x2d, 0x03, 0x0d, 0x03, 0x54, 0x06, 0xe5, 0x03, 0x62, 0x03, 0x2d, 0x03, 0x46, 0x03, 0x21, 0x03, 0x0d, 0x03, 0x54, 0x03, 0xe5, 0x03, 0x9c, 0x09, 00, 0x03, 0x59, 0x0f, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x03, 0x41, 0x03, 0x1f, 0x03, 0x15, 0x03, 0x1f, 0x03, 0xbf, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0x58, 0x03, 0x2a, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xa1, 0x03, 00, 0x06, 0xe5, 0x03, 0x90, 0x03, 00, 0x03, 0x2d, 0x03, 0x21, 0x03, 0xa0, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x74, 0x03, 0x0c, 0x03, 0x29, 0x03, 0x0c, 0x03, 0xa0, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x03, 0xd0, 0x03, 0xcf, 0x03, 0x29, 0x03, 0x4c, 0x03, 0x1f, 0x03, 0x2c, 0x03, 0xe5, 0x03, 0x90, 0x03, 00, 0x03, 0x2d, 0x03, 0x21, 0x03, 0x9f, 0x12, 0xe5, 0x03, 0x54, 0x03, 0x0d, 0x03, 0x2d, 0x03, 0x16, 0x03, 0xda, 0x03, 0xd1, 0x03, 0xce, 0x03, 0x74, 0x03, 0x0c, 0x03, 0x29, 0x03, 0x0c, 0x03, 0xa0, 0x06, 0xd0, 0x03, 0xa0, 0x06, 0x15, 0x03, 0x29, 0x03, 0x15, 0x06, 0xd0, 0x03, 0x4c, 0x03, 0x0c, 0x03, 0x29, 0x03, 0x0c, 0x03, 0x4c, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0x74, 0x06, 0x15, 0x03, 0x1f, 0x09, 0xd0, 0x03, 0x74, 0x03, 00, 0x03, 0x29, 0x03, 0x15, 0x03, 0x1f, 0x03, 0x2b, 0x06, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x16, 0x15, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x2c, 0x03, 0xcf, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x03, 0x20, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x45, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0x45, 0x03, 0x20, 0x03, 0x0c, 0x03, 0x52, 0x12, 0xe0, 0x03, 0x6e, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x20, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0x7c, 0x03, 0x16, 0x03, 0x20, 0x03, 0x0c, 0x03, 0xad, 0x06, 0xe0, 0x03, 00, 0x03, 0x6e, 0x03, 0x16, 0x03, 0x2c, 0x03, 00, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x20, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x52, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x06, 0xe0, 0x0f, 00, 0x03, 0x60, 0x4b, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x20, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 00, 0x06, 0xe0, 0x06, 0x45, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0x45, 0x03, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0x20, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x20, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xcf, 0x09, 0xe0, 0x03, 0x20, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x2c, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xbd, 0x06, 0xe0, 0x03, 0xcf, 0x09, 0xe0, 0x03, 0x20, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x38, 0x12, 0xe0, 0x03, 0x16, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0x06, 0xe0, 0x03, 0x60, 0x03, 00, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x8c, 0x03, 00, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x16, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x52, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x45, 0x03, 0x20, 0x03, 0xcf, 0x09, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x38, 0x06, 0xe0, 0x03, 0x16, 0x03, 0x7c, 0x03, 0xdd, 0x03, 0x93, 0x03, 0x0c, 0x12, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0x4c, 0x06, 0xd0, 0x06, 0x34, 0x03, 0xd0, 0x03, 0x74, 0x03, 0x15, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x67, 0x06, 0xd0, 0x03, 00, 0x03, 0x1f, 0x03, 0xbf, 0x03, 0xd0, 0x03, 0x1f, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x1f, 0x03, 0x5a, 0x03, 0xce, 0x03, 0xcf, 0x03, 0x5c, 0x03, 00, 0x03, 0xe5, 0x03, 0xe6, 0x03, 0xd4, 0x06, 0xe5, 0x03, 0x90, 0x03, 00, 0x06, 0xe5, 0x03, 0x62, 0x03, 00, 0x03, 0x80, 0x03, 0xe5, 0x03, 0x90, 0x03, 00, 0x03, 0xdf, 0x03, 0xd7, 0x03, 0x5a, 0x03, 0x29, 0x03, 0xce, 0x12, 0xd0, 0x03, 0x5a, 0x03, 00, 0x03, 0x83, 0x03, 0xd0, 0x03, 0xbf, 0x03, 0x15, 0x03, 0x67, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0x58, 0x03, 0x2a, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xa1, 0x03, 00, 0x06, 0xe5, 0x03, 0x2d, 0x03, 0x54, 0x03, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0xb0, 0x03, 00, 0x03, 0xb0, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x34, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x0c, 0x03, 0xb0, 0x03, 0xd7, 0x03, 0xdf, 0x03, 0x2d, 0x03, 0x54, 0x1b, 0xe5, 0x03, 00, 0x03, 0x90, 0x03, 0xe6, 0x03, 0xe5, 0x03, 0xdf, 0x03, 0xd6, 0x03, 0xaf, 0x03, 00, 0x03, 0xb0, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x34, 0x06, 0xd0, 0x03, 0x15, 0x03, 0x41, 0x0c, 0xd0, 0x03, 0x74, 0x03, 0x0c, 0x03, 0xbf, 0x03, 0xd0, 0x03, 0xbf, 0x03, 0x0c, 0x03, 0x74, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0x41, 0x03, 0xd0, 0x03, 0xbf, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0xbf, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0xbf, 0x03, 0x35, 0x03, 0x2b, 0x03, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x38, 0x06, 0xe0, 0x03, 00, 0x03, 0x8c, 0x18, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x45, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x16, 0x03, 0xad, 0x03, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x16, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0x06, 0xe0, 0x03, 0x60, 0x03, 00, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x8c, 0x03, 00, 0x12, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0x52, 0x06, 0xe0, 0x06, 0x38, 0x06, 0xe0, 0x03, 00, 0x03, 0x2c, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x6e, 0x03, 0x0c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x06, 0xbd, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x38, 0x0f, 0xe0, 0x03, 0x6e, 0x03, 0x0c, 0x03, 0xad, 0x4b, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4b, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x0c, 0x03, 0x6e, 0x06, 0x9c, 0x03, 0x20, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0x20, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x0f, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0x20, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x38, 0x03, 0x52, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x6e, 0x03, 0x20, 0x06, 0x9c, 0x03, 0x6e, 0x03, 00, 0x0f, 0xe0, 0x03, 0xad, 0x03, 00, 0x09, 0x9c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x20, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x0c, 0x03, 0x7c, 0x0c, 0xe0, 0x03, 0x6e, 0x03, 0x20, 0x06, 0x9c, 0x03, 0x6e, 0x03, 00, 0x03, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0x9c, 0x03, 0x99, 0x03, 0x91, 0x03, 00, 0x03, 0x92, 0x0f, 0xd0, 0x03, 0x92, 0x03, 00, 0x09, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0xd0, 0x03, 0x34, 0x03, 0x41, 0x06, 0x92, 0x03, 0x41, 0x03, 0x29, 0x06, 0xd0, 0x03, 00, 0x03, 0x83, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0xb0, 0x03, 00, 0x03, 0xaf, 0x03, 0xcf, 0x03, 0xd3, 0x03, 0x99, 0x03, 00, 0x06, 0xe6, 0x06, 0xe5, 0x03, 0x9f, 0x03, 0x70, 0x03, 00, 0x06, 0xe5, 0x03, 0x62, 0x03, 0x21, 0x06, 0xe6, 0x03, 0xa0, 0x03, 00, 0x03, 0xd7, 0x03, 0xd1, 0x03, 0x59, 0x03, 0x29, 0x15, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x09, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0x58, 0x03, 0x2a, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xa1, 0x03, 00, 0x06, 0xe5, 0x03, 0x46, 0x03, 0x0d, 0x03, 0x9f, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0x67, 0x03, 0x1f, 0x06, 0x92, 0x03, 0x67, 0x03, 00, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x59, 0x03, 0xce, 0x03, 0xd1, 0x03, 0xd7, 0x03, 0x45, 0x03, 0x0d, 0x03, 0xa0, 0x03, 0xe6, 0x15, 0xe5, 0x03, 0x16, 0x03, 0x21, 0x03, 0xc3, 0x03, 0xe6, 0x03, 0xe2, 0x03, 0xdb, 0x03, 0x68, 0x03, 0x1f, 0x03, 0x91, 0x03, 0x92, 0x03, 0x67, 0x03, 00, 0x03, 0xd0, 0x03, 0xa0, 0x03, 00, 0x03, 0xb0, 0x0c, 0xd0, 0x03, 0x34, 0x03, 0x4c, 0x09, 0xd0, 0x03, 0x4c, 0x03, 0x34, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0xbf, 0x06, 0xd0, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x74, 0x03, 0x15, 0x09, 0xd0, 0x03, 0x59, 0x03, 0x2b, 0x03, 0xe0, 0x03, 0x6e, 0x03, 0x20, 0x06, 0x9c, 0x03, 0x6e, 0x03, 00, 0x06, 0xe0, 0x03, 0x16, 0x03, 0x20, 0x03, 0xbd, 0x15, 0xe0, 0x03, 0x6e, 0x03, 0x20, 0x09, 0xe0, 0x03, 0x8c, 0x03, 0x0c, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xad, 0x03, 00, 0x09, 0x9c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x20, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x18, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0x8c, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x45, 0x03, 0xe0, 0x03, 0x6e, 0x03, 0x20, 0x06, 0x9c, 0x03, 0x6e, 0x03, 00, 0x0c, 0xe0, 0x03, 0x7c, 0x03, 00, 0x03, 0x9c, 0x4e, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4b, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 00, 0x03, 0x20, 0x09, 0x2c, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0xcf, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x0c, 0x0c, 0x2c, 0x0f, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0x2c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x0c, 0xe0, 0x03, 0x60, 0x03, 0x0c, 0x0c, 0x2c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0x2b, 0x03, 0x2a, 0x06, 0x29, 0x03, 0xa0, 0x0f, 0xd0, 0x03, 0x92, 0x03, 00, 0x09, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0xd0, 0x03, 0x29, 0x03, 0x15, 0x09, 0x29, 0x03, 0x4c, 0x06, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xd9, 0x03, 0x9d, 0x03, 00, 0x03, 0xe6, 0x03, 0xe5, 0x03, 0x80, 0x03, 0x0d, 0x06, 0x21, 0x03, 00, 0x06, 0xe5, 0x03, 0x63, 0x03, 0x2d, 0x06, 0xe6, 0x03, 0x9c, 0x03, 00, 0x03, 0xd0, 0x03, 0xce, 0x03, 0x59, 0x03, 0x29, 0x15, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x09, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0x58, 0x03, 0x2a, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xa1, 0x03, 00, 0x06, 0xe5, 0x03, 0xd3, 0x03, 0x54, 0x03, 00, 0x03, 0x21, 0x03, 0xc3, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x0c, 0x0c, 0x29, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xce, 0x03, 0xd0, 0x03, 0xc7, 0x03, 0x52, 0x03, 00, 0x03, 0x21, 0x03, 0xc3, 0x03, 0xe6, 0x0f, 0xe5, 0x03, 0xc2, 0x03, 0x2d, 0x03, 00, 0x03, 0x39, 0x03, 0xe6, 0x03, 0xe1, 0x03, 0x5d, 0x03, 0x0c, 0x0c, 0x29, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x0f, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x09, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x09, 0xd0, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x09, 0xd0, 0x03, 0x58, 0x03, 0x2a, 0x03, 0xdf, 0x03, 0x60, 0x03, 0x0c, 0x0c, 0x2c, 0x06, 0xe0, 0x03, 0xbd, 0x03, 0x2c, 0x03, 00, 0x03, 0x38, 0x12, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0x2c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x12, 0xe0, 0x03, 0xad, 0x06, 0x16, 0x03, 0x2c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x45, 0x03, 0x38, 0x03, 0xe0, 0x03, 0x16, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x0c, 0x0c, 0x2c, 0x09, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x7c, 0x51, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4b, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x16, 0x03, 0x7c, 0x0f, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x45, 0x03, 0x2c, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x45, 0x03, 0x2c, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x06, 0x45, 0x06, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x1b, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x0f, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x16, 0x03, 0x7c, 0x0c, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x0f, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbb, 0x03, 0xd5, 0x03, 0xce, 0x15, 0xd0, 0x03, 0x92, 0x03, 00, 0x09, 0xd0, 0x03, 0x74, 0x03, 0x15, 0x03, 0xd0, 0x06, 0x41, 0x12, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0xcf, 0x03, 0xd5, 0x03, 0xdd, 0x03, 0x9f, 0x03, 00, 0x03, 0xe6, 0x03, 0xc2, 0x03, 00, 0x03, 0x90, 0x03, 0xe5, 0x03, 0x9f, 0x03, 00, 0x06, 0xe5, 0x03, 0x63, 0x03, 0x2d, 0x03, 0xe4, 0x03, 0xe1, 0x03, 0x97, 0x03, 00, 0x03, 0xcd, 0x03, 0xce, 0x03, 0x5a, 0x03, 0x2a, 0x15, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x09, 0xd0, 0x06, 0x41, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0x58, 0x03, 0x2a, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0x91, 0x03, 00, 0x0c, 0xe5, 0x03, 0xd3, 0x03, 0x21, 0x03, 0x39, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0x74, 0x03, 0x15, 0x12, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x4c, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0xce, 0x03, 0xcd, 0x03, 0xd0, 0x03, 0xd9, 0x03, 0xd0, 0x03, 0x21, 0x03, 0x39, 0x03, 0xe6, 0x15, 0xe5, 0x03, 0xb0, 0x03, 0x0d, 0x03, 0x71, 0x03, 0xe4, 0x03, 0x7b, 0x03, 0x15, 0x03, 0xcf, 0x0c, 0xd0, 0x03, 0xb0, 0x03, 00, 0x03, 0xb0, 0x0c, 0xd0, 0x03, 0x34, 0x03, 0x4c, 0x09, 0xd0, 0x03, 0x4c, 0x03, 0x34, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x09, 0xd0, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x09, 0xd0, 0x03, 0x59, 0x03, 0x2a, 0x03, 0xdc, 0x03, 0x7c, 0x03, 0x16, 0x18, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x6e, 0x0f, 0xe0, 0x03, 0x6e, 0x03, 0x20, 0x09, 0xe0, 0x03, 0x8c, 0x03, 0x0c, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x20, 0x03, 0x60, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x16, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x0f, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x12, 0xe0, 0x03, 0x16, 0x03, 0x52, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0x7c, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x12, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0x45, 0x54, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x0c, 0x03, 0x6e, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x2c, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0x03, 0x7c, 0x03, 0x8c, 0x03, 0x2c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0x6e, 0x06, 0xe0, 0x03, 0xcf, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x38, 0x09, 0xe0, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x16, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x20, 0x03, 0xcf, 0x06, 0xe0, 0x06, 0xcf, 0x03, 0x0c, 0x03, 0x6e, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x2b, 0x03, 0x37, 0x03, 0xd3, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xbf, 0x0f, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x41, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0xa0, 0x06, 0xd0, 0x03, 0xbf, 0x06, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x0c, 0x03, 0x67, 0x03, 0xda, 0x03, 0xd0, 0x03, 0x2d, 0x03, 00, 0x03, 0xe6, 0x03, 0x9f, 0x03, 00, 0x03, 0xd3, 0x03, 0xe5, 0x03, 0x80, 0x03, 00, 0x06, 0xe5, 0x03, 0x63, 0x03, 0x2d, 0x03, 0xe1, 0x03, 0xda, 0x03, 0x93, 0x03, 00, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x15, 0x15, 0xd0, 0x03, 0x5a, 0x03, 0x15, 0x03, 0xb0, 0x03, 0xd0, 0x03, 0xbf, 0x03, 0x0c, 0x03, 0x74, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0x58, 0x03, 0x1f, 0x03, 0xdf, 0x03, 0xd4, 0x03, 0x21, 0x03, 00, 0x06, 0xe5, 0x03, 0xd3, 0x06, 0xe5, 0x03, 0x55, 0x03, 0x39, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0xbf, 0x03, 0x0c, 0x03, 0x67, 0x06, 0xd0, 0x03, 0xbf, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x4c, 0x03, 0xd0, 0x03, 0xa0, 0x03, 0x0c, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0xcf, 0x03, 0xbe, 0x03, 0xd3, 0x03, 0xda, 0x03, 0x52, 0x03, 0x39, 0x03, 0xe6, 0x0f, 0xe5, 0x03, 0xd3, 0x06, 0xe5, 0x03, 0x21, 0x03, 0x71, 0x03, 0xe5, 0x03, 0xd0, 0x03, 0x0c, 0x03, 0x67, 0x06, 0xd0, 0x03, 0xbf, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x41, 0x06, 0xd0, 0x03, 0xbf, 0x03, 0xd0, 0x03, 0x74, 0x03, 0x0c, 0x03, 0xbf, 0x03, 0xd0, 0x03, 0xbf, 0x03, 0x0c, 0x03, 0x74, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x09, 0xd0, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0xa0, 0x03, 00, 0x03, 0xa0, 0x03, 0xd0, 0x03, 0xa0, 0x03, 0x15, 0x03, 0x2a, 0x03, 0xda, 0x03, 0xce, 0x03, 0x0c, 0x03, 0x6e, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x20, 0x03, 0x6e, 0x0f, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x45, 0x06, 0xe0, 0x03, 00, 0x03, 0x8c, 0x03, 0xe0, 0x03, 0x7c, 0x03, 00, 0x03, 0x60, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x38, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x38, 0x09, 0xe0, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x12, 0xe0, 0x03, 00, 0x03, 0x8c, 0x03, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x45, 0x06, 0xe0, 0x03, 00, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x16, 0x03, 0x0c, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0x6e, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 0x38, 0x57, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x7c, 0x03, 00, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x6e, 0x03, 00, 0x09, 0xe0, 0x03, 0x38, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x6e, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x8c, 0x03, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x45, 0x03, 0x0c, 0x03, 0x7c, 0x03, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x8c, 0x03, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x45, 0x03, 0x0c, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x8c, 0x03, 0x2c, 0x03, 0x45, 0x03, 0xad, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x2c, 0x03, 0x0c, 0x12, 0xe0, 0x03, 0xbd, 0x03, 0x20, 0x03, 0x16, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x06, 0x20, 0x03, 0x16, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x2c, 0x03, 0x0c, 0x06, 0xe0, 0x03, 0xbc, 0x03, 0x1f, 0x03, 0x15, 0x03, 0x29, 0x03, 0x0c, 0x03, 0xa0, 0x0f, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0x29, 0x03, 0x1f, 0x03, 0x15, 0x03, 0x1f, 0x03, 0xbf, 0x06, 0xd0, 0x03, 0x67, 0x03, 00, 0x03, 0x29, 0x03, 0x1f, 0x03, 0x34, 0x06, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0xcf, 0x03, 0x74, 0x03, 00, 0x03, 0x2b, 0x03, 0x16, 0x03, 0x71, 0x03, 00, 0x06, 0xe5, 0x03, 0x21, 0x03, 0x16, 0x03, 0x21, 0x03, 0x54, 0x03, 0x0d, 0x03, 0x21, 0x03, 0xe6, 0x03, 0x63, 0x03, 0x2c, 0x03, 0xdc, 0x03, 0xd4, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0xb0, 0x03, 0x0c, 0x03, 0x1f, 0x03, 0x74, 0x0f, 0xd0, 0x03, 0x5a, 0x06, 0x15, 0x03, 0x29, 0x03, 0x0c, 0x03, 0x41, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x16, 0x03, 0x71, 0x03, 00, 0x06, 0xe5, 0x03, 0x39, 0x06, 0x21, 0x03, 0x0d, 0x03, 0xb2, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x92, 0x03, 0x0c, 0x03, 0x1f, 0x03, 0x29, 0x03, 0x0c, 0x06, 0xd0, 0x03, 0x83, 0x03, 00, 0x03, 0x29, 0x03, 0x1f, 0x03, 0x4c, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x09, 0xd0, 0x03, 0x34, 0x06, 0x1f, 0x03, 0x0c, 0x03, 0xae, 0x09, 0xe6, 0x09, 0xe5, 0x03, 0x0d, 0x03, 0x2d, 0x03, 0x16, 0x03, 0x21, 0x03, 0xd3, 0x03, 0xe6, 0x03, 0xe5, 0x03, 0x9b, 0x03, 0x0c, 0x03, 0x1f, 0x03, 0x29, 0x03, 0x0c, 0x06, 0xd0, 0x03, 0xa0, 0x06, 0x15, 0x03, 0x29, 0x03, 0x0c, 0x06, 0xd0, 0x03, 0x4c, 0x03, 0x0c, 0x03, 0x29, 0x03, 0x0c, 0x03, 0x4c, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x09, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x41, 0x03, 0x0c, 0x03, 0x29, 0x03, 0x1f, 0x03, 0x4c, 0x03, 0x29, 0x03, 0xd7, 0x03, 0xdf, 0x03, 0x9c, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x2c, 0x03, 0x0c, 0x06, 0xe0, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x20, 0x03, 0xcf, 0x12, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x2c, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x45, 0x03, 0x2c, 0x03, 0x60, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x16, 0x03, 0x2c, 0x03, 00, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0xbd, 0x03, 0x20, 0x03, 0x16, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x12, 0xe0, 0x03, 0x52, 0x03, 0x0c, 0x09, 0x2c, 0x03, 0x16, 0x03, 0xad, 0x03, 0x9c, 0x03, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x16, 0x03, 0x20, 0x03, 0xcf, 0x06, 0xe0, 0x03, 00, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x20, 0x03, 0x0c, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x8c, 0x03, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x52, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x6e, 0x03, 0x16, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xe0, 0x03, 0x9c, 0x0f, 00, 0x03, 0x60, 0x4b, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x51, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xcf, 0x12, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xcf, 0x2d, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 0xcf, 0x24, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 0xcf, 0x0c, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xcf, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0xad, 0x1b, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x36, 0xe0, 0x06, 0x9c, 0x2a, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xcf, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0xad, 0x09, 0xe0, 0x03, 0xdd, 0x03, 0xd4, 0x03, 0x9f, 0x03, 0x92, 0x15, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0xd0, 0x06, 0xa0, 0x0f, 0xd0, 0x03, 0xbf, 0x03, 0x92, 0x03, 0xb0, 0x1e, 0xd0, 0x03, 0xcf, 0x03, 0xd1, 0x03, 0xb8, 0x03, 0x9d, 0x03, 0xd4, 0x03, 0xe6, 0x0c, 0xe5, 0x03, 0x9f, 0x03, 0xc2, 0x03, 0xe5, 0x03, 0xc2, 0x03, 0xb2, 0x03, 0xe6, 0x03, 0xe4, 0x03, 0xdf, 0x03, 0xd6, 0x03, 0xd0, 0x03, 0xcf, 0x0c, 0xd0, 0x03, 0xbf, 0x03, 0x92, 0x03, 0xbf, 0x0f, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x03, 0xd0, 0x03, 0x92, 0x03, 0xb0, 0x15, 0xd0, 0x03, 0xcd, 0x03, 0xc1, 0x03, 0x9c, 0x03, 0xd4, 0x03, 0xe7, 0x0c, 0xe5, 0x03, 0xb0, 0x03, 0x9f, 0x03, 0xd5, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x0f, 0xd0, 0x03, 0x92, 0x03, 0xa0, 0x0c, 0xd0, 0x03, 0xb0, 0x03, 0x92, 0x21, 0xd0, 0x03, 0x9f, 0x03, 0x92, 0x03, 0xc5, 0x03, 0xdf, 0x03, 0xe4, 0x06, 0xe6, 0x0c, 0xe5, 0x06, 0x9f, 0x06, 0xe5, 0x06, 0xe6, 0x03, 0xe1, 0x03, 0xda, 0x03, 0x92, 0x03, 0x9f, 0x0f, 0xd0, 0x06, 0x92, 0x0c, 0xd0, 0x03, 0xb0, 0x03, 0x92, 0x03, 0xb0, 0x27, 0xd0, 0x03, 0xa0, 0x03, 0x92, 0x06, 0xd0, 0x03, 0xce, 0x03, 0xd4, 0x03, 0xdd, 0x06, 0xe0, 0x03, 0x9c, 0x03, 0xad, 0x0c, 0xe0, 0x06, 0x9c, 0x1b, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xad, 0x0f, 0xe0, 0x06, 0xad, 0x1b, 0xe0, 0x03, 0xad, 0x06, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x1b, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x30, 0xe0, 0x06, 0xad, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xe0, 0x06, 0xad, 0x0c, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xbd, 0x03, 0x9c, 0x0f, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x12, 0xe0, 0x03, 0x45, 0x03, 0x6e, 0x12, 0xe0, 0x03, 0x9c, 0x03, 0xad, 0x66, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xea, 0xe0, 0x03, 0xad, 0x03, 0x52, 0x03, 0x9c, 0x03, 0x8c, 0x03, 0x20, 0x03, 0x2c, 0xc0, 0xe0, 0x03, 0xdb, 0x03, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x15, 0xd0, 0x03, 0x92, 0x03, 00, 0x3c, 0xd0, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xd4, 0x03, 0xdf, 0x03, 0xe4, 0x1e, 0xe5, 0x03, 0xe6, 0x03, 0xe5, 0x03, 0xe1, 0x03, 0xd9, 0x03, 0xd1, 0x06, 0xcf, 0x24, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x1e, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x48, 0xd0, 0x06, 0xcf, 0x03, 0xd1, 0x03, 0xd9, 0x03, 0xe1, 0x03, 0xe5, 0x03, 0xe6, 0x1e, 0xe5, 0x03, 0xe4, 0x03, 0xdf, 0x03, 0xd4, 0x03, 0xd0, 0x03, 0xcf, 0x57, 0xd0, 0x03, 0xd1, 0x03, 0xcd, 0x03, 0xd0, 0x03, 0xdb, 0xe4, 0xe0, 0x03, 0x9c, 0x03, 00, 0x15, 0xe0, 0x03, 00, 0x03, 0x9c, 0x2a, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0xcf, 0x7e, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xea, 0xe0, 0x03, 0xcf, 0x03, 0x52, 0x06, 0x2c, 0x03, 0x60, 0x03, 0xcf, 0xbd, 0xe0, 0x03, 0xdf, 0x03, 0xda, 0x03, 0xd0, 0x03, 0xce, 0x03, 0xd1, 0x15, 0xd0, 0x03, 0xb0, 0x03, 0x5a, 0x3c, 0xd0, 0x03, 0xcf, 0x03, 0xd1, 0x03, 0xd7, 0x03, 0xe1, 0x03, 0xe6, 0x1b, 0xe5, 0x06, 0xe6, 0x03, 0xe4, 0x03, 0xdc, 0x03, 0xd4, 0x03, 0xce, 0x2a, 0xd0, 0x03, 0x92, 0x03, 0x74, 0x1e, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x4e, 0xd0, 0x03, 0xce, 0x03, 0xd4, 0x03, 0xdc, 0x03, 0xe4, 0x06, 0xe6, 0x1b, 0xe5, 0x03, 0xe6, 0x03, 0xe1, 0x03, 0xd7, 0x03, 0xd1, 0x03, 0xcf, 0x57, 0xd0, 0x03, 0xd1, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xda, 0x03, 0xdf, 0xe1, 0xe0, 0x03, 0xbd, 0x03, 0x60, 0x15, 0xe0, 0x03, 0x60, 0x03, 0xbd, 0x2a, 0xe0, 0x03, 0xad, 0x03, 0x8c, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xba, 0xe0, 0x03, 0xdd, 0x03, 0xd7, 0x03, 0xd0, 0x03, 0xce, 0x57, 0xd0, 0x06, 0xcf, 0x03, 0xd4, 0x03, 0xdc, 0x03, 0xe4, 0x03, 0xe6, 0x1b, 0xe5, 0x06, 0xe6, 0x03, 0xe0, 0x03, 0xd7, 0x03, 0xcf, 0x03, 0xce, 0x4e, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x4e, 0xd0, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd7, 0x03, 0xe0, 0x06, 0xe6, 0x1b, 0xe5, 0x03, 0xe6, 0x03, 0xe4, 0x03, 0xdc, 0x03, 0xd4, 0x06, 0xcf, 0x57, 0xd0, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xd7, 0x03, 0xdd, 0xff, 0xe0, 0xb4, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xb7, 0xe0, 0x03, 0xdf, 0x03, 0xdb, 0x03, 0xd5, 0x03, 0xd0, 0x03, 0xcf, 0x57, 0xd0, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd7, 0x03, 0xe1, 0x03, 0xe5, 0x03, 0xe6, 0x18, 0xe5, 0x06, 0xe6, 0x03, 0xe2, 0x03, 0xda, 0x03, 0xd3, 0x03, 0xce, 0x03, 0xcf, 0x4e, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x4e, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xd3, 0x03, 0xda, 0x03, 0xe2, 0x06, 0xe6, 0x18, 0xe5, 0x03, 0xe6, 0x03, 0xe5, 0x03, 0xe1, 0x03, 0xd7, 0x03, 0xcf, 0x03, 0xce, 0x57, 0xd0, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xd5, 0x03, 0xdb, 0x03, 0xdf, 0xff, 0xe0, 0xb1, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xab, 0xe0, 0x06, 0xad, 0x06, 0xe0, 0x03, 0xdf, 0x03, 0xda, 0x03, 0xd3, 0x03, 0xcf, 0x5a, 0xd0, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xda, 0x03, 0xe4, 0x1b, 0xe5, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0xdf, 0x03, 0xd5, 0x03, 0xcf, 0x03, 0xce, 0x51, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x51, 0xd0, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd5, 0x03, 0xdf, 0x03, 0xe5, 0x06, 0xe6, 0x1b, 0xe5, 0x03, 0xe4, 0x03, 0xda, 0x03, 0xd0, 0x03, 0xce, 0x5a, 0xd0, 0x03, 0xcf, 0x03, 0xd3, 0x03, 0xda, 0x03, 0xdf, 0xff, 0xe0, 0xb1, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x96, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x27, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x9c, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x3c, 0xe0, 0x03, 0x8c, 0x03, 0x0c, 0x03, 0xad, 0x06, 0xe0, 0x03, 0xbc, 0x03, 0x5d, 0x03, 0xd0, 0x03, 0xcf, 0x18, 0xd0, 0x03, 0xb0, 0x03, 0x5a, 0x15, 0xd0, 0x03, 0x74, 0x03, 0x92, 0x1b, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0xd5, 0x03, 0x60, 0x03, 0xc3, 0x03, 0xe6, 0x18, 0xe5, 0x06, 0xe6, 0x03, 0xe2, 0x03, 0xdb, 0x03, 0xd1, 0x06, 0xce, 0x0c, 0xd0, 0x03, 0x92, 0x03, 0x74, 0x3f, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x51, 0xd0, 0x06, 0xce, 0x03, 0xd1, 0x03, 0xdb, 0x03, 0xe2, 0x06, 0xe6, 0x18, 0xe5, 0x06, 0xe6, 0x03, 0xdf, 0x03, 0xd5, 0x5d, 0xd0, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xda, 0x03, 0xdf, 0xff, 0xe0, 0xb1, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x96, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x27, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x42, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x54, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x39, 0xe0, 0x03, 0xcf, 0x03, 0x38, 0x03, 0xad, 0x09, 0xe0, 0x03, 0xac, 0x03, 0x2a, 0x03, 0xcd, 0x03, 0xcf, 0x18, 0xd0, 0x03, 0xa0, 0x03, 0x29, 0x06, 0xd0, 0x03, 0xb0, 0x03, 0xa0, 0x09, 0xd0, 0x03, 0x4c, 0x03, 0x74, 0x1b, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xd1, 0x03, 0xd9, 0x03, 0x2c, 0x03, 0xb3, 0x03, 0xe6, 0x18, 0xe5, 0x06, 0xe6, 0x03, 0xe0, 0x03, 0xd6, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xaf, 0x03, 0xa0, 0x09, 0xd0, 0x03, 0x74, 0x03, 0x4c, 0x3f, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x51, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd6, 0x03, 0xe0, 0x06, 0xe6, 0x18, 0xe5, 0x03, 0xe6, 0x03, 0xe7, 0x03, 0xe2, 0x03, 0xd9, 0x03, 0xd1, 0x5a, 0xd0, 0x03, 0xcf, 0x03, 0xcd, 0x03, 0xd7, 0x03, 0xdf, 0xff, 0xe0, 0xb1, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x51, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xbd, 0x27, 0xe0, 0x03, 0xcf, 0x03, 0xad, 0x0f, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0xbd, 0x15, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x0f, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xbd, 0x21, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0f, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xcf, 0x12, 0xe0, 0x06, 0xad, 0x1b, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x1e, 0xe0, 0x03, 0x9c, 0x09, 0xe0, 0x06, 0xad, 0x06, 0xe0, 0x03, 0xdf, 0x03, 0xdc, 0x03, 0xd4, 0x03, 0xcd, 0x03, 0xcf, 0x03, 0xd1, 0x06, 0xd0, 0x06, 0xa0, 0x15, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x18, 0xd0, 0x03, 0xa0, 0x03, 0x92, 0x03, 0xb0, 0x09, 0xd0, 0x03, 0x29, 0x03, 0x59, 0x03, 0xd4, 0x03, 0xdb, 0x03, 0xe4, 0x06, 0xe6, 0x06, 0xe5, 0x06, 0x9f, 0x0c, 0xe5, 0x03, 0xd3, 0x03, 0x9f, 0x03, 0x9a, 0x03, 0xd3, 0x03, 0xce, 0x03, 0xcf, 0x03, 0x5a, 0x03, 0x29, 0x1b, 0xd0, 0x06, 0x92, 0x15, 0xd0, 0x03, 0x92, 0x03, 0xb0, 0x12, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x54, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xd3, 0x03, 0xdc, 0x03, 0xe4, 0x1b, 0xe5, 0x06, 0xe6, 0x03, 0xe4, 0x03, 0xdb, 0x03, 0xd4, 0x06, 0xcf, 0x51, 0xd0, 0x03, 0xd1, 0x03, 0xcf, 0x03, 0xcd, 0x03, 0xd4, 0x03, 0xdd, 0xff, 0xe0, 0xb1, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x52, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x16, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x60, 0x03, 0x20, 0x03, 0x52, 0x0f, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x7c, 0x12, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0x45, 0x03, 0x20, 0x03, 0x16, 0x03, 0x20, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x52, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x09, 00, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0x45, 0x03, 0x20, 0x03, 0x0c, 0x03, 0x52, 0x15, 0xe0, 0x03, 0x45, 0x03, 0x0c, 0x03, 0x2c, 0x06, 0x16, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x03, 0x20, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xcf, 0x06, 0x20, 0x03, 0x16, 0x03, 0x45, 0x03, 0xe0, 0x03, 0xdf, 0x03, 0x9a, 0x03, 00, 0x03, 0xcd, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x03, 0x41, 0x03, 0x1f, 0x03, 0x0c, 0x03, 0x4c, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0xd0, 0x03, 0x92, 0x09, 00, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x0c, 0x03, 0x1f, 0x03, 0x29, 0x03, 00, 0x03, 0x83, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x59, 0x03, 0xd4, 0x03, 0xdd, 0x03, 00, 0x03, 0xa0, 0x03, 0xe5, 0x03, 0xc2, 0x03, 0x0d, 0x03, 0x21, 0x03, 0x2d, 0x03, 0x62, 0x06, 0xe5, 0x03, 0x71, 0x03, 0x0d, 0x03, 0x2c, 0x03, 0x15, 0x03, 0x1f, 0x03, 0xce, 0x03, 0x92, 0x09, 00, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0xa0, 0x03, 0x15, 0x06, 0x1f, 0x03, 0x15, 0x03, 0xa0, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x4c, 0x03, 0x1f, 0x03, 0x29, 0x03, 00, 0x03, 0x83, 0x0f, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x57, 0xd0, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xd7, 0x03, 0xe1, 0x03, 0xe5, 0x03, 0xe6, 0x18, 0xe5, 0x03, 0xe6, 0x03, 0xe5, 0x03, 0xdd, 0x03, 0xd4, 0x06, 0xce, 0x51, 0xd0, 0x03, 0xd1, 0x03, 0xd0, 0x03, 0xcd, 0x03, 0xd4, 0x03, 0xdc, 0xff, 0xe0, 0xb1, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 00, 0x03, 0x8c, 0x0f, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x2c, 0x03, 0xcf, 0x12, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x16, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0x12, 0xe0, 0x03, 0x60, 0x03, 00, 0x03, 0x8c, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x16, 0x03, 0x6e, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x45, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x60, 0x03, 00, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x8c, 0x03, 00, 0x12, 0xe0, 0x03, 0x8c, 0x03, 0x0c, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0xbd, 0x03, 0x16, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x38, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xbd, 0x06, 0xe0, 0x06, 0x45, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0xad, 0x03, 0xdd, 0x03, 0x99, 0x03, 00, 0x03, 0xce, 0x03, 0xd0, 0x03, 0x5a, 0x03, 00, 0x03, 0x74, 0x03, 0xd0, 0x03, 0x83, 0x03, 00, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x09, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0xbf, 0x06, 0xd0, 0x03, 0x4c, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x59, 0x03, 0xd6, 0x03, 0xe0, 0x03, 00, 0x03, 0x9f, 0x03, 0xe5, 0x03, 0x62, 0x03, 0x21, 0x0f, 0xe5, 0x03, 0xd4, 0x03, 0xe4, 0x03, 0xdd, 0x03, 0xc4, 0x03, 00, 0x03, 0x90, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x09, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x15, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x15, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x0c, 0x03, 0xa0, 0x03, 0xd0, 0x03, 0x4c, 0x03, 0x29, 0x0f, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x57, 0xd0, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd5, 0x03, 0xdd, 0x03, 0xe4, 0x03, 0xe6, 0x1b, 0xe5, 0x03, 0xe6, 0x03, 0xe0, 0x03, 0xd6, 0x06, 0xce, 0x51, 0xd0, 0x03, 0xd1, 0x03, 0xd0, 0x03, 0xce, 0x03, 0xd3, 0x03, 0xdc, 0x03, 0xdf, 0xff, 0xe0, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x16, 0x03, 0x20, 0x03, 0xbd, 0x0c, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x15, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xad, 0x03, 00, 0x09, 0x9c, 0x03, 00, 0x03, 0x9c, 0x0f, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x38, 0x03, 0x52, 0x09, 0xe0, 0x03, 0x52, 0x03, 0x38, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x0c, 0x03, 0x8c, 0x09, 0xe0, 0x03, 0x20, 0x03, 0x6e, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x20, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x12, 0xe0, 0x06, 0x45, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x6e, 0x03, 0x20, 0x06, 0x9c, 0x03, 0x6e, 0x03, 00, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x0c, 0x03, 0x6e, 0x06, 0x9c, 0x03, 0x20, 0x03, 0x60, 0x03, 0xdc, 0x03, 0x99, 0x03, 00, 0x03, 0xce, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x1f, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x09, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x09, 0xd0, 0x03, 0xbf, 0x03, 0x92, 0x03, 0x41, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xda, 0x03, 0xe2, 0x03, 00, 0x03, 0x9f, 0x03, 0xe5, 0x03, 0x80, 0x03, 00, 0x03, 0x70, 0x0c, 0xe5, 0x03, 0xe6, 0x03, 0xe4, 0x03, 0xa8, 0x03, 0x93, 0x03, 00, 0x03, 0x91, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x09, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x03, 0xd0, 0x03, 0xa0, 0x03, 00, 0x03, 0xbf, 0x06, 0xd0, 0x03, 0xbf, 0x03, 00, 0x03, 0xa0, 0x03, 0xd0, 0x03, 0x29, 0x03, 0x4c, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x0f, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x57, 0xd0, 0x06, 0xcf, 0x03, 0xd3, 0x03, 0xda, 0x03, 0xe4, 0x03, 0xe6, 0x1b, 0xe5, 0x03, 0xe7, 0x03, 0xe2, 0x03, 0xda, 0x03, 0xd0, 0x03, 0xce, 0x51, 0xd0, 0x03, 0xd1, 0x03, 0xd0, 0x03, 0xce, 0x03, 0xd3, 0x03, 0xdb, 0x03, 0xdf, 0xff, 0xe0, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0xbd, 0x03, 0x2c, 0x03, 00, 0x03, 0x38, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x15, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0x2c, 0x03, 0xad, 0x0f, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x0c, 0x0c, 0x2c, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 00, 0x03, 0x20, 0x09, 0x2c, 0x03, 0x7c, 0x03, 0xdb, 0x03, 0x96, 0x03, 00, 0x03, 0xce, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x09, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x4c, 0x03, 00, 0x03, 0x29, 0x03, 0x15, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5b, 0x03, 0xdb, 0x03, 0xe4, 0x03, 00, 0x03, 0x9f, 0x06, 0xe5, 0x03, 0x70, 0x06, 0x0d, 0x03, 0x9f, 0x06, 0xe5, 0x03, 0xb2, 0x03, 0x16, 0x03, 0x15, 0x03, 0x29, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x09, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x0c, 0xd0, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x0f, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x5a, 0xd0, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xd6, 0x03, 0xe1, 0x03, 0xe6, 0x1b, 0xe5, 0x03, 0xe7, 0x03, 0xe4, 0x03, 0xdb, 0x03, 0xd3, 0x03, 0xcf, 0x51, 0xd0, 0x03, 0xd1, 0x03, 0xd0, 0x03, 0xce, 0x03, 0xd1, 0x03, 0xda, 0x03, 0xdd, 0xff, 0xe0, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x54, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x6e, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x20, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x15, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x1b, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x06, 0x45, 0x03, 0xe0, 0x03, 0x38, 0x03, 0x52, 0x09, 0xe0, 0x03, 0x52, 0x03, 0x38, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x0c, 0x03, 0x8c, 0x09, 0xe0, 0x03, 0x20, 0x03, 0x6e, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x1e, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x16, 0x03, 0x7c, 0x0c, 0xe0, 0x03, 0xda, 0x03, 0x95, 0x03, 00, 0x03, 0xce, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x09, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0x74, 0x03, 0x0c, 0x03, 0xb0, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x03, 0xd0, 0x03, 0xcf, 0x03, 0x29, 0x03, 0x5b, 0x03, 0xdd, 0x03, 0xe5, 0x03, 00, 0x03, 0x9f, 0x0c, 0xe5, 0x03, 0x46, 0x03, 0x0d, 0x03, 0xe5, 0x03, 0xe6, 0x03, 0x16, 0x03, 0x52, 0x03, 0xd4, 0x03, 0xcf, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x09, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x03, 0xd0, 0x03, 0xa0, 0x03, 00, 0x03, 0xbf, 0x06, 0xd0, 0x03, 0xbf, 0x03, 00, 0x03, 0xa0, 0x03, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x0f, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x5a, 0xd0, 0x06, 0xcf, 0x03, 0xd4, 0x03, 0xdf, 0x03, 0xe5, 0x03, 0xe6, 0x18, 0xe5, 0x03, 0xe7, 0x03, 0xe5, 0x03, 0xdd, 0x03, 0xd4, 0x06, 0xcf, 0x54, 0xd0, 0x03, 0xce, 0x03, 0xd1, 0x03, 0xd7, 0x03, 0xdc, 0xff, 0xe0, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x20, 0x03, 0x6e, 0x06, 0xe0, 0x03, 00, 0x03, 0x8c, 0x03, 0xe0, 0x03, 0x7c, 0x03, 00, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x15, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x38, 0x09, 0xe0, 0x03, 0xcf, 0x0f, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x45, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xbd, 0x06, 0xe0, 0x03, 0x45, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x12, 0xe0, 0x03, 0x6e, 0x03, 0x16, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x8c, 0x03, 00, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0x6e, 0x06, 0xe0, 0x03, 0xcf, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0xd7, 0x03, 0x95, 0x03, 00, 0x03, 0xce, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x15, 0x09, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x1f, 0x06, 0xd0, 0x03, 0x41, 0x03, 0x29, 0x03, 0xd0, 0x03, 0xcf, 0x03, 0x29, 0x03, 0x5c, 0x03, 0xdf, 0x03, 0xe6, 0x03, 00, 0x03, 0x9f, 0x03, 0xe5, 0x03, 0xd3, 0x06, 0xe5, 0x03, 0x90, 0x03, 0x0d, 0x03, 0xe5, 0x03, 0xe6, 0x03, 00, 0x03, 0x89, 0x03, 0xd0, 0x03, 0xae, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x15, 0x09, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x15, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x15, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x06, 0x74, 0x03, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x5a, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xdb, 0x03, 0xe4, 0x03, 0xe6, 0x18, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd6, 0x03, 0xd0, 0x03, 0xcf, 0x54, 0xd0, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xd6, 0x03, 0xdb, 0xff, 0xe0, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x20, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x45, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x15, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0xbd, 0x03, 0x20, 0x03, 0x16, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x0f, 0xe0, 0x03, 0x60, 0x06, 0x16, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x45, 0x09, 0xe0, 0x03, 0x52, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x52, 0x09, 0xe0, 0x03, 0x20, 0x06, 0x16, 0x03, 0x7c, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x20, 0x03, 0x16, 0x03, 0x52, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x12, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 0x16, 0x03, 0x20, 0x03, 0x45, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x2c, 0x03, 0x0c, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x0c, 0xe0, 0x03, 0x38, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x6e, 0x03, 0xd6, 0x03, 0x94, 0x03, 00, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0xb0, 0x03, 0x0c, 0x03, 0x1f, 0x03, 0x74, 0x03, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0xb0, 0x03, 0x0c, 0x06, 0x1f, 0x03, 0x4c, 0x03, 00, 0x03, 0x4c, 0x03, 0xce, 0x03, 0x29, 0x03, 0x5d, 0x03, 0xe0, 0x03, 0xe6, 0x03, 00, 0x03, 0x9f, 0x03, 0xe5, 0x03, 0x70, 0x03, 0x16, 0x03, 0x2d, 0x03, 00, 0x03, 0x81, 0x06, 0xe6, 0x03, 0x52, 0x03, 0x0c, 0x09, 0x29, 0x03, 0x15, 0x03, 0xa0, 0x03, 0xb0, 0x03, 0x0c, 0x03, 0x1f, 0x03, 0x74, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x03, 0xa0, 0x03, 0x15, 0x06, 0x1f, 0x03, 0x15, 0x03, 0xa0, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x06, 0xd0, 0x06, 0x29, 0x03, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x5a, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xd9, 0x03, 0xe1, 0x09, 0xe6, 0x12, 0xe5, 0x06, 0xe6, 0x03, 0xe0, 0x03, 0xd9, 0x03, 0xd0, 0x03, 0xce, 0x54, 0xd0, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xd5, 0x03, 0xda, 0xff, 0xe0, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x51, 0xe0, 0x06, 0x9c, 0x0f, 0xe0, 0x06, 0xad, 0x3c, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x15, 0xe0, 0x06, 0xbd, 0x03, 0xe0, 0x03, 0x9c, 0x03, 0xbd, 0x0f, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xbd, 0x0f, 0xe0, 0x03, 0x9c, 0x03, 0xbd, 0x12, 0xe0, 0x03, 0x9c, 0x03, 0xbd, 0x09, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xcf, 0x33, 0xe0, 0x03, 0x9c, 0x03, 0xad, 0x15, 0xe0, 0x03, 0x9c, 0x03, 0xad, 0x2a, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0xd5, 0x03, 0xd1, 0x03, 0xd0, 0x03, 0xcf, 0x2a, 0xd0, 0x03, 0xbf, 0x03, 0x92, 0x03, 0xbf, 0x0f, 0xd0, 0x03, 0xbf, 0x03, 0x92, 0x03, 0xbf, 0x03, 0xd0, 0x03, 0xa0, 0x03, 0xb0, 0x03, 0xcd, 0x03, 0xd0, 0x03, 0xda, 0x03, 0xe1, 0x06, 0xe6, 0x09, 0xe5, 0x03, 0xc2, 0x03, 0x9f, 0x03, 0xc2, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0xe0, 0x03, 0xa6, 0x03, 0xa0, 0x03, 0xcf, 0x03, 0xbf, 0x03, 0x92, 0x06, 0xd0, 0x03, 0xbf, 0x03, 0x92, 0x03, 0xbf, 0x15, 0xd0, 0x06, 0x92, 0x2d, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x5d, 0xd0, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xd7, 0x03, 0xe0, 0x03, 0xe5, 0x06, 0xe6, 0x12, 0xe5, 0x06, 0xe6, 0x03, 0xe1, 0x03, 0xda, 0x03, 0xd0, 0x03, 0xcd, 0x54, 0xd0, 0x06, 0xcf, 0x03, 0xd4, 0x03, 0xda, 0xff, 0xe0, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xb4, 0xe0, 0x03, 0xd3, 0x5d, 0xd0, 0x03, 0xcd, 0x03, 0xd0, 0x03, 0xdb, 0x03, 0xe2, 0x06, 0xe6, 0x12, 0xe5, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0xdd, 0x03, 0xd5, 0x03, 0xd0, 0x03, 0xcf, 0x5d, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x5d, 0xd0, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xd5, 0x03, 0xdd, 0x03, 0xe5, 0x06, 0xe6, 0x12, 0xe5, 0x06, 0xe6, 0x03, 0xe2, 0x03, 0xdb, 0x03, 0xd0, 0x03, 0xcd, 0x5a, 0xd0, 0x03, 0xd3, 0x03, 0xd9, 0xff, 0xe0, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xb4, 0xe0, 0x03, 0xd1, 0x03, 0xcf, 0x5a, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdc, 0x03, 0xe4, 0x06, 0xe6, 0x12, 0xe5, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0xdc, 0x03, 0xd3, 0x03, 0xd0, 0x03, 0xcf, 0x5d, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x5d, 0xd0, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xd3, 0x03, 0xdc, 0x03, 0xe5, 0x06, 0xe6, 0x12, 0xe5, 0x06, 0xe6, 0x03, 0xe4, 0x03, 0xdc, 0x03, 0xd1, 0x03, 0xcd, 0x5a, 0xd0, 0x03, 0xd1, 0x03, 0xd7, 0xff, 0xe0, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xb4, 0xe0, 0x03, 0xd0, 0x03, 0xcf, 0x5a, 0xd0, 0x03, 0xcd, 0x03, 0xd3, 0x03, 0xdd, 0x03, 0xe4, 0x06, 0xe6, 0x12, 0xe5, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0xdb, 0x03, 0xd1, 0x03, 0xd0, 0x03, 0xcf, 0x5d, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x5d, 0xd0, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xd1, 0x03, 0xdb, 0x03, 0xe5, 0x06, 0xe6, 0x12, 0xe5, 0x06, 0xe6, 0x03, 0xe4, 0x03, 0xdd, 0x03, 0xd3, 0x03, 0xcd, 0x5d, 0xd0, 0x03, 0xd6, 0xff, 0xe0, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xb4, 0xe0, 0x03, 0xcf, 0x03, 0xce, 0x5a, 0xd0, 0x03, 0xcb, 0x03, 0xd3, 0x03, 0xdf, 0x03, 0xe5, 0x06, 0xe6, 0x12, 0xe5, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0xda, 0x66, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x66, 0xd0, 0x03, 0xda, 0x03, 0xe5, 0x06, 0xe6, 0x12, 0xe5, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0xdf, 0x03, 0xd3, 0x03, 0xcb, 0x5a, 0xd0, 0x03, 0xcf, 0x03, 0xd4, 0xff, 0xe0, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xb4, 0xe0, 0x03, 0xce, 0x03, 0xcd, 0x5a, 0xd0, 0x03, 0xcb, 0x03, 0xd4, 0x03, 0xe0, 0x09, 0xe6, 0x12, 0xe5, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0xd9, 0x03, 0xcf, 0x63, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x63, 0xd0, 0x03, 0xcf, 0x03, 0xd9, 0x03, 0xe5, 0x06, 0xe6, 0x12, 0xe5, 0x09, 0xe6, 0x03, 0xe0, 0x03, 0xd4, 0x03, 0xcb, 0x5a, 0xd0, 0x03, 0xcf, 0x03, 0xd3, 0xff, 0xe0, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xb4, 0xe0, 0x06, 0xcd, 0x03, 0xcf, 0x57, 0xd0, 0x03, 0xcb, 0x03, 0xd4, 0x03, 0xe0, 0x06, 0xe6, 0x15, 0xe5, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0xd7, 0x03, 0xce, 0x63, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x63, 0xd0, 0x03, 0xce, 0x03, 0xd7, 0x03, 0xe5, 0x06, 0xe6, 0x15, 0xe5, 0x06, 0xe6, 0x03, 0xe0, 0x03, 0xd4, 0x03, 0xcb, 0x57, 0xd0, 0x06, 0xcf, 0x03, 0xd3, 0xff, 0xe0, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xb4, 0xe0, 0x06, 0xcd, 0x03, 0xcf, 0x57, 0xd0, 0x03, 0xcb, 0x03, 0xd4, 0x03, 0xe0, 0x06, 0xe6, 0x15, 0xe5, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0xd7, 0x03, 0xcd, 0x63, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x12, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x63, 0xd0, 0x03, 0xcd, 0x03, 0xd7, 0x03, 0xe5, 0x06, 0xe6, 0x15, 0xe5, 0x06, 0xe6, 0x03, 0xe0, 0x03, 0xd4, 0x03, 0xcb, 0x57, 0xd0, 0x06, 0xcf, 0x03, 0xd3, 0xff, 0xe0, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xb4, 0xe0, 0x03, 0xcb, 0x03, 0xcd, 0x03, 0xcf, 0x57, 0xd0, 0x03, 0xcb, 0x03, 0xd4, 0x03, 0xe1, 0x06, 0xe6, 0x15, 0xe5, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0xd6, 0x03, 0xcd, 0x63, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdf, 0x06, 0xe6, 0x12, 0xe5, 0x06, 0xe6, 0x03, 0xdf, 0x03, 0xd1, 0x03, 0xcd, 0x63, 0xd0, 0x03, 0xcd, 0x03, 0xd6, 0x03, 0xe5, 0x06, 0xe6, 0x15, 0xe5, 0x06, 0xe6, 0x03, 0xe1, 0x03, 0xd4, 0x03, 0xcb, 0x57, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xd1, 0xff, 0xe0, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xb4, 0xe0, 0x03, 0xcb, 0x03, 0xcd, 0x03, 0xcf, 0x57, 0xd0, 0x03, 0xcb, 0x03, 0xd4, 0x03, 0xe1, 0x06, 0xe6, 0x15, 0xe5, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0xd6, 0x03, 0xcd, 0x63, 0xd0, 0x03, 0xcd, 0x03, 0xd0, 0x03, 0xdc, 0x03, 0xe5, 0x03, 0xe6, 0x12, 0xe5, 0x03, 0xe6, 0x03, 0xe5, 0x03, 0xdc, 0x03, 0xd0, 0x03, 0xcd, 0x63, 0xd0, 0x03, 0xcd, 0x03, 0xd6, 0x03, 0xe5, 0x06, 0xe6, 0x15, 0xe5, 0x06, 0xe6, 0x03, 0xe1, 0x03, 0xd4, 0x03, 0xcb, 0x57, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xd1, 0xff, 0xe0, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xb4, 0xe0, 0x06, 0xcd, 0x03, 0xcf, 0x57, 0xd0, 0x03, 0xcb, 0x03, 0xd4, 0x03, 0xe0, 0x06, 0xe6, 0x15, 0xe5, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0xd7, 0x03, 0xcd, 0x63, 0xd0, 0x03, 0xcd, 0x03, 0xd0, 0x03, 0xda, 0x03, 0xe2, 0x06, 0xe6, 0x0c, 0xe5, 0x06, 0xe6, 0x03, 0xe2, 0x03, 0xda, 0x03, 0xd0, 0x03, 0xcd, 0x63, 0xd0, 0x03, 0xcd, 0x03, 0xd7, 0x03, 0xe5, 0x06, 0xe6, 0x15, 0xe5, 0x06, 0xe6, 0x03, 0xe0, 0x03, 0xd4, 0x03, 0xcb, 0x57, 0xd0, 0x06, 0xcf, 0x03, 0xd3, 0xff, 0xe0, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xb4, 0xe0, 0x06, 0xcd, 0x03, 0xcf, 0x57, 0xd0, 0x03, 0xcb, 0x03, 0xd4, 0x03, 0xe0, 0x06, 0xe6, 0x15, 0xe5, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0xd7, 0x03, 0xce, 0x63, 0xd0, 0x03, 0xcd, 0x03, 0xd0, 0x03, 0xd7, 0x03, 0xe0, 0x03, 0xe6, 0x03, 0xe7, 0x03, 0xe6, 0x06, 0xe5, 0x03, 0xe6, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xe0, 0x03, 0xd7, 0x03, 0xd0, 0x03, 0xcd, 0x63, 0xd0, 0x03, 0xce, 0x03, 0xd7, 0x03, 0xe5, 0x06, 0xe6, 0x15, 0xe5, 0x06, 0xe6, 0x03, 0xe0, 0x03, 0xd4, 0x03, 0xcb, 0x57, 0xd0, 0x06, 0xcf, 0x03, 0xd3, 0xff, 0xe0, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xb4, 0xe0, 0x03, 0xce, 0x03, 0xcd, 0x03, 0xcf, 0x57, 0xd0, 0x03, 0xcb, 0x03, 0xd4, 0x03, 0xe0, 0x09, 0xe6, 0x12, 0xe5, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0xd9, 0x03, 0xcf, 0x63, 0xd0, 0x06, 0xcf, 0x03, 0xd4, 0x03, 0xdb, 0x03, 0xe2, 0x12, 0xe6, 0x03, 0xe2, 0x03, 0xdb, 0x03, 0xd4, 0x06, 0xcf, 0x63, 0xd0, 0x03, 0xcf, 0x03, 0xd9, 0x03, 0xe5, 0x06, 0xe6, 0x12, 0xe5, 0x09, 0xe6, 0x03, 0xe0, 0x03, 0xd4, 0x03, 0xcb, 0x57, 0xd0, 0x06, 0xcf, 0x03, 0xd3, 0xff, 0xe0, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xb4, 0xe0, 0x03, 0xcf, 0x03, 0xcd, 0x03, 0xcf, 0x57, 0xd0, 0x03, 0xcb, 0x03, 0xd3, 0x03, 0xdf, 0x03, 0xe5, 0x06, 0xe6, 0x12, 0xe5, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0xda, 0x03, 0xd0, 0x03, 0xcf, 0x63, 0xd0, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd4, 0x03, 0xda, 0x03, 0xe0, 0x03, 0xe2, 0x06, 0xe5, 0x03, 0xe2, 0x03, 0xe0, 0x03, 0xda, 0x03, 0xd4, 0x03, 0xcf, 0x03, 0xce, 0x63, 0xd0, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xda, 0x03, 0xe5, 0x06, 0xe6, 0x12, 0xe5, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0xdf, 0x03, 0xd3, 0x03, 0xcb, 0x57, 0xd0, 0x06, 0xcf, 0x03, 0xd4, 0xff, 0xe0, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xb4, 0xe0, 0x03, 0xd0, 0x03, 0xce, 0x03, 0xcf, 0x57, 0xd0, 0x03, 0xcd, 0x03, 0xd3, 0x03, 0xdd, 0x03, 0xe4, 0x06, 0xe6, 0x12, 0xe5, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0xdb, 0x03, 0xd1, 0x06, 0xcf, 0x60, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd3, 0x03, 0xd7, 0x03, 0xda, 0x06, 0xdd, 0x03, 0xda, 0x03, 0xd7, 0x03, 0xd3, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xcf, 0x60, 0xd0, 0x06, 0xcf, 0x03, 0xd1, 0x03, 0xdb, 0x03, 0xe5, 0x06, 0xe6, 0x12, 0xe5, 0x06, 0xe6, 0x03, 0xe4, 0x03, 0xdd, 0x03, 0xd3, 0x03, 0xcd, 0x57, 0xd0, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xd5, 0xff, 0xe0, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xb4, 0xe0, 0x03, 0xd1, 0x06, 0xcf, 0x57, 0xd0, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdc, 0x03, 0xe4, 0x06, 0xe6, 0x12, 0xe5, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0xdc, 0x03, 0xd3, 0x03, 0xd0, 0x03, 0xcf, 0x63, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xcf, 0x12, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xcf, 0x63, 0xd0, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xd3, 0x03, 0xdc, 0x03, 0xe5, 0x06, 0xe6, 0x12, 0xe5, 0x06, 0xe6, 0x03, 0xe4, 0x03, 0xdc, 0x03, 0xd1, 0x03, 0xcd, 0x57, 0xd0, 0x03, 0xcf, 0x03, 0xd1, 0x03, 0xd6, 0xff, 0xe0, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xb4, 0xe0, 0x03, 0xd3, 0x06, 0xcf, 0x57, 0xd0, 0x03, 0xcd, 0x03, 0xd0, 0x03, 0xdb, 0x03, 0xe2, 0x06, 0xe6, 0x12, 0xe5, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0xdd, 0x03, 0xd5, 0x03, 0xd0, 0x03, 0xcf, 0x69, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x0c, 0xcd, 0x03, 0xce, 0x03, 0xcf, 0x69, 0xd0, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xd5, 0x03, 0xdd, 0x03, 0xe5, 0x06, 0xe6, 0x12, 0xe5, 0x06, 0xe6, 0x03, 0xe2, 0x03, 0xdb, 0x03, 0xd0, 0x03, 0xcd, 0x57, 0xd0, 0x03, 0xcf, 0x03, 0xd3, 0x03, 0xd7, 0xff, 0xe0, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xb4, 0xe0, 0x03, 0xd4, 0x5d, 0xd0, 0x03, 0xcd, 0x03, 0xd0, 0x03, 0xda, 0x03, 0xe1, 0x06, 0xe6, 0x12, 0xe5, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0xe0, 0x03, 0xd7, 0x03, 0xd0, 0x03, 0xcf, 0xea, 0xd0, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xd7, 0x03, 0xe0, 0x03, 0xe5, 0x06, 0xe6, 0x12, 0xe5, 0x06, 0xe6, 0x03, 0xe1, 0x03, 0xda, 0x03, 0xd0, 0x03, 0xcd, 0x57, 0xd0, 0x03, 0xcf, 0x03, 0xd4, 0x03, 0xd9, 0xff, 0xe0, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xb4, 0xe0, 0x03, 0xd5, 0x03, 0xd3, 0x06, 0xcf, 0x54, 0xd0, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xd7, 0x03, 0xe0, 0x06, 0xe6, 0x12, 0xe5, 0x09, 0xe6, 0x03, 0xe1, 0x03, 0xd9, 0x03, 0xd0, 0x03, 0xce, 0x03, 0xcf, 0xe4, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xd9, 0x03, 0xe1, 0x09, 0xe6, 0x12, 0xe5, 0x06, 0xe6, 0x03, 0xe0, 0x03, 0xd7, 0x03, 0xd0, 0x03, 0xce, 0x54, 0xd0, 0x06, 0xcf, 0x03, 0xd4, 0x03, 0xda, 0xff, 0xe0, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xb4, 0xe0, 0x03, 0xd6, 0x03, 0xd4, 0x03, 0xd0, 0x03, 0xce, 0x54, 0xd0, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xd6, 0x03, 0xdf, 0x03, 0xe6, 0x03, 0xe7, 0x18, 0xe5, 0x03, 0xe6, 0x03, 0xe4, 0x03, 0xdb, 0x03, 0xd0, 0x03, 0xcd, 0x03, 0xce, 0xe4, 0xd0, 0x03, 0xce, 0x03, 0xcd, 0x03, 0xd0, 0x03, 0xdb, 0x03, 0xe4, 0x03, 0xe6, 0x18, 0xe5, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd6, 0x03, 0xd0, 0x03, 0xce, 0x54, 0xd0, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd5, 0x03, 0xdb, 0xff, 0xe0, 0xae, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0xcf, 0x03, 0x45, 0x03, 0x2c, 0x03, 0x45, 0x03, 0x8c, 0x06, 0xe0, 0x03, 0x7c, 0x03, 0x9c, 0x4e, 0xe0, 0x06, 0xbd, 0x03, 0xe0, 0x03, 0x9c, 0x6c, 0xe0, 0x03, 0x7c, 0x03, 0x9c, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x60, 0xe0, 0x03, 0x9c, 0x03, 0x45, 0x06, 0x2c, 0x03, 0x52, 0x03, 0x9c, 0x03, 0xd9, 0x03, 0xd5, 0x03, 0xd0, 0x03, 0xce, 0x54, 0xd0, 0x06, 0xcf, 0x03, 0xd4, 0x03, 0xdd, 0x03, 0xe5, 0x03, 0xe7, 0x18, 0xe5, 0x03, 0xe6, 0x03, 0xe5, 0x03, 0xdd, 0x03, 0xd3, 0x06, 0xce, 0xe4, 0xd0, 0x06, 0xce, 0x03, 0xd3, 0x03, 0xdd, 0x03, 0xe5, 0x03, 0xe6, 0x0f, 0xe5, 0x03, 0x9f, 0x03, 0x80, 0x03, 0xe5, 0x03, 0xe7, 0x03, 0xe5, 0x03, 0xdd, 0x03, 0x76, 0x03, 0x91, 0x03, 0xcf, 0x18, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x36, 0xd0, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xd7, 0x03, 0xdc, 0x0c, 0xe0, 0x03, 0xcf, 0x03, 0x45, 0x03, 0x2c, 0x03, 0x45, 0x03, 0x8c, 0x06, 0xe0, 0x03, 0x7c, 0x03, 0x9c, 0x36, 0xe0, 0x03, 00, 0x03, 0x9c, 0x63, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0xbd, 0x03, 0x60, 0xd8, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x20, 0x03, 0x38, 0x03, 0x9c, 0x03, 0x7c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x7c, 0x4e, 0xe0, 0x06, 0x7c, 0x03, 0xe0, 0x03, 0x2c, 0x6c, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x5d, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0x60, 0x03, 0x9c, 0x03, 0x8c, 0x03, 0x52, 0x03, 0x45, 0x03, 0xda, 0x03, 0xd6, 0x03, 0xd1, 0x03, 0xce, 0x54, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xd1, 0x03, 0xdb, 0x03, 0xe4, 0x03, 0xe7, 0x03, 0xb0, 0x03, 0xc2, 0x15, 0xe5, 0x03, 0xe6, 0x03, 0xe1, 0x03, 0xd6, 0x03, 0xd0, 0x06, 0xcf, 0x78, 0xd0, 0x03, 0xbf, 0x03, 0x92, 0x30, 0xd0, 0x03, 0xa0, 0x03, 0xb0, 0x2a, 0xd0, 0x06, 0xcf, 0x03, 0xd0, 0x03, 0xd6, 0x03, 0xe1, 0x03, 0xe6, 0x12, 0xe5, 0x03, 0x62, 0x03, 0x2d, 0x03, 0xe5, 0x03, 0xe7, 0x03, 0xe4, 0x03, 0xdb, 0x03, 0x2a, 0x03, 0x59, 0x03, 0xcf, 0x18, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x92, 0x03, 0xbf, 0x2a, 0xd0, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xd9, 0x03, 0xdd, 0x0c, 0xe0, 0x03, 0x20, 0x03, 0x38, 0x03, 0x9c, 0x03, 0x7c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x7c, 0x36, 0xe0, 0x03, 00, 0x03, 0x9c, 0x63, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x2c, 0xd8, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4b, 0xe0, 0x03, 0x9c, 0x03, 00, 0x21, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x1e, 0xe0, 0x03, 0x9c, 0x03, 0xbd, 0x06, 0xe0, 0x06, 0xad, 0x24, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xad, 0x0c, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xbd, 0x0c, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x12, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x15, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x0f, 0xe0, 0x03, 0xcf, 0x03, 0xad, 0x09, 0xe0, 0x06, 0xad, 0x12, 0xe0, 0x06, 0xad, 0x15, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xad, 0x0f, 0xe0, 0x03, 0xdb, 0x03, 0xd7, 0x03, 0xd1, 0x03, 0xad, 0x03, 0x92, 0x03, 0xb0, 0x12, 0xd0, 0x03, 0xb0, 0x03, 0x92, 0x06, 0xd0, 0x03, 0xbf, 0x03, 0x92, 0x03, 0xbf, 0x0f, 0xd0, 0x03, 0xbf, 0x03, 0x92, 0x03, 0xb0, 0x12, 0xd0, 0x03, 0xcd, 0x03, 0xd0, 0x03, 0xd9, 0x03, 0xe2, 0x03, 0xe7, 0x03, 0x2d, 0x03, 0x62, 0x0c, 0xe5, 0x03, 0xd3, 0x03, 0x9f, 0x03, 0xd3, 0x03, 0xe6, 0x03, 0xe4, 0x03, 0xda, 0x03, 0xd3, 0x03, 0xce, 0x03, 0xcf, 0x03, 0x92, 0x18, 0xd0, 0x03, 0xb0, 0x03, 0x92, 0x0f, 0xd0, 0x03, 0xb0, 0x03, 0x92, 0x33, 0xd0, 0x03, 0xb0, 0x03, 0x92, 0x03, 0xb0, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x0f, 0xd0, 0x06, 0x92, 0x03, 0xbf, 0x0f, 0xd0, 0x06, 0xb0, 0x03, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x0c, 0xd0, 0x03, 0xbf, 0x03, 0x92, 0x03, 0xbf, 0x12, 0xd0, 0x03, 0x92, 0x03, 0xaf, 0x03, 0xce, 0x03, 0xd3, 0x03, 0xda, 0x03, 0xe4, 0x03, 0xe6, 0x12, 0xe5, 0x03, 0x62, 0x03, 0x2d, 0x03, 0xe5, 0x03, 0xe7, 0x03, 0xe2, 0x03, 0xd9, 0x03, 0x29, 0x03, 0x58, 0x09, 0xd0, 0x03, 0xb0, 0x03, 0x92, 0x03, 0xa0, 0x09, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 00, 0x03, 0x92, 0x0c, 0xd0, 0x03, 0xbf, 0x03, 0x92, 0x03, 0xbf, 0x12, 0xd0, 0x03, 0x92, 0x03, 0xad, 0x03, 0xd1, 0x03, 0xda, 0x03, 0xdd, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x21, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x1b, 0xe0, 0x06, 0xad, 0x03, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x06, 0x9c, 0x03, 0xcf, 0x48, 0xe0, 0x06, 0xad, 0x03, 0xe0, 0x03, 00, 0x03, 0x9c, 0x15, 0xe0, 0x06, 0xad, 0xc6, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4b, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0x8c, 0x0f, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x03, 0x20, 0x03, 0x2c, 0x03, 00, 0x03, 0x8c, 0x03, 0x45, 0x03, 0x20, 0x03, 0x0c, 0x03, 0x52, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x8c, 0x03, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x16, 0x09, 0xe0, 0x03, 0x45, 0x03, 0x16, 0x06, 0x20, 0x03, 0xcf, 0x06, 0xe0, 0x03, 00, 0x03, 0x6e, 0x03, 0x16, 0x03, 0x20, 0x03, 0x0c, 0x03, 0xbd, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x6e, 0x03, 0x16, 0x03, 0x20, 0x03, 0x0c, 0x03, 0xbd, 0x06, 0xe0, 0x03, 00, 0x03, 0x60, 0x03, 0x20, 0x03, 0x52, 0x03, 0xe0, 0x03, 0xcf, 0x06, 0x20, 0x03, 0x16, 0x03, 0x45, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0x45, 0x03, 0x20, 0x03, 0x0c, 0x03, 0x52, 0x12, 0xe0, 0x03, 0x52, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0xdd, 0x03, 0xd9, 0x03, 0x4d, 0x03, 0x0c, 0x03, 0x29, 0x03, 0x0c, 0x03, 0x4c, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0x74, 0x06, 0x15, 0x03, 0x1f, 0x03, 0xa0, 0x03, 0x15, 0x03, 0x1f, 0x03, 0x0c, 0x03, 0xb0, 0x06, 0xd0, 0x03, 00, 0x03, 0x67, 0x03, 0x15, 0x03, 0x29, 0x03, 00, 0x03, 0x74, 0x06, 0xd0, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0xcd, 0x03, 0x29, 0x03, 0x5c, 0x03, 0xe0, 0x03, 0x63, 0x09, 00, 0x03, 0x9f, 0x03, 0xe5, 0x03, 0x80, 0x03, 0x0d, 0x03, 0x2d, 0x03, 0x0d, 0x03, 0xb2, 0x03, 0xe4, 0x03, 0xdd, 0x03, 0x2a, 0x03, 0x4b, 0x03, 0x1e, 0x03, 0x29, 0x0f, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0x74, 0x06, 0x15, 0x03, 0x1f, 0x09, 0xd0, 0x03, 0x41, 0x03, 0x15, 0x06, 0x1f, 0x03, 0xbf, 0x06, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x12, 0xd0, 0x03, 0x4c, 0x03, 0x0c, 0x03, 0x29, 0x03, 0x15, 0x06, 0xd0, 0x09, 00, 0x03, 0x29, 0x03, 0xd0, 0x03, 0xa0, 0x03, 00, 0x03, 0x29, 0x03, 0x1f, 0x03, 0x0c, 0x03, 0xb0, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0x67, 0x03, 0x1f, 0x03, 0x74, 0x03, 0x5a, 0x09, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x74, 0x03, 0x0c, 0x03, 0x29, 0x03, 0x0c, 0x03, 0xa0, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x4c, 0x03, 0x1f, 0x03, 0x29, 0x03, 00, 0x03, 0x82, 0x03, 0xd5, 0x03, 0xdd, 0x03, 0xe4, 0x03, 0xe6, 0x12, 0xe5, 0x03, 0x62, 0x03, 0x2d, 0x03, 0xe5, 0x03, 0xe6, 0x03, 0xe0, 0x03, 0xd5, 0x03, 0x29, 0x03, 0x58, 0x06, 0xd0, 0x03, 0x34, 0x03, 0x15, 0x03, 0x29, 0x03, 0x0c, 0x03, 0x4c, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0x29, 0x09, 00, 0x06, 0xd0, 0x03, 0x74, 0x03, 0x0c, 0x03, 0x29, 0x03, 0x0c, 0x03, 0xa0, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x4c, 0x03, 0x1f, 0x03, 0x29, 0x03, 00, 0x03, 0x84, 0x03, 0xdb, 0x03, 0xdf, 0x09, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0x8c, 0x0f, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x12, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 0x16, 0x03, 0x20, 0x03, 0x2c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x0c, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x60, 0x0f, 00, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 0x16, 0x03, 0x20, 0x03, 0x2c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0x20, 0x03, 0x16, 0x03, 0x45, 0xc3, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x7c, 0x03, 00, 0x03, 0x45, 0x03, 0xcf, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x38, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x52, 0x03, 00, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x8c, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x0f, 0xe0, 0x03, 00, 0x03, 0x8c, 0x0c, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x6e, 0x06, 0xe0, 0x03, 00, 0x03, 0x20, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x20, 0x03, 0x60, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x20, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x20, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x2c, 0x03, 0xcf, 0x06, 0xe0, 0x06, 0x45, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x60, 0x03, 00, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x8c, 0x03, 00, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x12, 0xe0, 0x03, 0xdd, 0x03, 0x7a, 0x03, 0x0c, 0x03, 0xbd, 0x03, 0xd0, 0x03, 0xbf, 0x03, 0x0c, 0x03, 0x74, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0x41, 0x03, 0xd0, 0x03, 0xbf, 0x03, 00, 0x03, 0x1f, 0x03, 0xbf, 0x03, 0xd0, 0x03, 0x1f, 0x03, 0x5a, 0x06, 0xd0, 0x03, 00, 0x03, 0x29, 0x03, 0xbf, 0x03, 0xd0, 0x03, 0x67, 0x03, 0x0c, 0x06, 0xd0, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0xce, 0x03, 0x29, 0x03, 0x5b, 0x03, 0xdc, 0x03, 0xe5, 0x03, 0x2d, 0x03, 0x62, 0x06, 0xe5, 0x03, 0xc2, 0x03, 00, 0x03, 0xc2, 0x03, 0xe5, 0x03, 0x62, 0x03, 0x39, 0x03, 0xe5, 0x03, 0xe1, 0x03, 0x2a, 0x03, 0x0c, 0x03, 0xad, 0x12, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0x41, 0x03, 0xd0, 0x03, 0xbf, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x74, 0x03, 0x15, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x67, 0x06, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x12, 0xd0, 0x03, 00, 0x03, 0x83, 0x0c, 0xd0, 0x03, 0x92, 0x03, 00, 0x09, 0xd0, 0x03, 0xbf, 0x09, 0xd0, 0x03, 0x1f, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0x4c, 0x09, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0xb0, 0x03, 00, 0x03, 0xb0, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x34, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x0c, 0x03, 0xa0, 0x03, 0xd0, 0x03, 0x4b, 0x03, 0x29, 0x03, 0xd7, 0x03, 0xe1, 0x03, 0xe5, 0x03, 0xe6, 0x12, 0xe5, 0x03, 0x62, 0x03, 0x16, 0x03, 0x63, 0x03, 0x62, 0x03, 0x5f, 0x03, 0x5b, 0x03, 0x15, 0x03, 0x59, 0x06, 0xd0, 0x03, 0xbf, 0x06, 0xd0, 0x03, 0x83, 0x03, 00, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0xb0, 0x03, 00, 0x03, 0xb0, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x34, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x0c, 0x03, 0xa0, 0x03, 0xd0, 0x03, 0x4b, 0x03, 0x2a, 0x03, 0xdb, 0x0f, 0xe0, 0x03, 0x7c, 0x03, 00, 0x03, 0x45, 0x03, 0xcf, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x38, 0x12, 0xe0, 0x03, 0x52, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0xcf, 0x09, 0xe0, 0x03, 0x20, 0x03, 0x60, 0x0c, 0xe0, 0x03, 0xcf, 0x03, 0x16, 0x03, 0x45, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0x52, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x06, 0x45, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0xad, 0xc0, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x51, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x6e, 0x03, 0x20, 0x06, 0x9c, 0x03, 0x6e, 0x03, 00, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x45, 0x03, 0x0c, 0x03, 0x9c, 0x0c, 0xe0, 0x03, 0x16, 0x03, 0x20, 0x03, 0xbd, 0x09, 0xe0, 0x03, 0x38, 0x03, 0x45, 0x06, 0x9c, 0x03, 0x45, 0x03, 0x2c, 0x06, 0xe0, 0x03, 00, 0x03, 0x8c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x8c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 0x0c, 0x03, 0x6e, 0x06, 0x9c, 0x03, 0x20, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x20, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x12, 0xe0, 0x03, 0xdf, 0x03, 0x37, 0x03, 0x4d, 0x03, 0xcb, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0x4c, 0x03, 0x34, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x09, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 00, 0x03, 0x92, 0x09, 0xd0, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0xcf, 0x03, 0x29, 0x03, 0x5b, 0x03, 0xdb, 0x03, 0xe4, 0x03, 0x2d, 0x03, 0x63, 0x06, 0xe5, 0x03, 0x70, 0x03, 0x21, 0x06, 0x9f, 0x03, 0x70, 0x03, 00, 0x03, 0xe5, 0x03, 0xe4, 0x03, 0x2b, 0x03, 0x5a, 0x03, 0xce, 0x03, 0xcf, 0x0f, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0xbf, 0x06, 0xd0, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x34, 0x03, 0x41, 0x06, 0x92, 0x03, 0x41, 0x03, 0x29, 0x06, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x12, 0xd0, 0x03, 0x15, 0x03, 0x1f, 0x03, 0xb0, 0x09, 0xd0, 0x03, 0x92, 0x03, 00, 0x0f, 0xd0, 0x03, 0xb0, 0x03, 0x92, 0x03, 0x1f, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x0c, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x67, 0x03, 0x1f, 0x06, 0x92, 0x03, 0x67, 0x03, 00, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x4c, 0x03, 0xd0, 0x03, 0xcf, 0x03, 0x59, 0x03, 0x2a, 0x03, 0xdb, 0x03, 0xe4, 0x18, 0xe5, 0x03, 0x62, 0x03, 0x16, 0x03, 0x63, 0x03, 0x62, 0x03, 0x5e, 0x03, 0x5b, 0x03, 0x15, 0x03, 0x59, 0x0c, 0xd0, 0x03, 0x92, 0x03, 0x67, 0x03, 00, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x67, 0x03, 0x1f, 0x06, 0x92, 0x03, 0x67, 0x03, 00, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x4c, 0x03, 0xd0, 0x03, 0xcf, 0x03, 0x58, 0x03, 0x2a, 0x03, 0xdc, 0x12, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x6e, 0x03, 0x20, 0x06, 0x9c, 0x03, 0x6e, 0x03, 00, 0x12, 0xe0, 0x03, 0x16, 0x03, 0x7c, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0x20, 0x03, 0x60, 0x09, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0x16, 0x03, 0x7c, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x0c, 0x03, 0x6e, 0x06, 0x9c, 0x03, 0x20, 0x03, 0x60, 0xc0, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x57, 0xe0, 0x03, 0x60, 0x03, 0x0c, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x0c, 0x0c, 0x2c, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x52, 0x03, 00, 0x03, 0x20, 0x03, 0xbd, 0x06, 0xe0, 0x03, 0xbd, 0x03, 0x2c, 0x03, 00, 0x03, 0x38, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x16, 0x09, 0x2c, 0x03, 0x52, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 00, 0x03, 0x20, 0x09, 0x2c, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x12, 0xe0, 0x03, 0x38, 0x03, 0x45, 0x15, 0xe0, 0x03, 0x2b, 0x03, 0x5c, 0x03, 0xcb, 0x03, 0xce, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x09, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 00, 0x03, 0x92, 0x09, 0xd0, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0xcf, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xd7, 0x03, 0xe1, 0x03, 0x2d, 0x03, 0x63, 0x06, 0xe5, 0x03, 0x62, 0x03, 0x0d, 0x0c, 0x2d, 0x06, 0xe6, 0x03, 0x2c, 0x03, 0x5c, 0x03, 0xcf, 0x03, 0xcd, 0x03, 0xcf, 0x0c, 0xd0, 0x03, 0x92, 0x03, 00, 0x09, 0xd0, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x29, 0x03, 0x15, 0x09, 0x29, 0x03, 0x4c, 0x06, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x12, 0xd0, 0x03, 0xb0, 0x03, 0x29, 0x03, 00, 0x03, 0x34, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x09, 0xd0, 0x03, 0xbf, 0x03, 0x29, 0x03, 0x0c, 0x03, 0x29, 0x03, 0x0c, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x0c, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x0c, 0x0c, 0x29, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xcf, 0x03, 0xcd, 0x03, 0x59, 0x03, 0x2a, 0x03, 0xe0, 0x06, 0xe6, 0x15, 0xe5, 0x03, 0x62, 0x03, 0x2d, 0x03, 0xe7, 0x03, 0xe1, 0x03, 0xd7, 0x03, 0xd0, 0x03, 0x29, 0x03, 0x59, 0x06, 0xd0, 0x03, 0x74, 0x03, 0x0c, 0x06, 0x1f, 0x03, 00, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x0c, 0x0c, 0x29, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0xce, 0x03, 0x58, 0x03, 0x2a, 0x03, 0xdd, 0x18, 0xe0, 0x03, 0x60, 0x03, 0x0c, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x0c, 0x0c, 0x2c, 0x12, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x45, 0x03, 0x20, 0x03, 0xcf, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x12, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 00, 0x03, 0x20, 0x09, 0x2c, 0x03, 0x7c, 0xc0, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x5a, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x1e, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x8c, 0x03, 00, 0x0c, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 0x38, 0x0c, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x6e, 0x03, 0xe0, 0x06, 0x45, 0x12, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 0x16, 0x03, 0x7c, 0x0f, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x12, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0xcf, 0x12, 0xe0, 0x03, 0x38, 0x03, 0x4f, 0x06, 0xce, 0x03, 0xd0, 0x03, 0x4c, 0x03, 0x34, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x09, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0xb0, 0x03, 00, 0x03, 0xb0, 0x03, 0xd0, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0xcf, 0x03, 0x1f, 0x03, 0x59, 0x03, 0xd4, 0x03, 0xdf, 0x03, 0x2d, 0x03, 0x63, 0x06, 0xe5, 0x03, 0x80, 0x03, 0x16, 0x0c, 0xe5, 0x06, 0xe6, 0x03, 0x2c, 0x03, 0x5e, 0x03, 0xd1, 0x03, 0xcd, 0x03, 0xce, 0x0c, 0xd0, 0x03, 0x92, 0x03, 00, 0x09, 0xd0, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x06, 0x41, 0x12, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x1f, 0x03, 0x5a, 0x18, 0xd0, 0x03, 0xa0, 0x03, 0x0c, 0x03, 0x67, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x09, 0xd0, 0x03, 0x41, 0x03, 0x29, 0x03, 0xbf, 0x03, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x0c, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x74, 0x03, 0x15, 0x12, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xce, 0x03, 0xcd, 0x03, 0x5a, 0x03, 0x2a, 0x03, 0xe4, 0x06, 0xe6, 0x15, 0xe5, 0x03, 0x62, 0x03, 0x2d, 0x03, 0xe6, 0x03, 0xdf, 0x03, 0xd4, 0x03, 0xcf, 0x03, 0x29, 0x03, 0x59, 0x03, 0xd0, 0x03, 0xb0, 0x03, 00, 0x03, 0x83, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x74, 0x03, 0x15, 0x12, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0xce, 0x03, 0x59, 0x03, 0x2a, 0x03, 0xdf, 0x1b, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x1e, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x45, 0x03, 0x2c, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x0c, 0x03, 0xad, 0x0c, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x2c, 0x12, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x16, 0x03, 0x7c, 0xcc, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4b, 0xe0, 0x06, 0xbd, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0x6e, 0x06, 0xe0, 0x03, 0xcf, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x20, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 00, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x38, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x20, 0x03, 0x6e, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xad, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x12, 0xe0, 0x03, 0xcf, 0x03, 0x16, 0x03, 0x45, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0xc1, 0x03, 0xcf, 0x03, 0xbe, 0x03, 0x0c, 0x03, 0x74, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x09, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 00, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x15, 0x06, 0xd0, 0x03, 00, 0x03, 0x83, 0x03, 0xd0, 0x03, 0x74, 0x03, 00, 0x03, 0x58, 0x03, 0xd0, 0x03, 0xda, 0x03, 0x2c, 0x03, 0x46, 0x06, 0xe5, 0x03, 0xd3, 0x03, 0x0d, 0x03, 0x70, 0x06, 0xe5, 0x03, 0xd3, 0x06, 0xe6, 0x03, 0x2d, 0x03, 0x5f, 0x03, 0xd5, 0x06, 0xce, 0x0c, 0xd0, 0x03, 0x92, 0x03, 00, 0x09, 0xd0, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0xa0, 0x06, 0xd0, 0x03, 0xbf, 0x06, 0xd0, 0x03, 00, 0x03, 0x83, 0x03, 0xd0, 0x03, 0x74, 0x03, 00, 0x03, 0x5a, 0x12, 0xd0, 0x03, 0xbf, 0x06, 0xd0, 0x03, 0x1f, 0x03, 0x67, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0xb0, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x4c, 0x03, 0xd0, 0x03, 0xbf, 0x03, 0x1f, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x0c, 0xd0, 0x03, 0x29, 0x03, 0x41, 0x06, 0xd0, 0x03, 0xbf, 0x03, 0x0c, 0x03, 0x67, 0x06, 0xd0, 0x03, 0xbf, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xce, 0x03, 0x5c, 0x03, 0x2b, 0x06, 0xe6, 0x03, 0x81, 0x03, 0x80, 0x12, 0xe5, 0x03, 0x62, 0x03, 0x2d, 0x03, 0xe4, 0x03, 0xda, 0x03, 0xd0, 0x03, 0xcd, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0xbf, 0x03, 0xd0, 0x03, 0x74, 0x03, 00, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 00, 0x03, 0x74, 0x06, 0xd0, 0x03, 0xbf, 0x03, 0x0c, 0x03, 0x67, 0x06, 0xd0, 0x03, 0xbf, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xcf, 0x03, 0x5a, 0x03, 0x2a, 0x03, 0xdf, 0x0c, 0xe0, 0x06, 0xbd, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0x6e, 0x06, 0xe0, 0x03, 0xcf, 0x12, 0xe0, 0x06, 0x38, 0x06, 0xe0, 0x03, 0x52, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x7c, 0x03, 00, 0x03, 0xad, 0x0f, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x2c, 0x12, 0xe0, 0x06, 0x38, 0x06, 0xe0, 0x03, 0x52, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0xc0, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4b, 0xe0, 0x03, 0xbd, 0x06, 0x16, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x2c, 0x03, 0x0c, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0xbd, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x16, 0x03, 0x6e, 0x03, 00, 0x06, 0xe0, 0x03, 0x38, 0x06, 0x20, 0x03, 0x0c, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x20, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x6e, 0x03, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x38, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x0c, 0xe0, 0x03, 0x38, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x6e, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x15, 0xe0, 0x03, 0xbd, 0x03, 0x2c, 0x03, 00, 0x06, 0x2c, 0x03, 00, 0x03, 0x45, 0x03, 0xe0, 0x03, 0xdf, 0x03, 0x50, 0x03, 0x0c, 0x03, 0x29, 0x03, 0x0c, 0x03, 0x4c, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x09, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 00, 0x03, 0x29, 0x03, 0x15, 0x03, 0x1f, 0x03, 0x0c, 0x03, 0xa0, 0x06, 0xd0, 0x03, 0x4c, 0x03, 0x0c, 0x03, 0x1f, 0x03, 0x41, 0x03, 0x29, 0x03, 0x58, 0x03, 0xcf, 0x03, 0xd6, 0x03, 0x8e, 0x03, 00, 0x03, 0x2d, 0x03, 0xb0, 0x03, 0xe5, 0x03, 0x9f, 0x03, 0x0d, 0x03, 0x21, 0x03, 0x2d, 0x03, 0x0d, 0x03, 0xe5, 0x03, 0xe6, 0x03, 0x2d, 0x03, 0x61, 0x03, 0xd9, 0x03, 0xd1, 0x03, 0xcd, 0x03, 0xce, 0x09, 0xd0, 0x03, 0x92, 0x03, 00, 0x09, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x67, 0x03, 00, 0x03, 0x29, 0x03, 0x1f, 0x03, 0x34, 0x06, 0xd0, 0x03, 0x4c, 0x03, 0x0c, 0x03, 0x1f, 0x03, 0x41, 0x03, 0x29, 0x03, 0x5a, 0x12, 0xd0, 0x03, 0x0c, 0x03, 0x29, 0x03, 0x15, 0x03, 0x1f, 0x03, 0xbf, 0x06, 0xd0, 0x03, 0x1f, 0x03, 0x15, 0x03, 0x4c, 0x03, 0xd0, 0x03, 0x83, 0x03, 00, 0x03, 0x29, 0x03, 0x1f, 0x03, 0x41, 0x03, 0x0c, 0x03, 0x74, 0x03, 0x92, 0x03, 00, 0x0c, 0xd0, 0x03, 0x83, 0x03, 00, 0x03, 0x29, 0x03, 0xa0, 0x03, 0xd0, 0x03, 0x92, 0x03, 0x0c, 0x03, 0x1f, 0x03, 0x29, 0x03, 0x0c, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x59, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0x5d, 0x03, 0x2c, 0x06, 0xe6, 0x06, 0x2d, 0x12, 0xe5, 0x03, 0x63, 0x03, 0x2d, 0x03, 0xe1, 0x03, 0xd6, 0x03, 0xcf, 0x03, 0xcd, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x1f, 0x03, 0x15, 0x03, 0x1f, 0x03, 0x4c, 0x03, 0x0c, 0x03, 0x1f, 0x03, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x4c, 0x03, 0x0c, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x92, 0x03, 0x0c, 0x03, 0x1f, 0x03, 0x29, 0x03, 0x0c, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xcf, 0x03, 0x5b, 0x03, 0x2a, 0x03, 0xdf, 0x0c, 0xe0, 0x03, 0xbd, 0x06, 0x16, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x2c, 0x03, 0x0c, 0x12, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x16, 0x03, 0x7c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x8c, 0x03, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x45, 0x03, 0x0c, 0x03, 0x7c, 0x03, 0x2c, 0x0f, 00, 0x06, 0xe0, 0x03, 0x8c, 0x03, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x52, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x16, 0x03, 0x7c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x38, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x6e, 0xc0, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x51, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xcf, 0x1b, 0xe0, 0x03, 0x9c, 0x03, 0xad, 0x3c, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x0f, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xcf, 0x0c, 0xe0, 0x06, 0x9c, 0x0f, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xbd, 0x66, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xcf, 0x33, 0xe0, 0x03, 0xbd, 0x06, 0x9c, 0x03, 0xcf, 0x09, 0xe0, 0x03, 0xdc, 0x03, 0xb5, 0x03, 0x91, 0x03, 0xae, 0x30, 0xd0, 0x03, 00, 0x03, 0x92, 0x03, 0xb0, 0x03, 0x92, 0x0f, 0xd0, 0x06, 0xa0, 0x06, 0xd0, 0x06, 0xce, 0x03, 0xd4, 0x03, 0xdc, 0x03, 0xc1, 0x03, 0xa0, 0x0c, 0xe5, 0x03, 0x9f, 0x03, 0xb0, 0x09, 0xe5, 0x03, 0xe6, 0x03, 0xe5, 0x03, 0xdf, 0x03, 0xd6, 0x03, 0xcf, 0x03, 0xcd, 0x03, 0xcf, 0x24, 0xd0, 0x03, 0xbf, 0x03, 0x92, 0x03, 0xb0, 0x0c, 0xd0, 0x06, 0xa0, 0x1e, 0xd0, 0x06, 0x92, 0x0f, 0xd0, 0x03, 0x92, 0x03, 0xb0, 0x06, 0xd0, 0x03, 0xb0, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x92, 0x03, 0xbf, 0x15, 0xd0, 0x03, 0xb0, 0x03, 0x92, 0x0c, 0xd0, 0x03, 0x92, 0x03, 0xa0, 0x09, 0xd0, 0x03, 0xcf, 0x03, 0xcd, 0x03, 0xcf, 0x03, 0xd6, 0x03, 0xdf, 0x03, 0xe5, 0x03, 0xe6, 0x1b, 0xe5, 0x03, 0xe6, 0x03, 0xe4, 0x03, 0xdc, 0x03, 0xd4, 0x06, 0xce, 0x0f, 0xd0, 0x03, 0x92, 0x03, 0xb0, 0x03, 0xd0, 0x03, 0xb0, 0x03, 0xa0, 0x12, 0xd0, 0x06, 0xa0, 0x0c, 0xd0, 0x03, 0x92, 0x03, 0xa0, 0x0f, 0xd0, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd6, 0x03, 0xdc, 0x15, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xcf, 0x1b, 0xe0, 0x03, 0x9c, 0x03, 0xad, 0x18, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xbd, 0x0f, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 0xcf, 0x1b, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x1e, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xbd, 0x1e, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xcf, 0xc3, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xba, 0xe0, 0x03, 0xdd, 0x03, 0xd7, 0x03, 0xcf, 0x03, 0xcd, 0x30, 0xd0, 0x03, 00, 0x03, 0x92, 0x21, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xd7, 0x03, 0xe1, 0x1e, 0xe5, 0x06, 0xe6, 0x03, 0xe4, 0x03, 0xdc, 0x03, 0xd3, 0x03, 0xce, 0x06, 0xcf, 0xc0, 0xd0, 0x06, 0xcf, 0x03, 0xce, 0x03, 0xd3, 0x03, 0xdc, 0x03, 0xe4, 0x06, 0xe6, 0x1e, 0xe5, 0x03, 0xe1, 0x03, 0xd7, 0x03, 0xd0, 0x03, 0xce, 0x03, 0xcf, 0x57, 0xd0, 0x03, 0xcd, 0x03, 0xcf, 0x03, 0xd7, 0x03, 0xdd, 0xff, 0xe0, 0xb4, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xba, 0xe0, 0x03, 0xdf, 0x03, 0xda, 0x03, 0xcf, 0x03, 0xcd, 0x30, 0xd0, 0x03, 0x5a, 0x03, 0xb0, 0x21, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd4, 0x03, 0xdd, 0x03, 0xe4, 0x06, 0xe6, 0x18, 0xe5, 0x03, 0xe6, 0x03, 0xe5, 0x03, 0xe1, 0x03, 0xd9, 0x03, 0xd0, 0x06, 0xce, 0x03, 0xcf, 0xba, 0xd0, 0x03, 0xcf, 0x06, 0xce, 0x03, 0xd0, 0x03, 0xd9, 0x03, 0xe1, 0x03, 0xe5, 0x03, 0xe6, 0x18, 0xe5, 0x06, 0xe6, 0x03, 0xe4, 0x03, 0xdd, 0x03, 0xd4, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xcf, 0x57, 0xd0, 0x03, 0xcd, 0x03, 0xcf, 0x03, 0xda, 0x03, 0xdf, 0xff, 0xe0, 0xb4, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xbd, 0xe0, 0x03, 0xdc, 0x03, 0xd1, 0x03, 0xcd, 0x03, 0xcf, 0x57, 0xd0, 0x06, 0xce, 0x03, 0xd0, 0x03, 0xda, 0x03, 0xe1, 0x06, 0xe6, 0x18, 0xe5, 0x06, 0xe6, 0x03, 0xe4, 0x03, 0xdd, 0x03, 0xd5, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xcf, 0xba, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd5, 0x03, 0xdd, 0x03, 0xe4, 0x06, 0xe6, 0x18, 0xe5, 0x06, 0xe6, 0x03, 0xe1, 0x03, 0xda, 0x03, 0xd0, 0x06, 0xce, 0x57, 0xd0, 0x03, 0xcf, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdc, 0xff, 0xe0, 0xb7, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xbd, 0xe0, 0x03, 0xdd, 0x03, 0xd5, 0x03, 0xcf, 0x03, 0xce, 0x57, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd4, 0x03, 0xdd, 0x03, 0xe5, 0x03, 0xe6, 0x18, 0xe5, 0x09, 0xe6, 0x03, 0xe2, 0x03, 0xdb, 0x03, 0xd4, 0x06, 0xce, 0x03, 0xcf, 0xb4, 0xd0, 0x03, 0xcf, 0x06, 0xce, 0x03, 0xd4, 0x03, 0xdb, 0x03, 0xe2, 0x09, 0xe6, 0x18, 0xe5, 0x03, 0xe6, 0x03, 0xe5, 0x03, 0xdd, 0x03, 0xd4, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xcf, 0x57, 0xd0, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd5, 0x03, 0xdd, 0xff, 0xe0, 0xb7, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xbd, 0xe0, 0x03, 0xdd, 0x03, 0xd7, 0x03, 0xd0, 0x03, 0xce, 0x03, 0xcf, 0x54, 0xd0, 0x09, 0xcf, 0x03, 0xd0, 0x03, 0xd9, 0x03, 0xe1, 0x03, 0xe5, 0x06, 0xe6, 0x18, 0xe5, 0x03, 0xe6, 0x03, 0xe5, 0x03, 0xe0, 0x03, 0xda, 0x03, 0xd0, 0x03, 0xcd, 0x03, 0xce, 0x03, 0xcf, 0xae, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xcd, 0x03, 0xd0, 0x03, 0xda, 0x03, 0xe0, 0x03, 0xe5, 0x03, 0xe6, 0x18, 0xe5, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0xe1, 0x03, 0xd9, 0x03, 0xd0, 0x09, 0xcf, 0x54, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xd7, 0x03, 0xdd, 0xff, 0xe0, 0xb7, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x7c, 0x0c, 0x60, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x9c, 0x45, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x27, 0xe0, 0x03, 0x9c, 0x03, 00, 0x93, 0xe0, 0x03, 0x9c, 0x03, 0x7c, 0x1e, 0xe0, 0x03, 0x7c, 0x03, 0x9c, 0x1e, 0xe0, 0x03, 0xdf, 0x03, 0xda, 0x03, 0xd3, 0x03, 0xcd, 0x03, 0xcf, 0x15, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x03, 0x34, 0x03, 0x67, 0x1b, 0xd0, 0x03, 0x92, 0x03, 00, 0x18, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xd4, 0x03, 0xdd, 0x03, 0xe4, 0x06, 0xe6, 0x18, 0xe5, 0x06, 0xe6, 0x03, 0xe4, 0x03, 0xe0, 0x03, 00, 0x03, 0x92, 0x03, 0xcd, 0x03, 0xce, 0x03, 0xcf, 0x72, 0xd0, 0x03, 00, 0x03, 0x92, 0x18, 0xd0, 0x03, 0x92, 0x03, 0xd0, 0x06, 0xb0, 0x0c, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xcd, 0x03, 0xd0, 0x03, 0xd7, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe6, 0x18, 0xe5, 0x06, 0xe6, 0x03, 0xe4, 0x03, 0xdd, 0x03, 0xd4, 0x03, 0xce, 0x03, 0xcf, 0x1e, 0xd0, 0x03, 0x92, 0x03, 00, 0x36, 0xd0, 0x03, 0xcf, 0x03, 0xcd, 0x03, 0xd3, 0x03, 0xda, 0x03, 0xdf, 0x03, 0x60, 0x03, 0x2c, 0x18, 0xe0, 0x06, 0xbd, 0x03, 0xe0, 0x03, 0x9c, 0x1e, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x4b, 0xe0, 0x03, 0xcf, 0x03, 0x45, 0x03, 0x2c, 0x03, 0x45, 0x03, 0x8c, 0x06, 0xe0, 0x03, 0x7c, 0x03, 0x9c, 0x36, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 0x7c, 0xbd, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x06, 0x2c, 0x09, 0x60, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x52, 0x03, 0x7c, 0x45, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x27, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0xbd, 0x03, 0xad, 0x09, 0xe0, 0x03, 0xad, 0x03, 0xbd, 0x33, 0xe0, 0x03, 0x9c, 0x03, 0xcf, 0x3f, 0xe0, 0x03, 0x7c, 0x03, 0x52, 0x1e, 0xe0, 0x03, 0x52, 0x03, 0x7c, 0x21, 0xe0, 0x03, 0xdd, 0x03, 0xd5, 0x03, 0xcd, 0x03, 0xcf, 0x12, 0xd0, 0x03, 0x4c, 0x03, 0x1f, 0x06, 0x83, 0x03, 0x41, 0x1b, 0xd0, 0x03, 0x92, 0x03, 00, 0x1b, 0xd0, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xd9, 0x03, 0xe0, 0x06, 0xe6, 0x18, 0xe5, 0x09, 0xe6, 0x03, 0xe5, 0x03, 00, 0x03, 0x95, 0x03, 0xcf, 0x06, 0xcd, 0x03, 0xcf, 0x6f, 0xd0, 0x03, 00, 0x03, 0x92, 0x18, 0xd0, 0x03, 0x29, 0x03, 0xd0, 0x06, 0x74, 0x09, 0xd0, 0x03, 0xcf, 0x06, 0xcd, 0x03, 0xcf, 0x03, 0xd6, 0x03, 0xe0, 0x03, 0x62, 0x03, 0x2d, 0x06, 0xe6, 0x0c, 0xe5, 0x03, 0xb0, 0x03, 0xc2, 0x06, 0xe5, 0x06, 0xe6, 0x03, 0xe0, 0x03, 0xd9, 0x03, 0xd0, 0x03, 0xce, 0x21, 0xd0, 0x03, 0x92, 0x03, 00, 0x36, 0xd0, 0x03, 0xcf, 0x03, 0xcd, 0x03, 0xd5, 0x03, 0xdd, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x18, 0xe0, 0x06, 0x7c, 0x03, 0xe0, 0x03, 0x2c, 0x1e, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x4b, 0xe0, 0x03, 0x20, 0x03, 0x38, 0x03, 0x9c, 0x03, 0x7c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x7c, 0x36, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x52, 0xbd, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x21, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x0c, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xcf, 0x0c, 0xe0, 0x03, 0xcf, 0x06, 0x9c, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x06, 0xad, 0x0c, 0xe0, 0x03, 0xcf, 0x06, 0x9c, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x0c, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xad, 0x0c, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xbd, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x0c, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x1e, 0xe0, 0x03, 0x9c, 0x03, 0xbd, 0x1e, 0xe0, 0x03, 0x9c, 0x03, 0xbd, 0x18, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x12, 0xe0, 0x03, 0xce, 0x03, 0x97, 0x03, 0xbd, 0x03, 0xcf, 0x12, 0xd0, 0x03, 00, 0x03, 0x92, 0x15, 0xd0, 0x06, 0xa0, 0x09, 0xd0, 0x03, 0x92, 0x03, 00, 0x1b, 0xd0, 0x03, 0xce, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xdb, 0x03, 0xe2, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0x9f, 0x03, 0xc2, 0x0f, 0xe5, 0x03, 0xb0, 0x03, 0xb2, 0x03, 0xe6, 0x03, 00, 0x03, 0x9c, 0x03, 0xd6, 0x03, 0xd0, 0x03, 0xcd, 0x03, 0x9e, 0x03, 0x9f, 0x12, 0xd0, 0x03, 0xb0, 0x03, 0x92, 0x1b, 0xd0, 0x03, 0xb0, 0x03, 0x92, 0x15, 0xd0, 0x03, 0x92, 0x03, 0xb0, 0x0f, 0xd0, 0x06, 0xa0, 0x03, 0xd0, 0x03, 00, 0x03, 0x92, 0x0c, 0xd0, 0x03, 0xa0, 0x03, 0xbf, 0x18, 0xd0, 0x03, 0xcf, 0x06, 0xcd, 0x03, 0x92, 0x03, 0x95, 0x03, 0xcf, 0x03, 0xe6, 0x03, 0x63, 0x03, 0x2d, 0x12, 0xe5, 0x03, 0x2d, 0x03, 0x62, 0x03, 0xe5, 0x06, 0xe6, 0x03, 0xe2, 0x03, 0xdb, 0x03, 0xd1, 0x03, 0xcd, 0x03, 0xce, 0x03, 0xd0, 0x06, 0x92, 0x12, 0xd0, 0x03, 0x92, 0x03, 0xb0, 0x03, 0x92, 0x03, 00, 0x0c, 0xd0, 0x03, 0x92, 0x03, 0xb0, 0x12, 0xd0, 0x03, 0xa0, 0x03, 0xbf, 0x0c, 0xd0, 0x03, 0xcf, 0x03, 0xcd, 0x03, 0xc8, 0x03, 0x9c, 0x03, 0xcf, 0x03, 0x60, 0x03, 0x2c, 0x0f, 0xe0, 0x03, 0x9c, 0x21, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x15, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x12, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x12, 0xe0, 0x03, 0x9c, 0x03, 00, 0x21, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x1b, 0xe0, 0x06, 0xad, 0x03, 0xe0, 0x03, 00, 0x03, 0x9c, 0x15, 0xe0, 0x03, 0x9c, 0x03, 0xbd, 0xab, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x0f, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x6e, 0x03, 0x16, 0x03, 0x20, 0x03, 0x0c, 0x03, 0xbd, 0x06, 0xe0, 0x03, 0x20, 0x03, 0x16, 0x03, 0x2c, 0x03, 0x38, 0x09, 0xe0, 0x03, 0x52, 0x03, 00, 0x06, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0x45, 0x03, 0x20, 0x03, 0x0c, 0x03, 0x52, 0x06, 0xe0, 0x03, 0x6e, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x20, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xe0, 0x03, 0x9c, 0x09, 00, 0x06, 0x60, 0x09, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x38, 0x03, 0x16, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x52, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x2c, 0x09, 00, 0x06, 0xe0, 0x03, 0x45, 0x03, 0x16, 0x06, 0x20, 0x03, 0xcf, 0x12, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x03, 0x20, 0x03, 0x2c, 0x03, 00, 0x03, 0x8c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x7c, 0x03, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x16, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0x2b, 0x03, 0x0c, 0x03, 0x9f, 0x03, 0xcf, 0x0f, 0xd0, 0x03, 0x15, 0x03, 0x4c, 0x0f, 0xd0, 0x03, 0xbf, 0x06, 0x1f, 0x03, 0x15, 0x03, 0x41, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0x34, 0x03, 0x1f, 0x03, 0xbf, 0x03, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x58, 0x03, 0x29, 0x03, 0xd5, 0x03, 0xdd, 0x03, 0x2d, 0x03, 0x54, 0x03, 0x21, 0x03, 0x2d, 0x03, 00, 0x03, 0x90, 0x06, 0xe5, 0x03, 0xd3, 0x03, 0x21, 0x03, 0x16, 0x03, 0x21, 0x03, 0x2d, 0x03, 00, 0x03, 0x9f, 0x03, 0xdf, 0x03, 0xc5, 0x03, 0x1f, 0x03, 0x1e, 0x03, 0x15, 0x03, 0x40, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0x74, 0x06, 0x15, 0x03, 0x1f, 0x15, 0xd0, 0x03, 0x74, 0x03, 00, 0x03, 0x29, 0x03, 0x1f, 0x03, 0x15, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0xa0, 0x03, 0x0c, 0x03, 0x29, 0x03, 0x0c, 0x03, 0x74, 0x06, 0xd0, 0x03, 0xbf, 0x03, 0x1f, 0x03, 0x15, 0x03, 0x1f, 0x03, 0x29, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x03, 0x34, 0x03, 0x29, 0x03, 0xa0, 0x03, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xcf, 0x03, 0xcd, 0x03, 0x72, 0x03, 0x0c, 0x03, 0x1f, 0x03, 0x2b, 0x03, 0x39, 0x03, 0xe6, 0x03, 0x62, 0x03, 0x2d, 0x03, 0xe5, 0x03, 0xd3, 0x03, 0x16, 0x03, 0x46, 0x03, 0xe5, 0x03, 0x62, 0x09, 00, 0x03, 0xa0, 0x03, 0xe5, 0x03, 0xdd, 0x03, 0xd5, 0x03, 0xce, 0x03, 0xcd, 0x03, 0xa0, 0x03, 0x15, 0x06, 0x1f, 0x03, 0x15, 0x03, 0xa0, 0x06, 0xd0, 0x03, 0xa0, 0x03, 0x0c, 0x03, 0x1f, 0x03, 0x15, 0x03, 0x29, 0x03, 00, 0x06, 0xd0, 0x03, 0xa0, 0x03, 0x0c, 0x03, 0x29, 0x03, 0x0c, 0x03, 0x74, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x03, 0x34, 0x03, 0x29, 0x03, 0xa0, 0x09, 0xd0, 0x06, 0xcf, 0x03, 0x74, 0x03, 00, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x20, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x03, 0x20, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x45, 0x03, 0x16, 0x06, 0x20, 0x03, 0xcf, 0x06, 0xe0, 0x03, 00, 0x03, 0x6e, 0x03, 0x16, 0x03, 0x20, 0x03, 0x0c, 0x03, 0xbd, 0x0f, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0x8c, 0x0f, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x12, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 0x16, 0x03, 0x20, 0x03, 0x2c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x7c, 0xa8, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x06, 0x2c, 0x06, 0x60, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x20, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x20, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xcf, 0x0c, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0xad, 0x0c, 0xe0, 0x03, 0x60, 0x03, 00, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x8c, 0x03, 00, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x8c, 0x03, 00, 0x06, 0xe0, 0x03, 00, 0x03, 0x8c, 0x0f, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x6e, 0x12, 0xe0, 0x03, 0x16, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x52, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x16, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x03, 0xdd, 0x03, 0x5c, 0x03, 0x34, 0x03, 0xce, 0x0f, 0xd0, 0x03, 0xa0, 0x03, 0x0c, 0x03, 0x29, 0x03, 0xa0, 0x09, 0xd0, 0x06, 0x41, 0x03, 0xd0, 0x03, 0xbf, 0x03, 0x0c, 0x03, 0xa0, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0xd0, 0x03, 0x67, 0x03, 0x0c, 0x03, 0xa0, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x59, 0x03, 0x29, 0x03, 0xd0, 0x03, 0xd9, 0x03, 0x2c, 0x03, 0x0d, 0x03, 0xb2, 0x03, 0xe5, 0x03, 0x54, 0x03, 0x2d, 0x06, 0xe5, 0x03, 0x54, 0x03, 0x2d, 0x06, 0xe5, 0x03, 0x9f, 0x03, 00, 0x03, 0xa0, 0x03, 0xe5, 0x03, 0x45, 0x03, 0x42, 0x03, 0xcf, 0x03, 0xbd, 0x03, 0x0c, 0x03, 0x9f, 0x03, 0xcf, 0x03, 0x92, 0x03, 00, 0x03, 0x41, 0x03, 0xd0, 0x03, 0xbf, 0x03, 00, 0x03, 0x92, 0x0f, 0xd0, 0x03, 0xb0, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0xbf, 0x03, 0x15, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x15, 0x03, 0x74, 0x03, 0xd0, 0x03, 0x92, 0x03, 0x0c, 0x06, 0xd0, 0x03, 0x4c, 0x03, 0x29, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x5a, 0x03, 00, 0x03, 0x83, 0x09, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x59, 0x03, 0xce, 0x03, 0xad, 0x03, 00, 0x03, 0x78, 0x03, 0xe0, 0x03, 0xe5, 0x06, 0xe6, 0x03, 0x62, 0x03, 0x2d, 0x03, 0xe5, 0x03, 0x39, 0x03, 0x21, 0x03, 0xd3, 0x06, 0xe5, 0x03, 0x2d, 0x03, 0x62, 0x06, 0xe6, 0x03, 0xe1, 0x03, 0xd9, 0x03, 0xd0, 0x03, 0xcd, 0x03, 0xce, 0x03, 0x15, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x15, 0x06, 0xd0, 0x03, 0x1f, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x5a, 0x03, 00, 0x06, 0xd0, 0x03, 0x15, 0x03, 0x74, 0x03, 0xd0, 0x03, 0x92, 0x03, 0x0c, 0x06, 0xd0, 0x03, 0x5a, 0x03, 00, 0x03, 0x83, 0x0f, 0xd0, 0x03, 0xce, 0x03, 0xbe, 0x03, 00, 0x03, 0x9b, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x38, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xbd, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x45, 0x03, 0x20, 0x03, 0xcf, 0x0c, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xcf, 0x03, 0x16, 0x03, 0x45, 0x06, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x6e, 0x06, 0xe0, 0x03, 00, 0x03, 0x20, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x20, 0x03, 0x60, 0x12, 0xe0, 0x03, 0x7c, 0x03, 00, 0x03, 0x45, 0x03, 0xcf, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x38, 0x12, 0xe0, 0x03, 0x52, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x16, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0xa8, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x06, 0x2c, 0x06, 0x60, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x8c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0x45, 0x03, 0xcf, 0x09, 0xe0, 0x03, 0x38, 0x03, 0x45, 0x0f, 0xe0, 0x03, 0x60, 0x03, 0x20, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x0f, 0xe0, 0x03, 0x9c, 0x03, 0x6e, 0x03, 00, 0x06, 0xe0, 0x03, 0x16, 0x03, 0x20, 0x03, 0xbd, 0x0c, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x38, 0x03, 0x45, 0x06, 0x9c, 0x03, 0x45, 0x03, 0x2c, 0x0f, 0xe0, 0x03, 0xad, 0x03, 00, 0x09, 0x9c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x6e, 0x03, 0x20, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x6e, 0x03, 0x20, 0x06, 0x9c, 0x03, 0x6b, 0x03, 00, 0x03, 0xcd, 0x03, 0xcf, 0x0f, 0xd0, 0x03, 0xb0, 0x03, 0x41, 0x03, 00, 0x03, 0x4c, 0x06, 0xd0, 0x03, 0x0c, 0x03, 0x67, 0x06, 0x92, 0x03, 0x1f, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0x92, 0x03, 00, 0x03, 0x83, 0x09, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x59, 0x03, 0x29, 0x03, 0xce, 0x03, 0xd3, 0x03, 0x2b, 0x03, 0x53, 0x06, 0xe6, 0x03, 0x62, 0x03, 0x2d, 0x06, 0xe5, 0x03, 0x16, 0x03, 0x80, 0x09, 0xe5, 0x03, 00, 0x03, 0xa0, 0x03, 0xe7, 0x03, 0x0d, 0x03, 0x6e, 0x03, 0x96, 0x03, 0x92, 0x03, 0x1e, 0x03, 0x59, 0x03, 0xce, 0x03, 0x91, 0x03, 00, 0x03, 0xbf, 0x06, 0xd0, 0x03, 00, 0x03, 0x92, 0x0f, 0xd0, 0x03, 0x67, 0x03, 0x1f, 0x09, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0xa0, 0x03, 00, 0x09, 0x92, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x15, 0x03, 0x74, 0x09, 0xd0, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x0c, 0xd0, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0xcf, 0x03, 0x29, 0x03, 0x59, 0x03, 0xce, 0x03, 0x67, 0x03, 0x15, 0x03, 0xe0, 0x03, 0xe6, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xe5, 0x03, 0x62, 0x03, 0x2d, 0x03, 0x62, 0x03, 0x0d, 0x03, 0xc2, 0x09, 0xe5, 0x03, 0x2d, 0x03, 0x63, 0x03, 0xe6, 0x03, 0xe4, 0x03, 0xdb, 0x03, 0xd3, 0x06, 0xce, 0x03, 0x9f, 0x03, 00, 0x03, 0xbf, 0x06, 0xd0, 0x03, 0xbf, 0x03, 00, 0x03, 0xa0, 0x03, 0xb0, 0x03, 00, 0x03, 0xb0, 0x06, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0xd0, 0x03, 0xa0, 0x03, 00, 0x09, 0x92, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x0f, 0xd0, 0x03, 0xcf, 0x03, 0xcd, 0x03, 0x74, 0x03, 0x15, 0x03, 0xdf, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x0c, 0x03, 0x7c, 0x0f, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0x2c, 0x03, 0x20, 0x09, 0xe0, 0x03, 0x38, 0x03, 0x45, 0x06, 0x9c, 0x03, 0x45, 0x03, 0x2c, 0x06, 0xe0, 0x03, 00, 0x03, 0x8c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x15, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x6e, 0x03, 0x20, 0x06, 0x9c, 0x03, 0x6e, 0x03, 00, 0x12, 0xe0, 0x03, 0x16, 0x03, 0x7c, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xad, 0x03, 00, 0x09, 0x9c, 0x03, 00, 0x03, 0x9c, 0xa5, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x0f, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x9c, 0x03, 0x16, 0x03, 00, 0x03, 0x6e, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x0f, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0xad, 0x06, 0x16, 0x03, 0x2c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x06, 0x20, 0x03, 00, 0x06, 0xe0, 0x03, 0xbd, 0x03, 0x2c, 0x03, 00, 0x03, 0x38, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x16, 0x09, 0x2c, 0x03, 0x52, 0x0f, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0x2c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x0c, 0x06, 0x2c, 0x03, 0x2b, 0x03, 0x2a, 0x03, 0xcd, 0x03, 0xce, 0x15, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 00, 0x03, 0x1f, 0x09, 0x29, 0x03, 0x74, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0x15, 0x03, 0x1f, 0x0c, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x03, 0xcd, 0x03, 0xcf, 0x03, 0x2a, 0x03, 0x60, 0x03, 0xe5, 0x03, 0xe6, 0x03, 0x62, 0x03, 0x2d, 0x06, 0xe5, 0x03, 00, 0x03, 0x9f, 0x09, 0xe5, 0x03, 00, 0x03, 0x9f, 0x03, 0xe5, 0x03, 00, 0x03, 0x21, 0x03, 0x2c, 0x06, 0x2a, 0x03, 0x73, 0x03, 0xce, 0x03, 0x91, 0x03, 00, 0x09, 0xd0, 0x03, 00, 0x03, 0x92, 0x0f, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x09, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x0c, 0x29, 0x03, 0xa0, 0x03, 0xd0, 0x03, 00, 0x03, 0x92, 0x09, 0xd0, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x0c, 0xd0, 0x03, 00, 0x03, 0x92, 0x06, 0xcf, 0x03, 0x29, 0x03, 0x59, 0x03, 0xd3, 0x03, 0x5e, 0x03, 0x2c, 0x03, 0xe5, 0x03, 0xe6, 0x09, 0xe5, 0x03, 0x62, 0x03, 0x16, 0x03, 00, 0x03, 0x54, 0x0c, 0xe5, 0x03, 0x2d, 0x03, 0x63, 0x03, 0xe5, 0x03, 0xdf, 0x03, 0xd6, 0x03, 0xcf, 0x03, 0xcd, 0x03, 0xcf, 0x03, 0x92, 0x03, 00, 0x0c, 0xd0, 0x03, 00, 0x06, 0x92, 0x03, 00, 0x09, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x0c, 0x29, 0x03, 0xa0, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x0f, 0xd0, 0x03, 0xce, 0x03, 0xcd, 0x03, 0x5a, 0x03, 0x2b, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x0f, 0xe0, 0x03, 0x2c, 0x03, 0x16, 0x03, 00, 0x03, 0x8c, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x16, 0x09, 0x2c, 0x03, 0x52, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x1b, 0xe0, 0x03, 0x60, 0x03, 0x0c, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x0c, 0x0c, 0x2c, 0x12, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0x2c, 0x03, 0xad, 0xa5, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x0f, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x0c, 0xe0, 0x03, 0x7c, 0x03, 00, 0x03, 0xad, 0x03, 0xe0, 0x06, 0x45, 0x0f, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x16, 0x03, 0x52, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0x8c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x6e, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x06, 0x45, 0x1b, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x0f, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x09, 0xe0, 0x03, 0x20, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x06, 0xe0, 0x03, 0xdd, 0x03, 0xd6, 0x03, 0xd0, 0x03, 0xce, 0x18, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0x15, 0x03, 0x74, 0x0f, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0xa0, 0x03, 0x0c, 0x03, 0x5a, 0x09, 0xd0, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x4c, 0x03, 0x29, 0x03, 0xce, 0x03, 0xcd, 0x03, 0x29, 0x03, 0x5c, 0x03, 0xe0, 0x03, 0xe6, 0x03, 0x63, 0x03, 0x2d, 0x06, 0xe5, 0x03, 00, 0x03, 0x9f, 0x09, 0xe5, 0x03, 00, 0x03, 0x9f, 0x03, 0xe5, 0x03, 0x16, 0x03, 0x81, 0x03, 0xe4, 0x03, 0xe0, 0x03, 0xdb, 0x03, 0xd5, 0x03, 0xd0, 0x03, 0x8f, 0x03, 00, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd0, 0x03, 00, 0x03, 0x92, 0x0f, 0xd0, 0x03, 0x74, 0x03, 0x15, 0x09, 0xd0, 0x03, 0x1f, 0x03, 0x5a, 0x03, 0xd0, 0x03, 0xb0, 0x03, 00, 0x03, 0xb0, 0x0f, 0xd0, 0x03, 00, 0x03, 0x92, 0x09, 0xd0, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x0c, 0xd0, 0x03, 00, 0x03, 0x90, 0x06, 0xcd, 0x03, 0x1f, 0x03, 0x5c, 0x03, 0xdb, 0x03, 0x7c, 0x03, 0x16, 0x06, 0xe6, 0x09, 0xe5, 0x03, 0x62, 0x03, 0x2d, 0x03, 0x80, 0x03, 00, 0x03, 0x9f, 0x09, 0xe5, 0x03, 0x2d, 0x03, 0x63, 0x03, 0xe0, 0x03, 0xd6, 0x03, 0xd0, 0x03, 0xcd, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xa0, 0x03, 00, 0x03, 0xbf, 0x06, 0xd0, 0x03, 0xbf, 0x03, 00, 0x03, 0xa0, 0x03, 0x92, 0x03, 00, 0x09, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0xd0, 0x03, 0xb0, 0x03, 00, 0x03, 0xb0, 0x0f, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x0f, 0xd0, 0x03, 0xce, 0x03, 0xd0, 0x03, 0x5c, 0x03, 0x2b, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x8c, 0x03, 00, 0x06, 0xe0, 0x03, 0x16, 0x03, 0x7c, 0x0f, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0x45, 0x03, 0x0c, 0x03, 0xcf, 0x06, 0xe0, 0x06, 0x45, 0x12, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x1e, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x1e, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0xb1, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x0f, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0x03, 0xad, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 00, 0x03, 0x8c, 0x03, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x45, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x7c, 0x03, 00, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x20, 0x03, 0x6e, 0x06, 0xe0, 0x03, 00, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xad, 0x06, 0xe0, 0x03, 0xcf, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x38, 0x09, 0xe0, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0x60, 0x03, 0x9c, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0x6e, 0x06, 0xe0, 0x03, 0xc9, 0x03, 0xd3, 0x03, 0xce, 0x03, 0xcf, 0x09, 0xd0, 0x03, 0x92, 0x06, 0xd0, 0x03, 0xbf, 0x03, 0x0c, 0x03, 0x74, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x15, 0x03, 0xbf, 0x06, 0xd0, 0x03, 0xbf, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x03, 0xd0, 0x03, 0xa0, 0x03, 0x0c, 0x03, 0x74, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x4c, 0x03, 0xd0, 0x03, 0xa0, 0x03, 0x0c, 0x03, 0x29, 0x03, 0xcf, 0x03, 0xcd, 0x03, 0x29, 0x03, 0x5a, 0x03, 0xd9, 0x03, 0xe1, 0x03, 0x63, 0x03, 0x2d, 0x03, 0xe6, 0x03, 0xe5, 0x06, 0x39, 0x06, 0xe5, 0x03, 0x54, 0x03, 00, 0x03, 0x9f, 0x03, 0xe5, 0x03, 0x62, 0x03, 0x16, 0x03, 0xd4, 0x03, 0xe5, 0x03, 0xe4, 0x03, 0xcd, 0x03, 0xd9, 0x03, 0x93, 0x03, 00, 0x06, 0xcd, 0x03, 0xce, 0x03, 00, 0x03, 0x91, 0x0f, 0xd0, 0x03, 0xbf, 0x03, 0x0c, 0x03, 0x5a, 0x03, 0x92, 0x03, 0x29, 0x03, 0x15, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x34, 0x09, 0xd0, 0x03, 0xbf, 0x03, 0xd0, 0x06, 0x34, 0x06, 0xd0, 0x03, 0x4c, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x03, 0xd0, 0x06, 0xcf, 0x03, 0xce, 0x03, 00, 0x03, 0x81, 0x03, 0xcf, 0x03, 0x76, 0x03, 00, 0x03, 0x5f, 0x03, 0xe4, 0x03, 0xd3, 0x03, 0x0d, 0x03, 0x81, 0x06, 0xe5, 0x03, 0xd3, 0x03, 0xe5, 0x03, 0x62, 0x03, 0x2d, 0x03, 0xe5, 0x03, 0x80, 0x03, 0x0d, 0x03, 0xb0, 0x06, 0xe6, 0x03, 0x2d, 0x03, 0x45, 0x03, 0xd9, 0x03, 0xd0, 0x06, 0xcd, 0x03, 0xcf, 0x06, 0xd0, 0x03, 0x15, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0x5a, 0x03, 0x15, 0x06, 0xd0, 0x03, 0x0c, 0x03, 0x67, 0x03, 0xd0, 0x03, 0xbf, 0x03, 0x29, 0x03, 00, 0x06, 0xd0, 0x03, 0x29, 0x03, 0x34, 0x09, 0xd0, 0x03, 0xbf, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x0c, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xd3, 0x03, 0xa8, 0x03, 00, 0x03, 0xad, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x20, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 00, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x20, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x45, 0x03, 0x20, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xad, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x0f, 0xe0, 0x06, 0xbd, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0x6e, 0x06, 0xe0, 0x03, 0xcf, 0x12, 0xe0, 0x06, 0x38, 0x06, 0xe0, 0x03, 0x52, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x38, 0x09, 0xe0, 0x03, 0xcf, 0xa5, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x2c, 0x0c, 00, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x45, 0x09, 0xe0, 0x03, 0x52, 0x03, 00, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x6e, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x0c, 0x09, 0x2c, 0x03, 0x16, 0x03, 0xad, 0x03, 0x9c, 0x03, 00, 0x06, 0xe0, 0x03, 0xbd, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x8c, 0x03, 00, 0x03, 0x2c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x20, 0x03, 0x16, 0x03, 0x20, 0x03, 0x52, 0x03, 0x0c, 0x03, 0x20, 0x03, 0xe0, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x20, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x0c, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x6e, 0x03, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x38, 0x12, 0xe0, 0x03, 0xbd, 0x03, 0x20, 0x03, 0x16, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0xad, 0x06, 0x38, 0x03, 0x8c, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xd6, 0x06, 0xce, 0x09, 0xd0, 0x03, 0x29, 0x03, 0x0c, 0x03, 0x29, 0x03, 0x0c, 0x03, 0x4c, 0x09, 0xd0, 0x03, 0x34, 0x03, 0x0c, 0x03, 0x29, 0x03, 0x15, 0x03, 0x67, 0x03, 0xd0, 0x03, 0x92, 0x03, 00, 0x06, 0xd0, 0x03, 0x74, 0x03, 00, 0x03, 0x74, 0x03, 0xd0, 0x03, 0x83, 0x03, 00, 0x03, 0x29, 0x03, 0x1f, 0x03, 0x4c, 0x03, 0x29, 0x03, 0xd0, 0x03, 0xcf, 0x03, 0x29, 0x03, 0x59, 0x03, 0xd1, 0x03, 0xda, 0x03, 0x61, 0x03, 0x2d, 0x06, 0xe6, 0x03, 0xb0, 0x03, 0x0d, 0x03, 0x21, 0x03, 0x16, 0x03, 0x80, 0x03, 00, 0x03, 0x9f, 0x06, 0xe5, 0x03, 0x39, 0x03, 0x0d, 0x03, 0x2d, 0x03, 0x16, 0x03, 0x70, 0x03, 0xe1, 0x03, 0x9a, 0x03, 00, 0x03, 0xd0, 0x03, 0xce, 0x03, 0xcd, 0x03, 00, 0x03, 0x90, 0x06, 0xcf, 0x0c, 0xd0, 0x03, 0xa0, 0x06, 0x34, 0x03, 0x83, 0x03, 0x29, 0x03, 0x5a, 0x06, 0xd0, 0x03, 0xb0, 0x03, 0x1f, 0x03, 0x15, 0x03, 0x29, 0x03, 0x0c, 0x03, 0xa0, 0x03, 0xd0, 0x03, 0xa0, 0x03, 0x0c, 0x03, 0x1f, 0x03, 0x15, 0x03, 0x74, 0x03, 00, 0x03, 0x92, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x03, 0xcf, 0x03, 0xce, 0x06, 0xcd, 0x03, 0x4b, 0x03, 0x0c, 0x03, 0x1f, 0x03, 0x43, 0x03, 0x2c, 0x03, 0x62, 0x06, 0xe6, 0x03, 0x81, 0x03, 0x0d, 0x06, 0x21, 0x03, 0x39, 0x03, 0xe5, 0x03, 0x62, 0x03, 0x2d, 0x06, 0xe5, 0x03, 0x46, 0x03, 0x0d, 0x03, 0xb2, 0x03, 0xe5, 0x03, 0x8e, 0x03, 00, 0x03, 0x2a, 0x03, 0x9f, 0x03, 0xcd, 0x03, 0xcf, 0x09, 0xd0, 0x03, 0xa0, 0x03, 0x15, 0x06, 0x1f, 0x03, 0x15, 0x03, 0xa0, 0x06, 0xd0, 0x03, 0x74, 0x03, 00, 0x03, 0x29, 0x03, 0x15, 0x03, 0x67, 0x03, 00, 0x06, 0xd0, 0x03, 0xb0, 0x03, 0x1f, 0x03, 0x15, 0x03, 0x29, 0x03, 0x0c, 0x03, 0xa0, 0x03, 0xd0, 0x03, 0x5a, 0x03, 0x29, 0x0c, 0xd0, 0x06, 0xce, 0x03, 0xd6, 0x03, 0xdd, 0x03, 0x45, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x52, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0xbd, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x16, 0x03, 0x6e, 0x03, 00, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xcf, 0x06, 0x20, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x6e, 0x03, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x38, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x0f, 0xe0, 0x03, 0xbd, 0x06, 0x16, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x2c, 0x03, 0x0c, 0x12, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x16, 0x03, 0x7c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0xbd, 0x03, 0x20, 0x03, 0x16, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0xa5, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x87, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xad, 0x0f, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xbd, 0x21, 0xe0, 0x06, 0xad, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x12, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x09, 0xe0, 0x03, 0x9c, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0xbd, 0x03, 0xad, 0x06, 0xe0, 0x06, 0x9c, 0x0f, 0xe0, 0x06, 0xad, 0x09, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xbd, 0x1b, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x45, 0xe0, 0x03, 0x16, 0x03, 0x8c, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0xda, 0x03, 0xd0, 0x03, 0xce, 0x03, 0xcf, 0x09, 0xd0, 0x03, 0xb0, 0x03, 0x92, 0x03, 0xb0, 0x0f, 0xd0, 0x03, 0xb0, 0x03, 0x92, 0x03, 0xbf, 0x21, 0xd0, 0x03, 0xb0, 0x03, 0x92, 0x0f, 0xd0, 0x03, 0xcf, 0x06, 0xce, 0x03, 0xd4, 0x03, 0xdb, 0x03, 0xe1, 0x03, 0xe5, 0x06, 0xe6, 0x03, 0xd3, 0x03, 0x9f, 0x03, 0xc2, 0x12, 0xe5, 0x03, 0xc2, 0x03, 0x9f, 0x03, 0xd4, 0x03, 0xe6, 0x03, 0xe5, 0x03, 0xe4, 0x03, 0xdf, 0x03, 0xd9, 0x03, 0xd4, 0x03, 0xd0, 0x03, 0xce, 0x09, 0xcd, 0x03, 0xce, 0x06, 0xcf, 0x0f, 0xd0, 0x03, 0x15, 0x03, 0x83, 0x0c, 0xd0, 0x03, 0xa0, 0x03, 0x92, 0x0c, 0xd0, 0x03, 0xbf, 0x03, 0x92, 0x03, 0xb0, 0x06, 0xd0, 0x06, 0xcf, 0x03, 0xce, 0x09, 0xcd, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xd4, 0x03, 0xa7, 0x03, 0xac, 0x03, 0xe4, 0x03, 0xe5, 0x06, 0xe6, 0x06, 0xe5, 0x03, 0xd3, 0x03, 0x9f, 0x03, 0xb0, 0x12, 0xe5, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0xe1, 0x03, 0xdb, 0x03, 0xb3, 0x03, 0x90, 0x03, 0xce, 0x03, 0xcf, 0x12, 0xd0, 0x06, 0x92, 0x0f, 0xd0, 0x03, 0xb0, 0x03, 0x92, 0x03, 0xbf, 0x12, 0xd0, 0x03, 0xa0, 0x03, 0x92, 0x18, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xda, 0x06, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x21, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x12, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xcf, 0x21, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xbd, 0x30, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xcf, 0x1b, 0xe0, 0x03, 0x9c, 0x03, 0xad, 0x18, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xbd, 0x1e, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0xab, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xa5, 0xe0, 0x03, 0x45, 0x03, 0x8c, 0x03, 0x9c, 0x03, 0x38, 0x03, 0x0c, 0x03, 0xcf, 0x15, 0xe0, 0x03, 0xdd, 0x03, 0xd5, 0x06, 0xce, 0x03, 0xcf, 0x5d, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xcd, 0x03, 0xce, 0x03, 0xd4, 0x03, 0xdb, 0x03, 0xe1, 0x03, 0xe5, 0x09, 0xe6, 0x1e, 0xe5, 0x09, 0xe6, 0x03, 0xe5, 0x03, 0xe2, 0x03, 0xdd, 0x03, 0xda, 0x03, 0xd5, 0x03, 0xd1, 0x03, 0xcf, 0x0f, 0xce, 0x03, 0x40, 0x03, 0x82, 0x03, 0x91, 0x03, 0x34, 0x03, 0x0c, 0x03, 0xbf, 0x1b, 0xd0, 0x0c, 0xcf, 0x12, 0xce, 0x03, 0xcf, 0x03, 0xd1, 0x03, 0xd5, 0x03, 0xda, 0x03, 0xdd, 0x03, 0xe2, 0x03, 0xe5, 0x09, 0xe6, 0x1e, 0xe5, 0x09, 0xe6, 0x03, 0xe5, 0x03, 0xe1, 0x03, 0xdb, 0x03, 0xd4, 0x03, 0xce, 0x03, 0xcd, 0x03, 0xce, 0x03, 0xcf, 0x5d, 0xd0, 0x03, 0xcf, 0x06, 0xce, 0x03, 0xd5, 0x03, 0xdd, 0xff, 0xe0, 0xc6, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xa5, 0xe0, 0x03, 0x6e, 0x06, 0x2c, 0x03, 0x45, 0x03, 0xbd, 0x18, 0xe0, 0x03, 0xdf, 0x03, 0xda, 0x03, 0xd1, 0x03, 0xcd, 0x03, 0xce, 0x5d, 0xd0, 0x06, 0xcf, 0x03, 0xce, 0x03, 0xcd, 0x03, 0xce, 0x03, 0xd4, 0x03, 0xda, 0x03, 0xe1, 0x03, 0xe5, 0x06, 0xe6, 0x24, 0xe5, 0x09, 0xe6, 0x03, 0xe5, 0x03, 0xe4, 0x03, 0xe0, 0x03, 0xdb, 0x03, 0xd7, 0x03, 0xd5, 0x03, 0xd1, 0x03, 0xd0, 0x03, 0xce, 0x03, 0xcd, 0x03, 0x65, 0x06, 0x29, 0x03, 0x40, 0x03, 0xaf, 0x21, 0xcf, 0x09, 0xce, 0x06, 0xcd, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xd1, 0x03, 0xd5, 0x03, 0xd7, 0x03, 0xdb, 0x03, 0xe0, 0x03, 0xe4, 0x03, 0xe5, 0x09, 0xe6, 0x24, 0xe5, 0x06, 0xe6, 0x03, 0xe5, 0x03, 0xe1, 0x03, 0xda, 0x03, 0xd4, 0x03, 0xce, 0x03, 0xcd, 0x03, 0xce, 0x06, 0xcf, 0x5d, 0xd0, 0x03, 0xce, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xda, 0x03, 0xdf, 0xff, 0xe0, 0xc6, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xcf, 0xe0, 0x03, 0xdc, 0x03, 0xd5, 0x06, 0xce, 0x03, 0xd0, 0x63, 0xcf, 0x06, 0xce, 0x03, 0xcf, 0x03, 0xd4, 0x03, 0xdb, 0x03, 0xe1, 0x03, 0xe5, 0x03, 0xe6, 0x2d, 0xe5, 0x09, 0xe6, 0x03, 0xe4, 0x03, 0xe1, 0x03, 0xdd, 0x03, 0xda, 0x03, 0xd5, 0x03, 0xd3, 0x09, 0xd0, 0x0c, 0xcf, 0x06, 0xce, 0x0c, 0xcf, 0x06, 0xce, 0x0c, 0xcf, 0x09, 0xd0, 0x03, 0xd3, 0x03, 0xd5, 0x03, 0xda, 0x03, 0xdd, 0x03, 0xe1, 0x03, 0xe4, 0x09, 0xe6, 0x2d, 0xe5, 0x03, 0xe6, 0x03, 0xe5, 0x03, 0xe1, 0x03, 0xdb, 0x03, 0xd4, 0x03, 0xcf, 0x06, 0xce, 0x63, 0xcf, 0x03, 0xd0, 0x06, 0xce, 0x03, 0xd5, 0x03, 0xdc, 0xff, 0xe0, 0xc9, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xcf, 0xe0, 0x03, 0xdf, 0x03, 0xda, 0x03, 0xd1, 0x03, 0xcd, 0x69, 0xcf, 0x09, 0xce, 0x03, 0xd4, 0x03, 0xdb, 0x03, 0xe2, 0x06, 0xe6, 0x2d, 0xe5, 0x06, 0xe6, 0x06, 0xe5, 0x06, 0xe4, 0x03, 0xe0, 0x03, 0xdd, 0x03, 0xdb, 0x03, 0xd9, 0x03, 0xd6, 0x03, 0xd5, 0x03, 0xd3, 0x03, 0xd1, 0x03, 0xcf, 0x03, 0xce, 0x12, 0xcd, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd1, 0x03, 0xd3, 0x03, 0xd5, 0x03, 0xd6, 0x03, 0xd9, 0x03, 0xdb, 0x03, 0xdd, 0x03, 0xe0, 0x06, 0xe4, 0x06, 0xe5, 0x06, 0xe6, 0x2d, 0xe5, 0x06, 0xe6, 0x03, 0xe2, 0x03, 0xdb, 0x03, 0xd4, 0x09, 0xce, 0x69, 0xcf, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xda, 0x03, 0xdf, 0xff, 0xe0, 0xc9, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xd2, 0xe0, 0x03, 0xdd, 0x03, 0xd5, 0x03, 0xce, 0x03, 0xcd, 0x69, 0xcf, 0x03, 0xce, 0x03, 0xcd, 0x03, 0xcf, 0x03, 0xd4, 0x03, 0xda, 0x03, 0xe1, 0x09, 0xe6, 0x30, 0xe5, 0x06, 0xe6, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xe5, 0x03, 0xe4, 0x03, 0xe1, 0x03, 0xe0, 0x03, 0xdd, 0x03, 0xdc, 0x03, 0xdb, 0x03, 0xda, 0x03, 0xd9, 0x03, 0xd7, 0x0c, 0xd6, 0x03, 0xd7, 0x03, 0xd9, 0x03, 0xda, 0x03, 0xdb, 0x03, 0xdc, 0x03, 0xdd, 0x03, 0xe0, 0x03, 0xe1, 0x03, 0xe4, 0x03, 0xe5, 0x03, 0xe6, 0x03, 0xe7, 0x06, 0xe6, 0x30, 0xe5, 0x09, 0xe6, 0x03, 0xe1, 0x03, 0xda, 0x03, 0xd4, 0x03, 0xcf, 0x03, 0xcd, 0x03, 0xce, 0x69, 0xcf, 0x03, 0xcd, 0x03, 0xce, 0x03, 0xd5, 0x03, 0xdd, 0xff, 0xe0, 0xcc, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x7c, 0x03, 0x6e, 0x0c, 0xe0, 0x03, 0x60, 0x03, 0xbd, 0x99, 0xe0, 0x03, 0xbd, 0x18, 0x60, 0xb7, 0xe0, 0x03, 0xdf, 0x03, 0xda, 0x03, 0xd0, 0x03, 0xcd, 0x6f, 0xcf, 0x03, 0xcd, 0x03, 0xce, 0x03, 0xd1, 0x03, 0xd9, 0x03, 0xe0, 0x03, 0xe5, 0x03, 0xe6, 0x33, 0xe5, 0x06, 0xe6, 0x4e, 0xe5, 0x06, 0xe6, 0x33, 0xe5, 0x03, 0xe6, 0x03, 0xe5, 0x03, 0xe0, 0x03, 0xd9, 0x03, 0xd1, 0x03, 0xce, 0x03, 0xcd, 0x6f, 0xcf, 0x03, 0xcd, 0x03, 0xd0, 0x03, 0xda, 0x03, 0xdf, 0xff, 0xe0, 0xcc, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x2c, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x45, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x30, 0xe0, 0x03, 0xad, 0x03, 0xbd, 0x18, 0xe0, 0x03, 0xbd, 0x09, 0x60, 0x03, 0x16, 0x03, 0x2c, 0x09, 0x60, 0x2d, 0xe0, 0x03, 0x9c, 0x03, 0xcf, 0x87, 0xe0, 0x03, 0xdd, 0x03, 0xd5, 0x06, 0xce, 0x6c, 0xcf, 0x09, 0xce, 0x03, 0xd0, 0x03, 0xd7, 0x03, 0xdf, 0x03, 0xe2, 0x09, 0xe6, 0x33, 0xe5, 0x48, 0xe6, 0x33, 0xe5, 0x09, 0xe6, 0x03, 0xe2, 0x03, 0xdf, 0x03, 0xd7, 0x03, 0xd0, 0x09, 0xce, 0x6c, 0xcf, 0x06, 0xce, 0x03, 0xd5, 0x03, 0xdd, 0xff, 0xe0, 0xcf, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x20, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x09, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x27, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xbd, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0f, 0xe0, 0x06, 0x9c, 0x03, 0xcf, 0x0f, 0xe0, 0x06, 0xbd, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x24, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x0f, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0xad, 0x0c, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xad, 0x09, 0xe0, 0x03, 00, 0x03, 0x9c, 0x0c, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xcf, 0x72, 0xe0, 0x03, 0xdf, 0x03, 0xda, 0x03, 0xd3, 0x06, 0xce, 0x6f, 0xcf, 0x06, 0xcd, 0x03, 0xd0, 0x03, 0xd6, 0x03, 0xdb, 0x03, 0xe1, 0x03, 0xe5, 0x0c, 0xe6, 0x2a, 0xe5, 0x48, 0xe6, 0x2a, 0xe5, 0x0c, 0xe6, 0x03, 0xe5, 0x03, 0xe1, 0x03, 0xdb, 0x03, 0xd6, 0x03, 0xd0, 0x06, 0xcd, 0x6f, 0xcf, 0x06, 0xce, 0x03, 0xd3, 0x03, 0xda, 0x03, 0xdf, 0xff, 0xe0, 0xcf, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x03, 0x0c, 0x03, 0x6e, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x45, 0x03, 0x16, 0x06, 0x20, 0x03, 0xcf, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x16, 0x06, 0xe0, 0x09, 00, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x0c, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0x6e, 0x03, 0x20, 0x03, 0x7c, 0x03, 0x60, 0x09, 00, 0x03, 0x9c, 0x1e, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x0c, 0xe0, 0x03, 0x38, 0x03, 0x16, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x52, 0x06, 0xe0, 0x03, 0x8c, 0x03, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x2c, 0x09, 00, 0x06, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0xad, 0x72, 0xe0, 0x03, 0xdd, 0x03, 0xd7, 0x03, 0xcf, 0x03, 0xce, 0x6f, 0xcf, 0x03, 0xce, 0x06, 0xcd, 0x03, 0xcf, 0x03, 0xd3, 0x03, 0xd9, 0x03, 0xdf, 0x03, 0xe2, 0x0c, 0xe6, 0x96, 0xe5, 0x0c, 0xe6, 0x03, 0xe2, 0x03, 0xdf, 0x03, 0xd9, 0x03, 0xd3, 0x03, 0xcf, 0x06, 0xcd, 0x03, 0xce, 0x6f, 0xcf, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd7, 0x03, 0xdd, 0xff, 0xe0, 0xd2, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0xcf, 0x03, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x6e, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 00, 0x03, 0x8c, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0xcf, 0x09, 0xe0, 0x03, 0x20, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0x52, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x24, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x0c, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x8c, 0x03, 00, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x0f, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x38, 0x75, 0xe0, 0x03, 0xdc, 0x03, 0xd4, 0x03, 0xcf, 0x03, 0xce, 0x72, 0xcf, 0x03, 0xce, 0x03, 0xcd, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xd5, 0x03, 0xda, 0x03, 0xe0, 0x03, 0xe4, 0x03, 0xe5, 0x09, 0xe6, 0x8a, 0xe5, 0x09, 0xe6, 0x03, 0xe5, 0x03, 0xe4, 0x03, 0xe0, 0x03, 0xda, 0x03, 0xd5, 0x03, 0xd0, 0x03, 0xce, 0x03, 0xcd, 0x03, 0xce, 0x72, 0xcf, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd4, 0x03, 0xdc, 0xff, 0xe0, 0xd5, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x20, 0x03, 0x45, 0x03, 0xe0, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x38, 0x03, 0x45, 0x06, 0x9c, 0x03, 0x45, 0x03, 0x2c, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x16, 0x03, 0x20, 0x03, 0xbd, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0f, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0x20, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0xcf, 0x0f, 0x9c, 0x0c, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x12, 0xe0, 0x03, 0x9c, 0x03, 0x6e, 0x03, 00, 0x06, 0xe0, 0x03, 0x45, 0x03, 0x0c, 0x03, 0x9c, 0x0c, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x6e, 0x03, 0x20, 0x06, 0x9c, 0x03, 0x6e, 0x03, 00, 0x75, 0xe0, 0x03, 0xdf, 0x03, 0xda, 0x03, 0xd1, 0x03, 0xcd, 0x03, 0xce, 0x72, 0xcf, 0x06, 0xce, 0x06, 0xcd, 0x03, 0xd0, 0x03, 0xd7, 0x03, 0xdf, 0x03, 0xe2, 0x03, 0xe5, 0x03, 0xe6, 0x90, 0xe5, 0x03, 0xe6, 0x03, 0xe5, 0x03, 0xe2, 0x03, 0xdf, 0x03, 0xd7, 0x03, 0xd0, 0x06, 0xcd, 0x06, 0xce, 0x72, 0xcf, 0x03, 0xce, 0x03, 0xcd, 0x03, 0xd1, 0x03, 0xda, 0x03, 0xdf, 0xff, 0xe0, 0xd5, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xad, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x16, 0x09, 0x2c, 0x03, 0x52, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0xbd, 0x03, 0x2c, 0x03, 00, 0x03, 0x38, 0x06, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0xcf, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0xad, 0x0f, 0x2c, 0x0c, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x0c, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x06, 0x20, 0x03, 00, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x52, 0x03, 00, 0x03, 0x20, 0x03, 0xbd, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x0c, 0x0c, 0x2c, 0x78, 0xe0, 0x03, 0xdf, 0x03, 0xd7, 0x03, 0xcf, 0x03, 0xce, 0x78, 0xcf, 0x09, 0xcd, 0x03, 0xd0, 0x03, 0xd4, 0x03, 0xd9, 0x03, 0xdd, 0x03, 0xe1, 0x03, 0xe4, 0x09, 0xe6, 0x78, 0xe5, 0x09, 0xe6, 0x03, 0xe4, 0x03, 0xe1, 0x03, 0xdd, 0x03, 0xd9, 0x03, 0xd4, 0x03, 0xd0, 0x09, 0xcd, 0x78, 0xcf, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd7, 0x03, 0xdf, 0xff, 0xe0, 0xd8, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x45, 0x03, 0x2c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x06, 0x45, 0x12, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x20, 0x03, 0x60, 0x0c, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x6e, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x09, 0xe0, 0x03, 0x45, 0x03, 0x2c, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x24, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0xbd, 0x03, 00, 0x03, 0x8c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 0x38, 0x06, 0xe0, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x87, 0xe0, 0x03, 0xdc, 0x03, 0xd5, 0x03, 0xcf, 0x03, 0xce, 0x75, 0xcf, 0x03, 0xd0, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xcd, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd4, 0x03, 0xd9, 0x03, 0xdd, 0x03, 0xe1, 0x03, 0xe4, 0x06, 0xe5, 0x09, 0xe6, 0x60, 0xe5, 0x09, 0xe6, 0x06, 0xe5, 0x03, 0xe4, 0x03, 0xe1, 0x03, 0xdd, 0x03, 0xd9, 0x03, 0xd4, 0x03, 0xcf, 0x03, 0xce, 0x03, 0xcd, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd0, 0x75, 0xcf, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd5, 0x03, 0xdc, 0xff, 0xe0, 0xdb, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xad, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 00, 0x03, 0x8c, 0x03, 0xe0, 0x03, 0x7c, 0x03, 00, 0x03, 0x60, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x20, 0x03, 0x6e, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xbd, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x52, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x0c, 0xe0, 0x03, 0x2c, 0x03, 0x45, 0x24, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x9c, 0x03, 00, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x7c, 0x03, 00, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x38, 0x06, 0xe0, 0x03, 00, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0x6e, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x06, 0x7c, 0x6f, 0xe0, 0x03, 0xdf, 0x03, 0xda, 0x03, 0xd1, 0x06, 0xce, 0x7b, 0xcf, 0x0c, 0xce, 0x03, 0xd0, 0x03, 0xd4, 0x03, 0xd7, 0x03, 0xdc, 0x03, 0xe1, 0x03, 0xe4, 0x03, 0xe6, 0x03, 0xe7, 0x0c, 0xe6, 0x4e, 0xe5, 0x0c, 0xe6, 0x03, 0xe7, 0x03, 0xe6, 0x03, 0xe4, 0x03, 0xe1, 0x03, 0xdc, 0x03, 0xd7, 0x03, 0xd4, 0x03, 0xd0, 0x0c, 0xce, 0x7b, 0xcf, 0x06, 0xce, 0x03, 0xd1, 0x03, 0xda, 0x03, 0xdf, 0xff, 0xe0, 0xdb, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x60, 0x03, 00, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x6e, 0x03, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x38, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x45, 0x03, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x20, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x20, 0x03, 0x16, 0x03, 0x52, 0x03, 0xe0, 0x03, 0x8c, 0x03, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x45, 0x03, 0x0c, 0x03, 0x7c, 0x03, 0x9c, 0x03, 00, 0x0c, 0xe0, 0x03, 0x8c, 0x03, 00, 0x03, 0x2c, 0x03, 0xad, 0x1e, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x0c, 0xe0, 0x03, 0x20, 0x03, 0x16, 0x03, 0x20, 0x03, 0x52, 0x03, 0x0c, 0x03, 0x20, 0x03, 0xe0, 0x03, 0x38, 0x06, 0x20, 0x03, 0x0c, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x0c, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x2c, 0x03, 0x0c, 0x06, 0xe0, 0x06, 0x2c, 0x72, 0xe0, 0x03, 0xdd, 0x03, 0xd7, 0x03, 0xd0, 0x06, 0xce, 0x7e, 0xcf, 0x03, 0xce, 0x06, 0xcd, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xd3, 0x03, 0xd6, 0x03, 0xda, 0x03, 0xdf, 0x03, 0xe1, 0x06, 0xe4, 0x03, 0xe6, 0x0c, 0xe7, 0x15, 0xe6, 0x12, 0xe5, 0x15, 0xe6, 0x0c, 0xe7, 0x03, 0xe6, 0x06, 0xe4, 0x03, 0xe1, 0x03, 0xdf, 0x03, 0xda, 0x03, 0xd6, 0x03, 0xd3, 0x03, 0xd0, 0x03, 0xce, 0x06, 0xcd, 0x03, 0xce, 0x7e, 0xcf, 0x06, 0xce, 0x03, 0xd0, 0x03, 0xd7, 0x03, 0xdd, 0xff, 0xe0, 0xde, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x6f, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0xbd, 0x0c, 0xe0, 0x06, 0xad, 0x12, 0xe0, 0x06, 0x9c, 0x0f, 0xe0, 0x03, 0x9c, 0x03, 0xbd, 0x06, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 0xcf, 0x15, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x36, 0xe0, 0x03, 0x9c, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0xbd, 0x03, 0xad, 0x06, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xcf, 0x0c, 0xe0, 0x06, 0xad, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0xad, 0x84, 0xe0, 0x03, 0xdc, 0x03, 0xd6, 0x03, 0xcf, 0x03, 0xcd, 0x84, 0xcf, 0x03, 0xce, 0x09, 0xcd, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xd4, 0x03, 0xd6, 0x03, 0xda, 0x03, 0xdc, 0x03, 0xe0, 0x06, 0xe4, 0x06, 0xe5, 0x3c, 0xe6, 0x06, 0xe5, 0x06, 0xe4, 0x03, 0xe0, 0x03, 0xdc, 0x03, 0xda, 0x03, 0xd6, 0x03, 0xd4, 0x03, 0xd0, 0x03, 0xce, 0x09, 0xcd, 0x03, 0xce, 0x84, 0xcf, 0x03, 0xcd, 0x03, 0xcf, 0x03, 0xd6, 0x03, 0xdc, 0xff, 0xe0, 0xe1, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xe7, 0xe0, 0x03, 0xdf, 0x03, 0xdb, 0x03, 0xd4, 0x06, 0xce, 0x87, 0xcf, 0x03, 0xce, 0x09, 0xcd, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xd1, 0x03, 0xd3, 0x03, 0xd5, 0x03, 0xd9, 0x03, 0xdb, 0x03, 0xdc, 0x03, 0xdd, 0x03, 0xe0, 0x03, 0xe1, 0x03, 0xe2, 0x06, 0xe4, 0x03, 0xe5, 0x18, 0xe6, 0x03, 0xe5, 0x06, 0xe4, 0x03, 0xe2, 0x03, 0xe1, 0x03, 0xe0, 0x03, 0xdd, 0x03, 0xdc, 0x03, 0xdb, 0x03, 0xd9, 0x03, 0xd5, 0x03, 0xd3, 0x03, 0xd1, 0x03, 0xd0, 0x03, 0xce, 0x09, 0xcd, 0x03, 0xce, 0x87, 0xcf, 0x06, 0xce, 0x03, 0xd4, 0x03, 0xdb, 0x03, 0xdf, 0xff, 0xe0, 0xe1, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xea, 0xe0, 0x03, 0xdf, 0x03, 0xda, 0x03, 0xd1, 0x06, 0xce, 0x8d, 0xcf, 0x03, 0xce, 0x03, 0xcd, 0x03, 0xce, 0x09, 0xcd, 0x03, 0xcf, 0x03, 0xd1, 0x03, 0xd4, 0x03, 0xd6, 0x03, 0xd7, 0x03, 0xd9, 0x03, 0xda, 0x06, 0xdc, 0x03, 0xdd, 0x03, 0xdf, 0x12, 0xe0, 0x03, 0xdf, 0x03, 0xdd, 0x06, 0xdc, 0x03, 0xda, 0x03, 0xd9, 0x03, 0xd7, 0x03, 0xd6, 0x03, 0xd4, 0x03, 0xd1, 0x03, 0xcf, 0x09, 0xcd, 0x03, 0xce, 0x03, 0xcd, 0x03, 0xce, 0x8d, 0xcf, 0x06, 0xce, 0x03, 0xd1, 0x03, 0xda, 0x03, 0xdf, 0xff, 0xe0, 0xe4, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xed, 0xe0, 0x03, 0xdd, 0x03, 0xd9, 0x03, 0xd1, 0x03, 0xce, 0x87, 0xcf, 0x06, 0xd0, 0x03, 0xcf, 0x06, 0xce, 0x06, 0xcd, 0x03, 0xcb, 0x06, 0xcd, 0x03, 0xce, 0x06, 0xcf, 0x0c, 0xd0, 0x06, 0xd1, 0x12, 0xd3, 0x06, 0xd1, 0x0c, 0xd0, 0x06, 0xcf, 0x03, 0xce, 0x06, 0xcd, 0x03, 0xcb, 0x06, 0xcd, 0x06, 0xce, 0x03, 0xcf, 0x06, 0xd0, 0x87, 0xcf, 0x03, 0xce, 0x03, 0xd1, 0x03, 0xd9, 0x03, 0xdd, 0xff, 0xe0, 0xe7, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xf0, 0xe0, 0x03, 0xdd, 0x03, 0xd7, 0x03, 0xd0, 0x03, 0xce, 0x93, 0xcf, 0x03, 0xd0, 0x09, 0xcf, 0x06, 0xce, 0x06, 0xcd, 0x09, 0xcb, 0x24, 0xca, 0x09, 0xcb, 0x06, 0xcd, 0x06, 0xce, 0x09, 0xcf, 0x03, 0xd0, 0x93, 0xcf, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xd7, 0x03, 0xdd, 0xff, 0xe0, 0xea, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xf0, 0xe0, 0x03, 0xdf, 0x03, 0xdc, 0x03, 0xd5, 0x03, 0xcf, 0x03, 0xce, 0xff, 0xcf, 0x87, 0xcf, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd5, 0x03, 0xdc, 0x03, 0xdf, 0xff, 0xe0, 0xea, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xf3, 0xe0, 0x03, 0xdf, 0x03, 0xdb, 0x03, 0xd5, 0x06, 0xce, 0xff, 0xcf, 0x81, 0xcf, 0x06, 0xce, 0x03, 0xd5, 0x03, 0xdb, 0x03, 0xdf, 0xff, 0xe0, 0xed, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xf6, 0xe0, 0x03, 0xdf, 0x03, 0xdb, 0x03, 0xd4, 0x03, 0xcf, 0x06, 0xce, 0xff, 0xcf, 0x75, 0xcf, 0x06, 0xce, 0x03, 0xcf, 0x03, 0xd4, 0x03, 0xdb, 0x03, 0xdf, 0xff, 0xe0, 0xf0, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xf9, 0xe0, 0x03, 0xdf, 0x03, 0xda, 0x03, 0xd4, 0x03, 0xcf, 0x03, 0xce, 0xff, 0xcf, 0x75, 0xcf, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd4, 0x03, 0xda, 0x03, 0xdf, 0xff, 0xe0, 0xf3, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xfc, 0xe0, 0x03, 0xdd, 0x03, 0xda, 0x03, 0xd4, 0x06, 0xce, 0xff, 0xcf, 0x6f, 0xcf, 0x06, 0xce, 0x03, 0xd4, 0x03, 0xda, 0x03, 0xdd, 0xff, 0xe0, 0xf6, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0x03, 0xdf, 0x03, 0xda, 0x03, 0xd3, 0x03, 0xcf, 0x03, 0xce, 0xff, 0xcf, 0x69, 0xcf, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd3, 0x03, 0xda, 0x03, 0xdf, 0xff, 0xe0, 0xf9, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0x03, 0xe0, 0x03, 0xdf, 0x03, 0xda, 0x03, 0xd4, 0x03, 0xcf, 0x06, 0xce, 0xff, 0xcf, 0x5d, 0xcf, 0x06, 0xce, 0x03, 0xcf, 0x03, 0xd4, 0x03, 0xda, 0x03, 0xdf, 0xff, 0xe0, 0xfc, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0x06, 0xe0, 0x03, 0xdd, 0x03, 0xda, 0x03, 0xd4, 0x09, 0xce, 0xff, 0xcf, 0x57, 0xcf, 0x09, 0xce, 0x03, 0xd4, 0x03, 0xda, 0x03, 0xdd, 0xff, 0xe0, 0xff, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0x09, 0xe0, 0x03, 0xdf, 0x03, 0xdb, 0x03, 0xd4, 0x03, 0xcf, 0x03, 0xcd, 0x03, 0xce, 0xff, 0xcf, 0x51, 0xcf, 0x03, 0xce, 0x03, 0xcd, 0x03, 0xcf, 0x03, 0xd4, 0x03, 0xdb, 0x03, 0xdf, 0xff, 0xe0, 0xff, 0xe0, 0x03, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0x0c, 0xe0, 0x03, 0xdf, 0x03, 0xdb, 0x03, 0xd5, 0x03, 0xd0, 0x09, 0xce, 0xff, 0xcf, 0x45, 0xcf, 0x09, 0xce, 0x03, 0xd0, 0x03, 0xd5, 0x03, 0xdb, 0x03, 0xdf, 0xff, 0xe0, 0xff, 0xe0, 0x06, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0x0f, 0xe0, 0x03, 0xdf, 0x03, 0xdc, 0x03, 0xd7, 0x03, 0xd0, 0x03, 0xcd, 0x06, 0xce, 0xff, 0xcf, 0x3f, 0xcf, 0x06, 0xce, 0x03, 0xcd, 0x03, 0xd0, 0x03, 0xd7, 0x03, 0xdc, 0x03, 0xdf, 0xff, 0xe0, 0xff, 0xe0, 0x09, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0x12, 0xe0, 0x03, 0xdf, 0x03, 0xdd, 0x03, 0xd9, 0x03, 0xd1, 0x03, 0xce, 0x03, 0xcd, 0x03, 0xce, 0xff, 0xcf, 0x39, 0xcf, 0x03, 0xce, 0x03, 0xcd, 0x03, 0xce, 0x03, 0xd1, 0x03, 0xd9, 0x03, 0xdd, 0x03, 0xdf, 0xff, 0xe0, 0xff, 0xe0, 0x0c, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0x18, 0xe0, 0x03, 0xdd, 0x03, 0xd9, 0x03, 0xd3, 0x03, 0xcf, 0x06, 0xcd, 0x03, 0xce, 0xff, 0xcf, 0x2d, 0xcf, 0x03, 0xce, 0x06, 0xcd, 0x03, 0xcf, 0x03, 0xd3, 0x03, 0xd9, 0x03, 0xdd, 0xff, 0xe0, 0xff, 0xe0, 0x12, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0x1b, 0xe0, 0x03, 0xdf, 0x03, 0xdb, 0x03, 0xd6, 0x03, 0xd0, 0x06, 0xcd, 0x03, 0xce, 0xff, 0xcf, 0x27, 0xcf, 0x03, 0xce, 0x06, 0xcd, 0x03, 0xd0, 0x03, 0xd6, 0x03, 0xdb, 0x03, 0xdf, 0xff, 0xe0, 0xff, 0xe0, 0x15, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0x21, 0xe0, 0x03, 0xdc, 0x03, 0xd7, 0x03, 0xd1, 0x03, 0xcf, 0x09, 0xce, 0xff, 0xcf, 0x1b, 0xcf, 0x09, 0xce, 0x03, 0xcf, 0x03, 0xd1, 0x03, 0xd7, 0x03, 0xdc, 0xff, 0xe0, 0xff, 0xe0, 0x1b, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xb7, 0xe0, 0x06, 0x52, 0x03, 0xbd, 0x5d, 0xe0, 0x03, 0x6e, 0x03, 0xad, 0x21, 0xe0, 0x03, 0x9c, 0x03, 0xad, 0x12, 0xe0, 0x03, 0xcf, 0x21, 0x9c, 0x03, 0xcf, 0x09, 0xe0, 0x03, 0x7c, 0x03, 0xad, 0x1b, 0xe0, 0x03, 0xcf, 0x06, 0x9c, 0x03, 0x60, 0x03, 0x38, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x6e, 0x1e, 0xe0, 0x03, 0x60, 0x39, 0xe0, 0x03, 0xdd, 0x03, 0xda, 0x03, 0xd5, 0x03, 0x40, 0x03, 0x72, 0x06, 0xce, 0x0f, 0xcf, 0x03, 0xbe, 0x21, 0x91, 0x0f, 0xcf, 0x03, 0x91, 0x03, 0xbe, 0x0c, 0xcf, 0x03, 0xbe, 0x03, 0x66, 0x0f, 0xcf, 0x06, 0x91, 0x1e, 0xcf, 0x06, 0xaf, 0x2a, 0xcf, 0x03, 0x74, 0x03, 0xaf, 0x24, 0xcf, 0x03, 0x59, 0x2a, 0xcf, 0x06, 0xce, 0x03, 0xcd, 0x03, 0xcf, 0x03, 0xd5, 0x03, 0xda, 0x03, 0xdd, 0x7e, 0xe0, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x8c, 0x03, 0x9c, 0x03, 0x38, 0x12, 0xe0, 0x03, 0x6e, 0x03, 0xad, 0x48, 0xe0, 0x03, 0x9c, 0x03, 0xad, 0x15, 0xe0, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x7c, 0x06, 0xad, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x52, 0x03, 0xcf, 0x0f, 0xe0, 0x03, 0xcf, 0x03, 0x7c, 0x03, 0x38, 0x09, 0xe0, 0x03, 0x52, 0x0f, 0xe0, 0x03, 0xad, 0x09, 0x9c, 0x03, 0xad, 0x03, 0xe0, 0x0c, 0x9c, 0x03, 0xad, 0x09, 0xe0, 0x03, 0x7c, 0x03, 0xad, 0x03, 0xe0, 0x12, 0x9c, 0x03, 0xad, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0xcf, 0x69, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x78, 0xe0, 0x03, 0xcf, 0x24, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x0f, 0xe0, 0x03, 0x9c, 0x03, 0x7c, 0x03, 0xbd, 0x03, 0x60, 0x5a, 0xe0, 0x03, 0xcf, 0x03, 0x16, 0x03, 0xcf, 0x21, 0xe0, 0x03, 0x20, 0x03, 0xbd, 0x06, 0xe0, 0x03, 0xcf, 0x09, 0xe0, 0x03, 0xbd, 0x0f, 0x60, 0x03, 0x16, 0x0f, 0x60, 0x03, 0xbd, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0xad, 0x09, 0x2c, 0x03, 0x20, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x6e, 0x03, 0x60, 0x06, 0x45, 0x09, 0xe0, 0x03, 0x9c, 0x03, 0x60, 0x1e, 0xe0, 0x03, 00, 0x18, 0xe0, 0x03, 0x52, 0x03, 0x38, 0x09, 0x2c, 0x03, 0x20, 0x03, 0xad, 0x0f, 0xe0, 0x03, 0xdf, 0x03, 0xdc, 0x03, 0xb6, 0x03, 0x41, 0x03, 0x15, 0x03, 0x8f, 0x03, 0xce, 0x03, 0x66, 0x03, 0x9f, 0x06, 0xcf, 0x03, 0xaf, 0x09, 0x59, 0x03, 0x40, 0x03, 0x29, 0x03, 0x59, 0x03, 0x29, 0x03, 0x40, 0x09, 0x59, 0x0f, 0xcf, 0x03, 00, 0x0c, 0xcf, 0x03, 0x9f, 0x03, 0x40, 0x03, 0x4c, 0x03, 0x82, 0x0c, 0xcf, 0x06, 0x59, 0x06, 0xcf, 0x03, 0xbe, 0x03, 0x91, 0x03, 0xaf, 0x0f, 0xcf, 0x03, 0x4c, 0x03, 0x82, 0x03, 0xcf, 0x03, 0x74, 0x03, 0x59, 0x03, 0x91, 0x1e, 0xcf, 0x03, 0x29, 0x03, 0x91, 0x24, 0xcf, 0x03, 00, 0x24, 0xcf, 0x06, 0xce, 0x03, 0xcd, 0x03, 0xce, 0x03, 0xd1, 0x03, 0xd7, 0x03, 0xdc, 0x03, 0xdf, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0xbd, 0x03, 0xad, 0x03, 0x9c, 0x03, 0x45, 0x03, 0x38, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xad, 0x18, 0x9c, 0x03, 0xcf, 0x3c, 0xe0, 0x03, 00, 0x06, 0xe0, 0x03, 0xad, 0x03, 0x2c, 0x03, 0x60, 0x03, 0x9c, 0x0c, 0xe0, 0x03, 0xcf, 0x03, 0x16, 0x03, 0xcf, 0x18, 0xe0, 0x03, 0xcf, 0x2d, 0xe0, 0x03, 0x20, 0x03, 0xbd, 0x06, 0xe0, 0x03, 0xcf, 0x0c, 0xe0, 0x03, 0x7c, 0x06, 0x60, 0x03, 0x9c, 0x03, 0x38, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x20, 0x0c, 0xe0, 0x03, 0xcf, 0x03, 0x38, 0x03, 0x20, 0x03, 0x45, 0x03, 0xcf, 0x09, 0xe0, 0x03, 0x2c, 0x0f, 0xe0, 0x03, 0x2c, 0x09, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x16, 0x09, 0x60, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x16, 0x06, 0x60, 0x03, 0x16, 0x06, 0x60, 0x03, 0x2c, 0x0c, 0xe0, 0x03, 0x20, 0x03, 0x9c, 0x69, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x51, 0xe0, 0x03, 0x2c, 0x15, 00, 0x03, 0x2c, 0x0c, 0xe0, 0x03, 0x38, 0x03, 0x45, 0x03, 0xcf, 0x1e, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x0f, 0xe0, 0x03, 0xbd, 0x06, 0x52, 0x03, 0xbd, 0x5a, 0xe0, 0x03, 0x52, 0x09, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x16, 0x09, 0xe0, 0x03, 0xad, 0x09, 0x2c, 0x03, 0x0c, 0x06, 0x2c, 0x03, 0x20, 0x03, 0x2c, 0x03, 0xad, 0x18, 0xe0, 0x03, 0x2c, 0x15, 0xe0, 0x03, 0x52, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x20, 0x03, 0x2c, 0x03, 0xad, 0x09, 0xe0, 0x03, 0x9c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xad, 0x06, 0x2c, 0x03, 0x20, 0x03, 0x16, 0x06, 0x2c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 0x60, 0x0c, 0xe0, 0x03, 0x7c, 0x09, 0x60, 0x03, 0x38, 0x03, 0x2c, 0x03, 00, 0x09, 0x2c, 0x03, 0x52, 0x0c, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xad, 0x03, 0xe0, 0x06, 0x45, 0x18, 0xe0, 0x03, 0xdd, 0x03, 0xda, 0x03, 0xb3, 0x03, 0x29, 0x03, 0xbd, 0x03, 0x1e, 0x03, 0xbe, 0x09, 0xcf, 0x03, 0xbe, 0x06, 0x91, 0x03, 0x66, 0x03, 0x40, 0x03, 0x91, 0x03, 0x40, 0x03, 0x66, 0x06, 0x91, 0x0f, 0xcf, 0x03, 0xbe, 0x03, 0x1f, 0x0c, 0xcf, 0x03, 0xbe, 0x03, 0x59, 0x03, 0x74, 0x03, 0x91, 0x03, 0xcf, 0x03, 0x91, 0x06, 0x29, 0x03, 0x15, 0x03, 0x1f, 0x03, 0x29, 0x03, 0x1f, 0x03, 0x29, 0x03, 0x59, 0x03, 0xaf, 0x0f, 0xcf, 0x03, 0x29, 0x03, 0x9f, 0x03, 0x29, 0x03, 0x59, 0x03, 0x91, 0x03, 0x1f, 0x03, 0x74, 0x0c, 0xcf, 0x03, 0x9f, 0x03, 0x34, 0x09, 0x59, 0x03, 0x15, 0x03, 0x40, 0x03, 0x34, 0x03, 0x29, 0x03, 0x1f, 0x09, 0xcf, 0x03, 0x74, 0x09, 0x59, 0x03, 0x34, 0x03, 0x29, 0x03, 00, 0x09, 0x29, 0x03, 0x4c, 0x18, 0xcf, 0x06, 0xcd, 0x03, 0xcf, 0x03, 0xd4, 0x03, 0xda, 0x03, 0xdd, 0x09, 0xe0, 0x03, 0x9c, 0x03, 0x20, 0x06, 0xe0, 0x03, 0x9c, 0x03, 0x38, 0x03, 0x6e, 0x03, 0xad, 0x03, 0x6e, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x45, 0x12, 0x60, 0x03, 0x16, 0x03, 0x8c, 0x3c, 0xe0, 0x03, 00, 0x09, 0xe0, 0x03, 0x8c, 0x12, 0xe0, 0x03, 0x52, 0x09, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x16, 0x0c, 0xe0, 0x03, 0x38, 0x03, 0x45, 0x03, 0xcf, 0x1b, 0xe0, 0x03, 0xad, 0x09, 0x2c, 0x03, 0x0c, 0x06, 0x2c, 0x03, 0x20, 0x03, 0x2c, 0x03, 0xad, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0x60, 0x03, 0x45, 0x06, 0x60, 0x03, 0xad, 0x03, 0x8c, 0x03, 0x38, 0x09, 0x9c, 0x03, 0xbd, 0x06, 0xe0, 0x03, 0x9c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x45, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x2c, 0x09, 0xe0, 0x0f, 0x2c, 0x03, 0xe0, 0x03, 0x0c, 0x0c, 0x2c, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0x45, 0x03, 0x6e, 0x03, 0xbd, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x0c, 0xe0, 0x03, 0x0c, 0x03, 0xcf, 0x69, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x66, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x0f, 0xe0, 0x03, 0x45, 0x03, 0x20, 0x03, 0xad, 0x0c, 0xe0, 0x03, 0x8c, 0x03, 0x7c, 0x09, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0xcf, 0x03, 0x60, 0x03, 0x0c, 0x03, 0x9c, 0x5d, 0xe0, 0x03, 0x9c, 0x03, 0x20, 0x03, 0xcf, 0x09, 0xe0, 0x03, 0x6e, 0x03, 0x45, 0x12, 0xe0, 0x03, 0x20, 0x03, 0xbd, 0x1b, 0xe0, 0x03, 0x0c, 0x09, 0x2c, 0x03, 0x0c, 0x09, 0x2c, 0x03, 0x0c, 0x0f, 0xe0, 0x03, 0x60, 0x03, 0x9c, 0x0f, 0xe0, 0x03, 0x9c, 0x03, 0x60, 0x06, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0x6e, 0x03, 0x45, 0x03, 0x9c, 0x03, 0xad, 0x03, 0x52, 0x03, 0x20, 0x03, 0x16, 0x03, 0x2c, 0x03, 00, 0x06, 0xe0, 0x0f, 0x9c, 0x03, 0xbd, 0x03, 00, 0x09, 0xe0, 0x03, 0xcf, 0x15, 0xe0, 0x03, 0x45, 0x03, 0x52, 0x1b, 0xe0, 0x03, 0x2c, 0x03, 0xdd, 0x03, 0xdb, 0x03, 0xd7, 0x03, 0x68, 0x03, 0x59, 0x03, 0xcb, 0x03, 0xcd, 0x03, 0xce, 0x03, 0xcf, 0x03, 0x91, 0x03, 0x29, 0x03, 0x59, 0x03, 0x40, 0x03, 0x29, 0x03, 0x59, 0x03, 0x29, 0x03, 0x40, 0x03, 0x59, 0x03, 0x15, 0x09, 0xcf, 0x03, 0xbe, 0x03, 0x91, 0x03, 0x59, 0x03, 0x15, 0x03, 0x59, 0x03, 0x74, 0x03, 0xcf, 0x03, 0xbe, 0x03, 0x15, 0x03, 0x91, 0x12, 0xcf, 0x03, 0x59, 0x03, 0x91, 0x06, 0xcf, 0x03, 0x4c, 0x15, 0xcf, 0x03, 0x29, 0x03, 0x59, 0x03, 0x74, 0x06, 0xcf, 0x03, 0xaf, 0x03, 0x15, 0x0f, 0xcf, 0x03, 0x9f, 0x09, 0x91, 0x03, 0x1f, 0x03, 0x66, 0x03, 0xaf, 0x0f, 0xcf, 0x0f, 0x91, 0x03, 0xaf, 0x03, 00, 0x09, 0xcf, 0x03, 0xbe, 0x0f, 0xcf, 0x03, 0xce, 0x03, 0xcd, 0x03, 0xcb, 0x03, 0xce, 0x03, 0xd3, 0x03, 0xd7, 0x03, 0xdb, 0x03, 0xdd, 0x0c, 0xe0, 0x03, 0x8c, 0x03, 0x45, 0x09, 0xe0, 0x03, 0x16, 0x03, 0xcf, 0x03, 0x6e, 0x03, 0x7c, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x9c, 0x12, 0xe0, 0x03, 00, 0x03, 0xcf, 0x2d, 0xe0, 0x03, 0x52, 0x0c, 0x2c, 0x03, 00, 0x0c, 0x2c, 0x03, 0x52, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0x20, 0x03, 0xcf, 0x09, 0xe0, 0x03, 0x6e, 0x03, 0x45, 0x0f, 0xe0, 0x03, 0x45, 0x03, 0x20, 0x03, 0xad, 0x0c, 0xe0, 0x03, 0x8c, 0x03, 0x7c, 0x0f, 0xe0, 0x03, 0x20, 0x03, 0xbd, 0x15, 0xe0, 0x03, 0xbd, 0x03, 0x60, 0x03, 0x52, 0x03, 00, 0x03, 0x0c, 0x03, 0x60, 0x03, 0x7c, 0x03, 0x45, 0x03, 0x52, 0x03, 0x60, 0x03, 0x2c, 0x03, 0x45, 0x03, 0x9c, 0x03, 0xbd, 0x03, 0x60, 0x03, 0x45, 0x03, 0x2c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x20, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x45, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xbd, 0x03, 0x60, 0x03, 0x2c, 0x03, 0x45, 0x03, 0x9c, 0x03, 0x20, 0x06, 0x9c, 0x03, 0x20, 0x06, 0x9c, 0x03, 0x2c, 0x0c, 0xe0, 0x03, 00, 0x6c, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x66, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0x7c, 0x03, 0x52, 0x0c, 0xe0, 0x03, 0x2c, 0x03, 0x7c, 0x09, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x03, 0xcf, 0x03, 0x8c, 0x03, 0x45, 0x03, 0x16, 0x03, 0x60, 0x03, 0xcf, 0x5d, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x06, 0xad, 0x09, 0xe0, 0x03, 0x16, 0x03, 0xad, 0x0f, 0xe0, 0x03, 0x60, 0x03, 0x52, 0x03, 0x6e, 0x03, 0x60, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x0c, 0xe0, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0xbd, 0x06, 0x60, 0x03, 0x2c, 0x03, 0x45, 0x03, 0x60, 0x03, 0x9c, 0x09, 0x2c, 0x03, 0x20, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0x45, 0x03, 0x2c, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 0x60, 0x03, 0xe0, 0x03, 00, 0x0f, 0xe0, 0x03, 0x7c, 0x03, 0x2c, 0x03, 0x60, 0x03, 00, 0x1b, 0xe0, 0x03, 0xcf, 0x03, 0x2c, 0x03, 0x7c, 0x18, 0xe0, 0x03, 0x6e, 0x03, 0xe0, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0xbb, 0x03, 0x1f, 0x03, 0xb4, 0x03, 0x92, 0x03, 0xce, 0x06, 0xcd, 0x03, 0x8f, 0x03, 0x59, 0x03, 0xcf, 0x03, 0x91, 0x03, 0x59, 0x03, 0xcf, 0x03, 0x59, 0x03, 0x91, 0x03, 0xcf, 0x03, 0x29, 0x06, 0xcf, 0x03, 0xbe, 0x03, 0x29, 0x03, 0x59, 0x03, 0x29, 0x03, 0x4c, 0x03, 0x91, 0x03, 0x4c, 0x03, 0x40, 0x03, 0xcf, 0x03, 0x9f, 0x03, 0x1f, 0x12, 0xcf, 0x03, 0x59, 0x03, 0x66, 0x06, 0x59, 0x03, 0x1f, 0x15, 0xcf, 0x03, 0x0c, 0x03, 0x40, 0x0c, 0xcf, 0x03, 0x1f, 0x03, 0x9f, 0x0c, 0xcf, 0x03, 0xaf, 0x09, 0xcf, 0x03, 0x29, 0x09, 0x91, 0x03, 0x74, 0x12, 0xcf, 0x03, 0x74, 0x03, 0x29, 0x03, 0x59, 0x03, 00, 0x12, 0xcf, 0x03, 0xce, 0x09, 0xcd, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xd5, 0x03, 0xda, 0x03, 0xdd, 0x12, 0xe0, 0x03, 0x52, 0x03, 0x6e, 0x09, 0xe0, 0x03, 0x20, 0x03, 0xbd, 0x0f, 0xe0, 0x03, 0x2c, 0x03, 0x9c, 0x0f, 0xe0, 0x03, 0xbd, 0x03, 0x0c, 0x3f, 0xe0, 0x03, 00, 0x18, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x06, 0xad, 0x09, 0xe0, 0x03, 0x16, 0x03, 0xad, 0x12, 0xe0, 0x03, 0x7c, 0x03, 0x52, 0x0c, 0xe0, 0x03, 0x2c, 0x03, 0x7c, 0x0c, 0xe0, 0x03, 0x60, 0x03, 0x52, 0x03, 0x6e, 0x03, 0x60, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x09, 0xe0, 0x03, 0xcf, 0x03, 0x2c, 0x03, 0x45, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xad, 0x03, 00, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0x45, 0x03, 0x2c, 0x03, 0x9c, 0x03, 0xad, 0x03, 0x45, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 0x45, 0x06, 0xe0, 0x0c, 0x2c, 0x03, 0x52, 0x03, 0xe0, 0x0f, 0x2c, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x16, 0x06, 0x60, 0x03, 0x16, 0x06, 0x60, 0x03, 0x2c, 0x0c, 0xe0, 0x03, 00, 0x6c, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x66, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x21, 0xe0, 0x03, 0x8c, 0x03, 0x20, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x45, 0x03, 0x8c, 0x1b, 0xe0, 0x03, 0x52, 0x0c, 0x2c, 0x03, 0x20, 0x0f, 0xe0, 0x03, 0x7c, 0x1b, 0x60, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 0x16, 0x06, 0xad, 0x03, 0x16, 0x03, 0x52, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x2c, 0x0f, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0x38, 0x03, 0x8c, 0x03, 0x7c, 0x03, 0x38, 0x03, 0x8c, 0x03, 0x45, 0x03, 0x16, 0x03, 0x9c, 0x09, 0xe0, 0x03, 0x0c, 0x09, 0x2c, 0x03, 0x0c, 0x09, 0x2c, 0x03, 0x0c, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0x9c, 0x03, 0x45, 0x03, 0x6e, 0x03, 0x9c, 0x03, 0xbd, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x03, 0x45, 0x03, 0x2c, 0x03, 0x60, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x6e, 0x03, 0xe0, 0x03, 0x16, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0x45, 0x03, 0xe0, 0x03, 0x9c, 0x03, 00, 0x18, 0xe0, 0x03, 0xcf, 0x03, 0x2c, 0x03, 0x38, 0x03, 0x45, 0x03, 0x2c, 0x03, 0x38, 0x03, 0x7c, 0x0c, 0xe0, 0x03, 0xad, 0x03, 0x38, 0x03, 0xe0, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x9c, 0x03, 0xcb, 0x03, 0x1f, 0x03, 0xc4, 0x03, 0xd0, 0x03, 0xcd, 0x03, 0x8f, 0x03, 0x15, 0x03, 0x29, 0x03, 0x1f, 0x03, 0x15, 0x03, 0x29, 0x03, 0x15, 0x03, 0x1f, 0x03, 0x29, 0x03, 0x0c, 0x0f, 0xcf, 0x03, 0x29, 0x03, 0xaf, 0x06, 0xcf, 0x03, 00, 0x06, 0xcf, 0x03, 0x40, 0x03, 0x74, 0x0c, 0xcf, 0x03, 0x59, 0x03, 0x0c, 0x03, 0x40, 0x03, 0x91, 0x03, 0x34, 0x03, 0x40, 0x03, 0x1f, 0x03, 0x74, 0x0f, 0xcf, 0x03, 0x0c, 0x03, 0x82, 0x0c, 0xcf, 0x03, 0x29, 0x03, 0x91, 0x0c, 0xcf, 0x03, 0x34, 0x09, 0x29, 0x03, 0x15, 0x03, 0x1f, 0x06, 0x59, 0x03, 0x91, 0x0f, 0xcf, 0x03, 0x91, 0x03, 0x40, 0x03, 0xcf, 0x03, 0x91, 0x03, 00, 0x0f, 0xcf, 0x03, 0xce, 0x09, 0xcd, 0x03, 0xd0, 0x03, 0xd5, 0x03, 0xd9, 0x03, 0xdc, 0x03, 0xdf, 0x15, 0xe0, 0x03, 0x20, 0x03, 0xad, 0x09, 0xe0, 0x03, 0x52, 0x03, 0x6e, 0x0f, 0xe0, 0x03, 0x52, 0x03, 0xad, 0x0f, 0xe0, 0x03, 0x7c, 0x03, 0x38, 0x09, 0xe0, 0x03, 0x7c, 0x1b, 0x60, 0x03, 0x7c, 0x0c, 0xe0, 0x03, 0x16, 0x03, 0xcf, 0x03, 0xe0, 0x03, 00, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x16, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0x16, 0x06, 0xad, 0x03, 0x16, 0x03, 0x52, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x2c, 0x24, 0xe0, 0x03, 0x8c, 0x03, 0x20, 0x0c, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0x38, 0x03, 0x8c, 0x03, 0x7c, 0x03, 0x38, 0x03, 0x8c, 0x03, 0x45, 0x03, 0x16, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x03, 0xad, 0x03, 0x7c, 0x06, 0xad, 0x03, 0x2c, 0x03, 0x60, 0x03, 0x6e, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0xcf, 0x09, 0xe0, 0x03, 0x20, 0x03, 0x0c, 0x03, 0xbd, 0x03, 0x52, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x2c, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x2c, 0x06, 0xe0, 0x0f, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x8c, 0x03, 0xad, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x0c, 0xe0, 0x03, 00, 0x6c, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x66, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x1e, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x03, 0xad, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x30, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x0f, 0xe0, 0x03, 0x7c, 0x1b, 0x60, 0x03, 0x7c, 0x09, 0xe0, 0x03, 0xbd, 0x09, 0xe0, 0x03, 0x45, 0x03, 0x20, 0x03, 0x16, 0x03, 0xad, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0x16, 0x03, 0x8c, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x6e, 0x03, 00, 0x03, 0x52, 0x03, 0xad, 0x0f, 0xe0, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x8c, 0x03, 0x60, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x2c, 0x0c, 0xe0, 0x03, 0x60, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0xcf, 0x03, 00, 0x03, 0xad, 0x12, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x7c, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0xbd, 0x03, 0x45, 0x03, 0x2c, 0x09, 0xe0, 0x06, 0x6e, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x52, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x7c, 0x03, 0x5f, 0x03, 0xd9, 0x03, 0xd4, 0x03, 0xd0, 0x03, 0xce, 0x06, 0xcd, 0x03, 0x29, 0x03, 0xae, 0x18, 0xcf, 0x03, 0xbe, 0x03, 0x15, 0x09, 0xcf, 0x03, 00, 0x06, 0xcf, 0x03, 0xaf, 0x03, 0x15, 0x09, 0xcf, 0x03, 0x40, 0x03, 0x66, 0x03, 0x59, 0x03, 0x91, 0x03, 0xbe, 0x03, 0x1f, 0x03, 0xcf, 0x03, 0xbe, 0x03, 0x15, 0x03, 0x9f, 0x0c, 0xcf, 0x03, 00, 0x03, 0xbe, 0x0c, 0xcf, 0x03, 0x1f, 0x03, 0x91, 0x18, 0xcf, 0x03, 0x59, 0x03, 0x91, 0x18, 0xcf, 0x03, 0x59, 0x03, 0x91, 0x03, 0xcf, 0x03, 0xbe, 0x03, 00, 0x03, 0x9f, 0x03, 0xcf, 0x03, 0xce, 0x09, 0xcd, 0x03, 0xce, 0x03, 0xd0, 0x03, 0xd4, 0x03, 0xd9, 0x03, 0xdc, 0x03, 0xdf, 0x18, 0xe0, 0x03, 0xbd, 0x03, 0x16, 0x0c, 0xe0, 0x03, 0xad, 0x03, 0x20, 0x24, 0xe0, 0x03, 0x2c, 0x03, 0x9c, 0x09, 0xe0, 0x03, 0x7c, 0x1b, 0x60, 0x03, 0x7c, 0x09, 0xe0, 0x03, 0xad, 0x03, 0x20, 0x06, 0xe0, 0x03, 00, 0x06, 0xe0, 0x03, 0x38, 0x03, 0x9c, 0x0c, 0xe0, 0x03, 0xbd, 0x09, 0xe0, 0x03, 0x45, 0x03, 0x20, 0x03, 0x16, 0x03, 0xad, 0x21, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x03, 0xad, 0x09, 0xe0, 0x03, 0x9c, 0x03, 0x16, 0x03, 0x8c, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x6e, 0x03, 00, 0x03, 0x52, 0x03, 0xad, 0x0c, 0xe0, 0x06, 0xcf, 0x03, 0x20, 0x06, 0xe0, 0x03, 0xad, 0x03, 0xcf, 0x03, 0x38, 0x03, 0xcf, 0x03, 0x16, 0x09, 0xe0, 0x03, 0x9c, 0x03, 0x45, 0x03, 0x52, 0x03, 0x2c, 0x03, 0x38, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x38, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x16, 0x09, 0x60, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0xbd, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x9c, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x0c, 0xe0, 0x03, 00, 0x12, 0xe0, 0x03, 0x45, 0x03, 0xbd, 0x54, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x66, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x1b, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0x03, 0x7c, 0x0f, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x30, 0xe0, 0x03, 0x8c, 0x03, 0x60, 0x48, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x0f, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x20, 0x03, 0x6e, 0x03, 0x20, 0x0f, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0x20, 0x09, 0x9c, 0x03, 0x20, 0x09, 0x9c, 0x03, 0x20, 0x03, 0x9c, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x9c, 0x03, 0x60, 0x03, 0x20, 0x03, 0x2c, 0x03, 0x7c, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x52, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x16, 0x03, 0x2c, 0x03, 0x52, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x2c, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x03, 0x9c, 0x03, 0x45, 0x03, 0x16, 0x03, 0x9c, 0x0f, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x9c, 0x12, 0xe0, 0x03, 0x20, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x20, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0x7c, 0x03, 0x45, 0x09, 0xe0, 0x03, 0xcf, 0x03, 0x16, 0x03, 0xdf, 0x03, 0xa9, 0x06, 0x2a, 0x03, 0x29, 0x03, 00, 0x09, 0x29, 0x03, 0x0c, 0x09, 0x29, 0x09, 0xcf, 0x06, 0x59, 0x09, 0xcf, 0x03, 0x0c, 0x09, 0xcf, 0x03, 0x66, 0x03, 0xbe, 0x03, 0xcf, 0x03, 0x9f, 0x03, 0x34, 0x03, 0xcf, 0x03, 0x59, 0x03, 0x91, 0x03, 0x40, 0x03, 0x82, 0x06, 0xcf, 0x06, 0x59, 0x0c, 0xcf, 0x03, 0x29, 0x0c, 0xcf, 0x03, 0xbe, 0x03, 0x0c, 0x12, 0xcf, 0x03, 0x9f, 0x06, 0x59, 0x03, 0x29, 0x03, 0x74, 0x18, 0xcf, 0x03, 0x91, 0x03, 0x29, 0x03, 0x91, 0x03, 0x40, 0x03, 0x15, 0x03, 0x90, 0x03, 0xcd, 0x03, 0xce, 0x03, 0xcd, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd4, 0x03, 0xd9, 0x03, 0xdc, 0x03, 0xdf, 0x1e, 0xe0, 0x03, 0x45, 0x03, 0x60, 0x0f, 0xe0, 0x03, 0x2c, 0x03, 0x9c, 0x1e, 0xe0, 0x03, 0x6e, 0x03, 0x2c, 0x36, 0xe0, 0x03, 0x45, 0x03, 0x6e, 0x06, 0xe0, 0x03, 00, 0x06, 0xe0, 0x03, 0x8c, 0x03, 0x45, 0x1b, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x21, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0x03, 0x7c, 0x0c, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x20, 0x03, 0x6e, 0x03, 0x20, 0x0f, 0xe0, 0x03, 0xad, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x20, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x38, 0x06, 0x60, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 0x8c, 0x03, 0x60, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x9c, 0x06, 0x2c, 0x03, 0x9c, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x16, 0x09, 0x60, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x9c, 0x06, 0x38, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x0c, 0x06, 0x2c, 0x03, 0x0c, 0x09, 0x2c, 0x0c, 0xe0, 0x03, 00, 0x0f, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x57, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x66, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x15, 0xe0, 0x03, 0xbd, 0x03, 0x45, 0x03, 0x0c, 0x03, 0xad, 0x12, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x30, 0xe0, 0x03, 0x60, 0x03, 0x6e, 0x45, 0xe0, 0x06, 0x45, 0x18, 0xe0, 0x03, 0xcf, 0x03, 0x16, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x2c, 0x0f, 0xe0, 0x03, 0x9c, 0x03, 0x60, 0x03, 0x16, 0x15, 0x60, 0x03, 0x16, 0x03, 0x60, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x45, 0x03, 0x52, 0x03, 0x60, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x20, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0xbd, 0x03, 0xe0, 0x06, 0x9c, 0x03, 0x6e, 0x03, 0x45, 0x03, 0x9c, 0x03, 0xad, 0x03, 0xcf, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x2c, 0x0f, 0xe0, 0x03, 0x9c, 0x03, 0x60, 0x03, 0x9c, 0x03, 0x16, 0x03, 0xcf, 0x12, 0xe0, 0x03, 0xbd, 0x03, 0xe0, 0x06, 0x2c, 0x03, 0x38, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x20, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x0c, 0x03, 0x45, 0x09, 0xe0, 0x03, 0x38, 0x03, 0xe0, 0x03, 0x45, 0x03, 0x8c, 0x03, 0xe0, 0x03, 0xdf, 0x03, 0xdc, 0x03, 0x42, 0x03, 0x69, 0x03, 0xd3, 0x03, 0xcf, 0x03, 0x9e, 0x03, 0x29, 0x03, 0xcd, 0x03, 0xce, 0x0c, 0xcf, 0x03, 0x15, 0x03, 0xaf, 0x06, 0xcf, 0x03, 0x91, 0x03, 0x29, 0x12, 0xcf, 0x03, 0x59, 0x03, 0x91, 0x03, 0xcf, 0x03, 0x59, 0x06, 0x40, 0x09, 0xcf, 0x03, 0x34, 0x03, 0x74, 0x1b, 0xcf, 0x03, 0x4c, 0x03, 0x40, 0x0f, 0xcf, 0x03, 0x40, 0x03, 0x34, 0x03, 0x82, 0x03, 0x91, 0x03, 0x34, 0x03, 0x29, 0x03, 0x1f, 0x03, 0x91, 0x15, 0xcf, 0x03, 0x91, 0x03, 0x59, 0x03, 0x90, 0x03, 0x15, 0x03, 0xbd, 0x03, 0xcd, 0x03, 0xcf, 0x03, 0xd3, 0x03, 0xd5, 0x03, 0xd9, 0x03, 0x51, 0x03, 0x20, 0x03, 0x2c, 0x03, 0xcf, 0x1b, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x03, 0xcf, 0x0f, 0xe0, 0x03, 0x9c, 0x03, 0x16, 0x03, 0xcf, 0x18, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0xbd, 0x33, 0xe0, 0x03, 0xbd, 0x03, 0x0c, 0x03, 0xcf, 0x06, 0xe0, 0x03, 00, 0x09, 0xe0, 0x03, 0x16, 0x03, 0xad, 0x15, 0xe0, 0x06, 0x45, 0x1e, 0xe0, 0x03, 0xbd, 0x03, 0x45, 0x03, 0x0c, 0x03, 0xad, 0x15, 0xe0, 0x03, 0xcf, 0x03, 0x16, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0xcf, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x6e, 0x06, 0xe0, 0x03, 0x8c, 0x03, 00, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x6e, 0x03, 0x8c, 0x03, 0x9c, 0x03, 0x60, 0x0c, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 0xad, 0x09, 0xe0, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x20, 0x09, 0x9c, 0x03, 0x20, 0x06, 0xe0, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x7c, 0x0c, 0xe0, 0x03, 00, 0x03, 0xcf, 0x0c, 0xe0, 0x03, 0x52, 0x03, 0x60, 0x57, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x51, 0xe0, 0x03, 0x2c, 0x15, 00, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0x7c, 0x03, 0x38, 0x03, 0x0c, 0x03, 0x60, 0x03, 0xcf, 0x15, 0xe0, 0x03, 0xbd, 0x03, 0x0c, 0x03, 0xad, 0x09, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0x8c, 0x1b, 0xe0, 0x03, 0x38, 0x03, 0x9c, 0x3f, 0xe0, 0x03, 0xbd, 0x03, 0x2c, 0x03, 0x45, 0x1b, 0xe0, 0x03, 0x9c, 0x03, 0x20, 0x06, 0xe0, 0x03, 0xad, 0x15, 0xe0, 0x03, 0x2c, 0x15, 0xe0, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x20, 0x03, 0x60, 0x03, 0x20, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x52, 0x09, 0x2c, 0x03, 0x60, 0x06, 0xe0, 0x06, 0x60, 0x03, 0x45, 0x03, 0x2c, 0x03, 0x60, 0x06, 0x7c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x9c, 0x03, 0x38, 0x15, 0xe0, 0x03, 0x45, 0x03, 0x60, 0x18, 0xe0, 0x03, 0x9c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x20, 0x03, 0xe0, 0x03, 0x6e, 0x03, 0x20, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0xad, 0x03, 0xbd, 0x03, 0x2c, 0x03, 0x20, 0x0c, 0xe0, 0x03, 0x0c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 0xad, 0x06, 0xe0, 0x03, 0xbd, 0x03, 0x7c, 0x03, 0x44, 0x03, 0x2a, 0x03, 0x4e, 0x03, 0x15, 0x03, 0xbe, 0x0f, 0xce, 0x03, 0x73, 0x03, 0x40, 0x06, 0xbe, 0x03, 0xcf, 0x06, 0x4c, 0x12, 0xcf, 0x06, 0x66, 0x03, 0xbe, 0x03, 0x34, 0x03, 0x40, 0x09, 0xcf, 0x03, 0x66, 0x03, 0x1f, 0x1b, 0xcf, 0x03, 0x66, 0x03, 0x1f, 0x03, 0xbe, 0x0f, 0xcf, 0x03, 00, 0x09, 0xcf, 0x03, 0x4c, 0x03, 0x91, 0x03, 0x9f, 0x03, 0x29, 0x03, 0x34, 0x03, 0xbe, 0x09, 0xcf, 0x0c, 0xce, 0x03, 0x40, 0x03, 0x59, 0x03, 0xcf, 0x03, 0xd0, 0x03, 0xd5, 0x03, 0xda, 0x03, 0xdd, 0x03, 0xad, 0x03, 0x45, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x6e, 0x18, 0xe0, 0x03, 0xbd, 0x03, 0x16, 0x03, 0x8c, 0x15, 0xe0, 0x03, 0x45, 0x03, 0x38, 0x03, 0xcf, 0x0f, 0xe0, 0x03, 0xbd, 0x03, 0x45, 0x03, 0x16, 0x03, 0xad, 0x33, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 0x8c, 0x09, 0xe0, 0x03, 00, 0x09, 0xe0, 0x03, 0x9c, 0x03, 0x20, 0x03, 0xcf, 0x0c, 0xe0, 0x03, 0xbd, 0x03, 0x2c, 0x03, 0x45, 0x15, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0x7c, 0x03, 0x38, 0x03, 0x0c, 0x03, 0x60, 0x03, 0xcf, 0x18, 0xe0, 0x03, 0x9c, 0x03, 0x20, 0x06, 0xe0, 0x03, 0xad, 0x12, 0xe0, 0x03, 0xbd, 0x03, 0x52, 0x03, 0x2c, 0x03, 0x16, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x38, 0x03, 0x2c, 0x03, 0x6e, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x9c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0xbd, 0x03, 0x20, 0x03, 0x7c, 0x0c, 0xe0, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x16, 0x09, 0x60, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x9c, 0x0c, 0xe0, 0x03, 0x2c, 0x15, 0xe0, 0x03, 0x38, 0x03, 0x6e, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x60, 0x03, 0x20, 0x03, 0xcf, 0x57, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x66, 0xe0, 0x03, 0xad, 0x03, 0x52, 0x0c, 0xe0, 0x03, 0x16, 0x03, 0x45, 0x03, 0x8c, 0x21, 0xe0, 0x03, 0x8c, 0x03, 0x38, 0x0c, 0x2c, 0x03, 0x52, 0x03, 0x7c, 0x0c, 0xe0, 0x0f, 0x2c, 0x03, 0x0c, 0x06, 0x2c, 0x03, 0x52, 0x33, 0xe0, 0x03, 0xbd, 0x03, 0x45, 0x03, 0x0c, 0x03, 0x8c, 0x21, 0xe0, 0x03, 0x52, 0x03, 0x20, 0x09, 0x60, 0x03, 0x38, 0x03, 0x20, 0x0c, 0xe0, 0x03, 0x2c, 0x15, 0xe0, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x9c, 0x03, 0x45, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x2c, 0x03, 0x6e, 0x12, 0x9c, 0x03, 0x8c, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0x60, 0x03, 0x45, 0x03, 0x20, 0x03, 0x38, 0x03, 0x52, 0x03, 0x16, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x60, 0x0f, 0xe0, 0x03, 0x8c, 0x03, 0x20, 0x03, 0x52, 0x1e, 0xe0, 0x03, 0x2c, 0x03, 0x45, 0x03, 0x60, 0x06, 0x16, 0x03, 0x45, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xbd, 0x03, 0x60, 0x03, 0x20, 0x03, 0x9c, 0x03, 0x20, 0x09, 0xe0, 0x03, 0x9c, 0x03, 0x38, 0x12, 0xe0, 0x03, 0x9c, 0x03, 0x6e, 0x03, 0x2b, 0x03, 0x51, 0x03, 0x5e, 0x03, 0x1f, 0x03, 0x4e, 0x03, 0xb0, 0x03, 0xcd, 0x03, 0xca, 0x03, 0xbc, 0x03, 0x0c, 0x03, 0xad, 0x03, 0x9f, 0x03, 0x0c, 0x03, 0x29, 0x03, 0x0c, 0x03, 0xaf, 0x12, 0xcf, 0x03, 0xbe, 0x03, 0x40, 0x03, 0x34, 0x03, 0x74, 0x03, 0xcf, 0x03, 0x82, 0x03, 0x40, 0x03, 0x1f, 0x03, 0x4c, 0x03, 0xbe, 0x12, 0xcf, 0x03, 0x91, 0x03, 0x4c, 0x03, 0x15, 0x03, 0x40, 0x03, 0xbe, 0x12, 0xcf, 0x03, 0x59, 0x03, 0x1f, 0x03, 0x59, 0x03, 0x4c, 0x03, 0x1f, 0x03, 0xbe, 0x06, 0xcf, 0x03, 0x4c, 0x03, 0xbe, 0x06, 0xcf, 0x06, 0xcd, 0x03, 0xcb, 0x03, 0x7e, 0x03, 0x1e, 0x03, 0x4c, 0x03, 0xd5, 0x03, 0xd9, 0x03, 0xdb, 0x03, 0xdd, 0x03, 0xdf, 0x03, 0xe0, 0x03, 0xbd, 0x03, 0x2c, 0x03, 0xcf, 0x03, 0x52, 0x03, 0x7c, 0x18, 0xe0, 0x03, 0xcf, 0x03, 0x6e, 0x18, 0xe0, 0x03, 0xcf, 0x03, 0x60, 0x0f, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0x03, 0x60, 0x03, 0xcf, 0x39, 0xe0, 0x03, 0x9c, 0x0c, 0xe0, 0x03, 00, 0x0c, 0xe0, 0x03, 0x8c, 0x09, 0xe0, 0x03, 0xbd, 0x03, 0x45, 0x03, 0x0c, 0x03, 0x8c, 0x1b, 0xe0, 0x03, 0x16, 0x03, 0x45, 0x03, 0x8c, 0x24, 0xe0, 0x03, 0x52, 0x03, 0x20, 0x09, 0x60, 0x03, 0x38, 0x03, 0x20, 0x0c, 0xe0, 0x03, 0x7c, 0x03, 0x2c, 0x03, 0x52, 0x03, 0x38, 0x03, 0xbd, 0x03, 0x20, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x45, 0x03, 0x52, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x9c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xbd, 0x03, 0x60, 0x03, 0x20, 0x03, 0x9c, 0x0f, 0xe0, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x20, 0x0c, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x9c, 0x0c, 0xe0, 0x03, 0x2c, 0x15, 0xe0, 0x03, 0xcf, 0x06, 0x20, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x45, 0x03, 0xcf, 0x5a, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0x15, 0xe0, 0x03, 0xcf, 0x03, 0x60, 0x03, 0xcf, 0x27, 0xe0, 0x03, 0xcf, 0x09, 0x9c, 0x03, 0xbd, 0x0f, 0xe0, 0x03, 0x52, 0x0c, 0xe0, 0x03, 0xad, 0x06, 0x2c, 0x03, 0x52, 0x06, 0xe0, 0x03, 0x9c, 0x03, 0xad, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x12, 0x60, 0x03, 0x9c, 0x03, 0xbd, 0x03, 0x60, 0x06, 0x9c, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x60, 0x03, 0x8c, 0x03, 0x9c, 0x03, 0x2c, 0x03, 0x38, 0x03, 0xbd, 0x0f, 0xe0, 0x03, 0x6e, 0x03, 0x9c, 0x24, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xad, 0x0f, 0xe0, 0x03, 0xcf, 0x03, 0x6e, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x60, 0x09, 0x2c, 0x03, 0x45, 0x03, 0xad, 0x09, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 0x2c, 0x03, 0x52, 0x03, 0x7c, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0xdf, 0x03, 0xdd, 0x03, 0x9a, 0x03, 0x2a, 0x03, 0x6a, 0x03, 0xd4, 0x03, 0xd1, 0x03, 0x9f, 0x03, 0xce, 0x03, 0xcd, 0x03, 0xcb, 0x03, 0x8f, 0x03, 0xad, 0x06, 0xce, 0x1e, 0xcf, 0x03, 0xbe, 0x03, 0x90, 0x1b, 0xce, 0x03, 0xae, 0x03, 0x66, 0x03, 0xae, 0x09, 0xce, 0x12, 0xcf, 0x03, 0xbe, 0x06, 0x91, 0x06, 0xcf, 0x06, 0xce, 0x06, 0xcd, 0x03, 0xcb, 0x03, 0xcd, 0x03, 0xce, 0x03, 0xcf, 0x03, 0xd1, 0x03, 0x68, 0x03, 0x96, 0x03, 0xda, 0x03, 0xdc, 0x03, 0xdd, 0x03, 0xdf, 0x0c, 0xe0, 0x03, 0x8c, 0x03, 0x2c, 0x03, 0x60, 0x51, 0xe0, 0x03, 0xcf, 0x4e, 0xe0, 0x03, 0x60, 0x18, 0xe0, 0x03, 0xcf, 0x03, 0x60, 0x03, 0xcf, 0x4e, 0xe0, 0x03, 0xcf, 0x09, 0x9c, 0x03, 0xbd, 0x09, 0xe0, 0x03, 0xbd, 0x03, 0x20, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x9c, 0x03, 0x16, 0x03, 0x9c, 0x09, 0xe0, 0x03, 0x52, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x9c, 0x03, 0x60, 0x03, 0x7c, 0x03, 0x16, 0x03, 0x7c, 0x03, 0xcf, 0x12, 0xe0, 0x03, 0x2c, 0x15, 0xe0, 0x03, 0x45, 0x03, 0x2c, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x38, 0x03, 0xbd, 0x0c, 0xe0, 0x03, 0x2c, 0x1b, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xcf, 0x60, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0x69, 0xe0, 0x03, 0xdf, 0x03, 0xdd, 0x03, 0xda, 0x03, 0xd7, 0x03, 0xd4, 0x03, 0xcf, 0x90, 0xce, 0x03, 0xcf, 0x03, 0xd4, 0x03, 0xd7, 0x03, 0xda, 0x03, 0xdd, 0x03, 0xdf, 0xff, 0xe0, 0x60, 0xe0, 0x03, 0xcf, 0xff, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0x6c, 0xe0, 0x06, 0xdf, 0x03, 0xdd, 0x03, 0xdc, 0x03, 0xdb, 0x03, 0xd9, 0x03, 0xd6, 0x03, 0xd4, 0x03, 0xd1, 0x03, 0xd0, 0x03, 0xcd, 0x03, 0xcb, 0x03, 0xca, 0x09, 0xcb, 0x0c, 0xcd, 0x09, 0xce, 0x24, 0xcf, 0x09, 0xce, 0x0c, 0xcd, 0x09, 0xcb, 0x03, 0xca, 0x03, 0xcb, 0x03, 0xcd, 0x03, 0xd0, 0x03, 0xd1, 0x03, 0xd4, 0x03, 0xd6, 0x03, 0xd9, 0x03, 0xdb, 0x03, 0xdc, 0x03, 0xdd, 0x06, 0xdf, 0xff, 0xe0, 0xff, 0xe0, 0x66, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0x78, 0xe0, 0x06, 0xdf, 0x03, 0xdd, 0x03, 0xdb, 0x03, 0xda, 0x03, 0xd7, 0x03, 0xd5, 0x03, 0xd3, 0x03, 0xd1, 0x06, 0xd0, 0x06, 0xcf, 0x09, 0xce, 0x09, 0xcd, 0x03, 0xce, 0x1e, 0xcd, 0x03, 0xce, 0x09, 0xcd, 0x09, 0xce, 0x06, 0xcf, 0x06, 0xd0, 0x03, 0xd1, 0x03, 0xd3, 0x03, 0xd5, 0x03, 0xd7, 0x03, 0xda, 0x03, 0xdb, 0x03, 0xdd, 0x06, 0xdf, 0xff, 0xe0, 0xff, 0xe0, 0x72, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0x84, 0xe0, 0x03, 0xdf, 0x06, 0xdd, 0x03, 0xdc, 0x03, 0xdb, 0x03, 0xda, 0x03, 0xd9, 0x03, 0xd7, 0x03, 0xd6, 0x03, 0xd5, 0x03, 0xd4, 0x03, 0xd3, 0x03, 0xd1, 0x03, 0xd0, 0x06, 0xcf, 0x03, 0xce, 0x09, 0xcd, 0x06, 0xcb, 0x09, 0xcd, 0x03, 0xce, 0x06, 0xcf, 0x03, 0xd0, 0x03, 0xd1, 0x03, 0xd3, 0x03, 0xd4, 0x03, 0xd5, 0x03, 0xd6, 0x03, 0xd7, 0x03, 0xd9, 0x03, 0xda, 0x03, 0xdb, 0x03, 0xdc, 0x06, 0xdd, 0x03, 0xdf, 0xff, 0xe0, 0xff, 0xe0, 0x7e, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x51, 0xe0, 0x03, 0x9c, 0x03, 0x7c, 0x0c, 0xe0, 0x03, 0x52, 0x12, 0xe0, 0x03, 0xbd, 0x0f, 0xe0, 0x03, 0xbd, 0x03, 0xad, 0x3c, 0xe0, 0x03, 0x7c, 0x03, 0xad, 0xbd, 0xe0, 0x03, 0x9c, 0x2a, 0xe0, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x8c, 0x03, 0x9c, 0x03, 0x38, 0x12, 0xe0, 0x03, 0x6e, 0x03, 0xad, 0x48, 0xe0, 0x03, 0x9c, 0x03, 0xad, 0x18, 0xe0, 0x03, 0x7c, 0x03, 0xad, 0x03, 0xe0, 0x12, 0x9c, 0x03, 0xad, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0xcf, 0x15, 0xe0, 0x06, 0xdf, 0x03, 0xdd, 0x03, 0xdc, 0x03, 0xdb, 0x03, 0xda, 0x03, 0xd9, 0x03, 0xd7, 0x03, 0xd6, 0x03, 0xd5, 0x03, 0xd4, 0x03, 0xd3, 0x06, 0xd1, 0x0c, 0xd0, 0x06, 0xd1, 0x03, 0xd3, 0x03, 0xc3, 0x03, 0xa4, 0x03, 0xd6, 0x03, 0xd7, 0x03, 0xd9, 0x03, 0xda, 0x03, 0xdb, 0x03, 0xdc, 0x03, 0xdd, 0x03, 0xdf, 0x03, 0x7c, 0x0c, 0xe0, 0x03, 0xbd, 0x03, 0x52, 0x18, 0xe0, 0x03, 0x6e, 0xff, 0xe0, 0xff, 0xe0, 0x60, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x51, 0xe0, 0x03, 0x45, 0x06, 0xbd, 0x09, 0x60, 0x03, 0x16, 0x09, 0x60, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x7c, 0x0c, 0xe0, 0x03, 0x7c, 0x03, 0x52, 0x12, 0xe0, 0x03, 0x52, 0x03, 0x38, 0x09, 0x2c, 0x03, 0x20, 0x03, 0xad, 0x15, 0xe0, 0x03, 0x2c, 0x03, 0x9c, 0x45, 0xe0, 0x03, 00, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x15, 0xe0, 0x03, 00, 0x4b, 0xe0, 0x03, 00, 0x2a, 0xe0, 0x03, 00, 0x06, 0xe0, 0x03, 0xad, 0x03, 0x2c, 0x03, 0x60, 0x03, 0x9c, 0x0c, 0xe0, 0x03, 0xcf, 0x03, 0x16, 0x03, 0xcf, 0x18, 0xe0, 0x03, 0xcf, 0x2d, 0xe0, 0x03, 0x20, 0x03, 0xbd, 0x06, 0xe0, 0x03, 0xcf, 0x0f, 0xe0, 0x03, 0x60, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x16, 0x06, 0x60, 0x03, 0x16, 0x06, 0x60, 0x03, 0x2c, 0x0c, 0xe0, 0x03, 0x20, 0x03, 0x9c, 0x39, 0xe0, 0x03, 0xbd, 0x15, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 0x45, 0x15, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x09, 0xe0, 0x03, 0xad, 0x03, 0x38, 0x03, 0x60, 0x03, 0x6e, 0x15, 0xe0, 0x03, 0x38, 0x03, 0x8c, 0x12, 0xe0, 0x03, 0xcf, 0x03, 0xad, 0xff, 0xe0, 0xff, 0xe0, 0x45, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4b, 0xe0, 0x03, 0xbd, 0x03, 0x2c, 0x03, 0x52, 0x03, 0x9c, 0x03, 0x52, 0x09, 0x9c, 0x03, 0x20, 0x09, 0x9c, 0x09, 0xe0, 0x03, 0x38, 0x03, 0xad, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xad, 0x03, 0xe0, 0x06, 0x45, 0x18, 0xe0, 0x03, 0x16, 0x0c, 0xe0, 0x03, 0x8c, 0x39, 0xe0, 0x03, 00, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x15, 0xe0, 0x03, 00, 0x4b, 0xe0, 0x03, 00, 0x2a, 0xe0, 0x03, 00, 0x09, 0xe0, 0x03, 0x8c, 0x12, 0xe0, 0x03, 0x52, 0x09, 00, 0x03, 0x2c, 0x03, 0x20, 0x03, 0x16, 0x0c, 0xe0, 0x03, 0x38, 0x03, 0x45, 0x03, 0xcf, 0x1b, 0xe0, 0x03, 0xad, 0x09, 0x2c, 0x03, 0x0c, 0x06, 0x2c, 0x03, 0x20, 0x03, 0x2c, 0x03, 0xad, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0x45, 0x03, 0x6e, 0x03, 0xbd, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x0c, 0xe0, 0x03, 0x0c, 0x03, 0xcf, 0x1b, 0xe0, 0x03, 0x7c, 0x03, 0x45, 0x09, 0x2c, 0x03, 0x20, 0x03, 0x0c, 0x03, 0x16, 0x03, 00, 0x03, 0x16, 0x03, 0x7c, 0x12, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 0x45, 0x18, 0xe0, 0x03, 0x9c, 0x03, 0x38, 0x03, 0x9c, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x9c, 0x03, 0xbd, 0x15, 0xe0, 0x03, 0x9c, 0x03, 0x38, 0x03, 0x9c, 0x03, 0x60, 0x03, 0x20, 0x09, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x0f, 0xe0, 0x03, 0x9c, 0x03, 0xad, 0xff, 0xe0, 0xff, 0xe0, 0x30, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x7c, 0x03, 0x45, 0x03, 0x38, 0x03, 0xcf, 0x03, 0x7c, 0x06, 0x60, 0x03, 0x16, 0x06, 0x60, 0x03, 0x7c, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xbd, 0x09, 0x9c, 0x03, 0x6e, 0x03, 0x16, 0x03, 0x52, 0x03, 0x45, 0x15, 0xe0, 0x03, 0x45, 0x03, 0x52, 0x12, 0xe0, 0x03, 0x9c, 0x03, 0x60, 0x03, 0x52, 0x03, 00, 0x03, 0x2c, 0x03, 0x38, 0x03, 0x9c, 0x03, 0xe0, 0x06, 0x52, 0x36, 0xe0, 0x03, 00, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x15, 0xe0, 0x03, 00, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0x6e, 0x03, 0x60, 0x03, 0x2c, 0x03, 0x7c, 0x0c, 0xe0, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x60, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xad, 0x03, 0xbd, 0x12, 0xe0, 0x03, 00, 0x1b, 0xe0, 0x03, 0x52, 0x0c, 0x2c, 0x03, 00, 0x0c, 0x2c, 0x03, 0x52, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0x20, 0x03, 0xcf, 0x09, 0xe0, 0x03, 0x6e, 0x03, 0x45, 0x0f, 0xe0, 0x03, 0x45, 0x03, 0x20, 0x03, 0xad, 0x0c, 0xe0, 0x03, 0x8c, 0x03, 0x7c, 0x0f, 0xe0, 0x03, 0x20, 0x03, 0xbd, 0x15, 0xe0, 0x03, 0xbd, 0x03, 0x60, 0x03, 0x2c, 0x03, 0x45, 0x03, 0x9c, 0x03, 0x20, 0x06, 0x9c, 0x03, 0x20, 0x06, 0x9c, 0x03, 0x2c, 0x0c, 0xe0, 0x03, 00, 0x1e, 0xe0, 0x03, 0x8c, 0x06, 0x9c, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x38, 0x03, 0xbd, 0x15, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x03, 0x7c, 0x15, 0xe0, 0x03, 0x52, 0x03, 0x2c, 0x06, 0x16, 0x03, 0x52, 0x03, 0x60, 0x18, 0xe0, 0x09, 0x2c, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x45, 0x03, 0x8c, 0x03, 0xcf, 0x09, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x0f, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x03, 0xcf, 0xff, 0xe0, 0xff, 0xe0, 0x2d, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x51, 0xe0, 0x03, 0x38, 0x03, 0x6e, 0x03, 0x8c, 0x03, 0xad, 0x0f, 0x9c, 0x03, 0xad, 0x09, 0xe0, 0x03, 0x20, 0x03, 0xe0, 0x03, 0xbd, 0x09, 0x60, 0x03, 0x45, 0x03, 0x20, 0x03, 0x9c, 0x12, 0xe0, 0x03, 0xcf, 0x03, 0x2c, 0x03, 0x7c, 0x15, 0xe0, 0x03, 0x6e, 0x03, 0x7c, 0x03, 0x60, 0x03, 0x45, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x20, 0x03, 0x9c, 0x33, 0xe0, 0x03, 00, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x0c, 0xe0, 0x03, 0x60, 0x03, 0x45, 0x03, 0x2c, 0x03, 00, 0x06, 0x2c, 0x03, 0x60, 0x03, 0x6e, 0x03, 0x9c, 0x03, 0x16, 0x03, 0x9c, 0x09, 0xe0, 0x03, 0x7c, 0x03, 0x45, 0x03, 0xe0, 0x03, 0x6e, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x7c, 0x12, 0xe0, 0x03, 00, 0x03, 0x7c, 0x03, 0xcf, 0x24, 0xe0, 0x03, 00, 0x18, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x06, 0xad, 0x09, 0xe0, 0x03, 0x16, 0x03, 0xad, 0x12, 0xe0, 0x03, 0x7c, 0x03, 0x52, 0x0c, 0xe0, 0x03, 0x2c, 0x03, 0x7c, 0x0c, 0xe0, 0x03, 0x60, 0x03, 0x52, 0x03, 0x6e, 0x03, 0x60, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0xcf, 0x0c, 0xe0, 0x03, 0x60, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x16, 0x06, 0x60, 0x03, 0x16, 0x06, 0x60, 0x03, 0x2c, 0x0c, 0xe0, 0x03, 00, 0x2d, 0xe0, 0x03, 0x45, 0x03, 0x7c, 0x18, 0xe0, 0x03, 0x7c, 0x03, 0x16, 0x03, 0x9c, 0x1e, 0xe0, 0x03, 0x45, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x09, 0x60, 0x03, 0xbd, 0x18, 0xe0, 0x03, 0x7c, 0x03, 0x45, 0x0f, 0xe0, 0x03, 0xbd, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0x60, 0x03, 0x52, 0xff, 0xe0, 0xff, 0xe0, 0x2d, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0xbd, 0x03, 0x2c, 0x03, 0x9c, 0x03, 0x38, 0x03, 0x52, 0x12, 0x2c, 0x09, 0xe0, 0x03, 0x2c, 0x0f, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0xcf, 0x03, 0x2c, 0x03, 0x38, 0x03, 0x45, 0x03, 0x2c, 0x03, 0x38, 0x03, 0x7c, 0x12, 0xe0, 0x03, 0x52, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x33, 0xe0, 0x03, 00, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x0c, 0xe0, 0x03, 0x8c, 0x03, 0x9c, 0x03, 0xcf, 0x03, 00, 0x0c, 0xe0, 0x03, 0x45, 0x03, 0x52, 0x0f, 0xe0, 0x03, 0x16, 0x06, 0xcf, 0x03, 0x0c, 0x06, 0xe0, 0x03, 0x20, 0x03, 0xbd, 0x12, 0xe0, 0x03, 00, 0x03, 0x45, 0x03, 0x0c, 0x03, 0x52, 0x03, 0xbd, 0x15, 0xe0, 0x03, 0x16, 0x03, 0xcf, 0x03, 0xe0, 0x03, 00, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x16, 0x0c, 0xe0, 0x03, 0x9c, 0x03, 0x16, 0x06, 0xad, 0x03, 0x16, 0x03, 0x52, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x2c, 0x24, 0xe0, 0x03, 0x8c, 0x03, 0x20, 0x0c, 0xe0, 0x03, 0xad, 0x03, 00, 0x03, 0x38, 0x03, 0x8c, 0x03, 0x7c, 0x03, 0x38, 0x03, 0x8c, 0x03, 0x45, 0x03, 0x16, 0x03, 0x9c, 0x09, 0xe0, 0x03, 0x60, 0x03, 0x8c, 0x03, 0xad, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x0c, 0xe0, 0x03, 00, 0x2a, 0xe0, 0x06, 0x60, 0x18, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x03, 0xcf, 0x21, 0xe0, 0x03, 0x16, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x60, 0x09, 0x9c, 0x03, 0xcf, 0x1b, 0xe0, 0x03, 0x20, 0x03, 0xad, 0x0f, 0xe0, 0x03, 0x16, 0x12, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0xcf, 0xff, 0xe0, 0xff, 0xe0, 0x2a, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4b, 0xe0, 0x03, 0xad, 0x03, 0x2c, 0x03, 0x45, 0x03, 0x2c, 0x03, 0x45, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xad, 0x03, 0xcf, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x2c, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0xbd, 0x09, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0x0f, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x2c, 0x03, 0x7c, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0xbd, 0x03, 0x45, 0x03, 0x2c, 0x0f, 0xe0, 0x03, 0x16, 0x03, 0xcf, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x20, 0x03, 0xad, 0x30, 0xe0, 0x03, 0x60, 0x0c, 0xe0, 0x03, 0x7c, 0x03, 0x45, 0x15, 0xe0, 0x03, 00, 0x06, 0xe0, 0x03, 0xcf, 0x06, 0x45, 0x12, 0xe0, 0x03, 0x52, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x9c, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0x2c, 0x15, 0xe0, 0x03, 00, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x60, 0x03, 0x0c, 0x03, 0x60, 0x03, 0xcf, 0x0c, 0xe0, 0x03, 0xad, 0x03, 0x20, 0x06, 0xe0, 0x03, 00, 0x06, 0xe0, 0x03, 0x38, 0x03, 0x9c, 0x0c, 0xe0, 0x03, 0xbd, 0x09, 0xe0, 0x03, 0x45, 0x03, 0x20, 0x03, 0x16, 0x03, 0xad, 0x21, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x03, 0xad, 0x09, 0xe0, 0x03, 0x9c, 0x03, 0x16, 0x03, 0x8c, 0x03, 0xe0, 0x03, 0xcf, 0x03, 0x6e, 0x03, 00, 0x03, 0x52, 0x03, 0xad, 0x0c, 0xe0, 0x03, 0xbd, 0x03, 0x2c, 0x03, 0x16, 0x03, 0x9c, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x2c, 0x0c, 0xe0, 0x03, 00, 0x12, 0xe0, 0x03, 0x45, 0x03, 0xbd, 0x12, 0xe0, 0x03, 0x16, 0x03, 0xbd, 0x18, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x03, 0x7c, 0x1e, 0xe0, 0x03, 0xbd, 0x03, 0x20, 0x24, 0xe0, 0x03, 0xbd, 0x03, 0x60, 0x09, 0x2c, 0x03, 0x45, 0x03, 0x20, 0x0f, 0xe0, 0x03, 00, 0x06, 0xe0, 0x03, 0xcf, 0x0c, 0xe0, 0x03, 0x52, 0x03, 0x6e, 0xff, 0xe0, 0xff, 0xe0, 0x2a, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x6e, 0x03, 0x9c, 0x03, 0x60, 0x03, 0x6e, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x7c, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x7c, 0x03, 0x60, 0x09, 0xe0, 0x03, 0x7c, 0x03, 0x45, 0x0c, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x9c, 0x12, 0xe0, 0x03, 0x20, 0x03, 0xad, 0x09, 0xe0, 0x03, 0x9c, 0x03, 0x38, 0x09, 0xe0, 0x03, 0x20, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x8c, 0x03, 0xbd, 0x3f, 0xe0, 0x03, 0x45, 0x03, 0x6e, 0x15, 0xe0, 0x03, 00, 0x06, 0xe0, 0x03, 0xad, 0x03, 0x52, 0x24, 0xe0, 0x03, 0x38, 0x03, 0x9c, 0x15, 0xe0, 0x03, 00, 0x09, 0xe0, 0x03, 0xbd, 0x03, 0x38, 0x03, 0x52, 0x0c, 0xe0, 0x03, 0x45, 0x03, 0x6e, 0x06, 0xe0, 0x03, 00, 0x06, 0xe0, 0x03, 0x8c, 0x03, 0x45, 0x1b, 0xe0, 0x03, 0x2c, 0x03, 0x60, 0x21, 0xe0, 0x03, 0x9c, 0x03, 0x0c, 0x03, 0x7c, 0x0c, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x20, 0x03, 0x6e, 0x03, 0x20, 0x0f, 0xe0, 0x03, 0x9c, 0x06, 0x38, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x0c, 0x06, 0x2c, 0x03, 0x0c, 0x09, 0x2c, 0x0c, 0xe0, 0x03, 00, 0x0f, 0xe0, 0x03, 0xcf, 0x03, 0x0c, 0x15, 0xe0, 0x03, 00, 0x1e, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 0x52, 0x1b, 0xe0, 0x03, 0x6e, 0x03, 0x60, 0x06, 0xe0, 0x03, 0x60, 0x03, 0xcf, 0x15, 0xe0, 0x03, 0xad, 0x03, 0x16, 0x03, 0x8c, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x8c, 0x03, 0x2c, 0x03, 0xad, 0x0c, 0xe0, 0x03, 0x2c, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x6e, 0x03, 0x7c, 0x09, 0xe0, 0x03, 0x9c, 0x03, 0x2c, 0xff, 0xe0, 0xff, 0xe0, 0x2a, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x2c, 0x03, 0x9c, 0x03, 0x60, 0x03, 0x52, 0x06, 0xe0, 0x03, 0x16, 0x03, 0xe0, 0x03, 0x2c, 0x0f, 0xe0, 0x06, 0x2c, 0x03, 0xcf, 0x09, 0xe0, 0x03, 0x45, 0x03, 0x7c, 0x0f, 0xe0, 0x03, 0xbd, 0x03, 0xe0, 0x06, 0x2c, 0x03, 0x38, 0x03, 0xad, 0x06, 0xe0, 0x03, 0x20, 0x03, 0xad, 0x09, 0xe0, 0x03, 0x45, 0x03, 0x8c, 0x09, 0xe0, 0x03, 00, 0x0f, 0xe0, 0x03, 0xcf, 0x03, 0x8c, 0x36, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0xcf, 0x15, 0xe0, 0x03, 00, 0x2d, 0xe0, 0x03, 0x6e, 0x03, 0x45, 0x18, 0xe0, 0x03, 00, 0x0f, 0xe0, 0x03, 0xcf, 0x09, 0xe0, 0x03, 0xbd, 0x03, 0x0c, 0x03, 0xcf, 0x06, 0xe0, 0x03, 00, 0x09, 0xe0, 0x03, 0x16, 0x03, 0xad, 0x15, 0xe0, 0x06, 0x45, 0x1e, 0xe0, 0x03, 0xbd, 0x03, 0x45, 0x03, 0x0c, 0x03, 0xad, 0x15, 0xe0, 0x03, 0xcf, 0x03, 0x16, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x2c, 0x15, 0xe0, 0x03, 0x60, 0x03, 0x9c, 0x03, 0xe0, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0x2c, 0x06, 0xe0, 0x03, 0x7c, 0x0c, 0xe0, 0x03, 00, 0x03, 0xcf, 0x0c, 0xe0, 0x03, 0x52, 0x03, 0x60, 0x15, 0xe0, 0x03, 0x2c, 0x03, 0x6e, 0x21, 0xe0, 0x03, 0x45, 0x03, 0x20, 0x03, 0xcf, 0x15, 0xe0, 0x03, 0x20, 0x03, 0xad, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x45, 0x18, 0xe0, 0x03, 0x38, 0x03, 0x8c, 0x21, 0xe0, 0x03, 0x6e, 0x03, 0x60, 0x03, 0xe0, 0x03, 0x20, 0x03, 0xbd, 0x09, 0xe0, 0x03, 0xcf, 0x03, 0x16, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x20, 0x03, 0x2c, 0x03, 0xcf, 0xff, 0xe0, 0xff, 0xe0, 0x18, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0x38, 0x03, 0x9c, 0x03, 0x60, 0x03, 0x52, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x45, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x6e, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x2c, 0x03, 0x45, 0x09, 0xe0, 0x03, 0x7c, 0x03, 0x20, 0x15, 0xe0, 0x03, 0x9c, 0x03, 0x60, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x20, 0x03, 0xe0, 0x03, 0x6e, 0x03, 0x20, 0x09, 0xe0, 0x03, 0xbd, 0x03, 0x16, 0x03, 0xe0, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x8c, 0x03, 0x2c, 0x0f, 0xe0, 0x03, 0xbd, 0x03, 0x20, 0x03, 0x7c, 0x30, 0xe0, 0x03, 0x6e, 0x03, 0x16, 0x03, 0xad, 0x18, 0xe0, 0x03, 0x0c, 0x03, 0x9c, 0x09, 0xe0, 0x03, 0xad, 0x03, 0x8c, 0x18, 0xe0, 0x03, 0x60, 0x03, 0x20, 0x1b, 0xe0, 0x03, 00, 0x18, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 0x8c, 0x09, 0xe0, 0x03, 00, 0x09, 0xe0, 0x03, 0x9c, 0x03, 0x20, 0x03, 0xcf, 0x0c, 0xe0, 0x03, 0xbd, 0x03, 0x2c, 0x03, 0x45, 0x15, 0xe0, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0x7c, 0x03, 0x38, 0x03, 0x0c, 0x03, 0x60, 0x03, 0xcf, 0x18, 0xe0, 0x03, 0x9c, 0x03, 0x20, 0x06, 0xe0, 0x03, 0xad, 0x15, 0xe0, 0x03, 0x60, 0x03, 0x9c, 0x0c, 0xe0, 0x03, 0x2c, 0x15, 0xe0, 0x03, 0x38, 0x03, 0x6e, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x60, 0x03, 0x20, 0x03, 0xcf, 0x15, 0xe0, 0x03, 0xad, 0x03, 0x0c, 0x03, 0x60, 0x03, 0xbd, 0x1e, 0xe0, 0x03, 0x6e, 0x03, 0x20, 0x03, 0xbd, 0x0f, 0xe0, 0x03, 0xad, 0x03, 0x20, 0x06, 0xe0, 0x03, 0x6e, 0x03, 0x38, 0x0c, 0xe0, 0x03, 0xcf, 0x09, 0xe0, 0x03, 0x45, 0x03, 0x6e, 0x0f, 0xe0, 0x03, 0xbd, 0x0f, 0xe0, 0x03, 0xcf, 0x03, 0x16, 0x03, 0x52, 0x03, 0x2c, 0x0f, 0xe0, 0x03, 0xcf, 0x03, 0xe0, 0x03, 0xad, 0x03, 0x45, 0x03, 0xe0, 0x03, 0x7c, 0x03, 0x6e, 0xff, 0xe0, 0xff, 0xe0, 0x18, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4b, 0xe0, 0x03, 0xad, 0x03, 0x52, 0x03, 0x9c, 0x03, 0x60, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0x16, 0x03, 0xbd, 0x03, 0xe0, 0x03, 0x2c, 0x03, 0xe0, 0x03, 0x52, 0x03, 0x9c, 0x06, 0xe0, 0x03, 0x52, 0x03, 0x6e, 0x06, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x03, 0xad, 0x18, 0xe0, 0x03, 0x2c, 0x03, 0x45, 0x03, 0x60, 0x06, 0x16, 0x03, 0x45, 0x03, 0xcf, 0x09, 0xe0, 0x03, 0x2c, 0x03, 0x7c, 0x03, 0xe0, 0x03, 0x16, 0x03, 0x20, 0x03, 0x0c, 0x03, 0x8c, 0x12, 0xe0, 0x03, 0xcf, 0x03, 0x20, 0x03, 0x7c, 0x27, 0xe0, 0x03, 0x60, 0x03, 0x16, 0x03, 0x38, 0x03, 0xbd, 0x1b, 0xe0, 0x03, 0x8c, 0x03, 0x20, 0x09, 00, 0x03, 0x20, 0x03, 0x2c, 0x12, 0xe0, 0x03, 0x8c, 0x03, 0x16, 0x03, 0x52, 0x1e, 0xe0, 0x03, 00, 0x1b, 0xe0, 0x03, 0x9c, 0x0c, 0xe0, 0x03, 00, 0x0c, 0xe0, 0x03, 0x8c, 0x09, 0xe0, 0x03, 0xbd, 0x03, 0x45, 0x03, 0x0c, 0x03, 0x8c, 0x1b, 0xe0, 0x03, 0x16, 0x03, 0x45, 0x03, 0x8c, 0x24, 0xe0, 0x03, 0x52, 0x03, 0x20, 0x09, 0x60, 0x03, 0x38, 0x03, 0x20, 0x0c, 0xe0, 0x03, 0x60, 0x03, 0x9c, 0x0c, 0xe0, 0x03, 0x2c, 0x15, 0xe0, 0x03, 0xcf, 0x06, 0x20, 0x03, 0x2c, 0x03, 0x0c, 0x03, 0x45, 0x03, 0xcf, 0x1b, 0xe0, 0x03, 0xbd, 0x03, 0x45, 0x03, 0x16, 0x03, 0x20, 0x1e, 0xe0, 0x03, 0x7c, 0x03, 0x0c, 0x03, 0xad, 0x0c, 0xe0, 0x03, 0x38, 0x03, 0x7c, 0x06, 0xe0, 0x03, 0xcf, 0x03, 0x52, 0x03, 0x16, 0x06, 0x2c, 0x03, 0x20, 0x03, 0x52, 0x09, 0xe0, 0x03, 0xbd, 0x03, 0x2c, 0x03, 0x20, 0x06, 0x60, 0x03, 0x52, 0x06, 0x20, 0x12, 0xe0, 0x03, 0xad, 0x03, 0x60, 0x03, 0xcf, 0x15, 0xe0, 0x03, 0xbd, 0x03, 0x2c, 0x03, 0xcf, 0x03, 0x52, 0x03, 0x7c, 0xff, 0xe0, 0xff, 0xe0, 0x18, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x4e, 0xe0, 0x03, 0xbd, 0x03, 0x9c, 0x03, 0x60, 0x03, 0x9c, 0x03, 0x2c, 0x03, 0xbd, 0x06, 0xe0, 0x03, 0x45, 0x03, 0x2c, 0x03, 0x45, 0x15, 0xe0, 0x03, 0x9c, 0x03, 0xcf, 0x1e, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xad, 0x12, 0xe0, 0x03, 0xad, 0x09, 0xe0, 0x06, 0xad, 0x18, 0xe0, 0x03, 0xad, 0x03, 0x52, 0x27, 0xe0, 0x03, 0xad, 0x03, 0xbd, 0x48, 0xe0, 0x03, 0xad, 0x03, 0xbd, 0x21, 0xe0, 0x03, 0x60, 0x2a, 0xe0, 0x03, 0x60, 0x18, 0xe0, 0x03, 0xcf, 0x03, 0x60, 0x03, 0xcf, 0x4e, 0xe0, 0x03, 0xcf, 0x09, 0x9c, 0x03, 0xbd, 0x0c, 0xe0, 0x03, 0x2c, 0x03, 0x38, 0x03, 0xbd, 0x0c, 0xe0, 0x03, 0x2c, 0x1b, 0xe0, 0x03, 0xad, 0x03, 0x9c, 0x03, 0xcf, 0x2a, 0xe0, 0x03, 0xcf, 0x21, 0xe0, 0x03, 0x7c, 0x03, 0xcf, 0x0c, 0xe0, 0x03, 0xbd, 0x03, 0xcf, 0x2a, 0xe0, 0x03, 0xcf, 0x09, 0x9c, 0x39, 0xe0, 0x03, 0x8c, 0x03, 0x2c, 0x03, 0x60, 0xff, 0xe0, 0xff, 0xe0, 0x1b, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0x51, 0xe0, 0x03, 0xcf, 0x03, 0xbd, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x2a, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0x03, 0xf3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0x81, 0xe0, 0x06, 0xf3, +0xff, 0xf3, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xf3, 0x8a, 0xf3, + +}; diff --git a/osfmk/ppc/POWERMAC/rendered_numbers.c b/osfmk/ppc/POWERMAC/rendered_numbers.c new file mode 100644 index 000000000..a30a90a0c --- /dev/null +++ b/osfmk/ppc/POWERMAC/rendered_numbers.c @@ -0,0 +1,374 @@ +static const struct { + unsigned int num_w; + unsigned int num_h; + unsigned char num_pixel_data[0xac]; +} num_0 = { +/* w */ 9, +/* h */ 12, +/* pixel_data */ +0x1b, 0xe6, +0x06, 0xe6, 0x03, 0xcb, 0x03, 0x78, 0x03, 0x6c, 0x03, 0xb8, 0x09, 0xe6, +0x03, 0xe6, 0x03, 0xc9, 0x03, 0x1a, 0x03, 0x6e, 0x03, 0x84, 0x03, 0x16, 0x03, 0xa6, 0x06, 0xe6, +0x03, 0xe6, 0x03, 0x5a, 0x03, 0x58, 0x06, 0xe6, 0x03, 0x8f, 0x03, 0x26, 0x06, 0xe6, +0x03, 0xe6, 0x03, 0x09, 0x03, 0x9c, 0x06, 0xe6, 0x03, 0xd3, 0x03, 00, 0x03, 0xbb, 0x03, 0xe6, +0x03, 0xd3, 0x03, 00, 0x03, 0xb5, 0x09, 0xe6, 0x03, 0x04, 0x03, 0x9d, 0x03, 0xe6, +0x03, 0xc5, 0x03, 00, 0x03, 0xbd, 0x09, 0xe6, 0x03, 0x0b, 0x03, 0x91, 0x03, 0xe6, +0x03, 0xdc, 0x03, 00, 0x03, 0xae, 0x06, 0xe6, 0x03, 0xe2, 0x03, 00, 0x03, 0xa9, 0x03, 0xe6, +0x03, 0xe6, 0x03, 0x23, 0x03, 0x87, 0x06, 0xe6, 0x03, 0xba, 0x03, 0x03, 0x03, 0xd0, 0x03, 0xe6, +0x03, 0xe6, 0x03, 0x83, 0x03, 0x2e, 0x03, 0xe0, 0x03, 0xe6, 0x03, 0x57, 0x03, 0x4e, 0x06, 0xe6, +0x03, 0xe6, 0x03, 0xe4, 0x03, 0x58, 0x03, 0x1b, 0x03, 0x27, 0x03, 0x34, 0x03, 0xd6, 0x06, 0xe6, +0x09, 0xe6, 0x03, 0xd2, 0x03, 0xc9, 0x0c, 0xe6, + +}; +static const struct { + unsigned int num_w; + unsigned int num_h; + unsigned char num_pixel_data[0x72]; +} num_1 = { +/* w */ 7, +/* h */ 12, +/* pixel_data */ +0x15, 0xe6, +0x03, 0xe6, 0x03, 0xe5, 0x03, 0xbd, 0x03, 0x83, 0x03, 0xbc, 0x06, 0xe6, +0x03, 0xe6, 0x03, 0x36, 0x03, 0x31, 0x03, 0x03, 0x03, 0x9e, 0x06, 0xe6, +0x03, 0xe6, 0x03, 0xe0, 0x03, 0xe6, 0x03, 0x0b, 0x03, 0x9e, 0x06, 0xe6, +0x09, 0xe6, 0x03, 0x0b, 0x03, 0x9e, 0x06, 0xe6, +0x09, 0xe6, 0x03, 0x0b, 0x03, 0x9e, 0x06, 0xe6, +0x09, 0xe6, 0x03, 0x0b, 0x03, 0x9e, 0x06, 0xe6, +0x09, 0xe6, 0x03, 0x0b, 0x03, 0x9e, 0x06, 0xe6, +0x09, 0xe6, 0x03, 0x0b, 0x03, 0x9e, 0x06, 0xe6, +0x09, 0xe6, 0x03, 0x0b, 0x03, 0x9e, 0x06, 0xe6, +0x03, 0xe6, 0x03, 0x33, 0x03, 0x0d, 0x03, 00, 0x03, 0x09, 0x03, 0x0d, 0x03, 0xbd, +0x15, 0xe6, + +}; +static const struct { + unsigned int num_w; + unsigned int num_h; + unsigned char num_pixel_data[0x82]; +} num_2 = { +/* w */ 8, +/* h */ 12, +/* pixel_data */ +0x18, 0xe6, +0x03, 0xe6, 0x03, 0xe2, 0x03, 0xb4, 0x03, 0x7d, 0x03, 0x6d, 0x03, 0xb7, 0x06, 0xe6, +0x03, 0xe6, 0x03, 0xae, 0x03, 0x28, 0x03, 0x74, 0x03, 0x7b, 0x03, 0x1b, 0x03, 0x6d, 0x03, 0xe6, +0x03, 0xe6, 0x03, 0xe5, 0x09, 0xe6, 0x03, 0x93, 0x03, 0x11, 0x03, 0xde, +0x0f, 0xe6, 0x03, 0x9e, 0x03, 0x06, 0x03, 0xdc, +0x0c, 0xe6, 0x03, 0xe3, 0x03, 0x3b, 0x03, 0x51, 0x03, 0xe6, +0x09, 0xe6, 0x03, 0xe4, 0x03, 0x5c, 0x03, 0x3b, 0x03, 0xde, 0x03, 0xe6, +0x06, 0xe6, 0x03, 0xe5, 0x03, 0x55, 0x03, 0x40, 0x03, 0xdc, 0x06, 0xe6, +0x06, 0xe6, 0x03, 0x65, 0x03, 0x35, 0x03, 0xdd, 0x09, 0xe6, +0x03, 0xe6, 0x03, 0xb0, 0x03, 00, 0x03, 0x9d, 0x09, 0xcf, 0x03, 0xe4, +0x03, 0xe6, 0x03, 0x77, 0x0f, 00, 0x03, 0xcc, +0x18, 0xe6, + +}; +static const struct { + unsigned int num_w; + unsigned int num_h; + unsigned char num_pixel_data[0x8e]; +} num_3 = { +/* w */ 8, +/* h */ 12, +/* pixel_data */ +0x18, 0xe6, +0x06, 0xe6, 0x03, 0xa2, 0x03, 0x73, 0x03, 0x66, 0x03, 0x9f, 0x03, 0xdb, 0x03, 0xe6, +0x06, 0xe6, 0x03, 0x51, 0x03, 0x77, 0x03, 0x88, 0x03, 0x2e, 0x03, 0x4d, 0x03, 0xe6, +0x0f, 0xe6, 0x03, 0xaf, 0x03, 0x02, 0x03, 0xda, +0x0f, 0xe6, 0x03, 0x7b, 0x03, 0x29, 0x03, 0xe6, +0x06, 0xe6, 0x03, 0xd8, 0x03, 0x78, 0x03, 0x45, 0x03, 0x49, 0x03, 0xca, 0x03, 0xe6, +0x06, 0xe6, 0x03, 0xd7, 0x03, 0x76, 0x03, 0x42, 0x03, 0x24, 0x03, 0x8a, 0x03, 0xe6, +0x0f, 0xe6, 0x03, 0x9f, 0x03, 00, 0x03, 0xc5, +0x0f, 0xe6, 0x03, 0xe0, 0x03, 0x06, 0x03, 0x8a, +0x03, 0xe6, 0x03, 0xe5, 0x03, 0xcd, 0x06, 0xe6, 0x03, 0x8c, 0x03, 00, 0x03, 0xb6, +0x03, 0xe6, 0x03, 0xe2, 0x03, 0x03, 0x03, 0x20, 0x03, 0x22, 0x03, 0x29, 0x03, 0x86, 0x03, 0xe6, +0x06, 0xe6, 0x03, 0xe2, 0x03, 0xc6, 0x03, 0xc9, 0x09, 0xe6, + +}; +static const struct { + unsigned int num_w; + unsigned int num_h; + unsigned char num_pixel_data[0x80]; +} num_4 = { +/* w */ 8, +/* h */ 12, +/* pixel_data */ +0x18, 0xe6, +0x0f, 0xe6, 0x03, 0xc4, 0x03, 0x90, 0x03, 0xe6, +0x0c, 0xe6, 0x03, 0xdc, 0x03, 0x24, 0x03, 0x0a, 0x03, 0xe6, +0x0c, 0xe6, 0x03, 0x5a, 0x03, 0x3e, 0x03, 0x0a, 0x03, 0xe6, +0x09, 0xe6, 0x03, 0x98, 0x03, 0x29, 0x03, 0xbd, 0x03, 0x0b, 0x03, 0xe6, +0x06, 0xe6, 0x03, 0xc8, 0x03, 0x17, 0x03, 0xc1, 0x03, 0xc5, 0x03, 0x0b, 0x03, 0xe6, +0x03, 0xe6, 0x03, 0xe2, 0x03, 0x32, 0x03, 0x8f, 0x03, 0xe6, 0x03, 0xc5, 0x03, 0x0b, 0x03, 0xe6, +0x03, 0xe6, 0x03, 0x8a, 0x03, 0x07, 0x06, 0x49, 0x03, 0x3e, 0x03, 0x03, 0x03, 0x49, +0x03, 0xe6, 0x03, 0xc2, 0x09, 0x97, 0x03, 0x75, 0x03, 0x07, 0x03, 0x97, +0x0f, 0xe6, 0x03, 0xb2, 0x03, 0x0b, 0x03, 0xe6, +0x0f, 0xe6, 0x03, 0xb2, 0x03, 0x0b, 0x03, 0xe6, +0x18, 0xe6, + +}; +static const struct { + unsigned int num_w; + unsigned int num_h; + unsigned char num_pixel_data[0x82]; +} num_5 = { +/* w */ 8, +/* h */ 12, +/* pixel_data */ +0x18, 0xe6, +0x06, 0xe6, 0x03, 0xd7, 0x0c, 0x8a, 0x03, 0xaf, +0x06, 0xe6, 0x03, 0xc1, 0x03, 0x03, 0x09, 0x45, 0x03, 0x86, +0x06, 0xe6, 0x03, 0xc1, 0x03, 0x0d, 0x0c, 0xe6, +0x06, 0xe6, 0x03, 0xc1, 0x03, 0x0d, 0x0c, 0xe6, +0x06, 0xe6, 0x03, 0xc1, 0x03, 0x01, 0x03, 0x37, 0x03, 0x5e, 0x03, 0xc4, 0x03, 0xe6, +0x06, 0xe6, 0x03, 0xe0, 0x03, 0xc0, 0x03, 0x92, 0x03, 0x4c, 0x03, 0x08, 0x03, 0xbc, +0x03, 0xc6, 0x0c, 0xe6, 0x03, 0xe2, 0x03, 0x1b, 0x03, 0x56, +0x03, 0xd6, 0x0f, 0xe6, 0x03, 0x4b, 0x03, 0x3f, +0x06, 0xe6, 0x03, 0xe3, 0x06, 0xe6, 0x03, 0xcb, 0x03, 0x09, 0x03, 0x74, +0x06, 0xe6, 0x03, 0x9c, 0x03, 0x15, 0x03, 0x31, 0x03, 0x20, 0x03, 0x66, 0x03, 0xe0, +0x06, 0xe6, 0x03, 0xe2, 0x03, 0xc6, 0x03, 0xc2, 0x09, 0xe6, + +}; +static const struct { + unsigned int num_w; + unsigned int num_h; + unsigned char num_pixel_data[0x9c]; +} num_6 = { +/* w */ 9, +/* h */ 12, +/* pixel_data */ +0x1b, 0xe6, +0x0c, 0xe6, 0x03, 0xa9, 0x03, 0x6d, 0x03, 0x65, 0x03, 0x8d, 0x03, 0xdd, +0x09, 0xe6, 0x03, 0x6e, 0x03, 0x23, 0x03, 0x88, 0x03, 0x82, 0x03, 0x4c, 0x03, 0xcf, +0x06, 0xe6, 0x03, 0xbf, 0x03, 0x05, 0x03, 0xcd, 0x0c, 0xe6, +0x06, 0xe6, 0x03, 0x65, 0x03, 0x3d, 0x03, 0xe6, 0x03, 0xe5, 0x09, 0xe6, +0x06, 0xe6, 0x03, 0x46, 0x03, 0x50, 0x03, 0x56, 0x06, 0x15, 0x03, 0x86, 0x03, 0xe6, +0x06, 0xe6, 0x03, 0x32, 0x03, 0x03, 0x03, 0x9f, 0x03, 0xe2, 0x03, 0x99, 0x03, 0x02, 0x03, 0xce, +0x06, 0xe6, 0x03, 0x44, 0x03, 0x3f, 0x09, 0xe6, 0x03, 0x24, 0x03, 0x7b, +0x06, 0xe6, 0x03, 0x68, 0x03, 0x24, 0x09, 0xe6, 0x03, 0x37, 0x03, 0x71, +0x06, 0xe6, 0x03, 0xc2, 0x03, 00, 0x03, 0xa6, 0x03, 0xe6, 0x03, 0xc2, 0x03, 0x04, 0x03, 0xb6, +0x09, 0xe6, 0x03, 0x8f, 0x03, 0x06, 0x03, 0x26, 0x03, 0x09, 0x03, 0x84, 0x03, 0xe6, +0x0c, 0xe6, 0x03, 0xde, 0x03, 0xbc, 0x03, 0xdb, 0x06, 0xe6, + +}; +static const struct { + unsigned int num_w; + unsigned int num_h; + unsigned char num_pixel_data[0x68]; +} num_7 = { +/* w */ 8, +/* h */ 12, +/* pixel_data */ +0x18, 0xe6, +0x03, 0xe6, 0x03, 0xe2, 0x0f, 0x8a, 0x03, 0x8c, +0x03, 0xe6, 0x03, 0xdd, 0x0c, 0x32, 0x03, 0x24, 0x03, 0x07, +0x12, 0xe6, 0x03, 0x4d, 0x03, 0x67, +0x0f, 0xe6, 0x03, 0xa5, 0x03, 0x16, 0x03, 0xda, +0x0c, 0xe6, 0x03, 0xdd, 0x03, 0x1e, 0x03, 0x93, 0x03, 0xe6, +0x0c, 0xe6, 0x03, 0x6d, 0x03, 0x37, 0x06, 0xe6, +0x09, 0xe6, 0x03, 0xc8, 0x03, 0x05, 0x03, 0xb9, 0x06, 0xe6, +0x09, 0xe6, 0x03, 0x50, 0x03, 0x2a, 0x09, 0xe6, +0x06, 0xe6, 0x03, 0xd0, 0x03, 00, 0x03, 0x7b, 0x09, 0xe6, +0x06, 0xe6, 0x03, 0x92, 0x03, 00, 0x03, 0xca, 0x09, 0xe6, +0x18, 0xe6, + +}; +static const struct { + unsigned int num_w; + unsigned int num_h; + unsigned char num_pixel_data[0xa0]; +} num_8 = { +/* w */ 8, +/* h */ 12, +/* pixel_data */ +0x18, 0xe6, +0x09, 0xe6, 0x03, 0xd1, 0x03, 0x88, 0x03, 0x6b, 0x03, 0xae, 0x03, 0xe5, +0x06, 0xe6, 0x03, 0xd2, 0x03, 0x12, 0x03, 0x77, 0x03, 0x80, 0x03, 0x19, 0x03, 0x94, +0x06, 0xe6, 0x03, 0x76, 0x03, 0x56, 0x06, 0xe6, 0x03, 0x7f, 0x03, 0x46, +0x06, 0xe6, 0x03, 0x85, 0x03, 0x15, 0x03, 0xc3, 0x03, 0xe5, 0x03, 0x43, 0x03, 0x8c, +0x06, 0xe6, 0x03, 0xe2, 0x03, 0x4e, 0x03, 0x09, 0x03, 0x3a, 0x03, 0x76, 0x03, 0xe6, +0x06, 0xe6, 0x03, 0xcd, 0x03, 0x2b, 0x03, 0x60, 0x03, 0x0d, 0x03, 0x37, 0x03, 0xcd, +0x06, 0xe6, 0x03, 0x39, 0x03, 0x7f, 0x03, 0xe6, 0x03, 0xca, 0x03, 0x2f, 0x03, 0x30, +0x03, 0xe6, 0x03, 0xdb, 0x03, 0x02, 0x03, 0xb4, 0x06, 0xe6, 0x03, 0xb0, 0x03, 00, +0x03, 0xe6, 0x03, 0xe5, 0x03, 0x12, 0x03, 0x61, 0x03, 0xe4, 0x03, 0xe6, 0x03, 0x76, 0x03, 0x11, +0x06, 0xe6, 0x03, 0xa9, 0x03, 0x34, 0x03, 0x1b, 0x03, 0x24, 0x03, 0x3a, 0x03, 0xae, +0x0c, 0xe6, 0x03, 0xd1, 0x03, 0xd3, 0x06, 0xe6, + +}; +static const struct { + unsigned int num_w; + unsigned int num_h; + unsigned char num_pixel_data[0x96]; +} num_9 = { +/* w */ 8, +/* h */ 12, +/* pixel_data */ +0x18, 0xe6, +0x09, 0xe6, 0x03, 0xbf, 0x03, 0x6e, 0x03, 0x6c, 0x03, 0xb3, 0x03, 0xe6, +0x06, 0xe6, 0x03, 0xac, 0x03, 0x14, 0x03, 0x6e, 0x03, 0x63, 0x03, 0x0a, 0x03, 0x9b, +0x06, 0xe6, 0x03, 0x2f, 0x03, 0x70, 0x06, 0xe6, 0x03, 0x7c, 0x03, 0x1c, +0x03, 0xe6, 0x03, 0xe5, 0x03, 0x05, 0x03, 0xa2, 0x06, 0xe6, 0x03, 0xbd, 0x03, 00, +0x06, 0xe6, 0x03, 0x1a, 0x03, 0x6e, 0x06, 0xe6, 0x03, 0xa6, 0x03, 00, +0x06, 0xe6, 0x03, 0x88, 0x03, 0x12, 0x03, 0x80, 0x03, 0x90, 0x03, 0x39, 0x03, 00, +0x09, 0xe6, 0x03, 0x9c, 0x03, 0x52, 0x03, 0x6b, 0x03, 0x98, 0x03, 00, +0x03, 0xd1, 0x0f, 0xe6, 0x03, 0x74, 0x03, 0x19, +0x03, 0xe2, 0x03, 0xe6, 0x03, 0xde, 0x06, 0xe6, 0x03, 0xd3, 0x03, 0x23, 0x03, 0x85, +0x06, 0xe6, 0x03, 0x6c, 0x03, 0x15, 0x03, 0x37, 0x03, 0x14, 0x03, 0x79, 0x03, 0xe6, +0x09, 0xe6, 0x03, 0xcf, 0x03, 0xbc, 0x03, 0xe1, 0x06, 0xe6, + +}; +static const struct { + unsigned int num_w; + unsigned int num_h; + unsigned char num_pixel_data[0xa4]; +} num_a = { +/* w */ 10, +/* h */ 12, +/* pixel_data */ +0x1e, 0xe6, +0x0c, 0xe6, 0x03, 0xe2, 0x03, 0x8a, 0x03, 0xbf, 0x09, 0xe6, +0x0c, 0xe6, 0x03, 0x9c, 0x03, 00, 0x03, 0x43, 0x09, 0xe6, +0x03, 0xe3, 0x09, 0xe6, 0x03, 0x40, 0x03, 0x24, 0x03, 0x02, 0x03, 0xcd, 0x06, 0xe6, +0x03, 0xba, 0x06, 0xe6, 0x03, 0xca, 0x03, 0x02, 0x03, 0xc0, 0x03, 0x0e, 0x03, 0x76, 0x06, 0xe6, +0x03, 0xa0, 0x06, 0xe6, 0x03, 0x70, 0x03, 0x3f, 0x03, 0xe6, 0x03, 0x60, 0x03, 0x1d, 0x06, 0xe6, +0x03, 0xa3, 0x03, 0xe6, 0x03, 0xe3, 0x03, 0x18, 0x03, 0x9a, 0x03, 0xe6, 0x03, 0xbb, 0x03, 00, 0x03, 0xa8, 0x03, 0xe6, +0x03, 0xc0, 0x03, 0xe6, 0x03, 0xa0, 0x03, 00, 0x03, 0x58, 0x06, 0x5d, 0x03, 0x08, 0x03, 0x4e, 0x03, 0xe6, +0x03, 0xe1, 0x03, 0xe6, 0x03, 0x45, 0x03, 0x49, 0x09, 0x8a, 0x03, 0x5e, 0x03, 0x06, 0x03, 0xd5, +0x03, 0xe6, 0x03, 0xcd, 0x03, 0x02, 0x03, 0xc4, 0x09, 0xe6, 0x03, 0xda, 0x03, 0x09, 0x03, 0x80, +0x03, 0xe6, 0x03, 0x75, 0x03, 0x39, 0x0f, 0xe6, 0x03, 0x59, 0x03, 0x27, +0x1e, 0xe6, + +}; +static const struct { + unsigned int num_w; + unsigned int num_h; + unsigned char num_pixel_data[0x98]; +} num_b = { +/* w */ 7, +/* h */ 12, +/* pixel_data */ +0x15, 0xe6, +0x03, 0xe6, 0x03, 0xae, 0x03, 0x8a, 0x03, 0x8c, 0x03, 0xb1, 0x03, 0xe1, 0x03, 0xe6, +0x03, 0xe6, 0x03, 0x58, 0x03, 0x1b, 0x03, 0x4c, 0x03, 0x1b, 0x03, 0x09, 0x03, 0xc0, +0x03, 0xe6, 0x03, 0x58, 0x03, 0x43, 0x03, 0xe6, 0x03, 0xe2, 0x03, 0x1f, 0x03, 0x5a, +0x03, 0xe6, 0x03, 0x58, 0x03, 0x43, 0x03, 0xe6, 0x03, 0xe4, 0x03, 0x21, 0x03, 0x7b, +0x03, 0xe6, 0x03, 0x58, 0x03, 0x31, 0x03, 0x90, 0x03, 0x49, 0x03, 0x52, 0x03, 0xd8, +0x03, 0xe6, 0x03, 0x58, 0x03, 0x1c, 0x03, 0x44, 0x03, 0x0d, 0x03, 0x73, 0x03, 0xdd, +0x03, 0xe6, 0x03, 0x58, 0x03, 0x43, 0x03, 0xe6, 0x03, 0xdd, 0x03, 0x24, 0x03, 0x49, +0x03, 0xe6, 0x03, 0x58, 0x03, 0x43, 0x06, 0xe6, 0x03, 0x89, 0x03, 0x05, +0x03, 0xe6, 0x03, 0x58, 0x03, 0x43, 0x03, 0xe2, 0x03, 0xcc, 0x03, 0x3e, 0x03, 0x2a, +0x03, 0xe6, 0x03, 0x58, 0x06, 00, 0x03, 0x09, 0x03, 0x2f, 0x03, 0xb7, +0x15, 0xe6, + +}; +static const struct { + unsigned int num_w; + unsigned int num_h; + unsigned char num_pixel_data[0x8a]; +} num_c = { +/* w */ 9, +/* h */ 12, +/* pixel_data */ +0x1b, 0xe6, +0x09, 0xe6, 0x03, 0xd5, 0x03, 0x8c, 0x03, 0x65, 0x03, 0x66, 0x03, 0x87, 0x03, 0xab, +0x06, 0xe6, 0x03, 0xa8, 0x03, 0x14, 0x03, 0x3d, 0x03, 0x7e, 0x03, 0x80, 0x03, 0x56, 0x03, 0x2a, +0x03, 0xe6, 0x03, 0xd9, 0x03, 0x14, 0x03, 0x61, 0x0f, 0xe6, +0x03, 0xe6, 0x03, 0x86, 0x03, 0x08, 0x03, 0xd6, 0x0f, 0xe6, +0x03, 0xe6, 0x03, 0x62, 0x03, 0x27, 0x12, 0xe6, +0x03, 0xe6, 0x03, 0x50, 0x03, 0x36, 0x12, 0xe6, +0x03, 0xe6, 0x03, 0x6e, 0x03, 0x19, 0x12, 0xe6, +0x03, 0xde, 0x03, 0xa1, 0x03, 00, 0x03, 0xaa, 0x0f, 0xe6, +0x06, 0xe6, 0x03, 0x37, 0x03, 0x1b, 0x03, 0xb2, 0x06, 0xe6, 0x03, 0xd5, 0x03, 0x8a, +0x06, 0xe6, 0x03, 0xd8, 0x03, 0x58, 0x03, 0x03, 0x03, 0x13, 0x03, 0x1d, 0x03, 0x24, 0x03, 0x61, +0x0c, 0xe6, 0x03, 0xe1, 0x03, 0xc0, 0x03, 0xd1, 0x06, 0xe6, + +}; +static const struct { + unsigned int num_w; + unsigned int num_h; + unsigned char num_pixel_data[0xb2]; +} num_d = { +/* w */ 10, +/* h */ 12, +/* pixel_data */ +0x1e, 0xe6, +0x03, 0xe6, 0x03, 0xd9, 0x06, 0x8a, 0x03, 0x8b, 0x03, 0x9c, 0x03, 0xbb, 0x03, 0xdf, 0x06, 0xe6, +0x03, 0xe6, 0x03, 0xc5, 0x03, 00, 0x03, 0x49, 0x03, 0x55, 0x03, 0x3e, 0x03, 0x14, 0x03, 0x21, 0x03, 0xb6, 0x03, 0xe6, +0x03, 0xe6, 0x03, 0xc5, 0x03, 00, 0x03, 0xba, 0x06, 0xe6, 0x03, 0xda, 0x03, 0x49, 0x03, 0x0d, 0x03, 0xd4, +0x03, 0xe6, 0x03, 0xc5, 0x03, 00, 0x03, 0xba, 0x09, 0xe6, 0x03, 0xd4, 0x03, 0x09, 0x03, 0x79, +0x03, 0xe6, 0x03, 0xc5, 0x03, 00, 0x03, 0xba, 0x0c, 0xe6, 0x03, 0x2f, 0x03, 0x52, +0x03, 0xe6, 0x03, 0xc5, 0x03, 00, 0x03, 0xba, 0x0c, 0xe6, 0x03, 0x3c, 0x03, 0x4e, +0x03, 0xe6, 0x03, 0xc5, 0x03, 00, 0x03, 0xba, 0x0c, 0xe6, 0x03, 0x1d, 0x03, 0x70, +0x03, 0xe6, 0x03, 0xc5, 0x03, 00, 0x03, 0xba, 0x09, 0xe6, 0x03, 0xac, 0x03, 00, 0x03, 0xb6, +0x03, 0xe6, 0x03, 0xc5, 0x03, 00, 0x03, 0xba, 0x03, 0xe6, 0x03, 0xd1, 0x03, 0x9a, 0x03, 0x15, 0x03, 0x63, 0x03, 0xe6, +0x03, 0xe6, 0x03, 0xc5, 0x09, 00, 0x03, 0x12, 0x03, 0x37, 0x03, 0x95, 0x06, 0xe6, +0x1e, 0xe6, + +}; +static const struct { + unsigned int num_w; + unsigned int num_h; + unsigned char num_pixel_data[0x64]; +} num_e = { +/* w */ 7, +/* h */ 12, +/* pixel_data */ +0x15, 0xe6, +0x03, 0xe6, 0x03, 0xc1, 0x0c, 0x8a, 0x03, 0x99, +0x03, 0xe6, 0x03, 0x88, 0x03, 0x06, 0x09, 0x5b, 0x03, 0x71, +0x03, 0xe6, 0x03, 0x88, 0x03, 0x10, 0x0c, 0xe6, +0x03, 0xe6, 0x03, 0x88, 0x03, 0x10, 0x0c, 0xe6, +0x03, 0xe6, 0x03, 0x88, 0x03, 0x09, 0x09, 0x8d, 0x03, 0xd3, +0x03, 0xe6, 0x03, 0x88, 0x03, 0x06, 0x09, 0x5c, 0x03, 0xca, +0x03, 0xe6, 0x03, 0x88, 0x03, 0x10, 0x0c, 0xe6, +0x03, 0xe6, 0x03, 0x88, 0x03, 0x10, 0x0c, 0xe6, +0x03, 0xe6, 0x03, 0x88, 0x03, 0x10, 0x0c, 0xe6, +0x03, 0xe6, 0x03, 0x88, 0x0f, 00, +0x15, 0xe6, + +}; +static const struct { + unsigned int num_w; + unsigned int num_h; + unsigned char num_pixel_data[0x66]; +} num_f = { +/* w */ 7, +/* h */ 12, +/* pixel_data */ +0x15, 0xe6, +0x03, 0xe6, 0x03, 0xc5, 0x0c, 0x8a, 0x03, 0x95, +0x03, 0xe6, 0x03, 0x93, 0x03, 0x01, 0x09, 0x5b, 0x03, 0x6b, +0x03, 0xe6, 0x03, 0x93, 0x03, 0x06, 0x0c, 0xe6, +0x03, 0xe6, 0x03, 0x93, 0x03, 0x06, 0x0c, 0xe6, +0x03, 0xe6, 0x03, 0x93, 0x03, 0x04, 0x09, 0xad, 0x03, 0xd7, +0x03, 0xe6, 0x03, 0x93, 0x03, 00, 0x09, 0x3d, 0x03, 0xba, +0x03, 0xe6, 0x03, 0x93, 0x03, 0x06, 0x0c, 0xe6, +0x03, 0xe6, 0x03, 0x93, 0x03, 0x06, 0x0c, 0xe6, +0x03, 0xe6, 0x03, 0x93, 0x03, 0x06, 0x0c, 0xe6, +0x03, 0xcb, 0x03, 0x93, 0x03, 0x06, 0x0c, 0xe6, +0x15, 0xe6, + +}; +static const struct { + unsigned int num_w; + unsigned int num_h; + unsigned char num_pixel_data[0x3c]; +} num_colon = { +/* w */ 4, +/* h */ 12, +/* pixel_data */ +0x0c, 0xe6, +0x0c, 0xe6, +0x0c, 0xe6, +0x0c, 0xe6, +0x03, 0xe6, 0x03, 0xc1, 0x03, 0x18, 0x03, 0xd6, +0x03, 0xe6, 0x03, 0xd7, 0x03, 0x93, 0x03, 0xe0, +0x0c, 0xe6, +0x0c, 0xe6, +0x0c, 0xe6, +0x03, 0xe6, 0x03, 0xdc, 0x03, 0xac, 0x03, 0xe2, +0x03, 0xe6, 0x03, 0xbe, 0x03, 00, 0x03, 0xd4, +0x0c, 0xe6, + +}; diff --git a/osfmk/ppc/POWERMAC/video_console.c b/osfmk/ppc/POWERMAC/video_console.c index 907aef682..61a510e97 100644 --- a/osfmk/ppc/POWERMAC/video_console.c +++ b/osfmk/ppc/POWERMAC/video_console.c @@ -112,6 +112,12 @@ #include #include +#include + +#include "panic_image.c" +#include "rendered_numbers.c" + + #define FAST_JUMP_SCROLL #define CHARWIDTH 8 @@ -162,6 +168,50 @@ static void vc_putchar(char ch); void vcattach(void); +/* panic dialog and info saving */ +int mac_addr_digit_x; +int mac_addr_digit_y; +static void blit_digit( int digit ); +boolean_t panicDialogDrawn = FALSE; + +static void +panic_blit_rect( unsigned int x, unsigned int y, + unsigned int width, unsigned int height, + int transparent, unsigned char * dataPtr ); + +static void +panic_blit_rect_8( unsigned int x, unsigned int y, + unsigned int width, unsigned int height, + int transparent, unsigned char * dataPtr ); + +static void +panic_blit_rect_16( unsigned int x, unsigned int y, + unsigned int width, unsigned int height, + int transparent, unsigned char * dataPtr ); + +static void +panic_blit_rect_32( unsigned int x, unsigned int y, + unsigned int width, unsigned int height, + int transparent, unsigned char * dataPtr ); + +static void +blit_rect_of_size_and_color( unsigned int x, unsigned int y, + unsigned int width, unsigned int height, + unsigned int dataPtr ); + +static void +dim_screen(void); + +/*static void +dim_screen8(void); +*/ + +static void +dim_screen16(void); + +static void +dim_screen32(void); + /* * For the color support (Michel Pollet) @@ -1893,32 +1943,41 @@ struct vc_progress_element { typedef struct vc_progress_element vc_progress_element; static vc_progress_element * vc_progress; -static unsigned char * vc_progress_data; +static const unsigned char * vc_progress_data; +static const unsigned char * vc_progress_alpha; static boolean_t vc_progress_enable; -static unsigned char * vc_clut; +static const unsigned char * vc_clut; +static const unsigned char * vc_clut8; +static unsigned char vc_revclut8[256]; static unsigned int vc_progress_tick; static boolean_t vc_graphics_mode; static boolean_t vc_acquired; static boolean_t vc_need_clear; +static boolean_t vc_needsave; +static vm_address_t vc_saveunder; +static vm_size_t vc_saveunder_len; static void vc_blit_rect_8c( int x, int y, - int width, int height, - int transparent, unsigned char * dataPtr ) + int width, int height, + const unsigned char * dataPtr, + const unsigned char * alphaPtr, + unsigned char * backPtr, + boolean_t save, boolean_t static_alpha ) { volatile unsigned char * dst; int line, col; - unsigned char data; + unsigned int data; + unsigned char alpha; dst = (unsigned char *)(vinfo.v_baseaddr + - (y * vinfo.v_rowbytes) + - (x)); + (y * vinfo.v_rowbytes) + + (x)); for( line = 0; line < height; line++) { for( col = 0; col < width; col++) { - data = *dataPtr++; - if( data == transparent) - continue; - + data = 0; + if( dataPtr != 0) data = *dataPtr++; + else if( alphaPtr != 0) data = vc_revclut8[*alphaPtr++]; *(dst + col) = data; } dst = (volatile unsigned char *) (((int)dst) + vinfo.v_rowbytes); @@ -1926,105 +1985,643 @@ static void vc_blit_rect_8c( int x, int y, } -static void vc_blit_rect_8m( int x, int y, - int width, int height, - int transparent, unsigned char * dataPtr ) +static void vc_blit_rect_16( int x, int y, + int width, int height, + const unsigned char * dataPtr, + const unsigned char * alphaPtr, + unsigned short * backPtr, + boolean_t save, boolean_t static_alpha ) { - volatile unsigned char * dst; + volatile unsigned short * dst; int line, col; - unsigned int data; + unsigned int data, index, alpha, back; - dst = (unsigned char *)(vinfo.v_baseaddr + + dst = (volatile unsigned short *)(vinfo.v_baseaddr + (y * vinfo.v_rowbytes) + - (x)); + (x * 2)); for( line = 0; line < height; line++) { for( col = 0; col < width; col++) { - data = *dataPtr++; - if( data == transparent) - continue; + if( dataPtr != 0) { + index = *dataPtr++; + index *= 3; + } + + if( alphaPtr && backPtr) { + + alpha = *alphaPtr++; + data = 0; + if( dataPtr != 0) { + if( vc_clut[index + 0] > alpha) + data |= (((vc_clut[index + 0] - alpha) & 0xf8) << 7); + if( vc_clut[index + 1] > alpha) + data |= (((vc_clut[index + 1] - alpha) & 0xf8) << 2); + if( vc_clut[index + 2] > alpha) + data |= (((vc_clut[index + 2] - alpha) & 0xf8) >> 3); + } + + if( save) { + back = *(dst + col); + if ( !static_alpha) + *backPtr++ = back; + back = (((((back & 0x7c00) * alpha) + 0x3fc00) >> 8) & 0x7c00) + | (((((back & 0x03e0) * alpha) + 0x01fe0) >> 8) & 0x03e0) + | (((((back & 0x001f) * alpha) + 0x000ff) >> 8) & 0x001f); + if ( static_alpha) + *backPtr++ = back; + } else { + back = *backPtr++; + if ( !static_alpha) { + back = (((((back & 0x7c00) * alpha) + 0x3fc00) >> 8) & 0x7c00) + | (((((back & 0x03e0) * alpha) + 0x01fe0) >> 8) & 0x03e0) + | (((((back & 0x001f) * alpha) + 0x000ff) >> 8) & 0x001f); + } + } - data *= 3; - *(dst + col) = ((19595 * vc_clut[data + 0] + - 38470 * vc_clut[data + 1] + - 7471 * vc_clut[data + 2] ) / 65536); + data += back; + + } else + if( dataPtr != 0) { + data = ( (0xf8 & (vc_clut[index + 0])) << 7) + | ( (0xf8 & (vc_clut[index + 1])) << 2) + | ( (0xf8 & (vc_clut[index + 2])) >> 3); + } + + *(dst + col) = data; } - dst = (volatile unsigned char *) (((int)dst) + vinfo.v_rowbytes); + dst = (volatile unsigned short *) (((int)dst) + vinfo.v_rowbytes); } } +static void vc_blit_rect_32( unsigned int x, unsigned int y, + unsigned int width, unsigned int height, + const unsigned char * dataPtr, + const unsigned char * alphaPtr, + unsigned int * backPtr, + boolean_t save, boolean_t static_alpha ) +{ + volatile unsigned int * dst; + int line, col; + unsigned int data, index, alpha, back; + dst = (volatile unsigned int *) (vinfo.v_baseaddr + + (y * vinfo.v_rowbytes) + + (x * 4)); -static void vc_blit_rect_16( int x, int y, - int width, int height, + for( line = 0; line < height; line++) { + for( col = 0; col < width; col++) { + if( dataPtr != 0) { + index = *dataPtr++; + index *= 3; + } + + if( alphaPtr && backPtr) { + + alpha = *alphaPtr++; + data = 0; + if( dataPtr != 0) { + if( vc_clut[index + 0] > alpha) + data |= ((vc_clut[index + 0] - alpha) << 16); + if( vc_clut[index + 1] > alpha) + data |= ((vc_clut[index + 1] - alpha) << 8); + if( vc_clut[index + 2] > alpha) + data |= ((vc_clut[index + 2] - alpha)); + } + + if( save) { + back = *(dst + col); + if ( !static_alpha) + *backPtr++ = back; + back = (((((back & 0x00ff00ff) * alpha) + 0x00ff00ff) >> 8) & 0x00ff00ff) + | (((((back & 0x0000ff00) * alpha) + 0x0000ff00) >> 8) & 0x0000ff00); + if ( static_alpha) + *backPtr++ = back; + } else { + back = *backPtr++; + if ( !static_alpha) { + back = (((((back & 0x00ff00ff) * alpha) + 0x00ff00ff) >> 8) & 0x00ff00ff) + | (((((back & 0x0000ff00) * alpha) + 0x0000ff00) >> 8) & 0x0000ff00); + } + } + + data += back; + + } else + if( dataPtr != 0) { + data = (vc_clut[index + 0] << 16) + | (vc_clut[index + 1] << 8) + | (vc_clut[index + 2]); + } + + *(dst + col) = data; + } + dst = (volatile unsigned int *) (((int)dst) + vinfo.v_rowbytes); + } +} + +void +draw_panic_dialog( void ) +{ + int pd_x,pd_y, iconx, icony, tx_line, tx_col; + int line_width = 1; + int f1, f2, d1, d2, d3, rem; + char *pair = "ff"; + int count = 0; + char digit; + int nibble; + char colon = ':'; + char dot = '.'; + struct ether_addr kdp_mac_addr = kdp_get_mac_addr(); + unsigned int ip_addr = kdp_get_ip_address(); + + + if (!panicDialogDrawn) + { + if ( !logPanicDataToScreen ) + { + + /* dim the screen 50% before putting up panic dialog */ + dim_screen(); + + /* set up to draw background box */ + pd_x = (vinfo.v_width/2) - panic_dialog.pd_width/2; + pd_y = (vinfo.v_height/2) - panic_dialog.pd_height/2; + + /* draw image */ + panic_blit_rect( pd_x, pd_y, panic_dialog.pd_width, panic_dialog.pd_height, 0, (unsigned char*) panic_dialog.image_pixel_data); + + /* offset for mac address text */ + mac_addr_digit_x = (vinfo.v_width/2) - 130; /* use 62 if no ip */ + mac_addr_digit_y = (vinfo.v_height/2) + panic_dialog.pd_height/2 - 20; + + if(kdp_mac_addr.ether_addr_octet[0] || kdp_mac_addr.ether_addr_octet[1]|| kdp_mac_addr.ether_addr_octet[2] + || kdp_mac_addr.ether_addr_octet[3] || kdp_mac_addr.ether_addr_octet[4] || kdp_mac_addr.ether_addr_octet[5]) + { + /* blit the digits for mac address */ + for (count = 0; count < 6; count++ ) + { + nibble = (kdp_mac_addr.ether_addr_octet[count] & 0xf0) >> 4; + digit = nibble < 10 ? nibble + '0':nibble - 10 + 'a'; + blit_digit(digit); + + nibble = kdp_mac_addr.ether_addr_octet[count] & 0xf; + digit = nibble < 10 ? nibble + '0':nibble - 10 + 'a'; + blit_digit(digit); + if( count < 5 ) + blit_digit( colon ); + } + } + else /* blit the ff's */ + { + for( count = 0; count < 6; count++ ) + { + digit = pair[0]; + blit_digit(digit); + digit = pair[1]; + blit_digit(digit); + if( count < 5 ) + blit_digit( colon ); + } + } + /* now print the ip address */ + mac_addr_digit_x = (vinfo.v_width/2) + 10; + if(ip_addr != 0) + { + /* blit the digits for ip address */ + for (count = 0; count < 4; count++ ) + { + nibble = (ip_addr & 0xff000000 ) >> 24; + + d3 = (nibble % 0xa) + '0'; + nibble = nibble/0xa; + d2 = (nibble % 0xa) + '0'; + nibble = nibble /0xa; + d1 = (nibble % 0xa) + '0'; + + if( d1 ) blit_digit(d1); + blit_digit(d2); + blit_digit(d3); + if( count < 3 ) + blit_digit(dot); + + d1= d2 = d3 = 0; + ip_addr = ip_addr << 8; + } + } + } + } + panicDialogDrawn = TRUE; + +} + + +static void +blit_digit( int digit ) +{ + switch( digit ) + { + case '0': { + panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_0.num_w, num_0.num_h, 255, (unsigned char*) num_0.num_pixel_data); + mac_addr_digit_x = mac_addr_digit_x + num_0.num_w - 1; + break; + } + case '1': { + panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_1.num_w, num_1.num_h, 255, (unsigned char*) num_1.num_pixel_data); + mac_addr_digit_x = mac_addr_digit_x + num_1.num_w ; + break; + } + case '2': { + panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_2.num_w, num_2.num_h, 255, (unsigned char*) num_2.num_pixel_data); + mac_addr_digit_x = mac_addr_digit_x + num_2.num_w ; + break; + } + case '3': { + panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_3.num_w, num_3.num_h, 255, (unsigned char*) num_3.num_pixel_data); + mac_addr_digit_x = mac_addr_digit_x + num_3.num_w ; + break; + } + case '4': { + panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_4.num_w, num_4.num_h, 255, (unsigned char*) num_4.num_pixel_data); + mac_addr_digit_x = mac_addr_digit_x + num_4.num_w ; + break; + } + case '5': { + panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_5.num_w, num_5.num_h, 255, (unsigned char*) num_5.num_pixel_data); + mac_addr_digit_x = mac_addr_digit_x + num_5.num_w ; + break; + } + case '6': { + panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_6.num_w, num_6.num_h, 255, (unsigned char*) num_6.num_pixel_data); + mac_addr_digit_x = mac_addr_digit_x + num_6.num_w ; + break; + } + case '7': { + panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_7.num_w, num_7.num_h, 255, (unsigned char*) num_7.num_pixel_data); + mac_addr_digit_x = mac_addr_digit_x + num_7.num_w ; + break; + } + case '8': { + panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_8.num_w, num_8.num_h, 255, (unsigned char*) num_8.num_pixel_data); + mac_addr_digit_x = mac_addr_digit_x + num_8.num_w ; + break; + } + case '9': { + panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_9.num_w, num_9.num_h, 255, (unsigned char*) num_9.num_pixel_data); + mac_addr_digit_x = mac_addr_digit_x + num_9.num_w ; + break; + } + case 'a': { + panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_a.num_w, num_a.num_h, 255, (unsigned char*) num_a.num_pixel_data); + mac_addr_digit_x = mac_addr_digit_x + num_a.num_w ; + break; + } + case 'b': { + panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_b.num_w, num_b.num_h, 255, (unsigned char*) num_b.num_pixel_data); + mac_addr_digit_x = mac_addr_digit_x + num_b.num_w ; + break; + } + case 'c': { + panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_c.num_w, num_c.num_h, 255, (unsigned char*) num_c.num_pixel_data); + mac_addr_digit_x = mac_addr_digit_x + num_c.num_w ; + break; + } + case 'd': { + panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_d.num_w, num_d.num_h, 255, (unsigned char*) num_d.num_pixel_data); + mac_addr_digit_x = mac_addr_digit_x + num_d.num_w ; + break; + } + case 'e': { + panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_e.num_w, num_e.num_h, 255, (unsigned char*) num_e.num_pixel_data); + mac_addr_digit_x = mac_addr_digit_x + num_e.num_w ; + break; + } + case 'f': { + panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_f.num_w, num_f.num_h, 255, (unsigned char*) num_f.num_pixel_data); + mac_addr_digit_x = mac_addr_digit_x + num_f.num_w ; + break; + } + case ':': { + panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_colon.num_w, num_colon.num_h, 255, (unsigned char*) num_colon.num_pixel_data); + mac_addr_digit_x = mac_addr_digit_x + num_colon.num_w; + break; + } + case '.': { + panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y + (num_colon.num_h/2), num_colon.num_w, num_colon.num_h/2, 255, (unsigned char*) num_colon.num_pixel_data); + mac_addr_digit_x = mac_addr_digit_x + num_colon.num_w; + break; + } + default: + break; + + } +} + +static void +panic_blit_rect( unsigned int x, unsigned int y, + unsigned int width, unsigned int height, int transparent, unsigned char * dataPtr ) { - volatile unsigned short * dst; + if(!vinfo.v_depth) + return; + + switch( vinfo.v_depth) { + case 8: + panic_blit_rect_8( x, y, width, height, transparent, dataPtr); + break; + case 16: + panic_blit_rect_16( x, y, width, height, transparent, dataPtr); + break; + case 32: + panic_blit_rect_32( x, y, width, height, transparent, dataPtr); + break; + } +} + +/* panic_blit_rect_8 is not tested and probably doesn't draw correctly. + it really needs a clut to use +*/ +static void +panic_blit_rect_8( unsigned int x, unsigned int y, + unsigned int width, unsigned int height, + int transparent, unsigned char * dataPtr ) +{ + volatile unsigned int * dst; int line, col; - unsigned int data; + unsigned int pixelR, pixelG, pixelB; - dst = (volatile unsigned short *)(vinfo.v_baseaddr + + dst = (volatile unsigned int *) (vinfo.v_baseaddr + (y * vinfo.v_rowbytes) + - (x * 2)); + x); for( line = 0; line < height; line++) { for( col = 0; col < width; col++) { - data = *dataPtr++; - if( data == transparent) - continue; + pixelR = *dataPtr++; + pixelG = *dataPtr++; + pixelB = *dataPtr++; + if(( pixelR != transparent) || (pixelG != transparent) || (pixelB != transparent)) + { + *(dst + col) = ((19595 * pixelR + + 38470 * pixelG + + 7471 * pixelB ) / 65536); + } + + } + dst = (volatile unsigned int *) (((int)dst) + vinfo.v_rowbytes); + } +} + +/* panic_blit_rect_16 draws adequately. It would be better if it had a clut + to use instead of scaling the 32bpp color values. + + panic_blit_rect_16 decodes the RLE encoded image data on the fly, scales it down + to 16bpp, and fills in each of the three pixel values (RGB) for each pixel + and writes it to the screen. + +*/ +static void +panic_blit_rect_16( unsigned int x, unsigned int y, + unsigned int width, unsigned int height, + int transparent, unsigned char * dataPtr ) +{ + volatile unsigned int * dst; + int line, value, total = 0; + unsigned int quantity, tmp, pixel; + int pix_pos = 2; + int w = width / 2; + boolean_t secondTime = 0; + int pix_incr = 0; + - data *= 3; + dst = (volatile unsigned int *) (vinfo.v_baseaddr + + (y * vinfo.v_rowbytes) + + (x * 2)); + +/* *(dst + col) = ( (0xf8 & (vc_clut[data + 0])) << 7) | ( (0xf8 & (vc_clut[data + 1])) << 2) | ( (0xf8 & (vc_clut[data + 2])) >> 3); - } - dst = (volatile unsigned short *) (((int)dst) + vinfo.v_rowbytes); + +*/ + for( line = 0; line < height; line++) + { + while ( total < width ) + { + quantity = *dataPtr++; + value = *dataPtr++; + value = (0x1f * value)/255; + while( quantity > 0 ) + { + switch( pix_pos ) + { + case 2: /* red */ + { + tmp |= (value << 10) & 0x7c00; + // tmp |= (value & 0xf8) << 7; + quantity--; + pix_pos--; + break; + } + case 1: /* green */ + { + tmp |= (value << 5) & 0x3e0; + // tmp |= (value & 0xf8) << 2; + quantity--; + pix_pos--; + break; + } + default: /* blue */ + { + tmp |= value & 0x1f; + // tmp |= (value & 0xf8) >> 3; + total++; + quantity--; + pix_pos = 2; + if( secondTime ) + { + pixel |= tmp; + secondTime = 0; + *(dst + pix_incr++) = pixel; + tmp = 0; + pixel = 0; + } + else + { + pixel = tmp << 16; + secondTime = 1; + } + break; + } + } + } + } + dst = (volatile unsigned int *) (((int)dst) + vinfo.v_rowbytes); + total = 0; + pix_incr = 0; } } -static void vc_blit_rect_32( unsigned int x, unsigned int y, +/* + panic_blit_rect_32 decodes the RLE encoded image data on the fly, and fills + in each of the three pixel values (RGB) for each pixel and writes it to the + screen. +*/ +static void +panic_blit_rect_32( unsigned int x, unsigned int y, unsigned int width, unsigned int height, int transparent, unsigned char * dataPtr ) { volatile unsigned int * dst; - int line, col; - unsigned int data; + int line, total = 0; + unsigned int value, quantity, tmp; + int pix_pos = 2; dst = (volatile unsigned int *) (vinfo.v_baseaddr + (y * vinfo.v_rowbytes) + (x * 4)); - for( line = 0; line < height; line++) { - for( col = 0; col < width; col++) { - data = *dataPtr++; - if( data == transparent) - continue; - - data *= 3; - *(dst + col) = (vc_clut[data + 0] << 16) - | (vc_clut[data + 1] << 8) - | (vc_clut[data + 2]); - } + for( line = 0; line < height; line++) + { + while ( total < width ) + { + quantity = *dataPtr++; + value = *dataPtr++; + while( quantity > 0 ) + { + switch( pix_pos ) + { + case 2: + { + tmp = value << 16; + quantity--; + pix_pos--; + break; + } + case 1: + { + tmp |= value << 8; + quantity--; + pix_pos--; + break; + } + default: + { + tmp |= value; + *(dst + total) = tmp; + total++; + quantity--; + pix_pos = 2; + break; + } + + } + } + + } dst = (volatile unsigned int *) (((int)dst) + vinfo.v_rowbytes); + total = 0; } } -static void vc_blit_rect( int x, int y, - int width, int height, - int transparent, unsigned char * dataPtr ) +static void +dim_screen(void) +{ + if(!vinfo.v_depth) + return; + + switch( vinfo.v_depth) { + /*case 8: + dim_screen8(); + break; + */ + case 16: + dim_screen16(); + break; + case 32: + dim_screen32(); + break; + } +} + +static void +dim_screen16(void) +{ + unsigned long *p, *endp, *row; + int linelongs, col; + int rowline, rowlongs; + unsigned long value, tmp; + + rowline = vinfo.v_rowscanbytes / 4; + rowlongs = vinfo.v_rowbytes / 4; + + p = (unsigned long*) vinfo.v_baseaddr;; + endp = (unsigned long*) vinfo.v_baseaddr; + + linelongs = vinfo.v_rowbytes * CHARHEIGHT / 4; + endp += rowlongs * vinfo.v_height; + + for (row = p ; row < endp ; row += rowlongs) { + for (col = 0; col < rowline; col++) { + value = *(row+col); + tmp = ((value & 0x7C007C00) >> 1) & 0x3C003C00; + tmp |= ((value & 0x03E003E0) >> 1) & 0x01E001E0; + tmp |= ((value & 0x001F001F) >> 1) & 0x000F000F; + *(row+col) = tmp; //half (dimmed)? + } + + } + +} + +static void +dim_screen32(void) +{ + unsigned long *p, *endp, *row; + int linelongs, col; + int rowline, rowlongs; + unsigned long value, tmp; + + rowline = vinfo.v_rowscanbytes / 4; + rowlongs = vinfo.v_rowbytes / 4; + + p = (unsigned long*) vinfo.v_baseaddr;; + endp = (unsigned long*) vinfo.v_baseaddr; + + linelongs = vinfo.v_rowbytes * CHARHEIGHT / 4; + endp += rowlongs * vinfo.v_height; + + for (row = p ; row < endp ; row += rowlongs) { + for (col = 0; col < rowline; col++) { + value = *(row+col); + tmp = ((value & 0x00FF0000) >> 1) & 0x007F0000; + tmp |= ((value & 0x0000FF00) >> 1) & 0x00007F00; + tmp |= (value & 0x000000FF) >> 1; + *(row+col) = tmp; //half (dimmed)? + } + + } + +} + +static void vc_blit_rect( unsigned int x, unsigned int y, + unsigned int width, unsigned int height, + const unsigned char * dataPtr, + const unsigned char * alphaPtr, + vm_address_t backBuffer, + boolean_t save, boolean_t static_alpha ) { if(!vinfo.v_baseaddr) return; switch( vinfo.v_depth) { case 8: - vc_blit_rect_8c( x, y, width, height, transparent, dataPtr); + if( vc_clut8 == vc_clut) + vc_blit_rect_8c( x, y, width, height, dataPtr, alphaPtr, (unsigned char *) backBuffer, save, static_alpha ); break; case 16: - vc_blit_rect_16( x, y, width, height, transparent, dataPtr); + vc_blit_rect_16( x, y, width, height, dataPtr, alphaPtr, (unsigned short *) backBuffer, save, static_alpha ); break; case 32: - vc_blit_rect_32( x, y, width, height, transparent, dataPtr); + vc_blit_rect_32( x, y, width, height, dataPtr, alphaPtr, (unsigned int *) backBuffer, save, static_alpha ); break; } } @@ -2034,12 +2631,13 @@ static void vc_progress_task( void * arg ) spl_t s; int count = (int) arg; int x, y, width, height; - unsigned char * data; + const unsigned char * data; s = splhigh(); simple_lock(&vc_forward_lock); if( vc_progress_enable) { + count++; if( count >= vc_progress->count) count = 0; @@ -2051,11 +2649,13 @@ static void vc_progress_task( void * arg ) data = vc_progress_data; data += count * width * height; if( 1 & vc_progress->flags) { - x += (vinfo.v_width / 2); - x += (vinfo.v_height / 2); + x += ((vinfo.v_width - width) / 2); + y += ((vinfo.v_height - height) / 2); } vc_blit_rect( x, y, width, height, - vc_progress->transparent,data ); + NULL, data, vc_saveunder, + vc_needsave, (0 == (4 & vc_progress->flags)) ); + vc_needsave = FALSE; timeout( vc_progress_task, (void *) count, vc_progress_tick ); @@ -2065,7 +2665,7 @@ static void vc_progress_task( void * arg ) } void vc_display_icon( vc_progress_element * desc, - unsigned char * data ) + const unsigned char * data ) { int x, y, width, height; @@ -2076,51 +2676,144 @@ void vc_display_icon( vc_progress_element * desc, x = desc->dx; y = desc->dy; if( 1 & desc->flags) { - x += (vinfo.v_width / 2); - y += (vinfo.v_height / 2); + x += ((vinfo.v_width - width) / 2); + y += ((vinfo.v_height - height) / 2); } - vc_blit_rect( x, y, width, height, desc->transparent, data ); + vc_blit_rect( x, y, width, height, data, NULL, (vm_address_t) NULL, FALSE, TRUE ); } } +static boolean_t ignore_first_enable = TRUE; + static boolean_t -vc_progress_set( boolean_t enable ) +vc_progress_set( boolean_t enable, unsigned int initial_tick ) { - spl_t s; + spl_t s; + vm_address_t saveBuf = 0; + vm_size_t saveLen = 0; + unsigned int count; + unsigned int index; + unsigned char data8; + unsigned short data16; + unsigned short * buf16; + unsigned int data32; + unsigned int * buf32; if( !vc_progress) return( FALSE ); + if( enable & ignore_first_enable) { + enable = FALSE; + ignore_first_enable = FALSE; + } + + if( enable) { + saveLen = vc_progress->width * vc_progress->height * vinfo.v_depth / 8; + saveBuf = kalloc( saveLen ); + + if( !vc_need_clear) switch( vinfo.v_depth) { + case 8 : + for( count = 0; count < 256; count++) { + vc_revclut8[count] = vc_clut[0x01 * 3]; + data8 = (vc_clut[0x01 * 3] * count + 0x0ff) >> 8; + for( index = 0; index < 256; index++) { + if( (data8 == vc_clut[index * 3 + 0]) && + (data8 == vc_clut[index * 3 + 1]) && + (data8 == vc_clut[index * 3 + 2])) { + vc_revclut8[count] = index; + break; + } + } + } + memset( (void *) saveBuf, 0x01, saveLen ); + break; + + case 16 : + buf16 = (unsigned short *) saveBuf; + data16 = ((vc_clut[0x01 * 3 + 0] & 0xf8) << 7) + | ((vc_clut[0x01 * 3 + 0] & 0xf8) << 2) + | ((vc_clut[0x01 * 3 + 0] & 0xf8) >> 3); + for( count = 0; count < saveLen / 2; count++) + buf16[count] = data16; + break; + + case 32 : + buf32 = (unsigned int *) saveBuf; + data32 = ((vc_clut[0x01 * 3 + 0] & 0xff) << 16) + | ((vc_clut[0x01 * 3 + 1] & 0xff) << 8) + | ((vc_clut[0x01 * 3 + 2] & 0xff) << 0); + for( count = 0; count < saveLen / 4; count++) + buf32[count] = data32; + break; + } + } + s = splhigh(); simple_lock(&vc_forward_lock); if( vc_progress_enable != enable) { vc_progress_enable = enable; - if( enable) + if( enable) { + vc_needsave = vc_need_clear; + vc_saveunder = saveBuf; + vc_saveunder_len = saveLen; + saveBuf = 0; + saveLen = 0; timeout(vc_progress_task, (void *) 0, - vc_progress_tick ); - else + initial_tick ); + } else { + if( vc_saveunder) { + saveBuf = vc_saveunder; + saveLen = vc_saveunder_len; + vc_saveunder = 0; + vc_saveunder_len = 0; + } untimeout( vc_progress_task, (void *) 0 ); + } + } + + if( !enable) { + vc_forward_buffer_size = 0; + untimeout((timeout_fcn_t)vc_flush_forward_buffer, (void *)0); + + /* Spin if the flush is in progress */ + while (vc_forward_buffer_busy) { + simple_unlock(&vc_forward_lock); + splx(s); + /* wait */ + s = splhigh(); + simple_lock(&vc_forward_lock); + vc_forward_buffer_size = 0; + } } simple_unlock(&vc_forward_lock); splx(s); + if( saveBuf) + kfree( saveBuf, saveLen ); + return( TRUE ); } boolean_t vc_progress_initialize( vc_progress_element * desc, - unsigned char * data, - unsigned char * clut ) + const unsigned char * data, + const unsigned char * clut ) { if( (!clut) || (!desc) || (!data)) return( FALSE ); vc_clut = clut; + vc_clut8 = clut; vc_progress = desc; vc_progress_data = data; + if( 2 & vc_progress->flags) + vc_progress_alpha = vc_progress_data + + vc_progress->count * vc_progress->width * vc_progress->height; + else + vc_progress_alpha = NULL; vc_progress_tick = vc_progress->time * hz / 1000; return( TRUE ); @@ -2179,7 +2872,7 @@ initialize_screen(Boot_Video * boot_vinfo, unsigned int op) break; case kPETextScreen: - vc_progress_set( FALSE ); + vc_progress_set( FALSE, 0 ); disableConsoleOutput = FALSE; if( vc_need_clear) { vc_need_clear = FALSE; @@ -2190,20 +2883,20 @@ initialize_screen(Boot_Video * boot_vinfo, unsigned int op) case kPEEnableScreen: if( vc_acquired) { if( vc_graphics_mode) - vc_progress_set( TRUE ); + vc_progress_set( TRUE, vc_progress_tick ); else vc_clear_screen(); } break; case kPEDisableScreen: - vc_progress_set( FALSE ); + vc_progress_set( FALSE, 0 ); break; case kPEAcquireScreen: vc_need_clear = (FALSE == vc_acquired); vc_acquired = TRUE; - vc_progress_set( vc_graphics_mode ); + vc_progress_set( vc_graphics_mode, vc_need_clear ? 2 * hz : 0 ); disableConsoleOutput = vc_graphics_mode; if( vc_need_clear && !vc_graphics_mode) { vc_need_clear = FALSE; @@ -2213,7 +2906,8 @@ initialize_screen(Boot_Video * boot_vinfo, unsigned int op) case kPEReleaseScreen: vc_acquired = FALSE; - vc_progress_set( FALSE ); + vc_progress_set( FALSE, 0 ); + vc_clut8 = NULL; disableConsoleOutput = TRUE; #if 0 GratefulDebInit(0); /* Stop grateful debugger */ diff --git a/osfmk/ppc/POWERMAC/video_scroll.s b/osfmk/ppc/POWERMAC/video_scroll.s index f7d2611a3..c7931c150 100644 --- a/osfmk/ppc/POWERMAC/video_scroll.s +++ b/osfmk/ppc/POWERMAC/video_scroll.s @@ -41,6 +41,8 @@ ENTRY(video_scroll_up, TAG_NO_FRAME_USED) mfmsr r0 /* Get the MSR */ + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off mflr r6 /* Get the LR */ ori r7,r0,1<<(31-MSR_FP_BIT) /* Turn on floating point */ stwu r1,-(FM_SIZE+16)(r1) /* Get space for a couple of registers on stack */ @@ -52,8 +54,6 @@ ENTRY(video_scroll_up, TAG_NO_FRAME_USED) vsufpuon1: stfd f0,(FM_SIZE+0)(r1) /* Save one register */ stfd f1,(FM_SIZE+8)(r1) /* and the second */ - - stw r0,(FM_SIZE+FM_LR_SAVE)(r1) /* Save return */ /* ok, now we can use the FPU registers to do some fast copying */ @@ -96,6 +96,8 @@ ENTRY(video_scroll_down, TAG_NO_FRAME_USED) mfmsr r0 /* Get the MSR */ + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off mflr r6 /* Get the LR */ ori r7,r0,1<<(31-MSR_FP_BIT) /* Turn on floating point */ stwu r1,-(FM_SIZE+16)(r1) /* Get space for a couple of registers on stack */ @@ -107,8 +109,6 @@ ENTRY(video_scroll_down, TAG_NO_FRAME_USED) vsdfpuon1: stfd f0,(FM_SIZE+0)(r1) /* Save one register */ stfd f1,(FM_SIZE+8)(r1) /* and the second */ - - stw r0,(FM_SIZE+FM_LR_SAVE)(r1) /* Save return */ /* ok, now we can use the FPU registers to do some fast copying */ diff --git a/osfmk/ppc/PPCcalls.h b/osfmk/ppc/PPCcalls.h index 8dbbafaad..bab0f34f2 100644 --- a/osfmk/ppc/PPCcalls.h +++ b/osfmk/ppc/PPCcalls.h @@ -49,7 +49,8 @@ PPCcallEnt PPCcalls[] = { PPCcall(bb_settaskenv), /* 0x6007 Set the BlueBox per thread task environment data */ PPCcall(vmm_stop_vm), /* 0x6008 Stop a running VM */ - PPCcall(dis), /* 0x6009 disabled */ + PPCcall(dis), /* 0x6009 CHUD Interface hook */ + PPCcall(dis), /* 0x600A disabled */ PPCcall(dis), /* 0x600B disabled */ PPCcall(dis), /* 0x600C disabled */ diff --git a/osfmk/ppc/PseudoKernel.c b/osfmk/ppc/PseudoKernel.c index 449836187..ce31867cf 100644 --- a/osfmk/ppc/PseudoKernel.c +++ b/osfmk/ppc/PseudoKernel.c @@ -59,7 +59,6 @@ kern_return_t syscall_notify_interrupt ( void ) { UInt32 interruptState; task_t task; - spl_t s; thread_act_t act, fact; thread_t thread; bbRupt *bbr; @@ -121,9 +120,7 @@ kern_return_t syscall_notify_interrupt ( void ) { bbr->rh.next = act->handlers; /* Put our interrupt at the start of the list */ act->handlers = &bbr->rh; - s = splsched(); /* No talking in class */ act_set_apc(act); /* Set an APC AST */ - splx(s); /* Ok, you can talk now */ act_unlock_thread(act); /* Unlock the activation */ return KERN_SUCCESS; /* We're done... */ @@ -151,7 +148,7 @@ void bbSetRupt(ReturnHandler *rh, thread_act_t act) { (void)hw_atomic_sub(&act->mact.emPendRupts, 1); /* Uncount this 'rupt */ - if(!(sv = (savearea *)find_user_regs(act))) { /* Find the user state registers */ + if(!(sv = find_user_regs(act))) { /* Find the user state registers */ kfree((vm_offset_t)bbr, sizeof(bbRupt)); /* Couldn't find 'em, release the control block */ return; } @@ -256,7 +253,7 @@ kern_return_t enable_bluebox( (void) pmap_enter(kernel_pmap, /* Map this into the kernel */ kerndescaddr, physdescaddr, VM_PROT_READ|VM_PROT_WRITE, - TRUE); + VM_WIMG_USE_DEFAULT, TRUE); th->top_act->mact.bbDescAddr = (unsigned int)kerndescaddr+origdescoffset; /* Set kernel address of the table */ th->top_act->mact.bbUserDA = (unsigned int)Desc_TableStart; /* Set user address of the table */ diff --git a/osfmk/ppc/aligned_data.s b/osfmk/ppc/aligned_data.s index 00dbebc36..be7a239ef 100644 --- a/osfmk/ppc/aligned_data.s +++ b/osfmk/ppc/aligned_data.s @@ -101,45 +101,33 @@ EXT(DBGpreempt): #endif -/* 32-byte aligned areas */ +/* 128-byte aligned areas */ .globl EXT(saveanchor) - .align 5 + .align 7 EXT(saveanchor): .set .,.+SVsize .globl EXT(mapCtl) - .align 5 + .align 7 EXT(mapCtl): .set .,.+mapcsize - .globl EXT(dgWork) - .align 5 -EXT(dgWork): - .long 0 - .long 0 - .long 0 - .long 0 - .long 0 - .long 0 - .long 0 - .long 0 - .globl EXT(trcWork) - .align 5 + .align 7 EXT(trcWork): + .long EXT(traceTableBeg) ; The next trace entry to use #if DEBUG -/* .long 0x02000000 */ /* Only alignment exceptions enabled */ - .long 0xFFFFFFFF /* All enabled */ -/* .long 0xFBBFFFFF */ /* EXT and DEC disabled */ -/* .long 0xFFBFFFFF */ /* DEC disabled */ +/* .long 0x02000000 */ /* Only alignment exceptions enabled */ + .long 0xFFFFFFFF /* All enabled */ +/* .long 0xFBBFFFFF */ /* EXT and DEC disabled */ +/* .long 0xFFBFFFFF */ /* DEC disabled */ #else - .long 0x00000000 ; All disabled on non-debug systems + .long 0x00000000 ; All disabled on non-debug systems #endif - .long EXT(traceTableBeg) ; The next trace entry to use - .long EXT(traceTableBeg) ; Start of the trace table - .long EXT(traceTableEnd) ; End (wrap point) of the trace - .long 0 ; Saved mask while in debugger + .long EXT(traceTableBeg) ; Start of the trace table + .long EXT(traceTableEnd) ; End (wrap point) of the trace + .long 0 ; Saved mask while in debugger .long 0 .long 0 @@ -147,91 +135,104 @@ EXT(trcWork): .globl fwdisplock - .align 5 + .align 7 fwdisplock: - .set .,.+32 + .set .,.+128 + + .globl EXT(free_mappings) + .align 7 + +EXT(free_mappings): + .long 0 + + .globl EXT(syncClkSpot) + .align 7 +EXT(syncClkSpot): + .long 0 + .long 0 + .long 0 + .long 0 + .long 0 + .long 0 + .long 0 + .long 0 + + .globl EXT(NMIss) + .align 7 +EXT(NMIss): + .long 0 + .long 0 + .long 0 + .long 0 + .long 0 + .long 0 + .long 0 + .long 0 + +/* 32-byte aligned areas */ + + .globl EXT(dbvecs) + .align 5 +EXT(dbvecs): + .set .,.+(33*16) .globl hexfont .align 5 #include - .globl EXT(QNaNbarbarian) - .align 5 + .globl EXT(QNaNbarbarian) + .align 5 EXT(QNaNbarbarian): - .long 0x7FFFDEAD /* This is a quiet not-a-number which is a "known" debug value */ - .long 0x7FFFDEAD /* This is a quiet not-a-number which is a "known" debug value */ - .long 0x7FFFDEAD /* This is a quiet not-a-number which is a "known" debug value */ - .long 0x7FFFDEAD /* This is a quiet not-a-number which is a "known" debug value */ - - .long 0x7FFFDEAD /* This is a quiet not-a-number which is a "known" debug value */ - .long 0x7FFFDEAD /* This is a quiet not-a-number which is a "known" debug value */ - .long 0x7FFFDEAD /* This is a quiet not-a-number which is a "known" debug value */ - .long 0x7FFFDEAD /* This is a quiet not-a-number which is a "known" debug value */ - - .globl EXT(free_mappings) - .align 5 + .long 0x7FFFDEAD /* This is a quiet not-a-number which is a "known" debug value */ + .long 0x7FFFDEAD /* This is a quiet not-a-number which is a "known" debug value */ + .long 0x7FFFDEAD /* This is a quiet not-a-number which is a "known" debug value */ + .long 0x7FFFDEAD /* This is a quiet not-a-number which is a "known" debug value */ -EXT(free_mappings): - .long 0 - - .globl EXT(syncClkSpot) - .align 5 -EXT(syncClkSpot): - .long 0 - .long 0 - .long 0 - .long 0 - .long 0 - .long 0 - .long 0 - .long 0 - - .globl EXT(NMIss) - .align 5 -EXT(NMIss): - .long 0 - .long 0 - .long 0 - .long 0 - .long 0 - .long 0 - .long 0 - .long 0 - - .globl EXT(dbvecs) - .align 5 -EXT(dbvecs): - .set .,.+(33*16) + .long 0x7FFFDEAD /* This is a quiet not-a-number which is a "known" debug value */ + .long 0x7FFFDEAD /* This is a quiet not-a-number which is a "known" debug value */ + .long 0x7FFFDEAD /* This is a quiet not-a-number which is a "known" debug value */ + .long 0x7FFFDEAD /* This is a quiet not-a-number which is a "known" debug value */ + .globl EXT(dgWork) + .align 5 +EXT(dgWork): + .long 0 + .long 0 + .long 0 + .long 0 + .long 0 + .long 0 + .long 0 + .long 0 /* 8-byte aligned areas */ - .globl EXT(FloatInit) - .align 3 + .globl EXT(FloatInit) + .align 3 EXT(FloatInit): - .long 0xC24BC195 /* Initial value */ - .long 0x87859393 /* of floating point registers */ - .long 0xE681A2C8 /* and others */ - .long 0x8599855A + .long 0xC24BC195 /* Initial value */ + .long 0x87859393 /* of floating point registers */ + .long 0xE681A2C8 /* and others */ + .long 0x8599855A - .globl EXT(DebugWork) - .align 3 + .globl EXT(DebugWork) + .align 3 EXT(DebugWork): - .long 0 - .long 0 - .long 0 - .long 0 + .long 0 + .long 0 + .long 0 + .long 0 - .globl EXT(dbfloats) - .align 3 + .globl EXT(dbfloats) + .align 3 EXT(dbfloats): .set .,.+(33*8) - .globl EXT(dbspecrs) - .align 3 + .globl EXT(dbspecrs) + .align 3 EXT(dbspecrs): .set .,.+(80*4) diff --git a/osfmk/ppc/alignment.c b/osfmk/ppc/alignment.c deleted file mode 100644 index bfc4a7717..000000000 --- a/osfmk/ppc/alignment.c +++ /dev/null @@ -1,1041 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991 - * All Rights Reserved - * - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appears in all copies and - * that both the copyright notice and this permission notice appear in - * supporting documentation. - * - * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, - * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION - * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ -/* - * Copyright 1996 1995 by Apple Computer, Inc. 1997 1996 1995 1994 1993 1992 1991 - * All Rights Reserved - * - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appears in all copies and - * that both the copyright notice and this permission notice appear in - * supporting documentation. - * - * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, - * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION - * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if DEBUG -/* These variable may be used to keep track of alignment exceptions */ -int alignment_exception_count_user; -int alignment_exception_count_kernel; -#endif - -#define _AINST(x) boolean_t align_##x##(unsigned long dsisr,\ - struct ppc_saved_state *ssp, \ - struct ppc_float_state *fsp, \ - unsigned long *align_buffer, \ - unsigned long dar) - - -#define _AFENTRY(name, r, b) { #name, align_##name##, r, b, TRUE } -#define _AENTRY(name, r, b) { #name, align_##name##, r, b, FALSE } -#define _ANIL { (void *) 0, (void *) 0, 0, 0 } - -_AINST(lwz); -_AINST(stw); -_AINST(lhz); -_AINST(lha); -_AINST(sth); -_AINST(lmw); -_AINST(lfs); -_AINST(lfd); -_AINST(stfs); -_AINST(stfd); -_AINST(lwzu); -_AINST(stwu); -_AINST(lhzu); -_AINST(lhau); -_AINST(sthu); -_AINST(lfsu); -_AINST(lfdu); -_AINST(stfsu); -_AINST(stfdu); -_AINST(lswx); -_AINST(lswi); -_AINST(lwbrx); -_AINST(stwbrx); -_AINST(lhbrx); -_AINST(sthbrx); -_AINST(dcbz); -_AINST(lwzx); -_AINST(stwx); -_AINST(lhzx); -_AINST(lhax); -_AINST(sthx); -_AINST(lfsx); -_AINST(lfdx); -_AINST(stfsx); -_AINST(stfdx); -_AINST(lwzux); -_AINST(stwux); -_AINST(lhzux); -_AINST(lhaux); -_AINST(sthux); -_AINST(stmw); -_AINST(lfsux); -_AINST(lfdux); -_AINST(stfsux); -_AINST(stfdux); - -/* - * Routines to set and get FPU registers. - */ - -void GET_FPU_REG(struct ppc_float_state *fsp, - unsigned long reg, - unsigned long *value); -void SET_FPU_REG(struct ppc_float_state *fsp, - unsigned long reg, - unsigned long *value); - -__inline__ void GET_FPU_REG(struct ppc_float_state *fsp, - unsigned long reg, - unsigned long *value) -{ - value[0] = ((unsigned long *) &fsp->fpregs[reg])[0]; - value[1] = ((unsigned long *) &fsp->fpregs[reg])[1]; -} - -__inline__ void SET_FPU_REG(struct ppc_float_state *fsp, - unsigned long reg, unsigned long *value) -{ - ((unsigned long *) &fsp->fpregs[reg])[0] = value[0]; - ((unsigned long *) &fsp->fpregs[reg])[1] = value[1]; -} - - -/* - * Macros to load and set registers according to - * a given cast type. - */ - -#define GET_REG(p, reg, value, cast) \ - { *((cast *) value) = *((cast *) (&p->r0+reg)); } -#define SET_REG(p, reg, value, cast) \ - { *((cast *) (&p->r0+reg)) = *((cast *) value); } - -/* - * Macros to help decode the DSISR. - */ - -#define DSISR_BITS_15_16(bits) ((bits>>15) & 0x3) -#define DSISR_BITS_17_21(bits) ((bits>>10) & 0x1f) -#define DSISR_BITS_REG(bits) ((bits>>5) & 0x1f) -#define DSISR_BITS_RA(bits) (bits & 0x1f) - - -struct ppc_align_instruction { - char *name; - boolean_t (*a_instruct)(unsigned long, - struct ppc_saved_state *, - struct ppc_float_state *, - unsigned long *, - unsigned long ); - int a_readbytes; - int a_writebytes; - boolean_t a_is_float; -} align_table00[] = { -_AENTRY(lwz, 4, 0), /* 00 0 0000 */ -_ANIL, /* 00 0 0001 */ -_AENTRY(stw, 0, 4), /* 00 0 0010 */ -_ANIL, /* 00 0 0011 */ -_AENTRY(lhz, 2, 0), /* 00 0 0100 */ -_AENTRY(lha, 2, 0), /* 00 0 0101 */ -_AENTRY(sth, 0, 2), /* 00 0 0110 */ -_AENTRY(lmw, 32*4,0), /* 00 0 0111 */ -_AFENTRY(lfs, 4, 0), /* 00 0 1000 */ -_AFENTRY(lfd, 8, 0), /* 00 0 1001 */ -_AFENTRY(stfs, 0, 4), /* 00 0 1010 */ -_AFENTRY(stfd, 0, 8), /* 00 0 1011 */ -_ANIL, /* 00 0 1100 ?*/ -_ANIL, /* 00 0 1101 - lwa */ -_ANIL, /* 00 0 1110 ?*/ -_ANIL, /* 00 0 1111 - std */ -_AENTRY(lwzu, 4, 0), /* 00 1 0000 */ -_ANIL, /* 00 1 0001 ?*/ -_AENTRY(stwu, 0, 4), /* 00 1 0010 */ -_ANIL, /* 00 1 0011 */ -_AENTRY(lhzu, 2, 0), /* 00 1 0100 */ -_AENTRY(lhau, 2, 0), /* 00 1 0101 */ -_AENTRY(sthu, 0, 2), /* 00 1 0110 */ -_AENTRY(stmw, 0, 0), /* 00 1 0111 */ -_AFENTRY(lfsu, 4, 0), /* 00 1 1000 */ -_AFENTRY(lfdu, 8, 0), /* 00 1 1001 - lfdu */ -_AFENTRY(stfsu, 0, 4), /* 00 1 1010 */ -_AFENTRY(stfdu, 0, 8), /* 00 1 1011 - stfdu */ -}; - -struct ppc_align_instruction align_table01[] = { -_ANIL, /* 01 0 0000 - ldx */ -_ANIL, /* 01 0 0001 ?*/ -_ANIL, /* 01 0 0010 - stdx */ -_ANIL, /* 01 0 0011 ?*/ -_ANIL, /* 01 0 0100 ?*/ -_ANIL, /* 01 0 0101 - lwax */ -_ANIL, /* 01 0 0110 ?*/ -_ANIL, /* 01 0 0111 ?*/ -_AENTRY(lswx,32, 0), /* 01 0 1000 - lswx */ -_AENTRY(lswi,32, 0), /* 01 0 1001 - lswi */ -_ANIL, /* 01 0 1010 - stswx */ -_ANIL, /* 01 0 1011 - stswi */ -_ANIL, /* 01 0 1100 ?*/ -_ANIL, /* 01 0 1101 ?*/ -_ANIL, /* 01 0 1110 ?*/ -_ANIL, /* 01 0 1111 ?*/ -_ANIL, /* 01 1 0000 - ldux */ -_ANIL, /* 01 1 0001 ?*/ -_ANIL, /* 01 1 0010 - stdux */ -_ANIL, /* 01 1 0011 ?*/ -_ANIL, /* 01 1 0100 ?*/ -_ANIL, /* 01 1 0101 - lwaux */ -}; - -struct ppc_align_instruction align_table10[] = { -_ANIL, /* 10 0 0000 ?*/ -_ANIL, /* 10 0 0001 ?*/ -_ANIL, /* 10 0 0010 - stwcx. */ -_ANIL, /* 10 0 0011 - stdcx.*/ -_ANIL, /* 10 0 0100 ?*/ -_ANIL, /* 10 0 0101 ?*/ -_ANIL, /* 10 0 0110 ?*/ -_ANIL, /* 10 0 0111 ?*/ -_AENTRY(lwbrx, 4, 0), /* 10 0 1000 */ -_ANIL, /* 10 0 1001 ?*/ -_AENTRY(stwbrx, 0, 4), /* 10 0 1010 */ -_ANIL, /* 10 0 1011 */ -_AENTRY(lhbrx, 2, 0), /* 10 0 1110 */ -_ANIL, /* 10 0 1101 ?*/ -_AENTRY(sthbrx, 0, 2), /* 10 0 1110 */ -_ANIL, /* 10 0 1111 ?*/ -_ANIL, /* 10 1 0000 ?*/ -_ANIL, /* 10 1 0001 ?*/ -_ANIL, /* 10 1 0010 ?*/ -_ANIL, /* 10 1 0011 ?*/ -_ANIL, /* 10 1 0100 - eciwx */ -_ANIL, /* 10 1 0101 ?*/ -_ANIL, /* 10 1 0110 - ecowx */ -_ANIL, /* 10 1 0111 ?*/ -_ANIL, /* 10 1 1000 ?*/ -_ANIL, /* 10 1 1001 ?*/ -_ANIL, /* 10 1 1010 ?*/ -_ANIL, /* 10 1 1011 ?*/ -_ANIL, /* 10 1 1100 ?*/ -_ANIL, /* 10 1 1101 ?*/ -_ANIL, /* 10 1 1110 ?*/ -_AENTRY(dcbz, 0, 0), /* 10 1 1111 */ -}; - -struct ppc_align_instruction align_table11[] = { -_AENTRY(lwzx, 4, 0), /* 11 0 0000 */ -_ANIL, /* 11 0 0001 ?*/ -_AENTRY(stwx, 0, 4), /* 11 0 0010 */ -_ANIL, /* 11 0 0011 */ -_AENTRY(lhzx, 2, 0), /* 11 0 0100 */ -_AENTRY(lhax, 2, 0), /* 11 0 0101 */ -_AENTRY(sthx, 0, 2), /* 11 0 0110 */ -_ANIL, /* 11 0 0111?*/ -_AFENTRY(lfsx, 4, 0), /* 11 0 1000 */ -_AFENTRY(lfdx, 8, 0), /* 11 0 1001 */ -_AFENTRY(stfsx, 0, 4), /* 11 0 1010 */ -_AFENTRY(stfdx, 0, 8), /* 11 0 1011 */ -_ANIL, /* 11 0 1100 ?*/ -_ANIL, /* 11 0 1101 ?*/ -_ANIL, /* 11 0 1110 ?*/ -_ANIL, /* 11 0 1111 - stfiwx */ -_AENTRY(lwzux, 4, 0), /* 11 1 0000 */ -_ANIL, /* 11 1 0001 ?*/ -_AENTRY(stwux, 0, 4), /* 11 1 0010 */ -_ANIL, /* 11 1 0011 */ -_AENTRY(lhzux, 4, 0), /* 11 1 0100 */ -_AENTRY(lhaux, 4, 0), /* 11 1 0101 */ -_AENTRY(sthux, 0, 4), /* 11 1 0110 */ -_ANIL, /* 11 1 0111 ?*/ -_AFENTRY(lfsux, 4, 0), /* 11 1 1000 */ -_AFENTRY(lfdux, 8, 0), /* 11 1 1001 */ -_AFENTRY(stfsux, 0, 4), /* 11 1 1010 */ -_AFENTRY(stfdux, 0, 8), /* 11 1 1011 */ -}; - - -struct ppc_align_instruction_table { - struct ppc_align_instruction *table; - int size; -} align_tables[4] = { - align_table00, sizeof(align_table00)/ - sizeof(struct ppc_align_instruction), - - align_table01, sizeof(align_table01)/ - sizeof(struct ppc_align_instruction), - - align_table10, sizeof(align_table10)/ - sizeof(struct ppc_align_instruction), - - align_table11, sizeof(align_table11)/ - sizeof(struct ppc_align_instruction) -}; - -extern int real_ncpus; /* Number of actual CPUs */ - -/* - * Alignment Exception Handler - * - * - * This handler is called when the chip attempts - * to execute an instruction which causes page - * boundaries to be crossed. Typically, this will - * happen on stfd* and lfd* instructions. - * (A request has been made for GNU C compiler - * NOT to make use of these instructions to - * load and store 8 bytes at a time.) - * - * This is a *SLOW* handler. There is room for vast - * improvement. However, it is expected that alignment - * exceptions will be very infrequent. - * - * Not all of the 64 instructions (as listed in - * PowerPC Microprocessor Family book under the Alignment - * Exception section) are handled yet. - * Only the most common ones which are expected to - * happen. - * - * -- Michael Burg, Apple Computer, Inc. 1996 - * - * TODO NMGS finish handler - */ - -boolean_t -alignment(unsigned long dsisr, unsigned long dar, - struct ppc_saved_state *ssp) -{ - struct ppc_align_instruction_table *table; - struct ppc_align_instruction *entry; - struct ppc_float_state *fpc; - unsigned long align_buffer[32]; - boolean_t success = FALSE; - thread_act_t act; - spl_t s; - int i; - -#if DEBUG - if (USER_MODE(ssp->srr1)) (void)hw_atomic_add(&alignment_exception_count_user, 1); - else (void)hw_atomic_add(&alignment_exception_count_kernel, 1); -#endif - - act = current_act(); /* Get the current activation */ - - table = &align_tables[DSISR_BITS_15_16(dsisr)]; - - if (table == (void *) 0 - || table->size < DSISR_BITS_17_21(dsisr)) { -#if DEBUG - printf("EXCEPTION NOT HANDLED: Out of range.\n"); - printf("dsisr=%X, dar=%X\n",dsisr, dar); - printf("table=%X\n",DSISR_BITS_15_16(dsisr)); - printf("table->size=%X\n", table->size); - printf("entry=%X\n",DSISR_BITS_17_21(dsisr)); -#endif - goto out; - } - - entry = &table->table[DSISR_BITS_17_21(dsisr)]; - - if (entry->a_instruct == (void *) 0) { -#if DEBUG - printf("EXCEPTION NOT HANDLED: Inst out of table range.\n"); - printf("table=%X\n",DSISR_BITS_15_16(dsisr)); - printf("entry=%X\n",DSISR_BITS_17_21(dsisr)); -#endif - goto out; - } - - /* - * Check to see if the instruction is a - * floating point operation. Save off - * the FPU register set ... - */ - - if (entry->a_is_float) - fpu_save(act); - - /* - * Pull in any bytes which are going to be - * read. - */ - - if (entry->a_readbytes) { - if (USER_MODE(ssp->srr1)) { - if (copyin((char *) dar, - (char *) align_buffer, - entry->a_readbytes)) { - return TRUE; - } - } else { - bcopy((char *) dar, - (char *) align_buffer, - entry->a_readbytes); - } - } - -#if 0 && DEBUG - printf("Alignment exception: %s %d,0x%x (r%d/w%d) (tmp %x/%x)\n", - entry->name, DSISR_BITS_REG(dsisr), - dar, entry->a_readbytes, entry->a_writebytes, - align_buffer[0], align_buffer[1]); - printf(" pc=(0x%08X), msr=(0x%X)",ssp->srr0, ssp->srr1); -#endif - - - success = entry->a_instruct(dsisr, - ssp, - (entry->a_is_float ? find_user_fpu(act) : 0), /* Find this user's FPU state if FP op */ - align_buffer, - dar); - - if (success) { - if (entry->a_writebytes) { - if (USER_MODE(ssp->srr1)) { - if (copyout((char *) align_buffer, - (char *) dar, - entry->a_writebytes)) { - return TRUE; - } - } else { - bcopy((char *) align_buffer, - (char *) dar, - entry->a_writebytes); - } - } - else { - if(entry->a_is_float) { /* If we are an FP op, blow away live context */ - for(i=0; i < real_ncpus; i++) { /* Cycle through processors */ - (void)hw_compare_and_store((unsigned int)act, 0, &per_proc_info[i].FPU_thread); /* Clear if ours */ - } - } - - if (USER_MODE(ssp->srr1)) { - if (copyout((char *) align_buffer, - (char *) dar, - entry->a_writebytes)) { - return TRUE; - } - } else { - bcopy((char *) align_buffer, - (char *) dar, - entry->a_writebytes); - } - } - - ssp->srr0 += 4; /* Skip the instruction .. */ - } - - return !success; - -out: -#if 0 && DEBUG - printf("ALIGNMENT EXCEPTION: (dsisr 0x%x) table %d 0x%x\n", - dsisr, DSISR_BITS_15_16(dsisr), DSISR_BITS_17_21(dsisr)); -#endif - - return TRUE; -} - -_AINST(lwz) -{ - SET_REG(ssp, DSISR_BITS_REG(dsisr), align_buffer, unsigned long); - - return TRUE; -} - -_AINST(stw) -{ - GET_REG(ssp, DSISR_BITS_REG(dsisr), align_buffer, unsigned long); - - return TRUE; -} - -_AINST(lhz) -{ - unsigned long value = *((unsigned short *) align_buffer); - - SET_REG(ssp, DSISR_BITS_REG(dsisr), &value, unsigned long); - - return TRUE; -} - -_AINST(lha) -{ - long value = *((short *) align_buffer); - - SET_REG(ssp, DSISR_BITS_REG(dsisr), &value, unsigned long); - - return TRUE; -} - -_AINST(sth) -{ - GET_REG(ssp, DSISR_BITS_REG(dsisr), align_buffer, unsigned short); - - return TRUE; -} - -_AINST(lmw) -{ - int i; - - for (i = 0; i < (32-DSISR_BITS_REG(dsisr)); i++) - { - SET_REG(ssp, DSISR_BITS_REG(dsisr)+i, &align_buffer[i], unsigned long); - } - return TRUE; -} - -struct fpsp { - unsigned long s :1; /* Sign bit */ - unsigned long exp :8; /* exponent + bias */ - unsigned long fraction:23; /* fraction */ -}; -typedef struct fpsp fpsp_t, *fpspPtr; - -struct fpdp { - unsigned long s :1; /* Sign bit */ - unsigned long exp :11; /* exponent + bias */ - unsigned long fraction:20; /* fraction */ - unsigned long fraction1; /* fraction */ -}; -typedef struct fpdp fpdp_t, *fpdpPtr; - - -_AINST(lfs) -{ - unsigned long lalign_buf[2]; - - - lfs (align_buffer, lalign_buf); - SET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), lalign_buf); - return TRUE; -} - -_AINST(lfd) -{ - SET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), align_buffer); - return TRUE; -} - -_AINST(stfs) -{ - unsigned long lalign_buf[2]; - - - GET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), lalign_buf); - stfs(lalign_buf, align_buffer); - return TRUE; -} - -_AINST(stfd) -{ - GET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), align_buffer); - return TRUE; -} - -_AINST(lwzu) -{ - SET_REG(ssp, DSISR_BITS_REG(dsisr), align_buffer, unsigned long) - SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long); - return TRUE; -} - -_AINST(stwu) -{ - GET_REG(ssp, DSISR_BITS_REG(dsisr), align_buffer, unsigned long) - SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long); - return TRUE; -} - - -_AINST(lhzu) -{ - SET_REG(ssp, DSISR_BITS_REG(dsisr), align_buffer, unsigned short) - SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long); - return TRUE; -} - -_AINST(lhau) -{ - unsigned long value = *((short *) align_buffer); - - SET_REG(ssp, DSISR_BITS_REG(dsisr), &value, unsigned long); - SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long); - - return TRUE; -} - -_AINST(sthu) -{ - GET_REG(ssp, DSISR_BITS_REG(dsisr), align_buffer, unsigned short) - SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long); - return TRUE; -} - -_AINST(stmw) -{ - int i, rS = DSISR_BITS_REG(dsisr); - int numRegs = 32 - rS; - int numBytes = numRegs * 4; - int retval; - - - for (i = 0; i < numRegs; i++) - { -#if 0 - printf(" align_buffer[%d] == 0x%x\n",i,align_buffer[i]); -#endif - GET_REG(ssp, rS+i, &align_buffer[i], unsigned long); -#if 0 - printf(" now align_buffer[%d] == 0x%x\n",i,align_buffer[i]); -#endif - } - if (USER_MODE(ssp->srr1)) { - if ((retval=copyout((char *)align_buffer,(char *)dar,numBytes)) != 0) { - return FALSE; - } -#if 0 - printf(" copyout(%X, %X, %X) succeeded\n",align_buffer,dar,numBytes); -#endif - } - else { - bcopy((char *) align_buffer, (char *) dar, numBytes); - } - return TRUE; -} - -_AINST(lfsu) -{ - unsigned long lalign_buf[2]; - - - lfs (align_buffer, lalign_buf); - SET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), lalign_buf); - SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long); - return TRUE; -} - -_AINST(lfdu) -{ - SET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), align_buffer); - SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long); - - return TRUE; -} - -_AINST(stfsu) -{ - unsigned long lalign_buf[2]; - - - GET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), lalign_buf); - stfs(lalign_buf, align_buffer); - SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long); - return TRUE; -} - - -_AINST(stfdu) -{ - GET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), align_buffer); - SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long); - - return TRUE; -} - -_AINST(lswx) -{ - int i, nb, nr, inst, zero = 0; - - - /* check for invalid form of instruction */ - if (DSISR_BITS_RA(dsisr) >= DSISR_BITS_REG(dsisr) ) - return FALSE; - - if (USER_MODE(ssp->srr1)) { - if (copyin((char *) ssp->srr0, (char *) &inst, 4 )) { - return FALSE; - } - } else { - bcopy((char *) ssp->srr0, (char *) &inst, 4 ); - } - - nb = (inst >> 11) & 0x1F; /* get the number of bytes in the instr */ - nr = (nb + sizeof(long)-1) / sizeof(long);/* get the number of regs to copy */ - - if ((nr + DSISR_BITS_REG(dsisr)) > 31) - return FALSE; /* not supported yet */ - - for (i = 0; i < nr; i++) - { - SET_REG(ssp, DSISR_BITS_REG(dsisr)+i, &zero, unsigned long); - } - /* copy the string into the save state */ - bcopy((char *) align_buffer, (char *) ssp->r0+DSISR_BITS_REG(dsisr), nb ); - return TRUE; -} - -_AINST(lswi) -{ - int i, nb, nr, inst, zero = 0; - - - /* check for invalid form of instruction */ - if (DSISR_BITS_RA(dsisr) >= DSISR_BITS_REG(dsisr) ) - return FALSE; - - if (USER_MODE(ssp->srr1)) { - if (copyin((char *) ssp->srr0, (char *) &inst, 4 )) { - return FALSE; - } - } else { - bcopy((char *) ssp->srr0, (char *) &inst, 4 ); - } - - nb = (inst >> 11) & 0x1F; /* get the number of bytes in the instr */ - nr = (nb + sizeof(long)-1) / sizeof(long);/* get the number of regs to copy */ - - if ((nr + DSISR_BITS_REG(dsisr)) > 31) - return FALSE; /* not supported yet */ - - for (i = 0; i < nr; i++) - { - SET_REG(ssp, DSISR_BITS_REG(dsisr)+i, &zero, unsigned long); - } - /* copy the string into the save state */ - bcopy((char *) align_buffer, (char *) ssp->r0+DSISR_BITS_REG(dsisr), nb ); - return TRUE; -} - -_AINST(stswx) -{ - return FALSE; -} - -_AINST(stswi) -{ - return FALSE; -} - - - - - - - -_AINST(stwcx) -{ - return FALSE; -} - -_AINST(stdcx) -{ - return FALSE; -} - -_AINST(lwbrx) -{ - unsigned long new_value; - - __asm__ volatile("lwbrx %0,0,%1" : : "b" (new_value), - "b" (&align_buffer[0])); - - SET_REG(ssp, DSISR_BITS_REG(dsisr), &new_value, unsigned long); - - return TRUE; -} - -_AINST(stwbrx) -{ - unsigned long value; - - GET_REG(ssp, DSISR_BITS_REG(dsisr), &value, unsigned long); - __asm__ volatile("stwbrx %0,0,%1" : : "b" (value), "b" (&align_buffer[0])); - - return TRUE; -} - -_AINST(lhbrx) -{ - unsigned short value; - - __asm__ volatile("lhbrx %0,0,%1" : : "b" (value), "b" (&align_buffer[0])); - - SET_REG(ssp, DSISR_BITS_REG(dsisr), &value, unsigned short); - - return TRUE; -} - -_AINST(sthbrx) -{ - unsigned short value; - - GET_REG(ssp, DSISR_BITS_REG(dsisr), &value, unsigned short); - __asm__ volatile("sthbrx %0,0,%1" : : "b" (value), "b" (&align_buffer[0])); - - return TRUE; -} - -_AINST(eciwx) -{ - return FALSE; -} - -_AINST(ecowx) -{ - return FALSE; -} - -_AINST(dcbz) -{ - long *alignedDAR = (long *)((long)dar & ~(CACHE_LINE_SIZE-1)); - - - if (USER_MODE(ssp->srr1)) { - - align_buffer[0] = 0; - align_buffer[1] = 0; - align_buffer[2] = 0; - align_buffer[3] = 0; - align_buffer[4] = 0; - align_buffer[5] = 0; - align_buffer[6] = 0; - align_buffer[7] = 0; - - if (copyout((char *)align_buffer,(char *)alignedDAR,CACHE_LINE_SIZE) != 0) - return FALSE; - } else { - /* Cannot use bcopy here just in case it caused the exception */ - alignedDAR[0] = 0; - alignedDAR[1] = 0; - alignedDAR[2] = 0; - alignedDAR[3] = 0; - alignedDAR[4] = 0; - alignedDAR[5] = 0; - alignedDAR[6] = 0; - alignedDAR[7] = 0; - } - return TRUE; -} - - - - - - - -_AINST(lwzx) -{ - SET_REG(ssp, DSISR_BITS_REG(dsisr), &align_buffer[0], unsigned long); - - return TRUE; -} - -_AINST(stwx) -{ - GET_REG(ssp, DSISR_BITS_REG(dsisr), &align_buffer[0], unsigned long); - - return TRUE; -} - -_AINST(lhzx) -{ - SET_REG(ssp, DSISR_BITS_REG(dsisr), &align_buffer[0], unsigned short); - - return TRUE; -} - -_AINST(lhax) -{ - unsigned long value = *((short *) &align_buffer[0]); - - SET_REG(ssp, DSISR_BITS_REG(dsisr), &value, unsigned long); - - return TRUE; -} - -_AINST(sthx) -{ - GET_REG(ssp, DSISR_BITS_REG(dsisr), &align_buffer[0], unsigned short); - - return TRUE; -} - -_AINST(lfsx) -{ - long lalign_buf[2]; - - - lfs (align_buffer, lalign_buf); - SET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), lalign_buf); - return TRUE; -} - -_AINST(lfdx) -{ - SET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), align_buffer); - - return TRUE; -} - -_AINST(stfsx) -{ - long lalign_buf[2]; - - - GET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), lalign_buf); - stfs(lalign_buf, align_buffer); - return TRUE; -} - -_AINST(stfdx) -{ - GET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), align_buffer); - - return TRUE; -} - -_AINST(lwzux) -{ - SET_REG(ssp, DSISR_BITS_REG(dsisr), &align_buffer[0], unsigned long); - SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long); - - return TRUE; -} - -_AINST(stwux) -{ - GET_REG(ssp, DSISR_BITS_REG(dsisr), &align_buffer[0], unsigned long); - SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long); - - return TRUE; -} - -_AINST(lhzux) -{ - unsigned long value = *((unsigned short *)&align_buffer[0]); - - SET_REG(ssp, DSISR_BITS_REG(dsisr), &value, unsigned long); - SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long); - - return TRUE; -} - -_AINST(lhaux) -{ - long value = *((short *) &align_buffer[0]); - - SET_REG(ssp, DSISR_BITS_REG(dsisr), &value, unsigned long); - SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long); - - return TRUE; -} - -_AINST(sthux) -{ - GET_REG(ssp, DSISR_BITS_REG(dsisr), &align_buffer[0], unsigned short); - SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long); - - return TRUE; -} - -_AINST(lfsux) -{ - long lalign_buf[2]; - - - lfs (align_buffer, lalign_buf); - SET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), lalign_buf); - SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long); - return TRUE; -} - -_AINST(lfdux) -{ - SET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), &align_buffer[0]); - SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long); - - return TRUE; -} - - -_AINST(stfsux) -{ - long lalign_buf[2]; - - - GET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), lalign_buf); - stfs(lalign_buf, align_buffer); - SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long); - return TRUE; -} - -_AINST(stfdux) -{ - GET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), &align_buffer[0]); - SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long); - - return TRUE; -} diff --git a/osfmk/ppc/bcopy.s b/osfmk/ppc/bcopy.s index 95ad3ea6b..1a18bf37a 100644 --- a/osfmk/ppc/bcopy.s +++ b/osfmk/ppc/bcopy.s @@ -24,10 +24,6 @@ ; ; Change this to use Altivec later on, and maybe floating point. ; -; NOTE: This file compiles and executes on both MacOX 8.x (Codewarrior) -; and MacOX X. The "#if 0"s are treated as comments by CW so the -; stuff between them is included by CW and excluded on MacOX X. -; Same with the "#include"s. ; #include #include @@ -36,13 +32,8 @@ #define noncache 20 ; Use CR5_gt to indicate that we need to turn data translation back on #define fixxlate 21 -#if 0 -noncache: equ 20 -fixxlate: equ 21 -#endif -#if 0 -br0: equ 0 -#endif +; Use CR5_eq to indicate that we need to invalidate bats +#define killbats 22 ; ; bcopy_nc(from, to, nbytes) @@ -51,50 +42,90 @@ br0: equ 0 ; of cache instructions. ; + .align 5 + .globl EXT(bcopy_nc) - -#if 0 - IF 0 -#endif -ENTRY(bcopy_nc, TAG_NO_FRAME_USED) -#if 0 - ENDIF - export xbcopy_nc[DS] - tc xbcopy_nc[TC],xbcopy_nc[DS] - csect xbcopy_nc[DS] - dc.l .xbcopy_nc - dc.l TOC[tc0] - export .xbcopy_nc - csect xbcopy_nc[PR] -.xbcopy_nc: -#endif +LEXT(bcopy_nc) crset noncache ; Set non-cached b bcpswap +; +; void bcopy_physvir(from, to, nbytes) +; Attempt to copy physically addressed memory with translation on if conditions are met. +; Otherwise do a normal bcopy_phys. +; +; Rules are: neither source nor destination can cross a page. +; No accesses above the 2GB line (I/O or ROM). +; +; Interrupts must be disabled throughout the copy when this is called + +; To do this, we build a +; 128 DBAT for both the source and sink. If both are the same, only one is +; loaded. We do not touch the IBATs, so there is no issue if either physical page +; address is the same as the virtual address of the instructions we are executing. +; +; At the end, we invalidate the used DBATs and reenable interrupts. +; +; Note, this one will not work in user state +; + + .align 5 + .globl EXT(bcopy_physvir) + +LEXT(bcopy_physvir) + + addic. r0,r5,-1 ; Get length - 1 + add r11,r3,r0 ; Point to last byte of sink + cmplw cr1,r3,r4 ; Does source == sink? + add r12,r4,r0 ; Point to last byte of source + bltlr- ; Bail if length is 0 or way too big + xor r7,r11,r3 ; See if we went to next page + xor r8,r12,r4 ; See if we went to next page + or r0,r7,r8 ; Combine wrap + + li r9,((PTE_WIMG_CB_CACHED_COHERENT<<3)|2) ; Set default attributes + rlwinm. r0,r0,0,0,19 ; Did we overflow a page? + li r7,2 ; Set validity flags + li r8,2 ; Set validity flags + bne- EXT(bcopy_phys) ; Overflowed page, do normal physical copy... + + crset killbats ; Remember to trash BATs on the way out + rlwimi r11,r9,0,15,31 ; Set sink lower DBAT value + rlwimi r12,r9,0,15,31 ; Set source lower DBAT value + rlwimi r7,r11,0,0,14 ; Set sink upper DBAT value + rlwimi r8,r12,0,0,14 ; Set source upper DBAT value + cmplw cr1,r11,r12 ; See if sink and source are same block + + sync + + mtdbatl 0,r11 ; Set sink lower DBAT + mtdbatu 0,r7 ; Set sink upper DBAT + + beq- cr1,bcpvsame ; Source and sink are in same block + + mtdbatl 1,r12 ; Set source lower DBAT + mtdbatu 1,r8 ; Set source upper DBAT + +bcpvsame: mr r6,r3 ; Set source + crclr noncache ; Set cached + + b copyit ; Go copy it... + + ; ; void bcopy_phys(from, to, nbytes) ; Turns off data translation before the copy. Note, this one will ; not work in user state ; -#if 0 - IF 0 -#endif -ENTRY(bcopy_phys, TAG_NO_FRAME_USED) -#if 0 - ENDIF - export xbcopy_phys[DS] - tc bcopy_physc[TC],bcopy_phys[DS] - csect bcopy_phys[DS] - dc.l .bcopy_phys - dc.l TOC[tc0] - export .bcopy_phys - csect bcopy_phys[PR] -.bcopy_phys: -#endif + .align 5 + .globl EXT(bcopy_phys) + +LEXT(bcopy_phys) mfmsr r9 ; Get the MSR + crclr noncache ; Set cached rlwinm. r8,r9,0,MSR_DR_BIT,MSR_DR_BIT ; Is data translation on? @@ -105,6 +136,9 @@ ENTRY(bcopy_phys, TAG_NO_FRAME_USED) xor r9,r9,r8 ; Turn off translation if it is on (should be) beqlr- cr7 ; Bail if length is 0 + rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + crclr killbats ; Make sure we do not trash BATs on the way out + rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off mtmsr r9 ; Set DR translation off isync ; Wait for it @@ -115,27 +149,17 @@ ENTRY(bcopy_phys, TAG_NO_FRAME_USED) ; void bcopy(from, to, nbytes) ; -#if 0 - IF 0 -#endif -ENTRY(bcopy, TAG_NO_FRAME_USED) -#if 0 - ENDIF - export xbcopy[DS] - tc xbcopyc[TC],xbcopy[DS] - csect xbcopy[DS] - dc.l .xbcopy - dc.l TOC[tc0] - export .xbcopy - csect xbcopy[PR] -.xbcopy: -#endif + .align 5 + .globl EXT(bcopy) + +LEXT(bcopy) crclr noncache ; Set cached bcpswap: cmplw cr1,r4,r3 ; Compare "to" and "from" mr. r5,r5 ; Check if we have a 0 length mr r6,r3 ; Set source + crclr killbats ; Make sure we do not trash BATs on the way out beqlr- cr1 ; Bail if "to" and "from" are the same beqlr- ; Bail if length is 0 crclr fixxlate ; Set translation already ok @@ -154,21 +178,11 @@ bcpswap: cmplw cr1,r4,r3 ; Compare "to" and "from" ; Later, we should used Altivec for large moves. ; -#if 0 - IF 0 -#endif -ENTRY(memcpy, TAG_NO_FRAME_USED) -#if 0 - ENDIF - export xmemcpy[DS] - tc xmemcpy[TC],xmemcpy[DS] - csect xmemcpy[DS] - dc.l .xmemcpy - dc.l TOC[tc0] - export .xmemcpy - csect xmemcpy[PR] -.xmemcpy: -#endif + .align 5 + .globl EXT(memcpy) + +LEXT(memcpy) + cmplw cr1,r3,r4 ; "to" and "from" the same? mr r6,r4 ; Set the "from" mr. r5,r5 ; Length zero? @@ -177,6 +191,7 @@ ENTRY(memcpy, TAG_NO_FRAME_USED) crclr fixxlate ; Set translation already ok beqlr- cr1 ; "to" and "from" are the same beqlr- ; Length is 0 + crclr killbats ; Make sure we do not trash BATs on the way out copyit: sub r12,r4,r6 ; Get potential overlap (negative if backward move) lis r8,0x7FFF ; Start up a mask @@ -343,13 +358,25 @@ nohalf: bf 31,bcpydone ; Leave cuz we are all done... lbz r7,0(r6) ; Get the byte stb r7,0(r4) ; Save the single -bcpydone: bflr fixxlate ; Leave now if we do not need to fix translation... +bcpydone: bt- killbats,bcclrbat ; Jump if we need to clear bats... + bflr fixxlate ; Leave now if we do not need to fix translation... mfmsr r9 ; Get the MSR ori r9,r9,lo16(MASK(MSR_DR)) ; Turn data translation on + rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off mtmsr r9 ; Just do it isync ; Hang in there blr ; Leave cuz we are all done... +bcclrbat: li r0,0 ; Get set to invalidate upper half + sync ; Make sure all is well + mtdbatu 0,r0 ; Clear sink upper DBAT + mtdbatu 1,r0 ; Clear source upper DBAT + sync + isync + blr + + ; ; 0123456789ABCDEF0123456789ABCDEF ; 0123456789ABCDEF0123456789ABCDEF @@ -433,10 +460,6 @@ balquad: bf 27,balline ; No quad to do... balline: rlwinm. r0,r5,27,5,31 ; Get the number of full lines to move mtcrf 3,r5 ; Make branch mask for backend partial moves beq- bbackend ; No full lines to move -#if 0 - stwu r1,-8(r1) ; Dummy stack for MacOS - stw r2,4(r1) ; Save RTOC -#endif ; Registers in use: R0, R1, R3, R4, R5, R6 @@ -468,10 +491,6 @@ bnotouch: stw r5,-28(r4) ; Get the second word subi r4,r4,32 ; Bump sink bgt+ bnxtline ; Do the next line, if any... -#if 0 - lwz r2,4(r1) ; Restore RTOC - lwz r1,0(r1) ; Pop dummy stack -#endif ; ; Note: We touched these lines in at the beginning @@ -523,4 +542,4 @@ bnohalf: bflr 31 ; Leave cuz we are all done... lbz r7,-1(r6) ; Get the byte stb r7,-1(r4) ; Save the single - blr ; Leave cuz we are all done... + b bcpydone ; Go exit cuz we are all done... diff --git a/osfmk/ppc/bsd_ppc.c b/osfmk/ppc/bsd_ppc.c index e866c31bf..d3afa89dc 100644 --- a/osfmk/ppc/bsd_ppc.c +++ b/osfmk/ppc/bsd_ppc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -35,7 +35,10 @@ #include #include +#include +#include #include +struct proc; #define ERESTART -1 /* restart syscall */ #define EJUSTRETURN -2 /* don't modify regs, just return */ @@ -48,7 +51,7 @@ struct unix_syscallargs { struct sysent { /* system call table */ unsigned short sy_narg; /* number of args */ char sy_parallel; /* can execute in parallel */ - char sy_funnel; /* funnel type */ + char sy_funnel; /* funnel type */ unsigned long (*sy_call)(void *, void *, int *); /* implementing function */ }; @@ -101,79 +104,73 @@ unix_syscall( int arg7 ) { - struct ppc_saved_state *regs; - thread_act_t thread; - struct sysent *callp; - int nargs, error; - unsigned short code; - void * p, *vt; - int * vtint; + struct ppc_saved_state *regs; + thread_act_t thread; + struct sysent *callp; + int nargs, error; + unsigned short code; + struct proc *p; + void *vt; + int * vtint; int *rval; - int funnel_type; + int funnel_type; + struct proc *current_proc(); struct unix_syscallargs sarg; extern int nsysent; + regs = &pcb->ss; + code = regs->r0; - regs = &pcb->ss; - code = regs->r0; - - thread = current_act(); + thread = current_act(); p = current_proc(); rval = (int *)get_bsduthreadrval(thread); - /* - ** Get index into sysent table - */ - - /* - ** Set up call pointer - */ + * Set up call pointer + */ callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; sarg. flavor = (callp == sysent)? 1: 0; if (sarg.flavor) { - code = regs->r3; - callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; - - } - else + code = regs->r3; + callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; + } else sarg. r3 = regs->r3; if (code != 180) { - if (sarg.flavor) - KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START, - arg1, arg2, arg3, arg4, 0); + if (sarg.flavor) + KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START, + arg1, arg2, arg3, arg4, 0); else - KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START, - sarg.r3, arg1, arg2, arg3, 0); + KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START, + sarg.r3, arg1, arg2, arg3, 0); + } + sarg.arg1 = arg1; + sarg.arg2 = arg2; + sarg.arg3 = arg3; + sarg.arg4 = arg4; + sarg.arg5 = arg5; + sarg.arg6 = arg6; + sarg.arg7 = arg7; + + if(callp->sy_funnel == NETWORK_FUNNEL) { + (void) thread_funnel_set(network_flock, TRUE); + } else { + (void) thread_funnel_set(kernel_flock, TRUE); } - sarg. arg1 = arg1; - sarg. arg2 = arg2; - sarg. arg3 = arg3; - sarg. arg4 = arg4; - sarg. arg5 = arg5; - sarg. arg6 = arg6; - sarg. arg7 = arg7; - - if(callp->sy_funnel == NETWORK_FUNNEL) { - (void) thread_funnel_set(network_flock, TRUE); - } - else { - (void) thread_funnel_set(kernel_flock, TRUE); - } set_bsduthreadargs(thread,pcb,&sarg); - if (callp->sy_narg > 8) - panic("unix_syscall: max arg count exceeded"); + panic("unix_syscall: max arg count exceeded"); rval[0] = 0; - /* r4 is volatile, if we set it to regs->r4 here the child - * will have parents r4 after execve */ + /* + * r4 is volatile, if we set it to regs->r4 here the child + * will have parents r4 after execve + */ rval[1] = 0; error = 0; /* Start with a good value */ @@ -187,92 +184,97 @@ unix_syscall( vt = get_bsduthreadarg(thread); counter_always(c_syscalls_unix++); current_task()->syscalls_unix++; + + ktrsyscall(p, code, callp->sy_narg, vt); + error = (*(callp->sy_call))(p, (void *)vt, rval); regs = find_user_regs(thread); if (regs == (struct ppc_saved_state *)0) panic("No user savearea while returning from system call"); - if (error == ERESTART) { - regs->srr0 -= 8; - } - else if (error != EJUSTRETURN) { - if (error) - { - regs->r3 = error; - /* set the "pc" to execute cerror routine */ - regs->srr0 -= 4; - } else { /* (not error) */ - regs->r3 = rval[0]; - regs->r4 = rval[1]; - } - } - /* else (error == EJUSTRETURN) { nothing } */ - - (void) thread_funnel_set(current_thread()->funnel_lock, FALSE); - - if (code != 180) { - KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END, - error, rval[0], rval[1], 0, 0); - } - - thread_exception_return(); - /* NOTREACHED */ + if (error == ERESTART) { + regs->srr0 -= 8; + } else if (error != EJUSTRETURN) { + if (error) { + regs->r3 = error; + /* set the "pc" to execute cerror routine */ + regs->srr0 -= 4; + } else { /* (not error) */ + regs->r3 = rval[0]; + regs->r4 = rval[1]; + } + } + /* else (error == EJUSTRETURN) { nothing } */ + + ktrsysret(p, code, error, rval[0]); + + (void) thread_funnel_set(current_thread()->funnel_lock, FALSE); + + if (code != 180) { + KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END, + error, rval[0], rval[1], 0, 0); + } + + thread_exception_return(); + /* NOTREACHED */ } unix_syscall_return(error) { - struct ppc_saved_state *regs; - thread_act_t thread; - struct sysent *callp; - int nargs; - unsigned short code; + struct ppc_saved_state *regs; + thread_act_t thread; + struct sysent *callp; + int nargs; + unsigned short code; int *rval; - void * p, *vt; - int * vtint; + struct proc *p; + void *vt; + int * vtint; struct pcb *pcb; + struct proc *current_proc(); struct unix_syscallargs sarg; extern int nsysent; - thread = current_act(); + thread = current_act(); p = current_proc(); rval = (int *)get_bsduthreadrval(thread); pcb = thread->mact.pcb; - regs = &pcb->ss; - - if (thread_funnel_get() == THR_FUNNEL_NULL) - panic("Unix syscall return without funnel held"); - - /* - ** Get index into sysent table - */ - code = regs->r0; - - if (error == ERESTART) { - regs->srr0 -= 8; - } - else if (error != EJUSTRETURN) { - if (error) - { - regs->r3 = error; - /* set the "pc" to execute cerror routine */ - regs->srr0 -= 4; - } else { /* (not error) */ - regs->r3 = rval[0]; - regs->r4 = rval[1]; - } - } - /* else (error == EJUSTRETURN) { nothing } */ - - (void) thread_funnel_set(current_thread()->funnel_lock, FALSE); - - if (code != 180) { - KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END, - error, rval[0], rval[1], 0, 0); - } - - thread_exception_return(); - /* NOTREACHED */ + regs = &pcb->ss; + + if (thread_funnel_get() == THR_FUNNEL_NULL) + panic("Unix syscall return without funnel held"); + + /* + * Get index into sysent table + */ + code = regs->r0; + + if (error == ERESTART) { + regs->srr0 -= 8; + } else if (error != EJUSTRETURN) { + if (error) { + regs->r3 = error; + /* set the "pc" to execute cerror routine */ + regs->srr0 -= 4; + } else { /* (not error) */ + regs->r3 = rval[0]; + regs->r4 = rval[1]; + } + } + /* else (error == EJUSTRETURN) { nothing } */ + + ktrsysret(p, code, error, rval[0]); + + (void) thread_funnel_set(current_thread()->funnel_lock, FALSE); + + if (code != 180) { + KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END, + error, rval[0], rval[1], 0, 0); + } + + thread_exception_return(); + /* NOTREACHED */ } diff --git a/osfmk/ppc/bzero.s b/osfmk/ppc/bzero.s index ac0afddf9..2faf894a0 100644 --- a/osfmk/ppc/bzero.s +++ b/osfmk/ppc/bzero.s @@ -169,3 +169,119 @@ ENTRY(memset, TAG_NO_FRAME_USED) /* Return original address in ARG0 */ blr + +/* + * void bzero_nc(char *addr, unsigned int length) + * + * bzero implementation for PowerPC + * - assumes non-pic code + * + * returns start address in r3, as per memset (called by memset) + */ + +ENTRY(bzero_nc, TAG_NO_FRAME_USED) + + cmpwi cr0, r4, 0 /* no bytes to zero? */ + mr r7, r3 + mr r8, r3 /* use r8 as counter to where we are */ + beqlr- + cmpwi cr0, r4, CACHE_LINE_SIZE /* clear less than a block? */ + li r0, 0 /* use r0 as source of zeros */ + blt .L_bzeroNCEndWord + +/* first, clear bytes up to the next word boundary */ + addis r6, 0, HIGH_CADDR(.L_bzeroNCBeginWord) + addi r6, r6, LOW_ADDR(.L_bzeroNCBeginWord) + /* extract byte offset as word offset */ + rlwinm. r5, r8, 2, 28, 29 + addi r8, r8, -1 /* adjust for update */ + beq .L_bzeroNCBeginWord /* no bytes to zero */ + subfic r5, r5, 16 /* compute the number of instructions */ + sub r6, r6, r5 /* back from word clear to execute */ + mtctr r6 + bctr + + stbu r0, 1(r8) + stbu r0, 1(r8) + stbu r0, 1(r8) + +/* clear words up to the next block boundary */ +.L_bzeroNCBeginWord: + addis r6, 0, HIGH_CADDR(.L_bzeroNCBlock) + addi r6, r6, LOW_ADDR(.L_bzeroNCBlock) + addi r8, r8, 1 + rlwinm. r5, r8, 0, 27, 29 /* extract word offset */ + addi r8, r8, -4 /* adjust for update */ + beq .L_bzeroNCBlock /* no words to zero */ + /* compute the number of instructions */ + subfic r5, r5, CACHE_LINE_SIZE + sub r6, r6, r5 /* back from word clear to execute */ + mtctr r6 + bctr + + stwu r0, 4(r8) + stwu r0, 4(r8) + stwu r0, 4(r8) + stwu r0, 4(r8) + stwu r0, 4(r8) + stwu r0, 4(r8) + stwu r0, 4(r8) + + /* clear cache blocks */ +.L_bzeroNCBlock: + addi r8, r8, 4 /* remove update adjust */ + sub r5, r8, r7 /* bytes zeroed */ + sub r4, r4, r5 + srwi. r5, r4, CACHE_LINE_POW2 /* blocks to zero */ + beq .L_bzeroNCEndWord + mtctr r5 + +.L_bzeroNCBlock1: + stw r0, 0(r8) + stw r0, 4(r8) + stw r0, 8(r8) + stw r0, 12(r8) + stw r0, 16(r8) + stw r0, 20(r8) + stw r0, 24(r8) + stw r0, 28(r8) + addi r8, r8, CACHE_LINE_SIZE + bdnz .L_bzeroNCBlock1 + + /* clear remaining words */ +.L_bzeroNCEndWord: + addis r6, 0, HIGH_CADDR(.L_bzeroNCEndByte) + addi r6, r6, LOW_ADDR(.L_bzeroNCEndByte) + rlwinm. r5, r4, 0, 27, 29 /* extract word offset */ + addi r8, r8, -4 /* adjust for update */ + beq .L_bzeroNCEndByte /* no words to zero */ + sub r6, r6, r5 /* back from word clear to execute */ + mtctr r6 + bctr + + stwu r0, 4(r8) + stwu r0, 4(r8) + stwu r0, 4(r8) + stwu r0, 4(r8) + stwu r0, 4(r8) + stwu r0, 4(r8) + stwu r0, 4(r8) + + /* clear remaining bytes */ +.L_bzeroNCEndByte: + addis r6, 0, HIGH_CADDR(.L_bzeroNCEnd) + addi r6, r6, LOW_ADDR(.L_bzeroNCEnd) + /* extract byte offset as word offset */ + rlwinm. r5, r4, 2, 28, 29 + addi r8, r8, 3 /* adjust for update */ + beqlr + sub r6, r6, r5 /* back from word clear to execute */ + mtctr r6 + bctr + + stbu r0, 1(r8) + stbu r0, 1(r8) + stbu r0, 1(r8) + +.L_bzeroNCEnd: + blr diff --git a/osfmk/ppc/cache.s b/osfmk/ppc/cache.s index 5494446aa..0f3157714 100644 --- a/osfmk/ppc/cache.s +++ b/osfmk/ppc/cache.s @@ -46,6 +46,8 @@ ENTRY(sync_cache, TAG_NO_FRAME_USED) /* Switch off data translations */ mfmsr r6 + rlwinm r6,r6,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r6,r6,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r7, r6, 0, MSR_DR_BIT+1, MSR_DR_BIT-1 mtmsr r7 isync @@ -114,6 +116,8 @@ ENTRY(flush_dcache, TAG_NO_FRAME_USED) cmpwi r5, 0 mfmsr r6 beq+ 0f + rlwinm r6,r6,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r6,r6,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r7, r6, 0, MSR_DR_BIT+1, MSR_DR_BIT-1 mtmsr r7 isync @@ -174,6 +178,8 @@ ENTRY(invalidate_dcache, TAG_NO_FRAME_USED) cmpwi r5, 0 mfmsr r6 beq+ 0f + rlwinm r6,r6,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r6,r6,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r7, r6, 0, MSR_DR_BIT+1, MSR_DR_BIT-1 mtmsr r7 isync @@ -232,6 +238,8 @@ ENTRY(invalidate_icache, TAG_NO_FRAME_USED) cmpwi r5, 0 mfmsr r6 beq+ 0f + rlwinm r6,r6,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r6,r6,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r7, r6, 0, MSR_DR_BIT+1, MSR_DR_BIT-1 mtmsr r7 isync diff --git a/osfmk/ppc/cpu.c b/osfmk/ppc/cpu.c index a7d32465b..cbfab1860 100644 --- a/osfmk/ppc/cpu.c +++ b/osfmk/ppc/cpu.c @@ -37,8 +37,9 @@ #include #include #include +#include #include -//#include +#include /* TODO: BOGUS TO BE REMOVED */ int real_ncpus = 1; @@ -62,6 +63,8 @@ struct SIGtimebase { uint64_t abstime; }; +struct per_proc_info *pper_proc_info = per_proc_info; + extern struct SIGtimebase syncClkSpot; void cpu_sync_timebase(void); @@ -460,21 +463,19 @@ cpu_start( proc_info->cpu_number = cpu; proc_info->cpu_flags &= BootDone; - proc_info->istackptr = (vm_offset_t)&intstack + (INTSTACK_SIZE*(cpu+1)) - sizeof (struct ppc_saved_state); + proc_info->istackptr = (vm_offset_t)&intstack + (INTSTACK_SIZE*(cpu+1)) - FM_SIZE; proc_info->intstack_top_ss = proc_info->istackptr; #if MACH_KDP || MACH_KDB - proc_info->debstackptr = (vm_offset_t)&debstack + (KERNEL_STACK_SIZE*(cpu+1)) - sizeof (struct ppc_saved_state); + proc_info->debstackptr = (vm_offset_t)&debstack + (KERNEL_STACK_SIZE*(cpu+1)) - FM_SIZE; proc_info->debstack_top_ss = proc_info->debstackptr; #endif /* MACH_KDP || MACH_KDB */ proc_info->interrupts_enabled = 0; proc_info->active_kloaded = (unsigned int)&active_kloaded[cpu]; - proc_info->cpu_data = (unsigned int)&cpu_data[cpu]; proc_info->active_stacks = (unsigned int)&active_stacks[cpu]; proc_info->need_ast = (unsigned int)&need_ast[cpu]; - proc_info->FPU_thread = 0; - proc_info->FPU_vmmCtx = 0; - proc_info->VMX_thread = 0; - proc_info->VMX_vmmCtx = 0; + proc_info->FPU_owner = 0; + proc_info->VMX_owner = 0; + if (proc_info->start_paddr == EXCEPTION_VECTOR(T_RESET)) { @@ -499,7 +500,7 @@ cpu_start( * that all processors are the same. This is just to get close. */ - ml_get_timebase(&proc_info->ruptStamp); /* Pass our current time to the other guy */ + ml_get_timebase((unsigned long long *)&proc_info->ruptStamp); /* Pass our current time to the other guy */ __asm__ volatile("sync"); /* Commit to storage */ __asm__ volatile("isync"); /* Wait a second */ @@ -540,8 +541,8 @@ cpu_signal_handler( /* * Since we've been signaled, wait just under 1ms for the signal lock to pass */ - if(!hw_lock_mbits(&pproc->MPsigpStat, MPsigpMsgp, (MPsigpBusy | MPsigpPass), - (MPsigpBusy | MPsigpPass), (gPEClockFrequencyInfo.bus_clock_rate_hz >> 7))) { + if(!hw_lock_mbits(&pproc->MPsigpStat, (MPsigpMsgp | MPsigpAck), (MPsigpBusy | MPsigpPass), + (MPsigpBusy | MPsigpPass | MPsigpAck), (gPEClockFrequencyInfo.bus_clock_rate_hz >> 7))) { panic("cpu_signal_handler: Lock pass timed out\n"); } @@ -552,7 +553,7 @@ cpu_signal_handler( __asm__ volatile("isync"); /* Make sure we don't unlock until memory is in */ - pproc->MPsigpStat = holdStat & ~(MPsigpMsgp | MPsigpFunc); /* Release lock */ + pproc->MPsigpStat = holdStat & ~(MPsigpMsgp | MPsigpAck | MPsigpFunc); /* Release lock */ switch ((holdStat & MPsigpFunc) >> 8) { /* Decode function code */ @@ -568,9 +569,7 @@ cpu_signal_handler( #if 0 kprintf("cpu_signal_handler: AST check on cpu %x\n", cpu_number()); #endif - ast_check(); /* Yes, do it */ - /* XXX: Should check if AST_URGENT is needed */ - ast_on(AST_URGENT); + ast_check(cpu_to_processor(cpu)); return; /* All done... */ case SIGPcpureq: /* CPU specific function? */ @@ -673,6 +672,7 @@ cpu_signal( unsigned int holdStat, holdParm0, holdParm1, holdParm2, mtype; struct per_proc_info *tpproc, *mpproc; /* Area for per_proc addresses */ int cpu; + int busybitset =0; #if DEBUG if(target > NCPUS) panic("cpu_signal: invalid target CPU - %08X\n", target); @@ -686,18 +686,32 @@ cpu_signal( tpproc = &per_proc_info[target]; /* Point to the target's block */ if (!(tpproc->cpu_flags & SignalReady)) return KERN_FAILURE; - + if((tpproc->MPsigpStat & MPsigpMsgp) == MPsigpMsgp) { /* Is there an unreceived message already pending? */ - if(signal == SIGPwake) return KERN_SUCCESS; /* SIGPwake can merge into all others... */ + if(signal == SIGPwake) { /* SIGPwake can merge into all others... */ + mpproc->numSIGPmwake++; /* Account for merged wakes */ + return KERN_SUCCESS; + } if((signal == SIGPast) && (tpproc->MPsigpParm0 == SIGPast)) { /* We can merge ASTs */ + mpproc->numSIGPmast++; /* Account for merged ASTs */ return KERN_SUCCESS; /* Don't bother to send this one... */ } + + if (tpproc->MPsigpParm0 == SIGPwake) { + if (hw_lock_mbits(&tpproc->MPsigpStat, (MPsigpMsgp | MPsigpAck), + (MPsigpBusy | MPsigpPass ), MPsigpBusy, 0)) { + busybitset = 1; + mpproc->numSIGPmwake++; + } + } } - if(!hw_lock_mbits(&tpproc->MPsigpStat, MPsigpMsgp, 0, MPsigpBusy, - (gPEClockFrequencyInfo.bus_clock_rate_hz >> 13))) { /* Try to lock the message block with a .5ms timeout */ + if((busybitset == 0) && + (!hw_lock_mbits(&tpproc->MPsigpStat, MPsigpMsgp, 0, MPsigpBusy, + (gPEClockFrequencyInfo.bus_clock_rate_hz >> 13)))) { /* Try to lock the message block with a .5ms timeout */ + mpproc->numSIGPtimo++; /* Account for timeouts */ return KERN_FAILURE; /* Timed out, take your ball and go home... */ } @@ -711,7 +725,8 @@ cpu_signal( tpproc->MPsigpStat = holdStat; /* Set status and pass the lock */ __asm__ volatile("eieio"); /* I'm a paraniod freak */ - PE_cpu_signal(mpproc->cpu_id, tpproc->cpu_id); /* Kick the other processor */ + if (busybitset == 0) + PE_cpu_signal(mpproc->cpu_id, tpproc->cpu_id); /* Kick the other processor */ return KERN_SUCCESS; /* All is goodness and rainbows... */ } @@ -729,6 +744,7 @@ cpu_sleep( { struct per_proc_info *proc_info; unsigned int cpu; + facility_context *fowner; extern void (*exception_handlers[])(void); extern vm_offset_t intstack; extern vm_offset_t debstack; @@ -741,18 +757,20 @@ cpu_sleep( proc_info = &per_proc_info[cpu]; - if(proc_info->FPU_thread) fpu_save(proc_info->FPU_thread); /* If anyone owns FPU, save it */ - proc_info->FPU_thread = 0; /* Set no fpu owner now */ + fowner = proc_info->FPU_owner; /* Cache this */ + if(fowner) fpu_save(fowner); /* If anyone owns FPU, save it */ + proc_info->FPU_owner = 0; /* Set no fpu owner now */ - if(proc_info->VMX_thread) vec_save(proc_info->VMX_thread); /* If anyone owns vectors, save it */ - proc_info->VMX_thread = 0; /* Set no vector owner now */ + fowner = proc_info->VMX_owner; /* Cache this */ + if(fowner) vec_save(fowner); /* If anyone owns vectors, save it */ + proc_info->VMX_owner = 0; /* Set no vector owner now */ if (proc_info->cpu_number == 0) { proc_info->cpu_flags &= BootDone; - proc_info->istackptr = (vm_offset_t)&intstack + (INTSTACK_SIZE*(cpu+1)) - sizeof (struct ppc_saved_state); + proc_info->istackptr = (vm_offset_t)&intstack + (INTSTACK_SIZE*(cpu+1)) - FM_SIZE; proc_info->intstack_top_ss = proc_info->istackptr; #if MACH_KDP || MACH_KDB - proc_info->debstackptr = (vm_offset_t)&debstack + (KERNEL_STACK_SIZE*(cpu+1)) - sizeof (struct ppc_saved_state); + proc_info->debstackptr = (vm_offset_t)&debstack + (KERNEL_STACK_SIZE*(cpu+1)) - FM_SIZE; proc_info->debstack_top_ss = proc_info->debstackptr; #endif /* MACH_KDP || MACH_KDB */ proc_info->interrupts_enabled = 0; diff --git a/osfmk/ppc/cpu_data.h b/osfmk/ppc/cpu_data.h index ebaf57d90..e97ccb865 100644 --- a/osfmk/ppc/cpu_data.h +++ b/osfmk/ppc/cpu_data.h @@ -27,7 +27,6 @@ #ifndef PPC_CPU_DATA #define PPC_CPU_DATA -#if defined(__GNUC__) #define disable_preemption _disable_preemption #define enable_preemption _enable_preemption @@ -36,7 +35,20 @@ #define mp_enable_preemption _enable_preemption #define mp_enable_preemption_no_check _enable_preemption_no_check -extern thread_t current_thread(void); +extern cpu_data_t* get_cpu_data(void); + +extern __inline__ thread_act_t current_act(void) +{ + thread_act_t act; + __asm__ volatile("mfsprg %0,1" : "=r" (act)); + return act; +} + +#define current_thread() current_act()->thread + +extern void set_machine_current_thread(thread_t); +extern void set_machine_current_act(thread_act_t); + extern int get_preemption_level(void); extern void disable_preemption(void); extern void enable_preemption(void); @@ -45,6 +57,5 @@ extern void mp_disable_preemption(void); extern void mp_enable_preemption(void); extern void mp_enable_preemption_no_check(void); extern int get_simple_lock_count(void); -#endif /* defined(__GNUC__) */ #endif /* PPC_CPU_DATA */ diff --git a/osfmk/ppc/cpu_number.h b/osfmk/ppc/cpu_number.h index 6aea4245d..1c3626e58 100644 --- a/osfmk/ppc/cpu_number.h +++ b/osfmk/ppc/cpu_number.h @@ -25,6 +25,10 @@ #ifndef _PPC_CPU_NUMBER_H_ #define _PPC_CPU_NUMBER_H_ +#include + +#ifdef __APPLE_API_UNSTABLE extern int cpu_number(void); +#endif #endif /* _PPC_CPU_NUMBER_H_ */ diff --git a/osfmk/ppc/cswtch.s b/osfmk/ppc/cswtch.s index 8a4d0ac65..3cca411b2 100644 --- a/osfmk/ppc/cswtch.s +++ b/osfmk/ppc/cswtch.s @@ -30,6 +30,7 @@ #include #include #include +#include #define FPVECDBG 0 #define GDDBG 0 @@ -46,12 +47,19 @@ * otherwise both entry points are identical. */ -ENTRY2(load_context, Load_context, TAG_NO_FRAME_USED) + .align 5 + .globl EXT(load_context) + +LEXT(load_context) + + .globl EXT(Load_context) + +LEXT(Load_context) /* * Since this is the first thread, we came in on the interrupt * stack. The first thread never returns, so there is no need to - * worry about saving its frame, hence we can reset the istackptr + e worry about saving its frame, hence we can reset the istackptr * back to the saved_state structure at it's top */ @@ -63,29 +71,26 @@ ENTRY2(load_context, Load_context, TAG_NO_FRAME_USED) mfsprg r6,0 lwz r0,PP_INTSTACK_TOP_SS(r6) - lwz r11,PP_CPU_DATA(r6) stw r0,PP_ISTACKPTR(r6) - stw r3,CPU_ACTIVE_THREAD(r11) + stw r3,PP_ACTIVE_THREAD(r6) /* Find the new stack and store it in active_stacks */ lwz r12,PP_ACTIVE_STACKS(r6) lwz r1,THREAD_KERNEL_STACK(r3) lwz r9,THREAD_TOP_ACT(r3) /* Point to the active activation */ + mtsprg 1,r9 stw r1,0(r12) li r0,0 /* Clear a register */ lwz r8,ACT_MACT_PCB(r9) /* Get the savearea used */ - lwz r10,SAVflags(r8) /* Get the savearea flags */ rlwinm r7,r8,0,0,19 /* Switch to savearea base */ lwz r11,SAVprev(r8) /* Get the previous savearea */ mfmsr r5 /* Since we are passing control, get our MSR values */ lwz r1,saver1(r8) /* Load new stack pointer */ - rlwinm r10,r10,0,1,31 /* Remove the attached flag */ stw r0,saver3(r8) /* Make sure we pass in a 0 for the continuation */ lwz r7,SACvrswap(r7) /* Get the translation from virtual to real */ stw r0,FM_BACKPTR(r1) /* zero backptr */ stw r5,savesrr1(r8) /* Pass our MSR to the new guy */ - stw r10,SAVflags(r8) /* Pass back the flags */ xor r3,r7,r8 /* Get the physical address of the new context save area */ stw r11,ACT_MACT_PCB(r9) /* Unstack our savearea */ b EXT(exception_exit) /* Go end it all... */ @@ -102,10 +107,14 @@ ENTRY2(load_context, Load_context, TAG_NO_FRAME_USED) /* void Call_continuation( void (*continuation)(void), vm_offset_t stack_ptr) */ -ENTRY(Call_continuation, TAG_NO_FRAME_USED) - mtlr r3 - mr r1, r4 /* Load new stack pointer */ - blr /* Jump to the continuation */ + .align 5 + .globl EXT(Call_continuation) + +LEXT(Call_continuation) + + mtlr r3 + mr r1, r4 /* Load new stack pointer */ + blr /* Jump to the continuation */ /* * Get the old kernel stack, and store into the thread structure. @@ -129,48 +138,59 @@ ENTRY(Call_continuation, TAG_NO_FRAME_USED) */ -ENTRY(Switch_context, TAG_NO_FRAME_USED) + .align 5 + .globl EXT(Switch_context) - mfsprg r6,0 /* Get the per_proc block */ - lwz r12,PP_ACTIVE_STACKS(r6) +LEXT(Switch_context) + + mfsprg r12,0 ; Get the per_proc block + lwz r10,PP_ACTIVE_STACKS(r12) ; Get the pointer to the current stack #if DEBUG - lwz r11,PP_ISTACKPTR(r6) ; (DEBUG/TRACE) make sure we are not + lwz r11,PP_ISTACKPTR(r12) ; (DEBUG/TRACE) make sure we are not mr. r11,r11 ; (DEBUG/TRACE) on the interrupt bne+ notonintstack ; (DEBUG/TRACE) stack BREAKPOINT_TRAP notonintstack: #endif - stw r4,THREAD_CONTINUATION(r3) - cmpwi cr1,r4,0 /* used waaaay down below */ - lwz r7,0(r12) + stw r4,THREAD_CONTINUATION(r3) ; Set continuation into the thread + cmpwi cr1,r4,0 ; used waaaay down below + lwz r7,0(r10) ; Get the current stack /* * Make the new thread the current thread. */ - lwz r11,PP_CPU_DATA(r6) - stw r7,THREAD_KERNEL_STACK(r3) - stw r5, CPU_ACTIVE_THREAD(r11) + stw r7,THREAD_KERNEL_STACK(r3) ; Remember the current stack in the thread (do not need???) + stw r5, PP_ACTIVE_THREAD(r12) ; Make the new thread current - lwz r11,THREAD_KERNEL_STACK(r5) + lwz r11,THREAD_KERNEL_STACK(r5) ; Get the new stack pointer - lwz r5,THREAD_TOP_ACT(r5) - lwz r10,PP_ACTIVE_STACKS(r6) + lwz r5,THREAD_TOP_ACT(r5) ; Get the new activation + mtsprg 1,r5 lwz r7,CTHREAD_SELF(r5) ; Pick up the user assist word lwz r8,ACT_MACT_PCB(r5) ; Get the PCB for the new guy - - stw r11,0(r10) ; Save the kernel stack address - stw r7,UAW(r6) ; Save the assist word for the "ultra fast path" + +#if 0 + lwz r0,SAVflags(r8) ; (TEST/DEBUG) + rlwinm r0,r0,24,24,31 ; (TEST/DEBUG) + cmplwi r0,SAVempty ; (TEST/DEBUG) + bne+ nnnn ; (TEST/DEBUG) + b . ; (TEST/DEBUG) +nnnn: ; (TEST/DEBUG) +#endif + + stw r11,0(r10) ; Save the new kernel stack address + stw r7,UAW(r12) ; Save the assist word for the "ultra fast path" lwz r11,ACT_MACT_BTE(r5) ; Get BlueBox Task Environment lwz r7,ACT_MACT_SPF(r5) ; Get the special flags lwz r10,ACT_KLOADED(r5) - stw r11,ppbbTaskEnv(r6) ; Save the bb task env + stw r11,ppbbTaskEnv(r12) ; Save the bb task env li r0,0 cmpwi cr0,r10,0 - lwz r10,PP_ACTIVE_KLOADED(r6) - stw r7,spcFlags(r6) ; Set per_proc copy of the special flags + lwz r10,PP_ACTIVE_KLOADED(r12) + stw r7,spcFlags(r12) ; Set per_proc copy of the special flags beq cr0,.L_sw_ctx_not_kld stw r5,0(r10) @@ -197,26 +217,131 @@ notonintstack: cswNoTrc: mfmsr r6 /* Get the MSR because the switched to thread should inherit it */ lwz r7,SACvrswap(r7) /* Get the translation from virtual to real */ - lis r0,hi16(SwitchContextCall) /* Top part of switch context */ - lis r9,hi16(EXT(switch_in)) /* Get top of switch in routine */ stw r11,ACT_MACT_PCB(r5) /* Dequeue the savearea we're switching to */ rlwinm r6,r6,0,MSR_FP_BIT+1,MSR_FP_BIT-1 /* Turn off the FP */ - ori r9,r9,lo16(EXT(switch_in)) /* Bottom half of switch in */ - lwz r5,savesrr0(r8) /* Set up the new SRR0 */ + lwz r2,curctx(r5) ; Grab our current context pointer rlwinm r6,r6,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 /* Turn off the vector */ mr r4,r3 /* Save our old thread to pass back */ + + lhz r0,PP_CPU_NUMBER(r12) ; Get our CPU number + lwz r10,FPUowner(r12) ; Grab the owner of the FPU + lwz r9,VMXowner(r12) ; Grab the owner of the vector + cmplw r10,r2 ; Do we have the live float context? + lwz r10,FPUlevel(r2) ; Get the live level + cmplw cr5,r9,r2 ; Do we have the live vector context? + bne+ cswnofloat ; Float is not ours... + + cmplw r10,r11 ; Is the level the same? + lwz r5,FPUcpu(r2) ; Get the owning cpu + bne+ cswnofloat ; Level not the same, this is not live... + + cmplw r5,r0 ; Still owned by this cpu? + lwz r10,FPUsave(r2) ; Get the level + bne+ cswnofloat ; CPU claimed by someone else... + + mr. r10,r10 ; Is there a savearea here? + ori r6,r6,lo16(MASK(MSR_FP)) ; Enable floating point + + beq- cswnofloat ; No savearea to check... + + lwz r3,SAVlevel(r10) ; Get the level + lwz r5,SAVprev(r10) ; Get the previous of this savearea + cmplw r3,r11 ; Is it for the current level? + + bne+ cswnofloat ; Nope... + + stw r5,FPUsave(r2) ; Pop off this savearea + rlwinm r5,r10,0,0,19 ; Move back to start of page + lwz r5,SACvrswap(r5) ; Get the virtual to real conversion + la r9,quickfret(r12) ; Point to the quickfret chain header + xor r5,r10,r5 ; Convert savearea address to real + +#if FPVECDBG + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x4401 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) + lhz r0,PP_CPU_NUMBER(r12) ; (TEST/DEBUG) +#endif + +; +; Note: we need to do the atomic operation here because, even though +; it is impossible with the current implementation, that we may take a +; PTE miss between the load of the quickfret anchor and the subsequent +; store. The interrupt handler will dequeue everything on the list and +; we could end up using stale data. I do not like doing this... +; + +cswfpudq: lwarx r3,0,r9 ; Pick up the old chain head + stw r3,SAVprev(r10) ; Move it to the current guy + stwcx. r5,0,r9 ; Save it + bne- cswfpudq ; Someone chaged the list... + +cswnofloat: bne+ cr5,cswnovect ; Vector is not ours... + + lwz r10,VMXlevel(r2) ; Get the live level + + cmplw r10,r11 ; Is the level the same? + lwz r5,VMXcpu(r2) ; Get the owning cpu + bne+ cswnovect ; Level not the same, this is not live... + + cmplw r5,r0 ; Still owned by this cpu? + lwz r10,VMXsave(r2) ; Get the level + bne+ cswnovect ; CPU claimed by someone else... + + mr. r10,r10 ; Is there a savearea here? + oris r6,r6,hi16(MASK(MSR_VEC)) ; Enable vector + + beq- cswnovect ; No savearea to check... + + lwz r3,SAVlevel(r10) ; Get the level + lwz r5,SAVprev(r10) ; Get the previous of this savearea + cmplw r3,r11 ; Is it for the current level? + + bne+ cswnovect ; Nope... + + stw r5,VMXsave(r2) ; Pop off this savearea + rlwinm r5,r10,0,0,19 ; Move back to start of page + lwz r5,SACvrswap(r5) ; Get the virtual to real conversion + la r9,quickfret(r12) ; Point to the quickfret chain header + xor r5,r10,r5 ; Convert savearea address to real + +#if FPVECDBG + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x4501 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) +#endif + +; +; Note: we need to do the atomic operation here because, even though +; it is impossible with the current implementation, that we may take a +; PTE miss between the load of the quickfret anchor and the subsequent +; store. The interrupt handler will dequeue everything on the list and +; we could end up using stale data. I do not like doing this... +; + +cswvecdq: lwarx r3,0,r9 ; Pick up the old chain head + stw r3,SAVprev(r10) ; Move it to the current guy + stwcx. r5,0,r9 ; Save it + bne- cswvecdq ; Someone chaged the list... + +cswnovect: lis r9,hi16(EXT(switch_in)) /* Get top of switch in routine */ + lwz r5,savesrr0(r8) /* Set up the new SRR0 */ + ori r9,r9,lo16(EXT(switch_in)) /* Bottom half of switch in */ + lis r0,hi16(SwitchContextCall) /* Top part of switch context */ stw r9,savesrr0(r8) /* Make us jump to the switch in routine */ + li r10,MSR_SUPERVISOR_INT_OFF /* Get the switcher's MSR */ lwz r9,SAVflags(r8) /* Get the flags */ stw r10,savesrr1(r8) /* Set up for switch in */ rlwinm r9,r9,0,15,13 /* Reset the syscall flag */ ori r0,r0,lo16(SwitchContextCall) /* Bottom part of switch context */ - rlwinm r9,r9,0,1,31 /* Clear the attached flag */ xor r3,r7,r8 /* Get the physical address of the new context save area */ stw r9,SAVflags(r8) /* Set the flags */ -/* if blocking on continuation avoid saving state */ - bne cr1,1f + + bne cr1,swtchtocont ; Switch to the continuation sc /* Switch to the new context */ /* We come back here in the new thread context @@ -224,10 +349,22 @@ cswNoTrc: mfmsr r6 /* Get the MSR because the switched to thread should i * R3 where it belongs. */ blr /* Jump into the new thread */ + +; +; This is where we go when a continuation is set. We are actually +; killing off the old context of the new guy so we need to pop off +; any float or vector states for the ditched level. +; +; Note that we do the same kind of thing a chkfac in hw_exceptions.s +; + -1: stw r5,savesrr0(r8) /* go to real pc */ - stw r4,saver3(r8) /* must pass back old thread */ - b EXT(exception_exit) /* blocking on continuation, avoid state save */ +swtchtocont: + stw r5,savesrr0(r8) ; Set the pc + stw r6,savesrr1(r8) ; Set the next MSR to use + stw r4,saver3(r8) ; Make sure we pass back the old thread + + b EXT(exception_exit) ; Blocking on continuation, toss old context... @@ -246,10 +383,13 @@ cswNoTrc: mfmsr r6 /* Get the MSR because the switched to thread should i */ -ENTRY(switch_in, TAG_NO_FRAME_USED) + + .align 5 + .globl EXT(switch_in) + +LEXT(switch_in) lwz r4,saver4(r3) /* Get the old thread */ - li r8,MSR_VM_OFF /* Set to everything off */ lwz r9,THREAD_TOP_ACT(r4) /* Get the switched from ACT */ lwz r5,saver5(r3) /* Get the srr0 value */ lwz r10,ACT_MACT_PCB(r9) /* Get the top PCB on the old thread */ @@ -275,398 +415,158 @@ ENTRY(switch_in, TAG_NO_FRAME_USED) /* - * void fpu_save(thread_act_t act) - * - * To do the floating point and VMX, we keep three thread pointers: one - * to the current thread, one to the thread that has the floating point context - * loaded into the FPU registers, and one for the VMX owner. + * void fpu_save(facility_context ctx) * - * Each of these threads has three PCB pointers. The normal PCB, the FPU pcb, - * and the VMX pcb. There is also a bit for each in the savearea flags. - * When we take an exception, or need to use the FPU/VMX in the kernel, we call - * this routine. It checks to see if there is an owner thread for the facility. - * If so, it saves the facility's state information in the normal PCB. Then, it - * turns on the appropriate flag in the savearea to indicate that the state is - * in that particular savearea. Also, the thread pointer for the owner in - * the per_processor block is cleared. Note that we don't have to worry about the - * PCB pointers in the thread because whenever the state is loaded, the associated - * savearea is released and the pointer cleared. This is done so that the facility - * context always migrates to the normal savearea/PCB. This always insures that - * no more than 2 saveareas are used for a thread. - * - * When the context is loaded into the facility, the associated PCB is released if - * its usage flags indicate that it is empty. (Note that return from exception and - * context switch honor these flags and won't release a savearea if there is unrestored - * facility context.) The per_processor is set to point to the facility owner's - * thread and the associated PCB pointer within the thread is cleared because - * the PCB has been released. - * - * Part of loading a context is to release the savearea. If the savearea contains - * other context, the savearea cannot be released. So, what we're left with is - * that there will be no normal context savearea, but one for the as-not-yet - * restored facility savearea. Again, when that context is reloaded, the PCB - * is released, and when it is again stored, it goes into the "normal" savearea. - * - * So, what do we do when there is no general context, and we have some FPU/VMX - * state to save? Heck if I know, but it happens when we switch threads when - * we shortcut system calls. The question is: does the target thread carry the - * FPU/VMX context with it or not? Actually, it don't matter, not one little bit. - * If we are asked to save it, we gotta. It's a really lousy way to do it, but - * short of starting over with FPUs, it's what's what. Therefore, we'll - * allocate an FPU context save and attach it. - * - * Actually, it's not quite that simple: since we aren't in - * in interrupt handler context (that's only in fpu_switch) we can't use - * quickfret to merge FPU into general context. So, if there is an FPU - * savearea, we need to use that. So what we do is: if there is FPU context - * use that. If there is a general context, then use that. If neither, - * allocate a savearea and make that the FPU context. - * - * The next thing we have to do is to allow the kernel to use both the - * floating point and Altivec. It is not recommended, but there may be a - * good reason to do so. So, what we need to do is to treat each of the - * three types of context the same, by keeping a LIFO chain of states. - * We do have a problem with that in that there can be multiple levels of - * kernel context. For example, we are using floating point and we take a - * page fault, and somehow start using the FPU, and take another page fault, - * etc. - * - * Anyway, we will hope that we only reasonably use floating point and vectors in - * the kernel. And try to pack the context in as few saveareas as possible. - * - * The way we keep these "levels" of floating point or vector context straight is - * to remember the top of the normal savearea chain when we activate the - * facility when it is first used. Then, when we save that context, this value - * is saved in its level field. - * - * What the level concept gives us is a way to distinguish between multiple - * independent contexts under the same thread activation. Any time we take - * any kind of interruption (trap, system call, I/O interruption), we are, - * in effect, running with a different context even though we are in the - * same thread. The top savearea address is used only as a marker. It does not - * point to any context associated with the float or vector context. For example, - * the top savearea pointer will always be 0 for the user context, because there - * it it always last on the list. - * - * As normal context is unstacked, the first facility context is checked and - * if there is a match, the facility savearea is released. This is because we - * are returning to a level before the facility saved there was used. In effect, - * this allows us to unwind the facility context saveareas at different rates. - * - * In conjunction with the current activation, these markers are also used to - * determine the state of the facility enablement. Whenever the facility context is - * "live," i.e., loaded in the hardware registers and belonging to the currently - * running context, the facility is enabled before dispatch. - * - * There is nothing special about using floating point or vector facilities, - * no preliminary saving, enabling, or disabling. You just use them. The only exception - * is during context switching on an SMP system. In this case, the context must - * be saved as there is no guarantee that the thread will resume on the same - * processor. This is not a good thing, not at all. - * - * Whenever we switch out a thread with a dirty context, we always need to save it - * because it can wake up on a different processor. However, once the context has - * been saved, we don't need to save it again until it gets dirty, nor do we need - * to reload it unless someone else's context has been loaded. To handle this - * optimization, we need 3 things. We need to know what processor the saved context - * was last loaded on, whether the loaded context could be dirty, and if we've already - * saved it. - * - * Whenever the facility is enabled, the processor ID is saved in the activation. This - * will show which processor has dirty data. When a context switch occurs, the facility - * contexts are saved, but are still remembered as live. The next time we need to - * context switch, we first check if the state is live, and if not, do no state - * saving. Then we check if the state has already been save and if not, save it. - * The facility is always disabled on a context switch. On a UP, this save function - * does not occur. - * - * Whenever a facility unavailable interruption occurs, the current state is saved - * if it is live and unsaved. However, if the live state is the same as the new - * one to be loaded, the processor ID is checked and if it is the current processor - * the state does not need to be loaded or saved. The facility is simply enabled. - * - * Once allocated, facility saveareas are not released until a return is made to a - * previous level. Once a facility has been enabled, there is no way to tell if - * it will ever be used again, but it is likely. Therefore, discarding a savearea - * when its context is made live is extra overhead. So, we don't do it, but we - * do mark the savearea contents as invalid. - * + * Note that there are some oddities here when we save a context we are using. + * It is really not too cool to do this, but what the hey... Anyway, + * we turn fpus and vecs off before we leave., The oddity is that if you use fpus after this, the + * savearea containing the context just saved will go away. So, bottom line is + * that don't use fpus until after you are done with the saved context. */ + .align 5 + .globl EXT(fpu_save) -/* -; The following is the actual way it is implemented. It doesn't quite match -; the above text. I need to go and fix that. -; -; Context download (operates on owner's data): -; -; 0) enable facility -; 1) if no owner exit to context restore -; 2) if context processor != current processor exit to context restore -; 3) if current activation == owner activation: -; 1) if curr level == active level: -; 1) if top facility savearea exists: -; invalidate savearea by setting level to 1 -; 2) enable facility for user -; 3) exit -; -; 2) else go to 5 -; -; 4) if curr level == active level: -; 1) if top facility savearea exists: -; 1) if top save level == active level exit to context restore -; -; 5) allocate savearea -; 1) if there is a facility save and it is invalid, select it, and break -; 2) scan normal list for free facility area, select if found, and break -; 3) scan other facility for free save: select, if found, and break -; 4) allocate a new save area -; -; 6) save context -; 7) mark facility save with curr level -; 8) if reusing cached savearea (case #1) exit to context restore -; 9) set facility save backchain to facility top savearea -; 10) set facility top to savearea -; 11) exit to context restore -; -; -; Context restore/upload (operates on current activation's data): -; -; 1) set current to activation -; 2) set active level to current level -; 3) set context processor to current processor -; 4) if no facility savearea or top save level != curr level -; initialize facility registers to empty value -; 5) else -; 1) load registers from savearea -; 2) invalidate save area by setting level to 1 -; -; 6) enable facility for user -; 7) exit to interrupt return -; -; -; Context save (operates on specified activation's data): - -; 1) if no owner exit -; 2) if owner != specified activation exit -; 3) if context processor != current processor -; 1) clear owner -; 2) exit -; -; 4) if facility top savearea level exists and == active level exit -; 5) if curr level != active level exit -; 6) allocate savearea -; 1) if there is a facility save and it is invalid, select it, and break -; 2) scan normal list for free facility area, select if found, and break -; 3) scan other facility for free save: select, if found, and break -; 4) allocate a new save area -; 7) save context -; 8) mark facility savearea with curr level -; 9) if reusing cached savearea (case #1) exit -; 10) set facility save backchain to facility top savearea -; 11) set facility top to savearea -; 12) exit -; -; -; Exception exit (hw_exceptions): -; -; 1) disable return facility -; 2) if returning savearea != active level -; 1) if owner != current activation exit -; 2) if context processor != current processor: -; 1) clear owner -; 2) exit -; -; 3) if new level != active level exit -; 4) enable return facility -; 5) exit -; -; 3) if no facility savearea exit -; 4) if top save level == active or top is invalid -; 1) dequeue top facility savearea -; 2) set active level to new top savearea's level -; 3) release savearea -; 4) if owner == current activation clear owner -; 5) exit -; -; -; -; -; if (owner == activation) && (curr level == active level) -; && (activation processor == current processor) ::= context live -*/ - -ENTRY(fpu_save, TAG_NO_FRAME_USED) - - mfmsr r0 ; Get the MSR - rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Turn off floating point forever +LEXT(fpu_save) + + + mfmsr r0 ; Get the MSR + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r2,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; But do interrupts only for now - ori r2,r2,MASK(MSR_FP) ; Enable the floating point feature for now also - mtmsr r2 ; Set the MSR + ori r2,r2,MASK(MSR_FP) ; Enable the floating point feature for now also + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + mtmsr r2 ; Set the MSR isync - - mfsprg r6,0 ; Get the per_processor block - lwz r12,PP_FPU_THREAD(r6) ; Get the thread that owns the FPU + + mfsprg r6,0 ; Get the per_processor block + lwz r12,FPUowner(r6) ; Get the context ID for owner + #if FPVECDBG - mr r7,r0 ; (TEST/DEBUG) - li r4,0 ; (TEST/DEBUG) - mr r10,r3 ; (TEST/DEBUG) - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - mr. r3,r12 ; (TEST/DEBUG) - li r2,0x6F00 ; (TEST/DEBUG) - li r5,0 ; (TEST/DEBUG) - beq- noowneryet ; (TEST/DEBUG) - lwz r4,ACT_MACT_FPUlvl(r12) ; (TEST/DEBUG) - lwz r5,ACT_MACT_FPU(r12) ; (TEST/DEBUG) - -noowneryet: oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) - mr r0,r7 ; (TEST/DEBUG) - mr r3,r10 ; (TEST/DEBUG) + mr r7,r0 ; (TEST/DEBUG) + li r4,0 ; (TEST/DEBUG) + mr r10,r3 ; (TEST/DEBUG) + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + mr. r3,r12 ; (TEST/DEBUG) + li r2,0x6F00 ; (TEST/DEBUG) + li r5,0 ; (TEST/DEBUG) + beq- noowneryet ; (TEST/DEBUG) + lwz r4,FPUlevel(r12) ; (TEST/DEBUG) + lwz r5,FPUsave(r12) ; (TEST/DEBUG) + +noowneryet: oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) + mr r0,r7 ; (TEST/DEBUG) + mr r3,r10 ; (TEST/DEBUG) #endif - mflr r2 ; Save the return address - lhz r11,PP_CPU_NUMBER(r6) ; Get our CPU number + mflr r2 ; Save the return address + +fsretry: mr. r12,r12 ; Anyone own the FPU? + lhz r11,PP_CPU_NUMBER(r6) ; Get our CPU number + beq- fsret ; Nobody owns the FPU, no save required... - mr. r12,r12 ; Anyone own the FPU? - cmplw cr1,r3,r12 ; Is the specified thread the owner? + cmplw cr1,r3,r12 ; Is the specified context live? - beq- fsretnr ; Nobody owns the FPU, no save required... + isync ; Force owner check first - li r4,ACT_MACT_FPUcpu ; Point to the CPU indication/lock word - bne- cr1,fsretnr ; Facility belongs to some other activation... + lwz r9,FPUcpu(r12) ; Get the cpu that context was last on + bne- cr1,fsret ; No, it is not... -fsvSpin2: lwarx r9,r4,r12 ; Get and reserve the last used CPU - mr. r9,r9 ; Is it changing now? - oris r3,r9,hi16(fvChk) ; Set the "changing" flag - blt- fsvSpin2 ; Spin if changing - stwcx. r3,r4,r12 ; Lock it up - bne- fsvSpin2 ; Someone is messing right now + cmplw cr1,r9,r11 ; Was the context for this processor? + beq- cr1,fsgoodcpu ; Facility last used on this processor... - isync ; Make sure we see everything + b fsret ; Someone else claimed it... - cmplw cr1,r9,r11 ; Was the context for this processor? - li r3,0 ; Assume we need a fix-me-up - beq- cr1,fsgoodcpu ; Facility last used on this processor... - stw r3,PP_FPU_THREAD(r6) ; Clear owner because it was really on the other processor - b fsret ; Bail now with no save... + .align 5 -fsgoodcpu: lwz r3,ACT_MACT_FPU(r12) ; Get the current FPU savearea for the thread - lwz r9,ACT_MACT_FPUlvl(r12) ; Get our current level indicator +fsgoodcpu: lwz r3,FPUsave(r12) ; Get the current FPU savearea for the thread + lwz r9,FPUlevel(r12) ; Get our current level indicator - cmplwi cr1,r3,0 ; Have we ever saved this facility context? - beq- cr1,fsneedone ; Never saved it, so we need an area... + cmplwi cr1,r3,0 ; Have we ever saved this facility context? + beq- cr1,fsneedone ; Never saved it, so go do it... - lwz r8,SAVlvlfp(r3) ; Get the level this savearea is for - cmplwi r8,1 ; See if it is a spare - cmplw cr1,r9,r8 ; Correct level? - beq+ fsusespare ; We have a spare to use... - beq- cr1,fsret ; The current level is already saved, bail out... + lwz r8,SAVlevel(r3) ; Get the level this savearea is for + cmplw cr1,r9,r8 ; Correct level? + beq- cr1,fsret ; The current level is already saved, bail out... -fsneedone: li r3,0 ; Tell the routine to allocate an area if none found - bl fpsrchsave ; Find a free savearea - - mfsprg r6,0 ; Get back per_processor block - oris r7,r7,hi16(SAVfpuvalid) ; Set the allocated bit - lwz r12,PP_FPU_THREAD(r6) ; Get back our thread - mtlr r2 ; Restore return - lwz r8,ACT_MACT_FPU(r12) ; Get the current top floating point savearea - lwz r9,ACT_MACT_FPUlvl(r12) ; Get our current level indicator again - stw r3,ACT_MACT_FPU(r12) ; Set this as the latest FPU savearea for the thread - stw r8,SAVprefp(r3) ; And then chain this in front - stw r7,SAVflags(r3) ; Set the validity flags - stw r12,SAVact(r3) ; Make sure we point to the right guy +fsneedone: bl EXT(save_get) ; Get a savearea for the context + + mfsprg r6,0 ; Get back per_processor block + li r4,SAVfloat ; Get floating point tag + lwz r12,FPUowner(r6) ; Get back our thread + stb r4,SAVflags+2(r3) ; Mark this savearea as a float + mr. r12,r12 ; See if we were disowned while away. Very, very small chance of it... + beq- fsbackout ; If disowned, just toss savearea... + lwz r4,facAct(r12) ; Get the activation associated with live context + mtlr r2 ; Restore return + lwz r8,FPUsave(r12) ; Get the current top floating point savearea + stw r4,SAVact(r3) ; Indicate the right activation for this context + lwz r9,FPUlevel(r12) ; Get our current level indicator again + stw r3,FPUsave(r12) ; Set this as the most current floating point context + stw r8,SAVprev(r3) ; And then chain this in front -fsusespare: stw r9,SAVlvlfp(r3) ; And set the level this savearea is for + stw r9,SAVlevel(r3) ; Show level in savearea ; ; Save the current FPU state into the PCB of the thread that owns it. ; - la r11,savefp0(r3) ; Point to the 1st line - dcbz 0,r11 ; Allocate the first savearea line + la r11,savefp0(r3) ; Point to the 1st line + dcbz 0,r11 ; Allocate the first savearea line - la r11,savefp4(r3) /* Point to the 2nd line */ + la r11,savefp4(r3) ; Point to the 2nd line stfd f0,savefp0(r3) - dcbz 0,r11 /* allocate it */ + dcbz 0,r11 ; Allocate it stfd f1,savefp1(r3) stfd f2,savefp2(r3) - la r11,savefp8(r3) /* Point to the 3rd line */ + la r11,savefp8(r3) ; Point to the 3rd line stfd f3,savefp3(r3) - dcbz 0,r11 /* allocate it */ + dcbz 0,r11 ; Allocate it stfd f4,savefp4(r3) stfd f5,savefp5(r3) stfd f6,savefp6(r3) - la r11,savefp12(r3) /* Point to the 4th line */ + la r11,savefp12(r3) ; Point to the 4th line stfd f7,savefp7(r3) - dcbz 0,r11 /* allocate it */ + dcbz 0,r11 ; Allocate it stfd f8,savefp8(r3) stfd f9,savefp9(r3) stfd f10,savefp10(r3) - la r11,savefp16(r3) /* Point to the 5th line */ + la r11,savefp16(r3) ; Point to the 5th line stfd f11,savefp11(r3) - dcbz 0,r11 /* allocate it */ + dcbz 0,r11 ; Allocate it stfd f12,savefp12(r3) stfd f13,savefp13(r3) stfd f14,savefp14(r3) - la r11,savefp20(r3) /* Point to the 6th line */ + la r11,savefp20(r3) ; Point to the 6th line stfd f15,savefp15(r3) stfd f16,savefp16(r3) stfd f17,savefp17(r3) stfd f18,savefp18(r3) - la r11,savefp24(r3) /* Point to the 7th line */ + la r11,savefp24(r3) ; Point to the 7th line stfd f19,savefp19(r3) - dcbz 0,r11 /* allocate it */ + dcbz 0,r11 ; Allocate it stfd f20,savefp20(r3) - lwz r10,liveFPSCR(r6) ; Get the previously saved FPSCR stfd f21,savefp21(r3) stfd f22,savefp22(r3) - li r9,0 ; Just clear this out - la r11,savefp28(r3) /* Point to the 8th line */ + la r11,savefp28(r3) ; Point to the 8th line stfd f23,savefp23(r3) - dcbz 0,r11 /* allocate it */ + dcbz 0,r11 ; Allocate it stfd f24,savefp24(r3) stfd f25,savefp25(r3) stfd f26,savefp26(r3) stfd f27,savefp27(r3) stfd f28,savefp28(r3) -; Note that we just save the FPSCR here for ease. It is really already saved -; in the "normal" context area of the savearea. - - stw r9,savefpscrpad(r3) ; Save the FPSCR pad - stw r10,savefpscr(r3) ; Save the FPSCR - stfd f29,savefp29(r3) stfd f30,savefp30(r3) stfd f31,savefp31(r3) - lfd f0,savefp0(r3) ; We need to restore F0 because we used it - ; to get the FPSCR - -#if 0 - la r9,savefp0(r3) ; (TEST/DEBUG) - la r10,savefp31(r3) ; (TEST/DEBUG) - -chkkillmedead: - lha r8,0(r9) ; (TEST/DEBUG) - addi r9,r9,8 ; (TEST/DEBUG) - cmpwi r8,-8 ; (TEST/DEBUG) - cmplw cr1,r9,r10 ; (TEST/DEBUG) - bne+ dontkillmedead ; (TEST/DEBUG) - BREAKPOINT_TRAP ; (TEST/DEBUG) - -dontkillmedead: ; (TEST/DEBUG) - ble+ cr1,chkkillmedead ; (TEST/DEBUG) -#endif - -fsret: lwz r4,ACT_MACT_FPUcpu(r12) ; Get back the owner CPU - rlwinm r4,r4,0,fvChkb+1,31 ; Clear lock - sync - stw r4,ACT_MACT_FPUcpu(r12) ; Unlock the context - -fsretnr: mtmsr r0 ; Put interrupts on if they were and floating point off + +fsret: mtmsr r0 ; Put interrupts on if they were and floating point off isync blr +fsbackout: mr r12,r0 ; Save the original MSR + b EXT(save_ret_join) ; Toss savearea and return from there... + /* * fpu_switch() * @@ -685,356 +585,271 @@ fsretnr: mtmsr r0 ; Put interrupts on if they were and floating point off * */ -ENTRY(fpu_switch, TAG_NO_FRAME_USED) + .align 5 + .globl EXT(fpu_switch) + +LEXT(fpu_switch) + #if DEBUG -#if GDDBG - mr r7,r4 ; Save input parameter - lis r3,hi16(EXT(fpu_trap_count)) ; Get address of FP trap counter - ori r3,r3,lo16(EXT(fpu_trap_count)) ; Get address of FP trap counter - lwz r1,0(r3) - lis r5,hi16(EXT(GratefulDeb)) ; Point to top of display - ori r5,r5,lo16(EXT(GratefulDeb)) ; Put in bottom part - addi r1,r1,1 - mtlr r5 ; Set link register - stw r1,0(r3) - mr r4,r1 - li r3,0 - blrl ; Display count - mr r4,r7 ; Restore the parameter -#else lis r3,hi16(EXT(fpu_trap_count)) ; Get address of FP trap counter ori r3,r3,lo16(EXT(fpu_trap_count)) ; Get address of FP trap counter lwz r1,0(r3) addi r1,r1,1 stw r1,0(r3) -#endif #endif /* DEBUG */ - mfsprg r6,0 ; Get the per_processor block - mfmsr r19 ; Get the current MSR - - lwz r10,PP_CPU_DATA(r6) ; Get the CPU data pointer - lwz r12,PP_FPU_THREAD(r6) ; Get the thread that owns the FPU - lwz r10,CPU_ACTIVE_THREAD(r10) ; Get the pointer to the active thread - ori r19,r19,lo16(MASK(MSR_FP)) ; Enable the floating point feature - lwz r17,THREAD_TOP_ACT(r10) ; Now get the activation that is running - -; R12 has the "old" activation -; R17 has the "new" activation - -#if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x7F01 ; (TEST/DEBUG) - mr r3,r12 ; (TEST/DEBUG) - mr r5,r17 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#endif - mr. r12,r12 ; See if there is any live FP status + mfsprg r26,0 ; Get the per_processor block + mfmsr r19 ; Get the current MSR - lhz r18,PP_CPU_NUMBER(r6) ; Get the current CPU, we will need it later + mr r25,r4 ; Save the entry savearea + lwz r22,FPUowner(r26) ; Get the thread that owns the FPU + lwz r10,PP_ACTIVE_THREAD(r26) ; Get the pointer to the active thread + ori r19,r19,lo16(MASK(MSR_FP)) ; Enable the floating point feature + lwz r17,THREAD_TOP_ACT(r10) ; Now get the activation that is running - mtmsr r19 ; Enable floating point instructions + mtmsr r19 ; Enable floating point instructions isync - - beq- fsnosave ; No live context, so nothing to save... - li r20,ACT_MACT_FPUcpu ; Point to the CPU indication/lock word + lwz r27,ACT_MACT_PCB(r17) ; Get the current level + lwz r29,curctx(r17) ; Grab the current context anchor of the current thread -fsSpin1: lwarx r19,r20,r12 ; Get and reserve the last used CPU - mr. r19,r19 ; Is it changing now? - oris r21,r19,hi16(fvChk) ; Set the "changing" flag - blt- fsSpin1 ; Spin if changing - stwcx. r21,r20,r12 ; Lock it up - bne- fsSpin1 ; Someone is messing right now +; R22 has the "old" context anchor +; R29 has the "new" context anchor - isync ; Make sure we see everything - - lwz r15,ACT_MACT_PCB(r12) ; Get the current level of the "old" one - cmplw r18,r19 ; Check the CPU that the old context is live on - lwz r14,ACT_MACT_FPU(r12) ; Point to the top of the old context stack - bne- fsnosaverel ; Context is not live if used on a different CPU... - lwz r13,ACT_MACT_FPUlvl(r12) ; Get the "old" active level - -; -; First, check to see if all we are doing is enabling because the -; "new" context is live. -; #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x7F02 ; (TEST/DEBUG) - mr r1,r15 ; (TEST/DEBUG) - mr r3,r13 ; (TEST/DEBUG) - mr r5,r14 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x7F01 ; (TEST/DEBUG) + mr r3,r22 ; (TEST/DEBUG) + mr r5,r29 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif + + lhz r16,PP_CPU_NUMBER(r26) ; Get the current CPU number - cmplw cr1,r12,r17 ; Are the "old" activation and the "new" the same? - cmplwi cr2,r14,0 ; Is there any saved context on the "old" activation? - bne+ cr1,fsmstsave ; The activations are different so "old" context must be saved... +fswretry: mr. r22,r22 ; See if there is any live FP status -; -; Here we know that both the "old" and "new" activations are the same. We will -; check the current level and active levels. If they are the same, the context is -; already live, so all we do is turn on the facility and invalidate the top -; savearea. -; -; If the current level, the active level, and the top savearea level are the -; same, then the context was saved as part of a thread context switch and neither -; needs saving or restoration. -; -; In all other cases, the context must be saved unless we are just re-enabling -; floating point. -; + beq- fsnosave ; No live context, so nothing to save... - cmplw r13,r15 ; Are the levels the same? - cmplwi cr2,r14,0 ; Is there any saved context? - bne- fsmstsave ; Levels are different, we need to save... - - beq- cr2,fsenableret ; No saved context at all, enable and go... - - lwz r20,SAVlvlfp(r14) ; Get the level of the top savearea + isync ; Make sure we see this in the right order -#if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x7F03 ; (TEST/DEBUG) - mr r3,r15 ; (TEST/DEBUG) - mr r5,r20 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#endif - cmplw r15,r20 ; Is the top level the same as the current? - li r0,1 ; Get the invalid flag - bne- fsenableret ; Not the same, just enable and go... - - stw r0,SAVlvlfp(r14) ; Invalidate that top savearea -fsenableret: - sync ; Make sure everything is saved - stw r19,ACT_MACT_FPUcpu(r12) ; Say we are not using the context anymore + lwz r30,FPUsave(r22) ; Get the top savearea + cmplw cr2,r22,r29 ; Are both old and new the same context? + lwz r18,FPUcpu(r22) ; Get the last CPU we ran on + cmplwi cr1,r30,0 ; Anything saved yet? + cmplw r18,r16 ; Make sure we are on the right processor + lwz r31,FPUlevel(r22) ; Get the context level - b fsenable ; Then enable and go... - + bne- fsnosave ; No, not on the same processor... + ; -; We need to save the "old" context here. The LIFO queueing scheme works -; out for all cases because if both the "new" and "old" activations are the -; same, there can not be any saved state to load. the "new" level is -; truely new. +; Check to see if the live context has already been saved. +; Also check to see if all we are here just to re-enable the MSR +; and handle specially if so. ; -; When we save the context, we either use a new savearea, or the free -; one that is cached at the head of the list. + + cmplw r31,r27 ; See if the current and active levels are the same + crand cr0_eq,cr2_eq,cr0_eq ; Remember if both the levels and contexts are the same + li r3,0 ; Clear this -fsmstsave: beq- cr2,fsgetsave ; There is no possible cached save area + beq- fsthesame ; New and old are the same, just go enable... + + beq- cr1,fsmstsave ; Not saved yet, go do it... - lwz r5,SAVlvlfp(r14) ; Get the level of first facility savearea -#if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x7F04 ; (TEST/DEBUG) - mr r3,r15 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#endif - mr r3,r14 ; Assume we are invalid - cmplwi r5,1 ; Is it invalid? - cmplw cr1,r5,r13 ; Is the SA level the active one? - beq+ fsusecache ; Invalid, just use it... - beq- cr1,fsnosaverel ; The SA level is active, it is already saved... + lwz r11,SAVlevel(r30) ; Get the level of top saved context -fsgetsave: mr r3,r4 ; Use the interrupt save as the context savearea if none cached + cmplw r31,r11 ; Are live and saved the same? + #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x7F05 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x7F02 ; (TEST/DEBUG) + mr r3,r30 ; (TEST/DEBUG) + mr r5,r31 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif + + beq+ fsnosave ; Same level, so already saved... + - bl fpsrchsave ; Find a free savearea +fsmstsave: stw r3,FPUowner(r26) ; Kill the context now + eieio ; Make sure everyone sees it + bl EXT(save_get) ; Go get a savearea + + la r11,savefp0(r3) ; Point to the 1st line in new savearea + lwz r12,facAct(r22) ; Get the activation associated with the context + dcbz 0,r11 ; Allocate cache + stw r3,FPUsave(r22) ; Set this as the latest context savearea for the thread - stw r3,ACT_MACT_FPU(r12) ; Set this as the latest context savearea for the thread - mfsprg r6,0 ; Get back per_processor block - stw r14,SAVprefp(r3) ; And then chain this in front - oris r7,r7,hi16(SAVfpuvalid) ; Set the allocated bit - stw r12,SAVact(r3) ; Make sure we point to the right guy - stw r7,SAVflags(r3) ; Set the allocation flags + stw r30,SAVprev(r3) ; Point us to the old context + stw r31,SAVlevel(r3) ; Tag our level + li r7,SAVfloat ; Get the floating point ID + stw r12,SAVact(r3) ; Make sure we point to the right guy + stb r7,SAVflags+2(r3) ; Set that we have a floating point save area -fsusecache: la r11,savefp0(r3) ; Point to the 1st line in area - stw r13,SAVlvlfp(r3) ; Set this context level #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x7F06 ; (TEST/DEBUG) - mr r5,r13 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x7F03 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif ; ; Now we will actually save the old context ; - dcbz 0,r11 ; Allocate the output area - - la r11,savefp4(r3) ; Point to the 2nd line + la r11,savefp4(r3) ; Point to the 2nd line stfd f0,savefp0(r3) - dcbz 0,r11 ; Allocate cache + dcbz 0,r11 ; Allocate cache stfd f1,savefp1(r3) stfd f2,savefp2(r3) - la r11,savefp8(r3) ; Point to the 3rd line + la r11,savefp8(r3) ; Point to the 3rd line stfd f3,savefp3(r3) - dcbz 0,r11 ; Allocate cache + dcbz 0,r11 ; Allocate cache stfd f4,savefp4(r3) stfd f5,savefp5(r3) stfd f6,savefp6(r3) - la r11,savefp12(r3) ; Point to the 4th line + la r11,savefp12(r3) ; Point to the 4th line stfd f7,savefp7(r3) - dcbz 0,r11 ; Allocate cache + dcbz 0,r11 ; Allocate cache stfd f8,savefp8(r3) stfd f9,savefp9(r3) stfd f10,savefp10(r3) - la r11,savefp16(r3) ; Point to the 5th line + la r11,savefp16(r3) ; Point to the 5th line stfd f11,savefp11(r3) - dcbz 0,r11 ; Allocate cache + dcbz 0,r11 ; Allocate cache stfd f12,savefp12(r3) stfd f13,savefp13(r3) stfd f14,savefp14(r3) - la r11,savefp20(r3) ; Point to the 6th line + la r11,savefp20(r3) ; Point to the 6th line stfd f15,savefp15(r3) - dcbz 0,r11 ; Allocate cache + dcbz 0,r11 ; Allocate cache stfd f16,savefp16(r3) stfd f17,savefp17(r3) stfd f18,savefp18(r3) - la r11,savefp24(r3) ; Point to the 7th line + la r11,savefp24(r3) ; Point to the 7th line stfd f19,savefp19(r3) - dcbz 0,r11 ; Allocate cache + dcbz 0,r11 ; Allocate cache stfd f20,savefp20(r3) - li r14,0 ; Clear this for now - lwz r15,liveFPSCR(r6) ; Get the previously saved FPSCR - stfd f21,savefp21(r3) stfd f22,savefp22(r3) - la r11,savefp28(r3) ; Point to the 8th line + la r11,savefp28(r3) ; Point to the 8th line stfd f23,savefp23(r3) - dcbz 0,r11 ; allocate it + dcbz 0,r11 ; allocate it stfd f24,savefp24(r3) stfd f25,savefp25(r3) stfd f26,savefp26(r3) - la r11,savefpscrpad(r3) ; Point to the 9th line stfd f27,savefp27(r3) - dcbz 0,r11 ; allocate it + dcbz 0,r11 ; allocate it stfd f28,savefp28(r3) stfd f29,savefp29(r3) stfd f30,savefp30(r3) stfd f31,savefp31(r3) -; Note that we just save the FPSCR here for ease. It is really already saved -; in the "normal" context area of the savearea. - - stw r14,savefpscrpad(r3) ; Save the FPSCR pad - stw r15,savefpscr(r3) ; Save the FPSCR - ; ; The context is all saved now and the facility is free. ; -; Now check out the "new" and see if we need to load up his context. -; If we do (and this should be the normal case), do it and then invalidate the -; savearea. (This will keep it cached for quick access next time around.) -; -; If we do not (remember, we already took care of the case where we just enable -; the FPU), we need to fill the registers with junk, because this level has +; If we do not we need to fill the registers with junk, because this level has ; never used them before and some thieving bastard could hack the old values ; of some thread! Just imagine what would happen if they could! Why, nothing ; would be safe! My God! It is terrifying! ; -fsnosaverel: - sync ; Make sure everything is saved - stw r19,ACT_MACT_FPUcpu(r12) ; Say we are not using the context anymore - -fsnosave: - li r20,ACT_MACT_FPUcpu ; Point to the CPU indication/lock word - -fsSpin2: lwarx r19,r20,r17 ; Get and reserve the last used CPU - mr. r19,r19 ; Is it changing now? - oris r21,r19,hi16(fvChk) ; Set the "changing" flag - blt- fsSpin2 ; Spin if changing - stwcx. r21,r20,r17 ; Lock it up - bne- fsSpin2 ; Someone is messing right now +fsnosave: lwz r15,ACT_MACT_PCB(r17) ; Get the current level of the "new" one + lwz r19,FPUcpu(r29) ; Get the last CPU we ran on + lwz r14,FPUsave(r29) ; Point to the top of the "new" context stack - isync ; Make sure we see everything + stw r16,FPUcpu(r29) ; Claim context for us + eieio - lwz r15,ACT_MACT_PCB(r17) ; Get the current level of the "new" one - lwz r14,ACT_MACT_FPU(r17) ; Point to the top of the "new" context stack - lwz r13,ACT_MACT_FPUlvl(r17) ; Get the "new" active level #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x7F07 ; (TEST/DEBUG) - mr r1,r15 ; (TEST/DEBUG) - mr r3,r14 ; (TEST/DEBUG) - mr r5,r13 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) + lwz r13,FPUlevel(r29) ; (TEST/DEBUG) + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x7F04 ; (TEST/DEBUG) + mr r1,r15 ; (TEST/DEBUG) + mr r3,r14 ; (TEST/DEBUG) + mr r5,r13 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif - - cmplwi cr1,r14,0 ; Do we possibly have some context to load? - stw r15,ACT_MACT_FPUlvl(r17) ; Set the "new" active level - la r11,savefp0(r14) ; Point to first line to bring in - stw r17,PP_FPU_THREAD(r6) ; Store current thread address in fpu_thread to claim fpu for thread + + lis r18,hi16(EXT(per_proc_info)) ; Set base per_proc + mulli r19,r19,ppSize ; Find offset to the owner per_proc + ori r18,r18,lo16(EXT(per_proc_info)) ; Set base per_proc + li r16,FPUowner ; Displacement to float owner + add r19,r18,r19 ; Point to the owner per_proc + li r0,0 + +fsinvothr: lwarx r18,r16,r19 ; Get the owner + cmplw r18,r29 ; Does he still have this context? + bne fsinvoths ; Nope... + stwcx. r0,r16,r19 ; Try to invalidate it + bne- fsinvothr ; Try again if there was a collision... + +fsinvoths: cmplwi cr1,r14,0 ; Do we possibly have some context to load? + la r11,savefp0(r14) ; Point to first line to bring in + stw r15,FPUlevel(r29) ; Set the "new" active level + eieio + stw r29,FPUowner(r26) ; Mark us as having the live context beq+ cr1,MakeSureThatNoTerroristsCanHurtUsByGod ; No "new" context to load... - lwz r0,SAVlvlfp(r14) ; Get the level of first facility savearea - cmplw r0,r15 ; Top level correct to load? + + dcbt 0,r11 ; Touch line in + + lwz r3,SAVprev(r14) ; Get the previous context + lwz r0,SAVlevel(r14) ; Get the level of first facility savearea + cmplw r0,r15 ; Top level correct to load? bne- MakeSureThatNoTerroristsCanHurtUsByGod ; No, go initialize... + + stw r3,FPUsave(r29) ; Pop the context (we will toss the savearea later) #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x7F08 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x7F05 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif - dcbt 0,r11 ; Touch line in - li r0,1 ; Get the level invalid indication - - la r11,savefp4(r14) ; Point to next line - dcbt 0,r11 ; Touch line in + la r11,savefp4(r14) ; Point to next line + dcbt 0,r11 ; Touch line in lfd f0, savefp0(r14) lfd f1,savefp1(r14) - stw r0,SAVlvlfp(r14) ; Mark the savearea invalid because we are activating again lfd f2,savefp2(r14) - la r11,savefp8(r14) ; Point to next line + la r11,savefp8(r14) ; Point to next line lfd f3,savefp3(r14) - dcbt 0,r11 ; Touch line in + dcbt 0,r11 ; Touch line in lfd f4,savefp4(r14) lfd f5,savefp5(r14) lfd f6,savefp6(r14) - la r11,savefp12(r14) ; Point to next line + la r11,savefp12(r14) ; Point to next line lfd f7,savefp7(r14) - dcbt 0,r11 ; Touch line in + dcbt 0,r11 ; Touch line in lfd f8,savefp8(r14) lfd f9,savefp9(r14) lfd f10,savefp10(r14) - la r11,savefp16(r14) ; Point to next line + la r11,savefp16(r14) ; Point to next line lfd f11,savefp11(r14) - dcbt 0,r11 ; Touch line in + dcbt 0,r11 ; Touch line in lfd f12,savefp12(r14) lfd f13,savefp13(r14) lfd f14,savefp14(r14) - la r11,savefp20(r14) ; Point to next line + la r11,savefp20(r14) ; Point to next line lfd f15,savefp15(r14) - dcbt 0,r11 ; Touch line in + dcbt 0,r11 ; Touch line in lfd f16,savefp16(r14) lfd f17,savefp17(r14) lfd f18,savefp18(r14) - la r11,savefp24(r14) ; Point to next line + la r11,savefp24(r14) ; Point to next line lfd f19,savefp19(r14) - dcbt 0,r11 ; Touch line in + dcbt 0,r11 ; Touch line in lfd f20,savefp20(r14) lfd f21,savefp21(r14) - la r11,savefp28(r14) ; Point to next line + la r11,savefp28(r14) ; Point to next line lfd f22,savefp22(r14) lfd f23,savefp23(r14) - dcbt 0,r11 ; Touch line in + dcbt 0,r11 ; Touch line in lfd f24,savefp24(r14) lfd f25,savefp25(r14) lfd f26,savefp26(r14) @@ -1044,35 +859,31 @@ fsSpin2: lwarx r19,r20,r17 ; Get and reserve the last used CPU lfd f30,savefp30(r14) lfd f31,savefp31(r14) -fsenablexx: sync ; Make sure all is saved - stw r18,ACT_MACT_FPUcpu(r17) ; Set the active CPU and release - -fsenable: lwz r9,SAVflags(r4) /* Get the flags of the current savearea */ - lwz r8,savesrr1(r4) ; Get the msr of the interrupted guy - rlwinm r5,r4,0,0,19 /* Get the page address of the savearea */ - ori r8,r8,MASK(MSR_FP) ; Enable the floating point feature - lwz r10,ACT_MACT_SPF(r17) ; Get the special flags - lis r7,hi16(SAVattach) /* Get the attached flag */ - lwz r5,SACvrswap(r5) /* Get Virtual to Real translation */ + mr r3,r14 ; Get the old savearea (we popped it before) + bl EXT(save_ret) ; Toss it + +fsenable: lwz r8,savesrr1(r25) ; Get the msr of the interrupted guy + rlwinm r5,r25,0,0,19 ; Get the page address of the savearea + ori r8,r8,MASK(MSR_FP) ; Enable the floating point feature + lwz r10,ACT_MACT_SPF(r17) ; Get the special flags + lwz r5,SACvrswap(r5) ; Get Virtual to Real translation oris r10,r10,hi16(floatUsed|floatCng) ; Set that we used floating point - mr. r15,r15 ; See if we are doing this for user state - stw r8,savesrr1(r4) ; Set the msr of the interrupted guy - andc r9,r9,r7 /* Clear the attached bit */ - xor r3,r4,r5 /* Get the real address of the savearea */ - bne- fsnuser ; We are not user state... - stw r10,ACT_MACT_SPF(r17) ; Set the activation copy - stw r10,spcFlags(r6) ; Set per_proc copy + rlwinm. r0,r8,0,MSR_PR_BIT,MSR_PR_BIT ; See if we are doing this for user state + stw r8,savesrr1(r25) ; Set the msr of the interrupted guy + xor r3,r25,r5 ; Get the real address of the savearea + bne- fsnuser ; We are not user state... + stw r10,ACT_MACT_SPF(r17) ; Set the activation copy + stw r10,spcFlags(r26) ; Set per_proc copy fsnuser: #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x7F0A ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x7F07 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif - stw r9,SAVflags(r4) /* Set the flags of the current savearea */ - b EXT(exception_exit) /* Exit from the fray... */ + b EXT(exception_exit) ; Exit to the fray... /* * Initialize the registers to some bogus value @@ -1080,27 +891,16 @@ fsnuser: MakeSureThatNoTerroristsCanHurtUsByGod: -#if 0 - lwz r10,savesrr1(r4) ; (TEST/DEBUG) - rlwinm. r10,r10,0,MSR_PR_BIT,MSR_PR_BIT ; (TEST/DEBUG) - beq- nxxxxxx ; (TEST/DEBUG) - lwz r10,ACT_MACT_SPF(r17) ; (TEST/DEBUG) - rlwinm. r10,r10,0,1,1 ; (TEST/DEBUG) - beq+ nxxxxxx - BREAKPOINT_TRAP ; (TEST/DEBUG) -nxxxxxx: -#endif - #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x7F09 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x7F06 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif - lis r5,hi16(EXT(FloatInit)) /* Get top secret floating point init value address */ - ori r5,r5,lo16(EXT(FloatInit)) /* Slam bottom */ - lfd f0,0(r5) /* Initialize FP0 */ - fmr f1,f0 ; Do them all + lis r5,hi16(EXT(FloatInit)) ; Get top secret floating point init value address + ori r5,r5,lo16(EXT(FloatInit)) ; Slam bottom + lfd f0,0(r5) ; Initialize FP0 + fmr f1,f0 ; Do them all fmr f2,f0 fmr f3,f0 fmr f4,f0 @@ -1117,11 +917,9 @@ nxxxxxx: fmr f15,f0 fmr f16,f0 fmr f17,f0 - fsub f31,f31,f31 ; Get set to initialize the FPSCR fmr f18,f0 fmr f19,f0 fmr f20,f0 - mtfsf 0xff,f31 ; Clear all FPSCR exception eanbles fmr f21,f0 fmr f22,f0 fmr f23,f0 @@ -1133,46 +931,93 @@ nxxxxxx: fmr f29,f0 fmr f30,f0 fmr f31,f0 - b fsenablexx ; Finish setting it all up... + b fsenable ; Finish setting it all up... + ; -; Finds an unused floating point area in the activation pointed -; to by R12s saved contexts. If none are found (unlikely but possible) -; and R3 is 0, a new area is allocated. If R3 is non-zero, it contains -; a pointer to an floating point savearea that is free. +; We get here when we are switching to the same context at the same level and the context +; is still live. Essentially, all we are doing is turning on the faility. It may have +; gotten turned off due to doing a context save for the current level or a context switch +; back to the live guy. ; -fpsrchsave: - lwz r6,ACT_MACT_PCB(r12) ; Get the first "normal" savearea + + .align 5 -fpsrnorm: mr. r5,r6 ; Is there another? - beq- fpsrvect ; No, search the vector saveareas... - lwz r7,SAVflags(r5) ; Get the flags for this guy - lwz r6,SAVprev(r5) ; Get the previous savearea, just in case - andis. r8,r7,hi16(SAVfpuvalid) ; Have we found an empty FPU save in normal? - beq+ fpsrgot ; We found one... - b fpsrnorm ; Search again... +fsthesame: -fpsrvect: lwz r6,ACT_MACT_VMX(r12) ; Get the first "vector" savearea +#if FPVECDBG + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x7F0A ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) +#endif + beq- cr1,fsenable ; Not saved yet, nothing to pop, go enable and exit... -fpsrvectx: mr. r5,r6 ; Is there another? - beq- fpsrget ; No, try to allocate one... - lwz r7,SAVflags(r5) ; Get the flags for this guy - lwz r6,SAVprevec(r5) ; Get the previous savearea, just in case - andis. r8,r7,hi16(SAVfpuvalid) ; Have we found an empty FPU save in vector? - bne- fpsrvectx ; Search again... + lwz r11,SAVlevel(r30) ; Get the level of top saved context + lwz r14,SAVprev(r30) ; Get the previous savearea -fpsrgot: mr r3,r5 ; Get the savearea into the right register - blr ; Return... + cmplw r11,r31 ; Are live and saved the same? -fpsrget: mr. r5,r3 ; Do we allocate or use existing? - beq+ fpsrallo ; Allocate one... + bne+ fsenable ; Level not the same, nothing to pop, go enable and exit... - lwz r7,SAVflags(r3) ; Get the passed in area flags - blr ; Return... -; -; NOTE: save_get will return directly and set R7 to 0... + mr r3,r30 ; Get the old savearea (we popped it before) + bl EXT(save_ret) ; Toss it + b fsenable ; Go enable and exit... + + +; +; This function invalidates any live floating point context for the passed in facility_context. +; This is intended to be called just before act_machine_sv_free tosses saveareas. +; + + .align 5 + .globl EXT(toss_live_fpu) + +LEXT(toss_live_fpu) + + + mfmsr r9 ; Get the MSR + rlwinm r0,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear interuptions + rlwinm. r8,r9,0,MSR_FP_BIT,MSR_FP_BIT ; Are floats on right now? + rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Make sure vectors are turned off + rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Make sure floats are turned off + mtmsr r0 ; No interruptions + isync + beq+ tlfnotours ; Floats off, can not be live here... + + mfsprg r8,0 ; Get the per proc + +; +; Note that at this point, since floats are on, we are the owner +; of live state on this processor ; -fpsrallo: b EXT(save_get) ; Get a fresh savearea + + lwz r6,FPUowner(r8) ; Get the thread that owns the floats + li r0,0 ; Clear this just in case we need it + cmplw r6,r3 ; Are we tossing our own context? + bne- tlfnotours ; Nope... + + fsub f1,f1,f1 ; Make a 0 + mtfsf 0xFF,f1 ; Clear it + +tlfnotours: lwz r11,FPUcpu(r3) ; Get the cpu on which we last loaded context + lis r12,hi16(EXT(per_proc_info)) ; Set base per_proc + mulli r11,r11,ppSize ; Find offset to the owner per_proc + ori r12,r12,lo16(EXT(per_proc_info)) ; Set base per_proc + li r10,FPUowner ; Displacement to float owner + add r11,r12,r11 ; Point to the owner per_proc + li r0,0 ; Set a 0 to invalidate context + +tlfinvothr: lwarx r12,r10,r11 ; Get the owner + cmplw r12,r3 ; Does he still have this context? + bne+ tlfexit ; Nope, leave... + stwcx. r0,r10,r11 ; Try to invalidate it + bne- tlfinvothr ; Try again if there was a collision... + +tlfexit: mtmsr r9 ; Restore interruptions + isync ; Could be turning off floats here + blr ; Leave... + /* * Altivec stuff is here. The techniques used are pretty identical to @@ -1188,89 +1033,118 @@ fpsrallo: b EXT(save_get) ; Get a fresh savearea * don't want to load any registers we don't have a copy of, we want to set them * to zero instead. * + * Note that there are some oddities here when we save a context we are using. + * It is really not too cool to do this, but what the hey... Anyway, + * we turn vectors and fpu off before we leave. + * The oddity is that if you use vectors after this, the + * savearea containing the context just saved will go away. So, bottom line is + * that don't use vectors until after you are done with the saved context. + * */ -ENTRY(vec_save, TAG_NO_FRAME_USED) + .align 5 + .globl EXT(vec_save) + +LEXT(vec_save) - mfmsr r0 ; Get the MSR - rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Turn off vector forever + mfmsr r0 ; Get the MSR + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Make sure vectors are turned off when we leave rlwinm r2,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; But do interrupts only for now - oris r2,r2,hi16(MASK(MSR_VEC)) ; Enable the vector facility for now also - mtmsr r2 ; Set the MSR + oris r2,r2,hi16(MASK(MSR_VEC)) ; Enable the vector facility for now also + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force off fp + mtmsr r2 ; Set the MSR isync - mfsprg r6,0 ; Get the per_processor block - lwz r12,PP_VMX_THREAD(r6) ; Get the thread that owns the vector + mfsprg r6,0 ; Get the per_processor block + lwz r12,VMXowner(r6) ; Get the context ID for owner + #if FPVECDBG - mr r7,r0 ; (TEST/DEBUG) - li r4,0 ; (TEST/DEBUG) - mr r10,r3 ; (TEST/DEBUG) - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - mr. r3,r12 ; (TEST/DEBUG) - li r2,0x5F00 ; (TEST/DEBUG) - li r5,0 ; (TEST/DEBUG) - beq- noowneryeu ; (TEST/DEBUG) - lwz r4,ACT_MACT_VMXlvl(r12) ; (TEST/DEBUG) - lwz r5,ACT_MACT_VMX(r12) ; (TEST/DEBUG) - -noowneryeu: oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) - mr r0,r7 ; (TEST/DEBUG) - mr r3,r10 ; (TEST/DEBUG) + mr r7,r0 ; (TEST/DEBUG) + li r4,0 ; (TEST/DEBUG) + mr r10,r3 ; (TEST/DEBUG) + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + mr. r3,r12 ; (TEST/DEBUG) + li r2,0x5F00 ; (TEST/DEBUG) + li r5,0 ; (TEST/DEBUG) + beq- noowneryeu ; (TEST/DEBUG) + lwz r4,VMXlevel(r12) ; (TEST/DEBUG) + lwz r5,VMXsave(r12) ; (TEST/DEBUG) + +noowneryeu: oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) + mr r0,r7 ; (TEST/DEBUG) + mr r3,r10 ; (TEST/DEBUG) #endif - mflr r2 ; Save the return address - lhz r11,PP_CPU_NUMBER(r6) ; Get our CPU number + mflr r2 ; Save the return address + +vsretry: mr. r12,r12 ; Anyone own the vector? + lhz r11,PP_CPU_NUMBER(r6) ; Get our CPU number + beq- vsret ; Nobody owns the vector, no save required... + + cmplw cr1,r3,r12 ; Is the specified context live? + + isync ; Force owner check first + + lwz r9,VMXcpu(r12) ; Get the cpu that context was last on + bne- cr1,vsret ; Specified context is not live + + cmplw cr1,r9,r11 ; Was the context for this processor? + beq+ cr1,vsgoodcpu ; Facility last used on this processor... + + b vsret ; Someone else claimed this... + + .align 5 + +vsgoodcpu: lwz r3,VMXsave(r12) ; Get the current vector savearea for the thread + lwz r10,liveVRS(r6) ; Get the right VRSave register + lwz r9,VMXlevel(r12) ; Get our current level indicator + + + cmplwi cr1,r3,0 ; Have we ever saved this facility context? + beq- cr1,vsneedone ; Never saved it, so we need an area... + + lwz r8,SAVlevel(r3) ; Get the level this savearea is for + mr. r10,r10 ; Is VRsave set to 0? + cmplw cr1,r9,r8 ; Correct level? + bne- cr1,vsneedone ; Different level, so we need to save... - mr. r12,r12 ; Anyone own the vector? - cmplw cr1,r3,r12 ; Is the specified thread the owner? + bne+ vsret ; VRsave is non-zero so we need to keep what is saved... - beq- vsretnr ; Nobody owns the vector, no save required... - - li r4,ACT_MACT_VMXcpu ; Point to the CPU indication/lock word - bne- cr1,vsretnr ; Facility belongs to some other activation... - -vsvSpin2: lwarx r9,r4,r12 ; Get and reserve the last used CPU - mr. r9,r9 ; Is it changing now? - oris r3,r9,hi16(fvChk) ; Set the "changing" flag - blt- vsvSpin2 ; Spin if changing - stwcx. r3,r4,r12 ; Lock it up - bne- vsvSpin2 ; Someone is messing right now - - isync ; Make sure we see everything - - cmplw cr1,r9,r11 ; Was the context for this processor? - li r3,0 ; Assume we need a fix-me-up - beq- cr1,vsgoodcpu ; Facility last used on this processor... - stw r3,PP_VMX_THREAD(r6) ; Clear owner because it was really on the other processor - b vsret ; Bail now with no save... - -vsgoodcpu: lwz r3,ACT_MACT_VMX(r12) ; Get the current vector savearea for the thread - lwz r9,ACT_MACT_VMXlvl(r12) ; Get our current level indicator - - cmplwi cr1,r3,0 ; Have we ever saved this facility context? - beq- cr1,vsneedone ; Never saved it, so we need an area... - - lwz r8,SAVlvlvec(r3) ; Get the level this savearea is for - cmplwi r8,1 ; See if this is a spare - cmplw cr1,r9,r8 ; Correct level? - beq+ vsusespare ; It is still live... - beq- cr1,vsret ; The current level is already saved, bail out... - -vsneedone: li r3,0 ; Tell the routine to allocate an area if none found - bl vsrchsave ; Find a free savearea - - mfsprg r6,0 ; Get back per_processor block - oris r7,r7,hi16(SAVvmxvalid) ; Set the allocated bit - lwz r12,PP_VMX_THREAD(r6) ; Get back our thread - mtlr r2 ; Restore return - lwz r8,ACT_MACT_VMX(r12) ; Get the current top vector savearea - lwz r9,ACT_MACT_VMXlvl(r12) ; Get our current level indicator again - stw r3,ACT_MACT_VMX(r12) ; Set this as the latest vector savearea for the thread - stw r8,SAVprevec(r3) ; And then chain this in front - stw r7,SAVflags(r3) ; Set the allocation flags - stw r12,SAVact(r3) ; Make sure we point to the right guy - -vsusespare: stw r9,SAVlvlvec(r3) ; And set the level this savearea is for + lwz r4,SAVprev(r3) ; Pick up the previous area + lwz r5,SAVlevel(r4) ; Get the level associated with save + stw r4,VMXsave(r12) ; Dequeue this savearea + stw r5,VMXlevel(r12) ; Save the level + + li r3,0 ; Clear + stw r3,VMXowner(r12) ; Show no live context here + eieio + +vsbackout: mr r12,r0 ; Set the saved MSR + b EXT(save_ret_join) ; Toss the savearea and return from there... + + .align 5 + +vsneedone: mr. r10,r10 ; Is VRsave set to 0? + beq- vsret ; Yeah, they do not care about any of them... + + bl EXT(save_get) ; Get a savearea for the context + + mfsprg r6,0 ; Get back per_processor block + li r4,SAVvector ; Get vector tag + lwz r12,VMXowner(r6) ; Get back our context ID + stb r4,SAVflags+2(r3) ; Mark this savearea as a vector + mr. r12,r12 ; See if we were disowned while away. Very, very small chance of it... + beq- vsbackout ; If disowned, just toss savearea... + lwz r4,facAct(r12) ; Get the activation associated with live context + mtlr r2 ; Restore return + lwz r8,VMXsave(r12) ; Get the current top vector savearea + stw r4,SAVact(r3) ; Indicate the right activation for this context + lwz r9,VMXlevel(r12) ; Get our current level indicator again + stw r3,VMXsave(r12) ; Set this as the most current floating point context + stw r8,SAVprev(r3) ; And then chain this in front + + stw r9,SAVlevel(r3) ; Set level in savearea + mfcr r2 ; Save non-volatile CRs lwz r10,liveVRS(r6) ; Get the right VRSave register lis r9,0x5555 ; Mask with odd bits set @@ -1282,11 +1156,9 @@ vsusespare: stw r9,SAVlvlvec(r3) ; And set the level this savearea is for la r6,savevr0(r3) ; Point to line 0 rlwinm r4,r11,15,0,15 ; Move line 8-15 flags to high order odd bits - la r9,savevrvalid(r3) ; Point to the saved register mask field or r4,r11,r4 ; Set the odd bits ; (bit 0 is line 0, bit 1 is line 8, ; bit 2 is line 1, bit 3 is line 9, etc. - dcba br0,r9 ; Allocate the cache for it rlwimi r4,r10,16,16,31 ; Put vrsave 0 - 15 into positions 16 - 31 la r7,savevr2(r3) ; Point to line 1 mtcrf 255,r4 ; Load up the CRs @@ -1533,37 +1405,17 @@ snovr28: stvxl v29,r11,r8 ; Save VR29 snovr29: - mfvscr v27 ; Get the VSCR - la r8,savevscr(r3) ; Point to the VSCR save area bf 30,snovr30 ; Do not save VR30... stvxl v30,br0,r7 ; Save VR30 snovr30: - dcba br0,r8 ; Allocate VSCR savearea bf 31,snovr31 ; Do not save VR31... stvxl v31,r11,r7 ; Save VR31 snovr31: - add r11,r11,r9 ; Point to V27s saved value - stvxl v27,br0,r8 ; Save the VSCR - bt 27,v27ok ; V27 has been saved and is marked as wanted - - lis r11,hi16(EXT(QNaNbarbarian)) ; V27 is not wanted, so get empty value - ori r11,r11,lo16(EXT(QNaNbarbarian)) - -v27ok: mtcrf 255,r2 ; Restore all non-volatile CRs - lvxl v27,br0,r11 ; Restore or load empty value into V27 because we used it + mtcrf 255,r2 ; Restore all cr -; -; Save the current vector state into the savearea of the thread that owns it. -; - -vsret: lwz r4,ACT_MACT_VMXcpu(r12) ; Get back the owner CPU - rlwinm r4,r4,0,fvChkb+1,31 ; Clear lock - sync - stw r4,ACT_MACT_VMXcpu(r12) ; Unlock the context - -vsretnr: mtmsr r0 ; Put interrupts on if they were and vector off +vsret: mtmsr r0 ; Put interrupts on if they were and vector off isync blr @@ -1586,1162 +1438,1082 @@ vsretnr: mtmsr r0 ; Put interrupts on if they were and vector off * */ -ENTRY(vec_switch, TAG_NO_FRAME_USED) + .align 5 + .globl EXT(vec_switch) + +LEXT(vec_switch) #if DEBUG -#if GDDBG - mr r7,r4 ; Save input parameter - lis r3,hi16(EXT(vec_trap_count)) ; Get address of vector trap counter - ori r3,r3,lo16(EXT(vec_trap_count)) ; Get address of vector trap counter - lwz r1,0(r3) - lis r5,hi16(EXT(GratefulDeb)) ; Point to top of display - ori r5,r5,lo16(EXT(GratefulDeb)) ; Put in bottom part - addi r1,r1,1 - mtlr r5 ; Set link register - stw r1,0(r3) - mr r4,r1 - lis r3,1 - blrl ; Display count - mr r4,r7 ; Restore the parameter -#else lis r3,hi16(EXT(vec_trap_count)) ; Get address of vector trap counter ori r3,r3,lo16(EXT(vec_trap_count)) ; Get address of vector trap counter lwz r1,0(r3) addi r1,r1,1 stw r1,0(r3) -#endif #endif /* DEBUG */ - mfsprg r6,0 /* Get the per_processor block */ - mfmsr r19 /* Get the current MSR */ + mfsprg r26,0 ; Get the per_processor block + mfmsr r19 ; Get the current MSR - lwz r10,PP_CPU_DATA(r6) /* Get the CPU data pointer */ - lwz r12,PP_VMX_THREAD(r6) /* Get the thread that owns the vector */ - lwz r10,CPU_ACTIVE_THREAD(r10) /* Get the pointer to the active thread */ - oris r19,r19,hi16(MASK(MSR_VEC)) /* Enable the vector feature */ - lwz r17,THREAD_TOP_ACT(r10) /* Now get the activation that is running */ - -; R12 has the "old" activation -; R17 has the "new" activation - -#if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x5F01 ; (TEST/DEBUG) - mr r3,r12 ; (TEST/DEBUG) - mr r5,r17 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#if GDDBG - lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display - mr r18,r4 ; Save this - ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part - mr r4,r2 ; Set value - mtlr r3 ; Set link register - li r3,1 ; Display address - blrl ; Display it - mr r4,r18 ; Restore it - mfsprg r6,0 ; Get the per_processor block back -#endif -#endif - mr. r12,r12 ; See if there is any live vector status - - lhz r18,PP_CPU_NUMBER(r6) ; Get our CPU number - - mtmsr r19 /* Set vector available */ + mr r25,r4 ; Save the entry savearea + lwz r22,VMXowner(r26) ; Get the thread that owns the vector + lwz r10,PP_ACTIVE_THREAD(r26) ; Get the pointer to the active thread + oris r19,r19,hi16(MASK(MSR_VEC)) ; Enable the vector feature + lwz r17,THREAD_TOP_ACT(r10) ; Now get the activation that is running + + mtmsr r19 ; Enable vector instructions isync - beq- vsnosave ; No live context, so nothing to save... - - li r20,ACT_MACT_VMXcpu ; Point to the CPU indication/lock word - -vsSpin1: lwarx r19,r20,r12 ; Get and reserve the last used CPU - mr. r19,r19 ; Is it changing now? - oris r21,r19,hi16(fvChk) ; Set the "changing" flag - blt- vsSpin1 ; Spin if changing - stwcx. r21,r20,r12 ; Lock it up - bne- vsSpin1 ; Someone is messing right now + lwz r27,ACT_MACT_PCB(r17) ; Get the current level + lwz r29,curctx(r17) ; Grab the current context anchor of the current thread - isync ; Make sure we see everything +; R22 has the "old" context anchor +; R29 has the "new" context anchor - lwz r15,ACT_MACT_PCB(r12) ; Get the current level of the "old" one - cmplw r18,r19 ; Check the CPU that the old context is live on - lwz r14,ACT_MACT_VMX(r12) ; Point to the top of the old context stack - bne- vsnosaverel ; Context is not live if used on a different CPU... - lwz r13,ACT_MACT_VMXlvl(r12) ; Get the "old" active level - -; -; First, check to see if all we are doing is enabling because the -; "new" context is live. -; #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x5F02 ; (TEST/DEBUG) - mr r1,r15 ; (TEST/DEBUG) - mr r3,r13 ; (TEST/DEBUG) - mr r5,r14 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#if GDDBG - lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display - mr r8,r4 ; Save this - ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part - mr r4,r2 ; Set value - mtlr r3 ; Set link register - li r3,1 ; Display address - blrl ; Display it - mr r4,r8 ; Restore it -#endif + lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) + li r2,0x5F01 ; (TEST/DEBUG) + mr r3,r22 ; (TEST/DEBUG) + mr r5,r29 ; (TEST/DEBUG) + oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif - cmplw cr1,r12,r17 ; Is the "old" activation and the "new" the same? - cmplwi cr2,r14,0 ; Is there any saved context on the "old" activation? - bne+ cr1,vsmstsave ; The activations are different so "old" context must be saved... - -; -; Here we know that both the "old" and "new" activations are the same. We will -; check the current level and active levels. If they are the same, the context is -; already live, so all we do is turn on the facility and invalidate the top -; savearea. -; -; If the current level, the active level, and the top savearea level are the -; same, then the context was saved as part of a thread context switch and neither -; needs saving or restoration. -; -; In all other cases, the context must be saved unless we are just re-enabling -; vector. -; - - cmplw r13,r15 ; Are the levels the same? - cmplwi cr2,r14,0 ; Is there any saved context? - bne- vsmstsave ; Levels are different, we need to save... + lhz r16,PP_CPU_NUMBER(r26) ; Get the current CPU number - beq- cr2,vrenableret ; No saved context at all, enable and go... +vsvretry: mr. r22,r22 ; See if there is any live vector status - lwz r20,SAVlvlvec(r14) ; Get the level of the top savearea + beq- vsnosave ; No live context, so nothing to save... -#if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x5F03 ; (TEST/DEBUG) - mr r3,r15 ; (TEST/DEBUG) - mr r5,r20 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#if GDDBG - lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display - mr r8,r4 ; Save this - ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part - mr r4,r2 ; Set value - mtlr r3 ; Set link register - li r3,1 ; Display address - blrl ; Display it - mr r4,r8 ; Restore it -#endif -#endif - cmplw r15,r20 ; Is the top level the same as the current? - li r0,1 ; Get the invalid flag - bne- vrenableret ; Not the same, just enable and go... - - stw r0,SAVlvlvec(r14) ; Invalidate that top savearea + isync ; Make sure we see this in the right order -vrenableret: - sync ; Make sure everything is saved - stw r19,ACT_MACT_VMXcpu(r12) ; Say we are not using the context anymore - b vrenable ; Then enable and go... + lwz r30,VMXsave(r22) ; Get the top savearea + cmplw cr2,r22,r29 ; Are both old and new the same context? + lwz r18,VMXcpu(r22) ; Get the last CPU we ran on + cmplwi cr1,r30,0 ; Anything saved yet? + cmplw r18,r16 ; Make sure we are on the right processor + lwz r31,VMXlevel(r22) ; Get the context level + lwz r10,liveVRS(r26) ; Get the right VRSave register + + bne- vsnosave ; No, not on the same processor... + ; -; We need to save the "old" context here. The LIFO queueing scheme works -; out for all cases because if both the "new" and "old" activations are the -; same, there can not be any saved state to load. the "new" level is -; truely new. +; Check to see if the live context has already been saved. +; Also check to see if all we are here just to re-enable the MSR +; and handle specially if so. ; -; When we save the context, we either use a new savearea, or the free -; one that is cached at the head of the list. + + cmplw r31,r27 ; See if the current and active levels are the same + crand cr0_eq,cr2_eq,cr0_eq ; Remember if both the levels and contexts are the same + li r8,0 ; Clear this -vsmstsave: beq- cr2,vsgetsave ; There is no possible cached save area + beq- vsthesame ; New and old are the same, just go enable... + + cmplwi cr2,r10,0 ; Check VRSave to see if we really need to save anything... + beq- cr1,vsmstsave ; Not saved yet, go do it... - lwz r5,SAVlvlvec(r14) ; Get the level of first facility savearea -#if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x5F04 ; (TEST/DEBUG) - mr r3,r15 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#if GDDBG - lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display - mr r8,r4 ; Save this - mr r7,r5 ; Save this - ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part - mr r4,r2 ; Set value - mtlr r3 ; Set link register - li r3,1 ; Display address - blrl ; Display it - mr r4,r8 ; Restore it - mr r5,r7 ; Restore it -#endif -#endif - mr r3,r14 ; Assume we are invalid - cmplwi r5,1 ; Is it invalid? - cmplw cr1,r5,r13 ; Is the SA level the active one? - beq+ vsusecache ; Invalid, just use it... - beq- cr1,vsnosaverel ; The SA level is active, it is already saved... + lwz r11,SAVlevel(r30) ; Get the level of top saved context -vsgetsave: mr r3,r4 ; Use the interrupt save as the context savearea if none cached + cmplw r31,r11 ; Are live and saved the same? + #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x5F05 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#if GDDBG - lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display - mr r8,r4 ; Save this - ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part - mr r4,r2 ; Set value - mtlr r3 ; Set link register - li r3,1 ; Display address - blrl ; Display it - mr r4,r8 ; Restore it - mr r3,r8 ; This too -#endif + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x5F02 ; (TEST/DEBUG) + mr r3,r30 ; (TEST/DEBUG) + mr r5,r31 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif + + bne- vsmstsave ; Live context has not been saved yet... + + bne- cr2,vsnosave ; Live context saved and VRSave not 0, no save and keep context... - bl vsrchsave ; Find a free savearea + lwz r4,SAVprev(r30) ; Pick up the previous area + li r5,0 ; Assume this is the only one (which should be the ususal case) + mr. r4,r4 ; Was this the only one? + stw r4,VMXsave(r22) ; Dequeue this savearea + beq+ vsonlyone ; This was the only one... + lwz r5,SAVlevel(r4) ; Get the level associated with previous save + +vsonlyone: stw r5,VMXlevel(r22) ; Save the level + stw r8,VMXowner(r26) ; Clear owner + eieio + mr r3,r30 ; Copy the savearea we are tossing + bl EXT(save_ret) ; Toss the savearea + b vsnosave ; Go load up the context... + + .align 5 - stw r3,ACT_MACT_VMX(r12) ; Set this as the latest context savearea for the thread - mfsprg r6,0 ; Get back per_processor block - stw r14,SAVprevec(r3) ; And then chain this in front - oris r7,r7,hi16(SAVvmxvalid) ; Set the allocated bit - stw r12,SAVact(r3) ; Make sure we point to the right guy - stw r7,SAVflags(r3) ; Set the allocation flags + +vsmstsave: stw r8,VMXowner(r26) ; Clear owner + eieio + beq- cr2,vsnosave ; The VRSave was 0, so there is nothing to save... + + bl EXT(save_get) ; Go get a savearea + + lwz r12,facAct(r22) ; Get the activation associated with the context + stw r3,VMXsave(r22) ; Set this as the latest context savearea for the thread + + stw r30,SAVprev(r3) ; Point us to the old context + stw r31,SAVlevel(r3) ; Tag our level + li r7,SAVvector ; Get the vector ID + stw r12,SAVact(r3) ; Make sure we point to the right guy + stb r7,SAVflags+2(r3) ; Set that we have a vector save area -vsusecache: la r11,savevr0(r3) ; Point to the 1st line in area - stw r13,SAVlvlvec(r3) ; Set this context level #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x5F06 ; (TEST/DEBUG) - mr r5,r13 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#if GDDBG - mr r10,r3 - lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display - mr r8,r4 ; Save this - ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part - mr r4,r2 ; Set value - mtlr r3 ; Set link register - li r3,1 ; Display address - blrl ; Display it - mr r4,r8 ; Restore it - mr r3,r10 - mfsprg r6,0 ; Get back per_processor block -#endif + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x5F03 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif -vsgotsave: - lwz r10,liveVRS(r6) ; Get the right VRSave register - lis r9,0x5555 ; Mask with odd bits set - rlwinm r11,r10,1,0,31 ; Shift over 1 - ori r9,r9,0x5555 ; Finish mask - or r21,r10,r11 ; After this, even bits show which lines to zap - - stw r13,SAVlvlvec(r3) ; Set the savearea level - andc r13,r21,r9 ; Clear out odd bits - - la r20,savevr0(r3) ; Point to line 0 - rlwinm r24,r13,15,0,15 ; Move line 8-15 flags to high order odd bits - la r23,savevrvalid(r3) ; Point to the saved register mask field - or r24,r13,r24 ; Set the odd bits - ; (bit 0 is line 0, bit 1 is line 8, - ; bit 2 is line 1, bit 3 is line 9, etc. - dcba br0,r23 ; Allocate the cache for it - rlwimi r24,r10,16,16,31 ; Put vrsave 0 - 15 into positions 16 - 31 - la r21,savevr2(r3) ; Point to line 1 - mtcrf 255,r24 ; Load up the CRs - stw r10,savevrvalid(r3) ; Save the validity information - mr r22,r20 ; Start registers off + lwz r10,liveVRS(r26) ; Get the right VRSave register + lis r9,0x5555 ; Mask with odd bits set + rlwinm r11,r10,1,0,31 ; Shift over 1 + ori r9,r9,0x5555 ; Finish mask + or r21,r10,r11 ; After this, even bits show which lines to zap + + andc r13,r21,r9 ; Clear out odd bits + + la r11,savevr0(r3) ; Point to line 0 + rlwinm r24,r13,15,0,15 ; Move line 8-15 flags to high order odd bits + or r24,r13,r24 ; Set the odd bits + ; (bit 0 is line 0, bit 1 is line 8, + ; bit 2 is line 1, bit 3 is line 9, etc. + rlwimi r24,r10,16,16,31 ; Put vrsave 0 - 15 into positions 16 - 31 + la r21,savevr2(r3) ; Point to line 1 + mtcrf 255,r24 ; Load up the CRs + stw r10,savevrvalid(r3) ; Save the validity information + mr r12,r11 ; Start registers off ; ; Save the current vector state ; - bf 0,nol0 ; No line 0 to do... - dcba br0,r20 ; Allocate cache line 0 + bf 0,nol0 ; No line 0 to do... + dcba br0,r11 ; Allocate cache line 0 nol0: - la r20,savevr4(r3) ; Point to line 2 - bf 2,nol1 ; No line 1 to do... - dcba br0,r21 ; Allocate cache line 1 + la r11,savevr4(r3) ; Point to line 2 + bf 2,nol1 ; No line 1 to do... + dcba br0,r21 ; Allocate cache line 1 nol1: - la r21,savevr6(r3) ; Point to line 3 - bf 4,nol2 ; No line 2 to do... - dcba br0,r20 ; Allocate cache line 2 + la r21,savevr6(r3) ; Point to line 3 + bf 4,nol2 ; No line 2 to do... + dcba br0,r11 ; Allocate cache line 2 nol2: - li r30,16 ; Get offset for odd registers - bf 16,novr0 ; Do not save VR0... - stvxl v0,br0,r22 ; Save VR0 + li r14,16 ; Get offset for odd registers + bf 16,novr0 ; Do not save VR0... + stvxl v0,br0,r12 ; Save VR0 novr0: - la r23,savevr2(r3) ; Point to V2/V3 pair - bf 17,novr1 ; Do not save VR1... - stvxl v1,r30,r22 ; Save VR1 + la r13,savevr2(r3) ; Point to V2/V3 pair + bf 17,novr1 ; Do not save VR1... + stvxl v1,r14,r12 ; Save VR1 novr1: - la r20,savevr8(r3) ; Point to line 4 - bf 6,nol3 ; No line 3 to do... - dcba br0,r21 ; Allocate cache line 3 + la r11,savevr8(r3) ; Point to line 4 + bf 6,nol3 ; No line 3 to do... + dcba br0,r21 ; Allocate cache line 3 nol3: - la r22,savevr4(r3) ; Point to V4/V5 pair - bf 18,novr2 ; Do not save VR2... - stvxl v2,br0,r23 ; Save VR2 + la r12,savevr4(r3) ; Point to V4/V5 pair + bf 18,novr2 ; Do not save VR2... + stvxl v2,br0,r13 ; Save VR2 novr2: - bf 19,novr3 ; Do not save VR3... - stvxl v3,r30,r23 ; Save VR3 + bf 19,novr3 ; Do not save VR3... + stvxl v3,r14,r13 ; Save VR3 novr3: ; ; Note: CR4 is now free ; - la r21,savevr10(r3) ; Point to line 5 - bf 8,nol4 ; No line 4 to do... - dcba br0,r20 ; Allocate cache line 4 + la r21,savevr10(r3) ; Point to line 5 + bf 8,nol4 ; No line 4 to do... + dcba br0,r11 ; Allocate cache line 4 nol4: - la r23,savevr6(r3) ; Point to R6/R7 pair - bf 20,novr4 ; Do not save VR4... - stvxl v4,br0,r22 ; Save VR4 + la r13,savevr6(r3) ; Point to R6/R7 pair + bf 20,novr4 ; Do not save VR4... + stvxl v4,br0,r12 ; Save VR4 novr4: - bf 21,novr5 ; Do not save VR5... - stvxl v5,r30,r22 ; Save VR5 + bf 21,novr5 ; Do not save VR5... + stvxl v5,r14,r12 ; Save VR5 novr5: - mtcrf 0x08,r10 ; Set CRs for registers 16-19 - la r20,savevr12(r3) ; Point to line 6 - bf 10,nol5 ; No line 5 to do... - dcba br0,r21 ; Allocate cache line 5 + mtcrf 0x08,r10 ; Set CRs for registers 16-19 + la r11,savevr12(r3) ; Point to line 6 + bf 10,nol5 ; No line 5 to do... + dcba br0,r21 ; Allocate cache line 5 nol5: - la r22,savevr8(r3) ; Point to V8/V9 pair - bf 22,novr6 ; Do not save VR6... - stvxl v6,br0,r23 ; Save VR6 + la r12,savevr8(r3) ; Point to V8/V9 pair + bf 22,novr6 ; Do not save VR6... + stvxl v6,br0,r13 ; Save VR6 novr6: - bf 23,novr7 ; Do not save VR7... - stvxl v7,r30,r23 ; Save VR7 + bf 23,novr7 ; Do not save VR7... + stvxl v7,r14,r13 ; Save VR7 novr7: ; ; Note: CR5 is now free ; - la r21,savevr14(r3) ; Point to line 7 - bf 12,nol6 ; No line 6 to do... - dcba br0,r20 ; Allocate cache line 6 + la r21,savevr14(r3) ; Point to line 7 + bf 12,nol6 ; No line 6 to do... + dcba br0,r11 ; Allocate cache line 6 nol6: - la r23,savevr10(r3) ; Point to V10/V11 pair - bf 24,novr8 ; Do not save VR8... - stvxl v8,br0,r22 ; Save VR8 + la r13,savevr10(r3) ; Point to V10/V11 pair + bf 24,novr8 ; Do not save VR8... + stvxl v8,br0,r12 ; Save VR8 novr8: - bf 25,novr9 ; Do not save VR9... - stvxl v9,r30,r22 ; Save VR9 + bf 25,novr9 ; Do not save VR9... + stvxl v9,r14,r12 ; Save VR9 novr9: - mtcrf 0x04,r10 ; Set CRs for registers 20-23 - la r20,savevr16(r3) ; Point to line 8 - bf 14,nol7 ; No line 7 to do... - dcba br0,r21 ; Allocate cache line 7 + mtcrf 0x04,r10 ; Set CRs for registers 20-23 + la r11,savevr16(r3) ; Point to line 8 + bf 14,nol7 ; No line 7 to do... + dcba br0,r21 ; Allocate cache line 7 nol7: - la r22,savevr12(r3) ; Point to V12/V13 pair - bf 26,novr10 ; Do not save VR10... - stvxl v10,br0,r23 ; Save VR10 + la r12,savevr12(r3) ; Point to V12/V13 pair + bf 26,novr10 ; Do not save VR10... + stvxl v10,br0,r13 ; Save VR10 novr10: - bf 27,novr11 ; Do not save VR11... - stvxl v11,r30,r23 ; Save VR11 + bf 27,novr11 ; Do not save VR11... + stvxl v11,r14,r13 ; Save VR11 novr11: ; ; Note: CR6 is now free ; - la r21,savevr18(r3) ; Point to line 9 - bf 1,nol8 ; No line 8 to do... - dcba br0,r20 ; Allocate cache line 8 + la r21,savevr18(r3) ; Point to line 9 + bf 1,nol8 ; No line 8 to do... + dcba br0,r11 ; Allocate cache line 8 nol8: - la r23,savevr14(r3) ; Point to V14/V15 pair - bf 28,novr12 ; Do not save VR12... - stvxl v12,br0,r22 ; Save VR12 + la r13,savevr14(r3) ; Point to V14/V15 pair + bf 28,novr12 ; Do not save VR12... + stvxl v12,br0,r12 ; Save VR12 novr12: - bf 29,novr13 ; Do not save VR13... - stvxl v13,r30,r22 ; Save VR13 + bf 29,novr13 ; Do not save VR13... + stvxl v13,r14,r12 ; Save VR13 novr13: - mtcrf 0x02,r10 ; Set CRs for registers 24-27 - la r20,savevr20(r3) ; Point to line 10 - bf 3,nol9 ; No line 9 to do... - dcba br0,r21 ; Allocate cache line 9 + mtcrf 0x02,r10 ; Set CRs for registers 24-27 + la r11,savevr20(r3) ; Point to line 10 + bf 3,nol9 ; No line 9 to do... + dcba br0,r21 ; Allocate cache line 9 nol9: - la r22,savevr16(r3) ; Point to V16/V17 pair - bf 30,novr14 ; Do not save VR14... - stvxl v14,br0,r23 ; Save VR14 + la r12,savevr16(r3) ; Point to V16/V17 pair + bf 30,novr14 ; Do not save VR14... + stvxl v14,br0,r13 ; Save VR14 novr14: - bf 31,novr15 ; Do not save VR15... - stvxl v15,r30,r23 ; Save VR15 + bf 31,novr15 ; Do not save VR15... + stvxl v15,r14,r13 ; Save VR15 novr15: ; ; Note: CR7 is now free ; - la r21,savevr22(r3) ; Point to line 11 - bf 5,nol10 ; No line 10 to do... - dcba br0,r20 ; Allocate cache line 10 + la r21,savevr22(r3) ; Point to line 11 + bf 5,nol10 ; No line 10 to do... + dcba br0,r11 ; Allocate cache line 10 nol10: - la r23,savevr18(r3) ; Point to V18/V19 pair - bf 16,novr16 ; Do not save VR16... - stvxl v16,br0,r22 ; Save VR16 + la r13,savevr18(r3) ; Point to V18/V19 pair + bf 16,novr16 ; Do not save VR16... + stvxl v16,br0,r12 ; Save VR16 novr16: - bf 17,novr17 ; Do not save VR17... - stvxl v17,r30,r22 ; Save VR17 + bf 17,novr17 ; Do not save VR17... + stvxl v17,r14,r12 ; Save VR17 novr17: - mtcrf 0x01,r10 ; Set CRs for registers 28-31 + mtcrf 0x01,r10 ; Set CRs for registers 28-31 ; ; Note: All registers have been or are accounted for in CRs ; - la r20,savevr24(r3) ; Point to line 12 - bf 7,nol11 ; No line 11 to do... - dcba br0,r21 ; Allocate cache line 11 + la r11,savevr24(r3) ; Point to line 12 + bf 7,nol11 ; No line 11 to do... + dcba br0,r21 ; Allocate cache line 11 nol11: - la r22,savevr20(r3) ; Point to V20/V21 pair - bf 18,novr18 ; Do not save VR18... - stvxl v18,br0,r23 ; Save VR18 + la r12,savevr20(r3) ; Point to V20/V21 pair + bf 18,novr18 ; Do not save VR18... + stvxl v18,br0,r13 ; Save VR18 novr18: - bf 19,novr19 ; Do not save VR19... - stvxl v19,r30,r23 ; Save VR19 + bf 19,novr19 ; Do not save VR19... + stvxl v19,r14,r13 ; Save VR19 novr19: - la r21,savevr26(r3) ; Point to line 13 - bf 9,nol12 ; No line 12 to do... - dcba br0,r20 ; Allocate cache line 12 + la r21,savevr26(r3) ; Point to line 13 + bf 9,nol12 ; No line 12 to do... + dcba br0,r11 ; Allocate cache line 12 nol12: - la r23,savevr22(r3) ; Point to V22/V23 pair - bf 20,novr20 ; Do not save VR20... - stvxl v20,br0,r22 ; Save VR20 + la r13,savevr22(r3) ; Point to V22/V23 pair + bf 20,novr20 ; Do not save VR20... + stvxl v20,br0,r12 ; Save VR20 novr20: - bf 21,novr21 ; Do not save VR21... - stvxl v21,r30,r22 ; Save VR21 + bf 21,novr21 ; Do not save VR21... + stvxl v21,r14,r12 ; Save VR21 novr21: - la r20,savevr28(r3) ; Point to line 14 - bf 11,nol13 ; No line 13 to do... - dcba br0,r21 ; Allocate cache line 13 + la r11,savevr28(r3) ; Point to line 14 + bf 11,nol13 ; No line 13 to do... + dcba br0,r21 ; Allocate cache line 13 nol13: - la r22,savevr24(r3) ; Point to V24/V25 pair - bf 22,novr22 ; Do not save VR22... - stvxl v22,br0,r23 ; Save VR22 + la r12,savevr24(r3) ; Point to V24/V25 pair + bf 22,novr22 ; Do not save VR22... + stvxl v22,br0,r13 ; Save VR22 novr22: - bf 23,novr23 ; Do not save VR23... - stvxl v23,r30,r23 ; Save VR23 + bf 23,novr23 ; Do not save VR23... + stvxl v23,r14,r13 ; Save VR23 novr23: - la r21,savevr30(r3) ; Point to line 15 - bf 13,nol14 ; No line 14 to do... - dcba br0,r20 ; Allocate cache line 14 + la r21,savevr30(r3) ; Point to line 15 + bf 13,nol14 ; No line 14 to do... + dcba br0,r11 ; Allocate cache line 14 nol14: - la r23,savevr26(r3) ; Point to V26/V27 pair - bf 24,novr24 ; Do not save VR24... - stvxl v24,br0,r22 ; Save VR24 + la r13,savevr26(r3) ; Point to V26/V27 pair + bf 24,novr24 ; Do not save VR24... + stvxl v24,br0,r12 ; Save VR24 novr24: - bf 25,novr25 ; Do not save VR25... - stvxl v25,r30,r22 ; Save VR25 + bf 25,novr25 ; Do not save VR25... + stvxl v25,r14,r12 ; Save VR25 novr25: - bf 15,nol15 ; No line 15 to do... - dcba br0,r21 ; Allocate cache line 15 + bf 15,nol15 ; No line 15 to do... + dcba br0,r21 ; Allocate cache line 15 nol15: ; ; Note: All cache lines allocated now ; - la r22,savevr28(r3) ; Point to V28/V29 pair - bf 26,novr26 ; Do not save VR26... - stvxl v26,br0,r23 ; Save VR26 + la r12,savevr28(r3) ; Point to V28/V29 pair + bf 26,novr26 ; Do not save VR26... + stvxl v26,br0,r13 ; Save VR26 novr26: - bf 27,novr27 ; Do not save VR27... - stvxl v27,r30,r23 ; Save VR27 + bf 27,novr27 ; Do not save VR27... + stvxl v27,r14,r13 ; Save VR27 novr27: - la r23,savevr30(r3) ; Point to V30/V31 pair - bf 28,novr28 ; Do not save VR28... - stvxl v28,br0,r22 ; Save VR28 + la r13,savevr30(r3) ; Point to V30/V31 pair + bf 28,novr28 ; Do not save VR28... + stvxl v28,br0,r12 ; Save VR28 novr28: - mfvscr v27 ; Get the VSCR - bf 29,novr29 ; Do not save VR29... - stvxl v29,r30,r22 ; Save VR29 + bf 29,novr29 ; Do not save VR29... + stvxl v29,r14,r12 ; Save VR29 novr29: - la r22,savevscr(r3) ; Point to the VSCR save area - bf 30,novr30 ; Do not save VR30... - stvxl v30,br0,r23 ; Save VR30 + bf 30,novr30 ; Do not save VR30... + stvxl v30,br0,r13 ; Save VR30 novr30: - dcba br0,r22 ; Allocate VSCR savearea - bf 31,novr31 ; Do not save VR31... - stvxl v31,r30,r23 ; Save VR31 + bf 31,novr31 ; Do not save VR31... + stvxl v31,r14,r13 ; Save VR31 novr31: - stvxl v27,br0,r22 ; Save the VSCR -/* - * Now check out the current thread and see if we need to load up his context. - * If we do (and this should be the normal case), do it and then release the - * savearea. - * - * If we don't (remember, we already took care of the case where we just enable - * the vector), we need to fill the registers with garbage, because this thread has - * never used them before and some thieving bastard could hack the old values - * of some thread! Just imagine what would happen if they could! Why, nothing - * would be safe! My Gosh! It's terrifying! - */ +; +; The context is all saved now and the facility is free. +; +; If we do not we need to fill the registers with junk, because this level has +; never used them before and some thieving bastard could hack the old values +; of some thread! Just imagine what would happen if they could! Why, nothing +; would be safe! My God! It is terrifying! +; +; Also, along the way, thanks to Ian Ollmann, we generate the 0x7FFFDEAD (QNaNbarbarian) +; constant that we may need to fill unused vector registers. +; -vsnosaverel: - sync ; Make sure everything is saved - stw r19,ACT_MACT_VMXcpu(r12) ; Say we are not using the context anymore -vsnosave: - li r20,ACT_MACT_VMXcpu ; Point to the CPU indication/lock word - -vsSpin2: lwarx r19,r20,r17 ; Get and reserve the last used CPU - mr. r19,r19 ; Is it changing now? - oris r21,r19,hi16(fvChk) ; Set the "changing" flag - blt- vsSpin2 ; Spin if changing - stwcx. r21,r20,r17 ; Lock it up - bne- vsSpin2 ; Someone is messing right now - isync ; Make sure we see everything - - lwz r15,ACT_MACT_PCB(r17) ; Get the current level of the "new" one - lwz r14,ACT_MACT_VMX(r17) ; Point to the top of the "new" context stack - lwz r13,ACT_MACT_VMXlvl(r17) ; Get the "new" active level +vsnosave: vspltisb v31,-10 ; Get 0xF6F6F6F6 + lwz r15,ACT_MACT_PCB(r17) ; Get the current level of the "new" one + vspltisb v30,5 ; Get 0x05050505 + lwz r19,VMXcpu(r29) ; Get the last CPU we ran on + vspltish v29,4 ; Get 0x00040004 + lwz r14,VMXsave(r29) ; Point to the top of the "new" context stack + vrlb v31,v31,v30 ; Get 0xDEDEDEDE + + stw r16,VMXcpu(r29) ; Claim context for us + eieio #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x5F07 ; (TEST/DEBUG) - mr r1,r15 ; (TEST/DEBUG) - mr r3,r14 ; (TEST/DEBUG) - mr r5,r13 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) + lwz r13,VMXlevel(r29) ; (TEST/DEBUG) + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x5F04 ; (TEST/DEBUG) + mr r1,r15 ; (TEST/DEBUG) + mr r3,r14 ; (TEST/DEBUG) + mr r5,r13 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif + + lis r18,hi16(EXT(per_proc_info)) ; Set base per_proc + vspltisb v28,-2 ; Get 0xFEFEFEFE + mulli r19,r19,ppSize ; Find offset to the owner per_proc + vsubuhm v31,v31,v29 ; Get 0xDEDADEDA + ori r18,r18,lo16(EXT(per_proc_info)) ; Set base per_proc + vpkpx v30,v28,v3 ; Get 0x7FFF7FFF + li r16,VMXowner ; Displacement to vector owner + add r19,r18,r19 ; Point to the owner per_proc + vrlb v31,v31,v29 ; Get 0xDEADDEAD + li r0,0 + +vsinvothr: lwarx r18,r16,r19 ; Get the owner + cmplw r18,r29 ; Does he still have this context? + bne vsinvoths ; Nope... + stwcx. r0,r16,r19 ; Try to invalidate it + bne- vsinvothr ; Try again if there was a collision... + + +vsinvoths: cmplwi cr1,r14,0 ; Do we possibly have some context to load? + vmrghh v31,v30,v31 ; Get 0x7FFFDEAD. V31 keeps this value until the bitter end + stw r15,VMXlevel(r29) ; Set the "new" active level + eieio + stw r29,VMXowner(r26) ; Mark us as having the live context - cmplwi cr1,r14,0 ; Do we possibly have some context to load? - stw r15,ACT_MACT_VMXlvl(r17) ; Set the "new" active level - la r23,savevscr(r14) ; Point to the VSCR - la r20,savevr0(r14) ; Point to first line to bring in - stw r17,PP_VMX_THREAD(r6) ; Store current thread address in vmx_thread to claim vector for thread - beq- cr1,ProtectTheAmericanWay ; Nothing to restore, first time use... - lwz r0,SAVlvlvec(r14) ; Get the level of first facility savearea - cmplw r0,r15 ; Top level correct to load? - bne- ProtectTheAmericanWay ; No, go initialize... + beq- cr1,ProtectTheAmericanWay ; Nothing to restore, first time use... + + lwz r3,SAVprev(r14) ; Get the previous context + lwz r0,SAVlevel(r14) ; Get the level of first facility savearea + cmplw r0,r15 ; Top level correct to load? + bne- ProtectTheAmericanWay ; No, go initialize... + stw r3,VMXsave(r29) ; Pop the context (we will toss the savearea later) + #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x5F08 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#if GDDBG - mr r8,r3 - lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display - mr r22,r4 ; Save this - ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part - mr r4,r2 ; Set value - mtlr r3 ; Set link register - li r3,1 ; Display address - blrl ; Display it - mr r4,r22 ; Restore it - mr r3,r8 -#endif + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x5F05 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif - li r0,1 ; Get the level invalid indication - lwz r22,savevrsave(r4) ; Get the most current VRSAVE - lwz r10,savevrvalid(r14) ; Get the valid VRs in the savearea - lis r9,0x5555 ; Mask with odd bits set - and r10,r10,r22 ; Figure out just what registers need to be loaded - ori r9,r9,0x5555 ; Finish mask - rlwinm r11,r10,1,0,31 ; Shift over 1 - stw r0,SAVlvlvec(r14) ; Mark the savearea invalid because we are activating again - or r12,r10,r11 ; After this, even bits show which lines to touch - dcbt br0,r23 ; Touch in the VSCR - andc r13,r12,r9 ; Clear out odd bits - - la r20,savevr0(r14) ; Point to line 0 - rlwinm r3,r13,15,0,15 ; Move line 8-15 flags to high order odd bits - la r21,savevr2(r3) ; Point to line 1 - or r3,r13,r3 ; Set the odd bits - ; (bit 0 is line 0, bit 1 is line 8, - ; bit 2 is line 1, bit 3 is line 9, etc. - lvxl v31,br0,r23 ; Get the VSCR - rlwimi r3,r10,16,16,31 ; Put vrsave 0 - 15 into positions 16 - 31 - mtvscr v31 ; Slam the VSCR value - mtcrf 255,r3 ; Load up the CRs - mr r22,r20 ; Start registers off + lwz r22,savevrsave(r25) ; Get the most current VRSAVE + lwz r10,savevrvalid(r14) ; Get the valid VRs in the savearea + lis r9,0x5555 ; Mask with odd bits set + and r10,r10,r22 ; Figure out just what registers need to be loaded + ori r9,r9,0x5555 ; Finish mask + rlwinm r11,r10,1,0,31 ; Shift over 1 + or r12,r10,r11 ; After this, even bits show which lines to touch + andc r13,r12,r9 ; Clear out odd bits + + la r20,savevr0(r14) ; Point to line 0 + rlwinm r3,r13,15,0,15 ; Move line 8-15 flags to high order odd bits + la r21,savevr2(r3) ; Point to line 1 + or r3,r13,r3 ; Set the odd bits + ; (bit 0 is line 0, bit 1 is line 8, + ; bit 2 is line 1, bit 3 is line 9, etc. + rlwimi r3,r10,16,16,31 ; Put vrsave 0 - 15 into positions 16 - 31 + mtcrf 255,r3 ; Load up the CRs + mr r22,r20 ; Start registers off ; ; Load the new vector state ; - bf 0,lnol0 ; No line 0 to do... - dcbt br0,r20 ; Touch cache line 0 + bf 0,lnol0 ; No line 0 to do... + dcbt br0,r20 ; Touch cache line 0 lnol0: - la r20,savevr4(r14) ; Point to line 2 - bf 2,lnol1 ; No line 1 to do... - dcbt br0,r21 ; Touch cache line 1 + la r20,savevr4(r14) ; Point to line 2 + bf 2,lnol1 ; No line 1 to do... + dcbt br0,r21 ; Touch cache line 1 lnol1: - la r21,savevr6(r14) ; Point to line 3 - bf 4,lnol2 ; No line 2 to do... - dcbt br0,r20 ; Touch cache line 2 + la r21,savevr6(r14) ; Point to line 3 + bf 4,lnol2 ; No line 2 to do... + dcbt br0,r20 ; Touch cache line 2 lnol2: - li r30,16 ; Get offset for odd registers - bf 16,lnovr0 ; Do not restore VR0... - lvxl v0,br0,r22 ; Restore VR0 + li r30,16 ; Get offset for odd registers + bf 16,lnovr0 ; Do not restore VR0... + lvxl v0,br0,r22 ; Restore VR0 lnovr0: - la r23,savevr2(r14) ; Point to V2/V3 pair - bf 17,lnovr1 ; Do not restore VR1... - lvxl v1,r30,r22 ; Restore VR1 + la r23,savevr2(r14) ; Point to V2/V3 pair + bf 17,lnovr1 ; Do not restore VR1... + lvxl v1,r30,r22 ; Restore VR1 lnovr1: - la r20,savevr8(r14) ; Point to line 4 - bf 6,lnol3 ; No line 3 to do... - dcbt br0,r21 ; Touch cache line 3 + la r20,savevr8(r14) ; Point to line 4 + bf 6,lnol3 ; No line 3 to do... + dcbt br0,r21 ; Touch cache line 3 lnol3: - la r22,savevr4(r14) ; Point to V4/V5 pair - bf 18,lnovr2 ; Do not restore VR2... - lvxl v2,br0,r23 ; Restore VR2 + la r22,savevr4(r14) ; Point to V4/V5 pair + bf 18,lnovr2 ; Do not restore VR2... + lvxl v2,br0,r23 ; Restore VR2 lnovr2: - bf 19,lnovr3 ; Do not restore VR3... - lvxl v3,r30,r23 ; Restore VR3 + bf 19,lnovr3 ; Do not restore VR3... + lvxl v3,r30,r23 ; Restore VR3 lnovr3: ; ; Note: CR4 is now free ; - la r21,savevr10(r14) ; Point to line 5 - bf 8,lnol4 ; No line 4 to do... - dcbt br0,r20 ; Touch cache line 4 + la r21,savevr10(r14) ; Point to line 5 + bf 8,lnol4 ; No line 4 to do... + dcbt br0,r20 ; Touch cache line 4 lnol4: - la r23,savevr6(r14) ; Point to R6/R7 pair - bf 20,lnovr4 ; Do not restore VR4... - lvxl v4,br0,r22 ; Restore VR4 + la r23,savevr6(r14) ; Point to R6/R7 pair + bf 20,lnovr4 ; Do not restore VR4... + lvxl v4,br0,r22 ; Restore VR4 lnovr4: - bf 21,lnovr5 ; Do not restore VR5... - lvxl v5,r30,r22 ; Restore VR5 + bf 21,lnovr5 ; Do not restore VR5... + lvxl v5,r30,r22 ; Restore VR5 lnovr5: - mtcrf 0x08,r10 ; Set CRs for registers 16-19 - la r20,savevr12(r14) ; Point to line 6 - bf 10,lnol5 ; No line 5 to do... - dcbt br0,r21 ; Touch cache line 5 + mtcrf 0x08,r10 ; Set CRs for registers 16-19 + la r20,savevr12(r14) ; Point to line 6 + bf 10,lnol5 ; No line 5 to do... + dcbt br0,r21 ; Touch cache line 5 lnol5: - la r22,savevr8(r14) ; Point to V8/V9 pair - bf 22,lnovr6 ; Do not restore VR6... - lvxl v6,br0,r23 ; Restore VR6 + la r22,savevr8(r14) ; Point to V8/V9 pair + bf 22,lnovr6 ; Do not restore VR6... + lvxl v6,br0,r23 ; Restore VR6 lnovr6: - bf 23,lnovr7 ; Do not restore VR7... - lvxl v7,r30,r23 ; Restore VR7 + bf 23,lnovr7 ; Do not restore VR7... + lvxl v7,r30,r23 ; Restore VR7 lnovr7: ; ; Note: CR5 is now free ; - la r21,savevr14(r14) ; Point to line 7 - bf 12,lnol6 ; No line 6 to do... - dcbt br0,r20 ; Touch cache line 6 + la r21,savevr14(r14) ; Point to line 7 + bf 12,lnol6 ; No line 6 to do... + dcbt br0,r20 ; Touch cache line 6 lnol6: - la r23,savevr10(r14) ; Point to V10/V11 pair - bf 24,lnovr8 ; Do not restore VR8... - lvxl v8,br0,r22 ; Restore VR8 + la r23,savevr10(r14) ; Point to V10/V11 pair + bf 24,lnovr8 ; Do not restore VR8... + lvxl v8,br0,r22 ; Restore VR8 lnovr8: - bf 25,lnovr9 ; Do not save VR9... - lvxl v9,r30,r22 ; Restore VR9 + bf 25,lnovr9 ; Do not save VR9... + lvxl v9,r30,r22 ; Restore VR9 lnovr9: - mtcrf 0x04,r10 ; Set CRs for registers 20-23 - la r20,savevr16(r14) ; Point to line 8 - bf 14,lnol7 ; No line 7 to do... - dcbt br0,r21 ; Touch cache line 7 + mtcrf 0x04,r10 ; Set CRs for registers 20-23 + la r20,savevr16(r14) ; Point to line 8 + bf 14,lnol7 ; No line 7 to do... + dcbt br0,r21 ; Touch cache line 7 lnol7: - la r22,savevr12(r14) ; Point to V12/V13 pair - bf 26,lnovr10 ; Do not restore VR10... - lvxl v10,br0,r23 ; Restore VR10 + la r22,savevr12(r14) ; Point to V12/V13 pair + bf 26,lnovr10 ; Do not restore VR10... + lvxl v10,br0,r23 ; Restore VR10 lnovr10: - bf 27,lnovr11 ; Do not restore VR11... - lvxl v11,r30,r23 ; Restore VR11 + bf 27,lnovr11 ; Do not restore VR11... + lvxl v11,r30,r23 ; Restore VR11 lnovr11: ; ; Note: CR6 is now free ; - la r21,savevr18(r14) ; Point to line 9 - bf 1,lnol8 ; No line 8 to do... - dcbt br0,r20 ; Touch cache line 8 + la r21,savevr18(r14) ; Point to line 9 + bf 1,lnol8 ; No line 8 to do... + dcbt br0,r20 ; Touch cache line 8 lnol8: - la r23,savevr14(r14) ; Point to V14/V15 pair - bf 28,lnovr12 ; Do not restore VR12... - lvxl v12,br0,r22 ; Restore VR12 + la r23,savevr14(r14) ; Point to V14/V15 pair + bf 28,lnovr12 ; Do not restore VR12... + lvxl v12,br0,r22 ; Restore VR12 lnovr12: - bf 29,lnovr13 ; Do not restore VR13... - lvxl v13,r30,r22 ; Restore VR13 + bf 29,lnovr13 ; Do not restore VR13... + lvxl v13,r30,r22 ; Restore VR13 lnovr13: - mtcrf 0x02,r10 ; Set CRs for registers 24-27 - la r20,savevr20(r14) ; Point to line 10 - bf 3,lnol9 ; No line 9 to do... - dcbt br0,r21 ; Touch cache line 9 + mtcrf 0x02,r10 ; Set CRs for registers 24-27 + la r20,savevr20(r14) ; Point to line 10 + bf 3,lnol9 ; No line 9 to do... + dcbt br0,r21 ; Touch cache line 9 lnol9: - la r22,savevr16(r14) ; Point to V16/V17 pair - bf 30,lnovr14 ; Do not restore VR14... - lvxl v14,br0,r23 ; Restore VR14 + la r22,savevr16(r14) ; Point to V16/V17 pair + bf 30,lnovr14 ; Do not restore VR14... + lvxl v14,br0,r23 ; Restore VR14 lnovr14: - bf 31,lnovr15 ; Do not restore VR15... - lvxl v15,r30,r23 ; Restore VR15 + bf 31,lnovr15 ; Do not restore VR15... + lvxl v15,r30,r23 ; Restore VR15 lnovr15: ; ; Note: CR7 is now free ; - la r21,savevr22(r14) ; Point to line 11 - bf 5,lnol10 ; No line 10 to do... - dcbt br0,r20 ; Touch cache line 10 + la r21,savevr22(r14) ; Point to line 11 + bf 5,lnol10 ; No line 10 to do... + dcbt br0,r20 ; Touch cache line 10 lnol10: - la r23,savevr18(r14) ; Point to V18/V19 pair - bf 16,lnovr16 ; Do not restore VR16... - lvxl v16,br0,r22 ; Restore VR16 + la r23,savevr18(r14) ; Point to V18/V19 pair + bf 16,lnovr16 ; Do not restore VR16... + lvxl v16,br0,r22 ; Restore VR16 lnovr16: - bf 17,lnovr17 ; Do not restore VR17... - lvxl v17,r30,r22 ; Restore VR17 + bf 17,lnovr17 ; Do not restore VR17... + lvxl v17,r30,r22 ; Restore VR17 lnovr17: - mtcrf 0x01,r10 ; Set CRs for registers 28-31 + mtcrf 0x01,r10 ; Set CRs for registers 28-31 ; ; Note: All registers have been or are accounted for in CRs ; - la r20,savevr24(r14) ; Point to line 12 - bf 7,lnol11 ; No line 11 to do... - dcbt br0,r21 ; Touch cache line 11 + la r20,savevr24(r14) ; Point to line 12 + bf 7,lnol11 ; No line 11 to do... + dcbt br0,r21 ; Touch cache line 11 lnol11: - la r22,savevr20(r14) ; Point to V20/V21 pair - bf 18,lnovr18 ; Do not restore VR18... - lvxl v18,br0,r23 ; Restore VR18 + la r22,savevr20(r14) ; Point to V20/V21 pair + bf 18,lnovr18 ; Do not restore VR18... + lvxl v18,br0,r23 ; Restore VR18 lnovr18: - bf 19,lnovr19 ; Do not restore VR19... - lvxl v19,r30,r23 ; Restore VR19 + bf 19,lnovr19 ; Do not restore VR19... + lvxl v19,r30,r23 ; Restore VR19 lnovr19: - la r21,savevr26(r14) ; Point to line 13 - bf 9,lnol12 ; No line 12 to do... - dcbt br0,r20 ; Touch cache line 12 + la r21,savevr26(r14) ; Point to line 13 + bf 9,lnol12 ; No line 12 to do... + dcbt br0,r20 ; Touch cache line 12 lnol12: - la r23,savevr22(r14) ; Point to V22/V23 pair - bf 20,lnovr20 ; Do not restore VR20... - lvxl v20,br0,r22 ; Restore VR20 + la r23,savevr22(r14) ; Point to V22/V23 pair + bf 20,lnovr20 ; Do not restore VR20... + lvxl v20,br0,r22 ; Restore VR20 lnovr20: - bf 21,lnovr21 ; Do not restore VR21... - lvxl v21,r30,r22 ; Restore VR21 + bf 21,lnovr21 ; Do not restore VR21... + lvxl v21,r30,r22 ; Restore VR21 lnovr21: - la r20,savevr28(r14) ; Point to line 14 - bf 11,lnol13 ; No line 13 to do... - dcbt br0,r21 ; Touch cache line 13 + la r20,savevr28(r14) ; Point to line 14 + bf 11,lnol13 ; No line 13 to do... + dcbt br0,r21 ; Touch cache line 13 lnol13: - la r22,savevr24(r14) ; Point to V24/V25 pair - bf 22,lnovr22 ; Do not restore VR22... - lvxl v22,br0,r23 ; Restore VR22 + la r22,savevr24(r14) ; Point to V24/V25 pair + bf 22,lnovr22 ; Do not restore VR22... + lvxl v22,br0,r23 ; Restore VR22 lnovr22: - bf 23,lnovr23 ; Do not restore VR23... - lvxl v23,r30,r23 ; Restore VR23 + bf 23,lnovr23 ; Do not restore VR23... + lvxl v23,r30,r23 ; Restore VR23 lnovr23: - la r21,savevr30(r14) ; Point to line 15 - bf 13,lnol14 ; No line 14 to do... - dcbt br0,r20 ; Touch cache line 14 + la r21,savevr30(r14) ; Point to line 15 + bf 13,lnol14 ; No line 14 to do... + dcbt br0,r20 ; Touch cache line 14 lnol14: - la r23,savevr26(r14) ; Point to V26/V27 pair - bf 24,lnovr24 ; Do not restore VR24... - lvxl v24,br0,r22 ; Restore VR24 + la r23,savevr26(r14) ; Point to V26/V27 pair + bf 24,lnovr24 ; Do not restore VR24... + lvxl v24,br0,r22 ; Restore VR24 lnovr24: - bf 25,lnovr25 ; Do not restore VR25... - lvxl v25,r30,r22 ; Restore VR25 + bf 25,lnovr25 ; Do not restore VR25... + lvxl v25,r30,r22 ; Restore VR25 lnovr25: - bf 15,lnol15 ; No line 15 to do... - dcbt br0,r21 ; Touch cache line 15 + bf 15,lnol15 ; No line 15 to do... + dcbt br0,r21 ; Touch cache line 15 lnol15: ; ; Note: All needed cache lines have been touched now ; - la r22,savevr28(r14) ; Point to V28/V29 pair - bf 26,lnovr26 ; Do not restore VR26... - lvxl v26,br0,r23 ; Restore VR26 + la r22,savevr28(r14) ; Point to V28/V29 pair + bf 26,lnovr26 ; Do not restore VR26... + lvxl v26,br0,r23 ; Restore VR26 lnovr26: - bf 27,lnovr27 ; Do not restore VR27... - lvxl v27,r30,r23 ; Restore VR27 + bf 27,lnovr27 ; Do not restore VR27... + lvxl v27,r30,r23 ; Restore VR27 lnovr27: - la r23,savevr30(r14) ; Point to V30/V31 pair - bf 28,lnovr28 ; Do not restore VR28... - lvxl v28,br0,r22 ; Restore VR28 + la r23,savevr30(r14) ; Point to V30/V31 pair + bf 28,lnovr28 ; Do not restore VR28... + lvxl v28,br0,r22 ; Restore VR28 lnovr28: - bf 29,lnovr29 ; Do not restore VR29... - lvxl v29,r30,r22 ; Restore VR29 + bf 29,lnovr29 ; Do not restore VR29... + lvxl v29,r30,r22 ; Restore VR29 lnovr29: - bf 30,lnovr30 ; Do not restore VR30... - lvxl v30,br0,r23 ; Restore VR30 + bf 30,lnovr30 ; Do not restore VR30... + lvxl v30,br0,r23 ; Restore VR30 lnovr30: ; ; Everything is restored now except for VR31. We need it to get -; the QNaNBarbarian value to put into idle vector registers +; the QNaNBarbarian value to put into idle vector registers. +; Note: V31 was set above to QNaNbarbarian ; - lis r5,hi16(EXT(QNaNbarbarian)) ; Get address of empty value - cmpwi r10,-1 ; Handle the quick case of all registers in use - ori r5,r5,lo16(EXT(QNaNbarbarian)) ; Get low address of empty value - beq- mstlvr31 ; Not likely, but all are in use... - mtcrf 255,r10 ; Get mask of valid registers - lvxl v31,br0,r5 ; Initialize VR31 to the empty value + cmpwi r10,-1 ; Handle the quick case of all registers in use + beq- mstlvr31 ; Not likely, but all are in use... + mtcrf 255,r10 ; Get mask of valid registers - bt 0,ni0 ; Register is ok already... - vor v0,v31,v31 ; Copy into the next register + bt 0,ni0 ; Register is ok already... + vor v0,v31,v31 ; Copy into the next register ni0: - bt 1,ni1 ; Register is ok already... - vor v1,v31,v31 ; Copy into the next register + bt 1,ni1 ; Register is ok already... + vor v1,v31,v31 ; Copy into the next register ni1: - bt 2,ni2 ; Register is ok already... - vor v2,v31,v31 ; Copy into the next register + bt 2,ni2 ; Register is ok already... + vor v2,v31,v31 ; Copy into the next register ni2: - bt 3,ni3 ; Register is ok already... - vor v3,v31,v31 ; Copy into the next register + bt 3,ni3 ; Register is ok already... + vor v3,v31,v31 ; Copy into the next register ni3: - bt 4,ni4 ; Register is ok already... - vor v4,v31,v31 ; Copy into the next register + bt 4,ni4 ; Register is ok already... + vor v4,v31,v31 ; Copy into the next register ni4: - bt 5,ni5 ; Register is ok already... - vor v5,v31,v31 ; Copy into the next register + bt 5,ni5 ; Register is ok already... + vor v5,v31,v31 ; Copy into the next register ni5: - bt 6,ni6 ; Register is ok already... - vor v6,v31,v31 ; Copy into the next register + bt 6,ni6 ; Register is ok already... + vor v6,v31,v31 ; Copy into the next register ni6: - bt 7,ni7 ; Register is ok already... - vor v7,v31,v31 ; Copy into the next register + bt 7,ni7 ; Register is ok already... + vor v7,v31,v31 ; Copy into the next register ni7: - bt 8,ni8 ; Register is ok already... - vor v8,v31,v31 ; Copy into the next register + bt 8,ni8 ; Register is ok already... + vor v8,v31,v31 ; Copy into the next register ni8: - bt 9,ni9 ; Register is ok already... - vor v9,v31,v31 ; Copy into the next register + bt 9,ni9 ; Register is ok already... + vor v9,v31,v31 ; Copy into the next register ni9: - bt 10,ni10 ; Register is ok already... - vor v10,v31,v31 ; Copy into the next register + bt 10,ni10 ; Register is ok already... + vor v10,v31,v31 ; Copy into the next register ni10: - bt 11,ni11 ; Register is ok already... - vor v11,v31,v31 ; Copy into the next register + bt 11,ni11 ; Register is ok already... + vor v11,v31,v31 ; Copy into the next register ni11: - bt 12,ni12 ; Register is ok already... - vor v12,v31,v31 ; Copy into the next register + bt 12,ni12 ; Register is ok already... + vor v12,v31,v31 ; Copy into the next register ni12: - bt 13,ni13 ; Register is ok already... - vor v13,v31,v31 ; Copy into the next register + bt 13,ni13 ; Register is ok already... + vor v13,v31,v31 ; Copy into the next register ni13: - bt 14,ni14 ; Register is ok already... - vor v14,v31,v31 ; Copy into the next register + bt 14,ni14 ; Register is ok already... + vor v14,v31,v31 ; Copy into the next register ni14: - bt 15,ni15 ; Register is ok already... - vor v15,v31,v31 ; Copy into the next register + bt 15,ni15 ; Register is ok already... + vor v15,v31,v31 ; Copy into the next register ni15: - bt 16,ni16 ; Register is ok already... - vor v16,v31,v31 ; Copy into the next register + bt 16,ni16 ; Register is ok already... + vor v16,v31,v31 ; Copy into the next register ni16: - bt 17,ni17 ; Register is ok already... - vor v17,v31,v31 ; Copy into the next register + bt 17,ni17 ; Register is ok already... + vor v17,v31,v31 ; Copy into the next register ni17: - bt 18,ni18 ; Register is ok already... - vor v18,v31,v31 ; Copy into the next register + bt 18,ni18 ; Register is ok already... + vor v18,v31,v31 ; Copy into the next register ni18: - bt 19,ni19 ; Register is ok already... - vor v19,v31,v31 ; Copy into the next register + bt 19,ni19 ; Register is ok already... + vor v19,v31,v31 ; Copy into the next register ni19: - bt 20,ni20 ; Register is ok already... - vor v20,v31,v31 ; Copy into the next register + bt 20,ni20 ; Register is ok already... + vor v20,v31,v31 ; Copy into the next register ni20: - bt 21,ni21 ; Register is ok already... - vor v21,v31,v31 ; Copy into the next register + bt 21,ni21 ; Register is ok already... + vor v21,v31,v31 ; Copy into the next register ni21: - bt 22,ni22 ; Register is ok already... - vor v22,v31,v31 ; Copy into the next register + bt 22,ni22 ; Register is ok already... + vor v22,v31,v31 ; Copy into the next register ni22: - bt 23,ni23 ; Register is ok already... - vor v23,v31,v31 ; Copy into the next register + bt 23,ni23 ; Register is ok already... + vor v23,v31,v31 ; Copy into the next register ni23: - bt 24,ni24 ; Register is ok already... - vor v24,v31,v31 ; Copy into the next register + bt 24,ni24 ; Register is ok already... + vor v24,v31,v31 ; Copy into the next register ni24: - bt 25,ni25 ; Register is ok already... - vor v25,v31,v31 ; Copy into the next register + bt 25,ni25 ; Register is ok already... + vor v25,v31,v31 ; Copy into the next register ni25: - bt 26,ni26 ; Register is ok already... - vor v26,v31,v31 ; Copy into the next register + bt 26,ni26 ; Register is ok already... + vor v26,v31,v31 ; Copy into the next register ni26: - bt 27,ni27 ; Register is ok already... - vor v27,v31,v31 ; Copy into the next register + bt 27,ni27 ; Register is ok already... + vor v27,v31,v31 ; Copy into the next register ni27: - bt 28,ni28 ; Register is ok already... - vor v28,v31,v31 ; Copy into the next register + bt 28,ni28 ; Register is ok already... + vor v28,v31,v31 ; Copy into the next register ni28: - bt 29,ni29 ; Register is ok already... - vor v29,v31,v31 ; Copy into the next register + bt 29,ni29 ; Register is ok already... + vor v29,v31,v31 ; Copy into the next register ni29: - bt 30,ni30 ; Register is ok already... - vor v30,v31,v31 ; Copy into the next register + bt 30,ni30 ; Register is ok already... + vor v30,v31,v31 ; Copy into the next register ni30: - bf 31,lnovr31 ; R31 is empty, no need to restore... + bf 31,lnovr31 ; V31 is empty, no need to restore... -mstlvr31: lvxl v31,r30,r23 ; Restore VR31 +mstlvr31: lvxl v31,r30,r23 ; Restore VR31 -lnovr31: - -vrenablexx: sync ; Make sure all is saved - stw r18,ACT_MACT_VMXcpu(r17) ; Set the active CPU and release +lnovr31: mr r3,r14 ; Get the old savearea (we popped it before) + bl EXT(save_ret) ; Toss it -vrenable: - lwz r9,SAVflags(r4) /* Get the flags of the current savearea */ - lwz r8,savesrr1(r4) ; Get the msr of the interrupted guy - rlwinm r5,r4,0,0,19 /* Get the page address of the savearea */ - oris r8,r8,hi16(MASK(MSR_VEC)) ; Enable the vector facility - lwz r10,ACT_MACT_SPF(r17) ; Get the special flags - lis r7,hi16(SAVattach) /* Get the attached flag */ - lwz r5,SACvrswap(r5) /* Get Virtual to Real translation */ +vrenable: lwz r8,savesrr1(r25) ; Get the msr of the interrupted guy + rlwinm r5,r25,0,0,19 ; Get the page address of the savearea + oris r8,r8,hi16(MASK(MSR_VEC)) ; Enable the vector facility + lwz r10,ACT_MACT_SPF(r17) ; Get the special flags + lwz r5,SACvrswap(r5) ; Get Virtual to Real translation oris r10,r10,hi16(vectorUsed|vectorCng) ; Set that we used vectors - mr. r15,r15 ; See if we are doing this for user state - stw r8,savesrr1(r4) ; Set the msr of the interrupted guy - andc r9,r9,r7 /* Clear the attached bit */ - xor r3,r4,r5 /* Get the real address of the savearea */ - stw r9,SAVflags(r4) /* Set the flags of the current savearea */ - bne- vrnuser ; We are not user state... - stw r10,ACT_MACT_SPF(r17) ; Set the activation copy - stw r10,spcFlags(r6) ; Set per_proc copy + rlwinm. r0,r8,0,MSR_PR_BIT,MSR_PR_BIT ; See if we are doing this for user state + stw r8,savesrr1(r25) ; Set the msr of the interrupted guy + xor r3,r25,r5 ; Get the real address of the savearea + bne- vrnuser ; We are not user state... + stw r10,ACT_MACT_SPF(r17) ; Set the activation copy + stw r10,spcFlags(r26) ; Set per_proc copy vrnuser: #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x5F0A ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#if GDDBG - mr r8,r3 ; Save this - lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display - ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part - mr r4,r2 ; Set value - mtlr r3 ; Set link register - li r3,1 ; Display address - blrl ; Display it - mr r3,r8 ; Restore it -#endif + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x5F07 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif - b EXT(exception_exit) /* Exit from the fray... */ + b EXT(exception_exit) ; Exit to the fray... /* * Initialize the registers to some bogus value - * We make sure that non-Java mode is the default here */ ProtectTheAmericanWay: -#if 0 - lwz r10,savesrr1(r4) ; (TEST/DEBUG) - rlwinm. r10,r10,0,MSR_PR_BIT,MSR_PR_BIT ; (TEST/DEBUG) - beq- nxxxxxx2 ; (TEST/DEBUG) - lwz r10,ACT_MACT_SPF(r17) ; (TEST/DEBUG) - rlwinm. r10,r10,0,2,2 ; (TEST/DEBUG) - beq+ nxxxxxx2 - BREAKPOINT_TRAP ; (TEST/DEBUG) -nxxxxxx2: -#endif #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x5F09 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#if GDDBG - lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display - mr r8,r4 ; Save this - ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part - mr r4,r2 ; Set value - mtlr r3 ; Set link register - li r3,1 ; Display address - blrl ; Display it - mr r4,r8 ; Restore it -#endif + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x5F06 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif - lis r5,hi16(EXT(QNaNbarbarian)) ; Get address of empty value - vspltish v1,1 ; Turn on the non-Java bit and saturate - ori r5,r5,lo16(EXT(QNaNbarbarian)) ; Get low address of empty value - vspltisw v2,1 ; Turn on the saturate bit - lvxl v0,br0,r5 ; Initialize VR0 - vxor v1,v1,v2 ; Turn off saturate - - vor v2,v0,v0 ; Copy into the next register - mtvscr v1 ; Clear the vector status register - vor v3,v0,v0 ; Copy into the next register - vor v1,v0,v0 ; Copy into the next register - vor v4,v0,v0 ; Copy into the next register - vor v5,v0,v0 ; Copy into the next register - vor v6,v0,v0 ; Copy into the next register - vor v7,v0,v0 ; Copy into the next register - vor v8,v0,v0 ; Copy into the next register - vor v9,v0,v0 ; Copy into the next register - vor v10,v0,v0 ; Copy into the next register - vor v11,v0,v0 ; Copy into the next register - vor v12,v0,v0 ; Copy into the next register - vor v13,v0,v0 ; Copy into the next register - vor v14,v0,v0 ; Copy into the next register - vor v15,v0,v0 ; Copy into the next register - vor v16,v0,v0 ; Copy into the next register - vor v17,v0,v0 ; Copy into the next register - vor v18,v0,v0 ; Copy into the next register - vor v19,v0,v0 ; Copy into the next register - vor v20,v0,v0 ; Copy into the next register - vor v21,v0,v0 ; Copy into the next register - vor v22,v0,v0 ; Copy into the next register - vor v23,v0,v0 ; Copy into the next register - vor v24,v0,v0 ; Copy into the next register - vor v25,v0,v0 ; Copy into the next register - vor v26,v0,v0 ; Copy into the next register - vor v27,v0,v0 ; Copy into the next register - vor v28,v0,v0 ; Copy into the next register - vor v29,v0,v0 ; Copy into the next register - vor v30,v0,v0 ; Copy into the next register - vor v31,v0,v0 ; Copy into the next register - b vrenablexx ; Finish setting it all up... - -; -; Finds a unused vector area in the activation pointed -; to by R12s saved contexts. If none are found (unlikely but possible) -; and R3 is 0, a new area is allocated. If R3 is non-zero, it contains -; a pointer to a vector savearea that is free. -; - -vsrchsave: lwz r6,ACT_MACT_PCB(r12) ; Get the first "normal" savearea - -vsrnorm: mr. r5,r6 ; Is there another? - beq- vsrvect ; No, search the floating point saveareas... - lwz r7,SAVflags(r5) ; Get the flags for this guy - lwz r6,SAVprev(r5) ; Get the previous savearea, just in case - andis. r8,r7,hi16(SAVvmxvalid) ; Have we found an empty vector save in normal? - beq+ vsrgot ; We found one... - b vsrnorm ; Search again... - -vsrvect: lwz r6,ACT_MACT_FPU(r12) ; Get the first "floating point" savearea - -vsrvectx: mr. r5,r6 ; Is there another? - beq- vsrget ; No, try to allocate one... - lwz r7,SAVflags(r5) ; Get the flags for this guy - lwz r6,SAVprefp(r5) ; Get the previous savearea, just in case - andis. r8,r7,hi16(SAVvmxvalid) ; Have we found an empty vector save in float? - bne- vsrvectx ; Search again... - -vsrgot: mr r3,r5 ; Get the savearea into the right register - blr ; Return... - -vsrget: mr. r5,r3 ; Do we allocate or use existing? - beq+ vsrallo ; Allocate one... - - lwz r7,SAVflags(r3) ; Get the passed in area flags - blr ; Return... -; -; NOTE: save_get will return directly and set R7 to 0... + + vor v0,v31,v31 ; Copy into the next register + vor v1,v31,v31 ; Copy into the next register + vor v2,v31,v31 ; Copy into the next register + vor v3,v31,v31 ; Copy into the next register + vor v4,v31,v31 ; Copy into the next register + vor v5,v31,v31 ; Copy into the next register + vor v6,v31,v31 ; Copy into the next register + vor v7,v31,v31 ; Copy into the next register + vor v8,v31,v31 ; Copy into the next register + vor v9,v31,v31 ; Copy into the next register + vor v10,v31,v31 ; Copy into the next register + vor v11,v31,v31 ; Copy into the next register + vor v12,v31,v31 ; Copy into the next register + vor v13,v31,v31 ; Copy into the next register + vor v14,v31,v31 ; Copy into the next register + vor v15,v31,v31 ; Copy into the next register + vor v16,v31,v31 ; Copy into the next register + vor v17,v31,v31 ; Copy into the next register + vor v18,v31,v31 ; Copy into the next register + vor v19,v31,v31 ; Copy into the next register + vor v20,v31,v31 ; Copy into the next register + vor v21,v31,v31 ; Copy into the next register + vor v22,v31,v31 ; Copy into the next register + vor v23,v31,v31 ; Copy into the next register + vor v24,v31,v31 ; Copy into the next register + vor v25,v31,v31 ; Copy into the next register + vor v26,v31,v31 ; Copy into the next register + vor v27,v31,v31 ; Copy into the next register + vor v28,v31,v31 ; Copy into the next register + vor v29,v31,v31 ; Copy into the next register + vor v30,v31,v31 ; Copy into the next register + b vrenable ; Finish setting it all up... + + + +; +; We get here when we are switching to the same context at the same level and the context +; is still live. Essentially, all we are doing is turning on the faility. It may have +; gotten turned off due to doing a context save for the current level or a context switch +; back to the live guy. +; + + .align 5 + +vsthesame: + +#if FPVECDBG + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x5F0A ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) +#endif + beq- cr1,vrenable ; Not saved yet, nothing to pop, go enable and exit... + + lwz r11,SAVlevel(r30) ; Get the level of top saved context + lwz r14,SAVprev(r30) ; Get the previous savearea + + cmplw r11,r31 ; Are live and saved the same? + + bne+ vrenable ; Level not the same, nothing to pop, go enable and exit... + + mr r3,r30 ; Get the old savearea (we popped it before) + bl EXT(save_ret) ; Toss it + b vrenable ; Go enable and exit... + + +; +; This function invalidates any live vector context for the passed in facility_context. +; This is intended to be called just before act_machine_sv_free tosses saveareas. ; -vsrallo: b EXT(save_get) ; Get a fresh savearea + .align 5 + .globl EXT(toss_live_vec) -/* - * void lfs(fpsp,fpdp) - * - * load the single precision float to the double - * - * This routine is used by the alignment handler. - * - */ -ENTRY(lfs, TAG_NO_FRAME_USED) - lfs f1, 0(r3) - stfd f1, 0(r4) - blr +LEXT(toss_live_vec) + + mfmsr r9 ; Get the MSR + rlwinm r0,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear interuptions + rlwinm. r8,r9,0,MSR_VEC_BIT,MSR_VEC_BIT ; Is vector on right now? + rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Make sure vector is turned off + rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Make sure fpu is turned off + mtmsr r0 ; No interruptions + isync + beq+ tlvnotours ; Vector off, can not be live here... -/* - * fpsp stfs(fpdp,fpsp) - * - * store the double precision float to the single - * - * This routine is used by the alignment handler. - * - */ -ENTRY(stfs, TAG_NO_FRAME_USED) - lfd f1, 0(r3) - stfs f1, 0(r4) - blr + mfsprg r8,0 ; Get the per proc + +; +; Note that at this point, since vecs are on, we are the owner +; of live state on this processor +; + + lwz r6,VMXowner(r8) ; Get the thread that owns the vector + li r0,0 ; Clear this just in case we need it + cmplw r6,r3 ; Are we tossing our own context? + bne- tlvnotours ; Nope... + + vspltish v1,1 ; Turn on the non-Java bit and saturate + vspltisw v0,1 ; Turn on the saturate bit + vxor v1,v1,v0 ; Turn off saturate + mtspr vrsave,r0 ; Clear VRSAVE + mtvscr v1 ; Set the non-java, no saturate status + +tlvnotours: lwz r11,VMXcpu(r3) ; Get the cpu on which we last loaded context + lis r12,hi16(EXT(per_proc_info)) ; Set base per_proc + mulli r11,r11,ppSize ; Find offset to the owner per_proc + ori r12,r12,lo16(EXT(per_proc_info)) ; Set base per_proc + li r10,VMXowner ; Displacement to vector owner + add r11,r12,r11 ; Point to the owner per_proc + li r0,0 ; Set a 0 to invalidate context + +tlvinvothr: lwarx r12,r10,r11 ; Get the owner + cmplw r12,r3 ; Does he still have this context? + bne+ tlvexit ; Nope, leave... + stwcx. r0,r10,r11 ; Try to invalidate it + bne- tlvinvothr ; Try again if there was a collision... + +tlvexit: mtmsr r9 ; Restore interruptions + isync ; Could be turning off vectors here + blr ; Leave.... + +#if 0 +; +; This function invalidates any live vector context for the passed in facility_context +; if the level is current. It also tosses the corresponding savearea if there is one. +; This function is primarily used whenever we detect a VRSave that is all zeros. +; + + .align 5 + .globl EXT(vec_trash) + +LEXT(vec_trash) + + lwz r12,facAct(r3) ; Get the activation + lwz r11,VMXlevel(r3) ; Get the context level + lwz r10,ACT_MACT_PCB(r12) ; Grab the current level for the thread + lwz r9,VMXsave(r3) ; Get the savearea, if any + cmplw r10,r11 ; Are we at the right level? + cmplwi cr1,r9,0 ; Remember if there is a savearea + bnelr+ ; No, we do nothing... + + lwz r11,VMXcpu(r3) ; Get the cpu on which we last loaded context + lis r12,hi16(EXT(per_proc_info)) ; Set base per_proc + mulli r11,r11,ppSize ; Find offset to the owner per_proc + ori r12,r12,lo16(EXT(per_proc_info)) ; Set base per_proc + li r10,VMXowner ; Displacement to vector owner + add r11,r12,r11 ; Point to the owner per_proc + li r0,0 ; Set a 0 to invalidate context + +vtinvothr: lwarx r12,r10,r11 ; Get the owner + cmplw r12,r3 ; Does he still have this context? + bne vtnotlive ; Nope, not live anywhere... + stwcx. r0,r10,r11 ; Try to invalidate it + bne- vtinvothr ; Try again if there was a collision... + +vtnotlive: beqlr+ cr1 ; Leave if there is no savearea + lwz r8,SAVlevel(r9) ; Get the level of the savearea + cmplw r8,r11 ; Savearea for the current level? + bnelr+ ; No, nothing to release... + + lwz r8,SAVprev(r9) ; Pick up the previous area + mr. r8,r8 ; Is there a previous? + beq- vtnoprev ; Nope... + lwz r7,SAVlevel(r8) ; Get the level associated with save + +vtnoprev: stw r8,VMXsave(r3) ; Dequeue this savearea + stw r7,VMXlevel(r3) ; Pop the level + + mr r3,r9 ; Get the savearea to release + b EXT(save_ret) ; Go and toss the save area (note, we will return from there)... +#endif + +; +; Just some test code to force vector and/or floating point in the kernel +; + + .align 5 + .globl EXT(fctx_test) +LEXT(fctx_test) + + mfsprg r3,0 ; Get the per_proc block + lwz r3,PP_ACTIVE_THREAD(r3) ; Get the thread pointer + mr. r3,r3 ; Are we actually up and running? + beqlr- ; No... + + fmr f0,f0 ; Use floating point + mftb r4 ; Get time base for a random number + li r5,1 ; Get a potential vrsave to use + andi. r4,r4,0x3F ; Get a number from 0 - 63 + slw r5,r5,r4 ; Choose a register to save (should be 0 half the time) + mtspr vrsave,r5 ; Set VRSave + vor v0,v0,v0 ; Use vectors + blr diff --git a/osfmk/ppc/db_asm.s b/osfmk/ppc/db_asm.s index b26a1e1d0..37c800684 100644 --- a/osfmk/ppc/db_asm.s +++ b/osfmk/ppc/db_asm.s @@ -42,6 +42,8 @@ ENTRY(db_phys_copy, TAG_NO_FRAME_USED) /* Switch off data translations */ mfmsr r6 + rlwinm r6,r6,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r6,r6,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r7, r6, 0, MSR_DR_BIT+1, MSR_DR_BIT-1 mtmsr r7 isync /* Ensure data translations are off */ @@ -94,6 +96,8 @@ ENTRY(db_phys_copy, TAG_NO_FRAME_USED) /* Switch off data translations */ mfmsr r6 + rlwinm r6,r6,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r6,r6,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r7, r6, 0, MSR_DR_BIT+1, MSR_DR_BIT-1 mtmsr r7 isync /* Ensure data translations are off */ diff --git a/osfmk/ppc/db_interface.c b/osfmk/ppc/db_interface.c index 943baa616..229f4f5ac 100644 --- a/osfmk/ppc/db_interface.c +++ b/osfmk/ppc/db_interface.c @@ -65,8 +65,8 @@ #include #include -struct ppc_saved_state *ppc_last_saved_statep; -struct ppc_saved_state ppc_nested_saved_state; +struct savearea *ppc_last_saved_statep; +struct savearea ppc_nested_saved_state; unsigned ppc_last_kdb_sp; extern int debugger_active[NCPUS]; /* Debugger active on CPU */ @@ -149,7 +149,7 @@ void kdp_register_send_receive(void) {} extern jmp_buf_t *db_recover; spl_t saved_ipl[NCPUS]; /* just to know what IPL was before trap */ -struct ppc_saved_state *saved_state[NCPUS]; +struct savearea *saved_state[NCPUS]; /* * kdb_trap - field a TRACE or BPT trap @@ -157,7 +157,7 @@ struct ppc_saved_state *saved_state[NCPUS]; void kdb_trap( int type, - struct ppc_saved_state *regs) + struct savearea *regs) { boolean_t trap_from_user; int previous_console_device; @@ -183,11 +183,11 @@ kdb_trap( else db_printf("%s", trap_type[type]); db_printf(" trap, pc = %x\n", - regs->srr0); + regs->save_srr0); db_error(""); /*NOTREACHED*/ } - kdbprinttrap(type, code, (int *)®s->srr0, regs->r1); + kdbprinttrap(type, code, (int *)®s->save_srr0, regs->save_r1); } saved_state[cpu_number()] = regs; @@ -211,13 +211,13 @@ kdb_trap( *regs = ddb_regs; if ((type == T_PROGRAM) && - (db_get_task_value(regs->srr0, + (db_get_task_value(regs->save_srr0, BKPT_SIZE, FALSE, db_target_space(current_act(), trap_from_user)) == BKPT_INST)) - regs->srr0 += BKPT_SIZE; + regs->save_srr0 += BKPT_SIZE; kdb_exit: saved_state[cpu_number()] = 0; diff --git a/osfmk/ppc/db_low_trace.c b/osfmk/ppc/db_low_trace.c index 8b80ffba9..2bc5ce0c4 100644 --- a/osfmk/ppc/db_low_trace.c +++ b/osfmk/ppc/db_low_trace.c @@ -60,6 +60,7 @@ #include #include #include +#include void db_dumpphys(struct phys_entry *pp); /* Dump from physent */ void db_dumppca(struct mapping *mp); /* PCA */ @@ -467,11 +468,12 @@ void db_display_virtual(db_expr_t addr, int have_addr, db_expr_t count, char * m void db_display_save(db_expr_t addr, int have_addr, db_expr_t count, char * modif) { - int i, j, totsaves, tottasks, taskact, chainsize; + int i, j, totsaves, tottasks, taskact, chainsize, vmid, didvmhead; processor_set_t pset = &default_pset; task_t task; thread_act_t act; savearea *save; + vmmCntrlTable *CTable; tottasks = 0; totsaves = 0; @@ -480,46 +482,88 @@ void db_display_save(db_expr_t addr, int have_addr, db_expr_t count, char * modi taskact = 0; /* Reset activation count */ db_printf("\nTask %4d @%08X:\n", tottasks, task); /* Show where we're at */ for(act = (thread_act_t)task->thr_acts.next; act != (thread_act_t)&task->thr_acts; act = (thread_act_t)act->thr_acts.next) { /* Go through activations */ - db_printf(" Act %4d @%08X - p: %08X fp: %08X fl: %08X fc: %d vp: %08X vl: %08X vp: %d\n", - taskact, act, act->mact.pcb, act->mact.FPU_pcb, act->mact.FPU_lvl, act->mact.FPU_cpu, - act->mact.VMX_pcb, act->mact.VMX_lvl, act->mact.VMX_cpu); - + db_printf(" Act %4d @%08X - p: %08X current context: %08X\n", + taskact, act, act->mact.pcb, act->mact.curctx); save = (savearea *)act->mact.pcb; /* Set the start of the normal chain */ chainsize = 0; + + db_printf(" General context - fp: %08X fl: %08X fc: %d vp: %08X vl: %08X vp: %d\n", + act->mact.facctx.FPUsave, act->mact.facctx.FPUlevel, act->mact.facctx.FPUcpu, + act->mact.facctx.VMXsave, act->mact.facctx.VMXlevel, act->mact.facctx.VMXcpu); + while(save) { /* Do them all */ totsaves++; /* Count savearea */ - db_printf(" Norm %08X: %08X %08X - tot = %d\n", save, save->save_srr0, save->save_srr1, totsaves); - save = save->save_prev; /* Next one */ + db_printf(" Norm %08X: %08X %08X - tot = %d\n", save, save->save_srr0, save->save_srr1, totsaves); + save = save->save_hdr.save_prev; /* Next one */ if(chainsize++ > chainmax) { /* See if we might be in a loop */ - db_printf(" Chain terminated by count (%d) before %08X\n", chainmax, save); + db_printf(" Chain terminated by count (%d) before %08X\n", chainmax, save); break; } } - save = (savearea *)act->mact.FPU_pcb; /* Set the start of the floating point chain */ + save = (savearea *)act->mact.facctx.FPUsave; /* Set the start of the floating point chain */ chainsize = 0; while(save) { /* Do them all */ - if(!(save->save_flags & SAVattach)) totsaves++; /* Count savearea only if not a normal one also */ - db_printf(" FPU %08X: %08X - tot = %d\n", save, save->save_level_fp, totsaves); - save = save->save_prev_float; /* Next one */ + totsaves++; /* Count savearea */ + db_printf(" FPU %08X: %08X - tot = %d\n", save, save->save_hdr.save_level, totsaves); + save = save->save_hdr.save_prev; /* Next one */ if(chainsize++ > chainmax) { /* See if we might be in a loop */ - db_printf(" Chain terminated by count (%d) before %08X\n", chainmax, save); + db_printf(" Chain terminated by count (%d) before %08X\n", chainmax, save); break; } } - save = (savearea *)act->mact.VMX_pcb; /* Set the start of the floating point chain */ + save = (savearea *)act->mact.facctx.VMXsave; /* Set the start of the floating point chain */ chainsize = 0; while(save) { /* Do them all */ - if(!(save->save_flags & (SAVattach | SAVfpuvalid))) totsaves++; /* Count savearea only if not a normal one also */ - db_printf(" Vec %08X: %08X - tot = %d\n", save, save->save_level_vec, totsaves); - save = save->save_prev_vector; /* Next one */ + totsaves++; /* Count savearea */ + db_printf(" Vec %08X: %08X - tot = %d\n", save, save->save_hdr.save_level, totsaves); + save = save->save_hdr.save_prev; /* Next one */ if(chainsize++ > chainmax) { /* See if we might be in a loop */ - db_printf(" Chain terminated by count (%d) before %08X\n", chainmax, save); + db_printf(" Chain terminated by count (%d) before %08X\n", chainmax, save); break; } } + + if(CTable = act->mact.vmmControl) { /* Are there virtual machines? */ + + for(vmid = 0; vmid < kVmmMaxContextsPerThread; vmid++) { + + if(!(CTable->vmmc[vmid].vmmFlags & vmmInUse)) continue; /* Skip if vm is not in use */ + + if(!CTable->vmmc[vmid].vmmFacCtx.FPUsave && !CTable->vmmc[vmid].vmmFacCtx.VMXsave) continue; /* If neither types, skip this vm */ + + db_printf(" VMachine ID %3d - fp: %08X fl: %08X fc: %d vp: %08X vl: %08X vp: %d\n", vmid, /* Title it */ + CTable->vmmc[vmid].vmmFacCtx.FPUsave, CTable->vmmc[vmid].vmmFacCtx.FPUlevel, CTable->vmmc[vmid].vmmFacCtx.FPUcpu, + CTable->vmmc[vmid].vmmFacCtx.VMXsave, CTable->vmmc[vmid].vmmFacCtx.VMXlevel, CTable->vmmc[vmid].vmmFacCtx.VMXcpu + ); + + save = (savearea *)CTable->vmmc[vmid].vmmFacCtx.FPUsave; /* Set the start of the floating point chain */ + chainsize = 0; + while(save) { /* Do them all */ + totsaves++; /* Count savearea */ + db_printf(" FPU %08X: %08X - tot = %d\n", save, save->save_hdr.save_level, totsaves); + save = save->save_hdr.save_prev; /* Next one */ + if(chainsize++ > chainmax) { /* See if we might be in a loop */ + db_printf(" Chain terminated by count (%d) before %08X\n", chainmax, save); + break; + } + } + + save = (savearea *)CTable->vmmc[vmid].vmmFacCtx.VMXsave; /* Set the start of the floating point chain */ + chainsize = 0; + while(save) { /* Do them all */ + totsaves++; /* Count savearea */ + db_printf(" Vec %08X: %08X - tot = %d\n", save, save->save_hdr.save_level, totsaves); + save = save->save_hdr.save_prev; /* Next one */ + if(chainsize++ > chainmax) { /* See if we might be in a loop */ + db_printf(" Chain terminated by count (%d) before %08X\n", chainmax, save); + break; + } + } + } + } taskact++; } tottasks++; diff --git a/osfmk/ppc/db_machdep.h b/osfmk/ppc/db_machdep.h index 2d997f922..fb95f0608 100644 --- a/osfmk/ppc/db_machdep.h +++ b/osfmk/ppc/db_machdep.h @@ -63,23 +63,24 @@ #include /* for thread_status */ #include #include +#include typedef vm_offset_t db_addr_t; /* address - unsigned */ typedef int db_expr_t; /* expression - signed */ -typedef struct ppc_saved_state db_regs_t; +typedef struct savearea db_regs_t; db_regs_t ddb_regs; /* register state */ #define DDB_REGS (&ddb_regs) extern int db_active; /* ddb is active */ -#define PC_REGS(regs) ((db_addr_t)(regs)->srr0) +#define PC_REGS(regs) ((db_addr_t)(regs)->save_srr0) #define BKPT_INST 0x7c810808 /* breakpoint instruction */ #define BKPT_SIZE (4) /* size of breakpoint inst */ #define BKPT_SET(inst) (BKPT_INST) -#define db_clear_single_step(regs) ((regs)->srr1 &= ~MASK(MSR_SE)) -#define db_set_single_step(regs) ((regs)->srr1 |= MASK(MSR_SE)) +#define db_clear_single_step(regs) ((regs)->save_srr1 &= ~MASK(MSR_SE)) +#define db_set_single_step(regs) ((regs)->save_srr1 |= MASK(MSR_SE)) #define IS_BREAKPOINT_TRAP(type, code) (FALSE) #define IS_WATCHPOINT_TRAP(type, code) (FALSE) @@ -106,12 +107,12 @@ int db_inst_store(unsigned long); ((user) && (addr) < VM_MAX_ADDRESS)) /* - * Given pointer to ppc_saved_state, determine if it represents + * Given pointer to savearea, determine if it represents * a thread executing a) in user space, b) in the kernel, or c) * in a kernel-loaded task. Return true for cases a) and c). */ #define IS_USER_TRAP(regs) \ - (USER_MODE(regs->srr1)) + (USER_MODE(regs->save_srr1)) extern boolean_t db_check_access( vm_offset_t addr, @@ -175,9 +176,9 @@ extern void db_task_name( extern void kdb_trap( int type, - struct ppc_saved_state *regs); + struct savearea *regs); extern boolean_t db_trap_from_asm( - struct ppc_saved_state *regs); + struct savearea *regs); extern void kdb_on( int cpu); extern void cnpollc( diff --git a/osfmk/ppc/db_trace.c b/osfmk/ppc/db_trace.c index d24838fb6..f7129ff9f 100644 --- a/osfmk/ppc/db_trace.c +++ b/osfmk/ppc/db_trace.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -43,9 +44,9 @@ #include extern jmp_buf_t *db_recover; -extern struct ppc_saved_state *saved_state[]; +extern struct savearea *saved_state[]; -struct ppc_saved_state ddb_null_kregs; +struct savearea ddb_null_kregs; extern vm_offset_t vm_min_inks_addr; /* set by db_clone_symtabXXX */ @@ -123,47 +124,45 @@ extern int _setjmp( */ struct db_variable db_regs[] = { /* XXX "pc" is an alias to "srr0"... */ - { "pc", (int *)&ddb_regs.srr0, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "srr0", (int *)&ddb_regs.srr0, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "srr1", (int *)&ddb_regs.srr1, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r0", (int *)&ddb_regs.r0, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r1", (int *)&ddb_regs.r1, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r2", (int *)&ddb_regs.r2, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r3", (int *)&ddb_regs.r3, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r4", (int *)&ddb_regs.r4, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r5", (int *)&ddb_regs.r5, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r6", (int *)&ddb_regs.r6, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r7", (int *)&ddb_regs.r7, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r8", (int *)&ddb_regs.r8, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r9", (int *)&ddb_regs.r9, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r10", (int *)&ddb_regs.r10, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r11", (int *)&ddb_regs.r11, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r12", (int *)&ddb_regs.r12, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r13", (int *)&ddb_regs.r13, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r14", (int *)&ddb_regs.r14, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r15", (int *)&ddb_regs.r15, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r16", (int *)&ddb_regs.r16, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r17", (int *)&ddb_regs.r17, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r18", (int *)&ddb_regs.r18, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r19", (int *)&ddb_regs.r19, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r20", (int *)&ddb_regs.r20, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r21", (int *)&ddb_regs.r21, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r22", (int *)&ddb_regs.r22, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r23", (int *)&ddb_regs.r23, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r24", (int *)&ddb_regs.r24, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r25", (int *)&ddb_regs.r25, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r26", (int *)&ddb_regs.r26, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r27", (int *)&ddb_regs.r27, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r28", (int *)&ddb_regs.r28, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r29", (int *)&ddb_regs.r29, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r30", (int *)&ddb_regs.r30, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "r31", (int *)&ddb_regs.r31, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "cr", (int *)&ddb_regs.cr, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "xer", (int *)&ddb_regs.xer, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "lr", (int *)&ddb_regs.lr, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "ctr", (int *)&ddb_regs.ctr, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "mq", (int *)&ddb_regs.mq, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, - { "sr_copyin",(int *)&ddb_regs.sr_copyin,db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "pc", (int *)&ddb_regs.save_srr0, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "srr0", (int *)&ddb_regs.save_srr0, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "srr1", (int *)&ddb_regs.save_srr1, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r0", (int *)&ddb_regs.save_r0, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r1", (int *)&ddb_regs.save_r1, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r2", (int *)&ddb_regs.save_r2, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r3", (int *)&ddb_regs.save_r3, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r4", (int *)&ddb_regs.save_r4, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r5", (int *)&ddb_regs.save_r5, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r6", (int *)&ddb_regs.save_r6, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r7", (int *)&ddb_regs.save_r7, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r8", (int *)&ddb_regs.save_r8, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r9", (int *)&ddb_regs.save_r9, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r10", (int *)&ddb_regs.save_r10, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r11", (int *)&ddb_regs.save_r11, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r12", (int *)&ddb_regs.save_r12, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r13", (int *)&ddb_regs.save_r13, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r14", (int *)&ddb_regs.save_r14, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r15", (int *)&ddb_regs.save_r15, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r16", (int *)&ddb_regs.save_r16, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r17", (int *)&ddb_regs.save_r17, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r18", (int *)&ddb_regs.save_r18, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r19", (int *)&ddb_regs.save_r19, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r20", (int *)&ddb_regs.save_r20, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r21", (int *)&ddb_regs.save_r21, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r22", (int *)&ddb_regs.save_r22, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r23", (int *)&ddb_regs.save_r23, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r24", (int *)&ddb_regs.save_r24, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r25", (int *)&ddb_regs.save_r25, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r26", (int *)&ddb_regs.save_r26, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r27", (int *)&ddb_regs.save_r27, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r28", (int *)&ddb_regs.save_r28, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r29", (int *)&ddb_regs.save_r29, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r30", (int *)&ddb_regs.save_r30, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "r31", (int *)&ddb_regs.save_r31, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "cr", (int *)&ddb_regs.save_cr, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "xer", (int *)&ddb_regs.save_xer, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "lr", (int *)&ddb_regs.save_lr, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, + { "ctr", (int *)&ddb_regs.save_ctr, db_ppc_reg_value, 0, 0, 0, 0, TRUE }, }; struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]); @@ -187,7 +186,7 @@ db_ppc_reg_value( if (thr_act == current_act()) { if (IS_USER_TRAP((&ddb_regs))) dp = vp->valuep; - else if (INFIXEDSTACK(ddb_regs.r1)) + else if (INFIXEDSTACK(ddb_regs.save_r1)) db_error("cannot get/set user registers in nested interrupt\n"); } } else { @@ -200,25 +199,21 @@ db_ppc_reg_value( int cpu; for (cpu = 0; cpu < NCPUS; cpu++) { - if (machine_slot[cpu].running == TRUE && - cpu_data[cpu].active_thread == thr_act->thread && saved_state[cpu]) { + if (cpu_to_processor(cpu)->state == PROCESSOR_RUNNING && + cpu_to_processor(cpu)->cpu_data->active_thread == thr_act->thread && saved_state[cpu]) { dp = (int *) (((int)saved_state[cpu]) + (((int) vp->valuep) - (int) &ddb_regs)); break; } } -#if 0 - if (dp == 0 && thr_act && thr_act->thread) - dp = db_lookup_i386_kreg(vp->name, - (int *)(STACK_IKS(thr_act->thread->kernel_stack))); -#endif + if (dp == 0) dp = &null_reg; } else if (thr_act->thread && (thr_act->thread->state&TH_STACK_HANDOFF)){ /* only PC is valid */ - if (vp->valuep == (int *) &ddb_regs.srr0) { + if (vp->valuep == (int *) &ddb_regs.save_srr0) { dp = (int *)(&thr_act->thread->continuation); } else { dp = &null_reg; @@ -231,8 +226,8 @@ db_ppc_reg_value( if (!db_option(ap->modif, 'u')) { for (cpu = 0; cpu < NCPUS; cpu++) { - if (machine_slot[cpu].running == TRUE && - cpu_data[cpu].active_thread == thr_act->thread && saved_state[cpu]) { + if (cpu_to_processor(cpu)->state == PROCESSOR_RUNNING && + cpu_to_processor(cpu)->cpu_data->active_thread == thr_act->thread && saved_state[cpu]) { dp = (int *) (((int)saved_state[cpu]) + (((int) vp->valuep) - (int) &ddb_regs)); @@ -243,7 +238,7 @@ db_ppc_reg_value( if (dp == 0) { if (!thr_act || thr_act->mact.pcb == 0) db_error("no pcb\n"); - dp = (int *)((int)(&thr_act->mact.pcb->ss) + + dp = (int *)((int)thr_act->mact.pcb + ((int)vp->valuep - (int)&ddb_regs)); } } @@ -352,59 +347,28 @@ db_nextframe( extern char * trap_type[]; extern int TRAP_TYPES; - struct ppc_saved_state *saved_regs; + struct savearea *saved_regs; task_t task = (thr_act != THR_ACT_NULL)? thr_act->task: TASK_NULL; switch(frame_type) { case TRAP: -#if 0 - /* - * We know that trap() has 1 argument and we know that - * it is an (strcut i386_saved_state *). - */ - saved_regs = (struct i386_saved_state *) - db_get_task_value((int)&((*fp)->f_arg0),4,FALSE,task); - if (saved_regs->trapno >= 0 && saved_regs->trapno < TRAP_TYPES) { - db_printf(">>>>> %s trap at ", - trap_type[saved_regs->trapno]); - } else { - db_printf(">>>>> trap (number %d) at ", - saved_regs->trapno & 0xffff); - } - db_task_printsym(saved_regs->eip, DB_STGY_PROC, task); - db_printf(" <<<<<\n"); - *fp = (struct i386_frame *)saved_regs->ebp; - *ip = (db_addr_t)saved_regs->eip; -#else + db_printf(">>>>> trap <<<<<\n"); goto miss_frame; -#endif break; case INTERRUPT: if (*lfp == 0) { db_printf(">>>>> interrupt <<<<<\n"); goto miss_frame; } -#if 0 - db_printf(">>>>> interrupt at "); - ifp = (struct interrupt_frame *)(*lfp); - *fp = ifp->if_frame; - if (ifp->if_iretaddr == db_return_to_iret_symbol_value) - *ip = ((struct i386_interrupt_state *) ifp->if_edx)->eip; - else - *ip = (db_addr_t) ifp->if_eip; - db_task_printsym(*ip, DB_STGY_PROC, task); - db_printf(" <<<<<\n"); -#else db_printf(">>>>> interrupt <<<<<\n"); goto miss_frame; -#endif break; case SYSCALL: if (thr_act != THR_ACT_NULL && thr_act->mact.pcb) { - *ip = (db_addr_t) thr_act->mact.pcb->ss.srr0; - *fp = (struct db_ppc_frame *) (thr_act->mact.pcb->ss.r1); + *ip = (db_addr_t) thr_act->mact.pcb->save_srr0; + *fp = (struct db_ppc_frame *) (thr_act->mact.pcb->save_r1); break; } /* falling down for unknown case */ @@ -514,9 +478,9 @@ next_thread: frame_count = count; if (!have_addr && !trace_thread) { - frame = (struct db_ppc_frame *)(ddb_regs.r1); - callpc = (db_addr_t)ddb_regs.srr0; - linkpc = (db_addr_t)ddb_regs.lr; + frame = (struct db_ppc_frame *)(ddb_regs.save_r1); + callpc = (db_addr_t)ddb_regs.save_srr0; + linkpc = (db_addr_t)ddb_regs.save_lr; th = current_act(); task = (th != THR_ACT_NULL)? th->task: TASK_NULL; } @@ -545,9 +509,9 @@ next_activation: task = th->task; if (th == current_act()) { - frame = (struct db_ppc_frame *)(ddb_regs.r1); - callpc = (db_addr_t)ddb_regs.srr0; - linkpc = (db_addr_t)ddb_regs.lr; + frame = (struct db_ppc_frame *)(ddb_regs.save_r1); + callpc = (db_addr_t)ddb_regs.save_srr0; + linkpc = (db_addr_t)ddb_regs.save_lr; } else { if (th->mact.pcb == 0) { @@ -555,37 +519,31 @@ next_activation: goto thread_done; } if (!th->thread) { - register struct ppc_saved_state *pss = - &th->mact.pcb->ss; + register struct savearea *pss = + th->mact.pcb; db_printf("thread has no shuttle\n"); - #if 0 - frame = (struct db_ppc_frame *) (pss->r1); - callpc = (db_addr_t) (pss->srr0); - linkpc = (db_addr_t) (pss->lr); - #else goto thread_done; - #endif } else if ((th->thread->state & TH_STACK_HANDOFF) || th->thread->kernel_stack == 0) { - register struct ppc_saved_state *pss = - &th->mact.pcb->ss; + register struct savearea *pss = + th->mact.pcb; db_printf("Continuation "); db_task_printsym((db_expr_t)th->thread->continuation, DB_STGY_PROC, task); db_printf("\n"); - frame = (struct db_ppc_frame *) (pss->r1); - callpc = (db_addr_t) (pss->srr0); - linkpc = (db_addr_t) (pss->lr); + frame = (struct db_ppc_frame *) (pss->save_r1); + callpc = (db_addr_t) (pss->save_srr0); + linkpc = (db_addr_t) (pss->save_lr); } else { int cpu; for (cpu = 0; cpu < NCPUS; cpu++) { - if (machine_slot[cpu].running == TRUE && - cpu_data[cpu].active_thread == th->thread && + if (cpu_to_processor(cpu)->state == PROCESSOR_RUNNING && + cpu_to_processor(cpu)->cpu_data->active_thread == th->thread && saved_state[cpu]) { break; } @@ -596,22 +554,22 @@ next_activation: * which is not the top_most one in the RPC chain: * use the activation's pcb. */ - struct ppc_saved_state *pss; + struct savearea *pss; - pss = (struct ppc_saved_state *)th->mact.pcb; - frame = (struct db_ppc_frame *) (pss->r1); - callpc = (db_addr_t) (pss->srr0); - linkpc = (db_addr_t) (pss->lr); + pss = th->mact.pcb; + frame = (struct db_ppc_frame *) (pss->save_r1); + callpc = (db_addr_t) (pss->save_srr0); + linkpc = (db_addr_t) (pss->save_lr); } else { if (cpu == NCPUS) { - register struct ppc_saved_state *iks; + register struct savearea *iks; int r; - iks = (struct ppc_saved_state *)th->mact.pcb; + iks = th->mact.pcb; prev = db_recover; if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) { - frame = (struct db_ppc_frame *) (iks->r1); - callpc = (db_addr_t) (iks->lr); + frame = (struct db_ppc_frame *) (iks->save_r1); + callpc = (db_addr_t) (iks->save_lr); linkpc = 0; } else { /* @@ -631,9 +589,9 @@ next_activation: db_printf(">>>>> active on cpu %d <<<<<\n", cpu); frame = (struct db_ppc_frame *) - (saved_state[cpu]->r1); - callpc = (db_addr_t) saved_state[cpu]->srr0; - linkpc = (db_addr_t) saved_state[cpu]->lr; + (saved_state[cpu]->save_r1); + callpc = (db_addr_t) saved_state[cpu]->save_srr0; + linkpc = (db_addr_t) saved_state[cpu]->save_lr; } } } diff --git a/osfmk/ppc/exception.h b/osfmk/ppc/exception.h index 355c1074f..e268b0d2d 100644 --- a/osfmk/ppc/exception.h +++ b/osfmk/ppc/exception.h @@ -30,6 +30,8 @@ #ifndef _PPC_EXCEPTION_H_ #define _PPC_EXCEPTION_H_ +#include + #ifndef ASSEMBLER #include @@ -38,6 +40,7 @@ #include #include +#include #include #include #include @@ -63,6 +66,8 @@ struct procFeatures { #define pfThermalb 7 #define pfThermInt 0x00800000 #define pfThermIntb 8 +#define pfNoL2PFNap 0x00008000 +#define pfNoL2PFNapb 16 #define pfSlowNap 0x00004000 #define pfSlowNapb 17 #define pfNoMuMMCK 0x00002000 @@ -147,43 +152,44 @@ struct per_proc_info { /* PPC cache line boundary here - 020 */ unsigned int active_kloaded; /* pointer to active_kloaded[CPU_NO] */ - unsigned int cpu_data; /* pointer to cpu_data[CPU_NO] */ + unsigned int active_stacks; /* pointer to active_stacks[CPU_NO] */ unsigned int need_ast; /* pointer to need_ast[CPU_NO] */ /* * Note: the following two pairs of words need to stay in order and each pair must * be in the same reservation (line) granule */ - unsigned int FPU_thread; /* Thread owning the FPU on this cpu.*/ - unsigned int FPU_vmmCtx; /* Owing virtual machine context */ - unsigned int VMX_thread; /* Thread owning the VMX on this cpu */ - unsigned int VMX_vmmCtx; /* Owing virtual machine context */ - unsigned int active_stacks; /* pointer to active_stacks[CPU_NO] */ + struct facility_context *FPU_owner; /* Owner of the FPU on this cpu */ + unsigned int pprsv1; + struct facility_context *VMX_owner; /* Owner of the VMX on this cpu */ + unsigned int pprsv2; + unsigned int next_savearea; /* pointer to the next savearea */ /* PPC cache line boundary here - 040 */ - unsigned int quickfret; /* Pointer to savearea for exception exit to free */ + unsigned int quickfret; /* List of saveareas to release */ + unsigned int lclfree; /* Pointer to local savearea list */ + unsigned int lclfreecnt; /* Entries in local savearea list */ unsigned int Lastpmap; /* Last user pmap loaded */ unsigned int userspace; /* Last loaded user memory space ID */ unsigned int userpmap; /* User pmap - real address */ unsigned int liveVRSave; /* VRSave assiciated with live vector registers */ unsigned int spcFlags; /* Special thread flags */ - unsigned int liveFPSCR; /* FPSCR which is for the live context */ - unsigned int ppbbTaskEnv; /* BlueBox Task Environment */ /* PPC cache line boundary here - 060 */ boolean_t interrupts_enabled; - unsigned int rsrvd064; + unsigned int ppbbTaskEnv; /* BlueBox Task Environment */ IOInterruptHandler interrupt_handler; void * interrupt_nub; unsigned int interrupt_source; void * interrupt_target; void * interrupt_refCon; - unsigned int savedSave; /* Savearea saved across sleep - must be 0 at boot */ + time_base_enable_t time_base_enable; /* PPC cache line boundary here - 080 */ unsigned int MPsigpStat; /* Signal Processor status (interlocked update for this one) */ -#define MPsigpMsgp 0xC0000000 /* Message pending (busy + pass) */ +#define MPsigpMsgp 0xC0000000 /* Message pending (busy + pass ) */ #define MPsigpBusy 0x80000000 /* Processor area busy, i.e., locked */ #define MPsigpPass 0x40000000 /* Busy lock passed to receiving processor */ +#define MPsigpAck 0x20000000 /* Ack Busy lock passed to receiving processor */ #define MPsigpSrc 0x000000FF /* Processor that owns busy, i.e., the ID of */ /* whomever set busy. When a busy is passed, */ /* this is the requestor of the function. */ @@ -218,14 +224,17 @@ struct per_proc_info { unsigned int numSIGPwake; /* Number of SIGP wakes recieved */ /* PPC cache line boundary here - 140 */ + unsigned int numSIGPtimo; /* Number of SIGP send timeouts */ + unsigned int numSIGPmast; /* Number of SIGPast messages merged */ + unsigned int numSIGPmwake; /* Number of SIGPwake messages merged */ unsigned int spcTRc; /* Special trace count */ unsigned int spcTRp; /* Special trace buffer pointer */ unsigned int Uassist; /* User Assist Word */ - unsigned int rsrvd14C[5]; /* Reserved slots */ + unsigned int rsrvd158[2]; /* Reserved slots */ /* PPC cache line boundary here - 160 */ - time_base_enable_t time_base_enable; - unsigned int rsrvd164[7]; /* Reserved slots */ + cpu_data_t pp_cpu_data; /* cpu data info */ + unsigned int rsrvd170[4]; /* Reserved slots */ /* PPC cache line boundary here - 180 */ unsigned int rsrvd180[8]; /* Reserved slots */ @@ -324,242 +333,18 @@ struct per_proc_info { }; +#define pp_active_thread pp_cpu_data.active_thread +#define pp_preemption_count pp_cpu_data.preemption_level +#define pp_simple_lock_count pp_cpu_data.simple_lock_count +#define pp_interrupt_level pp_cpu_data.interrupt_level -extern struct per_proc_info per_proc_info[NCPUS]; - -typedef struct savearea { - -/* The following area corresponds to ppc_saved_state and ppc_thread_state */ - -/* offset 0x0000 */ - unsigned int save_srr0; - unsigned int save_srr1; - unsigned int save_r0; - unsigned int save_r1; - unsigned int save_r2; - unsigned int save_r3; - unsigned int save_r4; - unsigned int save_r5; - - unsigned int save_r6; - unsigned int save_r7; - unsigned int save_r8; - unsigned int save_r9; - unsigned int save_r10; - unsigned int save_r11; - unsigned int save_r12; - unsigned int save_r13; - - unsigned int save_r14; - unsigned int save_r15; - unsigned int save_r16; - unsigned int save_r17; - unsigned int save_r18; - unsigned int save_r19; - unsigned int save_r20; - unsigned int save_r21; - - unsigned int save_r22; - unsigned int save_r23; - unsigned int save_r24; - unsigned int save_r25; - unsigned int save_r26; - unsigned int save_r27; - unsigned int save_r28; - unsigned int save_r29; - - unsigned int save_r30; - unsigned int save_r31; - unsigned int save_cr; - unsigned int save_xer; - unsigned int save_lr; - unsigned int save_ctr; - unsigned int save_mq; - unsigned int save_vrsave; - - unsigned int save_sr_copyin; - unsigned int save_space; - unsigned int save_xfpscrpad; - unsigned int save_xfpscr; - unsigned int save_pad2[4]; - - -/* The following corresponds to ppc_exception_state */ - -/* offset 0x00C0 */ - unsigned int save_dar; - unsigned int save_dsisr; - unsigned int save_exception; - unsigned int save_pad3[5]; - -/* The following corresponds to ppc_float_state */ - -/* offset 0x00E0 */ - double save_fp0; - double save_fp1; - double save_fp2; - double save_fp3; - - double save_fp4; - double save_fp5; - double save_fp6; - double save_fp7; - - double save_fp8; - double save_fp9; - double save_fp10; - double save_fp11; - - double save_fp12; - double save_fp13; - double save_fp14; - double save_fp15; - - double save_fp16; - double save_fp17; - double save_fp18; - double save_fp19; - - double save_fp20; - double save_fp21; - double save_fp22; - double save_fp23; - - double save_fp24; - double save_fp25; - double save_fp26; - double save_fp27; - - double save_fp28; - double save_fp29; - double save_fp30; - double save_fp31; - - unsigned int save_fpscr_pad; - unsigned int save_fpscr; - unsigned int save_pad4[6]; - -/* The following is the save area for the VMX registers */ - -/* offset 0x0200 */ - unsigned int save_vr0[4]; - unsigned int save_vr1[4]; - unsigned int save_vr2[4]; - unsigned int save_vr3[4]; - unsigned int save_vr4[4]; - unsigned int save_vr5[4]; - unsigned int save_vr6[4]; - unsigned int save_vr7[4]; - unsigned int save_vr8[4]; - unsigned int save_vr9[4]; - unsigned int save_vr10[4]; - unsigned int save_vr11[4]; - unsigned int save_vr12[4]; - unsigned int save_vr13[4]; - unsigned int save_vr14[4]; - unsigned int save_vr15[4]; - unsigned int save_vr16[4]; - unsigned int save_vr17[4]; - unsigned int save_vr18[4]; - unsigned int save_vr19[4]; - unsigned int save_vr20[4]; - unsigned int save_vr21[4]; - unsigned int save_vr22[4]; - unsigned int save_vr23[4]; - unsigned int save_vr24[4]; - unsigned int save_vr25[4]; - unsigned int save_vr26[4]; - unsigned int save_vr27[4]; - unsigned int save_vr28[4]; - unsigned int save_vr29[4]; - unsigned int save_vr30[4]; - unsigned int save_vr31[4]; - unsigned int save_vscr[4]; /* Note that this is always valid if VMX has been used */ - unsigned int save_pad5[4]; /* Insures that vrvalid is on a cache line */ - unsigned int save_vrvalid; /* VRs that have been saved */ - unsigned int save_pad6[7]; - -/* The following is the save area for the segment registers */ - -/* offset 0x0440 */ - - unsigned int save_sr0; - unsigned int save_sr1; - unsigned int save_sr2; - unsigned int save_sr3; - unsigned int save_sr4; - unsigned int save_sr5; - unsigned int save_sr6; - unsigned int save_sr7; - - unsigned int save_sr8; - unsigned int save_sr9; - unsigned int save_sr10; - unsigned int save_sr11; - unsigned int save_sr12; - unsigned int save_sr13; - unsigned int save_sr14; - unsigned int save_sr15; - -/* The following are the control area for this save area */ - -/* offset 0x0480 */ - - struct savearea *save_prev; /* The address of the previous normal savearea */ - struct savearea *save_prev_float; /* The address of the previous floating point savearea */ - struct savearea *save_prev_vector; /* The address of the previous vector savearea */ - struct savearea *save_qfret; /* The "quick release" chain */ - struct savearea *save_phys; /* The physical address of this savearea */ - struct thread_activation *save_act; /* Pointer to the associated activation */ - unsigned int save_flags; /* Various flags */ -#define save_perm 0x80000000 /* Permanent area, cannot be released */ - unsigned int save_level_fp; /* Level that floating point state belongs to */ - unsigned int save_level_vec; /* Level that vector state belongs to */ - -} savearea; - -typedef struct savectl { /* Savearea control */ - - unsigned int *sac_next; /* Points to next savearea page that has a free slot - real */ - unsigned int sac_vrswap; /* XOR mask to swap V to R or vice versa */ - unsigned int sac_alloc; /* Bitmap of allocated slots */ - unsigned int sac_flags; /* Various flags */ -} savectl; - -struct Saveanchor { - unsigned int savelock; /* Lock word for savearea manipulation */ - int savecount; /* The total number of save areas allocated */ - int saveinuse; /* Number of areas in use */ - int savemin; /* We abend if lower than this */ - int saveneghyst; /* The negative hysteresis value */ - int savetarget; /* The target point for free save areas */ - int saveposhyst; /* The positive hysteresis value */ - unsigned int savefree; /* Anchor for the freelist queue */ - /* Cache line (32-byte) boundary */ - int savextnd; /* Free list extention count */ - int saveneed; /* Number of savearea's needed. So far, we assume we need 3 per activation */ - int savemaxcount; - int savespare[5]; /* Spare */ -}; +extern struct per_proc_info per_proc_info[NCPUS]; extern char *trap_type[]; #endif /* ndef ASSEMBLER */ - -#define sac_empty 0xC0000000 /* Mask with all entries empty */ -#define sac_cnt 2 /* Number of entries per page */ -#define sac_busy 0x80000000 /* This page is busy - used during initial allocation */ -#define sac_perm 0x40000000 /* Page permanently assigned */ - -#define SAVattach 0x80000000 /* Savearea is attached to a thread */ -#define SAVfpuvalid 0x40000000 /* Savearea contains FPU context */ -#define SAVvmxvalid 0x20000000 /* Savearea contains VMX context */ -#define SAVinuse 0xE0000000 /* Save area is inuse */ -#define SAVrststk 0x00010000 /* Indicates that the current stack should be reset to empty */ -#define SAVsyscall 0x00020000 /* Indicates that the savearea is associated with a syscall */ -#define SAVredrive 0x00040000 /* Indicates that the low-level fault handler associated */ - /* with this savearea should be redriven */ +/* with this savearea should be redriven */ /* cpu_flags defs */ #define SIGPactive 0x8000 @@ -572,12 +357,6 @@ extern char *trap_type[]; #define loadMSR 0x7FF4 #define T_VECTOR_SIZE 4 /* function pointer size */ -#define InitialSaveMin 4 /* The initial value for the minimum number of saveareas */ -#define InitialNegHysteresis 5 /* The number off from target before we adjust upwards */ -#define InitialPosHysteresis 10 /* The number off from target before we adjust downwards */ -#define InitialSaveTarget 20 /* The number of saveareas for an initial target */ -#define InitialSaveAreas 20 /* The number of saveareas to allocate at boot */ -#define InitialSaveBloks (InitialSaveAreas+sac_cnt-1)/sac_cnt /* The number of savearea blocks to allocate at boot */ /* Hardware exceptions */ @@ -636,9 +415,12 @@ extern char *trap_type[]; #define failStack 1 #define failMapping 2 #define failContext 3 +#define failNoSavearea 4 +#define failSaveareaCorr 5 +#define failBadLiveContext 6 /* Always must be last - update failNames table in model_dep.c as well */ -#define failUnknown 4 +#define failUnknown 7 #ifndef ASSEMBLER diff --git a/osfmk/ppc/genassym.c b/osfmk/ppc/genassym.c index 059d57174..54397dd3e 100644 --- a/osfmk/ppc/genassym.c +++ b/osfmk/ppc/genassym.c @@ -78,112 +78,36 @@ int main(int argc, char *argv[]) { /* Process Control Block */ - DECLARE("PCB_FLOAT_STATE", offsetof(struct pcb *, fs)); - - /* Floating point state */ - - DECLARE("PCB_FS_F0", offsetof(struct pcb *, fs.fpregs[0])); - DECLARE("PCB_FS_F1", offsetof(struct pcb *, fs.fpregs[1])); - DECLARE("PCB_FS_F2", offsetof(struct pcb *, fs.fpregs[2])); - DECLARE("PCB_FS_F3", offsetof(struct pcb *, fs.fpregs[3])); - DECLARE("PCB_FS_F4", offsetof(struct pcb *, fs.fpregs[4])); - DECLARE("PCB_FS_F5", offsetof(struct pcb *, fs.fpregs[5])); - DECLARE("PCB_FS_F6", offsetof(struct pcb *, fs.fpregs[6])); - DECLARE("PCB_FS_F7", offsetof(struct pcb *, fs.fpregs[7])); - DECLARE("PCB_FS_F8", offsetof(struct pcb *, fs.fpregs[8])); - DECLARE("PCB_FS_F9", offsetof(struct pcb *, fs.fpregs[9])); - DECLARE("PCB_FS_F10", offsetof(struct pcb *, fs.fpregs[10])); - DECLARE("PCB_FS_F11", offsetof(struct pcb *, fs.fpregs[11])); - DECLARE("PCB_FS_F12", offsetof(struct pcb *, fs.fpregs[12])); - DECLARE("PCB_FS_F13", offsetof(struct pcb *, fs.fpregs[13])); - DECLARE("PCB_FS_F14", offsetof(struct pcb *, fs.fpregs[14])); - DECLARE("PCB_FS_F15", offsetof(struct pcb *, fs.fpregs[15])); - DECLARE("PCB_FS_F16", offsetof(struct pcb *, fs.fpregs[16])); - DECLARE("PCB_FS_F17", offsetof(struct pcb *, fs.fpregs[17])); - DECLARE("PCB_FS_F18", offsetof(struct pcb *, fs.fpregs[18])); - DECLARE("PCB_FS_F19", offsetof(struct pcb *, fs.fpregs[19])); - DECLARE("PCB_FS_F20", offsetof(struct pcb *, fs.fpregs[20])); - DECLARE("PCB_FS_F21", offsetof(struct pcb *, fs.fpregs[21])); - DECLARE("PCB_FS_F22", offsetof(struct pcb *, fs.fpregs[22])); - DECLARE("PCB_FS_F23", offsetof(struct pcb *, fs.fpregs[23])); - DECLARE("PCB_FS_F24", offsetof(struct pcb *, fs.fpregs[24])); - DECLARE("PCB_FS_F25", offsetof(struct pcb *, fs.fpregs[25])); - DECLARE("PCB_FS_F26", offsetof(struct pcb *, fs.fpregs[26])); - DECLARE("PCB_FS_F27", offsetof(struct pcb *, fs.fpregs[27])); - DECLARE("PCB_FS_F28", offsetof(struct pcb *, fs.fpregs[28])); - DECLARE("PCB_FS_F29", offsetof(struct pcb *, fs.fpregs[29])); - DECLARE("PCB_FS_F30", offsetof(struct pcb *, fs.fpregs[30])); - DECLARE("PCB_FS_F31", offsetof(struct pcb *, fs.fpregs[31])); - DECLARE("PCB_FS_FPSCR", offsetof(struct pcb *, fs.fpscr_pad)); - - DECLARE("PCB_SAVED_STATE",offsetof(struct pcb *, ss)); DECLARE("ACT_MACT_KSP", offsetof(struct thread_activation *, mact.ksp)); DECLARE("ACT_MACT_BEDA", offsetof(struct thread_activation *, mact.bbDescAddr)); DECLARE("ACT_MACT_BTS", offsetof(struct thread_activation *, mact.bbTableStart)); DECLARE("ACT_MACT_BTE", offsetof(struct thread_activation *, mact.bbTaskEnv)); DECLARE("ACT_MACT_SPF", offsetof(struct thread_activation *, mact.specFlags)); DECLARE("qactTimer", offsetof(struct thread_activation *, mact.qactTimer)); + DECLARE("floatUsed", floatUsed); DECLARE("vectorUsed", vectorUsed); - DECLARE("bbNoMachSCbit",bbNoMachSCbit); DECLARE("runningVM", runningVM); + DECLARE("runningVMbit", runningVMbit); DECLARE("floatCng", floatCng); - DECLARE("vectorCng", vectorCng); DECLARE("floatCngbit", floatCngbit); + DECLARE("vectorCng", vectorCng); DECLARE("vectorCngbit", vectorCngbit); - DECLARE("bbThreadbit", bbThreadbit); - DECLARE("bbPreemptivebit", bbPreemptivebit); + DECLARE("userProtKey", userProtKey); + DECLARE("userProtKeybit", userProtKeybit); + DECLARE("trapUnalign", trapUnalign); + DECLARE("trapUnalignbit", trapUnalignbit); + DECLARE("notifyUnalign", notifyUnalign); + DECLARE("notifyUnalignbit", notifyUnalignbit); + DECLARE("bbThread", bbThread); + DECLARE("bbThreadbit", bbThreadbit); + DECLARE("bbNoMachSCbit",bbNoMachSCbit); DECLARE("bbPreemptive", bbPreemptive); + DECLARE("bbPreemptivebit", bbPreemptivebit); + DECLARE("fvChkb", fvChkb); DECLARE("fvChk", fvChk); - DECLARE("userProtKeybit", userProtKeybit); - DECLARE("userProtKey", userProtKey); - - DECLARE("PCB_SIZE", sizeof(struct pcb)); - - /* Save State Structure */ - DECLARE("SS_R0", offsetof(struct ppc_saved_state *, r0)); - DECLARE("SS_R1", offsetof(struct ppc_saved_state *, r1)); - DECLARE("SS_R2", offsetof(struct ppc_saved_state *, r2)); - DECLARE("SS_R3", offsetof(struct ppc_saved_state *, r3)); - DECLARE("SS_R4", offsetof(struct ppc_saved_state *, r4)); - DECLARE("SS_R5", offsetof(struct ppc_saved_state *, r5)); - DECLARE("SS_R6", offsetof(struct ppc_saved_state *, r6)); - DECLARE("SS_R7", offsetof(struct ppc_saved_state *, r7)); - DECLARE("SS_R8", offsetof(struct ppc_saved_state *, r8)); - DECLARE("SS_R9", offsetof(struct ppc_saved_state *, r9)); - DECLARE("SS_R10", offsetof(struct ppc_saved_state *, r10)); - DECLARE("SS_R11", offsetof(struct ppc_saved_state *, r11)); - DECLARE("SS_R12", offsetof(struct ppc_saved_state *, r12)); - DECLARE("SS_R13", offsetof(struct ppc_saved_state *, r13)); - DECLARE("SS_R14", offsetof(struct ppc_saved_state *, r14)); - DECLARE("SS_R15", offsetof(struct ppc_saved_state *, r15)); - DECLARE("SS_R16", offsetof(struct ppc_saved_state *, r16)); - DECLARE("SS_R17", offsetof(struct ppc_saved_state *, r17)); - DECLARE("SS_R18", offsetof(struct ppc_saved_state *, r18)); - DECLARE("SS_R19", offsetof(struct ppc_saved_state *, r19)); - DECLARE("SS_R20", offsetof(struct ppc_saved_state *, r20)); - DECLARE("SS_R21", offsetof(struct ppc_saved_state *, r21)); - DECLARE("SS_R22", offsetof(struct ppc_saved_state *, r22)); - DECLARE("SS_R23", offsetof(struct ppc_saved_state *, r23)); - DECLARE("SS_R24", offsetof(struct ppc_saved_state *, r24)); - DECLARE("SS_R25", offsetof(struct ppc_saved_state *, r25)); - DECLARE("SS_R26", offsetof(struct ppc_saved_state *, r26)); - DECLARE("SS_R27", offsetof(struct ppc_saved_state *, r27)); - DECLARE("SS_R28", offsetof(struct ppc_saved_state *, r28)); - DECLARE("SS_R29", offsetof(struct ppc_saved_state *, r29)); - DECLARE("SS_R30", offsetof(struct ppc_saved_state *, r30)); - DECLARE("SS_R31", offsetof(struct ppc_saved_state *, r31)); - DECLARE("SS_CR", offsetof(struct ppc_saved_state *, cr)); - DECLARE("SS_XER", offsetof(struct ppc_saved_state *, xer)); - DECLARE("SS_LR", offsetof(struct ppc_saved_state *, lr)); - DECLARE("SS_CTR", offsetof(struct ppc_saved_state *, ctr)); - DECLARE("SS_SRR0", offsetof(struct ppc_saved_state *, srr0)); - DECLARE("SS_SRR1", offsetof(struct ppc_saved_state *, srr1)); - DECLARE("SS_MQ", offsetof(struct ppc_saved_state *, mq)); - DECLARE("SS_SR_COPYIN", offsetof(struct ppc_saved_state *, sr_copyin)); - DECLARE("SS_SIZE", sizeof(struct ppc_saved_state)); /* Per Proc info structure */ DECLARE("PP_CPU_NUMBER", offsetof(struct per_proc_info *, cpu_number)); @@ -196,23 +120,25 @@ int main(int argc, char *argv[]) DECLARE("PP_USERSPACE", offsetof(struct per_proc_info *, userspace)); DECLARE("PP_USERPMAP", offsetof(struct per_proc_info *, userpmap)); DECLARE("PP_LASTPMAP", offsetof(struct per_proc_info *, Lastpmap)); - DECLARE("savedSave", offsetof(struct per_proc_info *, savedSave)); + DECLARE("FPUowner", offsetof(struct per_proc_info *, FPU_owner)); + DECLARE("VMXowner", offsetof(struct per_proc_info *, VMX_owner)); DECLARE("PP_SAVE_EXCEPTION_TYPE", offsetof(struct per_proc_info *, save_exception_type)); - DECLARE("PP_CPU_DATA", offsetof(struct per_proc_info *, cpu_data)); DECLARE("PP_ACTIVE_KLOADED", offsetof(struct per_proc_info *, active_kloaded)); DECLARE("PP_ACTIVE_STACKS", offsetof(struct per_proc_info *, active_stacks)); DECLARE("PP_NEED_AST", offsetof(struct per_proc_info *, need_ast)); - DECLARE("PP_FPU_THREAD", offsetof(struct per_proc_info *, FPU_thread)); - DECLARE("FPU_vmmCtx", offsetof(struct per_proc_info *, FPU_vmmCtx)); - DECLARE("PP_VMX_THREAD", offsetof(struct per_proc_info *, VMX_thread)); - DECLARE("VMX_vmmCtx", offsetof(struct per_proc_info *, VMX_vmmCtx)); - DECLARE("PP_QUICKFRET", offsetof(struct per_proc_info *, quickfret)); + DECLARE("quickfret", offsetof(struct per_proc_info *, quickfret)); + DECLARE("lclfree", offsetof(struct per_proc_info *, lclfree)); + DECLARE("lclfreecnt", offsetof(struct per_proc_info *, lclfreecnt)); DECLARE("PP_INTS_ENABLED", offsetof(struct per_proc_info *, interrupts_enabled)); DECLARE("UAW", offsetof(struct per_proc_info *, Uassist)); + DECLARE("next_savearea", offsetof(struct per_proc_info *, next_savearea)); + DECLARE("PP_ACTIVE_THREAD", offsetof(struct per_proc_info *, pp_active_thread)); + DECLARE("PP_PREEMPT_CNT", offsetof(struct per_proc_info *, pp_preemption_count)); + DECLARE("PP_SIMPLE_LOCK_CNT", offsetof(struct per_proc_info *, pp_simple_lock_count)); + DECLARE("PP_INTERRUPT_LVL", offsetof(struct per_proc_info *, pp_interrupt_level)); DECLARE("ppbbTaskEnv", offsetof(struct per_proc_info *, ppbbTaskEnv)); DECLARE("liveVRS", offsetof(struct per_proc_info *, liveVRSave)); - DECLARE("liveFPSCR", offsetof(struct per_proc_info *, liveFPSCR)); DECLARE("spcFlags", offsetof(struct per_proc_info *, spcFlags)); DECLARE("spcTRc", offsetof(struct per_proc_info *, spcTRc)); DECLARE("spcTRp", offsetof(struct per_proc_info *, spcTRp)); @@ -242,6 +168,8 @@ int main(int argc, char *argv[]) DECLARE("pfWillNapb", pfWillNapb); DECLARE("pfNoMSRir", pfNoMSRir); DECLARE("pfNoMSRirb", pfNoMSRirb); + DECLARE("pfNoL2PFNap", pfNoL2PFNap); + DECLARE("pfNoL2PFNapb", pfNoL2PFNapb); DECLARE("pfSlowNap", pfSlowNap); DECLARE("pfSlowNapb", pfSlowNapb); DECLARE("pfNoMuMMCK", pfNoMuMMCK); @@ -249,7 +177,7 @@ int main(int argc, char *argv[]) DECLARE("pfLClck", pfLClck); DECLARE("pfLClckb", pfLClckb); DECLARE("pfL3pdet", pfL3pdet); - DECLARE("pfL3pdetb", pfL3pdetb); + DECLARE("pfL3pdetb", pfL3pdetb); DECLARE("pfL1i", pfL1i); DECLARE("pfL1ib", pfL1ib); DECLARE("pfL1d", pfL1d); @@ -282,12 +210,12 @@ int main(int argc, char *argv[]) DECLARE("pfHID3", offsetof(struct per_proc_info *, pf.pfHID3)); DECLARE("pfMSSCR0", offsetof(struct per_proc_info *, pf.pfMSSCR0)); DECLARE("pfMSSCR1", offsetof(struct per_proc_info *, pf.pfMSSCR1)); - DECLARE("pfICTRL", offsetof(struct per_proc_info *, pf.pfICTRL)); + DECLARE("pfICTRL", offsetof(struct per_proc_info *, pf.pfICTRL)); DECLARE("pfLDSTCR", offsetof(struct per_proc_info *, pf.pfLDSTCR)); DECLARE("pfLDSTDB", offsetof(struct per_proc_info *, pf.pfLDSTDB)); DECLARE("pfl2crOriginal", offsetof(struct per_proc_info *, pf.l2crOriginal)); DECLARE("pfl3crOriginal", offsetof(struct per_proc_info *, pf.l3crOriginal)); - DECLARE("pfBootConfig", offsetof(struct per_proc_info *, pf.pfBootConfig)); + DECLARE("pfBootConfig", offsetof(struct per_proc_info *, pf.pfBootConfig)); DECLARE("pfSize", sizeof(procFeatures)); DECLARE("thrmmaxTemp", offsetof(struct per_proc_info *, thrm.maxTemp)); @@ -371,9 +299,9 @@ int main(int argc, char *argv[]) DECLARE("ppSize", sizeof(struct per_proc_info)); DECLARE("patcharea", offsetof(struct per_proc_info *, patcharea)); - DECLARE("RESETHANDLER_TYPE", offsetof(struct resethandler *, type)); - DECLARE("RESETHANDLER_CALL", offsetof(struct resethandler *, call_paddr)); - DECLARE("RESETHANDLER_ARG", offsetof(struct resethandler *, arg__paddr)); + DECLARE("RESETHANDLER_TYPE", offsetof(struct resethandler *, type)); + DECLARE("RESETHANDLER_CALL", offsetof(struct resethandler *, call_paddr)); + DECLARE("RESETHANDLER_ARG", offsetof(struct resethandler *, arg__paddr)); /* we want offset from * bottom of kernel stack, not offset into structure @@ -381,50 +309,49 @@ int main(int argc, char *argv[]) #define IKSBASE (u_int)STACK_IKS(0) /* values from kern/thread.h */ - DECLARE("THREAD_TOP_ACT", - offsetof(struct thread_shuttle *, top_act)); - DECLARE("THREAD_KERNEL_STACK", - offsetof(struct thread_shuttle *, kernel_stack)); - DECLARE("THREAD_CONTINUATION", - offsetof(struct thread_shuttle *, continuation)); - DECLARE("THREAD_RECOVER", - offsetof(struct thread_shuttle *, recover)); + DECLARE("THREAD_TOP_ACT", offsetof(struct thread_shuttle *, top_act)); + DECLARE("THREAD_KERNEL_STACK", offsetof(struct thread_shuttle *, kernel_stack)); + DECLARE("THREAD_CONTINUATION", offsetof(struct thread_shuttle *, continuation)); + DECLARE("THREAD_RECOVER", offsetof(struct thread_shuttle *, recover)); + DECLARE("THREAD_FUNNEL_LOCK", + offsetof(struct thread_shuttle *, funnel_lock)); + DECLARE("THREAD_FUNNEL_STATE", + offsetof(struct thread_shuttle *, funnel_state)); + DECLARE("LOCK_FNL_MUTEX", + offsetof(struct funnel_lock *, fnl_mutex)); #if MACH_LDEBUG - DECLARE("THREAD_MUTEX_COUNT", - offsetof(struct thread_shuttle *, mutex_count)); + DECLARE("THREAD_MUTEX_COUNT", offsetof(struct thread_shuttle *, mutex_count)); #endif /* MACH_LDEBUG */ - DECLARE("THREAD_PSET", offsetof(struct thread_shuttle *, processor_set)); - DECLARE("THREAD_LINKS", offsetof(struct thread_shuttle *, links)); - DECLARE("THREAD_PSTHRN", offsetof(struct thread_shuttle *, pset_threads.next)); + DECLARE("THREAD_PSET", offsetof(struct thread_shuttle *, processor_set)); + DECLARE("THREAD_LINKS", offsetof(struct thread_shuttle *, links)); + DECLARE("THREAD_PSTHRN", offsetof(struct thread_shuttle *, pset_threads.next)); /* values from kern/thread_act.h */ - DECLARE("ACT_TASK", offsetof(struct thread_activation *, task)); - DECLARE("ACT_THREAD", offsetof(struct thread_activation *, thread)); - DECLARE("ACT_LOWER", offsetof(struct thread_activation *, lower)); - DECLARE("ACT_MACT_PCB",offsetof(struct thread_activation *, mact.pcb)); - DECLARE("ACT_MACT_FPU",offsetof(struct thread_activation *, mact.FPU_pcb)); - DECLARE("ACT_MACT_FPUlvl",offsetof(struct thread_activation *, mact.FPU_lvl)); - DECLARE("ACT_MACT_FPUcpu",offsetof(struct thread_activation *, mact.FPU_cpu)); - DECLARE("ACT_MACT_VMX",offsetof(struct thread_activation *, mact.VMX_pcb)); - DECLARE("ACT_MACT_VMXlvl",offsetof(struct thread_activation *, mact.VMX_lvl)); - DECLARE("ACT_MACT_VMXcpu",offsetof(struct thread_activation *, mact.VMX_cpu)); - DECLARE("ACT_AST", offsetof(struct thread_activation *, ast)); - DECLARE("ACT_VMMAP", offsetof(struct thread_activation *, map)); - DECLARE("runningVM", runningVM); - DECLARE("runningVMbit", runningVMbit); - DECLARE("ACT_KLOADED", - offsetof(struct thread_activation *, kernel_loaded)); - DECLARE("ACT_KLOADING", - offsetof(struct thread_activation *, kernel_loading)); - DECLARE("ACT_MACH_EXC_PORT", - offsetof(struct thread_activation *, - exc_actions[EXC_MACH_SYSCALL].port)); - DECLARE("vmmCEntry", offsetof(struct thread_activation *, mact.vmmCEntry)); - DECLARE("vmmControl", offsetof(struct thread_activation *, mact.vmmControl)); + DECLARE("ACT_TASK", offsetof(struct thread_activation *, task)); + DECLARE("ACT_THREAD", offsetof(struct thread_activation *, thread)); + DECLARE("ACT_LOWER", offsetof(struct thread_activation *, lower)); + DECLARE("ACT_MACT_PCB", offsetof(struct thread_activation *, mact.pcb)); + DECLARE("ACT_AST", offsetof(struct thread_activation *, ast)); + DECLARE("ACT_VMMAP", offsetof(struct thread_activation *, map)); + DECLARE("ACT_KLOADED", offsetof(struct thread_activation *, kernel_loaded)); + DECLARE("ACT_KLOADING", offsetof(struct thread_activation *, kernel_loading)); + DECLARE("vmmCEntry", offsetof(struct thread_activation *, mact.vmmCEntry)); + DECLARE("vmmControl", offsetof(struct thread_activation *, mact.vmmControl)); + DECLARE("curctx", offsetof(struct thread_activation *, mact.curctx)); + DECLARE("deferctx", offsetof(struct thread_activation *, mact.deferctx)); + DECLARE("facctx", offsetof(struct thread_activation *, mact.facctx)); #ifdef MACH_BSD - DECLARE("CTHREAD_SELF", offsetof(struct thread_activation *, mact.cthread_self)); + DECLARE("CTHREAD_SELF", offsetof(struct thread_activation *, mact.cthread_self)); #endif + DECLARE("FPUsave", offsetof(struct facility_context *,FPUsave)); + DECLARE("FPUlevel", offsetof(struct facility_context *,FPUlevel)); + DECLARE("FPUcpu", offsetof(struct facility_context *,FPUcpu)); + DECLARE("VMXsave", offsetof(struct facility_context *,VMXsave)); + DECLARE("VMXlevel", offsetof(struct facility_context *,VMXlevel)); + DECLARE("VMXcpu", offsetof(struct facility_context *,VMXcpu)); + DECLARE("facAct", offsetof(struct facility_context *,facAct)); + /* Values from vmachmon.h */ DECLARE("kVmmGetVersion", kVmmGetVersion); @@ -465,10 +392,7 @@ int main(int argc, char *argv[]) DECLARE("vmmPmap", offsetof(struct vmmCntrlEntry *, vmmPmap)); DECLARE("vmmContextKern", offsetof(struct vmmCntrlEntry *, vmmContextKern)); DECLARE("vmmContextUser", offsetof(struct vmmCntrlEntry *, vmmContextUser)); - DECLARE("vmmFPU_pcb", offsetof(struct vmmCntrlEntry *, vmmFPU_pcb)); - DECLARE("vmmFPU_cpu", offsetof(struct vmmCntrlEntry *, vmmFPU_cpu)); - DECLARE("vmmVMX_pcb", offsetof(struct vmmCntrlEntry *, vmmVMX_pcb)); - DECLARE("vmmVMX_cpu", offsetof(struct vmmCntrlEntry *, vmmVMX_cpu)); + DECLARE("vmmFacCtx", offsetof(struct vmmCntrlEntry *, vmmFacCtx)); DECLARE("vmmLastMap", offsetof(struct vmmCntrlEntry *, vmmLastMap)); DECLARE("vmmCEntrySize", sizeof(struct vmmCntrlEntry)); DECLARE("kVmmMaxContextsPerThread", kVmmMaxContextsPerThread); @@ -483,8 +407,60 @@ int main(int argc, char *argv[]) DECLARE("return_params", offsetof(struct vmm_state_page_t *, return_params)); DECLARE("vmmppcVRs", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcVRs)); DECLARE("vmmppcVSCR", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcVSCR)); + DECLARE("vmmppcVSCRshadow", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcVSCRshadow)); DECLARE("vmmppcFPRs", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcFPRs)); DECLARE("vmmppcFPSCR", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcFPSCR)); + DECLARE("vmmppcFPSCRshadow", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcFPSCRshadow)); + + DECLARE("vmmppcpc", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcPC)); + DECLARE("vmmppcmsr", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcMSR)); + DECLARE("vmmppcr0", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x00)); + DECLARE("vmmppcr1", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x04)); + DECLARE("vmmppcr2", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x08)); + DECLARE("vmmppcr3", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x0C)); + DECLARE("vmmppcr4", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x10)); + DECLARE("vmmppcr5", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x14)); + + DECLARE("vmmppcr6", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x18)); + DECLARE("vmmppcr7", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x1C)); + DECLARE("vmmppcr8", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x20)); + DECLARE("vmmppcr9", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x24)); + DECLARE("vmmppcr10", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x28)); + DECLARE("vmmppcr11", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x2C)); + DECLARE("vmmppcr12", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x30)); + DECLARE("vmmppcr13", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x34)); + + DECLARE("vmmppcr14", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x38)); + DECLARE("vmmppcr15", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x3C)); + DECLARE("vmmppcr16", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x40)); + DECLARE("vmmppcr17", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x44)); + DECLARE("vmmppcr18", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x48)); + DECLARE("vmmppcr19", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x4C)); + DECLARE("vmmppcr20", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x50)); + DECLARE("vmmppcr21", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x54)); + + DECLARE("vmmppcr22", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x58)); + DECLARE("vmmppcr23", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x5C)); + DECLARE("vmmppcr24", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x60)); + DECLARE("vmmppcr25", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x64)); + DECLARE("vmmppcr26", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x68)); + DECLARE("vmmppcr27", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x6C)); + DECLARE("vmmppcr28", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x70)); + DECLARE("vmmppcr29", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x74)); + + DECLARE("vmmppcr30", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x78)); + DECLARE("vmmppcr31", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcGPRs+0x7C)); + DECLARE("vmmppccr", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcCR)); + DECLARE("vmmppcxer", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcXER)); + DECLARE("vmmppclr", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcLR)); + DECLARE("vmmppcctr", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcCTR)); + DECLARE("vmmppcmq", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcMQ)); + DECLARE("vmmppcvrsave", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcVRSave)); + + DECLARE("vmmppcvscr", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcVSCR+0x00)); + DECLARE("vmmppcfpscrpad", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcFPSCR)); + DECLARE("vmmppcfpscr", offsetof(struct vmm_state_page_t *, vmm_proc_state.ppcFPSCR+4)); + DECLARE("vmmFloatCngd", vmmFloatCngd); DECLARE("vmmFloatCngdb", vmmFloatCngdb); DECLARE("vmmVectCngd", vmmVectCngd); @@ -511,10 +487,10 @@ int main(int argc, char *argv[]) DECLARE("vmmKeyb", vmmKeyb); /* values from kern/task.h */ - DECLARE("TASK_MACH_EXC_PORT", - offsetof(struct task *, exc_actions[EXC_MACH_SYSCALL].port)); DECLARE("TASK_SYSCALLS_MACH", offsetof(struct task *, syscalls_mach)); + DECLARE("TASK_SYSCALLS_UNIX", + offsetof(struct task *, syscalls_unix)); /* values from vm/vm_map.h */ DECLARE("VMMAP_PMAP", offsetof(struct vm_map *, pmap)); @@ -527,6 +503,10 @@ int main(int argc, char *argv[]) DECLARE("PMAP_USAGE", offsetof(struct pmap *, pmapUsage)); DECLARE("PMAP_SEGS", offsetof(struct pmap *, pmapSegs)); DECLARE("PMAP_SIZE", pmapSize); + + /* values from kern/processor.h */ + DECLARE("psthreads", offsetof(struct processor_set *, threads)); + DECLARE("psthreadcnt", offsetof(struct processor_set *, thread_count)); /* Constants from pmap.h */ @@ -556,89 +536,26 @@ int main(int argc, char *argv[]) DECLARE("AST_URGENT", AST_URGENT); /* Simple Lock structure */ - DECLARE("SLOCK_ILK", offsetof(simple_lock_t, interlock)); + DECLARE("SLOCK_ILK", offsetof(usimple_lock_t, interlock)); #if MACH_LDEBUG - DECLARE("SLOCK_TYPE", offsetof(simple_lock_t, lock_type)); - DECLARE("SLOCK_PC", offsetof(simple_lock_t, debug.lock_pc)); - DECLARE("SLOCK_THREAD", offsetof(simple_lock_t, debug.lock_thread)); - DECLARE("SLOCK_DURATIONH",offsetof(simple_lock_t, debug.duration[0])); - DECLARE("SLOCK_DURATIONL",offsetof(simple_lock_t, debug.duration[1])); + DECLARE("SLOCK_TYPE", offsetof(usimple_lock_t, lock_type)); + DECLARE("SLOCK_PC", offsetof(usimple_lock_t, debug.lock_pc)); + DECLARE("SLOCK_THREAD", offsetof(usimple_lock_t, debug.lock_thread)); + DECLARE("SLOCK_DURATIONH",offsetof(usimple_lock_t, debug.duration[0])); + DECLARE("SLOCK_DURATIONL",offsetof(usimple_lock_t, debug.duration[1])); DECLARE("USLOCK_TAG", USLOCK_TAG); #endif /* MACH_LDEBUG */ /* Mutex structure */ DECLARE("LOCK_DATA", offsetof(mutex_t *, interlock)); DECLARE("MUTEX_WAITERS",offsetof(mutex_t *, waiters)); + DECLARE("MUTEX_PROMOTED_PRI",offsetof(mutex_t *, promoted_pri)); #if MACH_LDEBUG DECLARE("MUTEX_TYPE", offsetof(mutex_t *, type)); DECLARE("MUTEX_PC", offsetof(mutex_t *, pc)); DECLARE("MUTEX_THREAD", offsetof(mutex_t *, thread)); DECLARE("MUTEX_TAG", MUTEX_TAG); #endif /* MACH_LDEBUG */ - -#if NCPUS > 1 - /* values from mp/PlugIn.h */ - - DECLARE("MPSversionID", offsetof(struct MPPlugInSpec *, versionID)); - DECLARE("MPSareaAddr", offsetof(struct MPPlugInSpec *, areaAddr)); - DECLARE("MPSareaSize", offsetof(struct MPPlugInSpec *, areaSize)); - DECLARE("MPSoffsetTableAddr", offsetof(struct MPPlugInSpec *, offsetTableAddr)); - DECLARE("MPSbaseAddr", offsetof(struct MPPlugInSpec *, baseAddr)); - DECLARE("MPSdataArea", offsetof(struct MPPlugInSpec *, dataArea)); - DECLARE("MPSCPUArea", offsetof(struct MPPlugInSpec *, CPUArea)); - DECLARE("MPSSIGPhandler", offsetof(struct MPPlugInSpec *, SIGPhandler)); - - DECLARE("CSAstate", offsetof(struct CPUStatusArea *, state)); - DECLARE("CSAregsAreValid", offsetof(struct CPUStatusArea *, - regsAreValid)); - DECLARE("CSAgpr", offsetof(struct CPUStatusArea *, gpr)); - DECLARE("CSAfpr", offsetof(struct CPUStatusArea *, fpr)); - DECLARE("CSAcr", offsetof(struct CPUStatusArea *, cr)); - DECLARE("CSAfpscr", offsetof(struct CPUStatusArea *, fpscr)); - DECLARE("CSAxer", offsetof(struct CPUStatusArea *, xer)); - DECLARE("CSAlr", offsetof(struct CPUStatusArea *, lr)); - DECLARE("CSActr", offsetof(struct CPUStatusArea *, ctr)); - DECLARE("CSAtbu", offsetof(struct CPUStatusArea *, tbu)); - DECLARE("CSAtbl", offsetof(struct CPUStatusArea *, tbl)); - DECLARE("CSApvr", offsetof(struct CPUStatusArea *, pvr)); - DECLARE("CSAibat", offsetof(struct CPUStatusArea *, ibat)); - DECLARE("CSAdbat", offsetof(struct CPUStatusArea *, dbat)); - DECLARE("CSAsdr1", offsetof(struct CPUStatusArea *, sdr1)); - DECLARE("CSAsr", offsetof(struct CPUStatusArea *, sr)); - DECLARE("CSAdar", offsetof(struct CPUStatusArea *, dar)); - DECLARE("CSAdsisr", offsetof(struct CPUStatusArea *, dsisr)); - DECLARE("CSAsprg", offsetof(struct CPUStatusArea *, sprg)); - DECLARE("CSAsrr0", offsetof(struct CPUStatusArea *, srr0)); - DECLARE("CSAsrr1", offsetof(struct CPUStatusArea *, srr1)); - DECLARE("CSAdec", offsetof(struct CPUStatusArea *, dec)); - DECLARE("CSAdabr", offsetof(struct CPUStatusArea *, dabr)); - DECLARE("CSAiabr", offsetof(struct CPUStatusArea *, iabr)); - DECLARE("CSAear", offsetof(struct CPUStatusArea *, ear)); - DECLARE("CSAhid", offsetof(struct CPUStatusArea *, hid)); - DECLARE("CSAmmcr", offsetof(struct CPUStatusArea *, mmcr)); - DECLARE("CSApmc", offsetof(struct CPUStatusArea *, pmc)); - DECLARE("CSApir", offsetof(struct CPUStatusArea *, pir)); - DECLARE("CSAsda", offsetof(struct CPUStatusArea *, sda)); - DECLARE("CSAsia", offsetof(struct CPUStatusArea *, sia)); - DECLARE("CSAmq", offsetof(struct CPUStatusArea *, mq)); - DECLARE("CSAmsr", offsetof(struct CPUStatusArea *, msr)); - DECLARE("CSApc", offsetof(struct CPUStatusArea *, pc)); - DECLARE("CSAsysregs", offsetof(struct CPUStatusArea *, sysregs)); - DECLARE("CSAsize", sizeof(struct CPUStatusArea)); - - - DECLARE("MPPICStat", offsetof(struct MPPInterface *, MPPICStat)); - DECLARE("MPPICParm0", offsetof(struct MPPInterface *, MPPICParm0)); - DECLARE("MPPICParm1", offsetof(struct MPPInterface *, MPPICParm1)); - DECLARE("MPPICParm2", offsetof(struct MPPInterface *, MPPICParm2)); - DECLARE("MPPICspare0", offsetof(struct MPPInterface *, MPPICspare0)); - DECLARE("MPPICspare1", offsetof(struct MPPInterface *, MPPICspare1)); - DECLARE("MPPICParm0BU", offsetof(struct MPPInterface *, MPPICParm0BU)); - DECLARE("MPPICPriv", offsetof(struct MPPInterface *, MPPICPriv)); - - - -#endif /* NCPUS > 1 */ /* values from low_trace.h */ DECLARE("LTR_cpu", offsetof(struct LowTraceRecord *, LTR_cpu)); @@ -677,11 +594,15 @@ int main(int argc, char *argv[]) DECLARE("bmnext", offsetof(struct blokmap *, next)); DECLARE("bmstart", offsetof(struct blokmap *, start)); DECLARE("bmend", offsetof(struct blokmap *, end)); + DECLARE("bmcurrent", offsetof(struct blokmap *, current)); DECLARE("bmPTEr", offsetof(struct blokmap *, PTEr)); DECLARE("bmspace", offsetof(struct blokmap *, space)); DECLARE("blkFlags", offsetof(struct blokmap *, blkFlags)); DECLARE("blkPerm", blkPerm); + DECLARE("blkRem", blkRem); DECLARE("blkPermbit", blkPermbit); + DECLARE("blkRembit", blkRembit); + DECLARE("BLKREMMAX", BLKREMMAX); DECLARE("mbvrswap", offsetof(struct mappingblok *, mapblokvrswap)); DECLARE("mbfree", offsetof(struct mappingblok *, mapblokfree)); @@ -699,14 +620,19 @@ int main(int argc, char *argv[]) DECLARE("PCAgas", offsetof(struct PCA *, PCAgas)); DECLARE("PCAhash", offsetof(struct PCA *, PCAhash)); + DECLARE("MFpcaptr", offsetof(struct mappingflush *, pcaptr)); + DECLARE("MFmappingcnt", offsetof(struct mappingflush *, mappingcnt)); + DECLARE("MFmapping", offsetof(struct mappingflush *, mapping)); + DECLARE("MFmappingSize", sizeof(struct mfmapping)); + DECLARE("SVlock", offsetof(struct Saveanchor *, savelock)); - DECLARE("SVcount", offsetof(struct Saveanchor *, savecount)); + DECLARE("SVpoolfwd", offsetof(struct Saveanchor *, savepoolfwd)); + DECLARE("SVpoolbwd", offsetof(struct Saveanchor *, savepoolbwd)); + DECLARE("SVfree", offsetof(struct Saveanchor *, savefree)); + DECLARE("SVfreecnt", offsetof(struct Saveanchor *, savefreecnt)); + DECLARE("SVadjust", offsetof(struct Saveanchor *, saveadjust)); DECLARE("SVinuse", offsetof(struct Saveanchor *, saveinuse)); - DECLARE("SVmin", offsetof(struct Saveanchor *, savemin)); - DECLARE("SVneghyst", offsetof(struct Saveanchor *, saveneghyst)); DECLARE("SVtarget", offsetof(struct Saveanchor *, savetarget)); - DECLARE("SVposhyst", offsetof(struct Saveanchor *, saveposhyst)); - DECLARE("SVfree", offsetof(struct Saveanchor *, savefree)); DECLARE("SVsize", sizeof(struct Saveanchor)); #if 1 @@ -738,6 +664,8 @@ int main(int argc, char *argv[]) DECLARE("enaUsrPhyMpb", enaUsrPhyMpb); DECLARE("enaDiagSCs", enaDiagSCs); DECLARE("enaDiagSCsb", enaDiagSCsb); + DECLARE("enaDiagEM", enaDiagEM); + DECLARE("enaDiagEMb", enaDiagEMb); DECLARE("disLkType", disLkType); DECLARE("disLktypeb", disLktypeb); DECLARE("disLkThread", disLkThread); @@ -758,23 +686,35 @@ int main(int argc, char *argv[]) DECLARE("traceEnd", offsetof(struct traceWork *, traceEnd)); DECLARE("traceMsnd", offsetof(struct traceWork *, traceMsnd)); - DECLARE("SACsize", sizeof(struct savectl)); - DECLARE("SACspot", 4096-sizeof(struct savectl)); - DECLARE("SACnext", offsetof(struct savectl *, sac_next)+4096-sizeof(struct savectl)); - DECLARE("SACvrswap", offsetof(struct savectl *, sac_vrswap)+4096-sizeof(struct savectl)); - DECLARE("SACalloc", offsetof(struct savectl *, sac_alloc)+4096-sizeof(struct savectl)); - DECLARE("SACflags", offsetof(struct savectl *, sac_flags)+4096-sizeof(struct savectl)); - - DECLARE("SAVprev", offsetof(struct savearea *, save_prev)); - DECLARE("SAVprefp", offsetof(struct savearea *, save_prev_float)); - DECLARE("SAVprevec", offsetof(struct savearea *, save_prev_vector)); - DECLARE("SAVphys", offsetof(struct savearea *, save_phys)); - DECLARE("SAVqfret", offsetof(struct savearea *, save_qfret)); - DECLARE("SAVact", offsetof(struct savearea *, save_act)); - DECLARE("SAVflags", offsetof(struct savearea *, save_flags)); - DECLARE("SAVlvlfp", offsetof(struct savearea *, save_level_fp)); - DECLARE("SAVlvlvec", offsetof(struct savearea *, save_level_vec)); + DECLARE("SACnext", offsetof(struct savearea_comm *, sac_next)); + DECLARE("SACprev", offsetof(struct savearea_comm *, sac_prev)); + DECLARE("SACvrswap", offsetof(struct savearea_comm *, sac_vrswap)); + DECLARE("SACalloc", offsetof(struct savearea_comm *, sac_alloc)); + DECLARE("SACflags", offsetof(struct savearea_comm *, sac_flags)); + DECLARE("sac_cnt", sac_cnt); + DECLARE("sac_empty", sac_empty); + DECLARE("sac_perm", sac_perm); + DECLARE("sac_permb", sac_permb); + + DECLARE("LocalSaveTarget", LocalSaveTarget); + DECLARE("LocalSaveMin", LocalSaveMin); + DECLARE("LocalSaveMax", LocalSaveMax); + DECLARE("FreeListMin", FreeListMin); + DECLARE("SaveLowHysteresis", SaveLowHysteresis); + DECLARE("SaveHighHysteresis", SaveHighHysteresis); + DECLARE("InitialSaveAreas", InitialSaveAreas); + DECLARE("InitialSaveTarget", InitialSaveTarget); + DECLARE("InitialSaveBloks", InitialSaveBloks); + + DECLARE("SAVprev", offsetof(struct savearea_comm *, save_prev)); + DECLARE("SAVact", offsetof(struct savearea_comm *, save_act)); + DECLARE("SAVflags", offsetof(struct savearea_comm *, save_flags)); + DECLARE("SAVlevel", offsetof(struct savearea_comm *, save_level)); + DECLARE("SAVtime", offsetof(struct savearea_comm *, save_time)); DECLARE("SAVsize", sizeof(struct savearea)); + DECLARE("SAVsizefpu", sizeof(struct savearea_vec)); + DECLARE("SAVsizevec", sizeof(struct savearea_fpu)); + DECLARE("SAVcommsize", sizeof(struct savearea_comm)); DECLARE("savesrr0", offsetof(struct savearea *, save_srr0)); DECLARE("savesrr1", offsetof(struct savearea *, save_srr1)); @@ -782,14 +722,13 @@ int main(int argc, char *argv[]) DECLARE("savexer", offsetof(struct savearea *, save_xer)); DECLARE("savelr", offsetof(struct savearea *, save_lr)); DECLARE("savectr", offsetof(struct savearea *, save_ctr)); - DECLARE("savemq", offsetof(struct savearea *, save_mq)); - DECLARE("savecopyin", offsetof(struct savearea *, save_sr_copyin)); DECLARE("savedar", offsetof(struct savearea *, save_dar)); DECLARE("savedsisr", offsetof(struct savearea *, save_dsisr)); DECLARE("saveexception", offsetof(struct savearea *, save_exception)); - DECLARE("savexfpscrpad", offsetof(struct savearea *, save_xfpscrpad)); - DECLARE("savexfpscr", offsetof(struct savearea *, save_xfpscr)); + DECLARE("savefpscrpad", offsetof(struct savearea *, save_fpscrpad)); + DECLARE("savefpscr", offsetof(struct savearea *, save_fpscr)); DECLARE("savevrsave", offsetof(struct savearea *, save_vrsave)); + DECLARE("savevscr", offsetof(struct savearea *, save_vscr)); DECLARE("saver0", offsetof(struct savearea *, save_r0)); DECLARE("saver1", offsetof(struct savearea *, save_r1)); @@ -824,41 +763,6 @@ int main(int argc, char *argv[]) DECLARE("saver30", offsetof(struct savearea *, save_r30)); DECLARE("saver31", offsetof(struct savearea *, save_r31)); - DECLARE("savefp0", offsetof(struct savearea *, save_fp0)); - DECLARE("savefp1", offsetof(struct savearea *, save_fp1)); - DECLARE("savefp2", offsetof(struct savearea *, save_fp2)); - DECLARE("savefp3", offsetof(struct savearea *, save_fp3)); - DECLARE("savefp4", offsetof(struct savearea *, save_fp4)); - DECLARE("savefp5", offsetof(struct savearea *, save_fp5)); - DECLARE("savefp6", offsetof(struct savearea *, save_fp6)); - DECLARE("savefp7", offsetof(struct savearea *, save_fp7)); - DECLARE("savefp8", offsetof(struct savearea *, save_fp8)); - DECLARE("savefp9", offsetof(struct savearea *, save_fp9)); - DECLARE("savefp10", offsetof(struct savearea *, save_fp10)); - DECLARE("savefp11", offsetof(struct savearea *, save_fp11)); - DECLARE("savefp12", offsetof(struct savearea *, save_fp12)); - DECLARE("savefp13", offsetof(struct savearea *, save_fp13)); - DECLARE("savefp14", offsetof(struct savearea *, save_fp14)); - DECLARE("savefp15", offsetof(struct savearea *, save_fp15)); - DECLARE("savefp16", offsetof(struct savearea *, save_fp16)); - DECLARE("savefp17", offsetof(struct savearea *, save_fp17)); - DECLARE("savefp18", offsetof(struct savearea *, save_fp18)); - DECLARE("savefp19", offsetof(struct savearea *, save_fp19)); - DECLARE("savefp20", offsetof(struct savearea *, save_fp20)); - DECLARE("savefp21", offsetof(struct savearea *, save_fp21)); - DECLARE("savefp22", offsetof(struct savearea *, save_fp22)); - DECLARE("savefp23", offsetof(struct savearea *, save_fp23)); - DECLARE("savefp24", offsetof(struct savearea *, save_fp24)); - DECLARE("savefp25", offsetof(struct savearea *, save_fp25)); - DECLARE("savefp26", offsetof(struct savearea *, save_fp26)); - DECLARE("savefp27", offsetof(struct savearea *, save_fp27)); - DECLARE("savefp28", offsetof(struct savearea *, save_fp28)); - DECLARE("savefp29", offsetof(struct savearea *, save_fp29)); - DECLARE("savefp30", offsetof(struct savearea *, save_fp30)); - DECLARE("savefp31", offsetof(struct savearea *, save_fp31)); - DECLARE("savefpscrpad", offsetof(struct savearea *, save_fpscr_pad)); - DECLARE("savefpscr", offsetof(struct savearea *, save_fpscr)); - DECLARE("savesr0", offsetof(struct savearea *, save_sr0)); DECLARE("savesr1", offsetof(struct savearea *, save_sr1)); DECLARE("savesr2", offsetof(struct savearea *, save_sr2)); @@ -875,41 +779,73 @@ int main(int argc, char *argv[]) DECLARE("savesr13", offsetof(struct savearea *, save_sr13)); DECLARE("savesr14", offsetof(struct savearea *, save_sr14)); DECLARE("savesr15", offsetof(struct savearea *, save_sr15)); + + DECLARE("savefp0", offsetof(struct savearea_fpu *, save_fp0)); + DECLARE("savefp1", offsetof(struct savearea_fpu *, save_fp1)); + DECLARE("savefp2", offsetof(struct savearea_fpu *, save_fp2)); + DECLARE("savefp3", offsetof(struct savearea_fpu *, save_fp3)); + DECLARE("savefp4", offsetof(struct savearea_fpu *, save_fp4)); + DECLARE("savefp5", offsetof(struct savearea_fpu *, save_fp5)); + DECLARE("savefp6", offsetof(struct savearea_fpu *, save_fp6)); + DECLARE("savefp7", offsetof(struct savearea_fpu *, save_fp7)); + DECLARE("savefp8", offsetof(struct savearea_fpu *, save_fp8)); + DECLARE("savefp9", offsetof(struct savearea_fpu *, save_fp9)); + DECLARE("savefp10", offsetof(struct savearea_fpu *, save_fp10)); + DECLARE("savefp11", offsetof(struct savearea_fpu *, save_fp11)); + DECLARE("savefp12", offsetof(struct savearea_fpu *, save_fp12)); + DECLARE("savefp13", offsetof(struct savearea_fpu *, save_fp13)); + DECLARE("savefp14", offsetof(struct savearea_fpu *, save_fp14)); + DECLARE("savefp15", offsetof(struct savearea_fpu *, save_fp15)); + DECLARE("savefp16", offsetof(struct savearea_fpu *, save_fp16)); + DECLARE("savefp17", offsetof(struct savearea_fpu *, save_fp17)); + DECLARE("savefp18", offsetof(struct savearea_fpu *, save_fp18)); + DECLARE("savefp19", offsetof(struct savearea_fpu *, save_fp19)); + DECLARE("savefp20", offsetof(struct savearea_fpu *, save_fp20)); + DECLARE("savefp21", offsetof(struct savearea_fpu *, save_fp21)); + DECLARE("savefp22", offsetof(struct savearea_fpu *, save_fp22)); + DECLARE("savefp23", offsetof(struct savearea_fpu *, save_fp23)); + DECLARE("savefp24", offsetof(struct savearea_fpu *, save_fp24)); + DECLARE("savefp25", offsetof(struct savearea_fpu *, save_fp25)); + DECLARE("savefp26", offsetof(struct savearea_fpu *, save_fp26)); + DECLARE("savefp27", offsetof(struct savearea_fpu *, save_fp27)); + DECLARE("savefp28", offsetof(struct savearea_fpu *, save_fp28)); + DECLARE("savefp29", offsetof(struct savearea_fpu *, save_fp29)); + DECLARE("savefp30", offsetof(struct savearea_fpu *, save_fp30)); + DECLARE("savefp31", offsetof(struct savearea_fpu *, save_fp31)); - DECLARE("savevr0", offsetof(struct savearea *, save_vr0)); - DECLARE("savevr1", offsetof(struct savearea *, save_vr1)); - DECLARE("savevr2", offsetof(struct savearea *, save_vr2)); - DECLARE("savevr3", offsetof(struct savearea *, save_vr3)); - DECLARE("savevr4", offsetof(struct savearea *, save_vr4)); - DECLARE("savevr5", offsetof(struct savearea *, save_vr5)); - DECLARE("savevr6", offsetof(struct savearea *, save_vr6)); - DECLARE("savevr7", offsetof(struct savearea *, save_vr7)); - DECLARE("savevr8", offsetof(struct savearea *, save_vr8)); - DECLARE("savevr9", offsetof(struct savearea *, save_vr9)); - DECLARE("savevr10", offsetof(struct savearea *, save_vr10)); - DECLARE("savevr11", offsetof(struct savearea *, save_vr11)); - DECLARE("savevr12", offsetof(struct savearea *, save_vr12)); - DECLARE("savevr13", offsetof(struct savearea *, save_vr13)); - DECLARE("savevr14", offsetof(struct savearea *, save_vr14)); - DECLARE("savevr15", offsetof(struct savearea *, save_vr15)); - DECLARE("savevr16", offsetof(struct savearea *, save_vr16)); - DECLARE("savevr17", offsetof(struct savearea *, save_vr17)); - DECLARE("savevr18", offsetof(struct savearea *, save_vr18)); - DECLARE("savevr19", offsetof(struct savearea *, save_vr19)); - DECLARE("savevr20", offsetof(struct savearea *, save_vr20)); - DECLARE("savevr21", offsetof(struct savearea *, save_vr21)); - DECLARE("savevr22", offsetof(struct savearea *, save_vr22)); - DECLARE("savevr23", offsetof(struct savearea *, save_vr23)); - DECLARE("savevr24", offsetof(struct savearea *, save_vr24)); - DECLARE("savevr25", offsetof(struct savearea *, save_vr25)); - DECLARE("savevr26", offsetof(struct savearea *, save_vr26)); - DECLARE("savevr27", offsetof(struct savearea *, save_vr27)); - DECLARE("savevr28", offsetof(struct savearea *, save_vr28)); - DECLARE("savevr29", offsetof(struct savearea *, save_vr29)); - DECLARE("savevr30", offsetof(struct savearea *, save_vr30)); - DECLARE("savevr31", offsetof(struct savearea *, save_vr31)); - DECLARE("savevscr", offsetof(struct savearea *, save_vscr)); - DECLARE("savevrvalid", offsetof(struct savearea *, save_vrvalid)); + DECLARE("savevr0", offsetof(struct savearea_vec *, save_vr0)); + DECLARE("savevr1", offsetof(struct savearea_vec *, save_vr1)); + DECLARE("savevr2", offsetof(struct savearea_vec *, save_vr2)); + DECLARE("savevr3", offsetof(struct savearea_vec *, save_vr3)); + DECLARE("savevr4", offsetof(struct savearea_vec *, save_vr4)); + DECLARE("savevr5", offsetof(struct savearea_vec *, save_vr5)); + DECLARE("savevr6", offsetof(struct savearea_vec *, save_vr6)); + DECLARE("savevr7", offsetof(struct savearea_vec *, save_vr7)); + DECLARE("savevr8", offsetof(struct savearea_vec *, save_vr8)); + DECLARE("savevr9", offsetof(struct savearea_vec *, save_vr9)); + DECLARE("savevr10", offsetof(struct savearea_vec *, save_vr10)); + DECLARE("savevr11", offsetof(struct savearea_vec *, save_vr11)); + DECLARE("savevr12", offsetof(struct savearea_vec *, save_vr12)); + DECLARE("savevr13", offsetof(struct savearea_vec *, save_vr13)); + DECLARE("savevr14", offsetof(struct savearea_vec *, save_vr14)); + DECLARE("savevr15", offsetof(struct savearea_vec *, save_vr15)); + DECLARE("savevr16", offsetof(struct savearea_vec *, save_vr16)); + DECLARE("savevr17", offsetof(struct savearea_vec *, save_vr17)); + DECLARE("savevr18", offsetof(struct savearea_vec *, save_vr18)); + DECLARE("savevr19", offsetof(struct savearea_vec *, save_vr19)); + DECLARE("savevr20", offsetof(struct savearea_vec *, save_vr20)); + DECLARE("savevr21", offsetof(struct savearea_vec *, save_vr21)); + DECLARE("savevr22", offsetof(struct savearea_vec *, save_vr22)); + DECLARE("savevr23", offsetof(struct savearea_vec *, save_vr23)); + DECLARE("savevr24", offsetof(struct savearea_vec *, save_vr24)); + DECLARE("savevr25", offsetof(struct savearea_vec *, save_vr25)); + DECLARE("savevr26", offsetof(struct savearea_vec *, save_vr26)); + DECLARE("savevr27", offsetof(struct savearea_vec *, save_vr27)); + DECLARE("savevr28", offsetof(struct savearea_vec *, save_vr28)); + DECLARE("savevr29", offsetof(struct savearea_vec *, save_vr29)); + DECLARE("savevr30", offsetof(struct savearea_vec *, save_vr30)); + DECLARE("savevr31", offsetof(struct savearea_vec *, save_vr31)); + DECLARE("savevrvalid", offsetof(struct savearea_vec *, save_vrvalid)); /* PseudoKernel Exception Descriptor info */ DECLARE("BEDA_SRR0", offsetof(BEDA_t *, srr0)); @@ -965,6 +901,8 @@ int main(int argc, char *argv[]) DECLARE("shdIBAT", offsetof(struct shadowBAT *, IBATs)); DECLARE("shdDBAT", offsetof(struct shadowBAT *, DBATs)); + + return(0); /* For ANSI C :-) */ diff --git a/osfmk/ppc/hw_exception.s b/osfmk/ppc/hw_exception.s index 55b30c73e..f0296682b 100644 --- a/osfmk/ppc/hw_exception.s +++ b/osfmk/ppc/hw_exception.s @@ -44,6 +44,7 @@ #include #include #include +#include #include @@ -62,12 +63,12 @@ /* * If pcb.ksp == 0 then the kernel stack is already busy, - * we save ppc_saved state below the current stack pointer, + * we make a stack frame * leaving enough space for the 'red zone' in case the * trapped thread was in the middle of saving state below * its stack pointer. * - * otherwise we save a ppc_saved_state in the pcb, and switch to + * otherwise we make a stack frame and * the kernel stack (setting pcb.ksp to 0) * * on return, we do the reverse, the last state is popped from the pcb @@ -87,92 +88,66 @@ .align 5 .globl EXT(thandler) -LEXT(thandler) /* Trap handler */ +LEXT(thandler) ; Trap handler -#if 0 -; -; NOTE: This trap will hang VPC running Windows98 (and probably others)... -; - lwz r25,savedar(r4) ; (TEST/DEBUG) - cmplwi r25,0x298 ; (TEST/DEBUG) - -deadloop: addi r25,r25,1 ; (TEST/DEBUG) - addi r25,r25,1 ; (TEST/DEBUG) - addi r25,r25,1 ; (TEST/DEBUG) - addi r25,r25,1 ; (TEST/DEBUG) - addi r25,r25,1 ; (TEST/DEBUG) - addi r25,r25,1 ; (TEST/DEBUG) - addi r25,r25,1 ; (TEST/DEBUG) - addi r25,r25,1 ; (TEST/DEBUG) - addi r25,r25,1 ; (TEST/DEBUG) - addi r25,r25,1 ; (TEST/DEBUG) - addi r25,r25,1 ; (TEST/DEBUG) - beq- deadloop ; (TEST/DEBUG) -#endif - - mfsprg r25,0 /* Get the per_proc */ + mfsprg r25,0 ; Get the per_proc - lwz r1,PP_ISTACKPTR(r25) ; Get interrupt stack pointer + lwz r1,PP_ISTACKPTR(r25) ; Get interrupt stack pointer - lwz r6,PP_CPU_DATA(r25) /* Get point to cpu specific data */ - cmpwi cr0,r1,0 ; Are we on interrupt stack? - lwz r6,CPU_ACTIVE_THREAD(r6) /* Get the pointer to the currently active thread */ - beq- cr0,EXT(ihandler) ; If on interrupt stack, treat this as interrupt... - lwz r13,THREAD_TOP_ACT(r6) /* Point to the active activation */ - lwz r26,ACT_MACT_SPF(r13) ; Get special flags - lwz r8,ACT_MACT_PCB(r13) /* Get the last savearea used */ + cmpwi cr0,r1,0 ; Are we on interrupt stack? + lwz r6,PP_ACTIVE_THREAD(r25) ; Get the pointer to the currently active thread + beq- cr0,EXT(ihandler) ; If on interrupt stack, treat this as interrupt... + lwz r13,THREAD_TOP_ACT(r6) ; Point to the active activation + lwz r26,ACT_MACT_SPF(r13) ; Get special flags + lwz r8,ACT_MACT_PCB(r13) ; Get the last savearea used rlwinm. r26,r26,0,bbThreadbit,bbThreadbit ; Do we have Blue Box Assist active? - lwz r1,ACT_MACT_KSP(r13) ; Get the top of kernel stack - bnel- checkassist /* See if we should assist this */ - stw r4,ACT_MACT_PCB(r13) /* Point to our savearea */ - stw r8,SAVprev(r4) /* Queue the new save area in the front */ + lwz r1,ACT_MACT_KSP(r13) ; Get the top of kernel stack + bnel- checkassist ; See if we should assist this + stw r4,ACT_MACT_PCB(r13) ; Point to our savearea + stw r8,SAVprev(r4) ; Queue the new save area in the front #if VERIFYSAVE - bl versave ; (TEST/DEBUG) + bl versave ; (TEST/DEBUG) #endif - lwz r9,THREAD_KERNEL_STACK(r6) ; Get our kernel stack start - cmpwi cr1,r1,0 ; Are we already on kernel stack? - stw r13,SAVact(r4) ; Mark the savearea as belonging to this activation - lwz r26,saver1(r4) ; Get the stack at interrupt time + lwz r9,THREAD_KERNEL_STACK(r6) ; Get our kernel stack start + cmpwi cr1,r1,0 ; Are we already on kernel stack? + stw r13,SAVact(r4) ; Mark the savearea as belonging to this activation + lwz r26,saver1(r4) ; Get the stack at interrupt time - bne+ cr1,.L_kstackfree ; We are not on kernel stack yet... + bne+ cr1,.L_kstackfree ; We are not on kernel stack yet... - subi r1,r26,FM_REDZONE ; Make a red zone on interrupt time kernel stack + subi r1,r26,FM_REDZONE ; Make a red zone on interrupt time kernel stack .L_kstackfree: - lwz r7,savesrr1(r4) /* Pick up the entry MSR */ - sub r9,r1,r9 ; Get displacment into the kernel stack - li r0,0 /* Make this 0 */ - cmplwi cr2,r9,KERNEL_STACK_SIZE ; Do we still have room on the stack? - beq cr1,.L_state_on_kstack /* using above test for pcb/stack */ + lwz r7,savesrr1(r4) ; Pick up the entry MSR + sub r9,r1,r9 ; Get displacment into the kernel stack + li r0,0 ; Make this 0 + cmplwi cr2,r9,KERNEL_STACK_SIZE ; Do we still have room on the stack? + beq cr1,.L_state_on_kstack ; using above test for pcb/stack - stw r0,ACT_MACT_KSP(r13) /* Show that we have taken the stack */ + stw r0,ACT_MACT_KSP(r13) ; Show that we have taken the stack .L_state_on_kstack: + lwz r9,savevrsave(r4) ; Get the VRSAVE register rlwinm. r6,r7,0,MSR_VEC_BIT,MSR_VEC_BIT ; Was vector on? - bgt- cr2,kernelStackBad ; Kernel stack is bogus... -kernelStackNotBad: ; Not really - beq+ tvecoff ; Vector off, do not save vrsave... - lwz r3,savevrsave(r4) ; Get the VRSAVE register - stw r3,liveVRS(r25) ; Set the live value - -tvecoff: rlwinm. r3,r7,0,MSR_FP_BIT,MSR_FP_BIT ; Was floating point on? - subi r1,r1,FM_SIZE /* Push a header onto the current stack */ - beq+ tfpoff /* Floating point was off... */ - lwz r3,savexfpscr(r4) ; Grab the just saved FPSCR - stw r3,liveFPSCR(r25) ; Make it the live copy - -tfpoff: stw r26,FM_BACKPTR(r1) ; Link back to the previous frame + subi r1,r1,FM_SIZE ; Push a header onto the current stack + bgt- cr2,kernelStackBad ; Kernel stack is bogus... + +kernelStackNotBad: ; Vector was off + beq+ tvecoff ; Vector off, do not save vrsave... + stw r9,liveVRS(r25) ; Set the live value + +tvecoff: stw r26,FM_BACKPTR(r1) ; Link back to the previous frame #if DEBUG /* If debugging, we need two frames, the first being a dummy * which links back to the trapped routine. The second is * that which the C routine below will need */ - lwz r3,savesrr0(r4) /* Get the point of interruption */ - stw r3,FM_LR_SAVE(r1) /* save old instr ptr as LR value */ - stwu r1, -FM_SIZE(r1) /* and make new frame */ + lwz r3,savesrr0(r4) ; Get the point of interruption + stw r3,FM_LR_SAVE(r1) ; save old instr ptr as LR value + stwu r1, -FM_SIZE(r1) ; and make new frame #endif /* DEBUG */ @@ -184,80 +159,65 @@ tfpoff: stw r26,FM_BACKPTR(r1) ; Link back to the previous frame */ - lwz r3,saveexception(r4) /* Get the exception code */ - lwz r0,ACT_MACT_SPF(r13) ; Get the special flags + lwz r3,saveexception(r4) ; Get the exception code + lwz r0,ACT_MACT_SPF(r13) ; Get the special flags - addi r5,r3,-T_DATA_ACCESS ; Adjust to start of range + addi r5,r3,-T_DATA_ACCESS ; Adjust to start of range rlwinm. r0,r0,0,runningVMbit,runningVMbit ; Are we in VM state? (cr0_eq == 0 if yes) - cmplwi cr2,r5,T_RUNMODE_TRACE-T_DATA_ACCESS ; Are we still in range? (cr_gt if not) + cmplwi cr2,r5,T_TRACE-T_DATA_ACCESS ; Are we still in range? (cr_gt if not) - lwz r5,savedsisr(r4) /* Get the saved DSISR */ + lwz r5,savedsisr(r4) ; Get the saved DSISR - crnor cr7_eq,cr0_eq,cr2_gt ; We should intercept if in VM and is a true trap (cr7_eq == 1 if yes) + crnor cr7_eq,cr0_eq,cr2_gt ; We should intercept if in VM and is a true trap (cr7_eq == 1 if yes) rlwinm. r0,r7,0,MSR_PR_BIT,MSR_PR_BIT ; Are we trapping from supervisor state? (cr0_eq == 1 if yes) - cmpi cr2,r3,T_PREEMPT ; Is this a preemption? + cmpi cr2,r3,T_PREEMPT ; Is this a preemption? - crandc cr0_eq,cr7_eq,cr0_eq ; Do not intercept if we are in the kernel (cr0_eq == 1 if yes) + crandc cr0_eq,cr7_eq,cr0_eq ; Do not intercept if we are in the kernel (cr0_eq == 1 if yes) - lwz r6,savedar(r4) /* Get the DAR */ + lwz r6,savedar(r4) ; Get the DAR - beq- cr2, .L_call_trap /* Don't turn on interrupts for T_PREEMPT */ - beq- exitFromVM ; Any true trap but T_MACHINE_CHECK exits us from the VM... + beq- cr2, .L_call_trap ; Do not turn on interrupts for T_PREEMPT + beq- exitFromVM ; Any true trap but T_MACHINE_CHECK exits us from the VM... /* syscall exception might warp here if there's nothing left * to do except generate a trap */ .L_call_trap: -#if 0 - lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */ - oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */ - sc /* (TEST/DEBUG) */ -#endif bl EXT(trap) + mfmsr r7 ; Get the MSR + rlwinm r7,r7,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r7,r7,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off + rlwinm r7,r7,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear the interrupt enable mask + mtmsr r7 ; Disable for interrupts + mfsprg r10,0 ; Restore the per_proc info /* - * Ok, return from C function - * * This is also the point where new threads come when they are created. * The new thread is setup to look like a thread that took an * interrupt and went immediatly into trap. - * */ thread_return: - - mfmsr r7 /* Get the MSR */ - lwz r4,SAVprev(r3) /* Pick up the previous savearea */ - rlwinm r7,r7,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear the interrupt enable mask */ - lwz r11,SAVflags(r3) /* Get the flags of the current savearea */ - mtmsr r7 /* Disable for interrupts */ - - mfsprg r10,0 /* Restore the per_proc info */ - - lwz r8,savesrr1(r3) ; Get the MSR we are going to - lwz r1,PP_CPU_DATA(r10) /* Get the CPU data area */ - rlwinm r11,r11,0,15,13 /* Clear the syscall flag */ - lwz r1,CPU_ACTIVE_THREAD(r1) /* and the active thread */ + lwz r4,SAVprev(r3) ; Pick up the previous savearea + lwz r11,SAVflags(r3) ; Get the flags of the current savearea + lwz r8,savesrr1(r3) ; Get the MSR we are going to + rlwinm r11,r11,0,15,13 ; Clear the syscall flag + lwz r1,PP_ACTIVE_THREAD(r10) ; Get the active thread rlwinm. r8,r8,0,MSR_PR_BIT,MSR_PR_BIT ; Are we going to the user? - lwz r8,THREAD_TOP_ACT(r1) /* Now find the current activation */ - stw r11,SAVflags(r3) /* Save back the flags (with reset stack cleared) */ + mfsprg r8,1 ; Get the current activation + stw r11,SAVflags(r3) ; Save back the flags (with reset stack cleared) -#if 0 - lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */ - oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */ - sc /* (TEST/DEBUG) */ -#endif - stw r4,ACT_MACT_PCB(r8) /* Point to the previous savearea (or 0 if none) */ + stw r4,ACT_MACT_PCB(r8) ; Point to the previous savearea (or 0 if none) - beq- chkfac ; We are not leaving the kernel yet... + beq- chkfac ; We are not leaving the kernel yet... - lwz r5,THREAD_KERNEL_STACK(r1) /* Get the base pointer to the stack */ - addi r5,r5,KERNEL_STACK_SIZE-FM_SIZE /* Reset to empty */ - stw r5,ACT_MACT_KSP(r8) /* Save the empty stack pointer */ - b chkfac /* Go end it all... */ + lwz r5,THREAD_KERNEL_STACK(r1) ; Get the base pointer to the stack + addi r5,r5,KERNEL_STACK_SIZE-FM_SIZE ; Reset to empty + stw r5,ACT_MACT_KSP(r8) ; Save the empty stack pointer + b chkfac ; Go end it all... ; @@ -267,16 +227,16 @@ thread_return: kernelStackBad: - lwz r3,PP_DEBSTACK_TOP_SS(r25) ; Pick up debug stack top + lwz r3,PP_DEBSTACK_TOP_SS(r25) ; Pick up debug stack top subi r3,r3,KERNEL_STACK_SIZE-FM_SIZE ; Adjust to start of stack - sub r3,r1,r3 ; Get displacement into debug stack + sub r3,r1,r3 ; Get displacement into debug stack cmplwi cr2,r3,KERNEL_STACK_SIZE-FM_SIZE ; Check if we are on debug stack - blt+ cr2,kernelStackNotBad ; Yeah, that is ok too... + blt+ cr2,kernelStackNotBad ; Yeah, that is ok too... - lis r0,hi16(Choke) ; Choke code - ori r0,r0,lo16(Choke) ; and the rest - li r3,failStack ; Bad stack code - sc ; System ABEND + lis r0,hi16(Choke) ; Choke code + ori r0,r0,lo16(Choke) ; and the rest + li r3,failStack ; Bad stack code + sc ; System ABEND /* @@ -311,127 +271,113 @@ kernelStackBad: .align 5 .globl EXT(shandler) -LEXT(shandler) /* System call handler */ - - mfsprg r25,0 /* Get the per proc area */ - lwz r0,saver0(r4) /* Get the original syscall number */ - lwz r17,PP_ISTACKPTR(r25) ; Get interrupt stack pointer - rlwinm r15,r0,0,0,19 ; Clear the bottom of call number for fast check - lwz r16,PP_CPU_DATA(r25) /* Assume we need this */ - mr. r17,r17 ; Are we on interrupt stack? - lwz r7,savesrr1(r4) ; Get the SRR1 value - beq- EXT(ihandler) ; On interrupt stack, not allowed... +LEXT(shandler) ; System call handler + + mfsprg r25,0 ; Get the per proc area + lwz r0,saver0(r4) ; Get the original syscall number + lwz r17,PP_ISTACKPTR(r25) ; Get interrupt stack pointer + rlwinm r15,r0,0,0,19 ; Clear the bottom of call number for fast check + mr. r17,r17 ; Are we on interrupt stack? + lwz r7,savesrr1(r4) ; Get the SRR1 value + beq- EXT(ihandler) ; On interrupt stack, not allowed... + lwz r9,savevrsave(r4) ; Get the VRsave register rlwinm. r6,r7,0,MSR_VEC_BIT,MSR_VEC_BIT ; Was vector on? - lwz r16,CPU_ACTIVE_THREAD(r16) /* Get the thread pointer */ - - beq+ svecoff ; Vector off, do not save vrsave... - lwz r6,savevrsave(r4) ; Get the VRSAVE register - stw r6,liveVRS(r25) ; Set the live value - -svecoff: rlwinm. r6,r7,0,MSR_FP_BIT,MSR_FP_BIT ; Was floating point on? - lwz r13,THREAD_TOP_ACT(r16) /* Pick up the active thread */ - beq+ sfpoff ; Skip if floating point is off... - lwz r9,savexfpscr(r4) ; Grab the just saved FPSCR - stw r9,liveFPSCR(r25) ; Make it the live copy + lwz r16,PP_ACTIVE_THREAD(r25) ; Get the thread pointer + mfsprg r13,1 ; Pick up the active thread + beq+ svecoff ; Vector off, do not save vrsave... + stw r9,liveVRS(r25) ; Set the live value +; ; Check if SCs are being redirected for the BlueBox or to VMM +; -sfpoff: lwz r6,ACT_MACT_SPF(r13) ; Pick up activation special flags - mtcrf 0x41,r6 ; Check special flags - crmove cr6_eq,runningVMbit ; Remember if we are in VMM - bf+ bbNoMachSCbit,noassist ; Take branch if SCs are not redirected - lwz r26,ACT_MACT_BEDA(r13) ; Pick up the pointer to the blue box exception area - b EXT(atomic_switch_syscall) ; Go to the assist... +svecoff: lwz r6,ACT_MACT_SPF(r13) ; Pick up activation special flags + mtcrf 0x41,r6 ; Check special flags + crmove cr6_eq,runningVMbit ; Remember if we are in VMM + bf+ bbNoMachSCbit,noassist ; Take branch if SCs are not redirected + lwz r26,ACT_MACT_BEDA(r13) ; Pick up the pointer to the blue box exception area + b EXT(atomic_switch_syscall) ; Go to the assist... -noassist: cmplwi r15,0x7000 /* Do we have a fast path trap? */ - lwz r14,ACT_MACT_PCB(r13) /* Now point to the PCB */ - beql+ fastpath /* We think it's a fastpath... */ +noassist: cmplwi r15,0x7000 ; Do we have a fast path trap? + lwz r14,ACT_MACT_PCB(r13) ; Now point to the PCB + beql+ fastpath ; We think it is a fastpath... - lwz r1,ACT_MACT_KSP(r13) /* Get the kernel stack pointer */ + lwz r1,ACT_MACT_KSP(r13) ; Get the kernel stack pointer #if DEBUG - mr. r1,r1 /* Are we already on the kernel stack? */ - li r3,T_SYSTEM_CALL /* Yup, pretend we had an interrupt... */ - beq- EXT(ihandler) /* Bad boy, bad boy... What'cha gonna do when they come for you? */ + mr. r1,r1 ; Are we already on the kernel stack? + li r3,T_SYSTEM_CALL ; Yup, pretend we had an interrupt... + beq- EXT(ihandler) ; Bad boy, bad boy... What cha gonna do when they come for you? #endif /* DEBUG */ - stw r4,ACT_MACT_PCB(r13) /* Point to our savearea */ - li r0,0 /* Clear this out */ - stw r14,SAVprev(r4) /* Queue the new save area in the front */ - stw r13,SAVact(r4) /* Point the savearea at its activation */ + stw r4,ACT_MACT_PCB(r13) ; Point to our savearea + li r0,0 ; Clear this out + stw r14,SAVprev(r4) ; Queue the new save area in the front + stw r13,SAVact(r4) ; Point the savearea at its activation #if VERIFYSAVE - bl versave ; (TEST/DEBUG) + bl versave ; (TEST/DEBUG) #endif - mr r30,r4 /* Save pointer to the new context savearea */ - lwz r15,saver1(r4) /* Grab interrupt time stack */ - stw r0,ACT_MACT_KSP(r13) /* Mark stack as busy with 0 val */ - stw r15,FM_BACKPTR(r1) /* Link backwards */ + mr r30,r4 ; Save pointer to the new context savearea + lwz r15,saver1(r4) ; Grab interrupt time stack + stw r0,ACT_MACT_KSP(r13) ; Mark stack as busy with 0 val + stw r15,FM_BACKPTR(r1) ; Link stack frame backwards #if DEBUG - /* If debugging, we need two frames, the first being a dummy - * which links back to the trapped routine. The second is - * that which the C routine below will need - */ - lwz r8,savesrr0(r30) /* Get the point of interruption */ - stw r8,FM_LR_SAVE(r1) /* save old instr ptr as LR value */ - stwu r1, -FM_SIZE(r1) /* and make new frame */ +/* If debugging, we need two frames, the first being a dummy + * which links back to the trapped routine. The second is + * that which the C routine below will need + */ + lwz r8,savesrr0(r30) ; Get the point of interruption + stw r8,FM_LR_SAVE(r1) ; Save old instr ptr as LR value + stwu r1, -FM_SIZE(r1) ; and make new frame #endif /* DEBUG */ - mfmsr r11 /* Get the MSR */ - lwz r15,SAVflags(r4) /* Get the savearea flags */ - ori r11,r11,lo16(MASK(MSR_EE)) /* Turn on interruption enabled bit */ - lwz r0,saver0(r30) ; Get R0 back - oris r15,r15,SAVsyscall >> 16 /* Mark that it this is a syscall */ - rlwinm r10,r0,0,0,19 ; Keep only the top part - stwu r1,-(FM_SIZE+ARG_SIZE)(r1) /* Make a stack frame */ - cmplwi r10,0x6000 ; Is it the special ppc-only guy? - stw r15,SAVflags(r30) /* Save syscall marker */ - beq- cr6,exitFromVM ; It is time to exit from alternate context... - - beq- ppcscall ; Call the ppc-only system call handler... - - mtmsr r11 /* Enable interruptions */ - - /* Call a function that can print out our syscall info */ - /* Note that we don't care about any volatiles yet */ - mr r4,r30 - bl EXT(syscall_trace) - - lwz r0,saver0(r30) /* Get the system call selector */ - mr. r0,r0 /* What kind is it? */ - blt- .L_kernel_syscall /* -ve syscall - go to kernel */ - /* +ve syscall - go to server */ - cmpwi cr0,r0,0x7FFA - beq- .L_notify_interrupt_syscall - -#ifdef MACH_BSD - mr r3,r30 /* Get PCB/savearea */ - lwz r4,saver4(r30) /* Restore r4 */ - lwz r5,saver5(r30) /* Restore r5 */ - lwz r6,saver6(r30) /* Restore r6 */ - lwz r7,saver7(r30) /* Restore r7 */ - lwz r8,saver8(r30) /* Restore r8 */ - lwz r9,saver9(r30) /* Restore r9 */ - lwz r10,saver10(r30) /* Restore r10 */ - bl EXT(unix_syscall) /* Check out unix... */ -#endif + mfmsr r11 ; Get the MSR + lwz r15,SAVflags(r30) ; Get the savearea flags + ori r11,r11,lo16(MASK(MSR_EE)) ; Turn on interruption enabled bit + lwz r0,saver0(r30) ; Get R0 back + oris r15,r15,SAVsyscall >> 16 ; Mark that it this is a syscall + rlwinm r10,r0,0,0,19 ; Keep only the top part + stwu r1,-(FM_SIZE+ARG_SIZE)(r1) ; Make a stack frame + cmplwi r10,0x6000 ; Is it the special ppc-only guy? + stw r15,SAVflags(r30) ; Save syscall marker + beq- cr6,exitFromVM ; It is time to exit from alternate context... + + beq- ppcscall ; Call the ppc-only system call handler... + + mtmsr r11 ; Enable interruptions + + lwz r0,saver0(r30) ; Get the system call selector + mr. r0,r0 ; What kind is it? + blt- .L_kernel_syscall ; System call number if negative, this is a mach call... + + cmpwi cr0,r0,0x7FFA ; Special blue box call? + beq- .L_notify_interrupt_syscall ; Yeah, call it... + + lwz r8,ACT_TASK(r13) ; Get our task + lis r10,hi16(EXT(c_syscalls_unix)) ; Get top half of counter address + lwz r7,TASK_SYSCALLS_UNIX(r8) ; Get the current count + ori r10,r10,lo16(EXT(c_syscalls_unix)) ; Get low half of counter address + addi r7,r7,1 ; Bump it + lwz r9,0(r10) ; Get counter + stw r7,TASK_SYSCALLS_UNIX(r8) ; Save it + mr r3,r30 ; Get PCB/savearea + mr r4,r13 ; current activation + addi r9,r9,1 ; Add 1 + stw r9,0(r10) ; Save it back + bl EXT(unix_syscall) ; Check out unix... .L_call_server_syscall_exception: - li r3,EXC_SYSCALL /* doexception(EXC_SYSCALL, num, 1) */ + li r3,EXC_SYSCALL ; doexception(EXC_SYSCALL, num, 1) .L_call_server_exception: - mr r4,r0 /* Set syscall selector */ + mr r4,r0 ; Set syscall selector li r5,1 - b EXT(doexception) /* Go away, never to return... */ - -/* The above, but with EXC_MACH_SYSCALL */ -.L_call_server_mach_syscall: - li r3,EXC_MACH_SYSCALL - b .L_call_server_exception /* Join the common above... */ + b EXT(doexception) ; Go away, never to return... .L_notify_interrupt_syscall: - lwz r3,saver3(r30) ; Get the new PC address to pass in + lwz r3,saver3(r30) ; Get the new PC address to pass in bl EXT(syscall_notify_interrupt) b .L_syscall_return @@ -455,14 +401,18 @@ noassist: cmplwi r15,0x7000 /* Do we have a fast path trap? */ ; ; Note: the last option is intended for special diagnostics calls that ; want the thread to return and execute before checking for preemption. +; +; NOTE: Both R16 (thread) and R30 (savearea) need to be preserved over this call!!!! ; -ppcscall: rlwinm r11,r0,2,18,29 ; Make an index into the table - lis r10,hi16(EXT(PPCcalls)) ; Get PPC-only system call table - cmplwi r11,PPCcallmax ; See if we are too big - ori r10,r10,lo16(EXT(PPCcalls)) ; Merge in low half + .align 5 + +ppcscall: rlwinm r11,r0,2,18,29 ; Make an index into the table + lis r10,hi16(EXT(PPCcalls)) ; Get PPC-only system call table + cmplwi r11,PPCcallmax ; See if we are too big + ori r10,r10,lo16(EXT(PPCcalls)) ; Merge in low half bgt- .L_call_server_syscall_exception ; Bogus call... - lwzx r11,r10,r11 ; Get function address + lwzx r11,r10,r11 ; Get function address ; ; Note: make sure we do not change the savearea in R30 to @@ -470,22 +420,22 @@ ppcscall: rlwinm r11,r0,2,18,29 ; Make an index into the table ; depend upon it being there. ; - mr r3,r30 ; Pass the savearea - mr r4,r13 ; Pass the activation - mr. r11,r11 ; See if there is a function here - mtlr r11 ; Set the function address + mr r3,r30 ; Pass the savearea + mr r4,r13 ; Pass the activation + mr. r11,r11 ; See if there is a function here + mtlr r11 ; Set the function address beq- .L_call_server_syscall_exception ; Disabled call... - blrl ; Call it - - + blrl ; Call it + .globl EXT(ppcscret) + LEXT(ppcscret) - mr. r3,r3 ; See what we should do - mr r31,r16 ; Restore the current thread pointer + mr. r3,r3 ; See what we should do + mr r31,r16 ; Restore the current thread pointer bgt+ .L_thread_syscall_ret_check_ast ; Take normal AST checking return.... - mfsprg r10,0 ; Get the per_proc - blt+ .L_thread_syscall_return ; Return, but no ASTs.... - lwz r0,saver0(r30) ; Restore the system call number + mfsprg r10,0 ; Get the per_proc + blt+ .L_thread_syscall_return ; Return, but no ASTs.... + lwz r0,saver0(r30) ; Restore the system call number b .L_call_server_syscall_exception ; Go to common exit... @@ -496,81 +446,82 @@ LEXT(ppcscret) * r0 = syscall number * r30 = pointer to saved state (in pcb) */ -.L_kernel_syscall: - neg r31, r0 /* Make number +ve and put in r31*/ - - /* If out of range, call server with syscall exception */ - addis r29, 0, HIGH_CADDR(EXT(mach_trap_count)) - addi r29, r29, LOW_ADDR(EXT(mach_trap_count)) - lwz r29, 0(r29) - cmp cr0, r31, r29 - bge- cr0, .L_call_server_syscall_exception + .align 5 - addis r29, 0, HIGH_CADDR(EXT(mach_trap_table)) - addi r29, r29, LOW_ADDR(EXT(mach_trap_table)) - - /* multiply the trap number to get offset into table */ - slwi r31, r31, MACH_TRAP_OFFSET_POW2 - - /* r31 now holds offset into table of our trap entry, - * add on the table base, and it then holds pointer to entry - */ - add r31, r31, r29 - - /* If the function is kern_invalid, prepare to send an exception. - This is messy, but parallels the x86. We need it for task_by_pid, - at least. */ - lis r29, HIGH_CADDR(EXT(kern_invalid)) - addi r29, r29, LOW_ADDR(EXT(kern_invalid)) - lwz r0, MACH_TRAP_FUNCTION(r31) - cmp cr0, r0, r29 - beq- .L_call_server_syscall_exception - - /* get arg count. If argc > 8 then not all args were in regs, - * so we must perform copyin. - */ - lwz r29, MACH_TRAP_ARGC(r31) - cmpwi cr0, r29, 8 - ble+ .L_syscall_got_args +.L_kernel_syscall: +; +; Call a function that can print out our syscall info +; Note that we don t care about any volatiles yet +; + mr r4,r30 + bl EXT(syscall_trace) + lwz r0,saver0(r30) ; Get the system call selector */ + neg r31,r0 ; Make system call number positive and put in r31 + lis r29,hi16(EXT(mach_trap_count)) ; High part of valid trap number + ori r29,r29,lo16(EXT(mach_trap_count)) ; Low part of valid trap number + lis r28,hi16(EXT(mach_trap_table)) ; High part of trap table + lwz r29,0(r29) ; Get the first invalid system call number + ori r28,r28,lo16(EXT(mach_trap_table)) ; Low part of trap table + + cmplw r31,r29 ; See if we have a valid system call number + slwi r31,r31,MACH_TRAP_OFFSET_POW2 ; Get offset into table + + bge- .L_call_server_syscall_exception ; System call number of bogus + + add r31,r31,r28 ; Point to the system call entry + lis r28,hi16(EXT(kern_invalid)) ; Get the high invalid routine address + lwz r0,MACH_TRAP_FUNCTION(r31) ; Grab the system call routine address + ori r28,r28,lo16(EXT(kern_invalid)) ; Get the low part of the invalid routine address + lwz r29,MACH_TRAP_ARGC(r31) ; Get the number of arguments in the call + cmplw r0,r28 ; Is this an invalid entry? + beq- .L_call_server_syscall_exception ; Yes, it is invalid... + +/* get arg count. If argc > 8 then not all args were in regs, + * so we must perform copyin. + */ + cmpwi cr0,r29,8 ; Do we have more than 8 arguments? + ble+ .L_syscall_got_args ; Nope, no copy in needed... /* argc > 8 - perform a copyin */ /* if the syscall came from kernel space, we can just copy */ - lwz r0,savesrr1(r30) /* Pick up exception time MSR */ - andi. r0,r0,MASK(MSR_PR) /* Check the priv bit */ - bne+ .L_syscall_arg_copyin /* We're not priviliged... */ + lwz r0,savesrr1(r30) ; Pick up exception time MSR + andi. r0,r0,MASK(MSR_PR) ; Check the priv bit + bne+ .L_syscall_arg_copyin ; We are not priviliged... /* we came from a privilaged task, just do a copy */ /* get user's stack pointer */ - lwz r28,saver1(r30) /* Get the stack pointer */ + lwz r28,saver1(r30) ; Get the stack pointer - subi r29,r29,8 /* Get the number of arguments to copy */ + subi r29,r29,8 ; Get the number of arguments to copy - addi r28,r28,COPYIN_ARG0_OFFSET-4 /* Point to source - 4 */ - addi r27,r1,FM_ARG0-4 /* Point to sink - 4 */ + addi r28,r28,COPYIN_ARG0_OFFSET-4 ; Point to source - 4 + addi r27,r1,FM_ARG0-4 ; Point to sink - 4 .L_syscall_copy_word_loop: - addic. r29,r29,-1 /* Count down the number of arguments left */ - lwz r0,4(r28) /* Pick up the argument from the stack */ - addi r28,r28,4 /* Point to the next source */ - stw r0,4(r27) /* Store the argument */ - addi r27,r27,4 /* Point to the next sink */ - bne+ .L_syscall_copy_word_loop /* Move all arguments... */ - b .L_syscall_got_args /* Go call it now... */ + addic. r29,r29,-1 ; Count down the number of arguments left + lwz r0,4(r28) ; Pick up the argument from the stack + addi r28,r28,4 ; Point to the next source + stw r0,4(r27) ; Store the argument + addi r27,r27,4 ; Point to the next sink + bne+ .L_syscall_copy_word_loop ; Move all arguments... + b .L_syscall_got_args ; Go call it now... /* we came from a user task, pay the price of a real copyin */ /* set recovery point */ + .align 5 + .L_syscall_arg_copyin: lwz r8,ACT_VMMAP(r13) ; Get the vm_map for this activation lis r28,hi16(.L_syscall_copyin_recover) lwz r8,VMMAP_PMAP(r8) ; Get the pmap ori r28,r28,lo16(.L_syscall_copyin_recover) addi r8,r8,PMAP_SEGS ; Point to the pmap SR slots - stw r28,THREAD_RECOVER(r16) /* R16 still holds thread ptr */ + stw r28,THREAD_RECOVER(r16) ; R16 still holds thread ptr /* We can manipulate the COPYIN segment register quite easily * here, but we've also got to make sure we don't go over a @@ -579,9 +530,9 @@ LEXT(ppcscret) */ - lwz r28,saver1(r30) /* Get the stack pointer */ - subi r29,r29,8 /* Get the number of arguments to copy */ - addi r28,r28,COPYIN_ARG0_OFFSET /* Set source in user land */ + lwz r28,saver1(r30) ; Get the stack pointer + subi r29,r29,8 ; Get the number of arguments to copy + addi r28,r28,COPYIN_ARG0_OFFSET ; Set source in user land /* set up SR_COPYIN to allow us to copy, we may need to loop * around if we change segments. We know that this previously @@ -590,9 +541,7 @@ LEXT(ppcscret) rlwinm r7,r28,6,26,29 ; Get index to the segment slot -.L_syscall_copyin_seg_loop: - - +.L_syscall_copyin_seg_loop: lwzx r10,r8,r7 ; Get the source SR value rlwinm r26,r28,0,4,31 ; Clear the segment number from source address mtsr SR_COPYIN,r10 ; Set the copyin SR @@ -600,12 +549,10 @@ LEXT(ppcscret) oris r26,r26,(SR_COPYIN_NUM << (28-16)) ; Insert the copyin segment number into source address -/* Make r27 point to address-4 of where we will store copied args */ - addi r27,r1,FM_ARG0-4 + addi r27,r1,FM_ARG0-4 ; Point to area - 4 where we will store the arguments -.L_syscall_copyin_word_loop: - - lwz r0,0(r26) /* MAY CAUSE PAGE FAULT! */ +.L_syscall_copyin_word_loop: + lwz r0,0(r26) ; MAY CAUSE PAGE FAULT! subi r29,r29,1 ; Decrement count addi r26,r26,4 ; Bump input stw r0,4(r27) ; Save the copied in word @@ -618,43 +565,44 @@ LEXT(ppcscret) bne+ .L_syscall_copyin_word_loop ; We are still on the same segment... addi r7,r7,4 ; Bump to next slot - b .L_syscall_copyin_seg_loop /* On new segment! remap */ + b .L_syscall_copyin_seg_loop ; On new segment! remap /* Don't bother restoring SR_COPYIN, we can leave it trashed */ /* clear thread recovery as we're done touching user data */ + .align 5 + .L_syscall_copyin_done: li r0,0 - stw r0,THREAD_RECOVER(r16) /* R16 still holds thread ptr */ + stw r0,THREAD_RECOVER(r16) ; R16 still holds thread ptr .L_syscall_got_args: - lwz r8,ACT_TASK(r13) /* Get our task */ - lis r10,hi16(EXT(c_syscalls_mach)) /* Get top half of counter address */ + lwz r0,MACH_TRAP_FUNCTION(r31) ; Get function address + lwz r8,ACT_TASK(r13) ; Get our task + lis r10,hi16(EXT(c_syscalls_mach)) ; Get top half of counter address lwz r7,TASK_SYSCALLS_MACH(r8) ; Get the current count - lwz r3,saver3(r30) /* Restore r3 */ - addi r7,r7,1 ; Bump it - ori r10,r10,lo16(EXT(c_syscalls_mach)) /* Get low half of counter address */ + lwz r3,saver3(r30) ; Restore r3 + addi r7,r7,1 ; Bump it + ori r10,r10,lo16(EXT(c_syscalls_mach)) ; Get low half of counter address stw r7,TASK_SYSCALLS_MACH(r8) ; Save it - lwz r4,saver4(r30) /* Restore r4 */ - lwz r9,0(r10) /* Get counter */ - lwz r5,saver5(r30) /* Restore r5 */ - lwz r6,saver6(r30) /* Restore r6 */ - addi r9,r9,1 /* Add 1 */ - lwz r7,saver7(r30) /* Restore r7 */ - lwz r8,saver8(r30) /* Restore r8 */ - stw r9,0(r10) /* Save it back */ - lwz r9,saver9(r30) /* Restore r9 */ - lwz r10,saver10(r30) /* Restore r10 */ - - lwz r0,MACH_TRAP_FUNCTION(r31) - -/* calling this function, all the callee-saved registers are - * still valid except for r30 and r31 which are in the PCB - * r30 holds pointer to saved state (ie. pcb) - * r31 is scrap - */ - mtctr r0 - bctrl /* perform the actual syscall */ + lwz r4,saver4(r30) ; Restore r4 + lwz r9,0(r10) ; Get counter + mtctr r0 ; Set function address + lwz r5,saver5(r30) ; Restore r5 + lwz r6,saver6(r30) ; Restore r6 + addi r9,r9,1 ; Add 1 + lwz r7,saver7(r30) ; Restore r7 + lwz r8,saver8(r30) ; Restore r8 + stw r9,0(r10) ; Save it back + lwz r9,saver9(r30) ; Restore r9 + lwz r10,saver10(r30) ; Restore r10 + + +; +; Note that all arguments from the system call are passed into the function +; + + bctrl ; Perform the actual syscall /* 'standard' syscall returns here - INTERRUPTS ARE STILL ON */ @@ -662,7 +610,7 @@ LEXT(ppcscret) */ /* - * Ok, return from C function, ARG0 = return value + * Ok, return from C function, R3 = return value * * get the active thread's PCB pointer and thus pointer to user state * saved state is still in R30 and the active thread is in R16 . @@ -682,38 +630,30 @@ LEXT(ppcscret) /* save off return value, we must load it * back anyway for thread_exception_return - * TODO NMGS put in register? */ + .L_syscall_return: - mr r31,r16 /* Move the current thread pointer */ - stw r3,saver3(r30) /* Stash the return code */ + mr r31,r16 ; Move the current thread pointer + stw r3,saver3(r30) ; Stash the return code - /* Call a function that records the end of */ - /* the mach system call */ - mr r4,r30 - bl EXT(syscall_trace_end) + mr r4,r30 ; Pass in the savearea + bl EXT(syscall_trace_end) ; Trace the exit of the system call -#if 0 - lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */ - mr r4,r31 /* (TEST/DEBUG) */ - oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */ - mr r5,r30 /* (TEST/DEBUG) */ - sc /* (TEST/DEBUG) */ -#endif - .L_thread_syscall_ret_check_ast: - mfmsr r12 /* Get the current MSR */ - rlwinm r12,r12,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Turn off interruptions enable bit */ - mtmsr r12 /* Turn interruptions off */ + mfmsr r12 ; Get the current MSR + rlwinm r12,r12,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r12,r12,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off + rlwinm r12,r12,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Turn off interruptions enable bit + mtmsr r12 ; Turn interruptions off - mfsprg r10,0 /* Get the per_processor block */ + mfsprg r10,0 ; Get the per_processor block /* Check to see if there's an outstanding AST */ - lwz r4,PP_NEED_AST(r10) - lwz r4,0(r4) - cmpi cr0,r4, 0 - beq cr0,.L_syscall_no_ast + lwz r4,PP_NEED_AST(r10) ; Get the pointer to the ast requests + lwz r4,0(r4) ; Get the flags + cmpi cr0,r4, 0 ; Any pending asts? + beq+ cr0,.L_syscall_no_ast ; Nope... /* Yes there is, call ast_taken * pretending that the user thread took an AST exception here, @@ -724,22 +664,20 @@ LEXT(ppcscret) /* debug assert - make sure that we're not returning to kernel */ lwz r3,savesrr1(r30) andi. r3,r3,MASK(MSR_PR) - bne+ 0f /* returning to user level, check */ + bne+ scrnotkern ; returning to user level, check - lis r0,hi16(Choke) ; Choke code - ori r0,r0,lo16(Choke) ; and the rest - li r3,failContext ; Bad state code - sc ; System ABEND - + lis r0,hi16(Choke) ; Choke code + ori r0,r0,lo16(Choke) ; and the rest + li r3,failContext ; Bad state code + sc ; System ABEND -0: +scrnotkern: #endif /* DEBUG */ - li r3, AST_ALL - li r4, 1 - bl EXT(ast_taken) - - b .L_thread_syscall_ret_check_ast + li r3,AST_ALL ; Set ast flags + li r4,1 ; Set interrupt allowed + bl EXT(ast_taken) ; Process the pending ast + b .L_thread_syscall_ret_check_ast ; Go see if there was another... /* thread_exception_return returns to here, almost all * registers intact. It expects a full context restore @@ -750,42 +688,44 @@ LEXT(ppcscret) * r30 points to the current pcb */ + .align 5 + .L_syscall_no_ast: .L_thread_syscall_return: - mr r3,r30 ; Get savearea to the correct register for common exit - lwz r8,THREAD_TOP_ACT(r31) /* Now find the current activation */ - - lwz r11,SAVflags(r30) /* Get the flags */ - lwz r5,THREAD_KERNEL_STACK(r31) /* Get the base pointer to the stack */ - rlwinm r11,r11,0,15,13 /* Clear the syscall flag */ - lwz r4,SAVprev(r30) ; Get the previous save area - stw r11,SAVflags(r30) /* Stick back the flags */ - addi r5,r5,KERNEL_STACK_SIZE-FM_SIZE /* Reset to empty */ - stw r4,ACT_MACT_PCB(r8) ; Save previous save area - stw r5,ACT_MACT_KSP(r8) /* Save the empty stack pointer */ - - b chkfac ; Go end it all... + mr r3,r30 ; Get savearea to the correct register for common exit + mfsprg r8,1 ; Now find the current activation + lwz r11,SAVflags(r30) ; Get the flags + lwz r5,THREAD_KERNEL_STACK(r31) ; Get the base pointer to the stack + rlwinm r11,r11,0,15,13 ; Clear the syscall flag + lwz r4,SAVprev(r30) ; Get the previous save area + stw r11,SAVflags(r30) ; Stick back the flags + addi r5,r5,KERNEL_STACK_SIZE-FM_SIZE ; Reset to empty + stw r4,ACT_MACT_PCB(r8) ; Save previous save area + stw r5,ACT_MACT_KSP(r8) ; Save the empty stack pointer + b chkfac ; Go end it all... + + .align 5 .L_syscall_copyin_recover: - /* This is the catcher for any data faults in the copyin - * of arguments from the user's stack. - * r30 still holds a pointer to the PCB - * - * call syscall_error(EXC_BAD_ACCESS, EXC_PPC_VM_PROT_READ, sp, ssp), - * - * we already had a frame so we can do this - */ +/* This is the catcher for any data faults in the copyin + * of arguments from the user's stack. + * r30 still holds a pointer to the PCB + * + * call syscall_error(EXC_BAD_ACCESS, EXC_PPC_VM_PROT_READ, sp, ssp), + * + * we already had a frame so we can do this + */ - li r3,EXC_BAD_ACCESS - li r4,EXC_PPC_VM_PROT_READ - lwz r5,saver1(r30) - mr r6,r30 + li r3,EXC_BAD_ACCESS ; Set bad access code + li r4,EXC_PPC_VM_PROT_READ ; Set protection exception + lwz r5,saver1(r30) ; Point to the stack + mr r6,r30 ; Pass savearea - bl EXT(syscall_error) - b .L_syscall_return + bl EXT(syscall_error) ; Generate error... + b .L_syscall_return ; Continue out... /* @@ -802,10 +742,11 @@ LEXT(thread_bootstrap_return) ; NOTE: THIS IS GOING AWAY IN A FEW DAYS.... LEXT(thread_exception_return) ; Directly return to user mode .L_thread_exc_ret_check_ast: - - mfmsr r3 /* Get the MSR */ - rlwinm r3,r3,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear EE */ - mtmsr r3 /* Disable interrupts */ + mfmsr r3 ; Get the MSR + rlwinm r3,r3,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r3,r3,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off + rlwinm r3,r3,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear EE + mtmsr r3 ; Disable interrupts /* Check to see if there's an outstanding AST */ /* We don't bother establishing a call frame even though CHECK_AST @@ -813,35 +754,34 @@ LEXT(thread_exception_return) ; Directly return to user mode frame, given that we're not going to return. */ - mfsprg r10,0 /* Get the per_processor block */ + mfsprg r10,0 ; Get the per_processor block lwz r4,PP_NEED_AST(r10) lwz r4,0(r4) cmpi cr0,r4, 0 beq cr0,.L_exc_ret_no_ast - /* Yes there is, call ast_taken - * pretending that the user thread took an AST exception here, - * ast_taken will save all state and bring us back here - */ +/* Yes there is, call ast_taken + * pretending that the user thread took an AST exception here, + * ast_taken will save all state and bring us back here + */ - li r3,AST_ALL li r4,1 bl EXT(ast_taken) - b .L_thread_exc_ret_check_ast /* check for a second AST (rare)*/ + b .L_thread_exc_ret_check_ast ; check for a second AST (rare) /* arriving here, interrupts should be disabled */ /* Get the active thread's PCB pointer to restore regs */ .L_exc_ret_no_ast: - lwz r31,PP_CPU_DATA(r10) - lwz r31,CPU_ACTIVE_THREAD(r31) - lwz r30,THREAD_TOP_ACT(r31) + mfsprg r30,1 ; Get the currrent activation + lwz r31,ACT_THREAD(r30) ; Get the current thread + lwz r30,ACT_MACT_PCB(r30) - mr. r30,r30 ; Is there any context yet? - beq- makeDummyCtx ; No, hack one up... + mr. r30,r30 ; Is there any context yet? + beq- makeDummyCtx ; No, hack one up... #if DEBUG /* * debug assert - make sure that we're not returning to kernel @@ -850,47 +790,52 @@ LEXT(thread_exception_return) ; Directly return to user mode lwz r3,savesrr1(r30) andi. r3,r3,MASK(MSR_PR) - bne+ ret_user2 ; We are ok... + bne+ ret_user2 ; We are ok... - lis r0,hi16(Choke) ; Choke code - ori r0,r0,lo16(Choke) ; and the rest - li r3,failContext ; Bad state code - sc ; System ABEND + lis r0,hi16(Choke) ; Choke code + ori r0,r0,lo16(Choke) ; and the rest + li r3,failContext ; Bad state code + sc ; System ABEND ret_user2: #endif /* DEBUG */ -/* If the MSR_SYSCALL_MASK isn't set, then we came from a trap, +/* If the system call flag isn't set, then we came from a trap, * so warp into the return_from_trap (thread_return) routine, * which takes PCB pointer in R3, not in r30! */ - lwz r0,SAVflags(r30) - mr r3,r30 /* Copy pcb pointer into r3 in case */ - andis. r0,r0,SAVsyscall>>16 /* Are we returning from a syscall? */ - beq- cr0,thread_return /* Nope, must be a thread return... */ - b .L_thread_syscall_return + lwz r0,SAVflags(r30) ; Grab the savearea flags + mr r3,r30 ; Copy pcb pointer into r3 in case we need it + andis. r0,r0,SAVsyscall>>16 ; Are we returning from a syscall? + beq- cr0,thread_return ; Nope, must be a thread return... + b .L_thread_syscall_return ; Join up with the system call return... ; ; This is where we handle someone trying who did a thread_create followed ; by a thread_resume with no intervening thread_set_state. Just make an ; empty context, initialize it to trash and let em execute at 0... +; + + .align 5 makeDummyCtx: - bl EXT(save_get) ; Get a save_area - li r0,0 ; Get a 0 - addi r2,r3,savefp0 ; Point past what we are clearing - mr r4,r3 ; Save the start - -cleardummy: stw r0,0(r4) ; Clear stuff - addi r4,r4,4 ; Next word - cmplw r4,r2 ; Still some more? - blt+ cleardummy ; Yeah... + bl EXT(save_get) ; Get a save_area + li r4,SAVgeneral ; Get the general context type + li r0,0 ; Get a 0 + stb r4,SAVflags+2(r3) ; Set type + addi r2,r3,savevscr ; Point past what we are clearing + mr r4,r3 ; Save the start + +cleardummy: stw r0,0(r4) ; Clear stuff + addi r4,r4,4 ; Next word + cmplw r4,r2 ; Still some more? + blt+ cleardummy ; Yeah... lis r2,hi16(MSR_EXPORT_MASK_SET) ; Set the high part of the user MSR ori r2,r2,lo16(MSR_EXPORT_MASK_SET) ; And the low part - stw r2,savesrr1(r3) ; Set the default user MSR + stw r2,savesrr1(r3) ; Set the default user MSR - b thread_return ; Go let em try to execute, hah! + b thread_return ; Go let em try to execute, hah! /* * ihandler(type) @@ -905,91 +850,86 @@ cleardummy: stw r0,0(r4) ; Clear stuff .align 5 .globl EXT(ihandler) -LEXT(ihandler) /* Interrupt handler */ +LEXT(ihandler) ; Interrupt handler */ /* * get the value of istackptr, if it's zero then we're already on the - * interrupt stack, otherwise it points to a saved_state structure - * at the top of the interrupt stack. + * interrupt stack. */ - lwz r10,savesrr1(r4) /* Get SRR1 */ - mfsprg r25,0 /* Get the per_proc block */ - li r14,0 /* Zero this for now */ + lwz r10,savesrr1(r4) ; Get SRR1 + lwz r7,savevrsave(r4) ; Get the VRSAVE register + mfsprg r25,0 ; Get the per_proc block + li r14,0 ; Zero this for now rlwinm. r13,r10,0,MSR_VEC_BIT,MSR_VEC_BIT ; Was vector on? - lwz r16,PP_CPU_DATA(r25) /* Assume we need this */ - crmove cr1_eq,cr0_eq ; Remember vector enablement - lwz r1,PP_ISTACKPTR(r25) /* Get the interrupt stack */ - rlwinm. r10,r10,0,MSR_FP_BIT,MSR_FP_BIT ; Was floating point on? - li r13,0 /* Zero this for now */ - lwz r16,CPU_ACTIVE_THREAD(r16) /* Get the thread pointer */ - - beq+ cr1,ivecoff ; Vector off, do not save vrsave... - lwz r7,savevrsave(r4) ; Get the VRSAVE register - stw r7,liveVRS(r25) ; Set the live value - -ivecoff: li r0,0 /* Get a constant 0 */ - cmplwi cr1,r16,0 /* Are we still booting? */ - beq+ ifpoff ; Skip if floating point is off... - lwz r9,savexfpscr(r4) ; Grab the just saved FPSCR - stw r9,liveFPSCR(r25) ; Make it the live copy - -ifpoff: mr. r1,r1 /* Is it active? */ - beq- cr1,ihboot1 /* We're still coming up... */ - lwz r13,THREAD_TOP_ACT(r16) /* Pick up the active thread */ - lwz r14,ACT_MACT_PCB(r13) /* Now point to the PCB */ - -ihboot1: lwz r9,saver1(r4) /* Pick up the 'rupt time stack */ - stw r14,SAVprev(r4) /* Queue the new save area in the front */ - stw r13,SAVact(r4) /* Point the savearea at its activation */ - beq- cr1,ihboot4 /* We're still coming up... */ - stw r4,ACT_MACT_PCB(r13) /* Point to our savearea */ - -ihboot4: bne .L_istackfree /* Nope... */ + lwz r1,PP_ISTACKPTR(r25) ; Get the interrupt stack + li r13,0 ; Zero this for now + lwz r16,PP_ACTIVE_THREAD(r25) ; Get the thread pointer + + beq+ ivecoff ; Vector off, do not save vrsave... + stw r7,liveVRS(r25) ; Set the live value + +ivecoff: li r0,0 ; Get a constant 0 + cmplwi cr1,r16,0 ; Are we still booting? + +ifpoff: mr. r1,r1 ; Is it active? + beq- cr1,ihboot1 ; We are still coming up... + lwz r13,THREAD_TOP_ACT(r16) ; Pick up the active thread + lwz r14,ACT_MACT_PCB(r13) ; Now point to the PCB + +ihboot1: lwz r9,saver1(r4) ; Pick up the rupt time stack + stw r14,SAVprev(r4) ; Queue the new save area in the front + stw r13,SAVact(r4) ; Point the savearea at its activation + beq- cr1,ihboot4 ; We are still coming up... + stw r4,ACT_MACT_PCB(r13) ; Point to our savearea + +ihboot4: bne .L_istackfree ; Nope... /* We're already on the interrupt stack, get back the old * stack pointer and make room for a frame */ - lwz r10,PP_INTSTACK_TOP_SS(r25) ; Get the top of the interrupt stack - addi r5,r9,INTSTACK_SIZE-FM_SIZE ; Shift stack for bounds check - subi r1,r9,FM_REDZONE ; Back up beyond the red zone - sub r5,r5,r10 ; Get displacement into stack - cmplwi r5,INTSTACK_SIZE-FM_SIZE ; Is the stack actually invalid? - blt+ ihsetback ; The stack is ok... + lwz r10,PP_INTSTACK_TOP_SS(r25) ; Get the top of the interrupt stack + addi r5,r9,INTSTACK_SIZE-FM_SIZE ; Shift stack for bounds check + subi r1,r9,FM_REDZONE ; Back up beyond the red zone + sub r5,r5,r10 ; Get displacement into stack + cmplwi r5,INTSTACK_SIZE-FM_SIZE ; Is the stack actually invalid? + blt+ ihsetback ; The stack is ok... - lwz r5,PP_DEBSTACK_TOP_SS(r25) ; Pick up debug stack top + lwz r5,PP_DEBSTACK_TOP_SS(r25) ; Pick up debug stack top subi r5,r5,KERNEL_STACK_SIZE-FM_SIZE ; Adjust to start of stack - sub r5,r1,r5 ; Get displacement into debug stack + sub r5,r1,r5 ; Get displacement into debug stack cmplwi cr2,r5,KERNEL_STACK_SIZE-FM_SIZE ; Check if we are on debug stack - blt+ ihsetback ; Yeah, that is ok too... + blt+ ihsetback ; Yeah, that is ok too... - lis r0,hi16(Choke) ; Choke code - ori r0,r0,lo16(Choke) ; and the rest - li r3,failStack ; Bad stack code - sc ; System ABEND + lis r0,hi16(Choke) ; Choke code + ori r0,r0,lo16(Choke) ; and the rest + li r3,failStack ; Bad stack code + sc ; System ABEND .align 5 .L_istackfree: lwz r10,SAVflags(r4) - stw r0,PP_ISTACKPTR(r25) /* Mark the stack in use */ - oris r10,r10,HIGH_ADDR(SAVrststk) /* Indicate we reset stack when we return from this one */ - stw r10,SAVflags(r4) /* Stick it back */ + stw r0,PP_ISTACKPTR(r25) ; Mark the stack in use + oris r10,r10,HIGH_ADDR(SAVrststk) ; Indicate we reset stack when we return from this one + stw r10,SAVflags(r4) ; Stick it back - /* - * To summarize, when we reach here, the state has been saved and - * the stack is marked as busy. We now generate a small - * stack frame with backpointers to follow the calling - * conventions. We set up the backpointers to the trapped - * routine allowing us to backtrace. - */ +/* + * To summarize, when we reach here, the state has been saved and + * the stack is marked as busy. We now generate a small + * stack frame with backpointers to follow the calling + * conventions. We set up the backpointers to the trapped + * routine allowing us to backtrace. + */ -ihsetback: subi r1,r1,FM_SIZE /* Make a new frame */ - stw r9,FM_BACKPTR(r1) /* point back to previous stackptr */ +ihsetback: subi r1,r1,FM_SIZE ; Make a new frame + stw r9,FM_BACKPTR(r1) ; Point back to previous stackptr #if VERIFYSAVE - bl versave ; (TEST/DEBUG) + beq- cr1,ihbootnover ; (TEST/DEBUG) + bl versave ; (TEST/DEBUG) +ihbootnover: ; (TEST/DEBUG) #endif #if DEBUG @@ -997,13 +937,13 @@ ihsetback: subi r1,r1,FM_SIZE /* Make a new frame */ * which links back to the trapped routine. The second is * that which the C routine below will need */ - lwz r5,savesrr0(r4) /* Get interrupt address */ - stw r5,FM_LR_SAVE(r1) /* save old instr ptr as LR value */ - stwu r1,-FM_SIZE(r1) /* Make another new frame for C routine */ + lwz r5,savesrr0(r4) ; Get interrupt address + stw r5,FM_LR_SAVE(r1) ; save old instr ptr as LR value + stwu r1,-FM_SIZE(r1) ; Make another new frame for C routine #endif /* DEBUG */ - lwz r5,savedsisr(r4) /* Get the DSISR */ - lwz r6,savedar(r4) /* Get the DAR */ + lwz r5,savedsisr(r4) ; Get the DSISR + lwz r6,savedar(r4) ; Get the DAR bl EXT(interrupt) @@ -1014,28 +954,29 @@ ihsetback: subi r1,r1,FM_SIZE /* Make a new frame */ */ .globl EXT(ihandler_ret) -LEXT(ihandler_ret) /* Marks our return point from debugger entry */ +LEXT(ihandler_ret) ; Marks our return point from debugger entry - mfmsr r0 /* Get our MSR */ - rlwinm r0,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Flip off the interrupt enabled bit */ - mtmsr r0 /* Make sure interrupts are disabled */ - mfsprg r10,0 /* Get the per_proc block */ + mfmsr r0 ; Get our MSR + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off + rlwinm r0,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Flip off the interrupt enabled bit + mtmsr r0 ; Make sure interrupts are disabled + mfsprg r10,0 ; Get the per_proc block - lwz r8,PP_CPU_DATA(r10) /* Get the CPU data area */ - lwz r7,SAVflags(r3) /* Pick up the flags */ - lwz r8,CPU_ACTIVE_THREAD(r8) /* and the active thread */ - lwz r9,SAVprev(r3) /* Get previous save area */ - cmplwi cr1,r8,0 /* Are we still initializing? */ - lwz r12,savesrr1(r3) /* Get the MSR we will load on return */ - beq- cr1,ihboot2 /* Skip if we are still in init... */ - lwz r8,THREAD_TOP_ACT(r8) /* Pick up the active thread */ + lwz r7,SAVflags(r3) ; Pick up the flags + lwz r8,PP_ACTIVE_THREAD(r10) ; and the active thread + lwz r9,SAVprev(r3) ; Get previous save area + cmplwi cr1,r8,0 ; Are we still initializing? + lwz r12,savesrr1(r3) ; Get the MSR we will load on return + beq- cr1,ihboot2 ; Skip if we are still in init... + lwz r8,THREAD_TOP_ACT(r8) ; Pick up the active thread -ihboot2: andis. r11,r7,HIGH_ADDR(SAVrststk) /* Is this the first on the stack? */ - beq- cr1,ihboot3 /* Skip if we are still in init... */ - stw r9,ACT_MACT_PCB(r8) /* Point to previous context savearea */ +ihboot2: andis. r11,r7,hi16(SAVrststk) ; Is this the first on the stack? + beq- cr1,ihboot3 ; Skip if we are still in init... + stw r9,ACT_MACT_PCB(r8) ; Point to previous context savearea -ihboot3: mr r4,r3 /* Move the savearea pointer */ - beq .L_no_int_ast2 /* Get going if not the top o' stack... */ +ihboot3: mr r4,r3 ; Move the savearea pointer + beq .L_no_int_ast2 ; Get going if not the top-o-stack... /* We're the last frame on the stack. Restore istackptr to empty state. @@ -1044,29 +985,26 @@ ihboot3: mr r4,r3 /* Move the savearea pointer */ * returning to user mode * returning to a kloaded server */ - lwz r9,PP_INTSTACK_TOP_SS(r10) /* Get the empty stack value */ - lwz r5,PP_CPU_DATA(r10) /* Get cpu_data ptr */ - andc r7,r7,r11 /* Remove the stack reset bit in case we pass this one */ - stw r9,PP_ISTACKPTR(r10) /* Save that saved state ptr */ - lwz r3,CPU_PREEMPTION_LEVEL(r5) /* Get preemption level */ - stw r7,SAVflags(r4) /* Save the flags */ - cmplwi r3, 0 /* Check for preemption */ - bne .L_no_int_ast /* Don't preempt if level is not zero */ - andi. r6,r12,MASK(MSR_PR) /* privilege mode */ - lwz r11,PP_NEED_AST(r10) /* Get the AST request address */ - lwz r11,0(r11) /* Get the request */ - beq- .L_kernel_int_ast /* In kernel space, AST_URGENT check */ - li r3,T_AST /* Assume the worst */ - mr. r11,r11 /* Are there any pending? */ - beq .L_no_int_ast /* Nope... */ + lwz r9,PP_INTSTACK_TOP_SS(r10) ; Get the empty stack value + andc r7,r7,r11 ; Remove the stack reset bit in case we pass this one + stw r9,PP_ISTACKPTR(r10) ; Save that saved state ptr + lwz r3,PP_PREEMPT_CNT(r10) ; Get preemption level + stw r7,SAVflags(r4) ; Save the flags + cmplwi r3, 0 ; Check for preemption + bne .L_no_int_ast ; Do not preempt if level is not zero + andi. r6,r12,MASK(MSR_PR) ; privilege mode + lwz r11,PP_NEED_AST(r10) ; Get the AST request address + lwz r11,0(r11) ; Get the request + beq- .L_kernel_int_ast ; In kernel space, AST_URGENT check + li r3,T_AST ; Assume the worst + mr. r11,r11 ; Are there any pending? + beq .L_no_int_ast ; Nope... b .L_call_thandler .L_kernel_int_ast: - andi. r11,r11,AST_URGENT /* AST_URGENT */ - li r3,T_PREEMPT /* Assume the worst */ - beq .L_no_int_ast /* Nope... */ - -.L_call_thandler: + andi. r11,r11,AST_URGENT ; Do we have AST_URGENT? + li r3,T_PREEMPT ; Assume the worst + beq .L_no_int_ast ; Nope... /* * There is a pending AST. Massage things to make it look like @@ -1076,17 +1014,20 @@ ihboot3: mr r4,r3 /* Move the savearea pointer */ * trap instead of performing an rfi. */ - stw r3,saveexception(r4) /* Set the exception code to T_AST/T_PREEMPT */ - b EXT(thandler) /* hyperspace into AST trap */ +.L_call_thandler: + stw r3,saveexception(r4) ; Set the exception code to T_AST/T_PREEMPT + b EXT(thandler) ; We need to preempt so treat like a trap... .L_no_int_ast: - mr r3,r4 ; Get into the right register for common code + mr r3,r4 ; Get into the right register for common code + .L_no_int_ast2: - rlwinm r7,r7,0,15,13 /* Clear the syscall bit */ - li r4,0 ; Assume for a moment that we are in init - stw r7,SAVflags(r3) /* Set the flags */ - beq- cr1,chkfac ; Jump away if we are in init... - lwz r4,ACT_MACT_PCB(r8) ; Get the new level marker + rlwinm r7,r7,0,15,13 ; Clear the syscall flag + li r4,0 ; Assume for a moment that we are in init + stw r7,SAVflags(r3) ; Set the flags with cleared syscall flag + beq- cr1,chkfac ; Jump away if we are in init... + + lwz r4,ACT_MACT_PCB(r8) ; Get the new level marker ; @@ -1101,385 +1042,364 @@ ihboot3: mr r4,r3 /* Move the savearea pointer */ ; R8 = pointer to activation ; R10 = per_proc block ; -chkfac: mr. r8,r8 ; Are we still in boot? - beq- chkenax ; Yeah, skip it all... - - lwz r20,ACT_MACT_FPUlvl(r8) ; Get the FPU level - lwz r12,savesrr1(r3) ; Get the current MSR - cmplw cr1,r20,r3 ; Are we returning from the active level? - lwz r23,PP_FPU_THREAD(r10) ; Get floating point owner - rlwinm r12,r12,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Turn off floating point for now - cmplw cr2,r23,r8 ; Are we the facility owner? - lhz r26,PP_CPU_NUMBER(r10) ; Get the current CPU number - cror cr0_eq,cr1_eq,cr2_eq ; Check if returning from active or we own facility - bne- cr0,chkvecnr ; Nothing to do if not returning from active or not us... +; Note that barring unforseen crashes, there is no escape from this point +; on. We WILL call exception_exit and launch this context. No worries +; about preemption or interruptions here. +; +; Note that we will set up R26 with whatever context we will be launching, +; so it will indicate the current, or the deferred it it is set and we +; are going to user state. CR2_eq will be set to indicate deferred. +; -#if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x3301 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#endif +chkfac: mr r31,r10 ; Move per_proc address + mr r30,r4 ; Preserve new level + lwz r29,savesrr1(r3) ; Get the current MSR + mr. r28,r8 ; Are we still in boot? + mr r27,r3 ; Save the old level + beq- chkenax ; Yeah, skip it all... + + rlwinm. r0,r29,0,MSR_PR_BIT,MSR_PR_BIT ; Are we going into user state? - li r22,ACT_MACT_FPUcpu ; Point to the CPU indication/lock word - -cfSpin2: lwarx r27,r22,r8 ; Get and reserve the last used CPU - mr. r27,r27 ; Is it changing now? - oris r0,r27,hi16(fvChk) ; Set the "changing" flag - blt- cfSpin2 ; Spin if changing - stwcx. r0,r22,r8 ; Lock it up - bne- cfSpin2 ; Someone is messing right now - - isync ; Make sure we see everything - - cmplw r4,r20 ; Are we going to be in the right level? - beq- cr1,chkfpfree ; Leaving active level, can not possibly enable... - cmplw cr1,r27,r26 ; Are we on the right CPU? - li r0,0 ; Get a constant 0 - beq+ cr1,chkfpnlvl ; Right CPU... - - stw r0,PP_FPU_THREAD(r10) ; Show facility unowned so we do not get back here - b chkvec ; Go check out the vector facility... - -chkfpnlvl: bne- chkvec ; Different level, can not enable... - lwz r24,ACT_MACT_FPU(r8) ; Get the floating point save area - ori r12,r12,lo16(MASK(MSR_FP)) ; Enable facility - mr. r24,r24 ; Does the savearea exist? - li r0,1 ; Get set to invalidate - beq- chkvec ; Nothing to invalidate... - lwz r25,SAVlvlfp(r24) ; Get the level of top savearea - cmplw r4,r25 ; Is the top one ours? - bne+ chkvec ; Not ours... - stw r0,SAVlvlfp(r24) ; Invalidate the first one - b chkvec ; Go check out the vector facility... - -chkfpfree: li r0,0 ; Clear a register - lwz r24,ACT_MACT_FPU(r8) ; Get the floating point save area - - bne- cr2,chkfpnfr ; Not our facility, do not clear... - stw r0,PP_FPU_THREAD(r10) ; Clear floating point owner -chkfpnfr: +#if 0 + beq+ lllll ; (TEST/DEBUG) + BREAKPOINT_TRAP ; (TEST/DEBUG) +lllll: +#endif + + lwz r20,curctx(r28) ; Get our current context + lwz r26,deferctx(r28) ; Get any deferred context switch + rlwinm r29,r29,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Turn off floating point for now + lwz r21,FPUlevel(r20) ; Get the facility level + cmplwi cr2,r26,0 ; Are we going into a deferred context later? + rlwinm r29,r29,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Turn off vector for now + crnor cr2_eq,cr0_eq,cr2_eq ; Set cr2_eq if going to user state and there is deferred + cmplw r27,r21 ; Are we returning from the active level? + lhz r19,PP_CPU_NUMBER(r31) ; Get our CPU number + bne+ fpuchkena ; Nope... -#if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x3302 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#endif +; +; First clean up any live context we are returning from +; - mr. r24,r24 ; Do we even have a savearea? - beq+ chkvec ; Nope... + lwz r22,FPUcpu(r20) ; Get CPU this context was last dispatched on -#if FPVECDBG - rlwinm. r0,r24,0,0,15 ; (TEST/DEBUG) - bne+ notbadxxx1 ; (TEST/DEBUG) - BREAKPOINT_TRAP ; (TEST/DEBUG) -notbadxxx1: ; (TEST/DEBUG) - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x3303 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#endif - - lwz r25,SAVlvlfp(r24) ; Get the level of top savearea - cmplwi r25,1 ; Is the top area invalid? - cmplw cr1,r25,r3 ; Is it for the returned from context? - beq fptoss ; It is invalid... - bne cr1,chkvec ; Not for the returned context... + stw r19,FPUcpu(r20) ; Claim context for us + + eieio ; Make sure this gets out before owner clear -fptoss: lwz r25,SAVprefp(r24) ; Get previous savearea -#if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x3304 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - mr r5,r25 ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#endif - mr. r25,r25 ; Is there one? - stw r25,ACT_MACT_FPU(r8) ; Set the new pointer - beq fptoplvl ; Nope, we are at the top... -#if FPVECDBG - rlwinm. r0,r25,0,0,15 ; (TEST/DEBUG) - bne+ notbadxxx2 ; (TEST/DEBUG) - BREAKPOINT_TRAP ; (TEST/DEBUG) -notbadxxx2: ; (TEST/DEBUG) -#endif - lwz r25,SAVlvlfp(r25) ; Get the new level - -fptoplvl: lwz r19,SAVflags(r24) ; Get the savearea flags -#if FPVECDBG - rlwinm. r0,r19,0,1,1 ; (TEST/DEBUG) - bne+ donotdie3 ; (TEST/DEBUG) - BREAKPOINT_TRAP ; (TEST/DEBUG) -donotdie3: ; (TEST/DEBUG) -#endif - -#if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x3305 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#endif - rlwinm r22,r24,0,0,19 ; Round down to the base savearea block - rlwinm r19,r19,0,2,0 ; Remove the floating point in use flag - stw r25,ACT_MACT_FPUlvl(r8) ; Set the new top level - andis. r0,r19,hi16(SAVinuse) ; Still in use? - stw r19,SAVflags(r24) ; Set the savearea flags - bne- invlivefp ; Go invalidate live FP -#if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x3306 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#endif -#if FPVECDBG - rlwinm. r0,r24,0,0,15 ; (TEST/DEBUG) - bne+ notbadxxx3 ; (TEST/DEBUG) - BREAKPOINT_TRAP ; (TEST/DEBUG) -notbadxxx3: ; (TEST/DEBUG) -#endif - lwz r23,SACvrswap(r22) ; Get the conversion from virtual to real - lwz r20,PP_QUICKFRET(r10) ; Get the old quick fret head - xor r23,r24,r23 ; Convert to physical - stw r20,SAVqfret(r24) ; Back chain the quick release queue - stw r23,PP_QUICKFRET(r10) ; Anchor it - -invlivefp: lis r20,hi16(EXT(real_ncpus)) ; Get number of CPUs lis r23,hi16(EXT(per_proc_info)) ; Set base per_proc - ori r20,r20,lo16(EXT(real_ncpus)) ; Other half of number of CPUs - li r25,PP_FPU_THREAD ; Point to the FP owner address - lwz r20,0(r20) ; Get number of processors active + mulli r22,r22,ppSize ; Find offset to the owner per_proc ori r23,r23,lo16(EXT(per_proc_info)) ; Set base per_proc - li r2,0 ; Get something clear + li r24,FPUowner ; Displacement to FPU owner + add r22,r23,r22 ; Point to the owner per_proc + li r0,0 ; We need this in a bit + +fpuinvothr: lwarx r23,r24,r22 ; Get the owner + cmplw r23,r20 ; Does he still have this context? + bne fpuinvoths ; Nope... + stwcx. r0,r24,r22 ; Try to invalidate it + bne- fpuinvothr ; Try again if there was a collision... -invlivefl: cmplw r23,r10 ; We can skip our processor - addi r20,r20,-1 ; Count remaining processors - beq invlivefn ; Skip ourselves... +fpuinvoths: isync -invlivefa: lwarx r0,r25,r23 ; Get FP owner for this processor - cmplw r0,r8 ; Do we own it? - bne invlivefn ; Nope... - stwcx. r2,r25,r23 ; Show not live - bne- invlivefa ; Someone else did this, try again... - -invlivefn: mr. r20,r20 ; Have we finished? - addi r23,r23,ppSize ; Bump to next - bgt invlivefl ; Make sure we do all processors... +; +; Now if there is a savearea associated with the popped context, release it. +; Either way, pop the level to the top stacked context. +; + + lwz r22,FPUsave(r20) ; Get pointer to the first savearea + li r21,0 ; Assume we popped all the way out + mr. r22,r22 ; Is there anything there? + beq+ fpusetlvl ; No, see if we need to enable... + + lwz r21,SAVlevel(r22) ; Get the level of that savearea + cmplw r21,r27 ; Is this the saved copy of the live stuff? + bne fpusetlvl ; No, leave as is... + + lwz r24,SAVprev(r22) ; Pick up the previous area + li r21,0 ; Assume we popped all the way out + mr. r24,r24 ; Any more context stacked? + beq- fpuonlyone ; Nope... + lwz r21,SAVlevel(r24) ; Get the level associated with save +fpuonlyone: stw r24,FPUsave(r20) ; Dequeue this savearea + rlwinm r3,r22,0,0,19 ; Find main savearea header + lwz r3,SACvrswap(r3) ; Get the virtual to real conversion + la r9,quickfret(r31) ; Point to the quickfret chain header + xor r3,r22,r3 ; Convert to physical + +#if FPVECDBG + lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) + li r2,0x3301 ; (TEST/DEBUG) + oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) +#endif + +fpufpucdq: lwarx r0,0,r9 ; Pick up the old chain head + stw r0,SAVprev(r22) ; Move it to the current guy + stwcx. r3,0,r9 ; Save it + bne- fpufpucdq ; Someone chaged the list... + +fpusetlvl: stw r21,FPUlevel(r20) ; Save the level + ; -; Check out vector stuff (and translate savearea to physical for exit) +; Here we check if we are at the right level +; We need to check the level we are entering, not the one we are exiting. +; Therefore, we will use the defer level if it is non-zero and we are +; going into user state. ; -chkvec: sync ; Make sure all is saved - stw r27,ACT_MACT_FPUcpu(r8) ; Set the active CPU and release -chkvecnr: lwz r20,ACT_MACT_VMXlvl(r8) ; Get the vector level - lwz r23,PP_VMX_THREAD(r10) ; Get vector owner - cmplw cr1,r20,r3 ; Are we returning from the active level? - cmplw cr2,r23,r8 ; Are we the facility owner? - rlwinm r12,r12,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Turn off vector for now - cror cr0_eq,cr1_eq,cr2_eq ; Check if returning from active or we own facility - bne- cr0,setenanr ; Not our facility, nothing to do here... +fpuchkena: bt- cr2_eq,fpuhasdfrd ; Skip if deferred, R26 already set up... + mr r26,r20 ; Use the non-deferred value + +fpuhasdfrd: lwz r21,FPUowner(r31) ; Get the ID of the live context + lwz r23,FPUlevel(r26) ; Get the level ID + cmplw cr3,r26,r21 ; Do we have the live context? + lwz r24,FPUcpu(r26) ; Get the CPU that the context was last dispatched on + bne- cr3,chkvec ; No, can not possibly enable... + cmplw r30,r23 ; Are we about to launch the live level? + cmplw cr1,r19,r24 ; Was facility used on this processor last? + bne- chkvec ; No, not live... + bne- cr1,chkvec ; No, wrong cpu, have to enable later.... + + lwz r24,FPUsave(r26) ; Get the first savearea + mr. r24,r24 ; Any savearea? + beq+ fpuena ; Nope... + lwz r25,SAVlevel(r24) ; Get the level of savearea + lwz r0,SAVprev(r24) ; Get the previous + cmplw r30,r25 ; Is savearea for the level we are launching? + bne+ fpuena ; No, just go enable... + + stw r0,FPUsave(r26) ; Pop the chain + + rlwinm r3,r24,0,0,19 ; Find main savearea header + lwz r3,SACvrswap(r3) ; Get the virtual to real conversion + la r9,quickfret(r31) ; Point to the quickfret chain header + xor r3,r24,r3 ; Convert to physical #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x3401 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#endif + lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) + li r2,0x3302 ; (TEST/DEBUG) + oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) +#endif + +fpuhascdq: lwarx r0,0,r9 ; Pick up the old chain head + stw r0,SAVprev(r24) ; Move it to the current guy + stwcx. r3,0,r9 ; Save it + bne- fpuhascdq ; Someone chaged the list... - li r22,ACT_MACT_VMXcpu ; Point to the CPU indication/lock word - -cvSpin2: lwarx r27,r22,r8 ; Get and reserve the last used CPU - mr. r27,r27 ; Is it changing now? - oris r0,r27,hi16(fvChk) ; Set the "changing" flag - blt- cvSpin2 ; Spin if changing - stwcx. r0,r22,r8 ; Lock it up - bne- cvSpin2 ; Someone is messing right now - - isync ; Make sure we see everything - - cmplw r4,r20 ; Are we going to be in the right level? - beq- cr1,chkvecfree ; Leaving active level, can not possibly enable... - cmplw cr1,r27,r26 ; Are we on the right CPU? - li r0,0 ; Get a constant 0 - beq+ cr1,chkvecnlvl ; Right CPU... - - stw r0,PP_VMX_THREAD(r10) ; Show facility unowned so we do not get back here - b setena ; Go actually exit... - -chkvecnlvl: bne- setena ; Different level, can not enable... - lwz r24,ACT_MACT_VMX(r8) ; Get the vector save area - oris r12,r12,hi16(MASK(MSR_VEC)) ; Enable facility - mr. r24,r24 ; Does the savearea exist? - li r0,1 ; Get set to invalidate - beq- setena ; Nothing to invalidate... - lwz r25,SAVlvlvec(r24) ; Get the level of top savearea - cmplw r4,r25 ; Is the top one ours? - bne+ setena ; Not ours... - stw r0,SAVlvlvec(r24) ; Invalidate the first one - b setena ; Actually exit... - -chkvecfree: li r0,0 ; Clear a register - lwz r24,ACT_MACT_VMX(r8) ; Get the vector save area - - bne- cr2,chkvecnfr ; Not our facility, do not clear... - stw r0,PP_VMX_THREAD(r10) ; Clear vector owner -chkvecnfr: +fpuena: ori r29,r29,lo16(MASK(MSR_FP)) ; Enable facility -#if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x3402 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#endif +chkvec: + +#if 0 + rlwinm. r21,r29,0,MSR_PR_BIT,MSR_PR_BIT ; (TEST/DEBUG) + beq+ ppppp ; (TEST/DEBUG) + lwz r21,FPUlevel(r26) ; (TEST/DEBUG) + mr. r21,r21 ; (TEST/DEBUG) + bne- qqqqq ; (TEST/DEBUG) + lwz r21,FPUsave(r26) ; (TEST/DEBUG) + mr. r21,r21 ; (TEST/DEBUG) + beq+ ppppp ; (TEST/DEBUG) + lwz r22,SAVlevel(r21) ; (TEST/DEBUG) + mr. r22,r22 ; (TEST/DEBUG) + beq+ ppppp ; (TEST/DEBUG) +qqqqq: + BREAKPOINT_TRAP ; (TEST/DEBUG) - mr. r24,r24 ; Do we even have a savearea? - beq+ setena ; Nope... +ppppp: ; (TEST/DEBUG) +#endif -#if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x3403 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#endif - lwz r25,SAVlvlvec(r24) ; Get the level - cmplwi r25,1 ; Is the top area invalid? - cmplw cr1,r25,r3 ; Is it for the returned from context? - beq vectoss ; It is invalid... - bne cr1,setena ; Not for the returned context... + lwz r21,VMXlevel(r20) ; Get the facility level + + cmplw r27,r21 ; Are we returning from the active level? + bne+ vmxchkena ; Nope... -vectoss: lwz r25,SAVprevec(r24) ; Get previous savearea -#if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x3504 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - mr r5,r25 ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#endif - mr. r25,r25 ; Is there one? - stw r25,ACT_MACT_VMX(r8) ; Set the new pointer - beq vectoplvl ; Nope, we are at the top... - lwz r25,SAVlvlvec(r25) ; Get the new level - -vectoplvl: lwz r19,SAVflags(r24) ; Get the savearea flags -#if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x3405 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#endif - rlwinm r22,r24,0,0,19 ; Round down to the base savearea block - rlwinm r19,r19,0,3,1 ; Remove the vector in use flag - stw r25,ACT_MACT_VMXlvl(r8) ; Set the new top level - andis. r0,r19,hi16(SAVinuse) ; Still in use? - stw r19,SAVflags(r24) ; Set the savearea flags - bne- invliveve ; Go invalidate live vec... -#if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x3406 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#endif - lwz r23,SACvrswap(r22) ; Get the conversion from virtual to real - lwz r20,PP_QUICKFRET(r10) ; Get the old quick fret head - xor r23,r24,r23 ; Convert to physical - stw r20,SAVqfret(r24) ; Back chain the quick release queue - stw r23,PP_QUICKFRET(r10) ; Anchor it +; +; First clean up any live context we are returning from +; -invliveve: lis r20,hi16(EXT(real_ncpus)) ; Get number of CPUs + lwz r22,VMXcpu(r20) ; Get CPU this context was last dispatched on + + stw r19,VMXcpu(r20) ; Claim context for us + + eieio ; Make sure this gets out before owner clear + lis r23,hi16(EXT(per_proc_info)) ; Set base per_proc - ori r20,r20,lo16(EXT(real_ncpus)) ; Other half of number of CPUs - li r25,PP_VMX_THREAD ; Point to the vector owner address - lwz r20,0(r20) ; Get number of processors active + mulli r22,r22,ppSize ; Find offset to the owner per_proc ori r23,r23,lo16(EXT(per_proc_info)) ; Set base per_proc - li r2,0 ; Get something clear + li r24,VMXowner ; Displacement to VMX owner + add r22,r23,r22 ; Point to the owner per_proc + li r0,0 ; We need this in a bit -invlivevl: cmplw r23,r10 ; We can skip our processor - addi r20,r20,-1 ; Count remaining processors - beq invlivevn ; Skip ourselves... +vmxinvothr: lwarx r23,r24,r22 ; Get the owner + cmplw r23,r20 ; Does he still have this context? + bne vmxinvoths ; Nope... + stwcx. r0,r24,r22 ; Try to invalidate it + bne- vmxinvothr ; Try again if there was a collision... + +vmxinvoths: isync -invliveva: lwarx r0,r25,r23 ; Get vector owner for this processor - cmplw r0,r8 ; Do we own it? - bne invlivevn ; Nope... - stwcx. r2,r25,r23 ; Show not live - bne- invliveva ; Someone else did this, try again... - -invlivevn: mr. r20,r20 ; Have we finished? - addi r23,r23,ppSize ; Bump to next - bgt invlivevl ; Make sure we do all processors... +; +; Now if there is a savearea associated with the popped context, release it. +; Either way, pop the level to the top stacked context. +; -setena: sync ; Make sure all is saved - stw r27,ACT_MACT_VMXcpu(r8) ; Set the active CPU and release + lwz r22,VMXsave(r20) ; Get pointer to the first savearea + li r21,0 ; Assume we popped all the way out + mr. r22,r22 ; Is there anything there? + beq+ vmxsetlvl ; No, see if we need to enable... + + lwz r21,SAVlevel(r22) ; Get the level of that savearea + cmplw r21,r27 ; Is this the saved copy of the live stuff? + bne vmxsetlvl ; No, leave as is... + + lwz r24,SAVprev(r22) ; Pick up the previous area + li r21,0 ; Assume we popped all the way out + mr. r24,r24 ; Any more context? + beq- vmxonlyone ; Nope... + lwz r21,SAVlevel(r24) ; Get the level associated with save -setenanr: rlwinm r20,r12,(((31-vectorCngbit)+(MSR_VEC_BIT+1))&31),vectorCngbit,vectorCngbit ; Set flag if we enabled vector - rlwimi. r20,r12,(((31-floatCngbit)+(MSR_FP_BIT+1))&31),floatCngbit,floatCngbit ; Set flag if we enabled floats - beq setenaa ; Neither float nor vector turned on.... +vmxonlyone: stw r24,VMXsave(r20) ; Dequeue this savearea - lwz r5,ACT_MACT_SPF(r8) ; Get activation copy - lwz r6,spcFlags(r10) ; Get per_proc copy - or r5,r5,r20 ; Set vector/float changed bits in activation - or r6,r6,r20 ; Set vector/float changed bits in per_proc - stw r5,ACT_MACT_SPF(r8) ; Set activation copy - stw r6,spcFlags(r10) ; Set per_proc copy + rlwinm r3,r22,0,0,19 ; Find main savearea header + lwz r3,SACvrswap(r3) ; Get the virtual to real conversion + la r9,quickfret(r31) ; Point to the quickfret chain header + xor r3,r22,r3 ; Convert to physical -setenaa: stw r12,savesrr1(r3) ; Turn facility on or off - - mfdec r24 ; Get decrementer - lwz r22,qactTimer(r8) ; Get high order quick activation timer - mr. r24,r24 ; See if it has popped already... - lwz r23,qactTimer+4(r8) ; Get low order qact timer - ble- chkenax ; We have popped or are just about to... - -segtb: mftbu r20 ; Get the upper time base - mftb r21 ; Get the low - mftbu r19 ; Get upper again - or. r0,r22,r23 ; Any time set? - cmplw cr1,r20,r19 ; Did they change? - beq+ chkenax ; No time set.... - bne- cr1,segtb ; Timebase ticked, get them again... - - subfc r6,r21,r23 ; Subtract current from qact time - li r0,0 ; Make a 0 - subfe r5,r20,r22 ; Finish subtract - subfze r0,r0 ; Get a 0 if qact was bigger than current, -1 otherwise - andc. r12,r5,r0 ; Set 0 if qact has passed - andc r13,r6,r0 ; Set 0 if qact has passed - bne chkenax ; If high order is non-zero, this is too big for a decrementer - cmplw r13,r24 ; Is this earlier than the decrementer? (logical compare takes care of high bit on) - bge+ chkenax ; No, do not reset decrementer... - - mtdec r13 ; Set our value - -chkenax: lwz r6,SAVflags(r3) ; Pick up the flags of the old savearea +#if FPVECDBG + lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) + li r2,0x3401 ; (TEST/DEBUG) + oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) +#endif + +vmxhscdq: lwarx r0,0,r9 ; Pick up the old chain head + stw r0,SAVprev(r22) ; Move it to the current guy + stwcx. r3,0,r9 ; Save it + bne- vmxhscdq ; Someone chaged the list... + +vmxsetlvl: stw r21,VMXlevel(r20) ; Save the level + +; +; Here we check if we are at the right level +; + +vmxchkena: lwz r21,VMXowner(r31) ; Get the ID of the live context + lwz r23,VMXlevel(r26) ; Get the level ID + cmplw r26,r21 ; Do we have the live context? + lwz r24,VMXcpu(r26) ; Get the CPU that the context was last dispatched on + bne- setena ; No, can not possibly enable... + cmplw r30,r23 ; Are we about to launch the live level? + cmplw cr1,r19,r24 ; Was facility used on this processor last? + bne- setena ; No, not live... + bne- cr1,setena ; No, wrong cpu, have to enable later.... + + lwz r24,VMXsave(r26) ; Get the first savearea + mr. r24,r24 ; Any savearea? + beq+ vmxena ; Nope... + lwz r25,SAVlevel(r24) ; Get the level of savearea + lwz r0,SAVprev(r24) ; Get the previous + cmplw r30,r25 ; Is savearea for the level we are launching? + bne+ vmxena ; No, just go enable... + + stw r0,VMXsave(r26) ; Pop the chain + + rlwinm r3,r24,0,0,19 ; Find main savearea header + lwz r3,SACvrswap(r3) ; Get the virtual to real conversion + la r9,quickfret(r31) ; Point to the quickfret chain header + xor r3,r24,r3 ; Convert to physical + +#if FPVECDBG + lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) + li r2,0x3402 ; (TEST/DEBUG) + oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) +#endif + +vmxckcdq: lwarx r0,0,r9 ; Pick up the old chain head + stw r0,SAVprev(r24) ; Move it to the current guy + stwcx. r3,0,r9 ; Save it + bne- vmxckcdq ; Someone chaged the list... + +vmxena: oris r29,r29,hi16(MASK(MSR_VEC)) ; Enable facility + + +setena: rlwinm. r0,r29,0,MSR_PR_BIT,MSR_PR_BIT ; Are we about to launch user state? + rlwinm r20,r29,(((31-vectorCngbit)+(MSR_VEC_BIT+1))&31),vectorCngbit,vectorCngbit ; Set flag if we enabled vector + stw r29,savesrr1(r27) ; Turn facility on or off + crmove cr7_eq,cr0_eq ; Remember if we are going to user state + lwz r19,deferctx(r28) ; Get any deferred facility context switch + rlwimi. r20,r29,(((31-floatCngbit)+(MSR_FP_BIT+1))&31),floatCngbit,floatCngbit ; Set flag if we enabled floats + beq setenaa ; Neither float nor vector turned on.... + + lwz r5,ACT_MACT_SPF(r28) ; Get activation copy + lwz r6,spcFlags(r31) ; Get per_proc copy + or r5,r5,r20 ; Set vector/float changed bits in activation + or r6,r6,r20 ; Set vector/float changed bits in per_proc + stw r5,ACT_MACT_SPF(r28) ; Set activation copy + stw r6,spcFlags(r31) ; Set per_proc copy + +setenaa: mfdec r24 ; Get decrementer + bf+ cr2_eq,nodefer ; No deferred to switch to... + + li r20,0 ; Clear this + stw r26,curctx(r28) ; Make the facility context current + stw r20,deferctx(r28) ; Clear deferred context + +nodefer: lwz r22,qactTimer(r28) ; Get high order quick activation timer + mr. r24,r24 ; See if it has popped already... + lwz r23,qactTimer+4(r28) ; Get low order qact timer + ble- chkenax ; We have popped or are just about to... + +segtb: mftbu r20 ; Get the upper time base + mftb r21 ; Get the low + mftbu r19 ; Get upper again + or. r0,r22,r23 ; Any time set? + cmplw cr1,r20,r19 ; Did they change? + beq+ chkenax ; No time set.... + bne- cr1,segtb ; Timebase ticked, get them again... + + subfc r6,r21,r23 ; Subtract current from qact time + li r0,0 ; Make a 0 + subfe r5,r20,r22 ; Finish subtract + subfze r0,r0 ; Get a 0 if qact was bigger than current, -1 otherwise + andc. r12,r5,r0 ; Set 0 if qact has passed + andc r13,r6,r0 ; Set 0 if qact has passed + bne chkenax ; If high order is non-zero, this is too big for a decrementer + cmplw r13,r24 ; Is this earlier than the decrementer? (logical compare takes care of high bit on) + bge+ chkenax ; No, do not reset decrementer... + + mtdec r13 ; Set our value + +chkenax: #if DEBUG - lwz r20,SAVact(r3) ; (TEST/DEBUG) Make sure our restore - lwz r21,PP_CPU_DATA(r10) ; (TEST/DEBUG) context is associated - lwz r21,CPU_ACTIVE_THREAD(r21) ; (TEST/DEBUG) with the current act. - cmpwi r21,0 ; (TEST/DEBUG) - beq- yeswereok ; (TEST/DEBUG) - lwz r21,THREAD_TOP_ACT(r21) ; (TEST/DEBUG) - cmplw r21,r20 ; (TEST/DEBUG) - beq+ yeswereok ; (TEST/DEBUG) - - lis r0,hi16(Choke) ; (TEST/DEBUG) Choke code - ori r0,r0,lo16(Choke) ; (TEST/DEBUG) and the rest - mr r21,r3 ; (TEST/DEBUG) Save the savearea address - li r3,failContext ; (TEST/DEBUG) Bad state code - sc ; (TEST/DEBUG) System ABEND + lwz r20,SAVact(r27) ; (TEST/DEBUG) Make sure our restore + lwz r21,PP_ACTIVE_THREAD(r31) ; (TEST/DEBUG) with the current act. + cmpwi r21,0 ; (TEST/DEBUG) + beq- yeswereok ; (TEST/DEBUG) + lwz r21,THREAD_TOP_ACT(r21) ; (TEST/DEBUG) + cmplw r21,r20 ; (TEST/DEBUG) + beq+ yeswereok ; (TEST/DEBUG) + + lis r0,hi16(Choke) ; (TEST/DEBUG) Choke code + ori r0,r0,lo16(Choke) ; (TEST/DEBUG) and the rest + mr r21,r27 ; (TEST/DEBUG) Save the savearea address + li r3,failContext ; (TEST/DEBUG) Bad state code + sc ; (TEST/DEBUG) System ABEND yeswereok: #endif - rlwinm r5,r3,0,0,19 ; Round savearea down to page bndry - rlwinm r6,r6,0,1,31 ; Mark savearea free - lwz r5,SACvrswap(r5) ; Get the conversion from virtual to real - stw r6,SAVflags(r3) ; Set savearea flags - xor r3,r3,r5 ; Flip to physical address - b EXT(exception_exit) ; We are all done now... + rlwinm r5,r27,0,0,19 ; Round savearea down to page bndry + lwz r5,SACvrswap(r5) ; Get the conversion from virtual to real + xor r3,r27,r5 ; Flip to physical address + b EXT(exception_exit) ; We are all done now... @@ -1525,11 +1445,8 @@ CthreadSetSelfNumber: .globl EXT(fastexit) EXT(fastexit): - lwz r8,SAVflags(r4) /* Pick up the flags */ rlwinm r9,r4,0,0,19 /* Round down to the base savearea block */ - rlwinm r8,r8,0,1,31 /* Clear the attached bit */ lwz r9,SACvrswap(r9) /* Get the conversion from virtual to real */ - stw r8,SAVflags(r4) /* Set the flags */ xor r3,r4,r9 /* Switch savearea to physical addressing */ b EXT(exception_exit) /* Go back to the caller... */ @@ -1663,10 +1580,9 @@ chokestart: li r0,0 ; Get a zero ; versave: - -#if 0 +#if 1 ; -; Make sure that only the top FPU savearea is marked invalid +; Make sure that all savearea chains have the right type on them ; lis r28,hi16(EXT(default_pset)) ; (TEST/DEBUG) @@ -1676,45 +1592,78 @@ versave: li r20,0 ; (TEST/DEBUG) lwz r26,0(r27) ; (TEST/DEBUG) lwz r27,psthreadcnt(r28) ; (TEST/DEBUG) - mr. r26,r26 ; (TEST/DEBUG) + mr. r26,r26 ; (TEST/DEBUG) Have we locked the test out? lwz r28,psthreads(r28) ; (TEST/DEBUG) - bnelr- ; (TEST/DEBUG) + mflr r31 ; (TEST/DEBUG) Save return + bnelr- ; (TEST/DEBUG) Test already triggered, skip... + b fckgo ; (TEST/DEBUG) Join up... -fcknxtth: mr. r27,r27 ; (TEST/DEBUG) - beqlr- ; (TEST/DEBUG) +fcknext: mr. r27,r27 ; (TEST/DEBUG) Any more threads? + bne+ fckxxx ; (TEST/DEBUG) Yes... + + mtlr r31 ; (TEST/DEBUG) Restore return + blr ; (TEST/DEBUG) Leave... - lwz r26,THREAD_TOP_ACT(r28) ; (TEST/DEBUG) +fckxxx: lwz r28,THREAD_PSTHRN(r28) ; (TEST/DEBUG) Get next thread -fckact: mr. r26,r26 ; (TEST/DEBUG) - bne+ fckact2 ; (TEST/DEBUG) +fckgo: subi r27,r27,1 ; (TEST/DEBUG) Decrement thread count + lwz r24,THREAD_TOP_ACT(r28) ; (TEST/DEBUG) Get activation for the thread + lwz r20,ACT_MACT_PCB(r24) ; (TEST/DEBUG) Get the normal context + li r21,SAVgeneral ; (TEST/DEBUG) Make sure this is all general context + bl versavetype ; (TEST/DEBUG) Check the chain - lwz r28,THREAD_PSTHRN(r28) ; (TEST/DEBUG) Next in line - subi r27,r27,1 ; (TEST/DEBUG) - b fcknxtth ; (TEST/DEBUG) - -fckact2: lwz r20,ACT_MACT_FPU(r26) ; (TEST/DEBUG) Get FPU chain - mr. r20,r20 ; (TEST/DEBUG) Are there any? - beq+ fcknact ; (TEST/DEBUG) No... + lwz r20,facctx+FPUsave(r24) ; (TEST/DEBUG) Get regular floating point + li r21,SAVfloat ; (TEST/DEBUG) Make sure this is all floating point + bl versavetype ; (TEST/DEBUG) Check the chain -fckact3: lwz r20,SAVprefp(r20) ; (TEST/DEBUG) Get next in list - mr. r20,r20 ; (TEST/DEBUG) Check next savearea - beq+ fcknact ; (TEST/DEBUG) No... + lwz r20,facctx+VMXsave(r24) ; (TEST/DEBUG) Get regular vector point + li r21,SAVvector ; (TEST/DEBUG) Make sure this is all vector + bl versavetype ; (TEST/DEBUG) Check the chain - lwz r29,SAVlvlfp(r20) ; (TEST/DEBUG) Get the level - - cmplwi r29,1 ; (TEST/DEBUG) Is it invalid?? - bne+ fckact3 ; (TEST/DEBUG) Nope... + lwz r29,vmmControl(r24) ; (TEST/DEBUG) Get the virtual machine control blocks + mr. r29,r29 ; (TEST/DEBUG) Are there any? + beq+ fcknext ; (TEST/DEBUG) Nope, next thread... - lis r27,hi16(EXT(DebugWork)) ; (TEST/DEBUG) - ori r27,r27,lo16(EXT(DebugWork)) ; (TEST/DEBUG) - stw r27,0(r27) ; (TEST/DEBUG) - BREAKPOINT_TRAP ; (TEST/DEBUG) - -fcknact: lwz r26,ACT_LOWER(r26) ; (TEST/DEBUG) Next activation - b fckact ; (TEST/DEBUG) + li r22,kVmmMaxContextsPerThread ; (TEST/DEBUG) Get the number of control blocks + subi r29,r29,vmmCEntrySize ; (TEST/DEBUG) Get running start + +fcknvmm: subi r22,r22,1 ; (TEST/DEBUG) Do all of them + mr. r22,r22 ; (TEST/DEBUG) Are we all done? + addi r29,r29,vmmCEntrySize ; (TEST/DEBUG) Get the next entry + blt- fcknext ; (TEST/DEBUG) Yes, check next thread... + + lwz r23,vmmFlags(r29) ; (TEST/DEBUG) Get entry flags + rlwinm. r23,r23,0,0,0 ; (TEST/DEBUG) Is this in use? + beq+ fcknvmm ; (TEST/DEBUG) Not in use... + + lwz r20,vmmFacCtx+FPUsave(r29) ; (TEST/DEBUG) Get regular floating point + li r21,SAVfloat ; (TEST/DEBUG) Make sure this is all floating point + bl versavetype ; (TEST/DEBUG) Check the chain + + lwz r20,vmmFacCtx+VMXsave(r29) ; (TEST/DEBUG) Get regular vector point + li r21,SAVvector ; (TEST/DEBUG) Make sure this is all vector + bl versavetype ; (TEST/DEBUG) Check the chain + b fcknvmm ; (TEST/DEBUG) Get then vmm block... + +versavetype: + mr. r20,r20 ; (TEST/DEBUG) Chain done? + beqlr- ; (TEST/DEBUG) Yes... + + lwz r23,SAVflags(r20) ; (TEST/DEBUG) Get the flags + rlwinm r23,r23,24,24,31 ; (TEST/DEBUG) Position it + cmplw r23,r21 ; (TEST/DEBUG) Are we the correct type? + beq+ versvok ; (TEST/DEBUG) This one is ok... + + lis r22,hi16(EXT(DebugWork)) ; (TEST/DEBUG) + ori r22,r22,lo16(EXT(DebugWork)) ; (TEST/DEBUG) + stw r22,0(r22) ; (TEST/DEBUG) Lock out more checks + BREAKPOINT_TRAP ; (TEST/DEBUG) Get into debugger + +versvok: lwz r20,SAVprev(r20) ; (TEST/DEBUG) Get the previous one + b versavetype ; (TEST/DEBUG) Go check its type... #endif -#if 1 +#if 0 ; ; Make sure there are no circular links in the float chain ; And that FP is marked busy in it. diff --git a/osfmk/ppc/hw_lock.s b/osfmk/ppc/hw_lock.s index 14678dfd5..ec68b45a8 100644 --- a/osfmk/ppc/hw_lock.s +++ b/osfmk/ppc/hw_lock.s @@ -38,8 +38,9 @@ #define MISSED 8+FM_SIZE #define ILK_LOCKED 0x01 -#define MUTEX_LOCKED 0x02 +#define WAIT_FLAG 0x02 #define SLOCK_FAST 0x02 +#define TH_FN_OWNED 0x01 ; ; NOTE: make sure that PREEMPTSTACK in aligned_data is @@ -119,11 +120,13 @@ not_a_slock: #define CHECK_NO_SIMPLELOCKS() \ bt 24+disLkNmSimpb,2f __ASMNL__ \ mfmsr r11 __ASMNL__ \ + rlwinm r11,r11,0,MSR_FP_BIT+1,MSR_FP_BIT-1 __ASMNL__ \ + rlwinm r11,r11,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 __ASMNL__ \ rlwinm r10,r11,0,MSR_EE_BIT+1,MSR_EE_BIT-1 __ASMNL__ \ mtmsr r10 __ASMNL__ \ + isync __ASMNL__ \ mfsprg r10,0 __ASMNL__ \ - lwz r10,PP_CPU_DATA(r10) __ASMNL__ \ - lwz r10,CPU_SIMPLE_LOCK_COUNT(r10) __ASMNL__ \ + lwz r10,PP_SIMPLE_LOCK_CNT(r10) __ASMNL__ \ cmpwi r10,0 __ASMNL__ \ beq+ 1f __ASMNL__ \ lis r3,hi16(simple_locks_held) __ASMNL__ \ @@ -146,11 +149,13 @@ simple_locks_held: #define CHECK_THREAD(thread_offset) \ bt 24+disLkThreadb,2f __ASMNL__ \ mfmsr r11 __ASMNL__ \ + rlwinm r11,r11,0,MSR_FP_BIT+1,MSR_FP_BIT-1 __ASMNL__ \ + rlwinm r11,r11,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 __ASMNL__ \ rlwinm r10,r11,0,MSR_EE_BIT+1,MSR_EE_BIT-1 __ASMNL__ \ mtmsr r10 __ASMNL__ \ + isync __ASMNL__ \ mfsprg r10,0 __ASMNL__ \ - lwz r10,PP_CPU_DATA(r10) __ASMNL__ \ - lwz r10,CPU_ACTIVE_THREAD(r10) __ASMNL__ \ + lwz r10,PP_ACTIVE_THREAD(r10) __ASMNL__ \ cmpwi r10,0 __ASMNL__ \ beq- 1f __ASMNL__ \ lwz r9,thread_offset(r3) __ASMNL__ \ @@ -171,11 +176,13 @@ wrong_thread: #define CHECK_MYLOCK(thread_offset) \ bt 24+disLkMyLckb,2f __ASMNL__ \ mfmsr r11 __ASMNL__ \ + rlwinm r11,r11,0,MSR_FP_BIT+1,MSR_FP_BIT-1 __ASMNL__ \ + rlwinm r11,r11,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 __ASMNL__ \ rlwinm r10,r11,0,MSR_EE_BIT+1,MSR_EE_BIT-1 __ASMNL__ \ mtmsr r10 __ASMNL__ \ + isync __ASMNL__ \ mfsprg r10,0 __ASMNL__ \ - lwz r10,PP_CPU_DATA(r10) __ASMNL__ \ - lwz r10,CPU_ACTIVE_THREAD(r10) __ASMNL__ \ + lwz r10,PP_ACTIVE_THREAD(r10) __ASMNL__ \ cmpwi r10,0 __ASMNL__ \ beq- 1f __ASMNL__ \ lwz r9, thread_offset(r3) __ASMNL__ \ @@ -314,10 +321,13 @@ LEXT(hw_lock_to) cmplw cr1,r1,r1 /* Set flag to enable disable preemption */ lockComm: mfmsr r9 /* Get the MSR value */ + rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off mr r5,r3 /* Get the address of the lock */ + rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r7,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Get MSR that is uninterruptible */ mtmsr r7 /* Turn off interruptions */ + isync ; May have turned off vec and fp here mftb r8 /* Get the low part of the time base */ lcktry: lwarx r6,0,r5 /* Grab the lock value */ @@ -396,9 +406,12 @@ lckfail: /* We couldn't get the lock */ LEXT(hw_lock_bit) mfmsr r9 /* Get the MSR value */ + rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r7,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Get MSR that is uninterruptible */ mtmsr r7 /* Turn off interruptions */ + isync ; May have turned off vec and fp here mftb r8 /* Get the low part of the time base */ @@ -503,14 +516,17 @@ ubittry: lwarx r0,0,r3 /* Grab the lock value */ LEXT(hw_lock_mbits) mfmsr r9 ; Get the MSR value + rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r8,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Get MSR that is uninterruptible mtmsr r8 ; Turn off interruptions - + isync ; May have turned off vectors or float here mftb r10 ; Get the low part of the time base mbittry: lwarx r12,0,r3 ; Grab the lock value and r0,r12,r4 ; Clear extra bits + andc r12,r12,r4 ; Clear all bits in the bit mask or r12,r12,r6 ; Turn on the lock bits cmplw r0,r5 ; Are these the right bits? bne- mbitsniff ; Nope, wait for it to clear... @@ -522,7 +538,6 @@ mbittry: lwarx r12,0,r3 ; Grab the lock value mbitsniff: lwz r12,0(r3) ; Get that lock in here and r0,r12,r4 ; Clear extra bits - or r12,r12,r6 ; Turn on the lock bits cmplw r0,r5 ; Are these the right bits? beq+ mbittry ; Yeah, try for it again... @@ -653,6 +668,8 @@ LEXT(hw_lock_try) sc /* (TEST/DEBUG) */ #endif mfmsr r9 /* Save the MSR value */ + rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r7,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruption bit */ #if MACH_LDEBUG @@ -661,7 +678,7 @@ LEXT(hw_lock_try) #endif /* MACH_LDEBUG */ mtmsr r7 /* Disable interruptions and thus, preemption */ - + isync ; May have turned off fp/vec here .L_lock_try_loop: #if MACH_LDEBUG @@ -682,12 +699,11 @@ LEXT(hw_lock_try) mfsprg r6,0 /* Get the per_proc block */ bne- .L_lock_try_loop /* If set failed, loop back */ - lwz r6,PP_CPU_DATA(r6) /* Get the pointer to the CPU data from per proc */ isync - lwz r5,CPU_PREEMPTION_LEVEL(r6) /* Get the preemption level */ + lwz r5,PP_PREEMPT_CNT(r6) /* Get the preemption level */ addi r5,r5,1 /* Bring up the disable count */ - stw r5,CPU_PREEMPTION_LEVEL(r6) /* Save it back */ + stw r5,PP_PREEMPT_CNT(r6) /* Save it back */ mtmsr r9 /* Allow interruptions now */ li r3,1 /* Set that the lock was free */ @@ -722,11 +738,11 @@ LEXT(hw_lock_held) blr /* - * unsigned int hw_compare_and_store(unsigned int old, unsigned int new, unsigned int *area) + * uint32_t hw_compare_and_store(uint32_t oldval, uint32_t newval, uint32_t *dest) * * Compare old to area if equal, store new, and return true * else return false and no store - * This is an atomic operation + * This is an atomic operation * */ .align 5 @@ -750,7 +766,7 @@ csfail: li r3,0 /* Set failure */ /* - * unsigned int hw_atomic_add(unsigned int *area, int val) + * uint32_t hw_atomic_add(uint32_t *dest, uint32_t delt) * * Atomically add the second parameter to the first. * Returns the result. @@ -771,7 +787,7 @@ addtry: lwarx r3,0,r6 /* Grab the area value */ /* - * unsigned int hw_atomic_sub(unsigned int *area, int val) + * uint32_t hw_atomic_sub(uint32_t *dest, uint32_t delt) * * Atomically subtract the second parameter from the first. * Returns the result. @@ -792,7 +808,7 @@ subtry: lwarx r3,0,r6 /* Grab the area value */ /* - * unsigned int hw_atomic_or(unsigned int *area, int val) + * uint32_t hw_atomic_or(uint32_t *dest, uint32_t mask) * * Atomically ORs the second parameter into the first. * Returns the result. @@ -813,7 +829,7 @@ ortry: lwarx r3,0,r6 ; Grab the area value /* - * unsigned int hw_atomic_and(unsigned int *area, int val) + * uint32_t hw_atomic_and(uint32_t *dest, uint32_t mask) * * Atomically ANDs the second parameter with the first. * Returns the result. @@ -872,6 +888,7 @@ LEXT(hw_queue_atomic_list) hw_queue_comm: lwarx r9,0,r3 /* Pick up the anchor */ stwx r9,r8,r7 /* Chain that to the end of the new stuff */ + eieio ; Make sure this store makes it before the anchor update stwcx. r4,0,r3 /* Try to chain into the front */ bne- hw_queue_comm /* Didn't make it, try again... */ @@ -912,7 +929,7 @@ ENTRY(mutex_init,TAG_NO_FRAME_USED) li r10, 0 stw r10, LOCK_DATA(r3) /* clear lock word */ sth r10, MUTEX_WAITERS(r3) /* init waiter count */ - + sth r10, MUTEX_PROMOTED_PRI(r3) #if MACH_LDEBUG stw r10, MUTEX_PC(r3) /* init caller pc */ stw r10, MUTEX_THREAD(r3) /* and owning thread */ @@ -939,14 +956,14 @@ LEXT(mutex_lock) LEXT(_mutex_lock) #if !MACH_LDEBUG + mfsprg r6,1 /* load the current thread */ L_mutex_lock_loop: - lwarx r5,0,r3 - andi. r4,r5,ILK_LOCKED|MUTEX_LOCKED - bne- L_mutex_lock_slow - ori r5,r5,MUTEX_LOCKED - stwcx. r5,0,r3 - bne- L_mutex_lock_loop - isync + lwarx r5,0,r3 /* load the mutex lock */ + mr. r5,r5 + bne- L_mutex_lock_slow /* go to the slow path */ + stwcx. r6,0,r3 /* grab the lock */ + bne- L_mutex_lock_loop /* loop back if failed */ + isync /* stop prefeteching */ blr L_mutex_lock_slow: #endif @@ -988,9 +1005,8 @@ L_mutex_lock_assert_wait_1: .L_ml_retry: #if 0 mfsprg r4,0 /* (TEST/DEBUG) */ - lwz r4,PP_CPU_DATA(r4) /* (TEST/DEBUG) */ lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */ - lwz r4,CPU_ACTIVE_THREAD(r4) /* (TEST/DEBUG) */ + lwz r4,PP_ACTIVE_THREAD(r4) /* (TEST/DEBUG) */ lis r5,0xAAAA /* (TEST/DEBUG) */ oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */ sc /* (TEST/DEBUG) */ @@ -1018,19 +1034,17 @@ mlGotInt: have that, so, we're free to play */ lwz r4,LOCK_DATA(r3) /* Get the mutex's lock field */ - andi. r9,r4,MUTEX_LOCKED /* So, can we have it? */ - ori r10,r4,MUTEX_LOCKED /* Set the lock value */ + rlwinm. r9,r4,30,2,31 /* So, can we have it? */ bne- mlInUse /* Nope, sombody's playing already... */ #if MACH_LDEBUG - mfmsr r11 + mfmsr r11 ; Note: no need to deal with fp or vec here rlwinm r5,r11,0,MSR_EE_BIT+1,MSR_EE_BIT-1 mtmsr r5 mfsprg r9,0 /* Get the per_proc block */ lwz r5,0(r1) /* Get previous save frame */ - lwz r9,PP_CPU_DATA(r9) /* Point to the cpu data area */ lwz r5,FM_LR_SAVE(r5) /* Get our caller's address */ - lwz r8, CPU_ACTIVE_THREAD(r9) /* Get the active thread */ + lwz r8, PP_ACTIVE_THREAD(r9) /* Get the active thread */ stw r5,MUTEX_PC(r3) /* Save our caller */ mr. r8,r8 /* Is there any thread? */ stw r8,MUTEX_THREAD(r3) /* Set the mutex's holding thread */ @@ -1042,8 +1056,15 @@ mlGotInt: mtmsr r11 #endif /* MACH_LDEBUG */ - rlwinm r10,r10,0,0,30 /* Get the unlock value */ - stw r10,LOCK_DATA(r3) /* grab the mutexlock and free the interlock */ + bl EXT(mutex_lock_acquire) + mfsprg r5,1 + mr. r4,r3 + lwz r3,FM_ARG0(r1) + beq mlUnlock + ori r5,r5,WAIT_FLAG +mlUnlock: + sync + stw r5,LOCK_DATA(r3) /* grab the mutexlock and free the interlock */ #if ETAP_LOCK_TRACE mflr r4 @@ -1083,8 +1104,9 @@ mlInUse: /* Note that we come in here with the interlock set. The wait routine * will unlock it before waiting. */ - addis r4,r4,1 /* Bump the wait count */ + ori r4,r4,WAIT_FLAG /* Set the wait flag */ stw r4,LOCK_DATA(r3) + rlwinm r4,r4,0,0,29 /* Extract the lock owner */ bl EXT(mutex_lock_wait) /* Wait for our turn at the lock */ lwz r3,FM_ARG0(r1) /* restore r3 (saved in prolog) */ @@ -1102,14 +1124,14 @@ LEXT(mutex_try) .globl EXT(_mutex_try) LEXT(_mutex_try) #if !MACH_LDEBUG + mfsprg r6,1 /* load the current thread */ L_mutex_try_loop: - lwarx r5,0,r3 - andi. r4,r5,ILK_LOCKED|MUTEX_LOCKED - bne- L_mutex_try_slow - ori r5,r5,MUTEX_LOCKED - stwcx. r5,0,r3 - bne- L_mutex_try_loop - isync + lwarx r5,0,r3 /* load the lock value */ + mr. r5,r5 + bne- L_mutex_try_slow /* branch to the slow path */ + stwcx. r6,0,r3 /* grab the lock */ + bne- L_mutex_try_loop /* retry if failed */ + isync /* stop prefetching */ li r3, 1 blr L_mutex_try_slow: @@ -1134,7 +1156,7 @@ L_mutex_try_slow: CHECK_NO_SIMPLELOCKS() lwz r6,LOCK_DATA(r3) /* Quick check */ - andi. r6,r6,MUTEX_LOCKED /* to see if someone has this lock already */ + rlwinm. r6,r6,30,2,31 /* to see if someone has this lock already */ bne- mtFail /* Someone's got it already... */ bl lockDisa /* Go get a lock on the mutex's interlock lock */ @@ -1159,8 +1181,7 @@ mtGotInt: have that, so, we're free to play */ lwz r4,LOCK_DATA(r3) /* Get the mutex's lock field */ - andi. r9,r4,MUTEX_LOCKED /* So, can we have it? */ - ori r10,r4,MUTEX_LOCKED /* Set the lock value */ + rlwinm. r9,r4,30,2,31 /* So, can we have it? */ bne- mtInUse /* Nope, sombody's playing already... */ #if MACH_LDEBUG @@ -1169,9 +1190,8 @@ mtGotInt: mtmsr r5 mfsprg r9,0 /* Get the per_proc block */ lwz r5,0(r1) /* Get previous save frame */ - lwz r9,PP_CPU_DATA(r9) /* Point to the cpu data area */ lwz r5,FM_LR_SAVE(r5) /* Get our caller's address */ - lwz r8, CPU_ACTIVE_THREAD(r9) /* Get the active thread */ + lwz r8, PP_ACTIVE_THREAD(r9) /* Get the active thread */ stw r5,MUTEX_PC(r3) /* Save our caller */ mr. r8,r8 /* Is there any thread? */ stw r8,MUTEX_THREAD(r3) /* Set the mutex's holding thread */ @@ -1183,10 +1203,15 @@ mtGotInt: mtmsr r11 #endif /* MACH_LDEBUG */ - rlwinm r10,r10,0,0,30 /* Get the unlock value */ + bl EXT(mutex_lock_acquire) + mfsprg r5,1 + mr. r4,r3 + lwz r3,FM_ARG0(r1) + beq mtUnlock + ori r5,r5,WAIT_FLAG +mtUnlock: sync /* Push it all out */ - stw r10,LOCK_DATA(r3) /* grab the mutexlock and free the interlock */ - isync /* stop speculative instructions */ + stw r5,LOCK_DATA(r3) /* grab the mutexlock and free the interlock */ #if ETAP_LOCK_TRACE lwz r4,0(r1) /* Back chain the stack */ @@ -1208,8 +1233,8 @@ mtGotInt: */ mtInUse: - rlwinm r10,r10,0,0,30 /* Get the unlock value */ - stw r10,LOCK_DATA(r3) /* free the interlock */ + rlwinm r4,r4,0,0,30 /* Get the unlock value */ + stw r4,LOCK_DATA(r3) /* free the interlock */ bl epStart /* Go enable preemption... */ mtFail: li r3,0 /* Set failure code */ @@ -1226,14 +1251,14 @@ mtFail: li r3,0 /* Set failure code */ LEXT(mutex_unlock) #if !MACH_LDEBUG + sync L_mutex_unlock_loop: lwarx r5,0,r3 - rlwinm. r4,r5,16,15,31 /* Bail if pending waiter or interlock set */ - rlwinm r5,r5,0,0,29 /* Clear the mutexlock */ + rlwinm. r4,r5,0,30,31 /* Bail if pending waiter or interlock set */ + li r5,0 /* Clear the mutexlock */ bne- L_mutex_unlock_slow stwcx. r5,0,r3 bne- L_mutex_unlock_loop - sync blr L_mutex_unlock_slow: #endif @@ -1250,9 +1275,8 @@ L_mutex_unlock_slow: #if 0 mfsprg r4,0 /* (TEST/DEBUG) */ - lwz r4,PP_CPU_DATA(r4) /* (TEST/DEBUG) */ lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */ - lwz r4,CPU_ACTIVE_THREAD(r4) /* (TEST/DEBUG) */ + lwz r4,PP_ACTIVE_THREAD(r4) /* (TEST/DEBUG) */ lis r5,0xCCCC /* (TEST/DEBUG) */ oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */ sc /* (TEST/DEBUG) */ @@ -1274,14 +1298,14 @@ mutex_failed3: muGotInt: - lhz r5,LOCK_DATA(r3) - mr. r5,r5 /* are there any waiters ? */ + lwz r4,LOCK_DATA(r3) + andi. r5,r4,WAIT_FLAG /* are there any waiters ? */ + rlwinm r4,r4,0,0,29 beq+ muUnlock /* Nope, we're done... */ bl EXT(mutex_unlock_wakeup) /* yes, wake a thread */ lwz r3,FM_ARG0(r1) /* restore r3 (saved in prolog) */ - lhz r5,LOCK_DATA(r3) /* load the wait count */ - subi r5,r5,1 + lwz r5,LOCK_DATA(r3) /* load the lock */ muUnlock: #if MACH_LDEBUG @@ -1289,8 +1313,7 @@ muUnlock: rlwinm r9,r11,0,MSR_EE_BIT+1,MSR_EE_BIT-1 mtmsr r9 mfsprg r9,0 - lwz r9,PP_CPU_DATA(r9) - lwz r9,CPU_ACTIVE_THREAD(r9) + lwz r9,PP_ACTIVE_THREAD(r9) stw r9,MUTEX_THREAD(r3) /* disown thread */ cmpwi r9,0 beq- .L_mu_no_active_thread @@ -1301,7 +1324,7 @@ muUnlock: mtmsr r11 #endif /* MACH_LDEBUG */ - rlwinm r5,r5,16,0,15 /* Shift wait count */ + andi. r5,r5,WAIT_FLAG /* Get the unlock value */ sync /* Make sure it's all there before we release */ stw r5,LOCK_DATA(r3) /* unlock the interlock and lock */ @@ -1369,13 +1392,15 @@ epStart: cmplwi cr1,r1,0 /* Force non-zero cr so we know to check if preempted */ epCommn: mfmsr r9 /* Save the old MSR */ + rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r8,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */ mtmsr r8 /* Interrupts off */ - + isync ; May have mess with vec/fp here + mfsprg r3,0 /* Get the per_proc block */ - lwz r6,PP_CPU_DATA(r3) /* Get the pointer to the CPU data from per proc */ li r8,-1 /* Get a decrimenter */ - lwz r5,CPU_PREEMPTION_LEVEL(r6) /* Get the preemption level */ + lwz r5,PP_PREEMPT_CNT(r3) /* Get the preemption level */ add. r5,r5,r8 /* Bring down the disable count */ #if 0 mfsprg r4,1 ; (TEST/DEBUG) Note the next 3 keep from interrpting too early @@ -1390,7 +1415,7 @@ epskptrc0: mr. r5,r5 ; (TEST/DEBUG) #if MACH_LDEBUG blt- epTooFar /* Yeah, we did... */ #endif /* MACH_LDEBUG */ - stw r5,CPU_PREEMPTION_LEVEL(r6) /* Save it back */ + stw r5,PP_PREEMPT_CNT(r3) /* Save it back */ beq+ epCheckPreempt /* Go check if we need to be preempted... */ @@ -1454,14 +1479,16 @@ epCPno: mtmsr r9 /* Allow interrupts if we can */ LEXT(_disable_preemption) daPreAll: mfmsr r9 /* Save the old MSR */ + rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r8,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */ mtmsr r8 /* Interrupts off */ + isync ; May have mess with fp/vec daPreComm: mfsprg r6,0 /* Get the per_proc block */ - lwz r6,PP_CPU_DATA(r6) /* Get the pointer to the CPU data from per proc */ - lwz r5,CPU_PREEMPTION_LEVEL(r6) /* Get the preemption level */ + lwz r5,PP_PREEMPT_CNT(r6) /* Get the preemption level */ addi r5,r5,1 /* Bring up the disable count */ - stw r5,CPU_PREEMPTION_LEVEL(r6) /* Save it back */ + stw r5,PP_PREEMPT_CNT(r6) /* Save it back */ #if 0 mfsprg r4,1 ; (TEST/DEBUG) Note the next 3 keep from interrpting too early mr. r4,r4 ; (TEST/DEBUG) @@ -1550,15 +1577,83 @@ nopredeb: LEXT(current_thread) +#if 1 + mfsprg r3,1 + lwz r3,ACT_THREAD(r3) + blr +#else + mfmsr r9 /* Save the old MSR */ + rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off + rlwinm r8,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */ + mtmsr r8 /* Interrupts off */ + isync + mfsprg r6,0 /* Get the per_proc */ + lwz r3,PP_ACTIVE_THREAD(r6) /* Get the active thread */ + mfsprg r4,1 + lwz r4,ACT_THREAD(r4) + cmplw cr0,r4,r3 + beq current_thread_cont + lis r5,hi16(L_current_thread_paniced) + ori r5,r5,lo16(L_current_thread_paniced) + lwz r6,0(r5) + mr. r6,r6 + bne current_thread_cont + stw r9,0(r5) + mr r5,r4 + mr r4,r3 + lis r3,hi16(L_current_thread_panic) + ori r3,r3,lo16(L_current_thread_panic) + bl EXT(panic) + + .data +L_current_thread_panic: + STRINGD "current_thread: spr1 not sync %x %x %x\n\000" +L_current_thread_paniced: + .long 0 + .text +current_thread_cont: +#endif + mtmsr r9 /* Restore interruptions to entry */ + blr /* Return... */ + +/* + * Set the active thread + */ + .align 5 + .globl EXT(set_machine_current_thread) +LEXT(set_machine_current_thread) + mfmsr r9 /* Save the old MSR */ + rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r8,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */ mtmsr r8 /* Interrupts off */ + isync ; May have messed with fp/vec mfsprg r6,0 /* Get the per_proc */ - lwz r6,PP_CPU_DATA(r6) /* Get the pointer to the CPU data from per proc */ - lwz r3,CPU_ACTIVE_THREAD(r6) /* Get the active thread */ + stw r3,PP_ACTIVE_THREAD(r6) /* Set the active thread */ mtmsr r9 /* Restore interruptions to entry */ blr /* Return... */ +/* + * Set the current activation + */ + .align 5 + .globl EXT(set_machine_current_act) +LEXT(set_machine_current_act) + mtsprg 1,r3 /* Set spr1 with the active thread */ + blr /* Return... */ + +/* + * Return the current activation + */ + .align 5 + .globl EXT(current_act) +LEXT(current_act) + mfsprg r3,1 + blr + + /* * Return the current preemption level @@ -1570,15 +1665,31 @@ LEXT(current_thread) LEXT(get_preemption_level) mfmsr r9 /* Save the old MSR */ + rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r8,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */ mtmsr r8 /* Interrupts off */ + isync mfsprg r6,0 /* Get the per_proc */ - lwz r6,PP_CPU_DATA(r6) /* Get the pointer to the CPU data from per proc */ - lwz r3,CPU_PREEMPTION_LEVEL(r6) /* Get the preemption level */ + lwz r3,PP_PREEMPT_CNT(r6) /* Get the preemption level */ mtmsr r9 /* Restore interruptions to entry */ blr /* Return... */ +/* + * Return the cpu_data + */ + + .align 5 + .globl EXT(get_cpu_data) + +LEXT(get_cpu_data) + + mfsprg r3,0 /* Get the per_proc */ + addi r3,r3,PP_ACTIVE_THREAD /* Get the pointer to the CPU data from per proc */ + blr /* Return... */ + + /* * Return the simple lock count */ @@ -1589,11 +1700,13 @@ LEXT(get_preemption_level) LEXT(get_simple_lock_count) mfmsr r9 /* Save the old MSR */ + rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r8,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */ mtmsr r8 /* Interrupts off */ + isync ; May have messed with vec/fp mfsprg r6,0 /* Get the per_proc */ - lwz r6,PP_CPU_DATA(r6) /* Get the pointer to the CPU data from per proc */ - lwz r3,CPU_SIMPLE_LOCK_COUNT(r6) /* Get the simple lock count */ + lwz r3,PP_SIMPLE_LOCK_CNT(r6) /* Get the simple lock count */ mtmsr r9 /* Restore interruptions to entry */ blr /* Return... */ @@ -1609,6 +1722,9 @@ LEXT(get_simple_lock_count) LEXT(fast_usimple_lock) +#if CHECKNMI + b EXT(usimple_lock) ; (TEST/DEBUG) +#endif mfmsr r9 andi. r7,r9,lo16(MASK(MSR_EE)) bne- L_usimple_lock_c @@ -1636,6 +1752,9 @@ L_usimple_lock_c: LEXT(fast_usimple_lock_try) +#if CHECKNMI + b EXT(usimple_lock_try) ; (TEST/DEBUG) +#endif mfmsr r9 andi. r7,r9,lo16(MASK(MSR_EE)) bne- L_usimple_lock_try_c @@ -1666,6 +1785,9 @@ L_usimple_lock_try_c: LEXT(fast_usimple_unlock) +#if CHECKNMI + b EXT(usimple_unlock) ; (TEST/DEBUG) +#endif lwz r5,LOCK_DATA(r3) li r0,0 cmpi cr0,r5,ILK_LOCKED|SLOCK_FAST @@ -1690,3 +1812,99 @@ L_usimple_unlock_cont: L_usimple_unlock_c: b EXT(usimple_unlock) +/* + * enter_funnel_section(): + * + */ + .align 5 + .globl EXT(enter_funnel_section) + +LEXT(enter_funnel_section) + +#if !MACH_LDEBUG + lis r10,hi16(EXT(kdebug_enable)) + ori r10,r10,lo16(EXT(kdebug_enable)) + lwz r10,0(r10) + lis r11,hi16(EXT(split_funnel_off)) + ori r11,r11,lo16(EXT(split_funnel_off)) + lwz r11,0(r11) + or. r10,r11,r10 ; Check kdebug_enable or split_funnel_off + bne- L_enter_funnel_section_slow1 ; If set, call the slow path + mfsprg r6,1 ; Get the current activation + lwz r7,LOCK_FNL_MUTEX(r3) + mfmsr r11 + rlwinm r11,r11,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r11,r11,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off + rlwinm r10,r11,0,MSR_EE_BIT+1,MSR_EE_BIT-1 + mtmsr r10 ; Turn off EE + isync ; May have messed with vec/fp + mr r9,r6 +L_enter_funnel_section_loop: + lwarx r5,0,r7 ; Load the mutex lock + mr. r5,r5 + bne- L_enter_funnel_section_slow ; Go to the slow path + stwcx. r6,0,r7 ; Grab the lock + bne- L_enter_funnel_section_loop ; Loop back if failed + isync ; Stop prefeteching + lwz r6,ACT_THREAD(r6) ; Get the current thread + li r7,TH_FN_OWNED + stw r7,THREAD_FUNNEL_STATE(r6) ; Set the funnel state + stw r3,THREAD_FUNNEL_LOCK(r6) ; Set the funnel lock reference + mtmsr r11 + blr + +L_enter_funnel_section_slow: + mtmsr r11 +L_enter_funnel_section_slow1: +#endif + li r4,TRUE + b EXT(thread_funnel_set) + +/* + * exit_funnel_section(): + * + */ + .align 5 + .globl EXT(exit_funnel_section) + +LEXT(exit_funnel_section) + +#if !MACH_LDEBUG + mfsprg r6,1 ; Get the current activation + lwz r6,ACT_THREAD(r6) ; Get the current thread + lwz r3,THREAD_FUNNEL_LOCK(r6) ; Get the funnel lock + mr. r3,r3 ; Check on funnel held + beq- L_exit_funnel_section_ret ; + lis r10,hi16(EXT(kdebug_enable)) + ori r10,r10,lo16(EXT(kdebug_enable)) + lwz r10,0(r10) + mr. r10,r10 + bne- L_exit_funnel_section_slow1 ; If set, call the slow path + lwz r7,LOCK_FNL_MUTEX(r3) ; Get the funnel mutex lock + mfmsr r11 + rlwinm r11,r11,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r11,r11,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off + rlwinm r10,r11,0,MSR_EE_BIT+1,MSR_EE_BIT-1 + mtmsr r10 ; Turn off EE + isync ; May have messed with fp/vec + sync +L_exit_funnel_section_loop: + lwarx r5,0,r7 + rlwinm. r4,r5,0,30,31 ; Bail if pending waiter or interlock set + li r5,0 ; Clear the mutexlock + bne- L_exit_funnel_section_slow + stwcx. r5,0,r7 ; Release the funnel mutexlock + bne- L_exit_funnel_section_loop + li r7,0 + stw r7,THREAD_FUNNEL_STATE(r6) ; Clear the funnel state + stw r7,THREAD_FUNNEL_LOCK(r6) ; Clear the funnel lock reference + mtmsr r11 +L_exit_funnel_section_ret: + blr +L_exit_funnel_section_slow: + mtmsr r11 +L_exit_funnel_section_slow1: +#endif + li r4,FALSE + b EXT(thread_funnel_set) + diff --git a/osfmk/ppc/hw_lock_types.h b/osfmk/ppc/hw_lock_types.h index 73ac50030..54ffa016c 100644 --- a/osfmk/ppc/hw_lock_types.h +++ b/osfmk/ppc/hw_lock_types.h @@ -90,4 +90,21 @@ struct hslock { typedef struct hslock hw_lock_data_t, *hw_lock_t; #define hw_lock_addr(hwl) (&((hwl).lock_data)) + +#if defined(MACH_KERNEL_PRIVATE) + +#include +#include + +#if !(NCPUS == 1 || MACH_LDEBUG) + +typedef hw_lock_data_t simple_lock_data_t; +typedef hw_lock_data_t *simple_lock_t; + +#define decl_simple_lock_data(class, name) \ +class hw_lock_data_t name; +#endif + +#endif + #endif /* _PPC_HW_LOCK_TYPES_H_ */ diff --git a/osfmk/ppc/hw_vm.s b/osfmk/ppc/hw_vm.s index 18b11ef36..640a637f6 100644 --- a/osfmk/ppc/hw_vm.s +++ b/osfmk/ppc/hw_vm.s @@ -116,8 +116,10 @@ LEXT(hw_add_map) mfmsr r0 /* Get the MSR */ eqv r6,r6,r6 /* Fill the bottom with foxes */ + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off rlwinm r11,r4,6,6,25 /* Position the space for the VSID */ mfspr r10,sdr1 /* Get hash table base and size */ + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwimi r11,r5,30,2,5 /* Insert the segment no. to make a VSID */ mfsprg r12,2 ; Get feature flags rlwimi r6,r10,16,0,15 /* Make table size -1 out of mask */ @@ -165,8 +167,6 @@ hamNoMSRx: dcbt 0,r4 /* We'll need the hash area in a sec, so get it */ add r4,r4,r9 /* Point to the right mapping hash slot */ - lwarx r10,0,r8 ; ? - ptegLckx: lwarx r10,0,r8 /* Get the PTEG lock */ mr. r10,r10 /* Is it locked? */ bne- ptegLckwx /* Yeah... */ @@ -264,9 +264,11 @@ LEXT(hw_lock_phys_vir) eqv r6,r6,r6 /* Fill the bottom with foxes */ mfsprg r9,2 ; Get feature flags rlwinm r11,r3,6,6,25 /* Position the space for the VSID */ + rlwinm r12,r12,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off mfspr r5,sdr1 /* Get hash table base and size */ rlwimi r11,r4,30,2,5 /* Insert the segment no. to make a VSID */ mtcrf 0x04,r9 ; Set the features + rlwinm r12,r12,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwimi r6,r5,16,0,15 /* Make table size -1 out of mask */ andi. r0,r12,0x7FCF /* Disable translation and interruptions */ rlwinm r9,r4,4,0,3 ; Move nybble 1 up to 0 @@ -307,8 +309,6 @@ hlpNoMSRx: dcbt 0,r3 /* We'll need the hash area in a sec, so get it */ add r3,r3,r9 /* Point to the right mapping hash slot */ - lwarx r10,0,r8 ; ? - ptegLcka: lwarx r10,0,r8 /* Get the PTEG lock */ li r5,1 /* Get the locked value */ mr. r10,r10 /* Is it locked? */ @@ -459,6 +459,8 @@ LEXT(hw_rem_map) #endif mfsprg r9,2 ; Get feature flags mfmsr r0 /* Save the MSR */ + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r12,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */ mtcrf 0x04,r9 ; Set the features rlwinm r12,r12,0,28,25 /* Clear IR and DR */ @@ -489,8 +491,6 @@ lmvNoMSRx: li r12,1 /* Get the locked value */ subi r6,r6,mmhashnext /* Make the anchor look like an entry */ - lwarx r10,0,r7 ; ? - ptegLck1: lwarx r10,0,r7 /* Get the PTEG lock */ mr. r10,r10 /* Is it locked? */ bne- ptegLckw1 /* Yeah... */ @@ -547,8 +547,6 @@ mapok: lwz r6,mmhashnext(r6) /* Look at the next one */ cmplwi cr1,r11,3 /* Is this a 603? */ sync /* Make sure the invalid is stored */ - lwarx r5,0,r12 ; ? - tlbhang1: lwarx r5,0,r12 /* Get the TLBIE lock */ rlwinm r11,r4,29,29,31 /* Get the bit position of entry */ mr. r5,r5 /* Is it locked? */ @@ -590,8 +588,6 @@ nopte: mr. r10,r10 /* See if there is a physical entry */ lwz r6,4(r4) /* Get the latest reference and change bits */ la r12,pepte1(r10) /* Point right at the master copy */ rlwinm r6,r6,0,23,24 /* Extract just the RC bits */ - - lwarx r8,0,r12 ; ? mrgrc: lwarx r8,0,r12 /* Get the master copy */ or r8,r8,r6 /* Merge in latest RC */ @@ -600,10 +596,12 @@ mrgrc: lwarx r8,0,r12 /* Get the master copy */ nadamrg: li r11,0 /* Clear this out */ lwz r12,mmnext(r3) /* Prime with our next */ + + sync ; Make sure all is saved + stw r11,0(r7) /* Unlock the hash chain now so we don't - lock out another processor during the - our next little search */ - + lock out another processor during + our next little search */ srchpmap: mr. r10,r9 /* Save the previous entry */ bne+ mapok1 /* No error... */ @@ -686,8 +684,10 @@ LEXT(hw_prot) #endif mfsprg r9,2 ; Get feature flags mfmsr r0 /* Save the MSR */ - rlwinm r12,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */ li r5,pepte1 /* Get displacement to the second word of master pte */ + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off + rlwinm r12,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */ mtcrf 0x04,r9 ; Set the features rlwinm r12,r12,0,28,25 /* Clear IR and DR */ @@ -719,8 +719,6 @@ hpNoMSRx: * done via interlocked update. */ - lwarx r8,r5,r3 ; ? - protcng: lwarx r8,r5,r3 /* Get the master copy */ rlwimi r8,r4,0,30,31 /* Move in the protection bits */ stwcx. r8,r5,r3 /* Save it back */ @@ -737,8 +735,6 @@ protnext: mr. r10,r10 /* Are there any more mappings? */ li r12,1 /* Get the locked value */ - lwarx r11,0,r7 ; ? - protLck1: lwarx r11,0,r7 /* Get the PTEG lock */ mr. r11,r11 /* Is it locked? */ bne- protLckw1 /* Yeah... */ @@ -780,8 +776,6 @@ protSXg1: isync /* Make sure we haven't used anything yet */ cmplwi cr1,r11,3 /* Is this a 603? */ sync /* Make sure the invalid is stored */ - lwarx r11,0,r12 ; ? - tlbhangp: lwarx r11,0,r12 /* Get the TLBIE lock */ rlwinm r8,r6,29,29,31 /* Get the bit position of entry */ mr. r11,r11 /* Is it locked? */ @@ -817,17 +811,17 @@ its603p: stw r11,0(r12) /* Clear the lock */ li r5,pepte1 /* Get displacement to the second word of master pte */ stw r9,PCAallo(r7) /* Store the allocation controls */ - lwarx r11,r5,r3 ; ? protmod: lwarx r11,r5,r3 /* Get the master copy */ or r11,r11,r6 /* Merge in latest RC */ stwcx. r11,r5,r3 /* Save it back */ bne- protmod /* If it changed, try again... */ - sync /* Make sure that chain is updated */ - protul: li r4,0 /* Get a 0 */ stw r2,mmPTEr(r10) ; Save the updated mapping PTE lwz r10,mmnext(r10) /* Get the next */ + + sync ; Make sure stores are complete + stw r4,0(r7) /* Unlock the hash chain */ b protnext /* Go get the next one */ @@ -879,6 +873,8 @@ LEXT(hw_prot_virt) #endif mfsprg r9,2 ; Get feature flags mfmsr r0 /* Save the MSR */ + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r12,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */ mtcrf 0x04,r9 ; Set the features rlwinm r12,r12,0,28,25 /* Clear IR and DR */ @@ -914,8 +910,6 @@ hpvNoMSRx: li r12,1 /* Get the locked value */ - lwarx r11,0,r7 ; ? - protvLck1: lwarx r11,0,r7 /* Get the PTEG lock */ mr. r11,r11 /* Is it locked? */ bne- protvLckw1 /* Yeah... */ @@ -957,8 +951,6 @@ protvSXg1: isync /* Make sure we haven't used anything yet */ cmplwi cr1,r11,3 /* Is this a 603? */ sync /* Make sure the invalid is stored */ - lwarx r11,0,r12 ; ? - tlbhangpv: lwarx r11,0,r12 /* Get the TLBIE lock */ rlwinm r8,r6,29,29,31 /* Get the bit position of entry */ mr. r11,r11 /* Is it locked? */ @@ -997,18 +989,16 @@ its603pv: stw r11,0(r12) /* Clear the lock */ rlwimi r2,r6,0,23,24 ; Stick in RC bits beq- pvnophys ; No physical entry... - - lwarx r11,r5,r10 ; ? - protvmod: lwarx r11,r5,r10 /* Get the master copy */ or r11,r11,r6 /* Merge in latest RC */ stwcx. r11,r5,r10 /* Save it back */ bne- protvmod /* If it changed, try again... */ - sync /* Make sure that chain is updated */ - pvnophys: li r4,0 /* Get a 0 */ stw r2,mmPTEr(r3) ; Set the real part of the PTE + + sync ; Make sure everything is stored + stw r4,0(r7) /* Unlock the hash chain */ mtmsr r0 ; Restore interrupts and translation isync @@ -1057,6 +1047,8 @@ LEXT(hw_attr_virt) #endif mfsprg r9,2 ; Get feature flags mfmsr r0 /* Save the MSR */ + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off mtcrf 0x04,r9 ; Set the features rlwinm r12,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */ rlwinm r12,r12,0,28,25 /* Clear IR and DR */ @@ -1090,8 +1082,6 @@ havNoMSRx: li r12,1 /* Get the locked value */ - lwarx r11,0,r7 ; ? - attrvLck1: lwarx r11,0,r7 /* Get the PTEG lock */ mr. r11,r11 /* Is it locked? */ bne- attrvLckw1 /* Yeah... */ @@ -1132,8 +1122,6 @@ attrvSXg1: isync /* Make sure we haven't used anything yet */ cmplwi cr1,r11,3 /* Is this a 603? */ sync /* Make sure the invalid is stored */ - lwarx r11,0,r12 ; ? - tlbhangav: lwarx r11,0,r12 /* Get the TLBIE lock */ rlwinm r8,r6,29,29,31 /* Get the bit position of entry */ mr. r11,r11 /* Is it locked? */ @@ -1172,17 +1160,16 @@ its603av: stw r11,0(r12) /* Clear the lock */ rlwimi r2,r6,0,23,24 ; Stick in RC bits beq- avnophys ; No physical entry... - lwarx r11,r5,r10 ; ? - attrvmod: lwarx r11,r5,r10 /* Get the master copy */ or r11,r11,r6 /* Merge in latest RC */ stwcx. r11,r5,r10 /* Save it back */ bne- attrvmod /* If it changed, try again... */ - sync /* Make sure that chain is updated */ - avnophys: li r4,0 /* Get a 0 */ stw r2,mmPTEr(r3) ; Set the real part of the PTE + + sync ; Make sure that everything is updated + stw r4,0(r7) /* Unlock the hash chain */ rlwinm r2,r2,0,0,19 ; Clear back to page boundary @@ -1197,7 +1184,6 @@ attrflsh: cmplwi r4,(4096-32) ; Are we about to do the last line on page? attrimvl: cmplwi r4,(4096-32) ; Are we about to do the last line on page? dcbi r2,r4 ; Invalidate dcache because we changed attributes icbi r2,r4 ; Invalidate icache because we changed attributes - icbi r2,r4 ; Invalidate icache because we changed attributes addi r4,r4,32 ; Bump up cache blt+ attrimvl ; Do the whole page... sync @@ -1334,6 +1320,8 @@ hw_pte_comm: /* Common routine for pte tests and manips */ lwz r10,pephyslink(r3) /* Get the first mapping block */ mfmsr r0 /* Save the MSR */ rlwinm. r10,r10,0,0,26 ; Clear out the flags from first link and see if we are mapped + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r12,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */ mtcrf 0x04,r8 ; Set the features rlwinm r12,r12,0,28,25 /* Clear IR and DR */ @@ -1375,8 +1363,6 @@ commnext: lwz r11,mmnext(r10) ; Get the pointer to the next mapping (if any) commnxtch: li r12,1 /* Get the locked value */ - lwarx r11,0,r7 ; ? - commLck1: lwarx r11,0,r7 /* Get the PTEG lock */ mr. r11,r11 /* Is it locked? */ bne- commLckw1 /* Yeah... */ @@ -1414,8 +1400,6 @@ commSXg1: isync /* Make sure we haven't used anything yet */ mfspr r4,pvr /* Find out what kind of machine we are */ sync /* Make sure the invalid is stored */ - lwarx r11,0,r12 ; ? - tlbhangco: lwarx r11,0,r12 /* Get the TLBIE lock */ rlwinm r8,r6,29,29,31 /* Get the bit position of entry */ mr. r11,r11 /* Is it locked? */ @@ -1452,13 +1436,10 @@ its603co: stw r11,0(r12) /* Clear the lock */ li r5,pepte1 /* Get displacement to the second word of master pte */ stw r9,PCAallo(r7) /* Store the allocation controls */ - lwarx r11,r5,r3 ; ? commmod: lwarx r11,r5,r3 /* Get the master copy */ or r11,r11,r4 /* Merge in latest RC */ stwcx. r11,r5,r3 /* Save it back */ bne- commmod /* If it changed, try again... */ - - sync /* Make sure that chain is updated */ b commulnl ; Skip loading the old real part... commul: lwz r6,mmPTEr(r10) ; Get the real part @@ -1474,6 +1455,9 @@ commulnl: rlwinm r12,r2,5,23,24 ; Get the "set" bits lwz r10,mmnext(r10) /* Get the next */ li r4,0 /* Make sure this is 0 */ mr. r10,r10 ; Is there another mapping? + + sync ; Make sure that all is saved + stw r4,0(r7) /* Unlock the hash chain */ bne+ commnext ; Go get the next if there is one... @@ -1502,8 +1486,6 @@ commdone: li r5,pepte1 /* Get displacement to the second word of master pte rlwinm r12,r2,5,23,24 ; Get the "set" bits rlwinm r11,r2,7,23,24 ; Get the "clear" bits - lwarx r8,r5,r3 ; ? - commcng: lwarx r8,r5,r3 /* Get the master copy */ or r8,r8,r12 ; Set the bits to come on andc r8,r8,r11 ; Clear those to come off @@ -1583,7 +1565,9 @@ LEXT(hw_test_rc) mfsprg r9,2 ; Get feature flags mfmsr r0 ; Save the MSR + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off mr. r4,r4 ; See if we have a reset to do later + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r12,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear interruption mask crnot htrReset,cr0_eq ; Remember reset mtcrf 0x04,r9 ; Set the features @@ -1697,17 +1681,19 @@ htrmrc: lwarx r11,r5,r10 ; Get the master copy or r11,r11,r6 ; Merge in latest RC stwcx. r11,r5,r10 ; Save it back bne- htrmrc ; If it changed, try again... - - sync ; Make sure that chain update is stored -htrnopte: rlwinm r3,r2,25,30,31 ; Position RC and mask off +htrnopte: rlwinm r5,r2,25,30,31 ; Position RC and mask off bf htrReset,htrnorst ; No reset to do... rlwinm r2,r2,0,25,22 ; Clear the RC if requested htrnorst: li r4,0 ; Get a 0 stw r2,mmPTEr(r3) ; Set the real part of the PTE + + sync ; Make sure that stuff is all stored + stw r4,0(r7) ; Unlock the hash chain + mr r3,r5 ; Get the old RC to pass back mtmsr r0 ; Restore interrupts and translation isync blr ; Return... @@ -1750,6 +1736,8 @@ LEXT(hw_phys_attr) #endif mfsprg r9,2 ; Get feature flags mfmsr r0 /* Save the MSR */ + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off andi. r5,r5,0x0078 /* Clean up the WIMG */ rlwinm r12,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */ mtcrf 0x04,r9 ; Set the features @@ -1917,7 +1905,6 @@ havevsid: mfspr r5,sdr1 /* Get hash table base and size */ dcbt 0,r11 /* We'll need the hash area in a sec, so get it */ add r11,r11,r9 /* Point to the right mapping hash slot */ - lwarx r10,0,r8 ; ? ptegLck: lwarx r10,0,r8 /* Get the PTEG lock */ mr. r10,r10 /* Is it locked? */ bne- ptegLckw /* Yeah... */ @@ -1976,7 +1963,7 @@ gotphys: lwz r2,mmPTEr(r12) ; Get the second part of the PTE MustBeOK: li r10,0 /* Get lock clear value */ li r3,T_IN_VAIN /* Say that we handled it */ stw r10,PCAlock(r8) /* Clear the PTEG lock */ - sync + #if PERFTIMES && DEBUG mflr r11 mr r4,r3 @@ -2100,7 +2087,11 @@ findAuto: mr. r4,r4 ; Is there more? lwz r4,bmnext(r4) ; Get the next one b findAuto ; Check it out... -faGot: rlwinm r6,r6,0,0,19 ; Round to page +faGot: + lwz r7,blkFlags(r4) ; Get the flags + rlwinm. r7,r7,0,blkRembit,blkRembit ; is this mapping partially removed + bne bmapNone ; Pending remove, bail out + rlwinm r6,r6,0,0,19 ; Round to page lwz r2,bmPTEr(r4) ; Get the real part of the PTE sub r5,r6,r5 ; Get offset into area stw r9,0(r10) ; Unlock it, we are done with it (no sync needed) @@ -2250,8 +2241,6 @@ wasauto: oris r3,r3,0x8000 /* Turn on the valid bit */ xor r4,r4,r5 ; Finish splooching nybble 0, 1, and the low bits of the VSID - lwarx r5,0,r9 ; ? - tlbhang: lwarx r5,0,r9 /* Get the TLBIE lock */ rlwinm r4,r4,0,27,29 ; Clean up splooched hash value @@ -2321,8 +2310,6 @@ nomove: li r5,0 /* Clear this on out */ rlwinm r11,r9,0,23,24 /* Keep only the RC bits */ - lwarx r9,r5,r12 ; ? - mrgmrcx: lwarx r9,r5,r12 /* Get the master copy */ or r9,r9,r11 /* Merge in latest RC */ stwcx. r9,r5,r12 /* Save it back */ @@ -2368,6 +2355,8 @@ ENTRY(LRA, TAG_NO_FRAME_USED) mfsprg r8,2 ; Get feature flags mfmsr r10 /* Save the current MSR */ + rlwinm r10,r10,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r10,r10,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off mtcrf 0x04,r8 ; Set the features xoris r5,r3,HIGH_ADDR(PPC_SID_KERNEL) /* Clear the top half if equal */ andi. r9,r10,0x7FCF /* Turn off interrupts and translation */ @@ -2441,6 +2430,7 @@ fndbat: rlwinm r6,r6,0,0,14 /* Clean up the real address */ add r3,r7,r6 /* Relocate the offset to real */ isync /* Purge pipe */ blr /* Bye, bye... */ + notkernsp: mfspr r5,sdr1 /* Get hash table base and size */ rlwimi r11,r4,30,2,5 /* Insert the segment no. to make a VSID */ rlwimi r12,r5,16,0,15 /* Make table size -1 out of mask */ @@ -2497,6 +2487,8 @@ LEXT(hw_add_blk) mfsprg r9,2 ; Get feature flags lwz r6,PMAP_PMAPVR(r3) ; Get the v to r translation mfmsr r0 /* Save the MSR */ + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r12,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */ mtcrf 0x04,r9 ; Set the features xor r3,r3,r6 ; Get real address of bmap anchor @@ -2565,6 +2557,11 @@ abChk: mr. r10,r2 ; End of chain? crand cr1_eq,cr1_eq,cr6_eq ; Set cr1_eq if no overlap beq+ cr1,abChk ; Ok check the next... + lwz r8,blkFlags(r10) ; Get the flags + rlwinm. r8,r8,0,blkRembit,blkRembit ; Check the blkRem bit + beq abRet ; Is the mapping partially removed + ori r10,r10,2 ; Indicate that this block is partially removed +abRet: stw r9,0(r3) ; Unlock mtmsr r0 ; Restore xlation and rupts mr r3,r10 ; Pass back the overlap @@ -2614,6 +2611,8 @@ LEXT(hw_rem_blk) mfsprg r9,2 ; Get feature flags lwz r6,PMAP_PMAPVR(r3) ; Get the v to r translation mfmsr r0 /* Save the MSR */ + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r12,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */ mtcrf 0x04,r9 ; Set the features xor r3,r3,r6 ; Get real address of bmap anchor @@ -2635,6 +2634,14 @@ hrbNoMSR: mr r3,r8 mr r0,r9 hrbNoMSRx: + li r7,0 + cmp cr5,r0,r7 ; Request to invalidate the ptes + b rbLck + +rbunlink: + lwz r4,bmstart(r10) ; Get start of current mapping + lwz r5,bmend(r10) ; Get end of current mapping + cmp cr5,r3,r3 ; Request to unlink the mapping rbLck: lwarx r9,0,r3 ; Get the block map anchor and lock rlwinm. r8,r9,0,31,31 ; Is it locked? @@ -2673,19 +2680,58 @@ rbChk: mr r12,r10 ; Save the previous cror cr1_eq,cr0_lt,cr1_gt ; Set cr1_eq if new not in range lwz r2,bmnext(r10) ; Get the next one beq+ cr1,rbChk ; Not this one, check the next... + + cmplw cr1,r12,r3 ; Is the current mapping the first one? + + bne cr5,rbblkRem ; Do we have to unchain the mapping + + bne cr1,rbnFirst ; Yes, is this the first mapping? + rlwimi r9,r2,0,0,26 ; Yes, Change the lock value + ori r2,r9,1 ; Turn on the lock bit +rbnFirst: + stw r2,bmnext(r12) ; Unchain us + sync + b rbDone + +rbblkRem: lwz r8,blkFlags(r10) ; Get the flags - cmplw cr1,r12,r3 ; Did we delete the first one? - rlwinm. r8,r8,0,blkPermbit,blkPermbit ; is this a permanent block? - bne cr1,rbnFirst ; Nope... - rlwimi r9,r2,0,0,26 ; Change the lock value - ori r2,r9,1 ; Turn on the lock bit + rlwinm. r7,r8,0,blkPermbit,blkPermbit ; is this a permanent block? -rbnFirst: bne- rbPerm ; This is permanent, do not remove... - lwz r8,bmspace(r10) ; Get the VSID - stw r2,bmnext(r12) ; Unchain us + bne- rbPerm ; This is permanent, do not remove... + + rlwinm. r7,r8,0,blkRembit,blkRembit ; is this mapping partially removed + + beq rbblkRemcont ; If not, check the max size + lwz r11,bmcurrent(r10) ; If yes, resume for the current page + + cmp cr5,r11,r6 ; No partial remove left + beq cr5, rbpendret ; But there is a pending remove + +rbblkRemcont: + bne rbblkRemcont1 ; Is it the first remove + oris r8,r8,hi16(blkRem) ; Yes + stw r8,blkFlags(r10) ; set the blkRem bit in blkFlags + +rbblkRemcont1: + lis r5,hi16(BLKREMMAX*4096) ; Load maximun size tear down + ori r5,r5,lo16(BLKREMMAX*4096) ; Load maximun size tear down + sub r7,r6,r11 ; Get the remaining size to tear down + cmp cr5,r7,r5 ; Compare against the maximun size + ble cr5,rbfullblk ; If less or equal, go remove the mapping + + add r7,r11,r5 ; Add the max size tear down to the current page + stw r7,bmcurrent(r10) ; Update the current page + subi r6,r7,1 ; Set the current end of the partial tear down + b rbcont + +rbfullblk: + stw r6,bmcurrent(r10) ; Update the current page + +rbcont: + lwz r8,bmspace(r10) ; Get the VSID sync stw r9,0(r3) ; Unlock and chain the new first one @@ -2802,11 +2848,22 @@ rbits603a: sync ; Wait for quiet again sync ; Make sure that is done + ble cr5,rbunlink ; If all ptes are flush, go unlink the mapping mtmsr r0 ; Restore xlation and rupts - mr r3,r10 ; Pass back the removed block + mr r3,r10 ; Pass back the removed block in progress + ori r3,r3,2 ; Indicate that the block remove isn't completed yet isync blr ; Return... - + +rbpendret: + stw r9,0(r3) ; Unlock + mtmsr r0 ; Restore xlation and rupts + mr r3,r10 ; Pass back the removed block in progress + ori r3,r3,2 ; Indicate that the block remove isn't completed yet + isync + blr ; Return... + + rbMT: stw r9,0(r3) ; Unlock mtmsr r0 ; Restore xlation and rupts li r3,0 ; Say we did not find one @@ -2819,6 +2876,120 @@ rbPerm: stw r9,0(r3) ; Unlock isync blr ; Return... +rbDone: stw r9,0(r3) ; Unlock + mtmsr r0 ; Restore xlation and rupts + mr r3,r10 ; Pass back the removed block + isync + blr ; Return... + +/* + * hw_select_mappings(struct mappingflush *mappingflush) + * + * Input: PCA addr + * Ouput: up to 8 user mappings + * + * hw_select_mappings() scans every PCA mapping hash lists and select + * the last user mapping if it exists. + * + */ + + .align 5 + .globl EXT(hw_select_mappings) + +LEXT(hw_select_mappings) + mr r5,r3 ; Get the mapping flush addr + mfmsr r12 ; Get the MSR + rlwinm r12,r12,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r12,r12,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off + mfsprg r9,2 ; Get feature flags + andi. r0,r12,0x7FCF ; Disable translation and interruptions + mtcrf 0x04,r9 ; Set the features + bt pfNoMSRirb,hvmNoMSR ; No MSR... + mtmsr r0 + isync + b hvmNoMSRx +hvmNoMSR: + mr r3,r0 ; Get the new MSR + li r0,loadMSR ; Get the MSR setter SC + sc +hvmNoMSRx: + mr r0,r12 + li r11,1 ; Get the locked value + +hvmptegLckx: + lwz r3,MFpcaptr(r5) ; Get the PCA pointer + lwarx r10,0,r3 ; Get the PTEG lock + mr. r10,r10 ; Is it locked? + bne- hvmptegLckwx ; Yeah... + stwcx. r11,0,r3 ; Take take it + bne- hvmptegLckx ; Someone else was trying, try again... + b hvmptegSXgx ; All done... + + .align 4 + +hvmptegLckwx: + mr. r10,r10 ; Check if it is already held + beq+ hvmptegLckx ; It's clear... + lwz r10,0(r3) ; Get lock word again... + b hvmptegLckwx ; Wait... + + .align 4 + +hvmptegSXgx: + isync ; Make sure we haven't used anything yet + + li r11,8 ; set count to 8 + + lwz r6,PCAhash(r3) ; load the first mapping hash list + la r12,PCAhash(r3) ; Point to the mapping hash area + la r4,MFmapping(r5) ; Point to the mapping flush mapping area + li r7,0 ; Load zero + stw r7,MFmappingcnt(r5) ; Set the current count to 0 +hvmnexthash: + li r10,0 ; Mapping test + +hvmfindmap: + mr. r6,r6 ; Test if the hash list current pointer is zero + beq hvmfindmapret ; Did we hit the end of the hash list + lwz r7,mmPTEv(r6) ; Pick up our virtual ID + rlwinm r8,r7,5,0,19 ; Pick VSID 20 lower bits + mr. r8,r8 + beq hvmfindmapnext ; Skip Kernel VSIDs + rlwinm r8,r7,1,0,3 ; Extract the Segment index + rlwinm r9,r7,22,4,9 ; Extract API 6 upper bits + or r8,r8,r9 ; Add to the virtual address + rlwinm r9,r7,31,6,25 ; Pick VSID 19 lower bits + xor r9,r9,r3 ; Exclusive or with the PCA address + rlwinm r9,r9,6,10,19 ; Extract API 10 lower bits + or r8,r8,r9 ; Add to the virtual address + + stw r8,4(r4) ; Store the virtual address + lwz r8,mmpmap(r6) ; Get the pmap + stw r8,0(r4) ; Store the pmap + li r10,1 ; Found one + +hvmfindmapnext: + lwz r6,mmhashnext(r6) ; Pick up next mapping block + b hvmfindmap ; Scan the next mapping +hvmfindmapret: + mr. r10,r10 ; Found mapping + beq hvmnexthashprep ; If not, do not update the mappingflush array + lwz r7,MFmappingcnt(r5) ; Get the current count + addi r7,r7,1 ; Increment the current count + stw r7,MFmappingcnt(r5) ; Store the current count + addi r4,r4,MFmappingSize ; Point to the next mapping flush entry +hvmnexthashprep: + addi r12,r12,4 ; Load the next hash list + lwz r6,0(r12) ; Load the next hash list entry + subi r11,r11,1 ; Decrement hash list index + mr. r11,r11 ; Test for a remaining hash list + bne hvmnexthash ; Loop to scan the next hash list + + li r10,0 + stw r10,0(r3) ; Unlock the hash list + mtmsr r0 ; Restore translation and interruptions + isync + blr /* * vm_offset_t hw_cvp_blk(pmap_t pmap, vm_offset_t va) @@ -2836,6 +3007,8 @@ LEXT(hw_cvp_blk) mfsprg r9,2 ; Get feature flags lwz r6,PMAP_PMAPVR(r3) ; Get the v to r translation mfmsr r0 /* Save the MSR */ + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r12,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */ mtcrf 0x04,r9 ; Set the features xor r3,r3,r6 ; Get real address of bmap anchor @@ -2931,6 +3104,8 @@ cbNo: lwz r11,bmnext(r11) ; Link next LEXT(hw_set_user_space) mfmsr r10 /* Get the current MSR */ + rlwinm r10,r10,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r10,r10,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r9,r10,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Turn off 'rupts */ mtmsr r9 /* Disable 'em */ lwz r7,PMAP_PMAPVR(r3) ; Get the v to r translation @@ -2968,6 +3143,8 @@ LEXT(hw_cpv) rlwinm. r4,r3,0,0,19 ; Round back to the mapping block allocation control block mfmsr r10 ; Get the current MSR beq- hcpvret ; Skip if we are passed a 0... + rlwinm r10,r10,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r10,r10,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off andi. r9,r10,0x7FEF ; Turn off interrupts and data translation mtmsr r9 ; Disable DR and EE isync @@ -3076,8 +3253,10 @@ LEXT(logmem) mfmsr r2 ; Get the MSR lis r10,hi16(EXT(DebugWork)) ; High part of area + rlwinm r2,r2,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off lis r12,hi16(EXT(mem_actual)) ; High part of actual - andi. r0,r10,0x7FCF ; Interrupts and translation off + rlwinm r2,r2,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off + andi. r0,r2,0x7FCF ; Interrupts and translation off ori r10,r10,lo16(EXT(DebugWork)) ; Get the entry mtmsr r0 ; Turn stuff off ori r12,r12,lo16(EXT(mem_actual)) ; Get the actual diff --git a/osfmk/ppc/interrupt.c b/osfmk/ppc/interrupt.c index 3e08c2538..47e447e81 100644 --- a/osfmk/ppc/interrupt.c +++ b/osfmk/ppc/interrupt.c @@ -39,9 +39,9 @@ #endif /* NCPUS > 1 */ #include -struct ppc_saved_state * interrupt( +struct savearea * interrupt( int type, - struct ppc_saved_state *ssp, + struct savearea *ssp, unsigned int dsisr, unsigned int dar) { @@ -52,6 +52,14 @@ struct ppc_saved_state * interrupt( disable_preemption(); +#if 0 + { + extern void fctx_text(void); + fctx_test(); + } +#endif + + current_cpu = cpu_number(); switch (type) { @@ -100,7 +108,7 @@ struct ppc_saved_state * interrupt( case T_DECREMENTER: KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_DECI, 0) | DBG_FUNC_NONE, - isync_mfdec(), ((savearea *)ssp)->save_srr0, 0, 0, 0); + isync_mfdec(), ssp->save_srr0, 0, 0, 0); #if 0 if (pcsample_enable) { @@ -128,7 +136,7 @@ struct ppc_saved_state * interrupt( counter_always(c_incoming_interrupts++); KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_INTR, 0) | DBG_FUNC_START, - current_cpu, ((savearea *)ssp)->save_srr0, 0, 0, 0); + current_cpu, ssp->save_srr0, 0, 0, 0); per_proc_info[current_cpu].interrupt_handler( per_proc_info[current_cpu].interrupt_target, diff --git a/osfmk/ppc/lock.h b/osfmk/ppc/lock.h index 8748bf8ac..e5ba906b8 100644 --- a/osfmk/ppc/lock.h +++ b/osfmk/ppc/lock.h @@ -56,23 +56,41 @@ #ifndef _PPC_LOCK_H_ #define _PPC_LOCK_H_ +#include + +#ifdef __APPLE_API_PRIVATE + #include #include extern unsigned int LockTimeOut; /* Number of hardware ticks of a lock timeout */ -#if defined(MACH_KERNEL_PRIVATE) && !(NCPUS == 1 && !ETAP_LOCK_TRACE && !USLOCK_DEBUG) -extern void fast_usimple_lock(usimple_lock_t); -extern void fast_usimple_unlock(usimple_lock_t); -extern unsigned int fast_usimple_lock_try(usimple_lock_t); +#if defined(MACH_KERNEL_PRIVATE) + +#include + +#if !(NCPUS == 1 || ETAP_LOCK_TRACE || USLOCK_DEBUG) + +#include + +#define simple_lock_init(l,t) hw_lock_init(l) +#define __slock_held_func__(l) hw_lock_held(l) + +extern void fast_usimple_lock(simple_lock_t); +extern void fast_usimple_unlock(simple_lock_t); +extern unsigned int fast_usimple_lock_try(simple_lock_t); -#define simple_lock_init(l,t) usimple_lock_init(l,t) #define simple_lock(l) fast_usimple_lock(l) #define simple_unlock(l) fast_usimple_unlock(l) #define simple_lock_try(l) fast_usimple_lock_try(l) #define simple_lock_addr(l) (&(l)) -#define __slock_held_func__(l) usimple_lock_held(l) +#define thread_sleep_simple_lock(l, e, i) \ + thread_sleep_fast_usimple_lock((l), (e), (i)) + +#endif /* !(NCPUS == 1 || ETAP_LOCK_TRACE || USLOCK_DEBUG) */ + +#endif /* MACH_KERNEL_PRIVATE */ -#endif +#endif /* __APPLE_API_PRIVATE */ #endif /* _PPC_LOCK_H_ */ diff --git a/osfmk/ppc/low_trace.h b/osfmk/ppc/low_trace.h index 3f7515a2a..30bbf3f98 100644 --- a/osfmk/ppc/low_trace.h +++ b/osfmk/ppc/low_trace.h @@ -61,8 +61,8 @@ typedef struct LowTraceRecord { typedef struct traceWork { - unsigned int traceMask; /* Types to be traced */ unsigned int traceCurr; /* Address of next slot */ + unsigned int traceMask; /* Types to be traced */ unsigned int traceStart; /* Start of trace table */ unsigned int traceEnd; /* End of trace table */ unsigned int traceMsnd; /* Saved trace mask */ @@ -70,6 +70,7 @@ typedef struct traceWork { } traceWork; extern traceWork trcWork; +extern unsigned int lastTrace; /* Value of low-level exception trace controls */ #endif /* ifndef _LOW_TRACE_H_ */ diff --git a/osfmk/ppc/lowmem_vectors.s b/osfmk/ppc/lowmem_vectors.s index b77de7569..f3ccdb123 100644 --- a/osfmk/ppc/lowmem_vectors.s +++ b/osfmk/ppc/lowmem_vectors.s @@ -61,8 +61,8 @@ #include #include #include +#include #include -#include #define TRCSAVE 0 #define CHECKSAVE 0 @@ -78,6 +78,7 @@ #define featAltivec 26 #define wasNapping 27 #define featFP 28 +#define specAccess 29 #define VECTOR_SEGMENT .section __VECTORS, __interrupts @@ -118,7 +119,6 @@ EXT(ResetHandler): resetexc: mtcr r11 - mfsprg r13,1 /* Get the exception save area */ li r11,T_RESET /* Set 'rupt code */ b .L_exception_entry /* Join common... */ @@ -130,7 +130,6 @@ resetexc: .L_handler200: mtsprg 2,r13 /* Save R13 */ mtsprg 3,r11 /* Save R11 */ - mfsprg r13,1 /* Get the exception save area */ li r11,T_MACHINE_CHECK /* Set 'rupt code */ b .L_exception_entry /* Join common... */ @@ -142,7 +141,6 @@ resetexc: .L_handler300: mtsprg 2,r13 /* Save R13 */ mtsprg 3,r11 /* Save R11 */ - mfsprg r13,1 /* Get the exception save area */ li r11,T_DATA_ACCESS /* Set 'rupt code */ b .L_exception_entry /* Join common... */ @@ -154,7 +152,6 @@ resetexc: .L_handler400: mtsprg 2,r13 /* Save R13 */ mtsprg 3,r11 /* Save R11 */ - mfsprg r13,1 /* Get the exception save area */ li r11,T_INSTRUCTION_ACCESS /* Set 'rupt code */ b .L_exception_entry /* Join common... */ @@ -166,7 +163,6 @@ resetexc: .L_handler500: mtsprg 2,r13 /* Save R13 */ mtsprg 3,r11 /* Save R11 */ - mfsprg r13,1 /* Get the exception save area */ li r11,T_INTERRUPT /* Set 'rupt code */ b .L_exception_entry /* Join common... */ @@ -178,7 +174,6 @@ resetexc: .L_handler600: mtsprg 2,r13 /* Save R13 */ mtsprg 3,r11 /* Save R11 */ - mfsprg r13,1 /* Get the exception save area */ li r11,T_ALIGNMENT /* Set 'rupt code */ b .L_exception_entry /* Join common... */ @@ -190,7 +185,6 @@ resetexc: .L_handler700: mtsprg 2,r13 /* Save R13 */ mtsprg 3,r11 /* Save R11 */ - mfsprg r13,1 /* Get the exception save area */ li r11,T_PROGRAM /* Set 'rupt code */ b .L_exception_entry /* Join common... */ @@ -202,7 +196,6 @@ resetexc: .L_handler800: mtsprg 2,r13 /* Save R13 */ mtsprg 3,r11 /* Save R11 */ - mfsprg r13,1 /* Get the exception save area */ li r11,T_FP_UNAVAILABLE /* Set 'rupt code */ b .L_exception_entry /* Join common... */ @@ -215,7 +208,6 @@ resetexc: .L_handler900: mtsprg 2,r13 /* Save R13 */ mtsprg 3,r11 /* Save R11 */ - mfsprg r13,1 /* Get the exception save area */ li r11,T_DECREMENTER /* Set 'rupt code */ b .L_exception_entry /* Join common... */ @@ -227,7 +219,6 @@ resetexc: .L_handlerA00: mtsprg 2,r13 /* Save R13 */ mtsprg 3,r11 /* Save R11 */ - mfsprg r13,1 /* Get the exception save area */ li r11,T_IO_ERROR /* Set 'rupt code */ b .L_exception_entry /* Join common... */ @@ -239,7 +230,6 @@ resetexc: .L_handlerB00: mtsprg 2,r13 /* Save R13 */ mtsprg 3,r11 /* Save R11 */ - mfsprg r13,1 /* Get the exception save area */ li r11,T_RESERVED /* Set 'rupt code */ b .L_exception_entry /* Join common... */ @@ -278,6 +268,7 @@ xxxx1: ; 0x00007FF4 - Kernel only - loadMSR ; ; Note: none handled if virtual machine is running +; Also, it we treat SCs as kernel SCs if the RI bit is set ; . = 0xC00 @@ -285,10 +276,13 @@ xxxx1: mtsprg 2,r13 ; Save R13 mfsrr1 r13 ; Get SRR1 for loadMSR mtsprg 3,r11 ; Save R11 + rlwimi r13,r13,MSR_PR_BIT,0,0 ; Move PR bit to non-volatile CR0 bit 0 mfcr r11 ; Save the CR - rlwinm. r13,r13,0,MSR_PR_BIT,MSR_PR_BIT ; From problem state? + mtcrf 0x81,r13 ; Get the moved PR and the RI for testing + crnot 0,0 ; Get !PR + cror 0,0,MSR_RI_BIT ; See if we have !PR or RI mfsprg r13,0 ; Get the per_proc_area - beq- uftInKern ; We are in the kernel... + bt- 0,uftInKern ; We are in the kernel... cmplwi cr5,r0,0x7FF2 ; Ultra fast path cthread info call? cmpwi cr6,r0,0x7FF3 ; Ultra fast path facility status? @@ -341,7 +335,6 @@ isvecfp: lwz r3,spcFlags(r3) ; Get the facility status ; notufp: mtcrf 0xFF,r11 ; Restore the used CRs li r11,T_SYSTEM_CALL ; Set interrupt code - mfsprg r13,1 ; Get the exception save area b .L_exception_entry ; Join common... uftInKern: cmplwi r0,0x7FF4 ; Ultra fast path loadMSR? @@ -386,7 +379,6 @@ uftInKern: cmplwi r0,0x7FF4 ; Ultra fast path loadMSR? bne+ specbrtr ; Yeah... notspectr: mtcr r11 ; Restore CR - mfsprg r13,1 ; Get the savearea li r11,T_TRACE ; Set interrupt code b .L_exception_entry ; Join common... @@ -427,7 +419,6 @@ specbrtr: mfsprg r13,0 ; Get the per_proc area .L_handlerE00: mtsprg 2,r13 /* Save R13 */ mtsprg 3,r11 /* Save R11 */ - mfsprg r13,1 /* Get the exception save area */ li r11,T_FP_ASSIST /* Set 'rupt code */ b .L_exception_entry /* Join common... */ @@ -440,7 +431,6 @@ specbrtr: mfsprg r13,0 ; Get the per_proc area PMIhandler: mtsprg 2,r13 /* Save R13 */ mtsprg 3,r11 /* Save R11 */ - mfsprg r13,1 /* Get the exception save area */ li r11,T_PERF_MON /* Set 'rupt code */ b .L_exception_entry /* Join common... */ @@ -453,7 +443,6 @@ PMIhandler: VMXhandler: mtsprg 2,r13 /* Save R13 */ mtsprg 3,r11 /* Save R11 */ - mfsprg r13,1 /* Get the exception save area */ li r11,T_VMX /* Set 'rupt code */ b .L_exception_entry /* Join common... */ @@ -791,7 +780,6 @@ VMXhandler: .L_handler1300: mtsprg 2,r13 /* Save R13 */ mtsprg 3,r11 /* Save R11 */ - mfsprg r13,1 /* Get the exception save area */ li r11,T_INSTRUCTION_BKPT /* Set 'rupt code */ b .L_exception_entry /* Join common... */ @@ -803,7 +791,6 @@ VMXhandler: .L_handler1400: mtsprg 2,r13 /* Save R13 */ mtsprg 3,r11 /* Save R11 */ - mfsprg r13,1 /* Get the exception save area */ li r11,T_SYSTEM_MANAGEMENT /* Set 'rupt code */ b .L_exception_entry /* Join common... */ @@ -815,7 +802,6 @@ VMXhandler: .L_handler1600: mtsprg 2,r13 /* Save R13 */ mtsprg 3,r11 /* Save R11 */ - mfsprg r13,1 /* Get the exception save area */ li r11,T_ALTIVEC_ASSIST /* Set 'rupt code */ b .L_exception_entry /* Join common... */ @@ -827,7 +813,6 @@ VMXhandler: .L_handler1700: mtsprg 2,r13 /* Save R13 */ mtsprg 3,r11 /* Save R11 */ - mfsprg r13,1 /* Get the exception save area */ li r11,T_THERMAL /* Set 'rupt code */ b .L_exception_entry /* Join common... */ @@ -843,7 +828,6 @@ VMXhandler: .L_handler2000: mtsprg 2,r13 /* Save R13 */ mtsprg 3,r11 /* Save R11 */ - mfsprg r13,1 /* Get the exception save area */ li r11,T_RUNMODE_TRACE /* Set 'rupt code */ b .L_exception_entry /* Join common... */ @@ -881,9 +865,12 @@ EXT(exception_entry): * Note that if we are attempting to sleep (as opposed to nap or doze) all interruptions * are ignored. */ + mfsprg r13,0 /* Load per_proc */ + lwz r13,next_savearea(r13) /* Get the exception save area */ stw r1,saver1(r13) ; Save register 1 stw r0,saver0(r13) ; Save register 0 + dcbtst 0,r13 ; We will need this in a bit mfspr r1,hid0 ; Get HID0 mfcr r0 ; Save the CR mtcrf 255,r1 ; Get set to test for cache and sleep @@ -914,41 +901,46 @@ notsleep: stw r2,saver2(r13) ; Save this one rlwinm r2,r1,0,nap+1,doze-1 ; Clear any possible nap and doze bits mtspr hid0,r2 ; Clear the nap/doze bits cmplw r2,r1 ; See if we were napping - li r1,32 ; Point to the next line in case we need it + la r1,saver8(r13) ; Point to the next line in case we need it crnot wasNapping,cr0_eq ; Remember if we were napping mfsprg r2,0 ; Get the per_proc area bf- featL1ena,skipz1 ; L1 cache is disabled... - dcbz r1,r13 ; Reserve our line in cache + dcbz 0,r1 ; Reserve our line in cache ; ; Remember, we are setting up CR6 with feature flags ; skipz1: lwz r1,pfAvailable(r2) ; Get the CPU features flags stw r3,saver3(r13) ; Save this one + la r3,savesrr0(r13) ; Point to the last line mtcrf 0xE0,r1 ; Put the features flags (that we care about) in the CR stw r4,saver4(r13) ; Save this one stw r6,saver6(r13) ; Save this one crmove featSMP,pfSMPcapb ; See if we have a PIR stw r8,saver8(r13) ; Save this one crmove featAltivec,pfAltivecb ; Set the Altivec flag - mfsrr0 r6 /* Get the interruption SRR0 */ - stw r8,saver8(r13) /* Save this one */ - crmove featFP,pfFloatb ; Remember that we have floating point - stw r7,saver7(r13) /* Save this one */ + mfsrr0 r6 ; Get the interruption SRR0 + stw r8,saver8(r13) ; Save this one + bf- featL1ena,skipz1a ; L1 cache is disabled... + dcbz 0,r3 ; Reserve our line in cache +skipz1a: crmove featFP,pfFloatb ; Remember that we have floating point + stw r7,saver7(r13) ; Save this one lhz r8,PP_CPU_FLAGS(r2) ; Get the flags - mfsrr1 r7 /* Get the interrupt SRR1 */ + mfsrr1 r7 ; Get the interrupt SRR1 rlwinm r8,r8,(((31-MSR_BE_BIT)+(traceBEb+16+1))&31),MSR_BE_BIT,MSR_BE_BIT ; Set BE bit if special trace is on - stw r6,savesrr0(r13) /* Save the SRR0 */ + stw r6,savesrr0(r13) ; Save the SRR0 rlwinm r6,r7,(((31-MSR_BE_BIT)+(MSR_PR_BIT+1))&31),MSR_BE_BIT,MSR_BE_BIT ; Move PR bit to BE bit - stw r5,saver5(r13) /* Save this one */ + stw r5,saver5(r13) ; Save this one and r8,r6,r8 ; Remove BE bit only if problem state and special tracing on mfsprg r6,2 ; Get interrupt time R13 mtsprg 2,r1 ; Set the feature flags andc r7,r7,r8 ; Clear BE bit if special trace is on and PR is set - mfsprg r8,3 /* Get 'rupt time R11 */ - stw r7,savesrr1(r13) /* Save SRR1 */ - stw r6,saver13(r13) /* Save 'rupt R1 */ - stw r8,saver11(r13) /* Save 'rupt time R11 */ + mfsprg r8,3 ; Get rupt time R11 + stw r7,savesrr1(r13) ; Save SRR1 + rlwinm. r7,r7,MSR_RI_BIT,MSR_RI_BIT ; Is this a special case access fault? + stw r6,saver13(r13) ; Save rupt R1 + crnot specAccess,cr0_eq ; Set that we are doing a special access if RI is set + stw r8,saver11(r13) ; Save rupt time R11 getTB: mftbu r6 ; Get the upper timebase mftb r7 ; Get the lower timebase @@ -957,16 +949,18 @@ getTB: mftbu r6 ; Get the upper timebase bne- getTB ; Yeah, need to get it again... stw r8,ruptStamp(r2) ; Save the top of time stamp - la r6,saver14(r13) ; Point to the next cache line + stw r8,SAVtime(r13) ; Save the top of time stamp + la r6,saver16(r13) ; Point to the next cache line stw r7,ruptStamp+4(r2) ; Save the bottom of time stamp + stw r7,SAVtime+4(r13) ; Save the bottom of time stamp + bf- featL1ena,skipz2 ; L1 cache is disabled... - dcbz 0,r6 /* Allocate in cache */ + dcbz 0,r6 ; Allocate in cache skipz2: - stw r9,saver9(r13) /* Save this one */ + stw r9,saver9(r13) ; Save this one - la r9,saver30(r13) /* Point to the trailing end */ - stw r10,saver10(r13) /* Save this one */ - mflr r4 /* Get the LR */ + stw r10,saver10(r13) ; Save this one + mflr r4 ; Get the LR mfxer r10 ; Get the XER bf+ wasNapping,notNapping ; Skip if not waking up from nap... @@ -984,287 +978,248 @@ skipz2: stw r6,napTotal+4(r2) ; Save the low total stw r8,napTotal(r2) ; Save the high total stw r3,savesrr0(r13) ; Modify to return to nap/doze exit + + rlwinm. r3,r1,0,pfSlowNapb,pfSlowNapb ; Should HID1 be restored? + beq notInSlowNap + + lwz r3,pfHID1(r2) ; Get saved HID1 value + mtspr hid1, r3 ; Restore HID1 +notInSlowNap: + rlwinm. r3,r1,0,pfNoL2PFNapb,pfNoL2PFNapb ; Should MSSCR0 be restored? + beq notNapping -notNapping: stw r12,saver12(r13) /* Save this one */ + lwz r3,pfMSSCR0(r2) ; Get saved MSSCR0 value + mtspr msscr0, r3 ; Restore MSSCR0 + sync + isync + +notNapping: stw r12,saver12(r13) ; Save this one - bf- featL1ena,skipz3 ; L1 cache is disabled... - dcbz 0,r9 /* Allocate the last in the area */ -skipz3: - stw r14,saver14(r13) /* Save this one */ - stw r15,saver15(r13) /* Save this one */ - la r14,saver22(r13) /* Point to the next block to save into */ + stw r14,saver14(r13) ; Save this one + stw r15,saver15(r13) ; Save this one + la r14,saver24(r13) ; Point to the next block to save into stw r0,savecr(r13) ; Save rupt CR - mfctr r6 /* Get the CTR */ - stw r16,saver16(r13) /* Save this one */ - stw r4,savelr(r13) /* Save 'rupt LR */ + mfctr r6 ; Get the CTR + stw r16,saver16(r13) ; Save this one + stw r4,savelr(r13) ; Save rupt LR bf- featL1ena,skipz4 ; L1 cache is disabled... - dcbz 0,r14 /* Allocate next save area line */ + dcbz 0,r14 ; Allocate next save area line skipz4: - stw r17,saver17(r13) /* Save this one */ - stw r18,saver18(r13) /* Save this one */ - stw r6,savectr(r13) /* Save 'rupt CTR */ - stw r19,saver19(r13) /* Save this one */ - lis r12,HIGH_ADDR(KERNEL_SEG_REG0_VALUE) /* Get the high half of the kernel SR0 value */ - mfdar r6 /* Get the 'rupt DAR */ - stw r20,saver20(r13) /* Save this one */ -#if 0 - mfsr r14,sr0 ; (TEST/DEBUG) - stw r14,savesr0(r13) ; (TEST/DEBUG) - mfsr r14,sr1 ; (TEST/DEBUG) - stw r14,savesr1(r13) ; (TEST/DEBUG) - mfsr r14,sr2 ; (TEST/DEBUG) - stw r14,savesr2(r13) ; (TEST/DEBUG) - mfsr r14,sr3 ; (TEST/DEBUG) - stw r14,savesr3(r13) ; (TEST/DEBUG) - mfsr r14,sr4 ; (TEST/DEBUG) - stw r14,savesr4(r13) ; (TEST/DEBUG) - mfsr r14,sr5 ; (TEST/DEBUG) - stw r14,savesr5(r13) ; (TEST/DEBUG) - mfsr r14,sr6 ; (TEST/DEBUG) - stw r14,savesr6(r13) ; (TEST/DEBUG) - mfsr r14,sr7 ; (TEST/DEBUG) - stw r14,savesr7(r13) ; (TEST/DEBUG) - mfsr r14,sr8 ; (TEST/DEBUG) - stw r14,savesr8(r13) ; (TEST/DEBUG) - mfsr r14,sr9 ; (TEST/DEBUG) - stw r14,savesr9(r13) ; (TEST/DEBUG) - mfsr r14,sr10 ; (TEST/DEBUG) - stw r14,savesr10(r13) ; (TEST/DEBUG) - mfsr r14,sr11 ; (TEST/DEBUG) - stw r14,savesr11(r13) ; (TEST/DEBUG) - mfsr r14,sr12 ; (TEST/DEBUG) - stw r14,savesr12(r13) ; (TEST/DEBUG) - mfsr r14,sr13 ; (TEST/DEBUG) - stw r14,savesr13(r13) ; (TEST/DEBUG) - mfsr r14,sr15 ; (TEST/DEBUG) - stw r14,savesr15(r13) ; (TEST/DEBUG) -#endif - - mtsr sr0,r12 /* Set the kernel SR0 */ - stw r21,saver21(r13) /* Save this one */ + stw r17,saver17(r13) ; Save this one + stw r18,saver18(r13) ; Save this one + stw r6,savectr(r13) ; Save rupt CTR + stw r19,saver19(r13) ; Save this one + lis r12,hi16(KERNEL_SEG_REG0_VALUE) ; Get the high half of the kernel SR0 value + mfdar r6 ; Get the rupt DAR + stw r20,saver20(r13) ; Save this one + + bf+ specAccess,noSRsave ; Do not save SRs if this is not a special access... + mfsr r14,sr0 ; Get SR0 + stw r14,savesr0(r13) ; and save + mfsr r14,sr1 ; Get SR1 + stw r14,savesr1(r13) ; and save + mfsr r14,sr2 ; get SR2 + stw r14,savesr2(r13) ; and save + mfsr r14,sr3 ; get SR3 + stw r14,savesr3(r13) ; and save + +noSRsave: mtsr sr0,r12 ; Set the kernel SR0 + stw r21,saver21(r13) ; Save this one addis r12,r12,0x0010 ; Point to the second segment of kernel stw r10,savexer(r13) ; Save the rupt XER - mtsr sr1,r12 /* Set the kernel SR1 */ - stw r30,saver30(r13) /* Save this one */ + mtsr sr1,r12 ; Set the kernel SR1 + stw r30,saver30(r13) ; Save this one addis r12,r12,0x0010 ; Point to the third segment of kernel - stw r31,saver31(r13) /* Save this one */ - mtsr sr2,r12 /* Set the kernel SR2 */ - stw r22,saver22(r13) /* Save this one */ + stw r31,saver31(r13) ; Save this one + mtsr sr2,r12 ; Set the kernel SR2 + stw r22,saver22(r13) ; Save this one addis r12,r12,0x0010 ; Point to the third segment of kernel - la r10,savedar(r13) /* Point to exception info block */ - stw r23,saver23(r13) /* Save this one */ - mtsr sr3,r12 /* Set the kernel SR3 */ - stw r24,saver24(r13) /* Save this one */ - stw r25,saver25(r13) /* Save this one */ - mfdsisr r7 /* Get the 'rupt DSISR */ - stw r26,saver26(r13) /* Save this one */ - - bf- featL1ena,skipz5 ; L1 cache is disabled... - dcbz 0,r10 /* Allocate exception info line */ -skipz5: - - stw r27,saver27(r13) /* Save this one */ + stw r23,saver23(r13) ; Save this one + mtsr sr3,r12 ; Set the kernel SR3 + stw r24,saver24(r13) ; Save this one + stw r25,saver25(r13) ; Save this one + mfdsisr r7 ; Get the rupt DSISR + stw r26,saver26(r13) ; Save this one + stw r27,saver27(r13) ; Save this one li r10,emfp0 ; Point to floating point save - stw r28,saver28(r13) /* Save this one */ - stw r29,saver29(r13) /* Save this one */ + stw r28,saver28(r13) ; Save this one + stw r29,saver29(r13) ; Save this one mfsr r14,sr14 ; Get the copyin/out segment register - stw r6,savedar(r13) /* Save the 'rupt DAR */ + stw r6,savedar(r13) ; Save the rupt DAR bf- featL1ena,skipz5a ; Do not do this if no L1... dcbz r10,r2 ; Clear and allocate an L1 slot -skipz5a: stw r7,savedsisr(r13) /* Save the 'rupt code DSISR */ - stw r11,saveexception(r13) /* Save the exception code */ +skipz5a: stw r7,savedsisr(r13) ; Save the rupt code DSISR + stw r11,saveexception(r13) ; Save the exception code stw r14,savesr14(r13) ; Save copyin/copyout - lis r8,HIGH_ADDR(EXT(saveanchor)) /* Get the high part of the anchor */ + +; +; Here we will save some floating point and vector status +; and we also set a clean default status for a new interrupt level. +; Note that we assume that emfp0 is on an altivec boundary +; and that R10 points to it (as a displacemnt from R2). +; + + lis r8,hi16(MASK(MSR_VEC)) ; Get the vector enable bit + mfmsr r6 ; Get the current MSR value + ori r8,r8,lo16(MASK(MSR_FP)) ; Add in the float enable li r19,0 ; Assume no Altivec - ori r8,r8,LOW_ADDR(EXT(saveanchor)) /* Bottom half of the anchor */ + or r7,r6,r8 ; Enable floating point + li r9,0 ; Get set to clear VRSAVE + mtmsr r7 ; Do it + isync bf featAltivec,noavec ; No Altivec on this CPU... - li r9,0 ; Get set to clear VRSAVE + addi r14,r10,16 ; Displacement to second vector register + stvxl v0,r10,r2 ; Save a register + stvxl v1,r14,r2 ; Save a second register + mfvscr v0 ; Get the vector status register + la r28,savevscr(r13) ; Point to the status area + vspltish v1,1 ; Turn on the non-Java bit and saturate + stvxl v0,0,r28 ; Save the vector status + vspltisw v0,1 ; Turn on the saturate bit mfspr r19,vrsave ; Get the VRSAVE register + vxor v1,v1,v0 ; Turn off saturate mtspr vrsave,r9 ; Clear VRSAVE for each interrupt level + mtvscr v1 ; Set the non-java, no saturate status for new level + + lvxl v0,r10,r2 ; Restore first work register + lvxl v1,r14,r2 ; Restore second work register + +noavec: stw r19,savevrsave(r13) ; Save the vector register usage flags + ; ; We need to save the FPSCR as if it is normal context. ; This is because pending exceptions will cause an exception even if ; FP is disabled. We need to clear the FPSCR when we first start running in the ; kernel. ; -noavec: stw r19,savevrsave(r13) ; Save the vector register usage flags bf- featFP,nofpexe ; No possible floating point exceptions... - mfmsr r9 ; Get the MSR value - ori r7,r9,lo16(MASK(MSR_FP)) ; Enable floating point - mtmsr r7 ; Do it - isync stfd f0,emfp0(r2) ; Save FPR0 stfd f1,emfp1(r2) ; Save FPR1 mffs f0 ; Get the FPSCR fsub f1,f1,f1 ; Make a 0 - stfd f0,savexfpscrpad(r13) ; Save the FPSCR + stfd f0,savefpscrpad(r13) ; Save the FPSCR mtfsf 0xFF,f1 ; Clear it lfd f0,emfp0(r2) ; Restore FPR0 lfd f1,emfp1(r2) ; Restore FPR1 - mtmsr r9 ; Turn off FP + +nofpexe: mtmsr r6 ; Turn off FP and vector isync -nofpexe: + -/* - * Everything is saved at this point, except for FPRs, and VMX registers - * - * Time for a new save area. Allocate the trace table entry now also - * Note that we haven't touched R0-R5 yet. Except for R0 & R1, that's in the save - */ +; +; Everything is saved at this point, except for FPRs, and VMX registers. +; Time for us to get a new savearea and then trace interrupt if it is enabled. +; + + li r0,SAVgeneral ; Get the savearea type value + lis r23,hi16(EXT(trcWork)) ; Get the trace work area address + mr r14,r11 ; Save the interrupt code across the call + stb r0,SAVflags+2(r13) ; Mark valid context + ori r23,r23,lo16(EXT(trcWork)) ; Get the rest + rlwinm r22,r11,30,0,31 ; Divide interrupt code by 2 + lwz r25,traceMask(r23) ; Get the trace mask + addi r22,r22,10 ; Adjust code so we shift into CR5 + + bl EXT(save_get_phys) ; Grab a savearea + + mfsprg r2,0 ; Get back the per_proc block + rlwnm r7,r25,r22,22,22 ; Set CR5_EQ bit position to 0 if tracing allowed + lhz r19,PP_CPU_NUMBER(r2) ; Get the logical processor number + li r26,0x8 ; Get start of cpu mask + mr r11,r14 ; Get the exception code back + srw r26,r26,r19 ; Get bit position of cpu number + mtcrf 0x04,r7 ; Set CR5 to show trace or not + and. r26,r26,r25 ; See if we trace this cpu + stw r3,next_savearea(r2) ; Remember the savearea we just got for the next rupt + crandc cr5_eq,cr5_eq,cr0_eq ; Turn off tracing if cpu is disabled +; +; At this point, we can take another exception and lose nothing. +; + + lwz r0,saver0(r13) ; Get back interrupt time R0 (we need this whether we trace or not) + + bne+ cr5,skipTrace ; Skip all of this if no tracing here... +; +; We select a trace entry using a compare and swap on the next entry field. +; Since we do not lock the actual trace buffer, there is a potential that +; another processor could wrap an trash our entry. Who cares? +; -lllck: lwarx r9,0,r8 /* Grab the lock value */ - li r7,1 /* Use part of the delay time */ - mr. r9,r9 /* Is it locked? */ - bne- lllcks /* Yeah, wait for it to clear... */ - stwcx. r7,0,r8 /* Try to seize that there durn lock */ - beq+ lllckd /* Got it... */ - b lllck /* Collision, try again... */ + lwz r25,traceStart(r23) ; Get the start of trace table + lwz r26,traceEnd(r23) ; Get end of trace table + +trcsel: lwarx r20,0,r23 ; Get and reserve the next slot to allocate -lllcks: lwz r9,SVlock(r8) /* Get that lock in here */ - mr. r9,r9 /* Is it free yet? */ - beq+ lllck /* Yeah, try for it again... */ - b lllcks /* Sniff away... */ + addi r22,r20,LTR_size ; Point to the next trace entry + cmplw r22,r26 ; Do we need to wrap the trace table? + bne+ gotTrcEnt ; No wrap, we got us a trace entry... -lllckd: isync /* Purge any speculative executions here */ - lis r23,hi16(EXT(trcWork)) ; Get the work area address - rlwinm r7,r11,30,0,31 /* Save 'rupt code shifted right 2 */ - ori r23,r23,lo16(EXT(trcWork)) ; Get the rest -#if 1 - lwz r14,traceMask(r23) /* Get the trace mask */ -#else - li r14,-1 /* (TEST/DEBUG) */ -#endif - addi r7,r7,10 /* Adjust for CR5_EQ position */ - lwz r15,SVfree(r8) /* Get the head of the save area list */ - lwz r25,SVinuse(r8) /* Get the in use count */ - rlwnm r7,r14,r7,22,22 /* Set CR5_EQ bit position to 0 if tracing allowed */ - lwz r20,traceCurr(r23) /* Pick up the current trace entry */ - mtcrf 0x04,r7 /* Set CR5 to show trace or not */ - - lwz r14,SACalloc(r15) /* Pick up the allocation bits */ - addi r25,r25,1 /* Bump up the in use count for the new savearea */ - lwz r21,traceEnd(r23) /* Grab up the end of it all */ - mr. r14,r14 /* Can we use the first one? */ - blt use1st /* Yeah... */ - - andis. r14,r14,0x8000 /* Show we used the second and remember if it was the last */ - addi r10,r15,0x0800 /* Point to the first one */ - b gotsave /* We have the area now... */ - -use1st: andis. r14,r14,0x4000 /* Mark first gone and remember if empty */ - mr r10,r15 /* Set the save area */ - -gotsave: stw r14,SACalloc(r15) /* Put back the allocation bits */ - bne nodqsave /* There's still an empty slot, don't dequeue... */ - - lwz r16,SACnext(r15) /* Get the next in line */ - stw r16,SVfree(r8) /* Dequeue our now empty save area block */ - -nodqsave: addi r22,r20,LTR_size /* Point to the next trace entry */ - stw r25,SVinuse(r8) /* Set the in use count */ - li r17,0 /* Clear this for the lock */ - cmplw r22,r21 /* Do we need to wrap the trace table? */ - stw r17,SAVprev(r10) /* Clear back pointer for the newly allocated guy */ - mtsprg 1,r10 /* Get set for the next 'rupt */ - bne+ gotTrcEnt /* We got a trace entry... */ - - lwz r22,traceStart(r23) /* Wrap back to the top */ - -gotTrcEnt: bne- cr5,skipTrace1 /* Don't want to trace this kind... */ - - stw r22,traceCurr(r23) /* Set the next entry for the next guy */ + mr r22,r25 ; Wrap back to start + +gotTrcEnt: stwcx. r22,0,r23 ; Try to update the current pointer + bne- trcsel ; Collision, try again... #if ESPDEBUG - dcbst br0,r23 ; (TEST/DEBUG) - sync ; (TEST/DEBUG) + dcbf 0,r23 ; Force to memory + sync #endif bf- featL1ena,skipz6 ; L1 cache is disabled... - dcbz 0,r20 /* Allocate cache for the entry */ + dcbz 0,r20 ; Clear and allocate first trace line skipz6: - -skipTrace1: sync /* Make sure all stores are done */ - stw r17,SVlock(r8) /* Unlock both save and trace areas */ +; +; Let us cut that trace entry now. +; -/* - * At this point, we can take another exception and lose nothing. - * - * We still have the current savearea pointed to by R13, the next by R10 and - * sprg1. R20 contains the pointer to a trace entry and CR5_eq says - * to do the trace or not. - * - * Note that R13 was chosen as the save area pointer because the SIGP, - * firmware, and DSI/ISI handlers aren't supposed to touch anything - * over R12. But, actually, the DSI/ISI stuff does. - * - * - * Let's cut that trace entry now. - */ - - lwz r0,saver0(r13) ; Get back interrupt time R0 - bne- cr5,skipTrace2 /* Don't want to trace this kind... */ - mfsprg r2,0 ; Get the per_proc - li r14,32 /* Second line of entry */ + li r14,32 ; Offset to second line lwz r16,ruptStamp(r2) ; Get top of time base lwz r17,ruptStamp+4(r2) ; Get the bottom of time stamp bf- featL1ena,skipz7 ; L1 cache is disabled... - dcbz r14,r20 /* Zap the second half */ - -skipz7: stw r16,LTR_timeHi(r20) /* Set the upper part of TB */ - bf featSMP,nopir4 ; Is there a processor ID register on this guy? - mfspr r19,pir /* Get the processor address */ - b gotpir4 /* Got it... */ -nopir4: li r19,0 /* Assume processor 0 for those underprivileged folks */ -gotpir4: + dcbz r14,r20 ; Zap the second half + +skipz7: stw r16,LTR_timeHi(r20) ; Set the upper part of TB lwz r1,saver1(r13) ; Get back interrupt time R1 - stw r17,LTR_timeLo(r20) /* Set the lower part of TB */ - rlwinm r19,r19,0,27,31 /* Cut the junk */ - lwz r2,saver2(r13) ; Get back interrupt time R2 - stw r0,LTR_r0(r20) /* Save off register 0 */ + stw r17,LTR_timeLo(r20) ; Set the lower part of TB + lwz r18,saver2(r13) ; Get back interrupt time R2 + stw r0,LTR_r0(r20) ; Save off register 0 lwz r3,saver3(r13) ; Restore this one - sth r19,LTR_cpu(r20) /* Stash the cpu address */ - stw r1,LTR_r1(r20) /* Save off register 1 */ + sth r19,LTR_cpu(r20) ; Stash the cpu number + stw r1,LTR_r1(r20) ; Save off register 1 lwz r4,saver4(r13) ; Restore this one - stw r2,LTR_r2(r20) /* Save off register 2 */ + stw r18,LTR_r2(r20) ; Save off register 2 lwz r5,saver5(r13) ; Restore this one - stw r3,LTR_r3(r20) /* Save off register 3 */ - lwz r16,savecr(r13) /* We don't remember the CR anymore, get it */ - stw r4,LTR_r4(r20) /* Save off register 4 */ - mfsrr0 r17 /* Get this back, it's still good */ - stw r5,LTR_r5(r20) /* Save off register 5 */ - mfsrr1 r18 /* This is still good in here also */ - - stw r16,LTR_cr(r20) /* Save the CR (or dec) */ - stw r17,LTR_srr0(r20) /* Save the SSR0 */ - stw r18,LTR_srr1(r20) /* Save the SRR1 */ - mfdar r17 /* Get this back */ - - mflr r16 /* Get the LR */ - stw r17,LTR_dar(r20) /* Save the DAR */ - mfctr r17 /* Get the CTR */ - stw r16,LTR_lr(r20) /* Save the LR */ + stw r3,LTR_r3(r20) ; Save off register 3 + lwz r16,savecr(r13) ; Get the CR value + stw r4,LTR_r4(r20) ; Save off register 4 + mfsrr0 r17 ; Get SRR0 back, it is still good + stw r5,LTR_r5(r20) ; Save off register 5 + mfsrr1 r18 ; SRR1 is still good in here + stw r16,LTR_cr(r20) ; Save the CR + stw r17,LTR_srr0(r20) ; Save the SSR0 + stw r18,LTR_srr1(r20) ; Save the SRR1 + mfdar r17 ; Get this back + lwz r16,savelr(r13) ; Get the LR + stw r17,LTR_dar(r20) ; Save the DAR + mfctr r17 ; Get the CTR (still good in register) + stw r16,LTR_lr(r20) ; Save the LR #if 0 - lis r17,HIGH_ADDR(EXT(saveanchor)) ; (TEST/DEBUG) - ori r17,r17,LOW_ADDR(EXT(saveanchor)) ; (TEST/DEBUG) - lwz r16,SVcount(r17) ; (TEST/DEBUG) - lwz r17,SVinuse(r17) ; (TEST/DEBUG) - rlwimi r17,r16,16,0,15 ; (TEST/DEBUG) + lwz r17,emfp1(r2) ; (TEST/DEBUG) #endif - stw r17,LTR_ctr(r20) /* Save off the CTR */ - stw r13,LTR_save(r20) /* Save the savearea */ - sth r11,LTR_excpt(r20) /* Save the exception type */ + stw r17,LTR_ctr(r20) ; Save off the CTR + stw r13,LTR_save(r20) ; Save the savearea + sth r11,LTR_excpt(r20) ; Save the exception type #if ESPDEBUG addi r17,r20,32 ; (TEST/DEBUG) dcbst br0,r20 ; (TEST/DEBUG) @@ -1272,329 +1227,33 @@ gotpir4: sync ; (TEST/DEBUG) #endif -/* - * We're done with the trace, except for maybe modifying the exception - * code later on. So, that means that we need to save R20 and CR5, but - * R0 to R5 are clear now. - * - * So, let's finish setting up the kernel registers now. - */ - -skipTrace2: - -#if PERFTIMES && DEBUG - li r3,68 ; Indicate interrupt - mr r4,r11 ; Get code to log - mr r5,r13 ; Get savearea to log - mr r8,r0 ; Save R0 - bl EXT(dbgLog2) ; Cut log entry - mr r0,r8 ; Restore R0 -#endif - - mfsprg r2,0 /* Get the per processor block */ - -#if CHECKSAVE - - lis r4,0x7FFF /* (TEST/DEBUG) */ - mfdec r12 /* (TEST/DEBUG) */ - or r4,r4,r12 /* (TEST/DEBUG) */ - mtdec r4 /* (TEST/DEBUG) */ - li r4,0x20 /* (TEST/DEBUG) */ - - lwarx r8,0,r4 ; ? - -mpwait2: lwarx r8,0,r4 /* (TEST/DEBUG) */ - mr. r8,r8 /* (TEST/DEBUG) */ - bne- mpwait2 /* (TEST/DEBUG) */ - stwcx. r4,0,r4 /* (TEST/DEBUG) */ - bne- mpwait2 /* (TEST/DEBUG) */ - - isync /* (TEST/DEBUG) */ - lwz r4,0xE80(br0) /* (TEST/DEBUG) */ - mr. r4,r4 /* (TEST/DEBUG) */ - li r4,1 /* (TEST/DEBUG) */ - bne- doncheksv /* (TEST/DEBUG) */ - - lis r8,HIGH_ADDR(EXT(saveanchor)) /* (TEST/DEBUG) */ - ori r8,r8,LOW_ADDR(EXT(saveanchor)) /* (TEST/DEBUG) */ - - stw r4,0xE80(br0) /* (TEST/DEBUG) */ - - lwarx r4,0,r8 ; ? - -mpwait2x: lwarx r4,0,r8 /* (TEST/DEBUG) */ - mr. r4,r4 /* (TEST/DEBUG) */ - bne- mpwait2x /* (TEST/DEBUG) */ - stwcx. r8,0,r8 /* (TEST/DEBUG) */ - bne- mpwait2x /* (TEST/DEBUG) */ - - isync /* (TEST/DEBUG) */ - - rlwinm r4,r13,0,0,19 /* (TEST/DEBUG) */ - lwz r21,SACflags(r4) /* (TEST/DEBUG) */ - rlwinm r22,r21,24,24,31 /* (TEST/DEBUG) */ - cmplwi r22,0x00EE /* (TEST/DEBUG) */ - lwz r22,SACvrswap(r4) /* (TEST/DEBUG) */ - bnel- currbad /* (TEST/DEBUG) */ - andis. r21,r21,hi16(sac_perm) /* (TEST/DEBUG) */ - bne- currnotbad /* (TEST/DEBUG) */ - mr. r22,r22 /* (TEST/DEBUG) */ - bne+ currnotbad /* (TEST/DEBUG) */ - -currbad: lis r23,hi16(EXT(debugbackpocket)) /* (TEST/DEBUG) */ - ori r23,r23,lo16(EXT(debugbackpocket)) /* (TEST/DEBUG) */ - lwz r23,0(r23) ; (TEST/DEBUG) - stw r23,SVfree(r8) /* (TEST/DEBUG) */ - - mfsprg r25,1 /* (TEST/DEBUG) */ - mtsprg 1,r23 /* (TEST/DEBUG) */ - lwz r26,SACalloc(r23) /* (TEST/DEBUG) */ - rlwinm r26,r26,0,1,31 /* (TEST/DEBUG) */ - stw r26,SACalloc(r23) /* (TEST/DEBUG) */ - - sync /* (TEST/DEBUG) */ - - li r3,0 /* (TEST/DEBUG) */ - stw r3,0x20(br0) /* (TEST/DEBUG) */ - stw r3,0(r8) /* (TEST/DEBUG) */ - lis r0,hi16(Choke) ; (TEST/DEBUG) - ori r0,r0,lo16(Choke) ; (TEST/DEBUG) - sc ; System ABEND - -currnotbad: - lwz r28,SVcount(r8) /* (TEST/DEBUG) */ - lwz r21,SVinuse(r8) /* (TEST/DEBUG) */ - lwz r23,SVmin(r8) /* (TEST/DEBUG) */ - sub r22,r28,r21 /* (TEST/DEBUG) */ - cmpw r22,r23 /* (TEST/DEBUG) */ - bge+ cksave0 /* (TEST/DEBUG) */ - - bl currbad ; (TEST/DEBUG) - -cksave0: lwz r28,SVfree(r8) /* (TEST/DEBUG) */ - li r24,0 /* (TEST/DEBUG) */ - li r29,1 /* (TEST/SAVE) */ - -cksave0a: mr. r28,r28 /* (TEST/DEBUG) */ - beq- cksave3 /* (TEST/DEBUG) */ - - rlwinm. r21,r28,0,4,19 /* (TEST/DEBUG) */ - bne+ cksave1 /* (TEST/DEBUG) */ - - bl currbad ; (TEST/DEBUG) - -cksave1: rlwinm. r21,r28,0,21,3 /* (TEST/DEBUG) */ - beq+ cksave2 /* (TEST/DEBUG) */ - - bl currbad ; (TEST/DEBUG) - -cksave2: lwz r25,SACalloc(r28) /* (TEST/DEBUG) */ - lbz r26,SACflags+2(r28) /* (TEST/DEBUG) */ - lbz r21,SACflags+3(r28) /* (TEST/DEBUG) */ - cmplwi r26,0x00EE /* (TEST/DEBUG) */ - stb r29,SACflags+3(r28) /* (TEST/DEBUG) */ - beq+ cksave2z - - bl currbad ; (TEST/DEBUG) - -cksave2z: mr. r21,r21 /* (TEST/DEBUG) */ - beq+ cksave2a /* (TEST/DEBUG) */ - - bl currbad ; (TEST/DEBUG) - -cksave2a: rlwinm r26,r25,1,31,31 /* (TEST/DEBUG) */ - rlwinm r27,r25,2,31,31 /* (TEST/DEBUG) */ - add r24,r24,r26 /* (TEST/DEBUG) */ - add r24,r24,r27 /* (TEST/DEBUG) */ - lwz r28,SACnext(r28) /* (TEST/DEBUG) */ - b cksave0a /* (TEST/DEBUG) */ - -cksave3: cmplw r24,r22 /* (TEST/DEBUG) */ - beq+ cksave4 /* (TEST/DEBUG) */ - - bl currbad ; (TEST/DEBUG) - -cksave4: lwz r28,SVfree(r8) /* (TEST/DEBUG) */ - li r24,0 /* (TEST/DEBUG) */ - -cksave5: mr. r28,r28 /* (TEST/DEBUG) */ - beq- cksave6 /* (TEST/DEBUG) */ - stb r24,SACflags+3(r28) /* (TEST/DEBUG) */ - lwz r28,SACnext(r28) /* (TEST/DEBUG) */ - b cksave5 /* (TEST/DEBUG) */ - -cksave6: - - li r4,0 /* (TEST/DEBUG) */ - stw r4,0xE80(br0) /* (TEST/DEBUG) */ - stw r4,0(r8) /* (TEST/DEBUG) */ - -doncheksv: - li r4,0 /* (TEST/DEBUG) */ - stw r4,0x20(br0) /* (TEST/DEBUG) */ - mtdec r12 /* (TEST/DEBUG) */ -#endif - - lis r4,HIGH_ADDR(EXT(MPspec)) /* Get the MP control block */ - dcbt 0,r2 /* We'll need the per_proc in a sec */ - cmplwi cr0,r11,T_INTERRUPT /* Do we have an external interrupt? */ - ori r4,r4,LOW_ADDR(EXT(MPspec)) /* Get the bottom half of the MP control block */ - bne+ notracex /* Not an external... */ - -/* - * Here we check to see if there was a interprocessor signal - */ - - lwz r4,MPSSIGPhandler(r4) /* Get the address of the SIGP interrupt filter */ - lhz r3,PP_CPU_FLAGS(r2) /* Get the CPU flags */ - cmplwi cr1,r4,0 /* Check if signal filter is initialized yet */ - andi. r3,r3,LOW_ADDR(SIGPactive) /* See if this processor has started up */ - mtlr r4 /* Load up filter address */ - beq- cr1,notracex /* We don't have a filter yet... */ - beq- notracex /* This processor hasn't started filtering yet... */ - - blrl /* Filter the interrupt */ - - mfsprg r2,0 /* Make sure we have the per processor block */ - cmplwi cr0,r3,kMPIOInterruptPending /* See what the filter says */ - li r11,T_INTERRUPT /* Assume we have a regular external 'rupt */ - beq+ modRupt /* Yeah, we figured it would be... */ - li r11,T_SIGP /* Assume we had a signal processor interrupt */ - bgt+ modRupt /* Yeah, at this point we would assume so... */ - li r11,T_IN_VAIN /* Nothing there actually, so eat it */ - -modRupt: stw r11,PP_SAVE_EXCEPTION_TYPE(r2) /* Set that it was either in vain or a SIGP */ - stw r11,saveexception(r13) /* Save the exception code here also */ - bne- cr5,notracex /* Jump if no tracing... */ - sth r11,LTR_excpt(r20) /* Save the exception type */ - -notracex: - -#if 0 - bf featSMP,nopir6 /* (TEST/DEBUG) */ - mfspr r7,pir /* (TEST/DEBUG) */ - b gotpir6 /* (TEST/DEBUG) */ -nopir6: li r7,0 /* (TEST/DEBUG) */ -gotpir6: /* (TEST/DEBUG) */ - lis r6,HIGH_ADDR(EXT(RuptCtrs)) /* (TEST/DEBUG) */ - rlwinm r7,r7,8,23,23 /* (TEST/DEBUG) */ - lis r12,HIGH_ADDR(EXT(GratefulDeb)) /* (TEST/DEBUG) */ - rlwimi r7,r7,1,22,22 /* (TEST/DEBUG) */ - ori r6,r6,LOW_ADDR(EXT(RuptCtrs)) /* (TEST/DEBUG) */ - rlwinm r1,r11,2,0,29 /* (TEST/DEBUG) */ - add r6,r6,r7 /* (TEST/DEBUG) */ - ori r12,r12,LOW_ADDR(EXT(GratefulDeb)) /* (TEST/DEBUG) */ - lwz r21,(47*16)+8(r6) /* (TEST/DEBUG) */ - lwz r22,(47*16)+12(r6) /* (TEST/DEBUG) */ - add r1,r1,r6 /* (TEST/DEBUG) */ - mftb r24 /* (TEST/DEBUG) */ - sub r22,r24,r22 /* (TEST/DEBUG) */ - lwz r4,4(r6) /* (TEST/DEBUG) */ - cmplw cr2,r22,r21 /* (TEST/DEBUG) */ - lwz r7,4(r1) /* (TEST/DEBUG) */ - lwz r21,8(r6) /* (TEST/DEBUG) */ - blt+ cr2,nottime /* (TEST/DEBUG) */ - stw r24,(47*16)+12(r6) /* (TEST/DEBUG) */ - -nottime: addi r4,r4,1 /* (TEST/DEBUG) */ - lwz r22,8(r1) /* (TEST/DEBUG) */ - addi r7,r7,1 /* (TEST/DEBUG) */ - stw r4,4(r6) /* (TEST/DEBUG) */ - lwz r3,0(r6) /* (TEST/DEBUG) */ - mr. r21,r21 /* (TEST/DEBUG) */ - stw r7,4(r1) /* (TEST/DEBUG) */ - mtlr r12 /* (TEST/DEBUG) */ - lwz r1,0(r1) /* (TEST/DEBUG) */ - beq- nottimed1 /* (TEST/DEBUG) */ - blt+ cr2,isnttime1 /* (TEST/DEBUG) */ - -nottimed1: mr. r3,r3 /* (TEST/DEBUG) */ - bgelrl+ /* (TEST/DEBUG) */ - -isnttime1: mr. r22,r22 /* (TEST/DEBUG) */ - beq- nottimed2 /* (TEST/DEBUG) */ - blt+ cr2,isnttime2 /* (TEST/DEBUG) */ - -nottimed2: mr. r3,r1 /* (TEST/DEBUG) */ - mtlr r12 /* (TEST/DEBUG) */ - mr r4,r7 /* (TEST/DEBUG) */ - bgelrl+ /* (TEST/DEBUG) */ - mr r3,r11 /* (TEST/DEBUG) */ - -isnttime2: cmplwi r11,T_DATA_ACCESS /* (TEST/DEBUG) */ - lis r12,HIGH_ADDR(EXT(GratefulDeb)) /* (TEST/DEBUG) */ - bne+ nodsidisp /* (TEST/DEBUG) */ - mr. r22,r22 /* (TEST/DEBUG) */ - beq- nottimed3 /* (TEST/DEBUG) */ - blt+ cr2,nodsidisp /* (TEST/DEBUG) */ - -nottimed3: li r3,5 /* (TEST/DEBUG) */ - ori r12,r12,LOW_ADDR(EXT(GratefulDeb)) /* (TEST/DEBUG) */ - lwz r4,savesrr0(r13) /* (TEST/DEBUG) */ - mtlr r12 /* (TEST/DEBUG) */ - blrl /* (TEST/DEBUG) */ - - lis r12,HIGH_ADDR(EXT(GratefulDeb)) /* (TEST/DEBUG) */ - ori r12,r12,LOW_ADDR(EXT(GratefulDeb)) /* (TEST/DEBUG) */ - lis r3,9 /* (TEST/DEBUG) */ - ori r3,r3,5 /* (TEST/DEBUG) */ - mtlr r12 /* (TEST/DEBUG) */ - lwz r4,savedar(r13) /* (TEST/DEBUG) */ - blrl /* (TEST/DEBUG) */ - -nodsidisp: cmplwi r11,T_INSTRUCTION_ACCESS /* (TEST/DEBUG) */ - lis r12,HIGH_ADDR(EXT(GratefulDeb)) /* (TEST/DEBUG) */ - bne+ noisidisp /* (TEST/DEBUG) */ - mr. r22,r22 /* (TEST/DEBUG) */ - beq- nottimed4 /* (TEST/DEBUG) */ - blt+ cr2,noisidisp /* (TEST/DEBUG) */ - -nottimed4: li r3,6 /* (TEST/DEBUG) */ - ori r12,r12,LOW_ADDR(EXT(GratefulDeb)) /* (TEST/DEBUG) */ - lwz r4,savesrr0(r13) /* (TEST/DEBUG) */ - mtlr r12 /* (TEST/DEBUG) */ - blrl /* (TEST/DEBUG) */ - -noisidisp: mr r3,r11 /* (TEST/DEBUG) */ -#endif - -#if 0 - cmplwi r11,T_PROGRAM /* (TEST/DEBUG) */ - lis r12,HIGH_ADDR(EXT(GratefulDeb)) /* (TEST/DEBUG) */ - bne+ nopgmdisp /* (TEST/DEBUG) */ - li r3,7 /* (TEST/DEBUG) */ - ori r12,r12,LOW_ADDR(EXT(GratefulDeb)) /* (TEST/DEBUG) */ - lwz r4,savesrr0(r13) /* (TEST/DEBUG) */ - mtlr r12 /* (TEST/DEBUG) */ - blrl /* (TEST/DEBUG) */ - -nopgmdisp: mr r3,r11 /* (TEST/DEBUG) */ -#endif +; +; We are done with the trace, except for maybe modifying the exception +; code later on. So, that means that we need to save R20 and CR5. +; +; So, finish setting up the kernel registers now. +; - li r21,0 ; Assume no processor register for now +skipTrace: lhz r21,PP_CPU_NUMBER(r2) ; Get the logical processor number lis r12,hi16(EXT(hw_counts)) ; Get the high part of the interrupt counters - bf featSMP,nopirhere ; Jump if this processor does not have a PIR... - mfspr r21,pir ; Get the PIR - -nopirhere: ori r12,r12,lo16(EXT(hw_counts)) ; Get the low part of the interrupt counters lwz r7,savesrr1(r13) ; Get the entering MSR + ori r12,r12,lo16(EXT(hw_counts)) ; Get the low part of the interrupt counters rlwinm r21,r21,8,20,23 ; Get index to processor counts - mtcrf 0x80,r0 /* Set our CR0 to the high nybble of the request code */ - rlwinm r6,r0,1,0,31 /* Move sign bit to the end */ - cmplwi cr1,r11,T_SYSTEM_CALL /* Did we get a system call? */ - crandc cr0_lt,cr0_lt,cr0_gt /* See if we have R0 equal to 0b10xx...x */ + mtcrf 0x80,r0 ; Set our CR0 to the high nybble of possible syscall code + rlwinm r6,r0,1,0,31 ; Move sign bit to the end + cmplwi cr1,r11,T_SYSTEM_CALL ; Did we get a system call? add r12,r12,r21 ; Point to the processor count area - cmplwi cr3,r11,T_IN_VAIN /* Was this all in vain? All for nothing? */ + crandc cr0_lt,cr0_lt,cr0_gt ; See if we have R0 equal to 0b10xx...x lwzx r22,r12,r11 ; Get the old value - cmplwi cr2,r6,1 /* See if original R0 had the CutTrace request code in it */ + cmplwi cr3,r11,T_IN_VAIN ; Was this all in vain? All for nothing? addi r22,r22,1 ; Count this one - cmplwi cr4,r11,T_SIGP /* Indicate if we had a SIGP 'rupt */ + cmplwi cr2,r6,1 ; See if original R0 had the CutTrace request code in it stwx r22,r12,r11 ; Store it back - beq- cr3,EatRupt /* Interrupt was all for nothing... */ + beq- cr3,EatRupt ; Interrupt was all for nothing... cmplwi cr3,r11,T_MACHINE_CHECK ; Did we get a machine check? - bne+ cr1,noCutT /* Not a system call... */ - bnl+ cr0,noCutT /* R0 not 0b10xxx...x, can't be any kind of magical system call... */ + bne+ cr1,noCutT ; Not a system call... + bnl+ cr0,noCutT ; R0 not 0b10xxx...x, can not be any kind of magical system call... rlwinm. r7,r7,0,MSR_PR_BIT,MSR_PR_BIT ; Did we come from user state? lis r1,hi16(EXT(dgWork)) ; Get the diagnostics flags beq+ FCisok ; From supervisor state... @@ -1604,128 +1263,144 @@ nopirhere: ori r12,r12,lo16(EXT(hw_counts)) ; Get the low part of the interrupt rlwinm. r1,r1,0,enaUsrFCallb,enaUsrFCallb ; Are they valid? beq- noCutT ; No... -FCisok: beq- cr2,isCutTrace /* This is a CutTrace system call */ +FCisok: beq- cr2,isCutTrace ; This is a CutTrace system call... -/* - * Here's where we call the firmware. If it returns T_IN_VAIN, that means - * that it has handled the interruption. Remember: thou shalt not trash R13 - * or R20 while you are away. Anything else is ok. - */ - - lis r1,hi16(EXT(FirmwareCall)) /* Top half of firmware call handler */ - ori r1,r1,lo16(EXT(FirmwareCall)) /* Bottom half of it */ - lwz r3,saver3(r13) /* Restore the first parameter, the rest are ok already */ - mtlr r1 /* Get it in the link register */ - blrl /* Call the handler */ - - cmplwi r3,T_IN_VAIN /* Was it handled? */ - mfsprg r2,0 /* Restore the per_processor area */ - beq+ EatRupt /* Interrupt was handled... */ - mr r11,r3 /* Put the 'rupt code in the right register */ - b noSIGP /* Go to the normal system call handler */ +; +; Here is where we call the firmware. If it returns T_IN_VAIN, that means +; that it has handled the interruption. Remember: thou shalt not trash R13 +; or R20 while you are away. Anything else is ok. +; + + lwz r3,saver3(r13) ; Restore the first parameter + bl EXT(FirmwareCall) ; Go handle the firmware call.... + + cmplwi r3,T_IN_VAIN ; Was it handled? + mfsprg r2,0 ; Restore the per_proc + beq+ EatRupt ; Interrupt was handled... + mr r11,r3 ; Put the rupt code into the right register + b filter ; Go to the normal system call handler... + + .align 5 isCutTrace: - li r7,-32768 /* Get a 0x8000 for the exception code */ - bne- cr5,EatRupt /* Tracing is disabled... */ - sth r7,LTR_excpt(r20) /* Modify the exception type to a CutTrace */ - b EatRupt /* Time to go home... */ + li r7,-32768 ; Get a 0x8000 for the exception code + bne- cr5,EatRupt ; Tracing is disabled... + sth r7,LTR_excpt(r20) ; Modify the exception type to a CutTrace + b EatRupt ; Time to go home... -/* We are here 'cause we didn't have a CutTrace system call */ +; We are here because we did not have a CutTrace system call + + .align 5 noCutT: beq- cr3,MachineCheck ; Whoa... Machine check... - bne+ cr4,noSIGP /* Skip away if we didn't get a SIGP... */ - - lis r6,HIGH_ADDR(EXT(MPsignalFW)) /* Top half of SIGP handler */ - ori r6,r6,LOW_ADDR(EXT(MPsignalFW)) /* Bottom half of it */ - mtlr r6 /* Get it in the link register */ - - blrl /* Call the handler - we'll only come back if this is an AST, */ - /* 'cause FW can't handle that */ - mfsprg r2,0 /* Restore the per_processor area */ + ; ; The following interrupts are the only ones that can be redriven ; by the higher level code or emulation routines. ; -Redrive: cmplwi cr0,r3,T_IN_VAIN /* Did the signal handler eat the signal? */ - mr r11,r3 /* Move it to the right place */ - beq+ cr0,EatRupt /* Bail now if the signal handler processed the signal... */ +Redrive: cmplwi cr0,r11,T_IN_VAIN ; Did the signal handler eat the signal? + mfsprg r2,0 ; Get the per_proc block + beq+ cr0,EatRupt ; Bail now if we ate the rupt... -/* - * Here's where we check for the other fast-path exceptions: translation exceptions, - * emulated instructions, etc. - */ +; +; Here ss where we check for the other fast-path exceptions: translation exceptions, +; emulated instructions, etc. +; -noSIGP: cmplwi cr3,r11,T_ALTIVEC_ASSIST ; Check for an Altivec denorm assist - cmplwi cr1,r11,T_PROGRAM /* See if we got a program exception */ - cmplwi cr2,r11,T_INSTRUCTION_ACCESS /* Check on an ISI */ +filter: cmplwi cr3,r11,T_ALTIVEC_ASSIST ; Check for an Altivec denorm assist + cmplwi cr4,r11,T_ALIGNMENT ; See if we got an alignment exception + cmplwi cr1,r11,T_PROGRAM ; See if we got a program exception + cmplwi cr2,r11,T_INSTRUCTION_ACCESS ; Check on an ISI bne+ cr3,noAltivecAssist ; It is not an assist... b EXT(AltivecAssist) ; It is an assist... + + .align 5 noAltivecAssist: + bne+ cr4,noAlignAssist ; No alignment here... + b EXT(AlignAssist) ; Go try to emulate... + + .align 5 + +noAlignAssist: bne+ cr1,noEmulate ; No emulation here... b EXT(Emulate) ; Go try to emulate... -noEmulate: cmplwi cr3,r11,T_CSWITCH /* Are we context switching */ - cmplwi r11,T_DATA_ACCESS /* Check on a DSI */ - beq- cr2,DSIorISI /* It's a PTE fault... */ - beq- cr3,conswtch /* It's a context switch... */ - bne+ PassUp /* It's not a PTE fault... */ + .align 5 -/* - * This call will either handle the fault, in which case it will not - * return, or return to pass the fault up the line. - */ +noEmulate: cmplwi cr3,r11,T_CSWITCH ; Are we context switching + cmplwi r11,T_DATA_ACCESS ; Check on a DSI + beq- cr2,DSIorISI ; It is a PTE fault... + beq- cr3,conswtch ; It is a context switch... + bne+ PassUp ; It is not a PTE fault... + +; +; This call will either handle the fault, in which case it will not +; return, or return to pass the fault up the line. +; -DSIorISI: - lis r7,HIGH_ADDR(EXT(handlePF)) /* Top half of DSI handler */ - ori r7,r7,LOW_ADDR(EXT(handlePF)) /* Bottom half of it */ - mtlr r7 /* Get it in the link register */ - mr r3,r11 /* Move the 'rupt code */ +DSIorISI: mr r3,r11 ; Move the rupt code - blrl /* See if we can handle this fault */ + bl EXT(handlePF) ; See if we can handle this fault lwz r0,savesrr1(r13) ; Get the MSR in use at exception time - mfsprg r2, 0 /* Get back per_proc */ + mfsprg r2,0 ; Get back per_proc cmplwi cr1,r3,T_IN_VAIN ; Was it handled? andi. r4,r0,lo16(MASK(MSR_RI)) ; See if the recover bit is on - mr r11,r3 /* Make sure we can find this later */ + mr r11,r3 ; Put interrupt code back into the right register beq+ cr1,EatRupt ; Yeah, just blast back to the user... - andc r0,r0,r4 ; Remove the recover bit beq+ PassUp ; Not on, normal case... +; +; Here is where we handle the "recovery mode" stuff. +; This is set by an emulation routine to trap any faults when it is fetching data or +; instructions. +; +; If we get a fault, we turn off RI, set CR0_EQ to false, bump the PC, and set R0 +; and R1 to the DAR and DSISR, respectively. +; lwz r4,savesrr0(r13) ; Get the failing instruction address lwz r5,savecr(r13) ; Get the condition register - stw r0,savesrr1(r13) ; Save the result MSR addi r4,r4,4 ; Skip failing instruction + lwz r6,savedar(r13) ; Get the DAR rlwinm r5,r5,0,3,1 ; Clear CR0_EQ to let emulation code know we failed - stw r4,savesrr0(r13) ; Save instruction address - stw r4,savecr(r13) ; And the resume CR + lwz r7,savedsisr(r13) ; Grab the DSISR + stw r0,savesrr1(r13) ; Save the result MSR + stw r4,savesrr0(r13) ; Save resume address + stw r5,savecr(r13) ; And the resume CR + stw r6,saver0(r13) ; Pass back the DAR + stw r7,saver1(r13) ; Pass back the DSISR b EatRupt ; Resume emulated code -/* - * Here is where we handle the context switch firmware call. The old - * context has been saved, and the new savearea in in saver3. We'll just - * muck around with the savearea pointers, and then join the exit routine - */ -conswtch: lwz r28,SAVflags(r13) /* The the flags of the current */ - mr r29,r13 /* Save the save */ - rlwinm r30,r13,0,0,19 /* Get the start of the savearea block */ - lwz r5,saver3(r13) /* Switch to the new savearea */ - oris r28,r28,HIGH_ADDR(SAVattach) /* Turn on the attached flag */ - lwz r30,SACvrswap(r30) /* get real to virtual translation */ - mr r13,r5 /* Switch saveareas */ - xor r27,r29,r30 /* Flip to virtual */ - stw r28,SAVflags(r29) /* Stash it back */ - stw r27,saver3(r5) /* Push the new savearea to the switch to routine */ - b EatRupt /* Start 'er up... */ +; +; Here is where we handle the context switch firmware call. The old +; context has been saved, and the new savearea in in saver3. We will just +; muck around with the savearea pointers, and then join the exit routine +; + + .align 5 + +conswtch: + mr r29,r13 ; Save the save + rlwinm r30,r13,0,0,19 ; Get the start of the savearea block + lwz r5,saver3(r13) ; Switch to the new savearea + lwz r30,SACvrswap(r30) ; get real to virtual translation + mr r13,r5 ; Switch saveareas + xor r27,r29,r30 ; Flip to virtual + stw r27,saver3(r5) ; Push the new savearea to the switch to routine + b EatRupt ; Start it up... ; ; Handle machine check here. ; ; ? ; + + .align 5 + MachineCheck: + lwz r27,savesrr1(r13) ; ? rlwinm. r11,r27,0,dcmck,dcmck ; ? beq+ notDCache ; ? @@ -1750,9 +1425,9 @@ rstbsy: mfspr r11,msscr0 ; ? sync ; ? - li r11,T_IN_VAIN ; ? b EatRupt ; ? + .align 5 notDCache: ; @@ -1802,7 +1477,6 @@ notDCache: stw r28,savesrr0(r13) ; Set the return point stw r27,savesrr1(r13) ; Set the continued MSR stw r30,saver3(r13) ; Set return code - li r11,T_IN_VAIN ; Set new interrupt code b EatRupt ; Yum, yum, eat it all up... /* @@ -1817,10 +1491,10 @@ notDCache: LEXT(EmulExit) - cmplwi r11,T_IN_VAIN /* Was it emulated? */ + cmplwi r11,T_IN_VAIN ; Was it emulated? lis r1,hi16(SAVredrive) ; Get redrive request mfsprg r2,0 ; Restore the per_proc area - beq+ EatRupt /* Yeah, just blast back to the user... */ + beq+ EatRupt ; Yeah, just blast back to the user... lwz r4,SAVflags(r13) ; Pick up the flags and. r0,r4,r1 ; Check if redrive requested @@ -1828,38 +1502,38 @@ LEXT(EmulExit) beq+ PassUp ; No redrive, just keep on going... - lwz r3,saveexception(r13) ; Restore exception code stw r4,SAVflags(r13) ; Set the flags b Redrive ; Redrive the exception... -/* Jump into main handler code switching on VM at the same time */ +; +; Jump into main handler code switching on VM at the same time. +; +; We assume kernel data is mapped contiguously in physical +; memory, otherwise we would need to switch on (at least) virtual data. +; SRs are already set up. +; + + .align 5 -/* We assume kernel data is mapped contiguously in physical - * memory, otherwise we'd need to switch on (at least) virtual data. - * SRs are already set up. - */ PassUp: lis r2,hi16(EXT(exception_handlers)) ; Get exception vector address ori r2,r2,lo16(EXT(exception_handlers)) ; And low half - lwzx r6,r2,r11 /* Get the actual exception handler address */ - -PassUpDeb: lwz r8,SAVflags(r13) /* Get the flags */ - mtsrr0 r6 /* Set up the handler address */ - oris r8,r8,HIGH_ADDR(SAVattach) /* Since we're passing it up, attach it */ - rlwinm r5,r13,0,0,19 /* Back off to the start of savearea block */ - - mfmsr r3 /* Get our MSR */ - stw r8,SAVflags(r13) /* Pass up the flags */ - rlwinm r3,r3,0,MSR_BE_BIT+1,MSR_SE_BIT-1 /* Clear all but the trace bits */ - li r2,MSR_SUPERVISOR_INT_OFF /* Get our normal MSR value */ - lwz r5,SACvrswap(r5) /* Get real to virtual conversion */ - or r2,r2,r3 /* Keep the trace bits if they're on */ - mr r3,r11 /* Pass the exception code in the paramter reg */ - mtsrr1 r2 /* Set up our normal MSR value */ - xor r4,r13,r5 /* Pass up the virtual address of context savearea */ - - rfi /* Launch the exception handler */ - - .long 0 /* Leave these here gol durn it! */ + lwzx r6,r2,r11 ; Get the actual exception handler address + +PassUpDeb: mtsrr0 r6 ; Set up the handler address + rlwinm r5,r13,0,0,19 ; Back off to the start of savearea block + + mfmsr r3 ; Get our MSR + rlwinm r3,r3,0,MSR_BE_BIT+1,MSR_SE_BIT-1 ; Clear all but the trace bits + li r2,MSR_SUPERVISOR_INT_OFF ; Get our normal MSR value + lwz r5,SACvrswap(r5) ; Get real to virtual conversion + or r2,r2,r3 ; Keep the trace bits if they are on + mr r3,r11 ; Pass the exception code in the paramter reg + mtsrr1 r2 ; Set up our normal MSR value + xor r4,r13,r5 ; Pass up the virtual address of context savearea + + rfi ; Launch the exception handler + + .long 0 ; Leave these here gol durn it! .long 0 .long 0 .long 0 @@ -1884,59 +1558,35 @@ PassUpDeb: lwz r8,SAVflags(r13) /* Get the flags */ * before we get here. * * Speaking of tomfoolery, this is where we synthesize interruptions - * if any need to be. + * if we need to. */ .align 5 -EatRupt: mr r31,r13 /* Move the savearea pointer to the far end of the register set */ - -EatRupt2: mfsprg r2,0 /* Get the per_proc block */ - dcbt 0,r31 ; Get this because we need it very soon - -#if TRCSAVE - lwz r30,saver0(r31) ; (TEST/DEBUG) Get users R0 - lwz r20,saveexception(r31) ; (TEST/DEBUG) Returning from trace? - xor r30,r20,r30 ; (TEST/DEBUG) Make code - rlwinm r30,r30,1,0,31 ; (TEST/DEBUG) Make an easy test - cmplwi cr5,r30,0x61 ; (TEST/DEBUG) See if this is a trace -#endif - -/* - * First we see if we are able to free the new savearea. - * If it is not attached to anything, put it on the free list. - * This is real dangerous, we haven't restored context yet... - * So, the free savearea chain lock must stay until the bitter end! - */ +EatRupt: mfsprg r29,0 ; Get the per_proc block back + mr r31,r13 ; Move the savearea pointer to the far end of the register set + + lwz r30,quickfret(r29) ; Pick up the quick fret list, if any -/* - * It's dangerous here. We haven't restored anything from the current savearea yet. - * And, we mark it the active one. So, if we get an exception in here, it is - * unrecoverable. Unless we mess up, we can't get any kind of exception. So, - * it is important to assay this code as only the purest of gold. - * - * But first, see if there is a savearea hanging off of quickfret. If so, - * we release that one first and then come back for the other. We should rarely - * see one, they appear when FPU or VMX context is discarded by either returning - * to a higher exception level, or explicitly. - * - * A word about QUICKFRET: Multiple saveareas may be queued for release. It is - * the responsibility of the queuer to insure that the savearea is not multiply - * queued and that the appropriate inuse bits are reset. - */ + mfsprg r27,2 ; Get the processor features + lwz r21,savesrr1(r31) ; Get destination MSR + +erchkfret: mr. r3,r30 ; Any savearea to quickly release? + beq+ ernoqfret ; No quickfrets... + lwz r30,SAVprev(r30) ; Chain back now + + bl EXT(save_ret_phys) ; Put it on the free list + stw r30,quickfret(r29) ; Dequeue previous guy (really, it is ok to wait until after the release) + b erchkfret ; Try the next one... - - mfsprg r27,2 ; Get the processor features - lwz r1,savesrr1(r31) ; Get destination MSR - mtcrf 0x60,r27 ; Set CRs with thermal facilities - mr r18,r31 ; Save the savearea pointer - rlwinm. r0,r1,0,MSR_EE_BIT,MSR_EE_BIT ; Are interruptions going to be enabled? - lwz r19,PP_QUICKFRET(r2) ; Get the quick release savearea + .align 5 + +ernoqfret: mtcrf 0x60,r27 ; Set CRs with thermal facilities + rlwinm. r0,r21,0,MSR_EE_BIT,MSR_EE_BIT ; Are interruptions going to be enabled? crandc 31,pfThermalb,pfThermIntb ; See if we have both thermometer and not interrupt facility - li r0,0 ; Get a zero - crandc 31,31,cr0_eq ; Factor in enablement - la r21,savesr0(r18) ; Point to the first thing we restore + la r21,saver0(r31) ; Point to the first thing we restore + crandc 31,cr0_eq,31 ; Factor in enablement bf 31,tempisok ; No thermal checking needed... ; @@ -1963,177 +1613,43 @@ EatRupt2: mfsprg r2,0 /* Get the per_proc block */ andc r14,r14,r0 ; Keep low if high did not interrupt, zero if it did bne+ tempisok ; Nope, temprature is in range - li r3,T_THERMAL ; Time to emulate a thermal interruption + li r11,T_THERMAL ; Time to emulate a thermal interruption or r14,r14,r15 ; Get contents of interrupting register mr r13,r31 ; Make sure savearea is pointed to correctly - stw r3,saveexception(r31) ; Restore exception code + stw r11,saveexception(r31) ; Set the exception code stw r14,savedar(r31) ; Set the contents of the interrupting register into the dar - b Redrive ; Go process this new interruption... +; +; This code is here to prevent a problem that will probably never happen. If we are +; returning from an emulation routine (alignment, altivec assist, etc.) the SRs may +; not be set to the proper kernel values. Then, if we were to emulate a thermal here, +; we would end up running in the kernel with a bogus SR. So, to prevent +; this unfortunate circumstance, we slam the SRs here. (I worry too much...) +; -tempisok: lis r30,HIGH_ADDR(EXT(saveanchor)) /* Get the high part of the anchor */ - stw r0,PP_QUICKFRET(r2) /* Clear quickfret pointer */ - ori r30,r30,LOW_ADDR(EXT(saveanchor)) /* Bottom half of the anchor */ - dcbt 0,r21 /* Touch in the first thing */ - -#if 0 - li r23,0 ; (TEST/DEBUG) - rlwinm r14,r31,0,0,19 ; (TEST/DEBUG) - lwz r21,SACflags(r14) ; (TEST/DEBUG) - rlwinm r22,r21,24,24,31 ; (TEST/DEBUG) - cmplwi r22,0x00EE ; (TEST/DEBUG) - beq+ nodienodie1 ; (TEST/DEBUG) - -dodiedodie: li r1,0x666 ; (TEST/DEBUG) - BREAKPOINT_TRAP ; (TEST/DEBUG) - -nodienodie1: - mr r23,r19 ; (TEST/DEBUG) - -chkitagain: mr. r23,r23 ; (TEST/DEBUG) - beq nodienodie2 ; (TEST/DEBUG) - rlwinm r14,r23,0,0,19 ; (TEST/DEBUG) - lwz r21,SACflags(r14) ; (TEST/DEBUG) - rlwinm r22,r21,24,24,31 ; (TEST/DEBUG) - cmplwi r22,0x00EE ; (TEST/DEBUG) - bne- dodiedodie ; (TEST/DEBUG) - lwz r23,SAVqfret(r23) ; (TEST/DEBUG) - b chkitagain ; (TEST/DEBUG) - -nodienodie2: -#endif + lis r30,hi16(KERNEL_SEG_REG0_VALUE) ; Get the high half of the kernel SR0 value + mtsr sr0,r30 ; Set the kernel SR0 + addis r30,r30,0x0010 ; Point to the second segment of kernel + mtsr sr1,r30 ; Set the kernel SR1 + addis r30,r30,0x0010 ; Point to the third segment of kernel + mtsr sr2,r30 ; Set the kernel SR2 + addis r30,r30,0x0010 ; Point to the third segment of kernel + mtsr sr3,r30 ; Set the kernel SR3 + b Redrive ; Go process this new interruption... -#if TRCSAVE - beq- cr5,trkill0 ; (TEST/DEBUG) Do not trace this type - lwz r14,LOW_ADDR(traceMask-EXT(ExceptionVectorsStart))(br0) ; (TEST/DEBUG) Get the trace mask - mr. r14,r14 ; (TEST/DEBUG) Is it stopped? - beq- trkill0 ; (TEST/DEBUG) yes... - bl cte ; (TEST/DEBUG) Trace this - stw r18,LTR_r1(r20) ; (TEST/DEBUG) Normal savearea - stw r19,LTR_r2(r20) ; (TEST/DEBUG) Quickfret savearea -trkill0: -#endif -rtlck: lwarx r22,0,r30 /* Grab the lock value */ - li r23,1 /* Use part of the delay time */ - mr. r22,r22 /* Is it locked? */ - bne- rtlcks /* Yeah, wait for it to clear... */ - stwcx. r23,0,r30 /* Try to seize that there durn lock */ - beq+ fretagain ; Got it... - b rtlck /* Collision, try again... */ +tempisok: dcbt 0,r21 ; Touch in the first thing we need -rtlcks: lwz r22,SVlock(r30) /* Get that lock in here */ - mr. r22,r22 /* Is it free yet? */ - beq+ rtlck /* Yeah, try for it again... */ - b rtlcks /* Sniff away... */ - ; -; Lock gotten, toss the saveareas +; Here we release the savearea. ; -fretagain: isync ; Toss those prefetches -#if TRCSAVE - beq- cr5,trkill1 ; (TEST/DEBUG) Do not trace this type - lwz r14,LOW_ADDR(traceMask-EXT(ExceptionVectorsStart))(br0) ; (TEST/DEBUG) Get the trace mask - mr. r14,r14 ; (TEST/DEBUG) Is it stopped? - beq- trkill1 ; (TEST/DEBUG) yes... - li r0,1 ; (TEST/DEBUG) ID number - bl cte ; (TEST/DEBUG) Trace this - stw r18,LTR_r1(r20) ; (TEST/DEBUG) Normal savearea - stw r19,LTR_r2(r20) ; (TEST/DEBUG) Quickfret savearea -trkill1: -#endif - - mr. r18,r18 ; Are we actually done here? - beq- donefret ; Yeah... - mr. r31,r19 ; Is there a quickfret to do? - beq+ noqfrt ; Nope... - lwz r19,SAVqfret(r19) ; Yes, get the next in line -#if TRCSAVE - beq- cr5,trkill2 ; (TEST/DEBUG) Do not trace this type - lwz r14,LOW_ADDR(traceMask-EXT(ExceptionVectorsStart))(br0) ; (TEST/DEBUG) Get the trace mask - mr. r14,r14 ; (TEST/DEBUG) Is it stopped? - beq- trkill2 ; (TEST/DEBUG) yes... - li r0,2 ; (TEST/DEBUG) ID number - bl cte ; (TEST/DEBUG) Trace this - stw r18,LTR_r1(r20) ; (TEST/DEBUG) Normal savearea - stw r19,LTR_r2(r20) ; (TEST/DEBUG) next quickfret savearea - stw r31,LTR_r3(r20) ; (TEST/DEBUG) Current one to toss -trkill2: -#endif - b doqfrt ; Go do it... - -noqfrt: mr r31,r18 ; Set the area to release - li r18,0 ; Show we have done it -#if TRCSAVE - beq- cr5,trkill3 ; (TEST/DEBUG) Do not trace this type - lwz r14,LOW_ADDR(traceMask-EXT(ExceptionVectorsStart))(br0) ; (TEST/DEBUG) Get the trace mask - mr. r14,r14 ; (TEST/DEBUG) Is it stopped? - beq- trkill3 ; (TEST/DEBUG) yes... - li r0,3 ; (TEST/DEBUG) ID number - bl cte ; (TEST/DEBUG) Trace this - stw r18,LTR_r1(r20) ; (TEST/DEBUG) Normal savearea - stw r19,LTR_r2(r20) ; (TEST/DEBUG) next quickfret savearea - stw r31,LTR_r3(r20) ; (TEST/DEBUG) Current one to toss -trkill3: -#endif - -doqfrt: li r0,0 ; Get a constant 0 - lis r26,0x8000 /* Build a bit mask and assume first savearea */ - stw r0,SAVqfret(r31) ; Make sure back chain is unlinked - lwz r28,SAVflags(r31) ; Get the flags for the old active one -#if TRCSAVE - beq- cr5,trkill4 ; (TEST/DEBUG) Do not trace this type - lwz r14,LOW_ADDR(traceMask-EXT(ExceptionVectorsStart))(br0) ; (TEST/DEBUG) Get the trace mask - mr. r14,r14 ; (TEST/DEBUG) Is it stopped? - beq- trkill4 ; (TEST/DEBUG) yes... - li r0,4 ; (TEST/DEBUG) ID number - bl cte ; (TEST/DEBUG) Trace this - stw r18,LTR_r1(r20) ; (TEST/DEBUG) Normal savearea - stw r19,LTR_r2(r20) ; (TEST/DEBUG) next quickfret savearea - stw r31,LTR_r3(r20) ; (TEST/DEBUG) Current one to toss - stw r28,LTR_r4(r20) ; (TEST/DEBUG) Save current flags -trkill4: -#endif - rlwinm r25,r31,21,31,31 /* Get position of savearea in block */ - andis. r28,r28,HIGH_ADDR(SAVinuse) /* See if we need to free it */ - srw r26,r26,r25 /* Get bit position to deallocate */ - rlwinm r29,r31,0,0,19 /* Round savearea pointer to even page address */ - - bne- fretagain /* Still in use, we can't free this one... */ - - lwz r23,SACalloc(r29) /* Get the allocation for this block */ - lwz r24,SVinuse(r30) /* Get the in use count */ - mr r28,r23 ; (TEST/DEBUG) save for trace - or r23,r23,r26 /* Turn on our bit */ - subi r24,r24,1 /* Show that this one is free */ - cmplw r23,r26 /* Is our's the only one free? */ - stw r23,SACalloc(r29) /* Save it out */ - bne+ rstrest /* Nope, then the block is already on the free list */ - - lwz r22,SVfree(r30) /* Get the old head of the free list */ - stw r29,SVfree(r30) /* Point the head at us now */ - stw r22,SACnext(r29) ; Point us to the old last - -rstrest: stw r24,SVinuse(r30) /* Set the in use count */ -#if TRCSAVE - beq- cr5,trkill5 ; (TEST/DEBUG) Do not trace this type - lwz r14,LOW_ADDR(traceMask-EXT(ExceptionVectorsStart))(br0) ; (TEST/DEBUG) Get the trace mask - mr. r14,r14 ; (TEST/DEBUG) Is it stopped? - beq- trkill5 ; (TEST/DEBUG) yes... - li r0,5 ; (TEST/DEBUG) ID number - bl cte ; (TEST/DEBUG) Trace this - stw r18,LTR_r1(r20) ; (TEST/DEBUG) Normal savearea - stw r19,LTR_r2(r20) ; (TEST/DEBUG) Next quickfret savearea - stw r31,LTR_r3(r20) ; (TEST/DEBUG) Current one to toss - stw r28,LTR_srr1(r20) ; (TEST/DEBUG) Save the original allocation - stw r23,LTR_dar(r20) ; (TEST/DEBUG) Save the new allocation - stw r24,LTR_save(r20) ; (TEST/DEBUG) Save the new in use count - stw r22,LTR_lr(r20) ; (TEST/DEBUG) Save the old top of free list - stw r29,LTR_ctr(r20) ; (TEST/DEBUG) Save the new top of free list -trkill5: -#endif - b fretagain ; Go finish up the rest... - +; Important!!!! The savearea is released before we are done with it. When the +; local free savearea list (anchored at lclfree) gets too long, save_ret_phys +; will trim the list, making the extra saveareas allocatable by another processor +; The code in there must ALWAYS leave our savearea on the local list, otherwise +; we could be very, very unhappy. The code there always queues the "just released" +; savearea to the head of the local list. Then, if it needs to trim, it will +; start with the SECOND savearea, leaving ours intact. ; ; Build the SR values depending upon destination. If we are going to the kernel, ; the SRs are almost all the way set up. SR14 (or the currently used copyin/out register) @@ -2145,14 +1661,39 @@ trkill5: ; they are different that what was loaded last time (i.e., tasks have switched). ; We check the last loaded address space ID and if the same, we skip the loads. ; This is a performance gain because SR manipulations are slow. +; +; There is also the special case when MSR_RI is set. This happens when we are trying to +; make a special user state access when we are in the kernel. If we take an exception when +; during that, the SRs may have been modified. Therefore, we need to restore them to +; what they were before the exception because they could be non-standard. We saved them +; during exception entry, so we will just load them here. ; - .align 5 - -donefret: lwz r26,savesrr1(r31) ; Get destination state flags - lwz r7,PP_USERPMAP(r2) ; Pick up the user pmap we may launch + mr r3,r31 ; Get the exiting savearea in parm register + bl EXT(save_ret_phys) ; Put it on the free list + + li r3,savesrr1 ; Get offset to the srr1 value + + lwarx r26,r3,r31 ; Get destination MSR and take reservation along the way (just so we can blow it away) + lwz r7,PP_USERPMAP(r29) ; Pick up the user pmap we may launch + rlwinm. r17,r26,0,MSR_RI_BIT,MSR_RI_BIT ; See if we are returning from a special fault cmplw cr3,r14,r14 ; Set that we do not need to stop streams - rlwinm. r17,r26,0,MSR_PR_BIT,MSR_PR_BIT ; See if we are going to user or system + + beq+ nSpecAcc ; Do not reload the kernel SRs if this is not a special access... + + lwz r14,savesr0(r31) ; Get SR0 at fault time + mtsr sr0,r14 ; Set SR0 + lwz r14,savesr1(r31) ; Get SR1 at fault time + mtsr sr1,r14 ; Set SR1 + lwz r14,savesr2(r31) ; Get SR2 at fault time + mtsr sr2,r14 ; Set SR2 + lwz r14,savesr3(r31) ; Get SR3 at fault timee + mtsr sr3,r14 ; Set SR3 + b segsdone ; We are all set up now... + + .align 5 + +nSpecAcc: rlwinm. r17,r26,0,MSR_PR_BIT,MSR_PR_BIT ; See if we are going to user or system li r14,PMAP_SEGS ; Point to segments bne+ gotouser ; We are going into user state... @@ -2163,8 +1704,8 @@ donefret: lwz r26,savesrr1(r31) ; Get destination state flags .align 5 gotouser: dcbt r14,r7 ; Touch the segment register contents - lwz r9,spcFlags(r2) ; Pick up the special flags - lwz r16,PP_LASTPMAP(r2) ; Pick up the last loaded pmap + lwz r9,spcFlags(r29) ; Pick up the special flags + lwz r16,PP_LASTPMAP(r29) ; Pick up the last loaded pmap addi r14,r14,32 ; Second half of pmap segments rlwinm r9,r9,userProtKeybit-2,2,2 ; Isolate the user state protection key lwz r15,PMAP_SPACE(r7) ; Get the primary space @@ -2173,7 +1714,7 @@ gotouser: dcbt r14,r7 ; Touch the segment register contents oris r15,r15,hi16(SEG_REG_PROT) ; Set segment 0 SR value mtcrf 0x0F,r13 ; Set CRs to correspond to the subordinate spaces xor r15,r15,r9 ; Flip to proper segment register key - lhz r9,PP_CPU_FLAGS(r2) ; Get the processor flags + lhz r9,PP_CPU_FLAGS(r29) ; Get the processor flags addis r13,r15,0x0000 ; Get SR0 value bf 16,nlsr0 ; No alternate here... @@ -2189,7 +1730,7 @@ nlsr0: mtsr sr0,r13 ; Load up the SR nlsr1: mtsr sr1,r13 ; Load up the SR or r26,r26,r9 ; Flip on the BE bit for special trace if needed - cmplw r7,r16 ; Are we running the same segs as last time? + cmplw cr3,r7,r16 ; Are we running the same segs as last time? addis r13,r15,0x0020 ; Get SR2 value bf 18,nlsr2 ; No alternate here... @@ -2209,9 +1750,9 @@ nlsr3: mtsr sr3,r13 ; Load up the SR nlsr14: mtsr sr14,r13 ; Load up the SR - beq+ segsdone ; All done if same pmap as last time... + beq+ cr3,segsdone ; All done if same pmap as last time... - stw r7,PP_LASTPMAP(r2) ; Remember what we just loaded + stw r7,PP_LASTPMAP(r29) ; Remember what we just loaded addis r13,r15,0x0040 ; Get SR4 value bf 20,nlsr4 ; No alternate here... @@ -2279,129 +1820,114 @@ nlsr13: mtsr sr13,r13 ; Load up the SR nlsr15: mtsr sr15,r13 ; Load up the SR -segsdone: li r1,emfp0 ; Point to the fp savearea +segsdone: stwcx. r26,r3,r31 ; Blow away any reservations we hold + + li r21,emfp0 ; Point to the fp savearea lwz r25,savesrr0(r31) ; Get the SRR0 to use - la r28,saver6(r31) /* Point to the next line to use */ - dcbt r1,r2 ; Start moving in a work area - lwz r0,saver0(r31) /* Restore */ - dcbt 0,r28 /* Touch it in */ - mr r29,r2 ; Save the per_proc - lwz r1,saver1(r31) /* Restore */ - lwz r2,saver2(r31) /* Restore */ - la r28,saver14(r31) /* Point to the next line to get */ - lwz r3,saver3(r31) /* Restore */ + la r28,saver8(r31) ; Point to the next line to use + dcbt r21,r29 ; Start moving in a work area + lwz r0,saver0(r31) ; Restore R0 + dcbt 0,r28 ; Touch it in + lwz r1,saver1(r31) ; Restore R1 + lwz r2,saver2(r31) ; Restore R2 + la r28,saver16(r31) ; Point to the next line to get + lwz r3,saver3(r31) ; Restore R3 mtcrf 0x80,r27 ; Get facility availability flags (do not touch CR1-7) - lwz r4,saver4(r31) /* Restore */ - mtsrr0 r25 /* Restore the SRR0 now */ - lwz r5,saver5(r31) /* Restore */ - mtsrr1 r26 /* Restore the SRR1 now */ - lwz r6,saver6(r31) /* Restore */ - - dcbt 0,r28 /* Touch that next line on in */ - la r28,savexfpscrpad(r31) ; Point to the saved fpscr - - lwz r7,saver7(r31) /* Restore */ - dcbt 0,r28 ; Touch saved fpscr - lwz r8,saver8(r31) /* Restore */ - lwz r9,saver9(r31) /* Restore */ - lwz r10,saver10(r31) /* Restore */ - lwz r11,saver11(r31) /* Restore */ - lwz r12,saver12(r31) /* Restore */ - lwz r13,saver13(r31) /* Restore */ - la r28,saver22(r31) /* Point to the next line to do */ - lwz r14,saver14(r31) /* Restore */ - lwz r15,saver15(r31) /* Restore */ - -; -; Note that floating point will be enabled from here on until the RFI -; - - bf- pfFloatb,nofphere ; Skip if no floating point... - mfmsr r27 ; Save the MSR - ori r27,r27,lo16(MASK(MSR_FP)) ; Enable floating point - mtmsr r27 ; Really enable - isync + lwz r4,saver4(r31) ; Restore R4 + mtsrr0 r25 ; Restore the SRR0 now + lwz r5,saver5(r31) ; Restore R5 + mtsrr1 r26 ; Restore the SRR1 now + lwz r6,saver6(r31) ; Restore R6 + + dcbt 0,r28 ; Touch that next line on in + la r28,savevscr(r31) ; Point to the saved facility context + + lwz r7,saver7(r31) ; Restore R7 + lwz r8,saver8(r31) ; Restore R8 + lwz r9,saver9(r31) ; Restore R9 + mfmsr r26 ; Get the current MSR + dcbt 0,r28 ; Touch saved facility context + lwz r10,saver10(r31) ; Restore R10 + lwz r11,saver11(r31) ; Restore R11 + oris r26,r26,hi16(MASK(MSR_VEC)) ; Get the vector enable bit + lwz r12,saver12(r31) ; Restore R12 + ori r26,r26,lo16(MASK(MSR_FP)) ; Add in the float enable + lwz r13,saver13(r31) ; Restore R13 + la r28,saver24(r31) ; Point to the next line to do + +; +; Note that floating point and vector will be enabled from here on until the RFI +; + + mtmsr r26 ; Turn on vectors and floating point + isync + + dcbt 0,r28 ; Touch next line to do + + lwz r14,saver14(r31) ; Restore R14 + lwz r15,saver15(r31) ; Restore R15 + + bf pfAltivecb,noavec3 ; No Altivec on this CPU... + + la r28,savevscr(r31) ; Point to the status area + stvxl v0,r21,r29 ; Save a vector register + lvxl v0,0,r28 ; Get the vector status + lwz r27,savevrsave(r31) ; Get the vrsave + mtvscr v0 ; Set the vector status + + lvxl v0,r21,r29 ; Restore work vector register + beq+ cr3,noavec2 ; SRs have not changed, no need to stop the streams... + dssall ; Kill all data streams + sync + +noavec2: mtspr vrsave,r27 ; Set the vrsave + +noavec3: bf- pfFloatb,nofphere ; Skip if no floating point... + stfd f0,emfp0(r29) ; Save FP0 - lfd f0,savexfpscrpad(r31) ; Get the fpscr + lfd f0,savefpscrpad(r31) ; Get the fpscr mtfsf 0xFF,f0 ; Restore fpscr lfd f0,emfp0(r29) ; Restore the used register -nofphere: dcbt 0,r28 /* Touch in another line of context */ - - lwz r16,saver16(r31) /* Restore */ - lwz r17,saver17(r31) /* Restore */ - lwz r18,saver18(r31) /* Restore */ - lwz r19,saver19(r31) /* Restore */ - lwz r20,saver20(r31) /* Restore */ - lwz r21,saver21(r31) /* Restore */ - la r28,saver30(r31) /* Point to the final line */ - lwz r22,saver22(r31) /* Restore */ - - dcbt 0,r28 /* Suck it in */ - - lwz r23,saver23(r31) /* Restore */ - lwz r24,saver24(r31) /* Restore */ - lwz r25,saver25(r31) /* Restore */ - lwz r26,saver26(r31) /* Restore */ - lwz r27,saver27(r31) /* Restore */ - - lwz r28,savecr(r31) /* Get CR to restore */ - bf pfAltivecb,noavec4 ; No vector on this machine - lwz r29,savevrsave(r31) ; Get the vrsave - beq+ cr3,noavec3 ; SRs have not changed, no need to stop the streams... - dssall ; Kill all data streams - ; The streams should be suspended - ; already, and we do a bunch of - ; dependent loads and a sync later - ; so we should be cool. - -noavec3: mtspr vrsave,r29 ; Set the vrsave - -noavec4: lwz r29,savexer(r31) /* Get XER to restore */ - mtcr r28 /* Restore the CR */ - lwz r28,savelr(r31) /* Get LR to restore */ - mtxer r29 /* Restore the XER */ - lwz r29,savectr(r31) /* Get the CTR to restore */ - mtlr r28 /* Restore the LR */ - lwz r28,saver30(r31) /* Restore */ - mtctr r29 /* Restore the CTR */ - lwz r29,saver31(r31) /* Restore */ - mtsprg 2,r28 /* Save R30 */ - lwz r28,saver28(r31) /* Restore */ - mtsprg 3,r29 /* Save R31 */ - lwz r29,saver29(r31) /* Restore */ - -#if PERFTIMES && DEBUG - stmw r1,0x280(br0) ; Save all registers - mfcr r20 ; Save the CR - mflr r21 ; Save the LR - mfsrr0 r9 ; Save SRR0 - mfsrr1 r11 ; Save SRR1 - mr r8,r0 ; Save R0 - li r3,69 ; Indicate interrupt - mr r4,r11 ; Set MSR to log - mr r5,r31 ; Get savearea to log - bl EXT(dbgLog2) ; Cut log entry - mr r0,r8 ; Restore R0 - mtsrr0 r9 ; Restore SRR0 - mtsrr1 r11 ; Restore SRR1 - mtlr r21 ; Restore the LR - mtcr r20 ; Restore the CR - lmw r1,0x280(br0) ; Restore all the rest -#endif +nofphere: lwz r16,saver16(r31) ; Restore R16 + lwz r17,saver17(r31) ; Restore R17 + lwz r18,saver18(r31) ; Restore R18 + lwz r19,saver19(r31) ; Restore R19 + lwz r20,saver20(r31) ; Restore R20 + lwz r21,saver21(r31) ; Restore R21 + lwz r22,saver22(r31) ; Restore R22 + + lwz r23,saver23(r31) ; Restore R23 + lwz r24,saver24(r31) ; Restore R24 + lwz r25,saver25(r31) ; Restore R25 + lwz r26,saver26(r31) ; Restore R26 + lwz r27,saver27(r31) ; Restore R27 + + lwz r28,savecr(r31) ; Get CR to restore + + lwz r29,savexer(r31) ; Get XER to restore + mtcr r28 ; Restore the CR + lwz r28,savelr(r31) ; Get LR to restore + mtxer r29 ; Restore the XER + lwz r29,savectr(r31) ; Get the CTR to restore + mtlr r28 ; Restore the LR + lwz r28,saver30(r31) ; Get R30 + mtctr r29 ; Restore the CTR + lwz r29,saver31(r31) ; Get R31 + mtsprg 2,r28 ; Save R30 for later + lwz r28,saver28(r31) ; Restore R28 + mtsprg 3,r29 ; Save R31 for later + lwz r29,saver29(r31) ; Restore R29 - li r31,0 /* Get set to clear lock */ - sync /* Make sure it's all out there */ - stw r31,SVlock(r30) /* Unlock it */ - mfsprg r30,2 /* Restore R30 */ mfsprg r31,0 ; Get per_proc + mfsprg r30,2 ; Restore R30 lwz r31,pfAvailable(r31) ; Get the feature flags mtsprg 2,r31 ; Set the feature flags - mfsprg r31,3 /* Restore R31 */ + mfsprg r31,3 ; Restore R31 - rfi /* Click heels three times and think very hard that there's no place like home */ + rfi ; Click heels three times and think very hard that there is no place like home... - .long 0 /* For old 601 bug */ + .long 0 ; Leave this here .long 0 .long 0 .long 0 @@ -2427,10 +1953,13 @@ noavec4: lwz r29,savexer(r31) /* Get XER to restore */ LEXT(exception_exit) mfsprg r29,2 ; Get feature flags - mfmsr r30 /* Get the current MSR */ + mfmsr r30 ; Get the current MSR mtcrf 0x04,r29 ; Set the features - mr r31,r3 /* Get the savearea in the right register */ - andi. r30,r30,0x7FCF /* Turn off externals, IR, and DR */ + rlwinm r30,r30,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + mr r31,r3 ; Get the savearea in the right register + rlwinm r30,r30,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off + li r10,savesrr0 ; Point to one of the first things we touch in the savearea on exit + andi. r30,r30,0x7FCF ; Turn off externals, IR, and DR lis r1,hi16(SAVredrive) ; Get redrive request bt pfNoMSRirb,eeNoMSR ; No MSR... @@ -2443,7 +1972,7 @@ eeNoMSR: li r0,loadMSR ; Get the MSR setter SC mr r3,r30 ; Get new MSR sc ; Set it -eeNoMSRx: +eeNoMSRx: dcbt r10,r31 ; Touch in the first stuff we restore mfsprg r2,0 ; Get the per_proc block lwz r4,SAVflags(r31) ; Pick up the flags mr r13,r31 ; Put savearea here also @@ -2455,45 +1984,10 @@ eeNoMSRx: beq+ EatRupt ; No redrive, just exit... - lwz r3,saveexception(r13) ; Restore exception code + lwz r11,saveexception(r13) ; Restore exception code stw r4,SAVflags(r13) ; Set the flags b Redrive ; Redrive the exception... -; -; Make trace entry for lowmem_vectors internal debug -; -#if TRCSAVE -cte: - lwz r20,LOW_ADDR(EXT(traceCurr)-EXT(ExceptionVectorsStart))(br0) ; Pick up the current trace entry - lwz r16,LOW_ADDR(EXT(traceEnd)-EXT(ExceptionVectorsStart))(br0) ; Grab up the end of it all - addi r17,r20,LTR_size ; Point to the next trace entry - cmplw r17,r16 ; Do we need to wrap the trace table? - li r15,32 ; Second line of entry - bne+ ctenwrap ; We got a trace entry... - lwz r17,LOW_ADDR(EXT(traceStart)-EXT(ExceptionVectorsStart))(br0) ; Wrap back to the top - -ctenwrap: stw r17,LOW_ADDR(EXT(traceCurr)-EXT(ExceptionVectorsStart))(br0) ; Set the next entry for the next guy - - bf- featL1ena,skipz8 ; L1 cache is disabled... - dcbz 0,r20 ; Allocate cache for the entry - dcbz r15,r20 ; Zap the second half -skipz8: - -ctegetTB: mftbu r16 ; Get the upper timebase - mftb r17 ; Get the lower timebase - mftbu r15 ; Get the upper one again - cmplw r16,r15 ; Did the top tick? - bne- ctegetTB ; Yeah, need to get it again... - - li r15,0x111 ; Get the special trace ID code - stw r0,LTR_r0(r20) ; Save R0 (usually used as an ID number - stw r16,LTR_timeHi(r20) ; Set the upper part of TB - mflr r16 ; Get the return point - stw r17,LTR_timeLo(r20) ; Set the lower part of TB - sth r15,LTR_excpt(r20) ; Save the exception type - stw r16,LTR_srr0(r20) ; Save the return point - blr ; Leave... -#endif /* * Start of the trace table diff --git a/osfmk/ppc/machine_routines.c b/osfmk/ppc/machine_routines.c index 7ad338922..0a1080cef 100644 --- a/osfmk/ppc/machine_routines.c +++ b/osfmk/ppc/machine_routines.c @@ -121,6 +121,8 @@ void ml_install_interrupt_handler( per_proc_info[current_cpu].interrupts_enabled = TRUE; (void) ml_set_interrupts_enabled(current_state); + + initialize_screen(0, kPEAcquireScreen); } /* Initialize Interrupts */ @@ -192,14 +194,26 @@ void ml_cause_interrupt(void) CreateFakeIO(); } -void ml_thread_policy( +void ml_thread_policy( thread_t thread, unsigned policy_id, unsigned policy_info) { if ((policy_id == MACHINE_GROUP) && - ((per_proc_info[0].pf.Available) & pfSMPcap)) - thread_bind(thread, master_processor); + ((per_proc_info[0].pf.Available) & pfSMPcap)) + thread_bind(thread, master_processor); + + if (policy_info & MACHINE_NETWORK_WORKLOOP) { + spl_t s = splsched(); + + thread_lock(thread); + + thread->sched_mode |= TH_MODE_FORCEDPREEMPT; + set_priority(thread, thread->priority + 1); + + thread_unlock(thread); + splx(s); + } } void machine_idle(void) @@ -361,10 +375,11 @@ init_ast_check(processor_t processor) {} void -cause_ast_check(processor_t processor) +cause_ast_check( + processor_t processor) { - if ((processor != current_processor()) - && (per_proc_info[processor->slot_num].interrupts_enabled == TRUE)) + if ( processor != current_processor() && + per_proc_info[processor->slot_num].interrupts_enabled == TRUE ) cpu_signal(processor->slot_num, SIGPast, NULL, NULL); } @@ -374,9 +389,7 @@ switch_to_shutdown_context( void (*doshutdown)(processor_t), processor_t processor) { - disable_preemption(); CreateShutdownCTX(); - enable_preemption(); return((thread_t)(per_proc_info[cpu_number()].old_thread)); } diff --git a/osfmk/ppc/machine_routines.h b/osfmk/ppc/machine_routines.h index 7bb0b2176..dc0cef117 100644 --- a/osfmk/ppc/machine_routines.h +++ b/osfmk/ppc/machine_routines.h @@ -31,32 +31,42 @@ #include #include +#include -#if defined(PEXPERT_KERNEL_PRIVATE) || defined(MACH_KERNEL_PRIVATE) -/* IO memory map services */ +/* Get Interrupts Enabled */ +boolean_t ml_get_interrupts_enabled(void); -/* Map memory map IO space */ -vm_offset_t ml_io_map( - vm_offset_t phys_addr, - vm_size_t size); +/* Set Interrupts Enabled */ +boolean_t ml_set_interrupts_enabled(boolean_t enable); -/* boot memory allocation */ -vm_offset_t ml_static_malloc( - vm_size_t size); -#endif +/* Check if running at interrupt context */ +boolean_t ml_at_interrupt_context(void); -vm_offset_t -ml_static_ptovirt( - vm_offset_t); +/* Generate a fake interrupt */ +void ml_cause_interrupt(void); + +/* Type for the IPI Hander */ +typedef void (*ipi_handler_t)(void); + +/* Type for the Time Base Enable function */ +typedef void (*time_base_enable_t)(cpu_id_t cpu_id, boolean_t enable); + +/* enables (or disables) the processor nap mode the function returns the previous value*/ +boolean_t ml_enable_nap( + int target_cpu, + boolean_t nap_enabled); + +/* Put the processor to sleep */ +void ml_ppc_sleep(void); +void ml_get_timebase(unsigned long long *timstamp); +void ml_sense__nmi(void); + +int ml_enable_cache_level(int cache_level, int enable); void ml_static_mfree( vm_offset_t, vm_size_t); -/* virtual to physical on wired pages */ -vm_offset_t ml_vtophys( - vm_offset_t vaddr); - /* Init Interrupts */ void ml_install_interrupt_handler( void *nub, @@ -65,46 +75,15 @@ void ml_install_interrupt_handler( IOInterruptHandler handler, void *refCon); -#ifdef MACH_KERNEL_PRIVATE -void ml_init_interrupt(void); - -boolean_t fake_get_interrupts_enabled(void); - -boolean_t fake_set_interrupts_enabled( - boolean_t enable); -#endif +#ifdef __APPLE_API_UNSTABLE -/* Get Interrupts Enabled */ -boolean_t ml_get_interrupts_enabled(void); - -/* Set Interrupts Enabled */ -boolean_t ml_set_interrupts_enabled(boolean_t enable); - -/* Check if running at interrupt context */ -boolean_t ml_at_interrupt_context(void); - -/* Generate a fake interrupt */ -void ml_cause_interrupt(void); - -void ml_thread_policy( - thread_t thread, - unsigned policy_id, - unsigned policy_info); - -#define MACHINE_GROUP 0x00000001 -#define MACHINE_NETWORK_GROUP 0x10000000 -#define MACHINE_NETWORK_WORKLOOP 0x00000001 -#define MACHINE_NETWORK_NETISR 0x00000002 - -#ifdef MACH_KERNEL_PRIVATE -/* check pending timers */ -void machine_clock_assist(void); - -void machine_idle(void); +vm_offset_t +ml_static_ptovirt( + vm_offset_t); -void machine_signal_idle( - processor_t processor); -#endif +/* virtual to physical on wired pages */ +vm_offset_t ml_vtophys( + vm_offset_t vaddr); /* PCI config cycle probing */ boolean_t ml_probe_read( @@ -127,12 +106,6 @@ void ml_phys_write_byte( void ml_phys_write( vm_offset_t paddr, unsigned int data); -/* Type for the IPI Hander */ -typedef void (*ipi_handler_t)(void); - -/* Type for the Time Base Enable function */ -typedef void (*time_base_enable_t)(cpu_id_t cpu_id, boolean_t enable); - /* Struct for ml_processor_register */ struct ml_processor_info_t { cpu_id_t cpu_id; @@ -151,32 +124,39 @@ kern_return_t ml_processor_register( processor_t *processor, ipi_handler_t *ipi_handler); -/* enables (or disables) the processor nap mode the function returns the previous value*/ -boolean_t ml_enable_nap( - int target_cpu, - boolean_t nap_enabled); +#endif /* __APPLE_API_UNSTABLE */ -/* Put the processor to sleep */ -void ml_ppc_sleep(void); +#ifdef __APPLE_API_PRIVATE +#if defined(PEXPERT_KERNEL_PRIVATE) || defined(MACH_KERNEL_PRIVATE) +/* IO memory map services */ -/* Struct for ml_ppc_get_cpu_info */ -struct ml_ppc_cpu_info_t { - unsigned long vector_unit; - unsigned long cache_line_size; - unsigned long l1_icache_size; - unsigned long l1_dcache_size; - unsigned long l2_settings; - unsigned long l2_cache_size; - unsigned long l3_settings; - unsigned long l3_cache_size; -}; +/* Map memory map IO space */ +vm_offset_t ml_io_map( + vm_offset_t phys_addr, + vm_size_t size); -typedef struct ml_ppc_cpu_info_t ml_ppc_cpu_info_t; +/* boot memory allocation */ +vm_offset_t ml_static_malloc( + vm_size_t size); -/* Get processor info */ -void ml_ppc_get_info(ml_ppc_cpu_info_t *cpu_info); +#endif /* PEXPERT_KERNEL_PRIVATE || MACH_KERNEL_PRIVATE */ #ifdef MACH_KERNEL_PRIVATE +void ml_init_interrupt(void); + +boolean_t fake_get_interrupts_enabled(void); + +boolean_t fake_set_interrupts_enabled( + boolean_t enable); + +/* check pending timers */ +void machine_clock_assist(void); + +void machine_idle(void); + +void machine_signal_idle( + processor_t processor); + void cacheInit(void); void cacheDisable(void); @@ -190,12 +170,38 @@ void ml_thrm_set( unsigned int ml_throttle( unsigned int); -#endif -void ml_get_timebase(unsigned long long *timstamp); -void ml_sense__nmi(void); +#endif /* MACH_KERNEL_PRIVATE */ + +void ml_thread_policy( + thread_t thread, + unsigned policy_id, + unsigned policy_info); + +#define MACHINE_GROUP 0x00000001 +#define MACHINE_NETWORK_GROUP 0x10000000 +#define MACHINE_NETWORK_WORKLOOP 0x00000001 +#define MACHINE_NETWORK_NETISR 0x00000002 + +/* Struct for ml_ppc_get_cpu_info */ +struct ml_ppc_cpu_info_t { + unsigned long vector_unit; + unsigned long cache_line_size; + unsigned long l1_icache_size; + unsigned long l1_dcache_size; + unsigned long l2_settings; + unsigned long l2_cache_size; + unsigned long l3_settings; + unsigned long l3_cache_size; +}; + +typedef struct ml_ppc_cpu_info_t ml_ppc_cpu_info_t; + +/* Get processor info */ +void ml_ppc_get_info(ml_ppc_cpu_info_t *cpu_info); -int ml_enable_cache_level(int cache_level, int enable); void ml_set_processor_speed(unsigned long speed); +#endif /* __APPLE_API_PRIVATE */ + #endif /* _PPC_MACHINE_ROUTINES_H_ */ diff --git a/osfmk/ppc/machine_routines_asm.s b/osfmk/ppc/machine_routines_asm.s index a03a716d9..436307c24 100644 --- a/osfmk/ppc/machine_routines_asm.s +++ b/osfmk/ppc/machine_routines_asm.s @@ -45,6 +45,8 @@ LEXT(ml_probe_read) mfsprg r9,2 ; Get feature flags mfmsr r0 ; Save the current MSR + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off neg r10,r3 ; Number of bytes to end of page rlwinm r2,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear interruptions rlwinm. r10,r10,0,20,31 ; Clear excess junk and test for page bndry @@ -75,6 +77,15 @@ mprNoMSRx: mfspr r6, hid0 ; Get a copy of hid0 + rlwinm. r5, r9, 0, pfNoMuMMCKb, pfNoMuMMCKb ; Check for NoMuMMCK + bne mprNoMuM + + rlwinm r5, r6, 0, ice+1, ice-1 ; Turn off L1 I-Cache + mtspr hid0, r5 + isync ; Wait for I-Cache off + rlwinm r5, r6, 0, mum+1, mum-1 ; Turn off MuM w/ I-Cache on + mtspr hid0, r5 +mprNoMuM: ; ; We need to insure that there is no more than 1 BAT register that @@ -164,7 +175,9 @@ LEXT(ml_probe_read_mck) LEXT(ml_phys_read_byte) mfmsr r10 ; Save the current MSR - rlwinm r4,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear interruptions + rlwinm r10,r10,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r10,r10,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off + rlwinm r4,r10,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear interruptions rlwinm r4,r4,0,MSR_DR_BIT+1,MSR_DR_BIT-1 ; Clear translation mtmsr r4 ; Translation and all off @@ -191,6 +204,8 @@ LEXT(ml_phys_read_byte) LEXT(ml_phys_read) mfmsr r0 ; Save the current MSR + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r4,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear interruptions rlwinm r4,r4,0,MSR_DR_BIT+1,MSR_DR_BIT-1 ; Clear translation @@ -218,6 +233,8 @@ LEXT(ml_phys_read) LEXT(ml_phys_write_byte) mfmsr r0 ; Save the current MSR + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r5,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear interruptions rlwinm r5,r5,0,MSR_DR_BIT+1,MSR_DR_BIT-1 ; Clear translation @@ -245,6 +262,8 @@ LEXT(ml_phys_write_byte) LEXT(ml_phys_write) mfmsr r0 ; Save the current MSR + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r5,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear interruptions rlwinm r5,r5,0,MSR_DR_BIT+1,MSR_DR_BIT-1 ; Clear translation @@ -277,7 +296,9 @@ LEXT(ml_set_interrupts_enabled) mr. r4,r4 beq- EXT(fake_set_interrupts_enabled) mfmsr r5 ; Get the current MSR + rlwinm r5,r5,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off mr r4,r3 ; Save the old value + rlwinm r5,r5,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r3,r5,17,31,31 ; Set return value rlwimi r5,r4,15,16,16 ; Insert new EE bit andi. r8,r5,lo16(MASK(MSR_EE)) ; Interruptions @@ -288,18 +309,17 @@ NoPreemption: CheckPreemption: lwz r8,PP_NEED_AST(r7) - lwz r7,PP_CPU_DATA(r7) li r6,AST_URGENT lwz r8,0(r8) - lwz r7,CPU_PREEMPTION_LEVEL(r7) + lwz r7,PP_PREEMPT_CNT(r7) lis r0,HIGH_ADDR(DoPreemptCall) and. r8,r8,r6 ori r0,r0,LOW_ADDR(DoPreemptCall) - beq+ NoPreemption + beq+ NoPreemption cmpi cr0, r7, 0 - bne+ NoPreemption - sc - mtmsr r5 + mtmsr r5 ; Restore the MSR now, before we can preempt + bnelr+ ; Return if no premption + sc ; Preempt blr @@ -339,8 +359,11 @@ LEXT(machine_clock_assist) LEXT(machine_idle_ppc) mfmsr r3 ; Get the current MSR + rlwinm r3,r3,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r3,r3,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r5,r3,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Turn off interruptions mtmsr r5 ; Hold up interruptions for now + isync ; May have messed with fp/vec mfsprg r12,0 ; Get the per_proc_info mfspr r6,hid0 ; Get the current power-saving mode mfsprg r11,2 ; Get CPU specific features @@ -365,6 +388,24 @@ yesnap: mftbu r9 ; Get the upper timebase stw r8,napStamp(r12) ; Set high order time stamp stw r7,napStamp+4(r12) ; Set low order nap stamp + rlwinm. r7,r11,0,pfNoL2PFNapb,pfNoL2PFNapb ; Turn off L2 Prefetch before nap? + beq miL2PFok + + mfspr r7,msscr0 ; Get currect MSSCR0 value + rlwinm r7,r7,0,0,l2pfes-1 ; Dissable L2 Prefetch + mtspr msscr0,r7 ; Updates MSSCR0 value + sync + isync + +miL2PFok: + rlwinm. r7,r11,0,pfSlowNapb,pfSlowNapb ; Should nap at slow speed? + beq minoslownap + + mfspr r7,hid1 ; Get current HID1 value + oris r7,r7,hi16(hid1psm) ; Select PLL1 + mtspr hid1,r7 ; Update HID1 value + +minoslownap: ; ; We have to open up interruptions here because book 4 says that we should @@ -428,22 +469,26 @@ LEXT(ml_ppc_sleep) mtmsr r5 ; No talking isync -; No interrupts allowed after we get the savearea - - mfsprg r6,0 ; Get the per_proc - mfsprg r7,1 ; Get the pending savearea - stw r7,savedSave(r6) ; Save the savearea for when we wake up - deadsleep: addi r3,r3,1 ; Make analyzer happy addi r3,r3,1 addi r3,r3,1 b deadsleep ; Die the death of 1000 joys... #endif - mfsprg r12,0 ; Get the per_proc_info mfspr r4,hid0 ; Get the current power-saving mode eqv r10,r10,r10 ; Get all foxes mfsprg r11,2 ; Get CPU specific features + + rlwinm. r5,r11,0,pfNoL2PFNapb,pfNoL2PFNapb ; Turn off L2 Prefetch before sleep? + beq mpsL2PFok + + mfspr r5,msscr0 ; Get currect MSSCR0 value + rlwinm r5,r5,0,0,l2pfes-1 ; Dissable L2 Prefetch + mtspr msscr0,r5 ; Updates MSSCR0 value + sync + isync + +mpsL2PFok: mfmsr r5 ; Get the current MSR rlwinm r10,r10,0,1,31 ; Make 0x7FFFFFFF rlwinm r4,r4,0,sleep+1,doze-1 ; Clear all possible power-saving modes (not DPM though) @@ -484,9 +529,6 @@ mpsNoMSRx: mtmsr r5 ; Interruptions back off isync ; Toss prefetch - mfsprg r7,1 ; Get the pending savearea - stw r7,savedSave(r12) ; Save the savearea for when we wake up - ; ; We are here with translation off, interrupts off, all possible ; interruptions drained off, and a decrimenter that will not pop. @@ -532,6 +574,8 @@ LEXT(cacheInit) mfsprg r11,2 ; Get CPU specific features mfmsr r7 ; Get the current MSR rlwinm r4,r9,0,dpm+1,doze-1 ; Clear all possible power-saving modes (also disable DPM) + rlwinm r7,r7,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r7,r7,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwimi r11,r11,pfLClckb+1,31,31 ; Move pfLClck to another position (to keep from using non-volatile CRs) rlwinm r5,r7,0,MSR_DR_BIT+1,MSR_IR_BIT-1 ; Turn off translation rlwinm r5,r5,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Turn off interruptions @@ -1073,8 +1117,11 @@ smallenuf: rlwinm r3,r3,31-thrmsitve,thrmsitvs,thrmsitve ; Position LEXT(ml_thrm_set) mfmsr r0 ; Get the MSR + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r6,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear EE bit mtmsr r6 + isync mfsprg r12,0 ; Get the per_proc blok @@ -1113,8 +1160,10 @@ tsetcant: mtmsr r0 ; Reenable interruptions LEXT(ml_read_temp) mfmsr r9 ; Save the MSR - rlwinm r8,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Turn off interruptions li r5,15 ; Starting point for ranging (start at 15 so we do not overflow) + rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off + rlwinm r8,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Turn off interruptions mfsprg r7,2 ; Get CPU specific features mtmsr r8 ; Do not allow interruptions mtcrf 0x40,r7 ; See if we can thermal this machine @@ -1176,9 +1225,12 @@ thrmcant: eqv r3,r3,r3 ; Return bogus temprature because we can not read i LEXT(ml_throttle) mfmsr r9 ; Save the MSR + rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r8,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Turn off interruptions cmplwi r3,lo16(ictcfim>>1) ; See if we are going too far - mtmsr r8 ; Do not allow interruptions + mtmsr r8 ; Do not allow interruptions + isync ble+ throtok ; Throttle value is ok... li r3,lo16(ictcfim>>1) ; Set max @@ -1218,6 +1270,26 @@ loop: blr +/* + * The routine that implements cpu_number. + */ + + .align 5 + .globl EXT(cpu_number) + +LEXT(cpu_number) + + mfmsr r9 /* Save the old MSR */ + rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off + rlwinm r8,r9,0,17,15 /* Clear interruptions */ + mtmsr r8 /* Interrupts off */ + isync + mfsprg r7,0 /* Get per-proc block */ + lhz r3,PP_CPU_NUMBER(r7) /* Get CPU number */ + mtmsr r9 /* Restore interruptions to entry */ + blr /* Return... */ + /* ** ml_sense_nmi() ** @@ -1239,4 +1311,30 @@ LEXT(ml_sense_nmi) .globl EXT(ml_set_processor_speed) LEXT(ml_set_processor_speed) + mfsprg r5, 0 ; Get the per_proc_info + + cmpli cr0, r3, 0 ; Turn off BTIC before low speed + beq sps1 + mfspr r4, hid0 ; Get the current hid0 value + rlwinm r4, r4, 0, btic+1, btic-1 ; Clear the BTIC bit + sync + mtspr hid0, r4 ; Set the new hid0 value + isync + sync + +sps1: + mfspr r4, hid1 ; Get the current PLL settings + rlwimi r4, r3, 31-hid1ps, hid1ps, hid1ps ; Copy the PLL Select bit + stw r4, pfHID1(r5) ; Save the new hid1 value + mtspr hid1, r4 ; Select desired PLL + + cmpli cr0, r3, 0 ; Restore BTIC after high speed + bne sps2 + lwz r4, pfHID0(r5) ; Load the hid0 value + sync + mtspr hid0, r4 ; Set the hid0 value + isync + sync + +sps2: blr diff --git a/osfmk/ppc/machine_rpc.h b/osfmk/ppc/machine_rpc.h index dfda35fc5..087c562d5 100644 --- a/osfmk/ppc/machine_rpc.h +++ b/osfmk/ppc/machine_rpc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002,2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -27,19 +27,6 @@ #ifndef _MACHINE_RPC_H_ #define _MACHINE_RPC_H_ -#if ETAP_EVENT_MONITOR -#define ETAP_EXCEPTION_PROBE(_f, _th, _ex, _sysnum) \ - if (_ex == EXC_SYSCALL) { \ - ETAP_PROBE_DATA(ETAP_P_SYSCALL_UNIX, \ - _f, \ - _th, \ - _sysnum, \ - sizeof(int)); \ - } -#else /* ETAP_EVENT_MONITOR */ -#define ETAP_EXCEPTION_PROBE(_f, _th, _ex, _sysnum) -#endif /* ETAP_EVENT_MONITOR */ - #endif /* _MACHINE_RPC_H_ */ diff --git a/osfmk/ppc/mappings.c b/osfmk/ppc/mappings.c index d59d912d9..de3411de9 100644 --- a/osfmk/ppc/mappings.c +++ b/osfmk/ppc/mappings.c @@ -199,14 +199,16 @@ boolean_t mapping_remove(pmap_t pmap, vm_offset_t va) { /* Remove a single map mp = hw_lock_phys_vir(pmap->space, va); /* Lock the physical entry for this mapping */ if(!mp) { /* Did we find one? */ + splx(s); /* Allow 'rupts now */ if(mp = (mapping *)hw_rem_blk(pmap, va, va)) { /* No normal pages, try to remove an odd-sized one */ - splx(s); /* Allow 'rupts now */ if((unsigned int)mp & 1) { /* Make sure we don't unmap a permanent one */ - blm = (blokmap *)hw_cpv((mapping *)((unsigned int)mp & 0xFFFFFFFE)); /* Get virtual address */ + blm = (blokmap *)hw_cpv((mapping *)((unsigned int)mp & 0xFFFFFFFC)); /* Get virtual address */ panic("mapping_remove: attempt to unmap a permanent mapping - pmap = %08X, va = %08X, mapping = %08X\n", pmap, va, blm); } + while ((unsigned int)mp & 2) + mp = (mapping *)hw_rem_blk(pmap, va, va); #if 0 blm = (blokmap *)hw_cpv(mp); /* (TEST/DEBUG) */ kprintf("mapping_remove: removed block map - bm=%08X; start=%08X; end=%08X; PTEr=%08X\n", /* (TEST/DEBUG) */ @@ -216,7 +218,6 @@ boolean_t mapping_remove(pmap_t pmap, vm_offset_t va) { /* Remove a single map debugLog2(2, 1, 0); /* End mapping_remove */ return TRUE; /* Tell them we did it */ } - splx(s); /* Restore the interrupt level */ debugLog2(2, 0, 0); /* end mapping_remove */ return FALSE; /* Didn't find any, return FALSE... */ } @@ -290,7 +291,7 @@ void mapping_purge_pmap(struct phys_entry *pp, pmap_t pmap) { /* Remove all map mpv = hw_cpv(mp); /* Get the virtual address */ if(mpv->pmap != pmap) { - mp = ((unsigned int)mpv->next & ~PHYS_FLAGS); + mp = (mapping *)((unsigned int)mpv->next & ~PHYS_FLAGS); continue; } #if DEBUG @@ -566,7 +567,7 @@ void mapping_block_map_opt(pmap_t pmap, vm_offset_t va, vm_offset_t pa, vm_offse void pmap_map_block(pmap_t pmap, vm_offset_t va, vm_offset_t pa, vm_size_t size, vm_prot_t prot, int attr, unsigned int flags) { /* Map an autogenned block */ - register blokmap *blm, *oblm; + register blokmap *blm, *oblm, *oblm_virt;; unsigned int pg; #if 0 @@ -589,6 +590,7 @@ void pmap_map_block(pmap_t pmap, vm_offset_t va, vm_offset_t pa, vm_size_t size, blm->start = (unsigned int)va & -PAGE_SIZE; /* Get virtual block start */ blm->end = (blm->start + size - 1) | (PAGE_SIZE - 1); /* Get virtual block end */ + blm->current = 0; blm->PTEr = ((unsigned int)pa & -PAGE_SIZE) | attr<<3 | ppc_prot(prot); /* Build the real portion of the base PTE */ blm->space = pmap->space; /* Set the space (only needed for remove) */ blm->blkFlags = flags; /* Set the block's flags */ @@ -605,8 +607,22 @@ void pmap_map_block(pmap_t pmap, vm_offset_t va, vm_offset_t pa, vm_size_t size, blm, pmap->bmaps); #endif - if(oblm = hw_add_blk(pmap, blm)) { /* Add to list and make sure we don't overlap anything */ - panic("pmap_map_block: block map overlap - blm = %08X\n", oblm); /* Squeak loudly and carry a big stick */ + do { + oblm = hw_add_blk(pmap, blm); + if ((unsigned int)oblm & 2) { + oblm_virt = (blokmap *)hw_cpv((mapping *)((unsigned int)oblm & 0xFFFFFFFC)); + mapping_remove(pmap, oblm_virt->start); + }; + } while ((unsigned int)oblm & 2); + + if (oblm) { + oblm = (blokmap *)hw_cpv((mapping *) oblm); /* Get the old block virtual address */ + blm = (blokmap *)hw_cpv((mapping *)blm); /* Back to the virtual address of this */ + if((oblm->start != blm->start) || /* If we have a match, then this is a fault race and */ + (oblm->end != blm->end) || /* is acceptable */ + (oblm->PTEr != blm->PTEr)) + panic("pmap_map_block: block map overlap - blm = %08X\n", oblm);/* Otherwise, Squeak loudly and carry a big stick */ + mapping_free((struct mapping *)blm); } #if 0 @@ -1057,7 +1073,9 @@ void mapping_adjust(void) { /* Adjust free mappings */ } if (mapping_adjust_call == NULL) { - thread_call_setup(&mapping_adjust_call_data, mapping_adjust, NULL); + thread_call_setup(&mapping_adjust_call_data, + (thread_call_func_t)mapping_adjust, + (thread_call_param_t)NULL); mapping_adjust_call = &mapping_adjust_call_data; } @@ -1074,25 +1092,25 @@ void mapping_adjust(void) { /* Adjust free mappings */ else { /* No free ones, try to get it */ allocsize = (allocsize + MAPPERBLOK - 1) / MAPPERBLOK; /* Get the number of pages we need */ - if(allocsize > (mapCtl.mapcfree / 2)) allocsize = (mapCtl.mapcfree / 2); /* Don't try for anything that we can't comfortably map */ - + hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */ splx(s); /* Restore 'rupts */ for(; allocsize > 0; allocsize >>= 1) { /* Try allocating in descending halves */ retr = kmem_alloc_wired(mapping_map, (vm_offset_t *)&mbn, PAGE_SIZE * allocsize); /* Find a virtual address to use */ if((retr != KERN_SUCCESS) && (allocsize == 1)) { /* Did we find any memory at all? */ - panic("Whoops... Not a bit of wired memory left for anyone\n"); + break; } if(retr == KERN_SUCCESS) break; /* We got some memory, bail out... */ } - allocsize = allocsize * MAPPERBLOK; /* Convert pages to number of maps allocated */ s = splhigh(); /* Don't bother from now on */ if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) { /* Lock the control header */ panic("mapping_adjust - timeout getting control lock (2)\n"); /* Tell all and die */ } } + if (retr != KERN_SUCCESS) + break; /* Fail to alocate, bail out... */ for(; allocsize > 0; allocsize -= MAPPERBLOK) { /* Release one block at a time */ mapping_free_init((vm_offset_t)mbn, 0, 1); /* Initialize a non-permanent block */ mbn = (mappingblok *)((unsigned int)mbn + PAGE_SIZE); /* Point to the next slot */ @@ -1156,6 +1174,8 @@ void mapping_free(struct mapping *mp) { /* Release a mapping */ if(full) { /* If it was full before this: */ mb->nextblok = mapCtl.mapcnext; /* Move head of list to us */ mapCtl.mapcnext = mb; /* Chain us to the head of the list */ + if(!((unsigned int)mapCtl.mapclast)) + mapCtl.mapclast = mb; } mapCtl.mapcfree++; /* Bump free count */ @@ -1232,7 +1252,40 @@ mapping *mapping_alloc(void) { /* Obtain a mapping */ } if(!(mb = mapCtl.mapcnext)) { /* Get the first block entry */ - panic("mapping_alloc - free mappings exhausted\n"); /* Whine and moan */ + unsigned int i; + struct mappingflush mappingflush; + PCA *pca_min, *pca_max; + PCA *pca_base; + + pca_min = (PCA *)(hash_table_base+hash_table_size); + pca_max = (PCA *)(hash_table_base+hash_table_size+hash_table_size); + + while (mapCtl.mapcfree <= (MAPPERBLOK*2)) { + mapCtl.mapcflush.mappingcnt = 0; + pca_base = mapCtl.mapcflush.pcaptr; + do { + hw_select_mappings(&mapCtl.mapcflush); + mapCtl.mapcflush.pcaptr++; + if (mapCtl.mapcflush.pcaptr >= pca_max) + mapCtl.mapcflush.pcaptr = pca_min; + } while ((mapCtl.mapcflush.mappingcnt == 0) && (mapCtl.mapcflush.pcaptr != pca_base)); + + if ((mapCtl.mapcflush.mappingcnt == 0) && (mapCtl.mapcflush.pcaptr == pca_base)) { + hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); + panic("mapping_alloc - all mappings are wired\n"); + } + mappingflush = mapCtl.mapcflush; + hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); + splx(s); + for (i=0;ivflags & pmapAltSeg) return 0; /* If there are nested pmaps, fail immediately */ + s = splhigh(); if(!hw_lock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK, LockTimeOut)) { /* Try to get the lock on the physical entry */ splx(s); /* Restore 'rupts */ panic("mapping_p2v: timeout getting lock on physent\n"); /* Arrrgghhhh! */ @@ -1782,7 +1836,7 @@ kern_return_t copyp2v(vm_offset_t source, vm_offset_t sink, unsigned int size) { mp = hw_lock_phys_vir(spaceid, sink); /* Lock the physical entry for the sink */ if(!mp) { /* Was it there? */ splx(s); /* Restore the interrupt level */ - ret = vm_fault(map, trunc_page(sink), VM_PROT_READ | VM_PROT_WRITE, FALSE); /* Didn't find it, try to fault it in... */ + ret = vm_fault(map, trunc_page(sink), VM_PROT_READ | VM_PROT_WRITE, FALSE, NULL, 0); /* Didn't find it, try to fault it in... */ if (ret == KERN_SUCCESS) continue; /* We got it in, try again to find it... */ return KERN_FAILURE; /* Didn't find any, return no good... */ @@ -1798,7 +1852,7 @@ kern_return_t copyp2v(vm_offset_t source, vm_offset_t sink, unsigned int size) { if(mpv->PTEr & 1) { /* Are we write protected? yes, could indicate COW */ hw_unlock_bit((unsigned int *)&mpv->physent->phys_link, PHYS_LOCK); /* Unlock the sink */ splx(s); /* Restore the interrupt level */ - ret = vm_fault(map, trunc_page(sink), VM_PROT_READ | VM_PROT_WRITE, FALSE); /* check for a COW area */ + ret = vm_fault(map, trunc_page(sink), VM_PROT_READ | VM_PROT_WRITE, FALSE, NULL, 0); /* check for a COW area */ if (ret == KERN_SUCCESS) continue; /* We got it in, try again to find it... */ return KERN_FAILURE; /* Didn't find any, return no good... */ } @@ -1808,7 +1862,7 @@ kern_return_t copyp2v(vm_offset_t source, vm_offset_t sink, unsigned int size) { pa = (vm_offset_t)((mpv->physent->pte1 & ~PAGE_MASK) | ((unsigned int)sink & PAGE_MASK)); /* Get physical address of sink */ - bcopy_phys((char *)source, (char *)pa, csize); /* Do a physical copy */ + bcopy_physvir((char *)source, (char *)pa, csize); /* Do a physical copy, virtually */ hw_set_mod(mpv->physent); /* Go set the change of the sink */ diff --git a/osfmk/ppc/mappings.h b/osfmk/ppc/mappings.h index 6b780c344..8c278ab08 100644 --- a/osfmk/ppc/mappings.h +++ b/osfmk/ppc/mappings.h @@ -80,13 +80,16 @@ typedef struct blokmap { unsigned int PTEr; /* Real half of HW PTE at base address */ unsigned int space; /* Cached VSID */ unsigned int blkFlags; /* Flags for this block */ -#define blkPerm 0x80000000 -#define blkPermbit 0 - unsigned int gas3; /* Reserved */ +#define blkPerm 0x80000000 +#define blkRem 0x40000000 +#define blkPermbit 0 +#define blkRembit 1 + unsigned int current; /* Partial block remove current start */ unsigned int gas4; /* Reserved */ } blokmap; #define ODDBLKMIN (8 * PAGE_SIZE) +#define BLKREMMAX 128 #define MAPPING_NULL ((struct mapping *) 0) @@ -97,6 +100,17 @@ typedef struct blokmap { #define mapRORO 0x00000003 +typedef struct mfmapping { + struct pmap *pmap; + vm_offset_t offset; +} mfmapping; + +typedef struct mappingflush { + PCA *pcaptr; + unsigned int mappingcnt; + struct mfmapping mapping[8]; +} mappingflush; + typedef struct mappingctl { unsigned int mapclock; /* Mapping allocation lock */ unsigned int mapcrecurse; /* Mapping allocation recursion control */ @@ -111,7 +125,8 @@ typedef struct mappingctl { unsigned int mapcallocc; /* Total calls to mapping alloc */ unsigned int mapcmin; /* Minimum free mappings to keep */ unsigned int mapcmaxalloc; /* Maximum number of mappings allocated at one time */ - unsigned int mapcgas[3]; /* Pad to 64 bytes */ + struct mappingflush mapcflush; + unsigned int mapcgas[1]; /* Pad to 64 bytes */ } mappingctl; #define MAPPERBLOK 127 @@ -135,6 +150,7 @@ extern void mapping_free_prime(void); /* Primes the mapping block release extern void mapping_prealloc(unsigned int); /* Preallocate mappings for large use */ extern void mapping_relpre(void); /* Releases preallocate request */ extern void mapping_init(void); /* Do initial stuff */ +extern void mapping_flush(void); extern mapping *mapping_alloc(void); /* Obtain a mapping */ extern void mapping_free(struct mapping *mp); /* Release a mapping */ extern boolean_t mapping_tst_ref(struct phys_entry *pp); /* Tests the reference bit of a physical page */ @@ -161,6 +177,7 @@ extern mapping *hw_cpv(struct mapping *mapping); /* Converts a physical mapp extern mapping *hw_cvp(struct mapping *mapping); /* Converts a virtual mapping control block address to physical */ extern void hw_rem_map(struct mapping *mapping); /* Remove a mapping from the system */ extern void hw_add_map(struct mapping *mp, space_t space, vm_offset_t va); /* Add a mapping to the PTEG hash list */ +extern void hw_select_mappings(struct mappingflush *mappingflush); /* Select user mappings in a PTEG */ extern blokmap *hw_rem_blk(pmap_t pmap, vm_offset_t sva, vm_offset_t eva); /* Remove a block that falls within a range */ extern vm_offset_t hw_cvp_blk(pmap_t pmap, vm_offset_t va); /* Convert mapped block virtual to physical */ extern blokmap *hw_add_blk(pmap_t pmap, struct blokmap *bmr); /* Add a block to the pmap */ diff --git a/osfmk/ppc/misc.c b/osfmk/ppc/misc.c index 82d0471f4..5ed36d0e7 100644 --- a/osfmk/ppc/misc.c +++ b/osfmk/ppc/misc.c @@ -110,187 +110,3 @@ int copyout_multiple(const char *src, char *dst, vm_size_t count) return copyout(src + first_count, midpoint, count-first_count); } -#define HAVE_ASSEMBLY_BCMP -#ifndef HAVE_ASSEMBLY_BCMP -int bcmp( - const char *a, - const char *b, - vm_size_t len) -{ - if (len == 0) - return 0; - - do - if (*a++ != *b++) - break; - while (--len); - - return len; -} -#endif /* HAVE_ASSEMBLY_BCMP */ - -#define HAVE_ASSEMBLY_MEMCMP -#ifndef HAVE_ASSEMBLY_MEMCMP -int -memcmp(s1, s2, n) - register char *s1, *s2; - register n; -{ - while (--n >= 0) - if (*s1++ != *s2++) - return (*--s1 - *--s2); - return (0); -} -#endif /* HAVE_ASSEMBLY_MEMCMP */ - -#define HAVE_ASSEMBLY_STRLEN -#ifndef HAVE_ASSEMBLY_STRLEN -/* - * Abstract: - * strlen returns the number of characters in "string" preceeding - * the terminating null character. - */ - -size_t -strlen( - register const char *string) -{ - register const char *ret = string; - - while (*string++ != '\0') - continue; - return string - 1 - ret; -} -#endif /* HAVE_ASSEMBLY_STRLEN */ - -#if DEBUG -void regDump(struct ppc_saved_state *state) -{ - int i; - - for (i=0; i<32; i++) { - if ((i % 8) == 0) - kprintf("\n%4d :",i); - kprintf(" %08x",*(&state->r0+i)); - } - - kprintf("\n"); - kprintf("cr = 0x%08x\t\t",state->cr); - kprintf("xer = 0x%08x\n",state->xer); - kprintf("lr = 0x%08x\t\t",state->lr); - kprintf("ctr = 0x%08x\n",state->ctr); - kprintf("srr0(iar) = 0x%08x\t\t",state->srr0); - kprintf("srr1(msr) = 0x%08B\n",state->srr1, - "\x10\x11""EE\x12PR\x13""FP\x14ME\x15""FE0\x16SE\x18" - "FE1\x19""AL\x1a""EP\x1bIT\x1c""DT"); - kprintf("mq = 0x%08x\t\t",state->mq); - kprintf("sr_copyin = 0x%08x\n",state->sr_copyin); - kprintf("\n"); - - /* Be nice - for user tasks, generate some stack trace */ - if (state->srr1 & MASK(MSR_PR)) { - char *addr = (char*)state->r1; - unsigned int buf[2]; - for (i = 0; i < 8; i++) { - if (addr == (char*)NULL) - break; - if (!copyin(addr,(char*)buf, 2 * sizeof(int))) { - printf("0x%08x : %08x\n",buf[0],buf[1]); - addr = (char*)buf[0]; - } else { - break; - } - } - } -} -#endif /* DEBUG */ - -#if 0 -/* - * invalidate_cache_for_io - * - * Takes cache of those requests which may require to flush the - * data cache first before invalidation. - */ - - -void -invalidate_cache_for_io(vm_offset_t area, unsigned count, boolean_t phys) -{ - vm_offset_t aligned_start, aligned_end, end; - - /* For unaligned reads we need to flush any - * unaligned cache lines. We invalidate the - * rest as this is faster - */ - - aligned_start = area & ~(CACHE_LINE_SIZE-1); - if (aligned_start != area) - flush_dcache(aligned_start, CACHE_LINE_SIZE, phys); - - end = area + count; - aligned_end = (end & ~(CACHE_LINE_SIZE-1)); - if (aligned_end != end) - flush_dcache(aligned_end, CACHE_LINE_SIZE, phys); - - invalidate_dcache(area, count, phys); -} - -extern void tracecopyin(unsigned int src, unsigned int dest, unsigned int lgn, unsigned int from); -void tracecopyin(unsigned int src, unsigned int dest, unsigned int lgn, unsigned int from) { - - spl_t spl; - - spl = splhigh(); - printf("Copy in called from %08X: src=%08X; dest=%08X; lgn=%08X\n", from, src, dest, lgn); - splx(spl); - return; -} - -extern void tracecopyout(unsigned int src, unsigned int dest, unsigned int lgn, unsigned int from); -void tracecopyout(unsigned int src, unsigned int dest, unsigned int lgn, unsigned int from) { - - spl_t spl; - - spl = splhigh(); - printf("Copy out called from %08X: src=%08X; dest=%08X; lgn=%08X\n", from, src, dest, lgn); - splx(spl); - return; -} - -extern void tracecopystr(unsigned int src, unsigned int dest, unsigned int max, - unsigned int lgn, unsigned int from); -void tracecopystr(unsigned int src, unsigned int dest, unsigned int max, - unsigned int lgn, unsigned int from) { - - spl_t spl; - - spl = splhigh(); - printf("Copy in string called from %08X: src=%08X; dest=%08X; max=%08X; lgnadr=%08X\n", - from, src, dest, max, lgn); - splx(spl); - return; -} - -unsigned int ExceptionTrace = 0; -extern void ExceptionTracePrint(struct savearea *sv, int type); -void ExceptionTracePrint(struct savearea *sv, int type) { - - spl_t spl; - - spl = splhigh(); - - if(type) { - printf(" Trap from %08X, type=%08X, R0=%08X, R1=%08X, R3=%08X, LR=%08X, AST=%08X\n", - sv->save_srr0, sv->save_exception, sv->save_r0, sv->save_r1, sv->save_r3, - sv->save_lr, need_ast[0]); - } - else { - printf("Syscall from %08X, type=%08X, R0=%08X, R1=%08X, R3=%08X, LR=%08X, AST=%08X\n", - sv->save_srr0, sv->save_exception, sv->save_r0, sv->save_r1, sv->save_r3, - sv->save_lr, need_ast[0]); - } - splx(spl); - return; -} -#endif diff --git a/osfmk/ppc/misc_asm.s b/osfmk/ppc/misc_asm.s index fecfd70b6..f4668f2ef 100644 --- a/osfmk/ppc/misc_asm.s +++ b/osfmk/ppc/misc_asm.s @@ -48,8 +48,11 @@ ENTRY(getrpc, TAG_NO_FRAME_USED) /* Mask and unmask interrupts at the processor level */ ENTRY(interrupt_disable, TAG_NO_FRAME_USED) mfmsr r0 + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r0, r0, 0, MSR_EE_BIT+1, MSR_EE_BIT-1 mtmsr r0 + isync blr ENTRY(interrupt_enable, TAG_NO_FRAME_USED) @@ -68,8 +71,11 @@ ENTRY(interrupt_enable, TAG_NO_FRAME_USED) /* Mask and unmask interrupts at the processor level */ ENTRY(db_interrupt_disable, TAG_NO_FRAME_USED) mfmsr r0 + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r0, r0, 0, MSR_EE_BIT+1, MSR_EE_BIT-1 mtmsr r0 + isync blr ENTRY(db_interrupt_enable, TAG_NO_FRAME_USED) @@ -87,9 +93,12 @@ ENTRY(db_interrupt_enable, TAG_NO_FRAME_USED) ENTRY(Call_Debugger, TAG_NO_FRAME_USED) mfmsr r7 ; Get the current MSR + rlwinm r7,r7,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r7,r7,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off mflr r0 ; Save the return rlwinm r7,r7,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Turn off interruptions mtmsr r7 ; Do it + isync mfsprg r8,0 ; Get the per_proc block stw r0,FM_LR_SAVE(r1) ; Save return on current stack diff --git a/osfmk/ppc/misc_protos.h b/osfmk/ppc/misc_protos.h index 30b1612e8..2b22949dc 100644 --- a/osfmk/ppc/misc_protos.h +++ b/osfmk/ppc/misc_protos.h @@ -51,14 +51,15 @@ extern void printf(const char *fmt, ...); extern void bcopy_nc(char *from, char *to, int size); /* uncached-safe */ extern void bcopy_phys(char *from, char *to, int size); /* Physical to physical copy (ints must be disabled) */ +extern void bcopy_physvir(char *from, char *to, int size); /* Physical to physical copy virtually (ints must be disabled) */ extern void ppc_init(boot_args *args); -extern struct ppc_saved_state *enterDebugger(unsigned int trap, - struct ppc_saved_state *state, +extern struct savearea *enterDebugger(unsigned int trap, + struct savearea *state, unsigned int dsisr); +extern void draw_panic_dialog(void); extern void ppc_vm_init(unsigned int mem_size, boot_args *args); -extern void regDump(struct ppc_saved_state *state); extern void autoconf(void); extern void machine_init(void); @@ -75,7 +76,6 @@ extern void disable_bluebox_internal(thread_act_t act); extern void db_interrupt_enable(void); extern void db_interrupt_disable(void); #endif /* MACH_KDB */ -extern void amic_init(void); extern void phys_zero(vm_offset_t, vm_size_t); extern void phys_copy(vm_offset_t, vm_offset_t, vm_size_t); @@ -86,6 +86,11 @@ extern struct thread_shuttle *Switch_context(struct thread_shuttle *old, void (*cont)(void), struct thread_shuttle *new); +extern void fpu_save(struct facility_context *); +extern void vec_save(struct facility_context *); +extern void toss_live_fpu(struct facility_context *); +extern void toss_live_vec(struct facility_context *); + extern int nsec_to_processor_clock_ticks(int nsec); extern void tick_delay(int ticks); @@ -95,7 +100,6 @@ extern void tick_delay(int ticks); #endif /* DEBUG */ #if MACH_ASSERT -extern void dump_pcb(pcb_t pcb); extern void dump_thread(thread_t th); #endif diff --git a/osfmk/ppc/model_dep.c b/osfmk/ppc/model_dep.c index 8241a6434..05eb00f1f 100644 --- a/osfmk/ppc/model_dep.c +++ b/osfmk/ppc/model_dep.c @@ -125,8 +125,8 @@ char env_buf[256]; * from on to another using kdb_on! #cpu or cpu #cpu */ -decl_simple_lock_data(, debugger_lock) /* debugger lock */ -decl_simple_lock_data(, pbtlock) /* backtrace print lock */ +hw_lock_data_t debugger_lock; /* debugger lock */ +hw_lock_data_t pbtlock; /* backtrace print lock */ int debugger_cpu = -1; /* current cpu running debugger */ int debugger_debug = 0; /* Debug debugger */ @@ -179,7 +179,10 @@ char *failNames[] = { "Corrupt stack", /* failStack */ "Corrupt mapping tables", /* failMapping */ "Corrupt context", /* failContext */ - "Unknown failure code" /* Unknown failure code - must always be last */ + "No saveareas", /* failNoSavearea */ + "Savearea corruption", /* failSaveareaCorr */ + "Invalid live context", /* failBadLiveContext */ + "Unknown failure code" /* Unknown failure code - must always be last */ }; char *invxcption = "Unknown code"; @@ -189,15 +192,15 @@ extern char *trap_type[]; extern vm_offset_t mem_actual; #if !MACH_KDB -void kdb_trap(int type, struct ppc_saved_state *regs); -void kdb_trap(int type, struct ppc_saved_state *regs) { +void kdb_trap(int type, struct savearea *regs); +void kdb_trap(int type, struct savearea *regs) { return; } #endif #if !MACH_KDP -void kdp_trap(int type, struct ppc_saved_state *regs); -void kdp_trap(int type, struct ppc_saved_state *regs) { +void kdp_trap(int type, struct savearea *regs); +void kdp_trap(int type, struct savearea *regs) { return; } #endif @@ -220,6 +223,8 @@ machine_startup(boot_args *args) if (boot_arg & DB_HALT) halt_in_debugger=1; if (boot_arg & DB_PRT) disableDebugOuput=FALSE; if (boot_arg & DB_SLOG) systemLogDiags=TRUE; + if (boot_arg & DB_NMI) panicDebugging=TRUE; + if (boot_arg & DB_LOG_PI_SCRN) logPanicDataToScreen=TRUE; } hw_lock_init(&debugger_lock); /* initialize debugger lock */ @@ -253,13 +258,6 @@ machine_startup(boot_args *args) default_preemption_rate = boot_arg; } - if (PE_parse_boot_arg("kpreempt", &boot_arg)) { - extern int kernel_preemption_mode; - extern boolean_t zone_gc_allowed; - - kernel_preemption_mode = boot_arg; - zone_gc_allowed = FALSE; /* XXX: TO BE REMOVED */ - } if (PE_parse_boot_arg("unsafe", &boot_arg)) { extern int max_unsafe_quanta; @@ -353,7 +351,7 @@ void machine_callstack( void -print_backtrace(struct ppc_saved_state *ssp) +print_backtrace(struct savearea *ssp) { unsigned int stackptr, *raddr, *rstack, trans, fence; int i, frames_cnt, skip_top_frames, frames_max; @@ -382,47 +380,60 @@ print_backtrace(struct ppc_saved_state *ssp) if(sv) fence = sv->save_r1; /* Stop at previous exception point */ if(!svssp) { /* Should we start from stack? */ - printf("Latest stack backtrace for cpu %d:\n", cpu_number()); + kdb_printf("Latest stack backtrace for cpu %d:\n", cpu_number()); __asm__ volatile("mr %0,r1" : "=r" (stackptr)); /* Get current stack */ dump_backtrace(stackptr, fence); /* Dump the backtrace */ if(!sv) { /* Leave if no saveareas */ - printf("\nKernel version:\n%s\n",version); /* Print kernel version */ + kdb_printf("\nKernel version:\n%s\n",version); /* Print kernel version */ hw_lock_unlock(&pbtlock); /* Allow another back trace to happen */ return; } } else { /* Were we passed an exception? */ fence = 0xFFFFFFFF; /* Show we go all the way */ - if(svssp->save_prev) fence = svssp->save_prev->save_r1; /* Stop at previous exception point */ + if(svssp->save_hdr.save_prev) { + if((svssp->save_hdr.save_prev <= VM_MAX_KERNEL_ADDRESS) && ((unsigned int)LRA(PPC_SID_KERNEL, (void *)svssp->save_hdr.save_prev))) { /* Valid address? */ + fence = svssp->save_hdr.save_prev->save_r1; /* Stop at previous exception point */ + } + } - printf("Latest crash info for cpu %d:\n", cpu_number()); - printf(" Exception state (sv=0x%08x)\n", sv); + kdb_printf("Latest crash info for cpu %d:\n", cpu_number()); + kdb_printf(" Exception state (sv=0x%08X)\n", sv); dump_savearea(svssp, fence); /* Dump this savearea */ } if(!sv) { /* Leave if no saveareas */ - printf("\nKernel version:\n%s\n",version); /* Print kernel version */ + kdb_printf("\nKernel version:\n%s\n",version); /* Print kernel version */ hw_lock_unlock(&pbtlock); /* Allow another back trace to happen */ return; } - printf("Proceeding back via exception chain:\n"); + kdb_printf("Proceeding back via exception chain:\n"); while(sv) { /* Do them all... */ - printf(" Exception state (sv=0x%08x)\n", sv); + if(!((sv <= VM_MAX_KERNEL_ADDRESS) && (unsigned int)LRA(PPC_SID_KERNEL, (void *)sv))) { /* Valid address? */ + kdb_printf(" Exception state (sv=0x%08X) Not mapped or invalid. stopping...\n", sv); + break; + } + + kdb_printf(" Exception state (sv=0x%08X)\n", sv); if(sv == svssp) { /* Did we dump it already? */ - printf(" previously dumped as \"Latest\" state. skipping...\n"); + kdb_printf(" previously dumped as \"Latest\" state. skipping...\n"); } else { fence = 0xFFFFFFFF; /* Show we go all the way */ - if(sv->save_prev) fence = sv->save_prev->save_r1; /* Stop at previous exception point */ + if(sv->save_hdr.save_prev) { + if((sv->save_hdr.save_prev <= VM_MAX_KERNEL_ADDRESS) && ((unsigned int)LRA(PPC_SID_KERNEL, (void *)sv->save_hdr.save_prev))) { /* Valid address? */ + fence = sv->save_hdr.save_prev->save_r1; /* Stop at previous exception point */ + } + } dump_savearea(sv, fence); /* Dump this savearea */ } - sv = sv->save_prev; /* Back chain */ + sv = sv->save_hdr.save_prev; /* Back chain */ } - printf("\nKernel version:\n%s\n",version); /* Print kernel version */ + kdb_printf("\nKernel version:\n%s\n",version); /* Print kernel version */ pbtcpu = -1; /* Mark as unowned */ hw_lock_unlock(&pbtlock); /* Allow another back trace to happen */ @@ -440,7 +451,7 @@ void dump_savearea(savearea *sv, unsigned int fence) { if(sv->save_exception > T_MAX) xcode = invxcption; /* Too big for table */ else xcode = trap_type[sv->save_exception / 4]; /* Point to the type */ - printf(" PC=0x%08X; MSR=0x%08x; DAR=0x%08x; DSISR=0x%08x; LR=0x%08x; R1=0x%08x; XCP=0x%08x (%s)\n", + kdb_printf(" PC=0x%08X; MSR=0x%08X; DAR=0x%08X; DSISR=0x%08X; LR=0x%08X; R1=0x%08X; XCP=0x%08X (%s)\n", sv->save_srr0, sv->save_srr1, sv->save_dar, sv->save_dsisr, sv->save_lr, sv->save_r1, sv->save_exception, xcode); @@ -462,39 +473,39 @@ void dump_backtrace(unsigned int stackptr, unsigned int fence) { unsigned int sframe[8], raddr, dumbo; int i; - printf(" Backtrace:\n"); + kdb_printf(" Backtrace:\n"); for(i = 0; i < DUMPFRAMES; i++) { /* Dump up to max frames */ if(!stackptr || (stackptr == fence)) break; /* Hit stop point or end... */ if(stackptr & 0x0000000f) { /* Is stack pointer valid? */ - printf("\n backtrace terminated - unaligned frame address: 0x%08x\n", stackptr); /* No, tell 'em */ + kdb_printf("\n backtrace terminated - unaligned frame address: 0x%08X\n", stackptr); /* No, tell 'em */ break; } raddr = (unsigned int)LRA(PPC_SID_KERNEL, (void *)stackptr); /* Get physical frame address */ - if(!raddr) { /* Is it mapped? */ - printf("\n backtrace terminated - frame not mapped: 0x%08x\n", stackptr); /* No, tell 'em */ + if(!raddr || (stackptr > VM_MAX_KERNEL_ADDRESS)) { /* Is it mapped? */ + kdb_printf("\n backtrace terminated - frame not mapped or invalid: 0x%08X\n", stackptr); /* No, tell 'em */ break; } - if(raddr >= mem_actual) { /* Is it within physical RAM? */ - printf("\n backtrace terminated - frame outside of RAM: v=0x%08x, p=%08X\n", stackptr, raddr); /* No, tell 'em */ + if(raddr >= mem_actual) { /* Is it within physical RAM? */ + kdb_printf("\n backtrace terminated - frame outside of RAM: v=0x%08X, p=%08X\n", stackptr, raddr); /* No, tell 'em */ break; } - ReadReal(raddr, &sframe[0]); /* Fetch the stack frame */ + ReadReal(raddr, &sframe[0]); /* Fetch the stack frame */ - bframes[i] = sframe[LRindex]; /* Save the link register */ + bframes[i] = sframe[LRindex]; /* Save the link register */ - if(!i) printf(" "); /* Indent first time */ - else if(!(i & 7)) printf("\n "); /* Skip to new line every 8 */ - printf("0x%08x ", bframes[i]); /* Dump the link register */ + if(!i) kdb_printf(" "); /* Indent first time */ + else if(!(i & 7)) kdb_printf("\n "); /* Skip to new line every 8 */ + kdb_printf("0x%08X ", bframes[i]); /* Dump the link register */ - stackptr = sframe[0]; /* Chain back */ + stackptr = sframe[0]; /* Chain back */ } - printf("\n"); - if(i >= DUMPFRAMES) printf(" backtrace continues...\n"); /* Say we terminated early */ + kdb_printf("\n"); + if(i >= DUMPFRAMES) kdb_printf(" backtrace continues...\n"); /* Say we terminated early */ if(i) kmod_dump((vm_offset_t *)&bframes[0], i); /* Show what kmods are in trace */ } @@ -506,6 +517,7 @@ Debugger(const char *message) { int i; unsigned int store[8]; + unsigned long pi_size = 0; spl_t spl; spl = splhigh(); /* No interruptions from here on */ @@ -528,6 +540,49 @@ Debugger(const char *message) { return; /* Yeah, don't do it again... */ } + +/* + * The above stuff catches the double panic case so we shouldn't have to worry about that here. + */ + if ( panicstr != (char *)0 ) + { + /* diable kernel preemptions */ + disable_preemption(); + + /* everything should be printed now so copy to NVRAM + */ + if( debug_buf_size > 0) + pi_size = PESavePanicInfo( debug_buf, debug_buf_ptr - debug_buf); + + if( !panicDebugging && (pi_size != 0) ) { + int my_cpu, debugger_cpu; + int tcpu; + + my_cpu = cpu_number(); + debugger_cpu = my_cpu; + + hw_atomic_add(&debug_mode, 1); + debugger_active[my_cpu]++; + lock_debugger(); + + for(tcpu = 0; tcpu < NCPUS; tcpu++) { + if(tcpu == my_cpu) continue; + hw_atomic_add(&debugger_sync, 1); + (void)cpu_signal(tcpu, SIGPdebug, 0 ,0); + } + (void)hw_cpu_sync(&debugger_sync, LockTimeOut); + debugger_sync = 0; + } + + draw_panic_dialog(); + + if( !panicDebugging && (pi_size != 0)) + PEHaltRestart( kPEHangCPU ); + + enable_preemption(); + } + + if ((current_debugger != NO_CUR_DB)) { /* If there is a debugger configured, enter it */ printf("Debugger(%s)\n", message); TRAP_DEBUGGER; @@ -565,9 +620,9 @@ void SysChoked(int type, savearea *sv) { /* The system is bad dead */ if(failcode > failUnknown) failcode = failUnknown; /* Set unknown code code */ kprintf("System Failure: cpu=%d; code=%08X (%s)\n", cpu_number(), sv->save_r3, failNames[failcode]); - printf("System Failure: cpu=%d; code=%08X (%s)\n", cpu_number(), sv->save_r3, failNames[failcode]); + kdb_printf("System Failure: cpu=%d; code=%08X (%s)\n", cpu_number(), sv->save_r3, failNames[failcode]); - print_backtrace((struct ppc_saved_state *)sv); /* Attempt to print backtrace */ + print_backtrace(sv); /* Attempt to print backtrace */ Call_DebuggerC(type, sv); /* Attempt to get into debugger */ if ((current_debugger != NO_CUR_DB)) Call_DebuggerC(type, sv); /* Attempt to get into debugger */ @@ -583,7 +638,7 @@ void SysChoked(int type, savearea *sv) { /* The system is bad dead */ int Call_DebuggerC( int type, - struct ppc_saved_state *saved_state) + struct savearea *saved_state) { int directcall, wait; vm_offset_t instr_ptr; @@ -615,10 +670,10 @@ int Call_DebuggerC( kprintf("Call_DebuggerC(%d): %08X %08X, debact = %d\n", my_cpu, type, saved_state, debug_mode); /* (TEST/DEBUG) */ #endif printf("Call_Debugger: enter - cpu %d, is_slave %d, debugger_cpu %d, pc %08X\n", - my_cpu, debugger_is_slave[my_cpu], debugger_cpu, saved_state->srr0); + my_cpu, debugger_is_slave[my_cpu], debugger_cpu, saved_state->save_srr0); } - if (instr_ptr = (vm_offset_t)LRA(PPC_SID_KERNEL, (void *)(saved_state->srr0))) { + if (instr_ptr = (vm_offset_t)LRA(PPC_SID_KERNEL, (void *)(saved_state->save_srr0))) { instr = ml_phys_read(instr_ptr); /* Get the trap that caused entry */ } else instr = 0; @@ -654,7 +709,7 @@ int Call_DebuggerC( switch_debugger = 0; /* Make sure switch request is off */ directcall = 1; /* Assume direct call */ - if (saved_state->srr1 & MASK(SRR1_PRG_TRAP)) { /* Trap instruction? */ + if (saved_state->save_srr1 & MASK(SRR1_PRG_TRAP)) { /* Trap instruction? */ directcall = 0; /* We had a trap not a direct call */ @@ -736,7 +791,7 @@ debugger_exit: instr, my_cpu, debugger_cpu, db_run_mode); /* (TEST/DEBUG) */ #endif if ((instr == TRAP_DEBUGGER_INST) || /* Did we trap to enter debugger? */ - (instr == TRAP_DIRECT_INST)) saved_state->srr0 += TRAP_INST_SIZE; /* Yes, point past trap */ + (instr == TRAP_DIRECT_INST)) saved_state->save_srr0 += TRAP_INST_SIZE; /* Yes, point past trap */ if(debugger_cpu == my_cpu) LLTraceSet(lastTrace); /* Enable tracing on the way out if we are debugger */ diff --git a/osfmk/ppc/movc.s b/osfmk/ppc/movc.s index 4d88e9cee..cb3188f33 100644 --- a/osfmk/ppc/movc.s +++ b/osfmk/ppc/movc.s @@ -43,6 +43,8 @@ ENTRY(pmap_zero_page, TAG_NO_FRAME_USED) #endif /* DEBUG */ mfmsr r6 /* Get the MSR */ + rlwinm r6,r6,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r6,r6,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r7, r6, 0, MSR_DR_BIT+1, MSR_DR_BIT-1 /* Turn off DR */ rlwinm r7,r7,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Disable interruptions li r4,PPC_PGBYTES-CACHE_LINE_SIZE /* Point to the end of the page */ @@ -88,6 +90,8 @@ ENTRY(phys_copy, TAG_NO_FRAME_USED) /* Switch off data translations */ mfmsr r6 + rlwinm r6,r6,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r6,r6,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r7, r6, 0, MSR_DR_BIT+1, MSR_DR_BIT-1 rlwinm r7, r7, 0, MSR_EE_BIT+1, MSR_EE_BIT-1 mtmsr r7 @@ -161,6 +165,8 @@ ENTRY(pmap_copy_page, TAG_NO_FRAME_USED) #endif mfmsr r9 ; Get the MSR + rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off stwu r1,-(FM_SIZE+32)(r1) ; Make a frame for us rlwinm r7,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Disable interruptions ori r7,r7,lo16(MASK(MSR_FP)) ; Turn on the FPU @@ -283,21 +289,14 @@ ENTRY2(copyin, copyinmsg, TAG_NO_FRAME_USED) stw r0,FM_LR_SAVE(r1) stwu r1,-(FM_SIZE+16)(r1) - mfmsr r0 /* Get the MSR */ - rlwinm r6,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear 'rupts */ - mtmsr r6 /* Disable 'rupts */ - - mfsprg r6,0 /* Get the per_proc */ - lwz r6,PP_CPU_DATA(r6) cmpli cr0,r5,0 - lwz r10,CPU_ACTIVE_THREAD(r6) - mtmsr r0 /* Set 'rupts back */ ble- cr0,.L_copyinout_trivial /* we know we have a valid copyin to do now */ /* Set up thread_recover in case we hit an illegal address */ - lwz r8,THREAD_TOP_ACT(r10) + mfsprg r8,1 /* Get the current act */ + lwz r10,ACT_THREAD(r8) lis r11,hi16(.L_copyinout_error) lwz r8,ACT_VMMAP(r8) ori r11,r11,lo16(.L_copyinout_error) @@ -331,16 +330,10 @@ ENTRY2(copyin, copyinmsg, TAG_NO_FRAME_USED) bl EXT(bcopy) /* Now that copyin is done, we don't need a recovery point */ - mfmsr r7 /* Get the MSR */ - rlwinm r6,r7,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear 'rupts */ - mtmsr r6 /* Disable 'rupts */ - mfsprg r6,0 /* Get the per_proc */ - - lwz r6,PP_CPU_DATA(r6) addi r1,r1,FM_SIZE+16 - lwz r10,CPU_ACTIVE_THREAD(r6) - mtmsr r7 ; Restore interrupts + mfsprg r6,1 /* Get the current act */ + lwz r10,ACT_THREAD(r6) li r3,0 lwz r0,FM_LR_SAVE(r1) stw r3,THREAD_RECOVER(r10) /* Clear recovery */ @@ -354,16 +347,9 @@ ENTRY2(copyin, copyinmsg, TAG_NO_FRAME_USED) /* Now that copyin is done, we don't need a recovery point */ - mfmsr r7 /* Get the MSR */ - rlwinm r6,r7,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear 'rupts */ - mtmsr r6 /* Disable 'rupts */ - - mfsprg r6,0 /* Get the per_proc */ - - lwz r6,PP_CPU_DATA(r6) + mfsprg r6,1 /* Get the current act */ addi r1,r1,FM_SIZE+16 - lwz r10,CPU_ACTIVE_THREAD(r6) - mtmsr r7 ; Restore interrupts + lwz r10,ACT_THREAD(r6) li r4,0 lwz r0,FM_LR_SAVE(r1) stw r4,THREAD_RECOVER(r10) /* Clear recovery */ @@ -427,22 +413,14 @@ ENTRY2(copyout, copyoutmsg, TAG_NO_FRAME_USED) lwz r5,FM_SIZE+8(r1) /* (TEST/DEBUG) */ #endif - mfmsr r7 /* Get the MSR */ - rlwinm r6,r7,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear 'rupts */ - mtmsr r6 /* Disable 'rupts */ - - mfsprg r6,0 /* Get the per_proc */ - - lwz r6,PP_CPU_DATA(r6) cmpli cr0,r5,0 - lwz r10,CPU_ACTIVE_THREAD(r6) - mtmsr r7 /* Restore 'rupts */ ble- cr0,.L_copyinout_trivial /* we know we have a valid copyout to do now */ /* Set up thread_recover in case we hit an illegal address */ - lwz r8,THREAD_TOP_ACT(r10) + mfsprg r8,1 /* Get the current act */ + lwz r10,ACT_THREAD(r8) lis r11,HIGH_ADDR(.L_copyinout_error) lwz r8,ACT_VMMAP(r8) rlwinm r12,r4,6,26,29 ; Get index to the segment slot @@ -472,16 +450,9 @@ ENTRY2(copyout, copyoutmsg, TAG_NO_FRAME_USED) bl EXT(bcopy) /* Now that copyout is done, we don't need a recovery point */ - mfmsr r7 /* Get the MSR */ - rlwinm r6,r7,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear 'rupts */ - mtmsr r6 /* Disable 'rupts */ - - mfsprg r6,0 /* Get the per_proc */ - - lwz r6,PP_CPU_DATA(r6) + mfsprg r6,1 /* Get the current act */ addi r1,r1,FM_SIZE+16 - lwz r10,CPU_ACTIVE_THREAD(r6) - mtmsr r7 ; Restore interrupts + lwz r10,ACT_THREAD(r6) li r3,0 lwz r0,FM_LR_SAVE(r1) stw r3,THREAD_RECOVER(r10) /* Clear recovery */ @@ -532,22 +503,15 @@ ENTRY(copyinstr, TAG_NO_FRAME_USED) stw r6,FM_SIZE+12(r1) /* (TEST/DEBUG) */ #endif - mfmsr r0 /* Get the MSR */ - rlwinm r7,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear 'rupts */ - mtmsr r7 /* Disable 'rupts */ - - mfsprg r7,0 /* Get the per_proc */ - lwz r7,PP_CPU_DATA(r7) cmpli cr0,r5,0 - lwz r10,CPU_ACTIVE_THREAD(r7) - mtmsr r0 /* Restore 'rupts */ ble- cr0,.L_copyinout_trivial /* we know we have a valid copyin to do now */ /* Set up thread_recover in case we hit an illegal address */ li r0,0 - lwz r8,THREAD_TOP_ACT(r10) + mfsprg r8,1 /* Get the current act */ + lwz r10,ACT_THREAD(r8) stw r0,0(r6) /* Clear result length */ lis r11,HIGH_ADDR(.L_copyinout_error) lwz r8,ACT_VMMAP(r8) ; Get the map for this activation diff --git a/osfmk/ppc/pcb.c b/osfmk/ppc/pcb.c index 475c97637..9150455d6 100644 --- a/osfmk/ppc/pcb.c +++ b/osfmk/ppc/pcb.c @@ -58,7 +58,6 @@ #include #include -#include #include #include #include @@ -142,14 +141,15 @@ machine_kernel_stack_init( #endif /* MACH_ASSERT */ kss = (unsigned int *)STACK_IKS(stack); - sv=(savearea *)(thread->top_act->mact.pcb); /* This for the sake of C */ + sv = thread->top_act->mact.pcb; /* This for the sake of C */ - sv->save_lr = (unsigned int) start_pos; /* Set up the execution address */ - sv->save_srr0 = (unsigned int) start_pos; /* Here too */ - sv->save_srr1 = MSR_SUPERVISOR_INT_OFF; /* Set the normal running MSR */ + sv->save_lr = (unsigned int) start_pos; /* Set up the execution address */ + sv->save_srr0 = (unsigned int) start_pos; /* Here too */ + sv->save_srr1 = MSR_SUPERVISOR_INT_OFF; /* Set the normal running MSR */ sv->save_r1 = (vm_offset_t) ((int)kss - KF_SIZE); /* Point to the top frame on the stack */ - sv->save_xfpscrpad = 0; /* Start with a clear fpscr */ - sv->save_xfpscr = 0; /* Start with a clear fpscr */ + sv->save_fpscr = 0; /* Clear all floating point exceptions */ + sv->save_vrsave = 0; /* Set the vector save state */ + sv->save_vscr[3] = 0x00010000; /* Supress java mode */ *((int *)sv->save_r1) = 0; /* Zero the frame backpointer */ thread->top_act->mact.ksp = 0; /* Show that the kernel stack is in use already */ @@ -170,13 +170,16 @@ switch_context( register thread_act_t old_act = old->top_act, new_act = new->top_act; register struct thread_shuttle* retval; pmap_t new_pmap; + facility_context *fowner; + #if MACH_LDEBUG || MACH_KDB log_thread_action("switch", (long)old, (long)new, (long)__builtin_return_address(0)); #endif - per_proc_info[cpu_number()].old_thread = old; + + per_proc_info[cpu_number()].old_thread = (unsigned int)old; per_proc_info[cpu_number()].cpu_flags &= ~traceBE; /* disable branch tracing if on */ assert(old_act->kernel_loaded || active_stacks[cpu_number()] == old_act->thread->kernel_stack); @@ -187,9 +190,19 @@ switch_context( * not keep hot state in our FPU, it must go back to the pcb * so that it can be found by the other if needed */ - if(real_ncpus > 1) { /* This is potentially slow, so only do when actually SMP */ - fpu_save(old_act); /* Save floating point if used */ - vec_save(old_act); /* Save vector if used */ + if(real_ncpus > 1) { /* This is potentially slow, so only do when actually SMP */ + fowner = per_proc_info[cpu_number()].FPU_owner; /* Cache this because it may change */ + if(fowner) { /* Is there any live context? */ + if(fowner->facAct == old->top_act) { /* Is it for us? */ + fpu_save(fowner); /* Yes, save it */ + } + } + fowner = per_proc_info[cpu_number()].VMX_owner; /* Cache this because it may change */ + if(fowner) { /* Is there any live context? */ + if(fowner->facAct == old->top_act) { /* Is it for us? */ + vec_save(fowner); /* Yes, save it */ + } + } } #if DEBUG @@ -216,25 +229,9 @@ switch_context( } } - /* Sanity check - is the stack pointer inside the stack that - * we're about to switch to? Is the execution address within - * the kernel's VM space?? - */ -#if 0 - printf("************* stack=%08X; R1=%08X; LR=%08X; old=%08X; cont=%08X; new=%08X\n", - new->kernel_stack, new_act->mact.pcb->ss.r1, - new_act->mact.pcb->ss.lr, old, continuation, new); /* (TEST/DEBUG) */ - assert((new->kernel_stack < new_act->mact.pcb->ss.r1) && - ((unsigned int)STACK_IKS(new->kernel_stack) > - new_act->mact.pcb->ss.r1)); - assert(new_act->mact.pcb->ss.lr < VM_MAX_KERNEL_ADDRESS); -#endif - - KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SCHED,MACH_SCHED) | DBG_FUNC_NONE, (int)old, (int)new, old->sched_pri, new->sched_pri, 0); - retval = Switch_context(old, continuation, new); assert(retval != (struct thread_shuttle*)NULL); @@ -257,14 +254,13 @@ thread_set_syscall_return( struct thread_shuttle *thread, kern_return_t retval) { - struct ppc_saved_state *ssp = &thread->top_act->mact.pcb->ss; #if MACH_ASSERT if (watchacts & WA_PCB) printf("thread_set_syscall_return(thr=%x,retval=%d)\n", thread,retval); #endif /* MACH_ASSERT */ - ssp->r3 = retval; + thread->top_act->mact.pcb->save_r3 = retval; } /* @@ -286,17 +282,21 @@ thread_machine_create( printf("thread_machine_create(thr=%x,thr_act=%x,st=%x)\n", thread, thr_act, start_pos); #endif /* MACH_ASSERT */ - hw_atomic_add(&saveanchor.saveneed, 4); /* Account for the number of saveareas we think we "need" + hw_atomic_add(&saveanchor.savetarget, 4); /* Account for the number of saveareas we think we "need" for this activation */ - assert(thr_act->mact.pcb == (pcb_t)0); /* Make sure there was no previous savearea */ + assert(thr_act->mact.pcb == (savearea *)0); /* Make sure there was no previous savearea */ sv = save_alloc(); /* Go get us a savearea */ - bzero((char *) sv, sizeof(struct pcb)); /* Clear out the whole shebang */ - - sv->save_act = thr_act; /* Set who owns it */ - sv->save_vrsave = 0; - thr_act->mact.pcb = (pcb_t)sv; /* Point to the save area */ + bzero((char *)((unsigned int)sv + sizeof(savearea_comm)), (sizeof(savearea) - sizeof(savearea_comm))); /* Clear it */ + + sv->save_hdr.save_prev = 0; /* Clear the back pointer */ + sv->save_hdr.save_flags = (sv->save_hdr.save_flags & ~SAVtype) | (SAVgeneral << SAVtypeshft); /* Mark as in use */ + sv->save_hdr.save_act = thr_act; /* Set who owns it */ + sv->save_vscr[3] = 0x00010000; /* Supress java mode */ + thr_act->mact.pcb = sv; /* Point to the save area */ + thr_act->mact.curctx = &thr_act->mact.facctx; /* Initialize facility context */ + thr_act->mact.facctx.facAct = thr_act; /* Initialize facility context pointer to activation */ #if MACH_ASSERT if (watchacts & WA_PCB) @@ -311,11 +311,10 @@ thread_machine_create( sv->save_srr1 = MSR_EXPORT_MASK_SET; /* Set the default user MSR */ - CIsTooLimited = (unsigned int *)(&sv->save_sr0); /* Make a pointer 'cause C can't cast on the left */ + CIsTooLimited = (unsigned int *)(&sv->save_sr0); /* Make a pointer 'cause C can't cast on the left */ for(i=0; i<16; i++) { /* Initialize all SRs */ CIsTooLimited[i] = SEG_REG_PROT | (i << 20) | thr_act->task->map->pmap->space; /* Set the SR value */ } - sv->save_sr_copyin = SEG_REG_PROT | (SR_COPYIN_NUM<<20) | thr_act->task->map->pmap->space; /* Default the copyin */ return(KERN_SUCCESS); } @@ -364,14 +363,25 @@ machine_switch_act( int cpu) { pmap_t new_pmap; + facility_context *fowner; /* Our context might wake up on another processor, so we must * not keep hot state in our FPU, it must go back to the pcb * so that it can be found by the other if needed */ - if(real_ncpus > 1) { /* This is potentially slow, so only do when actually SMP */ - fpu_save(old); /* Save floating point if used */ - vec_save(old); /* Save vector if used */ + if(real_ncpus > 1) { /* This is potentially slow, so only do when actually SMP */ + fowner = per_proc_info[cpu_number()].FPU_owner; /* Cache this because it may change */ + if(fowner) { /* Is there any live context? */ + if(fowner->facAct == old) { /* Is it for us? */ + fpu_save(fowner); /* Yes, save it */ + } + } + fowner = per_proc_info[cpu_number()].VMX_owner; /* Cache this because it may change */ + if(fowner) { /* Is there any live context? */ + if(fowner->facAct == old) { /* Is it for us? */ + vec_save(fowner); /* Yes, save it */ + } + } } active_stacks[cpu] = thread->kernel_stack; @@ -413,92 +423,74 @@ pcb_user_to_kernel(thread_act_t act) void act_machine_sv_free(thread_act_t act) { - register pcb_t pcb,userpcb,npcb; + register savearea *pcb, *userpcb; + register savearea_vec *vsv, *vpsv; + register savearea_fpu *fsv, *fpsv; register savearea *svp; register int i; /* - * This next bit insures that any live facility context for this thread is discarded on every processor - * that may have it. We go through all per-processor blocks and zero the facility owner if - * it is the thread being destroyed. This needs to be done via a compare-and-swap because - * some other processor could change the owner while we are clearing it. It turns out that - * this is the only place where we need the interlock, normal use of the owner field is cpu-local - * and doesn't need the interlock. Because we are called during termintation, and a thread - * terminates itself, the context on other processors has been saved (because we save it as - * part of the context switch), even if it is still considered live. Since the dead thread is - * not running elsewhere, and the context is saved, any other processor looking at the owner - * field will not attempt to save context again, meaning that it doesn't matter if the owner - * changes out from under it. + * This function will release all non-user state context. */ - /* - * free VMX and FPU saveareas. do not free user save areas. - * user VMX and FPU saveareas, if any, i'm told are last in - * the chain so we just stop if we find them - * we identify user VMX and FPU saveareas when we find a pcb - * with a save level of 0. we identify user regular save - * areas when we find one with MSR_PR set - */ - - pcb = act->mact.VMX_pcb; /* Get the top vector savearea */ - while(pcb) { /* Any VMX saved state? */ - svp = (savearea *)pcb; /* save lots of casting later */ - if (svp->save_level_vec == 0) break; /* done when hit user if any */ - pcb = (pcb_t)svp->save_prev_vector; /* Get one underneath our's */ - svp->save_flags &= ~SAVvmxvalid; /* Clear the VMX flag */ - if(!(svp->save_flags & SAVinuse)) { /* Anyone left with this one? */ - - save_ret(svp); /* release it */ - } - } - act->mact.VMX_pcb = pcb; - if (act->mact.VMX_lvl != 0) { - for(i=0; i < real_ncpus; i++) { /* Cycle through processors */ - (void)hw_compare_and_store((unsigned int)act, 0, &per_proc_info[i].VMX_thread); /* Clear if ours */ - } +/* + * + * Walk through and release all floating point and vector contexts that are not + * user state. We will also blow away live context if it belongs to non-user state. + * + */ + + if(act->mact.curctx->VMXlevel) { /* Is the current level user state? */ + toss_live_vec(act->mact.curctx); /* Dump live vectors if is not user */ + act->mact.curctx->VMXlevel = 0; /* Mark as user state */ + } + + vsv = act->mact.curctx->VMXsave; /* Get the top vector savearea */ + + while(vsv) { /* Any VMX saved state? */ + vpsv = vsv; /* Remember so we can toss this */ + if (!vsv->save_hdr.save_level) break; /* Done when hit user if any */ + vsv = (savearea_vec *)vsv->save_hdr.save_prev; /* Get one underneath our's */ + save_ret((savearea *)vpsv); /* Release it */ } + + act->mact.curctx->VMXsave = vsv; /* Queue the user context to the top */ + + if(act->mact.curctx->FPUlevel) { /* Is the current level user state? */ + toss_live_fpu(act->mact.curctx); /* Dump live float if is not user */ + act->mact.curctx->FPUlevel = 0; /* Mark as user state */ + } - pcb = act->mact.FPU_pcb; /* Get the top floating point savearea */ - while(pcb) { /* Any floating point saved state? */ - svp = (savearea *)pcb; - if (svp->save_level_fp == 0) break; /* done when hit user if any */ - pcb = (pcb_t)svp->save_prev_float; /* Get one underneath our's */ - svp->save_flags &= ~SAVfpuvalid; /* Clear the floating point flag */ - if(!(svp->save_flags & SAVinuse)) { /* Anyone left with this one? */ - save_ret(svp); /* Nope, release it */ - } - } - act->mact.FPU_pcb = pcb; - if (act->mact.FPU_lvl != 0) { - for(i=0; i < real_ncpus; i++) { /* Cycle through processors */ - (void)hw_compare_and_store((unsigned int)act, 0, &per_proc_info[i].FPU_thread); /* Clear if ours */ - } + fsv = act->mact.curctx->FPUsave; /* Get the top float savearea */ + + while(fsv) { /* Any float saved state? */ + fpsv = fsv; /* Remember so we can toss this */ + if (!fsv->save_hdr.save_level) break; /* Done when hit user if any */ + fsv = (savearea_fpu *)fsv->save_hdr.save_prev; /* Get one underneath our's */ + save_ret((savearea *)fpsv); /* Release it */ } + + act->mact.curctx->FPUsave = fsv; /* Queue the user context to the top */ - /* - * free all regular saveareas except a user savearea, if any - */ +/* + * free all regular saveareas except a user savearea, if any + */ - pcb = act->mact.pcb; - userpcb = (pcb_t)0; - while(pcb) { - svp = (savearea *)pcb; - if ((svp->save_srr1 & MASK(MSR_PR))) { - assert(userpcb == (pcb_t)0); - userpcb = pcb; - svp = (savearea *)userpcb; - npcb = (pcb_t)svp->save_prev; - svp->save_prev = (struct savearea *)0; - } else { - svp->save_flags &= ~SAVattach; /* Clear the attached flag */ - npcb = (pcb_t)svp->save_prev; - if(!(svp->save_flags & SAVinuse)) /* Anyone left with this one? */ - save_ret(svp); - } - pcb = npcb; + pcb = act->mact.pcb; /* Get the general savearea */ + userpcb = 0; /* Assume no user context for now */ + + while(pcb) { /* Any float saved state? */ + if (pcb->save_srr1 & MASK(MSR_PR)) { /* Is this a user savearea? */ + userpcb = pcb; /* Remember so we can toss this */ + break; + } + svp = pcb; /* Remember this */ + pcb = pcb->save_hdr.save_prev; /* Get one underneath our's */ + save_ret(svp); /* Release it */ } - act->mact.pcb = userpcb; - + + act->mact.pcb = userpcb; /* Chain in the user if there is one, or 0 if not */ + } @@ -524,74 +516,71 @@ act_virtual_machine_destroy(thread_act_t act) void act_machine_destroy(thread_act_t act) { - register pcb_t pcb, opcb; - int i; + + register savearea *pcb, *ppsv; + register savearea_vec *vsv, *vpsv; + register savearea_fpu *fsv, *fpsv; + register savearea *svp; + register int i; #if MACH_ASSERT if (watchacts & WA_PCB) printf("act_machine_destroy(0x%x)\n", act); #endif /* MACH_ASSERT */ - act_virtual_machine_destroy(act); +/* + * This function will release all context. + */ + act_virtual_machine_destroy(act); /* Make sure all virtual machines are dead first */ + /* - * This next bit insures that any live facility context for this thread is discarded on every processor - * that may have it. We go through all per-processor blocks and zero the facility owner if - * it is the thread being destroyed. This needs to be done via a compare-and-swap because - * some other processor could change the owner while we are clearing it. It turns out that - * this is the only place where we need the interlock, normal use of the owner field is cpu-local - * and doesn't need the interlock. Because we are called during termintation, and a thread - * terminates itself, the context on other processors has been saved (because we save it as - * part of the context switch), even if it is still considered live. Since the dead thread is - * not running elsewhere, and the context is saved, any other processor looking at the owner - * field will not attempt to save context again, meaning that it doesn't matter if the owner - * changes out from under it. + * + * Walk through and release all floating point and vector contexts. Also kill live context. + * */ - for(i=0; i < real_ncpus; i++) { /* Cycle through processors */ - (void)hw_compare_and_store((unsigned int)act, 0, &per_proc_info[i].FPU_thread); /* Clear if ours */ - (void)hw_compare_and_store((unsigned int)act, 0, &per_proc_info[i].VMX_thread); /* Clear if ours */ - } + toss_live_vec(act->mact.curctx); /* Dump live vectors */ + + vsv = act->mact.curctx->VMXsave; /* Get the top vector savearea */ - pcb = act->mact.VMX_pcb; /* Get the top vector savearea */ - while(pcb) { /* Any VMX saved state? */ - opcb = pcb; /* Save current savearea address */ - pcb = (pcb_t)(((savearea *)pcb)->save_prev_vector); /* Get one underneath our's */ - ((savearea *)opcb)->save_flags &= ~SAVvmxvalid; /* Clear the VMX flag */ - - if(!(((savearea *)opcb)->save_flags & SAVinuse)) { /* Anyone left with this one? */ - save_release((savearea *)opcb); /* Nope, release it */ - } + while(vsv) { /* Any VMX saved state? */ + vpsv = vsv; /* Remember so we can toss this */ + vsv = (savearea_vec *)vsv->save_hdr.save_prev; /* Get one underneath our's */ + save_release((savearea *)vpsv); /* Release it */ } - act->mact.VMX_pcb = (pcb_t)0; /* Clear pointer */ + + act->mact.curctx->VMXsave = 0; /* Kill chain */ + + toss_live_fpu(act->mact.curctx); /* Dump live float */ - pcb = act->mact.FPU_pcb; /* Get the top floating point savearea */ - while(pcb) { /* Any floating point saved state? */ - opcb = pcb; /* Save current savearea address */ - pcb = (pcb_t)(((savearea *)pcb)->save_prev_float); /* Get one underneath our's */ - ((savearea *)opcb)->save_flags &= ~SAVfpuvalid; /* Clear the floating point flag */ - - if(!(((savearea *)opcb)->save_flags & SAVinuse)) { /* Anyone left with this one? */ - save_release((savearea *)opcb); /* Nope, release it */ - } + fsv = act->mact.curctx->FPUsave; /* Get the top float savearea */ + + while(fsv) { /* Any float saved state? */ + fpsv = fsv; /* Remember so we can toss this */ + fsv = (savearea_fpu *)fsv->save_hdr.save_prev; /* Get one underneath our's */ + save_release((savearea *)fpsv); /* Release it */ } - act->mact.FPU_pcb = (pcb_t)0; /* Clear pointer */ + + act->mact.curctx->FPUsave = 0; /* Kill chain */ + +/* + * free all regular saveareas. + */ - pcb = act->mact.pcb; /* Get the top normal savearea */ - act->mact.pcb = (pcb_t)0; /* Clear pointer */ + pcb = act->mact.pcb; /* Get the general savearea */ - while(pcb) { /* Any normal saved state left? */ - opcb = pcb; /* Keep track of what we're working on */ - pcb = (pcb_t)(((savearea *)pcb)->save_prev); /* Get one underneath our's */ - - ((savearea *)opcb)->save_flags = 0; /* Clear all flags since we release this in any case */ - save_release((savearea *)opcb); /* Release this one */ + while(pcb) { /* Any float saved state? */ + ppsv = pcb; /* Remember so we can toss this */ + pcb = pcb->save_hdr.save_prev; /* Get one underneath our's */ + save_release(ppsv); /* Release it */ } + + hw_atomic_sub(&saveanchor.savetarget, 4); /* Unaccount for the number of saveareas we think we "need" */ - hw_atomic_sub(&saveanchor.saveneed, 4); /* Unaccount for the number of saveareas we think we "need" - for this activation */ } + kern_return_t act_machine_create(task_t task, thread_act_t thr_act) { @@ -600,11 +589,6 @@ act_machine_create(task_t task, thread_act_t thr_act) * We don't use this anymore. */ - register pcb_t pcb; - register int i; - unsigned int *CIsTooLimited; - pmap_t pmap; - return KERN_SUCCESS; } @@ -621,7 +605,6 @@ void act_machine_init() assert( THREAD_STATE_MAX >= PPC_THREAD_STATE_COUNT ); assert( THREAD_STATE_MAX >= PPC_EXCEPTION_STATE_COUNT ); assert( THREAD_STATE_MAX >= PPC_FLOAT_STATE_COUNT ); - assert( THREAD_STATE_MAX >= sizeof(struct ppc_saved_state)/sizeof(int)); /* * If we start using kernel activations, @@ -654,72 +637,10 @@ act_machine_return(int code) */ assert( code == KERN_TERMINATED ); assert( thr_act ); - - act_lock_thread(thr_act); - -#ifdef CALLOUT_RPC_MODEL - /* - * JMM - This needs to get cleaned up to work under the much simpler - * return (instead of callout model). - */ - if (thr_act->thread->top_act != thr_act) { - /* - * this is not the top activation; - * if possible, we should clone the shuttle so that - * both the root RPC-chain and the soon-to-be-orphaned - * RPC-chain have shuttles - * - * JMM - Cloning is a horrible idea! Instead we should alert - * the pieces upstream to return the shuttle. We will use - * alerts for this. - */ - act_unlock_thread(thr_act); - panic("act_machine_return: ORPHAN CASE NOT YET IMPLEMENTED"); - } - - if (thr_act->lower != THR_ACT_NULL) { - thread_t cur_thread = current_thread(); - thread_act_t cur_act; - struct ipc_port *iplock; - - /* terminate the entire thread (shuttle plus activation) */ - /* terminate only this activation, send an appropriate */ - /* return code back to the activation that invoked us. */ - iplock = thr_act->pool_port; /* remember for unlock call */ - thr_act->lower->alerts |= SERVER_TERMINATED; - install_special_handler(thr_act->lower); - - /* Return to previous act with error code */ - - act_locked_act_reference(thr_act); /* keep it around */ - act_switch_swapcheck(cur_thread, (ipc_port_t)0); - - (void) switch_act(THR_ACT_NULL); - /* assert(thr_act->ref_count == 0); */ /* XXX */ - cur_act = cur_thread->top_act; - MACH_RPC_RET(cur_act) = KERN_RPC_SERVER_TERMINATED; - machine_kernel_stack_init(cur_thread, mach_rpc_return_error); - /* - * The following unlocks must be done separately since fields - * used by `act_unlock_thread()' have been cleared, meaning - * that it would not release all of the appropriate locks. - */ - rpc_unlock(cur_thread); - if (iplock) ip_unlock(iplock); /* must be done separately */ - act_unlock(thr_act); - act_deallocate(thr_act); /* free it */ - Load_context(cur_thread); - /*NOTREACHED*/ - - panic("act_machine_return: TALKING ZOMBIE! (2)"); - } - -#endif /* CALLOUT_RPC_MODEL */ + assert(thr_act->thread->top_act == thr_act); /* This is the only activation attached to the shuttle... */ - assert(thr_act->thread->top_act == thr_act); - act_unlock_thread(thr_act); thread_terminate_self(); /*NOTREACHED*/ @@ -731,7 +652,8 @@ thread_machine_set_current(struct thread_shuttle *thread) { register int my_cpu = cpu_number(); - cpu_data[my_cpu].active_thread = thread; + set_machine_current_thread(thread); + set_machine_current_act(thread->top_act); active_kloaded[my_cpu] = thread->top_act->kernel_loaded ? thread->top_act : THR_ACT_NULL; } @@ -747,14 +669,6 @@ thread_machine_init(void) } #if MACH_ASSERT -void -dump_pcb(pcb_t pcb) -{ - printf("pcb @ %8.8x:\n", pcb); -#if DEBUG - regDump(&pcb->ss); -#endif /* DEBUG */ -} void dump_thread(thread_t th) @@ -789,7 +703,7 @@ get_useraddr() thread_act_t thr_act = current_act(); - return(thr_act->mact.pcb->ss.srr0); + return(thr_act->mact.pcb->save_srr0); } /* @@ -801,10 +715,12 @@ stack_detach(thread_t thread) { vm_offset_t stack; - KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_STACK_DETACH), - thread, thread->priority, - thread->sched_pri, 0, - 0); + KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_STACK_DETACH), + thread, thread->priority, + thread->sched_pri, 0, 0); + + if (thread->top_act) + act_machine_sv_free(thread->top_act); stack = thread->kernel_stack; thread->kernel_stack = 0; @@ -845,17 +761,18 @@ stack_attach(struct thread_shuttle *thread, activation. in that case do not do anything */ if ((thr_act = thread->top_act) != 0) { sv = save_get(); /* cannot block */ - // bzero((char *) sv, sizeof(struct pcb)); - sv->save_act = thr_act; - sv->save_prev = (struct savearea *)thr_act->mact.pcb; - thr_act->mact.pcb = (pcb_t)sv; + sv->save_hdr.save_flags = (sv->save_hdr.save_flags & ~SAVtype) | (SAVgeneral << SAVtypeshft); /* Mark as in use */ + sv->save_hdr.save_act = thr_act; + sv->save_hdr.save_prev = thr_act->mact.pcb; + thr_act->mact.pcb = sv; sv->save_srr0 = (unsigned int) start_pos; /* sv->save_r3 = ARG ? */ sv->save_r1 = (vm_offset_t)((int)kss - KF_SIZE); sv->save_srr1 = MSR_SUPERVISOR_INT_OFF; - sv->save_xfpscrpad = 0; /* Start with a clear fpscr */ - sv->save_xfpscr = 0; /* Start with a clear fpscr */ + sv->save_fpscr = 0; /* Clear all floating point exceptions */ + sv->save_vrsave = 0; /* Set the vector save state */ + sv->save_vscr[3] = 0x00010000; /* Supress java mode */ *((int *)sv->save_r1) = 0; thr_act->mact.ksp = 0; } @@ -872,25 +789,39 @@ stack_handoff(thread_t old, thread_t new) { - vm_offset_t stack; - pmap_t new_pmap; - - assert(new->top_act); - assert(old->top_act); - - stack = stack_detach(old); - new->kernel_stack = stack; + vm_offset_t stack; + pmap_t new_pmap; + facility_context *fowner; + + assert(new->top_act); + assert(old->top_act); + + stack = stack_detach(old); + new->kernel_stack = stack; + if (stack == old->stack_privilege) { + assert(new->stack_privilege); + old->stack_privilege = new->stack_privilege; + new->stack_privilege = stack; + } - per_proc_info[cpu_number()].cpu_flags &= ~traceBE; + per_proc_info[cpu_number()].cpu_flags &= ~traceBE; -#if NCPUS > 1 - if (real_ncpus > 1) { - fpu_save(old->top_act); - vec_save(old->top_act); - } -#endif + if(real_ncpus > 1) { /* This is potentially slow, so only do when actually SMP */ + fowner = per_proc_info[cpu_number()].FPU_owner; /* Cache this because it may change */ + if(fowner) { /* Is there any live context? */ + if(fowner->facAct == old->top_act) { /* Is it for us? */ + fpu_save(fowner); /* Yes, save it */ + } + } + fowner = per_proc_info[cpu_number()].VMX_owner; /* Cache this because it may change */ + if(fowner) { /* Is there any live context? */ + if(fowner->facAct == old->top_act) { /* Is it for us? */ + vec_save(fowner); /* Yes, save it */ + } + } + } - KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SCHED,MACH_STACK_HANDOFF) | DBG_FUNC_NONE, + KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SCHED,MACH_STACK_HANDOFF) | DBG_FUNC_NONE, (int)old, (int)new, old->sched_pri, new->sched_pri, 0); @@ -904,17 +835,17 @@ stack_handoff(thread_t old, } } - thread_machine_set_current(new); - active_stacks[cpu_number()] = new->kernel_stack; - per_proc_info[cpu_number()].Uassist = new->top_act->mact.cthread_self; -#if 1 - per_proc_info[cpu_number()].ppbbTaskEnv = new->top_act->mact.bbTaskEnv; - per_proc_info[cpu_number()].spcFlags = new->top_act->mact.specFlags; -#endif - if (branch_tracing_enabled()) - per_proc_info[cpu_number()].cpu_flags |= traceBE; + thread_machine_set_current(new); + active_stacks[cpu_number()] = new->kernel_stack; + per_proc_info[cpu_number()].Uassist = new->top_act->mact.cthread_self; + + per_proc_info[cpu_number()].ppbbTaskEnv = new->top_act->mact.bbTaskEnv; + per_proc_info[cpu_number()].spcFlags = new->top_act->mact.specFlags; + + if (branch_tracing_enabled()) + per_proc_info[cpu_number()].cpu_flags |= traceBE; - if(trcWork.traceMask) dbgTrace(0x12345678, (unsigned int)old->top_act, (unsigned int)new->top_act); /* Cut trace entry if tracing */ + if(trcWork.traceMask) dbgTrace(0x12345678, (unsigned int)old->top_act, (unsigned int)new->top_act); /* Cut trace entry if tracing */ return; } @@ -953,8 +884,9 @@ thread_swapin_mach_alloc(thread_t thread) sv = save_alloc(); assert(sv); - // bzero((char *) sv, sizeof(struct pcb)); - sv->save_act = thread->top_act; - thread->top_act->mact.pcb = (pcb_t)sv; + sv->save_hdr.save_prev = 0; /* Initialize back chain */ + sv->save_hdr.save_flags = (sv->save_hdr.save_flags & ~SAVtype) | (SAVgeneral << SAVtypeshft); /* Mark as in use */ + sv->save_hdr.save_act = thread->top_act; /* Initialize owner */ + thread->top_act->mact.pcb = sv; } diff --git a/osfmk/ppc/pmap.c b/osfmk/ppc/pmap.c index b9153c7b9..f6f6a8e34 100644 --- a/osfmk/ppc/pmap.c +++ b/osfmk/ppc/pmap.c @@ -93,6 +93,7 @@ #include #include +#include #include #include #include @@ -113,6 +114,7 @@ #include #include #include +#include #include #if DB_MACHINE_COMMANDS @@ -426,8 +428,6 @@ pmap_bootstrap(unsigned int mem_size, vm_offset_t *first_avail, vm_offset_t *fir unsigned int mask; vm_offset_t first_used_addr; PCA *pcaptr; - savectl *savec, *savec2; - vm_offset_t save, save2; *first_avail = round_page(*first_avail); @@ -491,7 +491,7 @@ pmap_bootstrap(unsigned int mem_size, vm_offset_t *first_avail, vm_offset_t *fir size = (vm_size_t) ( (InitialSaveBloks * PAGE_SIZE) + /* Allow space for the initial context saveareas */ - (8 * PAGE_SIZE) + /* For backpocket saveareas */ + ((InitialSaveBloks / 2) * PAGE_SIZE) + /* For backpocket saveareas */ hash_table_size + /* For hash table */ hash_table_size + /* For PTEG allocation table */ (num * sizeof(struct phys_entry)) /* For the physical entries */ @@ -580,75 +580,15 @@ pmap_bootstrap(unsigned int mem_size, vm_offset_t *first_avail, vm_offset_t *fir assert((hash_table_base & (hash_table_size-1)) == 0); pcaptr = (PCA *)(hash_table_base+hash_table_size); /* Point to the PCA table */ + mapCtl.mapcflush.pcaptr = pcaptr; for(i=0; i < (hash_table_size/64) ; i++) { /* For all of PTEG control areas: */ pcaptr[i].flgs.PCAalflgs.PCAfree=0xFF; /* Mark all slots free */ pcaptr[i].flgs.PCAalflgs.PCAsteal=0x01; /* Initialize steal position */ } -/* - * Allocate our initial context save areas. As soon as we do this, - * we can take an interrupt. We do the saveareas here, 'cause they're guaranteed - * to be at least page aligned. - */ - save2 = addr; /* Remember first page */ - save = addr; /* Point to the whole block of blocks */ - savec2 = (savectl *)(addr + PAGE_SIZE - sizeof(savectl)); /* Point to the first's control area */ - - for(i=0; i < InitialSaveBloks; i++) { /* Initialize the saveareas */ - - savec = (savectl *)(save + PAGE_SIZE - sizeof(savectl)); /* Get the control area for this one */ - - savec->sac_alloc = sac_empty; /* Mark both free */ - savec->sac_vrswap = 0; /* V=R, so the translation factor is 0 */ - savec->sac_flags = sac_perm; /* Mark it permanent */ - - savec->sac_flags |= 0x0000EE00; /* (TEST/DEBUG) */ - - save += PAGE_SIZE; /* Jump up to the next one now */ - - savec->sac_next = (unsigned int *)save; /* Link these two */ - - } - - savec->sac_next = (unsigned int *)0; /* Clear the forward pointer for the last */ - savec2->sac_alloc &= 0x7FFFFFFF; /* Mark the first one in use */ - - saveanchor.savefree = (unsigned int)save2; /* Point to the first one */ - saveanchor.savecount = InitialSaveBloks * sac_cnt; /* The total number of save areas allocated */ - saveanchor.saveinuse = 1; /* Number of areas in use */ - saveanchor.savemin = InitialSaveMin; /* We abend if lower than this */ - saveanchor.saveneghyst = InitialNegHysteresis; /* The minimum number to keep free (must be a multiple of sac_cnt) */ - saveanchor.savetarget = InitialSaveTarget; /* The target point for free save areas (must be a multiple of sac_cnt) */ - saveanchor.saveposhyst = InitialPosHysteresis; /* The high water mark for free save areas (must be a multiple of sac_cnt) */ - __asm__ volatile ("mtsprg 1, %0" : : "r" (save2)); /* Tell the exception handler about it */ - - addr += InitialSaveBloks * PAGE_SIZE; /* Move up the next free address */ - - save2 = addr; - save = addr; - savec2 = (savectl *)(addr + PAGE_SIZE - sizeof(savectl)); - - for(i=0; i < 8; i++) { /* Allocate backpocket saveareas */ - - savec = (savectl *)(save + PAGE_SIZE - sizeof(savectl)); - - savec->sac_alloc = sac_empty; - savec->sac_vrswap = 0; - savec->sac_flags = sac_perm; - savec->sac_flags |= 0x0000EE00; - - save += PAGE_SIZE; - - savec->sac_next = (unsigned int *)save; - - } - - savec->sac_next = (unsigned int *)0; - savec2->sac_alloc &= 0x7FFFFFFF; - debugbackpocket = save2; - addr += 8 * PAGE_SIZE; - + savearea_init(&addr); /* Initialize the savearea chains and data */ + /* phys_table is static to help debugging, * this variable is no longer actually used * outside of this scope @@ -1175,13 +1115,13 @@ pmap_remove( while(mp = (mapping *)hw_rem_blk(pmap, sva, lpage)) { /* Keep going until no more */ if((unsigned int)mp & 1) { /* Make sure we don't unmap a permanent one */ - blm = (blokmap *)hw_cpv((mapping *)((unsigned int)mp & 0xFFFFFFFE)); /* Get virtual address */ + blm = (struct mapping *)hw_cpv((mapping *)((unsigned int)mp & 0xFFFFFFFC)); /* Get virtual address */ panic("mapping_remove: attempt to unmap a permanent mapping - pmap = %08X, va = %08X, mapping = %08X\n", pmap, sva, blm); } - mapping_free(hw_cpv(mp)); /* Release it */ + if (!((unsigned int)mp & 2)) + mapping_free(hw_cpv(mp)); /* Release it */ } - while (pmap->stats.resident_count && (eva > sva)) { eva -= PAGE_SIZE; /* Back up a page */ @@ -1324,6 +1264,8 @@ void pmap_protect( return; /* Leave... */ } + + /* * pmap_enter * @@ -1338,8 +1280,8 @@ void pmap_protect( * insert this page into the given map NOW. */ void -pmap_enter(pmap_t pmap, vm_offset_t va, vm_offset_t pa, vm_prot_t prot, - boolean_t wired) +pmap_enter(pmap_t pmap, vm_offset_t va, vm_offset_t pa, vm_prot_t prot, + unsigned int flags, boolean_t wired) { spl_t spl; struct mapping *mp; @@ -1368,11 +1310,21 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_offset_t pa, vm_prot_t prot, bug!!!!) */ mapping_remove(pmap, va); /* Remove any other mapping at this address */ + + if(flags & VM_WIMG_USE_DEFAULT) { + if(pp) { + /* Set attr to the phys default */ + memattr = ((pp->pte1&0x00000078) >> 3); + } else { + memattr = PTE_WIMG_UNCACHED_COHERENT_GUARDED; + } + } else { + memattr = flags & VM_WIMG_MASK; + } - memattr = PTE_WIMG_IO; /* Assume I/O mapping for a moment */ - if(pp) memattr = ((pp->pte1&0x00000078) >> 3); /* Set the attribute to the physical default */ - mp=mapping_make(pmap, pp, va, pa, prot, memattr, 0); /* Make the address mapping */ + /* Make the address mapping */ + mp=mapping_make(pmap, pp, va, pa, prot, memattr, 0); splx(spl); /* I'm not busy no more - come what may */ @@ -1442,6 +1394,45 @@ vm_offset_t pmap_extract(pmap_t pmap, vm_offset_t va) { return pa; /* Return physical address or 0 */ } +/* + * pmap_attribute_cache_sync + * Handle the machine attribute calls which involve sync the prcessor + * cache. + */ +kern_return_t +pmap_attribute_cache_sync(address, size, attribute, value) + vm_offset_t address; + vm_size_t size; + vm_machine_attribute_t attribute; + vm_machine_attribute_val_t* value; +{ + while(size) { + switch (*value) { /* What type was that again? */ + case MATTR_VAL_CACHE_SYNC: /* It is sync I+D caches */ + sync_cache(address, PAGE_SIZE); /* Sync up dem caches */ + break; /* Done with this one here... */ + + case MATTR_VAL_CACHE_FLUSH: /* It is flush from all caches */ + flush_dcache(address, PAGE_SIZE, TRUE); /* Flush out the data cache */ + invalidate_icache(address, + PAGE_SIZE, TRUE); /* Flush out the instruction cache */ + break; /* Done with this one here... */ + + case MATTR_VAL_DCACHE_FLUSH: /* It is flush from data cache(s) */ + flush_dcache(address, PAGE_SIZE, TRUE); /* Flush out the data cache */ + break; /* Done with this one here... */ + + case MATTR_VAL_ICACHE_FLUSH: /* It is flush from instr cache(s) */ + invalidate_icache(address, + PAGE_SIZE, TRUE); /* Flush out the instruction cache */ + break; /* Done with this one here... */ + } + size -= PAGE_SIZE; + } + return KERN_SUCCESS;; +} + + /* * pmap_attributes: * @@ -2283,7 +2274,10 @@ void pmap_ver(pmap_t pmap, vm_offset_t sva, vm_offset_t eva) { } - - - +/* temporary workaround */ +boolean_t +coredumpok(vm_map_t map, vm_offset_t va) +{ + return TRUE; +} diff --git a/osfmk/ppc/pmap.h b/osfmk/ppc/pmap.h index 444eb4b77..0a4d2e97e 100644 --- a/osfmk/ppc/pmap.h +++ b/osfmk/ppc/pmap.h @@ -116,6 +116,17 @@ extern pmap_t cursor_pmap; /* The pmap to start allocations with */ #define pmap_phys_address(x) ((x) << PPC_PGSHIFT) #define pmap_phys_to_frame(x) ((x) >> PPC_PGSHIFT) +#define PMAP_DEFAULT_CACHE 0 +#define PMAP_INHIBIT_CACHE 1 +#define PMAP_GUARDED_CACHE 2 +#define PMAP_ACTIVATE_CACHE 4 +#define PMAP_NO_GUARD_CACHE 8 + +/* corresponds to cached, coherent, not writethru, not guarded */ +#define VM_WIMG_DEFAULT VM_MEM_COHERENT +#define VM_WIMG_IO VM_MEM_COHERENT | \ + VM_MEM_NOT_CACHEABLE | VM_MEM_GUARDED + /* * prototypes. */ diff --git a/osfmk/ppc/ppc_init.c b/osfmk/ppc/ppc_init.c index d75761a1a..e52131729 100644 --- a/osfmk/ppc/ppc_init.c +++ b/osfmk/ppc/ppc_init.c @@ -113,6 +113,7 @@ void ppc_init(boot_args *args) char *str; unsigned long addr, videoAddr; unsigned int maxmem; + unsigned int cputrace; bat_t bat; extern vm_offset_t static_memory_end; @@ -129,16 +130,19 @@ void ppc_init(boot_args *args) per_proc_info[0].interrupts_enabled = 0; per_proc_info[0].active_kloaded = (unsigned int) &active_kloaded[0]; - per_proc_info[0].cpu_data = (unsigned int) - &cpu_data[0]; + set_machine_current_thread(&pageout_thread); + set_machine_current_act(&pageout_act); + pageout_thread.top_act = &pageout_act; + pageout_act.thread = &pageout_thread; + per_proc_info[0].pp_preemption_count = 1; + per_proc_info[0].pp_simple_lock_count = 0; + per_proc_info[0].pp_interrupt_level = 0; per_proc_info[0].active_stacks = (unsigned int) &active_stacks[0]; per_proc_info[0].need_ast = (unsigned int) &need_ast[0]; - per_proc_info[0].FPU_thread = 0; - per_proc_info[0].FPU_vmmCtx = 0; - per_proc_info[0].VMX_thread = 0; - per_proc_info[0].VMX_vmmCtx = 0; + per_proc_info[0].FPU_owner = 0; + per_proc_info[0].VMX_owner = 0; machine_slot[0].is_cpu = TRUE; @@ -244,6 +248,10 @@ void ppc_init(boot_args *args) if (!PE_parse_boot_arg("diag", &dgWork.dgFlags)) dgWork.dgFlags=0; /* Set diagnostic flags */ if(dgWork.dgFlags & enaExpTrace) trcWork.traceMask = 0xFFFFFFFF; /* If tracing requested, enable it */ + if(PE_parse_boot_arg("ctrc", &cputrace)) { /* See if tracing is limited to a specific cpu */ + trcWork.traceMask = (trcWork.traceMask & 0xFFFFFFF0) | (cputrace & 0xF); /* Limit to 4 */ + } + #if 0 GratefulDebInit((bootBumbleC *)&(args->Video)); /* Initialize the GratefulDeb debugger */ #endif @@ -301,19 +309,16 @@ ppc_init_cpu( struct per_proc_info *proc_info) { int i; - unsigned int gph; - savectl *sctl; /* Savearea controls */ - if(proc_info->savedSave) { /* Do we have a savearea set up already? */ - mtsprg(1, proc_info->savedSave); /* Set saved address of savearea */ - } - else { - gph = (unsigned int)save_get_phys(); /* Get a savearea (physical addressing) */ - mtsprg(1, gph); /* Set physical address of savearea */ - } + if(!(proc_info->next_savearea)) /* Do we have a savearea set up already? */ + proc_info->next_savearea = (savearea *)save_get_init(); /* Get a savearea */ cpu_init(); - + + proc_info->pp_preemption_count = 1; + proc_info->pp_simple_lock_count = 0; + proc_info->pp_interrupt_level = 0; + proc_info->Lastpmap = 0; /* Clear last used space */ /* Set up segment registers as VM through space 0 */ diff --git a/osfmk/ppc/ppc_vm_init.c b/osfmk/ppc/ppc_vm_init.c index b700ba2ff..0fe096d90 100644 --- a/osfmk/ppc/ppc_vm_init.c +++ b/osfmk/ppc/ppc_vm_init.c @@ -260,14 +260,18 @@ void ppc_vm_init(unsigned int mem_limit, boot_args *args) addr < round_page(sectKLDB+sectSizeKLD); addr += PAGE_SIZE) { - pmap_enter(kernel_pmap, addr, addr, VM_PROT_READ|VM_PROT_WRITE, TRUE); + pmap_enter(kernel_pmap, addr, addr, + VM_PROT_READ|VM_PROT_WRITE, + VM_WIMG_USE_DEFAULT, TRUE); } for (addr = trunc_page(sectLINKB); addr < round_page(sectLINKB+sectSizeLINK); addr += PAGE_SIZE) { - pmap_enter(kernel_pmap, addr, addr, VM_PROT_READ|VM_PROT_WRITE, TRUE); + pmap_enter(kernel_pmap, addr, addr, + VM_PROT_READ|VM_PROT_WRITE, + VM_WIMG_USE_DEFAULT, TRUE); } /* @@ -275,7 +279,9 @@ void ppc_vm_init(unsigned int mem_limit, boot_args *args) * be released later, but not all. Ergo, no block mapping here */ for(addr = trunc_page(end); addr < round_page(static_memory_end); addr += PAGE_SIZE) { - pmap_enter(kernel_pmap, addr, addr, VM_PROT_READ|VM_PROT_WRITE, TRUE); + pmap_enter(kernel_pmap, addr, addr, + VM_PROT_READ|VM_PROT_WRITE, + VM_WIMG_USE_DEFAULT, TRUE); } #endif /* __MACHO__ */ diff --git a/osfmk/ppc/proc_reg.h b/osfmk/ppc/proc_reg.h index c06e8b993..87e0955a7 100644 --- a/osfmk/ppc/proc_reg.h +++ b/osfmk/ppc/proc_reg.h @@ -118,19 +118,6 @@ #define SEG_REG_INVALID 0x0000 #define KERNEL_SEG_REG0_VALUE 0x20000000 /* T=0,Ks=0,Ku=1 PPC_SID_KERNEL=0*/ -/* the following segment register values are only used prior to the probe, - * they map the various device areas 1-1 on 601 machines - */ -#define KERNEL_SEG_REG5_VALUE 0xa7F00005 /* T=1,Ks=0,Ku=1,BUID=0x7F,SR=5 */ -#define KERNEL_SEG_REG8_VALUE 0xa7F00008 /* T=1,Ks=0,Ku=1,BUID=0x7F,SR=8 */ -#define KERNEL_SEG_REG9_VALUE 0xa7F00009 /* T=1,Ks=0,Ku=1,BUID=0x7F,SR=9 */ -#define KERNEL_SEG_REG10_VALUE 0xa7F0000a /* T=1,Ks=0,Ku=1,BUID=0x7F,SR=a */ -#define KERNEL_SEG_REG11_VALUE 0xa7F0000b /* T=1,Ks=0,Ku=1,BUID=0x7F,SR=b */ -#define KERNEL_SEG_REG12_VALUE 0xa7F0000c /* T=1,Ks=0,Ku=1,BUID=0x7F,SR=c */ -#define KERNEL_SEG_REG13_VALUE 0xa7F0000d /* T=1,Ks=0,Ku=1,BUID=0x7F,SR=d */ -#define KERNEL_SEG_REG14_VALUE 0xa7F0000e /* T=1,Ks=0,Ku=1,BUID=0x7F,SR=e */ -#define KERNEL_SEG_REG15_VALUE 0xa7F0000f /* T=1,Ks=0,Ku=1,BUID=0x7F,SR=f */ - /* For SEG_REG_PROT we have T=0, Ks=0, Ku=1 */ #define SEG_REG_PROT 0x20000000 /* seg regs should have these bits set */ @@ -198,9 +185,26 @@ #define PTE1_CHANGED_BIT 24 #define PTE0_HASH_ID_BIT 25 -#define PPC_HASHSIZE 2048 /* size of hash table */ -#define PPC_HASHSIZE_LOG2 11 -#define PPC_MIN_MPP 2 /* min # of mappings per phys page */ +#define PTE_NULL ((pte_t*) NULL) /* No pte found/associated with this */ +#define PTE_EMPTY 0x7fffffbf /* Value in the pte0.word of a free pte */ + +#define PTE_WIMG_CB_CACHED 0 /* cached, writeback */ +#define PTE_WIMG_CB_CACHED_GUARDED 1 /* cached, writeback, guarded */ +#define PTE_WIMG_CB_CACHED_COHERENT 2 /* cached, writeback, coherent (default) */ +#define PTE_WIMG_CB_CACHED_COHERENT_GUARDED 3 /* cached, writeback, coherent, guarded */ +#define PTE_WIMG_UNCACHED 4 /* uncached */ +#define PTE_WIMG_UNCACHED_GUARDED 5 /* uncached, guarded */ +#define PTE_WIMG_UNCACHED_COHERENT 6 /* uncached, coherentt */ +#define PTE_WIMG_UNCACHED_COHERENT_GUARDED 7 /* uncached, coherent, guarded */ +#define PTE_WIMG_WT_CACHED 8 /* cached, writethru */ +#define PTE_WIMG_WT_CACHED_GUARDED 9 /* cached, writethru, guarded */ +#define PTE_WIMG_WT_CACHED_COHERENT 10 /* cached, writethru, coherent */ +#define PTE_WIMG_WT_CACHED_COHERENT_GUARDED 11 /* cached, writethru, coherent, guarded */ + +#define PTE_WIMG_DEFAULT PTE_WIMG_CB_CACHED_COHERENT +#define PTE_WIMG_IO PTE_WIMG_UNCACHED_COHERENT_GUARDED + + #ifndef ASSEMBLER #ifdef __GNUC__ @@ -329,25 +333,6 @@ typedef struct pte_t { pte1_t pte1; } pte_t; -#define PTE_NULL ((pte_t*) NULL) /* No pte found/associated with this */ -#define PTE_EMPTY 0x7fffffbf /* Value in the pte0.word of a free pte */ - -#define PTE_WIMG_CB_CACHED 0 /* cached, writeback */ -#define PTE_WIMG_CB_CACHED_GUARDED 1 /* cached, writeback, guarded */ -#define PTE_WIMG_CB_CACHED_COHERENT 2 /* cached, writeback, coherent (default) */ -#define PTE_WIMG_CB_CACHED_COHERENT_GUARDED 3 /* cached, writeback, coherent, guarded */ -#define PTE_WIMG_UNCACHED 4 /* uncached */ -#define PTE_WIMG_UNCACHED_GUARDED 5 /* uncached, guarded */ -#define PTE_WIMG_UNCACHED_COHERENT 6 /* uncached, coherentt */ -#define PTE_WIMG_UNCACHED_COHERENT_GUARDED 7 /* uncached, coherent, guarded */ -#define PTE_WIMG_WT_CACHED 8 /* cached, writethru */ -#define PTE_WIMG_WT_CACHED_GUARDED 9 /* cached, writethru, guarded */ -#define PTE_WIMG_WT_CACHED_COHERENT 10 /* cached, writethru, coherent */ -#define PTE_WIMG_WT_CACHED_COHERENT_GUARDED 11 /* cached, writethru, coherent, guarded */ - -#define PTE_WIMG_DEFAULT PTE_WIMG_CB_CACHED_COHERENT -#define PTE_WIMG_IO PTE_WIMG_UNCACHED_COHERENT_GUARDED - /* * A virtual address is decoded into various parts when looking for its PTE */ diff --git a/osfmk/ppc/rtclock.c b/osfmk/ppc/rtclock.c index a7c215da6..2df172cfb 100644 --- a/osfmk/ppc/rtclock.c +++ b/osfmk/ppc/rtclock.c @@ -106,7 +106,7 @@ static struct rtclock { clock_timer_func_t timer_expire; - timer_call_data_t alarm[NCPUS]; + timer_call_data_t alarm_timer; /* debugging */ uint64_t last_abstime[NCPUS]; @@ -190,13 +190,10 @@ timebase_callback( int sysclk_config(void) { - int i; - if (cpu_number() != master_cpu) return(1); - for (i = 0; i < NCPUS; i++) - timer_call_setup(&rtclock.alarm[i], rtclock_alarm_timer, NULL); + timer_call_setup(&rtclock.alarm_timer, rtclock_alarm_timer, NULL); simple_lock_init(&rtclock.lock, ETAP_MISC_RT_CLOCK); @@ -537,7 +534,7 @@ sysclk_setalarm( uint64_t abstime; timespec_to_absolutetime(*deadline, &abstime); - timer_call_enter(&rtclock.alarm[cpu_number()], abstime); + timer_call_enter(&rtclock.alarm_timer, abstime); } /* @@ -753,7 +750,7 @@ rtclock_reset(void) void rtclock_intr( int device, - struct ppc_saved_state *ssp, + struct savearea *ssp, spl_t old_spl) { uint64_t abstime; @@ -775,7 +772,7 @@ rtclock_intr( if ( rtclock_tick_deadline[mycpu] <= abstime ) { clock_deadline_for_periodic_event(rtclock_tick_interval, abstime, &rtclock_tick_deadline[mycpu]); - hertz_tick(USER_MODE(ssp->srr1), ssp->srr0); + hertz_tick(USER_MODE(ssp->save_srr1), ssp->save_srr0); } clock_get_uptime(&abstime); diff --git a/osfmk/ppc/savearea.c b/osfmk/ppc/savearea.c index e96dd0246..1b59e82cc 100644 --- a/osfmk/ppc/savearea.c +++ b/osfmk/ppc/savearea.c @@ -53,6 +53,7 @@ extern struct Saveanchor saveanchor; /* Aliged savearea anchor */ +struct Saveanchor backpocket; /* Emergency saveareas */ unsigned int debsave0 = 0; /* Debug flag */ unsigned int backchain = 0; /* Debug flag */ @@ -67,190 +68,256 @@ unsigned int backchain = 0; /* Debug flag */ * processors. This represents the minimum number required to process a total system failure without * destroying valuable and ever-so-handy system debugging information. * + * We keep two global free lists (the savearea free pool and the savearea free list) and one local + * list per processor. * + * The local lists are small and require no locked access. They are chained using physical addresses + * and no interruptions are allowed when adding to or removing from the list. Also known as the + * qfret list. This list is local to a processor and is intended for use only by very low level + * context handling code. + * + * The savearea free list is a medium size list that is globally accessible. It is updated + * while holding a simple lock. The length of time that the lock is held is kept short. The + * longest period of time is when the list is trimmed. Like the qfret lists, this is chained physically + * and must be accessed with translation and interruptions disabled. This is where the bulk + * of the free entries are located. + * + * The saveareas are allocated from full pages. A pool element is marked + * with an allocation map that shows which "slots" are free. These pages are allocated via the + * normal kernel memory allocation functions. Queueing is with physical addresses. The enqueue, + * dequeue, and search for free blocks is done under free list lock. + * only if there are empty slots in it. + * + * Saveareas that are counted as "in use" once they are removed from the savearea free list. + * This means that all areas on the local qfret list are considered in use. + * + * There are two methods of obtaining a savearea. The save_get function (which is also inlined + * in the low-level exception handler) attempts to get an area from the local qfret list. This is + * done completely without locks. If qfret is exahusted (or maybe just too low) an area is allocated + * from the savearea free list. If the free list is empty, we install the back pocket areas and + * panic. + * + * The save_alloc function is designed to be called by high level routines, e.g., thread creation, + * etc. It will allocate from the free list. After allocation, it will compare the free count + * to the target value. If outside of the range, it will adjust the size either upwards or + * downwards. + * + * If we need to shrink the list, it will be trimmed to the target size and unlocked. The code + * will walk the chain and return each savearea to its pool page. If a pool page becomes + * completely empty, it is dequeued from the free pool list and enqueued (atomic queue + * function) to be released. + * + * Once the trim list is finished, the pool release queue is checked to see if there are pages + * waiting to be released. If so, they are released one at a time. + * + * If the free list needed to be grown rather than shrunken, we will first attempt to recover + * a page from the pending release queue (built when we trim the free list). If we find one, + * it is allocated, otherwise, a page of kernel memory is allocated. This loops until there are + * enough free saveareas. + * */ + + /* - * This routine allocates a save area. It checks if enough are available. - * If not, it allocates upward to the target free count. - * Then, it allocates one and returns it. + * Allocate our initial context save areas. As soon as we do this, + * we can take an interrupt. We do the saveareas here, 'cause they're guaranteed + * to be at least page aligned. */ +void savearea_init(vm_offset_t *addrx) { -struct savearea *save_alloc(void) { /* Reserve a save area */ - - kern_return_t retr; - savectl *sctl; /* Previous and current save pages */ - vm_offset_t vaddr, paddr; - struct savearea *newbaby; - - if(saveanchor.savecount <= (saveanchor.saveneed - saveanchor.saveneghyst)) { /* Start allocating if we drop too far */ - while(saveanchor.savecount < saveanchor.saveneed) { /* Keep adding until the adjustment is done */ - - - retr = kmem_alloc_wired(kernel_map, &vaddr, PAGE_SIZE); /* Find a virtual address to use */ - - if(retr != KERN_SUCCESS) { /* Did we get some memory? */ - panic("Whoops... Not a bit of wired memory left for saveareas\n"); - } - - paddr = pmap_extract(kernel_pmap, vaddr); /* Get the physical */ - - bzero((void *)vaddr, PAGE_SIZE); /* Clear it all to zeros */ - sctl = (savectl *)(vaddr+PAGE_SIZE-sizeof(savectl)); /* Point to the control area of the new page */ - sctl->sac_alloc = sac_empty; /* Mark all entries free */ - sctl->sac_vrswap = (unsigned int)vaddr ^ (unsigned int)paddr; /* Form mask to convert V to R and vice versa */ + savearea_comm *savec, *savec2, *saveprev; + vm_offset_t save, save2, addr; + int i; - sctl->sac_flags |= 0x0000EE00; /* (TEST/DEBUG) */ - - if(!save_queue(paddr)) { /* Add the new ones to the free savearea list */ - panic("Arrgghhhh, time out trying to lock the savearea anchor during upward adjustment\n"); - } - } - } - if (saveanchor.savecount > saveanchor.savemaxcount) - saveanchor.savemaxcount = saveanchor.savecount; + + saveanchor.savetarget = InitialSaveTarget; /* Initial target value */ + saveanchor.saveinuse = 0; /* Number of areas in use */ - newbaby = save_get(); /* Get a savearea and return it */ - if(!((unsigned int)newbaby & 0xFFFFF000)) { /* Whoa... None left??? No, way, no can do... */ - panic("No saveareas?!?!?! No way! Can't happen! Nuh-uh... I'm dead, done for, kaput...\n"); - } + saveanchor.savefree = 0; /* Remember the start of the free chain */ + saveanchor.savefreecnt = 0; /* Remember the length */ + saveanchor.savepoolfwd = (unsigned int *)&saveanchor; /* Remember pool forward */ + saveanchor.savepoolbwd = (unsigned int *)&saveanchor; /* Remember pool backward */ - return newbaby; /* Bye-bye baby... */ - -} + addr = *addrx; /* Make this easier for ourselves */ + save = addr; /* Point to the whole block of blocks */ /* - * This routine releases a save area to the free queue. If after that, we have more than our maximum target, - * we start releasing what we can until we hit the normal target. + * First we allocate the back pocket in case of emergencies */ + for(i=0; i < 8; i++) { /* Initialize the back pocket saveareas */ -void save_release(struct savearea *save) { /* Release a save area */ - - savectl *csave; /* The just released savearea block */ + savec = (savearea_comm *)save; /* Get the control area for this one */ - save_ret(save); /* Return a savearea to the free list */ - - if(saveanchor.savecount > (saveanchor.saveneed + saveanchor.saveposhyst)) { /* Start releasing if we have to many */ - csave = (savectl *)42; /* Start with some nonzero garbage */ - while((unsigned int)csave && (saveanchor.savecount > saveanchor.saveneed)) { /* Keep removing until the adjustment is done */ + savec->sac_alloc = 0; /* Mark it allocated */ + savec->sac_vrswap = 0; /* V=R, so the translation factor is 0 */ + savec->sac_flags = sac_perm; /* Mark it permanent */ + savec->sac_flags |= 0x0000EE00; /* Debug eyecatcher */ + save_queue((savearea *)savec); /* Add page to savearea lists */ + save += PAGE_SIZE; /* Jump up to the next one now */ - csave = save_dequeue(); /* Find and dequeue one that is all empty */ - - if((unsigned int)csave & 1) { /* Did we timeout trying to get the lock? */ - panic("Arrgghhhh, time out trying to lock the savearea anchor during downward adjustment\n"); - return; - } - - if((unsigned int)csave) kmem_free(kernel_map, (vm_offset_t) csave, PAGE_SIZE); /* Release the page if we found one */ - } } - return; - -} - - -save_fake_zone_info(int *count, vm_size_t *cur_size, vm_size_t *max_size, vm_size_t *elem_size, - vm_size_t *alloc_size, int *collectable, int *exhaustable) -{ - *count = saveanchor.saveinuse; - *cur_size = saveanchor.savecount * (PAGE_SIZE / 2); - *max_size = saveanchor.savemaxcount * (PAGE_SIZE / 2); - *elem_size = PAGE_SIZE / 2; - *alloc_size = PAGE_SIZE; - *collectable = 1; - *exhaustable = 0; -} + backpocket = saveanchor; /* Save this for emergencies */ /* - * This routine prints the free savearea block chain for debugging. + * We've saved away the back pocket savearea info, so reset it all and + * now allocate for real */ + saveanchor.savefree = 0; /* Remember the start of the free chain */ + saveanchor.savefreecnt = 0; /* Remember the length */ + saveanchor.saveadjust = 0; /* Set none needed yet */ + saveanchor.savepoolfwd = (unsigned int *)&saveanchor; /* Remember pool forward */ + saveanchor.savepoolbwd = (unsigned int *)&saveanchor; /* Remember pool backward */ -void save_free_dump(void) { /* Dump the free chain */ + for(i=0; i < InitialSaveBloks; i++) { /* Initialize the saveareas */ - unsigned int *dsv, omsr; - savectl *dsc; - - dsv = save_deb(&omsr); /* Get the virtual of the first and disable interrupts */ + savec = (savearea_comm *)save; /* Get the control area for this one */ - while(dsv) { /* Do 'em all */ - dsc=(savectl *)((unsigned int)dsv+4096-sizeof(savectl)); /* Point to the control area */ -// printf("%08X %08X: nxt=%08X; alloc=%08X; flags=%08X\n", dsv, /* Print it all out */ -// ((unsigned int)dsv)^(dsc->sac_vrswap), dsc->sac_next, dsc->sac_alloc, dsc->sac_flags); - dsv=(unsigned int *)(((unsigned int) dsc->sac_next)^(dsc->sac_vrswap)); /* On to the next, virtually */ + savec->sac_alloc = 0; /* Mark it allocated */ + savec->sac_vrswap = 0; /* V=R, so the translation factor is 0 */ + savec->sac_flags = sac_perm; /* Mark it permanent */ + savec->sac_flags |= 0x0000EE00; /* Debug eyecatcher */ + save_queue((savearea *)savec); /* Add page to savearea lists */ + save += PAGE_SIZE; /* Jump up to the next one now */ } - __asm__ volatile ("mtmsr %0" : : "r" (omsr)); /* Restore the interruption mask */ + + *addrx = save; /* Move the free storage lowwater mark */ + +/* + * We now have a free list that has our initial number of entries + * The local qfret lists is empty. When we call save_get below it will see that + * the local list is empty and fill it for us. + * + * It is ok to call save_get_phys here because even though if we are translation on, we are still V=R and + * running with BAT registers so no interruptions. Regular interruptions will be off. Using save_get + * would be wrong if the tracing was enabled--it would cause an exception. + */ + + save2 = (vm_offset_t)save_get_phys(); /* This will populate the local list + and get the first one for the system */ + per_proc_info[0].next_savearea = (unsigned int)save2; /* Tell the exception handler about it */ + +/* + * The system is now able to take interruptions + */ + return; + } + + + /* - * This routine prints the free savearea block chain for debugging. + * Returns a savearea. If the free list needs size adjustment it happens here. + * Don't actually allocate the savearea until after the adjustment is done. */ +struct savearea *save_alloc(void) { /* Reserve a save area */ + + + if(saveanchor.saveadjust) save_adjust(); /* If size need adjustment, do it now */ + + return save_get(); /* Pass the baby... */ +} + + +/* + * This routine releases a save area to the free queue. If after that, we have more than our maximum target, + * we start releasing what we can until we hit the normal target. + */ -void DumpTheSave(struct savearea *save) { /* Dump the free chain */ - unsigned int *r; +void save_release(struct savearea *save) { /* Release a save area */ + + save_ret(save); /* Return a savearea to the free list */ + + if(saveanchor.saveadjust) save_adjust(); /* Adjust the savearea free list and pool size if needed */ - printf("savearea at %08X\n", save); - printf(" srrs: %08X %08X\n", save->save_srr0, save->save_srr1); - printf(" cr, xer, lr: %08X %08X %08X\n", save->save_cr, save->save_xer, save->save_lr); - printf("ctr, dar, dsisr: %08X %08X %08X\n", save->save_ctr, save->save_dar, save->save_dsisr); - printf(" space, copyin: %08X %08X\n", save->save_space, save->save_sr_copyin); - r=&save->save_r0; - printf(" regs: %08X %08X %08X %08X %08X %08X %08X %08X\n", r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7]); - printf(" %08X %08X %08X %08X %08X %08X %08X %08X\n", r[8], r[9], r[10], r[11], r[12], r[13], r[14], r[15]); - printf(" %08X %08X %08X %08X %08X %08X %08X %08X\n", r[16], r[17], r[18], r[19], r[20], r[21], r[22], r[23]); - printf(" %08X %08X %08X %08X %08X %08X %08X %08X\n", r[24], r[25], r[29], r[27], r[28], r[29], r[30], r[31]); - r=(unsigned int *)&save->save_fp0; - printf(" floats: %08X%08X %08X%08X %08X%08X %08X%08X\n", r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7]); - printf(" %08X%08X %08X%08X %08X%08X %08X%08X\n", r[8], r[9], r[10], r[11], r[12], r[13], r[14], r[15]); - printf(" %08X%08X %08X%08X %08X%08X %08X%08X\n", r[16], r[17], r[18], r[19], r[20], r[21], r[22], r[23]); - printf(" %08X%08X %08X%08X %08X%08X %08X%08X\n", r[24], r[25], r[29], r[27], r[28], r[29], r[30], r[31]); - printf(" %08X%08X %08X%08X %08X%08X %08X%08X\n", r[32], r[33], r[34], r[35], r[36], r[37], r[38], r[39]); - printf(" %08X%08X %08X%08X %08X%08X %08X%08X\n", r[40], r[41], r[42], r[43], r[44], r[45], r[46], r[47]); - printf(" %08X%08X %08X%08X %08X%08X %08X%08X\n", r[48], r[49], r[50], r[51], r[52], r[53], r[54], r[55]); - printf(" %08X%08X %08X%08X %08X%08X %08X%08X\n", r[56], r[57], r[58], r[59], r[60], r[61], r[62], r[63]); - r=&save->save_sr0; - printf(" srs: %08X %08X %08X %08X %08X %08X %08X %08X\n", r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7]); - printf(" %08X %08X %08X %08X %08X %08X %08X %08X\n", r[8], r[9], r[10], r[11], r[12], r[13], r[14], r[15]); - printf("prev, phys, act: %08X %08X %08X\n", save->save_prev, save->save_phys, save->save_act); - printf(" flags: %08X\n", save->save_flags); return; + } - - /* - * Dumps out savearea and stack backchains + * Adjusts the size of the free list. Can either release or allocate full pages + * of kernel memory. This can block. + * + * Note that we will only run one adjustment and the amount needed may change + * while we are executing. + * + * Calling this routine is triggered by saveanchor.saveadjust. This value is always calculated just before + * we unlock the saveanchor lock (this keeps it pretty accurate). If the total of savefreecnt and saveinuse + * is within the hysteresis range, it is set to 0. If outside, it is set to the number needed to bring + * the total to the target value. Note that there is a minimum size to the free list (FreeListMin) and if + * savefreecnt falls below that, saveadjust is set to the number needed to bring it to that. */ - -void DumpBackChain(struct savearea *save) { /* Prints out back chains */ - unsigned int *r; - savearea *sv; + +void save_adjust(void) { - if(!backchain) return; - printf("Proceeding back from savearea at %08X:\n", save); - sv=save; - while(sv) { - printf(" curr=%08X; prev=%08X; stack=%08X\n", sv, sv->save_prev, sv->save_r1); - sv=sv->save_prev; + savearea_comm *sctl, *sctlnext, *freepool, *freepage, *realpage; + kern_return_t ret; + + if(saveanchor.saveadjust < 0) { /* Do we need to adjust down? */ + + sctl = (savearea_comm *)save_trim_free(); /* Trim list to the need count, return start of trim list */ + + while(sctl) { /* Release the free pages back to the kernel */ + sctlnext = (savearea_comm *)sctl->save_prev; /* Get next in list */ + kmem_free(kernel_map, (vm_offset_t) sctl, PAGE_SIZE); /* Release the page */ + sctl = sctlnext; /* Chain onwards */ + } + } + else { /* We need more... */ + + if(save_recover()) return; /* If we can recover enough from the pool, return */ + + while(saveanchor.saveadjust > 0) { /* Keep going until we have enough */ + + ret = kmem_alloc_wired(kernel_map, (vm_offset_t *)&freepage, PAGE_SIZE); /* Get a page for free pool */ + if(ret != KERN_SUCCESS) { /* Did we get some memory? */ + panic("Whoops... Not a bit of wired memory left for saveareas\n"); + } + + realpage = (savearea_comm *)pmap_extract(kernel_pmap, (vm_offset_t)freepage); /* Get the physical */ + + bzero((void *)freepage, PAGE_SIZE); /* Clear it all to zeros */ + freepage->sac_alloc = 0; /* Mark all entries taken */ + freepage->sac_vrswap = (unsigned int)freepage ^ (unsigned int)realpage; /* Form mask to convert V to R and vice versa */ + + freepage->sac_flags |= 0x0000EE00; /* Set debug eyecatcher */ + + save_queue((savearea *)realpage); /* Add all saveareas on page to free list */ + } } - return; } +/* + * Fake up information to make the saveareas look like a zone + */ +save_fake_zone_info(int *count, vm_size_t *cur_size, vm_size_t *max_size, vm_size_t *elem_size, + vm_size_t *alloc_size, int *collectable, int *exhaustable) +{ + *count = saveanchor.saveinuse; + *cur_size = (saveanchor.savefreecnt + saveanchor.saveinuse) * (PAGE_SIZE / sac_cnt); + *max_size = saveanchor.savemaxcount * (PAGE_SIZE / sac_cnt); + *elem_size = sizeof(savearea); + *alloc_size = PAGE_SIZE; + *collectable = 1; + *exhaustable = 0; +} diff --git a/osfmk/ppc/savearea.h b/osfmk/ppc/savearea.h index a8b4e180f..554cd2bb8 100644 --- a/osfmk/ppc/savearea.h +++ b/osfmk/ppc/savearea.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,24 +22,344 @@ #ifndef _PPC_SAVEAREA_H_ #define _PPC_SAVEAREA_H_ -#include +#ifndef ASSEMBLER + +#include + +#ifdef __APPLE_API_PRIVATE + +#ifdef MACH_KERNEL_PRIVATE #include +typedef struct savearea_comm { + +/* + * The following fields are common to all saveareas and are used to manage individual + * contexts. + * + * Fields that start with "save" are part of the individual saveareas. Those that + * start with "sac" pertain to the free pool stuff and are valid only on the first slot + * in the page. + */ + + +/* Keep the save_prev, sac_next, and sac_prev in these positions, some assemble code depends upon it to + * match up with fields in saveanchor. + */ + struct savearea *save_prev; /* The address of the previous (or next) savearea */ + unsigned int *sac_next; /* Points to next savearea page that has a free slot - real */ + unsigned int *sac_prev; /* Points to previous savearea page that has a free slot - real */ + unsigned int save_flags; /* Various flags */ + unsigned int save_level; /* Context ID */ + unsigned int save_time[2]; /* Context save time - for debugging or performance */ + struct thread_activation *save_act; /* Associated activation */ + +/* 0x20 */ + + unsigned int sac_vrswap; /* XOR mask to swap V to R or vice versa */ + unsigned int sac_alloc; /* Bitmap of allocated slots */ + unsigned int sac_flags; /* Various flags */ + unsigned int save_misc0; /* Various stuff */ + unsigned int save_misc1; /* Various stuff */ + unsigned int save_misc2; /* Various stuff */ + unsigned int save_misc3; /* Various stuff */ + unsigned int save_misc4; /* Various stuff */ + + unsigned int save_040[8]; /* Fill 32 bytes */ + + /* offset 0x0060 */ +} savearea_comm; +#endif + +#ifdef BSD_KERNEL_PRIVATE +typedef struct savearea_comm { + unsigned int save_000[24]; +} savearea_comm; +#endif + +#if defined(MACH_KERNEL_PRIVATE) || defined(BSD_KERNEL_PRIVATE) +/* + * This type of savearea contains all of the general context. + */ + +typedef struct savearea { + + savearea_comm save_hdr; /* Stuff common to all saveareas */ + + unsigned int save_060[8]; /* Fill 32 bytes */ + /* offset 0x0080 */ + unsigned int save_r0; + unsigned int save_r1; + unsigned int save_r2; + unsigned int save_r3; + unsigned int save_r4; + unsigned int save_r5; + unsigned int save_r6; + unsigned int save_r7; + + /* offset 0x0A0 */ + unsigned int save_r8; + unsigned int save_r9; + unsigned int save_r10; + unsigned int save_r11; + unsigned int save_r12; + unsigned int save_r13; + unsigned int save_r14; + unsigned int save_r15; + + /* offset 0x0C0 */ + unsigned int save_r16; + unsigned int save_r17; + unsigned int save_r18; + unsigned int save_r19; + unsigned int save_r20; + unsigned int save_r21; + unsigned int save_r22; + unsigned int save_r23; + + /* offset 0x0E0 */ + unsigned int save_r24; + unsigned int save_r25; + unsigned int save_r26; + unsigned int save_r27; + unsigned int save_r28; + unsigned int save_r29; + unsigned int save_r30; + unsigned int save_r31; + + /* offset 0x100 */ + unsigned int save_srr0; + unsigned int save_srr1; + unsigned int save_cr; + unsigned int save_xer; + unsigned int save_lr; + unsigned int save_ctr; + unsigned int save_dar; + unsigned int save_dsisr; + + + /* offset 0x120 */ + unsigned int save_vscr[4]; + unsigned int save_fpscrpad; + unsigned int save_fpscr; + unsigned int save_exception; + unsigned int save_vrsave; + + /* offset 0x140 */ + unsigned int save_sr0; + unsigned int save_sr1; + unsigned int save_sr2; + unsigned int save_sr3; + unsigned int save_sr4; + unsigned int save_sr5; + unsigned int save_sr6; + unsigned int save_sr7; + + /* offset 0x160 */ + unsigned int save_sr8; + unsigned int save_sr9; + unsigned int save_sr10; + unsigned int save_sr11; + unsigned int save_sr12; + unsigned int save_sr13; + unsigned int save_sr14; + unsigned int save_sr15; + + /* offset 0x180 */ + unsigned int save_180[8]; + unsigned int save_1A0[8]; + unsigned int save_1C0[8]; + unsigned int save_1E0[8]; + unsigned int save_200[8]; + unsigned int save_220[8]; + unsigned int save_240[8]; + unsigned int save_260[8]; + + /* offset 0x280 */ +} savearea; + + +/* + * This type of savearea contains all of the floating point context. + */ + +typedef struct savearea_fpu { -void save_release(struct savearea *save); /* Release a save area */ + savearea_comm save_hdr; /* Stuff common to all saveareas */ + + unsigned int save_060[8]; /* Fill 32 bytes */ + /* offset 0x0080 */ + double save_fp0; + double save_fp1; + double save_fp2; + double save_fp3; + + double save_fp4; + double save_fp5; + double save_fp6; + double save_fp7; + + double save_fp8; + double save_fp9; + double save_fp10; + double save_fp11; + + double save_fp12; + double save_fp13; + double save_fp14; + double save_fp15; + + double save_fp16; + double save_fp17; + double save_fp18; + double save_fp19; + + double save_fp20; + double save_fp21; + double save_fp22; + double save_fp23; + + double save_fp24; + double save_fp25; + double save_fp26; + double save_fp27; + + double save_fp28; + double save_fp29; + double save_fp30; + double save_fp31; + /* offset 0x180 */ + unsigned int save_180[8]; + unsigned int save_1A0[8]; + unsigned int save_1C0[8]; + unsigned int save_1E0[8]; + unsigned int save_200[8]; + unsigned int save_220[8]; + unsigned int save_240[8]; + unsigned int save_260[8]; + + /* offset 0x280 */ +} savearea_fpu; + + + +/* + * This type of savearea contains all of the vector context. + */ + +typedef struct savearea_vec { + + savearea_comm save_hdr; /* Stuff common to all saveareas */ + + unsigned int save_060[7]; /* Fill 32 bytes */ + unsigned int save_vrvalid; /* Valid registers in saved context */ + + /* offset 0x0080 */ + unsigned int save_vr0[4]; + unsigned int save_vr1[4]; + unsigned int save_vr2[4]; + unsigned int save_vr3[4]; + unsigned int save_vr4[4]; + unsigned int save_vr5[4]; + unsigned int save_vr6[4]; + unsigned int save_vr7[4]; + unsigned int save_vr8[4]; + unsigned int save_vr9[4]; + unsigned int save_vr10[4]; + unsigned int save_vr11[4]; + unsigned int save_vr12[4]; + unsigned int save_vr13[4]; + unsigned int save_vr14[4]; + unsigned int save_vr15[4]; + unsigned int save_vr16[4]; + unsigned int save_vr17[4]; + unsigned int save_vr18[4]; + unsigned int save_vr19[4]; + unsigned int save_vr20[4]; + unsigned int save_vr21[4]; + unsigned int save_vr22[4]; + unsigned int save_vr23[4]; + unsigned int save_vr24[4]; + unsigned int save_vr25[4]; + unsigned int save_vr26[4]; + unsigned int save_vr27[4]; + unsigned int save_vr28[4]; + unsigned int save_vr29[4]; + unsigned int save_vr30[4]; + unsigned int save_vr31[4]; + + /* offset 0x280 */ +} savearea_vec; +#endif /* MACH_KERNEL_PRIVATE || BSD_KERNEL_PRIVATE */ + +#ifdef MACH_KERNEL_PRIVATE + +struct Saveanchor { + +/* + * Note that this force aligned in aligned_data.s and must be in V=R storage. + * Also, all addresses in chains are physical. This structure can only be + * updated with translation and interrupts disabled. This is because it is + * locked during exception processing and if we were to take a PTE miss while the + * lock were held, well, that would be very bad now wouldn't it? + */ + + unsigned int savelock; /* Lock word for savearea free list manipulation */ + unsigned int *savepoolfwd; /* Forward anchor for the free pool */ + unsigned int *savepoolbwd; /* Backward anchor for the free pool */ + volatile unsigned int savefree; /* Anchor for the global free list */ + volatile unsigned int savefreecnt; /* Number of saveareas on global free list */ + volatile int saveadjust; /* If 0 number of saveareas is ok, otherwise number to change (positive means grow, negative means shrink */ + volatile int saveinuse; /* Number of areas in use counting those on the local free list */ + volatile int savetarget; /* Number of savearea's needed */ + int savemaxcount; /* Maximum saveareas ever allocated */ + + +}; + + +#define sac_cnt (4096 / sizeof(savearea)) /* Number of saveareas per page */ +#define sac_empty (0xFFFFFFFF << (32 - sac_cnt)) /* Mask with all entries empty */ +#define sac_perm 0x40000000 /* Page permanently assigned */ +#define sac_permb 1 /* Page permanently assigned - bit position */ + +#define LocalSaveTarget (((8 + sac_cnt - 1) / sac_cnt) * sac_cnt) /* Target for size of local savearea free list */ +#define LocalSaveMin (LocalSaveTarget / 2) /* Min size of local savearea free list before we grow */ +#define LocalSaveMax (LocalSaveTarget * 2) /* Max size of local savearea free list before we trim */ + +#define FreeListMin (2 * LocalSaveTarget * NCPUS) /* Always make sure there are enough to fill local list twice per processor */ +#define SaveLowHysteresis LocalSaveTarget /* The number off from target before we adjust upwards */ +#define SaveHighHysteresis FreeListMin /* The number off from target before we adjust downwards */ +#define InitialSaveAreas (2 * FreeListMin) /* The number of saveareas to make at boot time */ +#define InitialSaveTarget FreeListMin /* The number of saveareas for an initial target. This should be the minimum ever needed. */ +#define InitialSaveBloks (InitialSaveAreas + sac_cnt - 1) / sac_cnt /* The number of savearea blocks to allocate at boot */ + + +void save_release(struct savearea *); /* Release a save area */ struct savectl *save_dequeue(void); /* Find and dequeue one that is all empty */ -unsigned int save_queue(vm_offset_t); /* Add a new savearea block to the free list */ +unsigned int save_queue(struct savearea *); /* Add a new savearea block to the free list */ struct savearea *save_get(void); /* Obtains a savearea from the free list (returns virtual address) */ struct savearea *save_get_phys(void); /* Obtains a savearea from the free list (returns physical address) */ struct savearea *save_alloc(void); /* Obtains a savearea and allocates blocks if needed */ struct savearea *save_cpv(struct savearea *); /* Converts a physical savearea address to virtual */ -unsigned int *save_deb(unsigned int *msr); /* Finds virtual of first free block and disableds interrupts */ void save_ret(struct savearea *); /* Returns a savearea to the free list */ -#if DEBUG -void save_free_dump(void); /* Dump the free chain */ -void DumpTheSave(struct savearea *); /* Prints out a savearea */ -void DumpBackChain(struct savearea *save); /* Dumps a backchain */ -#endif +void save_ret_phys(struct savearea *); /* Returns a savearea to the free list */ +void save_adjust(void); /* Adjust size of the global free list */ +struct savearea_comm *save_trim_freet(void); /* Remove free pages from savearea pool */ -#endif /* _PPC_SAVEAREA_H_ */ +#endif /* MACH_KERNEL_PRIVATE */ +#endif /* __APPLE_API_PRIVATE */ + +#endif /* ndef ASSEMBLER */ +#define SAVattach 0x80000000 /* Savearea has valid context */ +#define SAVrststk 0x00010000 /* Indicates that the current stack should be reset to empty */ +#define SAVsyscall 0x00020000 /* Indicates that the savearea is associated with a syscall */ +#define SAVredrive 0x00040000 /* Indicates that the low-level fault handler associated */ +#define SAVtype 0x0000FF00 /* Shows type of savearea */ +#define SAVtypeshft 8 /* Shift to position type */ +#define SAVempty 0x86 /* Savearea is on free list */ +#define SAVgeneral 0x01 /* Savearea contains general context */ +#define SAVfloat 0x02 /* Savearea contains floating point context */ +#define SAVvector 0x03 /* Savearea contains vector context */ +#endif /* _PPC_SAVEAREA_H_ */ diff --git a/osfmk/ppc/savearea_asm.s b/osfmk/ppc/savearea_asm.s index 791705f69..d3891b019 100644 --- a/osfmk/ppc/savearea_asm.s +++ b/osfmk/ppc/savearea_asm.s @@ -19,6 +19,9 @@ * * @APPLE_LICENSE_HEADER_END@ */ + +#define FPVECDBG 0 + #include #include #include @@ -32,6 +35,7 @@ #include #include #include +#include #include .text @@ -43,19 +47,26 @@ * a guaranteed deadlock. That means we must disable for interrutions * and turn all translation off. * - * Note that the savearea list should NEVER be empty + * We also queue the block to the free pool list. This is a + * circular double linked list. Because this block has no free entries, + * it gets queued to the end of the list + * */ -ENTRY(save_queue,TAG_NO_FRAME_USED) + .align 5 + .globl EXT(save_queue) +LEXT(save_queue) mfsprg r9,2 ; Get the feature flags mr r11,r3 ; Save the block mtcrf 0x04,r9 ; Set the features mfmsr r12 ; Get the MSR - lis r10,HIGH_ADDR(EXT(saveanchor)) ; Get the high part of the anchor + rlwinm r12,r12,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r12,r12,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off + lis r10,hi16(EXT(saveanchor)) ; Get the high part of the anchor andi. r3,r12,0x7FCF ; Turn off all translation and rupts - ori r10,r10,LOW_ADDR(EXT(saveanchor)) ; Bottom half of the anchor + ori r10,r10,lo16(EXT(saveanchor)) ; Bottom half of the anchor bt pfNoMSRirb,sqNoMSR ; No MSR... @@ -67,249 +78,297 @@ sqNoMSR: li r0,loadMSR ; Get the MSR setter SC sc ; Set it sqNoMSRx: + rlwinm. r3,r11,0,0,19 ; (TEST/DEBUG) #if 0 - rlwinm. r3,r11,0,0,19 /* (TEST/DEBUG) */ - bne+ notraceit /* (TEST/DEBUG) */ - BREAKPOINT_TRAP /* (TEST/DEBUG) */ -notraceit: /* (TEST/DEBUG) */ -#else - rlwinm r3,r11,0,0,19 /* Make sure it's clean and tidy */ -#endif - -sqlck: lwarx r9,0,r10 /* Grab the lock value */ - li r8,1 /* Use part of the delay time */ - mr. r9,r9 /* Is it locked? */ - bne- sqlcks /* Yeah, wait for it to clear... */ - stwcx. r8,0,r10 /* Try to seize that there durn lock */ - beq+ sqlckd /* Got it... */ - b sqlck /* Collision, try again... */ - -sqlcks: lwz r9,SVlock(r10) /* Get that lock in here */ - mr. r9,r9 /* Is it free yet? */ - beq+ sqlck /* Yeah, try for it again... */ - b sqlcks /* Sniff away... */ - -sqlckd: isync /* Make sure translation is off */ - lwz r7,SVfree(r10) /* Get the free save area list anchor */ - lwz r6,SVcount(r10) /* Get the total count of saveareas */ - stw r3,SVfree(r10) /* Queue in the new one */ - addi r6,r6,sac_cnt /* Count the ones we are linking in */ - stw r7,SACnext(r3) /* Queue the old first one off of us */ - li r8,0 /* Get a free lock value */ - stw r6,SVcount(r10) /* Save the new count */ - - sync /* Make sure everything is done */ - stw r8,SVlock(r10) /* Unlock the savearea chain */ - - mtmsr r12 /* Restore interrupts and translation */ - isync /* Dump any speculations */ - -#if 0 - lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */ - li r2,0x2201 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */ - sc /* (TEST/DEBUG) */ + bne+ notrapit ; (TEST/DEBUG) + BREAKPOINT_TRAP ; (TEST/DEBUG) +notrapit: ; (TEST/DEBUG) #endif - blr /* Leave... */ - -/* - * This routine will find and remove an empty savearea block from the free list. - * Note really well: we can take NO exceptions of any kind, - * including a PTE miss once the savearea lock is held. That's - * a guaranteed deadlock. That means we must disable for interrutions - * and turn all translation off. - * - * We pass back the virtual address of the one we just released - * or a zero if none to free. - * - * Note that the savearea list should NEVER be empty - */ + li r8,sac_cnt ; Get the number of saveareas per page + mr r4,r11 ; Point to start of chain + li r0,SAVempty ; Get empty marker -ENTRY(save_dequeue,TAG_NO_FRAME_USED) +sqchain: addic. r8,r8,-1 ; Keep track of how many we did + stb r0,SAVflags+2(r4) ; Set empty + addi r9,r4,SAVsize ; Point to the next slot + ble- sqchaindn ; We are done with the chain + stw r9,SAVprev(r4) ; Set this chain + mr r4,r9 ; Step to the next + b sqchain ; Fill the whole block... + .align 5 - mfsprg r9,2 ; Get the feature flags - mfmsr r12 /* Get the MSR */ - mtcrf 0x04,r9 ; Set the features - lis r10,HIGH_ADDR(EXT(saveanchor)) /* Get the high part of the anchor */ - andi. r3,r12,0x7FCF /* Turn off all translation and 'rupts */ - ori r10,r10,LOW_ADDR(EXT(saveanchor)) /* Bottom half of the anchor */ +sqchaindn: mflr r9 ; Save the return address + bl savelock ; Go lock the save anchor - bt pfNoMSRirb,sdNoMSR ; No MSR... + lwz r7,SVfree(r10) ; Get the free save area list anchor + lwz r6,SVfreecnt(r10) ; Get the number of free saveareas - mtmsr r3 ; Translation and all off - isync ; Toss prefetch - b sdNoMSRx + stw r11,SVfree(r10) ; Queue in the new one + addi r6,r6,sac_cnt ; Count the ones we are linking in + stw r7,SAVprev(r4) ; Queue the old first one off of us + stw r6,SVfreecnt(r10) ; Save the new count -sdNoMSR: li r0,loadMSR ; Get the MSR setter SC - sc ; Set it -sdNoMSRx: - -sdqlck: lwarx r9,0,r10 /* Grab the lock value */ - li r8,1 /* Use part of the delay time */ - mr. r9,r9 /* Is it locked? */ - bne- sdqlcks /* Yeah, wait for it to clear... */ - stwcx. r8,0,r10 /* Try to seize that there durn lock */ - beq+ sdqlckd /* Got it... */ - b sdqlck /* Collision, try again... */ - -sdqlcks: lwz r9,SVlock(r10) /* Get that lock in here */ - mr. r9,r9 /* Is it free yet? */ - beq+ sdqlck /* Yeah, try for it again... */ - b sdqlcks /* Sniff away... */ - - -sdqlckd: isync ; Clean out the prefetches - lwz r3,SVfree(r10) /* Get the free save area list anchor */ - la r5,SVfree(r10) /* Remember that the we're just starting out */ - lwz r6,SVcount(r10) /* Get the total count of saveareas for later */ - lis r8,sac_empty>>16 /* Get the empty block indication */ - -sdqchk: lwz r4,SACalloc(r3) /* Get the allocation flags */ - lwz r9,SACflags(r3) /* Get the flags */ - lwz r7,SACnext(r3) /* Point on to the next one */ - andis. r9,r9,hi16(sac_perm) /* Is this permanently allocated? */ - cmplw cr1,r4,r8 /* Does this look empty? */ - bne- sdqperm /* It's permanent, can't release... */ - beq- cr1,sdqfnd /* Yeah, empty... */ - -sdqperm: la r5,SACnext(r3) /* Remember the last guy */ - mr. r3,r7 /* Any more left? */ - bne+ sdqchk /* Yeah... */ - b sdqunlk /* Nope, just go unlock and leave... */ - -sdqfnd: subi r6,r6,sac_cnt /* Back off the number of saveareas in here */ - stw r7,0(r5) /* Dequeue our guy */ - lwz r9,SACvrswap(r3) /* Get addressing conversion */ - stw r6,SVcount(r10) /* Back off the count for this block */ - xor r3,r3,r9 /* Flip to virtual addressing */ - -sdqunlk: li r8,0 /* Get a free lock value */ - sync /* Make sure everything is done */ - stw r8,SVlock(r10) /* Unlock the savearea chain */ - - mtmsr r12 /* Restore interrupts and translation */ - isync /* Dump any speculations */ - -#if 0 - lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */ - li r2,0x2202 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */ - sc /* (TEST/DEBUG) */ + bl saveunlock ; Unlock the list and set the adjust count + + mtlr r9 ; Restore the return + mtmsr r12 ; Restore interrupts and translation + isync ; Dump any speculations + +#if FPVECDBG + mfsprg r2,0 ; (TEST/DEBUG) + lwz r2,next_savearea(r2) ; (TEST/DEBUG) + mr. r2,r2 ; (TEST/DEBUG) + beqlr- ; (TEST/DEBUG) + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x2201 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif - blr /* Leave... */ - - + blr ; Leave... /* - * This routine will obtain a savearea from the free list. + * This routine will obtain a savearea. * Note really well: we can take NO exceptions of any kind, - * including a PTE miss once the savearea lock is held. That's - * a guaranteed deadlock. That means we must disable for interrutions + * including a PTE miss during this process. That's + * a guaranteed deadlock or screwup. That means we must disable for interrutions * and turn all translation off. * * We pass back the virtual address of the one we just obtained * or a zero if none to allocate. * - * Note that the savearea list should NEVER be empty + * First we try the local list. If that is below a threshold, we will + * lock the free list and replenish. + * + * If there are no saveareas in either list, we will install the + * backpocket and choke. + * + * The save_get_phys call assumes that translation and interruptions are + * already off and that the returned address is physical. + * + * Note that save_get_init is used in initial processor startup only. It + * is used because translation is on, but no tables exist yet and we have + * no V=R BAT registers that cover the entire physical memory. + * + * * NOTE!!! NEVER USE R0, R2, or R12 IN HERE THAT WAY WE DON'T NEED A * STACK FRAME IN FPU_SAVE, FPU_SWITCH, VEC_SAVE, OR VEC_SWITCH. */ + + .align 5 + .globl EXT(save_get_init) + +LEXT(save_get_init) + + mfsprg r9,2 ; Get the feature flags + mfmsr r12 ; Get the MSR + rlwinm r12,r12,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r12,r12,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off + mtcrf 0x04,r9 ; Set the features + andi. r3,r12,0x7FCF ; Turn off all translation and interrupts -ENTRY(save_get_phys,TAG_NO_FRAME_USED) + bt pfNoMSRirb,sgiNoMSR ; No MSR... + + mtmsr r3 ; Translation and all off + isync ; Toss prefetch + b sgiGetPhys ; Go get the savearea... - cmplw cr1,r1,r1 ; Set CR1_eq to indicate we want physical address - b csaveget ; Join the common... +sgiNoMSR: li r0,loadMSR ; Get the MSR setter SC + sc ; Set it -ENTRY(save_get,TAG_NO_FRAME_USED) +sgiGetPhys: mflr r11 ; Save R11 (save_get_phys does not use this one) + bl EXT(save_get_phys) ; Get a savearea + mtlr r11 ; Restore return - cmplwi cr1,r1,0 ; Set CR1_ne to indicate we want virtual address + mtmsr r12 ; Restore translation and exceptions + isync ; Make sure about it + blr ; Return... + + .align 5 + .globl EXT(save_get) -csaveget: mfsprg r9,2 ; Get the feature flags +LEXT(save_get) + + crclr cr1_eq ; Clear CR1_eq to indicate we want virtual address + mfsprg r9,2 ; Get the feature flags mfmsr r11 ; Get the MSR - mtcrf 0x04,r9 ; Set the features - lis r10,HIGH_ADDR(EXT(saveanchor)) /* Get the high part of the anchor */ - andi. r3,r11,0x7FCF /* Turn off all translation and 'rupts */ - ori r10,r10,LOW_ADDR(EXT(saveanchor)) /* Bottom half of the anchor */ + rlwinm. r3,r11,0,MSR_EE_BIT,MSR_EE_BIT ; Are interrupts enabled here? + beq+ sgnomess ; Nope, do not mess with fp or vec... + rlwinm r11,r11,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r11,r11,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off + +sgnomess: mtcrf 0x04,r9 ; Set the features + andi. r3,r11,0x7FCF ; Turn off all translation and interrupts bt pfNoMSRirb,sgNoMSR ; No MSR... mtmsr r3 ; Translation and all off isync ; Toss prefetch - b sgNoMSRx + b csaveget sgNoMSR: mr r9,r0 ; Save this li r0,loadMSR ; Get the MSR setter SC sc ; Set it mr r0,r9 ; Restore it -sgNoMSRx: - -sglck: lwarx r9,0,r10 /* Grab the lock value */ - li r7,1 /* Use part of the delay time */ - mr. r9,r9 /* Is it locked? */ - bne- sglcks /* Yeah, wait for it to clear... */ - stwcx. r7,0,r10 /* Try to seize that there durn lock */ - beq+ sglckd /* Got it... */ - b sglck /* Collision, try again... */ - -sglcks: lwz r9,SVlock(r10) /* Get that lock in here */ - mr. r9,r9 /* Is it free yet? */ - beq+ sglck /* Yeah, try for it again... */ - b sglcks /* Sniff away... */ - -sglckd: isync /* Make sure translation is off */ - lwz r8,SVfree(r10) /* Get the head of the save area list */ - lwz r9,SVinuse(r10) /* Get the inuse field */ - - lwz r7,SACalloc(r8) /* Pick up the allocation bits */ - lwz r5,SACvrswap(r8) /* Get real to virtual translation */ - mr. r7,r7 /* Can we use the first one? */ - blt use1st /* Yeah... */ - - andis. r7,r7,0x8000 /* Show we used the second and remember if it was the last */ - addi r3,r8,0x0800 /* Point to the first one */ - b gotsave /* We have the area now... */ - -use1st: andis. r7,r7,0x4000 /* Mark first gone and remember if empty */ - mr r3,r8 /* Set the save area */ - -gotsave: stw r7,SACalloc(r8) /* Put back the allocation bits */ - bne nodqsave /* There's still an empty slot, don't dequeue... */ - - lwz r4,SACnext(r8) /* Get the next in line */ - stw r4,SVfree(r10) /* Dequeue our now empty save area block */ - -nodqsave: lis r6,HIGH_ADDR(SAVattach) /* Show that it is attached for now */ - li r4,0 /* Clear this for the lock */ - stw r6,SAVflags(r3) /* Set the flags to attached */ - addi r9,r9,1 /* Bump up the inuse count */ - stw r4,SAVprev(r3) /* Make sure that backchain is clear */ - stw r9,SVinuse(r10) /* Set the inuse field */ - sync /* Make sure all stores are done */ - stw r4,SVlock(r10) /* Unlock both save and trace areas */ - mtmsr r11 /* Restore translation and exceptions */ - isync /* Make sure about it */ + b csaveget ; Join the common... + + .align 5 + .globl EXT(save_get_phys) + +LEXT(save_get_phys) + + crset cr1_eq ; Clear CR1_ne to indicate we want physical address + +csaveget: mfsprg r9,0 ; Get the per proc + lis r10,hi16(EXT(saveanchor)) ; Get the high part of the anchor + lwz r8,lclfreecnt(r9) ; Get the count + lwz r3,lclfree(r9) ; Get the start of local savearea list + cmplwi r8,LocalSaveMin ; Are we too low? + ori r10,r10,lo16(EXT(saveanchor)) ; Bottom half of the anchor + ble- sglow ; We are too low and need to grow list... + +sgreserve: lis r10,0x5555 ; Get top of empty indication + li r6,0 ; zero value + lwz r4,SAVprev(r3) ; Chain to the next one + stw r6,SAVflags(r3) ; Clear flags + ori r10,r10,0x5555 ; And the bottom + subi r8,r8,1 ; Back down count + stw r10,SAVprev(r3) ; Trash this + stw r10,SAVlevel(r3) ; Trash this + stw r4,lclfree(r9) ; Unchain first savearea + rlwinm r5,r3,0,0,19 ; Back up to first page where SAC is + stw r10,SAVact(r3) ; Trash this + stw r8,lclfreecnt(r9) ; Set new count + + btlr+ cr1_eq ; Return now if physical request + + lwz r5,SACvrswap(r5) ; Get the virtual to real translation + + mtmsr r11 ; Restore translation and exceptions + isync ; Make sure about it -#if 0 - mr r11,r0 /* (TEST/DEBUG) */ - mr r7,r2 /* (TEST/DEBUG) */ - lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */ +#if FPVECDBG +; Note: we do not trace the physical request because this ususally comes from the +; exception vector code + + mr r6,r0 ; (TEST/DEBUG) + mr r7,r2 ; (TEST/DEBUG) + lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) li r2,0x2203 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */ - sc /* (TEST/DEBUG) */ - mr r0,r11 /* (TEST/DEBUG) */ - mr r2,r7 /* (TEST/DEBUG) */ + oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) + mr r0,r6 ; (TEST/DEBUG) + mr r2,r7 ; (TEST/DEBUG) #endif - li r7,0 ; NOTE WELL: we set R7 to zero for vector and float saving code in cswtch.s - beqlr- cr1 ; Return now if we want the physical address - xor r3,r3,r5 /* Get the virtual address */ - blr /* Leave... */ - + xor r3,r3,r5 ; Get the virtual address + blr ; Leave... + +; +; Here is the slow path which is executed when there are not enough in the local list +; + + .align 5 + +sglow: mflr r9 ; Save the return + bl savelock ; Go lock up the anchor + mtlr r9 ; Restore the return + + subfic r5,r8,LocalSaveTarget ; Get the number of saveareas we need to grab to get to target + lwz r9,SVfreecnt(r10) ; Get the number on this list + lwz r8,SVfree(r10) ; Get the head of the save area list + + sub r3,r9,r5 ; Get number left after we swipe enough for local list + srawi r3,r3,31 ; Get 0 if enough or 0xFFFFFFFF if not + andc r4,r5,r3 ; Get number to get if there are enough, 0 otherwise + and r5,r9,r3 ; Get 0 if there are enough, number on list otherwise + or. r5,r4,r5 ; Get the number we will move + beq- sgnofree ; There are none to get... + + mtctr r5 ; Get loop count + mr r6,r8 ; Remember the first in the list + +sgtrimf: bdz sgtfdone ; Count down and branch when we hit 0... + lwz r8,SAVprev(r8) ; Get the next + b sgtrimf ; Keep going... + + .align 5 + +sgtfdone: lwz r7,SAVprev(r8) ; Get the next one + lwz r4,SVinuse(r10) ; Get the in use count + sub r9,r9,r5 ; Count down what we stole + stw r7,SVfree(r10) ; Set the new first in list + add r4,r4,r5 ; Count the ones we just put in the local list as "in use" + stw r9,SVfreecnt(r10) ; Set the new count + mfsprg r9,0 ; Get the per proc + stw r4,SVinuse(r10) ; Set the new in use count + + lwz r4,lclfree(r9) ; Get the old head of list + lwz r3,lclfreecnt(r9) ; Get the old count + stw r6,lclfree(r9) ; Set the new head of the list + add r3,r3,r5 ; Get the new count + stw r4,SAVprev(r8) ; Point to the old head + stw r3,lclfreecnt(r9) ; Set the new count + + mflr r9 ; Save the return + bl saveunlock ; Update the adjust field and unlock + mtlr r9 ; Restore return + b csaveget ; Start over and finally allocate the savearea... + +; +; The local list is below the repopulate threshold and the free list is empty. +; First we check if there are any left in the local list and if so, we allow +; them to be allocated. If not, we release the backpocket list and choke. +; There is nothing more that we can do at this point. Hopefully we stay alive +; long enough to grab some much-needed panic information. +; + +sgnofree: mfsprg r9,0 ; Get the per proc + lwz r8,lclfreecnt(r9) ; Get the count + lwz r3,lclfree(r9) ; Get the start of local savearea list + mr. r8,r8 ; Are there any reserve to get? + + mflr r9 ; Save the return + beq- sgchoke ; No, go choke and die... + bl saveunlock ; Update the adjust field and unlock + mtlr r9 ; Restore return + + mfsprg r9,0 ; Get the per proc again + lwz r3,lclfree(r9) ; Get the start of local savearea list + lwz r8,lclfreecnt(r9) ; Get the count + b sgreserve ; We have some left, dip on in... + +; +; We who are about to die salute you. The savearea chain is messed up or +; empty. Add in a few so we have enough to take down the system. +; + +sgchoke: lis r9,hi16(EXT(backpocket)) ; Get high order of back pocket + ori r9,r9,lo16(EXT(backpocket)) ; and low part + + lwz r8,SVfreecnt(r9) ; Get the new number of free elements + lwz r7,SVfree(r9) ; Get the head of the chain + lwz r6,SVinuse(r10) ; Get total in the old list + + stw r8,SVfreecnt(r10) ; Set the new number of free elements + add r6,r6,r8 ; Add in the new ones + stw r7,SVfree(r10) ; Set the new head of the chain + stw r6,SVinuse(r10) ; Set total in the new list + + lis r0,hi16(Choke) ; Set choke firmware call + li r7,0 ; Get a clear register to unlock + ori r0,r0,lo16(Choke) ; Set the rest of the choke call + li r3,failNoSavearea ; Set failure code + + sync ; Make sure all is committed + stw r7,SVlock(r10) ; Unlock the free list + sc ; System ABEND + + /* * This routine will return a savearea to the free list. @@ -318,181 +377,578 @@ nodqsave: lis r6,HIGH_ADDR(SAVattach) /* Show that it is attached for now */ * a guaranteed deadlock. That means we must disable for interrutions * and turn all translation off. * - * We take a virtual address. + * We take a virtual address for save_ret. For save_ret_phys we + * assume we are already physical/interrupts off and the address is physical. + * + * Here's a tricky bit, and important: + * + * When we trim the list, we NEVER trim the very first one. This is because that is + * the very last one released and the exception exit code will release the savearea + * BEFORE it is done using it. Wouldn't be too good if another processor started + * using it, eh? So for this case, we are safe so long as the savearea stays on + * the local list. (Note: the exit routine needs to do this because it is in the + * process of restoring all context and it needs to keep it until the last second.) * */ -ENTRY(save_ret,TAG_NO_FRAME_USED) +; +; Note: when called from interrupt enabled code, we want to turn off vector and +; floating point because we can not guarantee that the enablement will not change +; while we hold a copy of the MSR. We force it off so that the lazy switcher will +; turn it back on if used. However, we need to NOT change it save_ret or save_get +; is called with interrupts disabled. This is because both of these routine are +; called from within the context switcher and changing the enablement would be +; very, very bad..... (especially from within the lazt switcher) +; -#if 0 - cmplwi r3,0x1000 ; (TEST/DEBUG) - bgt+ notpage0 ; (TEST/DEBUG) - BREAKPOINT_TRAP /* (TEST/DEBUG) */ - -notpage0: rlwinm r6,r3,0,0,19 /* (TEST/DEBUG) */ - rlwinm r7,r3,21,31,31 /* (TEST/DEBUG) */ - lis r8,0x8000 /* (TEST/DEBUG) */ - lwz r6,SACalloc(r6) /* (TEST/DEBUG) */ - srw r8,r8,r7 /* (TEST/DEBUG) */ - and. r8,r8,r6 /* (TEST/DEBUG) */ - beq+ nodoublefret /* (TEST/DEBUG) */ - BREAKPOINT_TRAP /* (TEST/DEBUG) */ - -nodoublefret: /* (TEST/DEBUG) */ -#endif + .align 5 + .globl EXT(save_ret) + +LEXT(save_ret) + + mfmsr r12 ; Get the MSR + rlwinm. r9,r12,0,MSR_EE_BIT,MSR_EE_BIT ; Are interrupts enabled here? + beq+ EXT(save_ret_join) ; Nope, do not mess with fp or vec... + rlwinm r12,r12,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r12,r12,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off + .globl EXT(save_ret_join) + +LEXT(save_ret_join) + crclr cr1_eq ; Clear CR1_ne to indicate we have virtual address mfsprg r9,2 ; Get the feature flags - lwz r7,SAVflags(r3) /* Get the flags */ - rlwinm r6,r3,0,0,19 /* Round back down to the savearea page block */ - andis. r7,r7,HIGH_ADDR(SAVinuse) /* Still in use? */ - mfmsr r12 /* Get the MSR */ - bnelr- /* Still in use, just leave... */ - lwz r5,SACvrswap(r6) /* Get the conversion to real */ - mr r8,r3 ; Save the savearea address + rlwinm r6,r3,0,0,19 ; Round back down to the savearea page block + lwz r5,SACvrswap(r6) ; Get the conversion to real mtcrf 0x04,r9 ; Set the features - lis r10,HIGH_ADDR(EXT(saveanchor)) /* Get the high part of the anchor */ - andi. r3,r12,0x7FCF /* Turn off all translation and 'rupts */ - ori r10,r10,LOW_ADDR(EXT(saveanchor)) /* Bottom half of the anchor */ + mfsprg r9,0 ; Get the per proc + xor r8,r3,r5 ; Get the real address of the savearea + andi. r3,r12,0x7FCF ; Turn off all translation and rupts bt pfNoMSRirb,srNoMSR ; No MSR... mtmsr r3 ; Translation and all off isync ; Toss prefetch - b srNoMSRx + b srcommon + + .align 5 srNoMSR: li r0,loadMSR ; Get the MSR setter SC sc ; Set it -srNoMSRx: - - mfsprg r11,1 /* Get the active save area */ - xor r3,r8,r5 /* Get the real address of the savearea */ - cmplw r11,r3 /* Are we trying to toss the active one? */ - xor r6,r6,r5 /* Make the savearea block real also */ - beq- srbigtimepanic /* This is a no-no... */ - - rlwinm r7,r3,21,31,31 /* Get position of savearea in block */ - lis r8,0x8000 /* Build a bit mask and assume first savearea */ - srw r8,r8,r7 /* Get bit position of do deallocate */ - -srlck: lwarx r11,0,r10 /* Grab the lock value */ - li r7,1 /* Use part of the delay time */ - mr. r11,r11 /* Is it locked? */ - bne- srlcks /* Yeah, wait for it to clear... */ - stwcx. r7,0,r10 /* Try to seize that there durn lock */ - beq+ srlckd /* Got it... */ - b srlck /* Collision, try again... */ - -srlcks: lwz r11,SVlock(r10) /* Get that lock in here */ - mr. r11,r11 /* Is it free yet? */ - beq+ srlck /* Yeah, try for it again... */ - b srlcks /* Sniff away... */ - -srlckd: isync /* Toss preexecutions */ - lwz r11,SACalloc(r6) /* Get the allocation for this block */ - lwz r7,SVinuse(r10) /* Get the in use count */ - or r11,r11,r8 /* Turn on our bit */ - subi r7,r7,1 /* We released one, adjust count */ - cmplw r11,r8 /* Is our's the only one free? */ - stw r7,SVinuse(r10) /* Save out count */ - stw r11,SACalloc(r6) /* Save it out */ - bne+ srtrest /* Nope, then the block is already on the free list */ - - lwz r11,SVfree(r10) /* Get the old head of the free list */ - stw r6,SVfree(r10) /* Point the head at us now */ - stw r11,SACnext(r6) /* Point us at the old last */ - -srtrest: li r8,0 /* Get set to clear the savearea lock */ - sync /* Make sure it's all out there */ - stw r8,SVlock(r10) /* Unlock it */ - mtmsr r12 /* Restore interruptions and translation */ - isync +srNoMSRx: b srcommon ; Join up below... -#if 0 - lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */ + + .align 5 + .globl EXT(save_ret_phys) + +LEXT(save_ret_phys) + + mfsprg r9,0 ; Get the per proc + crset cr1_eq ; Clear CR1_ne to indicate we have physical address + mr r8,r3 ; Save the savearea address + + nop + +srcommon: + li r0,SAVempty ; Get marker for free savearea + lwz r7,lclfreecnt(r9) ; Get the local count + lwz r6,lclfree(r9) ; Get the old local header + addi r7,r7,1 ; Pop up the free count + stw r6,SAVprev(r8) ; Plant free chain pointer + cmplwi r7,LocalSaveMax ; Has the list gotten too long? + stb r0,SAVflags+2(r8) ; Mark savearea free + stw r8,lclfree(r9) ; Chain us on in + stw r7,lclfreecnt(r9) ; Bump up the count + bgt- srtrim ; List is too long, go trim it... + + btlr cr1_eq ; Leave if we were a physical request... + + mtmsr r12 ; Restore translation and exceptions + isync ; Make sure about it + +#if FPVECDBG + lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) li r2,0x2204 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */ - sc /* (TEST/DEBUG) */ + mr r3,r8 ; (TEST/DEBUG) + oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif + blr ; Leave... - blr /* Go away... */ +; +; The local savearea chain has gotten too long. Trim it down to the target. +; Note: never trim the first one, just skip over it. +; -srbigtimepanic: - lis r6,HIGH_ADDR(EXT(panic)) /* First half of panic call */ - lis r3,HIGH_ADDR(EXT(srfreeactive)) /* First half of panic string */ - ori r6,r6,LOW_ADDR(EXT(panic)) /* Second half of panic call */ - ori r3,r3,LOW_ADDR(EXT(srfreeactive)) /* Second half of panic string */ - mtlr r6 /* Get the address of the panic routine */ - mtmsr r12 /* Restore interruptions and translation */ - isync - blrl /* Panic... */ + .align 5 - .data -EXT(srfreeactive): - STRINGD "save_ret: Attempting to release the active savearea!!!!\000" - .text +srtrim: + mr r2,r8 ; Save the guy we are releasing + lwz r8,SAVprev(r8) ; Skip over the first + subi r7,r7,LocalSaveTarget ; Figure out how much to trim + mr r6,r8 ; Save the first one to trim + mr r5,r7 ; Save the number we are trimming + +srtrimming: addic. r7,r7,-1 ; Any left to do? + ble- srtrimmed ; Nope... + lwz r8,SAVprev(r8) ; Skip to the next one + b srtrimming ; Keep going... + + .align 5 +srtrimmed: lis r10,hi16(EXT(saveanchor)) ; Get the high part of the anchor + lwz r7,SAVprev(r8) ; Point to the next one + ori r10,r10,lo16(EXT(saveanchor)) ; Bottom half of the anchor + li r4,LocalSaveTarget ; Set the target count + stw r7,SAVprev(r2) ; Trim stuff leaving the one just released as first + stw r4,lclfreecnt(r9) ; Set the current count + + mflr r9 ; Save the return + bl savelock ; Lock up the anchor + + lwz r3,SVfree(r10) ; Get the old head of the free list + lwz r4,SVfreecnt(r10) ; Get the number of free ones + lwz r7,SVinuse(r10) ; Get the number that are in use + stw r6,SVfree(r10) ; Point to the first trimmed savearea + add r4,r4,r5 ; Add number trimmed to free count + stw r3,SAVprev(r8) ; Chain the old head to the tail of the trimmed guys + sub r7,r7,r5 ; Remove the trims from the in use count + stw r4,SVfreecnt(r10) ; Set new free count + stw r7,SVinuse(r10) ; Set new in use count -/* - * struct savearea *save_cpv(struct savearea *); Converts a physical savearea address to virtual - */ + bl saveunlock ; Set adjust count and unlock the saveanchor + + mtlr r9 ; Restore the return + + btlr+ cr1_eq ; Leave if we were a physical request... + + mtmsr r12 ; Restore translation and exceptions + isync ; Make sure about it + +#if FPVECDBG + lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) + mr r3,r2 ; (TEST/DEBUG) + li r2,0x2205 ; (TEST/DEBUG) + oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) +#endif + blr ; Leave... + + +; +; NOTE: This is the most complicated part of savearea maintainence. +; Expect errors here....... +; +; save_trim_free - this routine will trim the free list down to the target count. +; It trims the list and, if the pool page was fully allocated, puts that page on +; the start of the pool list. +; +; If the savearea being released is the last on a pool page (i.e., all entries +; are released), the page is dequeued from the pool and queued to any other +; found during this scan. Note that this queue is maintained virtually. +; +; When the scan is done, the saveanchor lock is released and the list of +; freed pool pages is returned. + + +; For latency sake we may want to revisit this code. If we are trimming a +; large number of saveareas, we could be disabled and holding the savearea lock +; for quite a while. It may be that we want to break the trim down into parts. +; Possibly trimming the free list, then individually pushing them into the free pool. +; +; This function expects to be called with translation on and a valid stack. +; .align 5 - .globl EXT(save_cpv) + .globl EXT(save_trim_free) -LEXT(save_cpv) +LEXT(save_trim_free) + + subi r1,r1,(FM_ALIGN(16)+FM_SIZE) ; Make space for 4 registers on stack + mfsprg r9,2 ; Get the feature flags + stw r28,FM_SIZE+0(r1) ; Save R28 + mfmsr r12 ; Get the MSR + rlwinm r12,r12,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r12,r12,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off + stw r29,FM_SIZE+4(r1) ; Save R28 + mtcrf 0x04,r9 ; Set the features + stw r30,FM_SIZE+8(r1) ; Save R28 + lis r10,hi16(EXT(saveanchor)) ; Get the high part of the anchor + stw r31,FM_SIZE+12(r1) ; Save R28 + andi. r3,r12,0x7FCF ; Turn off all translation and rupts + ori r10,r10,lo16(EXT(saveanchor)) ; Bottom half of the anchor + mflr r9 ; Save the return + + bt pfNoMSRirb,stNoMSR ; No MSR... + + mtmsr r3 ; Translation and all off + isync ; Toss prefetch + b stNoMSRx - mfmsr r10 ; Get the current MSR - rlwinm r4,r3,0,0,19 ; Round back to the start of the physical savearea block - andi. r9,r10,0x7FEF ; Turn off interrupts and data translation - mtmsr r9 ; Disable DR and EE - isync + .align 5 - lwz r4,SACvrswap(r4) ; Get the conversion to virtual - mtmsr r10 ; Interrupts and DR back on - isync - xor r3,r3,r4 ; Convert to physical - blr +stNoMSR: li r0,loadMSR ; Get the MSR setter SC + sc ; Set it + +stNoMSRx: bl savelock ; Go lock up the anchor + lwz r8,SVadjust(r10) ; How many do we need to clear out? + li r3,0 ; Get a 0 + neg. r8,r8 ; Get the actual we need to toss (adjust is neg if too many) + lwz r7,SVfree(r10) ; Get the first on the free list + bgt+ stneedtrim ; Yeah, we still need it... + + mtlr r9 ; Restore return + stw r3,SVlock(r10) ; Quick unlock (no need for sync or to set adjust, nothing changed) -/* - * This routine will return the virtual address of the first free savearea - * block and disable for interruptions. - * Note really well: this is only for debugging, don't expect it to always work! - * - * We take a virtual address in R3 to save the original MSR, and - * return the virtual address. - * - */ + mtmsr r12 ; Restore translation and exceptions + isync ; Make sure about it + +#if FPVECDBG + lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) + li r2,0x2206 ; (TEST/DEBUG) + oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) +#endif + addi r1,r1,(FM_ALIGN(16)+FM_SIZE) ; Pop stack - have not trashed register so no need to reload + blr ; Leave... -ENTRY(save_deb,TAG_NO_FRAME_USED) + .align 5 + +stneedtrim: mr r6,r7 ; Save the first one + mr r5,r8 ; Save the number we are trimming + + nop + nop + +sttrimming: addic. r5,r5,-1 ; Any left to do? + ble- sttrimmed ; Nope... + lwz r7,SAVprev(r7) ; Skip to the next one + b sttrimming ; Keep going... + + .align 5 + +sttrimmed: lwz r5,SAVprev(r7) ; Get the next one (for new head of free list) + lwz r4,SVfreecnt(r10) ; Get the free count + stw r5,SVfree(r10) ; Set new head + sub r4,r4,r8 ; Calculate the new free count + li r31,0 ; Show we have no free pool blocks yet + cmplwi cr1,r5,0 ; Make sure this is not equal + stw r4,SVfreecnt(r10) ; Set new free count + lis r30,hi16(sac_empty) ; Get what empty looks like + +; +; NOTE: The savearea size must be 640 (0x280). We are doing a divide by shifts and stuff +; here. +; +#if SAVsize != 640 +#error Savearea size is not 640!!!!!!!!!!!! +#endif + +sttoss: beq+ cr1,stdone ; All done now... + + cmplw cr1,r6,r7 ; Have we finished the loop? + + lis r0,0x0044 ; Get top of table + rlwinm r2,r6,0,0,19 ; Back down to the savearea control stuff + ori r0,r0,0x2200 ; Finish shift table + rlwinm r4,r6,25,27,30 ; Get (addr >> 7) & 0x1E (same as twice high nybble) + lwz r5,SACalloc(r2) ; Get the allocation bits + addi r4,r4,1 ; Shift 1 extra + rlwinm r3,r6,25,31,31 ; Get (addr >> 7) & 1 + rlwnm r0,r0,r4,29,31 ; Get partial index + lis r4,lo16(0x8000) ; Get the bit mask + add r0,r0,r3 ; Make the real index + srw r4,r4,r0 ; Get the allocation mask + or r5,r5,r4 ; Free this entry + cmplw r5,r4 ; Is this the only free entry? + lwz r6,SAVprev(r6) ; Chain to the next trimmed savearea + cmplw cr7,r30,r5 ; Does this look empty? + stw r5,SACalloc(r2) ; Save back the allocation bits + beq- stputpool ; First free entry, go put it into the pool... + bne+ cr7,sttoss ; Not an empty block + +; +; We have an empty block. Remove it from the pool list. +; + + lwz r29,SACflags(r2) ; Get the flags + cmplwi cr5,r31,0 ; Is this guy on the release list? + lwz r28,SACnext(r2) ; Get the forward chain + + rlwinm. r0,r29,0,sac_permb,sac_permb ; Is this a permanently allocated area? (also sets 0 needed below) + bne- sttoss ; This is permanent entry, do not try to release... + + lwz r29,SACprev(r2) ; and the previous + beq- cr5,stnot1st ; Not first + lwz r0,SACvrswap(r31) ; Load the previous pool page vr conversion + +stnot1st: stw r28,SACnext(r29) ; Previous guy points to my next + xor r0,r0,r31 ; Make the last guy virtual + stw r29,SACprev(r28) ; Next guy points back to my previous + stw r0,SAVprev(r2) ; Store the old top virtual as my back chain + mr r31,r2 ; My physical is now the head of the chain + b sttoss ; Get the next one... + +; +; A pool block that had no free entries now has one. Stick it on the pool list. +; + + .align 5 + +stputpool: lwz r28,SVpoolfwd(r10) ; Get the first guy on the list + stw r2,SVpoolfwd(r10) ; Put us on the top of the list + stw r28,SACnext(r2) ; We point to the old top + stw r2,SACprev(r28) ; Old top guy points back to us + stw r10,SACprev(r2) ; Our back points to the anchor + b sttoss ; Go on to the next one... + +; +; We are all done. Relocate pool release head, restore all, and go. +; + .align 5 + +stdone: bl saveunlock ; Unlock the saveanchor and set adjust field + + mr. r3,r31 ; Move release chain and see if there are any + li r5,0 ; Assume either V=R or no release chain + beq- stnorel ; Nothing to release... + lwz r5,SACvrswap(r31) ; Get the vr conversion + +stnorel: mtmsr r12 ; Restore translation and exceptions + isync ; Make sure about it + + mtlr r9 ; Restore the return + + lwz r28,FM_SIZE+0(r1) ; Restore R28 + lwz r29,FM_SIZE+4(r1) ; Restore R29 + lwz r30,FM_SIZE+8(r1) ; Restore R30 + lwz r31,FM_SIZE+12(r1) ; Restore R31 + addi r1,r1,(FM_ALIGN(16)+FM_SIZE) ; Pop the stack + xor r3,r3,r5 ; Convert release chain address to virtual + +#if FPVECDBG + lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) + li r2,0x2207 ; (TEST/DEBUG) + oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) +#endif + blr ; Return... + +; +; save_recover - here we scan the free pool and see if we can get +; enough free saveareas to hit target. +; +; If we empty a pool block, remove it from the pool list +; +; + + .align 5 + .globl EXT(save_recover) + +LEXT(save_recover) mfsprg r9,2 ; Get the feature flags - mfmsr r12 /* Get the MSR */ - lis r10,HIGH_ADDR(EXT(saveanchor)) /* Get the high part of the anchor */ + mfmsr r12 ; Get the MSR + rlwinm r12,r12,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r12,r12,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off mtcrf 0x04,r9 ; Set the features - stw r12,0(r3) /* Save it */ - andi. r3,r12,0x7FCF /* Turn off all translation and 'rupts */ - ori r10,r10,LOW_ADDR(EXT(saveanchor)) /* Bottom half of the anchor */ + lis r10,hi16(EXT(saveanchor)) ; Get the high part of the anchor + andi. r3,r12,0x7FCF ; Turn off all translation and rupts + ori r10,r10,lo16(EXT(saveanchor)) ; Bottom half of the anchor + mflr r9 ; Save the return - bt pfNoMSRirb,sdbNoMSR ; No MSR... + bt pfNoMSRirb,srcNoMSR ; No MSR... mtmsr r3 ; Translation and all off isync ; Toss prefetch - b sdbNoMSRx + b srcNoMSRx -sdbNoMSR: li r0,loadMSR ; Get the MSR setter SC + .align 5 + +srcNoMSR: li r0,loadMSR ; Get the MSR setter SC sc ; Set it -sdbNoMSRx: + +srcNoMSRx: bl savelock ; Go lock up the anchor - lwz r3,SVfree(r10) /* Get the physical first in list */ - andi. r11,r12,0x7FFF /* Clear only interruption */ - lwz r5,SACvrswap(r3) /* Get the conversion to virtual */ - mtmsr r11 /* Restore DAT but not INT */ - xor r3,r3,r5 /* Make it virtual */ - isync - blr + lwz r8,SVadjust(r10) ; How many do we need to clear get? + li r3,0 ; Get a 0 + mr. r8,r8 ; Do we need any? + bgt+ srcneedmore ; Yeah, we still need it... + + mtlr r9 ; Restore return + stw r3,SVlock(r10) ; Quick unlock (no need for sync or to set adjust, nothing changed) + + mtmsr r12 ; Restore translation and exceptions + isync ; Make sure about it + +#if FPVECDBG + lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) + li r2,0x2208 ; (TEST/DEBUG) + oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) +#endif + blr ; Leave... + + .align 5 + +srcneedmore: + mr r6,r10 ; Start at pool anchor + cmplwi cr1,r10,0 ; Make sure we start as not equal + lwz r7,SVfreecnt(r10) ; Get the current free count + +srcnpool: lwz r6,SACnext(r6) ; Point to the next one + cmplw r6,r10 ; Have we wrapped? + beq- srcdone ; Yes, did not have enough... + + lwz r5,SACalloc(r6) ; Pick up the allocation for this pool block + +; +; NOTE: The savearea size must be 640 (0x280). We are doing a multiply by shifts and add. +; offset = (index << 9) + (index << 7) +; +#if SAVsize != 640 +#error Savearea size is not 640!!!!!!!!!!!! +#endif + +srcnext: beq- cr1,srcdone ; We have no more to get... + + lis r3,0x8000 ; Get the top bit on + cntlzw r4,r5 ; Find a free slot + addi r7,r7,1 ; Bump up the free count + srw r3,r3,r4 ; Make a mask + slwi r0,r4,7 ; First multiply by 128 + subi r8,r8,1 ; Decrement the need count + slwi r2,r4,9 ; Then multiply by 512 + andc. r5,r5,r3 ; Clear out the "free" bit + add r2,r2,r0 ; Sum to multiply by 640 + + stw r5,SACalloc(r6) ; Set new allocation bits + + add r2,r2,r6 ; Get the actual address of the savearea + lwz r3,SVfree(r10) ; Get the head of the chain + cmplwi cr1,r8,0 ; Do we actually need any more? + stw r2,SVfree(r10) ; Push ourselves in the front + stw r3,SAVprev(r2) ; Chain the rest of the list behind + + bne+ srcnext ; The pool block is not empty yet, try for another... + + lwz r2,SACnext(r6) ; Get the next pointer + lwz r3,SACprev(r6) ; Get the previous pointer + stw r3,SACprev(r2) ; The previous of my next points to my previous + stw r2,SACnext(r3) ; The next of my previous points to my next + bne+ cr1,srcnpool ; We still have more to do... + +srcdone: stw r7,SVfreecnt(r10) ; Set the new free count + bl saveunlock ; Unlock the save and set adjust field + + mtlr r9 ; Restore the return + mtmsr r12 ; Restore translation and exceptions + isync ; Make sure about it + +#if FPVECDBG + lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) + li r2,0x2209 ; (TEST/DEBUG) + oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) +#endif + blr ; Leave... + +; +; Here is where we lock the saveanchor lock +; We assume R10 points to the saveanchor +; We trash R7 and R3 +; + + .align 5 + +savelock: lwarx r7,0,r10 ; Grab the lock value + li r3,1 ; Use part of the delay time + mr. r7,r7 ; Is it locked? */ + bne- sllcks ; Yeah, wait for it to clear... + stwcx. r3,0,r10 ; Try to seize that there durn lock + beq+ sllckd ; Got it... + b savelock ; Collision, try again... + + .align 5 + +sllcks: lwz r7,SVlock(r10) ; Get that lock in here + mr. r7,r7 ; Is it free yet? + beq+ savelock ; Yeah, try for it again... + b sllcks ; Sniff away... + + nop ; Force isync to last in ifetch buffer + nop + nop + +sllckd: isync ; Make sure translation is off + blr ; Return.... + + +; +; This is the common routine that sets the saveadjust field and unlocks the savearea +; anchor. +; +; Note that we can not use R9 here because we use it to save the LR across the call. +; Also, R10 is assumed to point to the saveanchor. R3 is also reserved. +; + + .align 5 + +saveunlock: + lwz r6,SVfreecnt(r10) ; and the number on the free list + lwz r5,SVinuse(r10) ; Pick up the in use count + cmplwi r6,FreeListMin ; Do we have at least the minimum? + blt- sutooshort ; Do not have minumum.... + lwz r7,SVtarget(r10) ; Get the target + add r6,r6,r5 ; Get the total number of saveareas + addi r5,r7,-SaveLowHysteresis ; Find bottom + sub r5,r6,r5 ; Make everything below hysteresis negative + sub r7,r7,r6 ; Get the distance from the target + rlwinm r5,r5,0,0,31 ; Clear negative bit + addi r5,r5,-(SaveLowHysteresis + SaveHighHysteresis + 1) ; Subtract full hysteresis range + srawi r5,r5,31 ; Get 0xFFFFFFFF if outside range or 0 if inside + and r7,r7,r5 ; Get 0 if in range or distance to target if not + + li r8,0 ; Set a clear value + stw r7,SVadjust(r10) ; Set the adjustment value + + sync ; Make sure everything is done + stw r8,SVlock(r10) ; Unlock the savearea chain + blr + .align 5 +sutooshort: subfic r6,r6,FreeListMin ; Get the number needed to hit minimum + li r8,0 ; Set a clear value + stw r6,SVadjust(r10) ; Set the adjustment value + + sync ; Make sure everything is done + stw r8,SVlock(r10) ; Unlock the savearea chain + blr + + + +/* + * struct savearea *save_cpv(struct savearea *); Converts a physical savearea address to virtual + */ + .align 5 + .globl EXT(save_cpv) + +LEXT(save_cpv) + + mfmsr r10 ; Get the current MSR + rlwinm r10,r10,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + rlwinm r10,r10,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off + rlwinm r4,r3,0,0,19 ; Round back to the start of the physical savearea block + andi. r9,r10,0x7FEF ; Turn off interrupts and data translation + mtmsr r9 ; Disable DR and EE + isync + + lwz r4,SACvrswap(r4) ; Get the conversion to virtual + mtmsr r10 ; Interrupts and DR back on + isync + xor r3,r3,r4 ; Convert to physical + blr diff --git a/osfmk/ppc/screen.h b/osfmk/ppc/screen.h deleted file mode 100644 index dd81dadb3..000000000 --- a/osfmk/ppc/screen.h +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * @OSF_COPYRIGHT@ - */ -/* - * Mach Operating System - * Copyright (c) 1991,1990,1989 Carnegie Mellon University - * All Rights Reserved. - * - * 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 Mellon - * the rights to redistribute these changes. - */ -/* - */ -/* - * File: screen.h - * Author: Alessandro Forin, Carnegie Mellon University - * Date: 9/90 - * - * Definitions for the Generic Screen Driver. - */ - -#ifndef _SCREEN_H_ -#define _SCREEN_H_ - -/* - * Most of these structures are defined so that the - * resulting structure mapped to user space appears - * to be compatible with the one used by the DEC X - * servers (pm_info..). Keep it that way and the - * X servers will keep on running. - */ - -/* - * Generic structures and defines - */ - -/* colors */ -typedef struct { - unsigned short red; - unsigned short green; - unsigned short blue; -} color_map_t; - -typedef struct { - short unused; - unsigned short index; - color_map_t value; -} color_map_entry_t; - -typedef struct { - unsigned int Bg_rgb[3]; - unsigned int Fg_rgb[3]; -} cursor_color_t; - -/* generic input event */ -typedef struct { - short x; /* x position */ - short y; /* y position */ - unsigned int time; /* 1 millisecond units */ - - unsigned char type; /* button up/down/raw or motion */ -# define EVT_BUTTON_UP 0 -# define EVT_BUTTON_DOWN 1 -# define EVT_BUTTON_RAW 2 -# define EVT_PTR_MOTION 3 - - unsigned char key; /* the key (button only) */ -# define KEY_LEFT_BUTTON 1 -# define KEY_MIDDLE_BUTTON 2 -# define KEY_RIGHT_BUTTON 3 -# define KEY_TBL_LEFT_BUTTON 0 -# define KEY_TBL_FRONT_BUTTON 1 -# define KEY_TBL_RIGHT_BUTTON 2 -# define KEY_TBL_BACK_BUTTON 3 - - unsigned char index; /* which instance of device */ - - unsigned char device; /* which device */ -# define DEV_NULL 0 -# define DEV_MOUSE 1 -# define DEV_KEYBD 2 -# define DEV_TABLET 3 -# define DEV_AUX 4 -# define DEV_CONSOLE 5 -# define DEV_KNOB 8 -# define DEV_JOYSTICK 9 - -} screen_event_t; - -/* timed coordinate info */ -typedef struct { - unsigned int time; - short x, y; -} screen_timed_point_t; - -/* queue of input events, and ring of mouse motions track */ -typedef struct { - screen_event_t *events; - unsigned int q_size; - unsigned int q_head; - unsigned int q_tail; - unsigned long timestamp; - screen_timed_point_t *track; - unsigned int t_size; - unsigned int t_next; -} screen_evque_t; - -/* mouse/cursor position */ -typedef struct { - short x; - short y; -} screen_point_t; - -/* mouse motion bounding boxes */ -typedef struct { - short bottom; - short right; - short left; - short top; -} screen_rect_t; - -/* - * Here it is, each field is marked as - * - * Kset : kernel sets it unconditionally - * Kuse : kernel uses it, safely - * Kdep : kernel might depend on it - */ -typedef struct { - screen_evque_t evque; /* Kset, Kuse */ - short mouse_buttons; /* Kset */ - screen_point_t xx3 /*tablet*/; - short xx4 /*tswitches*/; - screen_point_t cursor; /* Kset */ - short row; /* Kdep */ - short col; /* Kdep */ - short max_row; /* Kdep */ - short max_col; /* Kdep */ - short max_x; /* Kset */ - short max_y; /* Kset */ - short max_cur_x; /* Kdep */ - short max_cur_y; /* Kdep */ - int version; /* Kset */ - union { - struct { - unsigned char * bitmap; /* Kset */ - short * x16 /*scanmap*/; - short * x17 /*cursorbits*/; - short * x18 /*pmaddr*/; - unsigned char * planemask; /* Kset */ - } pm; - struct { - int x15 /* flags */; - int * gram /* Kset */; - int * rb_addr /* Kset */; - int rb_phys /* Kset */; - int rb_size /* Kset */; - } gx; - } dev_dep_1; - screen_point_t mouse_loc; /* Kdep */ - screen_rect_t mouse_box; /* Kdep */ - short mouse_threshold;/* Kuse */ - short mouse_scale; /* Kuse */ - short min_cur_x; /* Kdep */ - short min_cur_y; /* Kdep */ - union { - struct { - int x26 /*dev_type*/; - char * x27 /*framebuffer*/; - char * x28 /*volatile struct bt459 *bt459*/; - int x29 /*slot*/; - char cursor_sprite[1024];/* Kset */ - unsigned char Bg_color[3]; /* Kset */ - unsigned char Fg_color[3]; /* Kset */ - int tablet_scale_x; /* Kuse */ - int tablet_scale_y; /* Kuse */ - } pm; - struct { - char * gxo /* Kset */; - char stamp_width /* Kset */; - char stamp_height /* Kset */; - char nplanes /* Kset */; - char x27_4 /* n10_present */; - char x28_1 /* dplanes */; - char zplanes /* Kset */; - char zzplanes /* Kset */; - unsigned char cursor_sprite[1024] /* Kuse */; - char x285_0 /* padding for next, which was int */; - unsigned char Fg_color[4] /* Kuse */; - unsigned char Bg_color[4] /* Kuse */; - unsigned short cmap_index /* Kuse */; - unsigned short cmap_count /* Kuse */; - unsigned int colormap[256] /* Kuse */; - int * stic_dma_rb /* Kset */; - int * stic_reg /* Kset */; - int ptpt_phys /* Kdep */; - int ptpt_size /* Kdep */; - int * ptpt_pgin /* Kset */; - } gx; - } dev_dep_2; - short frame_scanline_width; /* in pixels, Kset */ - short frame_height; /* in scanlines, Kset */ - /* - * Event queues are allocated right after that - */ -#define MAX_EVENTS 64 -#define MAX_TRACK 100 - screen_event_t event_queue[MAX_EVENTS]; /* Kset */ - screen_timed_point_t point_track[MAX_TRACK]; /* Kset */ - /* - * Some like it hot - */ - unsigned int event_id; - int interrupt_info; -} user_info_t; - - -/* - * Screen get_status codes and arguments - */ -#include - - /* Get size (and offset) of mapped info */ -#define SCREEN_GET_OFFSETS _IOR('q', 6, unsigned **) - - /* Get screen status flags */ -#define SCREEN_STATUS_FLAGS _IOR('q', 22, int *) -# define MONO_SCREEN 0x01 -# define COLOR_SCREEN 0x02 -# define SCREEN_BEING_UPDATED 0x04 - -/* - * Screen set_status codes and arguments - */ - - /* start/stop screen saver, control fading interval */ -#define SCREEN_FADE _IOW('q', 114, int) /* fade screen */ -# define NO_FADE -1 - - /* Turn video on/off manually */ -#define SCREEN_ON _IO('q', 10) -#define SCREEN_OFF _IO('q', 11) - - /* Fixup pointers inside mapped info structure */ -#define SCREEN_ADJ_MAPPED_INFO _IOR('q', 1, user_info_t *) - - /* Initialize anything that needs to, hw-wise */ -#define SCREEN_INIT _IO('q', 4) - - /* Position cursor to a specific spot */ -#define SCREEN_SET_CURSOR _IOW('q', 2, screen_point_t) - - /* Load Bg/Fg colors for cursor */ -#define SCREEN_SET_CURSOR_COLOR _IOW('q', 3, cursor_color_t) - - /* Load cursor sprite, small cursor form */ -typedef unsigned short cursor_sprite_t[32]; - -#define SCREEN_LOAD_CURSOR _IOW('q', 7, cursor_sprite_t) - - /* Load cursor sprite, large 64x64 cursor form */ -typedef char cursor_sprite_long_t[1024]; - -#define SCREEN_LOAD_CURSOR_LONG _IOW('q', 13, cursor_sprite_long_t) - - /* Modify a given entry in the color map (VDAC) */ -#define SCREEN_SET_CMAP_ENTRY _IOW('q', 12, color_map_entry_t) - - /* Return some other information about hardware (optional) */ -typedef struct { - int frame_width; - int frame_height; - int frame_visible_width; - int frame_visible_height; -} screen_hw_info_t; -#define SCREEN_HARDWARE_INFO _IOR('q', 23, screen_hw_info_t) - - /* Screen-dependent, unspecified (and despised) */ -#define SCREEN_HARDWARE_DEP _IO('q', 24) - -#endif /* _SCREEN_H_ */ diff --git a/osfmk/ppc/serial_console.c b/osfmk/ppc/serial_console.c index 7c31eaa3c..2e5768c74 100644 --- a/osfmk/ppc/serial_console.c +++ b/osfmk/ppc/serial_console.c @@ -109,8 +109,7 @@ void cnputcusr(char c) { /* Echo input character directly */ unsigned int cpu; - if (cpu_data[master_cpu].active_thread) cpu = cpu_number(); /* If we're started up, use the current CPU */ - else cpu = master_cpu; /* Otherwise use the master_cpu */ + cpu = cpu_number(); hw_atomic_add(&debugger_holdoff[cpu], 1); /* Don't allow debugger entry just now (this is a HACK) */ @@ -140,8 +139,7 @@ cnputc(char c) return; /* If printing is disabled, bail... */ } - if (cpu_data[master_cpu].active_thread) cpu = cpu_number(); /* If we're started up, use the current CPU */ - else cpu = master_cpu; /* Otherwise use the master_cpu */ + cpu = cpu_number(); hw_atomic_add(&debugger_holdoff[cpu], 1); /* Don't allow debugger entry just now (this is a HACK) */ diff --git a/osfmk/ppc/spec_reg.h b/osfmk/ppc/spec_reg.h new file mode 100644 index 000000000..93b670fae --- /dev/null +++ b/osfmk/ppc/spec_reg.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * @OSF_COPYRIGHT@ + */ + +#ifndef _PPC_SPEC_REG_H_ +#define _PPC_SPEC_REG_H_ + +/* Defines for PVRs */ +#define PROCESSOR_VERSION_601 1 +#define PROCESSOR_VERSION_603 3 +#define PROCESSOR_VERSION_604 4 +#define PROCESSOR_VERSION_603e 6 +#define PROCESSOR_VERSION_750 8 +#define PROCESSOR_VERSION_750FX 0x7000 /* ? */ +#define PROCESSOR_VERSION_604e 9 +#define PROCESSOR_VERSION_604ev 10 /* ? */ +#define PROCESSOR_VERSION_7400 12 /* ? */ +#define PROCESSOR_VERSION_7410 0x800C /* ? */ +#define PROCESSOR_VERSION_7450 0x8000 /* ? */ +#define PROCESSOR_VERSION_7455 0x8001 /* ? */ + +#endif /* _PPC_SPEC_REG_H_ */ diff --git a/osfmk/ppc/start.s b/osfmk/ppc/start.s index 21a82ccdc..12714d551 100644 --- a/osfmk/ppc/start.s +++ b/osfmk/ppc/start.s @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -54,6 +55,7 @@ #define PROCESSOR_VERSION_604 4 #define PROCESSOR_VERSION_603e 6 #define PROCESSOR_VERSION_750 8 +#define PROCESSOR_VERSION_750FX 0x7000 /* ? */ #define PROCESSOR_VERSION_604e 9 #define PROCESSOR_VERSION_604ev 10 /* ? */ #define PROCESSOR_VERSION_7400 12 /* ? */ @@ -488,6 +490,40 @@ init750CX: b init750 ; Join common... +; 750FX + +init750FX: + bf firstBoot, init750FXnb + mfspr r11, hid1 + stw r11, pfHID1(r30) ; Save the HID1 value + b init750 + +init750FXnb: + lwz r13, pfHID0(r30) ; Get HID0 + lwz r11, pfHID1(r30) ; Get HID1 + + rlwinm. r0, r11, 0, hid1ps, hid1ps ; Isolate the hid1ps bit + beq init750FXnb2 ; Clear BTIC if hid1ps set + rlwinm r13, r13, 0, btic+1, btic-1 ; Clear the BTIC bit + +init750FXnb2: + sync + mtspr hid0, r13 ; Set the HID + isync + sync + + rlwinm r12, r11, 0, hid1ps+1, hid1ps-1 ; Select PLL0 + mtspr hid1, r12 ; Restore PLL config + mftb r13 ; Wait 5000 ticks (> 200 us) + +init750FXnbloop: + mftb r14 + sub r14, r14, r13 + cmpli cr0, r14, 5000 + ble init750FXnbloop + mtspr hid1, r11 ; Select the desired PLL + blr + ; 7400 init7400: bf firstBoot,i7400nb ; Do different if not initial boot... @@ -536,7 +572,18 @@ i7400nb: isync sync blr - + +; 7400 (ver 2.0 - ver 2.7) + +init7400v2_7: + bf firstBoot, init7400 + mfspr r13, hid0 ; Get the HID0 + ori r13, r13, nopdstm ; ? + mtspr hid0, r13 ; Set the HID0 + isync + sync + b init7400 + ; 7410 ; Note that this is the same as 7400 except we initialize the l2cr2 register @@ -810,7 +857,36 @@ processor_types: .long 32*1024 .long 32*1024 +; 750FX (generic) + .align 2 + .long 0xFFFF0000 ; All revisions + .short PROCESSOR_VERSION_750FX + .short 0 + .long pfFloat | pfCanSleep | pfCanNap | pfCanDoze | pfSlowNap | pfNoMuMMCK | pfL1i | pfL1d | pfL2 + .long init750FX + .long CPU_SUBTYPE_POWERPC_750 + .long 105 + .long 90 + .long 32 + .long 32*1024 + .long 32*1024 + +; 7400 (ver 2.0 - ver 2.7) + + .align 2 + .long 0xFFFFFFF8 ; All revisions + .short PROCESSOR_VERSION_7400 + .short 0x0200 + .long pfFloat | pfAltivec | pfSMPcap | pfCanSleep | pfCanNap | pfCanDoze | pfThermal | pfL1i | pfL1d | pfL1fa | pfL2 | pfL2fa + .long init7400v2_7 + .long CPU_SUBTYPE_POWERPC_7400 + .long 105 + .long 90 + .long 32 + .long 32*1024 + .long 32*1024 + ; 7400 (generic) .align 2 @@ -862,7 +938,7 @@ processor_types: .long 0xFFFFFF00 ; Just revisions 1.xx .short PROCESSOR_VERSION_7450 .short 0x0100 - .long pfFloat | pfAltivec | pfSMPcap | pfCanSleep | pfNoMSRir | pfLClck | pfL1i | pfL1d | pfL2 | pfL2fa | pfL2i | pfL3 | pfL3fa + .long pfFloat | pfAltivec | pfSMPcap | pfCanSleep | pfNoMSRir | pfNoL2PFNap | pfLClck | pfL1i | pfL1d | pfL2 | pfL2fa | pfL2i | pfL3 | pfL3fa .long init7450 .long CPU_SUBTYPE_POWERPC_7450 .long 105 @@ -877,7 +953,7 @@ processor_types: .long 0xFFFFFFFF ; Just revision 2.0 .short PROCESSOR_VERSION_7450 .short 0x0200 - .long pfFloat | pfAltivec | pfSMPcap | pfCanSleep | pfNoMSRir | pfLClck | pfL1i | pfL1d | pfL2 | pfL2fa | pfL2i | pfL3 | pfL3fa + .long pfFloat | pfAltivec | pfSMPcap | pfCanSleep | pfNoMSRir | pfNoL2PFNap | pfLClck | pfL1i | pfL1d | pfL2 | pfL2fa | pfL2i | pfL3 | pfL3fa .long init7450 .long CPU_SUBTYPE_POWERPC_7450 .long 105 @@ -892,7 +968,7 @@ processor_types: .long 0xFFFF0000 ; All other revisions .short PROCESSOR_VERSION_7450 .short 0 - .long pfFloat | pfAltivec | pfSMPcap | pfCanSleep | pfWillNap | pfNoMSRir | pfLClck | pfL1i | pfL1d | pfL2 | pfL2fa | pfL2i | pfL3 | pfL3fa + .long pfFloat | pfAltivec | pfSMPcap | pfCanSleep | pfWillNap | pfNoMSRir | pfNoL2PFNap | pfLClck | pfL1i | pfL1d | pfL2 | pfL2fa | pfL2i | pfL3 | pfL3fa .long init7450 .long CPU_SUBTYPE_POWERPC_7450 .long 105 @@ -907,7 +983,7 @@ processor_types: .long 0xFFFFFF00 ; Just revisions 1.xx .short PROCESSOR_VERSION_7455 .short 0x0100 - .long pfFloat | pfAltivec | pfSMPcap | pfCanSleep | pfNoMSRir | pfLClck | pfL1i | pfL1d | pfL2 | pfL2fa | pfL2i | pfL3 | pfL3fa + .long pfFloat | pfAltivec | pfSMPcap | pfCanSleep | pfNoMSRir | pfNoL2PFNap | pfLClck | pfL1i | pfL1d | pfL2 | pfL2fa | pfL2i | pfL3 | pfL3fa .long init745X .long CPU_SUBTYPE_POWERPC_7450 .long 105 @@ -922,7 +998,7 @@ processor_types: .long 0xFFFFFFFF ; Just revision 2.0 .short PROCESSOR_VERSION_7455 .short 0x0200 - .long pfFloat | pfAltivec | pfSMPcap | pfCanSleep | pfWillNap | pfNoMSRir | pfLClck | pfL1i | pfL1d | pfL2 | pfL2fa | pfL2i | pfL3 | pfL3fa + .long pfFloat | pfAltivec | pfSMPcap | pfCanSleep | pfWillNap | pfNoMSRir | pfNoL2PFNap | pfLClck | pfL1i | pfL1d | pfL2 | pfL2fa | pfL2i | pfL3 | pfL3fa .long init745X .long CPU_SUBTYPE_POWERPC_7450 .long 105 @@ -937,7 +1013,7 @@ processor_types: .long 0xFFFF0000 ; All other revisions .short PROCESSOR_VERSION_7455 .short 0 - .long pfFloat | pfAltivec | pfSMPcap | pfCanSleep | pfCanNap | pfNoMSRir | pfLClck | pfL1i | pfL1d | pfL2 | pfL2fa | pfL2i | pfL3 | pfL3fa + .long pfFloat | pfAltivec | pfSMPcap | pfCanSleep | pfCanNap | pfNoMSRir | pfNoL2PFNap | pfLClck | pfL1i | pfL1d | pfL2 | pfL2fa | pfL2i | pfL3 | pfL3fa .long init745X .long CPU_SUBTYPE_POWERPC_7450 .long 105 diff --git a/osfmk/ppc/status.c b/osfmk/ppc/status.c index f716068bc..8e7a65b05 100644 --- a/osfmk/ppc/status.c +++ b/osfmk/ppc/status.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -45,11 +44,6 @@ extern void thread_bootstrap_return(void); extern struct Saveanchor saveanchor; extern int real_ncpus; /* Number of actual CPUs */ - -struct ppc_saved_state * get_user_regs(thread_act_t); - -#define USRSTACK 0xc0000000 - kern_return_t thread_userstack( thread_t, @@ -100,6 +94,9 @@ act_machine_get_state( { register struct savearea *sv; /* Pointer to the context savearea */ + register savearea_fpu *fsv; + register savearea_vec *vsv; + savearea *genuser; int i, j; unsigned int vrvalidwrk; @@ -108,6 +105,7 @@ act_machine_get_state( register struct ppc_float_state *fs; register struct ppc_vector_state *vs; + #if MACH_ASSERT if (watchacts & WA_STATE) printf("act_%x act_machine_get_state(thr_act=%x,flav=%x,st=%x,cnt@%x=%x)\n", @@ -115,6 +113,7 @@ act_machine_get_state( count, (count ? *count : 0)); #endif /* MACH_ASSERT */ + genuser = find_user_regs(thr_act); /* Find the current user general context for this activation */ switch (flavor) { @@ -139,14 +138,8 @@ act_machine_get_state( ts = (struct ppc_thread_state *) tstate; - sv = (savearea *)(thr_act->mact.pcb); /* Start with the normal savearea */ - while(sv) { /* Find the user context */ - if(sv->save_srr1 & MASK(MSR_PR)) { /* Are we looking at the user context? */ - break; /* Outta here */ - } - sv = sv->save_prev; /* Back chain */ - } - + sv = genuser; /* Copy this over */ + if(sv) { /* Is there a save area yet? */ ts->r0 = sv->save_r0; ts->r1 = sv->save_r1; @@ -186,12 +179,12 @@ act_machine_get_state( ts->ctr = sv->save_ctr; ts->srr0 = sv->save_srr0; ts->srr1 = sv->save_srr1; - ts->mq = sv->save_mq; /* MQ register (601 only) */ - ts->vrsave = sv->save_vrsave; /* VRSAVE register (Altivec only) */ + ts->mq = 0; /* MQ register (601 only) */ + ts->vrsave = sv->save_vrsave; /* VRSAVE register (Altivec only) */ } - else { /* No user state yet. Save seemingly random values. */ + else { /* No user state yet. Save seemingly random values. */ - for(i=0; i < 32; i+=2) { /* Fill up with defaults */ + for(i=0; i < 32; i+=2) { /* Fill up with defaults */ ((unsigned int *)&ts->r0)[i] = ((unsigned int *)&FloatInit)[0]; ((unsigned int *)&ts->r0)[i+1] = ((unsigned int *)&FloatInit)[1]; } @@ -202,10 +195,10 @@ act_machine_get_state( ts->srr0 = ((unsigned int *)&FloatInit)[0]; ts->srr1 = MSR_EXPORT_MASK_SET; ts->mq = 0; - ts->vrsave = 0; /* VRSAVE register (Altivec only) */ + ts->vrsave = 0; /* VRSAVE register (Altivec only) */ } - *count = PPC_THREAD_STATE_COUNT; /* Pass back the amount we actually copied */ + *count = PPC_THREAD_STATE_COUNT; /* Pass back the amount we actually copied */ return KERN_SUCCESS; case PPC_EXCEPTION_STATE: @@ -216,12 +209,12 @@ act_machine_get_state( es = (struct ppc_exception_state *) tstate; - sv = (savearea *)(thr_act->mact.pcb); /* Start with the normal savearea */ - while(sv) { /* Find the user context */ - if(sv->save_srr1 & MASK(MSR_PR)) { /* Are we looking at the user context? */ - break; /* Outta here */ + sv = thr_act->mact.pcb; /* Start with the normal savearea */ + while(sv) { /* Find the user context */ + if(sv->save_srr1 & MASK(MSR_PR)) { /* Are we looking at the user context? */ + break; /* Outta here */ } - sv = sv->save_prev; /* Back chain */ + sv = sv->save_hdr.save_prev; /* Back chain */ } if(sv) { /* See if valid state yet */ @@ -244,20 +237,24 @@ act_machine_get_state( return KERN_INVALID_ARGUMENT; } - fpu_save(thr_act); /* Just in case it's live, save it */ + fpu_save(thr_act->mact.curctx); /* Just in case it's live, save it */ fs = (struct ppc_float_state *) tstate; /* Point to destination */ - sv = (savearea *)(thr_act->mact.FPU_pcb); /* Start with the top FPU savearea */ - while(sv) { /* Find the user context */ - if(!sv->save_level_fp) { /* Are we looking at the user context? */ + fsv = (savearea_fpu *)thr_act->mact.curctx->FPUsave; /* Start with the top FPU savearea */ + + while(fsv) { /* Find the user context */ + if(!fsv->save_hdr.save_level) { /* Are we looking at the user context? */ break; /* Outta here */ } - sv = sv->save_prev_float; /* Back chain */ + fsv = (savearea_fpu *)fsv->save_hdr.save_prev; /* Back chain */ } - if(sv) { /* See if we have any */ - bcopy((char *)&sv->save_fp0, (char *)fs, 33*8); /* 32 registers plus status and pad */ + if(fsv) { /* See if we have any */ + bcopy((char *)&fsv->save_fp0, (char *)fs, 32*8); /* 32 registers */ + fs->fpscr_pad = 0; /* Be clean and tidy */ + if(genuser) fs->fpscr = genuser->save_fpscr; /* Set the fpscr value to general */ + else fs->fpscr = 0; /* If no user, initialize this */ } else { /* No floating point yet */ @@ -278,28 +275,34 @@ act_machine_get_state( return KERN_INVALID_ARGUMENT; } - vec_save(thr_act); /* Just in case it's live, save it */ + vec_save(thr_act->mact.curctx); /* Just in case it's live, save it */ vs = (struct ppc_vector_state *) tstate; /* Point to destination */ - sv = (savearea *)(thr_act->mact.VMX_pcb); /* Start with the top FPU savearea */ - while(sv) { /* Find the user context */ - if(!sv->save_level_vec) { /* Are we looking at the user context? */ + vsv = (savearea_vec *)thr_act->mact.curctx->VMXsave; /* Start with the top vector savearea */ + + while(vsv) { /* Find the user context */ + if(!vsv->save_hdr.save_level) { /* Are we looking at the user context? */ break; /* Outta here */ } - sv = sv->save_prev_vector; /* Back chain */ + vsv = (savearea_vec *)vsv->save_hdr.save_prev; /* Back chain */ } - if(sv) { /* See if we have any */ - - vrvalidwrk = sv->save_vrvalid; /* Get the valid flags */ - vs->save_vrvalid = sv->save_vrvalid; /* Set the valid flags */ - for(j=0; j < 4; j++) vs->save_vscr[j] = sv->save_vscr[j]; /* Set value for vscr */ + if(vsv) { /* See if we have any */ + vrvalidwrk = vsv->save_vrvalid; /* Get the valid flags */ + vs->save_vrvalid = vsv->save_vrvalid; /* Set the valid flags */ + if(genuser) for(j=0; j < 4; j++) vs->save_vscr[j] = genuser->save_vscr[j]; /* Set value for vscr */ + else { + vs->save_vscr[0] = 0; /* Set an initial value if no general user yet */ + vs->save_vscr[1] = 0; + vs->save_vscr[2] = 0; + vs->save_vscr[3] = 0x00010000; + } for(i=0; i < 32; i++) { /* Copy the saved registers and invalidate the others */ for(j=0; j < 4; j++) { if(vrvalidwrk & 0x80000000) (vs->save_vr)[i][j] = - ((unsigned int *)&(sv->save_vr0))[(i * 4) + j]; /* We have this register saved */ + ((unsigned int *)&(vsv->save_vr0))[(i * 4) + j]; /* We have this register saved */ else vs->save_vr[i][j] = QNaNbarbarian[j]; /* Set invalid value */ } vrvalidwrk = vrvalidwrk << 1; /* Shift over to the next */ @@ -310,7 +313,14 @@ act_machine_get_state( for(i=0; i < 32; i++) { /* Initialize vector registers */ for(j=0; j < 4; j++) vs->save_vr[i][j] = QNaNbarbarian[j]; /* Initial value */ } - for(j=0; j < 4; j++) vs->save_vscr[j] = 0; /* Initial value */ + + if(genuser) for(j=0; j < 4; j++) vs->save_vscr[j] = genuser->save_vscr[j]; /* Set value for vscr */ + else { + vs->save_vscr[0] = 0; /* Set an initial value if no general user yet */ + vs->save_vscr[1] = 0; + vs->save_vscr[2] = 0; + vs->save_vscr[3] = 0x00010000; + } vs->save_vrvalid = 0; /* Clear the valid flags */ } @@ -339,13 +349,15 @@ act_machine_set_state( mach_msg_type_number_t count) { - savearea *sv, *osv, *usv, *ssv; - unsigned int spc, i, *srs, isnew, clgn; + savearea *sv, *genuser; + savearea_fpu *fsv, *fsvn, *fsvo; + savearea_vec *vsv, *vsvn, *vsvo; + unsigned int i; + int clgn; register struct ppc_thread_state *ts; register struct ppc_exception_state *es; register struct ppc_float_state *fs; register struct ppc_vector_state *vs; - spl_t spl; int kernel_act = thr_act->kernel_loading || thr_act->kernel_loaded; @@ -365,8 +377,6 @@ act_machine_set_state( if (clgn < PPC_THREAD_STATE_COUNT) { /* Is it too short? */ return KERN_INVALID_ARGUMENT; /* Yeah, just leave... */ } - - if(clgn > PPC_THREAD_STATE_COUNT) clgn = PPC_THREAD_STATE_COUNT; /* If too long, pin it at max */ break; case PPC_EXCEPTION_STATE: @@ -375,7 +385,6 @@ act_machine_set_state( return KERN_INVALID_ARGUMENT; /* Yeah, just leave... */ } - if(clgn > PPC_EXCEPTION_STATE_COUNT) clgn = PPC_EXCEPTION_STATE_COUNT; /* If too long, pin it at max */ break; case PPC_FLOAT_STATE: @@ -384,7 +393,6 @@ act_machine_set_state( return KERN_INVALID_ARGUMENT; /* Yeah, just leave... */ } - if(clgn > PPC_FLOAT_STATE_COUNT) clgn = PPC_FLOAT_STATE_COUNT; /* If too long, pin it at max */ break; @@ -394,302 +402,154 @@ act_machine_set_state( return KERN_INVALID_ARGUMENT; /* Yeah, just leave... */ } - if(clgn > PPC_VECTOR_STATE_COUNT) clgn = PPC_VECTOR_STATE_COUNT; /* If too long, pin it at max */ break; default: return KERN_INVALID_ARGUMENT; } - - isnew = 0; /* Remember when we make a new one */ + genuser = get_user_regs(thr_act); /* Find or allocate and initialize one */ + switch (flavor) { case PPC_THREAD_STATE: case PPC_EXCEPTION_STATE: ts = (struct ppc_thread_state *)tstate; - - sv = (savearea *)thr_act->mact.pcb; /* Get the top savearea on the stack */ - osv = 0; /* Set no user savearea yet */ - - while(sv) { /* Find the user context */ - if(sv->save_srr1 & MASK(MSR_PR)) { /* Are we looking at the user context? */ - break; /* Outta here */ - } - osv = sv; /* Save the last one */ - sv = sv->save_prev; /* Get the previous context */ - } - - if(!sv) { /* We didn't find a user context so allocate and initialize one */ - isnew = 1; /* Remember we made a new one */ - sv = save_alloc(); /* Get one */ - sv->save_act = thr_act; /* Point to the activation */ - sv->save_flags |= SAVattach; /* Say that it is in use */ - sv->save_srr1 = MSR_EXPORT_MASK_SET & ~MASK(MSR_PR); /* Assume kernel state */ - sv->save_xfpscrpad = 0; /* Start with a clear fpscr */ - sv->save_xfpscr = 0; /* Start with a clear fpscr */ - - spc = (unsigned int)thr_act->map->pmap->space; /* Get the space we're in */ - - srs = (unsigned int *)&sv->save_sr0; /* Point to the SRs */ - for(i=0; i < 16; i++) { /* Fill in the SRs for the new context */ - srs[i] = SEG_REG_PROT | (i<<20) | spc; /* Set the SR */ - } - - sv->save_sr_copyin = SEG_REG_PROT | (SR_COPYIN_NUM<<20) | spc; /* Make sure the copyin is set */ - - if(osv) { /* Did we already have one? */ - osv->save_prev = sv; /* Chain us on the end */ - } - else { /* We are the first */ - thr_act->mact.pcb = (pcb_t)sv; /* Put it there */ - } - sv->save_prev = 0; /* Properly terminate the chain */ - - } - + if(flavor == PPC_THREAD_STATE) { /* Are we updating plain state? */ - sv->save_r0 = ts->r0; - sv->save_r1 = ts->r1; - sv->save_r2 = ts->r2; - sv->save_r3 = ts->r3; - sv->save_r4 = ts->r4; - sv->save_r5 = ts->r5; - sv->save_r6 = ts->r6; - sv->save_r7 = ts->r7; - sv->save_r8 = ts->r8; - sv->save_r9 = ts->r9; - sv->save_r10 = ts->r10; - sv->save_r11 = ts->r11; - sv->save_r12 = ts->r12; - sv->save_r13 = ts->r13; - sv->save_r14 = ts->r14; - sv->save_r15 = ts->r15; - sv->save_r16 = ts->r16; - sv->save_r17 = ts->r17; - sv->save_r18 = ts->r18; - sv->save_r19 = ts->r19; - sv->save_r20 = ts->r20; - sv->save_r21 = ts->r21; - sv->save_r22 = ts->r22; - sv->save_r23 = ts->r23; - sv->save_r24 = ts->r24; - sv->save_r25 = ts->r25; - sv->save_r26 = ts->r26; - sv->save_r27 = ts->r27; - sv->save_r28 = ts->r28; - sv->save_r29 = ts->r29; - sv->save_r30 = ts->r30; - sv->save_r31 = ts->r31; + genuser->save_r0 = ts->r0; + genuser->save_r1 = ts->r1; + genuser->save_r2 = ts->r2; + genuser->save_r3 = ts->r3; + genuser->save_r4 = ts->r4; + genuser->save_r5 = ts->r5; + genuser->save_r6 = ts->r6; + genuser->save_r7 = ts->r7; + genuser->save_r8 = ts->r8; + genuser->save_r9 = ts->r9; + genuser->save_r10 = ts->r10; + genuser->save_r11 = ts->r11; + genuser->save_r12 = ts->r12; + genuser->save_r13 = ts->r13; + genuser->save_r14 = ts->r14; + genuser->save_r15 = ts->r15; + genuser->save_r16 = ts->r16; + genuser->save_r17 = ts->r17; + genuser->save_r18 = ts->r18; + genuser->save_r19 = ts->r19; + genuser->save_r20 = ts->r20; + genuser->save_r21 = ts->r21; + genuser->save_r22 = ts->r22; + genuser->save_r23 = ts->r23; + genuser->save_r24 = ts->r24; + genuser->save_r25 = ts->r25; + genuser->save_r26 = ts->r26; + genuser->save_r27 = ts->r27; + genuser->save_r28 = ts->r28; + genuser->save_r29 = ts->r29; + genuser->save_r30 = ts->r30; + genuser->save_r31 = ts->r31; - sv->save_cr = ts->cr; - sv->save_xer = ts->xer; - sv->save_lr = ts->lr; - sv->save_ctr = ts->ctr; - sv->save_srr0 = ts->srr0; - sv->save_mq = ts->mq; - sv->save_vrsave = ts->vrsave; /* VRSAVE register (Altivec only) */ + genuser->save_cr = ts->cr; + genuser->save_xer = ts->xer; + genuser->save_lr = ts->lr; + genuser->save_ctr = ts->ctr; + genuser->save_srr0 = ts->srr0; + genuser->save_vrsave = ts->vrsave; /* VRSAVE register (Altivec only) */ - sv->save_srr1 = MSR_PREPARE_FOR_IMPORT(sv->save_srr1, ts->srr1); /* Set the bits we can change */ + genuser->save_srr1 = MSR_PREPARE_FOR_IMPORT(genuser->save_srr1, ts->srr1); /* Set the bits we can change */ - if(!kernel_act) sv->save_srr1 |= MSR_EXPORT_MASK_SET; /* If not a kernel guy, force the magic bits on */ + if(!kernel_act) genuser->save_srr1 |= MSR_EXPORT_MASK_SET; /* If not a kernel guy, force the magic bits on */ - sv->save_srr1 &= ~(MASK(MSR_FP) | MASK(MSR_VEC)); /* Make sure we don't enable the floating point unit */ + genuser->save_srr1 &= ~(MASK(MSR_FP) | MASK(MSR_VEC)); /* Make sure we don't enable the floating point unit */ - if(isnew) { /* Is it a new one? */ - sv->save_dar = 0; /* Yes, these need initialization also */ - sv->save_dsisr = 0; - sv->save_exception = 0; - } - return KERN_SUCCESS; - } - else { /* This must be exception state */ - if(isnew) /* If new, we need to initialize the normal registers */ - for(i=0; i < 32; i+=2) { /* Fill up with defaults */ - ((unsigned int *)&sv->save_r0)[i] = ((unsigned int *)&FloatInit)[0]; - ((unsigned int *)&sv->save_r0)[i+1] = ((unsigned int *)&FloatInit)[1]; - } - sv->save_cr = 0; - sv->save_xer = 0; - sv->save_lr = ((unsigned int *)&FloatInit)[0]; - sv->save_ctr = ((unsigned int *)&FloatInit)[1]; - sv->save_srr0 = ((unsigned int *)&FloatInit)[0]; - sv->save_srr1 = MSR_EXPORT_MASK_SET; - sv->save_mq = 0; - sv->save_vrsave = 0; /* VRSAVE register (Altivec only) */ + } es = (struct ppc_exception_state *) tstate; - sv->save_dar = es->dar; - sv->save_dsisr = es->dsisr; - sv->save_exception = es->exception; + genuser->save_dar = es->dar; + genuser->save_dsisr = es->dsisr; + genuser->save_exception = es->exception; return KERN_SUCCESS; case PPC_FLOAT_STATE: - spl = splhigh(); /* Don't bother me while I'm zapping the owner stuff */ - - if (per_proc_info[cpu_number()].FPU_thread == (unsigned int)thr_act) /* If we own the FPU, and */ - if(!thr_act->mact.FPU_lvl) per_proc_info[cpu_number()].FPU_thread = 0; /* it's user level, say we don't own it any more */ - - splx(spl); /* Restore the interrupt level */ - - sv = (savearea *)thr_act->mact.FPU_pcb; /* Get the top savearea on the stack */ - osv = 0; /* Set no user savearea yet */ + toss_live_fpu(thr_act->mact.curctx); /* Toss my floating point if live anywhere */ - if(sv && (sv->save_level_fp == 1)) { /* Is the first savearea invalid? */ - thr_act->mact.FPU_pcb = (pcb_t)sv->save_prev_float; /* Yes, clean it out */ - sv->save_flags &= ~SAVfpuvalid; /* Clear the floating point flag */ - if(!(sv->save_flags & SAVinuse)) { /* Anyone left with this one? */ - save_release(sv); /* Nope, release it */ - } - sv = (savearea *)thr_act->mact.FPU_pcb; /* Get the new top savearea on the stack */ - } - - while(sv) { /* Find the user context */ - if(!(sv->save_level_fp)) { /* Are we looking at the user context? */ - break; /* Outta here */ - } - osv = sv; /* Save the last one */ - sv = sv->save_prev_float; /* Get the previous context */ - } - - if(!sv) { /* We didn't find a user context so allocate and initialize one */ - - sv = (savearea *)thr_act->mact.pcb; /* Point to the top savearea on the normal stack */ - - while(sv) { /* Have we hit the end? */ - if(!(sv->save_flags & SAVfpuvalid)) break; /* Is floating point in use here? */ - sv = sv->save_prev; /* Back chain */ - } - - if(!sv) { /* If there wasn't one on the normal chain, check vector */ - sv = (savearea *)thr_act->mact.VMX_pcb; /* Point to the top savearea on the vector stack */ - while(sv) { /* Have we hit the end? */ - if(!(sv->save_flags & SAVfpuvalid)) break; /* Is floating point in use here? */ - sv = sv->save_prev_vector; /* Back chain */ - } - } + fsv = find_user_fpu(thr_act); /* Get the user's floating point context */ + + if(!fsv) { /* Do we have one yet? */ + fsv = (savearea_fpu *)save_alloc(); /* If we still don't have one, get a new one */ + fsv->save_hdr.save_flags = (fsv->save_hdr.save_flags & ~SAVtype) | (SAVfloat << SAVtypeshft); /* Mark as in use as float */ + fsv->save_hdr.save_act = thr_act; /* Point to the activation */ + fsv->save_hdr.save_prev = 0; /* Mark no more */ + fsv->save_hdr.save_level = 0; /* Mark user state */ - if(!sv) { /* Do we have one yet? */ - sv = save_alloc(); /* If we still don't have one, get a new one */ - sv->save_act = thr_act; /* Point to the activation */ - - spc=(unsigned int)thr_act->map->pmap->space; /* Get the space we're in */ + if(!thr_act->mact.curctx->FPUsave) thr_act->mact.curctx->FPUsave = fsv; /* If no floating point, chain us first */ + else { + + fsvn = fsvo = thr_act->mact.curctx->FPUsave; /* Remember first one */ - srs=(unsigned int *)&sv->save_sr0; /* Point to the SRs */ - for(i=0; i < 16; i++) { /* Fill in the SRs for the new context */ - srs[i] = SEG_REG_PROT | (i<<20) | spc; /* Set the SR */ + while (fsvn) { /* Go until we hit the end */ + fsvo = fsvn; /* Remember the previous one */ + fsvn = (savearea_fpu *)fsvo->save_hdr.save_prev; /* Skip on to the next */ } - sv->save_sr_copyin = SEG_REG_PROT | (SR_COPYIN_NUM<<20) | spc; /* Make sure the copyin is set */ - } - - if(osv) { /* Did we already have one? */ - osv->save_prev_float = sv; /* Chain us on the end */ + fsvo->save_hdr.save_prev = (savearea *)fsv; /* Queue us on in */ } - else { /* We are the first */ - thr_act->mact.FPU_pcb = (pcb_t)sv; /* Put it there */ - } - sv->save_prev_float = 0; /* Properly terminate the chain */ - sv->save_level_fp = 0; /* Make sure we are for the user level */ - sv->save_flags |= SAVfpuvalid; /* Say that it is in use by floating point */ + } fs = (struct ppc_float_state *) tstate; /* Point to source */ - bcopy((char *)fs, (char *)&sv->save_fp0, clgn*4); /* 32 registers plus status and pad */ - - usv = find_user_regs(thr_act); /* Find the user registers */ - if(!usv) usv = get_user_regs(thr_act); /* Didn't find any, allocate and initialize one */ + bcopy((char *)fs, (char *)&fsv->save_fp0, 32*8); /* Move in the 32 registers */ - usv->save_xfpscrpad = sv->save_fpscr_pad; /* Copy the pad value to normal */ - usv->save_xfpscr = sv->save_fpscr; /* Copy the fpscr value to normal */ + genuser->save_fpscr = fs->fpscr; /* Copy the fpscr value to normal */ return KERN_SUCCESS; case PPC_VECTOR_STATE: - spl = splhigh(); /* Don't bother me while I'm zapping the owner stuff */ - - if (per_proc_info[cpu_number()].VMX_thread == (unsigned int)thr_act) /* If we own the vector, and */ - if(!thr_act->mact.VMX_lvl) per_proc_info[cpu_number()].VMX_thread = 0; /* it's user level, say we don't own it any more */ + toss_live_vec(thr_act->mact.curctx); /* Toss my vector if live anywhere */ - splx(spl); /* Restore the interrupt level */ - - sv = (savearea *)thr_act->mact.VMX_pcb; /* Get the top savearea on the stack */ - osv = 0; /* Set no user savearea yet */ - - if(sv && (sv->save_level_vec == 1)) { /* Is the first savearea invalid? */ - thr_act->mact.VMX_pcb = (pcb_t)sv->save_prev_vector; /* Yes, clean it out */ - sv->save_flags &= ~SAVvmxvalid; /* Clear the floating point flag */ - if(!(sv->save_flags & SAVinuse)) { /* Anyone left with this one? */ - save_release(sv); /* Nope, release it */ - } - sv = (savearea *)thr_act->mact.VMX_pcb; /* Get the new top savearea on the stack */ - } - - while(sv) { /* Find the user context */ - if(!(sv->save_level_vec)) { /* Are we looking at the user context? */ - break; /* Outta here */ - } - osv = sv; /* Save the last one */ - sv = sv->save_prev_vector; /* Get the previous context */ - } - - if(!sv) { /* We didn't find a user context so allocate and initialize one */ - - sv = (savearea *)thr_act->mact.pcb; /* Point to the top savearea on the normal stack */ - - while(sv) { /* Have we hit the end? */ - if(!(sv->save_flags & SAVvmxvalid)) break; /* Is vector in use here? */ - sv = sv->save_prev; /* Back chain */ - } - - if(!sv) { /* If there wasn't one on the normal chain, check vector */ - sv = (savearea *)thr_act->mact.FPU_pcb; /* Point to the top savearea on the FPU stack */ - while(sv) { /* Have we hit the end? */ - if(!(sv->save_flags & SAVvmxvalid)) break; /* Is vector in use here? */ - sv = sv->save_prev_float; /* Get the previous context */ - } - } + vsv = find_user_vec(thr_act); /* Get the user's vector context */ + + if(!vsv) { /* Do we have one yet? */ + vsv = (savearea_vec *)save_alloc(); /* If we still don't have one, get a new one */ + vsv->save_hdr.save_flags = (vsv->save_hdr.save_flags & ~SAVtype) | (SAVvector << SAVtypeshft); /* Mark as in use as vector */ + vsv->save_hdr.save_act = thr_act; /* Point to the activation */ + vsv->save_hdr.save_prev = 0; /* Mark no more */ + vsv->save_hdr.save_level = 0; /* Mark user state */ - if(!sv) { /* Do we have one yet? */ - sv = save_alloc(); /* If we still don't have one, get a new one */ - sv->save_act = thr_act; /* Point to the activation */ - - spc=(unsigned int)thr_act->map->pmap->space; /* Get the space we're in */ + if(!thr_act->mact.curctx->VMXsave) thr_act->mact.curctx->VMXsave = vsv; /* If no vector, chain us first */ + else { + + vsvn = vsvo = thr_act->mact.curctx->VMXsave; /* Remember first one */ - srs=(unsigned int *)&sv->save_sr0; /* Point to the SRs */ - for(i=0; i < 16; i++) { /* Fill in the SRs for the new context */ - srs[i] = SEG_REG_PROT | (i<<20) | spc; /* Set the SR */ + while (vsvn) { /* Go until we hit the end */ + vsvo = vsvn; /* Remember the previous one */ + vsvn = (savearea_vec *)vsvo->save_hdr.save_prev; /* Skip on to the next */ } - sv->save_sr_copyin = SEG_REG_PROT | (SR_COPYIN_NUM<<20) | spc; /* Make sure the copyin is set */ + vsvo->save_hdr.save_prev = (savearea *)vsv; /* Queue us on in */ } - - if(osv) { /* Did we already have one? */ - osv->save_prev_vector = sv; /* Chain us on the end */ - } - else { /* We are the first */ - thr_act->mact.VMX_pcb = (pcb_t)sv; /* Put it there */ - } - sv->save_prev_vector = 0; /* Properly terminate the chain */ - sv->save_level_vec = 0; /* Make sure we are for the user level */ - sv->save_flags |= SAVvmxvalid; /* Say that it is in use by vector */ + } - vs = (struct ppc_vector_state *) tstate; /* Point to source */ - bcopy((char *)vs, (char *)&sv->save_vr0, clgn*4); /* 32 registers plus status and validity and pad */ + bcopy((char *)vs, (char *)&vsv->save_vr0, 32*16); /* 32 registers plus status and validity and pad */ + vsv->save_vrvalid = vs->save_vrvalid; /* Set validity bits */ + + + for(i = 0; i < 4; i++) genuser->save_vscr[i] = vs->save_vscr[i]; /* Set value for vscr */ return KERN_SUCCESS; @@ -701,106 +561,70 @@ act_machine_set_state( /* * Duplicates the context of one thread into a new one. - * The new thread is assumed to be new and have no user state contexts. + * The new thread is assumed to be new and have no user state contexts except maybe a general one. * We also assume that the old thread can't be running anywhere. * * We're only going to be duplicating user context here. That means that we will have to * eliminate any floating point or vector kernel contexts and carry across the user state ones. - * We will optimize and cram all states into one savearea. Actually that will be the easiest thing - * to do. */ void act_thread_dup(thread_act_t old, thread_act_t new) { - savearea *sv, *osv, *fsv; + savearea *sv, *osv; + savearea_fpu *fsv, *fsvn; + savearea_vec *vsv, *vsvn; unsigned int spc, i, *srs; - fpu_save(old); /* Make certain floating point state is all saved */ - vec_save(old); /* Make certain the vector state is all saved */ + fpu_save(old->mact.curctx); /* Make certain floating point state is all saved */ + vec_save(old->mact.curctx); /* Make certain the vector state is all saved */ - osv = (savearea *)new->mact.pcb; /* Get the top savearea on the stack */ - sv = 0; /* Set no new user savearea yet */ + sv = get_user_regs(new); /* Allocate and initialze context in the new activation */ - while(osv) { /* Find the user context */ - if(osv->save_srr1 & MASK(MSR_PR)) { /* Are we looking at the user context? */ - sv=osv; /* Say which to use */ - break; /* Outta here */ - } - osv=osv->save_prev; /* Get the previous context */ + osv = find_user_regs(old); /* Find the original context */ + if(!osv) { + panic("act_thread_dup: old activation (%08X) has no general user context\n", old); } - if(!sv) { /* We didn't find a user context so allocate and initialize one */ - osv = (savearea *)new->mact.pcb; /* Point to the top savearea on the stack */ - sv = save_alloc(); /* Get one */ - sv->save_flags |= SAVattach; /* Say that it is in use */ - sv->save_act = new; /* Point to the activation */ - - spc=(unsigned int)new->map->pmap->space; /* Get the space we're in */ - - srs=(unsigned int *)&sv->save_sr0; /* Point to the SRs */ - for(i=0; i < 16; i++) { /* Fill in the SRs for the new context */ - srs[i] = SEG_REG_PROT | (i<<20) | spc; /* Set the SR */ - } - - sv->save_sr_copyin = SEG_REG_PROT | (SR_COPYIN_NUM<<20) | spc; /* Make sure the copyin is set */ - - if(osv) { /* Did we already have one? */ - sv->save_prev = osv->save_prev; /* Move the back chain of the top savearea */ - osv->save_prev = sv; /* Chain us just after it */ - } - else { /* We are the first */ - new->mact.pcb = (pcb_t)sv; /* Make it the active one */ - } - - } - - osv = (savearea *)(old->mact.pcb); /* Start with the normal savearea */ - while(osv) { /* Find the user context */ - if(osv->save_srr1 & MASK(MSR_PR)) { /* Are we looking at the user context? */ - break; /* Outta here */ - } - osv = osv->save_prev; /* Back chain */ - } + bcopy((char *)((unsigned int)osv + sizeof(savearea_comm)), /* Copy everything but the headers */ + (char *)((unsigned int)sv + sizeof(savearea_comm)), + sizeof(struct savearea) - sizeof(savearea_comm)); + + sv->save_srr1 &= ~(MASK(MSR_FP) | MASK(MSR_VEC)); /* Make certain that floating point and vector are turned off */ - bcopy((char *)&osv->save_srr0, (char *)&sv->save_srr0, sizeof(struct ppc_thread_state)); /* Copy in normal state stuff */ + fsv = find_user_fpu(old); /* Get any user floating point */ - sv->save_xfpscrpad = osv->save_xfpscrpad; /* Copy the pad value to old */ - sv->save_xfpscr = osv->save_xfpscr; /* Copy the fpscr value to old */ + new->mact.curctx->FPUsave = 0; /* Assume no floating point */ - new->mact.FPU_pcb = (pcb_t)0 ; /* Initialize floating point savearea */ - new->mact.FPU_lvl = (pcb_t)0 ; /* Initialize floating point level */ - new->mact.FPU_cpu = 0 ; /* Initialize last used cpu (FP not live, so this doesn't really matter) */ - new->mact.VMX_pcb = (pcb_t)0 ; /* Initialize vector savearea */ - new->mact.VMX_lvl = (pcb_t)0 ; /* Initialize vector level */ - new->mact.VMX_cpu = 0 ; /* Initialize last used cpu (vector not live, so this doesn't reall matter) */ + if(fsv) { /* Did we find one? */ + fsvn = (savearea_fpu *)save_alloc(); /* If we still don't have one, get a new one */ + fsvn->save_hdr.save_flags = (fsvn->save_hdr.save_flags & ~SAVtype) | (SAVfloat << SAVtypeshft); /* Mark as in use as float */ + fsvn->save_hdr.save_act = new; /* Point to the activation */ + fsvn->save_hdr.save_prev = 0; /* Mark no more */ + fsvn->save_hdr.save_level = 0; /* Mark user state */ - sv->save_prev_float = (savearea *)0; /* Clear the back chain */ - sv->save_prev_vector = (savearea *)0; /* Clear the back chain */ - sv->save_level_fp = 0; /* Set the level for FP */ - sv->save_level_vec = 0; /* Set the level for vector */ - - sv->save_srr1 &= ~(MASK(MSR_FP) | MASK(MSR_VEC)); /* Make certain that floating point and vector are turned off */ - - fsv = (savearea *)old->mact.FPU_pcb; /* Get the start of the floating point chain */ - while(fsv) { /* Look until the end or we find it */ - if(!(fsv->save_level_fp)) { /* Is the the user state stuff? (the level is 0 if so) */ - sv->save_flags |= SAVfpuvalid; /* Show we have it */ - bcopy((char *)&osv->save_fp0, (char *)&sv->save_fp0, sizeof(struct ppc_float_state)); /* Copy in floating point state stuff */ - new->mact.FPU_pcb = (pcb_t)sv; /* Make it the active one */ - break; /* Done, everything else is all set up... */ - } - fsv = fsv->save_prev_float; /* Try the previous one */ + new->mact.curctx->FPUsave = fsvn; /* Chain in the floating point */ + + bcopy((char *)((unsigned int)fsv + sizeof(savearea_comm)), /* Copy everything but the headers */ + (char *)((unsigned int)fsvn + sizeof(savearea_comm)), + sizeof(struct savearea) - sizeof(savearea_comm)); } + + vsv = find_user_vec(old); /* Get any user vector */ - fsv = (savearea *)old->mact.VMX_pcb; /* Get the start of the vector chain */ - while(fsv) { /* Look until the end or we find it */ - if(!(fsv->save_level_vec)) { /* Is the the user state stuff? (the level is 0 if so) */ - sv->save_flags |= SAVvmxvalid; /* Show we have it */ - bcopy((char *)&osv->save_vr0, (char *)&sv->save_vr0, sizeof(struct ppc_vector_state)); /* Copy in Altivec state stuff */ - new->mact.VMX_pcb = (pcb_t)sv; /* Make it the active one */ - break; /* Done, everything else is all set up... */ - } - fsv = fsv->save_prev_vector; /* Try the previous one */ + new->mact.curctx->VMXsave = 0; /* Assume no vector */ + + if(vsv) { /* Did we find one? */ + vsvn = (savearea_vec *)save_alloc(); /* If we still don't have one, get a new one */ + vsvn->save_hdr.save_flags = (vsvn->save_hdr.save_flags & ~SAVtype) | (SAVvector << SAVtypeshft); /* Mark as in use as float */ + vsvn->save_hdr.save_act = new; /* Point to the activation */ + vsvn->save_hdr.save_prev = 0; /* Mark no more */ + vsvn->save_hdr.save_level = 0; /* Mark user state */ + + new->mact.curctx->VMXsave = vsvn; /* Chain in the floating point */ + + bcopy((char *)((unsigned int)vsv + sizeof(savearea_comm)), /* Copy everything but the headers */ + (char *)((unsigned int)vsvn + sizeof(savearea_comm)), + sizeof(struct savearea) - sizeof(savearea_comm)); } return; /* Bye bye... */ @@ -808,37 +632,37 @@ void act_thread_dup(thread_act_t old, thread_act_t new) { /* * Initializes a fresh set of user state values. If there is no user state context, - * one is created. Floats and VMX are not created. We set initial values for everything. + * one is created. Floats and VMX are not created. + * + * We only set initial values if there was no context found. */ -struct ppc_saved_state * get_user_regs(thread_act_t act) { +savearea *get_user_regs(thread_act_t act) { savearea *sv, *osv; unsigned int spc, i, *srs; - sv = (savearea *)act->mact.pcb; /* Get the top savearea on the stack */ + sv = act->mact.pcb; /* Get the top savearea on the stack */ osv = 0; /* Set no user savearea yet */ while(sv) { /* Find the user context */ - if(sv->save_srr1 & MASK(MSR_PR)) { /* Are we looking at the user context? */ - break; /* Outta here */ - } + if(sv->save_srr1 & MASK(MSR_PR)) return sv; /* We found a user state context... */ + osv = sv; /* Save the last one */ - sv = sv->save_prev; /* Get the previous context */ + sv = sv->save_hdr.save_prev; /* Get the previous context */ } - if(!sv) { /* We didn't find a user context so allocate and initialize one */ - sv = save_alloc(); /* Get one */ - sv->save_flags |= SAVattach; /* Say that it is in use */ - sv->save_act = act; /* Point to the activation */ - - if(osv) { /* Did we already have one? */ - osv->save_prev = sv; /* Chain us on the end */ - } - else { /* We are the first */ - act->mact.pcb = (pcb_t)sv; /* Put it there */ - } - sv->save_prev = 0; /* Properly terminate the chain */ + sv = save_alloc(); /* Get one */ + sv->save_hdr.save_flags = (sv->save_hdr.save_flags & ~SAVtype) | (SAVgeneral << SAVtypeshft); /* Mark as in use as general */ + sv->save_hdr.save_act = act; /* Point to the activation */ + sv->save_hdr.save_prev = 0; /* Mark no more */ + sv->save_hdr.save_level = 0; /* Mark user state */ + + if(osv) { /* Did we already have one? */ + osv->save_hdr.save_prev = sv; /* Chain us on the end */ + } + else { /* We are the first */ + act->mact.pcb = sv; /* Put it there */ } for(i=0; i < 32; i+=2) { /* Fill up with defaults */ @@ -851,21 +675,23 @@ struct ppc_saved_state * get_user_regs(thread_act_t act) { sv->save_ctr = ((unsigned int *)&FloatInit)[1]; sv->save_srr0 = ((unsigned int *)&FloatInit)[0]; sv->save_srr1 = MSR_EXPORT_MASK_SET; - sv->save_mq = 0; - sv->save_vrsave = 0; /* VRSAVE register (Altivec only) */ - sv->save_xfpscrpad = 0; /* Start with a clear fpscr */ - sv->save_xfpscr = 0; /* Start with a clear fpscr */ + + sv->save_fpscr = 0; /* Clear all floating point exceptions */ + + sv->save_vrsave = 0; /* Set the vector save state */ + sv->save_vscr[0] = 0x00000000; + sv->save_vscr[1] = 0x00000000; + sv->save_vscr[2] = 0x00000000; + sv->save_vscr[3] = 0x00010000; /* Supress java mode and clear saturated */ - spc=(unsigned int)act->map->pmap->space; /* Get the space we're in */ + spc = (unsigned int)act->map->pmap->space; /* Get the space we're in */ - srs=(unsigned int *)&sv->save_sr0; /* Point to the SRs */ - for(i=0; i < 16; i++) { /* Fill in the SRs for the new context */ + srs = (unsigned int *)&sv->save_sr0; /* Point to the SRs */ + for(i = 0; i < 16; i++) { /* Fill in the SRs for the new context */ srs[i] = SEG_REG_PROT | (i<<20) | spc; /* Set the SR */ } - sv->save_sr_copyin = SEG_REG_PROT | (SR_COPYIN_NUM<<20) | spc; /* Make sure the copyin is set */ - - return (struct ppc_saved_state *)sv; /* Bye bye... */ + return sv; /* Bye bye... */ } /* @@ -873,38 +699,58 @@ struct ppc_saved_state * get_user_regs(thread_act_t act) { * we just return a 0. */ -struct ppc_saved_state * find_user_regs(thread_act_t act) { +savearea *find_user_regs(thread_act_t act) { savearea *sv; - sv = (savearea *)act->mact.pcb; /* Get the top savearea on the stack */ + sv = act->mact.pcb; /* Get the top savearea on the stack */ while(sv) { /* Find the user context */ if(sv->save_srr1 & MASK(MSR_PR)) { /* Are we looking at the user context? */ break; /* Outta here */ } - sv = sv->save_prev; /* Get the previous context */ + sv = sv->save_hdr.save_prev; /* Get the previous context */ } - return (struct ppc_saved_state *)sv; /* Bye bye... */ + return sv; /* Bye bye... */ } /* - * Find the user state floating pointcontext. If there is no user state context, + * Find the user state floating point context. If there is no user state context, * we just return a 0. */ -struct ppc_float_state * find_user_fpu(thread_act_t act) { +savearea_fpu *find_user_fpu(thread_act_t act) { - savearea *fsv; + savearea_fpu *fsv; - fsv = (savearea *)act->mact.FPU_pcb; /* Get the start of the floating point chain */ + fsv = act->mact.curctx->FPUsave; /* Get the start of the floating point chain */ + while(fsv) { /* Look until the end or we find it */ - if(!(fsv->save_level_fp)) break; /* Is the the user state stuff? (the level is 0 if so) */ - fsv = fsv->save_prev_float; /* Try the previous one */ + if(!(fsv->save_hdr.save_level)) break; /* Is the the user state stuff? (the level is 0 if so) */ + fsv = (savearea_fpu *)fsv->save_hdr.save_prev; /* Try the previous one */ } - return (struct ppc_float_state *)&(fsv->save_fp0); /* Bye bye... */ + return fsv; /* Bye bye... */ +} + +/* + * Find the user state vector context. If there is no user state context, + * we just return a 0. + */ + +savearea_vec *find_user_vec(thread_act_t act) { + + savearea_vec *vsv; + + vsv = act->mact.curctx->VMXsave; /* Get the start of the vector chain */ + + while(vsv) { /* Look until the end or we find it */ + if(!(vsv->save_hdr.save_level)) break; /* Is the the user state stuff? (the level is 0 if so) */ + vsv = (savearea_vec *)vsv->save_hdr.save_prev; /* Try the previous one */ + } + + return vsv; /* Bye bye... */ } /* @@ -925,13 +771,8 @@ thread_userstack( { struct ppc_thread_state *state; - /* - * Set a default. - */ - if (*user_stack == 0) - *user_stack = USRSTACK; - if (customstack) - *customstack = 0; + if (customstack) + *customstack = 0; switch (flavor) { case PPC_THREAD_STATE: @@ -940,14 +781,13 @@ thread_userstack( state = (struct ppc_thread_state *) tstate; - /* - * If a valid user stack is specified, use it. - */ - *user_stack = state->r1 ? state->r1: USRSTACK; + /* If a valid user stack is specified, use it. */ + if (state->r1) + *user_stack = state->r1; + + if (customstack && state->r1) + *customstack = 1; - if (customstack && state->r1) - *customstack = 1; - break; default : return (KERN_INVALID_ARGUMENT); @@ -956,6 +796,60 @@ thread_userstack( return (KERN_SUCCESS); } + +/* + * thread_setuserstack: + * + * Sets the user stack pointer into the machine + * dependent thread state info. + */ +void thread_setuserstack(struct thread_activation *act, unsigned int user_stack) +{ + savearea *sv; + + sv = get_user_regs(act); /* Get the user state registers */ + + sv->save_r1 = user_stack; + + return; +} + +/* + * thread_adjuserstack: + * + * Returns the adjusted user stack pointer from the machine + * dependent thread state info. + */ +unsigned int thread_adjuserstack(struct thread_activation *act, int adjust) +{ + savearea *sv; + + sv = get_user_regs(act); /* Get the user state registers */ + + sv->save_r1 += adjust; /* Adjust the stack */ + + return sv->save_r1; /* Return the adjusted stack */ + +} + +/* + * thread_setentrypoint: + * + * Sets the user PC into the machine + * dependent thread state info. + */ + +void thread_setentrypoint(struct thread_activation *act, unsigned int entry) +{ + savearea *sv; + + sv = get_user_regs(act); /* Get the user state registers */ + + sv->save_srr0 = entry; + + return; +} + kern_return_t thread_entrypoint( thread_t thread, @@ -1009,26 +903,27 @@ unsigned int get_msr_rbits(void) void thread_set_child(thread_act_t child, int pid) { - struct ppc_saved_state *child_state; + struct savearea *child_state; - child_state = find_user_regs(child); + child_state = get_user_regs(child); - child_state->r3 = pid; - child_state->r4 = 1; + child_state->save_r3 = pid; + child_state->save_r4 = 1; } void thread_set_parent(thread_act_t parent, int pid) { - struct ppc_saved_state *parent_state; + struct savearea *parent_state; - parent_state = find_user_regs(parent); + parent_state = get_user_regs(parent); - parent_state->r3 = pid; - parent_state->r4 = 0; + parent_state->save_r3 = pid; + parent_state->save_r4 = 0; } /* * Saves the complete context (general, floating point, and vector) of the current activation. - * We will collect everything into one savearea and pass that back. + * We will collect everything into an opaque block of 1 to 3 saveareas and pass back a + * pointer to that. * * The savearea is made to look like it belongs to the source activation. This needs to * be adjusted when these contexts are attached to a new activation. @@ -1037,90 +932,79 @@ void thread_set_parent(thread_act_t parent, int pid) void *act_thread_csave(void) { - savearea *sv, *osv, *fsv; + savearea *sv, *osv; + savearea_fpu *fsv, *ofsv; + savearea_vec *vsv, *ovsv; unsigned int spc, i, *srs; thread_act_t act; - fpu_save(current_act()); /* Make certain floating point state is all saved */ - vec_save(current_act()); /* Make certain the vector state is all saved */ + act = current_act(); /* Find ourselves */ + + fpu_save(act->mact.curctx); /* Make certain floating point state is all saved */ + vec_save(act->mact.curctx); /* Make certain the vector state is all saved */ - sv = save_alloc(); /* Get a fresh save area */ - hw_atomic_add(&saveanchor.saveneed, 1); /* Account for the extra saveareas "need" */ + osv = find_user_regs(act); /* Get our savearea */ - act = current_act(); /* Find ourselves */ + if(!osv) { + panic("act_thread_csave: attempting to preserve the context of an activation with none (%08X)\n", act); + } - sv->save_flags |= SAVattach; /* Say that it is in use */ - sv->save_act = act; /* Point to the activation */ + sv = save_alloc(); /* Get a fresh save area to save into */ + sv->save_hdr.save_flags = (sv->save_hdr.save_flags & ~SAVtype) | (SAVgeneral << SAVtypeshft); /* Mark as in use as general */ + sv->save_hdr.save_act = act; /* Point to the activation */ + sv->save_hdr.save_prev = 0; /* Mark no more */ + sv->save_hdr.save_level = 0; /* Mark user state */ - spc=(unsigned int)act->map->pmap->space; /* Get the space we're in */ - srs=(unsigned int *)&sv->save_sr0; /* Point to the SRs */ - for(i=0; i < 16; i++) { /* Fill in the SRs for the new context */ - srs[i] = SEG_REG_PROT | (i<<20) | spc; /* Set the SR */ - } + bcopy((char *)((unsigned int)osv + sizeof(savearea_comm)), /* Copy everything but the headers */ + (char *)((unsigned int)sv + sizeof(savearea_comm)), + sizeof(struct savearea) - sizeof(savearea_comm)); + + sv->save_srr1 &= ~(MASK(MSR_FP) | MASK(MSR_VEC)); /* Make certain that floating point and vector are turned off */ + + sv->save_hdr.save_misc2 = 0xDEBB1ED0; /* Eye catcher for debug */ + sv->save_hdr.save_misc3 = 0xE5DA11A5; /* Eye catcher for debug */ - sv->save_sr_copyin = SEG_REG_PROT | (SR_COPYIN_NUM<<20) | spc; /* Make sure the copyin is set */ - osv = (savearea *)(act->mact.pcb); /* Start with the normal savearea */ - fsv = 0; /* Assume none */ - while(osv) { /* Find the user context */ - if(osv->save_srr1 & MASK(MSR_PR)) { /* Are we looking at the user context? */ - fsv = osv; /* Remember what we found */ - break; /* Outta here */ - } - osv = osv->save_prev; /* Back chain */ - } + ofsv = find_user_fpu(act); /* Get any user floating point */ - if(!fsv) { /* Did we find one? */ - for(i=0; i < 32; i+=2) { /* Fill up with defaults */ - ((unsigned int *)&sv->save_r0)[i] = ((unsigned int *)&FloatInit)[0]; - ((unsigned int *)&sv->save_r0)[i+1] = ((unsigned int *)&FloatInit)[1]; - } - sv->save_cr = 0; - sv->save_xer = 0; - sv->save_lr = ((unsigned int *)&FloatInit)[0]; - sv->save_ctr = ((unsigned int *)&FloatInit)[1]; - sv->save_srr0 = ((unsigned int *)&FloatInit)[0]; - sv->save_srr1 = MSR_EXPORT_MASK_SET; - sv->save_mq = 0; - sv->save_vrsave = 0; /* VRSAVE register (Altivec only) */ - sv->save_xfpscrpad = 0; /* Start with a clear fpscr */ - sv->save_xfpscr = 0; /* Start with a clear fpscr */ - } - else { /* We did find one, copy it */ - bcopy((char *)&fsv->save_srr0, (char *)&sv->save_srr0, sizeof(struct ppc_thread_state)); /* Copy in normal state stuff */ - sv->save_xfpscrpad = osv->save_xfpscrpad; /* Copy the pad value to old */ - sv->save_xfpscr = osv->save_xfpscr; /* Copy the fpscr value to old */ - } + sv->save_hdr.save_misc0 = 0; /* Assume no floating point */ - - sv->save_prev = (savearea *)0xDEBB1ED0; /* Eye catcher for debug */ - sv->save_prev_float = (savearea *)0xE5DA11A5; /* Eye catcher for debug */ - sv->save_prev_vector = (savearea *)0; /* Clear */ - sv->save_level_fp = 0; /* Set the level for FP */ - sv->save_level_vec = 0; /* Set the level for vector */ - - sv->save_srr1 &= ~(MASK(MSR_FP) | MASK(MSR_VEC)); /* Make certain that floating point and vector are turned off */ - - fsv = (savearea *)act->mact.FPU_pcb; /* Get the start of the floating point chain */ - while(fsv) { /* Look until the end or we find it */ - if(!(fsv->save_level_fp)) { /* Is the the user state stuff? (the level is 0 if so) */ - sv->save_flags |= SAVfpuvalid; /* Show we have it */ - bcopy((char *)&fsv->save_fp0, (char *)&sv->save_fp0, sizeof(struct ppc_float_state)); /* Copy in floating point state stuff */ - break; /* Done, everything else is all set up... */ - } - fsv = fsv->save_prev_float; /* Try the previous one */ + if(ofsv) { /* Did we find one? */ + fsv = (savearea_fpu *)save_alloc(); /* If we still don't have one, get a new one */ + fsv->save_hdr.save_flags = (fsv->save_hdr.save_flags & ~SAVtype) | (SAVfloat << SAVtypeshft); /* Mark as in use as float */ + fsv->save_hdr.save_act = act; /* Point to the activation */ + fsv->save_hdr.save_prev = 0; /* Mark no more */ + fsv->save_hdr.save_level = 0; /* Mark user state */ + fsv->save_hdr.save_misc2 = 0xDEBB1ED0; /* Eye catcher for debug */ + fsv->save_hdr.save_misc3 = 0xE5DA11A5; /* Eye catcher for debug */ + + sv->save_hdr.save_misc0 = (unsigned int)fsv; /* Remember this one */ + + bcopy((char *)((unsigned int)ofsv + sizeof(savearea_comm)), /* Copy everything but the headers */ + (char *)((unsigned int)fsv + sizeof(savearea_comm)), + sizeof(struct savearea) - sizeof(savearea_comm)); } + + ovsv = find_user_vec(act); /* Get any user vector */ - fsv = (savearea *)act->mact.VMX_pcb; /* Get the start of the vector chain */ - while(fsv) { /* Look until the end or we find it */ - if(!(fsv->save_level_vec)) { /* Is the the user state stuff? (the level is 0 if so) */ - sv->save_flags |= SAVvmxvalid; /* Show we have it */ - bcopy((char *)&fsv->save_vr0, (char *)&sv->save_vr0, sizeof(struct ppc_vector_state)); /* Copy in Altivec state stuff */ - break; /* Done, everything else is all set up... */ - } - fsv = fsv->save_prev_vector; /* Try the previous one */ + sv->save_hdr.save_misc1 = 0; /* Assume no vector */ + + if(ovsv) { /* Did we find one? */ + vsv = (savearea_vec *)save_alloc(); /* If we still don't have one, get a new one */ + vsv->save_hdr.save_flags = (vsv->save_hdr.save_flags & ~SAVtype) | (SAVvector << SAVtypeshft); /* Mark as in use as float */ + vsv->save_hdr.save_act = act; /* Point to the activation */ + vsv->save_hdr.save_prev = 0; /* Mark no more */ + vsv->save_hdr.save_level = 0; /* Mark user state */ + vsv->save_hdr.save_misc2 = 0xDEBB1ED0; /* Eye catcher for debug */ + vsv->save_hdr.save_misc3 = 0xE5DA11A5; /* Eye catcher for debug */ + + sv->save_hdr.save_misc1 = (unsigned int)vsv; /* Chain in the floating point */ + + bcopy((char *)((unsigned int)ovsv + sizeof(savearea_comm)), /* Copy everything but the headers */ + (char *)((unsigned int)vsv + sizeof(savearea_comm)), + sizeof(struct savearea) - sizeof(savearea_comm)); } return (void *)sv; /* Bye bye... */ @@ -1141,141 +1025,114 @@ void *act_thread_csave(void) { void act_thread_catt(void *ctx) { - savearea *sv, *osv, *fsv, *psv; + savearea *sv, *osv, *psv; + savearea_fpu *fsv, *ofsv, *pfsv; + savearea_vec *vsv, *ovsv, *pvsv; unsigned int spc, i, *srs; thread_act_t act; sv = (savearea *)ctx; /* Make this easier for C */ - if((sv->save_prev != (savearea *)0xDEBB1ED0) || (sv->save_prev_float != (savearea *)0xE5DA11A5)) { /* See if valid savearea */ - panic("act_thread_catt: attempt to attach invalid context savearea - %08X\n", sv); /* Die */ + fsv = (savearea_fpu *)sv->save_hdr.save_misc0; /* Get a possible floating point savearea */ + vsv = (savearea_vec *)sv->save_hdr.save_misc1; /* Get a possible vector savearea */ + + if((sv->save_hdr.save_misc2 != 0xDEBB1ED0) || (sv->save_hdr.save_misc3 != 0xE5DA11A5)) { /* See if valid savearea */ + panic("act_thread_catt: attempt to attach invalid general context savearea - %08X\n", sv); /* Die */ } - act = current_act(); /* Find ourselves */ - -/* - * This next bit insures that any live facility context for this thread is discarded on every processor - * that may have it. - * - * Note that this will not be good if the activation has any kernel fp or vec contexts that are live. - * We won't worry about it because it would be silly to call this if we are a kernel task using altivec - * or floating point...... - */ - - for(i=0; i < real_ncpus; i++) { /* Cycle through processors */ - (void)hw_compare_and_store((unsigned int)act, 0, &per_proc_info[i].FPU_thread); /* Clear if ours */ - (void)hw_compare_and_store((unsigned int)act, 0, &per_proc_info[i].VMX_thread); /* Clear if ours */ + if(fsv && ((fsv->save_hdr.save_misc2 != 0xDEBB1ED0) || (fsv->save_hdr.save_misc3 != 0xE5DA11A5))) { /* See if valid savearea */ + panic("act_thread_catt: attempt to attach invalid float context savearea - %08X\n", fsv); /* Die */ } + if(vsv && ((vsv->save_hdr.save_misc2 != 0xDEBB1ED0) || (vsv->save_hdr.save_misc3 != 0xE5DA11A5))) { /* See if valid savearea */ + panic("act_thread_catt: attempt to attach invalid vector context savearea - %08X\n", vsv); /* Die */ + } -/* - * Now we make the savearea look like we own it - */ + act = current_act(); /* Find ourselves */ - sv->save_prev = (savearea *)0; /* Clear */ - sv->save_prev_float = (savearea *)0; /* Clear */ - sv->save_prev_vector = (savearea *)0; /* Clear */ - sv->save_act = act; /* Point to the activation */ + toss_live_fpu(act->mact.curctx); /* Toss my floating point if live anywhere */ + toss_live_vec(act->mact.curctx); /* Toss my vector if live anywhere */ + + sv->save_hdr.save_misc2 = 0; /* Eye catcher for debug */ + sv->save_hdr.save_misc3 = 0; /* Eye catcher for debug */ + sv->save_hdr.save_act = act; /* Set us as owner */ - spc=(unsigned int)act->map->pmap->space; /* Get the space we're in */ + spc = (unsigned int)act->map->pmap->space; /* Get the space we're in */ - srs=(unsigned int *)&sv->save_sr0; /* Point to the SRs */ - for(i=0; i < 16; i++) { /* Fill in the SRs for the new context */ + srs = (unsigned int *)&sv->save_sr0; /* Point to the SRs */ + for(i = 0; i < 16; i++) { /* Fill in the SRs for the new context */ srs[i] = SEG_REG_PROT | (i<<20) | spc; /* Set the SRs */ } - sv->save_sr_copyin = SEG_REG_PROT | (SR_COPYIN_NUM<<20) | spc; /* Make sure the copyin is set */ - - osv = (savearea *)act->mact.VMX_pcb; /* Get the top vector savearea */ - - if(osv && (osv->save_level_vec == 1)) { /* Is the first one a special dummy one? */ - psv = osv; /* Yes, remember it */ - osv = osv->save_prev_vector; /* Step to the next */ - (savearea *)act->mact.VMX_pcb = osv; /* Dequeue it */ - psv->save_flags &= ~SAVvmxvalid; /* Clear the VMX flag */ - if(!(psv->save_flags & SAVinuse)) { /* Anyone left with this one? */ - save_release(psv); /* Nope, release it */ - } - } - + osv = act->mact.pcb; /* Get the top general savearea */ psv = 0; - while(osv) { /* Any VMX saved state? */ - if(!(osv->save_level_vec)) break; /* Leave if this is user state */ + while(osv) { /* Any saved state? */ + if(osv->save_srr1 & MASK(MSR_PR)) break; /* Leave if this is user state */ psv = osv; /* Save previous savearea address */ - osv = osv->save_prev_vector; /* Get one underneath our's */ + osv = osv->save_hdr.save_prev; /* Get one underneath our's */ } if(osv) { /* Did we find one? */ - if(psv) psv->save_prev_vector = 0; /* Yes, clear pointer to it (it should always be last) or */ - else act->mact.VMX_pcb = 0; /* to the start if the only one */ + if(psv) psv->save_hdr.save_prev = 0; /* Yes, clear pointer to it (it should always be last) or */ + else act->mact.pcb = 0; /* to the start if the only one */ - osv->save_flags &= ~SAVvmxvalid; /* Clear the VMX flag */ - if(!(osv->save_flags & SAVinuse)) { /* Anyone left with this one? */ - save_release(osv); /* Nope, release it */ - } - } - - if(sv->save_flags & SAVvmxvalid) { /* Are we adding Altivec context? */ - if(psv) psv->save_prev_vector = sv; /* Yes, chain us to the end or */ - else act->mact.VMX_pcb = (pcb_t)sv; /* to the start if the only one */ + save_release(osv); /* Nope, release it */ + } + + if(psv) psv->save_hdr.save_prev = sv; /* Chain us to the end or */ + else act->mact.pcb = (pcb_t)sv; /* to the start if the only one */ - osv = (savearea *)act->mact.FPU_pcb; /* Get the top floating point savearea */ + ovsv = act->mact.curctx->VMXsave; /* Get the top vector savearea */ - if(osv && (osv->save_level_fp == 1)) { /* Is the first one a special dummy one? */ - psv = osv; /* Yes, remember it */ - osv = osv->save_prev_float; /* Step to the next */ - (savearea *)act->mact.FPU_pcb = osv; /* Dequeue it */ - psv->save_flags &= ~SAVfpuvalid; /* Clear the float flag */ - if(!(psv->save_flags & SAVinuse)) { /* Anyone left with this one? */ - save_release(psv); /* Nope, release it */ - } + pvsv = 0; + while(ovsv) { /* Any VMX saved state? */ + if(!(ovsv->save_hdr.save_level)) break; /* Leave if this is user state */ + pvsv = ovsv; /* Save previous savearea address */ + ovsv = (savearea_vec *)ovsv->save_hdr.save_prev; /* Get one underneath our's */ } + + if(ovsv) { /* Did we find one? */ + if(pvsv) pvsv->save_hdr.save_prev = 0; /* Yes, clear pointer to it (it should always be last) or */ + else act->mact.curctx->VMXsave = 0; /* to the start if the only one */ - psv = 0; - while(osv) { /* Any floating point saved state? */ - if(!(osv->save_level_fp)) break; /* Leave if this is user state */ - psv = osv; /* Save previous savearea address */ - osv = osv->save_prev_float; /* Get one underneath our's */ + save_release((savearea *)ovsv); /* Nope, release it */ } - if(osv) { /* Did we find one? */ - if(psv) psv->save_prev_float = 0; /* Yes, clear pointer to it (it should always be last) or */ - else act->mact.FPU_pcb = 0; /* to the start if the only one */ + if(vsv) { /* Are we sticking any vector on this one? */ + if(pvsv) pvsv->save_hdr.save_prev = (savearea *)vsv; /* Yes, chain us to the end or */ + else act->mact.curctx->VMXsave = vsv; /* to the start if the only one */ - osv->save_flags &= ~SAVfpuvalid; /* Clear the floating point flag */ - if(!(osv->save_flags & SAVinuse)) { /* Anyone left with this one? */ - save_release(osv); /* Nope, release it */ - } + vsv->save_hdr.save_misc2 = 0; /* Eye catcher for debug */ + vsv->save_hdr.save_misc3 = 0; /* Eye catcher for debug */ + vsv->save_hdr.save_act = act; /* Set us as owner */ } - if(sv->save_flags & SAVfpuvalid) { /* Are we adding floating point context? */ - if(psv) psv->save_prev_float = sv; /* Yes, chain us to the end or */ - else act->mact.FPU_pcb = (pcb_t)sv; /* to the start if the only one */ - } + ofsv = act->mact.curctx->FPUsave; /* Get the top float savearea */ - osv = (savearea *)act->mact.pcb; /* Get the top general savearea */ - psv = 0; - while(osv) { /* Any floating point saved state? */ - if(osv->save_srr1 & MASK(MSR_PR)) break; /* Leave if this is user state */ - psv = osv; /* Save previous savearea address */ - osv = osv->save_prev; /* Get one underneath our's */ + pfsv = 0; + while(ofsv) { /* Any float saved state? */ + if(!(ofsv->save_hdr.save_level)) break; /* Leave if this is user state */ + pfsv = ofsv; /* Save previous savearea address */ + ofsv = (savearea_fpu *)ofsv->save_hdr.save_prev; /* Get one underneath our's */ } - if(osv) { /* Did we find one? */ - if(psv) psv->save_prev = 0; /* Yes, clear pointer to it (it should always be last) or */ - else act->mact.pcb = 0; /* to the start if the only one */ + if(ofsv) { /* Did we find one? */ + if(pfsv) pfsv->save_hdr.save_prev = 0; /* Yes, clear pointer to it (it should always be last) or */ + else act->mact.curctx->FPUsave = 0; /* to the start if the only one */ - osv->save_flags &= ~SAVattach; /* Clear the attached flag */ - if(!(osv->save_flags & SAVinuse)) { /* Anyone left with this one? */ - save_release(osv); /* Nope, release it */ - } + save_release((savearea *)ofsv); /* Nope, release it */ } - if(psv) psv->save_prev = sv; /* Chain us to the end or */ - else act->mact.pcb = (pcb_t)sv; /* to the start if the only one */ + if(fsv) { /* Are we sticking any vector on this one? */ + if(pfsv) pfsv->save_hdr.save_prev = (savearea *)fsv; /* Yes, chain us to the end or */ + else act->mact.curctx->FPUsave = fsv; /* to the start if the only one */ - hw_atomic_sub(&saveanchor.saveneed, 1); /* Unaccount for the savearea we think we "need" */ + fsv->save_hdr.save_misc2 = 0; /* Eye catcher for debug */ + fsv->save_hdr.save_misc3 = 0; /* Eye catcher for debug */ + fsv->save_hdr.save_act = act; /* Set us as owner */ + } + } @@ -1288,14 +1145,59 @@ void act_thread_catt(void *ctx) { void act_thread_cfree(void *ctx) { - if((((savearea *)ctx)->save_prev != (savearea *)0xDEBB1ED0) || - (((savearea *)ctx)->save_prev_float != (savearea *)0xE5DA11A5)) { /* See if valid savearea */ - panic("act_thread_cfree: attempt to free invalid context savearea - %08X\n", ctx); /* Die */ + savearea *sv, *osv; + savearea_fpu *fsv, *ofsv; + savearea_vec *vsv, *ovsv, *pvsv; + + sv = (savearea *)ctx; /* Make this easier for C */ + + fsv = (savearea_fpu *)sv->save_hdr.save_misc0; /* Get a possible floating point savearea */ + vsv = (savearea_vec *)sv->save_hdr.save_misc1; /* Get a possible vector savearea */ + + if((sv->save_hdr.save_misc2 != 0xDEBB1ED0) || (sv->save_hdr.save_misc3 != 0xE5DA11A5)) { /* See if valid savearea */ + panic("act_thread_cfree: attempt to detatch invalid general context savearea - %08X\n", sv); /* Die */ + } + + save_release(sv); /* Toss the general savearea */ + + if(fsv) { /* See if there is any saved floating point */ + if((fsv->save_hdr.save_misc2 != 0xDEBB1ED0) || (fsv->save_hdr.save_misc3 != 0xE5DA11A5)) { /* See if valid savearea */ + panic("act_thread_cfree: attempt to detatch invalid float context savearea - %08X\n", fsv); /* Die */ + } + + save_release((savearea *)fsv); /* Toss saved context */ } - ((savearea *)ctx)->save_flags = 0; /* Clear all flags since we release this in any case */ - save_release((savearea *)ctx); /* Release this one */ - hw_atomic_sub(&saveanchor.saveneed, 1); /* Unaccount for the savearea we think we "need" */ + if(vsv) { /* See if there is any saved floating point */ + if((vsv->save_hdr.save_misc2 != 0xDEBB1ED0) || (vsv->save_hdr.save_misc3 != 0xE5DA11A5)) { /* See if valid savearea */ + panic("act_thread_cfree: attempt to detatch invalid vector context savearea - %08X\n", vsv); /* Die */ + } + + save_release((savearea *)vsv); /* Toss saved context */ + } return; } + +/* + * thread_enable_fpe: + * + * enables or disables floating point exceptions for the thread. + * returns old state + */ +int thread_enable_fpe(thread_act_t act, int onoff) +{ + savearea *sv; + unsigned int oldmsr; + + sv = find_user_regs(act); /* Find the user registers */ + if(!sv) sv = get_user_regs(act); /* Didn't find any, allocate and initialize o +ne */ + + oldmsr = sv->save_srr1; /* Get the old msr */ + + if(onoff) sv->save_srr1 = oldmsr | MASK(MSR_FE0) | MASK(MSR_FE1); /* Flip on precise FP exceptions */ + else sv->save_srr1 = oldmsr & ~(MASK(MSR_FE0) | MASK(MSR_FE1)); /* Flip on precise FP exceptions */ + + return ((oldmsr & (MASK(MSR_FE0) | MASK(MSR_FE1))) != 0); /* Return if it was enabled or not */ +} diff --git a/osfmk/ppc/stubs.c b/osfmk/ppc/stubs.c deleted file mode 100644 index 709f8b6e3..000000000 --- a/osfmk/ppc/stubs.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * @OSF_FREE_COPYRIGHT@ - */ - -/* TODO NMGS REMOVE ALL OF THESE AND THEN THIS FILE !!! */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int -procitab(u_int spllvl, - void (*handler)(int), - int unit) -{ - printf("NMGS TODO NOT YET"); - return 0; -} diff --git a/osfmk/ppc/thread_act.h b/osfmk/ppc/thread_act.h index 09e3097c5..9d0a0cbb1 100644 --- a/osfmk/ppc/thread_act.h +++ b/osfmk/ppc/thread_act.h @@ -33,6 +33,7 @@ #include #include #include +#include /* * Kernel state structure @@ -44,33 +45,35 @@ /* * PPC process control block * - * In the continuation model, the PCB holds the user context. It is used - * on entry to the kernel from user mode, either by system call or trap, - * to store the necessary user registers and other state. + * The PCB holds normal context. It does not contain vector or floating point + * registers. * - * Note that this structure overlays a savearea. Make sure that these - * guys are updated in concert with that. */ -struct pcb -{ - struct ppc_saved_state ss; - struct ppc_exception_state es; - struct ppc_float_state fs; - unsigned int gas1[6]; /* Force alignment with savearea */ - struct ppc_vector_state vec; +typedef struct savearea pcb; +typedef struct savearea *pcb_t; + +struct facility_context { + + savearea_fpu *FPUsave; /* The floating point savearea */ + savearea *FPUlevel; /* The floating point context level */ + unsigned int FPUcpu; /* The last processor to enable floating point */ + savearea_vec *VMXsave; /* The VMX savearea */ + savearea *VMXlevel; /* The VMX context level */ + unsigned int VMXcpu; /* The last processor to enable vector */ + struct thread_activation *facAct; /* Activation associated with context */ }; -typedef struct pcb *pcb_t; +typedef struct facility_context facility_context; /* * Maps state flavor to number of words in the state: */ extern unsigned int state_count[]; -#define USER_REGS(ThrAct) (&(ThrAct)->mact.pcb->ss) +#define USER_REGS(ThrAct) ((ThrAct)->mact.pcb) -#define user_pc(ThrAct) ((ThrAct)->mact.pcb->ss.srr0) +#define user_pc(ThrAct) ((ThrAct)->mact.pcb->save_srr0) #define act_machine_state_ptr(ThrAct) (thread_state_t)USER_REGS(ThrAct) @@ -80,13 +83,10 @@ typedef struct MachineThrAct { * one for each active facility context. They may point to the * same saveareas. */ - pcb_t pcb; /* The "normal" savearea */ - pcb_t FPU_pcb; /* The floating point savearea */ - pcb_t FPU_lvl; /* The floating point context level */ - unsigned int FPU_cpu; /* The last processor to enable floating point */ - pcb_t VMX_pcb; /* The VMX savearea */ - pcb_t VMX_lvl; /* The VMX context level */ - unsigned int VMX_cpu; /* The last processor to enable vector */ + savearea *pcb; /* The "normal" savearea */ + facility_context *curctx; /* Current facility context */ + facility_context *deferctx; /* Deferred facility context */ + facility_context facctx; /* "Normal" facility context */ struct vmmCntrlEntry *vmmCEntry; /* Pointer current emulation context or 0 */ struct vmmCntrlTable *vmmControl; /* Pointer to virtual machine monitor control table */ uint64_t qactTimer; /* Time thread needs to interrupt. This is a single-shot timer. Zero is unset */ @@ -109,6 +109,8 @@ typedef struct MachineThrAct { #define vectorCngbit 6 #define timerPopbit 7 #define userProtKeybit 8 +#define trapUnalignbit 9 +#define notifyUnalignbit 10 /* NOTE: Do not move or assign bit 31 without changing exception vector ultra fast path code */ #define bbThreadbit 28 #define bbNoMachSCbit 29 @@ -123,6 +125,8 @@ typedef struct MachineThrAct { #define vectorCng (1<<(31-vectorCngbit)) #define timerPop (1<<(31-timerPopbit)) #define userProtKey (1<<(31-userProtKeybit)) +#define trapUnalign (1<<(31-trapUnalignbit)) +#define notifyUnalign (1<<(31-notifyUnalignbit)) #define bbThread (1<<(31-bbThreadbit)) #define bbNoMachSC (1<<(31-bbNoMachSCbit)) #define bbPreemptive (1<<(31-bbPreemptivebit)) @@ -136,11 +140,16 @@ typedef struct MachineThrAct { } MachineThrAct, *MachineThrAct_t; -extern struct ppc_saved_state * find_user_regs(thread_act_t act); -extern struct ppc_float_state * find_user_fpu(thread_act_t act); +extern struct savearea *find_user_regs(thread_act_t act); +extern struct savearea *get_user_regs(thread_act_t); +extern struct savearea_fpu *find_user_fpu(thread_act_t act); +extern struct savearea_vec *find_user_vec(thread_act_t act); +extern int thread_enable_fpe(thread_act_t act, int onoff); extern void *act_thread_csave(void); extern void act_thread_catt(void *ctx); extern void act_thread_cfree(void *ctx); +#define current_act_fast() current_act() + #endif /* _PPC_THREAD_ACT_H_ */ diff --git a/osfmk/ppc/trap.c b/osfmk/ppc/trap.c index 05209b387..de7d7cd3e 100644 --- a/osfmk/ppc/trap.c +++ b/osfmk/ppc/trap.c @@ -41,10 +41,13 @@ #include /* for SR_xxx definitions */ #include #include -#include +#include +#include #include +perfTrap perfTrapHook = 0; /* Pointer to performance trap hook routine */ + #if MACH_KDB #include #include @@ -62,70 +65,73 @@ extern boolean_t db_breakpoints_inserted; #endif /* MACH_KDB */ extern int debugger_active[NCPUS]; -extern vm_address_t bsd_init_task; +extern task_t bsd_init_task; extern char init_task_failure_data[]; -/* - * XXX don't pass VM_PROT_EXECUTE to vm_fault(), execute permission is implied - * in either R or RW (note: the pmap module knows this). This is done for the - * benefit of programs that execute out of their data space (ala lisp). - * If we didn't do this in that scenerio, the ITLB miss code would call us - * and we would call vm_fault() with RX permission. However, the space was - * probably vm_allocate()ed with just RW and vm_fault would fail. The "right" - * solution to me is to have the un*x server always allocate data with RWX for - * compatibility with existing binaries. - */ -#define PROT_EXEC (VM_PROT_READ) +#define PROT_EXEC (VM_PROT_EXECUTE) #define PROT_RO (VM_PROT_READ) #define PROT_RW (VM_PROT_READ|VM_PROT_WRITE) /* A useful macro to update the ppc_exception_state in the PCB * before calling doexception */ -#define UPDATE_PPC_EXCEPTION_STATE { \ - thread_act_t thr_act = current_act(); \ - struct ppc_exception_state *es = &thr_act->mact.pcb->es; \ - es->dar = dar; \ - es->dsisr = dsisr; \ - es->exception = trapno / T_VECTOR_SIZE; /* back to powerpc */ \ +#define UPDATE_PPC_EXCEPTION_STATE { \ + thread_act_t thr_act = current_act(); \ + thr_act->mact.pcb->save_dar = dar; \ + thr_act->mact.pcb->save_dsisr = dsisr; \ + thr_act->mact.pcb->save_exception = trapno / T_VECTOR_SIZE; /* back to powerpc */ \ } static void unresolved_kernel_trap(int trapno, - struct ppc_saved_state *ssp, + struct savearea *ssp, unsigned int dsisr, unsigned int dar, char *message); -struct ppc_saved_state *trap(int trapno, - struct ppc_saved_state *ssp, +struct savearea *trap(int trapno, + struct savearea *ssp, unsigned int dsisr, unsigned int dar) { - int exception=0; + int exception; int code; int subcode; vm_map_t map; - unsigned int sp; - unsigned int space,space2; + unsigned int sp; + unsigned int space, space2; unsigned int offset; - thread_act_t thr_act = current_act(); + thread_act_t thr_act; boolean_t intr; #ifdef MACH_BSD time_value_t tv; #endif /* MACH_BSD */ + if(perfTrapHook) { /* Is there a hook? */ + if(perfTrapHook(trapno, ssp, dsisr, dar) == KERN_SUCCESS) return ssp; /* If it succeeds, we are done... */ + } + +#if 0 + { + extern void fctx_text(void); + fctx_test(); + } +#endif + + thr_act = current_act(); /* Get current activation */ + exception = 0; /* Clear exception for now */ + /* * Remember that we are disabled for interruptions when we come in here. Because * of latency concerns, we need to enable interruptions in the interrupted process * was enabled itself as soon as we can. */ - intr = (ssp->srr1 & MASK(MSR_EE)) != 0; /* Remember if we were enabled */ + intr = (ssp->save_srr1 & MASK(MSR_EE)) != 0; /* Remember if we were enabled */ /* Handle kernel traps first */ - if (!USER_MODE(ssp->srr1)) { + if (!USER_MODE(ssp->save_srr1)) { /* * Trap came from kernel */ @@ -138,10 +144,10 @@ struct ppc_saved_state *trap(int trapno, case T_RESET: /* Reset interruption */ #if 0 kprintf("*** Reset exception ignored; srr0 = %08X, srr1 = %08X\n", - ssp->srr0, ssp->srr1); + ssp->save_srr0, ssp->save_srr1); #else panic("Unexpected Reset exception; srr0 = %08X, srr1 = %08X\n", - ssp->srr0, ssp->srr1); + ssp->save_srr0, ssp->save_srr1); #endif break; /* We just ignore these */ @@ -162,6 +168,7 @@ struct ppc_saved_state *trap(int trapno, case T_FP_UNAVAILABLE: case T_IO_ERROR: case T_RESERVED: + case T_ALIGNMENT: default: unresolved_kernel_trap(trapno, ssp, dsisr, dar, NULL); break; @@ -174,7 +181,7 @@ struct ppc_saved_state *trap(int trapno, break; case T_PROGRAM: - if (ssp->srr1 & MASK(SRR1_PRG_TRAP)) { + if (ssp->save_srr1 & MASK(SRR1_PRG_TRAP)) { if (!Call_Debugger(trapno, ssp)) unresolved_kernel_trap(trapno, ssp, dsisr, dar, NULL); } else { @@ -183,12 +190,6 @@ struct ppc_saved_state *trap(int trapno, } break; - case T_ALIGNMENT: - if (alignment(dsisr, dar, ssp)) { - unresolved_kernel_trap(trapno, ssp, dsisr, dar, NULL); - } - break; - case T_DATA_ACCESS: #if MACH_KDB @@ -221,19 +222,19 @@ struct ppc_saved_state *trap(int trapno, if((0 == (dar & -PAGE_SIZE)) && /* Check for access of page 0 and */ ((thr_act->mact.specFlags) & ignoreZeroFault)) { /* special case of ignoring page zero faults */ - ssp->srr0 += 4; /* Point to next instruction */ + ssp->save_srr0 += 4; /* Point to next instruction */ break; } code = vm_fault(map, trunc_page(offset), dsisr & MASK(DSISR_WRITE) ? PROT_RW : PROT_RO, - FALSE, THREAD_UNINT); + FALSE, THREAD_UNINT, NULL, 0); if (code != KERN_SUCCESS) { unresolved_kernel_trap(trapno, ssp, dsisr, dar, NULL); } else { - ((savearea *)ssp)->save_flags |= SAVredrive; /* Tell low-level to re-try fault */ - ((savearea *)ssp)->save_dsisr |= MASK(DSISR_HASH); /* Make sure this is marked as a miss */ + ssp->save_hdr.save_flags |= SAVredrive; /* Tell low-level to re-try fault */ + ssp->save_dsisr |= MASK(DSISR_HASH); /* Make sure this is marked as a miss */ } break; } @@ -249,7 +250,7 @@ struct ppc_saved_state *trap(int trapno, code = vm_fault(map, trunc_page(offset), dsisr & MASK(DSISR_WRITE) ? PROT_RW : PROT_RO, - FALSE, THREAD_ABORTSAFE); + FALSE, THREAD_UNINT, NULL, 0); /* If we failed, there should be a recovery * spot to rfi to. @@ -259,7 +260,7 @@ struct ppc_saved_state *trap(int trapno, if (thr_act->thread->recover) { act_lock_thread(thr_act); - ssp->srr0 = thr_act->thread->recover; + ssp->save_srr0 = thr_act->thread->recover; thr_act->thread->recover = (vm_offset_t)NULL; act_unlock_thread(thr_act); @@ -268,8 +269,8 @@ struct ppc_saved_state *trap(int trapno, } } else { - ((savearea *)ssp)->save_flags |= SAVredrive; /* Tell low-level to re-try fault */ - ((savearea *)ssp)->save_dsisr |= MASK(DSISR_HASH); /* Make sure this is marked as a miss */ + ssp->save_hdr.save_flags |= SAVredrive; /* Tell low-level to re-try fault */ + ssp->save_dsisr |= MASK(DSISR_HASH); /* Make sure this is marked as a miss */ } break; @@ -295,14 +296,14 @@ struct ppc_saved_state *trap(int trapno, map = kernel_map; - code = vm_fault(map, trunc_page(ssp->srr0), - PROT_EXEC, FALSE, THREAD_UNINT); + code = vm_fault(map, trunc_page(ssp->save_srr0), + PROT_EXEC, FALSE, THREAD_UNINT, NULL, 0); if (code != KERN_SUCCESS) { unresolved_kernel_trap(trapno, ssp, dsisr, dar, NULL); } else { - ((savearea *)ssp)->save_flags |= SAVredrive; /* Tell low-level to re-try fault */ - ssp->srr1 |= MASK(DSISR_HASH); /* Make sure this is marked as a miss */ + ssp->save_hdr.save_flags |= SAVredrive; /* Tell low-level to re-try fault */ + ssp->save_srr1 |= MASK(DSISR_HASH); /* Make sure this is marked as a miss */ } break; @@ -362,21 +363,35 @@ struct ppc_saved_state *trap(int trapno, ml_set_interrupts_enabled(FALSE); /* Turn off interruptions */ panic("Unexpected user state trap(cpu %d): 0x%08x DSISR=0x%08x DAR=0x%08x PC=0x%08x, MSR=0x%08x\n", - cpu_number(), trapno, dsisr, dar, ssp->srr0, ssp->srr1); + cpu_number(), trapno, dsisr, dar, ssp->save_srr0, ssp->save_srr1); break; case T_RESET: #if 0 kprintf("*** Reset exception ignored; srr0 = %08X, srr1 = %08X\n", - ssp->srr0, ssp->srr1); + ssp->save_srr0, ssp->save_srr1); #else panic("Unexpected Reset exception: srr0 = %0x08x, srr1 = %0x08x\n", - ssp->srr0, ssp->srr1); + ssp->save_srr0, ssp->save_srr1); #endif break; /* We just ignore these */ case T_ALIGNMENT: - if (alignment(dsisr, dar, ssp)) { +/* +* If notifyUnaligned is set, we have actually already emulated the unaligned access. +* All that we want to do here is to ignore the interrupt. This is to allow logging or +* tracing of unaligned accesses. Note that if trapUnaligned is also set, it takes +* precedence and we will take a bad access fault. +*/ + + if(thr_act->mact.specFlags & notifyUnalign) { + + KERNEL_DEBUG_CONSTANT( + MACHDBG_CODE(DBG_MACH_EXCP_ALNG, 0) | DBG_FUNC_NONE, + (int)ssp->save_srr0, (int)dar, (int)dsisr, (int)ssp->save_lr, 0); + } + + if((!(thr_act->mact.specFlags & notifyUnalign)) || (thr_act->mact.specFlags & trapUnalign)) { code = EXC_PPC_UNALIGNED; exception = EXC_BAD_ACCESS; subcode = dar; @@ -394,36 +409,36 @@ struct ppc_saved_state *trap(int trapno, case T_RUNMODE_TRACE: /* 601 PPC chips */ exception = EXC_BREAKPOINT; code = EXC_PPC_TRACE; - subcode = ssp->srr0; + subcode = ssp->save_srr0; break; case T_PROGRAM: - if (ssp->srr1 & MASK(SRR1_PRG_FE)) { - fpu_save(thr_act); + if (ssp->save_srr1 & MASK(SRR1_PRG_FE)) { + fpu_save(thr_act->mact.curctx); UPDATE_PPC_EXCEPTION_STATE; exception = EXC_ARITHMETIC; code = EXC_ARITHMETIC; mp_disable_preemption(); - subcode = current_act()->mact.FPU_pcb->fs.fpscr; + subcode = ssp->save_fpscr; mp_enable_preemption(); } - else if (ssp->srr1 & MASK(SRR1_PRG_ILL_INS)) { + else if (ssp->save_srr1 & MASK(SRR1_PRG_ILL_INS)) { UPDATE_PPC_EXCEPTION_STATE exception = EXC_BAD_INSTRUCTION; code = EXC_PPC_UNIPL_INST; - subcode = ssp->srr0; - } else if (ssp->srr1 & MASK(SRR1_PRG_PRV_INS)) { + subcode = ssp->save_srr0; + } else if (ssp->save_srr1 & MASK(SRR1_PRG_PRV_INS)) { UPDATE_PPC_EXCEPTION_STATE; exception = EXC_BAD_INSTRUCTION; code = EXC_PPC_PRIVINST; - subcode = ssp->srr0; - } else if (ssp->srr1 & MASK(SRR1_PRG_TRAP)) { + subcode = ssp->save_srr0; + } else if (ssp->save_srr1 & MASK(SRR1_PRG_TRAP)) { unsigned int inst; - if (copyin((char *) ssp->srr0, (char *) &inst, 4 )) + if (copyin((char *) ssp->save_srr0, (char *) &inst, 4 )) panic("copyin failed\n"); UPDATE_PPC_EXCEPTION_STATE; if (inst == 0x7FE00008) { @@ -433,7 +448,7 @@ struct ppc_saved_state *trap(int trapno, exception = EXC_SOFTWARE; code = EXC_PPC_TRAP; } - subcode = ssp->srr0; + subcode = ssp->save_srr0; } break; @@ -441,7 +456,7 @@ struct ppc_saved_state *trap(int trapno, UPDATE_PPC_EXCEPTION_STATE; exception = EXC_ARITHMETIC; code = EXC_PPC_ALTIVECASSIST; - subcode = ssp->srr0; + subcode = ssp->save_srr0; break; case T_DATA_ACCESS: @@ -449,15 +464,15 @@ struct ppc_saved_state *trap(int trapno, code = vm_fault(map, trunc_page(dar), dsisr & MASK(DSISR_WRITE) ? PROT_RW : PROT_RO, - FALSE, THREAD_ABORTSAFE); + FALSE, THREAD_ABORTSAFE, NULL, 0); if ((code != KERN_SUCCESS) && (code != KERN_ABORTED)) { UPDATE_PPC_EXCEPTION_STATE; exception = EXC_BAD_ACCESS; subcode = dar; } else { - ((savearea *)ssp)->save_flags |= SAVredrive; /* Tell low-level to re-try fault */ - ((savearea *)ssp)->save_dsisr |= MASK(DSISR_HASH); /* Make sure this is marked as a miss */ + ssp->save_hdr.save_flags |= SAVredrive; /* Tell low-level to re-try fault */ + ssp->save_dsisr |= MASK(DSISR_HASH); /* Make sure this is marked as a miss */ } break; @@ -467,16 +482,16 @@ struct ppc_saved_state *trap(int trapno, */ map = thr_act->map; - code = vm_fault(map, trunc_page(ssp->srr0), - PROT_EXEC, FALSE, THREAD_ABORTSAFE); + code = vm_fault(map, trunc_page(ssp->save_srr0), + PROT_EXEC, FALSE, THREAD_ABORTSAFE, NULL, 0); if ((code != KERN_SUCCESS) && (code != KERN_ABORTED)) { UPDATE_PPC_EXCEPTION_STATE; exception = EXC_BAD_ACCESS; - subcode = ssp->srr0; + subcode = ssp->save_srr0; } else { - ((savearea *)ssp)->save_flags |= SAVredrive; /* Tell low-level to re-try fault */ - ssp->srr1 |= MASK(DSISR_HASH); /* Make sure this is marked as a miss */ + ssp->save_hdr.save_flags |= SAVredrive; /* Tell low-level to re-try fault */ + ssp->save_srr1 |= MASK(DSISR_HASH); /* Make sure this is marked as a miss */ } break; @@ -490,7 +505,7 @@ struct ppc_saved_state *trap(int trapno, { void bsd_uprofil(time_value_t *, unsigned int); - bsd_uprofil(&tv, ssp->srr0); + bsd_uprofil(&tv, ssp->save_srr0); } #endif /* MACH_BSD */ } @@ -513,24 +528,24 @@ struct ppc_saved_state *trap(int trapno, if ((i % 8) == 0) { buf += sprintf(buf, "\n%4d :",i); } - buf += sprintf(buf, " %08x",*(&ssp->r0+i)); + buf += sprintf(buf, " %08x",*(&ssp->save_r0+i)); } buf += sprintf(buf, "\n\n"); - buf += sprintf(buf, "cr = 0x%08x\t\t",ssp->cr); - buf += sprintf(buf, "xer = 0x%08x\n",ssp->xer); - buf += sprintf(buf, "lr = 0x%08x\t\t",ssp->lr); - buf += sprintf(buf, "ctr = 0x%08x\n",ssp->ctr); - buf += sprintf(buf, "srr0(iar) = 0x%08x\t\t",ssp->srr0); - buf += sprintf(buf, "srr1(msr) = 0x%08B\n",ssp->srr1, + buf += sprintf(buf, "cr = 0x%08x\t\t",ssp->save_cr); + buf += sprintf(buf, "xer = 0x%08x\n",ssp->save_xer); + buf += sprintf(buf, "lr = 0x%08x\t\t",ssp->save_lr); + buf += sprintf(buf, "ctr = 0x%08x\n",ssp->save_ctr); + buf += sprintf(buf, "srr0(iar) = 0x%08x\t\t",ssp->save_srr0); + buf += sprintf(buf, "srr1(msr) = 0x%08B\n",ssp->save_srr1, "\x10\x11""EE\x12PR\x13""FP\x14ME\x15""FE0\x16SE\x18" "FE1\x19""AL\x1a""EP\x1bIT\x1c""DT"); buf += sprintf(buf, "\n\n"); /* generate some stack trace */ buf += sprintf(buf, "Application level back trace:\n"); - if (ssp->srr1 & MASK(MSR_PR)) { - char *addr = (char*)ssp->r1; + if (ssp->save_srr1 & MASK(MSR_PR)) { + char *addr = (char*)ssp->save_r1; unsigned int stack_buf[3]; for (i = 0; i < 8; i++) { if (addr == (char*)NULL) @@ -553,7 +568,7 @@ struct ppc_saved_state *trap(int trapno, * Check to see if we need an AST, if so take care of it here */ ml_set_interrupts_enabled(FALSE); - if (USER_MODE(ssp->srr1)) + if (USER_MODE(ssp->save_srr1)) while (ast_needed(cpu_number())) { ast_taken(AST_ALL, intr); ml_set_interrupts_enabled(FALSE); @@ -566,28 +581,28 @@ struct ppc_saved_state *trap(int trapno, * It must preserve r3. */ -extern int syscall_trace(int, struct ppc_saved_state *); +extern int syscall_trace(int, struct savearea *); extern int pmdebug; -int syscall_trace(int retval, struct ppc_saved_state *ssp) +int syscall_trace(int retval, struct savearea *ssp) { int i, argc; int kdarg[3]; /* Always prepare to trace mach system calls */ - if (kdebug_enable && (ssp->r0 & 0x80000000)) { + if (kdebug_enable && (ssp->save_r0 & 0x80000000)) { /* Mach trap */ kdarg[0]=0; kdarg[1]=0; kdarg[2]=0; - argc = mach_trap_table[-(ssp->r0)].mach_trap_arg_count; + argc = mach_trap_table[-(ssp->save_r0)].mach_trap_arg_count; if (argc > 3) argc = 3; for (i=0; i < argc; i++) - kdarg[i] = (int)*(&ssp->r3 + i); - KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_SC, (-(ssp->r0))) | DBG_FUNC_START, + kdarg[i] = (int)*(&ssp->save_r3 + i); + KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_SC, (-(ssp->save_r0))) | DBG_FUNC_START, kdarg[0], kdarg[1], kdarg[2], 0, 0); } @@ -598,13 +613,13 @@ int syscall_trace(int retval, struct ppc_saved_state *ssp) * It must preserve r3. */ -extern int syscall_trace_end(int, struct ppc_saved_state *); +extern int syscall_trace_end(int, struct savearea *); -int syscall_trace_end(int retval, struct ppc_saved_state *ssp) +int syscall_trace_end(int retval, struct savearea *ssp) { - if (kdebug_enable && (ssp->r0 & 0x80000000)) { + if (kdebug_enable && (ssp->save_r0 & 0x80000000)) { /* Mach trap */ - KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_SC,(-(ssp->r0))) | DBG_FUNC_END, + KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_SC,(-(ssp->save_r0))) | DBG_FUNC_END, retval, 0, 0, 0, 0); } return retval; @@ -618,7 +633,7 @@ int syscall_error( int exception, int code, int subcode, - struct ppc_saved_state *ssp) + struct savearea *ssp) { register thread_t thread; @@ -627,7 +642,7 @@ int syscall_error( if (thread == 0) panic("syscall error in boot phase"); - if (!USER_MODE(ssp->srr1)) + if (!USER_MODE(ssp->save_srr1)) panic("system call called from kernel"); doexception(exception, code, subcode); @@ -693,18 +708,21 @@ char *trap_type[] = { int TRAP_TYPES = sizeof (trap_type) / sizeof (trap_type[0]); void unresolved_kernel_trap(int trapno, - struct ppc_saved_state *ssp, + struct savearea *ssp, unsigned int dsisr, unsigned int dar, char *message) { char *trap_name; - extern void print_backtrace(struct ppc_saved_state *); + extern void print_backtrace(struct savearea *); extern unsigned int debug_mode, disableDebugOuput; ml_set_interrupts_enabled(FALSE); /* Turn off interruptions */ + lastTrace = LLTraceSet(0); /* Disable low-level tracing */ - disableDebugOuput = FALSE; + if( logPanicDataToScreen ) + disableDebugOuput = FALSE; + debug_mode++; if ((unsigned)trapno <= T_MAX) trap_name = trap_type[trapno / T_VECTOR_SIZE]; @@ -713,12 +731,15 @@ void unresolved_kernel_trap(int trapno, if (message == NULL) message = trap_name; - printf("\n\nUnresolved kernel trap(cpu %d): %s DAR=0x%08x PC=0x%08x\n", - cpu_number(), trap_name, dar, ssp->srr0); + kdb_printf("\n\nUnresolved kernel trap(cpu %d): %s DAR=0x%08x PC=0x%08x\n", + cpu_number(), trap_name, dar, ssp->save_srr0); print_backtrace(ssp); - (void *)Call_Debugger(trapno, ssp); + draw_panic_dialog(); + + if( panicDebugging ) + (void *)Call_Debugger(trapno, ssp); panic(message); } @@ -727,14 +748,14 @@ thread_syscall_return( kern_return_t ret) { register thread_act_t thr_act = current_act(); - register struct ppc_saved_state *regs = USER_REGS(thr_act); + register struct savearea *regs = USER_REGS(thr_act); - if (kdebug_enable && (regs->r0 & 0x80000000)) { + if (kdebug_enable && (regs->save_r0 & 0x80000000)) { /* Mach trap */ - KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_SC,(-(regs->r0))) | DBG_FUNC_END, + KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_SC,(-(regs->save_r0))) | DBG_FUNC_END, ret, 0, 0, 0, 0); } - regs->r3 = ret; + regs->save_r3 = ret; thread_exception_return(); /*NOTREACHED*/ @@ -747,9 +768,9 @@ thread_kdb_return(void) { register thread_act_t thr_act = current_act(); register thread_t cur_thr = current_thread(); - register struct ppc_saved_state *regs = USER_REGS(thr_act); + register struct savearea *regs = USER_REGS(thr_act); - Call_Debugger(thr_act->mact.pcb->es.exception, regs); + Call_Debugger(thr_act->mact.pcb->save_exception, regs); #if MACH_LDEBUG assert(cur_thr->mutex_count == 0); #endif /* MACH_LDEBUG */ diff --git a/osfmk/ppc/trap.h b/osfmk/ppc/trap.h index 0cecf5f0c..fdc3ef828 100644 --- a/osfmk/ppc/trap.h +++ b/osfmk/ppc/trap.h @@ -65,33 +65,33 @@ #include #include +#include #include extern void doexception(int exc, int code, int sub); extern void thread_exception_return(void); -extern boolean_t alignment(unsigned long dsisr, - unsigned long dar, - struct ppc_saved_state *ssp); - -extern struct ppc_saved_state* trap(int trapno, - struct ppc_saved_state *ss, +extern struct savearea* trap(int trapno, + struct savearea *ss, unsigned int dsisr, unsigned int dar); -extern struct ppc_saved_state* interrupt(int intno, - struct ppc_saved_state *ss, +typedef kern_return_t (*perfTrap)(int trapno, struct savearea *ss, + unsigned int dsisr, unsigned int dar); + +extern perfTrap perfTrapHook; + +extern struct savearea* interrupt(int intno, + struct savearea *ss, unsigned int dsisr, unsigned int dar); extern int syscall_error(int exception, int code, int subcode, - struct ppc_saved_state *ss); - + struct savearea *ss); -extern int procitab(unsigned, void (*)(int), int); #endif /* ASSEMBLER */ diff --git a/osfmk/ppc/vmachmon.c b/osfmk/ppc/vmachmon.c index d46f6e1da..ae22aab36 100644 --- a/osfmk/ppc/vmachmon.c +++ b/osfmk/ppc/vmachmon.c @@ -282,7 +282,9 @@ int vmm_init_context(struct savearea *save) } /* Map it into the kernel's address space. */ - pmap_enter(kernel_pmap, conkern, conphys, VM_PROT_READ | VM_PROT_WRITE, TRUE); + pmap_enter(kernel_pmap, conkern, conphys, + VM_PROT_READ | VM_PROT_WRITE, + VM_WIMG_USE_DEFAULT, TRUE); /* Clear the vmm state structure. */ vks = (vmm_state_page_t *)conkern; @@ -309,12 +311,16 @@ int vmm_init_context(struct savearea *save) CTable->vmmc[cvi].vmmPmap = new_pmap; /* Remember the pmap for this guy */ CTable->vmmc[cvi].vmmContextKern = vks; /* Remember the kernel address of comm area */ CTable->vmmc[cvi].vmmContextUser = vmm_user_state; /* Remember user address of comm area */ - CTable->vmmc[cvi].vmmFPU_pcb = 0; /* Clear saved floating point context */ - CTable->vmmc[cvi].vmmFPU_cpu = -1; /* Invalidate CPU saved fp context is valid on */ - CTable->vmmc[cvi].vmmVMX_pcb = 0; /* Clear saved vector context */ - CTable->vmmc[cvi].vmmVMX_cpu = -1; /* Invalidate CPU saved vector context is valid on */ - - hw_atomic_add(&saveanchor.saveneed, 2); /* Account for the number of extra saveareas we think we might "need" */ + + CTable->vmmc[cvi].vmmFacCtx.FPUsave = 0; /* Clear facility context control */ + CTable->vmmc[cvi].vmmFacCtx.FPUlevel = 0; /* Clear facility context control */ + CTable->vmmc[cvi].vmmFacCtx.FPUcpu = 0; /* Clear facility context control */ + CTable->vmmc[cvi].vmmFacCtx.VMXsave = 0; /* Clear facility context control */ + CTable->vmmc[cvi].vmmFacCtx.VMXlevel = 0; /* Clear facility context control */ + CTable->vmmc[cvi].vmmFacCtx.VMXcpu = 0; /* Clear facility context control */ + CTable->vmmc[cvi].vmmFacCtx.facAct = act; /* Point back to the activation */ + + hw_atomic_add((int *)&saveanchor.savetarget, 2); /* Account for the number of extra saveareas we think we might "need" */ ml_set_interrupts_enabled(FALSE); /* Set back interruptions */ save->save_r3 = KERN_SUCCESS; /* Hip, hip, horay... */ @@ -358,24 +364,18 @@ kern_return_t vmm_tear_down_context( ml_set_interrupts_enabled(TRUE); /* This can take a bit of time so pass interruptions */ - hw_atomic_sub(&saveanchor.saveneed, 2); /* We don't need these extra saveareas anymore */ + hw_atomic_sub((int *)&saveanchor.savetarget, 2); /* We don't need these extra saveareas anymore */ - if(CEntry->vmmFPU_pcb) { /* Is there any floating point context? */ - sv = (savearea *)CEntry->vmmFPU_pcb; /* Make useable */ - sv->save_flags &= ~SAVfpuvalid; /* Clear in use bit */ - if(!(sv->save_flags & SAVinuse)) { /* Anyone left with this one? */ - save_release(sv); /* Nope, release it */ - } + if(CEntry->vmmFacCtx.FPUsave) { /* Is there any floating point context? */ + toss_live_fpu(&CEntry->vmmFacCtx); /* Get rid of any live context here */ + save_release((savearea *)CEntry->vmmFacCtx.FPUsave); /* Release it */ } - if(CEntry->vmmVMX_pcb) { /* Is there any vector context? */ - sv = (savearea *)CEntry->vmmVMX_pcb; /* Make useable */ - sv->save_flags &= ~SAVvmxvalid; /* Clear in use bit */ - if(!(sv->save_flags & SAVinuse)) { /* Anyone left with this one? */ - save_release(sv); /* Nope, release it */ - } + if(CEntry->vmmFacCtx.VMXsave) { /* Is there any vector context? */ + toss_live_vec(&CEntry->vmmFacCtx); /* Get rid of any live context here */ + save_release((savearea *)CEntry->vmmFacCtx.VMXsave); /* Release it */ } - + mapping_remove(CEntry->vmmPmap, 0xFFFFF000); /* Remove final page explicitly because we might have mapped it */ pmap_remove(CEntry->vmmPmap, 0, 0xFFFFF000); /* Remove all entries from this map */ pmap_destroy(CEntry->vmmPmap); /* Toss the pmap for this context */ @@ -393,10 +393,14 @@ kern_return_t vmm_tear_down_context( CEntry->vmmPmap = 0; /* Clear pmap pointer */ CEntry->vmmContextKern = 0; /* Clear the kernel address of comm area */ CEntry->vmmContextUser = 0; /* Clear the user address of comm area */ - CEntry->vmmFPU_pcb = 0; /* Clear saved floating point context */ - CEntry->vmmFPU_cpu = -1; /* Invalidate CPU saved fp context is valid on */ - CEntry->vmmVMX_pcb = 0; /* Clear saved vector context */ - CEntry->vmmVMX_cpu = -1; /* Invalidate CPU saved vector context is valid on */ + + CEntry->vmmFacCtx.FPUsave = 0; /* Clear facility context control */ + CEntry->vmmFacCtx.FPUlevel = 0; /* Clear facility context control */ + CEntry->vmmFacCtx.FPUcpu = 0; /* Clear facility context control */ + CEntry->vmmFacCtx.VMXsave = 0; /* Clear facility context control */ + CEntry->vmmFacCtx.VMXlevel = 0; /* Clear facility context control */ + CEntry->vmmFacCtx.VMXcpu = 0; /* Clear facility context control */ + CEntry->vmmFacCtx.facAct = 0; /* Clear facility context control */ CTable = act->mact.vmmControl; /* Get the control table address */ for(cvi = 0; cvi < kVmmMaxContextsPerThread; cvi++) { /* Search to find a free slot */ @@ -440,7 +444,7 @@ void vmm_tear_down_all(thread_act_t act) { spl_t s; if(act->mact.specFlags & runningVM) { /* Are we actually in a context right now? */ - save = (savearea *)find_user_regs(act); /* Find the user state context */ + save = find_user_regs(act); /* Find the user state context */ if(!save) { /* Did we find it? */ panic("vmm_tear_down_all: runningVM marked but no user state context\n"); return; @@ -562,7 +566,7 @@ kern_return_t vmm_map_page( } ml_set_interrupts_enabled(TRUE); /* Enable interruptions */ - ret = vm_fault(map, trunc_page(cva), VM_PROT_READ | VM_PROT_WRITE, FALSE); /* Didn't find it, try to fault it in read/write... */ + ret = vm_fault(map, trunc_page(cva), VM_PROT_READ | VM_PROT_WRITE, FALSE, NULL, 0); /* Didn't find it, try to fault it in read/write... */ ml_set_interrupts_enabled(FALSE); /* Disable interruptions */ if (ret != KERN_SUCCESS) return KERN_FAILURE; /* There isn't a page there, return... */ } @@ -620,6 +624,56 @@ vmm_return_code_t vmm_map_execute( } +/*----------------------------------------------------------------------- +** vmm_map_list +** +** This function maps a list of pages into the alternate's logical +** address space. +** +** Inputs: +** act - pointer to current thread activation +** index - index of vmm state for this page +** count - number of pages to release +** vmcpComm in the comm page contains up to kVmmMaxMapPages to map +** +** Outputs: +** kernel return code indicating success or failure +** KERN_FAILURE is returned if kVmmMaxUnmapPages is exceeded +** or the vmm_map_page call fails. +-----------------------------------------------------------------------*/ + +kern_return_t vmm_map_list( + thread_act_t act, + vmm_thread_index_t index, + unsigned int cnt) +{ + vmmCntrlEntry *CEntry; + boolean_t ret; + unsigned int i; + vmmMapList *lst; + vm_offset_t cva; + vm_offset_t ava; + vm_prot_t prot; + + CEntry = vmm_get_entry(act, index); /* Get and validate the index */ + if (CEntry == NULL)return -1; /* No good, failure... */ + + if(cnt > kVmmMaxMapPages) return KERN_FAILURE; /* They tried to map too many */ + if(!cnt) return KERN_SUCCESS; /* If they said none, we're done... */ + + lst = &((vmm_comm_page_t *)CEntry->vmmContextKern)->vmcpComm[0]; /* Point to the first entry */ + + for(i = 0; i < cnt; i++) { /* Step and release all pages in list */ + cva = lst[i].vmlva; /* Get the actual address */ + ava = lst[i].vmlava & -vmlFlgs; /* Get the alternate address */ + prot = lst[i].vmlava & vmlProt; /* Get the protection bits */ + ret = vmm_map_page(act, index, cva, ava, prot); /* Go try to map the page on in */ + if(ret != KERN_SUCCESS) return KERN_FAILURE; /* Bail if any error */ + } + + return KERN_SUCCESS ; /* Return... */ +} + /*----------------------------------------------------------------------- ** vmm_get_page_mapping ** @@ -714,6 +768,49 @@ kern_return_t vmm_unmap_page( return (ret ? KERN_SUCCESS : KERN_FAILURE); /* Return... */ } +/*----------------------------------------------------------------------- +** vmm_unmap_list +** +** This function unmaps a list of pages from the alternate's logical +** address space. +** +** Inputs: +** act - pointer to current thread activation +** index - index of vmm state for this page +** count - number of pages to release +** vmcpComm in the comm page contains up to kVmmMaxUnmapPages to unmap +** +** Outputs: +** kernel return code indicating success or failure +** KERN_FAILURE is returned if kVmmMaxUnmapPages is exceeded +-----------------------------------------------------------------------*/ + +kern_return_t vmm_unmap_list( + thread_act_t act, + vmm_thread_index_t index, + unsigned int cnt) +{ + vmmCntrlEntry *CEntry; + boolean_t ret; + kern_return_t kern_result = KERN_SUCCESS; + unsigned int *pgaddr, i; + + CEntry = vmm_get_entry(act, index); /* Get and validate the index */ + if (CEntry == NULL)return -1; /* No good, failure... */ + + if(cnt > kVmmMaxUnmapPages) return KERN_FAILURE; /* They tried to unmap too many */ + if(!cnt) return KERN_SUCCESS; /* If they said none, we're done... */ + + pgaddr = &((vmm_comm_page_t *)CEntry->vmmContextKern)->vmcpComm[0]; /* Point to the first entry */ + + for(i = 0; i < cnt; i++) { /* Step and release all pages in list */ + + (void)mapping_remove(CEntry->vmmPmap, pgaddr[i]); /* Toss the mapping */ + } + + return KERN_SUCCESS ; /* Return... */ +} + /*----------------------------------------------------------------------- ** vmm_unmap_all_pages ** @@ -907,23 +1004,26 @@ kern_return_t vmm_get_float_state( vmmCntrlEntry *CEntry; vmmCntrlTable *CTable; int i; - register struct savearea *sv; + register struct savearea_fpu *sv; CEntry = vmm_get_entry(act, index); /* Convert index to entry */ if (CEntry == NULL) return KERN_FAILURE; /* Either this isn't vmm thread or the index is bogus */ act->mact.specFlags &= ~floatCng; /* Clear the special flag */ CEntry->vmmContextKern->vmmStat &= ~vmmFloatCngd; /* Clear the change indication */ + + fpu_save(&CEntry->vmmFacCtx); /* Save context if live */ + + CEntry->vmmContextKern->vmm_proc_state.ppcFPSCRshadow.i[0] = CEntry->vmmContextKern->vmm_proc_state.ppcFPSCR.i[0]; /* Copy FPSCR */ + CEntry->vmmContextKern->vmm_proc_state.ppcFPSCRshadow.i[1] = CEntry->vmmContextKern->vmm_proc_state.ppcFPSCR.i[1]; /* Copy FPSCR */ - if(sv = (struct savearea *)CEntry->vmmFPU_pcb) { /* Is there context yet? */ - bcopy((char *)&sv->save_fp0, (char *)&(CEntry->vmmContextKern->vmm_proc_state.ppcFPRs[0].d), sizeof(vmm_processor_state_t)); /* 32 registers plus status and pad */ + if(sv = CEntry->vmmFacCtx.FPUsave) { /* Is there context yet? */ + bcopy((char *)&sv->save_fp0, (char *)&(CEntry->vmmContextKern->vmm_proc_state.ppcFPRs), 32 * 8); /* 32 registers */ return KERN_SUCCESS; } - CEntry->vmmContextKern->vmm_proc_state.ppcFPSCR.i[0] = 0; /* Clear FPSCR */ - CEntry->vmmContextKern->vmm_proc_state.ppcFPSCR.i[1] = 0; /* Clear FPSCR */ - for(i = 0; i < 32; i++) { /* Initialize floating points */ + for(i = 0; i < 32; i++) { /* Initialize floating points */ CEntry->vmmContextKern->vmm_proc_state.ppcFPRs[i].d = FloatInit; /* Initial value */ } @@ -953,22 +1053,24 @@ kern_return_t vmm_get_vector_state( vmmCntrlTable *CTable; int i, j; unsigned int vrvalidwrk; - register struct savearea *sv; + register struct savearea_vec *sv; CEntry = vmm_get_entry(act, index); /* Convert index to entry */ if (CEntry == NULL) return KERN_FAILURE; /* Either this isn't vmm thread or the index is bogus */ + + vec_save(&CEntry->vmmFacCtx); /* Save context if live */ act->mact.specFlags &= ~vectorCng; /* Clear the special flag */ CEntry->vmmContextKern->vmmStat &= ~vmmVectCngd; /* Clear the change indication */ - if(sv = (savearea *)CEntry->vmmVMX_pcb) { /* Is there context yet? */ + for(j=0; j < 4; j++) { /* Set value for vscr */ + CEntry->vmmContextKern->vmm_proc_state.ppcVSCRshadow.i[j] = CEntry->vmmContextKern->vmm_proc_state.ppcVSCR.i[j]; + } + + if(sv = CEntry->vmmFacCtx.VMXsave) { /* Is there context yet? */ vrvalidwrk = sv->save_vrvalid; /* Get the valid flags */ - for(j=0; j < 4; j++) { /* Set value for vscr */ - CEntry->vmmContextKern->vmm_proc_state.ppcVSCR.i[j] = sv->save_vscr[j]; - } - for(i = 0; i < 32; i++) { /* Copy the saved registers and invalidate the others */ if(vrvalidwrk & 0x80000000) { /* Do we have a valid value here? */ for(j = 0; j < 4; j++) { /* If so, copy it over */ @@ -988,10 +1090,6 @@ kern_return_t vmm_get_vector_state( return KERN_SUCCESS; } - for(j = 0; j < 4; j++) { /* Initialize vscr to java mode */ - CEntry->vmmContextKern->vmm_proc_state.ppcVSCR.i[j] = 0; /* Initial value */ - } - for(i = 0; i < 32; i++) { /* Initialize vector registers */ for(j=0; j < 4; j++) { /* Do words */ CEntry->vmmContextKern->vmm_proc_state.ppcVRs[i].i[j] = QNaNbarbarian[j]; /* Initial value */ @@ -1117,7 +1215,7 @@ void vmm_timer_pop( if(!(CTable->vmmc[cvi].vmmFlags & vmmInUse)) continue; /* Do not check if the entry is empty */ - if(CTable->vmmc[cvi].vmmTimer == 0) { /* Is the timer reset? */ + if(CTable->vmmc[cvi].vmmTimer == 0) { /* Is the timer reset? */ CTable->vmmc[cvi].vmmFlags &= ~vmmTimerPop; /* Clear timer popped */ CTable->vmmc[cvi].vmmContextKern->vmmStat &= ~vmmTimerPop; /* Clear timer popped */ continue; /* Check next */ @@ -1127,7 +1225,7 @@ void vmm_timer_pop( CTable->vmmc[cvi].vmmFlags |= vmmTimerPop; /* Set timer popped here */ CTable->vmmc[cvi].vmmContextKern->vmmStat |= vmmTimerPop; /* Set timer popped here */ if((unsigned int)&CTable->vmmc[cvi] == (unsigned int)act->mact.vmmCEntry) { /* Is this the running VM? */ - sv = (savearea *)find_user_regs(act); /* Get the user state registers */ + sv = find_user_regs(act); /* Get the user state registers */ if(!sv) { /* Did we find something? */ panic("vmm_timer_pop: no user context; act = %08X\n", act); } @@ -1304,7 +1402,7 @@ void vmm_interrupt(ReturnHandler *rh, thread_act_t act) { if(!((unsigned int)CTable & -2)) return; /* Leave if we aren't doing VMs any more... */ if(act->mact.vmmCEntry && (act->mact.vmmCEntry->vmmFlags & vmmXStop)) { /* Do we need to stop the running guy? */ - sv = (savearea *)find_user_regs(act); /* Get the user state registers */ + sv = find_user_regs(act); /* Get the user state registers */ if(!sv) { /* Did we find something? */ panic("vmm_interrupt: no user context; act = %08X\n", act); } diff --git a/osfmk/ppc/vmachmon.h b/osfmk/ppc/vmachmon.h index 2d7294888..7db97cd9f 100644 --- a/osfmk/ppc/vmachmon.h +++ b/osfmk/ppc/vmachmon.h @@ -53,9 +53,7 @@ typedef union vmm_fp_register_t { } vmm_fp_register_t; typedef struct vmm_processor_state_t { -/* - * NOTE: The general context needs to correspond to the order of the savearea for quick swaps - */ + unsigned long ppcPC; unsigned long ppcMSR; @@ -67,17 +65,21 @@ typedef struct vmm_processor_state_t { unsigned long ppcCTR; unsigned long ppcMQ; /* Obsolete */ unsigned long ppcVRSave; - unsigned long ppcReserved1[40]; /* Future processor state can go here */ + /* 32-byte bndry */ + vmm_vector_register_t ppcVSCR; + vmm_fp_register_t ppcFPSCR; + + unsigned long ppcReserved1[34]; /* Future processor state can go here */ /* We must be 16-byte aligned here */ vmm_vector_register_t ppcVRs[32]; - vmm_vector_register_t ppcVSCR; + vmm_vector_register_t ppcVSCRshadow; /* We must be 8-byte aligned here */ vmm_fp_register_t ppcFPRs[32]; - vmm_fp_register_t ppcFPSCR; + vmm_fp_register_t ppcFPSCRshadow; unsigned long ppcReserved2[2]; /* Pad out to multiple of 16 bytes */ } vmm_processor_state_t; @@ -87,7 +89,7 @@ typedef unsigned long vmm_thread_index_t; enum { kVmmCurMajorVersion = 0x0001, - kVmmCurMinorVersion = 0x0002, + kVmmCurMinorVersion = 0x0004, kVmmMinMajorVersion = 0x0001, }; #define kVmmCurrentVersion ((kVmmCurMajorVersion << 16) | kVmmCurMinorVersion) @@ -97,8 +99,9 @@ enum { kVmmFeature_LittleEndian = 0x00000001, kVmmFeature_Stop = 0x00000002, kVmmFeature_ExtendedMapping = 0x00000004, + kVmmFeature_ListMapping = 0x00000008, }; -#define kVmmCurrentFeatures (kVmmFeature_LittleEndian | kVmmFeature_Stop | kVmmFeature_ExtendedMapping) +#define kVmmCurrentFeatures (kVmmFeature_LittleEndian | kVmmFeature_Stop | kVmmFeature_ExtendedMapping | kVmmFeature_ListMapping) typedef unsigned long vmm_version_t; @@ -129,6 +132,14 @@ typedef struct vmm_state_page_t { } vmm_state_page_t; +typedef struct vmm_comm_page_t { + union { + vmm_state_page_t vmcpState; /* Reserve area for state */ + unsigned int vmcpPad[768]; /* Reserve space for 3/4 page state area */ + } vmcpfirst; + unsigned int vmcpComm[256]; /* Define last 1024 bytes as a communications area - function specific */ +} vmm_comm_page_t; + enum { /* Function Indices (passed in r3) */ kVmmGetVersion = 0, @@ -149,6 +160,8 @@ enum { kVmmProtectPage, kVmmMapExecute, kVmmProtectExecute, + kVmmMapList, + kVmmUnmapList, }; #define kVmmReturnNull 0 @@ -185,11 +198,25 @@ enum { #define kVmmProtRWRW (kVmmProtXtnd | 0x00000002) #define kVmmProtRORO (kVmmProtXtnd | 0x00000003) +/* + * Map list format + */ + +typedef struct vmmMapList { + unsigned int vmlva; /* Virtual address in emulator address space */ + unsigned int vmlava; /* Virtual address in alternate address space */ +#define vmlFlgs 0x00000FFF /* Flags passed in in vmlava low order 12 bits */ +#define vmlProt 0x00000003 /* Protection flags for the page */ +} vmmMapList; + + /************************************************************************************* Internal Emulation Types **************************************************************************************/ #define kVmmMaxContextsPerThread 32 +#define kVmmMaxUnmapPages 64 +#define kVmmMaxMapPages 64 typedef struct vmmCntrlEntry { /* Virtual Machine Monitor control table entry */ unsigned int vmmFlags; /* Assorted control flags */ @@ -210,10 +237,7 @@ typedef struct vmmCntrlEntry { /* Virtual Machine Monitor control table ent pmap_t vmmPmap; /* pmap for alternate context's view of task memory */ vmm_state_page_t *vmmContextKern; /* Kernel address of context communications area */ vmm_state_page_t *vmmContextUser; /* User address of context communications area */ - pcb_t vmmFPU_pcb; /* Saved floating point context */ - unsigned int vmmFPU_cpu; /* CPU saved fp context is valid on */ - pcb_t vmmVMX_pcb; /* Saved vector context */ - unsigned int vmmVMX_cpu; /* CPU saved vector context is valid on */ + facility_context vmmFacCtx; /* Header for vector and floating point contexts */ uint64_t vmmTimer; /* Last set timer value. Zero means unset */ vm_offset_t vmmLastMap; /* Last vaddr mapping into virtual machine */ } vmmCntrlEntry; @@ -254,6 +278,8 @@ extern void vmm_force_exit(thread_act_t act, struct savearea *); extern int vmm_stop_vm(struct savearea *save); extern void vmm_timer_pop(thread_act_t act); extern void vmm_interrupt(ReturnHandler *rh, thread_act_t act); +extern kern_return_t vmm_map_list(thread_act_t act, vmm_thread_index_t index, unsigned int cnt); +extern kern_return_t vmm_unmap_list(thread_act_t act, vmm_thread_index_t index, unsigned int cnt); #endif diff --git a/osfmk/ppc/vmachmon_asm.s b/osfmk/ppc/vmachmon_asm.s index 4b7e482b5..e3ffb412e 100644 --- a/osfmk/ppc/vmachmon_asm.s +++ b/osfmk/ppc/vmachmon_asm.s @@ -70,6 +70,8 @@ LEXT(vmm_dispatch_table) .long EXT(vmm_protect_page) ; Sets protection values for a page .long EXT(vmm_map_execute) ; Maps a page an launches VM .long EXT(vmm_protect_execute) ; Sets protection values for a page and launches VM + .long EXT(vmm_map_list) ; Maps a list of pages + .long EXT(vmm_unmap_list) ; Unmaps a list of pages .set vmm_count,(.-EXT(vmm_dispatch_table))/4 ; Get the top number @@ -236,7 +238,7 @@ swvmChkStop: b EXT(ppcscret) ; Go back to handler... swvmNoStop: - rlwinm. r26,r4,0,vmmTimerPopb,vmmTimerPopb ; Did the timer pop? + rlwinm. r26,r4,0,vmmTimerPopb,vmmTimerPopb ; Did the timer go pop? beq+ swvmDoSwitch ; No... li r2,kVmmReturnNull ; Set null return @@ -261,11 +263,10 @@ swvmDoSwitch: ; handling here is pretty funky anyway, so we just pick the ones that are ok. ; mr r26,r3 ; Save the activation pointer - mr r28,r5 ; Save the context pointer - mr r27,r2 ; Save the context entry - bl vmmxcng ; Exchange the vector and floating point contexts - mr r5,r28 ; Restore this register + la r11,vmmFacCtx(r2) ; Point to the virtual machine facility context + mr r27,r2 ; Save the context entry + stw r11,deferctx(r3) ; Start using the virtual machine facility context when we exit lwz r11,ACT_MACT_SPF(r26) ; Get the special flags lwz r3,vmmPmap(r27) ; Get the pointer to the PMAP @@ -312,35 +313,67 @@ swvmNoMap: lwz r20,vmmContextKern(r27) ; Get the comm area bl swapCtxt ; First, swap the general register state lwz r17,vmmContextKern(r27) ; Get the comm area back - + la r25,vmmFacCtx(r27) ; Point to the facility context lwz r15,vmmCntrl(r17) ; Get the control flags again + mfsprg r29,0 ; Get the per_proc +; +; Check if there is new floating point context to load +; + rlwinm. r0,r15,0,vmmFloatLoadb,vmmFloatLoadb ; Are there new floating point values? + lhz r29,PP_CPU_NUMBER(r29) ; Get our cpu number li r14,vmmppcFPRs ; Get displacement to the new values andc r15,r15,r0 ; Clear the bit beq+ swvmNoNewFloats ; Nope, good... - lwz r3,ACT_MACT_FPU(r26) ; Get the FPU savearea - dcbt r14,r18 ; Touch in first line of new stuff + lwz r19,FPUcpu(r25) ; Get the last CPU we ran on + + stw r29,FPUcpu(r25) ; Claim the context for ourselves + + eieio ; Make sure this stays in order + + lis r18,hi16(EXT(per_proc_info)) ; Set base per_proc + mulli r19,r19,ppSize ; Find offset to the owner per_proc + ori r18,r18,lo16(EXT(per_proc_info)) ; Set base per_proc + li r16,FPUowner ; Displacement to float owner + add r19,r18,r19 ; Point to the owner per_proc + li r0,0 ; Clear this out + +swvminvfpu: lwarx r18,r16,r19 ; Get the owner + cmplw r18,r25 ; Does he still have this context? + bne swvminvfpv ; Nope... + stwcx. r0,r16,r19 ; Try to invalidate it + bne- swvminvfpu ; Try again if there was a collision... + +swvminvfpv: lwz r3,FPUsave(r25) ; Get the FPU savearea + dcbt r14,r17 ; Touch in first line of new stuff mr. r3,r3 ; Is there one? bne+ swvmGotFloat ; Yes... bl EXT(save_get) ; Get a savearea - li r11,0 ; Get a 0 - lis r7,hi16(SAVfpuvalid) ; Set the allocated bit - stw r3,ACT_MACT_FPU(r26) ; Set the floating point savearea - stw r7,SAVflags(r3) ; Set the validity flags - stw r11,SAVlvlfp(r3) ; Set the context level + li r7,SAVfloat ; Get floating point flag + stw r26,SAVact(r3) ; Save our activation + li r0,0 ; Get a zero + stb r7,SAVflags+2(r3) ; Set that this is floating point + stw r0,SAVprev(r3) ; Clear the back chain + stw r0,SAVlevel(r3) ; We are always at level 0 (user state) + + stw r3,FPUsave(r25) ; Chain us to context swvmGotFloat: - dcbt r14,r17 ; Touch in first line of new stuff la r4,savefp0(r3) ; Point to the destination mr r21,r3 ; Save the save area la r3,vmmppcFPRs(r17) ; Point to the source - li r5,33*8 ; Get the size (32 FP + FPSCR at 8 bytes each) + li r5,32*8 ; Get the size (32 FPRs at 8 bytes each) bl EXT(bcopy) ; Copy the new values + + lwz r14,vmmppcFPSCRshadow(r17) ; Get the fpscr pad + lwz r10,vmmppcFPSCRshadow+4(r17) ; Get the fpscr + stw r14,savefpscrpad(r30) ; Save the new fpscr pad + stw r10,savefpscr(r30) ; Save the new fpscr lwz r11,ACT_MACT_SPF(r26) ; Get the special flags stw r15,vmmCntrl(r17) ; Save the control flags sans vmmFloatLoad @@ -351,39 +384,72 @@ swvmGotFloat: rlwinm r14,r14,0,vmmFloatCngdb+1,vmmFloatCngdb-1 ; Clear the changed flag stw r11,spcFlags(r10) ; Set per_proc copy of the special flags stw r14,vmmStat(r17) ; Set the status flags sans vmmFloatCngd - lwz r11,savefpscrpad(r21) ; Get the new fpscr pad - lwz r14,savefpscr(r21) ; Get the new fpscr - stw r11,savexfpscrpad(r30) ; Save the new fpscr pad - stw r14,savexfpscr(r30) ; Save the new fpscr +; +; Check if there is new vector context to load +; + swvmNoNewFloats: rlwinm. r0,r15,0,vmmVectLoadb,vmmVectLoadb ; Are there new vector values? li r14,vmmppcVRs ; Get displacement to the new values andc r15,r15,r0 ; Clear the bit beq+ swvmNoNewVects ; Nope, good... - lwz r3,ACT_MACT_VMX(r26) ; Get the vector savearea - dcbt r14,r27 ; Touch in first line of new stuff + lwz r19,VMXcpu(r25) ; Get the last CPU we ran on + + stw r29,VMXcpu(r25) ; Claim the context for ourselves + + eieio ; Make sure this stays in order + + lis r18,hi16(EXT(per_proc_info)) ; Set base per_proc + mulli r19,r19,ppSize ; Find offset to the owner per_proc + ori r18,r18,lo16(EXT(per_proc_info)) ; Set base per_proc + li r16,VMXowner ; Displacement to vector owner + add r19,r18,r19 ; Point to the owner per_proc + li r0,0 ; Clear this out + +swvminvvec: lwarx r18,r16,r19 ; Get the owner + cmplw r18,r25 ; Does he still have this context? + bne swvminvved ; Nope... + stwcx. r0,r16,r19 ; Try to invalidate it + bne- swvminvvec ; Try again if there was a collision... + +swvminvved: lwz r3,VMXsave(r25) ; Get the vector savearea + dcbt r14,r17 ; Touch in first line of new stuff mr. r3,r3 ; Is there one? bne+ swvmGotVect ; Yes... bl EXT(save_get) ; Get a savearea - li r21,0 ; Get a 0 - lis r7,hi16(SAVvmxvalid) ; Set the allocated bit - stw r3,ACT_MACT_VMX(r26) ; Set the vector savearea indication - stw r7,SAVflags(r3) ; Set the validity flags - stw r21,SAVlvlvec(r3) ; Set the context level + li r7,SAVvector ; Get the vector type flag + stw r26,SAVact(r3) ; Save our activation + li r0,0 ; Get a zero + stb r7,SAVflags+2(r3) ; Set that this is vector + stw r0,SAVprev(r3) ; Clear the back chain + stw r0,SAVlevel(r3) ; We are always at level 0 (user state) + + stw r3,VMXsave(r25) ; Chain us to context swvmGotVect: - dcbt r14,r17 ; Touch in first line of new stuff mr r21,r3 ; Save the pointer to the savearea la r4,savevr0(r3) ; Point to the destination la r3,vmmppcVRs(r17) ; Point to the source - li r5,33*16 ; Get the size (32 vectors + VSCR at 16 bytes each) + li r5,32*16 ; Get the size (32 vectors at 16 bytes each) bl EXT(bcopy) ; Copy the new values + lwz r11,vmmppcVSCRshadow+0(r17) ; Get the VSCR + lwz r14,vmmppcVSCRshadow+4(r17) ; Get the VSCR + lwz r10,vmmppcVSCRshadow+8(r17) ; Get the VSCR + lwz r9,vmmppcVSCRshadow+12(r17) ; Get the VSCR + lwz r8,savevrsave(r30) ; Get the current VRSave + + stw r11,savevscr+0(r30) ; Set the VSCR + stw r14,savevscr+4(r30) ; Set the VSCR + stw r10,savevscr+8(r30) ; Set the VSCR + stw r9,savevscr+12(r30) ; Set the VSCR + stw r8,savevrvalid(r21) ; Set the current VRSave as valid saved + lwz r11,ACT_MACT_SPF(r26) ; Get the special flags stw r15,vmmCntrl(r17) ; Save the control flags sans vmmVectLoad rlwinm r11,r11,0,vectorCngbit+1,vectorCngbit-1 ; Clear the changed bit here @@ -391,97 +457,15 @@ swvmGotVect: mfsprg r10,0 ; Get the per_proc stw r11,ACT_MACT_SPF(r26) ; Get the special flags rlwinm r14,r14,0,vmmVectCngdb+1,vmmVectCngdb-1 ; Clear the changed flag - eqv r15,r15,r15 ; Get all foxes stw r11,spcFlags(r10) ; Set per_proc copy of the special flags stw r14,vmmStat(r17) ; Set the status flags sans vmmVectCngd - stw r15,savevrvalid(r21) ; Set the valid bits to all foxes swvmNoNewVects: li r3,1 ; Show normal exit with check for AST - mr r9,r26 ; Move the activation pointer + lwz r16,ACT_THREAD(r26) ; Restore the thread pointer b EXT(ppcscret) ; Go back to handler... -; -; Here is where we exchange the emulator floating and vector contexts -; for the virtual machines. Remember, this is not so efficient and needs -; a rewrite. Also remember the funky register conventions (i.e., -; we need to know what our callers need saved and what our callees trash. -; -; Note: we expect R26 to contain the activation and R27 to contain the context -; entry pointer. -; - -vmmxcng: mflr r21 ; Save the return point - mr r3,r26 ; Pass in the activation - bl EXT(fpu_save) ; Save any floating point context - mr r3,r26 ; Pass in the activation - bl EXT(vec_save) ; Save any vector point context - - lis r10,hi16(EXT(per_proc_info)) ; Get top of first per_proc - li r8,PP_FPU_THREAD ; Index to FPU owner - ori r10,r10,lo16(EXT(per_proc_info)) ; Get bottom of first per_proc - lis r6,hi16(EXT(real_ncpus)) ; Get number of CPUs - li r7,0 ; Get set to clear - ori r6,r6,lo16(EXT(real_ncpus)) ; Get number of CPUs - li r9,PP_VMX_THREAD ; Index to vector owner - lwz r6,0(r6) ; Get the actual CPU count - -vmmrt1: lwarx r3,r8,r10 ; Get FPU owner - cmplw r3,r26 ; Do we own it? - bne vmmrt2 ; Nope... - stwcx. r7,r8,r10 ; Clear it - bne- vmmrt1 ; Someone else diddled, try again.... - -vmmrt2: lwarx r3,r9,r10 ; Get vector owner - cmplw r3,r26 ; Do we own it? - bne vmmxnvec ; Nope... - stwcx. r7,r9,r10 ; Clear it - bne- vmmrt2 ; Someone else diddled, try again.... - -vmmxnvec: addic. r6,r6,-1 ; Done with all CPUs? - addi r10,r10,ppSize ; On to the next - bgt vmmrt1 ; Do all processors... - -; -; At this point, the FP and Vector states for the current activation -; are saved and not live on any processor. Also, they should be the -; only contexts on the activation. Note that because we are currently -; taking the cowardly way out and insuring that no contexts are live, -; we do not need to worry about the CPU fields. -; - - lwz r8,ACT_MACT_FPU(r26) ; Get the FPU savearea - lwz r9,ACT_MACT_VMX(r26) ; Get the vector savearea - lwz r10,vmmFPU_pcb(r27) ; Get the FPU savearea - lwz r11,vmmVMX_pcb(r27) ; Get the vector savearea - li r7,0 ; Clear this - mtlr r21 ; Restore the return - stw r10,ACT_MACT_FPU(r26) ; Set the FPU savearea - stw r11,ACT_MACT_VMX(r26) ; Set the vector savearea - stw r8,vmmFPU_pcb(r27) ; Set the FPU savearea - stw r9,vmmVMX_pcb(r27) ; Set the vector savearea - stw r7,ACT_MACT_FPUlvl(r26) ; Make sure the level is clear - stw r7,ACT_MACT_VMXlvl(r26) ; Make sure the level is clear - - mr. r8,r8 ; Do we have any old floating point context? - lwz r7,savexfpscrpad(r30) ; Get first part of latest fpscr - lwz r9,savexfpscr(r30) ; Get second part of the latest fpscr - beq- xcngnold ; Nope... - stw r7,savefpscrpad(r8) ; Set first part of fpscr - stw r9,savefpscr(r8) ; Set fpscr - -xcngnold: mr. r10,r10 ; Any new context? - li r7,0 ; Assume no FP - li r9,0 ; Assume no FP - beq- xcngnnew ; Nope... - lwz r7,savefpscrpad(r10) ; Get first part of latest fpscr - lwz r9,savefpscr(r10) ; Get second part of the latest fpscr - -xcngnnew: stw r7,savexfpscrpad(r30) ; Set the fpsc - stw r9,savexfpscr(r30) ; Set the fpscr - blr ; Return... - ; ; Here is where we exit from vmm mode. We do this on any kind of exception. ; Interruptions (decrementer, external, etc.) are another story though. @@ -521,10 +505,10 @@ LEXT(vmm_exit) bl EXT(hw_set_user_space_dis) ; Swap the address spaces back to the emulator - bl vmmxcng ; Exchange the vector and floating point contexts - + la r5,facctx(r16) ; Point to the main facility context mr r2,r27 ; Restore - lwz r5,vmmContextKern(r2) ; Get the context area address + stw r5,deferctx(r16) ; Start using the main facility context on the way out + lwz r5,vmmContextKern(r27) ; Get the context area address mr r3,r16 ; Restore activation address stw r19,vmmStat(r5) ; Save the changed and popped flags bl swapCtxt ; Exchange the VM context for the emulator one @@ -578,15 +562,21 @@ LEXT(vmm_force_exit) bl EXT(hw_set_user_space_dis) ; Swap the address spaces back to the emulator - bl vmmxcng ; Exchange the vector and floating point contexts + la r7,facctx(r26) ; Point to the main facility context lwz r5,vmmContextKern(r27) ; Get the context area address stw r19,vmmStat(r5) ; Save the changed and popped flags + stw r7,deferctx(r26) ; Tell context launcher to switch facility context + bl swapCtxt ; Exchange the VM context for the emulator one lwz r8,saveexception(r30) ; Pick up the exception code + lwz r7,SAVflags(r30) ; Pick up the savearea flags + lis r9,hi16(SAVredrive) ; Get exception redrive bit rlwinm r8,r8,30,24,31 ; Convert exception to return code + andc r7,r7,r9 ; Make sure redrive is off because we are intercepting stw r8,saver3(r30) ; Set the return code as the return value also + stw r7,SAVflags(r30) ; Set the savearea flags vfeNotRun: lmw r13,FM_ARG0(r1) ; Restore all non-volatile registers @@ -597,59 +587,53 @@ vfeNotRun: lmw r13,FM_ARG0(r1) ; Restore all non-volatile registers ; ; Note: we will not do any DCBTs to the savearea. It was just stored to a few cycles ago and should -; still be in the cache. Note also that the context area registers map identically to the savearea. +; still be in the cache. ; -; NOTE: we do not save any of the non-volatile registers through this swap code ; NOTE NOTE: R16 is important to save!!!! -; NOTE: I am too dumb to figure out a faster way to swap 5 lines of memory. So I go for -; the simple way - +; .align 5 -swapCtxt: addi r6,r5,vmm_proc_state ; Point to the state - li r25,32 ; Get a cache size increment - addi r4,r30,savesrr0 ; Point to the start of the savearea - dcbt 0,r6 ; Touch in the first line of the context area +swapCtxt: la r6,vmmppcpc(r5) ; Point to the first line lwz r14,saveexception(r30) ; Get the exception code - lwz r7,savesrr0(r4) ; First line of savearea - lwz r8,savesrr1(r4) - lwz r9,saver0(r4) + dcbt 0,r6 ; Touch in the first line of the context area + lwz r7,savesrr0(r30) ; Start moving context + lwz r8,savesrr1(r30) + lwz r9,saver0(r30) cmplwi cr1,r14,T_SYSTEM_CALL ; Are we switching because of a system call? - lwz r10,saver1(r4) - lwz r11,saver2(r4) - lwz r12,saver3(r4) - lwz r13,saver4(r4) - lwz r14,saver5(r4) + lwz r10,saver1(r30) + lwz r11,saver2(r30) + lwz r12,saver3(r30) + lwz r13,saver4(r30) + la r6,vmmppcr6(r5) ; Point to second line + lwz r14,saver5(r30) - dcbt r25,r6 ; Touch second line of context area - addi r25,r25,32 ; Bump + dcbt 0,r6 ; Touch second line of context area - lwz r15,savesrr0(r6) ; First line of context + lwz r15,vmmppcpc(r5) ; First line of context lis r22,hi16(MSR_IMPORT_BITS) ; Get the MSR bits that are controllable by user - lwz r23,savesrr1(r6) + lwz r23,vmmppcmsr(r5) ori r22,r25,lo16(MSR_IMPORT_BITS) ; Get the rest of the MSR bits that are controllable by user - lwz r17,saver0(r6) - lwz r18,saver1(r6) + lwz r17,vmmppcr0(r5) + lwz r18,vmmppcr1(r5) and r23,r23,r22 ; Keep only the controllable bits - lwz r19,saver2(r6) + lwz r19,vmmppcr2(r5) oris r23,r23,hi16(MSR_EXPORT_MASK_SET) ; Force on the required bits - lwz r20,saver3(r6) + lwz r20,vmmppcr3(r5) ori r23,r23,lo16(MSR_EXPORT_MASK_SET) ; Force on the other required bits - lwz r21,saver4(r6) - lwz r22,saver5(r6) + lwz r21,vmmppcr4(r5) + lwz r22,vmmppcr5(r5) - dcbt r25,r6 ; Touch third line of context area - addi r25,r25,32 ; Bump (r25 is 64 now) + dcbt 0,r6 ; Touch third line of context area - stw r7,savesrr0(r6) ; Save emulator context into the context area - stw r8,savesrr1(r6) - stw r9,saver0(r6) - stw r10,saver1(r6) - stw r11,saver2(r6) - stw r12,saver3(r6) - stw r13,saver4(r6) - stw r14,saver5(r6) + stw r7,vmmppcpc(r5) ; Save emulator context into the context area + stw r8,vmmppcmsr(r5) + stw r9,vmmppcr0(r5) + stw r10,vmmppcr1(r5) + stw r11,vmmppcr2(r5) + stw r12,vmmppcr3(r5) + stw r13,vmmppcr4(r5) + stw r14,vmmppcr5(r5) ; ; Save the first 3 parameters if we are an SC (we will take care of the last later) @@ -659,63 +643,205 @@ swapCtxt: addi r6,r5,vmm_proc_state ; Point to the state stw r13,return_params+4(r5) ; Save the second return stw r14,return_params+8(r5) ; Save the third return -swapnotsc: stw r15,savesrr0(r4) ; Save vm context into the savearea - stw r23,savesrr1(r4) - stw r17,saver0(r4) - stw r18,saver1(r4) - stw r19,saver2(r4) - stw r20,saver3(r4) - stw r21,saver4(r4) - stw r22,saver5(r4) - -; -; The first hunk is swapped, do the rest in a loop -; - li r23,4 ; Four more hunks to swap - - -swaploop: addi r4,r4,32 ; Bump savearea pointer - addi r6,r6,32 ; Bump context area pointer - addic. r23,r23,-1 ; Count down - dcbt r25,r6 ; Touch 4th, 5th, and 6th and 7th which are extra - - lwz r7,0(r4) ; Read savearea - lwz r8,4(r4) - lwz r9,8(r4) - lwz r10,12(r4) - lwz r11,16(r4) - lwz r12,20(r4) - lwz r13,24(r4) - lwz r14,28(r4) - - lwz r15,0(r6) ; Read vm context - lwz r24,4(r6) - lwz r17,8(r6) - lwz r18,12(r6) - lwz r19,16(r6) - lwz r20,20(r6) - lwz r21,24(r6) - lwz r22,28(r6) - - stw r7,0(r6) ; Write context - stw r8,4(r6) - stw r9,8(r6) - stw r10,12(r6) - stw r11,16(r6) - stw r12,20(r6) - stw r13,24(r6) - stw r14,28(r6) - - stw r15,0(r4) ; Write vm context - stw r24,4(r4) - stw r17,8(r4) - stw r18,12(r4) - stw r19,16(r4) - stw r20,20(r4) - stw r21,24(r4) - stw r22,28(r4) - - bgt+ swaploop ; Do it all... +swapnotsc: stw r15,savesrr0(r30) ; Save vm context into the savearea + stw r23,savesrr1(r30) + stw r17,saver0(r30) + stw r18,saver1(r30) + stw r19,saver2(r30) + stw r20,saver3(r30) + stw r21,saver4(r30) + la r6,vmmppcr14(r5) ; Point to fourth line + stw r22,saver5(r30) + + dcbt 0,r6 ; Touch fourth line + +; Swap 8 registers + + lwz r7,saver6(r30) ; Read savearea + lwz r8,saver7(r30) + lwz r9,saver8(r30) + lwz r10,saver9(r30) + lwz r11,saver10(r30) + lwz r12,saver11(r30) + lwz r13,saver12(r30) + lwz r14,saver13(r30) + + lwz r15,vmmppcr6(r5) ; Read vm context + lwz r24,vmmppcr7(r5) + lwz r17,vmmppcr8(r5) + lwz r18,vmmppcr9(r5) + lwz r19,vmmppcr10(r5) + lwz r20,vmmppcr11(r5) + lwz r21,vmmppcr12(r5) + lwz r22,vmmppcr13(r5) + + stw r7,vmmppcr6(r5) ; Write context + stw r8,vmmppcr7(r5) + stw r9,vmmppcr8(r5) + stw r10,vmmppcr9(r5) + stw r11,vmmppcr10(r5) + stw r12,vmmppcr11(r5) + stw r13,vmmppcr12(r5) + la r6,vmmppcr22(r5) ; Point to fifth line + stw r14,vmmppcr13(r5) + + dcbt 0,r6 ; Touch fifth line + + stw r15,saver6(r30) ; Write vm context + stw r24,saver7(r30) + stw r17,saver8(r30) + stw r18,saver9(r30) + stw r19,saver10(r30) + stw r20,saver11(r30) + stw r21,saver12(r30) + stw r22,saver13(r30) + +; Swap 8 registers + + lwz r7,saver14(r30) ; Read savearea + lwz r8,saver15(r30) + lwz r9,saver16(r30) + lwz r10,saver17(r30) + lwz r11,saver18(r30) + lwz r12,saver19(r30) + lwz r13,saver20(r30) + lwz r14,saver21(r30) + + lwz r15,vmmppcr14(r5) ; Read vm context + lwz r24,vmmppcr15(r5) + lwz r17,vmmppcr16(r5) + lwz r18,vmmppcr17(r5) + lwz r19,vmmppcr18(r5) + lwz r20,vmmppcr19(r5) + lwz r21,vmmppcr20(r5) + lwz r22,vmmppcr21(r5) + + stw r7,vmmppcr14(r5) ; Write context + stw r8,vmmppcr15(r5) + stw r9,vmmppcr16(r5) + stw r10,vmmppcr17(r5) + stw r11,vmmppcr18(r5) + stw r12,vmmppcr19(r5) + stw r13,vmmppcr20(r5) + la r6,vmmppcr30(r5) ; Point to sixth line + stw r14,vmmppcr21(r5) + + dcbt 0,r6 ; Touch sixth line + + stw r15,saver14(r30) ; Write vm context + stw r24,saver15(r30) + stw r17,saver16(r30) + stw r18,saver17(r30) + stw r19,saver18(r30) + stw r20,saver19(r30) + stw r21,saver20(r30) + stw r22,saver21(r30) + +; Swap 8 registers + + lwz r7,saver22(r30) ; Read savearea + lwz r8,saver23(r30) + lwz r9,saver24(r30) + lwz r10,saver25(r30) + lwz r11,saver26(r30) + lwz r12,saver27(r30) + lwz r13,saver28(r30) + lwz r14,saver29(r30) + + lwz r15,vmmppcr22(r5) ; Read vm context + lwz r24,vmmppcr23(r5) + lwz r17,vmmppcr24(r5) + lwz r18,vmmppcr25(r5) + lwz r19,vmmppcr26(r5) + lwz r20,vmmppcr27(r5) + lwz r21,vmmppcr28(r5) + lwz r22,vmmppcr29(r5) + + stw r7,vmmppcr22(r5) ; Write context + stw r8,vmmppcr23(r5) + stw r9,vmmppcr24(r5) + stw r10,vmmppcr25(r5) + stw r11,vmmppcr26(r5) + stw r12,vmmppcr27(r5) + stw r13,vmmppcr28(r5) + la r6,vmmppcvscr(r5) ; Point to seventh line + stw r14,vmmppcr29(r5) + + dcbt 0,r6 ; Touch seventh line + + stw r15,saver22(r30) ; Write vm context + stw r24,saver23(r30) + stw r17,saver24(r30) + stw r18,saver25(r30) + stw r19,saver26(r30) + stw r20,saver27(r30) + stw r21,saver28(r30) + stw r22,saver29(r30) + +; Swap 8 registers + + lwz r7,saver30(r30) ; Read savearea + lwz r8,saver31(r30) + lwz r9,savecr(r30) + lwz r10,savexer(r30) + lwz r11,savelr(r30) + lwz r12,savectr(r30) + lwz r14,savevrsave(r30) + + lwz r15,vmmppcr30(r5) ; Read vm context + lwz r24,vmmppcr31(r5) + lwz r17,vmmppccr(r5) + lwz r18,vmmppcxer(r5) + lwz r19,vmmppclr(r5) + lwz r20,vmmppcctr(r5) + lwz r22,vmmppcvrsave(r5) + + stw r7,vmmppcr30(r5) ; Write context + stw r8,vmmppcr31(r5) + stw r9,vmmppccr(r5) + stw r10,vmmppcxer(r5) + stw r11,vmmppclr(r5) + stw r12,vmmppcctr(r5) + stw r14,vmmppcvrsave(r5) + + stw r15,saver30(r30) ; Write vm context + stw r24,saver31(r30) + stw r17,savecr(r30) + stw r18,savexer(r30) + stw r19,savelr(r30) + stw r20,savectr(r30) + stw r22,savevrsave(r30) + +; Swap 8 registers + + lwz r7,savevscr+0(r30) ; Read savearea + lwz r8,savevscr+4(r30) + lwz r9,savevscr+8(r30) + lwz r10,savevscr+12(r30) + lwz r11,savefpscrpad(r30) + lwz r12,savefpscr(r30) + + lwz r15,vmmppcvscr+0(r5) ; Read vm context + lwz r24,vmmppcvscr+4(r5) + lwz r17,vmmppcvscr+8(r5) + lwz r18,vmmppcvscr+12(r5) + lwz r19,vmmppcfpscrpad(r5) + lwz r20,vmmppcfpscr(r5) + + stw r7,vmmppcvscr+0(r5) ; Write context + stw r8,vmmppcvscr+4(r5) + stw r9,vmmppcvscr+8(r5) + stw r10,vmmppcvscr+12(r5) + stw r11,vmmppcfpscrpad(r5) + stw r12,vmmppcfpscr(r5) + + stw r15,savevscr+0(r30) ; Write vm context + stw r24,savevscr+4(r30) + stw r17,savevscr+8(r30) + stw r18,savevscr+12(r30) + stw r19,savefpscrpad(r30) + stw r20,savefpscr(r30) + ; ; Cobble up the exception return code and save any specific return values @@ -749,8 +875,8 @@ swapDSI: lwz r10,savedar(r30) ; Get the DAR ; Set exit returns for a ISI ; -swapISI: lwz r7,savesrr1+vmm_proc_state(r5) ; Get the SRR1 value - lwz r10,savesrr0+vmm_proc_state(r5) ; Get the PC as failing address +swapISI: lwz r7,vmmppcmsr(r5) ; Get the SRR1 value + lwz r10,vmmppcpc(r5) ; Get the PC as failing address rlwinm r7,r7,0,1,4 ; Save the bits that match the DSISR stw r10,return_params+0(r5) ; Save PC as first return parm stw r7,return_params+4(r5) ; Save the pseudo-DSISR as second return parm @@ -761,7 +887,7 @@ swapISI: lwz r7,savesrr1+vmm_proc_state(r5) ; Get the SRR1 value ; Do we really need to pass parameters back here???? ; -swapSC: lwz r10,saver6+vmm_proc_state(r5) ; Get the fourth paramter +swapSC: lwz r10,vmmppcr6(r5) ; Get the fourth paramter stw r10,return_params+12(r5) ; Save it blr ; Return... diff --git a/osfmk/sys/ioctl.h b/osfmk/sys/ioctl.h deleted file mode 100644 index b305d064d..000000000 --- a/osfmk/sys/ioctl.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * @OSF_COPYRIGHT@ - */ -/* - * HISTORY - * - * Revision 1.1.1.1 1998/09/22 21:05:48 wsanchez - * Import of Mac OS X kernel (~semeria) - * - * Revision 1.1.1.1 1998/03/07 02:25:59 wsanchez - * Import of OSF Mach kernel (~mburg) - * - * Revision 1.2.10.1 1996/11/29 16:59:52 stephen - * nmklinux_1.0b3_shared into pmk1.1 - * Moved contents to mach/mach_ioctl.h. - * [96/09/18 barbou] - * - * Revision 1.2.6.1 1994/09/23 03:12:49 ezf - * change marker to not FREE - * [1994/09/22 21:58:45 ezf] - * - * Revision 1.2.2.2 1993/06/09 02:55:17 gm - * Added to OSF/1 R1.3 from NMK15.0. - * [1993/06/02 21:30:51 jeffc] - * - * Revision 1.2 1993/04/19 17:16:43 devrcs - * Fixes for ANSI C - * [1993/02/26 14:02:24 sp] - * - * Revision 1.1 1992/09/30 02:36:52 robert - * Initial revision - * - * $EndLog$ - */ -/* CMU_HIST */ -/* - * Revision 2.5 91/10/09 16:18:46 af - * Revision 2.4.1.1 91/09/01 15:53:00 af - * Upgraded to BSD 4.4. - * [91/09/01 af] - * - * Revision 2.4.1.1 91/09/01 15:53:00 af - * Upgraded to BSD 4.4. - * [91/09/01 af] - * - * Revision 2.4 91/05/14 17:40:04 mrt - * Correcting copyright - * - * Revision 2.3 91/03/16 15:01:35 rpd - * Fixed the definitions for ANSI C. - * [91/02/20 rpd] - * - * Revision 2.2 91/02/14 15:04:02 mrt - * Changed to new Mach copyright - * - * - */ -/* CMU_ENDHIST */ -/* - * Mach Operating System - * Copyright (c) 1991 Carnegie Mellon University - * All Rights Reserved. - * - * 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 Mellon rights - * to redistribute these changes. - */ -/* - */ -/* - * Format definitions for 'ioctl' commands in device definitions. - * - * From BSD4.4. - */ - -#ifndef _SYS_IOCTL_H_ -#define _SYS_IOCTL_H_ - -#include - -#endif /* _SYS_IOCTL_H_ */ diff --git a/osfmk/vm/Makefile b/osfmk/vm/Makefile index 2339c55c6..07ae3474e 100644 --- a/osfmk/vm/Makefile +++ b/osfmk/vm/Makefile @@ -12,6 +12,7 @@ DATAFILES = EXPORT_ONLY_FILES = \ vm_map.h \ vm_kern.h \ + vm_shared_memory_server.h \ pmap.h INSTALL_MI_LIST = ${DATAFILES} diff --git a/osfmk/vm/bsd_vm.c b/osfmk/vm/bsd_vm.c index 01f6ffdef..c7136d470 100644 --- a/osfmk/vm/bsd_vm.c +++ b/osfmk/vm/bsd_vm.c @@ -36,8 +36,6 @@ #include #include -#include - #include /* BSD VM COMPONENT INTERFACES */ @@ -475,11 +473,11 @@ vnode_pager_reference( memory_object_t mem_obj) { register vnode_pager_t vnode_object; - unsigned int prev_ref_count; + unsigned int new_ref_count; vnode_object = vnode_pager_lookup(mem_obj); - prev_ref_count = OSIncrementAtomic((UInt32 *)&vnode_object->ref_count); - assert(prev_ref_count > 0); + new_ref_count = hw_atomic_add(&vnode_object->ref_count, 1); + assert(new_ref_count > 1); } /* @@ -495,7 +493,7 @@ vnode_pager_deallocate( vnode_object = vnode_pager_lookup(mem_obj); - if (OSDecrementAtomic((UInt32 *)&vnode_object->ref_count) == 1) { + if (hw_atomic_sub(&vnode_object->ref_count, 1) == 0) { if (vnode_object->vnode_handle != (vnode_port_t) NULL) { vnode_pager_vrele(vnode_object->vnode_handle); } @@ -642,7 +640,7 @@ vnode_pager_cluster_read( panic("vs_cluster_read: cnt not a multiple of PAGE_SIZE"); } - kret = vnode_pagein(vnode_object->vnode_handle, (upl_t)NULL, (vm_offset_t)NULL, offset, cnt, 2, &local_error); + kret = vnode_pagein(vnode_object->vnode_handle, (upl_t)NULL, (vm_offset_t)NULL, offset, cnt, 0, &local_error); /* if(kret == PAGER_ABSENT) { Need to work out the defs here, 1 corresponds to PAGER_ABSENT diff --git a/osfmk/vm/device_vm.c b/osfmk/vm/device_vm.c index c7fdc88bc..59532b21d 100644 --- a/osfmk/vm/device_vm.c +++ b/osfmk/vm/device_vm.c @@ -36,9 +36,6 @@ #include #include -#include - - /* Device VM COMPONENT INTERFACES */ @@ -190,13 +187,7 @@ device_pager_setup( device_object->device_handle = device_handle; device_object->size = size; - device_object->flags = 0; - if(flags & DEVICE_PAGER_CONTIGUOUS) { - device_object->flags |= DEVICE_PAGER_CONTIGUOUS; - } - if(flags & DEVICE_PAGER_NOPHYSCACHE) { - device_object->flags |= DEVICE_PAGER_NOPHYSCACHE; - } + device_object->flags = flags; return((memory_object_t)device_object); } @@ -296,6 +287,8 @@ device_pager_init(memory_object_t mem_obj, vm_object->phys_contiguous = TRUE; if(device_object->flags & DEVICE_PAGER_NOPHYSCACHE) vm_object->nophyscache = TRUE; + + vm_object->wimg_bits = device_object->flags & VM_WIMG_MASK; vm_object_unlock(vm_object); @@ -367,11 +360,11 @@ device_pager_reference( memory_object_t mem_obj) { device_pager_t device_object; - unsigned int prev_ref_count; + unsigned int new_ref_count; device_object = device_pager_lookup(mem_obj); - prev_ref_count = OSIncrementAtomic((UInt32 *)&device_object->ref_count); - assert(prev_ref_count > 0); + new_ref_count = hw_atomic_add(&device_object->ref_count, 1); + assert(new_ref_count > 1); } /* @@ -385,7 +378,7 @@ device_pager_deallocate( device_object = device_pager_lookup(mem_obj); - if (OSDecrementAtomic((UInt32 *)&device_object->ref_count) == 1) { + if (hw_atomic_sub(&device_object->ref_count, 1) == 0) { if (device_object->device_handle != (device_port_t) NULL) { device_close(device_object->device_handle); } diff --git a/osfmk/vm/memory_object.c b/osfmk/vm/memory_object.c index 318af4402..b65cc9948 100644 --- a/osfmk/vm/memory_object.c +++ b/osfmk/vm/memory_object.c @@ -776,10 +776,7 @@ BYPASS_COW_COPYIN: continue; } - PAGE_ASSERT_WAIT(m, THREAD_UNINT); - vm_object_unlock(object); - thread_block((void (*)(void))0); - vm_object_lock(object); + PAGE_SLEEP(object, m, THREAD_UNINT); continue; case MEMORY_OBJECT_LOCK_RESULT_MUST_CLEAN: @@ -812,9 +809,7 @@ BYPASS_COW_COPYIN: m->busy = FALSE; holding_page = VM_PAGE_NULL; if(m->cleaning) { - PAGE_ASSERT_WAIT(m, THREAD_UNINT); - vm_object_unlock(object); - thread_block((void (*)(void))0); + PAGE_SLEEP(object, m, THREAD_UNINT); continue; } if(!pending_pageout) { @@ -1462,9 +1457,12 @@ memory_manager_default_reference( mutex_lock(&memory_manager_default_lock); current_manager = memory_manager_default; while (current_manager == MEMORY_OBJECT_DEFAULT_NULL) { - thread_sleep_mutex((event_t) &memory_manager_default, - &memory_manager_default_lock, THREAD_UNINT); - mutex_lock(&memory_manager_default_lock); + wait_result_t res; + + res = thread_sleep_mutex((event_t) &memory_manager_default, + &memory_manager_default_lock, + THREAD_UNINT); + assert(res == THREAD_AWAKENED); current_manager = memory_manager_default; } memory_object_default_reference(current_manager); @@ -1560,7 +1558,15 @@ memory_object_deactivate_pages( } VM_PAGE_QUEUES_REMOVE(m); - queue_enter_first(&vm_page_queue_inactive, m, vm_page_t, pageq); + if(m->zero_fill) { + queue_enter_first( + &vm_page_queue_zf, + m, vm_page_t, pageq); + } else { + queue_enter_first( + &vm_page_queue_inactive, + m, vm_page_t, pageq); + } m->inactive = TRUE; if (!m->fictitious) @@ -1645,10 +1651,7 @@ memory_object_page_op( (ops & UPL_POP_BUSY)) || (ops & UPL_POP_DUMP))) { /* someone else is playing with the page, we will */ /* have to wait */ - PAGE_ASSERT_WAIT(dst_page, THREAD_UNINT); - vm_object_unlock(object); - thread_block((void(*)(void))0); - vm_object_lock(object); + PAGE_SLEEP(object, dst_page, THREAD_UNINT); continue; } diff --git a/osfmk/vm/pmap.h b/osfmk/vm/pmap.h index 1013077cb..26337c7e7 100644 --- a/osfmk/vm/pmap.h +++ b/osfmk/vm/pmap.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -61,6 +61,10 @@ #ifndef _VM_PMAP_H_ #define _VM_PMAP_H_ +#include + +#ifdef __APPLE_API_PRIVATE + #include #include #include @@ -80,7 +84,7 @@ * many address spaces. */ -#ifndef MACH_KERNEL_PRIVATE +#if !defined(MACH_KERNEL_PRIVATE) typedef void *pmap_t; @@ -163,6 +167,7 @@ extern void pmap_enter( /* Enter a mapping */ vm_offset_t v, vm_offset_t pa, vm_prot_t prot, + unsigned int flags, boolean_t wired); extern void pmap_remove_some_phys( @@ -259,6 +264,14 @@ extern kern_return_t (pmap_attribute)( /* Get/Set special memory vm_machine_attribute_t attribute, vm_machine_attribute_val_t* value); +extern kern_return_t (pmap_attribute_cache_sync)( /* Flush appropriate + * cache based on + * phys addr sent */ + vm_offset_t addr, + vm_size_t size, + vm_machine_attribute_t attribute, + vm_machine_attribute_val_t* value); + /* * Routines defined as macros. */ @@ -296,31 +309,19 @@ extern kern_return_t (pmap_attribute)( /* Get/Set special memory /* * Macro to be used in place of pmap_enter() */ -#define PMAP_ENTER(pmap, virtual_address, page, protection, wired) \ +#define PMAP_ENTER(pmap, virtual_address, page, protection, flags, wired) \ MACRO_BEGIN \ pmap_enter( \ (pmap), \ (virtual_address), \ (page)->phys_addr, \ (protection) & ~(page)->page_lock, \ + flags, \ (wired) \ ); \ MACRO_END #endif /* !PMAP_ENTER */ -#endif /* MACH_KERNEL_PRIVATE */ - -/* - * JMM - This portion is exported to other kernel components right now, - * but will be pulled back in the future when the needed functionality - * is provided in a cleaner manner. - */ - -#define PMAP_NULL ((pmap_t) 0) - -extern pmap_t kernel_pmap; /* The kernel's map */ -#define pmap_kernel() (kernel_pmap) - /* * Routines to manage reference/modify bits based on * physical addresses, simulating them if not provided @@ -340,11 +341,6 @@ extern boolean_t pmap_is_modified(vm_offset_t paddr); /* * Routines that operate on ranges of virtual addresses. */ -extern void pmap_remove( /* Remove mappings. */ - pmap_t map, - vm_offset_t s, - vm_offset_t e); - extern void pmap_protect( /* Change protections. */ pmap_t map, vm_offset_t s, @@ -357,6 +353,29 @@ extern void (pmap_pageable)( vm_offset_t end, boolean_t pageable); +#endif /* MACH_KERNEL_PRIVATE */ + +/* + * JMM - This portion is exported to other kernel components right now, + * but will be pulled back in the future when the needed functionality + * is provided in a cleaner manner. + */ + +#define PMAP_NULL ((pmap_t) 0) + +extern pmap_t kernel_pmap; /* The kernel's map */ +#define pmap_kernel() (kernel_pmap) + +/* machine independent WIMG bits */ + +#define VM_MEM_GUARDED 0x1 +#define VM_MEM_COHERENT 0x2 +#define VM_MEM_NOT_CACHEABLE 0x4 +#define VM_MEM_WRITE_THROUGH 0x8 + +#define VM_WIMG_MASK 0xFF +#define VM_WIMG_USE_DEFAULT 0x80000000 + extern void pmap_modify_pages( /* Set modify bit for pages */ pmap_t map, vm_offset_t s, @@ -369,4 +388,12 @@ extern void pmap_change_wiring( /* Specify pageability */ pmap_t pmap, vm_offset_t va, boolean_t wired); + +extern void pmap_remove( /* Remove mappings. */ + pmap_t map, + vm_offset_t s, + vm_offset_t e); + +#endif /* __APPLE_API_PRIVATE */ + #endif /* _VM_PMAP_H_ */ diff --git a/osfmk/vm/task_working_set.c b/osfmk/vm/task_working_set.c index 0fb44185e..90859e626 100644 --- a/osfmk/vm/task_working_set.c +++ b/osfmk/vm/task_working_set.c @@ -1,5 +1,6 @@ +int startup_miss = 0; /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002,2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -30,14 +31,75 @@ */ -#include +#include +#include #include +#include #include #include #include #include extern unsigned sched_tick; +extern zone_t lsf_zone; + +/* declarations for internal use only routines */ + +tws_startup_t +tws_create_startup_list( + tws_hash_t tws); + +unsigned int +tws_startup_list_lookup( + tws_startup_t startup, + vm_offset_t addr); + +kern_return_t +tws_internal_startup_send( + tws_hash_t tws); + +void +tws_traverse_address_hash_list ( + tws_hash_t tws, + unsigned int index, + vm_offset_t page_addr, + vm_object_t object, + vm_object_offset_t offset, + vm_map_t map, + tws_hash_ptr_t *target_ele, + tws_hash_ptr_t **previous_ptr, + tws_hash_ptr_t **free_list, + unsigned int exclusive_addr); + +void +tws_traverse_object_hash_list ( + tws_hash_t tws, + unsigned int index, + vm_object_t object, + vm_object_offset_t offset, + unsigned int page_mask, + tws_hash_ptr_t *target_ele, + tws_hash_ptr_t **previous_ptr, + tws_hash_ptr_t **free_list); + +tws_hash_ptr_t +new_addr_hash( + tws_hash_t tws, + unsigned int set, + unsigned int index); + +tws_hash_ptr_t +new_obj_hash( + tws_hash_t tws, + unsigned int set, + unsigned int index); + +int tws_test_for_community( + tws_hash_t tws, + vm_object_t object, + vm_object_offset_t offset, + unsigned int threshold, + unsigned int *page_mask); /* Note: all of the routines below depend on the associated map lock for */ /* synchronization, the map lock will be on when the routines are called */ @@ -63,36 +125,55 @@ tws_hash_create( if(tws == (tws_hash_t)NULL) return tws; - if((tws->table[0] = (tws_hash_ele_t *) - kalloc(sizeof(tws_hash_ele_t) * 2 * lines * rows)) + if((tws->table[0] = (tws_hash_ptr_t *) + kalloc(sizeof(tws_hash_ptr_t) * lines * rows)) == NULL) { kfree((vm_offset_t)tws, sizeof(struct tws_hash)); return (tws_hash_t)NULL; } - if((tws->alt_table[0] = (tws_hash_ele_t *) - kalloc(sizeof(tws_hash_ele_t) * 2 * lines * rows)) + if((tws->table_ele[0] = (tws_hash_ptr_t) + kalloc(sizeof(struct tws_hash_ptr) * lines * rows)) == NULL) { - kfree((vm_offset_t)tws, sizeof(struct tws_hash)); kfree((vm_offset_t)tws->table[0], sizeof(tws_hash_ele_t) - * 2 * lines * rows); + * lines * rows); + kfree((vm_offset_t)tws, sizeof(struct tws_hash)); + return (tws_hash_t)NULL; + } + if((tws->alt_ele[0] = (tws_hash_ptr_t) + kalloc(sizeof(struct tws_hash_ptr) * lines * rows)) + == NULL) { + kfree((vm_offset_t)tws->table[0], sizeof(tws_hash_ptr_t) + * lines * rows); + kfree((vm_offset_t)tws->table_ele[0], + sizeof(struct tws_hash_ptr) + * lines * rows); + kfree((vm_offset_t)tws, sizeof(struct tws_hash)); return (tws_hash_t)NULL; } if((tws->cache[0] = (struct tws_hash_line *) kalloc(sizeof(struct tws_hash_line) * lines)) == NULL) { + kfree((vm_offset_t)tws->table[0], sizeof(tws_hash_ptr_t) + * lines * rows); + kfree((vm_offset_t)tws->table_ele[0], + sizeof(struct tws_hash_ptr) + * lines * rows); + kfree((vm_offset_t)tws->alt_ele[0], sizeof(struct tws_hash_ptr) + * lines * rows); kfree((vm_offset_t)tws, sizeof(struct tws_hash)); - kfree((vm_offset_t)tws->table[0], sizeof(tws_hash_ele_t) - * 2 * lines * rows); - kfree((vm_offset_t)tws->alt_table[0], sizeof(tws_hash_ele_t) - * 2 * lines * rows); return (tws_hash_t)NULL; } + tws->free_hash_ele[0] = (tws_hash_ptr_t)0; + tws->obj_free_count[0] = 0; + tws->addr_free_count[0] = 0; /* most defaults are such that a bzero will initialize */ - bzero((char *)tws->table[0],sizeof(tws_hash_ele_t) - * 2 * lines * rows); - bzero((char *)tws->alt_table[0],sizeof(tws_hash_ele_t) - * 2 * lines * rows); + bzero((char *)tws->table[0],sizeof(tws_hash_ptr_t) + * lines * rows); + bzero((char *)tws->table_ele[0],sizeof(struct tws_hash_ptr) + * lines * rows); + bzero((char *)tws->alt_ele[0],sizeof(struct tws_hash_ptr) + * lines * rows); bzero((char *)tws->cache[0], sizeof(struct tws_hash_line) * lines); @@ -101,6 +182,8 @@ tws_hash_create( tws->current_line = 0; tws->pageout_count = 0; tws->line_count = 0; + tws->startup_cache = NULL; + tws->startup_name = NULL; tws->number_of_lines = lines; tws->number_of_elements = rows; tws->expansion_count = 1; @@ -119,9 +202,11 @@ tws_hash_line_clear( boolean_t live) { struct tws_hash_ele *hash_ele; + struct tws_hash_ptr **trailer; + struct tws_hash_ptr **free_list; + tws_hash_ele_t addr_ele; int index; unsigned int i, j, k; - int alt_index; int dump_pmap; int hash_loop; @@ -140,83 +225,99 @@ tws_hash_line_clear( } } hash_line->ele_count = 0; - for (i=0; inumber_of_elements; i++) { - hash_loop = 0; - hash_ele = &(hash_line->list[i]); - if(hash_ele->object != 0) { - vm_offset_t vaddr_off = 0; - vm_object_offset_t local_off = 0; - for (j = 0x1; j != 0; j = j<<1) { - if(j & hash_ele->page_cache) { - unsigned int alt_index; - alt_index = alt_tws_hash( - hash_ele->page_addr + vaddr_off, - tws->number_of_elements, - tws->number_of_lines); - for(k = 0; k < tws->expansion_count; k++) { - if(tws->alt_table[k][alt_index] == hash_ele) { - tws->alt_table[k][alt_index] = 0; - } - } - vaddr_off += PAGE_SIZE; - } - } - - if((hash_ele->map != NULL) && (live)) { - vm_page_t p; - - for (j = 0x1; j != 0; j = j<<1) { - if(j & hash_ele->page_cache) { - p = vm_page_lookup(hash_ele->object, + for (i=0; inumber_of_elements; i++) { + hash_loop = 0; + hash_ele = &(hash_line->list[i]); + if(hash_ele->object != 0) { + + vm_object_offset_t local_off = 0; + tws_hash_ptr_t cache_ele; + + index = alt_tws_hash( + hash_ele->page_addr & TWS_HASH_OFF_MASK, + tws->number_of_elements, + tws->number_of_lines); + + tws_traverse_address_hash_list(tws, index, + hash_ele->page_addr, hash_ele->object, + hash_ele->offset, hash_ele->map, + &cache_ele, &trailer, &free_list, 0); + if(cache_ele != NULL) { + addr_ele = (tws_hash_ele_t)((unsigned int) + (cache_ele->element) & ~TWS_ADDR_HASH); + if(addr_ele != hash_ele) + panic("tws_hash_line_clear:" + " out of sync\n"); + cache_ele->element = 0; + *trailer = cache_ele->next; + cache_ele->next = *free_list; + *free_list = cache_ele; + } + + index = alt_tws_hash( + (hash_ele->page_addr - 0x1f000) + & TWS_HASH_OFF_MASK, + tws->number_of_elements, + tws->number_of_lines); + + tws_traverse_address_hash_list(tws, index, + hash_ele->page_addr, hash_ele->object, + hash_ele->offset, hash_ele->map, + &cache_ele, &trailer, &free_list, 0); + + if(cache_ele != NULL) { + addr_ele = (tws_hash_ele_t)((unsigned int) + (cache_ele->element) & ~TWS_ADDR_HASH); + if(addr_ele != hash_ele) + panic("tws_hash_line_clear: " + "out of sync\n"); + cache_ele->element = 0; + *trailer = cache_ele->next; + cache_ele->next = *free_list; + *free_list = cache_ele; + } + + + if((hash_ele->map != NULL) && (live)) { + vm_page_t p; + + for (j = 0x1; j != 0; j = j<<1) { + if(j & hash_ele->page_cache) { + p = vm_page_lookup(hash_ele->object, hash_ele->offset + local_off); - if((p != NULL) && (p->wire_count == 0) - && (dump_pmap == 1)) { - pmap_remove_some_phys((pmap_t) - vm_map_pmap(hash_ele->map), - p->phys_addr); + if((p != NULL) && (p->wire_count == 0) + && (dump_pmap == 1)) { + pmap_remove_some_phys((pmap_t) + vm_map_pmap( + hash_ele->map), + p->phys_addr); + } + } + local_off += PAGE_SIZE_64; } - } - local_off += PAGE_SIZE_64; } - } - if(tws->style == TWS_HASH_STYLE_SIGNAL) { - vm_object_deallocate(hash_ele->object); - vm_map_deallocate(hash_ele->map); - } + + if(tws->style == TWS_HASH_STYLE_SIGNAL) { + vm_object_deallocate(hash_ele->object); + vm_map_deallocate(hash_ele->map); + } - index = do_tws_hash(hash_ele->object, hash_ele->offset, - tws->number_of_elements, tws->number_of_lines); + index = do_tws_hash(hash_ele->object, hash_ele->offset, + tws->number_of_elements, + tws->number_of_lines); - while (hash_loop < TWS_MAX_REHASH) { - for(k = 0; k < tws->expansion_count; k++) { - if((tws->table[k][index] != 0) && - (tws->table[k][index] == hash_ele)) { - tws->table[k][index] = 0; - break; - } - if(k < tws->expansion_count) - break; + tws_traverse_object_hash_list(tws, + index, hash_ele->object, hash_ele->offset, + 0xFFFFFFFF, &cache_ele, &trailer, &free_list); + if((cache_ele != NULL) && (cache_ele->element == hash_ele)) { + cache_ele->element = 0; + *trailer = cache_ele->next; + cache_ele->next = *free_list; + *free_list = cache_ele; } - index += 17; - if(index >= (2 * - tws->number_of_lines - * tws->number_of_elements)) { - index = index - (2 * - tws->number_of_lines - * tws->number_of_elements); - } - hash_loop++; + hash_ele->object = 0; } - hash_ele->object = 0; - hash_ele->page_cache = 0; - -if(newtest != 0) { - if (hash_loop == TWS_MAX_REHASH) { - panic("tws_hash_line_clear: Cache and Hash out of sync\n"); - } -} - } } } @@ -227,10 +328,14 @@ tws_lookup( vm_object_t object, tws_hash_line_t *line) { - struct tws_hash_ele *hash_ele; int index; - int k; int loop; + int set; + int ele_line; + vm_offset_t pagenum; + tws_hash_ptr_t cache_ele; + tws_hash_ptr_t *trailer; + tws_hash_ptr_t *free_list; /* don't cache private objects */ if(object->private) @@ -247,45 +352,54 @@ tws_lookup( tws->lookup_count++; if(tws->lookup_count == 0) tws->insert_count = 0; - while (loop < TWS_MAX_REHASH) { - for(k=0; kexpansion_count; k++) { - if((hash_ele = tws->table[k][index]) != 0) { - if((hash_ele->offset == (offset & TWS_HASH_OFF_MASK)) - && (hash_ele->object == object)) { - vm_offset_t pagenum; - - pagenum = (vm_offset_t) - (offset & TWS_INDEX_MASK); - pagenum = pagenum >> 12; - - if((1<page_cache) { - int set; - int ele_line; + if(tws->startup_name != NULL) { + int age_of_cache; + age_of_cache = ((sched_tick + - tws->time_of_creation) >> SCHED_TICK_SHIFT); + if (age_of_cache > 35) { + tws_unlock(tws); + return KERN_OPERATION_TIMED_OUT; + } + } - set = hash_ele->line/tws->number_of_lines; - ele_line = hash_ele->line - set; - *line = &tws->cache[k][ele_line]; - tws_unlock(tws); - return KERN_SUCCESS; + if(tws->lookup_count > (4 * tws->expansion_count + * tws->number_of_elements * tws->number_of_lines) && + (tws->lookup_count > (2 * tws->insert_count))) { + if(tws->startup_cache) { + int age_of_cache; + age_of_cache = ((sched_tick + - tws->time_of_creation) >> SCHED_TICK_SHIFT); + if (age_of_cache > 60) { + tws_unlock(tws); + return KERN_OPERATION_TIMED_OUT; } - } - } - } - index += 17; - if(index >= (2 * tws->number_of_lines * tws->number_of_elements)) { - index = index - - (2 * tws->number_of_lines * tws->number_of_elements); - } - loop++; + } } + + pagenum = (vm_offset_t)(offset & TWS_INDEX_MASK); + pagenum = pagenum >> 12; + pagenum = 1 << pagenum; /* get the appropriate page in 32 page block */ + tws_traverse_object_hash_list(tws, index, object, offset, pagenum, + &cache_ele, &trailer, &free_list); + if(cache_ele != NULL) { + set = cache_ele->element->line/tws->number_of_lines; + ele_line = cache_ele->element->line - set; + *line = &tws->cache[set][ele_line]; + tws_unlock(tws); + return KERN_SUCCESS; + } + tws_unlock(tws); return KERN_FAILURE; + + } kern_return_t tws_expand_working_set( vm_offset_t tws, - int line_count) + int line_count, + boolean_t dump_data) { tws_hash_t new_tws; tws_hash_t old_tws; @@ -307,14 +421,15 @@ tws_expand_working_set( } tws_lock(old_tws); - for(i = 0; inumber_of_lines; i++) { - for(j = 0; jnumber_of_elements; j++) { - for(k = 0; kexpansion_count; k++) { - tws_hash_ele_t entry; - vm_object_offset_t paddr; - unsigned int page_index; - entry = &old_tws->cache[k][i].list[j]; - if(entry->object != 0) { + if(!dump_data) { + for(i = 0; inumber_of_lines; i++) { + for(j = 0; jnumber_of_elements; j++) { + for(k = 0; kexpansion_count; k++) { + tws_hash_ele_t entry; + vm_object_offset_t paddr; + unsigned int page_index; + entry = &old_tws->cache[k][i].list[j]; + if(entry->object != 0) { paddr = 0; for(page_index = 1; page_index != 0; page_index = page_index << 1); { @@ -328,8 +443,9 @@ tws_expand_working_set( paddr+=PAGE_SIZE; } - } - } + } + } + } } } @@ -343,8 +459,12 @@ tws_expand_working_set( temp.lookup_count = new_tws->lookup_count; temp.insert_count = new_tws->insert_count; for(i = 0; iexpansion_count; i++) { + temp.obj_free_count[i] = new_tws->obj_free_count[i]; + temp.addr_free_count[i] = new_tws->addr_free_count[i]; + temp.free_hash_ele[i] = new_tws->free_hash_ele[i]; temp.table[i] = new_tws->table[i]; - temp.alt_table[i] = new_tws->alt_table[i]; + temp.table_ele[i] = new_tws->table_ele[i]; + temp.alt_ele[i] = new_tws->alt_ele[i]; temp.cache[i] = new_tws->cache[i]; } @@ -358,8 +478,12 @@ tws_expand_working_set( new_tws->lookup_count = old_tws->lookup_count; new_tws->insert_count = old_tws->insert_count; for(i = 0; iexpansion_count; i++) { + new_tws->obj_free_count[i] = old_tws->obj_free_count[i]; + new_tws->addr_free_count[i] = old_tws->addr_free_count[i]; + new_tws->free_hash_ele[i] = old_tws->free_hash_ele[i]; new_tws->table[i] = old_tws->table[i]; - new_tws->alt_table[i] = old_tws->alt_table[i]; + new_tws->table_ele[i] = old_tws->table_ele[i]; + new_tws->alt_ele[i] = old_tws->alt_ele[i]; new_tws->cache[i] = old_tws->cache[i]; } @@ -373,8 +497,12 @@ tws_expand_working_set( old_tws->lookup_count = temp.lookup_count; old_tws->insert_count = temp.insert_count; for(i = 0; iobj_free_count[i] = temp.obj_free_count[i];; + old_tws->addr_free_count[i] = temp.addr_free_count[i];; + old_tws->free_hash_ele[i] = NULL; old_tws->table[i] = temp.table[i]; - old_tws->alt_table[i] = temp.alt_table[i]; + old_tws->table_ele[i] = temp.table_ele[i]; + old_tws->alt_ele[i] = temp.alt_ele[i]; old_tws->cache[i] = temp.cache[i]; } @@ -383,6 +511,8 @@ tws_expand_working_set( return KERN_SUCCESS; } +tws_hash_t test_tws = 0; + kern_return_t tws_insert( tws_hash_t tws, @@ -392,17 +522,25 @@ tws_insert( vm_map_t map) { queue_t bucket; - struct tws_hash_ele *new_entry; unsigned int index; unsigned int alt_index; + unsigned int index_enum[2]; unsigned int ele_index; - unsigned int page_index; + tws_hash_ptr_t cache_ele; + tws_hash_ptr_t obj_ele = NULL; + tws_hash_ptr_t addr_ele = NULL; + tws_hash_ptr_t *trailer; + tws_hash_ptr_t *free_list; + tws_hash_ele_t target_element = NULL; int i,k; - int alt_k; - int alt_hash_count; int current_line; int set; - int hash_loop; + int ctr; + unsigned int startup_cache_line; + vm_offset_t startup_page_addr; + int cache_full = 0; + int ask_for_startup_cache_release = 0; + if(!tws_lock_try(tws)) { return KERN_FAILURE; @@ -410,133 +548,177 @@ tws_insert( tws->insert_count++; current_line = 0xFFFFFFFF; + startup_cache_line = 0; + startup_page_addr = + page_addr - (offset - (offset & TWS_HASH_OFF_MASK)); + if(tws->startup_cache) { + int age_of_cache; + age_of_cache = ((sched_tick - tws->time_of_creation) + >> SCHED_TICK_SHIFT); + startup_cache_line = tws_startup_list_lookup( + tws->startup_cache, startup_page_addr); +if(tws == test_tws) { +printf("cache_lookup, result = 0x%x, addr = 0x%x, object 0x%x, offset 0x%x%x\n", startup_cache_line, startup_page_addr, object, offset); +} + if(age_of_cache > 60) { + ask_for_startup_cache_release = 1; + } + } + if((tws->startup_name != NULL) && (tws->mod == 0)) { + /* Ensure as good a working set as possible */ + pmap_remove(map->pmap, 0, GLOBAL_SHARED_TEXT_SEGMENT); + pmap_remove(map->pmap, + GLOBAL_SHARED_DATA_SEGMENT + + SHARED_DATA_REGION_SIZE, 0xFFFFF000); + } + /* This next bit of code, the and alternate hash */ /* are all made necessary because of IPC COW */ - alt_index = alt_tws_hash(page_addr, + /* Note: the use of page_addr modified by delta from offset */ + /* frame base means we may miss some previous entries. However */ + /* we will not miss the present entry. This is most important */ + /* in avoiding duplication of entries against long lived non-cow */ + /* objects */ + index_enum[0] = alt_tws_hash( + page_addr & TWS_HASH_OFF_MASK, tws->number_of_elements, tws->number_of_lines); - for(alt_k=0; alt_kexpansion_count; alt_k++) { - new_entry = tws->alt_table[alt_k][alt_index]; - if((new_entry == 0) || (new_entry->object == 0)) { - tws->alt_table[alt_k][alt_index] = 0; - continue; - } - if(!((new_entry->offset == (offset & TWS_HASH_OFF_MASK)) - && (new_entry->object == object))) { - - tws->alt_table[alt_k][alt_index] = 0; - - index = do_tws_hash( - new_entry->object, new_entry->offset, - tws->number_of_elements, tws->number_of_lines); - - hash_loop = 0; - while (hash_loop < TWS_MAX_REHASH) { - - for(k=0; kexpansion_count; k++) { - if(tws->table[k][index] == new_entry) { - break; - } - } + index_enum[1] = alt_tws_hash( + (page_addr - 0x1f000) & TWS_HASH_OFF_MASK, + tws->number_of_elements, tws->number_of_lines); - if(k == tws->expansion_count) { - index+=17; - if(index >= (2 * tws->number_of_lines - * tws->number_of_elements)) { - index = index - - (2 * tws->number_of_lines - * tws->number_of_elements); - } - } else { + for(ctr = 0; ctr < 2;) { + tws_hash_ele_t resident; + tws_traverse_address_hash_list(tws, + index_enum[ctr], page_addr, NULL, + 0, NULL, + &cache_ele, &trailer, &free_list, 1); + if(cache_ele != NULL) { + /* found one */ + resident = (tws_hash_ele_t)((unsigned int) + cache_ele->element & ~TWS_ADDR_HASH); + if((object == resident->object) && + resident->offset == + (offset & TWS_HASH_OFF_MASK)) { + /* This is our object/offset */ + resident->page_cache + |= startup_cache_line; + resident->page_cache |= + (1<<(((vm_offset_t) + (offset & TWS_INDEX_MASK))>>12)); + tws_unlock(tws); + if(ask_for_startup_cache_release) + return KERN_OPERATION_TIMED_OUT; + return KERN_SUCCESS; + } + if((object->shadow == + resident->object) && + ((resident->offset + + object->shadow_offset) + == (offset & TWS_HASH_OFF_MASK))) { + /* if we just shadowed, inherit */ + /* access pattern from parent */ + startup_cache_line |= + resident->page_cache; + /* thow out old entry */ + resident->page_cache = 0; break; - } - hash_loop++; - + } else { + resident->page_cache &= + ~(1<<(((vm_offset_t)(page_addr + - resident->page_addr)) + >>12)); } - if((k < tws->expansion_count) && - (tws->table[k][index] == new_entry)) { - page_index = (offset & TWS_INDEX_MASK) >> 12; - new_entry->page_cache &= - ~((unsigned int)(1 << page_index)); - - if(new_entry->page_cache == 0) { - + /* Throw out old entry if there are no */ + /* more pages in cache */ + if(resident->page_cache == 0) { + /* delete addr hash entry */ + cache_ele->element = 0; + *trailer = cache_ele->next; + cache_ele->next = *free_list; + *free_list = cache_ele; + /* go after object hash */ + index = do_tws_hash( + resident->object, + resident->offset, + tws->number_of_elements, + tws->number_of_lines); + tws_traverse_object_hash_list(tws, + index, resident->object, + resident->offset, + 0xFFFFFFFF, &cache_ele, + &trailer, &free_list); + if(cache_ele != NULL) { if(tws->style == - TWS_HASH_STYLE_SIGNAL) { + TWS_HASH_STYLE_SIGNAL) { vm_object_deallocate( - new_entry->object); + cache_ele->element->object); vm_map_deallocate( - new_entry->map); + cache_ele->element->map); + } + current_line = + cache_ele->element->line; + set = current_line + /tws->number_of_lines; + current_line -= set * + tws->number_of_lines; + if(cache_ele->element->object != 0) { + cache_ele->element->object = 0; + tws->cache[set] + [current_line].ele_count--; } - new_entry->object = 0; - tws->table[k][index] = 0; - current_line = new_entry->line; - set = current_line/tws->number_of_lines; - current_line = current_line - - (set * tws->number_of_lines); - tws->cache[set] - [current_line].ele_count--; + cache_ele->element = 0; + *trailer = cache_ele->next; + cache_ele->next = *free_list; + *free_list = cache_ele; } - } - break; + continue; } + ctr+=1; } + /* + * We may or may not have a current line setting coming out of + * the code above. If we have a current line it means we can + * choose to back-fill the spot vacated by a previous entry. + * We have yet to do a definitive check using the original obj/off + * We will do that now and override the current line if we + * find an element + */ + index = do_tws_hash(object, offset, tws->number_of_elements, tws->number_of_lines); - alt_hash_count = 0; - /* we will do MAX_REHASH hash attempts and then give up */ - while (alt_hash_count < TWS_MAX_REHASH) { - for(k=0; kexpansion_count; k++) { - new_entry = tws->table[k][index]; - if(new_entry == NULL) - continue; - if((new_entry->object == object) && - (new_entry->offset == - (offset & TWS_HASH_OFF_MASK))) { - new_entry->page_cache |= - (1<<(((vm_offset_t) - (offset & TWS_INDEX_MASK))>>12)); - tws->alt_table[k][alt_index] = new_entry; - tws_unlock(tws); - return KERN_SUCCESS; - } - } - - alt_hash_count += 1; - index += 17; - if(index >= (2 * - tws->number_of_lines * tws->number_of_elements)) - index = index - - (2 * tws->number_of_lines * tws->number_of_elements); - } - alt_hash_count = 0; - index = do_tws_hash(object, offset, - tws->number_of_elements, tws->number_of_lines); - while (alt_hash_count < TWS_MAX_REHASH) { - for(k=0; kexpansion_count; k++) { - new_entry = tws->table[k][index]; - if(new_entry == NULL) - break; - } - if (kexpansion_count) - break; + alt_index = index_enum[0]; - alt_hash_count += 1; - index += 17; - if(index >= (2 * - tws->number_of_lines * tws->number_of_elements)) - index = index - - (2 * tws->number_of_lines * tws->number_of_elements); + tws_traverse_object_hash_list(tws, index, object, offset, + 0xFFFFFFFF, &cache_ele, &trailer, &free_list); + if(cache_ele != NULL) { + obj_ele = cache_ele; + current_line = cache_ele->element->line; + set = current_line/tws->number_of_lines; + current_line -= set * tws->number_of_lines; + target_element = cache_ele->element; + + /* Now check to see if we have a hash addr for it */ + tws_traverse_address_hash_list(tws, + alt_index, obj_ele->element->page_addr, + obj_ele->element->object, + obj_ele->element->offset, + obj_ele->element->map, + &cache_ele, &trailer, &free_list, 0); + if(cache_ele != NULL) { + addr_ele = cache_ele; + } else { + addr_ele = new_addr_hash(tws, set, alt_index); + /* if cannot allocate just do without */ + /* we'll get it next time around */ + } } - if(alt_hash_count == TWS_MAX_REHASH) { - tws_unlock(tws); - return KERN_FAILURE; - } + if(tws->style == TWS_HASH_STYLE_SIGNAL) { vm_object_reference(object); @@ -544,13 +726,17 @@ tws_insert( } if(current_line == 0xFFFFFFFF) { - current_line = tws->current_line; set = current_line/tws->number_of_lines; current_line = current_line - (set * tws->number_of_lines); +#ifdef notdef + if(cache_full) { + tws->current_line = tws->number_of_lines - 1; + } +#endif if(tws->cache[set][current_line].ele_count - >= tws->number_of_elements) { + >= tws->number_of_elements) { current_line++; tws->current_line++; if(current_line == tws->number_of_lines) { @@ -568,21 +754,36 @@ tws_insert( tws_unlock(tws); return KERN_NO_SPACE; } - if((tws->table[set] = (tws_hash_ele_t *) - kalloc(sizeof(tws_hash_ele_t) - * 2 * tws->number_of_lines + if((tws->table[set] = (tws_hash_ptr_t *) + kalloc(sizeof(tws_hash_ptr_t) + * tws->number_of_lines * tws->number_of_elements)) == NULL) { set = 0; - } else if((tws->alt_table[set] = - (tws_hash_ele_t *) - kalloc(sizeof(tws_hash_ele_t) - * 2 * tws->number_of_lines + } else if((tws->table_ele[set] = + (tws_hash_ptr_t) + kalloc(sizeof(struct tws_hash_ptr) + * tws->number_of_lines * tws->number_of_elements)) == NULL) { kfree((vm_offset_t)tws->table[set], - sizeof(tws_hash_ele_t) - * 2 * tws->number_of_lines + sizeof(tws_hash_ptr_t) + * tws->number_of_lines + * tws->number_of_elements); + set = 0; + } else if((tws->alt_ele[set] = + (tws_hash_ptr_t) + kalloc(sizeof(struct tws_hash_ptr) + * tws->number_of_lines + * tws->number_of_elements)) + == NULL) { + kfree((vm_offset_t)tws->table_ele[set], + sizeof(tws_hash_ptr_t) + * tws->number_of_lines + * tws->number_of_elements); + kfree((vm_offset_t)tws->table[set], + sizeof(struct tws_hash_ptr) + * tws->number_of_lines * tws->number_of_elements); tws->table[set] = NULL; set = 0; @@ -594,30 +795,67 @@ tws_insert( * tws->number_of_lines)) == NULL) { kfree((vm_offset_t)tws->table[set], - sizeof(tws_hash_ele_t) - * 2 * tws->number_of_lines - * tws->number_of_elements); - kfree((vm_offset_t)tws->alt_table[set], - sizeof(tws_hash_ele_t) - * 2 * tws->number_of_lines - * tws->number_of_elements); + sizeof(tws_hash_ptr_t) + * tws->number_of_lines + * tws->number_of_elements); + kfree((vm_offset_t)tws->table_ele[set], + sizeof(struct tws_hash_ptr) + * tws->number_of_lines + * tws->number_of_elements); + kfree((vm_offset_t)tws->alt_ele[set], + sizeof(struct tws_hash_ptr) + * tws->number_of_lines + * tws->number_of_elements); tws->table[set] = NULL; set = 0; } else { + tws->free_hash_ele[set] = + (tws_hash_ptr_t)0; + tws->obj_free_count[set] = 0; + tws->addr_free_count[set] = 0; bzero((char *)tws->table[set], - sizeof(tws_hash_ele_t) - * 2 * tws->number_of_lines + sizeof(tws_hash_ptr_t) + * tws->number_of_lines * tws->number_of_elements); - bzero((char *)tws->alt_table[set], - sizeof(tws_hash_ele_t) - * 2 * tws->number_of_lines + bzero((char *)tws->table_ele[set], + sizeof(struct tws_hash_ptr) + * tws->number_of_lines + * tws->number_of_elements); + bzero((char *)tws->alt_ele[set], + sizeof(struct tws_hash_ptr) + * tws->number_of_lines * tws->number_of_elements); bzero((char *)tws->cache[set], sizeof(struct tws_hash_line) * tws->number_of_lines); } } else { + int age_of_cache; + age_of_cache = + ((sched_tick - + tws->time_of_creation) + >> SCHED_TICK_SHIFT); + + if((tws->startup_cache) && + (age_of_cache > 60)) { + ask_for_startup_cache_release = 1; + } + if((tws->startup_name != NULL) && + (age_of_cache > 15)) { + tws->current_line--; + tws_unlock(tws); + return KERN_OPERATION_TIMED_OUT; + } + if((tws->startup_name != NULL) && + (age_of_cache < 15)) { + /* If we are creating a */ + /* cache, don't lose the */ + /* early info */ + tws->current_line--; + tws_unlock(tws); + return KERN_FAILURE; + } tws->lookup_count = 0; tws->insert_count = 0; set = 0; @@ -643,44 +881,67 @@ tws_insert( } } - ele_index = 0; - for(i = 0; inumber_of_elements; i++) { - if(tws->cache[set][current_line]. - list[ele_index].object == 0) { - break; + + /* set object hash element */ + if(obj_ele == NULL) { + obj_ele = new_obj_hash(tws, set, index); + if(obj_ele == NULL) { + tws->cache[set][current_line].ele_count + = tws->number_of_elements; + tws_unlock(tws); + return KERN_FAILURE; } - ele_index++; - if(ele_index >= tws->number_of_elements) - ele_index = 0; - } - if(i == tws->number_of_elements) - panic("tws_insert: no free elements"); + /* set address hash element */ + if(addr_ele == NULL) { + addr_ele = new_addr_hash(tws, set, alt_index); + } + if(target_element == NULL) { + ele_index = 0; + for(i = 0; inumber_of_elements; i++) { + if(tws->cache[set][current_line]. + list[ele_index].object == 0) { + break; + } + ele_index++; + if(ele_index >= tws->number_of_elements) + ele_index = 0; + + } + + if(i == tws->number_of_elements) + panic("tws_insert: no free elements"); - tws->cache[set][current_line].list[ele_index].object = object; - tws->cache[set][current_line].list[ele_index].offset = - offset & TWS_HASH_OFF_MASK; - tws->cache[set][current_line]. - list[ele_index].page_addr = page_addr & TWS_HASH_OFF_MASK; - tws->cache[set][current_line].list[ele_index].map = map; - tws->cache[set][current_line].list[ele_index].line = + target_element = + &(tws->cache[set][current_line].list[ele_index]); + + tws->cache[set][current_line].ele_count++; + } + + obj_ele->element = target_element; + if(addr_ele) { + addr_ele->element = (tws_hash_ele_t) + (((unsigned int)target_element) | TWS_ADDR_HASH); + } + target_element->object = object; + target_element->offset = offset & TWS_HASH_OFF_MASK; + target_element->page_addr = + page_addr - (offset - (offset & TWS_HASH_OFF_MASK)); + target_element->map = map; + target_element->line = current_line + (set * tws->number_of_lines); - tws->cache[set][current_line].list[ele_index].page_cache = + if(startup_cache_line) { + target_element->page_cache = startup_cache_line; + } + target_element->page_cache |= 1<<(((vm_offset_t)(offset & TWS_INDEX_MASK))>>12); - tws->table[k][index] = &tws->cache[set][current_line].list[ele_index]; - for(alt_k=0; alt_kexpansion_count; alt_k++) { - if(tws->alt_table[alt_k][alt_index] == 0) { - tws->alt_table[alt_k][alt_index] = - &tws->cache[set][current_line].list[ele_index]; - break; - } - } - tws->cache[set][current_line].ele_count++; tws_unlock(tws); + if(ask_for_startup_cache_release) + return KERN_OPERATION_TIMED_OUT; return KERN_SUCCESS; } @@ -756,12 +1017,17 @@ tws_build_cluster( task_t task; vm_object_offset_t before = *start; vm_object_offset_t after = *end; + vm_object_offset_t original_start = *start; + vm_object_offset_t original_end = *end; vm_size_t length = (vm_size_t)(*end - *start); vm_page_t m; kern_return_t kret; vm_object_offset_t object_size; - int pre_heat_size; - int age_of_cache; + int age_of_cache; + int pre_heat_size; + unsigned int ele_cache; + unsigned int end_cache = NULL; + unsigned int start_cache = NULL; if((object->private) || !(object->pager)) return; @@ -773,45 +1039,144 @@ tws_build_cluster( } else { object_size = object->size; } - /* - * determine age of cache in seconds - */ - age_of_cache = ((sched_tick - tws->time_of_creation) >> SCHED_TICK_SHIFT); - - if (object->internal || age_of_cache > 15 || (age_of_cache > 5 && vm_page_free_count < (vm_page_free_target * 2 ))) { - pre_heat_size = 0; + + age_of_cache = ((sched_tick + - tws->time_of_creation) >> SCHED_TICK_SHIFT); + + /* When pre-heat files are not available, resort to speculation */ + /* based on size of file */ + + if(tws->startup_cache || object->internal || age_of_cache > 15 || + (age_of_cache > 5 && + vm_page_free_count < (vm_page_free_target * 2) )) { + pre_heat_size = 0; } else { - if (object_size > (vm_object_offset_t)(1024 * 1024)) - pre_heat_size = 8 * PAGE_SIZE; - else if (object_size > (vm_object_offset_t)(128 * 1024)) - pre_heat_size = 4 * PAGE_SIZE; - else - pre_heat_size = 2 * PAGE_SIZE; + if (object_size > (vm_object_offset_t)(1024 * 1024)) + pre_heat_size = 8 * PAGE_SIZE; + else if (object_size > (vm_object_offset_t)(128 * 1024)) + pre_heat_size = 4 * PAGE_SIZE; + else + pre_heat_size = 2 * PAGE_SIZE; + } + + if ((age_of_cache < 10) && (tws->startup_cache)) { + if ((max_length >= ((*end - *start) + + (32 * PAGE_SIZE))) && + (tws_test_for_community(tws, object, + *start, 3, &ele_cache))) { + int expanded; + start_cache = ele_cache; + *start = *start & TWS_HASH_OFF_MASK; + *end = *start + (32 * PAGE_SIZE_64); + if(*end > object_size) { + *end = trunc_page(object_size); + max_length = 0; + if(before >= *end) { + *end = after; + } else { + end_cache = ele_cache; + } + } else { + end_cache = ele_cache; + } + while (max_length > ((*end - *start) + + (32 * PAGE_SIZE))) { + expanded = 0; + after = *end; + before = *start - PAGE_SIZE_64; + if((*end <= (object->size + + (32 * PAGE_SIZE_64))) && + (tws_test_for_community(tws, + object, after, + 5, &ele_cache))) { + *end = after + + (32 * PAGE_SIZE_64); + if(*end > object_size) { + *end = trunc_page(object_size); + max_length = 0; + if(*start >= *end) { + *end = after; + } + } + end_cache = ele_cache; + expanded = 1; + } + if (max_length > ((*end - *start) + + (32 * PAGE_SIZE_64))) { + break; + } + if((*start >= (32 * PAGE_SIZE_64)) && + (tws_test_for_community(tws, object, + before, 5, &ele_cache))) { + *start = before; + start_cache = ele_cache; + expanded = 1; + } + if(expanded == 0) + break; + } + + if(start_cache != NULL) { + unsigned int mask; + + for (mask = 1; mask != 0; mask = mask << 1) { + if (*start == original_start) + break; + if (!(start_cache & mask)) + *start += PAGE_SIZE_64; + else + break; + } + } + if(end_cache != NULL) { + unsigned int mask; + + for (mask = 0x80000000; + mask != 0; mask = mask >> 1) { + if (*end == original_end) + break; + if(!(end_cache & mask)) + *end -= PAGE_SIZE_64; + else + break; + } + } + + if (*start >= *end) + panic("bad clipping occurred\n"); + + return; + } } while ((length < max_length) && (object_size >= (after + PAGE_SIZE_64))) { - - if(length >= pre_heat_size) - { - if(tws_lookup(tws, after, object, + if(length >= pre_heat_size) { + if(tws_lookup(tws, after, object, &line) != KERN_SUCCESS) { vm_object_offset_t extend; extend = after + PAGE_SIZE_64; - if(tws_lookup(tws, extend, object, + if(tws_lookup(tws, extend, object, &line) != KERN_SUCCESS) { break; } - } - } - if (((object->existence_map != NULL) - && (!LOOK_FOR(object, after))) || - (vm_page_lookup(object, after) - != VM_PAGE_NULL)) { + } + } + + if ((object->existence_map != NULL) + && (!LOOK_FOR(object, after))) { break; + } + + if (vm_page_lookup(object, after) != VM_PAGE_NULL) { + /* we can bridge resident pages */ + after += PAGE_SIZE_64; + length += PAGE_SIZE; + continue; } + if (object->internal) { /* * need to acquire a real page in @@ -846,10 +1211,8 @@ tws_build_cluster( break; before -= PAGE_SIZE_64; - if(length >= pre_heat_size) - { - - if(tws_lookup(tws, before, object, + if(length >= pre_heat_size) { + if(tws_lookup(tws, before, object, &line) != KERN_SUCCESS) { vm_object_offset_t extend; @@ -857,18 +1220,24 @@ tws_build_cluster( if (extend == 0) break; extend -= PAGE_SIZE_64; - if(tws_lookup(tws, extend, object, + if(tws_lookup(tws, extend, object, &line) != KERN_SUCCESS) { break; } - } - } - if (((object->existence_map != NULL) - && (!LOOK_FOR(object, before))) || - (vm_page_lookup(object, before) - != VM_PAGE_NULL)) { + } + } + if ((object->existence_map != NULL) + && (!LOOK_FOR(object, before))) { break; } + + if (vm_page_lookup(object, before) != VM_PAGE_NULL) { + /* we can bridge resident pages */ + *start -= PAGE_SIZE_64; + length += PAGE_SIZE; + continue; + } + if (object->internal) { /* * need to acquire a real page in @@ -1029,6 +1398,441 @@ tws_line_signal( vm_map_unlock(map); } +/* tws locked on entry */ + +tws_startup_t +tws_create_startup_list( + tws_hash_t tws) +{ + + tws_startup_t startup; + unsigned int i,j,k; + unsigned int total_elements; + unsigned int startup_size; + unsigned int sindex; + unsigned int hash_index; + tws_startup_ptr_t element; + + total_elements = tws->expansion_count * + (tws->number_of_lines * tws->number_of_elements); + + startup_size = sizeof(struct tws_startup) + + (total_elements * sizeof(tws_startup_ptr_t *)) + + (total_elements * sizeof(struct tws_startup_ptr)) + + (total_elements * sizeof(struct tws_startup_ele)); + startup = (tws_startup_t)(kalloc(startup_size)); + + if(startup == NULL) + return startup; + + bzero((char *) startup, startup_size); + + startup->table = (tws_startup_ptr_t *) + (((int)startup) + (sizeof(struct tws_startup))); + startup->ele = (struct tws_startup_ptr *) + (((vm_offset_t)startup->table) + + (total_elements * sizeof(tws_startup_ptr_t))); + + startup->array = (struct tws_startup_ele *) + (((vm_offset_t)startup->ele) + + (total_elements * sizeof(struct tws_startup_ptr))); + + startup->tws_hash_size = startup_size; + startup->ele_count = 0; /* burn first hash ele, else we can't tell from zero */ + startup->array_size = total_elements; + startup->hash_count = 1; + + sindex = 0; + + + for(i = 0; inumber_of_lines; i++) { + for(j = 0; jnumber_of_elements; j++) { + for(k = 0; kexpansion_count; k++) { + tws_hash_ele_t entry; + unsigned int hash_retry; + vm_offset_t addr; + + entry = &tws->cache[k][i].list[j]; + addr = entry->page_addr; + hash_retry = 0; + if(entry->object != 0) { + /* get a hash element */ + hash_index = do_startup_hash(addr, + startup->array_size); + + if(startup->hash_count < total_elements) { + element = &(startup->ele[startup->hash_count]); + startup->hash_count += 1; + } else { + /* exit we're out of elements */ + break; + } + /* place the hash element */ + element->next = startup->table[hash_index]; + startup->table[hash_index] = (tws_startup_ptr_t) + ((int)element - (int)&startup->ele[0]); + + /* set entry OFFSET in hash element */ + element->element = (tws_startup_ele_t) + ((int)&startup->array[sindex] - + (int)&startup->array[0]); + + startup->array[sindex].page_addr = entry->page_addr; + startup->array[sindex].page_cache = entry->page_cache; + startup->ele_count++; + sindex++; + + } + } + } + } + + return startup; +} + + +/* + * Returns an entire cache line. The line is deleted from the startup + * cache on return. The caller can check startup->ele_count for an empty + * list. Access synchronization is the responsibility of the caller. + */ + +unsigned int +tws_startup_list_lookup( + tws_startup_t startup, + vm_offset_t addr) +{ + unsigned int hash_index; + unsigned int page_cache_bits; + unsigned int startup_shift; + tws_startup_ele_t entry; + vm_offset_t next_addr; + tws_startup_ptr_t element; + tws_startup_ptr_t base_ele; + tws_startup_ptr_t *previous_ptr; + + page_cache_bits = 0; + + hash_index = do_startup_hash(addr, startup->array_size); + + if(((unsigned int)&(startup->table[hash_index])) >= startup->tws_hash_size) { + return page_cache_bits = 0; + } + element = (tws_startup_ptr_t)((int)startup->table[hash_index] + + (int)&startup->ele[0]); + base_ele = element; + previous_ptr = &(startup->table[hash_index]); + while(element > &startup->ele[0]) { + if (((int)element + sizeof(struct tws_startup_ptr)) + > ((int)startup + startup->tws_hash_size)) { + return page_cache_bits; + } + entry = (tws_startup_ele_t) + ((int)element->element + + (int)&startup->array[0]); + if((((int)entry + sizeof(struct tws_startup_ele)) + > ((int)startup + startup->tws_hash_size)) + || ((int)entry < (int)startup)) { + return page_cache_bits; + } + if ((addr >= entry->page_addr) && + (addr <= (entry->page_addr + 0x1F000))) { + startup_shift = (addr - entry->page_addr)>>12; + page_cache_bits |= entry->page_cache >> startup_shift; + /* don't dump the pages, unless the addresses */ + /* line up perfectly. The cache may be used */ + /* by other mappings */ + entry->page_cache &= (1 << startup_shift) - 1; + if(addr == entry->page_addr) { + if(base_ele == element) { + base_ele = (tws_startup_ptr_t) + ((int)element->next + + (int)&startup->ele[0]); + startup->table[hash_index] = element->next; + element = base_ele; + } else { + *previous_ptr = element->next; + element = (tws_startup_ptr_t) + ((int)*previous_ptr + + (int)&startup->ele[0]); + } + entry->page_addr = 0; + startup->ele_count--; + continue; + } + } + next_addr = addr + 0x1F000; + if ((next_addr >= entry->page_addr) && + (next_addr <= (entry->page_addr + 0x1F000))) { + startup_shift = (next_addr - entry->page_addr)>>12; + page_cache_bits |= entry->page_cache << (0x1F - startup_shift); + entry->page_cache &= ~((1 << (startup_shift + 1)) - 1); + if(entry->page_cache == 0) { + if(base_ele == element) { + base_ele = (tws_startup_ptr_t) + ((int)element->next + + (int)&startup->ele[0]); + startup->table[hash_index] = element->next; + element = base_ele; + } else { + *previous_ptr = element->next; + element = (tws_startup_ptr_t) + ((int)*previous_ptr + + (int)&startup->ele[0]); + } + entry->page_addr = 0; + startup->ele_count--; + continue; + } + } + previous_ptr = &(element->next); + element = (tws_startup_ptr_t) + ((int) element->next + (int) &startup->ele[0]); + } + + return page_cache_bits; +} + +kern_return_t +tws_send_startup_info( + task_t task) +{ + + tws_hash_t tws; + tws_startup_t scache; + + task_lock(task); + tws = (tws_hash_t)task->dynamic_working_set; + task_unlock(task); + if(tws == NULL) { + return KERN_FAILURE; + } + return tws_internal_startup_send(tws); +} + + +kern_return_t +tws_internal_startup_send( + tws_hash_t tws) +{ + + tws_startup_t scache; + + if(tws == NULL) { + return KERN_FAILURE; + } + tws_lock(tws); + /* used to signal write or release depending on state of tws */ + if(tws->startup_cache) { + vm_offset_t startup_buf; + vm_size_t size; + startup_buf = (vm_offset_t)tws->startup_cache; + size = tws->startup_cache->tws_hash_size; + tws->startup_cache = 0; + tws_unlock(tws); + kmem_free(kernel_map, startup_buf, size); + return KERN_SUCCESS; + } + if(tws->startup_name == NULL) { + tws_unlock(tws); + return KERN_FAILURE; + } + scache = tws_create_startup_list(tws); + if(scache == NULL) + return KERN_FAILURE; + bsd_write_page_cache_file(tws->uid, tws->startup_name, + scache, scache->tws_hash_size, + tws->mod, tws->fid); + kfree((vm_offset_t)scache, scache->tws_hash_size); + kfree((vm_offset_t) tws->startup_name, tws->startup_name_length); + tws->startup_name = NULL; + tws_unlock(tws); + return KERN_SUCCESS; +} + +kern_return_t +tws_handle_startup_file( + task_t task, + unsigned int uid, + char *app_name, + vm_offset_t app_vp, + boolean_t *new_info) + +{ + tws_startup_t startup; + vm_offset_t cache_size; + kern_return_t error; + int fid; + int mod; + + *new_info = FALSE; + /* don't pre-heat kernel task */ + if(task == kernel_task) + return KERN_SUCCESS; + error = bsd_read_page_cache_file(uid, &fid, + &mod, app_name, + app_vp, &startup, + &cache_size); + if(error) { + return KERN_FAILURE; + } + if(startup == NULL) { + /* Entry for app does not exist, make */ + /* one */ + /* we will want our own copy of the shared */ + /* regions to pick up a true picture of all */ + /* the pages we will touch. */ + if((lsf_zone->count * lsf_zone->elem_size) + > (lsf_zone->max_size >> 1)) { + /* We don't want to run out of shared memory */ + /* map entries by starting too many private versions */ + /* of the shared library structures */ + return KERN_SUCCESS; + } + *new_info = TRUE; + error = tws_write_startup_file(task, + fid, mod, app_name, uid); + if(error) + return error; + /* use the mod in the write case as an init */ + /* flag */ + mod = 0; + + } else { + error = tws_read_startup_file(task, + (tws_startup_t)startup, + cache_size); + if(error) { + kmem_free(kernel_map, + (vm_offset_t)startup, cache_size); + return error; + } + } + return KERN_SUCCESS; +} + +kern_return_t +tws_write_startup_file( + task_t task, + int fid, + int mod, + char *name, + unsigned int uid) +{ + tws_hash_t tws; + unsigned int string_length; + + string_length = strlen(name); + + task_lock(task); + tws = (tws_hash_t)task->dynamic_working_set; + + task_unlock(task); + if(tws == NULL) { + /* create a dynamic working set of normal size */ + task_working_set_create(task, 0, + 0, TWS_HASH_STYLE_DEFAULT); + } + tws_lock(tws); + + if(tws->startup_name != NULL) { + tws_unlock(tws); + return KERN_FAILURE; + } + + tws->startup_name = (char *) + kalloc((string_length + 1) * (sizeof(char))); + if(tws->startup_name == NULL) { + tws_unlock(tws); + return KERN_FAILURE; + } + + bcopy(name, (char *)tws->startup_name, string_length + 1); + tws->startup_name_length = (string_length + 1) * sizeof(char); + tws->uid = uid; + tws->fid = fid; + tws->mod = mod; + + tws_unlock(tws); + return KERN_SUCCESS; +} + +kern_return_t +tws_read_startup_file( + task_t task, + tws_startup_t startup, + vm_offset_t cache_size) +{ + tws_hash_t tws; + int error; + int lines; + int old_exp_count; + + task_lock(task); + tws = (tws_hash_t)task->dynamic_working_set; + + if(cache_size < sizeof(struct tws_hash)) { + task_unlock(task); + kmem_free(kernel_map, (vm_offset_t)startup, cache_size); + return(KERN_SUCCESS); + } + + /* create a dynamic working set to match file size */ + lines = (cache_size - sizeof(struct tws_hash))/TWS_ARRAY_SIZE; + /* we now need to divide out element size and word size */ + /* all fields are 4 bytes. There are 8 bytes in each hash element */ + /* entry, 4 bytes in each table ptr location and 8 bytes in each */ + /* page_cache entry, making a total of 20 bytes for each entry */ + lines = (lines/(20)); + if(lines <= TWS_SMALL_HASH_LINE_COUNT) { + lines = TWS_SMALL_HASH_LINE_COUNT; + task_unlock(task); + kmem_free(kernel_map, (vm_offset_t)startup, cache_size); + return(KERN_SUCCESS); + } else { + old_exp_count = lines/TWS_HASH_LINE_COUNT; + if((old_exp_count * TWS_HASH_LINE_COUNT) != lines) { + lines = (old_exp_count + 1) + * TWS_HASH_LINE_COUNT; + } + if(tws == NULL) { + task_working_set_create(task, lines, + 0, TWS_HASH_STYLE_DEFAULT); + task_unlock(task); + } else { + task_unlock(task); + tws_expand_working_set( + (vm_offset_t)tws, lines, TRUE); + } + } + + + tws_lock(tws); + + if(tws->startup_cache != NULL) { + tws_unlock(tws); + return KERN_FAILURE; + } + + + /* now need to fix up internal table pointers */ + startup->table = (tws_startup_ptr_t *) + (((int)startup) + (sizeof(struct tws_startup))); + startup->ele = (struct tws_startup_ptr *) + (((vm_offset_t)startup->table) + + (startup->array_size * sizeof(tws_startup_ptr_t))); + startup->array = (struct tws_startup_ele *) + (((vm_offset_t)startup->ele) + + (startup->array_size * sizeof(struct tws_startup_ptr))); + /* the allocation size and file size should be the same */ + /* just in case their not, make sure we dealloc correctly */ + startup->tws_hash_size = cache_size; + + + tws->startup_cache = startup; + tws_unlock(tws); + return KERN_SUCCESS; +} void @@ -1037,6 +1841,15 @@ tws_hash_destroy(tws_hash_t tws) int i,k; vm_size_t cache_size; + if(tws->startup_cache != NULL) { + kmem_free(kernel_map, + (vm_offset_t)tws->startup_cache, + tws->startup_cache->tws_hash_size); + tws->startup_cache = NULL; + } + if(tws->startup_name != NULL) { + tws_internal_startup_send(tws); + } for (i=0; inumber_of_lines; i++) { for(k=0; kexpansion_count; k++) { /* clear the object refs */ @@ -1046,16 +1859,25 @@ tws_hash_destroy(tws_hash_t tws) i = 0; while (i < tws->expansion_count) { - kfree((vm_offset_t)tws->table[i], sizeof(tws_hash_ele_t) - * 2 * tws->number_of_lines + kfree((vm_offset_t)tws->table[i], sizeof(tws_hash_ptr_t) + * tws->number_of_lines + * tws->number_of_elements); + kfree((vm_offset_t)tws->table_ele[i], + sizeof(struct tws_hash_ptr) + * tws->number_of_lines * tws->number_of_elements); - kfree((vm_offset_t)tws->alt_table[i], sizeof(tws_hash_ele_t) - * 2 * tws->number_of_lines + kfree((vm_offset_t)tws->alt_ele[i], + sizeof(struct tws_hash_ptr) + * tws->number_of_lines * tws->number_of_elements); kfree((vm_offset_t)tws->cache[i], sizeof(struct tws_hash_line) * tws->number_of_lines); i++; } + if(tws->startup_name != NULL) { + kfree((vm_offset_t)tws->startup_name, + tws->startup_name_length); + } kfree((vm_offset_t)tws, sizeof(struct tws_hash)); } @@ -1101,3 +1923,280 @@ task_working_set_create( task_unlock(task); return KERN_SUCCESS; } + + +/* Internal use only routines */ + + +/* + * internal sub-function for address space lookup + * returns the target element and the address of the + * previous pointer The previous pointer is the address + * of the pointer pointing to the target element. + * TWS must be locked + */ + +void +tws_traverse_address_hash_list ( + tws_hash_t tws, + unsigned int index, + vm_offset_t page_addr, + vm_object_t object, + vm_object_offset_t offset, + vm_map_t map, + tws_hash_ptr_t *target_ele, + tws_hash_ptr_t **previous_ptr, + tws_hash_ptr_t **free_list, + unsigned int exclusive_addr) +{ + int k; + tws_hash_ptr_t cache_ele; + tws_hash_ptr_t base_ele; + + *target_ele = NULL; + *previous_ptr = NULL; + + for(k=0; kexpansion_count; k++) { + tws_hash_ele_t ele; + cache_ele = tws->table[k][index]; + base_ele = cache_ele; + *previous_ptr = (tws_hash_ptr_t *)&(tws->table[k][index]); + while(cache_ele != NULL) { + if(((unsigned int) + cache_ele->element & TWS_ADDR_HASH) == 0) { + *previous_ptr = (tws_hash_ptr_t *)&(cache_ele->next); + cache_ele = cache_ele->next; + continue; + } + ele = (tws_hash_ele_t)((unsigned int) + cache_ele->element & ~TWS_ADDR_HASH); + if ((ele == 0) || (ele->object == 0)) { + /* A little clean-up of empty elements */ + cache_ele->element = 0; + if(base_ele == cache_ele) { + base_ele = cache_ele->next; + tws->table[k][index] = cache_ele->next; + cache_ele->next = tws->free_hash_ele[k]; + tws->free_hash_ele[k] = cache_ele; + cache_ele = base_ele; + } else { + **previous_ptr = cache_ele->next; + cache_ele->next = tws->free_hash_ele[k]; + tws->free_hash_ele[k] = cache_ele; + cache_ele = **previous_ptr; + } + continue; + } + + if ((ele->page_addr <= page_addr) + && (page_addr <= (ele->page_addr + + (vm_offset_t)TWS_INDEX_MASK)) + && ((object == NULL) + || ((object == ele->object) + && (offset == ele->offset) + && (map == ele->map)))) { + if(exclusive_addr) { + int delta; + delta = ((page_addr - ele->page_addr) + >> 12); + if((1 << delta) & ele->page_cache) { + /* We've found a match */ + *target_ele = cache_ele; + *free_list = + (tws_hash_ptr_t *) + &(tws->free_hash_ele[k]); + return; + } + } else { + /* We've found a match */ + *target_ele = cache_ele; + *free_list = (tws_hash_ptr_t *) + &(tws->free_hash_ele[k]); + return; + } + } + *previous_ptr = (tws_hash_ptr_t *)&(cache_ele->next); + cache_ele = cache_ele->next; + } + } +} + + +/* + * internal sub-function for object space lookup + * returns the target element and the address of the + * previous pointer The previous pointer is the address + * of the pointer pointing to the target element. + * TWS must be locked + */ + + +void +tws_traverse_object_hash_list ( + tws_hash_t tws, + unsigned int index, + vm_object_t object, + vm_object_offset_t offset, + unsigned int page_mask, + tws_hash_ptr_t *target_ele, + tws_hash_ptr_t **previous_ptr, + tws_hash_ptr_t **free_list) +{ + int k; + tws_hash_ptr_t cache_ele; + tws_hash_ptr_t base_ele; + + *target_ele = NULL; + *previous_ptr = NULL; + + for(k=0; kexpansion_count; k++) { + cache_ele = tws->table[k][index]; + base_ele = cache_ele; + *previous_ptr = &(tws->table[k][index]); + while(cache_ele != NULL) { + if((((unsigned int)cache_ele->element) + & TWS_ADDR_HASH) != 0) { + *previous_ptr = &(cache_ele->next); + cache_ele = cache_ele->next; + continue; + } + if ((cache_ele->element == 0) || + (cache_ele->element->object == 0)) { + /* A little clean-up of empty elements */ + cache_ele->element = 0; + if(base_ele == cache_ele) { + base_ele = cache_ele->next; + tws->table[k][index] = cache_ele->next; + cache_ele->next = tws->free_hash_ele[k]; + tws->free_hash_ele[k] = cache_ele; + cache_ele = tws->table[k][index]; + } else { + **previous_ptr = cache_ele->next; + cache_ele->next = tws->free_hash_ele[k]; + tws->free_hash_ele[k] = cache_ele; + cache_ele = **previous_ptr; + } + continue; + } + if ((cache_ele->element->object == object) + && (cache_ele->element->offset == + (offset - (offset & ~TWS_HASH_OFF_MASK)))) { + if((cache_ele->element->page_cache & page_mask) + || (page_mask == 0xFFFFFFFF)) { + /* We've found a match */ + *target_ele = cache_ele; + *free_list = &(tws->free_hash_ele[k]); + return; + } + } + *previous_ptr = (tws_hash_ptr_t *)&(cache_ele->next); + cache_ele = cache_ele->next; + } + } +} + + +/* + * For a given object/offset, discover whether the indexed 32 page frame + * containing the object/offset exists and if their are at least threshold + * pages present. Returns true if population meets threshold. + */ +int +tws_test_for_community( + tws_hash_t tws, + vm_object_t object, + vm_object_offset_t offset, + unsigned int threshold, + unsigned int *page_mask) +{ + int index; + tws_hash_ptr_t cache_ele; + tws_hash_ptr_t *trailer; + tws_hash_ptr_t *free_list; + int community = 0; + + index = do_tws_hash(object, offset, + tws->number_of_elements, tws->number_of_lines); + tws_traverse_object_hash_list(tws, index, object, offset, 0xFFFFFFFF, + &cache_ele, &trailer, &free_list); + + if(cache_ele != NULL) { + int i; + int ctr; + ctr = 0; + for(i=1; i!=0; i=i<<1) { + if(i & cache_ele->element->page_cache) + ctr++; + if(ctr == threshold) { + community = 1; + *page_mask = cache_ele->element->page_cache; + break; + } + } + } + + return community; + +} + + +/* + * Gets new hash element for object hash from free pools + * TWS must be locked + */ + +tws_hash_ptr_t +new_obj_hash( + tws_hash_t tws, + unsigned int set, + unsigned int index) +{ + tws_hash_ptr_t element; + + if(tws->obj_free_count[set] < tws->number_of_lines * tws->number_of_elements) { + element = &(tws->table_ele[set][tws->obj_free_count[set]]); + tws->obj_free_count[set]+=1; + } else if(tws->free_hash_ele[set] == NULL) { + return NULL; + } else { + element = tws->free_hash_ele[set]; + if(element == NULL) + return element; + tws->free_hash_ele[set] = tws->free_hash_ele[set]->next; + } + element->element = 0; + element->next = tws->table[set][index]; + tws->table[set][index] = element; + return element; +} + +/* + * Gets new hash element for addr hash from free pools + * TWS must be locked + */ + +tws_hash_ptr_t +new_addr_hash( + tws_hash_t tws, + unsigned int set, + unsigned int index) +{ + tws_hash_ptr_t element; + + if(tws->addr_free_count[set] + < tws->number_of_lines * tws->number_of_elements) { + element = &(tws->alt_ele[set][tws->addr_free_count[set]]); + tws->addr_free_count[set]+=1; + } else if(tws->free_hash_ele[set] == NULL) { + return NULL; + } else { + element = tws->free_hash_ele[set]; + if(element == NULL) + return element; + tws->free_hash_ele[set] = tws->free_hash_ele[set]->next; + } + element->element = (tws_hash_ele_t)TWS_ADDR_HASH; + element->next = tws->table[set][index]; + tws->table[set][index] = element; + return element; +} diff --git a/osfmk/vm/task_working_set.h b/osfmk/vm/task_working_set.h index 2eb74691b..5c9e57f0a 100644 --- a/osfmk/vm/task_working_set.h +++ b/osfmk/vm/task_working_set.h @@ -50,35 +50,73 @@ /* of wired memory resource. */ #define TWS_SMALL_HASH_LINE_COUNT 4 -/* -#define do_tws_hash(object,offset, rows, lines) \ - ((((natural_t)(object)) + \ - (((natural_t)(offset)) >> 11) + \ - (((natural_t)(offset)) >> 12)) & \ - ((2 * rows * lines) -1)) -*/ /* * do not think of changing this hash unless you understand the implications * for the hash element page_cache field */ #define do_tws_hash(object,offset, rows, lines) \ - (((((natural_t)(object)) >> 2) + \ - ((natural_t)(object) >> 12) + \ - ((natural_t)(((vm_object_offset_t)(offset)) >> 12) \ - & 0xFFFFFFFFFFFFFFE0)) & \ - ((2 * rows * lines) -1)) -/* -#define do_tws_hash(object,offset, rows, lines) \ - (((((natural_t)(object)) >> 2) + \ - ((natural_t)(object) << 5) + \ + ((((((natural_t)(object)) + \ + (((natural_t)(object)) >> 6) + \ + (((natural_t)(object)) >> 12) + \ + (((natural_t)(object)) >> 18) + \ + (((natural_t)(object)) >> 24)) << 5) + \ ((natural_t)(((vm_object_offset_t)(offset)) >> 17))) & \ - ((2 * rows * lines) -1)) -*/ + ((rows * lines) -1)) #define alt_tws_hash(addr, rows, lines) \ - ((((natural_t)(addr)) >> 12) & \ - ((2 * rows * lines) -1)) + ((((natural_t)(addr)) >> 17) & \ + ((rows * lines) -1)) + + +/* Long term startup data structures for initial cache filling */ + +#define TWS_STARTUP_MAX_HASH_RETRY 3 + +/* 87 is the wrap skew, its based on RETRY times the RETRY offset of 29 */ +/* +#define do_startup_hash(addr, hash_size) \ + ((((((natural_t)(addr)) >> 17) & \ + ((2 * (hash_size)) -1)) + \ + (87 * (((addr) & TWS_ADDR_OFF_MASK)/(2 * (hash_size))))) & \ + ((2 * (hash_size)) -1)) +*/ +#define do_startup_hash(addr, hash_size) \ + (((((natural_t)(addr)) >> 17) * 3) & \ + (hash_size -1)) + + + +struct tws_startup_ele { + unsigned int page_cache; + vm_offset_t page_addr; +}; + +typedef struct tws_startup_ele *tws_startup_ele_t; + + +struct tws_startup_ptr { + tws_startup_ele_t element; + struct tws_startup_ptr *next; +}; + +typedef struct tws_startup_ptr *tws_startup_ptr_t; + +struct tws_startup { + unsigned int tws_hash_size; /* total size of struct in bytes */ + unsigned int ele_count; + unsigned int array_size; /* lines * rows * expansion_count */ + unsigned int hash_count; + + tws_startup_ptr_t *table; /* hash table */ + struct tws_startup_ptr *ele; /* hash elements */ + struct tws_startup_ele *array; +}; + +typedef struct tws_startup *tws_startup_t; + + +/* Dynamic cache data structures for working set */ struct tws_hash_ele { vm_object_t object; @@ -91,8 +129,15 @@ struct tws_hash_ele { typedef struct tws_hash_ele *tws_hash_ele_t; #define TWS_HASH_OFF_MASK ((vm_object_offset_t)0xFFFFFFFFFFFE0000) +#define TWS_ADDR_OFF_MASK ((vm_offset_t)0xFFFE0000) #define TWS_INDEX_MASK ((vm_object_offset_t)0x000000000001F000) +struct tws_hash_ptr { + tws_hash_ele_t element; + struct tws_hash_ptr *next; +}; +typedef struct tws_hash_ptr *tws_hash_ptr_t; + struct tws_hash_line { int ele_count; struct tws_hash_ele list[TWS_ARRAY_SIZE]; @@ -104,8 +149,9 @@ typedef struct tws_hash_line *tws_hash_line_t; #define TWS_HASH_STYLE_SIGNAL 0x2 +#define TWS_ADDR_HASH 1 #define TWS_HASH_EXPANSION_MAX 5 -#define TWS_MAX_REHASH 2 +#define TWS_MAX_REHASH 3 struct tws_hash { @@ -124,8 +170,19 @@ struct tws_hash { int lookup_count; int insert_count; - tws_hash_ele_t *table[TWS_HASH_EXPANSION_MAX]; - tws_hash_ele_t *alt_table[TWS_HASH_EXPANSION_MAX]; + tws_startup_t startup_cache; + char *startup_name; + int startup_name_length; + unsigned int uid; + int mod; + int fid; + + unsigned int obj_free_count[TWS_HASH_EXPANSION_MAX]; + unsigned int addr_free_count[TWS_HASH_EXPANSION_MAX]; + tws_hash_ptr_t free_hash_ele[TWS_HASH_EXPANSION_MAX]; + tws_hash_ptr_t *table[TWS_HASH_EXPANSION_MAX]; + tws_hash_ptr_t table_ele[TWS_HASH_EXPANSION_MAX]; + tws_hash_ptr_t alt_ele[TWS_HASH_EXPANSION_MAX]; struct tws_hash_line *cache[TWS_HASH_EXPANSION_MAX]; }; @@ -179,7 +236,28 @@ kern_return_t task_working_set_create( kern_return_t tws_expand_working_set( vm_offset_t old_tws, - int line_count); + int line_count, + boolean_t dump_data); + +kern_return_t tws_handle_startup_file( + task_t task, + unsigned int uid, + char *app_name, + vm_offset_t app_vp, + boolean_t *new_info); + +kern_return_t tws_write_startup_file( + task_t task, + int fid, + int mod, + char *name, + unsigned int string_length); + +kern_return_t tws_read_startup_file( + task_t task, + tws_startup_t startup, + vm_offset_t cache_size); + #endif /* _VM_TASK_WORKING_SET_H_ */ diff --git a/osfmk/vm/vm_fault.c b/osfmk/vm/vm_fault.c index a1200a69f..6d907567a 100644 --- a/osfmk/vm/vm_fault.c +++ b/osfmk/vm/vm_fault.c @@ -120,7 +120,8 @@ extern kern_return_t vm_fault_wire_fast( vm_map_t map, vm_offset_t va, vm_map_entry_t entry, - pmap_t pmap); + pmap_t pmap, + vm_offset_t pmap_addr); extern void vm_fault_continue(void); @@ -302,7 +303,6 @@ vm_fault_page( CLUSTER_STAT(int pages_at_higher_offsets;) CLUSTER_STAT(int pages_at_lower_offsets;) kern_return_t wait_result; - thread_t cur_thread; boolean_t interruptible_state; boolean_t bumped_pagein = FALSE; @@ -430,11 +430,7 @@ vm_fault_page( #endif /* MACH_KDB */ #endif /* STATIC_CONFIG */ - cur_thread = current_thread(); - - interruptible_state = cur_thread->interruptible; - if (interruptible == THREAD_UNINT) - cur_thread->interruptible = FALSE; + interruptible_state = thread_interrupt_level(interruptible); /* * INVARIANTS (through entire routine): @@ -491,7 +487,7 @@ vm_fault_page( #endif if (!object->alive) { vm_fault_cleanup(object, first_m); - cur_thread->interruptible = interruptible_state; + thread_interrupt_level(interruptible_state); return(VM_FAULT_MEMORY_ERROR); } m = vm_page_lookup(object, offset); @@ -522,19 +518,16 @@ vm_fault_page( #if TRACEFAULTPAGE dbgTrace(0xBEEF0005, (unsigned int) m, (unsigned int) 0); /* (TEST/DEBUG) */ #endif - PAGE_ASSERT_WAIT(m, interruptible); - vm_object_unlock(object); + wait_result = PAGE_SLEEP(object, m, interruptible); XPR(XPR_VM_FAULT, "vm_f_page: block busy obj 0x%X, offset 0x%X, page 0x%X\n", (integer_t)object, offset, (integer_t)m, 0, 0); counter(c_vm_fault_page_block_busy_kernel++); - wait_result = thread_block((void (*)(void))0); - vm_object_lock(object); if (wait_result != THREAD_AWAKENED) { vm_fault_cleanup(object, first_m); - cur_thread->interruptible = interruptible_state; + thread_interrupt_level(interruptible_state); if (wait_result == THREAD_RESTART) { return(VM_FAULT_RETRY); @@ -559,7 +552,7 @@ vm_fault_page( *error_code = m->page_error; VM_PAGE_FREE(m); vm_fault_cleanup(object, first_m); - cur_thread->interruptible = interruptible_state; + thread_interrupt_level(interruptible_state); return(VM_FAULT_MEMORY_ERROR); } @@ -576,7 +569,7 @@ vm_fault_page( #endif VM_PAGE_FREE(m); vm_fault_cleanup(object, first_m); - cur_thread->interruptible = interruptible_state; + thread_interrupt_level(interruptible_state); return(VM_FAULT_RETRY); } @@ -604,7 +597,7 @@ vm_fault_page( if (object->shadow_severed) { vm_fault_cleanup( object, first_m); - cur_thread->interruptible = interruptible_state; + thread_interrupt_level(interruptible_state); return VM_FAULT_MEMORY_ERROR; } @@ -618,7 +611,7 @@ vm_fault_page( if (VM_PAGE_THROTTLED() || (real_m = vm_page_grab()) == VM_PAGE_NULL) { vm_fault_cleanup(object, first_m); - cur_thread->interruptible = interruptible_state; + thread_interrupt_level(interruptible_state); return(VM_FAULT_MEMORY_SHORTAGE); } @@ -671,6 +664,17 @@ vm_fault_page( vm_page_lock_queues(); VM_PAGE_QUEUES_REMOVE(m); m->page_ticket = vm_page_ticket; + if(m->object->size > 0x80000) { + m->zero_fill = TRUE; + /* depends on the queues lock */ + vm_zf_count += 1; + queue_enter(&vm_page_queue_zf, + m, vm_page_t, pageq); + } else { + queue_enter( + &vm_page_queue_inactive, + m, vm_page_t, pageq); + } vm_page_ticket_roll++; if(vm_page_ticket_roll == VM_PAGE_TICKETS_IN_ROLL) { @@ -681,8 +685,6 @@ vm_fault_page( else vm_page_ticket++; } - queue_enter(&vm_page_queue_inactive, - m, vm_page_t, pageq); m->inactive = TRUE; vm_page_inactive_count++; vm_page_unlock_queues(); @@ -754,13 +756,13 @@ vm_fault_page( if (m != VM_PAGE_NULL && m->cleaning) { PAGE_ASSERT_WAIT(m, interruptible); vm_object_unlock(object); - wait_result = thread_block((void (*)(void)) 0); + wait_result = thread_block(THREAD_CONTINUE_NULL); vm_object_deallocate(object); goto backoff; } else { vm_object_unlock(object); vm_object_deallocate(object); - cur_thread->interruptible = interruptible_state; + thread_interrupt_level(interruptible_state); return VM_FAULT_RETRY; } } @@ -794,18 +796,19 @@ vm_fault_page( vm_object_lock(object); assert(object->ref_count > 0); if (!object->pager_ready) { - vm_object_assert_wait( + wait_result = vm_object_assert_wait( object, VM_OBJECT_EVENT_PAGER_READY, interruptible); vm_object_unlock(object); - wait_result = thread_block((void (*)(void))0); + if (wait_result == THREAD_WAITING) + wait_result = thread_block(THREAD_CONTINUE_NULL); vm_object_deallocate(object); goto backoff; } else { vm_object_unlock(object); vm_object_deallocate(object); - cur_thread->interruptible = interruptible_state; + thread_interrupt_level(interruptible_state); return VM_FAULT_RETRY; } } @@ -827,7 +830,7 @@ vm_fault_page( printf("vm_fault: memory_object_data_unlock failed\n"); vm_object_lock(object); vm_fault_cleanup(object, first_m); - cur_thread->interruptible = interruptible_state; + thread_interrupt_level(interruptible_state); return((rc == MACH_SEND_INTERRUPTED) ? VM_FAULT_INTERRUPTED : VM_FAULT_MEMORY_ERROR); @@ -854,13 +857,13 @@ vm_fault_page( !((access_required & m->unlock_request) != access_required)) { PAGE_ASSERT_WAIT(m, interruptible); vm_object_unlock(object); - wait_result = thread_block((void (*)(void)) 0); + wait_result = thread_block(THREAD_CONTINUE_NULL); vm_object_deallocate(object); goto backoff; } else { vm_object_unlock(object); vm_object_deallocate(object); - cur_thread->interruptible = interruptible_state; + thread_interrupt_level(interruptible_state); return VM_FAULT_RETRY; } } @@ -916,7 +919,7 @@ vm_fault_page( #endif if (m == VM_PAGE_NULL) { vm_fault_cleanup(object, first_m); - cur_thread->interruptible = interruptible_state; + thread_interrupt_level(interruptible_state); return(VM_FAULT_FICTITIOUS_SHORTAGE); } vm_page_insert(m, object, offset); @@ -947,17 +950,18 @@ vm_fault_page( vm_object_lock(object); assert(object->ref_count > 0); if (!object->pager_ready) { - vm_object_assert_wait(object, + wait_result = vm_object_assert_wait(object, VM_OBJECT_EVENT_PAGER_READY, interruptible); vm_object_unlock(object); - wait_result = thread_block((void (*)(void))0); + if (wait_result == THREAD_WAITING) + wait_result = thread_block(THREAD_CONTINUE_NULL); vm_object_deallocate(object); goto backoff; } else { vm_object_unlock(object); vm_object_deallocate(object); - cur_thread->interruptible = interruptible_state; + thread_interrupt_level(interruptible_state); return VM_FAULT_RETRY; } } @@ -986,7 +990,7 @@ vm_fault_page( if (m->fictitious && !vm_page_convert(m)) { VM_PAGE_FREE(m); vm_fault_cleanup(object, first_m); - cur_thread->interruptible = interruptible_state; + thread_interrupt_level(interruptible_state); return(VM_FAULT_MEMORY_SHORTAGE); } } else if (object->absent_count > @@ -1014,13 +1018,13 @@ vm_fault_page( vm_object_absent_assert_wait(object, interruptible); vm_object_unlock(object); - wait_result = thread_block((void (*)(void))0); + wait_result = thread_block(THREAD_CONTINUE_NULL); vm_object_deallocate(object); goto backoff; } else { vm_object_unlock(object); vm_object_deallocate(object); - cur_thread->interruptible = interruptible_state; + thread_interrupt_level(interruptible_state); return VM_FAULT_RETRY; } } @@ -1039,229 +1043,10 @@ vm_fault_page( } +no_clustering: cluster_start = offset; length = PAGE_SIZE; - cluster_size = object->cluster_size; - - /* - * Skip clustered pagein if it is globally disabled - * or random page reference behavior is expected - * for the address range containing the faulting - * address or the object paging block size is - * equal to the page size. - */ - if (!vm_allow_clustered_pagein || - behavior == VM_BEHAVIOR_RANDOM || - m == VM_PAGE_NULL || - cluster_size == PAGE_SIZE) { - cluster_start = trunc_page_64(cluster_start); - goto no_clustering; - } - - assert(offset >= lo_offset); - assert(offset < hi_offset); - assert(ALIGNED(object->paging_offset)); - assert(cluster_size >= PAGE_SIZE); - -#if TRACEFAULTPAGE - dbgTrace(0xBEEF0011, (unsigned int) m, (unsigned int) 0); /* (TEST/DEBUG) */ -#endif - /* - * Decide whether to scan ahead or behind for - * additional pages contiguous to the faulted - * page in the same paging block. The decision - * is based on system wide globals and the - * expected page reference behavior of the - * address range contained the faulting address. - * First calculate some constants. - */ - paging_offset = offset + object->paging_offset; - cluster_offset = paging_offset & (cluster_size - 1); - align_offset = paging_offset&(PAGE_SIZE_64-1); - if (align_offset != 0) { - cluster_offset = trunc_page_64(cluster_offset); - } - -#define SPANS_CLUSTER(x) ((((x) - align_offset) & (vm_object_offset_t)(cluster_size - 1)) == 0) - - /* - * Backward scan only if reverse sequential - * behavior has been specified - */ - CLUSTER_STAT(pages_at_lower_offsets = 0;) - if (((vm_default_behind != 0 && - behavior == VM_BEHAVIOR_DEFAULT) || - behavior == VM_BEHAVIOR_RSEQNTL) && offset) { - vm_object_offset_t cluster_bot; - - /* - * Calculate lower search boundary. - * Exclude pages that span a cluster boundary. - * Clip to start of map entry. - * For default page reference behavior, scan - * default pages behind. - */ - cluster_bot = (offset > cluster_offset) ? - offset - cluster_offset : offset; - if (align_offset != 0) { - if ((cluster_bot < offset) && - SPANS_CLUSTER(cluster_bot)) { - cluster_bot += PAGE_SIZE_64; - } - } - if (behavior == VM_BEHAVIOR_DEFAULT) { - vm_object_offset_t - bot = (vm_object_offset_t) - (vm_default_behind * PAGE_SIZE); - - if (cluster_bot < (offset - bot)) - cluster_bot = offset - bot; - } - if (lo_offset > cluster_bot) - cluster_bot = lo_offset; - - for ( cluster_start = offset - PAGE_SIZE_64; - (cluster_start >= cluster_bot) && - (cluster_start != - (align_offset - PAGE_SIZE_64)); - cluster_start -= PAGE_SIZE_64) { - assert(cluster_size > PAGE_SIZE_64); -retry_cluster_backw: - if (!LOOK_FOR(object, cluster_start) || - vm_page_lookup(object, cluster_start) - != VM_PAGE_NULL) { - break; - } - if (object->internal) { - /* - * need to acquire a real page in - * advance because this acts as - * a throttling mechanism for - * data_requests to the default - * pager. If this fails, give up - * trying to find any more pages - * in the cluster and send off the - * request for what we already have. - */ - if ((m = vm_page_grab()) - == VM_PAGE_NULL) { - cluster_start += PAGE_SIZE_64; - cluster_end = offset + PAGE_SIZE_64; - goto give_up; - } - } else if ((m = vm_page_grab_fictitious()) - == VM_PAGE_NULL) { - vm_object_unlock(object); - vm_page_more_fictitious(); - vm_object_lock(object); - goto retry_cluster_backw; - } - m->absent = TRUE; - m->unusual = TRUE; - m->clustered = TRUE; - m->list_req_pending = TRUE; - - vm_page_insert(m, object, cluster_start); - CLUSTER_STAT(pages_at_lower_offsets++;) - object->absent_count++; - } - cluster_start += PAGE_SIZE_64; - assert(cluster_start >= cluster_bot); - } - assert(cluster_start <= offset); - - /* - * Forward scan if default or sequential behavior - * specified - */ - CLUSTER_STAT(pages_at_higher_offsets = 0;) - if ((behavior == VM_BEHAVIOR_DEFAULT && - vm_default_ahead != 0) || - behavior == VM_BEHAVIOR_SEQUENTIAL) { - vm_object_offset_t cluster_top; - - /* - * Calculate upper search boundary. - * Exclude pages that span a cluster boundary. - * Clip to end of map entry. - * For default page reference behavior, scan - * default pages ahead. - */ - cluster_top = (offset + cluster_size) - - cluster_offset; - if (align_offset != 0) { - if ((cluster_top > (offset + PAGE_SIZE_64)) && - SPANS_CLUSTER(cluster_top)) { - cluster_top -= PAGE_SIZE_64; - } - } - if (behavior == VM_BEHAVIOR_DEFAULT) { - vm_object_offset_t top = (vm_object_offset_t) - ((vm_default_ahead*PAGE_SIZE)+PAGE_SIZE); - - if (cluster_top > (offset + top)) - cluster_top = offset + top; - } - if (cluster_top > hi_offset) - cluster_top = hi_offset; - - for (cluster_end = offset + PAGE_SIZE_64; - cluster_end < cluster_top; - cluster_end += PAGE_SIZE_64) { - assert(cluster_size > PAGE_SIZE); -retry_cluster_forw: - if (!LOOK_FOR(object, cluster_end) || - vm_page_lookup(object, cluster_end) - != VM_PAGE_NULL) { - break; - } - if (object->internal) { - /* - * need to acquire a real page in - * advance because this acts as - * a throttling mechanism for - * data_requests to the default - * pager. If this fails, give up - * trying to find any more pages - * in the cluster and send off the - * request for what we already have. - */ - if ((m = vm_page_grab()) - == VM_PAGE_NULL) { - break; - } - } else if ((m = vm_page_grab_fictitious()) - == VM_PAGE_NULL) { - vm_object_unlock(object); - vm_page_more_fictitious(); - vm_object_lock(object); - goto retry_cluster_forw; - } - m->absent = TRUE; - m->unusual = TRUE; - m->clustered = TRUE; - m->list_req_pending = TRUE; - vm_page_insert(m, object, cluster_end); - CLUSTER_STAT(pages_at_higher_offsets++;) - object->absent_count++; - } - assert(cluster_end <= cluster_top); - } - else { - cluster_end = offset + PAGE_SIZE_64; - } -give_up: - assert(cluster_end >= offset + PAGE_SIZE_64); - length = cluster_end - cluster_start; - -#if MACH_CLUSTER_STATS - CLUSTER_STAT_HIGHER(pages_at_higher_offsets); - CLUSTER_STAT_LOWER(pages_at_lower_offsets); - CLUSTER_STAT_CLUSTER(length/PAGE_SIZE); -#endif /* MACH_CLUSTER_STATS */ - -no_clustering: /* * lengthen the cluster by the pages in the working set */ @@ -1275,10 +1060,11 @@ no_clustering: * could be affected by re-entrance we * do not need to take the map lock. */ + cluster_end = offset + PAGE_SIZE_64; tws_build_cluster((tws_hash_t) current_task()->dynamic_working_set, object, &cluster_start, - &cluster_end, 0x16000); + &cluster_end, 0x40000); length = cluster_end - cluster_start; } #if TRACEFAULTPAGE @@ -1295,7 +1081,7 @@ no_clustering: */ if (type_of_fault) - *type_of_fault = DBG_PAGEIN_FAULT; + *type_of_fault = (length << 8) | DBG_PAGEIN_FAULT; VM_STAT(pageins++); current_task()->pageins++; bumped_pagein = TRUE; @@ -1360,7 +1146,7 @@ no_clustering: } } vm_fault_cleanup(object, first_m); - cur_thread->interruptible = interruptible_state; + thread_interrupt_level(interruptible_state); return((rc == MACH_SEND_INTERRUPTED) ? VM_FAULT_INTERRUPTED : VM_FAULT_MEMORY_ERROR); @@ -1372,11 +1158,22 @@ no_clustering: task = current_task(); if((map != NULL) && - (task->dynamic_working_set != 0)) { + (task->dynamic_working_set != 0)) + && !(object->private)) { + vm_object_t base_object; + vm_object_offset_t base_offset; + base_object = object; + base_offset = offset; + while(base_object->shadow) { + base_offset += + base_object->shadow_offset; + base_object = + base_object->shadow; + } if(tws_lookup ((tws_hash_t) task->dynamic_working_set, - offset, object, + base_offset, base_object, &line) == KERN_SUCCESS) { tws_line_signal((tws_hash_t) task->dynamic_working_set, @@ -1395,7 +1192,7 @@ no_clustering: if ((interruptible != THREAD_UNINT) && (current_thread()->state & TH_ABORT)) { vm_fault_cleanup(object, first_m); - cur_thread->interruptible = interruptible_state; + thread_interrupt_level(interruptible_state); return(VM_FAULT_INTERRUPTED); } if(m == VM_PAGE_NULL) @@ -1450,7 +1247,7 @@ no_clustering: if (object->shadow_severed) { VM_PAGE_FREE(m); vm_fault_cleanup(object, VM_PAGE_NULL); - cur_thread->interruptible = interruptible_state; + thread_interrupt_level(interruptible_state); return VM_FAULT_MEMORY_ERROR; } @@ -1458,7 +1255,7 @@ no_clustering: (m->fictitious && !vm_page_convert(m))) { VM_PAGE_FREE(m); vm_fault_cleanup(object, VM_PAGE_NULL); - cur_thread->interruptible = interruptible_state; + thread_interrupt_level(interruptible_state); return(VM_FAULT_MEMORY_SHORTAGE); } m->no_isync = FALSE; @@ -1478,6 +1275,17 @@ no_clustering: } vm_page_lock_queues(); VM_PAGE_QUEUES_REMOVE(m); + if(m->object->size > 0x80000) { + m->zero_fill = TRUE; + /* depends on the queues lock */ + vm_zf_count += 1; + queue_enter(&vm_page_queue_zf, + m, vm_page_t, pageq); + } else { + queue_enter( + &vm_page_queue_inactive, + m, vm_page_t, pageq); + } m->page_ticket = vm_page_ticket; vm_page_ticket_roll++; if(vm_page_ticket_roll == VM_PAGE_TICKETS_IN_ROLL) { @@ -1488,8 +1296,6 @@ no_clustering: else vm_page_ticket++; } - queue_enter(&vm_page_queue_inactive, - m, vm_page_t, pageq); m->inactive = TRUE; vm_page_inactive_count++; vm_page_unlock_queues(); @@ -1588,7 +1394,7 @@ no_clustering: if (copy_m == VM_PAGE_NULL) { RELEASE_PAGE(m); vm_fault_cleanup(object, first_m); - cur_thread->interruptible = interruptible_state; + thread_interrupt_level(interruptible_state); return(VM_FAULT_MEMORY_SHORTAGE); } @@ -1672,8 +1478,7 @@ no_clustering: * shadowed object, and one here to push it into the copy. */ - while (first_object->copy_strategy == MEMORY_OBJECT_COPY_DELAY && - (copy_object = first_object->copy) != VM_OBJECT_NULL && + while ((copy_object = first_object->copy) != VM_OBJECT_NULL && (m!= VM_PAGE_NULL)) { vm_object_offset_t copy_offset; vm_page_t copy_m; @@ -1754,13 +1559,13 @@ no_clustering: if (copy_m != VM_PAGE_NULL && copy_m->busy) { PAGE_ASSERT_WAIT(copy_m, interruptible); vm_object_unlock(copy_object); - wait_result = thread_block((void (*)(void))0); + wait_result = thread_block(THREAD_CONTINUE_NULL); vm_object_deallocate(copy_object); goto backoff; } else { vm_object_unlock(copy_object); vm_object_deallocate(copy_object); - cur_thread->interruptible = interruptible_state; + thread_interrupt_level(interruptible_state); return VM_FAULT_RETRY; } } @@ -1787,7 +1592,7 @@ no_clustering: assert(copy_object->ref_count > 0); vm_object_unlock(copy_object); vm_fault_cleanup(object, first_m); - cur_thread->interruptible = interruptible_state; + thread_interrupt_level(interruptible_state); return(VM_FAULT_MEMORY_SHORTAGE); } @@ -1948,7 +1753,7 @@ no_clustering: #if TRACEFAULTPAGE dbgTrace(0xBEEF001A, (unsigned int) VM_FAULT_SUCCESS, 0); /* (TEST/DEBUG) */ #endif - cur_thread->interruptible = interruptible_state; + thread_interrupt_level(interruptible_state); if(*result_page == VM_PAGE_NULL) { vm_object_unlock(object); } @@ -1959,11 +1764,11 @@ no_clustering: vm_fault_cleanup(object, first_m); counter(c_vm_fault_page_block_backoff_kernel++); - thread_block((void (*)(void))0); + thread_block(THREAD_CONTINUE_NULL); #endif backoff: - cur_thread->interruptible = interruptible_state; + thread_interrupt_level(interruptible_state); if (wait_result == THREAD_INTERRUPTED) return VM_FAULT_INTERRUPTED; return VM_FAULT_RETRY; @@ -1991,7 +1796,9 @@ vm_fault( vm_offset_t vaddr, vm_prot_t fault_type, boolean_t change_wiring, - int interruptible) + int interruptible, + pmap_t caller_pmap, + vm_offset_t caller_pmap_addr) { vm_map_version_t version; /* Map version for verificiation */ boolean_t wired; /* Should mapping be wired down? */ @@ -2022,6 +1829,9 @@ vm_fault( funnel_t *curflock; thread_t cur_thread; boolean_t interruptible_state; + unsigned int cache_attr; + int write_startup_file = 0; + vm_prot_t full_fault_type; KERNEL_DEBUG_CONSTANT((MACHDBG_CODE(DBG_MACH_VM, 0)) | DBG_FUNC_START, @@ -2032,10 +1842,16 @@ vm_fault( 0); cur_thread = current_thread(); + /* at present we do not fully check for execute permission */ + /* we generally treat it is read except in certain device */ + /* memory settings */ + full_fault_type = fault_type; + if(fault_type & VM_PROT_EXECUTE) { + fault_type &= ~VM_PROT_EXECUTE; + fault_type |= VM_PROT_READ; + } - interruptible_state = cur_thread->interruptible; - if (interruptible == THREAD_UNINT) - cur_thread->interruptible = FALSE; + interruptible_state = thread_interrupt_level(interruptible); /* * assume we will hit a page in the cache @@ -2204,27 +2020,54 @@ FastPmapEnter: if (m->no_isync == TRUE) pmap_sync_caches_phys(m->phys_addr); - PMAP_ENTER(pmap, vaddr, m, prot, wired); + cache_attr = ((unsigned int)m->object->wimg_bits) & VM_WIMG_MASK; + if(caller_pmap) { + PMAP_ENTER(caller_pmap, + caller_pmap_addr, m, + prot, cache_attr, wired); + } else { + PMAP_ENTER(pmap, vaddr, m, + prot, cache_attr, wired); + } { tws_hash_line_t line; task_t task; task = current_task(); if((map != NULL) && - (task->dynamic_working_set != 0)) { - if(tws_lookup - ((tws_hash_t) + (task->dynamic_working_set != 0) && + !(object->private)) { + kern_return_t kr; + vm_object_t base_object; + vm_object_offset_t base_offset; + base_object = object; + base_offset = cur_offset; + while(base_object->shadow) { + base_offset += + base_object->shadow_offset; + base_object = + base_object->shadow; + } + kr = tws_lookup((tws_hash_t) task->dynamic_working_set, - cur_offset, object, - &line) != KERN_SUCCESS) { - if(tws_insert((tws_hash_t) + base_offset, base_object, + &line); + if(kr == KERN_OPERATION_TIMED_OUT){ + write_startup_file = 1; + } else if (kr != KERN_SUCCESS) { + kr = tws_insert((tws_hash_t) task->dynamic_working_set, - m->offset, m->object, - vaddr, pmap_map) - == KERN_NO_SPACE) { + base_offset, base_object, + vaddr, pmap_map); + if(kr == KERN_NO_SPACE) { tws_expand_working_set( task->dynamic_working_set, - TWS_HASH_LINE_COUNT); + TWS_HASH_LINE_COUNT, + FALSE); + } + if(kr == + KERN_OPERATION_TIMED_OUT) { + write_startup_file = 1; } } } @@ -2290,17 +2133,20 @@ FastPmapEnter: if(pmap_map != map) vm_map_unlock(pmap_map); + if(write_startup_file) + tws_send_startup_info(current_task()); + if (funnel_set) { thread_funnel_set( curflock, TRUE); funnel_set = FALSE; } - cur_thread->interruptible = interruptible_state; + thread_interrupt_level(interruptible_state); KERNEL_DEBUG_CONSTANT((MACHDBG_CODE(DBG_MACH_VM, 0)) | DBG_FUNC_END, vaddr, - type_of_fault, + type_of_fault & 0xff, KERN_SUCCESS, - 0, + type_of_fault >> 8, 0); return KERN_SUCCESS; } @@ -2409,11 +2255,15 @@ FastPmapEnter: if(pmap_map != map) vm_map_unlock(pmap_map); + if(write_startup_file) + tws_send_startup_info( + current_task()); + if (funnel_set) { thread_funnel_set( curflock, TRUE); funnel_set = FALSE; } - cur_thread->interruptible = interruptible_state; + thread_interrupt_level(interruptible_state); return VM_FAULT_MEMORY_ERROR; } @@ -2471,6 +2321,17 @@ FastPmapEnter: VM_PAGE_QUEUES_REMOVE(m); m->page_ticket = vm_page_ticket; + if(m->object->size > 0x80000) { + m->zero_fill = TRUE; + /* depends on the queues lock */ + vm_zf_count += 1; + queue_enter(&vm_page_queue_zf, + m, vm_page_t, pageq); + } else { + queue_enter( + &vm_page_queue_inactive, + m, vm_page_t, pageq); + } vm_page_ticket_roll++; if(vm_page_ticket_roll == VM_PAGE_TICKETS_IN_ROLL) { @@ -2482,8 +2343,6 @@ FastPmapEnter: vm_page_ticket++; } - queue_enter(&vm_page_queue_inactive, - m, vm_page_t, pageq); m->inactive = TRUE; vm_page_inactive_count++; vm_page_unlock_queues(); @@ -2531,6 +2390,54 @@ FastPmapEnter: vm_object_paging_begin(object); XPR(XPR_VM_FAULT,"vm_fault -> vm_fault_page\n",0,0,0,0,0); + { + tws_hash_line_t line; + task_t task; + kern_return_t kr; + + task = current_task(); + if((map != NULL) && + (task->dynamic_working_set != 0) + && !(object->private)) { + vm_object_t base_object; + vm_object_offset_t base_offset; + base_object = object; + base_offset = offset; + while(base_object->shadow) { + base_offset += + base_object->shadow_offset; + base_object = + base_object->shadow; + } + kr = tws_lookup((tws_hash_t) + task->dynamic_working_set, + base_offset, base_object, + &line); + if(kr == KERN_OPERATION_TIMED_OUT){ + write_startup_file = 1; + } else if (kr != KERN_SUCCESS) { + tws_insert((tws_hash_t) + task->dynamic_working_set, + base_offset, base_object, + vaddr, pmap_map); + kr = tws_insert((tws_hash_t) + task->dynamic_working_set, + base_offset, base_object, + vaddr, pmap_map); + if(kr == KERN_NO_SPACE) { + vm_object_unlock(object); + tws_expand_working_set( + task->dynamic_working_set, + TWS_HASH_LINE_COUNT, + FALSE); + vm_object_lock(object); + } + if(kr == KERN_OPERATION_TIMED_OUT) { + write_startup_file = 1; + } + } + } + } kr = vm_fault_page(object, offset, fault_type, (change_wiring && !wired), interruptible, @@ -2734,43 +2641,71 @@ FastPmapEnter: m->no_isync = FALSE; } + + cache_attr = ((unsigned int)m->object->wimg_bits) & VM_WIMG_MASK; vm_object_unlock(m->object); - PMAP_ENTER(pmap, vaddr, m, prot, wired); + if(caller_pmap) { + PMAP_ENTER(caller_pmap, + caller_pmap_addr, m, + prot, cache_attr, wired); + } else { + PMAP_ENTER(pmap, vaddr, m, + prot, cache_attr, wired); + } { tws_hash_line_t line; task_t task; + kern_return_t kr; task = current_task(); if((map != NULL) && - (task->dynamic_working_set != 0)) { - if(tws_lookup - ((tws_hash_t) + (task->dynamic_working_set != 0) + && (object->private)) { + vm_object_t base_object; + vm_object_offset_t base_offset; + base_object = m->object; + base_offset = m->offset; + while(base_object->shadow) { + base_offset += + base_object->shadow_offset; + base_object = + base_object->shadow; + } + kr = tws_lookup((tws_hash_t) task->dynamic_working_set, - m->offset, m->object, - &line) != KERN_SUCCESS) { + base_offset, base_object, &line); + if(kr == KERN_OPERATION_TIMED_OUT){ + write_startup_file = 1; + } else if (kr != KERN_SUCCESS) { tws_insert((tws_hash_t) task->dynamic_working_set, - m->offset, m->object, + base_offset, base_object, vaddr, pmap_map); - if(tws_insert((tws_hash_t) + kr = tws_insert((tws_hash_t) task->dynamic_working_set, - m->offset, m->object, - vaddr, pmap_map) - == KERN_NO_SPACE) { + base_offset, base_object, + vaddr, pmap_map); + if(kr == KERN_NO_SPACE) { tws_expand_working_set( - task->dynamic_working_set, - TWS_HASH_LINE_COUNT); + task->dynamic_working_set, + TWS_HASH_LINE_COUNT, + FALSE); + } + if(kr == KERN_OPERATION_TIMED_OUT) { + write_startup_file = 1; } } } } } else { -/* if __ppc__ not working until figure out phys copy on block maps */ -#ifdef notdefcdy - int memattr; +#ifndef i386 + int memattr; struct phys_entry *pp; + vm_map_entry_t entry; + vm_offset_t laddr; + vm_offset_t ldelta, hdelta; /* * do a pmap block mapping from the physical address * in the object @@ -2779,20 +2714,102 @@ FastPmapEnter: (vm_offset_t)object->shadow_offset)) { memattr = ((pp->pte1 & 0x00000078) >> 3); } else { - memattr = PTE_WIMG_UNCACHED_COHERENT_GUARDED; + memattr = VM_WIMG_MASK & (int)object->wimg_bits; + } + + + /* While we do not worry about execution protection in */ + /* general, we may be able to read device memory and */ + /* still not be able to execute it. Here we check for */ + /* the guarded bit. If its set and we are attempting */ + /* to execute, we return with a protection failure. */ + + if((memattr & VM_MEM_GUARDED) && + (full_fault_type & VM_PROT_EXECUTE)) { + vm_map_verify_done(map, &version); + if(pmap_map != map) + vm_map_unlock(pmap_map); + vm_fault_cleanup(object, top_page); + vm_object_deallocate(object); + kr = KERN_PROTECTION_FAILURE; + goto done; } - pmap_map_block(pmap, vaddr, - (vm_offset_t)object->shadow_offset, - object->size, prot, - memattr, 0); /* Set up a block mapped area */ -//#else - vm_offset_t off; - for (off = 0; off < object->size; off += page_size) { - pmap_enter(pmap, vaddr + off, - object->shadow_offset + off, prot, TRUE); + + + if(pmap_map != map) { + vm_map_unlock(pmap_map); + } + if (original_map != map) { + vm_map_unlock_read(map); + vm_map_lock_read(original_map); + map = original_map; + } + pmap_map = map; + + laddr = vaddr; + hdelta = 0xFFFFF000; + ldelta = 0xFFFFF000; + + + while(vm_map_lookup_entry(map, laddr, &entry)) { + if(ldelta > (laddr - entry->vme_start)) + ldelta = laddr - entry->vme_start; + if(hdelta > (entry->vme_end - laddr)) + hdelta = entry->vme_end - laddr; + if(entry->is_sub_map) { + + laddr = (laddr - entry->vme_start) + + entry->offset; + vm_map_lock_read(entry->object.sub_map); + if(map != pmap_map) + vm_map_unlock_read(map); + if(entry->use_pmap) { + vm_map_unlock_read(pmap_map); + pmap_map = entry->object.sub_map; + } + map = entry->object.sub_map; + + } else { + break; + } + } + + if(vm_map_lookup_entry(map, laddr, &entry) && + (entry->object.vm_object != NULL) && + (entry->object.vm_object == object)) { + + + if(caller_pmap) { + pmap_map_block(caller_pmap, + caller_pmap_addr - ldelta, + ((vm_offset_t) + (entry->object.vm_object->shadow_offset)) + + entry->offset + + (laddr - entry->vme_start) - ldelta, + ldelta + hdelta, prot, + memattr, 0); /* Set up a block mapped area */ + } else { + pmap_map_block(pmap_map->pmap, vaddr - ldelta, + ((vm_offset_t) + (entry->object.vm_object->shadow_offset)) + + entry->offset + + (laddr - entry->vme_start) - ldelta, + ldelta + hdelta, prot, + memattr, 0); /* Set up a block mapped area */ + } + } +#else +#ifdef notyet + if(caller_pmap) { + pmap_enter(caller_pmap, caller_pmap_addr, + object->shadow_offset, prot, 0, TRUE); + } else { + pmap_enter(pmap, vaddr, + object->shadow_offset, prot, 0, TRUE); + } /* Map it in */ - } +#endif #endif } @@ -2850,17 +2867,19 @@ FastPmapEnter: #undef RELEASE_PAGE done: + if(write_startup_file) + tws_send_startup_info(current_task()); if (funnel_set) { thread_funnel_set( curflock, TRUE); funnel_set = FALSE; } - cur_thread->interruptible = interruptible_state; + thread_interrupt_level(interruptible_state); KERNEL_DEBUG_CONSTANT((MACHDBG_CODE(DBG_MACH_VM, 0)) | DBG_FUNC_END, vaddr, - type_of_fault, + type_of_fault & 0xff, kr, - 0, + type_of_fault >> 8, 0); return(kr); } @@ -2874,7 +2893,8 @@ kern_return_t vm_fault_wire( vm_map_t map, vm_map_entry_t entry, - pmap_t pmap) + pmap_t pmap, + vm_offset_t pmap_addr) { register vm_offset_t va; @@ -2883,13 +2903,20 @@ vm_fault_wire( assert(entry->in_transition); + if ((entry->object.vm_object != NULL) && + !entry->is_sub_map && + entry->object.vm_object->phys_contiguous) { + return KERN_SUCCESS; + } + /* * Inform the physical mapping system that the * range of addresses may not fault, so that * page tables and such can be locked down as well. */ - pmap_pageable(pmap, entry->vme_start, end_addr, FALSE); + pmap_pageable(pmap, pmap_addr, + pmap_addr + (end_addr - entry->vme_start), FALSE); /* * We simulate a fault to get the page and enter it @@ -2898,9 +2925,13 @@ vm_fault_wire( for (va = entry->vme_start; va < end_addr; va += PAGE_SIZE) { if ((rc = vm_fault_wire_fast( - map, va, entry, pmap)) != KERN_SUCCESS) { + map, va, entry, pmap, + pmap_addr + (va - entry->vme_start) + )) != KERN_SUCCESS) { rc = vm_fault(map, va, VM_PROT_NONE, TRUE, - (pmap == kernel_pmap) ? THREAD_UNINT : THREAD_ABORTSAFE); + (pmap == kernel_pmap) ? + THREAD_UNINT : THREAD_ABORTSAFE, + pmap, pmap_addr + (va - entry->vme_start)); } if (rc != KERN_SUCCESS) { @@ -2908,7 +2939,8 @@ vm_fault_wire( /* unwire wired pages */ tmp_entry.vme_end = va; - vm_fault_unwire(map, &tmp_entry, FALSE, pmap); + vm_fault_unwire(map, + &tmp_entry, FALSE, pmap, pmap_addr); return rc; } @@ -2926,7 +2958,8 @@ vm_fault_unwire( vm_map_t map, vm_map_entry_t entry, boolean_t deallocate, - pmap_t pmap) + pmap_t pmap, + vm_offset_t pmap_addr) { register vm_offset_t va; register vm_offset_t end_addr = entry->vme_end; @@ -2941,10 +2974,14 @@ vm_fault_unwire( */ for (va = entry->vme_start; va < end_addr; va += PAGE_SIZE) { - pmap_change_wiring(pmap, va, FALSE); + pmap_change_wiring(pmap, + pmap_addr + (va - entry->vme_start), FALSE); if (object == VM_OBJECT_NULL) { - (void) vm_fault(map, va, VM_PROT_NONE, TRUE, THREAD_UNINT); + (void) vm_fault(map, va, VM_PROT_NONE, + TRUE, THREAD_UNINT, pmap, pmap_addr); + } else if (object->phys_contiguous) { + continue; } else { vm_prot_t prot; vm_page_t result_page; @@ -3004,7 +3041,8 @@ vm_fault_unwire( * such may be unwired themselves. */ - pmap_pageable(pmap, entry->vme_start, end_addr, TRUE); + pmap_pageable(pmap, pmap_addr, + pmap_addr + (end_addr - entry->vme_start), TRUE); } @@ -3033,13 +3071,15 @@ vm_fault_wire_fast( vm_map_t map, vm_offset_t va, vm_map_entry_t entry, - pmap_t pmap) + pmap_t pmap, + vm_offset_t pmap_addr) { vm_object_t object; vm_object_offset_t offset; register vm_page_t m; vm_prot_t prot; thread_act_t thr_act; + unsigned int cache_attr; VM_STAT(faults++); @@ -3165,9 +3205,11 @@ vm_fault_wire_fast( m->no_isync = FALSE; } + + cache_attr = ((unsigned int)m->object->wimg_bits) & VM_WIMG_MASK; vm_object_unlock(object); - PMAP_ENTER(pmap, va, m, prot, TRUE); + PMAP_ENTER(pmap, pmap_addr, m, prot, cache_attr, TRUE); /* * Must relock object so that paging_in_progress can be cleared. @@ -3632,11 +3674,12 @@ vm_fault_page_overwrite( */ if (!dst_object->pager_ready) { - vm_object_assert_wait(dst_object, - VM_OBJECT_EVENT_PAGER_READY, - interruptible); + wait_result = vm_object_assert_wait(dst_object, + VM_OBJECT_EVENT_PAGER_READY, + interruptible); vm_object_unlock(dst_object); - wait_result = thread_block((void (*)(void))0); + if (wait_result == THREAD_WAITING) + wait_result = thread_block(THREAD_CONTINUE_NULL); if (wait_result != THREAD_AWAKENED) { DISCARD_PAGE; return(VM_FAULT_INTERRUPTED); @@ -3674,9 +3717,10 @@ vm_fault_page_overwrite( break; } - PAGE_ASSERT_WAIT(dst_page, interruptible); + wait_result = PAGE_ASSERT_WAIT(dst_page, interruptible); vm_object_unlock(dst_object); - wait_result = thread_block((void (*)(void))0); + if (wait_result == THREAD_WAITING) + wait_result = thread_block(THREAD_CONTINUE_NULL); if (wait_result != THREAD_AWAKENED) { DISCARD_PAGE; return(VM_FAULT_INTERRUPTED); diff --git a/osfmk/vm/vm_fault.h b/osfmk/vm/vm_fault.h index c8061ad0e..8c9bd88f5 100644 --- a/osfmk/vm/vm_fault.h +++ b/osfmk/vm/vm_fault.h @@ -118,18 +118,22 @@ extern kern_return_t vm_fault( vm_offset_t vaddr, vm_prot_t fault_type, boolean_t change_wiring, - int interruptible); + int interruptible, + pmap_t pmap, + vm_offset_t pmap_addr); extern kern_return_t vm_fault_wire( vm_map_t map, vm_map_entry_t entry, - pmap_t pmap); + pmap_t pmap, + vm_offset_t pmap_addr); extern void vm_fault_unwire( vm_map_t map, vm_map_entry_t entry, boolean_t deallocate, - pmap_t pmap); + pmap_t pmap, + vm_offset_t pmap_addr); extern kern_return_t vm_fault_copy( vm_object_t src_object, diff --git a/osfmk/vm/vm_kern.c b/osfmk/vm/vm_kern.c index 56143f42c..ab065e048 100644 --- a/osfmk/vm/vm_kern.c +++ b/osfmk/vm/vm_kern.c @@ -544,8 +544,8 @@ kmem_alloc_pages( /* * Enter it in the kernel pmap */ - PMAP_ENTER(kernel_pmap, start, mem, - protection, TRUE); + PMAP_ENTER(kernel_pmap, start, mem, protection, + VM_WIMG_USE_DEFAULT, TRUE); vm_object_lock(object); PAGE_WAKEUP_DONE(mem); @@ -598,8 +598,8 @@ kmem_remap_pages( * Enter it in the kernel pmap. The page isn't busy, * but this shouldn't be a problem because it is wired. */ - PMAP_ENTER(kernel_pmap, start, mem, - protection, TRUE); + PMAP_ENTER(kernel_pmap, start, mem, protection, + VM_WIMG_USE_DEFAULT, TRUE); start += PAGE_SIZE; offset += PAGE_SIZE; @@ -835,3 +835,93 @@ copyoutmap( return TRUE; } + + +kern_return_t +vm_conflict_check( + vm_map_t map, + vm_offset_t off, + vm_size_t len, + memory_object_t pager, + vm_object_offset_t file_off) +{ + vm_map_entry_t entry; + vm_object_t obj; + vm_object_offset_t obj_off; + vm_map_t base_map; + vm_offset_t base_offset; + vm_offset_t original_offset; + kern_return_t kr; + vm_size_t local_len; + + base_map = map; + base_offset = off; + original_offset = off; + kr = KERN_SUCCESS; + vm_map_lock(map); + while(vm_map_lookup_entry(map, off, &entry)) { + local_len = len; + + if (entry->object.vm_object == VM_OBJECT_NULL) { + vm_map_unlock(map); + return KERN_SUCCESS; + } + if (entry->is_sub_map) { + vm_map_t old_map; + old_map = map; + vm_map_lock(entry->object.sub_map); + map = entry->object.sub_map; + off = entry->offset + (off - entry->vme_start); + vm_map_unlock(old_map); + continue; + } + obj = entry->object.vm_object; + obj_off = (off - entry->vme_start) + entry->offset; + while(obj->shadow) { + obj_off += obj->shadow_offset; + obj = obj->shadow; + } + if((obj->pager_created) && (obj->pager == pager)) { + if(((obj->paging_offset) + obj_off) == file_off) { + if(off != base_offset) { + vm_map_unlock(map); + return KERN_FAILURE; + } + kr = KERN_ALREADY_WAITING; + } else if( + ((file_off < ((obj->paging_offset) + obj_off)) && + ((file_off + len) > + ((obj->paging_offset) + obj_off))) || + ((file_off > ((obj->paging_offset) + obj_off)) && + (((((obj->paging_offset) + obj_off)) + len) + > file_off))) { + vm_map_unlock(map); + return KERN_FAILURE; + } + } else if(kr != KERN_SUCCESS) { + return KERN_FAILURE; + } + + if(len < ((entry->vme_end - entry->vme_start) - + (off - entry->vme_start))) { + vm_map_unlock(map); + return kr; + } else { + len -= (entry->vme_end - entry->vme_start) - + (off - entry->vme_start); + } + base_offset = base_offset + (local_len - len); + file_off = file_off + (local_len - len); + off = base_offset; + if(map != base_map) { + vm_map_unlock(map); + vm_map_lock(base_map); + map = base_map; + } + } + + vm_map_unlock(map); + return kr; + + +} diff --git a/osfmk/vm/vm_kern.h b/osfmk/vm/vm_kern.h index 95302993f..247448732 100644 --- a/osfmk/vm/vm_kern.h +++ b/osfmk/vm/vm_kern.h @@ -147,6 +147,13 @@ extern boolean_t copyoutmap( vm_offset_t toaddr, vm_size_t length); +extern kern_return_t vm_conflict_check( + vm_map_t map, + vm_offset_t off, + vm_size_t len, + memory_object_t pager, + vm_object_offset_t file_off); + extern vm_map_t kernel_map; extern vm_map_t kernel_pageable_map; extern vm_map_t ipc_kernel_map; diff --git a/osfmk/vm/vm_map.c b/osfmk/vm/vm_map.c index f7c440eb6..87b0b30db 100644 --- a/osfmk/vm/vm_map.c +++ b/osfmk/vm/vm_map.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -388,6 +388,7 @@ vm_map_create( result->max_offset = max; result->wiring_required = FALSE; result->no_zero_fill = FALSE; + result->mapped = FALSE; result->wait_for_space = FALSE; result->first_free = vm_map_to_entry(result); result->hint = vm_map_to_entry(result); @@ -570,53 +571,7 @@ MACRO_END (entry)->vme_prev->vme_next = (entry)->vme_next; \ MACRO_END -/* - * kernel_vm_map_reference: - * - * kernel internal export version for iokit and bsd components - * in lieu of component interface semantics. - * - */ -void -kernel_vm_map_reference( - register vm_map_t map) -{ - if (map == VM_MAP_NULL) - return; - - mutex_lock(&map->s_lock); -#if TASK_SWAPPER - assert(map->res_count > 0); - assert(map->ref_count >= map->res_count); - map->res_count++; -#endif - map->ref_count++; - mutex_unlock(&map->s_lock); -} - #if MACH_ASSERT && TASK_SWAPPER -/* - * vm_map_reference: - * - * Adds valid reference and residence counts to the given map. - * The map must be in memory (i.e. non-zero residence count). - * - */ -void -vm_map_reference( - register vm_map_t map) -{ - if (map == VM_MAP_NULL) - return; - - mutex_lock(&map->s_lock); - assert(map->res_count > 0); - assert(map->ref_count >= map->res_count); - map->ref_count++; - map->res_count++; - mutex_unlock(&map->s_lock); -} - /* * vm_map_res_reference: * @@ -685,44 +640,6 @@ void vm_map_res_deallocate(register vm_map_t map) } #endif /* MACH_ASSERT && TASK_SWAPPER */ -/* - * vm_map_deallocate: - * - * Removes a reference from the specified map, - * destroying it if no references remain. - * The map should not be locked. - */ -void -vm_map_deallocate( - register vm_map_t map) -{ - unsigned int ref; - - if (map == VM_MAP_NULL) - return; - - mutex_lock(&map->s_lock); - ref = --map->ref_count; - if (ref > 0) { - vm_map_res_deallocate(map); - mutex_unlock(&map->s_lock); - return; - } - assert(map->ref_count == 0); - mutex_unlock(&map->s_lock); - -#if TASK_SWAPPER - /* - * The map residence count isn't decremented here because - * the vm_map_delete below will traverse the entire map, - * deleting entries, and the residence counts on objects - * and sharing maps will go away then. - */ -#endif - - vm_map_destroy(map); -} - /* * vm_map_destroy: * @@ -1190,6 +1107,7 @@ vm_map_pmap_enter( vm_object_offset_t offset, vm_prot_t protection) { + unsigned int cache_attr; while (addr < end_addr) { register vm_page_t m; @@ -1218,13 +1136,14 @@ vm_map_pmap_enter( if (m->no_isync == TRUE) { pmap_sync_caches_phys(m->phys_addr); - m->no_isync = FALSE; } + + cache_attr = ((unsigned int)object->wimg_bits) & VM_WIMG_MASK; vm_object_unlock(object); - PMAP_ENTER(map->pmap, addr, m, - protection, FALSE); + PMAP_ENTER(map->pmap, addr, m, + protection, cache_attr, FALSE); vm_object_lock(object); @@ -1524,13 +1443,16 @@ MACRO_BEGIN \ if (VMCS_startaddr > VMCS_entry->vme_start) { \ if(entry->use_pmap) { \ vm_offset_t pmap_base_addr; \ - vm_offset_t pmap_end_addr; \ \ pmap_base_addr = 0xF0000000 & entry->vme_start; \ - pmap_end_addr = (pmap_base_addr + 0x10000000) - 1; \ pmap_unnest(map->pmap, pmap_base_addr, \ - (pmap_end_addr - pmap_base_addr) + 1); \ + 0x10000000); \ entry->use_pmap = FALSE; \ + } else if(entry->object.vm_object \ + && !entry->is_sub_map \ + && entry->object.vm_object->phys_contiguous) { \ + pmap_remove(map->pmap, \ + entry->vme_start, entry->vme_end); \ } \ _vm_map_clip_start(&VMCS_map->hdr,VMCS_entry,VMCS_startaddr);\ } \ @@ -1613,13 +1535,16 @@ MACRO_BEGIN \ if (VMCE_endaddr < VMCE_entry->vme_end) { \ if(entry->use_pmap) { \ vm_offset_t pmap_base_addr; \ - vm_offset_t pmap_end_addr; \ \ pmap_base_addr = 0xF0000000 & entry->vme_start; \ - pmap_end_addr = (pmap_base_addr + 0x10000000) - 1; \ pmap_unnest(map->pmap, pmap_base_addr, \ - (pmap_end_addr - pmap_base_addr) + 1); \ + 0x10000000); \ entry->use_pmap = FALSE; \ + } else if(entry->object.vm_object \ + && !entry->is_sub_map \ + && entry->object.vm_object->phys_contiguous) { \ + pmap_remove(map->pmap, \ + entry->vme_start, entry->vme_end); \ } \ _vm_map_clip_end(&VMCE_map->hdr,VMCE_entry,VMCE_endaddr); \ } \ @@ -1789,6 +1714,8 @@ vm_map_submap( vm_map_lock(map); + submap->mapped = TRUE; + VM_MAP_RANGE_CHECK(map, start, end); if (vm_map_lookup_entry(map, start, &entry)) { @@ -2084,7 +2011,8 @@ vm_map_wire_nested( register vm_offset_t end, register vm_prot_t access_type, boolean_t user_wire, - pmap_t map_pmap) + pmap_t map_pmap, + vm_offset_t pmap_addr) { register vm_map_entry_t entry; struct vm_map_entry *first_entry, tmp_entry; @@ -2093,7 +2021,7 @@ vm_map_wire_nested( kern_return_t rc; boolean_t need_wakeup; boolean_t main_map = FALSE; - boolean_t interruptible_state; + wait_interrupt_t interruptible_state; thread_t cur_thread; unsigned int last_timestamp; vm_size_t size; @@ -2130,6 +2058,8 @@ vm_map_wire_nested( * block after informing other thread to wake us up. */ if (entry->in_transition) { + wait_result_t wait_result; + /* * We have not clipped the entry. Make sure that * the start address is in range so that the lookup @@ -2150,22 +2080,21 @@ vm_map_wire_nested( /* * User wiring is interruptible */ - vm_map_entry_wait(map, + wait_result = vm_map_entry_wait(map, (user_wire) ? THREAD_ABORTSAFE : THREAD_UNINT); - if (user_wire && cur_thread->wait_result == - THREAD_INTERRUPTED) { + if (user_wire && wait_result == THREAD_INTERRUPTED) { /* * undo the wirings we have done so far * We do not clear the needs_wakeup flag, * because we cannot tell if we were the * only one waiting. */ + vm_map_unlock(map); vm_map_unwire(map, start, s, user_wire); return(KERN_FAILURE); } - vm_map_lock(map); /* * Cannot avoid a lookup here. reset timestamp. */ @@ -2195,13 +2124,14 @@ vm_map_wire_nested( if(entry->is_sub_map) { vm_offset_t sub_start; vm_offset_t sub_end; + vm_offset_t local_start; vm_offset_t local_end; pmap_t pmap; vm_map_clip_start(map, entry, start); vm_map_clip_end(map, entry, end); - sub_start += entry->offset; + sub_start = entry->offset; sub_end = entry->vme_end - entry->vme_start; sub_end += entry->offset; @@ -2209,8 +2139,16 @@ vm_map_wire_nested( if(map_pmap == NULL) { if(entry->use_pmap) { pmap = entry->object.sub_map->pmap; + /* ppc implementation requires that */ + /* submaps pmap address ranges line */ + /* up with parent map */ +#ifdef notdef + pmap_addr = sub_start; +#endif + pmap_addr = start; } else { pmap = map->pmap; + pmap_addr = start; } if (entry->wired_count) { if (entry->wired_count @@ -2225,8 +2163,10 @@ vm_map_wire_nested( entry->vme_start, user_wire); return(KERN_FAILURE); } - if (!user_wire || - (entry->user_wired_count++ == 0)) + if(user_wire) + entry->user_wired_count++; + if((!user_wire) || + (entry->user_wired_count == 0)) entry->wired_count++; entry = entry->vme_next; continue; @@ -2239,7 +2179,6 @@ vm_map_wire_nested( vm_prot_t prot; boolean_t wired; vm_behavior_t behavior; - vm_offset_t local_start; vm_map_entry_t local_entry; vm_map_version_t version; vm_map_t lookup_map; @@ -2252,7 +2191,7 @@ vm_map_wire_nested( vm_map_lock_write_to_read(map); if(vm_map_lookup_locked( &lookup_map, local_start, - VM_PROT_WRITE, + access_type, &version, &object, &offset, &prot, &wired, &behavior, &offset_lo, @@ -2265,17 +2204,11 @@ vm_map_wire_nested( } if(pmap_map != lookup_map) vm_map_unlock(pmap_map); - if(lookup_map != map) { - vm_map_unlock(lookup_map); - vm_map_lock(map); - } else { - vm_map_unlock(map); - vm_map_lock(map); - } - last_timestamp = - version.main_timestamp; + vm_map_unlock_read(lookup_map); + vm_map_lock(map); vm_object_unlock(object); - if (vm_map_lookup_entry(map, + + if (!vm_map_lookup_entry(map, local_start, &local_entry)) { vm_map_unlock(map); vm_map_unwire(map, start, @@ -2283,11 +2216,15 @@ vm_map_wire_nested( return(KERN_FAILURE); } /* did we have a change of type? */ - if (!local_entry->is_sub_map) + if (!local_entry->is_sub_map) { + last_timestamp = map->timestamp; continue; + } entry = local_entry; if (user_wire) entry->user_wired_count++; + if((!user_wire) || + (entry->user_wired_count == 1)) entry->wired_count++; entry->in_transition = TRUE; @@ -2297,32 +2234,34 @@ vm_map_wire_nested( entry->object.sub_map, sub_start, sub_end, access_type, - user_wire, pmap); + user_wire, pmap, pmap_addr); vm_map_lock(map); - last_timestamp = map->timestamp; } } else { + local_start = entry->vme_start; + if (user_wire) + entry->user_wired_count++; + if((!user_wire) || + (entry->user_wired_count == 1)) + entry->wired_count++; vm_map_unlock(map); rc = vm_map_wire_nested(entry->object.sub_map, sub_start, sub_end, access_type, - user_wire, pmap); + user_wire, pmap, pmap_addr); vm_map_lock(map); - last_timestamp = map->timestamp; } s = entry->vme_start; e = entry->vme_end; - if (last_timestamp+1 != map->timestamp) { + /* * Find the entry again. It could have been clipped * after we unlocked the map. */ - if (!vm_map_lookup_entry(map, local_end, - &first_entry)) - panic("vm_map_wire: re-lookup failed"); - - entry = first_entry; - } + if (!vm_map_lookup_entry(map, local_start, + &first_entry)) + panic("vm_map_wire: re-lookup failed"); + entry = first_entry; last_timestamp = map->timestamp; while ((entry != vm_map_to_entry(map)) && @@ -2334,11 +2273,11 @@ vm_map_wire_nested( need_wakeup = TRUE; } if (rc != KERN_SUCCESS) {/* from vm_*_wire */ - if(main_map) { if (user_wire) entry->user_wired_count--; - entry->wired_count--; - } + if ((!user_wire) || + (entry->user_wired_count == 0)) + entry->wired_count--; } entry = entry->vme_next; } @@ -2359,7 +2298,7 @@ vm_map_wire_nested( * If this entry is already wired then increment * the appropriate wire reference count. */ - if (entry->wired_count && main_map) { + if (entry->wired_count) { /* sanity check: wired_count is a short */ if (entry->wired_count >= MAX_WIRE_COUNT) panic("vm_map_wire: too many wirings"); @@ -2377,7 +2316,9 @@ vm_map_wire_nested( */ vm_map_clip_start(map, entry, start); vm_map_clip_end(map, entry, end); - if (!user_wire || (entry->user_wired_count++ == 0)) + if (user_wire) + entry->user_wired_count++; + if ((!user_wire) || (entry->user_wired_count == 1)) entry->wired_count++; entry = entry->vme_next; @@ -2443,11 +2384,10 @@ vm_map_wire_nested( assert(entry->wired_count == 0 && entry->user_wired_count == 0); - if(main_map) { - if (user_wire) - entry->user_wired_count++; + if (user_wire) + entry->user_wired_count++; + if ((!user_wire) || (entry->user_wired_count == 1)) entry->wired_count++; - } entry->in_transition = TRUE; @@ -2469,18 +2409,19 @@ vm_map_wire_nested( */ vm_map_unlock(map); - if (!user_wire && cur_thread != THREAD_NULL) { - interruptible_state = cur_thread->interruptible; - cur_thread->interruptible = FALSE; - } - + if (!user_wire && cur_thread != THREAD_NULL) + interruptible_state = thread_interrupt_level(THREAD_UNINT); + if(map_pmap) - rc = vm_fault_wire(map, &tmp_entry, map_pmap); + rc = vm_fault_wire(map, + &tmp_entry, map_pmap, pmap_addr); else - rc = vm_fault_wire(map, &tmp_entry, map->pmap); + rc = vm_fault_wire(map, + &tmp_entry, map->pmap, + tmp_entry.vme_start); if (!user_wire && cur_thread != THREAD_NULL) - cur_thread->interruptible = interruptible_state; + thread_interrupt_level(interruptible_state); vm_map_lock(map); @@ -2507,11 +2448,11 @@ vm_map_wire_nested( need_wakeup = TRUE; } if (rc != KERN_SUCCESS) { /* from vm_*_wire */ - if(main_map) { - if (user_wire) - entry->user_wired_count--; + if (user_wire) + entry->user_wired_count--; + if ((!user_wire) || + (entry->user_wired_count == 0)) entry->wired_count--; - } } entry = entry->vme_next; } @@ -2564,7 +2505,7 @@ vm_map_wire( mapping_prealloc(end - start); #endif kret = vm_map_wire_nested(map, start, end, access_type, - user_wire, (pmap_t)NULL); + user_wire, (pmap_t)NULL, 0); #ifdef ppc mapping_relpre(); #endif @@ -2590,7 +2531,8 @@ vm_map_unwire_nested( register vm_offset_t start, register vm_offset_t end, boolean_t user_wire, - pmap_t map_pmap) + pmap_t map_pmap, + vm_offset_t pmap_addr) { register vm_map_entry_t entry; struct vm_map_entry *first_entry, tmp_entry; @@ -2657,8 +2599,10 @@ vm_map_unwire_nested( if(map_pmap == NULL) { if(entry->use_pmap) { pmap = entry->object.sub_map->pmap; + pmap_addr = sub_start; } else { pmap = map->pmap; + pmap_addr = start; } if (entry->wired_count == 0 || (user_wire && entry->user_wired_count == 0)) { @@ -2702,7 +2646,7 @@ vm_map_unwire_nested( */ vm_map_unlock(map); vm_map_unwire_nested(entry->object.sub_map, - sub_start, sub_end, user_wire, pmap); + sub_start, sub_end, user_wire, pmap, pmap_addr); vm_map_lock(map); if (last_timestamp+1 != map->timestamp) { @@ -2740,7 +2684,7 @@ vm_map_unwire_nested( } else { vm_map_unlock(map); vm_map_unwire_nested(entry->object.sub_map, - sub_start, sub_end, user_wire, pmap); + sub_start, sub_end, user_wire, pmap, pmap_addr); vm_map_lock(map); if (last_timestamp+1 != map->timestamp) { @@ -2762,8 +2706,8 @@ vm_map_unwire_nested( } - if (main_map && (entry->wired_count == 0 || - (user_wire && entry->user_wired_count == 0))) { + if ((entry->wired_count == 0) || + (user_wire && entry->user_wired_count == 0)) { if (!user_wire) panic("vm_map_unwire: entry is unwired"); @@ -2792,14 +2736,12 @@ vm_map_unwire_nested( continue; } - if(main_map) { - if (!user_wire || (--entry->user_wired_count == 0)) + if (!user_wire || (--entry->user_wired_count == 0)) entry->wired_count--; - if (entry->wired_count != 0) { + if (entry->wired_count != 0) { entry = entry->vme_next; continue; - } } entry->in_transition = TRUE; @@ -2811,9 +2753,12 @@ vm_map_unwire_nested( */ vm_map_unlock(map); if(map_pmap) { - vm_fault_unwire(map, &tmp_entry, FALSE, map_pmap); + vm_fault_unwire(map, + &tmp_entry, FALSE, map_pmap, pmap_addr); } else { - vm_fault_unwire(map, &tmp_entry, FALSE, map->pmap); + vm_fault_unwire(map, + &tmp_entry, FALSE, map->pmap, + tmp_entry.vme_start); } vm_map_lock(map); @@ -2865,7 +2810,8 @@ vm_map_unwire( register vm_offset_t end, boolean_t user_wire) { - return vm_map_unwire_nested(map, start, end, user_wire, (pmap_t)NULL); + return vm_map_unwire_nested(map, start, end, + user_wire, (pmap_t)NULL, 0); } @@ -2951,7 +2897,20 @@ vm_map_submap_pmap_clean( entry->object.sub_map, entry->offset); } else { - pmap_remove(map->pmap, start, start + remove_size); + + if((map->mapped) && (map->ref_count) + && (entry->object.vm_object != NULL)) { + vm_object_pmap_protect( + entry->object.vm_object, + entry->offset, + remove_size, + PMAP_NULL, + entry->vme_start, + VM_PROT_NONE); + } else { + pmap_remove(map->pmap, + start, start + remove_size); + } } } @@ -2971,9 +2930,21 @@ vm_map_submap_pmap_clean( entry->object.sub_map, entry->offset); } else { - pmap_remove(map->pmap, - (start + entry->vme_start) - offset, - ((start + entry->vme_start) - offset) + remove_size); + if((map->mapped) && (map->ref_count) + && (entry->object.vm_object != NULL)) { + vm_object_pmap_protect( + entry->object.vm_object, + entry->offset, + remove_size, + PMAP_NULL, + entry->vme_start, + VM_PROT_NONE); + } else { + pmap_remove(map->pmap, + (start + entry->vme_start) - offset, + ((start + entry->vme_start) + - offset) + remove_size); + } } entry = entry->vme_next; } @@ -3047,6 +3018,8 @@ vm_map_delete( vm_map_clip_end(map, entry, end); if (entry->in_transition) { + wait_result_t wait_result; + /* * Another thread is wiring/unwiring this entry. * Let the other thread know we are waiting. @@ -3063,21 +3036,17 @@ vm_map_delete( need_wakeup = FALSE; } - vm_map_entry_wait(map, interruptible); + wait_result = vm_map_entry_wait(map, interruptible); if (interruptible && - current_thread()->wait_result == THREAD_INTERRUPTED) + wait_result == THREAD_INTERRUPTED) { /* * We do not clear the needs_wakeup flag, * since we cannot tell if we were the only one. */ + vm_map_unlock(map); return KERN_ABORTED; - - vm_map_lock(map); - /* - * Cannot avoid a lookup here. reset timestamp. - */ - last_timestamp = map->timestamp; + } /* * The entry could have been clipped or it @@ -3094,6 +3063,7 @@ vm_map_delete( entry = first_entry; SAVE_HINT(map, entry->vme_prev); } + last_timestamp = map->timestamp; continue; } /* end in_transition */ @@ -3120,28 +3090,24 @@ vm_map_delete( * error. */ if (flags & VM_MAP_REMOVE_WAIT_FOR_KWIRE) { + wait_result_t wait_result; s = entry->vme_start; entry->needs_wakeup = TRUE; - vm_map_entry_wait(map, interruptible); + wait_result = vm_map_entry_wait(map, + interruptible); if (interruptible && - current_thread()->wait_result == - THREAD_INTERRUPTED) + wait_result == THREAD_INTERRUPTED) { /* * We do not clear the * needs_wakeup flag, since we * cannot tell if we were the * only one. */ + vm_map_unlock(map); return KERN_ABORTED; - - vm_map_lock(map); - /* - * Cannot avoid a lookup here. reset - * timestamp. - */ - last_timestamp = map->timestamp; + } /* * The entry could have been clipped or @@ -3160,6 +3126,7 @@ vm_map_delete( entry = first_entry; SAVE_HINT(map, entry->vme_prev); } + last_timestamp = map->timestamp; continue; } else { @@ -3182,7 +3149,7 @@ vm_map_delete( vm_map_unlock(map); vm_fault_unwire(map, &tmp_entry, tmp_entry.object.vm_object == kernel_object, - map->pmap); + map->pmap, tmp_entry.vme_start); vm_map_lock(map); if (last_timestamp+1 != map->timestamp) { @@ -3236,6 +3203,14 @@ vm_map_delete( pmap_unnest(map->pmap, entry->vme_start, entry->vme_end - entry->vme_start); #endif + if((map->mapped) && (map->ref_count)) { + /* clean up parent map/maps */ + vm_map_submap_pmap_clean( + map, entry->vme_start, + entry->vme_end, + entry->object.sub_map, + entry->offset); + } } else { vm_map_submap_pmap_clean( map, entry->vme_start, entry->vme_end, @@ -3243,8 +3218,19 @@ vm_map_delete( entry->offset); } } else { - pmap_remove(map->pmap, - entry->vme_start, entry->vme_end); + if((map->mapped) && (map->ref_count)) { + vm_object_pmap_protect( + entry->object.vm_object, + entry->offset, + entry->vme_end - entry->vme_start, + PMAP_NULL, + entry->vme_start, + VM_PROT_NONE); + } else { + pmap_remove(map->pmap, + entry->vme_start, + entry->vme_end); + } } } @@ -3310,12 +3296,25 @@ vm_map_remove( register boolean_t flags) { register kern_return_t result; + boolean_t funnel_set = FALSE; + funnel_t *curflock; + thread_t cur_thread; + + cur_thread = current_thread(); + if ((cur_thread->funnel_state & TH_FN_OWNED) == TH_FN_OWNED) { + funnel_set = TRUE; + curflock = cur_thread->funnel_lock; + thread_funnel_set( curflock , FALSE); + } vm_map_lock(map); VM_MAP_RANGE_CHECK(map, start, end); result = vm_map_delete(map, start, end, flags); vm_map_unlock(map); - + if (funnel_set) { + thread_funnel_set( curflock, TRUE); + funnel_set = FALSE; + } return(result); } @@ -3445,9 +3444,9 @@ vm_map_overwrite_submap_recurse( */ dst_end = round_page(dst_addr + dst_size); + vm_map_lock(dst_map); start_pass_1: - vm_map_lock(dst_map); if (!vm_map_lookup_entry(dst_map, dst_addr, &tmp_entry)) { vm_map_unlock(dst_map); return(KERN_INVALID_ADDRESS); @@ -3679,8 +3678,9 @@ vm_map_copy_overwrite_nested( dst_end = dst_addr + copy->size; } -start_pass_1: vm_map_lock(dst_map); + +start_pass_1: if (!vm_map_lookup_entry(dst_map, dst_addr, &tmp_entry)) { vm_map_unlock(dst_map); return(KERN_INVALID_ADDRESS); @@ -3854,7 +3854,6 @@ start_overwrite: entry->needs_wakeup = TRUE; vm_map_entry_wait(dst_map, THREAD_UNINT); - vm_map_lock(dst_map); if(!vm_map_lookup_entry(dst_map, base_addr, &tmp_entry)) { vm_map_unlock(dst_map); @@ -4536,32 +4535,48 @@ vm_map_copy_overwrite_aligned( if (old_object != VM_OBJECT_NULL) { if(entry->is_sub_map) { - if(entry->use_pmap) { + if(entry->use_pmap) { #ifndef i386 - pmap_unnest(dst_map->pmap, - entry->vme_start, - entry->vme_end - entry->vme_start); + pmap_unnest(dst_map->pmap, + entry->vme_start, + entry->vme_end + - entry->vme_start); #endif - } else { - vm_map_submap_pmap_clean( - dst_map, entry->vme_start, - entry->vme_end, - entry->object.sub_map, - entry->offset); - } - vm_map_deallocate( + if(dst_map->mapped) { + /* clean up parent */ + /* map/maps */ + vm_map_submap_pmap_clean( + dst_map, entry->vme_start, + entry->vme_end, + entry->object.sub_map, + entry->offset); + } + } else { + vm_map_submap_pmap_clean( + dst_map, entry->vme_start, + entry->vme_end, + entry->object.sub_map, + entry->offset); + } + vm_map_deallocate( entry->object.sub_map); - } else { - vm_object_pmap_protect( - old_object, - old_offset, - size, - pmap, - tmp_entry->vme_start, - VM_PROT_NONE); - + } else { + if(dst_map->mapped) { + vm_object_pmap_protect( + entry->object.vm_object, + entry->offset, + entry->vme_end + - entry->vme_start, + PMAP_NULL, + entry->vme_start, + VM_PROT_NONE); + } else { + pmap_remove(dst_map->pmap, + entry->vme_start, + entry->vme_end); + } vm_object_deallocate(old_object); - } + } } entry->is_sub_map = FALSE; @@ -4624,8 +4639,8 @@ vm_map_copy_overwrite_aligned( /* a pc to execute it. */ /* No isync here */ - PMAP_ENTER(pmap, va, m, - prot, FALSE); + PMAP_ENTER(pmap, va, m, prot, + VM_WIMG_USE_DEFAULT, FALSE); vm_object_lock(object); vm_page_lock_queues(); @@ -4666,7 +4681,8 @@ vm_map_copy_overwrite_aligned( vm_object_reference(dst_object); - version.main_timestamp = dst_map->timestamp; + /* account for unlock bumping up timestamp */ + version.main_timestamp = dst_map->timestamp + 1; vm_map_unlock(dst_map); @@ -4719,7 +4735,7 @@ vm_map_copy_overwrite_aligned( start += copy_size; vm_map_lock(dst_map); - if ((version.main_timestamp + 1) == dst_map->timestamp) { + if (version.main_timestamp == dst_map->timestamp) { /* We can safely use saved tmp_entry value */ vm_map_clip_end(dst_map, tmp_entry, start); @@ -5128,8 +5144,8 @@ vm_map_copyout( m->busy = TRUE; vm_object_unlock(object); - PMAP_ENTER(dst_map->pmap, va, m, - entry->protection, TRUE); + PMAP_ENTER(dst_map->pmap, va, m, entry->protection, + VM_WIMG_USE_DEFAULT, TRUE); vm_object_lock(object); PAGE_WAKEUP_DONE(m); @@ -5178,7 +5194,9 @@ vm_map_copyout( prot &= ~VM_PROT_WRITE; PMAP_ENTER(dst_map->pmap, va, - m, prot, FALSE); + m, prot, + VM_WIMG_USE_DEFAULT, + FALSE); vm_object_lock(object); vm_page_lock_queues(); @@ -5350,6 +5368,8 @@ vm_map_copyin_common( #define RETURN(x) \ MACRO_BEGIN \ vm_map_unlock(src_map); \ + if(src_map != base_map) \ + vm_map_deallocate(src_map); \ if (new_entry != VM_MAP_ENTRY_NULL) \ vm_map_copy_entry_dispose(copy,new_entry); \ vm_map_copy_discard(copy); \ @@ -5358,6 +5378,8 @@ vm_map_copyin_common( \ for(ptr = parent_maps; ptr != NULL; ptr = parent_maps) { \ parent_maps=parent_maps->next; \ + if (ptr->parent_map != base_map) \ + vm_map_deallocate(ptr->parent_map); \ kfree((vm_offset_t)ptr, sizeof(submap_map_t)); \ } \ } \ @@ -5428,6 +5450,9 @@ vm_map_copyin_common( src_end = src_start + submap_len; src_map = tmp_entry->object.sub_map; vm_map_lock(src_map); + /* keep an outstanding reference for all maps in */ + /* the parents tree except the base map */ + vm_map_reference(src_map); vm_map_unlock(ptr->parent_map); if (!vm_map_lookup_entry( src_map, src_start, &tmp_entry)) @@ -5438,7 +5463,8 @@ vm_map_copyin_common( src_entry = tmp_entry; } if ((tmp_entry->object.vm_object != VM_OBJECT_NULL) && - (tmp_entry->object.vm_object->phys_contiguous)) { + ((tmp_entry->object.vm_object->wimg_bits != VM_WIMG_DEFAULT) || + (tmp_entry->object.vm_object->phys_contiguous))) { /* This is not, cannot be supported for now */ /* we need a description of the caching mode */ /* reflected in the object before we can */ @@ -5607,7 +5633,7 @@ RestartCopy: */ version.main_timestamp = src_map->timestamp; - vm_map_unlock(src_map); + vm_map_unlock(src_map); /* Increments timestamp once! */ /* * Perform the copy @@ -5652,7 +5678,7 @@ RestartCopy: * changed while the copy was being made. */ - vm_map_lock(src_map); /* Increments timestamp once! */ + vm_map_lock(src_map); if ((version.main_timestamp + 1) == src_map->timestamp) goto VerificationSuccessful; @@ -5735,8 +5761,9 @@ RestartCopy: ptr = parent_maps; assert(ptr != NULL); parent_maps = parent_maps->next; - vm_map_lock(ptr->parent_map); vm_map_unlock(src_map); + vm_map_deallocate(src_map); + vm_map_lock(ptr->parent_map); src_map = ptr->parent_map; src_start = ptr->base_start; src_end = ptr->base_end; @@ -5977,16 +6004,19 @@ vm_map_fork_share( * to remove write permission. */ -/* CDY FIX this! page_protect! */ if (!old_entry->needs_copy && (old_entry->protection & VM_PROT_WRITE)) { - if(old_entry->is_sub_map && old_entry->use_pmap) { - pmap_protect(old_entry->object.sub_map->pmap, - old_entry->vme_start, - old_entry->vme_end, - old_entry->protection & ~VM_PROT_WRITE); + if(old_map->mapped) { + vm_object_pmap_protect( + old_entry->object.vm_object, + old_entry->offset, + (old_entry->vme_end - + old_entry->vme_start), + PMAP_NULL, + old_entry->vme_start, + old_entry->protection & ~VM_PROT_WRITE); } else { - pmap_protect(vm_map_pmap(old_map), + pmap_protect(old_map->pmap, old_entry->vme_start, old_entry->vme_end, old_entry->protection & ~VM_PROT_WRITE); @@ -6174,7 +6204,9 @@ vm_map_fork( if(old_entry->is_sub_map) break; - if (old_entry->wired_count != 0) { + if ((old_entry->wired_count != 0) || + ((old_entry->object.vm_object != NULL) && + (old_entry->object.vm_object->true_share))) { goto slow_vm_map_fork_copy; } @@ -6205,7 +6237,7 @@ vm_map_fork( (old_entry->vme_end - old_entry->vme_start), ((old_entry->is_shared - || old_entry->is_sub_map) + || old_map->mapped) ? PMAP_NULL : old_map->pmap), old_entry->vme_start, @@ -6489,7 +6521,8 @@ RetrySubMap: submap_entry->offset, submap_entry->vme_end - submap_entry->vme_start, - submap_entry->is_shared ? + (submap_entry->is_shared + || map->mapped) ? PMAP_NULL : map->pmap, submap_entry->vme_start, submap_entry->protection & @@ -7428,15 +7461,13 @@ vm_region_top_walk( register struct vm_object *obj, *tmp_obj; register int ref_count; - if (entry->object.vm_object == 0) { + if (entry->object.vm_object == 0 || entry->is_sub_map) { top->share_mode = SM_EMPTY; top->ref_count = 0; top->obj_id = 0; return; } - if (entry->is_sub_map) - vm_region_top_walk((vm_map_entry_t)entry->object.sub_map, top); - else { + { obj = entry->object.vm_object; vm_object_lock(obj); @@ -7500,16 +7531,14 @@ vm_region_walk( register int ref_count; void vm_region_look_for_page(); - if ((entry->object.vm_object == 0) || + if ((entry->object.vm_object == 0) || + (entry->is_sub_map) || (entry->object.vm_object->phys_contiguous)) { extended->share_mode = SM_EMPTY; extended->ref_count = 0; return; } - if (entry->is_sub_map) - vm_region_walk((vm_map_entry_t)entry->object.sub_map, extended, offset + entry->offset, - range, map, va); - else { + { obj = entry->object.vm_object; vm_object_lock(obj); @@ -7804,14 +7833,96 @@ vm_map_machine_attribute( vm_machine_attribute_val_t* value) /* IN/OUT */ { kern_return_t ret; - + vm_size_t sync_size; + vm_offset_t start; + vm_map_entry_t entry; + if (address < vm_map_min(map) || (address + size) > vm_map_max(map)) return KERN_INVALID_ADDRESS; vm_map_lock(map); + + if (attribute != MATTR_CACHE) { + /* If we don't have to find physical addresses, we */ + /* don't have to do an explicit traversal here. */ + ret = pmap_attribute(map->pmap, + address, size, attribute, value); + vm_map_unlock(map); + return ret; + } + + /* Get the starting address */ + start = trunc_page(address); + /* Figure how much memory we need to flush (in page increments) */ + sync_size = round_page(start + size) - start; - ret = pmap_attribute(map->pmap, address, size, attribute, value); + + ret = KERN_SUCCESS; /* Assume it all worked */ + + while(sync_size) { + if (vm_map_lookup_entry(map, start, &entry)) { + vm_size_t sub_size; + if((entry->vme_end - start) > sync_size) { + sub_size = sync_size; + sync_size = 0; + } else { + sub_size = entry->vme_end - start; + sync_size -= sub_size; + } + if(entry->is_sub_map) { + vm_map_machine_attribute( + entry->object.sub_map, + (start - entry->vme_start) + + entry->offset, + sub_size, + attribute, value); + } else { + if(entry->object.vm_object) { + vm_page_t m; + vm_object_t object; + vm_object_t base_object; + vm_object_offset_t offset; + vm_object_offset_t base_offset; + vm_size_t range; + range = sub_size; + offset = (start - entry->vme_start) + + entry->offset; + base_offset = offset; + object = entry->object.vm_object; + base_object = object; + while(range) { + m = vm_page_lookup( + object, offset); + if(m && !m->fictitious) { + + ret = + pmap_attribute_cache_sync( + m->phys_addr, + PAGE_SIZE, + attribute, value); + } else if (object->shadow) { + offset = offset + + object->shadow_offset; + object = object->shadow; + continue; + } + range -= PAGE_SIZE; + /* Bump to the next page */ + base_offset += PAGE_SIZE; + offset = base_offset; + object = base_object; + + } + } + } + start += sub_size; + } else { + vm_map_unlock(map); + return KERN_FAILURE; + } + + } vm_map_unlock(map); @@ -7846,6 +7957,10 @@ vm_map_behavior_set( case VM_BEHAVIOR_SEQUENTIAL: case VM_BEHAVIOR_RSEQNTL: break; + case VM_BEHAVIOR_WILLNEED: + case VM_BEHAVIOR_DONTNEED: + new_behavior = VM_BEHAVIOR_DEFAULT; + break; default: return(KERN_INVALID_ARGUMENT); } @@ -8348,11 +8463,22 @@ vm_remap_extract( if (!src_entry->needs_copy && (src_entry->protection & VM_PROT_WRITE)) { - pmap_protect(vm_map_pmap(map), - src_entry->vme_start, - src_entry->vme_end, - src_entry->protection & + if(map->mapped) { + vm_object_pmap_protect( + src_entry->object.vm_object, + src_entry->offset, + entry_size, + PMAP_NULL, + src_entry->vme_start, + src_entry->protection & + ~VM_PROT_WRITE); + } else { + pmap_protect(vm_map_pmap(map), + src_entry->vme_start, + src_entry->vme_end, + src_entry->protection & ~VM_PROT_WRITE); + } } object = src_entry->object.vm_object; @@ -8413,7 +8539,8 @@ vm_remap_extract( vm_object_pmap_protect(object, offset, entry_size, - (src_entry->is_shared ? + ((src_entry->is_shared + || map->mapped) ? PMAP_NULL : map->pmap), src_entry->vme_start, src_entry->protection & @@ -8437,7 +8564,7 @@ vm_remap_extract( * verification, and unlock the map. */ version.main_timestamp = map->timestamp; - vm_map_unlock(map); + vm_map_unlock(map); /* Increments timestamp once! */ /* * Perform the copy. @@ -8481,7 +8608,7 @@ vm_remap_extract( * changed while the copy was being made. */ - vm_map_lock(map); /* Increments timestamp once! */ + vm_map_lock(map); if (version.main_timestamp + 1 != map->timestamp) { /* * Simple version comparison failed. @@ -9053,3 +9180,77 @@ boolean_t vm_map_check_protection(map, start, end, protection) vm_map_unlock(map); return(TRUE); } + +/* + * This routine is obsolete, but included for backward + * compatibility for older drivers. + */ +void +kernel_vm_map_reference( + vm_map_t map) +{ + vm_map_reference(map); +} + +/* + * vm_map_reference: + * + * Most code internal to the osfmk will go through a + * macro defining this. This is always here for the + * use of other kernel components. + */ +#undef vm_map_reference +void +vm_map_reference( + register vm_map_t map) +{ + if (map == VM_MAP_NULL) + return; + + mutex_lock(&map->s_lock); +#if TASK_SWAPPER + assert(map->res_count > 0); + assert(map->ref_count >= map->res_count); + map->res_count++; +#endif + map->ref_count++; + mutex_unlock(&map->s_lock); +} + +/* + * vm_map_deallocate: + * + * Removes a reference from the specified map, + * destroying it if no references remain. + * The map should not be locked. + */ +void +vm_map_deallocate( + register vm_map_t map) +{ + unsigned int ref; + + if (map == VM_MAP_NULL) + return; + + mutex_lock(&map->s_lock); + ref = --map->ref_count; + if (ref > 0) { + vm_map_res_deallocate(map); + mutex_unlock(&map->s_lock); + return; + } + assert(map->ref_count == 0); + mutex_unlock(&map->s_lock); + +#if TASK_SWAPPER + /* + * The map residence count isn't decremented here because + * the vm_map_delete below will traverse the entire map, + * deleting entries, and the residence counts on objects + * and sharing maps will go away then. + */ +#endif + + vm_map_destroy(map); +} diff --git a/osfmk/vm/vm_map.h b/osfmk/vm/vm_map.h index d98593232..c32c121be 100644 --- a/osfmk/vm/vm_map.h +++ b/osfmk/vm/vm_map.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -73,13 +73,15 @@ #include #include -typedef struct vm_map_entry *vm_map_entry_t; +#include -extern void kernel_vm_map_reference(vm_map_t map); +#ifdef __APPLE_API_PRIVATE #ifndef MACH_KERNEL_PRIVATE -struct vm_map_entry {}; +#ifdef __APPLE_API_OBSOLETE +extern void kernel_vm_map_reference(vm_map_t map); +#endif /* __APPLE_API_OBSOLETE */ extern void vm_map_reference(vm_map_t map); extern vm_map_t current_map(void); @@ -96,10 +98,6 @@ extern vm_map_t current_map(void); #include #include -#define shared_region_mapping_lock_init(object) \ - mutex_init(&(object)->Lock, ETAP_VM_OBJ) -#define shared_region_mapping_lock(object) mutex_lock(&(object)->Lock) -#define shared_region_mapping_unlock(object) mutex_unlock(&(object)->Lock) #include #define current_map_fast() (current_act_fast()->map) @@ -114,6 +112,8 @@ extern vm_map_t current_map(void); * vm_map_copy_t represents memory copied from an address map, * used for inter-map copy operations */ +typedef struct vm_map_entry *vm_map_entry_t; + /* * Type: vm_map_object_t [internal use only] @@ -266,6 +266,7 @@ struct vm_map { for space? */ boolean_t wiring_required;/* All memory wired? */ boolean_t no_zero_fill; /* No zero fill absent pages */ + boolean_t mapped; /* has this map been mapped */ unsigned int timestamp; /* Version number */ } ; @@ -423,23 +424,17 @@ struct vm_map_copy { */ #define vm_map_lock_init(map) \ -MACRO_BEGIN \ - lock_init(&(map)->lock, TRUE, ETAP_VM_MAP, ETAP_VM_MAP_I); \ - (map)->timestamp = 0; \ -MACRO_END -#define vm_map_lock(map) \ -MACRO_BEGIN \ - lock_write(&(map)->lock); \ - (map)->timestamp++; \ -MACRO_END - -#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) + ((map)->timestamp = 0 , \ + lock_init(&(map)->lock, TRUE, ETAP_VM_MAP, ETAP_VM_MAP_I)) + +#define vm_map_lock(map) lock_write(&(map)->lock) +#define vm_map_unlock(map) \ + ((map)->timestamp++ , 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) #define vm_map_lock_write_to_read(map) \ - lock_write_to_read(&(map)->lock) -#define vm_map_lock_read_to_write(map) \ - (lock_read_to_write(&(map)->lock) || (((map)->timestamp++), 0)) + ((map)->timestamp++ , lock_write_to_read(&(map)->lock)) +#define vm_map_lock_read_to_write(map) lock_read_to_write(&(map)->lock) extern zone_t vm_map_copy_zone; /* zone for vm_map_copy structures */ @@ -667,14 +662,12 @@ extern vm_object_t vm_submap_object; * Wait and wakeup macros for in_transition map entries. */ #define vm_map_entry_wait(map, interruptible) \ - MACRO_BEGIN \ - assert_wait((event_t)&(map)->hdr, interruptible); \ - vm_map_unlock(map); \ - thread_block((void (*)(void))0); \ - MACRO_END + ((map)->timestamp++ , \ + thread_sleep_lock_write((event_t)&(map)->hdr, \ + &(map)->lock, interruptible)) -#define vm_map_entry_wakeup(map) thread_wakeup((event_t)(&(map)->hdr)) +#define vm_map_entry_wakeup(map) thread_wakeup((event_t)(&(map)->hdr)) #define vm_map_ref_fast(map) \ @@ -737,22 +730,7 @@ extern int vm_map_copy_cont_is_valid( vm_map_copy_t copy); - -#endif /* !MACH_KERNEL_PRIVATE */ - -/* Get rid of a map */ -extern void vm_map_destroy( - vm_map_t map); -/* Lose a reference */ -extern void vm_map_deallocate( - vm_map_t map); - -/* Create an empty map */ -extern vm_map_t vm_map_create( - pmap_t pmap, - vm_offset_t min, - vm_offset_t max, - boolean_t pageable); +#define VM_MAP_ENTRY_NULL ((vm_map_entry_t) 0) /* Enter a mapping */ @@ -785,20 +763,59 @@ extern kern_return_t vm_map_read_user( extern vm_map_t vm_map_fork( vm_map_t old_map); -/* Change protection */ -extern kern_return_t vm_map_protect( +/* Change inheritance */ +extern kern_return_t vm_map_inherit( vm_map_t map, vm_offset_t start, vm_offset_t end, - vm_prot_t new_prot, - boolean_t set_max); + vm_inherit_t new_inheritance); -/* Change inheritance */ -extern kern_return_t vm_map_inherit( +/* Add or remove machine-dependent attributes from map regions */ +extern kern_return_t vm_map_machine_attribute( + vm_map_t map, + vm_offset_t address, + vm_size_t size, + vm_machine_attribute_t attribute, + vm_machine_attribute_val_t* value); /* IN/OUT */ +/* Set paging behavior */ +extern kern_return_t vm_map_behavior_set( vm_map_t map, vm_offset_t start, vm_offset_t end, - vm_inherit_t new_inheritance); + vm_behavior_t new_behavior); + +extern kern_return_t vm_map_submap( + vm_map_t map, + vm_offset_t start, + vm_offset_t end, + vm_map_t submap, + vm_offset_t offset, + boolean_t use_pmap); + + +#endif /* MACH_KERNEL_PRIVATE */ + +/* Create an empty map */ +extern vm_map_t vm_map_create( + pmap_t pmap, + vm_offset_t min, + vm_offset_t max, + boolean_t pageable); + +/* Get rid of a map */ +extern void vm_map_destroy( + vm_map_t map); +/* Lose a reference */ +extern void vm_map_deallocate( + vm_map_t map); + +/* Change protection */ +extern kern_return_t vm_map_protect( + vm_map_t map, + vm_offset_t start, + vm_offset_t end, + vm_prot_t new_prot, + boolean_t set_max); /* wire down a region */ extern kern_return_t vm_map_wire( @@ -828,21 +845,6 @@ extern kern_return_t vm_map_copyout( vm_offset_t *dst_addr, /* OUT */ vm_map_copy_t copy); - -/* Add or remove machine-dependent attributes from map regions */ -extern kern_return_t vm_map_machine_attribute( - vm_map_t map, - vm_offset_t address, - vm_size_t size, - vm_machine_attribute_t attribute, - vm_machine_attribute_val_t* value); /* IN/OUT */ -/* Set paging behavior */ -extern kern_return_t vm_map_behavior_set( - vm_map_t map, - vm_offset_t start, - vm_offset_t end, - vm_behavior_t new_behavior); - extern kern_return_t vm_map_copyin_common( vm_map_t src_map, vm_offset_t src_addr, @@ -852,14 +854,6 @@ extern kern_return_t vm_map_copyin_common( vm_map_copy_t *copy_result, /* OUT */ boolean_t use_maxprot); -extern kern_return_t vm_map_submap( - vm_map_t map, - vm_offset_t start, - vm_offset_t end, - vm_map_t submap, - vm_offset_t offset, - boolean_t use_pmap); - extern kern_return_t vm_region_clone( ipc_port_t src_region, ipc_port_t dst_region); @@ -889,8 +883,6 @@ extern kern_return_t vm_map_region_replace( vm_map_copyin_common(src_map, src_addr, len, src_destroy, \ FALSE, copy_result, TRUE) -#define VM_MAP_ENTRY_NULL ((vm_map_entry_t) 0) - /* * Flags for vm_map_remove() and vm_map_delete() */ @@ -899,91 +891,7 @@ extern kern_return_t vm_map_region_replace( #define VM_MAP_REMOVE_INTERRUPTIBLE 0x2 #define VM_MAP_REMOVE_WAIT_FOR_KWIRE 0x4 +#endif /* __APPLE_API_PRIVATE */ -#ifdef MACH_KERNEL_PRIVATE - -/* address space shared region descriptor */ - -struct shared_region_mapping { - decl_mutex_data(, Lock) /* Synchronization */ - int ref_count; - ipc_port_t text_region; - vm_size_t text_size; - ipc_port_t data_region; - vm_size_t data_size; - vm_offset_t region_mappings; - vm_offset_t client_base; - vm_offset_t alternate_base; - vm_offset_t alternate_next; - int flags; - int depth; - struct shared_region_object_chain *object_chain; - struct shared_region_mapping *self; - struct shared_region_mapping *next; -}; - -typedef struct shared_region_mapping *shared_region_mapping_t; - -struct shared_region_object_chain { - shared_region_mapping_t object_chain_region; - int depth; - struct shared_region_object_chain *next; -}; - -typedef struct shared_region_object_chain *shared_region_object_chain_t; - -#else /* !MACH_KERNEL_PRIVATE */ - -typedef void *shared_region_mapping_t; - -#endif /* MACH_KERNEL_PRIVATE */ - -/* address space shared region descriptor */ - -extern kern_return_t shared_region_mapping_info( - shared_region_mapping_t shared_region, - ipc_port_t *text_region, - vm_size_t *text_size, - ipc_port_t *data_region, - vm_size_t *data_size, - vm_offset_t *region_mappings, - vm_offset_t *client_base, - vm_offset_t *alternate_base, - vm_offset_t *alternate_next, - int *flags, - shared_region_mapping_t *next); - -extern kern_return_t shared_region_mapping_create( - ipc_port_t text_region, - vm_size_t text_size, - ipc_port_t data_region, - vm_size_t data_size, - vm_offset_t region_mappings, - vm_offset_t client_base, - shared_region_mapping_t *shared_region, - vm_offset_t alt_base, - vm_offset_t alt_next); - -extern kern_return_t shared_region_mapping_ref( - shared_region_mapping_t shared_region); - -extern kern_return_t shared_region_mapping_dealloc( - shared_region_mapping_t shared_region); - -extern kern_return_t -shared_region_object_chain_attach( - shared_region_mapping_t target_region, - shared_region_mapping_t object_chain); - -/* -extern kern_return_t vm_get_shared_region( - task_t task, - shared_region_mapping_t *shared_region); - -extern kern_return_t vm_set_shared_region( - task_t task, - shared_region_mapping_t shared_region); -*/ - #endif /* _VM_VM_MAP_H_ */ diff --git a/osfmk/vm/vm_object.c b/osfmk/vm/vm_object.c index 9cec5d486..3e2579dbf 100644 --- a/osfmk/vm/vm_object.c +++ b/osfmk/vm/vm_object.c @@ -254,7 +254,7 @@ static struct vm_object vm_object_template; * not be held to make simple references. */ static queue_head_t vm_object_cached_list; -static int vm_object_cached_count; +static int vm_object_cached_count=0; static int vm_object_cached_high; /* highest # cached objects */ static int vm_object_cached_max = 512; /* may be patched*/ @@ -472,6 +472,9 @@ vm_object_bootstrap(void) vm_object_template.nophyscache = FALSE; /* End bitfields */ + /* cache bitfields */ + vm_object_template.wimg_bits = VM_WIMG_DEFAULT; + /* cached_list; init after allocation */ vm_object_template.last_alloc = (vm_object_offset_t) 0; vm_object_template.cluster_size = 0; @@ -631,7 +634,7 @@ vm_object_deallocate( THREAD_UNINT); vm_object_unlock(object); vm_object_cache_unlock(); - thread_block((void (*)(void))0); + thread_block(THREAD_CONTINUE_NULL); continue; } @@ -797,6 +800,16 @@ vm_object_cache_trim( (integer_t)vm_object_cached_list.prev, 0, 0, 0); object = (vm_object_t) queue_first(&vm_object_cached_list); + if(object == (vm_object_t) &vm_object_cached_list) { + /* something's wrong with the calling parameter or */ + /* the value of vm_object_cached_count, just fix */ + /* and return */ + if(vm_object_cached_max < 0) + vm_object_cached_max = 0; + vm_object_cached_count = 0; + vm_object_cache_unlock(); + return VM_OBJECT_NULL; + } vm_object_lock(object); queue_remove(&vm_object_cached_list, object, vm_object_t, cached_list); @@ -1314,7 +1327,15 @@ vm_object_deactivate_pages( } VM_PAGE_QUEUES_REMOVE(m); - queue_enter_first(&vm_page_queue_inactive, m, vm_page_t, pageq); + if(m->zero_fill) { + queue_enter_first( + &vm_page_queue_zf, + m, vm_page_t, pageq); + } else { + queue_enter_first( + &vm_page_queue_inactive, + m, vm_page_t, pageq); + } m->inactive = TRUE; if (!m->fictitious) @@ -1382,6 +1403,8 @@ vm_object_pmap_protect( { if (object == VM_OBJECT_NULL) return; + size = round_page_64(size); + offset = trunc_page_64(offset); vm_object_lock(object); @@ -1395,9 +1418,12 @@ vm_object_pmap_protect( return; } - { - register vm_page_t p; - register vm_object_offset_t end; + /* if we are doing large ranges with respect to resident */ + /* page count then we should interate over pages otherwise */ + /* inverse page look-up will be faster */ + if ((object->resident_page_count / 4) < atop(size)) { + vm_page_t p; + vm_object_offset_t end; end = offset + size; @@ -1422,7 +1448,33 @@ vm_object_pmap_protect( } } } - } + } else { + vm_page_t p; + vm_object_offset_t end; + vm_object_offset_t target_off; + + end = offset + size; + + if (pmap != PMAP_NULL) { + for(target_off = offset; + target_off < end; target_off += PAGE_SIZE) { + if(p = vm_page_lookup(object, target_off)) { + vm_offset_t start = pmap_start + + (vm_offset_t)(p->offset - offset); + pmap_protect(pmap, start, + start + PAGE_SIZE, prot); + } + } + } else { + for(target_off = offset; + target_off < end; target_off += PAGE_SIZE) { + if(p = vm_page_lookup(object, target_off)) { + pmap_page_protect(p->phys_addr, + prot & ~p->page_lock); + } + } + } + } if (prot == VM_PROT_NONE) { /* @@ -1793,9 +1845,8 @@ vm_object_copy_call( */ copy_call_count++; while (vm_object_wanted(src_object, VM_OBJECT_EVENT_COPY_CALL)) { - vm_object_wait(src_object, VM_OBJECT_EVENT_COPY_CALL, + vm_object_sleep(src_object, VM_OBJECT_EVENT_COPY_CALL, THREAD_UNINT); - vm_object_lock(src_object); copy_call_restart_count++; } @@ -1828,9 +1879,8 @@ vm_object_copy_call( */ vm_object_lock(src_object); while (vm_object_wanted(src_object, VM_OBJECT_EVENT_COPY_CALL)) { - vm_object_wait(src_object, VM_OBJECT_EVENT_COPY_CALL, + vm_object_sleep(src_object, VM_OBJECT_EVENT_COPY_CALL, THREAD_UNINT); - vm_object_lock(src_object); copy_call_sleep_count++; } Retry: @@ -1859,9 +1909,7 @@ Retry: if (check_ready == TRUE) { vm_object_lock(copy); while (!copy->pager_ready) { - vm_object_wait(copy, VM_OBJECT_EVENT_PAGER_READY, - FALSE); - vm_object_lock(copy); + vm_object_sleep(copy, VM_OBJECT_EVENT_PAGER_READY, THREAD_UNINT); } vm_object_unlock(copy); } @@ -2138,18 +2186,18 @@ vm_object_copy_strategically( */ while (!src_object->internal && !src_object->pager_ready) { + wait_result_t wait_result; - vm_object_wait( src_object, - VM_OBJECT_EVENT_PAGER_READY, - interruptible); - if (interruptible && - (current_thread()->wait_result != THREAD_AWAKENED)) { + wait_result = vm_object_sleep( src_object, + VM_OBJECT_EVENT_PAGER_READY, + interruptible); + if (wait_result != THREAD_AWAKENED) { + vm_object_unlock(src_object); *dst_object = VM_OBJECT_NULL; *dst_offset = 0; *dst_needs_copy = FALSE; return(MACH_SEND_INTERRUPTED); } - vm_object_lock(src_object); } copy_strategy = src_object->copy_strategy; @@ -2641,10 +2689,9 @@ restart: */ while (!object->pager_initialized) { - vm_object_wait( object, + vm_object_sleep(object, VM_OBJECT_EVENT_INITIALIZED, THREAD_UNINT); - vm_object_lock(object); } vm_object_unlock(object); @@ -2696,10 +2743,9 @@ vm_object_pager_create( * wait for them to finish initializing the ports */ while (!object->pager_initialized) { - vm_object_wait( object, - VM_OBJECT_EVENT_INITIALIZED, - THREAD_UNINT); - vm_object_lock(object); + vm_object_sleep(object, + VM_OBJECT_EVENT_INITIALIZED, + THREAD_UNINT); } vm_object_paging_end(object); return; @@ -4109,10 +4155,9 @@ memory_object_create_named( vm_object_lock(object); object->named = TRUE; while (!object->pager_ready) { - vm_object_wait(object, - VM_OBJECT_EVENT_PAGER_READY, - FALSE); - vm_object_lock(object); + vm_object_sleep(object, + VM_OBJECT_EVENT_PAGER_READY, + THREAD_UNINT); } *control = object->pager_request; vm_object_unlock(object); @@ -4188,10 +4233,9 @@ restart: object->ref_count++; vm_object_res_reference(object); while (!object->pager_ready) { - vm_object_wait(object, - VM_OBJECT_EVENT_PAGER_READY, - FALSE); - vm_object_lock(object); + vm_object_sleep(object, + VM_OBJECT_EVENT_PAGER_READY, + THREAD_UNINT); } vm_object_unlock(object); return (KERN_SUCCESS); @@ -4251,7 +4295,7 @@ vm_object_release_name( THREAD_UNINT); vm_object_unlock(object); vm_object_cache_unlock(); - thread_block((void (*)(void)) 0); + thread_block(THREAD_CONTINUE_NULL); continue; } diff --git a/osfmk/vm/vm_object.h b/osfmk/vm/vm_object.h index 92044ab01..679ea7eb9 100644 --- a/osfmk/vm/vm_object.h +++ b/osfmk/vm/vm_object.h @@ -275,6 +275,10 @@ struct vm_object { * put in current object */ #endif + /* hold object lock when altering */ + unsigned int /* cache WIMG bits */ + wimg_bits:8, /* wimg plus some expansion*/ + not_in_use:24; #ifdef UBC_DEBUG queue_head_t uplq; /* List of outstanding upls */ #endif /* UBC_DEBUG */ @@ -519,17 +523,21 @@ __private_extern__ vm_object_t vm_object_enter( #define VM_OBJECT_EVENT_CACHING 7 #define vm_object_assert_wait(object, event, interruptible) \ - MACRO_BEGIN \ - (object)->all_wanted |= 1 << (event); \ - assert_wait((event_t)((vm_offset_t)(object)+(event)),(interruptible)); \ - MACRO_END + (((object)->all_wanted |= 1 << (event)), \ + assert_wait((event_t)((vm_offset_t)(object)+(event)),(interruptible))) #define vm_object_wait(object, event, interruptible) \ - MACRO_BEGIN \ - vm_object_assert_wait((object),(event),(interruptible)); \ - vm_object_unlock(object); \ - thread_block((void (*)(void)) 0); \ - MACRO_END + (vm_object_assert_wait((object),(event),(interruptible)), \ + vm_object_unlock(object), \ + thread_block(THREAD_CONTINUE_NULL)) \ + +#define thread_sleep_vm_object(object, event, interruptible) \ + thread_sleep_mutex((event_t)(event), &(object)->Lock, (interruptible)) + +#define vm_object_sleep(object, event, interruptible) \ + (((object)->all_wanted |= 1 << (event)), \ + thread_sleep_vm_object((object), \ + ((vm_offset_t)(object)+(event)), (interruptible))) #define vm_object_wakeup(object, event) \ MACRO_BEGIN \ @@ -567,13 +575,13 @@ __private_extern__ vm_object_t vm_object_enter( #define vm_object_paging_wait(object, interruptible) \ MACRO_BEGIN \ while ((object)->paging_in_progress != 0) { \ - vm_object_wait( (object), \ + wait_result_t _wr; \ + \ + _wr = vm_object_sleep((object), \ VM_OBJECT_EVENT_PAGING_IN_PROGRESS, \ (interruptible)); \ - vm_object_lock(object); \ \ - /*XXX if ((interruptible) && */ \ - /*XXX (current_thread()->wait_result != THREAD_AWAKENED))*/ \ + /*XXX if ((interruptible) && (_wr != THREAD_AWAKENED))*/\ /*XXX break; */ \ } \ MACRO_END diff --git a/osfmk/vm/vm_page.h b/osfmk/vm/vm_page.h index 2cb7f1a00..7ab8fe83e 100644 --- a/osfmk/vm/vm_page.h +++ b/osfmk/vm/vm_page.h @@ -84,6 +84,7 @@ extern int vm_page_ticket_roll; extern int vm_page_ticket; + #define VM_PAGE_TICKETS_IN_ROLL 512 #define VM_PAGE_TICKET_ROLL_IDS 16 @@ -134,6 +135,7 @@ struct vm_page { gobbled:1, /* page used internally (P) */ private:1, /* Page should not be returned to * the free list (O) */ + zero_fill:1, :0; unsigned int @@ -220,6 +222,7 @@ extern queue_head_t vm_page_queue_active; /* active memory queue */ extern queue_head_t vm_page_queue_inactive; /* inactive memory queue */ +queue_head_t vm_page_queue_zf; /* inactive memory queue for zero fill */ extern vm_offset_t first_phys_addr; /* physical address for first_page */ @@ -252,6 +255,7 @@ decl_mutex_data(,vm_page_queue_lock) decl_mutex_data(,vm_page_queue_free_lock) /* lock on free page queue */ decl_simple_lock_data(extern,vm_page_preppin_lock) /* lock for prep/pin */ +decl_mutex_data(,vm_page_zero_fill_lock) extern unsigned int vm_page_free_wanted; /* how many threads are waiting for memory */ @@ -374,10 +378,12 @@ extern void vm_page_gobble( */ #define PAGE_ASSERT_WAIT(m, interruptible) \ - MACRO_BEGIN \ - (m)->wanted = TRUE; \ - assert_wait((event_t) (m), (interruptible)); \ - MACRO_END + (((m)->wanted = TRUE), \ + assert_wait((event_t) (m), (interruptible))) + +#define PAGE_SLEEP(o, m, interruptible) \ + (((m)->wanted = TRUE), \ + thread_sleep_vm_object((o), (m), (interruptible))) #define PAGE_WAKEUP_DONE(m) \ MACRO_BEGIN \ @@ -433,8 +439,13 @@ extern void vm_page_gobble( \ if (mem->inactive) { \ assert(!mem->active); \ - queue_remove(&vm_page_queue_inactive, \ + if (mem->zero_fill) { \ + queue_remove(&vm_page_queue_zf, \ + mem, vm_page_t, pageq); \ + } else { \ + queue_remove(&vm_page_queue_inactive, \ mem, vm_page_t, pageq); \ + } \ mem->inactive = FALSE; \ if (!mem->fictitious) \ vm_page_inactive_count--; \ diff --git a/osfmk/vm/vm_pageout.c b/osfmk/vm/vm_pageout.c index 57ecaa12b..3dee3f693 100644 --- a/osfmk/vm/vm_pageout.c +++ b/osfmk/vm/vm_pageout.c @@ -183,6 +183,16 @@ unsigned int vm_pageout_pause_count = 0; unsigned int vm_pageout_pause_max = 0; unsigned int vm_free_page_pause = 100; /* milliseconds */ +/* + * Protection against zero fill flushing live working sets derived + * from existing backing store and files + */ +unsigned int vm_accellerate_zf_pageout_trigger = 400; +unsigned int vm_zf_iterator; +unsigned int vm_zf_iterator_count = 40; +unsigned int last_page_zf; +unsigned int vm_zf_count = 0; + /* * These variables record the pageout daemon's actions: * how many pages it looks at and what happens to those pages. @@ -1365,7 +1375,8 @@ vm_pageout_scan(void) * 2) Flow control - wait for untrusted pagers to catch up. */ - if (queue_empty(&vm_page_queue_inactive) || + if ((queue_empty(&vm_page_queue_inactive) && + (queue_empty(&vm_page_queue_zf))) || ((--loop_detect) == 0) || (burst_count >= vm_pageout_burst_max)) { unsigned int pages, msecs; @@ -1388,6 +1399,7 @@ vm_pageout_scan(void) } if (queue_empty(&vm_page_queue_inactive) && + queue_empty(&vm_page_queue_zf) && (msecs < vm_pageout_empty_wait)) msecs = vm_pageout_empty_wait; vm_page_unlock_queues(); @@ -1409,7 +1421,24 @@ vm_pageout_scan(void) } vm_pageout_inactive++; - m = (vm_page_t) queue_first(&vm_page_queue_inactive); + + if (vm_zf_count < vm_accellerate_zf_pageout_trigger) { + vm_zf_iterator = 0; + } else { + last_page_zf = 0; + if((vm_zf_iterator+=1) >= vm_zf_iterator_count) { + vm_zf_iterator = 0; + } + } + if(queue_empty(&vm_page_queue_zf) || + (((last_page_zf) || (vm_zf_iterator == 0)) && + !queue_empty(&vm_page_queue_inactive))) { + m = (vm_page_t) queue_first(&vm_page_queue_inactive); + last_page_zf = 0; + } else { + m = (vm_page_t) queue_first(&vm_page_queue_zf); + last_page_zf = 1; + } if ((vm_page_free_count <= vm_page_free_reserved) && (IP_VALID(memory_manager_default))) { @@ -1440,10 +1469,15 @@ vm_pageout_scan(void) vm_object_unlock(object); } m = (vm_page_t) queue_next(&m->pageq); - } while (!queue_end(&vm_page_queue_inactive, - (queue_entry_t) m)); - if (queue_end(&vm_page_queue_inactive, - (queue_entry_t) m)) { + } while ((!queue_end(&vm_page_queue_zf, + (queue_entry_t) m)) + && (!queue_end(&vm_page_queue_inactive, + (queue_entry_t) m))); + + if ((queue_end(&vm_page_queue_zf, + (queue_entry_t) m)) + || (queue_end(&vm_page_queue_inactive, + (queue_entry_t) m))) { vm_pageout_scan_inactive_emm_throttle_failure++; /* * We should check the "active" queue @@ -1451,8 +1485,15 @@ vm_pageout_scan(void) */ need_more_inactive_pages = TRUE; - m = (vm_page_t) - queue_first(&vm_page_queue_inactive); + if(last_page_zf == 0) { + last_page_zf = 1; + vm_zf_iterator = vm_zf_iterator_count - 1; + } else { + last_page_zf = 0; + vm_zf_iterator = vm_zf_iterator_count - 2; + } + vm_page_unlock_queues(); + goto Restart; } } @@ -1469,10 +1510,17 @@ vm_pageout_scan(void) * Move page to end and continue. * Don't re-issue ticket */ - queue_remove(&vm_page_queue_inactive, m, + if(m->zero_fill) { + queue_remove(&vm_page_queue_zf, m, + vm_page_t, pageq); + queue_enter(&vm_page_queue_zf, m, + vm_page_t, pageq); + } else { + queue_remove(&vm_page_queue_inactive, m, vm_page_t, pageq); - queue_enter(&vm_page_queue_inactive, m, + queue_enter(&vm_page_queue_inactive, m, vm_page_t, pageq); + } vm_page_unlock_queues(); mutex_pause(); @@ -1504,10 +1552,21 @@ vm_pageout_scan(void) * one of its logically adjacent fellows is * targeted. */ - queue_remove(&vm_page_queue_inactive, m, - vm_page_t, pageq); - queue_enter(&vm_page_queue_inactive, m, - vm_page_t, pageq); + if(m->zero_fill) { + queue_remove(&vm_page_queue_zf, m, + vm_page_t, pageq); + queue_enter(&vm_page_queue_zf, m, + vm_page_t, pageq); + last_page_zf = 1; + vm_zf_iterator = vm_zf_iterator_count - 1; + } else { + queue_remove(&vm_page_queue_inactive, m, + vm_page_t, pageq); + queue_enter(&vm_page_queue_inactive, m, + vm_page_t, pageq); + last_page_zf = 0; + vm_zf_iterator = 1; + } vm_page_unlock_queues(); vm_object_unlock(object); vm_pageout_inactive_avoid++; @@ -1518,7 +1577,11 @@ vm_pageout_scan(void) * Remove the page from the inactive list. */ - queue_remove(&vm_page_queue_inactive, m, vm_page_t, pageq); + if(m->zero_fill) { + queue_remove(&vm_page_queue_zf, m, vm_page_t, pageq); + } else { + queue_remove(&vm_page_queue_inactive, m, vm_page_t, pageq); + } m->inactive = FALSE; if (!m->fictitious) vm_page_inactive_count--; @@ -1584,6 +1647,7 @@ vm_pageout_scan(void) m->discard_request = FALSE; } #endif /* ADVISORY_PAGEOUT */ + last_page_zf = 0; vm_object_unlock(object); vm_page_activate(m); VM_STAT(reactivations++); @@ -1815,10 +1879,8 @@ vm_pageout(void) s = splsched(); thread_lock(self); - self->priority = BASEPRI_PREEMPT - 1; - self->sched_pri = self->priority; - + set_sched_pri(self, self->priority); thread_unlock(self); splx(s); @@ -1839,6 +1901,7 @@ vm_pageout(void) vm_pageout_empty_wait = VM_PAGEOUT_EMPTY_WAIT; vm_page_free_count_init = vm_page_free_count; + vm_zf_iterator = 0; /* * even if we've already called vm_page_free_reserve * call it again here to insure that the targets are @@ -1873,11 +1936,95 @@ vm_pageout(void) /*NOTREACHED*/ } +kern_return_t +vm_pageout_emergency_availability_request() +{ + vm_page_t m; + vm_object_t object; + + vm_page_lock_queues(); + m = (vm_page_t) queue_first(&vm_page_queue_inactive); + + while (!queue_end(&vm_page_queue_inactive, (queue_entry_t) m)) { + if(m->fictitious) { + m = (vm_page_t) queue_next(&m->pageq); + continue; + } + if (!m->dirty) + m->dirty = pmap_is_modified(m->phys_addr); + if(m->dirty || m->busy || m->wire_count || m->absent + || m->precious || m->cleaning + || m->dump_cleaning || m->error + || m->pageout || m->laundry + || m->list_req_pending + || m->overwriting) { + m = (vm_page_t) queue_next(&m->pageq); + continue; + } + object = m->object; + + if (vm_object_lock_try(object)) { + if((!object->alive) || + (object->pageout)) { + vm_object_unlock(object); + m = (vm_page_t) queue_next(&m->pageq); + continue; + } + m->busy = TRUE; + pmap_page_protect(m->phys_addr, VM_PROT_NONE); + vm_page_free(m); + vm_object_unlock(object); + vm_page_unlock_queues(); + return KERN_SUCCESS; + } + m = (vm_page_t) queue_next(&m->pageq); + } + + m = (vm_page_t) queue_first(&vm_page_queue_active); + + while (!queue_end(&vm_page_queue_active, (queue_entry_t) m)) { + if(m->fictitious) { + m = (vm_page_t) queue_next(&m->pageq); + continue; + } + if (!m->dirty) + m->dirty = pmap_is_modified(m->phys_addr); + if(m->dirty || m->busy || m->wire_count || m->absent + || m->precious || m->cleaning + || m->dump_cleaning || m->error + || m->pageout || m->laundry + || m->list_req_pending + || m->overwriting) { + m = (vm_page_t) queue_next(&m->pageq); + continue; + } + object = m->object; + + if (vm_object_lock_try(object)) { + if((!object->alive) || + (object->pageout)) { + vm_object_unlock(object); + m = (vm_page_t) queue_next(&m->pageq); + continue; + } + m->busy = TRUE; + pmap_page_protect(m->phys_addr, VM_PROT_NONE); + vm_page_free(m); + vm_object_unlock(object); + vm_page_unlock_queues(); + return KERN_SUCCESS; + } + m = (vm_page_t) queue_next(&m->pageq); + } + vm_page_unlock_queues(); + return KERN_FAILURE; +} + static upl_t upl_create( boolean_t internal, - vm_size_t size) + vm_size_t size) { upl_t upl; @@ -1928,7 +2075,7 @@ upl_destroy( if(upl->flags & UPL_INTERNAL) { kfree((vm_offset_t)upl, sizeof(struct upl) + - (sizeof(struct upl_page_info) * (upl->size/page_size))); + (sizeof(struct upl_page_info) * (upl->size/page_size))); } else { kfree((vm_offset_t)upl, sizeof(struct upl)); } @@ -2083,6 +2230,7 @@ vm_object_upl_request( upl->map_object->can_persist = FALSE; upl->map_object->copy_strategy = MEMORY_OBJECT_COPY_NONE; upl->map_object->shadow_offset = offset; + upl->map_object->wimg_bits = object->wimg_bits; vm_object_unlock(upl->map_object); *upl_ptr = upl; } @@ -2137,11 +2285,7 @@ vm_object_upl_request( } /*someone else is playing with the */ /* page. We will have to wait. */ - PAGE_ASSERT_WAIT( - dst_page, THREAD_UNINT); - vm_object_unlock(object); - thread_block((void(*)(void))0); - vm_object_lock(object); + PAGE_SLEEP(object, dst_page, THREAD_UNINT); continue; } /* Someone else already cleaning the page? */ @@ -2159,9 +2303,9 @@ vm_object_upl_request( /* original object and its prodigy */ vm_page_lock_queues(); - pmap_page_protect(dst_page->phys_addr, - VM_PROT_NONE); - + if( !(cntrl_flags & UPL_FILE_IO)) { + pmap_page_protect(dst_page->phys_addr, VM_PROT_NONE); + } /* pageout statistics gathering. count */ /* all the pages we will page out that */ /* were not counted in the initial */ @@ -2246,14 +2390,25 @@ vm_object_upl_request( } dst_page = vm_page_lookup(object, dst_offset); if(dst_page != VM_PAGE_NULL) { + if((cntrl_flags & UPL_RET_ONLY_ABSENT) && + !((dst_page->list_req_pending) + && (dst_page->absent))) { + /* we are doing extended range */ + /* requests. we want to grab */ + /* pages around some which are */ + /* already present. */ + if(user_page_list) + user_page_list[entry].phys_addr = 0; + entry++; + dst_offset += PAGE_SIZE_64; + xfer_size -= PAGE_SIZE; + continue; + } if((dst_page->cleaning) && !(dst_page->list_req_pending)) { /*someone else is writing to the */ /* page. We will have to wait. */ - PAGE_ASSERT_WAIT(dst_page,THREAD_UNINT); - vm_object_unlock(object); - thread_block((void(*)(void))0); - vm_object_lock(object); + PAGE_SLEEP(object,dst_page,THREAD_UNINT); continue; } if ((dst_page->fictitious && @@ -2331,17 +2486,14 @@ vm_object_upl_request( if(dst_page->busy) { /*someone else is playing with the */ /* page. We will have to wait. */ - PAGE_ASSERT_WAIT( - dst_page, THREAD_UNINT); - vm_object_unlock(object); - thread_block((void(*)(void))0); - vm_object_lock(object); + PAGE_SLEEP(object, dst_page, THREAD_UNINT); continue; } vm_page_lock_queues(); - pmap_page_protect(dst_page->phys_addr, - VM_PROT_NONE); + if( !(cntrl_flags & UPL_FILE_IO)) { + pmap_page_protect(dst_page->phys_addr, VM_PROT_NONE); + } dirty = pmap_is_modified(dst_page->phys_addr); dirty = dirty ? TRUE : dst_page->dirty; @@ -2423,18 +2575,17 @@ vm_object_upl_request( ? VM_PROT_READ : VM_PROT_WRITE; while (TRUE) { kern_return_t rc; - thread_t thread; if(!object->pager_ready) { - thread = current_thread(); - vm_object_assert_wait(object, - VM_OBJECT_EVENT_PAGER_READY, THREAD_UNINT); - vm_object_unlock(object); - thread_block((void (*)(void))0); - if (thread->wait_result != THREAD_AWAKENED) { - return(KERN_FAILURE); + wait_result_t wait_result; + + wait_result = vm_object_sleep(object, + VM_OBJECT_EVENT_PAGER_READY, + THREAD_UNINT); + if (wait_result != THREAD_AWAKENED) { + vm_object_unlock(object); + return(KERN_FAILURE); } - vm_object_lock(object); continue; } @@ -2629,7 +2780,12 @@ vm_upl_map( for(addr=*dst_addr; size > 0; size-=PAGE_SIZE,addr+=PAGE_SIZE) { m = vm_page_lookup(upl->map_object, offset); if(m) { - PMAP_ENTER(map->pmap, addr, m, VM_PROT_ALL, TRUE); + unsigned int cache_attr; + cache_attr = ((unsigned int)m->object->wimg_bits) & VM_WIMG_MASK; + + PMAP_ENTER(map->pmap, addr, + m, VM_PROT_ALL, + cache_attr, TRUE); } offset+=PAGE_SIZE_64; } @@ -3311,6 +3467,21 @@ vm_countdirtypages(void) } while (!queue_end(&vm_page_queue_inactive,(queue_entry_t) m)); vm_page_unlock_queues(); + vm_page_lock_queues(); + m = (vm_page_t) queue_first(&vm_page_queue_zf); + do { + if (m ==(vm_page_t )0) break; + + if(m->dirty) dpages++; + if(m->pageout) pgopages++; + if(m->precious) precpages++; + + m = (vm_page_t) queue_next(&m->pageq); + if (m ==(vm_page_t )0) break; + + } while (!queue_end(&vm_page_queue_zf,(queue_entry_t) m)); + vm_page_unlock_queues(); + printf("IN Q: %d : %d : %d\n", dpages, pgopages, precpages); dpages=0; diff --git a/osfmk/vm/vm_pageout.h b/osfmk/vm/vm_pageout.h index e9515c4d7..853719b7c 100644 --- a/osfmk/vm/vm_pageout.h +++ b/osfmk/vm/vm_pageout.h @@ -69,6 +69,7 @@ extern unsigned int vm_pageout_scan_event_counter; +extern unsigned int vm_zf_count; /* * The following ifdef only exists because XMM must (currently) diff --git a/osfmk/vm/vm_resident.c b/osfmk/vm/vm_resident.c index 8828064d8..bf946edce 100644 --- a/osfmk/vm/vm_resident.c +++ b/osfmk/vm/vm_resident.c @@ -56,6 +56,7 @@ * Resident memory management module. */ +#include #include #include #include @@ -203,6 +204,8 @@ unsigned int vm_page_free_count_minimum; /* debugging */ */ zone_t vm_page_zone; decl_mutex_data(,vm_page_alloc_lock) +unsigned int io_throttle_zero_fill; +decl_mutex_data(,vm_page_zero_fill_lock) /* * Fictitious pages don't have a physical address, @@ -217,10 +220,14 @@ vm_offset_t vm_page_fictitious_addr = (vm_offset_t) -1; * queues that are used by the page replacement * system (pageout daemon). These queues are * defined here, but are shared by the pageout - * module. + * module. The inactive queue is broken into + * inactive and zf for convenience as the + * pageout daemon often assignes a higher + * affinity to zf pages */ queue_head_t vm_page_queue_active; queue_head_t vm_page_queue_inactive; +queue_head_t vm_page_queue_zf; decl_mutex_data(,vm_page_queue_lock) int vm_page_active_count; int vm_page_inactive_count; @@ -338,6 +345,7 @@ vm_page_bootstrap( m->lock_supplied = FALSE; m->unusual = FALSE; m->restart = FALSE; + m->zero_fill = FALSE; m->phys_addr = 0; /* reset later */ @@ -357,6 +365,7 @@ vm_page_bootstrap( vm_page_queue_fictitious = VM_PAGE_NULL; queue_init(&vm_page_queue_active); queue_init(&vm_page_queue_inactive); + queue_init(&vm_page_queue_zf); queue_init(&vm_page_queue_limbo); vm_page_free_wanted = 0; @@ -510,7 +519,8 @@ pmap_steal_memory( */ pmap_enter(kernel_pmap, vaddr, paddr, - VM_PROT_READ|VM_PROT_WRITE, FALSE); + VM_PROT_READ|VM_PROT_WRITE, + VM_WIMG_USE_DEFAULT, FALSE); /* * Account for newly stolen memory */ @@ -605,6 +615,7 @@ vm_page_module_init(void) vm_page_zone->cur_size += vm_page_pages * vm_page_zone->elem_size; mutex_init(&vm_page_alloc_lock, ETAP_VM_PAGE_ALLOC); + mutex_init(&vm_page_zero_fill_lock, ETAP_VM_PAGE_ALLOC); } /* @@ -1276,6 +1287,8 @@ vm_page_release( mutex_unlock(&vm_page_queue_free_lock); } +#define VM_PAGEOUT_DEADLOCK_TIMEOUT 3 + /* * vm_page_wait: * @@ -1298,20 +1311,39 @@ vm_page_wait( * succeeds, the second fails. After the first page is freed, * a call to vm_page_wait must really block. */ - kern_return_t wait_result; - int need_wakeup = 0; + uint64_t abstime; + kern_return_t wait_result; + kern_return_t kr; + int need_wakeup = 0; mutex_lock(&vm_page_queue_free_lock); if (vm_page_free_count < vm_page_free_target) { if (vm_page_free_wanted++ == 0) need_wakeup = 1; - assert_wait((event_t)&vm_page_free_count, interruptible); + wait_result = assert_wait((event_t)&vm_page_free_count, + interruptible); mutex_unlock(&vm_page_queue_free_lock); counter(c_vm_page_wait_block++); if (need_wakeup) thread_wakeup((event_t)&vm_page_free_wanted); - wait_result = thread_block((void (*)(void))0); + + if (wait_result == THREAD_WAITING) { + clock_interval_to_absolutetime_interval( + VM_PAGEOUT_DEADLOCK_TIMEOUT, + NSEC_PER_SEC, &abstime); + clock_absolutetime_interval_to_deadline( + abstime, &abstime); + thread_set_timer_deadline(abstime); + wait_result = thread_block(THREAD_CONTINUE_NULL); + + if(wait_result == THREAD_TIMED_OUT) { + kr = vm_pageout_emergency_availability_request(); + return TRUE; + } else { + thread_cancel_timer(); + } + } return(wait_result == THREAD_AWAKENED); } else { @@ -1427,6 +1459,11 @@ vm_page_free( if (mem->fictitious) { vm_page_release_fictitious(mem); } else { + /* depends on the queues lock */ + if(mem->zero_fill) { + vm_zf_count-=1; + mem->zero_fill = FALSE; + } vm_page_init(mem, mem->phys_addr); vm_page_release(mem); } @@ -1457,6 +1494,11 @@ vm_page_wire( if (mem->gobbled) vm_page_gobble_count--; mem->gobbled = FALSE; + if(mem->zero_fill) { + /* depends on the queues lock */ + vm_zf_count-=1; + mem->zero_fill = FALSE; + } } assert(!mem->gobbled); mem->wire_count++; @@ -1567,7 +1609,13 @@ vm_page_deactivate( vm_page_ticket++; } - queue_enter(&vm_page_queue_inactive, m, vm_page_t, pageq); + if(m->zero_fill) { + queue_enter(&vm_page_queue_zf, m, vm_page_t, pageq); + } else { + queue_enter(&vm_page_queue_inactive, + m, vm_page_t, pageq); + } + m->inactive = TRUE; if (!m->fictitious) vm_page_inactive_count++; @@ -1599,7 +1647,12 @@ vm_page_activate( return; if (m->inactive) { - queue_remove(&vm_page_queue_inactive, m, vm_page_t, pageq); + if (m->zero_fill) { + queue_remove(&vm_page_queue_zf, m, vm_page_t, pageq); + } else { + queue_remove(&vm_page_queue_inactive, + m, vm_page_t, pageq); + } if (!m->fictitious) vm_page_inactive_count--; m->inactive = FALSE; diff --git a/osfmk/vm/vm_shared_memory_server.c b/osfmk/vm/vm_shared_memory_server.c index b1fc23972..c685c5418 100644 --- a/osfmk/vm/vm_shared_memory_server.c +++ b/osfmk/vm/vm_shared_memory_server.c @@ -29,7 +29,6 @@ #include #include -#include #include #include #include @@ -37,14 +36,66 @@ #include #include +#include +#include + +/* forward declarations */ +static kern_return_t +shared_file_init( + ipc_port_t *shared_text_region_handle, + vm_size_t text_region_size, + ipc_port_t *shared_data_region_handle, + vm_size_t data_region_size, + vm_offset_t *shared_file_mapping_array); + +static load_struct_t * +lsf_hash_lookup( + queue_head_t *hash_table, + void *file_object, + int size, + boolean_t alternate, + shared_region_task_mappings_t sm_info); + +static load_struct_t * +lsf_hash_delete( + void *file_object, + vm_offset_t base_offset, + shared_region_task_mappings_t sm_info); + +static void +lsf_hash_insert( + load_struct_t *entry, + shared_region_task_mappings_t sm_info); + +static kern_return_t +lsf_load( + vm_offset_t mapped_file, + vm_size_t mapped_file_size, + vm_offset_t *base_address, + sf_mapping_t *mappings, + int map_cnt, + void *file_object, + int flags, + shared_region_task_mappings_t sm_info); + +static void +lsf_unload( + void *file_object, + vm_offset_t base_offset, + shared_region_task_mappings_t sm_info); + + +#define load_file_hash(file_object, size) \ + ((((natural_t)file_object) & 0xffffff) % size) +/* Implementation */ vm_offset_t shared_file_text_region; vm_offset_t shared_file_data_region; ipc_port_t shared_text_region_handle; ipc_port_t shared_data_region_handle; vm_offset_t shared_file_mapping_array = 0; -shared_region_mapping_t system_shared_region; +shared_region_mapping_t system_shared_region = NULL; ipc_port_t sfma_handle = NULL; zone_t lsf_zone; @@ -84,18 +135,31 @@ shared_file_boot_time_init( { long shared_text_region_size; long shared_data_region_size; + shared_region_mapping_t new_system_region; + shared_region_mapping_t old_system_region; shared_text_region_size = 0x10000000; shared_data_region_size = 0x10000000; shared_file_init(&shared_text_region_handle, shared_text_region_size, &shared_data_region_handle, shared_data_region_size, &shared_file_mapping_array); + shared_region_mapping_create(shared_text_region_handle, shared_text_region_size, shared_data_region_handle, shared_data_region_size, shared_file_mapping_array, - GLOBAL_SHARED_TEXT_SEGMENT, &system_shared_region, + GLOBAL_SHARED_TEXT_SEGMENT, &new_system_region, 0x9000000, 0x9000000); + old_system_region = system_shared_region; + system_shared_region = new_system_region; system_shared_region->flags = SHARED_REGION_SYSTEM; + /* consume the reference held because this is the */ + /* system shared region */ + if(old_system_region) { + shared_region_mapping_dealloc(old_system_region); + } + /* hold an extra reference because these are the system */ + /* shared regions. */ + shared_region_mapping_ref(system_shared_region); vm_set_shared_region(current_task(), system_shared_region); } @@ -108,7 +172,7 @@ shared_file_boot_time_init( /* but also coordinates requests for space. */ -kern_return_t +static kern_return_t shared_file_init( ipc_port_t *shared_text_region_handle, vm_size_t text_region_size, @@ -172,7 +236,8 @@ shared_file_init( p->busy = FALSE; vm_object_unlock(buf_object); pmap_enter(kernel_pmap, b, p->phys_addr, - VM_PROT_READ | VM_PROT_WRITE, TRUE); + VM_PROT_READ | VM_PROT_WRITE, + VM_WIMG_USE_DEFAULT, TRUE); } @@ -387,9 +452,13 @@ copyin_shared_file( regions = (shared_region_mapping_t)sm_info->self; regions->flags |= SHARED_REGION_FULL; if(regions == system_shared_region) { + shared_region_mapping_t new_system_shared_regions; shared_file_boot_time_init(); - /* current task must stay wit its current */ - /* regions */ + /* current task must stay with its current */ + /* regions, drop count on system_shared_region */ + /* and put back our original set */ + vm_get_shared_region(current_task(), &new_system_shared_regions); + shared_region_mapping_dealloc(new_system_shared_regions); vm_set_shared_region(current_task(), regions); } } @@ -401,7 +470,7 @@ copyin_shared_file( /* A hash lookup function for the list of loaded files in */ /* shared_memory_server space. */ -load_struct_t * +static load_struct_t * lsf_hash_lookup( queue_head_t *hash_table, void *file_object, @@ -486,7 +555,7 @@ lsf_remove_regions_mappings( /* Removes a map_list, (list of loaded extents) for a file from */ /* the loaded file hash table. */ -load_struct_t * +static load_struct_t * lsf_hash_delete( void *file_object, vm_offset_t base_offset, @@ -522,7 +591,7 @@ lsf_hash_delete( /* Inserts a new map_list, (list of loaded file extents), into the */ /* server loaded file hash table. */ -void +static void lsf_hash_insert( load_struct_t *entry, shared_region_task_mappings_t sm_info) @@ -542,7 +611,7 @@ lsf_hash_insert( /* if any extent fails to load or if the file was already loaded */ /* in a different configuration, lsf_load fails. */ -kern_return_t +static kern_return_t lsf_load( vm_offset_t mapped_file, vm_size_t mapped_file_size, @@ -708,7 +777,7 @@ lsf_load( /* If one is found the associated extents in shared memory are deallocated */ /* and the extent list is freed */ -void +static void lsf_unload( void *file_object, vm_offset_t base_offset, @@ -741,3 +810,10 @@ lsf_unload( shared_file_available_hash_ele++; } } + +/* integer is from 1 to 100 and represents percent full */ +unsigned int +lsf_mapping_pool_gauge() +{ + return ((lsf_zone->count * lsf_zone->elem_size) * 100)/lsf_zone->max_size; +} diff --git a/osfmk/vm/vm_shared_memory_server.h b/osfmk/vm/vm_shared_memory_server.h new file mode 100644 index 000000000..259be7ea1 --- /dev/null +++ b/osfmk/vm/vm_shared_memory_server.h @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2002,2000 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * + * File: vm/vm_shared_memory_server.h + * + * protos and struct definitions for shared library + * server and interface + */ + +#ifndef _VM_SHARED_MEMORY_SERVER_H_ +#define _VM_SHARED_MEMORY_SERVER_H_ + +#include + +#ifdef __APPLE_API_PRIVATE + +#include +#include +#include + +#include + +extern mach_port_t shared_text_region_handle; +extern mach_port_t shared_data_region_handle; + +struct shared_region_task_mappings { + mach_port_t text_region; + vm_size_t text_size; + mach_port_t data_region; + vm_size_t data_size; + vm_offset_t region_mappings; + vm_offset_t client_base; + vm_offset_t alternate_base; + vm_offset_t alternate_next; + int flags; + vm_offset_t self; +}; + +#define SHARED_REGION_SYSTEM 0x1 +#define SHARED_REGION_FULL 0x2 + +typedef struct shared_region_task_mappings *shared_region_task_mappings_t; +typedef struct shared_region_mapping *shared_region_mapping_t; + + +#ifdef MACH_KERNEL_PRIVATE + +#include +#include +#include + +extern vm_offset_t shared_file_mapping_array; + +struct loaded_mapping { + vm_offset_t mapping_offset; + vm_size_t size; + vm_offset_t file_offset; + vm_prot_t protection; /* read/write/execute/COW/ZF */ + + struct loaded_mapping *next; +}; + +typedef struct loaded_mapping loaded_mapping_t; + +struct load_struct { + queue_chain_t links; + shared_region_mapping_t regions_instance; + int depth; + int file_object; + vm_offset_t base_address; + int mapping_cnt; + loaded_mapping_t *mappings; +}; + +typedef struct load_struct load_struct_t; +typedef struct load_struct *load_struct_ptr_t; + +struct load_file_ele { + union { + sf_mapping_t mapping; + load_struct_t element; + } u; +}; + +struct shared_file_info { + mutex_t lock; /* lock for the structure */ + queue_head_t *hash; /* for later perf enhance */ + int hash_size; + boolean_t hash_init; +}; + +typedef struct shared_file_info shared_file_info_t; + +struct shared_region_object_chain { + shared_region_mapping_t object_chain_region; + int depth; + struct shared_region_object_chain *next; +}; +typedef struct shared_region_object_chain *shared_region_object_chain_t; + +/* address space shared region descriptor */ +struct shared_region_mapping { + decl_mutex_data(, Lock) /* Synchronization */ + int ref_count; + mach_port_t text_region; + vm_size_t text_size; + mach_port_t data_region; + vm_size_t data_size; + vm_offset_t region_mappings; + vm_offset_t client_base; + vm_offset_t alternate_base; + vm_offset_t alternate_next; + int flags; + int depth; + shared_region_object_chain_t object_chain; + shared_region_mapping_t self; + shared_region_mapping_t next; +}; + +#define shared_region_mapping_lock_init(object) \ + mutex_init(&(object)->Lock, ETAP_VM_OBJ) +#define shared_region_mapping_lock(object) mutex_lock(&(object)->Lock) +#define shared_region_mapping_unlock(object) mutex_unlock(&(object)->Lock) + +#else /* !MACH_KERNEL_PRIVATE */ + +struct shared_region_mapping ; + +#endif /* MACH_KERNEL_PRIVATE */ + +extern kern_return_t copyin_shared_file( + vm_offset_t mapped_file, + vm_size_t mapped_file_size, + vm_offset_t *base_address, + int map_cnt, + sf_mapping_t *mappings, + memory_object_control_t file_control, + shared_region_task_mappings_t shared_region, + int *flags); + +extern kern_return_t shared_region_mapping_info( + shared_region_mapping_t shared_region, + mach_port_t *text_region, + vm_size_t *text_size, + mach_port_t *data_region, + vm_size_t *data_size, + vm_offset_t *region_mappings, + vm_offset_t *client_base, + vm_offset_t *alternate_base, + vm_offset_t *alternate_next, + int *flags, + shared_region_mapping_t *next); + +extern kern_return_t shared_region_mapping_create( + mach_port_t text_region, + vm_size_t text_size, + mach_port_t data_region, + vm_size_t data_size, + vm_offset_t region_mappings, + vm_offset_t client_base, + shared_region_mapping_t *shared_region, + vm_offset_t alt_base, + vm_offset_t alt_next); + +extern kern_return_t shared_region_mapping_ref( + shared_region_mapping_t shared_region); + +extern kern_return_t shared_region_mapping_dealloc( + shared_region_mapping_t shared_region); + +extern kern_return_t shared_region_object_chain_attach( + shared_region_mapping_t target_region, + shared_region_mapping_t object_chain); + +extern kern_return_t vm_get_shared_region( + task_t task, + shared_region_mapping_t *shared_region); + +extern kern_return_t vm_set_shared_region( + task_t task, + shared_region_mapping_t shared_region); + +extern unsigned int lsf_mapping_pool_gauge(); + +#endif /* __APPLE_API_PRIVATE */ + +#endif /* _VM_SHARED_MEMORY_SERVER_H_ */ diff --git a/osfmk/vm/vm_user.c b/osfmk/vm/vm_user.c index 06794d0b1..ede0d2591 100644 --- a/osfmk/vm/vm_user.c +++ b/osfmk/vm/vm_user.c @@ -67,7 +67,9 @@ #include #include #include + #include +#include #include #include @@ -542,6 +544,11 @@ vm_map_64( /* wait for object (if any) to be ready */ if (object != VM_OBJECT_NULL) { + if(object == kernel_object) { + printf("Warning: Attempt to map kernel object" + " by a non-private kernel entity\n"); + return(KERN_INVALID_OBJECT); + } vm_object_lock(object); while (!object->pager_ready) { vm_object_wait(object, @@ -1167,7 +1174,8 @@ vm_allocate_cpm( m = vm_page_lookup(cpm_obj, (vm_object_offset_t)offset); vm_object_unlock(cpm_obj); assert(m != VM_PAGE_NULL); - PMAP_ENTER(pmap, va, m, VM_PROT_ALL, TRUE); + PMAP_ENTER(pmap, va, m, VM_PROT_ALL, + VM_WIMG_USE_DEFAULT, TRUE); } #if MACH_ASSERT @@ -1323,18 +1331,26 @@ mach_make_memory_entry_64( vm_map_t pmap_map; /* needed for call to vm_map_lookup_locked */ - boolean_t wired; + boolean_t wired; vm_object_offset_t obj_off; - vm_prot_t prot; + vm_prot_t prot; vm_object_offset_t lo_offset, hi_offset; vm_behavior_t behavior; - vm_object_t object; + vm_object_t object; + vm_object_t shadow_object; /* needed for direct map entry manipulation */ vm_map_entry_t map_entry; - vm_map_t local_map; + vm_map_entry_t next_entry; + vm_map_t local_map; + vm_map_t original_map = target_map; + vm_offset_t local_offset; vm_object_size_t mappable_size; + vm_object_size_t total_size; + + offset = trunc_page_64(offset); + *size = round_page_64(*size); user_object = (vm_named_entry_t) kalloc(sizeof (struct vm_named_entry)); @@ -1382,22 +1398,37 @@ mach_make_memory_entry_64( vm_map_unlock_read(target_map); goto make_mem_done; } - if ((prot & permission) != permission) { + if (((prot & permission) != permission) + || (object == kernel_object)) { kr = KERN_INVALID_RIGHT; vm_object_unlock(object); vm_map_unlock_read(target_map); if(pmap_map != target_map) vm_map_unlock_read(pmap_map); + if(object == kernel_object) { + printf("Warning: Attempt to create a named" + " entry from the kernel_object\n"); + } goto make_mem_done; } /* We have an object, now check to see if this object */ /* is suitable. If not, create a shadow and share that */ - local_map = target_map; redo_lookup: + local_map = original_map; + local_offset = offset; + if(target_map != local_map) { + vm_map_unlock_read(target_map); + if(pmap_map != target_map) + vm_map_unlock_read(pmap_map); + vm_map_lock_read(local_map); + target_map = local_map; + pmap_map = local_map; + } while(TRUE) { - if(!vm_map_lookup_entry(local_map, offset, &map_entry)) { + if(!vm_map_lookup_entry(local_map, + local_offset, &map_entry)) { kr = KERN_INVALID_ARGUMENT; vm_object_unlock(object); vm_map_unlock_read(target_map); @@ -1414,14 +1445,21 @@ redo_lookup: vm_map_unlock_read(pmap_map); goto make_mem_done; } + if(map_entry->wired_count) { + object->true_share = TRUE; + } break; } else { + vm_map_t tmap; + tmap = local_map; local_map = map_entry->object.sub_map; + vm_map_lock_read(local_map); - vm_map_unlock_read(target_map); - if(pmap_map != target_map) - vm_map_unlock_read(pmap_map); + vm_map_unlock_read(tmap); target_map = local_map; + pmap_map = local_map; + local_offset = local_offset - map_entry->vme_start; + local_offset += map_entry->offset; } } if(((map_entry->max_protection) & permission) != permission) { @@ -1432,6 +1470,40 @@ redo_lookup: vm_map_unlock_read(pmap_map); goto make_mem_done; } + + mappable_size = hi_offset - obj_off; + total_size = map_entry->vme_end - map_entry->vme_start; + if(*size > mappable_size) { + /* try to extend mappable size if the entries */ + /* following are from the same object and are */ + /* compatible */ + next_entry = map_entry->vme_next; + /* lets see if the next map entry is still */ + /* pointing at this object and is contiguous */ + while(*size > mappable_size) { + if((next_entry->object.vm_object == object) && + (next_entry->vme_start == + next_entry->vme_prev->vme_end) && + (next_entry->offset == + next_entry->vme_prev->offset + + (next_entry->vme_prev->vme_end - + next_entry->vme_prev->vme_start))) { + if(((next_entry->max_protection) + & permission) != permission) { + break; + } + mappable_size += next_entry->vme_end + - next_entry->vme_start; + total_size += next_entry->vme_end + - next_entry->vme_start; + next_entry = next_entry->vme_next; + } else { + break; + } + + } + } + if(object->internal) { /* vm_map_lookup_locked will create a shadow if */ /* needs_copy is set but does not check for the */ @@ -1440,10 +1512,8 @@ redo_lookup: /* under us. */ if ((map_entry->needs_copy || object->shadowed || - (object->size > - ((vm_object_size_t)map_entry->vme_end - - map_entry->vme_start))) - && !object->true_share) { + (object->size > total_size)) + && !object->true_share) { if (vm_map_lock_read_to_write(target_map)) { vm_map_lock_read(target_map); goto redo_lookup; @@ -1451,25 +1521,48 @@ redo_lookup: /* create a shadow object */ + vm_object_shadow(&map_entry->object.vm_object, + &map_entry->offset, total_size); + shadow_object = map_entry->object.vm_object; + vm_object_unlock(object); + vm_object_pmap_protect( + object, map_entry->offset, + total_size, + ((map_entry->is_shared + || target_map->mapped) + ? PMAP_NULL : + target_map->pmap), + map_entry->vme_start, + map_entry->protection & ~VM_PROT_WRITE); + total_size -= (map_entry->vme_end + - map_entry->vme_start); + next_entry = map_entry->vme_next; + map_entry->needs_copy = FALSE; + while (total_size) { + if(next_entry->object.vm_object == object) { + next_entry->object.vm_object + = shadow_object; + next_entry->offset + = next_entry->vme_prev->offset + + (next_entry->vme_prev->vme_end + - next_entry->vme_prev->vme_start); + next_entry->needs_copy = FALSE; + } else { + panic("mach_make_memory_entry_64:" + " map entries out of sync\n"); + } + total_size -= + next_entry->vme_end + - next_entry->vme_start; + next_entry = next_entry->vme_next; + } + + object = shadow_object; + vm_object_lock(object); + obj_off = (local_offset - map_entry->vme_start) + + map_entry->offset; + vm_map_lock_write_to_read(target_map); - vm_object_shadow(&map_entry->object.vm_object, - &map_entry->offset, - (map_entry->vme_end - - map_entry->vme_start)); - map_entry->needs_copy = FALSE; - vm_object_unlock(object); - object = map_entry->object.vm_object; - vm_object_lock(object); - object->size = map_entry->vme_end - - map_entry->vme_start; - obj_off = (offset - map_entry->vme_start) + - map_entry->offset; - lo_offset = map_entry->offset; - hi_offset = (map_entry->vme_end - - map_entry->vme_start) + - map_entry->offset; - - vm_map_lock_write_to_read(target_map); } } @@ -1499,7 +1592,6 @@ redo_lookup: /* offset of our beg addr within entry */ /* it corresponds to this: */ - mappable_size = hi_offset - obj_off; if(*size > mappable_size) *size = mappable_size; @@ -1513,7 +1605,6 @@ redo_lookup: vm_object_unlock(object); ipc_kobject_set(user_handle, (ipc_kobject_t) user_object, IKOT_NAMED_ENTRY); - *size = user_object->size; *object_handle = user_handle; vm_map_unlock_read(target_map); if(pmap_map != target_map) @@ -1715,16 +1806,17 @@ kern_return_t vm_map_region_replace( (entry->vme_start < end)) { if((entry->is_sub_map) && (entry->object.sub_map == old_submap)) { - entry->object.sub_map = new_submap; if(entry->use_pmap) { if((start & 0xfffffff) || ((end - start) != 0x10000000)) { vm_map_unlock(old_submap); + vm_map_deallocate(old_submap); vm_map_unlock(target_map); return KERN_INVALID_ARGUMENT; } nested_pmap = 1; } + entry->object.sub_map = new_submap; vm_map_reference(new_submap); vm_map_deallocate(old_submap); } @@ -1734,13 +1826,19 @@ kern_return_t vm_map_region_replace( if(nested_pmap) { #ifndef i386 pmap_unnest(target_map->pmap, start, end - start); + if(target_map->mapped) { + vm_map_submap_pmap_clean(target_map, + start, end, old_submap, 0); + } pmap_nest(target_map->pmap, new_submap->pmap, start, end - start); #endif i386 } else { - pmap_remove(target_map->pmap, start, end); + vm_map_submap_pmap_clean(target_map, + start, end, old_submap, 0); } vm_map_unlock(old_submap); + vm_map_deallocate(old_submap); vm_map_unlock(target_map); return KERN_SUCCESS; } @@ -2336,9 +2434,7 @@ shared_region_mapping_ref( { if(shared_region == NULL) return KERN_SUCCESS; - shared_region_mapping_lock(shared_region); - shared_region->ref_count++; - shared_region_mapping_unlock(shared_region); + hw_atomic_add(&shared_region->ref_count, 1); return KERN_SUCCESS; } @@ -2347,44 +2443,46 @@ shared_region_mapping_dealloc( shared_region_mapping_t shared_region) { struct shared_region_task_mappings sm_info; - shared_region_mapping_t next; - - if(shared_region == NULL) - return KERN_SUCCESS; - shared_region_mapping_lock(shared_region); - - if((--shared_region->ref_count) == 0) { - - sm_info.text_region = shared_region->text_region; - sm_info.text_size = shared_region->text_size; - sm_info.data_region = shared_region->data_region; - sm_info.data_size = shared_region->data_size; - sm_info.region_mappings = shared_region->region_mappings; - sm_info.client_base = shared_region->client_base; - sm_info.alternate_base = shared_region->alternate_base; - sm_info.alternate_next = shared_region->alternate_next; - sm_info.flags = shared_region->flags; - sm_info.self = (vm_offset_t)shared_region; - - lsf_remove_regions_mappings(shared_region, &sm_info); - pmap_remove(((vm_named_entry_t) - (shared_region->text_region->ip_kobject)) - ->backing.map->pmap, - sm_info.client_base, - sm_info.client_base + sm_info.text_size); - ipc_port_release_send(shared_region->text_region); - ipc_port_release_send(shared_region->data_region); - if(shared_region->object_chain) { - shared_region_mapping_dealloc( - shared_region->object_chain->object_chain_region); - kfree((vm_offset_t)shared_region->object_chain, - sizeof (struct shared_region_object_chain)); - } - kfree((vm_offset_t)shared_region, + shared_region_mapping_t next = NULL; + + while (shared_region) { + if (hw_atomic_sub(&shared_region->ref_count, 1) == 0) { + shared_region_mapping_lock(shared_region); + + sm_info.text_region = shared_region->text_region; + sm_info.text_size = shared_region->text_size; + sm_info.data_region = shared_region->data_region; + sm_info.data_size = shared_region->data_size; + sm_info.region_mappings = shared_region->region_mappings; + sm_info.client_base = shared_region->client_base; + sm_info.alternate_base = shared_region->alternate_base; + sm_info.alternate_next = shared_region->alternate_next; + sm_info.flags = shared_region->flags; + sm_info.self = (vm_offset_t)shared_region; + + lsf_remove_regions_mappings(shared_region, &sm_info); + pmap_remove(((vm_named_entry_t) + (shared_region->text_region->ip_kobject)) + ->backing.map->pmap, + sm_info.client_base, + sm_info.client_base + sm_info.text_size); + ipc_port_release_send(shared_region->text_region); + ipc_port_release_send(shared_region->data_region); + if (shared_region->object_chain) { + next = shared_region->object_chain->object_chain_region; + kfree((vm_offset_t)shared_region->object_chain, + sizeof (struct shared_region_object_chain)); + } else { + next = NULL; + } + shared_region_mapping_unlock(shared_region); + kfree((vm_offset_t)shared_region, sizeof (struct shared_region_mapping)); - return KERN_SUCCESS; + shared_region = next; + } else { + break; + } } - shared_region_mapping_unlock(shared_region); return KERN_SUCCESS; } @@ -2415,6 +2513,24 @@ vm_map_get_phys_page( vm_map_unlock(old_map); continue; } + if (entry->object.vm_object->phys_contiguous) { + /* These are not standard pageable memory mappings */ + /* If they are not present in the object they will */ + /* have to be picked up from the pager through the */ + /* fault mechanism. */ + if(entry->object.vm_object->shadow_offset == 0) { + /* need to call vm_fault */ + vm_map_unlock(map); + vm_fault(map, offset, VM_PROT_NONE, + FALSE, THREAD_UNINT, NULL, 0); + vm_map_lock(map); + continue; + } + offset = entry->offset + (offset - entry->vme_start); + phys_addr = entry->object.vm_object->shadow_offset + offset; + break; + + } offset = entry->offset + (offset - entry->vme_start); object = entry->object.vm_object; vm_object_lock(object); diff --git a/pexpert/conf/Makefile b/pexpert/conf/Makefile index 4baa6f1cf..bbeee5a37 100644 --- a/pexpert/conf/Makefile +++ b/pexpert/conf/Makefile @@ -47,14 +47,13 @@ do_setup_conf: $(OBJROOT)/$(KERNEL_CONFIG)_$(ARCH_CONFIG)/$(COMPONENT)/doconf \ do_all: do_setup_conf @echo "[ $(SOURCE) ] Starting do_all $(COMPONENT) $(PEXPERT_KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)"; \ - (cd $(COMPOBJROOT)/$(PEXPERT_KERNEL_CONFIG); \ next_source=$(subst conf/,,$(SOURCE)); \ - ${MAKE} MAKEFILES=$(TARGET)/$(PEXPERT_KERNEL_CONFIG)/Makefile \ + ${MAKE} -C $(COMPOBJROOT)/$(PEXPERT_KERNEL_CONFIG) \ + MAKEFILES=$(TARGET)/$(PEXPERT_KERNEL_CONFIG)/Makefile \ SOURCE=$${next_source} \ TARGET=$(TARGET) \ INCL_MAKEDEP=FALSE \ - build_all \ - ); \ + build_all; \ echo "[ $(SOURCE) ] Returning do_all $(COMPONENT) $(PEXPERT_KERNEL_CONFIG) $(ARCH_CONFIG) $(TARGET)"; do_build_all: do_all diff --git a/pexpert/conf/tools/doconf/doconf.csh b/pexpert/conf/tools/doconf/doconf.csh index 43388c11c..ae5ab908b 100755 --- a/pexpert/conf/tools/doconf/doconf.csh +++ b/pexpert/conf/tools/doconf/doconf.csh @@ -287,7 +287,7 @@ part != 0 {\ # kernel binaries are put). # echo 'builddir "."' >> $SYSCONF.new - set OBJRELDIR=`relpath $OBJROOT $OBJDIR` + set OBJRELDIR=`$RELPATH $OBJROOT $OBJDIR` echo 'objectdir "'$OBJROOT'/'$OBJRELDIR'"' >> $SYSCONF.new set SRCDIR=`dirname $SOURCE` echo 'sourcedir "'$SRCROOT'"' >> $SYSCONF.new diff --git a/pexpert/conf/version.major b/pexpert/conf/version.major index 7ed6ff82d..1e8b31496 100644 --- a/pexpert/conf/version.major +++ b/pexpert/conf/version.major @@ -1 +1 @@ -5 +6 diff --git a/pexpert/conf/version.minor b/pexpert/conf/version.minor index 7ed6ff82d..573541ac9 100644 --- a/pexpert/conf/version.minor +++ b/pexpert/conf/version.minor @@ -1 +1 @@ -5 +0 diff --git a/pexpert/conf/version.variant b/pexpert/conf/version.variant index 8b1378917..e69de29bb 100644 --- a/pexpert/conf/version.variant +++ b/pexpert/conf/version.variant @@ -1 +0,0 @@ - diff --git a/pexpert/gen/bootargs.c b/pexpert/gen/bootargs.c index 193261b2e..70463e769 100644 --- a/pexpert/gen/bootargs.c +++ b/pexpert/gen/bootargs.c @@ -41,6 +41,8 @@ PE_parse_boot_arg( boolean_t arg_found; args = PE_boot_args(); + if (*args == '\0') return FALSE; + arg_found = FALSE; while(isargsep(*args)) args++; diff --git a/pexpert/i386/boot_images.h b/pexpert/i386/boot_images.h new file mode 100644 index 000000000..761c82979 --- /dev/null +++ b/pexpert/i386/boot_images.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +static const unsigned char bootClut[ 256 * 3 ] = +{ + 0xff,0xff,0xff, 0xfe,0xfe,0xfe, 0xfd,0xfd,0xfd, 0xb8,0x27,0x2b, + 0xfc,0xfc,0xfc, 0xff,0xff,0x00, 0xfa,0xfa,0xfa, 0xf9,0xf9,0xf9, + 0xf8,0xf8,0xf8, 0xf7,0xf7,0xf7, 0xf6,0xf6,0xf6, 0xf5,0xf5,0xf5, + 0xf4,0xf4,0xf4, 0xf2,0xf2,0xf2, 0xf1,0xf1,0xf1, 0x00,0x00,0x00, + 0xef,0xef,0xef, 0xee,0xee,0xee, 0xed,0xed,0xed, 0xeb,0xeb,0xeb, + 0xe8,0xe8,0xe8, 0xe7,0xe7,0xe7, 0xc9,0x38,0x3e, 0xe5,0xe5,0xe5, + 0xff,0x00,0xff, 0xfb,0xfb,0xfb, 0xde,0x6c,0x72, 0xe0,0xe0,0xe0, + 0xe8,0x86,0x90, 0xde,0xde,0xde, 0xdd,0xdd,0xdd, 0xd3,0x7e,0x8d, + 0xd9,0xd9,0xd9, 0xf3,0x96,0xa6, 0xb1,0x1c,0x39, 0xff,0x00,0x00, + 0xbe,0x5e,0x72, 0xd3,0xd3,0xd3, 0xc6,0x2e,0x67, 0xd1,0xd1,0xd1, + 0xa3,0x06,0x45, 0xce,0xce,0xce, 0xcc,0xcc,0xff, 0xcc,0xcc,0xcc, + 0xc6,0x8f,0xa7, 0xe1,0xd3,0xd9, 0xce,0x9e,0xb4, 0xca,0xca,0xca, + 0xbf,0x3f,0x7d, 0xc9,0xc9,0xc9, 0xf4,0x89,0xbe, 0xc6,0xc6,0xc6, + 0xd6,0x51,0x97, 0xc9,0x2c,0x84, 0x96,0x1a,0x6a, 0xc2,0xc2,0xc2, + 0xf3,0x6f,0xc6, 0xe5,0x4c,0xbb, 0xb7,0x5a,0x9c, 0xbf,0xbf,0xbf, + 0xbe,0xbe,0xbe, 0xbd,0xbd,0xbd, 0xb8,0x21,0xa2, 0xd3,0x44,0xc0, + 0xc2,0x66,0xb7, 0xf4,0x66,0xe6, 0xfc,0x73,0xfd, 0xb9,0xb9,0xb9, + 0xea,0xdf,0xea, 0xd4,0x71,0xd5, 0xf9,0x8b,0xff, 0xf5,0xad,0xff, + 0xbc,0x92,0xc2, 0xc7,0x4f,0xd9, 0xa0,0x44,0xaf, 0xc8,0x8c,0xd5, + 0xd7,0x74,0xf7, 0xb4,0xb4,0xb4, 0xda,0x95,0xf9, 0xed,0xcb,0xff, + 0xb2,0xb2,0xb2, 0xa1,0x61,0xd7, 0xb2,0x85,0xe2, 0x59,0x26,0x9c, + 0x7c,0x51,0xcc, 0xb0,0xb0,0xb0, 0xb4,0x8e,0xfc, 0xd5,0xc0,0xff, + 0x5d,0x32,0xcc, 0x7b,0x5c,0xe5, 0xc0,0xb0,0xfd, 0x60,0x53,0xad, + 0x12,0x0c,0x7e, 0x2e,0x29,0x99, 0x79,0x78,0xe9, 0x5b,0x5c,0xd0, + 0x69,0x6a,0xcc, 0x93,0x94,0xf8, 0x92,0x92,0xc3, 0x41,0x44,0xba, + 0xa8,0xab,0xff, 0xa3,0xa3,0xa3, 0xdb,0xdd,0xea, 0x31,0x49,0xaa, + 0x70,0x8f,0xf9, 0x48,0x66,0xc1, 0x5c,0x7e,0xe9, 0xe2,0xe5,0xeb, + 0xb0,0xcd,0xff, 0x6c,0x89,0xb7, 0x34,0x65,0xaf, 0x8c,0xb9,0xff, + 0x37,0x79,0xd4, 0x5a,0x99,0xea, 0x0e,0x4c,0x95, 0x79,0xb9,0xff, + 0x8a,0xa3,0xbc, 0x20,0x61,0x9d, 0x8f,0xae,0xca, 0x0a,0x60,0xa8, + 0x3f,0x94,0xd9, 0x63,0xb5,0xf9, 0xe2,0xe8,0xed, 0x28,0x6a,0x99, + 0x55,0xb2,0xe7, 0x32,0x89,0xa9, 0xcf,0xda,0xde, 0x29,0xa1,0xc7, + 0x86,0xa9,0xb4, 0x00,0x5f,0x79, 0x0c,0x77,0x8e, 0x12,0x8f,0xab, + 0x41,0xba,0xd5, 0x24,0x82,0x83, 0x2c,0xc4,0xc3, 0x1a,0xab,0xa6, + 0x4b,0xa8,0xa2, 0x0a,0x93,0x85, 0x0d,0xa5,0x96, 0x26,0xbc,0xac, + 0x04,0x81,0x72, 0x19,0xb3,0x86, 0x29,0xc1,0x94, 0x21,0x9c,0x71, + 0x02,0x8c,0x50, 0x35,0xd0,0x89, 0x46,0xa5,0x76, 0x02,0x7d,0x39, + 0x29,0xc9,0x71, 0x57,0xd6,0x8f, 0xa2,0xb5,0xaa, 0x01,0x88,0x2a, + 0x74,0xbe,0x8a, 0x19,0xb6,0x47, 0x2d,0xc6,0x51, 0x38,0xde,0x5d, + 0x4c,0xf4,0x6f, 0x91,0x9c,0x93, 0x00,0x8e,0x19, 0x10,0xaf,0x28, + 0xe3,0xe3,0xe3, 0x08,0xa1,0x1a, 0x59,0xc2,0x61, 0xf0,0xf0,0xf0, + 0x8f,0x9c,0x90, 0x23,0xce,0x2a, 0x12,0xba,0x17, 0x01,0x8a,0x02, + 0x03,0x9a,0x02, 0x40,0xe4,0x40, 0x08,0xb2,0x05, 0x13,0xcc,0x0f, + 0x36,0xd7,0x32, 0x28,0xe9,0x1f, 0x53,0xfb,0x4c, 0x6f,0xaf,0x6a, + 0x71,0xe0,0x67, 0x32,0xc0,0x12, 0x29,0xa5,0x08, 0x5c,0xdd,0x35, + 0x00,0xff,0xff, 0x63,0xc8,0x45, 0x86,0xfd,0x5b, 0x71,0xf6,0x39, + 0x55,0xcc,0x15, 0x00,0xff,0x00, 0x90,0xca,0x6e, 0x43,0xa7,0x01, + 0x8d,0xe4,0x37, 0xb3,0xf0,0x64, 0x85,0x8e,0x7a, 0xb0,0xfa,0x4d, + 0xd6,0xd6,0xd6, 0x88,0xd0,0x1a, 0x6a,0xa7,0x03, 0x98,0xbf,0x41, + 0xcd,0xf8,0x51, 0x94,0xa4,0x55, 0x91,0xb0,0x0a, 0xda,0xf1,0x3c, + 0xba,0xca,0x53, 0xb9,0xc3,0x28, 0xb1,0xba,0x12, 0xd2,0xd9,0x26, + 0xe8,0xec,0x2d, 0x98,0x96,0x02, 0xad,0xad,0x5c, 0xe2,0xd8,0x38, + 0xd9,0xc4,0x38, 0xa8,0x9a,0x50, 0x00,0x00,0xff, 0xbe,0xae,0x5e, + 0x9a,0x98,0x8e, 0xac,0x8d,0x0d, 0xc5,0xa0,0x2b, 0xdb,0xb5,0x48, + 0xdd,0x00,0x00, 0x9c,0x6d,0x03, 0xd4,0xa8,0x47, 0xb7,0x71,0x17, + 0xdc,0xa1,0x5a, 0xb9,0x9c,0x7c, 0xb4,0xab,0xa2, 0x9e,0x4b,0x01, + 0xc8,0x78,0x35, 0xd2,0x8d,0x51, 0xad,0x52,0x0f, 0x00,0xbb,0x00, + 0xb2,0x66,0x38, 0xb1,0xa6,0x9f, 0xb1,0x87,0x6f, 0xa4,0x34,0x03, + 0xee,0x9e,0x85, 0xc9,0x73,0x5a, 0xe6,0x94,0x7c, 0xa9,0x22,0x06, + 0xdb,0x87,0x74, 0xb0,0x2e,0x15, 0xb7,0x5a,0x50, 0xb2,0x42,0x3b, + 0xcd,0x73,0x6e, 0xd9,0x58,0x58, 0xac,0xac,0xac, 0xa0,0xa0,0xa0, + 0x9a,0x9a,0x9a, 0x92,0x92,0x92, 0x8e,0x8e,0x8e, 0xbb,0xbb,0xbb, + 0x81,0x81,0x81, 0x88,0x88,0x88, 0x77,0x77,0x77, 0x55,0x55,0x55, + 0x44,0x44,0x44, 0x22,0x22,0x22, 0x7b,0x7b,0x7b, 0x00,0x00,0x00 +}; + +#define kFailedBootWidth 28 +#define kFailedBootHeight 28 +#define kFailedBootOffset -44 + +static const unsigned char failedBootPict[] = +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x13,0x1b,0xc0,0x27,0x27,0xc0,0x1b,0x13,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x15,0xc0,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0xc0,0x15,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x13,0xc0,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x11,0x27,0x29,0x29,0x29,0xc0,0xa0,0x11,0x09,0x09,0x11,0xa0,0xc0,0x29,0x29,0x29,0x20,0x0c,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x07,0x20,0x29,0x29,0x29,0xc0,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x15,0x25,0x29,0x29,0x1e,0x07,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x15,0x29,0x29,0x29,0x29,0x29,0x1b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa3,0x25,0x29,0x29,0x15,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x09,0xc0,0x29,0x29,0xc0,0x29,0x29,0x29,0x1b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x29,0x29,0xc0,0x09,0x00,0x00,0x00, + 0x00,0x00,0x00,0x13,0x29,0x29,0xc0,0x09,0x1b,0x29,0x29,0x29,0x1b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xc0,0x29,0x29,0x13,0x00,0x00,0x00, + 0x00,0x00,0x00,0x1b,0x29,0x29,0xa0,0x00,0x01,0x1b,0x29,0x29,0x29,0x1b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x29,0x29,0x1b,0x00,0x00,0x00, + 0x00,0x00,0x00,0xc0,0x29,0x29,0x11,0x00,0x00,0x01,0x1b,0x29,0x29,0x29,0x1b,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x29,0x29,0xc0,0x00,0x00,0x00, + 0x00,0x00,0x00,0x27,0x29,0x29,0x09,0x00,0x00,0x00,0x01,0x1b,0x29,0x29,0x29,0x1b,0x00,0x00,0x00,0x00,0x00,0x09,0x29,0x29,0x27,0x00,0x00,0x00, + 0x00,0x00,0x00,0x27,0x29,0x29,0x09,0x00,0x00,0x00,0x00,0x01,0x1b,0x29,0x29,0x29,0x1b,0x00,0x00,0x00,0x00,0x09,0x29,0x29,0x27,0x00,0x00,0x00, + 0x00,0x00,0x00,0xc0,0x29,0x29,0x11,0x00,0x00,0x00,0x00,0x00,0x01,0x1b,0x29,0x29,0x29,0x1b,0x00,0x00,0x00,0x11,0x29,0x29,0xc0,0x00,0x00,0x00, + 0x00,0x00,0x00,0x1b,0x29,0x29,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x1b,0x29,0x29,0x29,0x1b,0x00,0x00,0xa0,0x29,0x29,0x1b,0x00,0x00,0x00, + 0x00,0x00,0x00,0x13,0x29,0x29,0xc0,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x1b,0x29,0x29,0x29,0x1b,0x08,0xc0,0x29,0x29,0x13,0x00,0x00,0x00, + 0x00,0x00,0x00,0x09,0xc0,0x29,0x29,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x1b,0x29,0x29,0x29,0xc0,0x29,0x29,0xc0,0x09,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x15,0x29,0x29,0x25,0xa3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x1b,0x29,0x29,0x29,0x29,0x29,0x15,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x07,0x1e,0x29,0x29,0x25,0x15,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0xc0,0x29,0x29,0x29,0x1e,0x07,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x0c,0x20,0x29,0x29,0x29,0xc0,0xa0,0x11,0x09,0x09,0x11,0xa0,0xc0,0x29,0x29,0x29,0x20,0x0c,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x15,0xc0,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0xc0,0x15,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x13,0x1b,0xc0,0x27,0x27,0xc0,0x1b,0x13,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; diff --git a/pexpert/i386/pe_identify_machine.c b/pexpert/i386/pe_identify_machine.c index 8edc96285..c8ecface5 100644 --- a/pexpert/i386/pe_identify_machine.c +++ b/pexpert/i386/pe_identify_machine.c @@ -23,6 +23,9 @@ #include #include +/* External declarations */ +unsigned int LockTimeOut = 12500000; /* XXX - Need real value for i386 */ + /* Local declarations */ void pe_identify_machine(boot_args *args); diff --git a/pexpert/i386/pe_init.c b/pexpert/i386/pe_init.c index aa1c089ec..6e8001e6f 100644 --- a/pexpert/i386/pe_init.c +++ b/pexpert/i386/pe_init.c @@ -30,10 +30,11 @@ #include #include #include -#include +#include #include "fakePPCStructs.h" #include "fakePPCDeviceTree.h" +#include "boot_images.h" /* extern references */ extern void pe_identify_machine(void * args); @@ -105,11 +106,9 @@ int PE_initialize_console( PE_Video * info, int op ) void PE_init_iokit(void) { - long * dt; - void * desc; - unsigned char * data; - unsigned char * clut; - + long * dt; + int i; + typedef struct { char name[32]; unsigned long length; @@ -130,7 +129,6 @@ void PE_init_iokit(void) if ( dt ) { DriversPackageProp * prop = (DriversPackageProp *) gDriversProp.address; - int i; /* Copy driver info in kernBootStruct to fake device tree */ @@ -171,13 +169,21 @@ void PE_init_iokit(void) DTInit(dt); /* - * Initialize the spinning wheel (progress indicator). + * Fetch the CLUT and the noroot image. */ - clut = appleClut8; - desc = &default_progress; - data = default_progress_data; + bcopy( bootClut, appleClut8, sizeof(appleClut8) ); + + default_noroot.width = kFailedBootWidth; + default_noroot.height = kFailedBootHeight; + default_noroot.dx = 0; + default_noroot.dy = kFailedBootOffset; + default_noroot_data = failedBootPict; - vc_progress_initialize( desc, data, clut ); + /* + * Initialize the spinning wheel (progress indicator). + */ + vc_progress_initialize( &default_progress, default_progress_data, + (unsigned char *) appleClut8 ); PE_initialize_console( (PE_Video *) 0, kPEAcquireScreen ); @@ -188,9 +194,6 @@ void PE_init_platform(boolean_t vm_initialized, void * args) { if (PE_state.initialized == FALSE) { - extern unsigned int halt_in_debugger, disableDebugOuput; - unsigned int debug_arg; - PE_kbp = (KERNBOOTSTRUCT *) args; PE_state.initialized = TRUE; @@ -212,19 +215,6 @@ void PE_init_platform(boolean_t vm_initialized, void * args) */ PE_state.video.v_display = 0; } - - /* - * If DB_HALT flag is set, then cause a breakpoint to the debugger - * immediately after the kernel debugger has been initialized. - * - * If DB_PRT flag is set, then enable debugger printf. - */ - disableDebugOuput = TRUE; /* FIXME: override osfmk/i386/AT386/model_dep.c */ - - if (PE_parse_boot_arg("debug", &debug_arg)) { - if (debug_arg & DB_HALT) halt_in_debugger = 1; - if (debug_arg & DB_PRT) disableDebugOuput = FALSE; - } } if (!vm_initialized) @@ -283,9 +273,10 @@ int PE_current_console( PE_Video * info ) return (0); } -void PE_display_icon( unsigned int flags, - const char * name ) +void PE_display_icon( unsigned int flags, const char * name ) { + if ( default_noroot_data ) + vc_display_icon( &default_noroot, default_noroot_data ); } extern boolean_t PE_get_hotkey( unsigned char key ) diff --git a/pexpert/i386/pe_interrupt.c b/pexpert/i386/pe_interrupt.c index 533bf485c..a3d3a3a64 100644 --- a/pexpert/i386/pe_interrupt.c +++ b/pexpert/i386/pe_interrupt.c @@ -22,6 +22,7 @@ #include #include #include +#include struct i386_interrupt_handler { IOInterruptHandler handler; @@ -39,17 +40,22 @@ void PE_platform_interrupt_initialize(void) } void -PE_incoming_interrupt(int interrupt, struct i386_saved_state *ssp) +PE_incoming_interrupt(int interrupt, void *eip) { boolean_t save_int; - i386_interrupt_handler_t *vector; - vector = &PE_interrupt_handler; + KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_INTR, 0) | DBG_FUNC_START, + 0, (unsigned int)eip, 0, 0, 0); + vector = &PE_interrupt_handler; save_int = ml_set_interrupts_enabled(FALSE); vector->handler(vector->target, vector->refCon, vector->nub, interrupt); ml_set_interrupts_enabled(save_int); + + KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_INTR, 0) | DBG_FUNC_END, + 0, 0, 0, 0, 0); + } void PE_install_interrupt_handler(void *nub, int source, diff --git a/pexpert/pexpert/GearImage.h b/pexpert/pexpert/GearImage.h new file mode 100644 index 000000000..6c6b1137d --- /dev/null +++ b/pexpert/pexpert/GearImage.h @@ -0,0 +1,776 @@ +#define kGearWidth (32) +#define kGearHeight (32) +#define kGearOffset (200) +#define kGearFrames (24) +#define kGearFPS (24) + +const unsigned char gGearPict[] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0x8d,0x80,0xf6,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf5,0xfa,0xff,0xff,0xff,0xd2,0x23,0x1d,0xbd,0xff,0xff,0xff,0xfe,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd2,0x49,0x77,0xfa,0xff,0xff,0xc5,0x36,0x35,0xb1,0xff,0xff,0xfe,0xe8,0xdb,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa9,0x43,0x45,0xb4,0xff,0xff,0xc8,0x37,0x33,0xb4,0xff,0xff,0xf3,0xda,0xda,0xe8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xeb,0x62,0x52,0x5a,0xf3,0xff,0xc7,0x37,0x33,0xb4,0xff,0xfd,0xe1,0xdd,0xde,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xb3,0x4e,0x4c,0x97,0xff,0xc8,0x37,0x34,0xb2,0xff,0xec,0xdb,0xdb,0xea,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xd7,0xb8,0xf7,0xff,0xff,0xf5,0x72,0x52,0x50,0xeb,0xd2,0x28,0x24,0xb3,0xfd,0xde,0xde,0xe0,0xfb,0xff,0xff,0xfd,0xef,0xf3,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf5,0x64,0x5e,0x79,0xcc,0xfd,0xff,0xce,0x4c,0x3b,0x9a,0xf4,0x6c,0x60,0xe7,0xf2,0xda,0xdc,0xf0,0xfe,0xfe,0xf4,0xe0,0xd8,0xd8,0xf7,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf7,0x88,0x66,0x6d,0x64,0x8b,0xe6,0xf9,0x9e,0x67,0xd0,0xfc,0xf3,0xf1,0xfc,0xf5,0xe1,0xe6,0xfc,0xf8,0xe5,0xd9,0xda,0xd9,0xde,0xfa,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xf3,0xb1,0x73,0x6b,0x6a,0x61,0xb9,0xf8,0xf3,0xfb,0xfe,0xff,0xff,0xfd,0xfd,0xfb,0xfc,0xee,0xd9,0xda,0xda,0xdc,0xe6,0xf9,0xfe,0xfe,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xfb,0xe3,0x9d,0x6d,0x5a,0x84,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xfd,0xe2,0xd7,0xda,0xe3,0xf4,0xfd,0xfe,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0xd7,0x9f,0xd7,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xf4,0xe5,0xf1,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xfb,0xe2,0xe0,0xe2,0xe2,0xe0,0xe3,0xf8,0xfd,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfc,0xfb,0xf3,0xf2,0xf4,0xf5,0xf4,0xf4,0xfd,0xfe,0xff, + 0xff,0xfe,0xae,0x75,0x81,0x82,0x82,0x83,0x77,0xaf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe3,0xd2,0xd5,0xd6,0xd4,0xd5,0xd1,0xe4,0xfe,0xff, + 0xff,0xfd,0xa6,0x77,0x83,0x82,0x82,0x82,0x77,0xa6,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe0,0xd1,0xd6,0xd5,0xd5,0xd6,0xd1,0xe0,0xfe,0xff, + 0xff,0xfe,0xef,0xc7,0xc7,0xc7,0xc7,0xc6,0xce,0xf6,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xef,0xea,0xed,0xeb,0xeb,0xeb,0xf8,0xfe,0xff, + 0xff,0xfe,0xfe,0xfd,0xfd,0xfd,0xfe,0xfe,0xf5,0xce,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0xe2,0xf6,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xd0,0x9d,0x89,0xac,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xd8,0xc6,0xcc,0xe3,0xfc,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xe1,0xa5,0x92,0x97,0x90,0xbb,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe3,0xcc,0xce,0xcb,0xd1,0xeb,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfc,0xb9,0x90,0x97,0x95,0xa1,0xcf,0xf8,0xdc,0xbf,0xf2,0xff,0xff,0xff,0xff,0xf7,0xd2,0xdf,0xfb,0xec,0xd4,0xce,0xce,0xc9,0xd8,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf3,0x91,0x8f,0x9b,0xc0,0xf0,0xfd,0xf3,0xa5,0x9a,0xc8,0xfd,0xd4,0xd0,0xfc,0xe0,0xbb,0xbe,0xef,0xfe,0xf9,0xe4,0xd1,0xcb,0xc8,0xf7,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfb,0xcd,0xb7,0xe3,0xfb,0xfe,0xfe,0xbf,0xa6,0xa9,0xe4,0xf1,0xb1,0xaf,0xe6,0xf5,0xc4,0xc4,0xce,0xfd,0xff,0xfd,0xf4,0xe0,0xe6,0xfc,0xfe,0xff,0xff, + 0xff,0xff,0xff,0xfc,0xfc,0xfb,0xfd,0xff,0xff,0xe5,0xa4,0xa6,0xc1,0xfc,0xea,0xb9,0xb7,0xe1,0xfe,0xda,0xc2,0xc0,0xe8,0xff,0xff,0xfd,0xfd,0xfe,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xb4,0xa9,0xab,0xed,0xff,0xeb,0xb9,0xb7,0xe2,0xff,0xf7,0xc7,0xc4,0xc8,0xfb,0xff,0xff,0xfe,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd8,0xa2,0xa6,0xcc,0xfd,0xff,0xeb,0xb7,0xb7,0xe2,0xff,0xfe,0xe3,0xc1,0xbe,0xdd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xde,0xa1,0xb2,0xf5,0xff,0xff,0xeb,0xb8,0xb7,0xe2,0xff,0xff,0xfb,0xcf,0xbe,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf9,0xe4,0xef,0xfd,0xff,0xff,0xeb,0xb2,0xb2,0xe3,0xff,0xff,0xfd,0xf5,0xee,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfe,0xff,0xff,0xf8,0xc9,0xc6,0xf6,0xff,0xff,0xfe,0xfe,0xfe,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfc,0xf9,0xf9,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0x96,0x89,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf6,0xfa,0xff,0xff,0xff,0xd4,0x33,0x2d,0xc1,0xff,0xff,0xff,0xfe,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd6,0x57,0x82,0xfb,0xff,0xff,0xca,0x46,0x42,0xb7,0xff,0xff,0xfe,0xe8,0xdb,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xb0,0x51,0x52,0xba,0xff,0xff,0xcc,0x45,0x41,0xba,0xff,0xff,0xf3,0xda,0xda,0xe8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xee,0x6e,0x5e,0x67,0xf4,0xff,0xcc,0x45,0x41,0xba,0xff,0xfd,0xe1,0xdd,0xde,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xb9,0x5b,0x5a,0x9e,0xff,0xcc,0x45,0x42,0xb8,0xff,0xec,0xdb,0xdb,0xea,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xda,0xbe,0xf8,0xff,0xff,0xf6,0x7d,0x5e,0x5e,0xec,0xd4,0x38,0x34,0xb8,0xfd,0xdd,0xde,0xe0,0xfb,0xff,0xff,0xfd,0xf0,0xf5,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf5,0x6f,0x6a,0x83,0xd0,0xfd,0xff,0xd1,0x59,0x4b,0xa0,0xf5,0x76,0x6b,0xe9,0xf1,0xda,0xdc,0xf0,0xfe,0xfe,0xf5,0xe1,0xd9,0xda,0xf8,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf8,0x91,0x70,0x77,0x6f,0x93,0xe7,0xf9,0xa5,0x73,0xd4,0xfd,0xf5,0xf3,0xfc,0xf5,0xe1,0xe6,0xfc,0xf8,0xe5,0xda,0xdb,0xda,0xdf,0xfa,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xf4,0xb5,0x7f,0x75,0x76,0x6e,0xbe,0xf9,0xf2,0xfc,0xfe,0xff,0xff,0xff,0xfd,0xfb,0xfc,0xf0,0xdb,0xdb,0xdb,0xdd,0xe8,0xf8,0xfe,0xfe,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xfe,0xfb,0xe3,0xa4,0x79,0x66,0x8e,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xfd,0xe2,0xd8,0xdb,0xe4,0xf5,0xfc,0xfe,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0xda,0xa6,0xda,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xf4,0xe5,0xf1,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xfb,0xe5,0xe3,0xe4,0xe5,0xe3,0xe6,0xf8,0xfd,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfc,0xfc,0xf3,0xf3,0xf5,0xf5,0xf5,0xf5,0xfd,0xfe,0xff, + 0xff,0xfe,0xb5,0x82,0x8c,0x8d,0x8d,0x8e,0x83,0xb6,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe5,0xd5,0xd8,0xd9,0xd8,0xd8,0xd5,0xe5,0xfe,0xff, + 0xff,0xfd,0xad,0x82,0x8d,0x8e,0x8e,0x8d,0x82,0xae,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe3,0xd5,0xd9,0xd8,0xd8,0xd9,0xd6,0xe2,0xfe,0xff, + 0xff,0xfe,0xef,0xcd,0xcc,0xcc,0xcc,0xcb,0xd2,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfc,0xef,0xed,0xed,0xee,0xee,0xec,0xf9,0xfe,0xff, + 0xff,0xfe,0xfe,0xfd,0xfd,0xfd,0xfe,0xfe,0xf5,0xd2,0xf3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf7,0xe4,0xf6,0xfe,0xfe,0xfe,0xfe,0xfe,0xfc,0xfe,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xd4,0xa4,0x93,0xb3,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xdc,0xcb,0xd1,0xe5,0xfc,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xe4,0xac,0x9c,0xa1,0x9a,0xc0,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe5,0xd0,0xd2,0xd1,0xd4,0xed,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfc,0xc0,0x9a,0x9f,0x9e,0xa9,0xd3,0xf9,0xe0,0xc5,0xf3,0xff,0xff,0xff,0xff,0xf8,0xd6,0xe2,0xfc,0xee,0xd8,0xd2,0xd2,0xce,0xdc,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf3,0x9b,0x9b,0xa4,0xc6,0xf0,0xfd,0xf3,0xad,0xa4,0xce,0xfd,0xd7,0xd4,0xfc,0xe2,0xc2,0xc4,0xf1,0xfe,0xfa,0xe6,0xd5,0xd0,0xcd,0xf8,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfc,0xd2,0xbc,0xe5,0xfb,0xfe,0xfe,0xc5,0xaf,0xaf,0xe7,0xf3,0xb9,0xb7,0xe8,0xf6,0xca,0xc9,0xd3,0xfd,0xfe,0xfd,0xf5,0xe0,0xea,0xfc,0xfe,0xff,0xff, + 0xff,0xff,0xff,0xfc,0xfc,0xfc,0xfd,0xff,0xff,0xe6,0xad,0xaf,0xc5,0xfc,0xeb,0xc0,0xbd,0xe5,0xfd,0xdd,0xc7,0xc6,0xe8,0xff,0xfe,0xfe,0xfd,0xfe,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfb,0xbb,0xb0,0xb3,0xee,0xff,0xed,0xbf,0xbd,0xe5,0xff,0xf7,0xcd,0xc9,0xcc,0xfb,0xff,0xff,0xfe,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdb,0xab,0xad,0xd0,0xfd,0xff,0xec,0xbe,0xbd,0xe5,0xff,0xfe,0xe4,0xc6,0xc5,0xe1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0xa9,0xba,0xf7,0xff,0xff,0xec,0xbe,0xbe,0xe5,0xff,0xff,0xfa,0xd3,0xc4,0xe7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0xe8,0xf0,0xfd,0xff,0xff,0xeb,0xb9,0xb8,0xe4,0xff,0xff,0xfd,0xf6,0xf0,0xfc,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xfe,0xfe,0xfe,0xff,0xff,0xf9,0xcf,0xcc,0xf6,0xff,0xff,0xfe,0xfe,0xfe,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,0xfa,0xfa,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0x9c,0x92,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf7,0xfb,0xff,0xff,0xff,0xd8,0x41,0x3c,0xc5,0xff,0xff,0xff,0xfc,0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd9,0x65,0x8b,0xfb,0xff,0xff,0xcd,0x52,0x50,0xbc,0xff,0xff,0xfc,0x7b,0x2e,0xbe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xb6,0x5e,0x61,0xc0,0xff,0xff,0xd0,0x53,0x4f,0xbf,0xff,0xff,0xc1,0x2a,0x25,0x86,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0x79,0x6d,0x73,0xf5,0xff,0xd0,0x53,0x4f,0xbf,0xff,0xf7,0x50,0x36,0x40,0xda,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xbf,0x69,0x66,0xa7,0xff,0xcf,0x54,0x50,0xbe,0xff,0xa0,0x2e,0x32,0x92,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xdb,0xc2,0xf9,0xff,0xff,0xf7,0x86,0x6c,0x6a,0xee,0xd8,0x46,0x42,0xc5,0xef,0x3e,0x36,0x4d,0xef,0xff,0xff,0xfd,0xf0,0xf5,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf5,0x7b,0x75,0x8d,0xd3,0xfd,0xff,0xd4,0x67,0x5a,0xa8,0xf5,0x7f,0x75,0xf3,0xa0,0x1f,0x2c,0xb0,0xfe,0xff,0xf5,0xe2,0xda,0xda,0xf8,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf8,0x9a,0x7d,0x83,0x7b,0x9c,0xe9,0xfa,0xab,0x7e,0xd6,0xfc,0xf5,0xf3,0xfd,0xd1,0x4f,0x7a,0xf4,0xfb,0xe6,0xdb,0xde,0xdb,0xe0,0xf9,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xf4,0xbc,0x88,0x81,0x80,0x7a,0xc3,0xf9,0xf4,0xfc,0xfe,0xff,0xff,0xfe,0xfb,0xed,0xf5,0xf2,0xdc,0xdc,0xdc,0xdd,0xe9,0xf8,0xfe,0xfe,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xfe,0xfb,0xe6,0xaa,0x85,0x72,0x97,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe3,0xd9,0xdc,0xe4,0xf3,0xfc,0xfe,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xdc,0xad,0xdd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xf4,0xe6,0xf2,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xfc,0xe6,0xe5,0xe6,0xe6,0xe4,0xe7,0xf8,0xfd,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfc,0xfb,0xf5,0xf3,0xf6,0xf6,0xf6,0xf5,0xfd,0xfe,0xff, + 0xff,0xfe,0xbc,0x8c,0x97,0x97,0x97,0x97,0x8e,0xbd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe6,0xd7,0xdc,0xdb,0xdb,0xda,0xd7,0xe7,0xfe,0xff, + 0xff,0xfd,0xb4,0x8e,0x98,0x97,0x97,0x98,0x8d,0xb5,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe4,0xd8,0xdb,0xda,0xda,0xdb,0xd8,0xe5,0xfe,0xff, + 0xff,0xfe,0xf1,0xd1,0xcf,0xd0,0xd0,0xce,0xd6,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfc,0xf0,0xee,0xee,0xee,0xee,0xed,0xf9,0xfe,0xff, + 0xff,0xfe,0xfe,0xfe,0xfd,0xfd,0xfe,0xfe,0xf6,0xd7,0xf3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf7,0xe5,0xf6,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xd8,0xac,0x9d,0xba,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xde,0xd0,0xd4,0xe7,0xfc,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xe5,0xb2,0xa4,0xa9,0xa3,0xc6,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe7,0xd3,0xd5,0xd4,0xd7,0xee,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xc5,0xa3,0xa9,0xa8,0xb1,0xd6,0xf9,0xe2,0xca,0xf5,0xff,0xff,0xff,0xff,0xf9,0xd9,0xe4,0xfc,0xee,0xda,0xd5,0xd5,0xd3,0xde,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf5,0xa3,0xa3,0xab,0xcb,0xf1,0xfd,0xf4,0xb5,0xac,0xd3,0xfd,0xdb,0xd8,0xfc,0xe6,0xc7,0xca,0xf1,0xfe,0xf9,0xe9,0xd7,0xd4,0xd2,0xf8,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfc,0xd4,0xc3,0xe7,0xfb,0xfe,0xfd,0xca,0xb6,0xb7,0xe8,0xf3,0xbf,0xbd,0xea,0xf6,0xce,0xcd,0xd6,0xfd,0xfe,0xfd,0xf6,0xe3,0xeb,0xfc,0xfe,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xfd,0xfc,0xfe,0xff,0xff,0xe9,0xb4,0xb8,0xcb,0xfc,0xed,0xc5,0xc3,0xe6,0xfe,0xdf,0xcd,0xcb,0xea,0xff,0xfe,0xfe,0xfd,0xfe,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xc1,0xb7,0xb9,0xf0,0xff,0xed,0xc5,0xc3,0xe7,0xff,0xf8,0xd0,0xce,0xcf,0xfb,0xff,0xff,0xfe,0xfe,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xb3,0xb5,0xd4,0xfd,0xff,0xef,0xc3,0xc3,0xe7,0xff,0xfe,0xe6,0xcc,0xc9,0xe2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe3,0xb3,0xbf,0xf7,0xff,0xff,0xee,0xc4,0xc3,0xe7,0xff,0xff,0xfb,0xd7,0xc9,0xe8,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xea,0xf0,0xfd,0xff,0xff,0xed,0xbf,0xbe,0xe7,0xff,0xff,0xfd,0xf7,0xef,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xfe,0xfe,0xfe,0xff,0xff,0xf8,0xd3,0xd0,0xf6,0xff,0xff,0xfe,0xfe,0xfe,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,0xfb,0xfb,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xa3,0x99,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf7,0xfb,0xff,0xff,0xff,0xdb,0x50,0x4b,0xc9,0xff,0xff,0xff,0xfc,0xf6,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdb,0x71,0x95,0xfb,0xff,0xff,0xd1,0x61,0x5d,0xc1,0xff,0xff,0xfd,0x84,0x3c,0xc1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xba,0x6c,0x6d,0xc4,0xff,0xff,0xd3,0x60,0x5c,0xc3,0xff,0xff,0xc7,0x39,0x34,0x8f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x84,0x77,0x7d,0xf6,0xff,0xd3,0x60,0x5c,0xc3,0xff,0xf7,0x5c,0x45,0x4e,0xdd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xc4,0x72,0x73,0xad,0xff,0xd3,0x61,0x5d,0xc3,0xff,0xa6,0x3c,0x3f,0x99,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xdf,0xc8,0xf9,0xff,0xff,0xf7,0x90,0x76,0x75,0xed,0xda,0x55,0x51,0xca,0xf0,0x4b,0x45,0x5b,0xf0,0xff,0xff,0xfd,0xf0,0xf5,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf6,0x86,0x81,0x98,0xd7,0xfd,0xff,0xd8,0x72,0x66,0xaf,0xf6,0x89,0x7f,0xf3,0xa6,0x2f,0x3a,0xb6,0xfe,0xff,0xf5,0xe2,0xda,0xda,0xf8,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf8,0xa2,0x89,0x8e,0x86,0xa3,0xeb,0xfa,0xb2,0x87,0xda,0xfd,0xf5,0xf5,0xfd,0xd4,0x5c,0x83,0xf5,0xfb,0xe6,0xdb,0xde,0xdb,0xe0,0xf9,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xf5,0xc0,0x92,0x8c,0x8c,0x85,0xc8,0xfa,0xf5,0xfc,0xfe,0xff,0xff,0xfe,0xfb,0xee,0xf6,0xf2,0xdc,0xdc,0xdc,0xdd,0xe9,0xf8,0xfe,0xfe,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xfe,0xfb,0xe7,0xb2,0x8e,0x80,0x9f,0xfd,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe3,0xd9,0xdc,0xe4,0xf3,0xfc,0xfe,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xde,0xb5,0xdf,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xf4,0xe6,0xf2,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xfc,0xe9,0xe7,0xe9,0xe7,0xe7,0xe9,0xf9,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfc,0xfc,0xf4,0xf3,0xf6,0xf5,0xf5,0xf6,0xfe,0xfe,0xff, + 0xff,0xfe,0xc1,0x97,0xa0,0x9f,0x9f,0xa0,0x97,0xc2,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe7,0xd8,0xdd,0xdc,0xdc,0xdc,0xd8,0xe8,0xfe,0xff, + 0xff,0xfd,0xbb,0x96,0xa0,0xa0,0xa0,0xa0,0x97,0xbb,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe6,0xda,0xdc,0xdc,0xdc,0xdc,0xd9,0xe6,0xfe,0xff, + 0xff,0xfe,0xf1,0xd5,0xd3,0xd5,0xd5,0xd2,0xda,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfc,0xf0,0xee,0xee,0xee,0xee,0xee,0xf8,0xfe,0xff, + 0xff,0xfe,0xfe,0xfd,0xfd,0xfd,0xfe,0xfe,0xf7,0xd8,0xf6,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0xe8,0xf6,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xdb,0xb3,0xa6,0xbe,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe0,0xd3,0xd8,0xe8,0xfc,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xe8,0xb9,0xac,0xb0,0xab,0xca,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xea,0xd7,0xda,0xd7,0xdb,0xef,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xca,0xab,0xb0,0xaf,0xb7,0xda,0xfa,0xe5,0xce,0xf5,0xff,0xff,0xff,0xff,0xf8,0xdd,0xe6,0xfc,0xf1,0xde,0xd8,0xd8,0xd6,0xe0,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf6,0xab,0xac,0xb3,0xcf,0xf1,0xfd,0xf4,0xbc,0xb4,0xd6,0xfd,0xde,0xdb,0xfc,0xe7,0xcc,0xce,0xf2,0xfe,0xf9,0xeb,0xda,0xd7,0xd5,0xf9,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfc,0xd9,0xc7,0xe8,0xfc,0xfe,0xfe,0xcf,0xbc,0xbd,0xeb,0xf3,0xc5,0xc3,0xea,0xf7,0xd1,0xd2,0xd9,0xfd,0xfe,0xfd,0xf6,0xe5,0xec,0xfd,0xfe,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xfd,0xfc,0xfd,0xff,0xff,0xeb,0xbb,0xbe,0xd0,0xfc,0xef,0xca,0xc8,0xe8,0xfe,0xe2,0xd1,0xd0,0xec,0xff,0xfe,0xfe,0xfd,0xfc,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfc,0xc7,0xbe,0xc0,0xf1,0xfe,0xef,0xca,0xc8,0xe9,0xfe,0xf7,0xd5,0xd2,0xd4,0xfb,0xff,0xff,0xfe,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0xbb,0xbc,0xd8,0xfd,0xff,0xef,0xca,0xc8,0xe9,0xff,0xfe,0xea,0xd0,0xcd,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe5,0xb8,0xc5,0xf7,0xff,0xff,0xef,0xca,0xc8,0xe9,0xff,0xff,0xfc,0xda,0xce,0xeb,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xec,0xf2,0xfe,0xff,0xff,0xef,0xc5,0xc5,0xe8,0xff,0xff,0xfd,0xf8,0xf2,0xfb,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xfe,0xfe,0xfe,0xff,0xff,0xfa,0xd7,0xd6,0xf6,0xff,0xff,0xfe,0xfe,0xfe,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,0xfa,0xfb,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xab,0xa2,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf7,0xfb,0xff,0xff,0xff,0xdd,0x5e,0x5a,0xce,0xff,0xff,0xff,0xfc,0xf6,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xde,0x7c,0x9c,0xfb,0xff,0xff,0xd6,0x6e,0x6a,0xc6,0xff,0xff,0xfd,0x8d,0x4a,0xc5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc0,0x77,0x79,0xc8,0xff,0xff,0xd7,0x6d,0x69,0xc8,0xff,0xff,0xc8,0x46,0x42,0x97,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0x8d,0x83,0x89,0xf6,0xff,0xd7,0x6d,0x69,0xc8,0xff,0xf8,0x68,0x51,0x5a,0xde,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xc8,0x7f,0x7d,0xb4,0xff,0xd6,0x6e,0x69,0xc7,0xff,0xad,0x49,0x4e,0xa0,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xe2,0xcc,0xf9,0xff,0xff,0xf8,0x98,0x82,0x81,0xee,0xdd,0x62,0x60,0xcf,0xf1,0x59,0x51,0x66,0xf0,0xff,0xff,0xf8,0xb1,0xcb,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf7,0x91,0x8c,0xa1,0xdb,0xfd,0xff,0xda,0x7d,0x72,0xb6,0xf6,0x92,0x8a,0xf4,0xab,0x3e,0x49,0xbb,0xff,0xff,0xcb,0x58,0x26,0x2b,0xe5,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf9,0xaa,0x92,0x97,0x91,0xad,0xec,0xfa,0xb7,0x91,0xdc,0xfd,0xf6,0xf5,0xfd,0xd7,0x68,0x8d,0xf7,0xea,0x73,0x30,0x35,0x30,0x4e,0xeb,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xf5,0xc5,0x9d,0x96,0x96,0x8f,0xcd,0xfa,0xf5,0xfc,0xfe,0xff,0xff,0xfe,0xfb,0xf1,0xf8,0xb6,0x33,0x31,0x35,0x3e,0x83,0xe2,0xfc,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xfe,0xfc,0xe9,0xb8,0x98,0x8b,0xa7,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0x64,0x1c,0x36,0x6b,0xc9,0xf7,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xe2,0xbb,0xe2,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xc8,0x70,0xb0,0xf3,0xfd,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xfc,0xeb,0xe8,0xea,0xea,0xe8,0xea,0xf9,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xfc,0xf7,0xf7,0xf6,0xf7,0xf7,0xf5,0xf6,0xfe,0xfe,0xff, + 0xff,0xfe,0xc7,0xa0,0xa8,0xa8,0xa8,0xa9,0xa0,0xc7,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xea,0xdb,0xde,0xdd,0xdd,0xdc,0xd9,0xe8,0xfe,0xff, + 0xff,0xfd,0xc1,0xa1,0xa9,0xa8,0xa8,0xa9,0xa0,0xc1,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe5,0xdb,0xdd,0xdd,0xdd,0xdd,0xda,0xe6,0xfe,0xff, + 0xff,0xfe,0xf3,0xd8,0xd8,0xd8,0xd8,0xd7,0xdc,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfc,0xf1,0xef,0xef,0xef,0xef,0xee,0xfa,0xfe,0xff, + 0xff,0xfe,0xfe,0xfe,0xfd,0xfd,0xfe,0xfe,0xf7,0xdd,0xf6,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf9,0xe9,0xf6,0xfe,0xfe,0xfe,0xfe,0xfe,0xfd,0xfe,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xdf,0xbb,0xaf,0xc6,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe3,0xd5,0xda,0xe9,0xfc,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xe9,0xc1,0xb5,0xb7,0xb2,0xcf,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xeb,0xd9,0xdc,0xd9,0xdc,0xf0,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xd0,0xb3,0xb7,0xb6,0xbe,0xdd,0xfa,0xe7,0xd3,0xf6,0xff,0xff,0xff,0xff,0xf8,0xdf,0xe7,0xfc,0xf2,0xe0,0xda,0xdb,0xd8,0xe3,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf7,0xb2,0xb4,0xbb,0xd3,0xf3,0xfd,0xf5,0xc1,0xbb,0xda,0xfd,0xe0,0xdd,0xfc,0xe9,0xcf,0xd0,0xf3,0xfe,0xfa,0xec,0xdd,0xd9,0xd8,0xf8,0xff,0xff,0xff, + 0xff,0xff,0xfe,0xfc,0xdc,0xcc,0xeb,0xfc,0xfe,0xfe,0xd3,0xc3,0xc3,0xec,0xf4,0xc9,0xc9,0xec,0xf7,0xd5,0xd5,0xdd,0xfd,0xfe,0xfd,0xf6,0xe6,0xed,0xfd,0xfe,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xfd,0xfc,0xfe,0xff,0xff,0xed,0xc1,0xc3,0xd4,0xfc,0xf0,0xcf,0xcc,0xea,0xfe,0xe5,0xd4,0xd3,0xee,0xff,0xff,0xfe,0xfd,0xfe,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfc,0xcb,0xc4,0xc5,0xf2,0xfe,0xf0,0xce,0xcc,0xeb,0xfe,0xf8,0xd7,0xd6,0xd7,0xfc,0xff,0xff,0xfe,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe4,0xc0,0xc2,0xdb,0xfd,0xff,0xf1,0xce,0xcc,0xeb,0xff,0xfe,0xea,0xd3,0xd2,0xe7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe7,0xbe,0xc9,0xf8,0xff,0xff,0xf1,0xcf,0xcc,0xeb,0xff,0xff,0xfc,0xdc,0xd1,0xec,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0xee,0xf3,0xfe,0xff,0xff,0xf0,0xca,0xc9,0xeb,0xff,0xff,0xfd,0xf8,0xf1,0xfc,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xfe,0xfe,0xfe,0xff,0xff,0xfa,0xd9,0xd6,0xf8,0xff,0xff,0xfe,0xfe,0xfe,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,0xfc,0xfc,0xfb,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xb0,0xa9,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0xfc,0xff,0xff,0xff,0xe0,0x69,0x67,0xd2,0xff,0xff,0xff,0xfc,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe1,0x88,0xa4,0xfb,0xff,0xff,0xd8,0x78,0x76,0xcb,0xff,0xff,0xfd,0x96,0x58,0xca,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc6,0x83,0x84,0xce,0xff,0xff,0xd9,0x78,0x75,0xcc,0xff,0xff,0xcd,0x55,0x50,0x9d,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0x97,0x8d,0x91,0xf7,0xff,0xdb,0x78,0x75,0xcc,0xff,0xf8,0x73,0x5f,0x66,0xe2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xcd,0x89,0x89,0xba,0xff,0xd8,0x78,0x76,0xcb,0xff,0xb1,0x57,0x5c,0xa8,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xe4,0xd0,0xfa,0xff,0xff,0xf8,0xa1,0x8c,0x8c,0xf0,0xe0,0x6d,0x6b,0xd1,0xf2,0x65,0x5f,0x71,0xf1,0xff,0xff,0xf9,0xb6,0xcd,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf8,0x99,0x97,0xa8,0xdd,0xfe,0xff,0xde,0x88,0x7f,0xbb,0xf7,0x9b,0x92,0xf5,0xb2,0x4c,0x56,0xc0,0xff,0xfe,0xcf,0x64,0x34,0x3b,0xe6,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf9,0xb2,0x9c,0xa1,0x9a,0xb3,0xed,0xfb,0xbd,0x9b,0xe0,0xfd,0xf6,0xf5,0xfd,0xdb,0x72,0x94,0xf8,0xec,0x7d,0x3e,0x44,0x3f,0x5a,0xeb,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xf5,0xcb,0xa6,0x9f,0x9f,0x9a,0xd0,0xfa,0xf5,0xfc,0xfe,0xff,0xff,0xfe,0xfc,0xf1,0xf8,0xbb,0x40,0x40,0x44,0x4a,0x8d,0xe5,0xfc,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xfe,0xfc,0xeb,0xbf,0x9f,0x94,0xaf,0xfd,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0x6e,0x2d,0x44,0x75,0xce,0xf8,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xe5,0xc0,0xe6,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xcc,0x7b,0xb5,0xf4,0xfd,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xfc,0xeb,0xeb,0xec,0xec,0xeb,0xec,0xf9,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xfc,0xf7,0xf7,0xf7,0xf7,0xf7,0xf5,0xf6,0xfe,0xfe,0xff, + 0xff,0xfe,0xcc,0xa8,0xb0,0xb0,0xb0,0xb0,0xaa,0xcc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xea,0xda,0xde,0xdd,0xdd,0xdc,0xd9,0xe8,0xfe,0xff, + 0xff,0xfd,0xc7,0xa8,0xb0,0xb0,0xb0,0xb0,0xa8,0xc6,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe5,0xdc,0xdd,0xdd,0xdd,0xdd,0xda,0xe6,0xfe,0xff, + 0xff,0xfe,0xf4,0xdc,0xdc,0xdc,0xdc,0xdb,0xdf,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfc,0xef,0xef,0xef,0xef,0xef,0xee,0xfa,0xfe,0xff, + 0xff,0xfe,0xfe,0xfe,0xfd,0xfd,0xfe,0xfe,0xf8,0xe0,0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf9,0xea,0xf7,0xfe,0xfe,0xfe,0xfe,0xfe,0xfd,0xfe,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xe0,0xc2,0xb7,0xca,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe4,0xd6,0xdb,0xea,0xfd,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xeb,0xc5,0xbb,0xbf,0xba,0xd3,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xea,0xda,0xdd,0xda,0xde,0xf1,0xfe,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xd2,0xb9,0xbf,0xbe,0xc4,0xe1,0xfa,0xe9,0xd7,0xf7,0xff,0xff,0xff,0xff,0xf9,0xe2,0xe8,0xfc,0xf2,0xe0,0xdc,0xdb,0xd9,0xe4,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf7,0xba,0xbb,0xc0,0xd7,0xf5,0xfd,0xf7,0xc7,0xc1,0xdd,0xfd,0xe2,0xe1,0xfc,0xea,0xd3,0xd4,0xf4,0xfe,0xfa,0xec,0xde,0xda,0xd9,0xfa,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xdf,0xd2,0xed,0xfc,0xfe,0xfe,0xd6,0xc8,0xc8,0xee,0xf5,0xce,0xcd,0xed,0xf8,0xd8,0xd9,0xdf,0xfd,0xfe,0xfd,0xf6,0xe7,0xed,0xfd,0xfe,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xfc,0xfd,0xfe,0xff,0xff,0xef,0xc6,0xc9,0xd8,0xfc,0xf1,0xd3,0xd2,0xec,0xfd,0xe5,0xd8,0xd6,0xef,0xff,0xff,0xfe,0xfd,0xfe,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfc,0xd0,0xc9,0xcb,0xf4,0xfe,0xf2,0xd3,0xd2,0xed,0xfe,0xf9,0xda,0xd9,0xd9,0xfc,0xff,0xff,0xfe,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe6,0xc5,0xc7,0xde,0xfd,0xff,0xf2,0xd3,0xd0,0xed,0xff,0xfe,0xed,0xd7,0xd5,0xe8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe9,0xc6,0xce,0xf8,0xff,0xff,0xf1,0xd3,0xd1,0xed,0xff,0xff,0xfc,0xde,0xd5,0xed,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xee,0xf4,0xfe,0xff,0xff,0xf2,0xce,0xce,0xeb,0xff,0xff,0xfd,0xf8,0xf2,0xfc,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xfe,0xfe,0xfe,0xff,0xff,0xf9,0xdd,0xdb,0xf8,0xff,0xff,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,0xfb,0xfb,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xb6,0xb0,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0xfc,0xff,0xff,0xff,0xe3,0x76,0x72,0xd4,0xff,0xff,0xff,0xfc,0xf8,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe4,0x91,0xae,0xfc,0xff,0xff,0xdb,0x83,0x80,0xcf,0xff,0xff,0xfd,0x9d,0x66,0xce,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xca,0x8e,0x8f,0xd3,0xff,0xff,0xdd,0x83,0x80,0xcf,0xff,0xff,0xd2,0x62,0x5f,0xa7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf2,0x9f,0x97,0x9b,0xf8,0xff,0xdd,0x83,0x80,0xd1,0xff,0xf8,0x7e,0x6b,0x74,0xe4,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xd0,0x94,0x92,0xc0,0xff,0xdb,0x83,0x80,0xcf,0xff,0xb9,0x65,0x68,0xaf,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xe7,0xd3,0xfa,0xff,0xff,0xf9,0xaa,0x97,0x96,0xf3,0xe0,0x7a,0x76,0xd5,0xf3,0x71,0x6d,0x7d,0xf2,0xff,0xff,0xf9,0xbb,0xd1,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf7,0xa3,0x9f,0xb0,0xe1,0xfe,0xff,0xe0,0x92,0x8a,0xc1,0xf7,0xa3,0x9a,0xf6,0xb8,0x5b,0x63,0xc6,0xff,0xfe,0xd3,0x6e,0x43,0x47,0xe9,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfa,0xb7,0xa5,0xa9,0xa3,0xba,0xf0,0xfb,0xc3,0xa4,0xe1,0xfd,0xf7,0xf6,0xfd,0xdd,0x7e,0x9d,0xf8,0xec,0x86,0x4b,0x51,0x4c,0x66,0xec,0xff,0xff,0xff, + 0xff,0xff,0xfe,0xfe,0xf7,0xd0,0xad,0xa7,0xa7,0xa3,0xd4,0xfb,0xf6,0xfc,0xfe,0xff,0xff,0xfe,0xfc,0xf1,0xf9,0xc0,0x4e,0x4e,0x51,0x56,0x94,0xe6,0xfc,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xfc,0xec,0xc4,0xa8,0x9e,0xb6,0xfd,0xff,0xfe,0xff,0xff,0xff,0xff,0xfe,0xff,0xfd,0x79,0x3b,0x52,0x7e,0xd0,0xf8,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xe6,0xc5,0xe7,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xce,0x87,0xc8,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xfc,0xed,0xed,0xed,0xed,0xed,0xef,0xfa,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xfd,0xf3,0xd4,0xce,0xd1,0xd0,0xce,0xd2,0xf9,0xff,0xff, + 0xff,0xfe,0xd0,0xb1,0xb7,0xb7,0xb7,0xb7,0xb1,0xd1,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0x81,0x23,0x36,0x36,0x36,0x36,0x21,0x7f,0xfe,0xff, + 0xff,0xfd,0xcb,0xb2,0xb8,0xb7,0xb7,0xb9,0xb1,0xcc,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0x71,0x25,0x37,0x37,0x37,0x37,0x25,0x72,0xfd,0xff, + 0xff,0xfd,0xf4,0xdf,0xde,0xdf,0xdf,0xde,0xe2,0xf9,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe9,0xaa,0xa5,0xa7,0xa7,0xa3,0xa8,0xe4,0xfe,0xff, + 0xff,0xfe,0xfd,0xfe,0xfe,0xfe,0xfe,0xfe,0xf9,0xe2,0xf6,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf9,0xee,0xf9,0xfc,0xfc,0xfc,0xfc,0xfd,0xfe,0xfe,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xe4,0xc6,0xbc,0xcf,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe4,0xd9,0xde,0xed,0xfd,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xed,0xcb,0xc0,0xc5,0xc1,0xd7,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xec,0xdb,0xde,0xdb,0xde,0xf1,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xd7,0xbf,0xc4,0xc3,0xca,0xe2,0xfa,0xea,0xd9,0xf6,0xff,0xff,0xff,0xff,0xf8,0xe3,0xeb,0xfc,0xf1,0xe1,0xdd,0xdd,0xda,0xe5,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf8,0xc0,0xc1,0xc6,0xda,0xf5,0xfd,0xf6,0xcc,0xc5,0xdf,0xfd,0xe5,0xe2,0xfd,0xeb,0xd5,0xd6,0xf5,0xfe,0xf9,0xed,0xdf,0xdb,0xda,0xf8,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xe3,0xd5,0xef,0xfc,0xfe,0xfe,0xdb,0xce,0xcc,0xee,0xf5,0xd3,0xd0,0xef,0xf8,0xda,0xdb,0xe0,0xfd,0xfe,0xfd,0xf7,0xe9,0xec,0xfd,0xfe,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xfc,0xfd,0xfe,0xff,0xff,0xef,0xcc,0xcd,0xdb,0xfc,0xf2,0xd6,0xd5,0xec,0xfd,0xe8,0xda,0xd8,0xf0,0xff,0xff,0xfe,0xfc,0xfe,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xfe,0xff,0xff,0xfc,0xd5,0xce,0xce,0xf3,0xfe,0xf3,0xd6,0xd5,0xee,0xfe,0xfa,0xdc,0xdc,0xdc,0xfb,0xff,0xff,0xfe,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe7,0xca,0xcb,0xe0,0xfd,0xff,0xf3,0xd6,0xd5,0xee,0xff,0xfe,0xee,0xd9,0xd8,0xea,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xeb,0xca,0xd3,0xf9,0xff,0xff,0xf2,0xd6,0xd5,0xee,0xff,0xff,0xfc,0xe1,0xd7,0xee,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xef,0xf5,0xfe,0xff,0xff,0xf2,0xd2,0xd2,0xec,0xff,0xff,0xfd,0xf9,0xf3,0xfa,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xfe,0xfe,0xfe,0xff,0xff,0xf9,0xdf,0xde,0xf8,0xff,0xff,0xfe,0xfe,0xfe,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,0xfb,0xfb,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xbd,0xb7,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf9,0xfc,0xff,0xff,0xff,0xe5,0x81,0x7f,0xd8,0xff,0xff,0xff,0xfd,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe5,0x9b,0xb3,0xfc,0xff,0xff,0xdd,0x8e,0x8b,0xd2,0xff,0xff,0xfd,0xa5,0x70,0xd2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xce,0x98,0x98,0xd5,0xff,0xff,0xdf,0x8d,0x8a,0xd5,0xff,0xff,0xd4,0x6f,0x6b,0xac,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf4,0xa8,0x9f,0xa3,0xf8,0xff,0xdf,0x8d,0x8a,0xd4,0xff,0xf9,0x86,0x77,0x7e,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xd6,0x9d,0x9c,0xc4,0xff,0xdf,0x8e,0x8b,0xd4,0xff,0xbe,0x72,0x73,0xb4,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xe7,0xd8,0xfb,0xff,0xff,0xf9,0xb1,0x9f,0x9f,0xf2,0xe4,0x85,0x82,0xd9,0xf3,0x7c,0x77,0x86,0xf3,0xff,0xff,0xfa,0xbf,0xd5,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf7,0xab,0xa8,0xb7,0xe3,0xfd,0xff,0xe3,0x9b,0x94,0xc5,0xf8,0xab,0xa3,0xf6,0xbc,0x67,0x70,0xc9,0xff,0xfe,0xd6,0x79,0x52,0x56,0xea,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf9,0xbe,0xac,0xb0,0xab,0xbf,0xf1,0xfb,0xc8,0xaa,0xe3,0xfd,0xf7,0xf8,0xfd,0xdf,0x88,0xa4,0xf9,0xee,0x8f,0x59,0x5e,0x5a,0x71,0xed,0xff,0xff,0xff, + 0xff,0xff,0xfe,0xfc,0xf7,0xd4,0xb4,0xae,0xaf,0xaa,0xd8,0xfb,0xf8,0xfd,0xfe,0xff,0xff,0xfe,0xfc,0xf3,0xf9,0xc3,0x5a,0x5b,0x5f,0x64,0x9c,0xe8,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xfc,0xee,0xca,0xb1,0xa7,0xbd,0xfd,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0x82,0x4b,0x5f,0x87,0xd4,0xf9,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xe9,0xcb,0xe9,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xd2,0x90,0xcc,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xfd,0xef,0xef,0xef,0xef,0xef,0xef,0xfa,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xfd,0xf4,0xd6,0xd1,0xd4,0xd4,0xd2,0xd6,0xfa,0xff,0xff, + 0xff,0xfe,0xd5,0xb8,0xbe,0xbe,0xbe,0xbe,0xb8,0xd4,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0x8a,0x34,0x44,0x44,0x44,0x44,0x32,0x88,0xfe,0xff, + 0xff,0xfe,0xd0,0xb8,0xbf,0xbf,0xbf,0xbf,0xb8,0xd1,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0x7c,0x33,0x45,0x45,0x45,0x45,0x33,0x7c,0xfd,0xff, + 0xff,0xfe,0xf5,0xe1,0xe1,0xe2,0xe1,0xe1,0xe4,0xfa,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xea,0xb1,0xab,0xad,0xad,0xaa,0xb0,0xe6,0xfe,0xff, + 0xff,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xf9,0xe4,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf9,0xee,0xf9,0xfc,0xfd,0xfd,0xfd,0xfd,0xfe,0xfe,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xe5,0xca,0xc2,0xd4,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe4,0xd9,0xde,0xed,0xfd,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xef,0xce,0xc8,0xca,0xc7,0xda,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xec,0xdb,0xde,0xdb,0xde,0xf1,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xda,0xc6,0xca,0xc8,0xce,0xe6,0xfb,0xec,0xdd,0xf7,0xff,0xff,0xff,0xff,0xfa,0xe4,0xeb,0xfc,0xf1,0xe1,0xdd,0xdd,0xda,0xe5,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf7,0xc6,0xc6,0xcb,0xdd,0xf6,0xfe,0xf6,0xd0,0xcb,0xe3,0xfd,0xe7,0xe4,0xfd,0xeb,0xd6,0xd8,0xf5,0xfe,0xf9,0xed,0xdf,0xdb,0xda,0xf8,0xff,0xff,0xff, + 0xff,0xff,0xfe,0xfc,0xe5,0xd8,0xef,0xfd,0xfe,0xfe,0xdd,0xd2,0xd2,0xf0,0xf6,0xd6,0xd4,0xf0,0xf7,0xdc,0xdc,0xe1,0xfd,0xfe,0xfd,0xf7,0xe9,0xec,0xfd,0xfe,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xfd,0xfd,0xfe,0xff,0xff,0xf1,0xd0,0xd2,0xde,0xfd,0xf4,0xd9,0xd8,0xef,0xfd,0xe7,0xdb,0xd9,0xf0,0xff,0xff,0xfe,0xfc,0xfe,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xfe,0xff,0xff,0xfd,0xd8,0xd2,0xd2,0xf5,0xfe,0xf5,0xd9,0xd8,0xef,0xfe,0xfa,0xdd,0xdd,0xdd,0xfc,0xff,0xff,0xfe,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe9,0xce,0xcf,0xe4,0xfd,0xff,0xf5,0xd9,0xd8,0xf0,0xff,0xfe,0xed,0xda,0xd9,0xe9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xec,0xce,0xd6,0xf8,0xff,0xff,0xf5,0xd9,0xd8,0xee,0xff,0xff,0xfc,0xe2,0xd8,0xee,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xf0,0xf6,0xfd,0xff,0xff,0xf4,0xd6,0xd6,0xed,0xff,0xff,0xfe,0xf8,0xf3,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xfe,0xfe,0xfe,0xff,0xff,0xfa,0xe1,0xe0,0xf9,0xff,0xff,0xfe,0xfe,0xfe,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,0xfb,0xfc,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xc2,0xbc,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0xfc,0xff,0xff,0xff,0xe7,0x8d,0x8a,0xdb,0xff,0xff,0xff,0xfd,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe7,0xa3,0xba,0xfc,0xff,0xff,0xe0,0x98,0x96,0xd6,0xff,0xff,0xfd,0xac,0x7d,0xd5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd3,0xa1,0xa2,0xd9,0xff,0xff,0xe2,0x97,0x95,0xd7,0xff,0xff,0xd7,0x7a,0x77,0xb3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf4,0xb0,0xa9,0xad,0xf9,0xff,0xe2,0x97,0x95,0xd7,0xff,0xf9,0x91,0x81,0x88,0xe6,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xd8,0xa6,0xa5,0xca,0xff,0xe2,0x97,0x96,0xd7,0xff,0xc3,0x7c,0x7f,0xba,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xea,0xdd,0xfb,0xff,0xff,0xfa,0xb8,0xa9,0xa6,0xf3,0xe7,0x8f,0x8e,0xdb,0xf4,0x85,0x83,0x90,0xf3,0xff,0xff,0xfa,0xc5,0xd8,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf8,0xb3,0xb1,0xbc,0xe6,0xfd,0xff,0xe5,0xa6,0x9e,0xcb,0xf8,0xb3,0xab,0xf7,0xc2,0x74,0x7b,0xcd,0xff,0xfe,0xd8,0x84,0x5f,0x64,0xec,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfa,0xc5,0xb5,0xb9,0xb4,0xc5,0xf1,0xfb,0xcc,0xb3,0xe6,0xfd,0xf8,0xf7,0xfd,0xe2,0x91,0xac,0xf9,0xef,0x97,0x68,0x6c,0x68,0x7c,0xef,0xff,0xff,0xff, + 0xff,0xff,0xfe,0xfe,0xf8,0xd7,0xbc,0xb7,0xb7,0xb3,0xdb,0xfb,0xf7,0xfd,0xfe,0xff,0xff,0xfe,0xfc,0xf4,0xf9,0xc8,0x68,0x68,0x6c,0x6f,0xa5,0xeb,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xfc,0xef,0xcf,0xb9,0xb0,0xc3,0xfd,0xff,0xfe,0xff,0xff,0xff,0xff,0xfe,0xff,0xfd,0x8d,0x59,0x6c,0x91,0xd7,0xf9,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xea,0xd0,0xeb,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xd6,0x99,0xd1,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xfd,0xf1,0xef,0xf0,0xf0,0xef,0xf0,0xfb,0xfd,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xfd,0xf5,0xd9,0xd5,0xd6,0xd6,0xd4,0xd8,0xfa,0xff,0xff, + 0xff,0xfe,0xd8,0xbe,0xc3,0xc3,0xc3,0xc3,0xbe,0xd7,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0x92,0x41,0x52,0x51,0x51,0x51,0x3f,0x91,0xfe,0xff, + 0xff,0xfe,0xd5,0xbe,0xc5,0xc4,0xc4,0xc5,0xbf,0xd4,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0x84,0x41,0x53,0x52,0x52,0x53,0x42,0x84,0xfd,0xff, + 0xff,0xfe,0xf6,0xe4,0xe3,0xe5,0xe5,0xe3,0xe6,0xfa,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf4,0xc0,0xb0,0xb2,0xb3,0xb1,0xb4,0xe9,0xfe,0xff, + 0xff,0xfe,0xfe,0xfe,0xfe,0xfd,0xfe,0xfe,0xf9,0xe6,0xf6,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xea,0x98,0xe5,0xff,0xff,0xfd,0xfc,0xfd,0xfe,0xfe,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xe7,0xcf,0xc8,0xd7,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0x66,0x1a,0x38,0x92,0xf5,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xef,0xd3,0xcc,0xce,0xcb,0xdd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0x92,0x2b,0x37,0x2d,0x43,0xb4,0xfb,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xde,0xca,0xce,0xcd,0xd3,0xe8,0xfb,0xee,0xdf,0xf7,0xff,0xff,0xff,0xff,0xfa,0xe5,0xed,0xf5,0xb5,0x56,0x33,0x37,0x27,0x66,0xf8,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf8,0xc9,0xca,0xcf,0xdf,0xf7,0xfd,0xf7,0xd4,0xd0,0xe4,0xfd,0xe8,0xe5,0xfd,0xec,0xd9,0xda,0xf6,0xfc,0xed,0x99,0x46,0x2b,0x25,0xe5,0xff,0xff,0xff, + 0xff,0xff,0xfe,0xfc,0xe7,0xdc,0xf0,0xfd,0xfe,0xfe,0xdf,0xd5,0xd6,0xf1,0xf6,0xd8,0xd7,0xf1,0xf7,0xdd,0xdd,0xe2,0xfe,0xfe,0xfa,0xd9,0x82,0xa4,0xf9,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xfc,0xfd,0xfe,0xff,0xff,0xf2,0xd2,0xd5,0xdf,0xfd,0xf4,0xdb,0xdb,0xee,0xfd,0xe9,0xdc,0xda,0xf1,0xff,0xff,0xfd,0xfa,0xfb,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xfe,0xff,0xff,0xfd,0xda,0xd5,0xd6,0xf5,0xfe,0xf3,0xdb,0xda,0xf0,0xfe,0xfa,0xdf,0xde,0xde,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xea,0xd3,0xd4,0xe6,0xfd,0xff,0xf5,0xdb,0xda,0xf0,0xff,0xfe,0xed,0xdb,0xda,0xeb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xed,0xd1,0xd9,0xf9,0xff,0xff,0xf4,0xdb,0xda,0xef,0xff,0xff,0xfc,0xe3,0xd9,0xef,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfc,0xf1,0xf7,0xfd,0xff,0xff,0xf4,0xd9,0xd8,0xee,0xff,0xff,0xfe,0xf8,0xf5,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xfe,0xfe,0xfe,0xff,0xff,0xfa,0xe4,0xe1,0xf9,0xff,0xff,0xfe,0xfe,0xfe,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfc,0xfc,0xfc,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xc7,0xc1,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xfd,0xff,0xff,0xff,0xe8,0x96,0x95,0xde,0xff,0xff,0xff,0xfd,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xea,0xac,0xc1,0xfd,0xff,0xff,0xe3,0xa0,0x9e,0xd9,0xff,0xff,0xfd,0xb2,0x87,0xd9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd6,0xaa,0xab,0xdc,0xff,0xff,0xe3,0xa0,0x9e,0xdb,0xff,0xff,0xdb,0x86,0x82,0xba,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf6,0xb7,0xb0,0xb3,0xf9,0xff,0xe3,0xa0,0x9e,0xdb,0xff,0xfa,0x9a,0x8c,0x91,0xe8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xdc,0xad,0xae,0xce,0xff,0xe3,0xa0,0x9e,0xdb,0xff,0xc8,0x87,0x8a,0xc0,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xec,0xdf,0xfb,0xff,0xff,0xfa,0xbe,0xb0,0xb0,0xf4,0xe8,0x9a,0x96,0xde,0xf5,0x91,0x8d,0x9a,0xf4,0xff,0xff,0xfa,0xc9,0xda,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf9,0xb9,0xb8,0xc3,0xe9,0xfd,0xff,0xe7,0xac,0xa6,0xcf,0xf9,0xb8,0xb3,0xf7,0xc7,0x80,0x86,0xd2,0xff,0xfe,0xdb,0x8d,0x6b,0x6f,0xed,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfb,0xca,0xbc,0xbf,0xba,0xcb,0xf3,0xfb,0xd1,0xb8,0xe9,0xfd,0xf9,0xf7,0xfd,0xe5,0x9a,0xb2,0xfa,0xef,0xa0,0x73,0x76,0x72,0x87,0xf0,0xff,0xff,0xff, + 0xff,0xff,0xfe,0xfd,0xf8,0xdb,0xc1,0xbd,0xbd,0xb9,0xde,0xfb,0xf8,0xfc,0xfe,0xff,0xff,0xfe,0xfc,0xf4,0xfa,0xcd,0x74,0x74,0x76,0x7b,0xab,0xec,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xfd,0xf1,0xd3,0xc0,0xb7,0xc9,0xfd,0xff,0xfe,0xff,0xff,0xff,0xff,0xfe,0xff,0xfd,0x95,0x64,0x77,0x9a,0xd9,0xfa,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xec,0xd3,0xec,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xd8,0xa0,0xd3,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xfd,0xf2,0xf1,0xf2,0xf0,0xf1,0xf1,0xfb,0xfe,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xf6,0xdb,0xd8,0xda,0xda,0xd8,0xda,0xfa,0xff,0xff, + 0xff,0xfe,0xdc,0xc3,0xc9,0xc8,0xc9,0xc9,0xc5,0xdc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0x9a,0x50,0x5f,0x5e,0x5e,0x5d,0x4e,0x99,0xfe,0xff, + 0xff,0xfe,0xd8,0xc5,0xca,0xca,0xca,0xca,0xc4,0xd8,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0x8d,0x52,0x61,0x60,0x60,0x61,0x51,0x8d,0xfd,0xff, + 0xff,0xfe,0xf6,0xe6,0xe6,0xe7,0xe6,0xe6,0xe9,0xfa,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf5,0xc5,0xb6,0xb8,0xb9,0xb7,0xb9,0xeb,0xfe,0xff, + 0xff,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfa,0xe7,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xeb,0x9e,0xe6,0xff,0xff,0xfd,0xfc,0xfd,0xfe,0xfe,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xe9,0xd3,0xcc,0xdb,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0x71,0x28,0x45,0x9a,0xf5,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xf1,0xd6,0xd0,0xd2,0xcf,0xdf,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0x9a,0x3b,0x45,0x3d,0x50,0xb9,0xfc,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xe0,0xcf,0xd2,0xd1,0xd6,0xea,0xfb,0xed,0xe2,0xf8,0xff,0xff,0xff,0xff,0xfa,0xe5,0xec,0xf6,0xbb,0x62,0x41,0x45,0x37,0x71,0xf9,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf9,0xcf,0xd0,0xd3,0xe3,0xf7,0xfe,0xf6,0xd6,0xd3,0xe6,0xfd,0xe8,0xe7,0xfd,0xec,0xd9,0xda,0xf6,0xfc,0xee,0xa0,0x53,0x3a,0x34,0xe8,0xff,0xff,0xff, + 0xff,0xff,0xfe,0xfc,0xe9,0xde,0xf1,0xfd,0xfe,0xfe,0xe1,0xd8,0xd9,0xf2,0xf5,0xd9,0xd8,0xf1,0xf7,0xdd,0xdd,0xe2,0xfe,0xfe,0xfa,0xdb,0x8b,0xaa,0xf9,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xfd,0xfd,0xfd,0xff,0xff,0xf3,0xd7,0xd8,0xe3,0xfd,0xf3,0xdd,0xdc,0xf0,0xfd,0xe9,0xdc,0xda,0xf1,0xff,0xff,0xfd,0xfb,0xfb,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xfe,0xff,0xff,0xfd,0xdd,0xd8,0xd9,0xf5,0xfe,0xf5,0xdc,0xdb,0xef,0xfe,0xfa,0xdf,0xde,0xde,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xec,0xd6,0xd7,0xe8,0xfd,0xff,0xf4,0xdc,0xdb,0xf1,0xff,0xfe,0xed,0xdb,0xda,0xeb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xd5,0xdb,0xfa,0xff,0xff,0xf4,0xdc,0xdb,0xf1,0xff,0xff,0xfc,0xe3,0xd9,0xef,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfb,0xf4,0xf8,0xfd,0xff,0xff,0xf4,0xda,0xd9,0xef,0xff,0xff,0xfe,0xf8,0xf5,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xfe,0xfe,0xfe,0xff,0xff,0xfb,0xe5,0xe2,0xf9,0xff,0xff,0xfe,0xfe,0xfe,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfc,0xfa,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xcc,0xc7,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0xfd,0xff,0xff,0xff,0xea,0x9f,0x9e,0xe1,0xff,0xff,0xff,0xfd,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xec,0xb3,0xc5,0xfd,0xff,0xff,0xe4,0xa9,0xa7,0xdc,0xff,0xff,0xfd,0xba,0x91,0xdc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xda,0xb2,0xb3,0xe0,0xff,0xff,0xe6,0xa8,0xa7,0xde,0xff,0xff,0xdd,0x90,0x8e,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf6,0xbd,0xb7,0xbb,0xfa,0xff,0xe8,0xa8,0xa7,0xde,0xff,0xfa,0xa3,0x95,0x9b,0xeb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xdf,0xb5,0xb5,0xd3,0xff,0xe7,0xa9,0xa7,0xdd,0xff,0xcb,0x92,0x95,0xc5,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xed,0xe1,0xfc,0xff,0xff,0xfb,0xc3,0xb7,0xb8,0xf4,0xea,0xa3,0x9f,0xe1,0xf6,0x9a,0x97,0xa3,0xf4,0xff,0xff,0xfb,0xcd,0xdd,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfa,0xbf,0xbf,0xc9,0xe9,0xfe,0xff,0xea,0xb5,0xaf,0xd4,0xf9,0xbf,0xb9,0xf8,0xcb,0x8a,0x91,0xd5,0xff,0xfe,0xde,0x96,0x78,0x7b,0xef,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfa,0xce,0xc1,0xc4,0xc1,0xd0,0xf3,0xfc,0xd5,0xc0,0xe9,0xfd,0xf9,0xf8,0xfd,0xe6,0xa2,0xb9,0xfa,0xf2,0xa6,0x7e,0x82,0x7d,0x90,0xf1,0xff,0xff,0xff, + 0xff,0xff,0xfe,0xfd,0xf9,0xde,0xc7,0xc2,0xc3,0xbf,0xe1,0xfb,0xf9,0xfd,0xfd,0xff,0xff,0xfd,0xfd,0xf5,0xfa,0xd1,0x7f,0x7f,0x82,0x86,0xb1,0xed,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xfd,0xf2,0xd6,0xc5,0xbe,0xcc,0xfd,0xff,0xfe,0xff,0xff,0xff,0xff,0xfe,0xff,0xfd,0x9d,0x72,0x82,0xa1,0xdd,0xfa,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xee,0xd8,0xed,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xdb,0xa8,0xd6,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xfe,0xfd,0xf2,0xf2,0xf2,0xf2,0xf2,0xf1,0xfb,0xfe,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xfd,0xf6,0xde,0xda,0xdc,0xdd,0xdb,0xdd,0xfb,0xff,0xff, + 0xff,0xfe,0xde,0xc9,0xcd,0xcd,0xcd,0xcd,0xca,0xde,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xa3,0x5f,0x6c,0x6b,0x6b,0x6c,0x5d,0xa2,0xfe,0xff, + 0xff,0xfe,0xdb,0xc9,0xce,0xce,0xce,0xce,0xc9,0xdb,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0x97,0x5f,0x6d,0x6d,0x6d,0x6d,0x5f,0x98,0xfd,0xff, + 0xff,0xfe,0xf7,0xe8,0xe6,0xe9,0xe9,0xe8,0xe9,0xfb,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf6,0xcb,0xbc,0xbe,0xbf,0xbc,0xc0,0xea,0xfe,0xff, + 0xff,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfa,0xe9,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xec,0xa5,0xe6,0xff,0xff,0xfd,0xfd,0xfd,0xfe,0xfe,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xea,0xd7,0xcf,0xdd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0x7b,0x37,0x53,0x9f,0xf6,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xf1,0xda,0xd3,0xd5,0xd3,0xe2,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa2,0x48,0x53,0x4b,0x5d,0xbe,0xfc,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xe2,0xd2,0xd5,0xd4,0xda,0xea,0xfc,0xee,0xe4,0xf9,0xff,0xff,0xff,0xff,0xea,0x6c,0x9d,0xf6,0xc1,0x6b,0x4e,0x52,0x46,0x7a,0xf9,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf9,0xd2,0xd3,0xd6,0xe5,0xf7,0xfe,0xf7,0xd8,0xd5,0xe7,0xfd,0xe9,0xe7,0xff,0x98,0x1a,0x26,0xd2,0xff,0xf0,0xa6,0x60,0x48,0x43,0xe9,0xff,0xff,0xff, + 0xff,0xff,0xfe,0xfc,0xea,0xe0,0xf3,0xfd,0xfe,0xfe,0xe4,0xda,0xdb,0xf3,0xf7,0xda,0xd9,0xf9,0xd1,0x39,0x36,0x5a,0xfa,0xff,0xfb,0xdd,0x92,0xb0,0xfa,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xfd,0xfd,0xfd,0xff,0xff,0xf4,0xd9,0xda,0xe4,0xfd,0xf3,0xde,0xdd,0xf1,0xfa,0x84,0x32,0x2c,0xb1,0xff,0xff,0xfd,0xfb,0xfc,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xfe,0xff,0xff,0xfd,0xe0,0xda,0xdb,0xf7,0xfe,0xf4,0xdd,0xdc,0xf1,0xff,0xe9,0x45,0x37,0x44,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xed,0xd8,0xd9,0xe9,0xfd,0xff,0xf4,0xdd,0xdc,0xf0,0xff,0xfd,0xa3,0x2f,0x26,0x94,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xd7,0xde,0xfa,0xff,0xff,0xf4,0xde,0xdd,0xf0,0xff,0xff,0xf2,0x5f,0x25,0xa9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfb,0xf3,0xf7,0xfd,0xff,0xff,0xf3,0xdb,0xda,0xef,0xff,0xff,0xfd,0xe4,0xc9,0xf6,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfe,0xff,0xff,0xfb,0xe5,0xe3,0xf9,0xff,0xff,0xff,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfc,0xfc,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xd1,0xcd,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xfd,0xff,0xff,0xff,0xec,0xa9,0xa6,0xe3,0xff,0xff,0xff,0xfd,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xec,0xba,0xcb,0xfd,0xff,0xff,0xe7,0xb0,0xaf,0xdf,0xff,0xff,0xfe,0xbe,0x9b,0xdf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xde,0xb8,0xb9,0xe2,0xff,0xff,0xe9,0xb0,0xae,0xe1,0xff,0xff,0xe0,0x99,0x97,0xc4,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf7,0xc3,0xbd,0xc1,0xfa,0xff,0xe9,0xb0,0xae,0xe1,0xff,0xfb,0xab,0x9f,0xa3,0xed,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe2,0xbb,0xbd,0xd8,0xff,0xe9,0xb0,0xae,0xe0,0xff,0xd1,0x9b,0x9d,0xc9,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xef,0xe4,0xfc,0xff,0xff,0xfb,0xc9,0xbe,0xbe,0xf5,0xeb,0xaa,0xaa,0xe3,0xf7,0xa3,0x9f,0xa9,0xf6,0xff,0xff,0xfb,0xd1,0xe0,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfa,0xc5,0xc4,0xcd,0xec,0xfe,0xff,0xeb,0xbc,0xb7,0xd7,0xf9,0xc4,0xbf,0xf9,0xd0,0x94,0x9a,0xd9,0xff,0xfe,0xe1,0x9f,0x83,0x87,0xf0,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfb,0xd3,0xc6,0xca,0xc6,0xd3,0xf3,0xfc,0xd8,0xc6,0xeb,0xfd,0xf9,0xf9,0xfd,0xe8,0xac,0xbe,0xfa,0xf1,0xae,0x89,0x8c,0x89,0x99,0xf2,0xff,0xff,0xff, + 0xff,0xff,0xfe,0xfd,0xf8,0xe1,0xcc,0xc9,0xc8,0xc5,0xe3,0xfc,0xf8,0xfc,0xfd,0xff,0xff,0xfd,0xfd,0xf5,0xfb,0xd4,0x8b,0x8a,0x8c,0x91,0xb7,0xee,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xfe,0xfd,0xf2,0xd9,0xc9,0xc3,0xd2,0xfd,0xff,0xfe,0xff,0xff,0xff,0xff,0xfe,0xff,0xfd,0xa6,0x7e,0x8c,0xaa,0xdf,0xfa,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xf0,0xdb,0xef,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xde,0xae,0xdb,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xfe,0xfd,0xf3,0xf3,0xf3,0xf3,0xf2,0xf2,0xfb,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xfd,0xf7,0xe0,0xde,0xde,0xe0,0xde,0xe1,0xfb,0xff,0xff, + 0xff,0xfe,0xe1,0xce,0xd1,0xd1,0xd1,0xd3,0xce,0xe0,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xa8,0x6a,0x77,0x76,0x76,0x76,0x6a,0xa7,0xfe,0xff, + 0xff,0xfe,0xdf,0xcd,0xd2,0xd2,0xd2,0xd2,0xcd,0xdf,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0x9f,0x6b,0x78,0x77,0x77,0x78,0x6c,0x9e,0xfd,0xff, + 0xff,0xfe,0xf8,0xea,0xea,0xeb,0xea,0xea,0xec,0xfa,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf7,0xcd,0xc0,0xc2,0xc2,0xc2,0xc3,0xed,0xfe,0xff, + 0xff,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfa,0xea,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xed,0xab,0xe8,0xff,0xfe,0xfd,0xfd,0xfd,0xfe,0xfe,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xec,0xd9,0xd4,0xdf,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0x85,0x47,0x60,0xa7,0xf7,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xf3,0xdc,0xd7,0xd9,0xd6,0xe4,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa9,0x57,0x60,0x57,0x6a,0xc2,0xfc,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xe4,0xd5,0xd8,0xd9,0xdd,0xea,0xfc,0xed,0xe4,0xf9,0xff,0xff,0xff,0xff,0xec,0x75,0xa3,0xf7,0xc5,0x78,0x5c,0x5f,0x54,0x84,0xfa,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfa,0xd5,0xd6,0xda,0xe7,0xf8,0xfe,0xf7,0xd9,0xd6,0xe8,0xfd,0xe9,0xe8,0xfe,0x9f,0x29,0x35,0xd5,0xff,0xef,0xae,0x6a,0x56,0x51,0xea,0xff,0xff,0xff, + 0xff,0xff,0xfe,0xfd,0xeb,0xe2,0xf4,0xfd,0xfe,0xfe,0xe3,0xdb,0xdc,0xf3,0xf7,0xd9,0xd9,0xf9,0xd6,0x47,0x43,0x66,0xfa,0xff,0xfb,0xe1,0x9a,0xb5,0xfa,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xfe,0xfd,0xfd,0xff,0xff,0xf4,0xda,0xdb,0xe5,0xfd,0xf3,0xde,0xdd,0xf1,0xfb,0x8e,0x40,0x3b,0xb5,0xff,0xff,0xfe,0xfb,0xfc,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xfe,0xfe,0xff,0xff,0xfd,0xdf,0xdb,0xdd,0xf6,0xfe,0xf4,0xdd,0xdc,0xf1,0xff,0xe9,0x53,0x45,0x52,0xf3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xed,0xd9,0xdc,0xe9,0xfe,0xff,0xf4,0xdd,0xdc,0xf0,0xff,0xfd,0xa8,0x3d,0x35,0x9b,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xd8,0xdf,0xfa,0xff,0xff,0xf4,0xde,0xdd,0xf0,0xff,0xff,0xf3,0x6a,0x34,0xb0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xf3,0xf7,0xfe,0xff,0xff,0xf3,0xdb,0xda,0xef,0xff,0xff,0xfd,0xe6,0xcd,0xf6,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xff,0xfe,0xfe,0xfe,0xff,0xff,0xfb,0xe5,0xe3,0xf9,0xff,0xff,0xfe,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfc,0xfc,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xd5,0xd1,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0xfd,0xff,0xff,0xff,0xed,0xb1,0xaf,0xe5,0xff,0xff,0xff,0xfd,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xee,0xc0,0xd0,0xfd,0xff,0xff,0xea,0xb8,0xb7,0xe3,0xff,0xff,0xfe,0xc5,0xa4,0xe2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0xbf,0xc0,0xe5,0xff,0xff,0xeb,0xb7,0xb7,0xe3,0xff,0xff,0xe2,0xa3,0xa1,0xc9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf6,0xc9,0xc4,0xc7,0xfa,0xff,0xeb,0xb7,0xb7,0xe3,0xff,0xfb,0xb3,0xa9,0xac,0xee,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe4,0xc2,0xc2,0xdb,0xff,0xeb,0xb8,0xb7,0xe3,0xff,0xd5,0xa5,0xa6,0xce,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xf0,0xe5,0xfc,0xff,0xff,0xfb,0xce,0xc4,0xc2,0xf6,0xed,0xb4,0xb2,0xe6,0xf7,0xab,0xa9,0xb1,0xf6,0xff,0xff,0xfb,0xd6,0xe3,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfa,0xca,0xc9,0xd1,0xed,0xfe,0xff,0xed,0xc0,0xbe,0xda,0xfa,0xc9,0xc5,0xf9,0xd2,0x9f,0xa3,0xdc,0xff,0xfe,0xe2,0xa8,0x8e,0x90,0xf1,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfb,0xd6,0xcb,0xce,0xcb,0xd7,0xf4,0xfc,0xdd,0xca,0xee,0xfd,0xf9,0xfa,0xfd,0xea,0xb3,0xc4,0xfb,0xf2,0xb6,0x93,0x97,0x94,0xa2,0xf3,0xff,0xff,0xff, + 0xff,0xff,0xfe,0xfd,0xfa,0xe3,0xd1,0xcd,0xcd,0xca,0xe4,0xfc,0xf9,0xfd,0xfd,0xff,0xff,0xfd,0xfd,0xf7,0xfb,0xd8,0x95,0x94,0x96,0x9a,0xbe,0xef,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xfe,0xfd,0xf4,0xdd,0xce,0xc7,0xd5,0xfd,0xff,0xfe,0xff,0xff,0xff,0xff,0xfe,0xff,0xfd,0xac,0x8a,0x96,0xb1,0xe2,0xfb,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xf0,0xdd,0xf0,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe1,0xb7,0xdd,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xfe,0xfd,0xf4,0xf4,0xf5,0xf4,0xf3,0xf4,0xfb,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xf8,0xe1,0xe1,0xe2,0xe2,0xe0,0xe2,0xfb,0xff,0xff, + 0xff,0xfe,0xe4,0xd1,0xd5,0xd4,0xd6,0xd6,0xd1,0xe3,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xaf,0x77,0x81,0x82,0x82,0x81,0x75,0xae,0xfe,0xff, + 0xff,0xfe,0xe0,0xd1,0xd6,0xd5,0xd5,0xd5,0xd1,0xe0,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xa6,0x76,0x83,0x82,0x82,0x83,0x77,0xa6,0xfd,0xff, + 0xff,0xfe,0xf8,0xeb,0xeb,0xeb,0xed,0xeb,0xee,0xfa,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf7,0xd2,0xc5,0xc7,0xc7,0xc7,0xc7,0xef,0xfe,0xff, + 0xff,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xf9,0xec,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xee,0xb2,0xeb,0xff,0xfe,0xfd,0xfd,0xfd,0xfe,0xfe,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xeb,0xdb,0xd7,0xe0,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0x90,0x55,0x6e,0xae,0xf7,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xf2,0xde,0xd9,0xdb,0xd8,0xe5,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0x64,0x6d,0x66,0x76,0xc8,0xfc,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xe5,0xd8,0xda,0xdb,0xde,0xee,0xfc,0xef,0xe5,0xf8,0xff,0xff,0xff,0xff,0xed,0x7f,0xa9,0xf7,0xca,0x83,0x69,0x6d,0x61,0x8f,0xfa,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfa,0xd8,0xd8,0xdc,0xe8,0xf9,0xfe,0xf8,0xda,0xd7,0xec,0xfa,0x8a,0x7e,0xf8,0xa9,0x37,0x44,0xd8,0xff,0xf1,0xb5,0x76,0x64,0x5f,0xec,0xff,0xff,0xff, + 0xff,0xff,0xfe,0xfd,0xec,0xe4,0xf4,0xfd,0xfe,0xfe,0xe4,0xdc,0xdd,0xfb,0xd3,0x25,0x1f,0xc1,0xe6,0x54,0x51,0x70,0xfb,0xff,0xfb,0xe1,0xa3,0xbc,0xfa,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xfe,0xfd,0xfd,0xff,0xff,0xf4,0xdb,0xdd,0xe5,0xff,0xc8,0x37,0x33,0xb1,0xfd,0x95,0x4e,0x4a,0xb9,0xff,0xff,0xfe,0xfb,0xfc,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xfe,0xfe,0xff,0xff,0xfd,0xe1,0xdc,0xde,0xf7,0xff,0xca,0x38,0x32,0xb3,0xff,0xeb,0x5d,0x52,0x5d,0xf3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xda,0xdd,0xea,0xfe,0xff,0xcb,0x38,0x32,0xb3,0xff,0xfd,0xb0,0x4b,0x43,0xa2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xd9,0xe0,0xfa,0xff,0xff,0xc9,0x39,0x33,0xb1,0xff,0xff,0xf4,0x74,0x42,0xb5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xf3,0xf7,0xfd,0xff,0xff,0xcb,0x28,0x24,0xb4,0xff,0xff,0xfd,0xe7,0xd1,0xf6,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xff,0xfe,0xfe,0xfe,0xff,0xff,0xef,0x6d,0x65,0xe6,0xff,0xff,0xff,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xf6,0xf5,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xd9,0xd4,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xfd,0xff,0xff,0xff,0xef,0xb8,0xb6,0xe9,0xff,0xff,0xff,0xfd,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xc6,0xd5,0xfd,0xff,0xff,0xec,0xbe,0xbe,0xe6,0xff,0xff,0xfe,0xca,0xac,0xe3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe2,0xc4,0xc6,0xe7,0xff,0xff,0xec,0xbe,0xbd,0xe6,0xff,0xff,0xe5,0xaa,0xa8,0xce,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0xcd,0xc9,0xcb,0xfb,0xff,0xec,0xbe,0xbd,0xe6,0xff,0xfb,0xb9,0xb0,0xb2,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe6,0xc8,0xc7,0xde,0xff,0xec,0xbe,0xbd,0xe6,0xff,0xd7,0xac,0xad,0xd3,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xf1,0xe7,0xfc,0xff,0xff,0xfb,0xd2,0xc9,0xc8,0xf5,0xef,0xba,0xb8,0xe8,0xf8,0xb3,0xb0,0xb9,0xf7,0xff,0xff,0xfc,0xd9,0xe5,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf9,0xcf,0xcd,0xd5,0xee,0xfe,0xff,0xee,0xc6,0xc3,0xde,0xfa,0xce,0xcb,0xfa,0xd7,0xa6,0xac,0xdf,0xff,0xfe,0xe5,0xaf,0x97,0x9a,0xf1,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfa,0xda,0xd0,0xd2,0xd1,0xdb,0xf4,0xfc,0xdf,0xcf,0xee,0xfd,0xfa,0xf9,0xfd,0xeb,0xb9,0xca,0xfb,0xf3,0xbb,0x9c,0x9f,0x9c,0xaa,0xf3,0xff,0xff,0xff, + 0xff,0xff,0xfe,0xfd,0xfa,0xe5,0xd5,0xd1,0xd2,0xcf,0xe7,0xfc,0xfa,0xfd,0xfd,0xff,0xff,0xfd,0xfc,0xf6,0xfb,0xdb,0x9d,0x9e,0xa0,0xa1,0xc3,0xf1,0xfc,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xfe,0xfd,0xf5,0xe0,0xd2,0xcd,0xd8,0xfd,0xff,0xfe,0xff,0xff,0xff,0xff,0xfe,0xff,0xfd,0xb4,0x94,0x9f,0xb7,0xe5,0xfb,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xf1,0xe1,0xf1,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe4,0xbc,0xdf,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xfe,0xfd,0xf5,0xf5,0xf5,0xf5,0xf2,0xf4,0xfc,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,0xf8,0xe5,0xe1,0xe5,0xe4,0xe3,0xe5,0xfb,0xff,0xff, + 0xff,0xfe,0xe5,0xd5,0xd8,0xd8,0xd9,0xd9,0xd5,0xe5,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xb6,0x83,0x8e,0x8d,0x8d,0x8c,0x82,0xb5,0xfe,0xff, + 0xff,0xfe,0xe2,0xd6,0xd9,0xd8,0xd8,0xd8,0xd5,0xe3,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xae,0x81,0x8e,0x8e,0x8e,0x8d,0x82,0xad,0xfd,0xff, + 0xff,0xfe,0xf9,0xec,0xee,0xee,0xee,0xed,0xef,0xfb,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0xd6,0xca,0xcc,0xcc,0xcc,0xcd,0xef,0xfe,0xff, + 0xff,0xfe,0xfc,0xfe,0xfe,0xfe,0xfe,0xfe,0xfa,0xeb,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xb7,0xec,0xff,0xfe,0xfd,0xfd,0xfd,0xfe,0xfe,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xed,0xdc,0xd8,0xe2,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0x96,0x62,0x78,0xb4,0xf8,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xf4,0xdf,0xda,0xdc,0xdb,0xe6,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xb6,0x6f,0x78,0x72,0x80,0xcc,0xfc,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xe6,0xda,0xdb,0xdc,0xdf,0xed,0xfc,0xef,0xe5,0xf8,0xff,0xff,0xff,0xff,0xee,0x89,0xb0,0xf8,0xcd,0x8b,0x74,0x77,0x6d,0x97,0xfa,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfa,0xd9,0xd9,0xdd,0xe9,0xf9,0xfd,0xf9,0xda,0xd7,0xeb,0xfa,0x93,0x87,0xf9,0xaf,0x48,0x53,0xdb,0xff,0xf1,0xba,0x82,0x70,0x6b,0xed,0xff,0xff,0xff, + 0xff,0xff,0xfe,0xfc,0xed,0xe5,0xf5,0xfd,0xfe,0xfe,0xe4,0xdc,0xdd,0xfb,0xd5,0x35,0x2f,0xc6,0xe8,0x60,0x5e,0x7b,0xfb,0xff,0xfb,0xe4,0xaa,0xc1,0xfa,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xfd,0xfe,0xff,0xff,0xf4,0xdb,0xdd,0xe5,0xff,0xcb,0x45,0x42,0xb5,0xfd,0x9d,0x5c,0x57,0xbf,0xff,0xff,0xfe,0xfc,0xfc,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xfe,0xff,0xff,0xfd,0xe1,0xdc,0xde,0xf7,0xff,0xcd,0x46,0x41,0xb7,0xff,0xec,0x6a,0x5f,0x6b,0xf4,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xda,0xdd,0xea,0xfe,0xff,0xcf,0x46,0x41,0xb9,0xff,0xfd,0xb4,0x58,0x51,0xaa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xd9,0xe0,0xfa,0xff,0xff,0xcd,0x47,0x42,0xb5,0xff,0xff,0xf5,0x7e,0x51,0xba,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xf3,0xf7,0xfd,0xff,0xff,0xce,0x38,0x32,0xb9,0xff,0xff,0xfd,0xea,0xd4,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xff,0xfe,0xfe,0xfe,0xff,0xff,0xf0,0x77,0x6f,0xe7,0xff,0xff,0xfe,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xf6,0xf5,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xdc,0xd8,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xfd,0xff,0xff,0xff,0xf0,0xbd,0xbd,0xe9,0xff,0xff,0xff,0xfd,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xca,0xd7,0xfd,0xff,0xff,0xee,0xc4,0xc3,0xe7,0xff,0xff,0xfe,0xce,0xb4,0xe6,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe4,0xc9,0xca,0xe9,0xff,0xff,0xee,0xc3,0xc3,0xe7,0xff,0xff,0xe7,0xb2,0xb1,0xd3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf7,0xd1,0xcf,0xce,0xfb,0xff,0xee,0xc3,0xc3,0xe7,0xff,0xfb,0xc0,0xb7,0xba,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xe9,0xcc,0xcb,0xe0,0xff,0xee,0xc3,0xc3,0xe7,0xff,0xdc,0xb4,0xb6,0xd7,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xf1,0xea,0xfc,0xff,0xff,0xfc,0xd5,0xce,0xcd,0xf6,0xef,0xc2,0xbe,0xea,0xf8,0xb9,0xb7,0xbe,0xf8,0xff,0xff,0xfc,0xdc,0xe8,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfa,0xd3,0xd1,0xd9,0xef,0xfe,0xff,0xf0,0xcc,0xc7,0xe0,0xfa,0xd3,0xce,0xfa,0xdc,0xaf,0xb4,0xe2,0xff,0xfe,0xe8,0xb6,0xa1,0xa3,0xf3,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfb,0xdd,0xd3,0xd5,0xd3,0xde,0xf5,0xfc,0xe1,0xd2,0xf0,0xfd,0xfa,0xf9,0xfd,0xed,0xc0,0xce,0xfb,0xf5,0xc0,0xa5,0xa8,0xa6,0xb2,0xf5,0xff,0xff,0xff, + 0xff,0xff,0xfe,0xfd,0xf9,0xe7,0xd7,0xd5,0xd5,0xd3,0xe8,0xfc,0xf9,0xfe,0xfd,0xff,0xff,0xfd,0xfc,0xf7,0xfb,0xde,0xa6,0xa7,0xa8,0xaa,0xca,0xf2,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xfe,0xfd,0xf6,0xe2,0xd5,0xd0,0xdc,0xfd,0xff,0xfe,0xff,0xff,0xff,0xff,0xfe,0xff,0xfd,0xbb,0x9c,0xa8,0xbe,0xe7,0xfb,0xfe,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,0xf3,0xe3,0xf3,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe6,0xc2,0xe2,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xfe,0xfd,0xf5,0xf6,0xf6,0xf6,0xf5,0xf4,0xfb,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xf8,0xe7,0xe4,0xe6,0xe7,0xe5,0xe6,0xfc,0xff,0xff, + 0xff,0xfe,0xe7,0xd7,0xda,0xdb,0xdb,0xdb,0xd9,0xe6,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xbd,0x8d,0x97,0x97,0x96,0x97,0x8c,0xbc,0xfe,0xff, + 0xff,0xfe,0xe5,0xd8,0xdb,0xda,0xda,0xdb,0xd8,0xe4,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xb5,0x8d,0x98,0x97,0x97,0x98,0x8e,0xb4,0xfd,0xff, + 0xff,0xfe,0xf9,0xed,0xee,0xee,0xee,0xee,0xf0,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf9,0xd8,0xce,0xd0,0xd0,0xcf,0xd1,0xf1,0xfe,0xff, + 0xff,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfa,0xec,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xbd,0xed,0xfe,0xfe,0xfd,0xfd,0xfe,0xfe,0xfe,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xee,0xdd,0xd9,0xe3,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xa0,0x6e,0x83,0xb9,0xf8,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xf5,0xe0,0xdb,0xde,0xda,0xe7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbb,0x7b,0x82,0x7e,0x8a,0xcf,0xfd,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xe8,0xdb,0xde,0xdd,0xde,0xed,0xfd,0xb2,0x6d,0xe5,0xff,0xff,0xff,0xff,0xef,0x93,0xb6,0xf9,0xd2,0x95,0x80,0x83,0x78,0x9e,0xfb,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf9,0xda,0xdc,0xde,0xe9,0xf8,0xff,0xe5,0x30,0x19,0x86,0xfc,0x9b,0x8f,0xf9,0xb6,0x56,0x61,0xdc,0xff,0xf2,0xbe,0x8c,0x7b,0x77,0xef,0xff,0xff,0xff, + 0xff,0xff,0xfe,0xfd,0xed,0xe6,0xf4,0xfd,0xff,0xfd,0x6e,0x32,0x35,0xc6,0xe2,0x42,0x3e,0xc8,0xea,0x6d,0x6c,0x85,0xfb,0xff,0xfc,0xe5,0xb1,0xc5,0xfb,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xfe,0xfd,0xfe,0xfe,0xff,0xc6,0x2f,0x33,0x71,0xf9,0xd1,0x52,0x4f,0xba,0xfd,0xa5,0x68,0x65,0xc4,0xff,0xff,0xfe,0xfc,0xfc,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xfe,0xff,0xff,0xf6,0x54,0x36,0x3d,0xd8,0xff,0xd2,0x53,0x4e,0xbc,0xff,0xee,0x76,0x6b,0x76,0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa9,0x28,0x2f,0x8b,0xfc,0xff,0xd2,0x53,0x4e,0xbe,0xff,0xfd,0xba,0x66,0x60,0xaf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xb4,0x28,0x4f,0xed,0xff,0xff,0xd0,0x54,0x4f,0xbc,0xff,0xff,0xf6,0x89,0x5f,0xc1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf6,0xc7,0xdc,0xfc,0xff,0xff,0xd1,0x46,0x41,0xbe,0xff,0xff,0xfd,0xeb,0xd8,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xf1,0x82,0x7a,0xea,0xff,0xff,0xfe,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xf6,0xf6,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xde,0xdb,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xfd,0xff,0xff,0xff,0xf0,0xc5,0xc2,0xeb,0xff,0xff,0xff,0xfd,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf2,0xd0,0xda,0xfd,0xff,0xff,0xef,0xc9,0xc8,0xea,0xff,0xff,0xfe,0xd2,0xbc,0xe8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe6,0xce,0xce,0xea,0xff,0xff,0xef,0xc9,0xc8,0xea,0xff,0xff,0xea,0xb9,0xb9,0xd6,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0xd6,0xd2,0xd4,0xfb,0xff,0xef,0xc9,0xc8,0xea,0xff,0xfc,0xc6,0xbf,0xc1,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe9,0xd0,0xd1,0xe3,0xff,0xef,0xc9,0xc8,0xea,0xff,0xde,0xbc,0xbc,0xdb,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xf2,0xeb,0xfd,0xff,0xff,0xfc,0xd9,0xd2,0xd1,0xf8,0xef,0xc7,0xc5,0xec,0xf9,0xc0,0xbf,0xc5,0xf8,0xff,0xff,0xfc,0xde,0xe8,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfa,0xd6,0xd5,0xdb,0xf0,0xfe,0xff,0xf0,0xd0,0xcd,0xe2,0xfb,0xd7,0xd3,0xfa,0xdd,0xb7,0xba,0xe4,0xff,0xfe,0xe9,0xbc,0xaa,0xaa,0xf3,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfb,0xdf,0xd7,0xd8,0xd7,0xe0,0xf6,0xfc,0xe4,0xd6,0xf0,0xfd,0xfb,0xfb,0xfd,0xee,0xc6,0xd3,0xfb,0xf5,0xc7,0xac,0xb0,0xad,0xb8,0xf6,0xff,0xff,0xff, + 0xff,0xff,0xfe,0xfe,0xfa,0xe9,0xda,0xd8,0xd8,0xd5,0xea,0xfc,0xfa,0xfc,0xfd,0xff,0xff,0xfd,0xfd,0xf8,0xfb,0xdf,0xad,0xaf,0xaf,0xb2,0xcc,0xf3,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xfe,0xfd,0xf7,0xe4,0xd8,0xd5,0xde,0xfd,0xff,0xfe,0xff,0xff,0xff,0xff,0xfe,0xff,0xfd,0xc1,0xa6,0xaf,0xc3,0xe7,0xfb,0xfe,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,0xf4,0xe5,0xf3,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe7,0xc8,0xe5,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xfe,0xfe,0xf6,0xf5,0xf5,0xf6,0xf5,0xf4,0xfc,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xfd,0xf9,0xe8,0xe7,0xe7,0xe9,0xe7,0xe9,0xfc,0xff,0xff, + 0xff,0xfe,0xe8,0xd8,0xdc,0xdc,0xdc,0xdd,0xd8,0xe7,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xc2,0x97,0xa0,0x9f,0x9f,0xa0,0x97,0xc1,0xfe,0xff, + 0xff,0xfe,0xe6,0xd9,0xdc,0xdc,0xdc,0xdc,0xda,0xe6,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0x97,0xa0,0xa0,0xa0,0xa0,0x96,0xbb,0xfd,0xff, + 0xff,0xfe,0xf8,0xee,0xee,0xee,0xee,0xee,0xef,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf9,0xdc,0xd4,0xd5,0xd5,0xd3,0xd5,0xf1,0xfe,0xff, + 0xff,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfa,0xec,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xc2,0xee,0xfe,0xfe,0xfd,0xfd,0xfd,0xfe,0xfe,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xee,0xdd,0xd9,0xe3,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xa8,0x7b,0x8d,0xc0,0xf8,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xf5,0xe0,0xdb,0xde,0xda,0xe7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xc0,0x87,0x8e,0x88,0x93,0xd3,0xfd,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xe8,0xdb,0xde,0xdd,0xde,0xee,0xfd,0xb7,0x77,0xe7,0xff,0xff,0xff,0xff,0xf1,0x9b,0xbb,0xf9,0xd6,0x9e,0x8a,0x8e,0x85,0xa8,0xfb,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf9,0xda,0xdc,0xde,0xe9,0xf8,0xff,0xe7,0x3e,0x27,0x8f,0xfc,0xa3,0x99,0xf9,0xbb,0x63,0x6c,0xdf,0xff,0xf4,0xc3,0x95,0x87,0x83,0xef,0xff,0xff,0xff, + 0xff,0xff,0xfe,0xfd,0xed,0xe6,0xf4,0xfd,0xff,0xfd,0x78,0x41,0x43,0xca,0xe5,0x52,0x4b,0xcd,0xeb,0x79,0x76,0x90,0xfb,0xff,0xfc,0xe9,0xb7,0xc9,0xfb,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xfe,0xfd,0xfe,0xfe,0xff,0xca,0x3c,0x42,0x7b,0xfa,0xd3,0x5f,0x5d,0xc0,0xfd,0xab,0x74,0x70,0xc9,0xff,0xff,0xfe,0xfc,0xfc,0xfc,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xfe,0xff,0xff,0xf7,0x61,0x43,0x4a,0xda,0xff,0xd4,0x60,0x5c,0xc2,0xff,0xef,0x80,0x77,0x80,0xf6,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0x36,0x3e,0x95,0xfc,0xff,0xd4,0x60,0x5c,0xc2,0xff,0xfe,0xc0,0x71,0x6c,0xb6,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xb9,0x38,0x5b,0xef,0xff,0xff,0xd3,0x61,0x5d,0xc0,0xff,0xff,0xf6,0x92,0x6c,0xc4,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0xcb,0xde,0xfd,0xff,0xff,0xd3,0x53,0x50,0xc3,0xff,0xff,0xfd,0xed,0xdb,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xf2,0x8b,0x82,0xeb,0xff,0xff,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xf7,0xf7,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xe0,0xdf,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xfd,0xff,0xff,0xff,0xf3,0xc9,0xc7,0xee,0xff,0xff,0xff,0xfe,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf3,0xd4,0xdc,0xfd,0xff,0xff,0xf1,0xcf,0xcc,0xea,0xff,0xff,0xfe,0xd6,0xc0,0xea,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe9,0xd2,0xd3,0xed,0xff,0xff,0xf1,0xce,0xcc,0xeb,0xff,0xff,0xea,0xbf,0xbe,0xd9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf7,0xd8,0xd5,0xd7,0xfc,0xff,0xf1,0xce,0xcc,0xeb,0xff,0xfc,0xca,0xc4,0xc5,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xec,0xd3,0xd4,0xe4,0xfe,0xf1,0xce,0xcc,0xeb,0xff,0xe0,0xc1,0xc1,0xde,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xf2,0xec,0xfd,0xff,0xff,0xfb,0xdb,0xd5,0xd5,0xf7,0xf3,0xcb,0xc9,0xed,0xf9,0xc4,0xc4,0xca,0xf9,0xff,0xff,0xfc,0xe1,0xea,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfa,0xd9,0xd7,0xdd,0xf1,0xfe,0xff,0xf2,0xd3,0xd0,0xe4,0xfb,0xd9,0xd6,0xfa,0xdf,0xbd,0xc1,0xe6,0xff,0xfe,0xec,0xc3,0xb2,0xb3,0xf4,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfb,0xe2,0xd9,0xdb,0xda,0xe1,0xf7,0xfd,0xe5,0xda,0xf2,0xfd,0xfa,0xfb,0xfd,0xf0,0xca,0xd6,0xfb,0xf5,0xcc,0xb4,0xb7,0xb6,0xbf,0xf6,0xff,0xff,0xff, + 0xff,0xff,0xfe,0xfe,0xf9,0xeb,0xdb,0xda,0xda,0xd7,0xeb,0xfc,0xfa,0xfc,0xfd,0xff,0xff,0xfd,0xfd,0xf9,0xfc,0xe2,0xb5,0xb6,0xb8,0xb8,0xd2,0xf4,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xfe,0xfd,0xf6,0xe7,0xdb,0xd7,0xdf,0xfd,0xff,0xfe,0xff,0xff,0xff,0xff,0xfe,0xff,0xfd,0xc7,0xaf,0xb7,0xca,0xea,0xfc,0xfe,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,0xf3,0xe6,0xf4,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe9,0xcc,0xe7,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xfe,0xfe,0xf6,0xf5,0xf7,0xf6,0xf4,0xf5,0xfc,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,0xf9,0xe9,0xe8,0xea,0xea,0xea,0xeb,0xfc,0xff,0xff, + 0xff,0xfe,0xe8,0xd9,0xdc,0xdd,0xdd,0xde,0xd9,0xe7,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xc7,0xa0,0xa9,0xa8,0xa8,0xa8,0xa0,0xc7,0xfe,0xff, + 0xff,0xfe,0xe6,0xda,0xdd,0xdd,0xdd,0xdd,0xdb,0xe5,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xc0,0xa0,0xa9,0xa8,0xa8,0xa9,0xa1,0xc1,0xfd,0xff, + 0xff,0xfe,0xfa,0xee,0xef,0xef,0xef,0xee,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf9,0xdf,0xd6,0xd8,0xd8,0xd8,0xd8,0xf3,0xfe,0xff, + 0xff,0xfe,0xfd,0xfe,0xfe,0xfe,0xff,0xff,0xed,0xa4,0xe8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xc8,0xef,0xfe,0xfe,0xfd,0xfd,0xfe,0xfe,0xfe,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0xa4,0x3f,0x1b,0x5f,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xaf,0x86,0x97,0xc5,0xf9,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfd,0xc8,0x52,0x2d,0x37,0x2a,0x7d,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xc6,0x91,0x97,0x92,0x9c,0xd7,0xfd,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfa,0x7c,0x2b,0x36,0x33,0x4d,0xa4,0xf3,0xbf,0x81,0xe8,0xff,0xff,0xff,0xff,0xf1,0xa2,0xc1,0xf9,0xd8,0xa6,0x94,0x98,0x8f,0xae,0xfb,0xff,0xff,0xff, + 0xff,0xff,0xff,0xea,0x2c,0x2a,0x3f,0x8a,0xe2,0xfd,0xea,0x4c,0x36,0x95,0xfc,0xa9,0xa0,0xfa,0xc1,0x6e,0x79,0xe1,0xff,0xf5,0xca,0x9e,0x92,0x8e,0xf1,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf9,0xa1,0x75,0xca,0xf8,0xff,0xfd,0x82,0x4d,0x51,0xce,0xe7,0x61,0x5a,0xd0,0xed,0x83,0x81,0x97,0xfb,0xff,0xfc,0xea,0xbd,0xcf,0xfb,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xfb,0xf9,0xfd,0xff,0xff,0xcd,0x4b,0x50,0x85,0xfa,0xd7,0x6d,0x6a,0xc5,0xfe,0xb2,0x7f,0x7b,0xcd,0xff,0xff,0xfe,0xfc,0xfd,0xfc,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf7,0x6c,0x51,0x57,0xde,0xff,0xd8,0x6d,0x69,0xc7,0xff,0xf0,0x8b,0x83,0x8a,0xf6,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xb5,0x45,0x4b,0x9b,0xfc,0xff,0xd9,0x6d,0x69,0xc7,0xff,0xfe,0xc5,0x7d,0x78,0xbb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0x46,0x67,0xed,0xff,0xff,0xd8,0x6d,0x6a,0xc5,0xff,0xff,0xf7,0x9b,0x78,0xc8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf7,0xcf,0xe1,0xfc,0xff,0xff,0xd7,0x62,0x5e,0xc8,0xff,0xff,0xfd,0xef,0xdc,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xf3,0x94,0x8d,0xec,0xff,0xff,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xf8,0xf6,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xe4,0xe1,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xfd,0xff,0xff,0xff,0xf3,0xcd,0xcd,0xee,0xff,0xff,0xff,0xfe,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf4,0xd6,0xe0,0xfd,0xff,0xff,0xf1,0xd3,0xd1,0xed,0xff,0xff,0xfe,0xda,0xc6,0xea,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xea,0xd5,0xd6,0xee,0xff,0xff,0xf2,0xd3,0xd0,0xed,0xff,0xff,0xed,0xc4,0xc5,0xdd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0xdb,0xd9,0xda,0xfc,0xff,0xf2,0xd3,0xd0,0xed,0xff,0xfc,0xce,0xc9,0xcc,0xf3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xee,0xd6,0xd7,0xe6,0xfe,0xf2,0xd3,0xd0,0xed,0xff,0xe3,0xc6,0xc8,0xe1,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xf3,0xec,0xfd,0xff,0xff,0xfc,0xde,0xd8,0xd8,0xf8,0xf2,0xd0,0xcf,0xef,0xf9,0xca,0xca,0xcf,0xf9,0xff,0xff,0xfc,0xe3,0xec,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfa,0xda,0xd8,0xde,0xf2,0xfe,0xff,0xf2,0xd7,0xd4,0xe7,0xfb,0xdd,0xda,0xfb,0xe1,0xc4,0xc6,0xe8,0xff,0xfe,0xee,0xc8,0xb9,0xba,0xf5,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfb,0xe1,0xda,0xdd,0xdb,0xe2,0xf7,0xfd,0xe7,0xdc,0xf3,0xfd,0xfb,0xfc,0xfd,0xf1,0xcf,0xd9,0xfc,0xf6,0xd1,0xbb,0xbd,0xbd,0xc4,0xf7,0xff,0xff,0xff, + 0xff,0xff,0xfe,0xfe,0xfb,0xea,0xdc,0xdb,0xdb,0xda,0xeb,0xfc,0xfb,0xfc,0xfd,0xff,0xff,0xfd,0xfd,0xf8,0xfc,0xe4,0xbb,0xbe,0xbe,0xbf,0xd6,0xf5,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xfe,0xfd,0xf6,0xe6,0xdc,0xd8,0xe0,0xfd,0xff,0xfe,0xff,0xff,0xff,0xff,0xfe,0xff,0xfd,0xcb,0xb7,0xbd,0xce,0xec,0xfc,0xfe,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xf4,0xe8,0xf4,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xed,0xd0,0xe9,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xfe,0xfe,0xf6,0xf5,0xf7,0xf5,0xf4,0xf5,0xfc,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,0xfa,0xeb,0xea,0xec,0xec,0xeb,0xeb,0xfc,0xff,0xff, + 0xff,0xfe,0xe8,0xd9,0xdc,0xdd,0xdd,0xde,0xd9,0xe7,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xcb,0xa8,0xb0,0xb0,0xb0,0xb0,0xa8,0xcc,0xfe,0xff, + 0xff,0xfe,0xe6,0xda,0xdd,0xdd,0xdd,0xdd,0xdb,0xe5,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xc8,0xa8,0xb0,0xb0,0xb0,0xb0,0xa8,0xc7,0xfd,0xff, + 0xff,0xfe,0xfa,0xee,0xef,0xef,0xef,0xee,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0xe2,0xdb,0xdc,0xdc,0xdc,0xdc,0xf4,0xfe,0xff, + 0xff,0xfe,0xfd,0xfe,0xfe,0xfe,0xff,0xff,0xee,0xaa,0xe9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf3,0xcb,0xf0,0xfe,0xfe,0xfe,0xfd,0xfe,0xfe,0xfe,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0xab,0x4e,0x2b,0x6b,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xb6,0x91,0xa0,0xca,0xf9,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfd,0xcb,0x5d,0x3d,0x45,0x3a,0x86,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xcb,0x9a,0x9f,0x9c,0xa5,0xdb,0xfd,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfb,0x84,0x3a,0x45,0x42,0x5a,0xa9,0xf4,0xc4,0x8a,0xe9,0xff,0xff,0xff,0xff,0xf2,0xaa,0xc6,0xf9,0xdc,0xad,0x9e,0xa1,0x99,0xb5,0xfb,0xff,0xff,0xff, + 0xff,0xff,0xff,0xeb,0x3b,0x39,0x4d,0x91,0xe4,0xfd,0xec,0x59,0x46,0x9f,0xfc,0xb0,0xa6,0xfa,0xc6,0x7c,0x82,0xe5,0xff,0xf5,0xcf,0xa5,0x9a,0x97,0xf2,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf9,0xa8,0x7e,0xcf,0xf8,0xff,0xfe,0x8b,0x5b,0x5e,0xd1,0xe8,0x6c,0x67,0xd4,0xed,0x8e,0x8c,0xa0,0xfc,0xff,0xfc,0xec,0xc2,0xd3,0xfc,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xfb,0xf9,0xfd,0xff,0xff,0xd1,0x58,0x5c,0x8d,0xfa,0xd9,0x78,0x76,0xc9,0xfd,0xb9,0x8b,0x87,0xd0,0xff,0xff,0xfe,0xfc,0xfd,0xfc,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0x77,0x5e,0x63,0xe0,0xff,0xda,0x78,0x74,0xcb,0xff,0xf1,0x95,0x8d,0x94,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xba,0x53,0x59,0xa4,0xfc,0xff,0xda,0x78,0x74,0xcb,0xff,0xfe,0xca,0x88,0x84,0xc1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc4,0x52,0x72,0xef,0xff,0xff,0xd9,0x78,0x75,0xc9,0xff,0xff,0xf8,0xa3,0x82,0xce,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0xd1,0xe2,0xfd,0xff,0xff,0xda,0x6d,0x6a,0xca,0xff,0xff,0xfd,0xef,0xdf,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xf3,0x9c,0x95,0xec,0xff,0xff,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xf8,0xf7,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xe6,0xe2,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xfd,0xff,0xff,0xff,0xf4,0xd1,0xd0,0xef,0xff,0xff,0xff,0xfe,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf4,0xd9,0xe3,0xfd,0xff,0xff,0xf2,0xd5,0xd5,0xed,0xff,0xff,0xfe,0xdc,0xcb,0xed,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xeb,0xd7,0xd8,0xef,0xff,0xff,0xf2,0xd6,0xd5,0xed,0xff,0xff,0xee,0xcb,0xc9,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0xdc,0xdc,0xdc,0xfb,0xff,0xf2,0xd6,0xd5,0xef,0xff,0xfc,0xd3,0xcd,0xcf,0xf3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xef,0xd8,0xda,0xe7,0xff,0xf3,0xd6,0xd5,0xed,0xff,0xe5,0xca,0xcd,0xe3,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xf5,0xed,0xfd,0xff,0xff,0xfc,0xe0,0xda,0xda,0xf7,0xf3,0xd3,0xd2,0xef,0xf9,0xcf,0xce,0xd2,0xf9,0xff,0xff,0xfc,0xe5,0xee,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfb,0xda,0xdb,0xdf,0xf2,0xfe,0xff,0xf3,0xd9,0xd7,0xe8,0xfb,0xdf,0xdc,0xfb,0xe4,0xc8,0xcb,0xea,0xff,0xfe,0xf0,0xcb,0xbe,0xc0,0xf5,0xff,0xff,0xff, + 0xff,0xff,0xfe,0xfc,0xe3,0xdb,0xde,0xdc,0xe3,0xf7,0xfd,0xe8,0xde,0xf4,0xfd,0xfb,0xfb,0xfd,0xf2,0xd3,0xdd,0xfc,0xf5,0xd4,0xc0,0xc4,0xc2,0xc9,0xf7,0xff,0xff,0xff, + 0xff,0xff,0xfe,0xfe,0xfb,0xeb,0xdd,0xdd,0xdc,0xdb,0xec,0xfc,0xfb,0xfc,0xfd,0xff,0xff,0xfd,0xfc,0xf9,0xfc,0xe6,0xc1,0xc3,0xc3,0xc4,0xd9,0xf5,0xfe,0xfe,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xfe,0xfd,0xf6,0xe7,0xdc,0xd9,0xe2,0xfd,0xff,0xfe,0xff,0xff,0xff,0xff,0xfe,0xff,0xfe,0xcf,0xbc,0xc3,0xd1,0xee,0xfc,0xfe,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xeb,0xf3,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xed,0xd5,0xec,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xf9,0xd2,0xce,0xd1,0xcf,0xcc,0xd0,0xf8,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfa,0xee,0xeb,0xed,0xed,0xed,0xed,0xfc,0xff,0xff, + 0xff,0xfe,0x7f,0x21,0x36,0x36,0x36,0x36,0x23,0x7f,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xd1,0xb0,0xb8,0xb7,0xb7,0xb7,0xb1,0xd0,0xfe,0xff, + 0xff,0xfd,0x72,0x25,0x37,0x37,0x37,0x37,0x25,0x71,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xcc,0xb1,0xb9,0xb7,0xb7,0xb8,0xb2,0xcb,0xfd,0xff, + 0xff,0xfe,0xe4,0xa8,0xa3,0xa7,0xa7,0xa3,0xb2,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0xe4,0xdf,0xde,0xdf,0xde,0xdf,0xf4,0xfd,0xff, + 0xff,0xfe,0xfe,0xfd,0xfc,0xfc,0xfe,0xfe,0xef,0xb2,0xea,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf5,0xcf,0xf1,0xfe,0xff,0xfe,0xfe,0xfe,0xfd,0xfe,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xf9,0xb3,0x5c,0x3a,0x76,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xbc,0x9b,0xa8,0xce,0xfa,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfd,0xcf,0x68,0x4a,0x53,0x47,0x8e,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xd0,0xa4,0xa9,0xa4,0xad,0xdf,0xfd,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfb,0x8d,0x47,0x51,0x4f,0x65,0xaf,0xf5,0xc7,0x94,0xea,0xff,0xff,0xff,0xff,0xf2,0xb1,0xca,0xfa,0xdf,0xb5,0xa7,0xa9,0xa1,0xbc,0xfc,0xff,0xff,0xff, + 0xff,0xff,0xff,0xec,0x48,0x47,0x5b,0x99,0xe6,0xfd,0xec,0x67,0x54,0xa5,0xfc,0xb5,0xad,0xfb,0xca,0x87,0x8e,0xe7,0xfe,0xf6,0xd1,0xaf,0xa4,0x9f,0xf3,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfa,0xae,0x88,0xd0,0xf9,0xfe,0xfd,0x95,0x69,0x6b,0xd4,0xea,0x79,0x74,0xd6,0xf0,0x98,0x95,0xa9,0xfc,0xff,0xfc,0xed,0xc8,0xd6,0xfc,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xfb,0xfa,0xfd,0xff,0xff,0xd5,0x67,0x6a,0x96,0xfa,0xdd,0x83,0x80,0xce,0xfe,0xbe,0x94,0x92,0xd5,0xff,0xff,0xfe,0xfd,0xfd,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0x82,0x6c,0x71,0xe2,0xff,0xdd,0x83,0x80,0xce,0xff,0xf3,0x9e,0x97,0x9d,0xf8,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0x62,0x67,0xab,0xfc,0xff,0xde,0x82,0x80,0xd0,0xff,0xfe,0xce,0x92,0x8e,0xc6,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc8,0x62,0x7d,0xf0,0xff,0xff,0xde,0x83,0x80,0xcc,0xff,0xff,0xf8,0xab,0x8e,0xd2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0xd5,0xe5,0xfd,0xff,0xff,0xde,0x78,0x77,0xce,0xff,0xff,0xfd,0xf1,0xe2,0xfa,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xf3,0xa4,0x9e,0xee,0xff,0xff,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xf8,0xf9,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xe9,0xe4,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xfd,0xff,0xff,0xff,0xf4,0xd6,0xd3,0xf0,0xff,0xff,0xff,0xfe,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf5,0xda,0xe2,0xfd,0xff,0xff,0xf3,0xd9,0xd8,0xf0,0xff,0xff,0xfe,0xe0,0xcf,0xee,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xec,0xd8,0xd9,0xee,0xff,0xff,0xf3,0xd9,0xd8,0xf0,0xff,0xff,0xf0,0xcf,0xce,0xe3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf9,0xdd,0xdd,0xdd,0xfc,0xff,0xf3,0xd9,0xd8,0xf0,0xff,0xfc,0xd6,0xd2,0xd4,0xf6,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xef,0xda,0xdb,0xe8,0xfe,0xf4,0xd9,0xd8,0xf0,0xff,0xe7,0xd0,0xd1,0xe5,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xf5,0xed,0xfd,0xff,0xff,0xfc,0xe1,0xdb,0xdb,0xf7,0xf4,0xd7,0xd6,0xf0,0xfa,0xd3,0xd2,0xd7,0xfa,0xff,0xff,0xfd,0xe8,0xef,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfb,0xda,0xdb,0xdf,0xf2,0xfe,0xff,0xf4,0xda,0xd8,0xe8,0xfb,0xe1,0xde,0xfb,0xe7,0xcd,0xcf,0xec,0xff,0xfe,0xf0,0xd1,0xc5,0xc6,0xf6,0xff,0xff,0xff, + 0xff,0xff,0xfe,0xfc,0xe3,0xdb,0xde,0xdc,0xe3,0xf7,0xfd,0xea,0xdf,0xf3,0xfd,0xfb,0xfb,0xfd,0xf2,0xd6,0xe0,0xfc,0xf6,0xd8,0xc6,0xc9,0xc7,0xce,0xf7,0xff,0xff,0xff, + 0xff,0xff,0xfe,0xfe,0xfb,0xeb,0xdd,0xdd,0xdc,0xdb,0xec,0xfc,0xfb,0xfc,0xfd,0xff,0xff,0xfd,0xfc,0xf9,0xfc,0xe9,0xc7,0xc8,0xca,0xca,0xdc,0xf6,0xfe,0xfe,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xfe,0xfd,0xf6,0xe7,0xdc,0xd9,0xe2,0xfd,0xff,0xfe,0xff,0xff,0xff,0xff,0xfe,0xff,0xfe,0xd3,0xc3,0xc8,0xd5,0xf0,0xfc,0xfe,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xeb,0xf3,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xef,0xd9,0xec,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xfa,0xd6,0xd2,0xd4,0xd3,0xcf,0xd4,0xf8,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfa,0xee,0xed,0xef,0xef,0xef,0xef,0xfd,0xff,0xff, + 0xff,0xfe,0x88,0x32,0x44,0x44,0x44,0x44,0x32,0x86,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xd4,0xb7,0xbe,0xbe,0xbe,0xbe,0xb8,0xd5,0xfe,0xff, + 0xff,0xfd,0x7c,0x33,0x45,0x45,0x45,0x45,0x33,0x7b,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xd1,0xb8,0xbf,0xbf,0xbf,0xbf,0xb8,0xd0,0xfe,0xff, + 0xff,0xfe,0xe6,0xb0,0xaa,0xad,0xac,0xa9,0xb7,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0xe6,0xe1,0xe1,0xe2,0xe1,0xe1,0xf5,0xfe,0xff, + 0xff,0xfe,0xfe,0xfd,0xfd,0xfd,0xfe,0xff,0xf0,0xb7,0xeb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf4,0xd4,0xf3,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xf9,0xb9,0x68,0x49,0x80,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xc2,0xa4,0xb0,0xd2,0xfa,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfd,0xd2,0x75,0x56,0x5f,0x55,0x97,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xd4,0xac,0xb0,0xad,0xb6,0xe0,0xfd,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfb,0x96,0x56,0x5e,0x5d,0x70,0xb7,0xf5,0xcb,0x9b,0xec,0xff,0xff,0xff,0xff,0xf4,0xb7,0xce,0xfa,0xe1,0xbc,0xaf,0xb0,0xab,0xc2,0xfc,0xff,0xff,0xff, + 0xff,0xff,0xff,0xee,0x55,0x55,0x67,0xa0,0xe7,0xfd,0xee,0x73,0x61,0xac,0xfd,0xbc,0xb5,0xfb,0xcf,0x92,0x97,0xe8,0xff,0xf6,0xd7,0xb5,0xac,0xa9,0xf3,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfa,0xb3,0x90,0xd5,0xf9,0xfe,0xfe,0x9c,0x73,0x76,0xd6,0xeb,0x84,0x7f,0xda,0xef,0xa1,0x9f,0xb0,0xfc,0xff,0xfc,0xef,0xcc,0xda,0xfc,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xfb,0xfa,0xfd,0xff,0xff,0xd8,0x70,0x75,0x9f,0xfb,0xe0,0x8e,0x8b,0xd0,0xfd,0xc4,0x9d,0x9b,0xd8,0xff,0xff,0xfe,0xfd,0xfd,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf9,0x8b,0x76,0x7b,0xe4,0xff,0xe1,0x8d,0x8b,0xd2,0xff,0xf3,0xa6,0xa0,0xa5,0xf8,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc3,0x6e,0x71,0xb1,0xfc,0xff,0xe1,0x8d,0x8b,0xd3,0xff,0xfe,0xd2,0x9a,0x98,0xcb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xcc,0x6c,0x88,0xf2,0xff,0xff,0xe0,0x8e,0x8b,0xd1,0xff,0xff,0xf9,0xb2,0x97,0xd5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf7,0xd8,0xe7,0xfd,0xff,0xff,0xe0,0x85,0x82,0xd4,0xff,0xff,0xfd,0xf1,0xe5,0xf9,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xf5,0xad,0xa6,0xef,0xff,0xff,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xf8,0xf9,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xe8,0xe7,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xfd,0xff,0xff,0xff,0xf5,0xd8,0xd6,0xf1,0xff,0xff,0xff,0xfe,0xfb,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf5,0xdb,0xe4,0xfd,0xff,0xff,0xf4,0xdb,0xdb,0xef,0xff,0xff,0xfe,0xe2,0xd2,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xec,0xd9,0xda,0xf0,0xff,0xff,0xf4,0xdb,0xda,0xef,0xff,0xff,0xf1,0xd2,0xd2,0xe3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf9,0xdf,0xde,0xde,0xfc,0xff,0xf4,0xdb,0xda,0xf1,0xff,0xfd,0xda,0xd5,0xd7,0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xee,0xdb,0xdc,0xea,0xfe,0xf5,0xdb,0xda,0xef,0xff,0xe8,0xd4,0xd4,0xe6,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xc8,0x9f,0xf5,0xff,0xff,0xfc,0xe2,0xdc,0xdc,0xf7,0xf5,0xd9,0xd8,0xf1,0xf9,0xd7,0xd5,0xd9,0xf9,0xff,0xff,0xfd,0xe9,0xf1,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf1,0x2a,0x23,0x49,0xba,0xfc,0xff,0xf5,0xdb,0xd9,0xe9,0xfc,0xe4,0xe1,0xfb,0xe8,0xd1,0xd2,0xed,0xff,0xfe,0xf2,0xd4,0xc9,0xcb,0xf7,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf5,0x5d,0x2f,0x37,0x2c,0x60,0xd9,0xfe,0xea,0xe0,0xf4,0xfd,0xfb,0xfb,0xfd,0xf3,0xda,0xe2,0xfc,0xf6,0xdb,0xcc,0xcd,0xcb,0xd2,0xf8,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xee,0x94,0x42,0x34,0x34,0x28,0x9f,0xfd,0xfc,0xfc,0xfd,0xff,0xff,0xfd,0xfc,0xfa,0xfc,0xeb,0xcc,0xcc,0xce,0xce,0xdf,0xf6,0xfe,0xfe,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xfa,0xd8,0x78,0x39,0x1f,0x57,0xfb,0xff,0xfe,0xff,0xff,0xff,0xff,0xfe,0xff,0xfd,0xd7,0xc7,0xcd,0xd9,0xf0,0xfd,0xfe,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf9,0xc9,0x7d,0xc8,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xf0,0xdb,0xed,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xfa,0xd8,0xd4,0xd6,0xd6,0xd6,0xda,0xf5,0xfc,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,0xfb,0xef,0xee,0xf0,0xf0,0xef,0xf1,0xfd,0xff,0xff, + 0xff,0xfe,0x91,0x3f,0x51,0x51,0x51,0x52,0x41,0x92,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xd7,0xbe,0xc4,0xc3,0xc3,0xc3,0xbe,0xd8,0xfe,0xff, + 0xff,0xfd,0x84,0x42,0x53,0x52,0x52,0x53,0x42,0x84,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xd4,0xbf,0xc4,0xc4,0xc4,0xc5,0xbe,0xd5,0xfe,0xff, + 0xff,0xfe,0xe9,0xb4,0xb1,0xb3,0xb3,0xaf,0xbc,0xf3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xe8,0xe4,0xe5,0xe5,0xe3,0xe4,0xf6,0xfe,0xff, + 0xff,0xfe,0xfe,0xfd,0xfc,0xfc,0xfd,0xfe,0xf1,0xbc,0xed,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf6,0xd7,0xf4,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0xbf,0x74,0x59,0x89,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xc8,0xad,0xb7,0xd6,0xfb,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfd,0xd6,0x80,0x65,0x6d,0x64,0xa0,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xd8,0xb4,0xb9,0xb4,0xbc,0xe3,0xfd,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfb,0x9e,0x63,0x6c,0x69,0x7c,0xbb,0xf6,0xcf,0xa4,0xed,0xff,0xff,0xff,0xff,0xf5,0xbe,0xd1,0xfb,0xe4,0xc2,0xb7,0xb9,0xb2,0xc7,0xfc,0xff,0xff,0xff, + 0xff,0xff,0xff,0xef,0x64,0x63,0x73,0xa8,0xe8,0xfd,0xef,0x7e,0x6d,0xb3,0xfd,0xc2,0xbb,0xfb,0xd3,0x9c,0xa2,0xe9,0xfe,0xf8,0xd9,0xbd,0xb3,0xb2,0xf4,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfa,0xb9,0x9a,0xd7,0xfa,0xfe,0xfd,0xa4,0x7f,0x81,0xda,0xec,0x8f,0x8a,0xde,0xf0,0xaa,0xa7,0xb8,0xfc,0xff,0xfd,0xf0,0xd1,0xdd,0xfc,0xfe,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xfb,0xfa,0xfd,0xff,0xff,0xdb,0x7d,0x81,0xa5,0xfb,0xe2,0x97,0x96,0xd5,0xfe,0xc9,0xa7,0xa4,0xdc,0xff,0xff,0xfe,0xfd,0xfd,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf9,0x94,0x82,0x84,0xe6,0xff,0xe3,0x97,0x95,0xd7,0xff,0xf4,0xad,0xa9,0xae,0xf9,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc9,0x79,0x7e,0xb7,0xfd,0xff,0xe3,0x97,0x95,0xd7,0xff,0xfe,0xd7,0xa4,0xa2,0xcf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd0,0x78,0x91,0xf2,0xff,0xff,0xe3,0x97,0x96,0xd5,0xff,0xff,0xf9,0xb8,0xa1,0xd8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf9,0xdb,0xe8,0xfd,0xff,0xff,0xe3,0x8f,0x8e,0xd8,0xff,0xff,0xfe,0xf3,0xe6,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xf5,0xb4,0xad,0xf1,0xff,0xff,0xfe,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xf9,0xf8,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xe9,0xe6,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xfd,0xff,0xff,0xff,0xf5,0xd9,0xd8,0xf0,0xff,0xff,0xff,0xfe,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf5,0xdb,0xe4,0xfd,0xff,0xff,0xf4,0xdc,0xdb,0xf0,0xff,0xff,0xfe,0xe4,0xd6,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xec,0xd9,0xda,0xf0,0xff,0xff,0xf4,0xdc,0xdb,0xf1,0xff,0xff,0xf1,0xd5,0xd6,0xe6,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf9,0xdf,0xde,0xde,0xfc,0xff,0xf4,0xdc,0xdb,0xf1,0xff,0xfd,0xdd,0xd8,0xd9,0xf6,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xee,0xdb,0xdc,0xea,0xfe,0xf4,0xdc,0xdb,0xf1,0xff,0xea,0xd7,0xd7,0xe8,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xcd,0xa5,0xf6,0xff,0xff,0xfc,0xe2,0xdc,0xdc,0xf7,0xf5,0xda,0xd9,0xf1,0xfa,0xda,0xd8,0xdd,0xfa,0xff,0xff,0xfd,0xeb,0xf2,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf2,0x3a,0x32,0x56,0xbe,0xfc,0xff,0xf5,0xdb,0xd9,0xe9,0xfc,0xe3,0xe2,0xfb,0xeb,0xd5,0xd6,0xee,0xff,0xfe,0xf3,0xd8,0xce,0xd0,0xf6,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf5,0x68,0x3d,0x44,0x3a,0x6b,0xdc,0xfe,0xea,0xe0,0xf4,0xfc,0xfc,0xfb,0xfd,0xf4,0xdc,0xe5,0xfc,0xf7,0xde,0xd0,0xd1,0xd0,0xd6,0xf9,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xee,0x9b,0x4f,0x43,0x42,0x38,0xa5,0xfd,0xfc,0xfc,0xfd,0xff,0xff,0xfd,0xfc,0xfb,0xfc,0xec,0xd0,0xd0,0xd2,0xd3,0xe1,0xf7,0xfd,0xfe,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xfa,0xdb,0x83,0x47,0x2f,0x64,0xfb,0xff,0xfe,0xff,0xff,0xff,0xff,0xfe,0xff,0xfd,0xd9,0xcd,0xd1,0xdc,0xf1,0xfd,0xfe,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0xcd,0x85,0xcd,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xf1,0xde,0xef,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xfa,0xda,0xd8,0xda,0xda,0xd8,0xdd,0xf6,0xfd,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfb,0xf0,0xf0,0xf0,0xf2,0xf1,0xf2,0xfd,0xff,0xff, + 0xff,0xfe,0x99,0x4e,0x5d,0x5e,0x5e,0x5f,0x50,0x9a,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xdb,0xc4,0xc9,0xc9,0xc8,0xc9,0xc3,0xdc,0xfe,0xff, + 0xff,0xfd,0x8d,0x51,0x61,0x60,0x60,0x61,0x50,0x8e,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xd8,0xc5,0xca,0xca,0xca,0xca,0xc5,0xd8,0xfe,0xff, + 0xff,0xfe,0xeb,0xb9,0xb7,0xb9,0xb8,0xb5,0xc0,0xf4,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfb,0xea,0xe6,0xe6,0xe7,0xe6,0xe6,0xf6,0xfe,0xff, + 0xff,0xfe,0xfe,0xfd,0xfc,0xfd,0xfd,0xfe,0xf2,0xc0,0xee,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf7,0xda,0xf3,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0xc2,0x7e,0x64,0x93,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xcc,0xb6,0xbe,0xdb,0xfb,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xd9,0x89,0x71,0x78,0x6f,0xa5,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xdc,0xbb,0xbf,0xbc,0xc2,0xe6,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfc,0xa6,0x6e,0x77,0x74,0x86,0xc0,0xf7,0xd3,0xab,0xef,0xff,0xff,0xff,0xff,0xf5,0xc4,0xd5,0xfb,0xe6,0xc8,0xbd,0xbf,0xba,0xcc,0xfc,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf1,0x70,0x70,0x7c,0xae,0xea,0xfd,0xf0,0x8a,0x7b,0xb8,0xfd,0xc6,0xc1,0xfb,0xd7,0xa4,0xaa,0xec,0xfe,0xf7,0xdc,0xc2,0xbb,0xb7,0xf5,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfa,0xc0,0xa1,0xdb,0xfa,0xfe,0xfd,0xac,0x8b,0x8c,0xde,0xee,0x98,0x95,0xdf,0xf2,0xb0,0xb0,0xbd,0xfc,0xff,0xfd,0xf2,0xd5,0xe1,0xfc,0xfe,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xfc,0xfb,0xfd,0xff,0xff,0xdd,0x88,0x8b,0xae,0xfb,0xe4,0xa0,0x9f,0xd8,0xfe,0xcd,0xae,0xad,0xdf,0xff,0xff,0xfe,0xfd,0xfd,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0x9e,0x8c,0x90,0xe7,0xff,0xe5,0xa0,0x9e,0xda,0xff,0xf4,0xb4,0xb0,0xb5,0xf9,0xff,0xff,0xfe,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xcd,0x85,0x88,0xbe,0xfd,0xff,0xe5,0xa0,0x9e,0xda,0xff,0xfe,0xda,0xac,0xaa,0xd4,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd3,0x84,0x9b,0xf3,0xff,0xff,0xe5,0xa0,0x9e,0xd9,0xff,0xff,0xfa,0xbf,0xa8,0xdc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf9,0xde,0xea,0xfd,0xff,0xff,0xe4,0x9a,0x96,0xda,0xff,0xff,0xfe,0xf3,0xe9,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfe,0xfe,0xff,0xff,0xf6,0xba,0xb4,0xf2,0xff,0xff,0xfe,0xfe,0xfe,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,0xf8,0xf9,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xeb,0xe8,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf4,0xfa,0xff,0xff,0xff,0xf6,0xda,0xd9,0xf2,0xff,0xff,0xff,0xfe,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xcc,0x2d,0x62,0xf9,0xff,0xff,0xf4,0xde,0xdc,0xf2,0xff,0xff,0xfe,0xe5,0xd8,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x9c,0x25,0x27,0xa9,0xff,0xff,0xf4,0xdd,0xdc,0xf2,0xff,0xff,0xf2,0xd8,0xd8,0xe7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe9,0x49,0x37,0x3f,0xf1,0xff,0xf4,0xdd,0xdc,0xf2,0xff,0xfd,0xde,0xdb,0xdc,0xf6,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xa8,0x30,0x2f,0x86,0xff,0xf5,0xdd,0xdd,0xf0,0xff,0xeb,0xd9,0xd9,0xe9,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xd1,0xac,0xf6,0xff,0xff,0xf4,0x5c,0x36,0x35,0xd9,0xfc,0xda,0xda,0xf1,0xfa,0xdd,0xda,0xdd,0xfa,0xff,0xff,0xfd,0xec,0xf3,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf2,0x47,0x41,0x61,0xc3,0xfd,0xff,0xc6,0x2f,0x1e,0x85,0xfe,0xe4,0xe2,0xfc,0xea,0xd7,0xd9,0xf0,0xfe,0xfe,0xf2,0xdb,0xd1,0xd2,0xf8,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf6,0x74,0x49,0x52,0x48,0x76,0xe1,0xf9,0x8d,0x50,0xc8,0xfe,0xfc,0xfb,0xfd,0xf4,0xdd,0xe6,0xfc,0xf8,0xe0,0xd4,0xd5,0xd3,0xd8,0xf9,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xf1,0xa2,0x5b,0x51,0x50,0x46,0xae,0xf8,0xf1,0xfb,0xfe,0xff,0xff,0xfd,0xfc,0xfb,0xfc,0xed,0xd4,0xd5,0xd5,0xd6,0xe3,0xf7,0xfd,0xfe,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xfa,0xdd,0x8a,0x54,0x3d,0x6f,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xfd,0xdd,0xd0,0xd4,0xde,0xf2,0xfd,0xfe,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0xd0,0x8e,0xd1,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xf2,0xe0,0xf1,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xfb,0xdd,0xdb,0xdd,0xdc,0xda,0xdf,0xf7,0xfd,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfb,0xf1,0xf0,0xf1,0xf2,0xf2,0xf2,0xfd,0xfe,0xff, + 0xff,0xfe,0xa2,0x5d,0x6c,0x6b,0x6b,0x6c,0x5f,0xa3,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xdd,0xc8,0xcd,0xce,0xcd,0xcd,0xc9,0xde,0xfe,0xff, + 0xff,0xfd,0x98,0x5f,0x6d,0x6d,0x6d,0x6d,0x5f,0x97,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xdb,0xc9,0xce,0xce,0xce,0xce,0xc9,0xdb,0xfe,0xff, + 0xff,0xfe,0xea,0xc0,0xbc,0xbf,0xbe,0xbd,0xc5,0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfb,0xec,0xe8,0xe8,0xe9,0xe6,0xe8,0xf7,0xfe,0xff, + 0xff,0xfe,0xfe,0xfd,0xfd,0xfd,0xfe,0xfe,0xf3,0xc7,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0xde,0xf3,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0xc6,0x88,0x72,0x9b,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xd1,0xbb,0xc4,0xde,0xfb,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xdb,0x93,0x7c,0x83,0x7b,0xad,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xdd,0xc0,0xc4,0xc1,0xc8,0xe7,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfc,0xac,0x7b,0x82,0x80,0x8e,0xc5,0xf7,0xd7,0xb2,0xf0,0xff,0xff,0xff,0xff,0xf6,0xca,0xda,0xfb,0xe9,0xcc,0xc3,0xc4,0xc0,0xd0,0xfc,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf1,0x7a,0x7a,0x87,0xb4,0xed,0xfd,0xf1,0x92,0x85,0xbe,0xfd,0xcb,0xc6,0xfc,0xda,0xad,0xb2,0xed,0xfe,0xf9,0xdf,0xc8,0xc0,0xbf,0xf5,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfb,0xc4,0xa8,0xde,0xfa,0xfe,0xfe,0xb3,0x96,0x96,0xe0,0xee,0xa1,0x9e,0xe2,0xf3,0xb8,0xb7,0xc2,0xfc,0xff,0xfd,0xf3,0xd9,0xe3,0xfb,0xfe,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xfc,0xfb,0xfd,0xff,0xff,0xe0,0x93,0x95,0xb4,0xfb,0xe6,0xaa,0xa7,0xdb,0xfe,0xd2,0xb7,0xb4,0xe1,0xff,0xff,0xfd,0xfd,0xfc,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0xa6,0x97,0x9a,0xea,0xff,0xe8,0xa8,0xa7,0xdc,0xff,0xf6,0xbc,0xb7,0xbb,0xfa,0xff,0xff,0xfe,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd1,0x8f,0x92,0xc3,0xfd,0xff,0xe7,0xa8,0xa7,0xde,0xff,0xfe,0xde,0xb5,0xb2,0xd8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd7,0x8e,0xa3,0xf5,0xff,0xff,0xe7,0xa9,0xa7,0xde,0xff,0xff,0xfa,0xc4,0xb1,0xdf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf9,0xe1,0xec,0xfd,0xff,0xff,0xe8,0xa1,0xa1,0xdd,0xff,0xff,0xfe,0xf4,0xeb,0xfa,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xf7,0xbf,0xbb,0xf3,0xff,0xff,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xfb,0xf9,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xeb,0xe8,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf5,0xfa,0xff,0xff,0xff,0xf6,0xda,0xd9,0xf2,0xff,0xff,0xff,0xfe,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd0,0x3c,0x6e,0xfa,0xff,0xff,0xf4,0xde,0xdc,0xf2,0xff,0xff,0xfe,0xe6,0xda,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa4,0x35,0x37,0xb0,0xff,0xff,0xf4,0xdd,0xdc,0xf2,0xff,0xff,0xf2,0xd9,0xd9,0xe8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xec,0x55,0x46,0x4e,0xf2,0xff,0xf4,0xdd,0xdc,0xf2,0xff,0xfd,0xe0,0xdc,0xdd,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xaf,0x3f,0x3e,0x8f,0xff,0xf5,0xdd,0xdd,0xf0,0xff,0xec,0xda,0xda,0xea,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xd3,0xb1,0xf7,0xff,0xff,0xf4,0x67,0x45,0x42,0xdb,0xfb,0xdb,0xda,0xf1,0xfb,0xde,0xdb,0xdf,0xfb,0xff,0xff,0xfd,0xed,0xf4,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf4,0x56,0x4f,0x6c,0xc8,0xfd,0xff,0xcb,0x3d,0x2d,0x8d,0xfe,0xe4,0xe2,0xfc,0xeb,0xd8,0xdb,0xf0,0xfe,0xfe,0xf4,0xdd,0xd6,0xd5,0xf7,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf6,0x7e,0x59,0x5f,0x55,0x80,0xe3,0xf9,0x96,0x5c,0xcc,0xfe,0xfc,0xfb,0xfc,0xf5,0xde,0xe7,0xfc,0xf7,0xe2,0xd7,0xd8,0xd7,0xdb,0xfa,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfd,0xf2,0xa9,0x67,0x5d,0x5e,0x53,0xb4,0xf8,0xf2,0xfb,0xfe,0xff,0xff,0xfd,0xfd,0xfb,0xfd,0xed,0xd7,0xd8,0xd8,0xda,0xe5,0xf8,0xfe,0xfe,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xfa,0xdf,0x94,0x61,0x4d,0x79,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xfd,0xdf,0xd4,0xd8,0xe0,0xf4,0xfd,0xfe,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0xd3,0x96,0xd3,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xf3,0xe3,0xf0,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xfb,0xe1,0xde,0xe0,0xe0,0xde,0xe3,0xf7,0xfd,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfc,0xfb,0xf2,0xf1,0xf3,0xf3,0xf3,0xf3,0xfd,0xfe,0xff, + 0xff,0xfe,0xa7,0x6a,0x76,0x76,0x76,0x77,0x6a,0xaa,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe1,0xcd,0xd2,0xd1,0xd1,0xd1,0xce,0xe1,0xfe,0xff, + 0xff,0xfd,0x9e,0x6c,0x78,0x77,0x77,0x78,0x6c,0x9f,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xdf,0xcd,0xd2,0xd2,0xd2,0xd2,0xcd,0xdf,0xfe,0xff, + 0xff,0xfe,0xed,0xc3,0xc2,0xc2,0xc2,0xc1,0xc9,0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xee,0xea,0xea,0xea,0xea,0xea,0xf8,0xfe,0xff, + 0xff,0xfe,0xfe,0xfd,0xfd,0xfd,0xfe,0xfe,0xf4,0xcb,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf7,0xe0,0xf5,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xcb,0x92,0x7d,0xa3,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xd6,0xc2,0xc8,0xe1,0xfc,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xfe,0xde,0x9c,0x87,0x8e,0x86,0xb4,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xe1,0xc7,0xc9,0xc7,0xcc,0xe9,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfc,0xb4,0x86,0x8c,0x8a,0x98,0xca,0xf8,0xd9,0xb8,0xf1,0xff,0xff,0xff,0xff,0xf8,0xcf,0xdb,0xfb,0xeb,0xd1,0xc8,0xca,0xc5,0xd5,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xf3,0x86,0x86,0x91,0xbc,0xed,0xfd,0xf2,0x9c,0x91,0xc4,0xfd,0xd1,0xcb,0xfc,0xdd,0xb5,0xb8,0xed,0xfe,0xf8,0xe3,0xcc,0xc7,0xc3,0xf6,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfb,0xc9,0xb1,0xe0,0xfb,0xfe,0xfe,0xba,0x9e,0xa0,0xe1,0xf0,0xaa,0xa6,0xe5,0xf3,0xbf,0xbe,0xca,0xfd,0xff,0xfd,0xf3,0xdc,0xe4,0xfd,0xfe,0xff,0xff, + 0xff,0xff,0xff,0xfc,0xfc,0xfb,0xfd,0xff,0xff,0xe2,0x9c,0x9e,0xbb,0xfb,0xe8,0xb0,0xaf,0xde,0xfd,0xd7,0xbd,0xbb,0xe4,0xff,0xff,0xfd,0xfd,0xfd,0xfd,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0xae,0x9f,0xa2,0xeb,0xff,0xe9,0xb0,0xae,0xdf,0xff,0xf6,0xc1,0xbf,0xc2,0xfa,0xff,0xff,0xfe,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd4,0x99,0x9d,0xc8,0xfd,0xff,0xe9,0xb0,0xae,0xdf,0xff,0xfe,0xdf,0xbb,0xb9,0xdb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdc,0x97,0xab,0xf5,0xff,0xff,0xe9,0xb0,0xae,0xdf,0xff,0xff,0xfa,0xca,0xb8,0xe1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf9,0xe3,0xed,0xfd,0xff,0xff,0xe8,0xaa,0xa9,0xe0,0xff,0xff,0xfe,0xf5,0xed,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfe,0xfe,0xff,0xff,0xf7,0xc5,0xc1,0xf4,0xff,0xff,0xfe,0xfe,0xfe,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,0xfa,0xfa,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff +}; diff --git a/pexpert/pexpert/i386/protos.h b/pexpert/pexpert/i386/protos.h index 355e023bf..09857c7db 100644 --- a/pexpert/pexpert/i386/protos.h +++ b/pexpert/pexpert/i386/protos.h @@ -67,8 +67,13 @@ extern void cninit(void); extern void bcopy(void * from, void * to, int size); extern int sprintf(char * str, const char * format, ...); +//------------------------------------------------------------------------ +// from osfmk/i386/AT386/video_console.c + extern boolean_t vc_progress_initialize( void * desc, - unsigned char * data, - unsigned char * clut ); + const unsigned char * data, + const unsigned char * clut ); + +extern void vc_display_icon( void * desc, const unsigned char * data ); #endif /* _PEXPERT_I386_PROTOS_H */ diff --git a/pexpert/pexpert/pe_images.h b/pexpert/pexpert/pe_images.h index d19ed3f27..8fdab2dea 100644 --- a/pexpert/pexpert/pe_images.h +++ b/pexpert/pexpert/pe_images.h @@ -20,188 +20,8 @@ * @APPLE_LICENSE_HEADER_END@ */ -static unsigned char default_progress_data[16 * 16 * 3] = { +#include -#if 1 -// grey -#define TRANSPARENT 0xfa - 0xfa,0xfa,0xfa,0xfa,0x81,0xf8,0x2c,0x33,0x57,0x51,0xf9,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0x81,0xf8,0x33,0x3a,0x58,0x59,0x7d,0x58,0x7c,0x58,0x7b,0xfb,0xfa,0xfa, - 0xfa,0x81,0x2b,0x33,0x3a,0x34,0x5f,0x5e,0x59,0x7d,0x58,0x76,0x51,0x7b,0x81,0xfa, - 0xfa,0xf8,0x0f,0x39,0x33,0x3a,0x58,0x59,0x7d,0x58,0x76,0x51,0x75,0x75,0xfc,0xfa, - 0x81,0x0e,0x15,0x0f,0x15,0x34,0x3a,0x59,0x58,0x7c,0x52,0x75,0x51,0x6f,0x51,0xfb, - 0xf8,0x14,0x39,0x14,0x33,0x39,0x34,0x5d,0x58,0x52,0x75,0x6f,0x6f,0x4a,0x6f,0xfc, - 0x31,0x39,0x14,0x39,0x14,0x14,0xf9,0xfb,0xfa,0xfa,0x4b,0x4b,0x74,0x99,0x74,0xa6, - 0x32,0x3e,0x5d,0x3e,0x39,0x39,0x81,0xfa,0xfa,0xf9,0x9f,0x74,0x99,0x74,0x99,0xa5, - 0x38,0x3f,0x3e,0x63,0x3e,0x62,0xfa,0xfa,0x56,0xf8,0x9f,0x99,0x9e,0x99,0x98,0xa6, - 0xf8,0x68,0x63,0x68,0x68,0x69,0x80,0xf9,0x56,0xa5,0xc2,0xc2,0xc3,0x9e,0x9f,0xfc, - 0xf9,0x63,0x68,0x8d,0x68,0x86,0x61,0x7f,0x7f,0x9d,0xa4,0x9e,0xc2,0xc3,0xc2,0xfd, - 0xfb,0x62,0x8c,0x68,0x86,0x86,0x85,0x7e,0x78,0x7f,0x9d,0xa4,0xc3,0xc8,0xc9,0xfb, - 0xfa,0x81,0x68,0x86,0x62,0x61,0x5b,0x7e,0x5b,0x9d,0xa3,0x9e,0xa4,0xa4,0xfd,0xfb, - 0xfa,0xfa,0x81,0x86,0x85,0x61,0x7f,0x7e,0x78,0x7f,0x79,0xa3,0x9e,0xd0,0x81,0xfa, - 0xfa,0xfa,0xfa,0xfb,0x86,0x7f,0x5b,0x7e,0x5a,0x79,0x7f,0xa4,0xfd,0xfb,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfc,0xfc,0xab,0x80,0xa4,0xab,0xd0,0xfc,0xfa,0xfa,0xfa,0xfa, - - 0xfa,0xfa,0xfa,0xfa,0x81,0x2b,0x07,0x2c,0x2c,0x2c,0x56,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0x81,0x2b,0x08,0x09,0x09,0x2d,0x2e,0x52,0x58,0x7b,0xfa,0x81,0xfa,0xfa, - 0xfa,0x81,0x07,0x33,0x33,0x09,0x09,0x2e,0x2d,0x52,0x7c,0x7d,0xa1,0xfb,0x81,0xfa, - 0xfa,0xf6,0x3a,0x3a,0x33,0x0f,0x2c,0x09,0x2e,0x58,0x7c,0xa1,0xe5,0xa0,0xfc,0xfa, - 0xfa,0x39,0x64,0x3a,0x3a,0x33,0x09,0x09,0x52,0x7c,0x7d,0xa1,0xa1,0xa0,0xa0,0xfc, - 0x2b,0x64,0x6a,0x64,0x64,0x3a,0x33,0x2c,0x2d,0x7d,0xe5,0xa0,0x9a,0x9a,0x99,0xac, - 0x32,0xdb,0x6a,0x6a,0x6a,0x40,0x5d,0xfb,0xfa,0xfa,0xa0,0x9a,0x9f,0x99,0x75,0xa6, - 0x56,0x69,0x69,0x6a,0x64,0x6a,0x81,0xfa,0xfa,0xf9,0x9f,0x74,0x74,0x74,0x74,0x9f, - 0x38,0x63,0x63,0x63,0x69,0x62,0xfa,0xfa,0x56,0xf8,0x74,0x6e,0x6d,0x6e,0x6d,0xfb, - 0xf8,0x3e,0x62,0x3e,0x37,0x37,0x5b,0xf9,0x56,0x80,0x73,0x73,0x6d,0x4f,0x6d,0xa5, - 0xf9,0x3e,0x3d,0x3d,0x37,0x36,0x5a,0x86,0xaa,0xc8,0x9d,0x97,0x97,0x6d,0x73,0xfd, - 0x81,0x5b,0x37,0x36,0x36,0x36,0x5b,0x85,0xce,0xce,0xa4,0x9e,0x9d,0x73,0x9e,0xfc, - 0xfa,0xfa,0x37,0x30,0x36,0x5b,0x5b,0xa9,0xaa,0xce,0xa4,0xa4,0x9d,0x9e,0xac,0xfa, - 0xfa,0xfa,0xfa,0x36,0x54,0x5b,0x7f,0xa9,0xaa,0xce,0xce,0xa4,0xa4,0xfc,0xfc,0xfa, - 0xfa,0xfa,0xfa,0xfb,0x5c,0x85,0x85,0xaa,0xaa,0xce,0xce,0xc9,0xf3,0xfb,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfc,0xac,0xab,0xab,0xcf,0xf2,0xfe,0xfc,0xfa,0xfa,0xfa,0xfa, - - 0xfa,0xfa,0xfa,0xfa,0x81,0x56,0x2c,0x2c,0x08,0x2c,0xf9,0x81,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0x81,0x56,0x33,0x5e,0x34,0x2d,0x2e,0x27,0x27,0x50,0x81,0x81,0xfa,0xfa, - 0xfa,0x81,0xf7,0x65,0x65,0x5e,0x34,0x2e,0x2d,0x27,0x27,0x51,0x52,0x81,0xfb,0xfa, - 0xfa,0x56,0x64,0x65,0x65,0x5e,0x58,0x34,0x2d,0x2c,0x4b,0x51,0x76,0x76,0xfc,0xfa, - 0xfa,0x39,0x64,0x65,0x65,0x65,0x5e,0x34,0x27,0x27,0x51,0x76,0x9a,0xa0,0xa0,0xfb, - 0x56,0x3f,0x64,0x63,0x64,0x65,0x5f,0x57,0x2d,0x51,0x76,0x9a,0xa0,0xa0,0xc4,0xac, - 0xf7,0x39,0x39,0x40,0x3f,0x64,0x5d,0xfb,0xfa,0x57,0xa0,0xa0,0xa0,0xc4,0xc4,0xfd, - 0xf7,0x1a,0x38,0x38,0x38,0x38,0x81,0xfa,0xfa,0xf9,0xa0,0xc4,0xc4,0xc4,0xc4,0xca, - 0x31,0x13,0x14,0x13,0x13,0x14,0xfa,0xfa,0x56,0x56,0x9f,0x9e,0x9f,0x9f,0x9f,0xca, - 0xf8,0x13,0x0d,0x37,0x37,0x3d,0x80,0xf9,0x56,0x7a,0x73,0x97,0x98,0x98,0x9e,0xfc, - 0x81,0x37,0x3d,0x37,0x3d,0x62,0x8c,0xb0,0xa3,0x79,0x72,0x73,0x73,0x97,0x98,0xfd, - 0x81,0x37,0x37,0x61,0x62,0x86,0xb0,0xaa,0xa3,0x79,0x72,0x72,0x73,0x73,0x9e,0xfc, - 0xfa,0x81,0x61,0x62,0x85,0x8c,0xb0,0xaa,0xaa,0x7f,0x79,0x72,0x72,0x73,0xac,0xfa, - 0xfa,0xfa,0x81,0x86,0x86,0xb0,0xf0,0xaa,0xa9,0xa3,0x79,0x78,0x73,0xac,0xfb,0xfa, - 0xfa,0xfa,0xfa,0xfc,0x87,0xb1,0xb0,0xaa,0xa9,0xa3,0x7f,0xa4,0xac,0x81,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfc,0xfc,0xd0,0xab,0xf1,0xac,0xfd,0xfc,0xfa,0xfa,0xfa,0xfa, -#endif - -#if 0 -// blue -#define TRANSPARENT 0x80 - 0x80,0x80,0x80,0x80,0x81,0xf8,0x2c,0x33,0x57,0x51,0xf9,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0xf8,0x33,0x3a,0x58,0x59,0x7d,0x58,0x7c,0x58,0xfa,0xa5,0x80,0x80, - 0x80,0x81,0xf7,0x33,0x3a,0x34,0x5f,0x5e,0x59,0x7d,0x58,0x76,0x51,0x81,0xfb,0x80, - 0x80,0xf8,0x0f,0x39,0x33,0x3a,0x58,0x59,0x7d,0x58,0x76,0x51,0x75,0x6f,0xfb,0x80, - 0x81,0x0e,0x14,0x0f,0x15,0x34,0x3a,0x59,0x58,0x7c,0x52,0x75,0x51,0x6f,0x75,0xfb, - 0xf8,0x14,0x39,0x14,0x33,0x39,0x34,0x5d,0x58,0x52,0x75,0x6f,0x6f,0x4a,0x74,0xfc, - 0x31,0x39,0x14,0x39,0x14,0x14,0xf9,0xfb,0xfa,0xfa,0x4b,0x4b,0x74,0x99,0x74,0xa6, - 0x32,0x3e,0x5d,0x3e,0x39,0x39,0x81,0xfa,0xfa,0xf9,0x99,0x74,0x99,0x74,0x99,0xa5, - 0x38,0x3f,0x3e,0x63,0x3e,0x62,0xfa,0xfa,0x56,0xf8,0x9f,0x9f,0x98,0x99,0x98,0xa6, - 0xf8,0x68,0x63,0x68,0x69,0x68,0xfa,0xf9,0x56,0xa5,0xc2,0xc2,0xc3,0x9e,0x9f,0xfc, - 0xf9,0x63,0x68,0x8c,0x68,0x8c,0x61,0x7f,0x7f,0x9d,0xa4,0xc8,0x9e,0xc3,0xc2,0xd0, - 0xab,0x62,0x8c,0x68,0x86,0x85,0x7f,0x7e,0x78,0x7f,0x9d,0xa4,0xc3,0xc8,0xc9,0xfb, - 0x80,0x81,0x68,0x86,0x62,0x86,0x5b,0x5a,0x7f,0x79,0xa3,0x9e,0xa4,0xc8,0xac,0xab, - 0x80,0x80,0x81,0x86,0x85,0x61,0x7f,0x7e,0x78,0x7f,0x9d,0xa3,0x9e,0xd0,0xfb,0x80, - 0x80,0x80,0x80,0xfb,0x62,0x7f,0x5b,0x7e,0x5a,0x79,0x7f,0xa4,0xfd,0xfb,0x80,0x80, - 0x80,0x80,0x80,0x80,0xab,0xac,0xab,0x80,0xa4,0xab,0xac,0xab,0x80,0x80,0x80,0x80, - - 0x80,0x80,0x80,0x80,0x81,0x2b,0x07,0x2c,0x2c,0x2c,0x56,0xfa,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x2b,0x08,0x09,0x09,0x2d,0x2e,0x52,0x7c,0x7b,0xfa,0x81,0x80,0x80, - 0x80,0x81,0x07,0x33,0x33,0x09,0x09,0x2d,0x2d,0x52,0x7c,0x7d,0xa1,0xa5,0xfb,0x80, - 0x80,0x2b,0x3a,0x3a,0x33,0x0f,0x2d,0x09,0x2e,0x58,0x7c,0xa1,0xa1,0xa0,0xfb,0x80, - 0xfa,0x38,0x64,0x3a,0x3a,0x33,0x09,0x09,0x52,0x7c,0x7d,0xa1,0xa1,0xa0,0xa0,0xfc, - 0x2b,0x64,0x6a,0x64,0x64,0x3a,0x33,0x2c,0x2d,0x7d,0xe5,0xa0,0xa0,0x9a,0x9f,0xac, - 0x32,0xdb,0x6a,0x6a,0x6a,0x40,0x5d,0xfb,0xfa,0xfa,0xa0,0x9a,0x99,0x99,0x75,0xa6, - 0x56,0x69,0x69,0x6a,0x64,0x6a,0x81,0xfa,0xfa,0xf9,0x9f,0x74,0x74,0x74,0x74,0x9f, - 0x38,0x63,0x63,0x63,0x69,0x62,0xfa,0xfa,0x56,0xf8,0x74,0x6e,0x6d,0x6e,0x6d,0x9f, - 0xf8,0x3e,0x62,0x3e,0x37,0x37,0x5b,0xf9,0x56,0x80,0x73,0x73,0x6d,0x4f,0x6d,0xfb, - 0xf9,0x3e,0x3d,0x3d,0x37,0x36,0x5a,0x86,0xaa,0xc8,0x9d,0x97,0x97,0x6d,0x73,0xfd, - 0x81,0x5b,0x37,0x36,0x36,0x36,0x5b,0x85,0xce,0xce,0xa4,0x9e,0x9d,0x73,0x9e,0xab, - 0x80,0xfa,0x37,0x30,0x36,0x5b,0x5b,0xa9,0xaa,0xce,0xa4,0xa4,0x9d,0x9e,0xac,0x80, - 0x80,0x80,0xfa,0x36,0x54,0x5b,0x7f,0xa9,0xaa,0xce,0xce,0xa4,0xa4,0xfc,0xab,0x80, - 0x80,0x80,0x80,0x87,0x5c,0x85,0x85,0xaa,0xaa,0xce,0xce,0xcf,0xfd,0xab,0x80,0x80, - 0x80,0x80,0x80,0x80,0xab,0xac,0xab,0xab,0xcf,0xf2,0xfd,0xfc,0x80,0x80,0x80,0x80, - - 0x80,0x80,0x80,0x80,0x81,0x56,0x2c,0x2c,0x2c,0x2c,0xf9,0xa4,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x56,0x57,0x5e,0x34,0x2d,0x2e,0x27,0x27,0x50,0xfa,0xfb,0x80,0x80, - 0x80,0x81,0xf7,0x65,0x65,0x5e,0x34,0x2e,0x2d,0x2d,0x26,0x52,0x51,0x81,0xfb,0x80, - 0x80,0x56,0x64,0x65,0x65,0x5e,0x58,0x34,0x2d,0x27,0x4b,0x51,0x76,0x9a,0xfb,0x80, - 0x80,0x39,0x64,0x65,0x65,0x65,0x5e,0x34,0x27,0x27,0x51,0x76,0x76,0xa0,0xa0,0xab, - 0x56,0x3f,0x64,0x63,0x64,0x65,0x5f,0x33,0x2d,0x51,0x76,0x99,0xa0,0xc4,0xc4,0xfc, - 0xf7,0x39,0x39,0x40,0x3f,0x64,0x5d,0xfb,0xfa,0x57,0xa0,0xa1,0xc4,0xa0,0xc4,0xd0, - 0xf7,0x1a,0x38,0x38,0x38,0x38,0x81,0x81,0xfa,0xf9,0xa0,0xc3,0xc4,0xc4,0xc4,0xca, - 0x31,0x13,0x14,0x13,0x13,0x14,0xfa,0xfa,0x56,0x56,0x9f,0x9f,0x9f,0x9f,0x9f,0xd0, - 0xf8,0x13,0x0d,0x37,0x37,0x3d,0x80,0xf9,0x56,0x7a,0x73,0x97,0x98,0x98,0x98,0xfc, - 0x81,0x37,0x3d,0x37,0x3d,0x62,0x8c,0xaa,0xa3,0x79,0x72,0x73,0x73,0x97,0x9e,0xac, - 0x80,0x37,0x37,0x61,0x62,0x86,0xb0,0xaa,0xa9,0x79,0x72,0x72,0x73,0x73,0x9e,0xfc, - 0x80,0xfb,0x61,0x62,0x85,0x8c,0xb0,0xaa,0xaa,0x7f,0x79,0x72,0x72,0x73,0xfd,0x80, - 0x80,0x80,0x81,0x86,0x86,0xb0,0xf0,0xaa,0xa9,0xa3,0x79,0x78,0x73,0xab,0xfb,0x80, - 0x80,0x80,0x80,0xab,0x87,0xb1,0xb0,0xaa,0xa9,0xa3,0x7f,0xa4,0xac,0xab,0x80,0x80, - 0x80,0x80,0x80,0x80,0xab,0xfc,0xd0,0xab,0xf1,0xac,0xd0,0xfc,0x80,0x80,0x80,0x80, -#endif - -#if 0 -// panel - 0xf9,0xf9,0x56,0xf9,0xfa,0x2c,0x32,0x2d,0x57,0x51,0x56,0x56,0x56,0xf9,0xf9,0x56, - 0x56,0xfa,0x56,0x56,0x2c,0x5e,0x58,0x5f,0x58,0x7d,0x52,0x57,0x56,0x56,0xf9,0xf9, - 0xf9,0x56,0xf9,0x33,0x3a,0x34,0x5f,0x59,0x83,0x52,0x7c,0x76,0x76,0x7b,0x5d,0x56, - 0xf9,0x56,0x0f,0x39,0x33,0x3a,0x34,0x59,0x58,0x58,0x52,0x76,0x4b,0x75,0x7b,0x56, - 0xf9,0x0e,0x15,0x0f,0x39,0x34,0x5e,0x59,0x83,0x7c,0x7c,0x4b,0x75,0x6f,0x7b,0x56, - 0x56,0x39,0x0e,0x14,0x0e,0x39,0x33,0x57,0x57,0x7c,0x4b,0x6f,0x4a,0x75,0x6e,0xa6, - 0x32,0x38,0x3f,0x39,0x39,0x0e,0x5d,0x81,0x81,0x57,0x75,0x6f,0x75,0x6e,0x75,0xa6, - 0x31,0x3e,0x38,0x3e,0x38,0x38,0x7b,0x81,0x56,0x56,0x75,0x74,0x6e,0x74,0x74,0xa5, - 0x38,0x3f,0x63,0x63,0x69,0x62,0x81,0x7b,0x56,0x56,0xa5,0x99,0x9f,0x99,0x9f,0xa6, - 0x31,0x69,0x62,0x68,0x62,0x8d,0x5c,0x5c,0x56,0xa5,0xc2,0xc2,0x98,0xc3,0x98,0xac, - 0x5c,0x62,0x69,0x68,0x8c,0x62,0x86,0x7f,0x7f,0x79,0xa4,0xc2,0xc9,0x9e,0xc9,0xac, - 0x56,0x62,0x62,0x8c,0x62,0x85,0x5b,0x7e,0x78,0x7f,0x9d,0xc8,0x9e,0xc8,0xc9,0x81, - 0xf9,0x81,0x8c,0x62,0x8c,0x85,0x85,0x7e,0x7f,0x79,0xa3,0x9d,0xa4,0xc8,0xac,0x56, - 0xf9,0xf9,0x80,0x86,0x5b,0x85,0x5a,0x7e,0x54,0x7f,0x79,0xa3,0x9d,0xd0,0x56,0xf9, - 0xf9,0xf9,0x56,0x81,0x86,0x5b,0x85,0x7e,0x7e,0x78,0xa3,0xa4,0xac,0x56,0xfa,0xf9, - 0xf9,0x56,0xf9,0xf9,0x56,0xab,0xa5,0x80,0x80,0xab,0xac,0x81,0x56,0xf9,0x56,0xf9, - - 0xf9,0xf9,0x56,0xf9,0xfa,0xf9,0x2c,0x2c,0x2d,0x2c,0x56,0x56,0x56,0xf9,0xf9,0x56, - 0x56,0xfa,0x56,0x56,0x08,0x09,0x09,0x2d,0x2d,0x58,0x52,0x7b,0x56,0x56,0xf9,0xf9, - 0xf9,0x56,0x07,0x33,0x33,0x09,0x09,0x2d,0x2e,0x52,0x7d,0x7d,0xa7,0x7b,0x5d,0x56, - 0xf9,0x56,0x39,0x3a,0x33,0x0f,0x08,0x09,0x2d,0x58,0x76,0xa7,0xa1,0xa0,0x81,0x56, - 0xf9,0x39,0x64,0x3a,0x3a,0x33,0x0f,0x09,0x58,0x7c,0xa7,0xa1,0xa1,0xa0,0xa6,0x7b, - 0x56,0x6a,0x64,0x64,0x3a,0x3a,0x0f,0x2c,0x2d,0x7d,0xa1,0xa0,0x9a,0xa0,0x99,0xac, - 0x32,0x64,0x6a,0x6a,0x6a,0x40,0x5d,0x81,0x81,0x7b,0xa1,0x9a,0xa0,0x75,0x9f,0xa6, - 0x32,0x69,0x63,0x6a,0x64,0x6a,0x7b,0x81,0x56,0x56,0x75,0x74,0x6e,0x74,0x6e,0x9f, - 0x5c,0x63,0x69,0x63,0x69,0x62,0x81,0x7b,0x56,0x56,0x74,0x6d,0x74,0x6e,0x74,0x9f, - 0x31,0x62,0x3e,0x3e,0x37,0x3d,0x55,0x5c,0x50,0xa5,0x73,0x73,0x6d,0x73,0x49,0xa5, - 0x5c,0x37,0x3e,0x37,0x3d,0x30,0x5b,0x85,0xd4,0xa4,0xa4,0x97,0x97,0x6d,0x73,0xac, - 0x56,0x37,0x36,0x37,0x30,0x36,0x5a,0x85,0xaa,0xce,0x9d,0x9e,0x73,0x73,0x74,0x81, - 0xf9,0x81,0x37,0x30,0x36,0x5b,0x85,0xa9,0xd4,0xce,0xce,0x9e,0xa4,0x9e,0xac,0x56, - 0xf9,0xf9,0x5c,0x36,0x30,0x61,0x7f,0xa9,0xa9,0xce,0xc8,0xa4,0x9e,0xd0,0x56,0xf9, - 0xf9,0xf9,0x56,0x81,0x86,0x5b,0x85,0xaa,0xd4,0xaa,0xcf,0xcf,0xd6,0x56,0xfa,0xf9, - 0xf9,0x56,0xf9,0xf9,0x7b,0xac,0xab,0xab,0xab,0xd0,0xac,0x81,0x56,0xf9,0x56,0xf9, - - 0xf9,0xf9,0x56,0xf9,0xfa,0x2c,0x2c,0x2c,0x2c,0x2c,0x56,0x56,0x56,0xf9,0xf9,0x56, - 0x56,0xfa,0x56,0x56,0x33,0x5e,0x34,0x2d,0x27,0x2d,0x26,0x50,0x56,0x56,0xf9,0xf9, - 0xf9,0x56,0x32,0x65,0x65,0x58,0x5e,0x2e,0x2d,0x27,0x2d,0x51,0x76,0x7b,0x5d,0x56, - 0xf9,0x56,0x5e,0x65,0x5f,0x5e,0x34,0x34,0x27,0x27,0x27,0x76,0x75,0x76,0x81,0x56, - 0x56,0x39,0x6a,0x64,0x6b,0x65,0x5f,0x34,0x2d,0x27,0x51,0x75,0xa0,0xa0,0xa6,0x56, - 0xf9,0x64,0x39,0x64,0x64,0x65,0x5e,0x33,0x26,0x51,0x75,0x9a,0x9a,0xc4,0xa0,0xac, - 0x32,0x39,0x3f,0x3f,0x64,0x40,0x5d,0x81,0x81,0x57,0xa0,0xa0,0xca,0xa0,0xca,0xa6, - 0xf7,0x38,0x14,0x38,0x38,0x38,0x7b,0x81,0x56,0x56,0xa0,0xc4,0xc3,0xc4,0x9f,0xca, - 0x32,0x13,0x14,0x13,0x13,0x13,0x81,0x7b,0x56,0x56,0x9f,0x9f,0x9f,0x9f,0xc3,0xca, - 0xf7,0x13,0x0d,0x13,0x13,0x3d,0x5c,0x5c,0x50,0x80,0x6d,0x97,0x98,0x9e,0x98,0xac, - 0x81,0x13,0x3d,0x37,0x61,0x61,0x8c,0xaa,0xaa,0x72,0x73,0x73,0x97,0x73,0x9e,0xac, - 0x56,0x37,0x37,0x61,0x61,0x86,0xaa,0xaa,0xa3,0x79,0x72,0x72,0x6c,0x73,0x9e,0x81, - 0xf9,0x5d,0x62,0x61,0x8c,0x8c,0xb1,0xaa,0xaa,0x7f,0x79,0x4e,0x73,0x73,0xac,0x56, - 0xf9,0xf9,0x80,0x86,0x86,0xb0,0xaa,0xaa,0xa3,0xa3,0x78,0x78,0x72,0xac,0x56,0xf9, - 0xf9,0xf9,0x56,0x81,0xb1,0xaa,0xb0,0xaa,0xaa,0x7f,0xa3,0xa4,0xac,0x56,0xfa,0xf9, - 0xf9,0x56,0xf9,0xf9,0x56,0x87,0xac,0xab,0xab,0xac,0xa5,0x81,0x56,0xf9,0x56,0xf9 - - 0xf9,0xf9,0x56,0xf9,0xfa,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0x56,0x56,0xf9,0xf9,0x56, - 0x56,0xfa,0x56,0x56,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0x56,0x56,0xf9,0xf9,0xf9,0xf9, 0xf9,0x56,0xf9,0xf9,0x56,0xf9,0xf9,0x56,0xf9,0xf9,0x56,0x56,0xf9,0xf9,0xf9,0x56, 0xf9,0x56,0xf9,0x56,0xf9,0xf9,0x56,0x56,0xf9,0x56,0x56,0xf9,0xf9,0xf9,0x56,0x56, - 0xf9,0x56,0x56,0xf9,0x56,0x56,0xf9,0xf9,0xfa,0xf9,0xf9,0x56,0x56,0x56,0x56,0xf9, - 0x56,0x56,0xf9,0xf9,0xf9,0xf9,0xf9,0xfa,0x56,0x56,0x56,0x56,0xf9,0xf9,0x56,0xfa, - 0xf9,0xf9,0xf9,0xf9,0x56,0xf9,0x56,0x56,0x56,0x56,0x56,0x56,0xf9,0xf9,0xf9,0x56, - 0x56,0x56,0xf9,0xf9,0x56,0x56,0x56,0xf9,0xf9,0xfa,0xf9,0xf9,0xf9,0xf9,0x56,0xf9, - 0x56,0x56,0xf9,0x56,0x56,0x56,0xf9,0xf9,0xf9,0xf9,0x56,0x56,0xfa,0xf9,0x56,0xf9, - 0xf9,0xf9,0x56,0xf9,0xfa,0xf9,0xf9,0xf9,0xf9,0x56,0x56,0x56,0xf9,0xf9,0x56,0xf9, - 0x56,0x56,0x56,0xf9,0xf9,0x56,0x56,0xf9,0x56,0xf9,0xf9,0xf9,0xf9,0xf9,0x56,0x56, - 0x56,0xf9,0x56,0xfa,0x56,0xf9,0xfa,0xfa,0xf9,0xf9,0x56,0xf9,0xf9,0xf9,0xf9,0xf9, - 0xf9,0xf9,0x56,0xf9,0x56,0xf9,0x56,0x56,0x56,0x56,0xf9,0x56,0x56,0xf9,0xf9,0x56, - 0xf9,0xf9,0xf9,0xf9,0x56,0xf9,0xf9,0x56,0x56,0xfa,0xf9,0xf9,0x56,0xf9,0x56,0xf9, - 0xf9,0xf9,0x56,0xf9,0xf9,0xf9,0x56,0x56,0xf9,0xf9,0x56,0x56,0xf9,0xf9,0xfa,0xf9, - 0xf9,0x56,0xf9,0xf9,0x56,0xf9,0x56,0x56,0xf9,0xf9,0x56,0x56,0x56,0xf9,0x56,0xf9 -#endif - -}; #warning shared video_console.c struct vc_progress_element { @@ -219,112 +39,25 @@ struct vc_progress_element { }; typedef struct vc_progress_element vc_progress_element; -static vc_progress_element default_progress = - { 0, 0, 111, 3, {0, 0, 0}, - 16, 16, 15, 15, TRANSPARENT, {0, 0, 0} }; -/* (320-8), (256+4) */ - +struct boot_progress_element { + unsigned int width; + unsigned int height; + int yOffset; + unsigned int res[5]; + unsigned char data[0]; +}; +typedef struct boot_progress_element boot_progress_element; -static unsigned char default_noroot_data[ 32 * 48 ] = { - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xff,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xff,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xff,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xff,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xff,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xff,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xff,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xff,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfa, - 0xff,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xff,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xff,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xff, - 0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff, - 0xff,0x00,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0xff,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xff,0x00,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0xf7,0xff, - 0xff,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0x00,0x00,0xff,0xff,0xff,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xff,0xff,0xff,0xff,0xff,0x00,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0xff, - 0xff,0x00,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0xff,0xf7,0xf7,0xff,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xff,0xf7,0xfc,0xf7,0xf7,0xff,0x00,0xf7,0x00,0xf7,0x00,0xf7,0xf7,0xff, - 0xff,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xff,0xf7,0xfc,0xff,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xff,0xff,0xf7,0xff,0xf7,0xff,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0xff, - 0xff,0x00,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0xff,0xf7,0xfc,0x00,0xff,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xff,0x00,0xf7,0xf7,0xff,0x00,0xf7,0x00,0xf7,0x00,0xf7,0xf7,0xff, - 0xff,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xff,0xf7,0xfc,0xff,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xff,0x00,0xfc,0x00,0xf7,0xff,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0xff, - 0xff,0x00,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0xff,0xf7,0xfc,0x00,0xff,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xff,0x00,0xf7,0xf7,0xff,0x00,0xf7,0x00,0xf7,0x00,0xf7,0xf7,0xff, - 0xff,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xff,0xf7,0xfc,0xff,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xff,0x00,0xfc,0x00,0xf7,0xff,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0xff, - 0xff,0x00,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0xff,0xf7,0xfc,0x00,0xff,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xff,0x00,0xf7,0xf7,0xff,0x00,0xf7,0x00,0xf7,0x00,0xf7,0xf7,0xff, - 0xff,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xff,0xf7,0xf7,0xff,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xff,0x00,0xf7,0x00,0xf7,0xff,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0xff, - 0xff,0x00,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0xff,0xf7,0xf7,0xf7,0xff,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xff,0xf7,0xf7,0xf7,0xff,0x00,0xf7,0x00,0xf7,0x00,0xf7,0xf7,0xff, - 0xff,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xff,0xf7,0xff,0xf7,0xff,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xff,0xf7,0xf7,0xf7,0xff,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0xff, - 0xff,0x00,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0xff,0xf7,0xfc,0xf7,0xff,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xff,0xff,0xff,0xf7,0xff,0x00,0xf7,0x00,0xf7,0x00,0xf7,0xf7,0xff, - 0xff,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xff,0xf7,0xf7,0xff,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xff,0xf7,0xf7,0xf7,0xf7,0xff,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0xff, - 0xff,0x00,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0xf7,0xff,0xff,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0xf7,0x00,0xf7,0x00,0xf7,0xf7,0xff, - 0xff,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0x00,0x00,0xff,0xff,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0xff, - 0xff,0x00,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xff,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xff,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0x00,0xf7,0xf7,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, -}; +static const unsigned char * default_progress_data = gGearPict; +static const unsigned char * default_noroot_data = 0; -static vc_progress_element default_roroot = - { 0, 1, 0, 0, {0, 0, 0}, - 32, 48, -16, -26, 0x80, { 0, 0, 0 }}; +static vc_progress_element default_progress = + { 0, 4|1, 1000 / kGearFPS, kGearFrames, {0, 0, 0}, + kGearWidth, kGearHeight, 0, kGearOffset, + 0, {0, 0, 0} }; + +static vc_progress_element default_noroot = + { 0, 1, 0, 0, {0, 0, 0}, + 128, 128, 0, 0, + -1, {0, 0, 0} }; diff --git a/pexpert/pexpert/ppc/protos.h b/pexpert/pexpert/ppc/protos.h index 2bed21693..f9bb037c1 100644 --- a/pexpert/pexpert/ppc/protos.h +++ b/pexpert/pexpert/ppc/protos.h @@ -93,11 +93,11 @@ extern void ofw_init(void *); extern void initialize_screen(void *, unsigned int); extern boolean_t vc_progress_initialize( void * desc, - unsigned char * data, - unsigned char * clut ); + const unsigned char * data, + const unsigned char * clut ); extern void vc_display_icon( void * desc, - unsigned char * data ); + const unsigned char * data ); // from osfmk/ppc/serial_console.c extern int switch_to_serial_console(void); diff --git a/pexpert/ppc/pe_init.c b/pexpert/ppc/pe_init.c index a32134289..afffd30bf 100644 --- a/pexpert/ppc/pe_init.c +++ b/pexpert/ppc/pe_init.c @@ -31,6 +31,7 @@ #include #include #include +#include /* extern references */ void pe_identify_machine(void); @@ -113,42 +114,13 @@ int PE_initialize_console( PE_Video * info, int op ) return 0; } -static boolean_t find_image( const char * name, - void ** desc, - unsigned char ** data, - unsigned char ** clut ) -{ - boolean_t ok; -#if 0 - DTEntry entry; - int size; - - // This is a little flawed now the device tree data - // is freed. - if( (kSuccess == DTLookupEntry(0, "/AAPL,images", &entry)) - && (kSuccess == DTLookupEntry(entry, name, &entry)) ) { - - ok = ( (kSuccess == DTGetProperty(entry, "desc", - desc, &size)) - && (kSuccess == DTGetProperty(entry, "data", - (void **)data, &size))); - - if( clut && (kSuccess != DTGetProperty(entry, "clut", - (void **)clut, &size))) - *clut = appleClut8; - } else -#endif - ok = FALSE; - - return( ok ); -} - void PE_init_iokit(void) { kern_return_t ret; - void * desc; - unsigned char * data; - unsigned char * clut; + DTEntry entry; + int size; + int i; + void ** map; PE_init_kprintf(TRUE); PE_init_printf(TRUE); @@ -156,12 +128,25 @@ void PE_init_iokit(void) // init this now to get mace debugger for iokit startup PE_init_ethernet_debugger(); - if( !find_image( "progress", &desc, &data, &clut)) { - clut = appleClut8; - desc = &default_progress; - data = default_progress_data; + + if( kSuccess == DTLookupEntry(0, "/chosen/memory-map", &entry)) { + + boot_progress_element * bootPict; + + if( kSuccess == DTGetProperty(entry, "BootCLUT", (void **) &map, &size)) + bcopy( map[0], appleClut8, sizeof(appleClut8) ); + + if( kSuccess == DTGetProperty(entry, "Pict-FailedBoot", (void **) &map, &size)) { + + bootPict = (boot_progress_element *) map[0]; + default_noroot.width = bootPict->width; + default_noroot.height = bootPict->height; + default_noroot.dx = 0; + default_noroot.dy = bootPict->yOffset; + default_noroot_data = &bootPict->data[0]; + } } - vc_progress_initialize( desc, data, clut ); + vc_progress_initialize( &default_progress, default_progress_data, (unsigned char *) appleClut8 ); PE_initialize_console( (PE_Video *) 0, kPEAcquireScreen ); @@ -222,14 +207,8 @@ int PE_current_console( PE_Video * info ) void PE_display_icon( unsigned int flags, const char * name ) { - void * desc; - unsigned char * data; - - if( !find_image( name, &desc, &data, 0)) { - desc = &default_roroot; - data = default_noroot_data; - } - vc_display_icon( desc, data ); + if( default_noroot_data) + vc_display_icon( &default_noroot, default_noroot_data ); } extern boolean_t PE_get_hotkey(